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-09-20 14:18:08 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-20 14:18:08 +0300
commit5afcbe03ead9ada87621888a31a62652b10a7e4f (patch)
tree9918b67a0d0f0bafa6542e839a8be37adf73102d
parentc97c0201564848c1f53226fe19d71fdcc472f7d0 (diff)
Add latest changes from gitlab-org/gitlab@16-4-stable-eev16.4.0-rc42
-rw-r--r--.eslintrc.yml4
-rw-r--r--.gitignore8
-rw-r--r--.gitlab-ci.yml16
-rw-r--r--.gitlab/CODEOWNERS48
-rw-r--r--.gitlab/ci/as-if-jh.gitlab-ci.yml9
-rw-r--r--.gitlab/ci/cng/main.gitlab-ci.yml1
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml10
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml1
-rw-r--r--.gitlab/ci/gitlab-gems.gitlab-ci.yml3
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml5
-rw-r--r--.gitlab/ci/package-and-test/main.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/qa-common/main.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/qa-common/rules.gitlab-ci.yml24
-rw-r--r--.gitlab/ci/qa-common/variables.gitlab-ci.yml1
-rw-r--r--.gitlab/ci/qa.gitlab-ci.yml1
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml68
-rw-r--r--.gitlab/ci/rails/shared.gitlab-ci.yml3
-rw-r--r--.gitlab/ci/review-apps/main.gitlab-ci.yml1
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml81
-rw-r--r--.gitlab/ci/test-on-gdk/main.gitlab-ci.yml45
-rw-r--r--.gitlab/ci/workhorse.gitlab-ci.yml9
-rw-r--r--.gitlab/issue_templates/Operational Readiness.md102
-rw-r--r--.gitlab/issue_templates/Security developer workflow.md1
-rw-r--r--.gitlab/merge_request_templates/Stable Branch.md2
-rw-r--r--.rubocop.yml22
-rw-r--r--.rubocop_todo/capybara/testid_finders.yml249
-rw-r--r--.rubocop_todo/cop/experiments_test_coverage.yml1
-rw-r--r--.rubocop_todo/cop/ignored_columns.yml1
-rw-r--r--.rubocop_todo/factory_bot/create_list.yml1
-rw-r--r--.rubocop_todo/gitlab/doc_url.yml2
-rw-r--r--.rubocop_todo/gitlab/feature_available_usage.yml6
-rw-r--r--.rubocop_todo/gitlab/namespaced_class.yml2
-rw-r--r--.rubocop_todo/gitlab/strong_memoize_attr.yml1
-rw-r--r--.rubocop_todo/graphql/resource_not_available_error.yml1
-rw-r--r--.rubocop_todo/internal_affairs/use_restrict_on_send.yml1
-rw-r--r--.rubocop_todo/layout/argument_alignment.yml95
-rw-r--r--.rubocop_todo/layout/empty_line_after_magic_comment.yml4
-rw-r--r--.rubocop_todo/layout/extra_spacing.yml8
-rw-r--r--.rubocop_todo/layout/first_hash_element_indentation.yml1
-rw-r--r--.rubocop_todo/layout/line_end_string_concatenation_indentation.yml2
-rw-r--r--.rubocop_todo/layout/line_length.yml7
-rw-r--r--.rubocop_todo/layout/space_in_lambda_literal.yml1
-rw-r--r--.rubocop_todo/lint/assignment_in_condition.yml4
-rw-r--r--.rubocop_todo/lint/redundant_cop_disable_directive.yml1
-rw-r--r--.rubocop_todo/lint/redundant_safe_navigation.yml1
-rw-r--r--.rubocop_todo/lint/redundant_string_coercion.yml1
-rw-r--r--.rubocop_todo/migration/avoid_finalize_background_migration.yml1
-rw-r--r--.rubocop_todo/naming/heredoc_delimiter_naming.yml1
-rw-r--r--.rubocop_todo/performance/regexp_match.yml1
-rw-r--r--.rubocop_todo/rails/output_safety.yml1
-rw-r--r--.rubocop_todo/rails/time_zone.yml2
-rw-r--r--.rubocop_todo/rspec/before_all.yml1
-rw-r--r--.rubocop_todo/rspec/before_all_role_assignment.yml3
-rw-r--r--.rubocop_todo/rspec/context_wording.yml8
-rw-r--r--.rubocop_todo/rspec/expect_in_hook.yml2
-rw-r--r--.rubocop_todo/rspec/factory_bot/excessive_create_list.yml1
-rw-r--r--.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml1
-rw-r--r--.rubocop_todo/rspec/missing_feature_category.yml17
-rw-r--r--.rubocop_todo/rspec/useless_dynamic_definition.yml1
-rw-r--r--.rubocop_todo/rspec/verified_doubles.yml3
-rw-r--r--.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml1
-rw-r--r--.rubocop_todo/style/class_and_module_children.yml3
-rw-r--r--.rubocop_todo/style/conditional_assignment.yml5
-rw-r--r--.rubocop_todo/style/each_for_simple_loop.yml6
-rw-r--r--.rubocop_todo/style/format_string.yml3
-rw-r--r--.rubocop_todo/style/hash_as_last_array_item.yml1
-rw-r--r--.rubocop_todo/style/if_unless_modifier.yml1
-rw-r--r--.rubocop_todo/style/mutable_constant.yml1
-rw-r--r--.rubocop_todo/style/next.yml5
-rw-r--r--.rubocop_todo/style/percent_literal_delimiters.yml385
-rw-r--r--.rubocop_todo/style/redundant_condition.yml5
-rw-r--r--.rubocop_todo/style/redundant_freeze.yml83
-rw-r--r--.rubocop_todo/style/redundant_parentheses.yml9
-rw-r--r--.rubocop_todo/style/redundant_self.yml2
-rw-r--r--.rubocop_todo/style/string_literals_in_interpolation.yml1
-rw-r--r--CHANGELOG.md56
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_ELASTICSEARCH_INDEXER_VERSION2
-rw-r--r--GITLAB_KAS_VERSION2
-rw-r--r--GITLAB_METRICS_EXPORTER_VERSION1
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile78
-rw-r--r--Gemfile.checksum121
-rw-r--r--Gemfile.lock187
-rw-r--r--Guardfile4
-rw-r--r--README.md2
-rwxr-xr-xRakefile4
-rw-r--r--app/assets/images/auth_buttons/salesforce_64.pngbin2012 -> 0 bytes
-rw-r--r--app/assets/javascripts/access_tokens/components/access_token_table_app.vue17
-rw-r--r--app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue3
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue46
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/activity_events_list.vue19
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/activity_history_item.vue42
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report.query.graphql13
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql11
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/graphql/create_abuse_report_label.mutation.graphql10
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/history_items.vue51
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/labels_select.vue235
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/report_actions.vue8
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/report_details.vue49
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/report_header.vue16
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/reported_content.vue13
-rw-r--r--app/assets/javascripts/admin/abuse_report/components/user_details.vue40
-rw-r--r--app/assets/javascripts/admin/abuse_report/constants.js4
-rw-r--r--app/assets/javascripts/admin/abuse_report/index.js18
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue21
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/components/message_form.vue3
-rw-r--r--app/assets/javascripts/admin/users/components/actions/approve.vue4
-rw-r--r--app/assets/javascripts/admin/users/components/user_actions.vue3
-rw-r--r--app/assets/javascripts/alert_management/components/alert_management_table.vue2
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_form.vue8
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue11
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue3
-rw-r--r--app/assets/javascripts/analytics/cycle_analytics/components/formatted_stage_count.vue3
-rw-r--r--app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue3
-rw-r--r--app/assets/javascripts/api.js14
-rw-r--r--app/assets/javascripts/api/application_settings_api.js14
-rw-r--r--app/assets/javascripts/authentication/webauthn/error.js9
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js3
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/keybindings.js1
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_help.vue26
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.js8
-rw-r--r--app/assets/javascripts/behaviors/toggler_behavior.js16
-rw-r--r--app/assets/javascripts/blob/components/blob_header.vue61
-rw-r--r--app/assets/javascripts/blob/line_highlighter.js19
-rw-r--r--app/assets/javascripts/blob/openapi/index.js9
-rw-r--r--app/assets/javascripts/blob/queries/application_info.query.graphql (renamed from app/assets/javascripts/repository/queries/application_info.query.graphql)0
-rw-r--r--app/assets/javascripts/blob/queries/user_info.query.graphql (renamed from app/assets/javascripts/repository/queries/user_info.query.graphql)0
-rw-r--r--app/assets/javascripts/boards/components/board_card_inner.vue9
-rw-r--r--app/assets/javascripts/boards/components/board_content_sidebar.vue8
-rw-r--r--app/assets/javascripts/boards/components/board_form.vue4
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue14
-rw-r--r--app/assets/javascripts/boards/components/board_list_header.vue6
-rw-r--r--app/assets/javascripts/boards/components/board_settings_sidebar.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_top_bar.vue9
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue10
-rw-r--r--app/assets/javascripts/boards/components/issue_board_filtered_search.vue5
-rw-r--r--app/assets/javascripts/boards/components/issue_due_date.vue9
-rw-r--r--app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue5
-rw-r--r--app/assets/javascripts/boards/graphql/cache_updates.js4
-rw-r--r--app/assets/javascripts/boards/graphql/group_board_members.query.graphql15
-rw-r--r--app/assets/javascripts/boards/graphql/project_board_members.query.graphql15
-rw-r--r--app/assets/javascripts/boards/index.js1
-rw-r--r--app/assets/javascripts/boards/issue_board_filters.js40
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/admin_jobs_table_app.vue271
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/components/cancel_jobs.vue37
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/components/cancel_jobs_modal.vue66
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/components/cells/project_cell.vue (renamed from app/assets/javascripts/pages/admin/jobs/components/table/cell/project_cell.vue)0
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/components/cells/runner_cell.vue39
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/components/jobs_skeleton_loader.vue (renamed from app/assets/javascripts/pages/admin/jobs/components/jobs_skeleton_loader.vue)0
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/constants.js35
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/graphql/cache_config.js (renamed from app/assets/javascripts/pages/admin/jobs/components/table/graphql/cache_config.js)0
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_all_jobs.query.graphql90
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_all_jobs_count.query.graphql5
-rw-r--r--app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_cancelable_jobs_count.query.graphql5
-rw-r--r--app/assets/javascripts/ci/artifacts/components/feedback_banner.vue41
-rw-r--r--app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue3
-rw-r--r--app/assets/javascripts/ci/artifacts/constants.js7
-rw-r--r--app/assets/javascripts/ci/artifacts/index.js8
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/ci_variable_list.js262
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue195
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue5
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue3
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue49
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/constants.js1
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/native_form_variable_list.js25
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/utils.js10
-rw-r--r--app/assets/javascripts/ci/common/pipelines_table.vue240
-rw-r--r--app/assets/javascripts/ci/common/private/job_action_component.vue136
-rw-r--r--app/assets/javascripts/ci/common/private/job_links_layer.vue75
-rw-r--r--app/assets/javascripts/ci/common/private/job_name_component.vue (renamed from app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue)0
-rw-r--r--app/assets/javascripts/ci/common/private/jobs_filtered_search/app.vue99
-rw-r--r--app/assets/javascripts/ci/common/private/jobs_filtered_search/constants.js23
-rw-r--r--app/assets/javascripts/ci/common/private/jobs_filtered_search/tokens/job_runner_type_token.vue79
-rw-r--r--app/assets/javascripts/ci/common/private/jobs_filtered_search/tokens/job_status_token.vue (renamed from app/assets/javascripts/jobs/components/filtered_search/tokens/job_status_token.vue)0
-rw-r--r--app/assets/javascripts/ci/common/private/jobs_filtered_search/utils.js22
-rw-r--r--app/assets/javascripts/ci/constants.js51
-rw-r--r--app/assets/javascripts/ci/event_hub.js (renamed from app/assets/javascripts/jobs/components/table/event_hub.js)0
-rw-r--r--app/assets/javascripts/ci/inherited_ci_variables/components/inherited_ci_variables_app.vue2
-rw-r--r--app/assets/javascripts/ci/job_details/components/empty_state.vue100
-rw-r--r--app/assets/javascripts/ci/job_details/components/environments_block.vue (renamed from app/assets/javascripts/jobs/components/job/environments_block.vue)0
-rw-r--r--app/assets/javascripts/ci/job_details/components/erased_block.vue (renamed from app/assets/javascripts/jobs/components/job/erased_block.vue)0
-rw-r--r--app/assets/javascripts/ci/job_details/components/job_header.vue148
-rw-r--r--app/assets/javascripts/ci/job_details/components/job_log_controllers.vue260
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/collapsible_section.vue71
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/duration_badge.vue (renamed from app/assets/javascripts/jobs/components/log/duration_badge.vue)0
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/line.vue83
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/line_header.vue81
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/line_number.vue (renamed from app/assets/javascripts/jobs/components/log/line_number.vue)0
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/log.vue106
-rw-r--r--app/assets/javascripts/ci/job_details/components/log/utils.js12
-rw-r--r--app/assets/javascripts/ci/job_details/components/manual_variables_form.vue305
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/artifacts_block.vue120
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/commit_block.vue54
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/external_links_block.vue34
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/job_container_item.vue77
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/job_retry_forward_deployment_modal.vue72
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/job_sidebar_retry_button.vue84
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/jobs_container.vue36
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue127
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue64
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue168
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue130
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue179
-rw-r--r--app/assets/javascripts/ci/job_details/components/sidebar/trigger_block.vue94
-rw-r--r--app/assets/javascripts/ci/job_details/components/stuck_block.vue91
-rw-r--r--app/assets/javascripts/ci/job_details/components/unmet_prerequisites_block.vue (renamed from app/assets/javascripts/jobs/components/job/unmet_prerequisites_block.vue)0
-rw-r--r--app/assets/javascripts/ci/job_details/graphql/fragments/ci_job.fragment.graphql11
-rw-r--r--app/assets/javascripts/ci/job_details/graphql/fragments/ci_variable.fragment.graphql (renamed from app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/job_details/graphql/mutations/job_play_with_variables.mutation.graphql11
-rw-r--r--app/assets/javascripts/ci/job_details/graphql/mutations/job_retry_with_variables.mutation.graphql11
-rw-r--r--app/assets/javascripts/ci/job_details/graphql/queries/get_job.query.graphql12
-rw-r--r--app/assets/javascripts/ci/job_details/index.js69
-rw-r--r--app/assets/javascripts/ci/job_details/job_app.vue349
-rw-r--r--app/assets/javascripts/ci/job_details/store/actions.js277
-rw-r--r--app/assets/javascripts/ci/job_details/store/getters.js (renamed from app/assets/javascripts/jobs/store/getters.js)0
-rw-r--r--app/assets/javascripts/ci/job_details/store/index.js (renamed from app/assets/javascripts/jobs/store/index.js)0
-rw-r--r--app/assets/javascripts/ci/job_details/store/mutation_types.js (renamed from app/assets/javascripts/jobs/store/mutation_types.js)0
-rw-r--r--app/assets/javascripts/ci/job_details/store/mutations.js (renamed from app/assets/javascripts/jobs/store/mutations.js)0
-rw-r--r--app/assets/javascripts/ci/job_details/store/state.js (renamed from app/assets/javascripts/jobs/store/state.js)0
-rw-r--r--app/assets/javascripts/ci/job_details/store/utils.js (renamed from app/assets/javascripts/jobs/store/utils.js)0
-rw-r--r--app/assets/javascripts/ci/job_details/utils.js29
-rw-r--r--app/assets/javascripts/ci/jobs_page/components/job_cells/actions_cell.vue265
-rw-r--r--app/assets/javascripts/ci/jobs_page/components/job_cells/duration_cell.vue52
-rw-r--r--app/assets/javascripts/ci/jobs_page/components/job_cells/job_cell.vue171
-rw-r--r--app/assets/javascripts/ci/jobs_page/components/job_cells/pipeline_cell.vue56
-rw-r--r--app/assets/javascripts/ci/jobs_page/components/jobs_table.vue112
-rw-r--r--app/assets/javascripts/ci/jobs_page/components/jobs_table_empty_state.vue36
-rw-r--r--app/assets/javascripts/ci/jobs_page/components/jobs_table_tabs.vue88
-rw-r--r--app/assets/javascripts/ci/jobs_page/constants.js (renamed from app/assets/javascripts/jobs/components/table/constants.js)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/event_hub.js (renamed from app/assets/javascripts/pipelines/event_hub.js)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/graphql/cache_config.js (renamed from app/assets/javascripts/jobs/components/table/graphql/cache_config.js)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/graphql/fragments/job.fragment.graphql (renamed from app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/graphql/mutations/job_cancel.mutation.graphql (renamed from app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/graphql/mutations/job_play.mutation.graphql (renamed from app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/graphql/mutations/job_retry.mutation.graphql (renamed from app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/graphql/mutations/job_unschedule.mutation.graphql (renamed from app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/graphql/queries/get_jobs.query.graphql (renamed from app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/graphql/queries/get_jobs_count.query.graphql (renamed from app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/jobs_page/index.js50
-rw-r--r--app/assets/javascripts/ci/jobs_page/jobs_page_app.vue238
-rw-r--r--app/assets/javascripts/ci/merge_requests/components/pipelines_table_wrapper.vue60
-rw-r--r--app/assets/javascripts/ci/merge_requests/graphql/mutations/retry_mr_failed_job.mutation.graphql (renamed from app/assets/javascripts/pipelines/graphql/mutations/retry_mr_failed_job.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/merge_requests/graphql/queries/get_merge_request_pipelines.query.graphql16
-rw-r--r--app/assets/javascripts/ci/mixins/delayed_job_mixin.js (renamed from app/assets/javascripts/jobs/mixins/delayed_job_mixin.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/constants.js77
-rw-r--r--app/assets/javascripts/ci/pipeline_details/dag/components/dag_annotations.vue (renamed from app/assets/javascripts/pipelines/components/dag/dag_annotations.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/dag/components/dag_graph.vue329
-rw-r--r--app/assets/javascripts/ci/pipeline_details/dag/constants.js (renamed from app/assets/javascripts/pipelines/components/dag/constants.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/dag/dag.vue254
-rw-r--r--app/assets/javascripts/ci/pipeline_details/dag/graphql/queries/get_dag_vis_data.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/dag/utils/drawing_utils.js (renamed from app/assets/javascripts/pipelines/components/dag/drawing_utils.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/dag/utils/interactions.js154
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/api_utils.js13
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/graph_component.vue261
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/graph_view_selector.vue176
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/job_group_dropdown.vue110
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/job_item.vue396
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/linked_graph_wrapper.vue (renamed from app/assets/javascripts/pipelines/components/graph_shared/linked_graph_wrapper.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipeline.vue306
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipelines_column.vue247
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/links_inner.vue162
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/root_graph_layout.vue (renamed from app/assets/javascripts/pipelines/components/graph_shared/main_graph_wrapper.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/components/stage_column_component.vue196
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/constants.js (renamed from app/assets/javascripts/pipelines/components/graph/constants.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/graph_component_wrapper.vue345
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/graphql/mutations/dismiss_pipeline_notification.graphql (renamed from app/assets/javascripts/pipelines/graphql/mutations/dismiss_pipeline_notification.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/perf_utils.js50
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graph/utils.js117
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graphql/fragments/pipeline_stages_connection.fragment.graphql (renamed from app/assets/javascripts/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graphql/mutations/cancel_pipeline.mutation.graphql (renamed from app/assets/javascripts/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graphql/mutations/delete_pipeline.mutation.graphql (renamed from app/assets/javascripts/pipelines/graphql/mutations/delete_pipeline.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graphql/mutations/retry_pipeline.mutation.graphql (renamed from app/assets/javascripts/pipelines/graphql/mutations/retry_pipeline.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graphql/provider.js (renamed from app/assets/javascripts/pipelines/graphql/provider.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_linked_pipelines.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue625
-rw-r--r--app/assets/javascripts/ci/pipeline_details/jobs/components/failed_jobs_table.vue126
-rw-r--r--app/assets/javascripts/ci/pipeline_details/jobs/failed_jobs_app.vue65
-rw-r--r--app/assets/javascripts/ci/pipeline_details/jobs/graphql/mutations/retry_failed_job.mutation.graphql (renamed from app/assets/javascripts/pipelines/graphql/mutations/retry_failed_job.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/jobs/graphql/queries/get_failed_jobs.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_failed_jobs.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/jobs/graphql/queries/get_pipeline_jobs.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_pipeline_jobs.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/jobs/jobs_app.vue133
-rw-r--r--app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js237
-rw-r--r--app/assets/javascripts/ci/pipeline_details/pipeline_details_bundle.js67
-rw-r--r--app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js75
-rw-r--r--app/assets/javascripts/ci/pipeline_details/pipeline_shared_client.js (renamed from app/assets/javascripts/pipelines/pipeline_shared_client.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/pipeline_tabs.js116
-rw-r--r--app/assets/javascripts/ci/pipeline_details/pipelines_index.js100
-rw-r--r--app/assets/javascripts/ci/pipeline_details/routes.js20
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/pipelines_store.js (renamed from app/assets/javascripts/pipelines/stores/pipelines_store.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/test_reports/actions.js (renamed from app/assets/javascripts/pipelines/stores/test_reports/actions.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/test_reports/constants.js (renamed from app/assets/javascripts/pipelines/stores/test_reports/constants.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/test_reports/getters.js (renamed from app/assets/javascripts/pipelines/stores/test_reports/getters.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/test_reports/index.js (renamed from app/assets/javascripts/pipelines/stores/test_reports/index.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/test_reports/mutation_types.js (renamed from app/assets/javascripts/pipelines/stores/test_reports/mutation_types.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/test_reports/mutations.js (renamed from app/assets/javascripts/pipelines/stores/test_reports/mutations.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/test_reports/state.js (renamed from app/assets/javascripts/pipelines/stores/test_reports/state.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/stores/test_reports/utils.js (renamed from app/assets/javascripts/pipelines/stores/test_reports/utils.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/tabs/pipeline_tabs.vue138
-rw-r--r--app/assets/javascripts/ci/pipeline_details/test_reports/empty_state.vue61
-rw-r--r--app/assets/javascripts/ci/pipeline_details/test_reports/test_case_details.vue152
-rw-r--r--app/assets/javascripts/ci/pipeline_details/test_reports/test_reports.vue (renamed from app/assets/javascripts/pipelines/components/test_reports/test_reports.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/test_reports/test_suite_table.vue (renamed from app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/test_reports/test_summary.vue117
-rw-r--r--app/assets/javascripts/ci/pipeline_details/test_reports/test_summary_table.vue (renamed from app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/utils/drawing_utils.js (renamed from app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_details/utils/index.js147
-rw-r--r--app/assets/javascripts/ci/pipeline_details/utils/parsing_utils.js182
-rw-r--r--app/assets/javascripts/ci/pipeline_details/utils/unwrapping_utils.js73
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/commit/commit_form.vue7
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/editor/ci_editor_header.vue4
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue1
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue2
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/graph/job_pill.vue (renamed from app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/graph/pipeline_graph.vue169
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/graph/stage_name.vue (renamed from app/assets/javascripts/pipelines/components/pipeline_graph/stage_name.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_header.vue50
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue6
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue28
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/header/validation_segment.vue4
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/utils.js6
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/pipeline_editor_tabs.vue4
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/popovers/file_tree_popover.vue1
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/ui/pipeline_editor_empty_state.vue3
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue1
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/graphql/queries/ci_config.query.graphql2
-rw-r--r--app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue4
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/accessors/linked_pipelines_accessors.js (renamed from app/assets/javascripts/pipelines/components/pipeline_mini_graph/accessors/linked_pipelines_accessors.js)0
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stage.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_pipeline_stage.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stages.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_pipeline_stages.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/job_item.vue (renamed from app/assets/javascripts/pipelines/components/pipeline_mini_graph/job_item.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/legacy_job_item.vue168
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue (renamed from app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/legacy_pipeline_stage.vue176
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/linked_pipelines_mini_list.vue132
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/pipeline_mini_graph.vue147
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/pipeline_stage.vue81
-rw-r--r--app/assets/javascripts/ci/pipeline_mini_graph/pipeline_stages.vue63
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_empty_state.vue1
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue38
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue7
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue50
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/empty_state/ci_templates.vue (renamed from app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ci_templates.vue)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/empty_state/ios_templates.vue220
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue53
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/empty_state/pipelines_ci_templates.vue (renamed from app/assets/javascripts/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_job_details.vue165
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_jobs_list.vue180
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue121
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/failure_widget/utils.js15
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue (renamed from app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue170
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipeline_multi_actions.vue189
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue113
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue (renamed from app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipeline_triggerer.vue (renamed from app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue242
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipelines_artifacts.vue72
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipelines_filtered_search.vue130
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue159
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipelines_status_badge.vue51
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/time_ago.vue (renamed from app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/constants.js2
-rw-r--r--app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_actions.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_pipeline_actions.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_failed_jobs.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_pipeline_failed_jobs.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_failed_jobs_count.query.graphql (renamed from app/assets/javascripts/pipelines/graphql/queries/get_pipeline_failed_jobs_count.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/pipelines.vue450
-rw-r--r--app/assets/javascripts/ci/pipelines_page/services/pipelines_service.js51
-rw-r--r--app/assets/javascripts/ci/pipelines_page/tokens/constants.js (renamed from app/assets/javascripts/pipelines/components/pipelines_list/tokens/constants.js)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/tokens/pipeline_branch_name_token.vue83
-rw-r--r--app/assets/javascripts/ci/pipelines_page/tokens/pipeline_source_token.vue47
-rw-r--r--app/assets/javascripts/ci/pipelines_page/tokens/pipeline_status_token.vue (renamed from app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_status_token.vue)0
-rw-r--r--app/assets/javascripts/ci/pipelines_page/tokens/pipeline_tag_name_token.vue67
-rw-r--r--app/assets/javascripts/ci/pipelines_page/tokens/pipeline_trigger_author_token.vue110
-rw-r--r--app/assets/javascripts/ci/reports/components/issue_status_icon.vue5
-rw-r--r--app/assets/javascripts/ci/reports/components/report_section.vue3
-rw-r--r--app/assets/javascripts/ci/runner/admin_runners/admin_runners_app.vue28
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/runner_owner_cell.vue7
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/runner_summary_cell.vue16
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/runner_summary_field.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_create_form.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue1
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_form_fields.vue15
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_managers_table.vue12
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue4
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_type_tabs.vue7
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_update_form.vue2
-rw-r--r--app/assets/javascripts/ci/runner/components/stat/runner_count.vue6
-rw-r--r--app/assets/javascripts/ci/runner/components/stat/runner_stats.vue1
-rw-r--r--app/assets/javascripts/ci/runner/constants.js3
-rw-r--r--app/assets/javascripts/ci/runner/graphql/show/runner_manager_shared.fragment.graphql1
-rw-r--r--app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue34
-rw-r--r--app/assets/javascripts/ci/runner/project_runners/index.js23
-rw-r--r--app/assets/javascripts/ci/runner/project_runners/project_runners_app.vue19
-rw-r--r--app/assets/javascripts/ci/runner/runner_search_utils.js3
-rw-r--r--app/assets/javascripts/ci/utils.js17
-rw-r--r--app/assets/javascripts/ci_secure_files/components/metadata/modal.vue6
-rw-r--r--app/assets/javascripts/clusters_list/components/agent_table.vue6
-rw-r--r--app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue3
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters.vue12
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters_actions.vue3
-rw-r--r--app/assets/javascripts/commit/constants.js6
-rw-r--r--app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue342
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_bundle.js3
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table.vue342
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue0
-rw-r--r--app/assets/javascripts/commons/gitlab_ui.js10
-rw-r--r--app/assets/javascripts/commons/index.js1
-rw-r--r--app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_created.vue2
-rw-r--r--app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_destroyed.vue28
-rw-r--r--app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_pushed.vue3
-rw-r--r--app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_updated.vue25
-rw-r--r--app/assets/javascripts/contribution_events/components/contribution_events.vue10
-rw-r--r--app/assets/javascripts/contribution_events/components/target_link.vue2
-rw-r--r--app/assets/javascripts/contribution_events/constants.js26
-rw-r--r--app/assets/javascripts/create_item_dropdown.js4
-rw-r--r--app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue10
-rw-r--r--app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js12
-rw-r--r--app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_filter.js2
-rw-r--r--app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_remote.js3
-rw-r--r--app/assets/javascripts/deprecated_jquery_dropdown/index.js5
-rw-r--r--app/assets/javascripts/deprecated_jquery_dropdown/render.js3
-rw-r--r--app/assets/javascripts/deprecated_notes.js3
-rw-r--r--app/assets/javascripts/diffs/components/app.vue9
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_inline_findings_item.vue32
-rw-r--r--app/assets/javascripts/diffs/components/diff_row.vue14
-rw-r--r--app/assets/javascripts/diffs/components/diff_view.vue3
-rw-r--r--app/assets/javascripts/diffs/store/actions.js3
-rw-r--r--app/assets/javascripts/diffs/store/getters.js3
-rw-r--r--app/assets/javascripts/drawio/drawio_editor.js3
-rw-r--r--app/assets/javascripts/editor/schema/ci.json7
-rw-r--r--app/assets/javascripts/entrypoints/analytics.js17
-rw-r--r--app/assets/javascripts/entrypoints/jira_connect_app.js1
-rw-r--r--app/assets/javascripts/entrypoints/main.js6
-rw-r--r--app/assets/javascripts/entrypoints/main_ee.js5
-rw-r--r--app/assets/javascripts/entrypoints/main_jh.js5
-rw-r--r--app/assets/javascripts/entrypoints/performance_bar.js1
-rw-r--r--app/assets/javascripts/entrypoints/redirect_listbox.js1
-rw-r--r--app/assets/javascripts/entrypoints/sandboxed_mermaid.js1
-rw-r--r--app/assets/javascripts/entrypoints/sentry.js1
-rw-r--r--app/assets/javascripts/environments/components/deployment.vue2
-rw-r--r--app/assets/javascripts/environments/components/edit_environment.vue7
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue2
-rw-r--r--app/assets/javascripts/environments/components/environment_form.vue7
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue17
-rw-r--r--app/assets/javascripts/environments/components/kubernetes_status_bar.vue15
-rw-r--r--app/assets/javascripts/environments/components/new_environment_item.vue8
-rw-r--r--app/assets/javascripts/environments/environment_details/deployments_table.vue2
-rw-r--r--app/assets/javascripts/environments/graphql/queries/environment.query.graphql1
-rw-r--r--app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql1
-rw-r--r--app/assets/javascripts/environments/graphql/queries/environment_cluster_agent_with_flux_resource.query.graphql21
-rw-r--r--app/assets/javascripts/environments/graphql/queries/environment_with_flux_resource.query.graphql16
-rw-r--r--app/assets/javascripts/environments/mixins/environments_pagination_api_mixin.js2
-rw-r--r--app/assets/javascripts/environments/mount_show.js3
-rw-r--r--app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue147
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js2
-rw-r--r--app/assets/javascripts/frequent_items/utils.js3
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js26
-rw-r--r--app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue6
-rw-r--r--app/assets/javascripts/google_cloud/deployments/service_table.vue2
-rw-r--r--app/assets/javascripts/google_cloud/service_accounts/list.vue1
-rw-r--r--app/assets/javascripts/graphql_shared/possible_types.json5
-rw-r--r--app/assets/javascripts/graphql_shared/queries/project_autocomplete_users.query.graphql12
-rw-r--r--app/assets/javascripts/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql19
-rw-r--r--app/assets/javascripts/groups/components/empty_states/groups_dashboard_empty_state.vue24
-rw-r--r--app/assets/javascripts/groups/components/empty_states/groups_explore_empty_state.vue17
-rw-r--r--app/assets/javascripts/groups/index.js13
-rw-r--r--app/assets/javascripts/helpers/avatar_helper.js38
-rw-r--r--app/assets/javascripts/ide/commit_icon.js3
-rw-r--r--app/assets/javascripts/ide/components/file_templates/dropdown.vue103
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/modal.vue6
-rw-r--r--app/assets/javascripts/ide/components/terminal/terminal.vue3
-rw-r--r--app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue6
-rw-r--r--app/assets/javascripts/ide/init_gitlab_web_ide.js3
-rw-r--r--app/assets/javascripts/ide/lib/diff/controller.js6
-rw-r--r--app/assets/javascripts/ide/lib/errors.js6
-rw-r--r--app/assets/javascripts/ide/lib/files.js3
-rw-r--r--app/assets/javascripts/ide/lib/mirror.js3
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js3
-rw-r--r--app/assets/javascripts/ide/stores/getters.js3
-rw-r--r--app/assets/javascripts/ide/stores/modules/terminal/messages.js3
-rw-r--r--app/assets/javascripts/ide/stores/utils.js9
-rw-r--r--app/assets/javascripts/import_entities/components/import_status.vue6
-rw-r--r--app/assets/javascripts/incidents/components/incidents_list.vue10
-rw-r--r--app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue2
-rw-r--r--app/assets/javascripts/integrations/index/components/integrations_table.vue66
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue126
-rw-r--r--app/assets/javascripts/invite_members/components/invite_modal_base.vue2
-rw-r--r--app/assets/javascripts/invite_members/constants.js20
-rw-r--r--app/assets/javascripts/invite_members/init_invite_members_modal.js3
-rw-r--r--app/assets/javascripts/invite_members/utils/member_utils.js6
-rw-r--r--app/assets/javascripts/issuable/components/csv_export_modal.vue4
-rw-r--r--app/assets/javascripts/issuable/components/csv_import_export_buttons.vue2
-rw-r--r--app/assets/javascripts/issuable/components/issuable_header_warnings.vue87
-rw-r--r--app/assets/javascripts/issuable/components/issue_assignees.vue4
-rw-r--r--app/assets/javascripts/issuable/components/issue_milestone.vue3
-rw-r--r--app/assets/javascripts/issuable/components/status_badge.vue98
-rw-r--r--app/assets/javascripts/issuable/components/status_box.vue146
-rw-r--r--app/assets/javascripts/issuable/index.js19
-rw-r--r--app/assets/javascripts/issuable/issuable_context.js23
-rw-r--r--app/assets/javascripts/issuable/popover/components/issue_popover.vue13
-rw-r--r--app/assets/javascripts/issues/constants.js1
-rw-r--r--app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue1
-rw-r--r--app/assets/javascripts/issues/index.js38
-rw-r--r--app/assets/javascripts/issues/issue.js5
-rw-r--r--app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue2
-rw-r--r--app/assets/javascripts/issues/list/components/issue_card_time_info.vue40
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue49
-rw-r--r--app/assets/javascripts/issues/list/constants.js1
-rw-r--r--app/assets/javascripts/issues/list/queries/issue.fragment.graphql1
-rw-r--r--app/assets/javascripts/issues/list/queries/search_milestones.query.graphql11
-rw-r--r--app/assets/javascripts/issues/list/queries/search_users.query.graphql29
-rw-r--r--app/assets/javascripts/issues/list/queries/user.fragment.graphql6
-rw-r--r--app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue9
-rw-r--r--app/assets/javascripts/issues/related_merge_requests/index.js10
-rw-r--r--app/assets/javascripts/issues/service_desk/components/empty_state_with_any_issues.vue59
-rw-r--r--app/assets/javascripts/issues/service_desk/components/empty_state_without_any_issues.vue (renamed from app/assets/javascripts/service_desk/components/empty_state_without_any_issues.vue)0
-rw-r--r--app/assets/javascripts/issues/service_desk/components/info_banner.vue (renamed from app/assets/javascripts/service_desk/components/info_banner.vue)0
-rw-r--r--app/assets/javascripts/issues/service_desk/components/service_desk_list_app.vue599
-rw-r--r--app/assets/javascripts/issues/service_desk/constants.js254
-rw-r--r--app/assets/javascripts/issues/service_desk/graphql.js (renamed from app/assets/javascripts/service_desk/graphql.js)0
-rw-r--r--app/assets/javascripts/issues/service_desk/index.js82
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/get_service_desk_issues.query.graphql67
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/get_service_desk_issues_counts.query.graphql82
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/issue.fragment.graphql61
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/label.fragment.graphql (renamed from app/assets/javascripts/service_desk/queries/label.fragment.graphql)0
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/milestone.fragment.graphql (renamed from app/assets/javascripts/service_desk/queries/milestone.fragment.graphql)0
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/reorder_service_desk_issues.mutation.graphql13
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/search_project_labels.query.graphql (renamed from app/assets/javascripts/service_desk/queries/search_project_labels.query.graphql)0
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/search_project_milestones.query.graphql (renamed from app/assets/javascripts/service_desk/queries/search_project_milestones.query.graphql)0
-rw-r--r--app/assets/javascripts/issues/service_desk/queries/set_sorting_preference.mutation.graphql5
-rw-r--r--app/assets/javascripts/issues/service_desk/search_tokens.js (renamed from app/assets/javascripts/service_desk/search_tokens.js)0
-rw-r--r--app/assets/javascripts/issues/service_desk/utils.js (renamed from app/assets/javascripts/service_desk/utils.js)0
-rw-r--r--app/assets/javascripts/issues/show/components/app.vue202
-rw-r--r--app/assets/javascripts/issues/show/components/description.vue3
-rw-r--r--app/assets/javascripts/issues/show/components/header_actions.vue79
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue5
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue2
-rw-r--r--app/assets/javascripts/issues/show/components/sticky_header.vue130
-rw-r--r--app/assets/javascripts/issues/show/components/task_list_item_actions.vue17
-rw-r--r--app/assets/javascripts/issues/show/index.js190
-rw-r--r--app/assets/javascripts/issues/show/stores/index.js46
-rw-r--r--app/assets/javascripts/jira_connect/branches/components/new_branch_form.vue1
-rw-r--r--app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue2
-rw-r--r--app/assets/javascripts/jira_connect/branches/components/source_branch_dropdown.vue55
-rw-r--r--app/assets/javascripts/jira_connect/branches/index.js1
-rw-r--r--app/assets/javascripts/jira_import/components/jira_import_form.vue4
-rw-r--r--app/assets/javascripts/jobs/components/filtered_search/constants.js13
-rw-r--r--app/assets/javascripts/jobs/components/filtered_search/jobs_filtered_search.vue64
-rw-r--r--app/assets/javascripts/jobs/components/filtered_search/utils.js27
-rw-r--r--app/assets/javascripts/jobs/components/job/empty_state.vue100
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql11
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql11
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql11
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/queries/get_job.query.graphql12
-rw-r--r--app/assets/javascripts/jobs/components/job/job_app.vue350
-rw-r--r--app/assets/javascripts/jobs/components/job/job_log_controllers.vue269
-rw-r--r--app/assets/javascripts/jobs/components/job/manual_variables_form.vue305
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue121
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/commit_block.vue47
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/job_container_item.vue77
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue64
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/job_sidebar_retry_button.vue81
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/jobs_container.vue35
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue154
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar_detail_row.vue59
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue146
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar_job_details_container.vue124
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue171
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue94
-rw-r--r--app/assets/javascripts/jobs/components/job/stuck_block.vue90
-rw-r--r--app/assets/javascripts/jobs/components/log/collapsible_section.vue57
-rw-r--r--app/assets/javascripts/jobs/components/log/line.vue93
-rw-r--r--app/assets/javascripts/jobs/components/log/line_header.vue69
-rw-r--r--app/assets/javascripts/jobs/components/log/log.vue100
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/actions_cell.vue265
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/duration_cell.vue45
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/job_cell.vue171
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue52
-rw-r--r--app/assets/javascripts/jobs/components/table/index.js50
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table.vue112
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_app.vue238
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_empty_state.vue35
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_tabs.vue88
-rw-r--r--app/assets/javascripts/jobs/constants.js40
-rw-r--r--app/assets/javascripts/jobs/index.js69
-rw-r--r--app/assets/javascripts/jobs/store/actions.js277
-rw-r--r--app/assets/javascripts/jobs/utils.js30
-rw-r--r--app/assets/javascripts/labels/labels_select.js6
-rw-r--r--app/assets/javascripts/lib/swagger.js2
-rw-r--r--app/assets/javascripts/lib/utils/array_utility.js15
-rw-r--r--app/assets/javascripts/lib/utils/breadcrumbs.js28
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js10
-rw-r--r--app/assets/javascripts/lib/utils/constants.js9
-rw-r--r--app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js9
-rw-r--r--app/assets/javascripts/lib/utils/datetime/date_format_utility.js27
-rw-r--r--app/assets/javascripts/lib/utils/datetime_range.js311
-rw-r--r--app/assets/javascripts/lib/utils/grammar.js6
-rw-r--r--app/assets/javascripts/lib/utils/number_utils.js6
-rw-r--r--app/assets/javascripts/lib/utils/secret_detection.js4
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js3
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js18
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js8
-rw-r--r--app/assets/javascripts/lib/utils/webpack.js5
-rw-r--r--app/assets/javascripts/locale/ensure_single_line.cjs10
-rw-r--r--app/assets/javascripts/locale/index.js64
-rw-r--r--app/assets/javascripts/locale/sprintf.js22
-rw-r--r--app/assets/javascripts/main.js3
-rw-r--r--app/assets/javascripts/members/components/action_buttons/approve_access_request_button.vue2
-rw-r--r--app/assets/javascripts/members/components/action_buttons/remove_member_button.vue2
-rw-r--r--app/assets/javascripts/members/components/modals/remove_member_modal.vue3
-rw-r--r--app/assets/javascripts/members/components/table/members_table_cell.vue6
-rw-r--r--app/assets/javascripts/merge_request_tabs.js10
-rw-r--r--app/assets/javascripts/merge_requests/components/compare_app.vue20
-rw-r--r--app/assets/javascripts/merge_requests/components/compare_dropdown.vue13
-rw-r--r--app/assets/javascripts/merge_requests/components/header_metadata.vue69
-rw-r--r--app/assets/javascripts/merge_requests/components/merge_request_status_badge.vue74
-rw-r--r--app/assets/javascripts/merge_requests/components/sticky_header.vue12
-rw-r--r--app/assets/javascripts/merge_requests/index.js19
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue45
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue13
-rw-r--r--app/assets/javascripts/notes/components/discussion_filter.vue3
-rw-r--r--app/assets/javascripts/notes/components/mr_discussion_filter.vue3
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue14
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue2
-rw-r--r--app/assets/javascripts/notes/components/sidebar_subscription.vue2
-rw-r--r--app/assets/javascripts/notes/stores/actions.js115
-rw-r--r--app/assets/javascripts/notes/stores/getters.js2
-rw-r--r--app/assets/javascripts/observability/client.js115
-rw-r--r--app/assets/javascripts/observability/mock_traces.json443
-rw-r--r--app/assets/javascripts/organizations/constants.js4
-rw-r--r--app/assets/javascripts/organizations/groups_and_projects/components/app.vue21
-rw-r--r--app/assets/javascripts/organizations/groups_and_projects/components/groups_page.vue43
-rw-r--r--app/assets/javascripts/organizations/groups_and_projects/components/projects_page.vue46
-rw-r--r--app/assets/javascripts/organizations/groups_and_projects/constants.js2
-rw-r--r--app/assets/javascripts/organizations/groups_and_projects/graphql/resolvers.js22
-rw-r--r--app/assets/javascripts/organizations/groups_and_projects/index.js21
-rw-r--r--app/assets/javascripts/organizations/groups_and_projects/utils.js23
-rw-r--r--app/assets/javascripts/organizations/mock_data.js258
-rw-r--r--app/assets/javascripts/organizations/shared/components/groups_view.vue82
-rw-r--r--app/assets/javascripts/organizations/shared/components/projects_view.vue86
-rw-r--r--app/assets/javascripts/organizations/shared/graphql/queries/groups.query.graphql (renamed from app/assets/javascripts/organizations/groups_and_projects/graphql/queries/groups.query.graphql)0
-rw-r--r--app/assets/javascripts/organizations/shared/graphql/queries/projects.query.graphql (renamed from app/assets/javascripts/organizations/groups_and_projects/graphql/queries/projects.query.graphql)0
-rw-r--r--app/assets/javascripts/organizations/shared/graphql/resolvers.js18
-rw-r--r--app/assets/javascripts/organizations/shared/utils.js26
-rw-r--r--app/assets/javascripts/organizations/show/components/app.vue37
-rw-r--r--app/assets/javascripts/organizations/show/components/association_count_card.vue54
-rw-r--r--app/assets/javascripts/organizations/show/components/association_counts.vue71
-rw-r--r--app/assets/javascripts/organizations/show/components/groups_and_projects.vue110
-rw-r--r--app/assets/javascripts/organizations/show/components/organization_avatar.vue71
-rw-r--r--app/assets/javascripts/organizations/show/constants.js1
-rw-r--r--app/assets/javascripts/organizations/show/index.js63
-rw-r--r--app/assets/javascripts/organizations/show/utils.js4
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js4
-rw-r--r--app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue58
-rw-r--r--app/assets/javascripts/packages_and_registries/dependency_proxy/index.js14
-rw-r--r--app/assets/javascripts/packages_and_registries/dependency_proxy/router.js14
-rw-r--r--app/assets/javascripts/packages_and_registries/dependency_proxy/utils.js24
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/index.js4
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue77
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue7
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/index.js4
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue41
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/utils.js24
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue17
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue1
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/utils.js26
-rw-r--r--app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js38
-rw-r--r--app/assets/javascripts/pages/admin/abuse_reports/index.js7
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/general/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/jobs/components/cancel_jobs.vue37
-rw-r--r--app/assets/javascripts/pages/admin/jobs/components/cancel_jobs_modal.vue66
-rw-r--r--app/assets/javascripts/pages/admin/jobs/components/constants.js35
-rw-r--r--app/assets/javascripts/pages/admin/jobs/components/table/admin_jobs_table_app.vue259
-rw-r--r--app/assets/javascripts/pages/admin/jobs/components/table/cells/runner_cell.vue39
-rw-r--r--app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_all_jobs.query.graphql85
-rw-r--r--app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_all_jobs_count.query.graphql5
-rw-r--r--app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_cancelable_jobs_count.query.graphql5
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/index.js45
-rw-r--r--app/assets/javascripts/pages/dashboard/groups/index/index.js3
-rw-r--r--app/assets/javascripts/pages/explore/groups/index.js3
-rw-r--r--app/assets/javascripts/pages/import/bitbucket_server/status/components/bitbucket_server_status_table.vue11
-rw-r--r--app/assets/javascripts/pages/organizations/organizations/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/incidents/show/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/issues/service_desk/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/issues/show/index.js7
-rw-r--r--app/assets/javascripts/pages/projects/jobs/index/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/jobs/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/creations/new/branch_finder.js1
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/creations/new/index.js37
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js18
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/page.js4
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js7
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js74
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js7
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue3
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue62
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js94
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/tracing/index/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/tracing/show/index.js4
-rw-r--r--app/assets/javascripts/performance_bar/components/detailed_metric.vue3
-rw-r--r--app/assets/javascripts/persistent_user_callouts.js2
-rw-r--r--app/assets/javascripts/pipelines/components/dag/dag.vue249
-rw-r--r--app/assets/javascripts/pipelines/components/dag/dag_graph.vue329
-rw-r--r--app/assets/javascripts/pipelines/components/dag/interactions.js154
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_component.vue261
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue345
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue176
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue110
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_item.vue396
-rw-r--r--app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue304
-rw-r--r--app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue247
-rw-r--r--app/assets/javascripts/pipelines/components/graph/perf_utils.js50
-rw-r--r--app/assets/javascripts/pipelines/components/graph/stage_column_component.vue196
-rw-r--r--app/assets/javascripts/pipelines/components/graph/utils.js116
-rw-r--r--app/assets/javascripts/pipelines/components/graph_shared/api.js13
-rw-r--r--app/assets/javascripts/pipelines/components/graph_shared/links_inner.vue161
-rw-r--r--app/assets/javascripts/pipelines/components/graph_shared/links_layer.vue75
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue65
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue125
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/jobs_app.vue133
-rw-r--r--app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue136
-rw-r--r--app/assets/javascripts/pipelines/components/parsing_utils.js182
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_details_header.vue631
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue174
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_job_item.vue168
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage.vue176
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list.vue132
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue150
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue84
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stages.vue63
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_tabs.vue138
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue53
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ios_templates.vue220
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/failed_job_details.vue165
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/failed_jobs_list.vue179
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget.vue121
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/utils.js19
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_labels.vue170
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_multi_actions.vue172
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue113
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue239
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue449
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_artifacts.vue72
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue130
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions.vue159
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue50
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue240
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue82
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_source_token.vue47
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_tag_name_token.vue66
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue113
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/empty_state.vue60
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue145
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_summary.vue117
-rw-r--r--app/assets/javascripts/pipelines/components/unwrapping_utils.js73
-rw-r--r--app/assets/javascripts/pipelines/constants.js120
-rw-r--r--app/assets/javascripts/pipelines/mixins/pipelines_mixin.js237
-rw-r--r--app/assets/javascripts/pipelines/mixins/stage_column_mixin.js14
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_bundle.js61
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_header.js75
-rw-r--r--app/assets/javascripts/pipelines/pipeline_tabs.js115
-rw-r--r--app/assets/javascripts/pipelines/pipelines_index.js100
-rw-r--r--app/assets/javascripts/pipelines/routes.js20
-rw-r--r--app/assets/javascripts/pipelines/services/pipelines_service.js51
-rw-r--r--app/assets/javascripts/pipelines/utils.js156
-rw-r--r--app/assets/javascripts/profile/profile.js1
-rw-r--r--app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue15
-rw-r--r--app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_status.vue5
-rw-r--r--app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue156
-rw-r--r--app/assets/javascripts/projects/pipelines/charts/constants.js2
-rw-r--r--app/assets/javascripts/projects/project_star_button.js46
-rw-r--r--app/assets/javascripts/projects/settings/access_dropdown.js611
-rw-r--r--app/assets/javascripts/projects/settings/api/access_dropdown_api.js16
-rw-r--r--app/assets/javascripts/projects/settings/components/access_dropdown.vue126
-rw-r--r--app/assets/javascripts/projects/settings/constants.js7
-rw-r--r--app/assets/javascripts/projects/settings/init_access_dropdown.js25
-rw-r--r--app/assets/javascripts/projects/settings_service_desk/components/custom_email_form.vue33
-rw-r--r--app/assets/javascripts/projects/settings_service_desk/components/custom_email_wrapper.vue1
-rw-r--r--app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js2
-rw-r--r--app/assets/javascripts/projects/star.js43
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_create.js101
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_edit.js141
-rw-r--r--app/assets/javascripts/protected_tags/constants.js4
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_create.js71
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_edit.js115
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_edit.vue113
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_edit_list.js46
-rw-r--r--app/assets/javascripts/related_issues/components/add_issuable_form.vue3
-rw-r--r--app/assets/javascripts/related_issues/index.js5
-rw-r--r--app/assets/javascripts/repository/components/blob_content_viewer.vue141
-rw-r--r--app/assets/javascripts/repository/components/last_commit.vue22
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue7
-rw-r--r--app/assets/javascripts/repository/constants.js8
-rw-r--r--app/assets/javascripts/rest_api.js1
-rw-r--r--app/assets/javascripts/right_sidebar.js15
-rw-r--r--app/assets/javascripts/run_modules.js9
-rw-r--r--app/assets/javascripts/search/index.js3
-rw-r--r--app/assets/javascripts/search/sidebar/components/app.vue81
-rw-r--r--app/assets/javascripts/search/sidebar/components/archived_filter/data.js5
-rw-r--r--app/assets/javascripts/search/sidebar/components/archived_filter/index.vue6
-rw-r--r--app/assets/javascripts/search/sidebar/components/blobs_filters.vue22
-rw-r--r--app/assets/javascripts/search/sidebar/components/commits_filters.vue18
-rw-r--r--app/assets/javascripts/search/sidebar/components/filters_template.vue8
-rw-r--r--app/assets/javascripts/search/sidebar/components/issues_filters.vue21
-rw-r--r--app/assets/javascripts/search/sidebar/components/language_filter/index.vue2
-rw-r--r--app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue33
-rw-r--r--app/assets/javascripts/search/sidebar/components/notes_filters.vue18
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_legacy_navigation.vue3
-rw-r--r--app/assets/javascripts/search/sidebar/components/small_screen_drawer_navigation.vue61
-rw-r--r--app/assets/javascripts/search/sidebar/constants/index.js6
-rw-r--r--app/assets/javascripts/search/sidebar/index.js6
-rw-r--r--app/assets/javascripts/search/store/actions.js2
-rw-r--r--app/assets/javascripts/search/store/mutations.js2
-rw-r--r--app/assets/javascripts/search/store/state.js3
-rw-r--r--app/assets/javascripts/search/store/utils.js3
-rw-r--r--app/assets/javascripts/security_configuration/components/app.vue13
-rw-r--r--app/assets/javascripts/security_configuration/components/constants.js4
-rw-r--r--app/assets/javascripts/security_configuration/components/continuous_vulnerability_scan.vue127
-rw-r--r--app/assets/javascripts/security_configuration/components/feature_card.vue7
-rw-r--r--app/assets/javascripts/security_configuration/graphql/project_set_continuous_vulnerability_scanning.graphql8
-rw-r--r--app/assets/javascripts/security_configuration/index.js2
-rw-r--r--app/assets/javascripts/security_configuration/utils.js5
-rw-r--r--app/assets/javascripts/sentry/index.js35
-rw-r--r--app/assets/javascripts/sentry/init_sentry.js77
-rw-r--r--app/assets/javascripts/sentry/sentry_browser_wrapper.js4
-rw-r--r--app/assets/javascripts/sentry/sentry_config.js31
-rw-r--r--app/assets/javascripts/service_desk/components/empty_state_with_any_issues.vue58
-rw-r--r--app/assets/javascripts/service_desk/components/service_desk_list_app.vue443
-rw-r--r--app/assets/javascripts/service_desk/constants.js251
-rw-r--r--app/assets/javascripts/service_desk/index.js78
-rw-r--r--app/assets/javascripts/service_desk/queries/get_service_desk_issues.query.graphql72
-rw-r--r--app/assets/javascripts/service_desk/queries/get_service_desk_issues_counts.query.graphql91
-rw-r--r--app/assets/javascripts/service_desk/queries/issue.fragment.graphql60
-rw-r--r--app/assets/javascripts/settings_panels.js12
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_invite_members.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue13
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue27
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/copy/sidebar_reference_widget.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue7
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/getters.js3
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue24
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue13
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_footer.vue15
-rw-r--r--app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/participants/participants.vue11
-rw-r--r--app/assets/javascripts/sidebar/components/participants/sidebar_participants_widget.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue24
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/report.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue9
-rw-r--r--app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue3
-rw-r--r--app/assets/javascripts/sidebar/constants.js268
-rw-r--r--app/assets/javascripts/sidebar/queries/constants.js291
-rw-r--r--app/assets/javascripts/sidebar/queries/test_case_confidential.query.graphql9
-rw-r--r--app/assets/javascripts/sidebar/queries/update_test_case_confidential.mutation.graphql9
-rw-r--r--app/assets/javascripts/silent_mode_settings/components/app.vue70
-rw-r--r--app/assets/javascripts/silent_mode_settings/index.js27
-rw-r--r--app/assets/javascripts/snippets/components/embed_dropdown.vue39
-rw-r--r--app/assets/javascripts/snippets/utils/blob.js3
-rw-r--r--app/assets/javascripts/super_sidebar/components/brand_logo.vue14
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_header.vue56
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher.vue209
-rw-r--r--app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue43
-rw-r--r--app/assets/javascripts/super_sidebar/components/create_menu.vue78
-rw-r--r--app/assets/javascripts/super_sidebar/components/flyout_menu.vue129
-rw-r--r--app/assets/javascripts/super_sidebar/components/frequent_items_list.vue106
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue15
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js10
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/command_palette/utils.js35
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/components/frequent_items.vue8
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue17
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_places.vue20
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/store/getters.js13
-rw-r--r--app/assets/javascripts/super_sidebar/components/global_search/utils.js13
-rw-r--r--app/assets/javascripts/super_sidebar/components/groups_list.vue81
-rw-r--r--app/assets/javascripts/super_sidebar/components/items_list.vue44
-rw-r--r--app/assets/javascripts/super_sidebar/components/menu_section.vue16
-rw-r--r--app/assets/javascripts/super_sidebar/components/nav_item.vue148
-rw-r--r--app/assets/javascripts/super_sidebar/components/pinned_section.vue30
-rw-r--r--app/assets/javascripts/super_sidebar/components/projects_list.vue82
-rw-r--r--app/assets/javascripts/super_sidebar/components/search_results.vue99
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_hover_peek_behavior.vue126
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_menu.vue16
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue14
-rw-r--r--app/assets/javascripts/super_sidebar/components/super_sidebar.vue95
-rw-r--r--app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue26
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_bar.vue57
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_menu.vue14
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_name_group.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/constants.js10
-rw-r--r--app/assets/javascripts/super_sidebar/graphql/queries/search_user_groups_and_projects.query.graphql24
-rw-r--r--app/assets/javascripts/super_sidebar/super_sidebar_bundle.js9
-rw-r--r--app/assets/javascripts/super_sidebar/super_sidebar_collapsed_state_manager.js3
-rw-r--r--app/assets/javascripts/super_sidebar/utils.js64
-rw-r--r--app/assets/javascripts/time_tracking/components/queries/get_timelogs.query.graphql8
-rw-r--r--app/assets/javascripts/time_tracking/components/timelogs_app.vue28
-rw-r--r--app/assets/javascripts/token_access/components/outbound_token_access.vue10
-rw-r--r--app/assets/javascripts/tracing/components/tracing_details.vue90
-rw-r--r--app/assets/javascripts/tracing/components/tracing_empty_state.vue35
-rw-r--r--app/assets/javascripts/tracing/components/tracing_list.vue125
-rw-r--r--app/assets/javascripts/tracing/components/tracing_list_filtered_search.vue87
-rw-r--r--app/assets/javascripts/tracing/components/tracing_table_list.vue101
-rw-r--r--app/assets/javascripts/tracing/details_index.vue49
-rw-r--r--app/assets/javascripts/tracing/filters.js104
-rw-r--r--app/assets/javascripts/tracing/list_index.vue37
-rw-r--r--app/assets/javascripts/tracking/constants.js8
-rw-r--r--app/assets/javascripts/tracking/dispatch_snowplow_event.js8
-rw-r--r--app/assets/javascripts/tracking/index.js1
-rw-r--r--app/assets/javascripts/tracking/internal_events.js48
-rw-r--r--app/assets/javascripts/tracking/tracker.js8
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/project_storage_app.stories.js64
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue80
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/usage_graph.vue136
-rw-r--r--app/assets/javascripts/user_lists/components/user_list.vue2
-rw-r--r--app/assets/javascripts/users_select/index.js1047
-rw-r--r--app/assets/javascripts/visibility_level/constants.js8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue55
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue36
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/memory_usage.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue13
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js12
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.vue15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js189
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.vue313
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue17
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js39
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js11
-rw-r--r--app/assets/javascripts/vue_shared/components/blob_viewers/constants.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue85
-rw-r--r--app/assets/javascripts/vue_shared/components/changed_file_icon.vue9
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_badge_link.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/confidentiality_badge.vue28
-rw-r--r--app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue283
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_input.vue77
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_lib.js91
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/empty_file.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/entity_select/group_select.vue25
-rw-r--r--app/assets/javascripts/vue_shared/components/entity_select/utils.js19
-rw-r--r--app/assets/javascripts/vue_shared/components/file_finder/index.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue21
-rw-r--r--app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue203
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue172
-rw-r--r--app/assets/javascripts/vue_shared/components/incidents/utils.js3
-rw-r--r--app/assets/javascripts/vue_shared/components/list_actions/constants.js16
-rw-r--r--app/assets/javascripts/vue_shared/components/list_actions/list_actions.stories.js44
-rw-r--r--app/assets/javascripts/vue_shared/components/list_actions/list_actions.vue52
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue45
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/comment_templates_dropdown.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/constants.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field_view.vue20
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js6
-rw-r--r--app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.vue45
-rw-r--r--app/assets/javascripts/vue_shared/components/projects_list/constants.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue49
-rw-r--r--app/assets/javascripts/vue_shared/components/source_editor.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_new.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue66
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/split_button.vue85
-rw-r--r--app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/user_select/user_select.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/web_ide_link.vue6
-rw-r--r--app/assets/javascripts/vue_shared/constants.js2
-rw-r--r--app/assets/javascripts/vue_shared/issuable/create/components/issuable_form.vue2
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue56
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue8
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_tabs.vue2
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_description.vue2
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue11
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_show_root.vue8
-rw-r--r--app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue3
-rw-r--r--app/assets/javascripts/vue_shared/new_namespace/new_namespace_page.vue24
-rw-r--r--app/assets/javascripts/vue_shared/security_reports/components/security_report_download_dropdown.vue44
-rw-r--r--app/assets/javascripts/vuex_shared/bindings.js3
-rw-r--r--app/assets/javascripts/webpack.js3
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_activity_sort_filter.vue35
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_add_note.vue6
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue150
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_discussion.vue6
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note.vue4
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_notes_activity_header.vue4
-rw-r--r--app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue11
-rw-r--r--app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue3
-rw-r--r--app/assets/javascripts/work_items/components/shared/work_item_links_menu.vue25
-rw-r--r--app/assets/javascripts/work_items/components/shared/work_item_token_input.vue145
-rw-r--r--app/assets/javascripts/work_items/components/widget_wrapper.vue19
-rw-r--r--app/assets/javascripts/work_items/components/work_item_actions.vue80
-rw-r--r--app/assets/javascripts/work_items/components/work_item_assignees.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_created_updated.vue8
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue23
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_children_wrapper.vue5
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue7
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue3
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue94
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_notes.vue7
-rw-r--r--app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationship_list.vue61
-rw-r--r--app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationships.vue185
-rw-r--r--app/assets/javascripts/work_items/components/work_item_state_badge.vue12
-rw-r--r--app/assets/javascripts/work_items/components/work_item_type_icon.vue2
-rw-r--r--app/assets/javascripts/work_items/constants.js27
-rw-r--r--app/assets/javascripts/work_items/graphql/group_work_item_types.query.graphql11
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql27
-rw-r--r--app/assets/javascripts/work_items/list/components/work_items_list_app.vue25
-rw-r--r--app/assets/javascripts/work_items/list/index.js15
-rw-r--r--app/assets/javascripts/work_items/list/queries/base_work_item_widgets.fragment.graphql38
-rw-r--r--app/assets/javascripts/work_items/list/queries/get_work_items.query.graphql27
-rw-r--r--app/assets/javascripts/work_items/list/queries/work_item_widgets.fragment.graphql5
-rw-r--r--app/assets/javascripts/work_items/pages/create_work_item.vue11
-rw-r--r--app/assets/javascripts/work_items/utils.js23
-rw-r--r--app/assets/javascripts/work_items_hierarchy/hierarchy_util.js3
-rw-r--r--app/assets/stylesheets/disable_animations.scss5
-rw-r--r--app/assets/stylesheets/framework/common.scss5
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss17
-rw-r--r--app/assets/stylesheets/framework/filters.scss16
-rw-r--r--app/assets/stylesheets/framework/header.scss8
-rw-r--r--app/assets/stylesheets/framework/job_log.scss2
-rw-r--r--app/assets/stylesheets/framework/layout.scss12
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss2
-rw-r--r--app/assets/stylesheets/framework/mixins.scss2
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss35
-rw-r--r--app/assets/stylesheets/framework/super_sidebar.scss103
-rw-r--r--app/assets/stylesheets/framework/variables.scss148
-rw-r--r--app/assets/stylesheets/page_bundles/admin/jobs_index.scss5
-rw-r--r--app/assets/stylesheets/page_bundles/build.scss77
-rw-r--r--app/assets/stylesheets/page_bundles/incidents.scss3
-rw-r--r--app/assets/stylesheets/page_bundles/issuable.scss12
-rw-r--r--app/assets/stylesheets/page_bundles/merge_request.scss7
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss15
-rw-r--r--app/assets/stylesheets/page_bundles/pipeline_schedules.scss82
-rw-r--r--app/assets/stylesheets/page_bundles/profiles/preferences.scss8
-rw-r--r--app/assets/stylesheets/page_bundles/projects_usage_quotas.scss19
-rw-r--r--app/assets/stylesheets/page_bundles/work_items.scss10
-rw-r--r--app/assets/stylesheets/pages/note_form.scss2
-rw-r--r--app/assets/stylesheets/pages/projects.scss2
-rw-r--r--app/assets/stylesheets/themes/dark_mode_overrides.scss2
-rw-r--r--app/assets/stylesheets/themes/theme_helper.scss9
-rw-r--r--app/assets/stylesheets/themes/theme_light_gray.scss2
-rw-r--r--app/assets/stylesheets/themes/theme_light_green.scss2
-rw-r--r--app/assets/stylesheets/utilities.scss13
-rw-r--r--app/channels/noteable/notes_channel.rb1
-rw-r--r--app/components/pajamas/banner_component.html.haml3
-rw-r--r--app/components/pajamas/banner_component.rb8
-rw-r--r--app/controllers/activity_pub/application_controller.rb27
-rw-r--r--app/controllers/activity_pub/projects/application_controller.rb28
-rw-r--r--app/controllers/activity_pub/projects/releases_controller.rb29
-rw-r--r--app/controllers/admin/abuse_reports_controller.rb14
-rw-r--r--app/controllers/admin/jobs_controller.rb12
-rw-r--r--app/controllers/admin/users_controller.rb9
-rw-r--r--app/controllers/application_controller.rb35
-rw-r--r--app/controllers/clusters/agents/dashboard_controller.rb34
-rw-r--r--app/controllers/concerns/access_tokens_actions.rb1
-rw-r--r--app/controllers/concerns/harbor/access.rb8
-rw-r--r--app/controllers/concerns/issuable_actions.rb13
-rw-r--r--app/controllers/concerns/issuable_collections.rb18
-rw-r--r--app/controllers/concerns/notes_actions.rb3
-rw-r--r--app/controllers/concerns/onboarding/status.rb6
-rw-r--r--app/controllers/concerns/preferred_language_switcher.rb31
-rw-r--r--app/controllers/concerns/search_rate_limitable.rb3
-rw-r--r--app/controllers/concerns/verifies_with_email.rb1
-rw-r--r--app/controllers/concerns/web_hooks/hook_log_actions.rb9
-rw-r--r--app/controllers/confirmations_controller.rb1
-rw-r--r--app/controllers/groups/email_campaigns_controller.rb69
-rw-r--r--app/controllers/groups/labels_controller.rb5
-rw-r--r--app/controllers/groups/runners_controller.rb2
-rw-r--r--app/controllers/groups/work_items_controller.rb4
-rw-r--r--app/controllers/groups_controller.rb1
-rw-r--r--app/controllers/help_controller.rb2
-rw-r--r--app/controllers/import/bitbucket_server_controller.rb4
-rw-r--r--app/controllers/invites_controller.rb2
-rw-r--r--app/controllers/oauth/authorizations_controller.rb2
-rw-r--r--app/controllers/organizations/application_controller.rb15
-rw-r--r--app/controllers/organizations/organizations_controller.rb16
-rw-r--r--app/controllers/passwords_controller.rb4
-rw-r--r--app/controllers/profiles/notifications_controller.rb2
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb1
-rw-r--r--app/controllers/profiles/preferences_controller.rb1
-rw-r--r--app/controllers/projects/alerting/notifications_controller.rb6
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/environments/sample_metrics_controller.rb16
-rw-r--r--app/controllers/projects/environments_controller.rb14
-rw-r--r--app/controllers/projects/graphs_controller.rb2
-rw-r--r--app/controllers/projects/incidents_controller.rb1
-rw-r--r--app/controllers/projects/issues_controller.rb12
-rw-r--r--app/controllers/projects/jobs_controller.rb20
-rw-r--r--app/controllers/projects/labels_controller.rb5
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb12
-rw-r--r--app/controllers/projects/merge_requests/conflicts_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb20
-rw-r--r--app/controllers/projects/mirrors_controller.rb1
-rw-r--r--app/controllers/projects/notes_controller.rb3
-rw-r--r--app/controllers/projects/pages_controller.rb10
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb5
-rw-r--r--app/controllers/projects/pipelines/tests_controller.rb2
-rw-r--r--app/controllers/projects/pipelines_controller.rb7
-rw-r--r--app/controllers/projects/prometheus/alerts_controller.rb43
-rw-r--r--app/controllers/projects/service_desk_controller.rb2
-rw-r--r--app/controllers/projects/tracing_controller.rb23
-rw-r--r--app/controllers/projects/work_items_controller.rb1
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/controllers/pwa_controller.rb2
-rw-r--r--app/controllers/registrations/welcome_controller.rb10
-rw-r--r--app/controllers/registrations_controller.rb10
-rw-r--r--app/controllers/search_controller.rb4
-rw-r--r--app/controllers/sent_notifications_controller.rb2
-rw-r--r--app/controllers/sessions_controller.rb11
-rw-r--r--app/controllers/users/namespace_visits_controller.rb15
-rw-r--r--app/experiments/ios_specific_templates_experiment.rb2
-rw-r--r--app/finders/abuse_reports_finder.rb47
-rw-r--r--app/finders/ci/jobs_finder.rb33
-rw-r--r--app/finders/ci/runners_finder.rb3
-rw-r--r--app/finders/ci/triggers_finder.rb16
-rw-r--r--app/finders/group_members_finder.rb16
-rw-r--r--app/finders/groups/accepting_group_transfers_finder.rb4
-rw-r--r--app/finders/groups/base.rb4
-rw-r--r--app/finders/issuable_finder.rb2
-rw-r--r--app/finders/organizations/groups_finder.rb59
-rw-r--r--app/finders/organizations/organization_users_finder.rb33
-rw-r--r--app/finders/packages/npm/packages_for_user_finder.rb18
-rw-r--r--app/finders/packages/nuget/package_finder.rb3
-rw-r--r--app/finders/repositories/changelog_commits_finder.rb2
-rw-r--r--app/finders/work_items/namespace_work_items_finder.rb27
-rw-r--r--app/graphql/gitlab_schema.rb6
-rw-r--r--app/graphql/mutations/admin/abuse_report_labels/create.rb36
-rw-r--r--app/graphql/mutations/ci/project_ci_cd_settings_update.rb13
-rw-r--r--app/graphql/mutations/issues/bulk_update.rb2
-rw-r--r--app/graphql/mutations/issues/update.rb8
-rw-r--r--app/graphql/mutations/merge_requests/update.rb8
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/base.rb18
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/create.rb24
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/delete.rb4
-rw-r--r--app/graphql/mutations/work_items/linked_items/add.rb3
-rw-r--r--app/graphql/mutations/work_items/linked_items/base.rb7
-rw-r--r--app/graphql/mutations/work_items/linked_items/remove.rb28
-rw-r--r--app/graphql/resolvers/blame_resolver.rb62
-rw-r--r--app/graphql/resolvers/ci/all_jobs_resolver.rb28
-rw-r--r--app/graphql/resolvers/ci/pipeline_triggers_resolver.rb3
-rw-r--r--app/graphql/resolvers/ci/runner_jobs_resolver.rb16
-rw-r--r--app/graphql/resolvers/ci/runners_resolver.rb24
-rw-r--r--app/graphql/resolvers/ci/test_suite_resolver.rb2
-rw-r--r--app/graphql/resolvers/codequality_reports_comparer_resolver.rb19
-rw-r--r--app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb2
-rw-r--r--app/graphql/resolvers/namespaces/work_item_resolver.rb31
-rw-r--r--app/graphql/resolvers/namespaces/work_items_resolver.rb38
-rw-r--r--app/graphql/resolvers/organizations/groups_resolver.rb37
-rw-r--r--app/graphql/resolvers/organizations/organization_resolver.rb22
-rw-r--r--app/graphql/resolvers/organizations/organization_users_resolver.rb36
-rw-r--r--app/graphql/resolvers/work_items/linked_items_resolver.rb14
-rw-r--r--app/graphql/resolvers/work_items_resolver.rb11
-rw-r--r--app/graphql/types/blame/blame_type.rb20
-rw-r--r--app/graphql/types/blame/commit_data_type.rb20
-rw-r--r--app/graphql/types/blame/groups_type.rb20
-rw-r--r--app/graphql/types/ci/ci_cd_setting_type.rb3
-rw-r--r--app/graphql/types/ci/job_base_field.rb35
-rw-r--r--app/graphql/types/ci/job_failure_reason_enum.rb15
-rw-r--r--app/graphql/types/ci/job_trace_type.rb19
-rw-r--r--app/graphql/types/ci/job_type.rb28
-rw-r--r--app/graphql/types/ci/pipeline_schedule_type.rb5
-rw-r--r--app/graphql/types/ci/runner_job_execution_status_enum.rb4
-rw-r--r--app/graphql/types/ci/runner_membership_filter_enum.rb2
-rw-r--r--app/graphql/types/group_type.rb6
-rw-r--r--app/graphql/types/issue_type.rb2
-rw-r--r--app/graphql/types/label_type.rb3
-rw-r--r--app/graphql/types/merge_request_type.rb12
-rw-r--r--app/graphql/types/mutation_type.rb2
-rw-r--r--app/graphql/types/organizations/group_sort_enum.rb24
-rw-r--r--app/graphql/types/organizations/organization_type.rb38
-rw-r--r--app/graphql/types/organizations/organization_user_type.rb36
-rw-r--r--app/graphql/types/permission_types/work_item.rb2
-rw-r--r--app/graphql/types/query_type.rb9
-rw-r--r--app/graphql/types/repository/blob_type.rb3
-rw-r--r--app/graphql/types/security/codequality_reports_comparer/degradation_type.rb45
-rw-r--r--app/graphql/types/security/codequality_reports_comparer/report_type.rb40
-rw-r--r--app/graphql/types/security/codequality_reports_comparer/status_enum.rb16
-rw-r--r--app/graphql/types/security/codequality_reports_comparer/summary_type.rb30
-rw-r--r--app/graphql/types/security/codequality_reports_comparer_type.rb19
-rw-r--r--app/graphql/types/user_type.rb2
-rw-r--r--app/graphql/types/work_items/award_emoji_update_action_enum.rb1
-rw-r--r--app/graphql/types/work_items/widgets/linked_items_type.rb2
-rw-r--r--app/helpers/admin/abuse_reports_helper.rb3
-rw-r--r--app/helpers/application_helper.rb12
-rw-r--r--app/helpers/application_settings_helper.rb6
-rw-r--r--app/helpers/artifacts_helper.rb3
-rw-r--r--app/helpers/auth_helper.rb9
-rw-r--r--app/helpers/button_helper.rb68
-rw-r--r--app/helpers/ci/status_helper.rb72
-rw-r--r--app/helpers/ci/variables_helper.rb4
-rw-r--r--app/helpers/clusters_helper.rb2
-rw-r--r--app/helpers/colors_helper.rb2
-rw-r--r--app/helpers/diff_helper.rb2
-rw-r--r--app/helpers/emails_helper.rb2
-rw-r--r--app/helpers/environment_helper.rb2
-rw-r--r--app/helpers/environments_helper.rb7
-rw-r--r--app/helpers/external_link_helper.rb2
-rw-r--r--app/helpers/icons_helper.rb74
-rw-r--r--app/helpers/integrations_helper.rb23
-rw-r--r--app/helpers/invite_members_helper.rb25
-rw-r--r--app/helpers/issuables_helper.rb237
-rw-r--r--app/helpers/issues_helper.rb30
-rw-r--r--app/helpers/labels_helper.rb10
-rw-r--r--app/helpers/markup_helper.rb6
-rw-r--r--app/helpers/members_helper.rb8
-rw-r--r--app/helpers/merge_requests_helper.rb9
-rw-r--r--app/helpers/nav/new_dropdown_helper.rb2
-rw-r--r--app/helpers/nav_helper.rb4
-rw-r--r--app/helpers/organizations/organization_helper.rb34
-rw-r--r--app/helpers/profiles_helper.rb2
-rw-r--r--app/helpers/projects/observability_helper.rb23
-rw-r--r--app/helpers/projects/pipeline_helper.rb2
-rw-r--r--app/helpers/projects_helper.rb8
-rw-r--r--app/helpers/registrations_helper.rb2
-rw-r--r--app/helpers/routing/projects_helper.rb13
-rw-r--r--app/helpers/safe_format_helper.rb2
-rw-r--r--app/helpers/search_helper.rb8
-rw-r--r--app/helpers/sidebars_helper.rb99
-rw-r--r--app/helpers/sidekiq_helper.rb2
-rw-r--r--app/helpers/stat_anchors_helper.rb2
-rw-r--r--app/helpers/todos_helper.rb4
-rw-r--r--app/helpers/users/callouts_helper.rb7
-rw-r--r--app/helpers/users_helper.rb4
-rw-r--r--app/helpers/version_check_helper.rb3
-rw-r--r--app/helpers/vite_helper.rb29
-rw-r--r--app/helpers/webpack_helper.rb10
-rw-r--r--app/helpers/work_items_helper.rb6
-rw-r--r--app/mailers/emails/in_product_marketing.rb9
-rw-r--r--app/mailers/emails/profile.rb26
-rw-r--r--app/mailers/emails/service_desk.rb22
-rw-r--r--app/mailers/notify.rb1
-rw-r--r--app/mailers/previews/notify_preview.rb4
-rw-r--r--app/models/ability.rb1
-rw-r--r--app/models/abuse_report.rb15
-rw-r--r--app/models/active_session.rb11
-rw-r--r--app/models/alerting/project_alerting_setting.rb28
-rw-r--r--app/models/analytics/cycle_analytics/runtime_limiter.rb30
-rw-r--r--app/models/analytics/cycle_analytics/stage_event_hash.rb2
-rw-r--r--app/models/application_setting.rb71
-rw-r--r--app/models/application_setting_implementation.rb24
-rw-r--r--app/models/approval.rb3
-rw-r--r--app/models/award_emoji.rb2
-rw-r--r--app/models/badge.rb2
-rw-r--r--app/models/blob_viewer/binary_stl.rb2
-rw-r--r--app/models/blob_viewer/cargo_toml.rb2
-rw-r--r--app/models/blob_viewer/cartfile.rb2
-rw-r--r--app/models/blob_viewer/changelog.rb2
-rw-r--r--app/models/blob_viewer/composer_json.rb2
-rw-r--r--app/models/blob_viewer/contributing.rb2
-rw-r--r--app/models/blob_viewer/csv.rb2
-rw-r--r--app/models/blob_viewer/gemfile.rb2
-rw-r--r--app/models/blob_viewer/gemspec.rb2
-rw-r--r--app/models/blob_viewer/gitlab_ci_yml.rb2
-rw-r--r--app/models/blob_viewer/go_mod.rb4
-rw-r--r--app/models/blob_viewer/godeps_json.rb2
-rw-r--r--app/models/blob_viewer/license.rb2
-rw-r--r--app/models/blob_viewer/markup.rb2
-rw-r--r--app/models/blob_viewer/notebook.rb2
-rw-r--r--app/models/blob_viewer/open_api.rb2
-rw-r--r--app/models/blob_viewer/package_json.rb2
-rw-r--r--app/models/blob_viewer/pdf.rb2
-rw-r--r--app/models/blob_viewer/podfile.rb2
-rw-r--r--app/models/blob_viewer/podspec.rb2
-rw-r--r--app/models/blob_viewer/podspec_json.rb2
-rw-r--r--app/models/blob_viewer/readme.rb2
-rw-r--r--app/models/blob_viewer/requirements_txt.rb2
-rw-r--r--app/models/blob_viewer/route_map.rb2
-rw-r--r--app/models/blob_viewer/sketch.rb2
-rw-r--r--app/models/blob_viewer/svg.rb2
-rw-r--r--app/models/blob_viewer/yarn_lock.rb2
-rw-r--r--app/models/bulk_imports/batch_tracker.rb2
-rw-r--r--app/models/bulk_imports/entity.rb8
-rw-r--r--app/models/bulk_imports/file_transfer/group_config.rb2
-rw-r--r--app/models/bulk_imports/file_transfer/project_config.rb4
-rw-r--r--app/models/chat_name.rb3
-rw-r--r--app/models/ci/build.rb24
-rw-r--r--app/models/ci/build_need.rb5
-rw-r--r--app/models/ci/build_runner_session.rb2
-rw-r--r--app/models/ci/pipeline.rb2
-rw-r--r--app/models/ci/runner.rb10
-rw-r--r--app/models/clusters/agent.rb2
-rw-r--r--app/models/clusters/agent_token.rb12
-rw-r--r--app/models/clusters/platforms/kubernetes.rb2
-rw-r--r--app/models/commit.rb20
-rw-r--r--app/models/commit_range.rb6
-rw-r--r--app/models/commit_signatures/gpg_signature.rb1
-rw-r--r--app/models/commit_status.rb17
-rw-r--r--app/models/concerns/avatarable.rb6
-rw-r--r--app/models/concerns/chronic_duration_attribute.rb7
-rw-r--r--app/models/concerns/ci/deployable.rb6
-rw-r--r--app/models/concerns/ci/has_runner_executor.rb4
-rw-r--r--app/models/concerns/ci/maskable.rb4
-rw-r--r--app/models/concerns/ci/partitionable.rb5
-rw-r--r--app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb2
-rw-r--r--app/models/concerns/cross_database_ignored_tables.rb11
-rw-r--r--app/models/concerns/diff_positionable_note.rb2
-rw-r--r--app/models/concerns/each_batch.rb4
-rw-r--r--app/models/concerns/editable.rb2
-rw-r--r--app/models/concerns/enums/prometheus_metric.rb14
-rw-r--r--app/models/concerns/has_unique_internal_users.rb51
-rw-r--r--app/models/concerns/has_user_type.rb17
-rw-r--r--app/models/concerns/integrations/enable_ssl_verification.rb17
-rw-r--r--app/models/concerns/integrations/reset_secret_fields.rb4
-rw-r--r--app/models/concerns/integrations/slack_mattermost_fields.rb43
-rw-r--r--app/models/concerns/issuable.rb17
-rw-r--r--app/models/concerns/issue_available_features.rb8
-rw-r--r--app/models/concerns/linkable_item.rb1
-rw-r--r--app/models/concerns/mentionable/reference_regexes.rb2
-rw-r--r--app/models/concerns/noteable.rb27
-rw-r--r--app/models/concerns/packages/nuget/version_normalizable.rb2
-rw-r--r--app/models/concerns/pg_full_text_searchable.rb6
-rw-r--r--app/models/concerns/protected_ref.rb5
-rw-r--r--app/models/concerns/redactable.rb2
-rw-r--r--app/models/concerns/require_email_verification.rb5
-rw-r--r--app/models/concerns/resolvable_discussion.rb2
-rw-r--r--app/models/concerns/resolvable_note.rb2
-rw-r--r--app/models/concerns/restricted_signup.rb2
-rw-r--r--app/models/concerns/routable.rb71
-rw-r--r--app/models/concerns/storage/legacy_namespace.rb2
-rw-r--r--app/models/concerns/taskable.rb6
-rw-r--r--app/models/concerns/transitionable.rb21
-rw-r--r--app/models/concerns/users/visitable.rb18
-rw-r--r--app/models/concerns/with_uploads.rb2
-rw-r--r--app/models/container_expiration_policy.rb4
-rw-r--r--app/models/container_registry/event.rb12
-rw-r--r--app/models/custom_emoji.rb2
-rw-r--r--app/models/deploy_key.rb2
-rw-r--r--app/models/deploy_token.rb4
-rw-r--r--app/models/description_version.rb2
-rw-r--r--app/models/design_management.rb2
-rw-r--r--app/models/diff_note.rb2
-rw-r--r--app/models/discussion_note.rb2
-rw-r--r--app/models/draft_note.rb4
-rw-r--r--app/models/environment.rb7
-rw-r--r--app/models/environment_status.rb3
-rw-r--r--app/models/error_tracking/project_error_tracking_setting.rb2
-rw-r--r--app/models/event.rb5
-rw-r--r--app/models/gpg_key.rb2
-rw-r--r--app/models/group.rb25
-rw-r--r--app/models/hooks/web_hook.rb2
-rw-r--r--app/models/hooks/web_hook_log.rb11
-rw-r--r--app/models/instance_configuration.rb2
-rw-r--r--app/models/integration.rb6
-rw-r--r--app/models/integrations/apple_app_store.rb4
-rw-r--r--app/models/integrations/asana.rb5
-rw-r--r--app/models/integrations/assembla.rb2
-rw-r--r--app/models/integrations/base_chat_notification.rb89
-rw-r--r--app/models/integrations/base_issue_tracker.rb2
-rw-r--r--app/models/integrations/base_monitoring.rb2
-rw-r--r--app/models/integrations/base_slack_notification.rb14
-rw-r--r--app/models/integrations/base_slash_commands.rb2
-rw-r--r--app/models/integrations/base_third_party_wiki.rb2
-rw-r--r--app/models/integrations/buildkite.rb2
-rw-r--r--app/models/integrations/campfire.rb30
-rw-r--r--app/models/integrations/chat_message/base_message.rb2
-rw-r--r--app/models/integrations/chat_message/deployment_message.rb8
-rw-r--r--app/models/integrations/confluence.rb10
-rw-r--r--app/models/integrations/datadog.rb4
-rw-r--r--app/models/integrations/discord.rb28
-rw-r--r--app/models/integrations/drone_ci.rb2
-rw-r--r--app/models/integrations/emails_on_push.rb2
-rw-r--r--app/models/integrations/external_wiki.rb2
-rw-r--r--app/models/integrations/gitlab_slack_application.rb17
-rw-r--r--app/models/integrations/hangouts_chat.rb6
-rw-r--r--app/models/integrations/jenkins.rb2
-rw-r--r--app/models/integrations/jira.rb2
-rw-r--r--app/models/integrations/mattermost.rb3
-rw-r--r--app/models/integrations/microsoft_teams.rb26
-rw-r--r--app/models/integrations/packagist.rb2
-rw-r--r--app/models/integrations/pivotaltracker.rb2
-rw-r--r--app/models/integrations/prometheus.rb12
-rw-r--r--app/models/integrations/pumble.rb6
-rw-r--r--app/models/integrations/pushover.rb24
-rw-r--r--app/models/integrations/shimo.rb4
-rw-r--r--app/models/integrations/slack.rb4
-rw-r--r--app/models/integrations/teamcity.rb4
-rw-r--r--app/models/integrations/telegram.rb29
-rw-r--r--app/models/integrations/unify_circuit.rb6
-rw-r--r--app/models/integrations/webex_teams.rb6
-rw-r--r--app/models/integrations/zentao.rb6
-rw-r--r--app/models/issuable_severity.rb10
-rw-r--r--app/models/issue.rb54
-rw-r--r--app/models/label_link.rb2
-rw-r--r--app/models/lfs_download_object.rb2
-rw-r--r--app/models/license_template.rb6
-rw-r--r--app/models/loose_foreign_keys/modification_tracker.rb22
-rw-r--r--app/models/loose_foreign_keys/turbo_modification_tracker.rb25
-rw-r--r--app/models/members/group_member.rb13
-rw-r--r--app/models/members/project_member.rb2
-rw-r--r--app/models/merge_request.rb55
-rw-r--r--app/models/metrics/dashboard/annotation.rb34
-rw-r--r--app/models/metrics/users_starred_dashboard.rb18
-rw-r--r--app/models/milestone.rb4
-rw-r--r--app/models/ml/model_version.rb2
-rw-r--r--app/models/namespace.rb29
-rw-r--r--app/models/namespace/detail.rb1
-rw-r--r--app/models/namespace/root_storage_statistics.rb6
-rw-r--r--app/models/namespace/traversal_hierarchy.rb13
-rw-r--r--app/models/namespaces/randomized_suffix_path.rb2
-rw-r--r--app/models/note.rb24
-rw-r--r--app/models/notification_setting.rb2
-rw-r--r--app/models/operations/feature_flag.rb2
-rw-r--r--app/models/organizations/organization.rb3
-rw-r--r--app/models/packages/debian.rb8
-rw-r--r--app/models/packages/debian/file_entry.rb2
-rw-r--r--app/models/packages/dependency_link.rb28
-rw-r--r--app/models/packages/ml_model/package.rb19
-rw-r--r--app/models/packages/nuget/metadatum.rb3
-rw-r--r--app/models/packages/nuget/symbol.rb32
-rw-r--r--app/models/packages/package.rb14
-rw-r--r--app/models/packages/protection.rb9
-rw-r--r--app/models/packages/protection/rule.rb21
-rw-r--r--app/models/pages/lookup_path.rb2
-rw-r--r--app/models/pages/virtual_domain.rb27
-rw-r--r--app/models/pages_deployment.rb13
-rw-r--r--app/models/pages_domain.rb13
-rw-r--r--app/models/performance_monitoring/prometheus_metric.rb33
-rw-r--r--app/models/performance_monitoring/prometheus_panel.rb42
-rw-r--r--app/models/performance_monitoring/prometheus_panel_group.rb36
-rw-r--r--app/models/personal_access_token.rb2
-rw-r--r--app/models/plan.rb2
-rw-r--r--app/models/pool_repository.rb10
-rw-r--r--app/models/project.rb80
-rw-r--r--app/models/project_authorization.rb11
-rw-r--r--app/models/project_authorizations/changes.rb2
-rw-r--r--app/models/project_ci_cd_setting.rb1
-rw-r--r--app/models/project_feature.rb8
-rw-r--r--app/models/project_import_state.rb7
-rw-r--r--app/models/project_metrics_setting.rb16
-rw-r--r--app/models/project_setting.rb27
-rw-r--r--app/models/project_team.rb1
-rw-r--r--app/models/releases/link.rb4
-rw-r--r--app/models/repository.rb30
-rw-r--r--app/models/resource_label_event.rb9
-rw-r--r--app/models/resource_state_event.rb2
-rw-r--r--app/models/resource_timebox_event.rb2
-rw-r--r--app/models/review.rb4
-rw-r--r--app/models/self_managed_prometheus_alert_event.rb18
-rw-r--r--app/models/sent_notification.rb4
-rw-r--r--app/models/snippet_repository.rb2
-rw-r--r--app/models/terraform/state.rb2
-rw-r--r--app/models/user.rb149
-rw-r--r--app/models/user_custom_attribute.rb9
-rw-r--r--app/models/user_interacted_project.rb2
-rw-r--r--app/models/user_preference.rb1
-rw-r--r--app/models/users/callout.rb8
-rw-r--r--app/models/users/credit_card_validation.rb27
-rw-r--r--app/models/users/group_visit.rb17
-rw-r--r--app/models/users/project_callout.rb6
-rw-r--r--app/models/users/project_visit.rb17
-rw-r--r--app/models/work_item.rb30
-rw-r--r--app/models/work_items/parent_link.rb3
-rw-r--r--app/models/work_items/related_work_item_link.rb14
-rw-r--r--app/models/work_items/type.rb2
-rw-r--r--app/models/work_items/widgets/linked_items.rb2
-rw-r--r--app/models/x509_certificate.rb2
-rw-r--r--app/models/x509_issuer.rb7
-rw-r--r--app/policies/base_policy.rb6
-rw-r--r--app/policies/ci/bridge_policy.rb8
-rw-r--r--app/policies/ci/pipeline_policy.rb8
-rw-r--r--app/policies/design_management/repository_policy.rb7
-rw-r--r--app/policies/global_policy.rb5
-rw-r--r--app/policies/group_policy.rb1
-rw-r--r--app/policies/organizations/organization_policy.rb2
-rw-r--r--app/policies/organizations/organization_user_policy.rb7
-rw-r--r--app/policies/project_member_policy.rb2
-rw-r--r--app/policies/project_policy.rb6
-rw-r--r--app/presenters/blob_presenter.rb2
-rw-r--r--app/presenters/ci/build_runner_presenter.rb10
-rw-r--r--app/presenters/dev_ops_report/metric_presenter.rb20
-rw-r--r--app/presenters/event_presenter.rb25
-rw-r--r--app/presenters/gitlab/blame_presenter.rb16
-rw-r--r--app/presenters/issue_presenter.rb3
-rw-r--r--app/presenters/projects/security/configuration_presenter.rb8
-rw-r--r--app/presenters/search_service_presenter.rb2
-rw-r--r--app/serializers/activity_pub/activity_streams_serializer.rb90
-rw-r--r--app/serializers/activity_pub/project_entity.rb23
-rw-r--r--app/serializers/activity_pub/release_entity.rb40
-rw-r--r--app/serializers/activity_pub/releases_actor_entity.rb29
-rw-r--r--app/serializers/activity_pub/releases_actor_serializer.rb7
-rw-r--r--app/serializers/activity_pub/releases_outbox_serializer.rb9
-rw-r--r--app/serializers/activity_pub/user_entity.rb22
-rw-r--r--app/serializers/admin/abuse_report_details_entity.rb50
-rw-r--r--app/serializers/admin/abuse_report_entity.rb1
-rw-r--r--app/serializers/admin/reported_content_entity.rb38
-rw-r--r--app/serializers/build_details_entity.rb4
-rw-r--r--app/serializers/ci/job_annotation_entity.rb8
-rw-r--r--app/serializers/codequality_degradation_entity.rb3
-rw-r--r--app/serializers/issue_serializer.rb27
-rw-r--r--app/serializers/pipeline_serializer.rb2
-rw-r--r--app/serializers/profile/event_entity.rb31
-rw-r--r--app/services/admin/abuse_report_labels/create_service.rb17
-rw-r--r--app/services/admin/abuse_reports/moderate_user_service.rb7
-rw-r--r--app/services/admin/abuse_reports/update_service.rb32
-rw-r--r--app/services/application_settings/update_service.rb2
-rw-r--r--app/services/auth/container_registry_authentication_service.rb4
-rw-r--r--app/services/auto_merge/base_service.rb21
-rw-r--r--app/services/boards/update_service.rb2
-rw-r--r--app/services/bulk_imports/create_pipeline_trackers_service.rb72
-rw-r--r--app/services/bulk_imports/create_service.rb5
-rw-r--r--app/services/bulk_imports/file_download_service.rb10
-rw-r--r--app/services/ci/create_commit_status_service.rb158
-rw-r--r--app/services/ci/create_pipeline_service.rb7
-rw-r--r--app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb6
-rw-r--r--app/services/ci/register_job_service.rb22
-rw-r--r--app/services/ci/update_instance_variables_service.rb2
-rw-r--r--app/services/clusters/agent_tokens/track_usage_service.rb2
-rw-r--r--app/services/clusters/kubernetes/create_or_update_service_account_service.rb12
-rw-r--r--app/services/commits/create_service.rb7
-rw-r--r--app/services/compare_service.rb5
-rw-r--r--app/services/concerns/alert_management/alert_processing.rb2
-rw-r--r--app/services/concerns/rate_limited_service.rb8
-rw-r--r--app/services/concerns/service_desk/custom_emails/logger.rb41
-rw-r--r--app/services/concerns/update_repository_storage_methods.rb12
-rw-r--r--app/services/design_management/copy_design_collection/copy_service.rb4
-rw-r--r--app/services/design_management/delete_designs_service.rb6
-rw-r--r--app/services/design_management/runs_design_actions.rb10
-rw-r--r--app/services/design_management/save_designs_service.rb8
-rw-r--r--app/services/error_tracking/base_service.rb6
-rw-r--r--app/services/event_create_service.rb12
-rw-r--r--app/services/feature_flags/base_service.rb2
-rw-r--r--app/services/files/multi_service.rb2
-rw-r--r--app/services/files/update_service.rb22
-rw-r--r--app/services/google_cloud/create_cloudsql_instance_service.rb38
-rw-r--r--app/services/google_cloud/fetch_google_ip_list_service.rb8
-rw-r--r--app/services/google_cloud/generate_pipeline_service.rb8
-rw-r--r--app/services/gpg_keys/destroy_service.rb15
-rw-r--r--app/services/groups/create_service.rb12
-rw-r--r--app/services/groups/destroy_service.rb7
-rw-r--r--app/services/groups/ssh_certificates/create_service.rb51
-rw-r--r--app/services/groups/ssh_certificates/destroy_service.rb35
-rw-r--r--app/services/groups/transfer_service.rb18
-rw-r--r--app/services/groups/update_service.rb19
-rw-r--r--app/services/import/bitbucket_server_service.rb2
-rw-r--r--app/services/import/fogbugz_service.rb2
-rw-r--r--app/services/import/github/cancel_project_import_service.rb6
-rw-r--r--app/services/import/github_service.rb2
-rw-r--r--app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb2
-rw-r--r--app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb2
-rw-r--r--app/services/import/validate_remote_git_endpoint_service.rb2
-rw-r--r--app/services/import_export_clean_up_service.rb2
-rw-r--r--app/services/incident_management/pager_duty/create_incident_issue_service.rb2
-rw-r--r--app/services/incident_management/pager_duty/process_webhook_service.rb2
-rw-r--r--app/services/issuable/bulk_update_service.rb2
-rw-r--r--app/services/issuable_base_service.rb51
-rw-r--r--app/services/issuable_links/create_service.rb6
-rw-r--r--app/services/issues/base_service.rb5
-rw-r--r--app/services/issues/close_service.rb12
-rw-r--r--app/services/issues/create_service.rb11
-rw-r--r--app/services/issues/move_service.rb20
-rw-r--r--app/services/issues/relative_position_rebalancing_service.rb2
-rw-r--r--app/services/labels/available_labels_service.rb15
-rw-r--r--app/services/labels/create_service.rb4
-rw-r--r--app/services/labels/update_service.rb6
-rw-r--r--app/services/loose_foreign_keys/process_deleted_records_service.rb6
-rw-r--r--app/services/members/creator_service.rb51
-rw-r--r--app/services/members/destroy_service.rb4
-rw-r--r--app/services/merge_requests/approval_service.rb18
-rw-r--r--app/services/merge_requests/base_service.rb18
-rw-r--r--app/services/merge_requests/build_service.rb8
-rw-r--r--app/services/merge_requests/create_ref_service.rb94
-rw-r--r--app/services/merge_requests/ff_merge_service.rb31
-rw-r--r--app/services/merge_requests/merge_base_service.rb36
-rw-r--r--app/services/merge_requests/merge_service.rb97
-rw-r--r--app/services/merge_requests/merge_strategies/from_source_branch.rb4
-rw-r--r--app/services/merge_requests/merge_to_ref_service.rb8
-rw-r--r--app/services/merge_requests/refresh_service.rb4
-rw-r--r--app/services/merge_requests/update_service.rb2
-rw-r--r--app/services/metrics/global_metrics_update_service.rb24
-rw-r--r--app/services/metrics/sample_metrics_service.rb36
-rw-r--r--app/services/namespaces/in_product_marketing_emails_service.rb102
-rw-r--r--app/services/notes/create_service.rb4
-rw-r--r--app/services/notes/post_process_service.rb2
-rw-r--r--app/services/notification_recipients/builder/base.rb1
-rw-r--r--app/services/notification_service.rb20
-rw-r--r--app/services/packages/debian/generate_distribution_service.rb4
-rw-r--r--app/services/packages/npm/generate_metadata_service.rb52
-rw-r--r--app/services/packages/nuget/check_duplicates_service.rb88
-rw-r--r--app/services/packages/nuget/extract_metadata_file_service.rb15
-rw-r--r--app/services/packages/nuget/extract_remote_metadata_file_service.rb82
-rw-r--r--app/services/packages/nuget/metadata_extraction_service.rb18
-rw-r--r--app/services/packages/nuget/odata_package_entry_service.rb70
-rw-r--r--app/services/packages/nuget/update_package_from_metadata_service.rb2
-rw-r--r--app/services/preview_markdown_service.rb2
-rw-r--r--app/services/projects/apple_target_platform_detector_service.rb2
-rw-r--r--app/services/projects/container_repository/cleanup_tags_base_service.rb2
-rw-r--r--app/services/projects/container_repository/gitlab/delete_tags_service.rb2
-rw-r--r--app/services/projects/create_service.rb28
-rw-r--r--app/services/projects/destroy_service.rb6
-rw-r--r--app/services/projects/download_service.rb2
-rw-r--r--app/services/projects/hashed_storage/migrate_attachments_service.rb2
-rw-r--r--app/services/projects/import_error_filter.rb2
-rw-r--r--app/services/projects/in_product_marketing_campaign_emails_service.rb6
-rw-r--r--app/services/projects/lfs_pointers/lfs_object_download_list_service.rb4
-rw-r--r--app/services/projects/transfer_service.rb42
-rw-r--r--app/services/projects/update_pages_service.rb79
-rw-r--r--app/services/projects/update_repository_storage_service.rb4
-rw-r--r--app/services/projects/update_service.rb13
-rw-r--r--app/services/releases/destroy_service.rb10
-rw-r--r--app/services/repositories/base_service.rb2
-rw-r--r--app/services/repository_archive_clean_up_service.rb4
-rw-r--r--app/services/resource_access_tokens/create_service.rb2
-rw-r--r--app/services/resource_access_tokens/revoke_service.rb2
-rw-r--r--app/services/resource_events/base_change_timebox_service.rb2
-rw-r--r--app/services/resource_events/change_labels_service.rb2
-rw-r--r--app/services/resource_events/change_state_service.rb2
-rw-r--r--app/services/search/global_service.rb2
-rw-r--r--app/services/search/project_service.rb2
-rw-r--r--app/services/service_desk/custom_email_verifications/base_service.rb8
-rw-r--r--app/services/service_desk/custom_email_verifications/create_service.rb5
-rw-r--r--app/services/service_desk/custom_email_verifications/update_service.rb7
-rw-r--r--app/services/service_desk/custom_emails/base_service.rb3
-rw-r--r--app/services/service_desk/custom_emails/create_service.rb1
-rw-r--r--app/services/service_desk/custom_emails/destroy_service.rb1
-rw-r--r--app/services/service_desk_settings/update_service.rb7
-rw-r--r--app/services/service_response.rb22
-rw-r--r--app/services/snippets/update_service.rb2
-rw-r--r--app/services/spam/akismet_service.rb6
-rw-r--r--app/services/spam/spam_action_service.rb22
-rw-r--r--app/services/spam/spam_verdict_service.rb21
-rw-r--r--app/services/submodules/update_service.rb12
-rw-r--r--app/services/suggestions/create_service.rb26
-rw-r--r--app/services/system_notes/alert_management_service.rb4
-rw-r--r--app/services/system_notes/issuables_service.rb13
-rw-r--r--app/services/todos/destroy/destroyed_issuable_service.rb2
-rw-r--r--app/services/todos/destroy/entity_leave_service.rb2
-rw-r--r--app/services/users/activity_service.rb4
-rw-r--r--app/services/users/authorized_build_service.rb2
-rw-r--r--app/services/users/build_service.rb4
-rw-r--r--app/services/users/destroy_service.rb11
-rw-r--r--app/services/users/migrate_records_to_ghost_user_in_batches_service.rb8
-rw-r--r--app/services/users/migrate_records_to_ghost_user_service.rb2
-rw-r--r--app/services/users/refresh_authorized_projects_service.rb20
-rw-r--r--app/services/users/upsert_credit_card_validation_service.rb8
-rw-r--r--app/services/webauthn/authenticate_service.rb11
-rw-r--r--app/services/work_items/callbacks/award_emoji.rb3
-rw-r--r--app/services/work_items/create_service.rb14
-rw-r--r--app/services/work_items/related_work_item_links/create_service.rb2
-rw-r--r--app/services/work_items/related_work_item_links/destroy_service.rb85
-rw-r--r--app/uploaders/design_management/design_v432x230_uploader.rb2
-rw-r--r--app/uploaders/file_uploader.rb4
-rw-r--r--app/uploaders/gitlab_uploader.rb2
-rw-r--r--app/uploaders/packages/nuget/symbol_uploader.rb25
-rw-r--r--app/validators/addressable_url_validator.rb2
-rw-r--r--app/validators/certificate_fingerprint_validator.rb2
-rw-r--r--app/validators/duration_validator.rb2
-rw-r--r--app/validators/gitlab/zoom_url_validator.rb2
-rw-r--r--app/validators/json_schema_validator.rb4
-rw-r--r--app/validators/json_schemas/pinned_nav_items.json7
-rw-r--r--app/validators/json_schemas/scan_result_policy_project_approval_settings.json22
-rw-r--r--app/validators/line_code_validator.rb2
-rw-r--r--app/views/admin/abuse_reports/_abuse_report.html.haml39
-rw-r--r--app/views/admin/abuse_reports/index.html.haml34
-rw-r--r--app/views/admin/application_settings/_account_and_limit.html.haml21
-rw-r--r--app/views/admin/application_settings/_email.html.haml3
-rw-r--r--app/views/admin/application_settings/_gitpod.html.haml2
-rw-r--r--app/views/admin/application_settings/_import_and_export.html.haml43
-rw-r--r--app/views/admin/application_settings/_pages.html.haml19
-rw-r--r--app/views/admin/application_settings/_protected_paths.html.haml13
-rw-r--r--app/views/admin/application_settings/_search_limits.html.haml6
-rw-r--r--app/views/admin/application_settings/_sentry.html.haml8
-rw-r--r--app/views/admin/application_settings/_silent_mode_settings_form.html.haml11
-rw-r--r--app/views/admin/application_settings/_snowplow.html.haml2
-rw-r--r--app/views/admin/application_settings/_usage.html.haml21
-rw-r--r--app/views/admin/application_settings/_visibility_and_access.html.haml20
-rw-r--r--app/views/admin/application_settings/general.html.haml14
-rw-r--r--app/views/admin/dev_ops_report/_score.html.haml2
-rw-r--r--app/views/admin/groups/_form.html.haml2
-rw-r--r--app/views/admin/groups/_group.html.haml4
-rw-r--r--app/views/admin/groups/index.html.haml2
-rw-r--r--app/views/admin/groups/show.html.haml2
-rw-r--r--app/views/admin/hook_logs/show.html.haml2
-rw-r--r--app/views/admin/identities/_identity.html.haml2
-rw-r--r--app/views/admin/identities/index.html.haml3
-rw-r--r--app/views/admin/jobs/index.html.haml25
-rw-r--r--app/views/admin/topics/_form.html.haml2
-rw-r--r--app/views/admin/users/_access_levels.html.haml2
-rw-r--r--app/views/admin/users/_head.html.haml4
-rw-r--r--app/views/admin/users/_users.html.haml4
-rw-r--r--app/views/admin/users/show.html.haml4
-rw-r--r--app/views/ci/runner/_how_to_setup_runner.html.haml4
-rw-r--r--app/views/ci/variables/_variable_row.html.haml36
-rw-r--r--app/views/clusters/clusters/_provider_details_form.html.haml6
-rw-r--r--app/views/dashboard/groups/_groups.html.haml2
-rw-r--r--app/views/dashboard/groups/index.html.haml6
-rw-r--r--app/views/dashboard/todos/_todo.html.haml6
-rw-r--r--app/views/dashboard/todos/index.html.haml2
-rw-r--r--app/views/devise/sessions/_new_base.html.haml2
-rw-r--r--app/views/devise/shared/_email_opted_in.html.haml6
-rw-r--r--app/views/devise/shared/_omniauth_box.html.haml2
-rw-r--r--app/views/devise/shared/_signup_box.html.haml10
-rw-r--r--app/views/doorkeeper/authorized_applications/_delete_form.html.haml3
-rw-r--r--app/views/events/_event.atom.builder2
-rw-r--r--app/views/events/event/_push.html.haml8
-rw-r--r--app/views/explore/groups/_groups.html.haml2
-rw-r--r--app/views/explore/groups/index.html.haml5
-rw-r--r--app/views/groups/_import_group_from_another_instance_panel.html.haml16
-rw-r--r--app/views/groups/dependency_proxies/show.html.haml1
-rw-r--r--app/views/groups/edit.html.haml4
-rw-r--r--app/views/groups/group_members/index.html.haml2
-rw-r--r--app/views/groups/labels/edit.html.haml3
-rw-r--r--app/views/groups/milestones/_form.html.haml2
-rw-r--r--app/views/groups/settings/_permissions.html.haml2
-rw-r--r--app/views/groups/settings/applications/index.html.haml2
-rw-r--r--app/views/groups/work_items/index.html.haml2
-rw-r--r--app/views/groups/work_items/show.html.haml1
-rw-r--r--app/views/help/instance_configuration/_size_limits.html.haml4
-rw-r--r--app/views/import/bitbucket_server/new.html.haml3
-rw-r--r--app/views/layouts/_head.html.haml12
-rw-r--r--app/views/layouts/_page.html.haml2
-rw-r--r--app/views/layouts/_snowplow.html.haml2
-rw-r--r--app/views/layouts/application.html.haml9
-rw-r--r--app/views/layouts/errors.html.haml2
-rw-r--r--app/views/layouts/group.html.haml1
-rw-r--r--app/views/layouts/header/_current_user_dropdown.html.haml2
-rw-r--r--app/views/layouts/header/_super_sidebar_logged_out.haml2
-rw-r--r--app/views/layouts/minimal.html.haml2
-rw-r--r--app/views/layouts/oauth_error.html.haml2
-rw-r--r--app/views/layouts/organization.html.haml6
-rw-r--r--app/views/layouts/project.html.haml1
-rw-r--r--app/views/layouts/service_desk.html.haml8
-rw-r--r--app/views/layouts/terms.html.haml1
-rw-r--r--app/views/notify/in_product_marketing_email.html.haml51
-rw-r--r--app/views/notify/in_product_marketing_email.text.erb36
-rw-r--r--app/views/notify/member_access_granted_email.html.haml5
-rw-r--r--app/views/notify/member_invited_email.html.haml5
-rw-r--r--app/views/notify/new_email_address_added_email.html.haml (renamed from app/views/notify/new_email_address_added_email.haml)0
-rw-r--r--app/views/notify/new_email_address_added_email.text.erb (renamed from app/views/notify/new_email_address_added_email.erb)0
-rw-r--r--app/views/notify/resource_access_tokens_about_to_expire_email.html.haml13
-rw-r--r--app/views/notify/resource_access_tokens_about_to_expire_email.text.erb11
-rw-r--r--app/views/organizations/organizations/groups_and_projects.html.haml2
-rw-r--r--app/views/organizations/organizations/index.html.haml2
-rw-r--r--app/views/organizations/organizations/new.html.haml3
-rw-r--r--app/views/organizations/organizations/show.html.haml2
-rw-r--r--app/views/profiles/gpg_keys/index.html.haml2
-rw-r--r--app/views/profiles/keys/_key_details.html.haml2
-rw-r--r--app/views/profiles/notifications/_email_settings.html.haml3
-rw-r--r--app/views/profiles/notifications/show.html.haml4
-rw-r--r--app/views/profiles/preferences/show.html.haml9
-rw-r--r--app/views/projects/_export.html.haml4
-rw-r--r--app/views/projects/_home_panel.html.haml2
-rw-r--r--app/views/projects/_invite_members_empty_project.html.haml2
-rw-r--r--app/views/projects/_merge_request_merge_checks_settings.html.haml8
-rw-r--r--app/views/projects/_merge_request_merge_commit_template.html.haml14
-rw-r--r--app/views/projects/_merge_request_merge_options_settings.html.haml14
-rw-r--r--app/views/projects/_merge_request_merge_suggestions_settings.html.haml14
-rw-r--r--app/views/projects/_merge_request_settings.html.haml18
-rw-r--r--app/views/projects/_merge_request_squash_commit_template.html.haml14
-rw-r--r--app/views/projects/_service_desk_settings.html.haml2
-rw-r--r--app/views/projects/_transfer.html.haml8
-rw-r--r--app/views/projects/activity.html.haml2
-rw-r--r--app/views/projects/artifacts/_tree_directory.html.haml2
-rw-r--r--app/views/projects/blob/_header_content.html.haml2
-rw-r--r--app/views/projects/blob/viewers/_markup.html.haml2
-rw-r--r--app/views/projects/blob/viewers/_metrics_dashboard_yml.html.haml2
-rw-r--r--app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml2
-rw-r--r--app/views/projects/branch_defaults/_branch_names_fields.html.haml2
-rw-r--r--app/views/projects/branch_defaults/_default_branch_fields.html.haml3
-rw-r--r--app/views/projects/buttons/_clone.html.haml4
-rw-r--r--app/views/projects/commit/_commit_box.html.haml3
-rw-r--r--app/views/projects/commit/_signature_badge.html.haml6
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/compare/index.html.haml2
-rw-r--r--app/views/projects/deployments/_commit.html.haml17
-rw-r--r--app/views/projects/deployments/_deployment.html.haml49
-rw-r--r--app/views/projects/deployments/_rollback.haml4
-rw-r--r--app/views/projects/diffs/_file_header.html.haml4
-rw-r--r--app/views/projects/edit.html.haml6
-rw-r--r--app/views/projects/environments/show.html.haml31
-rw-r--r--app/views/projects/hook_logs/show.html.haml2
-rw-r--r--app/views/projects/incidents/show.html.haml12
-rw-r--r--app/views/projects/issuable/_show.html.haml10
-rw-r--r--app/views/projects/issues/_details_content.html.haml47
-rw-r--r--app/views/projects/issues/_emoji_block.html.haml (renamed from app/views/shared/issue_type/_emoji_block.html.haml)0
-rw-r--r--app/views/projects/issues/_related_issues.html.haml1
-rw-r--r--app/views/projects/issues/_sentry_stack_trace.html.haml (renamed from app/views/shared/issue_type/_sentry_stack_trace.html.haml)0
-rw-r--r--app/views/projects/issues/service_desk.html.haml3
-rw-r--r--app/views/projects/issues/service_desk/_issue.html.haml4
-rw-r--r--app/views/projects/issues/show.html.haml12
-rw-r--r--app/views/projects/jobs/_table.html.haml37
-rw-r--r--app/views/projects/labels/edit.html.haml3
-rw-r--r--app/views/projects/labels/index.html.haml1
-rw-r--r--app/views/projects/merge_requests/_code_dropdown.html.haml8
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml4
-rw-r--r--app/views/projects/merge_requests/_mr_title.html.haml2
-rw-r--r--app/views/projects/merge_requests/_page.html.haml7
-rw-r--r--app/views/projects/merge_requests/creations/_new_compare.html.haml4
-rw-r--r--app/views/projects/merge_requests/creations/_new_submit.html.haml2
-rw-r--r--app/views/projects/merge_requests/tabs/_tab.html.haml4
-rw-r--r--app/views/projects/milestones/_form.html.haml2
-rw-r--r--app/views/projects/mirrors/_authentication_method.html.haml11
-rw-r--r--app/views/projects/mirrors/_instructions.html.haml2
-rw-r--r--app/views/projects/mirrors/_mirror_repos.html.haml2
-rw-r--r--app/views/projects/mirrors/_mirror_repos_form.html.haml2
-rw-r--r--app/views/projects/mirrors/_mirror_repos_list.html.haml2
-rw-r--r--app/views/projects/new.html.haml5
-rw-r--r--app/views/projects/notes/_more_actions_dropdown.html.haml2
-rw-r--r--app/views/projects/pages/_pages_settings.html.haml17
-rw-r--r--app/views/projects/pages_domains/_dns.html.haml4
-rw-r--r--app/views/projects/pipeline_schedules/_form.html.haml43
-rw-r--r--app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml45
-rw-r--r--app/views/projects/pipeline_schedules/_table.html.haml12
-rw-r--r--app/views/projects/pipeline_schedules/_tabs.html.haml12
-rw-r--r--app/views/projects/pipeline_schedules/edit.html.haml6
-rw-r--r--app/views/projects/pipeline_schedules/index.html.haml26
-rw-r--r--app/views/projects/pipeline_schedules/new.html.haml6
-rw-r--r--app/views/projects/project_members/index.html.haml4
-rw-r--r--app/views/projects/protected_tags/_create_protected_tag.html.haml6
-rw-r--r--app/views/projects/protected_tags/_protected_tag_create_access_levels.haml5
-rw-r--r--app/views/projects/settings/access_tokens/index.html.haml5
-rw-r--r--app/views/projects/settings/ci_cd/show.html.haml11
-rw-r--r--app/views/projects/settings/integrations/_form.html.haml5
-rw-r--r--app/views/projects/settings/integrations/index.html.haml6
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_merge_checks_settings.html.haml8
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml13
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_merge_method_settings.html.haml (renamed from app/views/projects/_merge_request_merge_method_settings.html.haml)0
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_merge_options_settings.html.haml14
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml13
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_pipelines_and_threads_options.html.haml (renamed from app/views/projects/_merge_request_pipelines_and_threads_options.html.haml)0
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_settings.html.haml18
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_settings_description_text.html.haml (renamed from app/views/projects/_merge_request_settings_description_text.html.haml)0
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml13
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_squash_options_settings.html.haml (renamed from app/views/projects/_merge_request_squash_options_settings.html.haml)0
-rw-r--r--app/views/projects/settings/merge_requests/_merge_request_target_project_settings.html.haml (renamed from app/views/projects/_merge_request_target_project_settings.html.haml)0
-rw-r--r--app/views/projects/settings/merge_requests/show.html.haml5
-rw-r--r--app/views/projects/settings/operations/_alert_management.html.haml2
-rw-r--r--app/views/projects/show.html.haml1
-rw-r--r--app/views/projects/tags/new.html.haml5
-rw-r--r--app/views/projects/tracing/index.html.haml4
-rw-r--r--app/views/projects/tracing/show.html.haml5
-rw-r--r--app/views/projects/usage_quotas/index.html.haml3
-rw-r--r--app/views/protected_branches/_create_protected_branch.html.haml11
-rw-r--r--app/views/protected_branches/shared/_index.html.haml7
-rw-r--r--app/views/protected_branches/shared/_update_protected_branch.html.haml8
-rw-r--r--app/views/registrations/welcome/show.html.haml2
-rw-r--r--app/views/repository_check_mailer/notify.html.haml2
-rw-r--r--app/views/repository_check_mailer/notify.text.haml2
-rw-r--r--app/views/search/_results.html.haml2
-rw-r--r--app/views/search/_results_list.html.haml2
-rw-r--r--app/views/search/_results_status.html.haml53
-rw-r--r--app/views/search/show.html.haml4
-rw-r--r--app/views/shared/_clone_panel.html.haml2
-rw-r--r--app/views/shared/_label_row.html.haml3
-rw-r--r--app/views/shared/_logo.svg2
-rw-r--r--app/views/shared/_mobile_clone_panel.html.haml2
-rw-r--r--app/views/shared/_outdated_browser.html.haml4
-rw-r--r--app/views/shared/_silent_mode_banner.html.haml9
-rw-r--r--app/views/shared/_visibility_level.html.haml5
-rw-r--r--app/views/shared/builds/_build_output.html.haml6
-rw-r--r--app/views/shared/builds/_tabs.html.haml15
-rw-r--r--app/views/shared/deploy_keys/_index.html.haml4
-rw-r--r--app/views/shared/deploy_keys/_project_group_form.html.haml26
-rw-r--r--app/views/shared/deploy_tokens/_form.html.haml5
-rw-r--r--app/views/shared/deploy_tokens/_new_deploy_token.html.haml4
-rw-r--r--app/views/shared/doorkeeper/applications/_show.html.haml2
-rw-r--r--app/views/shared/form_elements/_description.html.haml2
-rw-r--r--app/views/shared/groups/_empty_state.html.haml8
-rw-r--r--app/views/shared/hook_logs/_content.html.haml33
-rw-r--r--app/views/shared/icons/_icon_empty_groups.svg1
-rw-r--r--app/views/shared/integrations/mattermost_slash_commands/_detailed_help.html.haml43
-rw-r--r--app/views/shared/integrations/mattermost_slash_commands/_installation_info.html.haml8
-rw-r--r--app/views/shared/integrations/prometheus/_custom_metrics.html.haml1
-rw-r--r--app/views/shared/integrations/prometheus/_metrics.html.haml4
-rw-r--r--app/views/shared/integrations/slack_slash_commands/_help.html.haml10
-rw-r--r--app/views/shared/issuable/_form.html.haml7
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml6
-rw-r--r--app/views/shared/issuable/_sidebar_assignees.html.haml2
-rw-r--r--app/views/shared/issuable/_sidebar_reviewers.html.haml2
-rw-r--r--app/views/shared/issuable/_status_box.html.haml3
-rw-r--r--app/views/shared/issuable/form/_default_templates.html.haml5
-rw-r--r--app/views/shared/issuable/form/_title.html.haml2
-rw-r--r--app/views/shared/issue_type/_details_content.html.haml46
-rw-r--r--app/views/shared/issue_type/_details_header.html.haml21
-rw-r--r--app/views/shared/labels/_form.html.haml9
-rw-r--r--app/views/shared/members/_access_request_links.html.haml2
-rw-r--r--app/views/shared/milestones/_sidebar.html.haml4
-rw-r--r--app/views/shared/packages/_no_packages.html.haml5
-rw-r--r--app/views/shared/projects/_project.html.haml4
-rw-r--r--app/views/shared/web_hooks/_hook_errors.html.haml19
-rw-r--r--app/views/shared/web_hooks/_title_and_docs.html.haml8
-rw-r--r--app/views/users/_deletion_guidance.html.haml4
-rw-r--r--app/views/users/_profile_basic_info.html.haml2
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--app/workers/all_queues.yml97
-rw-r--r--app/workers/background_migration/single_database_worker.rb5
-rw-r--r--app/workers/build_success_worker.rb12
-rw-r--r--app/workers/bulk_import_worker.rb55
-rw-r--r--app/workers/bulk_imports/finish_project_import_worker.rb20
-rw-r--r--app/workers/click_house/events_sync_worker.rb93
-rw-r--r--app/workers/concerns/gitlab/bitbucket_import/object_importer.rb98
-rw-r--r--app/workers/concerns/gitlab/bitbucket_import/stage_methods.rb76
-rw-r--r--app/workers/concerns/gitlab/bitbucket_server_import/object_importer.rb4
-rw-r--r--app/workers/concerns/gitlab/github_import/object_importer.rb4
-rw-r--r--app/workers/concerns/gitlab/github_import/rescheduling_methods.rb2
-rw-r--r--app/workers/concerns/gitlab/github_import/stage_methods.rb2
-rw-r--r--app/workers/concerns/gitlab/import/notify_upon_death.rb32
-rw-r--r--app/workers/concerns/gitlab/notify_upon_death.rb29
-rw-r--r--app/workers/database/batched_background_migration/execution_worker.rb2
-rw-r--r--app/workers/database/batched_background_migration/single_database_worker.rb2
-rw-r--r--app/workers/database/lock_tables_worker.rb66
-rw-r--r--app/workers/database/monitor_locked_tables_worker.rb7
-rw-r--r--app/workers/environments/stop_job_success_worker.rb8
-rw-r--r--app/workers/gitlab/bitbucket_import/advance_stage_worker.rb37
-rw-r--r--app/workers/gitlab/bitbucket_import/import_pull_request_worker.rb13
-rw-r--r--app/workers/gitlab/bitbucket_import/stage/finish_import_worker.rb19
-rw-r--r--app/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker.rb30
-rw-r--r--app/workers/gitlab/bitbucket_import/stage/import_repository_worker.rb29
-rw-r--r--app/workers/gitlab/github_gists_import/import_gist_worker.rb4
-rw-r--r--app/workers/gitlab/import/advance_stage.rb16
-rw-r--r--app/workers/gitlab/jira_import/import_issue_worker.rb4
-rw-r--r--app/workers/incident_management/close_incident_worker.rb2
-rw-r--r--app/workers/incident_management/process_alert_worker_v2.rb2
-rw-r--r--app/workers/loose_foreign_keys/cleanup_worker.rb24
-rw-r--r--app/workers/members_destroyer/unassign_issuables_worker.rb2
-rw-r--r--app/workers/merge_requests/ensure_prepared_worker.rb34
-rw-r--r--app/workers/merge_worker.rb2
-rw-r--r--app/workers/metrics/global_metrics_update_worker.rb4
-rw-r--r--app/workers/namespaces/in_product_marketing_emails_worker.rb33
-rw-r--r--app/workers/new_merge_request_worker.rb5
-rw-r--r--app/workers/pages/invalidate_domain_cache_worker.rb37
-rw-r--r--app/workers/personal_access_tokens/expiring_worker.rb16
-rw-r--r--app/workers/post_receive.rb2
-rw-r--r--app/workers/projects/inactive_projects_deletion_cron_worker.rb2
-rw-r--r--app/workers/projects/record_target_platforms_worker.rb4
-rw-r--r--app/workers/users/deactivate_dormant_users_worker.rb2
-rw-r--r--app/workers/users/track_namespace_visits_worker.rb30
-rw-r--r--app/workers/x509_issuer_crl_check_worker.rb2
-rwxr-xr-xbin/vite27
-rw-r--r--config/application.rb40
-rw-r--r--config/boot.rb2
-rw-r--r--config/database.yml.decomposed-clusterwide-postgresql5
-rw-r--r--config/database.yml.decomposed-postgresql4
-rw-r--r--config/database.yml.postgresql4
-rw-r--r--config/environments/production.rb2
-rw-r--r--config/events/202109151015_groups__email_campaigns_controller_click.yml20
-rw-r--r--config/events/p_analytics_ci_cd_deployment_frequency.yml24
-rw-r--r--config/events/p_analytics_ci_cd_lead_time.yml24
-rw-r--r--config/events/p_analytics_ci_cd_pipelines.yml24
-rw-r--r--config/feature_categories.yml7
-rw-r--r--config/feature_flags/development/abuse_report_labels.yml8
-rw-r--r--config/feature_flags/development/abuse_reports_list.yml8
-rw-r--r--config/feature_flags/development/action_cable_notes.yml8
-rw-r--r--config/feature_flags/development/activity_pub.yml8
-rw-r--r--config/feature_flags/development/activity_pub_project.yml8
-rw-r--r--config/feature_flags/development/add_prepared_state_to_mr.yml8
-rw-r--r--config/feature_flags/development/admin_jobs_vue.yml8
-rw-r--r--config/feature_flags/development/advanced_search_decrease_indexing_timeout.yml8
-rw-r--r--config/feature_flags/development/ai_tool_info.yml8
-rw-r--r--config/feature_flags/development/anthropic_experimentation.yml8
-rw-r--r--config/feature_flags/development/api_keyset_pagination_multi_order.yml8
-rw-r--r--config/feature_flags/development/batched_api_mergeability_checks.yml8
-rw-r--r--config/feature_flags/development/bitbucket_parallel_importer.yml8
-rw-r--r--config/feature_flags/development/bitbucket_server_parallel_importer.yml8
-rw-r--r--config/feature_flags/development/browsersdk_tracking.yml8
-rw-r--r--config/feature_flags/development/cache_pages_domain_api.yml8
-rw-r--r--config/feature_flags/development/ci_editor_assistant_tool.yml8
-rw-r--r--config/feature_flags/development/ci_partitioning_use_ci_builds_routing_table.yml8
-rw-r--r--config/feature_flags/development/ci_refactor_external_rules.yml8
-rw-r--r--config/feature_flags/development/clickhouse_ci_analytics.yml8
-rw-r--r--config/feature_flags/development/code_quality_inline_drawer.yml8
-rw-r--r--config/feature_flags/development/code_suggestions_tokens_from_customers_dot.yml8
-rw-r--r--config/feature_flags/development/collect_all_diff_paths.yml8
-rw-r--r--config/feature_flags/development/combined_analytics_visualization_editor.yml8
-rw-r--r--config/feature_flags/development/command_palette.yml8
-rw-r--r--config/feature_flags/development/compliance_pipeline_in_policies.yml8
-rw-r--r--config/feature_flags/development/composer_use_ssh_source_urls.yml8
-rw-r--r--config/feature_flags/development/copy_additional_properties_approval_rules.yml8
-rw-r--r--config/feature_flags/development/create_embeddings_with_vertex_ai.yml8
-rw-r--r--config/feature_flags/development/custom_roles_in_members_page.yml8
-rw-r--r--config/feature_flags/development/custom_roles_ui_saas.yml8
-rw-r--r--config/feature_flags/development/database_analyze_on_partitioned_tables.yml8
-rw-r--r--config/feature_flags/development/emoji_webhooks.yml2
-rw-r--r--config/feature_flags/development/ensure_merge_requests_prepared.yml8
-rw-r--r--config/feature_flags/development/environment_details_vue.yml8
-rw-r--r--config/feature_flags/development/epic_relations_for_non_members.yml8
-rw-r--r--config/feature_flags/development/errors_utf_8_encoding.yml8
-rw-r--r--config/feature_flags/development/explain_vulnerability_anthropic.yml8
-rw-r--r--config/feature_flags/development/explain_vulnerability_vertex.yml8
-rw-r--r--config/feature_flags/development/fill_in_mr_template.yml2
-rw-r--r--config/feature_flags/development/flux_resource_for_environment.yml8
-rw-r--r--config/feature_flags/development/graphql_git_blame.yml8
-rw-r--r--config/feature_flags/development/graphql_job_trace_html_summary_max_size.yml7
-rw-r--r--config/feature_flags/development/group_mentions.yml8
-rw-r--r--config/feature_flags/development/harbor_registry_integration.yml8
-rw-r--r--config/feature_flags/development/introduce_ci_max_total_yaml_size_bytes.yml8
-rw-r--r--config/feature_flags/development/k8s_dashboard.yml8
-rw-r--r--config/feature_flags/development/k8s_proxy_pat.yml8
-rw-r--r--config/feature_flags/development/keep_merge_commits_for_approvals.yml8
-rw-r--r--config/feature_flags/development/limited_access_modal.yml8
-rw-r--r--config/feature_flags/development/loose_foreign_keys_batch_load_using_union.yml2
-rw-r--r--config/feature_flags/development/lower_interval_for_canceling_redundant_pipelines.yml8
-rw-r--r--config/feature_flags/development/member_expiring_email_notification.yml2
-rw-r--r--config/feature_flags/development/merge_request_refs_cleanup.yml2
-rw-r--r--config/feature_flags/development/merge_trains_create_ref_service.yml2
-rw-r--r--config/feature_flags/development/merge_trains_skip_train.yml8
-rw-r--r--config/feature_flags/development/mr_pipelines_graphql.yml8
-rw-r--r--config/feature_flags/development/namespace_storage_forks_cost_factor.yml8
-rw-r--r--config/feature_flags/development/new_graphql_users_autocomplete.yml8
-rw-r--r--config/feature_flags/development/npm_package_registry_fix_group_path_validation.yml8
-rw-r--r--config/feature_flags/development/nuget_normalized_version.yml8
-rw-r--r--config/feature_flags/development/okr_checkin_reminders.yml8
-rw-r--r--config/feature_flags/development/optimize_group_template_query.yml8
-rw-r--r--config/feature_flags/development/optimize_routable.yml8
-rw-r--r--config/feature_flags/development/pages_multiple_versions_setting.yml8
-rw-r--r--config/feature_flags/development/pipeline_schedules_vue.yml8
-rw-r--r--config/feature_flags/development/post_import_repository_size_check.yml8
-rw-r--r--config/feature_flags/development/prevent_visibility_restriction.yml2
-rw-r--r--config/feature_flags/development/product_analytics_snowplow_support.yml8
-rw-r--r--config/feature_flags/development/project_runners_vue_ui.yml8
-rw-r--r--config/feature_flags/development/refactor_merge_service.yml8
-rw-r--r--config/feature_flags/development/resolvable_issue_threads.yml2
-rw-r--r--config/feature_flags/development/resolve_organization_groups.yml8
-rw-r--r--config/feature_flags/development/review_apps_redeploy_mr_widget.yml8
-rw-r--r--config/feature_flags/development/scan_execution_bot_users.yml8
-rw-r--r--config/feature_flags/development/search_index_integrity.yml8
-rw-r--r--config/feature_flags/development/search_issues_hide_archived_projects.yml8
-rw-r--r--config/feature_flags/development/search_milestones_hide_archived_projects.yml9
-rw-r--r--config/feature_flags/development/search_projects_hide_archived.yml8
-rw-r--r--config/feature_flags/development/self_managed_code_suggestions_completion_api.yml8
-rw-r--r--config/feature_flags/development/server_side_frecent_namespaces.yml8
-rw-r--r--config/feature_flags/development/service_desk_custom_email.yml2
-rw-r--r--config/feature_flags/development/service_desk_custom_email_reply.yml8
-rw-r--r--config/feature_flags/development/skip_validations_during_transitions.yml8
-rw-r--r--config/feature_flags/development/ssh_certificates_rest_endpoints.yml8
-rw-r--r--config/feature_flags/development/standard_merge_train_ref_merge_commit.yml8
-rw-r--r--config/feature_flags/development/summarize_review_vertex.yml8
-rw-r--r--config/feature_flags/development/super_sidebar_flyout_menus.yml8
-rw-r--r--config/feature_flags/development/ultimate_feature_removal_banner.yml8
-rw-r--r--config/feature_flags/development/unbatch_graphql_queries.yml2
-rw-r--r--config/feature_flags/development/use_merge_approval_rules_when_merged.yml8
-rw-r--r--config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml4
-rw-r--r--config/feature_flags/development/use_primary_and_secondary_stores_for_action_cable.yml8
-rw-r--r--config/feature_flags/development/use_primary_and_secondary_stores_for_etag_cache.yml8
-rw-r--r--config/feature_flags/development/use_primary_and_secondary_stores_for_queues_metadata.yml8
-rw-r--r--config/feature_flags/development/use_primary_and_secondary_stores_for_workhorse.yml8
-rw-r--r--config/feature_flags/development/use_primary_store_as_default_for_action_cable.yml8
-rw-r--r--config/feature_flags/development/use_primary_store_as_default_for_etag_cache.yml8
-rw-r--r--config/feature_flags/development/use_primary_store_as_default_for_queues_metadata.yml8
-rw-r--r--config/feature_flags/development/use_primary_store_as_default_for_workhorse.yml8
-rw-r--r--config/feature_flags/development/value_stream_dashboard_on_off_setting.yml2
-rw-r--r--config/feature_flags/development/vite.yml8
-rw-r--r--config/feature_flags/development/vulnerability_report_grouping.yml8
-rw-r--r--config/feature_flags/ops/admin_jobs_filter_runner_type.yml8
-rw-r--r--config/feature_flags/ops/disallow_database_ddl_feature_flags.yml8
-rw-r--r--config/feature_flags/ops/lock_tables_in_monitoring.yml8
-rw-r--r--config/feature_flags/ops/loose_foreign_keys_turbo_mode_ci.yml8
-rw-r--r--config/feature_flags/ops/loose_foreign_keys_turbo_mode_main.yml8
-rw-r--r--config/gitlab.yml.example2
-rw-r--r--config/gitlab_loose_foreign_keys.yml32
-rw-r--r--config/initializers/00_active_record_disable_cross_database.rb11
-rw-r--r--config/initializers/00_deprecations.rb5
-rw-r--r--config/initializers/1_database_single_connection.rb3
-rw-r--r--config/initializers/1_postgresql_only.rb2
-rw-r--r--config/initializers/1_settings.rb34
-rw-r--r--config/initializers/8_devise.rb8
-rw-r--r--config/initializers/action_cable.rb5
-rw-r--r--config/initializers/click_house.rb21
-rw-r--r--config/initializers/content_security_policy.rb2
-rw-r--r--config/initializers/declarative_policy_cached_attributes.rb25
-rw-r--r--config/initializers/doorkeeper.rb10
-rw-r--r--config/initializers/enumerator_next_patch.rb4
-rw-r--r--config/initializers/fog_core_patch.rb2
-rw-r--r--config/initializers/forbid_sidekiq_in_transactions.rb4
-rw-r--r--config/initializers/health_check.rb4
-rw-r--r--config/initializers/invisible_captcha.rb2
-rw-r--r--config/initializers/licensee_license_patch.rb14
-rw-r--r--config/initializers/lograge.rb2
-rw-r--r--config/initializers/mail_starttls_patch.rb2
-rw-r--r--config/initializers/postgres_partitioning.rb4
-rw-r--r--config/initializers/rspec_profiling.rb4
-rw-r--r--config/initializers/session_store.rb14
-rw-r--r--config/initializers/sidekiq.rb5
-rw-r--r--config/initializers/warden.rb2
-rw-r--r--config/initializers_before_autoloader/000_inflections.rb5
-rw-r--r--config/locales/doorkeeper.en.yml8
-rw-r--r--config/locales/en.yml2
-rw-r--r--config/metrics/counts_28d/20210216175000_i_analytics_dev_ops_score_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216175004_g_analytics_merge_request_monthly.yml4
-rw-r--r--config/metrics/counts_28d/20210216175055_merge_requests.yml1
-rw-r--r--config/metrics/counts_28d/20210216175109_suggestions.yml1
-rw-r--r--config/metrics/counts_28d/20210216175132_i_code_review_user_create_mr_monthly.yml3
-rw-r--r--config/metrics/counts_28d/20210216175405_clusters_applications_cert_managers.yml1
-rw-r--r--config/metrics/counts_28d/20210216175407_clusters_applications_helm.yml1
-rw-r--r--config/metrics/counts_28d/20210216175409_clusters_applications_ingress.yml1
-rw-r--r--config/metrics/counts_28d/20210216175411_clusters_applications_knative.yml1
-rw-r--r--config/metrics/counts_28d/20210216180319_action_monthly_active_users_web_ide_edit.yml2
-rw-r--r--config/metrics/counts_28d/20210216180321_action_monthly_active_users_sfe_edit.yml2
-rw-r--r--config/metrics/counts_28d/20210216180323_action_monthly_active_users_snippet_editor_edit.yml2
-rw-r--r--config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml1
-rw-r--r--config/metrics/counts_28d/20210216180330_g_edit_by_web_ide_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216180338_g_edit_by_snippet_ide_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216180341_ide_edit_total_unique_counts_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20210216180955_projects_with_prometheus_alerts.yml1
-rw-r--r--config/metrics/counts_28d/20210216180958_clusters_applications_prometheus.yml1
-rw-r--r--config/metrics/counts_28d/20210216181304_g_project_management_issue_title_changed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181308_g_project_management_issue_description_changed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181311_g_project_management_issue_assignee_changed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181315_g_project_management_issue_made_confidential_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181319_g_project_management_issue_made_visible_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181326_g_project_management_issue_closed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181330_g_project_management_issue_reopened_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181334_g_project_management_issue_label_changed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181348_g_project_management_issue_cross_referenced_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181352_g_project_management_issue_moved_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181356_g_project_management_issue_related_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181400_g_project_management_issue_unrelated_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181403_g_project_management_issue_marked_as_duplicate_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181407_g_project_management_issue_locked_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181411_g_project_management_issue_unlocked_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181424_g_project_management_issue_designs_added_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181427_g_project_management_issue_designs_modified_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181431_g_project_management_issue_designs_removed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181435_g_project_management_issue_due_date_changed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181438_g_project_management_issue_time_estimate_changed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181442_g_project_management_issue_time_spent_changed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181446_g_project_management_issue_comment_added_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181450_g_project_management_issue_comment_edited_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181453_g_project_management_issue_comment_removed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181501_g_project_management_issue_cloned_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20210216181951_clusters_applications_runner.yml1
-rw-r--r--config/metrics/counts_28d/20210216183203_product_analytics_test_metrics_union.yml1
-rw-r--r--config/metrics/counts_28d/20210216183205_product_analytics_test_metrics_intersection.yml1
-rw-r--r--config/metrics/counts_28d/20210216183640_gitlab.yml2
-rw-r--r--config/metrics/counts_28d/20210216183646_gitlab.yml1
-rw-r--r--config/metrics/counts_28d/20210216183712_total.yml2
-rw-r--r--config/metrics/counts_28d/20210216183714_gitlab_project.yml2
-rw-r--r--config/metrics/counts_28d/20210216183716_gitlab.yml2
-rw-r--r--config/metrics/counts_28d/20210216183718_github.yml2
-rw-r--r--config/metrics/counts_28d/20210216183720_bitbucket.yml2
-rw-r--r--config/metrics/counts_28d/20210216183722_bitbucket_server.yml2
-rw-r--r--config/metrics/counts_28d/20210216183724_gitea.yml2
-rw-r--r--config/metrics/counts_28d/20210216183726_git.yml2
-rw-r--r--config/metrics/counts_28d/20210216183728_manifest.yml2
-rw-r--r--config/metrics/counts_28d/20210216183730_jira.yml2
-rw-r--r--config/metrics/counts_28d/20210216183731_fogbugz.yml2
-rw-r--r--config/metrics/counts_28d/20210216183733_phabricator.yml2
-rw-r--r--config/metrics/counts_28d/20210216183735_csv.yml2
-rw-r--r--config/metrics/counts_28d/20210216183737_groups_imported.yml2
-rw-r--r--config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184502_p_ci_templates_implicit_auto_devops_build_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20210216184506_p_ci_templates_implicit_auto_devops_deploy_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20210216184517_p_ci_templates_5_min_production_app_monthly.yml3
-rw-r--r--config/metrics/counts_28d/20210216184526_p_ci_templates_aws_cf_deploy_ec2_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20210216184534_p_ci_templates_auto_devops_build_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20210216184538_p_ci_templates_auto_devops_deploy_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20210216184542_p_ci_templates_auto_devops_deploy_latest_monthly.yml1
-rwxr-xr-xconfig/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184814_i_package_container_deploy_token_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184818_i_package_debian_deploy_token_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184826_i_package_golang_deploy_token_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184846_i_package_tag_deploy_token_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184902_i_package_container_user_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184906_i_package_debian_user_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184913_i_package_golang_user_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184933_i_package_tag_user_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml1
-rw-r--r--config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml1
-rw-r--r--config/metrics/counts_28d/20210902000813_p_ci_templates_implicit_auto_devops_deploy_latest_monthly.yml1
-rw-r--r--config/metrics/counts_28d/20211126084446_p_analytics_ci_cd_pipelines_monthly.yml3
-rw-r--r--config/metrics/counts_28d/20211126090835_p_analytics_ci_cd_deployment_frequency_monthly.yml3
-rw-r--r--config/metrics/counts_28d/20211126091206_p_analytics_ci_cd_lead_time_monthly.yml3
-rw-r--r--config/metrics/counts_28d/20220428154012_live_preview.yml4
-rw-r--r--config/metrics/counts_28d/20220525231314_unique_monthly_active_users.yml1
-rw-r--r--config/metrics/counts_28d/20221213182900_i_code_review_create_mr_monthly.yml3
-rw-r--r--config/metrics/counts_28d/20230105222225_g_project_management_issue_design_comments_removed_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20230531170613_ci_builds.yml3
-rw-r--r--config/metrics/counts_28d/20230724140653_i_code_review_saved_replies_create_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20230725194658_i_code_review_saved_replies_use_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20230809194743_i_code_review_saved_replies_use_in_mr_monthly.yml5
-rw-r--r--config/metrics/counts_28d/20230810124157_count_cicd_component_usage_monthly.yml23
-rw-r--r--config/metrics/counts_28d/20230815171559_i_code_review_saved_replies_use_in_other_monthly.yml28
-rw-r--r--config/metrics/counts_28d/20230816085153_k8s_api_proxy_requests_unique_agents_via_pat_access_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20230816085153_k8s_api_proxy_requests_unique_users_via_pat_access_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20230830153031_p_ci_templates_cosign_monthly.yml25
-rw-r--r--config/metrics/counts_7d/20210201124931_g_project_management_issue_title_changed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216174900_i_analytics_dev_ops_score.yml5
-rw-r--r--config/metrics/counts_7d/20210216174902_g_analytics_merge_request.yml2
-rw-r--r--config/metrics/counts_7d/20210216180328_g_edit_by_web_ide_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216180336_g_edit_by_snippet_ide_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20210216181306_g_project_management_issue_description_changed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181310_g_project_management_issue_assignee_changed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181313_g_project_management_issue_made_confidential_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181317_g_project_management_issue_made_visible_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181324_g_project_management_issue_closed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181328_g_project_management_issue_reopened_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181332_g_project_management_issue_label_changed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181336_g_project_management_issue_milestone_changed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181347_g_project_management_issue_cross_referenced_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181350_g_project_management_issue_moved_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181354_g_project_management_issue_related_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181358_g_project_management_issue_unrelated_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181401_g_project_management_issue_marked_as_duplicate_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181405_g_project_management_issue_locked_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181409_g_project_management_issue_unlocked_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181422_g_project_management_issue_designs_added_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181425_g_project_management_issue_designs_modified_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181429_g_project_management_issue_designs_removed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181433_g_project_management_issue_due_date_changed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181437_g_project_management_issue_time_estimate_changed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181440_g_project_management_issue_time_spent_changed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181444_g_project_management_issue_comment_added_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181448_g_project_management_issue_comment_edited_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181451_g_project_management_issue_comment_removed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216181459_g_project_management_issue_cloned_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216183213_product_analytics_test_metrics_union.yml1
-rw-r--r--config/metrics/counts_7d/20210216183215_product_analytics_test_metrics_intersection.yml1
-rw-r--r--config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml4
-rw-r--r--config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184500_p_ci_templates_implicit_auto_devops_build_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20210216184504_p_ci_templates_implicit_auto_devops_deploy_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20210216184515_p_ci_templates_5_min_production_app_weekly.yml3
-rw-r--r--config/metrics/counts_7d/20210216184524_p_ci_templates_aws_cf_deploy_ec2_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20210216184536_p_ci_templates_auto_devops_deploy_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20210216184540_p_ci_templates_auto_devops_deploy_latest_weekly.yml1
-rwxr-xr-xconfig/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184805_i_package_composer_deploy_token_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184812_i_package_container_deploy_token_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184816_i_package_debian_deploy_token_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184824_i_package_golang_deploy_token_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184844_i_package_tag_deploy_token_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184900_i_package_container_user_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184904_i_package_debian_user_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184911_i_package_golang_user_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184931_i_package_tag_user_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210423005644_i_analytics_dev_ops_adoption.yml5
-rw-r--r--config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml1
-rw-r--r--config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml1
-rw-r--r--config/metrics/counts_7d/20210902000809_p_ci_templates_implicit_auto_devops_deploy_latest_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml1
-rw-r--r--config/metrics/counts_7d/20211126084441_p_analytics_ci_cd_pipelines_weekly.yml3
-rw-r--r--config/metrics/counts_7d/20211126090829_p_analytics_ci_cd_deployment_frequency_weekly.yml3
-rw-r--r--config/metrics/counts_7d/20211126091200_p_analytics_ci_cd_lead_time_weekly.yml3
-rw-r--r--config/metrics/counts_7d/20230105222224_g_project_management_issue_design_comments_removed_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20230714160504_batched_background_migration_failed_jobs_metric.yml5
-rw-r--r--config/metrics/counts_7d/20230724140652_i_code_review_saved_replies_create_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20230725194657_i_code_review_saved_replies_use_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20230809194743_i_code_review_saved_replies_use_in_mr_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20230810124157_count_cicd_component_usage_weekly.yml23
-rw-r--r--config/metrics/counts_7d/20230815171559_i_code_review_saved_replies_use_in_other_weekly.yml28
-rw-r--r--config/metrics/counts_7d/20230816085153_k8s_api_proxy_requests_unique_agents_via_pat_access_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20230816085153_k8s_api_proxy_requests_unique_users_via_pat_access_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20230822210848_i_quickactions_checkin_reminder_weekly.yml23
-rw-r--r--config/metrics/counts_7d/20230830153031_p_ci_templates_cosign_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20230905083259_batched_background_migration_count_failed_jobs_metric.yml23
-rw-r--r--config/metrics/counts_all/20210216175019_projects_with_prometheus_alerts.yml1
-rw-r--r--config/metrics/counts_all/20210216175021_pod_logs_usages_total.yml1
-rw-r--r--config/metrics/counts_all/20210216175045_merge_requests.yml1
-rw-r--r--config/metrics/counts_all/20210216175053_suggestions.yml1
-rw-r--r--config/metrics/counts_all/20210216175255_clusters_applications_helm.yml1
-rw-r--r--config/metrics/counts_all/20210216175257_clusters_applications_ingress.yml1
-rw-r--r--config/metrics/counts_all/20210216175259_clusters_applications_cert_managers.yml1
-rw-r--r--config/metrics/counts_all/20210216175301_clusters_applications_crossplane.yml1
-rw-r--r--config/metrics/counts_all/20210216175303_clusters_applications_prometheus.yml1
-rw-r--r--config/metrics/counts_all/20210216175305_clusters_applications_runner.yml1
-rw-r--r--config/metrics/counts_all/20210216175307_clusters_applications_knative.yml1
-rw-r--r--config/metrics/counts_all/20210216175309_clusters_applications_elastic_stack.yml1
-rw-r--r--config/metrics/counts_all/20210216175310_clusters_applications_jupyter.yml1
-rw-r--r--config/metrics/counts_all/20210216175312_clusters_applications_cilium.yml1
-rw-r--r--config/metrics/counts_all/20210216175318_kubernetes_agents_with_token.yml3
-rw-r--r--config/metrics/counts_all/20210216175329_clusters_applications_cert_managers.yml1
-rw-r--r--config/metrics/counts_all/20210216175331_clusters_applications_helm.yml1
-rw-r--r--config/metrics/counts_all/20210216175333_clusters_applications_ingress.yml1
-rw-r--r--config/metrics/counts_all/20210216175335_clusters_applications_knative.yml1
-rw-r--r--config/metrics/counts_all/20210216175403_projects_with_prometheus_alerts.yml1
-rw-r--r--config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml3
-rw-r--r--config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml3
-rw-r--r--config/metrics/counts_all/20210216175446_network_policy_forwards.yml2
-rw-r--r--config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml3
-rw-r--r--config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml3
-rw-r--r--config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml3
-rw-r--r--config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml3
-rw-r--r--config/metrics/counts_all/20210216175518_ci_pipeline_config_repository.yml5
-rw-r--r--config/metrics/counts_all/20210216175523_ci_pipeline_schedules.yml3
-rw-r--r--config/metrics/counts_all/20210216175533_ci_pipeline_config_repository.yml4
-rw-r--r--config/metrics/counts_all/20210216175535_ci_pipeline_schedules.yml4
-rw-r--r--config/metrics/counts_all/20210216175627_templates_asana_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175638_templates_assembla_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175649_templates_bamboo_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175712_templates_buildkite_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175723_templates_campfire_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175734_templates_confluence_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175756_templates_discord_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175840_templates_flowdock_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175910_projects_hipchat_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175912_groups_hipchat_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175913_templates_hipchat_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175915_instances_hipchat_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175924_templates_irker_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175935_templates_jenkins_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175946_templates_jira_active.yml1
-rw-r--r--config/metrics/counts_all/20210216175957_templates_mattermost_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180030_templates_packagist_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180104_templates_pushover_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180115_templates_redmine_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180126_templates_slack_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180148_templates_teamcity_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180221_templates_youtrack_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180451_incident_labeled_issues.yml1
-rw-r--r--config/metrics/counts_all/20210216180456_projects_with_alerts_service_enabled.yml1
-rw-r--r--config/metrics/counts_all/20210216180634_gitlab.yml2
-rw-r--r--config/metrics/counts_all/20210216180639_gitlab.yml1
-rw-r--r--config/metrics/counts_all/20210216180705_total.yml2
-rw-r--r--config/metrics/counts_all/20210216180707_gitlab_project.yml2
-rw-r--r--config/metrics/counts_all/20210216180709_gitlab.yml2
-rw-r--r--config/metrics/counts_all/20210216180711_github.yml2
-rw-r--r--config/metrics/counts_all/20210216180713_bitbucket.yml2
-rw-r--r--config/metrics/counts_all/20210216180715_bitbucket_server.yml2
-rw-r--r--config/metrics/counts_all/20210216180716_gitea.yml2
-rw-r--r--config/metrics/counts_all/20210216180718_git.yml2
-rw-r--r--config/metrics/counts_all/20210216180720_manifest.yml2
-rw-r--r--config/metrics/counts_all/20210216180722_jira.yml2
-rw-r--r--config/metrics/counts_all/20210216180724_fogbugz.yml2
-rw-r--r--config/metrics/counts_all/20210216180726_phabricator.yml2
-rw-r--r--config/metrics/counts_all/20210216180727_csv.yml2
-rw-r--r--config/metrics/counts_all/20210216180729_groups_imported.yml2
-rw-r--r--config/metrics/counts_all/20210216180750_groups.yml3
-rw-r--r--config/metrics/counts_all/20210216180934_templates_prometheus_active.yml1
-rw-r--r--config/metrics/counts_all/20210216180947_clusters_applications_prometheus.yml1
-rw-r--r--config/metrics/counts_all/20210216181949_clusters_applications_runner.yml1
-rw-r--r--config/metrics/counts_all/20210216182551_templates_datadog_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182618_templates_ewm_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml1
-rw-r--r--config/metrics/counts_all/20210216182907_package_events_i_package_container_delete_package.yml1
-rw-r--r--config/metrics/counts_all/20210216182909_package_events_i_package_container_pull_package.yml1
-rw-r--r--config/metrics/counts_all/20210216182911_package_events_i_package_container_push_package.yml1
-rw-r--r--config/metrics/counts_all/20210216182917_package_events_i_package_debian_push_package.yml1
-rw-r--r--config/metrics/counts_all/20210216183017_package_events_i_package_tag_delete_package.yml2
-rw-r--r--config/metrics/counts_all/20210216183019_package_events_i_package_tag_pull_package.yml2
-rw-r--r--config/metrics/counts_all/20210216183021_package_events_i_package_tag_push_package.yml2
-rw-r--r--config/metrics/counts_all/20230809084619_connected_agents.yml23
-rw-r--r--config/metrics/counts_all/20230815054809_i_code_review_saved_replies_use_in_other.yml25
-rw-r--r--config/metrics/counts_all/20230816085929_kubernetes_agent_k8s_api_proxy_requests_via_pat_access.yml25
-rw-r--r--config/metrics/license/20230228110448_installation_creation_date.yml1
-rw-r--r--config/metrics/schema.json34
-rw-r--r--config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml3
-rw-r--r--config/object_store_settings.rb8
-rw-r--r--config/redis.yml.example6
-rw-r--r--config/resque.yml.example5
-rw-r--r--config/routes.rb10
-rw-r--r--config/routes/activity_pub.rb31
-rw-r--r--config/routes/group.rb3
-rw-r--r--config/routes/organizations.rb7
-rw-r--r--config/routes/project.rb20
-rw-r--r--config/session_store.yml.example3
-rw-r--r--config/sidekiq_queues.yml42
-rw-r--r--config/spring.rb4
-rw-r--r--config/vite.json18
-rw-r--r--config/webpack.config.js28
-rw-r--r--config/webpack.constants.js31
-rw-r--r--danger/architecture/Dangerfile2
-rw-r--r--danger/clickhouse/Dangerfile29
-rw-r--r--danger/ignored_model_columns/Dangerfile3
-rw-r--r--danger/plugins/clickhouse.rb10
-rw-r--r--danger/plugins/ignored_model_columns.rb9
-rw-r--r--danger/qa_selector/Dangerfile4
-rw-r--r--danger/roulette/Dangerfile11
-rw-r--r--data/deprecations/14-8-graphql-project-network-policies.yml9
-rw-r--r--data/deprecations/15-0-oauth-noexpiry.yml2
-rw-r--r--data/deprecations/15-6-deprecate-runner-reg-token-helm.yml8
-rw-r--r--data/deprecations/15-6-deprecate-runner-register-command.yml6
-rw-r--r--data/deprecations/15-6-deprecate-runner-register-token-k8s-operator.yml6
-rw-r--r--data/deprecations/15-7-deprecate-api-v4-runner-registration-token-reset-endpoints.yml10
-rw-r--r--data/deprecations/15-9-JWT-OIDC.yml6
-rw-r--r--data/deprecations/15-9-license-compliance-ci-template.yml14
-rw-r--r--data/deprecations/16-0-Vault-integration.yml4
-rw-r--r--data/deprecations/16-3-CI-job-token-scope-update.yml28
-rw-r--r--data/deprecations/16-3-remove-rsa-key-size-larger-than-8k-support.yml12
-rw-r--r--data/deprecations/16-4-ci_job_token_scope_enabled-attribute-deprecation.yml26
-rw-r--r--data/deprecations/16-4-deprecate-change-vulnerability-status-with-developer-role.yml11
-rw-r--r--data/deprecations/16-4-geo-legacy-component-routes-deprecation.yml17
-rw-r--r--data/deprecations/16-4_support_for_delete_tags_endpoint.yml21
-rw-r--r--data/deprecations/16-5-ci-job-token-limit-setting.yml37
-rw-r--r--data/whats_new/202212200001_15_07.yml4
-rw-r--r--data/whats_new/202308220001_16_3.yml74
-rw-r--r--db/click_house/main/20230707151359_create_ci_finished_builds.sql33
-rw-r--r--db/click_house/main/20230719101806_create_ci_finished_builds_aggregated_queueing_delay_percentiles.sql11
-rw-r--r--db/click_house/main/20230808070520_create_events_cursor.sql9
-rw-r--r--db/click_house/main/20230808140217_create_ci_finished_builds_aggregated_queueing_delay_percentiles_mv.sql12
-rw-r--r--db/docs/audit_events_amazon_s3_configurations.yml10
-rw-r--r--db/docs/audit_events_instance_google_cloud_logging_configurations.yml10
-rw-r--r--db/docs/batched_background_migrations/backfill_has_merge_request_of_vulnerability_reads.yml6
-rw-r--r--db/docs/batched_background_migrations/backfill_nuget_normalized_version.yml6
-rw-r--r--db/docs/batched_background_migrations/backfill_project_statistics_storage_size_with_recent_size.yml6
-rw-r--r--db/docs/batched_background_migrations/backfill_user_preferences_with_defaults.yml6
-rw-r--r--db/docs/batched_background_migrations/backfill_users_with_defaults.yml6
-rw-r--r--db/docs/batched_background_migrations/backfill_workspace_personal_access_token.yml5
-rw-r--r--db/docs/batched_background_migrations/convert_credit_card_validation_data_to_hashes.yml8
-rw-r--r--db/docs/batched_background_migrations/create_compliance_standards_adherence.yml6
-rw-r--r--db/docs/batched_background_migrations/fix_namespace_ids_of_vulnerability_reads.yml6
-rw-r--r--db/docs/batched_background_migrations/populate_denormalized_columns_for_sbom_occurrences.yml6
-rw-r--r--db/docs/batched_background_migrations/sync_scan_result_policies.yml8
-rw-r--r--db/docs/batched_background_migrations/update_users_set_external_if_service_account.yml6
-rw-r--r--db/docs/groups_visits.yml10
-rw-r--r--db/docs/integrations.yml2
-rw-r--r--db/docs/issues.yml2
-rw-r--r--db/docs/members.yml2
-rw-r--r--db/docs/merge_request_predictions.yml2
-rw-r--r--db/docs/notification_settings.yml2
-rw-r--r--db/docs/p_ci_builds.yml5
-rw-r--r--db/docs/packages_nuget_symbols.yml10
-rw-r--r--db/docs/packages_packages.yml1
-rw-r--r--db/docs/packages_protection_rules.yml10
-rw-r--r--db/docs/projects_visits.yml10
-rw-r--r--db/docs/web_hooks.yml2
-rw-r--r--db/docs/workspace_variables.yml10
-rw-r--r--db/gitlab_schemas/gitlab_main_cell.yaml3
-rw-r--r--db/migrate/20220907124320_add_internal_to_notes.rb9
-rw-r--r--db/migrate/20220907124320_add_internal_to_notes_renamed.rb11
-rw-r--r--db/migrate/20230728020644_add_snowplow_database_collector_hostname_to_application_settings.rb19
-rw-r--r--db/migrate/20230802205051_add_admin_merge_request_to_member_roles.rb17
-rw-r--r--db/migrate/20230804055559_add_rollup_progress_to_wi_progresses.rb9
-rw-r--r--db/migrate/20230807035953_add_index_to_abuse_reports_on_user_id_status_and_category.rb15
-rw-r--r--db/migrate/20230811144601_add_pages_multiple_versions_enabled_to_project_settings.rb9
-rw-r--r--db/migrate/20230814181359_add_decompress_archive_file_timeout_to_application_setting.rb9
-rw-r--r--db/migrate/20230814203548_add_merged_commit_sha_to_merge_requests.rb17
-rw-r--r--db/migrate/20230815072912_add_hashes_to_credit_card_validations.rb28
-rw-r--r--db/migrate/20230816210052_add_licenses_to_sbom_occurrences.rb7
-rw-r--r--db/migrate/20230817040352_init_bigint_conversion_for_shared_runners_duration.rb20
-rw-r--r--db/migrate/20230821000001_create_workspace_variables.rb14
-rw-r--r--db/migrate/20230821000002_add_personal_access_token_id_to_workspaces.rb33
-rw-r--r--db/migrate/20230821000003_add_config_version_to_workspaces.rb7
-rw-r--r--db/migrate/20230821081508_add_mr_requires_saml_auth_for_approval_to_group_mr_approval_settings.rb13
-rw-r--r--db/migrate/20230821101010_remove_crl_null.rb15
-rw-r--r--db/migrate/20230821133549_create_packages_nuget_symbols.rb24
-rw-r--r--db/migrate/20230822064649_add_organization_id_to_project.rb11
-rw-r--r--db/migrate/20230822151454_remove_free_user_cap_email_workers.rb18
-rw-r--r--db/migrate/20230822175304_add_okr_reminder_fields_to_work_item_progresses.rb7
-rw-r--r--db/migrate/20230823132142_create_instance_google_cloud_logging_configurations.rb23
-rw-r--r--db/migrate/20230823174108_add_patch_id_sha_on_approvals.rb13
-rw-r--r--db/migrate/20230824015840_add_finding_id_to_vulnerabilities.rb11
-rw-r--r--db/migrate/20230824022229_make_finding_id_on_vulnerabilities_invalid_foreign_key.rb14
-rw-r--r--db/migrate/20230828153646_extend_push_rules_regex_limits.rb38
-rw-r--r--db/migrate/20230829045459_add_search_rate_limit_allowlist_to_application_settings.rb7
-rw-r--r--db/migrate/20230830084959_validate_push_rules_constraints.rb25
-rw-r--r--db/migrate/20230830085501_remove_push_rules_regex_limits.rb17
-rw-r--r--db/migrate/20230831111051_add_approval_settings_to_scan_result_policies.rb10
-rw-r--r--db/migrate/20230901170145_update_vulnerability_reads_trigger_to_set_has_merge_request.rb211
-rw-r--r--db/migrate/20230903170000_create_packages_protection_rules.rb18
-rw-r--r--db/migrate/20230905040539_add_foreign_key_for_ci_pipeline_chat_data_for_pipeline_id_bigint.rb20
-rw-r--r--db/migrate/20230905061815_add_foreign_key_for_ci_pipeline_messages_pipeline_id_bigint.rb20
-rw-r--r--db/migrate/20230905234948_create_projects_visits_tables.rb19
-rw-r--r--db/migrate/20230905234949_create_groups_visits_tables.rb19
-rw-r--r--db/migrate/20230906072349_create_audit_events_amazon_s3_configurations.rb24
-rw-r--r--db/migrate/20230906100001_add_metadata_columns_to_packages_py_pi_metadata.rb34
-rw-r--r--db/migrate/20230906105445_add_audit_events_amazon_s3_configuration_limit_to_plan_limits.rb7
-rw-r--r--db/migrate/20230906175220_replace_sbom_occurrences_component_id_index.rb18
-rw-r--r--db/migrate/20230906185552_add_markdown_fields_to_review_llm_summary.rb23
-rw-r--r--db/migrate/20230906204934_restart_self_hosted_sent_notifications_bigint_conversion.rb36
-rw-r--r--db/migrate/20230906204935_restart_self_hosted_sent_notifications_backfill.rb56
-rw-r--r--db/migrate/20230907162613_add_force_full_reconciliation_to_workspaces.rb9
-rw-r--r--db/migrate/20230908155831_add_continuous_vuln_scans_toggle_to_security_project_settings.rb16
-rw-r--r--db/migrate/20230911095016_add_root_namespace_id_to_project_statistics.rb25
-rw-r--r--db/migrate/20230913171402_add_deleted_at_to_pages_deployments.rb7
-rw-r--r--db/migrate/20230913171403_add_pages_deployments_deleted_at_index.rb19
-rw-r--r--db/migrate/20230913235822_change_geo_node_statuses_last_event_id_integer_to_big_int.rb21
-rw-r--r--db/migrate/20230914001329_change_geo_node_statuses_cursor_last_event_id_integer_to_big_int.rb21
-rw-r--r--db/migrate/20230914185814_add_keyboard_shortcuts_toggle_to_user_preferences.rb9
-rw-r--r--db/migrate/20230918194153_add_merge_immediately_to_ci_cd_settings.rb13
-rw-r--r--db/post_migrate/20220920124709_backfill_internal_on_notes.rb26
-rw-r--r--db/post_migrate/20220920124709_backfill_internal_on_notes_renamed.rb28
-rw-r--r--db/post_migrate/20230125093723_rebalance_partition_id_ci_pipeline.rb23
-rw-r--r--db/post_migrate/20230125093840_rebalance_partition_id_ci_build.rb23
-rw-r--r--db/post_migrate/20230208100917_fix_partition_ids_for_ci_pipeline_variable.rb23
-rw-r--r--db/post_migrate/20230208103009_fix_partition_ids_for_ci_job_artifact.rb23
-rw-r--r--db/post_migrate/20230208132608_fix_partition_ids_for_ci_stage.rb23
-rw-r--r--db/post_migrate/20230209090702_fix_partition_ids_for_ci_build_report_result.rb23
-rw-r--r--db/post_migrate/20230209092204_fix_partition_ids_for_ci_build_trace_metadata.rb23
-rw-r--r--db/post_migrate/20230209140102_fix_partition_ids_for_ci_build_metadata.rb23
-rw-r--r--db/post_migrate/20230214122717_fix_partition_ids_for_ci_job_variables.rb14
-rw-r--r--db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb27
-rw-r--r--db/post_migrate/20230703024031_cleanup_project_pipeline_status_key.rb3
-rw-r--r--db/post_migrate/20230802212443_add_current_user_todos_widget_to_epic_work_item_type.rb56
-rw-r--r--db/post_migrate/20230804122825_add_unique_index_on_uuid_convert_string_to_uuid.rb23
-rw-r--r--db/post_migrate/20230804123252_add_unique_index_on_uuid_convert_string_to_uuid_including_vulnerability_id.rb22
-rw-r--r--db/post_migrate/20230808200355_remove_application_settings_dashboard_columns.rb8
-rw-r--r--db/post_migrate/20230809170822_ensure_system_note_metadata_bigint_backfill_is_finished_for_self_managed.rb23
-rw-r--r--db/post_migrate/20230809174702_swap_system_note_metadata_note_id_to_bigint_for_self_managed.rb62
-rw-r--r--db/post_migrate/20230809203254_ensure_issue_user_mentions_bigint_backfill_is_finished_for_self_managed.rb23
-rw-r--r--db/post_migrate/20230809210550_swap_issue_user_mentions_note_id_to_bigint_for_self_managed.rb74
-rw-r--r--db/post_migrate/20230810112715_ensure_note_diff_files_bigint_backfill_is_finished_for_self_hosts.rb21
-rw-r--r--db/post_migrate/20230810113227_swap_note_diff_files_note_id_to_bigint_for_self_hosts.rb64
-rw-r--r--db/post_migrate/20230810124545_schedule_fixing_namespace_ids_of_vulnerability_reads.rb24
-rw-r--r--db/post_migrate/20230811103457_queue_backfill_nuget_normalized_version.rb25
-rw-r--r--db/post_migrate/20230811185901_remove_application_settings_dashboard_notification_limit_column.rb9
-rw-r--r--db/post_migrate/20230811211544_backfill_alert_management_prometheus_integrations.rb52
-rw-r--r--db/post_migrate/20230815140656_queue_populate_denormalized_columns_for_sbom_occurrences.rb27
-rw-r--r--db/post_migrate/20230815160428_rename_plans_titles_with_legacy_plan_names.rb18
-rw-r--r--db/post_migrate/20230816111730_ensure_id_uniqueness_for_p_ci_builds_v3.rb40
-rw-r--r--db/post_migrate/20230816152540_ensure_dum_note_id_bigint_backfill_is_finished_for_self_managed.rb24
-rw-r--r--db/post_migrate/20230816152639_swap_design_user_mentions_note_id_to_big_int_for_self_managed.rb62
-rw-r--r--db/post_migrate/20230816210503_ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_self_managed.rb23
-rw-r--r--db/post_migrate/20230816213228_swap_merge_request_user_mentions_note_id_to_bigint_for_self_managed.rb74
-rw-r--r--db/post_migrate/20230817050946_backfill_shared_runners_duration_for_project_bigint_conversion.rb16
-rw-r--r--db/post_migrate/20230817111753_ensure_events_bigint_backfill_is_finished_for_self_hosts.rb21
-rw-r--r--db/post_migrate/20230817111938_swap_events_target_id_to_bigint_for_self_hosts.rb51
-rw-r--r--db/post_migrate/20230817143507_ensure_award_emoji_bigint_backfill_is_finished_for_self_hosts.rb21
-rw-r--r--db/post_migrate/20230817143637_swap_award_emoji_note_id_to_bigint_for_self_hosts.rb58
-rw-r--r--db/post_migrate/20230818034041_prepare_removal_index_success_deployments_on_cluster_id_and_environment_id.rb17
-rw-r--r--db/post_migrate/20230818050946_backfill_shared_runners_duration_for_namespace_bigint_conversion.rb16
-rw-r--r--db/post_migrate/20230818055517_prepare_removal_index_deployments_on_id_where_cluster_id_present.rb14
-rw-r--r--db/post_migrate/20230818083610_queue_backfill_users_with_defaults.rb28
-rw-r--r--db/post_migrate/20230818085219_queue_backfill_user_preferences_with_defaults.rb28
-rw-r--r--db/post_migrate/20230818142801_queue_create_compliance_standards_adherence.rb28
-rw-r--r--db/post_migrate/20230821081603_queue_convert_credit_card_validation_data_to_hashes.rb25
-rw-r--r--db/post_migrate/20230822064841_prepare_index_for_org_id_on_projects.rb13
-rw-r--r--db/post_migrate/20230822104028_delete_project_callout_three.rb23
-rw-r--r--db/post_migrate/20230822125256_drop_temporary_index_on_vulnerability_reads_dismissal_reason.rb24
-rw-r--r--db/post_migrate/20230822153124_remove_free_user_cap_email_workers_related_columns.rb29
-rw-r--r--db/post_migrate/20230822154640_add_async_index_on_merge_requests_target_project_id_and_merged_commit_sha.rb17
-rw-r--r--db/post_migrate/20230822195852_remove_pa_jitsu_related_settings.rb13
-rw-r--r--db/post_migrate/20230823085627_add_temp_index_for_project_statistics_updated_at.rb18
-rw-r--r--db/post_migrate/20230823090001_queue_backfill_project_statistics_storage_size_with_recent_size.rb25
-rw-r--r--db/post_migrate/20230823140934_add_linked_items_widget_to_ticket_work_item_type.rb49
-rw-r--r--db/post_migrate/20230823143519_remove_users_notification_settings_user_id_fk.rb22
-rw-r--r--db/post_migrate/20230823144846_remove_users_members_user_id_fk.rb22
-rw-r--r--db/post_migrate/20230823145053_ensure_notes_bigint_backfill_is_finished_for_self_managed.rb24
-rw-r--r--db/post_migrate/20230823145126_swap_notes_id_to_bigint_for_self_managed.rb183
-rw-r--r--db/post_migrate/20230823161514_remove_namespaces_routes_namespace_id_fk.rb22
-rw-r--r--db/post_migrate/20230823194111_remove_pages_deployments_project_id_path_prefix_unique_index.rb14
-rw-r--r--db/post_migrate/20230825085648_ensure_backfill_for_ci_stages_pipeline_id_is_finished.rb23
-rw-r--r--db/post_migrate/20230825085719_create_async_index_for_ci_stages_pipeline_id.rb31
-rw-r--r--db/post_migrate/20230829120720_index_finding_id_for_vulnerabilities.rb14
-rw-r--r--db/post_migrate/20230830121830_queue_update_users_set_external_if_service_account.rb26
-rw-r--r--db/post_migrate/20230831084632_queue_sync_scan_result_policies.rb25
-rw-r--r--db/post_migrate/20230831101144_index_org_id_and_id_on_organization_user.rb15
-rw-r--r--db/post_migrate/20230901033401_ensure_backfill_for_ci_sources_pipelines_pipeline_id_is_finished.rb26
-rw-r--r--db/post_migrate/20230901044003_add_sync_foreign_key_for_ci_pipeline_variables_pipeline_id.rb15
-rw-r--r--db/post_migrate/20230901050458_ensure_backfill_for_ci_pipelines_auto_canceled_by_id_is_finished.rb26
-rw-r--r--db/post_migrate/20230901054536_ensure_backfill_for_ci_pipeline_chat_data_pipeline_id_is_finished.rb23
-rw-r--r--db/post_migrate/20230901064536_add_concurrent_index_for_ci_pipeline_chat_data_pipeline_id_convert_to_bigint.rb17
-rw-r--r--db/post_migrate/20230901064537_remove_namespace_details_dashboard_fields.rb10
-rw-r--r--db/post_migrate/20230902033401_create_async_index_for_ci_sources_pipelines_pipeline_id.rb25
-rw-r--r--db/post_migrate/20230902050458_create_async_index_for_ci_pipelines_auto_canceled_by_id.rb15
-rw-r--r--db/post_migrate/20230902054536_ensure_backfill_for_ci_pipeline_messages_pipeline_id_is_finished.rb23
-rw-r--r--db/post_migrate/20230903064536_concurrent_index_for_ci_pipeline_messages_pipeline_id_convert_to_bigint.rb17
-rw-r--r--db/post_migrate/20230903064537_add_ci_job_artifacts_file_final_path_index.rb17
-rw-r--r--db/post_migrate/20230904100544_drop_index_deployments_on_id_where_cluster_id_present.rb18
-rw-r--r--db/post_migrate/20230904103804_drop_index_successful_deployments_on_cluster_id_and_environment_id.rb18
-rw-r--r--db/post_migrate/20230905071915_prepare_async_foreign_key_for_ci_pipeline_messages_pipeline_id_bigint.rb15
-rw-r--r--db/post_migrate/20230905091059_sync_index_for_ci_stages_pipeline_id_bigint.rb33
-rw-r--r--db/post_migrate/20230906181457_add_index_to_violations_on_target_proj_id.rb16
-rw-r--r--db/post_migrate/20230907155247_queue_backfill_has_merge_request_of_vulnerability_reads.rb26
-rw-r--r--db/post_migrate/20230907204731_add_index_to_sbom_occurrences_licenses.rb23
-rw-r--r--db/post_migrate/20230908072558_analyze_p_ci_runner_machine_builds.rb15
-rw-r--r--db/post_migrate/20230908072612_analyze_p_ci_job_annotations.rb15
-rw-r--r--db/post_migrate/20230908072626_analyze_p_ci_builds_metadata.rb15
-rw-r--r--db/post_migrate/20230908072639_analyze_p_ci_builds.rb15
-rw-r--r--db/post_migrate/20230909120000_queue_backfill_workspace_personal_access_token.rb26
-rw-r--r--db/post_migrate/20230913100953_create_supporting_index_for_uuid_type_casting.rb23
-rw-r--r--db/post_migrate/20230913115113_add_prepared_at_created_at_index_async.rb15
-rw-r--r--db/post_migrate/20230913120111_remove_prepared_at_created_at_index_async.rb15
-rw-r--r--db/post_migrate/20230913130629_index_org_id_on_projects.rb15
-rw-r--r--db/post_migrate/20230913175529_add_index_on_merge_requests_target_project_id_and_merged_commit_sha.rb16
-rw-r--r--db/post_migrate/20230914054914_index_finding_id_for_vulnerabilities_sync.rb15
-rw-r--r--db/schema_migrations/202307280206441
-rw-r--r--db/schema_migrations/202308022050511
-rw-r--r--db/schema_migrations/202308022124431
-rw-r--r--db/schema_migrations/202308040555591
-rw-r--r--db/schema_migrations/202308041228251
-rw-r--r--db/schema_migrations/202308041232521
-rw-r--r--db/schema_migrations/202308070359531
-rw-r--r--db/schema_migrations/202308082003551
-rw-r--r--db/schema_migrations/202308091708221
-rw-r--r--db/schema_migrations/202308091747021
-rw-r--r--db/schema_migrations/202308092032541
-rw-r--r--db/schema_migrations/202308092105501
-rw-r--r--db/schema_migrations/202308101127151
-rw-r--r--db/schema_migrations/202308101132271
-rw-r--r--db/schema_migrations/202308101245451
-rw-r--r--db/schema_migrations/202308111034571
-rw-r--r--db/schema_migrations/202308111446011
-rw-r--r--db/schema_migrations/202308111859011
-rw-r--r--db/schema_migrations/202308112115441
-rw-r--r--db/schema_migrations/202308141813591
-rw-r--r--db/schema_migrations/202308142035481
-rw-r--r--db/schema_migrations/202308150729121
-rw-r--r--db/schema_migrations/202308151406561
-rw-r--r--db/schema_migrations/202308151604281
-rw-r--r--db/schema_migrations/202308161117301
-rw-r--r--db/schema_migrations/202308161525401
-rw-r--r--db/schema_migrations/202308161526391
-rw-r--r--db/schema_migrations/202308162100521
-rw-r--r--db/schema_migrations/202308162105031
-rw-r--r--db/schema_migrations/202308162132281
-rw-r--r--db/schema_migrations/202308170403521
-rw-r--r--db/schema_migrations/202308170509461
-rw-r--r--db/schema_migrations/202308171117531
-rw-r--r--db/schema_migrations/202308171119381
-rw-r--r--db/schema_migrations/202308171435071
-rw-r--r--db/schema_migrations/202308171436371
-rw-r--r--db/schema_migrations/202308180340411
-rw-r--r--db/schema_migrations/202308180509461
-rw-r--r--db/schema_migrations/202308180555171
-rw-r--r--db/schema_migrations/202308180836101
-rw-r--r--db/schema_migrations/202308180852191
-rw-r--r--db/schema_migrations/202308181428011
-rw-r--r--db/schema_migrations/202308210000011
-rw-r--r--db/schema_migrations/202308210000021
-rw-r--r--db/schema_migrations/202308210000031
-rw-r--r--db/schema_migrations/202308210815081
-rw-r--r--db/schema_migrations/202308210816031
-rw-r--r--db/schema_migrations/202308211010101
-rw-r--r--db/schema_migrations/202308211335491
-rw-r--r--db/schema_migrations/202308220646491
-rw-r--r--db/schema_migrations/202308220648411
-rw-r--r--db/schema_migrations/202308221040281
-rw-r--r--db/schema_migrations/202308221252561
-rw-r--r--db/schema_migrations/202308221514541
-rw-r--r--db/schema_migrations/202308221531241
-rw-r--r--db/schema_migrations/202308221546401
-rw-r--r--db/schema_migrations/202308221753041
-rw-r--r--db/schema_migrations/202308221958521
-rw-r--r--db/schema_migrations/202308230856271
-rw-r--r--db/schema_migrations/202308230900011
-rw-r--r--db/schema_migrations/202308231321421
-rw-r--r--db/schema_migrations/202308231409341
-rw-r--r--db/schema_migrations/202308231435191
-rw-r--r--db/schema_migrations/202308231448461
-rw-r--r--db/schema_migrations/202308231450531
-rw-r--r--db/schema_migrations/202308231451261
-rw-r--r--db/schema_migrations/202308231615141
-rw-r--r--db/schema_migrations/202308231741081
-rw-r--r--db/schema_migrations/202308231941111
-rw-r--r--db/schema_migrations/202308240158401
-rw-r--r--db/schema_migrations/202308240222291
-rw-r--r--db/schema_migrations/202308250856481
-rw-r--r--db/schema_migrations/202308250857191
-rw-r--r--db/schema_migrations/202308281536461
-rw-r--r--db/schema_migrations/202308290454591
-rw-r--r--db/schema_migrations/202308291207201
-rw-r--r--db/schema_migrations/202308300849591
-rw-r--r--db/schema_migrations/202308300855011
-rw-r--r--db/schema_migrations/202308301218301
-rw-r--r--db/schema_migrations/202308310846321
-rw-r--r--db/schema_migrations/202308311011441
-rw-r--r--db/schema_migrations/202308311110511
-rw-r--r--db/schema_migrations/202309010334011
-rw-r--r--db/schema_migrations/202309010440031
-rw-r--r--db/schema_migrations/202309010504581
-rw-r--r--db/schema_migrations/202309010545361
-rw-r--r--db/schema_migrations/202309010645361
-rw-r--r--db/schema_migrations/202309010645371
-rw-r--r--db/schema_migrations/202309011701451
-rw-r--r--db/schema_migrations/202309020334011
-rw-r--r--db/schema_migrations/202309020504581
-rw-r--r--db/schema_migrations/202309020545361
-rw-r--r--db/schema_migrations/202309030645361
-rw-r--r--db/schema_migrations/202309030645371
-rw-r--r--db/schema_migrations/202309031700001
-rw-r--r--db/schema_migrations/202309041005441
-rw-r--r--db/schema_migrations/202309041038041
-rw-r--r--db/schema_migrations/202309050405391
-rw-r--r--db/schema_migrations/202309050618151
-rw-r--r--db/schema_migrations/202309050719151
-rw-r--r--db/schema_migrations/202309050910591
-rw-r--r--db/schema_migrations/202309052349481
-rw-r--r--db/schema_migrations/202309052349491
-rw-r--r--db/schema_migrations/202309060723491
-rw-r--r--db/schema_migrations/202309061000011
-rw-r--r--db/schema_migrations/202309061054451
-rw-r--r--db/schema_migrations/202309061752201
-rw-r--r--db/schema_migrations/202309061814571
-rw-r--r--db/schema_migrations/202309061855521
-rw-r--r--db/schema_migrations/202309062049341
-rw-r--r--db/schema_migrations/202309062049351
-rw-r--r--db/schema_migrations/202309071552471
-rw-r--r--db/schema_migrations/202309071626131
-rw-r--r--db/schema_migrations/202309072047311
-rw-r--r--db/schema_migrations/202309080725581
-rw-r--r--db/schema_migrations/202309080726121
-rw-r--r--db/schema_migrations/202309080726261
-rw-r--r--db/schema_migrations/202309080726391
-rw-r--r--db/schema_migrations/202309081558311
-rw-r--r--db/schema_migrations/202309091200001
-rw-r--r--db/schema_migrations/202309110950161
-rw-r--r--db/schema_migrations/202309131009531
-rw-r--r--db/schema_migrations/202309131151131
-rw-r--r--db/schema_migrations/202309131201111
-rw-r--r--db/schema_migrations/202309131306291
-rw-r--r--db/schema_migrations/202309131714021
-rw-r--r--db/schema_migrations/202309131714031
-rw-r--r--db/schema_migrations/202309131755291
-rw-r--r--db/schema_migrations/202309132358221
-rw-r--r--db/schema_migrations/202309140013291
-rw-r--r--db/schema_migrations/202309140549141
-rw-r--r--db/schema_migrations/202309141858141
-rw-r--r--db/schema_migrations/202309181941531
-rw-r--r--db/structure.sql452
-rw-r--r--doc/.vale/gitlab/BadgeCapitalization.yml4
-rw-r--r--doc/.vale/gitlab/SubstitutionWarning.yml2
-rw-r--r--doc/.vale/gitlab/Substitutions.yml1
-rw-r--r--doc/.vale/gitlab/Uppercase.yml2
-rw-r--r--doc/.vale/gitlab/spelling-exceptions.txt5
-rw-r--r--doc/administration/admin_area.md44
-rw-r--r--doc/administration/analytics/dev_ops_reports.md2
-rw-r--r--doc/administration/analytics/index.md2
-rw-r--r--doc/administration/analytics/usage_trends.md2
-rw-r--r--doc/administration/appearance.md14
-rw-r--r--doc/administration/audit_event_streaming/audit_event_types.md31
-rw-r--r--doc/administration/audit_event_streaming/examples.md2
-rw-r--r--doc/administration/audit_event_streaming/graphql_api.md15
-rw-r--r--doc/administration/audit_event_streaming/index.md57
-rw-r--r--doc/administration/audit_events.md283
-rw-r--r--doc/administration/auditor_users.md4
-rw-r--r--doc/administration/auth/atlassian.md2
-rw-r--r--doc/administration/auth/cognito.md2
-rw-r--r--doc/administration/auth/crowd.md2
-rw-r--r--doc/administration/auth/index.md2
-rw-r--r--doc/administration/auth/jwt.md2
-rw-r--r--doc/administration/auth/ldap/google_secure_ldap.md2
-rw-r--r--doc/administration/auth/ldap/index.md134
-rw-r--r--doc/administration/auth/ldap/ldap-troubleshooting.md8
-rw-r--r--doc/administration/auth/ldap/ldap_synchronization.md6
-rw-r--r--doc/administration/auth/oidc.md4
-rw-r--r--doc/administration/auth/smartcard.md2
-rw-r--r--doc/administration/auth/test_oidc_oauth.md2
-rw-r--r--doc/administration/backup_restore/backup_gitlab.md34
-rw-r--r--doc/administration/backup_restore/index.md4
-rw-r--r--doc/administration/backup_restore/restore_gitlab.md20
-rw-r--r--doc/administration/broadcast_messages.md6
-rw-r--r--doc/administration/cicd.md2
-rw-r--r--doc/administration/clusters/kas.md49
-rw-r--r--doc/administration/credentials_inventory.md69
-rw-r--r--doc/administration/custom_project_templates.md4
-rw-r--r--doc/administration/dedicated/index.md79
-rw-r--r--doc/administration/diff_limits.md2
-rw-r--r--doc/administration/email_from_gitlab.md2
-rw-r--r--doc/administration/encrypted_configuration.md2
-rw-r--r--doc/administration/external_users.md8
-rw-r--r--doc/administration/geo/disaster_recovery/background_verification.md8
-rw-r--r--doc/administration/geo/disaster_recovery/index.md20
-rw-r--r--doc/administration/geo/disaster_recovery/planned_failover.md18
-rw-r--r--doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md11
-rw-r--r--doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md9
-rw-r--r--doc/administration/geo/glossary.md4
-rw-r--r--doc/administration/geo/index.md13
-rw-r--r--doc/administration/geo/replication/configuration.md59
-rw-r--r--doc/administration/geo/replication/container_registry.md2
-rw-r--r--doc/administration/geo/replication/datatypes.md79
-rw-r--r--doc/administration/geo/replication/disable_geo.md2
-rw-r--r--doc/administration/geo/replication/object_storage.md8
-rw-r--r--doc/administration/geo/replication/remove_geo_site.md2
-rw-r--r--doc/administration/geo/replication/troubleshooting.md1423
-rw-r--r--doc/administration/geo/replication/tuning.md2
-rw-r--r--doc/administration/geo/replication/version_specific_upgrades.md109
-rw-r--r--doc/administration/geo/secondary_proxy/index.md2
-rw-r--r--doc/administration/geo/setup/external_database.md5
-rw-r--r--doc/administration/geo/setup/two_single_node_sites.md17
-rw-r--r--doc/administration/geo_sites.md4
-rw-r--r--doc/administration/gitaly/configure_gitaly.md327
-rw-r--r--doc/administration/gitaly/index.md7
-rw-r--r--doc/administration/gitaly/monitoring.md70
-rw-r--r--doc/administration/gitaly/praefect.md21
-rw-r--r--doc/administration/gitaly/recovery.md21
-rw-r--r--doc/administration/gitaly/reference.md36
-rw-r--r--doc/administration/gitaly/troubleshooting.md7
-rw-r--r--doc/administration/housekeeping.md6
-rw-r--r--doc/administration/inactive_project_deletion.md2
-rw-r--r--doc/administration/instance_limits.md78
-rw-r--r--doc/administration/integration/diagrams_net.md5
-rw-r--r--doc/administration/integration/kroki.md6
-rw-r--r--doc/administration/integration/mailgun.md4
-rw-r--r--doc/administration/integration/plantuml.md4
-rw-r--r--doc/administration/integration/terminal.md2
-rw-r--r--doc/administration/job_artifacts_troubleshooting.md13
-rw-r--r--doc/administration/lfs/index.md2
-rw-r--r--doc/administration/license.md26
-rw-r--r--doc/administration/license_file.md6
-rw-r--r--doc/administration/load_balancer.md2
-rw-r--r--doc/administration/logs/index.md33
-rw-r--r--doc/administration/logs/tracing_correlation_id.md2
-rw-r--r--doc/administration/maintenance_mode/index.md6
-rw-r--r--doc/administration/merge_requests_approvals.md2
-rw-r--r--doc/administration/moderate_users.md26
-rw-r--r--doc/administration/monitoring/gitlab_self_monitoring_project/index.md12
-rw-r--r--doc/administration/monitoring/performance/gitlab_configuration.md2
-rw-r--r--doc/administration/monitoring/performance/grafana_configuration.md8
-rw-r--r--doc/administration/monitoring/performance/performance_bar.md2
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md13
-rw-r--r--doc/administration/monitoring/prometheus/index.md4
-rw-r--r--doc/administration/object_storage.md8
-rw-r--r--doc/administration/operations/fast_ssh_key_lookup.md6
-rw-r--r--doc/administration/operations/moving_repositories.md19
-rw-r--r--doc/administration/package_information/supported_os.md7
-rw-r--r--doc/administration/packages/container_registry.md52
-rw-r--r--doc/administration/pages/index.md40
-rw-r--r--doc/administration/pages/source.md2
-rw-r--r--doc/administration/pages/troubleshooting.md6
-rw-r--r--doc/administration/polling.md2
-rw-r--r--doc/administration/postgresql/database_load_balancing.md6
-rw-r--r--doc/administration/postgresql/replication_and_failover.md2
-rw-r--r--doc/administration/raketasks/github_import.md3
-rw-r--r--doc/administration/raketasks/ldap.md2
-rw-r--r--doc/administration/raketasks/maintenance.md8
-rw-r--r--doc/administration/raketasks/service_desk_email.md2
-rw-r--r--doc/administration/raketasks/storage.md8
-rw-r--r--doc/administration/reference_architectures/10k_users.md4
-rw-r--r--doc/administration/reference_architectures/25k_users.md4
-rw-r--r--doc/administration/reference_architectures/2k_users.md2
-rw-r--r--doc/administration/reference_architectures/3k_users.md4
-rw-r--r--doc/administration/reference_architectures/50k_users.md4
-rw-r--r--doc/administration/reference_architectures/5k_users.md4
-rw-r--r--doc/administration/reference_architectures/index.md20
-rw-r--r--doc/administration/reporting/git_abuse_rate_limit.md6
-rw-r--r--doc/administration/reporting/ip_addr_restrictions.md4
-rw-r--r--doc/administration/reporting/spamcheck.md2
-rw-r--r--doc/administration/repository_checks.md8
-rw-r--r--doc/administration/repository_storage_paths.md260
-rw-r--r--doc/administration/repository_storage_types.md245
-rw-r--r--doc/administration/review_abuse_reports.md6
-rw-r--r--doc/administration/secure_files.md2
-rw-r--r--doc/administration/server_hooks.md14
-rw-r--r--doc/administration/settings/account_and_limit_settings.md110
-rw-r--r--doc/administration/settings/continuous_integration.md57
-rw-r--r--doc/administration/settings/deprecated_api_rate_limits.md2
-rw-r--r--doc/administration/settings/email.md12
-rw-r--r--doc/administration/settings/external_authorization.md6
-rw-r--r--doc/administration/settings/files_api_rate_limits.md2
-rw-r--r--doc/administration/settings/floc.md2
-rw-r--r--doc/administration/settings/git_lfs_rate_limits.md2
-rw-r--r--doc/administration/settings/gitaly_timeouts.md2
-rw-r--r--doc/administration/settings/help_page.md10
-rw-r--r--doc/administration/settings/import_and_export_settings.md153
-rw-r--r--doc/administration/settings/import_export_rate_limits.md2
-rw-r--r--doc/administration/settings/incident_management_rate_limits.md2
-rw-r--r--doc/administration/settings/index.md6
-rw-r--r--doc/administration/settings/instance_template_repository.md5
-rw-r--r--doc/administration/settings/package_registry_rate_limits.md4
-rw-r--r--doc/administration/settings/project_integration_management.md50
-rw-r--r--doc/administration/settings/protected_paths.md2
-rw-r--r--doc/administration/settings/push_event_activities_limit.md2
-rw-r--r--doc/administration/settings/rate_limit_on_issues_creation.md2
-rw-r--r--doc/administration/settings/rate_limit_on_notes_creation.md2
-rw-r--r--doc/administration/settings/rate_limit_on_pipelines_creation.md2
-rw-r--r--doc/administration/settings/rate_limit_on_projects_api.md2
-rw-r--r--doc/administration/settings/rate_limit_on_users_api.md4
-rw-r--r--doc/administration/settings/rate_limits_on_git_ssh_operations.md2
-rw-r--r--doc/administration/settings/rate_limits_on_raw_endpoints.md2
-rw-r--r--doc/administration/settings/scim_setup.md16
-rw-r--r--doc/administration/settings/security_and_compliance.md8
-rw-r--r--doc/administration/settings/sidekiq_job_limits.md2
-rw-r--r--doc/administration/settings/sign_in_restrictions.md10
-rw-r--r--doc/administration/settings/sign_up_restrictions.md14
-rw-r--r--doc/administration/settings/slack_app.md6
-rw-r--r--doc/administration/settings/terms.md2
-rw-r--r--doc/administration/settings/terraform_limits.md2
-rw-r--r--doc/administration/settings/third_party_offers.md2
-rw-r--r--doc/administration/settings/usage_statistics.md15
-rw-r--r--doc/administration/settings/user_and_ip_rate_limits.md10
-rw-r--r--doc/administration/settings/visibility_and_access_controls.md80
-rw-r--r--doc/administration/sidekiq/extra_sidekiq_processes.md2
-rw-r--r--doc/administration/sidekiq/sidekiq_job_migration.md2
-rw-r--r--doc/administration/silent_mode/index.md73
-rw-r--r--doc/administration/static_objects_external_storage.md2
-rw-r--r--doc/administration/system_hooks.md2
-rw-r--r--doc/administration/troubleshooting/postgresql.md60
-rw-r--r--doc/administration/user_cohorts.md2
-rw-r--r--doc/administration/user_settings.md4
-rw-r--r--doc/administration/whats-new.md2
-rw-r--r--doc/api/access_requests.md2
-rw-r--r--doc/api/api_resources.md82
-rw-r--r--doc/api/appearance.md2
-rw-r--r--doc/api/applications.md2
-rw-r--r--doc/api/audit_events.md8
-rw-r--r--doc/api/avatar.md2
-rw-r--r--doc/api/award_emoji.md2
-rw-r--r--doc/api/boards.md12
-rw-r--r--doc/api/branches.md65
-rw-r--r--doc/api/bulk_imports.md14
-rw-r--r--doc/api/code_suggestions.md10
-rw-r--r--doc/api/commits.md28
-rw-r--r--doc/api/dependency_list_export.md158
-rw-r--r--doc/api/deploy_keys.md2
-rw-r--r--doc/api/deploy_tokens.md46
-rw-r--r--doc/api/discussions.md4
-rw-r--r--doc/api/error_tracking.md2
-rw-r--r--doc/api/events.md2
-rw-r--r--doc/api/feature_flags.md43
-rw-r--r--doc/api/geo_nodes.md40
-rw-r--r--doc/api/geo_sites.md57
-rw-r--r--doc/api/graphql/custom_emoji.md6
-rw-r--r--doc/api/graphql/reference/index.md1596
-rw-r--r--doc/api/graphql/users_example.md2
-rw-r--r--doc/api/group_access_tokens.md20
-rw-r--r--doc/api/group_badges.md6
-rw-r--r--doc/api/group_boards.md8
-rw-r--r--doc/api/group_clusters.md4
-rw-r--r--doc/api/group_import_export.md2
-rw-r--r--doc/api/group_level_variables.md4
-rw-r--r--doc/api/group_protected_branches.md24
-rw-r--r--doc/api/group_ssh_certificates.md115
-rw-r--r--doc/api/group_wikis.md2
-rw-r--r--doc/api/groups.md50
-rw-r--r--doc/api/index.md7
-rw-r--r--doc/api/integrations.md11
-rw-r--r--doc/api/issue_links.md6
-rw-r--r--doc/api/issues.md50
-rw-r--r--doc/api/issues_statistics.md2
-rw-r--r--doc/api/job_artifacts.md26
-rw-r--r--doc/api/license.md37
-rw-r--r--doc/api/linked_epics.md24
-rw-r--r--doc/api/managed_licenses.md17
-rw-r--r--doc/api/member_roles.md19
-rw-r--r--doc/api/members.md10
-rw-r--r--doc/api/merge_request_approvals.md8
-rw-r--r--doc/api/merge_requests.md55
-rw-r--r--doc/api/namespaces.md2
-rw-r--r--doc/api/notification_settings.md6
-rw-r--r--doc/api/oauth2.md2
-rw-r--r--doc/api/packages.md2
-rw-r--r--doc/api/packages/debian_group_distributions.md14
-rw-r--r--doc/api/packages/debian_project_distributions.md14
-rw-r--r--doc/api/packages/nuget.md39
-rw-r--r--doc/api/personal_access_tokens.md40
-rw-r--r--doc/api/plan_limits.md2
-rw-r--r--doc/api/project_access_tokens.md20
-rw-r--r--doc/api/project_aliases.md8
-rw-r--r--doc/api/project_badges.md18
-rw-r--r--doc/api/project_clusters.md2
-rw-r--r--doc/api/project_import_export.md4
-rw-r--r--doc/api/project_relations_export.md4
-rw-r--r--doc/api/project_templates.md18
-rw-r--r--doc/api/project_vulnerabilities.md4
-rw-r--r--doc/api/projects.md1000
-rw-r--r--doc/api/protected_branches.md42
-rw-r--r--doc/api/remote_mirrors.md4
-rw-r--r--doc/api/repositories.md4
-rw-r--r--doc/api/repository_files.md28
-rw-r--r--doc/api/repository_submodules.md2
-rw-r--r--doc/api/rest/deprecations.md5
-rw-r--r--doc/api/rest/index.md32
-rw-r--r--doc/api/runners.md4
-rw-r--r--doc/api/saml.md2
-rw-r--r--doc/api/scim.md2
-rw-r--r--doc/api/search.md26
-rw-r--r--doc/api/settings.md130
-rw-r--r--doc/api/snippets.md6
-rw-r--r--doc/api/statistics.md2
-rw-r--r--doc/api/status_checks.md12
-rw-r--r--doc/api/system_hooks.md2
-rw-r--r--doc/api/tags.md84
-rw-r--r--doc/api/topics.md34
-rw-r--r--doc/api/usage_data.md2
-rw-r--r--doc/api/users.md38
-rw-r--r--doc/api/vulnerability_exports.md14
-rw-r--r--doc/api/vulnerability_findings.md210
-rw-r--r--doc/api/wikis.md2
-rw-r--r--doc/architecture/blueprints/ai_gateway/index.md14
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-admin-area.md81
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md30
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-backups.md53
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-ci-runners.md144
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-container-registry.md114
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-contributions-forks.md106
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-data-migration.md99
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-database-sequences.md74
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-explore.md71
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-git-access.md156
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md30
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-global-search.md35
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-graphql.md81
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-organizations.md36
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-personal-access-tokens.md31
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md30
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md34
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-schema-changes.md38
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-secrets.md43
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-snippets.md56
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-template.md30
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-uploads.md30
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-user-profile.md52
-rw-r--r--doc/architecture/blueprints/cells/cells-feature-your-work.md58
-rw-r--r--doc/architecture/blueprints/cells/diagrams/cells-and-fulfillment.drawio.pngbin192221 -> 0 bytes
-rw-r--r--doc/architecture/blueprints/cells/diagrams/index.md2
-rw-r--r--doc/architecture/blueprints/cells/diagrams/term-cell.drawio.pngbin93379 -> 31802 bytes
-rw-r--r--doc/architecture/blueprints/cells/diagrams/term-cluster.drawio.pngbin436724 -> 102686 bytes
-rw-r--r--doc/architecture/blueprints/cells/diagrams/term-organization.drawio.pngbin169719 -> 39566 bytes
-rw-r--r--doc/architecture/blueprints/cells/diagrams/term-top-level-group.drawio.pngbin65137 -> 15865 bytes
-rw-r--r--doc/architecture/blueprints/cells/glossary.md106
-rw-r--r--doc/architecture/blueprints/cells/goals.md387
-rw-r--r--doc/architecture/blueprints/cells/impact.md59
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/admin-area.md81
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/agent-for-kubernetes.md30
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/backups.md53
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/ci-cd-catalog.md54
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/ci-runners.md144
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/container-registry.md114
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/contributions-forks.md163
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/data-migration.md99
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/data-pipeline-ingestion.md39
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/database-sequences.md74
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/explore.md71
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/git-access.md156
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/gitlab-pages.md30
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/global-search.md35
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/graphql.md81
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/organizations.md36
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/personal-access-tokens.md31
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/personal-namespaces.md71
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/router-endpoints-classification.md34
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/schema-changes.md38
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/secrets.md43
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/snippets.md56
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/template.md30
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/uploads.md30
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/user-profile.md53
-rw-r--r--doc/architecture/blueprints/cells/impacted_features/your-work.md60
-rw-r--r--doc/architecture/blueprints/cells/index.md152
-rw-r--r--doc/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md8
-rw-r--r--doc/architecture/blueprints/cells/proposal-stateless-router-with-routes-learning.md8
-rw-r--r--doc/architecture/blueprints/code_search_with_zoekt/diagrams/sharding_proposal_2023-08.drawio.pngbin0 -> 167701 bytes
-rw-r--r--doc/architecture/blueprints/code_search_with_zoekt/index.md51
-rw-r--r--doc/architecture/blueprints/container_registry_metadata_database_self_managed_rollout/index.md63
-rw-r--r--doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.pngbin129675 -> 36052 bytes
-rw-r--r--doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md6
-rw-r--r--doc/architecture/blueprints/gitaly_handle_upload_pack_in_http2_server/index.md310
-rw-r--r--doc/architecture/blueprints/gitlab_events_platform/index.md120
-rw-r--r--doc/architecture/blueprints/gitlab_steps/index.md142
-rw-r--r--doc/architecture/blueprints/google_artifact_registry_integration/index.md159
-rw-r--r--doc/architecture/blueprints/google_artifact_registry_integration/ui_ux.md17
-rw-r--r--doc/architecture/blueprints/modular_monolith/bounded_contexts.md27
-rw-r--r--doc/architecture/blueprints/modular_monolith/hexagonal_monolith/index.md98
-rw-r--r--doc/architecture/blueprints/modular_monolith/index.md21
-rw-r--r--doc/architecture/blueprints/organization/index.md54
-rw-r--r--doc/architecture/blueprints/organization/organization-faq.md44
-rw-r--r--doc/architecture/blueprints/remote_development/index.md49
-rw-r--r--doc/architecture/blueprints/runner_tokens/index.md24
-rw-r--r--doc/architecture/blueprints/runway/img/runway-architecture.pngbin0 -> 426450 bytes
-rw-r--r--doc/architecture/blueprints/runway/img/runway_vault_4_.drawio189
-rw-r--r--doc/architecture/blueprints/runway/img/runway_vault_4_.drawio.pngbin0 -> 134342 bytes
-rw-r--r--doc/architecture/blueprints/runway/index.md251
-rw-r--r--doc/architecture/blueprints/transfer_data/index.md141
-rw-r--r--doc/architecture/blueprints/transfer_data/repository.md67
-rw-r--r--doc/architecture/blueprints/work_items/index.md36
-rw-r--r--doc/ci/caching/index.md4
-rw-r--r--doc/ci/ci_cd_for_external_repos/bitbucket_integration.md6
-rw-r--r--doc/ci/ci_cd_for_external_repos/github_integration.md8
-rw-r--r--doc/ci/ci_cd_for_external_repos/index.md8
-rw-r--r--doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md2
-rw-r--r--doc/ci/cloud_services/aws/index.md9
-rw-r--r--doc/ci/cloud_services/azure/index.md4
-rw-r--r--doc/ci/cloud_services/google_cloud/index.md2
-rw-r--r--doc/ci/cloud_services/index.md4
-rw-r--r--doc/ci/components/catalog.md33
-rw-r--r--doc/ci/components/index.md503
-rw-r--r--doc/ci/docker/authenticate_registry.md10
-rw-r--r--doc/ci/docker/buildah_rootless_tutorial.md149
-rw-r--r--doc/ci/docker/docker_layer_caching.md4
-rw-r--r--doc/ci/docker/using_docker_build.md170
-rw-r--r--doc/ci/docker/using_kaniko.md26
-rw-r--r--doc/ci/enable_or_disable_ci.md4
-rw-r--r--doc/ci/environments/deployment_approvals.md65
-rw-r--r--doc/ci/environments/environments_dashboard.md2
-rw-r--r--doc/ci/environments/incremental_rollouts.md6
-rw-r--r--doc/ci/environments/index.md25
-rw-r--r--doc/ci/environments/kubernetes_dashboard.md38
-rw-r--r--doc/ci/environments/protected_environments.md4
-rw-r--r--doc/ci/examples/authenticating-with-hashicorp-vault/index.md2
-rw-r--r--doc/ci/examples/deployment/index.md2
-rw-r--r--doc/ci/examples/semantic-release.md2
-rw-r--r--doc/ci/index.md246
-rw-r--r--doc/ci/introduction/img/gitlab_workflow_example_11_9.pngbin40769 -> 0 bytes
-rw-r--r--doc/ci/introduction/img/gitlab_workflow_example_extended_v12_3.pngbin78448 -> 0 bytes
-rw-r--r--doc/ci/introduction/index.md119
-rw-r--r--doc/ci/jobs/ci_job_token.md8
-rw-r--r--doc/ci/jobs/index.md2
-rw-r--r--doc/ci/jobs/job_artifacts.md4
-rw-r--r--doc/ci/jobs/job_control.md4
-rw-r--r--doc/ci/large_repositories/index.md257
-rw-r--r--doc/ci/lint.md4
-rw-r--r--doc/ci/migration/examples/img/maven-freestyle-plugin.pngbin0 -> 16589 bytes
-rw-r--r--doc/ci/migration/examples/img/maven-freestyle-shell.pngbin0 -> 21379 bytes
-rw-r--r--doc/ci/migration/examples/jenkins-maven.md232
-rw-r--r--doc/ci/migration/jenkins.md345
-rw-r--r--doc/ci/migration/plan_a_migration.md71
-rw-r--r--doc/ci/mobile_devops.md9
-rw-r--r--doc/ci/pipeline_editor/index.md2
-rw-r--r--doc/ci/pipelines/cicd_minutes.md8
-rw-r--r--doc/ci/pipelines/downstream_pipelines.md82
-rw-r--r--doc/ci/pipelines/index.md14
-rw-r--r--doc/ci/pipelines/merge_request_pipelines.md9
-rw-r--r--doc/ci/pipelines/merge_trains.md2
-rw-r--r--doc/ci/pipelines/merged_results_pipelines.md2
-rw-r--r--doc/ci/pipelines/pipeline_architectures.md3
-rw-r--r--doc/ci/pipelines/pipeline_artifacts.md14
-rw-r--r--doc/ci/pipelines/pipeline_efficiency.md4
-rw-r--r--doc/ci/pipelines/schedules.md8
-rw-r--r--doc/ci/pipelines/settings.md20
-rw-r--r--doc/ci/quick_start/tutorial.md11
-rw-r--r--doc/ci/resource_groups/index.md8
-rw-r--r--doc/ci/review_apps/img/enable_review_app_v16.pngbin0 -> 105290 bytes
-rw-r--r--doc/ci/review_apps/index.md6
-rw-r--r--doc/ci/runners/configure_runners.md34
-rw-r--r--doc/ci/runners/index.md74
-rw-r--r--doc/ci/runners/new_creation_workflow.md89
-rw-r--r--doc/ci/runners/runners_scope.md151
-rw-r--r--doc/ci/runners/saas/linux_saas_runner.md2
-rw-r--r--doc/ci/runners/saas/macos/codesigning.md11
-rw-r--r--doc/ci/runners/saas/macos/environment.md11
-rw-r--r--doc/ci/runners/saas/macos_saas_runner.md34
-rw-r--r--doc/ci/runners/saas/windows_saas_runner.md21
-rw-r--r--doc/ci/secrets/id_token_authentication.md2
-rw-r--r--doc/ci/secure_files/index.md2
-rw-r--r--doc/ci/services/index.md9
-rw-r--r--doc/ci/test_cases/index.md6
-rw-r--r--doc/ci/testing/code_coverage.md2
-rw-r--r--doc/ci/testing/load_performance_testing.md6
-rw-r--r--doc/ci/triggers/index.md4
-rw-r--r--doc/ci/troubleshooting.md40
-rw-r--r--doc/ci/variables/index.md6
-rw-r--r--doc/ci/variables/predefined_variables.md10
-rw-r--r--doc/ci/variables/where_variables_can_be_used.md8
-rw-r--r--doc/ci/yaml/artifacts_reports.md55
-rw-r--r--doc/ci/yaml/includes.md176
-rw-r--r--doc/ci/yaml/index.md91
-rw-r--r--doc/ci/yaml/inputs.md174
-rw-r--r--doc/ci/yaml/signing_examples.md20
-rw-r--r--doc/cloud_seed/index.md20
-rw-r--r--doc/development/activitypub/actor.md11
-rw-r--r--doc/development/activitypub/actors/group.md205
-rw-r--r--doc/development/activitypub/actors/index.md148
-rw-r--r--doc/development/activitypub/actors/project.md640
-rw-r--r--doc/development/activitypub/actors/releases.md85
-rw-r--r--doc/development/activitypub/actors/topic.md91
-rw-r--r--doc/development/activitypub/actors/user.md47
-rw-r--r--doc/development/activitypub/index.md216
-rw-r--r--doc/development/adding_service_component.md2
-rw-r--r--doc/development/ai_architecture.md23
-rw-r--r--doc/development/ai_features.md662
-rw-r--r--doc/development/ai_features/duo_chat.md139
-rw-r--r--doc/development/ai_features/index.md577
-rw-r--r--doc/development/ai_features/prompts.md28
-rw-r--r--doc/development/api_graphql_styleguide.md11
-rw-r--r--doc/development/audit_event_guide/index.md24
-rw-r--r--doc/development/avoiding_required_stops.md12
-rw-r--r--doc/development/build_test_package.md19
-rw-r--r--doc/development/cascading_settings.md2
-rw-r--r--doc/development/cloud_connector/code_suggestions_for_sm.md259
-rw-r--r--doc/development/cloud_connector/img/code_suggestions_components.pngbin0 -> 44296 bytes
-rw-r--r--doc/development/code_review.md6
-rw-r--r--doc/development/code_suggestions/index.md56
-rw-r--r--doc/development/contributing/index.md2
-rw-r--r--doc/development/database/avoiding_downtime_in_migrations.md3
-rw-r--r--doc/development/database/batched_background_migrations.md3
-rw-r--r--doc/development/database/clickhouse/clickhouse_within_gitlab.md237
-rw-r--r--doc/development/database/foreign_keys.md2
-rw-r--r--doc/development/database/index.md2
-rw-r--r--doc/development/database/multiple_databases.md116
-rw-r--r--doc/development/database/not_null_constraints.md2
-rw-r--r--doc/development/database/poc_tree_iterator.md475
-rw-r--r--doc/development/database_review.md16
-rw-r--r--doc/development/development_seed_files.md26
-rw-r--r--doc/development/documentation/alpha_beta.md52
-rw-r--r--doc/development/documentation/experiment_beta.md49
-rw-r--r--doc/development/documentation/help.md3
-rw-r--r--doc/development/documentation/restful_api_styleguide.md8
-rw-r--r--doc/development/documentation/review_apps.md1
-rw-r--r--doc/development/documentation/site_architecture/automation.md77
-rw-r--r--doc/development/documentation/site_architecture/deployment_process.md42
-rw-r--r--doc/development/documentation/styleguide/index.md102
-rw-r--r--doc/development/documentation/styleguide/word_list.md129
-rw-r--r--doc/development/documentation/testing.md16
-rw-r--r--doc/development/documentation/topic_types/task.md2
-rw-r--r--doc/development/ee_features.md6
-rw-r--r--doc/development/event_store.md15
-rw-r--r--doc/development/experiment_guide/implementing_experiments.md2
-rw-r--r--doc/development/fe_guide/accessibility.md39
-rw-r--r--doc/development/fe_guide/architecture.md18
-rw-r--r--doc/development/fe_guide/axios.md4
-rw-r--r--doc/development/fe_guide/customizable_dashboards.md11
-rw-r--r--doc/development/fe_guide/dark_mode.md2
-rw-r--r--doc/development/fe_guide/design_anti_patterns.md220
-rw-r--r--doc/development/fe_guide/design_patterns.md220
-rw-r--r--doc/development/fe_guide/development_process.md125
-rw-r--r--doc/development/fe_guide/getting_started.md54
-rw-r--r--doc/development/fe_guide/guides.md13
-rw-r--r--doc/development/fe_guide/img/boards_diagram.pngbin9518 -> 0 bytes
-rw-r--r--doc/development/fe_guide/index.md125
-rw-r--r--doc/development/fe_guide/principles.md21
-rw-r--r--doc/development/fe_guide/sentry.md34
-rw-r--r--doc/development/fe_guide/tech_stack.md11
-rw-r--r--doc/development/fe_guide/tips_and_tricks.md31
-rw-r--r--doc/development/feature_development.md6
-rw-r--r--doc/development/feature_flags/index.md9
-rw-r--r--doc/development/features_inside_dot_gitlab.md2
-rw-r--r--doc/development/file_storage.md2
-rw-r--r--doc/development/fips_compliance.md2
-rw-r--r--doc/development/gems.md9
-rw-r--r--doc/development/git_object_deduplication.md4
-rw-r--r--doc/development/github_importer.md11
-rw-r--r--doc/development/go_guide/index.md61
-rw-r--r--doc/development/gotchas.md58
-rw-r--r--doc/development/i18n/externalization.md4
-rw-r--r--doc/development/i18n/proofreader.md2
-rw-r--r--doc/development/img/build_package_v12_6.pngbin39482 -> 0 bytes
-rw-r--r--doc/development/img/trigger_build_package_v12_6.pngbin44149 -> 0 bytes
-rw-r--r--doc/development/img/trigger_omnibus_v16_3.pngbin0 -> 34918 bytes
-rw-r--r--doc/development/img/triggered_ee_pipeline_v16_3.pngbin0 -> 47309 bytes
-rw-r--r--doc/development/integrations/index.md75
-rw-r--r--doc/development/integrations/jenkins.md6
-rw-r--r--doc/development/integrations/secure.md2
-rw-r--r--doc/development/internal_analytics/index.md2
-rw-r--r--doc/development/internal_analytics/internal_event_tracking/architecture.md2
-rw-r--r--doc/development/internal_analytics/internal_event_tracking/event_definition_guide.md2
-rw-r--r--doc/development/internal_analytics/internal_event_tracking/index.md2
-rw-r--r--doc/development/internal_analytics/internal_event_tracking/introduction.md2
-rw-r--r--doc/development/internal_analytics/internal_event_tracking/migration.md155
-rw-r--r--doc/development/internal_analytics/internal_event_tracking/quick_start.md46
-rw-r--r--doc/development/internal_analytics/service_ping/implement.md2
-rw-r--r--doc/development/internal_analytics/service_ping/index.md2
-rw-r--r--doc/development/internal_analytics/service_ping/metrics_dictionary.md6
-rw-r--r--doc/development/internal_analytics/service_ping/metrics_instrumentation.md2
-rw-r--r--doc/development/internal_analytics/service_ping/metrics_lifecycle.md2
-rw-r--r--doc/development/internal_analytics/service_ping/performance_indicator_metrics.md2
-rw-r--r--doc/development/internal_analytics/service_ping/review_guidelines.md2
-rw-r--r--doc/development/internal_analytics/service_ping/troubleshooting.md6
-rw-r--r--doc/development/internal_analytics/service_ping/usage_data.md2
-rw-r--r--doc/development/internal_analytics/snowplow/event_dictionary_guide.md2
-rw-r--r--doc/development/internal_analytics/snowplow/implementation.md2
-rw-r--r--doc/development/internal_analytics/snowplow/index.md4
-rw-r--r--doc/development/internal_analytics/snowplow/infrastructure.md2
-rw-r--r--doc/development/internal_analytics/snowplow/review_guidelines.md2
-rw-r--r--doc/development/internal_analytics/snowplow/schemas.md2
-rw-r--r--doc/development/internal_analytics/snowplow/troubleshooting.md2
-rw-r--r--doc/development/internal_api/index.md79
-rw-r--r--doc/development/internal_users.md2
-rw-r--r--doc/development/merge_request_concepts/performance.md10
-rw-r--r--doc/development/migration_style_guide.md42
-rw-r--r--doc/development/packages/debian_repository.md12
-rw-r--r--doc/development/performance.md2
-rw-r--r--doc/development/permissions.md2
-rw-r--r--doc/development/permissions/authorizations.md2
-rw-r--r--doc/development/permissions/custom_roles.md2
-rw-r--r--doc/development/permissions/predefined_roles.md16
-rw-r--r--doc/development/pipelines/index.md4
-rw-r--r--doc/development/pipelines/internals.md29
-rw-r--r--doc/development/pipelines/performance.md2
-rw-r--r--doc/development/policies.md2
-rw-r--r--doc/development/rails_update.md6
-rw-r--r--doc/development/rake_tasks.md17
-rw-r--r--doc/development/redis.md8
-rw-r--r--doc/development/rubocop_development_guide.md10
-rw-r--r--doc/development/ruby_upgrade.md2
-rw-r--r--doc/development/sec/token_revocation_api.md4
-rw-r--r--doc/development/secure_coding_guidelines.md2
-rw-r--r--doc/development/service_ping/implement.md11
-rw-r--r--doc/development/service_ping/index.md11
-rw-r--r--doc/development/service_ping/metrics_dictionary.md11
-rw-r--r--doc/development/service_ping/metrics_instrumentation.md11
-rw-r--r--doc/development/service_ping/metrics_lifecycle.md11
-rw-r--r--doc/development/service_ping/performance_indicator_metrics.md11
-rw-r--r--doc/development/service_ping/review_guidelines.md11
-rw-r--r--doc/development/service_ping/troubleshooting.md11
-rw-r--r--doc/development/service_ping/usage_data.md11
-rw-r--r--doc/development/shell_commands.md2
-rw-r--r--doc/development/snowplow/event_dictionary_guide.md11
-rw-r--r--doc/development/snowplow/implementation.md11
-rw-r--r--doc/development/snowplow/index.md11
-rw-r--r--doc/development/snowplow/infrastructure.md11
-rw-r--r--doc/development/snowplow/review_guidelines.md11
-rw-r--r--doc/development/snowplow/schemas.md11
-rw-r--r--doc/development/snowplow/troubleshooting.md11
-rw-r--r--doc/development/testing_guide/best_practices.md7
-rw-r--r--doc/development/testing_guide/end_to_end/beginners_guide.md9
-rw-r--r--doc/development/testing_guide/end_to_end/best_practices.md10
-rw-r--r--doc/development/testing_guide/end_to_end/index.md8
-rw-r--r--doc/development/testing_guide/end_to_end/resources.md76
-rw-r--r--doc/development/testing_guide/flaky_tests.md18
-rw-r--r--doc/development/testing_guide/frontend_testing.md4
-rw-r--r--doc/development/testing_guide/review_apps.md12
-rw-r--r--doc/development/value_stream_analytics.md34
-rw-r--r--doc/development/work_items.md174
-rw-r--r--doc/editor_extensions/index.md4
-rw-r--r--doc/editor_extensions/jetbrains_ide/index.md2
-rw-r--r--doc/editor_extensions/neovim/index.md2
-rw-r--r--doc/editor_extensions/visual_studio/index.md2
-rw-r--r--doc/editor_extensions/visual_studio_code/index.md5
-rw-r--r--doc/gitlab-basics/add-file.md2
-rw-r--r--doc/install/aws/gitlab_hybrid_on_aws.md36
-rw-r--r--doc/install/azure/index.md2
-rw-r--r--doc/install/cloud_native/index.md11
-rw-r--r--doc/install/install_methods.md2
-rw-r--r--doc/install/next_steps.md2
-rw-r--r--doc/install/requirements.md14
-rw-r--r--doc/integration/advanced_search/elasticsearch.md77
-rw-r--r--doc/integration/advanced_search/elasticsearch_troubleshooting.md6
-rw-r--r--doc/integration/akismet.md4
-rw-r--r--doc/integration/alicloud.md2
-rw-r--r--doc/integration/arkose.md2
-rw-r--r--doc/integration/auth0.md2
-rw-r--r--doc/integration/azure.md2
-rw-r--r--doc/integration/bitbucket.md2
-rw-r--r--doc/integration/cas.md13
-rw-r--r--doc/integration/datadog.md2
-rw-r--r--doc/integration/ding_talk.md2
-rw-r--r--doc/integration/external-issue-tracker.md2
-rw-r--r--doc/integration/facebook.md2
-rw-r--r--doc/integration/github.md2
-rw-r--r--doc/integration/gitlab.md2
-rw-r--r--doc/integration/gitpod.md4
-rw-r--r--doc/integration/google.md2
-rw-r--r--doc/integration/jenkins.md125
-rw-r--r--doc/integration/jira/configure.md4
-rw-r--r--doc/integration/jira/connect-app.md11
-rw-r--r--doc/integration/jira/dvcs/troubleshooting.md6
-rw-r--r--doc/integration/jira/index.md5
-rw-r--r--doc/integration/jira/issues.md8
-rw-r--r--doc/integration/jira/troubleshooting.md2
-rw-r--r--doc/integration/kerberos.md6
-rw-r--r--doc/integration/mattermost/index.md72
-rw-r--r--doc/integration/oauth2_generic.md2
-rw-r--r--doc/integration/oauth_provider.md26
-rw-r--r--doc/integration/omniauth.md4
-rw-r--r--doc/integration/openid_connect_provider.md40
-rw-r--r--doc/integration/recaptcha.md2
-rw-r--r--doc/integration/salesforce.md2
-rw-r--r--doc/integration/saml.md4
-rw-r--r--doc/integration/shibboleth.md2
-rw-r--r--doc/integration/sourcegraph.md2
-rw-r--r--doc/integration/twitter.md2
-rw-r--r--doc/operations/error_tracking.md18
-rw-r--r--doc/operations/feature_flags.md16
-rw-r--r--doc/operations/img/tracing_list_v16_3.pngbin0 -> 59957 bytes
-rw-r--r--doc/operations/incident_management/alerts.md4
-rw-r--r--doc/operations/incident_management/escalation_policies.md6
-rw-r--r--doc/operations/incident_management/incident_timeline_events.md10
-rw-r--r--doc/operations/incident_management/incidents.md2
-rw-r--r--doc/operations/incident_management/integrations.md9
-rw-r--r--doc/operations/incident_management/linked_resources.md6
-rw-r--r--doc/operations/incident_management/manage_incidents.md12
-rw-r--r--doc/operations/incident_management/oncall_schedules.md12
-rw-r--r--doc/operations/incident_management/paging.md2
-rw-r--r--doc/operations/incident_management/slack.md2
-rw-r--r--doc/operations/incident_management/status_page.md4
-rw-r--r--doc/operations/metrics/alerts.md12
-rw-r--r--doc/operations/metrics/dashboards/default.md12
-rw-r--r--doc/operations/metrics/dashboards/develop.md12
-rw-r--r--doc/operations/metrics/dashboards/index.md12
-rw-r--r--doc/operations/metrics/dashboards/panel_types.md12
-rw-r--r--doc/operations/metrics/dashboards/settings.md12
-rw-r--r--doc/operations/metrics/dashboards/templating_variables.md12
-rw-r--r--doc/operations/metrics/dashboards/variables.md12
-rw-r--r--doc/operations/metrics/dashboards/yaml.md12
-rw-r--r--doc/operations/metrics/dashboards/yaml_number_format.md12
-rw-r--r--doc/operations/metrics/embed.md12
-rw-r--r--doc/operations/metrics/embed_grafana.md12
-rw-r--r--doc/operations/metrics/index.md12
-rw-r--r--doc/operations/tracing.md75
-rw-r--r--doc/policy/alpha-beta-support.md11
-rw-r--r--doc/policy/experiment-beta-support.md12
-rw-r--r--doc/policy/maintenance.md4
-rw-r--r--doc/raketasks/cleanup.md2
-rw-r--r--doc/raketasks/generate_sample_prometheus_data.md12
-rw-r--r--doc/raketasks/import.md11
-rw-r--r--doc/raketasks/list_repos.md11
-rw-r--r--doc/raketasks/x509_signatures.md2
-rw-r--r--doc/security/asset_proxy.md2
-rw-r--r--doc/security/crime_vulnerability.md2
-rw-r--r--doc/security/email_verification.md2
-rw-r--r--doc/security/hardening.md2
-rw-r--r--doc/security/hardening_application_recommendations.md18
-rw-r--r--doc/security/hardening_cicd_recommendations.md2
-rw-r--r--doc/security/hardening_configuration_recommendations.md2
-rw-r--r--doc/security/hardening_general_concepts.md2
-rw-r--r--doc/security/hardening_operating_system_recommendations.md2
-rw-r--r--doc/security/identity_verification.md2
-rw-r--r--doc/security/index.md4
-rw-r--r--doc/security/information_exclusivity.md2
-rw-r--r--doc/security/password_length_limits.md4
-rw-r--r--doc/security/password_storage.md2
-rw-r--r--doc/security/passwords_for_integrated_authentication_methods.md2
-rw-r--r--doc/security/project_import_decompressed_archive_size_limits.md4
-rw-r--r--doc/security/rate_limits.md7
-rw-r--r--doc/security/reset_user_password.md4
-rw-r--r--doc/security/responding_to_security_incidents.md2
-rw-r--r--doc/security/ssh_keys_restrictions.md4
-rw-r--r--doc/security/token_overview.md68
-rw-r--r--doc/security/two_factor_authentication.md162
-rw-r--r--doc/security/unlock_user.md10
-rw-r--r--doc/security/user_email_confirmation.md4
-rw-r--r--doc/security/user_file_uploads.md4
-rw-r--r--doc/security/webhooks.md10
-rw-r--r--doc/subscriptions/bronze_starter.md4
-rw-r--r--doc/subscriptions/community_programs.md8
-rw-r--r--doc/subscriptions/gitlab_com/index.md57
-rw-r--r--doc/subscriptions/gitlab_dedicated/index.md25
-rw-r--r--doc/subscriptions/quarterly_reconciliation.md9
-rw-r--r--doc/subscriptions/self_managed/index.md10
-rw-r--r--doc/topics/authentication/index.md3
-rw-r--r--doc/topics/autodevops/cicd_variables.md2
-rw-r--r--doc/topics/autodevops/cloud_deployments/auto_devops_with_ecs.md2
-rw-r--r--doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md2
-rw-r--r--doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md2
-rw-r--r--doc/topics/autodevops/index.md8
-rw-r--r--doc/topics/autodevops/prepare_deployment.md2
-rw-r--r--doc/topics/autodevops/requirements.md4
-rw-r--r--doc/topics/git/how_to_install_git/index.md6
-rw-r--r--doc/topics/git/index.md188
-rw-r--r--doc/topics/git/lfs/index.md22
-rw-r--r--doc/topics/git/troubleshooting_git.md2
-rw-r--r--doc/topics/offline/quick_start_guide.md32
-rw-r--r--doc/tutorials/automate_runner_creation/index.md220
-rw-r--r--doc/tutorials/boards_for_teams/index.md4
-rw-r--r--doc/tutorials/build_application.md2
-rw-r--r--doc/tutorials/compliance_pipeline/index.md18
-rw-r--r--doc/tutorials/configure_gitlab_runner_to_use_gke/index.md7
-rw-r--r--doc/tutorials/convert_personal_namespace_to_group/index.md4
-rw-r--r--doc/tutorials/create_register_first_runner/index.md8
-rw-r--r--doc/tutorials/dependency_scanning.md2
-rw-r--r--doc/tutorials/export_sbom.md95
-rw-r--r--doc/tutorials/fuzz_testing/index.md2
-rw-r--r--doc/tutorials/hugo/index.md2
-rw-r--r--doc/tutorials/issue_triage/index.md4
-rw-r--r--doc/tutorials/left_sidebar/img/admin_area_v16_4.pngbin0 -> 18865 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/project_selected_v16_0.pngbin23651 -> 0 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/project_selected_v16_4.pngbin0 -> 7385 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/search_projects_v16_0.pngbin12721 -> 0 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/search_projects_v16_4.pngbin0 -> 14560 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/sidebar_middle_v16_1.pngbin7789 -> 0 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/sidebar_middle_v16_4.pngbin0 -> 5528 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/sidebar_top_v16_1.pngbin8245 -> 0 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/sidebar_top_v16_4.pngbin0 -> 2786 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/your_work_v16_0.pngbin20880 -> 0 bytes
-rw-r--r--doc/tutorials/left_sidebar/img/your_work_v16_4.pngbin0 -> 7818 bytes
-rw-r--r--doc/tutorials/left_sidebar/index.md35
-rw-r--r--doc/tutorials/manage_user/index.md24
-rw-r--r--doc/tutorials/move_personal_project_to_group/index.md4
-rw-r--r--doc/tutorials/plan_and_track.md2
-rw-r--r--doc/tutorials/protected_workflow/index.md10
-rw-r--r--doc/tutorials/scan_execution_policy/index.md197
-rw-r--r--doc/tutorials/scan_result_policy/index.md6
-rw-r--r--doc/tutorials/secure_application.md2
-rw-r--r--doc/tutorials/update_commit_messages/index.md4
-rw-r--r--doc/tutorials/website_project_with_analytics/index.md28
-rw-r--r--doc/update/background_migrations.md239
-rw-r--r--doc/update/deprecations.md495
-rw-r--r--doc/update/index.md1551
-rw-r--r--doc/update/package/index.md8
-rw-r--r--doc/update/plan_your_upgrade.md8
-rw-r--r--doc/update/versions/gitlab_14_changes.md909
-rw-r--r--doc/update/versions/gitlab_15_changes.md921
-rw-r--r--doc/update/versions/gitlab_16_changes.md647
-rw-r--r--doc/user/ai_features.md89
-rw-r--r--doc/user/analytics/analytics_dashboards.md32
-rw-r--r--doc/user/analytics/ci_cd_analytics.md10
-rw-r--r--doc/user/analytics/code_review_analytics.md2
-rw-r--r--doc/user/analytics/contributor_statistics.md6
-rw-r--r--doc/user/analytics/dora_metrics.md22
-rw-r--r--doc/user/analytics/img/dora_performers_score_panel_v16_3.pngbin13108 -> 0 bytes
-rw-r--r--doc/user/analytics/img/issues_closed_analytics_v16_4.pngbin0 -> 17190 bytes
-rw-r--r--doc/user/analytics/index.md81
-rw-r--r--doc/user/analytics/issue_analytics.md18
-rw-r--r--doc/user/analytics/merge_request_analytics.md6
-rw-r--r--doc/user/analytics/productivity_analytics.md6
-rw-r--r--doc/user/analytics/repository_analytics.md4
-rw-r--r--doc/user/analytics/value_streams_dashboard.md34
-rw-r--r--doc/user/application_security/api_fuzzing/index.md2
-rw-r--r--doc/user/application_security/configuration/index.md9
-rw-r--r--doc/user/application_security/continuous_vulnerability_scanning/index.md59
-rw-r--r--doc/user/application_security/coverage_fuzzing/index.md6
-rw-r--r--doc/user/application_security/dast/authentication.md5
-rw-r--r--doc/user/application_security/dast/checks/113.1.md27
-rw-r--r--doc/user/application_security/dast/checks/16.7.md4
-rw-r--r--doc/user/application_security/dast/checks/16.9.md2
-rw-r--r--doc/user/application_security/dast/checks/index.md3
-rw-r--r--doc/user/application_security/dast/index.md4
-rw-r--r--doc/user/application_security/dast/proxy-based.md37
-rw-r--r--doc/user/application_security/dependency_list/img/dependency_list_v13_11.pngbin85626 -> 0 bytes
-rw-r--r--doc/user/application_security/dependency_list/img/dependency_list_v16_3.pngbin70360 -> 22792 bytes
-rw-r--r--doc/user/application_security/dependency_list/index.md79
-rw-r--r--doc/user/application_security/dependency_scanning/index.md124
-rw-r--r--doc/user/application_security/gitlab_advisory_database/index.md95
-rw-r--r--doc/user/application_security/iac_scanning/index.md4
-rw-r--r--doc/user/application_security/img/security_widget_v13_7.pngbin3276 -> 0 bytes
-rw-r--r--doc/user/application_security/img/security_widget_v16_4.pngbin0 -> 3147 bytes
-rw-r--r--doc/user/application_security/index.md46
-rw-r--r--doc/user/application_security/policies/index.md11
-rw-r--r--doc/user/application_security/policies/scan-execution-policies.md22
-rw-r--r--doc/user/application_security/policies/scan-result-policies.md41
-rw-r--r--doc/user/application_security/sast/analyzers.md2
-rw-r--r--doc/user/application_security/sast/customize_rulesets.md10
-rw-r--r--doc/user/application_security/sast/index.md34
-rw-r--r--doc/user/application_security/sast/rules.md101
-rw-r--r--doc/user/application_security/secret_detection/index.md16
-rw-r--r--doc/user/application_security/secure_your_application.md1
-rw-r--r--doc/user/application_security/security_dashboard/index.md12
-rw-r--r--doc/user/application_security/vulnerabilities/index.md91
-rw-r--r--doc/user/application_security/vulnerability_report/index.md18
-rw-r--r--doc/user/application_security/vulnerability_report/pipeline.md10
-rw-r--r--doc/user/award_emojis.md2
-rw-r--r--doc/user/clusters/agent/ci_cd_workflow.md14
-rw-r--r--doc/user/clusters/agent/gitops/flux_tutorial.md13
-rw-r--r--doc/user/clusters/agent/install/index.md18
-rw-r--r--doc/user/clusters/agent/user_access.md56
-rw-r--r--doc/user/clusters/agent/vulnerabilities.md13
-rw-r--r--doc/user/clusters/agent/work_with_agent.md14
-rw-r--r--doc/user/clusters/cost_management.md12
-rw-r--r--doc/user/clusters/integrations.md12
-rw-r--r--doc/user/clusters/management_project.md2
-rw-r--r--doc/user/clusters/management_project_template.md5
-rw-r--r--doc/user/compliance/compliance_center/index.md52
-rw-r--r--doc/user/compliance/license_approval_policies.md2
-rw-r--r--doc/user/compliance/license_compliance/index.md14
-rw-r--r--doc/user/compliance/license_list.md2
-rw-r--r--doc/user/compliance/license_scanning_of_cyclonedx_files/index.md47
-rw-r--r--doc/user/crm/index.md20
-rw-r--r--doc/user/discussions/index.md28
-rw-r--r--doc/user/enterprise_user/index.md12
-rw-r--r--doc/user/free_user_limit.md2
-rw-r--r--doc/user/gitlab_com/index.md10
-rw-r--r--doc/user/group/access_and_permissions.md29
-rw-r--r--doc/user/group/clusters/index.md4
-rw-r--r--doc/user/group/compliance_frameworks.md10
-rw-r--r--doc/user/group/contribution_analytics/index.md2
-rw-r--r--doc/user/group/custom_project_templates.md31
-rw-r--r--doc/user/group/devops_adoption/index.md4
-rw-r--r--doc/user/group/epics/epic_boards.md6
-rw-r--r--doc/user/group/epics/manage_epics.md4
-rw-r--r--doc/user/group/import/index.md30
-rw-r--r--doc/user/group/index.md42
-rw-r--r--doc/user/group/insights/index.md4
-rw-r--r--doc/user/group/issues_analytics/img/issues_closed_analytics_v16_4.pngbin0 -> 17190 bytes
-rw-r--r--doc/user/group/issues_analytics/index.md20
-rw-r--r--doc/user/group/iterations/index.md16
-rw-r--r--doc/user/group/manage.md53
-rw-r--r--doc/user/group/moderate_users.md2
-rw-r--r--doc/user/group/reporting/git_abuse_rate_limit.md2
-rw-r--r--doc/user/group/repositories_analytics/index.md4
-rw-r--r--doc/user/group/saml_sso/example_saml_config.md2
-rw-r--r--doc/user/group/saml_sso/group_sync.md11
-rw-r--r--doc/user/group/saml_sso/index.md14
-rw-r--r--doc/user/group/saml_sso/scim_setup.md29
-rw-r--r--doc/user/group/saml_sso/troubleshooting.md64
-rw-r--r--doc/user/group/saml_sso/troubleshooting_scim.md15
-rw-r--r--doc/user/group/settings/group_access_tokens.md14
-rw-r--r--doc/user/group/subgroups/index.md12
-rw-r--r--doc/user/group/value_stream_analytics/index.md20
-rw-r--r--doc/user/img/enable_AI_ML_features.pngbin0 -> 72967 bytes
-rw-r--r--doc/user/img/forecast_deployment_frequency.pngbin0 -> 7158468 bytes
-rw-r--r--doc/user/infrastructure/clusters/connect/index.md6
-rw-r--r--doc/user/infrastructure/clusters/connect/new_civo_cluster.md4
-rw-r--r--doc/user/infrastructure/clusters/connect/new_eks_cluster.md4
-rw-r--r--doc/user/infrastructure/clusters/connect/new_gke_cluster.md4
-rw-r--r--doc/user/infrastructure/clusters/index.md7
-rw-r--r--doc/user/infrastructure/clusters/manage/clusters_health.md12
-rw-r--r--doc/user/infrastructure/clusters/manage/management_project_applications/vault.md2
-rw-r--r--doc/user/infrastructure/iac/index.md2
-rw-r--r--doc/user/infrastructure/iac/terraform_state.md4
-rw-r--r--doc/user/instance/clusters/index.md2
-rw-r--r--doc/user/markdown.md5
-rw-r--r--doc/user/okrs.md10
-rw-r--r--doc/user/operations_dashboard/index.md2
-rw-r--r--doc/user/packages/composer_repository/index.md52
-rw-r--r--doc/user/packages/conan_repository/index.md2
-rw-r--r--doc/user/packages/container_registry/delete_container_registry_images.md2
-rw-r--r--doc/user/packages/container_registry/index.md10
-rw-r--r--doc/user/packages/container_registry/reduce_container_registry_storage.md2
-rw-r--r--doc/user/packages/container_registry/troubleshoot_container_registry.md11
-rw-r--r--doc/user/packages/debian_repository/index.md11
-rw-r--r--doc/user/packages/dependency_proxy/index.md15
-rw-r--r--doc/user/packages/generic_packages/index.md2
-rw-r--r--doc/user/packages/go_proxy/index.md2
-rw-r--r--doc/user/packages/harbor_container_registry/index.md10
-rw-r--r--doc/user/packages/helm_repository/index.md2
-rw-r--r--doc/user/packages/maven_repository/index.md2
-rw-r--r--doc/user/packages/nuget_repository/index.md15
-rw-r--r--doc/user/packages/package_registry/index.md13
-rw-r--r--doc/user/packages/package_registry/supported_functionality.md25
-rw-r--r--doc/user/packages/rubygems_registry/index.md2
-rw-r--r--doc/user/packages/yarn_repository/index.md4
-rw-r--r--doc/user/permissions.md143
-rw-r--r--doc/user/product_analytics/index.md21
-rw-r--r--doc/user/profile/account/create_accounts.md4
-rw-r--r--doc/user/profile/account/delete_account.md4
-rw-r--r--doc/user/profile/account/two_factor_authentication.md30
-rw-r--r--doc/user/profile/achievements.md2
-rw-r--r--doc/user/profile/img/profile-preferences-syntax-themes_v15_11.pngbin56643 -> 0 bytes
-rw-r--r--doc/user/profile/index.md12
-rw-r--r--doc/user/profile/notifications.md34
-rw-r--r--doc/user/profile/personal_access_tokens.md9
-rw-r--r--doc/user/profile/preferences.md309
-rw-r--r--doc/user/profile/service_accounts.md40
-rw-r--r--doc/user/profile/user_passwords.md2
-rw-r--r--doc/user/project/badges.md10
-rw-r--r--doc/user/project/clusters/add_eks_clusters.md4
-rw-r--r--doc/user/project/clusters/add_existing_cluster.md2
-rw-r--r--doc/user/project/clusters/add_gke_clusters.md2
-rw-r--r--doc/user/project/clusters/add_remove_clusters.md2
-rw-r--r--doc/user/project/clusters/index.md2
-rw-r--r--doc/user/project/codeowners/index.md110
-rw-r--r--doc/user/project/deploy_boards.md2
-rw-r--r--doc/user/project/deploy_keys/index.md14
-rw-r--r--doc/user/project/deploy_tokens/index.md6
-rw-r--r--doc/user/project/description_templates.md23
-rw-r--r--doc/user/project/file_lock.md4
-rw-r--r--doc/user/project/import/bitbucket.md4
-rw-r--r--doc/user/project/import/bitbucket_server.md5
-rw-r--r--doc/user/project/import/cvs.md6
-rw-r--r--doc/user/project/import/fogbugz.md2
-rw-r--r--doc/user/project/import/gitea.md2
-rw-r--r--doc/user/project/import/github.md33
-rw-r--r--doc/user/project/import/index.md2
-rw-r--r--doc/user/project/import/manifest.md2
-rw-r--r--doc/user/project/import/phabricator.md11
-rw-r--r--doc/user/project/import/repo_by_url.md6
-rw-r--r--doc/user/project/index.md2
-rw-r--r--doc/user/project/insights/index.md4
-rw-r--r--doc/user/project/integrations/apple_app_store.md2
-rw-r--r--doc/user/project/integrations/asana.md2
-rw-r--r--doc/user/project/integrations/bamboo.md2
-rw-r--r--doc/user/project/integrations/bugzilla.md4
-rw-r--r--doc/user/project/integrations/clickup.md4
-rw-r--r--doc/user/project/integrations/custom_issue_tracker.md2
-rw-r--r--doc/user/project/integrations/discord_notifications.md2
-rw-r--r--doc/user/project/integrations/emails_on_push.md2
-rw-r--r--doc/user/project/integrations/ewm.md2
-rw-r--r--doc/user/project/integrations/github.md2
-rw-r--r--doc/user/project/integrations/gitlab_slack_application.md21
-rw-r--r--doc/user/project/integrations/google_play.md2
-rw-r--r--doc/user/project/integrations/harbor.md2
-rw-r--r--doc/user/project/integrations/index.md2
-rw-r--r--doc/user/project/integrations/irker.md2
-rw-r--r--doc/user/project/integrations/mattermost.md2
-rw-r--r--doc/user/project/integrations/mattermost_slash_commands.md4
-rw-r--r--doc/user/project/integrations/microsoft_teams.md2
-rw-r--r--doc/user/project/integrations/pivotal_tracker.md2
-rw-r--r--doc/user/project/integrations/prometheus.md12
-rw-r--r--doc/user/project/integrations/prometheus_library/cloudwatch.md12
-rw-r--r--doc/user/project/integrations/prometheus_library/haproxy.md12
-rw-r--r--doc/user/project/integrations/prometheus_library/index.md12
-rw-r--r--doc/user/project/integrations/prometheus_library/kubernetes.md12
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx.md12
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress.md12
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md12
-rw-r--r--doc/user/project/integrations/pumble.md2
-rw-r--r--doc/user/project/integrations/redmine.md4
-rw-r--r--doc/user/project/integrations/shimo.md4
-rw-r--r--doc/user/project/integrations/slack.md17
-rw-r--r--doc/user/project/integrations/slack_slash_commands.md2
-rw-r--r--doc/user/project/integrations/squash_tm.md2
-rw-r--r--doc/user/project/integrations/telegram.md4
-rw-r--r--doc/user/project/integrations/unify_circuit.md2
-rw-r--r--doc/user/project/integrations/webex_teams.md4
-rw-r--r--doc/user/project/integrations/webhook_events.md16
-rw-r--r--doc/user/project/integrations/webhooks.md2
-rw-r--r--doc/user/project/integrations/youtrack.md4
-rw-r--r--doc/user/project/issues/confidential_issues.md4
-rw-r--r--doc/user/project/issues/create_issues.md10
-rw-r--r--doc/user/project/issues/crosslinking_issues.md7
-rw-r--r--doc/user/project/issues/csv_export.md151
-rw-r--r--doc/user/project/issues/design_management.md89
-rw-r--r--doc/user/project/issues/img/csv_export_button_v12_9.pngbin12951 -> 0 bytes
-rw-r--r--doc/user/project/issues/img/csv_export_modal.pngbin16825 -> 0 bytes
-rw-r--r--doc/user/project/issues/managing_issues.md38
-rw-r--r--doc/user/project/labels.md22
-rw-r--r--doc/user/project/members/index.md16
-rw-r--r--doc/user/project/members/share_project_with_groups.md11
-rw-r--r--doc/user/project/merge_requests/ai_in_merge_requests.md3
-rw-r--r--doc/user/project/merge_requests/approvals/rules.md36
-rw-r--r--doc/user/project/merge_requests/approvals/settings.md1
-rw-r--r--doc/user/project/merge_requests/changes.md2
-rw-r--r--doc/user/project/merge_requests/cherry_pick_changes.md8
-rw-r--r--doc/user/project/merge_requests/commit_templates.md18
-rw-r--r--doc/user/project/merge_requests/commits.md8
-rw-r--r--doc/user/project/merge_requests/conflicts.md4
-rw-r--r--doc/user/project/merge_requests/creating_merge_requests.md10
-rw-r--r--doc/user/project/merge_requests/csv_export.md2
-rw-r--r--doc/user/project/merge_requests/dependencies.md6
-rw-r--r--doc/user/project/merge_requests/index.md39
-rw-r--r--doc/user/project/merge_requests/merge_when_pipeline_succeeds.md10
-rw-r--r--doc/user/project/merge_requests/methods/index.md2
-rw-r--r--doc/user/project/merge_requests/revert_changes.md4
-rw-r--r--doc/user/project/merge_requests/reviews/img/suggested_reviewers_v15_9.pngbin9184 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/reviews/img/suggested_reviewers_v16_3.pngbin0 -> 18574 bytes
-rw-r--r--doc/user/project/merge_requests/reviews/index.md50
-rw-r--r--doc/user/project/merge_requests/reviews/suggestions.md8
-rw-r--r--doc/user/project/merge_requests/squash_and_merge.md2
-rw-r--r--doc/user/project/merge_requests/status_checks.md2
-rw-r--r--doc/user/project/milestones/burndown_and_burnup_charts.md9
-rw-r--r--doc/user/project/milestones/index.md14
-rw-r--r--doc/user/project/ml/experiment_tracking/index.md2
-rw-r--r--doc/user/project/ml/experiment_tracking/mlflow_client.md3
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/index.md16
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md6
-rw-r--r--doc/user/project/pages/getting_started/pages_ci_cd_template.md2
-rw-r--r--doc/user/project/pages/getting_started/pages_ui.md2
-rw-r--r--doc/user/project/pages/getting_started_part_one.md16
-rw-r--r--doc/user/project/pages/introduction.md14
-rw-r--r--doc/user/project/pages/redirects.md11
-rw-r--r--doc/user/project/protected_branches.md24
-rw-r--r--doc/user/project/protected_tags.md10
-rw-r--r--doc/user/project/push_options.md136
-rw-r--r--doc/user/project/quick_actions.md5
-rw-r--r--doc/user/project/releases/index.md36
-rw-r--r--doc/user/project/releases/release_cli.md2
-rw-r--r--doc/user/project/remote_development/connect_machine.md2
-rw-r--r--doc/user/project/remote_development/index.md2
-rw-r--r--doc/user/project/repository/branches/default.md12
-rw-r--r--doc/user/project/repository/branches/index.md101
-rw-r--r--doc/user/project/repository/code_suggestions.md375
-rw-r--r--doc/user/project/repository/code_suggestions/index.md192
-rw-r--r--doc/user/project/repository/code_suggestions/saas.md54
-rw-r--r--doc/user/project/repository/code_suggestions/self_managed.md187
-rw-r--r--doc/user/project/repository/code_suggestions/troubleshooting.md69
-rw-r--r--doc/user/project/repository/file_finder.md2
-rw-r--r--doc/user/project/repository/forking_workflow.md8
-rw-r--r--doc/user/project/repository/gpg_signed_commits/index.md333
-rw-r--r--doc/user/project/repository/index.md9
-rw-r--r--doc/user/project/repository/jupyter_notebooks/index.md2
-rw-r--r--doc/user/project/repository/managing_large_repositories.md408
-rw-r--r--doc/user/project/repository/mirror/bidirectional.md2
-rw-r--r--doc/user/project/repository/mirror/index.md9
-rw-r--r--doc/user/project/repository/mirror/pull.md7
-rw-r--r--doc/user/project/repository/mirror/push.md25
-rw-r--r--doc/user/project/repository/mirror/troubleshooting.md4
-rw-r--r--doc/user/project/repository/push_rules.md8
-rw-r--r--doc/user/project/repository/reducing_the_repo_size_using_git.md4
-rw-r--r--doc/user/project/repository/signed_commits/gpg.md284
-rw-r--r--doc/user/project/repository/signed_commits/img/profile_settings_gpg_keys_single_key.png (renamed from doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png)bin4366 -> 4366 bytes
-rw-r--r--doc/user/project/repository/signed_commits/img/project_signed_and_unsigned_commits.png (renamed from doc/user/project/repository/gpg_signed_commits/img/project_signed_and_unsigned_commits.png)bin42290 -> 42290 bytes
-rw-r--r--doc/user/project/repository/signed_commits/img/project_signed_commit_unverified_signature.png (renamed from doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_unverified_signature.png)bin7188 -> 7188 bytes
-rw-r--r--doc/user/project/repository/signed_commits/img/project_signed_commit_verified_signature.png (renamed from doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_verified_signature.png)bin9771 -> 9771 bytes
-rw-r--r--doc/user/project/repository/signed_commits/index.md64
-rw-r--r--doc/user/project/repository/signed_commits/ssh.md167
-rw-r--r--doc/user/project/repository/signed_commits/x509.md362
-rw-r--r--doc/user/project/repository/ssh_signed_commits/index.md184
-rw-r--r--doc/user/project/repository/tags/index.md6
-rw-r--r--doc/user/project/repository/web_editor.md14
-rw-r--r--doc/user/project/repository/x509_signed_commits/index.md369
-rw-r--r--doc/user/project/requirements/index.md2
-rw-r--r--doc/user/project/service_desk/configure.md873
-rw-r--r--doc/user/project/service_desk/index.md879
-rw-r--r--doc/user/project/service_desk/using_service_desk.md182
-rw-r--r--doc/user/project/settings/import_export.md8
-rw-r--r--doc/user/project/settings/index.md333
-rw-r--r--doc/user/project/settings/project_access_tokens.md12
-rw-r--r--doc/user/project/system_notes.md6
-rw-r--r--doc/user/project/time_tracking.md2
-rw-r--r--doc/user/project/web_ide/index.md18
-rw-r--r--doc/user/project/web_ide_beta/index.md11
-rw-r--r--doc/user/project/wiki/group.md4
-rw-r--r--doc/user/project/wiki/index.md26
-rw-r--r--doc/user/project/working_with_projects.md70
-rw-r--r--doc/user/public_access.md4
-rw-r--r--doc/user/report_abuse.md13
-rw-r--r--doc/user/search/advanced_search.md18
-rw-r--r--doc/user/search/command_palette.md10
-rw-r--r--doc/user/search/exact_code_search.md18
-rw-r--r--doc/user/search/index.md182
-rw-r--r--doc/user/shortcuts.md40
-rw-r--r--doc/user/snippets.md24
-rw-r--r--doc/user/ssh.md22
-rw-r--r--doc/user/storage_management_automation.md4
-rw-r--r--doc/user/tasks.md10
-rw-r--r--doc/user/usage_quotas.md29
-rw-r--r--doc/user/workspace/configuration.md13
-rw-r--r--doc/user/workspace/create_image.md2
-rw-r--r--doc/user/workspace/index.md19
-rw-r--r--gems/activerecord-gitlab/lib/active_record/gitlab_patches/rescue_from.rb6
-rw-r--r--gems/activerecord-gitlab/spec/active_record/gitlab_patches/rescue_from_spec.rb26
-rw-r--r--gems/click_house-client/lib/click_house/client.rb61
-rw-r--r--gems/click_house-client/lib/click_house/client/bind_index_manager.rb17
-rw-r--r--gems/click_house-client/lib/click_house/client/configuration.rb12
-rw-r--r--gems/click_house-client/lib/click_house/client/database.rb15
-rw-r--r--gems/click_house-client/lib/click_house/client/formatter.rb3
-rw-r--r--gems/click_house-client/lib/click_house/client/query.rb74
-rw-r--r--gems/click_house-client/lib/click_house/client/query_like.rb19
-rw-r--r--gems/click_house-client/spec/click_house/client/bind_index_manager_spec.rb33
-rw-r--r--gems/click_house-client/spec/click_house/client/database_spec.rb1
-rw-r--r--gems/click_house-client/spec/click_house/client/formatter_spec.rb63
-rw-r--r--gems/click_house-client/spec/click_house/client/query_like_spec.rb15
-rw-r--r--gems/click_house-client/spec/click_house/client/query_spec.rb125
-rw-r--r--gems/click_house-client/spec/click_house/client_spec.rb34
-rw-r--r--gems/config/rubocop.yml5
-rw-r--r--gems/csv_builder/lib/csv_builder/gzip.rb8
-rw-r--r--gems/csv_builder/spec/csv_builder/gzip_spec.rb7
-rw-r--r--gems/gem.gitlab-ci.yml2
-rw-r--r--gems/gitlab-http/.gitignore11
-rw-r--r--gems/gitlab-http/.gitlab-ci.yml4
-rw-r--r--gems/gitlab-http/.rspec3
-rw-r--r--gems/gitlab-http/.rubocop.yml22
-rw-r--r--gems/gitlab-http/Gemfile12
-rw-r--r--gems/gitlab-http/Gemfile.lock185
-rw-r--r--gems/gitlab-http/README.md42
-rw-r--r--gems/gitlab-http/gitlab-http.gemspec33
-rw-r--r--gems/gitlab-http/lib/gitlab-http.rb11
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2.rb23
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/buffered_io.rb74
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/client.rb95
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/configuration.rb17
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/domain_allowlist_entry.rb21
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/exceptions.rb24
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/ip_allowlist_entry.rb43
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/net_http_adapter.rb35
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb81
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/patches.rb6
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/url_allowlist.rb70
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/url_blocker.rb409
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/version.rb9
-rw-r--r--gems/gitlab-http/lib/hostname_override_patch.rb54
-rw-r--r--gems/gitlab-http/lib/httparty/response_patch.rb15
-rw-r--r--gems/gitlab-http/lib/net_http/protocol_patch.rb39
-rw-r--r--gems/gitlab-http/lib/net_http/response_patch.rb52
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/buffered_io_spec.rb56
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/domain_allowlist_entry_spec.rb58
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/ip_allowlist_entry_spec.rb95
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/net_http_adapter_spec.rb23
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb92
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/net_http_response_patch_spec.rb77
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/new_connection_adapter_spec.rb157
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/url_allowlist_spec.rb153
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2/url_blocker_spec.rb988
-rw-r--r--gems/gitlab-http/spec/gitlab/http_v2_spec.rb453
-rw-r--r--gems/gitlab-http/spec/gitlab/stub_requests.rb57
-rw-r--r--gems/gitlab-http/spec/spec_helper.rb50
-rw-r--r--gems/gitlab-schema-validation/lib/gitlab/schema/validation/inconsistency.rb11
-rw-r--r--gems/gitlab-schema-validation/spec/lib/gitlab/schema/validation/inconsistency_spec.rb19
-rw-r--r--jest.config.base.js6
-rw-r--r--lefthook.yml12
-rw-r--r--lib/api/ci/helpers/runner.rb14
-rw-r--r--lib/api/ci/jobs.rb2
-rw-r--r--lib/api/commit_statuses.rb82
-rw-r--r--lib/api/commits.rb2
-rw-r--r--lib/api/concerns/packages/npm_endpoints.rb27
-rw-r--r--lib/api/discussions.rb2
-rw-r--r--lib/api/entities/ci/job_request/job_info.rb2
-rw-r--r--lib/api/entities/diff.rb2
-rw-r--r--lib/api/entities/feature.rb6
-rw-r--r--lib/api/entities/feature_flag/basic_user_list.rb14
-rw-r--r--lib/api/entities/feature_flag/strategy.rb1
-rw-r--r--lib/api/entities/feature_flag/user_list.rb6
-rw-r--r--lib/api/entities/merge_request_diff.rb2
-rw-r--r--lib/api/entities/ml/mlflow/get_run.rb13
-rw-r--r--lib/api/entities/ml/mlflow/run.rb12
-rw-r--r--lib/api/entities/ml/mlflow/search_runs.rb14
-rw-r--r--lib/api/entities/note.rb2
-rw-r--r--lib/api/entities/personal_access_token.rb2
-rw-r--r--lib/api/entities/project_integration_basic.rb2
-rw-r--r--lib/api/feature_flags.rb4
-rw-r--r--lib/api/helpers.rb33
-rw-r--r--lib/api/helpers/common_helpers.rb2
-rw-r--r--lib/api/helpers/integrations_helpers.rb115
-rw-r--r--lib/api/helpers/kubernetes/agent_helpers.rb119
-rw-r--r--lib/api/helpers/notes_helpers.rb2
-rw-r--r--lib/api/helpers/packages/maven.rb60
-rw-r--r--lib/api/helpers/packages_helpers.rb5
-rw-r--r--lib/api/helpers/projects_helpers.rb42
-rw-r--r--lib/api/helpers/search_helpers.rb8
-rw-r--r--lib/api/integrations.rb2
-rw-r--r--lib/api/internal/kubernetes.rb104
-rw-r--r--lib/api/internal/pages.rb11
-rw-r--r--lib/api/maven_packages.rb52
-rw-r--r--lib/api/merge_requests.rb2
-rw-r--r--lib/api/metadata.rb2
-rw-r--r--lib/api/ml/mlflow/api_helpers.rb39
-rw-r--r--lib/api/ml/mlflow/entrypoint.rb3
-rw-r--r--lib/api/ml/mlflow/runs.rb44
-rw-r--r--lib/api/notification_settings.rb8
-rw-r--r--lib/api/npm_group_packages.rb4
-rw-r--r--lib/api/npm_instance_packages.rb4
-rw-r--r--lib/api/nuget_project_packages.rb97
-rw-r--r--lib/api/project_export.rb2
-rw-r--r--lib/api/project_import.rb3
-rw-r--r--lib/api/repositories.rb2
-rw-r--r--lib/api/search.rb5
-rw-r--r--lib/api/settings.rb2
-rw-r--r--lib/api/users.rb8
-rw-r--r--lib/api/validations/validators/bulk_imports.rb5
-rw-r--r--lib/backup/database.rb123
-rw-r--r--lib/backup/database_model.rb80
-rw-r--r--lib/backup/manager.rb4
-rw-r--r--lib/backup/repositories.rb5
-rw-r--r--lib/banzai/filter/ascii_doc_sanitization_filter.rb32
-rw-r--r--lib/banzai/filter/autolink_filter.rb2
-rw-r--r--lib/banzai/filter/base_sanitization_filter.rb10
-rw-r--r--lib/banzai/filter/broadcast_message_sanitization_filter.rb2
-rw-r--r--lib/banzai/filter/code_language_filter.rb11
-rw-r--r--lib/banzai/filter/custom_emoji_filter.rb2
-rw-r--r--lib/banzai/filter/emoji_filter.rb2
-rw-r--r--lib/banzai/filter/gollum_tags_filter.rb4
-rw-r--r--lib/banzai/filter/inline_diff_filter.rb2
-rw-r--r--lib/banzai/filter/issuable_reference_expansion_filter.rb2
-rw-r--r--lib/banzai/filter/references/reference_filter.rb2
-rw-r--r--lib/banzai/filter/repository_link_filter.rb2
-rw-r--r--lib/banzai/filter/sanitization_filter.rb2
-rw-r--r--lib/banzai/filter/spaced_link_filter.rb2
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb2
-rw-r--r--lib/banzai/filter/table_of_contents_filter.rb4
-rw-r--r--lib/banzai/pipeline/base_pipeline.rb2
-rw-r--r--lib/banzai/pipeline/description_pipeline.rb2
-rw-r--r--lib/banzai/pipeline/incident_management/timeline_event_pipeline.rb2
-rw-r--r--lib/bitbucket/page.rb2
-rw-r--r--lib/bitbucket/representation/issue.rb2
-rw-r--r--lib/bitbucket/representation/pull_request.rb34
-rw-r--r--lib/bulk_imports/common/graphql/get_members_query.rb23
-rw-r--r--lib/bulk_imports/common/pipelines/entity_finisher.rb2
-rw-r--r--lib/bulk_imports/common/transformers/member_attributes_transformer.rb13
-rw-r--r--lib/bulk_imports/groups/loaders/group_loader.rb12
-rw-r--r--lib/bulk_imports/network_error.rb13
-rw-r--r--lib/bulk_imports/pipeline/runner.rb8
-rw-r--r--lib/bulk_imports/projects/pipelines/references_pipeline.rb25
-rw-r--r--lib/bulk_imports/users_mapper.rb41
-rw-r--r--lib/click_house/bind_index_manager.rb15
-rw-r--r--lib/click_house/logger.rb11
-rw-r--r--lib/click_house/query_builder.rb6
-rw-r--r--lib/click_house/record_sync_context.rb43
-rw-r--r--lib/click_house/redactor.rb3
-rw-r--r--lib/click_house/sync_cursor.rb41
-rw-r--r--lib/constraints/activity_pub_constrainer.rb20
-rw-r--r--lib/container_registry/path.rb2
-rw-r--r--lib/feature.rb2
-rw-r--r--lib/generators/batched_background_migration/templates/batched_background_migration_job_spec.template2
-rw-r--r--lib/generators/gitlab/analytics/internal_events_generator.rb16
-rw-r--r--lib/generators/gitlab/usage_metric_definition_generator.rb2
-rw-r--r--lib/generators/gitlab/usage_metric_generator.rb4
-rw-r--r--lib/gitlab.rb2
-rw-r--r--lib/gitlab/alert_management/payload/prometheus.rb28
-rw-r--r--lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb2
-rw-r--r--lib/gitlab/auth.rb11
-rw-r--r--lib/gitlab/auth/devise/strategies/combined_two_factor_authenticatable.rb52
-rw-r--r--lib/gitlab/auth/ldap/adapter.rb2
-rw-r--r--lib/gitlab/auth/ldap/config.rb4
-rw-r--r--lib/gitlab/auth/o_auth/provider.rb4
-rw-r--r--lib/gitlab/background_migration/backfill_has_merge_request_of_vulnerability_reads.rb41
-rw-r--r--lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb2
-rw-r--r--lib/gitlab/background_migration/backfill_note_discussion_id.rb2
-rw-r--r--lib/gitlab/background_migration/backfill_nuget_normalized_version.rb98
-rw-r--r--lib/gitlab/background_migration/backfill_project_statistics_storage_size_with_recent_size.rb165
-rw-r--r--lib/gitlab/background_migration/backfill_snippet_repositories.rb2
-rw-r--r--lib/gitlab/background_migration/backfill_user_preferences_with_defaults.rb21
-rw-r--r--lib/gitlab/background_migration/backfill_users_with_defaults.rb22
-rw-r--r--lib/gitlab/background_migration/backfill_workspace_personal_access_token.rb13
-rw-r--r--lib/gitlab/background_migration/cleanup_orphaned_routes.rb2
-rw-r--r--lib/gitlab/background_migration/convert_credit_card_validation_data_to_hashes.rb39
-rw-r--r--lib/gitlab/background_migration/create_compliance_standards_adherence.rb17
-rw-r--r--lib/gitlab/background_migration/fix_first_mentioned_in_commit_at.rb2
-rw-r--r--lib/gitlab/background_migration/fix_namespace_ids_of_vulnerability_reads.rb17
-rw-r--r--lib/gitlab/background_migration/fix_projects_without_project_feature.rb2
-rw-r--r--lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb4
-rw-r--r--lib/gitlab/background_migration/populate_denormalized_columns_for_sbom_occurrences.rb17
-rw-r--r--lib/gitlab/background_migration/populate_projects_star_count.rb2
-rw-r--r--lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces.rb2
-rw-r--r--lib/gitlab/background_migration/rebalance_partition_id.rb21
-rw-r--r--lib/gitlab/background_migration/sync_scan_result_policies.rb14
-rw-r--r--lib/gitlab/background_migration/update_users_set_external_if_service_account.rb18
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb6
-rw-r--r--lib/gitlab/bitbucket_import/importers/pull_request_importer.rb88
-rw-r--r--lib/gitlab/bitbucket_import/importers/pull_requests_importer.rb47
-rw-r--r--lib/gitlab/bitbucket_import/importers/repository_importer.rb78
-rw-r--r--lib/gitlab/bitbucket_import/loggable.rb41
-rw-r--r--lib/gitlab/bitbucket_import/logger.rb11
-rw-r--r--lib/gitlab/bitbucket_import/parallel_importer.rb37
-rw-r--r--lib/gitlab/bitbucket_import/parallel_scheduling.rb93
-rw-r--r--lib/gitlab/bitbucket_import/user_finder.rb46
-rw-r--r--lib/gitlab/bitbucket_server_import/importer.rb468
-rw-r--r--lib/gitlab/checks/matching_merge_request.rb4
-rw-r--r--lib/gitlab/ci/ansi2html.rb12
-rw-r--r--lib/gitlab/ci/build/artifacts/metadata.rb8
-rw-r--r--lib/gitlab/ci/build/duration_parser.rb2
-rw-r--r--lib/gitlab/ci/components/instance_path.rb48
-rw-r--r--lib/gitlab/ci/config.rb1
-rw-r--r--lib/gitlab/ci/config/entry/bridge.rb2
-rw-r--r--lib/gitlab/ci/config/entry/default.rb7
-rw-r--r--lib/gitlab/ci/config/entry/include/rules.rb5
-rw-r--r--lib/gitlab/ci/config/entry/include/rules/rule.rb10
-rw-r--r--lib/gitlab/ci/config/entry/job.rb18
-rw-r--r--lib/gitlab/ci/config/entry/processable.rb8
-rw-r--r--lib/gitlab/ci/config/external/context.rb10
-rw-r--r--lib/gitlab/ci/config/external/file/component.rb2
-rw-r--r--lib/gitlab/ci/config/external/mapper/verifier.rb2
-rw-r--r--lib/gitlab/ci/config/external/rules.rb44
-rw-r--r--lib/gitlab/ci/config/interpolation/interpolator.rb7
-rw-r--r--lib/gitlab/ci/jwt_v2.rb4
-rw-r--r--lib/gitlab/ci/parsers/sbom/cyclonedx.rb9
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb4
-rw-r--r--lib/gitlab/ci/pipeline/chain/sequence.rb1
-rw-r--r--lib/gitlab/ci/queue/metrics.rb27
-rw-r--r--lib/gitlab/ci/reports/codequality_reports.rb2
-rw-r--r--lib/gitlab/ci/reports/sbom/component.rb14
-rw-r--r--lib/gitlab/ci/reports/sbom/metadata.rb19
-rw-r--r--lib/gitlab/ci/reports/sbom/report.rb16
-rw-r--r--lib/gitlab/ci/reports/test_reports_comparer.rb2
-rw-r--r--lib/gitlab/ci/reports/test_suite.rb2
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml4
-rw-r--r--lib/gitlab/ci/templates/Cosign.gitlab-ci.yml22
-rw-r--r--lib/gitlab/ci/templates/Docker.gitlab-ci.yml17
-rw-r--r--lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml39
-rw-r--r--lib/gitlab/ci/trace.rb6
-rw-r--r--lib/gitlab/ci/trace/stream.rb41
-rw-r--r--lib/gitlab/ci/variables/builder.rb12
-rw-r--r--lib/gitlab/ci/yaml_processor.rb6
-rw-r--r--lib/gitlab/cleanup/orphan_job_artifact_files.rb2
-rw-r--r--lib/gitlab/cluster/rack_timeout_observer.rb2
-rw-r--r--lib/gitlab/composer/version_index.rb3
-rw-r--r--lib/gitlab/config/entry/legacy_validation_helpers.rb10
-rw-r--r--lib/gitlab/content_security_policy/config_loader.rb11
-rw-r--r--lib/gitlab/data_builder/deployment.rb2
-rw-r--r--lib/gitlab/database.rb31
-rw-r--r--lib/gitlab/database/as_with_materialized.rb18
-rw-r--r--lib/gitlab/database/async_indexes/migration_helpers.rb1
-rw-r--r--lib/gitlab/database/bulk_update.rb2
-rw-r--r--lib/gitlab/database/load_balancing/connection_proxy.rb8
-rw-r--r--lib/gitlab/database/load_balancing/host.rb24
-rw-r--r--lib/gitlab/database/load_balancing/load_balancer.rb30
-rw-r--r--lib/gitlab/database/load_balancing/rack_middleware.rb10
-rw-r--r--lib/gitlab/database/load_balancing/service_discovery.rb47
-rw-r--r--lib/gitlab/database/load_balancing/service_discovery/sampler.rb2
-rw-r--r--lib/gitlab/database/load_balancing/sticking.rb95
-rw-r--r--lib/gitlab/database/load_balancing/wal_tracking_receiver.rb2
-rw-r--r--lib/gitlab/database/migration_helpers/cascading_namespace_settings.rb2
-rw-r--r--lib/gitlab/database/migrations/instrumentation.rb2
-rw-r--r--lib/gitlab/database/partitioning.rb14
-rw-r--r--lib/gitlab/database/partitioning/monthly_strategy.rb7
-rw-r--r--lib/gitlab/database/partitioning/partition_manager.rb64
-rw-r--r--lib/gitlab/database/partitioning/sliding_list_strategy.rb5
-rw-r--r--lib/gitlab/database/postgres_hll/batch_distinct_counter.rb2
-rw-r--r--lib/gitlab/database/query_analyzers/prevent_cross_database_modification.rb1
-rw-r--r--lib/gitlab/database/reindexing.rb14
-rw-r--r--lib/gitlab/database/tables_truncate.rb52
-rw-r--r--lib/gitlab/database_importers/work_items/base_type_importer.rb6
-rw-r--r--lib/gitlab/database_warnings.rb60
-rw-r--r--lib/gitlab/dependency_linker/base_linker.rb4
-rw-r--r--lib/gitlab/diff/char_diff.rb2
-rw-r--r--lib/gitlab/diff/inline_diff_marker.rb2
-rw-r--r--lib/gitlab/diff/line.rb2
-rw-r--r--lib/gitlab/doorkeeper_secret_storing/token/unique_application_token.rb18
-rw-r--r--lib/gitlab/email/handler/create_note_handler.rb4
-rw-r--r--lib/gitlab/email/handler/service_desk_handler.rb6
-rw-r--r--lib/gitlab/email/message/in_product_marketing.rb18
-rw-r--r--lib/gitlab/email/message/in_product_marketing/admin_verify.rb47
-rw-r--r--lib/gitlab/email/message/in_product_marketing/base.rb127
-rw-r--r--lib/gitlab/email/message/in_product_marketing/create.rb105
-rw-r--r--lib/gitlab/email/message/in_product_marketing/helper.rb9
-rw-r--r--lib/gitlab/email/message/in_product_marketing/team.rb84
-rw-r--r--lib/gitlab/email/message/in_product_marketing/team_short.rb47
-rw-r--r--lib/gitlab/email/message/in_product_marketing/trial.rb79
-rw-r--r--lib/gitlab/email/message/in_product_marketing/trial_short.rb47
-rw-r--r--lib/gitlab/email/message/in_product_marketing/verify.rb97
-rw-r--r--lib/gitlab/email/service_desk/custom_email.rb25
-rw-r--r--lib/gitlab/etag_caching/middleware.rb2
-rw-r--r--lib/gitlab/etag_caching/router/graphql.rb6
-rw-r--r--lib/gitlab/etag_caching/router/rails.rb39
-rw-r--r--lib/gitlab/etag_caching/store.rb4
-rw-r--r--lib/gitlab/event_store.rb20
-rw-r--r--lib/gitlab/event_store/store.rb4
-rw-r--r--lib/gitlab/event_store/subscription.rb11
-rw-r--r--lib/gitlab/fips.rb14
-rw-r--r--lib/gitlab/fogbugz_import/importer.rb12
-rw-r--r--lib/gitlab/git.rb1
-rw-r--r--lib/gitlab/git/blob.rb2
-rw-r--r--lib/gitlab/git/diff.rb38
-rw-r--r--lib/gitlab/git/diff_collection.rb13
-rw-r--r--lib/gitlab/git/repository.rb18
-rw-r--r--lib/gitlab/git/rugged_impl/repository.rb2
-rw-r--r--lib/gitlab/git/tree.rb2
-rw-r--r--lib/gitlab/git_access.rb4
-rw-r--r--lib/gitlab/git_access_design.rb21
-rw-r--r--lib/gitlab/gitaly_client.rb2
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb3
-rw-r--r--lib/gitlab/gitaly_client/diff.rb2
-rw-r--r--lib/gitlab/gitaly_client/operation_service.rb3
-rw-r--r--lib/gitlab/gitaly_client/ref_service.rb31
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb16
-rw-r--r--lib/gitlab/gitaly_client/wiki_page.rb2
-rw-r--r--lib/gitlab/github_import.rb2
-rw-r--r--lib/gitlab/github_import/attachments_downloader.rb39
-rw-r--r--lib/gitlab/github_import/client.rb14
-rw-r--r--lib/gitlab/github_import/importer/note_attachments_importer.rb19
-rw-r--r--lib/gitlab/github_import/markdown/attachment.rb13
-rw-r--r--lib/gitlab/github_import/object_counter.rb10
-rw-r--r--lib/gitlab/github_import/user_finder.rb110
-rw-r--r--lib/gitlab/gl_repository.rb3
-rw-r--r--lib/gitlab/gl_repository/repo_type.rb32
-rw-r--r--lib/gitlab/gon_helper.rb15
-rw-r--r--lib/gitlab/graphql/deprecations.rb1
-rw-r--r--lib/gitlab/graphql/deprecations/deprecation.rb4
-rw-r--r--lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb2
-rw-r--r--lib/gitlab/hook_data/user_builder.rb2
-rw-r--r--lib/gitlab/hotlinking_detector.rb8
-rw-r--r--lib/gitlab/http.rb14
-rw-r--r--lib/gitlab/http_connection_adapter.rb2
-rw-r--r--lib/gitlab/i18n.rb14
-rw-r--r--lib/gitlab/import.rb7
-rw-r--r--lib/gitlab/import_export/base/relation_object_saver.rb3
-rw-r--r--lib/gitlab/import_export/command_line_util.rb10
-rw-r--r--lib/gitlab/import_export/decompressed_archive_size_validator.rb23
-rw-r--r--lib/gitlab/import_export/json/ndjson_writer.rb3
-rw-r--r--lib/gitlab/import_export/json/streaming_serializer.rb14
-rw-r--r--lib/gitlab/import_export/project/import_export.yml5
-rw-r--r--lib/gitlab/import_export/project/relation_factory.rb3
-rw-r--r--lib/gitlab/import_export/repo_restorer.rb2
-rw-r--r--lib/gitlab/import_sources.rb13
-rw-r--r--lib/gitlab/instrumentation/redis_base.rb10
-rw-r--r--lib/gitlab/instrumentation/redis_interceptor.rb5
-rw-r--r--lib/gitlab/jira_import/metadata_collector.rb4
-rw-r--r--lib/gitlab/job_waiter.rb14
-rw-r--r--lib/gitlab/kas.rb2
-rw-r--r--lib/gitlab/kroki.rb4
-rw-r--r--lib/gitlab/kubernetes/kubectl_cmd.rb8
-rw-r--r--lib/gitlab/logger.rb2
-rw-r--r--lib/gitlab/lograge/custom_options.rb2
-rw-r--r--lib/gitlab/manifest_import/metadata.rb6
-rw-r--r--lib/gitlab/metrics/background_transaction.rb2
-rw-r--r--lib/gitlab/metrics/dashboard/cache.rb63
-rw-r--r--lib/gitlab/metrics/dashboard/errors.rb41
-rw-r--r--lib/gitlab/metrics/dashboard/processor.rb33
-rw-r--r--lib/gitlab/metrics/dashboard/repo_dashboard_finder.rb37
-rw-r--r--lib/gitlab/metrics/dashboard/stages/base_stage.rb74
-rw-r--r--lib/gitlab/metrics/dashboard/stages/url_validator.rb58
-rw-r--r--lib/gitlab/metrics/dashboard/transformers/errors.rb19
-rw-r--r--lib/gitlab/metrics/dashboard/url.rb133
-rw-r--r--lib/gitlab/metrics/requests_rack_middleware.rb14
-rw-r--r--lib/gitlab/metrics/samplers/database_sampler.rb4
-rw-r--r--lib/gitlab/metrics/subscribers/action_view.rb2
-rw-r--r--lib/gitlab/metrics/subscribers/active_record.rb8
-rw-r--r--lib/gitlab/metrics/transaction.rb2
-rw-r--r--lib/gitlab/metrics/web_transaction.rb2
-rw-r--r--lib/gitlab/middleware/read_only/controller.rb14
-rw-r--r--lib/gitlab/observability.rb16
-rw-r--r--lib/gitlab/pages.rb24
-rw-r--r--lib/gitlab/pages/virtual_host_finder.rb18
-rw-r--r--lib/gitlab/pagination/cursor_based_keyset.rb31
-rw-r--r--lib/gitlab/pagination/keyset/cursor_based_request_context.rb8
-rw-r--r--lib/gitlab/patch/redis_cache_store.rb10
-rw-r--r--lib/gitlab/patch/sidekiq_scheduled_enq.rb36
-rw-r--r--lib/gitlab/project_search_results.rb2
-rw-r--r--lib/gitlab/prometheus/additional_metrics_parser.rb45
-rw-r--r--lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb27
-rw-r--r--lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb27
-rw-r--r--lib/gitlab/prometheus/query_variables.rb2
-rw-r--r--lib/gitlab/query_limiting/transaction.rb2
-rw-r--r--lib/gitlab/rack_attack.rb94
-rw-r--r--lib/gitlab/rack_attack/request.rb34
-rw-r--r--lib/gitlab/rack_load_balancing_helpers.rb14
-rw-r--r--lib/gitlab/redis.rb5
-rw-r--r--lib/gitlab/redis/etag_cache.rb22
-rw-r--r--lib/gitlab/redis/multi_store.rb24
-rw-r--r--lib/gitlab/redis/pubsub.rb13
-rw-r--r--lib/gitlab/redis/queues_metadata.rb22
-rw-r--r--lib/gitlab/redis/workhorse.rb22
-rw-r--r--lib/gitlab/redis/wrapper.rb43
-rw-r--r--lib/gitlab/reference_extractor.rb6
-rw-r--r--lib/gitlab/regex.rb7
-rw-r--r--lib/gitlab/regex/bulk_imports.rb18
-rw-r--r--lib/gitlab/repo_path.rb8
-rw-r--r--lib/gitlab/saas.rb2
-rw-r--r--lib/gitlab/sanitizers/exception_message.rb4
-rw-r--r--lib/gitlab/sanitizers/exif.rb10
-rw-r--r--lib/gitlab/sanitizers/svg.rb2
-rw-r--r--lib/gitlab/search/abuse_detection.rb14
-rw-r--r--lib/gitlab/search/found_blob.rb4
-rw-r--r--lib/gitlab/search/query.rb4
-rw-r--r--lib/gitlab/search_context.rb2
-rw-r--r--lib/gitlab/search_results.rb33
-rw-r--r--lib/gitlab/security/scan_configuration.rb4
-rw-r--r--lib/gitlab/setup_helper.rb4
-rw-r--r--lib/gitlab/sidekiq_config/worker_matcher.rb2
-rw-r--r--lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb7
-rw-r--r--lib/gitlab/silent_mode.rb4
-rw-r--r--lib/gitlab/slash_commands/deploy.rb2
-rw-r--r--lib/gitlab/slash_commands/presenters/base.rb2
-rw-r--r--lib/gitlab/slug/path.rb6
-rw-r--r--lib/gitlab/spamcheck/client.rb2
-rw-r--r--lib/gitlab/sql/pattern.rb22
-rw-r--r--lib/gitlab/ssh_public_key.rb12
-rw-r--r--lib/gitlab/task_helpers.rb12
-rw-r--r--lib/gitlab/themes.rb24
-rw-r--r--lib/gitlab/time_tracking_formatter.rb7
-rw-r--r--lib/gitlab/tracking/destinations/database_events_snowplow.rb2
-rw-r--r--lib/gitlab/tracking/service_ping_context.rb21
-rw-r--r--lib/gitlab/tracking/standard_context.rb8
-rw-r--r--lib/gitlab/unicode.rb4
-rw-r--r--lib/gitlab/untrusted_regexp/ruby_syntax.rb2
-rw-r--r--lib/gitlab/url_blocker.rb2
-rw-r--r--lib/gitlab/url_sanitizer.rb14
-rw-r--r--lib/gitlab/usage/metric_definition.rb19
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb4
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/count_connected_agents_metric.rb17
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric.rb4
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric.rb2
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/database_metric.rb2
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/issues_created_from_alerts_metric.rb3
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/issues_with_self_managed_prometheus_alert_events.rb24
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb2
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/redis_metric.rb2
-rw-r--r--lib/gitlab/usage/time_series_storable.rb22
-rw-r--r--lib/gitlab/usage_data.rb8
-rw-r--r--lib/gitlab/usage_data/topology.rb2
-rw-r--r--lib/gitlab/usage_data_counters/ci_template_unique_counter.rb2
-rw-r--r--lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter.rb2
-rw-r--r--lib/gitlab/usage_data_counters/hll_redis_counter.rb9
-rw-r--r--lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb108
-rw-r--r--lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb2
-rw-r--r--lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb1
-rw-r--r--lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter.rb2
-rw-r--r--lib/gitlab/utils/link_header_parser.rb4
-rw-r--r--lib/gitlab/utils/markdown.rb4
-rw-r--r--lib/gitlab/utils/override.rb3
-rw-r--r--lib/gitlab/utils/sanitize_node_link.rb4
-rw-r--r--lib/gitlab/uuid.rb2
-rw-r--r--lib/gitlab/web_hooks/rate_limiter.rb2
-rw-r--r--lib/gitlab/workhorse.rb29
-rw-r--r--lib/gitlab/x509/certificate.rb2
-rw-r--r--lib/gitlab/x509/signature.rb5
-rw-r--r--lib/gitlab/zoom_link_extractor.rb2
-rw-r--r--lib/grafana/validator.rb4
-rw-r--r--lib/omni_auth/strategies/jwt.rb4
-rw-r--r--lib/peek/views/click_house.rb2
-rw-r--r--lib/quality/seeders/issues.rb59
-rw-r--r--lib/release_highlights/validator/entry.rb2
-rw-r--r--lib/sbom/package_url/argument_validator.rb4
-rw-r--r--lib/security/ci_configuration/sast_build_action.rb8
-rw-r--r--lib/sidebars/admin/panel.rb5
-rw-r--r--lib/sidebars/concerns/has_avatar.rb21
-rw-r--r--lib/sidebars/explore/panel.rb5
-rw-r--r--lib/sidebars/groups/menus/packages_registries_menu.rb3
-rw-r--r--lib/sidebars/groups/menus/scope_menu.rb4
-rw-r--r--lib/sidebars/groups/super_sidebar_panel.rb6
-rw-r--r--lib/sidebars/menu.rb4
-rw-r--r--lib/sidebars/menu_item.rb8
-rw-r--r--lib/sidebars/organizations/menus/scope_menu.rb4
-rw-r--r--lib/sidebars/organizations/super_sidebar_panel.rb5
-rw-r--r--lib/sidebars/panel.rb2
-rw-r--r--lib/sidebars/projects/menus/issues_menu.rb2
-rw-r--r--lib/sidebars/projects/menus/monitor_menu.rb15
-rw-r--r--lib/sidebars/projects/menus/packages_registries_menu.rb3
-rw-r--r--lib/sidebars/projects/menus/repository_menu.rb2
-rw-r--r--lib/sidebars/projects/menus/scope_menu.rb4
-rw-r--r--lib/sidebars/projects/super_sidebar_panel.rb6
-rw-r--r--lib/sidebars/search/panel.rb13
-rw-r--r--lib/sidebars/user_profile/menus/overview_menu.rb34
-rw-r--r--lib/sidebars/user_profile/panel.rb16
-rw-r--r--lib/sidebars/user_settings/panel.rb7
-rw-r--r--lib/sidebars/your_work/menus/organizations_menu.rb34
-rw-r--r--lib/sidebars/your_work/panel.rb8
-rw-r--r--lib/system_check/app/migrations_are_up_check.rb2
-rw-r--r--lib/system_check/app/table_truncate_check.rb34
-rw-r--r--lib/system_check/incoming_email/mail_room_running_check.rb2
-rw-r--r--lib/system_check/rake_task/app_task.rb1
-rw-r--r--lib/system_check/sidekiq_check.rb4
-rw-r--r--lib/tasks/cleanup.rake2
-rw-r--r--lib/tasks/gitlab/db.rake20
-rw-r--r--lib/tasks/gitlab/generate_sample_prometheus_data.rake27
-rw-r--r--lib/tasks/gitlab/info.rake16
-rw-r--r--lib/tasks/gitlab/list_repos.rake3
-rw-r--r--lib/tasks/gitlab/shell.rake4
-rw-r--r--lib/tasks/gitlab/update_templates.rake6
-rw-r--r--lib/tasks/tanuki_emoji.rake2
-rw-r--r--lib/users/internal.rb151
-rw-r--r--locale/am_ET/gitlab.po1867
-rw-r--r--locale/ar_SA/gitlab.po1883
-rw-r--r--locale/as_IN/gitlab.po1867
-rw-r--r--locale/az_AZ/gitlab.po1867
-rw-r--r--locale/ba_RU/gitlab.po1863
-rw-r--r--locale/be_BY/gitlab.po1875
-rw-r--r--locale/bg/gitlab.po1867
-rw-r--r--locale/bn_BD/gitlab.po1867
-rw-r--r--locale/bn_IN/gitlab.po1867
-rw-r--r--locale/br_FR/gitlab.po1879
-rw-r--r--locale/bs_BA/gitlab.po1871
-rw-r--r--locale/ca_ES/gitlab.po1867
-rw-r--r--locale/cs_CZ/gitlab.po1875
-rw-r--r--locale/cy_GB/gitlab.po1883
-rw-r--r--locale/da_DK/gitlab.po1899
-rw-r--r--locale/de/gitlab.po2203
-rw-r--r--locale/el_GR/gitlab.po1867
-rw-r--r--locale/en_GB/gitlab.po1871
-rw-r--r--locale/eo/gitlab.po1867
-rw-r--r--locale/es/gitlab.po1913
-rw-r--r--locale/et_EE/gitlab.po1867
-rw-r--r--locale/fa_IR/gitlab.po1867
-rw-r--r--locale/fi_FI/gitlab.po1867
-rw-r--r--locale/fil_PH/gitlab.po1867
-rw-r--r--locale/fr/gitlab.po2229
-rw-r--r--locale/gitlab.pot1925
-rw-r--r--locale/gl_ES/gitlab.po1867
-rw-r--r--locale/he_IL/gitlab.po1875
-rw-r--r--locale/hi_IN/gitlab.po1867
-rw-r--r--locale/hr_HR/gitlab.po1871
-rw-r--r--locale/hu_HU/gitlab.po1867
-rw-r--r--locale/hy_AM/gitlab.po1867
-rw-r--r--locale/id_ID/gitlab.po1863
-rw-r--r--locale/ig_NG/gitlab.po1863
-rw-r--r--locale/is_IS/gitlab.po1867
-rw-r--r--locale/it/gitlab.po1867
-rw-r--r--locale/ja/gitlab.po2279
-rw-r--r--locale/ka_GE/gitlab.po1867
-rw-r--r--locale/kab/gitlab.po1867
-rw-r--r--locale/ko/gitlab.po3139
-rw-r--r--locale/ku_TR/gitlab.po1867
-rw-r--r--locale/ky_KG/gitlab.po1867
-rw-r--r--locale/lt_LT/gitlab.po1875
-rw-r--r--locale/mk_MK/gitlab.po1867
-rw-r--r--locale/ml_IN/gitlab.po1867
-rw-r--r--locale/mn_MN/gitlab.po1867
-rw-r--r--locale/ms_MY/gitlab.po1863
-rw-r--r--locale/nb_NO/gitlab.po1889
-rw-r--r--locale/ne_NP/gitlab.po57314
-rw-r--r--locale/nl_NL/gitlab.po1867
-rw-r--r--locale/or_IN/gitlab.po1867
-rw-r--r--locale/pa_IN/gitlab.po1867
-rw-r--r--locale/pa_PK/gitlab.po1867
-rw-r--r--locale/pl_PL/gitlab.po1879
-rw-r--r--locale/pt_BR/gitlab.po2253
-rw-r--r--locale/pt_PT/gitlab.po1869
-rw-r--r--locale/ro_RO/gitlab.po1937
-rw-r--r--locale/ru/gitlab.po1901
-rw-r--r--locale/si_LK/gitlab.po3305
-rw-r--r--locale/sk_SK/gitlab.po1875
-rw-r--r--locale/sl_SI/gitlab.po1875
-rw-r--r--locale/sq_AL/gitlab.po1867
-rw-r--r--locale/sr_CS/gitlab.po1871
-rw-r--r--locale/sr_SP/gitlab.po1871
-rw-r--r--locale/sv_SE/gitlab.po1867
-rw-r--r--locale/sw_KE/gitlab.po1867
-rw-r--r--locale/ta_IN/gitlab.po1867
-rw-r--r--locale/th_TH/gitlab.po1863
-rw-r--r--locale/tr_TR/gitlab.po1889
-rw-r--r--locale/uk/gitlab.po2181
-rw-r--r--locale/ur_PK/gitlab.po1867
-rw-r--r--locale/uz_UZ/gitlab.po1867
-rw-r--r--locale/vi_VN/gitlab.po1863
-rw-r--r--locale/zh_CN/gitlab.po2227
-rw-r--r--locale/zh_HK/gitlab.po1863
-rw-r--r--locale/zh_TW/gitlab.po2057
-rw-r--r--package.json53
-rw-r--r--patches/@vue+compiler-core+3.2.47.dev.patch35
-rw-r--r--postcss.config.js5
-rw-r--r--public/404.html2
-rw-r--r--public/422.html2
-rw-r--r--public/500.html2
-rw-r--r--public/502.html2
-rw-r--r--public/503.html2
-rw-r--r--public/deploy.html2
-rw-r--r--qa/Gemfile8
-rw-r--r--qa/Gemfile.lock18
-rw-r--r--qa/README.md24
-rw-r--r--qa/gdk/Dockerfile.gdk82
-rw-r--r--qa/gdk/Dockerfile.gdk.dockerignore25
-rwxr-xr-xqa/gdk/entrypoint10
-rw-r--r--qa/lib/gitlab/page/group/settings/billing.rb3
-rw-r--r--qa/lib/gitlab/page/group/settings/billing.stub.rb24
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quotas.rb25
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb144
-rw-r--r--qa/lib/gitlab/page/main/login.rb38
-rw-r--r--qa/lib/gitlab/page/main/login.stub.rb183
-rw-r--r--qa/lib/gitlab/page/main/sign_up.rb13
-rw-r--r--qa/lib/gitlab/page/subscriptions/new.rb4
-rw-r--r--qa/lib/gitlab/page/subscriptions/new.stub.rb82
-rw-r--r--qa/perf/ai/Dockerfile.ab7
-rw-r--r--qa/perf/ai/README.md43
-rw-r--r--qa/perf/ai/prompt.json10
-rw-r--r--qa/qa.rb1
-rw-r--r--qa/qa/factories/access_tokens.rb8
-rw-r--r--qa/qa/factories/files.rb7
-rw-r--r--qa/qa/factories/jobs.rb8
-rw-r--r--qa/qa/factories/labels.rb8
-rw-r--r--qa/qa/factories/milestones.rb8
-rw-r--r--qa/qa/factories/pipelines.rb8
-rw-r--r--qa/qa/factories/runners.rb8
-rw-r--r--qa/qa/factories/snippets.rb13
-rw-r--r--qa/qa/factories/users.rb20
-rw-r--r--qa/qa/flow/merge_request.rb2
-rw-r--r--qa/qa/page/admin/menu.rb70
-rw-r--r--qa/qa/page/admin/overview/groups/edit.rb4
-rw-r--r--qa/qa/page/admin/overview/groups/index.rb12
-rw-r--r--qa/qa/page/admin/overview/groups/show.rb4
-rw-r--r--qa/qa/page/admin/overview/users/index.rb8
-rw-r--r--qa/qa/page/admin/overview/users/show.rb31
-rw-r--r--qa/qa/page/blame/show.rb6
-rw-r--r--qa/qa/page/component/access_tokens.rb1
-rw-r--r--qa/qa/page/component/ci_badge_link.rb4
-rw-r--r--qa/qa/page/component/members/invite_members_modal.rb4
-rw-r--r--qa/qa/page/component/members/members_table.rb6
-rw-r--r--qa/qa/page/dashboard/todos.rb28
-rw-r--r--qa/qa/page/group/menu.rb177
-rw-r--r--qa/qa/page/group/milestone/new.rb4
-rw-r--r--qa/qa/page/group/runners/index.rb45
-rw-r--r--qa/qa/page/group/show.rb4
-rw-r--r--qa/qa/page/group/sub_menus/build.rb23
-rw-r--r--qa/qa/page/group/sub_menus/deploy.rb21
-rw-r--r--qa/qa/page/group/sub_menus/main.rb25
-rw-r--r--qa/qa/page/group/sub_menus/operate.rb21
-rw-r--r--qa/qa/page/group/sub_menus/super_sidebar/build.rb25
-rw-r--r--qa/qa/page/group/sub_menus/super_sidebar/deploy.rb23
-rw-r--r--qa/qa/page/group/sub_menus/super_sidebar/main.rb27
-rw-r--r--qa/qa/page/group/sub_menus/super_sidebar/operate.rb23
-rw-r--r--qa/qa/page/issuable/new.rb8
-rw-r--r--qa/qa/page/main/menu.rb197
-rw-r--r--qa/qa/page/merge_request/new.rb22
-rw-r--r--qa/qa/page/merge_request/show.rb56
-rw-r--r--qa/qa/page/profile/menu.rb52
-rw-r--r--qa/qa/page/profile/super_sidebar/menu.rb31
-rw-r--r--qa/qa/page/project/artifact/show.rb4
-rw-r--r--qa/qa/page/project/issue/index.rb43
-rw-r--r--qa/qa/page/project/issue/jira_import.rb8
-rw-r--r--qa/qa/page/project/issue/new.rb4
-rw-r--r--qa/qa/page/project/job/show.rb48
-rw-r--r--qa/qa/page/project/menu.rb85
-rw-r--r--qa/qa/page/project/milestone/new.rb4
-rw-r--r--qa/qa/page/project/monitor/alerts/index.rb2
-rw-r--r--qa/qa/page/project/monitor/incidents/index.rb10
-rw-r--r--qa/qa/page/project/pipeline/index.rb16
-rw-r--r--qa/qa/page/project/pipeline/show.rb18
-rw-r--r--qa/qa/page/project/pipeline_editor/new.rb19
-rw-r--r--qa/qa/page/project/pipeline_editor/show.rb143
-rw-r--r--qa/qa/page/project/settings/alerts.rb52
-rw-r--r--qa/qa/page/project/settings/merge_request.rb4
-rw-r--r--qa/qa/page/project/settings/mirroring_repositories.rb9
-rw-r--r--qa/qa/page/project/settings/monitor.rb8
-rw-r--r--qa/qa/page/project/settings/protected_branches.rb20
-rw-r--r--qa/qa/page/project/settings/protected_tags.rb14
-rw-r--r--qa/qa/page/project/sub_menus/build.rb47
-rw-r--r--qa/qa/page/project/sub_menus/ci_cd.rb47
-rw-r--r--qa/qa/page/project/sub_menus/code.rb51
-rw-r--r--qa/qa/page/project/sub_menus/common.rb8
-rw-r--r--qa/qa/page/project/sub_menus/create_new_menu.rb11
-rw-r--r--qa/qa/page/project/sub_menus/deploy.rb29
-rw-r--r--qa/qa/page/project/sub_menus/deployments.rb40
-rw-r--r--qa/qa/page/project/sub_menus/infrastructure.rb40
-rw-r--r--qa/qa/page/project/sub_menus/issues.rb78
-rw-r--r--qa/qa/page/project/sub_menus/main.rb17
-rw-r--r--qa/qa/page/project/sub_menus/monitor.rb47
-rw-r--r--qa/qa/page/project/sub_menus/operate.rb39
-rw-r--r--qa/qa/page/project/sub_menus/packages.rb48
-rw-r--r--qa/qa/page/project/sub_menus/plan.rb35
-rw-r--r--qa/qa/page/project/sub_menus/project.rb29
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb63
-rw-r--r--qa/qa/page/project/sub_menus/secure.rb23
-rw-r--r--qa/qa/page/project/sub_menus/settings.rb79
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/build.rb49
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/code.rb53
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/deploy.rb31
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/main.rb19
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/monitor.rb41
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/operate.rb41
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/plan.rb37
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/secure.rb25
-rw-r--r--qa/qa/page/project/sub_menus/super_sidebar/settings.rb41
-rw-r--r--qa/qa/page/project/web_ide/edit.rb12
-rw-r--r--qa/qa/page/project/web_ide/vscode.rb10
-rw-r--r--qa/qa/page/registration/sign_up.rb24
-rw-r--r--qa/qa/page/sub_menus/common.rb25
-rw-r--r--qa/qa/page/sub_menus/create_new_menu.rb2
-rw-r--r--qa/qa/page/sub_menus/deploy.rb25
-rw-r--r--qa/qa/page/sub_menus/main.rb19
-rw-r--r--qa/qa/page/sub_menus/manage.rb29
-rw-r--r--qa/qa/page/sub_menus/operate.rb21
-rw-r--r--qa/qa/page/sub_menus/plan.rb33
-rw-r--r--qa/qa/page/sub_menus/settings.rb45
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/context_switcher.rb56
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/deploy.rb27
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/global_search_modal.rb80
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/main.rb21
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/manage.rb31
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/operate.rb23
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/plan.rb35
-rw-r--r--qa/qa/page/sub_menus/super_sidebar/settings.rb47
-rw-r--r--qa/qa/page/user/show.rb8
-rw-r--r--qa/qa/resource/api_fabricator.rb4
-rw-r--r--qa/qa/resource/base.rb19
-rw-r--r--qa/qa/resource/graphql.rb20
-rw-r--r--qa/qa/resource/job.rb2
-rw-r--r--qa/qa/resource/merge_request_from_fork.rb4
-rw-r--r--qa/qa/resource/project_snippet.rb2
-rw-r--r--qa/qa/resource/snippet.rb6
-rw-r--r--qa/qa/runtime/application_settings.rb14
-rw-r--r--qa/qa/runtime/browser.rb5
-rw-r--r--qa/qa/runtime/env.rb4
-rw-r--r--qa/qa/service/cluster_provider/gcloud.rb15
-rw-r--r--qa/qa/service/docker_run/smocker.rb10
-rw-r--r--qa/qa/specs/features/api/1_manage/group_access_token_spec.rb20
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb10
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb22
-rw-r--r--qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb8
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb34
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb12
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb6
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb11
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb17
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb6
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb8
-rw-r--r--qa/qa/specs/features/api/1_manage/project_access_token_spec.rb29
-rw-r--r--qa/qa/specs/features/api/1_manage/rate_limits_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb81
-rw-r--r--qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb6
-rw-r--r--qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb11
-rw-r--r--qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb5
-rw-r--r--qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb6
-rw-r--r--qa/qa/specs/features/api/4_verify/file_variable_downstream_pipeline_spec.rb194
-rw-r--r--qa/qa/specs/features/api/4_verify/file_variable_spec.rb14
-rw-r--r--qa/qa/specs/features/api/4_verify/job_downloads_artifacts_spec.rb91
-rw-r--r--qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb14
-rw-r--r--qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb36
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb9
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb12
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb46
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb31
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/user/user_access_termination_spec.rb85
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb13
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb22
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb20
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb9
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/file/delete_file_via_web_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/file/edit_file_via_web_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb10
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb19
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb18
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb36
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb32
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb49
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb41
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb9
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb62
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_counts_spec.rb41
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_status_counts_spec.rb35
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb46
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb12
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb29
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb26
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb16
-rw-r--r--qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb24
-rw-r--r--qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb7
-rw-r--r--qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb23
-rw-r--r--qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb9
-rw-r--r--qa/qa/specs/features/shared_contexts/merge_train_spec_with_user_prep.rb88
-rw-r--r--qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb14
-rw-r--r--qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb8
-rw-r--r--qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb37
-rw-r--r--qa/qa/specs/features/shared_examples/audit_event_streaming_shared_examples.rb26
-rw-r--r--qa/qa/specs/helpers/context_selector.rb4
-rw-r--r--qa/qa/support/audit_event_streaming_service.rb98
-rw-r--r--qa/qa/support/matchers/have_matcher.rb1
-rw-r--r--qa/qa/support/page/logging.rb2
-rw-r--r--qa/qa/support/system_logs/sentry.rb8
-rw-r--r--qa/qa/tools/delete_projects.rb33
-rw-r--r--qa/qa/tools/delete_subgroups.rb34
-rw-r--r--qa/qa/tools/lib/group.rb20
-rw-r--r--qa/qa/tools/reliable_report.rb58
-rw-r--r--qa/qa/tools/test_resources_handler.rb2
-rw-r--r--qa/spec/resource/api_fabricator_spec.rb2
-rw-r--r--qa/spec/specs/helpers/context_selector_spec.rb11
-rw-r--r--qa/spec/support/system_logs/sentry_spec.rb8
-rw-r--r--qa/spec/tools/reliable_report_spec.rb25
-rw-r--r--rubocop/cop/capybara/testid_finders.rb54
-rw-r--r--rubocop/cop/lint/last_keyword_argument.rb89
-rw-r--r--rubocop/cop/migration/versioned_migration_class.rb1
-rw-r--r--rubocop/rubocop-ruby27.yml9
-rw-r--r--rubocop/rubocop-ruby30.yml16
-rwxr-xr-xscripts/build_gdk_image13
-rwxr-xr-xscripts/decomposition/generate-loose-foreign-key2
-rwxr-xr-xscripts/frontend/create_jsconfig.js29
-rw-r--r--scripts/frontend/preinstall.mjs59
-rwxr-xr-xscripts/frontend/webpack_dev_server.js14
-rwxr-xr-xscripts/generate-message-to-run-e2e-pipeline.rb2
-rwxr-xr-xscripts/gitaly-test-spawn2
-rwxr-xr-xscripts/lint-doc.sh2
-rwxr-xr-xscripts/lint-docs-redirects.rb203
-rwxr-xr-xscripts/process_custom_semgrep_results.sh2
-rwxr-xr-xscripts/remote_development/run-e2e-tests.sh7
-rwxr-xr-xscripts/remote_development/run-smoke-test-suite.sh2
-rw-r--r--scripts/rspec_helpers.sh1
-rwxr-xr-xscripts/setup-test-env1
-rwxr-xr-xscripts/setup/as-if-jh.sh53
-rwxr-xr-xscripts/trigger-build.rb2
-rw-r--r--spec/components/pajamas/banner_component_spec.rb2
-rw-r--r--spec/contracts/consumer/resources/graphql/pipelines.js4
-rw-r--r--spec/contracts/consumer/specs/project/pipelines/show.spec.js4
-rw-r--r--spec/controllers/activity_pub/projects/releases_controller_spec.rb134
-rw-r--r--spec/controllers/admin/jobs_controller_spec.rb2
-rw-r--r--spec/controllers/admin/users_controller_spec.rb2
-rw-r--r--spec/controllers/application_controller_spec.rb27
-rw-r--r--spec/controllers/concerns/onboarding/status_spec.rb28
-rw-r--r--spec/controllers/concerns/preferred_language_switcher_spec.rb74
-rw-r--r--spec/controllers/confirmations_controller_spec.rb22
-rw-r--r--spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb4
-rw-r--r--spec/controllers/groups/labels_controller_spec.rb48
-rw-r--r--spec/controllers/groups/runners_controller_spec.rb230
-rw-r--r--spec/controllers/groups/uploads_controller_spec.rb2
-rw-r--r--spec/controllers/invites_controller_spec.rb20
-rw-r--r--spec/controllers/oauth/applications_controller_spec.rb15
-rw-r--r--spec/controllers/oauth/authorizations_controller_spec.rb33
-rw-r--r--spec/controllers/profiles/notifications_controller_spec.rb3
-rw-r--r--spec/controllers/profiles/personal_access_tokens_controller_spec.rb56
-rw-r--r--spec/controllers/profiles/preferences_controller_spec.rb1
-rw-r--r--spec/controllers/profiles_controller_spec.rb14
-rw-r--r--spec/controllers/projects/alerting/notifications_controller_spec.rb27
-rw-r--r--spec/controllers/projects/environments/sample_metrics_controller_spec.rb55
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb10
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb16
-rw-r--r--spec/controllers/projects/labels_controller_spec.rb47
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb66
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb2
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb42
-rw-r--r--spec/controllers/projects/prometheus/alerts_controller_spec.rb110
-rw-r--r--spec/controllers/projects/uploads_controller_spec.rb2
-rw-r--r--spec/controllers/registrations/welcome_controller_spec.rb28
-rw-r--r--spec/controllers/repositories/git_http_controller_spec.rb25
-rw-r--r--spec/controllers/search_controller_spec.rb54
-rw-r--r--spec/controllers/sent_notifications_controller_spec.rb2
-rw-r--r--spec/controllers/uploads_controller_spec.rb2
-rw-r--r--spec/db/avoid_migration_name_collisions_spec.rb17
-rw-r--r--spec/db/schema_spec.rb51
-rw-r--r--spec/experiments/application_experiment_spec.rb31
-rw-r--r--spec/factories/ci/catalog/resources.rb2
-rw-r--r--spec/factories/ci/catalog/resources/components.rb4
-rw-r--r--spec/factories/ci/catalog/resources/versions.rb4
-rw-r--r--spec/factories/ci/reports/sbom/metadatum.rb44
-rw-r--r--spec/factories/ci/reports/sbom/reports.rb20
-rw-r--r--spec/factories/issues.rb12
-rw-r--r--spec/factories/merge_requests.rb8
-rw-r--r--spec/factories/metrics/dashboard/annotations.rb9
-rw-r--r--spec/factories/metrics/users_starred_dashboards.rb9
-rw-r--r--spec/factories/ml/candidate_params.rb2
-rw-r--r--spec/factories/ml/candidates.rb10
-rw-r--r--spec/factories/packages/dependency_links.rb20
-rw-r--r--spec/factories/packages/nuget/symbol.rb11
-rw-r--r--spec/factories/packages/package_protection_rules.rb10
-rw-r--r--spec/factories/packages/packages.rb4
-rw-r--r--spec/factories/pages_domains.rb466
-rw-r--r--spec/factories/project_alerting_settings.rb20
-rw-r--r--spec/factories/project_authorizations.rb8
-rw-r--r--spec/factories/project_metrics_settings.rb8
-rw-r--r--spec/factories/projects.rb2
-rw-r--r--spec/factories/self_managed_prometheus_alert_event.rb12
-rw-r--r--spec/factories/service_desk/custom_email_verification.rb5
-rw-r--r--spec/factories/usage_data.rb5
-rw-r--r--spec/factories/users.rb4
-rw-r--r--spec/factories/users/group_visit.rb12
-rw-r--r--spec/factories/users/project_visit.rb12
-rw-r--r--spec/factories/work_items.rb12
-rw-r--r--spec/features/abuse_report_spec.rb8
-rw-r--r--spec/features/admin/admin_abuse_reports_spec.rb354
-rw-r--r--spec/features/admin/admin_hooks_spec.rb2
-rw-r--r--spec/features/admin/admin_jobs_spec.rb114
-rw-r--r--spec/features/admin/admin_mode/logout_spec.rb2
-rw-r--r--spec/features/admin/admin_mode/workers_spec.rb6
-rw-r--r--spec/features/admin/admin_mode_spec.rb2
-rw-r--r--spec/features/admin/admin_runners_spec.rb7
-rw-r--r--spec/features/admin/admin_sees_background_migrations_spec.rb2
-rw-r--r--spec/features/admin/admin_settings_spec.rb10
-rw-r--r--spec/features/admin/users/user_spec.rb10
-rw-r--r--spec/features/admin/users/users_spec.rb6
-rw-r--r--spec/features/alert_management/alert_details_spec.rb2
-rw-r--r--spec/features/alert_management/alert_management_list_spec.rb2
-rw-r--r--spec/features/boards/board_filters_spec.rb250
-rw-r--r--spec/features/boards/multiple_boards_spec.rb2
-rw-r--r--spec/features/boards/sidebar_spec.rb2
-rw-r--r--spec/features/calendar_spec.rb2
-rw-r--r--spec/features/contextual_sidebar_spec.rb5
-rw-r--r--spec/features/cycle_analytics_spec.rb4
-rw-r--r--spec/features/dashboard/activity_spec.rb2
-rw-r--r--spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb2
-rw-r--r--spec/features/dashboard/groups_list_spec.rb13
-rw-r--r--spec/features/dashboard/issuables_counter_spec.rb2
-rw-r--r--spec/features/dashboard/issues_spec.rb2
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb2
-rw-r--r--spec/features/dashboard/milestones_spec.rb4
-rw-r--r--spec/features/dashboard/navbar_spec.rb2
-rw-r--r--spec/features/dashboard/projects_spec.rb2
-rw-r--r--spec/features/dashboard/shortcuts_spec.rb2
-rw-r--r--spec/features/dashboard/snippets_spec.rb2
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb6
-rw-r--r--spec/features/explore/groups_list_spec.rb132
-rw-r--r--spec/features/explore/navbar_spec.rb1
-rw-r--r--spec/features/explore/user_explores_projects_spec.rb4
-rw-r--r--spec/features/global_search_spec.rb2
-rw-r--r--spec/features/groups/container_registry_spec.rb2
-rw-r--r--spec/features/groups/dependency_proxy_for_containers_spec.rb12
-rw-r--r--spec/features/groups/dependency_proxy_spec.rb4
-rw-r--r--spec/features/groups/group_page_with_external_authorization_service_spec.rb2
-rw-r--r--spec/features/groups/group_runners_spec.rb301
-rw-r--r--spec/features/groups/labels/create_spec.rb6
-rw-r--r--spec/features/groups/labels/edit_spec.rb14
-rw-r--r--spec/features/groups/members/manage_members_spec.rb2
-rw-r--r--spec/features/groups/members/request_access_spec.rb4
-rw-r--r--spec/features/groups/navbar_spec.rb5
-rw-r--r--spec/features/groups/new_group_page_spec.rb4
-rw-r--r--spec/features/groups/packages_spec.rb2
-rw-r--r--spec/features/groups/settings/packages_and_registries_spec.rb2
-rw-r--r--spec/features/groups/user_sees_package_sidebar_spec.rb2
-rw-r--r--spec/features/groups_spec.rb2
-rw-r--r--spec/features/help_dropdown_spec.rb4
-rw-r--r--spec/features/ide/user_opens_merge_request_spec.rb6
-rw-r--r--spec/features/incidents/incident_details_spec.rb5
-rw-r--r--spec/features/invites_spec.rb52
-rw-r--r--spec/features/issues/filtered_search/dropdown_assignee_spec.rb28
-rw-r--r--spec/features/issues/filtered_search/visual_tokens_spec.rb4
-rw-r--r--spec/features/issues/form_spec.rb85
-rw-r--r--spec/features/issues/issue_state_spec.rb66
-rw-r--r--spec/features/issues/move_spec.rb2
-rw-r--r--spec/features/issues/note_polling_spec.rb16
-rw-r--r--spec/features/issues/service_desk_spec.rb6
-rw-r--r--spec/features/issues/todo_spec.rb2
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb2
-rw-r--r--spec/features/issues/user_sees_live_update_spec.rb22
-rw-r--r--spec/features/issues/user_uses_quick_actions_spec.rb4
-rw-r--r--spec/features/jira_connect/branches_spec.rb4
-rw-r--r--spec/features/labels_hierarchy_spec.rb2
-rw-r--r--spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb81
-rw-r--r--spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb3
-rw-r--r--spec/features/merge_request/user_merges_merge_request_spec.rb4
-rw-r--r--spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb150
-rw-r--r--spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb7
-rw-r--r--spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb6
-rw-r--r--spec/features/merge_request/user_sees_deployment_widget_spec.rb34
-rw-r--r--spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb506
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb29
-rw-r--r--spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb28
-rw-r--r--spec/features/merge_request/user_sees_pipelines_spec.rb396
-rw-r--r--spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb5
-rw-r--r--spec/features/merge_request/user_sets_to_auto_merge_spec.rb144
-rw-r--r--spec/features/merge_request/user_uses_quick_actions_spec.rb11
-rw-r--r--spec/features/monitor_sidebar_link_spec.rb2
-rw-r--r--spec/features/nav/pinned_nav_items_spec.rb18
-rw-r--r--spec/features/nav/top_nav_responsive_spec.rb2
-rw-r--r--spec/features/nav/top_nav_spec.rb2
-rw-r--r--spec/features/oauth_login_spec.rb2
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb4
-rw-r--r--spec/features/profiles/user_visits_notifications_tab_spec.rb8
-rw-r--r--spec/features/profiles/user_visits_profile_account_page_spec.rb2
-rw-r--r--spec/features/profiles/user_visits_profile_authentication_log_spec.rb2
-rw-r--r--spec/features/profiles/user_visits_profile_preferences_page_spec.rb2
-rw-r--r--spec/features/profiles/user_visits_profile_spec.rb2
-rw-r--r--spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb2
-rw-r--r--spec/features/projects/active_tabs_spec.rb5
-rw-r--r--spec/features/projects/branches/user_creates_branch_spec.rb2
-rw-r--r--spec/features/projects/ci/editor_spec.rb2
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb2
-rw-r--r--spec/features/projects/clusters/user_spec.rb2
-rw-r--r--spec/features/projects/clusters_spec.rb2
-rw-r--r--spec/features/projects/commit/user_sees_pipelines_tab_spec.rb2
-rw-r--r--spec/features/projects/confluence/user_views_confluence_page_spec.rb2
-rw-r--r--spec/features/projects/environments/environment_spec.rb188
-rw-r--r--spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb29
-rw-r--r--spec/features/projects/features_visibility_spec.rb4
-rw-r--r--spec/features/projects/files/project_owner_creates_license_file_spec.rb4
-rw-r--r--spec/features/projects/files/user_find_file_spec.rb2
-rw-r--r--spec/features/projects/files/user_searches_for_files_spec.rb11
-rw-r--r--spec/features/projects/forks/fork_list_spec.rb2
-rw-r--r--spec/features/projects/graph_spec.rb2
-rw-r--r--spec/features/projects/import_export/export_file_spec.rb4
-rw-r--r--spec/features/projects/jobs/user_browses_jobs_spec.rb8
-rw-r--r--spec/features/projects/jobs_spec.rb8
-rw-r--r--spec/features/projects/labels/user_creates_labels_spec.rb2
-rw-r--r--spec/features/projects/labels/user_edits_labels_spec.rb25
-rw-r--r--spec/features/projects/members/manage_members_spec.rb2
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb4
-rw-r--r--spec/features/projects/milestones/user_interacts_with_labels_spec.rb2
-rw-r--r--spec/features/projects/navbar_spec.rb8
-rw-r--r--spec/features/projects/new_project_spec.rb14
-rw-r--r--spec/features/projects/pages/user_edits_settings_spec.rb2
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb484
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb12
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb18
-rw-r--r--spec/features/projects/settings/monitor_settings_spec.rb5
-rw-r--r--spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb2
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/service_desk_setting_spec.rb2
-rw-r--r--spec/features/projects/show/user_sees_collaboration_links_spec.rb2
-rw-r--r--spec/features/projects/user_sees_sidebar_spec.rb4
-rw-r--r--spec/features/projects/user_uses_shortcuts_spec.rb57
-rw-r--r--spec/features/projects/wikis_spec.rb2
-rw-r--r--spec/features/projects/work_items/work_item_spec.rb48
-rw-r--r--spec/features/projects_spec.rb18
-rw-r--r--spec/features/runners_spec.rb489
-rw-r--r--spec/features/search/user_searches_for_code_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_comments_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_commits_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_issues_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_merge_requests_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_milestones_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_projects_spec.rb2
-rw-r--r--spec/features/search/user_searches_for_users_spec.rb6
-rw-r--r--spec/features/search/user_searches_for_wiki_pages_spec.rb2
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb4
-rw-r--r--spec/features/sentry_js_spec.rb1
-rw-r--r--spec/features/signed_commits_spec.rb8
-rw-r--r--spec/features/snippets/search_snippets_spec.rb5
-rw-r--r--spec/features/snippets/show_spec.rb8
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb10
-rw-r--r--spec/features/task_lists_spec.rb4
-rw-r--r--spec/features/unsubscribe_links_spec.rb8
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_profile_spec.rb2
-rw-r--r--spec/features/usage_stats_consent_spec.rb2
-rw-r--r--spec/features/users/active_sessions_spec.rb8
-rw-r--r--spec/features/users/anonymous_sessions_spec.rb2
-rw-r--r--spec/features/users/email_verification_on_login_spec.rb11
-rw-r--r--spec/features/users/login_spec.rb50
-rw-r--r--spec/features/users/logout_spec.rb2
-rw-r--r--spec/features/users/overview_spec.rb2
-rw-r--r--spec/features/users/rss_spec.rb6
-rw-r--r--spec/features/users/show_spec.rb4
-rw-r--r--spec/features/users/signup_spec.rb16
-rw-r--r--spec/features/users/snippets_spec.rb6
-rw-r--r--spec/features/users/terms_spec.rb6
-rw-r--r--spec/features/users/user_browses_projects_on_user_page_spec.rb6
-rw-r--r--spec/features/webauthn_spec.rb17
-rw-r--r--spec/features/whats_new_spec.rb6
-rw-r--r--spec/finders/abuse_reports_finder_spec.rb48
-rw-r--r--spec/finders/ci/jobs_finder_spec.rb281
-rw-r--r--spec/finders/ci/runners_finder_spec.rb226
-rw-r--r--spec/finders/ci/triggers_finder_spec.rb29
-rw-r--r--spec/finders/deployments_finder_spec.rb16
-rw-r--r--spec/finders/group_members_finder_spec.rb35
-rw-r--r--spec/finders/groups/accepting_group_transfers_finder_spec.rb21
-rw-r--r--spec/finders/organizations/groups_finder_spec.rb84
-rw-r--r--spec/finders/organizations/organization_users_finder_spec.rb35
-rw-r--r--spec/finders/packages/npm/packages_for_user_finder_spec.rb41
-rw-r--r--spec/finders/packages/nuget/package_finder_spec.rb10
-rw-r--r--spec/fixtures/api/schemas/entities/codequality_degradation.json3
-rw-r--r--spec/fixtures/api/schemas/job/job.json1
-rw-r--r--spec/fixtures/api/schemas/ml/search_runs.json82
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/integration.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/operations/strategy.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/operations/user_list.json16
-rw-r--r--spec/fixtures/api/schemas/status/ci_detailed_status.json2
-rw-r--r--spec/fixtures/ci_secure_files/sample.p12bin3352 -> 3219 bytes
-rw-r--r--spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event.yml14
-rw-r--r--spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event_ee.yml10
-rw-r--r--spec/fixtures/packages/nuget/symbol/package.pdbbin0 -> 10588 bytes
-rw-r--r--spec/fixtures/security_reports/master/gl-common-scanning-report.json48
-rw-r--r--spec/frontend/__helpers__/clean_html_element_serializer.js142
-rw-r--r--spec/frontend/__helpers__/dom_shims/get_client_rects.js3
-rw-r--r--spec/frontend/__helpers__/html_string_serializer.js11
-rw-r--r--spec/frontend/__helpers__/vue_test_utils_helper.js121
-rw-r--r--spec/frontend/__helpers__/vue_test_utils_helper_spec.js46
-rw-r--r--spec/frontend/access_tokens/components/access_token_table_app_spec.js4
-rw-r--r--spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap4
-rw-r--r--spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js80
-rw-r--r--spec/frontend/admin/abuse_report/components/activity_events_list_spec.js30
-rw-r--r--spec/frontend/admin/abuse_report/components/activity_history_item_spec.js64
-rw-r--r--spec/frontend/admin/abuse_report/components/history_items_spec.js66
-rw-r--r--spec/frontend/admin/abuse_report/components/labels_select_spec.js297
-rw-r--r--spec/frontend/admin/abuse_report/components/report_actions_spec.js27
-rw-r--r--spec/frontend/admin/abuse_report/components/report_details_spec.js74
-rw-r--r--spec/frontend/admin/abuse_report/components/report_header_spec.js55
-rw-r--r--spec/frontend/admin/abuse_report/components/reported_content_spec.js11
-rw-r--r--spec/frontend/admin/abuse_report/components/user_details_spec.js62
-rw-r--r--spec/frontend/admin/abuse_report/mock_data.js88
-rw-r--r--spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js14
-rw-r--r--spec/frontend/admin/abuse_reports/mock_data.js3
-rw-r--r--spec/frontend/admin/applications/components/__snapshots__/delete_application_spec.js.snap1
-rw-r--r--spec/frontend/admin/topics/components/__snapshots__/remove_avatar_spec.js.snap1
-rw-r--r--spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap9
-rw-r--r--spec/frontend/admin/users/components/modals/__snapshots__/delete_user_modal_spec.js.snap2
-rw-r--r--spec/frontend/admin/users/components/user_actions_spec.js2
-rw-r--r--spec/frontend/alerts_settings/components/__snapshots__/alerts_form_spec.js.snap32
-rw-r--r--spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js2
-rw-r--r--spec/frontend/analytics/cycle_analytics/components/__snapshots__/total_time_spec.js.snap46
-rw-r--r--spec/frontend/api/application_settings_api_spec.js45
-rw-r--r--spec/frontend/artifacts_settings/components/__snapshots__/keep_latest_artifact_checkbox_spec.js.snap74
-rw-r--r--spec/frontend/avatar_helper_spec.js110
-rw-r--r--spec/frontend/behaviors/markdown/paste_markdown_table_spec.js6
-rw-r--r--spec/frontend/blob/components/__snapshots__/blob_edit_header_spec.js.snap6
-rw-r--r--spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap10
-rw-r--r--spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap34
-rw-r--r--spec/frontend/blob/components/blob_header_spec.js61
-rw-r--r--spec/frontend/blob/components/mock_data.js15
-rw-r--r--spec/frontend/blob/line_highlighter_spec.js9
-rw-r--r--spec/frontend/blob/openapi/index_spec.js31
-rw-r--r--spec/frontend/boards/board_card_inner_spec.js1
-rw-r--r--spec/frontend/boards/components/board_card_spec.js1
-rw-r--r--spec/frontend/boards/components/boards_selector_spec.js12
-rw-r--r--spec/frontend/boards/components/issue_board_filtered_search_spec.js7
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js8
-rw-r--r--spec/frontend/boards/mock_data.js5
-rw-r--r--spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap51
-rw-r--r--spec/frontend/branches/components/__snapshots__/divergence_graph_spec.js.snap8
-rw-r--r--spec/frontend/ci/admin/jobs_table/admin_job_table_app_spec.js445
-rw-r--r--spec/frontend/ci/admin/jobs_table/components/cancel_jobs_modal_spec.js66
-rw-r--r--spec/frontend/ci/admin/jobs_table/components/cancel_jobs_spec.js54
-rw-r--r--spec/frontend/ci/admin/jobs_table/components/cells/project_cell_spec.js32
-rw-r--r--spec/frontend/ci/admin/jobs_table/components/cells/runner_cell_spec.js64
-rw-r--r--spec/frontend/ci/admin/jobs_table/components/jobs_skeleton_loader_spec.js28
-rw-r--r--spec/frontend/ci/admin/jobs_table/graphql/cache_config_spec.js106
-rw-r--r--spec/frontend/ci/artifacts/components/feedback_banner_spec.js59
-rw-r--r--spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js12
-rw-r--r--spec/frontend/ci/ci_variable_list/ci_variable_list/ci_variable_list_spec.js161
-rw-r--r--spec/frontend/ci/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js41
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js338
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js15
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js5
-rw-r--r--spec/frontend/ci/common/pipelines_table_spec.js280
-rw-r--r--spec/frontend/ci/common/private/job_links_layer_spec.js85
-rw-r--r--spec/frontend/ci/common/private/jobs_filtered_search/jobs_filtered_search_spec.js123
-rw-r--r--spec/frontend/ci/common/private/jobs_filtered_search/tokens/job_status_token_spec.js58
-rw-r--r--spec/frontend/ci/common/private/jobs_filtered_search/utils_spec.js22
-rw-r--r--spec/frontend/ci/job_details/components/empty_state_spec.js140
-rw-r--r--spec/frontend/ci/job_details/components/environments_block_spec.js260
-rw-r--r--spec/frontend/ci/job_details/components/erased_block_spec.js59
-rw-r--r--spec/frontend/ci/job_details/components/job_header_spec.js154
-rw-r--r--spec/frontend/ci/job_details/components/job_log_controllers_spec.js321
-rw-r--r--spec/frontend/ci/job_details/components/log/collapsible_section_spec.js95
-rw-r--r--spec/frontend/ci/job_details/components/log/duration_badge_spec.js26
-rw-r--r--spec/frontend/ci/job_details/components/log/line_header_spec.js133
-rw-r--r--spec/frontend/ci/job_details/components/log/line_number_spec.js35
-rw-r--r--spec/frontend/ci/job_details/components/log/line_spec.js256
-rw-r--r--spec/frontend/ci/job_details/components/log/log_spec.js162
-rw-r--r--spec/frontend/ci/job_details/components/log/mock_data.js (renamed from spec/frontend/jobs/components/log/mock_data.js)0
-rw-r--r--spec/frontend/ci/job_details/components/manual_variables_form_spec.js364
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/artifacts_block_spec.js193
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/commit_block_spec.js66
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/external_links_block_spec.js49
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/job_container_item_spec.js87
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/job_retry_forward_deployment_modal_spec.js68
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/job_sidebar_retry_button_spec.js64
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/jobs_container_spec.js143
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/sidebar_detail_row_spec.js68
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js101
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js134
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/sidebar_spec.js222
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/stages_dropdown_spec.js192
-rw-r--r--spec/frontend/ci/job_details/components/sidebar/trigger_block_spec.js81
-rw-r--r--spec/frontend/ci/job_details/components/stuck_block_spec.js94
-rw-r--r--spec/frontend/ci/job_details/components/unmet_prerequisites_block_spec.js37
-rw-r--r--spec/frontend/ci/job_details/job_app_spec.js343
-rw-r--r--spec/frontend/ci/job_details/mock_data.js (renamed from spec/frontend/jobs/components/job/mock_data.js)0
-rw-r--r--spec/frontend/ci/job_details/store/actions_spec.js502
-rw-r--r--spec/frontend/ci/job_details/store/getters_spec.js245
-rw-r--r--spec/frontend/ci/job_details/store/helpers.js5
-rw-r--r--spec/frontend/ci/job_details/store/mutations_spec.js269
-rw-r--r--spec/frontend/ci/job_details/store/utils_spec.js510
-rw-r--r--spec/frontend/ci/job_details/utils_spec.js265
-rw-r--r--spec/frontend/ci/jobs_mock_data.js1629
-rw-r--r--spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js240
-rw-r--r--spec/frontend/ci/jobs_page/components/job_cells/duration_cell_spec.js77
-rw-r--r--spec/frontend/ci/jobs_page/components/job_cells/job_cell_spec.js142
-rw-r--r--spec/frontend/ci/jobs_page/components/job_cells/pipeline_cell_spec.js78
-rw-r--r--spec/frontend/ci/jobs_page/components/jobs_table_empty_state_spec.js37
-rw-r--r--spec/frontend/ci/jobs_page/components/jobs_table_spec.js107
-rw-r--r--spec/frontend/ci/jobs_page/components/jobs_table_tabs_spec.js81
-rw-r--r--spec/frontend/ci/jobs_page/graphql/cache_config_spec.js106
-rw-r--r--spec/frontend/ci/jobs_page/job_page_app_spec.js338
-rw-r--r--spec/frontend/ci/merge_requests/components/pipelines_table_wrapper_spec.js117
-rw-r--r--spec/frontend/ci/merge_requests/mock_data.js30
-rw-r--r--spec/frontend/ci/mixins/delayed_job_mixin_spec.js119
-rw-r--r--spec/frontend/ci/pipeline_details/dag/components/__snapshots__/dag_graph_spec.js.snap743
-rw-r--r--spec/frontend/ci/pipeline_details/dag/components/dag_annotations_spec.js98
-rw-r--r--spec/frontend/ci/pipeline_details/dag/components/dag_graph_spec.js209
-rw-r--r--spec/frontend/ci/pipeline_details/dag/dag_spec.js168
-rw-r--r--spec/frontend/ci/pipeline_details/dag/mock_data.js (renamed from spec/frontend/pipelines/components/dag/mock_data.js)0
-rw-r--r--spec/frontend/ci/pipeline_details/dag/utils/drawing_utils_spec.js57
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/__snapshots__/links_inner_spec.js.snap110
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/action_component_spec.js116
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/graph_component_spec.js182
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/graph_view_selector_spec.js217
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/job_group_dropdown_spec.js84
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/job_item_spec.js492
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/job_name_component_spec.js30
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/linked_pipeline_spec.js464
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/linked_pipelines_column_spec.js214
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/linked_pipelines_mock_data.js (renamed from spec/frontend/pipelines/graph/linked_pipelines_mock_data.js)0
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/links_inner_spec.js223
-rw-r--r--spec/frontend/ci/pipeline_details/graph/components/stage_column_component_spec.js228
-rw-r--r--spec/frontend/ci/pipeline_details/graph/graph_component_wrapper_spec.js603
-rw-r--r--spec/frontend/ci/pipeline_details/graph/mock_data.js383
-rw-r--r--spec/frontend/ci/pipeline_details/header/pipeline_details_header_spec.js452
-rw-r--r--spec/frontend/ci/pipeline_details/jobs/components/failed_jobs_table_spec.js141
-rw-r--r--spec/frontend/ci/pipeline_details/jobs/failed_jobs_app_spec.js80
-rw-r--r--spec/frontend/ci/pipeline_details/jobs/jobs_app_spec.js127
-rw-r--r--spec/frontend/ci/pipeline_details/linked_pipelines_mock.json (renamed from spec/frontend/pipelines/linked_pipelines_mock.json)0
-rw-r--r--spec/frontend/ci/pipeline_details/mock_data.js1277
-rw-r--r--spec/frontend/ci/pipeline_details/pipeline_tabs_spec.js63
-rw-r--r--spec/frontend/ci/pipeline_details/pipelines_store_spec.js80
-rw-r--r--spec/frontend/ci/pipeline_details/tabs/pipeline_tabs_spec.js114
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/empty_state_spec.js45
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/mock_data.js31
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/stores/actions_spec.js149
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/stores/getters_spec.js171
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/stores/mutations_spec.js114
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/stores/utils_spec.js40
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/test_case_details_spec.js149
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/test_reports_spec.js125
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/test_suite_table_spec.js169
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/test_summary_spec.js106
-rw-r--r--spec/frontend/ci/pipeline_details/test_reports/test_summary_table_spec.js100
-rw-r--r--spec/frontend/ci/pipeline_details/utils/index_spec.js201
-rw-r--r--spec/frontend/ci/pipeline_details/utils/parsing_utils_spec.js191
-rw-r--r--spec/frontend/ci/pipeline_details/utils/unwrapping_utils_spec.js127
-rw-r--r--spec/frontend/ci/pipeline_editor/components/graph/mock_data.js (renamed from spec/frontend/pipelines/pipeline_graph/mock_data.js)0
-rw-r--r--spec/frontend/ci/pipeline_editor/components/graph/pipeline_graph_spec.js100
-rw-r--r--spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_header_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js4
-rw-r--r--spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js13
-rw-r--r--spec/frontend/ci/pipeline_editor/components/pipeline_editor_tabs_spec.js2
-rw-r--r--spec/frontend/ci/pipeline_editor/mock_data.js2
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/job_item_spec.js29
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/legacy_pipeline_mini_graph_spec.js122
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/legacy_pipeline_stage_spec.js247
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/linked_pipelines_mini_list_spec.js166
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/linked_pipelines_mock_data.js (renamed from spec/frontend/pipelines/components/pipeline_mini_graph/linked_pipelines_mock_data.js)0
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/mock_data.js252
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/pipeline_mini_graph_spec.js123
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/pipeline_stage_spec.js46
-rw-r--r--spec/frontend/ci/pipeline_mini_graph/pipeline_stages_spec.js63
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js11
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js36
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js42
-rw-r--r--spec/frontend/ci/pipeline_schedules/mock_data.js2
-rw-r--r--spec/frontend/ci/pipelines_page/components/empty_state/ci_templates_spec.js107
-rw-r--r--spec/frontend/ci/pipelines_page/components/empty_state/ios_templates_spec.js133
-rw-r--r--spec/frontend/ci/pipelines_page/components/empty_state/no_ci_empty_state_spec.js87
-rw-r--r--spec/frontend/ci/pipelines_page/components/empty_state/pipelines_ci_templates_spec.js58
-rw-r--r--spec/frontend/ci/pipelines_page/components/failure_widget/failed_job_details_spec.js254
-rw-r--r--spec/frontend/ci/pipelines_page/components/failure_widget/failed_jobs_list_spec.js279
-rw-r--r--spec/frontend/ci/pipelines_page/components/failure_widget/mock.js (renamed from spec/frontend/pipelines/components/pipelines_list/failure_widget/mock.js)0
-rw-r--r--spec/frontend/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget_spec.js139
-rw-r--r--spec/frontend/ci/pipelines_page/components/failure_widget/utils_spec.js55
-rw-r--r--spec/frontend/ci/pipelines_page/components/nav_controls_spec.js80
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipeline_labels_spec.js164
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipeline_multi_actions_spec.js316
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js77
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js27
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipeline_triggerer_spec.js76
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipeline_url_spec.js188
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipelines_artifacts_spec.js64
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipelines_filtered_search_spec.js199
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipelines_manual_actions_spec.js216
-rw-r--r--spec/frontend/ci/pipelines_page/components/time_ago_spec.js85
-rw-r--r--spec/frontend/ci/pipelines_page/pipelines_spec.js851
-rw-r--r--spec/frontend/ci/pipelines_page/tokens/pipeline_branch_name_token_spec.js142
-rw-r--r--spec/frontend/ci/pipelines_page/tokens/pipeline_source_token_spec.js53
-rw-r--r--spec/frontend/ci/pipelines_page/tokens/pipeline_status_token_spec.js58
-rw-r--r--spec/frontend/ci/pipelines_page/tokens/pipeline_tag_name_token_spec.js95
-rw-r--r--spec/frontend/ci/pipelines_page/tokens/pipeline_trigger_author_token_spec.js99
-rw-r--r--spec/frontend/ci/reports/components/__snapshots__/issue_status_icon_spec.js.snap7
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js10
-rw-r--r--spec/frontend/ci/runner/components/runner_create_form_spec.js1
-rw-r--r--spec/frontend/ci/runner/components/runner_form_fields_spec.js3
-rw-r--r--spec/frontend/ci/runner/components/runner_managers_table_spec.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_update_form_spec.js2
-rw-r--r--spec/frontend/ci_secure_files/components/metadata/__snapshots__/modal_spec.js.snap101
-rw-r--r--spec/frontend/clusters/components/__snapshots__/new_cluster_spec.js.snap19
-rw-r--r--spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap103
-rw-r--r--spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap24
-rw-r--r--spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap47
-rw-r--r--spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js8
-rw-r--r--spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js362
-rw-r--r--spec/frontend/commit/pipelines/pipelines_table_spec.js362
-rw-r--r--spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap26
-rw-r--r--spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap20
-rw-r--r--spec/frontend/content_editor/components/wrappers/__snapshots__/table_of_contents_spec.js.snap54
-rw-r--r--spec/frontend/content_editor/components/wrappers/code_block_spec.js71
-rw-r--r--spec/frontend/content_editor/services/markdown_serializer_spec.js2
-rw-r--r--spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js18
-rw-r--r--spec/frontend/contribution_events/components/contribution_event/contribution_event_destroyed_spec.js32
-rw-r--r--spec/frontend/contribution_events/components/contribution_event/contribution_event_updated_spec.js31
-rw-r--r--spec/frontend/contribution_events/components/contribution_events_spec.js8
-rw-r--r--spec/frontend/contribution_events/components/target_link_spec.js2
-rw-r--r--spec/frontend/contribution_events/utils.js95
-rw-r--r--spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap20
-rw-r--r--spec/frontend/custom_emoji/components/__snapshots__/list_spec.js.snap58
-rw-r--r--spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap30
-rw-r--r--spec/frontend/design_management/components/__snapshots__/image_spec.js.snap18
-rw-r--r--spec/frontend/design_management/components/design_notes/__snapshots__/design_note_signed_out_spec.js.snap12
-rw-r--r--spec/frontend/design_management/components/design_notes/__snapshots__/design_reply_form_spec.js.snap36
-rw-r--r--spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap66
-rw-r--r--spec/frontend/design_management/components/list/item_spec.js4
-rw-r--r--spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap19
-rw-r--r--spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap10
-rw-r--r--spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap65
-rw-r--r--spec/frontend/diffs/components/app_spec.js23
-rw-r--r--spec/frontend/diffs/components/diff_inline_findings_item_spec.js51
-rw-r--r--spec/frontend/diffs/components/diff_inline_findings_spec.js6
-rw-r--r--spec/frontend/diffs/components/diff_row_spec.js3
-rw-r--r--spec/frontend/diffs/components/inline_findings_spec.js6
-rw-r--r--spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap31
-rw-r--r--spec/frontend/diffs/mock_data/inline_findings.js60
-rw-r--r--spec/frontend/drawio/drawio_editor_spec.js5
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/positive_tests/include.yml11
-rw-r--r--spec/frontend/emoji/index_spec.js17
-rw-r--r--spec/frontend/environments/edit_environment_spec.js20
-rw-r--r--spec/frontend/environments/environment_form_spec.js47
-rw-r--r--spec/frontend/environments/new_environment_item_spec.js45
-rw-r--r--spec/frontend/feature_flags/components/new_environments_dropdown_spec.js80
-rw-r--r--spec/frontend/feature_flags/components/strategy_spec.js13
-rw-r--r--spec/frontend/filtered_search/filtered_search_manager_spec.js2
-rw-r--r--spec/frontend/fixtures/abuse_reports.rb28
-rw-r--r--spec/frontend/fixtures/issues.rb2
-rw-r--r--spec/frontend/fixtures/jobs.rb10
-rw-r--r--spec/frontend/fixtures/pipeline_header.rb2
-rw-r--r--spec/frontend/fixtures/pipeline_schedules.rb29
-rw-r--r--spec/frontend/fixtures/pipelines.rb2
-rw-r--r--spec/frontend/fixtures/snippet.rb4
-rw-r--r--spec/frontend/groups/components/empty_states/groups_dashboard_empty_state_spec.js29
-rw-r--r--spec/frontend/groups/components/empty_states/groups_explore_empty_state_spec.js27
-rw-r--r--spec/frontend/ide/components/file_templates/dropdown_spec.js168
-rw-r--r--spec/frontend/ide/components/pipelines/__snapshots__/list_spec.js.snap4
-rw-r--r--spec/frontend/ide/init_gitlab_web_ide_spec.js3
-rw-r--r--spec/frontend/ide/lib/gitlab_web_ide/setup_root_element_spec.js4
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_table_spec.js2
-rw-r--r--spec/frontend/incidents/components/incidents_list_spec.js2
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap14
-rw-r--r--spec/frontend/integrations/index/mock_data.js6
-rw-r--r--spec/frontend/invite_members/components/invite_members_modal_spec.js145
-rw-r--r--spec/frontend/invite_members/mock_data/api_responses.js6
-rw-r--r--spec/frontend/invite_members/mock_data/member_modal.js14
-rw-r--r--spec/frontend/invite_members/utils/member_utils_spec.js22
-rw-r--r--spec/frontend/issuable/components/csv_export_modal_spec.js2
-rw-r--r--spec/frontend/issuable/components/issuable_header_warnings_spec.js105
-rw-r--r--spec/frontend/issuable/components/status_badge_spec.js43
-rw-r--r--spec/frontend/issuable/components/status_box_spec.js50
-rw-r--r--spec/frontend/issuable/popover/components/issue_popover_spec.js6
-rw-r--r--spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js1
-rw-r--r--spec/frontend/issues/dashboard/mock_data.js1
-rw-r--r--spec/frontend/issues/list/components/issue_card_time_info_spec.js125
-rw-r--r--spec/frontend/issues/list/components/issues_list_app_spec.js1
-rw-r--r--spec/frontend/issues/list/mock_data.js1
-rw-r--r--spec/frontend/issues/new/components/__snapshots__/type_popover_spec.js.snap10
-rw-r--r--spec/frontend/issues/service_desk/components/empty_state_with_any_issues_spec.js74
-rw-r--r--spec/frontend/issues/service_desk/components/empty_state_without_any_issues_spec.js90
-rw-r--r--spec/frontend/issues/service_desk/components/info_banner_spec.js81
-rw-r--r--spec/frontend/issues/service_desk/components/service_desk_list_app_spec.js717
-rw-r--r--spec/frontend/issues/service_desk/mock_data.js253
-rw-r--r--spec/frontend/issues/show/components/app_spec.js154
-rw-r--r--spec/frontend/issues/show/components/sticky_header_spec.js135
-rw-r--r--spec/frontend/issues/show/components/task_list_item_actions_spec.js52
-rw-r--r--spec/frontend/issues/show/issue_spec.js43
-rw-r--r--spec/frontend/issues/show/mock_data/mock_data.js3
-rw-r--r--spec/frontend/issues/show/store_spec.js39
-rw-r--r--spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js146
-rw-r--r--spec/frontend/jira_connect/branches/mock_data.js15
-rw-r--r--spec/frontend/jira_connect/subscriptions/components/__snapshots__/group_item_name_spec.js.snap13
-rw-r--r--spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap86
-rw-r--r--spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js71
-rw-r--r--spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js58
-rw-r--r--spec/frontend/jobs/components/filtered_search/utils_spec.js19
-rw-r--r--spec/frontend/jobs/components/job/artifacts_block_spec.js193
-rw-r--r--spec/frontend/jobs/components/job/commit_block_spec.js66
-rw-r--r--spec/frontend/jobs/components/job/empty_state_spec.js140
-rw-r--r--spec/frontend/jobs/components/job/environments_block_spec.js260
-rw-r--r--spec/frontend/jobs/components/job/erased_block_spec.js59
-rw-r--r--spec/frontend/jobs/components/job/job_app_spec.js343
-rw-r--r--spec/frontend/jobs/components/job/job_container_item_spec.js87
-rw-r--r--spec/frontend/jobs/components/job/job_log_controllers_spec.js323
-rw-r--r--spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js67
-rw-r--r--spec/frontend/jobs/components/job/job_sidebar_details_container_spec.js133
-rw-r--r--spec/frontend/jobs/components/job/job_sidebar_retry_button_spec.js64
-rw-r--r--spec/frontend/jobs/components/job/jobs_container_spec.js143
-rw-r--r--spec/frontend/jobs/components/job/manual_variables_form_spec.js364
-rw-r--r--spec/frontend/jobs/components/job/sidebar_detail_row_spec.js68
-rw-r--r--spec/frontend/jobs/components/job/sidebar_header_spec.js87
-rw-r--r--spec/frontend/jobs/components/job/sidebar_spec.js216
-rw-r--r--spec/frontend/jobs/components/job/stages_dropdown_spec.js191
-rw-r--r--spec/frontend/jobs/components/job/stuck_block_spec.js94
-rw-r--r--spec/frontend/jobs/components/job/trigger_block_spec.js81
-rw-r--r--spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js37
-rw-r--r--spec/frontend/jobs/components/log/collapsible_section_spec.js71
-rw-r--r--spec/frontend/jobs/components/log/duration_badge_spec.js26
-rw-r--r--spec/frontend/jobs/components/log/line_header_spec.js119
-rw-r--r--spec/frontend/jobs/components/log/line_number_spec.js35
-rw-r--r--spec/frontend/jobs/components/log/line_spec.js267
-rw-r--r--spec/frontend/jobs/components/log/log_spec.js135
-rw-r--r--spec/frontend/jobs/components/table/cells/actions_cell_spec.js240
-rw-r--r--spec/frontend/jobs/components/table/cells/duration_cell_spec.js77
-rw-r--r--spec/frontend/jobs/components/table/cells/job_cell_spec.js142
-rw-r--r--spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js78
-rw-r--r--spec/frontend/jobs/components/table/graphql/cache_config_spec.js106
-rw-r--r--spec/frontend/jobs/components/table/job_table_app_spec.js338
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_empty_state_spec.js37
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_spec.js98
-rw-r--r--spec/frontend/jobs/components/table/jobs_table_tabs_spec.js81
-rw-r--r--spec/frontend/jobs/mixins/delayed_job_mixin_spec.js119
-rw-r--r--spec/frontend/jobs/mock_data.js1628
-rw-r--r--spec/frontend/jobs/store/actions_spec.js502
-rw-r--r--spec/frontend/jobs/store/getters_spec.js245
-rw-r--r--spec/frontend/jobs/store/helpers.js5
-rw-r--r--spec/frontend/jobs/store/mutations_spec.js269
-rw-r--r--spec/frontend/jobs/store/utils_spec.js510
-rw-r--r--spec/frontend/lib/utils/array_utility_spec.js36
-rw-r--r--spec/frontend/lib/utils/breadcrumbs_spec.js84
-rw-r--r--spec/frontend/lib/utils/common_utils_spec.js39
-rw-r--r--spec/frontend/lib/utils/datetime_range_spec.js382
-rw-r--r--spec/frontend/lib/utils/secret_detection_spec.js1
-rw-r--r--spec/frontend/lib/utils/text_utility_spec.js17
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js10
-rw-r--r--spec/frontend/members/components/table/__snapshots__/member_activity_spec.js.snap26
-rw-r--r--spec/frontend/merge_request_tabs_spec.js16
-rw-r--r--spec/frontend/merge_requests/components/compare_app_spec.js54
-rw-r--r--spec/frontend/merge_requests/components/header_metadata_spec.js93
-rw-r--r--spec/frontend/nav/components/top_nav_new_dropdown_spec.js3
-rw-r--r--spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap40
-rw-r--r--spec/frontend/notes/components/comment_form_spec.js5
-rw-r--r--spec/frontend/notes/components/notes_app_spec.js1
-rw-r--r--spec/frontend/notes/stores/actions_spec.js174
-rw-r--r--spec/frontend/observability/client_spec.js129
-rw-r--r--spec/frontend/organizations/groups_and_projects/components/app_spec.js19
-rw-r--r--spec/frontend/organizations/groups_and_projects/components/groups_page_spec.js88
-rw-r--r--spec/frontend/organizations/groups_and_projects/components/projects_page_spec.js88
-rw-r--r--spec/frontend/organizations/groups_and_projects/mock_data.js252
-rw-r--r--spec/frontend/organizations/groups_and_projects/utils_spec.js35
-rw-r--r--spec/frontend/organizations/shared/components/groups_view_spec.js146
-rw-r--r--spec/frontend/organizations/shared/components/projects_view_spec.js146
-rw-r--r--spec/frontend/organizations/shared/utils_spec.js39
-rw-r--r--spec/frontend/organizations/show/components/app_spec.js49
-rw-r--r--spec/frontend/organizations/show/components/association_count_card_spec.js48
-rw-r--r--spec/frontend/organizations/show/components/association_counts_spec.js61
-rw-r--r--spec/frontend/organizations/show/components/groups_and_projects_spec.js106
-rw-r--r--spec/frontend/organizations/show/components/organization_avatar_spec.js64
-rw-r--r--spec/frontend/organizations/show/utils_spec.js20
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap6
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap2
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap18
-rw-r--r--spec/frontend/packages_and_registries/dependency_proxy/app_spec.js71
-rw-r--r--spec/frontend/packages_and_registries/dependency_proxy/utils_spec.js25
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/file_sha_spec.js.snap11
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/terraform_installation_spec.js.snap4
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap25
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap42
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/conan_installation_spec.js.snap5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/dependency_row_spec.js.snap8
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/file_sha_spec.js.snap11
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/maven_installation_spec.js.snap67
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/npm_installation_spec.js.snap8
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/nuget_installation_spec.js.snap5
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/pypi_installation_spec.js.snap112
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap47
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/publish_method_spec.js.snap6
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js20
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js105
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/list_spec.js21
-rw-r--r--spec/frontend/packages_and_registries/package_registry/utils_spec.js52
-rw-r--r--spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap2
-rw-r--r--spec/frontend/packages_and_registries/shared/components/__snapshots__/publish_method_spec.js.snap6
-rw-r--r--spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap24
-rw-r--r--spec/frontend/packages_and_registries/shared/components/cli_commands_spec.js4
-rw-r--r--spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js4
-rw-r--r--spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js48
-rw-r--r--spec/frontend/pages/admin/jobs/components/cancel_jobs_modal_spec.js66
-rw-r--r--spec/frontend/pages/admin/jobs/components/cancel_jobs_spec.js9
-rw-r--r--spec/frontend/pages/admin/jobs/components/jobs_skeleton_loader_spec.js28
-rw-r--r--spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js105
-rw-r--r--spec/frontend/pages/admin/jobs/components/table/cells/project_cell_spec.js32
-rw-r--r--spec/frontend/pages/admin/jobs/components/table/cells/runner_cell_spec.js64
-rw-r--r--spec/frontend/pages/admin/jobs/components/table/graphql/cache_config_spec.js106
-rw-r--r--spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js6
-rw-r--r--spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js92
-rw-r--r--spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap230
-rw-r--r--spec/frontend/pipelines/components/dag/dag_annotations_spec.js98
-rw-r--r--spec/frontend/pipelines/components/dag/dag_graph_spec.js209
-rw-r--r--spec/frontend/pipelines/components/dag/dag_spec.js168
-rw-r--r--spec/frontend/pipelines/components/dag/drawing_utils_spec.js57
-rw-r--r--spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js80
-rw-r--r--spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js141
-rw-r--r--spec/frontend/pipelines/components/jobs/jobs_app_spec.js127
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/job_item_spec.js29
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph_spec.js122
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage_spec.js247
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list_spec.js166
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/mock_data.js150
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_mini_graph_spec.js123
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stage_spec.js46
-rw-r--r--spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stages_spec.js63
-rw-r--r--spec/frontend/pipelines/components/pipeline_tabs_spec.js114
-rw-r--r--spec/frontend/pipelines/components/pipelines_filtered_search_spec.js199
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js107
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js133
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js58
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/failure_widget/failed_job_details_spec.js254
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/failure_widget/failed_jobs_list_spec.js279
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js139
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/failure_widget/utils_spec.js58
-rw-r--r--spec/frontend/pipelines/components/pipelines_list/pipieline_stop_modal_spec.js27
-rw-r--r--spec/frontend/pipelines/empty_state_spec.js87
-rw-r--r--spec/frontend/pipelines/graph/action_component_spec.js116
-rw-r--r--spec/frontend/pipelines/graph/graph_component_spec.js182
-rw-r--r--spec/frontend/pipelines/graph/graph_component_wrapper_spec.js603
-rw-r--r--spec/frontend/pipelines/graph/graph_view_selector_spec.js217
-rw-r--r--spec/frontend/pipelines/graph/job_group_dropdown_spec.js84
-rw-r--r--spec/frontend/pipelines/graph/job_item_spec.js492
-rw-r--r--spec/frontend/pipelines/graph/job_name_component_spec.js30
-rw-r--r--spec/frontend/pipelines/graph/linked_pipeline_spec.js464
-rw-r--r--spec/frontend/pipelines/graph/linked_pipelines_column_spec.js214
-rw-r--r--spec/frontend/pipelines/graph/mock_data.js387
-rw-r--r--spec/frontend/pipelines/graph/stage_column_component_spec.js228
-rw-r--r--spec/frontend/pipelines/graph_shared/__snapshots__/links_inner_spec.js.snap30
-rw-r--r--spec/frontend/pipelines/graph_shared/links_inner_spec.js223
-rw-r--r--spec/frontend/pipelines/graph_shared/links_layer_spec.js85
-rw-r--r--spec/frontend/pipelines/mock_data.js1379
-rw-r--r--spec/frontend/pipelines/nav_controls_spec.js80
-rw-r--r--spec/frontend/pipelines/notification/mock_data.js33
-rw-r--r--spec/frontend/pipelines/pipeline_details_header_spec.js452
-rw-r--r--spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js100
-rw-r--r--spec/frontend/pipelines/pipeline_graph/utils_spec.js197
-rw-r--r--spec/frontend/pipelines/pipeline_labels_spec.js164
-rw-r--r--spec/frontend/pipelines/pipeline_multi_actions_spec.js288
-rw-r--r--spec/frontend/pipelines/pipeline_operations_spec.js77
-rw-r--r--spec/frontend/pipelines/pipeline_tabs_spec.js63
-rw-r--r--spec/frontend/pipelines/pipeline_triggerer_spec.js76
-rw-r--r--spec/frontend/pipelines/pipeline_url_spec.js184
-rw-r--r--spec/frontend/pipelines/pipelines_artifacts_spec.js64
-rw-r--r--spec/frontend/pipelines/pipelines_manual_actions_spec.js216
-rw-r--r--spec/frontend/pipelines/pipelines_spec.js850
-rw-r--r--spec/frontend/pipelines/pipelines_store_spec.js80
-rw-r--r--spec/frontend/pipelines/pipelines_table_spec.js280
-rw-r--r--spec/frontend/pipelines/test_reports/empty_state_spec.js45
-rw-r--r--spec/frontend/pipelines/test_reports/mock_data.js31
-rw-r--r--spec/frontend/pipelines/test_reports/stores/actions_spec.js149
-rw-r--r--spec/frontend/pipelines/test_reports/stores/getters_spec.js171
-rw-r--r--spec/frontend/pipelines/test_reports/stores/mutations_spec.js114
-rw-r--r--spec/frontend/pipelines/test_reports/stores/utils_spec.js40
-rw-r--r--spec/frontend/pipelines/test_reports/test_case_details_spec.js149
-rw-r--r--spec/frontend/pipelines/test_reports/test_reports_spec.js125
-rw-r--r--spec/frontend/pipelines/test_reports/test_suite_table_spec.js169
-rw-r--r--spec/frontend/pipelines/test_reports/test_summary_spec.js106
-rw-r--r--spec/frontend/pipelines/test_reports/test_summary_table_spec.js100
-rw-r--r--spec/frontend/pipelines/time_ago_spec.js85
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js142
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_source_token_spec.js53
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_status_token_spec.js58
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js95
-rw-r--r--spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js99
-rw-r--r--spec/frontend/pipelines/unwrapping_utils_spec.js127
-rw-r--r--spec/frontend/pipelines/utils_spec.js191
-rw-r--r--spec/frontend/profile/preferences/components/__snapshots__/diffs_colors_preview_spec.js.snap210
-rw-r--r--spec/frontend/projects/commit/components/form_modal_spec.js9
-rw-r--r--spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js136
-rw-r--r--spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap3
-rw-r--r--spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap1
-rw-r--r--spec/frontend/projects/pipelines/charts/components/__snapshots__/statistics_list_spec.js.snap8
-rw-r--r--spec/frontend/projects/settings/access_dropdown_spec.js204
-rw-r--r--spec/frontend/projects/settings/components/new_access_dropdown_spec.js55
-rw-r--r--spec/frontend/projects/settings_service_desk/components/custom_email_form_spec.js13
-rw-r--r--spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js21
-rw-r--r--spec/frontend/protected_branches/protected_branch_create_spec.js51
-rw-r--r--spec/frontend/protected_branches/protected_branch_edit_spec.js2
-rw-r--r--spec/frontend/protected_tags/mock_data.js18
-rw-r--r--spec/frontend/protected_tags/protected_tag_edit_spec.js113
-rw-r--r--spec/frontend/releases/__snapshots__/util_spec.js.snap48
-rw-r--r--spec/frontend/releases/components/__snapshots__/issuable_stats_spec.js.snap67
-rw-r--r--spec/frontend/releases/components/release_block_milestone_info_spec.js6
-rw-r--r--spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap18
-rw-r--r--spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap44
-rw-r--r--spec/frontend/repository/components/blob_content_viewer_spec.js81
-rw-r--r--spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap114
-rw-r--r--spec/frontend/repository/mock_data.js11
-rw-r--r--spec/frontend/search/mock_data.js2
-rw-r--r--spec/frontend/search/sidebar/components/app_spec.js117
-rw-r--r--spec/frontend/search/sidebar/components/blobs_filters_spec.js85
-rw-r--r--spec/frontend/search/sidebar/components/commits_filters_spec.js28
-rw-r--r--spec/frontend/search/sidebar/components/issues_filters_spec.js98
-rw-r--r--spec/frontend/search/sidebar/components/merge_requests_filters_spec.js123
-rw-r--r--spec/frontend/search/sidebar/components/notes_filters_spec.js28
-rw-r--r--spec/frontend/search/sidebar/components/projects_filters_spec.js28
-rw-r--r--spec/frontend/search/sidebar/components/projects_filters_specs.js28
-rw-r--r--spec/frontend/search/sidebar/components/small_screen_drawer_navigation_spec.js68
-rw-r--r--spec/frontend/search/store/actions_spec.js16
-rw-r--r--spec/frontend/security_configuration/components/continuous_vulnerability_scan_spec.js124
-rw-r--r--spec/frontend/security_configuration/components/feature_card_spec.js18
-rw-r--r--spec/frontend/security_configuration/utils_spec.js64
-rw-r--r--spec/frontend/sentry/index_spec.js104
-rw-r--r--spec/frontend/sentry/init_sentry_spec.js177
-rw-r--r--spec/frontend/sentry/legacy_index_spec.js6
-rw-r--r--spec/frontend/sentry/sentry_config_spec.js103
-rw-r--r--spec/frontend/service_desk/components/empty_state_with_any_issues_spec.js74
-rw-r--r--spec/frontend/service_desk/components/empty_state_without_any_issues_spec.js86
-rw-r--r--spec/frontend/service_desk/components/info_banner_spec.js81
-rw-r--r--spec/frontend/service_desk/components/service_desk_list_app_spec.js376
-rw-r--r--spec/frontend/service_desk/mock_data.js236
-rw-r--r--spec/frontend/sidebar/components/assignees/assignees_spec.js2
-rw-r--r--spec/frontend/sidebar/components/assignees/sidebar_invite_members_spec.js2
-rw-r--r--spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js2
-rw-r--r--spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js86
-rw-r--r--spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js7
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js27
-rw-r--r--spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js37
-rw-r--r--spec/frontend/sidebar/components/lock/__snapshots__/edit_form_spec.js.snap4
-rw-r--r--spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js6
-rw-r--r--spec/frontend/sidebar/components/todo_toggle/__snapshots__/todo_spec.js.snap4
-rw-r--r--spec/frontend/sidebar/mock_data.js80
-rw-r--r--spec/frontend/silent_mode_settings/components/app_spec.js133
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap3
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap26
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap2
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap25
-rw-r--r--spec/frontend/snippets/components/embed_dropdown_spec.js48
-rw-r--r--spec/frontend/super_sidebar/components/context_header_spec.js50
-rw-r--r--spec/frontend/super_sidebar/components/context_switcher_spec.js302
-rw-r--r--spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js39
-rw-r--r--spec/frontend/super_sidebar/components/create_menu_spec.js21
-rw-r--r--spec/frontend/super_sidebar/components/flyout_menu_spec.js16
-rw-r--r--spec/frontend/super_sidebar/components/frequent_items_list_spec.js85
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap27
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js42
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js17
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js4
-rw-r--r--spec/frontend/super_sidebar/components/global_search/components/global_search_default_places_spec.js16
-rw-r--r--spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js63
-rw-r--r--spec/frontend/super_sidebar/components/global_search/mock_data.js44
-rw-r--r--spec/frontend/super_sidebar/components/global_search/utils_spec.js88
-rw-r--r--spec/frontend/super_sidebar/components/groups_list_spec.js90
-rw-r--r--spec/frontend/super_sidebar/components/items_list_spec.js63
-rw-r--r--spec/frontend/super_sidebar/components/menu_section_spec.js36
-rw-r--r--spec/frontend/super_sidebar/components/nav_item_spec.js97
-rw-r--r--spec/frontend/super_sidebar/components/pinned_section_spec.js29
-rw-r--r--spec/frontend/super_sidebar/components/projects_list_spec.js85
-rw-r--r--spec/frontend/super_sidebar/components/search_results_spec.js69
-rw-r--r--spec/frontend/super_sidebar/components/sidebar_hover_peek_behavior_spec.js213
-rw-r--r--spec/frontend/super_sidebar/components/sidebar_menu_spec.js69
-rw-r--r--spec/frontend/super_sidebar/components/sidebar_peek_behavior_spec.js25
-rw-r--r--spec/frontend/super_sidebar/components/super_sidebar_spec.js111
-rw-r--r--spec/frontend/super_sidebar/components/super_sidebar_toggle_spec.js23
-rw-r--r--spec/frontend/super_sidebar/components/user_bar_spec.js20
-rw-r--r--spec/frontend/super_sidebar/components/user_menu_spec.js21
-rw-r--r--spec/frontend/super_sidebar/mock_data.js46
-rw-r--r--spec/frontend/super_sidebar/mocks.js24
-rw-r--r--spec/frontend/super_sidebar/utils_spec.js78
-rw-r--r--spec/frontend/time_tracking/components/timelogs_app_spec.js25
-rw-r--r--spec/frontend/tracing/components/tracing_details_spec.js103
-rw-r--r--spec/frontend/tracing/components/tracing_empty_state_spec.js39
-rw-r--r--spec/frontend/tracing/components/tracing_list_filtered_search_spec.js38
-rw-r--r--spec/frontend/tracing/components/tracing_list_spec.js216
-rw-r--r--spec/frontend/tracing/components/tracing_table_list_spec.js77
-rw-r--r--spec/frontend/tracing/details_index_spec.js42
-rw-r--r--spec/frontend/tracing/filters_spec.js141
-rw-r--r--spec/frontend/tracing/list_index_spec.js37
-rw-r--r--spec/frontend/tracking/dispatch_snowplow_event_spec.js76
-rw-r--r--spec/frontend/tracking/internal_events_spec.js147
-rw-r--r--spec/frontend/tracking/mock_data.js17
-rw-r--r--spec/frontend/tracking/tracking_initialization_spec.js29
-rw-r--r--spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js29
-rw-r--r--spec/frontend/usage_quotas/storage/components/usage_graph_spec.js125
-rw-r--r--spec/frontend/user_lists/components/user_list_spec.js2
-rw-r--r--spec/frontend/users_select/test_helper.js3
-rw-r--r--spec/frontend/vue_merge_request_widget/components/action_buttons.js43
-rw-r--r--spec/frontend/vue_merge_request_widget/components/action_buttons_spec.js61
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/__snapshots__/new_ready_to_merge_spec.js.snap18
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js6
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap154
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/app_spec.js45
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js72
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js7
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js31
-rw-r--r--spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js16
-rw-r--r--spec/frontend/vue_merge_request_widget/mock_data.js168
-rw-r--r--spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js811
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap32
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/integration_help_text_spec.js.snap6
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap4
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap59
-rw-r--r--spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap6
-rw-r--r--spec/frontend/vue_shared/components/blob_viewers/__snapshots__/simple_viewer_spec.js.snap29
-rw-r--r--spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js77
-rw-r--r--spec/frontend/vue_shared/components/ci_badge_link_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/code_block_highlighted_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/code_block_spec.js56
-rw-r--r--spec/frontend/vue_shared/components/confidentiality_badge_spec.js42
-rw-r--r--spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js13
-rw-r--r--spec/frontend/vue_shared/components/date_time_picker/date_time_picker_input_spec.js62
-rw-r--r--spec/frontend/vue_shared/components/date_time_picker/date_time_picker_lib_spec.js190
-rw-r--r--spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js326
-rw-r--r--spec/frontend/vue_shared/components/design_management/__snapshots__/design_note_pin_spec.js.snap12
-rw-r--r--spec/frontend/vue_shared/components/entity_select/utils_spec.js12
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js16
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js45
-rw-r--r--spec/frontend/vue_shared/components/form/__snapshots__/form_footer_actions_spec.js.snap2
-rw-r--r--spec/frontend/vue_shared/components/gl_modal_vuex_spec.js10
-rw-r--r--spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js69
-rw-r--r--spec/frontend/vue_shared/components/groups_list/groups_list_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/groups_list/mock_data.js6
-rw-r--r--spec/frontend/vue_shared/components/header_ci_component_spec.js165
-rw-r--r--spec/frontend/vue_shared/components/list_actions/list_actions_spec.js135
-rw-r--r--spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap3
-rw-r--r--spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js23
-rw-r--r--spec/frontend/vue_shared/components/markdown/comment_templates_dropdown_spec.js35
-rw-r--r--spec/frontend/vue_shared/components/markdown/field_view_spec.js22
-rw-r--r--spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js7
-rw-r--r--spec/frontend/vue_shared/components/metric_images/__snapshots__/metric_images_table_spec.js.snap13
-rw-r--r--spec/frontend/vue_shared/components/notes/__snapshots__/noteable_warning_spec.js.snap18
-rw-r--r--spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_note_spec.js.snap15
-rw-r--r--spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_system_note_spec.js.snap2
-rw-r--r--spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/pagination_bar/pagination_bar_spec.js12
-rw-r--r--spec/frontend/vue_shared/components/projects_list/projects_list_item_spec.js33
-rw-r--r--spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap14
-rw-r--r--spec/frontend/vue_shared/components/registry/__snapshots__/history_item_spec.js.snap6
-rw-r--r--spec/frontend/vue_shared/components/resizable_chart/__snapshots__/skeleton_loader_spec.js.snap12
-rw-r--r--spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap15
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/components/__snapshots__/chunk_new_spec.js.snap13
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js1
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js3
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js35
-rw-r--r--spec/frontend/vue_shared/components/split_button_spec.js117
-rw-r--r--spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap328
-rw-r--r--spec/frontend/vue_shared/components/user_select_spec.js28
-rw-r--r--spec/frontend/vue_shared/issuable/__snapshots__/issuable_blocked_icon_spec.js.snap30
-rw-r--r--spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js2
-rw-r--r--spec/frontend/vue_shared/issuable/issuable_blocked_icon_spec.js4
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js33
-rw-r--r--spec/frontend/vue_shared/issuable/list/mock_data.js2
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js12
-rw-r--r--spec/frontend/vue_shared/issuable/show/components/issuable_title_spec.js4
-rw-r--r--spec/frontend/vue_shared/issuable/show/mock_data.js1
-rw-r--r--spec/frontend/vue_shared/new_namespace/new_namespace_page_spec.js20
-rw-r--r--spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js64
-rw-r--r--spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap168
-rw-r--r--spec/frontend/work_items/components/notes/__snapshots__/work_item_note_body_spec.js.snap40
-rw-r--r--spec/frontend/work_items/components/notes/__snapshots__/work_item_note_replying_spec.js.snap12
-rw-r--r--spec/frontend/work_items/components/notes/work_item_activity_sort_filter_spec.js27
-rw-r--r--spec/frontend/work_items/components/notes/work_item_add_note_spec.js14
-rw-r--r--spec/frontend/work_items/components/notes/work_item_note_spec.js7
-rw-r--r--spec/frontend/work_items/components/shared/work_item_link_child_contents_spec.js14
-rw-r--r--spec/frontend/work_items/components/shared/work_item_links_menu_spec.js8
-rw-r--r--spec/frontend/work_items/components/shared/work_item_token_input_spec.js81
-rw-r--r--spec/frontend/work_items/components/work_item_actions_spec.js21
-rw-r--r--spec/frontend/work_items/components/work_item_detail_spec.js84
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js2
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js50
-rw-r--r--spec/frontend/work_items/components/work_item_notes_spec.js12
-rw-r--r--spec/frontend/work_items/components/work_item_relationships/__snapshots__/work_item_relationship_list_spec.js.snap29
-rw-r--r--spec/frontend/work_items/components/work_item_relationships/work_item_relationship_list_spec.js41
-rw-r--r--spec/frontend/work_items/components/work_item_relationships/work_item_relationships_spec.js93
-rw-r--r--spec/frontend/work_items/components/work_item_state_badge_spec.js5
-rw-r--r--spec/frontend/work_items/list/components/work_items_list_app_spec.js18
-rw-r--r--spec/frontend/work_items/mock_data.js192
-rw-r--r--spec/frontend/work_items/utils_spec.js13
-rw-r--r--spec/graphql/mutations/base_mutation_spec.rb2
-rw-r--r--spec/graphql/mutations/design_management/delete_spec.rb35
-rw-r--r--spec/graphql/mutations/work_items/linked_items/base_spec.rb3
-rw-r--r--spec/graphql/resolvers/base_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/blame_resolver_spec.rb81
-rw-r--r--spec/graphql/resolvers/branch_commit_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb117
-rw-r--r--spec/graphql/resolvers/ci/group_runners_resolver_spec.rb20
-rw-r--r--spec/graphql/resolvers/ci/project_runners_resolver_spec.rb16
-rw-r--r--spec/graphql/resolvers/ci/runners_resolver_spec.rb30
-rw-r--r--spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb16
-rw-r--r--spec/graphql/resolvers/work_items_resolver_spec.rb5
-rw-r--r--spec/graphql/types/base_argument_spec.rb2
-rw-r--r--spec/graphql/types/base_edge_spec.rb2
-rw-r--r--spec/graphql/types/base_enum_spec.rb2
-rw-r--r--spec/graphql/types/base_field_spec.rb2
-rw-r--r--spec/graphql/types/base_object_spec.rb2
-rw-r--r--spec/graphql/types/blame/blame_type_spec.rb16
-rw-r--r--spec/graphql/types/blame/commit_data_type_spec.rb21
-rw-r--r--spec/graphql/types/blame/groups_type_spec.rb19
-rw-r--r--spec/graphql/types/ci/job_base_field_spec.rb143
-rw-r--r--spec/graphql/types/ci/job_kind_enum_spec.rb2
-rw-r--r--spec/graphql/types/ci/job_trace_type_spec.rb184
-rw-r--r--spec/graphql/types/ci/job_type_spec.rb1
-rw-r--r--spec/graphql/types/issue_type_spec.rb2
-rw-r--r--spec/graphql/types/label_type_spec.rb1
-rw-r--r--spec/graphql/types/merge_request_type_spec.rb2
-rw-r--r--spec/graphql/types/organizations/group_sort_enum_spec.rb26
-rw-r--r--spec/graphql/types/organizations/organization_type_spec.rb11
-rw-r--r--spec/graphql/types/organizations/organization_user_type_spec.rb11
-rw-r--r--spec/graphql/types/permission_types/work_item_spec.rb2
-rw-r--r--spec/graphql/types/project_type_spec.rb11
-rw-r--r--spec/graphql/types/query_type_spec.rb10
-rw-r--r--spec/graphql/types/repository/blob_type_spec.rb1
-rw-r--r--spec/graphql/types/security/codequality_reports_comparer/degradation_type_spec.rb13
-rw-r--r--spec/graphql/types/security/codequality_reports_comparer/report_type_spec.rb13
-rw-r--r--spec/graphql/types/security/codequality_reports_comparer/status_enum_spec.rb11
-rw-r--r--spec/graphql/types/security/codequality_reports_comparer/summary_type_spec.rb13
-rw-r--r--spec/graphql/types/security/codequality_reports_comparer_type_spec.rb11
-rw-r--r--spec/helpers/admin/abuse_reports_helper_spec.rb8
-rw-r--r--spec/helpers/application_helper_spec.rb100
-rw-r--r--spec/helpers/artifacts_helper_spec.rb3
-rw-r--r--spec/helpers/button_helper_spec.rb98
-rw-r--r--spec/helpers/ci/status_helper_spec.rb23
-rw-r--r--spec/helpers/environment_helper_spec.rb9
-rw-r--r--spec/helpers/environments_helper_spec.rb12
-rw-r--r--spec/helpers/icons_helper_spec.rb11
-rw-r--r--spec/helpers/integrations_helper_spec.rb20
-rw-r--r--spec/helpers/invite_members_helper_spec.rb56
-rw-r--r--spec/helpers/issuables_helper_spec.rb325
-rw-r--r--spec/helpers/issues_helper_spec.rb84
-rw-r--r--spec/helpers/members_helper_spec.rb6
-rw-r--r--spec/helpers/nav/new_dropdown_helper_spec.rb2
-rw-r--r--spec/helpers/nav_helper_spec.rb9
-rw-r--r--spec/helpers/organizations/organization_helper_spec.rb65
-rw-r--r--spec/helpers/projects/observability_helper_spec.rb37
-rw-r--r--spec/helpers/projects/pipeline_helper_spec.rb2
-rw-r--r--spec/helpers/projects_helper_spec.rb16
-rw-r--r--spec/helpers/registrations_helper_spec.rb2
-rw-r--r--spec/helpers/sidebars_helper_spec.rb229
-rw-r--r--spec/helpers/sidekiq_helper_spec.rb2
-rw-r--r--spec/helpers/vite_helper_spec.rb59
-rw-r--r--spec/helpers/webpack_helper_spec.rb18
-rw-r--r--spec/helpers/work_items_helper_spec.rb14
-rw-r--r--spec/initializers/action_cable_subscription_adapter_identifier_spec.rb3
-rw-r--r--spec/initializers/mail_starttls_patch_spec.rb31
-rw-r--r--spec/initializers/sidekiq_spec.rb2
-rw-r--r--spec/lib/api/ci/helpers/runner_spec.rb34
-rw-r--r--spec/lib/api/entities/merge_request_basic_spec.rb2
-rw-r--r--spec/lib/api/entities/merge_request_diff_spec.rb44
-rw-r--r--spec/lib/api/entities/ml/mlflow/get_run_spec.rb63
-rw-r--r--spec/lib/api/entities/ml/mlflow/run_info_spec.rb2
-rw-r--r--spec/lib/api/entities/ml/mlflow/run_spec.rb20
-rw-r--r--spec/lib/api/entities/ml/mlflow/search_runs_spec.rb37
-rw-r--r--spec/lib/api/entities/project_spec.rb2
-rw-r--r--spec/lib/api/helpers/packages_helpers_spec.rb4
-rw-r--r--spec/lib/api/helpers_spec.rb222
-rw-r--r--spec/lib/api/ml/mlflow/api_helpers_spec.rb24
-rw-r--r--spec/lib/backup/database_model_spec.rb82
-rw-r--r--spec/lib/backup/database_spec.rb92
-rw-r--r--spec/lib/backup/gitaly_backup_spec.rb14
-rw-r--r--spec/lib/backup/repositories_spec.rb46
-rw-r--r--spec/lib/banzai/filter/code_language_filter_spec.rb36
-rw-r--r--spec/lib/banzai/filter/inline_diff_filter_spec.rb2
-rw-r--r--spec/lib/bitbucket/representation/pull_request_spec.rb51
-rw-r--r--spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb24
-rw-r--r--spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb6
-rw-r--r--spec/lib/bulk_imports/common/transformers/member_attributes_transformer_spec.rb53
-rw-r--r--spec/lib/bulk_imports/file_downloads/validations_spec.rb2
-rw-r--r--spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb27
-rw-r--r--spec/lib/bulk_imports/network_error_spec.rb30
-rw-r--r--spec/lib/bulk_imports/pipeline/runner_spec.rb2
-rw-r--r--spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb34
-rw-r--r--spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb125
-rw-r--r--spec/lib/bulk_imports/users_mapper_spec.rb26
-rw-r--r--spec/lib/click_house/bind_index_manager_spec.rb33
-rw-r--r--spec/lib/click_house/query_builder_spec.rb26
-rw-r--r--spec/lib/click_house/record_sync_context_spec.rb32
-rw-r--r--spec/lib/click_house/sync_cursor_spec.rb35
-rw-r--r--spec/lib/constraints/activity_pub_constrainer_spec.rb39
-rw-r--r--spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_spec_matcher.txt2
-rw-r--r--spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb6
-rw-r--r--spec/lib/generators/gitlab/partitioning/foreign_keys_generator_spec.rb6
-rw-r--r--spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb5
-rw-r--r--spec/lib/gitlab/auth/o_auth/provider_spec.rb14
-rw-r--r--spec/lib/gitlab/auth/user_access_denied_reason_spec.rb2
-rw-r--r--spec/lib/gitlab/auth_spec.rb24
-rw-r--r--spec/lib/gitlab/background_migration/backfill_has_merge_request_of_vulnerability_reads_spec.rb101
-rw-r--r--spec/lib/gitlab/background_migration/backfill_nuget_normalized_version_spec.rb74
-rw-r--r--spec/lib/gitlab/background_migration/backfill_project_statistics_storage_size_with_recent_size_spec.rb165
-rw-r--r--spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb4
-rw-r--r--spec/lib/gitlab/background_migration/backfill_user_preferences_with_defaults_spec.rb66
-rw-r--r--spec/lib/gitlab/background_migration/backfill_users_with_defaults_spec.rb68
-rw-r--r--spec/lib/gitlab/background_migration/convert_credit_card_validation_data_to_hashes_spec.rb81
-rw-r--r--spec/lib/gitlab/background_migration/rebalance_partition_id_spec.rb46
-rw-r--r--spec/lib/gitlab/background_migration/update_users_set_external_if_service_account_spec.rb42
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb22
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb166
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb71
-rw-r--r--spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb49
-rw-r--r--spec/lib/gitlab/bitbucket_import/parallel_importer_spec.rb43
-rw-r--r--spec/lib/gitlab/bitbucket_import/user_finder_spec.rb75
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importer_spec.rb653
-rw-r--r--spec/lib/gitlab/checks/matching_merge_request_spec.rb45
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb206
-rw-r--r--spec/lib/gitlab/ci/build/duration_parser_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/components/instance_path_spec.rb251
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/default_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb38
-rw-r--r--spec/lib/gitlab/ci/config/entry/include/rules_spec.rb35
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/config/external/context_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/config/external/file/component_spec.rb35
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb26
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/config/external/rules_spec.rb218
-rw-r--r--spec/lib/gitlab/ci/config/interpolation/interpolator_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb65
-rw-r--r--spec/lib/gitlab/ci/parsers/security/common_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb120
-rw-r--r--spec/lib/gitlab/ci/reports/sbom/component_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/reports/sbom/metadata_spec.rb54
-rw-r--r--spec/lib/gitlab/ci/templates/MATLAB_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/trace/stream_spec.rb50
-rw-r--r--spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb7
-rw-r--r--spec/lib/gitlab/ci/variables/builder_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb122
-rw-r--r--spec/lib/gitlab/composer/version_index_spec.rb115
-rw-r--r--spec/lib/gitlab/content_security_policy/config_loader_spec.rb56
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb34
-rw-r--r--spec/lib/gitlab/data_builder/deployment_spec.rb9
-rw-r--r--spec/lib/gitlab/database/async_indexes/migration_helpers_spec.rb8
-rw-r--r--spec/lib/gitlab/database/click_house_client_spec.rb191
-rw-r--r--spec/lib/gitlab/database/gitlab_schema_spec.rb2
-rw-r--r--spec/lib/gitlab/database/load_balancing/host_spec.rb33
-rw-r--r--spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb51
-rw-r--r--spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb119
-rw-r--r--spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb127
-rw-r--r--spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb44
-rw-r--r--spec/lib/gitlab/database/load_balancing/sticking_spec.rb353
-rw-r--r--spec/lib/gitlab/database/migrations/instrumentation_spec.rb2
-rw-r--r--spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb7
-rw-r--r--spec/lib/gitlab/database/no_overrides_for_through_associations_spec.rb80
-rw-r--r--spec/lib/gitlab/database/partitioning/ci_sliding_list_strategy_spec.rb26
-rw-r--r--spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb30
-rw-r--r--spec/lib/gitlab/database/partitioning/partition_manager_spec.rb155
-rw-r--r--spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb26
-rw-r--r--spec/lib/gitlab/database/partitioning_spec.rb91
-rw-r--r--spec/lib/gitlab/database/reindexing_spec.rb20
-rw-r--r--spec/lib/gitlab/database/tables_truncate_spec.rb278
-rw-r--r--spec/lib/gitlab/database_spec.rb53
-rw-r--r--spec/lib/gitlab/database_warnings_spec.rb96
-rw-r--r--spec/lib/gitlab/email/handler/create_note_handler_spec.rb4
-rw-r--r--spec/lib/gitlab/email/handler/service_desk_handler_spec.rb8
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/admin_verify_spec.rb45
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb108
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb28
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/team_short_spec.rb47
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb82
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/trial_short_spec.rb45
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb48
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb54
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing_spec.rb35
-rw-r--r--spec/lib/gitlab/email/service_desk/custom_email_spec.rb37
-rw-r--r--spec/lib/gitlab/etag_caching/middleware_spec.rb16
-rw-r--r--spec/lib/gitlab/etag_caching/router/rails_spec.rb14
-rw-r--r--spec/lib/gitlab/etag_caching/store_spec.rb2
-rw-r--r--spec/lib/gitlab/event_store/store_spec.rb20
-rw-r--r--spec/lib/gitlab/experiment/rollout/feature_spec.rb2
-rw-r--r--spec/lib/gitlab/git/blame_spec.rb10
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb25
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb31
-rw-r--r--spec/lib/gitlab/git_access_snippet_spec.rb2
-rw-r--r--spec/lib/gitlab/gitaly_client/operation_service_spec.rb105
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_service_spec.rb110
-rw-r--r--spec/lib/gitlab/gitaly_client/repository_service_spec.rb13
-rw-r--r--spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb23
-rw-r--r--spec/lib/gitlab/github_import/attachments_downloader_spec.rb51
-rw-r--r--spec/lib/gitlab/github_import/client_spec.rb22
-rw-r--r--spec/lib/gitlab/github_import/importer/note_attachments_importer_spec.rb41
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_requests/merged_by_importer_spec.rb4
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_requests/review_importer_spec.rb4
-rw-r--r--spec/lib/gitlab/github_import/markdown/attachment_spec.rb24
-rw-r--r--spec/lib/gitlab/github_import/object_counter_spec.rb26
-rw-r--r--spec/lib/gitlab/github_import/user_finder_spec.rb269
-rw-r--r--spec/lib/gitlab/github_import_spec.rb4
-rw-r--r--spec/lib/gitlab/gl_repository/identifier_spec.rb6
-rw-r--r--spec/lib/gitlab/gl_repository/repo_type_spec.rb24
-rw-r--r--spec/lib/gitlab/gl_repository_spec.rb11
-rw-r--r--spec/lib/gitlab/gon_helper_spec.rb88
-rw-r--r--spec/lib/gitlab/graphql/deprecations/deprecation_spec.rb2
-rw-r--r--spec/lib/gitlab/group_search_results_spec.rb13
-rw-r--r--spec/lib/gitlab/http_spec.rb9
-rw-r--r--spec/lib/gitlab/import/errors_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml8
-rw-r--r--spec/lib/gitlab/import_export/attributes_permitter_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/base/relation_object_saver_spec.rb31
-rw-r--r--spec/lib/gitlab/import_export/command_line_util_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb14
-rw-r--r--spec/lib/gitlab/import_export/file_importer_spec.rb3
-rw-r--r--spec/lib/gitlab/import_export/import_test_coverage_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb11
-rw-r--r--spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb3
-rw-r--r--spec/lib/gitlab/import_export/project/export_task_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project/tree_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_sources_spec.rb54
-rw-r--r--spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb1
-rw-r--r--spec/lib/gitlab/job_waiter_spec.rb40
-rw-r--r--spec/lib/gitlab/manifest_import/metadata_spec.rb18
-rw-r--r--spec/lib/gitlab/metrics/dashboard/cache_spec.rb88
-rw-r--r--spec/lib/gitlab/metrics/dashboard/processor_spec.rb30
-rw-r--r--spec/lib/gitlab/metrics/dashboard/repo_dashboard_finder_spec.rb54
-rw-r--r--spec/lib/gitlab/metrics/dashboard/stages/url_validator_spec.rb101
-rw-r--r--spec/lib/gitlab/metrics/dashboard/url_spec.rb106
-rw-r--r--spec/lib/gitlab/metrics/samplers/database_sampler_spec.rb78
-rw-r--r--spec/lib/gitlab/middleware/webhook_recursion_detection_spec.rb2
-rw-r--r--spec/lib/gitlab/observability_spec.rb29
-rw-r--r--spec/lib/gitlab/other_markup_spec.rb41
-rw-r--r--spec/lib/gitlab/pages/cache_control_spec.rb88
-rw-r--r--spec/lib/gitlab/pages/virtual_host_finder_spec.rb58
-rw-r--r--spec/lib/gitlab/pages_spec.rb87
-rw-r--r--spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb102
-rw-r--r--spec/lib/gitlab/patch/redis_cache_store_spec.rb66
-rw-r--r--spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb89
-rw-r--r--spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb248
-rw-r--r--spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb23
-rw-r--r--spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb45
-rw-r--r--spec/lib/gitlab/rack_attack/request_spec.rb33
-rw-r--r--spec/lib/gitlab/redis/chat_spec.rb2
-rw-r--r--spec/lib/gitlab/redis/etag_cache_spec.rb56
-rw-r--r--spec/lib/gitlab/redis/multi_store_spec.rb100
-rw-r--r--spec/lib/gitlab/redis/pubsub_spec.rb8
-rw-r--r--spec/lib/gitlab/redis/queues_metadata_spec.rb43
-rw-r--r--spec/lib/gitlab/redis/workhorse_spec.rb44
-rw-r--r--spec/lib/gitlab/regex_spec.rb25
-rw-r--r--spec/lib/gitlab/repo_path_spec.rb14
-rw-r--r--spec/lib/gitlab/search_results_spec.rb54
-rw-r--r--spec/lib/gitlab/security/scan_configuration_spec.rb10
-rw-r--r--spec/lib/gitlab/setup_helper/workhorse_spec.rb10
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb2
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb65
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb6
-rw-r--r--spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb3
-rw-r--r--spec/lib/gitlab/sidekiq_queue_spec.rb2
-rw-r--r--spec/lib/gitlab/sql/cte_spec.rb3
-rw-r--r--spec/lib/gitlab/sql/pattern_spec.rb46
-rw-r--r--spec/lib/gitlab/time_tracking_formatter_spec.rb8
-rw-r--r--spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb4
-rw-r--r--spec/lib/gitlab/tracking/service_ping_context_spec.rb24
-rw-r--r--spec/lib/gitlab/tracking/standard_context_spec.rb3
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb3
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb19
-rw-r--r--spec/lib/gitlab/usage/metric_definition_spec.rb60
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb16
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_connected_agents_metric_spec.rb12
-rw-r--r--spec/lib/gitlab/usage/metrics/query_spec.rb2
-rw-r--r--spec/lib/gitlab/usage/time_series_storable_spec.rb40
-rw-r--r--spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb186
-rw-r--r--spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb6
-rw-r--r--spec/lib/gitlab/usage_data_queries_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb8
-rw-r--r--spec/lib/gitlab/user_access_snippet_spec.rb2
-rw-r--r--spec/lib/gitlab/utils/markdown_spec.rb35
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb145
-rw-r--r--spec/lib/gitlab/x509/certificate_spec.rb2
-rw-r--r--spec/lib/gitlab/x509/commit_sigstore_spec.rb53
-rw-r--r--spec/lib/gitlab/x509/commit_spec.rb6
-rw-r--r--spec/lib/gitlab/x509/signature_sigstore_spec.rb453
-rw-r--r--spec/lib/gitlab/x509/signature_spec.rb2
-rw-r--r--spec/lib/gitlab/x509/tag_sigstore_spec.rb45
-rw-r--r--spec/lib/gitlab/x509/tag_spec.rb27
-rw-r--r--spec/lib/peek/views/click_house_spec.rb13
-rw-r--r--spec/lib/sidebars/admin/panel_spec.rb8
-rw-r--r--spec/lib/sidebars/concerns/has_avatar_spec.rb29
-rw-r--r--spec/lib/sidebars/explore/panel_spec.rb17
-rw-r--r--spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb39
-rw-r--r--spec/lib/sidebars/groups/menus/scope_menu_spec.rb5
-rw-r--r--spec/lib/sidebars/groups/super_sidebar_panel_spec.rb8
-rw-r--r--spec/lib/sidebars/menu_item_spec.rb9
-rw-r--r--spec/lib/sidebars/menu_spec.rb12
-rw-r--r--spec/lib/sidebars/organizations/menus/scope_menu_spec.rb4
-rw-r--r--spec/lib/sidebars/organizations/panel_spec.rb1
-rw-r--r--spec/lib/sidebars/organizations/super_sidebar_panel_spec.rb7
-rw-r--r--spec/lib/sidebars/panel_spec.rb18
-rw-r--r--spec/lib/sidebars/projects/menus/issues_menu_spec.rb1
-rw-r--r--spec/lib/sidebars/projects/menus/monitor_menu_spec.rb14
-rw-r--r--spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb25
-rw-r--r--spec/lib/sidebars/projects/menus/scope_menu_spec.rb5
-rw-r--r--spec/lib/sidebars/projects/super_sidebar_panel_spec.rb8
-rw-r--r--spec/lib/sidebars/search/panel_spec.rb7
-rw-r--r--spec/lib/sidebars/static_menu_spec.rb4
-rw-r--r--spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb5
-rw-r--r--spec/lib/sidebars/user_profile/panel_spec.rb7
-rw-r--r--spec/lib/sidebars/user_settings/panel_spec.rb3
-rw-r--r--spec/lib/sidebars/your_work/menus/organizations_menu_spec.rb42
-rw-r--r--spec/lib/sidebars/your_work/panel_spec.rb3
-rw-r--r--spec/lib/system_check/app/table_truncate_check_spec.rb75
-rw-r--r--spec/lib/unnested_in_filters/rewriter_spec.rb251
-rw-r--r--spec/lib/users/internal_spec.rb97
-rw-r--r--spec/mailers/emails/in_product_marketing_spec.rb69
-rw-r--r--spec/mailers/emails/profile_spec.rb73
-rw-r--r--spec/mailers/emails/service_desk_spec.rb90
-rw-r--r--spec/mailers/notify_spec.rb72
-rw-r--r--spec/migrations/20230125093723_rebalance_partition_id_ci_pipeline_spec.rb58
-rw-r--r--spec/migrations/20230125093840_rebalance_partition_id_ci_build_spec.rb58
-rw-r--r--spec/migrations/20230208100917_fix_partition_ids_for_ci_pipeline_variable_spec.rb58
-rw-r--r--spec/migrations/20230208103009_fix_partition_ids_for_ci_job_artifact_spec.rb58
-rw-r--r--spec/migrations/20230208132608_fix_partition_ids_for_ci_stage_spec.rb58
-rw-r--r--spec/migrations/20230209090702_fix_partition_ids_for_ci_build_report_result_spec.rb60
-rw-r--r--spec/migrations/20230209092204_fix_partition_ids_for_ci_build_trace_metadata_spec.rb60
-rw-r--r--spec/migrations/20230209140102_fix_partition_ids_for_ci_build_metadata_spec.rb60
-rw-r--r--spec/migrations/20230214122717_fix_partition_ids_for_ci_job_variables_spec.rb51
-rw-r--r--spec/migrations/20230214154101_fix_partition_ids_on_ci_sources_pipelines_spec.rb45
-rw-r--r--spec/migrations/20230726142555_ensure_notes_bigint_backfill_is_finished_for_self_managed_spec.rb35
-rw-r--r--spec/migrations/20230726144458_swap_notes_id_to_bigint_for_self_managed_spec.rb120
-rw-r--r--spec/migrations/20230802212443_add_current_user_todos_widget_to_epic_work_item_type_spec.rb25
-rw-r--r--spec/migrations/20230809170822_ensure_system_note_metadata_bigint_backfill_is_finished_for_self_managed_spec.rb35
-rw-r--r--spec/migrations/20230809174702_swap_system_note_metadata_note_id_to_bigint_for_self_managed_spec.rb121
-rw-r--r--spec/migrations/20230809203254_ensure_issue_user_mentions_bigint_backfill_is_finished_for_self_managed_spec.rb35
-rw-r--r--spec/migrations/20230809210550_swap_issue_user_mentions_note_id_to_bigint_for_self_managed_spec.rb127
-rw-r--r--spec/migrations/20230810113227_swap_note_diff_files_note_id_to_bigint_for_self_hosts_spec.rb156
-rw-r--r--spec/migrations/20230810124545_schedule_fixing_namespace_ids_of_vulnerability_reads_spec.rb27
-rw-r--r--spec/migrations/20230811103457_queue_backfill_nuget_normalized_version_spec.rb26
-rw-r--r--spec/migrations/20230815140656_queue_populate_denormalized_columns_for_sbom_occurrences_spec.rb26
-rw-r--r--spec/migrations/20230815160428_rename_plans_titles_with_legacy_plan_names_spec.rb23
-rw-r--r--spec/migrations/20230816152540_ensure_dum_note_id_bigint_backfill_is_finished_for_self_managed_spec.rb36
-rw-r--r--spec/migrations/20230816152639_swap_design_user_mentions_note_id_to_big_int_for_self_managed_spec.rb122
-rw-r--r--spec/migrations/20230817111938_swap_events_target_id_to_bigint_for_self_hosts_spec.rb121
-rw-r--r--spec/migrations/20230817143637_swap_award_emoji_note_id_to_bigint_for_self_hosts_spec.rb121
-rw-r--r--spec/migrations/20230818083610_queue_backfill_users_with_defaults_spec.rb27
-rw-r--r--spec/migrations/20230818085219_queue_backfill_user_preferences_with_defaults_spec.rb27
-rw-r--r--spec/migrations/20230818142801_queue_create_compliance_standards_adherence_spec.rb50
-rw-r--r--spec/migrations/20230821081603_queue_convert_credit_card_validation_data_to_hashes_spec.rb26
-rw-r--r--spec/migrations/20230822104028_delete_project_callout_three_spec.rb21
-rw-r--r--spec/migrations/20230822151454_remove_free_user_cap_email_workers_spec.rb24
-rw-r--r--spec/migrations/20230823090001_queue_backfill_project_statistics_storage_size_with_recent_size_spec.rb26
-rw-r--r--spec/migrations/20230823140934_add_linked_items_widget_to_ticket_work_item_type_spec.rb29
-rw-r--r--spec/migrations/20230830121830_queue_update_users_set_external_if_service_account_spec.rb26
-rw-r--r--spec/migrations/20230831084632_queue_sync_scan_result_policies_spec.rb26
-rw-r--r--spec/migrations/20230906204934_restart_self_hosted_sent_notifications_bigint_conversion_spec.rb144
-rw-r--r--spec/migrations/20230906204935_restart_self_hosted_sent_notifications_backfill_spec.rb162
-rw-r--r--spec/migrations/20230907155247_queue_backfill_has_merge_request_of_vulnerability_reads_spec.rb26
-rw-r--r--spec/migrations/backfill_alert_management_prometheus_integrations_spec.rb126
-rw-r--r--spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_self_managed_spec.rb35
-rw-r--r--spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_for_self_managed_spec.rb135
-rw-r--r--spec/models/ability_spec.rb5
-rw-r--r--spec/models/abuse_report_spec.rb27
-rw-r--r--spec/models/active_session_spec.rb18
-rw-r--r--spec/models/alert_management/http_integration_spec.rb2
-rw-r--r--spec/models/alerting/project_alerting_setting_spec.rb29
-rw-r--r--spec/models/analytics/cycle_analytics/runtime_limiter_spec.rb55
-rw-r--r--spec/models/application_setting_spec.rb12
-rw-r--r--spec/models/award_emoji_spec.rb33
-rw-r--r--spec/models/bulk_imports/entity_spec.rb8
-rw-r--r--spec/models/ci/build_spec.rb179
-rw-r--r--spec/models/ci/catalog/listing_spec.rb12
-rw-r--r--spec/models/ci/catalog/resource_spec.rb6
-rw-r--r--spec/models/ci/catalog/resources/component_spec.rb2
-rw-r--r--spec/models/ci/runner_spec.rb7
-rw-r--r--spec/models/clusters/agent_token_spec.rb39
-rw-r--r--spec/models/commit_status_spec.rb40
-rw-r--r--spec/models/concerns/as_cte_spec.rb2
-rw-r--r--spec/models/concerns/each_batch_spec.rb20
-rw-r--r--spec/models/concerns/expirable_spec.rb7
-rw-r--r--spec/models/concerns/has_user_type_spec.rb80
-rw-r--r--spec/models/concerns/issuable_spec.rb31
-rw-r--r--spec/models/concerns/prometheus_adapter_spec.rb22
-rw-r--r--spec/models/concerns/require_email_verification_spec.rb2
-rw-r--r--spec/models/concerns/resolvable_discussion_spec.rb8
-rw-r--r--spec/models/concerns/routable_spec.rb71
-rw-r--r--spec/models/concerns/transitionable_spec.rb40
-rw-r--r--spec/models/deploy_key_spec.rb2
-rw-r--r--spec/models/design_management/design_spec.rb10
-rw-r--r--spec/models/doorkeeper/application_spec.rb11
-rw-r--r--spec/models/environment_status_spec.rb12
-rw-r--r--spec/models/group_spec.rb21
-rw-r--r--spec/models/hooks/web_hook_log_spec.rb38
-rw-r--r--spec/models/integration_spec.rb6
-rw-r--r--spec/models/integrations/base_chat_notification_spec.rb21
-rw-r--r--spec/models/integrations/chat_message/deployment_message_spec.rb36
-rw-r--r--spec/models/integrations/confluence_spec.rb6
-rw-r--r--spec/models/integrations/mattermost_spec.rb2
-rw-r--r--spec/models/integrations/prometheus_spec.rb28
-rw-r--r--spec/models/integrations/shimo_spec.rb8
-rw-r--r--spec/models/integrations/slack_spec.rb2
-rw-r--r--spec/models/integrations/zentao_spec.rb8
-rw-r--r--spec/models/issue_spec.rb7
-rw-r--r--spec/models/loose_foreign_keys/modification_tracker_spec.rb14
-rw-r--r--spec/models/loose_foreign_keys/turbo_modification_tracker_spec.rb23
-rw-r--r--spec/models/member_spec.rb7
-rw-r--r--spec/models/members/group_member_spec.rb16
-rw-r--r--spec/models/merge_request_spec.rb160
-rw-r--r--spec/models/metrics/dashboard/annotation_spec.rb73
-rw-r--r--spec/models/metrics/users_starred_dashboard_spec.rb39
-rw-r--r--spec/models/ml/model_version_spec.rb10
-rw-r--r--spec/models/namespace_spec.rb326
-rw-r--r--spec/models/note_spec.rb111
-rw-r--r--spec/models/notification_setting_spec.rb7
-rw-r--r--spec/models/oauth_access_token_spec.rb6
-rw-r--r--spec/models/organizations/organization_spec.rb1
-rw-r--r--spec/models/packages/dependency_link_spec.rb68
-rw-r--r--spec/models/packages/ml_model/package_spec.rb67
-rw-r--r--spec/models/packages/nuget/metadatum_spec.rb23
-rw-r--r--spec/models/packages/nuget/symbol_spec.rb70
-rw-r--r--spec/models/packages/package_spec.rb43
-rw-r--r--spec/models/packages/protection/rule_spec.rb40
-rw-r--r--spec/models/pages/virtual_domain_spec.rb53
-rw-r--r--spec/models/pages_deployment_spec.rb51
-rw-r--r--spec/models/pages_domain_spec.rb11
-rw-r--r--spec/models/performance_monitoring/prometheus_metric_spec.rb67
-rw-r--r--spec/models/performance_monitoring/prometheus_panel_group_spec.rb62
-rw-r--r--spec/models/performance_monitoring/prometheus_panel_spec.rb85
-rw-r--r--spec/models/plan_spec.rb12
-rw-r--r--spec/models/pool_repository_spec.rb46
-rw-r--r--spec/models/project_authorization_spec.rb37
-rw-r--r--spec/models/project_authorizations/changes_spec.rb10
-rw-r--r--spec/models/project_ci_cd_setting_spec.rb2
-rw-r--r--spec/models/project_feature_spec.rb20
-rw-r--r--spec/models/project_import_state_spec.rb8
-rw-r--r--spec/models/project_metrics_setting_spec.rb63
-rw-r--r--spec/models/project_spec.rb113
-rw-r--r--spec/models/repository_spec.rb31
-rw-r--r--spec/models/resource_label_event_spec.rb17
-rw-r--r--spec/models/resource_state_event_spec.rb16
-rw-r--r--spec/models/review_spec.rb19
-rw-r--r--spec/models/route_spec.rb10
-rw-r--r--spec/models/snippet_repository_spec.rb2
-rw-r--r--spec/models/user_custom_attribute_spec.rb29
-rw-r--r--spec/models/user_preference_spec.rb14
-rw-r--r--spec/models/user_spec.rb125
-rw-r--r--spec/models/users/credit_card_validation_spec.rb143
-rw-r--r--spec/models/users/group_visit_spec.rb25
-rw-r--r--spec/models/users/project_visit_spec.rb25
-rw-r--r--spec/models/work_item_spec.rb81
-rw-r--r--spec/models/work_items/related_work_item_link_spec.rb40
-rw-r--r--spec/models/work_items/widgets/description_spec.rb2
-rw-r--r--spec/models/work_items/widgets/linked_items_spec.rb4
-rw-r--r--spec/models/x509_certificate_spec.rb1
-rw-r--r--spec/models/x509_issuer_spec.rb2
-rw-r--r--spec/policies/ci/bridge_policy_spec.rb34
-rw-r--r--spec/policies/ci/pipeline_policy_spec.rb25
-rw-r--r--spec/policies/global_policy_spec.rb16
-rw-r--r--spec/policies/group_policy_spec.rb22
-rw-r--r--spec/policies/issue_policy_spec.rb4
-rw-r--r--spec/policies/organizations/organization_policy_spec.rb14
-rw-r--r--spec/policies/packages/policies/project_policy_spec.rb2
-rw-r--r--spec/policies/project_policy_spec.rb4
-rw-r--r--spec/presenters/blob_presenter_spec.rb12
-rw-r--r--spec/presenters/event_presenter_spec.rb100
-rw-r--r--spec/presenters/gitlab/blame_presenter_spec.rb29
-rw-r--r--spec/presenters/issue_presenter_spec.rb2
-rw-r--r--spec/presenters/packages/composer/packages_presenter_spec.rb2
-rw-r--r--spec/presenters/projects/security/configuration_presenter_spec.rb3
-rw-r--r--spec/presenters/snippet_blob_presenter_spec.rb2
-rw-r--r--spec/rake_helper.rb2
-rw-r--r--spec/requests/admin/abuse_reports_controller_spec.rb79
-rw-r--r--spec/requests/admin/users_controller_spec.rb23
-rw-r--r--spec/requests/api/bulk_imports_spec.rb24
-rw-r--r--spec/requests/api/ci/jobs_spec.rb8
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb61
-rw-r--r--spec/requests/api/commit_statuses_spec.rb30
-rw-r--r--spec/requests/api/commits_spec.rb2
-rw-r--r--spec/requests/api/discussions_spec.rb11
-rw-r--r--spec/requests/api/feature_flags_spec.rb162
-rw-r--r--spec/requests/api/features_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/jobs_spec.rb103
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb166
-rw-r--r--spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb20
-rw-r--r--spec/requests/api/graphql/ci/runners_spec.rb10
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb5
-rw-r--r--spec/requests/api/graphql/group/work_item_spec.rb71
-rw-r--r--spec/requests/api/graphql/group/work_items_spec.rb32
-rw-r--r--spec/requests/api/graphql/group_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/groups_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/jobs_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb185
-rw-r--r--spec/requests/api/graphql/mutations/admin/abuse_report_labels/create_spec.rb55
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_schedule/create_spec.rb25
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_schedule/delete_spec.rb23
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_schedule/play_spec.rb23
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_schedule/update_spec.rb25
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_trigger/create_spec.rb23
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/update_spec.rb32
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb41
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb22
-rw-r--r--spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb9
-rw-r--r--spec/requests/api/graphql/mutations/work_items/linked_items/remove_spec.rb120
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_spec.rb14
-rw-r--r--spec/requests/api/graphql/organizations/organization_query_spec.rb178
-rw-r--r--spec/requests/api/graphql/packages/package_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/merge_request_spec.rb7
-rw-r--r--spec/requests/api/graphql/project/runners_spec.rb14
-rw-r--r--spec/requests/api/graphql/project/work_items_spec.rb38
-rw-r--r--spec/requests/api/graphql/project_query_spec.rb18
-rw-r--r--spec/requests/api/graphql/work_item_spec.rb44
-rw-r--r--spec/requests/api/groups_spec.rb36
-rw-r--r--spec/requests/api/internal/base_spec.rb15
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb162
-rw-r--r--spec/requests/api/merge_requests_spec.rb28
-rw-r--r--spec/requests/api/metadata_spec.rb18
-rw-r--r--spec/requests/api/metrics/dashboard/annotations_spec.rb3
-rw-r--r--spec/requests/api/metrics/user_starred_dashboards_spec.rb5
-rw-r--r--spec/requests/api/ml/mlflow/experiments_spec.rb4
-rw-r--r--spec/requests/api/ml/mlflow/runs_spec.rb138
-rw-r--r--spec/requests/api/npm_group_packages_spec.rb43
-rw-r--r--spec/requests/api/npm_instance_packages_spec.rb29
-rw-r--r--spec/requests/api/nuget_project_packages_spec.rb68
-rw-r--r--spec/requests/api/project_attributes.yml3
-rw-r--r--spec/requests/api/project_import_spec.rb10
-rw-r--r--spec/requests/api/project_packages_spec.rb6
-rw-r--r--spec/requests/api/projects_spec.rb8
-rw-r--r--spec/requests/api/search_spec.rb45
-rw-r--r--spec/requests/api/settings_spec.rb6
-rw-r--r--spec/requests/api/usage_data_queries_spec.rb6
-rw-r--r--spec/requests/api/users_spec.rb47
-rw-r--r--spec/requests/clusters/agents/dashboard_controller_spec.rb76
-rw-r--r--spec/requests/content_security_policy_spec.rb29
-rw-r--r--spec/requests/groups/email_campaigns_controller_spec.rb127
-rw-r--r--spec/requests/groups/settings/access_tokens_controller_spec.rb22
-rw-r--r--spec/requests/groups/work_items_controller_spec.rb44
-rw-r--r--spec/requests/openid_connect_spec.rb2
-rw-r--r--spec/requests/organizations/organizations_controller_spec.rb70
-rw-r--r--spec/requests/projects/noteable_notes_spec.rb78
-rw-r--r--spec/requests/projects/settings/access_tokens_controller_spec.rb22
-rw-r--r--spec/requests/projects/tracing_controller_spec.rb104
-rw-r--r--spec/requests/rack_attack_global_spec.rb114
-rw-r--r--spec/requests/search_controller_spec.rb1
-rw-r--r--spec/requests/sessions_spec.rb42
-rw-r--r--spec/requests/users/namespace_visits_controller_spec.rb72
-rw-r--r--spec/requests/verifies_with_email_spec.rb6
-rw-r--r--spec/routing/organizations/organizations_controller_routing_spec.rb10
-rw-r--r--spec/rubocop/cop/capybara/testid_finders_spec.rb50
-rw-r--r--spec/rubocop/cop/lint/last_keyword_argument_spec.rb168
-rw-r--r--spec/rubocop/cop/migration/versioned_migration_class_spec.rb9
-rw-r--r--spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb2
-rw-r--r--spec/scripts/trigger-build_spec.rb12
-rw-r--r--spec/serializers/activity_pub/activity_streams_serializer_spec.rb157
-rw-r--r--spec/serializers/activity_pub/project_entity_spec.rb32
-rw-r--r--spec/serializers/activity_pub/release_entity_spec.rb48
-rw-r--r--spec/serializers/activity_pub/releases_actor_entity_spec.rb39
-rw-r--r--spec/serializers/activity_pub/releases_actor_serializer_spec.rb16
-rw-r--r--spec/serializers/activity_pub/releases_outbox_serializer_spec.rb34
-rw-r--r--spec/serializers/activity_pub/user_entity_spec.rb28
-rw-r--r--spec/serializers/admin/abuse_report_details_entity_spec.rb113
-rw-r--r--spec/serializers/admin/abuse_report_details_serializer_spec.rb5
-rw-r--r--spec/serializers/admin/abuse_report_entity_spec.rb15
-rw-r--r--spec/serializers/admin/reported_content_entity_spec.rb50
-rw-r--r--spec/serializers/build_details_entity_spec.rb16
-rw-r--r--spec/serializers/ci/job_annotation_entity_spec.rb30
-rw-r--r--spec/serializers/codequality_degradation_entity_spec.rb17
-rw-r--r--spec/serializers/codequality_reports_comparer_serializer_spec.rb4
-rw-r--r--spec/serializers/deployment_entity_spec.rb89
-rw-r--r--spec/serializers/import/github_realtime_repo_entity_spec.rb4
-rw-r--r--spec/serializers/import/github_realtime_repo_serializer_spec.rb2
-rw-r--r--spec/serializers/profile/event_entity_spec.rb11
-rw-r--r--spec/services/admin/abuse_report_labels/create_service_spec.rb51
-rw-r--r--spec/services/admin/abuse_reports/moderate_user_service_spec.rb17
-rw-r--r--spec/services/admin/abuse_reports/update_service_spec.rb85
-rw-r--r--spec/services/application_settings/update_service_spec.rb8
-rw-r--r--spec/services/auto_merge/base_service_spec.rb5
-rw-r--r--spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb176
-rw-r--r--spec/services/bulk_imports/create_service_spec.rb22
-rw-r--r--spec/services/bulk_imports/file_download_service_spec.rb14
-rw-r--r--spec/services/ci/components/fetch_service_spec.rb37
-rw-r--r--spec/services/ci/create_commit_status_service_spec.rb461
-rw-r--r--spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb17
-rw-r--r--spec/services/ci/create_pipeline_service/environment_spec.rb22
-rw-r--r--spec/services/ci/create_pipeline_service/logger_spec.rb69
-rw-r--r--spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb32
-rw-r--r--spec/services/ci/create_pipeline_service/rules_spec.rb40
-rw-r--r--spec/services/ci/create_pipeline_service/variables_spec.rb33
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb174
-rw-r--r--spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb14
-rw-r--r--spec/services/ci/register_job_service_spec.rb15
-rw-r--r--spec/services/ci/runners/set_runner_associated_projects_service_spec.rb4
-rw-r--r--spec/services/concerns/rate_limited_service_spec.rb2
-rw-r--r--spec/services/concerns/services/return_service_responses_spec.rb32
-rw-r--r--spec/services/deployments/update_environment_service_spec.rb21
-rw-r--r--spec/services/design_management/delete_designs_service_spec.rb8
-rw-r--r--spec/services/design_management/save_designs_service_spec.rb27
-rw-r--r--spec/services/discussions/resolve_service_spec.rb8
-rw-r--r--spec/services/draft_notes/publish_service_spec.rb9
-rw-r--r--spec/services/environments/stop_service_spec.rb3
-rw-r--r--spec/services/environments/stop_stale_service_spec.rb6
-rw-r--r--spec/services/files/delete_service_spec.rb7
-rw-r--r--spec/services/files/update_service_spec.rb6
-rw-r--r--spec/services/git/branch_push_service_spec.rb24
-rw-r--r--spec/services/google_cloud/create_cloudsql_instance_service_spec.rb30
-rw-r--r--spec/services/google_cloud/fetch_google_ip_list_service_spec.rb2
-rw-r--r--spec/services/google_cloud/generate_pipeline_service_spec.rb48
-rw-r--r--spec/services/google_cloud/get_cloudsql_instances_service_spec.rb38
-rw-r--r--spec/services/gpg_keys/destroy_service_spec.rb22
-rw-r--r--spec/services/groups/destroy_service_spec.rb11
-rw-r--r--spec/services/groups/group_links/create_service_spec.rb3
-rw-r--r--spec/services/groups/update_service_spec.rb72
-rw-r--r--spec/services/import_export_clean_up_service_spec.rb16
-rw-r--r--spec/services/incident_management/incidents/create_service_spec.rb2
-rw-r--r--spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb4
-rw-r--r--spec/services/issuable/process_assignees_spec.rb80
-rw-r--r--spec/services/issue_links/destroy_service_spec.rb9
-rw-r--r--spec/services/issue_links/list_service_spec.rb55
-rw-r--r--spec/services/issues/close_service_spec.rb4
-rw-r--r--spec/services/issues/create_service_spec.rb8
-rw-r--r--spec/services/issues/export_csv_service_spec.rb32
-rw-r--r--spec/services/issues/move_service_spec.rb3
-rw-r--r--spec/services/issues/resolve_discussions_spec.rb26
-rw-r--r--spec/services/issues/update_service_spec.rb13
-rw-r--r--spec/services/labels/available_labels_service_spec.rb24
-rw-r--r--spec/services/labels/update_service_spec.rb8
-rw-r--r--spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb20
-rw-r--r--spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb4
-rw-r--r--spec/services/members/invitation_reminder_email_service_spec.rb2
-rw-r--r--spec/services/merge_requests/approval_service_spec.rb45
-rw-r--r--spec/services/merge_requests/base_service_spec.rb28
-rw-r--r--spec/services/merge_requests/create_ref_service_spec.rb183
-rw-r--r--spec/services/merge_requests/ff_merge_service_spec.rb144
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb895
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb7
-rw-r--r--spec/services/merge_requests/update_service_spec.rb52
-rw-r--r--spec/services/metrics/global_metrics_update_service_spec.rb14
-rw-r--r--spec/services/metrics/sample_metrics_service_spec.rb45
-rw-r--r--spec/services/namespaces/in_product_marketing_emails_service_spec.rb216
-rw-r--r--spec/services/note_summary_spec.rb9
-rw-r--r--spec/services/notes/create_service_spec.rb5
-rw-r--r--spec/services/notes/destroy_service_spec.rb7
-rw-r--r--spec/services/notes/quick_actions_service_spec.rb39
-rw-r--r--spec/services/notes/update_service_spec.rb12
-rw-r--r--spec/services/notification_service_spec.rb134
-rw-r--r--spec/services/packages/ml_model/create_package_file_service_spec.rb4
-rw-r--r--spec/services/packages/npm/generate_metadata_service_spec.rb11
-rw-r--r--spec/services/packages/nuget/check_duplicates_service_spec.rb155
-rw-r--r--spec/services/packages/nuget/extract_metadata_file_service_spec.rb14
-rw-r--r--spec/services/packages/nuget/extract_remote_metadata_file_service_spec.rb126
-rw-r--r--spec/services/packages/nuget/metadata_extraction_service_spec.rb4
-rw-r--r--spec/services/packages/nuget/odata_package_entry_service_spec.rb69
-rw-r--r--spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb24
-rw-r--r--spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb3
-rw-r--r--spec/services/preview_markdown_service_spec.rb21
-rw-r--r--spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb19
-rw-r--r--spec/services/projects/create_service_spec.rb26
-rw-r--r--spec/services/projects/import_service_spec.rb102
-rw-r--r--spec/services/projects/in_product_marketing_campaign_emails_service_spec.rb54
-rw-r--r--spec/services/projects/prometheus/alerts/notify_service_spec.rb4
-rw-r--r--spec/services/projects/update_pages_service_spec.rb128
-rw-r--r--spec/services/projects/update_repository_storage_service_spec.rb47
-rw-r--r--spec/services/projects/update_service_spec.rb74
-rw-r--r--spec/services/protected_branches/api_service_spec.rb20
-rw-r--r--spec/services/push_event_payload_service_spec.rb4
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb33
-rw-r--r--spec/services/releases/create_service_spec.rb2
-rw-r--r--spec/services/releases/destroy_service_spec.rb28
-rw-r--r--spec/services/resource_access_tokens/revoke_service_spec.rb3
-rw-r--r--spec/services/resource_events/change_labels_service_spec.rb12
-rw-r--r--spec/services/resource_events/merge_into_notes_service_spec.rb3
-rw-r--r--spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb2
-rw-r--r--spec/services/security/merge_reports_service_spec.rb105
-rw-r--r--spec/services/service_desk/custom_email_verifications/create_service_spec.rb23
-rw-r--r--spec/services/service_desk/custom_email_verifications/update_service_spec.rb34
-rw-r--r--spec/services/service_desk/custom_emails/create_service_spec.rb13
-rw-r--r--spec/services/service_desk/custom_emails/destroy_service_spec.rb7
-rw-r--r--spec/services/service_desk_settings/update_service_spec.rb25
-rw-r--r--spec/services/spam/spam_action_service_spec.rb11
-rw-r--r--spec/services/system_notes/alert_management_service_spec.rb4
-rw-r--r--spec/services/system_notes/issuables_service_spec.rb13
-rw-r--r--spec/services/system_notes/time_tracking_service_spec.rb21
-rw-r--r--spec/services/users/authorized_build_service_spec.rb8
-rw-r--r--spec/services/users/build_service_spec.rb51
-rw-r--r--spec/services/users/migrate_records_to_ghost_user_service_spec.rb10
-rw-r--r--spec/services/users/upsert_credit_card_validation_service_spec.rb11
-rw-r--r--spec/services/work_items/related_work_item_links/destroy_service_spec.rb82
-rw-r--r--spec/services/work_items/update_service_spec.rb5
-rw-r--r--spec/spec_helper.rb48
-rw-r--r--spec/support/before_all_adapter.rb11
-rw-r--r--spec/support/capybara.rb6
-rw-r--r--spec/support/capybara_wait_for_all_requests.rb20
-rw-r--r--spec/support/database/auto_explain.rb15
-rw-r--r--spec/support/database/click_house/hooks.rb8
-rw-r--r--spec/support/database/prevent_cross_database_modification.rb48
-rw-r--r--spec/support/database_cleaner.rb10
-rw-r--r--spec/support/db_cleaner.rb3
-rw-r--r--spec/support/factory_bot.rb14
-rw-r--r--spec/support/finder_collection_allowlist.yml6
-rw-r--r--spec/support/gitlab_stubs/gitlab_ci_dast_includes.yml7
-rw-r--r--spec/support/helpers/database/duplicate_indexes.rb77
-rw-r--r--spec/support/helpers/database/duplicate_indexes.yml265
-rw-r--r--spec/support/helpers/features/admin_users_helpers.rb2
-rw-r--r--spec/support/helpers/features/highlight_content_helper.rb19
-rw-r--r--spec/support/helpers/features/runners_helpers.rb10
-rw-r--r--spec/support/helpers/filtered_search_helpers.rb2
-rw-r--r--spec/support/helpers/loose_foreign_keys_helper.rb11
-rw-r--r--spec/support/helpers/sign_up_helpers.rb27
-rw-r--r--spec/support/helpers/stub_gitlab_calls.rb14
-rw-r--r--spec/support/helpers/x509_helpers.rb181
-rw-r--r--spec/support/matchers/pagination_matcher.rb10
-rw-r--r--spec/support/migration.rb14
-rw-r--r--spec/support/multiple_databases.rb2
-rw-r--r--spec/support/protected_branch_helpers.rb2
-rw-r--r--spec/support/rspec.rb10
-rw-r--r--spec/support/rspec_order_todo.yml17
-rw-r--r--spec/support/shared_contexts/dependency_proxy_shared_context.rb14
-rw-r--r--spec/support/shared_contexts/email_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb4
-rw-r--r--spec/support/shared_contexts/finders/users_finder_shared_contexts.rb2
-rw-r--r--spec/support/shared_contexts/lib/gitlab/database/load_balancing/wal_tracking_shared_context.rb8
-rw-r--r--spec/support/shared_contexts/navbar_structure_context.rb20
-rw-r--r--spec/support/shared_contexts/policies/group_policy_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb2
-rw-r--r--spec/support/shared_examples/channels/noteable/notes_channel_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/ci/create_pipeline_service_environment_shared_examples.rb166
-rw-r--r--spec/support/shared_examples/ci/deployable_shared_examples.rb56
-rw-r--r--spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb17
-rw-r--r--spec/support/shared_examples/controllers/labels_controller_shared_examples.rb38
-rw-r--r--spec/support/shared_examples/controllers/search_rate_limit_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb2
-rw-r--r--spec/support/shared_examples/features/2fa_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/content_editor_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb4
-rw-r--r--spec/support/shared_examples/features/runners_shared_examples.rb18
-rw-r--r--spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/features/snippets_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/features/variable_list_shared_examples.rb34
-rw-r--r--spec/support/shared_examples/features/work_items_shared_examples.rb39
-rw-r--r--spec/support/shared_examples/finders/issues_finder_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/graphql/mutations/update_time_estimate_shared_examples.rb20
-rw-r--r--spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/harbor/artifacts_controller_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/harbor/repositories_controller_shared_examples.rb24
-rw-r--r--spec/support/shared_examples/harbor/tags_controller_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb45
-rw-r--r--spec/support/shared_examples/lib/gitlab/bitbucket_import/object_import_shared_examples.rb100
-rw-r--r--spec/support/shared_examples/lib/gitlab/bitbucket_import/stage_methods_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb37
-rw-r--r--spec/support/shared_examples/lib/gitlab/import/advance_stage_shared_examples.rb109
-rw-r--r--spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb33
-rw-r--r--spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb87
-rw-r--r--spec/support/shared_examples/lib/menus_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb14
-rw-r--r--spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb6
-rw-r--r--spec/support/shared_examples/mailers/notify_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb107
-rw-r--r--spec/support/shared_examples/models/concerns/linkable_items_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/models/group_shared_examples.rb45
-rw-r--r--spec/support/shared_examples/models/members_notifications_shared_example.rb8
-rw-r--r--spec/support/shared_examples/models/users/pages_visits_shared_examples.rb27
-rw-r--r--spec/support/shared_examples/redis/redis_shared_examples.rb84
-rw-r--r--spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb33
-rw-r--r--spec/support/shared_examples/requests/api/graphql/work_item_list_shared_examples.rb98
-rw-r--r--spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb15
-rw-r--r--spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb69
-rw-r--r--spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb42
-rw-r--r--spec/support/shared_examples/requests/api_keyset_pagination_shared_examples.rb50
-rw-r--r--spec/support/shared_examples/requests/rack_attack_shared_examples.rb38
-rw-r--r--spec/support/shared_examples/services/incident_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/issuable/issuable_update_service_shared_examples.rb71
-rw-r--r--spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb193
-rw-r--r--spec/support/shared_examples/services/migrate_to_ghost_user_service_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/pages_size_limit_shared_examples.rb32
-rw-r--r--spec/support/shared_examples/services/protected_branches_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/services/users/build_service_shared_examples.rb51
-rw-r--r--spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/users/pages_visits_shared_examples.rb63
-rw-r--r--spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb36
-rw-r--r--spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb21
-rw-r--r--spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb22
-rw-r--r--spec/support/sidekiq.rb2
-rw-r--r--spec/support_specs/capybara_wait_for_all_requests_spec.rb16
-rw-r--r--spec/support_specs/database/duplicate_indexes_spec.rb108
-rw-r--r--spec/support_specs/database/multiple_databases_helpers_spec.rb2
-rw-r--r--spec/support_specs/helpers/redis_commands/recorder_spec.rb6
-rw-r--r--spec/tasks/gitlab/audit_event_types/check_docs_task_spec.rb12
-rw-r--r--spec/tasks/gitlab/audit_event_types/compile_docs_task_spec.rb8
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb24
-rw-r--r--spec/tasks/gitlab/ci_secure_files/check_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/ci_secure_files/migrate_rake_spec.rb4
-rw-r--r--spec/tasks/gitlab/container_registry_rake_spec.rb4
-rw-r--r--spec/tasks/gitlab/db/cells/bump_cell_sequences_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/db/decomposition/connection_status_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/db/decomposition/rollback/bump_ci_sequences_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/db/lock_writes_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/db/migration_fix_15_11_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/db/truncate_legacy_tables_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/db/validate_config_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/db_rake_spec.rb32
-rw-r--r--spec/tasks/gitlab/dependency_proxy/migrate_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/generate_sample_prometheus_data_rake_spec.rb34
-rw-r--r--spec/tasks/gitlab/gitaly_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/lfs/migrate_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/packages/migrate_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/password_rake_spec.rb4
-rw-r--r--spec/tasks/gitlab/refresh_project_statistics_build_artifacts_size_rake_spec.rb6
-rw-r--r--spec/tasks/gitlab/snippets_rake_spec.rb6
-rw-r--r--spec/tasks/gitlab/terraform/migrate_rake_spec.rb4
-rw-r--r--spec/tasks/gitlab/web_hook_rake_spec.rb8
-rw-r--r--spec/tasks/gitlab/workhorse_rake_spec.rb2
-rw-r--r--spec/tasks/gitlab/x509/update_rake_spec.rb2
-rw-r--r--spec/tasks/migrate/schema_check_rake_spec.rb2
-rw-r--r--spec/tooling/danger/clickhouse_spec.rb70
-rw-r--r--spec/tooling/danger/ignored_model_columns_spec.rb145
-rw-r--r--spec/tooling/fixtures/cleanup_conversion_migration.txt44
-rw-r--r--spec/tooling/fixtures/remove_column_migration.txt84
-rw-r--r--spec/tooling/fixtures/rename_column_migration.txt45
-rw-r--r--spec/uploaders/packages/nuget/symbol_uploader_spec.rb28
-rw-r--r--spec/views/admin/application_settings/general.html.haml_spec.rb1
-rw-r--r--spec/views/admin/identities/index.html.haml_spec.rb9
-rw-r--r--spec/views/devise/shared/_signin_box.html.haml_spec.rb2
-rw-r--r--spec/views/devise/shared/_signup_omniauth_provider_list_spec.rb50
-rw-r--r--spec/views/events/event/_push.html.haml_spec.rb13
-rw-r--r--spec/views/layouts/_page.html.haml_spec.rb38
-rw-r--r--spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb4
-rw-r--r--spec/views/layouts/organization.html.haml_spec.rb59
-rw-r--r--spec/views/layouts/snippets.html.haml_spec.rb2
-rw-r--r--spec/views/projects/empty.html.haml_spec.rb2
-rw-r--r--spec/views/projects/issues/service_desk/_issue.html.haml_spec.rb2
-rw-r--r--spec/views/projects/pages/_pages_settings.html.haml_spec.rb30
-rw-r--r--spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb49
-rw-r--r--spec/views/registrations/welcome/show.html.haml_spec.rb1
-rw-r--r--spec/workers/bulk_import_worker_spec.rb169
-rw-r--r--spec/workers/bulk_imports/finish_project_import_worker_spec.rb28
-rw-r--r--spec/workers/bulk_imports/pipeline_batch_worker_spec.rb10
-rw-r--r--spec/workers/click_house/events_sync_worker_spec.rb145
-rw-r--r--spec/workers/concerns/gitlab/github_import/object_importer_spec.rb3
-rw-r--r--spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb2
-rw-r--r--spec/workers/concerns/gitlab/import/notify_upon_death_spec.rb51
-rw-r--r--spec/workers/concerns/gitlab/notify_upon_death_spec.rb51
-rw-r--r--spec/workers/concerns/limited_capacity/worker_spec.rb18
-rw-r--r--spec/workers/database/lock_tables_worker_spec.rb136
-rw-r--r--spec/workers/database/monitor_locked_tables_worker_spec.rb55
-rw-r--r--spec/workers/environments/stop_job_success_worker_spec.rb55
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb14
-rw-r--r--spec/workers/gitlab/bitbucket_import/advance_stage_worker_spec.rb115
-rw-r--r--spec/workers/gitlab/bitbucket_import/import_pull_request_worker_spec.rb9
-rw-r--r--spec/workers/gitlab/bitbucket_import/stage/finish_import_worker_spec.rb27
-rw-r--r--spec/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker_spec.rb77
-rw-r--r--spec/workers/gitlab/bitbucket_import/stage/import_repository_worker_spec.rb21
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/advance_stage_worker_spec.rb7
-rw-r--r--spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb6
-rw-r--r--spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb8
-rw-r--r--spec/workers/gitlab/github_import/advance_stage_worker_spec.rb112
-rw-r--r--spec/workers/gitlab/jira_import/advance_stage_worker_spec.rb7
-rw-r--r--spec/workers/gitlab/jira_import/import_issue_worker_spec.rb2
-rw-r--r--spec/workers/incident_management/close_incident_worker_spec.rb2
-rw-r--r--spec/workers/incident_management/process_alert_worker_v2_spec.rb4
-rw-r--r--spec/workers/loose_foreign_keys/cleanup_worker_spec.rb62
-rw-r--r--spec/workers/merge_requests/ensure_prepared_worker_spec.rb59
-rw-r--r--spec/workers/metrics/global_metrics_update_worker_spec.rb30
-rw-r--r--spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb32
-rw-r--r--spec/workers/new_merge_request_worker_spec.rb28
-rw-r--r--spec/workers/new_note_worker_spec.rb2
-rw-r--r--spec/workers/pages/invalidate_domain_cache_worker_spec.rb267
-rw-r--r--spec/workers/personal_access_tokens/expiring_worker_spec.rb27
-rw-r--r--spec/workers/post_receive_spec.rb2
-rw-r--r--spec/workers/projects/record_target_platforms_worker_spec.rb2
-rw-r--r--spec/workers/users/migrate_records_to_ghost_user_in_batches_worker_spec.rb4
-rw-r--r--spec/workers/users/track_namespace_visits_worker_spec.rb27
-rw-r--r--storybook/config/addons/make_container/index.js12
-rw-r--r--storybook/config/preview.js2
-rw-r--r--tooling/audit_events/docs/templates/audit_event_types.md.erb18
-rw-r--r--tooling/danger/clickhouse.rb11
-rw-r--r--tooling/danger/ignored_model_columns.rb76
-rw-r--r--tooling/danger/project_helper.rb4
-rw-r--r--tooling/danger/required_stops.rb3
-rw-r--r--vendor/assets/javascripts/vue-virtual-scroller/src/components/RecycleScroller.vue2
-rw-r--r--vendor/gems/mail-smtp_pool/.gitlab-ci.yml5
-rw-r--r--vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec2
-rw-r--r--vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb4
-rw-r--r--vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb2
-rw-r--r--vendor/gems/mail-smtp_pool/spec/spec_helper.rb67
-rw-r--r--vendor/project_templates/typo3_distribution.tar.gzbin77071 -> 76924 bytes
-rw-r--r--vite.config.js106
-rw-r--r--workhorse/config_test.go2
-rw-r--r--workhorse/gitaly_integration_test.go54
-rw-r--r--workhorse/gitaly_test.go17
-rw-r--r--workhorse/go.mod4
-rw-r--r--workhorse/go.sum6
-rw-r--r--workhorse/internal/config/config.go15
-rw-r--r--workhorse/internal/dependencyproxy/dependencyproxy.go73
-rw-r--r--workhorse/internal/dependencyproxy/dependencyproxy_test.go153
-rw-r--r--workhorse/internal/gitaly/gitaly.go35
-rw-r--r--workhorse/internal/gitaly/gitaly_test.go9
-rw-r--r--workhorse/internal/gitaly/namespace.go8
-rw-r--r--workhorse/internal/goredis/goredis.go186
-rw-r--r--workhorse/internal/goredis/goredis_test.go107
-rw-r--r--workhorse/internal/goredis/keywatcher.go236
-rw-r--r--workhorse/internal/goredis/keywatcher_test.go301
-rw-r--r--workhorse/internal/redis/keywatcher.go24
-rw-r--r--workhorse/internal/redis/redis.go12
-rw-r--r--workhorse/main.go37
-rw-r--r--workhorse/main_test.go20
-rw-r--r--workhorse/sendfile_test.go9
-rw-r--r--workhorse/upload_test.go8
-rw-r--r--yarn.lock1398
6566 files changed, 286847 insertions, 164992 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml
index dfb9e8f97eb..f98f7acc0ad 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -33,10 +33,6 @@ rules:
# consider. See
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89831.
- '^(ee|jh)_component/'
- # Disabled for now, to make the airbnb-base 12.1.0 -> 13.1.0 update smoother
- no-else-return:
- - error
- - allowElseIf: true
lines-between-class-members: off
# all offenses of no-jquery/no-animate-toggle are false positives ( $toast.show() )
no-jquery/no-animate-toggle: off
diff --git a/.gitignore b/.gitignore
index d6c6d41e3ca..914daba7994 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,6 +46,7 @@ eslint-report.html
/config/unicorn.rb
/config/puma.rb
/config/secrets.yml
+/config/session_store.yml
/config/sidekiq.yml
/config/click_house.yml
/config/registry.key
@@ -106,3 +107,10 @@ tags.lock
tags.temp
.stylelintcache
.solargraph.yml
+
+# Vite Ruby
+/public/vite*
+# Vite uses dotenv and suggests to ignore local-only env files. See
+# https://vitejs.dev/guide/env-and-mode.html#env-files
+*.local
+
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 050f5f41515..aa9c228648d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -37,6 +37,9 @@ default:
CREATE_RAILS_TEST_FAILURE_ISSUES: "true"
CREATE_RAILS_SLOW_TEST_ISSUES: "true"
+.default-merge-request-slow-tests-variables: &default-merge-request-slow-tests-variables
+ ADD_SLOW_TEST_NOTE_TO_MERGE_REQUEST: "true"
+
.if-merge-request-security-canonical-sync: &if-merge-request-security-canonical-sync
if: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == "gitlab-org/security/gitlab" && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
@@ -81,13 +84,13 @@ workflow:
- if: '$CI_MERGE_REQUEST_IID'
variables:
<<: *default-ruby-variables
+ <<: *default-merge-request-slow-tests-variables
PIPELINE_NAME: 'Ruby $RUBY_VERSION $CI_MERGE_REQUEST_EVENT_TYPE MR pipeline'
NO_SOURCEMAPS: 'true'
# For the scheduled pipelines, we set specific variables.
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule"'
variables:
- <<: *default-ruby-variables
- <<: *default-branch-pipeline-failure-variables
+ <<: [*default-ruby-variables, *default-branch-pipeline-failure-variables]
CRYSTALBALL: "true"
PIPELINE_NAME: 'Scheduled Ruby $RUBY_VERSION $CI_COMMIT_BRANCH branch pipeline'
# Run pipelines for ruby3_1 branch
@@ -99,15 +102,13 @@ workflow:
# when pipeline is triggered by a project access token.
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $GITLAB_USER_LOGIN =~ /project_\d+_bot\d*/'
variables:
- <<: *default-ruby-variables
- <<: *default-branch-pipeline-failure-variables
+ <<: [*default-ruby-variables, *default-branch-pipeline-failure-variables]
GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
PIPELINE_NAME: 'Ruby $RUBY_VERSION $CI_COMMIT_BRANCH branch pipeline (triggered by a project token)'
# For `$CI_DEFAULT_BRANCH` branch, create a pipeline (this includes on schedules, pushes, merges, etc.).
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
variables:
- <<: *default-ruby-variables
- <<: *default-branch-pipeline-failure-variables
+ <<: [*default-ruby-variables, *default-branch-pipeline-failure-variables]
PIPELINE_NAME: 'Ruby $RUBY_VERSION $CI_COMMIT_BRANCH branch pipeline'
# For tags, create a pipeline.
- if: '$CI_COMMIT_TAG'
@@ -152,7 +153,7 @@ variables:
DEBIAN_VERSION: "bullseye"
UBI_VERSION: "8.6"
CHROME_VERSION: "113"
- DOCKER_VERSION: "23.0.1"
+ DOCKER_VERSION: "24.0.5"
RUBYGEMS_VERSION: "3.4"
GO_VERSION: "1.20"
RUST_VERSION: "1.65"
@@ -198,6 +199,7 @@ variables:
REVIEW_APPS_GCP_REGION: "us-central1"
CACHE_ASSETS_AS_PACKAGE: "true"
+ REUSE_FRONTEND_FIXTURES_ENABLED: "true"
BUILD_ASSETS_IMAGE: "true" # Set it to "false" to disable assets image building, used in `build-assets-image`
SIMPLECOV: "true"
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 989d74ff117..ddcb8f2ffaf 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -48,9 +48,29 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend
/spec/frontend_integration/
/ee/spec/frontend_integration/
+[Clickhouse] @gitlab-org/maintainers/clickhouse
+/db/click_house/
+/ee/db/click_house/
+/**/click(_|-)?house/
+
+## We list db/ subfolders explicitly as we don't want to match Clickhouse files
[Database] @gitlab-org/maintainers/database
-/db/
-/ee/db/
+/db/database_connections/
+/ee/db/database_connections/
+/db/docs/
+/ee/db/docs/
+/ee/db/embedding/
+/ee/db/geo/
+/ee/db/seeds/
+/db/gitlab_schemas/
+/ee/db/gitlab_schemas/
+/db/*migrate/
+/ee/db/*migrate/
+/db/schema_migrations/
+/ee/db/schema_migrations/
+# The following two lines only match db/ root files
+/db/*
+/ee/db/*
/lib/gitlab/background_migration/
/ee/lib/ee/gitlab/background_migration/
/lib/gitlab/database/
@@ -79,7 +99,7 @@ Dangerfile
/tooling/danger/
/scripts/
/scripts/**/*.rb @gl-quality/eng-prod @gitlab-org/maintainers/rails-backend
-/scripts/**/glfm/**/* @gl-quality/eng-prod @gitlab-org/maintainers/rails-backend
+/scripts/**/glfm/**/* @gl-quality/eng-prod @gitlab-org/plan-stage/backend-engineers
/scripts/**/*.js @gl-quality/eng-prod @gitlab-org/maintainers/frontend
/scripts/frontend/ @gl-quality/eng-prod @gitlab-org/maintainers/frontend
/scripts/remote_development/ @gitlab-org/maintainers/remote-development/backend
@@ -96,12 +116,13 @@ Dangerfile
/lefthook.yml
/tests.yml
-^[Backend Static Code Analysis] @gl-quality/eng-prod @dstull @splattael
+^[Backend Static Code Analysis] @gl-quality/eng-prod @dstull
.rubocop*.yml
.rubocop_todo/
/gems/config/rubocop.yml
/rubocop/
/spec/rubocop/
+/spec/rubocop*
^[End-to-end] @gl-quality
/qa/
@@ -120,6 +141,7 @@ Dangerfile
# Secure & Threat Management ownership delineation
# https://about.gitlab.com/handbook/engineering/development/threat-management/delineate-secure-threat-management.html#technical-boundaries
^[Threat Insights backend] @gitlab-org/govern/threat-insights-backend-team
+/development/sec/cyclonedx_property_taxonomy.md
/app/finders/security/
/app/models/vulnerability.rb
/app/presenters/projects/security/
@@ -731,14 +753,13 @@ lib/gitlab/checks/**
/doc/ci/examples/deployment/ @phillipwells
/doc/ci/examples/semantic-release.md @phillipwells
/doc/ci/interactive_web_terminal/ @fneill
-/doc/ci/large_repositories/ @fneill
/doc/ci/resource_groups/ @phillipwells
/doc/ci/runners/ @fneill
/doc/ci/services/ @fneill
/doc/ci/test_cases/ @msedlakjakubowski
/doc/ci/testing/code_quality.md @rdickenson
/doc/development/advanced_search.md @ashrafkhamis
-/doc/development/ai_features.md @sselhorn
+/doc/development/ai_features/ @sselhorn
/doc/development/application_limits.md @axil
/doc/development/audit_event_guide/ @eread
/doc/development/auto_devops.md @phillipwells
@@ -935,6 +956,7 @@ lib/gitlab/checks/**
/doc/user/profile/index.md @jglassman1
/doc/user/profile/notifications.md @msedlakjakubowski
/doc/user/profile/personal_access_tokens.md @jglassman1
+/doc/user/profile/service_accounts.md @jglassman1
/doc/user/profile/user_passwords.md @jglassman1
/doc/user/project/autocomplete_characters.md @aqualls
/doc/user/project/badges.md @lciutacu
@@ -973,9 +995,9 @@ lib/gitlab/checks/**
/doc/user/project/releases/release_evidence.md @eread
/doc/user/project/remote_development/ @ashrafkhamis
/doc/user/project/repository/ @aqualls
-/doc/user/project/repository/code_suggestions.md @sselhorn
+/doc/user/project/repository/code_suggestions/ @sselhorn
/doc/user/project/repository/file_finder.md @ashrafkhamis
-/doc/user/project/repository/managing_large_repositories.md @axil
+/doc/user/project/repository/managing_large_repositories.md @eread
/doc/user/project/repository/web_editor.md @ashrafkhamis
/doc/user/project/requirements/ @msedlakjakubowski
/doc/user/project/service_desk/ @msedlakjakubowski
@@ -1170,6 +1192,7 @@ lib/gitlab/checks/**
/ee/app/models/ee/personal_access_token.rb
/ee/app/models/ee/project_authorization.rb
/ee/app/models/scim_oauth_access_token.rb
+/ee/app/models/members/member_role.rb
/ee/app/serializers/scim_oauth_access_token_entity.rb
/ee/app/services/arkose/token_verification_service.rb
/ee/app/services/ee/auth/
@@ -1202,6 +1225,7 @@ lib/gitlab/checks/**
/ee/lib/gitlab/geo/oauth/
/ee/lib/gitlab/kerberos/
/ee/lib/omni_auth/
+/ee/spec/requests/custom_roles/
/ee/lib/system_check/geo/authorized_keys_check.rb
/ee/lib/system_check/geo/authorized_keys_flag_check.rb
/lib/api/entities/impersonation_token.rb
@@ -1328,8 +1352,6 @@ lib/gitlab/checks/**
# Verify frontend
/**/javascripts/ci/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/pipelines/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/jobs/ @gitlab-org/ci-cd/verify/frontend
/**/javascripts/token_access/ @gitlab-org/ci-cd/verify/frontend
/**/javascripts/admin/application_settings/runner_token_expiration/ @gitlab-org/ci-cd/verify/frontend
/**/javascripts/usage_quotas/pipelines/ @gitlab-org/ci-cd/verify/frontend @sheldonled @aalakkad @kpalchyk
@@ -1381,8 +1403,7 @@ lib/gitlab/checks/**
/lib/tasks/gitlab/seed/runner_fleet.rake @gitlab-org/ci-cd/runner-fleet-team/backend-approvers
# CI/CD templates require approval from specific owners.
/lib/gitlab/ci/templates/ @gitlab-org/maintainers/cicd-templates
-/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah
-/lib/gitlab/ci/templates/Security/ @gonzoyumo @twoodham @sethgitlab @thiagocsf
+/lib/gitlab/ci/templates/Security/ @gonzoyumo @twoodham @amarpatel
/lib/gitlab/ci/templates/Security/API-Fuzzing.*.yml @gitlab-org/secure/dynamic-analysis
/lib/gitlab/ci/templates/Security/Container-Scanning.*.yml @gitlab-org/secure/composition-analysis-be
/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.*.yml @gitlab-org/secure/dynamic-analysis
@@ -1493,7 +1514,6 @@ ee/lib/ee/api/entities/project.rb
/ee/app/controllers/remote_development/
/ee/app/services/remote_development/
/ee/lib/remote_development/
-/ee/spec/frontend/remote_development/
/ee/spec/features/remote_development/
/ee/spec/models/remote_development/
/ee/spec/policies/remote_development/
@@ -1511,8 +1531,10 @@ ee/lib/ee/api/entities/project.rb
/qa/qa/specs/features/**/remote_development/ @gitlab-org/maintainers/remote-development/backend @gl-quality/qe-maintainers
[Create::IDE - Remote Development Frontend] @gitlab-org/maintainers/remote-development/frontend
+/ee/app/assets/remote_development/
/ee/app/assets/**/remote_development/
/ee/app/views/remote_development/
+/ee/spec/frontend/remote_development/
/ee/spec/frontend/**/remote_development/
# JiHu GitLab rules. See https://gitlab.com/gitlab-jh/gitlab-jh-enablement/-/issues/213#note_1024367528
diff --git a/.gitlab/ci/as-if-jh.gitlab-ci.yml b/.gitlab/ci/as-if-jh.gitlab-ci.yml
index ec9acdb5d4d..6c1c3357089 100644
--- a/.gitlab/ci/as-if-jh.gitlab-ci.yml
+++ b/.gitlab/ci/as-if-jh.gitlab-ci.yml
@@ -1,6 +1,7 @@
.as-if-jh-sandbox-variables:
variables:
AS_IF_JH_BRANCH: "as-if-jh/${CI_COMMIT_REF_NAME}"
+ JH_MIRROR_REPOSITORY: "https://dummy:${ADD_JH_FILES_TOKEN}@gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab.git"
SANDBOX_REPOSITORY: "https://dummy:${AS_IF_JH_TOKEN}@gitlab.com/gitlab-org-sandbox/gitlab-jh-validation.git"
.shared-as-if-jh:
@@ -22,18 +23,22 @@ add-jh-files:
- source ./scripts/setup/as-if-jh.sh
- install_gitlab_gem
script:
- - prepare_jh_branch
- - download_jh_path ${JH_FILES_TO_COMMIT}
+ - set_jh_branch_env_variable
+ - download_jh_files ${JH_FILES_TO_COMMIT}
- echoinfo "Changes after downloading JiHu files:"
- git diff
- git status
artifacts:
expire_in: 2d
+ when: always # We also want the artifacts when we exit with error 3 (detached pipeline in that case)
paths:
# This should match JH_FILES_TO_COMMIT
- jh/
- package.json
- yarn.lock
+ allow_failure:
+ exit_codes:
+ - 3 # Set in the download_jh_files_from_git_clone function
prepare-as-if-jh-branch:
extends:
diff --git a/.gitlab/ci/cng/main.gitlab-ci.yml b/.gitlab/ci/cng/main.gitlab-ci.yml
index 208567f569b..e7593b8f208 100644
--- a/.gitlab/ci/cng/main.gitlab-ci.yml
+++ b/.gitlab/ci/cng/main.gitlab-ci.yml
@@ -49,7 +49,6 @@ include:
EE_PIPELINE: "${EE_PIPELINE}" # Based on https://docs.gitlab.com/ee/ci/jobs/job_control.html#check-if-a-variable-exists, `if: '$EE_PIPELINE'` will evaluate to `false` when this variable is empty
GITLAB_ELASTICSEARCH_INDEXER_VERSION: "${GITLAB_ELASTICSEARCH_INDEXER_VERSION}"
GITLAB_KAS_VERSION: "${GITLAB_KAS_VERSION}"
- GITLAB_METRICS_EXPORTER_VERSION: "${GITLAB_METRICS_EXPORTER_VERSION}"
GITLAB_PAGES_VERSION: "${GITLAB_PAGES_VERSION}"
GITLAB_SHELL_VERSION: "${GITLAB_SHELL_VERSION}"
GITLAB_WORKHORSE_VERSION: "${GITLAB_WORKHORSE_VERSION}"
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index 6aad4de64bd..25d974b1580 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -123,3 +123,13 @@ docs-lint deprecations-and-removals:
needs: []
script:
- bundle exec rake gitlab:docs:check_deprecations
+
+docs-lint redirects:
+ image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}-alpine
+ stage: lint
+ extends:
+ - .default-retry
+ - .docs:rules:redirect-check
+ needs: []
+ script:
+ - ./scripts/lint-docs-redirects.rb
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index f103032ee69..a1c209abd98 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -67,6 +67,7 @@ compile-test-assets:
paths:
- public/assets/
- node_modules/@gitlab/svgs/dist/icons.json # app/helpers/icons_helper.rb uses this file
+ - node_modules/@gitlab/svgs/dist/file_icons/file_icons.json # app/helpers/icons_helper.rb uses this file
- "${WEBPACK_COMPILE_LOG_PATH}"
when: always
diff --git a/.gitlab/ci/gitlab-gems.gitlab-ci.yml b/.gitlab/ci/gitlab-gems.gitlab-ci.yml
index 1ee08c4ab85..a773e9c7f90 100644
--- a/.gitlab/ci/gitlab-gems.gitlab-ci.yml
+++ b/.gitlab/ci/gitlab-gems.gitlab-ci.yml
@@ -26,3 +26,6 @@ include:
- local: .gitlab/ci/templates/gem.gitlab-ci.yml
inputs:
gem_name: "csv_builder"
+ - local: .gitlab/ci/templates/gem.gitlab-ci.yml
+ inputs:
+ gem_name: "gitlab-http"
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index dd615fe5e9d..51e23dce320 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -179,11 +179,6 @@
cache:
- *ruby-coverage-gems-cache-push
-# This cache should eventually be replaced by .ruby-gems-coverage-cache.
-.coverage-cache:
- cache:
- - *ruby-gems-cache
-
.ruby-node-cache:
cache:
- *ruby-gems-cache
diff --git a/.gitlab/ci/package-and-test/main.gitlab-ci.yml b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
index 9e11a6606f7..c616fe3de82 100644
--- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
@@ -104,6 +104,7 @@ instance:
variables:
QA_SCENARIO: Test::Instance::Image
rules:
+ - !reference [.rules:test:smoke-for-omnibus-mr, rules]
- !reference [.rules:test:feature-flags-set, rules] # always run instance to validate ff change
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
@@ -140,6 +141,7 @@ praefect:
QA_CAN_TEST_PRAEFECT: "true"
KNAPSACK_TEST_FILE_PATTERN: "qa/specs/features/**/3_create/**/*_spec.rb"
rules:
+ - !reference [.rules:test:smoke-for-omnibus-mr, rules]
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
@@ -177,6 +179,7 @@ decomposition-single-db:
QA_SCENARIO: Test::Instance::Image
GITLAB_QA_OPTS: --omnibus-config decomposition_single_db $EXTRA_GITLAB_QA_OPTS
rules:
+ - !reference [.rules:test:smoke-for-omnibus-mr, rules]
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
@@ -213,6 +216,7 @@ decomposition-multiple-db:
GITLAB_ALLOW_SEPARATE_CI_DATABASE: "true"
GITLAB_QA_OPTS: --omnibus-config decomposition_multiple_db $EXTRA_GITLAB_QA_OPTS
rules:
+ - !reference [.rules:test:smoke-for-omnibus-mr, rules]
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
diff --git a/.gitlab/ci/qa-common/main.gitlab-ci.yml b/.gitlab/ci/qa-common/main.gitlab-ci.yml
index 5c9043f8694..bdb5e776808 100644
--- a/.gitlab/ci/qa-common/main.gitlab-ci.yml
+++ b/.gitlab/ci/qa-common/main.gitlab-ci.yml
@@ -6,7 +6,7 @@ workflow:
include:
- project: gitlab-org/quality/pipeline-common
- ref: 7.2.3
+ ref: 7.5.1
file:
- /ci/base.gitlab-ci.yml
- /ci/knapsack-report.yml
diff --git a/.gitlab/ci/qa-common/rules.gitlab-ci.yml b/.gitlab/ci/qa-common/rules.gitlab-ci.yml
index 7518f08398f..c593ec4ccfb 100644
--- a/.gitlab/ci/qa-common/rules.gitlab-ci.yml
+++ b/.gitlab/ci/qa-common/rules.gitlab-ci.yml
@@ -43,6 +43,10 @@
.not-canonical-project: &not-canonical-project
if: '$CI_PROJECT_PATH != "gitlab-org/gitlab" && $CI_PROJECT_PATH != "gitlab-cn/gitlab"'
+# If Schedule pipeline
+.if-schedule-pipeline: &if-schedule-pipeline
+ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $SCHEDULE_TYPE == "maintenance"'
+
# Selective test execution against omnibus instance have following execution scenarios:
# * only e2e spec files changed - runs only changed specs
# * qa framework changes - runs full test suite
@@ -149,12 +153,32 @@
when: never
- !reference [.rules:test:qa, rules]
+.rules:test:never-schedule-pipeline:
+ rules:
+ - <<: *if-schedule-pipeline
+ when: never
+
+.rules:test:gdk-load-balancer-changes:
+ rules:
+ - changes:
+ - ".gitlab/ci/test-on-gdk/**"
+ - "lib/gitlab/database/load_balancing/**/*"
+
.rules:test:qa-default-branch:
rules:
- *qa-run-all-e2e-label
- *default-branch
- *feature-flags-set-manual
+.rules:test:smoke-for-omnibus-mr:
+ rules:
+ - if: '$CI_PROJECT_NAME == "omnibus-gitlab" && $PIPELINE_TYPE =~ /TRIGGERED_(CE|EE)_PIPELINE/ && $QA_OMNIBUS_MR_TESTS == "only-smoke-reliable"'
+ variables:
+ QA_RSPEC_TAGS: "--tag smoke --tag reliable --tag ~orchestrated --tag ~skip_live_env"
+ - if: '$CI_PROJECT_NAME == "omnibus-gitlab" && $PIPELINE_TYPE =~ /TRIGGERED_(CE|EE)_PIPELINE/ && $QA_OMNIBUS_MR_TESTS == "except-smoke-reliable"'
+ variables:
+ QA_RSPEC_TAGS: "--tag ~smoke --tag ~reliable --tag ~orchestrated --tag ~skip_live_env --tag ~transient"
+
# ------------------------------------------
# Report
# ------------------------------------------
diff --git a/.gitlab/ci/qa-common/variables.gitlab-ci.yml b/.gitlab/ci/qa-common/variables.gitlab-ci.yml
index 9498df47ecc..a449d960cff 100644
--- a/.gitlab/ci/qa-common/variables.gitlab-ci.yml
+++ b/.gitlab/ci/qa-common/variables.gitlab-ci.yml
@@ -17,3 +17,4 @@ variables:
RSPEC_FAST_QUARANTINE_FILE: "fast_quarantine-gitlab.txt"
# This path is relative to /home/gitlab/qa/ in the QA container
RSPEC_FAST_QUARANTINE_PATH: "rspec/${RSPEC_FAST_QUARANTINE_FILE}"
+ QA_OMNIBUS_MR_TESTS: "only-smoke-reliable"
diff --git a/.gitlab/ci/qa.gitlab-ci.yml b/.gitlab/ci/qa.gitlab-ci.yml
index 5cdaf6ada82..0a06418e7c6 100644
--- a/.gitlab/ci/qa.gitlab-ci.yml
+++ b/.gitlab/ci/qa.gitlab-ci.yml
@@ -84,7 +84,6 @@ trigger-omnibus:
GITALY_SERVER_VERSION: $GITALY_SERVER_VERSION
GITLAB_ELASTICSEARCH_INDEXER_VERSION: $GITLAB_ELASTICSEARCH_INDEXER_VERSION
GITLAB_KAS_VERSION: $GITLAB_KAS_VERSION
- GITLAB_METRICS_EXPORTER_VERSION: $GITLAB_METRICS_EXPORTER_VERSION
GITLAB_PAGES_VERSION: $GITLAB_PAGES_VERSION
GITLAB_SHELL_VERSION: $GITLAB_SHELL_VERSION
GITLAB_WORKHORSE_VERSION: $GITLAB_WORKHORSE_VERSION
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 326d23be5a4..419c659e745 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -68,19 +68,17 @@ update-ruby-gems-coverage-cache-push:
- bundle_install_script
# Used in:
+# - rspec:coverage
# - rspec:undercoverage
-# - rspec:feature-flags
-# - rspec:merge-auto-explain-logs
-#
-# TODO: Consider making rspec:coverage reuse this base job, or split into two base jobs.
.coverage-base:
extends:
- .default-retry
- # TODO: If applicable for all children jobs, delete/replace this cache with .ruby-gems-coverage-cache, as it is much smaller.
- - .coverage-cache
+ - .ruby-gems-coverage-cache
+ variables:
+ BUNDLE_WITHOUT: "" # This is to override the variable defined in .gitlab-ci.yml
+ BUNDLE_ONLY: "coverage"
before_script:
- source scripts/utils.sh
- - export BUNDLE_WITHOUT="${BUNDLE_WITHOUT}:default:test:puma:kerberos:metrics:omnibus:ed25519"
- bundle_install_script
rspec migration pg14:
@@ -289,6 +287,11 @@ rspec unit clickhouse:
- .rspec-base-pg14-clickhouse23
- .rails:rules:clickhouse-changes
+rspec-ee unit clickhouse:
+ extends:
+ - .rspec-base-pg14-clickhouse23
+ - .rails:rules:clickhouse-changes
+
gitlab:setup:
extends: .db-job-base
variables:
@@ -306,35 +309,6 @@ gitlab:setup:
paths:
- log/*.log
-rspec:deprecations:
- extends:
- - .default-retry
- - .default-before_script
- - .static-analysis-cache
- - .rails:rules:deprecations
- stage: post-test
- allow_failure: true
- needs:
- - job: rspec:artifact-collector unit
- optional: true
- - job: rspec:artifact-collector system
- optional: true
- - job: rspec:artifact-collector remainder
- optional: true
- - job: rspec:artifact-collector ee
- optional: true
- variables:
- SETUP_DB: "false"
- script:
- - grep -h -R "keyword" deprecations/ | awk '{$1=$1};1' | sort | uniq -c | sort
- - grep -R "keyword" deprecations/ | wc
- - run_timed_command "fail_on_warnings bundle exec rubocop --only Lint/LastKeywordArgument --parallel"
- artifacts:
- expire_in: 31d
- when: always
- paths:
- - deprecations/
-
# The jobs built upon `.artifact-collector` are to work around the
# needs: [] limit of a maximum of 50 dependencies.
# These intermediate jobs allow us to collect the artifacts of
@@ -362,6 +336,8 @@ rspec:artifact-collector unit:
- .rails:rules:ee-and-foss-unit
needs:
- rspec unit pg14 # 28 jobs
+ - job: rspec unit clickhouse # 1 job
+ optional: true
rspec:artifact-collector system:
extends:
@@ -451,6 +427,8 @@ rspec:artifact-collector ee:
optional: true
- job: rspec-ee unit pg14 # 18 jobs
optional: true
+ - job: rspec-ee unit clickhouse # 1 job
+ optional: true
- job: rspec-ee integration pg14 # 6 jobs
optional: true
- job: rspec-ee system pg14 # 10 jobs
@@ -463,8 +441,9 @@ rspec:artifact-collector ee:
- !reference ['.rails:rules:ee-only-system', rules]
rspec:coverage:
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-slim-ruby-${RUBY_VERSION}
extends:
- - .ruby-gems-coverage-cache
+ - .coverage-base
- .rails:rules:rspec-coverage
stage: post-test
needs:
@@ -497,12 +476,6 @@ rspec:coverage:
- job: memory-on-boot
optional: true
artifacts: false
- variables:
- BUNDLE_WITHOUT: "" # This is to override the variable defined in .gitlab-ci.yml
- BUNDLE_ONLY: "coverage"
- before_script:
- - source scripts/utils.sh
- - bundle_install_script
script:
- run_timed_command "bundle exec scripts/merge-simplecov"
coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
@@ -519,6 +492,7 @@ rspec:coverage:
path: coverage/coverage.xml
rspec:undercoverage:
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-slim-ruby-${RUBY_VERSION}
extends:
- .coverage-base
- .rails:rules:rspec-undercoverage
@@ -539,7 +513,6 @@ rspec:undercoverage:
rspec:feature-flags:
extends:
- - .coverage-base
- .rails:rules:rspec-feature-flags
stage: post-test
needs:
@@ -547,11 +520,13 @@ rspec:feature-flags:
- job: "haml-lint"
- job: "haml-lint ee"
optional: true
+ before_script:
+ - source scripts/utils.sh
script:
- if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; then
- run_timed_command "bundle exec scripts/used-feature-flags" || (scripts/slack master-broken "â˜ ï¸ \`${CI_JOB_NAME}\` failed! â˜ ï¸ See ${CI_JOB_URL}" ci_failing "GitLab Bot" && exit 1);
+ run_timed_command "scripts/used-feature-flags" || (scripts/slack master-broken "â˜ ï¸ \`${CI_JOB_NAME}\` failed! â˜ ï¸ See ${CI_JOB_URL}" ci_failing "GitLab Bot" && exit 1);
else
- run_timed_command "bundle exec scripts/used-feature-flags";
+ run_timed_command "scripts/used-feature-flags";
fi
rspec:flaky-tests-report:
@@ -572,7 +547,6 @@ rspec:flaky-tests-report:
rspec:merge-auto-explain-logs:
extends:
- - .coverage-base
- .rails:rules:rspec-merge-auto-explain-logs
stage: post-test
needs: !reference ["rspec:coverage", "needs"]
diff --git a/.gitlab/ci/rails/shared.gitlab-ci.yml b/.gitlab/ci/rails/shared.gitlab-ci.yml
index ce89e7ef689..6803bdd3386 100644
--- a/.gitlab/ci/rails/shared.gitlab-ci.yml
+++ b/.gitlab/ci/rails/shared.gitlab-ci.yml
@@ -88,6 +88,9 @@ include:
if [ "$CREATE_RAILS_SLOW_TEST_ISSUES" == "true" ]; then
bundle exec slow-test-issues --input-files "rspec/rspec-*.json" --project "gitlab-org/gitlab" --token "${TEST_FAILURES_PROJECT_TOKEN}";
fi
+ if [ "$ADD_SLOW_TEST_NOTE_TO_MERGE_REQUEST" == "true" ]; then
+ bundle exec slow-test-merge-request-report-note --input-files "rspec/rspec-*.json" --project "gitlab-org/gitlab" --merge_request_iid "$CI_MERGE_REQUEST_IID" --token "${TEST_SLOW_NOTE_PROJECT_TOKEN}";
+ fi
- echo -e "\e[0Ksection_end:`date +%s`:report_results_section\r\e[0K"
allow_failure:
diff --git a/.gitlab/ci/review-apps/main.gitlab-ci.yml b/.gitlab/ci/review-apps/main.gitlab-ci.yml
index a3ced427ea1..2df67713ecc 100644
--- a/.gitlab/ci/review-apps/main.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/main.gitlab-ci.yml
@@ -40,7 +40,6 @@ review-build-cng-env:
GITALY_SERVER_VERSION
GITLAB_ELASTICSEARCH_INDEXER_VERSION
GITLAB_KAS_VERSION
- GITLAB_METRICS_EXPORTER_VERSION
GITLAB_PAGES_VERSION
GITLAB_SHELL_VERSION
scripts/trigger-build.rb
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index 224312bd8ee..d4b199a9a81 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -75,6 +75,10 @@ start-review-app-pipeline:
stage: review
needs:
- job: e2e-test-pipeline-generate
+ - job: rails-production-server-boot-puma-example
+ optional: true
+ - job: rails-production-server-boot-puma-cng
+ optional: true
- job: build-assets-image
artifacts: false
# We do not want to have ALL global variables passed as trigger variables,
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 304544468ac..d8cc67a966a 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -378,9 +378,12 @@
- "spec/support/database_cleaner.rb"
- "config/prometheus/common_metrics.yml" # Used by Gitlab::DatabaseImporters::CommonMetrics::Importer
- "{,ee/,jh/}app/models/project_statistics.rb" # Used to calculate sizes in migration specs
+ - "{,ee/,jh/}app/{,models/,services/,workers/}loose_foreign_keys/**/*"
# Gitaly has interactions with background migrations: https://gitlab.com/gitlab-org/gitlab/-/issues/336538
- "GITALY_SERVER_VERSION"
- "lib/gitlab/setup_helper.rb"
+ # Test-gap from https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/issues/275
+ - "{,ee/,jh/}lib/tasks/gitlab/seed/*.rake"
# DB backup patterns
.db-backup-patterns: &db-backup-patterns
@@ -503,7 +506,9 @@
- "tests.yml"
- "config.ru"
- "{,ee/,jh/}{app,bin,config,db,generator_templates,haml_lint,lib,locale,public,scripts,storybook,symbol,vendor}/**/*"
- - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
+ # Auto-generated files
+ - "doc/api/graphql/reference/*"
+ - "doc/administration/audit_event_streaming/audit_event_types.md"
# CI changes
- ".gitlab-ci.yml"
- ".gitlab/ci/**/*"
@@ -609,10 +614,13 @@
- qa/gdk/**/*
- Gemfile.lock
- yarn.lock
+ - scripts/build_gdk_image
+ - scripts/frontend/postinstall.js
- workhorse/**/*
+ - vendor/gems/**/*
+ - gems/**/*
- VERSION
- GITLAB_WORKHORSE_VERSION
- - GITLAB_METRICS_EXPORTER_VERSION
- GITLAB_SHELL_VERSION
- GITALY_SERVER_VERSION
@@ -756,6 +764,8 @@
changes: *backend-patterns
- <<: *if-merge-request
changes: *backstage-patterns
+ - <<: *if-merge-request
+ changes: ["**/*click_house*"]
.rails:rules:ee-and-foss-integration:predictive:
rules:
@@ -905,9 +915,12 @@
# It's better to fail early and avoid wasting resources running test jobs that would just fail anyway.
.build-images:rules:build-gdk-image:
rules:
+ # Allows to force rebuild base image in case something goes wrong and this had to be disabled
- if: '$QA_RUN_TESTS_ON_GDK !~ /true|yes|1/i'
when: manual
allow_failure: true
+ variables:
+ BUILD_GDK_BASE: "true"
- !reference [".qa:rules:package-and-test-never-run", rules]
- <<: *if-default-branch-schedule-nightly # already executed in the 2-hourly schedule
when: never
@@ -982,6 +995,8 @@
#################
.caching:rules:cache-workhorse:
rules:
+ - <<: *if-not-ee
+ when: never
# That would run for any project that has a "maintenance" pipeline schedule
# but in fact, the cache package is only uploaded for gitlab.com/gitlab-org/gitlab and jihulab.com/gitlab-cn/gitlab
- <<: *if-schedule-maintenance
@@ -999,6 +1014,8 @@
# The new strategy to cache assets as generic packages is experimental and can be disabled by removing the `CACHE_ASSETS_AS_PACKAGE` variable
- if: '$CACHE_ASSETS_AS_PACKAGE != "true"'
when: never
+ - <<: *if-not-ee
+ when: never
# That would run for any project that has a "maintenance" pipeline schedule
# but in fact, the cache package is only uploaded for gitlab.com/gitlab-org/gitlab and jihulab.com/gitlab-cn/gitlab
- <<: *if-schedule-maintenance
@@ -1014,8 +1031,7 @@
.caching:rules:cache-assets-as-if-foss:
rules:
- - <<: *if-jh
- when: never
+ - !reference [".strict-ee-only-rules", rules]
- !reference [".caching:rules:cache-assets", "rules"]
.caching:rules:packages-cleanup:
@@ -1023,6 +1039,8 @@
# The new strategy to cache assets as generic packages is experimental and can be disabled by removing the `CACHE_ASSETS_AS_PACKAGE` variable
- if: '$CACHE_ASSETS_AS_PACKAGE != "true"'
when: never
+ - <<: *if-not-ee
+ when: never
# That would run for any project that has a "maintenance" pipeline schedule
# but in fact, the cache package is only uploaded for gitlab.com/gitlab-org/gitlab and jihulab.com/gitlab-cn/gitlab
- <<: *if-schedule-maintenance
@@ -1071,6 +1089,11 @@
when: manual
allow_failure: true
+.docs:rules:redirect-check:
+ rules:
+ - <<: *if-dot-com-gitlab-org-merge-request
+ changes: *docs-patterns
+
.docs:rules:docs-lint:
rules:
- <<: *if-default-refs
@@ -1182,8 +1205,7 @@
rules:
- <<: *if-not-canonical-namespace
when: never
- - <<: *if-not-ee
- when: never
+ - !reference [".strict-ee-only-rules", rules]
- !reference [.frontend:rules:compile-production-assets, rules]
.frontend:rules:compile-test-assets:
@@ -1240,12 +1262,12 @@
# The new strategy to upload fixtures as generic packages is experimental and can be disabled by removing the `REUSE_FRONTEND_FIXTURES_ENABLED` variable
- if: '$REUSE_FRONTEND_FIXTURES_ENABLED != "true"'
when: never
+ - <<: *if-not-ee
+ when: never
- <<: *if-merge-request-labels-pipeline-expedite
when: never
- <<: *if-dot-com-gitlab-org-default-branch
changes: *code-backstage-patterns
- - <<: *if-foss-default-branch
- changes: *code-backstage-patterns
- <<: *if-dot-com-gitlab-org-merge-request
changes:
- ".gitlab/ci/frontend.gitlab-ci.yml"
@@ -1603,14 +1625,12 @@
.qa:rules:package-and-test-schedule:
rules:
- - <<: *if-dot-com-gitlab-org-schedule
+ - <<: [*if-dot-com-gitlab-org-schedule, *qa-e2e-test-schedule-variables]
allow_failure: true
- <<: *qa-e2e-test-schedule-variables
.qa:rules:e2e-schedule-blocking:
rules:
- - <<: *if-dot-com-gitlab-org-schedule
- <<: *qa-e2e-test-schedule-variables
+ - <<: [*if-dot-com-gitlab-org-schedule, *qa-e2e-test-schedule-variables]
# Note: If any changes are made to this rule, the following should also be updated:
# 1) .qa:rules:manual-omnibus-and-follow-up-e2e
@@ -1653,6 +1673,7 @@
.qa:rules:package-and-test-nightly:
rules:
+ - !reference [".qa:rules:package-and-test-never-run", rules]
- <<: *if-default-branch-schedule-nightly
allow_failure: true
variables:
@@ -1800,6 +1821,9 @@
# From .qa:rules:package-and-test-schedule
- <<: *if-dot-com-gitlab-org-schedule
when: never
+ # Do not run on unapproved MR
+ - <<: *if-merge-request-not-approved
+ when: never
# From .qa:rules:code-merge-request-manual
- <<: *if-merge-request
changes: *code-patterns
@@ -1840,8 +1864,7 @@
.rails:rules:single-db-as-if-foss:
rules:
- - <<: *if-jh
- when: never
+ - !reference [".strict-ee-only-rules", rules]
- !reference [".rails:rules:single-db", "rules"]
.rails:rules:db:check-migrations-single-db:
@@ -1867,8 +1890,7 @@
.rails:rules:single-db-ci-connection-as-if-foss:
rules:
- - <<: *if-jh
- when: never
+ - !reference [".strict-ee-only-rules", rules]
- !reference [".rails:rules:single-db-ci-connection", "rules"]
.rails:rules:db:check-migrations-single-db-ci-connection:
@@ -1973,6 +1995,8 @@
changes: *backend-patterns
- <<: *if-default-refs
changes: *backstage-patterns
+ - <<: *if-merge-request
+ changes: ["**/*click_house*"]
.rails:rules:ee-and-foss-integration:
rules:
@@ -2192,16 +2216,6 @@
changes: *code-backstage-patterns
when: on_failure
-.rails:rules:deprecations:
- rules:
- - <<: *if-not-ee
- when: never
- - <<: *if-merge-request-labels-pipeline-expedite
- when: never
- - <<: *if-default-branch-schedule-nightly
- - <<: *if-ruby3_1-branch-schedule-nightly
- - <<: *if-merge-request-labels-run-all-rspec
-
.rails:rules:rspec-coverage:
rules:
- <<: *if-not-ee
@@ -2221,11 +2235,11 @@
when: never
- <<: *if-merge-request-labels-skip-undercoverage
when: never
+ - <<: *if-merge-request-labels-run-all-rspec
# We cannot get the coverage data from child pipeline so we only run undercoverage on full pipelines for now
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113410#note_1335422806
- <<: *if-merge-request-not-approved
when: never
- - <<: *if-merge-request-labels-run-all-rspec
- <<: *if-merge-request
changes: *backend-patterns
@@ -2242,6 +2256,8 @@
when: never
- <<: *if-merge-request-labels-run-all-rspec
- <<: *if-merge-request-labels-record-queries
+ - <<: *if-default-branch-refs
+ changes: *code-patterns
.rails:rules:default-branch-schedule-nightly--code-backstage-default-rules:
rules:
@@ -2287,6 +2303,7 @@
rules:
- <<: *if-merge-request
changes: ["**/*click_house*"]
+ - <<: *if-merge-request-labels-run-all-rspec
#########################
# Static analysis rules #
@@ -2530,7 +2547,7 @@
# The following rules needs to be the same as the one for .review:rules:review-cleanup
# except that:
-# - most rules re automatic here (i.e. no `when: manual`) and not allowed to fail (i.e. no `allow_failure: true`) here
+# - we start review apps automatically for scheduled pipelines and when the `pipeline:run-review-app` label is set
# - several rules have `variables: *review-change-pattern` here
.review:rules:start-review-app-pipeline:
rules:
@@ -2538,12 +2555,18 @@
when: never
- <<: *if-merge-request-labels-pipeline-expedite
when: never
+ - if: '$CI_REVIEW_APPS_ENABLED != "true"'
+ when: never
- <<: *if-merge-request-labels-run-review-app
- <<: *if-dot-com-gitlab-org-merge-request
changes: *ci-review-patterns
+ when: manual
+ allow_failure: true
- <<: *if-dot-com-gitlab-org-merge-request
changes: *frontend-build-patterns
variables: *review-change-pattern
+ when: manual
+ allow_failure: true
- <<: *if-dot-com-gitlab-org-merge-request
changes: *controllers-patterns
variables: *review-change-pattern
@@ -2561,6 +2584,8 @@
allow_failure: true
- <<: *if-dot-com-gitlab-org-merge-request
changes: *qa-patterns
+ when: manual
+ allow_failure: true
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-patterns
when: manual
diff --git a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
index 41f85c492d9..9e179fec458 100644
--- a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
+++ b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
@@ -26,6 +26,7 @@ variables:
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}:bundler-2.3-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}-gcloud-383-kubectl-1.23
extends:
- .qa-cache
+ - .default-retry
stage: test
services:
- docker:${DOCKER_VERSION}-dind
@@ -41,15 +42,16 @@ variables:
FF_NETWORK_PER_BUILD: 1
GDK_URL: http://gdk.test:3000
KNAPSACK_TEST_FILE_PATTERN: "qa/specs/features/**/*_spec.rb"
+ QA_SUITE_STATUS_ENV_FILE: "$CI_PROJECT_DIR/suite_status.env"
before_script:
- - echo "SUITE_RAN=true" > suite_status.env
- - echo -e "\e[0Ksection_start:`date +%s`:pull_image\r\e[0KPull GDK QA image"
+ - echo "SUITE_RAN=true" > "$QA_SUITE_STATUS_ENV_FILE"
+ - echo -e "\e[0Ksection_start:`date +%s`:pull_image[collapsed=true]\r\e[0KPull GDK QA image"
- docker pull ${GDK_IMAGE}
- echo -e "\e[0Ksection_end:`date +%s`:pull_image\r\e[0K"
# Despite `incremental: false` and `static: true`, GDK sometimes fails to start without increasing max user watches
# This is why we're not running the GDK container as a service
- sysctl -n -w fs.inotify.max_user_watches=524288
- - echo -e "\e[0Ksection_start:`date +%s`:launch_gdk\r\e[0KLaunch GDK"
+ - echo -e "\e[0Ksection_start:`date +%s`:launch_gdk[collapsed=true]\r\e[0KLaunch GDK"
- mkdir -p $CI_PROJECT_DIR/log/gdk $CI_PROJECT_DIR/log/gitlab
# This command matches the permissions of the user that runs GDK inside the container.
- chown -R 1000:1000 $CI_PROJECT_DIR/log
@@ -61,29 +63,28 @@ variables:
# With `FF_NETWORK_PER_BUILD=1` and `--network host` the IP of the gdk container should be 172.18.0.2, but we get it
# dynamically just in case
- echo "$(docker exec gdk bash -c "getent hosts \$HOSTNAME" | awk '{print $1}') gdk.test" >> /etc/hosts
+ - echo -e "\e[0Ksection_end:`date +%s`:launch_gdk\r\e[0K"
+ - echo -e "\e[0Ksection_start:`date +%s`:install_gems[collapsed=true]\r\e[0KInstall gems"
- source scripts/utils.sh
- cd qa && bundle install
+ - echo -e "\e[0Ksection_end:`date +%s`:install_gems\r\e[0K"
script:
- - retry_exponential test_url $GDK_URL/users/sign_in
- - echo -e "\e[0Ksection_end:`date +%s`:launch_gdk\r\e[0K"
+ - echo -e "\e[0Ksection_start:`date +%s`:healthcheck[collapsed=true]\r\e[0KWait for gdk to start"
+ - retry_times_sleep 100 3 test_url $GDK_URL/users/sign_in
+ - echo -e "\e[0Ksection_end:`date +%s`:healthcheck\r\e[0K"
- echo -e "\e[0Ksection_start:`date +%s`:run_tests\r\e[0KRun E2E tests"
- export QA_COMMAND="bundle exec bin/qa ${QA_SCENARIO:=Test::Instance::All} $GDK_URL $GITLAB_QA_OPTS -- $QA_TESTS $QA_RSPEC_TAGS $RSPEC_REPORT_OPTS"
- echo "Running - '$QA_COMMAND'"
- eval "$QA_COMMAND"
- echo -e "\e[0Ksection_end:`date +%s`:run_tests\r\e[0K"
- after_script:
- - |
- if [ "$CI_JOB_STATUS" == "failed" ]; then
- echo "SUITE_FAILED=true" >> suite_status.env
- fi
- - docker stop gdk
artifacts:
paths:
- qa/tmp
- - log
+ - log/gitlab
+ - log/gdk/*/current
reports:
junit: qa/tmp/rspec-*.xml
- dotenv: suite_status.env
+ dotenv: "$QA_SUITE_STATUS_ENV_FILE"
expire_in: 7 days
when: always
@@ -125,6 +126,7 @@ download-fast-quarantine-report:
gdk-qa-smoke:
extends:
- .gdk-qa-base
+ - .gitlab-qa-report
variables:
QA_SCENARIO: Test::Instance::Smoke
QA_RUN_TYPE: gdk-qa-smoke
@@ -144,21 +146,23 @@ gdk-qa-smoke-with-load-balancer:
reports:
dotenv: ""
rules:
- - changes:
- - ".gitlab/ci/test-on-gdk/**"
- - "lib/gitlab/database/load_balancing/**/*"
+ - !reference [".rules:test:never-schedule-pipeline", rules]
+ - !reference [".rules:test:gdk-load-balancer-changes", rules]
allow_failure: true
gdk-qa-reliable:
extends:
- .gdk-qa-base
+ - .gitlab-qa-report
- .parallel
variables:
QA_SCENARIO: Test::Instance::Blocking
QA_RUN_TYPE: gdk-qa-blocking
+ parallel: 10
rules:
- - when: always
- allow_failure: true
+ - if: '$CI_MERGE_REQUEST_LABELS =~ /devops::govern/'
+ - when: on_success
+ allow_failure: true
gdk-qa-reliable-with-load-balancer:
extends:
@@ -174,9 +178,8 @@ gdk-qa-reliable-with-load-balancer:
reports:
dotenv: ""
rules:
- - changes:
- - ".gitlab/ci/test-on-gdk/**"
- - "lib/gitlab/database/load_balancing/**/*"
+ - !reference [".rules:test:never-schedule-pipeline", rules]
+ - !reference [".rules:test:gdk-load-balancer-changes", rules]
allow_failure: true
gdk-qa-non-blocking:
diff --git a/.gitlab/ci/workhorse.gitlab-ci.yml b/.gitlab/ci/workhorse.gitlab-ci.yml
index 5b128ef6170..cedcde27b7e 100644
--- a/.gitlab/ci/workhorse.gitlab-ci.yml
+++ b/.gitlab/ci/workhorse.gitlab-ci.yml
@@ -11,6 +11,8 @@ workhorse:verify:
.workhorse:test:
extends: .workhorse:rules:workhorse
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-golang-${GO_VERSION}-rust-${RUST_VERSION}:rubygems-${RUBYGEMS_VERSION}-git-2.36-exiftool-12.60
+ services:
+ - name: redis:${REDIS_VERSION}-alpine
variables:
GITALY_ADDRESS: "tcp://127.0.0.1:8075"
stage: test
@@ -22,6 +24,8 @@ workhorse:verify:
- bundle_install_script
- go version
- scripts/gitaly-test-build
+ - cp workhorse/config.toml.example workhorse/config.toml
+ - sed -i 's|URL.*$|URL = "redis://redis:6379"|g' workhorse/config.toml
script:
- make -C workhorse test
@@ -30,6 +34,7 @@ workhorse:test go:
parallel:
matrix:
- GO_VERSION: ["1.18", "1.19", "1.20"]
+ REDIS_VERSION: ["7.0", "6.2"]
script:
- make -C workhorse test-coverage
coverage: '/\d+.\d+%/'
@@ -43,11 +48,15 @@ workhorse:test fips:
parallel:
matrix:
- GO_VERSION: ["1.18", "1.19", "1.20"]
+ REDIS_VERSION: ["7.0", "6.2"]
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/ubi-${UBI_VERSION}-ruby-${RUBY_VERSION}-golang-${GO_VERSION}-rust-${RUST_VERSION}:rubygems-${RUBYGEMS_VERSION}-git-2.36-exiftool-12.60
variables:
FIPS_MODE: 1
workhorse:test race:
extends: .workhorse:test
+ parallel:
+ matrix:
+ - REDIS_VERSION: ["7.0", "6.2"]
script:
- make -C workhorse test-race
diff --git a/.gitlab/issue_templates/Operational Readiness.md b/.gitlab/issue_templates/Operational Readiness.md
new file mode 100644
index 00000000000..ef295bf893b
--- /dev/null
+++ b/.gitlab/issue_templates/Operational Readiness.md
@@ -0,0 +1,102 @@
+<!-- title format: Operational Readiness Review - {`new component name`}
+
+When we add a new component to our platform, we should keep in mind the non-functional requirements and operational needs we are adding to our platform. While
+we want to move quickly, we also want to ensure:
+
+- We know what is being added.
+- If we can operate it.
+- The it meets our general legal, compliance, and operational standards.
+
+-->
+
+## Links
+<!-- Provide Links to the Epic, issue, handbook page, and/or blueprint. -->
+
+## Type of new component
+
+<!-- List the type of new component from one of following values:
+
+- New third party SaaS service
+- New data store (that is not a SaaS service)
+- New service
+- New software dependency
+- New programming language
+- New development and testing framework
+ -->
+
+## Review process
+
+To help us to make concise and sustainable decision when converting the prototype to a product, it is highly recommended that the PM and EM start with a
+self assessment with this checklist, and then engage the appropriate groups and/or departments to review if anything in doubt. This is **NOT** a gating
+process, rather a friendly checklist to ensure the success of the new component.
+
+The review should be quick and with the least number of steps. The review will likely have 2 DRIs as reviewers for each component to ensure we can move
+quickly and handle any out of office (OOO).
+
+## Checklist
+
+Complete common and the appropriate checklists per the type of new component mentioned above (Skip any item if not applicable).
+
+### Common
+
+- [ ] Definition and Goals
+ - [ ] What the component does and what values it provides from the external and internal customer's perspective?
+ - [ ] Is any existing component capable for the same use case? If so, why is the new component required?
+ - [ ] What is the usage estimation in both .com and self-managed?
+ - [ ] Who are the development and operation DRI groups?
+
+- [ ] Legal and Security
+ - [ ] Are you conducting a legal and compliance review with legal department?
+ - [ ] Are you conducting an in-depth security review of the component with security department?
+ - [ ] What type of license do they use?
+ - [ ] What is the data classification this component will process?
+- [ ] Support
+ - [ ] Have you involved the Customer Support Team by drafting a [Support Readiness Issue](https://gitlab.com/gitlab-com/support/support-team-meta/-/issues/new?issuable_template=Support%20Readiness)? And complete it before releasing to customers.
+
+- [ ] Business
+ - [ ] Margin impact - (sheet to be created)
+ - [ ] What is the estimated cost of the component and associated support including infrastructure operations if any?
+
+- [ ] Architecture
+ - [ ] Does the component support auto-scaling? If not, how does it handle a sudden traffic increasing?
+ - [ ] What are the dependencies between existing GitLab services and this component?
+ - [ ] What is the infrastructure requirement?
+ - [ ] Is this SaaS only, or will it also be supported for Self-Managed and Dedicated?
+
+- [ ] Development, Testing, Deployment, and Operation
+ - [ ] Complete the [production readiness review](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/).
+ - [ ] As the owner, are you confident to manage and maintain the new component end to end (E2E)? You can review below typical considerations as a guidance.
+ - <details><summary>Typical considerations</summary>
+ - [ ] Talent pool, e.g. existing engineers, maintainers, and future hiring opportunities. <br />
+ - [ ] Testing, e.g. end-to-end, dependencies, performance. <br />
+ - [ ] Operational considerations, e.g. observability, hosting knowledge, etc. <br />
+ </details>
+
+### New GitLab service
+
+- [ ] Legal and Security
+ - [ ] Is there any specific security standard and compliance required before deploying to production? If so, what needs to be done?
+- [ ] Architecture
+ - [ ] Complete `New data store, third party dependency` checklist as well if a new dependency is used
+ - [ ] Complete `New programming language, development, and testing framework` checklist as well if a new programming language, development, and/or testing framework is used
+
+### New data store, third party dependency
+
+- [ ] Legal and Security
+ - [ ] What is the [classification](https://about.gitlab.com/handbook/security/data-classification-standard.html#data-classification-levels) of data stored in the data store?
+ - [ ] Have they got any security standards to meet our and/or our customers' requirements? (i.e. FIPS and/or Fed-RAMP) If not, what needs to be done?
+- [ ] Development, Testing, Deployment, and Operation
+ - [ ] What integration types do they provide, e.g. SaaS and/or self-hosting?
+ - [ ] Is rate limit possible?
+ - [ ] What is the cadence of version upgrades?
+ - [ ] What is their defect fix and security patch turnaround time?
+
+### New programming language, development, and testing framework
+
+- [ ] Is there a mature ecosystem that provides tooling (profiling, debugging, etc.) and 3rd party libraries?
+
+
+/assign <pm/em>
+/label <tbd>
+/cc <tbd>
+/confidential
diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md
index 9cbb74d10d8..0a801bb09a3 100644
--- a/.gitlab/issue_templates/Security developer workflow.md
+++ b/.gitlab/issue_templates/Security developer workflow.md
@@ -41,6 +41,7 @@ After your merge request has been approved according to our [approval guidelines
## Documentation and final details
+- [ ] When you believe this issue is ready for release (Backports are approved and ready to be merged), apply the ~"security-target" label (This label does not have an effect yet, but will in upcoming releases. See <https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/19611#computer-developer-process> for more information).
- [ ] To avoid release delays, please nominate a developer in a different timezone who will be able to respond to any pipeline or merge failures in your absence `@gitlab-username`
- [ ] Ensure `~severity::x` label is on this issue, all associated issues, and merge requests
- [ ] Ensure the [Links section](#links) is completed.
diff --git a/.gitlab/merge_request_templates/Stable Branch.md b/.gitlab/merge_request_templates/Stable Branch.md
index f8fc85f5bd2..4ad8e6fc8a2 100644
--- a/.gitlab/merge_request_templates/Stable Branch.md
+++ b/.gitlab/merge_request_templates/Stable Branch.md
@@ -16,7 +16,7 @@ _Describe in detail what merge request is being backported and why_
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
* [ ] This MR is backporting a bug fix, documentation update, or spec fix, previously merged in the default branch.
-* [ ] The original MR has been deployed to GitLab.com (not applicable for documentation or spec changes).
+* [ ] The MR that fixed the bug on the default branch has been deployed to GitLab.com (not applicable for documentation or spec changes).
* [ ] This MR has a [severity label] assigned (if applicable).
* [ ] This MR has been approved by a maintainer (only one approval is required).
* [ ] Ensure the `e2e:package-and-test-ee` job has either succeeded or been approved by a Software Engineer in Test.
diff --git a/.rubocop.yml b/.rubocop.yml
index f4bd7913b47..f42d7c7b076 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -13,12 +13,6 @@ inherit_from:
<% end %>
- '.rubocop_todo.yml'
<% end %>
- <% if RUBY_VERSION[/^\d+\.\d+/, 0] == '2.7' %>
- - ./rubocop/rubocop-ruby27.yml
- <% end %>
- <% if RUBY_VERSION[/^\d+\.\d+/, 0] == '3.0' %>
- - ./rubocop/rubocop-ruby30.yml
- <% end %>
<% if RUBY_VERSION[/^\d+\.\d+/, 0] == '3.1' %>
- ./rubocop/rubocop-ruby31.yml
<% end %>
@@ -36,9 +30,9 @@ inherit_mode:
- AllowedPatterns
AllCops:
- # Target the current Ruby version. For example, "2.7" or "3.0".
+ # Target the current Ruby version. For example, "3.0" or "3.1".
TargetRubyVersion: <%= RUBY_VERSION[/^\d+\.\d+/, 0] %>
- TargetRailsVersion: 6.0
+ TargetRailsVersion: 7.0
Exclude:
- 'gems/**/*'
- 'vendor/**/*'
@@ -112,9 +106,6 @@ Layout/LineLength:
- 'ee/spec/controllers/concerns/routable_actions_spec.rb'
- 'ee/spec/lib/gitlab/auth/group_saml/sso_enforcer_spec.rb'
-Lint/LastKeywordArgument:
- Safe: false
-
Lint/Debugger:
DebuggerMethods:
PryShell:
@@ -166,6 +157,11 @@ RSpec/MultipleMemoizedHelpers:
Max: 25
AllowSubject: true
+Capybara/TestidFinders:
+ Include:
+ - 'spec/features/**/*'
+ - 'ee/spec/features/**/*'
+
Naming/FileName:
ExpectMatchingDefinition: true
CheckDefinitionPathHierarchy: false
@@ -527,6 +523,8 @@ Naming/RescuedExceptionsVariableName:
RSpec/AvoidTestProf:
Include:
+ - 'spec/tasks/**/*.rb'
+ - 'ee/spec/tasks/**/*.rb'
- 'spec/migrations/**/*.rb'
- 'ee/spec/migrations/**/*.rb'
- 'spec/lib/gitlab/background_migration/**/*.rb'
@@ -581,6 +579,8 @@ RSpec/BeforeAll:
- 'ee/spec/**/*.rb'
# Conflict with RSpec/AvoidTestProf
Exclude:
+ - 'spec/tasks/**/*.rb'
+ - 'ee/spec/tasks/**/*.rb'
- 'spec/migrations/**/*.rb'
- 'ee/spec/migrations/**/*.rb'
- 'spec/lib/gitlab/background_migration/**/*.rb'
diff --git a/.rubocop_todo/capybara/testid_finders.yml b/.rubocop_todo/capybara/testid_finders.yml
new file mode 100644
index 00000000000..a1e0c7f642e
--- /dev/null
+++ b/.rubocop_todo/capybara/testid_finders.yml
@@ -0,0 +1,249 @@
+---
+Capybara/TestidFinders:
+ Exclude:
+ - 'ee/spec/features/admin/admin_dev_ops_reports_spec.rb'
+ - 'ee/spec/features/admin/admin_merge_requests_approvals_spec.rb'
+ - 'ee/spec/features/admin/admin_sends_notification_spec.rb'
+ - 'ee/spec/features/admin/admin_settings_spec.rb'
+ - 'ee/spec/features/admin/geo/admin_geo_projects_spec.rb'
+ - 'ee/spec/features/admin/groups/admin_subscription_alerts_spec.rb'
+ - 'ee/spec/features/admin/subscriptions/admin_views_subscription_spec.rb'
+ - 'ee/spec/features/billings/billing_plans_spec.rb'
+ - 'ee/spec/features/boards/boards_licensed_features_spec.rb'
+ - 'ee/spec/features/boards/boards_spec.rb'
+ - 'ee/spec/features/boards/group_boards/board_deletion_spec.rb'
+ - 'ee/spec/features/boards/new_issue_spec.rb'
+ - 'ee/spec/features/boards/scoped_issue_board_spec.rb'
+ - 'ee/spec/features/boards/sidebar_spec.rb'
+ - 'ee/spec/features/boards/swimlanes/epics_swimlanes_drag_drop_spec.rb'
+ - 'ee/spec/features/boards/swimlanes/epics_swimlanes_sidebar_labels_spec.rb'
+ - 'ee/spec/features/boards/swimlanes/epics_swimlanes_sidebar_spec.rb'
+ - 'ee/spec/features/boards/swimlanes/epics_swimlanes_spec.rb'
+ - 'ee/spec/features/boards/user_adds_lists_to_board_spec.rb'
+ - 'ee/spec/features/ci/ci_catalog_spec.rb'
+ - 'ee/spec/features/ci/ci_minutes_spec.rb'
+ - 'ee/spec/features/epic_boards/epic_boards_sidebar_spec.rb'
+ - 'ee/spec/features/epic_boards/epic_boards_spec.rb'
+ - 'ee/spec/features/epics/epic_labels_spec.rb'
+ - 'ee/spec/features/epics/epic_related_epics_spec.rb'
+ - 'ee/spec/features/epics/epic_show_spec.rb'
+ - 'ee/spec/features/epics/update_epic_spec.rb'
+ - 'ee/spec/features/gitlab_subscriptions/seat_count_alert_spec.rb'
+ - 'ee/spec/features/groups/analytics/ci_cd_analytics_spec.rb'
+ - 'ee/spec/features/groups/analytics/cycle_analytics/charts_spec.rb'
+ - 'ee/spec/features/groups/analytics/cycle_analytics/filters_and_data_spec.rb'
+ - 'ee/spec/features/groups/analytics/cycle_analytics/multiple_value_streams_spec.rb'
+ - 'ee/spec/features/groups/contribution_analytics_spec.rb'
+ - 'ee/spec/features/groups/group_roadmap_spec.rb'
+ - 'ee/spec/features/groups/group_settings_spec.rb'
+ - 'ee/spec/features/groups/iterations/user_edits_iteration_cadence_spec.rb'
+ - 'ee/spec/features/groups/security/compliance_dashboards_spec.rb'
+ - 'ee/spec/features/groups/settings/user_configures_analytics_dashboards_spec.rb'
+ - 'ee/spec/features/groups/settings/user_configures_insights_spec.rb'
+ - 'ee/spec/features/groups/settings/user_configures_vsd_aggregation_spec.rb'
+ - 'ee/spec/features/groups/show_spec.rb'
+ - 'ee/spec/features/groups/usage_quotas/pipelines_tab_spec.rb'
+ - 'ee/spec/features/groups/usage_quotas/seats_tab_spec.rb'
+ - 'ee/spec/features/incidents/incident_details_spec.rb'
+ - 'ee/spec/features/incidents/user_uploads_metric_images_spec.rb'
+ - 'ee/spec/features/issues/blocking_issues_spec.rb'
+ - 'ee/spec/features/issues/epic_in_issue_sidebar_spec.rb'
+ - 'ee/spec/features/issues/issue_sidebar_spec.rb'
+ - 'ee/spec/features/merge_request/draft_comments_spec.rb'
+ - 'ee/spec/features/merge_request/user_merges_immediately_spec.rb'
+ - 'ee/spec/features/merge_request/user_sees_approval_widget_spec.rb'
+ - 'ee/spec/features/merge_request/user_sees_status_checks_widget_spec.rb'
+ - 'ee/spec/features/merge_request/user_sets_approval_rules_spec.rb'
+ - 'ee/spec/features/merge_request/user_sets_approvers_spec.rb'
+ - 'ee/spec/features/merge_request/user_views_blocked_merge_request_spec.rb'
+ - 'ee/spec/features/merge_trains/user_adds_to_merge_train_when_pipeline_succeeds_spec.rb'
+ - 'ee/spec/features/profiles/usage_quotas_spec.rb'
+ - 'ee/spec/features/projects/analytics/visualization_designer_spec.rb'
+ - 'ee/spec/features/projects/audit_events_spec.rb'
+ - 'ee/spec/features/projects/issues/user_creates_issue_spec.rb'
+ - 'ee/spec/features/projects/jobs/blocked_deployment_job_page_spec.rb'
+ - 'ee/spec/features/projects/pipelines/pipeline_spec.rb'
+ - 'ee/spec/features/projects/product_analytics/dashboards_shared_examples.rb'
+ - 'ee/spec/features/projects/security/vulnerability_report_spec.rb'
+ - 'ee/spec/features/projects/settings/analytics/user_configures_analytics_custom_dashboards_spec.rb'
+ - 'ee/spec/features/projects/settings/ee/service_desk_setting_spec.rb'
+ - 'ee/spec/features/projects/settings/merge_requests_settings_spec.rb'
+ - 'ee/spec/features/projects/settings/pipeline_subscriptions_spec.rb'
+ - 'ee/spec/features/projects/settings/protected_environments_spec.rb'
+ - 'ee/spec/features/projects/work_items/okr_spec.rb'
+ - 'ee/spec/features/protected_branches_spec.rb'
+ - 'ee/spec/features/registrations/combined_registration_spec.rb'
+ - 'ee/spec/features/registrations/identity_verification_spec.rb'
+ - 'ee/spec/features/remote_development/workspaces_dropdown_group_spec.rb'
+ - 'ee/spec/features/remote_development/workspaces_spec.rb'
+ - 'ee/spec/features/search/elastic/group_search_spec.rb'
+ - 'ee/spec/features/search/zoekt/search_spec.rb'
+ - 'ee/spec/features/tanuki_bot_chat_spec.rb'
+ - 'ee/spec/features/trials/saas/creation_with_multiple_existing_namespace_flow_spec.rb'
+ - 'ee/spec/features/trials/show_trial_banner_spec.rb'
+ - 'spec/features/admin/admin_deploy_keys_spec.rb'
+ - 'spec/features/admin/admin_dev_ops_reports_spec.rb'
+ - 'spec/features/admin/admin_groups_spec.rb'
+ - 'spec/features/admin/admin_projects_spec.rb'
+ - 'spec/features/admin/admin_runners_spec.rb'
+ - 'spec/features/admin/admin_settings_spec.rb'
+ - 'spec/features/admin/admin_uses_repository_checks_spec.rb'
+ - 'spec/features/admin/broadcast_messages_spec.rb'
+ - 'spec/features/admin/users/user_spec.rb'
+ - 'spec/features/admin/users/users_spec.rb'
+ - 'spec/features/alert_management/alert_details_spec.rb'
+ - 'spec/features/boards/board_filters_spec.rb'
+ - 'spec/features/boards/boards_spec.rb'
+ - 'spec/features/boards/issue_ordering_spec.rb'
+ - 'spec/features/boards/new_issue_spec.rb'
+ - 'spec/features/boards/sidebar_assignee_spec.rb'
+ - 'spec/features/broadcast_messages_spec.rb'
+ - 'spec/features/callouts/registration_enabled_spec.rb'
+ - 'spec/features/clusters/create_agent_spec.rb'
+ - 'spec/features/commits_spec.rb'
+ - 'spec/features/dashboard/group_spec.rb'
+ - 'spec/features/dashboard/issues_spec.rb'
+ - 'spec/features/dashboard/merge_requests_spec.rb'
+ - 'spec/features/dashboard/milestones_spec.rb'
+ - 'spec/features/dashboard/projects_spec.rb'
+ - 'spec/features/dashboard/todos/todos_spec.rb'
+ - 'spec/features/groups/board_sidebar_spec.rb'
+ - 'spec/features/groups/board_spec.rb'
+ - 'spec/features/groups/clusters/user_spec.rb'
+ - 'spec/features/groups/dependency_proxy_spec.rb'
+ - 'spec/features/groups/group_settings_spec.rb'
+ - 'spec/features/groups/members/leave_group_spec.rb'
+ - 'spec/features/groups/members/manage_groups_spec.rb'
+ - 'spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb'
+ - 'spec/features/groups/members/search_members_spec.rb'
+ - 'spec/features/groups/members/sort_members_spec.rb'
+ - 'spec/features/groups/members/tabs_spec.rb'
+ - 'spec/features/groups/merge_requests_spec.rb'
+ - 'spec/features/groups/milestone_spec.rb'
+ - 'spec/features/groups/packages_spec.rb'
+ - 'spec/features/groups/settings/ci_cd_spec.rb'
+ - 'spec/features/groups/settings/packages_and_registries_spec.rb'
+ - 'spec/features/groups/show_spec.rb'
+ - 'spec/features/groups_spec.rb'
+ - 'spec/features/incidents/incident_details_spec.rb'
+ - 'spec/features/incidents/incident_timeline_events_spec.rb'
+ - 'spec/features/issuables/shortcuts_issuable_spec.rb'
+ - 'spec/features/issues/form_spec.rb'
+ - 'spec/features/issues/incident_issue_spec.rb'
+ - 'spec/features/issues/issue_detail_spec.rb'
+ - 'spec/features/issues/issue_sidebar_spec.rb'
+ - 'spec/features/issues/issue_state_spec.rb'
+ - 'spec/features/issues/user_creates_issue_spec.rb'
+ - 'spec/features/issues/user_edits_issue_spec.rb'
+ - 'spec/features/issues/user_resets_their_incoming_email_token_spec.rb'
+ - 'spec/features/issues/user_sees_live_update_spec.rb'
+ - 'spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb'
+ - 'spec/features/issues/user_toggles_subscription_spec.rb'
+ - 'spec/features/labels_hierarchy_spec.rb'
+ - 'spec/features/merge_request/merge_request_discussion_lock_spec.rb'
+ - 'spec/features/merge_request/user_accepts_merge_request_spec.rb'
+ - 'spec/features/merge_request/user_assigns_themselves_spec.rb'
+ - 'spec/features/merge_request/user_comments_on_diff_spec.rb'
+ - 'spec/features/merge_request/user_comments_on_whitespace_hidden_diff_spec.rb'
+ - 'spec/features/merge_request/user_creates_mr_spec.rb'
+ - 'spec/features/merge_request/user_customizes_merge_commit_message_spec.rb'
+ - 'spec/features/merge_request/user_edits_mr_spec.rb'
+ - 'spec/features/merge_request/user_expands_diff_spec.rb'
+ - 'spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb'
+ - 'spec/features/merge_request/user_manages_subscription_spec.rb'
+ - 'spec/features/merge_request/user_merges_immediately_spec.rb'
+ - 'spec/features/merge_request/user_posts_notes_spec.rb'
+ - 'spec/features/merge_request/user_resolves_conflicts_spec.rb'
+ - 'spec/features/merge_request/user_reverts_merge_request_spec.rb'
+ - 'spec/features/merge_request/user_sees_merge_widget_spec.rb'
+ - 'spec/features/merge_request/user_sees_pipelines_spec.rb'
+ - 'spec/features/merge_request/user_sees_suggest_pipeline_spec.rb'
+ - 'spec/features/merge_request/user_sees_versions_spec.rb'
+ - 'spec/features/merge_request/user_squashes_merge_request_spec.rb'
+ - 'spec/features/merge_request/user_toggles_whitespace_changes_spec.rb'
+ - 'spec/features/merge_request/user_views_open_merge_request_spec.rb'
+ - 'spec/features/milestone_spec.rb'
+ - 'spec/features/nav/new_nav_callout_spec.rb'
+ - 'spec/features/nav/new_nav_toggle_spec.rb'
+ - 'spec/features/nav/pinned_nav_items_spec.rb'
+ - 'spec/features/nav/top_nav_responsive_spec.rb'
+ - 'spec/features/nav/top_nav_spec.rb'
+ - 'spec/features/populate_new_pipeline_vars_with_params_spec.rb'
+ - 'spec/features/profile_spec.rb'
+ - 'spec/features/profiles/account_spec.rb'
+ - 'spec/features/profiles/keys_spec.rb'
+ - 'spec/features/profiles/oauth_applications_spec.rb'
+ - 'spec/features/profiles/password_spec.rb'
+ - 'spec/features/profiles/personal_access_tokens_spec.rb'
+ - 'spec/features/profiles/user_creates_comment_template_spec.rb'
+ - 'spec/features/profiles/user_deletes_comment_template_spec.rb'
+ - 'spec/features/profiles/user_edit_profile_spec.rb'
+ - 'spec/features/profiles/user_updates_comment_template_spec.rb'
+ - 'spec/features/project_group_variables_spec.rb'
+ - 'spec/features/project_variables_spec.rb'
+ - 'spec/features/projects/blobs/blame_spec.rb'
+ - 'spec/features/projects/branches/user_deletes_branch_spec.rb'
+ - 'spec/features/projects/branches_spec.rb'
+ - 'spec/features/projects/ci/editor_spec.rb'
+ - 'spec/features/projects/ci/lint_spec.rb'
+ - 'spec/features/projects/clusters/gcp_spec.rb'
+ - 'spec/features/projects/clusters/user_spec.rb'
+ - 'spec/features/projects/commit/cherry_pick_spec.rb'
+ - 'spec/features/projects/commit/user_sees_pipelines_tab_spec.rb'
+ - 'spec/features/projects/commits/user_browses_commits_spec.rb'
+ - 'spec/features/projects/compare_spec.rb'
+ - 'spec/features/projects/environments/environment_spec.rb'
+ - 'spec/features/projects/environments/environments_spec.rb'
+ - 'spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb'
+ - 'spec/features/projects/features_visibility_spec.rb'
+ - 'spec/features/projects/fork_spec.rb'
+ - 'spec/features/projects/integrations/user_activates_jira_spec.rb'
+ - 'spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb'
+ - 'spec/features/projects/jobs/permissions_spec.rb'
+ - 'spec/features/projects/jobs/user_browses_job_spec.rb'
+ - 'spec/features/projects/jobs/user_browses_jobs_spec.rb'
+ - 'spec/features/projects/jobs/user_triggers_manual_job_with_variables_spec.rb'
+ - 'spec/features/projects/jobs_spec.rb'
+ - 'spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb'
+ - 'spec/features/projects/members/groups_with_access_list_spec.rb'
+ - 'spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb'
+ - 'spec/features/projects/members/sorting_spec.rb'
+ - 'spec/features/projects/packages_spec.rb'
+ - 'spec/features/projects/pipeline_schedules_spec.rb'
+ - 'spec/features/projects/pipelines/pipeline_spec.rb'
+ - 'spec/features/projects/pipelines/pipelines_spec.rb'
+ - 'spec/features/projects/releases/user_creates_release_spec.rb'
+ - 'spec/features/projects/releases/user_views_releases_spec.rb'
+ - 'spec/features/projects/settings/merge_requests_settings_spec.rb'
+ - 'spec/features/projects/settings/monitor_settings_spec.rb'
+ - 'spec/features/projects/settings/project_settings_spec.rb'
+ - 'spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb'
+ - 'spec/features/projects/settings/registry_settings_spec.rb'
+ - 'spec/features/projects/settings/repository_settings_spec.rb'
+ - 'spec/features/projects/settings/secure_files_spec.rb'
+ - 'spec/features/projects/settings/service_desk_setting_spec.rb'
+ - 'spec/features/projects/settings/slack_application_spec.rb'
+ - 'spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb'
+ - 'spec/features/projects/settings/user_transfers_a_project_spec.rb'
+ - 'spec/features/projects/show/user_sees_collaboration_links_spec.rb'
+ - 'spec/features/projects/sub_group_issuables_spec.rb'
+ - 'spec/features/projects/terraform_spec.rb'
+ - 'spec/features/projects/tree/create_directory_spec.rb'
+ - 'spec/features/projects/tree/create_file_spec.rb'
+ - 'spec/features/projects/user_uses_shortcuts_spec.rb'
+ - 'spec/features/projects/work_items/work_item_children_spec.rb'
+ - 'spec/features/projects/work_items/work_item_spec.rb'
+ - 'spec/features/protected_branches_spec.rb'
+ - 'spec/features/runners_spec.rb'
+ - 'spec/features/search/user_searches_for_code_spec.rb'
+ - 'spec/features/search/user_searches_for_issues_spec.rb'
+ - 'spec/features/search/user_searches_for_merge_requests_spec.rb'
+ - 'spec/features/search/user_searches_for_milestones_spec.rb'
+ - 'spec/features/search/user_searches_for_wiki_pages_spec.rb'
+ - 'spec/features/search/user_uses_header_search_field_spec.rb'
+ - 'spec/features/search/user_uses_search_filters_spec.rb'
+ - 'spec/features/tags/developer_deletes_tag_spec.rb'
+ - 'spec/features/tags/maintainer_deletes_protected_tag_spec.rb'
+ - 'spec/features/triggers_spec.rb'
+ - 'spec/features/uploads/user_uploads_avatar_to_profile_spec.rb'
+ - 'spec/features/user_sees_revert_modal_spec.rb'
diff --git a/.rubocop_todo/cop/experiments_test_coverage.yml b/.rubocop_todo/cop/experiments_test_coverage.yml
index 1e347b2b466..07c47bc11a6 100644
--- a/.rubocop_todo/cop/experiments_test_coverage.yml
+++ b/.rubocop_todo/cop/experiments_test_coverage.yml
@@ -1,6 +1,5 @@
---
Cop/ExperimentsTestCoverage:
- Details: grace period
Exclude:
- 'app/controllers/groups/boards_controller.rb'
- 'app/controllers/projects/boards_controller.rb'
diff --git a/.rubocop_todo/cop/ignored_columns.yml b/.rubocop_todo/cop/ignored_columns.yml
index eaba218d385..a791fcd0d6d 100644
--- a/.rubocop_todo/cop/ignored_columns.yml
+++ b/.rubocop_todo/cop/ignored_columns.yml
@@ -1,6 +1,5 @@
---
Cop/IgnoredColumns:
- Details: grace period
Exclude:
- 'app/models/loose_foreign_keys/deleted_record.rb'
- 'ee/lib/ee/gitlab/background_migration/create_vulnerability_links.rb'
diff --git a/.rubocop_todo/factory_bot/create_list.yml b/.rubocop_todo/factory_bot/create_list.yml
index 289be6ef20b..9f6d3b19735 100644
--- a/.rubocop_todo/factory_bot/create_list.yml
+++ b/.rubocop_todo/factory_bot/create_list.yml
@@ -1,7 +1,6 @@
---
# Cop supports --autocorrect.
FactoryBot/CreateList:
- Details: grace period
Exclude:
- 'ee/spec/controllers/ee/search_controller_spec.rb'
- 'ee/spec/controllers/projects/licenses_controller_spec.rb'
diff --git a/.rubocop_todo/gitlab/doc_url.yml b/.rubocop_todo/gitlab/doc_url.yml
index 13537a142a1..ba9d066f94c 100644
--- a/.rubocop_todo/gitlab/doc_url.yml
+++ b/.rubocop_todo/gitlab/doc_url.yml
@@ -31,7 +31,7 @@ Gitlab/DocUrl:
- 'lib/gitlab/ci/config/entry/processable.rb'
- 'lib/gitlab/config_checker/external_database_checker.rb'
- 'lib/gitlab/config_checker/puma_rugged_checker.rb'
- - 'lib/gitlab/database.rb'
+ - 'lib/gitlab/database_warnings.rb'
- 'lib/gitlab/database/migration_helpers/automatic_lock_writes_on_tables.rb'
- 'lib/gitlab/database/migration_helpers/v2.rb'
- 'lib/gitlab/database/migrations/batched_background_migration_helpers.rb'
diff --git a/.rubocop_todo/gitlab/feature_available_usage.yml b/.rubocop_todo/gitlab/feature_available_usage.yml
index a0c71dec923..302bf8d17c4 100644
--- a/.rubocop_todo/gitlab/feature_available_usage.yml
+++ b/.rubocop_todo/gitlab/feature_available_usage.yml
@@ -92,8 +92,6 @@ Gitlab/FeatureAvailableUsage:
- 'ee/app/views/compliance_management/compliance_framework/_project_settings.html.haml.rb'
- 'ee/app/views/groups/epics/index.html.haml.rb'
- 'ee/app/views/product_analytics/_project_settings.html.haml.rb'
- - 'ee/app/views/projects/_merge_request_settings.html.haml.rb'
- - 'ee/app/views/projects/_merge_request_settings_description_text.html.haml.rb'
- 'ee/app/views/projects/_remove.html.haml.rb'
- 'ee/app/views/projects/audit_events/index.html.haml.rb'
- 'ee/app/views/projects/blob/_header_file_locks.html.haml.rb'
@@ -106,6 +104,8 @@ Gitlab/FeatureAvailableUsage:
- 'ee/app/views/projects/settings/ci_cd/_auto_rollback.html.haml.rb'
- 'ee/app/views/projects/settings/ci_cd/_pipeline_subscriptions.html.haml.rb'
- 'ee/app/views/projects/settings/merge_requests/_merge_request_approvals_settings.html.haml.rb'
+ - 'ee/app/views/projects/settings/merge_requests/_merge_request_settings.html.haml.rb'
+ - 'ee/app/views/projects/settings/merge_requests/_merge_request_settings_description_text.html.haml.rb'
- 'ee/app/views/projects/settings/operations/_status_page.html.haml.rb'
- 'ee/app/views/projects/settings/repository/_protected_branches.html.haml.rb'
- 'ee/app/views/protected_branches/ee/_code_owner_approval_form.html.haml.rb'
@@ -130,9 +130,7 @@ Gitlab/FeatureAvailableUsage:
- 'ee/lib/gitlab/ci/project_config/compliance.rb'
- 'ee/lib/gitlab/code_owners.rb'
- 'ee/lib/gitlab/path_locks_finder.rb'
- - 'ee/lib/incident_management/incident_sla.rb'
- 'ee/spec/models/ee/project_spec.rb'
- 'ee/spec/models/instance_security_dashboard_spec.rb'
- - 'ee/spec/models/license_spec.rb'
- 'lib/api/helpers/related_resources_helpers.rb'
- 'spec/models/concerns/featurable_spec.rb'
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml
index 4b000876d0e..4511497315b 100644
--- a/.rubocop_todo/gitlab/namespaced_class.yml
+++ b/.rubocop_todo/gitlab/namespaced_class.yml
@@ -989,8 +989,6 @@ Gitlab/NamespacedClass:
- 'ee/app/serializers/epic_note_serializer.rb'
- 'ee/app/serializers/epic_serializer.rb'
- 'ee/app/serializers/file_lock_entity.rb'
- - 'ee/app/serializers/geo_design_registry_entity.rb'
- - 'ee/app/serializers/geo_design_registry_serializer.rb'
- 'ee/app/serializers/geo_node_serializer.rb'
- 'ee/app/serializers/geo_node_status_serializer.rb'
- 'ee/app/serializers/geo_project_registry_entity.rb'
diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml
index cd58daeeab4..703c80c7667 100644
--- a/.rubocop_todo/gitlab/strong_memoize_attr.yml
+++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml
@@ -1,7 +1,6 @@
---
# Cop supports --autocorrect.
Gitlab/StrongMemoizeAttr:
- Details: grace period
Exclude:
- 'app/components/pajamas/avatar_component.rb'
- 'app/controllers/application_controller.rb'
diff --git a/.rubocop_todo/graphql/resource_not_available_error.yml b/.rubocop_todo/graphql/resource_not_available_error.yml
index 316cd4a99cb..c52cdfff6b4 100644
--- a/.rubocop_todo/graphql/resource_not_available_error.yml
+++ b/.rubocop_todo/graphql/resource_not_available_error.yml
@@ -35,7 +35,6 @@ Graphql/ResourceNotAvailableError:
- 'ee/app/graphql/mutations/ai/action.rb'
- 'ee/app/graphql/mutations/audit_events/instance_external_audit_event_destinations/base.rb'
- 'ee/app/graphql/mutations/ci/ai/generate_config.rb'
- - 'ee/app/graphql/mutations/geo/registries/update.rb'
- 'ee/app/graphql/mutations/issues/set_escalation_policy.rb'
- 'ee/app/graphql/mutations/projects/set_locked.rb'
- 'ee/app/graphql/resolvers/incident_management/oncall_shifts_resolver.rb'
diff --git a/.rubocop_todo/internal_affairs/use_restrict_on_send.yml b/.rubocop_todo/internal_affairs/use_restrict_on_send.yml
index def67cd71b1..ee5ad00d14e 100644
--- a/.rubocop_todo/internal_affairs/use_restrict_on_send.yml
+++ b/.rubocop_todo/internal_affairs/use_restrict_on_send.yml
@@ -1,6 +1,5 @@
---
InternalAffairs/UseRestrictOnSend:
- Details: grace period
Exclude:
- 'rubocop/cop/gitlab/feature_available_usage.rb'
- 'rubocop/cop/migration/add_concurrent_foreign_key.rb'
diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml
index 35923d68b93..c7b47be48fa 100644
--- a/.rubocop_todo/layout/argument_alignment.yml
+++ b/.rubocop_todo/layout/argument_alignment.yml
@@ -491,22 +491,6 @@ Layout/ArgumentAlignment:
- 'app/graphql/types/work_items/widgets/start_and_due_date_update_input_type.rb'
- 'app/graphql/types/x509_certificate_type.rb'
- 'app/graphql/types/x509_issuer_type.rb'
- - 'app/services/compare_service.rb'
- - 'app/services/concerns/rate_limited_service.rb'
- - 'app/services/design_management/copy_design_collection/copy_service.rb'
- - 'app/services/design_management/delete_designs_service.rb'
- - 'app/services/design_management/runs_design_actions.rb'
- - 'app/services/design_management/save_designs_service.rb'
- - 'app/services/error_tracking/base_service.rb'
- - 'app/services/event_create_service.rb'
- - 'app/services/files/update_service.rb'
- - 'app/services/google_cloud/create_cloudsql_instance_service.rb'
- - 'app/services/google_cloud/fetch_google_ip_list_service.rb'
- - 'app/services/issuable_base_service.rb'
- - 'app/services/issues/close_service.rb'
- - 'app/services/issues/create_service.rb'
- - 'app/services/issues/move_service.rb'
- - 'app/services/issues/referenced_merge_requests_service.rb'
- 'app/services/lfs/lock_file_service.rb'
- 'app/services/markdown_content_rewriter_service.rb'
- 'app/services/members/base_service.rb'
@@ -529,19 +513,6 @@ Layout/ArgumentAlignment:
- 'app/services/security/ci_configuration/dependency_scanning_create_service.rb'
- 'app/services/security/ci_configuration/sast_iac_create_service.rb'
- 'app/services/security/ci_configuration/secret_detection_create_service.rb'
- - 'app/services/service_response.rb'
- - 'app/services/spam/akismet_service.rb'
- - 'app/services/spam/spam_action_service.rb'
- - 'app/services/spam/spam_verdict_service.rb'
- - 'app/services/submodules/update_service.rb'
- - 'app/services/suggestions/create_service.rb'
- - 'app/services/users/activity_service.rb'
- - 'app/services/users/build_service.rb'
- - 'app/services/users/destroy_service.rb'
- - 'app/services/users/migrate_records_to_ghost_user_in_batches_service.rb'
- - 'app/services/users/refresh_authorized_projects_service.rb'
- - 'app/services/webauthn/authenticate_service.rb'
- - 'app/services/work_items/create_service.rb'
- 'app/validators/feature_flag_user_xids_validator.rb'
- 'config/application.rb'
- 'config/initializers/hashie_mash_permitted_patch.rb'
@@ -1199,35 +1170,6 @@ Layout/ArgumentAlignment:
- 'ee/spec/requests/groups/two_factor_auths_controller_spec.rb'
- 'ee/spec/requests/smartcard_controller_spec.rb'
- 'ee/spec/requests/users/identity_verification_controller_spec.rb'
- - 'ee/spec/services/analytics/cycle_analytics/aggregator_service_spec.rb'
- - 'ee/spec/services/analytics/devops_adoption/enabled_namespaces/find_or_create_service_spec.rb'
- - 'ee/spec/services/arkose/blocked_users_report_service_spec.rb'
- - 'ee/spec/services/audit_events/protected_branch_audit_event_service_spec.rb'
- - 'ee/spec/services/audit_events/streaming/event_type_filters/create_service_spec.rb'
- - 'ee/spec/services/audit_events/streaming/event_type_filters/destroy_service_spec.rb'
- - 'ee/spec/services/auto_merge/merge_train_service_spec.rb'
- - 'ee/spec/services/boards/lists/update_service_spec.rb'
- - 'ee/spec/services/ee/boards/issues/create_service_spec.rb'
- - 'ee/spec/services/ee/boards/issues/list_service_spec.rb'
- - 'ee/spec/services/ee/boards/issues/move_service_spec.rb'
- - 'ee/spec/services/ee/boards/lists/create_service_spec.rb'
- - 'ee/spec/services/ee/boards/lists/max_limits_spec.rb'
- - 'ee/spec/services/ee/incident_management/issuable_escalation_statuses/after_update_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/refresh_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/update_assignees_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/update_reviewers_service_spec.rb'
- - 'ee/spec/services/ee/notification_service_spec.rb'
- - 'ee/spec/services/ee/users/migrate_records_to_ghost_user_service_spec.rb'
- - 'ee/spec/services/ee/vulnerability_feedback_module/update_service_spec.rb'
- - 'ee/spec/services/elastic/process_bookkeeping_service_spec.rb'
- - 'ee/spec/services/epics/issue_promote_service_spec.rb'
- - 'ee/spec/services/geo/blob_upload_service_spec.rb'
- - 'ee/spec/services/geo/framework_repository_sync_service_spec.rb'
- - 'ee/spec/services/geo/hashed_storage_attachments_migration_service_spec.rb'
- - 'ee/spec/services/geo/registry_consistency_service_spec.rb'
- - 'ee/spec/services/geo/replication_toggle_request_service_spec.rb'
- - 'ee/spec/services/geo/repository_sync_service_spec.rb'
- - 'ee/spec/services/geo/wiki_sync_service_spec.rb'
- 'ee/spec/services/gitlab_subscriptions/reconciliations/check_seat_usage_alerts_eligibility_service_spec.rb'
- 'ee/spec/services/groups/compliance_report_csv_service_spec.rb'
- 'ee/spec/services/groups/mark_for_deletion_service_spec.rb'
@@ -1879,43 +1821,6 @@ Layout/ArgumentAlignment:
- 'spec/rubocop/cop/rspec/env_mocking_spec.rb'
- 'spec/rubocop/cop/style/regexp_literal_mixed_preserve_spec.rb'
- 'spec/rubocop/formatter/graceful_formatter_spec.rb'
- - 'spec/services/design_management/save_designs_service_spec.rb'
- - 'spec/services/discussions/resolve_service_spec.rb'
- - 'spec/services/draft_notes/publish_service_spec.rb'
- - 'spec/services/environments/stop_service_spec.rb'
- - 'spec/services/environments/stop_stale_service_spec.rb'
- - 'spec/services/files/delete_service_spec.rb'
- - 'spec/services/files/update_service_spec.rb'
- - 'spec/services/git/branch_push_service_spec.rb'
- - 'spec/services/google_cloud/create_cloudsql_instance_service_spec.rb'
- - 'spec/services/google_cloud/fetch_google_ip_list_service_spec.rb'
- - 'spec/services/google_cloud/generate_pipeline_service_spec.rb'
- - 'spec/services/google_cloud/get_cloudsql_instances_service_spec.rb'
- - 'spec/services/groups/destroy_service_spec.rb'
- - 'spec/services/groups/group_links/create_service_spec.rb'
- - 'spec/services/import_export_clean_up_service_spec.rb'
- - 'spec/services/issuable/process_assignees_spec.rb'
- - 'spec/services/issue_links/list_service_spec.rb'
- - 'spec/services/issues/create_service_spec.rb'
- - 'spec/services/issues/export_csv_service_spec.rb'
- - 'spec/services/issues/move_service_spec.rb'
- - 'spec/services/issues/resolve_discussions_spec.rb'
- - 'spec/services/issues/update_service_spec.rb'
- - 'spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb'
- - 'spec/services/metrics/dashboard/clone_dashboard_service_spec.rb'
- - 'spec/services/note_summary_spec.rb'
- - 'spec/services/notification_service_spec.rb'
- - 'spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb'
- - 'spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb'
- - 'spec/services/preview_markdown_service_spec.rb'
- - 'spec/services/protected_branches/api_service_spec.rb'
- - 'spec/services/push_event_payload_service_spec.rb'
- - 'spec/services/quick_actions/interpret_service_spec.rb'
- - 'spec/services/releases/destroy_service_spec.rb'
- - 'spec/services/resource_access_tokens/revoke_service_spec.rb'
- - 'spec/services/resource_events/merge_into_notes_service_spec.rb'
- - 'spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb'
- - 'spec/services/security/merge_reports_service_spec.rb'
- 'spec/sidekiq/cron/job_gem_dependency_spec.rb'
- 'spec/support/shared_examples/initializers/uses_gitlab_url_blocker_shared_examples.rb'
- 'spec/support/shared_examples/integrations/integration_settings_form.rb'
diff --git a/.rubocop_todo/layout/empty_line_after_magic_comment.yml b/.rubocop_todo/layout/empty_line_after_magic_comment.yml
index 698247e419c..35cd5f9135d 100644
--- a/.rubocop_todo/layout/empty_line_after_magic_comment.yml
+++ b/.rubocop_todo/layout/empty_line_after_magic_comment.yml
@@ -256,7 +256,6 @@ Layout/EmptyLineAfterMagicComment:
- 'ee/lib/ee/gitlab/ci/parsers/security/validators/schema_validator.rb'
- 'ee/lib/ee/gitlab/hook_data/group_member_builder.rb'
- 'ee/lib/ee/gitlab/hook_data/issue_builder.rb'
- - 'ee/lib/ee/gitlab/hook_data/user_builder.rb'
- 'ee/lib/ee/gitlab/scim/base_deprovisioning_service.rb'
- 'ee/lib/ee/gitlab/scim/base_provisioning_service.rb'
- 'ee/lib/ee/gitlab/scim/provisioning_service.rb'
@@ -290,7 +289,6 @@ Layout/EmptyLineAfterMagicComment:
- 'ee/spec/features/projects/settings/merge_request_approvals_settings_spec.rb'
- 'ee/spec/features/projects/settings/merge_requests_settings_spec.rb'
- 'ee/spec/finders/auth/group_saml_identity_finder_spec.rb'
- - 'ee/spec/finders/geo/design_registry_finder_spec.rb'
- 'ee/spec/finders/geo/project_registry_status_finder_spec.rb'
- 'ee/spec/frontend/fixtures/analytics/charts.rb'
- 'ee/spec/frontend/fixtures/analytics/metrics.rb'
@@ -318,7 +316,6 @@ Layout/EmptyLineAfterMagicComment:
- 'ee/spec/graphql/mutations/vulnerabilities/revert_to_detected_spec.rb'
- 'ee/spec/helpers/ee/auth_helper_spec.rb'
- 'ee/spec/helpers/ee/geo_helper_spec.rb'
- - 'ee/spec/helpers/ee/invite_members_helper_spec.rb'
- 'ee/spec/helpers/ee/namespaces_helper_spec.rb'
- 'ee/spec/helpers/ee/saml_providers_helper_spec.rb'
- 'ee/spec/helpers/roadmaps_helper_spec.rb'
@@ -332,7 +329,6 @@ Layout/EmptyLineAfterMagicComment:
- 'ee/spec/lib/ee/gitlab/git_access_snippet_spec.rb'
- 'ee/spec/lib/ee/gitlab/hook_data/group_member_builder_spec.rb'
- 'ee/spec/lib/ee/gitlab/hook_data/issue_builder_spec.rb'
- - 'ee/spec/lib/ee/gitlab/hook_data/user_builder_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/project/tree_restorer_spec.rb'
- 'ee/spec/lib/ee/gitlab/snippet_search_results_spec.rb'
- 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/group/stage_summary_spec.rb'
diff --git a/.rubocop_todo/layout/extra_spacing.yml b/.rubocop_todo/layout/extra_spacing.yml
deleted file mode 100644
index 6da17195834..00000000000
--- a/.rubocop_todo/layout/extra_spacing.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-# Cop supports --autocorrect.
-Layout/ExtraSpacing:
- Details: grace period
- Exclude:
- - 'ee/spec/requests/api/debian_project_packages_spec.rb'
- - 'spec/serializers/admin/abuse_report_details_entity_spec.rb'
- - 'spec/services/bulk_imports/create_service_spec.rb'
diff --git a/.rubocop_todo/layout/first_hash_element_indentation.yml b/.rubocop_todo/layout/first_hash_element_indentation.yml
index 5f586cc6206..893a6d2242b 100644
--- a/.rubocop_todo/layout/first_hash_element_indentation.yml
+++ b/.rubocop_todo/layout/first_hash_element_indentation.yml
@@ -229,7 +229,6 @@ Layout/FirstHashElementIndentation:
- 'spec/requests/api/ml/mlflow_spec.rb'
- 'spec/requests/api/releases_spec.rb'
- 'spec/requests/api/task_completion_status_spec.rb'
- - 'spec/requests/groups/email_campaigns_controller_spec.rb'
- 'spec/requests/pwa_controller_spec.rb'
- 'spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb'
- 'spec/rubocop/cop/usage_data/histogram_with_large_table_spec.rb'
diff --git a/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml b/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml
index 53954249ed4..0253613849e 100644
--- a/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml
+++ b/.rubocop_todo/layout/line_end_string_concatenation_indentation.yml
@@ -125,6 +125,7 @@ Layout/LineEndStringConcatenationIndentation:
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_deployment_approvals_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/protected_environment_approval_rules_required_approvals_average_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/protected_environments_required_approvals_average_metric_spec.rb'
+ - 'ee/spec/lib/remote_development/workspaces/reconcile/input/actual_state_calculator_spec.rb'
- 'ee/spec/mailers/ee/emails/identity_verification_spec.rb'
- 'ee/spec/requests/api/analytics/product_analytics_spec.rb'
- 'ee/spec/requests/api/graphql/mutations/boards/lists/update_limit_metrics_spec.rb'
@@ -141,6 +142,7 @@ Layout/LineEndStringConcatenationIndentation:
- 'ee/spec/services/geo/container_repository_sync_spec.rb'
- 'ee/spec/services/merge_trains/create_pipeline_service_spec.rb'
- 'ee/spec/services/users/abuse/git_abuse/application_throttle_service_spec.rb'
+ - 'ee/spec/support/shared_contexts/remote_development/remote_development_shared_contexts.rb'
- 'ee/spec/support/shared_examples/finders/geo/framework_registry_finder_shared_examples.rb'
- 'ee/spec/support/shared_examples/graphql/geo/geo_registries_resolver_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/license_shared_examples.rb'
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index 162afb96a09..9fd3d47d8f0 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -34,7 +34,6 @@ Layout/LineLength:
- 'app/controllers/dashboard/todos_controller.rb'
- 'app/controllers/explore/projects_controller.rb'
- 'app/controllers/groups/dependency_proxy_for_containers_controller.rb'
- - 'app/controllers/groups/email_campaigns_controller.rb'
- 'app/controllers/groups/group_members_controller.rb'
- 'app/controllers/groups/settings/applications_controller.rb'
- 'app/controllers/groups/settings/ci_cd_controller.rb'
@@ -346,7 +345,6 @@ Layout/LineLength:
- 'app/models/integrations/base_chat_notification.rb'
- 'app/models/integrations/base_issue_tracker.rb'
- 'app/models/integrations/bugzilla.rb'
- - 'app/models/integrations/campfire.rb'
- 'app/models/integrations/chat_message/deployment_message.rb'
- 'app/models/integrations/chat_message/merge_message.rb'
- 'app/models/integrations/chat_message/note_message.rb'
@@ -690,7 +688,6 @@ Layout/LineLength:
- 'config/initializers/kaminari_active_record_relation_methods_with_limit.rb'
- 'config/initializers/pages_storage_check.rb'
- 'config/initializers/rails_host_authorization.rb'
- - 'config/initializers/session_store.rb'
- 'config/initializers/validate_database_config.rb'
- 'config/initializers/validate_puma.rb'
- 'config/initializers/zz_metrics.rb'
@@ -714,7 +711,6 @@ Layout/LineLength:
- 'danger/z_metadata/Dangerfile'
- 'ee/app/controllers/admin/elasticsearch_controller.rb'
- 'ee/app/controllers/admin/geo/application_controller.rb'
- - 'ee/app/controllers/admin/geo/projects_controller.rb'
- 'ee/app/controllers/admin/licenses_controller.rb'
- 'ee/app/controllers/concerns/audit_events/date_range.rb'
- 'ee/app/controllers/concerns/credentials_inventory_actions.rb'
@@ -1305,7 +1301,6 @@ Layout/LineLength:
- 'ee/lib/tasks/gitlab/seed/metrics.rake'
- 'ee/lib/world.rb'
- 'ee/spec/controllers/admin/elasticsearch_controller_spec.rb'
- - 'ee/spec/controllers/admin/geo/projects_controller_spec.rb'
- 'ee/spec/controllers/admin/impersonations_controller_spec.rb'
- 'ee/spec/controllers/admin/licenses_controller_spec.rb'
- 'ee/spec/controllers/admin/projects_controller_spec.rb'
@@ -4501,7 +4496,6 @@ Layout/LineLength:
- 'spec/requests/api/v3/github_spec.rb'
- 'spec/requests/dashboard_controller_spec.rb'
- 'spec/requests/git_http_spec.rb'
- - 'spec/requests/groups/email_campaigns_controller_spec.rb'
- 'spec/requests/groups/milestones_controller_spec.rb'
- 'spec/requests/groups/settings/access_tokens_controller_spec.rb'
- 'spec/requests/groups_controller_spec.rb'
@@ -4724,7 +4718,6 @@ Layout/LineLength:
- 'spec/services/metrics/users_starred_dashboards/delete_service_spec.rb'
- 'spec/services/milestones/transfer_service_spec.rb'
- 'spec/services/namespace_settings/update_service_spec.rb'
- - 'spec/services/namespaces/in_product_marketing_emails_service_spec.rb'
- 'spec/services/notes/build_service_spec.rb'
- 'spec/services/notes/copy_service_spec.rb'
- 'spec/services/notes/create_service_spec.rb'
diff --git a/.rubocop_todo/layout/space_in_lambda_literal.yml b/.rubocop_todo/layout/space_in_lambda_literal.yml
index 01189989eec..54ed188fd26 100644
--- a/.rubocop_todo/layout/space_in_lambda_literal.yml
+++ b/.rubocop_todo/layout/space_in_lambda_literal.yml
@@ -79,7 +79,6 @@ Layout/SpaceInLambdaLiteral:
- 'app/models/packages/maven/metadatum.rb'
- 'app/models/packages/package.rb'
- 'app/models/packages/tag.rb'
- - 'app/models/pages_deployment.rb'
- 'app/models/personal_access_token.rb'
- 'app/models/project.rb'
- 'app/models/project_daily_statistic.rb'
diff --git a/.rubocop_todo/lint/assignment_in_condition.yml b/.rubocop_todo/lint/assignment_in_condition.yml
index 0d893f4c1a0..69470c7d5f0 100644
--- a/.rubocop_todo/lint/assignment_in_condition.yml
+++ b/.rubocop_todo/lint/assignment_in_condition.yml
@@ -1,7 +1,6 @@
---
# Cop supports --autocorrect.
Lint/AssignmentInCondition:
- Details: grace period
Exclude:
- 'app/controllers/concerns/uploads_actions.rb'
- 'app/controllers/concerns/verifies_with_email.rb'
@@ -88,7 +87,6 @@ Lint/AssignmentInCondition:
- 'app/workers/concerns/gitlab/bitbucket_server_import/stage_methods.rb'
- 'app/workers/concerns/gitlab/github_import/object_importer.rb'
- 'app/workers/concerns/gitlab/github_import/stage_methods.rb'
- - 'app/workers/concerns/gitlab/notify_upon_death.rb'
- 'app/workers/deployments/hooks_worker.rb'
- 'app/workers/deployments/link_merge_request_worker.rb'
- 'app/workers/gitlab/github_gists_import/import_gist_worker.rb'
@@ -138,7 +136,7 @@ Lint/AssignmentInCondition:
- 'ee/lib/ee/gitlab/repo_path.rb'
- 'ee/lib/gem_extensions/elasticsearch/model/indexing/instance_methods.rb'
- 'ee/lib/gitlab/group_plans_preloader.rb'
- - 'ee/lib/gitlab/llm/content_parser.rb'
+ - 'ee/lib/gitlab/llm/embeddings/utils/base_content_parser.rb'
- 'ee/lib/gitlab/path_locks_finder.rb'
- 'ee/lib/gitlab/subscription_portal/clients/graphql.rb'
- 'ee/lib/system_check/geo/authorized_keys_check.rb'
diff --git a/.rubocop_todo/lint/redundant_cop_disable_directive.yml b/.rubocop_todo/lint/redundant_cop_disable_directive.yml
index 7a07242ab29..38ea0ea12e6 100644
--- a/.rubocop_todo/lint/redundant_cop_disable_directive.yml
+++ b/.rubocop_todo/lint/redundant_cop_disable_directive.yml
@@ -123,7 +123,6 @@ Lint/RedundantCopDisableDirective:
- 'ee/app/services/ee/search_service.rb'
- 'ee/app/services/security/token_revocation_service.rb'
- 'ee/app/workers/ee/issuable_export_csv_worker.rb'
- - 'ee/app/workers/ee/namespaces/in_product_marketing_emails_worker.rb'
- 'ee/app/workers/geo/design_repository_shard_sync_worker.rb'
- 'ee/app/workers/geo/repository_shard_sync_worker.rb'
- 'ee/app/workers/geo/repository_verification/secondary/shard_worker.rb'
diff --git a/.rubocop_todo/lint/redundant_safe_navigation.yml b/.rubocop_todo/lint/redundant_safe_navigation.yml
index 8c4b66313eb..2fda82208fe 100644
--- a/.rubocop_todo/lint/redundant_safe_navigation.yml
+++ b/.rubocop_todo/lint/redundant_safe_navigation.yml
@@ -1,7 +1,6 @@
---
# Cop supports --autocorrect.
Lint/RedundantSafeNavigation:
- Details: grace period
Exclude:
- 'app/controllers/import/base_controller.rb'
- 'app/graphql/resolvers/users_resolver.rb'
diff --git a/.rubocop_todo/lint/redundant_string_coercion.yml b/.rubocop_todo/lint/redundant_string_coercion.yml
index 8d9bb93395b..2663e0420b3 100644
--- a/.rubocop_todo/lint/redundant_string_coercion.yml
+++ b/.rubocop_todo/lint/redundant_string_coercion.yml
@@ -1,7 +1,6 @@
---
# Cop supports --autocorrect.
Lint/RedundantStringCoercion:
- Details: grace period
Exclude:
- 'ee/bin/geo_log_cursor'
- 'ee/db/fixtures/development/31_devops_adoption.rb'
diff --git a/.rubocop_todo/migration/avoid_finalize_background_migration.yml b/.rubocop_todo/migration/avoid_finalize_background_migration.yml
index bde85ce3e48..89adc410f22 100644
--- a/.rubocop_todo/migration/avoid_finalize_background_migration.yml
+++ b/.rubocop_todo/migration/avoid_finalize_background_migration.yml
@@ -1,6 +1,5 @@
---
Migration/AvoidFinalizeBackgroundMigration:
- Details: grace period
Exclude:
- 'db/post_migrate/20220502015011_clean_up_fix_merge_request_diff_commit_users.rb'
- 'db/post_migrate/20220525131557_cleanup_backfill_integrations_enable_ssl_verification.rb'
diff --git a/.rubocop_todo/naming/heredoc_delimiter_naming.yml b/.rubocop_todo/naming/heredoc_delimiter_naming.yml
index 68129f910d1..fa60792bbdc 100644
--- a/.rubocop_todo/naming/heredoc_delimiter_naming.yml
+++ b/.rubocop_todo/naming/heredoc_delimiter_naming.yml
@@ -30,7 +30,6 @@ Naming/HeredocDelimiterNaming:
- 'lib/feature/shared.rb'
- 'lib/gitlab/cache/import/caching.rb'
- 'lib/gitlab/conflict/file_collection.rb'
- - 'lib/gitlab/database.rb'
- 'lib/gitlab/database/migration_helpers.rb'
- 'lib/gitlab/database/migration_helpers/v2.rb'
- 'lib/gitlab/exclusive_lease.rb'
diff --git a/.rubocop_todo/performance/regexp_match.yml b/.rubocop_todo/performance/regexp_match.yml
index 0248938c84b..b4a21bfe40a 100644
--- a/.rubocop_todo/performance/regexp_match.yml
+++ b/.rubocop_todo/performance/regexp_match.yml
@@ -1,7 +1,6 @@
---
# Cop supports --autocorrect.
Performance/RegexpMatch:
- Details: grace period
Exclude:
- 'config/initializers/wikicloth_redos_patch.rb'
- 'ee/app/controllers/concerns/audit_events/enforces_valid_date_params.rb'
diff --git a/.rubocop_todo/rails/output_safety.yml b/.rubocop_todo/rails/output_safety.yml
index cc2f52a3ddc..85388e8a1da 100644
--- a/.rubocop_todo/rails/output_safety.yml
+++ b/.rubocop_todo/rails/output_safety.yml
@@ -1,6 +1,5 @@
---
Rails/OutputSafety:
- Details: grace period
Exclude:
- 'app/controllers/concerns/confirm_email_warning.rb'
- 'app/controllers/concerns/web_hooks/hook_actions.rb'
diff --git a/.rubocop_todo/rails/time_zone.yml b/.rubocop_todo/rails/time_zone.yml
index 00e8150585d..01dcb78bdce 100644
--- a/.rubocop_todo/rails/time_zone.yml
+++ b/.rubocop_todo/rails/time_zone.yml
@@ -5,13 +5,11 @@ Rails/TimeZone:
- 'ee/lib/delay.rb'
- 'ee/lib/gitlab/elastic/indexer.rb'
- 'ee/lib/gitlab/geo/event_gap_tracking.rb'
- - 'ee/lib/gitlab/geo/log_cursor/events/design_repository_updated_event.rb'
- 'ee/lib/gitlab/geo/log_cursor/events/repository_updated_event.rb'
- 'ee/lib/gitlab/geo/log_cursor/logger.rb'
- 'ee/lib/gitlab/geo/oauth/login_state.rb'
- 'ee/spec/lib/gitlab/geo/base_request_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/cache_invalidation_event_spec.rb'
- - 'ee/spec/lib/gitlab/geo/log_cursor/events/design_repository_updated_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/hashed_storage_attachments_event_spec.rb'
- 'ee/spec/lib/gitlab/geo/log_cursor/events/hashed_storage_migrated_event_spec.rb'
diff --git a/.rubocop_todo/rspec/before_all.yml b/.rubocop_todo/rspec/before_all.yml
index e7c57db9996..f1b7ac64bdd 100644
--- a/.rubocop_todo/rspec/before_all.yml
+++ b/.rubocop_todo/rspec/before_all.yml
@@ -1,6 +1,5 @@
---
# Cop supports --autocorrect.
RSpec/BeforeAll:
- Details: grace period
Exclude:
- 'ee/spec/support/shared_examples/finders/security/findings_finder_shared_examples.rb'
diff --git a/.rubocop_todo/rspec/before_all_role_assignment.yml b/.rubocop_todo/rspec/before_all_role_assignment.yml
index c74c0d93813..cc0781a337e 100644
--- a/.rubocop_todo/rspec/before_all_role_assignment.yml
+++ b/.rubocop_todo/rspec/before_all_role_assignment.yml
@@ -1,6 +1,5 @@
---
RSpec/BeforeAllRoleAssignment:
- Details: grace period
Exclude:
- 'ee/spec/components/namespaces/free_user_cap/non_owner_notification_alert_component_spec.rb'
- 'ee/spec/components/namespaces/free_user_cap/notification_alert_component_spec.rb'
@@ -1380,7 +1379,6 @@ RSpec/BeforeAllRoleAssignment:
- 'spec/requests/api/wikis_spec.rb'
- 'spec/requests/concerns/planning_hierarchy_spec.rb'
- 'spec/requests/groups/deploy_tokens_controller_spec.rb'
- - 'spec/requests/groups/email_campaigns_controller_spec.rb'
- 'spec/requests/groups/settings/access_tokens_controller_spec.rb'
- 'spec/requests/groups/settings/applications_controller_spec.rb'
- 'spec/requests/groups/usage_quotas_controller_spec.rb'
@@ -1505,7 +1503,6 @@ RSpec/BeforeAllRoleAssignment:
- 'spec/services/metrics/dashboard/system_dashboard_service_spec.rb'
- 'spec/services/metrics/dashboard/transient_embed_service_spec.rb'
- 'spec/services/metrics/dashboard/update_dashboard_service_spec.rb'
- - 'spec/services/namespaces/in_product_marketing_emails_service_spec.rb'
- 'spec/services/notes/build_service_spec.rb'
- 'spec/services/notes/create_service_spec.rb'
- 'spec/services/notes/quick_actions_service_spec.rb'
diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml
index ec3ac9ff220..9f6b07c397e 100644
--- a/.rubocop_todo/rspec/context_wording.yml
+++ b/.rubocop_todo/rspec/context_wording.yml
@@ -1,12 +1,10 @@
---
RSpec/ContextWording:
- Details: grace period
Exclude:
- 'ee/spec/controllers/admin/application_settings_controller_spec.rb'
- 'ee/spec/controllers/admin/audit_logs_controller_spec.rb'
- 'ee/spec/controllers/admin/dev_ops_report_controller_spec.rb'
- 'ee/spec/controllers/admin/emails_controller_spec.rb'
- - 'ee/spec/controllers/admin/geo/projects_controller_spec.rb'
- 'ee/spec/controllers/admin/licenses_controller_spec.rb'
- 'ee/spec/controllers/admin/push_rules_controller_spec.rb'
- 'ee/spec/controllers/admin/users_controller_spec.rb'
@@ -63,7 +61,6 @@ RSpec/ContextWording:
- 'ee/spec/controllers/security/dashboard_controller_spec.rb'
- 'ee/spec/controllers/security/vulnerabilities_controller_spec.rb'
- 'ee/spec/controllers/subscriptions_controller_spec.rb'
- - 'ee/spec/controllers/trial_registrations_controller_spec.rb'
- 'ee/spec/controllers/users_controller_spec.rb'
- 'ee/spec/elastic/migrate/migration_shared_examples.rb'
- 'ee/spec/elastic_integration/global_search_spec.rb'
@@ -312,7 +309,6 @@ RSpec/ContextWording:
- 'ee/spec/lib/ee/gitlab/gon_helper_spec.rb'
- 'ee/spec/lib/ee/gitlab/group_search_results_spec.rb'
- 'ee/spec/lib/ee/gitlab/hook_data/group_member_builder_spec.rb'
- - 'ee/spec/lib/ee/gitlab/hook_data/user_builder_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/group/tree_restorer_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/group/tree_saver_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/project/tree_saver_spec.rb'
@@ -460,13 +456,11 @@ RSpec/ContextWording:
- 'ee/spec/models/epic_issue_spec.rb'
- 'ee/spec/models/epic_spec.rb'
- 'ee/spec/models/geo/container_repository_registry_spec.rb'
- - 'ee/spec/models/geo/design_registry_spec.rb'
- 'ee/spec/models/geo/project_registry_spec.rb'
- 'ee/spec/models/geo/secondary_usage_data_spec.rb'
- 'ee/spec/models/geo_node_spec.rb'
- 'ee/spec/models/geo_node_status_spec.rb'
- 'ee/spec/models/gitlab_subscription_spec.rb'
- - 'ee/spec/models/gitlab_subscriptions/features_spec.rb'
- 'ee/spec/models/group_member_spec.rb'
- 'ee/spec/models/group_wiki_repository_spec.rb'
- 'ee/spec/models/incident_management/escalation_rule_spec.rb'
@@ -738,7 +732,6 @@ RSpec/ContextWording:
- 'ee/spec/services/geo/repository_sync_service_spec.rb'
- 'ee/spec/services/geo/repository_verification_reset_spec.rb'
- 'ee/spec/services/geo/wiki_sync_service_spec.rb'
- - 'ee/spec/services/gitlab_subscriptions/create_hand_raise_lead_service_spec.rb'
- 'ee/spec/services/gitlab_subscriptions/create_service_spec.rb'
- 'ee/spec/services/gitlab_subscriptions/preview_billable_user_change_service_spec.rb'
- 'ee/spec/services/group_saml/group_managed_accounts/transfer_membership_service_spec.rb'
@@ -2523,7 +2516,6 @@ RSpec/ContextWording:
- 'spec/requests/projects/usage_quotas_spec.rb'
- 'spec/requests/projects_controller_spec.rb'
- 'spec/requests/rack_attack_global_spec.rb'
- - 'spec/requests/sessions_spec.rb'
- 'spec/requests/users_controller_spec.rb'
- 'spec/routing/git_http_routing_spec.rb'
- 'spec/routing/group_routing_spec.rb'
diff --git a/.rubocop_todo/rspec/expect_in_hook.yml b/.rubocop_todo/rspec/expect_in_hook.yml
index b0369d5180d..86f2a5abd41 100644
--- a/.rubocop_todo/rspec/expect_in_hook.yml
+++ b/.rubocop_todo/rspec/expect_in_hook.yml
@@ -28,7 +28,6 @@ RSpec/ExpectInHook:
- 'ee/spec/lib/ee/api/helpers/members_helpers_spec.rb'
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb'
- 'ee/spec/lib/ee/gitlab/gon_helper_spec.rb'
- - 'ee/spec/lib/ee/gitlab/hook_data/user_builder_spec.rb'
- 'ee/spec/lib/gitlab/auth/smartcard/certificate_spec.rb'
- 'ee/spec/lib/gitlab/checks/diff_check_spec.rb'
- 'ee/spec/lib/gitlab/ci/minutes/cost_factor_spec.rb'
@@ -69,7 +68,6 @@ RSpec/ExpectInHook:
- 'ee/spec/services/geo/blob_download_service_spec.rb'
- 'ee/spec/services/geo/project_housekeeping_service_spec.rb'
- 'ee/spec/services/geo/registry_consistency_service_spec.rb'
- - 'ee/spec/services/gitlab_subscriptions/create_hand_raise_lead_service_spec.rb'
- 'ee/spec/services/gitlab_subscriptions/fetch_subscription_plans_service_spec.rb'
- 'ee/spec/services/gitlab_subscriptions/plan_upgrade_service_spec.rb'
- 'ee/spec/services/gitlab_subscriptions/reconciliations/calculate_seat_count_data_service_spec.rb'
diff --git a/.rubocop_todo/rspec/factory_bot/excessive_create_list.yml b/.rubocop_todo/rspec/factory_bot/excessive_create_list.yml
index 640b0c7f400..009e60b5129 100644
--- a/.rubocop_todo/rspec/factory_bot/excessive_create_list.yml
+++ b/.rubocop_todo/rspec/factory_bot/excessive_create_list.yml
@@ -1,6 +1,5 @@
---
RSpec/FactoryBot/ExcessiveCreateList:
- Details: grace period
Exclude:
- 'ee/spec/controllers/groups/hooks_controller_spec.rb'
- 'ee/spec/features/search/elastic/global_search_spec.rb'
diff --git a/.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml b/.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml
index 732bfd246cf..696ada420c4 100644
--- a/.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml
+++ b/.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml
@@ -7,7 +7,6 @@ RSpec/FactoryBot/StrategyInCallback:
- 'ee/spec/factories/description_version.rb'
- 'ee/spec/factories/elastic/reindexing_tasks.rb'
- 'ee/spec/factories/epic_issues.rb'
- - 'ee/spec/factories/geo/design_registry.rb'
- 'ee/spec/factories/geo_nodes.rb'
- 'ee/spec/factories/groups.rb'
- 'ee/spec/factories/merge_requests.rb'
diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml
index 0d625f92c3f..4cc8ee1210c 100644
--- a/.rubocop_todo/rspec/missing_feature_category.yml
+++ b/.rubocop_todo/rspec/missing_feature_category.yml
@@ -11,7 +11,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
- 'ee/spec/controllers/projects/pipelines_controller_spec.rb'
- 'ee/spec/controllers/projects/security/configuration_controller_spec.rb'
- - 'ee/spec/controllers/projects_controller_spec.rb'
- 'ee/spec/controllers/users_controller_spec.rb'
- 'ee/spec/db/production/license_spec.rb'
- 'ee/spec/elastic/migrate/20201105181100_apply_max_analyzed_offset_spec.rb'
@@ -516,7 +515,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/helpers/security_helper_spec.rb'
- 'ee/spec/helpers/subscriptions_helper_spec.rb'
- 'ee/spec/helpers/timeboxes_helper_spec.rb'
- - 'ee/spec/helpers/trial_registrations/reassurances_helper_spec.rb'
- 'ee/spec/helpers/users/identity_verification_helper_spec.rb'
- 'ee/spec/initializers/1_settings_spec.rb'
- 'ee/spec/initializers/database_config_spec.rb'
@@ -660,8 +658,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/ee/gitlab/group_search_results_spec.rb'
- 'ee/spec/lib/ee/gitlab/hook_data/group_member_builder_spec.rb'
- 'ee/spec/lib/ee/gitlab/hook_data/issue_builder_spec.rb'
- - 'ee/spec/lib/ee/gitlab/hook_data/user_builder_spec.rb'
- - 'ee/spec/lib/ee/gitlab/import_export/after_export_strategies/custom_template_export_import_strategy_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/group/tree_restorer_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/group/tree_saver_spec.rb'
- 'ee/spec/lib/ee/gitlab/import_export/project/tree_saver_spec.rb'
@@ -852,7 +848,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/import_export/group/relation_factory_spec.rb'
- 'ee/spec/lib/gitlab/import_export/project/object_builder_spec.rb'
- 'ee/spec/lib/gitlab/import_export/project/relation_factory_spec.rb'
- - 'ee/spec/lib/gitlab/import_sources_spec.rb'
- 'ee/spec/lib/gitlab/incident_management_spec.rb'
- 'ee/spec/lib/gitlab/ingestion/bulk_insertable_task_spec.rb'
- 'ee/spec/lib/gitlab/insights/executors/issuable_executor_spec.rb'
@@ -1455,8 +1450,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/projects/after_rename_service_spec.rb'
- 'ee/spec/services/projects/alerting/notify_service_spec.rb'
- 'ee/spec/services/projects/cleanup_service_spec.rb'
- - 'ee/spec/services/projects/create_from_template_service_spec.rb'
- - 'ee/spec/services/projects/create_service_spec.rb'
- 'ee/spec/services/projects/disable_deploy_key_service_spec.rb'
- 'ee/spec/services/projects/disable_legacy_inactive_projects_service_spec.rb'
- 'ee/spec/services/projects/enable_deploy_key_service_spec.rb'
@@ -1526,7 +1519,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/views/operations/environments.html.haml_spec.rb'
- 'ee/spec/views/operations/index.html.haml_spec.rb'
- 'ee/spec/views/profiles/preferences/show.html.haml_spec.rb'
- - 'ee/spec/views/projects/_merge_request_status_checks_settings.html.haml_spec.rb'
- 'ee/spec/views/projects/edit.html.haml_spec.rb'
- 'ee/spec/views/projects/issues/show.html.haml_spec.rb'
- 'ee/spec/views/projects/security/corpus_management/show.html.haml_spec.rb'
@@ -1539,6 +1531,7 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/views/projects/security/policies/index.html.haml_spec.rb'
- 'ee/spec/views/projects/security/sast_configuration/show.html.haml_spec.rb'
- 'ee/spec/views/projects/settings/merge_requests/_merge_request_approvals.html.haml_spec.rb'
+ - 'ee/spec/views/projects/settings/merge_requests/_merge_request_status_checks_settings.html.haml_spec.rb'
- 'ee/spec/views/projects/settings/subscriptions/_index.html.haml_spec.rb'
- 'ee/spec/views/shared/_clone_panel.html.haml_spec.rb'
- 'ee/spec/views/shared/_kerberos_clone_button.html.haml_spec.rb'
@@ -2744,7 +2737,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/bulk_imports/common/extractors/ndjson_extractor_spec.rb'
- 'spec/lib/bulk_imports/common/extractors/rest_extractor_spec.rb'
- 'spec/lib/bulk_imports/common/pipelines/badges_pipeline_spec.rb'
- - 'spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb'
- 'spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb'
- 'spec/lib/bulk_imports/common/pipelines/members_pipeline_spec.rb'
- 'spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb'
@@ -2760,10 +2752,8 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/bulk_imports/groups/pipelines/namespace_settings_pipeline_spec.rb'
- 'spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb'
- 'spec/lib/bulk_imports/groups/transformers/subgroup_to_entity_transformer_spec.rb'
- - 'spec/lib/bulk_imports/network_error_spec.rb'
- 'spec/lib/bulk_imports/pipeline/context_spec.rb'
- 'spec/lib/bulk_imports/pipeline/extracted_data_spec.rb'
- - 'spec/lib/bulk_imports/pipeline/runner_spec.rb'
- 'spec/lib/bulk_imports/pipeline_spec.rb'
- 'spec/lib/bulk_imports/projects/graphql/get_project_query_spec.rb'
- 'spec/lib/bulk_imports/projects/graphql/get_repository_query_spec.rb'
@@ -3402,12 +3392,9 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/database/migrations/test_background_runner_spec.rb'
- 'spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb'
- 'spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/partition_manager_spec.rb'
- 'spec/lib/gitlab/database/partitioning/partition_monitoring_spec.rb'
- 'spec/lib/gitlab/database/partitioning/replace_table_spec.rb'
- 'spec/lib/gitlab/database/partitioning/single_numeric_list_partition_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb'
- 'spec/lib/gitlab/database/partitioning/time_partition_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb'
@@ -3671,7 +3658,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/github_import/logger_spec.rb'
- 'spec/lib/gitlab/github_import/markdown_text_spec.rb'
- '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/representation/diff_note_spec.rb'
- 'spec/lib/gitlab/github_import/representation/diff_notes/suggestion_formatter_spec.rb'
@@ -5504,7 +5490,6 @@ RSpec/MissingFeatureCategory:
- 'spec/serializers/user_serializer_spec.rb'
- 'spec/serializers/web_ide_terminal_entity_spec.rb'
- 'spec/serializers/web_ide_terminal_serializer_spec.rb'
- - 'spec/services/application_settings/update_service_spec.rb'
- 'spec/services/applications/create_service_spec.rb'
- 'spec/services/gpg_keys/destroy_service_spec.rb'
- 'spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb'
diff --git a/.rubocop_todo/rspec/useless_dynamic_definition.yml b/.rubocop_todo/rspec/useless_dynamic_definition.yml
index b3dabf433a0..94a53324dee 100644
--- a/.rubocop_todo/rspec/useless_dynamic_definition.yml
+++ b/.rubocop_todo/rspec/useless_dynamic_definition.yml
@@ -1,6 +1,5 @@
---
RSpec/UselessDynamicDefinition:
- Details: grace period
Exclude:
- 'ee/spec/factories/ci/builds.rb'
- 'ee/spec/factories/ci/job_artifacts.rb'
diff --git a/.rubocop_todo/rspec/verified_doubles.yml b/.rubocop_todo/rspec/verified_doubles.yml
index 6f2e884fc55..42d1363358b 100644
--- a/.rubocop_todo/rspec/verified_doubles.yml
+++ b/.rubocop_todo/rspec/verified_doubles.yml
@@ -162,7 +162,6 @@ RSpec/VerifiedDoubles:
- 'ee/spec/services/merge_requests/approval_service_spec.rb'
- 'ee/spec/services/merge_requests/build_service_spec.rb'
- 'ee/spec/services/merge_requests/reset_approvals_service_spec.rb'
- - 'ee/spec/services/namespaces/in_product_marketing_emails_service_spec.rb'
- 'ee/spec/services/projects/update_mirror_service_spec.rb'
- 'ee/spec/services/security/ingestion/ingest_report_slice_service_spec.rb'
- 'ee/spec/services/security/orchestration/assign_service_spec.rb'
@@ -891,7 +890,6 @@ RSpec/VerifiedDoubles:
- 'spec/services/metrics/dashboard/update_dashboard_service_spec.rb'
- 'spec/services/metrics/users_starred_dashboards/create_service_spec.rb'
- 'spec/services/milestones/update_service_spec.rb'
- - 'spec/services/namespaces/in_product_marketing_emails_service_spec.rb'
- 'spec/services/notes/create_service_spec.rb'
- 'spec/services/notes/render_service_spec.rb'
- 'spec/services/notification_service_spec.rb'
@@ -1003,7 +1001,6 @@ RSpec/VerifiedDoubles:
- 'spec/workers/create_commit_signature_worker_spec.rb'
- 'spec/workers/environments/auto_stop_worker_spec.rb'
- 'spec/workers/error_tracking_issue_link_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/advance_stage_worker_spec.rb'
- 'spec/workers/gitlab/github_import/import_diff_note_worker_spec.rb'
- 'spec/workers/gitlab/github_import/import_issue_worker_spec.rb'
- 'spec/workers/gitlab/github_import/import_note_worker_spec.rb'
diff --git a/.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml b/.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml
index 9eed58acdc7..1c61aa893a2 100644
--- a/.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml
+++ b/.rubocop_todo/sidekiq_load_balancing/worker_data_consistency.yml
@@ -181,7 +181,6 @@ SidekiqLoadBalancing/WorkerDataConsistency:
- 'app/workers/metrics/dashboard/schedule_annotations_prune_worker.rb'
- 'app/workers/metrics/dashboard/sync_dashboards_worker.rb'
- 'app/workers/migrate_external_diffs_worker.rb'
- - 'app/workers/namespaces/in_product_marketing_emails_worker.rb'
- 'app/workers/namespaces/process_sync_events_worker.rb'
- 'app/workers/namespaces/prune_aggregation_schedules_worker.rb'
- 'app/workers/namespaces/schedule_aggregation_worker.rb'
diff --git a/.rubocop_todo/style/class_and_module_children.yml b/.rubocop_todo/style/class_and_module_children.yml
index 55df73d3633..80e5b613fac 100644
--- a/.rubocop_todo/style/class_and_module_children.yml
+++ b/.rubocop_todo/style/class_and_module_children.yml
@@ -70,7 +70,6 @@ Style/ClassAndModuleChildren:
- 'app/controllers/groups/dependency_proxy_auth_controller.rb'
- 'app/controllers/groups/dependency_proxy_for_containers_controller.rb'
- 'app/controllers/groups/deploy_tokens_controller.rb'
- - 'app/controllers/groups/email_campaigns_controller.rb'
- 'app/controllers/groups/group_links_controller.rb'
- 'app/controllers/groups/group_members_controller.rb'
- 'app/controllers/groups/imports_controller.rb'
@@ -358,7 +357,6 @@ Style/ClassAndModuleChildren:
- 'ee/app/controllers/admin/geo/application_controller.rb'
- 'ee/app/controllers/admin/geo/designs_controller.rb'
- 'ee/app/controllers/admin/geo/nodes_controller.rb'
- - 'ee/app/controllers/admin/geo/projects_controller.rb'
- 'ee/app/controllers/admin/geo/replicables_controller.rb'
- 'ee/app/controllers/admin/geo/settings_controller.rb'
- 'ee/app/controllers/admin/licenses_controller.rb'
@@ -459,7 +457,6 @@ Style/ClassAndModuleChildren:
- 'ee/app/models/geo/base_registry.rb'
- 'ee/app/models/geo/container_repository_registry.rb'
- 'ee/app/models/geo/deleted_project.rb'
- - 'ee/app/models/geo/design_registry.rb'
- 'ee/app/models/geo/event_log_state.rb'
- 'ee/app/models/geo/group_wiki_repository_registry.rb'
- 'ee/app/models/geo/job_artifact_registry.rb'
diff --git a/.rubocop_todo/style/conditional_assignment.yml b/.rubocop_todo/style/conditional_assignment.yml
deleted file mode 100644
index d16f2f7c3a7..00000000000
--- a/.rubocop_todo/style/conditional_assignment.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-# Cop supports --autocorrect.
-Style/ConditionalAssignment:
- Exclude:
- - 'app/helpers/icons_helper.rb'
diff --git a/.rubocop_todo/style/each_for_simple_loop.yml b/.rubocop_todo/style/each_for_simple_loop.yml
deleted file mode 100644
index e7f99d69528..00000000000
--- a/.rubocop_todo/style/each_for_simple_loop.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-# Cop supports --autocorrect.
-Style/EachForSimpleLoop:
- Exclude:
- - 'ee/spec/lib/gitlab/insights/reducers/count_per_period_reducer_spec.rb'
- - 'spec/services/members/invitation_reminder_email_service_spec.rb'
diff --git a/.rubocop_todo/style/format_string.yml b/.rubocop_todo/style/format_string.yml
index c128f96eafe..c45ddab8441 100644
--- a/.rubocop_todo/style/format_string.yml
+++ b/.rubocop_todo/style/format_string.yml
@@ -80,7 +80,6 @@ Style/FormatString:
- 'app/models/integrations/asana.rb'
- 'app/models/integrations/bamboo.rb'
- 'app/models/integrations/bugzilla.rb'
- - 'app/models/integrations/campfire.rb'
- 'app/models/integrations/chat_message/pipeline_message.rb'
- 'app/models/integrations/confluence.rb'
- 'app/models/integrations/custom_issue_tracker.rb'
@@ -160,7 +159,6 @@ Style/FormatString:
- 'ee/app/components/namespaces/free_user_cap/usage_quota_trial_alert_component.rb'
- 'ee/app/controllers/admin/elasticsearch_controller.rb'
- 'ee/app/controllers/admin/geo/application_controller.rb'
- - 'ee/app/controllers/admin/geo/projects_controller.rb'
- 'ee/app/controllers/admin/licenses_controller.rb'
- 'ee/app/controllers/concerns/audit_events/date_range.rb'
- 'ee/app/controllers/ee/projects/issues_controller.rb'
@@ -182,7 +180,6 @@ Style/FormatString:
- 'ee/app/helpers/ee/projects_helper.rb'
- 'ee/app/helpers/ee/timeboxes_helper.rb'
- 'ee/app/helpers/groups/sso_helper.rb'
- - 'ee/app/helpers/trial_registrations/reassurances_helper.rb'
- 'ee/app/helpers/vulnerabilities_helper.rb'
- 'ee/app/mailers/ee/emails/admin_notification.rb'
- 'ee/app/mailers/emails/namespace_storage_usage_mailer.rb'
diff --git a/.rubocop_todo/style/hash_as_last_array_item.yml b/.rubocop_todo/style/hash_as_last_array_item.yml
index d7032af8805..b2dceb48c1b 100644
--- a/.rubocop_todo/style/hash_as_last_array_item.yml
+++ b/.rubocop_todo/style/hash_as_last_array_item.yml
@@ -39,7 +39,6 @@ Style/HashAsLastArrayItem:
- 'ee/app/serializers/dashboard_environments_serializer.rb'
- 'ee/spec/finders/projects/integrations/jira/by_ids_finder_spec.rb'
- 'ee/spec/lib/ee/gitlab/ci/config/entry/needs_spec.rb'
- - 'ee/spec/lib/gitlab/geo/log_cursor/events/design_repository_updated_event_spec.rb'
- 'ee/spec/models/ee/ci/job_artifact_spec.rb'
- 'lib/api/entities/project.rb'
- 'lib/gitlab/analytics/cycle_analytics/request_params.rb'
diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml
index 872282a6a93..ef4fca8270d 100644
--- a/.rubocop_todo/style/if_unless_modifier.yml
+++ b/.rubocop_todo/style/if_unless_modifier.yml
@@ -389,7 +389,6 @@ Style/IfUnlessModifier:
- 'ee/app/controllers/admin/elasticsearch_controller.rb'
- 'ee/app/controllers/admin/emails_controller.rb'
- 'ee/app/controllers/admin/geo/application_controller.rb'
- - 'ee/app/controllers/admin/geo/projects_controller.rb'
- 'ee/app/controllers/admin/geo/settings_controller.rb'
- 'ee/app/controllers/admin/push_rules_controller.rb'
- 'ee/app/controllers/concerns/credentials_inventory_actions.rb'
diff --git a/.rubocop_todo/style/mutable_constant.yml b/.rubocop_todo/style/mutable_constant.yml
index f7a82be400a..d549830992f 100644
--- a/.rubocop_todo/style/mutable_constant.yml
+++ b/.rubocop_todo/style/mutable_constant.yml
@@ -7,7 +7,6 @@ Style/MutableConstant:
- 'app/graphql/mutations/packages/bulk_destroy.rb'
- 'app/helpers/blame_helper.rb'
- 'app/models/ci/build_trace_chunks/redis_base.rb'
- - 'app/models/design_management/repository.rb'
- 'app/models/integrations/datadog.rb'
- 'app/presenters/packages/helm/index_presenter.rb'
- 'app/services/import/validate_remote_git_endpoint_service.rb'
diff --git a/.rubocop_todo/style/next.yml b/.rubocop_todo/style/next.yml
deleted file mode 100644
index 6800ba2baf3..00000000000
--- a/.rubocop_todo/style/next.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-# Cop supports --autocorrect.
-Style/Next:
- Exclude:
- - 'lib/gitlab/fogbugz_import/importer.rb'
diff --git a/.rubocop_todo/style/percent_literal_delimiters.yml b/.rubocop_todo/style/percent_literal_delimiters.yml
index aee5872a343..59acd655d4b 100644
--- a/.rubocop_todo/style/percent_literal_delimiters.yml
+++ b/.rubocop_todo/style/percent_literal_delimiters.yml
@@ -2,230 +2,6 @@
# Cop supports --autocorrect.
Style/PercentLiteralDelimiters:
Exclude:
- - 'Guardfile'
- - 'app/helpers/auth_helper.rb'
- - 'app/helpers/ci/variables_helper.rb'
- - 'app/helpers/clusters_helper.rb'
- - 'app/helpers/commits_helper.rb'
- - 'app/helpers/diff_helper.rb'
- - 'app/helpers/emails_helper.rb'
- - 'app/helpers/external_link_helper.rb'
- - 'app/helpers/labels_helper.rb'
- - 'app/helpers/markup_helper.rb'
- - 'app/helpers/nav_helper.rb'
- - 'app/helpers/profiles_helper.rb'
- - 'app/helpers/search_helper.rb'
- - 'app/helpers/stat_anchors_helper.rb'
- - 'app/helpers/todos_helper.rb'
- - 'app/models/application_setting.rb'
- - 'app/models/application_setting_implementation.rb'
- - 'app/models/blob_viewer/binary_stl.rb'
- - 'app/models/blob_viewer/cargo_toml.rb'
- - 'app/models/blob_viewer/cartfile.rb'
- - 'app/models/blob_viewer/changelog.rb'
- - 'app/models/blob_viewer/composer_json.rb'
- - 'app/models/blob_viewer/contributing.rb'
- - 'app/models/blob_viewer/csv.rb'
- - 'app/models/blob_viewer/gemfile.rb'
- - 'app/models/blob_viewer/gemspec.rb'
- - 'app/models/blob_viewer/gitlab_ci_yml.rb'
- - 'app/models/blob_viewer/go_mod.rb'
- - 'app/models/blob_viewer/godeps_json.rb'
- - 'app/models/blob_viewer/license.rb'
- - 'app/models/blob_viewer/markup.rb'
- - 'app/models/blob_viewer/notebook.rb'
- - 'app/models/blob_viewer/open_api.rb'
- - 'app/models/blob_viewer/package_json.rb'
- - 'app/models/blob_viewer/pdf.rb'
- - 'app/models/blob_viewer/podfile.rb'
- - 'app/models/blob_viewer/podspec.rb'
- - 'app/models/blob_viewer/podspec_json.rb'
- - 'app/models/blob_viewer/readme.rb'
- - 'app/models/blob_viewer/requirements_txt.rb'
- - 'app/models/blob_viewer/route_map.rb'
- - 'app/models/blob_viewer/sketch.rb'
- - 'app/models/blob_viewer/svg.rb'
- - 'app/models/blob_viewer/yarn_lock.rb'
- - 'app/models/bulk_imports/file_transfer/group_config.rb'
- - 'app/models/bulk_imports/file_transfer/project_config.rb'
- - 'app/models/ci/build.rb'
- - 'app/models/ci/build_runner_session.rb'
- - 'app/models/ci/pipeline.rb'
- - 'app/models/clusters/platforms/kubernetes.rb'
- - 'app/models/commit.rb'
- - 'app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb'
- - 'app/models/concerns/diff_positionable_note.rb'
- - 'app/models/concerns/enums/prometheus_metric.rb'
- - 'app/models/concerns/issuable.rb'
- - 'app/models/concerns/issue_available_features.rb'
- - 'app/models/concerns/mentionable/reference_regexes.rb'
- - 'app/models/concerns/noteable.rb'
- - 'app/models/concerns/resolvable_note.rb'
- - 'app/models/concerns/with_uploads.rb'
- - 'app/models/container_registry/event.rb'
- - 'app/models/deploy_token.rb'
- - 'app/models/description_version.rb'
- - 'app/models/design_management.rb'
- - 'app/models/diff_note.rb'
- - 'app/models/discussion_note.rb'
- - 'app/models/draft_note.rb'
- - 'app/models/environment.rb'
- - 'app/models/event.rb'
- - 'app/models/instance_configuration.rb'
- - 'app/models/integrations/asana.rb'
- - 'app/models/integrations/assembla.rb'
- - 'app/models/integrations/base_issue_tracker.rb'
- - 'app/models/integrations/base_monitoring.rb'
- - 'app/models/integrations/base_slash_commands.rb'
- - 'app/models/integrations/base_third_party_wiki.rb'
- - 'app/models/integrations/buildkite.rb'
- - 'app/models/integrations/campfire.rb'
- - 'app/models/integrations/datadog.rb'
- - 'app/models/integrations/drone_ci.rb'
- - 'app/models/integrations/emails_on_push.rb'
- - 'app/models/integrations/external_wiki.rb'
- - 'app/models/integrations/field.rb'
- - 'app/models/integrations/jenkins.rb'
- - 'app/models/integrations/jira.rb'
- - 'app/models/integrations/packagist.rb'
- - 'app/models/integrations/pivotaltracker.rb'
- - 'app/models/integrations/pushover.rb'
- - 'app/models/integrations/teamcity.rb'
- - 'app/models/integrations/zentao.rb'
- - 'app/models/issuable_severity.rb'
- - 'app/models/issue.rb'
- - 'app/models/lfs_download_object.rb'
- - 'app/models/namespace.rb'
- - 'app/models/namespace/root_storage_statistics.rb'
- - 'app/models/note.rb'
- - 'app/models/notification_setting.rb'
- - 'app/models/performance_monitoring/prometheus_dashboard.rb'
- - 'app/models/project.rb'
- - 'app/models/project_feature.rb'
- - 'app/models/project_setting.rb'
- - 'app/models/releases/link.rb'
- - 'app/models/repository.rb'
- - 'app/models/resource_label_event.rb'
- - 'app/models/resource_state_event.rb'
- - 'app/models/resource_timebox_event.rb'
- - 'app/models/user.rb'
- - 'app/models/user_interacted_project.rb'
- - 'app/policies/identity_provider_policy.rb'
- - 'app/presenters/dev_ops_report/metric_presenter.rb'
- - 'app/presenters/search_service_presenter.rb'
- - 'app/serializers/pipeline_serializer.rb'
- - 'app/services/application_settings/update_service.rb'
- - 'app/services/auth/container_registry_authentication_service.rb'
- - 'app/services/boards/update_service.rb'
- - 'app/services/bulk_imports/file_download_service.rb'
- - 'app/services/ci/update_instance_variables_service.rb'
- - 'app/services/clusters/kubernetes/create_or_update_service_account_service.rb'
- - 'app/services/feature_flags/base_service.rb'
- - 'app/services/files/multi_service.rb'
- - 'app/services/import/bitbucket_server_service.rb'
- - 'app/services/import/fogbugz_service.rb'
- - 'app/services/import/github_service.rb'
- - 'app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb'
- - 'app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb'
- - 'app/services/import_export_clean_up_service.rb'
- - 'app/services/incident_management/pager_duty/process_webhook_service.rb'
- - 'app/services/issuable/bulk_update_service.rb'
- - 'app/services/merge_requests/update_service.rb'
- - 'app/services/metrics/dashboard/default_embed_service.rb'
- - 'app/services/packages/debian/generate_distribution_service.rb'
- - 'app/services/preview_markdown_service.rb'
- - 'app/services/projects/apple_target_platform_detector_service.rb'
- - 'app/services/projects/download_service.rb'
- - 'app/services/projects/hashed_storage/migrate_attachments_service.rb'
- - 'app/services/projects/lfs_pointers/lfs_object_download_list_service.rb'
- - 'app/services/projects/update_service.rb'
- - 'app/services/prometheus/proxy_service.rb'
- - 'app/services/repositories/base_service.rb'
- - 'app/services/repository_archive_clean_up_service.rb'
- - 'app/services/resource_access_tokens/create_service.rb'
- - 'app/services/resource_access_tokens/revoke_service.rb'
- - 'app/services/search/global_service.rb'
- - 'app/services/search/project_service.rb'
- - 'app/services/snippets/update_service.rb'
- - 'app/services/todos/destroy/destroyed_issuable_service.rb'
- - 'app/services/todos/destroy/entity_leave_service.rb'
- - 'app/uploaders/design_management/design_v432x230_uploader.rb'
- - 'app/uploaders/gitlab_uploader.rb'
- - 'app/validators/addressable_url_validator.rb'
- - 'app/validators/gitlab/zoom_url_validator.rb'
- - 'app/validators/json_schema_validator.rb'
- - 'app/workers/members_destroyer/unassign_issuables_worker.rb'
- - 'app/workers/projects/record_target_platforms_worker.rb'
- - 'config/application.rb'
- - 'config/boot.rb'
- - 'config/environments/production.rb'
- - 'config/initializers/1_settings.rb'
- - 'config/initializers/content_security_policy.rb'
- - 'config/initializers/doorkeeper.rb'
- - 'config/initializers/enumerator_next_patch.rb'
- - 'config/initializers/fog_core_patch.rb'
- - 'config/initializers/forbid_sidekiq_in_transactions.rb'
- - 'config/initializers/health_check.rb'
- - 'config/initializers/invisible_captcha.rb'
- - 'config/initializers/lograge.rb'
- - 'config/initializers/rspec_profiling.rb'
- - 'config/initializers_before_autoloader/000_inflections.rb'
- - 'config/object_store_settings.rb'
- - 'config/spring.rb'
- - 'ee/app/controllers/ee/admin/application_settings_controller.rb'
- - 'ee/app/controllers/ee/projects/service_desk_controller.rb'
- - 'ee/app/controllers/ee/repositories/git_http_client_controller.rb'
- - 'ee/app/controllers/groups/protected_environments_controller.rb'
- - 'ee/app/controllers/projects/integrations/jira/issues_controller.rb'
- - 'ee/app/controllers/projects/protected_environments_controller.rb'
- - 'ee/app/finders/iterations_finder.rb'
- - 'ee/app/graphql/types/incident_management/oncall_rotation_date_input_type.rb'
- - 'ee/app/helpers/credentials_inventory_helper.rb'
- - 'ee/app/helpers/ee/auth_helper.rb'
- - 'ee/app/helpers/ee/dashboard_helper.rb'
- - 'ee/app/helpers/ee/integrations_helper.rb'
- - 'ee/app/helpers/ee/issues_helper.rb'
- - 'ee/app/helpers/ee/labels_helper.rb'
- - 'ee/app/helpers/ee/nav_helper.rb'
- - 'ee/app/mailers/previews/ci_minutes_usage_mailer_preview.rb'
- - 'ee/app/mailers/previews/emails/namespace_storage_usage_mailer_preview.rb'
- - 'ee/app/mailers/previews/license_mailer_preview.rb'
- - 'ee/app/models/app_sec/fuzzing/api/scan_profile.rb'
- - 'ee/app/models/app_sec/fuzzing/coverage/corpus.rb'
- - 'ee/app/models/concerns/ee/issue_available_features.rb'
- - 'ee/app/models/ee/audit_event.rb'
- - 'ee/app/models/ee/description_version.rb'
- - 'ee/app/models/ee/groups/feature_setting.rb'
- - 'ee/app/models/ee/issue.rb'
- - 'ee/app/models/ee/project_feature.rb'
- - 'ee/app/models/ee/resource_label_event.rb'
- - 'ee/app/models/ee/resource_state_event.rb'
- - 'ee/app/models/ee/user.rb'
- - 'ee/app/models/ee/vulnerability.rb'
- - 'ee/app/models/geo/project_registry.rb'
- - 'ee/app/models/geo/secondary_usage_data.rb'
- - 'ee/app/models/geo_node_status.rb'
- - 'ee/app/models/incident_management/issuable_resource_link.rb'
- - 'ee/app/models/integrations/github.rb'
- - 'ee/app/models/merge_requests/status_check_response.rb'
- - 'ee/app/models/saml_provider.rb'
- - 'ee/app/models/security/orchestration_policy_configuration.rb'
- - 'ee/app/models/software_license_policy.rb'
- - 'ee/app/models/storage_shard.rb'
- - 'ee/app/services/approval_rules/create_service.rb'
- - 'ee/app/services/boards/epic_boards/update_service.rb'
- - 'ee/app/services/ci/sync_reports_to_approval_rules_service.rb'
- - 'ee/app/services/concerns/search/elasticsearchable.rb'
- - 'ee/app/services/ee/boards/update_service.rb'
- - 'ee/app/services/ee/search/group_service.rb'
- - 'ee/app/services/ee/search/project_service.rb'
- - 'ee/app/services/epics/tree_reorder_service.rb'
- - 'ee/app/services/iterations/update_service.rb'
- - 'ee/app/services/jira/jql_builder_service.rb'
- - 'ee/app/services/security/configuration/save_auto_fix_service.rb'
- - 'ee/app/services/security/dependency_list_service.rb'
- - 'ee/app/services/security/ingestion/tasks/update_vulnerability_uuids.rb'
- - 'ee/elastic/migrate/20220613120500_migrate_commits_to_separate_index.rb'
- 'ee/lib/api/status_checks.rb'
- 'ee/lib/api/visual_review_discussions.rb'
- 'ee/lib/ee/api/helpers/members_helpers.rb'
@@ -250,7 +26,6 @@ Style/PercentLiteralDelimiters:
- 'ee/lib/gitlab/geo/replicator.rb'
- 'ee/lib/gitlab/usage/metrics/instrumentations/license_metric.rb'
- 'ee/lib/tasks/gitlab/elastic/test.rake'
- - 'ee/spec/config/metrics/every_metric_definition_spec.rb'
- 'ee/spec/controllers/ee/sessions_controller_spec.rb'
- 'ee/spec/controllers/groups/saml_providers_controller_spec.rb'
- 'ee/spec/controllers/groups/scim_oauth_controller_spec.rb'
@@ -284,7 +59,6 @@ Style/PercentLiteralDelimiters:
- 'ee/spec/helpers/ee/application_settings_helper_spec.rb'
- 'ee/spec/helpers/ee/auth_helper_spec.rb'
- 'ee/spec/helpers/ee/environments_helper_spec.rb'
- - 'ee/spec/helpers/ee/geo_helper_spec.rb'
- 'ee/spec/helpers/ee/labels_helper_spec.rb'
- 'ee/spec/helpers/ee/security_orchestration_helper_spec.rb'
- 'ee/spec/helpers/merge_requests_helper_spec.rb'
@@ -301,7 +75,6 @@ Style/PercentLiteralDelimiters:
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/external_users_spec.rb'
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb'
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/groups_spec.rb'
- - 'ee/spec/lib/ee/gitlab/ci/reports/security/reports_spec.rb'
- 'ee/spec/lib/ee/gitlab/git_access_design_spec.rb'
- 'ee/spec/lib/ee/gitlab/git_access_snippet_spec.rb'
- 'ee/spec/lib/ee/gitlab/security/scan_configuration_spec.rb'
@@ -314,7 +87,6 @@ Style/PercentLiteralDelimiters:
- 'ee/spec/lib/gitlab/auth/group_saml/user_spec.rb'
- 'ee/spec/lib/gitlab/auth/ldap/adapter_spec.rb'
- 'ee/spec/lib/gitlab/auth/ldap/person_spec.rb'
- - 'ee/spec/lib/gitlab/auth/saml/membership_updater_spec.rb'
- 'ee/spec/lib/gitlab/auth/saml/user_spec.rb'
- 'ee/spec/lib/gitlab/authority_analyzer_spec.rb'
- 'ee/spec/lib/gitlab/cache_spec.rb'
@@ -348,7 +120,6 @@ Style/PercentLiteralDelimiters:
- 'ee/spec/models/ee/ci/job_artifact_spec.rb'
- 'ee/spec/models/ee/ci/runner_spec.rb'
- 'ee/spec/models/ee/groups/feature_setting_spec.rb'
- - 'ee/spec/models/ee/integration_spec.rb'
- 'ee/spec/models/ee/integrations/jira_spec.rb'
- 'ee/spec/models/ee/personal_access_token_spec.rb'
- 'ee/spec/models/instance_security_dashboard_spec.rb'
@@ -398,7 +169,6 @@ Style/PercentLiteralDelimiters:
- 'ee/spec/support/license_scanning_reports/license_scanning_report_helper.rb'
- 'ee/spec/support/prometheus/additional_metrics_shared_examples.rb'
- 'ee/spec/support/protected_tags/access_control_shared_examples.rb'
- - 'ee/spec/support/shared_examples/features/protected_branches_access_control_shared_examples.rb'
- 'ee/spec/support/shared_examples/finders/geo/file_registry_finder_shared_examples.rb'
- 'ee/spec/support/shared_examples/finders/geo/registry_finder_shared_examples.rb'
- 'ee/spec/support/shared_examples/lib/gitlab/git_access_shared_examples.rb'
@@ -409,134 +179,6 @@ Style/PercentLiteralDelimiters:
- 'ee/spec/workers/ee/issuable_export_csv_worker_spec.rb'
- 'ee/spec/workers/project_cache_worker_spec.rb'
- 'ee/spec/workers/repository_import_worker_spec.rb'
- - 'lib/api/ci/helpers/runner.rb'
- - 'lib/api/commit_statuses.rb'
- - 'lib/api/discussions.rb'
- - 'lib/api/entities/note.rb'
- - 'lib/api/helpers/common_helpers.rb'
- - 'lib/api/helpers/notes_helpers.rb'
- - 'lib/api/helpers/projects_helpers.rb'
- - 'lib/api/helpers/search_helpers.rb'
- - 'lib/api/maven_packages.rb'
- - 'lib/api/repositories.rb'
- - 'lib/api/search.rb'
- - 'lib/api/users.rb'
- - 'lib/backup/database.rb'
- - 'lib/backup/manager.rb'
- - 'lib/banzai/filter/ascii_doc_sanitization_filter.rb'
- - 'lib/banzai/filter/autolink_filter.rb'
- - 'lib/banzai/filter/base_sanitization_filter.rb'
- - 'lib/banzai/filter/broadcast_message_sanitization_filter.rb'
- - 'lib/banzai/filter/custom_emoji_filter.rb'
- - 'lib/banzai/filter/emoji_filter.rb'
- - 'lib/banzai/filter/gollum_tags_filter.rb'
- - 'lib/banzai/filter/inline_diff_filter.rb'
- - 'lib/banzai/filter/issuable_reference_expansion_filter.rb'
- - 'lib/banzai/filter/references/reference_filter.rb'
- - 'lib/banzai/filter/repository_link_filter.rb'
- - 'lib/banzai/filter/sanitization_filter.rb'
- - 'lib/banzai/filter/spaced_link_filter.rb'
- - 'lib/banzai/filter/syntax_highlight_filter.rb'
- - 'lib/banzai/filter/table_of_contents_filter.rb'
- - 'lib/banzai/pipeline/base_pipeline.rb'
- - 'lib/banzai/pipeline/description_pipeline.rb'
- - 'lib/banzai/pipeline/incident_management/timeline_event_pipeline.rb'
- - 'lib/bitbucket/page.rb'
- - 'lib/bitbucket/representation/issue.rb'
- - 'lib/container_registry/path.rb'
- - 'lib/feature.rb'
- - 'lib/generators/gitlab/usage_metric_definition_generator.rb'
- - 'lib/generators/gitlab/usage_metric_generator.rb'
- - 'lib/gitlab.rb'
- - 'lib/gitlab/alert_management/payload/managed_prometheus.rb'
- - 'lib/gitlab/alert_management/payload/prometheus.rb'
- - 'lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb'
- - 'lib/gitlab/auth/ldap/adapter.rb'
- - 'lib/gitlab/auth/ldap/config.rb'
- - 'lib/gitlab/background_migration/backfill_note_discussion_id.rb'
- - 'lib/gitlab/ci/ansi2html.rb'
- - 'lib/gitlab/ci/config/entry/bridge.rb'
- - 'lib/gitlab/ci/reports/codequality_reports.rb'
- - 'lib/gitlab/ci/reports/test_reports_comparer.rb'
- - 'lib/gitlab/cleanup/orphan_job_artifact_files.rb'
- - 'lib/gitlab/cluster/rack_timeout_observer.rb'
- - 'lib/gitlab/content_security_policy/config_loader.rb'
- - 'lib/gitlab/database/load_balancing/connection_proxy.rb'
- - 'lib/gitlab/database/migration_helpers/cascading_namespace_settings.rb'
- - 'lib/gitlab/database/reindexing.rb'
- - 'lib/gitlab/dependency_linker/base_linker.rb'
- - 'lib/gitlab/diff/char_diff.rb'
- - 'lib/gitlab/diff/inline_diff_marker.rb'
- - 'lib/gitlab/diff/line.rb'
- - 'lib/gitlab/etag_caching/middleware.rb'
- - 'lib/gitlab/etag_caching/router/graphql.rb'
- - 'lib/gitlab/etag_caching/router/rails.rb'
- - 'lib/gitlab/fips.rb'
- - 'lib/gitlab/git/blob.rb'
- - 'lib/gitlab/git/diff.rb'
- - 'lib/gitlab/git/rugged_impl/repository.rb'
- - 'lib/gitlab/git/tree.rb'
- - 'lib/gitlab/git_access.rb'
- - 'lib/gitlab/gitaly_client.rb'
- - 'lib/gitlab/gitaly_client/diff.rb'
- - 'lib/gitlab/gitaly_client/wiki_page.rb'
- - 'lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb'
- - 'lib/gitlab/hotlinking_detector.rb'
- - 'lib/gitlab/import_export/command_line_util.rb'
- - 'lib/gitlab/import_export/file_importer.rb'
- - 'lib/gitlab/import_export/repo_restorer.rb'
- - 'lib/gitlab/jira_import/metadata_collector.rb'
- - 'lib/gitlab/kas.rb'
- - 'lib/gitlab/kroki.rb'
- - 'lib/gitlab/kubernetes/kubectl_cmd.rb'
- - 'lib/gitlab/logger.rb'
- - 'lib/gitlab/lograge/custom_options.rb'
- - 'lib/gitlab/metrics/background_transaction.rb'
- - 'lib/gitlab/metrics/dashboard/importers/prometheus_metrics.rb'
- - 'lib/gitlab/metrics/dashboard/stages/url_validator.rb'
- - 'lib/gitlab/metrics/requests_rack_middleware.rb'
- - 'lib/gitlab/metrics/subscribers/action_view.rb'
- - 'lib/gitlab/metrics/subscribers/active_record.rb'
- - 'lib/gitlab/metrics/transaction.rb'
- - 'lib/gitlab/metrics/web_transaction.rb'
- - 'lib/gitlab/middleware/read_only/controller.rb'
- - 'lib/gitlab/project_search_results.rb'
- - 'lib/gitlab/prometheus/query_variables.rb'
- - 'lib/gitlab/query_limiting/transaction.rb'
- - 'lib/gitlab/reference_extractor.rb'
- - 'lib/gitlab/regex.rb'
- - 'lib/gitlab/regex/bulk_imports.rb'
- - 'lib/gitlab/sanitizers/exception_message.rb'
- - 'lib/gitlab/sanitizers/exif.rb'
- - 'lib/gitlab/search/abuse_detection.rb'
- - 'lib/gitlab/search_context.rb'
- - 'lib/gitlab/slash_commands/presenters/base.rb'
- - 'lib/gitlab/ssh_public_key.rb'
- - 'lib/gitlab/task_helpers.rb'
- - 'lib/gitlab/url_blocker.rb'
- - 'lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric.rb'
- - 'lib/gitlab/usage/metrics/instrumentations/database_metric.rb'
- - 'lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb'
- - 'lib/gitlab/usage_data.rb'
- - 'lib/gitlab/usage_data/topology.rb'
- - 'lib/gitlab/usage_data_counters/hll_redis_counter.rb'
- - 'lib/gitlab/utils/sanitize_node_link.rb'
- - 'lib/gitlab/web_hooks/rate_limiter.rb'
- - 'lib/gitlab/workhorse.rb'
- - 'lib/grafana/validator.rb'
- - 'lib/omni_auth/strategies/jwt.rb'
- - 'lib/release_highlights/validator/entry.rb'
- - 'lib/security/ci_configuration/sast_build_action.rb'
- - 'lib/sidebars/projects/menus/repository_menu.rb'
- - 'lib/system_check/app/migrations_are_up_check.rb'
- - 'lib/system_check/incoming_email/mail_room_running_check.rb'
- - 'lib/system_check/sidekiq_check.rb'
- - 'lib/tasks/cleanup.rake'
- - 'lib/tasks/gettext.rake'
- - 'lib/tasks/gitlab/info.rake'
- - 'lib/tasks/gitlab/shell.rake'
- - 'lib/tasks/gitlab/update_templates.rake'
- - 'lib/tasks/tanuki_emoji.rake'
- 'metrics_server/metrics_server.rb'
- 'qa/qa/ee/page/dashboard/projects.rb'
- 'qa/qa/ee/page/group/settings/general.rb'
@@ -568,7 +210,6 @@ Style/PercentLiteralDelimiters:
- 'spec/benchmarks/banzai_benchmark.rb'
- 'spec/commands/sidekiq_cluster/cli_spec.rb'
- 'spec/components/pajamas/component_spec.rb'
- - 'spec/config/mail_room_spec.rb'
- 'spec/controllers/concerns/continue_params_spec.rb'
- 'spec/controllers/graphql_controller_spec.rb'
- 'spec/controllers/groups/releases_controller_spec.rb'
@@ -577,13 +218,9 @@ Style/PercentLiteralDelimiters:
- 'spec/controllers/profiles/two_factor_auths_controller_spec.rb'
- 'spec/controllers/projects/artifacts_controller_spec.rb'
- 'spec/controllers/projects/deploy_keys_controller_spec.rb'
- - 'spec/controllers/projects/environments/prometheus_api_controller_spec.rb'
- - 'spec/controllers/projects/environments_controller_spec.rb'
- 'spec/controllers/projects/issues_controller_spec.rb'
- 'spec/controllers/projects/merge_requests/conflicts_controller_spec.rb'
- - 'spec/controllers/projects/merge_requests/creations_controller_spec.rb'
- 'spec/controllers/projects/merge_requests_controller_spec.rb'
- - 'spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb'
- 'spec/controllers/projects/pipelines_controller_spec.rb'
- 'spec/controllers/projects/settings/ci_cd_controller_spec.rb'
- 'spec/controllers/projects_controller_spec.rb'
@@ -663,7 +300,6 @@ Style/PercentLiteralDelimiters:
- 'spec/lib/banzai/filter/autolink_filter_spec.rb'
- 'spec/lib/banzai/filter/broadcast_message_sanitization_filter_spec.rb'
- 'spec/lib/banzai/filter/image_link_filter_spec.rb'
- - 'spec/lib/banzai/filter/inline_metrics_filter_spec.rb'
- 'spec/lib/banzai/filter/references/alert_reference_filter_spec.rb'
- 'spec/lib/banzai/filter/references/commit_range_reference_filter_spec.rb'
- 'spec/lib/banzai/filter/references/commit_reference_filter_spec.rb'
@@ -682,10 +318,8 @@ Style/PercentLiteralDelimiters:
- 'spec/lib/banzai/pipeline/description_pipeline_spec.rb'
- 'spec/lib/banzai/pipeline/full_pipeline_spec.rb'
- 'spec/lib/banzai/pipeline/gfm_pipeline_spec.rb'
- - 'spec/lib/banzai/pipeline/incident_management/timeline_event_pipeline_spec.rb'
- 'spec/lib/banzai/pipeline/plain_markdown_pipeline_spec.rb'
- 'spec/lib/banzai/reference_parser/base_parser_spec.rb'
- - 'spec/lib/banzai/reference_parser/commit_parser_spec.rb'
- 'spec/lib/banzai/reference_parser/issue_parser_spec.rb'
- 'spec/lib/banzai/reference_parser/merge_request_parser_spec.rb'
- 'spec/lib/bitbucket/collection_spec.rb'
@@ -779,7 +413,6 @@ Style/PercentLiteralDelimiters:
- 'spec/lib/gitlab/graphql/tracers/metrics_tracer_spec.rb'
- 'spec/lib/gitlab/hashed_path_spec.rb'
- 'spec/lib/gitlab/highlight_spec.rb'
- - 'spec/lib/gitlab/http_spec.rb'
- 'spec/lib/gitlab/i18n/translation_entry_spec.rb'
- 'spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb'
- 'spec/lib/gitlab/import_export/after_export_strategies/web_upload_strategy_spec.rb'
@@ -802,8 +435,6 @@ Style/PercentLiteralDelimiters:
- 'spec/lib/gitlab/kubernetes/role_spec.rb'
- 'spec/lib/gitlab/language_data_spec.rb'
- 'spec/lib/gitlab/markup_helper_spec.rb'
- - 'spec/lib/gitlab/metrics/dashboard/processor_spec.rb'
- - 'spec/lib/gitlab/metrics/dashboard/validator/errors_spec.rb'
- 'spec/lib/gitlab/metrics/rails_slis_spec.rb'
- 'spec/lib/gitlab/metrics/samplers/threads_sampler_spec.rb'
- 'spec/lib/gitlab/middleware/go_spec.rb'
@@ -815,7 +446,6 @@ Style/PercentLiteralDelimiters:
- 'spec/lib/gitlab/popen_spec.rb'
- 'spec/lib/gitlab/process_management_spec.rb'
- 'spec/lib/gitlab/process_supervisor_spec.rb'
- - 'spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb'
- 'spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb'
- 'spec/lib/gitlab/prometheus/query_variables_spec.rb'
- 'spec/lib/gitlab/quick_actions/extractor_spec.rb'
@@ -836,12 +466,12 @@ Style/PercentLiteralDelimiters:
- 'spec/lib/gitlab/string_range_marker_spec.rb'
- 'spec/lib/gitlab/string_regex_marker_spec.rb'
- 'spec/lib/gitlab/suggestions/suggestion_set_spec.rb'
+ - 'spec/lib/gitlab/task_helpers_spec.rb'
- 'spec/lib/gitlab/tracking/event_definition_spec.rb'
- 'spec/lib/gitlab/url_sanitizer_spec.rb'
- 'spec/lib/gitlab/usage/metric_definition_spec.rb'
- 'spec/lib/gitlab/usage/metric_spec.rb'
- 'spec/lib/gitlab/usage/service_ping/instrumented_payload_spec.rb'
- - 'spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb'
- 'spec/lib/gitlab/usage_data_spec.rb'
- 'spec/lib/gitlab/utils/log_limited_array_spec.rb'
- 'spec/lib/gitlab/webpack/graphql_known_operations_spec.rb'
@@ -889,7 +519,6 @@ Style/PercentLiteralDelimiters:
- 'spec/models/concerns/reactive_caching_spec.rb'
- 'spec/models/concerns/sortable_spec.rb'
- 'spec/models/deployment_spec.rb'
- - 'spec/models/design_management/repository_spec.rb'
- 'spec/models/diff_viewer/base_spec.rb'
- 'spec/models/environment_spec.rb'
- 'spec/models/group_label_spec.rb'
@@ -908,11 +537,9 @@ Style/PercentLiteralDelimiters:
- 'spec/models/packages/package_spec.rb'
- 'spec/models/packages/tag_spec.rb'
- 'spec/models/pages_domain_spec.rb'
- - 'spec/models/performance_monitoring/prometheus_dashboard_spec.rb'
- 'spec/models/personal_access_token_spec.rb'
- 'spec/models/project_feature_spec.rb'
- 'spec/models/project_label_spec.rb'
- - 'spec/models/project_setting_spec.rb'
- 'spec/models/project_spec.rb'
- 'spec/models/project_team_spec.rb'
- 'spec/models/projects/topic_spec.rb'
@@ -924,13 +551,11 @@ Style/PercentLiteralDelimiters:
- 'spec/models/user_spec.rb'
- 'spec/models/web_ide_terminal_spec.rb'
- 'spec/models/zoom_meeting_spec.rb'
- - 'spec/policies/group_policy_spec.rb'
- 'spec/policies/project_policy_spec.rb'
- 'spec/presenters/ci/pipeline_artifacts/code_coverage_presenter_spec.rb'
- 'spec/presenters/ci/pipeline_artifacts/code_quality_mr_diff_presenter_spec.rb'
- 'spec/presenters/packages/nuget/packages_metadata_presenter_spec.rb'
- 'spec/presenters/packages/nuget/search_results_presenter_spec.rb'
- - 'spec/requests/api/admin/broadcast_messages_spec.rb'
- 'spec/requests/api/badges_spec.rb'
- 'spec/requests/api/ci/jobs_spec.rb'
- 'spec/requests/api/ci/pipelines_spec.rb'
@@ -1022,7 +647,6 @@ Style/PercentLiteralDelimiters:
- 'spec/services/merge_requests/refresh_service_spec.rb'
- 'spec/services/packages/create_dependency_service_spec.rb'
- 'spec/services/packages/nuget/create_dependency_service_spec.rb'
- - 'spec/services/packages/nuget/metadata_extraction_service_spec.rb'
- 'spec/services/packages/nuget/update_package_from_metadata_service_spec.rb'
- 'spec/services/packages/update_tags_service_spec.rb'
- 'spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb'
@@ -1032,12 +656,10 @@ Style/PercentLiteralDelimiters:
- 'spec/services/projects/operations/update_service_spec.rb'
- 'spec/services/projects/record_target_platforms_service_spec.rb'
- 'spec/services/projects/update_statistics_service_spec.rb'
- - 'spec/services/prometheus/proxy_variable_substitution_service_spec.rb'
- 'spec/services/quick_actions/interpret_service_spec.rb'
- 'spec/services/upload_service_spec.rb'
- 'spec/sidekiq_cluster/sidekiq_cluster_spec.rb'
- 'spec/support/atlassian/jira_connect/schemata.rb'
- - 'spec/support/banzai/reference_filter_shared_examples.rb'
- 'spec/support/capybara.rb'
- 'spec/support/helpers/gpg_helpers.rb'
- 'spec/support/helpers/login_helpers.rb'
@@ -1049,11 +671,8 @@ Style/PercentLiteralDelimiters:
- 'spec/support/import_export/configuration_helper.rb'
- 'spec/support/import_export/export_file_helper.rb'
- 'spec/support/matchers/markdown_matchers.rb'
- - 'spec/support/prometheus/additional_metrics_shared_examples.rb'
- - 'spec/support/prometheus/metric_builders.rb'
- 'spec/support/shared_contexts/graphql/resolvers/runners_resolver_shared_context.rb'
- 'spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb'
- - 'spec/support/shared_examples/controllers/metrics_dashboard_shared_examples.rb'
- 'spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb'
- 'spec/support/shared_examples/features/page_description_shared_examples.rb'
- 'spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb'
@@ -1079,7 +698,6 @@ Style/PercentLiteralDelimiters:
- 'spec/support_specs/helpers/active_record/query_recorder_spec.rb'
- 'spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb'
- 'spec/tasks/gitlab/db_rake_spec.rb'
- - 'spec/lib/gitlab/task_helpers_spec.rb'
- 'spec/tooling/danger/customer_success_spec.rb'
- 'spec/tooling/danger/datateam_spec.rb'
- 'spec/tooling/danger/sidekiq_queues_spec.rb'
@@ -1107,7 +725,6 @@ Style/PercentLiteralDelimiters:
- 'spec/views/projects/commit/branches.html.haml_spec.rb'
- 'spec/workers/concerns/worker_context_spec.rb'
- 'spec/workers/container_registry/migration/enqueuer_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/advance_stage_worker_spec.rb'
- 'spec/workers/groups/update_statistics_worker_spec.rb'
- 'spec/workers/jira_connect/sync_branch_worker_spec.rb'
- 'spec/workers/post_receive_spec.rb'
diff --git a/.rubocop_todo/style/redundant_condition.yml b/.rubocop_todo/style/redundant_condition.yml
deleted file mode 100644
index 535dfa9e462..00000000000
--- a/.rubocop_todo/style/redundant_condition.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-# Cop supports --autocorrect.
-Style/RedundantCondition:
- Exclude:
- - 'spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb'
diff --git a/.rubocop_todo/style/redundant_freeze.yml b/.rubocop_todo/style/redundant_freeze.yml
index 12126c58313..12c9200bf54 100644
--- a/.rubocop_todo/style/redundant_freeze.yml
+++ b/.rubocop_todo/style/redundant_freeze.yml
@@ -2,61 +2,7 @@
# Cop supports --autocorrect.
Style/RedundantFreeze:
Exclude:
- - 'app/controllers/help_controller.rb'
- - 'app/controllers/import/bitbucket_server_controller.rb'
- - 'app/finders/issuable_finder.rb'
- - 'app/finders/repositories/changelog_commits_finder.rb'
- - 'app/helpers/auth_helper.rb'
- - 'app/helpers/colors_helper.rb'
- - 'app/helpers/sidekiq_helper.rb'
- - 'app/models/application_setting_implementation.rb'
- - 'app/models/badge.rb'
- - 'app/models/blob_viewer/go_mod.rb'
- - 'app/models/ci/runner.rb'
- - 'app/models/commit.rb'
- - 'app/models/commit_range.rb'
- - 'app/models/concerns/ci/maskable.rb'
- - 'app/models/concerns/pg_full_text_searchable.rb'
- - 'app/models/concerns/redactable.rb'
- - 'app/models/concerns/taskable.rb'
- - 'app/models/custom_emoji.rb'
- - 'app/models/environment_status.rb'
- - 'app/models/error_tracking/project_error_tracking_setting.rb'
- - 'app/models/hooks/web_hook.rb'
- - 'app/models/integrations/apple_app_store.rb'
- - 'app/models/integrations/campfire.rb'
- - 'app/models/integrations/chat_message/base_message.rb'
- - 'app/models/integrations/confluence.rb'
- - 'app/models/integrations/datadog.rb'
- - 'app/models/integrations/discord.rb'
- - 'app/models/integrations/field.rb'
- - 'app/models/integrations/teamcity.rb'
- - 'app/models/license_template.rb'
- - 'app/models/members/group_member.rb'
- - 'app/models/members/project_member.rb'
- - 'app/models/merge_request.rb'
- - 'app/models/namespaces/randomized_suffix_path.rb'
- - 'app/models/note.rb'
- - 'app/models/packages/debian.rb'
- - 'app/models/packages/debian/file_entry.rb'
- - 'app/models/personal_access_token.rb'
- - 'app/models/releases/link.rb'
- - 'app/models/snippet_repository.rb'
- - 'app/models/terraform/state.rb'
- - 'app/services/clusters/agent_tokens/track_usage_service.rb'
- - 'app/services/error_tracking/list_projects_service.rb'
- - 'app/services/grafana/proxy_service.rb'
- - 'app/services/import/validate_remote_git_endpoint_service.rb'
- - 'app/services/issues/base_service.rb'
- - 'app/services/projects/import_error_filter.rb'
- - 'app/services/projects/lfs_pointers/lfs_object_download_list_service.rb'
- - 'app/services/prometheus/proxy_variable_substitution_service.rb'
- - 'app/uploaders/file_uploader.rb'
- - 'app/validators/certificate_fingerprint_validator.rb'
- - 'app/validators/json_schema_validator.rb'
- - 'app/validators/line_code_validator.rb'
- 'lib/api/api.rb'
- - 'lib/api/concerns/packages/nuget_endpoints.rb'
- 'lib/api/debian_group_packages.rb'
- 'lib/api/go_proxy.rb'
- 'lib/api/helpers.rb'
@@ -68,8 +14,6 @@ Style/RedundantFreeze:
- 'lib/banzai/filter/attributes_filter.rb'
- 'lib/banzai/filter/autolink_filter.rb'
- 'lib/banzai/filter/blockquote_fence_filter.rb'
- - 'lib/banzai/filter/dollar_math_post_filter.rb'
- - 'lib/banzai/filter/dollar_math_pre_filter.rb'
- 'lib/banzai/filter/footnote_filter.rb'
- 'lib/banzai/filter/gollum_tags_filter.rb'
- 'lib/banzai/filter/markdown_post_escape_filter.rb'
@@ -90,7 +34,6 @@ Style/RedundantFreeze:
- 'lib/gitlab/ci/build/artifacts/metadata.rb'
- 'lib/gitlab/ci/config/entry/artifacts.rb'
- 'lib/gitlab/ci/config/external/file/base.rb'
- - 'lib/gitlab/ci/interpolation/block.rb'
- 'lib/gitlab/ci/parsers/test/junit.rb'
- 'lib/gitlab/ci/pipeline/chain/skip.rb'
- 'lib/gitlab/ci/pipeline/expression/lexeme/and.rb'
@@ -113,7 +56,6 @@ Style/RedundantFreeze:
- 'lib/gitlab/database/background_migration/batch_optimizer.rb'
- 'lib/gitlab/database/load_balancing/service_discovery.rb'
- 'lib/gitlab/database/migrations/runner.rb'
- - 'lib/gitlab/database/query_analyzers/query_recorder.rb'
- 'lib/gitlab/dependency_linker/base_linker.rb'
- 'lib/gitlab/dependency_linker/gemfile_linker.rb'
- 'lib/gitlab/dependency_linker/godeps_json_linker.rb'
@@ -128,7 +70,6 @@ Style/RedundantFreeze:
- 'lib/gitlab/email/handler/service_desk_handler.rb'
- 'lib/gitlab/email/receiver.rb'
- 'lib/gitlab/error_tracking/error_repository/open_api_strategy.rb'
- - 'lib/gitlab/front_matter.rb'
- 'lib/gitlab/git.rb'
- 'lib/gitlab/git/base_error.rb'
- 'lib/gitlab/git/diff.rb'
@@ -140,7 +81,6 @@ Style/RedundantFreeze:
- 'lib/gitlab/golang.rb'
- 'lib/gitlab/graphql/queries.rb'
- 'lib/gitlab/harbor/query.rb'
- - 'lib/gitlab/hook_data/base_builder.rb'
- 'lib/gitlab/i18n/po_linter.rb'
- 'lib/gitlab/i18n/translation_entry.rb'
- 'lib/gitlab/jira/dvcs.rb'
@@ -165,26 +105,3 @@ Style/RedundantFreeze:
- 'lib/gitlab/regex.rb'
- 'lib/gitlab/regex/packages.rb'
- 'lib/gitlab/robots_txt/parser.rb'
- - 'lib/gitlab/saas.rb'
- - 'lib/gitlab/sanitizers/exception_message.rb'
- - 'lib/gitlab/sanitizers/svg.rb'
- - 'lib/gitlab/search/abuse_detection.rb'
- - 'lib/gitlab/search/found_blob.rb'
- - 'lib/gitlab/search/query.rb'
- - 'lib/gitlab/sidekiq_config/worker_matcher.rb'
- - 'lib/gitlab/slash_commands/deploy.rb'
- - 'lib/gitlab/slug/path.rb'
- - 'lib/gitlab/spamcheck/client.rb'
- - 'lib/gitlab/sql/pattern.rb'
- - 'lib/gitlab/unicode.rb'
- - 'lib/gitlab/untrusted_regexp/ruby_syntax.rb'
- - 'lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter.rb'
- - 'lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb'
- - 'lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter.rb'
- - 'lib/gitlab/utils/link_header_parser.rb'
- - 'lib/gitlab/utils/markdown.rb'
- - 'lib/gitlab/uuid.rb'
- - 'lib/gitlab/version_info.rb'
- - 'lib/gitlab/x509/certificate.rb'
- - 'lib/gitlab/zoom_link_extractor.rb'
- - 'lib/sbom/package_url/argument_validator.rb'
diff --git a/.rubocop_todo/style/redundant_parentheses.yml b/.rubocop_todo/style/redundant_parentheses.yml
deleted file mode 100644
index 540dcfa3ca7..00000000000
--- a/.rubocop_todo/style/redundant_parentheses.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-# Cop supports --autocorrect.
-Style/RedundantParentheses:
- Details: grace period
- Exclude:
- - 'spec/graphql/types/ci/job_kind_enum_spec.rb'
- - 'spec/lib/gitlab/import_export/command_line_util_spec.rb'
- - 'spec/requests/verifies_with_email_spec.rb'
- - 'spec/services/projects/create_service_spec.rb'
diff --git a/.rubocop_todo/style/redundant_self.yml b/.rubocop_todo/style/redundant_self.yml
index df5c1b6172a..3dd497248bc 100644
--- a/.rubocop_todo/style/redundant_self.yml
+++ b/.rubocop_todo/style/redundant_self.yml
@@ -87,7 +87,6 @@ Style/RedundantSelf:
- 'app/models/integrations/base_ci.rb'
- 'app/models/integrations/base_issue_tracker.rb'
- 'app/models/integrations/base_slash_commands.rb'
- - 'app/models/integrations/campfire.rb'
- 'app/models/integrations/emails_on_push.rb'
- 'app/models/integrations/jira.rb'
- 'app/models/integrations/pipelines_email.rb'
@@ -205,7 +204,6 @@ Style/RedundantSelf:
- 'ee/app/models/ee/user.rb'
- 'ee/app/models/epic/metrics.rb'
- 'ee/app/models/geo/base_registry.rb'
- - 'ee/app/models/geo/design_registry.rb'
- 'ee/app/models/geo/project_registry.rb'
- 'ee/app/models/geo/upload_registry.rb'
- 'ee/app/models/geo_node.rb'
diff --git a/.rubocop_todo/style/string_literals_in_interpolation.yml b/.rubocop_todo/style/string_literals_in_interpolation.yml
index 30a649cb4fa..c8cd3c9f074 100644
--- a/.rubocop_todo/style/string_literals_in_interpolation.yml
+++ b/.rubocop_todo/style/string_literals_in_interpolation.yml
@@ -6,7 +6,6 @@ Style/StringLiteralsInInterpolation:
- 'app/helpers/colors_helper.rb'
- 'app/models/application_setting_implementation.rb'
- 'app/models/ci/namespace_mirror.rb'
- - 'app/models/integrations/campfire.rb'
- 'app/models/integrations/jira.rb'
- 'app/services/draft_notes/publish_service.rb'
- 'app/services/projects/create_service.rb'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 006a7a2bd69..9fa29b12563 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -836,6 +836,42 @@ entry.
- [Fix test pollution in count_deployments_metric_spec](gitlab-org/gitlab@610e6a033fe9b20aabc237b18837cddf150d4d1b) ([merge request](gitlab-org/gitlab!126808))
- [Update BulkImports::PipelineBatchWorker resource boundary](gitlab-org/gitlab@7d2477d81bcc2d035be26587802706f7098b6e44) ([merge request](gitlab-org/gitlab!126696))
+## 16.2.7 (2023-09-18)
+
+### Security (1 change)
+
+- [Enforce that the policy is executed by the bot user](gitlab-org/security/gitlab@336d6829bf5268dbbb1ccdaa224ed65c431a9ed6) ([merge request](gitlab-org/security/gitlab!3569))
+
+## 16.2.6 (2023-09-12)
+
+### Fixed (3 changes)
+
+- [Prevent pipeline creation while import is running](gitlab-org/gitlab@457561758ed262b3958ff202f31a3f4d1098e983) ([merge request](gitlab-org/gitlab!131155))
+- [Create iid sequence for ci_pipelines with new projects](gitlab-org/gitlab@386708854a916b28154535bf76777526ffb78a31) ([merge request](gitlab-org/gitlab!130836))
+- [Drop bridge jobs on unknown failures](gitlab-org/gitlab@0cf3c9c5fc59bf6a8ea66d6017b33960c109852f) ([merge request](gitlab-org/gitlab!130834))
+
+## 16.2.5 (2023-08-31)
+
+### Fixed (1 change)
+
+- [Geo: Resync direct upload object stored artifacts](gitlab-org/security/gitlab@2b89dcd8d4e238ee081b5a886a43f2d7d390e853) **GitLab Enterprise Edition**
+
+### Security (13 changes)
+
+- [Add authorization checks to import status endpoint](gitlab-org/security/gitlab@4ace6aaeaa836d0545576857080b6a01163d40b6) ([merge request](gitlab-org/security/gitlab!3514))
+- [Update commonmarker to 0.23.10](gitlab-org/security/gitlab@41ae8c446666e478addfff8c2d450103435c1ac1) ([merge request](gitlab-org/security/gitlab!3508))
+- [Remove DAST secret variables when URL is updated](gitlab-org/security/gitlab@ab9b3384bfdf15698285e99d1f31c7d8b3ec7db5) ([merge request](gitlab-org/security/gitlab!3499))
+- [Maintainer can leak sentry token by changing the configured URL](gitlab-org/security/gitlab@8c423fdd1afceedf34a5d7c11f9be96b7d273b95) ([merge request](gitlab-org/security/gitlab!3517))
+- [Service account users are external by default](gitlab-org/security/gitlab@9abbd558d4307c4bcb62a5fea2bffa2e59ded4fa) ([merge request](gitlab-org/security/gitlab!3502))
+- [Additional permission check when editing label](gitlab-org/security/gitlab@416b3a3d448c21b96c4cd6dda42da2e561f8040d) ([merge request](gitlab-org/security/gitlab!3505))
+- [Fix ReDOS in bulk_imports endpoint params](gitlab-org/security/gitlab@90dbac471eff8d1d867db979be5aaf7f8660e64c) ([merge request](gitlab-org/security/gitlab!3511))
+- [Prevent namespace level banned users from accessing API](gitlab-org/security/gitlab@76ce2605f091d7c2d10ed3dd00cf8c7e37e26b5a) ([merge request](gitlab-org/security/gitlab!3484))
+- [Requires write_model_experiments on mlflow api](gitlab-org/security/gitlab@a385fb7b6422e6d41c8197655947fc6d3f0d65c8) ([merge request](gitlab-org/security/gitlab!3480))
+- [Check prohibit_outer_forks in fork relationship api](gitlab-org/security/gitlab@d8ee7ec151440088bb34b5d2c20b490986bba654) ([merge request](gitlab-org/security/gitlab!3477))
+- [Remove GCP private key from streaming audit events UI](gitlab-org/security/gitlab@36b15be1d8643172d4f54063fb6430068d57e6f8) ([merge request](gitlab-org/security/gitlab!3487))
+- [Prevent traversal for `path` parameter in refs/switch endpoint](gitlab-org/security/gitlab@89cd4dae070fcf20df467639934accb41f5c46da) ([merge request](gitlab-org/security/gitlab!3475))
+- [Gitaly keyset pager when pagination none only with tree view](gitlab-org/security/gitlab@498f72aed3d0e70f7af5335ee3fb11f6cfc21986) ([merge request](gitlab-org/security/gitlab!3481))
+
## 16.2.4 (2023-08-11)
### Fixed (2 changes)
@@ -1601,6 +1637,26 @@ No changes.
- [Add schema_version in the commits index mapping](gitlab-org/gitlab@e75b94903b69e1e1588e251217926882875555a8) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123435)) **GitLab Enterprise Edition**
- [Allow to set labels for Redis calls](gitlab-org/gitlab@8ccfff9e2d250eb22afaa7d0243e707b536a5436) ([merge request](gitlab-org/gitlab!122340))
+## 16.1.5 (2023-08-31)
+
+### Fixed (1 change)
+
+- [Geo: Resync direct upload object stored artifacts](gitlab-org/security/gitlab@2bb514a62edce03477b16049ad20030609779a05) **GitLab Enterprise Edition**
+
+### Security (11 changes)
+
+- [Add authorization checks to import status endpoint](gitlab-org/security/gitlab@c2dad0797d673348e75f695bea6459a5849beb99) ([merge request](gitlab-org/security/gitlab!3515))
+- [Update commonmarker to 0.23.10](gitlab-org/security/gitlab@13c49cfed688bd255716e44a33600fcda5f847a9) ([merge request](gitlab-org/security/gitlab!3509))
+- [Remove DAST secret variables when URL is updated](gitlab-org/security/gitlab@8c5c9eda9a4f3da398cc2617a562ab080d259337) ([merge request](gitlab-org/security/gitlab!3500))
+- [Maintainer can leak sentry token by changing the configured URL](gitlab-org/security/gitlab@9d961725e5732190fd9797c8807adbce3778fa71) ([merge request](gitlab-org/security/gitlab!3518))
+- [Service account users are external by default](gitlab-org/security/gitlab@64d11f5e38ef7f6916887bd916c3571901a6d4a5) ([merge request](gitlab-org/security/gitlab!3503))
+- [Additional permission check when editing label](gitlab-org/security/gitlab@f2cb7ebae05f63dfa00e434a9e4d86ebf972a5e2) ([merge request](gitlab-org/security/gitlab!3506))
+- [Fix ReDOS in bulk_imports endpoint params](gitlab-org/security/gitlab@c5815c2b1863bc197266f1efeca88568205214d6) ([merge request](gitlab-org/security/gitlab!3512))
+- [Prevent namespace level banned users from accessing API](gitlab-org/security/gitlab@c99f5af50d231c47673a5873610b27a0418c8320) ([merge request](gitlab-org/security/gitlab!3485))
+- [Check prohibit_outer_forks in fork relationship api](gitlab-org/security/gitlab@8d2c0249ec06d245df7449d2b0e0349e1fe20329) ([merge request](gitlab-org/security/gitlab!3478))
+- [Prevent traversal for `path` parameter in refs/switch endpoint](gitlab-org/security/gitlab@ce664649a8827dbd91ce5491308a040dc332dd58) ([merge request](gitlab-org/security/gitlab!3476))
+- [Gitaly keyset pager when pagination none only with tree view](gitlab-org/security/gitlab@884a061d1f04fb19bee884dac9b8cafc3c1cdb1c) ([merge request](gitlab-org/security/gitlab!3482))
+
## 16.1.4 (2023-08-03)
No changes.
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index f0cc64aa12a..f811ca23f9d 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-16.3.4 \ No newline at end of file
+fe0a04858c9a5172379077343b16e1fd2e017903
diff --git a/GITLAB_ELASTICSEARCH_INDEXER_VERSION b/GITLAB_ELASTICSEARCH_INDEXER_VERSION
index 5d72fe47eb9..7de8a1d72bb 100644
--- a/GITLAB_ELASTICSEARCH_INDEXER_VERSION
+++ b/GITLAB_ELASTICSEARCH_INDEXER_VERSION
@@ -1 +1 @@
-4.3.10
+4.3.9
diff --git a/GITLAB_KAS_VERSION b/GITLAB_KAS_VERSION
index a8ec175ad83..142d3b2b8bd 100644
--- a/GITLAB_KAS_VERSION
+++ b/GITLAB_KAS_VERSION
@@ -1 +1 @@
-v16.3.0
+v16.4.0
diff --git a/GITLAB_METRICS_EXPORTER_VERSION b/GITLAB_METRICS_EXPORTER_VERSION
deleted file mode 100644
index 7170f523988..00000000000
--- a/GITLAB_METRICS_EXPORTER_VERSION
+++ /dev/null
@@ -1 +0,0 @@
-862528b4c59ddb9b266552f53e133cfba38c9765
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index f0cc64aa12a..ff56d3c5926 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-16.3.4 \ No newline at end of file
+eadd269e8d53425f090fa059a7cd30c266bde8a7
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 0b0636a9b07..72e4eb38be4 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-14.26.0
+14.28.0
diff --git a/Gemfile b/Gemfile
index a31ae24ecbc..d9ee8a8ae71 100644
--- a/Gemfile
+++ b/Gemfile
@@ -19,6 +19,8 @@ gem 'rails', '~> 7.0.6'
gem 'activerecord-gitlab', path: 'gems/activerecord-gitlab'
+gem 'vite_rails'
+
gem 'bootsnap', '~> 1.16.0', require: false
gem 'openssl', '~> 3.0'
@@ -36,10 +38,10 @@ gem 'responders', '~> 3.0'
gem 'sprockets', '~> 3.7.0'
-gem 'view_component', '~> 3.2.0'
+gem 'view_component', '~> 3.5.0'
# Supported DBs
-gem 'pg', '~> 1.5.3'
+gem 'pg', '~> 1.5.4'
gem 'neighbor', '~> 0.2.3'
@@ -58,7 +60,7 @@ gem 'devise-pbkdf2-encryptable', '~> 0.0.0', path: 'vendor/gems/devise-pbkdf2-en
gem 'bcrypt', '~> 3.1', '>= 3.1.14'
gem 'doorkeeper', '~> 5.6', '>= 5.6.6'
gem 'doorkeeper-openid_connect', '~> 1.8', '>= 1.8.7'
-gem 'rexml', '~> 3.2.5'
+gem 'rexml', '~> 3.2.6'
gem 'ruby-saml', '~> 1.15.0'
gem 'omniauth', '~> 2.1.0'
gem 'omniauth-auth0', '~> 3.1'
@@ -91,7 +93,7 @@ gem 'timfel-krb5-auth', '~> 0.8', group: :kerberos
# Spam and anti-bot protection
gem 'recaptcha', '~> 5.12', require: 'recaptcha/rails'
gem 'akismet', '~> 3.0'
-gem 'invisible_captcha', '~> 2.0.0'
+gem 'invisible_captcha', '~> 2.1.0'
# Two-factor authentication
gem 'devise-two-factor', '~> 4.0.2'
@@ -99,7 +101,7 @@ gem 'rqrcode-rails3', '~> 0.1.7'
gem 'attr_encrypted', '~> 3.2.4', path: 'vendor/gems/attr_encrypted'
# GitLab Pages
-gem 'validates_hostname', '~> 1.0.11'
+gem 'validates_hostname', '~> 1.0.13'
gem 'rubyzip', '~> 2.3.2', require: 'zip'
# GitLab Pages letsencrypt support
gem 'acme-client', '~> 2.0'
@@ -111,7 +113,7 @@ gem 'browser', '~> 5.3.1'
gem 'ohai', '~> 17.9'
# GPG
-gem 'gpgme', '~> 2.0.22'
+gem 'gpgme', '~> 2.0.23'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
@@ -122,13 +124,13 @@ gem 'net-ldap', '~> 0.17.1'
# API
gem 'grape', '~> 1.7.1'
gem 'grape-entity', '~> 0.10.0'
-gem 'rack-cors', '~> 1.1.1', require: 'rack/cors'
+gem 'rack-cors', '~> 2.0.1', require: 'rack/cors'
gem 'grape-swagger', '~> 1.6.1', group: [:development, :test]
gem 'grape-swagger-entity', '~> 0.5.1', group: [:development, :test]
# GraphQL API
-gem 'graphql', '~> 1.13.12'
-gem 'graphiql-rails', '~> 1.8'
+gem 'graphql', '~> 1.13.19'
+gem 'graphiql-rails', '~> 1.8.0'
gem 'apollo_upload_server', '~> 2.1.0'
gem 'graphql-docs', '~> 2.1.0', group: [:development, :test]
gem 'graphlient', '~> 0.5.0' # Used by BulkImport feature (group::import)
@@ -177,9 +179,6 @@ gem 'google-apis-serviceusage_v1', '~> 0.28.0'
gem 'google-apis-sqladmin_v1beta4', '~> 0.41.0'
gem 'google-apis-androidpublisher_v3', '~> 0.34.0'
-# for aws storage
-gem 'unf', '~> 0.1.4'
-
# Seed data
gem 'seed-fu', '~> 2.3.7'
@@ -187,15 +186,15 @@ gem 'seed-fu', '~> 2.3.7'
gem 'elasticsearch-model', '~> 7.2'
gem 'elasticsearch-rails', '~> 7.2', require: 'elasticsearch/rails/instrumentation'
gem 'elasticsearch-api', '7.13.3'
-gem 'aws-sdk-core', '~> 3.180.3'
+gem 'aws-sdk-core', '~> 3.181.1'
gem 'aws-sdk-cloudformation', '~> 1'
-gem 'aws-sdk-s3', '~> 1.132.1'
+gem 'aws-sdk-s3', '~> 1.134.0'
gem 'faraday_middleware-aws-sigv4', '~>0.3.0'
gem 'typhoeus', '~> 1.4.0' # Used with Elasticsearch to support http keep-alive connections
# Markdown and HTML processing
gem 'html-pipeline', '~> 2.14.3'
-gem 'deckar01-task_list', '2.3.2'
+gem 'deckar01-task_list', '2.3.3'
gem 'gitlab-markup', '~> 1.9.0', require: 'github/markup'
gem 'commonmarker', '~> 0.23.10'
gem 'kramdown', '~> 2.3.1'
@@ -225,7 +224,7 @@ gem 'rack', '~> 2.2.8'
gem 'rack-timeout', '~> 0.6.3', require: 'rack/timeout/base'
group :puma do
- gem 'puma', '~> 6.3', require: false
+ gem 'puma', '~> 6.3', '>= 6.3.1', require: false
gem 'sd_notify', '~> 0.1.0', require: false
end
@@ -245,7 +244,7 @@ gem 'gitlab-sidekiq-fetcher', path: 'vendor/gems/sidekiq-reliable-fetch', requir
gem 'fugit', '~> 1.8.1'
# HTTP requests
-gem 'httparty', '~> 0.20.0'
+gem 'httparty', '~> 0.21.0'
# Colored output to console
gem 'rainbow', '~> 3.0'
@@ -254,7 +253,7 @@ gem 'rainbow', '~> 3.0'
gem 'ruby-progressbar', '~> 1.10'
# Linear-time regex library for untrusted regular expressions
-gem 're2', '~> 1.7.0'
+gem 're2', '2.0.0'
# Misc
@@ -302,16 +301,14 @@ gem 'ruby-openai', '~> 3.7'
gem 'circuitbox', '2.0.0'
# Sanitize user input
-gem 'sanitize', '~> 6.0'
+gem 'sanitize', '~> 6.0.2'
gem 'babosa', '~> 2.0'
# Sanitizes SVG input
gem 'loofah', '~> 2.21.3'
-# Working with license
-# Detects the open source license the repository includes
-# This version needs to be in sync with gitlab-org/gitaly
-gem 'licensee', '~> 9.15'
+# Used to provide license templates
+gem 'licensee', '~> 9.16'
# Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.7.7'
@@ -320,13 +317,13 @@ gem 'charlock_holmes', '~> 0.7.7'
gem 'ruby-magic', '~> 0.6'
# Faster blank
-gem 'fast_blank'
+gem 'fast_blank', '~> 1.0.1'
# Parse time & duration
gem 'gitlab-chronic', '~> 0.10.5'
-gem 'gitlab_chronic_duration', '~> 0.10.6.2'
+gem 'gitlab_chronic_duration', '~> 0.11'
-gem 'rack-proxy', '~> 0.7.6'
+gem 'rack-proxy', '~> 0.7.7'
gem 'sassc-rails', '~> 2.1.0'
gem 'autoprefixer-rails', '10.2.5.1'
@@ -334,7 +331,7 @@ gem 'terser', '1.0.2'
gem 'click_house-client', path: 'gems/click_house-client', require: 'click_house/client'
gem 'addressable', '~> 2.8'
-gem 'tanuki_emoji', '~> 0.6'
+gem 'tanuki_emoji', '~> 0.7'
gem 'gon', '~> 6.4.0'
gem 'request_store', '~> 1.5.1'
gem 'base32', '~> 0.3.0'
@@ -362,7 +359,6 @@ gem 'gitlab-labkit', '~> 0.34.0'
gem 'thrift', '>= 0.16.0'
# I18n
-gem 'ruby_parser', '~> 3.20', require: false
gem 'rails-i18n', '~> 7.0'
gem 'gettext_i18n_rails', '~> 1.11.0'
gem 'gettext_i18n_rails_js', '~> 1.3'
@@ -381,7 +377,7 @@ gem 'snowplow-tracker', '~> 0.8.0'
# Metrics
gem 'webrick', '~> 1.8.1', require: false
-gem 'prometheus-client-mmap', '~> 0.27', require: 'prometheus/client'
+gem 'prometheus-client-mmap', '~> 0.28', require: 'prometheus/client'
gem 'warning', '~> 1.3.0'
@@ -447,7 +443,7 @@ group :development, :test do
end
group :development, :test, :danger do
- gem 'gitlab-dangerfiles', '~> 3.13.0', require: false
+ gem 'gitlab-dangerfiles', '~> 4.0.0', require: false
end
group :development, :test, :coverage do
@@ -477,13 +473,13 @@ group :test do
gem 'capybara', '~> 3.39', '>= 3.39.2'
gem 'capybara-screenshot', '~> 1.0.26'
- gem 'selenium-webdriver', '= 4.11.0'
+ gem 'selenium-webdriver', '= 4.12.0'
gem 'graphlyte', '~> 1.0.0'
gem 'shoulda-matchers', '~> 5.1.0', require: false
gem 'email_spec', '~> 2.2.0'
- gem 'webmock', '~> 3.18.1'
+ gem 'webmock', '~> 3.19.1'
gem 'rails-controller-testing'
gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 1.2.2'
@@ -494,10 +490,10 @@ group :test do
# Moved in `test` because https://gitlab.com/gitlab-org/gitlab/-/issues/217527
gem 'derailed_benchmarks', require: false
- gem 'gitlab_quality-test_tooling', '~> 0.9.3', require: false
+ gem 'gitlab_quality-test_tooling', '~> 1.0.0', require: false
end
-gem 'octokit', '~> 4.15'
+gem 'octokit', '~> 6.0'
gem 'gitlab-mail_room', '~> 0.0.23', require: 'mail_room'
@@ -529,23 +525,23 @@ gem 'ssh_data', '~> 1.3'
gem 'spamcheck', '~> 1.3.0'
# Gitaly GRPC protocol definitions
-gem 'gitaly', '~> 16.2.0-rc4'
+gem 'gitaly', '~> 16.3.0-rc1'
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.2.0'
gem 'grpc', '~> 1.55.0'
-gem 'google-protobuf', '~> 3.23', '>= 3.23.4'
+gem 'google-protobuf', '~> 3.24', '>= 3.24.3'
gem 'toml-rb', '~> 2.2.0'
# Feature toggles
-gem 'flipper', '~> 0.25.0'
-gem 'flipper-active_record', '~> 0.25.0'
-gem 'flipper-active_support_cache_store', '~> 0.25.0'
+gem 'flipper', '~> 0.26.2'
+gem 'flipper-active_record', '~> 0.26.2'
+gem 'flipper-active_support_cache_store', '~> 0.26.2'
gem 'unleash', '~> 3.2.2'
-gem 'gitlab-experiment', '~> 0.7.1'
+gem 'gitlab-experiment', '~> 0.8.0'
# Structured logging
gem 'lograge', '~> 0.5'
@@ -575,7 +571,7 @@ gem 'mail-smtp_pool', '~> 0.1.0', path: 'vendor/gems/mail-smtp_pool', require: f
gem 'microsoft_graph_mailer', '~> 0.1.0', path: 'vendor/gems/microsoft_graph_mailer'
# File encryption
-gem 'lockbox', '~> 1.1.1'
+gem 'lockbox', '~> 1.3.0'
# Email validation
gem 'valid_email', '~> 0.1'
diff --git a/Gemfile.checksum b/Gemfile.checksum
index d87b57c74a6..3efef6fcc9f 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -37,9 +37,9 @@
{"name":"aws-eventstream","version":"1.2.0","platform":"ruby","checksum":"ffa53482c92880b001ff2fb06919b9bb82fd847cbb0fa244985d2ebb6dd0d1df"},
{"name":"aws-partitions","version":"1.761.0","platform":"ruby","checksum":"291e444e1edfc92c5521a6dbdd1236ccc3f122b3520163b2be6ec5b6ef350ef2"},
{"name":"aws-sdk-cloudformation","version":"1.41.0","platform":"ruby","checksum":"31e47539719734413671edf9b1a31f8673fbf9688549f50c41affabbcb1c6b26"},
-{"name":"aws-sdk-core","version":"3.180.3","platform":"ruby","checksum":"829915d511bb018acab0905d860c1831c4a7f7e8daba1afd546225b2c9918351"},
+{"name":"aws-sdk-core","version":"3.181.1","platform":"ruby","checksum":"eb2e42271eecc80e2dd2496c78e45ab29745db0f707bd5cea9f816d20081dce2"},
{"name":"aws-sdk-kms","version":"1.64.0","platform":"ruby","checksum":"40de596c95047bfc6e1aacea24f3df6241aa716b6f7ce08ac4c5f7e3120395ad"},
-{"name":"aws-sdk-s3","version":"1.132.1","platform":"ruby","checksum":"cac01fbba5d717907b8df7b4e482447678c8392c7a4707ba09956d10e3549145"},
+{"name":"aws-sdk-s3","version":"1.134.0","platform":"ruby","checksum":"25135ec8af8b44c5221f50241810d3ae60bad0f52bfd618ab31d18ad52117fb9"},
{"name":"aws-sigv4","version":"1.6.0","platform":"ruby","checksum":"ca9e6a15cd424f1f32b524b9760995331459bc22e67d3daad4fcf0c0084b087d"},
{"name":"axe-core-api","version":"4.6.0","platform":"ruby","checksum":"1b0ddec3353f108dc10363baf2282f43a5ff7f13d4e25f99071294e78f8a6c62"},
{"name":"axe-core-rspec","version":"4.6.0","platform":"ruby","checksum":"11c25bc9dd388c137ba4e5e63d64d20092bf22c884d8ffc829a22acfbacd747f"},
@@ -96,14 +96,14 @@
{"name":"crystalball","version":"0.7.0","platform":"ruby","checksum":"6e729f372a5071daec877adb40c5df4cb25fe21f350635e2a9624373fc151ef2"},
{"name":"css_parser","version":"1.14.0","platform":"ruby","checksum":"f2ce6148cd505297b07bdbe7a5db4cce5cf530071f9b732b9a23538d6cdc0113"},
{"name":"cvss-suite","version":"3.0.1","platform":"ruby","checksum":"b5ca9e9e94032a42fd0dc28c1e305378b62c949e35ed7111fc4a1d76f68ad3f9"},
-{"name":"danger","version":"8.6.1","platform":"ruby","checksum":"d95eb58b41f68d3aaa9bbef697916b6b4d161a38819517c98562531be75cdfd8"},
+{"name":"danger","version":"9.3.1","platform":"ruby","checksum":"9070fbac181eb45fb9b69ea25e6ea4faa86796ef33bf8d00346cab4385e51df5"},
{"name":"danger-gitlab","version":"8.0.0","platform":"ruby","checksum":"497dd7d0f6513913de651019223d8058cf494df10acbd17de92b175dfa04a3a8"},
{"name":"database_cleaner","version":"1.7.0","platform":"ruby","checksum":"bdf833c197afac7054015bcde2567c3834c366bbfe6a377c30151ca984b32016"},
{"name":"date","version":"3.3.3","platform":"java","checksum":"584e0a582d1eb2207b4eaac089d8a43f2ca10bea02682f286099642f15c56cce"},
{"name":"date","version":"3.3.3","platform":"ruby","checksum":"819792019d5712b748fb15f6dfaaedef14b0328723ef23583ea35f186774530f"},
{"name":"dead_end","version":"3.1.1","platform":"ruby","checksum":"1011df7f7c0149be004e11cbbc37747760227c55305cd902fd3c06e1394b2f5b"},
{"name":"debug_inspector","version":"1.1.0","platform":"ruby","checksum":"eaa5a2d0195e1d65fb4164e8e7e466cca2e7eb53bc5e608cf12b8bf02c3a8606"},
-{"name":"deckar01-task_list","version":"2.3.2","platform":"ruby","checksum":"5a19092548d24309d8b2c2704d64cdc08a4a615823c9a722f4142edec1de8805"},
+{"name":"deckar01-task_list","version":"2.3.3","platform":"ruby","checksum":"918abaf3f81e6c0d224c2b7bef593d7f84ee5847a0692726d24e3fb272c2c758"},
{"name":"declarative","version":"0.0.20","platform":"ruby","checksum":"8021dd6cb17ab2b61233c56903d3f5a259c5cf43c80ff332d447d395b17d9ff9"},
{"name":"declarative_policy","version":"1.1.0","platform":"ruby","checksum":"9af4cf299ade03f2bbf63908f2ce6a117d132fc714c39a128596667fb13331cb"},
{"name":"deprecation_toolkit","version":"1.5.1","platform":"ruby","checksum":"a8a1ab1a19ae40ea12560b65010e099f3459ebde390b76621ef0c21c516a04ba"},
@@ -125,6 +125,7 @@
{"name":"doorkeeper","version":"5.6.6","platform":"ruby","checksum":"2344e86c77770526efcda893b5217aa13d1c7eb1b40de840b58b19eb1ff757e0"},
{"name":"doorkeeper-openid_connect","version":"1.8.7","platform":"ruby","checksum":"71edaf33118deefe25674ba3f8280c32835f057351f70e9beb222c0fd6b8e786"},
{"name":"dotenv","version":"2.7.6","platform":"ruby","checksum":"2451ed5e8e43776d7a787e51d6f8903b98e446146c7ad143d5678cc2c409d547"},
+{"name":"dry-cli","version":"1.0.0","platform":"ruby","checksum":"28ead169f872954dd08910eb8ead59cf86cd18b4aab321e8eeefe945749569f0"},
{"name":"dry-core","version":"1.0.0","platform":"ruby","checksum":"7a92099870967f0d2c9997950608cb8bb622dafeea20b2fe1dd49e9ba1d0f305"},
{"name":"dry-inflector","version":"1.0.0","platform":"ruby","checksum":"6ad22361ca2d6f3f001ae3037ffcfea01163f644280d13a9195d3c3a94dd1626"},
{"name":"dry-logic","version":"1.5.0","platform":"ruby","checksum":"99ed2180f1970c3d8247004f277a01dffbe8e82cf6680de9c7209312d86cd416"},
@@ -146,7 +147,7 @@
{"name":"erubi","version":"1.12.0","platform":"ruby","checksum":"27bedb74dfb1e04ff60674975e182d8ca787f2224f2e8143268c7696f42e4723"},
{"name":"escape_utils","version":"1.2.1","platform":"ruby","checksum":"e5292fe8d7e12a9bcb4502d99e28fb602e4e1514690d98a1c4957f6f77b4b162"},
{"name":"et-orbi","version":"1.2.7","platform":"ruby","checksum":"3b693d47f94a4060ccc07e60adda488759b1e8b9228a633ebbad842dfc245fb4"},
-{"name":"ethon","version":"0.15.0","platform":"ruby","checksum":"0809805a035bc10f54162ca99f15ded49e428e0488bcfe1c08c821e18261a74d"},
+{"name":"ethon","version":"0.16.0","platform":"ruby","checksum":"bba0da1cea8ac3e1f5cdd7cb1cb5fc78d7ac562c33736f18f0c3eb2b63053d9e"},
{"name":"excon","version":"0.99.0","platform":"ruby","checksum":"09f0de591b5bd1c642680aa1340538a16b90c1111694b46f61f6d8bfdd340249"},
{"name":"execjs","version":"2.8.1","platform":"ruby","checksum":"6d939919cfd81bcc4d6556f322c3995a70cfe4289ea0bd3b1f999b489c323088"},
{"name":"expgen","version":"0.1.1","platform":"ruby","checksum":"4e6a0f65b210a201d6045debb3e62a24e33251a49f81a11b067d303a60d3a239"},
@@ -169,7 +170,8 @@
{"name":"faraday_middleware","version":"1.2.0","platform":"ruby","checksum":"ded15d574d50e92bd04448d5566913af5cb1a01b2fa311ceecc2464fa0ab88af"},
{"name":"faraday_middleware-aws-sigv4","version":"0.3.0","platform":"ruby","checksum":"744654bd5b15539a54aed39b806e2dfb45aa47708fa1e6f6766fedcda6c262be"},
{"name":"faraday_middleware-multi_json","version":"0.0.6","platform":"ruby","checksum":"38fc4dab7a78916ad09827d5a164aab62fbf2cb8b9de0507763de1f561d7a118"},
-{"name":"fast_blank","version":"1.0.0","platform":"ruby","checksum":"a67c93dbcb8c34ba40973688e4b600b640760503362f3aeb63b37ebe3d8d419b"},
+{"name":"fast_blank","version":"1.0.1","platform":"java","checksum":"90d82106b0e4aa19ac24ba1604c79a0c5a4c471601e800c9b2b072938a6d9a92"},
+{"name":"fast_blank","version":"1.0.1","platform":"ruby","checksum":"269fc30414fed4e6403bc4a49081e1ea539f8b9226e59276ed1efaefabaa17ea"},
{"name":"fast_gettext","version":"2.3.0","platform":"ruby","checksum":"0253e26423ccab68061c42387827e3b99243a1b15ad614df1c800ba870d64f84"},
{"name":"ffaker","version":"2.10.0","platform":"ruby","checksum":"4323b85b4bbdb0d932695b2ebffeb3645304215092e64e2a451630a9f5a5e507"},
{"name":"ffi","version":"1.15.5","platform":"java","checksum":"610b9a993e67b812123cfedc1c45a639aa2f2455747af5443d54f98e092b1abe"},
@@ -182,9 +184,9 @@
{"name":"ffi-yajl","version":"2.6.0","platform":"universal-java","checksum":"1159a093c51d75d67578e31d2ed429f2481ef7e73021c5d667ebf6ab481a0d21"},
{"name":"filelock","version":"1.1.1","platform":"ruby","checksum":"5207258374370a75d5927b2eaf9b831732d224e48ce56c318e8308c7cdcabb20"},
{"name":"find_a_port","version":"1.0.1","platform":"ruby","checksum":"605d6a84b5e6f138da2b06c87c5a4a0231e4fdc9b9a92022d9caa361f77d5ceb"},
-{"name":"flipper","version":"0.25.0","platform":"ruby","checksum":"ccb2776752b8378bc994c9d873ccde290c090341940761b873494695ee697add"},
-{"name":"flipper-active_record","version":"0.25.0","platform":"ruby","checksum":"85a5c99465e2cc6a09e91931a9998b0dbd463cd6c80dd513129377132e3eb67f"},
-{"name":"flipper-active_support_cache_store","version":"0.25.0","platform":"ruby","checksum":"7282bf994b08d1a076b65c6f3b51e3dc04fcb00fa6e7b20089e60db25c7b531b"},
+{"name":"flipper","version":"0.26.2","platform":"ruby","checksum":"6d577208d971b2d53b7c090ef19765685c31bb43c3cc345d4ee11c1052f6f988"},
+{"name":"flipper-active_record","version":"0.26.2","platform":"ruby","checksum":"61deaeef8ce2f775e67d7095f40fd95fc2d07241e143dd4436e78c7b26a320bc"},
+{"name":"flipper-active_support_cache_store","version":"0.26.2","platform":"ruby","checksum":"c2d3883ad1e5c7de827c37df455ffe6e175bc0be93f2a260c54efdabb313d2b0"},
{"name":"fog-aliyun","version":"0.4.0","platform":"ruby","checksum":"8f2334604beb781eafbb9cd5f50141fbb2c7eb77c7f2b01f45c2e04db0e5cc38"},
{"name":"fog-aws","version":"3.18.0","platform":"ruby","checksum":"f4c5880ecfbc4edbf711dfd41140f9f17dfc68b519546d121448d2d3a5584704"},
{"name":"fog-core","version":"2.1.0","platform":"ruby","checksum":"53e5d793554d7080d015ef13cd44b54027e421d924d9dba4ce3d83f95f37eda9"},
@@ -202,12 +204,12 @@
{"name":"gettext","version":"3.3.6","platform":"ruby","checksum":"ee6bbd1b2f833ee52d7797fa68acbfecc4726aec6b6280fd7eab92aa0190b413"},
{"name":"gettext_i18n_rails","version":"1.11.0","platform":"ruby","checksum":"e19c7e4a256c500f7f38396dca44a282b9838ae278f57c362993a54964b22bbe"},
{"name":"gettext_i18n_rails_js","version":"1.3.0","platform":"ruby","checksum":"5d10afe4be3639bff78c50a56768c20f39aecdabc580c08aa45573911c2bd687"},
-{"name":"git","version":"1.11.0","platform":"ruby","checksum":"7e95ba4da8298a0373ef1a6862aa22007d761f3c8274b675aa787966fecea0f1"},
-{"name":"gitaly","version":"16.2.0.pre.rc4","platform":"ruby","checksum":"08756662fb1537b7d481bbd377c20648f3e0c50fff7d1fd25c6e6034cea2517c"},
+{"name":"git","version":"1.18.0","platform":"ruby","checksum":"c9b80462e4565cd3d7a9ba8440c41d2c52244b17b0dad0bfddb46de70630c465"},
+{"name":"gitaly","version":"16.3.0.pre.rc1","platform":"ruby","checksum":"55d9cc414a4f3859588f3770bd88d7c67c0f5454a1178b018b7a6f6913674c43"},
{"name":"gitlab","version":"4.19.0","platform":"ruby","checksum":"3f645e3e195dbc24f0834fbf83e8ccfb2056d8e9712b01a640aad418a6949679"},
{"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"},
-{"name":"gitlab-dangerfiles","version":"3.13.0","platform":"ruby","checksum":"2081eac7fe1f538427f8ebec1e8cd7c143a30d50e1470348cdec4f2d273ea1ad"},
-{"name":"gitlab-experiment","version":"0.7.1","platform":"ruby","checksum":"166dddb3aa83428bcaa93c35684ed01dc4d61f321fd2ae40b020806dc54a7824"},
+{"name":"gitlab-dangerfiles","version":"4.0.0","platform":"ruby","checksum":"e3abe81790388e6a686a2cfb248c9a46486c0efbf169a07b62df2dad740f4812"},
+{"name":"gitlab-experiment","version":"0.8.0","platform":"ruby","checksum":"b4e2f73e0af19cdd899a745f5a846c1318d44054e068a8f4ac887f6b1017d3f9"},
{"name":"gitlab-fog-azure-rm","version":"1.8.0","platform":"ruby","checksum":"e4f24b174b273b88849d12fbcfecb79ae1c09f56cbd614998714c7f0a81e6c28"},
{"name":"gitlab-labkit","version":"0.34.0","platform":"ruby","checksum":"ca5c504201390cd07ba1029e6ca3059f4e2e6005eb121ba8a103af1e166a3ecd"},
{"name":"gitlab-license","version":"2.3.0","platform":"ruby","checksum":"60cae3871c46607dde58994faf761c6755adc61133a92e5ab59ab26a8b9b4157"},
@@ -215,9 +217,9 @@
{"name":"gitlab-markup","version":"1.9.0","platform":"ruby","checksum":"7eda045a08ec2d110084252fa13a8c9eac8bdac0e302035ca7db4b82bcbd7ed4"},
{"name":"gitlab-net-dns","version":"0.9.2","platform":"ruby","checksum":"f726d978479d43810819f12a45c0906d775a07e34df111bbe693fffbbef3059d"},
{"name":"gitlab-styles","version":"10.1.0","platform":"ruby","checksum":"f42745f5397d042fe24cf2d0eb56c995b37f9f43d8fb79b834d197a1cafdc84a"},
-{"name":"gitlab_chronic_duration","version":"0.10.6.2","platform":"ruby","checksum":"6dda4cfe7dca9b958f163ac8835c3d9cc70cf8df8cbb89bb2fbf9ba4375105fb"},
+{"name":"gitlab_chronic_duration","version":"0.11.0","platform":"ruby","checksum":"c2fd201724a9031ff0af23d07a30231cebefbf83c3e682daae452cda5f514ba6"},
{"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"},
-{"name":"gitlab_quality-test_tooling","version":"0.9.3","platform":"ruby","checksum":"9751f3504b717499588bd0fa5517de9b6756e8b9548777ea0283b889694580f0"},
+{"name":"gitlab_quality-test_tooling","version":"1.0.0","platform":"ruby","checksum":"b030be168a6a0eb3c47202beb6c64a4fbe36f5547d189c3f64cad29cfcc331db"},
{"name":"globalid","version":"1.1.0","platform":"ruby","checksum":"b337e1746f0c8cb0a6c918234b03a1ddeb4966206ce288fbb57779f59b2d154f"},
{"name":"gon","version":"6.4.0","platform":"ruby","checksum":"e3a618d659392890f1aa7db420f17c75fd7d35aeb5f8fe003697d02c4b88d2f0"},
{"name":"google-apis-androidpublisher_v3","version":"0.34.0","platform":"ruby","checksum":"d7e1d7dd92f79c498fe2082222a1740d788e022e660c135564b3fd299cab5425"},
@@ -240,20 +242,20 @@
{"name":"google-cloud-errors","version":"1.3.0","platform":"ruby","checksum":"450b681e24c089a20721a01acc4408bb4a7b0df28c175aaab488da917480d64b"},
{"name":"google-cloud-profiler-v2","version":"0.4.0","platform":"ruby","checksum":"53fc2ab175d08f54233c644310d47798feac996220916815c4fb44c937b5d3e3"},
{"name":"google-cloud-storage","version":"1.44.0","platform":"ruby","checksum":"299a1e055c9277c8120f7c10d21d37e4d8c17c7b963350c0e0bff7e9d9a570ea"},
-{"name":"google-protobuf","version":"3.23.4","platform":"aarch64-linux","checksum":"f886ff6f24a4de32e08915d398e574e444eda289999124acfc7c5d1fd1eec7f5"},
-{"name":"google-protobuf","version":"3.23.4","platform":"arm64-darwin","checksum":"2637adb0fc734e9f2d0118c37ae1934fac6fe19ad28dabcb49790a4711cdee99"},
-{"name":"google-protobuf","version":"3.23.4","platform":"java","checksum":"a3346070a005c92f9a50c4d3d83964149e8f1bb4edf7e026fc337315f50117f0"},
-{"name":"google-protobuf","version":"3.23.4","platform":"ruby","checksum":"f239ea4b2009976d102e55e808b778abd18ce20721f32c3fcaf829d8e7a305b7"},
-{"name":"google-protobuf","version":"3.23.4","platform":"x64-mingw-ucrt","checksum":"0c7fde44cb23df5905fa4f9f7c1c629f5be10cef3cb36d89f4cb025eee6627e3"},
-{"name":"google-protobuf","version":"3.23.4","platform":"x64-mingw32","checksum":"bc8a2801dfdf73e41565d72ba1d15bcf5cf72e05d34099cc7fcd39727111f3d2"},
-{"name":"google-protobuf","version":"3.23.4","platform":"x86-linux","checksum":"49d380017efcd03972fc007faad9aa9a47cb60dab484094bf233969b7c355b93"},
-{"name":"google-protobuf","version":"3.23.4","platform":"x86-mingw32","checksum":"9583cb050c064ee9adc1eb88f6bf9db081f6d4f4f3accb18653f0c392a5ed999"},
-{"name":"google-protobuf","version":"3.23.4","platform":"x86_64-darwin","checksum":"2d324de99d797287e8845ef1ebf561c9f9b396f7dba4075fa4f34000be94d641"},
-{"name":"google-protobuf","version":"3.23.4","platform":"x86_64-linux","checksum":"73a753b1aa0305d3de31ba5c8f692821efafb8e7f8250a88877bc0fc9a1abea5"},
+{"name":"google-protobuf","version":"3.24.3","platform":"aarch64-linux","checksum":"02591f0bb6a7b34da7f4451b3e9b684787eae6fab5c9283ff09be993830683cd"},
+{"name":"google-protobuf","version":"3.24.3","platform":"arm64-darwin","checksum":"34919ce25e3260954a509a7fb4ff4767e438c1d09cffe0998fa97aa7f547c50c"},
+{"name":"google-protobuf","version":"3.24.3","platform":"java","checksum":"f1582bd2665df61a363501b2a51bea61e2c8466bd1f8823a22b53cbea5aa7401"},
+{"name":"google-protobuf","version":"3.24.3","platform":"ruby","checksum":"63f3cceb398b5f3258760da95037d26ef65405aa3425fd7ba1560fce4827945d"},
+{"name":"google-protobuf","version":"3.24.3","platform":"x64-mingw-ucrt","checksum":"381f16aeda20d23465b9d9efffaa660367cda951299df0d5fd5662e9a119a36c"},
+{"name":"google-protobuf","version":"3.24.3","platform":"x64-mingw32","checksum":"5a687545a4a9deb93375107600aee43edfc495979ec8b88fff39d8c139e49330"},
+{"name":"google-protobuf","version":"3.24.3","platform":"x86-linux","checksum":"d7f556d618b83629a49f831a9358122a22c3a3ebd65f59c10f690c4ec95ad321"},
+{"name":"google-protobuf","version":"3.24.3","platform":"x86-mingw32","checksum":"05711b1c8cdf77fdbe8eabbe477b2b792758b6e2c5a72add222ac6f4c5626119"},
+{"name":"google-protobuf","version":"3.24.3","platform":"x86_64-darwin","checksum":"10d9645ebe89758fd81fcbcd678aaaa30c34ca2b2a2182e8dfc90e29df9cafb4"},
+{"name":"google-protobuf","version":"3.24.3","platform":"x86_64-linux","checksum":"e081a8345680b7883b48823a4123acdf45ebd169e3d5a3c2e0cb9ac47fc896eb"},
{"name":"googleapis-common-protos","version":"1.4.0","platform":"ruby","checksum":"da2380fb5ab1563580816c74e8d684ac17512c3654c829a3ee84f6d6139de382"},
{"name":"googleapis-common-protos-types","version":"1.5.0","platform":"ruby","checksum":"5769cf7376abc86ef7f5897a4aaca1d5c5a3c49ddabeddd2c251fcf8155f858b"},
{"name":"googleauth","version":"1.3.0","platform":"ruby","checksum":"51dd7362353cf1e90a2d01e1fb94321ae3926c776d4dc4a79db65230217ffcc2"},
-{"name":"gpgme","version":"2.0.22","platform":"ruby","checksum":"7c6904952afdd0bf2c7c3ed6de98a5143f86c6b7390dbcd9d7012bddfa3ec862"},
+{"name":"gpgme","version":"2.0.23","platform":"ruby","checksum":"c87bbafdb8719da7c58ebcac08297aa1fb227022ac6cd2972829ba68adc91c04"},
{"name":"grape","version":"1.7.1","platform":"ruby","checksum":"6b679d8918ee3dc19b0da95a5069dc95a71a15cf5788f5f787bb2ededf58cbb6"},
{"name":"grape-entity","version":"0.10.0","platform":"ruby","checksum":"9aed1e7cbbc96d9e73f72e5f32c776d4ba8a5baf54c3acda2682008dba2b2cfe"},
{"name":"grape-path-helpers","version":"1.7.1","platform":"ruby","checksum":"2e27271a20d4073e3a3b2b955425c7f803e198be3ba8f6e59e3d59643c5381e2"},
@@ -263,7 +265,7 @@
{"name":"graphiql-rails","version":"1.8.0","platform":"ruby","checksum":"02e2c5098be2c6c29219a0e9b2910a2cd3c494301587a3199a7c4484d8038ed1"},
{"name":"graphlient","version":"0.5.0","platform":"ruby","checksum":"0f2c9416142e50b6bd4edcd86fe6810f792951732c487f9061aee6d420e0f292"},
{"name":"graphlyte","version":"1.0.0","platform":"ruby","checksum":"b5af4ab67dde6e961f00ea1c18f159f73b52ed11395bb4ece297fe628fa1804d"},
-{"name":"graphql","version":"1.13.12","platform":"ruby","checksum":"1d82666cf201193a8d0cb54cea38576b820418db4869b549f61a35f3a2d97ac3"},
+{"name":"graphql","version":"1.13.19","platform":"ruby","checksum":"43581db30e21f781d3c175e85807071dc0ba94304d59621b44116f817a5f5a5a"},
{"name":"graphql-client","version":"0.17.0","platform":"ruby","checksum":"5aaf02ce8f2dbc8e3ba05a7eaeb3ad9336762c4424c6093f4438fbb9490eeb5d"},
{"name":"graphql-docs","version":"2.1.0","platform":"ruby","checksum":"7eb82402f8fda455104b2b60364e9ada145d79d3121a8f915790d49da38bb576"},
{"name":"grpc","version":"1.55.0","platform":"ruby","checksum":"529332f8e5e98f5b138afd5c4a9c7bdc9e247f4c10c84c1adbf1a114eba161ae"},
@@ -295,15 +297,15 @@
{"name":"http-accept","version":"1.7.0","platform":"ruby","checksum":"c626860682bfbb3b46462f8c39cd470fd7b0584f61b3cc9df5b2e9eb9972a126"},
{"name":"http-cookie","version":"1.0.5","platform":"ruby","checksum":"73756d46c7dbdc7023deecdb8a171348ea95a1b99810b31cfe8b4fb4e9a6318f"},
{"name":"http-form_data","version":"2.3.0","platform":"ruby","checksum":"cc4eeb1361d9876821e31d7b1cf0b68f1cf874b201d27903480479d86448a5f3"},
-{"name":"httparty","version":"0.20.0","platform":"ruby","checksum":"490d2a028a5accc611f1685d479d80ef80b129140d24a93c53c119f578614867"},
+{"name":"httparty","version":"0.21.0","platform":"ruby","checksum":"00ef7bf9a71f30a3bff88edeb5b16a34bea883ab67c246b3f0db2d6794fe1214"},
{"name":"httpclient","version":"2.8.3","platform":"ruby","checksum":"2951e4991214464c3e92107e46438527d23048e634f3aee91c719e0bdfaebda6"},
-{"name":"i18n","version":"1.12.0","platform":"ruby","checksum":"91e3cc1b97616d308707eedee413d82ee021d751c918661fb82152793e64aced"},
+{"name":"i18n","version":"1.14.1","platform":"ruby","checksum":"9d03698903547c060928e70a9bc8b6b87fda674453cda918fc7ab80235ae4a61"},
{"name":"i18n_data","version":"0.13.1","platform":"ruby","checksum":"e5aa99b09a69b463bb0443fc1f9540351a49f3d1541c5e91316bafa035c63f66"},
{"name":"icalendar","version":"2.8.0","platform":"ruby","checksum":"e404f970c7572bdebf6f09f9890970b68aab400ba9e609dc7d46098f28d0ee87"},
{"name":"ice_cube","version":"0.16.4","platform":"ruby","checksum":"da117e5de24bdc33931be629f9b55048641924442c7e9b72fedc05e5592531b7"},
{"name":"ice_nine","version":"0.11.2","platform":"ruby","checksum":"5d506a7d2723d5592dc121b9928e4931742730131f22a1a37649df1c1e2e63db"},
{"name":"imagen","version":"0.1.8","platform":"ruby","checksum":"fde7b727d4fe79c6bb5ac46c1f7184bf87a6d54df54d712ad2be039d2f93a162"},
-{"name":"invisible_captcha","version":"2.0.0","platform":"ruby","checksum":"a381edcb1d1b8744e9dc398ecad142c3e2ab077604645f85eeb02f9ea535c042"},
+{"name":"invisible_captcha","version":"2.1.0","platform":"ruby","checksum":"02b452f3eb1b691d155ba3e8e97e1be0e6b6be62e8bc94957234b9cde0852b1e"},
{"name":"ipaddr","version":"1.2.5","platform":"ruby","checksum":"4e679c71d6d8ed99f925487082f70f9a958de155591caa0e7f6cef9aa160f17a"},
{"name":"ipaddress","version":"0.8.3","platform":"ruby","checksum":"85640c4f9194c26937afc8c78e3074a8e7c97d5d1210358d1440f01034d006f5"},
{"name":"jaeger-client","version":"1.1.0","platform":"ruby","checksum":"cb5e9b9bbee6ee8d6a82d03d947a5b04543d8c0a949c22e484254f18d8a458a8"},
@@ -335,11 +337,11 @@
{"name":"letter_opener_web","version":"2.0.0","platform":"ruby","checksum":"33860ad41e1785d75456500e8ca8bba8ed71ee6eaf08a98d06bbab67c5577b6f"},
{"name":"libyajl2","version":"1.2.0","platform":"ruby","checksum":"1117cd1e48db013b626e36269bbf1cef210538ca6d2e62d3fa3db9ded005b258"},
{"name":"license_finder","version":"7.0.1","platform":"ruby","checksum":"0b22c9567e2a8b102c7245da49ebeddaec60f66d237d2bb91b9feddf5d242f6a"},
-{"name":"licensee","version":"9.15.2","platform":"ruby","checksum":"4b6959b544da88499d3be0d9f486179c90b93d5049ef500ae340ac1420493ded"},
+{"name":"licensee","version":"9.16.0","platform":"ruby","checksum":"7b1693639019dbb1d3e020d72c4470ca84da3cfc67e4d6da1d1cdcb736d09044"},
{"name":"listen","version":"3.7.1","platform":"ruby","checksum":"3b80caa7aa77fae836916c2f9e3fbcafbd15f5d695dd487c1f5b5e7e465efe29"},
{"name":"llhttp-ffi","version":"0.4.0","platform":"ruby","checksum":"e5f7327db3cf8007e648342ef76347d6e0ae545a8402e519cca9c886eb37b001"},
{"name":"locale","version":"2.1.3","platform":"ruby","checksum":"b6ddee011e157817cb98e521b3ce7cb626424d5882f1e844aafdee3e8b212725"},
-{"name":"lockbox","version":"1.1.1","platform":"ruby","checksum":"0af16b14c54f791c148615a0115387b51903d868c7fe622f49606c97071c2ac0"},
+{"name":"lockbox","version":"1.3.0","platform":"ruby","checksum":"ca8e5806e4e0c56d1d762ac5cf401940ff53fc37554ef623d3313c7a6331a3ea"},
{"name":"lograge","version":"0.11.2","platform":"ruby","checksum":"4cbd1554b86f545d795eff15a0c24fd25057d2ac4e1caa5fc186168b3da932ef"},
{"name":"loofah","version":"2.21.3","platform":"ruby","checksum":"43d21a8bb96c380199a8f66e0298649eaa7362fcd32f3a6114f39775e524e4dc"},
{"name":"lookbook","version":"2.0.1","platform":"ruby","checksum":"0f14729c8c992810de0792a0be865a5792e5765fbaea5950cce74c6e5c73fc4a"},
@@ -357,7 +359,7 @@
{"name":"mini_histogram","version":"0.3.1","platform":"ruby","checksum":"6a114b504e4618b0e076cc672996036870f7cc6f16b8e5c25c0c637726d2dd94"},
{"name":"mini_magick","version":"4.10.1","platform":"ruby","checksum":"e939d2c70c8002233fc6b1eecfe762f38a156d69ad31a87160205870be08f852"},
{"name":"mini_mime","version":"1.1.2","platform":"ruby","checksum":"a54aec0cc7438a03a850adb00daca2bdb60747f839e28186994df057cea87151"},
-{"name":"mini_portile2","version":"2.8.2","platform":"ruby","checksum":"46b2d244cc6ff01a89bf61274690c09fdbdca47a84ae9eac39039e81231aee7c"},
+{"name":"mini_portile2","version":"2.8.4","platform":"ruby","checksum":"180bc4193701bbeb9b6c02df5a6b8185bff7f32abd466dd97d6532d36e45b20a"},
{"name":"minitest","version":"5.11.3","platform":"ruby","checksum":"78e18aa2c49c58e9bc53c54a0b900e87ad0a96394e92fbbfa58d3ff860a68f45"},
{"name":"mixlib-cli","version":"2.1.8","platform":"ruby","checksum":"e6f27be34d580f6ed71731ca46b967e57793a627131c1f6e1ed2dad39ea3bdf9"},
{"name":"mixlib-config","version":"3.0.9","platform":"ruby","checksum":"9867adab3ab547eb74a8efdc9dfab6bcc83d2802a571ff8af8d6e981ca8d53ab"},
@@ -404,7 +406,7 @@
{"name":"numerizer","version":"0.2.0","platform":"ruby","checksum":"e58076d5ee5370417b7e52d9cb25836d62acd1b8d9a194c308707986c1705d7b"},
{"name":"oauth","version":"0.5.6","platform":"ruby","checksum":"4085fe28e0c5e2434135e00a6555294fd2a4ff96a98d1bdecdcd619fc6368dff"},
{"name":"oauth2","version":"2.0.9","platform":"ruby","checksum":"b21f9defcf52dc1610e0dfab4c868342173dcd707fd15c777d9f4f04e153f7fb"},
-{"name":"octokit","version":"4.25.1","platform":"ruby","checksum":"c02092ee82dcdfe84db0e0ea630a70d32becc54245a4f0bacfd21c010df09b96"},
+{"name":"octokit","version":"6.1.1","platform":"ruby","checksum":"920e4a9d820205f70738f58de6a7e6ef0e2f25b27db954b5806a63105207b0bf"},
{"name":"ohai","version":"17.9.0","platform":"ruby","checksum":"c59cf16124c0a6481fb85013ec7ec5b398651b6abed782d3e06ab058ce9a5406"},
{"name":"oj","version":"3.13.23","platform":"ruby","checksum":"206dfdc4020ad9974705037f269cfba211d61b7662a58c717cce771829ccef51"},
{"name":"oj-introspect","version":"0.7.2","platform":"ruby","checksum":"c415a44567ed2870d8e963a69421d9322128e194fab7867e37e54d5a25d5333d"},
@@ -441,10 +443,7 @@
{"name":"parslet","version":"1.8.2","platform":"ruby","checksum":"08d1ab3721cd3f175bfbee8788b2ddff71f92038f2d69bd65454c22bb9fbd98a"},
{"name":"pastel","version":"0.8.0","platform":"ruby","checksum":"481da9fb7d2f6e6b1a08faf11fa10363172dc40fd47848f096ae21209f805a75"},
{"name":"peek","version":"1.1.0","platform":"ruby","checksum":"d6501ead8cde46d8d8ed0d59eb6f0ba713d0a41c11a2c4a81447b2dce37b3ecc"},
-{"name":"pg","version":"1.5.3","platform":"ruby","checksum":"6b9ee5e2d5aee975588232c41f8203e766157cf71dba54ee85b343a45ced9bfd"},
-{"name":"pg","version":"1.5.3","platform":"x64-mingw-ucrt","checksum":"1f2a6b2afaf0ccb8afe8b6a00131bce8151fbd6e8826b2d944288f6f2b615389"},
-{"name":"pg","version":"1.5.3","platform":"x64-mingw32","checksum":"ab7f5f3020323094a2b16f9638166b04c103e152a9079a1b8e795f4bf79765e0"},
-{"name":"pg","version":"1.5.3","platform":"x86-mingw32","checksum":"aa6ddda9887462d30a6d49d875eb9d27fca8cdb7185103b650e7351b38f15ddf"},
+{"name":"pg","version":"1.5.4","platform":"ruby","checksum":"04f7b247151c639a0b955d8e5a9a41541343f4640aa3c2bdf749a872c339d25d"},
{"name":"pg_query","version":"4.2.3","platform":"ruby","checksum":"1cc9955c7bce8e51e1abc11f1952e3d9d0f1cd4c16c58c56ec75d5aaf1cfd697"},
{"name":"plist","version":"3.6.0","platform":"ruby","checksum":"f468bcf6b72ec6d1585ed6744eb4817c1932a5bf91895ed056e69b7f12ca10f2"},
{"name":"png_quantizator","version":"0.2.1","platform":"ruby","checksum":"6023d4d064125c3a7e02929c95b7320ed6ac0d7341f9e8de0c9ea6576ef3106b"},
@@ -452,19 +451,18 @@
{"name":"premailer","version":"1.16.0","platform":"ruby","checksum":"03e4402c448e6bae13fb5f6301a8bde4f3508e1bff90ae7c0972c7be94694786"},
{"name":"premailer-rails","version":"1.10.3","platform":"ruby","checksum":"7cdcb97027866f7a81c490c6d15ada7f39666b5f6375f0821b7e97e0483b112f"},
{"name":"proc_to_ast","version":"0.1.0","platform":"ruby","checksum":"92a73fa66e2250a83f8589f818b0751bcf227c68f85916202df7af85082f8691"},
-{"name":"prometheus-client-mmap","version":"0.27.0","platform":"aarch64-linux","checksum":"307c880989a7963c2a7e00ed941e49a192c8fcc2dca23579041ddc0d930c349c"},
-{"name":"prometheus-client-mmap","version":"0.27.0","platform":"arm64-darwin","checksum":"224a21c9a9ee2823ba683e1229d29314a61405e26371a8405afcb83030a38932"},
-{"name":"prometheus-client-mmap","version":"0.27.0","platform":"ruby","checksum":"716f57a352e8fa00b3ec24056ae26c64f5f0e6f076244b1e39b57db86b2f7067"},
-{"name":"prometheus-client-mmap","version":"0.27.0","platform":"x86_64-darwin","checksum":"95300e4a739cd9a6d17bf83bfeca4b2460b5cd8480a82be40f714940f41b6d83"},
-{"name":"prometheus-client-mmap","version":"0.27.0","platform":"x86_64-linux","checksum":"43776c1e27b546077288558cb532ae939b0e8cceecafc0cf62386d9f6b2a0140"},
+{"name":"prometheus-client-mmap","version":"0.28.0","platform":"aarch64-linux","checksum":"3e69581021c2117293f603990cff499fde94fe7741cecab0590359653e90d3f2"},
+{"name":"prometheus-client-mmap","version":"0.28.0","platform":"arm64-darwin","checksum":"889c8ec7173b7713107edd92cb33ab8489202254e8597adf9e2137b05eade3fd"},
+{"name":"prometheus-client-mmap","version":"0.28.0","platform":"ruby","checksum":"f3e14e8c5d3e5cbec0436620e3f813ab329259db5b34000e93c4ecf5770dcd7b"},
+{"name":"prometheus-client-mmap","version":"0.28.0","platform":"x86_64-darwin","checksum":"2ec7f200ba332ec314f7f387ab26f4aa5e18f1bd7c084beb17c3ad6bcdb7f265"},
+{"name":"prometheus-client-mmap","version":"0.28.0","platform":"x86_64-linux","checksum":"e04a4915567f81365ba86e3fe7f1dd512f8ae0a6b5169e0acfe6433205c87c57"},
{"name":"pry","version":"0.14.2","platform":"java","checksum":"fd780670977ba04ff7ee32dabd4d02fe4bf02e977afe8809832d5dca1412862e"},
{"name":"pry","version":"0.14.2","platform":"ruby","checksum":"c4fe54efedaca1d351280b45b8849af363184696fcac1c72e0415f9bdac4334d"},
{"name":"pry-byebug","version":"3.10.1","platform":"ruby","checksum":"c8f975c32255bfdb29e151f5532130be64ff3d0042dc858d0907e849125581f8"},
{"name":"pry-rails","version":"0.3.9","platform":"ruby","checksum":"468662575abb6b67f4a9831219f99290d5eae7bf186e64dd810d0a3e4a8cc4b1"},
{"name":"pry-shell","version":"0.6.4","platform":"ruby","checksum":"ad024882d29912b071a7de65ebea538b242d2dc1498c60c7c2352ef94769f208"},
{"name":"public_suffix","version":"5.0.0","platform":"ruby","checksum":"26ee4fbce33ada25eb117ac71f2c24bf4d8b3414ab6b34f05b4708a3e90f1c6b"},
-{"name":"puma","version":"6.3.0","platform":"java","checksum":"5e2ff95953608d1ba0350b80a3961a43e9bbb78ec60ebd5e4db1940c2921d5d8"},
-{"name":"puma","version":"6.3.0","platform":"ruby","checksum":"b0e35b4fe7ae440237a9ff1647c6bb252a1c0951ff356020670d2e62c1aeeeec"},
+{"name":"puma","version":"6.3.1","platform":"ruby","checksum":"ec989c775f88f5cbea0c7178b94ed9ff44797241f9245d353d1774a845e78df4"},
{"name":"pyu-ruby-sasl","version":"0.0.3.3","platform":"ruby","checksum":"5683a6bc5738db5a1bf5ceddeaf545405fb241b4184dd4f2587e679a7e9497e5"},
{"name":"raabro","version":"1.4.0","platform":"ruby","checksum":"d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882"},
{"name":"racc","version":"1.6.2","platform":"java","checksum":"0880781e7dfde09e665d0b6160b583e01ed52fcc2955d7891447d33c2d1d2cf1"},
@@ -472,10 +470,10 @@
{"name":"rack","version":"2.2.8","platform":"ruby","checksum":"7b83a1f1304a8f5554c67bc83632d29ecd2ed1daeb88d276b7898533fde22d97"},
{"name":"rack-accept","version":"0.4.5","platform":"ruby","checksum":"66247b5449db64ebb93ae2ec4af4764b87d1ae8a7463c7c68893ac13fa8d4da2"},
{"name":"rack-attack","version":"6.7.0","platform":"ruby","checksum":"3ca47e8f66cd33b2c96af53ea4754525cd928ed3fa8da10ee6dad0277791d77c"},
-{"name":"rack-cors","version":"1.1.1","platform":"ruby","checksum":"4702644ac6d63ebbddff372a3cd4cd573513287e3524b5a5415f678970057a4b"},
+{"name":"rack-cors","version":"2.0.1","platform":"ruby","checksum":"bcc66bdf5c6a4af05d571c4d01d35ac4a873552ba4f86c05fbe39365c39b9b0a"},
{"name":"rack-oauth2","version":"1.21.3","platform":"ruby","checksum":"4e72a79dd6a866692e84422a552b27c38a5a1918ded06661e04910f2bbe676ba"},
{"name":"rack-protection","version":"2.2.2","platform":"ruby","checksum":"fd41414dbabbec274af0bdb1f72a48504449de4d979782c9af38cbb5dfff3299"},
-{"name":"rack-proxy","version":"0.7.6","platform":"ruby","checksum":"8704c5009bb60eb16dacf4bcc5e067a8484e668321e8443534bb58ded320c2a8"},
+{"name":"rack-proxy","version":"0.7.7","platform":"ruby","checksum":"446a4b57001022145d5c3ba73b775f66a2260eaf7420c6907483141900395c8a"},
{"name":"rack-test","version":"2.1.0","platform":"ruby","checksum":"0c61fc61904049d691922ea4bb99e28004ed3f43aa5cfd495024cc345f125dfb"},
{"name":"rack-timeout","version":"0.6.3","platform":"ruby","checksum":"1754892eacc124d405e7f1145731ec9b7421ebd1bee5d51ddc18b72c204d0ab3"},
{"name":"rails","version":"7.0.6","platform":"ruby","checksum":"5dfbd481a23556ad425fc8541399a129a08ed550f877294b44d0170ca5b9f421"},
@@ -493,7 +491,16 @@
{"name":"rbtree","version":"0.4.6","platform":"ruby","checksum":"14eea4469b24fd2472542e5f3eb105d6344c8ccf36f0b56d55fdcfeb4e0f10fc"},
{"name":"rchardet","version":"1.8.0","platform":"ruby","checksum":"693acd5253d5ade81a51940697955f6dd4bb2f0d245bda76a8e23deec70a52c7"},
{"name":"rdoc","version":"6.3.2","platform":"ruby","checksum":"def4a720235c27d56c176ae73555e647eb04ea58a8bbaa927f8f9f79de7805a6"},
-{"name":"re2","version":"1.7.0","platform":"ruby","checksum":"0ccf19e3b289e67b56bd89a542488075de98d9b101b9946c4133d4b96af4d903"},
+{"name":"re2","version":"2.0.0","platform":"aarch64-linux","checksum":"677ddce4c38d659de899651acbfd7c6b5331f984a7101d9179ac247284f2212a"},
+{"name":"re2","version":"2.0.0","platform":"arm-linux","checksum":"f657d689922e5ac215b486e4f2ca909f1079eab616269a1d8fc0cccd63ef28af"},
+{"name":"re2","version":"2.0.0","platform":"arm64-darwin","checksum":"ffc8e5663381ff344ee6a2e55c7d0be81ef9b43174a41e977c4e18a11f965be1"},
+{"name":"re2","version":"2.0.0","platform":"ruby","checksum":"09075fab88b7ab40c2374d75a20504408dc26539c11931b146d5f72892718925"},
+{"name":"re2","version":"2.0.0","platform":"x64-mingw-ucrt","checksum":"253b3de21ca563cdb93c9fd69738a2a66713e381bae4530ff2cae105c6fd1a8e"},
+{"name":"re2","version":"2.0.0","platform":"x64-mingw32","checksum":"d4b52fc21719f262c2a438912f009da868b31aed1688ec90e4e1696898fb53d3"},
+{"name":"re2","version":"2.0.0","platform":"x86-linux","checksum":"26abee219e3fd69ba5c6a7bdb882880b8af6502cf912da7a7837e38ad02a29e7"},
+{"name":"re2","version":"2.0.0","platform":"x86-mingw32","checksum":"ffec6da4c547e44a6c1a467b0b01b2dcc2940e081923221a2ac3e4b08a219c26"},
+{"name":"re2","version":"2.0.0","platform":"x86_64-darwin","checksum":"48b3ba3fea8cc84709a4195300cd1c627b2496f16e5865662c54e67f7aca1ccf"},
+{"name":"re2","version":"2.0.0","platform":"x86_64-linux","checksum":"1fb161e6e5d9efed59ed0062536f2cb9ab5fba367e209d0dc66f99f2864d42ff"},
{"name":"recaptcha","version":"5.12.3","platform":"ruby","checksum":"37d1894add9e70a54d0c6c7f0ecbeedffbfa7d075acfbd4c509818dfdebdb7ee"},
{"name":"recursive-open-struct","version":"1.1.3","platform":"ruby","checksum":"a3538a72552fcebcd0ada657bdff313641a4a5fbc482c08cfb9a65acb1c9de5a"},
{"name":"redcarpet","version":"3.6.0","platform":"ruby","checksum":"8ad1889c0355ff4c47174af14edd06d62f45a326da1da6e8a121d59bdcd2e9e9"},
@@ -514,7 +521,7 @@
{"name":"rest-client","version":"2.1.0","platform":"x86-mswin32","checksum":"a35a3bb8d16ca39d110a946a2c805267f98ce07a0ae890e4512a45eadea47a6e"},
{"name":"retriable","version":"3.1.2","platform":"ruby","checksum":"0a5a5d0ca4ba61a76fb31a17ab8f7f80281beb040c329d34dfc137a1398688e0"},
{"name":"reverse_markdown","version":"1.4.0","platform":"ruby","checksum":"a3305da1509ac8388fa84a28745621113e121383402a2e8e9350ba649034e870"},
-{"name":"rexml","version":"3.2.5","platform":"ruby","checksum":"a33c3bf95fda7983ec7f05054f3a985af41dbc25a0339843bd2479e93cabb123"},
+{"name":"rexml","version":"3.2.6","platform":"ruby","checksum":"e0669a2d4e9f109951cb1fde723d8acd285425d81594a2ea929304af50282816"},
{"name":"rinku","version":"2.0.0","platform":"ruby","checksum":"3e695aaf9f24baba3af45823b5c427b58a624582132f18482320e2737f9f8a85"},
{"name":"rotp","version":"6.2.0","platform":"ruby","checksum":"239a2eefba6f1bd4157b2c735d0f975598e0ef94823eea2f35d103d2e5cc0787"},
{"name":"rouge","version":"4.1.3","platform":"ruby","checksum":"9c8663db26e05e52b3b0286daacae73ebb361c1bd31d7febd8c57087faa0b9a5"},
@@ -548,14 +555,13 @@
{"name":"ruby-saml","version":"1.15.0","platform":"ruby","checksum":"3a9dda2b448310f4f90d5cf0967d4b668530fa7994d2a4d9cbfdfa62e35f76a3"},
{"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.20.0","platform":"ruby","checksum":"17d0c8bbef7fcdf99b1070bb2555d49111758f75d312e8799f66df831ebdcbe3"},
{"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"},
{"name":"rugged","version":"1.6.3","platform":"ruby","checksum":"362631de8dc6f1074242f21e01148ac70b7fe8cdb17f85eee91d4ea83457cb04"},
{"name":"safe_yaml","version":"1.0.4","platform":"ruby","checksum":"248193992ef1730a0c9ec579999ef2256a2b3a32a9bd9d708a1e12544a489ec2"},
{"name":"safety_net_attestation","version":"0.4.0","platform":"ruby","checksum":"96be2d74e7ed26453a51894913449bea0e072f44490021545ac2d1c38b0718ce"},
-{"name":"sanitize","version":"6.0.0","platform":"ruby","checksum":"81795f985873f3bacee2eaaededeaafc3a29aafeaa9aff51e04b85a66bbf08ff"},
+{"name":"sanitize","version":"6.0.2","platform":"ruby","checksum":"48c4eb8e92bb1699056b6000986ac50fc9df82f458a941abf2c4d6759bccd5cf"},
{"name":"sass","version":"3.5.5","platform":"ruby","checksum":"1bb5431bc620ce29076728a4c8f7b4acb55066ed9df8cf5d57db6cda450d8080"},
{"name":"sass-listen","version":"4.0.0","platform":"ruby","checksum":"ae9dcb76dd3e234329e5ba6e213f48e532c5a3e7b0b4d8a87f13aaca0cc18377"},
{"name":"sassc","version":"2.4.0","platform":"ruby","checksum":"4c60a2b0a3b36685c83b80d5789401c2f678c1652e3288315a1551d811d9f83e"},
@@ -564,14 +570,13 @@
{"name":"sawyer","version":"0.9.2","platform":"ruby","checksum":"fa3a72d62a4525517b18857ddb78926aab3424de0129be6772a8e2ba240e7aca"},
{"name":"sd_notify","version":"0.1.1","platform":"ruby","checksum":"cbc7ac6caa7cedd26b30a72b5eeb6f36050dc0752df263452ea24fb5a4ad3131"},
{"name":"seed-fu","version":"2.3.7","platform":"ruby","checksum":"f19673443e9af799b730e3d4eca6a89b39e5a36825015dffd00d02ea3365cf74"},
-{"name":"selenium-webdriver","version":"4.11.0","platform":"ruby","checksum":"4c7991756ec3109b3d6a4b062df3858eaa00382299d1ccbadf37503004ac4073"},
+{"name":"selenium-webdriver","version":"4.12.0","platform":"ruby","checksum":"5ab2295b67adb88993c54771fb4f31b39cd0f83eb51cfa288117af5347a0944b"},
{"name":"semver_dialects","version":"1.2.1","platform":"ruby","checksum":"60a1f67659f79c51a667e8858ec9b089c1e4ce4f6d2a0f0b4ac101916946eb23"},
{"name":"sentry-rails","version":"5.8.0","platform":"ruby","checksum":"c11b2d909de2c2bfda793c45f64180fd784d54c46886338b683ee3f8efa7731b"},
{"name":"sentry-raven","version":"3.1.2","platform":"ruby","checksum":"103d3b122958810d34898ce2e705bcf549ddb9d855a70ce9a3970ee2484f364a"},
{"name":"sentry-ruby","version":"5.8.0","platform":"ruby","checksum":"caeb121433be379fb94e991a45265a287b13a9a9083e7264f539752369d37110"},
{"name":"sentry-sidekiq","version":"5.8.0","platform":"ruby","checksum":"90d1123d16a9fc5fd99dbad190b766dd189eaf9e2baddad641f1334e1877c779"},
{"name":"set","version":"1.0.2","platform":"ruby","checksum":"02ffa4de1f2621495e05b72326040dd014d7abbcb02fea698bc600a389992c02"},
-{"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"},
@@ -619,7 +624,7 @@
{"name":"sys-filesystem","version":"1.4.3","platform":"ruby","checksum":"390919de89822ad6d3ba3daf694d720be9d83ed95cdf7adf54d4573c98b17421"},
{"name":"sysexits","version":"1.2.0","platform":"ruby","checksum":"598241c4ae57baa403c125182dfdcc0d1ac4c0fb606dd47fbed57e4aaf795662"},
{"name":"table_print","version":"1.5.7","platform":"ruby","checksum":"436664281f93387b882335795e16cfeeb839ad0c785ff7f9110fc0f17c68b5cb"},
-{"name":"tanuki_emoji","version":"0.6.0","platform":"ruby","checksum":"4ce91aefed2d076b73fba3eff50e89660c3d25691787a9fe4c0dfabb4218c12a"},
+{"name":"tanuki_emoji","version":"0.7.0","platform":"ruby","checksum":"d10df452d8087b2c6a0eecb888609315d47bb30bb9e17c11441869cf24aae987"},
{"name":"telesign","version":"2.2.4","platform":"ruby","checksum":"dcc6e96ea7bcb4da1e2ae786bfe7a4d670a4b5f94ae95dfcdde77d547c544c42"},
{"name":"telesignenterprise","version":"2.2.2","platform":"ruby","checksum":"f147a03263a8c2fe0a0db1a7a9454a6ee37d9e8abd58eaca305bdd8081f9f1b3"},
{"name":"temple","version":"0.8.2","platform":"ruby","checksum":"c12071214346c606dbd219b4117276d04a9f2c20d65e66a66b2c4ec18efc1f18"},
@@ -670,17 +675,19 @@
{"name":"valid_email","version":"0.1.3","platform":"ruby","checksum":"b81452b51b64c4beb67913f68db52c20ecb4d73d45512f5b282ab4a3f4416570"},
{"name":"validate_email","version":"0.1.6","platform":"ruby","checksum":"9dfe9016d527b17a8d3a6e95e4dc50a125400eef899d13d4cc2a254393f82ee4"},
{"name":"validate_url","version":"1.0.15","platform":"ruby","checksum":"72fe164c0713d63a9970bd6700bea948babbfbdcec392f2342b6704042f57451"},
-{"name":"validates_hostname","version":"1.0.11","platform":"ruby","checksum":"d506bae0342ec14c920eb319e057fc1886c321a59b85b4b6e966ee4b88fab8c3"},
+{"name":"validates_hostname","version":"1.0.13","platform":"ruby","checksum":"eac40178cc0b4f727df9cc6a5cb5bc2550718ad8d9bb3728df9aba6354bdda19"},
{"name":"version_gem","version":"1.1.0","platform":"ruby","checksum":"6b009518020db57f51ec7b410213fae2bf692baea9f1b51770db97fbc93d9a80"},
{"name":"version_sorter","version":"2.3.0","platform":"ruby","checksum":"2147f2a1a3804fbb8f60d268b7d7c1ec717e6dd727ffe2c165b4e05e82efe1da"},
-{"name":"view_component","version":"3.2.0","platform":"ruby","checksum":"1dfaa85e13b5393f30b60bd3a03348b5298240a13137985d71eb2b8cc94c4c22"},
+{"name":"view_component","version":"3.5.0","platform":"ruby","checksum":"c3e3cdf5abb2383157684d76cfb153d23bfc9834a7defa82441edab54635e8af"},
{"name":"virtus","version":"2.0.0","platform":"ruby","checksum":"8841dae4eb7fcc097320ba5ea516bf1839e5d056c61ee27138aa4bddd6e3d1c2"},
+{"name":"vite_rails","version":"3.0.15","platform":"ruby","checksum":"b8ec528aedf7e24b54f222b449cd9250810ea2456d5f8dd4ef87f06b475cf860"},
+{"name":"vite_ruby","version":"3.3.4","platform":"ruby","checksum":"025e438385a6dc2320c8c148dff453f5bb1d4f056ce69c3386f47d4c388ad80c"},
{"name":"vmstat","version":"2.3.0","platform":"ruby","checksum":"ab5446a3e3bd0a9cdb9d9ac69a0bbd119c4f161d945a0846a519dd7018af656d"},
{"name":"warden","version":"1.2.9","platform":"ruby","checksum":"46684f885d35a69dbb883deabf85a222c8e427a957804719e143005df7a1efd0"},
{"name":"warning","version":"1.3.0","platform":"ruby","checksum":"23695a5d8e50bd5c46068931b529bee0b28e4982cbcefbe77d867800dde8069e"},
{"name":"webauthn","version":"3.0.0","platform":"ruby","checksum":"3f77d422c2a8a4b31e56cf42f83414bd066e0506e9896936e1730262dc4a20e6"},
{"name":"webfinger","version":"1.2.0","platform":"ruby","checksum":"7814ef1c85da47514f65c6e5ca14205fa9ce41ea2a70785e0c872842162852a2"},
-{"name":"webmock","version":"3.18.1","platform":"ruby","checksum":"54c955df4ae4bec6181dd266eeec632a1808288c633f9551d81bafb53921d2d7"},
+{"name":"webmock","version":"3.19.1","platform":"ruby","checksum":"eae7eee33989478188451f1fda4224d7fbe097c5c14e96b40b57347ef2d5d16d"},
{"name":"webrick","version":"1.8.1","platform":"ruby","checksum":"19411ec6912911fd3df13559110127ea2badd0c035f7762873f58afc803e158f"},
{"name":"websocket","version":"1.2.9","platform":"ruby","checksum":"884b12dee993217795bb5f58acc89c0121c88bdc99df4d1636c0505dca352b36"},
{"name":"websocket-driver","version":"0.7.5","platform":"java","checksum":"fffa83aa188e9ac90e32a385832ec9d26acdf019538e1c7d703f2c8a323b39c8"},
diff --git a/Gemfile.lock b/Gemfile.lock
index cf94510e923..2a8f80bf393 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -100,7 +100,7 @@ PATH
specs:
mail-smtp_pool (0.1.0)
connection_pool (~> 2.0)
- mail (~> 2.7)
+ mail (~> 2.8)
PATH
remote: vendor/gems/microsoft_graph_mailer
@@ -265,7 +265,7 @@ GEM
aws-sdk-cloudformation (1.41.0)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.1)
- aws-sdk-core (3.180.3)
+ aws-sdk-core (3.181.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
@@ -273,8 +273,8 @@ GEM
aws-sdk-kms (1.64.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.132.1)
- aws-sdk-core (~> 3, >= 3.179.0)
+ aws-sdk-s3 (1.134.0)
+ aws-sdk-core (~> 3, >= 3.181.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.6)
aws-sigv4 (1.6.0)
@@ -389,18 +389,18 @@ GEM
css_parser (1.14.0)
addressable
cvss-suite (3.0.1)
- danger (8.6.1)
+ danger (9.3.1)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
cork (~> 0.1)
- faraday (>= 0.9.0, < 2.0)
+ faraday (>= 0.9.0, < 3.0)
faraday-http-cache (~> 2.0)
- git (~> 1.7)
+ git (~> 1.13)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.0)
no_proxy_fix
- octokit (~> 4.7)
+ octokit (~> 6.0)
terminal-table (>= 1, < 4)
danger-gitlab (8.0.0)
danger
@@ -409,7 +409,7 @@ GEM
date (3.3.3)
dead_end (3.1.1)
debug_inspector (1.1.0)
- deckar01-task_list (2.3.2)
+ deckar01-task_list (2.3.3)
html-pipeline
declarative (0.0.20)
declarative_policy (1.1.0)
@@ -459,6 +459,7 @@ GEM
doorkeeper (>= 5.5, < 5.7)
jwt (>= 2.5)
dotenv (2.7.6)
+ dry-cli (1.0.0)
dry-core (1.0.0)
concurrent-ruby (~> 1.0)
zeitwerk (~> 2.6)
@@ -502,7 +503,7 @@ GEM
escape_utils (1.2.1)
et-orbi (1.2.7)
tzinfo
- ethon (0.15.0)
+ ethon (0.16.0)
ffi (>= 1.15.0)
excon (0.99.0)
execjs (2.8.1)
@@ -549,7 +550,7 @@ GEM
faraday_middleware-multi_json (0.0.6)
faraday_middleware
multi_json
- fast_blank (1.0.0)
+ fast_blank (1.0.1)
fast_gettext (2.3.0)
ffaker (2.10.0)
ffi (1.15.5)
@@ -560,13 +561,14 @@ GEM
libyajl2 (>= 1.2)
filelock (1.1.1)
find_a_port (1.0.1)
- flipper (0.25.0)
- flipper-active_record (0.25.0)
+ flipper (0.26.2)
+ concurrent-ruby (< 2)
+ flipper-active_record (0.26.2)
activerecord (>= 4.2, < 8)
- flipper (~> 0.25.0)
- flipper-active_support_cache_store (0.25.0)
+ flipper (~> 0.26.2)
+ flipper-active_support_cache_store (0.26.2)
activesupport (>= 4.2, < 8)
- flipper (~> 0.25.0)
+ flipper (~> 0.26.2)
fog-aliyun (0.4.0)
addressable (~> 2.8.0)
aliyun-sdk (~> 0.8.0)
@@ -632,20 +634,21 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
- git (1.11.0)
+ git (1.18.0)
+ addressable (~> 2.8)
rchardet (~> 1.8)
- gitaly (16.2.0.pre.rc4)
+ gitaly (16.3.0.pre.rc1)
grpc (~> 1.0)
gitlab (4.19.0)
httparty (~> 0.20)
terminal-table (>= 1.5.1)
gitlab-chronic (0.10.5)
numerizer (~> 0.2)
- gitlab-dangerfiles (3.13.0)
- danger (>= 8.4.5)
+ gitlab-dangerfiles (4.0.0)
+ danger (>= 9.3.0)
danger-gitlab (>= 8.0.0)
rake
- gitlab-experiment (0.7.1)
+ gitlab-experiment (0.8.0)
activesupport (>= 3.0)
request_store (>= 1.0)
gitlab-fog-azure-rm (1.8.0)
@@ -675,14 +678,14 @@ GEM
rubocop-performance (~> 1.15)
rubocop-rails (~> 2.17)
rubocop-rspec (~> 2.22)
- gitlab_chronic_duration (0.10.6.2)
+ gitlab_chronic_duration (0.11.0)
numerizer (~> 0.2)
gitlab_omniauth-ldap (2.2.0)
net-ldap (~> 0.16)
omniauth (>= 1.3, < 3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
- gitlab_quality-test_tooling (0.9.3)
+ gitlab_quality-test_tooling (1.0.0)
activesupport (>= 6.1, < 7.1)
gitlab (~> 4.19)
http (~> 5.0)
@@ -752,7 +755,7 @@ GEM
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
- google-protobuf (3.23.4)
+ google-protobuf (3.24.3)
googleapis-common-protos (1.4.0)
google-protobuf (~> 3.14)
googleapis-common-protos-types (~> 1.2)
@@ -766,7 +769,7 @@ GEM
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
- gpgme (2.0.22)
+ gpgme (2.0.23)
mini_portile2 (~> 2.7)
grape (1.7.1)
activesupport
@@ -799,7 +802,7 @@ GEM
faraday_middleware
graphql-client
graphlyte (1.0.0)
- graphql (1.13.12)
+ graphql (1.13.19)
graphql-client (0.17.0)
activesupport (>= 3.0)
graphql (~> 1.10)
@@ -867,11 +870,11 @@ GEM
http-cookie (1.0.5)
domain_name (~> 0.5)
http-form_data (2.3.0)
- httparty (0.20.0)
- mime-types (~> 3.0)
+ httparty (0.21.0)
+ mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
- i18n (1.12.0)
+ i18n (1.14.1)
concurrent-ruby (~> 1.0)
i18n_data (0.13.1)
icalendar (2.8.0)
@@ -880,8 +883,8 @@ GEM
ice_nine (0.11.2)
imagen (0.1.8)
parser (>= 2.5, != 2.5.1.1)
- invisible_captcha (2.0.0)
- rails (>= 5.0)
+ invisible_captcha (2.1.0)
+ rails (>= 5.2)
ipaddr (1.2.5)
ipaddress (0.8.3)
jaeger-client (1.1.0)
@@ -959,10 +962,10 @@ GEM
tomlrb (>= 1.3, < 2.1)
with_env (= 1.1.0)
xml-simple (~> 1.1.9)
- licensee (9.15.2)
+ licensee (9.16.0)
dotenv (~> 2.0)
- octokit (~> 4.20)
- reverse_markdown (~> 1.0)
+ octokit (>= 4.20, < 7.0)
+ reverse_markdown (>= 1, < 3)
rugged (>= 0.24, < 2.0)
thor (>= 0.19, < 2.0)
listen (3.7.1)
@@ -972,7 +975,7 @@ GEM
ffi-compiler (~> 1.0)
rake (~> 13.0)
locale (2.1.3)
- lockbox (1.1.1)
+ lockbox (1.3.0)
lograge (0.11.2)
actionpack (>= 4)
activesupport (>= 4)
@@ -1014,7 +1017,7 @@ GEM
mini_histogram (0.3.1)
mini_magick (4.10.1)
mini_mime (1.1.2)
- mini_portile2 (2.8.2)
+ mini_portile2 (2.8.4)
minitest (5.11.3)
mixlib-cli (2.1.8)
mixlib-config (3.0.9)
@@ -1072,7 +1075,7 @@ GEM
rack (>= 1.2, < 4)
snaky_hash (~> 2.0)
version_gem (~> 1.1)
- octokit (4.25.1)
+ octokit (6.1.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
ohai (17.9.0)
@@ -1189,7 +1192,7 @@ GEM
tty-color (~> 0.5)
peek (1.1.0)
railties (>= 4.0.0)
- pg (1.5.3)
+ pg (1.5.4)
pg_query (4.2.3)
google-protobuf (>= 3.22.3)
plist (3.6.0)
@@ -1207,7 +1210,7 @@ GEM
coderay
parser
unparser
- prometheus-client-mmap (0.27.0)
+ prometheus-client-mmap (0.28.0)
rb_sys (~> 0.9)
pry (0.14.2)
coderay (~> 1.1)
@@ -1222,7 +1225,7 @@ GEM
tty-markdown
tty-prompt
public_suffix (5.0.0)
- puma (6.3.0)
+ puma (6.3.1)
nio4r (~> 2.0)
pyu-ruby-sasl (0.0.3.3)
raabro (1.4.0)
@@ -1232,7 +1235,7 @@ GEM
rack (>= 0.4)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
- rack-cors (1.1.1)
+ rack-cors (2.0.1)
rack (>= 2.0.0)
rack-oauth2 (1.21.3)
activesupport
@@ -1242,7 +1245,7 @@ GEM
rack (>= 2.1.0)
rack-protection (2.2.2)
rack
- rack-proxy (0.7.6)
+ rack-proxy (0.7.7)
rack
rack-test (2.1.0)
rack (>= 1.3)
@@ -1293,7 +1296,8 @@ GEM
rbtree (0.4.6)
rchardet (1.8.0)
rdoc (6.3.2)
- re2 (1.7.0)
+ re2 (2.0.0)
+ mini_portile2 (~> 2.8.4)
recaptcha (5.12.3)
json
recursive-open-struct (1.1.3)
@@ -1329,7 +1333,7 @@ GEM
retriable (3.1.2)
reverse_markdown (1.4.0)
nokogiri
- rexml (3.2.5)
+ rexml (3.2.6)
rinku (2.0.0)
rotp (6.2.0)
rouge (4.1.3)
@@ -1425,8 +1429,6 @@ GEM
rexml
ruby-statistics (3.0.0)
ruby2_keywords (0.0.5)
- ruby_parser (3.20.0)
- sexp_processor (~> 4.16)
rubyntlm (0.6.3)
rubypants (0.2.0)
rubyzip (2.3.2)
@@ -1434,7 +1436,7 @@ GEM
safe_yaml (1.0.4)
safety_net_attestation (0.4.0)
jwt (~> 2.0)
- sanitize (6.0.0)
+ sanitize (6.0.2)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
sass (3.5.5)
@@ -1457,7 +1459,7 @@ GEM
seed-fu (2.3.7)
activerecord (>= 3.1)
activesupport (>= 3.1)
- selenium-webdriver (4.11.0)
+ selenium-webdriver (4.12.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
@@ -1476,7 +1478,6 @@ GEM
sentry-ruby (~> 5.8.0)
sidekiq (>= 3.0)
set (1.0.2)
- sexp_processor (4.16.1)
shellany (0.0.1)
shoulda-matchers (5.1.0)
activesupport (>= 5.2.0)
@@ -1567,7 +1568,7 @@ GEM
ffi (~> 1.1)
sysexits (1.2.0)
table_print (1.5.7)
- tanuki_emoji (0.6.0)
+ tanuki_emoji (0.7.0)
telesign (2.2.4)
net-http-persistent (>= 3.0.0, < 5.0)
telesignenterprise (2.2.2)
@@ -1659,12 +1660,12 @@ GEM
validate_url (1.0.15)
activemodel (>= 3.0.0)
public_suffix
- validates_hostname (1.0.11)
+ validates_hostname (1.0.13)
activerecord (>= 3.0)
activesupport (>= 3.0)
version_gem (1.1.0)
version_sorter (2.3.0)
- view_component (3.2.0)
+ view_component (3.5.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
@@ -1672,6 +1673,13 @@ GEM
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
+ vite_rails (3.0.15)
+ railties (>= 5.1, < 8)
+ vite_ruby (~> 3.0, >= 3.2.2)
+ vite_ruby (3.3.4)
+ dry-cli (>= 0.7, < 2)
+ rack-proxy (~> 0.6, >= 0.6.1)
+ zeitwerk (~> 2.2)
vmstat (2.3.0)
warden (1.2.9)
rack (>= 2.0.9)
@@ -1688,7 +1696,7 @@ GEM
webfinger (1.2.0)
activesupport
httpclient (>= 2.4)
- webmock (3.18.1)
+ webmock (3.19.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
@@ -1737,8 +1745,8 @@ DEPENDENCIES
autoprefixer-rails (= 10.2.5.1)
awesome_print
aws-sdk-cloudformation (~> 1)
- aws-sdk-core (~> 3.180.3)
- aws-sdk-s3 (~> 1.132.1)
+ aws-sdk-core (~> 3.181.1)
+ aws-sdk-s3 (~> 1.134.0)
axe-core-rspec
babosa (~> 2.0)
base32 (~> 0.3.0)
@@ -1768,7 +1776,7 @@ DEPENDENCIES
csv_builder!
cvss-suite (~> 3.0.1)
database_cleaner (~> 1.7.0)
- deckar01-task_list (= 2.3.2)
+ deckar01-task_list (= 2.3.3)
declarative_policy (~> 1.1.0)
deprecation_toolkit (~> 1.5.1)
derailed_benchmarks
@@ -1793,11 +1801,11 @@ DEPENDENCIES
factory_bot_rails (~> 6.2.0)
faraday (~> 1.0)
faraday_middleware-aws-sigv4 (~> 0.3.0)
- fast_blank
+ fast_blank (~> 1.0.1)
ffaker (~> 2.10)
- flipper (~> 0.25.0)
- flipper-active_record (~> 0.25.0)
- flipper-active_support_cache_store (~> 0.25.0)
+ flipper (~> 0.26.2)
+ flipper-active_record (~> 0.26.2)
+ flipper-active_support_cache_store (~> 0.26.2)
fog-aliyun (~> 0.4)
fog-aws (~> 3.18)
fog-core (= 2.1.0)
@@ -1808,10 +1816,10 @@ DEPENDENCIES
gettext (~> 3.3)
gettext_i18n_rails (~> 1.11.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly (~> 16.2.0.pre.rc4)
+ gitaly (~> 16.3.0.pre.rc1)
gitlab-chronic (~> 0.10.5)
- gitlab-dangerfiles (~> 3.13.0)
- gitlab-experiment (~> 0.7.1)
+ gitlab-dangerfiles (~> 4.0.0)
+ gitlab-experiment (~> 0.8.0)
gitlab-fog-azure-rm (~> 1.8.0)
gitlab-labkit (~> 0.34.0)
gitlab-license (~> 2.3)
@@ -1824,9 +1832,9 @@ DEPENDENCIES
gitlab-sidekiq-fetcher!
gitlab-styles (~> 10.1.0)
gitlab-utils!
- gitlab_chronic_duration (~> 0.10.6.2)
+ gitlab_chronic_duration (~> 0.11)
gitlab_omniauth-ldap (~> 2.2.0)
- gitlab_quality-test_tooling (~> 0.9.3)
+ gitlab_quality-test_tooling (~> 1.0.0)
gon (~> 6.4.0)
google-apis-androidpublisher_v3 (~> 0.34.0)
google-apis-cloudbilling_v1 (~> 0.21.0)
@@ -1839,18 +1847,18 @@ DEPENDENCIES
google-apis-serviceusage_v1 (~> 0.28.0)
google-apis-sqladmin_v1beta4 (~> 0.41.0)
google-cloud-storage (~> 1.44.0)
- google-protobuf (~> 3.23, >= 3.23.4)
- gpgme (~> 2.0.22)
+ google-protobuf (~> 3.24, >= 3.24.3)
+ gpgme (~> 2.0.23)
grape (~> 1.7.1)
grape-entity (~> 0.10.0)
grape-path-helpers (~> 1.7.1)
grape-swagger (~> 1.6.1)
grape-swagger-entity (~> 0.5.1)
grape_logging (~> 1.8)
- graphiql-rails (~> 1.8)
+ graphiql-rails (~> 1.8.0)
graphlient (~> 0.5.0)
graphlyte (~> 1.0.0)
- graphql (~> 1.13.12)
+ graphql (~> 1.13.19)
graphql-docs (~> 2.1.0)
grpc (~> 1.55.0)
gssapi (~> 1.3.1)
@@ -1862,9 +1870,9 @@ DEPENDENCIES
health_check (~> 3.0)
html-pipeline (~> 2.14.3)
html2text
- httparty (~> 0.20.0)
+ httparty (~> 0.21.0)
icalendar
- invisible_captcha (~> 2.0.0)
+ invisible_captcha (~> 2.1.0)
ipaddr (~> 1.2.5)
ipaddress (~> 0.8.3)
ipynbdiff!
@@ -1882,9 +1890,9 @@ DEPENDENCIES
lefthook (~> 1.4.7)
letter_opener_web (~> 2.0.0)
license_finder (~> 7.0)
- licensee (~> 9.15)
+ licensee (~> 9.16)
listen (~> 3.7)
- lockbox (~> 1.1.1)
+ lockbox (~> 1.3.0)
lograge (~> 0.5)
loofah (~> 2.21.3)
lookbook (~> 2.0, >= 2.0.1)
@@ -1904,7 +1912,7 @@ DEPENDENCIES
net-protocol (~> 0.1.3)
nokogiri (~> 1.15, >= 1.15.4)
oauth2 (~> 2.0)
- octokit (~> 4.15)
+ octokit (~> 6.0)
ohai (~> 17.9)
oj (~> 3.13.21)
oj-introspect (~> 0.7)
@@ -1934,20 +1942,20 @@ DEPENDENCIES
parser (~> 3.2, >= 3.2.2.3)
parslet (~> 1.8)
peek (~> 1.1)
- pg (~> 1.5.3)
+ pg (~> 1.5.4)
pg_query (~> 4.2.3)
png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3)
- prometheus-client-mmap (~> 0.27)
+ prometheus-client-mmap (~> 0.28)
pry-byebug
pry-rails (~> 0.3.9)
pry-shell (~> 0.6.4)
- puma (~> 6.3)
+ puma (~> 6.3, >= 6.3.1)
rack (~> 2.2.8)
rack-attack (~> 6.7.0)
- rack-cors (~> 1.1.1)
+ rack-cors (~> 2.0.1)
rack-oauth2 (~> 1.21.3)
- rack-proxy (~> 0.7.6)
+ rack-proxy (~> 0.7.7)
rack-timeout (~> 0.6.3)
rails (~> 7.0.6)
rails-controller-testing
@@ -1955,7 +1963,7 @@ DEPENDENCIES
rainbow (~> 3.0)
rbtrace (~> 0.4)
rdoc (~> 6.3.2)
- re2 (~> 1.7.0)
+ re2 (= 2.0.0)
recaptcha (~> 5.12)
redis (~> 4.8.0)
redis-actionpack (~> 5.3.0)
@@ -1963,7 +1971,7 @@ DEPENDENCIES
request_store (~> 1.5.1)
responders (~> 3.0)
retriable (~> 3.1.2)
- rexml (~> 3.2.5)
+ rexml (~> 3.2.6)
rouge (~> 4.1.3)
rqrcode-rails3 (~> 0.1.7)
rspec-benchmark (~> 0.6.0)
@@ -1979,14 +1987,13 @@ DEPENDENCIES
ruby-openai (~> 3.7)
ruby-progressbar (~> 1.10)
ruby-saml (~> 1.15.0)
- ruby_parser (~> 3.20)
rubyzip (~> 2.3.2)
rugged (~> 1.6)
- sanitize (~> 6.0)
+ sanitize (~> 6.0.2)
sassc-rails (~> 2.1.0)
sd_notify (~> 0.1.0)
seed-fu (~> 2.3.7)
- selenium-webdriver (= 4.11.0)
+ selenium-webdriver (= 4.12.0)
semver_dialects (~> 1.2.1)
sentry-rails (~> 5.8.0)
sentry-raven (~> 3.1)
@@ -2012,7 +2019,7 @@ DEPENDENCIES
stackprof (~> 0.2.25)
state_machines-activerecord (~> 0.8.0)
sys-filesystem (~> 1.4.3)
- tanuki_emoji (~> 0.6)
+ tanuki_emoji (~> 0.7)
telesignenterprise (~> 2.2)
terser (= 1.0.2)
test-prof (~> 1.2.2)
@@ -2023,19 +2030,19 @@ DEPENDENCIES
truncato (~> 0.7.12)
typhoeus (~> 1.4.0)
undercover (~> 0.4.4)
- unf (~> 0.1.4)
unleash (~> 3.2.2)
valid_email (~> 0.1)
- validates_hostname (~> 1.0.11)
+ validates_hostname (~> 1.0.13)
version_sorter (~> 2.3)
- view_component (~> 3.2.0)
+ view_component (~> 3.5.0)
+ vite_rails
vmstat (~> 2.3.0)
warning (~> 1.3.0)
webauthn (~> 3.0)
- webmock (~> 3.18.1)
+ webmock (~> 3.19.1)
webrick (~> 1.8.1)
wikicloth (= 0.8.1)
yajl-ruby (~> 1.4.3)
BUNDLED WITH
- 2.4.18
+ 2.4.19
diff --git a/Guardfile b/Guardfile
index 66a689ed978..cd4486db404 100644
--- a/Guardfile
+++ b/Guardfile
@@ -6,7 +6,7 @@ require "guard/rspec/dsl"
cmd = ENV['GUARD_CMD'] || (ENV['SPRING'] ? 'spring rspec' : 'bundle exec rspec')
-directories %w(app ee lib rubocop tooling spec)
+directories %w[app ee lib rubocop tooling spec]
rspec_context_for = proc do |context_path|
OpenStruct.new(to_s: "spec").tap do |rspec| # rubocop:disable Style/OpenStructUse
@@ -46,7 +46,7 @@ guard_setup = proc do |context_path|
watch(%r{^#{context_path}(tooling/.+)\.rb$}) { |m| rspec.spec.call(m[1]) }
# Rails files
- rails = rails_context_for.call(context_path, %w(erb haml slim))
+ rails = rails_context_for.call(context_path, %w[erb haml slim])
watch(rails.app_files) { |m| rspec.spec.call(m[1]) }
watch(rails.views) { |m| rspec.spec.call(m[1]) }
diff --git a/README.md b/README.md
index ee46c4ccdf6..9fd168f208e 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
- [Community](https://about.gitlab.com/community/)
- [Hosted GitLab.com](https://about.gitlab.com/gitlab-com/) use GitLab as a free service
- [GitLab Enterprise Edition](https://about.gitlab.com/features/#enterprise) with additional features aimed at larger organizations.
-- [GitLab CI](https://about.gitlab.com/gitlab-ci/) a continuous integration (CI) server that is easy to integrate with GitLab.
+- [GitLab CI](https://about.gitlab.com/solutions/continuous-integration/) a continuous integration (CI) server that is easy to integrate with GitLab.
## Requirements
diff --git a/Rakefile b/Rakefile
index 4db94c50130..36176721e13 100755
--- a/Rakefile
+++ b/Rakefile
@@ -11,6 +11,10 @@ require File.expand_path('config/application', __dir__)
relative_url_conf = File.expand_path('config/initializers/relative_url', __dir__)
require relative_url_conf if File.exist?("#{relative_url_conf}.rb")
+# This is the only way to change how vite_ruby works for rake tasks
+# See https://github.com/ElMassimo/vite_ruby/blob/vite_ruby%403.3.4/vite_ruby/lib/tasks/vite.rake#L58
+ENV['VITE_RUBY_SKIP_ASSETS_PRECOMPILE_EXTENSION'] = 'true'
+
Gitlab::Application.load_tasks
Knapsack.load_tasks if defined?(Knapsack)
diff --git a/app/assets/images/auth_buttons/salesforce_64.png b/app/assets/images/auth_buttons/salesforce_64.png
deleted file mode 100644
index b562e09c20f..00000000000
--- a/app/assets/images/auth_buttons/salesforce_64.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/javascripts/access_tokens/components/access_token_table_app.vue b/app/assets/javascripts/access_tokens/components/access_token_table_app.vue
index 85b3c994e02..9a7296b6b1f 100644
--- a/app/assets/javascripts/access_tokens/components/access_token_table_app.vue
+++ b/app/assets/javascripts/access_tokens/components/access_token_table_app.vue
@@ -33,7 +33,7 @@ export default {
emptyField: __('Never'),
expired: __('Expired'),
modalMessage: __(
- 'Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone.',
+ 'Are you sure you want to revoke the %{accessTokenType} "%{tokenName}"? This action cannot be undone.',
),
revokeButton: __('Revoke'),
tokenValidity: __('Token valid until revoked'),
@@ -72,11 +72,6 @@ export default {
return FIELDS.filter(({ key }) => !ignoredFields.includes(key));
},
- modalMessage() {
- return sprintf(this.$options.i18n.modalMessage, {
- accessTokenType: this.accessTokenType,
- });
- },
showPagination() {
return this.activeAccessTokens.length > PAGE_SIZE;
},
@@ -87,6 +82,12 @@ export default {
this.activeAccessTokens = convertObjectPropsToCamelCase(activeAccessTokens, { deep: true });
this.currentPage = INITIAL_PAGE;
},
+ modalMessage(tokenName) {
+ return sprintf(this.$options.i18n.modalMessage, {
+ accessTokenType: this.accessTokenType,
+ tokenName,
+ });
+ },
sortingChanged(aRow, bRow, key) {
if (['createdAt', 'lastUsedAt', 'expiresAt'].includes(key)) {
// Transform `null` value to the latest possible date
@@ -149,13 +150,13 @@ export default {
}}</span>
</template>
- <template #cell(action)="{ item: { revokePath } }">
+ <template #cell(action)="{ item: { name, revokePath } }">
<gl-button
v-if="revokePath"
category="tertiary"
:title="$options.i18n.revokeButton"
:aria-label="$options.i18n.revokeButton"
- :data-confirm="modalMessage"
+ :data-confirm="modalMessage(name)"
data-confirm-btn-variant="danger"
data-qa-selector="revoke_button"
data-method="put"
diff --git a/app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue b/app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue
index c1ec46cfc50..9bcdcec8b78 100644
--- a/app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue
+++ b/app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue
@@ -267,7 +267,8 @@ export default {
});
}
});
- } else if (this.uniqueCommits.length > 0) {
+ }
+ if (this.uniqueCommits.length > 0) {
return this.createContextCommits({ commits: this.uniqueCommits, forceReload: true });
}
diff --git a/app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue b/app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue
index 1490d7e64f5..3c46de7c2be 100644
--- a/app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue
+++ b/app/assets/javascripts/admin/abuse_report/components/abuse_report_app.vue
@@ -1,9 +1,12 @@
<script>
import { GlAlert } from '@gitlab/ui';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ReportHeader from './report_header.vue';
import UserDetails from './user_details.vue';
+import ReportDetails from './report_details.vue';
import ReportedContent from './reported_content.vue';
-import HistoryItems from './history_items.vue';
+import ActivityEventsList from './activity_events_list.vue';
+import ActivityHistoryItem from './activity_history_item.vue';
const alertDefaults = {
visible: false,
@@ -17,9 +20,12 @@ export default {
GlAlert,
ReportHeader,
UserDetails,
+ ReportDetails,
ReportedContent,
- HistoryItems,
+ ActivityEventsList,
+ ActivityHistoryItem,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
abuseReport: {
type: Object,
@@ -31,6 +37,11 @@ export default {
alert: { ...alertDefaults },
};
},
+ computed: {
+ similarOpenReports() {
+ return this.abuseReport.user?.similarOpenReports || [];
+ },
+ },
methods: {
showAlert(variant, message) {
this.alert.visible = true;
@@ -49,6 +60,7 @@ export default {
<gl-alert v-if="alert.visible" :variant="alert.variant" class="gl-mt-4" @dismiss="closeAlert">{{
alert.message
}}</gl-alert>
+
<report-header
v-if="abuseReport.user"
:user="abuseReport.user"
@@ -56,7 +68,33 @@ export default {
@showAlert="showAlert"
/>
<user-details v-if="abuseReport.user" :user="abuseReport.user" />
- <reported-content :report="abuseReport.report" :reporter="abuseReport.reporter" />
- <history-items :report="abuseReport.report" :reporter="abuseReport.reporter" />
+
+ <report-details
+ v-if="glFeatures.abuseReportLabels"
+ :report-id="abuseReport.report.globalId"
+ class="gl-mt-6"
+ />
+
+ <reported-content :report="abuseReport.report" data-testid="reported-content" />
+
+ <div
+ v-for="report in similarOpenReports"
+ :key="report.id"
+ data-testid="reported-content-similar-open-reports"
+ >
+ <reported-content :report="report" />
+ </div>
+
+ <activity-events-list>
+ <template #history-items>
+ <activity-history-item :report="abuseReport.report" data-testid="activity" />
+ <activity-history-item
+ v-for="report in similarOpenReports"
+ :key="report.id"
+ :report="report"
+ data-testid="activity-similar-open-reports"
+ />
+ </template>
+ </activity-events-list>
</section>
</template>
diff --git a/app/assets/javascripts/admin/abuse_report/components/activity_events_list.vue b/app/assets/javascripts/admin/abuse_report/components/activity_events_list.vue
new file mode 100644
index 00000000000..8c4c1da28b8
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_report/components/activity_events_list.vue
@@ -0,0 +1,19 @@
+<script>
+import { HISTORY_ITEMS_I18N } from '../constants';
+
+export default {
+ name: 'ActivityEventsList',
+ i18n: HISTORY_ITEMS_I18N,
+};
+</script>
+
+<template>
+ <!-- The styles `issuable-discussion`, `timeline`, `main-notes-list` and `notes` used below
+ are declared in app/assets/stylesheets/pages/notes.scss -->
+ <section class="gl-pt-6 issuable-discussion">
+ <h2 class="gl-font-lg gl-mt-0 gl-mb-2">{{ $options.i18n.activity }}</h2>
+ <ul class="timeline main-notes-list notes">
+ <slot name="history-items"></slot>
+ </ul>
+ </section>
+</template>
diff --git a/app/assets/javascripts/admin/abuse_report/components/activity_history_item.vue b/app/assets/javascripts/admin/abuse_report/components/activity_history_item.vue
new file mode 100644
index 00000000000..5962203c382
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_report/components/activity_history_item.vue
@@ -0,0 +1,42 @@
+<script>
+import { GlSprintf } from '@gitlab/ui';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
+import { HISTORY_ITEMS_I18N } from '../constants';
+
+export default {
+ name: 'ActivityHistoryItem',
+ components: {
+ GlSprintf,
+ TimeAgoTooltip,
+ HistoryItem,
+ },
+ props: {
+ report: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ reporter() {
+ return this.report.reporter;
+ },
+ reporterName() {
+ return this.reporter?.name || this.$options.i18n.deletedReporter;
+ },
+ },
+ i18n: HISTORY_ITEMS_I18N,
+};
+</script>
+
+<template>
+ <history-item icon="warning">
+ <div class="gl-display-flex gl-xs-flex-direction-column">
+ <gl-sprintf :message="$options.i18n.reportedByForCategory">
+ <template #name>{{ reporterName }}</template>
+ <template #category>{{ report.category }}</template>
+ </gl-sprintf>
+ <time-ago-tooltip :time="report.reportedAt" class="gl-text-secondary gl-sm-ml-3" />
+ </div>
+ </history-item>
+</template>
diff --git a/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report.query.graphql b/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report.query.graphql
new file mode 100644
index 00000000000..f5b075cb9af
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report.query.graphql
@@ -0,0 +1,13 @@
+query abuseReportQuery($id: AbuseReportID!) {
+ abuseReport(id: $id) {
+ labels {
+ nodes {
+ id
+ title
+ description
+ color
+ textColor
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql b/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql
new file mode 100644
index 00000000000..4e724b4db2c
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql
@@ -0,0 +1,11 @@
+query abuseReportLabelsQuery($searchTerm: String) {
+ labels: abuseReportLabels(searchTerm: $searchTerm) {
+ nodes {
+ id
+ title
+ description
+ color
+ textColor
+ }
+ }
+}
diff --git a/app/assets/javascripts/admin/abuse_report/components/graphql/create_abuse_report_label.mutation.graphql b/app/assets/javascripts/admin/abuse_report/components/graphql/create_abuse_report_label.mutation.graphql
new file mode 100644
index 00000000000..0781b8e634b
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_report/components/graphql/create_abuse_report_label.mutation.graphql
@@ -0,0 +1,10 @@
+#import "~/graphql_shared/fragments/label.fragment.graphql"
+
+mutation createAbuseReportLabel($title: String!, $color: String) {
+ labelCreate: abuseReportLabelCreate(input: { title: $title, color: $color }) {
+ label {
+ ...Label
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/admin/abuse_report/components/history_items.vue b/app/assets/javascripts/admin/abuse_report/components/history_items.vue
deleted file mode 100644
index 28b66db84a2..00000000000
--- a/app/assets/javascripts/admin/abuse_report/components/history_items.vue
+++ /dev/null
@@ -1,51 +0,0 @@
-<script>
-import { GlSprintf } from '@gitlab/ui';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
-import { HISTORY_ITEMS_I18N } from '../constants';
-
-export default {
- name: 'HistoryItems',
- components: {
- GlSprintf,
- TimeAgoTooltip,
- HistoryItem,
- },
- props: {
- report: {
- type: Object,
- required: true,
- },
- reporter: {
- type: Object,
- required: false,
- default: null,
- },
- },
- computed: {
- reporterName() {
- return this.reporter?.name || this.$options.i18n.deletedReporter;
- },
- },
- i18n: HISTORY_ITEMS_I18N,
-};
-</script>
-
-<template>
- <!-- The styles `issuable-discussion`, `timeline`, `main-notes-list` and `notes` used below
- are declared in app/assets/stylesheets/pages/notes.scss -->
- <section class="gl-pt-6 issuable-discussion">
- <h2 class="gl-font-size-h1 gl-mt-0 gl-mb-2">{{ $options.i18n.activity }}</h2>
- <ul class="timeline main-notes-list notes">
- <history-item icon="warning">
- <div class="gl-display-flex gl-xs-flex-direction-column">
- <gl-sprintf :message="$options.i18n.reportedByForCategory">
- <template #name>{{ reporterName }}</template>
- <template #category>{{ report.category }}</template>
- </gl-sprintf>
- <time-ago-tooltip :time="report.reportedAt" class="gl-text-secondary gl-sm-ml-3" />
- </div>
- </history-item>
- </ul>
- </section>
-</template>
diff --git a/app/assets/javascripts/admin/abuse_report/components/labels_select.vue b/app/assets/javascripts/admin/abuse_report/components/labels_select.vue
new file mode 100644
index 00000000000..747c9a1a947
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_report/components/labels_select.vue
@@ -0,0 +1,235 @@
+<script>
+import { GlButton, GlLoadingIcon } from '@gitlab/ui';
+import { debounce } from 'lodash';
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+import { __, s__, sprintf } from '~/locale';
+import LabelItem from '~/sidebar/components/labels/labels_select_widget/label_item.vue';
+import DropdownValue from '~/sidebar/components/labels/labels_select_widget/dropdown_value.vue';
+import DropdownContentsCreateView from '~/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue';
+import DropdownHeader from '~/sidebar/components/labels/labels_select_widget/dropdown_header.vue';
+import DropdownFooter from '~/sidebar/components/labels/labels_select_widget/dropdown_footer.vue';
+import DropdownWidget from '~/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue';
+import abuseReportLabelsQuery from './graphql/abuse_report_labels.query.graphql';
+
+export default {
+ components: {
+ DropdownWidget,
+ GlButton,
+ GlLoadingIcon,
+ LabelItem,
+ DropdownValue,
+ DropdownContentsCreateView,
+ DropdownHeader,
+ DropdownFooter,
+ },
+ inject: ['updatePath', 'listPath'],
+ props: {
+ report: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ search: '',
+ labels: [],
+ selected: this.report.labels,
+ initialLoading: true,
+ isEditing: false,
+ isUpdating: false,
+ showCreateView: false,
+ };
+ },
+ apollo: {
+ labels: {
+ query() {
+ return abuseReportLabelsQuery;
+ },
+ variables() {
+ return { searchTerm: this.search };
+ },
+ skip() {
+ return !this.isEditing;
+ },
+ update(data) {
+ return data.labels?.nodes;
+ },
+ error() {
+ createAlert({ message: this.$options.i18n.searchError });
+ },
+ },
+ },
+ computed: {
+ isLabelsEmpty() {
+ return this.selected.length === 0;
+ },
+ selectedLabelIds() {
+ return this.selected.map((label) => label.id);
+ },
+ isLoading() {
+ return this.$apollo.queries.labels.loading;
+ },
+ selectText() {
+ if (!this.selected.length) {
+ return this.$options.i18n.labelsListTitle;
+ }
+ if (this.selected.length > 1) {
+ return sprintf(s__('LabelSelect|%{firstLabelName} +%{remainingLabelCount} more'), {
+ firstLabelName: this.selected[0].title,
+ remainingLabelCount: this.selected.length - 1,
+ });
+ }
+ return this.selected[0].title;
+ },
+ },
+ watch: {
+ report({ labels }) {
+ this.selected = labels;
+ this.initialLoading = false;
+ },
+ },
+ created() {
+ const setSearch = (search) => {
+ this.search = search;
+ };
+ this.debouncedSetSearch = debounce(setSearch, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
+ },
+ methods: {
+ toggleEdit() {
+ return this.isEditing ? this.hideDropdown() : this.showDropdown();
+ },
+ showDropdown() {
+ this.isEditing = true;
+ this.$refs.editDropdown.showDropdown();
+ },
+ hideDropdown() {
+ this.saveSelectedLabels();
+ this.isEditing = false;
+ },
+ saveSelectedLabels() {
+ this.isUpdating = true;
+
+ axios
+ .put(this.updatePath, { label_ids: this.selectedLabelIds })
+ .catch((error) => {
+ createAlert({
+ message: __('An error occurred while updating labels.'),
+ captureError: true,
+ error,
+ });
+ })
+ .finally(() => {
+ this.isUpdating = false;
+ });
+ },
+ isLabelSelected(label) {
+ return this.selectedLabelIds.includes(label.id);
+ },
+ filterSelected(id) {
+ return this.selected.filter(({ id: labelId }) => labelId !== id);
+ },
+ toggleLabelSelection(label) {
+ this.selected = this.isLabelSelected(label)
+ ? this.filterSelected(label.id)
+ : [...this.selected, label];
+ },
+ removeLabel(labelId) {
+ this.selected = this.filterSelected(labelId);
+ this.saveSelectedLabels();
+ },
+ toggleCreateView() {
+ this.showCreateView = !this.showCreateView;
+ },
+ onLabelCreated(label) {
+ this.toggleLabelSelection(label);
+ this.toggleCreateView();
+ },
+ },
+ i18n: {
+ label: __('Labels'),
+ noLabels: __('None'),
+ labelsListTitle: __('Assign labels'),
+ searchError: __('An error occurred while searching for labels, please try again.'),
+ edit: __('Edit'),
+ },
+};
+</script>
+<template>
+ <div class="labels-select-wrapper">
+ <div class="gl-display-flex gl-align-items-center gl-gap-3 gl-mb-2">
+ <span>{{ $options.i18n.label }}</span>
+ <gl-loading-icon v-if="initialLoading" size="sm" inline class="gl-ml-2" />
+ <gl-button
+ category="tertiary"
+ size="small"
+ :disabled="isUpdating || initialLoading"
+ class="edit-link gl-ml-auto"
+ @click="toggleEdit"
+ >
+ {{ $options.i18n.edit }}
+ </gl-button>
+ </div>
+ <div class="gl-text-gray-500 gl-mb-2" data-testid="selected-labels">
+ <template v-if="isLabelsEmpty">{{ $options.i18n.noLabels }}</template>
+ <dropdown-value
+ v-else
+ :disable-labels="isLoading"
+ :selected-labels="selected"
+ :allow-label-remove="!isUpdating"
+ :labels-filter-base-path="listPath"
+ :labels-filter-param="'label_name'"
+ @onLabelRemove="removeLabel"
+ />
+ </div>
+
+ <dropdown-widget
+ v-show="isEditing"
+ ref="editDropdown"
+ :select-text="selectText"
+ :options="labels"
+ :is-loading="isLoading"
+ :selected="selected"
+ :search-term="search"
+ :allow-multiselect="true"
+ :no-options-text="__('No labels found')"
+ @hide="hideDropdown"
+ @set-option="toggleLabelSelection"
+ @set-search="debouncedSetSearch"
+ >
+ <template #header>
+ <dropdown-header
+ ref="header"
+ :search-key="search"
+ labels-create-title=""
+ :labels-list-title="$options.i18n.labelsListTitle"
+ :show-dropdown-contents-create-view="showCreateView"
+ @toggleDropdownContentsCreateView="toggleCreateView"
+ @closeDropdown="hideDropdown"
+ @input="debouncedSetSearch"
+ />
+ </template>
+ <template #item="{ item }">
+ <label-item v-if="item" :label="item" />
+ </template>
+ <template v-if="showCreateView" #default>
+ <dropdown-contents-create-view
+ attr-workspace-path=""
+ full-path=""
+ label-create-type=""
+ workspace-type="abuseReport"
+ @hideCreateView="toggleCreateView"
+ @labelCreated="onLabelCreated"
+ />
+ </template>
+ <template #footer>
+ <dropdown-footer
+ v-if="!showCreateView"
+ :footer-create-label-title="__('Create label')"
+ @toggleDropdownContentsCreateView="toggleCreateView"
+ />
+ </template>
+ </dropdown-widget>
+ </div>
+</template>
diff --git a/app/assets/javascripts/admin/abuse_report/components/report_actions.vue b/app/assets/javascripts/admin/abuse_report/components/report_actions.vue
index 92478e10289..560d733c10c 100644
--- a/app/assets/javascripts/admin/abuse_report/components/report_actions.vue
+++ b/app/assets/javascripts/admin/abuse_report/components/report_actions.vue
@@ -95,12 +95,8 @@ export default {
return;
}
- // TODO: In 16.4 use moderateUserPath without falling back to using updatePath
- // See https://gitlab.com/gitlab-org/modelops/anti-abuse/team-tasks/-/issues/167?work_item_iid=443
- const { moderateUserPath, updatePath } = this.report;
- const path = moderateUserPath || updatePath;
-
- axios.put(path, this.form).then(this.handleResponse).catch(this.handleError);
+ const { moderateUserPath } = this.report;
+ axios.put(moderateUserPath, this.form).then(this.handleResponse).catch(this.handleError);
},
handleResponse({ data }) {
this.toggleActionsDrawer();
diff --git a/app/assets/javascripts/admin/abuse_report/components/report_details.vue b/app/assets/javascripts/admin/abuse_report/components/report_details.vue
new file mode 100644
index 00000000000..10e1dca7f91
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_report/components/report_details.vue
@@ -0,0 +1,49 @@
+<script>
+import { __ } from '~/locale';
+import { createAlert } from '~/alert';
+import LabelsSelect from './labels_select.vue';
+import abuseReportQuery from './graphql/abuse_report.query.graphql';
+
+export default {
+ name: 'ReportDetails',
+ components: {
+ LabelsSelect,
+ },
+ props: {
+ reportId: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ report: { labels: [] },
+ };
+ },
+ apollo: {
+ report: {
+ query() {
+ return abuseReportQuery;
+ },
+ variables() {
+ return { id: this.reportId };
+ },
+ update({ abuseReport }) {
+ return {
+ labels: abuseReport.labels?.nodes,
+ };
+ },
+ error() {
+ createAlert({ message: this.$options.i18n.fetchError });
+ },
+ },
+ },
+ i18n: {
+ fetchError: __('An error occurred while fetching labels, please try again.'),
+ },
+};
+</script>
+
+<template>
+ <labels-select :report="report" />
+</template>
diff --git a/app/assets/javascripts/admin/abuse_report/components/report_header.vue b/app/assets/javascripts/admin/abuse_report/components/report_header.vue
index 624dcd47650..90c1943cb27 100644
--- a/app/assets/javascripts/admin/abuse_report/components/report_header.vue
+++ b/app/assets/javascripts/admin/abuse_report/components/report_header.vue
@@ -32,9 +32,6 @@ export default {
isOpen() {
return this.state === STATUS_OPEN;
},
- badgeClass() {
- return this.isOpen ? 'issuable-status-badge-open' : 'issuable-status-badge-closed';
- },
badgeVariant() {
return this.isOpen ? 'success' : 'info';
},
@@ -58,21 +55,16 @@ export default {
<header
class="gl-py-4 gl-border-b gl-display-flex gl-justify-content-space-between gl-xs-flex-direction-column"
>
- <div class="gl-display-flex gl-align-items-center">
- <gl-badge
- class="issuable-status-badge gl-mr-3"
- :class="badgeClass"
- :variant="badgeVariant"
- :aria-label="badgeText"
- >
+ <div class="gl-display-flex gl-align-items-center gl-gap-3">
+ <gl-badge :variant="badgeVariant" :aria-label="badgeText">
<gl-icon :name="badgeIcon" class="gl-badge-icon" />
<span class="gl-display-none gl-sm-display-block gl-ml-2">{{ badgeText }}</span>
</gl-badge>
<gl-avatar :size="48" :src="user.avatarUrl" />
- <h1 class="gl-font-size-h-display gl-my-0 gl-ml-3">
+ <h1 class="gl-font-size-h-display gl-my-0">
{{ user.name }}
</h1>
- <gl-link :href="user.path" class="gl-ml-3"> @{{ user.username }} </gl-link>
+ <gl-link :href="user.path"> @{{ user.username }} </gl-link>
</div>
<nav
class="gl-display-flex gl-sm-align-items-center gl-mt-4 gl-sm-mt-0 gl-xs-flex-direction-column"
diff --git a/app/assets/javascripts/admin/abuse_report/components/reported_content.vue b/app/assets/javascripts/admin/abuse_report/components/reported_content.vue
index f4f0fcac58f..84d6f25ac05 100644
--- a/app/assets/javascripts/admin/abuse_report/components/reported_content.vue
+++ b/app/assets/javascripts/admin/abuse_report/components/reported_content.vue
@@ -26,11 +26,6 @@ export default {
type: Object,
required: true,
},
- reporter: {
- type: Object,
- required: false,
- default: null,
- },
},
data() {
return {
@@ -38,6 +33,9 @@ export default {
};
},
computed: {
+ reporter() {
+ return this.report.reporter;
+ },
reporterName() {
return this.reporter?.name || this.$options.i18n.deletedReporter;
},
@@ -67,11 +65,12 @@ export default {
<template>
<div class="gl-pt-6">
<div
- class="gl-pb-3 gl-display-flex gl-justify-content-space-between gl-xs-flex-direction-column"
+ class="gl-pb-3 gl-display-flex gl-justify-content-space-between gl-xs-flex-direction-column gl-align-items-center"
>
- <h2 class="gl-font-size-h1 gl-mt-0 gl-mb-2">
+ <h2 class="gl-font-lg gl-mt-2 gl-mb-2">
{{ $options.i18n.reportTypes[reportType] }}
</h2>
+
<div
class="gl-display-flex gl-align-items-stretch gl-xs-flex-direction-column gl-mt-3 gl-sm-mt-0"
>
diff --git a/app/assets/javascripts/admin/abuse_report/components/user_details.vue b/app/assets/javascripts/admin/abuse_report/components/user_details.vue
index 3dc03a8748f..fe0add1ba8d 100644
--- a/app/assets/javascripts/admin/abuse_report/components/user_details.vue
+++ b/app/assets/javascripts/admin/abuse_report/components/user_details.vue
@@ -39,19 +39,27 @@ export default {
<template>
<div class="gl-mt-6">
- <user-detail data-testid="createdAt" :label="$options.i18n.createdAt">
+ <user-detail data-testid="created-at" :label="$options.i18n.createdAt">
<time-ago-tooltip :time="user.createdAt" />
</user-detail>
+
<user-detail data-testid="email" :label="$options.i18n.email">
<gl-link :href="`mailto:${user.email}`">{{ user.email }}</gl-link>
</user-detail>
+
<user-detail data-testid="plan" :label="$options.i18n.plan" :value="user.plan" />
+
<user-detail
data-testid="verification"
:label="$options.i18n.verification"
:value="verificationState"
/>
- <user-detail v-if="user.creditCard" data-testid="creditCard" :label="$options.i18n.creditCard">
+
+ <user-detail
+ v-if="user.creditCard"
+ data-testid="credit-card-verification"
+ :label="$options.i18n.creditCard"
+ >
<gl-sprintf :message="$options.i18n.registeredWith">
<template #name>{{ user.creditCard.name }}</template>
</gl-sprintf>
@@ -65,17 +73,18 @@ export default {
</template>
</gl-sprintf>
</user-detail>
+
<user-detail
- v-if="user.otherReports.length"
- data-testid="otherReports"
- :label="$options.i18n.otherReports"
+ v-if="user.pastClosedReports.length"
+ data-testid="past-closed-reports"
+ :label="$options.i18n.pastReports"
>
<div
- v-for="(report, index) in user.otherReports"
+ v-for="(report, index) in user.pastClosedReports"
:key="index"
- :data-testid="`other-report-${index}`"
+ :data-testid="`past-report-${index}`"
>
- <gl-sprintf :message="$options.i18n.otherReport">
+ <gl-sprintf :message="$options.i18n.reportedFor">
<template #reportLink="{ content }">
<gl-link :href="report.reportPath">{{ content }}</gl-link>
</template>
@@ -86,28 +95,33 @@ export default {
</gl-sprintf>
</div>
</user-detail>
+
<user-detail
- data-testid="normalLocation"
+ data-testid="normal-location"
:label="$options.i18n.normalLocation"
:value="user.mostUsedIp || user.lastSignInIp"
/>
+
<user-detail
- data-testid="lastSignInIp"
+ data-testid="last-sign-in-ip"
:label="$options.i18n.lastSignInIp"
:value="user.lastSignInIp"
/>
+
<user-detail
- data-testid="snippets"
+ data-testid="user-snippets-count"
:label="$options.i18n.snippets"
:value="$options.i18n.snippetsCount(user.snippetsCount)"
/>
+
<user-detail
- data-testid="groups"
+ data-testid="user-groups-count"
:label="$options.i18n.groups"
:value="$options.i18n.groupsCount(user.groupsCount)"
/>
+
<user-detail
- data-testid="notes"
+ data-testid="user-notes-count"
:label="$options.i18n.notes"
:value="$options.i18n.notesCount(user.notesCount)"
/>
diff --git a/app/assets/javascripts/admin/abuse_report/constants.js b/app/assets/javascripts/admin/abuse_report/constants.js
index b290581598a..6cae6b24f20 100644
--- a/app/assets/javascripts/admin/abuse_report/constants.js
+++ b/app/assets/javascripts/admin/abuse_report/constants.js
@@ -58,7 +58,7 @@ export const USER_DETAILS_I18N = {
plan: s__('AbuseReport|Tier'),
verification: s__('AbuseReport|Verification'),
creditCard: s__('AbuseReport|Credit card'),
- otherReports: s__('AbuseReport|Abuse reports'),
+ pastReports: s__('AbuseReport|Past abuse reports'),
normalLocation: s__('AbuseReport|Normal location'),
lastSignInIp: s__('AbuseReport|Last login'),
snippets: s__('AbuseReport|Snippets'),
@@ -72,7 +72,7 @@ export const USER_DETAILS_I18N = {
phone: s__('AbuseReport|Phone'),
creditCard: s__('AbuseReport|Credit card'),
},
- otherReport: s__(
+ reportedFor: s__(
'AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}.',
),
registeredWith: s__('AbuseReport|Registered with name %{name}.'),
diff --git a/app/assets/javascripts/admin/abuse_report/index.js b/app/assets/javascripts/admin/abuse_report/index.js
index 8ff3e690127..c2117130d26 100644
--- a/app/assets/javascripts/admin/abuse_report/index.js
+++ b/app/assets/javascripts/admin/abuse_report/index.js
@@ -1,7 +1,15 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { defaultClient } from '~/graphql_shared/issuable_client';
import AbuseReportApp from './components/abuse_report_app.vue';
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient,
+});
+
export const initAbuseReportApp = () => {
const el = document.querySelector('#js-abuse-reports-detail-view');
@@ -9,14 +17,22 @@ export const initAbuseReportApp = () => {
return null;
}
- const { abuseReportData } = el.dataset;
+ const { abuseReportData, abuseReportsListPath } = el.dataset;
const abuseReport = convertObjectPropsToCamelCase(JSON.parse(abuseReportData), {
deep: true,
});
return new Vue({
el,
+ apolloProvider,
name: 'AbuseReportAppRoot',
+ provide: {
+ allowScopedLabels: false,
+ updatePath: abuseReport.report.updatePath,
+ listPath: abuseReportsListPath,
+ labelsManagePath: '',
+ allowLabelCreate: true,
+ },
render: (createElement) =>
createElement(AbuseReportApp, {
props: {
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
index f24e491a745..b9fef57c2a2 100644
--- a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
@@ -1,7 +1,7 @@
<script>
-import { GlLink } from '@gitlab/ui';
+import { GlLabel, GlLink } from '@gitlab/ui';
import { getTimeago } from '~/lib/utils/datetime_utility';
-import { queryToObject } from '~/lib/utils/url_utility';
+import { mergeUrlParams, queryToObject } from '~/lib/utils/url_utility';
import { s__, __, sprintf } from '~/locale';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { SORT_UPDATED_AT } from '../constants';
@@ -10,6 +10,7 @@ import AbuseCategory from './abuse_category.vue';
export default {
name: 'AbuseReportRow',
components: {
+ GlLabel,
GlLink,
ListItem,
AbuseCategory,
@@ -53,6 +54,11 @@ export default {
});
},
},
+ methods: {
+ labelTarget(labelName) {
+ return mergeUrlParams({ 'label_name[]': labelName }, window.location.href);
+ },
+ },
};
</script>
@@ -68,7 +74,16 @@ export default {
</gl-link>
</template>
<template #left-secondary>
- <abuse-category :category="report.category" class="gl-mt-2 gl-mb-3" />
+ <abuse-category :category="report.category" class="gl-mr-2" />
+ <gl-label
+ v-for="label in report.labels"
+ :key="label.id"
+ class="gl-mr-2"
+ size="sm"
+ :background-color="label.color"
+ :title="label.title"
+ :target="labelTarget(label.title)"
+ />
</template>
<template #right-secondary>
diff --git a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue
index 109df943c42..2c555aca3c0 100644
--- a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue
+++ b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue
@@ -234,7 +234,8 @@ export default {
initialTarget() {
if (this.targetAccessLevels.length > 0) {
return TARGET_ROLES;
- } else if (this.targetPath !== '') {
+ }
+ if (this.targetPath !== '') {
return TARGET_ALL_MATCHING_PATH;
}
return TARGET_ALL;
diff --git a/app/assets/javascripts/admin/users/components/actions/approve.vue b/app/assets/javascripts/admin/users/components/actions/approve.vue
index 5b13bd177ae..bcd17570b95 100644
--- a/app/assets/javascripts/admin/users/components/actions/approve.vue
+++ b/app/assets/javascripts/admin/users/components/actions/approve.vue
@@ -44,7 +44,7 @@ export default {
},
actionPrimary: {
text: I18N_USER_ACTIONS.approve,
- attributes: { variant: 'confirm', 'data-qa-selector': 'approve_user_confirm_button' },
+ attributes: { variant: 'confirm', 'data-testid': 'approve-user-confirm-button' },
},
messageHtml,
},
@@ -55,7 +55,7 @@ export default {
</script>
<template>
- <gl-disclosure-dropdown-item data-qa-selector="approve_user_button" @action="onClick">
+ <gl-disclosure-dropdown-item @action="onClick">
<template #list-item>
<slot></slot>
</template>
diff --git a/app/assets/javascripts/admin/users/components/user_actions.vue b/app/assets/javascripts/admin/users/components/user_actions.vue
index 38c7d3f9b90..a9482d479b6 100644
--- a/app/assets/javascripts/admin/users/components/user_actions.vue
+++ b/app/assets/javascripts/admin/users/components/user_actions.vue
@@ -116,8 +116,7 @@ export default {
category="tertiary"
:toggle-text="$options.i18n.userAdministration"
text-sr-only
- data-testid="dropdown-toggle"
- data-qa-selector="user_actions_dropdown_toggle"
+ data-testid="user-actions-dropdown-toggle"
:data-qa-username="user.username"
no-caret
>
diff --git a/app/assets/javascripts/alert_management/components/alert_management_table.vue b/app/assets/javascripts/alert_management/components/alert_management_table.vue
index 170bd6895aa..9e57b834c88 100644
--- a/app/assets/javascripts/alert_management/components/alert_management_table.vue
+++ b/app/assets/javascripts/alert_management/components/alert_management_table.vue
@@ -313,7 +313,7 @@ export default {
<template #table>
<gl-table
class="alert-management-table"
- data-qa-selector="alert_table_container"
+ data-testid="alert-table-container"
:items="
alerts
? alerts.list
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_form.vue b/app/assets/javascripts/alerts_settings/components/alerts_form.vue
index b9e37b9ede7..6baa431f2d9 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_form.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_form.vue
@@ -72,7 +72,7 @@ export default {
</p>
<form ref="settingsForm" @submit.prevent="updateAlertsIntegrationSettings">
<gl-form-group class="gl-pl-0">
- <gl-form-checkbox v-model="createIssueEnabled" data-qa-selector="create_incident_checkbox">
+ <gl-form-checkbox v-model="createIssueEnabled" data-testid="create-incident-checkbox">
<span>{{ $options.i18n.createIncident.label }}</span>
</gl-form-checkbox>
</gl-form-group>
@@ -93,14 +93,14 @@ export default {
v-model="issueTemplate"
:items="templates"
block
- data-qa-selector="incident_templates_dropdown"
+ data-testid="incident-templates-dropdown"
/>
</gl-form-group>
<gl-form-group class="gl-pl-0 gl-mb-5">
<gl-form-checkbox
v-model="sendEmailEnabled"
- data-qa-selector="enable_email_notification_checkbox"
+ data-testid="enable-email-notification-checkbox"
>
<span>{{ $options.i18n.sendEmail.label }}</span>
</gl-form-checkbox>
@@ -112,7 +112,7 @@ export default {
</gl-form-group>
<gl-button
ref="submitBtn"
- data-qa-selector="save_changes_button"
+ data-testid="save-changes-button"
:disabled="loading"
variant="confirm"
type="submit"
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
index 56740e436ca..fb872243e5e 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
@@ -406,7 +406,7 @@ export default {
v-model="integrationForm.type"
:disabled="isSelectDisabled"
class="gl-max-w-full"
- data-qa-selector="integration_type_dropdown"
+ data-testid="integration-type-dropdown"
:options="integrationTypesOptions"
autofocus
/>
@@ -439,7 +439,7 @@ export default {
v-model="integrationForm.name"
type="text"
:placeholder="$options.i18n.integrationFormSteps.nameIntegration.placeholder"
- data-qa-selector="integration_name_field"
+ data-testid="integration-name-field"
@input="validateName"
/>
</gl-form-group>
@@ -462,7 +462,7 @@ export default {
v-model="integrationForm.active"
:is-loading="loading"
:label="$options.i18n.integrationFormSteps.nameIntegration.activeToggle"
- data-qa-selector="active_toggle_container"
+ data-testid="active-toggle-container"
class="gl-mt-4 gl-font-weight-normal"
/>
</gl-form-group>
@@ -552,7 +552,7 @@ export default {
variant="confirm"
category="secondary"
class="gl-ml-3 js-no-auto-disable"
- data-qa-selector="save_and_create_alert_button"
+ data-testid="save-and-create-alert-button"
@click="submit(true)"
>
{{ $options.i18n.saveAndTestIntegration }}
@@ -654,7 +654,7 @@ export default {
:debounce="$options.JSON_VALIDATE_DELAY"
rows="6"
max-rows="10"
- data-qa-selector="test_payload_field"
+ data-testid="test-payload-field"
@input="validateJson(false)"
/>
</gl-form-group>
@@ -666,7 +666,6 @@ export default {
data-testid="send-test-alert"
variant="confirm"
class="js-no-auto-disable"
- data-qa-selector="send_test_alert_button"
@click="isFormDirty ? null : sendTestAlert()"
>
{{ $options.i18n.send }}
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue
index e4fc37f9760..e735ee466ad 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue
@@ -385,8 +385,7 @@ export default {
<gl-button
v-if="canAddIntegration && !formVisible"
size="small"
- data-testid="add-integration-btn"
- data-qa-selector="add_integration_button"
+ data-testid="add-integration-button"
@click="setFormVisibility(true)"
>
{{ $options.i18n.addNewIntegration }}
diff --git a/app/assets/javascripts/analytics/cycle_analytics/components/formatted_stage_count.vue b/app/assets/javascripts/analytics/cycle_analytics/components/formatted_stage_count.vue
index b622b0441e2..724e9c91305 100644
--- a/app/assets/javascripts/analytics/cycle_analytics/components/formatted_stage_count.vue
+++ b/app/assets/javascripts/analytics/cycle_analytics/components/formatted_stage_count.vue
@@ -13,7 +13,8 @@ export default {
formattedStageCount() {
if (!this.stageCount) {
return '-';
- } else if (this.stageCount > 1000) {
+ }
+ if (this.stageCount > 1000) {
return sprintf(s__('ValueStreamAnalytics|%{stageCount}+ items'), {
stageCount: formatNumber(1000),
});
diff --git a/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue b/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
index f881c924ae5..ddfc6baafa9 100644
--- a/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
+++ b/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
@@ -69,7 +69,8 @@ export default {
selectedProjectsLabel() {
if (this.selectedProjects.length === 1) {
return this.selectedProjects[0].name;
- } else if (this.selectedProjects.length > 1) {
+ }
+ if (this.selectedProjects.length > 1) {
return n__(
'CycleAnalytics|Project selected',
'CycleAnalytics|%d projects selected',
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 185cdaa1c99..6dfc1c609de 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -33,6 +33,7 @@ const Api = {
forkedProjectsPath: '/api/:version/projects/:id/forks',
projectLabelsPath: '/:namespace_path/:project_path/-/labels',
projectFileSchemaPath: '/:namespace_path/:project_path/-/schema/:ref/:filename',
+ projectGroupsPath: '/api/:version/projects/:id/groups.json',
projectUsersPath: '/api/:version/projects/:id/users',
projectInvitationsPath: '/api/:version/projects/:id/invitations',
projectMembersPath: '/api/:version/projects/:id/members',
@@ -177,6 +178,19 @@ const Api = {
});
},
+ projectGroups(id, options) {
+ const url = Api.buildUrl(this.projectGroupsPath).replace(':id', encodeURIComponent(id));
+
+ return axios
+ .get(url, {
+ params: {
+ ...options,
+ },
+ })
+ .then(({ data }) => {
+ return data;
+ });
+ },
/**
* @deprecated This method will be removed soon. Use the
* `getGroups` method in `~/rest_api` instead.
diff --git a/app/assets/javascripts/api/application_settings_api.js b/app/assets/javascripts/api/application_settings_api.js
new file mode 100644
index 00000000000..839636c36f4
--- /dev/null
+++ b/app/assets/javascripts/api/application_settings_api.js
@@ -0,0 +1,14 @@
+import axios from '../lib/utils/axios_utils';
+import { buildApiUrl } from './api_utils';
+
+const APPLICATION_SETTINGS_PATH = '/api/:version/application/settings';
+
+export function getApplicationSettings() {
+ const url = buildApiUrl(APPLICATION_SETTINGS_PATH);
+ return axios.get(url);
+}
+
+export function updateApplicationSettings(data) {
+ const url = buildApiUrl(APPLICATION_SETTINGS_PATH);
+ return axios.put(url, data);
+}
diff --git a/app/assets/javascripts/authentication/webauthn/error.js b/app/assets/javascripts/authentication/webauthn/error.js
index 40dbecd8bc9..ce6c79a1f11 100644
--- a/app/assets/javascripts/authentication/webauthn/error.js
+++ b/app/assets/javascripts/authentication/webauthn/error.js
@@ -14,11 +14,14 @@ export default class WebAuthnError {
message() {
if (this.errorName === 'NotSupportedError') {
return __('Your device is not compatible with GitLab. Please try another device');
- } else if (this.errorName === 'InvalidStateError' && this.flowType === WEBAUTHN_AUTHENTICATE) {
+ }
+ if (this.errorName === 'InvalidStateError' && this.flowType === WEBAUTHN_AUTHENTICATE) {
return __('This device has not been registered with us.');
- } else if (this.errorName === 'InvalidStateError' && this.flowType === WEBAUTHN_REGISTER) {
+ }
+ if (this.errorName === 'InvalidStateError' && this.flowType === WEBAUTHN_REGISTER) {
return __('This device has already been registered with us.');
- } else if (this.errorName === 'SecurityError' && this.httpsDisabled) {
+ }
+ if (this.errorName === 'SecurityError' && this.httpsDisabled) {
return __(
'WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details.',
);
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js b/app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js
index 095634340c1..e1c1bd58ee2 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js
@@ -20,7 +20,8 @@ export default () => ({
const checkbox = el.querySelector('input[type=checkbox].task-list-item-checkbox');
if (checkbox?.matches('[data-inapplicable]')) {
return { state: 'inapplicable' };
- } else if (checkbox?.checked) {
+ }
+ if (checkbox?.checked) {
return { state: 'done' };
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/keybindings.js b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
index 689f2f0898e..e8c486f6e74 100644
--- a/app/assets/javascripts/behaviors/shortcuts/keybindings.js
+++ b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
@@ -636,6 +636,7 @@ const MR_SHORTCUTS_GROUP = {
MR_NEXT_UNRESOLVED_DISCUSSION,
MR_PREVIOUS_UNRESOLVED_DISCUSSION,
MR_COPY_SOURCE_BRANCH_NAME,
+ MR_TOGGLE_FILE_BROWSER,
],
};
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts_help.vue b/app/assets/javascripts/behaviors/shortcuts/shortcuts_help.vue
index cb7c6f9f6bc..e81ceae57c0 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts_help.vue
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_help.vue
@@ -1,15 +1,16 @@
<script>
-import { GlModal, GlSearchBoxByType } from '@gitlab/ui';
+import { GlModal, GlSearchBoxByType, GlLink, GlSprintf } from '@gitlab/ui';
import { s__, __ } from '~/locale';
+import { joinPaths } from '../../lib/utils/url_utility';
import { keybindingGroups } from './keybindings';
import Shortcut from './shortcut.vue';
-import ShortcutsToggle from './shortcuts_toggle.vue';
export default {
components: {
GlModal,
GlSearchBoxByType,
- ShortcutsToggle,
+ GlLink,
+ GlSprintf,
Shortcut,
},
data() {
@@ -39,6 +40,9 @@ export default {
return mapped.filter((group) => group.keybindings.length);
},
+ absoluteUserPreferencesPath() {
+ return joinPaths(gon.relative_url_root || '/', '/-/profile/preferences');
+ },
},
i18n: {
title: __(`Keyboard shortcuts`),
@@ -66,7 +70,21 @@ export default {
:aria-label="$options.i18n.search"
class="gl-w-half gl-mr-3"
/>
- <shortcuts-toggle class="gl-w-half gl-ml-3" />
+ <span>
+ <gl-sprintf
+ :message="
+ __(
+ 'Enable or disable keyboard shortcuts in your %{linkStart}user preferences%{linkEnd}.',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="absoluteUserPreferencesPath">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </span>
</div>
<div v-if="filteredKeybindings.length === 0" class="gl-px-5">
{{ $options.i18n.noMatch }}
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.js
index 3f3e0c51de5..22f2478c530 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_toggle.js
@@ -3,13 +3,7 @@ import 'mousetrap/plugins/pause/mousetrap-pause';
const shorcutsDisabledKey = 'shortcutsDisabled';
-export const shouldDisableShortcuts = () => {
- try {
- return localStorage.getItem(shorcutsDisabledKey) === 'true';
- } catch (e) {
- return false;
- }
-};
+export const shouldDisableShortcuts = () => !window.gon.keyboard_shortcuts_enabled;
export function enableShortcuts() {
localStorage.setItem(shorcutsDisabledKey, false);
diff --git a/app/assets/javascripts/behaviors/toggler_behavior.js b/app/assets/javascripts/behaviors/toggler_behavior.js
index 30424fee46a..4e643f71c4b 100644
--- a/app/assets/javascripts/behaviors/toggler_behavior.js
+++ b/app/assets/javascripts/behaviors/toggler_behavior.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { fixTitle } from '~/tooltips';
import { getLocationHash } from '../lib/utils/url_utility';
// Toggle button. Show/hide content inside parent container.
@@ -29,9 +30,22 @@ $(() => {
$container.find('.js-toggle-content').toggle(toggleState);
}
+ function updateTitle(el, container) {
+ const $container = $(container);
+ const isExpanded = $container.data('is-expanded');
+
+ el.setAttribute('title', isExpanded ? el.dataset.collapseTitle : el.dataset.expandTitle);
+
+ fixTitle(el);
+ }
+
$('body').on('click', '.js-toggle-button', function toggleButton(e) {
e.currentTarget.classList.toggle(e.currentTarget.dataset.toggleOpenClass || 'selected');
- toggleContainer($(this).closest('.js-toggle-container'));
+
+ const containerEl = this.closest('.js-toggle-container');
+
+ toggleContainer(containerEl);
+ updateTitle(this, containerEl);
const targetTag = e.currentTarget.tagName.toLowerCase();
if (targetTag === 'a' || targetTag === 'button') {
diff --git a/app/assets/javascripts/blob/components/blob_header.vue b/app/assets/javascripts/blob/components/blob_header.vue
index 4e47aa99fd8..699a0491183 100644
--- a/app/assets/javascripts/blob/components/blob_header.vue
+++ b/app/assets/javascripts/blob/components/blob_header.vue
@@ -1,5 +1,8 @@
<script>
import DefaultActions from 'jh_else_ce/blob/components/blob_header_default_actions.vue';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import userInfoQuery from '../queries/user_info.query.graphql';
+import applicationInfoQuery from '../queries/application_info.query.graphql';
import BlobFilepath from './blob_header_filepath.vue';
import ViewerSwitcher from './blob_header_viewer_switcher.vue';
import { SIMPLE_BLOB_VIEWER } from './constants';
@@ -11,6 +14,21 @@ export default {
DefaultActions,
BlobFilepath,
TableOfContents,
+ WebIdeLink: () => import('ee_else_ce/vue_shared/components/web_ide_link.vue'),
+ },
+ apollo: {
+ currentUser: {
+ query: userInfoQuery,
+ error() {
+ this.$emit('error');
+ },
+ },
+ gitpodEnabled: {
+ query: applicationInfoQuery,
+ error() {
+ this.$emit('error');
+ },
+ },
},
props: {
blob: {
@@ -52,10 +70,26 @@ export default {
required: false,
default: false,
},
+ showForkSuggestion: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ projectPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ projectId: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
return {
viewer: this.hideViewerSwitcher ? null : this.activeViewerType,
+ gitpodEnabled: false,
};
},
computed: {
@@ -65,12 +99,18 @@ export default {
showDefaultActions() {
return !this.hideDefaultActions;
},
+ showWebIdeLink() {
+ return !this.blob.archived && this.blob.editBlobPath;
+ },
isEmpty() {
return this.blob.rawSize === '0';
},
blobSwitcherDocIcon() {
return this.blob.richViewer?.fileType === 'csv' ? 'table' : 'document';
},
+ projectIdAsNumber() {
+ return getIdFromGraphQLId(this.projectId);
+ },
},
watch: {
viewer(newVal, oldVal) {
@@ -100,6 +140,27 @@ export default {
<div class="gl-display-flex gl-flex-wrap file-actions">
<viewer-switcher v-if="showViewerSwitcher" v-model="viewer" :doc-icon="blobSwitcherDocIcon" />
+ <web-ide-link
+ v-if="showWebIdeLink"
+ :show-edit-button="!isBinary"
+ class="gl-mr-3"
+ :edit-url="blob.editBlobPath"
+ :web-ide-url="blob.ideEditPath"
+ :needs-to-fork="showForkSuggestion"
+ :show-pipeline-editor-button="Boolean(blob.pipelineEditorPath)"
+ :pipeline-editor-url="blob.pipelineEditorPath"
+ :gitpod-url="blob.gitpodBlobUrl"
+ :show-gitpod-button="gitpodEnabled"
+ :gitpod-enabled="currentUser && currentUser.gitpodEnabled"
+ :project-path="projectPath"
+ :project-id="projectIdAsNumber"
+ :user-preferences-gitpod-path="currentUser && currentUser.preferencesGitpodPath"
+ :user-profile-enable-gitpod-path="currentUser && currentUser.profileEnableGitpodPath"
+ is-blob
+ disable-fork-modal
+ v-on="$listeners"
+ />
+
<slot name="actions"></slot>
<default-actions
diff --git a/app/assets/javascripts/blob/line_highlighter.js b/app/assets/javascripts/blob/line_highlighter.js
index 4258d16b69f..9c6a5958e1f 100644
--- a/app/assets/javascripts/blob/line_highlighter.js
+++ b/app/assets/javascripts/blob/line_highlighter.js
@@ -59,7 +59,7 @@ LineHighlighter.prototype.bindEvents = function () {
}
};
-LineHighlighter.prototype.highlightHash = function (newHash) {
+LineHighlighter.prototype.highlightHash = function (newHash, scrollEnabled = true) {
let range;
if (newHash && typeof newHash === 'string') this._hash = newHash;
@@ -71,12 +71,14 @@ LineHighlighter.prototype.highlightHash = function (newHash) {
this.highlightRange(range);
const lineSelector = `#L${range[0]}`;
- scrollToElement(lineSelector, {
- // Scroll to the first highlighted line on initial load
- // Add an offset of -100 for some context
- offset: -100,
- behavior: this.options.scrollBehavior,
- });
+ if (scrollEnabled) {
+ scrollToElement(lineSelector, {
+ // Scroll to the first highlighted line on initial load
+ // Add an offset of -100 for some context
+ offset: -100,
+ behavior: this.options.scrollBehavior,
+ });
+ }
}
}
};
@@ -94,7 +96,8 @@ LineHighlighter.prototype.clickHandler = function (event) {
// treat this like a single-line selection.
this.setHash(lineNumber);
return this.highlightLine(lineNumber);
- } else if (event.shiftKey) {
+ }
+ if (event.shiftKey) {
if (lineNumber < current[0]) {
range = [lineNumber, current[0]];
} else {
diff --git a/app/assets/javascripts/blob/openapi/index.js b/app/assets/javascripts/blob/openapi/index.js
index 94ae281cada..9c22d960bf5 100644
--- a/app/assets/javascripts/blob/openapi/index.js
+++ b/app/assets/javascripts/blob/openapi/index.js
@@ -5,6 +5,7 @@ import {
relativePathToAbsolute,
joinPaths,
setUrlParams,
+ getParameterByName,
} from '~/lib/utils/url_utility';
const SANDBOX_FRAME_PATH = '/-/sandbox/swagger';
@@ -12,10 +13,14 @@ const SANDBOX_FRAME_PATH = '/-/sandbox/swagger';
const getSandboxFrameSrc = () => {
const path = joinPaths(gon.relative_url_root || '', SANDBOX_FRAME_PATH);
const absoluteUrl = relativePathToAbsolute(path, getBaseURL());
+ const displayOperationId = getParameterByName('displayOperationId');
+ const params = { displayOperationId };
+
if (window.gon?.relative_url_root) {
- return setUrlParams({ relativeRootPath: window.gon.relative_url_root }, absoluteUrl);
+ params.relativeRootPath = window.gon.relative_url_root;
}
- return absoluteUrl;
+
+ return setUrlParams(params, absoluteUrl);
};
const createSandbox = () => {
diff --git a/app/assets/javascripts/repository/queries/application_info.query.graphql b/app/assets/javascripts/blob/queries/application_info.query.graphql
index fd69de39f75..fd69de39f75 100644
--- a/app/assets/javascripts/repository/queries/application_info.query.graphql
+++ b/app/assets/javascripts/blob/queries/application_info.query.graphql
diff --git a/app/assets/javascripts/repository/queries/user_info.query.graphql b/app/assets/javascripts/blob/queries/user_info.query.graphql
index 114947a423d..114947a423d 100644
--- a/app/assets/javascripts/repository/queries/user_info.query.graphql
+++ b/app/assets/javascripts/blob/queries/user_info.query.graphql
diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue
index 692ca6bf59b..c441a718dd8 100644
--- a/app/assets/javascripts/boards/components/board_card_inner.vue
+++ b/app/assets/javascripts/boards/components/board_card_inner.vue
@@ -20,6 +20,7 @@ import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue';
import { ListType } from '../constants';
import eventHub from '../eventhub';
+import { setError } from '../graphql/cache_updates';
import IssueDueDate from './issue_due_date.vue';
import IssueTimeEstimate from './issue_time_estimate.vue';
@@ -45,6 +46,7 @@ export default {
},
mixins: [boardCardInner],
inject: [
+ 'allowSubEpics',
'rootPath',
'scopedLabelsAvailable',
'isEpicBoard',
@@ -85,7 +87,7 @@ export default {
};
},
computed: {
- ...mapState(['isShowingLabels', 'allowSubEpics']),
+ ...mapState(['isShowingLabels']),
isLoading() {
return this.item.isLoading || this.item.iid === '-1';
},
@@ -175,7 +177,8 @@ export default {
},
},
methods: {
- ...mapActions(['performSearch', 'setError']),
+ ...mapActions(['performSearch']),
+ setError,
isIndexLessThanlimit(index) {
return index < this.limitBeforeCounter;
},
@@ -288,7 +291,7 @@ export default {
<gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-5" />
<span
v-if="item.referencePath && !isLoading"
- class="board-card-number gl-overflow-hidden gl-display-flex gl-mr-3 gl-mt-3 gl-font-sm gl-text-secondary"
+ class="board-card-number gl-overflow-hidden gl-display-flex gl-gap-2 gl-mr-3 gl-mt-3 gl-font-sm gl-text-secondary"
:class="{ 'gl-font-base': isEpicBoard }"
>
<work-item-type-icon
diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue
index 5e1e46dd198..bb740c0e7eb 100644
--- a/app/assets/javascripts/boards/components/board_content_sidebar.vue
+++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue
@@ -222,7 +222,7 @@ export default {
<template #default>
<board-sidebar-title :active-item="activeBoardIssuable" data-testid="sidebar-title" />
<sidebar-assignees-widget
- v-if="activeBoardItem.assignees"
+ v-if="activeBoardIssuable.assignees"
:iid="activeBoardIssuable.iid"
:full-path="projectPathForActiveIssue"
:initial-assignees="activeBoardIssuable.assignees"
@@ -232,7 +232,7 @@ export default {
/>
<sidebar-dropdown-widget
v-if="epicFeatureAvailable && !isIncidentSidebar"
- :key="`epic-${activeBoardItem.iid}`"
+ :key="`epic-${activeBoardIssuable.iid}`"
:iid="activeBoardIssuable.iid"
issuable-attribute="epic"
:workspace-path="projectPathForActiveIssue"
@@ -242,7 +242,7 @@ export default {
/>
<div>
<sidebar-dropdown-widget
- :key="`milestone-${activeBoardItem.iid}`"
+ :key="`milestone-${activeBoardIssuable.iid}`"
:iid="activeBoardIssuable.iid"
issuable-attribute="milestone"
:workspace-path="projectPathForActiveIssue"
@@ -252,7 +252,7 @@ export default {
/>
<sidebar-iteration-widget
v-if="iterationFeatureAvailable && !isIncidentSidebar"
- :key="`iteration-${activeBoardItem.iid}`"
+ :key="`iteration-${activeBoardIssuable.iid}`"
:iid="activeBoardIssuable.iid"
:workspace-path="projectPathForActiveIssue"
:attr-workspace-path="groupPathForActiveIssue"
diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue
index 4986c3780e5..d12478b42d8 100644
--- a/app/assets/javascripts/boards/components/board_form.vue
+++ b/app/assets/javascripts/boards/components/board_form.vue
@@ -178,6 +178,9 @@ export default {
},
methods: {
...mapActions(['setError', 'unsetError', 'setBoard']),
+ isFocusMode() {
+ return Boolean(document.querySelector('.content-wrapper > .js-focus-mode-board.is-focused'));
+ },
cancel() {
this.$emit('cancel');
},
@@ -281,6 +284,7 @@ export default {
modal-class="board-config-modal"
content-class="gl-absolute gl-top-7"
visible
+ :static="isFocusMode()"
:hide-footer="readonly"
:title="title"
:action-primary="primaryProps"
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index 67bfcfb9d97..1bb7e88122a 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -88,6 +88,7 @@ export default {
toListId: null,
toList: {},
addItemToListInProgress: false,
+ updateIssueOrderInProgress: false,
};
},
apollo: {
@@ -253,7 +254,9 @@ export default {
return this.canMoveIssue ? options : {};
},
disableScrollingWhenMutationInProgress() {
- return this.hasNextPage && this.isUpdateIssueOrderInProgress;
+ return (
+ this.hasNextPage && (this.isUpdateIssueOrderInProgress || this.updateIssueOrderInProgress)
+ );
},
showMoveToPosition() {
return !this.disabled && this.list.listType !== ListType.closed;
@@ -343,7 +346,7 @@ export default {
sortableStart();
this.track('drag_card', { label: 'board' });
},
- handleDragOnEnd({
+ async handleDragOnEnd({
newIndex: originalNewIndex,
oldIndex,
from,
@@ -394,7 +397,8 @@ export default {
}
if (this.isApolloBoard) {
- this.moveBoardItem(
+ this.updateIssueOrderInProgress = true;
+ await this.moveBoardItem(
{
epicId: itemId,
iid: itemIid,
@@ -404,7 +408,9 @@ export default {
moveAfterId,
},
newIndex,
- );
+ ).finally(() => {
+ this.updateIssueOrderInProgress = false;
+ });
} else {
this.moveItem({
itemId,
diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue
index 068db98a750..42c30dc8245 100644
--- a/app/assets/javascripts/boards/components/board_list_header.vue
+++ b/app/assets/javascripts/boards/components/board_list_header.vue
@@ -490,7 +490,11 @@ export default {
>
<span class="gl-display-inline-flex" :class="{ 'gl-rotate-90': list.collapsed }">
<gl-tooltip :target="() => $refs.itemCount" :title="itemsTooltipLabel" />
- <span ref="itemCount" class="gl-display-inline-flex gl-align-items-center">
+ <span
+ ref="itemCount"
+ class="gl-display-inline-flex gl-align-items-center"
+ data-testid="item-count"
+ >
<gl-icon class="gl-mr-2" :name="countIcon" :size="14" />
<item-count
v-if="!isLoading"
diff --git a/app/assets/javascripts/boards/components/board_settings_sidebar.vue b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
index 58db2c9ac2a..89e13625210 100644
--- a/app/assets/javascripts/boards/components/board_settings_sidebar.vue
+++ b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
@@ -166,7 +166,7 @@ export default {
<mounting-portal mount-to="#js-right-sidebar-portal" name="board-settings-sidebar" append>
<gl-drawer
v-bind="$attrs"
- class="js-board-settings-sidebar gl-absolute boards-sidebar"
+ class="js-board-settings-sidebar boards-sidebar"
:open="showSidebar"
variant="sidebar"
@close="unsetActiveListId"
diff --git a/app/assets/javascripts/boards/components/board_top_bar.vue b/app/assets/javascripts/boards/components/board_top_bar.vue
index 2b8418333a8..7fd1a934381 100644
--- a/app/assets/javascripts/boards/components/board_top_bar.vue
+++ b/app/assets/javascripts/boards/components/board_top_bar.vue
@@ -93,6 +93,9 @@ export default {
});
return hasScope;
},
+ isLoading() {
+ return this.$apollo.queries.board.loading;
+ },
},
};
</script>
@@ -105,7 +108,11 @@ export default {
<div
class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-flex-grow-1 gl-lg-mb-0 gl-mb-3 gl-w-full gl-min-w-0"
>
- <boards-selector :board-apollo="board" @switchBoard="$emit('switchBoard', $event)" />
+ <boards-selector
+ :board-apollo="board"
+ :is-current-board-loading="isLoading"
+ @switchBoard="$emit('switchBoard', $event)"
+ />
<new-board-button />
<issue-board-filtered-search
v-if="isIssueBoard"
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index b3fe52944dc..cc6fde92f9b 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -70,6 +70,11 @@ export default {
required: false,
default: () => ({}),
},
+ isCurrentBoardLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -92,6 +97,9 @@ export default {
boardToUse() {
return this.isApolloBoard ? this.boardApollo : this.board;
},
+ isBoardToUseLoading() {
+ return this.isApolloBoard ? this.isCurrentBoardLoading : this.isBoardLoading;
+ },
parentType() {
return this.boardType;
},
@@ -301,7 +309,7 @@ export default {
data-qa-selector="boards_dropdown"
toggle-class="dropdown-menu-toggle"
menu-class="flex-column dropdown-extended-height"
- :loading="isBoardLoading"
+ :loading="isBoardToUseLoading"
:text="boardToUse.name"
@show="loadBoards"
>
diff --git a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
index f60f00be368..a7b3f5536a4 100644
--- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
@@ -62,7 +62,7 @@ export default {
tokensCE() {
const { issue, incident } = this.$options.i18n;
const { types } = this.$options;
- const { fetchUsers, fetchLabels, fetchMilestones } = issueBoardFilters(
+ const { fetchUsers, fetchLabels } = issueBoardFilters(
this.$apollo,
this.fullPath,
this.isGroupBoard,
@@ -148,7 +148,8 @@ export default {
token: MilestoneToken,
unique: true,
shouldSkipSort: true,
- fetchMilestones,
+ isProject: !this.isGroupBoard,
+ fullPath: this.fullPath,
},
{
icon: 'issues',
diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue
index 1f28974afd1..46009df2bd3 100644
--- a/app/assets/javascripts/boards/components/issue_due_date.vue
+++ b/app/assets/javascripts/boards/components/issue_due_date.vue
@@ -52,11 +52,14 @@ export default {
if (timeDifference === 0) {
return __('Today');
- } else if (timeDifference === 1) {
+ }
+ if (timeDifference === 1) {
return __('Tomorrow');
- } else if (timeDifference === -1) {
+ }
+ if (timeDifference === -1) {
return __('Yesterday');
- } else if (timeDifference > 0 && timeDifference < 7) {
+ }
+ if (timeDifference > 0 && timeDifference < 7) {
return dateFormat(issueDueDate, 'dddd');
}
diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue
index 1c2c0022ddf..a2c4b42b6c5 100644
--- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue
+++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue
@@ -7,6 +7,7 @@ import { joinPaths } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import { titleQueries } from 'ee_else_ce/boards/constants';
+import { setError } from '../../graphql/cache_updates';
export default {
components: {
@@ -65,7 +66,7 @@ export default {
},
},
methods: {
- ...mapActions(['setActiveItemTitle', 'setError']),
+ ...mapActions(['setActiveItemTitle']),
getPendingChangesKey(item) {
if (!item) {
return '';
@@ -130,7 +131,7 @@ export default {
this.showChangesAlert = false;
} catch (e) {
this.title = this.item.title;
- this.setError({ error: e, message: this.$options.i18n.updateTitleError });
+ setError({ error: e, message: this.$options.i18n.updateTitleError });
} finally {
this.loading = false;
}
diff --git a/app/assets/javascripts/boards/graphql/cache_updates.js b/app/assets/javascripts/boards/graphql/cache_updates.js
index e54701a63c0..3551c3ed982 100644
--- a/app/assets/javascripts/boards/graphql/cache_updates.js
+++ b/app/assets/javascripts/boards/graphql/cache_updates.js
@@ -109,9 +109,9 @@ export function updateEpicsCount({
epicBoardList: {
...epicBoardList,
metadata: {
+ ...epicBoardList.metadata,
epicsCount: epicBoardList.metadata.epicsCount - 1,
totalWeight: epicBoardList.metadata.totalWeight - epicWeight,
- ...epicBoardList.metadata,
},
},
}),
@@ -127,9 +127,9 @@ export function updateEpicsCount({
epicBoardList: {
...epicBoardList,
metadata: {
+ ...epicBoardList.metadata,
epicsCount: epicBoardList.metadata.epicsCount + 1,
totalWeight: epicBoardList.metadata.totalWeight + epicWeight,
- ...epicBoardList.metadata,
},
},
}),
diff --git a/app/assets/javascripts/boards/graphql/group_board_members.query.graphql b/app/assets/javascripts/boards/graphql/group_board_members.query.graphql
deleted file mode 100644
index 252e8c1ab06..00000000000
--- a/app/assets/javascripts/boards/graphql/group_board_members.query.graphql
+++ /dev/null
@@ -1,15 +0,0 @@
-#import "~/graphql_shared/fragments/user.fragment.graphql"
-
-query GroupBoardMembers($fullPath: ID!, $search: String) {
- workspace: group(fullPath: $fullPath) {
- id
- assignees: groupMembers(search: $search, relations: [DIRECT, DESCENDANTS, INHERITED]) {
- nodes {
- id
- user {
- ...User
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/boards/graphql/project_board_members.query.graphql b/app/assets/javascripts/boards/graphql/project_board_members.query.graphql
deleted file mode 100644
index 5279680b03c..00000000000
--- a/app/assets/javascripts/boards/graphql/project_board_members.query.graphql
+++ /dev/null
@@ -1,15 +0,0 @@
-#import "~/graphql_shared/fragments/user.fragment.graphql"
-
-query ProjectBoardMembers($fullPath: ID!, $search: String) {
- workspace: project(fullPath: $fullPath) {
- id
- assignees: projectMembers(search: $search) {
- nodes {
- id
- user {
- ...User
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index a03ec9193ea..9d7b7a38c6d 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -102,6 +102,7 @@ function mountBoardApp(el) {
swimlanesFeatureAvailable: gon.licensed_features?.swimlanes,
multipleIssueBoardsAvailable: parseBoolean(el.dataset.multipleBoardsAvailable),
scopedIssueBoardFeatureEnabled: parseBoolean(el.dataset.scopedIssueBoardFeatureEnabled),
+ allowSubEpics: false,
},
render: (createComponent) => createComponent(BoardApp),
});
diff --git a/app/assets/javascripts/boards/issue_board_filters.js b/app/assets/javascripts/boards/issue_board_filters.js
index 27efb3f775c..ba5da70c6ec 100644
--- a/app/assets/javascripts/boards/issue_board_filters.js
+++ b/app/assets/javascripts/boards/issue_board_filters.js
@@ -1,7 +1,5 @@
-import groupBoardMembers from '~/boards/graphql/group_board_members.query.graphql';
-import projectBoardMembers from '~/boards/graphql/project_board_members.query.graphql';
-import groupBoardMilestonesQuery from './graphql/group_board_milestones.query.graphql';
-import projectBoardMilestonesQuery from './graphql/project_board_milestones.query.graphql';
+import { BoardType } from 'ee_else_ce/boards/constants';
+import usersAutocompleteQuery from '~/graphql_shared/queries/users_autocomplete.query.graphql';
import boardLabels from './graphql/board_labels.query.graphql';
export default function issueBoardFilters(apollo, fullPath, isGroupBoard) {
@@ -9,20 +7,15 @@ export default function issueBoardFilters(apollo, fullPath, isGroupBoard) {
return isGroupBoard ? data.group?.labels.nodes || [] : data.project?.labels.nodes || [];
};
- const boardAssigneesQuery = () => {
- return isGroupBoard ? groupBoardMembers : projectBoardMembers;
- };
-
const fetchUsers = (usersSearchTerm) => {
+ const namespace = isGroupBoard ? BoardType.group : BoardType.project;
+
return apollo
.query({
- query: boardAssigneesQuery(),
- variables: {
- fullPath,
- search: usersSearchTerm,
- },
+ query: usersAutocompleteQuery,
+ variables: { fullPath, search: usersSearchTerm, isProject: !isGroupBoard },
})
- .then(({ data }) => data.workspace?.assignees.nodes.map(({ user }) => user));
+ .then(({ data }) => data[namespace]?.autocompleteUsers);
};
const fetchLabels = (labelSearchTerm) => {
@@ -39,27 +32,8 @@ export default function issueBoardFilters(apollo, fullPath, isGroupBoard) {
.then(transformLabels);
};
- const fetchMilestones = (searchTerm) => {
- const variables = {
- fullPath,
- searchTerm,
- };
-
- const query = isGroupBoard ? groupBoardMilestonesQuery : projectBoardMilestonesQuery;
-
- return apollo
- .query({
- query,
- variables,
- })
- .then(({ data }) => {
- return data.workspace?.milestones.nodes;
- });
- };
-
return {
fetchLabels,
fetchUsers,
- fetchMilestones,
};
}
diff --git a/app/assets/javascripts/ci/admin/jobs_table/admin_jobs_table_app.vue b/app/assets/javascripts/ci/admin/jobs_table/admin_jobs_table_app.vue
new file mode 100644
index 00000000000..89582e64f3a
--- /dev/null
+++ b/app/assets/javascripts/ci/admin/jobs_table/admin_jobs_table_app.vue
@@ -0,0 +1,271 @@
+<script>
+import { GlAlert, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
+import { setUrlParams, updateHistory, queryToObject } from '~/lib/utils/url_utility';
+import { validateQueryString } from '~/ci/common/private/jobs_filtered_search/utils';
+import JobsTable from '~/ci/jobs_page/components/jobs_table.vue';
+import JobsTableTabs from '~/ci/jobs_page/components/jobs_table_tabs.vue';
+import JobsFilteredSearch from '~/ci/common/private/jobs_filtered_search/app.vue';
+import JobsTableEmptyState from '~/ci/jobs_page/components/jobs_table_empty_state.vue';
+import { createAlert } from '~/alert';
+import {
+ TOKEN_TYPE_STATUS,
+ TOKEN_TYPE_JOBS_RUNNER_TYPE,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import {
+ DEFAULT_FIELDS_ADMIN,
+ RAW_TEXT_WARNING_ADMIN,
+ JOBS_COUNT_ERROR_MESSAGE,
+ JOBS_FETCH_ERROR_MSG,
+ LOADING_ARIA_LABEL,
+ CANCELABLE_JOBS_ERROR_MSG,
+} from './constants';
+import JobsSkeletonLoader from './components/jobs_skeleton_loader.vue';
+import GetAllJobs from './graphql/queries/get_all_jobs.query.graphql';
+import GetAllJobsCount from './graphql/queries/get_all_jobs_count.query.graphql';
+import getCancelableJobs from './graphql/queries/get_cancelable_jobs_count.query.graphql';
+
+export default {
+ i18n: {
+ jobsCountErrorMsg: JOBS_COUNT_ERROR_MESSAGE,
+ jobsFetchErrorMsg: JOBS_FETCH_ERROR_MSG,
+ loadingAriaLabel: LOADING_ARIA_LABEL,
+ cancelableJobsErrorMsg: CANCELABLE_JOBS_ERROR_MSG,
+ },
+ filterSearchBoxStyles:
+ 'gl-my-0 gl-p-5 gl-bg-gray-10 gl-text-gray-900 gl-border-b gl-border-gray-100',
+ components: {
+ JobsSkeletonLoader,
+ JobsTableEmptyState,
+ GlAlert,
+ JobsFilteredSearch,
+ JobsTable,
+ JobsTableTabs,
+ GlIntersectionObserver,
+ GlLoadingIcon,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ inject: {
+ jobStatuses: {
+ default: null,
+ required: false,
+ },
+ url: {
+ default: '',
+ required: false,
+ },
+ emptyStateSvgPath: {
+ default: '',
+ required: false,
+ },
+ },
+ apollo: {
+ jobs: {
+ query: GetAllJobs,
+ variables() {
+ return this.variables;
+ },
+ update(data) {
+ const { jobs: { nodes: list = [], pageInfo = {} } = {} } = data || {};
+ return {
+ list,
+ pageInfo,
+ };
+ },
+ error() {
+ this.error = this.$options.i18n.jobsFetchErrorMsg;
+ },
+ },
+ jobsCount: {
+ query: GetAllJobsCount,
+ variables() {
+ return this.variables;
+ },
+ update(data) {
+ return data?.jobs?.count || 0;
+ },
+ context: {
+ isSingleRequest: true,
+ },
+ error() {
+ this.error = this.$options.i18n.jobsCountErrorMsg;
+ },
+ },
+ cancelable: {
+ query: getCancelableJobs,
+ update(data) {
+ this.isCancelable = data.cancelable.count !== 0;
+ },
+ error() {
+ this.error = this.$options.i18n.cancelableJobsErrorMsg;
+ },
+ },
+ },
+ data() {
+ return {
+ jobs: {
+ list: [],
+ },
+ error: '',
+ count: 0,
+ scope: null,
+ infiniteScrollingTriggered: false,
+ filterSearchTriggered: false,
+ DEFAULT_FIELDS_ADMIN,
+ isCancelable: false,
+ jobsCount: null,
+ };
+ },
+ computed: {
+ loading() {
+ return this.$apollo.queries.jobs.loading;
+ },
+ // Show when on All tab with no jobs
+ // Show only when not loading and filtered search has not been triggered
+ // So we don't show empty state when results are empty on a filtered search
+ showEmptyState() {
+ return (
+ this.jobs.list.length === 0 && !this.scope && !this.loading && !this.filterSearchTriggered
+ );
+ },
+ hasNextPage() {
+ return this.jobs?.pageInfo?.hasNextPage;
+ },
+ variables() {
+ return { ...this.validatedQueryString };
+ },
+ validatedQueryString() {
+ const queryStringObject = queryToObject(window.location.search);
+
+ return validateQueryString(queryStringObject);
+ },
+ showFilteredSearch() {
+ return !this.scope;
+ },
+ showLoadingSpinner() {
+ return this.loading && this.infiniteScrollingTriggered;
+ },
+ showSkeletonLoader() {
+ return this.loading && !this.showLoadingSpinner;
+ },
+ },
+ watch: {
+ // this watcher ensures that the count on the all tab
+ // is not updated when switching to the finished tab
+ jobsCount(newCount) {
+ if (this.scope) return;
+
+ this.count = newCount;
+ },
+ },
+ methods: {
+ updateHistoryAndFetchCount(filterParams = {}) {
+ this.$apollo.queries.jobsCount.refetch(filterParams);
+
+ updateHistory({
+ url: setUrlParams(filterParams, window.location.href, true),
+ });
+ },
+ fetchJobsByStatus(scope) {
+ this.infiniteScrollingTriggered = false;
+
+ if (this.scope === scope) return;
+
+ this.scope = scope;
+
+ if (!this.scope) this.updateHistoryAndFetchCount();
+
+ this.$apollo.queries.jobs.refetch({ statuses: scope });
+ },
+ fetchMoreJobs() {
+ if (!this.loading) {
+ this.infiniteScrollingTriggered = true;
+
+ const parameters = this.variables;
+ parameters.after = this.jobs?.pageInfo?.endCursor;
+
+ this.$apollo.queries.jobs.fetchMore({
+ variables: parameters,
+ });
+ }
+ },
+ filterJobsBySearch(filters) {
+ this.infiniteScrollingTriggered = false;
+ this.filterSearchTriggered = true;
+
+ if (filters.some((filter) => !filter.type)) {
+ // Raw text input in filtered search does not have a type
+ // when a user enters raw text we alert them that it is
+ // not supported and we do not make an additional API call
+ createAlert({ message: RAW_TEXT_WARNING_ADMIN, type: 'warning' });
+ return;
+ }
+
+ const defaultFilterParams = this.glFeatures.adminJobsFilterRunnerType
+ ? { statuses: null, runnerTypes: null }
+ : { statuses: null };
+
+ const filterParams = filters.reduce((acc, filter) => {
+ switch (filter.type) {
+ case TOKEN_TYPE_STATUS:
+ return { ...acc, statuses: filter.value.data };
+
+ case TOKEN_TYPE_JOBS_RUNNER_TYPE:
+ if (this.glFeatures.adminJobsFilterRunnerType) {
+ return { ...acc, runnerTypes: filter.value.data };
+ }
+ return acc;
+
+ default:
+ return acc;
+ }
+ }, defaultFilterParams);
+
+ this.updateHistoryAndFetchCount(filterParams);
+ this.$apollo.queries.jobs.refetch(filterParams);
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-alert v-if="error" class="gl-mt-2" variant="danger" dismissible @dismiss="error = ''">
+ {{ error }}
+ </gl-alert>
+
+ <jobs-table-tabs
+ :all-jobs-count="count"
+ :loading="loading"
+ :show-cancel-all-jobs-button="isCancelable"
+ @fetchJobsByStatus="fetchJobsByStatus"
+ />
+
+ <div v-if="showFilteredSearch" :class="$options.filterSearchBoxStyles">
+ <jobs-filtered-search
+ :query-string="validatedQueryString"
+ @filterJobsBySearch="filterJobsBySearch"
+ />
+ </div>
+
+ <jobs-skeleton-loader v-if="showSkeletonLoader" class="gl-mt-5" />
+
+ <jobs-table-empty-state v-else-if="showEmptyState" />
+
+ <jobs-table
+ v-else
+ :jobs="jobs.list"
+ :table-fields="DEFAULT_FIELDS_ADMIN"
+ admin
+ class="gl-table-no-top-border"
+ />
+
+ <gl-intersection-observer v-if="hasNextPage" @appear="fetchMoreJobs">
+ <gl-loading-icon
+ v-if="showLoadingSpinner"
+ size="lg"
+ :aria-label="$options.i18n.loadingAriaLabel"
+ />
+ </gl-intersection-observer>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/admin/jobs_table/components/cancel_jobs.vue b/app/assets/javascripts/ci/admin/jobs_table/components/cancel_jobs.vue
new file mode 100644
index 00000000000..fb13fd4b03e
--- /dev/null
+++ b/app/assets/javascripts/ci/admin/jobs_table/components/cancel_jobs.vue
@@ -0,0 +1,37 @@
+<script>
+import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
+import { CANCEL_JOBS_MODAL_ID, CANCEL_JOBS_BUTTON_TEXT, CANCEL_BUTTON_TOOLTIP } from '../constants';
+import CancelJobsModal from './cancel_jobs_modal.vue';
+
+export default {
+ name: 'CancelJobs',
+ components: {
+ GlButton,
+ CancelJobsModal,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ url: {
+ type: String,
+ required: true,
+ },
+ },
+ modalId: CANCEL_JOBS_MODAL_ID,
+ buttonText: CANCEL_JOBS_BUTTON_TEXT,
+ buttonTooltip: CANCEL_BUTTON_TOOLTIP,
+};
+</script>
+<template>
+ <div>
+ <gl-button
+ v-gl-modal="$options.modalId"
+ v-gl-tooltip="$options.buttonTooltip"
+ variant="danger"
+ >{{ $options.buttonText }}</gl-button
+ >
+ <cancel-jobs-modal :modal-id="$options.modalId" :url="url" @confirm="$emit('confirm')" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/admin/jobs_table/components/cancel_jobs_modal.vue b/app/assets/javascripts/ci/admin/jobs_table/components/cancel_jobs_modal.vue
new file mode 100644
index 00000000000..7c1cd75609a
--- /dev/null
+++ b/app/assets/javascripts/ci/admin/jobs_table/components/cancel_jobs_modal.vue
@@ -0,0 +1,66 @@
+<script>
+import { GlModal } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import {
+ CANCEL_TEXT,
+ CANCEL_JOBS_FAILED_TEXT,
+ CANCEL_JOBS_MODAL_TITLE,
+ CANCEL_JOBS_WARNING,
+ PRIMARY_ACTION_TEXT,
+} from '../constants';
+
+export default {
+ components: {
+ GlModal,
+ },
+ props: {
+ url: {
+ type: String,
+ required: true,
+ },
+ modalId: {
+ type: String,
+ required: true,
+ },
+ },
+ methods: {
+ onSubmit() {
+ return axios
+ .post(this.url)
+ .then((response) => {
+ // follow the rediect to refresh the page
+ redirectTo(response.request.responseURL); // eslint-disable-line import/no-deprecated
+ })
+ .catch((error) => {
+ createAlert({
+ message: CANCEL_JOBS_FAILED_TEXT,
+ });
+ throw error;
+ });
+ },
+ },
+ primaryAction: {
+ text: PRIMARY_ACTION_TEXT,
+ attributes: { variant: 'danger' },
+ },
+ cancelAction: {
+ text: CANCEL_TEXT,
+ },
+ CANCEL_JOBS_WARNING,
+ CANCEL_JOBS_MODAL_TITLE,
+};
+</script>
+
+<template>
+ <gl-modal
+ :modal-id="modalId"
+ :action-primary="$options.primaryAction"
+ :action-cancel="$options.cancelAction"
+ :title="$options.CANCEL_JOBS_MODAL_TITLE"
+ @primary="onSubmit"
+ >
+ {{ $options.CANCEL_JOBS_WARNING }}
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/components/table/cell/project_cell.vue b/app/assets/javascripts/ci/admin/jobs_table/components/cells/project_cell.vue
index cbb80a5175f..cbb80a5175f 100644
--- a/app/assets/javascripts/pages/admin/jobs/components/table/cell/project_cell.vue
+++ b/app/assets/javascripts/ci/admin/jobs_table/components/cells/project_cell.vue
diff --git a/app/assets/javascripts/ci/admin/jobs_table/components/cells/runner_cell.vue b/app/assets/javascripts/ci/admin/jobs_table/components/cells/runner_cell.vue
new file mode 100644
index 00000000000..a76829aa129
--- /dev/null
+++ b/app/assets/javascripts/ci/admin/jobs_table/components/cells/runner_cell.vue
@@ -0,0 +1,39 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+import { RUNNER_EMPTY_TEXT, RUNNER_NO_DESCRIPTION } from '../../constants';
+
+export default {
+ i18n: {
+ emptyRunnerText: RUNNER_EMPTY_TEXT,
+ noRunnerDescription: RUNNER_NO_DESCRIPTION,
+ },
+ components: {
+ GlLink,
+ },
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ adminUrl() {
+ return this.job.runner?.adminUrl;
+ },
+ description() {
+ return this.job.runner?.description
+ ? this.job.runner.description
+ : this.$options.i18n.noRunnerDescription;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-text-truncate">
+ <gl-link v-if="adminUrl" :href="adminUrl">
+ {{ description }}
+ </gl-link>
+ <span v-else data-testid="empty-runner-text"> {{ $options.i18n.emptyRunnerText }}</span>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/components/jobs_skeleton_loader.vue b/app/assets/javascripts/ci/admin/jobs_table/components/jobs_skeleton_loader.vue
index c305e09af0d..c305e09af0d 100644
--- a/app/assets/javascripts/pages/admin/jobs/components/jobs_skeleton_loader.vue
+++ b/app/assets/javascripts/ci/admin/jobs_table/components/jobs_skeleton_loader.vue
diff --git a/app/assets/javascripts/ci/admin/jobs_table/constants.js b/app/assets/javascripts/ci/admin/jobs_table/constants.js
new file mode 100644
index 00000000000..ff0efdb1f5b
--- /dev/null
+++ b/app/assets/javascripts/ci/admin/jobs_table/constants.js
@@ -0,0 +1,35 @@
+import { s__, __ } from '~/locale';
+import { RAW_TEXT_WARNING } from '~/ci/jobs_page/constants';
+
+export const JOBS_COUNT_ERROR_MESSAGE = __('There was an error fetching the number of jobs.');
+export const JOBS_FETCH_ERROR_MSG = __('There was an error fetching the jobs.');
+export const LOADING_ARIA_LABEL = __('Loading');
+export const CANCELABLE_JOBS_ERROR_MSG = __('There was an error fetching the cancelable jobs.');
+export const CANCEL_JOBS_MODAL_ID = 'cancel-jobs-modal';
+export const CANCEL_JOBS_MODAL_TITLE = s__('AdminArea|Are you sure?');
+export const CANCEL_JOBS_BUTTON_TEXT = s__('AdminArea|Cancel all jobs');
+export const CANCEL_BUTTON_TOOLTIP = s__('AdminArea|Cancel all running and pending jobs');
+export const CANCEL_TEXT = __('Cancel');
+export const CANCEL_JOBS_FAILED_TEXT = s__('AdminArea|Canceling jobs failed');
+export const PRIMARY_ACTION_TEXT = s__('AdminArea|Yes, proceed');
+export const CANCEL_JOBS_WARNING = s__(
+ "AdminArea|You're about to cancel all running and pending jobs across this instance. Do you want to proceed?",
+);
+export const RUNNER_EMPTY_TEXT = __('None');
+export const RUNNER_NO_DESCRIPTION = s__('Runners|No description');
+
+/* Admin Table constants */
+/* The field list is based on app/assets/javascripts/jobs/components/table/constants.js */
+export const DEFAULT_FIELDS_ADMIN = [
+ { key: 'status', label: __('Status'), columnClass: 'gl-w-15p' },
+ { key: 'job', label: __('Job'), columnClass: 'gl-w-20p' },
+ { key: 'project', label: __('Project'), columnClass: 'gl-w-20p' },
+ { key: 'runner', label: __('Runner'), columnClass: 'gl-w-15p' },
+ { key: 'pipeline', label: __('Pipeline'), columnClass: 'gl-w-10p' },
+ { key: 'stage', label: __('Stage'), columnClass: 'gl-w-10p' },
+ { key: 'name', label: __('Name'), columnClass: 'gl-w-15p' },
+ { key: 'duration', label: __('Duration'), columnClass: 'gl-w-15p' },
+ { key: 'actions', label: '', columnClass: 'gl-w-10p' },
+];
+
+export const RAW_TEXT_WARNING_ADMIN = RAW_TEXT_WARNING;
diff --git a/app/assets/javascripts/pages/admin/jobs/components/table/graphql/cache_config.js b/app/assets/javascripts/ci/admin/jobs_table/graphql/cache_config.js
index fd7ee2a6f8c..fd7ee2a6f8c 100644
--- a/app/assets/javascripts/pages/admin/jobs/components/table/graphql/cache_config.js
+++ b/app/assets/javascripts/ci/admin/jobs_table/graphql/cache_config.js
diff --git a/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_all_jobs.query.graphql b/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_all_jobs.query.graphql
new file mode 100644
index 00000000000..89fb1782e46
--- /dev/null
+++ b/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_all_jobs.query.graphql
@@ -0,0 +1,90 @@
+query getAllJobs(
+ $after: String
+ $first: Int = 50
+ $statuses: [CiJobStatus!]
+ $runnerTypes: [CiRunnerType!]
+) {
+ jobs(after: $after, first: $first, statuses: $statuses, runnerTypes: $runnerTypes) {
+ pageInfo {
+ endCursor
+ hasNextPage
+ hasPreviousPage
+ startCursor
+ }
+ nodes {
+ runner {
+ id
+ description
+ adminUrl
+ }
+ artifacts {
+ nodes {
+ id
+ downloadPath
+ fileType
+ }
+ }
+ allowFailure
+ status
+ scheduledAt
+ manualJob
+ triggered
+ createdByTag
+ detailedStatus {
+ id
+ detailsPath
+ group
+ icon
+ label
+ text
+ tooltip
+ action {
+ id
+ buttonTitle
+ icon
+ method
+ path
+ title
+ }
+ }
+ id
+ refName
+ refPath
+ tags
+ shortSha
+ commitPath
+ pipeline {
+ id
+ project {
+ id
+ fullPath
+ webUrl
+ }
+ path
+ user {
+ id
+ webPath
+ avatarUrl
+ }
+ }
+ stage {
+ id
+ name
+ }
+ name
+ duration
+ finishedAt
+ coverage
+ retryable
+ playable
+ cancelable
+ active
+ stuck
+ userPermissions {
+ readBuild
+ readJobArtifacts
+ updateBuild
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_all_jobs_count.query.graphql b/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_all_jobs_count.query.graphql
new file mode 100644
index 00000000000..bcb0123e9e3
--- /dev/null
+++ b/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_all_jobs_count.query.graphql
@@ -0,0 +1,5 @@
+query getAllJobsCount($statuses: [CiJobStatus!], $runnerTypes: [CiRunnerType!]) {
+ jobs(statuses: $statuses, runnerTypes: $runnerTypes) {
+ count
+ }
+}
diff --git a/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_cancelable_jobs_count.query.graphql b/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_cancelable_jobs_count.query.graphql
new file mode 100644
index 00000000000..9bf5e1449b7
--- /dev/null
+++ b/app/assets/javascripts/ci/admin/jobs_table/graphql/queries/get_cancelable_jobs_count.query.graphql
@@ -0,0 +1,5 @@
+query getCancelableJobsCount {
+ cancelable: jobs(statuses: [PENDING, RUNNING]) {
+ count
+ }
+}
diff --git a/app/assets/javascripts/ci/artifacts/components/feedback_banner.vue b/app/assets/javascripts/ci/artifacts/components/feedback_banner.vue
deleted file mode 100644
index d2c96b1a201..00000000000
--- a/app/assets/javascripts/ci/artifacts/components/feedback_banner.vue
+++ /dev/null
@@ -1,41 +0,0 @@
-<script>
-import { GlBanner } from '@gitlab/ui';
-import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
-import {
- I18N_FEEDBACK_BANNER_TITLE,
- I18N_FEEDBACK_BANNER_BODY,
- I18N_FEEDBACK_BANNER_BUTTON,
- FEEDBACK_URL,
-} from '../constants';
-
-export default {
- components: {
- GlBanner,
- UserCalloutDismisser,
- },
- inject: ['artifactsManagementFeedbackImagePath'],
- FEEDBACK_URL,
- i18n: {
- title: I18N_FEEDBACK_BANNER_TITLE,
- body: I18N_FEEDBACK_BANNER_BODY,
- button: I18N_FEEDBACK_BANNER_BUTTON,
- },
-};
-</script>
-<template>
- <user-callout-dismisser feature-name="artifacts_management_page_feedback_banner">
- <template #default="{ dismiss, shouldShowCallout }">
- <gl-banner
- v-if="shouldShowCallout"
- class="gl-mb-6"
- :title="$options.i18n.title"
- :button-text="$options.i18n.button"
- :button-link="$options.FEEDBACK_URL"
- :svg-path="artifactsManagementFeedbackImagePath"
- @close="dismiss"
- >
- <p>{{ $options.i18n.body }}</p>
- </gl-banner>
- </template>
- </user-callout-dismisser>
-</template>
diff --git a/app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue b/app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue
index 88334488fdd..e08470c62be 100644
--- a/app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue
+++ b/app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue
@@ -48,7 +48,6 @@ import JobCheckbox from './job_checkbox.vue';
import ArtifactsBulkDelete from './artifacts_bulk_delete.vue';
import BulkDeleteModal from './bulk_delete_modal.vue';
import ArtifactsTableRowDetails from './artifacts_table_row_details.vue';
-import FeedbackBanner from './feedback_banner.vue';
const INITIAL_PAGINATION_STATE = {
currentPage: INITIAL_CURRENT_PAGE,
@@ -76,7 +75,6 @@ export default {
ArtifactsBulkDelete,
BulkDeleteModal,
ArtifactsTableRowDetails,
- FeedbackBanner,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -374,7 +372,6 @@ export default {
</script>
<template>
<div>
- <feedback-banner />
<artifacts-bulk-delete
v-if="canBulkDestroyArtifacts"
:selected-artifacts="selectedArtifacts"
diff --git a/app/assets/javascripts/ci/artifacts/constants.js b/app/assets/javascripts/ci/artifacts/constants.js
index 2d89b6541f3..28c371cda1e 100644
--- a/app/assets/javascripts/ci/artifacts/constants.js
+++ b/app/assets/javascripts/ci/artifacts/constants.js
@@ -47,13 +47,6 @@ export const I18N_MODAL_BODY = s__(
export const I18N_MODAL_PRIMARY = s__('Artifacts|Delete artifact');
export const I18N_MODAL_CANCEL = __('Cancel');
-export const I18N_FEEDBACK_BANNER_TITLE = s__('Artifacts|Help us improve this page');
-export const I18N_FEEDBACK_BANNER_BODY = s__(
- 'Artifacts|We want you to be able to use this page to easily manage your CI/CD job artifacts. We are working to improve this experience and would appreciate any feedback you have about the improvements we are making.',
-);
-export const I18N_FEEDBACK_BANNER_BUTTON = s__('Artifacts|Take a quick survey');
-export const FEEDBACK_URL = 'https://gitlab.fra1.qualtrics.com/jfe/form/SV_cI9rAUI20Vo2St8';
-
export const SELECTED_ARTIFACTS_MAX_COUNT = 50;
export const I18N_BULK_DELETE_MAX_SELECTED = s__(
'Artifacts|Maximum selected artifacts limit reached',
diff --git a/app/assets/javascripts/ci/artifacts/index.js b/app/assets/javascripts/ci/artifacts/index.js
index 6e795fd9bd7..c6021eb056f 100644
--- a/app/assets/javascripts/ci/artifacts/index.js
+++ b/app/assets/javascripts/ci/artifacts/index.js
@@ -19,12 +19,7 @@ export const initArtifactsTable = () => {
return false;
}
- const {
- projectPath,
- projectId,
- canDestroyArtifacts,
- artifactsManagementFeedbackImagePath,
- } = el.dataset;
+ const { projectPath, projectId, canDestroyArtifacts } = el.dataset;
return new Vue({
el,
@@ -33,7 +28,6 @@ export const initArtifactsTable = () => {
projectPath,
projectId,
canDestroyArtifacts: parseBoolean(canDestroyArtifacts),
- artifactsManagementFeedbackImagePath,
},
render: (createElement) => createElement(App),
});
diff --git a/app/assets/javascripts/ci/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci/ci_variable_list/ci_variable_list.js
deleted file mode 100644
index 574a5e7fd99..00000000000
--- a/app/assets/javascripts/ci/ci_variable_list/ci_variable_list.js
+++ /dev/null
@@ -1,262 +0,0 @@
-import $ from 'jquery';
-import SecretValues from '~/behaviors/secret_values';
-import CreateItemDropdown from '~/create_item_dropdown';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import { s__ } from '~/locale';
-
-const ALL_ENVIRONMENTS_STRING = s__('CiVariable|All environments');
-
-function createEnvironmentItem(value) {
- return {
- title: value === '*' ? ALL_ENVIRONMENTS_STRING : value,
- id: value,
- text: value === '*' ? s__('CiVariable|* (All environments)') : value,
- };
-}
-
-export default class VariableList {
- constructor({ container, formField, maskableRegex }) {
- this.$container = $(container);
- this.formField = formField;
- this.maskableRegex = new RegExp(maskableRegex);
- this.environmentDropdownMap = new WeakMap();
-
- this.inputMap = {
- id: {
- selector: '.js-ci-variable-input-id',
- default: '',
- },
- variable_type: {
- selector: '.js-ci-variable-input-variable-type',
- default: 'env_var',
- },
- key: {
- selector: '.js-ci-variable-input-key',
- default: '',
- },
- secret_value: {
- selector: '.js-ci-variable-input-value',
- default: '',
- },
- protected: {
- selector: '.js-ci-variable-input-protected',
- // use `attr` instead of `data` as we don't want the value to be
- // converted. we need the value as a string.
- default: $('.js-ci-variable-input-protected').attr('data-default'),
- },
- masked: {
- selector: '.js-ci-variable-input-masked',
- // use `attr` instead of `data` as we don't want the value to be
- // converted. we need the value as a string.
- default: $('.js-ci-variable-input-masked').attr('data-default'),
- },
- environment_scope: {
- // We can't use a `.js-` class here because
- // deprecated_jquery_dropdown replaces the <input> and doesn't copy over the class
- // See https://gitlab.com/gitlab-org/gitlab-foss/issues/42458
- selector: `input[name="${this.formField}[variables_attributes][][environment_scope]"]`,
- default: '*',
- },
- _destroy: {
- selector: '.js-ci-variable-input-destroy',
- default: '',
- },
- };
-
- this.secretValues = new SecretValues({
- container: this.$container[0],
- valueSelector: '.js-row:not(:last-child) .js-secret-value',
- placeholderSelector: '.js-row:not(:last-child) .js-secret-value-placeholder',
- });
- }
-
- init() {
- this.bindEvents();
- this.secretValues.init();
- }
-
- bindEvents() {
- this.$container.find('.js-row').each((index, rowEl) => {
- this.initRow(rowEl);
- });
-
- this.$container.on('click', '.js-row-remove-button', (e) => {
- e.preventDefault();
- this.removeRow($(e.currentTarget).closest('.js-row'));
- });
-
- const inputSelector = Object.keys(this.inputMap)
- .map((name) => this.inputMap[name].selector)
- .join(',');
-
- // Remove any empty rows except the last row
- this.$container.on('blur', inputSelector, (e) => {
- const $row = $(e.currentTarget).closest('.js-row');
-
- if ($row.is(':not(:last-child)') && !this.checkIfRowTouched($row)) {
- this.removeRow($row);
- }
- });
-
- this.$container.on('input trigger-change', inputSelector, (e) => {
- // Always make sure there is an empty last row
- const $lastRow = this.$container.find('.js-row').last();
-
- if (this.checkIfRowTouched($lastRow)) {
- this.insertRow($lastRow);
- }
-
- // If masked, validate value against regex
- this.validateMaskability($(e.currentTarget).closest('.js-row'));
- });
- }
-
- initRow(rowEl) {
- const $row = $(rowEl);
-
- // Reset the resizable textarea
- $row.find(this.inputMap.secret_value.selector).css('height', '');
-
- const $environmentSelect = $row.find('.js-variable-environment-toggle');
- if ($environmentSelect.length) {
- const createItemDropdown = new CreateItemDropdown({
- $dropdown: $environmentSelect,
- defaultToggleLabel: ALL_ENVIRONMENTS_STRING,
- fieldName: `${this.formField}[variables_attributes][][environment_scope]`,
- getData: (term, callback) => callback(this.getEnvironmentValues()),
- createNewItemFromValue: createEnvironmentItem,
- onSelect: () => {
- // Refresh the other dropdowns in the variable list
- // so they have the new value we just picked
- this.refreshDropdownData();
-
- $row.find(this.inputMap.environment_scope.selector).trigger('trigger-change');
- },
- });
-
- // Clear out any data that might have been left-over from the row clone
- createItemDropdown.clearDropdown();
-
- this.environmentDropdownMap.set($row[0], createItemDropdown);
- }
- }
-
- insertRow($row) {
- const $rowClone = $row.clone();
- $rowClone.removeAttr('data-is-persisted');
-
- // Reset the inputs to their defaults
- Object.keys(this.inputMap).forEach((name) => {
- const entry = this.inputMap[name];
- $rowClone.find(entry.selector).val(entry.default);
- });
-
- // Close any dropdowns
- $rowClone.find('.dropdown-menu.show').each((index, $dropdown) => {
- $dropdown.classList.remove('show');
- });
-
- this.initRow($rowClone);
-
- $row.after($rowClone);
- }
-
- removeRow(row) {
- const $row = $(row);
- const isPersisted = parseBoolean($row.attr('data-is-persisted'));
-
- if (isPersisted) {
- $row.hide();
- $row
- // eslint-disable-next-line no-underscore-dangle
- .find(this.inputMap._destroy.selector)
- .val(true);
- } else {
- $row.remove();
- }
-
- // Refresh the other dropdowns in the variable list
- // so any value with the variable deleted is gone
- this.refreshDropdownData();
- }
-
- checkIfRowTouched($row) {
- return Object.keys(this.inputMap).some((name) => {
- // Row should not qualify as touched if only switches have been touched
- if (['protected', 'masked'].includes(name)) return false;
-
- const entry = this.inputMap[name];
- const $el = $row.find(entry.selector);
- return $el.length && $el.val() !== entry.default;
- });
- }
-
- validateMaskability($row) {
- const invalidInputClass = 'gl-field-error-outline';
-
- const variableValue = $row.find(this.inputMap.secret_value.selector).val();
- const isValueMaskable = this.maskableRegex.test(variableValue) || variableValue === '';
- const isMaskedChecked = $row.find(this.inputMap.masked.selector).val() === 'true';
-
- // Show a validation error if the user wants to mask an unmaskable variable value
- $row
- .find(this.inputMap.secret_value.selector)
- .toggleClass(invalidInputClass, isMaskedChecked && !isValueMaskable);
- $row
- .find('.js-secret-value-placeholder')
- .toggleClass(invalidInputClass, isMaskedChecked && !isValueMaskable);
- $row.find('.masking-validation-error').toggle(isMaskedChecked && !isValueMaskable);
- }
-
- toggleEnableRow(isEnabled = true) {
- this.$container.find(this.inputMap.key.selector).attr('disabled', !isEnabled);
- this.$container.find('.js-row-remove-button').attr('disabled', !isEnabled);
- }
-
- hideValues() {
- this.secretValues.updateDom(false);
- }
-
- getAllData() {
- // Ignore the last empty row because we don't want to try persist
- // a blank variable and run into validation problems.
- const validRows = this.$container.find('.js-row').toArray().slice(0, -1);
-
- return validRows.map((rowEl) => {
- const resultant = {};
- Object.keys(this.inputMap).forEach((name) => {
- const entry = this.inputMap[name];
- const $input = $(rowEl).find(entry.selector);
- if ($input.length) {
- resultant[name] = $input.val();
- }
- });
-
- return resultant;
- });
- }
-
- getEnvironmentValues() {
- const valueMap = this.$container
- .find(this.inputMap.environment_scope.selector)
- .toArray()
- .reduce(
- (prevValueMap, envInput) => ({
- ...prevValueMap,
- [envInput.value]: envInput.value,
- }),
- {},
- );
-
- return Object.keys(valueMap).map(createEnvironmentItem);
- }
-
- refreshDropdownData() {
- this.$container.find('.js-row').each((index, rowEl) => {
- const environmentDropdown = this.environmentDropdownMap.get(rowEl);
- if (environmentDropdown) {
- environmentDropdown.refreshData();
- }
- });
- }
-}
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue
index 0ce11da658c..c609e05bbb7 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue
@@ -1,10 +1,12 @@
<script>
import {
+ GlAlert,
GlButton,
GlDrawer,
GlFormCheckbox,
GlFormCombobox,
GlFormGroup,
+ GlFormInput,
GlFormSelect,
GlFormTextarea,
GlIcon,
@@ -15,9 +17,14 @@ import { __, s__ } from '~/locale';
import { DRAWER_Z_INDEX } from '~/lib/utils/constants';
import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
import { helpPagePath } from '~/helpers/help_page_helper';
+import Tracking from '~/tracking';
import {
+ allEnvironments,
defaultVariableState,
+ DRAWER_EVENT_LABEL,
+ EDIT_VARIABLE_ACTION,
ENVIRONMENT_SCOPE_LINK_TITLE,
+ EVENT_ACTION,
EXPANDED_VARIABLES_NOTE,
FLAG_LINK_TITLE,
VARIABLE_ACTIONS,
@@ -26,9 +33,13 @@ import {
import CiEnvironmentsDropdown from './ci_environments_dropdown.vue';
import { awsTokenList } from './ci_variable_autocomplete_tokens';
-const i18n = {
+const trackingMixin = Tracking.mixin({ label: DRAWER_EVENT_LABEL });
+
+export const i18n = {
addVariable: s__('CiVariables|Add Variable'),
cancel: __('Cancel'),
+ defaultScope: allEnvironments.text,
+ editVariable: s__('CiVariables|Edit Variable'),
environments: __('Environments'),
environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE,
expandedField: s__('CiVariables|Expand variable reference'),
@@ -44,39 +55,60 @@ const i18n = {
protectedDescription: s__(
'CiVariables|Export variable to pipelines running on protected branches and tags only.',
),
+ valueFeedback: {
+ rawHelpText: s__('CiVariables|Variable value will be evaluated as raw string.'),
+ maskedReqsNotMet: s__(
+ 'CiVariables|This variable value does not meet the masking requirements.',
+ ),
+ },
+ variableReferenceTitle: s__('CiVariables|Value might contain a variable reference'),
+ variableReferenceDescription: s__(
+ 'CiVariables|Unselect "Expand variable reference" if you want to use the variable value as a raw string.',
+ ),
type: __('Type'),
value: __('Value'),
};
+const VARIABLE_REFERENCE_REGEX = /\$/;
+
export default {
DRAWER_Z_INDEX,
components: {
CiEnvironmentsDropdown,
+ GlAlert,
GlButton,
GlDrawer,
GlFormCheckbox,
GlFormCombobox,
GlFormGroup,
+ GlFormInput,
GlFormSelect,
GlFormTextarea,
GlIcon,
GlLink,
GlSprintf,
},
- inject: ['environmentScopeLink'],
+ mixins: [trackingMixin],
+ inject: ['environmentScopeLink', 'isProtectedByDefault', 'maskableRawRegex', 'maskableRegex'],
props: {
areEnvironmentsLoading: {
type: Boolean,
required: true,
},
+ areScopedVariablesAvailable: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
environments: {
type: Array,
required: false,
default: () => [],
},
- hasEnvScopeQuery: {
+ hideEnvironmentScope: {
type: Boolean,
- required: true,
+ required: false,
+ default: false,
},
mode: {
type: String,
@@ -85,22 +117,107 @@ export default {
return VARIABLE_ACTIONS.includes(val);
},
},
+ selectedVariable: {
+ type: Object,
+ required: false,
+ default: () => {},
+ },
},
data() {
return {
- key: defaultVariableState.key,
- variableType: defaultVariableState.variableType,
+ variable: { ...defaultVariableState, ...this.selectedVariable },
+ trackedValidationErrorProperty: undefined,
};
},
computed: {
+ isValueMaskable() {
+ return this.variable.masked && !this.isValueMasked;
+ },
+ isValueMasked() {
+ const regex = RegExp(this.maskedRegexToUse);
+ return regex.test(this.variable.value);
+ },
+ canSubmit() {
+ return this.variable.key.length > 0 && this.isValueValid;
+ },
getDrawerHeaderHeight() {
return getContentWrapperHeight();
},
+ hasVariableReference() {
+ return this.isExpanded && VARIABLE_REFERENCE_REGEX.test(this.variable.value);
+ },
+ isExpanded() {
+ return !this.variable.raw;
+ },
+ isMaskedReqsMet() {
+ return !this.variable.masked || this.isValueMasked;
+ },
+ isValueEmpty() {
+ return this.variable.value === '';
+ },
+ isValueValid() {
+ return this.isValueEmpty || this.isMaskedReqsMet;
+ },
+ isEditing() {
+ return this.mode === EDIT_VARIABLE_ACTION;
+ },
+ maskedRegexToUse() {
+ return this.variable.raw ? this.maskableRawRegex : this.maskableRegex;
+ },
+ maskedReqsNotMetText() {
+ return !this.isMaskedReqsMet ? this.$options.i18n.valueFeedback.maskedReqsNotMet : '';
+ },
+ modalActionText() {
+ return this.isEditing ? this.$options.i18n.editVariable : this.$options.i18n.addVariable;
+ },
+ },
+ watch: {
+ variable: {
+ handler() {
+ this.trackVariableValidationErrors();
+ },
+ deep: true,
+ },
+ },
+ mounted() {
+ if (this.isProtectedByDefault && !this.isEditing) {
+ this.variable = { ...this.variable, protected: true };
+ }
},
methods: {
close() {
this.$emit('close-form');
},
+ getTrackingErrorProperty() {
+ if (this.isValueEmpty) {
+ return null;
+ }
+
+ let property;
+ if (this.isValueMaskable) {
+ const supportedChars = this.maskedRegexToUse.replace('^', '').replace(/{(\d,)}\$/, '');
+ const regex = new RegExp(supportedChars, 'g');
+ property = this.variable.value.replace(regex, '');
+ } else if (this.hasVariableReference) {
+ property = '$';
+ }
+
+ return property;
+ },
+ setRaw(expanded) {
+ this.variable = { ...this.variable, raw: !expanded };
+ },
+ submit() {
+ this.$emit(this.isEditing ? 'update-variable' : 'add-variable', this.variable);
+ this.close();
+ },
+ trackVariableValidationErrors() {
+ const property = this.getTrackingErrorProperty();
+ if (property && !this.trackedValidationErrorProperty) {
+ this.track(EVENT_ACTION, { property });
+ this.trackedValidationErrorProperty = property;
+ }
+ },
},
awsTokenList,
flagLink: helpPagePath('ci/variables/index', {
@@ -119,20 +236,25 @@ export default {
@close="close"
>
<template #title>
- <h2 class="gl-m-0">{{ $options.i18n.addVariable }}</h2>
+ <h2 class="gl-m-0">{{ modalActionText }}</h2>
</template>
<gl-form-group
:label="$options.i18n.type"
label-for="ci-variable-type"
- class="gl-border-none gl-mb-n5"
+ class="gl-border-none"
+ :class="{
+ 'gl-mb-n5': !hideEnvironmentScope,
+ 'gl-mb-n1': hideEnvironmentScope,
+ }"
>
<gl-form-select
id="ci-variable-type"
- v-model="variableType"
+ v-model="variable.variableType"
:options="$options.variableOptions"
/>
</gl-form-group>
<gl-form-group
+ v-if="!hideEnvironmentScope"
class="gl-border-none gl-mb-n5"
label-for="ci-variable-env"
data-testid="environment-scope"
@@ -154,11 +276,18 @@ export default {
</div>
</template>
<ci-environments-dropdown
+ v-if="areScopedVariablesAvailable"
class="gl-mb-5"
+ has-env-scope-query
:are-environments-loading="areEnvironmentsLoading"
:environments="environments"
- :has-env-scope-query="hasEnvScopeQuery"
- selected-environment-scope=""
+ :selected-environment-scope="variable.environmentScope"
+ />
+ <gl-form-input
+ v-else
+ :value="$options.i18n.defaultScope"
+ class="gl-w-full gl-mb-5"
+ readonly
/>
</gl-form-group>
<gl-form-group class="gl-border-none gl-mb-n8">
@@ -177,17 +306,21 @@ export default {
</gl-link>
</div>
</template>
- <gl-form-checkbox data-testid="ci-variable-protected-checkbox">
+ <gl-form-checkbox v-model="variable.protected" data-testid="ci-variable-protected-checkbox">
{{ $options.i18n.protectedField }}
<p class="gl-text-secondary">
{{ $options.i18n.protectedDescription }}
</p>
</gl-form-checkbox>
- <gl-form-checkbox data-testid="ci-variable-masked-checkbox">
+ <gl-form-checkbox v-model="variable.masked" data-testid="ci-variable-masked-checkbox">
{{ $options.i18n.maskedField }}
<p class="gl-text-secondary">{{ $options.i18n.maskedDescription }}</p>
</gl-form-checkbox>
- <gl-form-checkbox data-testid="ci-variable-expanded-checkbox">
+ <gl-form-checkbox
+ data-testid="ci-variable-expanded-checkbox"
+ :checked="isExpanded"
+ @change="setRaw"
+ >
{{ $options.i18n.expandedField }}
<p class="gl-text-secondary">
<gl-sprintf :message="$options.i18n.expandedDescription" class="gl-text-secondary">
@@ -199,34 +332,56 @@ export default {
</gl-form-checkbox>
</gl-form-group>
<gl-form-combobox
- v-model="key"
+ v-model="variable.key"
:token-list="$options.awsTokenList"
:label-text="$options.i18n.key"
class="gl-border-none gl-pb-0! gl-mb-n5"
- data-testid="pipeline-form-ci-variable-key"
+ data-testid="ci-variable-key"
data-qa-selector="ci_variable_key_field"
/>
<gl-form-group
:label="$options.i18n.value"
label-for="ci-variable-value"
class="gl-border-none gl-mb-n2"
+ data-testid="ci-variable-value-label"
+ :invalid-feedback="maskedReqsNotMetText"
+ :state="isValueValid"
>
<gl-form-textarea
id="ci-variable-value"
+ v-model="variable.value"
class="gl-border-none gl-font-monospace!"
rows="3"
max-rows="10"
- data-testid="pipeline-form-ci-variable-value"
+ data-testid="ci-variable-value"
data-qa-selector="ci_variable_value_field"
spellcheck="false"
/>
+ <p v-if="variable.raw" class="gl-mt-2 gl-mb-0 text-secondary" data-testid="raw-variable-tip">
+ {{ $options.i18n.valueFeedback.rawHelpText }}
+ </p>
</gl-form-group>
+ <gl-alert
+ v-if="hasVariableReference"
+ :title="$options.i18n.variableReferenceTitle"
+ :dismissible="false"
+ variant="warning"
+ class="gl-mx-4 gl-pl-9! gl-border-bottom-0"
+ data-testid="has-variable-reference-alert"
+ >
+ {{ $options.i18n.variableReferenceDescription }}
+ </gl-alert>
<div class="gl-display-flex gl-justify-content-end">
- <gl-button category="primary" class="gl-mr-3" data-testid="cancel-button" @click="close"
+ <gl-button category="secondary" class="gl-mr-3" data-testid="cancel-button" @click="close"
>{{ $options.i18n.cancel }}
</gl-button>
- <gl-button category="primary" variant="confirm" data-testid="confirm-button"
- >{{ $options.i18n.addVariable }}
+ <gl-button
+ category="primary"
+ variant="confirm"
+ :disabled="!canSubmit"
+ data-testid="ci-variable-confirm-btn"
+ @click="submit"
+ >{{ modalActionText }}
</gl-button>
</div>
</gl-drawer>
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue
index f4e1da9b34f..482f6da5617 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_settings.vue
@@ -139,7 +139,10 @@ export default {
<ci-variable-drawer
v-if="showDrawer"
:are-environments-loading="areEnvironmentsLoading"
- :has-env-scope-query="hasEnvScopeQuery"
+ :are-scoped-variables-available="areScopedVariablesAvailable"
+ :environments="environments"
+ :hide-environment-scope="hideEnvironmentScope"
+ :selected-variable="selectedVariable"
:mode="mode"
v-on="$listeners"
@close-form="closeForm"
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue
index 9786f25ed87..3d5ed327dc7 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_shared.vue
@@ -2,7 +2,8 @@
import { createAlert } from '~/alert';
import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { mapEnvironmentNames, reportMessageToSentry } from '../utils';
+import { reportMessageToSentry } from '~/ci/utils';
+import { mapEnvironmentNames } from '../utils';
import {
ADD_MUTATION_ACTION,
DELETE_MUTATION_ACTION,
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue
index a14cd1e387a..3d62313815c 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_variable_table.vue
@@ -32,24 +32,20 @@ export default {
label: s__('CiVariables|Key'),
tdClass: 'text-plain',
sortable: true,
+ thClass: 'gl-w-40p',
},
{
key: 'value',
label: s__('CiVariables|Value'),
},
{
- key: 'Attributes',
- label: s__('CiVariables|Attributes'),
- thClass: 'gl-w-40p',
- },
- {
key: 'environmentScope',
label: s__('CiVariables|Environments'),
},
{
key: 'actions',
label: __('Actions'),
- thClass: 'gl-text-right',
+ thClass: 'gl-text-right gl-w-15',
},
],
inheritedVarsFields: [
@@ -287,7 +283,7 @@ export default {
</template>
<template #cell(key)="{ item }">
<div
- class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
+ class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-md-justify-content-start gl-mr-n3"
>
<span
:id="`ci-variable-key-${item.id}`"
@@ -298,16 +294,28 @@ export default {
v-gl-tooltip
category="tertiary"
icon="copy-to-clipboard"
- class="gl-my-n3 gl-ml-2"
+ class="gl-my-n2 gl-ml-2"
+ size="small"
:title="__('Copy key')"
:data-clipboard-text="item.key"
:aria-label="__('Copy to clipboard')"
/>
</div>
+ <div data-testid="ci-variable-table-row-attributes" class="gl-mt-2">
+ <gl-badge
+ v-for="attribute in item.attributes"
+ :key="`${item.key}-${attribute}`"
+ class="gl-mr-2"
+ variant="info"
+ size="sm"
+ >
+ {{ attribute }}
+ </gl-badge>
+ </div>
</template>
<template v-if="!isInheritedGroupVars" #cell(value)="{ item }">
<div
- class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
+ class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-md-justify-content-start gl-mr-n3"
>
<span v-if="areValuesHidden" data-testid="hiddenValue">*****</span>
<span
@@ -321,29 +329,17 @@ export default {
v-gl-tooltip
category="tertiary"
icon="copy-to-clipboard"
- class="gl-my-n3 gl-ml-2"
+ class="gl-my-n2 gl-ml-2"
+ size="small"
:title="__('Copy value')"
:data-clipboard-text="item.value"
:aria-label="__('Copy to clipboard')"
/>
</div>
</template>
- <template #cell(attributes)="{ item }">
- <span data-testid="ci-variable-table-row-attributes">
- <gl-badge
- v-for="attribute in item.attributes"
- :key="`${item.key}-${attribute}`"
- class="gl-mr-2"
- variant="info"
- size="sm"
- >
- {{ attribute }}
- </gl-badge>
- </span>
- </template>
<template #cell(environmentScope)="{ item }">
<div
- class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
+ class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-md-justify-content-start gl-mr-n3"
>
<span
:id="`ci-variable-env-${item.id}`"
@@ -354,7 +350,8 @@ export default {
v-gl-tooltip
category="tertiary"
icon="copy-to-clipboard"
- class="gl-my-n3 gl-ml-2"
+ class="gl-my-n2 gl-ml-2"
+ size="small"
:title="__('Copy environment')"
:data-clipboard-text="convertEnvironmentScopeValue(item.environmentScope)"
:aria-label="__('Copy to clipboard')"
@@ -363,7 +360,7 @@ export default {
</template>
<template v-if="isInheritedGroupVars" #cell(group)="{ item }">
<div
- class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
+ class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-md-justify-content-start gl-mr-n3"
>
<gl-link
:id="`ci-variable-group-${item.id}`"
diff --git a/app/assets/javascripts/ci/ci_variable_list/constants.js b/app/assets/javascripts/ci/ci_variable_list/constants.js
index 825b39e0cf9..fc37b62299d 100644
--- a/app/assets/javascripts/ci/ci_variable_list/constants.js
+++ b/app/assets/javascripts/ci/ci_variable_list/constants.js
@@ -46,6 +46,7 @@ export const AWS_TIP_MESSAGE = s__(
);
export const EVENT_LABEL = 'ci_variable_modal';
+export const DRAWER_EVENT_LABEL = 'ci_variable_drawer';
export const EVENT_ACTION = 'validation_error';
// AWS TOKEN CONSTANTS
diff --git a/app/assets/javascripts/ci/ci_variable_list/native_form_variable_list.js b/app/assets/javascripts/ci/ci_variable_list/native_form_variable_list.js
deleted file mode 100644
index fdbefd8c313..00000000000
--- a/app/assets/javascripts/ci/ci_variable_list/native_form_variable_list.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import $ from 'jquery';
-import VariableList from './ci_variable_list';
-
-// Used for the variable list on scheduled pipeline edit page
-export default function setupNativeFormVariableList({ container, formField = 'variables' }) {
- const $container = $(container);
-
- const variableList = new VariableList({
- container: $container,
- formField,
- });
- variableList.init();
-
- // Clear out the names in the empty last row so it
- // doesn't get submitted and throw validation errors
- $container.closest('form').on('submit trigger-submit', () => {
- const $lastRow = $container.find('.js-row').last();
-
- const isTouched = variableList.checkIfRowTouched($lastRow);
- if (!isTouched) {
- $lastRow.find('input, textarea').attr('name', '');
- $lastRow.find('select').attr('name', '');
- }
- });
-}
diff --git a/app/assets/javascripts/ci/ci_variable_list/utils.js b/app/assets/javascripts/ci/ci_variable_list/utils.js
index eeca69274ce..1faa97a5f73 100644
--- a/app/assets/javascripts/ci/ci_variable_list/utils.js
+++ b/app/assets/javascripts/ci/ci_variable_list/utils.js
@@ -1,4 +1,3 @@
-import * as Sentry from '@sentry/browser';
import { uniq } from 'lodash';
import { allEnvironments } from './constants';
@@ -49,12 +48,3 @@ export const convertEnvironmentScope = (environmentScope = '') => {
export const mapEnvironmentNames = (nodes = []) => {
return nodes.map((env) => env.name);
};
-
-export const reportMessageToSentry = (component, message, context) => {
- Sentry.withScope((scope) => {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- scope.setContext('Vue data', context);
- scope.setTag('component', component);
- Sentry.captureMessage(message);
- });
-};
diff --git a/app/assets/javascripts/ci/common/pipelines_table.vue b/app/assets/javascripts/ci/common/pipelines_table.vue
new file mode 100644
index 00000000000..807128d2341
--- /dev/null
+++ b/app/assets/javascripts/ci/common/pipelines_table.vue
@@ -0,0 +1,240 @@
+<script>
+import { GlTableLite, GlTooltipDirective } from '@gitlab/ui';
+import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
+import { s__, __ } from '~/locale';
+import Tracking from '~/tracking';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+import { keepLatestDownstreamPipelines } from '~/ci/pipeline_details/utils/parsing_utils';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import PipelineFailedJobsWidget from '~/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue';
+import eventHub from '~/ci/event_hub';
+import PipelineOperations from '../pipelines_page/components/pipeline_operations.vue';
+import PipelineStopModal from '../pipelines_page/components/pipeline_stop_modal.vue';
+import PipelineTriggerer from '../pipelines_page/components/pipeline_triggerer.vue';
+import PipelineUrl from '../pipelines_page/components/pipeline_url.vue';
+import PipelinesStatusBadge from '../pipelines_page/components/pipelines_status_badge.vue';
+
+const HIDE_TD_ON_MOBILE = 'gl-display-none! gl-lg-display-table-cell!';
+const DEFAULT_TH_CLASSES =
+ 'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-100! gl-p-5! gl-border-b-1!';
+
+export default {
+ components: {
+ GlTableLite,
+ LegacyPipelineMiniGraph,
+ PipelineFailedJobsWidget,
+ PipelineOperations,
+ PipelinesStatusBadge,
+ PipelineStopModal,
+ PipelineTriggerer,
+ PipelineUrl,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [Tracking.mixin(), glFeatureFlagMixin()],
+ inject: {
+ withFailedJobsDetails: {
+ default: false,
+ },
+ },
+ props: {
+ pipelines: {
+ type: Array,
+ required: true,
+ },
+ pipelineScheduleUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ updateGraphDropdown: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ viewType: {
+ type: String,
+ required: true,
+ },
+ pipelineKeyOption: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ pipelineId: 0,
+ pipeline: {},
+ endpoint: '',
+ cancelingPipeline: null,
+ };
+ },
+ computed: {
+ showFailedJobsWidget() {
+ return this.glFeatures.ciJobFailuresInMr;
+ },
+ tableFields() {
+ return [
+ {
+ key: 'status',
+ label: s__('Pipeline|Status'),
+ thClass: DEFAULT_TH_CLASSES,
+ columnClass: 'gl-w-15p',
+ tdClass: this.tdClasses,
+ thAttr: { 'data-testid': 'status-th' },
+ },
+ {
+ key: 'pipeline',
+ label: __('Pipeline'),
+ thClass: DEFAULT_TH_CLASSES,
+ tdClass: `${this.tdClasses}`,
+ columnClass: 'gl-w-30p',
+ thAttr: { 'data-testid': 'pipeline-th' },
+ },
+ {
+ key: 'triggerer',
+ label: s__('Pipeline|Created by'),
+ thClass: DEFAULT_TH_CLASSES,
+ tdClass: `${this.tdClasses} ${HIDE_TD_ON_MOBILE}`,
+ columnClass: 'gl-w-15p',
+ thAttr: { 'data-testid': 'triggerer-th' },
+ },
+ {
+ key: 'stages',
+ label: s__('Pipeline|Stages'),
+ thClass: DEFAULT_TH_CLASSES,
+ tdClass: this.tdClasses,
+ columnClass: 'gl-w-quarter',
+ thAttr: { 'data-testid': 'stages-th' },
+ },
+ {
+ key: 'actions',
+ thClass: DEFAULT_TH_CLASSES,
+ tdClass: this.tdClasses,
+ columnClass: 'gl-w-20p',
+ thAttr: { 'data-testid': 'actions-th' },
+ },
+ ];
+ },
+ tdClasses() {
+ return this.withFailedJobsDetails ? 'gl-pb-0! gl-border-none!' : 'pl-p-5!';
+ },
+ pipelinesWithDetails() {
+ if (this.withFailedJobsDetails) {
+ return this.pipelines.map((p) => {
+ return { ...p, _showDetails: true };
+ });
+ }
+
+ return this.pipelines;
+ },
+ },
+ watch: {
+ pipelines() {
+ this.cancelingPipeline = null;
+ },
+ },
+ created() {
+ eventHub.$on('openConfirmationModal', this.setModalData);
+ },
+ beforeDestroy() {
+ eventHub.$off('openConfirmationModal', this.setModalData);
+ },
+ methods: {
+ getDownstreamPipelines(pipeline) {
+ const downstream = pipeline.triggered;
+ return keepLatestDownstreamPipelines(downstream);
+ },
+ getProjectPath(item) {
+ return cleanLeadingSeparator(item.project.full_path);
+ },
+ failedJobsCount(pipeline) {
+ return pipeline?.failed_builds?.length || 0;
+ },
+ setModalData(data) {
+ this.pipelineId = data.pipeline.id;
+ this.pipeline = data.pipeline;
+ this.endpoint = data.endpoint;
+ },
+ onSubmit() {
+ eventHub.$emit('postAction', this.endpoint);
+ this.cancelingPipeline = this.pipelineId;
+ },
+ trackPipelineMiniGraph() {
+ this.track('click_minigraph', { label: TRACKING_CATEGORIES.table });
+ },
+ },
+ TBODY_TR_ATTR: {
+ 'data-testid': 'pipeline-table-row',
+ 'data-qa-selector': 'pipeline_row_container',
+ },
+};
+</script>
+<template>
+ <div class="ci-table">
+ <gl-table-lite
+ :fields="tableFields"
+ :items="pipelinesWithDetails"
+ :tbody-tr-attr="$options.TBODY_TR_ATTR"
+ stacked="lg"
+ fixed
+ >
+ <template #head(actions)>
+ <span class="gl-display-block gl-lg-display-none!">{{ s__('Pipeline|Actions') }}</span>
+ <slot name="table-header-actions"></slot>
+ </template>
+
+ <template #table-colgroup="{ fields }">
+ <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
+ </template>
+
+ <template #cell(status)="{ item }">
+ <pipelines-status-badge :pipeline="item" :view-type="viewType" />
+ </template>
+
+ <template #cell(pipeline)="{ item }">
+ <pipeline-url
+ :pipeline="item"
+ :pipeline-schedule-url="pipelineScheduleUrl"
+ :pipeline-key="pipelineKeyOption.value"
+ ref-color="gl-text-black-normal"
+ />
+ </template>
+
+ <template #cell(triggerer)="{ item }">
+ <pipeline-triggerer :pipeline="item" />
+ </template>
+
+ <template #cell(stages)="{ item }">
+ <legacy-pipeline-mini-graph
+ :downstream-pipelines="getDownstreamPipelines(item)"
+ :pipeline-path="item.path"
+ :stages="item.details.stages"
+ :update-dropdown="updateGraphDropdown"
+ :upstream-pipeline="item.triggered_by"
+ @miniGraphStageClick="trackPipelineMiniGraph"
+ />
+ </template>
+
+ <template #cell(actions)="{ item }">
+ <pipeline-operations :pipeline="item" :canceling-pipeline="cancelingPipeline" />
+ </template>
+
+ <template #row-details="{ item }">
+ <pipeline-failed-jobs-widget
+ v-if="showFailedJobsWidget"
+ :failed-jobs-count="failedJobsCount(item)"
+ :is-pipeline-active="item.active"
+ :pipeline-iid="item.iid"
+ :pipeline-path="item.path"
+ :project-path="getProjectPath(item)"
+ class="gl-ml-n4 gl-mt-n3 gl-mb-n1"
+ />
+ </template>
+ </gl-table-lite>
+
+ <pipeline-stop-modal :pipeline="pipeline" @submit="onSubmit" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/common/private/job_action_component.vue b/app/assets/javascripts/ci/common/private/job_action_component.vue
new file mode 100644
index 00000000000..f649750ce8a
--- /dev/null
+++ b/app/assets/javascripts/ci/common/private/job_action_component.vue
@@ -0,0 +1,136 @@
+<script>
+import { GlTooltipDirective, GlButton, GlLoadingIcon, GlIcon } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
+import { dasherize } from '~/lib/utils/text_utility';
+import { __ } from '~/locale';
+import { reportToSentry } from '~/ci/utils';
+
+/**
+ * Renders either a cancel, retry or play icon button and handles the post request
+ *
+ * Used in:
+ * - mr widget mini pipeline graph: `mr_widget_pipeline.vue`
+ * - pipelines table
+ * - pipelines table in merge request page
+ * - pipelines table in commit page
+ * - pipelines detail page in big graph
+ */
+export default {
+ components: {
+ GlIcon,
+ GlButton,
+ GlLoadingIcon,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ tooltipText: {
+ type: String,
+ required: true,
+ },
+ link: {
+ type: String,
+ required: true,
+ },
+ actionIcon: {
+ type: String,
+ required: true,
+ },
+ withConfirmationModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ shouldTriggerClick: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ isDisabled: false,
+ isLoading: false,
+ };
+ },
+ computed: {
+ cssClass() {
+ const actionIconDash = dasherize(this.actionIcon);
+ return `${actionIconDash} js-icon-${actionIconDash}`;
+ },
+ },
+ watch: {
+ shouldTriggerClick(flag) {
+ if (flag && this.withConfirmationModal) {
+ this.executeAction();
+ this.$emit('actionButtonClicked');
+ }
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry('action_component', `error: ${err}, info: ${info}`);
+ },
+ methods: {
+ /**
+ * The request should not be handled here.
+ * However due to this component being used in several
+ * different apps it avoids repetition & complexity.
+ *
+ */
+ onClickAction() {
+ if (this.withConfirmationModal) {
+ this.$emit('showActionConfirmationModal');
+ } else {
+ this.executeAction();
+ }
+ },
+ executeAction() {
+ this.$root.$emit(BV_HIDE_TOOLTIP, `js-ci-action-${this.link}`);
+ this.isDisabled = true;
+ this.isLoading = true;
+
+ axios
+ .post(`${this.link}.json`)
+ .then(() => {
+ this.isLoading = false;
+
+ this.$emit('pipelineActionRequestComplete');
+ })
+ .catch((err) => {
+ this.isDisabled = false;
+ this.isLoading = false;
+
+ reportToSentry('action_component', err);
+
+ createAlert({
+ message: __('An error occurred while making the request.'),
+ });
+ });
+ },
+ },
+};
+</script>
+<template>
+ <gl-button
+ :id="`js-ci-action-${link}`"
+ ref="button"
+ :class="cssClass"
+ :disabled="isDisabled"
+ class="js-ci-action gl-ci-action-icon-container ci-action-icon-container ci-action-icon-wrapper gl-display-flex gl-align-items-center gl-justify-content-center"
+ data-testid="ci-action-component"
+ @click.stop="onClickAction"
+ >
+ <div
+ v-gl-tooltip.viewport
+ :title="tooltipText"
+ class="gl-display-flex gl-align-items-center gl-justify-content-center gl-h-full"
+ data-testid="ci-action-icon-tooltip-wrapper"
+ >
+ <gl-loading-icon v-if="isLoading" size="sm" class="js-action-icon-loading" />
+ <gl-icon v-else :name="actionIcon" class="gl-mr-0!" :aria-label="actionIcon" />
+ </div>
+ </gl-button>
+</template>
diff --git a/app/assets/javascripts/ci/common/private/job_links_layer.vue b/app/assets/javascripts/ci/common/private/job_links_layer.vue
new file mode 100644
index 00000000000..59260ca3f81
--- /dev/null
+++ b/app/assets/javascripts/ci/common/private/job_links_layer.vue
@@ -0,0 +1,75 @@
+<script>
+import { memoize } from 'lodash';
+import { reportToSentry } from '~/ci/utils';
+import { parseData } from '~/ci/pipeline_details/utils/parsing_utils';
+import LinksInner from '~/ci/pipeline_details/graph/components/links_inner.vue';
+
+const parseForLinksBare = (pipeline) => {
+ const arrayOfJobs = pipeline.flatMap(({ groups }) => groups);
+ return parseData(arrayOfJobs).links;
+};
+
+const parseForLinks = memoize(parseForLinksBare);
+
+export default {
+ name: 'LinksLayer',
+ components: {
+ LinksInner,
+ },
+ props: {
+ containerMeasurements: {
+ type: Object,
+ required: true,
+ },
+ pipelineData: {
+ type: Array,
+ required: true,
+ },
+ linksData: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ showLinks: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ },
+ computed: {
+ containerZero() {
+ return !this.containerMeasurements.width || !this.containerMeasurements.height;
+ },
+ getLinksData() {
+ if (this.linksData.length > 0) {
+ return this.linksData;
+ }
+
+ return parseForLinks(this.pipelineData);
+ },
+ showLinkedLayers() {
+ return this.showLinks && !this.containerZero;
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
+ },
+};
+</script>
+<template>
+ <links-inner
+ v-if="showLinkedLayers"
+ :container-measurements="containerMeasurements"
+ :links-data="getLinksData"
+ :pipeline-data="pipelineData"
+ v-bind="$attrs"
+ v-on="$listeners"
+ >
+ <slot></slot>
+ </links-inner>
+ <div v-else>
+ <div class="gl-display-flex gl-relative">
+ <slot></slot>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue b/app/assets/javascripts/ci/common/private/job_name_component.vue
index 1c7f5a7476d..1c7f5a7476d 100644
--- a/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue
+++ b/app/assets/javascripts/ci/common/private/job_name_component.vue
diff --git a/app/assets/javascripts/ci/common/private/jobs_filtered_search/app.vue b/app/assets/javascripts/ci/common/private/jobs_filtered_search/app.vue
new file mode 100644
index 00000000000..86ccdb2c87b
--- /dev/null
+++ b/app/assets/javascripts/ci/common/private/jobs_filtered_search/app.vue
@@ -0,0 +1,99 @@
+<script>
+import { GlFilteredSearch } from '@gitlab/ui';
+import {
+ OPERATOR_IS,
+ OPERATORS_IS,
+ TOKEN_TITLE_STATUS,
+ TOKEN_TYPE_STATUS,
+ TOKEN_TITLE_JOBS_RUNNER_TYPE,
+ TOKEN_TYPE_JOBS_RUNNER_TYPE,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import JobStatusToken from './tokens/job_status_token.vue';
+import JobRunnerTypeToken from './tokens/job_runner_type_token.vue';
+
+export default {
+ components: {
+ GlFilteredSearch,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ props: {
+ queryString: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ },
+ computed: {
+ tokens() {
+ const tokens = [
+ {
+ type: TOKEN_TYPE_STATUS,
+ icon: 'status',
+ title: TOKEN_TITLE_STATUS,
+ unique: true,
+ token: JobStatusToken,
+ operators: OPERATORS_IS,
+ },
+ ];
+
+ if (this.glFeatures.adminJobsFilterRunnerType) {
+ tokens.push({
+ type: TOKEN_TYPE_JOBS_RUNNER_TYPE,
+ title: TOKEN_TITLE_JOBS_RUNNER_TYPE,
+ unique: true,
+ token: JobRunnerTypeToken,
+ operators: OPERATORS_IS,
+ });
+ }
+
+ return tokens;
+ },
+ filteredSearchValue() {
+ return Object.entries(this.queryString || {}).reduce(
+ (acc, [queryStringKey, queryStringValue]) => {
+ switch (queryStringKey) {
+ case 'statuses':
+ return [
+ ...acc,
+ {
+ type: TOKEN_TYPE_STATUS,
+ value: { data: queryStringValue, operator: OPERATOR_IS },
+ },
+ ];
+ case 'runnerTypes':
+ if (!this.glFeatures.adminJobsFilterRunnerType) {
+ return acc;
+ }
+
+ return [
+ ...acc,
+ {
+ type: TOKEN_TYPE_JOBS_RUNNER_TYPE,
+ value: { data: queryStringValue, operator: OPERATOR_IS },
+ },
+ ];
+ default:
+ return acc;
+ }
+ },
+ [],
+ );
+ },
+ },
+ methods: {
+ onSubmit(filters) {
+ this.$emit('filterJobsBySearch', filters);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-filtered-search
+ :placeholder="s__('Jobs|Filter jobs')"
+ :available-tokens="tokens"
+ :value="filteredSearchValue"
+ @submit="onSubmit"
+ />
+</template>
diff --git a/app/assets/javascripts/ci/common/private/jobs_filtered_search/constants.js b/app/assets/javascripts/ci/common/private/jobs_filtered_search/constants.js
new file mode 100644
index 00000000000..86b8290864c
--- /dev/null
+++ b/app/assets/javascripts/ci/common/private/jobs_filtered_search/constants.js
@@ -0,0 +1,23 @@
+export const jobStatusValues = [
+ 'CANCELED',
+ 'CREATED',
+ 'FAILED',
+ 'MANUAL',
+ 'SUCCESS',
+ 'PENDING',
+ 'PREPARING',
+ 'RUNNING',
+ 'SCHEDULED',
+ 'SKIPPED',
+ 'WAITING_FOR_RESOURCE',
+];
+
+export const JOB_RUNNER_TYPE_INSTANCE_TYPE = 'INSTANCE_TYPE';
+export const JOB_RUNNER_TYPE_GROUP_TYPE = 'GROUP_TYPE';
+export const JOB_RUNNER_TYPE_PROJECT_TYPE = 'PROJECT_TYPE';
+
+export const jobRunnerTypeValues = [
+ JOB_RUNNER_TYPE_INSTANCE_TYPE,
+ JOB_RUNNER_TYPE_GROUP_TYPE,
+ JOB_RUNNER_TYPE_PROJECT_TYPE,
+];
diff --git a/app/assets/javascripts/ci/common/private/jobs_filtered_search/tokens/job_runner_type_token.vue b/app/assets/javascripts/ci/common/private/jobs_filtered_search/tokens/job_runner_type_token.vue
new file mode 100644
index 00000000000..5bd3693b4d9
--- /dev/null
+++ b/app/assets/javascripts/ci/common/private/jobs_filtered_search/tokens/job_runner_type_token.vue
@@ -0,0 +1,79 @@
+<script>
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlIcon } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import {
+ JOB_RUNNER_TYPE_INSTANCE_TYPE,
+ JOB_RUNNER_TYPE_GROUP_TYPE,
+ JOB_RUNNER_TYPE_PROJECT_TYPE,
+} from '../constants';
+
+export default {
+ components: {
+ GlFilteredSearchToken,
+ GlFilteredSearchSuggestion,
+ GlIcon,
+ },
+ props: {
+ config: {
+ type: Object,
+ required: true,
+ },
+ value: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ runnerTypes() {
+ return [
+ {
+ class: 'ci-runner-runner-type-instance',
+ icon: 'users',
+ text: s__('Runners|Instance'),
+ value: JOB_RUNNER_TYPE_INSTANCE_TYPE,
+ },
+ {
+ class: 'ci-runner-runner-type-group',
+ icon: 'group',
+ text: s__('Runners|Group'),
+ value: JOB_RUNNER_TYPE_GROUP_TYPE,
+ },
+ {
+ class: 'ci-runner-runner-type-project',
+ icon: 'project',
+ text: s__('Runners|Project'),
+ value: JOB_RUNNER_TYPE_PROJECT_TYPE,
+ },
+ ];
+ },
+ findActiveRunnerType() {
+ return this.runnerTypes.find((runnerType) => runnerType.value === this.value.data);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-filtered-search-token v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
+ <template #view>
+ <div class="gl-display-flex gl-align-items-center">
+ <div :class="findActiveRunnerType.class">
+ <gl-icon :name="findActiveRunnerType.icon" class="gl-mr-2 gl-display-block" />
+ </div>
+ <span>{{ findActiveRunnerType.text }}</span>
+ </div>
+ </template>
+ <template #suggestions>
+ <gl-filtered-search-suggestion
+ v-for="(runnerType, index) in runnerTypes"
+ :key="index"
+ :value="runnerType.value"
+ >
+ <div class="gl-display-flex" :class="runnerType.class">
+ <gl-icon :name="runnerType.icon" class="gl-mr-3" />
+ <span>{{ runnerType.text }}</span>
+ </div>
+ </gl-filtered-search-suggestion>
+ </template>
+ </gl-filtered-search-token>
+</template>
diff --git a/app/assets/javascripts/jobs/components/filtered_search/tokens/job_status_token.vue b/app/assets/javascripts/ci/common/private/jobs_filtered_search/tokens/job_status_token.vue
index aad86ded80a..aad86ded80a 100644
--- a/app/assets/javascripts/jobs/components/filtered_search/tokens/job_status_token.vue
+++ b/app/assets/javascripts/ci/common/private/jobs_filtered_search/tokens/job_status_token.vue
diff --git a/app/assets/javascripts/ci/common/private/jobs_filtered_search/utils.js b/app/assets/javascripts/ci/common/private/jobs_filtered_search/utils.js
new file mode 100644
index 00000000000..43c0da72d3d
--- /dev/null
+++ b/app/assets/javascripts/ci/common/private/jobs_filtered_search/utils.js
@@ -0,0 +1,22 @@
+import { jobStatusValues, jobRunnerTypeValues } from './constants';
+
+// validates query string used for filtered search
+// on jobs table to ensure GraphQL query is called correctly
+export const validateQueryString = (queryStringObj) => {
+ return Object.entries(queryStringObj).reduce((acc, [queryStringKey, queryStringValue]) => {
+ switch (queryStringKey) {
+ case 'statuses': {
+ const statusValue = queryStringValue.toUpperCase();
+ const statusValueValid = jobStatusValues.includes(statusValue);
+ return statusValueValid ? { ...acc, statuses: statusValue } : acc;
+ }
+ case 'runnerTypes': {
+ const runnerTypesValue = queryStringValue.toUpperCase();
+ const runnerTypesValueValid = jobRunnerTypeValues.includes(runnerTypesValue);
+ return runnerTypesValueValid ? { ...acc, runnerTypes: runnerTypesValue } : acc;
+ }
+ default:
+ return acc;
+ }
+ }, null);
+};
diff --git a/app/assets/javascripts/ci/constants.js b/app/assets/javascripts/ci/constants.js
new file mode 100644
index 00000000000..93c2504dd5d
--- /dev/null
+++ b/app/assets/javascripts/ci/constants.js
@@ -0,0 +1,51 @@
+import { __, s__ } from '~/locale';
+
+export const forwardDeploymentFailureModalId = 'forward-deployment-failure';
+
+export const BUTTON_TOOLTIP_RETRY = __('Retry all failed or cancelled jobs');
+export const BUTTON_TOOLTIP_CANCEL = __('Cancel the running pipeline');
+
+export const FILTER_TAG_IDENTIFIER = 'tag';
+
+export const JOB_GRAPHQL_ERRORS = {
+ jobMutationErrorText: __('There was an error running the job. Please try again.'),
+ jobQueryErrorText: __('There was an error fetching the job.'),
+};
+
+export const ICONS = {
+ TAG: 'tag',
+ MR: 'git-merge',
+ BRANCH: 'branch',
+ RETRY: 'retry',
+ SUCCESS: 'success',
+};
+
+export const SUCCESS_STATUS = 'SUCCESS';
+export const PASSED_STATUS = 'passed';
+export const MANUAL_STATUS = 'manual';
+
+// Constants for the ID and IID selection dropdown
+export const PipelineKeyOptions = [
+ {
+ text: __('Show Pipeline ID'),
+ label: __('Pipeline ID'),
+ value: 'id',
+ },
+ {
+ text: __('Show Pipeline IID'),
+ label: __('Pipeline IID'),
+ value: 'iid',
+ },
+];
+
+export const RAW_TEXT_WARNING = s__(
+ 'Pipeline|Raw text search is not currently supported. Please use the available search tokens.',
+);
+
+export const TRACKING_CATEGORIES = {
+ table: 'pipelines_table_component',
+ tabs: 'pipelines_filter_tabs',
+ search: 'pipelines_filtered_search',
+ failed: 'pipeline_failed_jobs_tab',
+ tests: 'pipeline_tests_tab',
+};
diff --git a/app/assets/javascripts/jobs/components/table/event_hub.js b/app/assets/javascripts/ci/event_hub.js
index e31806ad199..e31806ad199 100644
--- a/app/assets/javascripts/jobs/components/table/event_hub.js
+++ b/app/assets/javascripts/ci/event_hub.js
diff --git a/app/assets/javascripts/ci/inherited_ci_variables/components/inherited_ci_variables_app.vue b/app/assets/javascripts/ci/inherited_ci_variables/components/inherited_ci_variables_app.vue
index 27ee1b794f6..f02d59af1d9 100644
--- a/app/assets/javascripts/ci/inherited_ci_variables/components/inherited_ci_variables_app.vue
+++ b/app/assets/javascripts/ci/inherited_ci_variables/components/inherited_ci_variables_app.vue
@@ -3,7 +3,7 @@ import { produce } from 'immer';
import { s__ } from '~/locale';
import { createAlert } from '~/alert';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { reportMessageToSentry } from '~/ci/ci_variable_list/utils';
+import { reportMessageToSentry } from '~/ci/utils';
import CiVariableTable from '~/ci/ci_variable_list/components/ci_variable_table.vue';
import getInheritedCiVariables from '../graphql/queries/inherited_ci_variables.query.graphql';
diff --git a/app/assets/javascripts/ci/job_details/components/empty_state.vue b/app/assets/javascripts/ci/job_details/components/empty_state.vue
new file mode 100644
index 00000000000..5756d4a71df
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/empty_state.vue
@@ -0,0 +1,100 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+import ManualVariablesForm from '~/ci/job_details/components/manual_variables_form.vue';
+
+export default {
+ components: {
+ GlLink,
+ ManualVariablesForm,
+ },
+ props: {
+ illustrationPath: {
+ type: String,
+ required: true,
+ },
+ illustrationSizeClass: {
+ type: String,
+ required: true,
+ },
+ isRetryable: {
+ type: Boolean,
+ required: true,
+ },
+ jobId: {
+ type: Number,
+ required: true,
+ },
+ title: {
+ type: String,
+ required: true,
+ },
+ content: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ playable: {
+ type: Boolean,
+ required: true,
+ default: false,
+ },
+ scheduled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ action: {
+ type: Object,
+ required: false,
+ default: null,
+ validator(value) {
+ return (
+ value === null ||
+ (Object.prototype.hasOwnProperty.call(value, 'path') &&
+ Object.prototype.hasOwnProperty.call(value, 'method') &&
+ Object.prototype.hasOwnProperty.call(value, 'button_title'))
+ );
+ },
+ },
+ },
+ computed: {
+ shouldRenderManualVariables() {
+ return this.playable && !this.scheduled;
+ },
+ },
+};
+</script>
+<template>
+ <div class="row empty-state">
+ <div class="col-12">
+ <div :class="illustrationSizeClass" class="svg-content">
+ <img :src="illustrationPath" />
+ </div>
+ </div>
+
+ <div class="col-12">
+ <div class="text-content">
+ <h4 class="text-center" data-testid="job-empty-state-title">{{ title }}</h4>
+
+ <p v-if="content" data-testid="job-empty-state-content">{{ content }}</p>
+ </div>
+ <manual-variables-form
+ v-if="shouldRenderManualVariables"
+ :is-retryable="isRetryable"
+ :job-id="jobId"
+ @hideManualVariablesForm="$emit('hideManualVariablesForm')"
+ />
+ <div v-if="action && !shouldRenderManualVariables" class="text-content">
+ <div class="text-center">
+ <gl-link
+ :href="action.path"
+ :data-method="action.method"
+ class="btn gl-button btn-confirm gl-text-decoration-none!"
+ data-testid="job-empty-state-action"
+ >{{ action.button_title }}</gl-link
+ >
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/jobs/components/job/environments_block.vue b/app/assets/javascripts/ci/job_details/components/environments_block.vue
index 4046e1ade82..4046e1ade82 100644
--- a/app/assets/javascripts/jobs/components/job/environments_block.vue
+++ b/app/assets/javascripts/ci/job_details/components/environments_block.vue
diff --git a/app/assets/javascripts/jobs/components/job/erased_block.vue b/app/assets/javascripts/ci/job_details/components/erased_block.vue
index a815689659e..a815689659e 100644
--- a/app/assets/javascripts/jobs/components/job/erased_block.vue
+++ b/app/assets/javascripts/ci/job_details/components/erased_block.vue
diff --git a/app/assets/javascripts/ci/job_details/components/job_header.vue b/app/assets/javascripts/ci/job_details/components/job_header.vue
new file mode 100644
index 00000000000..13f3eebd447
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/job_header.vue
@@ -0,0 +1,148 @@
+<script>
+import { GlTooltipDirective, GlButton, GlAvatarLink, GlAvatarLabeled, GlTooltip } from '@gitlab/ui';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { glEmojiTag } from '~/emoji';
+import { __, sprintf } from '~/locale';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+export default {
+ components: {
+ CiBadgeLink,
+ TimeagoTooltip,
+ GlButton,
+ GlAvatarLink,
+ GlAvatarLabeled,
+ GlTooltip,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ SafeHtml,
+ },
+ EMOJI_REF: 'EMOJI_REF',
+ props: {
+ status: {
+ type: Object,
+ required: true,
+ },
+ name: {
+ type: String,
+ required: true,
+ },
+ time: {
+ type: String,
+ required: true,
+ },
+ user: {
+ type: Object,
+ required: true,
+ },
+ shouldRenderTriggeredLabel: {
+ type: Boolean,
+ required: true,
+ },
+ },
+
+ computed: {
+ userAvatarAltText() {
+ return sprintf(__(`%{username}'s avatar`), { username: this.user.name });
+ },
+ userPath() {
+ // GraphQL returns `webPath` and Rest `path`
+ return this.user?.webPath || this.user?.path;
+ },
+ avatarUrl() {
+ // GraphQL returns `avatarUrl` and Rest `avatar_url`
+ return this.user?.avatarUrl || this.user?.avatar_url;
+ },
+ webUrl() {
+ // GraphQL returns `webUrl` and Rest `web_url`
+ return this.user?.webUrl || this.user?.web_url;
+ },
+ statusTooltipHTML() {
+ // Rest `status_tooltip_html` which is a ready to work
+ // html for the emoji and the status text inside a tooltip.
+ // GraphQL returns `status.emoji` and `status.message` which
+ // needs to be combined to make the html we want.
+ const { emoji } = this.user?.status || {};
+ const emojiHtml = emoji ? glEmojiTag(emoji) : '';
+
+ return emojiHtml || this.user?.status_tooltip_html;
+ },
+ message() {
+ return this.user?.status?.message;
+ },
+ userId() {
+ return isGid(this.user?.id) ? getIdFromGraphQLId(this.user?.id) : this.user?.id;
+ },
+ },
+
+ methods: {
+ onClickSidebarButton() {
+ this.$emit('clickedSidebarButton');
+ },
+ },
+ safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
+};
+</script>
+
+<template>
+ <header
+ class="page-content-header gl-md-display-flex gl-min-h-7"
+ data-testid="job-header-content"
+ >
+ <section class="header-main-content gl-mr-3">
+ <ci-badge-link class="gl-mr-3" :status="status" />
+
+ <strong data-testid="job-name">{{ name }}</strong>
+
+ <template v-if="shouldRenderTriggeredLabel">{{ __('started') }}</template>
+ <template v-else>{{ __('created') }}</template>
+
+ <timeago-tooltip :time="time" />
+
+ {{ __('by') }}
+
+ <template v-if="user">
+ <gl-avatar-link
+ :data-user-id="userId"
+ :data-username="user.username"
+ :data-name="user.name"
+ :href="webUrl"
+ target="_blank"
+ class="js-user-link gl-vertical-align-middle gl-mx-2 gl-align-items-center"
+ >
+ <gl-avatar-labeled
+ :size="24"
+ :src="avatarUrl"
+ :label="user.name"
+ class="gl-display-none gl-sm-display-inline-flex gl-mx-1"
+ />
+ <strong class="author gl-display-inline gl-sm-display-none!">@{{ user.username }}</strong>
+ <gl-tooltip v-if="message" :target="() => $refs[$options.EMOJI_REF]">
+ {{ message }}
+ </gl-tooltip>
+ <span
+ v-if="statusTooltipHTML"
+ :ref="$options.EMOJI_REF"
+ v-safe-html:[$options.safeHtmlConfig]="statusTooltipHTML"
+ class="gl-ml-2"
+ :data-testid="message"
+ ></span>
+ </gl-avatar-link>
+ </template>
+ </section>
+
+ <!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots -->
+ <section v-if="$slots.default" data-testid="job-header-action-buttons" class="gl-display-flex">
+ <slot></slot>
+ </section>
+ <gl-button
+ class="gl-md-display-none gl-ml-auto gl-align-self-start js-sidebar-build-toggle"
+ icon="chevron-double-lg-left"
+ :aria-label="__('Toggle sidebar')"
+ @click="onClickSidebarButton"
+ />
+ </header>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue b/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue
new file mode 100644
index 00000000000..419efcba46d
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/job_log_controllers.vue
@@ -0,0 +1,260 @@
+<script>
+import { GlTooltipDirective, GlLink, GlButton, GlSearchBoxByClick } from '@gitlab/ui';
+import { scrollToElement, backOff } from '~/lib/utils/common_utils';
+import { numberToHumanSize } from '~/lib/utils/number_utils';
+import { __, s__, sprintf } from '~/locale';
+import { compactJobLog } from '~/ci/job_details/utils';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+
+export default {
+ i18n: {
+ scrollToBottomButtonLabel: s__('Job|Scroll to bottom'),
+ scrollToTopButtonLabel: s__('Job|Scroll to top'),
+ scrollToNextFailureButtonLabel: s__('Job|Scroll to next failure'),
+ showRawButtonLabel: s__('Job|Show complete raw'),
+ searchPlaceholder: s__('Job|Search job log'),
+ noResults: s__('Job|No search results found'),
+ searchPopoverTitle: s__('Job|Job log search'),
+ searchPopoverDescription: s__(
+ 'Job|Search for substrings in your job log output. Currently search is only supported for the visible job log output, not for any log output that is truncated due to size.',
+ ),
+ logLineNumberNotFound: s__('Job|We could not find this element'),
+ },
+ components: {
+ GlLink,
+ GlButton,
+ GlSearchBoxByClick,
+ HelpPopover,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [glFeatureFlagMixin()],
+ props: {
+ size: {
+ type: Number,
+ required: true,
+ },
+ rawPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ isScrollTopDisabled: {
+ type: Boolean,
+ required: true,
+ },
+ isScrollBottomDisabled: {
+ type: Boolean,
+ required: true,
+ },
+ isScrollingDown: {
+ type: Boolean,
+ required: true,
+ },
+ isJobLogSizeVisible: {
+ type: Boolean,
+ required: true,
+ },
+ isComplete: {
+ type: Boolean,
+ required: true,
+ },
+ jobLog: {
+ type: Array,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ searchTerm: '',
+ searchResults: [],
+ failureCount: null,
+ failureIndex: 0,
+ };
+ },
+ computed: {
+ jobLogSize() {
+ return sprintf(__('Showing last %{size} of log -'), {
+ size: numberToHumanSize(this.size),
+ });
+ },
+ showJumpToFailures() {
+ return this.glFeatures.jobLogJumpToFailures;
+ },
+ hasFailures() {
+ return this.failureCount > 0;
+ },
+ shouldDisableJumpToFailures() {
+ return !this.hasFailures;
+ },
+ },
+ mounted() {
+ this.checkFailureCount();
+ },
+ methods: {
+ checkFailureCount() {
+ if (this.glFeatures.jobLogJumpToFailures) {
+ backOff((next, stop) => {
+ this.failureCount = document.querySelectorAll('.term-fg-l-red').length;
+
+ if (this.hasFailures || (this.isComplete && !this.hasFailures)) {
+ stop();
+ } else {
+ next();
+ }
+ }).catch(() => {
+ this.failureCount = null;
+ });
+ }
+ },
+ handleScrollToNextFailure() {
+ const failures = document.querySelectorAll('.term-fg-l-red');
+ const nextFailure = failures[this.failureIndex];
+
+ if (nextFailure) {
+ nextFailure.scrollIntoView({ block: 'center' });
+ this.failureIndex = (this.failureIndex + 1) % failures.length;
+ }
+ },
+ handleScrollToTop() {
+ this.$emit('scrollJobLogTop');
+ this.failureIndex = 0;
+ },
+ handleScrollToBottom() {
+ this.$emit('scrollJobLogBottom');
+ this.failureIndex = 0;
+ },
+ searchJobLog() {
+ this.searchResults = [];
+
+ if (!this.searchTerm) return;
+
+ const compactedLog = compactJobLog(this.jobLog);
+
+ compactedLog.forEach((line) => {
+ const lineText = line.content[0].text;
+
+ if (lineText.toLocaleLowerCase().includes(this.searchTerm.toLocaleLowerCase())) {
+ this.searchResults.push(line);
+ }
+ });
+
+ if (this.searchResults.length > 0) {
+ this.$emit('searchResults', this.searchResults);
+
+ // BE returns zero based index, we need to add one to match the line numbers in the DOM
+ const firstSearchResult = `#L${this.searchResults[0].lineNumber + 1}`;
+ const logLine = document.querySelector(`.log-line ${firstSearchResult}`);
+
+ if (logLine) {
+ setTimeout(() => scrollToElement(logLine));
+
+ const message = sprintf(s__('Job|%{searchLength} results found for %{searchTerm}'), {
+ searchLength: this.searchResults.length,
+ searchTerm: this.searchTerm,
+ });
+
+ this.$toast.show(message);
+ } else {
+ this.$toast.show(this.$options.i18n.logLineNumberNotFound);
+ }
+ } else {
+ this.$toast.show(this.$options.i18n.noResults);
+ }
+ },
+ },
+};
+</script>
+<template>
+ <div class="top-bar gl-display-flex gl-justify-content-space-between">
+ <slot name="drawers"></slot>
+ <!-- truncate information -->
+ <div
+ class="truncated-info gl-display-none gl-sm-display-flex gl-flex-wrap gl-align-items-center"
+ data-testid="log-truncated-info"
+ >
+ <template v-if="isJobLogSizeVisible">
+ {{ jobLogSize }}
+ <gl-link
+ v-if="rawPath"
+ :href="rawPath"
+ class="text-plain text-underline gl-ml-2"
+ data-testid="raw-link"
+ >{{ s__('Job|Complete Raw') }}</gl-link
+ >
+ </template>
+ </div>
+ <!-- eo truncate information -->
+
+ <div class="controllers">
+ <slot name="controllers"> </slot>
+ <gl-search-box-by-click
+ v-model="searchTerm"
+ class="gl-mr-3"
+ :placeholder="$options.i18n.searchPlaceholder"
+ data-testid="job-log-search-box"
+ @clear="$emit('searchResults', [])"
+ @submit="searchJobLog"
+ />
+
+ <help-popover class="gl-mr-3">
+ <template #title>{{ $options.i18n.searchPopoverTitle }}</template>
+
+ <p class="gl-mb-0">
+ {{ $options.i18n.searchPopoverDescription }}
+ </p>
+ </help-popover>
+
+ <!-- links -->
+ <gl-button
+ v-if="rawPath"
+ v-gl-tooltip.body
+ :title="$options.i18n.showRawButtonLabel"
+ :aria-label="$options.i18n.showRawButtonLabel"
+ :href="rawPath"
+ data-testid="job-raw-link-controller"
+ icon="doc-code"
+ />
+ <!-- eo links -->
+
+ <!-- scroll buttons -->
+ <gl-button
+ v-if="showJumpToFailures"
+ v-gl-tooltip
+ :title="$options.i18n.scrollToNextFailureButtonLabel"
+ :aria-label="$options.i18n.scrollToNextFailureButtonLabel"
+ :disabled="shouldDisableJumpToFailures"
+ class="btn-scroll gl-ml-3"
+ data-testid="job-controller-scroll-to-failure"
+ icon="soft-wrap"
+ @click="handleScrollToNextFailure"
+ />
+
+ <div v-gl-tooltip :title="$options.i18n.scrollToTopButtonLabel" class="gl-ml-3">
+ <gl-button
+ :disabled="isScrollTopDisabled"
+ class="btn-scroll"
+ data-testid="job-controller-scroll-top"
+ icon="scroll_up"
+ :aria-label="$options.i18n.scrollToTopButtonLabel"
+ @click="handleScrollToTop"
+ />
+ </div>
+
+ <div v-gl-tooltip :title="$options.i18n.scrollToBottomButtonLabel" class="gl-ml-3">
+ <gl-button
+ :disabled="isScrollBottomDisabled"
+ class="js-scroll-bottom btn-scroll"
+ data-testid="job-controller-scroll-bottom"
+ icon="scroll_down"
+ :class="{ animate: isScrollingDown }"
+ :aria-label="$options.i18n.scrollToBottomButtonLabel"
+ @click="handleScrollToBottom"
+ />
+ </div>
+ <!-- eo scroll buttons -->
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/log/collapsible_section.vue b/app/assets/javascripts/ci/job_details/components/log/collapsible_section.vue
new file mode 100644
index 00000000000..39c612bc600
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/log/collapsible_section.vue
@@ -0,0 +1,71 @@
+<script>
+import LogLine from './line.vue';
+import LogLineHeader from './line_header.vue';
+
+export default {
+ name: 'CollapsibleLogSection',
+ components: {
+ LogLine,
+ LogLineHeader,
+ },
+ props: {
+ section: {
+ type: Object,
+ required: true,
+ },
+ jobLogEndpoint: {
+ type: String,
+ required: true,
+ },
+ searchResults: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ computed: {
+ badgeDuration() {
+ return this.section.line && this.section.line.section_duration;
+ },
+ highlightedLines() {
+ return this.searchResults.map((result) => result.lineNumber);
+ },
+ headerIsHighlighted() {
+ const {
+ line: { lineNumber },
+ } = this.section;
+
+ return this.highlightedLines.includes(lineNumber);
+ },
+ },
+ methods: {
+ handleOnClickCollapsibleLine(section) {
+ this.$emit('onClickCollapsibleLine', section);
+ },
+ lineIsHighlighted({ lineNumber }) {
+ return this.highlightedLines.includes(lineNumber);
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <log-line-header
+ :line="section.line"
+ :duration="badgeDuration"
+ :path="jobLogEndpoint"
+ :is-closed="section.isClosed"
+ :is-highlighted="headerIsHighlighted"
+ @toggleLine="handleOnClickCollapsibleLine(section)"
+ />
+ <template v-if="!section.isClosed">
+ <log-line
+ v-for="line in section.lines"
+ :key="line.offset"
+ :line="line"
+ :path="jobLogEndpoint"
+ :is-highlighted="lineIsHighlighted(line)"
+ />
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/jobs/components/log/duration_badge.vue b/app/assets/javascripts/ci/job_details/components/log/duration_badge.vue
index 54b76fd9edd..54b76fd9edd 100644
--- a/app/assets/javascripts/jobs/components/log/duration_badge.vue
+++ b/app/assets/javascripts/ci/job_details/components/log/duration_badge.vue
diff --git a/app/assets/javascripts/ci/job_details/components/log/line.vue b/app/assets/javascripts/ci/job_details/components/log/line.vue
new file mode 100644
index 00000000000..fa4a12b3dd3
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/log/line.vue
@@ -0,0 +1,83 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<script>
+import { getLocationHash } from '~/lib/utils/url_utility';
+import { linkRegex } from './utils';
+import LineNumber from './line_number.vue';
+
+export default {
+ functional: true,
+ props: {
+ line: {
+ type: Object,
+ required: true,
+ },
+ path: {
+ type: String,
+ required: true,
+ },
+ isHighlighted: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ render(h, { props }) {
+ const { line, path, isHighlighted } = props;
+
+ const chars = line.content.map((content) => {
+ return h(
+ 'span',
+ {
+ class: ['gl-white-space-pre-wrap', content.style],
+ },
+ // Simple "tokenization": Split text in chunks of text
+ // which alternate between text and urls.
+ content.text.split(linkRegex).map((chunk) => {
+ // Return normal string for non-links
+ if (!chunk.match(linkRegex)) {
+ return chunk;
+ }
+ return h(
+ 'a',
+ {
+ attrs: {
+ href: chunk,
+ class: 'gl-reset-color! gl-text-decoration-underline',
+ rel: 'nofollow noopener noreferrer', // eslint-disable-line @gitlab/require-i18n-strings
+ },
+ },
+ chunk,
+ );
+ }),
+ );
+ });
+
+ let applyHashHighlight = false;
+
+ if (window.location.hash) {
+ const hash = getLocationHash();
+ const lineToMatch = `L${line.lineNumber + 1}`;
+
+ if (hash === lineToMatch) {
+ applyHashHighlight = true;
+ }
+ }
+
+ return h(
+ 'div',
+ {
+ class: ['js-line', 'log-line', { 'gl-bg-gray-700': isHighlighted || applyHashHighlight }],
+ },
+ [
+ h(LineNumber, {
+ props: {
+ lineNumber: line.lineNumber,
+ path,
+ },
+ }),
+ ...chars,
+ ],
+ );
+ },
+};
+</script>
diff --git a/app/assets/javascripts/ci/job_details/components/log/line_header.vue b/app/assets/javascripts/ci/job_details/components/log/line_header.vue
new file mode 100644
index 00000000000..e647ab4ac0b
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/log/line_header.vue
@@ -0,0 +1,81 @@
+<script>
+import { GlIcon } from '@gitlab/ui';
+import { getLocationHash } from '~/lib/utils/url_utility';
+import DurationBadge from './duration_badge.vue';
+import LineNumber from './line_number.vue';
+
+export default {
+ components: {
+ GlIcon,
+ LineNumber,
+ DurationBadge,
+ },
+ props: {
+ line: {
+ type: Object,
+ required: true,
+ },
+ isClosed: {
+ type: Boolean,
+ required: true,
+ },
+ path: {
+ type: String,
+ required: true,
+ },
+ duration: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ isHighlighted: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ applyHashHighlight: false,
+ };
+ },
+ computed: {
+ iconName() {
+ return this.isClosed ? 'chevron-lg-right' : 'chevron-lg-down';
+ },
+ },
+ mounted() {
+ const hash = getLocationHash();
+ const lineToMatch = `L${this.line.lineNumber + 1}`;
+
+ if (hash === lineToMatch) {
+ this.applyHashHighlight = true;
+ }
+ },
+ methods: {
+ handleOnClick() {
+ this.$emit('toggleLine');
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ class="log-line collapsible-line d-flex justify-content-between ws-normal gl-align-items-flex-start gl-relative"
+ :class="{ 'gl-bg-gray-700': isHighlighted || applyHashHighlight }"
+ role="button"
+ @click="handleOnClick"
+ >
+ <gl-icon :name="iconName" class="arrow gl-absolute gl-top-2" />
+ <line-number :line-number="line.lineNumber" :path="path" />
+ <span
+ v-for="(content, i) in line.content"
+ :key="i"
+ class="line-text w-100 gl-white-space-pre-wrap"
+ :class="content.style"
+ >{{ content.text }}</span
+ >
+ <duration-badge v-if="duration" :duration="duration" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/jobs/components/log/line_number.vue b/app/assets/javascripts/ci/job_details/components/log/line_number.vue
index 7ca9154d2fe..7ca9154d2fe 100644
--- a/app/assets/javascripts/jobs/components/log/line_number.vue
+++ b/app/assets/javascripts/ci/job_details/components/log/line_number.vue
diff --git a/app/assets/javascripts/ci/job_details/components/log/log.vue b/app/assets/javascripts/ci/job_details/components/log/log.vue
new file mode 100644
index 00000000000..fb6a6a58074
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/log/log.vue
@@ -0,0 +1,106 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<script>
+// eslint-disable-next-line no-restricted-imports
+import { mapState, mapActions } from 'vuex';
+import { scrollToElement } from '~/lib/utils/common_utils';
+import { getLocationHash } from '~/lib/utils/url_utility';
+import CollapsibleLogSection from './collapsible_section.vue';
+import LogLine from './line.vue';
+
+export default {
+ components: {
+ CollapsibleLogSection,
+ LogLine,
+ },
+ props: {
+ searchResults: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ computed: {
+ ...mapState([
+ 'jobLogEndpoint',
+ 'jobLog',
+ 'isJobLogComplete',
+ 'isScrolledToBottomBeforeReceivingJobLog',
+ ]),
+ highlightedLines() {
+ return this.searchResults.map((result) => result.lineNumber);
+ },
+ },
+ updated() {
+ this.$nextTick(() => {
+ if (!window.location.hash) {
+ this.handleScrollDown();
+ }
+ });
+ },
+ mounted() {
+ if (window.location.hash) {
+ const lineNumber = getLocationHash();
+
+ this.unwatchJobLog = this.$watch('jobLog', async () => {
+ if (this.jobLog.length) {
+ await this.$nextTick();
+
+ const el = document.getElementById(lineNumber);
+ scrollToElement(el);
+ this.unwatchJobLog();
+ }
+ });
+ }
+ },
+ methods: {
+ ...mapActions(['toggleCollapsibleLine', 'scrollBottom']),
+ handleOnClickCollapsibleLine(section) {
+ this.toggleCollapsibleLine(section);
+ },
+ /**
+ * The job log is sent in HTML, which means we need to use `v-html` to render it
+ * Using the updated hook with $nextTick is not enough to wait for the DOM to be updated
+ * in this case because it runs before `v-html` has finished running, since there's no
+ * Vue binding.
+ * In order to scroll the page down after `v-html` has finished, we need to use setTimeout
+ */
+ handleScrollDown() {
+ if (this.isScrolledToBottomBeforeReceivingJobLog) {
+ setTimeout(() => {
+ this.scrollBottom();
+ }, 0);
+ }
+ },
+ isHighlighted({ lineNumber }) {
+ return this.highlightedLines.includes(lineNumber);
+ },
+ },
+};
+</script>
+<template>
+ <code class="job-log d-block" data-testid="job-log-content">
+ <template v-for="(section, index) in jobLog">
+ <collapsible-log-section
+ v-if="section.isHeader"
+ :key="`collapsible-${index}`"
+ :section="section"
+ :job-log-endpoint="jobLogEndpoint"
+ :search-results="searchResults"
+ @onClickCollapsibleLine="handleOnClickCollapsibleLine"
+ />
+ <log-line
+ v-else
+ :key="section.offset"
+ :line="section"
+ :path="jobLogEndpoint"
+ :is-highlighted="isHighlighted(section)"
+ />
+ </template>
+
+ <div v-if="!isJobLogComplete" class="js-log-animation loader-animation pt-3 pl-3">
+ <div class="dot"></div>
+ <div class="dot"></div>
+ <div class="dot"></div>
+ </div>
+ </code>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/log/utils.js b/app/assets/javascripts/ci/job_details/components/log/utils.js
new file mode 100644
index 00000000000..1ccecf3eb53
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/log/utils.js
@@ -0,0 +1,12 @@
+/**
+ * capture anything starting with http:// or https://
+ * https?:\/\/
+ *
+ * up until a disallowed character or whitespace
+ * [^"<>()\\^`{|}\s]+
+ *
+ * and a disallowed character or whitespace, including non-ending chars .,:;!?
+ * [^"<>()\\^`{|}\s.,:;!?]
+ */
+export const linkRegex = /(https?:\/\/[^"<>()\\^`{|}\s]+[^"<>()\\^`{|}\s.,:;!?])/g;
+export default { linkRegex };
diff --git a/app/assets/javascripts/ci/job_details/components/manual_variables_form.vue b/app/assets/javascripts/ci/job_details/components/manual_variables_form.vue
new file mode 100644
index 00000000000..1232ffffb57
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/manual_variables_form.vue
@@ -0,0 +1,305 @@
+<script>
+import {
+ GlFormInputGroup,
+ GlInputGroupText,
+ GlFormInput,
+ GlButton,
+ GlLink,
+ GlLoadingIcon,
+ GlSprintf,
+ GlTooltipDirective,
+} from '@gitlab/ui';
+import { cloneDeep, uniqueId } from 'lodash';
+import { fetchPolicies } from '~/lib/graphql';
+import { createAlert } from '~/alert';
+import { TYPENAME_CI_BUILD, TYPENAME_COMMIT_STATUS } from '~/graphql_shared/constants';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { JOB_GRAPHQL_ERRORS } from '~/ci/constants';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import { s__ } from '~/locale';
+import { reportMessageToSentry } from '~/ci/utils';
+import GetJob from '../graphql/queries/get_job.query.graphql';
+import playJobWithVariablesMutation from '../graphql/mutations/job_play_with_variables.mutation.graphql';
+import retryJobWithVariablesMutation from '../graphql/mutations/job_retry_with_variables.mutation.graphql';
+
+// This component is a port of ~/ci/job_details/components/legacy_manual_variables_form.vue
+// It is meant to fetch/update the job information via GraphQL instead of REST API.
+
+export default {
+ name: 'ManualVariablesForm',
+ components: {
+ GlFormInputGroup,
+ GlInputGroupText,
+ GlFormInput,
+ GlButton,
+ GlLink,
+ GlLoadingIcon,
+ GlSprintf,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ inject: ['projectPath'],
+ apollo: {
+ variables: {
+ query: GetJob,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ id: convertToGraphQLId(TYPENAME_COMMIT_STATUS, this.jobId),
+ };
+ },
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
+ update(data) {
+ const jobVariables = cloneDeep(data?.project?.job?.manualVariables?.nodes);
+ return [...jobVariables.reverse(), ...this.variables];
+ },
+ error(error) {
+ createAlert({ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText });
+ reportMessageToSentry(this.$options.name, error, {});
+ },
+ },
+ },
+ props: {
+ isRetryable: {
+ type: Boolean,
+ required: true,
+ },
+ jobId: {
+ type: Number,
+ required: true,
+ },
+ },
+ clearBtnSharedClasses: ['gl-flex-grow-0 gl-flex-basis-0 gl-m-0! gl-ml-3!'],
+ inputTypes: {
+ key: 'key',
+ value: 'value',
+ },
+ i18n: {
+ cancel: s__('CiVariables|Cancel'),
+ removeInputs: s__('CiVariables|Remove inputs'),
+ formHelpText: s__(
+ 'CiVariables|Specify variable values to be used in this run. The variables specified in the configuration file and %{linkStart}CI/CD settings%{linkEnd} are used by default.',
+ ),
+ overrideNoteText: s__(
+ 'CiVariables|Variables specified here are %{boldStart}expanded%{boldEnd} and not %{boldStart}masked.%{boldEnd}',
+ ),
+ header: s__('CiVariables|Variables'),
+ keyLabel: s__('CiVariables|Key'),
+ keyPlaceholder: s__('CiVariables|Input variable key'),
+ runAgainButtonText: s__('CiVariables|Run job again'),
+ runButtonText: s__('CiVariables|Run job'),
+ valueLabel: s__('CiVariables|Value'),
+ valuePlaceholder: s__('CiVariables|Input variable value'),
+ },
+ data() {
+ return {
+ job: {},
+ variables: [
+ {
+ id: uniqueId(),
+ key: '',
+ value: '',
+ },
+ ],
+ runBtnDisabled: false,
+ };
+ },
+ computed: {
+ mutationVariables() {
+ return {
+ id: convertToGraphQLId(TYPENAME_CI_BUILD, this.jobId),
+ variables: this.preparedVariables,
+ };
+ },
+ preparedVariables() {
+ return this.variables
+ .filter((variable) => variable.key !== '')
+ .map(({ key, value }) => ({ key, value }));
+ },
+ runBtnText() {
+ return this.isRetryable
+ ? this.$options.i18n.runAgainButtonText
+ : this.$options.i18n.runButtonText;
+ },
+ variableSettings() {
+ return helpPagePath('ci/variables/index', { anchor: 'add-a-cicd-variable-to-a-project' });
+ },
+ },
+ methods: {
+ async playJob() {
+ try {
+ const { data } = await this.$apollo.mutate({
+ mutation: playJobWithVariablesMutation,
+ variables: this.mutationVariables,
+ });
+ if (data.jobPlay?.errors?.length) {
+ createAlert({ message: data.jobPlay.errors[0] });
+ } else {
+ this.navigateToJob(data.jobPlay?.job?.webPath);
+ }
+ } catch (error) {
+ createAlert({ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText });
+ reportMessageToSentry(this.$options.name, error, {});
+ }
+ },
+ async retryJob() {
+ try {
+ const { data } = await this.$apollo.mutate({
+ mutation: retryJobWithVariablesMutation,
+ variables: this.mutationVariables,
+ });
+ if (data.jobRetry?.errors?.length) {
+ createAlert({ message: data.jobRetry.errors[0] });
+ } else {
+ this.navigateToJob(data.jobRetry?.job?.webPath);
+ }
+ } catch (error) {
+ createAlert({ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText });
+ reportMessageToSentry(this.$options.name, error, {});
+ }
+ },
+ addEmptyVariable() {
+ const lastVar = this.variables[this.variables.length - 1];
+
+ if (lastVar.key === '') {
+ return;
+ }
+
+ this.variables.push({
+ id: uniqueId(),
+ key: '',
+ value: '',
+ });
+ },
+ canRemove(index) {
+ return index < this.variables.length - 1;
+ },
+ deleteVariable(id) {
+ this.variables.splice(
+ this.variables.findIndex((el) => el.id === id),
+ 1,
+ );
+ },
+ inputRef(type, id) {
+ return `${this.$options.inputTypes[type]}-${id}`;
+ },
+ navigateToJob(path) {
+ redirectTo(path); // eslint-disable-line import/no-deprecated
+ },
+ runJob() {
+ this.runBtnDisabled = true;
+
+ if (this.isRetryable) {
+ this.retryJob();
+ } else {
+ this.playJob();
+ }
+ },
+ },
+};
+</script>
+<template>
+ <gl-loading-icon v-if="$apollo.queries.variables.loading" class="gl-mt-9" size="lg" />
+ <div v-else class="row gl-justify-content-center">
+ <div class="col-10">
+ <label>{{ $options.i18n.header }}</label>
+
+ <div
+ v-for="(variable, index) in variables"
+ :key="variable.id"
+ class="gl-display-flex gl-align-items-center gl-mb-5"
+ data-testid="ci-variable-row"
+ >
+ <gl-form-input-group class="gl-mr-4 gl-flex-grow-1">
+ <template #prepend>
+ <gl-input-group-text>
+ {{ $options.i18n.keyLabel }}
+ </gl-input-group-text>
+ </template>
+ <gl-form-input
+ :ref="inputRef('key', variable.id)"
+ v-model="variable.key"
+ :placeholder="$options.i18n.keyPlaceholder"
+ data-testid="ci-variable-key"
+ @change="addEmptyVariable"
+ />
+ </gl-form-input-group>
+
+ <gl-form-input-group class="gl-flex-grow-2">
+ <template #prepend>
+ <gl-input-group-text>
+ {{ $options.i18n.valueLabel }}
+ </gl-input-group-text>
+ </template>
+ <gl-form-input
+ :ref="inputRef('value', variable.id)"
+ v-model="variable.value"
+ :placeholder="$options.i18n.valuePlaceholder"
+ data-testid="ci-variable-value"
+ />
+ </gl-form-input-group>
+
+ <gl-button
+ v-if="canRemove(index)"
+ v-gl-tooltip
+ :aria-label="$options.i18n.removeInputs"
+ :title="$options.i18n.removeInputs"
+ :class="$options.clearBtnSharedClasses"
+ category="tertiary"
+ icon="remove"
+ data-testid="delete-variable-btn"
+ @click="deleteVariable(variable.id)"
+ />
+ <!-- Placeholder button to keep the layout fixed -->
+ <gl-button
+ v-else
+ class="gl-opacity-0 gl-pointer-events-none"
+ :class="$options.clearBtnSharedClasses"
+ data-testid="delete-variable-btn-placeholder"
+ category="tertiary"
+ icon="remove"
+ />
+ </div>
+
+ <div class="gl-text-center gl-mt-5">
+ <gl-sprintf :message="$options.i18n.formHelpText">
+ <template #link="{ content }">
+ <gl-link :href="variableSettings" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-text-center gl-mt-3">
+ <gl-sprintf :message="$options.i18n.overrideNoteText">
+ <template #bold="{ content }">
+ <strong>
+ {{ content }}
+ </strong>
+ </template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-display-flex gl-justify-content-center gl-mt-5">
+ <gl-button
+ v-if="isRetryable"
+ class="gl-mt-5"
+ data-testid="cancel-btn"
+ @click="$emit('hideManualVariablesForm')"
+ >{{ $options.i18n.cancel }}</gl-button
+ >
+ <gl-button
+ class="gl-mt-5"
+ variant="confirm"
+ category="primary"
+ :disabled="runBtnDisabled"
+ data-testid="run-manual-job-btn"
+ @click="runJob"
+ >
+ {{ runBtnText }}
+ </gl-button>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/artifacts_block.vue b/app/assets/javascripts/ci/job_details/components/sidebar/artifacts_block.vue
new file mode 100644
index 00000000000..4c81a9bd033
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/artifacts_block.vue
@@ -0,0 +1,120 @@
+<script>
+import { GlButton, GlButtonGroup, GlIcon, GlLink, GlPopover } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+
+export default {
+ i18n: {
+ jobArtifacts: s__('Job|Job artifacts'),
+ artifactsHelpText: s__(
+ 'Job|Job artifacts are files that are configured to be uploaded when a job finishes execution. Artifacts could be compiled files, unit tests or scanning reports, or any other files generated by a job.',
+ ),
+ expiredText: s__('Job|The artifacts were removed'),
+ willExpireText: s__('Job|The artifacts will be removed'),
+ lockedText: s__(
+ 'Job|These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available.',
+ ),
+ keepText: s__('Job|Keep'),
+ downloadText: s__('Job|Download'),
+ browseText: s__('Job|Browse'),
+ },
+ artifactsHelpPath: helpPagePath('ci/jobs/job_artifacts'),
+ components: {
+ GlButton,
+ GlButtonGroup,
+ GlIcon,
+ GlLink,
+ GlPopover,
+ TimeagoTooltip,
+ },
+ mixins: [timeagoMixin],
+ props: {
+ artifact: {
+ type: Object,
+ required: true,
+ },
+ helpUrl: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ isExpired() {
+ return this.artifact?.expired && !this.isLocked;
+ },
+ isLocked() {
+ return this.artifact?.locked;
+ },
+ // Only when the key is `false` we can render this block
+ willExpire() {
+ return this.artifact?.expired === false && !this.isLocked;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <div class="title gl-font-weight-bold">
+ <span class="gl-mr-2">{{ $options.i18n.jobArtifacts }}</span>
+ <gl-link :href="$options.artifactsHelpPath" data-testid="artifacts-help-link">
+ <gl-icon id="artifacts-help" name="question-o" />
+ </gl-link>
+ <gl-popover
+ target="artifacts-help"
+ :title="$options.i18n.jobArtifacts"
+ triggers="hover focus"
+ >
+ {{ $options.i18n.artifactsHelpText }}
+ </gl-popover>
+ </div>
+ <p
+ v-if="isExpired || willExpire"
+ class="build-detail-row"
+ data-testid="artifacts-remove-timeline"
+ >
+ <span v-if="isExpired">{{ $options.i18n.expiredText }}</span>
+ <span v-if="willExpire" data-testid="artifacts-unlocked-message-content">
+ {{ $options.i18n.willExpireText }}
+ </span>
+ <timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" />
+ <gl-link
+ :href="helpUrl"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ data-testid="artifact-expired-help-link"
+ >
+ <gl-icon name="question-o" />
+ </gl-link>
+ </p>
+ <p v-else-if="isLocked" class="build-detail-row">
+ <span data-testid="artifacts-locked-message-content">
+ {{ $options.i18n.lockedText }}
+ </span>
+ </p>
+ <gl-button-group class="gl-display-flex gl-mt-3">
+ <gl-button
+ v-if="artifact.keep_path"
+ :href="artifact.keep_path"
+ data-method="post"
+ data-testid="keep-artifacts"
+ >{{ $options.i18n.keepText }}</gl-button
+ >
+ <gl-button
+ v-if="artifact.download_path"
+ :href="artifact.download_path"
+ rel="nofollow"
+ data-testid="download-artifacts"
+ download
+ >{{ $options.i18n.downloadText }}</gl-button
+ >
+ <gl-button
+ v-if="artifact.browse_path"
+ :href="artifact.browse_path"
+ data-testid="browse-artifacts-button"
+ >{{ $options.i18n.browseText }}</gl-button
+ >
+ </gl-button-group>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/commit_block.vue b/app/assets/javascripts/ci/job_details/components/sidebar/commit_block.vue
new file mode 100644
index 00000000000..95616a4c706
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/commit_block.vue
@@ -0,0 +1,54 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+export default {
+ components: {
+ ClipboardButton,
+ GlLink,
+ },
+ props: {
+ commit: {
+ type: Object,
+ required: true,
+ },
+ mergeRequest: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <p class="gl-display-flex gl-flex-wrap gl-align-items-baseline gl-gap-2 gl-mb-0">
+ <span class="gl-display-flex gl-font-weight-bold">{{ __('Commit') }}</span>
+
+ <gl-link
+ :href="commit.commit_path"
+ class="gl-text-blue-500! gl-font-monospace"
+ data-testid="commit-sha"
+ >
+ {{ commit.short_id }}
+ </gl-link>
+
+ <clipboard-button
+ :text="commit.id"
+ :title="__('Copy commit SHA')"
+ category="tertiary"
+ size="small"
+ class="gl-align-self-center"
+ />
+
+ <span v-if="mergeRequest">
+ {{ __('in') }}
+ <gl-link :href="mergeRequest.path" class="gl-text-blue-500!" data-testid="link-commit"
+ >!{{ mergeRequest.iid }}</gl-link
+ >
+ </span>
+ </p>
+
+ <p class="gl-mb-0">{{ commit.title }}</p>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/external_links_block.vue b/app/assets/javascripts/ci/job_details/components/sidebar/external_links_block.vue
new file mode 100644
index 00000000000..a87f4b8467e
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/external_links_block.vue
@@ -0,0 +1,34 @@
+<script>
+import { GlIcon, GlLink } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlIcon,
+ GlLink,
+ },
+ props: {
+ externalLinks: {
+ type: Array,
+ required: true,
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <div class="title gl-font-weight-bold">{{ s__('Job|External links') }}</div>
+ <ul class="gl-list-style-none gl-p-0 gl-m-0">
+ <li v-for="(externalLink, index) in externalLinks" :key="index">
+ <gl-link
+ :href="externalLink.url"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ class="gl-text-blue-600!"
+ >
+ <gl-icon name="external-link" class="flex-shrink-0" />
+ {{ externalLink.label }}
+ </gl-link>
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/job_container_item.vue b/app/assets/javascripts/ci/job_details/components/sidebar/job_container_item.vue
new file mode 100644
index 00000000000..8e87f118fa4
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/job_container_item.vue
@@ -0,0 +1,77 @@
+<script>
+import { GlLink, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import delayedJobMixin from '~/ci/mixins/delayed_job_mixin';
+import { sprintf } from '~/locale';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+
+export default {
+ components: {
+ CiIcon,
+ GlIcon,
+ GlLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [delayedJobMixin],
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ isActive: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ tooltipText() {
+ const { name, status } = this.job;
+ const text = `${name} - ${status.tooltip}`;
+
+ if (this.isDelayedJob) {
+ return sprintf(text, { remainingTime: this.remainingTime });
+ }
+
+ return text;
+ },
+ jobName() {
+ return this.job.name ? this.job.name : this.job.id;
+ },
+ classes() {
+ return {
+ 'retried gl-text-secondary': this.job.retried,
+ 'gl-font-weight-bold': this.isActive,
+ };
+ },
+ dataTestId() {
+ return this.isActive ? 'active-job' : null;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="build-job gl-relative" :class="classes">
+ <gl-link
+ v-gl-tooltip.left.viewport
+ :href="job.status.details_path"
+ :title="tooltipText"
+ class="gl-display-flex gl-align-items-center gl-py-3 gl-pl-7"
+ :data-testid="dataTestId"
+ >
+ <gl-icon
+ v-if="isActive"
+ name="arrow-right"
+ class="icon-arrow-right gl-absolute gl-display-block"
+ :size="14"
+ />
+
+ <ci-icon :status="job.status" class="gl-mr-3" :size="14" />
+
+ <span class="gl-text-truncate gl-w-full">{{ jobName }}</span>
+
+ <gl-icon v-if="job.retried" name="retry" class="gl-mr-4" />
+ </gl-link>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/job_retry_forward_deployment_modal.vue b/app/assets/javascripts/ci/job_details/components/sidebar/job_retry_forward_deployment_modal.vue
new file mode 100644
index 00000000000..58e49c71830
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/job_retry_forward_deployment_modal.vue
@@ -0,0 +1,72 @@
+<script>
+import { GlLink, GlModal } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+
+export default {
+ name: 'JobRetryForwardDeploymentModal',
+ components: {
+ GlLink,
+ GlModal,
+ },
+ i18n: {
+ cancel: __('Cancel'),
+ info: s__(
+ `Jobs|You're about to retry a job that failed because it attempted to deploy code that is older than the latest deployment.
+ Retrying this job could result in overwriting the environment with the older source code.`,
+ ),
+ areYouSure: s__('Jobs|Are you sure you want to proceed?'),
+ moreInfo: __('More information'),
+ primaryText: __('Retry job'),
+ title: s__('Jobs|Are you sure you want to retry this job?'),
+ },
+ inject: {
+ retryOutdatedJobDocsUrl: {
+ default: '',
+ },
+ },
+ props: {
+ modalId: {
+ type: String,
+ required: true,
+ },
+ href: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ primaryProps: {
+ text: this.$options.i18n.primaryText,
+ attributes: {
+ 'data-method': 'post',
+ 'data-testid': 'retry-button-modal',
+ href: this.href,
+ variant: 'danger',
+ },
+ },
+ cancelProps: {
+ text: this.$options.i18n.cancel,
+ attributes: { category: 'secondary', variant: 'default' },
+ },
+ };
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ :action-cancel="cancelProps"
+ :action-primary="primaryProps"
+ :modal-id="modalId"
+ :title="$options.i18n.title"
+ >
+ <p>
+ {{ $options.i18n.info }}
+ <gl-link v-if="retryOutdatedJobDocsUrl" :href="retryOutdatedJobDocsUrl" target="_blank">
+ {{ $options.i18n.moreInfo }}
+ </gl-link>
+ </p>
+ <p>{{ $options.i18n.areYouSure }}</p>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/job_sidebar_retry_button.vue b/app/assets/javascripts/ci/job_details/components/sidebar/job_sidebar_retry_button.vue
new file mode 100644
index 00000000000..26676123dc3
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/job_sidebar_retry_button.vue
@@ -0,0 +1,84 @@
+<script>
+import { GlButton, GlDisclosureDropdown, GlModalDirective } from '@gitlab/ui';
+// eslint-disable-next-line no-restricted-imports
+import { mapGetters } from 'vuex';
+import { s__ } from '~/locale';
+
+export default {
+ name: 'JobSidebarRetryButton',
+ i18n: {
+ retryJobLabel: s__('Job|Retry'),
+ runAgainJobButtonLabel: s__('Job|Run again'),
+ updateVariables: s__('Job|Update CI/CD variables'),
+ },
+ components: {
+ GlButton,
+ GlDisclosureDropdown,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ props: {
+ modalId: {
+ type: String,
+ required: true,
+ },
+ href: {
+ type: String,
+ required: true,
+ },
+ isManualJob: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapGetters(['hasForwardDeploymentFailure']),
+ dropdownItems() {
+ return [
+ {
+ text: this.$options.i18n.runAgainJobButtonLabel,
+ href: this.href,
+ extraAttrs: {
+ 'data-method': 'post',
+ },
+ },
+ {
+ text: this.$options.i18n.updateVariables,
+ action: () => this.$emit('updateVariablesClicked'),
+ },
+ ];
+ },
+ },
+};
+</script>
+<template>
+ <gl-button
+ v-if="hasForwardDeploymentFailure"
+ v-gl-modal="modalId"
+ :aria-label="$options.i18n.retryJobLabel"
+ category="primary"
+ variant="confirm"
+ icon="retry"
+ data-testid="retry-job-button"
+ />
+ <gl-disclosure-dropdown
+ v-else-if="isManualJob"
+ icon="retry"
+ category="primary"
+ placement="right"
+ positioning-strategy="fixed"
+ variant="confirm"
+ :items="dropdownItems"
+ />
+ <gl-button
+ v-else
+ :href="href"
+ :aria-label="$options.i18n.retryJobLabel"
+ category="primary"
+ variant="confirm"
+ icon="retry"
+ data-method="post"
+ data-testid="retry-job-link"
+ />
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/jobs_container.vue b/app/assets/javascripts/ci/job_details/components/sidebar/jobs_container.vue
new file mode 100644
index 00000000000..18bd2593c2a
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/jobs_container.vue
@@ -0,0 +1,36 @@
+<script>
+import JobContainerItem from './job_container_item.vue';
+
+export default {
+ components: {
+ JobContainerItem,
+ },
+
+ props: {
+ jobs: {
+ type: Array,
+ required: true,
+ },
+ jobId: {
+ type: Number,
+ required: true,
+ },
+ },
+ methods: {
+ isJobActive(currentJobId) {
+ return this.jobId === currentJobId;
+ },
+ },
+};
+</script>
+<template>
+ <div class="block builds-container">
+ <b class="gl-display-flex gl-mb-2 gl-font-weight-semibold">{{ __('Related jobs') }}</b>
+ <job-container-item
+ v-for="job in jobs"
+ :key="job.id"
+ :job="job"
+ :is-active="isJobActive(job.id)"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue
new file mode 100644
index 00000000000..7f2f4fc0331
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue
@@ -0,0 +1,127 @@
+<script>
+import { isEmpty } from 'lodash';
+// eslint-disable-next-line no-restricted-imports
+import { mapActions, mapGetters, mapState } from 'vuex';
+import { forwardDeploymentFailureModalId } from '~/ci/constants';
+import { filterAnnotations } from '~/ci/job_details/utils';
+import ArtifactsBlock from './artifacts_block.vue';
+import CommitBlock from './commit_block.vue';
+import ExternalLinksBlock from './external_links_block.vue';
+import JobsContainer from './jobs_container.vue';
+import JobRetryForwardDeploymentModal from './job_retry_forward_deployment_modal.vue';
+import JobSidebarDetailsContainer from './sidebar_job_details_container.vue';
+import SidebarHeader from './sidebar_header.vue';
+import StagesDropdown from './stages_dropdown.vue';
+import TriggerBlock from './trigger_block.vue';
+
+export default {
+ name: 'JobSidebar',
+ forwardDeploymentFailureModalId,
+ components: {
+ ArtifactsBlock,
+ CommitBlock,
+ JobsContainer,
+ JobRetryForwardDeploymentModal,
+ JobSidebarDetailsContainer,
+ SidebarHeader,
+ StagesDropdown,
+ TriggerBlock,
+ ExternalLinksBlock,
+ },
+ props: {
+ artifactHelpUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ ...mapGetters(['hasForwardDeploymentFailure']),
+ ...mapState(['job', 'stages', 'jobs', 'selectedStage']),
+ hasArtifact() {
+ // the artifact object will always have a locked property
+ return Object.keys(this.job.artifact).length > 1;
+ },
+ hasExternalLinks() {
+ return this.externalLinks.length > 0;
+ },
+ hasTriggers() {
+ return !isEmpty(this.job.trigger);
+ },
+ commit() {
+ return this.job?.pipeline?.commit || {};
+ },
+ selectedStageData() {
+ return this.stages.find((val) => val.name === this.selectedStage);
+ },
+ shouldShowJobRetryForwardDeploymentModal() {
+ return this.job.retry_path && this.hasForwardDeploymentFailure;
+ },
+ externalLinks() {
+ return filterAnnotations(this.job.annotations, 'external_link');
+ },
+ },
+ watch: {
+ job(value, oldValue) {
+ const hasNewStatus = value.status.text !== oldValue.status.text;
+ const isCurrentStage = value?.stage === this.selectedStage;
+
+ if (hasNewStatus && isCurrentStage) {
+ this.fetchJobsForStage(this.selectedStageData);
+ }
+ },
+ },
+ methods: {
+ ...mapActions(['fetchJobsForStage']),
+ },
+};
+</script>
+<template>
+ <aside class="right-sidebar build-sidebar" data-offset-top="101" data-spy="affix">
+ <div class="sidebar-container">
+ <div class="blocks-container gl-p-4">
+ <sidebar-header
+ class="block gl-pb-4! gl-mb-2"
+ :rest-job="job"
+ :job-id="job.id"
+ @updateVariables="$emit('updateVariables')"
+ />
+
+ <job-sidebar-details-container class="block gl-mb-2" />
+
+ <artifacts-block
+ v-if="hasArtifact"
+ class="block gl-mb-2"
+ :artifact="job.artifact"
+ :help-url="artifactHelpUrl"
+ />
+
+ <external-links-block
+ v-if="hasExternalLinks"
+ class="block gl-mb-2"
+ :external-links="externalLinks"
+ />
+
+ <trigger-block v-if="hasTriggers" class="block gl-mb-2" :trigger="job.trigger" />
+
+ <commit-block class="block gl-mb-2" :commit="commit" :merge-request="job.merge_request" />
+
+ <stages-dropdown
+ v-if="job.pipeline"
+ class="block gl-mb-2"
+ :pipeline="job.pipeline"
+ :selected-stage="selectedStage"
+ :stages="stages"
+ @requestSidebarStageDropdown="fetchJobsForStage"
+ />
+
+ <jobs-container v-if="jobs.length" :job-id="job.id" :jobs="jobs" />
+ </div>
+ </div>
+ <job-retry-forward-deployment-modal
+ v-if="shouldShowJobRetryForwardDeploymentModal"
+ :modal-id="$options.forwardDeploymentFailureModalId"
+ :href="job.retry_path"
+ />
+ </aside>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue
new file mode 100644
index 00000000000..5b1bf354fd4
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue
@@ -0,0 +1,64 @@
+<script>
+import { GlIcon, GlLink } from '@gitlab/ui';
+
+export default {
+ name: 'SidebarDetailRow',
+ components: {
+ GlIcon,
+ GlLink,
+ },
+ props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ value: {
+ type: String,
+ required: true,
+ },
+ helpUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ path: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ hasTitle() {
+ return this.title.length > 0;
+ },
+ hasHelpURL() {
+ return this.helpUrl.length > 0;
+ },
+ },
+};
+</script>
+<template>
+ <p class="build-sidebar-item gl-mb-2">
+ <b v-if="hasTitle" class="gl-display-flex">{{ title }}:</b>
+ <gl-link
+ v-if="path"
+ :href="path"
+ class="gl-text-blue-600!"
+ data-testid="job-sidebar-value-link"
+ >
+ {{ value }}
+ </gl-link>
+ <span v-else
+ >{{ value }}
+ <gl-link
+ v-if="hasHelpURL"
+ :href="helpUrl"
+ target="_blank"
+ data-testid="job-sidebar-help-link"
+ >
+ <gl-icon name="question-o" class="gl-ml-2 gl-text-blue-500" />
+ </gl-link>
+ </span>
+ </p>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue
new file mode 100644
index 00000000000..77e3ecb9b3c
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue
@@ -0,0 +1,168 @@
+<script>
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+// eslint-disable-next-line no-restricted-imports
+import { mapActions } from 'vuex';
+import { createAlert } from '~/alert';
+import { TYPENAME_COMMIT_STATUS } from '~/graphql_shared/constants';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { __, s__ } from '~/locale';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
+import { JOB_GRAPHQL_ERRORS, forwardDeploymentFailureModalId, PASSED_STATUS } from '~/ci/constants';
+import GetJob from '../../graphql/queries/get_job.query.graphql';
+import JobSidebarRetryButton from './job_sidebar_retry_button.vue';
+
+export default {
+ name: 'SidebarHeader',
+ i18n: {
+ cancelJobButtonLabel: s__('Job|Cancel'),
+ debug: __('Debug'),
+ eraseLogButtonLabel: s__('Job|Erase job log and artifacts'),
+ eraseLogConfirmText: s__('Job|Are you sure you want to erase this job log and artifacts?'),
+ newIssue: __('New issue'),
+ retryJobLabel: s__('Job|Retry'),
+ toggleSidebar: __('Toggle Sidebar'),
+ runAgainJobButtonLabel: s__('Job|Run again'),
+ },
+ forwardDeploymentFailureModalId,
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ GlButton,
+ JobSidebarRetryButton,
+ TooltipOnTruncate,
+ },
+ inject: ['projectPath'],
+ apollo: {
+ job: {
+ query: GetJob,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ id: convertToGraphQLId(TYPENAME_COMMIT_STATUS, this.jobId),
+ };
+ },
+ update(data) {
+ const { name, manualJob } = data?.project?.job || {};
+ return {
+ name,
+ manualJob,
+ };
+ },
+ error() {
+ createAlert({ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText });
+ },
+ },
+ },
+ props: {
+ jobId: {
+ type: Number,
+ required: true,
+ },
+ restJob: {
+ type: Object,
+ required: true,
+ default: () => ({}),
+ },
+ },
+ data() {
+ return {
+ job: {},
+ };
+ },
+ computed: {
+ buttonTitle() {
+ return this.restJob.status?.text === PASSED_STATUS
+ ? this.$options.i18n.runAgainJobButtonLabel
+ : this.$options.i18n.retryJobLabel;
+ },
+ canShowJobRetryButton() {
+ return this.restJob.retry_path && !this.$apollo.queries.job.loading;
+ },
+ isManualJob() {
+ return this.job?.manualJob;
+ },
+ retryButtonCategory() {
+ return this.restJob.status && this.restJob.recoverable ? 'primary' : 'secondary';
+ },
+ },
+ methods: {
+ ...mapActions(['toggleSidebar']),
+ },
+};
+</script>
+
+<template>
+ <div>
+ <tooltip-on-truncate :title="job.name" truncate-target="child"
+ ><h4 class="gl-mt-0 gl-mb-3 gl-text-truncate" data-testid="job-name">{{ job.name }}</h4>
+ </tooltip-on-truncate>
+ <div class="gl-display-flex gl-gap-3">
+ <gl-button
+ v-if="restJob.erase_path"
+ v-gl-tooltip.bottom
+ :title="$options.i18n.eraseLogButtonLabel"
+ :aria-label="$options.i18n.eraseLogButtonLabel"
+ :href="restJob.erase_path"
+ :data-confirm="$options.i18n.eraseLogConfirmText"
+ data-testid="job-log-erase-link"
+ data-confirm-btn-variant="danger"
+ data-method="post"
+ icon="remove"
+ />
+ <gl-button
+ v-if="restJob.new_issue_path"
+ v-gl-tooltip.bottom
+ :href="restJob.new_issue_path"
+ :title="$options.i18n.newIssue"
+ :aria-label="$options.i18n.newIssue"
+ category="secondary"
+ variant="confirm"
+ data-testid="job-new-issue"
+ icon="issue-new"
+ />
+ <gl-button
+ v-if="restJob.terminal_path"
+ v-gl-tooltip.bottom
+ :href="restJob.terminal_path"
+ :title="$options.i18n.debug"
+ :aria-label="$options.i18n.debug"
+ target="_blank"
+ icon="external-link"
+ data-testid="terminal-link"
+ />
+ <job-sidebar-retry-button
+ v-if="canShowJobRetryButton"
+ v-gl-tooltip.bottom
+ :title="buttonTitle"
+ :aria-label="buttonTitle"
+ :is-manual-job="isManualJob"
+ :category="retryButtonCategory"
+ :href="restJob.retry_path"
+ :modal-id="$options.forwardDeploymentFailureModalId"
+ variant="confirm"
+ data-testid="retry-button"
+ @updateVariablesClicked="$emit('updateVariables')"
+ />
+ <gl-button
+ v-if="restJob.cancel_path"
+ v-gl-tooltip.bottom
+ :title="$options.i18n.cancelJobButtonLabel"
+ :aria-label="$options.i18n.cancelJobButtonLabel"
+ :href="restJob.cancel_path"
+ variant="danger"
+ icon="cancel"
+ data-method="post"
+ data-testid="cancel-button"
+ rel="nofollow"
+ />
+ <gl-button
+ :aria-label="$options.i18n.toggleSidebar"
+ category="secondary"
+ class="gl-md-display-none gl-ml-2"
+ icon="chevron-double-lg-right"
+ @click="toggleSidebar"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue
new file mode 100644
index 00000000000..ebef3ecaa3f
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue
@@ -0,0 +1,130 @@
+<script>
+// eslint-disable-next-line no-restricted-imports
+import { mapState } from 'vuex';
+import { GlBadge } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
+import { __, sprintf } from '~/locale';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+import DetailRow from './sidebar_detail_row.vue';
+
+export default {
+ name: 'JobSidebarDetailsContainer',
+ components: {
+ DetailRow,
+ GlBadge,
+ },
+ mixins: [timeagoMixin],
+ computed: {
+ ...mapState(['job']),
+ coverage() {
+ return `${this.job.coverage}%`;
+ },
+ duration() {
+ return timeIntervalInWords(this.job.duration);
+ },
+ durationTitle() {
+ return this.job.finished_at ? __('Duration') : __('Elapsed time');
+ },
+ erasedAt() {
+ return this.timeFormatted(this.job.erased_at);
+ },
+ finishedAt() {
+ return this.timeFormatted(this.job.finished_at);
+ },
+ hasTags() {
+ return this.job?.tags?.length;
+ },
+ hasTimeout() {
+ return this.job?.metadata?.timeout_human_readable ?? false;
+ },
+ hasAnyDetail() {
+ return Boolean(
+ this.job.duration ||
+ this.job.finished_at ||
+ this.job.erased_at ||
+ this.job.queued_duration ||
+ this.job.id ||
+ this.job.runner ||
+ this.job.coverage,
+ );
+ },
+ jobId() {
+ return this.job?.id ? `#${this.job.id}` : '';
+ },
+ runnerId() {
+ const { id, short_sha: token, description } = this.job.runner;
+
+ return `#${id} (${token}) ${description}`;
+ },
+ queuedDuration() {
+ return timeIntervalInWords(this.job.queued_duration);
+ },
+ shouldRenderBlock() {
+ return Boolean(this.hasAnyDetail || this.hasTimeout || this.hasTags);
+ },
+ timeout() {
+ return `${this.job?.metadata?.timeout_human_readable}${this.timeoutSource}`;
+ },
+ timeoutSource() {
+ if (!this.job?.metadata?.timeout_source) {
+ return '';
+ }
+
+ return sprintf(__(' (from %{timeoutSource})'), {
+ timeoutSource: this.job.metadata.timeout_source,
+ });
+ },
+ runnerAdminPath() {
+ return this.job?.runner?.admin_path || '';
+ },
+ },
+ i18n: {
+ COVERAGE: __('Coverage'),
+ FINISHED: __('Finished'),
+ ERASED: __('Erased'),
+ QUEUED: __('Queued'),
+ RUNNER: __('Runner'),
+ TAGS: __('Tags'),
+ TIMEOUT: __('Timeout'),
+ ID: __('Job ID'),
+ },
+ TIMEOUT_HELP_URL: helpPagePath('/ci/pipelines/settings.md', {
+ anchor: 'set-a-limit-for-how-long-jobs-can-run',
+ }),
+};
+</script>
+
+<template>
+ <div v-if="shouldRenderBlock">
+ <detail-row v-if="job.duration" :value="duration" :title="durationTitle" />
+ <detail-row
+ v-if="job.finished_at"
+ :value="finishedAt"
+ data-testid="job-finished"
+ :title="$options.i18n.FINISHED"
+ />
+ <detail-row v-if="job.erased_at" :value="erasedAt" :title="$options.i18n.ERASED" />
+ <detail-row v-if="job.queued_duration" :value="queuedDuration" :title="$options.i18n.QUEUED" />
+ <detail-row
+ v-if="hasTimeout"
+ :help-url="$options.TIMEOUT_HELP_URL"
+ :value="timeout"
+ data-testid="job-timeout"
+ :title="$options.i18n.TIMEOUT"
+ />
+ <detail-row v-if="job.id" :value="jobId" :title="$options.i18n.ID" />
+ <detail-row
+ v-if="job.runner"
+ :value="runnerId"
+ :title="$options.i18n.RUNNER"
+ :path="runnerAdminPath"
+ />
+ <detail-row v-if="job.coverage" :value="coverage" :title="$options.i18n.COVERAGE" />
+
+ <p v-if="hasTags" class="build-detail-row" data-testid="job-tags">
+ <span class="font-weight-bold">{{ $options.i18n.TAGS }}:</span>
+ <gl-badge v-for="(tag, i) in job.tags" :key="i" variant="info" size="sm">{{ tag }}</gl-badge>
+ </p>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue b/app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue
new file mode 100644
index 00000000000..7744395734f
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue
@@ -0,0 +1,179 @@
+<script>
+import { GlLink, GlDisclosureDropdown, GlSprintf } from '@gitlab/ui';
+import { isEmpty } from 'lodash';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import { Mousetrap } from '~/lib/mousetrap';
+import { s__ } from '~/locale';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import { clickCopyToClipboardButton } from '~/behaviors/copy_to_clipboard';
+import { keysFor, MR_COPY_SOURCE_BRANCH_NAME } from '~/behaviors/shortcuts/keybindings';
+
+export default {
+ components: {
+ ClipboardButton,
+ GlDisclosureDropdown,
+ GlLink,
+ GlSprintf,
+ CiBadgeLink,
+ },
+ props: {
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ stages: {
+ type: Array,
+ required: true,
+ },
+ selectedStage: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ dropdownItems() {
+ return this.stages.map((stage) => ({
+ text: stage.name,
+ action: () => {
+ this.onStageClick(stage);
+ },
+ }));
+ },
+
+ hasRef() {
+ return !isEmpty(this.pipeline.ref);
+ },
+ isTriggeredByMergeRequest() {
+ return Boolean(this.pipeline.merge_request);
+ },
+ isMergeRequestPipeline() {
+ return Boolean(this.pipeline.flags && this.pipeline.flags.merge_request_pipeline);
+ },
+ pipelineInfo() {
+ if (!this.hasRef) {
+ return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status}');
+ }
+ if (!this.isTriggeredByMergeRequest) {
+ return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status} for %{ref}');
+ }
+ if (!this.isMergeRequestPipeline) {
+ return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status} for %{mrId} with %{source}');
+ }
+
+ return s__(
+ 'Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into %{target}',
+ );
+ },
+ },
+ mounted() {
+ Mousetrap.bind(keysFor(MR_COPY_SOURCE_BRANCH_NAME), this.handleKeyboardCopy);
+ },
+ beforeDestroy() {
+ Mousetrap.unbind(keysFor(MR_COPY_SOURCE_BRANCH_NAME));
+ },
+ methods: {
+ onStageClick(stage) {
+ this.$emit('requestSidebarStageDropdown', stage);
+ },
+ handleKeyboardCopy() {
+ let button;
+
+ if (!this.hasRef) {
+ return;
+ }
+ if (!this.isTriggeredByMergeRequest) {
+ button = this.$refs['copy-source-ref-link'];
+ } else {
+ button = this.$refs['copy-source-branch-link'];
+ }
+
+ clickCopyToClipboardButton(button.$el);
+ },
+ },
+};
+</script>
+<template>
+ <div class="dropdown">
+ <div class="gl-display-flex gl-flex-wrap gl-gap-2 js-pipeline-info" data-testid="pipeline-info">
+ <gl-sprintf :message="pipelineInfo">
+ <template #bold="{ content }">
+ <span class="gl-display-flex gl-font-weight-bold">{{ content }}</span>
+ </template>
+ <template #id>
+ <gl-link
+ :href="pipeline.path"
+ class="js-pipeline-path link-commit gl-text-blue-500!"
+ data-testid="pipeline-path"
+ >#{{ pipeline.id }}</gl-link
+ >
+ </template>
+ <template #status>
+ <ci-badge-link
+ :status="pipeline.details.status"
+ size="sm"
+ data-testid="pipeline-status-link"
+ />
+ </template>
+ <template #mrId>
+ <gl-link
+ :href="pipeline.merge_request.path"
+ class="link-commit gl-text-blue-500!"
+ data-testid="mr-link"
+ >!{{ pipeline.merge_request.iid }}</gl-link
+ >
+ </template>
+ <template #ref>
+ <gl-link
+ :href="pipeline.ref.path"
+ class="link-commit ref-name gl-mt-1"
+ data-testid="source-ref-link"
+ >{{ pipeline.ref.name }}</gl-link
+ ><clipboard-button
+ ref="copy-source-ref-link"
+ :text="pipeline.ref.name"
+ :title="__('Copy reference')"
+ category="tertiary"
+ size="small"
+ data-testid="copy-source-ref-link"
+ />
+ </template>
+ <template #source>
+ <gl-link
+ :href="pipeline.merge_request.source_branch_path"
+ class="link-commit ref-name gl-mt-1"
+ data-testid="source-branch-link"
+ >{{ pipeline.merge_request.source_branch }}</gl-link
+ ><clipboard-button
+ ref="copy-source-branch-link"
+ :text="pipeline.merge_request.source_branch"
+ :title="__('Copy branch name')"
+ category="tertiary"
+ size="small"
+ data-testid="copy-source-branch-link"
+ />
+ </template>
+ <template #target>
+ <gl-link
+ :href="pipeline.merge_request.target_branch_path"
+ class="link-commit ref-name gl-mt-1"
+ data-testid="target-branch-link"
+ >{{ pipeline.merge_request.target_branch }}</gl-link
+ ><clipboard-button
+ :text="pipeline.merge_request.target_branch"
+ :title="__('Copy branch name')"
+ category="tertiary"
+ size="small"
+ data-testid="copy-target-branch-link"
+ />
+ </template>
+ </gl-sprintf>
+ </div>
+
+ <gl-disclosure-dropdown
+ :toggle-text="selectedStage"
+ :items="dropdownItems"
+ block
+ class="gl-mt-2"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/trigger_block.vue b/app/assets/javascripts/ci/job_details/components/sidebar/trigger_block.vue
new file mode 100644
index 00000000000..315587a3376
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/sidebar/trigger_block.vue
@@ -0,0 +1,94 @@
+<script>
+import { GlButton, GlTableLite } from '@gitlab/ui';
+import { __ } from '~/locale';
+
+const DEFAULT_TD_CLASSES = 'gl-font-sm!';
+
+export default {
+ fields: [
+ {
+ key: 'key',
+ label: __('Key'),
+ tdAttr: { 'data-testid': 'trigger-build-key' },
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ {
+ key: 'value',
+ label: __('Value'),
+ tdAttr: { 'data-testid': 'trigger-build-value' },
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ ],
+ components: {
+ GlButton,
+ GlTableLite,
+ },
+ props: {
+ trigger: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ showVariableValues: false,
+ };
+ },
+ computed: {
+ hasVariables() {
+ return this.trigger.variables.length > 0;
+ },
+ getToggleButtonText() {
+ return this.showVariableValues ? __('Hide values') : __('Reveal values');
+ },
+ hasValues() {
+ return this.trigger.variables.some((v) => v.value);
+ },
+ },
+ methods: {
+ toggleValues() {
+ this.showVariableValues = !this.showVariableValues;
+ },
+ getDisplayValue(value) {
+ return this.showVariableValues ? value : '••••••';
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <p
+ v-if="trigger.short_token"
+ :class="{ 'gl-mb-2': hasVariables, 'gl-mb-0': !hasVariables }"
+ data-testid="trigger-short-token"
+ >
+ <span class="gl-font-weight-bold">{{ __('Trigger token:') }}</span> {{ trigger.short_token }}
+ </p>
+
+ <template v-if="hasVariables">
+ <p class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
+ <span class="gl-display-flex gl-font-weight-bold">{{ __('Trigger variables') }}</span>
+
+ <gl-button
+ v-if="hasValues"
+ class="gl-mt-2"
+ size="small"
+ data-testid="trigger-reveal-values-button"
+ @click="toggleValues"
+ >{{ getToggleButtonText }}</gl-button
+ >
+ </p>
+
+ <gl-table-lite :items="trigger.variables" :fields="$options.fields" small bordered fixed>
+ <template #cell(key)="{ item }">
+ <span class="gl-overflow-break-word">{{ item.key }}</span>
+ </template>
+
+ <template #cell(value)="data">
+ <span class="gl-overflow-break-word">{{ getDisplayValue(data.value) }}</span>
+ </template>
+ </gl-table-lite>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/components/stuck_block.vue b/app/assets/javascripts/ci/job_details/components/stuck_block.vue
new file mode 100644
index 00000000000..8c73f09daea
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/components/stuck_block.vue
@@ -0,0 +1,91 @@
+<script>
+import { GlAlert, GlBadge, GlLink, GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
+/**
+ * Renders Stuck Runners block for job's view.
+ */
+export default {
+ components: {
+ GlAlert,
+ GlBadge,
+ GlLink,
+ GlSprintf,
+ },
+ props: {
+ hasOfflineRunnersForProject: {
+ type: Boolean,
+ required: true,
+ },
+ tags: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ runnersPath: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ hasNoRunnersWithCorrespondingTags() {
+ return this.tags.length > 0;
+ },
+ protectedBranchSettingsDocsLink() {
+ return `${DOCS_URL}/runner/security/index.html#reduce-the-security-risk-of-using-privileged-containers`;
+ },
+ stuckData() {
+ if (this.hasNoRunnersWithCorrespondingTags) {
+ return {
+ text: s__(
+ `Job|This job is stuck because of one of the following problems. There are no active runners online, no runners for the %{linkStart}protected branch%{linkEnd}, or no runners that match all of the job's tags:`,
+ ),
+ dataTestId: 'job-stuck-with-tags',
+ showTags: true,
+ };
+ }
+ if (this.hasOfflineRunnersForProject) {
+ return {
+ text: s__(`Job|This job is stuck because the project
+ doesn't have any runners online assigned to it.`),
+ dataTestId: 'job-stuck-no-runners',
+ showTags: false,
+ };
+ }
+
+ return {
+ text: s__(`Job|This job is stuck because you don't
+ have any active runners that can run this job.`),
+ dataTestId: 'job-stuck-no-active-runners',
+ showTags: false,
+ };
+ },
+ },
+};
+</script>
+<template>
+ <gl-alert variant="warning" :dismissible="false">
+ <p class="gl-mb-0" :data-testid="stuckData.dataTestId">
+ <gl-sprintf :message="stuckData.text">
+ <template #link="{ content }">
+ <a
+ class="gl-display-inline-block"
+ :href="protectedBranchSettingsDocsLink"
+ target="_blank"
+ >
+ {{ content }}
+ </a>
+ </template>
+ </gl-sprintf>
+ <template v-if="stuckData.showTags">
+ <gl-badge v-for="tag in tags" :key="tag" variant="info">
+ {{ tag }}
+ </gl-badge>
+ </template>
+ </p>
+ {{ __('Go to project') }}
+ <gl-link v-if="runnersPath" :href="runnersPath">
+ {{ __('CI settings') }}
+ </gl-link>
+ </gl-alert>
+</template>
diff --git a/app/assets/javascripts/jobs/components/job/unmet_prerequisites_block.vue b/app/assets/javascripts/ci/job_details/components/unmet_prerequisites_block.vue
index c9747ca9f02..c9747ca9f02 100644
--- a/app/assets/javascripts/jobs/components/job/unmet_prerequisites_block.vue
+++ b/app/assets/javascripts/ci/job_details/components/unmet_prerequisites_block.vue
diff --git a/app/assets/javascripts/ci/job_details/graphql/fragments/ci_job.fragment.graphql b/app/assets/javascripts/ci/job_details/graphql/fragments/ci_job.fragment.graphql
new file mode 100644
index 00000000000..7fb887b2dd4
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/graphql/fragments/ci_job.fragment.graphql
@@ -0,0 +1,11 @@
+#import "~/ci/job_details/graphql/fragments/ci_variable.fragment.graphql"
+
+fragment BaseCiJob on CiJob {
+ id
+ manualVariables {
+ nodes {
+ ...ManualCiVariable
+ }
+ }
+ __typename
+}
diff --git a/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql b/app/assets/javascripts/ci/job_details/graphql/fragments/ci_variable.fragment.graphql
index 0479df7bc4c..0479df7bc4c 100644
--- a/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql
+++ b/app/assets/javascripts/ci/job_details/graphql/fragments/ci_variable.fragment.graphql
diff --git a/app/assets/javascripts/ci/job_details/graphql/mutations/job_play_with_variables.mutation.graphql b/app/assets/javascripts/ci/job_details/graphql/mutations/job_play_with_variables.mutation.graphql
new file mode 100644
index 00000000000..5d8a7b4c6f6
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/graphql/mutations/job_play_with_variables.mutation.graphql
@@ -0,0 +1,11 @@
+#import "~/ci/job_details/graphql/fragments/ci_job.fragment.graphql"
+
+mutation playJobWithVariables($id: CiBuildID!, $variables: [CiVariableInput!]) {
+ jobPlay(input: { id: $id, variables: $variables }) {
+ job {
+ ...BaseCiJob
+ webPath
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/ci/job_details/graphql/mutations/job_retry_with_variables.mutation.graphql b/app/assets/javascripts/ci/job_details/graphql/mutations/job_retry_with_variables.mutation.graphql
new file mode 100644
index 00000000000..cd66a30ce63
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/graphql/mutations/job_retry_with_variables.mutation.graphql
@@ -0,0 +1,11 @@
+#import "~/ci/job_details/graphql/fragments/ci_job.fragment.graphql"
+
+mutation retryJobWithVariables($id: CiBuildID!, $variables: [CiVariableInput!]) {
+ jobRetry(input: { id: $id, variables: $variables }) {
+ job {
+ ...BaseCiJob
+ webPath
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/ci/job_details/graphql/queries/get_job.query.graphql b/app/assets/javascripts/ci/job_details/graphql/queries/get_job.query.graphql
new file mode 100644
index 00000000000..a521ec2bb72
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/graphql/queries/get_job.query.graphql
@@ -0,0 +1,12 @@
+#import "~/ci/job_details/graphql/fragments/ci_job.fragment.graphql"
+
+query getJob($fullPath: ID!, $id: JobID!) {
+ project(fullPath: $fullPath) {
+ id
+ job(id: $id) {
+ ...BaseCiJob
+ manualJob
+ name
+ }
+ }
+}
diff --git a/app/assets/javascripts/ci/job_details/index.js b/app/assets/javascripts/ci/job_details/index.js
new file mode 100644
index 00000000000..5a1ecf2fff3
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/index.js
@@ -0,0 +1,69 @@
+import { GlToast } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import JobApp from './job_app.vue';
+import createStore from './store';
+
+Vue.use(VueApollo);
+Vue.use(GlToast);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+const initializeJobPage = (element) => {
+ const store = createStore();
+
+ // Let's start initializing the store (i.e. fetching data) right away
+ store.dispatch('init', element.dataset);
+
+ const {
+ artifactHelpUrl,
+ deploymentHelpUrl,
+ runnerSettingsUrl,
+ subscriptionsMoreMinutesUrl,
+ endpoint,
+ pagePath,
+ logState,
+ buildStatus,
+ projectPath,
+ retryOutdatedJobDocsUrl,
+ aiRootCauseAnalysisAvailable,
+ } = element.dataset;
+
+ return new Vue({
+ el: element,
+ apolloProvider,
+ store,
+ components: {
+ JobApp,
+ },
+ provide: {
+ projectPath,
+ retryOutdatedJobDocsUrl,
+ aiRootCauseAnalysisAvailable: parseBoolean(aiRootCauseAnalysisAvailable),
+ },
+ render(createElement) {
+ return createElement('job-app', {
+ props: {
+ artifactHelpUrl,
+ deploymentHelpUrl,
+ runnerSettingsUrl,
+ subscriptionsMoreMinutesUrl,
+ endpoint,
+ pagePath,
+ logState,
+ buildStatus,
+ projectPath,
+ },
+ });
+ },
+ });
+};
+
+export default () => {
+ const jobElement = document.getElementById('js-job-page');
+ initializeJobPage(jobElement);
+};
diff --git a/app/assets/javascripts/ci/job_details/job_app.vue b/app/assets/javascripts/ci/job_details/job_app.vue
new file mode 100644
index 00000000000..5137ebfeaa8
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/job_app.vue
@@ -0,0 +1,349 @@
+<script>
+import { GlLoadingIcon, GlIcon, GlAlert } from '@gitlab/ui';
+import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import { throttle, isEmpty } from 'lodash';
+// eslint-disable-next-line no-restricted-imports
+import { mapGetters, mapState, mapActions } from 'vuex';
+import LogTopBar from 'ee_else_ce/ci/job_details/components/job_log_controllers.vue';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
+import { __, sprintf } from '~/locale';
+import delayedJobMixin from '~/ci/mixins/delayed_job_mixin';
+import Log from '~/ci/job_details/components/log/log.vue';
+import { MANUAL_STATUS } from '~/ci/constants';
+import EmptyState from './components/empty_state.vue';
+import EnvironmentsBlock from './components/environments_block.vue';
+import ErasedBlock from './components/erased_block.vue';
+import JobHeader from './components/job_header.vue';
+import StuckBlock from './components/stuck_block.vue';
+import UnmetPrerequisitesBlock from './components/unmet_prerequisites_block.vue';
+import Sidebar from './components/sidebar/sidebar.vue';
+
+export default {
+ name: 'JobPageApp',
+ components: {
+ JobHeader,
+ EmptyState,
+ EnvironmentsBlock,
+ ErasedBlock,
+ GlIcon,
+ Log,
+ LogTopBar,
+ StuckBlock,
+ UnmetPrerequisitesBlock,
+ Sidebar,
+ GlLoadingIcon,
+ SharedRunner: () => import('ee_component/ci/runner/components/shared_runner_limit_block.vue'),
+ GlAlert,
+ },
+ directives: {
+ SafeHtml,
+ },
+ mixins: [delayedJobMixin],
+ props: {
+ artifactHelpUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ runnerSettingsUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ deploymentHelpUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ terminalPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ subscriptionsMoreMinutesUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ searchResults: [],
+ showUpdateVariablesState: false,
+ };
+ },
+ computed: {
+ ...mapState([
+ 'isLoading',
+ 'job',
+ 'isSidebarOpen',
+ 'jobLog',
+ 'isJobLogComplete',
+ 'jobLogSize',
+ 'isJobLogSizeVisible',
+ 'isScrollBottomDisabled',
+ 'isScrollTopDisabled',
+ 'isScrolledToBottomBeforeReceivingJobLog',
+ 'hasError',
+ 'selectedStage',
+ ]),
+ ...mapGetters([
+ 'headerTime',
+ 'hasUnmetPrerequisitesFailure',
+ 'shouldRenderCalloutMessage',
+ 'shouldRenderTriggeredLabel',
+ 'hasEnvironment',
+ 'shouldRenderSharedRunnerLimitWarning',
+ 'hasJobLog',
+ 'emptyStateIllustration',
+ 'isScrollingDown',
+ 'emptyStateAction',
+ 'hasOfflineRunnersForProject',
+ ]),
+
+ shouldRenderContent() {
+ return !this.isLoading && !this.hasError;
+ },
+
+ emptyStateTitle() {
+ const { emptyStateIllustration, remainingTime } = this;
+ const { title } = emptyStateIllustration;
+
+ if (this.isDelayedJob) {
+ return sprintf(title, { remainingTime });
+ }
+
+ return title;
+ },
+
+ shouldRenderHeaderCallout() {
+ return this.shouldRenderCalloutMessage && !this.hasUnmetPrerequisitesFailure;
+ },
+
+ isJobRetryable() {
+ return Boolean(this.job.retry_path);
+ },
+
+ jobName() {
+ return sprintf(__('Job %{jobName}'), { jobName: this.job.name });
+ },
+ },
+ watch: {
+ // Once the job log is loaded,
+ // fetch the stages for the dropdown on the sidebar
+ job(newVal, oldVal) {
+ if (isEmpty(oldVal) && !isEmpty(newVal.pipeline)) {
+ const stages = this.job.pipeline.details.stages || [];
+
+ const defaultStage = stages.find((stage) => stage && stage.name === this.selectedStage);
+
+ if (defaultStage) {
+ this.fetchJobsForStage(defaultStage);
+ }
+ }
+
+ // Only poll for job log if we are not in the manual variables form empty state.
+ // This will be handled more elegantly in the future with GraphQL in https://gitlab.com/gitlab-org/gitlab/-/issues/389597
+ if (newVal?.status?.group !== MANUAL_STATUS && !this.showUpdateVariablesState) {
+ this.fetchJobLog();
+ }
+ },
+ },
+ created() {
+ this.throttled = throttle(this.toggleScrollButtons, 100);
+
+ window.addEventListener('resize', this.onResize);
+ window.addEventListener('scroll', this.updateScroll);
+ },
+ mounted() {
+ this.updateSidebar();
+ },
+ beforeDestroy() {
+ this.stopPollingJobLog();
+ this.stopPolling();
+ window.removeEventListener('resize', this.onResize);
+ window.removeEventListener('scroll', this.updateScroll);
+ },
+ methods: {
+ ...mapActions([
+ 'fetchJobLog',
+ 'fetchJobsForStage',
+ 'hideSidebar',
+ 'showSidebar',
+ 'toggleSidebar',
+ 'scrollBottom',
+ 'scrollTop',
+ 'stopPollingJobLog',
+ 'stopPolling',
+ 'toggleScrollButtons',
+ 'toggleScrollAnimation',
+ ]),
+ onHideManualVariablesForm() {
+ this.showUpdateVariablesState = false;
+ },
+ onResize() {
+ this.updateSidebar();
+ this.updateScroll();
+ },
+ onUpdateVariables() {
+ this.showUpdateVariablesState = true;
+ },
+ updateSidebar() {
+ const breakpoint = bp.getBreakpointSize();
+ if (breakpoint === 'xs' || breakpoint === 'sm') {
+ this.hideSidebar();
+ } else if (!this.isSidebarOpen) {
+ this.showSidebar();
+ }
+ },
+ updateScroll() {
+ if (!isScrolledToBottom()) {
+ this.toggleScrollAnimation(false);
+ } else if (this.isScrollingDown) {
+ this.toggleScrollAnimation(true);
+ }
+
+ this.throttled();
+ },
+ setSearchResults(searchResults) {
+ this.searchResults = searchResults;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-6" />
+
+ <template v-else-if="shouldRenderContent">
+ <div class="build-page" data-testid="job-content">
+ <!-- Header Section -->
+ <header>
+ <div class="build-header top-area">
+ <job-header
+ :status="job.status"
+ :time="headerTime"
+ :user="job.user"
+ :should-render-triggered-label="shouldRenderTriggeredLabel"
+ :name="jobName"
+ @clickedSidebarButton="toggleSidebar"
+ />
+ </div>
+ <gl-alert
+ v-if="shouldRenderHeaderCallout"
+ variant="danger"
+ class="gl-mt-3"
+ :dismissible="false"
+ >
+ <div v-safe-html="job.callout_message"></div>
+ </gl-alert>
+ </header>
+ <!-- EO Header Section -->
+
+ <!-- Body Section -->
+ <stuck-block
+ v-if="job.stuck"
+ :has-offline-runners-for-project="hasOfflineRunnersForProject"
+ :tags="job.tags"
+ :runners-path="runnerSettingsUrl"
+ />
+
+ <unmet-prerequisites-block
+ v-if="hasUnmetPrerequisitesFailure"
+ :help-path="deploymentHelpUrl"
+ />
+
+ <shared-runner
+ v-if="shouldRenderSharedRunnerLimitWarning"
+ :quota-used="job.runners.quota.used"
+ :quota-limit="job.runners.quota.limit"
+ :project-path="projectPath"
+ :subscriptions-more-minutes-url="subscriptionsMoreMinutesUrl"
+ />
+
+ <environments-block
+ v-if="hasEnvironment"
+ :deployment-status="job.deployment_status"
+ :deployment-cluster="job.deployment_cluster"
+ :icon-status="job.status"
+ />
+
+ <erased-block
+ v-if="job.erased_at"
+ data-testid="job-erased-block"
+ :user="job.erased_by"
+ :erased-at="job.erased_at"
+ />
+
+ <div
+ v-if="job.archived"
+ class="gl-mt-3 gl-py-2 gl-px-3 gl-align-items-center gl-z-index-1 gl-m-auto archived-job"
+ :class="{ 'sticky-top gl-border-bottom-0': hasJobLog }"
+ data-testid="archived-job"
+ >
+ <gl-icon name="lock" class="gl-vertical-align-bottom" />
+ {{ __('This job is archived. Only the complete pipeline can be retried.') }}
+ </div>
+ <!-- job log -->
+ <div
+ v-if="hasJobLog && !showUpdateVariablesState"
+ class="build-log-container gl-relative"
+ :class="{ 'gl-mt-3': !job.archived }"
+ >
+ <log-top-bar
+ :class="{
+ 'has-archived-block': job.archived,
+ }"
+ :size="jobLogSize"
+ :raw-path="job.raw_path"
+ :is-scroll-bottom-disabled="isScrollBottomDisabled"
+ :is-scroll-top-disabled="isScrollTopDisabled"
+ :is-job-log-size-visible="isJobLogSizeVisible"
+ :is-scrolling-down="isScrollingDown"
+ :is-complete="isJobLogComplete"
+ :job-log="jobLog"
+ @scrollJobLogTop="scrollTop"
+ @scrollJobLogBottom="scrollBottom"
+ @searchResults="setSearchResults"
+ />
+ <log :job-log="jobLog" :is-complete="isJobLogComplete" :search-results="searchResults" />
+ </div>
+ <!-- EO job log -->
+
+ <!-- empty state -->
+ <empty-state
+ v-if="!hasJobLog || showUpdateVariablesState"
+ :illustration-path="emptyStateIllustration.image"
+ :illustration-size-class="emptyStateIllustration.size"
+ :is-retryable="isJobRetryable"
+ :job-id="job.id"
+ :title="emptyStateTitle"
+ :content="emptyStateIllustration.content"
+ :action="emptyStateAction"
+ :playable="job.playable"
+ :scheduled="job.scheduled"
+ @hideManualVariablesForm="onHideManualVariablesForm()"
+ />
+ <!-- EO empty state -->
+
+ <!-- EO Body Section -->
+ </div>
+ </template>
+
+ <sidebar
+ v-if="shouldRenderContent"
+ :class="{
+ 'right-sidebar-expanded': isSidebarOpen,
+ 'right-sidebar-collapsed': !isSidebarOpen,
+ }"
+ :artifact-help-url="artifactHelpUrl"
+ data-testid="job-sidebar"
+ @updateVariables="onUpdateVariables()"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/job_details/store/actions.js b/app/assets/javascripts/ci/job_details/store/actions.js
new file mode 100644
index 00000000000..33d83689e61
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/store/actions.js
@@ -0,0 +1,277 @@
+import Visibility from 'visibilityjs';
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { setFaviconOverlay, resetFavicon } from '~/lib/utils/favicon';
+import { HTTP_STATUS_FORBIDDEN } from '~/lib/utils/http_status';
+import Poll from '~/lib/utils/poll';
+import {
+ canScroll,
+ isScrolledToBottom,
+ isScrolledToTop,
+ scrollDown,
+ scrollUp,
+} from '~/lib/utils/scroll_utils';
+import { __ } from '~/locale';
+import { reportToSentry } from '~/ci/utils';
+import * as types from './mutation_types';
+
+export const init = ({ dispatch }, { endpoint, logState, pagePath }) => {
+ dispatch('setJobEndpoint', endpoint);
+ dispatch('setJobLogOptions', {
+ logState,
+ pagePath,
+ });
+
+ return dispatch('fetchJob');
+};
+
+export const setJobEndpoint = ({ commit }, endpoint) => commit(types.SET_JOB_ENDPOINT, endpoint);
+export const setJobLogOptions = ({ commit }, options) => commit(types.SET_JOB_LOG_OPTIONS, options);
+
+export const hideSidebar = ({ commit }) => commit(types.HIDE_SIDEBAR);
+export const showSidebar = ({ commit }) => commit(types.SHOW_SIDEBAR);
+
+export const toggleSidebar = ({ dispatch, state }) => {
+ if (state.isSidebarOpen) {
+ dispatch('hideSidebar');
+ } else {
+ dispatch('showSidebar');
+ }
+};
+
+let eTagPoll;
+
+export const clearEtagPoll = () => {
+ eTagPoll = null;
+};
+
+export const stopPolling = () => {
+ if (eTagPoll) eTagPoll.stop();
+};
+
+export const restartPolling = () => {
+ if (eTagPoll) eTagPoll.restart();
+};
+
+export const requestJob = ({ commit }) => commit(types.REQUEST_JOB);
+
+export const fetchJob = ({ state, dispatch }) => {
+ dispatch('requestJob');
+
+ eTagPoll = new Poll({
+ resource: {
+ getJob(endpoint) {
+ return axios.get(endpoint);
+ },
+ },
+ data: state.jobEndpoint,
+ method: 'getJob',
+ successCallback: ({ data }) => dispatch('receiveJobSuccess', data),
+ errorCallback: () => dispatch('receiveJobError'),
+ });
+
+ if (!Visibility.hidden()) {
+ eTagPoll.makeRequest();
+ } else {
+ axios
+ .get(state.jobEndpoint)
+ .then(({ data }) => dispatch('receiveJobSuccess', data))
+ .catch(() => dispatch('receiveJobError'));
+ }
+
+ Visibility.change(() => {
+ if (!Visibility.hidden()) {
+ dispatch('restartPolling');
+ } else {
+ dispatch('stopPolling');
+ }
+ });
+};
+
+export const receiveJobSuccess = ({ commit }, data = {}) => {
+ commit(types.RECEIVE_JOB_SUCCESS, data);
+
+ if (data.status && data.status.favicon) {
+ setFaviconOverlay(data.status.favicon);
+ } else {
+ resetFavicon();
+ }
+};
+export const receiveJobError = ({ commit }) => {
+ commit(types.RECEIVE_JOB_ERROR);
+ createAlert({
+ message: __('An error occurred while fetching the job.'),
+ });
+ resetFavicon();
+};
+
+/**
+ * Job Log
+ */
+export const scrollTop = ({ dispatch }) => {
+ scrollUp();
+ dispatch('toggleScrollButtons');
+};
+
+export const scrollBottom = ({ dispatch }) => {
+ scrollDown();
+ dispatch('toggleScrollButtons');
+};
+
+/**
+ * Responsible for toggling the disabled state of the scroll buttons
+ */
+export const toggleScrollButtons = ({ dispatch }) => {
+ if (canScroll()) {
+ if (isScrolledToTop()) {
+ dispatch('disableScrollTop');
+ dispatch('enableScrollBottom');
+ } else if (isScrolledToBottom()) {
+ dispatch('disableScrollBottom');
+ dispatch('enableScrollTop');
+ } else {
+ dispatch('enableScrollTop');
+ dispatch('enableScrollBottom');
+ }
+ } else {
+ dispatch('disableScrollBottom');
+ dispatch('disableScrollTop');
+ }
+};
+
+export const disableScrollBottom = ({ commit }) => commit(types.DISABLE_SCROLL_BOTTOM);
+export const disableScrollTop = ({ commit }) => commit(types.DISABLE_SCROLL_TOP);
+export const enableScrollBottom = ({ commit }) => commit(types.ENABLE_SCROLL_BOTTOM);
+export const enableScrollTop = ({ commit }) => commit(types.ENABLE_SCROLL_TOP);
+
+/**
+ * While the automatic scroll down is active,
+ * we show the scroll down button with an animation
+ */
+export const toggleScrollAnimation = ({ commit }, toggle) =>
+ commit(types.TOGGLE_SCROLL_ANIMATION, toggle);
+
+/**
+ * Responsible to handle automatic scroll
+ */
+export const toggleScrollisInBottom = ({ commit }, toggle) => {
+ commit(types.TOGGLE_IS_SCROLL_IN_BOTTOM_BEFORE_UPDATING_JOB_LOG, toggle);
+};
+
+export const requestJobLog = ({ commit }) => commit(types.REQUEST_JOB_LOG);
+
+export const fetchJobLog = ({ dispatch, state }) =>
+ // update trace endpoint once BE compeletes trace re-naming in #340626
+ axios
+ .get(`${state.jobLogEndpoint}/trace.json`, {
+ params: { state: state.jobLogState },
+ })
+ .then(({ data }) => {
+ dispatch('toggleScrollisInBottom', isScrolledToBottom());
+ dispatch('receiveJobLogSuccess', data);
+
+ if (data.complete) {
+ dispatch('stopPollingJobLog');
+ } else if (!state.jobLogTimeout) {
+ dispatch('startPollingJobLog');
+ }
+ })
+ .catch((e) => {
+ if (e.response.status === HTTP_STATUS_FORBIDDEN) {
+ dispatch('receiveJobLogUnauthorizedError');
+ } else {
+ reportToSentry('job_actions', e);
+ dispatch('receiveJobLogError');
+ }
+ });
+
+export const startPollingJobLog = ({ dispatch, commit }) => {
+ const jobLogTimeout = setTimeout(() => {
+ commit(types.SET_JOB_LOG_TIMEOUT, 0);
+ dispatch('fetchJobLog');
+ }, 4000);
+
+ commit(types.SET_JOB_LOG_TIMEOUT, jobLogTimeout);
+};
+
+export const stopPollingJobLog = ({ state, commit }) => {
+ clearTimeout(state.jobLogTimeout);
+ commit(types.SET_JOB_LOG_TIMEOUT, 0);
+ commit(types.STOP_POLLING_JOB_LOG);
+};
+
+export const receiveJobLogSuccess = ({ commit }, log) => commit(types.RECEIVE_JOB_LOG_SUCCESS, log);
+
+export const receiveJobLogError = ({ dispatch }) => {
+ dispatch('stopPollingJobLog');
+ createAlert({
+ message: __('An error occurred while fetching the job log.'),
+ });
+};
+
+export const receiveJobLogUnauthorizedError = ({ dispatch }) => {
+ dispatch('stopPollingJobLog');
+ createAlert({
+ message: __('The current user is not authorized to access the job log.'),
+ });
+};
+/**
+ * When the user clicks a collapsible line in the job
+ * log, we commit a mutation to update the state
+ *
+ * @param {Object} section
+ */
+export const toggleCollapsibleLine = ({ commit }, section) =>
+ commit(types.TOGGLE_COLLAPSIBLE_LINE, section);
+
+/**
+ * Jobs list on sidebar - depend on stages dropdown
+ */
+export const requestJobsForStage = ({ commit }, stage) =>
+ commit(types.REQUEST_JOBS_FOR_STAGE, stage);
+
+// On stage click, set selected stage + fetch job
+export const fetchJobsForStage = ({ dispatch }, stage = {}) => {
+ dispatch('requestJobsForStage', stage);
+
+ axios
+ .get(stage.dropdown_path, {
+ params: {
+ retried: 1,
+ },
+ })
+ .then(({ data }) => {
+ const retriedJobs = data.retried.map((job) => ({ ...job, retried: true }));
+ const jobs = data.latest_statuses.concat(retriedJobs);
+
+ dispatch('receiveJobsForStageSuccess', jobs);
+ })
+ .catch(() => dispatch('receiveJobsForStageError'));
+};
+export const receiveJobsForStageSuccess = ({ commit }, data) =>
+ commit(types.RECEIVE_JOBS_FOR_STAGE_SUCCESS, data);
+
+export const receiveJobsForStageError = ({ commit }) => {
+ commit(types.RECEIVE_JOBS_FOR_STAGE_ERROR);
+ createAlert({
+ message: __('An error occurred while fetching the jobs.'),
+ });
+};
+
+export const triggerManualJob = ({ state }, variables) => {
+ const parsedVariables = variables.map((variable) => {
+ const copyVar = { ...variable };
+ delete copyVar.id;
+ return copyVar;
+ });
+
+ axios
+ .post(state.job.status.action.path, {
+ job_variables_attributes: parsedVariables,
+ })
+ .catch(() =>
+ createAlert({
+ message: __('An error occurred while triggering the job.'),
+ }),
+ );
+};
diff --git a/app/assets/javascripts/jobs/store/getters.js b/app/assets/javascripts/ci/job_details/store/getters.js
index a0f9db7409d..a0f9db7409d 100644
--- a/app/assets/javascripts/jobs/store/getters.js
+++ b/app/assets/javascripts/ci/job_details/store/getters.js
diff --git a/app/assets/javascripts/jobs/store/index.js b/app/assets/javascripts/ci/job_details/store/index.js
index b9d76765d8d..b9d76765d8d 100644
--- a/app/assets/javascripts/jobs/store/index.js
+++ b/app/assets/javascripts/ci/job_details/store/index.js
diff --git a/app/assets/javascripts/jobs/store/mutation_types.js b/app/assets/javascripts/ci/job_details/store/mutation_types.js
index 4915a826b84..4915a826b84 100644
--- a/app/assets/javascripts/jobs/store/mutation_types.js
+++ b/app/assets/javascripts/ci/job_details/store/mutation_types.js
diff --git a/app/assets/javascripts/jobs/store/mutations.js b/app/assets/javascripts/ci/job_details/store/mutations.js
index b7d7006ee61..b7d7006ee61 100644
--- a/app/assets/javascripts/jobs/store/mutations.js
+++ b/app/assets/javascripts/ci/job_details/store/mutations.js
diff --git a/app/assets/javascripts/jobs/store/state.js b/app/assets/javascripts/ci/job_details/store/state.js
index dfff65c364d..dfff65c364d 100644
--- a/app/assets/javascripts/jobs/store/state.js
+++ b/app/assets/javascripts/ci/job_details/store/state.js
diff --git a/app/assets/javascripts/jobs/store/utils.js b/app/assets/javascripts/ci/job_details/store/utils.js
index bc76901026d..bc76901026d 100644
--- a/app/assets/javascripts/jobs/store/utils.js
+++ b/app/assets/javascripts/ci/job_details/store/utils.js
diff --git a/app/assets/javascripts/ci/job_details/utils.js b/app/assets/javascripts/ci/job_details/utils.js
new file mode 100644
index 00000000000..4d06c241b4f
--- /dev/null
+++ b/app/assets/javascripts/ci/job_details/utils.js
@@ -0,0 +1,29 @@
+export const compactJobLog = (jobLog) => {
+ const compactedLog = [];
+
+ jobLog.forEach((obj) => {
+ // push header section line
+ if (obj.line && obj.isHeader) {
+ compactedLog.push(obj.line);
+ }
+
+ // push lines within section header
+ if (obj.lines?.length > 0) {
+ compactedLog.push(...obj.lines);
+ }
+
+ // push lines from plain log
+ if (!obj.lines && obj.content.length > 0) {
+ compactedLog.push(obj);
+ }
+ });
+
+ return compactedLog;
+};
+
+export const filterAnnotations = (annotations, type) => {
+ return [...annotations]
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .flatMap((annotationList) => annotationList.data)
+ .flatMap((annotation) => annotation[type] ?? []);
+};
diff --git a/app/assets/javascripts/ci/jobs_page/components/job_cells/actions_cell.vue b/app/assets/javascripts/ci/jobs_page/components/job_cells/actions_cell.vue
new file mode 100644
index 00000000000..609f2790869
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/components/job_cells/actions_cell.vue
@@ -0,0 +1,265 @@
+<script>
+import {
+ GlButton,
+ GlButtonGroup,
+ GlModal,
+ GlModalDirective,
+ GlSprintf,
+ GlTooltipDirective,
+} from '@gitlab/ui';
+import { reportMessageToSentry } from '~/ci/utils';
+import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import {
+ ACTIONS_DOWNLOAD_ARTIFACTS,
+ ACTIONS_START_NOW,
+ ACTIONS_UNSCHEDULE,
+ ACTIONS_PLAY,
+ ACTIONS_RETRY,
+ ACTIONS_RUN_AGAIN,
+ CANCEL,
+ GENERIC_ERROR,
+ JOB_SCHEDULED,
+ JOB_SUCCESS,
+ PLAY_JOB_CONFIRMATION_MESSAGE,
+ RUN_JOB_NOW_HEADER_TITLE,
+ FILE_TYPE_ARCHIVE,
+} from '../../constants';
+import eventHub from '../../event_hub';
+import cancelJobMutation from '../../graphql/mutations/job_cancel.mutation.graphql';
+import playJobMutation from '../../graphql/mutations/job_play.mutation.graphql';
+import retryJobMutation from '../../graphql/mutations/job_retry.mutation.graphql';
+import unscheduleJobMutation from '../../graphql/mutations/job_unschedule.mutation.graphql';
+
+export default {
+ ACTIONS_DOWNLOAD_ARTIFACTS,
+ ACTIONS_START_NOW,
+ ACTIONS_UNSCHEDULE,
+ ACTIONS_PLAY,
+ ACTIONS_RETRY,
+ CANCEL,
+ GENERIC_ERROR,
+ PLAY_JOB_CONFIRMATION_MESSAGE,
+ RUN_JOB_NOW_HEADER_TITLE,
+ jobRetry: 'jobRetry',
+ jobCancel: 'jobCancel',
+ jobPlay: 'jobPlay',
+ jobUnschedule: 'jobUnschedule',
+ playJobModalId: 'play-job-modal',
+ name: 'JobActionsCell',
+ components: {
+ GlButton,
+ GlButtonGroup,
+ GlCountdown,
+ GlModal,
+ GlSprintf,
+ },
+ directives: {
+ GlModalDirective,
+ GlTooltip: GlTooltipDirective,
+ },
+ inject: {
+ admin: {
+ default: false,
+ },
+ },
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ retryBtnDisabled: false,
+ cancelBtnDisabled: false,
+ playManualBtnDisabled: false,
+ unscheduleBtnDisabled: false,
+ };
+ },
+ computed: {
+ hasArtifacts() {
+ return this.job.artifacts.nodes.find((artifact) => artifact.fileType === FILE_TYPE_ARCHIVE);
+ },
+ artifactDownloadPath() {
+ return this.hasArtifacts.downloadPath;
+ },
+ canReadJob() {
+ return this.job.userPermissions?.readBuild;
+ },
+ canUpdateJob() {
+ return this.job.userPermissions?.updateBuild;
+ },
+ canReadArtifacts() {
+ return this.job.userPermissions?.readJobArtifacts;
+ },
+ isActive() {
+ return this.job.active;
+ },
+ manualJobPlayable() {
+ return this.job.playable && !this.admin && this.job.manualJob;
+ },
+ isRetryable() {
+ return this.job.retryable;
+ },
+ isScheduled() {
+ return this.job.status === JOB_SCHEDULED;
+ },
+ scheduledAt() {
+ return this.job.scheduledAt;
+ },
+ currentJobActionPath() {
+ return this.job.detailedStatus?.action?.path;
+ },
+ currentJobMethod() {
+ return this.job.detailedStatus?.action?.method;
+ },
+ shouldDisplayArtifacts() {
+ return this.canReadArtifacts && this.hasArtifacts;
+ },
+ retryButtonTitle() {
+ return this.job.status === JOB_SUCCESS ? ACTIONS_RUN_AGAIN : ACTIONS_RETRY;
+ },
+ },
+ methods: {
+ async postJobAction(name, mutation, redirect = false) {
+ try {
+ const {
+ data: {
+ [name]: { errors, job },
+ },
+ } = await this.$apollo.mutate({
+ mutation,
+ variables: { id: this.job.id },
+ });
+ if (errors.length > 0) {
+ reportMessageToSentry(this.$options.name, errors.join(', '), {});
+ this.showToastMessage();
+ } else if (redirect) {
+ // Retry and Play actions redirect to job detail view
+ // we don't need to refetch with jobActionPerformed event
+ redirectTo(job.detailedStatus.detailsPath); // eslint-disable-line import/no-deprecated
+ } else {
+ eventHub.$emit('jobActionPerformed');
+ }
+ } catch (failure) {
+ reportMessageToSentry(this.$options.name, failure, {});
+ this.showToastMessage();
+ }
+ },
+ showToastMessage() {
+ const toastProps = {
+ text: this.$options.GENERIC_ERROR,
+ variant: 'danger',
+ };
+
+ this.$toast.show(toastProps.text, {
+ variant: toastProps.variant,
+ });
+ },
+ cancelJob() {
+ this.cancelBtnDisabled = true;
+
+ this.postJobAction(this.$options.jobCancel, cancelJobMutation);
+ },
+ retryJob() {
+ this.retryBtnDisabled = true;
+
+ this.postJobAction(this.$options.jobRetry, retryJobMutation, true);
+ },
+ playJob() {
+ this.playManualBtnDisabled = true;
+
+ this.postJobAction(this.$options.jobPlay, playJobMutation, true);
+ },
+ unscheduleJob() {
+ this.unscheduleBtnDisabled = true;
+
+ this.postJobAction(this.$options.jobUnschedule, unscheduleJobMutation);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-button-group>
+ <template v-if="canReadJob && canUpdateJob">
+ <gl-button
+ v-if="isActive"
+ v-gl-tooltip
+ icon="cancel"
+ :title="$options.CANCEL"
+ :aria-label="$options.CANCEL"
+ :disabled="cancelBtnDisabled"
+ data-testid="cancel-button"
+ @click="cancelJob()"
+ />
+ <template v-else-if="isScheduled">
+ <gl-button icon="planning" disabled data-testid="countdown">
+ <gl-countdown :end-date-string="scheduledAt" />
+ </gl-button>
+ <gl-button
+ v-gl-modal-directive="$options.playJobModalId"
+ v-gl-tooltip
+ icon="play"
+ :title="$options.ACTIONS_START_NOW"
+ :aria-label="$options.ACTIONS_START_NOW"
+ data-testid="play-scheduled"
+ />
+ <gl-modal
+ :modal-id="$options.playJobModalId"
+ :title="$options.RUN_JOB_NOW_HEADER_TITLE"
+ @primary="playJob()"
+ >
+ <gl-sprintf :message="$options.PLAY_JOB_CONFIRMATION_MESSAGE">
+ <template #job_name>{{ job.name }}</template>
+ </gl-sprintf>
+ </gl-modal>
+ <gl-button
+ v-gl-tooltip
+ icon="time-out"
+ :title="$options.ACTIONS_UNSCHEDULE"
+ :aria-label="$options.ACTIONS_UNSCHEDULE"
+ :disabled="unscheduleBtnDisabled"
+ data-testid="unschedule"
+ @click="unscheduleJob()"
+ />
+ </template>
+ <template v-else>
+ <!--Note: This is the manual job play button -->
+ <gl-button
+ v-if="manualJobPlayable"
+ v-gl-tooltip
+ icon="play"
+ :title="$options.ACTIONS_PLAY"
+ :aria-label="$options.ACTIONS_PLAY"
+ :disabled="playManualBtnDisabled"
+ data-testid="play"
+ @click="playJob()"
+ />
+ <gl-button
+ v-else-if="isRetryable"
+ v-gl-tooltip
+ icon="retry"
+ :title="retryButtonTitle"
+ :aria-label="retryButtonTitle"
+ :method="currentJobMethod"
+ :disabled="retryBtnDisabled"
+ data-testid="retry"
+ @click="retryJob()"
+ />
+ </template>
+ </template>
+ <gl-button
+ v-if="shouldDisplayArtifacts"
+ v-gl-tooltip
+ icon="download"
+ :title="$options.ACTIONS_DOWNLOAD_ARTIFACTS"
+ :aria-label="$options.ACTIONS_DOWNLOAD_ARTIFACTS"
+ :href="artifactDownloadPath"
+ rel="nofollow"
+ download
+ data-testid="download-artifacts"
+ />
+ </gl-button-group>
+</template>
diff --git a/app/assets/javascripts/ci/jobs_page/components/job_cells/duration_cell.vue b/app/assets/javascripts/ci/jobs_page/components/job_cells/duration_cell.vue
new file mode 100644
index 00000000000..dbf1dfe7a29
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/components/job_cells/duration_cell.vue
@@ -0,0 +1,52 @@
+<script>
+import { GlIcon } from '@gitlab/ui';
+import { formatTime } from '~/lib/utils/datetime_utility';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+
+export default {
+ iconSize: 12,
+ components: {
+ GlIcon,
+ TimeAgoTooltip,
+ },
+ mixins: [timeagoMixin],
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ finishedTime() {
+ return this.job?.finishedAt;
+ },
+ duration() {
+ return this.job?.duration;
+ },
+ durationFormatted() {
+ return formatTime(this.duration * 1000);
+ },
+ hasDurationAndFinishedTime() {
+ return this.finishedTime && this.duration;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div v-if="duration" data-testid="job-duration">
+ <gl-icon name="timer" :size="$options.iconSize" data-testid="duration-icon" />
+ {{ durationFormatted }}
+ </div>
+ <div
+ v-if="finishedTime"
+ :class="{ 'gl-mt-2': hasDurationAndFinishedTime }"
+ data-testid="job-finished-time"
+ >
+ <gl-icon name="calendar" :size="$options.iconSize" data-testid="finished-time-icon" />
+ <time-ago-tooltip :time="finishedTime" />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/jobs_page/components/job_cells/job_cell.vue b/app/assets/javascripts/ci/jobs_page/components/job_cells/job_cell.vue
new file mode 100644
index 00000000000..b435eb283fd
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/components/job_cells/job_cell.vue
@@ -0,0 +1,171 @@
+<script>
+import { GlBadge, GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { s__ } from '~/locale';
+import { SUCCESS_STATUS } from '../../../constants';
+
+export default {
+ iconSize: 12,
+ badgeSize: 'sm',
+ i18n: {
+ stuckText: s__('Jobs|Job is stuck. Check runners.'),
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ GlBadge,
+ GlIcon,
+ GlLink,
+ },
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ jobId() {
+ const id = getIdFromGraphQLId(this.job.id);
+ return `#${id}`;
+ },
+ jobPath() {
+ return this.job.detailedStatus?.detailsPath;
+ },
+ jobRef() {
+ return this.job?.refName;
+ },
+ jobRefPath() {
+ return this.job?.refPath;
+ },
+ jobTags() {
+ return this.job.tags;
+ },
+ createdByTag() {
+ return this.job.createdByTag;
+ },
+ triggered() {
+ return this.job.triggered;
+ },
+ isManualJob() {
+ return this.job.manualJob;
+ },
+ successfulJob() {
+ return this.job.status === SUCCESS_STATUS;
+ },
+ showAllowedToFailBadge() {
+ return this.job.allowFailure && !this.successfulJob;
+ },
+ isScheduledJob() {
+ return Boolean(this.job.scheduledAt);
+ },
+ canReadJob() {
+ return this.job?.userPermissions?.readBuild;
+ },
+ jobStuck() {
+ return this.job?.stuck;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div class="gl-text-truncate gl-p-3 gl-mt-n3 gl-mx-n3 gl-mb-n2">
+ <gl-link
+ v-if="canReadJob"
+ class="gl-text-blue-600!"
+ :href="jobPath"
+ data-testid="job-id-link"
+ >
+ {{ jobId }}
+ </gl-link>
+
+ <span v-else data-testid="job-id-limited-access">{{ jobId }}</span>
+
+ <gl-icon
+ v-if="jobStuck"
+ v-gl-tooltip="$options.i18n.stuckText"
+ name="warning"
+ :size="$options.iconSize"
+ data-testid="stuck-icon"
+ />
+
+ <div
+ class="gl-display-flex gl-text-gray-700 gl-align-items-center gl-lg-justify-content-start gl-justify-content-end gl-mt-2"
+ >
+ <div
+ v-if="jobRef"
+ class="gl-p-2 gl-rounded-base gl-bg-gray-50 gl-max-w-15 gl-text-truncate"
+ >
+ <gl-icon
+ v-if="createdByTag"
+ name="label"
+ :size="$options.iconSize"
+ data-testid="label-icon"
+ />
+ <gl-icon v-else name="fork" :size="$options.iconSize" data-testid="fork-icon" />
+ <gl-link
+ class="gl-font-sm gl-font-monospace gl-text-gray-700 gl-hover-text-gray-900"
+ :href="job.refPath"
+ data-testid="job-ref"
+ >{{ job.refName }}</gl-link
+ >
+ </div>
+
+ <span v-else>{{ __('none') }}</span>
+ <div class="gl-ml-2 gl-p-2 gl-rounded-base gl-bg-gray-50">
+ <gl-icon class="gl-mx-2" name="commit" :size="$options.iconSize" />
+ <gl-link
+ class="gl-font-sm gl-font-monospace gl-text-gray-700 gl-hover-text-gray-900"
+ :href="job.commitPath"
+ data-testid="job-sha"
+ >{{ job.shortSha }}</gl-link
+ >
+ </div>
+ </div>
+ </div>
+
+ <div>
+ <gl-badge
+ v-for="tag in jobTags"
+ :key="tag"
+ variant="info"
+ :size="$options.badgeSize"
+ data-testid="job-tag-badge"
+ >
+ {{ tag }}
+ </gl-badge>
+
+ <gl-badge
+ v-if="triggered"
+ variant="info"
+ :size="$options.badgeSize"
+ data-testid="triggered-job-badge"
+ >{{ s__('Job|triggered') }}
+ </gl-badge>
+ <gl-badge
+ v-if="showAllowedToFailBadge"
+ variant="warning"
+ :size="$options.badgeSize"
+ data-testid="fail-job-badge"
+ >{{ s__('Job|allowed to fail') }}
+ </gl-badge>
+ <gl-badge
+ v-if="isScheduledJob"
+ variant="info"
+ :size="$options.badgeSize"
+ data-testid="delayed-job-badge"
+ >{{ s__('Job|delayed') }}
+ </gl-badge>
+ <gl-badge
+ v-if="isManualJob"
+ variant="info"
+ :size="$options.badgeSize"
+ data-testid="manual-job-badge"
+ >
+ {{ s__('Job|manual') }}
+ </gl-badge>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/jobs_page/components/job_cells/pipeline_cell.vue b/app/assets/javascripts/ci/jobs_page/components/job_cells/pipeline_cell.vue
new file mode 100644
index 00000000000..18d68ee8a29
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/components/job_cells/pipeline_cell.vue
@@ -0,0 +1,56 @@
+<script>
+import { GlAvatar, GlLink } from '@gitlab/ui';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+
+export default {
+ components: {
+ GlAvatar,
+ GlLink,
+ },
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ pipelineId() {
+ const id = getIdFromGraphQLId(this.job.pipeline.id);
+ return `#${id}`;
+ },
+ pipelinePath() {
+ return this.job.pipeline?.path;
+ },
+ pipelineUserAvatar() {
+ return this.job.pipeline?.user?.avatarUrl;
+ },
+ userPath() {
+ return this.job.pipeline?.user?.webPath;
+ },
+ showAvatar() {
+ return this.job.pipeline?.user;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div class="gl-p-3 gl-mt-n3">
+ <gl-link
+ class="gl-text-truncate gl-ml-n3 gl-text-gray-500!"
+ :href="pipelinePath"
+ data-testid="pipeline-id"
+ >
+ {{ pipelineId }}
+ </gl-link>
+ </div>
+ <div class="gl-font-sm gl-text-secondary gl-mt-n2">
+ <span>{{ __('created by') }}</span>
+ <gl-link v-if="showAvatar" :href="userPath" data-testid="pipeline-user-link">
+ <gl-avatar :src="pipelineUserAvatar" :size="16" />
+ </gl-link>
+ <span v-else>{{ __('API') }}</span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/jobs_page/components/jobs_table.vue b/app/assets/javascripts/ci/jobs_page/components/jobs_table.vue
new file mode 100644
index 00000000000..23100a3f3db
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/components/jobs_table.vue
@@ -0,0 +1,112 @@
+<script>
+import { GlTable } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import ProjectCell from '~/ci/admin/jobs_table/components/cells/project_cell.vue';
+import RunnerCell from '~/ci/admin/jobs_table/components/cells/runner_cell.vue';
+import { DEFAULT_FIELDS } from '../constants';
+import ActionsCell from './job_cells/actions_cell.vue';
+import DurationCell from './job_cells/duration_cell.vue';
+import JobCell from './job_cells/job_cell.vue';
+import PipelineCell from './job_cells/pipeline_cell.vue';
+
+export default {
+ i18n: {
+ emptyText: s__('Jobs|No jobs to show'),
+ },
+ components: {
+ ActionsCell,
+ CiBadgeLink,
+ DurationCell,
+ GlTable,
+ JobCell,
+ PipelineCell,
+ ProjectCell,
+ RunnerCell,
+ },
+ props: {
+ jobs: {
+ type: Array,
+ required: true,
+ },
+ tableFields: {
+ type: Array,
+ required: false,
+ default: () => DEFAULT_FIELDS,
+ },
+ admin: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ methods: {
+ formatCoverage(coverage) {
+ return coverage ? `${coverage}%` : '';
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-table
+ :items="jobs"
+ :fields="tableFields"
+ :tbody-tr-attr="{ 'data-testid': 'jobs-table-row' }"
+ :empty-text="$options.i18n.emptyText"
+ data-testid="jobs-table"
+ show-empty
+ stacked="lg"
+ fixed
+ >
+ <template #table-colgroup="{ fields }">
+ <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
+ </template>
+
+ <template #cell(status)="{ item }">
+ <ci-badge-link :status="item.detailedStatus" />
+ </template>
+
+ <template #cell(job)="{ item }">
+ <job-cell :job="item" />
+ </template>
+
+ <template #cell(pipeline)="{ item }">
+ <pipeline-cell :job="item" />
+ </template>
+
+ <template v-if="admin" #cell(project)="{ item }">
+ <project-cell :job="item" />
+ </template>
+
+ <template v-if="admin" #cell(runner)="{ item }">
+ <runner-cell :job="item" />
+ </template>
+
+ <template #cell(stage)="{ item }">
+ <div class="gl-text-truncate">
+ <span v-if="item.stage" data-testid="job-stage-name">{{ item.stage.name }}</span>
+ </div>
+ </template>
+
+ <template #cell(name)="{ item }">
+ <div class="gl-text-truncate">
+ <span data-testid="job-name">{{ item.name }}</span>
+ </div>
+ </template>
+
+ <template #cell(duration)="{ item }">
+ <duration-cell :job="item" />
+ </template>
+
+ <template #cell(coverage)="{ item }">
+ <span v-if="item.coverage" data-testid="job-coverage">{{
+ formatCoverage(item.coverage)
+ }}</span>
+ </template>
+
+ <template #cell(actions)="{ item }">
+ <actions-cell class="gl-float-right" :job="item" />
+ </template>
+ </gl-table>
+</template>
diff --git a/app/assets/javascripts/ci/jobs_page/components/jobs_table_empty_state.vue b/app/assets/javascripts/ci/jobs_page/components/jobs_table_empty_state.vue
new file mode 100644
index 00000000000..d2cd27be034
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/components/jobs_table_empty_state.vue
@@ -0,0 +1,36 @@
+<script>
+import { GlEmptyState } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+export default {
+ i18n: {
+ title: s__('Jobs|Use jobs to automate your tasks'),
+ description: s__(
+ 'Jobs|Jobs are the building blocks of a GitLab CI/CD pipeline. Each job has a specific task, like testing code. To set up jobs in a CI/CD pipeline, add a CI/CD configuration file to your project.',
+ ),
+ buttonText: s__('Jobs|Create CI/CD configuration file'),
+ },
+ components: {
+ GlEmptyState,
+ },
+ inject: {
+ pipelineEditorPath: {
+ default: '',
+ },
+ emptyStateSvgPath: {
+ default: '',
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-empty-state
+ :title="$options.i18n.title"
+ :description="$options.i18n.description"
+ :svg-path="emptyStateSvgPath"
+ :primary-button-link="pipelineEditorPath"
+ :primary-button-text="$options.i18n.buttonText"
+ data-testid="jobs-empty-state"
+ />
+</template>
diff --git a/app/assets/javascripts/ci/jobs_page/components/jobs_table_tabs.vue b/app/assets/javascripts/ci/jobs_page/components/jobs_table_tabs.vue
new file mode 100644
index 00000000000..b753195da9a
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/components/jobs_table_tabs.vue
@@ -0,0 +1,88 @@
+<script>
+import { GlBadge, GlTab, GlTabs, GlLoadingIcon } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import CancelJobs from '~/ci/admin/jobs_table/components/cancel_jobs.vue';
+import { limitedCounterWithDelimiter } from '~/lib/utils/text_utility';
+
+export default {
+ components: {
+ GlBadge,
+ GlTab,
+ GlTabs,
+ GlLoadingIcon,
+ CancelJobs,
+ },
+ inject: {
+ jobStatuses: {
+ default: {},
+ },
+ url: {
+ type: String,
+ default: '',
+ },
+ },
+ props: {
+ allJobsCount: {
+ type: Number,
+ required: true,
+ },
+ loading: {
+ type: Boolean,
+ required: true,
+ },
+ showCancelAllJobsButton: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ tabs() {
+ return [
+ {
+ text: s__('Jobs|All'),
+ count: limitedCounterWithDelimiter(this.allJobsCount),
+ scope: null,
+ testId: 'jobs-all-tab',
+ showBadge: true,
+ },
+ {
+ text: s__('Jobs|Finished'),
+ scope: [this.jobStatuses.success, this.jobStatuses.failed, this.jobStatuses.canceled],
+ testId: 'jobs-finished-tab',
+ showBadge: false,
+ },
+ ];
+ },
+ showLoadingIcon() {
+ return this.loading && !this.allJobsCount;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-flex align-items-lg-center">
+ <gl-tabs content-class="gl-py-0" class="gl-w-full">
+ <gl-tab
+ v-for="tab in tabs"
+ :key="tab.text"
+ :title-link-attributes="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ {
+ 'data-testid': tab.testId,
+ } /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
+ @click="$emit('fetchJobsByStatus', tab.scope)"
+ >
+ <template #title>
+ <span>{{ tab.text }}</span>
+ <gl-loading-icon v-if="showLoadingIcon && tab.showBadge" class="gl-ml-2" />
+
+ <gl-badge v-else-if="tab.showBadge" size="sm" class="gl-tab-counter-badge">
+ {{ tab.count }}
+ </gl-badge>
+ </template>
+ </gl-tab>
+ </gl-tabs>
+ <div class="gl-flex-grow-1"></div>
+ <cancel-jobs v-if="showCancelAllJobsButton" :url="url" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/jobs/components/table/constants.js b/app/assets/javascripts/ci/jobs_page/constants.js
index 1b572e60c58..1b572e60c58 100644
--- a/app/assets/javascripts/jobs/components/table/constants.js
+++ b/app/assets/javascripts/ci/jobs_page/constants.js
diff --git a/app/assets/javascripts/pipelines/event_hub.js b/app/assets/javascripts/ci/jobs_page/event_hub.js
index e31806ad199..e31806ad199 100644
--- a/app/assets/javascripts/pipelines/event_hub.js
+++ b/app/assets/javascripts/ci/jobs_page/event_hub.js
diff --git a/app/assets/javascripts/jobs/components/table/graphql/cache_config.js b/app/assets/javascripts/ci/jobs_page/graphql/cache_config.js
index 5390c023da4..5390c023da4 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/cache_config.js
+++ b/app/assets/javascripts/ci/jobs_page/graphql/cache_config.js
diff --git a/app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql b/app/assets/javascripts/ci/jobs_page/graphql/fragments/job.fragment.graphql
index 3038216fdfc..3038216fdfc 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql
+++ b/app/assets/javascripts/ci/jobs_page/graphql/fragments/job.fragment.graphql
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql b/app/assets/javascripts/ci/jobs_page/graphql/mutations/job_cancel.mutation.graphql
index 20935514d51..20935514d51 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql
+++ b/app/assets/javascripts/ci/jobs_page/graphql/mutations/job_cancel.mutation.graphql
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql b/app/assets/javascripts/ci/jobs_page/graphql/mutations/job_play.mutation.graphql
index c94b045ac40..c94b045ac40 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql
+++ b/app/assets/javascripts/ci/jobs_page/graphql/mutations/job_play.mutation.graphql
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql b/app/assets/javascripts/ci/jobs_page/graphql/mutations/job_retry.mutation.graphql
index 6e51f9a20fa..6e51f9a20fa 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql
+++ b/app/assets/javascripts/ci/jobs_page/graphql/mutations/job_retry.mutation.graphql
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql b/app/assets/javascripts/ci/jobs_page/graphql/mutations/job_unschedule.mutation.graphql
index 8be8c42f3c3..8be8c42f3c3 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql
+++ b/app/assets/javascripts/ci/jobs_page/graphql/mutations/job_unschedule.mutation.graphql
diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql b/app/assets/javascripts/ci/jobs_page/graphql/queries/get_jobs.query.graphql
index 69719011079..69719011079 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
+++ b/app/assets/javascripts/ci/jobs_page/graphql/queries/get_jobs.query.graphql
diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql b/app/assets/javascripts/ci/jobs_page/graphql/queries/get_jobs_count.query.graphql
index a4e02ae721a..a4e02ae721a 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql
+++ b/app/assets/javascripts/ci/jobs_page/graphql/queries/get_jobs_count.query.graphql
diff --git a/app/assets/javascripts/ci/jobs_page/index.js b/app/assets/javascripts/ci/jobs_page/index.js
new file mode 100644
index 00000000000..7e99157289b
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/index.js
@@ -0,0 +1,50 @@
+import { GlToast } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import JobsTableApp from '~/ci/jobs_page/jobs_page_app.vue';
+import createDefaultClient from '~/lib/graphql';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import cacheConfig from './graphql/cache_config';
+
+Vue.use(VueApollo);
+Vue.use(GlToast);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(
+ {},
+ {
+ cacheConfig,
+ },
+ ),
+});
+
+export default (containerId = 'js-jobs-table') => {
+ const containerEl = document.getElementById(containerId);
+
+ if (!containerEl) {
+ return false;
+ }
+
+ const {
+ fullPath,
+ jobStatuses,
+ pipelineEditorPath,
+ emptyStateSvgPath,
+ admin,
+ } = containerEl.dataset;
+
+ return new Vue({
+ el: containerEl,
+ apolloProvider,
+ provide: {
+ emptyStateSvgPath,
+ fullPath,
+ pipelineEditorPath,
+ jobStatuses: JSON.parse(jobStatuses),
+ admin: parseBoolean(admin),
+ },
+ render(createElement) {
+ return createElement(JobsTableApp);
+ },
+ });
+};
diff --git a/app/assets/javascripts/ci/jobs_page/jobs_page_app.vue b/app/assets/javascripts/ci/jobs_page/jobs_page_app.vue
new file mode 100644
index 00000000000..03e0f2dadc8
--- /dev/null
+++ b/app/assets/javascripts/ci/jobs_page/jobs_page_app.vue
@@ -0,0 +1,238 @@
+<script>
+import { GlAlert, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { createAlert } from '~/alert';
+import { setUrlParams, updateHistory, queryToObject } from '~/lib/utils/url_utility';
+import JobsSkeletonLoader from '~/ci/admin/jobs_table/components/jobs_skeleton_loader.vue';
+import JobsFilteredSearch from '~/ci/common/private/jobs_filtered_search/app.vue';
+import { validateQueryString } from '~/ci/common/private/jobs_filtered_search/utils';
+import GetJobs from './graphql/queries/get_jobs.query.graphql';
+import GetJobsCount from './graphql/queries/get_jobs_count.query.graphql';
+import JobsTable from './components/jobs_table.vue';
+import JobsTableEmptyState from './components/jobs_table_empty_state.vue';
+import JobsTableTabs from './components/jobs_table_tabs.vue';
+import { RAW_TEXT_WARNING } from './constants';
+
+export default {
+ i18n: {
+ jobsFetchErrorMsg: __('There was an error fetching the jobs for your project.'),
+ jobsCountErrorMsg: __('There was an error fetching the number of jobs for your project.'),
+ loadingAriaLabel: __('Loading'),
+ },
+ filterSearchBoxStyles:
+ 'gl-my-0 gl-p-5 gl-bg-gray-10 gl-text-gray-900 gl-border-b gl-border-gray-100',
+ components: {
+ GlAlert,
+ JobsFilteredSearch,
+ JobsTable,
+ JobsTableEmptyState,
+ JobsTableTabs,
+ GlIntersectionObserver,
+ GlLoadingIcon,
+ JobsSkeletonLoader,
+ },
+ inject: {
+ fullPath: {
+ default: '',
+ },
+ },
+ apollo: {
+ jobs: {
+ query: GetJobs,
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ ...this.validatedQueryString,
+ };
+ },
+ update(data) {
+ const { jobs: { nodes: list = [], pageInfo = {} } = {} } = data.project || {};
+ return {
+ list,
+ pageInfo,
+ };
+ },
+ error() {
+ this.error = this.$options.i18n.jobsFetchErrorMsg;
+ },
+ },
+ jobsCount: {
+ query: GetJobsCount,
+ context: {
+ isSingleRequest: true,
+ },
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ ...this.validatedQueryString,
+ };
+ },
+ update({ project }) {
+ return project?.jobs?.count || 0;
+ },
+ error() {
+ this.error = this.$options.i18n.jobsCountErrorMsg;
+ },
+ },
+ },
+ data() {
+ return {
+ jobs: {
+ list: [],
+ },
+ error: '',
+ scope: null,
+ infiniteScrollingTriggered: false,
+ filterSearchTriggered: false,
+ jobsCount: null,
+ count: 0,
+ };
+ },
+ computed: {
+ loading() {
+ return this.$apollo.queries.jobs.loading;
+ },
+ // Show when on All tab with no jobs
+ // Show only when not loading and filtered search has not been triggered
+ // So we don't show empty state when results are empty on a filtered search
+ showEmptyState() {
+ return (
+ this.jobs.list.length === 0 && !this.scope && !this.loading && !this.filterSearchTriggered
+ );
+ },
+ hasNextPage() {
+ return this.jobs?.pageInfo?.hasNextPage;
+ },
+ showLoadingSpinner() {
+ return this.loading && this.infiniteScrollingTriggered;
+ },
+ showSkeletonLoader() {
+ return this.loading && !this.showLoadingSpinner;
+ },
+ showFilteredSearch() {
+ return !this.scope;
+ },
+ validatedQueryString() {
+ const queryStringObject = queryToObject(window.location.search);
+
+ return validateQueryString(queryStringObject);
+ },
+ },
+ watch: {
+ // this watcher ensures that the count on the all tab
+ // is not updated when switching to the finished tab
+ jobsCount(newCount, oldCount) {
+ if (this.scope) {
+ this.count = oldCount;
+ } else {
+ this.count = newCount;
+ }
+ },
+ },
+ methods: {
+ updateHistoryAndFetchCount(status = null) {
+ this.$apollo.queries.jobsCount.refetch({ statuses: status });
+
+ updateHistory({
+ url: setUrlParams({ statuses: status }, window.location.href, true),
+ });
+ },
+ fetchJobsByStatus(scope) {
+ this.infiniteScrollingTriggered = false;
+
+ if (this.scope === scope) return;
+
+ this.scope = scope;
+
+ if (!this.scope) this.updateHistoryAndFetchCount();
+
+ this.$apollo.queries.jobs.refetch({ statuses: scope });
+ },
+ filterJobsBySearch(filters) {
+ this.infiniteScrollingTriggered = false;
+ this.filterSearchTriggered = true;
+
+ // all filters have been cleared reset query param
+ // and refetch jobs/count with defaults
+ if (!filters.length) {
+ this.updateHistoryAndFetchCount();
+ this.$apollo.queries.jobs.refetch({ statuses: null });
+
+ return;
+ }
+
+ // Eventually there will be more tokens available
+ // this code is written to scale for those tokens
+ filters.forEach((filter) => {
+ // Raw text input in filtered search does not have a type
+ // when a user enters raw text we alert them that it is
+ // not supported and we do not make an additional API call
+ if (!filter.type) {
+ createAlert({
+ message: RAW_TEXT_WARNING,
+ type: 'warning',
+ });
+ }
+
+ if (filter.type === 'status') {
+ this.updateHistoryAndFetchCount(filter.value.data);
+ this.$apollo.queries.jobs.refetch({ statuses: filter.value.data });
+ }
+ });
+ },
+ fetchMoreJobs() {
+ if (!this.loading) {
+ this.infiniteScrollingTriggered = true;
+
+ this.$apollo.queries.jobs.fetchMore({
+ variables: {
+ fullPath: this.fullPath,
+ after: this.jobs?.pageInfo?.endCursor,
+ },
+ });
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-alert
+ v-if="error"
+ class="gl-mt-2"
+ variant="danger"
+ data-testid="jobs-table-error-alert"
+ dismissible
+ @dismiss="error = ''"
+ >
+ {{ error }}
+ </gl-alert>
+
+ <jobs-table-tabs
+ :all-jobs-count="count"
+ :loading="loading"
+ @fetchJobsByStatus="fetchJobsByStatus"
+ />
+ <div v-if="showFilteredSearch" :class="$options.filterSearchBoxStyles">
+ <jobs-filtered-search
+ :query-string="validatedQueryString"
+ @filterJobsBySearch="filterJobsBySearch"
+ />
+ </div>
+
+ <jobs-skeleton-loader v-if="showSkeletonLoader" class="gl-mt-5" />
+
+ <jobs-table-empty-state v-else-if="showEmptyState" />
+
+ <jobs-table v-else :jobs="jobs.list" class="gl-table-no-top-border" />
+
+ <gl-intersection-observer v-if="hasNextPage" @appear="fetchMoreJobs">
+ <gl-loading-icon
+ v-if="showLoadingSpinner"
+ size="lg"
+ :aria-label="$options.i18n.loadingAriaLabel"
+ />
+ </gl-intersection-observer>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/merge_requests/components/pipelines_table_wrapper.vue b/app/assets/javascripts/ci/merge_requests/components/pipelines_table_wrapper.vue
new file mode 100644
index 00000000000..ee911d716e4
--- /dev/null
+++ b/app/assets/javascripts/ci/merge_requests/components/pipelines_table_wrapper.vue
@@ -0,0 +1,60 @@
+<script>
+import { GlLoadingIcon } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { getQueryHeaders } from '~/ci/pipeline_details/graph/utils';
+import { graphqlEtagMergeRequestPipelines } from '~/ci/pipeline_details/utils';
+import getMergeRequestPipelines from '../graphql/queries/get_merge_request_pipelines.query.graphql';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ },
+ inject: ['graphqlPath', 'mergeRequestId', 'targetProjectFullPath'],
+ data() {
+ return {
+ pipelines: [],
+ };
+ },
+ apollo: {
+ pipelines: {
+ query: getMergeRequestPipelines,
+ context() {
+ return getQueryHeaders(this.graphqlResourceEtag);
+ },
+ pollInterval: 10000,
+ variables() {
+ return {
+ fullPath: this.targetProjectFullPath,
+ mergeRequestIid: String(this.mergeRequestId),
+ };
+ },
+ update(data) {
+ return data?.project?.mergeRequest?.pipelines?.nodes || [];
+ },
+ error() {
+ createAlert({ message: this.$options.i18n.fetchError });
+ },
+ },
+ },
+ computed: {
+ graphqlResourceEtag() {
+ return graphqlEtagMergeRequestPipelines(this.graphqlPath, this.mergeRequestId);
+ },
+ isLoading() {
+ return this.$apollo.queries.pipelines.loading;
+ },
+ },
+ i18n: {
+ fetchError: __("There was an error fetching this merge request's pipelines."),
+ },
+};
+</script>
+<template>
+ <div class="gl-mt-3">
+ <gl-loading-icon v-if="isLoading" size="lg" />
+ <ul v-else>
+ <li v-for="pipeline in pipelines" :key="pipeline.id">{{ pipeline.path }}</li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/graphql/mutations/retry_mr_failed_job.mutation.graphql b/app/assets/javascripts/ci/merge_requests/graphql/mutations/retry_mr_failed_job.mutation.graphql
index 022d461dbec..022d461dbec 100644
--- a/app/assets/javascripts/pipelines/graphql/mutations/retry_mr_failed_job.mutation.graphql
+++ b/app/assets/javascripts/ci/merge_requests/graphql/mutations/retry_mr_failed_job.mutation.graphql
diff --git a/app/assets/javascripts/ci/merge_requests/graphql/queries/get_merge_request_pipelines.query.graphql b/app/assets/javascripts/ci/merge_requests/graphql/queries/get_merge_request_pipelines.query.graphql
new file mode 100644
index 00000000000..8c235032e6c
--- /dev/null
+++ b/app/assets/javascripts/ci/merge_requests/graphql/queries/get_merge_request_pipelines.query.graphql
@@ -0,0 +1,16 @@
+query getMergeRequestPipelines($mergeRequestIid: String!, $fullPath: ID!) {
+ project(fullPath: $fullPath) {
+ id
+ mergeRequest(iid: $mergeRequestIid) {
+ id
+ pipelines {
+ count
+ nodes {
+ id
+ iid
+ path
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/jobs/mixins/delayed_job_mixin.js b/app/assets/javascripts/ci/mixins/delayed_job_mixin.js
index 7b17dc7f693..7b17dc7f693 100644
--- a/app/assets/javascripts/jobs/mixins/delayed_job_mixin.js
+++ b/app/assets/javascripts/ci/mixins/delayed_job_mixin.js
diff --git a/app/assets/javascripts/ci/pipeline_details/constants.js b/app/assets/javascripts/ci/pipeline_details/constants.js
new file mode 100644
index 00000000000..bf312e66144
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/constants.js
@@ -0,0 +1,77 @@
+import { __, s__ } from '~/locale';
+
+export const CANCEL_REQUEST = 'CANCEL_REQUEST';
+export const SUPPORTED_FILTER_PARAMETERS = ['username', 'ref', 'status', 'source'];
+export const SCHEDULE_ORIGIN = 'schedule';
+export const NEEDS_PROPERTY = 'needs';
+export const EXPLICIT_NEEDS_PROPERTY = 'previousStageJobsOrNeeds';
+
+export const TestStatus = {
+ FAILED: 'failed',
+ SKIPPED: 'skipped',
+ SUCCESS: 'success',
+ ERROR: 'error',
+ UNKNOWN: 'unknown',
+};
+
+/* Error constants shared across graphs */
+export const DEFAULT = 'default';
+export const DELETE_FAILURE = 'delete_pipeline_failure';
+export const DRAW_FAILURE = 'draw_failure';
+export const LOAD_FAILURE = 'load_failure';
+export const PARSE_FAILURE = 'parse_failure';
+export const POST_FAILURE = 'post_failure';
+export const UNSUPPORTED_DATA = 'unsupported_data';
+
+export const CHILD_VIEW = 'child';
+
+// Pipeline tabs
+
+export const pipelineTabName = 'graph';
+export const needsTabName = 'dag';
+export const jobsTabName = 'builds';
+export const failedJobsTabName = 'failures';
+export const testReportTabName = 'test_report';
+export const securityTabName = 'security';
+export const licensesTabName = 'licenses';
+export const codeQualityTabName = 'codequality_report';
+
+export const validPipelineTabNames = [
+ needsTabName,
+ jobsTabName,
+ failedJobsTabName,
+ testReportTabName,
+ securityTabName,
+ licensesTabName,
+ codeQualityTabName,
+];
+
+export const TOAST_MESSAGE = s__('Pipeline|Creating pipeline.');
+
+export const DEFAULT_FIELDS = [
+ {
+ key: 'name',
+ label: __('Name'),
+ columnClass: 'gl-w-20p',
+ },
+ {
+ key: 'stage',
+ label: __('Stage'),
+ columnClass: 'gl-w-20p',
+ },
+ {
+ key: 'failureMessage',
+ label: __('Failure'),
+ columnClass: 'gl-w-40p',
+ },
+ {
+ key: 'actions',
+ label: '',
+ tdClass: 'gl-text-right',
+ columnClass: 'gl-w-20p',
+ },
+];
+
+// Pipeline Mini Graph
+
+export const PIPELINE_MINI_GRAPH_POLL_INTERVAL = 5000;
diff --git a/app/assets/javascripts/pipelines/components/dag/dag_annotations.vue b/app/assets/javascripts/ci/pipeline_details/dag/components/dag_annotations.vue
index a1500166cdc..a1500166cdc 100644
--- a/app/assets/javascripts/pipelines/components/dag/dag_annotations.vue
+++ b/app/assets/javascripts/ci/pipeline_details/dag/components/dag_annotations.vue
diff --git a/app/assets/javascripts/ci/pipeline_details/dag/components/dag_graph.vue b/app/assets/javascripts/ci/pipeline_details/dag/components/dag_graph.vue
new file mode 100644
index 00000000000..6e975d55a7f
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/dag/components/dag_graph.vue
@@ -0,0 +1,329 @@
+<script>
+import * as d3 from 'd3';
+import { uniqueId } from 'lodash';
+import { getMaxNodes, removeOrphanNodes } from '~/ci/pipeline_details/utils/parsing_utils';
+import { PARSE_FAILURE } from '../../constants';
+import { LINK_SELECTOR, NODE_SELECTOR, ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from '../constants';
+import { calculateClip, createLinkPath, createSankey, labelPosition } from '../utils/drawing_utils';
+import {
+ currentIsLive,
+ getLiveLinksAsDict,
+ highlightLinks,
+ restoreLinks,
+ toggleLinkHighlight,
+ togglePathHighlights,
+} from '../utils/interactions';
+
+export default {
+ viewOptions: {
+ baseHeight: 300,
+ baseWidth: 1000,
+ minNodeHeight: 60,
+ nodeWidth: 16,
+ nodePadding: 25,
+ paddingForLabels: 100,
+ labelMargin: 8,
+
+ baseOpacity: 0.8,
+ containerClasses: ['dag-graph-container', 'gl-display-flex', 'gl-flex-direction-column'].join(
+ ' ',
+ ),
+ hoverFadeClasses: [
+ 'gl-cursor-pointer',
+ 'gl-transition-duration-slow',
+ 'gl-transition-timing-function-ease',
+ ].join(' '),
+ },
+ gitLabColorRotation: [
+ '#e17223',
+ '#83ab4a',
+ '#5772ff',
+ '#b24800',
+ '#25d2d2',
+ '#006887',
+ '#487900',
+ '#d84280',
+ '#3547de',
+ '#6f3500',
+ '#006887',
+ '#275600',
+ '#b31756',
+ ],
+ props: {
+ graphData: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ color: () => {},
+ height: 0,
+ width: 0,
+ };
+ },
+ mounted() {
+ let countedAndTransformed;
+
+ try {
+ countedAndTransformed = this.transformData(this.graphData);
+ } catch {
+ this.$emit('on-failure', PARSE_FAILURE);
+ return;
+ }
+
+ this.drawGraph(countedAndTransformed);
+ },
+ methods: {
+ addSvg() {
+ return d3
+ .select('.dag-graph-container')
+ .append('svg')
+ .attr('viewBox', [0, 0, this.width, this.height])
+ .attr('width', this.width)
+ .attr('height', this.height);
+ },
+
+ appendLinks(link) {
+ return (
+ link
+ .append('path')
+ .attr('d', (d, i) => createLinkPath(d, i, this.$options.viewOptions.nodeWidth))
+ .attr('stroke', ({ gradId }) => `url(#${gradId})`)
+ .style('stroke-linejoin', 'round')
+ // minus two to account for the rounded nodes
+ .attr('stroke-width', ({ width }) => Math.max(1, width - 2))
+ .attr('clip-path', ({ clipId }) => `url(#${clipId})`)
+ );
+ },
+
+ appendLinkInteractions(link) {
+ const { baseOpacity } = this.$options.viewOptions;
+ return link
+ .on('mouseover', (d, idx, collection) => {
+ if (currentIsLive(idx, collection)) {
+ return;
+ }
+ this.$emit('update-annotation', { type: ADD_NOTE, data: d });
+ highlightLinks(d, idx, collection);
+ })
+ .on('mouseout', (d, idx, collection) => {
+ if (currentIsLive(idx, collection)) {
+ return;
+ }
+ this.$emit('update-annotation', { type: REMOVE_NOTE, data: d });
+ restoreLinks(baseOpacity);
+ })
+ .on('click', (d, idx, collection) => {
+ toggleLinkHighlight(baseOpacity, d, idx, collection);
+ this.$emit('update-annotation', { type: REPLACE_NOTES, data: getLiveLinksAsDict() });
+ });
+ },
+
+ appendNodeInteractions(node) {
+ return node.on('click', (d, idx, collection) => {
+ togglePathHighlights(this.$options.viewOptions.baseOpacity, d, idx, collection);
+ this.$emit('update-annotation', { type: REPLACE_NOTES, data: getLiveLinksAsDict() });
+ });
+ },
+
+ appendLabelAsForeignObject(d, i, n) {
+ const currentNode = n[i];
+ const { height, wrapperWidth, width, x, y, textAlign } = labelPosition(d, {
+ ...this.$options.viewOptions,
+ width: this.width,
+ });
+
+ const labelClasses = [
+ 'gl-display-flex',
+ 'gl-pointer-events-none',
+ 'gl-flex-direction-column',
+ 'gl-justify-content-center',
+ 'gl-overflow-wrap-break',
+ ].join(' ');
+
+ return (
+ d3
+ .select(currentNode)
+ .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
+ .attr('height', height)
+ /*
+ items with a 'max-content' width will have a wrapperWidth for the foreignObject
+ */
+ .attr('width', wrapperWidth || width)
+ .attr('x', x)
+ .attr('y', y)
+ .classed('gl-overflow-visible', true)
+ .append('xhtml:div')
+ .classed(labelClasses, true)
+ .style('height', height)
+ .style('width', width)
+ .style('text-align', textAlign)
+ .text(({ name }) => name)
+ );
+ },
+
+ createAndAssignId(datum, field, modifier = '') {
+ const id = uniqueId(modifier);
+ /* eslint-disable-next-line no-param-reassign */
+ datum[field] = id;
+ return id;
+ },
+
+ createClip(link) {
+ return link
+ .append('clipPath')
+ .attr('id', (d) => {
+ return this.createAndAssignId(d, 'clipId', 'dag-clip');
+ })
+ .append('path')
+ .attr('d', calculateClip);
+ },
+
+ createGradient(link) {
+ const gradient = link
+ .append('linearGradient')
+ .attr('id', (d) => {
+ return this.createAndAssignId(d, 'gradId', 'dag-grad');
+ })
+ .attr('gradientUnits', 'userSpaceOnUse')
+ .attr('x1', ({ source }) => source.x1)
+ .attr('x2', ({ target }) => target.x0);
+
+ gradient
+ .append('stop')
+ .attr('offset', '0%')
+ .attr('stop-color', ({ source }) => this.color(source));
+
+ gradient
+ .append('stop')
+ .attr('offset', '100%')
+ .attr('stop-color', ({ target }) => this.color(target));
+ },
+
+ createLinks(svg, linksData) {
+ const links = this.generateLinks(svg, linksData);
+ this.createGradient(links);
+ this.createClip(links);
+ this.appendLinks(links);
+ this.appendLinkInteractions(links);
+ },
+
+ createNodes(svg, nodeData) {
+ const nodes = this.generateNodes(svg, nodeData);
+ this.labelNodes(svg, nodeData);
+ this.appendNodeInteractions(nodes);
+ },
+
+ drawGraph({ maxNodesPerLayer, linksAndNodes }) {
+ const {
+ baseWidth,
+ baseHeight,
+ minNodeHeight,
+ nodeWidth,
+ nodePadding,
+ paddingForLabels,
+ } = this.$options.viewOptions;
+
+ this.width = baseWidth;
+ this.height = baseHeight + maxNodesPerLayer * minNodeHeight;
+ this.color = this.initColors();
+
+ const { links, nodes } = createSankey({
+ width: this.width,
+ height: this.height,
+ nodeWidth,
+ nodePadding,
+ paddingForLabels,
+ })(linksAndNodes);
+
+ const svg = this.addSvg();
+ this.createLinks(svg, links);
+ this.createNodes(svg, nodes);
+ },
+
+ generateLinks(svg, linksData) {
+ return svg
+ .append('g')
+ .attr('fill', 'none')
+ .attr('stroke-opacity', this.$options.viewOptions.baseOpacity)
+ .selectAll(`.${LINK_SELECTOR}`)
+ .data(linksData)
+ .enter()
+ .append('g')
+ .attr('id', (d) => {
+ return this.createAndAssignId(d, 'uid', LINK_SELECTOR);
+ })
+ .classed(
+ `${LINK_SELECTOR} gl-transition-property-stroke-opacity ${this.$options.viewOptions.hoverFadeClasses}`,
+ true,
+ );
+ },
+
+ generateNodes(svg, nodeData) {
+ const { nodeWidth } = this.$options.viewOptions;
+
+ return svg
+ .append('g')
+ .selectAll(`.${NODE_SELECTOR}`)
+ .data(nodeData)
+ .enter()
+ .append('line')
+ .classed(
+ `${NODE_SELECTOR} gl-transition-property-stroke ${this.$options.viewOptions.hoverFadeClasses}`,
+ true,
+ )
+ .attr('id', (d) => {
+ return this.createAndAssignId(d, 'uid', NODE_SELECTOR);
+ })
+ .attr('stroke', (d) => {
+ const color = this.color(d);
+ /* eslint-disable-next-line no-param-reassign */
+ d.color = color;
+ return color;
+ })
+ .attr('stroke-width', nodeWidth)
+ .attr('stroke-linecap', 'round')
+ .attr('x1', (d) => Math.floor((d.x1 + d.x0) / 2))
+ .attr('x2', (d) => Math.floor((d.x1 + d.x0) / 2))
+ .attr('y1', (d) => d.y0 + 4)
+ .attr('y2', (d) => d.y1 - 4);
+ },
+
+ initColors() {
+ const colorFn = d3.scaleOrdinal(this.$options.gitLabColorRotation);
+ return ({ name }) => colorFn(name);
+ },
+
+ labelNodes(svg, nodeData) {
+ return svg
+ .append('g')
+ .classed('gl-font-sm', true)
+ .selectAll('text')
+ .data(nodeData)
+ .enter()
+ .append('foreignObject')
+ .each(this.appendLabelAsForeignObject);
+ },
+
+ transformData(parsed) {
+ const baseLayout = createSankey()(parsed);
+ const cleanedNodes = removeOrphanNodes(baseLayout.nodes);
+ const maxNodesPerLayer = getMaxNodes(cleanedNodes);
+
+ return {
+ maxNodesPerLayer,
+ linksAndNodes: {
+ links: parsed.links,
+ nodes: cleanedNodes,
+ },
+ };
+ },
+ },
+};
+</script>
+<template>
+ <div :class="$options.viewOptions.containerClasses" data-testid="dag-graph-container">
+ <!-- graph goes here -->
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/dag/constants.js b/app/assets/javascripts/ci/pipeline_details/dag/constants.js
index cd89055737f..cd89055737f 100644
--- a/app/assets/javascripts/pipelines/components/dag/constants.js
+++ b/app/assets/javascripts/ci/pipeline_details/dag/constants.js
diff --git a/app/assets/javascripts/ci/pipeline_details/dag/dag.vue b/app/assets/javascripts/ci/pipeline_details/dag/dag.vue
new file mode 100644
index 00000000000..5415340c956
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/dag/dag.vue
@@ -0,0 +1,254 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<script>
+import { GlAlert, GlButton, GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
+import { isEmpty } from 'lodash';
+import { fetchPolicies } from '~/lib/graphql';
+import { __ } from '~/locale';
+import {
+ DEFAULT,
+ PARSE_FAILURE,
+ LOAD_FAILURE,
+ UNSUPPORTED_DATA,
+} from '~/ci/pipeline_details/constants';
+import { parseData } from '~/ci/pipeline_details/utils/parsing_utils';
+import getDagVisData from './graphql/queries/get_dag_vis_data.query.graphql';
+import { ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from './constants';
+import DagAnnotations from './components/dag_annotations.vue';
+import DagGraph from './components/dag_graph.vue';
+
+export default {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ name: 'Dag',
+ components: {
+ DagAnnotations,
+ DagGraph,
+ GlAlert,
+ GlButton,
+ GlEmptyState,
+ GlLink,
+ GlSprintf,
+ },
+ inject: {
+ aboutDagDocPath: {
+ default: null,
+ },
+ dagDocPath: {
+ default: null,
+ },
+ emptyDagSvgPath: {
+ default: '',
+ },
+ pipelineIid: {
+ default: '',
+ },
+ pipelineProjectPath: {
+ default: '',
+ },
+ },
+ apollo: {
+ graphData: {
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
+ query: getDagVisData,
+ variables() {
+ return {
+ projectPath: this.pipelineProjectPath,
+ iid: this.pipelineIid,
+ };
+ },
+ update(data) {
+ if (!data?.project?.pipeline) {
+ return this.graphData;
+ }
+
+ const {
+ stages: { nodes: stages },
+ } = data.project.pipeline;
+
+ const unwrappedGroups = stages
+ .map(({ name, groups: { nodes: groups } }) => {
+ return groups.map((group) => {
+ return { category: name, ...group };
+ });
+ })
+ .flat(2);
+
+ const nodes = unwrappedGroups.map((group) => {
+ const jobs = group.jobs.nodes.map(({ name, needs }) => {
+ return { name, needs: needs.nodes.map((need) => need.name) };
+ });
+
+ return { ...group, jobs };
+ });
+
+ return nodes;
+ },
+ error() {
+ this.reportFailure(LOAD_FAILURE);
+ },
+ },
+ },
+ data() {
+ return {
+ annotationsMap: {},
+ failureType: null,
+ graphData: null,
+ showFailureAlert: false,
+ hasNoDependentJobs: false,
+ };
+ },
+ errorTexts: {
+ [LOAD_FAILURE]: __('We are currently unable to fetch data for this graph.'),
+ [PARSE_FAILURE]: __('There was an error parsing the data for this graph.'),
+ [UNSUPPORTED_DATA]: __('DAG visualization requires at least 3 dependent jobs.'),
+ [DEFAULT]: __('An unknown error occurred while loading this graph.'),
+ },
+ emptyStateTexts: {
+ title: __('Speed up your pipelines with Needs relationships'),
+ firstDescription: __(
+ 'Using the %{codeStart}needs%{codeEnd} keyword makes jobs run before their stage is reached. Jobs run as soon as their %{codeStart}needs%{codeEnd} relationships are met, which speeds up your pipelines.',
+ ),
+ secondDescription: __(
+ "If you add %{codeStart}needs%{codeEnd} to jobs in your pipeline you'll be able to view the %{codeStart}needs%{codeEnd} relationships between jobs in this tab as a %{linkStart}Directed Acyclic Graph (DAG)%{linkEnd}.",
+ ),
+ button: __('Learn more about Needs relationships'),
+ },
+ computed: {
+ failure() {
+ switch (this.failureType) {
+ case LOAD_FAILURE:
+ return {
+ text: this.$options.errorTexts[LOAD_FAILURE],
+ variant: 'danger',
+ };
+ case PARSE_FAILURE:
+ return {
+ text: this.$options.errorTexts[PARSE_FAILURE],
+ variant: 'danger',
+ };
+ case UNSUPPORTED_DATA:
+ return {
+ text: this.$options.errorTexts[UNSUPPORTED_DATA],
+ variant: 'info',
+ };
+ default:
+ return {
+ text: this.$options.errorTexts[DEFAULT],
+ variant: 'danger',
+ };
+ }
+ },
+ processedData() {
+ return this.processGraphData(this.graphData);
+ },
+ shouldDisplayAnnotations() {
+ return !isEmpty(this.annotationsMap);
+ },
+ shouldDisplayGraph() {
+ return Boolean(!this.showFailureAlert && !this.hasNoDependentJobs && this.graphData);
+ },
+ },
+ methods: {
+ addAnnotationToMap({ uid, source, target }) {
+ this.$set(this.annotationsMap, uid, { source, target });
+ },
+ processGraphData(data) {
+ let parsed;
+
+ try {
+ parsed = parseData(data);
+ } catch {
+ this.reportFailure(PARSE_FAILURE);
+ return {};
+ }
+
+ if (parsed.links.length === 1) {
+ this.reportFailure(UNSUPPORTED_DATA);
+ return {};
+ }
+
+ // If there are no links, we don't report failure
+ // as it simply means the user does not use job dependencies
+ if (parsed.links.length === 0) {
+ this.hasNoDependentJobs = true;
+ return {};
+ }
+
+ return parsed;
+ },
+ hideAlert() {
+ this.showFailureAlert = false;
+ },
+ removeAnnotationFromMap({ uid }) {
+ this.$delete(this.annotationsMap, uid);
+ },
+ reportFailure(type) {
+ this.showFailureAlert = true;
+ this.failureType = type;
+ },
+ updateAnnotation({ type, data }) {
+ switch (type) {
+ case ADD_NOTE:
+ this.addAnnotationToMap(data);
+ break;
+ case REMOVE_NOTE:
+ this.removeAnnotationFromMap(data);
+ break;
+ case REPLACE_NOTES:
+ this.annotationsMap = data;
+ break;
+ default:
+ break;
+ }
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert v-if="showFailureAlert" :variant="failure.variant" @dismiss="hideAlert">
+ {{ failure.text }}
+ </gl-alert>
+
+ <div class="gl-relative">
+ <dag-annotations v-if="shouldDisplayAnnotations" :annotations="annotationsMap" />
+ <dag-graph
+ v-if="shouldDisplayGraph"
+ :graph-data="processedData"
+ @onFailure="reportFailure"
+ @update-annotation="updateAnnotation"
+ />
+ <gl-empty-state
+ v-else-if="hasNoDependentJobs"
+ :svg-path="emptyDagSvgPath"
+ :title="$options.emptyStateTexts.title"
+ >
+ <template #description>
+ <div class="gl-text-left">
+ <p>
+ <gl-sprintf :message="$options.emptyStateTexts.firstDescription">
+ <template #code="{ content }">
+ <code>{{ content }}</code>
+ </template>
+ </gl-sprintf>
+ </p>
+ <p>
+ <gl-sprintf :message="$options.emptyStateTexts.secondDescription">
+ <template #code="{ content }">
+ <code>{{ content }}</code>
+ </template>
+ <template #link="{ content }">
+ <gl-link :href="aboutDagDocPath">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </div>
+ </template>
+ <template v-if="dagDocPath" #actions>
+ <gl-button :href="dagDocPath" target="_blank" variant="confirm">
+ {{ $options.emptyStateTexts.button }}
+ </gl-button>
+ </template>
+ </gl-empty-state>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql b/app/assets/javascripts/ci/pipeline_details/dag/graphql/queries/get_dag_vis_data.query.graphql
index 2a0b13dd0cc..2a0b13dd0cc 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/dag/graphql/queries/get_dag_vis_data.query.graphql
diff --git a/app/assets/javascripts/pipelines/components/dag/drawing_utils.js b/app/assets/javascripts/ci/pipeline_details/dag/utils/drawing_utils.js
index 3cd09d57ffb..3cd09d57ffb 100644
--- a/app/assets/javascripts/pipelines/components/dag/drawing_utils.js
+++ b/app/assets/javascripts/ci/pipeline_details/dag/utils/drawing_utils.js
diff --git a/app/assets/javascripts/ci/pipeline_details/dag/utils/interactions.js b/app/assets/javascripts/ci/pipeline_details/dag/utils/interactions.js
new file mode 100644
index 00000000000..d2b7b7f9069
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/dag/utils/interactions.js
@@ -0,0 +1,154 @@
+import * as d3 from 'd3';
+import { LINK_SELECTOR, NODE_SELECTOR, IS_HIGHLIGHTED } from '../constants';
+
+export const highlightIn = 1;
+export const highlightOut = 0.2;
+
+const getCurrent = (idx, collection) => d3.select(collection[idx]);
+const getLiveLinks = () => d3.selectAll(`.${LINK_SELECTOR}.${IS_HIGHLIGHTED}`);
+const getOtherLinks = () => d3.selectAll(`.${LINK_SELECTOR}:not(.${IS_HIGHLIGHTED})`);
+const getNodesNotLive = () => d3.selectAll(`.${NODE_SELECTOR}:not(.${IS_HIGHLIGHTED})`);
+
+export const getLiveLinksAsDict = () => {
+ return Object.fromEntries(
+ getLiveLinks()
+ .data()
+ .map((d) => [d.uid, d]),
+ );
+};
+export const currentIsLive = (idx, collection) =>
+ getCurrent(idx, collection).classed(IS_HIGHLIGHTED);
+
+const backgroundLinks = (selection) => selection.style('stroke-opacity', highlightOut);
+const backgroundNodes = (selection) => selection.attr('stroke', '#f2f2f2');
+const foregroundLinks = (selection) => selection.style('stroke-opacity', highlightIn);
+const foregroundNodes = (selection) => selection.attr('stroke', (d) => d.color);
+const renewLinks = (selection, baseOpacity) => selection.style('stroke-opacity', baseOpacity);
+const renewNodes = (selection) => selection.attr('stroke', (d) => d.color);
+
+export const getAllLinkAncestors = (node) => {
+ if (node.targetLinks) {
+ return node.targetLinks.flatMap((n) => {
+ return [n, ...getAllLinkAncestors(n.source)];
+ });
+ }
+
+ return [];
+};
+
+const getAllNodeAncestors = (node) => {
+ let allNodes = [];
+
+ if (node.targetLinks) {
+ allNodes = node.targetLinks.flatMap((n) => {
+ return getAllNodeAncestors(n.source);
+ });
+ }
+
+ return [...allNodes, node.uid];
+};
+
+export const highlightLinks = (d, idx, collection) => {
+ const currentLink = getCurrent(idx, collection);
+ const currentSourceNode = d3.select(`#${d.source.uid}`);
+ const currentTargetNode = d3.select(`#${d.target.uid}`);
+
+ /* Higlight selected link, de-emphasize others */
+ backgroundLinks(getOtherLinks());
+ foregroundLinks(currentLink);
+
+ /* Do the same to related nodes */
+ backgroundNodes(getNodesNotLive());
+ foregroundNodes(currentSourceNode);
+ foregroundNodes(currentTargetNode);
+};
+
+const highlightPath = (parentLinks, parentNodes) => {
+ /* de-emphasize everything else */
+ backgroundLinks(getOtherLinks());
+ backgroundNodes(getNodesNotLive());
+
+ /* highlight correct links */
+ parentLinks.forEach(({ uid }) => {
+ foregroundLinks(d3.select(`#${uid}`)).classed(IS_HIGHLIGHTED, true);
+ });
+
+ /* highlight correct nodes */
+ parentNodes.forEach((id) => {
+ foregroundNodes(d3.select(`#${id}`)).classed(IS_HIGHLIGHTED, true);
+ });
+};
+
+const restoreNodes = () => {
+ /*
+ When paths are unclicked, they can take down nodes that
+ are still in use for other paths. This checks the live paths and
+ rehighlights their nodes.
+ */
+
+ getLiveLinks().each((d) => {
+ foregroundNodes(d3.select(`#${d.source.uid}`)).classed(IS_HIGHLIGHTED, true);
+ foregroundNodes(d3.select(`#${d.target.uid}`)).classed(IS_HIGHLIGHTED, true);
+ });
+};
+
+const restorePath = (parentLinks, parentNodes, baseOpacity) => {
+ parentLinks.forEach(({ uid }) => {
+ renewLinks(d3.select(`#${uid}`), baseOpacity).classed(IS_HIGHLIGHTED, false);
+ });
+
+ parentNodes.forEach((id) => {
+ d3.select(`#${id}`).classed(IS_HIGHLIGHTED, false);
+ });
+
+ if (d3.selectAll(`.${IS_HIGHLIGHTED}`).empty()) {
+ renewLinks(getOtherLinks(), baseOpacity);
+ renewNodes(getNodesNotLive());
+ return;
+ }
+
+ backgroundLinks(getOtherLinks());
+ backgroundNodes(getNodesNotLive());
+ restoreNodes();
+};
+
+export const restoreLinks = (baseOpacity) => {
+ /*
+ if there exist live links, reset to highlight out / pale
+ otherwise, reset to base
+ */
+
+ if (d3.selectAll(`.${IS_HIGHLIGHTED}`).empty()) {
+ renewLinks(d3.selectAll(`.${LINK_SELECTOR}`), baseOpacity);
+ renewNodes(d3.selectAll(`.${NODE_SELECTOR}`));
+ return;
+ }
+
+ backgroundLinks(getOtherLinks());
+ backgroundNodes(getNodesNotLive());
+};
+
+export const toggleLinkHighlight = (baseOpacity, d, idx, collection) => {
+ if (currentIsLive(idx, collection)) {
+ restorePath([d], [d.source.uid, d.target.uid], baseOpacity);
+ restoreNodes();
+ return;
+ }
+
+ highlightPath([d], [d.source.uid, d.target.uid]);
+};
+
+export const togglePathHighlights = (baseOpacity, d, idx, collection) => {
+ const parentLinks = getAllLinkAncestors(d);
+ const parentNodes = getAllNodeAncestors(d);
+ const currentNode = getCurrent(idx, collection);
+
+ /* if this node is already live, make it unlive and reset its path */
+ if (currentIsLive(idx, collection)) {
+ currentNode.classed(IS_HIGHLIGHTED, false);
+ restorePath(parentLinks, parentNodes, baseOpacity);
+ return;
+ }
+
+ highlightPath(parentLinks, parentNodes);
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/api_utils.js b/app/assets/javascripts/ci/pipeline_details/graph/api_utils.js
new file mode 100644
index 00000000000..f9f47d1ea15
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/api_utils.js
@@ -0,0 +1,13 @@
+import axios from '~/lib/utils/axios_utils';
+import { reportToSentry } from '~/ci/utils';
+
+export const reportPerformance = (path, stats) => {
+ // FIXME: https://gitlab.com/gitlab-org/gitlab/-/issues/330245
+ if (!path) {
+ return;
+ }
+
+ axios.post(path, stats).catch((err) => {
+ reportToSentry('links_inner_perf', `error: ${err}`);
+ });
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/components/graph_component.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/graph_component.vue
new file mode 100644
index 00000000000..f098d790736
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/graph_component.vue
@@ -0,0 +1,261 @@
+<script>
+import { reportToSentry } from '~/ci/utils';
+import {
+ generateColumnsFromLayersListMemoized,
+ keepLatestDownstreamPipelines,
+} from '~/ci/pipeline_details/utils/parsing_utils';
+import LinksLayer from '../../../common/private/job_links_layer.vue';
+import { DOWNSTREAM, MAIN, UPSTREAM, ONE_COL_WIDTH, STAGE_VIEW } from '../constants';
+import { validateConfigPaths } from '../utils';
+import LinkedGraphWrapper from './linked_graph_wrapper.vue';
+import LinkedPipelinesColumn from './linked_pipelines_column.vue';
+import StageColumnComponent from './stage_column_component.vue';
+
+export default {
+ name: 'PipelineGraph',
+ components: {
+ LinksLayer,
+ LinkedGraphWrapper,
+ LinkedPipelinesColumn,
+ StageColumnComponent,
+ },
+ props: {
+ configPaths: {
+ type: Object,
+ required: true,
+ validator: validateConfigPaths,
+ },
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ showLinks: {
+ type: Boolean,
+ required: true,
+ },
+ viewType: {
+ type: String,
+ required: true,
+ },
+ isLinkedPipeline: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ computedPipelineInfo: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ skipRetryModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ type: {
+ type: String,
+ required: false,
+ default: MAIN,
+ },
+ },
+ pipelineTypeConstants: {
+ DOWNSTREAM,
+ UPSTREAM,
+ },
+ CONTAINER_REF: 'PIPELINE_LINKS_CONTAINER_REF',
+ BASE_CONTAINER_ID: 'pipeline-links-container',
+ data() {
+ return {
+ hoveredJobName: '',
+ hoveredSourceJobName: '',
+ highlightedJobs: [],
+ measurements: {
+ width: 0,
+ height: 0,
+ },
+ pipelineExpanded: {
+ jobName: '',
+ expanded: false,
+ },
+ };
+ },
+ computed: {
+ containerId() {
+ return `${this.$options.BASE_CONTAINER_ID}-${this.pipeline.id}`;
+ },
+ downstreamPipelines() {
+ return this.hasDownstreamPipelines
+ ? keepLatestDownstreamPipelines(this.pipeline.downstream)
+ : [];
+ },
+ layout() {
+ return this.isStageView
+ ? this.pipeline.stages
+ : generateColumnsFromLayersListMemoized(
+ this.pipeline,
+ this.computedPipelineInfo.pipelineLayers,
+ );
+ },
+ hasDownstreamPipelines() {
+ return Boolean(this.pipeline?.downstream?.length > 0);
+ },
+ hasUpstreamPipelines() {
+ return Boolean(this.pipeline?.upstream?.length > 0);
+ },
+ isStageView() {
+ return this.viewType === STAGE_VIEW;
+ },
+ linksData() {
+ return this.computedPipelineInfo?.linksData ?? null;
+ },
+ metricsConfig() {
+ return {
+ path: this.configPaths.metricsPath,
+ collectMetrics: true,
+ };
+ },
+ showJobLinks() {
+ return !this.isStageView && this.showLinks;
+ },
+ // The show downstream check prevents showing redundant linked columns
+ showDownstreamPipelines() {
+ return (
+ this.hasDownstreamPipelines && this.type !== this.$options.pipelineTypeConstants.UPSTREAM
+ );
+ },
+ // The show upstream check prevents showing redundant linked columns
+ showUpstreamPipelines() {
+ return (
+ this.hasUpstreamPipelines && this.type !== this.$options.pipelineTypeConstants.DOWNSTREAM
+ );
+ },
+ upstreamPipelines() {
+ return this.hasUpstreamPipelines ? this.pipeline.upstream : [];
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
+ },
+ mounted() {
+ this.getMeasurements();
+ },
+ methods: {
+ getMeasurements() {
+ this.measurements = {
+ width: this.$refs[this.containerId].scrollWidth,
+ height: this.$refs[this.containerId].scrollHeight,
+ };
+ },
+ onError(payload) {
+ this.$emit('error', payload);
+ },
+ setJob(jobName) {
+ this.hoveredJobName = jobName;
+ },
+ setSourceJob(jobName) {
+ this.hoveredSourceJobName = jobName;
+ },
+ slidePipelineContainer() {
+ this.$refs.mainPipelineContainer.scrollBy({
+ left: ONE_COL_WIDTH,
+ top: 0,
+ behavior: 'smooth',
+ });
+ },
+ togglePipelineExpanded(jobName, expanded) {
+ this.pipelineExpanded = {
+ expanded,
+ jobName: expanded ? jobName : '',
+ };
+ },
+ updateHighlightedJobs(jobs) {
+ this.highlightedJobs = jobs;
+ },
+ },
+};
+</script>
+<template>
+ <div class="js-pipeline-graph">
+ <div
+ ref="mainPipelineContainer"
+ class="gl-display-flex gl-position-relative gl-bg-gray-10 gl-white-space-nowrap"
+ :class="{
+ 'gl-pipeline-min-h gl-py-5 gl-overflow-auto': !isLinkedPipeline,
+ }"
+ >
+ <linked-graph-wrapper>
+ <template #upstream>
+ <linked-pipelines-column
+ v-if="showUpstreamPipelines"
+ :config-paths="configPaths"
+ :linked-pipelines="upstreamPipelines"
+ :column-title="__('Upstream')"
+ :show-links="showJobLinks"
+ :skip-retry-modal="skipRetryModal"
+ :type="$options.pipelineTypeConstants.UPSTREAM"
+ :view-type="viewType"
+ @error="onError"
+ @setSkipRetryModal="$emit('setSkipRetryModal')"
+ />
+ </template>
+ <template #main>
+ <div :id="containerId" :ref="containerId">
+ <links-layer
+ :pipeline-data="layout"
+ :pipeline-id="pipeline.id"
+ :container-id="containerId"
+ :container-measurements="measurements"
+ :highlighted-job="hoveredJobName"
+ :links-data="linksData"
+ :metrics-config="metricsConfig"
+ :show-links="showJobLinks"
+ :view-type="viewType"
+ @error="onError"
+ @highlightedJobsChange="updateHighlightedJobs"
+ >
+ <stage-column-component
+ v-for="column in layout"
+ :key="column.id || column.name"
+ :name="column.name"
+ :groups="column.groups"
+ :action="column.status.action"
+ :highlighted-jobs="highlightedJobs"
+ :is-stage-view="isStageView"
+ :job-hovered="hoveredJobName"
+ :skip-retry-modal="skipRetryModal"
+ :source-job-hovered="hoveredSourceJobName"
+ :pipeline-expanded="pipelineExpanded"
+ :pipeline-id="pipeline.id"
+ :user-permissions="pipeline.userPermissions"
+ @refreshPipelineGraph="$emit('refreshPipelineGraph')"
+ @setSkipRetryModal="$emit('setSkipRetryModal')"
+ @jobHover="setJob"
+ @updateMeasurements="getMeasurements"
+ />
+ </links-layer>
+ </div>
+ </template>
+ <template #downstream>
+ <linked-pipelines-column
+ v-if="showDownstreamPipelines"
+ class="gl-mr-6"
+ :config-paths="configPaths"
+ :linked-pipelines="downstreamPipelines"
+ :column-title="__('Downstream')"
+ :skip-retry-modal="skipRetryModal"
+ :show-links="showJobLinks"
+ :type="$options.pipelineTypeConstants.DOWNSTREAM"
+ :view-type="viewType"
+ data-testid="downstream-pipelines"
+ @downstreamHovered="setSourceJob"
+ @pipelineExpandToggle="togglePipelineExpanded"
+ @refreshPipelineGraph="$emit('refreshPipelineGraph')"
+ @setSkipRetryModal="$emit('setSkipRetryModal')"
+ @scrollContainer="slidePipelineContainer"
+ @error="onError"
+ />
+ </template>
+ </linked-graph-wrapper>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/components/graph_view_selector.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/graph_view_selector.vue
new file mode 100644
index 00000000000..fb7dcb300f1
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/graph_view_selector.vue
@@ -0,0 +1,176 @@
+<script>
+import { GlAlert, GlButton, GlButtonGroup, GlLoadingIcon, GlToggle } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+import { STAGE_VIEW, LAYER_VIEW } from '../constants';
+
+export default {
+ name: 'GraphViewSelector',
+
+ components: {
+ GlAlert,
+ GlButton,
+ GlButtonGroup,
+ GlLoadingIcon,
+ GlToggle,
+ },
+
+ props: {
+ showLinks: {
+ type: Boolean,
+ required: true,
+ },
+ tipPreviouslyDismissed: {
+ type: Boolean,
+ required: true,
+ },
+ type: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ hoverTipDismissed: false,
+ isToggleLoading: false,
+ isSwitcherLoading: false,
+ segmentSelectedType: this.type,
+ showLinksActive: false,
+ };
+ },
+ i18n: {
+ hoverTipText: __('Tip: Hover over a job to see the jobs it depends on to run.'),
+ linksLabelText: s__('GraphViewType|Show dependencies'),
+ viewLabelText: __('Group jobs by'),
+ },
+ views: {
+ [STAGE_VIEW]: {
+ type: STAGE_VIEW,
+ text: {
+ primary: s__('GraphViewType|Stage'),
+ },
+ },
+ [LAYER_VIEW]: {
+ type: LAYER_VIEW,
+ text: {
+ primary: s__('GraphViewType|Job dependencies'),
+ },
+ },
+ },
+ computed: {
+ showLinksToggle() {
+ return this.segmentSelectedType === LAYER_VIEW;
+ },
+ showTip() {
+ return (
+ this.showLinksToggle &&
+ this.showLinks &&
+ this.showLinksActive &&
+ !this.tipPreviouslyDismissed &&
+ !this.hoverTipDismissed
+ );
+ },
+ viewTypesList() {
+ return Object.keys(this.$options.views).map((key) => {
+ return {
+ value: key,
+ text: this.$options.views[key].text.primary,
+ };
+ });
+ },
+ },
+ watch: {
+ /*
+ How does this reset the loading? As we note in the methods comment below,
+ the loader is set to on before the update work is undertaken (in the parent).
+ Once the work is complete, one of these values will change, since that's the
+ point of the work. When that happens, the related value will update and we are done.
+
+ The bonus for this approach is that it works the same whichever "direction"
+ the work goes in.
+ */
+ showLinks() {
+ this.isToggleLoading = false;
+ },
+ type() {
+ this.isSwitcherLoading = false;
+ },
+ },
+ methods: {
+ dismissTip() {
+ this.hoverTipDismissed = true;
+ this.$emit('dismissHoverTip');
+ },
+ isCurrentType(type) {
+ return this.segmentSelectedType === type;
+ },
+ /*
+ In both toggle methods, we use setTimeout so that the loading indicator displays,
+ then the work is done to update the DOM. The process is:
+ → user clicks
+ → call stack: set loading to true
+ → render: the loading icon appears on the screen
+ → callback queue: now do the work to calculate the new view / links
+ (note: this work is done in the parent after the event is emitted)
+
+ setTimeout is how we move the work to the callback queue.
+ We can't use nextTick because that is called before the render loop.
+
+ See https://www.hesselinkwebdesign.nl/2019/nexttick-vs-settimeout-in-vue/ for more details.
+ */
+ setViewType(type) {
+ if (!this.isCurrentType(type)) {
+ this.isSwitcherLoading = true;
+ this.segmentSelectedType = type;
+ setTimeout(() => {
+ this.$emit('updateViewType', type);
+ });
+ }
+ },
+ toggleShowLinksActive(val) {
+ this.isToggleLoading = true;
+ setTimeout(() => {
+ this.$emit('updateShowLinksState', val);
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div class="gl-relative gl-display-flex gl-align-items-center gl-w-max-content gl-my-4">
+ <gl-loading-icon
+ v-if="isSwitcherLoading"
+ data-testid="switcher-loading-state"
+ class="gl-absolute gl-w-full gl-bg-white gl-opacity-5 gl-z-index-2"
+ size="lg"
+ />
+ <span class="gl-font-weight-bold">{{ $options.i18n.viewLabelText }}</span>
+ <gl-button-group class="gl-mx-4">
+ <gl-button
+ v-for="viewType in viewTypesList"
+ :key="viewType.value"
+ :selected="isCurrentType(viewType.value)"
+ @click="setViewType(viewType.value)"
+ >
+ {{ viewType.text }}
+ </gl-button>
+ </gl-button-group>
+
+ <div v-if="showLinksToggle" class="gl-display-flex gl-align-items-center">
+ <gl-toggle
+ v-model="showLinksActive"
+ data-testid="show-links-toggle"
+ class="gl-mx-4"
+ :label="$options.i18n.linksLabelText"
+ :is-loading="isToggleLoading"
+ label-position="left"
+ @change="toggleShowLinksActive"
+ />
+ </div>
+ </div>
+ <gl-alert v-if="showTip" class="gl-my-5" variant="tip" @dismiss="dismissTip">
+ {{ $options.i18n.hoverTipText }}
+ </gl-alert>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/components/job_group_dropdown.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/job_group_dropdown.vue
new file mode 100644
index 00000000000..7538ad87af8
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/job_group_dropdown.vue
@@ -0,0 +1,110 @@
+<script>
+import { reportToSentry } from '~/ci/utils';
+import { JOB_DROPDOWN, SINGLE_JOB } from '../constants';
+import JobItem from './job_item.vue';
+
+/**
+ * Renders the dropdown for the pipeline graph.
+ *
+ * The object provided as `group` corresponds to app/serializers/job_group_entity.rb.
+ *
+ */
+export default {
+ components: {
+ JobItem,
+ },
+ props: {
+ group: {
+ type: Object,
+ required: true,
+ },
+ pipelineId: {
+ type: Number,
+ required: false,
+ default: -1,
+ },
+ cssClassJobName: {
+ type: [String, Array],
+ required: false,
+ default: '',
+ },
+ stageName: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ jobItemTypes: {
+ jobDropdown: JOB_DROPDOWN,
+ singleJob: SINGLE_JOB,
+ },
+ computed: {
+ computedJobId() {
+ return this.pipelineId > -1 ? `${this.group.name}-${this.pipelineId}` : '';
+ },
+ tooltipText() {
+ const { name, status } = this.group;
+ return `${name} - ${status.label}`;
+ },
+ jobGroupClasses() {
+ return [this.cssClassJobName, `job-${this.group.status.group}`];
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry('job_group_dropdown', `error: ${err}, info: ${info}`);
+ },
+ methods: {
+ pipelineActionRequestComplete() {
+ this.$emit('pipelineActionRequestComplete');
+ },
+ },
+};
+</script>
+<template>
+ <!-- eslint-disable @gitlab/vue-no-data-toggle -->
+ <div
+ :id="computedJobId"
+ class="ci-job-dropdown-container dropdown dropright"
+ data-qa-selector="job_dropdown_container"
+ >
+ <button
+ type="button"
+ data-toggle="dropdown"
+ data-display="static"
+ :class="jobGroupClasses"
+ class="dropdown-menu-toggle gl-pipeline-job-width! gl-pr-4!"
+ >
+ <div class="gl-display-flex gl-align-items-stretch gl-justify-content-space-between">
+ <job-item
+ :type="$options.jobItemTypes.jobDropdown"
+ :group-tooltip="tooltipText"
+ :job="group"
+ :stage-name="stageName"
+ />
+
+ <div class="gl-font-weight-100 gl-font-size-lg gl-ml-n4 gl-align-self-center">
+ {{ group.size }}
+ </div>
+ </div>
+ </button>
+
+ <ul
+ class="dropdown-menu big-pipeline-graph-dropdown-menu js-grouped-pipeline-dropdown"
+ data-qa-selector="jobs_dropdown_menu"
+ >
+ <li class="scrollable-menu">
+ <ul>
+ <li v-for="job in group.jobs" :key="job.id">
+ <job-item
+ :dropdown-length="group.size"
+ :job="job"
+ :type="$options.jobItemTypes.singleJob"
+ css-class-job-name="pipeline-job-item"
+ @pipelineActionRequestComplete="pipelineActionRequestComplete"
+ />
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/components/job_item.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/job_item.vue
new file mode 100644
index 00000000000..4298052d1c0
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/job_item.vue
@@ -0,0 +1,396 @@
+<script>
+import { GlBadge, GlForm, GlFormCheckbox, GlLink, GlModal, GlTooltipDirective } from '@gitlab/ui';
+import { reportToSentry } from '~/ci/utils';
+import delayedJobMixin from '~/ci/mixins/delayed_job_mixin';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
+import { __, s__, sprintf } from '~/locale';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import ActionComponent from '../../../common/private/job_action_component.vue';
+import JobNameComponent from '../../../common/private/job_name_component.vue';
+import { BRIDGE_KIND, RETRY_ACTION_TITLE, SINGLE_JOB, SKIP_RETRY_MODAL_KEY } from '../constants';
+
+/**
+ * Renders the badge for the pipeline graph and the job's dropdown.
+ *
+ * The following object should be provided as `job`:
+ *
+ * {
+ * "id": 4256,
+ * "name": "test",
+ * "status": {
+ * "icon": "status_success",
+ * "text": "passed",
+ * "label": "passed",
+ * "group": "success",
+ * "tooltip": "passed",
+ * "details_path": "/root/ci-mock/builds/4256",
+ * "action": {
+ * "icon": "retry",
+ * "title": "Retry",
+ * "path": "/root/ci-mock/builds/4256/retry",
+ * "method": "post"
+ * }
+ * }
+ * }
+ */
+
+export default {
+ confirmationModalDocLink: helpPagePath('/ci/pipelines/downstream_pipelines'),
+ i18n: {
+ bridgeBadgeText: __('Trigger job'),
+ bridgeRetryText: s__(
+ 'PipelineGraph|Downstream pipeline might not display in the graph while the new downstream pipeline is being created.',
+ ),
+ unauthorizedTooltip: __('You are not authorized to run this manual job'),
+ confirmationModal: {
+ title: s__('PipelineGraph|Are you sure you want to retry %{jobName}?'),
+ description: s__(
+ 'PipelineGraph|Retrying a trigger job will create a new downstream pipeline.',
+ ),
+ linkText: s__('PipelineGraph|What is a downstream pipeline?'),
+ footer: __("Don't show this again"),
+ actionPrimary: { text: __('Retry') },
+ actionCancel: { text: __('Cancel') },
+ },
+ runAgainTooltipText: __('Run again'),
+ },
+ hoverClass: 'gl-shadow-x0-y0-b3-s1-blue-500',
+ components: {
+ ActionComponent,
+ CiIcon,
+ GlBadge,
+ GlForm,
+ GlFormCheckbox,
+ GlLink,
+ GlModal,
+ JobNameComponent,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [delayedJobMixin],
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ cssClassJobName: {
+ type: [String, Array, Object],
+ required: false,
+ default: '',
+ },
+ dropdownLength: {
+ type: Number,
+ required: false,
+ default: Infinity,
+ },
+ groupTooltip: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ jobHovered: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ pipelineExpanded: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ pipelineId: {
+ type: Number,
+ required: false,
+ default: -1,
+ },
+ skipRetryModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ sourceJobHovered: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ stageName: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ type: {
+ type: String,
+ required: false,
+ default: SINGLE_JOB,
+ },
+ },
+ data() {
+ return {
+ currentSkipModalValue: this.skipRetryModal,
+ showConfirmationModal: false,
+ shouldTriggerActionClick: false,
+ };
+ },
+ computed: {
+ boundary() {
+ return this.dropdownLength === 1 ? 'viewport' : 'scrollParent';
+ },
+ computedJobId() {
+ return this.pipelineId > -1 ? `${this.job.name}-${this.pipelineId}` : '';
+ },
+ detailsPath() {
+ return this.status.detailsPath;
+ },
+ hasDetails() {
+ return this.status.hasDetails;
+ },
+ hasRetryAction() {
+ return Boolean(this.job?.status?.action?.title === RETRY_ACTION_TITLE);
+ },
+ isRetryableBridge() {
+ return this.isBridge && this.hasRetryAction;
+ },
+ isSingleItem() {
+ return this.type === SINGLE_JOB;
+ },
+ isBridge() {
+ return this.kind === BRIDGE_KIND;
+ },
+ kind() {
+ return this.job?.kind || '';
+ },
+ nameComponent() {
+ return this.hasDetails ? 'gl-link' : 'div';
+ },
+ retryTriggerJobWarningText() {
+ return sprintf(this.$options.i18n.confirmationModal.title, {
+ jobName: this.job.name,
+ });
+ },
+ showStageName() {
+ return Boolean(this.stageName);
+ },
+ status() {
+ return this.job && this.job.status ? this.job.status : {};
+ },
+ testId() {
+ return this.hasDetails ? 'job-with-link' : 'job-without-link';
+ },
+ tooltipText() {
+ if (this.groupTooltip) {
+ return this.groupTooltip;
+ }
+
+ const textBuilder = [];
+ const { name: jobName } = this.job;
+
+ if (jobName) {
+ textBuilder.push(jobName);
+ }
+
+ const { tooltip: statusTooltip } = this.status;
+ if (jobName && statusTooltip) {
+ textBuilder.push('-');
+ }
+
+ if (statusTooltip) {
+ if (this.isDelayedJob) {
+ textBuilder.push(sprintf(statusTooltip, { remainingTime: this.remainingTime }));
+ } else {
+ textBuilder.push(statusTooltip);
+ }
+ }
+
+ return textBuilder.join(' ');
+ },
+ /**
+ * Verifies if the provided job has an action path
+ *
+ * @return {Boolean}
+ */
+ hasAction() {
+ return this.job.status && this.job.status.action && this.job.status.action.path;
+ },
+ hasUnauthorizedManualAction() {
+ return (
+ !this.hasAction &&
+ this.job.status?.group === 'manual' &&
+ this.job.status?.label?.includes('(not allowed)')
+ );
+ },
+ unauthorizedManualActionIcon() {
+ /*
+ The action object is not available when the user cannot run the action.
+ So we can show the correct icon, extract the action name from the label instead:
+ "manual play action (not allowed)" or "manual stop action (not allowed)"
+ */
+ return this.job.status?.label?.split(' ')[1];
+ },
+ relatedDownstreamHovered() {
+ return this.job.name === this.sourceJobHovered;
+ },
+ relatedDownstreamExpanded() {
+ return this.job.name === this.pipelineExpanded.jobName && this.pipelineExpanded.expanded;
+ },
+ jobClasses() {
+ return [
+ {
+ [this.$options.hoverClass]:
+ this.relatedDownstreamHovered || this.relatedDownstreamExpanded,
+ },
+ { 'gl-rounded-lg': this.isBridge },
+ this.cssClassJobName,
+ {
+ [`job-${this.status.group}`]: this.isSingleItem,
+ },
+ ];
+ },
+ withConfirmationModal() {
+ return this.isRetryableBridge && !this.skipRetryModal;
+ },
+ jobActionTooltipText() {
+ const { group } = this.status;
+ const { title, icon } = this.status.action;
+
+ return icon === 'retry' && group === 'success'
+ ? this.$options.i18n.runAgainTooltipText
+ : title;
+ },
+ },
+ watch: {
+ skipRetryModal(val) {
+ this.currentSkipModalValue = val;
+ this.shouldTriggerActionClick = false;
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry('job_item', `error: ${err}, info: ${info}`);
+ },
+ methods: {
+ handleConfirmationModalPreferences() {
+ if (this.currentSkipModalValue) {
+ this.$emit('setSkipRetryModal');
+ localStorage.setItem(SKIP_RETRY_MODAL_KEY, String(this.currentSkipModalValue));
+ }
+ },
+ hideTooltips() {
+ this.$root.$emit(BV_HIDE_TOOLTIP);
+ },
+ jobItemClick(evt) {
+ if (this.isSingleItem) {
+ /*
+ This is so the jobDropdown still toggles. Issue to refactor:
+ https://gitlab.com/gitlab-org/gitlab/-/issues/267117
+ */
+ evt.stopPropagation();
+ }
+
+ this.hideTooltips();
+ },
+ pipelineActionRequestComplete() {
+ this.$emit('pipelineActionRequestComplete');
+
+ if (this.isBridge) {
+ this.$toast.show(this.$options.i18n.bridgeRetryText);
+ }
+ },
+ executePendingAction() {
+ this.shouldTriggerActionClick = true;
+ },
+ showActionConfirmationModal() {
+ this.showConfirmationModal = true;
+ },
+ toggleSkipRetryModalCheckbox() {
+ this.currentSkipModalValue = !this.currentSkipModalValue;
+ },
+ },
+};
+</script>
+<template>
+ <div
+ :id="computedJobId"
+ class="ci-job-component gl-display-flex gl-justify-content-space-between gl-pipeline-job-width"
+ data-qa-selector="job_item_container"
+ >
+ <component
+ :is="nameComponent"
+ v-gl-tooltip="{
+ boundary: 'viewport',
+ placement: 'bottom',
+ customClass: 'gl-pointer-events-none',
+ }"
+ :title="tooltipText"
+ :class="jobClasses"
+ :href="detailsPath"
+ class="js-pipeline-graph-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none gl-focus-text-decoration-none gl-hover-text-decoration-none gl-w-full"
+ :data-testid="testId"
+ data-qa-selector="job_link"
+ @click="jobItemClick"
+ @mouseout="hideTooltips"
+ >
+ <div class="gl-display-flex gl-align-items-center gl-flex-grow-1">
+ <ci-icon :size="24" :status="job.status" class="gl-line-height-0" />
+ <div class="gl-pl-3 gl-pr-3 gl-display-flex gl-flex-direction-column gl-pipeline-job-width">
+ <div class="gl-text-truncate gl-pr-9 gl-line-height-normal">{{ job.name }}</div>
+ <div
+ v-if="showStageName"
+ data-testid="stage-name-in-job"
+ class="gl-text-truncate gl-pr-9 gl-font-sm gl-text-gray-500 gl-line-height-normal"
+ >
+ {{ stageName }}
+ </div>
+ </div>
+ </div>
+ <gl-badge v-if="isBridge" class="gl-mt-3" variant="info" size="sm">
+ {{ $options.i18n.bridgeBadgeText }}
+ </gl-badge>
+ </component>
+
+ <action-component
+ v-if="hasAction"
+ :tooltip-text="jobActionTooltipText"
+ :link="status.action.path"
+ :action-icon="status.action.icon"
+ class="gl-mr-1"
+ :should-trigger-click="shouldTriggerActionClick"
+ :with-confirmation-modal="withConfirmationModal"
+ data-qa-selector="job_action_button"
+ @actionButtonClicked="handleConfirmationModalPreferences"
+ @pipelineActionRequestComplete="pipelineActionRequestComplete"
+ @showActionConfirmationModal="showActionConfirmationModal"
+ />
+ <action-component
+ v-if="hasUnauthorizedManualAction"
+ disabled
+ :tooltip-text="$options.i18n.unauthorizedTooltip"
+ :action-icon="unauthorizedManualActionIcon"
+ :link="`unauthorized-${computedJobId}`"
+ class="gl-mr-1"
+ />
+ <gl-modal
+ v-if="showConfirmationModal"
+ ref="modal"
+ v-model="showConfirmationModal"
+ modal-id="action-confirmation-modal"
+ :title="retryTriggerJobWarningText"
+ :action-cancel="$options.i18n.confirmationModal.actionCancel"
+ :action-primary="$options.i18n.confirmationModal.actionPrimary"
+ @primary="executePendingAction"
+ @close="handleConfirmationModalPreferences"
+ @hide="handleConfirmationModalPreferences"
+ >
+ <p class="gl-mb-1">{{ $options.i18n.confirmationModal.description }}</p>
+ <gl-link :href="$options.confirmationModalDocLink" target="_blank">{{
+ $options.i18n.confirmationModal.linkText
+ }}</gl-link>
+ <div class="gl-mt-4 gl-display-flex">
+ <gl-form>
+ <gl-form-checkbox class="gl-min-h-0" @input="toggleSkipRetryModalCheckbox" />
+ </gl-form>
+ <p class="gl-m-0">{{ $options.i18n.confirmationModal.footer }}</p>
+ </div>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/graph_shared/linked_graph_wrapper.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/linked_graph_wrapper.vue
index fb2280d971a..fb2280d971a 100644
--- a/app/assets/javascripts/pipelines/components/graph_shared/linked_graph_wrapper.vue
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/linked_graph_wrapper.vue
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipeline.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipeline.vue
new file mode 100644
index 00000000000..d6adaf78da4
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipeline.vue
@@ -0,0 +1,306 @@
+<script>
+import {
+ GlBadge,
+ GlButton,
+ GlLink,
+ GlLoadingIcon,
+ GlTooltip,
+ GlTooltipDirective,
+} from '@gitlab/ui';
+import { TYPENAME_CI_PIPELINE } from '~/graphql_shared/constants';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
+import { __, sprintf } from '~/locale';
+import CancelPipelineMutation from '~/ci/pipeline_details/graphql/mutations/cancel_pipeline.mutation.graphql';
+import RetryPipelineMutation from '~/ci/pipeline_details/graphql/mutations/retry_pipeline.mutation.graphql';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import { reportToSentry } from '~/ci/utils';
+import { ACTION_FAILURE, DOWNSTREAM, UPSTREAM } from '../constants';
+
+export default {
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ CiIcon,
+ GlBadge,
+ GlButton,
+ GlLink,
+ GlLoadingIcon,
+ GlTooltip,
+ },
+ styles: {
+ actionSizeClasses: ['gl-h-7 gl-w-7'],
+ flatLeftBorder: ['gl-rounded-bottom-left-none!', 'gl-rounded-top-left-none!'],
+ flatRightBorder: ['gl-rounded-bottom-right-none!', 'gl-rounded-top-right-none!'],
+ },
+ props: {
+ columnTitle: {
+ type: String,
+ required: true,
+ },
+ expanded: {
+ type: Boolean,
+ required: true,
+ },
+ isLoading: {
+ type: Boolean,
+ required: true,
+ },
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ type: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ hasActionTooltip: false,
+ isActionLoading: false,
+ isExpandBtnFocus: false,
+ };
+ },
+ computed: {
+ action() {
+ if (this.isDownstream) {
+ if (this.isCancelable) {
+ return {
+ icon: 'cancel',
+ method: this.cancelPipeline,
+ ariaLabel: __('Cancel downstream pipeline'),
+ };
+ }
+ if (this.isRetryable) {
+ return {
+ icon: 'retry',
+ method: this.retryPipeline,
+ ariaLabel: __('Retry downstream pipeline'),
+ };
+ }
+ }
+
+ return {};
+ },
+ buttonBorderClasses() {
+ return this.isUpstream
+ ? ['gl-border-r-0!', ...this.$options.styles.flatRightBorder]
+ : ['gl-border-l-0!', ...this.$options.styles.flatLeftBorder];
+ },
+ buttonShadowClass() {
+ return this.isExpandBtnFocus ? '' : 'gl-shadow-none!';
+ },
+ buttonId() {
+ return `js-linked-pipeline-${this.pipeline.id}`;
+ },
+ cardClasses() {
+ return this.isDownstream
+ ? this.$options.styles.flatRightBorder
+ : this.$options.styles.flatLeftBorder;
+ },
+ expandedIcon() {
+ if (this.isUpstream) {
+ return this.expanded ? 'chevron-lg-right' : 'chevron-lg-left';
+ }
+ return this.expanded ? 'chevron-lg-left' : 'chevron-lg-right';
+ },
+ expandBtnText() {
+ return this.expanded ? __('Collapse jobs') : __('Expand jobs');
+ },
+ childPipeline() {
+ return this.isDownstream && this.isSameProject;
+ },
+ downstreamTitle() {
+ return this.childPipeline ? this.sourceJobName : this.pipeline.project.name;
+ },
+ flexDirection() {
+ return this.isUpstream ? 'gl-flex-direction-row-reverse' : 'gl-flex-direction-row';
+ },
+ graphqlPipelineId() {
+ return convertToGraphQLId(TYPENAME_CI_PIPELINE, this.pipeline.id);
+ },
+ hasUpdatePipelinePermissions() {
+ return Boolean(this.pipeline?.userPermissions?.updatePipeline);
+ },
+ isCancelable() {
+ return Boolean(this.pipeline?.cancelable && this.hasUpdatePipelinePermissions);
+ },
+ isDownstream() {
+ return this.type === DOWNSTREAM;
+ },
+ isRetryable() {
+ return Boolean(this.pipeline?.retryable && this.hasUpdatePipelinePermissions);
+ },
+ isSameProject() {
+ return !this.pipeline.multiproject;
+ },
+ isUpstream() {
+ return this.type === UPSTREAM;
+ },
+ label() {
+ if (this.parentPipeline) {
+ return __('Parent');
+ }
+ if (this.childPipeline) {
+ return __('Child');
+ }
+ return __('Multi-project');
+ },
+ parentPipeline() {
+ return this.isUpstream && this.isSameProject;
+ },
+ pipelineIsLoading() {
+ return Boolean(this.isLoading || this.pipeline.isLoading);
+ },
+ pipelineStatus() {
+ return this.pipeline.status;
+ },
+ projectName() {
+ return this.pipeline.project.name;
+ },
+ showAction() {
+ return Boolean(this.action?.method && this.action?.icon && this.action?.ariaLabel);
+ },
+ showCardTooltip() {
+ return !this.hasActionTooltip && !this.isExpandBtnFocus;
+ },
+ sourceJobName() {
+ return this.pipeline.sourceJob?.name ?? '';
+ },
+ sourceJobInfo() {
+ return this.isDownstream ? sprintf(__('Created by %{job}'), { job: this.sourceJobName }) : '';
+ },
+ cardTooltipText() {
+ return `${this.downstreamTitle} #${this.pipeline.id} - ${this.pipelineStatus.label} -
+ ${this.sourceJobInfo}`;
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry('linked_pipeline', `error: ${err}, info: ${info}`);
+ },
+ methods: {
+ cancelPipeline() {
+ this.executePipelineAction(CancelPipelineMutation);
+ },
+ async executePipelineAction(mutation) {
+ try {
+ this.isActionLoading = true;
+
+ await this.$apollo.mutate({
+ mutation,
+ variables: {
+ id: this.graphqlPipelineId,
+ },
+ });
+ this.$emit('refreshPipelineGraph');
+ } catch {
+ this.$emit('error', { type: ACTION_FAILURE });
+ } finally {
+ this.isActionLoading = false;
+ }
+ },
+ hideTooltips() {
+ this.$root.$emit(BV_HIDE_TOOLTIP);
+ },
+ onClickLinkedPipeline() {
+ this.hideTooltips();
+ this.$emit('pipelineClicked', this.$refs.linkedPipeline);
+ this.$emit('pipelineExpandToggle', this.sourceJobName, !this.expanded);
+ },
+ onDownstreamHovered() {
+ this.$emit('downstreamHovered', this.sourceJobName);
+ },
+ onDownstreamHoverLeave() {
+ this.$emit('downstreamHovered', '');
+ },
+ retryPipeline() {
+ this.executePipelineAction(RetryPipelineMutation);
+ },
+ setActionTooltip(flag) {
+ this.hasActionTooltip = flag;
+ },
+ setExpandBtnActiveState(flag) {
+ this.isExpandBtnFocus = flag;
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ ref="linkedPipeline"
+ class="gl-h-full gl-display-flex! gl-px-2"
+ :class="flexDirection"
+ data-qa-selector="linked_pipeline_container"
+ @mouseover="onDownstreamHovered"
+ @mouseleave="onDownstreamHoverLeave"
+ >
+ <gl-tooltip v-if="showCardTooltip" :target="() => $refs.linkedPipeline">
+ {{ cardTooltipText }}
+ </gl-tooltip>
+ <div class="gl-bg-white gl-border gl-p-3 gl-rounded-lg gl-w-full" :class="cardClasses">
+ <div class="gl-display-flex gl-gap-x-3">
+ <ci-icon v-if="!pipelineIsLoading" :status="pipelineStatus" :size="24" />
+ <div v-else class="gl-pr-3"><gl-loading-icon size="sm" inline /></div>
+ <div
+ class="gl-display-flex gl-downstream-pipeline-job-width gl-flex-direction-column gl-line-height-normal"
+ >
+ <span
+ class="gl-text-truncate"
+ data-testid="downstream-title"
+ data-qa-selector="downstream_title_content"
+ >
+ {{ downstreamTitle }}
+ </span>
+ <div class="gl-text-truncate">
+ <gl-link
+ class="gl-text-blue-500! gl-font-sm"
+ :href="pipeline.path"
+ data-testid="pipelineLink"
+ >#{{ pipeline.id }}</gl-link
+ >
+ </div>
+ </div>
+ <gl-button
+ v-if="showAction"
+ v-gl-tooltip
+ :title="action.ariaLabel"
+ :loading="isActionLoading"
+ :icon="action.icon"
+ class="gl-rounded-full!"
+ :class="$options.styles.actionSizeClasses"
+ :aria-label="action.ariaLabel"
+ @click="action.method"
+ @mouseover="setActionTooltip(true)"
+ @mouseout="setActionTooltip(false)"
+ />
+ <div v-else :class="$options.styles.actionSizeClasses"></div>
+ </div>
+ <div class="gl-pt-2">
+ <gl-badge size="sm" variant="info" data-testid="downstream-pipeline-label">
+ {{ label }}
+ </gl-badge>
+ </div>
+ </div>
+ <div class="gl-display-flex">
+ <gl-button
+ :id="buttonId"
+ v-gl-tooltip
+ :title="expandBtnText"
+ class="gl-border! gl-rounded-lg!"
+ :class="[`js-pipeline-expand-${pipeline.id}`, buttonBorderClasses, buttonShadowClass]"
+ :icon="expandedIcon"
+ :aria-label="expandBtnText"
+ data-testid="expand-pipeline-button"
+ data-qa-selector="expand_linked_pipeline_button"
+ @mouseover="setExpandBtnActiveState(true)"
+ @mouseout="setExpandBtnActiveState(false)"
+ @focus="setExpandBtnActiveState(true)"
+ @blur="setExpandBtnActiveState(false)"
+ @click="onClickLinkedPipeline"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipelines_column.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipelines_column.vue
new file mode 100644
index 00000000000..2de7e43c9b1
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipelines_column.vue
@@ -0,0 +1,247 @@
+<script>
+import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
+import { reportToSentry } from '~/ci/utils';
+import { LOAD_FAILURE } from '../../constants';
+import { ONE_COL_WIDTH, UPSTREAM, LAYER_VIEW, STAGE_VIEW } from '../constants';
+import {
+ calculatePipelineLayersInfo,
+ getQueryHeaders,
+ serializeLoadErrors,
+ toggleQueryPollingByVisibility,
+ unwrapPipelineData,
+ validateConfigPaths,
+} from '../utils';
+import LinkedPipeline from './linked_pipeline.vue';
+
+export default {
+ components: {
+ LinkedPipeline,
+ PipelineGraph: () => import('./graph_component.vue'),
+ },
+ props: {
+ columnTitle: {
+ type: String,
+ required: true,
+ },
+ configPaths: {
+ type: Object,
+ required: true,
+ validator: validateConfigPaths,
+ },
+ linkedPipelines: {
+ type: Array,
+ required: true,
+ },
+ showLinks: {
+ type: Boolean,
+ required: true,
+ },
+ skipRetryModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ type: {
+ type: String,
+ required: true,
+ },
+ viewType: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ currentPipeline: null,
+ loadingPipelineId: null,
+ pipelineLayers: {},
+ pipelineExpanded: false,
+ };
+ },
+ titleClasses: [
+ 'gl-font-weight-bold',
+ 'gl-pipeline-job-width',
+ 'gl-text-truncate',
+ 'gl-line-height-36',
+ 'gl-pl-3',
+ 'gl-mb-5',
+ ],
+ minWidth: `${ONE_COL_WIDTH}px`,
+ computed: {
+ columnClass() {
+ const positionValues = {
+ right: 'gl-ml-6',
+ left: 'gl-mx-6',
+ };
+
+ return `graph-position-${this.graphPosition} ${positionValues[this.graphPosition]}`;
+ },
+ computedTitleClasses() {
+ const positionalClasses = this.isUpstream ? ['gl-w-full', 'gl-linked-pipeline-padding'] : [];
+
+ return [...this.$options.titleClasses, ...positionalClasses];
+ },
+ graphPosition() {
+ return this.isUpstream ? 'left' : 'right';
+ },
+ graphViewType() {
+ return this.currentPipeline?.usesNeeds ? this.viewType : STAGE_VIEW;
+ },
+ isUpstream() {
+ return this.type === UPSTREAM;
+ },
+ minWidth() {
+ return this.isUpstream ? 0 : this.$options.minWidth;
+ },
+ },
+ methods: {
+ getPipelineData(pipeline) {
+ const projectPath = pipeline.project.fullPath;
+
+ this.$apollo.addSmartQuery('currentPipeline', {
+ query: getPipelineDetails,
+ pollInterval: 10000,
+ context() {
+ return getQueryHeaders(this.configPaths.graphqlResourceEtag);
+ },
+ variables() {
+ return {
+ projectPath,
+ iid: pipeline.iid,
+ };
+ },
+ update(data) {
+ /*
+ This check prevents the pipeline from being overwritten
+ when a poll times out and the data returned is empty.
+ This can be removed once the timeout behavior is updated.
+ See: https://gitlab.com/gitlab-org/gitlab/-/issues/323213.
+ */
+
+ if (!data?.project?.pipeline) {
+ return this.currentPipeline;
+ }
+
+ return unwrapPipelineData(projectPath, JSON.parse(JSON.stringify(data)));
+ },
+ result() {
+ this.loadingPipelineId = null;
+ this.$emit('scrollContainer');
+ },
+ error(err) {
+ this.$emit('error', { type: LOAD_FAILURE, skipSentry: true });
+
+ reportToSentry(
+ 'linked_pipelines_column',
+ `error type: ${LOAD_FAILURE}, error: ${serializeLoadErrors(err)}`,
+ );
+ },
+ });
+
+ toggleQueryPollingByVisibility(this.$apollo.queries.currentPipeline);
+ },
+ getPipelineLayers(id) {
+ if (this.viewType === LAYER_VIEW && !this.pipelineLayers[id]) {
+ this.pipelineLayers[id] = calculatePipelineLayersInfo(
+ this.currentPipeline,
+ this.$options.name,
+ this.configPaths.metricsPath,
+ );
+ }
+
+ return this.pipelineLayers[id];
+ },
+ isExpanded(id) {
+ return Boolean(this.currentPipeline?.id && id === this.currentPipeline.id);
+ },
+ isLoadingPipeline(id) {
+ return this.loadingPipelineId === id;
+ },
+ onPipelineClick(pipeline) {
+ /* If the clicked pipeline has been expanded already, close it, clear, exit */
+ if (this.currentPipeline?.id === pipeline.id) {
+ this.pipelineExpanded = false;
+ this.currentPipeline = null;
+ return;
+ }
+
+ /* Set the loading id */
+ this.loadingPipelineId = pipeline.id;
+
+ /*
+ Expand the pipeline.
+ If this was not a toggle close action, and
+ it was already showing a different pipeline, then
+ this will be a no-op, but that doesn't matter.
+ */
+ this.pipelineExpanded = true;
+
+ this.getPipelineData(pipeline);
+ },
+ onDownstreamHovered(jobName) {
+ this.$emit('downstreamHovered', jobName);
+ },
+ onPipelineExpandToggle(jobName, expanded) {
+ // Highlighting only applies to downstream pipelines
+ if (this.isUpstream) {
+ return;
+ }
+
+ this.$emit('pipelineExpandToggle', jobName, expanded);
+ },
+ showContainer(id) {
+ return this.isExpanded(id) || this.isLoadingPipeline(id);
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-flex">
+ <div :class="columnClass" class="linked-pipelines-column">
+ <div data-testid="linked-column-title" :class="computedTitleClasses">
+ {{ columnTitle }}
+ </div>
+ <ul class="gl-pl-0">
+ <li
+ v-for="pipeline in linkedPipelines"
+ :key="pipeline.id"
+ class="gl-display-flex gl-mb-3"
+ :class="{ 'gl-flex-direction-row-reverse': isUpstream }"
+ >
+ <linked-pipeline
+ class="gl-display-inline-block"
+ :is-loading="isLoadingPipeline(pipeline.id)"
+ :pipeline="pipeline"
+ :column-title="columnTitle"
+ :type="type"
+ :expanded="isExpanded(pipeline.id)"
+ @downstreamHovered="onDownstreamHovered"
+ @pipelineClicked="onPipelineClick(pipeline)"
+ @pipelineExpandToggle="onPipelineExpandToggle"
+ @refreshPipelineGraph="$emit('refreshPipelineGraph')"
+ />
+ <div
+ v-if="showContainer(pipeline.id)"
+ :style="{ minWidth }"
+ class="gl-display-inline-block"
+ >
+ <pipeline-graph
+ v-if="isExpanded(pipeline.id)"
+ :type="type"
+ class="gl-inline-block gl-mt-n2"
+ :config-paths="configPaths"
+ :pipeline="currentPipeline"
+ :computed-pipeline-info="getPipelineLayers(pipeline.id)"
+ :show-links="showLinks"
+ :skip-retry-modal="skipRetryModal"
+ :is-linked-pipeline="true"
+ :view-type="graphViewType"
+ @setSkipRetryModal="$emit('setSkipRetryModal')"
+ />
+ </div>
+ </li>
+ </ul>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/components/links_inner.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/links_inner.vue
new file mode 100644
index 00000000000..09285525c38
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/links_inner.vue
@@ -0,0 +1,162 @@
+<script>
+import { isEmpty } from 'lodash';
+import { STAGE_VIEW } from '~/ci/pipeline_details/graph/constants';
+import { createJobsHash, generateJobNeedsDict } from '~/ci/pipeline_details/utils';
+import { reportToSentry } from '~/ci/utils';
+import { DRAW_FAILURE } from '../../constants';
+import { generateLinksData } from '../../utils/drawing_utils';
+
+export default {
+ name: 'LinksInner',
+ STROKE_WIDTH: 2,
+ props: {
+ containerId: {
+ type: String,
+ required: true,
+ },
+ containerMeasurements: {
+ type: Object,
+ required: true,
+ },
+ linksData: {
+ type: Array,
+ required: true,
+ },
+ pipelineId: {
+ type: Number,
+ required: true,
+ },
+ pipelineData: {
+ type: Array,
+ required: true,
+ },
+ defaultLinkColor: {
+ type: String,
+ required: false,
+ default: 'gl-stroke-gray-200',
+ },
+ highlightedJob: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ viewType: {
+ type: String,
+ required: false,
+ default: STAGE_VIEW,
+ },
+ },
+ data() {
+ return {
+ links: [],
+ needsObject: null,
+ };
+ },
+ computed: {
+ hasHighlightedJob() {
+ return Boolean(this.highlightedJob);
+ },
+ isPipelineDataEmpty() {
+ return isEmpty(this.pipelineData);
+ },
+ highlightedJobs() {
+ // If you are hovering on a job, then the jobs we want to highlight are:
+ // The job you are currently hovering + all of its needs.
+ return this.hasHighlightedJob
+ ? [this.highlightedJob, ...this.needsObject[this.highlightedJob]]
+ : [];
+ },
+ highlightedLinks() {
+ // If you are hovering on a job, then the links we want to highlight are:
+ // All the links whose `source` and `target` are highlighted jobs.
+ if (this.hasHighlightedJob) {
+ const filteredLinks = this.links.filter((link) => {
+ return (
+ this.highlightedJobs.includes(link.source) && this.highlightedJobs.includes(link.target)
+ );
+ });
+
+ return filteredLinks.map((link) => link.ref);
+ }
+
+ return [];
+ },
+ viewBox() {
+ return [0, 0, this.containerMeasurements.width, this.containerMeasurements.height];
+ },
+ },
+ watch: {
+ highlightedJob() {
+ // On first hover, generate the needs reference
+ if (!this.needsObject) {
+ const jobs = createJobsHash(this.pipelineData);
+ this.needsObject = generateJobNeedsDict(jobs) ?? {};
+ }
+ },
+ highlightedJobs(jobs) {
+ this.$emit('highlightedJobsChange', jobs);
+ },
+ linksData() {
+ this.calculateLinkData();
+ },
+ viewType() {
+ /*
+ We need to wait a tick so that the layout reflows
+ before the links refresh.
+ */
+ this.$nextTick(() => {
+ this.calculateLinkData();
+ });
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
+ },
+ mounted() {
+ if (!isEmpty(this.linksData)) {
+ this.calculateLinkData();
+ }
+ },
+ methods: {
+ isLinkHighlighted(linkRef) {
+ return this.highlightedLinks.includes(linkRef);
+ },
+ calculateLinkData() {
+ try {
+ this.links = generateLinksData(this.linksData, this.containerId, `-${this.pipelineId}`);
+ } catch (err) {
+ this.$emit('error', { type: DRAW_FAILURE, reportToSentry: false });
+ reportToSentry(this.$options.name, err);
+ }
+ },
+ getLinkClasses(link) {
+ return [
+ this.isLinkHighlighted(link.ref) ? 'gl-stroke-blue-400' : this.defaultLinkColor,
+ { 'gl-opacity-3': this.hasHighlightedJob && !this.isLinkHighlighted(link.ref) },
+ ];
+ },
+ },
+};
+</script>
+<template>
+ <div class="gl-display-flex gl-relative">
+ <svg
+ id="link-svg"
+ class="gl-absolute gl-pointer-events-none"
+ :viewBox="viewBox"
+ :width="`${containerMeasurements.width}px`"
+ :height="`${containerMeasurements.height}px`"
+ >
+ <path
+ v-for="link in links"
+ :key="link.path"
+ :ref="link.ref"
+ :d="link.path"
+ class="gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease"
+ :class="getLinkClasses(link)"
+ :stroke-width="$options.STROKE_WIDTH"
+ />
+ </svg>
+ <slot></slot>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/graph_shared/main_graph_wrapper.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/root_graph_layout.vue
index bcd7705669e..bcd7705669e 100644
--- a/app/assets/javascripts/pipelines/components/graph_shared/main_graph_wrapper.vue
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/root_graph_layout.vue
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/components/stage_column_component.vue b/app/assets/javascripts/ci/pipeline_details/graph/components/stage_column_component.vue
new file mode 100644
index 00000000000..1401bdba5ca
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/components/stage_column_component.vue
@@ -0,0 +1,196 @@
+<script>
+import { escape, isEmpty } from 'lodash';
+import ActionComponent from '~/ci/common/private/job_action_component.vue';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { reportToSentry } from '~/ci/utils';
+import RootGraphLayout from './root_graph_layout.vue';
+import JobGroupDropdown from './job_group_dropdown.vue';
+import JobItem from './job_item.vue';
+
+export default {
+ components: {
+ ActionComponent,
+ JobGroupDropdown,
+ JobItem,
+ RootGraphLayout,
+ },
+ mixins: [glFeatureFlagMixin()],
+ props: {
+ groups: {
+ type: Array,
+ required: true,
+ },
+ name: {
+ type: String,
+ required: true,
+ },
+ pipelineId: {
+ type: Number,
+ required: true,
+ },
+ action: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ highlightedJobs: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ isStageView: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ jobHovered: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ pipelineExpanded: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ skipRetryModal: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ sourceJobHovered: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ userPermissions: {
+ type: Object,
+ required: true,
+ },
+ },
+ jobClasses: [
+ 'gl-p-3',
+ 'gl-border-gray-100',
+ 'gl-border-solid',
+ 'gl-border-1',
+ 'gl-bg-white',
+ 'gl-rounded-7',
+ 'gl-hover-bg-gray-50',
+ 'gl-focus-bg-gray-50',
+ 'gl-hover-text-gray-900',
+ 'gl-focus-text-gray-900',
+ 'gl-hover-border-gray-200',
+ 'gl-focus-border-gray-200',
+ ],
+ titleClasses: [
+ 'gl-font-weight-bold',
+ 'gl-pipeline-job-width',
+ 'gl-text-truncate',
+ 'gl-line-height-36',
+ 'gl-pl-3',
+ ],
+ computed: {
+ canUpdatePipeline() {
+ return this.userPermissions.updatePipeline;
+ },
+ columnSpacingClass() {
+ return this.isStageView ? 'gl-px-6' : 'gl-px-9';
+ },
+ hasAction() {
+ return !isEmpty(this.action);
+ },
+ showStageName() {
+ return !this.isStageView;
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry('stage_column_component', `error: ${err}, info: ${info}`);
+ },
+ mounted() {
+ this.$emit('updateMeasurements');
+ },
+ methods: {
+ getGroupId(group) {
+ return group.name;
+ },
+ groupId(group) {
+ return `ci-badge-${escape(group.name)}`;
+ },
+ isFadedOut(jobName) {
+ return this.highlightedJobs.length > 1 && !this.highlightedJobs.includes(jobName);
+ },
+ isParallel(group) {
+ return group.size > 1 && group.jobs.length > 1;
+ },
+ singleJobExists(group) {
+ const firstJobDefined = Boolean(group.jobs?.[0]);
+
+ if (!firstJobDefined) {
+ reportToSentry('stage_column_component', 'undefined_job_hunt');
+ }
+
+ return group.size === 1 && firstJobDefined;
+ },
+ },
+};
+</script>
+<template>
+ <root-graph-layout :class="columnSpacingClass" data-testid="stage-column">
+ <template #stages>
+ <div
+ data-testid="stage-column-title"
+ class="gl-display-flex gl-justify-content-space-between gl-relative"
+ :class="$options.titleClasses"
+ >
+ <span :title="name" class="gl-text-truncate gl-pr-3 gl-w-85p">
+ {{ name }}
+ </span>
+ <action-component
+ v-if="hasAction && canUpdatePipeline"
+ :action-icon="action.icon"
+ :tooltip-text="action.title"
+ :link="action.path"
+ class="js-stage-action"
+ @pipelineActionRequestComplete="$emit('refreshPipelineGraph')"
+ />
+ </div>
+ </template>
+ <template #jobs>
+ <div
+ v-for="group in groups"
+ :id="groupId(group)"
+ :key="getGroupId(group)"
+ data-testid="stage-column-group"
+ class="gl-relative gl-mb-3 gl-white-space-normal gl-pipeline-job-width"
+ @mouseenter="$emit('jobHover', group.name)"
+ @mouseleave="$emit('jobHover', '')"
+ >
+ <job-item
+ v-if="singleJobExists(group)"
+ :job="group.jobs[0]"
+ :job-hovered="jobHovered"
+ :skip-retry-modal="skipRetryModal"
+ :source-job-hovered="sourceJobHovered"
+ :pipeline-expanded="pipelineExpanded"
+ :pipeline-id="pipelineId"
+ :stage-name="showStageName ? group.stageName : ''"
+ :css-class-job-name="$options.jobClasses"
+ :class="[
+ { 'gl-opacity-3': isFadedOut(group.name) },
+ 'gl-transition-duration-slow gl-transition-timing-function-ease',
+ ]"
+ @pipelineActionRequestComplete="$emit('refreshPipelineGraph')"
+ @setSkipRetryModal="$emit('setSkipRetryModal')"
+ />
+ <div v-else-if="isParallel(group)" :class="{ 'gl-opacity-3': isFadedOut(group.name) }">
+ <job-group-dropdown
+ :group="group"
+ :stage-name="showStageName ? group.stageName : ''"
+ :pipeline-id="pipelineId"
+ :css-class-job-name="$options.jobClasses"
+ />
+ </div>
+ </div>
+ </template>
+ </root-graph-layout>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/constants.js b/app/assets/javascripts/ci/pipeline_details/graph/constants.js
index e650a48bc2a..e650a48bc2a 100644
--- a/app/assets/javascripts/pipelines/components/graph/constants.js
+++ b/app/assets/javascripts/ci/pipeline_details/graph/constants.js
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/graph_component_wrapper.vue b/app/assets/javascripts/ci/pipeline_details/graph/graph_component_wrapper.vue
new file mode 100644
index 00000000000..bd7325f7925
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/graph_component_wrapper.vue
@@ -0,0 +1,345 @@
+<script>
+import { GlAlert, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
+import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
+import getUserCallouts from '~/graphql_shared/queries/get_user_callouts.query.graphql';
+import { __, s__ } from '~/locale';
+import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
+import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '~/ci/pipeline_details/constants';
+import getPipelineQuery from '~/ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql';
+import { reportToSentry, reportMessageToSentry } from '~/ci/utils';
+import DismissPipelineGraphCallout from './graphql/mutations/dismiss_pipeline_notification.graphql';
+import {
+ ACTION_FAILURE,
+ IID_FAILURE,
+ LAYER_VIEW,
+ SKIP_RETRY_MODAL_KEY,
+ STAGE_VIEW,
+ VIEW_TYPE_KEY,
+} from './constants';
+import PipelineGraph from './components/graph_component.vue';
+import GraphViewSelector from './components/graph_view_selector.vue';
+import {
+ calculatePipelineLayersInfo,
+ getQueryHeaders,
+ serializeLoadErrors,
+ toggleQueryPollingByVisibility,
+ unwrapPipelineData,
+} from './utils';
+
+const featureName = 'pipeline_needs_hover_tip';
+const enumFeatureName = featureName.toUpperCase();
+
+export default {
+ name: 'PipelineGraphWrapper',
+ components: {
+ GlAlert,
+ GlLoadingIcon,
+ GlSprintf,
+ GraphViewSelector,
+ LocalStorageSync,
+ PipelineGraph,
+ },
+ inject: {
+ graphqlResourceEtag: {
+ default: '',
+ },
+ metricsPath: {
+ default: '',
+ },
+ pipelineIid: {
+ default: '',
+ },
+ pipelineProjectPath: {
+ default: '',
+ },
+ },
+ data() {
+ return {
+ alertType: null,
+ callouts: [],
+ computedPipelineInfo: null,
+ currentViewType: STAGE_VIEW,
+ canRefetchHeaderPipeline: false,
+ pipeline: null,
+ skipRetryModal: false,
+ showAlert: false,
+ showJobCountWarning: false,
+ showLinks: false,
+ };
+ },
+ errors: {
+ [ACTION_FAILURE]: {
+ text: __('An error occurred while performing this action.'),
+ variant: 'danger',
+ },
+ [DRAW_FAILURE]: {
+ text: __('An error occurred while drawing job relationship links.'),
+ variant: 'danger',
+ },
+ [IID_FAILURE]: {
+ text: __(
+ 'The data in this pipeline is too old to be rendered as a graph. Please check the Jobs tab to access historical data.',
+ ),
+ variant: 'info',
+ },
+ [LOAD_FAILURE]: {
+ text: __('Currently unable to fetch data for this pipeline.'),
+ variant: 'danger',
+ },
+ [DEFAULT]: {
+ text: __('An unknown error occurred while loading this graph.'),
+ variant: 'danger',
+ },
+ },
+ apollo: {
+ callouts: {
+ query: getUserCallouts,
+ update(data) {
+ return data?.currentUser?.callouts?.nodes.map((callout) => callout.featureName) || [];
+ },
+ error(err) {
+ reportToSentry(
+ this.$options.name,
+ `type: callout_load_failure, info: ${serializeLoadErrors(err)}`,
+ );
+ },
+ },
+ headerPipeline: {
+ query: getPipelineQuery,
+ // this query is already being called in pipeline_details_header.vue, which shares the same cache as this component
+ // the skip here is to prevent sending double network requests on page load
+ skip() {
+ return !this.canRefetchHeaderPipeline;
+ },
+ variables() {
+ return {
+ fullPath: this.pipelineProjectPath,
+ iid: this.pipelineIid,
+ };
+ },
+ update(data) {
+ return data.project?.pipeline || {};
+ },
+ error() {
+ this.reportFailure({ type: LOAD_FAILURE, skipSentry: true });
+ },
+ },
+ pipeline: {
+ context() {
+ return getQueryHeaders(this.graphqlResourceEtag);
+ },
+ query: getPipelineDetails,
+ pollInterval: 10000,
+ variables() {
+ return {
+ projectPath: this.pipelineProjectPath,
+ iid: this.pipelineIid,
+ };
+ },
+ skip() {
+ return !(this.pipelineProjectPath && this.pipelineIid);
+ },
+ update(data) {
+ /*
+ This check prevents the pipeline from being overwritten
+ when a poll times out and the data returned is empty.
+ This can be removed once the timeout behavior is updated.
+ See: https://gitlab.com/gitlab-org/gitlab/-/issues/323213.
+ */
+
+ if (!data?.project?.pipeline) {
+ return this.pipeline;
+ }
+
+ return unwrapPipelineData(this.pipelineProjectPath, JSON.parse(JSON.stringify(data)));
+ },
+ error(err) {
+ this.reportFailure({ type: LOAD_FAILURE, skipSentry: true });
+
+ reportMessageToSentry(
+ this.$options.name,
+ `| type: ${LOAD_FAILURE} , info: ${JSON.stringify(err)}`,
+ {
+ graphViewType: this.graphViewType,
+ graphqlResourceEtag: this.graphqlResourceEtag,
+ metricsPath: this.metricsPath,
+ projectPath: this.pipelineProjectPath,
+ pipelineIid: this.pipelineIid,
+ },
+ );
+ },
+ result({ data, error }) {
+ const stages = data?.project?.pipeline?.stages?.nodes || [];
+
+ this.showJobCountWarning = stages.some((stage) => {
+ return stage.groups.nodes.length >= 100;
+ });
+ /*
+ If there is a successful load after a failure, clear
+ the failure notification to avoid confusion.
+ */
+ if (!error && this.alertType === LOAD_FAILURE) {
+ this.hideAlert();
+ }
+ },
+ },
+ },
+ computed: {
+ alert() {
+ const { errors } = this.$options;
+
+ return {
+ text: errors[this.alertType]?.text ?? errors[DEFAULT].text,
+ variant: errors[this.alertType]?.variant ?? errors[DEFAULT].variant,
+ };
+ },
+ configPaths() {
+ return {
+ graphqlResourceEtag: this.graphqlResourceEtag,
+ metricsPath: this.metricsPath,
+ };
+ },
+ graphViewType() {
+ /* This prevents reading view type off the localStorage value if it does not apply. */
+ return this.showGraphViewSelector ? this.currentViewType : STAGE_VIEW;
+ },
+ hoverTipPreviouslyDismissed() {
+ return this.callouts.includes(enumFeatureName);
+ },
+ showLoadingIcon() {
+ /*
+ Shows the icon only when the graph is empty, not when it is is
+ being refetched, for instance, on action completion
+ */
+ return this.$apollo.queries.pipeline.loading && !this.pipeline;
+ },
+ showGraphViewSelector() {
+ return this.pipeline?.usesNeeds;
+ },
+ },
+ mounted() {
+ if (!this.pipelineIid) {
+ this.reportFailure({ type: IID_FAILURE, skipSentry: true });
+ }
+ toggleQueryPollingByVisibility(this.$apollo.queries.pipeline);
+ this.skipRetryModal = Boolean(JSON.parse(localStorage.getItem(SKIP_RETRY_MODAL_KEY)));
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
+ },
+ methods: {
+ getPipelineInfo() {
+ if (this.currentViewType === LAYER_VIEW && !this.computedPipelineInfo) {
+ this.computedPipelineInfo = calculatePipelineLayersInfo(
+ this.pipeline,
+ this.$options.name,
+ this.metricsPath,
+ );
+ }
+
+ return this.computedPipelineInfo;
+ },
+ handleTipDismissal() {
+ try {
+ this.$apollo.mutate({
+ mutation: DismissPipelineGraphCallout,
+ variables: {
+ featureName,
+ },
+ });
+ } catch (err) {
+ reportToSentry(this.$options.name, `type: callout_dismiss_failure, info: ${err}`);
+ }
+ },
+ hideAlert() {
+ this.showAlert = false;
+ this.alertType = null;
+ },
+ refreshPipelineGraph() {
+ this.$apollo.queries.pipeline.refetch();
+
+ // this will update the status in header_component since they share the same cache
+ this.canRefetchHeaderPipeline = true;
+ this.$apollo.queries.headerPipeline.refetch();
+ },
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ reportFailure({ type, err = 'No error string passed.', skipSentry = false }) {
+ this.showAlert = true;
+ this.alertType = type;
+ if (!skipSentry) {
+ reportToSentry(this.$options.name, `type: ${type}, info: ${err}`);
+ }
+ },
+ updateShowLinksState(val) {
+ this.showLinks = val;
+ },
+ setSkipRetryModal() {
+ this.skipRetryModal = true;
+ },
+ updateViewType(type) {
+ this.currentViewType = type;
+ },
+ },
+ i18n: {
+ jobLimitWarning: {
+ title: s__('Pipeline|Only the first 100 jobs per stage are displayed'),
+ desc: s__('Pipeline|To see the remaining jobs, go to the %{boldStart}Jobs%{boldEnd} tab.'),
+ },
+ },
+ viewTypeKey: VIEW_TYPE_KEY,
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="showAlert"
+ :variant="alert.variant"
+ data-testid="error-alert"
+ @dismiss="hideAlert"
+ >
+ {{ alert.text }}
+ </gl-alert>
+ <gl-alert
+ v-if="showJobCountWarning"
+ variant="warning"
+ :dismissible="false"
+ :title="$options.i18n.jobLimitWarning.title"
+ data-testid="job-count-warning"
+ >
+ <gl-sprintf :message="$options.i18n.jobLimitWarning.desc">
+ <template #bold="{ content }">
+ <b>{{ content }}</b>
+ </template>
+ </gl-sprintf>
+ </gl-alert>
+ <local-storage-sync
+ :storage-key="$options.viewTypeKey"
+ :value="currentViewType"
+ as-string
+ @input="updateViewType"
+ >
+ <graph-view-selector
+ v-if="showGraphViewSelector"
+ :type="graphViewType"
+ :show-links="showLinks"
+ :tip-previously-dismissed="hoverTipPreviouslyDismissed"
+ @dismissHoverTip="handleTipDismissal"
+ @updateViewType="updateViewType"
+ @updateShowLinksState="updateShowLinksState"
+ />
+ </local-storage-sync>
+ <gl-loading-icon v-if="showLoadingIcon" class="gl-mx-auto gl-my-4" size="lg" />
+ <pipeline-graph
+ v-if="pipeline"
+ :config-paths="configPaths"
+ :pipeline="pipeline"
+ :computed-pipeline-info="getPipelineInfo()"
+ :skip-retry-modal="skipRetryModal"
+ :show-links="showLinks"
+ :view-type="graphViewType"
+ @error="reportFailure"
+ @refreshPipelineGraph="refreshPipelineGraph"
+ @setSkipRetryModal="setSkipRetryModal"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/graphql/mutations/dismiss_pipeline_notification.graphql b/app/assets/javascripts/ci/pipeline_details/graph/graphql/mutations/dismiss_pipeline_notification.graphql
index e8af1db9592..e8af1db9592 100644
--- a/app/assets/javascripts/pipelines/graphql/mutations/dismiss_pipeline_notification.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/graph/graphql/mutations/dismiss_pipeline_notification.graphql
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/perf_utils.js b/app/assets/javascripts/ci/pipeline_details/graph/perf_utils.js
new file mode 100644
index 00000000000..511dcbe6889
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/perf_utils.js
@@ -0,0 +1,50 @@
+import {
+ PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START,
+ PIPELINES_DETAIL_LINKS_MARK_CALCULATE_END,
+ PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION,
+ PIPELINES_DETAIL_LINK_DURATION,
+ PIPELINES_DETAIL_LINKS_TOTAL,
+ PIPELINES_DETAIL_LINKS_JOB_RATIO,
+} from '~/performance/constants';
+
+import { performanceMarkAndMeasure } from '~/performance/utils';
+import { reportPerformance } from './api_utils';
+
+export const beginPerfMeasure = () => {
+ performanceMarkAndMeasure({ mark: PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START });
+};
+
+export const finishPerfMeasureAndSend = (numLinks, numGroups, metricsPath) => {
+ performanceMarkAndMeasure({
+ mark: PIPELINES_DETAIL_LINKS_MARK_CALCULATE_END,
+ measures: [
+ {
+ name: PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION,
+ start: PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START,
+ },
+ ],
+ });
+
+ window.requestAnimationFrame(() => {
+ const duration = window.performance.getEntriesByName(
+ PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION,
+ )[0]?.duration;
+
+ if (!duration) {
+ return;
+ }
+
+ const data = {
+ histograms: [
+ { name: PIPELINES_DETAIL_LINK_DURATION, value: duration / 1000 },
+ { name: PIPELINES_DETAIL_LINKS_TOTAL, value: numLinks },
+ {
+ name: PIPELINES_DETAIL_LINKS_JOB_RATIO,
+ value: numLinks / numGroups,
+ },
+ ],
+ };
+
+ reportPerformance(metricsPath, data);
+ });
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/graph/utils.js b/app/assets/javascripts/ci/pipeline_details/graph/utils.js
new file mode 100644
index 00000000000..9a8d6440d4d
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/graph/utils.js
@@ -0,0 +1,117 @@
+import { isEmpty } from 'lodash';
+import { getIdFromGraphQLId, etagQueryHeaders } from '~/graphql_shared/utils';
+import { reportToSentry } from '~/ci/utils';
+
+import { listByLayers } from '~/ci/pipeline_details/utils/parsing_utils';
+import { unwrapStagesWithNeedsAndLookup } from '~/ci/pipeline_details/utils/unwrapping_utils';
+import { beginPerfMeasure, finishPerfMeasureAndSend } from './perf_utils';
+
+export { toggleQueryPollingByVisibility } from '~/graphql_shared/utils';
+
+const addMulti = (mainPipelineProjectPath, linkedPipeline) => {
+ return {
+ ...linkedPipeline,
+ multiproject: mainPipelineProjectPath !== linkedPipeline.project.fullPath,
+ };
+};
+
+const calculatePipelineLayersInfo = (pipeline, componentName, metricsPath) => {
+ const shouldCollectMetrics = Boolean(metricsPath);
+
+ if (shouldCollectMetrics) {
+ beginPerfMeasure();
+ }
+
+ let layers = null;
+
+ try {
+ layers = listByLayers(pipeline);
+
+ if (shouldCollectMetrics) {
+ finishPerfMeasureAndSend(layers.linksData.length, layers.numGroups, metricsPath);
+ }
+ } catch (err) {
+ reportToSentry(componentName, err);
+ }
+
+ return layers;
+};
+
+const getQueryHeaders = (etagResource) =>
+ etagQueryHeaders('verify/ci/pipeline-graph', etagResource);
+
+const serializeGqlErr = (gqlError) => {
+ const { locations = [], message = '', path = [] } = gqlError;
+
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ return `
+ ${message}.
+ Locations: ${locations
+ .flatMap((loc) => Object.entries(loc))
+ .flat(2)
+ .join(' ')}.
+ Path: ${path.join(', ')}.
+ `;
+};
+
+const serializeLoadErrors = (errors) => {
+ const { gqlError, graphQLErrors, networkError, message } = errors;
+
+ if (!isEmpty(graphQLErrors)) {
+ return graphQLErrors.map((err) => serializeGqlErr(err)).join('; ');
+ }
+
+ if (!isEmpty(gqlError)) {
+ return serializeGqlErr(gqlError);
+ }
+
+ if (!isEmpty(networkError)) {
+ return `Network error: ${networkError.message}`; // eslint-disable-line @gitlab/require-i18n-strings
+ }
+
+ return message;
+};
+
+const transformId = (linkedPipeline) => {
+ return { ...linkedPipeline, id: getIdFromGraphQLId(linkedPipeline.id) };
+};
+
+const unwrapPipelineData = (mainPipelineProjectPath, data) => {
+ if (!data?.project?.pipeline) {
+ return null;
+ }
+
+ const { pipeline } = data.project;
+
+ const {
+ upstream,
+ downstream,
+ stages: { nodes: stages },
+ } = pipeline;
+
+ const { stages: updatedStages, lookup } = unwrapStagesWithNeedsAndLookup(stages);
+
+ return {
+ ...pipeline,
+ id: getIdFromGraphQLId(pipeline.id),
+ stages: updatedStages,
+ stagesLookup: lookup,
+ upstream: upstream
+ ? [upstream].map(addMulti.bind(null, mainPipelineProjectPath)).map(transformId)
+ : [],
+ downstream: downstream
+ ? downstream.nodes.map(addMulti.bind(null, mainPipelineProjectPath)).map(transformId)
+ : [],
+ };
+};
+
+const validateConfigPaths = (value) => value.graphqlResourceEtag?.length > 0;
+
+export {
+ calculatePipelineLayersInfo,
+ getQueryHeaders,
+ serializeGqlErr,
+ serializeLoadErrors,
+ unwrapPipelineData,
+ validateConfigPaths,
+};
diff --git a/app/assets/javascripts/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql b/app/assets/javascripts/ci/pipeline_details/graphql/fragments/pipeline_stages_connection.fragment.graphql
index f93908aeb04..f93908aeb04 100644
--- a/app/assets/javascripts/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/graphql/fragments/pipeline_stages_connection.fragment.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql b/app/assets/javascripts/ci/pipeline_details/graphql/mutations/cancel_pipeline.mutation.graphql
index 9afb474cb17..9afb474cb17 100644
--- a/app/assets/javascripts/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/graphql/mutations/cancel_pipeline.mutation.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/mutations/delete_pipeline.mutation.graphql b/app/assets/javascripts/ci/pipeline_details/graphql/mutations/delete_pipeline.mutation.graphql
index a52cecafcaf..a52cecafcaf 100644
--- a/app/assets/javascripts/pipelines/graphql/mutations/delete_pipeline.mutation.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/graphql/mutations/delete_pipeline.mutation.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/mutations/retry_pipeline.mutation.graphql b/app/assets/javascripts/ci/pipeline_details/graphql/mutations/retry_pipeline.mutation.graphql
index 2b3b0822653..2b3b0822653 100644
--- a/app/assets/javascripts/pipelines/graphql/mutations/retry_pipeline.mutation.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/graphql/mutations/retry_pipeline.mutation.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/provider.js b/app/assets/javascripts/ci/pipeline_details/graphql/provider.js
index ef96b443da8..ef96b443da8 100644
--- a/app/assets/javascripts/pipelines/graphql/provider.js
+++ b/app/assets/javascripts/ci/pipeline_details/graphql/provider.js
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_linked_pipelines.query.graphql b/app/assets/javascripts/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql
index 9257cc7de7b..9257cc7de7b 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_linked_pipelines.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql b/app/assets/javascripts/ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql
index eb5643126a2..eb5643126a2 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql
diff --git a/app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue b/app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue
new file mode 100644
index 00000000000..3a6a655bfa6
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue
@@ -0,0 +1,625 @@
+<script>
+import {
+ GlAlert,
+ GlBadge,
+ GlButton,
+ GlIcon,
+ GlLink,
+ GlLoadingIcon,
+ GlModal,
+ GlModalDirective,
+ GlSprintf,
+ GlTooltipDirective,
+} from '@gitlab/ui';
+import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL } from '~/ci/constants';
+import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
+import { setUrlFragment, redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import { __, s__, sprintf, formatNumber } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { LOAD_FAILURE, POST_FAILURE, DELETE_FAILURE, DEFAULT } from '../constants';
+import cancelPipelineMutation from '../graphql/mutations/cancel_pipeline.mutation.graphql';
+import deletePipelineMutation from '../graphql/mutations/delete_pipeline.mutation.graphql';
+import retryPipelineMutation from '../graphql/mutations/retry_pipeline.mutation.graphql';
+import { getQueryHeaders } from '../graph/utils';
+import getPipelineQuery from './graphql/queries/get_pipeline_header_data.query.graphql';
+
+const DELETE_MODAL_ID = 'pipeline-delete-modal';
+const POLL_INTERVAL = 10000;
+
+export default {
+ name: 'PipelineDetailsHeader',
+ BUTTON_TOOLTIP_RETRY,
+ BUTTON_TOOLTIP_CANCEL,
+ pipelineCancel: 'pipelineCancel',
+ pipelineRetry: 'pipelineRetry',
+ finishedStatuses: ['FAILED', 'SUCCESS', 'CANCELED'],
+ components: {
+ CiBadgeLink,
+ ClipboardButton,
+ GlAlert,
+ GlBadge,
+ GlButton,
+ GlIcon,
+ GlLink,
+ GlLoadingIcon,
+ GlModal,
+ GlSprintf,
+ TimeAgoTooltip,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ GlTooltip: GlTooltipDirective,
+ SafeHtml,
+ },
+ i18n: {
+ scheduleBadgeText: s__('Pipelines|Scheduled'),
+ scheduleBadgeTooltip: __('This pipeline was created by a schedule'),
+ childBadgeText: s__('Pipelines|Child pipeline (%{linkStart}parent%{linkEnd})'),
+ childBadgeTooltip: __('This is a child pipeline within the parent pipeline'),
+ latestBadgeText: s__('Pipelines|latest'),
+ latestBadgeTooltip: __('Latest pipeline for the most recent commit on this branch'),
+ mergeTrainBadgeText: s__('Pipelines|merge train'),
+ mergeTrainBadgeTooltip: s__(
+ 'Pipelines|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch.',
+ ),
+ invalidBadgeText: s__('Pipelines|yaml invalid'),
+ failedBadgeText: s__('Pipelines|error'),
+ autoDevopsBadgeText: s__('Pipelines|Auto DevOps'),
+ autoDevopsBadgeTooltip: __(
+ 'This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps.',
+ ),
+ detachedBadgeText: s__('Pipelines|merge request'),
+ detachedBadgeTooltip: s__(
+ "Pipelines|This pipeline ran on the contents of this merge request's source branch, not the target branch.",
+ ),
+ stuckBadgeText: s__('Pipelines|stuck'),
+ stuckBadgeTooltip: s__('Pipelines|This pipeline is stuck'),
+ computeMinutesTooltip: s__('Pipelines|Total amount of compute minutes used for the pipeline'),
+ totalJobsTooltip: s__('Pipelines|Total number of jobs for the pipeline'),
+ retryPipelineText: __('Retry'),
+ cancelPipelineText: __('Cancel pipeline'),
+ deletePipelineText: __('Delete'),
+ clipboardTooltip: __('Copy commit SHA'),
+ createdText: s__('Pipelines|created'),
+ finishedText: s__('Pipelines|finished'),
+ },
+ errorTexts: {
+ [LOAD_FAILURE]: __('We are currently unable to fetch data for the pipeline header.'),
+ [POST_FAILURE]: __('An error occurred while making the request.'),
+ [DELETE_FAILURE]: __('An error occurred while deleting the pipeline.'),
+ [DEFAULT]: __('An unknown error occurred.'),
+ },
+ modal: {
+ id: DELETE_MODAL_ID,
+ title: __('Delete pipeline'),
+ deleteConfirmationText: __(
+ 'Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone.',
+ ),
+ actionPrimary: {
+ text: __('Delete pipeline'),
+ attributes: {
+ variant: 'danger',
+ },
+ },
+ actionCancel: {
+ text: __('Cancel'),
+ },
+ },
+ inject: {
+ graphqlResourceEtag: {
+ default: '',
+ },
+ paths: {
+ default: {},
+ },
+ pipelineIid: {
+ default: '',
+ },
+ },
+ props: {
+ name: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ totalJobs: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ computeMinutes: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ yamlErrors: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ failureReason: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ refText: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ badges: {
+ type: Object,
+ required: false,
+ default: () => {},
+ },
+ },
+ apollo: {
+ pipeline: {
+ context() {
+ return getQueryHeaders(this.graphqlResourceEtag);
+ },
+ query: getPipelineQuery,
+ variables() {
+ return {
+ fullPath: this.paths.fullProject,
+ iid: this.pipelineIid,
+ };
+ },
+ update(data) {
+ return data.project.pipeline;
+ },
+ error() {
+ this.reportFailure(LOAD_FAILURE);
+ },
+ pollInterval: POLL_INTERVAL,
+ watchLoading(isLoading) {
+ if (!isLoading) {
+ // To ensure apollo has updated the cache,
+ // we only remove the loading state in sync with GraphQL
+ this.isCanceling = false;
+ this.isRetrying = false;
+ }
+ },
+ },
+ },
+ data() {
+ return {
+ pipeline: null,
+ failureMessages: [],
+ failureType: null,
+ isCanceling: false,
+ isRetrying: false,
+ isDeleting: false,
+ };
+ },
+ computed: {
+ loading() {
+ return this.$apollo.queries.pipeline.loading;
+ },
+ hasError() {
+ return this.failureType;
+ },
+ hasPipelineData() {
+ return Boolean(this.pipeline);
+ },
+ isLoadingInitialQuery() {
+ return this.$apollo.queries.pipeline.loading && !this.hasPipelineData;
+ },
+ detailedStatus() {
+ return this.pipeline?.detailedStatus || {};
+ },
+ status() {
+ return this.pipeline?.status;
+ },
+ isFinished() {
+ return this.$options.finishedStatuses.includes(this.status);
+ },
+ shouldRenderContent() {
+ return !this.isLoadingInitialQuery && this.hasPipelineData;
+ },
+ failure() {
+ switch (this.failureType) {
+ case LOAD_FAILURE:
+ return {
+ text: this.$options.errorTexts[LOAD_FAILURE],
+ variant: 'danger',
+ };
+ case POST_FAILURE:
+ return {
+ text: this.$options.errorTexts[POST_FAILURE],
+ variant: 'danger',
+ };
+ case DELETE_FAILURE:
+ return {
+ text: this.$options.errorTexts[DELETE_FAILURE],
+ variant: 'danger',
+ };
+ default:
+ return {
+ text: this.$options.errorTexts[DEFAULT],
+ variant: 'danger',
+ };
+ }
+ },
+ user() {
+ return this.pipeline?.user;
+ },
+ userId() {
+ return getIdFromGraphQLId(this.user?.id);
+ },
+ shortId() {
+ return this.pipeline?.commit?.shortId || '';
+ },
+ commitPath() {
+ return this.pipeline?.commit?.webPath || '';
+ },
+ commitTitle() {
+ return this.pipeline?.commit?.title || '';
+ },
+ totalJobsText() {
+ return sprintf(__('%{jobs} Jobs'), {
+ jobs: this.totalJobs,
+ });
+ },
+ triggeredText() {
+ return sprintf(__('created pipeline for commit %{linkStart}%{shortId}%{linkEnd}'), {
+ shortId: this.shortId,
+ });
+ },
+ inProgress() {
+ return this.status === 'RUNNING';
+ },
+ duration() {
+ return this.pipeline?.duration || 0;
+ },
+ showDuration() {
+ return this.duration && this.isFinished;
+ },
+ durationFormatted() {
+ return timeIntervalInWords(this.duration);
+ },
+ queuedDuration() {
+ return this.pipeline?.queuedDuration || 0;
+ },
+ inProgressText() {
+ return sprintf(__('In progress, queued for %{queuedDuration} seconds'), {
+ queuedDuration: formatNumber(this.queuedDuration),
+ });
+ },
+ durationText() {
+ return sprintf(__('%{duration}, queued for %{queuedDuration} seconds'), {
+ duration: this.durationFormatted,
+ queuedDuration: formatNumber(this.queuedDuration),
+ });
+ },
+ canRetryPipeline() {
+ const { retryable, userPermissions } = this.pipeline;
+
+ return retryable && userPermissions.updatePipeline;
+ },
+ canCancelPipeline() {
+ const { cancelable, userPermissions } = this.pipeline;
+
+ return cancelable && userPermissions.updatePipeline;
+ },
+ showComputeMinutes() {
+ return this.isFinished && this.computeMinutes !== '0.0';
+ },
+ },
+ methods: {
+ reportFailure(errorType, errorMessages = []) {
+ this.failureType = errorType;
+ this.failureMessages = errorMessages;
+ },
+ async postPipelineAction(name, mutation) {
+ try {
+ const {
+ data: {
+ [name]: { errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation,
+ variables: { id: this.pipeline.id },
+ });
+
+ if (errors.length > 0) {
+ this.isRetrying = false;
+
+ this.reportFailure(POST_FAILURE, errors);
+ } else {
+ await this.$apollo.queries.pipeline.refetch();
+ if (!this.isFinished) {
+ this.$apollo.queries.pipeline.startPolling(POLL_INTERVAL);
+ }
+ }
+ } catch {
+ this.isRetrying = false;
+
+ this.reportFailure(POST_FAILURE);
+ }
+ },
+ cancelPipeline() {
+ this.isCanceling = true;
+ this.postPipelineAction(this.$options.pipelineCancel, cancelPipelineMutation);
+ },
+ retryPipeline() {
+ this.isRetrying = true;
+ this.postPipelineAction(this.$options.pipelineRetry, retryPipelineMutation);
+ },
+ async deletePipeline() {
+ this.isDeleting = true;
+ this.$apollo.queries.pipeline.stopPolling();
+
+ try {
+ const {
+ data: {
+ pipelineDestroy: { errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: deletePipelineMutation,
+ variables: {
+ id: this.pipeline.id,
+ },
+ });
+
+ if (errors.length > 0) {
+ this.reportFailure(DELETE_FAILURE, errors);
+ this.isDeleting = false;
+ } else {
+ redirectTo(setUrlFragment(this.paths.pipelinesPath, 'delete_success')); // eslint-disable-line import/no-deprecated
+ }
+ } catch {
+ this.$apollo.queries.pipeline.startPolling(POLL_INTERVAL);
+ this.reportFailure(DELETE_FAILURE);
+ this.isDeleting = false;
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-my-4" data-testid="pipeline-details-header">
+ <gl-alert
+ v-if="hasError"
+ class="gl-mb-4"
+ :title="failure.text"
+ :variant="failure.variant"
+ :dismissible="false"
+ >
+ <div v-for="(failureMessage, index) in failureMessages" :key="`failure-message-${index}`">
+ {{ failureMessage }}
+ </div>
+ </gl-alert>
+ <gl-loading-icon v-if="loading" class="gl-text-left" size="lg" />
+ <div
+ v-else
+ class="gl-display-flex gl-justify-content-space-between gl-flex-wrap"
+ data-qa-selector="pipeline_details_header"
+ >
+ <div>
+ <h3 v-if="name" class="gl-mt-0 gl-mb-3" data-testid="pipeline-name">{{ name }}</h3>
+ <h3 v-else class="gl-mt-0 gl-mb-3" data-testid="pipeline-commit-title">
+ {{ commitTitle }}
+ </h3>
+ <div>
+ <ci-badge-link :status="detailedStatus" />
+ <div class="gl-ml-2 gl-mb-3 gl-display-inline-block gl-h-6">
+ <gl-link
+ v-if="user"
+ :href="user.webUrl"
+ class="gl-display-inline-block gl-text-gray-900 gl-font-weight-bold js-user-link"
+ :data-user-id="userId"
+ :data-username="user.username"
+ data-testid="pipeline-user-link"
+ >
+ {{ user.name }}
+ </gl-link>
+ <gl-sprintf :message="triggeredText">
+ <template #link="{ content }">
+ <gl-link
+ :href="commitPath"
+ class="gl-bg-blue-50 gl-rounded-base gl-px-2 gl-mx-2"
+ data-testid="commit-link"
+ target="_blank"
+ >
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ <clipboard-button
+ :text="shortId"
+ category="tertiary"
+ :title="$options.i18n.clipboardTooltip"
+ size="small"
+ />
+ <span v-if="inProgress" data-testid="pipeline-created-time-ago">
+ {{ $options.i18n.createdText }}
+ <time-ago-tooltip :time="pipeline.createdAt" />
+ </span>
+ <span v-if="isFinished" data-testid="pipeline-finished-time-ago">
+ {{ $options.i18n.finishedText }}
+ <time-ago-tooltip :time="pipeline.finishedAt" />
+ </span>
+ </div>
+ </div>
+ <div v-safe-html="refText" class="gl-mb-3" data-testid="pipeline-ref-text"></div>
+ <div>
+ <gl-badge
+ v-if="badges.schedule"
+ v-gl-tooltip
+ :title="$options.i18n.scheduleBadgeTooltip"
+ variant="info"
+ size="sm"
+ >
+ {{ $options.i18n.scheduleBadgeText }}
+ </gl-badge>
+ <gl-badge
+ v-if="badges.child"
+ v-gl-tooltip
+ :title="$options.i18n.childBadgeTooltip"
+ variant="info"
+ size="sm"
+ >
+ <gl-sprintf :message="$options.i18n.childBadgeText">
+ <template #link="{ content }">
+ <gl-link :href="paths.triggeredByPath" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-badge>
+ <gl-badge
+ v-if="badges.latest"
+ v-gl-tooltip
+ :title="$options.i18n.latestBadgeTooltip"
+ variant="success"
+ size="sm"
+ >
+ {{ $options.i18n.latestBadgeText }}
+ </gl-badge>
+ <gl-badge
+ v-if="badges.mergeTrainPipeline"
+ v-gl-tooltip
+ :title="$options.i18n.mergeTrainBadgeTooltip"
+ variant="info"
+ size="sm"
+ >
+ {{ $options.i18n.mergeTrainBadgeText }}
+ </gl-badge>
+ <gl-badge
+ v-if="badges.invalid"
+ v-gl-tooltip
+ :title="yamlErrors"
+ variant="danger"
+ size="sm"
+ >
+ {{ $options.i18n.invalidBadgeText }}
+ </gl-badge>
+ <gl-badge
+ v-if="badges.failed"
+ v-gl-tooltip
+ :title="failureReason"
+ variant="danger"
+ size="sm"
+ >
+ {{ $options.i18n.failedBadgeText }}
+ </gl-badge>
+ <gl-badge
+ v-if="badges.autoDevops"
+ v-gl-tooltip
+ :title="$options.i18n.autoDevopsBadgeTooltip"
+ variant="info"
+ size="sm"
+ >
+ {{ $options.i18n.autoDevopsBadgeText }}
+ </gl-badge>
+ <gl-badge
+ v-if="badges.detached"
+ v-gl-tooltip
+ :title="$options.i18n.detachedBadgeTooltip"
+ variant="info"
+ size="sm"
+ >
+ {{ $options.i18n.detachedBadgeText }}
+ </gl-badge>
+ <gl-badge
+ v-if="badges.stuck"
+ v-gl-tooltip
+ :title="$options.i18n.stuckBadgeTooltip"
+ variant="warning"
+ size="sm"
+ >
+ {{ $options.i18n.stuckBadgeText }}
+ </gl-badge>
+ <span
+ v-gl-tooltip
+ :title="$options.i18n.totalJobsTooltip"
+ class="gl-ml-2"
+ data-testid="total-jobs"
+ >
+ <gl-icon name="pipeline" />
+ {{ totalJobsText }}
+ </span>
+ <span
+ v-if="showComputeMinutes"
+ v-gl-tooltip
+ :title="$options.i18n.computeMinutesTooltip"
+ class="gl-ml-2"
+ data-testid="compute-minutes"
+ >
+ <gl-icon name="quota" />
+ {{ computeMinutes }}
+ </span>
+ <span v-if="inProgress" class="gl-ml-2" data-testid="pipeline-running-text">
+ <gl-icon name="timer" />
+ {{ inProgressText }}
+ </span>
+ <span v-if="showDuration" class="gl-ml-2" data-testid="pipeline-duration-text">
+ <gl-icon name="timer" />
+ {{ durationText }}
+ </span>
+ </div>
+ </div>
+ <div class="gl-mt-5 gl-lg-mt-0">
+ <gl-button
+ v-if="canRetryPipeline"
+ v-gl-tooltip
+ :aria-label="$options.BUTTON_TOOLTIP_RETRY"
+ :title="$options.BUTTON_TOOLTIP_RETRY"
+ :loading="isRetrying"
+ :disabled="isRetrying"
+ variant="confirm"
+ data-testid="retry-pipeline"
+ class="js-retry-button"
+ @click="retryPipeline()"
+ >
+ {{ $options.i18n.retryPipelineText }}
+ </gl-button>
+
+ <gl-button
+ v-if="canCancelPipeline"
+ v-gl-tooltip
+ :aria-label="$options.BUTTON_TOOLTIP_CANCEL"
+ :title="$options.BUTTON_TOOLTIP_CANCEL"
+ :loading="isCanceling"
+ :disabled="isCanceling"
+ class="gl-ml-3"
+ variant="danger"
+ data-testid="cancel-pipeline"
+ @click="cancelPipeline()"
+ >
+ {{ $options.i18n.cancelPipelineText }}
+ </gl-button>
+
+ <gl-button
+ v-if="pipeline.userPermissions.destroyPipeline"
+ v-gl-modal="$options.modal.id"
+ :loading="isDeleting"
+ :disabled="isDeleting"
+ class="gl-ml-3"
+ variant="danger"
+ category="secondary"
+ data-testid="delete-pipeline"
+ >
+ {{ $options.i18n.deletePipelineText }}
+ </gl-button>
+ </div>
+ </div>
+ <gl-modal
+ :modal-id="$options.modal.id"
+ :title="$options.modal.title"
+ :action-primary="$options.modal.actionPrimary"
+ :action-cancel="$options.modal.actionCancel"
+ @primary="deletePipeline()"
+ >
+ <p>
+ {{ $options.modal.deleteConfirmationText }}
+ </p>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/jobs/components/failed_jobs_table.vue b/app/assets/javascripts/ci/pipeline_details/jobs/components/failed_jobs_table.vue
new file mode 100644
index 00000000000..4752fbb3e96
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/jobs/components/failed_jobs_table.vue
@@ -0,0 +1,126 @@
+<script>
+import { GlButton, GlLink, GlTableLite } from '@gitlab/ui';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { __, s__ } from '~/locale';
+import { createAlert } from '~/alert';
+import Tracking from '~/tracking';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+import RetryFailedJobMutation from '../graphql/mutations/retry_failed_job.mutation.graphql';
+import { DEFAULT_FIELDS } from '../../constants';
+
+export default {
+ fields: DEFAULT_FIELDS,
+ retry: __('Retry'),
+ components: {
+ CiBadgeLink,
+ GlButton,
+ GlLink,
+ GlTableLite,
+ },
+ directives: {
+ SafeHtml,
+ },
+ mixins: [Tracking.mixin()],
+ props: {
+ failedJobs: {
+ type: Array,
+ required: true,
+ },
+ },
+ methods: {
+ async retryJob(id) {
+ this.track('click_retry', { label: TRACKING_CATEGORIES.failed });
+
+ try {
+ const {
+ data: {
+ jobRetry: { errors, job },
+ },
+ } = await this.$apollo.mutate({
+ mutation: RetryFailedJobMutation,
+ variables: { id },
+ });
+ if (errors.length > 0) {
+ this.showErrorMessage();
+ } else {
+ redirectTo(job.detailedStatus.detailsPath); // eslint-disable-line import/no-deprecated
+ }
+ } catch {
+ this.showErrorMessage();
+ }
+ },
+ canRetryJob(job) {
+ return job.retryable && job.userPermissions.updateBuild;
+ },
+ showErrorMessage() {
+ createAlert({ message: s__('Job|There was a problem retrying the failed job.') });
+ },
+ failureSummary(trace) {
+ return trace ? trace.htmlSummary : s__('Job|No job log');
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-table-lite
+ :items="failedJobs"
+ :fields="$options.fields"
+ stacked="lg"
+ fixed
+ data-testId="tab-failures"
+ >
+ <template #table-colgroup="{ fields }">
+ <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
+ </template>
+
+ <template #cell(name)="{ item }">
+ <div
+ class="gl-display-flex gl-align-items-center gl-lg-justify-content-start gl-justify-content-end"
+ >
+ <ci-badge-link :status="item.detailedStatus" :show-text="false" class="gl-mr-3" />
+ <div class="gl-text-truncate">
+ <gl-link
+ :href="item.detailedStatus.detailsPath"
+ class="gl-font-weight-bold gl-text-gray-900!"
+ >
+ {{ item.name }}
+ </gl-link>
+ </div>
+ </div>
+ </template>
+
+ <template #cell(stage)="{ item }">
+ <div class="gl-text-truncate">
+ <span>{{ item.stage.name }}</span>
+ </div>
+ </template>
+
+ <template #cell(failureMessage)="{ item }">
+ <span data-testid="job-failure-message">{{ item.failureMessage }}</span>
+ </template>
+
+ <template #cell(actions)="{ item }">
+ <gl-button
+ v-if="canRetryJob(item)"
+ icon="retry"
+ :title="$options.retry"
+ :aria-label="$options.retry"
+ @click="retryJob(item.id)"
+ />
+ </template>
+
+ <template #row-details="{ item }">
+ <pre
+ v-if="item.userPermissions.readBuild"
+ class="gl-w-full gl-text-left gl-border-none"
+ data-testid="job-log"
+ >
+ <code v-safe-html="failureSummary(item.trace)" class="gl-reset-bg gl-p-0" data-testid="job-trace-summary">
+ </code>
+ </pre>
+ </template>
+ </gl-table-lite>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/jobs/failed_jobs_app.vue b/app/assets/javascripts/ci/pipeline_details/jobs/failed_jobs_app.vue
new file mode 100644
index 00000000000..b946a40e590
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/jobs/failed_jobs_app.vue
@@ -0,0 +1,65 @@
+<script>
+import { GlLoadingIcon } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { createAlert } from '~/alert';
+import GetFailedJobsQuery from './graphql/queries/get_failed_jobs.query.graphql';
+import FailedJobsTable from './components/failed_jobs_table.vue';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ FailedJobsTable,
+ },
+ inject: {
+ projectPath: {
+ default: '',
+ },
+ pipelineIid: {
+ default: '',
+ },
+ },
+ apollo: {
+ failedJobs: {
+ query: GetFailedJobsQuery,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ pipelineIid: this.pipelineIid,
+ };
+ },
+ update({ project }) {
+ const jobNodes = project?.pipeline?.jobs?.nodes || [];
+
+ return jobNodes.map((job) => {
+ return {
+ ...job,
+ // this field is needed for the slot row-details
+ // on the failed_jobs_table.vue component
+ _showDetails: true,
+ };
+ });
+ },
+ error() {
+ createAlert({ message: s__('Jobs|There was a problem fetching the failed jobs.') });
+ },
+ },
+ },
+ data() {
+ return {
+ failedJobs: [],
+ };
+ },
+ computed: {
+ loading() {
+ return this.$apollo.queries.failedJobs.loading;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-loading-icon v-if="loading" size="lg" class="gl-mt-4" />
+ <failed-jobs-table v-else :failed-jobs="failedJobs" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/graphql/mutations/retry_failed_job.mutation.graphql b/app/assets/javascripts/ci/pipeline_details/jobs/graphql/mutations/retry_failed_job.mutation.graphql
index 1955cc9b0ac..1955cc9b0ac 100644
--- a/app/assets/javascripts/pipelines/graphql/mutations/retry_failed_job.mutation.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/jobs/graphql/mutations/retry_failed_job.mutation.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_failed_jobs.query.graphql b/app/assets/javascripts/ci/pipeline_details/jobs/graphql/queries/get_failed_jobs.query.graphql
index c1f994ece24..c1f994ece24 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_failed_jobs.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/jobs/graphql/queries/get_failed_jobs.query.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_jobs.query.graphql b/app/assets/javascripts/ci/pipeline_details/jobs/graphql/queries/get_pipeline_jobs.query.graphql
index b0f875160d4..b0f875160d4 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_jobs.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_details/jobs/graphql/queries/get_pipeline_jobs.query.graphql
diff --git a/app/assets/javascripts/ci/pipeline_details/jobs/jobs_app.vue b/app/assets/javascripts/ci/pipeline_details/jobs/jobs_app.vue
new file mode 100644
index 00000000000..81b6152347d
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/jobs/jobs_app.vue
@@ -0,0 +1,133 @@
+<script>
+import { GlIntersectionObserver, GlLoadingIcon, GlSkeletonLoader } from '@gitlab/ui';
+import produce from 'immer';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import eventHub from '~/ci/jobs_page/event_hub';
+import JobsTable from '~/ci/jobs_page/components/jobs_table.vue';
+import { JOBS_TAB_FIELDS } from '~/ci/jobs_page/constants';
+import getPipelineJobs from './graphql/queries/get_pipeline_jobs.query.graphql';
+
+export default {
+ fields: JOBS_TAB_FIELDS,
+ components: {
+ GlIntersectionObserver,
+ GlLoadingIcon,
+ GlSkeletonLoader,
+ JobsTable,
+ },
+ inject: {
+ projectPath: {
+ default: '',
+ },
+ pipelineIid: {
+ default: '',
+ },
+ },
+ apollo: {
+ jobs: {
+ query: getPipelineJobs,
+ variables() {
+ return {
+ ...this.queryVariables,
+ };
+ },
+ update(data) {
+ return data.project?.pipeline?.jobs?.nodes || [];
+ },
+ result({ data }) {
+ if (!data) {
+ return;
+ }
+ this.jobsPageInfo = data.project?.pipeline?.jobs?.pageInfo || {};
+ },
+ error() {
+ createAlert({ message: __('An error occurred while fetching the pipelines jobs.') });
+ },
+ },
+ },
+ data() {
+ return {
+ jobs: [],
+ jobsPageInfo: {},
+ firstLoad: true,
+ };
+ },
+ computed: {
+ queryVariables() {
+ return {
+ fullPath: this.projectPath,
+ iid: this.pipelineIid,
+ };
+ },
+ loading() {
+ return this.$apollo.queries.jobs.loading;
+ },
+ showSkeletonLoader() {
+ return this.firstLoad && this.loading;
+ },
+ showLoadingSpinner() {
+ return !this.firstLoad && this.loading;
+ },
+ },
+ mounted() {
+ eventHub.$on('jobActionPerformed', this.handleJobAction);
+ },
+ beforeDestroy() {
+ eventHub.$off('jobActionPerformed', this.handleJobAction);
+ },
+ methods: {
+ handleJobAction() {
+ this.firstLoad = false;
+
+ this.$apollo.queries.jobs.refetch();
+ },
+ fetchMoreJobs() {
+ this.firstLoad = false;
+
+ this.$apollo.queries.jobs.fetchMore({
+ variables: {
+ ...this.queryVariables,
+ after: this.jobsPageInfo.endCursor,
+ },
+ updateQuery: (previousResult, { fetchMoreResult }) => {
+ const results = produce(fetchMoreResult, (draftData) => {
+ draftData.project.pipeline.jobs.nodes = [
+ ...previousResult.project.pipeline.jobs.nodes,
+ ...draftData.project.pipeline.jobs.nodes,
+ ];
+ });
+ return results;
+ },
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div v-if="showSkeletonLoader" class="gl-mt-5">
+ <gl-skeleton-loader :width="1248" :height="73">
+ <circle cx="748.031" cy="37.7193" r="15.0307" />
+ <circle cx="787.241" cy="37.7193" r="15.0307" />
+ <circle cx="827.759" cy="37.7193" r="15.0307" />
+ <circle cx="866.969" cy="37.7193" r="15.0307" />
+ <circle cx="380" cy="37" r="18" />
+ <rect x="432" y="19" width="126.587" height="15" />
+ <rect x="432" y="41" width="247" height="15" />
+ <rect x="158" y="19" width="86.1" height="15" />
+ <rect x="158" y="41" width="168" height="15" />
+ <rect x="22" y="19" width="96" height="36" />
+ <rect x="924" y="30" width="96" height="15" />
+ <rect x="1057" y="20" width="166" height="35" />
+ </gl-skeleton-loader>
+ </div>
+
+ <jobs-table v-else :jobs="jobs" :table-fields="$options.fields" data-testid="jobs-tab-table" />
+
+ <gl-intersection-observer v-if="jobsPageInfo.hasNextPage" @appear="fetchMoreJobs">
+ <gl-loading-icon v-if="showLoadingSpinner" size="lg" />
+ </gl-intersection-observer>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js b/app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js
new file mode 100644
index 00000000000..53f755fda37
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js
@@ -0,0 +1,237 @@
+import Visibility from 'visibilityjs';
+import { createAlert } from '~/alert';
+import eventHub from '~/ci/event_hub';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { historyPushState, buildUrlWithCurrentLocation } from '~/lib/utils/common_utils';
+import { HTTP_STATUS_UNAUTHORIZED } from '~/lib/utils/http_status';
+import Poll from '~/lib/utils/poll';
+import { __ } from '~/locale';
+import { validateParams } from '~/ci/pipeline_details/utils';
+import { CANCEL_REQUEST, TOAST_MESSAGE } from '../constants';
+
+export default {
+ data() {
+ return {
+ isLoading: false,
+ hasError: false,
+ isMakingRequest: false,
+ updateGraphDropdown: false,
+ hasMadeRequest: false,
+ };
+ },
+ computed: {
+ shouldRenderPagination() {
+ return !this.isLoading;
+ },
+ },
+ beforeMount() {
+ this.poll = new Poll({
+ resource: this.service,
+ method: 'getPipelines',
+ data: this.requestData ? this.requestData : undefined,
+ successCallback: this.successCallback,
+ errorCallback: this.errorCallback,
+ notificationCallback: this.setIsMakingRequest,
+ });
+
+ if (!Visibility.hidden()) {
+ this.isLoading = true;
+ this.poll.makeRequest();
+ } else {
+ // If tab is not visible we need to make the first request so we don't show the empty
+ // state without knowing if there are any pipelines
+ this.fetchPipelines();
+ }
+
+ Visibility.change(() => {
+ if (!Visibility.hidden()) {
+ this.poll.restart();
+ } else {
+ this.poll.stop();
+ }
+ });
+
+ eventHub.$on('postAction', this.postAction);
+ eventHub.$on('retryPipeline', this.postAction);
+ eventHub.$on('clickedDropdown', this.updateTable);
+ eventHub.$on('updateTable', this.updateTable);
+ eventHub.$on('runMergeRequestPipeline', this.runMergeRequestPipeline);
+ },
+ beforeDestroy() {
+ eventHub.$off('postAction', this.postAction);
+ eventHub.$off('retryPipeline', this.postAction);
+ eventHub.$off('clickedDropdown', this.updateTable);
+ eventHub.$off('updateTable', this.updateTable);
+ eventHub.$off('runMergeRequestPipeline', this.runMergeRequestPipeline);
+ },
+ destroyed() {
+ this.poll.stop();
+ },
+ methods: {
+ updateInternalState(parameters) {
+ this.poll.stop();
+
+ const queryString = Object.keys(parameters)
+ .map((parameter) => {
+ const value = parameters[parameter];
+ // update internal state for UI
+ this[parameter] = value;
+ return `${parameter}=${encodeURIComponent(value)}`;
+ })
+ .join('&');
+
+ // update polling parameters
+ this.requestData = parameters;
+
+ historyPushState(buildUrlWithCurrentLocation(`?${queryString}`));
+
+ this.isLoading = true;
+ },
+ /**
+ * Handles URL and query parameter changes.
+ * When the user uses the pagination or the tabs,
+ * - update URL
+ * - Make API request to the server with new parameters
+ * - Update the polling function
+ * - Update the internal state
+ */
+ updateContent(parameters) {
+ this.updateInternalState(parameters);
+
+ // fetch new data
+ return this.service
+ .getPipelines(this.requestData)
+ .then((response) => {
+ this.isLoading = false;
+ this.successCallback(response);
+
+ this.poll.enable({ data: this.requestData, response });
+ })
+ .catch(() => {
+ this.isLoading = false;
+ this.errorCallback();
+
+ // restart polling
+ this.poll.restart({ data: this.requestData });
+ });
+ },
+ updateTable() {
+ // Cancel ongoing request
+ if (this.isMakingRequest) {
+ this.service.cancelationSource.cancel(CANCEL_REQUEST);
+ }
+ // Stop polling
+ this.poll.stop();
+ // Restarting the poll also makes an initial request
+ return this.poll.restart();
+ },
+ fetchPipelines() {
+ if (!this.isMakingRequest) {
+ this.isLoading = true;
+
+ this.getPipelines();
+ }
+ },
+ getPipelines() {
+ return this.service
+ .getPipelines(this.requestData)
+ .then((response) => this.successCallback(response))
+ .catch((error) => this.errorCallback(error));
+ },
+ setCommonData(pipelines) {
+ this.store.storePipelines(pipelines);
+ this.isLoading = false;
+ this.updateGraphDropdown = true;
+ this.hasMadeRequest = true;
+
+ // In case the previous polling request returned an error, we need to reset it
+ if (this.hasError) {
+ this.hasError = false;
+ }
+ },
+ errorCallback(error) {
+ this.hasMadeRequest = true;
+ this.isLoading = false;
+
+ if (error && error.message && error.message !== CANCEL_REQUEST) {
+ this.hasError = true;
+ this.updateGraphDropdown = false;
+ }
+ },
+ setIsMakingRequest(isMakingRequest) {
+ this.isMakingRequest = isMakingRequest;
+
+ if (isMakingRequest) {
+ this.updateGraphDropdown = false;
+ }
+ },
+ postAction(endpoint) {
+ this.service
+ .postAction(endpoint)
+ .then(() => this.updateTable())
+ .catch(() =>
+ createAlert({
+ message: __('An error occurred while making the request.'),
+ }),
+ );
+ },
+
+ /**
+ * When the user clicks on the run pipeline button
+ * we toggle the state of the button to be disabled
+ *
+ * Once the post request has finished, we fetch the
+ * pipelines again to show the most recent data
+ *
+ * Once the pipeline has been updated, we toggle back the
+ * loading state and re-enable the run pipeline button
+ */
+ runMergeRequestPipeline(options) {
+ this.store.toggleIsRunningPipeline(true);
+
+ this.service
+ .runMRPipeline(options)
+ .then(() => {
+ this.$toast.show(TOAST_MESSAGE);
+ this.updateTable();
+ })
+ .catch((e) => {
+ const unauthorized = e.response.status === HTTP_STATUS_UNAUTHORIZED;
+ let errorMessage = __(
+ 'An error occurred while trying to run a new pipeline for this merge request.',
+ );
+
+ if (unauthorized) {
+ errorMessage = __('You do not have permission to run a pipeline on this branch.');
+ }
+
+ createAlert({
+ message: errorMessage,
+ primaryButton: {
+ text: __('Learn more'),
+ link: helpPagePath('ci/pipelines/merge_request_pipelines.md'),
+ },
+ });
+ })
+ .finally(() => this.store.toggleIsRunningPipeline(false));
+ },
+ onChangePage(page) {
+ /* URLS parameters are strings, we need to parse to match types */
+ let params = {
+ page: Number(page).toString(),
+ };
+
+ if (this.scope) {
+ params.scope = this.scope;
+ }
+
+ params = this.onChangeWithFilter(params);
+
+ this.updateContent(params);
+ },
+
+ onChangeWithFilter(params) {
+ return { ...params, ...validateParams(this.requestData) };
+ },
+ },
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/pipeline_details_bundle.js b/app/assets/javascripts/ci/pipeline_details/pipeline_details_bundle.js
new file mode 100644
index 00000000000..da09852a7f4
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/pipeline_details_bundle.js
@@ -0,0 +1,67 @@
+import VueRouter from 'vue-router';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { pipelineTabName } from './constants';
+import { createPipelineDetailsHeaderApp } from './pipeline_details_header';
+import { apolloProvider } from './pipeline_shared_client';
+
+const SELECTORS = {
+ PIPELINE_DETAILS_HEADER: '#js-pipeline-details-header-vue',
+ PIPELINE_TABS: '#js-pipeline-tabs',
+};
+
+export default async function initPipelineDetailsBundle() {
+ const headerSelector = SELECTORS.PIPELINE_DETAILS_HEADER;
+
+ const headerApp = createPipelineDetailsHeaderApp;
+
+ const headerEl = document.querySelector(headerSelector);
+
+ if (headerEl) {
+ const { dataset: headerDataset } = headerEl;
+
+ try {
+ headerApp(headerSelector, apolloProvider, headerDataset.graphqlResourceEtag);
+ } catch {
+ createAlert({
+ message: __('An error occurred while loading a section of this page.'),
+ });
+ }
+ }
+
+ const tabsEl = document.querySelector(SELECTORS.PIPELINE_TABS);
+
+ if (tabsEl) {
+ const { dataset } = tabsEl;
+ const dismissalDescriptions = JSON.parse(dataset.dismissalDescriptions || '{}');
+ const { createAppOptions } = await import('ee_else_ce/ci/pipeline_details/pipeline_tabs');
+ const { createPipelineTabs } = await import('./pipeline_tabs');
+ const { routes } = await import('ee_else_ce/ci/pipeline_details/routes');
+
+ const securityRoute = routes.find((route) => route.path === '/security');
+ if (securityRoute) {
+ securityRoute.props = { dismissalDescriptions };
+ }
+
+ const router = new VueRouter({
+ mode: 'history',
+ base: dataset.pipelinePath,
+ routes,
+ });
+
+ // We handle the shortcut `pipelines/latest` by forwarding the user to the pipeline graph
+ // tab and changing the route to the correct `pipelines/:id`
+ if (window.location.pathname.endsWith('latest')) {
+ router.replace({ name: pipelineTabName });
+ }
+
+ try {
+ const appOptions = createAppOptions(SELECTORS.PIPELINE_TABS, apolloProvider, router);
+ createPipelineTabs(appOptions);
+ } catch {
+ createAlert({
+ message: __('An error occurred while loading a section of this page.'),
+ });
+ }
+ }
+}
diff --git a/app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js b/app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js
new file mode 100644
index 00000000000..067ec3f305e
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/pipeline_details_header.js
@@ -0,0 +1,75 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import PipelineDetailsHeader from './header/pipeline_details_header.vue';
+
+Vue.use(VueApollo);
+
+export const createPipelineDetailsHeaderApp = (elSelector, apolloProvider, graphqlResourceEtag) => {
+ const el = document.querySelector(elSelector);
+
+ if (!el) {
+ return;
+ }
+
+ const {
+ fullPath,
+ pipelineIid,
+ pipelinesPath,
+ name,
+ totalJobs,
+ computeMinutes,
+ yamlErrors,
+ failureReason,
+ triggeredByPath,
+ schedule,
+ child,
+ latest,
+ mergeTrainPipeline,
+ invalid,
+ failed,
+ autoDevops,
+ detached,
+ stuck,
+ refText,
+ } = el.dataset;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ name: 'PipelineDetailsHeaderApp',
+ apolloProvider,
+ provide: {
+ paths: {
+ fullProject: fullPath,
+ graphqlResourceEtag,
+ pipelinesPath,
+ triggeredByPath,
+ },
+ pipelineIid,
+ },
+ render(createElement) {
+ return createElement(PipelineDetailsHeader, {
+ props: {
+ name,
+ totalJobs,
+ computeMinutes,
+ yamlErrors,
+ failureReason,
+ refText,
+ badges: {
+ schedule: parseBoolean(schedule),
+ child: parseBoolean(child),
+ latest: parseBoolean(latest),
+ mergeTrainPipeline: parseBoolean(mergeTrainPipeline),
+ invalid: parseBoolean(invalid),
+ failed: parseBoolean(failed),
+ autoDevops: parseBoolean(autoDevops),
+ detached: parseBoolean(detached),
+ stuck: parseBoolean(stuck),
+ },
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/pipelines/pipeline_shared_client.js b/app/assets/javascripts/ci/pipeline_details/pipeline_shared_client.js
index c3be487caae..c3be487caae 100644
--- a/app/assets/javascripts/pipelines/pipeline_shared_client.js
+++ b/app/assets/javascripts/ci/pipeline_details/pipeline_shared_client.js
diff --git a/app/assets/javascripts/ci/pipeline_details/pipeline_tabs.js b/app/assets/javascripts/ci/pipeline_details/pipeline_tabs.js
new file mode 100644
index 00000000000..0ca9a68e70d
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/pipeline_tabs.js
@@ -0,0 +1,116 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import VueApollo from 'vue-apollo';
+import { GlToast } from '@gitlab/ui';
+import PipelineTabs from 'ee_else_ce/ci/pipeline_details/tabs/pipeline_tabs.vue';
+import { reportToSentry } from '~/ci/utils';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import createTestReportsStore from './stores/test_reports';
+import { getPipelineDefaultTab } from './utils';
+
+Vue.use(GlToast);
+Vue.use(VueApollo);
+Vue.use(VueRouter);
+Vue.use(Vuex);
+
+export const createAppOptions = (selector, apolloProvider, router) => {
+ const el = document.querySelector(selector);
+
+ if (!el) return null;
+
+ const { dataset } = el;
+ const {
+ canGenerateCodequalityReports,
+ codequalityReportDownloadPath,
+ codequalityBlobPath,
+ codequalityProjectPath,
+ downloadablePathForReportType,
+ exposeSecurityDashboard,
+ exposeLicenseScanningData,
+ failedJobsCount,
+ projectPath,
+ graphqlResourceEtag,
+ pipelineIid,
+ pipelineProjectPath,
+ totalJobCount,
+ licenseManagementApiUrl,
+ licenseScanCount,
+ licensesApiPath,
+ canManageLicenses,
+ summaryEndpoint,
+ suiteEndpoint,
+ blobPath,
+ hasTestReport,
+ emptyDagSvgPath,
+ emptyStateImagePath,
+ artifactsExpiredImagePath,
+ isFullCodequalityReportAvailable,
+ securityPoliciesPath,
+ testsCount,
+ } = dataset;
+
+ const defaultTabValue = getPipelineDefaultTab(window.location.href);
+
+ return {
+ el,
+ components: {
+ PipelineTabs,
+ },
+ apolloProvider,
+ store: new Vuex.Store({
+ modules: {
+ testReports: createTestReportsStore({
+ blobPath,
+ summaryEndpoint,
+ suiteEndpoint,
+ }),
+ },
+ }),
+ router,
+ provide: {
+ canGenerateCodequalityReports: parseBoolean(canGenerateCodequalityReports),
+ codequalityReportDownloadPath,
+ codequalityBlobPath,
+ codequalityProjectPath,
+ isFullCodequalityReportAvailable: parseBoolean(isFullCodequalityReportAvailable),
+ projectPath,
+ defaultTabValue,
+ downloadablePathForReportType,
+ exposeSecurityDashboard: parseBoolean(exposeSecurityDashboard),
+ exposeLicenseScanningData: parseBoolean(exposeLicenseScanningData),
+ failedJobsCount,
+ graphqlResourceEtag,
+ pipelineIid,
+ pipelineProjectPath,
+ totalJobCount,
+ licenseManagementApiUrl,
+ licenseScanCount,
+ licensesApiPath,
+ canManageLicenses: parseBoolean(canManageLicenses),
+ summaryEndpoint,
+ suiteEndpoint,
+ blobPath,
+ hasTestReport,
+ emptyDagSvgPath,
+ emptyStateImagePath,
+ artifactsExpiredImagePath,
+ securityPoliciesPath,
+ testsCount,
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry('pipeline_tabs', `error: ${err}, info: ${info}`);
+ },
+ render(createElement) {
+ return createElement(PipelineTabs);
+ },
+ };
+};
+
+export const createPipelineTabs = (options) => {
+ if (!options) return;
+
+ // eslint-disable-next-line no-new
+ new Vue(options);
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/pipelines_index.js b/app/assets/javascripts/ci/pipeline_details/pipelines_index.js
new file mode 100644
index 00000000000..d38397e7479
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/pipelines_index.js
@@ -0,0 +1,100 @@
+import { GlToast } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import {
+ parseBoolean,
+ historyReplaceState,
+ buildUrlWithCurrentLocation,
+} from '~/lib/utils/common_utils';
+import { doesHashExistInUrl } from '~/lib/utils/url_utility';
+import { __ } from '~/locale';
+import Translate from '~/vue_shared/translate';
+import Pipelines from '~/ci/pipelines_page/pipelines.vue';
+import PipelinesStore from './stores/pipelines_store';
+
+Vue.use(Translate);
+Vue.use(GlToast);
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+export const initPipelinesIndex = (selector = '#pipelines-list-vue') => {
+ const el = document.querySelector(selector);
+ if (!el) {
+ return null;
+ }
+
+ const {
+ endpoint,
+ artifactsEndpoint,
+ artifactsEndpointPlaceholder,
+ pipelineScheduleUrl,
+ emptyStateSvgPath,
+ errorStateSvgPath,
+ noPipelinesSvgPath,
+ newPipelinePath,
+ pipelineEditorPath,
+ suggestedCiTemplates,
+ canCreatePipeline,
+ hasGitlabCi,
+ ciLintPath,
+ resetCachePath,
+ projectId,
+ defaultBranchName,
+ params,
+ iosRunnersAvailable,
+ registrationToken,
+ fullPath,
+ visibilityPipelineIdType,
+ } = el.dataset;
+
+ return new Vue({
+ el,
+ apolloProvider,
+ provide: {
+ pipelineEditorPath,
+ artifactsEndpoint,
+ artifactsEndpointPlaceholder,
+ suggestedCiTemplates: JSON.parse(suggestedCiTemplates),
+ iosRunnersAvailable: parseBoolean(iosRunnersAvailable),
+ fullPath,
+ manualActionsLimit: 50,
+ },
+ data() {
+ return {
+ store: new PipelinesStore(),
+ };
+ },
+ created() {
+ if (doesHashExistInUrl('delete_success')) {
+ this.$toast.show(__('The pipeline has been deleted'));
+ historyReplaceState(buildUrlWithCurrentLocation());
+ }
+ },
+ render(createElement) {
+ return createElement(Pipelines, {
+ props: {
+ store: this.store,
+ endpoint,
+ pipelineScheduleUrl,
+ emptyStateSvgPath,
+ errorStateSvgPath,
+ noPipelinesSvgPath,
+ newPipelinePath,
+ canCreatePipeline: parseBoolean(canCreatePipeline),
+ hasGitlabCi: parseBoolean(hasGitlabCi),
+ ciLintPath,
+ resetCachePath,
+ projectId,
+ defaultBranchName,
+ params: JSON.parse(params),
+ registrationToken,
+ defaultVisibilityPipelineIdType: visibilityPipelineIdType,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/routes.js b/app/assets/javascripts/ci/pipeline_details/routes.js
new file mode 100644
index 00000000000..84207f3ab0c
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/routes.js
@@ -0,0 +1,20 @@
+import PipelineGraphWrapper from './graph/graph_component_wrapper.vue';
+import Dag from './dag/dag.vue';
+import FailedJobsApp from './jobs/failed_jobs_app.vue';
+import JobsApp from './jobs/jobs_app.vue';
+import TestReports from './test_reports/test_reports.vue';
+import {
+ pipelineTabName,
+ needsTabName,
+ jobsTabName,
+ failedJobsTabName,
+ testReportTabName,
+} from './constants';
+
+export const routes = [
+ { name: pipelineTabName, path: '/', component: PipelineGraphWrapper },
+ { name: needsTabName, path: '/dag', component: Dag },
+ { name: jobsTabName, path: '/builds', component: JobsApp },
+ { name: failedJobsTabName, path: '/failures', component: FailedJobsApp },
+ { name: testReportTabName, path: '/test_report', component: TestReports },
+];
diff --git a/app/assets/javascripts/pipelines/stores/pipelines_store.js b/app/assets/javascripts/ci/pipeline_details/stores/pipelines_store.js
index 765441560d8..765441560d8 100644
--- a/app/assets/javascripts/pipelines/stores/pipelines_store.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/pipelines_store.js
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/actions.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/actions.js
index 1b51bb804d0..1b51bb804d0 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/actions.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/actions.js
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/constants.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/constants.js
index 83d14e1a109..83d14e1a109 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/constants.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/constants.js
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/getters.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/getters.js
index e6a88bb4175..e6a88bb4175 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/getters.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/getters.js
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/index.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/index.js
index f45a53f47b7..f45a53f47b7 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/index.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/index.js
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/mutation_types.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/mutation_types.js
index 7651a2f4327..7651a2f4327 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/mutation_types.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/mutation_types.js
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/mutations.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/mutations.js
index 466574157f5..466574157f5 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/mutations.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/mutations.js
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/state.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/state.js
index 3ec9418c14e..3ec9418c14e 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/state.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/state.js
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/utils.js b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/utils.js
index 6b616601bc5..6b616601bc5 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/utils.js
+++ b/app/assets/javascripts/ci/pipeline_details/stores/test_reports/utils.js
diff --git a/app/assets/javascripts/ci/pipeline_details/tabs/pipeline_tabs.vue b/app/assets/javascripts/ci/pipeline_details/tabs/pipeline_tabs.vue
new file mode 100644
index 00000000000..9783a9b5937
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/tabs/pipeline_tabs.vue
@@ -0,0 +1,138 @@
+<script>
+import { GlBadge, GlTabs, GlTab } from '@gitlab/ui';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+import { __ } from '~/locale';
+import Tracking from '~/tracking';
+import {
+ failedJobsTabName,
+ jobsTabName,
+ needsTabName,
+ pipelineTabName,
+ testReportTabName,
+} from '../constants';
+
+export default {
+ i18n: {
+ tabs: {
+ failedJobsTitle: __('Failed Jobs'),
+ jobsTitle: __('Jobs'),
+ needsTitle: __('Needs'),
+ pipelineTitle: __('Pipeline'),
+ testsTitle: __('Tests'),
+ },
+ },
+ tabNames: {
+ pipeline: pipelineTabName,
+ needs: needsTabName,
+ jobs: jobsTabName,
+ failures: failedJobsTabName,
+ tests: testReportTabName,
+ },
+ components: {
+ GlBadge,
+ GlTab,
+ GlTabs,
+ },
+ mixins: [Tracking.mixin()],
+ inject: ['defaultTabValue', 'failedJobsCount', 'totalJobCount', 'testsCount'],
+ data() {
+ return {
+ activeTab: this.defaultTabValue,
+ };
+ },
+ computed: {
+ showFailedJobsTab() {
+ return this.failedJobsCount > 0;
+ },
+ },
+ watch: {
+ $route(to) {
+ this.activeTab = to.name;
+ },
+ },
+ methods: {
+ isActive(tabName) {
+ return tabName === this.activeTab;
+ },
+ navigateTo(tabName) {
+ if (this.isActive(tabName)) return;
+
+ this.$router.push({ name: tabName });
+ },
+ failedJobsTabClick() {
+ this.track('click_tab', { label: TRACKING_CATEGORIES.failed });
+
+ this.navigateTo(this.$options.tabNames.failures);
+ },
+ testsTabClick() {
+ this.track('click_tab', { label: TRACKING_CATEGORIES.tests });
+
+ this.navigateTo(this.$options.tabNames.tests);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-tabs>
+ <gl-tab
+ ref="pipelineTab"
+ :title="$options.i18n.tabs.pipelineTitle"
+ :active="isActive($options.tabNames.pipeline)"
+ data-testid="pipeline-tab"
+ lazy
+ @click="navigateTo($options.tabNames.pipeline)"
+ >
+ <router-view />
+ </gl-tab>
+ <gl-tab
+ ref="dagTab"
+ :title="$options.i18n.tabs.needsTitle"
+ :active="isActive($options.tabNames.needs)"
+ data-testid="dag-tab"
+ lazy
+ @click="navigateTo($options.tabNames.needs)"
+ >
+ <router-view />
+ </gl-tab>
+ <gl-tab
+ :active="isActive($options.tabNames.jobs)"
+ data-testid="jobs-tab"
+ lazy
+ @click="navigateTo($options.tabNames.jobs)"
+ >
+ <template #title>
+ <span class="gl-mr-2">{{ $options.i18n.tabs.jobsTitle }}</span>
+ <gl-badge size="sm" data-testid="builds-counter">{{ totalJobCount }}</gl-badge>
+ </template>
+ <router-view />
+ </gl-tab>
+ <gl-tab
+ v-if="showFailedJobsTab"
+ :title="$options.i18n.tabs.failedJobsTitle"
+ :active="isActive($options.tabNames.failures)"
+ data-testid="failed-jobs-tab"
+ lazy
+ @click="failedJobsTabClick"
+ >
+ <template #title>
+ <span class="gl-mr-2">{{ $options.i18n.tabs.failedJobsTitle }}</span>
+ <gl-badge size="sm" data-testid="failed-builds-counter">{{ failedJobsCount }}</gl-badge>
+ </template>
+ <router-view />
+ </gl-tab>
+ <gl-tab
+ :active="isActive($options.tabNames.tests)"
+ data-testid="tests-tab"
+ lazy
+ @click="testsTabClick"
+ >
+ <template #title>
+ <span class="gl-mr-2">{{ $options.i18n.tabs.testsTitle }}</span>
+ <gl-badge size="sm" data-testid="tests-counter">{{ testsCount }}</gl-badge>
+ </template>
+ <router-view />
+ </gl-tab>
+ <slot></slot>
+ </gl-tabs>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/test_reports/empty_state.vue b/app/assets/javascripts/ci/pipeline_details/test_reports/empty_state.vue
new file mode 100644
index 00000000000..055b6742ae1
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/test_reports/empty_state.vue
@@ -0,0 +1,61 @@
+<script>
+import { GlEmptyState } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { s__ } from '~/locale';
+
+export const i18n = {
+ noTestsButton: s__('TestReports|Learn more about pipeline test reports'),
+ noTestsDescription: s__('TestReports|No test cases were found in the test report.'),
+ noTestsTitle: s__('TestReports|There are no tests to display'),
+ noReportsButton: s__('TestReports|Learn how to upload pipeline test reports'),
+ noReportsDescription: s__(
+ 'TestReports|You can configure your job to use unit test reports, and GitLab displays a report here and in the related merge request.',
+ ),
+ noReportsTitle: s__('TestReports|There are no test reports for this pipeline'),
+};
+
+export default {
+ i18n,
+ components: {
+ GlEmptyState,
+ },
+ inject: {
+ emptyStateImagePath: {
+ default: '',
+ },
+ hasTestReport: {
+ default: false,
+ },
+ },
+ computed: {
+ emptyStateText() {
+ if (this.hasTestReport) {
+ return {
+ button: this.$options.i18n.noTestsButton,
+ description: this.$options.i18n.noTestsDescription,
+ title: this.$options.i18n.noTestsTitle,
+ };
+ }
+ return {
+ button: this.$options.i18n.noReportsButton,
+ description: this.$options.i18n.noReportsDescription,
+ title: this.$options.i18n.noReportsTitle,
+ };
+ },
+ testReportDocPath() {
+ return helpPagePath('ci/testing/unit_test_reports');
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-empty-state
+ :title="emptyStateText.title"
+ :description="emptyStateText.description"
+ :svg-path="emptyStateImagePath"
+ :svg-height="150"
+ :primary-button-link="testReportDocPath"
+ :primary-button-text="emptyStateText.button"
+ />
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/test_reports/test_case_details.vue b/app/assets/javascripts/ci/pipeline_details/test_reports/test_case_details.vue
new file mode 100644
index 00000000000..3e6faa6b346
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/test_reports/test_case_details.vue
@@ -0,0 +1,152 @@
+<script>
+import { GlBadge, GlFriendlyWrap, GlLink, GlModal, GlTooltipDirective } from '@gitlab/ui';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
+import { __, n__, s__, sprintf } from '~/locale';
+import CodeBlock from '~/vue_shared/components/code_block.vue';
+
+export default {
+ name: 'TestCaseDetails',
+ components: {
+ CodeBlock,
+ GlBadge,
+ GlFriendlyWrap,
+ GlLink,
+ GlModal,
+ ModalCopyButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ modalId: {
+ type: String,
+ required: true,
+ },
+ testCase: {
+ type: Object,
+ required: false,
+ default: () => {
+ return {};
+ },
+ },
+ visible: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ failureHistoryMessage() {
+ if (!this.hasRecentFailures) {
+ return null;
+ }
+
+ return sprintf(
+ n__(
+ 'Reports|Failed %{count} time in %{baseBranch} in the last 14 days',
+ 'Reports|Failed %{count} times in %{baseBranch} in the last 14 days',
+ this.recentFailures.count,
+ ),
+ {
+ count: this.recentFailures.count,
+ baseBranch: this.recentFailures.base_branch,
+ },
+ );
+ },
+ hasRecentFailures() {
+ return Boolean(this.recentFailures);
+ },
+ recentFailures() {
+ return this.testCase.recent_failures;
+ },
+ },
+ text: {
+ name: __('Name'),
+ file: __('File'),
+ duration: __('Execution time'),
+ history: __('History'),
+ trace: __('System output'),
+ attachment: s__('TestReports|Attachment'),
+ copyTestName: s__('TestReports|Copy test name to rerun locally'),
+ },
+ modalCloseButton: {
+ text: __('Close'),
+ attributes: { variant: 'confirm' },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ data-testid="test-case-details-modal"
+ :modal-id="modalId"
+ :title="testCase.classname"
+ :action-primary="$options.modalCloseButton"
+ :visible="visible"
+ @hidden="$emit('hidden')"
+ >
+ <div class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
+ <strong class="gl-text-right col-sm-3">{{ $options.text.name }}</strong>
+ <div class="col-sm-9" data-testid="test-case-name">
+ {{ testCase.name }}
+ </div>
+ </div>
+
+ <div v-if="testCase.file" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
+ <strong class="gl-text-right col-sm-3">{{ $options.text.file }}</strong>
+ <div class="col-sm-9" data-testid="test-case-file">
+ <gl-link v-if="testCase.filePath" :href="testCase.filePath">
+ {{ testCase.file }}
+ </gl-link>
+ <span v-else>{{ testCase.file }}</span>
+ <modal-copy-button
+ :title="$options.text.copyTestName"
+ :text="testCase.file"
+ :modal-id="modalId"
+ category="tertiary"
+ class="gl-ml-1"
+ />
+ </div>
+ </div>
+
+ <div class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
+ <strong class="gl-text-right col-sm-3">{{ $options.text.duration }}</strong>
+ <div v-if="testCase.formattedTime" class="col-sm-9" data-testid="test-case-duration">
+ {{ testCase.formattedTime }}
+ </div>
+ <div v-else-if="testCase.execution_time" class="col-sm-9" data-testid="test-case-duration">
+ {{ sprintf('%{value} s', { value: testCase.execution_time }) }}
+ </div>
+ </div>
+
+ <div v-if="testCase.recent_failures" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
+ <strong class="gl-text-right col-sm-3">{{ $options.text.history }}</strong>
+ <div class="col-sm-9" data-testid="test-case-recent-failures">
+ <gl-badge variant="warning">{{ failureHistoryMessage }}</gl-badge>
+ </div>
+ </div>
+
+ <div v-if="testCase.attachment_url" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
+ <strong class="gl-text-right col-sm-3">{{ $options.text.attachment }}</strong>
+ <gl-link
+ class="col-sm-9"
+ :href="testCase.attachment_url"
+ target="_blank"
+ data-testid="test-case-attachment-url"
+ >
+ <gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.attachment_url" />
+ </gl-link>
+ </div>
+
+ <div
+ v-if="testCase.system_output"
+ class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3"
+ data-testid="test-case-trace"
+ >
+ <strong class="gl-text-right col-sm-3">{{ $options.text.trace }}</strong>
+ <div class="col-sm-9">
+ <code-block :code="testCase.system_output" />
+ </div>
+ </div>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue b/app/assets/javascripts/ci/pipeline_details/test_reports/test_reports.vue
index a7737d33285..a7737d33285 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_reports.vue
+++ b/app/assets/javascripts/ci/pipeline_details/test_reports/test_reports.vue
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue b/app/assets/javascripts/ci/pipeline_details/test_reports/test_suite_table.vue
index d8af926a796..d8af926a796 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue
+++ b/app/assets/javascripts/ci/pipeline_details/test_reports/test_suite_table.vue
diff --git a/app/assets/javascripts/ci/pipeline_details/test_reports/test_summary.vue b/app/assets/javascripts/ci/pipeline_details/test_reports/test_summary.vue
new file mode 100644
index 00000000000..f6090678ca4
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/test_reports/test_summary.vue
@@ -0,0 +1,117 @@
+<script>
+import { GlButton, GlProgressBar } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { formattedTime } from '../stores/test_reports/utils';
+
+export default {
+ name: 'TestSummary',
+ components: {
+ GlButton,
+ GlProgressBar,
+ },
+ props: {
+ report: {
+ type: Object,
+ required: true,
+ },
+ showBack: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ heading() {
+ return this.report.name || __('Summary');
+ },
+ successPercentage() {
+ // Returns a full number when the decimals equal .00.
+ // Otherwise returns a float to two decimal points
+ // Do not include skipped tests as part of the total when doing success calculations.
+
+ const totalCompletedCount = this.report.total_count - this.report.skipped_count;
+
+ if (totalCompletedCount > 0) {
+ return Number(((this.report.success_count / totalCompletedCount) * 100 || 0).toFixed(2));
+ }
+ return 0;
+ },
+ formattedDuration() {
+ return formattedTime(this.report.total_time);
+ },
+ progressBarVariant() {
+ if (this.successPercentage < 33) {
+ return 'danger';
+ }
+
+ if (this.successPercentage >= 33 && this.successPercentage < 66) {
+ return 'warning';
+ }
+
+ if (this.successPercentage >= 66 && this.successPercentage < 90) {
+ return 'primary';
+ }
+
+ return 'success';
+ },
+ },
+ methods: {
+ onBackClick() {
+ this.$emit('on-back-click');
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div class="gl-w-full gl-display-flex gl-mt-3 gl-align-items-center">
+ <gl-button
+ v-if="showBack"
+ size="small"
+ class="gl-mr-3 js-back-button"
+ icon="chevron-lg-left"
+ :aria-label="__('Go back')"
+ @click="onBackClick"
+ />
+
+ <h4>{{ heading }}</h4>
+ </div>
+
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-w-full gl-mt-3"
+ >
+ <div class="gl-display-flex gl-justify-content-space-between gl-flex-basis-half">
+ <span class="js-total-tests gl-flex-grow-1">{{
+ sprintf(s__('TestReports|%{count} tests'), { count: report.total_count })
+ }}</span>
+
+ <span class="js-failed-tests gl-flex-grow-1">{{
+ sprintf(s__('TestReports|%{count} failures'), { count: report.failed_count })
+ }}</span>
+
+ <span class="js-errored-tests">{{
+ sprintf(s__('TestReports|%{count} errors'), { count: report.error_count })
+ }}</span>
+ </div>
+ <div class="gl-display-flex gl-justify-content-space-between gl-flex-grow-1">
+ <div class="gl-display-none gl-md-display-block gl-flex-grow-1"></div>
+ <span class="js-success-rate gl-flex-grow-1">{{
+ sprintf(s__('TestReports|%{rate}%{sign} success rate'), {
+ rate: successPercentage,
+ sign: '%',
+ })
+ }}</span>
+
+ <span class="js-duration">{{ formattedDuration }}</span>
+ </div>
+ </div>
+
+ <gl-progress-bar
+ class="gl-mt-5"
+ :value="successPercentage"
+ :variant="progressBarVariant"
+ height="10px"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue b/app/assets/javascripts/ci/pipeline_details/test_reports/test_summary_table.vue
index 9141947ea04..9141947ea04 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue
+++ b/app/assets/javascripts/ci/pipeline_details/test_reports/test_summary_table.vue
diff --git a/app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js b/app/assets/javascripts/ci/pipeline_details/utils/drawing_utils.js
index d6d9ea94c13..d6d9ea94c13 100644
--- a/app/assets/javascripts/pipelines/components/graph_shared/drawing_utils.js
+++ b/app/assets/javascripts/ci/pipeline_details/utils/drawing_utils.js
diff --git a/app/assets/javascripts/ci/pipeline_details/utils/index.js b/app/assets/javascripts/ci/pipeline_details/utils/index.js
new file mode 100644
index 00000000000..9109342707e
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/utils/index.js
@@ -0,0 +1,147 @@
+import { pickBy } from 'lodash';
+import { parseUrlPathname } from '~/lib/utils/url_utility';
+import {
+ NEEDS_PROPERTY,
+ SUPPORTED_FILTER_PARAMETERS,
+ validPipelineTabNames,
+ pipelineTabName,
+} from '../constants';
+/*
+ The following functions are the main engine in transforming the data as
+ received from the endpoint into the format the d3 graph expects.
+
+ Input is of the form:
+ [nodes]
+ nodes: [{category, name, jobs, size}]
+ category is the stage name
+ name is a group name; in the case that the group has one job, it is
+ also the job name
+ size is the number of parallel jobs
+ jobs: [{ name, needs}]
+ job name is either the same as the group name or group x/y
+ needs: [job-names]
+ needs is an array of job-name strings
+
+ Output is of the form:
+ { nodes: [node], links: [link] }
+ node: { name, category }, + unused info passed through
+ link: { source, target, value }, with source & target being node names
+ and value being a constant
+
+ We create nodes in the GraphQL update function, and then here we create the node dictionary,
+ then create links, and then dedupe the links, so that in the case where
+ job 4 depends on job 1 and job 2, and job 2 depends on job 1, we show only a single link
+ from job 1 to job 2 then another from job 2 to job 4.
+
+ CREATE LINKS
+ nodes.name -> target
+ nodes.name.needs.each -> source (source is the name of the group, not the parallel job)
+ 10 -> value (constant)
+ */
+
+export const createNodeDict = (nodes, { needsKey = NEEDS_PROPERTY } = {}) => {
+ return nodes.reduce((acc, node) => {
+ const newNode = {
+ ...node,
+ needs: node.jobs.map((job) => job[needsKey] || []).flat(),
+ };
+
+ if (node.size > 1) {
+ node.jobs.forEach((job) => {
+ acc[job.name] = newNode;
+ });
+ }
+
+ acc[node.name] = newNode;
+ return acc;
+ }, {});
+};
+
+export const validateParams = (params) => {
+ return pickBy(params, (val, key) => SUPPORTED_FILTER_PARAMETERS.includes(key) && val);
+};
+
+/**
+ * This function takes the stages array and transform it
+ * into a hash where each key is a job name and the job data
+ * is associated to that key.
+ * @param {Array} stages
+ * @returns {Object} - Hash of jobs
+ */
+export const createJobsHash = (stages = []) => {
+ const nodes = stages.flatMap(({ groups }) => groups);
+ return createNodeDict(nodes);
+};
+
+/**
+ * This function takes the jobs hash generated by
+ * `createJobsHash` function and returns an easier
+ * structure to work with for needs relationship
+ * where the key is the job name and the value is an
+ * array of all the needs this job has recursively
+ * (includes the needs of the needs)
+ * @param {Object} jobs
+ * @returns {Object} - Hash of jobs and array of needs
+ */
+export const generateJobNeedsDict = (jobs = {}) => {
+ const arrOfJobNames = Object.keys(jobs);
+
+ return arrOfJobNames.reduce((acc, value) => {
+ const recursiveNeeds = (jobName) => {
+ if (!jobs[jobName]?.needs) {
+ return [];
+ }
+
+ return jobs[jobName].needs
+ .reduce((needsAcc, job) => {
+ // It's possible that a needs refer to an optional job
+ // that is not defined in which case we don't add that entry
+ if (!jobs[job]) {
+ return needsAcc;
+ }
+
+ // If we already have the needs of a job in the accumulator,
+ // then we use the memoized data instead of the recursive call
+ // to save some performance.
+ const newNeeds = acc[job] ?? recursiveNeeds(job);
+
+ // In case it's a parallel job (size > 1), the name of the group
+ // and the job will be different. This mean we also need to add the group name
+ // to the list of `needs` to ensure we can properly reference it.
+ const group = jobs[job];
+ if (group.size > 1) {
+ return [...needsAcc, job, group.name, newNeeds];
+ }
+
+ return [...needsAcc, job, newNeeds];
+ }, [])
+ .flat(Infinity);
+ };
+
+ // To ensure we don't have duplicates job relationship when 2 jobs
+ // needed by another both depends on the same jobs, we remove any
+ // duplicates from the array.
+ const uniqueValues = Array.from(new Set(recursiveNeeds(value)));
+
+ return { ...acc, [value]: uniqueValues };
+ }, {});
+};
+
+export const getPipelineDefaultTab = (url) => {
+ const strippedUrl = parseUrlPathname(url);
+ const regexp = /\w*$/;
+ const [tabName] = strippedUrl.match(regexp);
+
+ if (tabName && validPipelineTabNames.includes(tabName)) return tabName;
+ if (tabName === '') return pipelineTabName;
+
+ return null;
+};
+
+export const graphqlEtagPipelinePath = (graphqlPath, pipelineId) => {
+ return `${graphqlPath}pipelines/id/${pipelineId}`;
+};
+
+export const graphqlEtagMergeRequestPipelines = (graphqlPath, mergeRequestId) => {
+ return `${graphqlPath}merge_requests/id/${mergeRequestId}`;
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/utils/parsing_utils.js b/app/assets/javascripts/ci/pipeline_details/utils/parsing_utils.js
new file mode 100644
index 00000000000..0a2a6d16498
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/utils/parsing_utils.js
@@ -0,0 +1,182 @@
+import { memoize } from 'lodash';
+import { EXPLICIT_NEEDS_PROPERTY, NEEDS_PROPERTY } from '../constants';
+import { createSankey } from '../dag/utils/drawing_utils';
+import { createNodeDict } from './index';
+
+/*
+ A peformant alternative to lodash's isEqual. Because findIndex always finds
+ the first instance of a match, if the found index is not the first, we know
+ it is in fact a duplicate.
+*/
+const deduplicate = (item, itemIndex, arr) => {
+ const foundIdx = arr.findIndex((test) => {
+ return test.source === item.source && test.target === item.target;
+ });
+
+ return foundIdx === itemIndex;
+};
+
+export const makeLinksFromNodes = (nodes, nodeDict, { needsKey = NEEDS_PROPERTY } = {}) => {
+ const constantLinkValue = 10; // all links are the same weight
+ return nodes
+ .map(({ jobs, name: groupName }) =>
+ jobs.map((job) => {
+ const needs = job[needsKey] || [];
+
+ return needs.reduce((acc, needed) => {
+ // It's possible that we have an optional job, which
+ // is being needed by another job. In that scenario,
+ // the needed job doesn't exist, so we don't want to
+ // create link for it.
+ if (nodeDict[needed]?.name) {
+ acc.push({
+ source: nodeDict[needed].name,
+ target: groupName,
+ value: constantLinkValue,
+ });
+ }
+
+ return acc;
+ }, []);
+ }),
+ )
+ .flat(2);
+};
+
+export const getAllAncestors = (nodes, nodeDict) => {
+ const needs = nodes
+ .map((node) => {
+ return nodeDict[node]?.needs || '';
+ })
+ .flat()
+ .filter(Boolean)
+ .filter(deduplicate);
+
+ if (needs.length) {
+ return [...needs, ...getAllAncestors(needs, nodeDict)];
+ }
+
+ return [];
+};
+
+export const filterByAncestors = (links, nodeDict) =>
+ links.filter(({ target, source }) => {
+ /*
+
+ for every link, check out it's target
+ for every target, get the target node's needs
+ then drop the current link source from that list
+
+ call a function to get all ancestors, recursively
+ is the current link's source in the list of all parents?
+ then we drop this link
+
+ */
+ const targetNode = target;
+ const targetNodeNeeds = nodeDict[targetNode].needs;
+ const targetNodeNeedsMinusSource = targetNodeNeeds.filter((need) => need !== source);
+ const allAncestors = getAllAncestors(targetNodeNeedsMinusSource, nodeDict);
+ return !allAncestors.includes(source);
+ });
+
+export const parseData = (nodes, { needsKey = NEEDS_PROPERTY } = {}) => {
+ const nodeDict = createNodeDict(nodes, { needsKey });
+ const allLinks = makeLinksFromNodes(nodes, nodeDict, { needsKey });
+ const filteredLinks = allLinks.filter(deduplicate);
+ const links = filterByAncestors(filteredLinks, nodeDict);
+
+ return { nodes, links };
+};
+
+/*
+ The number of nodes in the most populous generation drives the height of the graph.
+*/
+
+export const getMaxNodes = (nodes) => {
+ const counts = nodes.reduce((acc, { layer }) => {
+ if (!acc[layer]) {
+ acc[layer] = 0;
+ }
+
+ acc[layer] += 1;
+
+ return acc;
+ }, []);
+
+ return Math.max(...counts);
+};
+
+/*
+ Because we cannot know if a node is part of a relationship until after we
+ generate the links with createSankey, this function is used after the first call
+ to find nodes that have no relations.
+*/
+
+export const removeOrphanNodes = (sankeyfiedNodes) => {
+ return sankeyfiedNodes.filter((node) => node.sourceLinks.length || node.targetLinks.length);
+};
+
+/*
+ This utility accepts unwrapped pipeline data in the format returned from
+ our standard pipeline GraphQL query and returns a list of names by layer
+ for the layer view. It can be combined with the stageLookup on the pipeline
+ to generate columns by layer.
+*/
+
+export const listByLayers = ({ stages }) => {
+ const arrayOfJobs = stages.flatMap(({ groups }) => groups);
+ const parsedData = parseData(arrayOfJobs);
+ const explicitParsedData = parseData(arrayOfJobs, { needsKey: EXPLICIT_NEEDS_PROPERTY });
+ const dataWithLayers = createSankey()(explicitParsedData);
+
+ const pipelineLayers = dataWithLayers.nodes.reduce((acc, { layer, name }) => {
+ /* sort groups by layer */
+
+ if (!acc[layer]) {
+ acc[layer] = [];
+ }
+
+ acc[layer].push(name);
+
+ return acc;
+ }, []);
+
+ return {
+ linksData: parsedData.links,
+ numGroups: arrayOfJobs.length,
+ pipelineLayers,
+ };
+};
+
+export const generateColumnsFromLayersListBare = ({ stages, stagesLookup }, pipelineLayers) => {
+ return pipelineLayers.map((layers, idx) => {
+ /*
+ Look up the groups in each layer,
+ then add each set of layer groups to a stage-like object.
+ */
+
+ const groups = layers.map((id) => {
+ const { stageIdx, groupIdx } = stagesLookup[id];
+ return stages[stageIdx]?.groups?.[groupIdx];
+ });
+
+ return {
+ name: '',
+ id: `layer-${idx}`,
+ status: { action: null },
+ groups: groups.filter(Boolean),
+ };
+ });
+};
+
+export const generateColumnsFromLayersListMemoized = memoize(generateColumnsFromLayersListBare);
+
+export const keepLatestDownstreamPipelines = (downstreamPipelines = []) => {
+ return downstreamPipelines.filter((pipeline) => {
+ if (pipeline.source_job) {
+ return !pipeline?.source_job?.retried || false;
+ }
+
+ return !pipeline?.sourceJob?.retried || false;
+ });
+};
diff --git a/app/assets/javascripts/ci/pipeline_details/utils/unwrapping_utils.js b/app/assets/javascripts/ci/pipeline_details/utils/unwrapping_utils.js
new file mode 100644
index 00000000000..7ac813bd527
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_details/utils/unwrapping_utils.js
@@ -0,0 +1,73 @@
+import { reportToSentry } from '~/ci/utils';
+import { EXPLICIT_NEEDS_PROPERTY, NEEDS_PROPERTY } from '../constants';
+
+const unwrapGroups = (stages) => {
+ return stages.map((stage, idx) => {
+ const {
+ groups: { nodes: groups },
+ } = stage;
+
+ /*
+ Being peformance conscious here means we don't want to spread and copy the
+ group value just to add one parameter.
+ */
+ /* eslint-disable no-param-reassign */
+ const groupsWithStageName = groups.map((group) => {
+ group.stageName = stage.name;
+ return group;
+ });
+ /* eslint-enable no-param-reassign */
+
+ return { node: { ...stage, groups: groupsWithStageName }, lookup: { stageIdx: idx } };
+ });
+};
+
+const unwrapNodesWithName = (jobArray, prop, field = 'name') => {
+ if (jobArray.length < 1) {
+ reportToSentry('unwrapping_utils', 'undefined_job_hunt, array empty from backend');
+ }
+
+ return jobArray.map((job) => {
+ if (job[prop]) {
+ return { ...job, [prop]: job[prop].nodes.map((item) => item[field] || '') };
+ }
+ return job;
+ });
+};
+
+const unwrapJobWithNeeds = (denodedJobArray) => {
+ const explicitNeedsUnwrapped = unwrapNodesWithName(denodedJobArray, EXPLICIT_NEEDS_PROPERTY);
+ return unwrapNodesWithName(explicitNeedsUnwrapped, NEEDS_PROPERTY);
+};
+
+const unwrapStagesWithNeedsAndLookup = (denodedStages) => {
+ const unwrappedNestedGroups = unwrapGroups(denodedStages);
+
+ const lookupMap = {};
+
+ const nodes = unwrappedNestedGroups.map(({ node, lookup }) => {
+ const { groups } = node;
+ const groupsWithJobs = groups.map((group, idx) => {
+ const jobs = unwrapJobWithNeeds(group.jobs.nodes);
+
+ lookupMap[group.name] = { ...lookup, groupIdx: idx };
+ return { ...group, jobs };
+ });
+
+ return { ...node, groups: groupsWithJobs };
+ });
+
+ return { stages: nodes, lookup: lookupMap };
+};
+
+const unwrapStagesWithNeeds = (denodedStages) => {
+ return unwrapStagesWithNeedsAndLookup(denodedStages).stages;
+};
+
+export {
+ unwrapGroups,
+ unwrapJobWithNeeds,
+ unwrapNodesWithName,
+ unwrapStagesWithNeeds,
+ unwrapStagesWithNeedsAndLookup,
+};
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/commit/commit_form.vue b/app/assets/javascripts/ci/pipeline_editor/components/commit/commit_form.vue
index 3fe9103c2b3..baf3dbfa090 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/commit/commit_form.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/commit/commit_form.vue
@@ -108,7 +108,6 @@ export default {
<gl-form-group
id="commit-group"
:label="$options.i18n.commitMessage"
- label-cols-sm="2"
label-for="commit-message"
>
<gl-form-textarea
@@ -122,7 +121,6 @@ export default {
<gl-form-group
id="source-branch-group"
:label="$options.i18n.sourceBranch"
- label-cols-sm="2"
label-for="source-branch-field"
>
<gl-form-input
@@ -130,13 +128,12 @@ export default {
v-model="sourceBranch"
class="gl-font-monospace!"
required
- data-qa-selector="source_branch_field"
+ data-testid="source-branch-field"
/>
<gl-form-checkbox
v-if="!isCurrentBranchSourceBranch"
v-model="openMergeRequest"
data-testid="new-mr-checkbox"
- data-qa-selector="new_mr_checkbox"
class="gl-mt-3"
>
<gl-sprintf :message="$options.i18n.startMergeRequest">
@@ -152,7 +149,7 @@ export default {
class="js-no-auto-disable gl-mr-3"
category="primary"
variant="confirm"
- data-qa-selector="commit_changes_button"
+ data-testid="commit-changes-button"
:disabled="isSubmitDisabled"
:loading="isSaving"
>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/editor/ci_editor_header.vue b/app/assets/javascripts/ci/pipeline_editor/components/editor/ci_editor_header.vue
index bc0cad75c60..8f4d566e7e6 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/editor/ci_editor_header.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/editor/ci_editor_header.vue
@@ -89,7 +89,6 @@ export default {
icon="external-link"
target="_blank"
data-testid="template-repo-link"
- data-qa-selector="template_repo_link"
@click="trackTemplateBrowsing"
>
{{ $options.i18n.browseTemplates }}
@@ -98,7 +97,6 @@ export default {
icon="information-o"
size="small"
data-testid="drawer-toggle"
- data-qa-selector="drawer_toggle"
@click="toggleHelpDrawer"
>
{{ $options.i18n.help }}
@@ -107,7 +105,6 @@ export default {
v-if="glFeatures.ciJobAssistantDrawer"
icon="bulb"
size="small"
- data-qa-selector="job_assistant_drawer_toggle"
@click="toggleJobAssistantDrawer"
>
{{ $options.i18n.jobAssistant }}
@@ -117,7 +114,6 @@ export default {
icon="bulb"
size="small"
data-testid="ai-assistant-drawer-toggle"
- data-qa-selector="ai_assistant_drawer_toggle"
@click="toggleAiAssistantDrawer"
>
{{ $options.i18n.aiAssistant }}
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue
index a410e4c933c..221a45d4d9a 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue
@@ -218,7 +218,6 @@ export default {
:text="currentBranch"
:disabled="!enableBranchSwitcher"
icon="branch"
- data-qa-selector="branch_selector_button"
data-testid="branch-selector"
>
<gl-search-box-by-type :debounce="$options.inputDebounce" @input="setSearchTerm" />
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
index 7368d1a3a91..20b42e26f08 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue
@@ -52,7 +52,7 @@ export default {
};
</script>
<template>
- <div class="gl-mb-4 gl-display-flex gl-flex-wrap gl-gap-3">
+ <div class="gl-display-flex gl-flex-wrap gl-gap-3 gl-mb-4">
<gl-button
v-if="showFileTreeToggle"
id="file-tree-toggle"
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue b/app/assets/javascripts/ci/pipeline_editor/components/graph/job_pill.vue
index 3f1d7255a2b..3f1d7255a2b 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/graph/job_pill.vue
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/graph/pipeline_graph.vue b/app/assets/javascripts/ci/pipeline_editor/components/graph/pipeline_graph.vue
new file mode 100644
index 00000000000..eb906cfc486
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_editor/components/graph/pipeline_graph.vue
@@ -0,0 +1,169 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { DRAW_FAILURE, DEFAULT } from '~/ci/pipeline_details/constants';
+import LinksLayer from '~/ci/common/private/job_links_layer.vue';
+import JobPill from './job_pill.vue';
+import StageName from './stage_name.vue';
+
+export default {
+ components: {
+ GlAlert,
+ JobPill,
+ LinksLayer,
+ StageName,
+ },
+ CONTAINER_REF: 'PIPELINE_GRAPH_CONTAINER_REF',
+ BASE_CONTAINER_ID: 'pipeline-graph-container',
+ PIPELINE_ID: 0,
+ STROKE_WIDTH: 2,
+ errorTexts: {
+ [DRAW_FAILURE]: __('Could not draw the lines for job relationships'),
+ [DEFAULT]: __('An unknown error occurred.'),
+ },
+ // The combination of gl-w-full gl-min-w-full and gl-max-w-15 is necessary.
+ // The max width and the width make sure the ellipsis to work and the min width
+ // is for when there is less text than the stage column width (which the width 100% does not fix)
+ jobWrapperClasses:
+ 'gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full gl-px-8 gl-min-w-full gl-max-w-15',
+ props: {
+ pipelineData: {
+ required: true,
+ type: Object,
+ },
+ },
+ data() {
+ return {
+ failureType: null,
+ highlightedJob: null,
+ highlightedJobs: [],
+ measurements: {
+ height: 0,
+ width: 0,
+ },
+ };
+ },
+ computed: {
+ containerId() {
+ return `${this.$options.BASE_CONTAINER_ID}-${this.$options.PIPELINE_ID}`;
+ },
+ failure() {
+ switch (this.failureType) {
+ case DRAW_FAILURE:
+ return {
+ text: this.$options.errorTexts[DRAW_FAILURE],
+ variant: 'danger',
+ dismissible: true,
+ };
+ default:
+ return {
+ text: this.$options.errorTexts[DEFAULT],
+ variant: 'danger',
+ dismissible: true,
+ };
+ }
+ },
+ hasError() {
+ return this.failureType;
+ },
+ hasHighlightedJob() {
+ return Boolean(this.highlightedJob);
+ },
+ pipelineStages() {
+ return this.pipelineData?.stages || [];
+ },
+ },
+ watch: {
+ pipelineData: {
+ immediate: true,
+ handler() {
+ this.$nextTick(() => {
+ this.computeGraphDimensions();
+ });
+ },
+ },
+ },
+ methods: {
+ computeGraphDimensions() {
+ this.measurements = {
+ width: this.$refs[this.$options.CONTAINER_REF].scrollWidth,
+ height: this.$refs[this.$options.CONTAINER_REF].scrollHeight,
+ };
+ },
+ isFadedOut(jobName) {
+ return this.highlightedJobs.length > 1 && !this.isJobHighlighted(jobName);
+ },
+ isJobHighlighted(jobName) {
+ return this.highlightedJobs.includes(jobName);
+ },
+ onError(error) {
+ this.reportFailure(error.type);
+ },
+ removeHoveredJob() {
+ this.highlightedJob = null;
+ },
+ reportFailure(errorType) {
+ this.failureType = errorType;
+ },
+ resetFailure() {
+ this.failureType = null;
+ },
+ setHoveredJob(jobName) {
+ this.highlightedJob = jobName;
+ },
+ updateHighlightedJobs(jobs) {
+ this.highlightedJobs = jobs;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="hasError"
+ :variant="failure.variant"
+ :dismissible="failure.dismissible"
+ @dismiss="resetFailure"
+ >
+ {{ failure.text }}
+ </gl-alert>
+ <div
+ :id="containerId"
+ :ref="$options.CONTAINER_REF"
+ class="gl-bg-gray-10 gl-overflow-auto"
+ data-testid="graph-container"
+ >
+ <links-layer
+ :pipeline-data="pipelineStages"
+ :pipeline-id="$options.PIPELINE_ID"
+ :container-id="containerId"
+ :container-measurements="measurements"
+ :highlighted-job="highlightedJob"
+ @highlightedJobsChange="updateHighlightedJobs"
+ @error="onError"
+ >
+ <div
+ v-for="(stage, index) in pipelineStages"
+ :key="`${stage.name}-${index}`"
+ class="gl-flex-direction-column"
+ >
+ <div class="gl-display-flex gl-align-items-center gl-w-full gl-px-9 gl-py-4 gl-mb-5">
+ <stage-name :stage-name="stage.name" />
+ </div>
+ <div :class="$options.jobWrapperClasses">
+ <job-pill
+ v-for="group in stage.groups"
+ :key="group.name"
+ :job-name="group.name"
+ :pipeline-id="$options.PIPELINE_ID"
+ :is-hovered="highlightedJob === group.name"
+ :is-faded-out="isFadedOut(group.name)"
+ @on-mouse-enter="setHoveredJob"
+ @on-mouse-leave="removeHoveredJob"
+ />
+ </div>
+ </div>
+ </links-layer>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/stage_name.vue b/app/assets/javascripts/ci/pipeline_editor/components/graph/stage_name.vue
index 600832b7633..600832b7633 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/stage_name.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/graph/stage_name.vue
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_header.vue b/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_header.vue
index ec6ee52b6b2..665ca907ed9 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_header.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_header.vue
@@ -1,30 +1,11 @@
<script>
+import { GlCard } from '@gitlab/ui';
import PipelineStatus from './pipeline_status.vue';
import ValidationSegment from './validation_segment.vue';
-const baseClasses = ['gl-p-5', 'gl-bg-gray-10', 'gl-border-solid', 'gl-border-gray-100'];
-
-const pipelineStatusClasses = [
- ...baseClasses,
- 'gl-border-1',
- 'gl-border-b-0!',
- 'gl-rounded-top-base',
-];
-
-const validationSegmentClasses = [...baseClasses, 'gl-border-1', 'gl-rounded-base'];
-
-const validationSegmentWithPipelineStatusClasses = [
- ...baseClasses,
- 'gl-border-1',
- 'gl-rounded-bottom-left-base',
- 'gl-rounded-bottom-right-base',
-];
-
export default {
- pipelineStatusClasses,
- validationSegmentClasses,
- validationSegmentWithPipelineStatusClasses,
components: {
+ GlCard,
PipelineStatus,
ValidationSegment,
},
@@ -47,24 +28,19 @@ export default {
showPipelineStatus() {
return !this.isNewCiConfigFile;
},
- // make sure corners are rounded correctly depending on if
- // pipeline status is rendered
- validationStyling() {
- return this.showPipelineStatus
- ? this.$options.validationSegmentWithPipelineStatusClasses
- : this.$options.validationSegmentClasses;
- },
},
};
</script>
<template>
- <div class="gl-mb-5">
- <pipeline-status
- v-if="showPipelineStatus"
- :commit-sha="commitSha"
- :class="$options.pipelineStatusClasses"
- v-on="$listeners"
- />
- <validation-segment :class="validationStyling" :ci-config="ciConfigData" />
- </div>
+ <gl-card
+ class="gl-new-card gl-mb-3 gl-mt-0"
+ header-class="gl-new-card-header"
+ body-class="gl-new-card-body gl-py-4 gl-px-5"
+ >
+ <template v-if="showPipelineStatus" #header>
+ <pipeline-status :commit-sha="commitSha" v-on="$listeners" />
+ </template>
+
+ <validation-segment :ci-config="ciConfigData" />
+ </gl-card>
</template>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue b/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue
index f1c9770714a..f00098105d3 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue
@@ -1,8 +1,8 @@
<script>
import { __ } from '~/locale';
-import { keepLatestDownstreamPipelines } from '~/pipelines/components/parsing_utils';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
-import getLinkedPipelinesQuery from '~/pipelines/graphql/queries/get_linked_pipelines.query.graphql';
+import { keepLatestDownstreamPipelines } from '~/ci/pipeline_details/utils/parsing_utils';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import getLinkedPipelinesQuery from '~/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql';
import { PIPELINE_FAILURE } from '../../constants';
export default {
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue b/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue
index 3bce50224d9..58b5c0004e0 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue
@@ -5,13 +5,10 @@ import { truncateSha } from '~/lib/utils/text_utility';
import { s__ } from '~/locale';
import getPipelineQuery from '~/ci/pipeline_editor/graphql/queries/pipeline.query.graphql';
import getPipelineEtag from '~/ci/pipeline_editor/graphql/queries/client/pipeline_etag.query.graphql';
-import {
- getQueryHeaders,
- toggleQueryPollingByVisibility,
-} from '~/pipelines/components/graph/utils';
+import { getQueryHeaders, toggleQueryPollingByVisibility } from '~/ci/pipeline_details/graph/utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
+import PipelineMiniGraph from '~/ci/pipeline_mini_graph/pipeline_mini_graph.vue';
import PipelineEditorMiniGraph from './pipeline_editor_mini_graph.vue';
const POLL_INTERVAL = 10000;
@@ -141,7 +138,9 @@ export default {
</script>
<template>
- <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-flex-wrap">
+ <div
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-flex-wrap gl-w-full"
+ >
<template v-if="showLoadingState">
<div>
<gl-loading-icon class="gl-mr-auto gl-display-inline-block" size="sm" />
@@ -149,20 +148,20 @@ export default {
</div>
</template>
<template v-else-if="hasError">
- <gl-icon class="gl-mr-auto" name="warning-solid" />
- <span data-testid="pipeline-error-msg">{{ $options.i18n.fetchError }}</span>
+ <div>
+ <gl-icon class="gl-mr-auto" name="warning-solid" />
+ <span data-testid="pipeline-error-msg">{{ $options.i18n.fetchError }}</span>
+ </div>
</template>
<template v-else>
<div class="gl-text-truncate gl-md-max-w-50p gl-mr-1">
<a :href="status.detailsPath" class="gl-mr-auto">
- <ci-icon :status="status" :size="16" data-testid="pipeline-status-icon" />
+ <ci-icon :status="status" :size="16" data-testid="pipeline-status-icon" class="gl-mr-2" />
</a>
<span class="gl-font-weight-bold">
<gl-sprintf :message="$options.i18n.pipelineInfo">
<template #id="{ content }">
- <span data-testid="pipeline-id" data-qa-selector="pipeline_id_content">
- {{ content }}{{ pipelineId }}
- </span>
+ <span data-testid="pipeline-id"> {{ content }}{{ pipelineId }} </span>
</template>
<template #status>{{ status.text }}</template>
<template #commit>
@@ -187,9 +186,8 @@ export default {
/>
<pipeline-editor-mini-graph v-else :pipeline="pipeline" v-on="$listeners" />
<gl-button
- class="gl-ml-3"
- category="secondary"
- variant="confirm"
+ class="gl-ml-3 gl-align-self-center"
+ size="small"
:href="status.detailsPath"
data-testid="pipeline-view-btn"
>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/header/validation_segment.vue b/app/assets/javascripts/ci/pipeline_editor/components/header/validation_segment.vue
index 8553256f13a..d54ad78b3d3 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/header/validation_segment.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/header/validation_segment.vue
@@ -112,8 +112,8 @@ export default {
{{ $options.i18n.loading }}
</template>
<span v-else data-testid="validation-segment">
- <span class="gl-max-w-full" data-qa-selector="validation_message_content">
- <gl-icon :name="icon" />
+ <span class="gl-max-w-full">
+ <gl-icon :name="icon" class="gl-mr-2" />
<gl-sprintf :message="message">
<template v-if="hasLink" #link="{ content }">
<gl-link :href="helpPath">{{ content }}</gl-link>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/utils.js b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/utils.js
index a604d79259d..32eda355e66 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/utils.js
+++ b/app/assets/javascripts/ci/pipeline_editor/components/job_assistant_drawer/utils.js
@@ -10,7 +10,8 @@ const trimText = (val) => (isString(val) ? trim(val) : val);
export const removeEmptyObj = (obj) => {
if (isArray(obj)) {
return reject(map(obj, removeEmptyObj), isEmptyValue);
- } else if (isObject(obj)) {
+ }
+ if (isObject(obj)) {
return omitBy(mapValues(obj, removeEmptyObj), isEmptyValue);
}
return obj;
@@ -19,7 +20,8 @@ export const removeEmptyObj = (obj) => {
export const trimFields = (data) => {
if (isArray(data)) {
return data.map(trimFields);
- } else if (isObject(data)) {
+ }
+ if (isObject(data)) {
return mapValues(data, trimFields);
}
return trimText(data);
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/pipeline_editor_tabs.vue b/app/assets/javascripts/ci/pipeline_editor/components/pipeline_editor_tabs.vue
index a954615ca8a..c7c15cdd76e 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/pipeline_editor_tabs.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/pipeline_editor_tabs.vue
@@ -2,7 +2,7 @@
import { GlAlert, GlLoadingIcon, GlTabs } from '@gitlab/ui';
import CiEditorHeader from 'ee_else_ce/ci/pipeline_editor/components/editor/ci_editor_header.vue';
import { s__, __ } from '~/locale';
-import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
+import PipelineGraph from '~/ci/pipeline_editor/components/graph/pipeline_graph.vue';
import { getParameterValues, setUrlParams, updateHistory } from '~/lib/utils/url_utility';
import {
CREATE_TAB,
@@ -182,7 +182,7 @@ export default {
<template>
<gl-tabs
class="file-editor gl-mb-3"
- data-qa-selector="file_editor_container"
+ data-testid="file-editor-container"
:query-param-name="$options.query.TAB_QUERY_PARAM"
sync-active-tab-with-query-params
>
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/popovers/file_tree_popover.vue b/app/assets/javascripts/ci/pipeline_editor/components/popovers/file_tree_popover.vue
index efa6a54c638..57694bbcd77 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/popovers/file_tree_popover.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/popovers/file_tree_popover.vue
@@ -42,7 +42,6 @@ export default {
target="file-tree-toggle"
triggers="manual"
placement="right"
- data-qa-selector="file_tree_popover"
@close-button-clicked="dismissPermanently"
>
<div v-outside="dismissPermanently" class="gl-font-base gl-mb-3">
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/ui/pipeline_editor_empty_state.vue b/app/assets/javascripts/ci/pipeline_editor/components/ui/pipeline_editor_empty_state.vue
index 25e4e99bf54..90402a89280 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/ui/pipeline_editor_empty_state.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/ui/pipeline_editor_empty_state.vue
@@ -61,8 +61,7 @@ export default {
<gl-button
variant="confirm"
class="gl-mt-3"
- data-testid="create_new_ci_button"
- data-qa-selector="create_new_ci_button"
+ data-testid="create-new-ci-button"
@click="createEmptyConfigFile"
>
{{ $options.i18n.btnText }}
diff --git a/app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue b/app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue
index 7583fa7a3b5..617088f303b 100644
--- a/app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue
@@ -246,7 +246,6 @@ export default {
class="gl-mt-3"
:disabled="isInitialCiContentLoading"
data-testid="simulate-pipeline-button"
- data-qa-selector="simulate_pipeline_button"
@click="validateYaml"
>
{{ $options.i18n.cta }}
diff --git a/app/assets/javascripts/ci/pipeline_editor/graphql/queries/ci_config.query.graphql b/app/assets/javascripts/ci/pipeline_editor/graphql/queries/ci_config.query.graphql
index 5354ed7c2d5..3570fc1f008 100644
--- a/app/assets/javascripts/ci/pipeline_editor/graphql/queries/ci_config.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_editor/graphql/queries/ci_config.query.graphql
@@ -1,4 +1,4 @@
-#import "~/pipelines/graphql/fragments/pipeline_stages_connection.fragment.graphql"
+#import "~/ci/pipeline_details/graphql/fragments/pipeline_stages_connection.fragment.graphql"
query getCiConfigData($projectPath: ID!, $sha: String, $content: String!) {
ciConfig(projectPath: $projectPath, sha: $sha, content: $content) {
diff --git a/app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue
index de8e5a1a284..49562b0be28 100644
--- a/app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue
+++ b/app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue
@@ -4,7 +4,7 @@ import { fetchPolicies } from '~/lib/graphql';
import { mergeUrlParams, queryToObject, redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
import { __, s__ } from '~/locale';
-import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
+import { unwrapStagesWithNeeds } from '~/ci/pipeline_details/utils/unwrapping_utils';
import ConfirmUnsavedChangesDialog from './components/ui/confirm_unsaved_changes_dialog.vue';
import PipelineEditorEmptyState from './components/ui/pipeline_editor_empty_state.vue';
@@ -394,7 +394,7 @@ export default {
</script>
<template>
- <div class="gl-mt-4 gl-relative" data-qa-selector="pipeline_editor_app">
+ <div class="gl-mt-4 gl-relative">
<gl-loading-icon v-if="isBlobContentLoading" size="lg" class="gl-m-3" />
<pipeline-editor-empty-state
v-else-if="showStartScreen || usesExternalConfig"
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/accessors/linked_pipelines_accessors.js b/app/assets/javascripts/ci/pipeline_mini_graph/accessors/linked_pipelines_accessors.js
index 1ca9e35c008..1ca9e35c008 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/accessors/linked_pipelines_accessors.js
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/accessors/linked_pipelines_accessors.js
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_stage.query.graphql b/app/assets/javascripts/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stage.query.graphql
index 64a5964dbeb..64a5964dbeb 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_stage.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stage.query.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_stages.query.graphql b/app/assets/javascripts/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stages.query.graphql
index 69a29947b16..69a29947b16 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_stages.query.graphql
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stages.query.graphql
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/job_item.vue b/app/assets/javascripts/ci/pipeline_mini_graph/job_item.vue
index 7f97097def6..7f97097def6 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/job_item.vue
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/job_item.vue
diff --git a/app/assets/javascripts/ci/pipeline_mini_graph/legacy_job_item.vue b/app/assets/javascripts/ci/pipeline_mini_graph/legacy_job_item.vue
new file mode 100644
index 00000000000..d20d4aec59d
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/legacy_job_item.vue
@@ -0,0 +1,168 @@
+<script>
+import { GlTooltipDirective, GlLink } from '@gitlab/ui';
+import ActionComponent from '~/ci/common/private/job_action_component.vue';
+import JobNameComponent from '~/ci/common/private/job_name_component.vue';
+import { ICONS } from '~/ci/constants';
+import delayedJobMixin from '~/ci/mixins/delayed_job_mixin';
+import { s__, sprintf } from '~/locale';
+import { reportToSentry } from '~/ci/utils';
+
+/**
+ * Renders the badge for the pipeline graph and the job's dropdown.
+ *
+ * The following object should be provided as `job`:
+ *
+ * {
+ * "id": 4256,
+ * "name": "test",
+ * "status": {
+ * "icon": "status_success",
+ * "text": "passed",
+ * "label": "passed",
+ * "group": "success",
+ * "tooltip": "passed",
+ * "details_path": "/root/ci-mock/builds/4256",
+ * "action": {
+ * "icon": "retry",
+ * "title": "Retry",
+ * "path": "/root/ci-mock/builds/4256/retry",
+ * "method": "post"
+ * }
+ * }
+ * }
+ */
+
+export default {
+ i18n: {
+ runAgainTooltipText: s__('Pipeline|Run again'),
+ },
+ tooltipConfig: {
+ boundary: 'viewport',
+ placement: 'bottom',
+ customClass: 'gl-pointer-events-none',
+ },
+ components: {
+ ActionComponent,
+ JobNameComponent,
+ GlLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [delayedJobMixin],
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ cssClassJobName: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ dropdownLength: {
+ type: Number,
+ required: false,
+ default: Infinity,
+ },
+ pipelineId: {
+ type: Number,
+ required: false,
+ default: -1,
+ },
+ },
+ computed: {
+ boundary() {
+ return this.dropdownLength === 1 ? 'viewport' : 'scrollParent';
+ },
+ detailsPath() {
+ return this.status?.details_path;
+ },
+ hasDetails() {
+ return this.status?.has_details;
+ },
+ status() {
+ return this.job?.status ? this.job.status : {};
+ },
+ tooltipText() {
+ const textBuilder = [];
+ const { name: jobName } = this.job;
+
+ if (jobName) {
+ textBuilder.push(jobName);
+ }
+
+ const { tooltip: statusTooltip } = this.status;
+ if (jobName && statusTooltip) {
+ textBuilder.push('-');
+ }
+
+ if (statusTooltip) {
+ if (this.isDelayedJob) {
+ textBuilder.push(sprintf(statusTooltip, { remainingTime: this.remainingTime }));
+ } else {
+ textBuilder.push(statusTooltip);
+ }
+ }
+
+ return textBuilder.join(' ');
+ },
+ /**
+ * Verifies if the provided job has an action path
+ *
+ * @return {Boolean}
+ */
+ hasJobAction() {
+ return Boolean(this.job?.status?.action?.path);
+ },
+ jobActionTooltipText() {
+ const { group } = this.status;
+ const { title, icon } = this.status.action;
+
+ return icon === ICONS.RETRY && group === ICONS.SUCCESS
+ ? this.$options.i18n.runAgainTooltipText
+ : title;
+ },
+ },
+ errorCaptured(err, _vm, info) {
+ reportToSentry('pipelines_job_item', `pipelines_job_item error: ${err}, info: ${info}`);
+ },
+};
+</script>
+<template>
+ <div
+ class="ci-job-component gl-display-flex gl-align-items-center gl-justify-content-space-between"
+ data-qa-selector="job_item_container"
+ >
+ <gl-link
+ v-if="hasDetails"
+ v-gl-tooltip="$options.tooltipConfig"
+ :href="detailsPath"
+ :title="tooltipText"
+ :class="cssClassJobName"
+ class="js-pipeline-graph-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none gl-focus-text-decoration-none gl-hover-text-decoration-none"
+ data-testid="job-with-link"
+ >
+ <job-name-component :name="job.name" :status="job.status" />
+ </gl-link>
+
+ <div
+ v-else
+ v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }"
+ :title="tooltipText"
+ :class="cssClassJobName"
+ class="js-job-component-tooltip non-details-job-component menu-item"
+ data-testid="job-without-link"
+ >
+ <job-name-component :name="job.name" :status="job.status" />
+ </div>
+
+ <action-component
+ v-if="hasJobAction"
+ :tooltip-text="jobActionTooltipText"
+ :link="status.action.path"
+ :action-icon="status.action.icon"
+ data-qa-selector="action_button"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue b/app/assets/javascripts/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue
index 8c0e65d1d39..8c0e65d1d39 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue
diff --git a/app/assets/javascripts/ci/pipeline_mini_graph/legacy_pipeline_stage.vue b/app/assets/javascripts/ci/pipeline_mini_graph/legacy_pipeline_stage.vue
new file mode 100644
index 00000000000..bbe0f1fbefc
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/legacy_pipeline_stage.vue
@@ -0,0 +1,176 @@
+<script>
+/**
+ * Renders each stage of the pipeline mini graph.
+ *
+ * Given the provided endpoint will make a request to
+ * fetch the dropdown data when the stage is clicked.
+ *
+ * Request is made inside this component to make it reusable between:
+ * 1. Pipelines main table
+ * 2. Pipelines table in commit and Merge request views
+ * 3. Merge request widget
+ * 4. Commit widget
+ */
+
+import { GlDropdown, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import { createAlert } from '~/alert';
+import eventHub from '~/ci/event_hub';
+import axios from '~/lib/utils/axios_utils';
+import { __, s__, sprintf } from '~/locale';
+import LegacyJobItem from './legacy_job_item.vue';
+
+export default {
+ i18n: {
+ errorMessage: __('Something went wrong on our end.'),
+ loadingText: __('Loading...'),
+ mergeTrainMessage: s__('Pipeline|Merge train pipeline jobs can not be retried'),
+ stage: __('Stage:'),
+ viewStageLabel: __('View Stage: %{title}'),
+ },
+ dropdownPopperOpts: {
+ placement: 'bottom',
+ positionFixed: true,
+ },
+ components: {
+ CiIcon,
+ GlLoadingIcon,
+ GlDropdown,
+ LegacyJobItem,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ stage: {
+ type: Object,
+ required: true,
+ },
+ updateDropdown: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isMergeTrain: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ isDropdownOpen: false,
+ isLoading: false,
+ dropdownContent: [],
+ stageName: '',
+ };
+ },
+ watch: {
+ updateDropdown() {
+ if (this.updateDropdown && this.isDropdownOpen && !this.isLoading) {
+ this.fetchJobs();
+ }
+ },
+ },
+ methods: {
+ onHideDropdown() {
+ this.isDropdownOpen = false;
+ },
+ onShowDropdown() {
+ eventHub.$emit('clickedDropdown');
+ this.isDropdownOpen = true;
+ this.isLoading = true;
+ this.fetchJobs();
+
+ // used for tracking and is separate from event hub
+ // to avoid complexity with mixin
+ this.$emit('miniGraphStageClick');
+ },
+ fetchJobs() {
+ axios
+ .get(this.stage.dropdown_path)
+ .then(({ data }) => {
+ this.dropdownContent = data.latest_statuses;
+ this.stageName = data.name;
+ this.isLoading = false;
+ })
+ .catch(() => {
+ this.$refs.dropdown.hide();
+ this.isLoading = false;
+
+ createAlert({
+ message: this.$options.i18n.errorMessage,
+ });
+ });
+ },
+ stageAriaLabel(title) {
+ return sprintf(this.$options.i18n.viewStageLabel, { title });
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ ref="dropdown"
+ v-gl-tooltip.hover.ds0
+ v-gl-tooltip="stage.title"
+ data-testid="mini-pipeline-graph-dropdown"
+ variant="link"
+ :aria-label="stageAriaLabel(stage.title)"
+ :lazy="true"
+ :popper-opts="$options.dropdownPopperOpts"
+ :toggle-class="['gl-rounded-full!']"
+ menu-class="mini-pipeline-graph-dropdown-menu"
+ @hide="onHideDropdown"
+ @show="onShowDropdown"
+ >
+ <template #button-content>
+ <ci-icon
+ is-borderless
+ is-interactive
+ css-classes="gl-rounded-full"
+ :is-active="isDropdownOpen"
+ :size="24"
+ :status="stage.status"
+ class="gl-display-inline-flex gl-align-items-center gl-border gl-z-index-1"
+ />
+ </template>
+ <div v-if="isLoading" class="gl--flex-center gl-p-2" data-testid="pipeline-stage-loading-state">
+ <gl-loading-icon size="sm" class="gl-mr-3" />
+ <p class="gl-line-height-normal gl-mb-0">{{ $options.i18n.loadingText }}</p>
+ </div>
+ <ul
+ v-else
+ class="js-builds-dropdown-list scrollable-menu"
+ data-testid="mini-pipeline-graph-dropdown-menu-list"
+ >
+ <div class="gl--flex-center gl-border-b gl-font-weight-bold gl-mb-3 gl-pb-3">
+ <span class="gl-mr-1">{{ $options.i18n.stage }}</span>
+ <span data-testid="pipeline-stage-dropdown-menu-title">{{ stageName }}</span>
+ </div>
+ <li v-for="job in dropdownContent" :key="job.id">
+ <legacy-job-item
+ :dropdown-length="dropdownContent.length"
+ :job="job"
+ css-class-job-name="pipeline-job-item"
+ />
+ </li>
+ <template v-if="isMergeTrain">
+ <li class="gl-dropdown-divider" role="presentation">
+ <hr role="separator" aria-orientation="horizontal" class="dropdown-divider" />
+ </li>
+ <li>
+ <div
+ class="gl-display-flex gl-align-items-center"
+ data-testid="warning-message-merge-trains"
+ >
+ <div class="menu-item gl-font-sm gl-text-gray-300!">
+ {{ $options.i18n.mergeTrainMessage }}
+ </div>
+ </div>
+ </li>
+ </template>
+ </ul>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_mini_graph/linked_pipelines_mini_list.vue b/app/assets/javascripts/ci/pipeline_mini_graph/linked_pipelines_mini_list.vue
new file mode 100644
index 00000000000..8567654a89e
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/linked_pipelines_mini_list.vue
@@ -0,0 +1,132 @@
+<script>
+import { GlTooltipDirective } from '@gitlab/ui';
+import { sprintf, s__ } from '~/locale';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import { accessValue } from './accessors/linked_pipelines_accessors';
+/**
+ * Renders the upstream/downstream portions of the pipeline mini graph.
+ */
+export default {
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ CiIcon,
+ },
+ inject: {
+ dataMethod: {
+ default: 'rest',
+ },
+ },
+ props: {
+ triggeredBy: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ triggered: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ pipelinePath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ maxRenderedPipelines: 3,
+ };
+ },
+ computed: {
+ // Exactly one of these (triggeredBy and triggered) must be truthy. Never both. Never neither.
+ isUpstream() {
+ return Boolean(this.triggeredBy.length) && !this.triggered.length;
+ },
+ isDownstream() {
+ return !this.triggeredBy.length && Boolean(this.triggered.length);
+ },
+ linkedPipelines() {
+ return this.isUpstream ? this.triggeredBy : this.triggered;
+ },
+ totalPipelineCount() {
+ return this.linkedPipelines.length;
+ },
+ linkedPipelinesTrimmed() {
+ return this.totalPipelineCount > this.maxRenderedPipelines
+ ? this.linkedPipelines.slice(0, this.maxRenderedPipelines)
+ : this.linkedPipelines;
+ },
+ shouldRenderCounter() {
+ return this.isDownstream && this.linkedPipelines.length > this.maxRenderedPipelines;
+ },
+ counterLabel() {
+ return `+${this.linkedPipelines.length - this.maxRenderedPipelines}`;
+ },
+ counterTooltipText() {
+ return sprintf(s__('LinkedPipelines|%{counterLabel} more downstream pipelines'), {
+ counterLabel: this.counterLabel,
+ });
+ },
+ },
+ methods: {
+ pipelineTooltipText(pipeline) {
+ const { label } = accessValue(pipeline, this.dataMethod, 'detailedStatus');
+
+ return `${pipeline.project.name} - ${label}`;
+ },
+ pipelineStatus(pipeline) {
+ // detailedStatus is graphQL, details.status is REST
+ return pipeline?.detailedStatus || pipeline?.details?.status;
+ },
+ triggerButtonClass(pipeline) {
+ const { group } = accessValue(pipeline, this.dataMethod, 'detailedStatus');
+
+ return `ci-status-icon-${group}`;
+ },
+ },
+};
+</script>
+
+<template>
+ <span
+ v-if="linkedPipelines"
+ :class="{
+ 'is-upstream': isUpstream,
+ 'is-downstream': isDownstream,
+ }"
+ class="linked-pipeline-mini-list gl-display-inline gl-vertical-align-middle"
+ >
+ <a
+ v-for="pipeline in linkedPipelinesTrimmed"
+ :key="pipeline.id"
+ v-gl-tooltip="{ title: pipelineTooltipText(pipeline) }"
+ :href="pipeline.path"
+ :class="triggerButtonClass(pipeline)"
+ class="linked-pipeline-mini-item gl-display-inline-flex gl-mr-2 gl-my-2 gl-rounded-full gl-vertical-align-middle"
+ data-testid="linked-pipeline-mini-item"
+ >
+ <ci-icon
+ is-borderless
+ is-interactive
+ css-classes="gl-rounded-full"
+ :size="24"
+ :status="pipelineStatus(pipeline)"
+ class="gl-align-items-center gl-border gl-display-inline-flex"
+ />
+ </a>
+
+ <a
+ v-if="shouldRenderCounter"
+ v-gl-tooltip="{ title: counterTooltipText }"
+ :title="counterTooltipText"
+ :href="pipelinePath"
+ class="gl-align-items-center gl-bg-gray-50 gl-display-inline-flex gl-font-sm gl-h-6 gl-justify-content-center gl-rounded-pill gl-text-decoration-none gl-text-gray-500 gl-w-7 linked-pipelines-counter linked-pipeline-mini-item"
+ data-testid="linked-pipeline-counter"
+ >
+ {{ counterLabel }}
+ </a>
+ </span>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_mini_graph.vue b/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_mini_graph.vue
new file mode 100644
index 00000000000..358d3dc826e
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_mini_graph.vue
@@ -0,0 +1,147 @@
+<script>
+import { GlLoadingIcon } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { keepLatestDownstreamPipelines } from '~/ci/pipeline_details/utils/parsing_utils';
+import { getQueryHeaders, toggleQueryPollingByVisibility } from '~/ci/pipeline_details/graph/utils';
+import { PIPELINE_MINI_GRAPH_POLL_INTERVAL } from '~/ci/pipeline_details/constants';
+import getLinkedPipelinesQuery from '~/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql';
+import getPipelineStagesQuery from './graphql/queries/get_pipeline_stages.query.graphql';
+import LegacyPipelineMiniGraph from './legacy_pipeline_mini_graph.vue';
+
+export default {
+ i18n: {
+ linkedPipelinesFetchError: __('There was a problem fetching linked pipelines.'),
+ stagesFetchError: __('There was a problem fetching the pipeline stages.'),
+ },
+ components: {
+ GlLoadingIcon,
+ LegacyPipelineMiniGraph,
+ },
+ props: {
+ pipelineEtag: {
+ type: String,
+ required: true,
+ },
+ fullPath: {
+ type: String,
+ required: true,
+ },
+ iid: {
+ type: String,
+ required: true,
+ },
+ isMergeTrain: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ pollInterval: {
+ type: Number,
+ required: false,
+ default: PIPELINE_MINI_GRAPH_POLL_INTERVAL,
+ },
+ },
+ data() {
+ return {
+ linkedPipelines: null,
+ pipelineStages: [],
+ };
+ },
+ apollo: {
+ linkedPipelines: {
+ context() {
+ return getQueryHeaders(this.pipelineEtag);
+ },
+ query: getLinkedPipelinesQuery,
+ pollInterval() {
+ return this.pollInterval;
+ },
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ iid: this.iid,
+ };
+ },
+ update({ project }) {
+ return project?.pipeline || this.linkedpipelines;
+ },
+ error() {
+ createAlert({ message: this.$options.i18n.linkedPipelinesFetchError });
+ },
+ },
+ pipelineStages: {
+ context() {
+ return getQueryHeaders(this.pipelineEtag);
+ },
+ query: getPipelineStagesQuery,
+ pollInterval() {
+ return this.pollInterval;
+ },
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ iid: this.iid,
+ };
+ },
+ update({ project }) {
+ return project?.pipeline?.stages?.nodes || this.pipelineStages;
+ },
+ error() {
+ createAlert({ message: this.$options.i18n.stagesFetchError });
+ },
+ },
+ },
+ computed: {
+ downstreamPipelines() {
+ return keepLatestDownstreamPipelines(this.linkedPipelines?.downstream?.nodes);
+ },
+ formattedStages() {
+ return this.pipelineStages.map((stage) => {
+ const { name, detailedStatus } = stage;
+ return {
+ // TODO: Once we fetch stage by ID with GraphQL,
+ // this method will change.
+ // see https://gitlab.com/gitlab-org/gitlab/-/issues/384853
+ id: stage.id,
+ dropdown_path: `${this.pipelinePath}/stage.json?stage=${name}`,
+ name,
+ path: `${this.pipelinePath}#${name}`,
+ status: {
+ details_path: `${this.pipelinePath}#${name}`,
+ has_details: detailedStatus?.hasDetails || false,
+ ...detailedStatus,
+ },
+ title: `${name}: ${detailedStatus?.text || ''}`,
+ };
+ });
+ },
+ pipelinePath() {
+ return this.linkedPipelines?.path || '';
+ },
+ upstreamPipeline() {
+ return this.linkedPipelines?.upstream;
+ },
+ },
+ mounted() {
+ toggleQueryPollingByVisibility(this.$apollo.queries.linkedPipelines);
+ toggleQueryPollingByVisibility(this.$apollo.queries.pipelineStages);
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-loading-icon v-if="$apollo.queries.pipelineStages.loading" />
+ <legacy-pipeline-mini-graph
+ v-else
+ data-testid="pipeline-mini-graph"
+ is-graphql
+ :downstream-pipelines="downstreamPipelines"
+ :is-merge-train="isMergeTrain"
+ :pipeline-path="pipelinePath"
+ :stages="formattedStages"
+ :upstream-pipeline="upstreamPipeline"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_stage.vue b/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_stage.vue
new file mode 100644
index 00000000000..747b5d33b1a
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_stage.vue
@@ -0,0 +1,81 @@
+<script>
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { PIPELINE_MINI_GRAPH_POLL_INTERVAL } from '~/ci/pipeline_details/constants';
+import { getQueryHeaders, toggleQueryPollingByVisibility } from '~/ci/pipeline_details/graph/utils';
+import getPipelineStageQuery from './graphql/queries/get_pipeline_stage.query.graphql';
+import JobItem from './job_item.vue';
+
+export default {
+ i18n: {
+ stageFetchError: __('There was a problem fetching the pipeline stage.'),
+ },
+
+ components: {
+ JobItem,
+ },
+ props: {
+ isMergeTrain: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ pipelineEtag: {
+ type: String,
+ required: true,
+ },
+ pollInterval: {
+ type: Number,
+ required: false,
+ default: PIPELINE_MINI_GRAPH_POLL_INTERVAL,
+ },
+ stageId: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ jobs: [],
+ stage: null,
+ };
+ },
+ apollo: {
+ stage: {
+ context() {
+ return getQueryHeaders(this.pipelineEtag);
+ },
+ query: getPipelineStageQuery,
+ pollInterval() {
+ return this.pollInterval;
+ },
+ variables() {
+ return {
+ id: this.stageId,
+ };
+ },
+ skip() {
+ return !this.stageId;
+ },
+ update(data) {
+ this.jobs = data?.ciPipelineStage?.jobs.nodes;
+ return data?.ciPipelineStage;
+ },
+ error() {
+ createAlert({ message: this.$options.i18n.stageFetchError });
+ },
+ },
+ },
+ mounted() {
+ toggleQueryPollingByVisibility(this.$apollo.queries.stage);
+ },
+};
+</script>
+
+<template>
+ <div data-testid="pipeline-stage">
+ <ul v-for="job in jobs" :key="job.id">
+ <job-item :job="job" />
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_stages.vue b/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_stages.vue
new file mode 100644
index 00000000000..f883833f7ea
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_mini_graph/pipeline_stages.vue
@@ -0,0 +1,63 @@
+<script>
+import PipelineStage from './pipeline_stage.vue';
+import LegacyPipelineStage from './legacy_pipeline_stage.vue';
+/**
+ * Renders the pipeline stages portion of the pipeline mini graph.
+ */
+export default {
+ components: {
+ LegacyPipelineStage,
+ PipelineStage,
+ },
+ props: {
+ stages: {
+ type: Array,
+ required: true,
+ },
+ updateDropdown: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isGraphql: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isMergeTrain: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ pipelineEtag: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+};
+</script>
+<template>
+ <div class="gl-display-inline gl-vertical-align-middle">
+ <div
+ v-for="stage in stages"
+ :key="stage.name"
+ class="pipeline-mini-graph-stage-container dropdown gl-display-inline-flex gl-mr-2 gl-my-2 gl-vertical-align-middle"
+ >
+ <pipeline-stage
+ v-if="isGraphql"
+ :stage-id="stage.id"
+ :is-merge-train="isMergeTrain"
+ :pipeline-etag="pipelineEtag"
+ @miniGraphStageClick="$emit('miniGraphStageClick')"
+ />
+ <legacy-pipeline-stage
+ v-else
+ :stage="stage"
+ :update-dropdown="updateDropdown"
+ :is-merge-train="isMergeTrain"
+ @miniGraphStageClick="$emit('miniGraphStageClick')"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_empty_state.vue b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_empty_state.vue
index fbdb60f61f1..f701bedc74d 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_empty_state.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_empty_state.vue
@@ -41,6 +41,7 @@ export default {
<template>
<gl-empty-state
:svg-path="$options.SCHEDULE_MD_SVG_URL"
+ :svg-height="150"
:primary-button-text="$options.i18n.createNew"
:primary-button-link="newSchedulePath"
>
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue
index 396ff9808f2..0c3ede47015 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue
@@ -1,8 +1,7 @@
<script>
import {
GlButton,
- GlDropdown,
- GlDropdownItem,
+ GlCollapsibleListbox,
GlFormCheckbox,
GlForm,
GlFormGroup,
@@ -27,8 +26,7 @@ const scheduleId = queryToObject(window.location.search).id;
export default {
components: {
GlButton,
- GlDropdown,
- GlDropdownItem,
+ GlCollapsibleListbox,
GlForm,
GlFormCheckbox,
GlFormGroup,
@@ -81,7 +79,7 @@ export default {
this.description = schedule.description;
this.cron = schedule.cron;
this.cronTimezone = schedule.cronTimezone;
- this.scheduleRef = schedule.ref;
+ this.scheduleRef = schedule.ref || this.defaultBranch;
this.variables = variables.map((variable) => {
return {
id: variable.id,
@@ -144,10 +142,6 @@ export default {
revealText: __('Reveal values'),
hideText: __('Hide values'),
},
- typeOptions: {
- [VARIABLE_TYPE]: __('Variable'),
- [FILE_TYPE]: __('File'),
- },
formElementClasses: 'gl-md-mr-3 gl-mb-3 gl-flex-basis-quarter gl-flex-shrink-0 gl-flex-grow-0',
computed: {
dropdownTranslations() {
@@ -155,7 +149,7 @@ export default {
dropdownHeader: this.$options.i18n.targetBranchTag,
};
},
- typeOptionsListbox() {
+ typeOptions() {
return [
{
text: __('Variable'),
@@ -232,9 +226,9 @@ export default {
empty: true,
});
},
- setVariableAttribute(key, attribute, value) {
+ setVariableType(typeValue, key) {
const variable = this.variables.find((v) => v.key === key);
- variable[attribute] = value;
+ variable.variableType = typeValue;
},
removeVariable(index) {
this.variables[index].destroy = true;
@@ -387,19 +381,15 @@ export default {
class="gl-display-flex gl-align-items-stretch gl-flex-direction-column gl-md-flex-direction-row gl-mb-3 gl-pb-2"
data-testid="ci-variable-row"
>
- <gl-dropdown
- :text="$options.typeOptions[variable.variableType]"
+ <gl-collapsible-listbox
+ :items="typeOptions"
+ :selected="variable.variableType"
:class="$options.formElementClasses"
+ block
data-testid="pipeline-form-ci-variable-type"
- >
- <gl-dropdown-item
- v-for="type in Object.keys($options.typeOptions)"
- :key="type"
- @click="setVariableAttribute(variable.key, 'variableType', type)"
- >
- {{ $options.typeOptions[type] }}
- </gl-dropdown-item>
- </gl-dropdown>
+ @select="setVariableType($event, variable.key)"
+ />
+
<gl-form-input
v-model="variable.key"
:placeholder="s__('CiVariables|Input variable key')"
@@ -414,7 +404,6 @@ export default {
value="*****************"
disabled
class="gl-mb-3 gl-h-7!"
- :style="$options.textAreaStyle"
:no-resize="false"
data-testid="pipeline-form-ci-variable-hidden-value"
/>
@@ -424,7 +413,6 @@ export default {
v-model="variable.value"
:placeholder="s__('CiVariables|Input variable value')"
class="gl-mb-3 gl-h-7!"
- :style="$options.textAreaStyle"
:no-resize="false"
data-testid="pipeline-form-ci-variable-value"
data-qa-selector="ci_variable_value_field"
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue
index 08efa794bcc..56d50026f17 100644
--- a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue
@@ -27,10 +27,13 @@ export default {
</script>
<template>
- <div>
- <gl-icon :name="iconName" />
+ <div data-testid="pipeline-schedule-target">
<span v-if="refPath">
+ <gl-icon :name="iconName" />
<gl-link :href="refPath" class="gl-text-gray-900">{{ refDisplay }}</gl-link>
</span>
+ <span v-else>
+ {{ s__('PipelineSchedules|None') }}
+ </span>
</div>
</template>
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue
deleted file mode 100644
index b4d84309c5f..00000000000
--- a/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-<script>
-import { GlModal } from '@gitlab/ui';
-import { __, s__ } from '~/locale';
-
-export default {
- components: {
- GlModal,
- },
- props: {
- ownershipUrl: {
- type: String,
- required: true,
- },
- },
- modalId: 'pipeline-take-ownership-modal',
- i18n: {
- takeOwnership: s__('PipelineSchedules|Take ownership'),
- ownershipMessage: s__(
- 'PipelineSchedules|Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?',
- ),
- cancelLabel: __('Cancel'),
- },
- computed: {
- actionCancel() {
- return { text: this.$options.i18n.cancelLabel };
- },
- actionPrimary() {
- return {
- text: this.$options.i18n.takeOwnership,
- attributes: {
- variant: 'confirm',
- category: 'primary',
- href: this.ownershipUrl,
- 'data-method': 'post',
- },
- };
- },
- },
-};
-</script>
-<template>
- <gl-modal
- :modal-id="$options.modalId"
- :action-primary="actionPrimary"
- :action-cancel="actionCancel"
- :title="$options.i18n.takeOwnership"
- >
- <p>{{ $options.i18n.ownershipMessage }}</p>
- </gl-modal>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ci_templates.vue b/app/assets/javascripts/ci/pipelines_page/components/empty_state/ci_templates.vue
index 439dc0eb253..439dc0eb253 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ci_templates.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/empty_state/ci_templates.vue
diff --git a/app/assets/javascripts/ci/pipelines_page/components/empty_state/ios_templates.vue b/app/assets/javascripts/ci/pipelines_page/components/empty_state/ios_templates.vue
new file mode 100644
index 00000000000..1a2021df9c8
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/empty_state/ios_templates.vue
@@ -0,0 +1,220 @@
+<script>
+import { GlButton, GlCard, GlSprintf, GlLink, GlPopover, GlModalDirective } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { mergeUrlParams, DOCS_URL } from '~/lib/utils/url_utility';
+import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
+import apolloProvider from '~/ci/pipeline_details/graphql/provider';
+import CiTemplates from './ci_templates.vue';
+
+export default {
+ components: {
+ GlButton,
+ GlCard,
+ GlSprintf,
+ GlLink,
+ GlPopover,
+ RunnerInstructionsModal,
+ CiTemplates,
+ },
+ directives: {
+ GlModalDirective,
+ },
+ inject: ['pipelineEditorPath', 'iosRunnersAvailable'],
+ props: {
+ registrationToken: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ apolloProvider,
+ iOSTemplateName: 'iOS-Fastlane',
+ modalId: 'runner-instructions-modal',
+ runnerDocsLink: `${DOCS_URL}/runner/install/osx`,
+ whatElseLink: helpPagePath('ci/index.md'),
+ i18n: {
+ title: s__('Pipelines|Get started with GitLab CI/CD'),
+ subtitle: s__('Pipelines|Building for iOS?'),
+ explanation: s__("Pipelines|We'll walk you through how to deploy to iOS in two easy steps."),
+ runnerSetupTitle: s__('Pipelines|1. Set up a runner'),
+ runnerSetupButton: s__('Pipelines|Set up a runner'),
+ runnerSetupBodyUnfinished: s__(
+ 'Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline.',
+ ),
+ runnerSetupBodyFinished: s__(
+ 'Pipelines|You have runners available to run your job now. No need to do anything else.',
+ ),
+ runnerSetupPopoverTitle: s__(
+ "Pipelines|Let's get that runner set up! %{emojiStart}tada%{emojiEnd}",
+ ),
+ runnerSetupPopoverBodyLine1: s__(
+ 'Pipelines|Follow these instructions to install GitLab Runner on macOS.',
+ ),
+ runnerSetupPopoverBodyLine2: s__(
+ 'Pipelines|Need more information to set up your runner? %{linkStart}Check out our documentation%{linkEnd}.',
+ ),
+ configurePipelineTitle: s__('Pipelines|2. Configure deployment pipeline'),
+ configurePipelineBody: s__("Pipelines|We'll guide you through a simple pipeline set-up."),
+ configurePipelineButton: s__('Pipelines|Configure pipeline'),
+ noWalkthroughTitle: s__("Pipelines|Don't need a guide? Jump in right away with a template."),
+ noWalkthroughExplanation: s__('Pipelines|Based on your project, we recommend this template:'),
+ notBuildingForIos: s__(
+ "Pipelines|Not building for iOS or not what you're looking for? %{linkStart}See what else%{linkEnd} GitLab CI/CD has to offer.",
+ ),
+ },
+ data() {
+ return {
+ isModalShown: false,
+ isPopoverShown: false,
+ isRunnerSetupFinished: this.iosRunnersAvailable,
+ popoverTarget: `${this.$options.modalId}___BV_modal_content_`,
+ configurePipelineLink: mergeUrlParams(
+ { template: this.$options.iOSTemplateName },
+ this.pipelineEditorPath,
+ ),
+ };
+ },
+ computed: {
+ runnerSetupBodyText() {
+ return this.iosRunnersAvailable
+ ? this.$options.i18n.runnerSetupBodyFinished
+ : this.$options.i18n.runnerSetupBodyUnfinished;
+ },
+ },
+ methods: {
+ showModal() {
+ this.isModalShown = true;
+ },
+ hideModal() {
+ this.togglePopover();
+ this.isRunnerSetupFinished = true;
+ },
+ togglePopover() {
+ this.isPopoverShown = !this.isPopoverShown;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <h2 class="gl-font-size-h2 gl-text-gray-900">{{ $options.i18n.title }}</h2>
+ <h3 class="gl-font-lg gl-text-gray-900 gl-mt-1">{{ $options.i18n.subtitle }}</h3>
+ <p>{{ $options.i18n.explanation }}</p>
+
+ <div class="gl-lg-display-flex">
+ <div class="gl-lg-display-flex gl-lg-w-25p gl-lg-pr-4 gl-mb-4">
+ <gl-card body-class="gl-display-flex gl-flex-grow-1">
+ <div
+ class="gl-display-flex gl-flex-grow-1 gl-flex-direction-column gl-justify-content-space-between gl-align-items-flex-start"
+ >
+ <div>
+ <div class="gl-py-5">
+ <gl-emoji
+ v-show="isRunnerSetupFinished"
+ class="gl-font-size-h2-xl"
+ data-name="white_check_mark"
+ data-testid="runner-setup-marked-completed"
+ />
+ <gl-emoji
+ v-show="!isRunnerSetupFinished"
+ class="gl-font-size-h2-xl"
+ data-name="tools"
+ data-testid="runner-setup-marked-todo"
+ />
+ </div>
+ <span class="gl-text-gray-800 gl-font-weight-bold">
+ {{ $options.i18n.runnerSetupTitle }}
+ </span>
+ <p class="gl-font-sm gl-mt-3">{{ runnerSetupBodyText }}</p>
+ </div>
+
+ <gl-button
+ v-if="!iosRunnersAvailable"
+ v-gl-modal-directive="$options.modalId"
+ category="primary"
+ variant="confirm"
+ @click="showModal"
+ >
+ {{ $options.i18n.runnerSetupButton }}
+ </gl-button>
+ <runner-instructions-modal
+ v-if="isModalShown"
+ :modal-id="$options.modalId"
+ :registration-token="registrationToken"
+ default-platform-name="osx"
+ @shown="togglePopover"
+ @hide="hideModal"
+ />
+ <gl-popover
+ v-if="isPopoverShown"
+ :show="true"
+ :show-close-button="true"
+ :target="popoverTarget"
+ triggers="manual"
+ placement="left"
+ fallback-placement="clockwise"
+ >
+ <template #title>
+ <gl-sprintf :message="$options.i18n.runnerSetupPopoverTitle">
+ <template #emoji="{ content }">
+ <gl-emoji class="gl-ml-2" :data-name="content" />
+ </template>
+ </gl-sprintf>
+ </template>
+ <div class="gl-mb-5">
+ {{ $options.i18n.runnerSetupPopoverBodyLine1 }}
+ </div>
+ <gl-sprintf :message="$options.i18n.runnerSetupPopoverBodyLine2">
+ <template #link="{ content }">
+ <gl-link :href="$options.runnerDocsLink" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-popover>
+ </div>
+ </gl-card>
+ </div>
+ <div class="gl-lg-display-flex gl-lg-w-25p gl-lg-pr-4 gl-mb-4">
+ <gl-card body-class="gl-display-flex gl-flex-grow-1">
+ <div
+ class="gl-display-flex gl-flex-grow-1 gl-flex-direction-column gl-justify-content-space-between gl-align-items-flex-start"
+ >
+ <div>
+ <div class="gl-py-5"><gl-emoji class="gl-font-size-h2-xl" data-name="tools" /></div>
+ <span class="gl-text-gray-800 gl-font-weight-bold">
+ {{ $options.i18n.configurePipelineTitle }}
+ </span>
+ <p class="gl-font-sm gl-mt-3">{{ $options.i18n.configurePipelineBody }}</p>
+ </div>
+
+ <gl-button
+ :disabled="!isRunnerSetupFinished"
+ category="primary"
+ variant="confirm"
+ data-testid="configure-pipeline-link"
+ :href="configurePipelineLink"
+ >
+ {{ $options.i18n.configurePipelineButton }}
+ </gl-button>
+ </div>
+ </gl-card>
+ </div>
+ </div>
+ <h3 class="gl-font-lg gl-text-gray-900 gl-mt-5">{{ $options.i18n.noWalkthroughTitle }}</h3>
+ <p>{{ $options.i18n.noWalkthroughExplanation }}</p>
+ <ci-templates
+ :filter-templates="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
+ $options.iOSTemplateName,
+ ] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
+ :disabled="!isRunnerSetupFinished"
+ />
+ <p>
+ <gl-sprintf :message="$options.i18n.notBuildingForIos">
+ <template #link="{ content }">
+ <gl-link :href="$options.whatElseLink">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue b/app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue
new file mode 100644
index 00000000000..6e7d6908cd9
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue
@@ -0,0 +1,53 @@
+<script>
+import { GlEmptyState } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
+import PipelinesCiTemplates from './pipelines_ci_templates.vue';
+import IosTemplates from './ios_templates.vue';
+
+export default {
+ i18n: {
+ noCiDescription: s__('Pipelines|This project is not currently set up to run pipelines.'),
+ },
+ name: 'PipelinesEmptyState',
+ components: {
+ GlEmptyState,
+ GitlabExperiment,
+ PipelinesCiTemplates,
+ IosTemplates,
+ },
+ props: {
+ emptyStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ canSetCi: {
+ type: Boolean,
+ required: true,
+ },
+ registrationToken: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gitlab-experiment v-if="canSetCi" name="ios_specific_templates">
+ <template #control>
+ <pipelines-ci-templates />
+ </template>
+ <template #candidate>
+ <ios-templates :registration-token="registrationToken" />
+ </template>
+ </gitlab-experiment>
+ <gl-empty-state
+ v-else
+ title=""
+ :svg-path="emptyStateSvgPath"
+ :description="$options.i18n.noCiDescription"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue b/app/assets/javascripts/ci/pipelines_page/components/empty_state/pipelines_ci_templates.vue
index a6297213402..a6297213402 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/empty_state/pipelines_ci_templates.vue
diff --git a/app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_job_details.vue b/app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_job_details.vue
new file mode 100644
index 00000000000..82f1d57912a
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_job_details.vue
@@ -0,0 +1,165 @@
+<script>
+import { GlButton, GlIcon, GlLink, GlTooltip } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import { __, s__, sprintf } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { BRIDGE_KIND } from '~/ci/pipeline_details/graph/constants';
+import RetryMrFailedJobMutation from '~/ci/merge_requests/graphql/mutations/retry_mr_failed_job.mutation.graphql';
+
+export default {
+ components: {
+ CiIcon,
+ GlButton,
+ GlIcon,
+ GlLink,
+ GlTooltip,
+ },
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isHovered: false,
+ isJobLogVisible: false,
+ isLoadingAction: false,
+ };
+ },
+ computed: {
+ canReadBuild() {
+ return this.job.userPermissions.readBuild;
+ },
+ canRetryJob() {
+ return this.job.retryable && this.job.userPermissions.updateBuild && !this.isBridgeJob;
+ },
+ isBridgeJob() {
+ return this.job.kind === BRIDGE_KIND;
+ },
+ jobChevronName() {
+ return this.isJobLogVisible ? 'chevron-down' : 'chevron-right';
+ },
+ jobTrace() {
+ if (this.canReadBuild) {
+ return this.job?.trace?.htmlSummary || this.$options.i18n.noTraceText;
+ }
+
+ return this.$options.i18n.cannotReadBuild;
+ },
+ parsedJobId() {
+ return getIdFromGraphQLId(this.job.id);
+ },
+ tooltipErrorText() {
+ return this.isBridgeJob
+ ? this.$options.i18n.cannotRetryTrigger
+ : this.$options.i18n.cannotRetry;
+ },
+ tooltipText() {
+ return sprintf(this.$options.i18n.jobActionTooltipText, { jobName: this.job.name });
+ },
+ },
+ methods: {
+ setActiveRow() {
+ this.isHovered = true;
+ },
+ resetActiveRow() {
+ this.isHovered = false;
+ },
+ async retryJob() {
+ try {
+ this.isLoadingAction = true;
+
+ const {
+ data: {
+ jobRetry: { errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: RetryMrFailedJobMutation,
+ variables: { id: this.job.id },
+ });
+
+ if (errors.length > 0) {
+ throw new Error(errors[0]);
+ }
+
+ this.$emit('job-retried', this.job.name);
+ } catch (error) {
+ createAlert({ message: error?.message || this.$options.i18n.retryError });
+ } finally {
+ this.isLoadingAction = false;
+ }
+ },
+ toggleJobLog(event) {
+ // Do not toggle the log visibility when clicking on a link
+ if (event.target.tagName === 'A') {
+ return;
+ }
+ this.isJobLogVisible = !this.isJobLogVisible;
+ },
+ },
+ i18n: {
+ cannotReadBuild: s__("Job|You do not have permission to read this job's log."),
+ cannotRetry: s__('Job|You do not have permission to run this job again.'),
+ cannotRetryTrigger: s__('Job|You cannot rerun trigger jobs from this list.'),
+ jobActionTooltipText: s__('Pipelines|Retry %{jobName} Job'),
+ noTraceText: s__('Job|No job log'),
+ retry: __('Retry'),
+ retryError: __('There was an error while retrying this job'),
+ },
+};
+</script>
+<template>
+ <div class="container-fluid gl-grid-tpl-rows-auto">
+ <div
+ class="row gl-my-3 gl-cursor-pointer gl-display-flex gl-align-items-center"
+ :aria-pressed="isJobLogVisible"
+ role="button"
+ tabindex="0"
+ data-testid="widget-row"
+ @click="toggleJobLog"
+ @keyup.enter="toggleJobLog"
+ @keyup.space="toggleJobLog"
+ @mouseover="setActiveRow"
+ @mouseout="resetActiveRow"
+ >
+ <div class="col-6 gl-text-gray-900 gl-font-weight-bold gl-text-left">
+ <gl-icon :name="jobChevronName" />
+ <ci-icon :status="job.detailedStatus" />
+ {{ job.name }}
+ </div>
+ <div class="col-2 gl-text-left">{{ job.stage.name }}</div>
+ <div class="col-2 gl-text-left">
+ <gl-link :href="job.detailedStatus.detailsPath">#{{ parsedJobId }}</gl-link>
+ </div>
+ <gl-tooltip v-if="!canRetryJob" :target="() => $refs.retryBtn" placement="top">
+ {{ tooltipErrorText }}
+ </gl-tooltip>
+ <div class="col-2 gl-text-right">
+ <span ref="retryBtn">
+ <gl-button
+ :disabled="!canRetryJob"
+ icon="retry"
+ category="tertiary"
+ :loading="isLoadingAction"
+ :title="$options.i18n.retry"
+ :aria-label="$options.i18n.retry"
+ @click.stop="retryJob"
+ />
+ </span>
+ </div>
+ </div>
+ <div v-if="isJobLogVisible" class="row">
+ <pre
+ v-safe-html="jobTrace"
+ class="gl-bg-gray-900 gl-text-white gl-w-full"
+ data-testid="job-log"
+ ></pre>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_jobs_list.vue b/app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_jobs_list.vue
new file mode 100644
index 00000000000..138269bdb8a
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_jobs_list.vue
@@ -0,0 +1,180 @@
+<script>
+import { GlLoadingIcon } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import { __, s__, sprintf } from '~/locale';
+import { getQueryHeaders } from '~/ci/pipeline_details/graph/utils';
+import { graphqlEtagPipelinePath } from '~/ci/pipeline_details/utils';
+import getPipelineFailedJobs from '~/ci/pipelines_page/graphql/queries/get_pipeline_failed_jobs.query.graphql';
+import { sortJobsByStatus } from './utils';
+import FailedJobDetails from './failed_job_details.vue';
+
+const POLL_INTERVAL = 10000;
+
+const JOB_ID_HEADER = __('ID');
+const JOB_NAME_HEADER = __('Name');
+const STAGE_HEADER = __('Stage');
+
+export default {
+ components: {
+ GlLoadingIcon,
+ FailedJobDetails,
+ },
+ inject: ['graphqlPath'],
+ props: {
+ failedJobsCount: {
+ required: true,
+ type: Number,
+ },
+ isPipelineActive: {
+ required: true,
+ type: Boolean,
+ },
+ pipelineIid: {
+ type: Number,
+ required: true,
+ },
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ failedJobs: [],
+ isActive: false,
+ isLoadingMore: false,
+ };
+ },
+ apollo: {
+ failedJobs: {
+ context() {
+ return getQueryHeaders(this.graphqlResourceEtag);
+ },
+ query: getPipelineFailedJobs,
+ pollInterval: POLL_INTERVAL,
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ pipelineIid: this.pipelineIid,
+ };
+ },
+ update(data) {
+ const jobs = data?.project?.pipeline?.jobs?.nodes || [];
+ return sortJobsByStatus(jobs);
+ },
+ result({ data }) {
+ const pipeline = data?.project?.pipeline;
+
+ if (pipeline?.jobs?.count) {
+ this.$emit('failed-jobs-count', pipeline.jobs.count);
+ this.isActive = pipeline.active;
+ }
+ },
+ error(e) {
+ createAlert({ message: e?.message || this.$options.i18n.fetchError, variant: 'danger' });
+ },
+ },
+ },
+ computed: {
+ graphqlResourceEtag() {
+ return graphqlEtagPipelinePath(this.graphqlPath, this.pipelineIid);
+ },
+ hasFailedJobs() {
+ return this.failedJobs.length > 0;
+ },
+ isInitialLoading() {
+ return this.isLoading && !this.isLoadingMore;
+ },
+ isLoading() {
+ return this.$apollo.queries.failedJobs.loading;
+ },
+ },
+ watch: {
+ isPipelineActive(flag) {
+ // Turn polling on and off based on REST actions
+ // By refetching jobs, we will get the graphql `active`
+ // field to update properly and cascade the polling changes
+ this.refetchJobs();
+ this.handlePolling(flag);
+ },
+ isActive(flag) {
+ this.handlePolling(flag);
+ },
+ failedJobsCount(count) {
+ // If the REST data is updated first, we force a refetch
+ // to keep them in sync
+ if (this.failedJobs.length !== count) {
+ this.$apollo.queries.failedJobs.refetch();
+ }
+ },
+ },
+ mounted() {
+ if (!this.isActive && !this.isPipelineActive) {
+ this.handlePolling(false);
+ }
+ },
+ methods: {
+ handlePolling(isActive) {
+ // If the pipeline status has changed and the widget is not expanded,
+ // We start polling.
+ if (isActive) {
+ this.$apollo.queries.failedJobs.startPolling(POLL_INTERVAL);
+ } else {
+ this.$apollo.queries.failedJobs.stopPolling();
+ }
+ },
+ async retryJob(jobName) {
+ await this.refetchJobs();
+
+ this.$toast.show(sprintf(this.$options.i18n.retriedJobsSuccess, { jobName }));
+ },
+ async refetchJobs() {
+ this.isLoadingMore = true;
+
+ try {
+ await this.$apollo.queries.failedJobs.refetch();
+ } catch {
+ createAlert(this.$options.i18n.fetchError);
+ } finally {
+ this.isLoadingMore = false;
+ }
+ },
+ },
+ columns: [
+ { text: JOB_NAME_HEADER, class: 'col-6' },
+ { text: STAGE_HEADER, class: 'col-2' },
+ { text: JOB_ID_HEADER, class: 'col-2' },
+ ],
+ i18n: {
+ fetchError: __('There was a problem fetching failed jobs'),
+ noFailedJobs: s__('Pipeline|No failed jobs in this pipeline 🎉'),
+ retriedJobsSuccess: __('%{jobName} job is being retried'),
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-loading-icon v-if="isInitialLoading" class="gl-p-4" />
+ <div v-else-if="!hasFailedJobs" class="gl-p-4">{{ $options.i18n.noFailedJobs }}</div>
+ <div v-else class="container-fluid gl-grid-tpl-rows-auto">
+ <div class="row gl-my-4 gl-text-gray-900">
+ <div
+ v-for="col in $options.columns"
+ :key="col.text"
+ class="gl-font-weight-bold gl-text-left"
+ :class="col.class"
+ data-testid="header"
+ >
+ {{ col.text }}
+ </div>
+ </div>
+ </div>
+ <failed-job-details
+ v-for="job in failedJobs"
+ :key="job.id"
+ :job="job"
+ @job-retried="retryJob"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue b/app/assets/javascripts/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue
new file mode 100644
index 00000000000..c01037e9791
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue
@@ -0,0 +1,121 @@
+<script>
+import { GlButton, GlCard, GlIcon, GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
+import { __, s__, sprintf } from '~/locale';
+import FailedJobsList from './failed_jobs_list.vue';
+
+export default {
+ components: {
+ GlButton,
+ GlCard,
+ GlIcon,
+ GlLink,
+ GlPopover,
+ GlSprintf,
+ FailedJobsList,
+ },
+ inject: ['fullPath'],
+ props: {
+ failedJobsCount: {
+ required: true,
+ type: Number,
+ },
+ isPipelineActive: {
+ required: true,
+ type: Boolean,
+ },
+ pipelineIid: {
+ required: true,
+ type: Number,
+ },
+ pipelinePath: {
+ required: true,
+ type: String,
+ },
+ projectPath: {
+ required: true,
+ type: String,
+ },
+ },
+ data() {
+ return {
+ currentFailedJobsCount: this.failedJobsCount,
+ isActive: false,
+ isExpanded: false,
+ };
+ },
+ computed: {
+ bodyClasses() {
+ return this.isExpanded ? '' : 'gl-display-none';
+ },
+ failedJobsCountText() {
+ return sprintf(this.$options.i18n.failedJobsLabel, { count: this.currentFailedJobsCount });
+ },
+ iconName() {
+ return this.isExpanded ? 'chevron-down' : 'chevron-right';
+ },
+ popoverId() {
+ return `popover-${this.pipelineIid}`;
+ },
+ },
+ watch: {
+ failedJobsCount(val) {
+ this.currentFailedJobsCount = val;
+ },
+ },
+ methods: {
+ setFailedJobsCount(count) {
+ this.currentFailedJobsCount = count;
+ },
+ toggleWidget() {
+ this.isExpanded = !this.isExpanded;
+ },
+ },
+ i18n: {
+ additionalInfoPopover: s__(
+ 'Pipelines|You will see a maximum of 100 jobs in this list. To view all failed jobs, %{linkStart}go to the details page%{linkEnd} of this pipeline.',
+ ),
+ additionalInfoTitle: __('Limitation on this view'),
+ failedJobsLabel: __('Failed jobs (%{count})'),
+ },
+};
+</script>
+<template>
+ <gl-card
+ class="gl-new-card"
+ :class="{ 'gl-border-white gl-hover-border-gray-100': !isExpanded }"
+ header-class="gl-new-card-header gl-px-3 gl-py-3"
+ body-class="gl-new-card-body"
+ data-testid="failed-jobs-card"
+ :aria-expanded="isExpanded.toString()"
+ >
+ <template #header>
+ <gl-button
+ variant="link"
+ class="gl-text-gray-500! gl-font-weight-semibold"
+ @click="toggleWidget"
+ >
+ <gl-icon :name="iconName" />
+ {{ failedJobsCountText }}
+ <gl-icon :id="popoverId" name="information-o" class="gl-ml-2" />
+ <gl-popover :target="popoverId" placement="top">
+ <template #title> {{ $options.i18n.additionalInfoTitle }} </template>
+ <slot>
+ <gl-sprintf :message="$options.i18n.additionalInfoPopover">
+ <template #link="{ content }">
+ <gl-link class="gl-font-sm" :href="pipelinePath">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </slot>
+ </gl-popover>
+ </gl-button>
+ </template>
+ <failed-jobs-list
+ v-if="isExpanded"
+ :failed-jobs-count="failedJobsCount"
+ :is-pipeline-active="isPipelineActive"
+ :pipeline-iid="pipelineIid"
+ :project-path="projectPath"
+ @failed-jobs-count="setFailedJobsCount"
+ />
+ </gl-card>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/failure_widget/utils.js b/app/assets/javascripts/ci/pipelines_page/components/failure_widget/utils.js
new file mode 100644
index 00000000000..3f395fff7e0
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/failure_widget/utils.js
@@ -0,0 +1,15 @@
+export const isFailedJob = (job = {}) => {
+ return job?.detailedStatus?.group === 'failed' || false;
+};
+
+export const sortJobsByStatus = (jobs = []) => {
+ const newJobs = [...jobs];
+
+ return newJobs.sort((a) => {
+ if (isFailedJob(a)) {
+ return -1;
+ }
+
+ return 1;
+ });
+};
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue b/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue
index 235126fea0c..235126fea0c 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue
new file mode 100644
index 00000000000..082ede60244
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue
@@ -0,0 +1,170 @@
+<script>
+import { GlLink, GlPopover, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { SCHEDULE_ORIGIN } from '~/ci/pipeline_details/constants';
+
+export default {
+ components: {
+ GlBadge,
+ GlLink,
+ GlPopover,
+ GlSprintf,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ inject: {
+ targetProjectFullPath: {
+ default: '',
+ },
+ },
+ props: {
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ pipelineScheduleUrl: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ isScheduled() {
+ return this.pipeline.source === SCHEDULE_ORIGIN;
+ },
+ isInFork() {
+ return Boolean(
+ this.targetProjectFullPath &&
+ this.pipeline?.project?.full_path !== `/${this.targetProjectFullPath}`,
+ );
+ },
+ autoDevopsTagId() {
+ return `pipeline-url-autodevops-${this.pipeline.id}`;
+ },
+ autoDevopsHelpPath() {
+ return helpPagePath('topics/autodevops/index.md');
+ },
+ },
+};
+</script>
+<template>
+ <div class="label-container gl-mt-1">
+ <gl-badge
+ v-if="isScheduled"
+ v-gl-tooltip
+ :href="pipelineScheduleUrl"
+ target="__blank"
+ :title="__('This pipeline was created by a schedule.')"
+ variant="info"
+ size="sm"
+ data-testid="pipeline-url-scheduled"
+ >{{ __('Scheduled') }}</gl-badge
+ >
+ <gl-badge
+ v-if="pipeline.flags.latest"
+ v-gl-tooltip
+ :title="__('Latest pipeline for the most recent commit on this branch')"
+ variant="success"
+ size="sm"
+ data-testid="pipeline-url-latest"
+ >{{ __('latest') }}</gl-badge
+ >
+ <gl-badge
+ v-if="pipeline.flags.merge_train_pipeline"
+ v-gl-tooltip
+ :title="
+ s__(
+ 'Pipeline|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch.',
+ )
+ "
+ variant="info"
+ size="sm"
+ data-testid="pipeline-url-train"
+ >{{ s__('Pipeline|merge train') }}</gl-badge
+ >
+ <gl-badge
+ v-if="pipeline.flags.yaml_errors"
+ v-gl-tooltip
+ :title="pipeline.yaml_errors"
+ variant="danger"
+ size="sm"
+ data-testid="pipeline-url-yaml"
+ >{{ __('yaml invalid') }}</gl-badge
+ >
+ <gl-badge
+ v-if="pipeline.flags.failure_reason"
+ v-gl-tooltip
+ :title="pipeline.failure_reason"
+ variant="danger"
+ size="sm"
+ data-testid="pipeline-url-failure"
+ >{{ __('error') }}</gl-badge
+ >
+ <template v-if="pipeline.flags.auto_devops">
+ <gl-link
+ :id="autoDevopsTagId"
+ tabindex="0"
+ data-testid="pipeline-url-autodevops"
+ role="button"
+ >
+ <gl-badge variant="info" size="sm">
+ {{ __('Auto DevOps') }}
+ </gl-badge>
+ </gl-link>
+ <gl-popover :target="autoDevopsTagId" triggers="focus" placement="top">
+ <template #title>
+ <div class="gl-font-weight-normal gl-line-height-normal">
+ <gl-sprintf
+ :message="
+ __(
+ 'This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}',
+ )
+ "
+ >
+ <template #strong="{ content }">
+ <b>{{ content }}</b>
+ </template>
+ </gl-sprintf>
+ </div>
+ </template>
+ <gl-link
+ :href="autoDevopsHelpPath"
+ data-testid="pipeline-url-autodevops-link"
+ target="_blank"
+ >
+ {{ __('Learn more about Auto DevOps') }}
+ </gl-link>
+ </gl-popover>
+ </template>
+
+ <gl-badge
+ v-if="pipeline.flags.stuck"
+ variant="warning"
+ size="sm"
+ data-testid="pipeline-url-stuck"
+ >{{ __('stuck') }}</gl-badge
+ >
+ <gl-badge
+ v-if="pipeline.flags.detached_merge_request_pipeline"
+ v-gl-tooltip
+ :title="
+ s__(
+ `Pipeline|This pipeline ran on the contents of this merge request's source branch, not the target branch.`,
+ )
+ "
+ variant="info"
+ size="sm"
+ data-testid="pipeline-url-detached"
+ >{{ s__('Pipeline|merge request') }}</gl-badge
+ >
+ <gl-badge
+ v-if="isInFork"
+ v-gl-tooltip
+ :title="__('Pipeline ran in fork of project')"
+ variant="info"
+ size="sm"
+ data-testid="pipeline-url-fork"
+ >{{ __('fork') }}</gl-badge
+ >
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_multi_actions.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_multi_actions.vue
new file mode 100644
index 00000000000..78acead95f4
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_multi_actions.vue
@@ -0,0 +1,189 @@
+<script>
+import {
+ GlAlert,
+ GlDisclosureDropdown,
+ GlSearchBoxByType,
+ GlLoadingIcon,
+ GlTooltipDirective,
+} from '@gitlab/ui';
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
+import axios from '~/lib/utils/axios_utils';
+import { __, s__ } from '~/locale';
+import Tracking from '~/tracking';
+import { TRACKING_CATEGORIES } from '../../constants';
+
+export const i18n = {
+ searchPlaceholder: __('Search artifacts'),
+ downloadArtifacts: __('Download artifacts'),
+ artifactsFetchErrorMessage: s__('Pipelines|Could not load artifacts.'),
+ artifactsFetchWarningMessage: s__(
+ 'Pipelines|Failed to update. Please reload page to update the list of artifacts.',
+ ),
+ emptyArtifactsMessage: __('No artifacts found'),
+};
+
+export default {
+ i18n,
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ GlAlert,
+ GlDisclosureDropdown,
+ GlSearchBoxByType,
+ GlLoadingIcon,
+ },
+ mixins: [Tracking.mixin()],
+ inject: {
+ artifactsEndpoint: {
+ default: '',
+ },
+ artifactsEndpointPlaceholder: {
+ default: '',
+ },
+ },
+ props: {
+ pipelineId: {
+ type: Number,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ artifacts: [],
+ hasError: false,
+ isLoading: false,
+ searchQuery: '',
+ isNewPipeline: false,
+ };
+ },
+ computed: {
+ hasArtifacts() {
+ return this.artifacts.length > 0;
+ },
+ filteredArtifacts() {
+ return this.searchQuery.length > 0
+ ? fuzzaldrinPlus.filter(this.artifacts, this.searchQuery, { key: 'name' })
+ : this.artifacts;
+ },
+ items() {
+ return this.filteredArtifacts.map(({ name, path }) => ({
+ text: name,
+ href: path,
+ extraAttrs: {
+ download: '',
+ rel: 'nofollow',
+ 'data-testid': 'artifact-item',
+ },
+ }));
+ },
+ },
+ watch: {
+ pipelineId() {
+ this.isNewPipeline = true;
+ },
+ },
+ methods: {
+ fetchArtifacts() {
+ // refactor tracking based on action once this dropdown supports
+ // actions other than artifacts
+ this.track('click_artifacts_dropdown', { label: TRACKING_CATEGORIES.table });
+
+ // Preserve the last good list and present it if a request fails
+ const oldArtifacts = [...this.artifacts];
+ this.artifacts = [];
+
+ this.hasError = false;
+ this.isLoading = true;
+
+ // Replace the placeholder with the ID of the pipeline we are viewing
+ const endpoint = this.artifactsEndpoint.replace(
+ this.artifactsEndpointPlaceholder,
+ this.pipelineId,
+ );
+ return axios
+ .get(endpoint)
+ .then(({ data }) => {
+ this.artifacts = data.artifacts;
+ this.isNewPipeline = false;
+ })
+ .catch(() => {
+ this.hasError = true;
+ if (!this.isNewPipeline) {
+ this.artifacts = oldArtifacts;
+ }
+ })
+ .finally(() => {
+ this.isLoading = false;
+ });
+ },
+ onDisclosureDropdownShown() {
+ this.fetchArtifacts();
+ },
+ onDisclosureDropdownHidden() {
+ this.searchQuery = '';
+ },
+ },
+};
+</script>
+<template>
+ <gl-disclosure-dropdown
+ v-gl-tooltip
+ class="gl-text-left"
+ :title="$options.i18n.downloadArtifacts"
+ :toggle-text="$options.i18n.downloadArtifacts"
+ :aria-label="$options.i18n.downloadArtifacts"
+ :items="items"
+ icon="download"
+ placement="right"
+ text-sr-only
+ data-testid="pipeline-multi-actions-dropdown"
+ @shown="onDisclosureDropdownShown"
+ @hidden="onDisclosureDropdownHidden"
+ >
+ <template #header>
+ <div
+ aria-hidden="true"
+ class="gl-display-flex gl-align-items-center gl-p-4! gl-min-h-8 gl-font-sm gl-font-weight-bold gl-text-gray-900 gl-border-b-1 gl-border-b-solid gl-border-b-gray-200"
+ >
+ {{ $options.i18n.downloadArtifacts }}
+ </div>
+ <div v-if="hasArtifacts" class="gl-border-b-1 gl-border-b-solid gl-border-b-gray-200">
+ <gl-search-box-by-type
+ ref="searchInput"
+ v-model.trim="searchQuery"
+ :placeholder="$options.i18n.searchPlaceholder"
+ borderless
+ autofocus
+ />
+ </div>
+ <gl-alert
+ v-if="hasError && !hasArtifacts"
+ variant="danger"
+ :dismissible="false"
+ data-testid="artifacts-fetch-error"
+ >
+ {{ $options.i18n.artifactsFetchErrorMessage }}
+ </gl-alert>
+ </template>
+
+ <gl-loading-icon v-if="isLoading" class="gl-m-3" size="sm" />
+ <p
+ v-else-if="filteredArtifacts.length === 0"
+ class="gl-px-4 gl-py-3 gl-m-0 gl-text-gray-600"
+ data-testid="artifacts-empty-message"
+ >
+ {{ $options.i18n.emptyArtifactsMessage }}
+ </p>
+
+ <template #footer>
+ <p
+ v-if="hasError && hasArtifacts"
+ class="gl-font-sm gl-text-secondary gl-py-4 gl-px-5 gl-mb-0 gl-border-t"
+ data-testid="artifacts-fetch-warning"
+ >
+ {{ $options.i18n.artifactsFetchWarningMessage }}
+ </p>
+ </template>
+ </gl-disclosure-dropdown>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue
new file mode 100644
index 00000000000..b05bdae65c4
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue
@@ -0,0 +1,113 @@
+<script>
+import { GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui';
+import Tracking from '~/tracking';
+import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL, TRACKING_CATEGORIES } from '~/ci/constants';
+import eventHub from '../../event_hub';
+import PipelineMultiActions from './pipeline_multi_actions.vue';
+import PipelinesManualActions from './pipelines_manual_actions.vue';
+
+export default {
+ BUTTON_TOOLTIP_RETRY,
+ BUTTON_TOOLTIP_CANCEL,
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ GlModalDirective,
+ },
+ components: {
+ GlButton,
+ PipelineMultiActions,
+ PipelinesManualActions,
+ },
+ mixins: [Tracking.mixin()],
+ props: {
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ cancelingPipeline: {
+ type: Number,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ isRetrying: false,
+ };
+ },
+ computed: {
+ hasActions() {
+ return (
+ this.pipeline?.details?.has_manual_actions || this.pipeline?.details?.has_scheduled_actions
+ );
+ },
+ isCancelling() {
+ return this.cancelingPipeline === this.pipeline.id;
+ },
+ },
+ watch: {
+ pipeline() {
+ this.isRetrying = false;
+ },
+ },
+ methods: {
+ handleCancelClick() {
+ this.trackClick('click_cancel_button');
+ eventHub.$emit('openConfirmationModal', {
+ pipeline: this.pipeline,
+ endpoint: this.pipeline.cancel_path,
+ });
+ },
+ handleRetryClick() {
+ this.isRetrying = true;
+ this.trackClick('click_retry_button');
+ eventHub.$emit('retryPipeline', this.pipeline.retry_path);
+ },
+ trackClick(action) {
+ this.track(action, { label: TRACKING_CATEGORIES.table });
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-text-right">
+ <div class="btn-group">
+ <pipelines-manual-actions v-if="hasActions" :iid="pipeline.iid" />
+
+ <gl-button
+ v-if="pipeline.flags.retryable"
+ v-gl-tooltip.hover
+ :aria-label="$options.BUTTON_TOOLTIP_RETRY"
+ :title="$options.BUTTON_TOOLTIP_RETRY"
+ :disabled="isRetrying"
+ :loading="isRetrying"
+ class="js-pipelines-retry-button"
+ data-qa-selector="pipeline_retry_button"
+ data-testid="pipelines-retry-button"
+ icon="retry"
+ variant="default"
+ category="secondary"
+ @click="handleRetryClick"
+ />
+
+ <gl-button
+ v-if="pipeline.flags.cancelable"
+ v-gl-tooltip.hover
+ v-gl-modal-directive="'confirmation-modal'"
+ :aria-label="$options.BUTTON_TOOLTIP_CANCEL"
+ :title="$options.BUTTON_TOOLTIP_CANCEL"
+ :loading="isCancelling"
+ :disabled="isCancelling"
+ icon="cancel"
+ variant="danger"
+ category="primary"
+ class="js-pipelines-cancel-button gl-ml-1"
+ data-testid="pipelines-cancel-button"
+ @click="handleCancelClick"
+ />
+
+ <pipeline-multi-actions :pipeline-id="pipeline.id" />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue
index 9f38be668f2..9f38be668f2 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_triggerer.vue
index 2a73795db0a..2a73795db0a 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_triggerer.vue
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue
new file mode 100644
index 00000000000..edaeb481d7b
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue
@@ -0,0 +1,242 @@
+<script>
+import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
+import { __ } from '~/locale';
+import Tracking from '~/tracking';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import { ICONS, TRACKING_CATEGORIES } from '~/ci/constants';
+import PipelineLabels from './pipeline_labels.vue';
+
+export default {
+ components: {
+ GlIcon,
+ GlLink,
+ PipelineLabels,
+ TooltipOnTruncate,
+ UserAvatarLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [Tracking.mixin()],
+ props: {
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ pipelineScheduleUrl: {
+ type: String,
+ required: true,
+ },
+ pipelineKey: {
+ type: String,
+ required: true,
+ },
+ refClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ mergeRequestRef() {
+ return this.pipeline?.merge_request;
+ },
+ commitRef() {
+ return this.pipeline?.ref;
+ },
+ commitTag() {
+ return this.commitRef?.tag;
+ },
+ commitUrl() {
+ return this.pipeline?.commit?.commit_path;
+ },
+ commitShortSha() {
+ return this.pipeline?.commit?.short_id;
+ },
+ refUrl() {
+ return this.commitRef?.ref_url || this.commitRef?.path;
+ },
+ tooltipTitle() {
+ return this.mergeRequestRef?.title || this.commitRef?.name;
+ },
+ commitAuthor() {
+ let commitAuthorInformation;
+ const pipelineCommit = this.pipeline?.commit;
+ const pipelineCommitAuthor = pipelineCommit?.author;
+
+ if (!pipelineCommit) {
+ return null;
+ }
+
+ // 1. person who is an author of a commit might be a GitLab user
+ if (pipelineCommitAuthor) {
+ // 2. if person who is an author of a commit is a GitLab user
+ // they can have a GitLab avatar
+ if (pipelineCommitAuthor?.avatar_url) {
+ commitAuthorInformation = pipelineCommitAuthor;
+
+ // 3. If GitLab user does not have avatar, they might have a Gravatar
+ } else if (pipelineCommit.author_gravatar_url) {
+ commitAuthorInformation = {
+ ...pipelineCommitAuthor,
+ avatar_url: pipelineCommit.author_gravatar_url,
+ };
+ }
+ // 4. If committer is not a GitLab User, they can have a Gravatar
+ } else {
+ commitAuthorInformation = {
+ avatar_url: pipelineCommit.author_gravatar_url,
+ path: `mailto:${pipelineCommit.author_email}`,
+ username: pipelineCommit.author_name,
+ };
+ }
+
+ return commitAuthorInformation;
+ },
+ commitIcon() {
+ let name = '';
+
+ if (this.commitTag) {
+ name = ICONS.TAG;
+ } else if (this.mergeRequestRef) {
+ name = ICONS.MR;
+ } else {
+ name = ICONS.BRANCH;
+ }
+
+ return name;
+ },
+ commitIconTooltipTitle() {
+ switch (this.commitIcon) {
+ case ICONS.TAG:
+ return __('Tag');
+ case ICONS.MR:
+ return __('Merge Request');
+ default:
+ return __('Branch');
+ }
+ },
+ commitTitle() {
+ return this.pipeline?.commit?.title;
+ },
+ pipelineName() {
+ return this.pipeline?.name;
+ },
+ },
+ methods: {
+ trackClick(action) {
+ this.track(action, { label: TRACKING_CATEGORIES.table });
+ },
+ },
+};
+</script>
+<template>
+ <div class="pipeline-tags" data-testid="pipeline-url-table-cell">
+ <div v-if="pipelineName" class="gl-mb-2" data-testid="pipeline-name-container">
+ <span class="gl-display-flex">
+ <tooltip-on-truncate
+ :title="pipelineName"
+ class="gl-flex-grow-1 gl-text-truncate gl-text-gray-900"
+ >
+ <gl-link
+ :href="pipeline.path"
+ class="gl-text-blue-600!"
+ data-testid="pipeline-url-link"
+ >{{ pipelineName }}</gl-link
+ >
+ </tooltip-on-truncate>
+ </span>
+ </div>
+
+ <div v-if="!pipelineName" class="commit-title gl-mb-2" data-testid="commit-title-container">
+ <span v-if="commitTitle" class="gl-display-flex">
+ <tooltip-on-truncate
+ :title="commitTitle"
+ class="gl-flex-grow-1 gl-text-truncate gl-p-3 gl-ml-n3 gl-mr-n3 gl-mt-n3 gl-mb-n3"
+ >
+ <gl-link
+ :href="commitUrl"
+ class="commit-row-message gl-text-blue-600!"
+ data-testid="commit-title"
+ @click="trackClick('click_commit_title')"
+ >{{ commitTitle }}</gl-link
+ >
+ </tooltip-on-truncate>
+ </span>
+ <span v-else class="gl-text-gray-500">{{
+ __("Can't find HEAD commit for this branch")
+ }}</span>
+ </div>
+ <div class="gl-mb-2">
+ <gl-link
+ :href="pipeline.path"
+ class="gl-mr-1 gl-text-blue-500!"
+ data-testid="pipeline-url-link"
+ data-qa-selector="pipeline_url_link"
+ @click="trackClick('click_pipeline_id')"
+ >#{{ pipeline[pipelineKey] }}</gl-link
+ >
+ <!--Commit row-->
+ <div class="gl-display-inline-flex gl-rounded-base gl-px-2 gl-bg-gray-50 gl-text-gray-700">
+ <tooltip-on-truncate :title="tooltipTitle" truncate-target="child" placement="top">
+ <gl-icon
+ v-gl-tooltip
+ :name="commitIcon"
+ :title="commitIconTooltipTitle"
+ :size="12"
+ data-testid="commit-icon-type"
+ />
+ <gl-link
+ v-if="mergeRequestRef"
+ :href="mergeRequestRef.path"
+ class="gl-font-sm gl-font-monospace gl-text-gray-700! gl-hover-text-gray-900!"
+ :class="refClass"
+ data-testid="merge-request-ref"
+ @click="trackClick('click_mr_ref')"
+ >{{ mergeRequestRef.iid }}</gl-link
+ >
+ <gl-link
+ v-else
+ :href="refUrl"
+ class="gl-font-sm gl-font-monospace gl-text-gray-700! gl-hover-text-gray-900!"
+ :class="refClass"
+ data-testid="commit-ref-name"
+ @click="trackClick('click_commit_name')"
+ >{{ commitRef.name }}</gl-link
+ >
+ </tooltip-on-truncate>
+ </div>
+ <div
+ class="gl-display-inline-block gl-rounded-base gl-font-sm gl-px-2 gl-bg-gray-50 gl-text-black-normal"
+ >
+ <gl-icon
+ v-gl-tooltip
+ name="commit"
+ class="commit-icon gl-mr-1"
+ :title="__('Commit')"
+ :size="12"
+ data-testid="commit-icon"
+ />
+ <gl-link
+ :href="commitUrl"
+ class="gl-font-sm gl-font-monospace gl-mr-0 gl-text-gray-700!"
+ data-testid="commit-short-sha"
+ @click="trackClick('click_commit_sha')"
+ >{{ commitShortSha }}</gl-link
+ >
+ </div>
+ <user-avatar-link
+ v-if="commitAuthor"
+ :link-href="commitAuthor.path"
+ :img-src="commitAuthor.avatar_url"
+ :img-size="16"
+ :img-alt="commitAuthor.name"
+ :tooltip-text="commitAuthor.name"
+ class="gl-ml-1"
+ />
+ <!--End of commit row-->
+ </div>
+ <pipeline-labels :pipeline-schedule-url="pipelineScheduleUrl" :pipeline="pipeline" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipelines_artifacts.vue b/app/assets/javascripts/ci/pipelines_page/components/pipelines_artifacts.vue
new file mode 100644
index 00000000000..3021b4a2ef8
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipelines_artifacts.vue
@@ -0,0 +1,72 @@
+<script>
+import { GlDisclosureDropdown, GlTooltipDirective } from '@gitlab/ui';
+import { __ } from '~/locale';
+
+export const i18n = {
+ artifacts: __('Artifacts'),
+ artifactSectionHeader: __('Download artifacts'),
+};
+
+export default {
+ i18n,
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ GlDisclosureDropdown,
+ },
+ inject: {
+ artifactsEndpoint: {
+ default: '',
+ },
+ artifactsEndpointPlaceholder: {
+ default: '',
+ },
+ },
+ props: {
+ pipelineId: {
+ type: Number,
+ required: true,
+ },
+ artifacts: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ computed: {
+ items() {
+ return [
+ {
+ name: this.$options.i18n.artifactSectionHeader,
+ items: this.artifacts.map(({ name, path }) => ({
+ text: name,
+ href: path,
+ extraAttrs: {
+ download: '',
+ rel: 'nofollow',
+ },
+ })),
+ },
+ ];
+ },
+ shouldShowDropdown() {
+ return this.artifacts?.length;
+ },
+ },
+};
+</script>
+<template>
+ <gl-disclosure-dropdown
+ v-if="shouldShowDropdown"
+ v-gl-tooltip
+ class="gl-text-left"
+ :title="$options.i18n.artifacts"
+ :toggle-text="$options.i18n.artifacts"
+ :aria-label="$options.i18n.artifacts"
+ icon="download"
+ placement="right"
+ text-sr-only
+ :items="items"
+ />
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipelines_filtered_search.vue b/app/assets/javascripts/ci/pipelines_page/components/pipelines_filtered_search.vue
new file mode 100644
index 00000000000..6aadb6b73c8
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipelines_filtered_search.vue
@@ -0,0 +1,130 @@
+<script>
+import { GlFilteredSearch } from '@gitlab/ui';
+import { map } from 'lodash';
+import { s__ } from '~/locale';
+import Tracking from '~/tracking';
+import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
+import { TRACKING_CATEGORIES } from '../../constants';
+import PipelineBranchNameToken from '../tokens/pipeline_branch_name_token.vue';
+import PipelineSourceToken from '../tokens/pipeline_source_token.vue';
+import PipelineStatusToken from '../tokens/pipeline_status_token.vue';
+import PipelineTagNameToken from '../tokens/pipeline_tag_name_token.vue';
+import PipelineTriggerAuthorToken from '../tokens/pipeline_trigger_author_token.vue';
+
+export default {
+ userType: 'username',
+ branchType: 'ref',
+ tagType: 'tag',
+ statusType: 'status',
+ sourceType: 'source',
+ defaultTokensLength: 1,
+ components: {
+ GlFilteredSearch,
+ },
+ mixins: [Tracking.mixin()],
+ props: {
+ projectId: {
+ type: String,
+ required: true,
+ },
+ defaultBranchName: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ params: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ internalValue: [],
+ };
+ },
+ computed: {
+ selectedTypes() {
+ return this.value.map((i) => i.type);
+ },
+ tokens() {
+ return [
+ {
+ type: this.$options.userType,
+ icon: 'user',
+ title: s__('Pipeline|Trigger author'),
+ unique: true,
+ token: PipelineTriggerAuthorToken,
+ operators: OPERATORS_IS,
+ projectId: this.projectId,
+ },
+ {
+ type: this.$options.branchType,
+ icon: 'branch',
+ title: s__('Pipeline|Branch name'),
+ unique: true,
+ token: PipelineBranchNameToken,
+ operators: OPERATORS_IS,
+ projectId: this.projectId,
+ defaultBranchName: this.defaultBranchName,
+ disabled: this.selectedTypes.includes(this.$options.tagType),
+ },
+ {
+ type: this.$options.tagType,
+ icon: 'tag',
+ title: s__('Pipeline|Tag name'),
+ unique: true,
+ token: PipelineTagNameToken,
+ operators: OPERATORS_IS,
+ projectId: this.projectId,
+ disabled: this.selectedTypes.includes(this.$options.branchType),
+ },
+ {
+ type: this.$options.statusType,
+ icon: 'status',
+ title: s__('Pipeline|Status'),
+ unique: true,
+ token: PipelineStatusToken,
+ operators: OPERATORS_IS,
+ },
+ {
+ type: this.$options.sourceType,
+ icon: 'trigger-source',
+ title: s__('Pipeline|Source'),
+ unique: true,
+ token: PipelineSourceToken,
+ operators: OPERATORS_IS,
+ },
+ ];
+ },
+ parsedParams() {
+ return map(this.params, (val, key) => ({
+ type: key,
+ value: { data: val, operator: '=' },
+ }));
+ },
+ value: {
+ get() {
+ return this.internalValue.length > 0 ? this.internalValue : this.parsedParams;
+ },
+ set(value) {
+ this.internalValue = value;
+ },
+ },
+ },
+ methods: {
+ onSubmit(filters) {
+ this.track('click_filtered_search', { label: TRACKING_CATEGORIES.search });
+ this.$emit('filterPipelines', filters);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-filtered-search
+ v-model="value"
+ :placeholder="__('Filter pipelines')"
+ :available-tokens="tokens"
+ @submit="onSubmit"
+ />
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue b/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue
new file mode 100644
index 00000000000..4dacd474bde
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue
@@ -0,0 +1,159 @@
+<script>
+import { GlDropdown, GlDropdownItem, GlIcon, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
+import { s__, __, sprintf } from '~/locale';
+import Tracking from '~/tracking';
+import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
+import eventHub from '../../event_hub';
+import { TRACKING_CATEGORIES } from '../../constants';
+import getPipelineActionsQuery from '../graphql/queries/get_pipeline_actions.query.graphql';
+
+export default {
+ name: 'PipelinesManualActions',
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ GlCountdown,
+ GlDropdown,
+ GlDropdownItem,
+ GlIcon,
+ GlLoadingIcon,
+ },
+ mixins: [Tracking.mixin()],
+ inject: ['fullPath', 'manualActionsLimit'],
+ props: {
+ iid: {
+ type: Number,
+ required: true,
+ },
+ },
+ apollo: {
+ actions: {
+ query: getPipelineActionsQuery,
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ iid: this.iid,
+ limit: this.manualActionsLimit,
+ };
+ },
+ skip() {
+ return !this.hasDropdownBeenShown;
+ },
+ update({ project }) {
+ return project?.pipeline?.jobs?.nodes || [];
+ },
+ },
+ },
+ data() {
+ return {
+ isLoading: false,
+ actions: [],
+ hasDropdownBeenShown: false,
+ };
+ },
+ computed: {
+ isActionsLoading() {
+ return this.$apollo.queries.actions.loading;
+ },
+ isDropdownLimitReached() {
+ return this.actions.length === this.manualActionsLimit;
+ },
+ },
+ methods: {
+ async onClickAction(action) {
+ if (action.scheduledAt) {
+ const confirmationMessage = sprintf(
+ s__(
+ 'DelayedJobs|Are you sure you want to run %{jobName} immediately? Otherwise this job will run automatically after its timer finishes.',
+ ),
+ { jobName: action.name },
+ );
+
+ const confirmed = await confirmAction(confirmationMessage);
+
+ if (!confirmed) {
+ return;
+ }
+ }
+
+ this.isLoading = true;
+
+ /**
+ * Ideally, the component would not make an api call directly.
+ * However, in order to use the eventhub and know when to
+ * toggle back the `isLoading` property we'd need an ID
+ * to track the request with a watcher - since this component
+ * is rendered at least 20 times in the same page, moving the
+ * api call directly here is the most performant solution
+ */
+ axios
+ .post(`${action.playPath}.json`)
+ .then(() => {
+ this.isLoading = false;
+ eventHub.$emit('updateTable');
+ })
+ .catch(() => {
+ this.isLoading = false;
+ createAlert({ message: __('An error occurred while making the request.') });
+ });
+ },
+ fetchActions() {
+ this.hasDropdownBeenShown = true;
+
+ this.$apollo.queries.actions.refetch();
+
+ this.trackClick();
+ },
+ trackClick() {
+ this.track('click_manual_actions', { label: TRACKING_CATEGORIES.table });
+ },
+ },
+};
+</script>
+<template>
+ <gl-dropdown
+ v-gl-tooltip
+ :title="__('Run manual or delayed jobs')"
+ :loading="isLoading"
+ data-testid="pipelines-manual-actions-dropdown"
+ right
+ lazy
+ icon="play"
+ @shown="fetchActions"
+ >
+ <gl-dropdown-item v-if="isActionsLoading">
+ <div class="gl-display-flex">
+ <gl-loading-icon class="mr-2" />
+ <span>{{ __('Loading...') }}</span>
+ </div>
+ </gl-dropdown-item>
+
+ <gl-dropdown-item
+ v-for="action in actions"
+ v-else
+ :key="action.id"
+ :disabled="!action.canPlayJob"
+ @click="onClickAction(action)"
+ >
+ <div class="gl-display-flex gl-justify-content-space-between gl-flex-wrap">
+ {{ action.name }}
+ <span v-if="action.scheduledAt">
+ <gl-icon name="clock" />
+ <gl-countdown :end-date-string="action.scheduledAt" />
+ </span>
+ </div>
+ </gl-dropdown-item>
+
+ <template #footer>
+ <gl-dropdown-item v-if="isDropdownLimitReached">
+ <span class="gl-font-sm gl-text-gray-300!" data-testid="limit-reached-msg">
+ {{ __('Showing first 50 actions.') }}
+ </span>
+ </gl-dropdown-item>
+ </template>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipelines_status_badge.vue b/app/assets/javascripts/ci/pipelines_page/components/pipelines_status_badge.vue
new file mode 100644
index 00000000000..2da9141df8e
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipelines_status_badge.vue
@@ -0,0 +1,51 @@
+<script>
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+import { CHILD_VIEW } from '~/ci/pipeline_details/constants';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import Tracking from '~/tracking';
+import PipelinesTimeago from './time_ago.vue';
+
+export default {
+ components: {
+ CiBadgeLink,
+ PipelinesTimeago,
+ },
+ mixins: [Tracking.mixin()],
+ props: {
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ viewType: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ pipelineStatus() {
+ return this.pipeline?.details?.status ?? {};
+ },
+ isChildView() {
+ return this.viewType === CHILD_VIEW;
+ },
+ },
+ methods: {
+ trackClick() {
+ this.track('click_ci_status_badge', { label: TRACKING_CATEGORIES.table });
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <ci-badge-link
+ class="gl-mb-3"
+ :status="pipelineStatus"
+ :show-text="!isChildView"
+ data-qa-selector="pipeline_commit_status"
+ @ciStatusBadgeClick="trackClick"
+ />
+ <pipelines-timeago :pipeline="pipeline" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue b/app/assets/javascripts/ci/pipelines_page/components/time_ago.vue
index 70343544638..70343544638 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/time_ago.vue
diff --git a/app/assets/javascripts/ci/pipelines_page/constants.js b/app/assets/javascripts/ci/pipelines_page/constants.js
new file mode 100644
index 00000000000..aa6ef8a25ee
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/constants.js
@@ -0,0 +1,2 @@
+export const ANY_TRIGGER_AUTHOR = 'Any';
+export const FILTER_PIPELINES_SEARCH_DELAY = 200;
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_actions.query.graphql b/app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_actions.query.graphql
index d1878c01e91..d1878c01e91 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_actions.query.graphql
+++ b/app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_actions.query.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_failed_jobs.query.graphql b/app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_failed_jobs.query.graphql
index 6b553866f63..6b553866f63 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_failed_jobs.query.graphql
+++ b/app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_failed_jobs.query.graphql
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_failed_jobs_count.query.graphql b/app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_failed_jobs_count.query.graphql
index b70e95deab6..b70e95deab6 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_failed_jobs_count.query.graphql
+++ b/app/assets/javascripts/ci/pipelines_page/graphql/queries/get_pipeline_failed_jobs_count.query.graphql
diff --git a/app/assets/javascripts/ci/pipelines_page/pipelines.vue b/app/assets/javascripts/ci/pipelines_page/pipelines.vue
new file mode 100644
index 00000000000..87ee5463bb0
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/pipelines.vue
@@ -0,0 +1,450 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<script>
+import { GlEmptyState, GlIcon, GlLoadingIcon, GlCollapsibleListbox } from '@gitlab/ui';
+import { isEqual } from 'lodash';
+import * as Sentry from '@sentry/browser';
+import { createAlert, VARIANT_INFO, VARIANT_WARNING } from '~/alert';
+import { getParameterByName } from '~/lib/utils/url_utility';
+import { __, s__ } from '~/locale';
+import Tracking from '~/tracking';
+import {
+ FILTER_TAG_IDENTIFIER,
+ PipelineKeyOptions,
+ RAW_TEXT_WARNING,
+ TRACKING_CATEGORIES,
+} from '~/ci/constants';
+import PipelinesTableComponent from '~/ci/common/pipelines_table.vue';
+import PipelinesMixin from '~/ci/pipeline_details/mixins/pipelines_mixin';
+import { validateParams } from '~/ci/pipeline_details/utils';
+import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
+import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
+import { isLoggedIn } from '~/lib/utils/common_utils';
+import setSortPreferenceMutation from '~/issues/list/queries/set_sort_preference.mutation.graphql';
+import PipelinesService from './services/pipelines_service';
+import { ANY_TRIGGER_AUTHOR } from './constants';
+import NoCiEmptyState from './components/empty_state/no_ci_empty_state.vue';
+import NavigationControls from './components/nav_controls.vue';
+import PipelinesFilteredSearch from './components/pipelines_filtered_search.vue';
+
+export default {
+ PipelineKeyOptions,
+ components: {
+ NoCiEmptyState,
+ GlCollapsibleListbox,
+ GlEmptyState,
+ GlIcon,
+ GlLoadingIcon,
+ NavigationTabs,
+ NavigationControls,
+ PipelinesFilteredSearch,
+ PipelinesTableComponent,
+ TablePagination,
+ },
+ mixins: [PipelinesMixin, Tracking.mixin()],
+ props: {
+ store: {
+ type: Object,
+ required: true,
+ },
+ // Can be rendered in 3 different places, with some visual differences
+ // Accepts root | child
+ // `root` -> main view
+ // `child` -> rendered inside MR or Commit View
+ viewType: {
+ type: String,
+ required: false,
+ default: 'root',
+ },
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ pipelineScheduleUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ emptyStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ errorStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ noPipelinesSvgPath: {
+ type: String,
+ required: true,
+ },
+ hasGitlabCi: {
+ type: Boolean,
+ required: true,
+ },
+ canCreatePipeline: {
+ type: Boolean,
+ required: true,
+ },
+ ciLintPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ resetCachePath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ newPipelinePath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ projectId: {
+ type: String,
+ required: true,
+ },
+ defaultBranchName: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ params: {
+ type: Object,
+ required: true,
+ },
+ registrationToken: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ defaultVisibilityPipelineIdType: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ // Start with loading state to avoid a glitch when the empty state will be rendered
+ isLoading: true,
+ state: this.store.state,
+ scope: getParameterByName('scope') || 'all',
+ page: getParameterByName('page') || '1',
+ requestData: {},
+ isResetCacheButtonLoading: false,
+ visibilityPipelineIdType: this.defaultVisibilityPipelineIdType,
+ };
+ },
+ stateMap: {
+ // with tabs
+ loading: 'loading',
+ tableList: 'tableList',
+ error: 'error',
+ emptyTab: 'emptyTab',
+
+ // without tabs
+ emptyState: 'emptyState',
+ },
+ scopes: {
+ all: 'all',
+ finished: 'finished',
+ branches: 'branches',
+ tags: 'tags',
+ },
+ computed: {
+ /**
+ * `hasGitlabCi` handles both internal and external CI.
+ * The order on which the checks are made in this method is
+ * important to guarantee we handle all the corner cases.
+ */
+ stateToRender() {
+ const { stateMap } = this.$options;
+
+ if (this.isLoading) {
+ return stateMap.loading;
+ }
+
+ if (this.hasError) {
+ return stateMap.error;
+ }
+
+ if (this.state.pipelines.length) {
+ return stateMap.tableList;
+ }
+
+ if ((this.scope !== 'all' && this.scope !== null) || this.hasGitlabCi) {
+ return stateMap.emptyTab;
+ }
+
+ return stateMap.emptyState;
+ },
+ /**
+ * Tabs are rendered in all states except empty state.
+ * They are not rendered before the first request to avoid a flicker on first load.
+ */
+ shouldRenderTabs() {
+ const { stateMap } = this.$options;
+ return (
+ this.hasMadeRequest &&
+ [stateMap.loading, stateMap.tableList, stateMap.error, stateMap.emptyTab].includes(
+ this.stateToRender,
+ )
+ );
+ },
+
+ shouldRenderButtons() {
+ return (
+ (this.newPipelinePath || this.resetCachePath || this.ciLintPath) && this.shouldRenderTabs
+ );
+ },
+
+ shouldRenderPagination() {
+ return !this.isLoading && !this.hasError;
+ },
+
+ emptyTabMessage() {
+ if (this.scope === this.$options.scopes.finished) {
+ return s__('Pipelines|There are currently no finished pipelines.');
+ }
+
+ return s__('Pipelines|There are currently no pipelines.');
+ },
+
+ tabs() {
+ const { count } = this.state;
+ const { scopes } = this.$options;
+
+ return [
+ {
+ name: __('All'),
+ scope: scopes.all,
+ count: count.all,
+ isActive: this.scope === 'all',
+ },
+ {
+ name: __('Finished'),
+ scope: scopes.finished,
+ isActive: this.scope === 'finished',
+ },
+ {
+ name: __('Branches'),
+ scope: scopes.branches,
+ isActive: this.scope === 'branches',
+ },
+ {
+ name: __('Tags'),
+ scope: scopes.tags,
+ isActive: this.scope === 'tags',
+ },
+ ];
+ },
+ validatedParams() {
+ return validateParams(this.params);
+ },
+ selectedPipelineKeyOption() {
+ return (
+ this.$options.PipelineKeyOptions.find((e) => this.visibilityPipelineIdType === e.value) ||
+ this.$options.PipelineKeyOptions[0]
+ );
+ },
+ },
+ created() {
+ this.service = new PipelinesService(this.endpoint);
+ this.requestData = { page: this.page, scope: this.scope, ...this.validatedParams };
+ },
+ methods: {
+ onChangeTab(scope) {
+ if (this.scope === scope) {
+ return;
+ }
+
+ let params = {
+ scope,
+ page: '1',
+ };
+
+ params = this.onChangeWithFilter(params);
+
+ this.updateContent(params);
+
+ this.track('click_filter_tabs', { label: TRACKING_CATEGORIES.tabs, property: scope });
+ },
+ successCallback(resp) {
+ // Because we are polling & the user is interacting verify if the response received
+ // matches the last request made
+ if (isEqual(resp.config.params, this.requestData)) {
+ this.store.storeCount(resp.data.count);
+ this.store.storePagination(resp.headers);
+ this.setCommonData(resp.data.pipelines);
+ }
+ },
+ handleResetRunnersCache(endpoint) {
+ this.isResetCacheButtonLoading = true;
+
+ this.service
+ .postAction(endpoint)
+ .then(() => {
+ this.isResetCacheButtonLoading = false;
+ createAlert({
+ message: s__('Pipelines|Project cache successfully reset.'),
+ variant: VARIANT_INFO,
+ });
+ })
+ .catch(() => {
+ this.isResetCacheButtonLoading = false;
+ createAlert({
+ message: s__('Pipelines|Something went wrong while cleaning runners cache.'),
+ });
+ });
+ },
+ resetRequestData() {
+ this.requestData = { page: this.page, scope: this.scope };
+ },
+ filterPipelines(filters) {
+ this.resetRequestData();
+
+ filters.forEach((filter) => {
+ // do not add Any for username query param, so we
+ // can fetch all trigger authors
+ if (
+ filter.type &&
+ filter.value.data !== ANY_TRIGGER_AUTHOR &&
+ filter.type !== FILTER_TAG_IDENTIFIER
+ ) {
+ this.requestData[filter.type] = filter.value.data;
+ }
+
+ if (filter.type === FILTER_TAG_IDENTIFIER) {
+ this.requestData.ref = filter.value.data;
+ }
+
+ if (!filter.type) {
+ createAlert({
+ message: RAW_TEXT_WARNING,
+ variant: VARIANT_WARNING,
+ });
+ }
+ });
+
+ if (filters.length === 0) {
+ this.resetRequestData();
+ }
+
+ this.updateContent({ ...this.requestData, page: '1' });
+ },
+ changeVisibilityPipelineIDType(idType) {
+ this.visibilityPipelineIdType = idType;
+ this.saveVisibilityPipelineIDType(idType);
+ },
+ saveVisibilityPipelineIDType(idType) {
+ if (!isLoggedIn()) return;
+
+ this.$apollo
+ .mutate({
+ mutation: setSortPreferenceMutation,
+ variables: { input: { visibilityPipelineIdType: idType.toUpperCase() } },
+ })
+ .then(({ data }) => {
+ if (data.userPreferencesUpdate.errors.length) {
+ throw new Error(data.userPreferencesUpdate.errors);
+ }
+ })
+ .catch((error) => {
+ Sentry.captureException(error);
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div class="pipelines-container">
+ <div
+ v-if="shouldRenderTabs || shouldRenderButtons"
+ class="top-area scrolling-tabs-container inner-page-scroll-tabs gl-border-none"
+ >
+ <div class="fade-left"><gl-icon name="chevron-lg-left" :size="12" /></div>
+ <div class="fade-right"><gl-icon name="chevron-lg-right" :size="12" /></div>
+
+ <navigation-tabs
+ v-if="shouldRenderTabs"
+ :tabs="tabs"
+ scope="pipelines"
+ @onChangeTab="onChangeTab"
+ />
+
+ <navigation-controls
+ v-if="shouldRenderButtons"
+ :new-pipeline-path="newPipelinePath"
+ :reset-cache-path="resetCachePath"
+ :ci-lint-path="ciLintPath"
+ :is-reset-cache-button-loading="isResetCacheButtonLoading"
+ @resetRunnersCache="handleResetRunnersCache"
+ />
+ </div>
+
+ <div v-if="stateToRender !== $options.stateMap.emptyState" class="gl-display-flex">
+ <div class="row-content-block gl-display-flex gl-flex-grow-1 gl-border-b-0">
+ <pipelines-filtered-search
+ class="gl-display-flex gl-flex-grow-1 gl-mr-4"
+ :project-id="projectId"
+ :default-branch-name="defaultBranchName"
+ :params="validatedParams"
+ @filterPipelines="filterPipelines"
+ />
+ <gl-collapsible-listbox
+ v-model="visibilityPipelineIdType"
+ data-testid="pipeline-key-collapsible-box"
+ :toggle-text="selectedPipelineKeyOption.text"
+ :items="$options.PipelineKeyOptions"
+ @select="changeVisibilityPipelineIDType"
+ />
+ </div>
+ </div>
+
+ <div class="content-list pipelines">
+ <gl-loading-icon
+ v-if="stateToRender === $options.stateMap.loading"
+ :label="s__('Pipelines|Loading Pipelines')"
+ size="lg"
+ class="prepend-top-20"
+ />
+
+ <no-ci-empty-state
+ v-else-if="stateToRender === $options.stateMap.emptyState"
+ :empty-state-svg-path="emptyStateSvgPath"
+ :can-set-ci="canCreatePipeline"
+ :registration-token="registrationToken"
+ />
+
+ <gl-empty-state
+ v-else-if="stateToRender === $options.stateMap.error"
+ :svg-path="errorStateSvgPath"
+ :title="s__('Pipelines|There was an error fetching the pipelines.')"
+ :description="s__('Pipelines|Try again in a few moments or contact your support team.')"
+ />
+
+ <gl-empty-state
+ v-else-if="stateToRender === $options.stateMap.emptyTab"
+ :svg-path="noPipelinesSvgPath"
+ :svg-height="150"
+ :title="emptyTabMessage"
+ />
+
+ <div v-else-if="stateToRender === $options.stateMap.tableList">
+ <pipelines-table-component
+ :pipelines="state.pipelines"
+ :pipeline-schedule-url="pipelineScheduleUrl"
+ :update-graph-dropdown="updateGraphDropdown"
+ :view-type="viewType"
+ :pipeline-key-option="selectedPipelineKeyOption"
+ />
+ </div>
+
+ <table-pagination
+ v-if="shouldRenderPagination"
+ :change="onChangePage"
+ :page-info="state.pageInfo"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/services/pipelines_service.js b/app/assets/javascripts/ci/pipelines_page/services/pipelines_service.js
new file mode 100644
index 00000000000..c38fa07c7e3
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/services/pipelines_service.js
@@ -0,0 +1,51 @@
+import Api from '~/api';
+import axios from '~/lib/utils/axios_utils';
+import { validateParams } from '../../pipeline_details/utils';
+
+export default class PipelinesService {
+ /**
+ * Commits and merge request endpoints need to be requested with `.json`.
+ *
+ * The url provided to request the pipelines in the new merge request
+ * page already has `.json`.
+ *
+ * @param {String} root
+ */
+ constructor(root) {
+ if (root.indexOf('.json') === -1) {
+ this.endpoint = `${root}.json`;
+ } else {
+ this.endpoint = root;
+ }
+ }
+
+ getPipelines(data = {}) {
+ const { scope, page } = data;
+ const { CancelToken } = axios;
+
+ const queryParams = { scope, page, ...validateParams(data) };
+
+ this.cancelationSource = CancelToken.source();
+
+ return axios.get(this.endpoint, {
+ params: queryParams,
+ cancelToken: this.cancelationSource.token,
+ });
+ }
+
+ /**
+ * Post request for all pipelines actions.
+ *
+ * @param {String} endpoint
+ * @return {Promise}
+ */
+ // eslint-disable-next-line class-methods-use-this
+ postAction(endpoint) {
+ return axios.post(`${endpoint}.json`);
+ }
+
+ // eslint-disable-next-line class-methods-use-this
+ runMRPipeline({ projectId, mergeRequestId }) {
+ return Api.postMergeRequestPipeline(projectId, { mergeRequestId });
+ }
+}
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/constants.js b/app/assets/javascripts/ci/pipelines_page/tokens/constants.js
index d8f15cfde91..d8f15cfde91 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/constants.js
+++ b/app/assets/javascripts/ci/pipelines_page/tokens/constants.js
diff --git a/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_branch_name_token.vue b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_branch_name_token.vue
new file mode 100644
index 00000000000..45b6fb380a9
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_branch_name_token.vue
@@ -0,0 +1,83 @@
+<script>
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
+import { debounce } from 'lodash';
+import Api from '~/api';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { FILTER_PIPELINES_SEARCH_DELAY } from '../constants';
+
+export default {
+ components: {
+ GlFilteredSearchToken,
+ GlFilteredSearchSuggestion,
+ GlLoadingIcon,
+ },
+ props: {
+ config: {
+ type: Object,
+ required: true,
+ },
+ value: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ branches: null,
+ loading: true,
+ };
+ },
+ created() {
+ this.fetchBranches();
+ },
+ methods: {
+ fetchBranches(searchterm) {
+ Api.branches(this.config.projectId, searchterm)
+ .then(({ data }) => {
+ this.branches = data.map((branch) => branch.name);
+ if (!searchterm && this.config.defaultBranchName) {
+ // Shift the default branch to the top of the list
+ this.branches = this.branches.filter(
+ (branch) => branch !== this.config.defaultBranchName,
+ );
+ this.branches.unshift(this.config.defaultBranchName);
+ }
+ this.loading = false;
+ })
+ .catch((err) => {
+ createAlert({
+ message: __('There was a problem fetching project branches.'),
+ });
+ this.loading = false;
+ throw err;
+ });
+ },
+ searchBranches: debounce(function debounceSearch({ data }) {
+ this.fetchBranches(data);
+ }, FILTER_PIPELINES_SEARCH_DELAY),
+ },
+};
+</script>
+
+<template>
+ <gl-filtered-search-token
+ :config="config"
+ v-bind="{ ...$props, ...$attrs }"
+ v-on="$listeners"
+ @input="searchBranches"
+ >
+ <template #suggestions>
+ <gl-loading-icon v-if="loading" size="sm" />
+ <template v-else>
+ <gl-filtered-search-suggestion
+ v-for="(branch, index) in branches"
+ :key="index"
+ :value="branch"
+ >
+ {{ branch }}
+ </gl-filtered-search-suggestion>
+ </template>
+ </template>
+ </gl-filtered-search-token>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_source_token.vue b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_source_token.vue
new file mode 100644
index 00000000000..b4b5c5c1b37
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_source_token.vue
@@ -0,0 +1,47 @@
+<script>
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion } from '@gitlab/ui';
+import { PIPELINE_SOURCES } from 'ee_else_ce/ci/pipelines_page/tokens/constants';
+
+export default {
+ PIPELINE_SOURCES,
+ components: {
+ GlFilteredSearchToken,
+ GlFilteredSearchSuggestion,
+ },
+ props: {
+ config: {
+ type: Object,
+ required: true,
+ },
+ value: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ activeSource() {
+ return PIPELINE_SOURCES.find((source) => source.value === this.value.data);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-filtered-search-token v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
+ <template #view>
+ <div class="gl-display-flex gl-align-items-center">
+ <span>{{ activeSource.text }}</span>
+ </div>
+ </template>
+
+ <template #suggestions>
+ <gl-filtered-search-suggestion
+ v-for="source in $options.PIPELINE_SOURCES"
+ :key="source.value"
+ :value="source.value"
+ >
+ {{ source.text }}
+ </gl-filtered-search-suggestion>
+ </template>
+ </gl-filtered-search-token>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_status_token.vue b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_status_token.vue
index 020a08b8cee..020a08b8cee 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_status_token.vue
+++ b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_status_token.vue
diff --git a/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_tag_name_token.vue b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_tag_name_token.vue
new file mode 100644
index 00000000000..a6034e78b6d
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_tag_name_token.vue
@@ -0,0 +1,67 @@
+<script>
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
+import { debounce } from 'lodash';
+import Api from '~/api';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { FILTER_PIPELINES_SEARCH_DELAY } from '../constants';
+
+export default {
+ components: {
+ GlFilteredSearchToken,
+ GlFilteredSearchSuggestion,
+ GlLoadingIcon,
+ },
+ props: {
+ config: {
+ type: Object,
+ required: true,
+ },
+ value: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ tags: null,
+ loading: true,
+ };
+ },
+ created() {
+ this.fetchTags();
+ },
+ methods: {
+ fetchTags(searchTerm) {
+ Api.tags(this.config.projectId, searchTerm)
+ .then(({ data }) => {
+ this.tags = data.map((tag) => tag.name);
+ this.loading = false;
+ })
+ .catch((err) => {
+ createAlert({
+ message: __('There was a problem fetching project tags.'),
+ });
+ this.loading = false;
+ throw err;
+ });
+ },
+ searchTags: debounce(function debounceSearch({ data }) {
+ this.fetchTags(data);
+ }, FILTER_PIPELINES_SEARCH_DELAY),
+ },
+};
+</script>
+
+<template>
+ <gl-filtered-search-token v-bind="{ ...$props, ...$attrs }" v-on="$listeners" @input="searchTags">
+ <template #suggestions>
+ <gl-loading-icon v-if="loading" size="sm" />
+ <template v-else>
+ <gl-filtered-search-suggestion v-for="(tag, index) in tags" :key="index" :value="tag">
+ {{ tag }}
+ </gl-filtered-search-suggestion>
+ </template>
+ </template>
+ </gl-filtered-search-token>
+</template>
diff --git a/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_trigger_author_token.vue b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_trigger_author_token.vue
new file mode 100644
index 00000000000..20c5e1557a7
--- /dev/null
+++ b/app/assets/javascripts/ci/pipelines_page/tokens/pipeline_trigger_author_token.vue
@@ -0,0 +1,110 @@
+<script>
+import {
+ GlFilteredSearchToken,
+ GlAvatar,
+ GlFilteredSearchSuggestion,
+ GlDropdownDivider,
+ GlLoadingIcon,
+} from '@gitlab/ui';
+import { debounce } from 'lodash';
+import Api from '~/api';
+import { createAlert } from '~/alert';
+import { __ } from '~/locale';
+import { ANY_TRIGGER_AUTHOR, FILTER_PIPELINES_SEARCH_DELAY } from '../constants';
+
+export default {
+ anyTriggerAuthor: ANY_TRIGGER_AUTHOR,
+ components: {
+ GlFilteredSearchToken,
+ GlAvatar,
+ GlFilteredSearchSuggestion,
+ GlDropdownDivider,
+ GlLoadingIcon,
+ },
+ props: {
+ config: {
+ type: Object,
+ required: true,
+ },
+ value: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ users: [],
+ loading: true,
+ };
+ },
+ computed: {
+ currentValue() {
+ return this.value.data.toLowerCase();
+ },
+ activeUser() {
+ return this.users.find((user) => {
+ return user.username.toLowerCase() === this.currentValue;
+ });
+ },
+ },
+ created() {
+ this.fetchProjectUsers();
+ },
+ methods: {
+ fetchProjectUsers(searchTerm) {
+ Api.projectUsers(this.config.projectId, searchTerm)
+ .then((users) => {
+ this.users = users;
+ this.loading = false;
+ })
+ .catch((err) => {
+ createAlert({
+ message: __('There was a problem fetching project users.'),
+ });
+ this.loading = false;
+ throw err;
+ });
+ },
+ searchAuthors: debounce(function debounceSearch({ data }) {
+ this.fetchProjectUsers(data);
+ }, FILTER_PIPELINES_SEARCH_DELAY),
+ },
+};
+</script>
+
+<template>
+ <gl-filtered-search-token
+ :config="config"
+ v-bind="{ ...$props, ...$attrs }"
+ v-on="$listeners"
+ @input="searchAuthors"
+ >
+ <template #view="{ inputValue }">
+ <gl-avatar v-if="activeUser" :size="16" :src="activeUser.avatar_url" class="gl-mr-2" />
+ <span>{{ activeUser ? activeUser.name : inputValue }}</span>
+ </template>
+ <template #suggestions>
+ <gl-filtered-search-suggestion :value="$options.anyTriggerAuthor">{{
+ $options.anyTriggerAuthor
+ }}</gl-filtered-search-suggestion>
+ <gl-dropdown-divider />
+
+ <gl-loading-icon v-if="loading" size="sm" />
+ <template v-else>
+ <gl-filtered-search-suggestion
+ v-for="user in users"
+ :key="user.username"
+ :value="user.username"
+ >
+ <div class="d-flex">
+ <gl-avatar :size="32" :src="user.avatar_url" />
+ <div>
+ <div>{{ user.name }}</div>
+ <div>@{{ user.username }}</div>
+ </div>
+ </div>
+ </gl-filtered-search-suggestion>
+ </template>
+ </template>
+ </gl-filtered-search-token>
+</template>
diff --git a/app/assets/javascripts/ci/reports/components/issue_status_icon.vue b/app/assets/javascripts/ci/reports/components/issue_status_icon.vue
index bd41b8d23f1..f2346a5512e 100644
--- a/app/assets/javascripts/ci/reports/components/issue_status_icon.vue
+++ b/app/assets/javascripts/ci/reports/components/issue_status_icon.vue
@@ -22,7 +22,8 @@ export default {
iconName() {
if (this.isStatusFailed) {
return 'status_failed_borderless';
- } else if (this.isStatusSuccess) {
+ }
+ if (this.isStatusSuccess) {
return 'status_success_borderless';
}
@@ -49,6 +50,6 @@ export default {
}"
class="report-block-list-icon"
>
- <gl-icon :name="iconName" :size="statusIconSize" :data-qa-selector="`status_${status}_icon`" />
+ <gl-icon :name="iconName" :size="statusIconSize" />
</div>
</template>
diff --git a/app/assets/javascripts/ci/reports/components/report_section.vue b/app/assets/javascripts/ci/reports/components/report_section.vue
index a4ec7b6a325..fd6c6cca6b7 100644
--- a/app/assets/javascripts/ci/reports/components/report_section.vue
+++ b/app/assets/javascripts/ci/reports/components/report_section.vue
@@ -159,7 +159,8 @@ export default {
slotName() {
if (this.isSuccess) {
return SLOT_SUCCESS;
- } else if (this.isLoading) {
+ }
+ if (this.isLoading) {
return SLOT_LOADING;
}
diff --git a/app/assets/javascripts/ci/runner/admin_runners/admin_runners_app.vue b/app/assets/javascripts/ci/runner/admin_runners/admin_runners_app.vue
index e6813211fe9..0ec94dc865f 100644
--- a/app/assets/javascripts/ci/runner/admin_runners/admin_runners_app.vue
+++ b/app/assets/javascripts/ci/runner/admin_runners/admin_runners_app.vue
@@ -178,6 +178,22 @@ export default {
</script>
<template>
<div>
+ <header class="gl-my-5 gl-display-flex gl-justify-content-space-between">
+ <h2 class="gl-my-0 header-title">
+ {{ s__('Runners|Runners') }}
+ </h2>
+ <div class="gl-display-flex gl-gap-3">
+ <runner-dashboard-link />
+ <gl-button :href="newRunnerPath" variant="confirm">
+ {{ s__('Runners|New instance runner') }}
+ </gl-button>
+ <registration-dropdown
+ :registration-token="registrationToken"
+ :type="$options.INSTANCE_TYPE"
+ placement="right"
+ />
+ </div>
+ </header>
<div
class="gl-display-flex gl-align-items-center gl-flex-direction-column-reverse gl-md-flex-direction-row gl-mt-3 gl-md-mt-0"
>
@@ -189,18 +205,6 @@ export default {
content-class="gl-display-none"
nav-class="gl-border-none!"
/>
-
- <div class="gl-w-full gl-md-w-auto gl-display-flex gl-gap-3">
- <runner-dashboard-link />
- <gl-button :href="newRunnerPath" variant="confirm">
- {{ s__('Runners|New instance runner') }}
- </gl-button>
- <registration-dropdown
- :registration-token="registrationToken"
- :type="$options.INSTANCE_TYPE"
- placement="right"
- />
- </div>
</div>
<runner-filtered-search-bar
diff --git a/app/assets/javascripts/ci/runner/components/cells/runner_owner_cell.vue b/app/assets/javascripts/ci/runner/components/cells/runner_owner_cell.vue
index cb43760b2d6..8f1c7234b84 100644
--- a/app/assets/javascripts/ci/runner/components/cells/runner_owner_cell.vue
+++ b/app/assets/javascripts/ci/runner/components/cells/runner_owner_cell.vue
@@ -50,12 +50,7 @@ export default {
<template>
<div>
- <gl-link
- v-if="cell.href"
- v-gl-tooltip="cell.tooltip"
- :href="cell.href"
- class="gl-text-body gl-text-decoration-underline"
- >
+ <gl-link v-if="cell.href" v-gl-tooltip="cell.tooltip" :href="cell.href" class="gl-text-body">
{{ cell.text }}
</gl-link>
<span v-else>{{ cell.text }}</span>
diff --git a/app/assets/javascripts/ci/runner/components/cells/runner_summary_cell.vue b/app/assets/javascripts/ci/runner/components/cells/runner_summary_cell.vue
index cc31afea88c..a80d6207be8 100644
--- a/app/assets/javascripts/ci/runner/components/cells/runner_summary_cell.vue
+++ b/app/assets/javascripts/ci/runner/components/cells/runner_summary_cell.vue
@@ -12,7 +12,6 @@ import RunnerManagersBadge from '../runner_managers_badge.vue';
import { formatJobCount } from '../../utils';
import {
- I18N_NO_DESCRIPTION,
I18N_LOCKED_RUNNER_DESCRIPTION,
I18N_VERSION_LABEL,
I18N_LAST_CONTACT_LABEL,
@@ -73,7 +72,6 @@ export default {
formatNumber,
},
i18n: {
- I18N_NO_DESCRIPTION,
I18N_LOCKED_RUNNER_DESCRIPTION,
I18N_VERSION_LABEL,
I18N_LAST_CONTACT_LABEL,
@@ -100,7 +98,10 @@ export default {
<runner-type-badge :type="runner.runnerType" size="sm" class="gl-vertical-align-middle" />
</div>
- <div class="gl-mb-3 gl-ml-auto gl-display-inline-flex gl-max-w-full">
+ <div
+ v-if="runner.version || runner.description"
+ class="gl-mb-3 gl-ml-auto gl-display-inline-flex gl-max-w-full gl-font-sm gl-align-items-center"
+ >
<template v-if="runner.version">
<div class="gl-flex-shrink-0">
<runner-upgrade-status-icon :upgrade-status="runner.upgradeStatus" />
@@ -108,19 +109,20 @@ export default {
<template #version>{{ runner.version }}</template>
</gl-sprintf>
</div>
- <div class="gl-text-secondary gl-mx-2" aria-hidden="true">·</div>
+ <div v-if="runner.description" class="gl-text-secondary gl-mx-2" aria-hidden="true">·</div>
</template>
<tooltip-on-truncate
+ v-if="runner.description"
class="gl-text-truncate gl-display-block"
:class="{ 'gl-text-secondary': !runner.description }"
:title="runner.description"
>
- {{ runner.description || $options.i18n.I18N_NO_DESCRIPTION }}
+ {{ runner.description }}
</tooltip-on-truncate>
</div>
- <div>
- <runner-summary-field icon="clock">
+ <div class="gl-font-sm">
+ <runner-summary-field icon="clock" icon-size="sm">
<gl-sprintf :message="$options.i18n.I18N_LAST_CONTACT_LABEL">
<template #timeAgo>
<time-ago v-if="runner.contactedAt" :time="runner.contactedAt" />
diff --git a/app/assets/javascripts/ci/runner/components/cells/runner_summary_field.vue b/app/assets/javascripts/ci/runner/components/cells/runner_summary_field.vue
index 742259ee491..b1b61e03eec 100644
--- a/app/assets/javascripts/ci/runner/components/cells/runner_summary_field.vue
+++ b/app/assets/javascripts/ci/runner/components/cells/runner_summary_field.vue
@@ -25,7 +25,7 @@ export default {
<template>
<div v-gl-tooltip="tooltip" class="gl-display-inline-block gl-text-secondary gl-mb-3 gl-mr-4">
- <gl-icon v-if="icon" :name="icon" />
+ <gl-icon v-if="icon" :name="icon" :size="12" />
<!-- display tooltip as a label for screen readers -->
<span class="gl-sr-only">{{ tooltip }}</span>
<slot></slot>
diff --git a/app/assets/javascripts/ci/runner/components/runner_create_form.vue b/app/assets/javascripts/ci/runner/components/runner_create_form.vue
index 1b363174d28..adaed77055a 100644
--- a/app/assets/javascripts/ci/runner/components/runner_create_form.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_create_form.vue
@@ -120,7 +120,7 @@ export default {
</script>
<template>
<gl-form @submit.prevent="onSubmit">
- <runner-form-fields v-model="runner" />
+ <runner-form-fields v-model="runner" :runner-type="runnerType" />
<div class="gl-display-flex gl-mt-6">
<gl-button type="submit" variant="confirm" class="js-no-auto-disable" :loading="saving">
diff --git a/app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue b/app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue
index 3634dcf1c93..81b2a17631e 100644
--- a/app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue
@@ -92,7 +92,6 @@ export default {
:initial-filter-value="initialFilterValue"
:tokens="validTokens"
:initial-sort-by="initialSortBy"
- :search-input-placeholder="__('Search or filter results...')"
:search-text-option-label="s__('Runners|Search description...')"
terms-as-tokens
data-testid="runners-filtered-search"
diff --git a/app/assets/javascripts/ci/runner/components/runner_form_fields.vue b/app/assets/javascripts/ci/runner/components/runner_form_fields.vue
index d090a562ff7..38e36733045 100644
--- a/app/assets/javascripts/ci/runner/components/runner_form_fields.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_form_fields.vue
@@ -10,7 +10,12 @@ import {
GlSkeletonLoader,
} from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
-import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants';
+import {
+ ACCESS_LEVEL_NOT_PROTECTED,
+ ACCESS_LEVEL_REF_PROTECTED,
+ PROJECT_TYPE,
+ RUNNER_TYPES,
+} from '../constants';
export default {
name: 'RunnerFormFields',
@@ -26,6 +31,12 @@ export default {
import('ee_component/ci/runner/components/runner_maintenance_note_field.vue'),
},
props: {
+ runnerType: {
+ type: String,
+ required: false,
+ default: null,
+ validator: (t) => RUNNER_TYPES.includes(t),
+ },
value: {
type: Object,
default: null,
@@ -44,7 +55,7 @@ export default {
},
computed: {
canBeLockedToProject() {
- return this.value?.runnerType === PROJECT_TYPE;
+ return this.runnerType === PROJECT_TYPE;
},
},
watch: {
diff --git a/app/assets/javascripts/ci/runner/components/runner_managers_table.vue b/app/assets/javascripts/ci/runner/components/runner_managers_table.vue
index 10790c398b0..58244e1f2df 100644
--- a/app/assets/javascripts/ci/runner/components/runner_managers_table.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_managers_table.vue
@@ -6,6 +6,7 @@ import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { tableField } from '../utils';
import { I18N_STATUS_NEVER_CONTACTED } from '../constants';
import RunnerStatusBadge from './runner_status_badge.vue';
+import RunnerJobStatusBadge from './runner_job_status_badge.vue';
export default {
name: 'RunnerManagersTable',
@@ -15,6 +16,7 @@ export default {
HelpPopover,
GlIntersperse,
RunnerStatusBadge,
+ RunnerJobStatusBadge,
RunnerUpgradeStatusIcon: () =>
import('ee_component/ci/runner/components/runner_upgrade_status_icon.vue'),
},
@@ -52,7 +54,15 @@ export default {
</help-popover>
</template>
<template #cell(status)="{ item = {} }">
- <runner-status-badge :contacted-at="item.contactedAt" :status="item.status" />
+ <runner-status-badge
+ class="gl-vertical-align-middle"
+ :contacted-at="item.contactedAt"
+ :status="item.status"
+ />
+ <runner-job-status-badge
+ class="gl-vertical-align-middle"
+ :job-status="item.jobExecutionStatus"
+ />
</template>
<template #cell(version)="{ item = {} }">
{{ item.version }}
diff --git a/app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue b/app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue
index a49641194a7..a841f66b566 100644
--- a/app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_platforms_radio_group.vue
@@ -55,7 +55,7 @@ export default {
<div class="gl-mt-3 gl-mb-6">
<label>{{ s__('Runners|Operating systems') }}</label>
- <div class="gl-display-flex gl-flex-wrap gl-gap-5">
+ <div class="gl-display-flex gl-flex-wrap gl-gap-3">
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
<runner-platforms-radio
v-model="model"
@@ -76,7 +76,7 @@ export default {
<div class="gl-mt-3 gl-mb-6">
<label>{{ s__('Runners|Containers') }}</label>
- <div class="gl-display-flex gl-flex-wrap gl-gap-5">
+ <div class="gl-display-flex gl-flex-wrap gl-gap-3">
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
<runner-platforms-radio :image="$options.DOCKER_LOGO_URL">
<gl-link :href="$options.DOCKER_HELP_URL" target="_blank">
diff --git a/app/assets/javascripts/ci/runner/components/runner_type_tabs.vue b/app/assets/javascripts/ci/runner/components/runner_type_tabs.vue
index 70226074993..3af10c59e31 100644
--- a/app/assets/javascripts/ci/runner/components/runner_type_tabs.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_type_tabs.vue
@@ -112,7 +112,12 @@ export default {
:scope="countScope"
:variables="tabBadgeCountVariables(tab.runnerType)"
>
- <gl-badge v-if="tabCount(count)" class="gl-ml-1" size="sm">
+ <gl-badge
+ v-if="tabCount(count)"
+ class="gl-ml-1"
+ size="sm"
+ :data-testid="`runner-count-${tab.title.toLowerCase()}`"
+ >
{{ tabCount(count) }}
</gl-badge>
</runner-count>
diff --git a/app/assets/javascripts/ci/runner/components/runner_update_form.vue b/app/assets/javascripts/ci/runner/components/runner_update_form.vue
index 6b94e594f1c..4278615ba66 100644
--- a/app/assets/javascripts/ci/runner/components/runner_update_form.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_update_form.vue
@@ -96,7 +96,7 @@ export default {
</script>
<template>
<gl-form @submit.prevent="onSubmit">
- <runner-form-fields v-model="model" :loading="loading" />
+ <runner-form-fields v-model="model" :loading="loading" :runner-type="runnerType" />
<runner-update-cost-factor-fields v-model="model" :runner-type="runnerType" />
<div class="gl-mt-6">
diff --git a/app/assets/javascripts/ci/runner/components/stat/runner_count.vue b/app/assets/javascripts/ci/runner/components/stat/runner_count.vue
index c33c42f3afe..cee1088d90b 100644
--- a/app/assets/javascripts/ci/runner/components/stat/runner_count.vue
+++ b/app/assets/javascripts/ci/runner/components/stat/runner_count.vue
@@ -55,7 +55,8 @@ export default {
query() {
if (this.scope === INSTANCE_TYPE) {
return allRunnersCountQuery;
- } else if (this.scope === GROUP_TYPE) {
+ }
+ if (this.scope === GROUP_TYPE) {
return groupRunnersCountQuery;
}
return null;
@@ -74,7 +75,8 @@ export default {
update(data) {
if (this.scope === INSTANCE_TYPE) {
return data?.runners?.count;
- } else if (this.scope === GROUP_TYPE) {
+ }
+ if (this.scope === GROUP_TYPE) {
return data?.group?.runners?.count;
}
return null;
diff --git a/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue b/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue
index e0a6f4b1e67..6c49263ac82 100644
--- a/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue
+++ b/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue
@@ -90,6 +90,7 @@ export default {
:scope="scope"
v-bind="stat.props"
class="gl-px-5"
+ :data-testid="`runner-stats-${stat.key.toLowerCase()}`"
/>
<runner-upgrade-status-stats
diff --git a/app/assets/javascripts/ci/runner/constants.js b/app/assets/javascripts/ci/runner/constants.js
index 203f97876de..3293c68ddb8 100644
--- a/app/assets/javascripts/ci/runner/constants.js
+++ b/app/assets/javascripts/ci/runner/constants.js
@@ -15,7 +15,7 @@ export const I18N_CREATE_ERROR = s__(
);
export const FILTER_CSS_CLASSES =
- 'gl-bg-gray-10 gl-p-5 gl-border-solid gl-border-gray-100 gl-border-0 gl-border-t-1 gl-border-b-1';
+ 'gl-bg-gray-10 gl-p-5 gl-border-solid gl-border-gray-100 gl-border-0 gl-border-t-1';
// Type
@@ -96,7 +96,6 @@ export const I18N_DELETE_RUNNER = s__('Runners|Delete runner');
export const I18N_DELETED_TOAST = s__('Runners|Runner %{name} was deleted');
// List
-export const I18N_NO_DESCRIPTION = s__('Runners|No description');
export const I18N_LOCKED_RUNNER_DESCRIPTION = s__(
'Runners|Runner is locked and available for currently assigned projects only. Only administrators can change the assigned projects.',
);
diff --git a/app/assets/javascripts/ci/runner/graphql/show/runner_manager_shared.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/show/runner_manager_shared.fragment.graphql
index ead005d1252..84d32e24f24 100644
--- a/app/assets/javascripts/ci/runner/graphql/show/runner_manager_shared.fragment.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/show/runner_manager_shared.fragment.graphql
@@ -9,4 +9,5 @@ fragment CiRunnerManagerShared on CiRunnerManager {
platformName
ipAddress
contactedAt
+ jobExecutionStatus
}
diff --git a/app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue b/app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue
index 71584c40a38..dcaf8635f5c 100644
--- a/app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue
+++ b/app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue
@@ -212,6 +212,27 @@ export default {
<template>
<div>
+ <header class="gl-my-5 gl-display-flex gl-justify-content-space-between">
+ <h2 class="gl-my-0 header-title">
+ {{ s__('Runners|Runners') }}
+ </h2>
+ <div class="gl-display-flex gl-gap-3">
+ <gl-button
+ v-if="newRunnerPath"
+ :href="newRunnerPath"
+ variant="confirm"
+ data-testid="new-group-runner-button"
+ >
+ {{ s__('Runners|New group runner') }}
+ </gl-button>
+ <registration-dropdown
+ v-if="registrationToken"
+ :registration-token="registrationToken"
+ :type="$options.GROUP_TYPE"
+ placement="right"
+ />
+ </div>
+ </header>
<div
class="gl-display-flex gl-align-items-center gl-flex-direction-column-reverse gl-md-flex-direction-row gl-mt-3 gl-md-mt-0"
>
@@ -225,19 +246,6 @@ export default {
content-class="gl-display-none"
nav-class="gl-border-none!"
/>
-
- <div class="gl-w-full gl-md-w-auto gl-display-flex">
- <gl-button v-if="newRunnerPath" :href="newRunnerPath" variant="confirm">
- {{ s__('Runners|New group runner') }}
- </gl-button>
- <registration-dropdown
- v-if="registrationToken"
- class="gl-ml-3"
- :registration-token="registrationToken"
- :type="$options.GROUP_TYPE"
- placement="right"
- />
- </div>
</div>
<div
class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-gap-3"
diff --git a/app/assets/javascripts/ci/runner/project_runners/index.js b/app/assets/javascripts/ci/runner/project_runners/index.js
deleted file mode 100644
index 3be2b4a7422..00000000000
--- a/app/assets/javascripts/ci/runner/project_runners/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import Vue from 'vue';
-import ProjectRunnersApp from './project_runners_app.vue';
-
-export const initProjectRunners = (selector = '#js-project-runners') => {
- const el = document.querySelector(selector);
-
- if (!el) {
- return null;
- }
-
- const { projectFullPath } = el.dataset;
-
- return new Vue({
- el,
- render(h) {
- return h(ProjectRunnersApp, {
- props: {
- projectFullPath,
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/ci/runner/project_runners/project_runners_app.vue b/app/assets/javascripts/ci/runner/project_runners/project_runners_app.vue
deleted file mode 100644
index c7bf5e521a1..00000000000
--- a/app/assets/javascripts/ci/runner/project_runners/project_runners_app.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-<script>
-export default {
- props: {
- projectFullPath: {
- required: true,
- type: String,
- },
- },
-};
-</script>
-<template>
- <div>
- <!--
- Under development
- Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/33803
- Feature rollout: https://gitlab.com/gitlab-org/gitlab/-/issues/386573
- -->
- </div>
-</template>
diff --git a/app/assets/javascripts/ci/runner/runner_search_utils.js b/app/assets/javascripts/ci/runner/runner_search_utils.js
index 3dc99baa329..8915198350f 100644
--- a/app/assets/javascripts/ci/runner/runner_search_utils.js
+++ b/app/assets/javascripts/ci/runner/runner_search_utils.js
@@ -97,7 +97,8 @@ const outdatedStatusParams = (status) => {
[PARAM_KEY_PAUSED]: ['false'],
[PARAM_KEY_STATUS]: [], // Important! clear PARAM_KEY_STATUS to avoid a redirection loop!
};
- } else if (status === STATUS_PAUSED) {
+ }
+ if (status === STATUS_PAUSED) {
return {
[PARAM_KEY_PAUSED]: ['true'],
[PARAM_KEY_STATUS]: [], // Important! clear PARAM_KEY_STATUS to avoid a redirection loop!
diff --git a/app/assets/javascripts/ci/utils.js b/app/assets/javascripts/ci/utils.js
new file mode 100644
index 00000000000..eb9e9538b75
--- /dev/null
+++ b/app/assets/javascripts/ci/utils.js
@@ -0,0 +1,17 @@
+import * as Sentry from '@sentry/browser';
+
+export const reportToSentry = (component, failureType) => {
+ Sentry.withScope((scope) => {
+ scope.setTag('component', component);
+ Sentry.captureException(failureType);
+ });
+};
+
+export const reportMessageToSentry = (component, message, context) => {
+ Sentry.withScope((scope) => {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ scope.setContext('Vue data', context);
+ scope.setTag('component', component);
+ Sentry.captureMessage(message);
+ });
+};
diff --git a/app/assets/javascripts/ci_secure_files/components/metadata/modal.vue b/app/assets/javascripts/ci_secure_files/components/metadata/modal.vue
index fdf720a5f94..cbb9c31b54b 100644
--- a/app/assets/javascripts/ci_secure_files/components/metadata/modal.vue
+++ b/app/assets/javascripts/ci_secure_files/components/metadata/modal.vue
@@ -101,10 +101,12 @@ export default {
if (this.fileExtension === 'cer') {
this.track('load_secure_file_metadata_cer');
return this.cerItems();
- } else if (this.fileExtension === 'p12') {
+ }
+ if (this.fileExtension === 'p12') {
this.track('load_secure_file_metadata_p12');
return this.p12Items();
- } else if (this.fileExtension === 'mobileprovision') {
+ }
+ if (this.fileExtension === 'mobileprovision') {
this.track('load_secure_file_metadata_mobileprovision');
return this.mobileprovisionItems(this.metadata);
}
diff --git a/app/assets/javascripts/clusters_list/components/agent_table.vue b/app/assets/javascripts/clusters_list/components/agent_table.vue
index 529be7169db..7482aaca36e 100644
--- a/app/assets/javascripts/clusters_list/components/agent_table.vue
+++ b/app/assets/javascripts/clusters_list/components/agent_table.vue
@@ -191,9 +191,11 @@ export default {
getVersionPopoverTitle(agent) {
if (this.isVersionMismatch(agent) && this.isVersionOutdated(agent)) {
return this.$options.i18n.versionMismatchOutdatedTitle;
- } else if (this.isVersionMismatch(agent)) {
+ }
+ if (this.isVersionMismatch(agent)) {
return this.$options.i18n.versionMismatchTitle;
- } else if (this.isVersionOutdated(agent)) {
+ }
+ if (this.isVersionOutdated(agent)) {
return this.$options.i18n.versionOutdatedTitle;
}
diff --git a/app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue b/app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue
index 75850cbb108..96ecbe9fa12 100644
--- a/app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue
+++ b/app/assets/javascripts/clusters_list/components/available_agents_dropdown.vue
@@ -30,7 +30,8 @@ export default {
dropdownText() {
if (this.isRegistering) {
return this.$options.i18n.registeringAgent;
- } else if (this.selectedAgent === null) {
+ }
+ if (this.selectedAgent === null) {
return this.$options.i18n.selectAgent;
}
diff --git a/app/assets/javascripts/clusters_list/components/clusters.vue b/app/assets/javascripts/clusters_list/components/clusters.vue
index 590fdb947b3..0258d8e0da0 100644
--- a/app/assets/javascripts/clusters_list/components/clusters.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters.vue
@@ -125,9 +125,11 @@ export default {
k8sQuantityToGb(quantity) {
if (!quantity) {
return 0;
- } else if (quantity.endsWith(__('Ki'))) {
+ }
+ if (quantity.endsWith(__('Ki'))) {
return parseInt(quantity.substr(0, quantity.length - 2), 10) * 0.000001024;
- } else if (quantity.endsWith(__('Mi'))) {
+ }
+ if (quantity.endsWith(__('Mi'))) {
return parseInt(quantity.substr(0, quantity.length - 2), 10) * 0.001048576;
}
@@ -138,9 +140,11 @@ export default {
k8sQuantityToCpu(quantity) {
if (!quantity) {
return 0;
- } else if (quantity.endsWith('m')) {
+ }
+ if (quantity.endsWith('m')) {
return parseInt(quantity.substr(0, quantity.length - 1), 10) / 1000.0;
- } else if (quantity.endsWith('n')) {
+ }
+ if (quantity.endsWith('n')) {
return parseInt(quantity.substr(0, quantity.length - 1), 10) / 1000000000.0;
}
diff --git a/app/assets/javascripts/clusters_list/components/clusters_actions.vue b/app/assets/javascripts/clusters_list/components/clusters_actions.vue
index c388d3fee71..e92b98946d0 100644
--- a/app/assets/javascripts/clusters_list/components/clusters_actions.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters_actions.vue
@@ -37,7 +37,8 @@ export default {
if (!this.displayClusterAgents) {
return connectClusterDeprecated;
- } else if (!this.certificateBasedClustersEnabled) {
+ }
+ if (!this.certificateBasedClustersEnabled) {
return connectCluster;
}
return connectWithAgent;
diff --git a/app/assets/javascripts/commit/constants.js b/app/assets/javascripts/commit/constants.js
index 4f865e99e46..e28009ab996 100644
--- a/app/assets/javascripts/commit/constants.js
+++ b/app/assets/javascripts/commit/constants.js
@@ -80,14 +80,14 @@ export const typeConfig = {
keyNamespace: 'gpgKeyPrimaryKeyid',
helpLink: {
label: __('Learn about signing commits'),
- path: 'user/project/repository/gpg_signed_commits/index.md',
+ path: 'user/project/repository/signed_commits/index.md',
},
},
[signatureTypes.X509]: {
keyLabel: '',
helpLink: {
label: __('Learn more about X.509 signed commits'),
- path: '/user/project/repository/x509_signed_commits/index.md',
+ path: '/user/project/repository/signed_commits/x509.md',
},
subjectTitle: __('Certificate Subject'),
issuerTitle: __('Certificate Issuer'),
@@ -98,7 +98,7 @@ export const typeConfig = {
keyNamespace: 'keyFingerprintSha256',
helpLink: {
label: __('Learn about signing commits with SSH keys.'),
- path: '/user/project/repository/ssh_signed_commits/index.md',
+ path: '/user/project/repository/signed_commits/ssh.md',
},
},
};
diff --git a/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue b/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue
new file mode 100644
index 00000000000..5e84dcbe48e
--- /dev/null
+++ b/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue
@@ -0,0 +1,342 @@
+<script>
+import { GlButton, GlEmptyState, GlLoadingIcon, GlModal, GlLink, GlSprintf } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { getParameterByName } from '~/lib/utils/url_utility';
+import PipelinesTableComponent from '~/ci/common/pipelines_table.vue';
+import { PipelineKeyOptions } from '~/ci/constants';
+import eventHub from '~/ci/event_hub';
+import PipelinesMixin from '~/ci/pipeline_details/mixins/pipelines_mixin';
+import PipelinesService from '~/ci/pipelines_page/services/pipelines_service';
+import PipelineStore from '~/ci/pipeline_details/stores/pipelines_store';
+import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { s__, __ } from '~/locale';
+
+export default {
+ PipelineKeyOptions,
+ components: {
+ GlButton,
+ GlEmptyState,
+ GlLink,
+ GlLoadingIcon,
+ GlModal,
+ GlSprintf,
+ PipelinesTableComponent,
+ TablePagination,
+ },
+ mixins: [PipelinesMixin, glFeatureFlagMixin()],
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ errorStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ emptyStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ viewType: {
+ type: String,
+ required: false,
+ default: 'root',
+ },
+ canCreatePipelineInTargetProject: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ sourceProjectFullPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ targetProjectFullPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ projectId: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ mergeRequestId: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
+ },
+
+ data() {
+ const store = new PipelineStore();
+
+ return {
+ store,
+ state: store.state,
+ page: getParameterByName('page') || '1',
+ requestData: {},
+ modalId: 'create-pipeline-for-fork-merge-request-modal',
+ };
+ },
+
+ computed: {
+ shouldRenderTable() {
+ return !this.isLoading && this.state.pipelines.length > 0 && !this.hasError;
+ },
+ shouldRenderErrorState() {
+ return this.hasError && !this.isLoading;
+ },
+ shouldRenderEmptyState() {
+ return this.state.pipelines.length === 0 && !this.shouldRenderErrorState;
+ },
+ /**
+ * The "Run pipeline" button can only be rendered when:
+ * - In MR view - we use `canCreatePipelineInTargetProject` for that purpose
+ * - If the latest pipeline has the `detached_merge_request_pipeline` flag
+ *
+ * @returns {Boolean}
+ */
+ canRenderPipelineButton() {
+ return this.latestPipelineDetachedFlag;
+ },
+ isForkMergeRequest() {
+ return this.sourceProjectFullPath !== this.targetProjectFullPath;
+ },
+ isLatestPipelineCreatedInTargetProject() {
+ const latest = this.state.pipelines[0];
+
+ return latest?.project?.full_path === `/${this.targetProjectFullPath}`;
+ },
+ shouldShowSecurityWarning() {
+ return (
+ this.canCreatePipelineInTargetProject &&
+ this.isForkMergeRequest &&
+ !this.isLatestPipelineCreatedInTargetProject
+ );
+ },
+ /**
+ * Checks if either `detached_merge_request_pipeline` or
+ * `merge_request_pipeline` are tru in the first
+ * object in the pipelines array.
+ *
+ * @returns {Boolean}
+ */
+ latestPipelineDetachedFlag() {
+ const latest = this.state.pipelines[0];
+ return (
+ latest &&
+ latest.flags &&
+ (latest.flags.detached_merge_request_pipeline || latest.flags.merge_request_pipeline)
+ );
+ },
+ },
+ created() {
+ this.service = new PipelinesService(this.endpoint);
+ this.requestData = { page: this.page };
+ },
+ methods: {
+ successCallback(resp) {
+ // depending of the endpoint the response can either bring a `pipelines` key or not.
+ const pipelines = resp.data.pipelines || resp.data;
+
+ this.store.storePagination(resp.headers);
+ this.setCommonData(pipelines);
+
+ if (resp.headers?.['x-total']) {
+ const updatePipelinesEvent = new CustomEvent('update-pipelines-count', {
+ detail: { pipelineCount: resp.headers['x-total'] },
+ });
+
+ // notifiy to update the count in tabs
+ if (this.$el.parentElement) {
+ this.$el.parentElement.dispatchEvent(updatePipelinesEvent);
+ }
+ }
+ },
+ /**
+ * When the user clicks on the "Run pipeline" button
+ * we need to make a post request and
+ * to update the table content once the request is finished.
+ *
+ * We are emitting an event through the eventHub using the old pattern
+ * to make use of the code in mixins/pipelines.js that handles all the
+ * table events
+ *
+ */
+ onClickRunPipeline() {
+ eventHub.$emit('runMergeRequestPipeline', {
+ projectId: this.projectId,
+ mergeRequestId: this.mergeRequestId,
+ });
+ },
+ tryRunPipeline() {
+ if (!this.shouldShowSecurityWarning) {
+ this.onClickRunPipeline();
+ } else {
+ this.$refs.modal.show();
+ }
+ },
+ },
+ modal: {
+ actionPrimary: {
+ text: s__('Pipeline|Run pipeline'),
+ attributes: {
+ variant: 'danger',
+ },
+ },
+ actionCancel: {
+ text: __('Cancel'),
+ attributes: {
+ variant: 'default',
+ },
+ },
+ },
+ i18n: {
+ runPipelinePopoverTitle: s__('Pipeline|Run merge request pipeline'),
+ runPipelinePopoverDescription: s__(
+ 'Pipeline|To run a merge request pipeline, the jobs in the CI/CD configuration file %{linkStart}must be configured%{linkEnd} to run in merge request pipelines.',
+ ),
+ runPipelineText: s__('Pipeline|Run pipeline'),
+ emptyStateTitle: s__('Pipelines|There are currently no pipelines.'),
+ },
+ mrPipelinesDocsPath: helpPagePath('ci/pipelines/merge_request_pipelines.md', {
+ anchor: 'prerequisites',
+ }),
+ runPipelinesInTheParentProjectHelpPath: helpPagePath(
+ '/ci/pipelines/merge_request_pipelines.html',
+ {
+ anchor: 'run-pipelines-in-the-parent-project',
+ },
+ ),
+};
+</script>
+<template>
+ <div class="content-list pipelines">
+ <gl-loading-icon
+ v-if="isLoading"
+ :label="s__('Pipelines|Loading pipelines')"
+ size="lg"
+ class="prepend-top-20"
+ />
+
+ <gl-empty-state
+ v-else-if="shouldRenderErrorState"
+ :svg-path="errorStateSvgPath"
+ :title="
+ s__(`Pipelines|There was an error fetching the pipelines.
+ Try again in a few moments or contact your support team.`)
+ "
+ data-testid="pipeline-error-empty-state"
+ />
+ <template v-else-if="shouldRenderEmptyState">
+ <gl-empty-state
+ :svg-path="emptyStateSvgPath"
+ :svg-height="150"
+ :title="$options.i18n.emptyStateTitle"
+ data-testid="pipeline-empty-state"
+ >
+ <template #description>
+ <gl-sprintf :message="$options.i18n.runPipelinePopoverDescription">
+ <template #link="{ content }">
+ <gl-link
+ :href="$options.mrPipelinesDocsPath"
+ target="_blank"
+ data-testid="mr-pipelines-docs-link"
+ >{{ content }}</gl-link
+ >
+ </template>
+ </gl-sprintf>
+ </template>
+
+ <template #actions>
+ <div class="gl-vertical-align-middle">
+ <gl-button
+ variant="confirm"
+ :loading="state.isRunningMergeRequestPipeline"
+ data-testid="run_pipeline_button"
+ @click="tryRunPipeline"
+ >
+ {{ $options.i18n.runPipelineText }}
+ </gl-button>
+ </div>
+ </template>
+ </gl-empty-state>
+ </template>
+
+ <div v-else-if="shouldRenderTable">
+ <gl-button
+ v-if="canRenderPipelineButton"
+ block
+ class="gl-mt-3 gl-mb-3 gl-lg-display-none"
+ variant="confirm"
+ data-testid="run_pipeline_button_mobile"
+ :loading="state.isRunningMergeRequestPipeline"
+ @click="tryRunPipeline"
+ >
+ {{ $options.i18n.runPipelineText }}
+ </gl-button>
+
+ <pipelines-table-component
+ :pipelines="state.pipelines"
+ :update-graph-dropdown="updateGraphDropdown"
+ :view-type="viewType"
+ :pipeline-key-option="$options.PipelineKeyOptions[0]"
+ >
+ <template #table-header-actions>
+ <div v-if="canRenderPipelineButton" class="gl-text-right">
+ <gl-button
+ data-testid="run_pipeline_button"
+ :loading="state.isRunningMergeRequestPipeline"
+ @click="tryRunPipeline"
+ >
+ {{ $options.i18n.runPipelineText }}
+ </gl-button>
+ </div>
+ </template>
+ </pipelines-table-component>
+ </div>
+
+ <gl-modal
+ v-if="canRenderPipelineButton || shouldRenderEmptyState"
+ :id="modalId"
+ ref="modal"
+ :modal-id="modalId"
+ :title="s__('Pipelines|Are you sure you want to run this pipeline?')"
+ :action-primary="$options.modal.actionPrimary"
+ :action-cancel="$options.modal.actionCancel"
+ @primary="onClickRunPipeline"
+ >
+ <p>
+ {{
+ s__(
+ 'Pipelines|This pipeline will run code originating from a forked project merge request. This means that the code can potentially have security considerations like exposing CI variables.',
+ )
+ }}
+ </p>
+ <p>
+ {{
+ s__(
+ "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource.",
+ )
+ }}
+ </p>
+ <p>
+ {{
+ s__('Pipelines|If you are unsure, please ask a project maintainer to review it for you.')
+ }}
+ </p>
+ <gl-link :href="$options.runPipelinesInTheParentProjectHelpPath" target="_blank">
+ {{ s__('Pipelines|More Information') }}
+ </gl-link>
+ </gl-modal>
+
+ <table-pagination
+ v-if="shouldRenderPagination"
+ :change="onChangePage"
+ :page-info="state.pageInfo"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
index 96c274225d8..beeb9b9ada4 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
@@ -26,7 +26,8 @@ export default () => {
if (pipelineTableViewEl.dataset.disableInitialization === undefined) {
const table = new Vue({
components: {
- CommitPipelinesTable: () => import('~/commit/pipelines/pipelines_table.vue'),
+ CommitPipelinesTable: () =>
+ import('~/commit/pipelines/legacy_pipelines_table_wrapper.vue'),
},
apolloProvider,
provide: {
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
deleted file mode 100644
index 8c8293eb09e..00000000000
--- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue
+++ /dev/null
@@ -1,342 +0,0 @@
-<script>
-import { GlButton, GlEmptyState, GlLoadingIcon, GlModal, GlLink, GlSprintf } from '@gitlab/ui';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { getParameterByName } from '~/lib/utils/url_utility';
-import PipelinesTableComponent from '~/pipelines/components/pipelines_list/pipelines_table.vue';
-import { PipelineKeyOptions } from '~/pipelines/constants';
-import eventHub from '~/pipelines/event_hub';
-import PipelinesMixin from '~/pipelines/mixins/pipelines_mixin';
-import PipelinesService from '~/pipelines/services/pipelines_service';
-import PipelineStore from '~/pipelines/stores/pipelines_store';
-import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { s__, __ } from '~/locale';
-
-export default {
- PipelineKeyOptions,
- components: {
- GlButton,
- GlEmptyState,
- GlLink,
- GlLoadingIcon,
- GlModal,
- GlSprintf,
- PipelinesTableComponent,
- TablePagination,
- },
- mixins: [PipelinesMixin, glFeatureFlagMixin()],
- props: {
- endpoint: {
- type: String,
- required: true,
- },
- errorStateSvgPath: {
- type: String,
- required: true,
- },
- emptyStateSvgPath: {
- type: String,
- required: true,
- },
- viewType: {
- type: String,
- required: false,
- default: 'root',
- },
- canCreatePipelineInTargetProject: {
- type: Boolean,
- required: false,
- default: false,
- },
- sourceProjectFullPath: {
- type: String,
- required: false,
- default: '',
- },
- targetProjectFullPath: {
- type: String,
- required: false,
- default: '',
- },
- projectId: {
- type: String,
- required: false,
- default: '',
- },
- mergeRequestId: {
- type: Number,
- required: false,
- default: 0,
- },
- },
-
- data() {
- const store = new PipelineStore();
-
- return {
- store,
- state: store.state,
- page: getParameterByName('page') || '1',
- requestData: {},
- modalId: 'create-pipeline-for-fork-merge-request-modal',
- };
- },
-
- computed: {
- shouldRenderTable() {
- return !this.isLoading && this.state.pipelines.length > 0 && !this.hasError;
- },
- shouldRenderErrorState() {
- return this.hasError && !this.isLoading;
- },
- shouldRenderEmptyState() {
- return this.state.pipelines.length === 0 && !this.shouldRenderErrorState;
- },
- /**
- * The "Run pipeline" button can only be rendered when:
- * - In MR view - we use `canCreatePipelineInTargetProject` for that purpose
- * - If the latest pipeline has the `detached_merge_request_pipeline` flag
- *
- * @returns {Boolean}
- */
- canRenderPipelineButton() {
- return this.latestPipelineDetachedFlag;
- },
- isForkMergeRequest() {
- return this.sourceProjectFullPath !== this.targetProjectFullPath;
- },
- isLatestPipelineCreatedInTargetProject() {
- const latest = this.state.pipelines[0];
-
- return latest?.project?.full_path === `/${this.targetProjectFullPath}`;
- },
- shouldShowSecurityWarning() {
- return (
- this.canCreatePipelineInTargetProject &&
- this.isForkMergeRequest &&
- !this.isLatestPipelineCreatedInTargetProject
- );
- },
- /**
- * Checks if either `detached_merge_request_pipeline` or
- * `merge_request_pipeline` are tru in the first
- * object in the pipelines array.
- *
- * @returns {Boolean}
- */
- latestPipelineDetachedFlag() {
- const latest = this.state.pipelines[0];
- return (
- latest &&
- latest.flags &&
- (latest.flags.detached_merge_request_pipeline || latest.flags.merge_request_pipeline)
- );
- },
- },
- created() {
- this.service = new PipelinesService(this.endpoint);
- this.requestData = { page: this.page };
- },
- methods: {
- successCallback(resp) {
- // depending of the endpoint the response can either bring a `pipelines` key or not.
- const pipelines = resp.data.pipelines || resp.data;
-
- this.store.storePagination(resp.headers);
- this.setCommonData(pipelines);
-
- if (resp.headers?.['x-total']) {
- const updatePipelinesEvent = new CustomEvent('update-pipelines-count', {
- detail: { pipelineCount: resp.headers['x-total'] },
- });
-
- // notifiy to update the count in tabs
- if (this.$el.parentElement) {
- this.$el.parentElement.dispatchEvent(updatePipelinesEvent);
- }
- }
- },
- /**
- * When the user clicks on the "Run pipeline" button
- * we need to make a post request and
- * to update the table content once the request is finished.
- *
- * We are emitting an event through the eventHub using the old pattern
- * to make use of the code in mixins/pipelines.js that handles all the
- * table events
- *
- */
- onClickRunPipeline() {
- eventHub.$emit('runMergeRequestPipeline', {
- projectId: this.projectId,
- mergeRequestId: this.mergeRequestId,
- });
- },
- tryRunPipeline() {
- if (!this.shouldShowSecurityWarning) {
- this.onClickRunPipeline();
- } else {
- this.$refs.modal.show();
- }
- },
- },
- modal: {
- actionPrimary: {
- text: s__('Pipeline|Run pipeline'),
- attributes: {
- variant: 'danger',
- },
- },
- actionCancel: {
- text: __('Cancel'),
- attributes: {
- variant: 'default',
- },
- },
- },
- i18n: {
- runPipelinePopoverTitle: s__('Pipeline|Run merge request pipeline'),
- runPipelinePopoverDescription: s__(
- 'Pipeline|To run a merge request pipeline, the jobs in the CI/CD configuration file %{linkStart}must be configured%{linkEnd} to run in merge request pipelines.',
- ),
- runPipelineText: s__('Pipeline|Run pipeline'),
- emptyStateTitle: s__('Pipelines|There are currently no pipelines.'),
- },
- mrPipelinesDocsPath: helpPagePath('ci/pipelines/merge_request_pipelines.md', {
- anchor: 'prerequisites',
- }),
- runPipelinesInTheParentProjectHelpPath: helpPagePath(
- '/ci/pipelines/merge_request_pipelines.html',
- {
- anchor: 'run-pipelines-in-the-parent-project',
- },
- ),
-};
-</script>
-<template>
- <div class="content-list pipelines">
- <gl-loading-icon
- v-if="isLoading"
- :label="s__('Pipelines|Loading pipelines')"
- size="lg"
- class="prepend-top-20"
- />
-
- <gl-empty-state
- v-else-if="shouldRenderErrorState"
- :svg-path="errorStateSvgPath"
- :title="
- s__(`Pipelines|There was an error fetching the pipelines.
- Try again in a few moments or contact your support team.`)
- "
- data-testid="pipeline-error-empty-state"
- />
- <template v-else-if="shouldRenderEmptyState">
- <gl-empty-state
- :svg-path="emptyStateSvgPath"
- :svg-height="150"
- :title="$options.i18n.emptyStateTitle"
- data-testid="pipeline-empty-state"
- >
- <template #description>
- <gl-sprintf :message="$options.i18n.runPipelinePopoverDescription">
- <template #link="{ content }">
- <gl-link
- :href="$options.mrPipelinesDocsPath"
- target="_blank"
- data-testid="mr-pipelines-docs-link"
- >{{ content }}</gl-link
- >
- </template>
- </gl-sprintf>
- </template>
-
- <template #actions>
- <div class="gl-vertical-align-middle">
- <gl-button
- variant="confirm"
- :loading="state.isRunningMergeRequestPipeline"
- data-testid="run_pipeline_button"
- @click="tryRunPipeline"
- >
- {{ $options.i18n.runPipelineText }}
- </gl-button>
- </div>
- </template>
- </gl-empty-state>
- </template>
-
- <div v-else-if="shouldRenderTable">
- <gl-button
- v-if="canRenderPipelineButton"
- block
- class="gl-mt-3 gl-mb-3 gl-lg-display-none"
- variant="confirm"
- data-testid="run_pipeline_button_mobile"
- :loading="state.isRunningMergeRequestPipeline"
- @click="tryRunPipeline"
- >
- {{ $options.i18n.runPipelineText }}
- </gl-button>
-
- <pipelines-table-component
- :pipelines="state.pipelines"
- :update-graph-dropdown="updateGraphDropdown"
- :view-type="viewType"
- :pipeline-key-option="$options.PipelineKeyOptions[0]"
- >
- <template #table-header-actions>
- <div v-if="canRenderPipelineButton" class="gl-text-right">
- <gl-button
- data-testid="run_pipeline_button"
- :loading="state.isRunningMergeRequestPipeline"
- @click="tryRunPipeline"
- >
- {{ $options.i18n.runPipelineText }}
- </gl-button>
- </div>
- </template>
- </pipelines-table-component>
- </div>
-
- <gl-modal
- v-if="canRenderPipelineButton || shouldRenderEmptyState"
- :id="modalId"
- ref="modal"
- :modal-id="modalId"
- :title="s__('Pipelines|Are you sure you want to run this pipeline?')"
- :action-primary="$options.modal.actionPrimary"
- :action-cancel="$options.modal.actionCancel"
- @primary="onClickRunPipeline"
- >
- <p>
- {{
- s__(
- 'Pipelines|This pipeline will run code originating from a forked project merge request. This means that the code can potentially have security considerations like exposing CI variables.',
- )
- }}
- </p>
- <p>
- {{
- s__(
- "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource.",
- )
- }}
- </p>
- <p>
- {{
- s__('Pipelines|If you are unsure, please ask a project maintainer to review it for you.')
- }}
- </p>
- <gl-link :href="$options.runPipelinesInTheParentProjectHelpPath" target="_blank">
- {{ s__('Pipelines|More Information') }}
- </gl-link>
- </gl-modal>
-
- <table-pagination
- v-if="shouldRenderPagination"
- :change="onChangePage"
- :page-info="state.pageInfo"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue b/app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue
+++ /dev/null
diff --git a/app/assets/javascripts/commons/gitlab_ui.js b/app/assets/javascripts/commons/gitlab_ui.js
new file mode 100644
index 00000000000..4a9f79460da
--- /dev/null
+++ b/app/assets/javascripts/commons/gitlab_ui.js
@@ -0,0 +1,10 @@
+import applyGitLabUIConfig from '@gitlab/ui/dist/config';
+import { __ } from '~/locale';
+
+applyGitLabUIConfig({
+ translations: {
+ 'GlSearchBoxByType.input.placeholder': __('Search'),
+ 'GlSearchBoxByType.clearButtonTitle': __('Clear'),
+ 'ClearIconButton.title': __('Clear'),
+ },
+});
diff --git a/app/assets/javascripts/commons/index.js b/app/assets/javascripts/commons/index.js
index 77c85d85e27..d2a5ef83faf 100644
--- a/app/assets/javascripts/commons/index.js
+++ b/app/assets/javascripts/commons/index.js
@@ -1,6 +1,7 @@
import './polyfills';
import './bootstrap';
import './vue';
+import './gitlab_ui';
import '../lib/utils/axios_utils';
import { openUserCountsBroadcast } from './nav/user_merge_requests';
diff --git a/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_created.vue b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_created.vue
index 7915cd6679d..fe9b2f81f85 100644
--- a/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_created.vue
+++ b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_created.vue
@@ -24,7 +24,7 @@ export default {
return this.event.resource_parent;
},
message() {
- if (!this.target) {
+ if (!this.target.type) {
return EVENT_CREATED_I18N[this.resourceParent.type] || EVENT_CREATED_I18N[TYPE_FALLBACK];
}
diff --git a/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_destroyed.vue b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_destroyed.vue
new file mode 100644
index 00000000000..11b6affb944
--- /dev/null
+++ b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_destroyed.vue
@@ -0,0 +1,28 @@
+<script>
+import { EVENT_DESTROYED_I18N, EVENT_DESTROYED_ICONS } from '../../constants';
+import { getValueByEventTarget } from '../../utils';
+import ContributionEventBase from './contribution_event_base.vue';
+
+export default {
+ name: 'ContributionEventDestroyed',
+ components: { ContributionEventBase },
+ props: {
+ event: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ message() {
+ return getValueByEventTarget(EVENT_DESTROYED_I18N, this.event);
+ },
+ iconName() {
+ return getValueByEventTarget(EVENT_DESTROYED_ICONS, this.event);
+ },
+ },
+};
+</script>
+
+<template>
+ <contribution-event-base :event="event" :message="message" :icon-name="iconName" />
+</template>
diff --git a/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_pushed.vue b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_pushed.vue
index 557f2912f17..a2516f37c92 100644
--- a/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_pushed.vue
+++ b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_pushed.vue
@@ -53,7 +53,8 @@ export default {
message() {
if (this.ref.is_new) {
return this.$options.i18n.new[this.ref.type];
- } else if (this.ref.is_removed) {
+ }
+ if (this.ref.is_removed) {
return this.$options.i18n.removed[this.ref.type];
}
diff --git a/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_updated.vue b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_updated.vue
new file mode 100644
index 00000000000..e795e611ee5
--- /dev/null
+++ b/app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_updated.vue
@@ -0,0 +1,25 @@
+<script>
+import { EVENT_UPDATED_I18N } from '../../constants';
+import { getValueByEventTarget } from '../../utils';
+import ContributionEventBase from './contribution_event_base.vue';
+
+export default {
+ name: 'ContributionEventUpdated',
+ components: { ContributionEventBase },
+ props: {
+ event: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ message() {
+ return getValueByEventTarget(EVENT_UPDATED_I18N, this.event);
+ },
+ },
+};
+</script>
+
+<template>
+ <contribution-event-base :event="event" :message="message" icon-name="pencil" />
+</template>
diff --git a/app/assets/javascripts/contribution_events/components/contribution_events.vue b/app/assets/javascripts/contribution_events/components/contribution_events.vue
index 8b42d77675f..f3116717783 100644
--- a/app/assets/javascripts/contribution_events/components/contribution_events.vue
+++ b/app/assets/javascripts/contribution_events/components/contribution_events.vue
@@ -12,6 +12,8 @@ import {
EVENT_TYPE_CLOSED,
EVENT_TYPE_REOPENED,
EVENT_TYPE_COMMENTED,
+ EVENT_TYPE_UPDATED,
+ EVENT_TYPE_DESTROYED,
} from '../constants';
import ContributionEventApproved from './contribution_event/contribution_event_approved.vue';
import ContributionEventExpired from './contribution_event/contribution_event_expired.vue';
@@ -24,6 +26,8 @@ import ContributionEventCreated from './contribution_event/contribution_event_cr
import ContributionEventClosed from './contribution_event/contribution_event_closed.vue';
import ContributionEventReopened from './contribution_event/contribution_event_reopened.vue';
import ContributionEventCommented from './contribution_event/contribution_event_commented.vue';
+import ContributionEventUpdated from './contribution_event/contribution_event_updated.vue';
+import ContributionEventDestroyed from './contribution_event/contribution_event_destroyed.vue';
export default {
props: {
@@ -151,6 +155,12 @@ export default {
case EVENT_TYPE_COMMENTED:
return ContributionEventCommented;
+ case EVENT_TYPE_UPDATED:
+ return ContributionEventUpdated;
+
+ case EVENT_TYPE_DESTROYED:
+ return ContributionEventDestroyed;
+
default:
return EmptyComponent;
}
diff --git a/app/assets/javascripts/contribution_events/components/target_link.vue b/app/assets/javascripts/contribution_events/components/target_link.vue
index a14574ed826..86fddbb063e 100644
--- a/app/assets/javascripts/contribution_events/components/target_link.vue
+++ b/app/assets/javascripts/contribution_events/components/target_link.vue
@@ -27,5 +27,5 @@ export default {
</script>
<template>
- <gl-link v-if="target" v-bind="targetLinkAttributes">{{ targetLinkText }}</gl-link>
+ <gl-link v-if="target.type" v-bind="targetLinkAttributes">{{ targetLinkText }}</gl-link>
</template>
diff --git a/app/assets/javascripts/contribution_events/constants.js b/app/assets/javascripts/contribution_events/constants.js
index b5eddbf7e25..c0224ce94ff 100644
--- a/app/assets/javascripts/contribution_events/constants.js
+++ b/app/assets/javascripts/contribution_events/constants.js
@@ -119,14 +119,31 @@ export const EVENT_COMMENTED_I18N = Object.freeze({
[COMMIT_NOTEABLE_TYPE]: s__(
'ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}.',
),
- fallback: s__('ContributionEvent|Commented on %{noteableLink}.'),
+ [TYPE_FALLBACK]: s__('ContributionEvent|Commented on %{noteableLink}.'),
});
export const EVENT_COMMENTED_SNIPPET_I18N = Object.freeze({
[RESOURCE_PARENT_TYPE_PROJECT]: s__(
'ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}.',
),
- fallback: s__('ContributionEvent|Commented on snippet %{noteableLink}.'),
+ [TYPE_FALLBACK]: s__('ContributionEvent|Commented on snippet %{noteableLink}.'),
+});
+
+export const EVENT_UPDATED_I18N = Object.freeze({
+ [TARGET_TYPE_DESIGN]: s__(
+ 'ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}.',
+ ),
+ [TARGET_TYPE_WIKI]: s__(
+ 'ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}.',
+ ),
+ [TYPE_FALLBACK]: s__('ContributionEvent|Updated resource.'),
+});
+
+export const EVENT_DESTROYED_I18N = Object.freeze({
+ [TARGET_TYPE_DESIGN]: s__('ContributionEvent|Archived design in %{resourceParentLink}.'),
+ [TARGET_TYPE_WIKI]: s__('ContributionEvent|Deleted wiki page in %{resourceParentLink}.'),
+ [TARGET_TYPE_MILESTONE]: s__('ContributionEvent|Deleted milestone in %{resourceParentLink}.'),
+ [TYPE_FALLBACK]: s__('ContributionEvent|Deleted resource.'),
});
export const EVENT_CLOSED_ICONS = Object.freeze({
@@ -139,3 +156,8 @@ export const EVENT_REOPENED_ICONS = Object.freeze({
[TARGET_TYPE_MERGE_REQUEST]: 'merge-request-open',
[TYPE_FALLBACK]: 'status_open',
});
+
+export const EVENT_DESTROYED_ICONS = Object.freeze({
+ [TARGET_TYPE_DESIGN]: 'archive',
+ [TYPE_FALLBACK]: 'remove',
+});
diff --git a/app/assets/javascripts/create_item_dropdown.js b/app/assets/javascripts/create_item_dropdown.js
index b39720c6094..08c2e235819 100644
--- a/app/assets/javascripts/create_item_dropdown.js
+++ b/app/assets/javascripts/create_item_dropdown.js
@@ -114,4 +114,8 @@ export default class CreateItemDropdown {
toggleFooter(toggleState) {
this.$dropdownFooter.toggleClass('hidden', toggleState);
}
+
+ close() {
+ this.$dropdown.data('deprecatedJQueryDropdown')?.close();
+ }
}
diff --git a/app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue b/app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue
index a56fce98f85..ccf4b064fa4 100644
--- a/app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue
+++ b/app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue
@@ -249,7 +249,12 @@ export default {
:description="$options.translations.addTokenNameDescription"
label-for="deploy_token_name"
>
- <gl-form-input id="deploy_token_name" v-model="name" name="deploy_token_name" />
+ <gl-form-input
+ id="deploy_token_name"
+ v-model="name"
+ class="gl-form-input-xl"
+ name="deploy_token_name"
+ />
</gl-form-group>
<gl-form-group
:label="$options.translations.addTokenExpiryLabel"
@@ -258,6 +263,7 @@ export default {
>
<gl-form-input
id="deploy_token_expires_at"
+ class="gl-form-input-xl"
name="deploy_token_expires_at"
:value="formattedExpiryDate"
data-qa-selector="deploy_token_expires_at_field"
@@ -277,7 +283,7 @@ export default {
</template>
</gl-sprintf>
</template>
- <gl-form-input id="deploy_token_username" v-model="username" />
+ <gl-form-input id="deploy_token_username" v-model="username" class="gl-form-input-xl" />
</gl-form-group>
<gl-form-group
:label="$options.translations.addTokenScopesLabel"
diff --git a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js
index 69f1d62539a..3f14a8a8a26 100644
--- a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js
+++ b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown.js
@@ -94,6 +94,7 @@ export class GitLabDropdown {
dataType: this.options.dataType,
beforeSend: this.toggleLoading.bind(this),
success: (data) => {
+ this.dropdown.trigger('done.remote.loading.gl.dropdown');
this.fullData = data;
this.parseData(this.fullData);
this.focusTextInput();
@@ -220,7 +221,12 @@ export class GitLabDropdown {
}
toggleLoading() {
- return $('.dropdown-menu', this.dropdown).toggleClass(LOADING_CLASS);
+ const menu = this.dropdown[0].querySelector('.dropdown-menu');
+ const isLoading = menu.classList.contains(LOADING_CLASS);
+
+ this.dropdown.trigger(`toggle.${isLoading ? 'off' : 'on'}.loading.gl.dropdown`);
+
+ menu.classList.toggle(LOADING_CLASS);
}
togglePage() {
@@ -719,4 +725,8 @@ export class GitLabDropdown {
clearField(field, isInput) {
return isInput ? field.val('') : field.remove();
}
+
+ close() {
+ this.dropdown.find('.dropdown-menu-toggle').dropdown('hide');
+ }
}
diff --git a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_filter.js b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_filter.js
index 2cb9e9a56a3..271347feebd 100644
--- a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_filter.js
+++ b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_filter.js
@@ -17,9 +17,11 @@ export class GitLabDropdownFilter {
const $inputContainer = this.input.parent();
const $clearButton = $inputContainer.find('.js-dropdown-input-clear');
const filterRemoteDebounced = debounce(() => {
+ options.instance.dropdown.trigger('filtering.gl.dropdown');
$inputContainer.parent().addClass('is-loading');
return this.options.query(this.input.val(), (data) => {
+ options.instance.dropdown.trigger('done.filtering.gl.dropdown');
$inputContainer.parent().removeClass('is-loading');
return this.options.callback(data);
});
diff --git a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_remote.js b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_remote.js
index ae5d3298b62..bacd84048af 100644
--- a/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_remote.js
+++ b/app/assets/javascripts/deprecated_jquery_dropdown/gl_dropdown_remote.js
@@ -11,7 +11,8 @@ export class GitLabDropdownRemote {
execute() {
if (typeof this.dataEndpoint === 'string') {
return this.fetchData();
- } else if (typeof this.dataEndpoint === 'function') {
+ }
+ if (typeof this.dataEndpoint === 'function') {
if (this.options.beforeSend) {
this.options.beforeSend();
}
diff --git a/app/assets/javascripts/deprecated_jquery_dropdown/index.js b/app/assets/javascripts/deprecated_jquery_dropdown/index.js
index 6a3d2026192..38236707e06 100644
--- a/app/assets/javascripts/deprecated_jquery_dropdown/index.js
+++ b/app/assets/javascripts/deprecated_jquery_dropdown/index.js
@@ -5,7 +5,10 @@ export default function initDeprecatedJQueryDropdown($el, opts) {
// eslint-disable-next-line func-names
return $el.each(function () {
if (!$.data(this, 'deprecatedJQueryDropdown')) {
- $.data(this, 'deprecatedJQueryDropdown', new GitLabDropdown(this, opts));
+ const instance = new GitLabDropdown(this, opts);
+
+ $.data(this, 'deprecatedJQueryDropdown', instance);
+ this.GitLabDropdownInstance = instance;
}
});
}
diff --git a/app/assets/javascripts/deprecated_jquery_dropdown/render.js b/app/assets/javascripts/deprecated_jquery_dropdown/render.js
index 97698d55011..1b133c57302 100644
--- a/app/assets/javascripts/deprecated_jquery_dropdown/render.js
+++ b/app/assets/javascripts/deprecated_jquery_dropdown/render.js
@@ -89,7 +89,8 @@ function checkSelected(data, options) {
if (!options.parent) {
return !data.id;
- } else if (value) {
+ }
+ if (value) {
return (
options.parent.querySelector(`input[name='${options.fieldName}'][value='${value}']`) != null
);
diff --git a/app/assets/javascripts/deprecated_notes.js b/app/assets/javascripts/deprecated_notes.js
index 4e5e07c57e4..008e12abbcd 100644
--- a/app/assets/javascripts/deprecated_notes.js
+++ b/app/assets/javascripts/deprecated_notes.js
@@ -458,7 +458,8 @@ export default class Notes {
this.setupNewNote($newNote);
this.refresh();
return this.updateNotesCount(1);
- } else if (Notes.isUpdatedNote(noteEntity, $note)) {
+ }
+ if (Notes.isUpdatedNote(noteEntity, $note)) {
// The server can send the same update multiple times so we need to make sure to only update once per actual update.
const isEditing = $note.hasClass('is-editing');
const initialContent = normalizeNewlines($note.find('.original-note-content').text().trim());
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index e3882ce42c2..08306312c2e 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -19,7 +19,6 @@ import { parseBoolean } from '~/lib/utils/common_utils';
import { Mousetrap } from '~/lib/mousetrap';
import { updateHistory } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import notesEventHub from '~/notes/event_hub';
import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller';
@@ -76,7 +75,6 @@ export default {
GenerateTestFileDrawer: () =>
import('ee_component/ai/components/generate_test_file_drawer.vue'),
},
- mixins: [glFeatureFlagsMixin()],
alerts: {
ALERT_OVERFLOW_HIDDEN,
ALERT_MERGE_CONFLICT,
@@ -580,11 +578,7 @@ export default {
<template>
<div v-show="shouldShow">
- <findings-drawer
- v-if="glFeatures.codeQualityInlineDrawer"
- :drawer="activeDrawer"
- @close="closeDrawer"
- />
+ <findings-drawer :drawer="activeDrawer" @close="closeDrawer" />
<div v-if="isLoading || !isTreeLoaded" class="loading"><gl-loading-icon size="lg" /></div>
<div v-else id="diffs" :class="{ active: shouldShow }" class="diffs tab-pane">
<compare-versions :diff-files-count-text="numTotalFiles" />
@@ -631,6 +625,7 @@ export default {
<template #default="{ item, index, active }">
<dynamic-scroller-item :item="item" :active="active" :class="{ active }">
<diff-file
+ v-if="active"
:file="item"
:reviewed="fileReviews[item.id]"
:is-first-file="index === 0"
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index d62d0e11bff..a9e63ad53bb 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -337,7 +337,7 @@ export default {
:title="filePath"
class="file-title-name"
data-container="body"
- data-qa-selector="file_name_content"
+ data-testid="file-name-content"
>
{{ filePath }}
</strong>
diff --git a/app/assets/javascripts/diffs/components/diff_inline_findings_item.vue b/app/assets/javascripts/diffs/components/diff_inline_findings_item.vue
index 5cc2a3079b0..8a30d6ee7f8 100644
--- a/app/assets/javascripts/diffs/components/diff_inline_findings_item.vue
+++ b/app/assets/javascripts/diffs/components/diff_inline_findings_item.vue
@@ -1,23 +1,15 @@
<script>
-import { GlLink, GlIcon } from '@gitlab/ui';
-// eslint-disable-next-line no-restricted-imports
-import { mapActions } from 'vuex';
+import { GlIcon } from '@gitlab/ui';
import { getSeverity } from '~/ci/reports/utils';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
- components: { GlLink, GlIcon },
- mixins: [glFeatureFlagsMixin()],
+ components: { GlIcon },
+
props: {
finding: {
type: Object,
required: true,
},
- link: {
- type: Boolean,
- required: false,
- default: true,
- },
},
computed: {
enhancedFinding() {
@@ -27,12 +19,6 @@ export default {
return `${this.finding.severity} - ${this.finding.description}`;
},
},
- methods: {
- toggleDrawer() {
- this.setDrawer(this.finding);
- },
- ...mapActions('findingsDrawer', ['setDrawer']),
- },
};
</script>
@@ -46,17 +32,7 @@ export default {
class="inline-findings-severity-icon"
/>
</span>
- <span
- v-if="glFeatures.codeQualityInlineDrawer"
- data-testid="description-button-section"
- class="gl-display-flex"
- >
- <gl-link v-if="link" category="primary" variant="link" @click="toggleDrawer">
- {{ listText }}</gl-link
- >
- <span v-else>{{ listText }}</span>
- </span>
- <span v-else data-testid="description-plain-text" class="gl-display-flex">
+ <span data-testid="description-plain-text" class="gl-display-flex">
{{ listText }}
</span>
</li>
diff --git a/app/assets/javascripts/diffs/components/diff_row.vue b/app/assets/javascripts/diffs/components/diff_row.vue
index 318ecc89d14..ee6e9a2fc94 100644
--- a/app/assets/javascripts/diffs/components/diff_row.vue
+++ b/app/assets/javascripts/diffs/components/diff_row.vue
@@ -24,8 +24,8 @@ import * as utils from './diff_row_utils';
export default {
DiffGutterAvatars,
- InlineFindingsGutterIcon: () =>
- import('ee_component/diffs/components/inline_findings_gutter_icon.vue'),
+ InlineFindingsFlagSwitcher: () =>
+ import('ee_component/diffs/components/inline_findings_flag_switcher.vue'),
// Temporary mixin for migration from Vue.js 2 to @vue/compat
mixins: [compatFunctionalMixin],
@@ -338,10 +338,11 @@ export default {
:class="$options.parallelViewLeftLineType(props)"
>
<component
- :is="$options.InlineFindingsGutterIcon"
+ :is="$options.InlineFindingsFlagSwitcher"
v-if="$options.showCodequalityLeft(props) || $options.showSecurityLeft(props)"
:inline-findings-expanded="props.inlineFindingsExpanded"
- :codequality="props.line.left.codequality"
+ :code-quality="props.line.left.codequality"
+ :sast="props.line.left.sast"
:file-path="props.filePath"
@showInlineFindings="
listeners.toggleCodeQualityFindings(
@@ -479,9 +480,10 @@ export default {
:class="$options.classNameMapCellRight(props)"
>
<component
- :is="$options.InlineFindingsGutterIcon"
+ :is="$options.InlineFindingsFlagSwitcher"
v-if="$options.showCodequalityRight(props) || $options.showSecurityRight(props)"
- :codequality="props.line.right.codequality"
+ :code-quality="props.line.right.codequality"
+ :sast="props.line.right.sast"
:file-path="props.filePath"
data-testid="inlineFindingsIcon"
@showInlineFindings="
diff --git a/app/assets/javascripts/diffs/components/diff_view.vue b/app/assets/javascripts/diffs/components/diff_view.vue
index 88ea4e15552..641616a34f5 100644
--- a/app/assets/javascripts/diffs/components/diff_view.vue
+++ b/app/assets/javascripts/diffs/components/diff_view.vue
@@ -186,7 +186,8 @@ export default {
getCountBetweenIndex(index) {
if (index === 0) {
return -1;
- } else if (!this.diffLines[index + 1]) {
+ }
+ if (!this.diffLines[index + 1]) {
return -1;
}
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index bbc602aedf6..7c68b5f69f1 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -910,7 +910,8 @@ export const setSuggestPopoverDismissed = ({ commit, state }) =>
export function changeCurrentCommit({ dispatch, commit, state }, { commitId }) {
if (!commitId) {
return Promise.reject(new Error('`commitId` is a required argument'));
- } else if (!state.commit) {
+ }
+ if (!state.commit) {
return Promise.reject(new Error('`state` must already contain a valid `commit`')); // eslint-disable-line @gitlab/require-i18n-strings
}
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index d82959daa9d..bfafb4d281d 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -139,7 +139,8 @@ export const fileLineCoverage = (state) => (file, line) => {
if (lineCoverage === 0) {
return { text: __('No test coverage'), class: 'no-coverage' };
- } else if (lineCoverage >= 0) {
+ }
+ if (lineCoverage >= 0) {
return {
text: n__('Test coverage: %d hit', 'Test coverage: %d hits', lineCoverage),
class: 'coverage',
diff --git a/app/assets/javascripts/drawio/drawio_editor.js b/app/assets/javascripts/drawio/drawio_editor.js
index 3c411d8093c..37bfde0ed9f 100644
--- a/app/assets/javascripts/drawio/drawio_editor.js
+++ b/app/assets/javascripts/drawio/drawio_editor.js
@@ -1,6 +1,7 @@
import _ from 'lodash';
import { createAlert, VARIANT_SUCCESS } from '~/alert';
import { darkModeEnabled } from '~/lib/utils/color_utils';
+import { base64DecodeUnicode } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
import { setAttributes } from '~/lib/utils/dom_utils';
import {
@@ -28,7 +29,7 @@ function disposeDrawioEditor(drawIOEditorState) {
}
function getSvg(data) {
- const svgPath = atob(data.substring(data.indexOf(',') + 1));
+ const svgPath = base64DecodeUnicode(data.substring(data.indexOf(',') + 1));
return `<?xml version="1.0" encoding="UTF-8"?>\n\
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n\
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index 65091487c93..2dba919cf58 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -845,6 +845,9 @@
"if": {
"$ref": "#/definitions/if"
},
+ "changes": {
+ "$ref": "#/definitions/changes"
+ },
"exists": {
"$ref": "#/definitions/exists"
},
@@ -2084,6 +2087,10 @@
"publish": {
"description": "A path to a directory that contains the files to be published with Pages",
"type": "string"
+ },
+ "pages_path_prefix": {
+ "description": "The path prefix identifier for this version of pages. Allows creation of multiple versions of the same site with different path prefixes",
+ "type": "string"
}
},
"oneOf": [
diff --git a/app/assets/javascripts/entrypoints/analytics.js b/app/assets/javascripts/entrypoints/analytics.js
new file mode 100644
index 00000000000..8eb265cb1e8
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/analytics.js
@@ -0,0 +1,17 @@
+import { glClientSDK } from '@gitlab/application-sdk-browser';
+
+const { analytics_id: appId, analytics_url: host } = window.gon;
+
+if (appId && host) {
+ window.glClient = glClientSDK({
+ appId,
+ host,
+ hasCookieConsent: true,
+ plugins: {
+ clientHints: false,
+ linkTracking: false,
+ performanceTiming: false,
+ errorTracking: false,
+ },
+ });
+}
diff --git a/app/assets/javascripts/entrypoints/jira_connect_app.js b/app/assets/javascripts/entrypoints/jira_connect_app.js
new file mode 100644
index 00000000000..90ad39ea487
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/jira_connect_app.js
@@ -0,0 +1 @@
+import '../jira_connect/subscriptions';
diff --git a/app/assets/javascripts/entrypoints/main.js b/app/assets/javascripts/entrypoints/main.js
new file mode 100644
index 00000000000..6d59e89cfd0
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/main.js
@@ -0,0 +1,6 @@
+import '../main';
+import { runModules } from '~/run_modules';
+
+const modules = import.meta.glob('../pages/**/index.js');
+
+runModules(modules, '../pages/');
diff --git a/app/assets/javascripts/entrypoints/main_ee.js b/app/assets/javascripts/entrypoints/main_ee.js
new file mode 100644
index 00000000000..4a83be6be94
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/main_ee.js
@@ -0,0 +1,5 @@
+import { runModules } from '~/run_modules';
+
+const modules = import.meta.glob('../../../../ee/app/assets/javascripts/pages/**/index.js');
+
+runModules(modules, '../../../../ee/app/assets/javascripts/pages/');
diff --git a/app/assets/javascripts/entrypoints/main_jh.js b/app/assets/javascripts/entrypoints/main_jh.js
new file mode 100644
index 00000000000..92a42a9ac70
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/main_jh.js
@@ -0,0 +1,5 @@
+import { runModules } from '~/run_modules';
+
+const modules = import.meta.glob('../../../../jh/app/assets/javascripts/pages/**/index.js');
+
+runModules(modules, '../../../../jh/app/assets/javascripts/pages/');
diff --git a/app/assets/javascripts/entrypoints/performance_bar.js b/app/assets/javascripts/entrypoints/performance_bar.js
new file mode 100644
index 00000000000..3f6fc6272d0
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/performance_bar.js
@@ -0,0 +1 @@
+import '../performance_bar';
diff --git a/app/assets/javascripts/entrypoints/redirect_listbox.js b/app/assets/javascripts/entrypoints/redirect_listbox.js
new file mode 100644
index 00000000000..811a73fbf2f
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/redirect_listbox.js
@@ -0,0 +1 @@
+import './behaviors/redirect_listbox';
diff --git a/app/assets/javascripts/entrypoints/sandboxed_mermaid.js b/app/assets/javascripts/entrypoints/sandboxed_mermaid.js
new file mode 100644
index 00000000000..d3dd144ffba
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/sandboxed_mermaid.js
@@ -0,0 +1 @@
+import '../lib/mermaid';
diff --git a/app/assets/javascripts/entrypoints/sentry.js b/app/assets/javascripts/entrypoints/sentry.js
new file mode 100644
index 00000000000..debafc6fab3
--- /dev/null
+++ b/app/assets/javascripts/entrypoints/sentry.js
@@ -0,0 +1 @@
+import '../sentry/index';
diff --git a/app/assets/javascripts/environments/components/deployment.vue b/app/assets/javascripts/environments/components/deployment.vue
index 96d2a8d9ba2..ef6d3b79198 100644
--- a/app/assets/javascripts/environments/components/deployment.vue
+++ b/app/assets/javascripts/environments/components/deployment.vue
@@ -209,7 +209,7 @@ export default {
</div>
<time-ago-tooltip v-if="createdAt" :time="createdAt" class="gl-display-flex">
<template #default="{ timeAgo }">
- <gl-icon name="calendar" />
+ <gl-icon name="calendar" class="gl-mr-2" />
<span class="gl-mr-2 gl-white-space-nowrap">{{ timeAgo }}</span>
</template>
</time-ago-tooltip>
diff --git a/app/assets/javascripts/environments/components/edit_environment.vue b/app/assets/javascripts/environments/components/edit_environment.vue
index f90a1dcd193..0eebd81b671 100644
--- a/app/assets/javascripts/environments/components/edit_environment.vue
+++ b/app/assets/javascripts/environments/components/edit_environment.vue
@@ -4,7 +4,6 @@ import { createAlert } from '~/alert';
import { visitUrl } from '~/lib/utils/url_utility';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import getEnvironment from '../graphql/queries/environment.query.graphql';
-import getEnvironmentWithFluxResource from '../graphql/queries/environment_with_flux_resource.query.graphql';
import updateEnvironment from '../graphql/mutations/update_environment.mutation.graphql';
import EnvironmentForm from './environment_form.vue';
@@ -17,11 +16,7 @@ export default {
inject: ['projectEnvironmentsPath', 'projectPath', 'environmentName'],
apollo: {
environment: {
- query() {
- return this.glFeatures?.fluxResourceForEnvironment
- ? getEnvironmentWithFluxResource
- : getEnvironment;
- },
+ query: getEnvironment,
variables() {
return {
environmentName: this.environmentName,
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index d49598d2f21..926c556966c 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -87,7 +87,7 @@ export default {
</script>
<template>
<gl-disclosure-dropdown
- :text="title"
+ :toggle-text="title"
:title="title"
:loading="isLoading"
:aria-label="title"
diff --git a/app/assets/javascripts/environments/components/environment_form.vue b/app/assets/javascripts/environments/components/environment_form.vue
index d89dcf56b7c..846f2cf73b2 100644
--- a/app/assets/javascripts/environments/components/environment_form.vue
+++ b/app/assets/javascripts/environments/components/environment_form.vue
@@ -181,13 +181,8 @@ export default {
namespaceDropdownToggleText() {
return this.selectedNamespace || this.$options.i18n.namespaceHelpText;
},
- isKasFluxResourceAvailable() {
- return this.glFeatures?.fluxResourceForEnvironment;
- },
showFluxResourceSelector() {
- return Boolean(
- this.isKasFluxResourceAvailable && this.selectedNamespace && this.selectedAgentId,
- );
+ return Boolean(this.selectedNamespace && this.selectedAgentId);
},
k8sAccessConfiguration() {
if (!this.showNamespaceSelector) {
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index b02142c24cf..08a1eacec7a 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -1,6 +1,6 @@
<script>
import {
- GlDropdown,
+ GlDisclosureDropdown,
GlTooltipDirective,
GlIcon,
GlLink,
@@ -24,7 +24,6 @@ import PinComponent from './environment_pin.vue';
import RollbackComponent from './environment_rollback.vue';
import StopComponent from './environment_stop.vue';
import TerminalButtonComponent from './environment_terminal_button.vue';
-
/**
* Environment Item Component
*
@@ -36,7 +35,7 @@ export default {
ActionsComponent,
CommitComponent,
ExternalUrlComponent,
- GlDropdown,
+ GlDisclosureDropdown,
GlBadge,
GlIcon,
GlLink,
@@ -820,13 +819,13 @@ export default {
data-track-label="environment_stop"
/>
- <gl-dropdown
- v-if="hasExtraActions"
- icon="ellipsis_v"
+ <gl-disclosure-dropdown
text-sr-only
- :text="__('More actions')"
- category="secondary"
no-caret
+ icon="ellipsis_v"
+ category="secondary"
+ placement="right"
+ :toggle-text="__('More actions')"
>
<rollback-component
v-if="canRetry"
@@ -857,7 +856,7 @@ export default {
data-track-action="click_button"
data-track-label="environment_delete"
/>
- </gl-dropdown>
+ </gl-disclosure-dropdown>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/environments/components/kubernetes_status_bar.vue b/app/assets/javascripts/environments/components/kubernetes_status_bar.vue
index e8857dfe459..c603d83db9c 100644
--- a/app/assets/javascripts/environments/components/kubernetes_status_bar.vue
+++ b/app/assets/javascripts/environments/components/kubernetes_status_bar.vue
@@ -145,15 +145,20 @@ export default {
syncStatusBadge() {
if (!this.fluxCRD.length && this.fluxApiError) {
return { ...SYNC_STATUS_BADGES.unavailable, popoverText: this.fluxApiError };
- } else if (!this.fluxCRD.length) {
+ }
+ if (!this.fluxCRD.length) {
return SYNC_STATUS_BADGES.unavailable;
- } else if (this.fluxAnyFailed) {
+ }
+ if (this.fluxAnyFailed) {
return { ...SYNC_STATUS_BADGES.failed, popoverText: this.fluxAnyFailed.message };
- } else if (this.fluxAnyStalled) {
+ }
+ if (this.fluxAnyStalled) {
return { ...SYNC_STATUS_BADGES.stalled, popoverText: this.fluxAnyStalled.message };
- } else if (this.fluxAnyReconciling) {
+ }
+ if (this.fluxAnyReconciling) {
return SYNC_STATUS_BADGES.reconciling;
- } else if (this.fluxAnyReconciled) {
+ }
+ if (this.fluxAnyReconciled) {
return SYNC_STATUS_BADGES.reconciled;
}
return SYNC_STATUS_BADGES.unknown;
diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue
index 2148343f690..149cab21acd 100644
--- a/app/assets/javascripts/environments/components/new_environment_item.vue
+++ b/app/assets/javascripts/environments/components/new_environment_item.vue
@@ -14,7 +14,6 @@ import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import isLastDeployment from '../graphql/queries/is_last_deployment.query.graphql';
import getEnvironmentClusterAgent from '../graphql/queries/environment_cluster_agent.query.graphql';
-import getEnvironmentClusterAgentWithFluxResource from '../graphql/queries/environment_cluster_agent_with_flux_resource.query.graphql';
import ExternalUrl from './environment_external_url.vue';
import Actions from './environment_actions.vue';
import StopComponent from './environment_stop.vue';
@@ -165,9 +164,6 @@ export default {
rolloutStatus() {
return this.environment?.rolloutStatus;
},
- isFluxResourceAvailable() {
- return this.glFeatures?.fluxResourceForEnvironment;
- },
},
methods: {
toggleEnvironmentCollapse() {
@@ -185,9 +181,7 @@ export default {
return { environmentName: this.environment.name, projectFullPath: this.projectPath };
},
query() {
- return this.isFluxResourceAvailable
- ? getEnvironmentClusterAgentWithFluxResource
- : getEnvironmentClusterAgent;
+ return getEnvironmentClusterAgent;
},
update(data) {
this.clusterAgent = data?.project?.environment?.clusterAgent;
diff --git a/app/assets/javascripts/environments/environment_details/deployments_table.vue b/app/assets/javascripts/environments/environment_details/deployments_table.vue
index f37f93798ae..261d8106438 100644
--- a/app/assets/javascripts/environments/environment_details/deployments_table.vue
+++ b/app/assets/javascripts/environments/environment_details/deployments_table.vue
@@ -36,7 +36,7 @@ export default {
<deployment-status-link :deployment-job="item.job" :status="item.status" />
</template>
<template #cell(id)="{ item }">
- <strong>{{ item.id }}</strong>
+ <strong data-testid="deployment-id">{{ item.id }}</strong>
</template>
<template #cell(triggerer)="{ item }">
<deployment-triggerer :triggerer="item.triggerer" />
diff --git a/app/assets/javascripts/environments/graphql/queries/environment.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment.query.graphql
index 53dfe5303f3..2d6faed5c88 100644
--- a/app/assets/javascripts/environments/graphql/queries/environment.query.graphql
+++ b/app/assets/javascripts/environments/graphql/queries/environment.query.graphql
@@ -6,6 +6,7 @@ query getEnvironment($projectFullPath: ID!, $environmentName: String) {
name
externalUrl
kubernetesNamespace
+ fluxResourcePath
clusterAgent {
id
name
diff --git a/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql
index 19374ae7a81..3f8874f2a8d 100644
--- a/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql
+++ b/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent.query.graphql
@@ -3,6 +3,7 @@ query getEnvironmentClusterAgent($projectFullPath: ID!, $environmentName: String
id
environment(name: $environmentName) {
id
+ fluxResourcePath
kubernetesNamespace
clusterAgent {
id
diff --git a/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent_with_flux_resource.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent_with_flux_resource.query.graphql
deleted file mode 100644
index 80363a06d42..00000000000
--- a/app/assets/javascripts/environments/graphql/queries/environment_cluster_agent_with_flux_resource.query.graphql
+++ /dev/null
@@ -1,21 +0,0 @@
-query getEnvironmentClusterAgentWithFluxResource($projectFullPath: ID!, $environmentName: String) {
- project(fullPath: $projectFullPath) {
- id
- environment(name: $environmentName) {
- id
- kubernetesNamespace
- fluxResourcePath
- clusterAgent {
- id
- name
- webPath
- tokens {
- nodes {
- id
- lastUsedAt
- }
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/environments/graphql/queries/environment_with_flux_resource.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment_with_flux_resource.query.graphql
deleted file mode 100644
index 166cd64189f..00000000000
--- a/app/assets/javascripts/environments/graphql/queries/environment_with_flux_resource.query.graphql
+++ /dev/null
@@ -1,16 +0,0 @@
-query getEnvironmentWithFluxResource($projectFullPath: ID!, $environmentName: String) {
- project(fullPath: $projectFullPath) {
- id
- environment(name: $environmentName) {
- id
- name
- externalUrl
- kubernetesNamespace
- fluxResourcePath
- clusterAgent {
- id
- name
- }
- }
- }
-}
diff --git a/app/assets/javascripts/environments/mixins/environments_pagination_api_mixin.js b/app/assets/javascripts/environments/mixins/environments_pagination_api_mixin.js
index 55e2536e283..a64cc0405bb 100644
--- a/app/assets/javascripts/environments/mixins/environments_pagination_api_mixin.js
+++ b/app/assets/javascripts/environments/mixins/environments_pagination_api_mixin.js
@@ -3,7 +3,7 @@
*
* Components need to have `scope`, `page` and `requestData`
*/
-import { validateParams } from '~/pipelines/utils';
+import { validateParams } from '~/ci/pipeline_details/utils';
import { historyPushState, buildUrlWithCurrentLocation } from '~/lib/utils/common_utils';
export default {
diff --git a/app/assets/javascripts/environments/mount_show.js b/app/assets/javascripts/environments/mount_show.js
index fb9a7a02d07..9924e1c7d7b 100644
--- a/app/assets/javascripts/environments/mount_show.js
+++ b/app/assets/javascripts/environments/mount_show.js
@@ -59,9 +59,6 @@ export const initHeader = () => {
};
export const initPage = async () => {
- if (!gon.features.environmentDetailsVue) {
- return null;
- }
const EnvironmentsDetailPageModule = await import('./environment_details/index.vue');
const EnvironmentsDetailPage = EnvironmentsDetailPageModule.default;
const dataElement = document.getElementById('environments-detail-view');
diff --git a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
index 420c34a88f1..ad80ee099ad 100644
--- a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
+++ b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
@@ -1,25 +1,15 @@
<script>
-import {
- GlDropdown,
- GlDropdownDivider,
- GlDropdownItem,
- GlIcon,
- GlLoadingIcon,
- GlSearchBoxByType,
-} from '@gitlab/ui';
-import { debounce } from 'lodash';
+import { GlCollapsibleListbox, GlButton } from '@gitlab/ui';
+import { debounce, memoize } from 'lodash';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
-import { __, sprintf } from '~/locale';
+import { __, n__, sprintf } from '~/locale';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
export default {
components: {
- GlDropdown,
- GlDropdownDivider,
- GlDropdownItem,
- GlSearchBoxByType,
- GlIcon,
- GlLoadingIcon,
+ GlButton,
+ GlCollapsibleListbox,
},
inject: ['environmentsEndpoint'],
data() {
@@ -34,69 +24,96 @@ export default {
noResultsLabel: __('No matching results'),
},
computed: {
+ srOnlyResultsCount() {
+ return n__('%d environment found', '%d environments found', this.results.length);
+ },
createEnvironmentLabel() {
return sprintf(__('Create %{environment}'), { environment: this.environmentSearch });
},
+ isCreateEnvironmentShown() {
+ return !this.isLoading && this.results.length === 0 && Boolean(this.environmentSearch);
+ },
+ },
+ mounted() {
+ this.fetchEnvironments();
+ },
+ unmounted() {
+ // cancel debounce if the component is unmounted to avoid unnecessary fetches
+ this.fetchEnvironments.cancel();
+ },
+ created() {
+ this.fetch = memoize(async function fetchEnvironmentsFromApi(query) {
+ this.isLoading = true;
+ try {
+ const { data } = await axios.get(this.environmentsEndpoint, { params: { query } });
+
+ return data;
+ } catch {
+ createAlert({
+ message: __('Something went wrong on our end. Please try again.'),
+ });
+ return [];
+ } finally {
+ this.isLoading = false;
+ }
+ });
+
+ this.fetchEnvironments = debounce(function debouncedFetchEnvironments(query = '') {
+ this.fetch(query)
+ .then((data) => {
+ this.results = data.map((item) => ({ text: item, value: item }));
+ })
+ .catch(() => {
+ this.results = [];
+ });
+ }, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
},
methods: {
+ onSelect(selected) {
+ this.$emit('add', selected[0]);
+ },
addEnvironment(newEnvironment) {
this.$emit('add', newEnvironment);
- this.environmentSearch = '';
this.results = [];
},
- fetchEnvironments: debounce(function debouncedFetchEnvironments() {
- this.isLoading = true;
- axios
- .get(this.environmentsEndpoint, { params: { query: this.environmentSearch } })
- .then(({ data }) => {
- this.results = data || [];
- })
- .catch(() => {
- createAlert({
- message: __('Something went wrong on our end. Please try again.'),
- });
- })
- .finally(() => {
- this.isLoading = false;
- });
- }, 250),
- setFocus() {
- this.$refs.searchBox.focusInput();
+ onSearch(query) {
+ this.environmentSearch = query;
+ this.fetchEnvironments(query);
},
},
};
</script>
<template>
- <gl-dropdown class="js-new-environments-dropdown" @shown="setFocus">
- <template #button-content>
- <span class="d-md-none mr-1">
- {{ $options.translations.addEnvironmentsLabel }}
- </span>
- <gl-icon class="d-none d-md-inline-flex gl-mr-1" name="plus" />
+ <gl-collapsible-listbox
+ icon="plus"
+ data-testid="new-environments-dropdown"
+ :toggle-text="$options.translations.addEnvironmentsLabel"
+ :items="results"
+ :searching="isLoading"
+ :header-text="$options.translations.addEnvironmentsLabel"
+ searchable
+ multiple
+ @search="onSearch"
+ @select="onSelect"
+ >
+ <template #footer>
+ <div
+ v-if="isCreateEnvironmentShown"
+ class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-200 gl-p-2"
+ >
+ <gl-button
+ category="tertiary"
+ block
+ class="gl-justify-content-start!"
+ data-testid="add-environment-button"
+ @click="addEnvironment(environmentSearch)"
+ >
+ {{ createEnvironmentLabel }}
+ </gl-button>
+ </div>
</template>
- <gl-search-box-by-type
- ref="searchBox"
- v-model.trim="environmentSearch"
- @focus="fetchEnvironments"
- @keyup="fetchEnvironments"
- />
- <gl-loading-icon v-if="isLoading" size="sm" />
- <gl-dropdown-item
- v-for="environment in results"
- v-else-if="results.length"
- :key="environment"
- @click="addEnvironment(environment)"
- >
- {{ environment }}
- </gl-dropdown-item>
- <template v-else-if="environmentSearch.length">
- <span ref="noResults" class="text-secondary gl-p-3">
- {{ $options.translations.noMatchingResults }}
- </span>
- <gl-dropdown-divider />
- <gl-dropdown-item @click="addEnvironment(environmentSearch)">
- {{ createEnvironmentLabel }}
- </gl-dropdown-item>
+ <template #search-summary-sr-only>
+ {{ srOnlyResultsCount }}
</template>
- </gl-dropdown>
+ </gl-collapsible-listbox>
</template>
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index 684375177bb..8ccf7ba92a5 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -42,7 +42,7 @@ export default class FilteredSearchManager {
useDefaultState = false,
filteredSearchTokenKeys = IssuableFilteredSearchTokenKeys,
stateFiltersSelector = '.issues-state-filters',
- placeholder = __('Search or filter results...'),
+ placeholder = __('Search or filter results…'),
anchor = null,
}) {
this.isGroup = isGroup;
diff --git a/app/assets/javascripts/frequent_items/utils.js b/app/assets/javascripts/frequent_items/utils.js
index 1c33c8b1084..f71405a5bc4 100644
--- a/app/assets/javascripts/frequent_items/utils.js
+++ b/app/assets/javascripts/frequent_items/utils.js
@@ -24,7 +24,8 @@ export const getTopFrequentItems = (items) => {
// and then by lastAccessedOn with recent most first
if (itemA.frequency !== itemB.frequency) {
return itemB.frequency - itemA.frequency;
- } else if (itemA.lastAccessedOn !== itemB.lastAccessedOn) {
+ }
+ if (itemA.lastAccessedOn !== itemB.lastAccessedOn) {
return itemB.lastAccessedOn - itemA.lastAccessedOn;
}
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 9e7006bb6e7..264427f5806 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -393,13 +393,16 @@ class GfmAutoComplete {
if (command === MEMBER_COMMAND.ASSIGN) {
// Only include members which are not assigned to Issuable currently
return data.filter((member) => !assignees.includes(member.search));
- } else if (command === MEMBER_COMMAND.UNASSIGN) {
+ }
+ if (command === MEMBER_COMMAND.UNASSIGN) {
// Only include members which are assigned to Issuable currently
return data.filter((member) => assignees.includes(member.search));
- } else if (command === MEMBER_COMMAND.ASSIGN_REVIEWER) {
+ }
+ if (command === MEMBER_COMMAND.ASSIGN_REVIEWER) {
// Only include members which are not assigned as a reviewer to Issuable currently
return data.filter((member) => !reviewers.includes(member.search));
- } else if (command === MEMBER_COMMAND.UNASSIGN_REVIEWER) {
+ }
+ if (command === MEMBER_COMMAND.UNASSIGN_REVIEWER) {
// Only include members which are not assigned as a reviewer to Issuable currently
return data.filter((member) => reviewers.includes(member.search));
}
@@ -617,11 +620,6 @@ class GfmAutoComplete {
if (labels.find((label) => label.title.startsWith(lastCandidate))) {
return lastCandidate;
}
- } else {
- // Load all labels into the autocompleter.
- // This needs to happen if e.g. editing a label in an existing comment, because normally
- // label data would only be loaded only once you type `~`.
- fetchData(this.$inputor, this.at);
}
const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
@@ -642,7 +640,8 @@ class GfmAutoComplete {
if (command === LABEL_COMMAND.LABEL || command === LABEL_COMMAND.LABELS) {
// Return labels with set: undefined.
return data.filter((label) => !label.set);
- } else if (command === LABEL_COMMAND.UNLABEL) {
+ }
+ if (command === LABEL_COMMAND.UNLABEL) {
// Return labels with set: true.
return data.filter((label) => label.set);
}
@@ -751,7 +750,8 @@ class GfmAutoComplete {
if (command === CONTACTS_ADD_COMMAND) {
// Return contacts that are active and not already on the issue
return data.filter((contact) => contact.state === CONTACT_STATE_ACTIVE && !contact.set);
- } else if (command === CONTACTS_REMOVE_COMMAND) {
+ }
+ if (command === CONTACTS_REMOVE_COMMAND) {
// Return contacts already on the issue
return data.filter((contact) => contact.set);
}
@@ -779,10 +779,8 @@ class GfmAutoComplete {
if (GfmAutoComplete.isLoading(data)) {
self.fetchData(this.$inputor, this.at);
return data;
- } else if (
- GfmAutoComplete.isTypeWithBackendFiltering(this.at) &&
- self.previousQuery !== query
- ) {
+ }
+ if (GfmAutoComplete.isTypeWithBackendFiltering(this.at) && self.previousQuery !== query) {
self.fetchData(this.$inputor, this.at, query);
self.previousQuery = query;
return data;
diff --git a/app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue b/app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue
index 1536a9a525b..25ddfc911f3 100644
--- a/app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue
+++ b/app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue
@@ -30,9 +30,11 @@ export default {
title() {
if (this.status === STATUS_TYPES.SUCCESS) {
return s__('VersionCheck|Up to date');
- } else if (this.status === STATUS_TYPES.WARNING) {
+ }
+ if (this.status === STATUS_TYPES.WARNING) {
return s__('VersionCheck|Update available');
- } else if (this.status === STATUS_TYPES.DANGER) {
+ }
+ if (this.status === STATUS_TYPES.DANGER) {
return s__('VersionCheck|Update ASAP');
}
diff --git a/app/assets/javascripts/google_cloud/deployments/service_table.vue b/app/assets/javascripts/google_cloud/deployments/service_table.vue
index 26c9fd14dc6..9388b41127e 100644
--- a/app/assets/javascripts/google_cloud/deployments/service_table.vue
+++ b/app/assets/javascripts/google_cloud/deployments/service_table.vue
@@ -34,7 +34,7 @@ export default {
methods: {
actionUrl(key) {
if (key === cloudRun) return this.cloudRunUrl;
- else if (key === cloudStorage) return this.cloudStorageUrl;
+ if (key === cloudStorage) return this.cloudStorageUrl;
return '#';
},
},
diff --git a/app/assets/javascripts/google_cloud/service_accounts/list.vue b/app/assets/javascripts/google_cloud/service_accounts/list.vue
index 635b185d207..ebba9332c53 100644
--- a/app/assets/javascripts/google_cloud/service_accounts/list.vue
+++ b/app/assets/javascripts/google_cloud/service_accounts/list.vue
@@ -63,6 +63,7 @@ export default {
:primary-button-link="createUrl"
:primary-button-text="$options.i18n.createServiceAccount"
:svg-path="emptyIllustrationUrl"
+ :svg-height="150"
/>
<div v-else>
diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json
index e6c0b86d9a6..37c1674cc5a 100644
--- a/app/assets/javascripts/graphql_shared/possible_types.json
+++ b/app/assets/javascripts/graphql_shared/possible_types.json
@@ -48,6 +48,10 @@
"ExternalAuditEventDestination",
"InstanceExternalAuditEventDestination"
],
+ "GoogleCloudLoggingConfigurationInterface": [
+ "GoogleCloudLoggingConfigurationType",
+ "InstanceGoogleCloudLoggingConfigurationType"
+ ],
"Issuable": [
"Epic",
"Issue",
@@ -139,6 +143,7 @@
"WorkItem"
],
"User": [
+ "AddOnUser",
"AutocompletedUser",
"MergeRequestAssignee",
"MergeRequestAuthor",
diff --git a/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users.query.graphql b/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users.query.graphql
new file mode 100644
index 00000000000..ed318ef1b8d
--- /dev/null
+++ b/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users.query.graphql
@@ -0,0 +1,12 @@
+#import "../fragments/user.fragment.graphql"
+#import "~/graphql_shared/fragments/user_availability.fragment.graphql"
+
+query projectAutocompleteUsersSearch($search: String!, $fullPath: ID!) {
+ workspace: project(fullPath: $fullPath) {
+ id
+ users: autocompleteUsers(search: $search) {
+ ...User
+ ...UserAvailability
+ }
+ }
+}
diff --git a/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql b/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql
new file mode 100644
index 00000000000..8155451fb7c
--- /dev/null
+++ b/app/assets/javascripts/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql
@@ -0,0 +1,19 @@
+#import "../fragments/user.fragment.graphql"
+#import "~/graphql_shared/fragments/user_availability.fragment.graphql"
+
+query projectAutocompleteUsersSearchWithMRPermissions(
+ $search: String!
+ $fullPath: ID!
+ $mergeRequestId: MergeRequestID!
+) {
+ workspace: project(fullPath: $fullPath) {
+ id
+ users: autocompleteUsers(search: $search) {
+ ...User
+ ...UserAvailability
+ mergeRequestInteraction(id: $mergeRequestId) {
+ canMerge
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/groups/components/empty_states/groups_dashboard_empty_state.vue b/app/assets/javascripts/groups/components/empty_states/groups_dashboard_empty_state.vue
new file mode 100644
index 00000000000..470ff45f47a
--- /dev/null
+++ b/app/assets/javascripts/groups/components/empty_states/groups_dashboard_empty_state.vue
@@ -0,0 +1,24 @@
+<script>
+import { GlEmptyState } from '@gitlab/ui';
+
+import { s__ } from '~/locale';
+
+export default {
+ components: { GlEmptyState },
+ inject: ['groupsEmptyStateIllustration'],
+ i18n: {
+ title: s__('GroupsEmptyState|A group is a collection of several projects'),
+ description: s__(
+ "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group.",
+ ),
+ },
+};
+</script>
+
+<template>
+ <gl-empty-state
+ :title="$options.i18n.title"
+ :description="$options.i18n.description"
+ :svg-path="groupsEmptyStateIllustration"
+ />
+</template>
diff --git a/app/assets/javascripts/groups/components/empty_states/groups_explore_empty_state.vue b/app/assets/javascripts/groups/components/empty_states/groups_explore_empty_state.vue
new file mode 100644
index 00000000000..f524b769802
--- /dev/null
+++ b/app/assets/javascripts/groups/components/empty_states/groups_explore_empty_state.vue
@@ -0,0 +1,17 @@
+<script>
+import { GlEmptyState } from '@gitlab/ui';
+
+import { __ } from '~/locale';
+
+export default {
+ components: { GlEmptyState },
+ inject: ['groupsEmptyStateIllustration'],
+ i18n: {
+ title: __('No public groups'),
+ },
+};
+</script>
+
+<template>
+ <gl-empty-state :title="$options.i18n.title" :svg-path="groupsEmptyStateIllustration" />
+</template>
diff --git a/app/assets/javascripts/groups/index.js b/app/assets/javascripts/groups/index.js
index e71ff6d9107..2539d899865 100644
--- a/app/assets/javascripts/groups/index.js
+++ b/app/assets/javascripts/groups/index.js
@@ -13,7 +13,7 @@ import GroupsStore from './store/groups_store';
Vue.use(Translate);
-export default () => {
+export default (EmptyStateComponent) => {
const el = document.getElementById('js-groups-tree');
// eslint-disable-next-line no-new
@@ -36,16 +36,19 @@ export default () => {
components: {
GroupsApp,
},
+ provide() {
+ const { groupsEmptyStateIllustration } = dataset;
+
+ return { groupsEmptyStateIllustration };
+ },
data() {
const showSchemaMarkup = parseBoolean(dataset.showSchemaMarkup);
- const renderEmptyState = parseBoolean(dataset.renderEmptyState);
const service = new GroupsService(dataset.endpoint);
const store = new GroupsStore({ hideProjects: true, showSchemaMarkup });
return {
store,
service,
- renderEmptyState,
loading: true,
};
},
@@ -74,7 +77,9 @@ export default () => {
props: {
store: this.store,
service: this.service,
- renderEmptyState: this.renderEmptyState,
+ },
+ scopedSlots: {
+ 'empty-state': () => createElement(EmptyStateComponent),
},
});
},
diff --git a/app/assets/javascripts/helpers/avatar_helper.js b/app/assets/javascripts/helpers/avatar_helper.js
deleted file mode 100644
index 35b09e9b027..00000000000
--- a/app/assets/javascripts/helpers/avatar_helper.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { escape } from 'lodash';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { getFirstCharacterCapitalized } from '~/lib/utils/text_utility';
-
-export const DEFAULT_SIZE_CLASS = 's40';
-export const IDENTICON_BG_COUNT = 7;
-
-export function getIdenticonBackgroundClass(entityId) {
- // If a GraphQL string id is passed in, convert it to the entity number
- const id = typeof entityId === 'string' ? getIdFromGraphQLId(entityId) : entityId;
- const type = (id % IDENTICON_BG_COUNT) + 1;
- return `bg${type}`;
-}
-
-export function getIdenticonTitle(entityName) {
- return getFirstCharacterCapitalized(entityName) || ' ';
-}
-
-export function renderIdenticon(entity, options = {}) {
- const { sizeClass = DEFAULT_SIZE_CLASS } = options;
-
- const bgClass = getIdenticonBackgroundClass(entity.id);
- const title = getIdenticonTitle(entity.name);
-
- return `<div class="avatar identicon ${escape(sizeClass)} ${escape(bgClass)}">${escape(
- title,
- )}</div>`;
-}
-
-export function renderAvatar(entity, options = {}) {
- if (!entity.avatar_url) {
- return renderIdenticon(entity, options);
- }
-
- const { sizeClass = DEFAULT_SIZE_CLASS } = options;
-
- return `<img src="${escape(entity.avatar_url)}" class="avatar ${escape(sizeClass)}" />`;
-}
diff --git a/app/assets/javascripts/ide/commit_icon.js b/app/assets/javascripts/ide/commit_icon.js
index 70ee9cff22b..07eef897910 100644
--- a/app/assets/javascripts/ide/commit_icon.js
+++ b/app/assets/javascripts/ide/commit_icon.js
@@ -3,7 +3,8 @@ import { commitItemIconMap } from './constants';
export default (file) => {
if (file.deleted) {
return commitItemIconMap.deleted;
- } else if (file.tempFile && !file.prevPath) {
+ }
+ if (file.tempFile && !file.prevPath) {
return commitItemIconMap.addition;
}
diff --git a/app/assets/javascripts/ide/components/file_templates/dropdown.vue b/app/assets/javascripts/ide/components/file_templates/dropdown.vue
deleted file mode 100644
index f58a35e7624..00000000000
--- a/app/assets/javascripts/ide/components/file_templates/dropdown.vue
+++ /dev/null
@@ -1,103 +0,0 @@
-<!-- eslint-disable vue/multi-word-component-names -->
-<script>
-import { GlIcon, GlLoadingIcon } from '@gitlab/ui';
-import $ from 'jquery';
-// eslint-disable-next-line no-restricted-imports
-import { mapActions, mapState } from 'vuex';
-import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
-
-export default {
- components: {
- DropdownButton,
- GlIcon,
- GlLoadingIcon,
- },
- props: {
- data: {
- type: Array,
- required: false,
- default: () => [],
- },
- label: {
- type: String,
- required: true,
- },
- title: {
- type: String,
- required: false,
- default: null,
- },
- isAsyncData: {
- type: Boolean,
- required: false,
- default: false,
- },
- searchable: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- data() {
- return {
- search: '',
- };
- },
- computed: {
- ...mapState('fileTemplates', ['templates', 'isLoading']),
- outputData() {
- return (this.isAsyncData ? this.templates : this.data).filter((t) => {
- if (!this.searchable) return true;
-
- return t.name.toLowerCase().indexOf(this.search.toLowerCase()) >= 0;
- });
- },
- showLoading() {
- return this.isAsyncData ? this.isLoading : false;
- },
- },
- mounted() {
- $(this.$el).on('show.bs.dropdown', this.fetchTemplatesIfAsync);
- },
- beforeDestroy() {
- $(this.$el).off('show.bs.dropdown', this.fetchTemplatesIfAsync);
- },
- methods: {
- ...mapActions('fileTemplates', ['fetchTemplateTypes']),
- fetchTemplatesIfAsync() {
- if (this.isAsyncData) {
- this.fetchTemplateTypes();
- }
- },
- clickItem(item) {
- this.$emit('click', item);
- },
- },
-};
-</script>
-
-<template>
- <div class="dropdown">
- <dropdown-button :toggle-text="label" data-display="static" />
- <div class="dropdown-menu pb-0">
- <div v-if="title" class="dropdown-title ml-0 mr-0">{{ title }}</div>
- <div v-if="!showLoading && searchable" class="dropdown-input">
- <input
- v-model="search"
- :placeholder="__('Filter...')"
- type="search"
- class="dropdown-input-field"
- />
- <gl-icon name="search" class="dropdown-input-search" />
- </div>
- <div class="dropdown-content">
- <gl-loading-icon v-if="showLoading" size="lg" />
- <ul v-else>
- <li v-for="(item, index) in outputData" :key="index">
- <button type="button" @click="clickItem(item)">{{ item.name }}</button>
- </li>
- </ul>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
index 854daa20628..741845e3325 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
@@ -32,7 +32,8 @@ export default {
if (this.modalType === modalTypes.tree) {
return __('Create new directory');
- } else if (this.modalType === modalTypes.rename) {
+ }
+ if (this.modalType === modalTypes.rename) {
return entry.type === modalTypes.tree ? __('Rename folder') : __('Rename file');
}
@@ -43,7 +44,8 @@ export default {
if (this.modalType === modalTypes.tree) {
return __('Create directory');
- } else if (this.modalType === modalTypes.rename) {
+ }
+ if (this.modalType === modalTypes.rename) {
return entry.type === modalTypes.tree ? __('Rename folder') : __('Rename file');
}
diff --git a/app/assets/javascripts/ide/components/terminal/terminal.vue b/app/assets/javascripts/ide/components/terminal/terminal.vue
index 9e8b3d87397..b2e90a64758 100644
--- a/app/assets/javascripts/ide/components/terminal/terminal.vue
+++ b/app/assets/javascripts/ide/components/terminal/terminal.vue
@@ -37,7 +37,8 @@ export default {
loadingText() {
if (isStartingStatus(this.status)) {
return __('Starting...');
- } else if (this.status === STOPPING) {
+ }
+ if (this.status === STOPPING) {
return __('Stopping...');
}
diff --git a/app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue b/app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue
index 38e53b64503..332408b9ecf 100644
--- a/app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue
+++ b/app/assets/javascripts/ide/components/terminal_sync/terminal_sync_status.vue
@@ -31,12 +31,14 @@ export default {
icon: '',
text: this.isStarted ? MSG_TERMINAL_SYNC_UPLOADING : MSG_TERMINAL_SYNC_CONNECTING,
};
- } else if (this.isError) {
+ }
+ if (this.isError) {
return {
icon: 'warning',
text: this.message,
};
- } else if (this.isStarted) {
+ }
+ if (this.isStarted) {
return {
icon: 'mobile-issue-close',
text: MSG_TERMINAL_SYNC_RUNNING,
diff --git a/app/assets/javascripts/ide/init_gitlab_web_ide.js b/app/assets/javascripts/ide/init_gitlab_web_ide.js
index 11a0095db92..2e113003f8a 100644
--- a/app/assets/javascripts/ide/init_gitlab_web_ide.js
+++ b/app/assets/javascripts/ide/init_gitlab_web_ide.js
@@ -62,9 +62,8 @@ export const initGitlabWebIDE = async (el) => {
filePath,
mrId,
mrTargetProject: getMRTargetProject(),
- // note: At the time of writing this, forkInfo isn't expected by `@gitlab/web-ide`,
- // but it will be soon.
forkInfo,
+ username: gon.current_username,
links: {
feedbackIssue: GITLAB_WEB_IDE_FEEDBACK_ISSUE,
userPreferences: el.dataset.userPreferencesPath,
diff --git a/app/assets/javascripts/ide/lib/diff/controller.js b/app/assets/javascripts/ide/lib/diff/controller.js
index 7595a1cedf1..ec28845d805 100644
--- a/app/assets/javascripts/ide/lib/diff/controller.js
+++ b/app/assets/javascripts/ide/lib/diff/controller.js
@@ -7,9 +7,11 @@ import DirtyDiffWorker from './diff_worker?worker';
export const getDiffChangeType = (change) => {
if (change.modified) {
return 'modified';
- } else if (change.added) {
+ }
+ if (change.added) {
return 'added';
- } else if (change.removed) {
+ }
+ if (change.removed) {
return 'removed';
}
diff --git a/app/assets/javascripts/ide/lib/errors.js b/app/assets/javascripts/ide/lib/errors.js
index a8a048e588f..5063cf5fd4f 100644
--- a/app/assets/javascripts/ide/lib/errors.js
+++ b/app/assets/javascripts/ide/lib/errors.js
@@ -55,9 +55,11 @@ export const parseCommitError = (e) => {
if (CODEOWNERS_REGEX.test(message)) {
return createCodeownersCommitError(message);
- } else if (BRANCH_CHANGED_REGEX.test(message)) {
+ }
+ if (BRANCH_CHANGED_REGEX.test(message)) {
return createBranchChangedCommitError(message);
- } else if (BRANCH_ALREADY_EXISTS.test(message)) {
+ }
+ if (BRANCH_ALREADY_EXISTS.test(message)) {
return branchAlreadyExistsCommitError(message);
}
diff --git a/app/assets/javascripts/ide/lib/files.js b/app/assets/javascripts/ide/lib/files.js
index 3fdf012bbb2..415e34f56b8 100644
--- a/app/assets/javascripts/ide/lib/files.js
+++ b/app/assets/javascripts/ide/lib/files.js
@@ -35,7 +35,8 @@ export const decorateFiles = ({
const insertParent = (path) => {
if (!path) {
return null;
- } else if (entries[path]) {
+ }
+ if (entries[path]) {
return entries[path];
}
diff --git a/app/assets/javascripts/ide/lib/mirror.js b/app/assets/javascripts/ide/lib/mirror.js
index f437965b25a..286798d7560 100644
--- a/app/assets/javascripts/ide/lib/mirror.js
+++ b/app/assets/javascripts/ide/lib/mirror.js
@@ -32,7 +32,8 @@ const isErrorPayload = (payload) => payload && payload.status_code !== HTTP_STAT
const getErrorFromResponse = (data) => {
if (isErrorResponse(data.error)) {
return { message: data.error.Message };
- } else if (isErrorPayload(data.payload)) {
+ }
+ if (isErrorPayload(data.payload)) {
return { message: data.payload.error_message };
}
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index f4fa52b2d4d..11e3d8260f7 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -133,7 +133,8 @@ export const loadBranch = ({ dispatch, getters, state }, { projectId, branchId }
if (currentProject?.branches?.[branchId]) {
return Promise.resolve();
- } else if (getters.emptyRepo) {
+ }
+ if (getters.emptyRepo) {
return dispatch('loadEmptyBranch', { projectId, branchId });
}
diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js
index c0f666c6652..74fe61b6e2f 100644
--- a/app/assets/javascripts/ide/stores/getters.js
+++ b/app/assets/javascripts/ide/stores/getters.js
@@ -30,7 +30,8 @@ const getCannotPushCodeViewModel = (state) => {
text: MSG_GO_TO_FORK,
},
};
- } else if (forkPath) {
+ }
+ if (forkPath) {
return {
message: MSG_CANNOT_PUSH_CODE_SHOULD_FORK,
action: {
diff --git a/app/assets/javascripts/ide/stores/modules/terminal/messages.js b/app/assets/javascripts/ide/stores/modules/terminal/messages.js
index ad7ad35a98c..a2b45f9dc62 100644
--- a/app/assets/javascripts/ide/stores/modules/terminal/messages.js
+++ b/app/assets/javascripts/ide/stores/modules/terminal/messages.js
@@ -39,7 +39,8 @@ export const configCheckError = (status, helpUrl) => {
},
false,
);
- } else if (status === HTTP_STATUS_FORBIDDEN) {
+ }
+ if (status === HTTP_STATUS_FORBIDDEN) {
return ERROR_PERMISSION;
}
diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js
index ec661fdb0d6..bac3803e68f 100644
--- a/app/assets/javascripts/ide/stores/utils.js
+++ b/app/assets/javascripts/ide/stores/utils.js
@@ -81,9 +81,11 @@ export const setPageTitleForFile = (state, file) => {
export const commitActionForFile = (file) => {
if (file.prevPath) {
return commitActionTypes.move;
- } else if (file.deleted) {
+ }
+ if (file.deleted) {
return commitActionTypes.delete;
- } else if (file.tempFile) {
+ }
+ if (file.tempFile) {
return commitActionTypes.create;
}
@@ -131,7 +133,8 @@ export const createNewMergeRequestUrl = (projectUrl, source, target) =>
const sortTreesByTypeAndName = (a, b) => {
if (a.type === 'tree' && b.type === 'blob') {
return -1;
- } else if (a.type === 'blob' && b.type === 'tree') {
+ }
+ if (a.type === 'blob' && b.type === 'tree') {
return 1;
}
if (a.name < b.name) return -1;
diff --git a/app/assets/javascripts/import_entities/components/import_status.vue b/app/assets/javascripts/import_entities/components/import_status.vue
index 94c04123112..91436457b03 100644
--- a/app/assets/javascripts/import_entities/components/import_status.vue
+++ b/app/assets/javascripts/import_entities/components/import_status.vue
@@ -133,9 +133,11 @@ export default {
if (fetched === imported) {
return { name: 'status-success', class: 'gl-text-green-400' };
- } else if (imported === 0) {
+ }
+ if (imported === 0) {
return { name: 'status-scheduled', class: 'gl-text-gray-400' };
- } else if (this.status === STATUSES.FINISHED) {
+ }
+ if (this.status === STATUSES.FINISHED) {
return { name: 'status-alert', class: 'gl-text-orange-400' };
}
diff --git a/app/assets/javascripts/incidents/components/incidents_list.vue b/app/assets/javascripts/incidents/components/incidents_list.vue
index e5a88cf9510..782f417a989 100644
--- a/app/assets/javascripts/incidents/components/incidents_list.vue
+++ b/app/assets/javascripts/incidents/components/incidents_list.vue
@@ -11,9 +11,9 @@ import {
GlIcon,
GlEmptyState,
} from '@gitlab/ui';
-import { isValidSlaDueAt } from 'ee_else_ce/vue_shared/components/incidents/utils';
import { STATUS_CLOSED } from '~/issues/constants';
import { visitUrl, mergeUrlParams, joinPaths } from '~/lib/utils/url_utility';
+import { isValidDateString } from '~/lib/utils/datetime_range';
import { s__, n__ } from '~/locale';
import { INCIDENT_SEVERITY } from '~/sidebar/constants';
import SeverityToken from '~/sidebar/components/severity/severity.vue';
@@ -330,7 +330,7 @@ export default {
item.assignees.nodes.length - MAX_VISIBLE_ASSIGNEES,
);
},
- isValidSlaDueAt,
+ isValidDateString,
},
};
</script>
@@ -357,8 +357,7 @@ export default {
<gl-button
v-if="isHeaderButtonVisible"
class="gl-my-3 gl-mr-5 create-incident-button"
- data-testid="createIncidentBtn"
- data-qa-selector="create_incident_button"
+ data-testid="create-incident-button"
:loading="redirecting"
:disabled="redirecting"
category="primary"
@@ -406,7 +405,6 @@ export default {
>
<gl-link
data-testid="incident-link"
- data-qa-selector="incident_link"
:href="showIncidentLink(item)"
class="gl-min-w-0"
>
@@ -443,7 +441,7 @@ export default {
<template v-if="slaFeatureAvailable" #cell(incidentSla)="{ item }">
<service-level-agreement-cell
- v-if="isValidSlaDueAt(item.slaDueAt)"
+ v-if="isValidDateString(item.slaDueAt)"
:issue-iid="item.iid"
:project-path="projectPath"
:sla-due-at="item.slaDueAt"
diff --git a/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue b/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
index fe3f4ed4bf9..0a5bb82f151 100644
--- a/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
+++ b/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
@@ -25,7 +25,7 @@ export default {
<template>
<section
id="incident-management-settings"
- data-qa-selector="incidents_settings_content"
+ data-testid="incidents-settings-content"
class="settings no-animate"
>
<div class="settings-header">
diff --git a/app/assets/javascripts/integrations/index/components/integrations_table.vue b/app/assets/javascripts/integrations/index/components/integrations_table.vue
index eff64ed7c42..c94c509e811 100644
--- a/app/assets/javascripts/integrations/index/components/integrations_table.vue
+++ b/app/assets/javascripts/integrations/index/components/integrations_table.vue
@@ -1,13 +1,22 @@
<script>
-import { GlIcon, GlLink, GlTable, GlTooltipDirective } from '@gitlab/ui';
+import {
+ GlAvatarLabeled,
+ GlAvatarLink,
+ GlButton,
+ GlIcon,
+ GlTable,
+ GlTooltipDirective,
+} from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
components: {
+ GlAvatarLabeled,
+ GlAvatarLink,
+ GlButton,
GlIcon,
- GlLink,
GlTable,
TimeAgoTooltip,
},
@@ -49,17 +58,12 @@ export default {
key: 'active',
label: '',
thClass: 'gl-w-7',
+ tdClass: 'gl-vertical-align-middle!',
},
{
key: 'title',
label: __('Integration'),
- thClass: 'gl-w-quarter gl-xs-w-full',
- },
- {
- key: 'description',
- label: __('Description'),
- thClass: 'gl-display-none d-sm-table-cell',
- tdClass: 'gl-display-none d-sm-table-cell',
+ thClass: 'd-sm-table-cell',
},
);
@@ -67,11 +71,17 @@ export default {
fields.push({
key: 'updated_at',
label: this.showUpdatedAt ? __('Last updated') : '',
- thClass: 'gl-w-20 gl-text-right',
- tdClass: 'gl-text-right',
+ thClass: 'gl-display-none d-sm-table-cell gl-text-right',
+ tdClass: 'gl-text-right gl-display-none d-sm-table-cell gl-vertical-align-middle!',
});
}
+ fields.push({
+ key: 'edit_path',
+ label: '',
+ thClass: 'gl-w-15',
+ });
+
return fields;
},
filteredIntegrations() {
@@ -83,8 +93,11 @@ export default {
},
methods: {
getStatusTooltipTitle(integration) {
- return sprintf(s__('Integrations|%{integrationTitle}: active'), {
+ const status = integration.active ? 'active' : 'inactive';
+
+ return sprintf(s__('Integrations|%{integrationTitle}: %{status}'), {
integrationTitle: integration.title,
+ status,
});
},
},
@@ -95,26 +108,41 @@ export default {
<gl-table :items="filteredIntegrations" :fields="fields" :empty-text="emptyText" show-empty fixed>
<template #cell(active)="{ item }">
<gl-icon
- v-if="item.active"
+ v-if="item.configured"
v-gl-tooltip
- name="check"
- class="gl-text-green-500"
+ :name="item.active ? 'status-success' : 'status-paused'"
+ :class="item.active ? 'gl-text-green-500' : 'gl-text-gray-500'"
:title="getStatusTooltipTitle(item)"
/>
</template>
<template #cell(title)="{ item }">
- <gl-link
+ <gl-avatar-link
:href="item.edit_path"
- class="gl-font-weight-bold"
+ :title="item.title"
:data-qa-selector="`${item.name}_link`"
>
- {{ item.title }}
- </gl-link>
+ <gl-avatar-labeled
+ :label="item.title"
+ :sub-label="item.description"
+ :entity-id="item.id"
+ :entity-name="item.title"
+ :src="item.icon"
+ :size="32"
+ shape="rect"
+ :label-link="item.edit_path"
+ />
+ </gl-avatar-link>
</template>
<template #cell(updated_at)="{ item }">
<time-ago-tooltip v-if="showUpdatedAt && item.updated_at" :time="item.updated_at" />
</template>
+
+ <template #cell(edit_path)="{ item }">
+ <gl-button :href="item.edit_path">
+ {{ __('Configure') }}
+ </gl-button>
+ </template>
</gl-table>
</template>
diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
index e99a61caf3f..e9d7acdc913 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
@@ -1,28 +1,14 @@
<script>
-import {
- GlAlert,
- GlCollapsibleListbox,
- GlLink,
- GlSprintf,
- GlFormCheckboxGroup,
- GlButton,
- GlCollapse,
- GlIcon,
-} from '@gitlab/ui';
+import { GlAlert, GlButton, GlCollapse, GlIcon } from '@gitlab/ui';
import { partition, isString, uniqueId, isEmpty } from 'lodash';
import InviteModalBase from 'ee_else_ce/invite_members/components/invite_modal_base.vue';
import Api from '~/api';
import Tracking from '~/tracking';
import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants';
import { n__, sprintf } from '~/locale';
-import {
- memberName,
- triggerExternalAlert,
- qualifiesForTasksToBeDone,
-} from 'ee_else_ce/invite_members/utils/member_utils';
+import { memberName, triggerExternalAlert } from 'ee_else_ce/invite_members/utils/member_utils';
import {
USERS_FILTER_ALL,
- INVITE_MEMBERS_FOR_TASK,
MEMBER_MODAL_LABELS,
INVITE_MEMBER_MODAL_TRACKING_CATEGORY,
} from '../constants';
@@ -41,10 +27,6 @@ export default {
name: 'InviteMembersModal',
components: {
GlAlert,
- GlLink,
- GlCollapsibleListbox,
- GlSprintf,
- GlFormCheckboxGroup,
GlButton,
GlCollapse,
GlIcon,
@@ -56,7 +38,6 @@ export default {
import('ee_component/invite_members/components/active_trial_notification.vue'),
},
mixins: [Tracking.mixin({ category: INVITE_MEMBER_MODAL_TRACKING_CATEGORY })],
- inject: ['newProjectPath'],
props: {
id: {
type: String,
@@ -96,14 +77,6 @@ export default {
required: false,
default: null,
},
- tasksToBeDoneOptions: {
- type: Array,
- required: true,
- },
- projects: {
- type: Array,
- required: true,
- },
fullPath: {
type: String,
required: true,
@@ -131,9 +104,6 @@ export default {
modalId: uniqueId('invite-members-modal-'),
newUsersToInvite: [],
invalidMembers: {},
- selectedTasksToBeDone: [],
- selectedTaskProject: this.projects[0],
- selectedTaskProjectId: this.projects[0]?.id,
source: 'unknown',
mode: 'default',
// Kept in sync with "base"
@@ -141,7 +111,6 @@ export default {
errorsLimit: 2,
isErrorsSectionExpanded: false,
shouldShowEmptyInvitesAlert: false,
- projectsForDropdown: this.projects.map((p) => ({ value: p.id, text: p.title, ...p })),
};
},
computed: {
@@ -170,26 +139,6 @@ export default {
this.errorList.length,
);
},
- tasksToBeDoneEnabled() {
- return qualifiesForTasksToBeDone(this.source) && this.tasksToBeDoneOptions.length;
- },
- showTasksToBeDone() {
- return (
- this.tasksToBeDoneEnabled &&
- this.selectedAccessLevel >= INVITE_MEMBERS_FOR_TASK.minimum_access_level
- );
- },
- showTaskProjects() {
- return !this.isProject && this.selectedTasksToBeDone.length;
- },
- tasksToBeDoneForPost() {
- return this.showTasksToBeDone ? this.selectedTasksToBeDone : [];
- },
- tasksProjectForPost() {
- return this.showTasksToBeDone && this.selectedTasksToBeDone.length
- ? this.selectedTaskProject.id
- : '';
- },
showUserLimitNotification() {
return !isEmpty(this.usersLimitDataset.alertVariant);
},
@@ -243,10 +192,6 @@ export default {
eventHub.$on('openModal', (options) => {
this.openModal(options);
});
-
- if (this.tasksToBeDoneEnabled) {
- this.openModal({ source: 'in_product_marketing_email' });
- }
},
methods: {
showInvalidFeedbackMessage(response) {
@@ -289,8 +234,6 @@ export default {
expires_at: expiresAt,
access_level: accessLevel,
invite_source: this.source,
- tasks_to_be_done: this.tasksToBeDoneForPost,
- tasks_project_id: this.tasksProjectForPost,
...email,
...userId,
};
@@ -304,8 +247,6 @@ export default {
return;
}
- this.trackInviteMembersForTask();
-
const apiAddByInvite = this.isProject
? Api.inviteProjectMembers.bind(Api)
: Api.inviteGroupMembers.bind(Api);
@@ -317,7 +258,7 @@ export default {
const { error, message } = responseFromSuccess(response);
if (error) {
- this.showMemberErrors(message);
+ this.showErrors(message);
} else {
this.onInviteSuccess();
}
@@ -327,19 +268,18 @@ export default {
this.isLoading = false;
}
},
- showMemberErrors(message) {
- this.invalidMembers = message;
- this.$refs.alerts.focus();
+ showErrors(message) {
+ if (isString(message)) {
+ this.invalidFeedbackMessage = message;
+ } else {
+ this.invalidMembers = message;
+ this.$refs.alerts.focus();
+ }
},
tokenName(username) {
// initial token creation hits this and nothing is found... so safe navigation
return this.newUsersToInvite.find((member) => memberName(member) === username)?.name;
},
- trackInviteMembersForTask() {
- const label = 'selected_tasks_to_be_done';
- const property = this.selectedTasksToBeDone.join(',');
- this.track(INVITE_MEMBERS_FOR_TASK.submit, { label, property });
- },
onCancel() {
this.track('click_cancel', { label: this.source });
},
@@ -351,11 +291,6 @@ export default {
this.isLoading = false;
this.shouldShowEmptyInvitesAlert = false;
this.newUsersToInvite = [];
- this.selectedTasksToBeDone = [];
- [this.selectedTaskProject] = this.projects;
- },
- changeSelectedTaskProject(projectId) {
- this.selectedTaskProject = this.projects.find((project) => project.id === projectId);
},
onInviteSuccess() {
this.track('invite_successful', { label: this.source });
@@ -513,46 +448,5 @@ export default {
@token-remove="removeToken"
/>
</template>
- <template #form-after>
- <div v-if="showTasksToBeDone" data-testid="invite-members-modal-tasks-to-be-done">
- <label class="gl-mt-5">
- {{ $options.labels.tasksToBeDone.title }}
- </label>
- <template v-if="projects.length">
- <gl-form-checkbox-group
- v-model="selectedTasksToBeDone"
- :options="tasksToBeDoneOptions"
- data-testid="invite-members-modal-tasks"
- />
- <template v-if="showTaskProjects">
- <label class="gl-mt-5 gl-display-block">
- {{ $options.labels.tasksProject.title }}
- </label>
- <gl-collapsible-listbox
- v-model="selectedTaskProjectId"
- :items="projectsForDropdown"
- :block="true"
- class="gl-w-half gl-xs-w-full"
- data-testid="invite-members-modal-project-select"
- @select="changeSelectedTaskProject"
- />
- </template>
- </template>
- <gl-alert
- v-else-if="tasksToBeDoneEnabled"
- variant="tip"
- :dismissible="false"
- data-testid="invite-members-modal-no-projects-alert"
- >
- <gl-sprintf :message="$options.labels.tasksToBeDone.noProjects">
- <template #link="{ content }">
- <gl-link :href="newProjectPath" target="_blank" class="gl-label-link">
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </gl-alert>
- </div>
- </template>
</invite-modal-base>
</template>
diff --git a/app/assets/javascripts/invite_members/components/invite_modal_base.vue b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
index 91b623821dd..5a891e23faf 100644
--- a/app/assets/javascripts/invite_members/components/invite_modal_base.vue
+++ b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
@@ -330,8 +330,6 @@ export default {
:target="null"
/>
</gl-form-group>
-
- <slot name="form-after"></slot>
</template>
<template v-for="{ key } in extraSlots" #[key]>
diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js
index 1cee0c32008..93386e5504b 100644
--- a/app/assets/javascripts/invite_members/constants.js
+++ b/app/assets/javascripts/invite_members/constants.js
@@ -5,10 +5,6 @@ export const PROJECT_SELECT_LABEL_ID = 'project-select';
export const SEARCH_DELAY = 200;
export const VALID_TOKEN_BACKGROUND = 'gl-bg-green-100';
export const INVALID_TOKEN_BACKGROUND = 'gl-bg-red-100';
-export const INVITE_MEMBERS_FOR_TASK = {
- minimum_access_level: 30,
- submit: 'submit',
-};
export const TOAST_MESSAGE_LOCALSTORAGE_KEY = 'members_invited_successfully';
export const GROUP_FILTERS = {
@@ -46,15 +42,6 @@ export const MEMBERS_TO_PROJECT_CELEBRATE_INTRO_TEXT = s__(
);
export const MEMBERS_SEARCH_FIELD = s__('InviteMembersModal|Username or email address');
export const MEMBERS_PLACEHOLDER = s__('InviteMembersModal|Select members or type email addresses');
-export const MEMBERS_TASKS_TO_BE_DONE_TITLE = s__(
- 'InviteMembersModal|Create issues for your new team member to work on (optional)',
-);
-export const MEMBERS_TASKS_TO_BE_DONE_NO_PROJECTS = s__(
- 'InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}',
-);
-export const MEMBERS_TASKS_PROJECTS_TITLE = s__(
- 'InviteMembersModal|Choose a project for the issues',
-);
export const GROUP_MODAL_DEFAULT_TITLE = s__('InviteMembersModal|Invite a group');
export const GROUP_MODAL_TO_GROUP_DEFAULT_INTRO_TEXT = s__(
@@ -123,13 +110,6 @@ export const MEMBER_MODAL_LABELS = {
},
searchField: MEMBERS_SEARCH_FIELD,
placeHolder: MEMBERS_PLACEHOLDER,
- tasksToBeDone: {
- title: MEMBERS_TASKS_TO_BE_DONE_TITLE,
- noProjects: MEMBERS_TASKS_TO_BE_DONE_NO_PROJECTS,
- },
- tasksProject: {
- title: MEMBERS_TASKS_PROJECTS_TITLE,
- },
toastMessageSuccessful: TOAST_MESSAGE_SUCCESSFUL,
memberErrorListText: MEMBER_ERROR_LIST_TEXT,
collapsedErrors: COLLAPSED_ERRORS,
diff --git a/app/assets/javascripts/invite_members/init_invite_members_modal.js b/app/assets/javascripts/invite_members/init_invite_members_modal.js
index 4f539cd8756..41ed0179364 100644
--- a/app/assets/javascripts/invite_members/init_invite_members_modal.js
+++ b/app/assets/javascripts/invite_members/init_invite_members_modal.js
@@ -25,7 +25,6 @@ export default (function initInviteMembersModal() {
name: 'InviteMembersModalRoot',
provide: {
name: el.dataset.name,
- newProjectPath: el.dataset.newProjectPath,
},
render: (createElement) =>
createElement(InviteMembersModal, {
@@ -34,8 +33,6 @@ export default (function initInviteMembersModal() {
isProject: parseBoolean(el.dataset.isProject),
accessLevels: JSON.parse(el.dataset.accessLevels),
defaultAccessLevel: parseInt(el.dataset.defaultAccessLevel, 10),
- tasksToBeDoneOptions: JSON.parse(el.dataset.tasksToBeDoneOptions || '[]'),
- projects: JSON.parse(el.dataset.projects || '[]'),
usersFilter: el.dataset.usersFilter,
filterId: parseInt(el.dataset.filterId, 10),
usersLimitDataset: convertObjectPropsToCamelCase(
diff --git a/app/assets/javascripts/invite_members/utils/member_utils.js b/app/assets/javascripts/invite_members/utils/member_utils.js
index 240a3a89686..7998cb69445 100644
--- a/app/assets/javascripts/invite_members/utils/member_utils.js
+++ b/app/assets/javascripts/invite_members/utils/member_utils.js
@@ -1,5 +1,3 @@
-import { getParameterValues } from '~/lib/utils/url_utility';
-
export function memberName(member) {
// user defined tokens(invites by email) will have email in `name` and will not contain `username`
return member.username || member.name;
@@ -8,7 +6,3 @@ export function memberName(member) {
export function triggerExternalAlert() {
return false;
}
-
-export function qualifiesForTasksToBeDone() {
- return getParameterValues('open_modal')[0] === 'invite_members_for_task';
-}
diff --git a/app/assets/javascripts/issuable/components/csv_export_modal.vue b/app/assets/javascripts/issuable/components/csv_export_modal.vue
index c1de507cd80..fd279a6a451 100644
--- a/app/assets/javascripts/issuable/components/csv_export_modal.vue
+++ b/app/assets/javascripts/issuable/components/csv_export_modal.vue
@@ -47,7 +47,7 @@ export default {
href: this.exportCsvPath,
variant: 'confirm',
'data-method': 'post',
- 'data-qa-selector': `export_issues_button`,
+ 'data-testid': 'export-issues-button',
'data-track-action': 'click_button',
'data-track-label': this.dataTrackLabel,
},
@@ -78,7 +78,7 @@ export default {
:action-cancel="$options.actionCancel"
body-class="gl-p-0!"
:title="exportText"
- data-qa-selector="export_issuable_modal"
+ data-testid="export-issuable-modal"
>
<div
class="gl-justify-content-start gl-align-items-center gl-p-4 gl-border-b-solid gl-border-1 gl-border-gray-50"
diff --git a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue
index 872e1d4269d..8e2ed63613d 100644
--- a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue
+++ b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue
@@ -76,7 +76,6 @@ export default {
v-if="showExportButton"
v-gl-modal="exportModalId"
data-testid="export-as-csv-button"
- data-qa-selector="export_as_csv_button"
:item="dropdownItems.exportAsCSV"
/>
<gl-disclosure-dropdown-item
@@ -88,7 +87,6 @@ export default {
<gl-disclosure-dropdown-item
v-if="showImportButton && canEdit"
data-testid="import-from-jira-link"
- data-qa-selector="import_from_jira_link"
:item="dropdownItems.importFromJIRA"
/>
diff --git a/app/assets/javascripts/issuable/components/issuable_header_warnings.vue b/app/assets/javascripts/issuable/components/issuable_header_warnings.vue
deleted file mode 100644
index a0854be099d..00000000000
--- a/app/assets/javascripts/issuable/components/issuable_header_warnings.vue
+++ /dev/null
@@ -1,87 +0,0 @@
-<script>
-import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
-// eslint-disable-next-line no-restricted-imports
-import { mapGetters } from 'vuex';
-import { sprintf, __ } from '~/locale';
-import { TYPE_ISSUE, TYPE_MERGE_REQUEST, WORKSPACE_PROJECT } from '~/issues/constants';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
-
-const noteableTypeText = {
- issue: __('issue'),
- merge_request: __('merge request'),
-};
-
-export default {
- TYPE_ISSUE,
- WORKSPACE_PROJECT,
- components: {
- GlIcon,
- ConfidentialityBadge,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [glFeatureFlagMixin()],
- inject: ['hidden'],
- computed: {
- ...mapGetters(['getNoteableData']),
- isLocked() {
- return this.getNoteableData.discussion_locked;
- },
- isConfidential() {
- return this.getNoteableData.confidential;
- },
- isMergeRequest() {
- return this.getNoteableData.targetType === TYPE_MERGE_REQUEST;
- },
- warningIconsMeta() {
- return [
- {
- iconName: 'lock',
- visible: this.isLocked,
- dataTestId: 'locked',
- tooltip: sprintf(__('This %{issuable} is locked. Only project members can comment.'), {
- issuable: noteableTypeText[this.getNoteableData.targetType],
- }),
- },
- {
- iconName: 'spam',
- visible: this.hidden,
- dataTestId: 'hidden',
- tooltip: sprintf(__('This %{issuable} is hidden because its author has been banned'), {
- issuable: noteableTypeText[this.getNoteableData.targetType],
- }),
- },
- ];
- },
- },
-};
-</script>
-
-<template>
- <div class="gl-display-inline-block">
- <confidentiality-badge
- v-if="isConfidential"
- data-testid="confidential"
- :workspace-type="$options.WORKSPACE_PROJECT"
- :issuable-type="$options.TYPE_ISSUE"
- />
- <template v-for="meta in warningIconsMeta">
- <div
- v-if="meta.visible"
- :key="meta.iconName"
- v-gl-tooltip.bottom
- :data-testid="meta.dataTestId"
- :title="meta.tooltip || null"
- :class="{
- 'gl-mr-3 gl-mt-2 gl-display-flex gl-justify-content-center gl-align-items-center': isMergeRequest,
- 'gl-display-inline-block': !isMergeRequest,
- }"
- class="issuable-warning-icon"
- >
- <gl-icon :name="meta.iconName" class="icon" />
- </div>
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/issuable/components/issue_assignees.vue b/app/assets/javascripts/issuable/components/issue_assignees.vue
index d8cbc45684b..2181b4e1a40 100644
--- a/app/assets/javascripts/issuable/components/issue_assignees.vue
+++ b/app/assets/javascripts/issuable/components/issue_assignees.vue
@@ -89,7 +89,7 @@ export default {
:img-size="iconSize"
class="js-no-trigger author-link"
tooltip-placement="bottom"
- data-qa-selector="assignee_link"
+ data-testid="assignee-link"
>
<span class="js-assignee-tooltip">
<span class="bold d-block">{{ s__('Label|Assignee') }}</span> {{ assignee.name }}
@@ -101,7 +101,7 @@ export default {
v-gl-tooltip.bottom
:title="assigneesCounterTooltip"
class="avatar-counter"
- data-qa-selector="avatar_counter_content"
+ data-testid="avatar-counter-content"
>{{ assigneeCounterLabel }}</span
>
</div>
diff --git a/app/assets/javascripts/issuable/components/issue_milestone.vue b/app/assets/javascripts/issuable/components/issue_milestone.vue
index c7da3e59098..3340ef2338c 100644
--- a/app/assets/javascripts/issuable/components/issue_milestone.vue
+++ b/app/assets/javascripts/issuable/components/issue_milestone.vue
@@ -42,7 +42,8 @@ export default {
milestoneDatesAbsolute() {
if (this.milestoneDue) {
return `(${dateInWords(this.milestoneDue)})`;
- } else if (this.milestoneStart) {
+ }
+ if (this.milestoneStart) {
return `(${dateInWords(this.milestoneStart)})`;
}
return '';
diff --git a/app/assets/javascripts/issuable/components/status_badge.vue b/app/assets/javascripts/issuable/components/status_badge.vue
new file mode 100644
index 00000000000..949fb3c1ce5
--- /dev/null
+++ b/app/assets/javascripts/issuable/components/status_badge.vue
@@ -0,0 +1,98 @@
+<script>
+import { GlBadge, GlIcon } from '@gitlab/ui';
+import { __ } from '~/locale';
+import {
+ STATUS_CLOSED,
+ STATUS_LOCKED,
+ STATUS_MERGED,
+ STATUS_OPEN,
+ TYPE_EPIC,
+ TYPE_ISSUE,
+ TYPE_MERGE_REQUEST,
+} from '~/issues/constants';
+
+const badgePropertiesMap = {
+ [TYPE_EPIC]: {
+ [STATUS_OPEN]: {
+ icon: 'epic',
+ text: __('Open'),
+ variant: 'success',
+ },
+ [STATUS_CLOSED]: {
+ icon: 'epic-closed',
+ text: __('Closed'),
+ variant: 'info',
+ },
+ },
+ [TYPE_ISSUE]: {
+ [STATUS_OPEN]: {
+ icon: 'issues',
+ text: __('Open'),
+ variant: 'success',
+ },
+ [STATUS_CLOSED]: {
+ icon: 'issue-closed',
+ text: __('Closed'),
+ variant: 'info',
+ },
+ [STATUS_LOCKED]: {
+ icon: 'issues',
+ text: __('Open'),
+ variant: 'success',
+ },
+ },
+ [TYPE_MERGE_REQUEST]: {
+ [STATUS_OPEN]: {
+ icon: 'merge-request-open',
+ text: __('Open'),
+ variant: 'success',
+ },
+ [STATUS_CLOSED]: {
+ icon: 'merge-request-close',
+ text: __('Closed'),
+ variant: 'danger',
+ },
+ [STATUS_MERGED]: {
+ icon: 'merge',
+ text: __('Merged'),
+ variant: 'info',
+ },
+ [STATUS_LOCKED]: {
+ icon: 'merge-request-open',
+ text: __('Open'),
+ variant: 'success',
+ },
+ },
+};
+
+export default {
+ components: {
+ GlBadge,
+ GlIcon,
+ },
+ props: {
+ issuableType: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ state: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ computed: {
+ badgeProperties() {
+ return badgePropertiesMap[this.issuableType][this.state];
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-badge :variant="badgeProperties.variant" :aria-label="badgeProperties.text">
+ <gl-icon :name="badgeProperties.icon" />
+ <span class="gl-display-none gl-sm-display-block gl-ml-2">{{ badgeProperties.text }}</span>
+ </gl-badge>
+</template>
diff --git a/app/assets/javascripts/issuable/components/status_box.vue b/app/assets/javascripts/issuable/components/status_box.vue
deleted file mode 100644
index 0d7d0f020dd..00000000000
--- a/app/assets/javascripts/issuable/components/status_box.vue
+++ /dev/null
@@ -1,146 +0,0 @@
-<script>
-import { GlBadge, GlIcon } from '@gitlab/ui';
-import Vue from 'vue';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { fetchPolicies } from '~/lib/graphql';
-import { __ } from '~/locale';
-import {
- STATUS_CLOSED,
- STATUS_OPEN,
- TYPE_ISSUE,
- TYPE_MERGE_REQUEST,
- TYPE_EPIC,
-} from '~/issues/constants';
-
-export const badgeState = Vue.observable({
- state: '',
- updateStatus: null,
-});
-
-const CLASSES = {
- opened: 'issuable-status-badge-open',
- locked: 'issuable-status-badge-open',
- closed: 'issuable-status-badge-closed',
- merged: 'issuable-status-badge-merged',
-};
-
-const ICONS = {
- [TYPE_EPIC]: {
- opened: 'epic',
- closed: 'epic-closed',
- },
- [TYPE_ISSUE]: {
- opened: 'issues',
- locked: 'issues',
- closed: 'issue-closed',
- },
- [TYPE_MERGE_REQUEST]: {
- opened: 'merge-request-open',
- locked: 'merge-request-open',
- closed: 'merge-request-close',
- merged: 'merge',
- },
-};
-
-const STATUS = {
- opened: __('Open'),
- locked: __('Open'),
- closed: __('Closed'),
- merged: __('Merged'),
-};
-
-export default {
- components: {
- GlBadge,
- GlIcon,
- },
- mixins: [glFeatureFlagMixin()],
- inject: {
- query: { default: null },
- projectPath: { default: null },
- iid: { default: null },
- },
- props: {
- initialState: {
- type: String,
- required: false,
- default: null,
- },
- issuableType: {
- type: String,
- required: false,
- default: '',
- },
- },
- data() {
- if (!this.iid) return { state: this.initialState };
-
- if (this.initialState && !badgeState.state) {
- badgeState.state = this.initialState;
- }
-
- return badgeState;
- },
- computed: {
- badgeClass() {
- return [
- CLASSES[this.state],
- {
- 'gl-vertical-align-bottom': this.issuableType === TYPE_MERGE_REQUEST,
- },
- ];
- },
- badgeVariant() {
- if (this.state === STATUS_OPEN) {
- return 'success';
- } else if (this.state === STATUS_CLOSED) {
- return this.issuableType === TYPE_MERGE_REQUEST ? 'danger' : 'info';
- }
- return 'info';
- },
- badgeText() {
- return STATUS[this.state];
- },
- badgeIcon() {
- const type = this.issuableType || TYPE_MERGE_REQUEST;
- return ICONS[type][this.state];
- },
- },
- created() {
- if (!badgeState.updateStatus) {
- badgeState.updateStatus = this.fetchState;
- }
- },
- beforeDestroy() {
- if (badgeState.updateStatus && this.query) {
- badgeState.updateStatus = null;
- }
- },
- methods: {
- async fetchState() {
- const { data } = await this.$apollo.query({
- query: this.query,
- variables: {
- projectPath: this.projectPath,
- iid: this.iid,
- },
- fetchPolicy: fetchPolicies.NO_CACHE,
- });
-
- badgeState.state = data?.workspace?.issuable?.state;
- },
- },
-};
-</script>
-
-<template>
- <gl-badge
- class="issuable-status-badge gl-mr-3 gl-align-self-center"
- :class="badgeClass"
- :variant="badgeVariant"
- :aria-label="badgeText"
- >
- <gl-icon :name="badgeIcon" class="gl-badge-icon" />
- <span class="gl-display-none gl-sm-display-block gl-ml-2">{{ badgeText }}</span>
- </gl-badge>
-</template>
diff --git a/app/assets/javascripts/issuable/index.js b/app/assets/javascripts/issuable/index.js
index acc0161bf6a..40f92763b29 100644
--- a/app/assets/javascripts/issuable/index.js
+++ b/app/assets/javascripts/issuable/index.js
@@ -5,7 +5,6 @@ import Sidebar from '~/right_sidebar';
import { getSidebarOptions } from '~/sidebar/mount_sidebar';
import CsvImportExportButtons from './components/csv_import_export_buttons.vue';
import IssuableByEmail from './components/issuable_by_email.vue';
-import IssuableHeaderWarnings from './components/issuable_header_warnings.vue';
import issuableBulkUpdateActions from './issuable_bulk_update_actions';
import IssuableBulkUpdateSidebar from './issuable_bulk_update_sidebar';
import IssuableContext from './issuable_context';
@@ -97,24 +96,6 @@ export function initIssuableByEmail() {
});
}
-export function initIssuableHeaderWarnings(store) {
- const el = document.getElementById('js-issuable-header-warnings');
-
- if (!el) {
- return null;
- }
-
- const { hidden } = el.dataset;
-
- return new Vue({
- el,
- name: 'IssuableHeaderWarningsRoot',
- store,
- provide: { hidden: parseBoolean(hidden) },
- render: (createElement) => createElement(IssuableHeaderWarnings),
- });
-}
-
export function initIssuableSidebar() {
const el = document.querySelector('.js-sidebar-options');
diff --git a/app/assets/javascripts/issuable/issuable_context.js b/app/assets/javascripts/issuable/issuable_context.js
index 8c2e2a5df67..ef49bd29a40 100644
--- a/app/assets/javascripts/issuable/issuable_context.js
+++ b/app/assets/javascripts/issuable/issuable_context.js
@@ -8,6 +8,29 @@ export default class IssuableContext {
this.userSelect = new UsersSelect(currentUser);
this.reviewersSelect = new UsersSelect(currentUser, '.js-reviewer-search');
+ this.reviewersSelect.dropdowns.forEach((glDropdownInstance) => {
+ const jQueryWrapper = glDropdownInstance.dropdown;
+ const domElement = jQueryWrapper[0];
+ const content = domElement.querySelector('.dropdown-content');
+ const loader = domElement.querySelector('.dropdown-loading');
+ const spinner = loader.querySelector('.gl-spinner-container');
+ const realParent = loader.parentNode;
+
+ domElement.classList.add('non-blocking-loader');
+ spinner.classList.remove('gl-mt-7');
+ spinner.classList.add('gl-mt-2');
+
+ jQueryWrapper.on('shown.bs.dropdown', () => {
+ glDropdownInstance.filterInput.focus();
+ });
+ jQueryWrapper.on('toggle.on.loading.gl.dropdown filtering.gl.dropdown', () => {
+ content.appendChild(loader);
+ });
+ jQueryWrapper.on('done.remote.loading.gl.dropdown done.filtering.gl.dropdown', () => {
+ realParent.appendChild(loader);
+ });
+ });
+
$('.issuable-sidebar .inline-update').on('change', 'select', function onClickSelect() {
return $(this).submit();
});
diff --git a/app/assets/javascripts/issuable/popover/components/issue_popover.vue b/app/assets/javascripts/issuable/popover/components/issue_popover.vue
index 044a1bba7ad..12d76ec4b54 100644
--- a/app/assets/javascripts/issuable/popover/components/issue_popover.vue
+++ b/app/assets/javascripts/issuable/popover/components/issue_popover.vue
@@ -3,12 +3,13 @@ import { GlIcon, GlPopover, GlSkeletonLoader, GlTooltipDirective } from '@gitlab
import query from 'ee_else_ce/issuable/popover/queries/issue.query.graphql';
import IssueDueDate from '~/boards/components/issue_due_date.vue';
import IssueMilestone from '~/issuable/components/issue_milestone.vue';
-import StatusBox from '~/issuable/components/status_box.vue';
-import { STATUS_CLOSED } from '~/issues/constants';
+import StatusBadge from '~/issuable/components/status_badge.vue';
+import { STATUS_CLOSED, TYPE_ISSUE } from '~/issues/constants';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
export default {
+ TYPE_ISSUE,
components: {
GlIcon,
GlPopover,
@@ -16,7 +17,7 @@ export default {
IssueDueDate,
IssueMilestone,
IssueWeight: () => import('ee_component/boards/components/issue_card_weight.vue'),
- StatusBox,
+ StatusBadge,
WorkItemTypeIcon,
},
directives: {
@@ -82,14 +83,14 @@ export default {
<gl-skeleton-loader v-if="$apollo.queries.issue.loading" :height="15">
<rect width="250" height="15" rx="4" />
</gl-skeleton-loader>
- <div v-else-if="showDetails" class="gl-display-flex gl-align-items-center">
- <status-box issuable-type="issue" :initial-state="issue.state" />
+ <div v-else-if="showDetails" class="gl-display-flex gl-align-items-center gl-gap-2">
+ <status-badge :issuable-type="$options.TYPE_ISSUE" :state="issue.state" />
<gl-icon
v-if="issue.confidential"
v-gl-tooltip
name="eye-slash"
:title="__('Confidential')"
- class="gl-text-orange-500 gl-mr-2"
+ class="gl-text-orange-500"
:aria-label="__('Confidential')"
/>
<span class="gl-text-secondary">
diff --git a/app/assets/javascripts/issues/constants.js b/app/assets/javascripts/issues/constants.js
index 0a1a1324d7d..80344efc44c 100644
--- a/app/assets/javascripts/issues/constants.js
+++ b/app/assets/javascripts/issues/constants.js
@@ -30,6 +30,7 @@ export const issuableStatusText = {
export const IssuableTypeText = {
[TYPE_ISSUE]: __('issue'),
+ [TYPE_EPIC]: __('epic'),
[TYPE_MERGE_REQUEST]: __('merge request'),
[TYPE_ALERT]: __('alert'),
[TYPE_INCIDENT]: __('incident'),
diff --git a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
index 9febebf7e55..a756229e6ca 100644
--- a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
+++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
@@ -495,7 +495,6 @@ export default {
:issuables-loading="isLoading"
namespace="dashboard"
recent-searches-storage-key="issues"
- :search-input-placeholder="$options.i18n.searchPlaceholder"
:search-tokens="searchTokens"
:show-pagination-controls="showPaginationControls"
show-work-item-type-icon
diff --git a/app/assets/javascripts/issues/index.js b/app/assets/javascripts/issues/index.js
index eec7c6bf842..3bd28c50800 100644
--- a/app/assets/javascripts/issues/index.js
+++ b/app/assets/javascripts/issues/index.js
@@ -3,21 +3,20 @@ import IssuableForm from 'ee_else_ce/issuable/issuable_form';
import IssuableLabelSelector from '~/issuable/issuable_label_selector';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
-import { initIssuableHeaderWarnings, initIssuableSidebar } from '~/issuable';
-import { TYPE_INCIDENT } from '~/issues/constants';
+import { initIssuableSidebar } from '~/issuable';
import Issue from '~/issues/issue';
import { initTitleSuggestions, initTypePopover, initTypeSelect } from '~/issues/new';
import { initRelatedMergeRequests } from '~/issues/related_merge_requests';
import { initRelatedIssues } from '~/related_issues';
-import { initIncidentApp, initIssueApp, initSentryErrorStackTrace } from '~/issues/show';
-import { parseIssuableData } from '~/issues/show/utils/parse_data';
+import { initIssuableApp, initSentryErrorStackTrace } from '~/issues/show';
import LabelsSelect from '~/labels/labels_select';
import initNotesApp from '~/notes';
import { store } from '~/notes/stores';
import { mountMilestoneDropdown } from '~/sidebar/mount_sidebar';
+import initSidebarBundle from '~/sidebar/sidebar_bundle';
+import initWorkItemLinks from '~/work_items/components/work_item_links';
import ZenMode from '~/zen_mode';
import initAwardsApp from '~/emoji/awards_app';
-import initLinkedResources from '~/linked_resources';
import FilteredSearchServiceDesk from './filtered_search_service_desk';
export function initFilteredSearchServiceDesk() {
@@ -42,33 +41,20 @@ export function initForm() {
mountMilestoneDropdown();
}
-export function initShow({ notesParams } = {}) {
- const el = document.getElementById('js-issuable-app');
-
- if (!el) {
- return;
- }
-
- const { issueType, ...issuableData } = parseIssuableData(el);
-
- if (issueType === TYPE_INCIDENT) {
- initIncidentApp({ ...issuableData, issuableId: el.dataset.issuableId }, store);
- initLinkedResources();
- initRelatedIssues(TYPE_INCIDENT);
- } else {
- initIssueApp(issuableData, store);
- }
-
+export function initShow() {
new Issue(); // eslint-disable-line no-new
new ShortcutsIssuable(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new
- initIssuableHeaderWarnings(store);
+
+ initAwardsApp(document.getElementById('js-vue-awards-block'));
+ initIssuableApp(store);
initIssuableSidebar();
- initNotesApp(notesParams);
+ initNotesApp();
+ initRelatedIssues();
initRelatedMergeRequests();
initSentryErrorStackTrace();
-
- initAwardsApp(document.getElementById('js-vue-awards-block'));
+ initSidebarBundle(store);
+ initWorkItemLinks();
import(/* webpackChunkName: 'design_management' */ '~/design_management')
.then((module) => module.default())
diff --git a/app/assets/javascripts/issues/issue.js b/app/assets/javascripts/issues/issue.js
index b7fd99d8042..06bbcdc12ea 100644
--- a/app/assets/javascripts/issues/issue.js
+++ b/app/assets/javascripts/issues/issue.js
@@ -49,13 +49,8 @@ export default class Issue {
issueFailMessage = __('Unable to update this issue at this time.'),
) {
if ('id' in data) {
- const isClosedBadge = $('.issuable-status-badge-closed');
- const isOpenBadge = $('.issuable-status-badge-open');
const projectIssuesCounter = $('.issue_counter');
- isClosedBadge.toggleClass('hidden', !isClosed);
- isOpenBadge.toggleClass('hidden', isClosed);
-
$(document).trigger('issuable:change', isClosed);
let numProjectIssues = Number(
diff --git a/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue b/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue
index 9f7fca0ceca..3d62ea07f59 100644
--- a/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue
+++ b/app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue
@@ -82,7 +82,7 @@ export default {
v-if="showCsvButtons"
class="gl-w-full gl-sm-w-auto gl-sm-mr-3"
:toggle-text="$options.i18n.importIssues"
- data-qa-selector="import_issues_dropdown"
+ data-testid="import-issues-dropdown"
>
<csv-import-export-buttons
:export-csv-path="exportCsvPathWithQuery"
diff --git a/app/assets/javascripts/issues/list/components/issue_card_time_info.vue b/app/assets/javascripts/issues/list/components/issue_card_time_info.vue
index dde1a4fd2d6..22c0984ebdb 100644
--- a/app/assets/javascripts/issues/list/components/issue_card_time_info.vue
+++ b/app/assets/javascripts/issues/list/components/issue_card_time_info.vue
@@ -10,6 +10,8 @@ import {
newDateAsLocaleTime,
} from '~/lib/utils/datetime_utility';
import { __ } from '~/locale';
+import { STATE_CLOSED } from '~/work_items/constants';
+import { isMilestoneWidget, isStartAndDueDateWidget } from '~/work_items/utils';
export default {
components: {
@@ -26,9 +28,12 @@ export default {
},
},
computed: {
+ milestone() {
+ return this.issue.milestone || this.issue.widgets?.find(isMilestoneWidget)?.milestone;
+ },
milestoneDate() {
- if (this.issue.milestone?.dueDate) {
- const { dueDate, startDate } = this.issue.milestone;
+ if (this.milestone.dueDate) {
+ const { dueDate, startDate } = this.milestone;
const date = dateInWords(newDateAsLocaleTime(dueDate), true);
const remainingTime = this.milestoneRemainingTime(dueDate, startDate);
return `${date} (${remainingTime})`;
@@ -36,15 +41,19 @@ export default {
return __('Milestone');
},
milestoneLink() {
- return this.issue.milestone.webPath || this.issue.milestone.webUrl;
+ return this.milestone.webPath || this.milestone.webUrl;
},
dueDate() {
- return this.issue.dueDate && dateInWords(newDateAsLocaleTime(this.issue.dueDate), true);
+ return this.issue.dueDate || this.issue.widgets?.find(isStartAndDueDateWidget)?.dueDate;
+ },
+ dueDateText() {
+ return this.dueDate && dateInWords(newDateAsLocaleTime(this.dueDate), true);
+ },
+ isClosed() {
+ return this.issue.state === STATUS_CLOSED || this.issue.state === STATE_CLOSED;
},
showDueDateInRed() {
- return (
- isInPast(newDateAsLocaleTime(this.issue.dueDate)) && this.issue.state !== STATUS_CLOSED
- );
+ return isInPast(newDateAsLocaleTime(this.dueDate)) && !this.isClosed;
},
timeEstimate() {
return this.issue.humanTimeEstimate || this.issue.timeStats?.humanTimeEstimate;
@@ -57,11 +66,14 @@ export default {
if (dueDate && isInPast(due)) {
return __('Past due');
- } else if (dueDate && isToday(due)) {
+ }
+ if (dueDate && isToday(due)) {
return __('Today');
- } else if (startDate && isInFuture(start)) {
+ }
+ if (startDate && isInFuture(start)) {
return __('Upcoming');
- } else if (dueDate) {
+ }
+ if (dueDate) {
return getTimeRemainingInWords(due);
}
return '';
@@ -73,7 +85,7 @@ export default {
<template>
<span>
<span
- v-if="issue.milestone"
+ v-if="milestone"
class="issuable-milestone gl-mr-3 gl-text-truncate gl-max-w-26 gl-display-inline-block gl-vertical-align-bottom"
data-testid="issuable-milestone"
>
@@ -84,11 +96,11 @@ export default {
class="gl-font-sm gl-text-gray-500!"
>
<gl-icon name="clock" :size="12" />
- {{ issue.milestone.title }}
+ {{ milestone.title }}
</gl-link>
</span>
<span
- v-if="issue.dueDate"
+ v-if="dueDate"
v-gl-tooltip
class="issuable-due-date gl-mr-3"
:class="{ 'gl-text-red-500': showDueDateInRed }"
@@ -96,7 +108,7 @@ export default {
data-testid="issuable-due-date"
>
<gl-icon name="calendar" :size="12" />
- {{ dueDate }}
+ {{ dueDateText }}
</span>
<span
v-if="timeEstimate"
diff --git a/app/assets/javascripts/issues/list/components/issues_list_app.vue b/app/assets/javascripts/issues/list/components/issues_list_app.vue
index c50b48ca0d8..3d8ed3af816 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -99,8 +99,6 @@ import {
import eventHub from '../eventhub';
import reorderIssuesMutation from '../queries/reorder_issues.mutation.graphql';
import searchLabelsQuery from '../queries/search_labels.query.graphql';
-import searchMilestonesQuery from '../queries/search_milestones.query.graphql';
-import searchUsersQuery from '../queries/search_users.query.graphql';
import setSortPreferenceMutation from '../queries/set_sort_preference.mutation.graphql';
import {
convertToApiParams,
@@ -204,11 +202,6 @@ export default {
required: false,
default: () => [],
},
- eeIsOkrsEnabled: {
- type: Boolean,
- required: false,
- default: false,
- },
},
data() {
return {
@@ -411,9 +404,10 @@ export default {
title: TOKEN_TITLE_MILESTONE,
icon: 'clock',
token: MilestoneToken,
- fetchMilestones: this.fetchMilestones,
recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-milestone`,
shouldSkipSort: true,
+ fullPath: this.fullPath,
+ isProject: this.isProject,
},
{
type: TOKEN_TYPE_LABEL,
@@ -640,32 +634,13 @@ export default {
fetchLatestLabels(search) {
return this.fetchLabelsWithFetchPolicy(search, fetchPolicies.NETWORK_ONLY);
},
- fetchMilestones(search) {
- return this.$apollo
- .query({
- query: searchMilestonesQuery,
- variables: { fullPath: this.fullPath, search, isProject: this.isProject },
- })
- .then(({ data }) => data[this.namespace]?.milestones.nodes);
- },
fetchUsers(search) {
- if (gon.features?.newGraphqlUsersAutocomplete) {
- return this.$apollo
- .query({
- query: usersAutocompleteQuery,
- variables: { fullPath: this.fullPath, search, isProject: this.isProject },
- })
- .then(({ data }) => data[this.namespace]?.autocompleteUsers);
- }
-
return this.$apollo
.query({
- query: searchUsersQuery,
+ query: usersAutocompleteQuery,
variables: { fullPath: this.fullPath, search, isProject: this.isProject },
})
- .then(({ data }) =>
- data[this.namespace]?.[`${this.namespace}Members`].nodes.map((member) => member.user),
- );
+ .then(({ data }) => data[this.namespace]?.autocompleteUsers);
},
getExportCsvPathWithQuery() {
return `${this.exportCsvPath}${window.location.search}`;
@@ -966,7 +941,6 @@ export default {
v-if="hasAnyIssues"
:namespace="fullPath"
recent-searches-storage-key="issues"
- :search-input-placeholder="$options.i18n.searchPlaceholder"
:search-tokens="searchTokens"
:has-scoped-labels-feature="hasScopedLabelsFeature"
:initial-filter-value="filterTokens"
@@ -1037,14 +1011,11 @@ export default {
>
{{ $options.i18n.editIssues }}
</gl-button>
- <gl-button
- v-if="showNewIssueLink && !eeIsOkrsEnabled"
- :href="newIssuePath"
- variant="confirm"
- >
- {{ $options.i18n.newIssueLabel }}
- </gl-button>
- <slot name="new-objective-button"></slot>
+ <slot name="new-issuable-button">
+ <gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm">
+ {{ $options.i18n.newIssueLabel }}
+ </gl-button>
+ </slot>
<new-resource-dropdown
v-if="showNewIssueDropdown"
:query="$options.searchProjectsQuery"
@@ -1059,7 +1030,7 @@ export default {
no-caret
:toggle-text="$options.i18n.actionsLabel"
text-sr-only
- data-qa-selector="issues_list_more_actions_dropdown"
+ data-testid="issues-list-more-actions-dropdown"
>
<csv-import-export-buttons
v-if="showCsvButtons"
diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js
index 85e300b6474..682c7629962 100644
--- a/app/assets/javascripts/issues/list/constants.js
+++ b/app/assets/javascripts/issues/list/constants.js
@@ -121,7 +121,6 @@ export const i18n = {
reorderError: __('An error occurred while reordering issues.'),
deleteError: __('An error occurred while deleting an issuable.'),
rssLabel: __('Subscribe to RSS feed'),
- searchPlaceholder: __('Search or filter results...'),
upvotes: __('Upvotes'),
titles: __('Titles'),
descriptions: __('Descriptions'),
diff --git a/app/assets/javascripts/issues/list/queries/issue.fragment.graphql b/app/assets/javascripts/issues/list/queries/issue.fragment.graphql
index 3b49c0efb14..f3173f0e33a 100644
--- a/app/assets/javascripts/issues/list/queries/issue.fragment.graphql
+++ b/app/assets/javascripts/issues/list/queries/issue.fragment.graphql
@@ -11,6 +11,7 @@ fragment IssueFragment on Issue {
moved
state
title
+ titleHtml
updatedAt
closedAt
upvotes
diff --git a/app/assets/javascripts/issues/list/queries/search_milestones.query.graphql b/app/assets/javascripts/issues/list/queries/search_milestones.query.graphql
index 040240cde99..941e71b7ca7 100644
--- a/app/assets/javascripts/issues/list/queries/search_milestones.query.graphql
+++ b/app/assets/javascripts/issues/list/queries/search_milestones.query.graphql
@@ -1,6 +1,11 @@
#import "./milestone.fragment.graphql"
-query searchMilestones($fullPath: ID!, $search: String, $isProject: Boolean = false) {
+query searchMilestones(
+ $fullPath: ID!
+ $search: String
+ $isProject: Boolean = false
+ $state: MilestoneStateEnum
+) {
group(fullPath: $fullPath) @skip(if: $isProject) {
id
milestones(
@@ -8,7 +13,7 @@ query searchMilestones($fullPath: ID!, $search: String, $isProject: Boolean = fa
includeAncestors: true
includeDescendants: true
sort: EXPIRED_LAST_DUE_DATE_ASC
- state: active
+ state: $state
) {
nodes {
...Milestone
@@ -21,7 +26,7 @@ query searchMilestones($fullPath: ID!, $search: String, $isProject: Boolean = fa
searchTitle: $search
includeAncestors: true
sort: EXPIRED_LAST_DUE_DATE_ASC
- state: active
+ state: $state
) {
nodes {
...Milestone
diff --git a/app/assets/javascripts/issues/list/queries/search_users.query.graphql b/app/assets/javascripts/issues/list/queries/search_users.query.graphql
deleted file mode 100644
index 6a1967a8875..00000000000
--- a/app/assets/javascripts/issues/list/queries/search_users.query.graphql
+++ /dev/null
@@ -1,29 +0,0 @@
-#import "./user.fragment.graphql"
-
-query searchUsers($fullPath: ID!, $search: String, $isProject: Boolean = false) {
- group(fullPath: $fullPath) @skip(if: $isProject) {
- id
- groupMembers(search: $search, relations: [DIRECT, INHERITED, SHARED_FROM_GROUPS]) {
- nodes {
- id
- user {
- ...User
- }
- }
- }
- }
- project(fullPath: $fullPath) @include(if: $isProject) {
- id
- projectMembers(
- search: $search
- relations: [DIRECT, INHERITED, INVITED_GROUPS, SHARED_INTO_ANCESTORS]
- ) {
- nodes {
- id
- user {
- ...User
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/issues/list/queries/user.fragment.graphql b/app/assets/javascripts/issues/list/queries/user.fragment.graphql
deleted file mode 100644
index 3e5bc0f7b93..00000000000
--- a/app/assets/javascripts/issues/list/queries/user.fragment.graphql
+++ /dev/null
@@ -1,6 +0,0 @@
-fragment User on User {
- id
- avatarUrl
- name
- username
-}
diff --git a/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue b/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue
index d819a371c69..5e81f7ad4f6 100644
--- a/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue
+++ b/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue
@@ -4,7 +4,6 @@ import { GlLink, GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import { sprintf, __, n__ } from '~/locale';
import RelatedIssuableItem from '~/issuable/components/related_issuable_item.vue';
-import { parseIssuableData } from '~/issues/show/utils/parse_data';
export default {
name: 'RelatedMergeRequests',
@@ -19,6 +18,11 @@ export default {
type: String,
required: true,
},
+ hasClosingMergeRequest: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
projectNamespace: {
type: String,
required: true,
@@ -48,9 +52,6 @@ export default {
this.setInitialState({ apiEndpoint: this.endpoint });
this.fetchMergeRequests();
},
- created() {
- this.hasClosingMergeRequest = parseIssuableData().hasClosingMergeRequest;
- },
methods: {
...mapActions(['setInitialState', 'fetchMergeRequests']),
getAssignees(mr) {
diff --git a/app/assets/javascripts/issues/related_merge_requests/index.js b/app/assets/javascripts/issues/related_merge_requests/index.js
index 196084093c8..413b48b9720 100644
--- a/app/assets/javascripts/issues/related_merge_requests/index.js
+++ b/app/assets/javascripts/issues/related_merge_requests/index.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
import RelatedMergeRequests from './components/related_merge_requests.vue';
import createStore from './store';
@@ -9,7 +10,7 @@ export function initRelatedMergeRequests() {
return undefined;
}
- const { endpoint, projectPath, projectNamespace } = el.dataset;
+ const { endpoint, hasClosingMergeRequest, projectPath, projectNamespace } = el.dataset;
return new Vue({
el,
@@ -17,7 +18,12 @@ export function initRelatedMergeRequests() {
store: createStore(),
render: (createElement) =>
createElement(RelatedMergeRequests, {
- props: { endpoint, projectNamespace, projectPath },
+ props: {
+ endpoint,
+ hasClosingMergeRequest: parseBoolean(hasClosingMergeRequest),
+ projectNamespace,
+ projectPath,
+ },
}),
});
}
diff --git a/app/assets/javascripts/issues/service_desk/components/empty_state_with_any_issues.vue b/app/assets/javascripts/issues/service_desk/components/empty_state_with_any_issues.vue
new file mode 100644
index 00000000000..ab9e70ae223
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/components/empty_state_with_any_issues.vue
@@ -0,0 +1,59 @@
+<script>
+import { GlEmptyState } from '@gitlab/ui';
+import {
+ noSearchResultsTitle,
+ noSearchResultsDescription,
+ infoBannerUserNote,
+ noOpenIssuesTitle,
+ noClosedIssuesTitle,
+} from '../constants';
+
+export default {
+ i18n: {
+ noSearchResultsTitle,
+ noSearchResultsDescription,
+ infoBannerUserNote,
+ noOpenIssuesTitle,
+ noClosedIssuesTitle,
+ },
+ components: {
+ GlEmptyState,
+ },
+ inject: ['emptyStateSvgPath'],
+ props: {
+ hasSearch: {
+ type: Boolean,
+ required: true,
+ },
+ isOpenTab: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ content() {
+ if (this.hasSearch) {
+ return {
+ title: noSearchResultsTitle,
+ description: noSearchResultsDescription,
+ svgHeight: 150,
+ };
+ }
+ if (this.isOpenTab) {
+ return { title: noOpenIssuesTitle, description: infoBannerUserNote };
+ }
+
+ return { title: noClosedIssuesTitle, svgHeight: 150 };
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-empty-state
+ :description="content.description"
+ :title="content.title"
+ :svg-path="emptyStateSvgPath"
+ :svg-height="content.svgHeight"
+ />
+</template>
diff --git a/app/assets/javascripts/service_desk/components/empty_state_without_any_issues.vue b/app/assets/javascripts/issues/service_desk/components/empty_state_without_any_issues.vue
index 9dbed2c2579..9dbed2c2579 100644
--- a/app/assets/javascripts/service_desk/components/empty_state_without_any_issues.vue
+++ b/app/assets/javascripts/issues/service_desk/components/empty_state_without_any_issues.vue
diff --git a/app/assets/javascripts/service_desk/components/info_banner.vue b/app/assets/javascripts/issues/service_desk/components/info_banner.vue
index 5667ee2f31d..5667ee2f31d 100644
--- a/app/assets/javascripts/service_desk/components/info_banner.vue
+++ b/app/assets/javascripts/issues/service_desk/components/info_banner.vue
diff --git a/app/assets/javascripts/issues/service_desk/components/service_desk_list_app.vue b/app/assets/javascripts/issues/service_desk/components/service_desk_list_app.vue
new file mode 100644
index 00000000000..4b59672428b
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/components/service_desk_list_app.vue
@@ -0,0 +1,599 @@
+<script>
+import * as Sentry from '@sentry/browser';
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
+import { isEmpty } from 'lodash';
+import { fetchPolicies } from '~/lib/graphql';
+import { isPositiveInteger } from '~/lib/utils/number_utils';
+import axios from '~/lib/utils/axios_utils';
+import { getParameterByName, joinPaths } from '~/lib/utils/url_utility';
+import { scrollUp } from '~/lib/utils/scroll_utils';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
+import { DEFAULT_PAGE_SIZE, issuableListTabs } from '~/vue_shared/issuable/list/constants';
+import {
+ convertToSearchQuery,
+ convertToApiParams,
+ getInitialPageParams,
+ getFilterTokens,
+ isSortKey,
+ getSortOptions,
+ getSortKey,
+} from '~/issues/list/utils';
+import {
+ OPERATORS_IS_NOT,
+ OPERATORS_IS_NOT_OR,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ MAX_LIST_SIZE,
+ ISSUE_REFERENCE,
+ PARAM_STATE,
+ PARAM_FIRST_PAGE_SIZE,
+ PARAM_LAST_PAGE_SIZE,
+ PARAM_PAGE_AFTER,
+ PARAM_PAGE_BEFORE,
+ PARAM_SORT,
+ CREATED_DESC,
+ UPDATED_DESC,
+ RELATIVE_POSITION_ASC,
+ urlSortParams,
+} from '~/issues/list/constants';
+import { createAlert, VARIANT_INFO } from '~/alert';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { TYPENAME_USER } from '~/graphql_shared/constants';
+import searchProjectMembers from '~/graphql_shared/queries/project_user_members_search.query.graphql';
+import getServiceDeskIssuesQuery from 'ee_else_ce/issues/service_desk/queries/get_service_desk_issues.query.graphql';
+import getServiceDeskIssuesCounts from 'ee_else_ce/issues/service_desk/queries/get_service_desk_issues_counts.query.graphql';
+import searchProjectLabelsQuery from '../queries/search_project_labels.query.graphql';
+import searchProjectMilestonesQuery from '../queries/search_project_milestones.query.graphql';
+import setSortingPreferenceMutation from '../queries/set_sorting_preference.mutation.graphql';
+import reorderServiceDeskIssuesMutation from '../queries/reorder_service_desk_issues.mutation.graphql';
+import {
+ errorFetchingCounts,
+ errorFetchingIssues,
+ issueRepositioningMessage,
+ reorderError,
+ SERVICE_DESK_BOT_USERNAME,
+ STATUS_OPEN,
+ STATUS_CLOSED,
+ STATUS_ALL,
+ WORKSPACE_PROJECT,
+} from '../constants';
+import { convertToUrlParams } from '../utils';
+import {
+ searchWithinTokenBase,
+ assigneeTokenBase,
+ milestoneTokenBase,
+ labelTokenBase,
+ releaseTokenBase,
+ reactionTokenBase,
+ confidentialityTokenBase,
+} from '../search_tokens';
+import InfoBanner from './info_banner.vue';
+import EmptyStateWithAnyIssues from './empty_state_with_any_issues.vue';
+import EmptyStateWithoutAnyIssues from './empty_state_without_any_issues.vue';
+
+export default {
+ i18n: {
+ errorFetchingCounts,
+ errorFetchingIssues,
+ issueRepositioningMessage,
+ reorderError,
+ },
+ issuableListTabs,
+ components: {
+ IssuableList,
+ InfoBanner,
+ EmptyStateWithAnyIssues,
+ EmptyStateWithoutAnyIssues,
+ },
+ mixins: [glFeatureFlagMixin()],
+ inject: [
+ 'releasesPath',
+ 'autocompleteAwardEmojisPath',
+ 'hasBlockedIssuesFeature',
+ 'hasIterationsFeature',
+ 'hasIssueWeightsFeature',
+ 'hasIssuableHealthStatusFeature',
+ 'groupPath',
+ 'emptyStateSvgPath',
+ 'isProject',
+ 'isSignedIn',
+ 'fullPath',
+ 'isServiceDeskSupported',
+ 'hasAnyIssues',
+ 'initialSort',
+ 'isIssueRepositioningDisabled',
+ ],
+ props: {
+ eeSearchTokens: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ data() {
+ return {
+ serviceDeskIssues: [],
+ serviceDeskIssuesCounts: {},
+ filterTokens: [],
+ pageInfo: {},
+ pageParams: {},
+ sortKey: CREATED_DESC,
+ state: STATUS_OPEN,
+ pageSize: DEFAULT_PAGE_SIZE,
+ issuesError: '',
+ };
+ },
+ apollo: {
+ serviceDeskIssues: {
+ query: getServiceDeskIssuesQuery,
+ variables() {
+ return this.queryVariables;
+ },
+ update(data) {
+ return data.project.issues.nodes ?? [];
+ },
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
+ // We need this for handling loading state when using frontend cache
+ // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106004#note_1217325202 for details
+ notifyOnNetworkStatusChange: true,
+ result({ data }) {
+ if (!data) {
+ return;
+ }
+ this.pageInfo = data?.project.issues.pageInfo ?? {};
+ },
+ error(error) {
+ this.issuesError = this.$options.i18n.errorFetchingIssues;
+ Sentry.captureException(error);
+ },
+ skip() {
+ return this.shouldSkipQuery;
+ },
+ },
+ serviceDeskIssuesCounts: {
+ query: getServiceDeskIssuesCounts,
+ variables() {
+ return this.queryVariables;
+ },
+ update(data) {
+ return data?.project ?? {};
+ },
+ error(error) {
+ this.issuesError = this.$options.i18n.errorFetchingCounts;
+ Sentry.captureException(error);
+ },
+ skip() {
+ return this.shouldSkipQuery;
+ },
+ context: {
+ isSingleRequest: true,
+ },
+ },
+ },
+ computed: {
+ queryVariables() {
+ const isIidSearch = ISSUE_REFERENCE.test(this.searchQuery);
+ return {
+ fullPath: this.fullPath,
+ iid: isIidSearch ? this.searchQuery.slice(1) : undefined,
+ isSignedIn: this.isSignedIn,
+ authorUsername: SERVICE_DESK_BOT_USERNAME,
+ sort: this.sortKey,
+ state: this.state,
+ ...this.pageParams,
+ ...this.apiFilterParams,
+ search: isIidSearch ? undefined : this.searchQuery,
+ };
+ },
+ shouldSkipQuery() {
+ return !this.hasAnyIssues || isEmpty(this.pageParams);
+ },
+ sortOptions() {
+ return getSortOptions({
+ hasBlockedIssuesFeature: this.hasBlockedIssuesFeature,
+ hasIssuableHealthStatusFeature: this.hasIssuableHealthStatusFeature,
+ hasIssueWeightsFeature: this.hasIssueWeightsFeature,
+ });
+ },
+ tabCounts() {
+ const { openedIssues, closedIssues, allIssues } = this.serviceDeskIssuesCounts;
+ return {
+ [STATUS_OPEN]: openedIssues?.count,
+ [STATUS_CLOSED]: closedIssues?.count,
+ [STATUS_ALL]: allIssues?.count,
+ };
+ },
+ currentTabCount() {
+ return this.tabCounts[this.state] ?? 0;
+ },
+ showPaginationControls() {
+ return (
+ this.serviceDeskIssues.length > 0 &&
+ (this.pageInfo.hasNextPage || this.pageInfo.hasPreviousPage)
+ );
+ },
+ showPageSizeControls() {
+ return this.currentTabCount > DEFAULT_PAGE_SIZE;
+ },
+ isLoading() {
+ return this.$apollo.loading;
+ },
+ isOpenTab() {
+ return this.state === STATUS_OPEN;
+ },
+ urlParams() {
+ return {
+ sort: urlSortParams[this.sortKey],
+ state: this.state,
+ ...this.urlFilterParams,
+ first_page_size: this.pageParams.firstPageSize,
+ last_page_size: this.pageParams.lastPageSize,
+ page_after: this.pageParams.afterCursor ?? undefined,
+ page_before: this.pageParams.beforeCursor ?? undefined,
+ };
+ },
+ hasAnyServiceDeskIssue() {
+ return this.hasSearch || Boolean(this.tabCounts.all);
+ },
+ isInfoBannerVisible() {
+ return this.isServiceDeskSupported && this.hasAnyServiceDeskIssue;
+ },
+ canShowIssuesList() {
+ return this.isLoading || this.issuesError.length || this.hasAnyServiceDeskIssue;
+ },
+ hasOrFeature() {
+ return this.glFeatures.orIssuableQueries;
+ },
+ hasSearch() {
+ return Boolean(
+ this.searchQuery ||
+ Object.keys(this.urlFilterParams).length ||
+ this.pageParams.afterCursor ||
+ this.pageParams.beforeCursor,
+ );
+ },
+ apiFilterParams() {
+ return convertToApiParams(this.filterTokens);
+ },
+ urlFilterParams() {
+ return convertToUrlParams(this.filterTokens);
+ },
+ searchQuery() {
+ return convertToSearchQuery(this.filterTokens);
+ },
+ searchTokens() {
+ const preloadedUsers = [];
+
+ if (gon.current_user_id) {
+ preloadedUsers.push({
+ id: convertToGraphQLId(TYPENAME_USER, gon.current_user_id),
+ name: gon.current_user_fullname,
+ username: gon.current_username,
+ avatar_url: gon.current_user_avatar_url,
+ });
+ }
+
+ const tokens = [
+ {
+ ...searchWithinTokenBase,
+ },
+ {
+ ...assigneeTokenBase,
+ operators: this.hasOrFeature ? OPERATORS_IS_NOT_OR : OPERATORS_IS_NOT,
+ fetchUsers: this.fetchUsers,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-assignee`,
+ preloadedUsers,
+ },
+ {
+ ...milestoneTokenBase,
+ fetchMilestones: this.fetchMilestones,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-milestone`,
+ },
+ {
+ ...labelTokenBase,
+ operators: this.hasOrFeature ? OPERATORS_IS_NOT_OR : OPERATORS_IS_NOT,
+ fetchLabels: this.fetchLabels,
+ fetchLatestLabels: this.glFeatures.frontendCaching ? this.fetchLatestLabels : null,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-label`,
+ },
+ ];
+
+ if (this.isProject) {
+ tokens.push({
+ ...releaseTokenBase,
+ fetchReleases: this.fetchReleases,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-release`,
+ });
+ }
+
+ if (this.isSignedIn) {
+ tokens.push({
+ ...reactionTokenBase,
+ fetchEmojis: this.fetchEmojis,
+ recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-my_reaction`,
+ });
+
+ tokens.push({
+ ...confidentialityTokenBase,
+ });
+ }
+
+ if (this.eeSearchTokens.length) {
+ tokens.push(...this.eeSearchTokens);
+ }
+
+ tokens.sort((a, b) => a.title.localeCompare(b.title));
+
+ return tokens;
+ },
+ isManualOrdering() {
+ return this.sortKey === RELATIVE_POSITION_ASC;
+ },
+ },
+ watch: {
+ $route(newValue, oldValue) {
+ if (newValue.fullPath !== oldValue.fullPath) {
+ this.updateData(getParameterByName(PARAM_SORT));
+ }
+ },
+ },
+ created() {
+ this.updateData(this.initialSort);
+ this.cache = {};
+ },
+ methods: {
+ fetchWithCache(path, cacheName, searchKey, search) {
+ if (this.cache[cacheName]) {
+ const data = search
+ ? fuzzaldrinPlus.filter(this.cache[cacheName], search, { key: searchKey })
+ : this.cache[cacheName].slice(0, MAX_LIST_SIZE);
+ return Promise.resolve(data);
+ }
+
+ return axios.get(path).then(({ data }) => {
+ this.cache[cacheName] = data;
+ return data.slice(0, MAX_LIST_SIZE);
+ });
+ },
+ fetchUsers(search) {
+ return this.$apollo
+ .query({
+ query: searchProjectMembers,
+ variables: { fullPath: this.fullPath, search },
+ })
+ .then(({ data }) =>
+ data[WORKSPACE_PROJECT]?.[`${WORKSPACE_PROJECT}Members`].nodes.map(
+ (member) => member.user,
+ ),
+ );
+ },
+ fetchMilestones(search) {
+ return this.$apollo
+ .query({
+ query: searchProjectMilestonesQuery,
+ variables: { fullPath: this.fullPath, search },
+ })
+ .then(({ data }) => data[WORKSPACE_PROJECT]?.milestones.nodes);
+ },
+ fetchEmojis(search) {
+ return this.fetchWithCache(this.autocompleteAwardEmojisPath, 'emojis', 'name', search);
+ },
+ fetchReleases(search) {
+ return this.fetchWithCache(this.releasesPath, 'releases', 'tag', search);
+ },
+ fetchLabelsWithFetchPolicy(search, fetchPolicy = fetchPolicies.CACHE_FIRST) {
+ return this.$apollo
+ .query({
+ query: searchProjectLabelsQuery,
+ variables: { fullPath: this.fullPath, search },
+ fetchPolicy,
+ })
+ .then(({ data }) => data[WORKSPACE_PROJECT]?.labels.nodes)
+ .then((labels) =>
+ // TODO remove once we can search by title-only on the backend
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/346353
+ labels.filter((label) => label.title.toLowerCase().includes(search.toLowerCase())),
+ );
+ },
+ fetchLabels(search) {
+ return this.fetchLabelsWithFetchPolicy(search);
+ },
+ fetchLatestLabels(search) {
+ return this.fetchLabelsWithFetchPolicy(search, fetchPolicies.NETWORK_ONLY);
+ },
+ handleClickTab(state) {
+ if (this.state === state) {
+ return;
+ }
+ this.state = state;
+ this.pageParams = getInitialPageParams(this.pageSize);
+
+ this.$router.push({ query: this.urlParams });
+ },
+ handleFilter(tokens) {
+ this.filterTokens = tokens;
+ this.pageParams = getInitialPageParams(this.pageSize);
+
+ this.$router.push({ query: this.urlParams });
+ },
+ handleDismissAlert() {
+ this.issuesError = '';
+ },
+ handleNextPage() {
+ this.pageParams = {
+ afterCursor: this.pageInfo.endCursor,
+ firstPageSize: this.pageSize,
+ };
+ scrollUp();
+
+ this.$router.push({ query: this.urlParams });
+ },
+ handlePreviousPage() {
+ this.pageParams = {
+ beforeCursor: this.pageInfo.startCursor,
+ lastPageSize: this.pageSize,
+ };
+ scrollUp();
+
+ this.$router.push({ query: this.urlParams });
+ },
+ handlePageSizeChange(newPageSize) {
+ const pageParam = getParameterByName(PARAM_LAST_PAGE_SIZE) ? 'lastPageSize' : 'firstPageSize';
+ this.pageParams[pageParam] = newPageSize;
+ this.pageSize = newPageSize;
+ scrollUp();
+
+ this.$router.push({ query: this.urlParams });
+ },
+ handleSort(sortKey) {
+ if (this.sortKey === sortKey) {
+ return;
+ }
+
+ if (this.isIssueRepositioningDisabled && sortKey === RELATIVE_POSITION_ASC) {
+ this.showIssueRepositioningMessage();
+ return;
+ }
+
+ this.sortKey = sortKey;
+ this.pageParams = getInitialPageParams(this.pageSize);
+
+ if (this.isSignedIn) {
+ this.saveSortPreference(sortKey);
+ }
+
+ this.$router.push({ query: this.urlParams });
+ },
+ saveSortPreference(sortKey) {
+ this.$apollo
+ .mutate({
+ mutation: setSortingPreferenceMutation,
+ variables: { input: { issuesSort: sortKey } },
+ })
+ .then(({ data }) => {
+ if (data.userPreferencesUpdate.errors.length) {
+ throw new Error(data.userPreferencesUpdate.errors);
+ }
+ })
+ .catch((error) => {
+ Sentry.captureException(error);
+ });
+ },
+ handleReorder({ newIndex, oldIndex }) {
+ const issueToMove = this.serviceDeskIssues[oldIndex];
+ const isDragDropDownwards = newIndex > oldIndex;
+ const isMovingToBeginning = newIndex === 0;
+ const isMovingToEnd = newIndex === this.serviceDeskIssues.length - 1;
+
+ let moveBeforeId;
+ let moveAfterId;
+
+ if (isDragDropDownwards) {
+ const afterIndex = isMovingToEnd ? newIndex : newIndex + 1;
+ moveBeforeId = this.serviceDeskIssues[newIndex].id;
+ moveAfterId = this.serviceDeskIssues[afterIndex].id;
+ } else {
+ const beforeIndex = isMovingToBeginning ? newIndex : newIndex - 1;
+ moveBeforeId = this.serviceDeskIssues[beforeIndex].id;
+ moveAfterId = this.serviceDeskIssues[newIndex].id;
+ }
+
+ return axios
+ .put(joinPaths(issueToMove.webPath, 'reorder'), {
+ move_before_id: isMovingToBeginning ? null : getIdFromGraphQLId(moveBeforeId),
+ move_after_id: isMovingToEnd ? null : getIdFromGraphQLId(moveAfterId),
+ })
+ .then(() => {
+ const serializedVariables = JSON.stringify(this.queryVariables);
+ return this.$apollo.mutate({
+ mutation: reorderServiceDeskIssuesMutation,
+ variables: { oldIndex, newIndex, namespace: this.namespace, serializedVariables },
+ });
+ })
+ .catch((error) => {
+ this.issuesError = this.$options.i18n.reorderError;
+ Sentry.captureException(error);
+ });
+ },
+ updateData(sortValue) {
+ const firstPageSize = getParameterByName(PARAM_FIRST_PAGE_SIZE);
+ const lastPageSize = getParameterByName(PARAM_LAST_PAGE_SIZE);
+ const state = getParameterByName(PARAM_STATE);
+
+ const defaultSortKey = state === STATUS_CLOSED ? UPDATED_DESC : CREATED_DESC;
+ const dashboardSortKey = getSortKey(sortValue);
+ const graphQLSortKey = isSortKey(sortValue?.toUpperCase()) && sortValue.toUpperCase();
+
+ let sortKey = dashboardSortKey || graphQLSortKey || defaultSortKey;
+
+ if (this.isIssueRepositioningDisabled && sortKey === RELATIVE_POSITION_ASC) {
+ this.showIssueRepositioningMessage();
+ sortKey = defaultSortKey;
+ }
+
+ this.filterTokens = getFilterTokens(window.location.search);
+
+ this.pageParams = getInitialPageParams(
+ this.pageSize,
+ isPositiveInteger(firstPageSize) ? parseInt(firstPageSize, 10) : undefined,
+ isPositiveInteger(lastPageSize) ? parseInt(lastPageSize, 10) : undefined,
+ getParameterByName(PARAM_PAGE_AFTER),
+ getParameterByName(PARAM_PAGE_BEFORE),
+ );
+ this.sortKey = sortKey;
+ this.state = state || STATUS_OPEN;
+ },
+ showIssueRepositioningMessage() {
+ createAlert({
+ message: this.$options.i18n.issueRepositioningMessage,
+ variant: VARIANT_INFO,
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <section>
+ <info-banner v-if="isInfoBannerVisible" />
+ <issuable-list
+ v-if="canShowIssuesList"
+ namespace="service-desk"
+ recent-searches-storage-key="service-desk-issues"
+ :error="issuesError"
+ :search-tokens="searchTokens"
+ :issuables-loading="isLoading"
+ :initial-filter-value="filterTokens"
+ :show-filtered-search-friendly-text="hasOrFeature"
+ :show-pagination-controls="showPaginationControls"
+ :show-page-size-change-controls="showPageSizeControls"
+ :sort-options="sortOptions"
+ :initial-sort-by="sortKey"
+ :is-manual-ordering="isManualOrdering"
+ :issuables="serviceDeskIssues"
+ :tabs="$options.issuableListTabs"
+ :tab-counts="tabCounts"
+ :current-tab="state"
+ :default-page-size="pageSize"
+ :has-next-page="pageInfo.hasNextPage"
+ :has-previous-page="pageInfo.hasPreviousPage"
+ sync-filter-and-sort
+ use-keyset-pagination
+ @click-tab="handleClickTab"
+ @dismiss-alert="handleDismissAlert"
+ @filter="handleFilter"
+ @sort="handleSort"
+ @reorder="handleReorder"
+ @next-page="handleNextPage"
+ @previous-page="handlePreviousPage"
+ @page-size-change="handlePageSizeChange"
+ >
+ <template #empty-state>
+ <empty-state-with-any-issues :has-search="hasSearch" :is-open-tab="isOpenTab" />
+ </template>
+ </issuable-list>
+
+ <empty-state-without-any-issues v-else />
+ </section>
+</template>
diff --git a/app/assets/javascripts/issues/service_desk/constants.js b/app/assets/javascripts/issues/service_desk/constants.js
new file mode 100644
index 00000000000..e498a4f39a1
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/constants.js
@@ -0,0 +1,254 @@
+import { __, s__ } from '~/locale';
+import {
+ FILTERED_SEARCH_TERM,
+ OPERATOR_IS,
+ OPERATOR_NOT,
+ OPERATOR_OR,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_EPIC,
+ TOKEN_TYPE_HEALTH,
+ TOKEN_TYPE_ITERATION,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
+ TOKEN_TYPE_WEIGHT,
+ TOKEN_TYPE_SEARCH_WITHIN,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ ALTERNATIVE_FILTER,
+ API_PARAM,
+ NORMAL_FILTER,
+ SPECIAL_FILTER,
+ URL_PARAM,
+} from '~/issues/list/constants';
+
+export const SERVICE_DESK_BOT_USERNAME = 'support-bot';
+export const ISSUE_REFERENCE = /^#\d+$/;
+
+export const STATUS_ALL = 'all';
+export const STATUS_CLOSED = 'closed';
+export const STATUS_OPEN = 'opened';
+
+export const WORKSPACE_PROJECT = 'project';
+
+export const filtersMap = {
+ [FILTERED_SEARCH_TERM]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'search',
+ },
+ [URL_PARAM]: {
+ [undefined]: {
+ [NORMAL_FILTER]: 'search',
+ },
+ },
+ },
+ [TOKEN_TYPE_SEARCH_WITHIN]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'in',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'in',
+ },
+ },
+ },
+ [TOKEN_TYPE_ASSIGNEE]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'assigneeUsernames',
+ [SPECIAL_FILTER]: 'assigneeId',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'assignee_username[]',
+ [SPECIAL_FILTER]: 'assignee_id',
+ [ALTERNATIVE_FILTER]: 'assignee_username',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[assignee_username][]',
+ },
+ [OPERATOR_OR]: {
+ [NORMAL_FILTER]: 'or[assignee_username][]',
+ },
+ },
+ },
+ [TOKEN_TYPE_MILESTONE]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'milestoneTitle',
+ [SPECIAL_FILTER]: 'milestoneWildcardId',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'milestone_title',
+ [SPECIAL_FILTER]: 'milestone_title',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[milestone_title]',
+ [SPECIAL_FILTER]: 'not[milestone_title]',
+ },
+ },
+ },
+ [TOKEN_TYPE_LABEL]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'labelName',
+ [SPECIAL_FILTER]: 'labelName',
+ [ALTERNATIVE_FILTER]: 'labelNames',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'label_name[]',
+ [SPECIAL_FILTER]: 'label_name[]',
+ [ALTERNATIVE_FILTER]: 'label_name',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[label_name][]',
+ },
+ [OPERATOR_OR]: {
+ [ALTERNATIVE_FILTER]: 'or[label_name][]',
+ },
+ },
+ },
+ [TOKEN_TYPE_TYPE]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'types',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'type[]',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[type][]',
+ },
+ },
+ },
+ [TOKEN_TYPE_RELEASE]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'releaseTag',
+ [SPECIAL_FILTER]: 'releaseTagWildcardId',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'release_tag',
+ [SPECIAL_FILTER]: 'release_tag',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[release_tag]',
+ },
+ },
+ },
+ [TOKEN_TYPE_MY_REACTION]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'myReactionEmoji',
+ [SPECIAL_FILTER]: 'myReactionEmoji',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'my_reaction_emoji',
+ [SPECIAL_FILTER]: 'my_reaction_emoji',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[my_reaction_emoji]',
+ },
+ },
+ },
+ [TOKEN_TYPE_CONFIDENTIAL]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'confidential',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'confidential',
+ },
+ },
+ },
+ [TOKEN_TYPE_ITERATION]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'iterationId',
+ [SPECIAL_FILTER]: 'iterationWildcardId',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'iteration_id',
+ [SPECIAL_FILTER]: 'iteration_id',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[iteration_id]',
+ [SPECIAL_FILTER]: 'not[iteration_id]',
+ },
+ },
+ },
+ [TOKEN_TYPE_EPIC]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'epicId',
+ [SPECIAL_FILTER]: 'epicId',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'epic_id',
+ [SPECIAL_FILTER]: 'epic_id',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[epic_id]',
+ },
+ },
+ },
+ [TOKEN_TYPE_WEIGHT]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'weight',
+ [SPECIAL_FILTER]: 'weight',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'weight',
+ [SPECIAL_FILTER]: 'weight',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[weight]',
+ },
+ },
+ },
+ [TOKEN_TYPE_HEALTH]: {
+ [API_PARAM]: {
+ [NORMAL_FILTER]: 'healthStatusFilter',
+ [SPECIAL_FILTER]: 'healthStatusFilter',
+ },
+ [URL_PARAM]: {
+ [OPERATOR_IS]: {
+ [NORMAL_FILTER]: 'health_status',
+ [SPECIAL_FILTER]: 'health_status',
+ },
+ [OPERATOR_NOT]: {
+ [NORMAL_FILTER]: 'not[health_status]',
+ },
+ },
+ },
+};
+
+export const errorFetchingCounts = __('An error occurred while getting issue counts');
+export const errorFetchingIssues = __('An error occurred while loading issues');
+export const noOpenIssuesTitle = __('There are no open issues');
+export const noClosedIssuesTitle = __('There are no closed issues');
+export const noIssuesSignedOutButtonText = __('Register / Sign In');
+export const noSearchResultsDescription = __(
+ 'To widen your search, change or remove filters above',
+);
+export const noSearchResultsTitle = __('Sorry, your filter produced no results');
+export const issueRepositioningMessage = __(
+ 'Issues are being rebalanced at the moment, so manual reordering is disabled.',
+);
+export const reorderError = __('An error occurred while reordering issues.');
+export const infoBannerTitle = s__(
+ 'ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab',
+);
+export const infoBannerAdminNote = s__('ServiceDesk|Your users can send emails to this address:');
+export const infoBannerUserNote = s__(
+ 'ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation.',
+);
+export const enableServiceDesk = s__('ServiceDesk|Enable Service Desk');
+export const learnMore = __('Learn more about Service Desk');
+export const titles = __('Titles');
+export const descriptions = __('Descriptions');
+export const no = __('No');
+export const yes = __('Yes');
diff --git a/app/assets/javascripts/service_desk/graphql.js b/app/assets/javascripts/issues/service_desk/graphql.js
index e01973f1e8a..e01973f1e8a 100644
--- a/app/assets/javascripts/service_desk/graphql.js
+++ b/app/assets/javascripts/issues/service_desk/graphql.js
diff --git a/app/assets/javascripts/issues/service_desk/index.js b/app/assets/javascripts/issues/service_desk/index.js
new file mode 100644
index 00000000000..579cf343477
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/index.js
@@ -0,0 +1,82 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import VueRouter from 'vue-router';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import ServiceDeskListApp from 'ee_else_ce/issues/service_desk/components/service_desk_list_app.vue';
+import { gqlClient } from './graphql';
+
+export async function mountServiceDeskListApp() {
+ const el = document.querySelector('.js-service-desk-list');
+
+ if (!el) {
+ return null;
+ }
+
+ const {
+ projectDataReleasesPath,
+ projectDataAutocompleteAwardEmojisPath,
+ projectDataHasBlockedIssuesFeature,
+ projectDataHasIterationsFeature,
+ projectDataHasIssueWeightsFeature,
+ projectDataHasIssuableHealthStatusFeature,
+ projectDataGroupPath,
+ projectDataEmptyStateSvgPath,
+ projectDataFullPath,
+ projectDataIsProject,
+ projectDataIsSignedIn,
+ projectDataSignInPath,
+ projectDataHasAnyIssues,
+ projectDataInitialSort,
+ projectDataIsIssueRepositioningDisabled,
+ serviceDeskEmailAddress,
+ canAdminIssues,
+ canEditProjectSettings,
+ serviceDeskCalloutSvgPath,
+ serviceDeskSettingsPath,
+ serviceDeskHelpPath,
+ isServiceDeskSupported,
+ isServiceDeskEnabled,
+ } = el.dataset;
+
+ Vue.use(VueApollo);
+ Vue.use(VueRouter);
+
+ return new Vue({
+ el,
+ name: 'ServiceDeskListRoot',
+ apolloProvider: new VueApollo({
+ defaultClient: await gqlClient(),
+ }),
+ router: new VueRouter({
+ base: window.location.pathname,
+ mode: 'history',
+ routes: [{ path: '/' }],
+ }),
+ provide: {
+ releasesPath: projectDataReleasesPath,
+ autocompleteAwardEmojisPath: projectDataAutocompleteAwardEmojisPath,
+ hasBlockedIssuesFeature: parseBoolean(projectDataHasBlockedIssuesFeature),
+ hasIterationsFeature: parseBoolean(projectDataHasIterationsFeature),
+ hasIssueWeightsFeature: parseBoolean(projectDataHasIssueWeightsFeature),
+ hasIssuableHealthStatusFeature: parseBoolean(projectDataHasIssuableHealthStatusFeature),
+ groupPath: projectDataGroupPath,
+ emptyStateSvgPath: projectDataEmptyStateSvgPath,
+ fullPath: projectDataFullPath,
+ isProject: parseBoolean(projectDataIsProject),
+ isSignedIn: parseBoolean(projectDataIsSignedIn),
+ serviceDeskEmailAddress,
+ canAdminIssues: parseBoolean(canAdminIssues),
+ canEditProjectSettings: parseBoolean(canEditProjectSettings),
+ serviceDeskCalloutSvgPath,
+ serviceDeskSettingsPath,
+ serviceDeskHelpPath,
+ isServiceDeskSupported: parseBoolean(isServiceDeskSupported),
+ isServiceDeskEnabled: parseBoolean(isServiceDeskEnabled),
+ signInPath: projectDataSignInPath,
+ hasAnyIssues: parseBoolean(projectDataHasAnyIssues),
+ initialSort: projectDataInitialSort,
+ isIssueRepositioningDisabled: parseBoolean(projectDataIsIssueRepositioningDisabled),
+ },
+ render: (createComponent) => createComponent(ServiceDeskListApp),
+ });
+}
diff --git a/app/assets/javascripts/issues/service_desk/queries/get_service_desk_issues.query.graphql b/app/assets/javascripts/issues/service_desk/queries/get_service_desk_issues.query.graphql
new file mode 100644
index 00000000000..d8cd28f5cf1
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/queries/get_service_desk_issues.query.graphql
@@ -0,0 +1,67 @@
+#import "~/graphql_shared/fragments/page_info.fragment.graphql"
+#import "./issue.fragment.graphql"
+
+query getServiceDeskIssues(
+ $hideUsers: Boolean = false
+ $isSignedIn: Boolean = false
+ $fullPath: ID!
+ $iid: String
+ $search: String
+ $sort: IssueSort
+ $state: IssuableState
+ $in: [IssuableSearchableField!]
+ $assigneeId: String
+ $assigneeUsernames: [String!]
+ $authorUsername: String
+ $confidential: Boolean
+ $labelName: [String]
+ $milestoneTitle: [String]
+ $milestoneWildcardId: MilestoneWildcardId
+ $myReactionEmoji: String
+ $releaseTag: [String!]
+ $releaseTagWildcardId: ReleaseTagWildcardId
+ $types: [IssueType!]
+ $not: NegatedIssueFilterInput
+ $or: UnionedIssueFilterInput
+ $beforeCursor: String
+ $afterCursor: String
+ $firstPageSize: Int
+ $lastPageSize: Int
+) {
+ project(fullPath: $fullPath) @persist {
+ id
+ issues(
+ iid: $iid
+ search: $search
+ sort: $sort
+ state: $state
+ in: $in
+ assigneeId: $assigneeId
+ assigneeUsernames: $assigneeUsernames
+ authorUsername: $authorUsername
+ confidential: $confidential
+ labelName: $labelName
+ milestoneTitle: $milestoneTitle
+ milestoneWildcardId: $milestoneWildcardId
+ myReactionEmoji: $myReactionEmoji
+ releaseTag: $releaseTag
+ releaseTagWildcardId: $releaseTagWildcardId
+ types: $types
+ not: $not
+ or: $or
+ before: $beforeCursor
+ after: $afterCursor
+ first: $firstPageSize
+ last: $lastPageSize
+ ) {
+ __persist
+ pageInfo {
+ ...PageInfo
+ }
+ nodes {
+ __persist
+ ...IssueFragment
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/issues/service_desk/queries/get_service_desk_issues_counts.query.graphql b/app/assets/javascripts/issues/service_desk/queries/get_service_desk_issues_counts.query.graphql
new file mode 100644
index 00000000000..008cde60b74
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/queries/get_service_desk_issues_counts.query.graphql
@@ -0,0 +1,82 @@
+query getServiceDeskIssuesCount(
+ $fullPath: ID!
+ $iid: String
+ $search: String
+ $assigneeId: String
+ $assigneeUsernames: [String!]
+ $authorUsername: String
+ $confidential: Boolean
+ $labelName: [String]
+ $milestoneTitle: [String]
+ $milestoneWildcardId: MilestoneWildcardId
+ $myReactionEmoji: String
+ $releaseTag: [String!]
+ $releaseTagWildcardId: ReleaseTagWildcardId
+ $types: [IssueType!]
+ $not: NegatedIssueFilterInput
+ $or: UnionedIssueFilterInput
+) {
+ project(fullPath: $fullPath) {
+ id
+ openedIssues: issues(
+ state: opened
+ iid: $iid
+ search: $search
+ assigneeId: $assigneeId
+ assigneeUsernames: $assigneeUsernames
+ authorUsername: $authorUsername
+ confidential: $confidential
+ labelName: $labelName
+ milestoneTitle: $milestoneTitle
+ milestoneWildcardId: $milestoneWildcardId
+ myReactionEmoji: $myReactionEmoji
+ releaseTag: $releaseTag
+ releaseTagWildcardId: $releaseTagWildcardId
+ types: $types
+ not: $not
+ or: $or
+ ) {
+ count
+ }
+ closedIssues: issues(
+ state: closed
+ iid: $iid
+ search: $search
+ assigneeId: $assigneeId
+ assigneeUsernames: $assigneeUsernames
+ authorUsername: $authorUsername
+ confidential: $confidential
+ labelName: $labelName
+ milestoneTitle: $milestoneTitle
+ milestoneWildcardId: $milestoneWildcardId
+ myReactionEmoji: $myReactionEmoji
+ releaseTag: $releaseTag
+ releaseTagWildcardId: $releaseTagWildcardId
+ types: $types
+ not: $not
+ or: $or
+ ) {
+ count
+ }
+ allIssues: issues(
+ state: all
+ iid: $iid
+ search: $search
+ assigneeId: $assigneeId
+ assigneeUsernames: $assigneeUsernames
+ authorUsername: $authorUsername
+ confidential: $confidential
+ labelName: $labelName
+ milestoneTitle: $milestoneTitle
+ milestoneWildcardId: $milestoneWildcardId
+ myReactionEmoji: $myReactionEmoji
+ releaseTag: $releaseTag
+ releaseTagWildcardId: $releaseTagWildcardId
+ types: $types
+ not: $not
+ or: $or
+ ) {
+ count
+ }
+ }
+}
diff --git a/app/assets/javascripts/issues/service_desk/queries/issue.fragment.graphql b/app/assets/javascripts/issues/service_desk/queries/issue.fragment.graphql
new file mode 100644
index 00000000000..f72663ae5f6
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/queries/issue.fragment.graphql
@@ -0,0 +1,61 @@
+fragment IssueFragment on Issue {
+ id
+ iid
+ confidential
+ createdAt
+ downvotes
+ dueDate
+ hidden
+ humanTimeEstimate
+ mergeRequestsCount
+ moved
+ state
+ title
+ updatedAt
+ closedAt
+ upvotes
+ userDiscussionsCount @include(if: $isSignedIn)
+ webPath
+ webUrl
+ type
+ assignees @skip(if: $hideUsers) {
+ nodes {
+ __persist
+ id
+ avatarUrl
+ name
+ username
+ webUrl
+ }
+ }
+ author @skip(if: $hideUsers) {
+ __persist
+ id
+ avatarUrl
+ name
+ username
+ webUrl
+ }
+ externalAuthor
+ labels {
+ nodes {
+ __persist
+ id
+ color
+ title
+ description
+ }
+ }
+ milestone {
+ __persist
+ id
+ dueDate
+ startDate
+ webPath
+ title
+ }
+ taskCompletionStatus {
+ completedCount
+ count
+ }
+}
diff --git a/app/assets/javascripts/service_desk/queries/label.fragment.graphql b/app/assets/javascripts/issues/service_desk/queries/label.fragment.graphql
index bb1d8f1ac9b..bb1d8f1ac9b 100644
--- a/app/assets/javascripts/service_desk/queries/label.fragment.graphql
+++ b/app/assets/javascripts/issues/service_desk/queries/label.fragment.graphql
diff --git a/app/assets/javascripts/service_desk/queries/milestone.fragment.graphql b/app/assets/javascripts/issues/service_desk/queries/milestone.fragment.graphql
index 3cdf69bf585..3cdf69bf585 100644
--- a/app/assets/javascripts/service_desk/queries/milestone.fragment.graphql
+++ b/app/assets/javascripts/issues/service_desk/queries/milestone.fragment.graphql
diff --git a/app/assets/javascripts/issues/service_desk/queries/reorder_service_desk_issues.mutation.graphql b/app/assets/javascripts/issues/service_desk/queries/reorder_service_desk_issues.mutation.graphql
new file mode 100644
index 00000000000..2da7850d77d
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/queries/reorder_service_desk_issues.mutation.graphql
@@ -0,0 +1,13 @@
+mutation reorderServiceDeskIssues(
+ $oldIndex: Int
+ $newIndex: Int
+ $namespace: String
+ $serializedVariables: String
+) {
+ reorderIssues(
+ oldIndex: $oldIndex
+ newIndex: $newIndex
+ namespace: $namespace
+ serializedVariables: $serializedVariables
+ ) @client
+}
diff --git a/app/assets/javascripts/service_desk/queries/search_project_labels.query.graphql b/app/assets/javascripts/issues/service_desk/queries/search_project_labels.query.graphql
index 89ce14134b4..89ce14134b4 100644
--- a/app/assets/javascripts/service_desk/queries/search_project_labels.query.graphql
+++ b/app/assets/javascripts/issues/service_desk/queries/search_project_labels.query.graphql
diff --git a/app/assets/javascripts/service_desk/queries/search_project_milestones.query.graphql b/app/assets/javascripts/issues/service_desk/queries/search_project_milestones.query.graphql
index f34166be87d..f34166be87d 100644
--- a/app/assets/javascripts/service_desk/queries/search_project_milestones.query.graphql
+++ b/app/assets/javascripts/issues/service_desk/queries/search_project_milestones.query.graphql
diff --git a/app/assets/javascripts/issues/service_desk/queries/set_sorting_preference.mutation.graphql b/app/assets/javascripts/issues/service_desk/queries/set_sorting_preference.mutation.graphql
new file mode 100644
index 00000000000..b01ae3863cd
--- /dev/null
+++ b/app/assets/javascripts/issues/service_desk/queries/set_sorting_preference.mutation.graphql
@@ -0,0 +1,5 @@
+mutation setSortingPreference($input: UserPreferencesUpdateInput!) {
+ userPreferencesUpdate(input: $input) {
+ errors
+ }
+}
diff --git a/app/assets/javascripts/service_desk/search_tokens.js b/app/assets/javascripts/issues/service_desk/search_tokens.js
index 72750f518e4..72750f518e4 100644
--- a/app/assets/javascripts/service_desk/search_tokens.js
+++ b/app/assets/javascripts/issues/service_desk/search_tokens.js
diff --git a/app/assets/javascripts/service_desk/utils.js b/app/assets/javascripts/issues/service_desk/utils.js
index 86f76da3880..86f76da3880 100644
--- a/app/assets/javascripts/service_desk/utils.js
+++ b/app/assets/javascripts/issues/service_desk/utils.js
diff --git a/app/assets/javascripts/issues/show/components/app.vue b/app/assets/javascripts/issues/show/components/app.vue
index 26c3db647a3..d59692d2a28 100644
--- a/app/assets/javascripts/issues/show/components/app.vue
+++ b/app/assets/javascripts/issues/show/components/app.vue
@@ -1,49 +1,36 @@
<script>
-import { GlIcon, GlBadge, GlIntersectionObserver, GlTooltipDirective } from '@gitlab/ui';
import Visibility from 'visibilityjs';
import { createAlert } from '~/alert';
-import {
- issuableStatusText,
- STATUS_CLOSED,
- TYPE_EPIC,
- TYPE_INCIDENT,
- TYPE_ISSUE,
- WORKSPACE_PROJECT,
-} from '~/issues/constants';
+import { TYPE_EPIC, TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
+import updateDescription from '~/issues/show/utils/update_description';
+import { sanitize } from '~/lib/dompurify';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import Poll from '~/lib/utils/poll';
+import { containsSensitiveToken, confirmSensitiveAction, i18n } from '~/lib/utils/secret_detection';
import { visitUrl } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
-import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
-import { containsSensitiveToken, confirmSensitiveAction, i18n } from '~/lib/utils/secret_detection';
import { ISSUE_TYPE_PATH, INCIDENT_TYPE_PATH, POLLING_DELAY } from '../constants';
import eventHub from '../event_hub';
import getIssueStateQuery from '../queries/get_issue_state.query.graphql';
import Service from '../services/index';
-import Store from '../stores';
import DescriptionComponent from './description.vue';
import EditedComponent from './edited.vue';
import FormComponent from './form.vue';
import HeaderActions from './header_actions.vue';
import IssueHeader from './issue_header.vue';
import PinnedLinks from './pinned_links.vue';
+import StickyHeader from './sticky_header.vue';
import TitleComponent from './title.vue';
export default {
- WORKSPACE_PROJECT,
components: {
- GlIcon,
- GlBadge,
- GlIntersectionObserver,
HeaderActions,
IssueHeader,
TitleComponent,
EditedComponent,
FormComponent,
PinnedLinks,
- ConfidentialityBadge,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
+ StickyHeader,
},
props: {
author: {
@@ -234,21 +221,26 @@ export default {
},
},
data() {
- const store = new Store({
- titleHtml: this.initialTitleHtml,
- titleText: this.initialTitleText,
- descriptionHtml: this.initialDescriptionHtml,
- descriptionText: this.initialDescriptionText,
- updatedAt: this.updatedAt,
- updatedByName: this.updatedByName,
- updatedByPath: this.updatedByPath,
- taskCompletionStatus: this.initialTaskCompletionStatus,
- lock_version: this.lockVersion,
- });
-
return {
- store,
- state: store.state,
+ formState: {
+ title: '',
+ description: '',
+ lockedWarningVisible: false,
+ updateLoading: false,
+ lock_version: 0,
+ issuableTemplates: {},
+ },
+ state: {
+ titleHtml: this.initialTitleHtml,
+ titleText: this.initialTitleText,
+ descriptionHtml: this.initialDescriptionHtml,
+ descriptionText: this.initialDescriptionText,
+ updatedAt: this.updatedAt,
+ updatedByName: this.updatedByName,
+ updatedByPath: this.updatedByPath,
+ taskCompletionStatus: this.initialTaskCompletionStatus,
+ lock_version: this.lockVersion,
+ },
showForm: false,
templatesRequested: false,
isStickyHeaderShowing: false,
@@ -264,17 +256,9 @@ export default {
headerClasses() {
return this.issuableType === TYPE_INCIDENT ? 'gl-mb-3' : 'gl-mb-6';
},
- issuableTemplates() {
- return this.store.formState.issuableTemplates;
- },
- formState() {
- return this.store.formState;
- },
issueChanged() {
const {
- store: {
- formState: { description, title },
- },
+ formState: { description, title },
initialDescriptionText,
initialTitleText,
} = this;
@@ -292,26 +276,13 @@ export default {
defaultErrorMessage() {
return sprintf(__('Error updating %{issuableType}'), { issuableType: this.issuableType });
},
- isClosed() {
- return this.issuableStatus === STATUS_CLOSED;
- },
+
pinnedLinkClasses() {
return this.showTitleBorder
? 'gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-mb-6'
: '';
},
- statusIcon() {
- if (this.issuableType === TYPE_EPIC) {
- return this.isClosed ? 'epic-closed' : 'epic';
- }
- return this.isClosed ? 'issue-closed' : 'issues';
- },
- statusVariant() {
- return this.isClosed ? 'info' : 'success';
- },
- statusText() {
- return issuableStatusText[this.issuableStatus];
- },
+
shouldShowStickyHeader() {
return [TYPE_INCIDENT, TYPE_ISSUE, TYPE_EPIC].includes(this.issuableType);
},
@@ -322,7 +293,7 @@ export default {
this.poll = new Poll({
resource: this.service,
method: 'getData',
- successCallback: (res) => this.store.updateState(res.data),
+ successCallback: (res) => this.updateState(res.data),
errorCallback(err) {
throw new Error(err);
},
@@ -360,23 +331,37 @@ export default {
}
return undefined;
},
+ updateState(data) {
+ const stateShouldUpdate =
+ this.state.titleText !== data.title_text ||
+ this.state.descriptionText !== data.description_text;
- updateStoreState() {
+ if (stateShouldUpdate) {
+ this.formState.lockedWarningVisible = true;
+ }
+
+ Object.assign(this.state, convertObjectPropsToCamelCase(data));
+ // find if there is an open details node inside of the issue description.
+ const descriptionSection = document.body.querySelector(
+ '.detail-page-description.content-block',
+ );
+ const details =
+ descriptionSection != null && descriptionSection.getElementsByTagName('details');
+
+ this.state.descriptionHtml = updateDescription(sanitize(data.description), details);
+ this.state.titleHtml = sanitize(data.title);
+ this.state.lock_version = data.lock_version;
+ },
+ refetchData() {
return this.service
.getData()
.then((res) => res.data)
- .then((data) => {
- this.store.updateState(data);
- })
- .catch(() => {
- createAlert({
- message: this.defaultErrorMessage,
- });
- });
+ .then(this.updateState)
+ .catch(() => createAlert({ message: this.defaultErrorMessage }));
},
setFormState(state) {
- this.store.setFormState(state);
+ this.formState = { ...this.formState, ...state };
},
updateFormState(templates = {}) {
@@ -416,7 +401,7 @@ export default {
this.templatesRequested = true;
this.requestTemplatesAndShowForm();
} else {
- this.updateAndShowForm(this.issuableTemplates);
+ this.updateAndShowForm(this.formState.issuableTemplates);
}
},
@@ -427,10 +412,7 @@ export default {
async updateIssuable() {
this.setFormState({ updateLoading: true });
- const {
- store: { formState },
- issueState,
- } = this;
+ const { formState, issueState } = this;
const issuablePayload = issueState.isDirty
? { ...formState, issue_type: issueState.issueType }
: formState;
@@ -464,7 +446,7 @@ export default {
visitUrl(URI);
}
})
- .then(this.updateStoreState)
+ .then(this.refetchData)
.then(() => {
eventHub.$emit('close.form');
})
@@ -518,7 +500,7 @@ export default {
this.poll.enable();
this.poll.makeDelayedRequest(POLLING_DELAY);
- this.updateStoreState();
+ this.refetchData();
},
},
};
@@ -531,7 +513,7 @@ export default {
:endpoint="endpoint"
:form-state="formState"
:initial-description-text="initialDescriptionText"
- :issuable-templates="issuableTemplates"
+ :issuable-templates="formState.issuableTemplates"
:markdown-docs-path="markdownDocsPath"
:markdown-preview-path="markdownPreviewPath"
:project-path="projectPath"
@@ -559,61 +541,19 @@ export default {
</template>
</title-component>
- <gl-intersection-observer
+ <sticky-header
v-if="shouldShowStickyHeader"
- @appear="hideStickyHeader"
- @disappear="showStickyHeader"
- >
- <transition name="issuable-header-slide">
- <div
- v-if="isStickyHeaderShowing"
- class="issue-sticky-header gl-fixed gl-z-index-3 gl-bg-white gl-border-1 gl-border-b-solid gl-border-b-gray-100 gl-py-3"
- data-testid="issue-sticky-header"
- >
- <div
- class="issue-sticky-header-text gl-display-flex gl-align-items-center gl-mx-auto gl-px-5"
- >
- <gl-badge :variant="statusVariant" class="gl-mr-2">
- <gl-icon :name="statusIcon" />
- <span class="gl-display-none gl-sm-display-block gl-ml-2">{{
- statusText
- }}</span></gl-badge
- >
- <span
- v-if="isLocked"
- v-gl-tooltip.bottom
- data-testid="locked"
- class="issuable-warning-icon"
- :title="__('This issue is locked. Only project members can comment.')"
- >
- <gl-icon name="lock" :aria-label="__('Locked')" />
- </span>
- <confidentiality-badge
- v-if="isConfidential"
- data-testid="confidential"
- :workspace-type="$options.WORKSPACE_PROJECT"
- :issuable-type="issuableType"
- />
- <span
- v-if="isHidden"
- v-gl-tooltip.bottom
- :title="__('This issue is hidden because its author has been banned')"
- data-testid="hidden"
- class="issuable-warning-icon"
- >
- <gl-icon name="spam" />
- </span>
- <a
- href="#top"
- class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0 gl-text-black-normal"
- :title="state.titleText"
- >
- {{ state.titleText }}
- </a>
- </div>
- </div>
- </transition>
- </gl-intersection-observer>
+ :is-confidential="isConfidential"
+ :is-hidden="isHidden"
+ :is-locked="isLocked"
+ :issuable-status="issuableStatus"
+ :issuable-type="issuableType"
+ :show="isStickyHeaderShowing"
+ :title="state.titleText"
+ :title-html="state.titleHtml"
+ @hide="hideStickyHeader"
+ @show="showStickyHeader"
+ />
<slot name="header">
<issue-header
diff --git a/app/assets/javascripts/issues/show/components/description.vue b/app/assets/javascripts/issues/show/components/description.vue
index 90f01603f96..acbba216601 100644
--- a/app/assets/javascripts/issues/show/components/description.vue
+++ b/app/assets/javascripts/issues/show/components/description.vue
@@ -307,7 +307,8 @@ export default {
);
taskListItems?.forEach((item) => {
- const dropdown = this.createTaskListItemActions({ canUpdate: this.canUpdate });
+ const provide = { canUpdate: this.canUpdate, issuableType: this.issuableType };
+ const dropdown = this.createTaskListItemActions(provide);
this.insertNextToTaskListItemText(dropdown, item);
this.addPointerEventListeners(item, '.task-list-item-actions');
this.hasTaskListItemActions = true;
diff --git a/app/assets/javascripts/issues/show/components/header_actions.vue b/app/assets/javascripts/issues/show/components/header_actions.vue
index 1ade5e654e9..81e5c30a264 100644
--- a/app/assets/javascripts/issues/show/components/header_actions.vue
+++ b/app/assets/javascripts/issues/show/components/header_actions.vue
@@ -79,62 +79,25 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [trackingMixin, glFeatureFlagMixin()],
- inject: {
- canCreateIssue: {
- default: false,
- },
- canDestroyIssue: {
- default: false,
- },
- canPromoteToEpic: {
- default: false,
- },
- canReopenIssue: {
- default: false,
- },
- canReportSpam: {
- default: false,
- },
- canUpdateIssue: {
- default: false,
- },
- iid: {
- default: '',
- },
- issuableId: {
- default: '',
- },
- isIssueAuthor: {
- default: false,
- },
- issuePath: {
- default: '',
- },
- issueType: {
- default: TYPE_ISSUE,
- },
- newIssuePath: {
- default: '',
- },
- projectPath: {
- default: '',
- },
- submitAsSpamPath: {
- default: '',
- },
- reportedUserId: {
- default: '',
- },
- reportedFromUrl: {
- default: '',
- },
- issuableEmailAddress: {
- default: '',
- },
- fullPath: {
- default: '',
- },
- },
+ inject: [
+ 'canCreateIssue',
+ 'canDestroyIssue',
+ 'canPromoteToEpic',
+ 'canReopenIssue',
+ 'canReportSpam',
+ 'canUpdateIssue',
+ 'iid',
+ 'isIssueAuthor',
+ 'issuePath',
+ 'issueType',
+ 'newIssuePath',
+ 'projectPath',
+ 'submitAsSpamPath',
+ 'reportedUserId',
+ 'reportedFromUrl',
+ 'issuableEmailAddress',
+ 'fullPath',
+ ],
data() {
return {
isReportAbuseDrawerOpen: false,
@@ -256,7 +219,7 @@ export default {
mutation: updateIssueMutation,
variables: {
input: {
- iid: this.iid.toString(),
+ iid: String(this.iid),
projectPath: this.projectPath,
stateEvent: this.isClosed ? ISSUE_STATE_EVENT_REOPEN : ISSUE_STATE_EVENT_CLOSE,
},
@@ -501,7 +464,7 @@ export default {
>{{ copyMailAddressText }}</gl-dropdown-item
>
</template>
- <gl-dropdown-divider v-if="showToggleIssueStateButton || canDestroyIssue || canReportSpam" />
+ <gl-dropdown-divider v-if="canDestroyIssue || canReportSpam || !isIssueAuthor" />
<gl-dropdown-item
v-if="canReportSpam"
:href="submitAsSpamPath"
diff --git a/app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue b/app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue
index ac64c35bf15..ab1bb9253f4 100644
--- a/app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue
@@ -107,10 +107,7 @@ export default {
</script>
<template>
- <div
- class="create-timeline-event gl-relative gl-display-flex gl-align-items-start"
- :class="{ 'timeline-entry-vertical-line': hasTimelineEvents }"
- >
+ <div class="create-timeline-event gl-relative gl-display-flex gl-align-items-start">
<div
v-if="hasTimelineEvents"
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-align-self-start gl-bg-white gl-text-gray-200 gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-full gl-mt-2 gl-w-8 gl-h-8 gl-flex-shrink-0 gl-p-3 gl-z-index-1"
diff --git a/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue b/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue
index 4ec64ef838d..2909a4d2666 100644
--- a/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue
@@ -43,7 +43,7 @@ export default {
variables() {
return {
fullPath: this.fullPath,
- iid: this.iid,
+ iid: String(this.iid),
};
},
update(data) {
diff --git a/app/assets/javascripts/issues/show/components/sticky_header.vue b/app/assets/javascripts/issues/show/components/sticky_header.vue
new file mode 100644
index 00000000000..bcf10ee92bb
--- /dev/null
+++ b/app/assets/javascripts/issues/show/components/sticky_header.vue
@@ -0,0 +1,130 @@
+<script>
+import { GlBadge, GlIcon, GlIntersectionObserver, GlTooltipDirective } from '@gitlab/ui';
+import {
+ issuableStatusText,
+ STATUS_CLOSED,
+ TYPE_EPIC,
+ WORKSPACE_PROJECT,
+} from '~/issues/constants';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
+
+export default {
+ WORKSPACE_PROJECT,
+ components: {
+ ConfidentialityBadge,
+ GlBadge,
+ GlIcon,
+ GlIntersectionObserver,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ SafeHtml,
+ },
+ props: {
+ isConfidential: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isHidden: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isLocked: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ issuableStatus: {
+ type: String,
+ required: true,
+ },
+ issuableType: {
+ type: String,
+ required: true,
+ },
+ show: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ title: {
+ type: String,
+ required: true,
+ },
+ titleHtml: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ isClosed() {
+ return this.issuableStatus === STATUS_CLOSED;
+ },
+ statusIcon() {
+ if (this.issuableType === TYPE_EPIC) {
+ return this.isClosed ? 'epic-closed' : 'epic';
+ }
+ return this.isClosed ? 'issue-closed' : 'issues';
+ },
+ statusText() {
+ return issuableStatusText[this.issuableStatus];
+ },
+ statusVariant() {
+ return this.isClosed ? 'info' : 'success';
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-intersection-observer @appear="$emit('hide')" @disappear="$emit('show')">
+ <transition name="issuable-header-slide">
+ <div
+ v-if="show"
+ class="issue-sticky-header gl-fixed gl-z-index-3 gl-bg-white gl-border-1 gl-border-b-solid gl-border-b-gray-100 gl-py-3"
+ data-testid="issue-sticky-header"
+ >
+ <div
+ class="issue-sticky-header-text gl-display-flex gl-align-items-center gl-gap-2 gl-mx-auto gl-px-5"
+ >
+ <gl-badge :variant="statusVariant">
+ <gl-icon :name="statusIcon" />
+ <span class="gl-display-none gl-sm-display-block gl-ml-2">{{ statusText }}</span>
+ </gl-badge>
+ <span
+ v-if="isLocked"
+ v-gl-tooltip.bottom
+ data-testid="locked"
+ class="issuable-warning-icon"
+ :title="__('This issue is locked. Only project members can comment.')"
+ >
+ <gl-icon name="lock" :aria-label="__('Locked')" />
+ </span>
+ <confidentiality-badge
+ v-if="isConfidential"
+ :issuable-type="issuableType"
+ :workspace-type="$options.WORKSPACE_PROJECT"
+ />
+ <span
+ v-if="isHidden"
+ v-gl-tooltip.bottom
+ :title="__('This issue is hidden because its author has been banned')"
+ data-testid="hidden"
+ class="issuable-warning-icon"
+ >
+ <gl-icon name="spam" />
+ </span>
+ <a
+ v-safe-html="titleHtml || title"
+ href="#top"
+ class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0 gl-text-black-normal"
+ >
+ </a>
+ </div>
+ </div>
+ </transition>
+ </gl-intersection-observer>
+</template>
diff --git a/app/assets/javascripts/issues/show/components/task_list_item_actions.vue b/app/assets/javascripts/issues/show/components/task_list_item_actions.vue
index 64b916caddb..55e2e857050 100644
--- a/app/assets/javascripts/issues/show/components/task_list_item_actions.vue
+++ b/app/assets/javascripts/issues/show/components/task_list_item_actions.vue
@@ -1,5 +1,6 @@
<script>
import { GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
+import { TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import { __, s__ } from '~/locale';
import eventHub from '../event_hub';
@@ -13,7 +14,12 @@ export default {
GlDisclosureDropdown,
GlDisclosureDropdownItem,
},
- inject: ['canUpdate'],
+ inject: ['canUpdate', 'issuableType'],
+ computed: {
+ showConvertToTaskItem() {
+ return [TYPE_INCIDENT, TYPE_ISSUE].includes(this.issuableType);
+ },
+ },
methods: {
convertToTask() {
eventHub.$emit('convert-task-list-item', this.$el.closest('li').dataset.sourcepos);
@@ -37,12 +43,17 @@ export default {
text-sr-only
toggle-class="task-list-item-actions gl-opacity-0 gl-p-2! "
>
- <gl-disclosure-dropdown-item class="gl-ml-2!" @action="convertToTask">
+ <gl-disclosure-dropdown-item
+ v-if="showConvertToTaskItem"
+ class="gl-ml-2!"
+ data-testid="convert"
+ @action="convertToTask"
+ >
<template #list-item>
{{ $options.i18n.convertToTask }}
</template>
</gl-disclosure-dropdown-item>
- <gl-disclosure-dropdown-item class="gl-ml-2!" @action="deleteTaskListItem">
+ <gl-disclosure-dropdown-item class="gl-ml-2!" data-testid="delete" @action="deleteTaskListItem">
<template #list-item>
<span class="gl-text-red-500!">{{ $options.i18n.delete }}</span>
</template>
diff --git a/app/assets/javascripts/issues/show/index.js b/app/assets/javascripts/issues/show/index.js
index a27f86bd9c3..b94f88f690e 100644
--- a/app/assets/javascripts/issues/show/index.js
+++ b/app/assets/javascripts/issues/show/index.js
@@ -6,13 +6,15 @@ import { apolloProvider } from '~/graphql_shared/issuable_client';
import { TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import { scrollToTargetOnResize } from '~/lib/utils/resize_observer';
+import initLinkedResources from '~/linked_resources';
import IssueApp from './components/app.vue';
-import HeaderActions from './components/header_actions.vue';
+import DescriptionComponent from './components/description.vue';
import IncidentTabs from './components/incidents/incident_tabs.vue';
import SentryErrorStackTrace from './components/sentry_error_stack_trace.vue';
import { issueState } from './constants';
import getIssueStateQuery from './queries/get_issue_state.query.graphql';
import createRouter from './components/incidents/router';
+import { parseIssuableData } from './utils/parse_data';
const bootstrapApollo = (state = {}) => {
return apolloProvider.clients.defaultClient.cache.writeQuery({
@@ -23,14 +25,15 @@ const bootstrapApollo = (state = {}) => {
});
};
-export function initIncidentApp(issueData = {}, store) {
+export function initIssuableApp(store) {
const el = document.getElementById('js-issuable-app');
if (!el) {
return undefined;
}
- bootstrapApollo({ ...issueState, issueType: TYPE_INCIDENT });
+ const issuableData = parseIssuableData(el);
+ const headerActionsData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.headerActionsData));
const {
authorId,
@@ -38,137 +41,72 @@ export function initIncidentApp(issueData = {}, store) {
authorUsername,
authorWebUrl,
canCreateIncident,
- canUpdate,
- canUpdateTimelineEvent,
+ fullPath,
iid,
issuableId,
+ issueType,
+ hasIterationsFeature,
+ // for issue
+ registerPath,
+ signInPath,
+ // for incident
+ canUpdate,
+ canUpdateTimelineEvent,
currentPath,
currentTab,
- projectNamespace,
- projectPath,
- projectId,
hasLinkedAlerts,
+ projectId,
slaFeatureAvailable,
uploadMetricsFeatureAvailable,
- } = issueData;
- const headerActionsData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.headerActionsData));
-
- const fullPath = `${projectNamespace}/${projectPath}`;
- const router = createRouter(currentPath, currentTab);
-
- return new Vue({
- el,
- name: 'DescriptionRoot',
- apolloProvider,
- store,
- router,
- provide: {
- issueType: TYPE_INCIDENT,
- canCreateIncident,
- canUpdateTimelineEvent,
- canUpdate,
- fullPath,
- iid,
- issuableId,
- projectId,
- hasLinkedAlerts: parseBoolean(hasLinkedAlerts),
- slaFeatureAvailable: parseBoolean(slaFeatureAvailable),
- uploadMetricsFeatureAvailable: parseBoolean(uploadMetricsFeatureAvailable),
- contentEditorOnIssues: gon.features.contentEditorOnIssues,
- // for HeaderActions component
- canCreateIssue: parseBoolean(headerActionsData.canCreateIncident),
- canDestroyIssue: parseBoolean(headerActionsData.canDestroyIssue),
- canPromoteToEpic: parseBoolean(headerActionsData.canPromoteToEpic),
- canReopenIssue: parseBoolean(headerActionsData.canReopenIssue),
- canReportSpam: parseBoolean(headerActionsData.canReportSpam),
- canUpdateIssue: parseBoolean(headerActionsData.canUpdateIssue),
- isIssueAuthor: parseBoolean(headerActionsData.isIssueAuthor),
- issuePath: headerActionsData.issuePath,
- newIssuePath: headerActionsData.newIssuePath,
- projectPath: headerActionsData.projectPath,
- reportAbusePath: headerActionsData.reportAbusePath,
- reportedUserId: headerActionsData.reportedUserId,
- reportedFromUrl: headerActionsData.reportedFromUrl,
- submitAsSpamPath: headerActionsData.submitAsSpamPath,
- issuableEmailAddress: headerActionsData.issuableEmailAddress,
- },
- computed: {
- ...mapGetters(['getNoteableData']),
- },
- render(createElement) {
- return createElement(IssueApp, {
- props: {
- ...issueData,
- author: {
- id: authorId,
- name: authorName,
- username: authorUsername,
- webUrl: authorWebUrl,
- },
- issueId: Number(issuableId),
- issuableStatus: this.getNoteableData?.state,
- issuableType: TYPE_INCIDENT,
- descriptionComponent: IncidentTabs,
- showTitleBorder: false,
- isConfidential: this.getNoteableData?.confidential,
- },
- });
- },
- });
-}
-
-export function initIssueApp(issueData, store) {
- const el = document.getElementById('js-issuable-app');
+ } = issuableData;
- if (!el) {
- return undefined;
- }
+ const issueProvideData = { registerPath, signInPath };
+ const incidentProvideData = {
+ canUpdate,
+ canUpdateTimelineEvent,
+ hasLinkedAlerts: parseBoolean(hasLinkedAlerts),
+ projectId,
+ slaFeatureAvailable: parseBoolean(slaFeatureAvailable),
+ uploadMetricsFeatureAvailable: parseBoolean(uploadMetricsFeatureAvailable),
+ };
- const { fullPath, registerPath, signInPath } = el.dataset;
- const headerActionsData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.headerActionsData));
+ bootstrapApollo({ ...issueState, issueType });
scrollToTargetOnResize();
- bootstrapApollo({ ...issueState, issueType: TYPE_ISSUE });
-
- const {
- authorId,
- authorName,
- authorUsername,
- authorWebUrl,
- canCreateIncident,
- hasIssueWeightsFeature,
- hasIterationsFeature,
- ...issueProps
- } = issueData;
+ if (issueType === TYPE_INCIDENT) {
+ initLinkedResources();
+ }
return new Vue({
el,
name: 'DescriptionRoot',
apolloProvider,
store,
+ router: issueType === TYPE_INCIDENT ? createRouter(currentPath, currentTab) : undefined,
provide: {
canCreateIncident,
fullPath,
- registerPath,
- signInPath,
- hasIssueWeightsFeature,
+ iid,
+ issuableId,
+ issueType,
hasIterationsFeature,
+ ...(issueType === TYPE_ISSUE && issueProvideData),
+ ...(issueType === TYPE_INCIDENT && incidentProvideData),
// for HeaderActions component
- canCreateIssue: parseBoolean(headerActionsData.canCreateIssue),
+ canCreateIssue:
+ issueType === TYPE_INCIDENT
+ ? parseBoolean(headerActionsData.canCreateIncident)
+ : parseBoolean(headerActionsData.canCreateIssue),
canDestroyIssue: parseBoolean(headerActionsData.canDestroyIssue),
canPromoteToEpic: parseBoolean(headerActionsData.canPromoteToEpic),
canReopenIssue: parseBoolean(headerActionsData.canReopenIssue),
canReportSpam: parseBoolean(headerActionsData.canReportSpam),
canUpdateIssue: parseBoolean(headerActionsData.canUpdateIssue),
- iid: headerActionsData.iid,
- issuableId: headerActionsData.issuableId,
isIssueAuthor: parseBoolean(headerActionsData.isIssueAuthor),
issuePath: headerActionsData.issuePath,
- issueType: headerActionsData.issueType,
newIssuePath: headerActionsData.newIssuePath,
projectPath: headerActionsData.projectPath,
- projectId: headerActionsData.projectId,
reportAbusePath: headerActionsData.reportAbusePath,
reportedUserId: headerActionsData.reportedUserId,
reportedFromUrl: headerActionsData.reportedFromUrl,
@@ -181,67 +119,27 @@ export function initIssueApp(issueData, store) {
render(createElement) {
return createElement(IssueApp, {
props: {
- ...issueProps,
+ ...issuableData,
author: {
id: authorId,
name: authorName,
username: authorUsername,
webUrl: authorWebUrl,
},
+ descriptionComponent: issueType === TYPE_INCIDENT ? IncidentTabs : DescriptionComponent,
isConfidential: this.getNoteableData?.confidential,
isLocked: this.getNoteableData?.discussion_locked,
issuableStatus: this.getNoteableData?.state,
+ issuableType: issueType,
issueId: this.getNoteableData?.id,
issueIid: this.getNoteableData?.iid,
+ showTitleBorder: issueType !== TYPE_INCIDENT,
},
});
},
});
}
-export function initHeaderActions(store, type = '') {
- const el = document.querySelector('.js-issue-header-actions');
-
- if (!el) {
- return undefined;
- }
-
- bootstrapApollo({ ...issueState, issueType: el.dataset.issueType });
-
- const canCreate =
- type === TYPE_INCIDENT ? el.dataset.canCreateIncident : el.dataset.canCreateIssue;
-
- return new Vue({
- el,
- name: 'HeaderActionsRoot',
- apolloProvider,
- store,
- provide: {
- canCreateIssue: parseBoolean(canCreate),
- canDestroyIssue: parseBoolean(el.dataset.canDestroyIssue),
- canPromoteToEpic: parseBoolean(el.dataset.canPromoteToEpic),
- canReopenIssue: parseBoolean(el.dataset.canReopenIssue),
- canReportSpam: parseBoolean(el.dataset.canReportSpam),
- canUpdateIssue: parseBoolean(el.dataset.canUpdateIssue),
- iid: el.dataset.iid,
- issuableId: el.dataset.issuableId,
- isIssueAuthor: parseBoolean(el.dataset.isIssueAuthor),
- issuePath: el.dataset.issuePath,
- issueType: el.dataset.issueType,
- newIssuePath: el.dataset.newIssuePath,
- projectPath: el.dataset.projectPath,
- projectId: el.dataset.projectId,
- reportAbusePath: el.dataset.reportAbusePath,
- reportedUserId: parseInt(el.dataset.reportedUserId, 10),
- reportedFromUrl: el.dataset.reportedFromUrl,
- submitAsSpamPath: el.dataset.submitAsSpamPath,
- issuableEmailAddress: el.dataset.issuableEmailAddress,
- fullPath: el.dataset.projectPath,
- },
- render: (createElement) => createElement(HeaderActions),
- });
-}
-
export function initSentryErrorStackTrace() {
const el = document.querySelector('#js-sentry-error-stack-trace');
diff --git a/app/assets/javascripts/issues/show/stores/index.js b/app/assets/javascripts/issues/show/stores/index.js
deleted file mode 100644
index a50913d3455..00000000000
--- a/app/assets/javascripts/issues/show/stores/index.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import { sanitize } from '~/lib/dompurify';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import updateDescription from '../utils/update_description';
-
-export default class Store {
- constructor(initialState) {
- this.state = initialState;
- this.formState = {
- title: '',
- description: '',
- lockedWarningVisible: false,
- updateLoading: false,
- lock_version: 0,
- issuableTemplates: {},
- };
- }
-
- updateState(data) {
- if (this.stateShouldUpdate(data)) {
- this.formState.lockedWarningVisible = true;
- }
-
- Object.assign(this.state, convertObjectPropsToCamelCase(data));
- // find if there is an open details node inside of the issue description.
- const descriptionSection = document.body.querySelector(
- '.detail-page-description.content-block',
- );
- const details =
- descriptionSection != null && descriptionSection.getElementsByTagName('details');
-
- this.state.descriptionHtml = updateDescription(sanitize(data.description), details);
- this.state.titleHtml = sanitize(data.title);
- this.state.lock_version = data.lock_version;
- }
-
- stateShouldUpdate(data) {
- return (
- this.state.titleText !== data.title_text ||
- this.state.descriptionText !== data.description_text
- );
- }
-
- setFormState(state) {
- this.formState = Object.assign(this.formState, state);
- }
-}
diff --git a/app/assets/javascripts/jira_connect/branches/components/new_branch_form.vue b/app/assets/javascripts/jira_connect/branches/components/new_branch_form.vue
index 46c27c33f56..1d926c0d0c5 100644
--- a/app/assets/javascripts/jira_connect/branches/components/new_branch_form.vue
+++ b/app/assets/javascripts/jira_connect/branches/components/new_branch_form.vue
@@ -193,6 +193,7 @@ export default {
>
<source-branch-dropdown
id="source-branch-select"
+ :key="selectedProject.id"
:selected-project="selectedProject"
:selected-branch-name="selectedSourceBranchName"
@change="onSourceBranchSelect"
diff --git a/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue b/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue
index dd9afb01590..52a12cc7771 100644
--- a/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue
+++ b/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue
@@ -98,13 +98,13 @@ export default {
:loading="initialProjectsLoading"
:searchable="true"
:searching="projectsLoading"
+ fluid-width
@search="onSearch"
@select="onProjectSelect"
>
<template #list-item="{ item: project }">
<gl-avatar-labeled
v-if="project"
- class="gl-text-truncate"
:shape="$options.AVATAR_SHAPE_OPTION_RECT"
:size="32"
:src="project.avatarUrl"
diff --git a/app/assets/javascripts/jira_connect/branches/components/source_branch_dropdown.vue b/app/assets/javascripts/jira_connect/branches/components/source_branch_dropdown.vue
index dac807dceb0..3f9dd4eb6c6 100644
--- a/app/assets/javascripts/jira_connect/branches/components/source_branch_dropdown.vue
+++ b/app/assets/javascripts/jira_connect/branches/components/source_branch_dropdown.vue
@@ -2,6 +2,8 @@
import { GlCollapsibleListbox } from '@gitlab/ui';
import { debounce } from 'lodash';
import { __ } from '~/locale';
+import { logError } from '~/lib/logger';
+
import { BRANCHES_PER_PAGE } from '../constants';
import getProjectQuery from '../graphql/queries/get_project.query.graphql';
@@ -26,6 +28,7 @@ export default {
return {
initialSourceBranchNamesLoading: false,
sourceBranchNamesLoading: false,
+ sourceBranchNamesLoadingMore: false,
sourceBranchNames: [],
};
},
@@ -36,6 +39,11 @@ export default {
hasSelectedSourceBranch() {
return Boolean(this.selectedBranchName);
},
+ hasMoreBranches() {
+ return (
+ this.sourceBranchNames.length > 0 && this.sourceBranchNames.length % BRANCHES_PER_PAGE === 0
+ );
+ },
branchDropdownText() {
return this.selectedBranchName || __('Select a branch');
},
@@ -59,45 +67,63 @@ export default {
onSearch: debounce(function debouncedSearch(branchSearchQuery) {
this.onSourceBranchSearchQuery(branchSearchQuery);
}, 250),
- onSourceBranchSearchQuery(branchSearchQuery) {
+ async onSourceBranchSearchQuery(branchSearchQuery) {
this.branchSearchQuery = branchSearchQuery;
- this.fetchSourceBranchNames({
+ this.sourceBranchNamesLoading = true;
+
+ await this.fetchSourceBranchNames({
+ projectPath: this.selectedProject.fullPath,
+ searchPattern: this.branchSearchQuery,
+ });
+ this.sourceBranchNamesLoading = false;
+ },
+ async onBottomReached() {
+ this.sourceBranchNamesLoadingMore = true;
+
+ await this.fetchSourceBranchNames({
projectPath: this.selectedProject.fullPath,
searchPattern: this.branchSearchQuery,
+ append: true,
});
+
+ this.sourceBranchNamesLoadingMore = false;
},
onError({ message } = {}) {
this.$emit('error', { message });
},
- async fetchSourceBranchNames({ projectPath, searchPattern } = {}) {
- this.sourceBranchNamesLoading = true;
+ async fetchSourceBranchNames({ projectPath, searchPattern, append = false } = {}) {
try {
const { data } = await this.$apollo.query({
query: getProjectQuery,
variables: {
projectPath,
branchNamesLimit: this.$options.BRANCHES_PER_PAGE,
- branchNamesOffset: 0,
+ branchNamesOffset: append ? this.sourceBranchNames.length : 0,
branchNamesSearchPattern: searchPattern ? `*${searchPattern}*` : '*',
},
});
const { branchNames, rootRef } = data?.project.repository || {};
- this.sourceBranchNames =
- branchNames.map((value) => {
+ const branchNameItems =
+ branchNames?.map((value) => {
return { text: value, value };
}) || [];
- // Use root ref as the default selection
- if (rootRef && !this.hasSelectedSourceBranch) {
- this.onSourceBranchSelect(rootRef);
+ if (append) {
+ this.sourceBranchNames.push(...branchNameItems);
+ } else {
+ this.sourceBranchNames = branchNameItems;
+
+ // Use root ref as the default selection
+ if (rootRef && !this.hasSelectedSourceBranch) {
+ this.onSourceBranchSelect(rootRef);
+ }
}
} catch (err) {
+ logError(err);
this.onError({
message: __('Something went wrong while fetching source branches.'),
});
- } finally {
- this.sourceBranchNamesLoading = false;
}
},
},
@@ -107,12 +133,17 @@ export default {
<template>
<gl-collapsible-listbox
:class="{ 'gl-font-monospace': hasSelectedSourceBranch }"
+ :selected="selectedBranchName"
:disabled="!hasSelectedProject"
:items="sourceBranchNames"
:loading="initialSourceBranchNamesLoading"
:searchable="true"
:searching="sourceBranchNamesLoading"
:toggle-text="branchDropdownText"
+ fluid-width
+ :infinite-scroll="hasMoreBranches"
+ :infinite-scroll-loading="sourceBranchNamesLoadingMore"
+ @bottom-reached="onBottomReached"
@search="onSearch"
@select="onSourceBranchSelect"
/>
diff --git a/app/assets/javascripts/jira_connect/branches/index.js b/app/assets/javascripts/jira_connect/branches/index.js
index a9a56a6362e..893b9dfa1c7 100644
--- a/app/assets/javascripts/jira_connect/branches/index.js
+++ b/app/assets/javascripts/jira_connect/branches/index.js
@@ -19,6 +19,7 @@ export default function initJiraConnectBranches() {
return new Vue({
el,
+ name: 'JiraConnectNewBranchRoot',
apolloProvider,
provide: {
initialBranchName,
diff --git a/app/assets/javascripts/jira_import/components/jira_import_form.vue b/app/assets/javascripts/jira_import/components/jira_import_form.vue
index f8ca62da1a5..d737916857b 100644
--- a/app/assets/javascripts/jira_import/components/jira_import_form.vue
+++ b/app/assets/javascripts/jira_import/components/jira_import_form.vue
@@ -269,7 +269,7 @@ export default {
<gl-form-select
id="jira-project-select"
v-model="selectedProject"
- data-qa-selector="jira_project_dropdown"
+ data-testid="jira-project-dropdown"
class="mb-2"
:options="jiraProjects"
:state="selectState"
@@ -349,7 +349,7 @@ export default {
variant="confirm"
class="js-no-auto-disable"
:loading="isSubmitting"
- data-qa-selector="jira_issues_import_button"
+ data-testid="jira-issues-import-button"
>
{{ __('Continue') }}
</gl-button>
diff --git a/app/assets/javascripts/jobs/components/filtered_search/constants.js b/app/assets/javascripts/jobs/components/filtered_search/constants.js
deleted file mode 100644
index 0daba892375..00000000000
--- a/app/assets/javascripts/jobs/components/filtered_search/constants.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export const jobStatusValues = [
- 'CANCELED',
- 'CREATED',
- 'FAILED',
- 'MANUAL',
- 'SUCCESS',
- 'PENDING',
- 'PREPARING',
- 'RUNNING',
- 'SCHEDULED',
- 'SKIPPED',
- 'WAITING_FOR_RESOURCE',
-];
diff --git a/app/assets/javascripts/jobs/components/filtered_search/jobs_filtered_search.vue b/app/assets/javascripts/jobs/components/filtered_search/jobs_filtered_search.vue
deleted file mode 100644
index 67cdca6aa0a..00000000000
--- a/app/assets/javascripts/jobs/components/filtered_search/jobs_filtered_search.vue
+++ /dev/null
@@ -1,64 +0,0 @@
-<script>
-import { GlFilteredSearch } from '@gitlab/ui';
-import {
- OPERATORS_IS,
- TOKEN_TITLE_STATUS,
- TOKEN_TYPE_STATUS,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import JobStatusToken from './tokens/job_status_token.vue';
-
-export default {
- components: {
- GlFilteredSearch,
- },
- props: {
- queryString: {
- type: Object,
- required: false,
- default: null,
- },
- },
- computed: {
- tokens() {
- return [
- {
- type: TOKEN_TYPE_STATUS,
- icon: 'status',
- title: TOKEN_TITLE_STATUS,
- unique: true,
- token: JobStatusToken,
- operators: OPERATORS_IS,
- },
- ];
- },
- filteredSearchValue() {
- if (this.queryString?.statuses) {
- return [
- {
- type: TOKEN_TYPE_STATUS,
- value: {
- data: this.queryString?.statuses,
- operator: '=',
- },
- },
- ];
- }
- return [];
- },
- },
- methods: {
- onSubmit(filters) {
- this.$emit('filterJobsBySearch', filters);
- },
- },
-};
-</script>
-
-<template>
- <gl-filtered-search
- :placeholder="s__('Jobs|Filter jobs')"
- :available-tokens="tokens"
- :value="filteredSearchValue"
- @submit="onSubmit"
- />
-</template>
diff --git a/app/assets/javascripts/jobs/components/filtered_search/utils.js b/app/assets/javascripts/jobs/components/filtered_search/utils.js
deleted file mode 100644
index 696cd8d4706..00000000000
--- a/app/assets/javascripts/jobs/components/filtered_search/utils.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import { jobStatusValues } from './constants';
-
-// validates query string used for filtered search
-// on jobs table to ensure GraphQL query is called correctly
-export const validateQueryString = (queryStringObj) => {
- // currently only one token is supported `statuses`
- // this code will need to be expanded as more tokens
- // are introduced
-
- const filters = Object.keys(queryStringObj);
-
- if (filters.includes('statuses')) {
- const queryStringStatus = {
- statuses: queryStringObj.statuses.toUpperCase(),
- };
-
- const found = jobStatusValues.find((status) => status === queryStringStatus.statuses);
-
- if (found) {
- return queryStringStatus;
- }
-
- return null;
- }
-
- return null;
-};
diff --git a/app/assets/javascripts/jobs/components/job/empty_state.vue b/app/assets/javascripts/jobs/components/job/empty_state.vue
deleted file mode 100644
index d0a39025807..00000000000
--- a/app/assets/javascripts/jobs/components/job/empty_state.vue
+++ /dev/null
@@ -1,100 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-import ManualVariablesForm from '~/jobs/components/job/manual_variables_form.vue';
-
-export default {
- components: {
- GlLink,
- ManualVariablesForm,
- },
- props: {
- illustrationPath: {
- type: String,
- required: true,
- },
- illustrationSizeClass: {
- type: String,
- required: true,
- },
- isRetryable: {
- type: Boolean,
- required: true,
- },
- jobId: {
- type: Number,
- required: true,
- },
- title: {
- type: String,
- required: true,
- },
- content: {
- type: String,
- required: false,
- default: null,
- },
- playable: {
- type: Boolean,
- required: true,
- default: false,
- },
- scheduled: {
- type: Boolean,
- required: false,
- default: false,
- },
- action: {
- type: Object,
- required: false,
- default: null,
- validator(value) {
- return (
- value === null ||
- (Object.prototype.hasOwnProperty.call(value, 'path') &&
- Object.prototype.hasOwnProperty.call(value, 'method') &&
- Object.prototype.hasOwnProperty.call(value, 'button_title'))
- );
- },
- },
- },
- computed: {
- shouldRenderManualVariables() {
- return this.playable && !this.scheduled;
- },
- },
-};
-</script>
-<template>
- <div class="row empty-state">
- <div class="col-12">
- <div :class="illustrationSizeClass" class="svg-content">
- <img :src="illustrationPath" />
- </div>
- </div>
-
- <div class="col-12">
- <div class="text-content">
- <h4 class="text-center" data-testid="job-empty-state-title">{{ title }}</h4>
-
- <p v-if="content" data-testid="job-empty-state-content">{{ content }}</p>
- </div>
- <manual-variables-form
- v-if="shouldRenderManualVariables"
- :is-retryable="isRetryable"
- :job-id="jobId"
- @hideManualVariablesForm="$emit('hideManualVariablesForm')"
- />
- <div v-if="action && !shouldRenderManualVariables" class="text-content">
- <div class="text-center">
- <gl-link
- :href="action.path"
- :data-method="action.method"
- class="btn gl-button btn-confirm gl-text-decoration-none!"
- data-testid="job-empty-state-action"
- >{{ action.button_title }}</gl-link
- >
- </div>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql b/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql
deleted file mode 100644
index f4a0b10672e..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql
+++ /dev/null
@@ -1,11 +0,0 @@
-#import "~/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql"
-
-fragment BaseCiJob on CiJob {
- id
- manualVariables {
- nodes {
- ...ManualCiVariable
- }
- }
- __typename
-}
diff --git a/app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql b/app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql
deleted file mode 100644
index 520deef5136..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql
+++ /dev/null
@@ -1,11 +0,0 @@
-#import "~/jobs/components/job/graphql/fragments/ci_job.fragment.graphql"
-
-mutation playJobWithVariables($id: CiBuildID!, $variables: [CiVariableInput!]) {
- jobPlay(input: { id: $id, variables: $variables }) {
- job {
- ...BaseCiJob
- webPath
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql b/app/assets/javascripts/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql
deleted file mode 100644
index e35d603ea71..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql
+++ /dev/null
@@ -1,11 +0,0 @@
-#import "~/jobs/components/job/graphql/fragments/ci_job.fragment.graphql"
-
-mutation retryJobWithVariables($id: CiBuildID!, $variables: [CiVariableInput!]) {
- jobRetry(input: { id: $id, variables: $variables }) {
- job {
- ...BaseCiJob
- webPath
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/jobs/components/job/graphql/queries/get_job.query.graphql b/app/assets/javascripts/jobs/components/job/graphql/queries/get_job.query.graphql
deleted file mode 100644
index 95e3521091d..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/queries/get_job.query.graphql
+++ /dev/null
@@ -1,12 +0,0 @@
-#import "~/jobs/components/job/graphql/fragments/ci_job.fragment.graphql"
-
-query getJob($fullPath: ID!, $id: JobID!) {
- project(fullPath: $fullPath) {
- id
- job(id: $id) {
- ...BaseCiJob
- manualJob
- name
- }
- }
-}
diff --git a/app/assets/javascripts/jobs/components/job/job_app.vue b/app/assets/javascripts/jobs/components/job/job_app.vue
deleted file mode 100644
index 52030a0f830..00000000000
--- a/app/assets/javascripts/jobs/components/job/job_app.vue
+++ /dev/null
@@ -1,350 +0,0 @@
-<script>
-import { GlLoadingIcon, GlIcon, GlAlert } from '@gitlab/ui';
-import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
-import { throttle, isEmpty } from 'lodash';
-// eslint-disable-next-line no-restricted-imports
-import { mapGetters, mapState, mapActions } from 'vuex';
-import LogTopBar from 'ee_else_ce/jobs/components/job/job_log_controllers.vue';
-import SafeHtml from '~/vue_shared/directives/safe_html';
-import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
-import { __, sprintf } from '~/locale';
-import CiHeader from '~/vue_shared/components/header_ci_component.vue';
-import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
-import Log from '~/jobs/components/log/log.vue';
-import { MANUAL_STATUS } from '~/jobs/constants';
-import EmptyState from './empty_state.vue';
-import EnvironmentsBlock from './environments_block.vue';
-import ErasedBlock from './erased_block.vue';
-import StuckBlock from './stuck_block.vue';
-import UnmetPrerequisitesBlock from './unmet_prerequisites_block.vue';
-import Sidebar from './sidebar/sidebar.vue';
-
-export default {
- name: 'JobPageApp',
- components: {
- CiHeader,
- EmptyState,
- EnvironmentsBlock,
- ErasedBlock,
- GlIcon,
- Log,
- LogTopBar,
- StuckBlock,
- UnmetPrerequisitesBlock,
- Sidebar,
- GlLoadingIcon,
- SharedRunner: () => import('ee_component/jobs/components/shared_runner_limit_block.vue'),
- GlAlert,
- },
- directives: {
- SafeHtml,
- },
- mixins: [delayedJobMixin],
- props: {
- artifactHelpUrl: {
- type: String,
- required: false,
- default: '',
- },
- runnerSettingsUrl: {
- type: String,
- required: false,
- default: null,
- },
- deploymentHelpUrl: {
- type: String,
- required: false,
- default: null,
- },
- terminalPath: {
- type: String,
- required: false,
- default: null,
- },
- projectPath: {
- type: String,
- required: true,
- },
- subscriptionsMoreMinutesUrl: {
- type: String,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- searchResults: [],
- showUpdateVariablesState: false,
- };
- },
- computed: {
- ...mapState([
- 'isLoading',
- 'job',
- 'isSidebarOpen',
- 'jobLog',
- 'isJobLogComplete',
- 'jobLogSize',
- 'isJobLogSizeVisible',
- 'isScrollBottomDisabled',
- 'isScrollTopDisabled',
- 'isScrolledToBottomBeforeReceivingJobLog',
- 'hasError',
- 'selectedStage',
- ]),
- ...mapGetters([
- 'headerTime',
- 'hasUnmetPrerequisitesFailure',
- 'shouldRenderCalloutMessage',
- 'shouldRenderTriggeredLabel',
- 'hasEnvironment',
- 'shouldRenderSharedRunnerLimitWarning',
- 'hasJobLog',
- 'emptyStateIllustration',
- 'isScrollingDown',
- 'emptyStateAction',
- 'hasOfflineRunnersForProject',
- ]),
-
- shouldRenderContent() {
- return !this.isLoading && !this.hasError;
- },
-
- emptyStateTitle() {
- const { emptyStateIllustration, remainingTime } = this;
- const { title } = emptyStateIllustration;
-
- if (this.isDelayedJob) {
- return sprintf(title, { remainingTime });
- }
-
- return title;
- },
-
- shouldRenderHeaderCallout() {
- return this.shouldRenderCalloutMessage && !this.hasUnmetPrerequisitesFailure;
- },
-
- isJobRetryable() {
- return Boolean(this.job.retry_path);
- },
-
- itemName() {
- return sprintf(__('Job %{jobName}'), { jobName: this.job.name });
- },
- },
- watch: {
- // Once the job log is loaded,
- // fetch the stages for the dropdown on the sidebar
- job(newVal, oldVal) {
- if (isEmpty(oldVal) && !isEmpty(newVal.pipeline)) {
- const stages = this.job.pipeline.details.stages || [];
-
- const defaultStage = stages.find((stage) => stage && stage.name === this.selectedStage);
-
- if (defaultStage) {
- this.fetchJobsForStage(defaultStage);
- }
- }
-
- // Only poll for job log if we are not in the manual variables form empty state.
- // This will be handled more elegantly in the future with GraphQL in https://gitlab.com/gitlab-org/gitlab/-/issues/389597
- if (newVal?.status?.group !== MANUAL_STATUS && !this.showUpdateVariablesState) {
- this.fetchJobLog();
- }
- },
- },
- created() {
- this.throttled = throttle(this.toggleScrollButtons, 100);
-
- window.addEventListener('resize', this.onResize);
- window.addEventListener('scroll', this.updateScroll);
- },
- mounted() {
- this.updateSidebar();
- },
- beforeDestroy() {
- this.stopPollingJobLog();
- this.stopPolling();
- window.removeEventListener('resize', this.onResize);
- window.removeEventListener('scroll', this.updateScroll);
- },
- methods: {
- ...mapActions([
- 'fetchJobLog',
- 'fetchJobsForStage',
- 'hideSidebar',
- 'showSidebar',
- 'toggleSidebar',
- 'scrollBottom',
- 'scrollTop',
- 'stopPollingJobLog',
- 'stopPolling',
- 'toggleScrollButtons',
- 'toggleScrollAnimation',
- ]),
- onHideManualVariablesForm() {
- this.showUpdateVariablesState = false;
- },
- onResize() {
- this.updateSidebar();
- this.updateScroll();
- },
- onUpdateVariables() {
- this.showUpdateVariablesState = true;
- },
- updateSidebar() {
- const breakpoint = bp.getBreakpointSize();
- if (breakpoint === 'xs' || breakpoint === 'sm') {
- this.hideSidebar();
- } else if (!this.isSidebarOpen) {
- this.showSidebar();
- }
- },
- updateScroll() {
- if (!isScrolledToBottom()) {
- this.toggleScrollAnimation(false);
- } else if (this.isScrollingDown) {
- this.toggleScrollAnimation(true);
- }
-
- this.throttled();
- },
- setSearchResults(searchResults) {
- this.searchResults = searchResults;
- },
- },
-};
-</script>
-<template>
- <div>
- <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-6" />
-
- <template v-else-if="shouldRenderContent">
- <div class="build-page" data-testid="job-content">
- <!-- Header Section -->
- <header>
- <div class="build-header top-area">
- <ci-header
- :status="job.status"
- :time="headerTime"
- :user="job.user"
- :has-sidebar-button="true"
- :should-render-triggered-label="shouldRenderTriggeredLabel"
- :item-name="itemName"
- @clickedSidebarButton="toggleSidebar"
- />
- </div>
- <gl-alert
- v-if="shouldRenderHeaderCallout"
- variant="danger"
- class="gl-mt-3"
- :dismissible="false"
- >
- <div v-safe-html="job.callout_message"></div>
- </gl-alert>
- </header>
- <!-- EO Header Section -->
-
- <!-- Body Section -->
- <stuck-block
- v-if="job.stuck"
- :has-offline-runners-for-project="hasOfflineRunnersForProject"
- :tags="job.tags"
- :runners-path="runnerSettingsUrl"
- />
-
- <unmet-prerequisites-block
- v-if="hasUnmetPrerequisitesFailure"
- :help-path="deploymentHelpUrl"
- />
-
- <shared-runner
- v-if="shouldRenderSharedRunnerLimitWarning"
- :quota-used="job.runners.quota.used"
- :quota-limit="job.runners.quota.limit"
- :project-path="projectPath"
- :subscriptions-more-minutes-url="subscriptionsMoreMinutesUrl"
- />
-
- <environments-block
- v-if="hasEnvironment"
- :deployment-status="job.deployment_status"
- :deployment-cluster="job.deployment_cluster"
- :icon-status="job.status"
- />
-
- <erased-block
- v-if="job.erased_at"
- data-testid="job-erased-block"
- :user="job.erased_by"
- :erased-at="job.erased_at"
- />
-
- <div
- v-if="job.archived"
- class="gl-mt-3 gl-py-2 gl-px-3 gl-align-items-center gl-z-index-1 gl-m-auto archived-job"
- :class="{ 'sticky-top gl-border-bottom-0': hasJobLog }"
- data-testid="archived-job"
- >
- <gl-icon name="lock" class="gl-vertical-align-bottom" />
- {{ __('This job is archived. Only the complete pipeline can be retried.') }}
- </div>
- <!-- job log -->
- <div
- v-if="hasJobLog && !showUpdateVariablesState"
- class="build-log-container gl-relative"
- :class="{ 'gl-mt-3': !job.archived }"
- >
- <log-top-bar
- :class="{
- 'has-archived-block': job.archived,
- }"
- :size="jobLogSize"
- :raw-path="job.raw_path"
- :is-scroll-bottom-disabled="isScrollBottomDisabled"
- :is-scroll-top-disabled="isScrollTopDisabled"
- :is-job-log-size-visible="isJobLogSizeVisible"
- :is-scrolling-down="isScrollingDown"
- :is-complete="isJobLogComplete"
- :job-log="jobLog"
- @scrollJobLogTop="scrollTop"
- @scrollJobLogBottom="scrollBottom"
- @searchResults="setSearchResults"
- />
- <log :job-log="jobLog" :is-complete="isJobLogComplete" :search-results="searchResults" />
- </div>
- <!-- EO job log -->
-
- <!-- empty state -->
- <empty-state
- v-if="!hasJobLog || showUpdateVariablesState"
- :illustration-path="emptyStateIllustration.image"
- :illustration-size-class="emptyStateIllustration.size"
- :is-retryable="isJobRetryable"
- :job-id="job.id"
- :title="emptyStateTitle"
- :content="emptyStateIllustration.content"
- :action="emptyStateAction"
- :playable="job.playable"
- :scheduled="job.scheduled"
- @hideManualVariablesForm="onHideManualVariablesForm()"
- />
- <!-- EO empty state -->
-
- <!-- EO Body Section -->
- </div>
- </template>
-
- <sidebar
- v-if="shouldRenderContent"
- :class="{
- 'right-sidebar-expanded': isSidebarOpen,
- 'right-sidebar-collapsed': !isSidebarOpen,
- }"
- :artifact-help-url="artifactHelpUrl"
- data-testid="job-sidebar"
- @updateVariables="onUpdateVariables()"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job/job_log_controllers.vue
deleted file mode 100644
index efd4eed2a9f..00000000000
--- a/app/assets/javascripts/jobs/components/job/job_log_controllers.vue
+++ /dev/null
@@ -1,269 +0,0 @@
-<script>
-import { GlTooltipDirective, GlLink, GlButton, GlSearchBoxByClick } from '@gitlab/ui';
-import { scrollToElement, backOff } from '~/lib/utils/common_utils';
-import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { __, s__, sprintf } from '~/locale';
-import HelpPopover from '~/vue_shared/components/help_popover.vue';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-
-export default {
- i18n: {
- scrollToBottomButtonLabel: s__('Job|Scroll to bottom'),
- scrollToTopButtonLabel: s__('Job|Scroll to top'),
- scrollToNextFailureButtonLabel: s__('Job|Scroll to next failure'),
- showRawButtonLabel: s__('Job|Show complete raw'),
- searchPlaceholder: s__('Job|Search job log'),
- noResults: s__('Job|No search results found'),
- searchPopoverTitle: s__('Job|Job log search'),
- searchPopoverDescription: s__(
- 'Job|Search for substrings in your job log output. Currently search is only supported for the visible job log output, not for any log output that is truncated due to size.',
- ),
- logLineNumberNotFound: s__('Job|We could not find this element'),
- },
- components: {
- GlLink,
- GlButton,
- GlSearchBoxByClick,
- HelpPopover,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [glFeatureFlagMixin()],
- props: {
- size: {
- type: Number,
- required: true,
- },
- rawPath: {
- type: String,
- required: false,
- default: null,
- },
- isScrollTopDisabled: {
- type: Boolean,
- required: true,
- },
- isScrollBottomDisabled: {
- type: Boolean,
- required: true,
- },
- isScrollingDown: {
- type: Boolean,
- required: true,
- },
- isJobLogSizeVisible: {
- type: Boolean,
- required: true,
- },
- isComplete: {
- type: Boolean,
- required: true,
- },
- jobLog: {
- type: Array,
- required: true,
- },
- },
- data() {
- return {
- searchTerm: '',
- searchResults: [],
- failureCount: null,
- failureIndex: 0,
- };
- },
- computed: {
- jobLogSize() {
- return sprintf(__('Showing last %{size} of log -'), {
- size: numberToHumanSize(this.size),
- });
- },
- showJumpToFailures() {
- return this.glFeatures.jobLogJumpToFailures;
- },
- hasFailures() {
- return this.failureCount > 0;
- },
- shouldDisableJumpToFailures() {
- return !this.hasFailures;
- },
- },
- mounted() {
- this.checkFailureCount();
- },
- methods: {
- checkFailureCount() {
- if (this.glFeatures.jobLogJumpToFailures) {
- backOff((next, stop) => {
- this.failureCount = document.querySelectorAll('.term-fg-l-red').length;
-
- if (this.hasFailures || (this.isComplete && !this.hasFailures)) {
- stop();
- } else {
- next();
- }
- }).catch(() => {
- this.failureCount = null;
- });
- }
- },
- handleScrollToNextFailure() {
- const failures = document.querySelectorAll('.term-fg-l-red');
- const nextFailure = failures[this.failureIndex];
-
- if (nextFailure) {
- nextFailure.scrollIntoView({ block: 'center' });
- this.failureIndex = (this.failureIndex + 1) % failures.length;
- }
- },
- handleScrollToTop() {
- this.$emit('scrollJobLogTop');
- this.failureIndex = 0;
- },
- handleScrollToBottom() {
- this.$emit('scrollJobLogBottom');
- this.failureIndex = 0;
- },
- searchJobLog() {
- this.searchResults = [];
-
- if (!this.searchTerm) return;
-
- const compactedLog = [];
-
- this.jobLog.forEach((obj) => {
- if (obj.lines && obj.lines.length > 0) {
- compactedLog.push(...obj.lines);
- }
-
- if (!obj.lines && obj.content.length > 0) {
- compactedLog.push(obj);
- }
- });
-
- compactedLog.forEach((line) => {
- const lineText = line.content[0].text;
-
- if (lineText.toLocaleLowerCase().includes(this.searchTerm.toLocaleLowerCase())) {
- this.searchResults.push(line);
- }
- });
-
- if (this.searchResults.length > 0) {
- this.$emit('searchResults', this.searchResults);
-
- // BE returns zero based index, we need to add one to match the line numbers in the DOM
- const firstSearchResult = `#L${this.searchResults[0].lineNumber + 1}`;
- const logLine = document.querySelector(`.js-line ${firstSearchResult}`);
-
- if (logLine) {
- setTimeout(() => scrollToElement(logLine));
-
- const message = sprintf(s__('Job|%{searchLength} results found for %{searchTerm}'), {
- searchLength: this.searchResults.length,
- searchTerm: this.searchTerm,
- });
-
- this.$toast.show(message);
- } else {
- this.$toast.show(this.$options.i18n.logLineNumberNotFound);
- }
- } else {
- this.$toast.show(this.$options.i18n.noResults);
- }
- },
- },
-};
-</script>
-<template>
- <div class="top-bar gl-display-flex gl-justify-content-space-between">
- <slot name="drawers"></slot>
- <!-- truncate information -->
- <div
- class="truncated-info gl-display-none gl-sm-display-flex gl-flex-wrap gl-align-items-center"
- data-testid="log-truncated-info"
- >
- <template v-if="isJobLogSizeVisible">
- {{ jobLogSize }}
- <gl-link
- v-if="rawPath"
- :href="rawPath"
- class="text-plain text-underline gl-ml-2"
- data-testid="raw-link"
- >{{ s__('Job|Complete Raw') }}</gl-link
- >
- </template>
- </div>
- <!-- eo truncate information -->
-
- <div class="controllers">
- <slot name="controllers"> </slot>
- <gl-search-box-by-click
- v-model="searchTerm"
- class="gl-mr-3"
- :placeholder="$options.i18n.searchPlaceholder"
- data-testid="job-log-search-box"
- @clear="$emit('searchResults', [])"
- @submit="searchJobLog"
- />
-
- <help-popover class="gl-mr-3">
- <template #title>{{ $options.i18n.searchPopoverTitle }}</template>
-
- <p class="gl-mb-0">
- {{ $options.i18n.searchPopoverDescription }}
- </p>
- </help-popover>
-
- <!-- links -->
- <gl-button
- v-if="rawPath"
- v-gl-tooltip.body
- :title="$options.i18n.showRawButtonLabel"
- :aria-label="$options.i18n.showRawButtonLabel"
- :href="rawPath"
- data-testid="job-raw-link-controller"
- icon="doc-text"
- />
- <!-- eo links -->
-
- <!-- scroll buttons -->
- <gl-button
- v-if="showJumpToFailures"
- v-gl-tooltip
- :title="$options.i18n.scrollToNextFailureButtonLabel"
- :aria-label="$options.i18n.scrollToNextFailureButtonLabel"
- :disabled="shouldDisableJumpToFailures"
- class="btn-scroll gl-ml-3"
- data-testid="job-controller-scroll-to-failure"
- icon="soft-wrap"
- @click="handleScrollToNextFailure"
- />
-
- <div v-gl-tooltip :title="$options.i18n.scrollToTopButtonLabel" class="gl-ml-3">
- <gl-button
- :disabled="isScrollTopDisabled"
- class="btn-scroll"
- data-testid="job-controller-scroll-top"
- icon="scroll_up"
- :aria-label="$options.i18n.scrollToTopButtonLabel"
- @click="handleScrollToTop"
- />
- </div>
-
- <div v-gl-tooltip :title="$options.i18n.scrollToBottomButtonLabel" class="gl-ml-3">
- <gl-button
- :disabled="isScrollBottomDisabled"
- class="js-scroll-bottom btn-scroll"
- data-testid="job-controller-scroll-bottom"
- icon="scroll_down"
- :class="{ animate: isScrollingDown }"
- :aria-label="$options.i18n.scrollToBottomButtonLabel"
- @click="handleScrollToBottom"
- />
- </div>
- <!-- eo scroll buttons -->
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/manual_variables_form.vue b/app/assets/javascripts/jobs/components/job/manual_variables_form.vue
deleted file mode 100644
index 356d65e1d14..00000000000
--- a/app/assets/javascripts/jobs/components/job/manual_variables_form.vue
+++ /dev/null
@@ -1,305 +0,0 @@
-<script>
-import {
- GlFormInputGroup,
- GlInputGroupText,
- GlFormInput,
- GlButton,
- GlLink,
- GlLoadingIcon,
- GlSprintf,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import { cloneDeep, uniqueId } from 'lodash';
-import { fetchPolicies } from '~/lib/graphql';
-import { createAlert } from '~/alert';
-import { TYPENAME_CI_BUILD, TYPENAME_COMMIT_STATUS } from '~/graphql_shared/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import { JOB_GRAPHQL_ERRORS } from '~/jobs/constants';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import { s__ } from '~/locale';
-import { reportMessageToSentry } from '~/jobs/utils';
-import GetJob from './graphql/queries/get_job.query.graphql';
-import playJobWithVariablesMutation from './graphql/mutations/job_play_with_variables.mutation.graphql';
-import retryJobWithVariablesMutation from './graphql/mutations/job_retry_with_variables.mutation.graphql';
-
-// This component is a port of ~/jobs/components/job/legacy_manual_variables_form.vue
-// It is meant to fetch/update the job information via GraphQL instead of REST API.
-
-export default {
- name: 'ManualVariablesForm',
- components: {
- GlFormInputGroup,
- GlInputGroupText,
- GlFormInput,
- GlButton,
- GlLink,
- GlLoadingIcon,
- GlSprintf,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- inject: ['projectPath'],
- apollo: {
- variables: {
- query: GetJob,
- variables() {
- return {
- fullPath: this.projectPath,
- id: convertToGraphQLId(TYPENAME_COMMIT_STATUS, this.jobId),
- };
- },
- fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
- update(data) {
- const jobVariables = cloneDeep(data?.project?.job?.manualVariables?.nodes);
- return [...jobVariables.reverse(), ...this.variables];
- },
- error(error) {
- createAlert({ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText });
- reportMessageToSentry(this.$options.name, error, {});
- },
- },
- },
- props: {
- isRetryable: {
- type: Boolean,
- required: true,
- },
- jobId: {
- type: Number,
- required: true,
- },
- },
- clearBtnSharedClasses: ['gl-flex-grow-0 gl-flex-basis-0 gl-m-0! gl-ml-3!'],
- inputTypes: {
- key: 'key',
- value: 'value',
- },
- i18n: {
- cancel: s__('CiVariables|Cancel'),
- removeInputs: s__('CiVariables|Remove inputs'),
- formHelpText: s__(
- 'CiVariables|Specify variable values to be used in this run. The variables specified in the configuration file and %{linkStart}CI/CD settings%{linkEnd} are used by default.',
- ),
- overrideNoteText: s__(
- 'CiVariables|Variables specified here are %{boldStart}expanded%{boldEnd} and not %{boldStart}masked.%{boldEnd}',
- ),
- header: s__('CiVariables|Variables'),
- keyLabel: s__('CiVariables|Key'),
- keyPlaceholder: s__('CiVariables|Input variable key'),
- runAgainButtonText: s__('CiVariables|Run job again'),
- runButtonText: s__('CiVariables|Run job'),
- valueLabel: s__('CiVariables|Value'),
- valuePlaceholder: s__('CiVariables|Input variable value'),
- },
- data() {
- return {
- job: {},
- variables: [
- {
- id: uniqueId(),
- key: '',
- value: '',
- },
- ],
- runBtnDisabled: false,
- };
- },
- computed: {
- mutationVariables() {
- return {
- id: convertToGraphQLId(TYPENAME_CI_BUILD, this.jobId),
- variables: this.preparedVariables,
- };
- },
- preparedVariables() {
- return this.variables
- .filter((variable) => variable.key !== '')
- .map(({ key, value }) => ({ key, value }));
- },
- runBtnText() {
- return this.isRetryable
- ? this.$options.i18n.runAgainButtonText
- : this.$options.i18n.runButtonText;
- },
- variableSettings() {
- return helpPagePath('ci/variables/index', { anchor: 'add-a-cicd-variable-to-a-project' });
- },
- },
- methods: {
- async playJob() {
- try {
- const { data } = await this.$apollo.mutate({
- mutation: playJobWithVariablesMutation,
- variables: this.mutationVariables,
- });
- if (data.jobPlay?.errors?.length) {
- createAlert({ message: data.jobPlay.errors[0] });
- } else {
- this.navigateToJob(data.jobPlay?.job?.webPath);
- }
- } catch (error) {
- createAlert({ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText });
- reportMessageToSentry(this.$options.name, error, {});
- }
- },
- async retryJob() {
- try {
- const { data } = await this.$apollo.mutate({
- mutation: retryJobWithVariablesMutation,
- variables: this.mutationVariables,
- });
- if (data.jobRetry?.errors?.length) {
- createAlert({ message: data.jobRetry.errors[0] });
- } else {
- this.navigateToJob(data.jobRetry?.job?.webPath);
- }
- } catch (error) {
- createAlert({ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText });
- reportMessageToSentry(this.$options.name, error, {});
- }
- },
- addEmptyVariable() {
- const lastVar = this.variables[this.variables.length - 1];
-
- if (lastVar.key === '') {
- return;
- }
-
- this.variables.push({
- id: uniqueId(),
- key: '',
- value: '',
- });
- },
- canRemove(index) {
- return index < this.variables.length - 1;
- },
- deleteVariable(id) {
- this.variables.splice(
- this.variables.findIndex((el) => el.id === id),
- 1,
- );
- },
- inputRef(type, id) {
- return `${this.$options.inputTypes[type]}-${id}`;
- },
- navigateToJob(path) {
- redirectTo(path); // eslint-disable-line import/no-deprecated
- },
- runJob() {
- this.runBtnDisabled = true;
-
- if (this.isRetryable) {
- this.retryJob();
- } else {
- this.playJob();
- }
- },
- },
-};
-</script>
-<template>
- <gl-loading-icon v-if="$apollo.queries.variables.loading" class="gl-mt-9" size="lg" />
- <div v-else class="row gl-justify-content-center">
- <div class="col-10">
- <label>{{ $options.i18n.header }}</label>
-
- <div
- v-for="(variable, index) in variables"
- :key="variable.id"
- class="gl-display-flex gl-align-items-center gl-mb-5"
- data-testid="ci-variable-row"
- >
- <gl-form-input-group class="gl-mr-4 gl-flex-grow-1">
- <template #prepend>
- <gl-input-group-text>
- {{ $options.i18n.keyLabel }}
- </gl-input-group-text>
- </template>
- <gl-form-input
- :ref="inputRef('key', variable.id)"
- v-model="variable.key"
- :placeholder="$options.i18n.keyPlaceholder"
- data-testid="ci-variable-key"
- @change="addEmptyVariable"
- />
- </gl-form-input-group>
-
- <gl-form-input-group class="gl-flex-grow-2">
- <template #prepend>
- <gl-input-group-text>
- {{ $options.i18n.valueLabel }}
- </gl-input-group-text>
- </template>
- <gl-form-input
- :ref="inputRef('value', variable.id)"
- v-model="variable.value"
- :placeholder="$options.i18n.valuePlaceholder"
- data-testid="ci-variable-value"
- />
- </gl-form-input-group>
-
- <gl-button
- v-if="canRemove(index)"
- v-gl-tooltip
- :aria-label="$options.i18n.removeInputs"
- :title="$options.i18n.removeInputs"
- :class="$options.clearBtnSharedClasses"
- category="tertiary"
- icon="remove"
- data-testid="delete-variable-btn"
- @click="deleteVariable(variable.id)"
- />
- <!-- Placeholder button to keep the layout fixed -->
- <gl-button
- v-else
- class="gl-opacity-0 gl-pointer-events-none"
- :class="$options.clearBtnSharedClasses"
- data-testid="delete-variable-btn-placeholder"
- category="tertiary"
- icon="remove"
- />
- </div>
-
- <div class="gl-text-center gl-mt-5">
- <gl-sprintf :message="$options.i18n.formHelpText">
- <template #link="{ content }">
- <gl-link :href="variableSettings" target="_blank">
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </div>
- <div class="gl-text-center gl-mt-3">
- <gl-sprintf :message="$options.i18n.overrideNoteText">
- <template #bold="{ content }">
- <strong>
- {{ content }}
- </strong>
- </template>
- </gl-sprintf>
- </div>
- <div class="gl-display-flex gl-justify-content-center gl-mt-5">
- <gl-button
- v-if="isRetryable"
- class="gl-mt-5"
- data-testid="cancel-btn"
- @click="$emit('hideManualVariablesForm')"
- >{{ $options.i18n.cancel }}</gl-button
- >
- <gl-button
- class="gl-mt-5"
- variant="confirm"
- category="primary"
- :disabled="runBtnDisabled"
- data-testid="run-manual-job-btn"
- @click="runJob"
- >
- {{ runBtnText }}
- </gl-button>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue
deleted file mode 100644
index a78cacf110f..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue
+++ /dev/null
@@ -1,121 +0,0 @@
-<script>
-import { GlButton, GlButtonGroup, GlIcon, GlLink, GlPopover } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-
-export default {
- i18n: {
- jobArtifacts: s__('Job|Job artifacts'),
- artifactsHelpText: s__(
- 'Job|Job artifacts are files that are configured to be uploaded when a job finishes execution. Artifacts could be compiled files, unit tests or scanning reports, or any other files generated by a job.',
- ),
- expiredText: s__('Job|The artifacts were removed'),
- willExpireText: s__('Job|The artifacts will be removed'),
- lockedText: s__(
- 'Job|These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available.',
- ),
- keepText: s__('Job|Keep'),
- downloadText: s__('Job|Download'),
- browseText: s__('Job|Browse'),
- },
- artifactsHelpPath: helpPagePath('ci/jobs/job_artifacts'),
- components: {
- GlButton,
- GlButtonGroup,
- GlIcon,
- GlLink,
- GlPopover,
- TimeagoTooltip,
- },
- mixins: [timeagoMixin],
- props: {
- artifact: {
- type: Object,
- required: true,
- },
- helpUrl: {
- type: String,
- required: true,
- },
- },
- computed: {
- isExpired() {
- return this.artifact?.expired && !this.isLocked;
- },
- isLocked() {
- return this.artifact?.locked;
- },
- // Only when the key is `false` we can render this block
- willExpire() {
- return this.artifact?.expired === false && !this.isLocked;
- },
- },
-};
-</script>
-<template>
- <div>
- <div class="title gl-font-weight-bold">
- <span class="gl-mr-2">{{ $options.i18n.jobArtifacts }}</span>
- <gl-link :href="$options.artifactsHelpPath" data-testid="artifacts-help-link">
- <gl-icon id="artifacts-help" name="question-o" />
- </gl-link>
- <gl-popover
- target="artifacts-help"
- :title="$options.i18n.jobArtifacts"
- triggers="hover focus"
- >
- {{ $options.i18n.artifactsHelpText }}
- </gl-popover>
- </div>
- <p
- v-if="isExpired || willExpire"
- class="build-detail-row"
- data-testid="artifacts-remove-timeline"
- >
- <span v-if="isExpired">{{ $options.i18n.expiredText }}</span>
- <span v-if="willExpire" data-qa-selector="artifacts_unlocked_message_content">
- {{ $options.i18n.willExpireText }}
- </span>
- <timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" />
- <gl-link
- :href="helpUrl"
- target="_blank"
- rel="noopener noreferrer nofollow"
- data-testid="artifact-expired-help-link"
- >
- <gl-icon name="question-o" />
- </gl-link>
- </p>
- <p v-else-if="isLocked" class="build-detail-row">
- <span data-testid="job-locked-message" data-qa-selector="artifacts_locked_message_content">
- {{ $options.i18n.lockedText }}
- </span>
- </p>
- <gl-button-group class="gl-display-flex gl-mt-3">
- <gl-button
- v-if="artifact.keep_path"
- :href="artifact.keep_path"
- data-method="post"
- data-testid="keep-artifacts"
- >{{ $options.i18n.keepText }}</gl-button
- >
- <gl-button
- v-if="artifact.download_path"
- :href="artifact.download_path"
- rel="nofollow"
- data-testid="download-artifacts"
- download
- >{{ $options.i18n.downloadText }}</gl-button
- >
- <gl-button
- v-if="artifact.browse_path"
- :href="artifact.browse_path"
- data-testid="browse-artifacts"
- data-qa-selector="browse_artifacts_button"
- >{{ $options.i18n.browseText }}</gl-button
- >
- </gl-button-group>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/commit_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/commit_block.vue
deleted file mode 100644
index 7f25ca8a94d..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/commit_block.vue
+++ /dev/null
@@ -1,47 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-
-export default {
- components: {
- ClipboardButton,
- GlLink,
- },
- props: {
- commit: {
- type: Object,
- required: true,
- },
- mergeRequest: {
- type: Object,
- required: false,
- default: null,
- },
- },
-};
-</script>
-<template>
- <div>
- <span class="gl-font-weight-bold">{{ __('Commit') }}</span>
-
- <gl-link :href="commit.commit_path" class="gl-text-blue-600!" data-testid="commit-sha">
- {{ commit.short_id }}
- </gl-link>
-
- <clipboard-button
- :text="commit.id"
- :title="__('Copy commit SHA')"
- category="tertiary"
- size="small"
- />
-
- <span v-if="mergeRequest">
- {{ __('in') }}
- <gl-link :href="mergeRequest.path" class="gl-text-blue-600!" data-testid="link-commit"
- >!{{ mergeRequest.iid }}</gl-link
- >
- </span>
-
- <p class="gl-mb-0">{{ commit.title }}</p>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/job_container_item.vue b/app/assets/javascripts/jobs/components/job/sidebar/job_container_item.vue
deleted file mode 100644
index 097ab3b4cf6..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/job_container_item.vue
+++ /dev/null
@@ -1,77 +0,0 @@
-<script>
-import { GlLink, GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
-import { sprintf } from '~/locale';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-
-export default {
- components: {
- CiIcon,
- GlIcon,
- GlLink,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [delayedJobMixin],
- props: {
- job: {
- type: Object,
- required: true,
- },
- isActive: {
- type: Boolean,
- required: true,
- },
- },
- computed: {
- tooltipText() {
- const { name, status } = this.job;
- const text = `${name} - ${status.tooltip}`;
-
- if (this.isDelayedJob) {
- return sprintf(text, { remainingTime: this.remainingTime });
- }
-
- return text;
- },
- jobName() {
- return this.job.name ? this.job.name : this.job.id;
- },
- classes() {
- return {
- retried: this.job.retried,
- 'gl-font-weight-bold': this.isActive,
- };
- },
- dataTestId() {
- return this.isActive ? 'active-job' : null;
- },
- },
-};
-</script>
-
-<template>
- <div class="build-job gl-relative" :class="classes">
- <gl-link
- v-gl-tooltip.left.viewport
- :href="job.status.details_path"
- :title="tooltipText"
- class="gl-display-flex gl-align-items-center"
- :data-testid="dataTestId"
- >
- <gl-icon
- v-if="isActive"
- name="arrow-right"
- class="icon-arrow-right gl-absolute gl-display-block"
- :size="14"
- />
-
- <ci-icon :status="job.status" class="gl-mr-2" :size="14" />
-
- <span class="gl-text-truncate gl-w-full">{{ jobName }}</span>
-
- <gl-icon v-if="job.retried" name="retry" />
- </gl-link>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue b/app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue
deleted file mode 100644
index a3f1a2c4be8..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue
+++ /dev/null
@@ -1,64 +0,0 @@
-<script>
-import { GlLink, GlModal } from '@gitlab/ui';
-import { JOB_RETRY_FORWARD_DEPLOYMENT_MODAL } from '~/jobs/constants';
-
-export default {
- name: 'JobRetryForwardDeploymentModal',
- components: {
- GlLink,
- GlModal,
- },
- i18n: {
- ...JOB_RETRY_FORWARD_DEPLOYMENT_MODAL,
- },
- inject: {
- retryOutdatedJobDocsUrl: {
- default: '',
- },
- },
- props: {
- modalId: {
- type: String,
- required: true,
- },
- href: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- primaryProps: {
- text: this.$options.i18n.primaryText,
- attributes: {
- 'data-method': 'post',
- 'data-testid': 'retry-button-modal',
- href: this.href,
- variant: 'danger',
- },
- },
- cancelProps: {
- text: this.$options.i18n.cancel,
- attributes: { category: 'secondary', variant: 'default' },
- },
- };
- },
-};
-</script>
-
-<template>
- <gl-modal
- :action-cancel="cancelProps"
- :action-primary="primaryProps"
- :modal-id="modalId"
- :title="$options.i18n.title"
- >
- <p>
- {{ $options.i18n.info }}
- <gl-link v-if="retryOutdatedJobDocsUrl" :href="retryOutdatedJobDocsUrl" target="_blank">
- {{ $options.i18n.moreInfo }}
- </gl-link>
- </p>
- <p>{{ $options.i18n.areYouSure }}</p>
- </gl-modal>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/job_sidebar_retry_button.vue b/app/assets/javascripts/jobs/components/job/sidebar/job_sidebar_retry_button.vue
deleted file mode 100644
index 87c47f592aa..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/job_sidebar_retry_button.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-<script>
-import { GlButton, GlDisclosureDropdown, GlModalDirective } from '@gitlab/ui';
-// eslint-disable-next-line no-restricted-imports
-import { mapGetters } from 'vuex';
-import { JOB_SIDEBAR_COPY } from '~/jobs/constants';
-
-export default {
- name: 'JobSidebarRetryButton',
- i18n: {
- ...JOB_SIDEBAR_COPY,
- },
- components: {
- GlButton,
- GlDisclosureDropdown,
- },
- directives: {
- GlModal: GlModalDirective,
- },
- props: {
- modalId: {
- type: String,
- required: true,
- },
- href: {
- type: String,
- required: true,
- },
- isManualJob: {
- type: Boolean,
- required: true,
- },
- },
- computed: {
- ...mapGetters(['hasForwardDeploymentFailure']),
- dropdownItems() {
- return [
- {
- text: this.$options.i18n.runAgainJobButtonLabel,
- href: this.href,
- extraAttrs: {
- 'data-method': 'post',
- },
- },
- {
- text: this.$options.i18n.updateVariables,
- action: () => this.$emit('updateVariablesClicked'),
- },
- ];
- },
- },
-};
-</script>
-<template>
- <gl-button
- v-if="hasForwardDeploymentFailure"
- v-gl-modal="modalId"
- :aria-label="$options.i18n.retryJobLabel"
- category="primary"
- variant="confirm"
- icon="retry"
- data-testid="retry-job-button"
- />
- <gl-disclosure-dropdown
- v-else-if="isManualJob"
- icon="retry"
- category="primary"
- placement="right"
- variant="confirm"
- :items="dropdownItems"
- />
- <gl-button
- v-else
- :href="href"
- :aria-label="$options.i18n.retryJobLabel"
- category="primary"
- variant="confirm"
- icon="retry"
- data-method="post"
- data-testid="retry-job-link"
- />
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/jobs_container.vue b/app/assets/javascripts/jobs/components/job/sidebar/jobs_container.vue
deleted file mode 100644
index df64b6422c7..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/jobs_container.vue
+++ /dev/null
@@ -1,35 +0,0 @@
-<script>
-import JobContainerItem from './job_container_item.vue';
-
-export default {
- components: {
- JobContainerItem,
- },
-
- props: {
- jobs: {
- type: Array,
- required: true,
- },
- jobId: {
- type: Number,
- required: true,
- },
- },
- methods: {
- isJobActive(currentJobId) {
- return this.jobId === currentJobId;
- },
- },
-};
-</script>
-<template>
- <div class="builds-container">
- <job-container-item
- v-for="job in jobs"
- :key="job.id"
- :job="job"
- :is-active="isJobActive(job.id)"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue
deleted file mode 100644
index 92e1557ada2..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue
+++ /dev/null
@@ -1,154 +0,0 @@
-<script>
-import { GlButton, GlIcon } from '@gitlab/ui';
-import { isEmpty } from 'lodash';
-// eslint-disable-next-line no-restricted-imports
-import { mapActions, mapGetters, mapState } from 'vuex';
-import { JOB_SIDEBAR_COPY, forwardDeploymentFailureModalId } from '~/jobs/constants';
-import ArtifactsBlock from './artifacts_block.vue';
-import CommitBlock from './commit_block.vue';
-import JobsContainer from './jobs_container.vue';
-import JobRetryForwardDeploymentModal from './job_retry_forward_deployment_modal.vue';
-import JobSidebarDetailsContainer from './sidebar_job_details_container.vue';
-import SidebarHeader from './sidebar_header.vue';
-import StagesDropdown from './stages_dropdown.vue';
-import TriggerBlock from './trigger_block.vue';
-
-export default {
- name: 'JobSidebar',
- i18n: {
- ...JOB_SIDEBAR_COPY,
- },
- borderTopClass: ['gl-border-t-solid', 'gl-border-t-1', 'gl-border-t-gray-100'],
- forwardDeploymentFailureModalId,
- components: {
- ArtifactsBlock,
- CommitBlock,
- GlButton,
- GlIcon,
- JobsContainer,
- JobRetryForwardDeploymentModal,
- JobSidebarDetailsContainer,
- SidebarHeader,
- StagesDropdown,
- TriggerBlock,
- },
- props: {
- artifactHelpUrl: {
- type: String,
- required: false,
- default: '',
- },
- },
- computed: {
- ...mapGetters(['hasForwardDeploymentFailure']),
- ...mapState(['job', 'stages', 'jobs', 'selectedStage']),
- hasArtifact() {
- // the artifact object will always have a locked property
- return Object.keys(this.job.artifact).length > 1;
- },
- hasTriggers() {
- return !isEmpty(this.job.trigger);
- },
- commit() {
- return this.job?.pipeline?.commit || {};
- },
- selectedStageData() {
- return this.stages.find((val) => val.name === this.selectedStage);
- },
- shouldShowJobRetryForwardDeploymentModal() {
- return this.job.retry_path && this.hasForwardDeploymentFailure;
- },
- },
- watch: {
- job(value, oldValue) {
- const hasNewStatus = value.status.text !== oldValue.status.text;
- const isCurrentStage = value?.stage === this.selectedStage;
-
- if (hasNewStatus && isCurrentStage) {
- this.fetchJobsForStage(this.selectedStageData);
- }
- },
- },
- methods: {
- ...mapActions(['fetchJobsForStage']),
- },
-};
-</script>
-<template>
- <aside class="right-sidebar build-sidebar" data-offset-top="101" data-spy="affix">
- <div class="sidebar-container">
- <div class="blocks-container">
- <sidebar-header
- :rest-job="job"
- :job-id="job.id"
- @updateVariables="$emit('updateVariables')"
- />
- <div
- v-if="job.terminal_path || job.new_issue_path"
- class="gl-py-5"
- :class="$options.borderTopClass"
- >
- <gl-button
- v-if="job.new_issue_path"
- :href="job.new_issue_path"
- category="secondary"
- variant="confirm"
- data-testid="job-new-issue"
- >
- {{ $options.i18n.newIssue }}
- </gl-button>
- <gl-button
- v-if="job.terminal_path"
- :href="job.terminal_path"
- target="_blank"
- data-testid="terminal-link"
- >
- {{ $options.i18n.debug }}
- <gl-icon name="external-link" />
- </gl-button>
- </div>
-
- <job-sidebar-details-container class="gl-py-5" :class="$options.borderTopClass" />
-
- <artifacts-block
- v-if="hasArtifact"
- class="gl-py-5"
- :class="$options.borderTopClass"
- :artifact="job.artifact"
- :help-url="artifactHelpUrl"
- />
-
- <trigger-block
- v-if="hasTriggers"
- class="gl-py-5"
- :class="$options.borderTopClass"
- :trigger="job.trigger"
- />
-
- <commit-block
- :commit="commit"
- class="gl-py-5"
- :class="$options.borderTopClass"
- :merge-request="job.merge_request"
- />
-
- <stages-dropdown
- v-if="job.pipeline"
- class="gl-py-5"
- :class="$options.borderTopClass"
- :pipeline="job.pipeline"
- :selected-stage="selectedStage"
- :stages="stages"
- @requestSidebarStageDropdown="fetchJobsForStage"
- />
- </div>
-
- <jobs-container v-if="jobs.length" :job-id="job.id" :jobs="jobs" />
- </div>
- <job-retry-forward-deployment-modal
- v-if="shouldShowJobRetryForwardDeploymentModal"
- :modal-id="$options.forwardDeploymentFailureModalId"
- :href="job.retry_path"
- />
- </aside>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_detail_row.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar_detail_row.vue
deleted file mode 100644
index 0ba34eafa58..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_detail_row.vue
+++ /dev/null
@@ -1,59 +0,0 @@
-<script>
-import { GlIcon, GlLink } from '@gitlab/ui';
-
-export default {
- name: 'SidebarDetailRow',
- components: {
- GlIcon,
- GlLink,
- },
- props: {
- title: {
- type: String,
- required: false,
- default: '',
- },
- value: {
- type: String,
- required: true,
- },
- helpUrl: {
- type: String,
- required: false,
- default: '',
- },
- path: {
- type: String,
- required: false,
- default: '',
- },
- },
- computed: {
- hasTitle() {
- return this.title.length > 0;
- },
- hasHelpURL() {
- return this.helpUrl.length > 0;
- },
- },
-};
-</script>
-<template>
- <p class="gl-display-flex gl-justify-content-space-between gl-mb-2">
- <span v-if="hasTitle">
- <b>{{ title }}:</b>
- <gl-link
- v-if="path"
- :href="path"
- class="gl-text-blue-600!"
- data-testid="job-sidebar-value-link"
- >
- {{ value }}
- </gl-link>
- <span v-else>{{ value }}</span>
- </span>
- <gl-link v-if="hasHelpURL" :href="helpUrl" target="_blank" data-testid="job-sidebar-help-link">
- <gl-icon name="question-o" />
- </gl-link>
- </p>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue
deleted file mode 100644
index 56fcd8738d7..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue
+++ /dev/null
@@ -1,146 +0,0 @@
-<script>
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-// eslint-disable-next-line no-restricted-imports
-import { mapActions } from 'vuex';
-import { createAlert } from '~/alert';
-import { TYPENAME_COMMIT_STATUS } from '~/graphql_shared/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import {
- JOB_GRAPHQL_ERRORS,
- JOB_SIDEBAR_COPY,
- forwardDeploymentFailureModalId,
- PASSED_STATUS,
-} from '~/jobs/constants';
-import GetJob from '../graphql/queries/get_job.query.graphql';
-import JobSidebarRetryButton from './job_sidebar_retry_button.vue';
-
-export default {
- name: 'SidebarHeader',
- i18n: {
- ...JOB_SIDEBAR_COPY,
- },
- forwardDeploymentFailureModalId,
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- GlButton,
- JobSidebarRetryButton,
- TooltipOnTruncate,
- },
- inject: ['projectPath'],
- apollo: {
- job: {
- query: GetJob,
- variables() {
- return {
- fullPath: this.projectPath,
- id: convertToGraphQLId(TYPENAME_COMMIT_STATUS, this.jobId),
- };
- },
- update(data) {
- const { name, manualJob } = data?.project?.job || {};
- return {
- name,
- manualJob,
- };
- },
- error() {
- createAlert({ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText });
- },
- },
- },
- props: {
- jobId: {
- type: Number,
- required: true,
- },
- restJob: {
- type: Object,
- required: true,
- default: () => ({}),
- },
- },
- data() {
- return {
- job: {},
- };
- },
- computed: {
- buttonTitle() {
- return this.restJob.status?.text === PASSED_STATUS
- ? this.$options.i18n.runAgainJobButtonLabel
- : this.$options.i18n.retryJobLabel;
- },
- canShowJobRetryButton() {
- return this.restJob.retry_path && !this.$apollo.queries.job.loading;
- },
- isManualJob() {
- return this.job?.manualJob;
- },
- retryButtonCategory() {
- return this.restJob.status && this.restJob.recoverable ? 'primary' : 'secondary';
- },
- },
- methods: {
- ...mapActions(['toggleSidebar']),
- },
-};
-</script>
-
-<template>
- <div class="gl-py-5 gl-display-flex gl-align-items-center">
- <tooltip-on-truncate :title="job.name" truncate-target="child"
- ><h4 class="gl-my-0 gl-mr-3 gl-text-truncate" data-testid="job-name">{{ job.name }}</h4>
- </tooltip-on-truncate>
- <div class="gl-flex-grow-1 gl-flex-shrink-0 gl-text-right">
- <gl-button
- v-if="restJob.erase_path"
- v-gl-tooltip.left
- :title="$options.i18n.eraseLogButtonLabel"
- :aria-label="$options.i18n.eraseLogButtonLabel"
- :href="restJob.erase_path"
- :data-confirm="$options.i18n.eraseLogConfirmText"
- class="gl-mr-2"
- data-testid="job-log-erase-link"
- data-confirm-btn-variant="danger"
- data-method="post"
- icon="remove"
- />
- <job-sidebar-retry-button
- v-if="canShowJobRetryButton"
- v-gl-tooltip.left
- :title="buttonTitle"
- :aria-label="buttonTitle"
- :is-manual-job="isManualJob"
- :category="retryButtonCategory"
- :href="restJob.retry_path"
- :modal-id="$options.forwardDeploymentFailureModalId"
- variant="confirm"
- data-qa-selector="retry_button"
- data-testid="retry-button"
- @updateVariablesClicked="$emit('updateVariables')"
- />
- <gl-button
- v-if="restJob.cancel_path"
- v-gl-tooltip.left
- :title="$options.i18n.cancelJobButtonLabel"
- :aria-label="$options.i18n.cancelJobButtonLabel"
- :href="restJob.cancel_path"
- variant="danger"
- icon="cancel"
- data-method="post"
- data-testid="cancel-button"
- rel="nofollow"
- />
- <gl-button
- :aria-label="$options.i18n.toggleSidebar"
- category="tertiary"
- class="gl-md-display-none gl-ml-2"
- icon="chevron-double-lg-right"
- @click="toggleSidebar"
- />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_job_details_container.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar_job_details_container.vue
deleted file mode 100644
index 09335476008..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_job_details_container.vue
+++ /dev/null
@@ -1,124 +0,0 @@
-<script>
-// eslint-disable-next-line no-restricted-imports
-import { mapState } from 'vuex';
-import { GlBadge } from '@gitlab/ui';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
-import { __, sprintf } from '~/locale';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-import DetailRow from './sidebar_detail_row.vue';
-
-export default {
- name: 'JobSidebarDetailsContainer',
- components: {
- DetailRow,
- GlBadge,
- },
- mixins: [timeagoMixin],
- computed: {
- ...mapState(['job']),
- coverage() {
- return `${this.job.coverage}%`;
- },
- duration() {
- return timeIntervalInWords(this.job.duration);
- },
- durationTitle() {
- return this.job.finished_at ? __('Duration') : __('Elapsed time');
- },
- erasedAt() {
- return this.timeFormatted(this.job.erased_at);
- },
- finishedAt() {
- return this.timeFormatted(this.job.finished_at);
- },
- hasTags() {
- return this.job?.tags?.length;
- },
- hasTimeout() {
- return this.job?.metadata?.timeout_human_readable ?? false;
- },
- hasAnyDetail() {
- return Boolean(
- this.job.duration ||
- this.job.finished_at ||
- this.job.erased_at ||
- this.job.queued_duration ||
- this.job.runner ||
- this.job.coverage,
- );
- },
- runnerId() {
- const { id, short_sha: token, description } = this.job.runner;
-
- return `#${id} (${token}) ${description}`;
- },
- queuedDuration() {
- return timeIntervalInWords(this.job.queued_duration);
- },
- shouldRenderBlock() {
- return Boolean(this.hasAnyDetail || this.hasTimeout || this.hasTags);
- },
- timeout() {
- return `${this.job?.metadata?.timeout_human_readable}${this.timeoutSource}`;
- },
- timeoutSource() {
- if (!this.job?.metadata?.timeout_source) {
- return '';
- }
-
- return sprintf(__(' (from %{timeoutSource})'), {
- timeoutSource: this.job.metadata.timeout_source,
- });
- },
- runnerAdminPath() {
- return this.job?.runner?.admin_path || '';
- },
- },
- i18n: {
- COVERAGE: __('Coverage'),
- FINISHED: __('Finished'),
- ERASED: __('Erased'),
- QUEUED: __('Queued'),
- RUNNER: __('Runner'),
- TAGS: __('Tags:'),
- TIMEOUT: __('Timeout'),
- },
- TIMEOUT_HELP_URL: helpPagePath('/ci/pipelines/settings.md', {
- anchor: 'set-a-limit-for-how-long-jobs-can-run',
- }),
-};
-</script>
-
-<template>
- <div v-if="shouldRenderBlock">
- <detail-row v-if="job.duration" :value="duration" :title="durationTitle" />
- <detail-row
- v-if="job.finished_at"
- :value="finishedAt"
- data-testid="job-finished"
- :title="$options.i18n.FINISHED"
- />
- <detail-row v-if="job.erased_at" :value="erasedAt" :title="$options.i18n.ERASED" />
- <detail-row v-if="job.queued_duration" :value="queuedDuration" :title="$options.i18n.QUEUED" />
- <detail-row
- v-if="hasTimeout"
- :help-url="$options.TIMEOUT_HELP_URL"
- :value="timeout"
- data-testid="job-timeout"
- :title="$options.i18n.TIMEOUT"
- />
- <detail-row
- v-if="job.runner"
- :value="runnerId"
- :title="$options.i18n.RUNNER"
- :path="runnerAdminPath"
- />
- <detail-row v-if="job.coverage" :value="coverage" :title="$options.i18n.COVERAGE" />
-
- <p v-if="hasTags" class="build-detail-row" data-testid="job-tags">
- <span class="font-weight-bold">{{ $options.i18n.TAGS }}</span>
- <gl-badge v-for="(tag, i) in job.tags" :key="i" variant="info">{{ tag }}</gl-badge>
- </p>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue b/app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue
deleted file mode 100644
index c1f84adf664..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue
+++ /dev/null
@@ -1,171 +0,0 @@
-<script>
-import { GlLink, GlDisclosureDropdown, GlSprintf } from '@gitlab/ui';
-import { isEmpty } from 'lodash';
-import { Mousetrap } from '~/lib/mousetrap';
-import { s__ } from '~/locale';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import { clickCopyToClipboardButton } from '~/behaviors/copy_to_clipboard';
-import { keysFor, MR_COPY_SOURCE_BRANCH_NAME } from '~/behaviors/shortcuts/keybindings';
-
-export default {
- components: {
- CiIcon,
- ClipboardButton,
- GlDisclosureDropdown,
- GlLink,
- GlSprintf,
- },
- props: {
- pipeline: {
- type: Object,
- required: true,
- },
- stages: {
- type: Array,
- required: true,
- },
- selectedStage: {
- type: String,
- required: true,
- },
- },
- computed: {
- dropdownItems() {
- return this.stages.map((stage) => ({
- text: stage.name,
- action: () => {
- this.onStageClick(stage);
- },
- }));
- },
-
- hasRef() {
- return !isEmpty(this.pipeline.ref);
- },
- isTriggeredByMergeRequest() {
- return Boolean(this.pipeline.merge_request);
- },
- isMergeRequestPipeline() {
- return Boolean(this.pipeline.flags && this.pipeline.flags.merge_request_pipeline);
- },
- pipelineInfo() {
- if (!this.hasRef) {
- return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id}');
- } else if (!this.isTriggeredByMergeRequest) {
- return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}');
- } else if (!this.isMergeRequestPipeline) {
- return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source}');
- }
-
- return s__(
- 'Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into %{target}',
- );
- },
- },
- mounted() {
- Mousetrap.bind(keysFor(MR_COPY_SOURCE_BRANCH_NAME), this.handleKeyboardCopy);
- },
- beforeDestroy() {
- Mousetrap.unbind(keysFor(MR_COPY_SOURCE_BRANCH_NAME));
- },
- methods: {
- onStageClick(stage) {
- this.$emit('requestSidebarStageDropdown', stage);
- },
- handleKeyboardCopy() {
- let button;
-
- if (!this.hasRef) {
- return;
- } else if (!this.isTriggeredByMergeRequest) {
- button = this.$refs['copy-source-ref-link'];
- } else {
- button = this.$refs['copy-source-branch-link'];
- }
-
- clickCopyToClipboardButton(button.$el);
- },
- },
-};
-</script>
-<template>
- <div class="dropdown">
- <div class="js-pipeline-info" data-testid="pipeline-info">
- <ci-icon :status="pipeline.details.status" />
- <gl-sprintf :message="pipelineInfo">
- <template #bold="{ content }">
- <span class="font-weight-bold">{{ content }}</span>
- </template>
- <template #id>
- <gl-link
- :href="pipeline.path"
- class="js-pipeline-path link-commit"
- data-testid="pipeline-path"
- data-qa-selector="pipeline_path"
- >#{{ pipeline.id }}</gl-link
- >
- </template>
- <template #mrId>
- <gl-link
- :href="pipeline.merge_request.path"
- class="link-commit ref-name"
- data-testid="mr-link"
- >!{{ pipeline.merge_request.iid }}</gl-link
- >
- </template>
- <template #ref>
- <gl-link
- :href="pipeline.ref.path"
- class="link-commit ref-name"
- data-testid="source-ref-link"
- >{{ pipeline.ref.name }}</gl-link
- ><clipboard-button
- ref="copy-source-ref-link"
- :text="pipeline.ref.name"
- :title="__('Copy reference')"
- category="tertiary"
- size="small"
- data-testid="copy-source-ref-link"
- />
- </template>
- <template #source>
- <gl-link
- :href="pipeline.merge_request.source_branch_path"
- class="link-commit ref-name"
- data-testid="source-branch-link"
- >{{ pipeline.merge_request.source_branch }}</gl-link
- ><clipboard-button
- ref="copy-source-branch-link"
- :text="pipeline.merge_request.source_branch"
- :title="__('Copy branch name')"
- category="tertiary"
- size="small"
- data-testid="copy-source-branch-link"
- />
- </template>
- <template #target>
- <gl-link
- :href="pipeline.merge_request.target_branch_path"
- class="link-commit ref-name"
- data-testid="target-branch-link"
- >{{ pipeline.merge_request.target_branch }}</gl-link
- ><clipboard-button
- :text="pipeline.merge_request.target_branch"
- :title="__('Copy branch name')"
- category="tertiary"
- size="small"
- data-testid="copy-target-branch-link"
- />
- </template>
- </gl-sprintf>
- </div>
-
- <gl-disclosure-dropdown
- :toggle-text="selectedStage"
- :items="dropdownItems"
- block
- class="gl-mt-3"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue
deleted file mode 100644
index c9172fe0322..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue
+++ /dev/null
@@ -1,94 +0,0 @@
-<script>
-import { GlButton, GlTableLite } from '@gitlab/ui';
-import { __ } from '~/locale';
-
-const DEFAULT_TD_CLASSES = 'gl-font-sm!';
-
-export default {
- fields: [
- {
- key: 'key',
- label: __('Key'),
- tdAttr: { 'data-testid': 'trigger-build-key' },
- tdClass: DEFAULT_TD_CLASSES,
- },
- {
- key: 'value',
- label: __('Value'),
- tdAttr: { 'data-testid': 'trigger-build-value' },
- tdClass: DEFAULT_TD_CLASSES,
- },
- ],
- components: {
- GlButton,
- GlTableLite,
- },
- props: {
- trigger: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- showVariableValues: false,
- };
- },
- computed: {
- hasVariables() {
- return this.trigger.variables.length > 0;
- },
- getToggleButtonText() {
- return this.showVariableValues ? __('Hide values') : __('Reveal values');
- },
- hasValues() {
- return this.trigger.variables.some((v) => v.value);
- },
- },
- methods: {
- toggleValues() {
- this.showVariableValues = !this.showVariableValues;
- },
- getDisplayValue(value) {
- return this.showVariableValues ? value : '••••••';
- },
- },
-};
-</script>
-
-<template>
- <div>
- <p
- v-if="trigger.short_token"
- :class="{ 'gl-mb-2': hasVariables, 'gl-mb-0': !hasVariables }"
- data-testid="trigger-short-token"
- >
- <span class="gl-font-weight-bold">{{ __('Trigger token:') }}</span> {{ trigger.short_token }}
- </p>
-
- <template v-if="hasVariables">
- <p class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
- <span class="gl-font-weight-bold">{{ __('Trigger variables:') }}</span>
-
- <gl-button
- v-if="hasValues"
- class="gl-mt-2"
- size="small"
- data-testid="trigger-reveal-values-button"
- @click="toggleValues"
- >{{ getToggleButtonText }}</gl-button
- >
- </p>
-
- <gl-table-lite :items="trigger.variables" :fields="$options.fields" small bordered fixed>
- <template #cell(key)="{ item }">
- <span class="gl-overflow-break-word">{{ item.key }}</span>
- </template>
-
- <template #cell(value)="data">
- <span class="gl-overflow-break-word">{{ getDisplayValue(data.value) }}</span>
- </template>
- </gl-table-lite>
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/stuck_block.vue b/app/assets/javascripts/jobs/components/job/stuck_block.vue
deleted file mode 100644
index 1a678ce69a8..00000000000
--- a/app/assets/javascripts/jobs/components/job/stuck_block.vue
+++ /dev/null
@@ -1,90 +0,0 @@
-<script>
-import { GlAlert, GlBadge, GlLink, GlSprintf } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
-/**
- * Renders Stuck Runners block for job's view.
- */
-export default {
- components: {
- GlAlert,
- GlBadge,
- GlLink,
- GlSprintf,
- },
- props: {
- hasOfflineRunnersForProject: {
- type: Boolean,
- required: true,
- },
- tags: {
- type: Array,
- required: false,
- default: () => [],
- },
- runnersPath: {
- type: String,
- required: true,
- },
- },
- computed: {
- hasNoRunnersWithCorrespondingTags() {
- return this.tags.length > 0;
- },
- protectedBranchSettingsDocsLink() {
- return `${DOCS_URL}/runner/security/index.html#reduce-the-security-risk-of-using-privileged-containers`;
- },
- stuckData() {
- if (this.hasNoRunnersWithCorrespondingTags) {
- return {
- text: s__(
- `Job|This job is stuck because of one of the following problems. There are no active runners online, no runners for the %{linkStart}protected branch%{linkEnd}, or no runners that match all of the job's tags:`,
- ),
- dataTestId: 'job-stuck-with-tags',
- showTags: true,
- };
- } else if (this.hasOfflineRunnersForProject) {
- return {
- text: s__(`Job|This job is stuck because the project
- doesn't have any runners online assigned to it.`),
- dataTestId: 'job-stuck-no-runners',
- showTags: false,
- };
- }
-
- return {
- text: s__(`Job|This job is stuck because you don't
- have any active runners that can run this job.`),
- dataTestId: 'job-stuck-no-active-runners',
- showTags: false,
- };
- },
- },
-};
-</script>
-<template>
- <gl-alert variant="warning" :dismissible="false">
- <p class="gl-mb-0" :data-testid="stuckData.dataTestId">
- <gl-sprintf :message="stuckData.text">
- <template #link="{ content }">
- <a
- class="gl-display-inline-block"
- :href="protectedBranchSettingsDocsLink"
- target="_blank"
- >
- {{ content }}
- </a>
- </template>
- </gl-sprintf>
- <template v-if="stuckData.showTags">
- <gl-badge v-for="tag in tags" :key="tag" variant="info">
- {{ tag }}
- </gl-badge>
- </template>
- </p>
- {{ __('Go to project') }}
- <gl-link v-if="runnersPath" :href="runnersPath">
- {{ __('CI settings') }}
- </gl-link>
- </gl-alert>
-</template>
diff --git a/app/assets/javascripts/jobs/components/log/collapsible_section.vue b/app/assets/javascripts/jobs/components/log/collapsible_section.vue
deleted file mode 100644
index 13716b4d391..00000000000
--- a/app/assets/javascripts/jobs/components/log/collapsible_section.vue
+++ /dev/null
@@ -1,57 +0,0 @@
-<script>
-import LogLine from './line.vue';
-import LogLineHeader from './line_header.vue';
-
-export default {
- name: 'CollapsibleLogSection',
- components: {
- LogLine,
- LogLineHeader,
- },
- props: {
- section: {
- type: Object,
- required: true,
- },
- jobLogEndpoint: {
- type: String,
- required: true,
- },
- searchResults: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- computed: {
- badgeDuration() {
- return this.section.line && this.section.line.section_duration;
- },
- },
- methods: {
- handleOnClickCollapsibleLine(section) {
- this.$emit('onClickCollapsibleLine', section);
- },
- },
-};
-</script>
-<template>
- <div>
- <log-line-header
- :line="section.line"
- :duration="badgeDuration"
- :path="jobLogEndpoint"
- :is-closed="section.isClosed"
- @toggleLine="handleOnClickCollapsibleLine(section)"
- />
- <template v-if="!section.isClosed">
- <log-line
- v-for="line in section.lines"
- :key="line.offset"
- :line="line"
- :path="jobLogEndpoint"
- :search-results="searchResults"
- />
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/log/line.vue b/app/assets/javascripts/jobs/components/log/line.vue
deleted file mode 100644
index 3c9c5097122..00000000000
--- a/app/assets/javascripts/jobs/components/log/line.vue
+++ /dev/null
@@ -1,93 +0,0 @@
-<!-- eslint-disable vue/multi-word-component-names -->
-<script>
-import { getLocationHash } from '~/lib/utils/url_utility';
-import { linkRegex } from '../../utils';
-import LineNumber from './line_number.vue';
-
-export default {
- functional: true,
- props: {
- line: {
- type: Object,
- required: true,
- },
- path: {
- type: String,
- required: true,
- },
- searchResults: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- render(h, { props }) {
- const { line, path, searchResults } = props;
-
- const chars = line.content.map((content) => {
- return h(
- 'span',
- {
- class: ['gl-white-space-pre-wrap', content.style],
- },
- // Simple "tokenization": Split text in chunks of text
- // which alternate between text and urls.
- content.text.split(linkRegex).map((chunk) => {
- // Return normal string for non-links
- if (!chunk.match(linkRegex)) {
- return chunk;
- }
- return h(
- 'a',
- {
- attrs: {
- href: chunk,
- class: 'gl-reset-color! gl-text-decoration-underline',
- rel: 'nofollow noopener noreferrer', // eslint-disable-line @gitlab/require-i18n-strings
- },
- },
- chunk,
- );
- }),
- );
- });
-
- let applyHighlight = false;
-
- if (searchResults.length > 0) {
- const linesToHighlight = searchResults.map((searchResultLine) => searchResultLine.lineNumber);
-
- linesToHighlight.forEach((num) => {
- if (num === line.lineNumber) {
- applyHighlight = true;
- }
- });
- }
-
- if (window.location.hash) {
- const hash = getLocationHash();
- const lineToMatch = `L${line.lineNumber + 1}`;
-
- if (hash === lineToMatch) {
- applyHighlight = true;
- }
- }
-
- return h(
- 'div',
- {
- class: ['js-line', 'log-line', applyHighlight ? 'gl-bg-gray-700' : ''],
- },
- [
- h(LineNumber, {
- props: {
- lineNumber: line.lineNumber,
- path,
- },
- }),
- ...chars,
- ],
- );
- },
-};
-</script>
diff --git a/app/assets/javascripts/jobs/components/log/line_header.vue b/app/assets/javascripts/jobs/components/log/line_header.vue
deleted file mode 100644
index 115b090b32a..00000000000
--- a/app/assets/javascripts/jobs/components/log/line_header.vue
+++ /dev/null
@@ -1,69 +0,0 @@
-<script>
-import { GlIcon } from '@gitlab/ui';
-import { getLocationHash } from '~/lib/utils/url_utility';
-import DurationBadge from './duration_badge.vue';
-import LineNumber from './line_number.vue';
-
-export default {
- components: {
- GlIcon,
- LineNumber,
- DurationBadge,
- },
- props: {
- line: {
- type: Object,
- required: true,
- },
- isClosed: {
- type: Boolean,
- required: true,
- },
- path: {
- type: String,
- required: true,
- },
- duration: {
- type: String,
- required: false,
- default: '',
- },
- },
- computed: {
- iconName() {
- return this.isClosed ? 'chevron-lg-right' : 'chevron-lg-down';
- },
- applyHighlight() {
- const hash = getLocationHash();
- const lineToMatch = `L${this.line.lineNumber + 1}`;
-
- return hash === lineToMatch;
- },
- },
- methods: {
- handleOnClick() {
- this.$emit('toggleLine');
- },
- },
-};
-</script>
-
-<template>
- <div
- class="log-line collapsible-line d-flex justify-content-between ws-normal gl-align-items-flex-start"
- :class="{ 'gl-bg-gray-700': applyHighlight }"
- role="button"
- @click="handleOnClick"
- >
- <gl-icon :name="iconName" class="arrow position-absolute" />
- <line-number :line-number="line.lineNumber" :path="path" />
- <span
- v-for="(content, i) in line.content"
- :key="i"
- class="line-text w-100 gl-white-space-pre-wrap"
- :class="content.style"
- >{{ content.text }}</span
- >
- <duration-badge v-if="duration" :duration="duration" />
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/log/log.vue b/app/assets/javascripts/jobs/components/log/log.vue
deleted file mode 100644
index 6a1101bf297..00000000000
--- a/app/assets/javascripts/jobs/components/log/log.vue
+++ /dev/null
@@ -1,100 +0,0 @@
-<!-- eslint-disable vue/multi-word-component-names -->
-<script>
-// eslint-disable-next-line no-restricted-imports
-import { mapState, mapActions } from 'vuex';
-import { scrollToElement } from '~/lib/utils/common_utils';
-import { getLocationHash } from '~/lib/utils/url_utility';
-import CollapsibleLogSection from './collapsible_section.vue';
-import LogLine from './line.vue';
-
-export default {
- components: {
- CollapsibleLogSection,
- LogLine,
- },
- props: {
- searchResults: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- computed: {
- ...mapState([
- 'jobLogEndpoint',
- 'jobLog',
- 'isJobLogComplete',
- 'isScrolledToBottomBeforeReceivingJobLog',
- ]),
- },
- updated() {
- this.$nextTick(() => {
- if (!window.location.hash) {
- this.handleScrollDown();
- }
- });
- },
- mounted() {
- if (window.location.hash) {
- const lineNumber = getLocationHash();
-
- this.unwatchJobLog = this.$watch('jobLog', async () => {
- if (this.jobLog.length) {
- await this.$nextTick();
-
- const el = document.getElementById(lineNumber);
- scrollToElement(el);
- this.unwatchJobLog();
- }
- });
- }
- },
- methods: {
- ...mapActions(['toggleCollapsibleLine', 'scrollBottom']),
- handleOnClickCollapsibleLine(section) {
- this.toggleCollapsibleLine(section);
- },
- /**
- * The job log is sent in HTML, which means we need to use `v-html` to render it
- * Using the updated hook with $nextTick is not enough to wait for the DOM to be updated
- * in this case because it runs before `v-html` has finished running, since there's no
- * Vue binding.
- * In order to scroll the page down after `v-html` has finished, we need to use setTimeout
- */
- handleScrollDown() {
- if (this.isScrolledToBottomBeforeReceivingJobLog) {
- setTimeout(() => {
- this.scrollBottom();
- }, 0);
- }
- },
- },
-};
-</script>
-<template>
- <code class="job-log d-block" data-qa-selector="job_log_content">
- <template v-for="(section, index) in jobLog">
- <collapsible-log-section
- v-if="section.isHeader"
- :key="`collapsible-${index}`"
- :section="section"
- :job-log-endpoint="jobLogEndpoint"
- :search-results="searchResults"
- @onClickCollapsibleLine="handleOnClickCollapsibleLine"
- />
- <log-line
- v-else
- :key="section.offset"
- :line="section"
- :path="jobLogEndpoint"
- :search-results="searchResults"
- />
- </template>
-
- <div v-if="!isJobLogComplete" class="js-log-animation loader-animation pt-3 pl-3">
- <div class="dot"></div>
- <div class="dot"></div>
- <div class="dot"></div>
- </div>
- </code>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
deleted file mode 100644
index d97f6f6ff8c..00000000000
--- a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
+++ /dev/null
@@ -1,265 +0,0 @@
-<script>
-import {
- GlButton,
- GlButtonGroup,
- GlModal,
- GlModalDirective,
- GlSprintf,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import {
- ACTIONS_DOWNLOAD_ARTIFACTS,
- ACTIONS_START_NOW,
- ACTIONS_UNSCHEDULE,
- ACTIONS_PLAY,
- ACTIONS_RETRY,
- ACTIONS_RUN_AGAIN,
- CANCEL,
- GENERIC_ERROR,
- JOB_SCHEDULED,
- JOB_SUCCESS,
- PLAY_JOB_CONFIRMATION_MESSAGE,
- RUN_JOB_NOW_HEADER_TITLE,
- FILE_TYPE_ARCHIVE,
-} from '../constants';
-import eventHub from '../event_hub';
-import cancelJobMutation from '../graphql/mutations/job_cancel.mutation.graphql';
-import playJobMutation from '../graphql/mutations/job_play.mutation.graphql';
-import retryJobMutation from '../graphql/mutations/job_retry.mutation.graphql';
-import unscheduleJobMutation from '../graphql/mutations/job_unschedule.mutation.graphql';
-import { reportMessageToSentry } from '../../../utils';
-
-export default {
- ACTIONS_DOWNLOAD_ARTIFACTS,
- ACTIONS_START_NOW,
- ACTIONS_UNSCHEDULE,
- ACTIONS_PLAY,
- ACTIONS_RETRY,
- CANCEL,
- GENERIC_ERROR,
- PLAY_JOB_CONFIRMATION_MESSAGE,
- RUN_JOB_NOW_HEADER_TITLE,
- jobRetry: 'jobRetry',
- jobCancel: 'jobCancel',
- jobPlay: 'jobPlay',
- jobUnschedule: 'jobUnschedule',
- playJobModalId: 'play-job-modal',
- name: 'JobActionsCell',
- components: {
- GlButton,
- GlButtonGroup,
- GlCountdown,
- GlModal,
- GlSprintf,
- },
- directives: {
- GlModalDirective,
- GlTooltip: GlTooltipDirective,
- },
- inject: {
- admin: {
- default: false,
- },
- },
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- retryBtnDisabled: false,
- cancelBtnDisabled: false,
- playManualBtnDisabled: false,
- unscheduleBtnDisabled: false,
- };
- },
- computed: {
- hasArtifacts() {
- return this.job.artifacts.nodes.find((artifact) => artifact.fileType === FILE_TYPE_ARCHIVE);
- },
- artifactDownloadPath() {
- return this.hasArtifacts.downloadPath;
- },
- canReadJob() {
- return this.job.userPermissions?.readBuild;
- },
- canUpdateJob() {
- return this.job.userPermissions?.updateBuild;
- },
- canReadArtifacts() {
- return this.job.userPermissions?.readJobArtifacts;
- },
- isActive() {
- return this.job.active;
- },
- manualJobPlayable() {
- return this.job.playable && !this.admin && this.job.manualJob;
- },
- isRetryable() {
- return this.job.retryable;
- },
- isScheduled() {
- return this.job.status === JOB_SCHEDULED;
- },
- scheduledAt() {
- return this.job.scheduledAt;
- },
- currentJobActionPath() {
- return this.job.detailedStatus?.action?.path;
- },
- currentJobMethod() {
- return this.job.detailedStatus?.action?.method;
- },
- shouldDisplayArtifacts() {
- return this.canReadArtifacts && this.hasArtifacts;
- },
- retryButtonTitle() {
- return this.job.status === JOB_SUCCESS ? ACTIONS_RUN_AGAIN : ACTIONS_RETRY;
- },
- },
- methods: {
- async postJobAction(name, mutation, redirect = false) {
- try {
- const {
- data: {
- [name]: { errors, job },
- },
- } = await this.$apollo.mutate({
- mutation,
- variables: { id: this.job.id },
- });
- if (errors.length > 0) {
- reportMessageToSentry(this.$options.name, errors.join(', '), {});
- this.showToastMessage();
- } else if (redirect) {
- // Retry and Play actions redirect to job detail view
- // we don't need to refetch with jobActionPerformed event
- redirectTo(job.detailedStatus.detailsPath); // eslint-disable-line import/no-deprecated
- } else {
- eventHub.$emit('jobActionPerformed');
- }
- } catch (failure) {
- reportMessageToSentry(this.$options.name, failure, {});
- this.showToastMessage();
- }
- },
- showToastMessage() {
- const toastProps = {
- text: this.$options.GENERIC_ERROR,
- variant: 'danger',
- };
-
- this.$toast.show(toastProps.text, {
- variant: toastProps.variant,
- });
- },
- cancelJob() {
- this.cancelBtnDisabled = true;
-
- this.postJobAction(this.$options.jobCancel, cancelJobMutation);
- },
- retryJob() {
- this.retryBtnDisabled = true;
-
- this.postJobAction(this.$options.jobRetry, retryJobMutation, true);
- },
- playJob() {
- this.playManualBtnDisabled = true;
-
- this.postJobAction(this.$options.jobPlay, playJobMutation, true);
- },
- unscheduleJob() {
- this.unscheduleBtnDisabled = true;
-
- this.postJobAction(this.$options.jobUnschedule, unscheduleJobMutation);
- },
- },
-};
-</script>
-
-<template>
- <gl-button-group>
- <template v-if="canReadJob && canUpdateJob">
- <gl-button
- v-if="isActive"
- v-gl-tooltip
- icon="cancel"
- :title="$options.CANCEL"
- :aria-label="$options.CANCEL"
- :disabled="cancelBtnDisabled"
- data-testid="cancel-button"
- @click="cancelJob()"
- />
- <template v-else-if="isScheduled">
- <gl-button icon="planning" disabled data-testid="countdown">
- <gl-countdown :end-date-string="scheduledAt" />
- </gl-button>
- <gl-button
- v-gl-modal-directive="$options.playJobModalId"
- v-gl-tooltip
- icon="play"
- :title="$options.ACTIONS_START_NOW"
- :aria-label="$options.ACTIONS_START_NOW"
- data-testid="play-scheduled"
- />
- <gl-modal
- :modal-id="$options.playJobModalId"
- :title="$options.RUN_JOB_NOW_HEADER_TITLE"
- @primary="playJob()"
- >
- <gl-sprintf :message="$options.PLAY_JOB_CONFIRMATION_MESSAGE">
- <template #job_name>{{ job.name }}</template>
- </gl-sprintf>
- </gl-modal>
- <gl-button
- v-gl-tooltip
- icon="time-out"
- :title="$options.ACTIONS_UNSCHEDULE"
- :aria-label="$options.ACTIONS_UNSCHEDULE"
- :disabled="unscheduleBtnDisabled"
- data-testid="unschedule"
- @click="unscheduleJob()"
- />
- </template>
- <template v-else>
- <!--Note: This is the manual job play button -->
- <gl-button
- v-if="manualJobPlayable"
- v-gl-tooltip
- icon="play"
- :title="$options.ACTIONS_PLAY"
- :aria-label="$options.ACTIONS_PLAY"
- :disabled="playManualBtnDisabled"
- data-testid="play"
- @click="playJob()"
- />
- <gl-button
- v-else-if="isRetryable"
- v-gl-tooltip
- icon="retry"
- :title="retryButtonTitle"
- :aria-label="retryButtonTitle"
- :method="currentJobMethod"
- :disabled="retryBtnDisabled"
- data-testid="retry"
- @click="retryJob()"
- />
- </template>
- </template>
- <gl-button
- v-if="shouldDisplayArtifacts"
- v-gl-tooltip
- icon="download"
- :title="$options.ACTIONS_DOWNLOAD_ARTIFACTS"
- :aria-label="$options.ACTIONS_DOWNLOAD_ARTIFACTS"
- :href="artifactDownloadPath"
- rel="nofollow"
- download
- data-testid="download-artifacts"
- />
- </gl-button-group>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue b/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue
deleted file mode 100644
index 11593fa355a..00000000000
--- a/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue
+++ /dev/null
@@ -1,45 +0,0 @@
-<script>
-import { GlIcon } from '@gitlab/ui';
-import { formatTime } from '~/lib/utils/datetime_utility';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-
-export default {
- iconSize: 12,
- components: {
- GlIcon,
- TimeAgoTooltip,
- },
- mixins: [timeagoMixin],
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- computed: {
- finishedTime() {
- return this.job?.finishedAt;
- },
- duration() {
- return this.job?.duration;
- },
- durationFormatted() {
- return formatTime(this.duration * 1000);
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div v-if="duration" data-testid="job-duration">
- <gl-icon name="timer" :size="$options.iconSize" data-testid="duration-icon" />
- {{ durationFormatted }}
- </div>
- <div v-if="finishedTime" data-testid="job-finished-time">
- <gl-icon name="calendar" :size="$options.iconSize" data-testid="finished-time-icon" />
- <time-ago-tooltip :time="finishedTime" />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/cells/job_cell.vue b/app/assets/javascripts/jobs/components/table/cells/job_cell.vue
deleted file mode 100644
index 27d286fc766..00000000000
--- a/app/assets/javascripts/jobs/components/table/cells/job_cell.vue
+++ /dev/null
@@ -1,171 +0,0 @@
-<script>
-import { GlBadge, GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { s__ } from '~/locale';
-import { SUCCESS_STATUS } from '../../../constants';
-
-export default {
- iconSize: 12,
- badgeSize: 'sm',
- i18n: {
- stuckText: s__('Jobs|Job is stuck. Check runners.'),
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- GlBadge,
- GlIcon,
- GlLink,
- },
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- computed: {
- jobId() {
- const id = getIdFromGraphQLId(this.job.id);
- return `#${id}`;
- },
- jobPath() {
- return this.job.detailedStatus?.detailsPath;
- },
- jobRef() {
- return this.job?.refName;
- },
- jobRefPath() {
- return this.job?.refPath;
- },
- jobTags() {
- return this.job.tags;
- },
- createdByTag() {
- return this.job.createdByTag;
- },
- triggered() {
- return this.job.triggered;
- },
- isManualJob() {
- return this.job.manualJob;
- },
- successfulJob() {
- return this.job.status === SUCCESS_STATUS;
- },
- showAllowedToFailBadge() {
- return this.job.allowFailure && !this.successfulJob;
- },
- isScheduledJob() {
- return Boolean(this.job.scheduledAt);
- },
- canReadJob() {
- return this.job?.userPermissions?.readBuild;
- },
- jobStuck() {
- return this.job?.stuck;
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div class="gl-text-truncate gl-mb-2">
- <gl-link
- v-if="canReadJob"
- class="gl-text-blue-600!"
- :href="jobPath"
- data-testid="job-id-link"
- >
- {{ jobId }}
- </gl-link>
-
- <span v-else data-testid="job-id-limited-access">{{ jobId }}</span>
-
- <gl-icon
- v-if="jobStuck"
- v-gl-tooltip="$options.i18n.stuckText"
- name="warning"
- :size="$options.iconSize"
- data-testid="stuck-icon"
- />
-
- <div
- class="gl-display-flex gl-text-gray-700 gl-align-items-center gl-lg-justify-content-start gl-justify-content-end gl-mt-2"
- >
- <div
- v-if="jobRef"
- class="gl-px-2 gl-rounded-base gl-bg-gray-50 gl-max-w-15 gl-text-truncate"
- >
- <gl-icon
- v-if="createdByTag"
- name="label"
- :size="$options.iconSize"
- data-testid="label-icon"
- />
- <gl-icon v-else name="fork" :size="$options.iconSize" data-testid="fork-icon" />
- <gl-link
- class="gl-font-sm gl-font-monospace gl-text-gray-700 gl-hover-text-gray-900"
- :href="job.refPath"
- data-testid="job-ref"
- >{{ job.refName }}</gl-link
- >
- </div>
-
- <span v-else>{{ __('none') }}</span>
- <div class="gl-ml-2 gl-rounded-base gl-px-2 gl-bg-gray-50">
- <gl-icon class="gl-mx-2" name="commit" :size="$options.iconSize" />
- <gl-link
- class="gl-font-sm gl-font-monospace gl-text-gray-700 gl-hover-text-gray-900"
- :href="job.commitPath"
- data-testid="job-sha"
- >{{ job.shortSha }}</gl-link
- >
- </div>
- </div>
- </div>
-
- <div>
- <gl-badge
- v-for="tag in jobTags"
- :key="tag"
- variant="info"
- :size="$options.badgeSize"
- data-testid="job-tag-badge"
- >
- {{ tag }}
- </gl-badge>
-
- <gl-badge
- v-if="triggered"
- variant="info"
- :size="$options.badgeSize"
- data-testid="triggered-job-badge"
- >{{ s__('Job|triggered') }}
- </gl-badge>
- <gl-badge
- v-if="showAllowedToFailBadge"
- variant="warning"
- :size="$options.badgeSize"
- data-testid="fail-job-badge"
- >{{ s__('Job|allowed to fail') }}
- </gl-badge>
- <gl-badge
- v-if="isScheduledJob"
- variant="info"
- :size="$options.badgeSize"
- data-testid="delayed-job-badge"
- >{{ s__('Job|delayed') }}
- </gl-badge>
- <gl-badge
- v-if="isManualJob"
- variant="info"
- :size="$options.badgeSize"
- data-testid="manual-job-badge"
- >
- {{ s__('Job|manual') }}
- </gl-badge>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue b/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue
deleted file mode 100644
index 1a6d1a341b0..00000000000
--- a/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue
+++ /dev/null
@@ -1,52 +0,0 @@
-<script>
-import { GlAvatar, GlLink } from '@gitlab/ui';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-
-export default {
- components: {
- GlAvatar,
- GlLink,
- },
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- computed: {
- pipelineId() {
- const id = getIdFromGraphQLId(this.job.pipeline.id);
- return `#${id}`;
- },
- pipelinePath() {
- return this.job.pipeline?.path;
- },
- pipelineUserAvatar() {
- return this.job.pipeline?.user?.avatarUrl;
- },
- userPath() {
- return this.job.pipeline?.user?.webPath;
- },
- showAvatar() {
- return this.job.pipeline?.user;
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div class="gl-text-truncate">
- <gl-link class="gl-text-gray-500!" :href="pipelinePath" data-testid="pipeline-id">
- {{ pipelineId }}
- </gl-link>
- </div>
- <div>
- <span>{{ __('created by') }}</span>
- <gl-link v-if="showAvatar" :href="userPath" data-testid="pipeline-user-link">
- <gl-avatar :src="pipelineUserAvatar" :size="16" />
- </gl-link>
- <span v-else>{{ __('API') }}</span>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/index.js b/app/assets/javascripts/jobs/components/table/index.js
deleted file mode 100644
index 88da1169e01..00000000000
--- a/app/assets/javascripts/jobs/components/table/index.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { GlToast } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue';
-import createDefaultClient from '~/lib/graphql';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import cacheConfig from './graphql/cache_config';
-
-Vue.use(VueApollo);
-Vue.use(GlToast);
-
-const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(
- {},
- {
- cacheConfig,
- },
- ),
-});
-
-export default (containerId = 'js-jobs-table') => {
- const containerEl = document.getElementById(containerId);
-
- if (!containerEl) {
- return false;
- }
-
- const {
- fullPath,
- jobStatuses,
- pipelineEditorPath,
- emptyStateSvgPath,
- admin,
- } = containerEl.dataset;
-
- return new Vue({
- el: containerEl,
- apolloProvider,
- provide: {
- emptyStateSvgPath,
- fullPath,
- pipelineEditorPath,
- jobStatuses: JSON.parse(jobStatuses),
- admin: parseBoolean(admin),
- },
- render(createElement) {
- return createElement(JobsTableApp);
- },
- });
-};
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table.vue b/app/assets/javascripts/jobs/components/table/jobs_table.vue
deleted file mode 100644
index 84479ec421e..00000000000
--- a/app/assets/javascripts/jobs/components/table/jobs_table.vue
+++ /dev/null
@@ -1,112 +0,0 @@
-<script>
-import { GlTable } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import ProjectCell from '~/pages/admin/jobs/components/table/cell/project_cell.vue';
-import RunnerCell from '~/pages/admin/jobs/components/table/cells/runner_cell.vue';
-import ActionsCell from './cells/actions_cell.vue';
-import DurationCell from './cells/duration_cell.vue';
-import JobCell from './cells/job_cell.vue';
-import PipelineCell from './cells/pipeline_cell.vue';
-import { DEFAULT_FIELDS } from './constants';
-
-export default {
- i18n: {
- emptyText: s__('Jobs|No jobs to show'),
- },
- components: {
- ActionsCell,
- CiBadgeLink,
- DurationCell,
- GlTable,
- JobCell,
- PipelineCell,
- ProjectCell,
- RunnerCell,
- },
- props: {
- jobs: {
- type: Array,
- required: true,
- },
- tableFields: {
- type: Array,
- required: false,
- default: () => DEFAULT_FIELDS,
- },
- admin: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- methods: {
- formatCoverage(coverage) {
- return coverage ? `${coverage}%` : '';
- },
- },
-};
-</script>
-
-<template>
- <gl-table
- :items="jobs"
- :fields="tableFields"
- :tbody-tr-attr="{ 'data-testid': 'jobs-table-row' }"
- :empty-text="$options.i18n.emptyText"
- data-testid="jobs-table"
- show-empty
- stacked="lg"
- fixed
- >
- <template #table-colgroup="{ fields }">
- <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
- </template>
-
- <template #cell(status)="{ item }">
- <ci-badge-link :status="item.detailedStatus" />
- </template>
-
- <template #cell(job)="{ item }">
- <job-cell :job="item" />
- </template>
-
- <template #cell(pipeline)="{ item }">
- <pipeline-cell :job="item" />
- </template>
-
- <template v-if="admin" #cell(project)="{ item }">
- <project-cell :job="item" />
- </template>
-
- <template v-if="admin" #cell(runner)="{ item }">
- <runner-cell :job="item" />
- </template>
-
- <template #cell(stage)="{ item }">
- <div class="gl-text-truncate">
- <span data-testid="job-stage-name">{{ item.stage.name }}</span>
- </div>
- </template>
-
- <template #cell(name)="{ item }">
- <div class="gl-text-truncate">
- <span data-testid="job-name">{{ item.name }}</span>
- </div>
- </template>
-
- <template #cell(duration)="{ item }">
- <duration-cell :job="item" />
- </template>
-
- <template #cell(coverage)="{ item }">
- <span v-if="item.coverage" data-testid="job-coverage">{{
- formatCoverage(item.coverage)
- }}</span>
- </template>
-
- <template #cell(actions)="{ item }">
- <actions-cell class="gl-float-right" :job="item" />
- </template>
- </gl-table>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
deleted file mode 100644
index 09fa006cb88..00000000000
--- a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
+++ /dev/null
@@ -1,238 +0,0 @@
-<script>
-import { GlAlert, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
-import { __ } from '~/locale';
-import { createAlert } from '~/alert';
-import { setUrlParams, updateHistory, queryToObject } from '~/lib/utils/url_utility';
-import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
-import JobsFilteredSearch from '../filtered_search/jobs_filtered_search.vue';
-import { validateQueryString } from '../filtered_search/utils';
-import GetJobs from './graphql/queries/get_jobs.query.graphql';
-import GetJobsCount from './graphql/queries/get_jobs_count.query.graphql';
-import JobsTable from './jobs_table.vue';
-import JobsTableEmptyState from './jobs_table_empty_state.vue';
-import JobsTableTabs from './jobs_table_tabs.vue';
-import { RAW_TEXT_WARNING } from './constants';
-
-export default {
- i18n: {
- jobsFetchErrorMsg: __('There was an error fetching the jobs for your project.'),
- jobsCountErrorMsg: __('There was an error fetching the number of jobs for your project.'),
- loadingAriaLabel: __('Loading'),
- },
- filterSearchBoxStyles:
- 'gl-my-0 gl-p-5 gl-bg-gray-10 gl-text-gray-900 gl-border-b gl-border-gray-100',
- components: {
- GlAlert,
- JobsFilteredSearch,
- JobsTable,
- JobsTableEmptyState,
- JobsTableTabs,
- GlIntersectionObserver,
- GlLoadingIcon,
- JobsSkeletonLoader,
- },
- inject: {
- fullPath: {
- default: '',
- },
- },
- apollo: {
- jobs: {
- query: GetJobs,
- variables() {
- return {
- fullPath: this.fullPath,
- ...this.validatedQueryString,
- };
- },
- update(data) {
- const { jobs: { nodes: list = [], pageInfo = {} } = {} } = data.project || {};
- return {
- list,
- pageInfo,
- };
- },
- error() {
- this.error = this.$options.i18n.jobsFetchErrorMsg;
- },
- },
- jobsCount: {
- query: GetJobsCount,
- context: {
- isSingleRequest: true,
- },
- variables() {
- return {
- fullPath: this.fullPath,
- ...this.validatedQueryString,
- };
- },
- update({ project }) {
- return project?.jobs?.count || 0;
- },
- error() {
- this.error = this.$options.i18n.jobsCountErrorMsg;
- },
- },
- },
- data() {
- return {
- jobs: {
- list: [],
- },
- error: '',
- scope: null,
- infiniteScrollingTriggered: false,
- filterSearchTriggered: false,
- jobsCount: null,
- count: 0,
- };
- },
- computed: {
- loading() {
- return this.$apollo.queries.jobs.loading;
- },
- // Show when on All tab with no jobs
- // Show only when not loading and filtered search has not been triggered
- // So we don't show empty state when results are empty on a filtered search
- showEmptyState() {
- return (
- this.jobs.list.length === 0 && !this.scope && !this.loading && !this.filterSearchTriggered
- );
- },
- hasNextPage() {
- return this.jobs?.pageInfo?.hasNextPage;
- },
- showLoadingSpinner() {
- return this.loading && this.infiniteScrollingTriggered;
- },
- showSkeletonLoader() {
- return this.loading && !this.showLoadingSpinner;
- },
- showFilteredSearch() {
- return !this.scope;
- },
- validatedQueryString() {
- const queryStringObject = queryToObject(window.location.search);
-
- return validateQueryString(queryStringObject);
- },
- },
- watch: {
- // this watcher ensures that the count on the all tab
- // is not updated when switching to the finished tab
- jobsCount(newCount, oldCount) {
- if (this.scope) {
- this.count = oldCount;
- } else {
- this.count = newCount;
- }
- },
- },
- methods: {
- updateHistoryAndFetchCount(status = null) {
- this.$apollo.queries.jobsCount.refetch({ statuses: status });
-
- updateHistory({
- url: setUrlParams({ statuses: status }, window.location.href, true),
- });
- },
- fetchJobsByStatus(scope) {
- this.infiniteScrollingTriggered = false;
-
- if (this.scope === scope) return;
-
- this.scope = scope;
-
- if (!this.scope) this.updateHistoryAndFetchCount();
-
- this.$apollo.queries.jobs.refetch({ statuses: scope });
- },
- filterJobsBySearch(filters) {
- this.infiniteScrollingTriggered = false;
- this.filterSearchTriggered = true;
-
- // all filters have been cleared reset query param
- // and refetch jobs/count with defaults
- if (!filters.length) {
- this.updateHistoryAndFetchCount();
- this.$apollo.queries.jobs.refetch({ statuses: null });
-
- return;
- }
-
- // Eventually there will be more tokens available
- // this code is written to scale for those tokens
- filters.forEach((filter) => {
- // Raw text input in filtered search does not have a type
- // when a user enters raw text we alert them that it is
- // not supported and we do not make an additional API call
- if (!filter.type) {
- createAlert({
- message: RAW_TEXT_WARNING,
- type: 'warning',
- });
- }
-
- if (filter.type === 'status') {
- this.updateHistoryAndFetchCount(filter.value.data);
- this.$apollo.queries.jobs.refetch({ statuses: filter.value.data });
- }
- });
- },
- fetchMoreJobs() {
- if (!this.loading) {
- this.infiniteScrollingTriggered = true;
-
- this.$apollo.queries.jobs.fetchMore({
- variables: {
- fullPath: this.fullPath,
- after: this.jobs?.pageInfo?.endCursor,
- },
- });
- }
- },
- },
-};
-</script>
-
-<template>
- <div>
- <gl-alert
- v-if="error"
- class="gl-mt-2"
- variant="danger"
- data-testid="jobs-table-error-alert"
- dismissible
- @dismiss="error = ''"
- >
- {{ error }}
- </gl-alert>
-
- <jobs-table-tabs
- :all-jobs-count="count"
- :loading="loading"
- @fetchJobsByStatus="fetchJobsByStatus"
- />
- <div v-if="showFilteredSearch" :class="$options.filterSearchBoxStyles">
- <jobs-filtered-search
- :query-string="validatedQueryString"
- @filterJobsBySearch="filterJobsBySearch"
- />
- </div>
-
- <jobs-skeleton-loader v-if="showSkeletonLoader" class="gl-mt-5" />
-
- <jobs-table-empty-state v-else-if="showEmptyState" />
-
- <jobs-table v-else :jobs="jobs.list" class="gl-table-no-top-border" />
-
- <gl-intersection-observer v-if="hasNextPage" @appear="fetchMoreJobs">
- <gl-loading-icon
- v-if="showLoadingSpinner"
- size="lg"
- :aria-label="$options.i18n.loadingAriaLabel"
- />
- </gl-intersection-observer>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_empty_state.vue b/app/assets/javascripts/jobs/components/table/jobs_table_empty_state.vue
deleted file mode 100644
index fcdd52b719c..00000000000
--- a/app/assets/javascripts/jobs/components/table/jobs_table_empty_state.vue
+++ /dev/null
@@ -1,35 +0,0 @@
-<script>
-import { GlEmptyState } from '@gitlab/ui';
-import { s__ } from '~/locale';
-
-export default {
- i18n: {
- title: s__('Jobs|Use jobs to automate your tasks'),
- description: s__(
- 'Jobs|Jobs are the building blocks of a GitLab CI/CD pipeline. Each job has a specific task, like testing code. To set up jobs in a CI/CD pipeline, add a CI/CD configuration file to your project.',
- ),
- buttonText: s__('Jobs|Create CI/CD configuration file'),
- },
- components: {
- GlEmptyState,
- },
- inject: {
- pipelineEditorPath: {
- default: '',
- },
- emptyStateSvgPath: {
- default: '',
- },
- },
-};
-</script>
-
-<template>
- <gl-empty-state
- :title="$options.i18n.title"
- :description="$options.i18n.description"
- :svg-path="emptyStateSvgPath"
- :primary-button-link="pipelineEditorPath"
- :primary-button-text="$options.i18n.buttonText"
- />
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_tabs.vue b/app/assets/javascripts/jobs/components/table/jobs_table_tabs.vue
deleted file mode 100644
index 797facb1eb8..00000000000
--- a/app/assets/javascripts/jobs/components/table/jobs_table_tabs.vue
+++ /dev/null
@@ -1,88 +0,0 @@
-<script>
-import { GlBadge, GlTab, GlTabs, GlLoadingIcon } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import CancelJobs from '~/pages/admin/jobs/components/cancel_jobs.vue';
-import { limitedCounterWithDelimiter } from '~/lib/utils/text_utility';
-
-export default {
- components: {
- GlBadge,
- GlTab,
- GlTabs,
- GlLoadingIcon,
- CancelJobs,
- },
- inject: {
- jobStatuses: {
- default: {},
- },
- url: {
- type: String,
- default: '',
- },
- },
- props: {
- allJobsCount: {
- type: Number,
- required: true,
- },
- loading: {
- type: Boolean,
- required: true,
- },
- showCancelAllJobsButton: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- computed: {
- tabs() {
- return [
- {
- text: s__('Jobs|All'),
- count: limitedCounterWithDelimiter(this.allJobsCount),
- scope: null,
- testId: 'jobs-all-tab',
- showBadge: true,
- },
- {
- text: s__('Jobs|Finished'),
- scope: [this.jobStatuses.success, this.jobStatuses.failed, this.jobStatuses.canceled],
- testId: 'jobs-finished-tab',
- showBadge: false,
- },
- ];
- },
- showLoadingIcon() {
- return this.loading && !this.allJobsCount;
- },
- },
-};
-</script>
-
-<template>
- <div class="gl-display-flex align-items-lg-center">
- <gl-tabs content-class="gl-py-0">
- <gl-tab
- v-for="tab in tabs"
- :key="tab.text"
- :title-link-attributes="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ {
- 'data-testid': tab.testId,
- } /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
- @click="$emit('fetchJobsByStatus', tab.scope)"
- >
- <template #title>
- <span>{{ tab.text }}</span>
- <gl-loading-icon v-if="showLoadingIcon && tab.showBadge" class="gl-ml-2" />
-
- <gl-badge v-else-if="tab.showBadge" size="sm" class="gl-tab-counter-badge">
- {{ tab.count }}
- </gl-badge>
- </template>
- </gl-tab>
- </gl-tabs>
- <div class="gl-flex-grow-1"></div>
- <cancel-jobs v-if="showCancelAllJobsButton" :url="url" />
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/constants.js b/app/assets/javascripts/jobs/constants.js
deleted file mode 100644
index 40b3de7edd9..00000000000
--- a/app/assets/javascripts/jobs/constants.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import { __, s__ } from '~/locale';
-
-const cancel = __('Cancel');
-const moreInfo = __('More information');
-
-export const forwardDeploymentFailureModalId = 'forward-deployment-failure';
-
-export const JOB_SIDEBAR_COPY = {
- cancel,
- cancelJobButtonLabel: s__('Job|Cancel'),
- debug: __('Debug'),
- eraseLogButtonLabel: s__('Job|Erase job log and artifacts'),
- eraseLogConfirmText: s__('Job|Are you sure you want to erase this job log and artifacts?'),
- newIssue: __('New issue'),
- retryJobLabel: s__('Job|Retry'),
- toggleSidebar: __('Toggle Sidebar'),
- runAgainJobButtonLabel: s__('Job|Run again'),
- updateVariables: s__('Job|Update CI/CD variables'),
-};
-
-export const JOB_GRAPHQL_ERRORS = {
- jobMutationErrorText: __('There was an error running the job. Please try again.'),
- jobQueryErrorText: __('There was an error fetching the job.'),
-};
-
-export const JOB_RETRY_FORWARD_DEPLOYMENT_MODAL = {
- cancel,
- info: s__(
- `Jobs|You're about to retry a job that failed because it attempted to deploy code that is older than the latest deployment.
- Retrying this job could result in overwriting the environment with the older source code.`,
- ),
- areYouSure: s__('Jobs|Are you sure you want to proceed?'),
- moreInfo,
- primaryText: __('Retry job'),
- title: s__('Jobs|Are you sure you want to retry this job?'),
-};
-
-export const SUCCESS_STATUS = 'SUCCESS';
-export const PASSED_STATUS = 'passed';
-export const MANUAL_STATUS = 'manual';
diff --git a/app/assets/javascripts/jobs/index.js b/app/assets/javascripts/jobs/index.js
deleted file mode 100644
index 8cd69f25218..00000000000
--- a/app/assets/javascripts/jobs/index.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import { GlToast } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createDefaultClient from '~/lib/graphql';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import JobApp from './components/job/job_app.vue';
-import createStore from './store';
-
-Vue.use(VueApollo);
-Vue.use(GlToast);
-
-const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
-});
-
-const initializeJobPage = (element) => {
- const store = createStore();
-
- // Let's start initializing the store (i.e. fetching data) right away
- store.dispatch('init', element.dataset);
-
- const {
- artifactHelpUrl,
- deploymentHelpUrl,
- runnerSettingsUrl,
- subscriptionsMoreMinutesUrl,
- endpoint,
- pagePath,
- logState,
- buildStatus,
- projectPath,
- retryOutdatedJobDocsUrl,
- aiRootCauseAnalysisAvailable,
- } = element.dataset;
-
- return new Vue({
- el: element,
- apolloProvider,
- store,
- components: {
- JobApp,
- },
- provide: {
- projectPath,
- retryOutdatedJobDocsUrl,
- aiRootCauseAnalysisAvailable: parseBoolean(aiRootCauseAnalysisAvailable),
- },
- render(createElement) {
- return createElement('job-app', {
- props: {
- artifactHelpUrl,
- deploymentHelpUrl,
- runnerSettingsUrl,
- subscriptionsMoreMinutesUrl,
- endpoint,
- pagePath,
- logState,
- buildStatus,
- projectPath,
- },
- });
- },
- });
-};
-
-export default () => {
- const jobElement = document.getElementById('js-job-page');
- initializeJobPage(jobElement);
-};
diff --git a/app/assets/javascripts/jobs/store/actions.js b/app/assets/javascripts/jobs/store/actions.js
deleted file mode 100644
index b348478ccda..00000000000
--- a/app/assets/javascripts/jobs/store/actions.js
+++ /dev/null
@@ -1,277 +0,0 @@
-import Visibility from 'visibilityjs';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { setFaviconOverlay, resetFavicon } from '~/lib/utils/favicon';
-import { HTTP_STATUS_FORBIDDEN } from '~/lib/utils/http_status';
-import Poll from '~/lib/utils/poll';
-import {
- canScroll,
- isScrolledToBottom,
- isScrolledToTop,
- scrollDown,
- scrollUp,
-} from '~/lib/utils/scroll_utils';
-import { __ } from '~/locale';
-import { reportToSentry } from '../utils';
-import * as types from './mutation_types';
-
-export const init = ({ dispatch }, { endpoint, logState, pagePath }) => {
- dispatch('setJobEndpoint', endpoint);
- dispatch('setJobLogOptions', {
- logState,
- pagePath,
- });
-
- return dispatch('fetchJob');
-};
-
-export const setJobEndpoint = ({ commit }, endpoint) => commit(types.SET_JOB_ENDPOINT, endpoint);
-export const setJobLogOptions = ({ commit }, options) => commit(types.SET_JOB_LOG_OPTIONS, options);
-
-export const hideSidebar = ({ commit }) => commit(types.HIDE_SIDEBAR);
-export const showSidebar = ({ commit }) => commit(types.SHOW_SIDEBAR);
-
-export const toggleSidebar = ({ dispatch, state }) => {
- if (state.isSidebarOpen) {
- dispatch('hideSidebar');
- } else {
- dispatch('showSidebar');
- }
-};
-
-let eTagPoll;
-
-export const clearEtagPoll = () => {
- eTagPoll = null;
-};
-
-export const stopPolling = () => {
- if (eTagPoll) eTagPoll.stop();
-};
-
-export const restartPolling = () => {
- if (eTagPoll) eTagPoll.restart();
-};
-
-export const requestJob = ({ commit }) => commit(types.REQUEST_JOB);
-
-export const fetchJob = ({ state, dispatch }) => {
- dispatch('requestJob');
-
- eTagPoll = new Poll({
- resource: {
- getJob(endpoint) {
- return axios.get(endpoint);
- },
- },
- data: state.jobEndpoint,
- method: 'getJob',
- successCallback: ({ data }) => dispatch('receiveJobSuccess', data),
- errorCallback: () => dispatch('receiveJobError'),
- });
-
- if (!Visibility.hidden()) {
- eTagPoll.makeRequest();
- } else {
- axios
- .get(state.jobEndpoint)
- .then(({ data }) => dispatch('receiveJobSuccess', data))
- .catch(() => dispatch('receiveJobError'));
- }
-
- Visibility.change(() => {
- if (!Visibility.hidden()) {
- dispatch('restartPolling');
- } else {
- dispatch('stopPolling');
- }
- });
-};
-
-export const receiveJobSuccess = ({ commit }, data = {}) => {
- commit(types.RECEIVE_JOB_SUCCESS, data);
-
- if (data.status && data.status.favicon) {
- setFaviconOverlay(data.status.favicon);
- } else {
- resetFavicon();
- }
-};
-export const receiveJobError = ({ commit }) => {
- commit(types.RECEIVE_JOB_ERROR);
- createAlert({
- message: __('An error occurred while fetching the job.'),
- });
- resetFavicon();
-};
-
-/**
- * Job Log
- */
-export const scrollTop = ({ dispatch }) => {
- scrollUp();
- dispatch('toggleScrollButtons');
-};
-
-export const scrollBottom = ({ dispatch }) => {
- scrollDown();
- dispatch('toggleScrollButtons');
-};
-
-/**
- * Responsible for toggling the disabled state of the scroll buttons
- */
-export const toggleScrollButtons = ({ dispatch }) => {
- if (canScroll()) {
- if (isScrolledToTop()) {
- dispatch('disableScrollTop');
- dispatch('enableScrollBottom');
- } else if (isScrolledToBottom()) {
- dispatch('disableScrollBottom');
- dispatch('enableScrollTop');
- } else {
- dispatch('enableScrollTop');
- dispatch('enableScrollBottom');
- }
- } else {
- dispatch('disableScrollBottom');
- dispatch('disableScrollTop');
- }
-};
-
-export const disableScrollBottom = ({ commit }) => commit(types.DISABLE_SCROLL_BOTTOM);
-export const disableScrollTop = ({ commit }) => commit(types.DISABLE_SCROLL_TOP);
-export const enableScrollBottom = ({ commit }) => commit(types.ENABLE_SCROLL_BOTTOM);
-export const enableScrollTop = ({ commit }) => commit(types.ENABLE_SCROLL_TOP);
-
-/**
- * While the automatic scroll down is active,
- * we show the scroll down button with an animation
- */
-export const toggleScrollAnimation = ({ commit }, toggle) =>
- commit(types.TOGGLE_SCROLL_ANIMATION, toggle);
-
-/**
- * Responsible to handle automatic scroll
- */
-export const toggleScrollisInBottom = ({ commit }, toggle) => {
- commit(types.TOGGLE_IS_SCROLL_IN_BOTTOM_BEFORE_UPDATING_JOB_LOG, toggle);
-};
-
-export const requestJobLog = ({ commit }) => commit(types.REQUEST_JOB_LOG);
-
-export const fetchJobLog = ({ dispatch, state }) =>
- // update trace endpoint once BE compeletes trace re-naming in #340626
- axios
- .get(`${state.jobLogEndpoint}/trace.json`, {
- params: { state: state.jobLogState },
- })
- .then(({ data }) => {
- dispatch('toggleScrollisInBottom', isScrolledToBottom());
- dispatch('receiveJobLogSuccess', data);
-
- if (data.complete) {
- dispatch('stopPollingJobLog');
- } else if (!state.jobLogTimeout) {
- dispatch('startPollingJobLog');
- }
- })
- .catch((e) => {
- if (e.response.status === HTTP_STATUS_FORBIDDEN) {
- dispatch('receiveJobLogUnauthorizedError');
- } else {
- reportToSentry('job_actions', e);
- dispatch('receiveJobLogError');
- }
- });
-
-export const startPollingJobLog = ({ dispatch, commit }) => {
- const jobLogTimeout = setTimeout(() => {
- commit(types.SET_JOB_LOG_TIMEOUT, 0);
- dispatch('fetchJobLog');
- }, 4000);
-
- commit(types.SET_JOB_LOG_TIMEOUT, jobLogTimeout);
-};
-
-export const stopPollingJobLog = ({ state, commit }) => {
- clearTimeout(state.jobLogTimeout);
- commit(types.SET_JOB_LOG_TIMEOUT, 0);
- commit(types.STOP_POLLING_JOB_LOG);
-};
-
-export const receiveJobLogSuccess = ({ commit }, log) => commit(types.RECEIVE_JOB_LOG_SUCCESS, log);
-
-export const receiveJobLogError = ({ dispatch }) => {
- dispatch('stopPollingJobLog');
- createAlert({
- message: __('An error occurred while fetching the job log.'),
- });
-};
-
-export const receiveJobLogUnauthorizedError = ({ dispatch }) => {
- dispatch('stopPollingJobLog');
- createAlert({
- message: __('The current user is not authorized to access the job log.'),
- });
-};
-/**
- * When the user clicks a collapsible line in the job
- * log, we commit a mutation to update the state
- *
- * @param {Object} section
- */
-export const toggleCollapsibleLine = ({ commit }, section) =>
- commit(types.TOGGLE_COLLAPSIBLE_LINE, section);
-
-/**
- * Jobs list on sidebar - depend on stages dropdown
- */
-export const requestJobsForStage = ({ commit }, stage) =>
- commit(types.REQUEST_JOBS_FOR_STAGE, stage);
-
-// On stage click, set selected stage + fetch job
-export const fetchJobsForStage = ({ dispatch }, stage = {}) => {
- dispatch('requestJobsForStage', stage);
-
- axios
- .get(stage.dropdown_path, {
- params: {
- retried: 1,
- },
- })
- .then(({ data }) => {
- const retriedJobs = data.retried.map((job) => ({ ...job, retried: true }));
- const jobs = data.latest_statuses.concat(retriedJobs);
-
- dispatch('receiveJobsForStageSuccess', jobs);
- })
- .catch(() => dispatch('receiveJobsForStageError'));
-};
-export const receiveJobsForStageSuccess = ({ commit }, data) =>
- commit(types.RECEIVE_JOBS_FOR_STAGE_SUCCESS, data);
-
-export const receiveJobsForStageError = ({ commit }) => {
- commit(types.RECEIVE_JOBS_FOR_STAGE_ERROR);
- createAlert({
- message: __('An error occurred while fetching the jobs.'),
- });
-};
-
-export const triggerManualJob = ({ state }, variables) => {
- const parsedVariables = variables.map((variable) => {
- const copyVar = { ...variable };
- delete copyVar.id;
- return copyVar;
- });
-
- axios
- .post(state.job.status.action.path, {
- job_variables_attributes: parsedVariables,
- })
- .catch(() =>
- createAlert({
- message: __('An error occurred while triggering the job.'),
- }),
- );
-};
diff --git a/app/assets/javascripts/jobs/utils.js b/app/assets/javascripts/jobs/utils.js
deleted file mode 100644
index a4e695518f1..00000000000
--- a/app/assets/javascripts/jobs/utils.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import * as Sentry from '@sentry/browser';
-
-/**
- * capture anything starting with http:// or https://
- * https?:\/\/
- *
- * up until a disallowed character or whitespace
- * [^"<>()\\^`{|}\s]+
- *
- * and a disallowed character or whitespace, including non-ending chars .,:;!?
- * [^"<>()\\^`{|}\s.,:;!?]
- */
-export const linkRegex = /(https?:\/\/[^"<>()\\^`{|}\s]+[^"<>()\\^`{|}\s.,:;!?])/g;
-export default { linkRegex };
-
-export const reportToSentry = (component, failureType) => {
- Sentry.withScope((scope) => {
- scope.setTag('component', component);
- Sentry.captureException(failureType);
- });
-};
-
-export const reportMessageToSentry = (component, message, context) => {
- Sentry.withScope((scope) => {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- scope.setContext('Vue data', context);
- scope.setTag('component', component);
- Sentry.captureMessage(message);
- });
-};
diff --git a/app/assets/javascripts/labels/labels_select.js b/app/assets/javascripts/labels/labels_select.js
index 587cc82f0fa..db1dbc72624 100644
--- a/app/assets/javascripts/labels/labels_select.js
+++ b/app/assets/javascripts/labels/labels_select.js
@@ -276,7 +276,8 @@ export default class LabelsSelect {
if (selected && selected.id === 0) {
this.selected = [];
return __('No label');
- } else if (isSelected) {
+ }
+ if (isSelected) {
this.selected.push(title);
} else if (!isSelected && title) {
const index = this.selected.indexOf(title);
@@ -285,7 +286,8 @@ export default class LabelsSelect {
if (selectedLabels.length === 1) {
return selectedLabels;
- } else if (selectedLabels.length) {
+ }
+ if (selectedLabels.length) {
return sprintf(__('%{firstLabel} +%{labelCount} more'), {
firstLabel: selectedLabels[0],
labelCount: selectedLabels.length - 1,
diff --git a/app/assets/javascripts/lib/swagger.js b/app/assets/javascripts/lib/swagger.js
index fcdab18c623..b0701054174 100644
--- a/app/assets/javascripts/lib/swagger.js
+++ b/app/assets/javascripts/lib/swagger.js
@@ -27,7 +27,7 @@ const renderSwaggerUI = (value) => {
spec,
dom_id: '#swagger-ui',
deepLinking: true,
- displayOperationId: true,
+ displayOperationId: Boolean(getParameterByName('displayOperationId')),
});
})
.catch((error) => {
diff --git a/app/assets/javascripts/lib/utils/array_utility.js b/app/assets/javascripts/lib/utils/array_utility.js
index 04f9cb1cdb5..9eddae860c2 100644
--- a/app/assets/javascripts/lib/utils/array_utility.js
+++ b/app/assets/javascripts/lib/utils/array_utility.js
@@ -28,3 +28,18 @@ export const swapArrayItems = (array, leftIndex = 0, rightIndex = 0) => {
export const getDuplicateItemsFromArray = (array) => [
...new Set(array.filter((value, index) => array.indexOf(value) !== index)),
];
+
+/**
+ * Toggles the presence of an item in a given array.
+ * Use pass by reference when toggling non-primivive types.
+ *
+ * @param {Array} array - The array to use
+ * @param {Any} item - The array item to toggle
+ * @returns {Array} new array with toggled item
+ */
+export const toggleArrayItem = (array, value) => {
+ if (array.includes(value)) {
+ return array.filter((item) => item !== value);
+ }
+ return [...array, value];
+};
diff --git a/app/assets/javascripts/lib/utils/breadcrumbs.js b/app/assets/javascripts/lib/utils/breadcrumbs.js
new file mode 100644
index 00000000000..e38094fc895
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/breadcrumbs.js
@@ -0,0 +1,28 @@
+import Vue from 'vue';
+
+// TODO: Review replacing this when a breadcrumbs ViewComponent has been created https://gitlab.com/gitlab-org/gitlab/-/issues/367326
+export const injectVueAppBreadcrumbs = (router, BreadcrumbsComponent, apolloProvider = null) => {
+ const breadcrumbEls = document.querySelectorAll('nav .js-breadcrumbs-list li');
+
+ if (breadcrumbEls.length < 1) {
+ return false;
+ }
+
+ const breadcrumbEl = breadcrumbEls[breadcrumbEls.length - 1];
+
+ const lastCrumb = breadcrumbEl.children[0];
+ const nestedBreadcrumbEl = document.createElement('div');
+
+ breadcrumbEl.replaceChild(nestedBreadcrumbEl, lastCrumb);
+
+ return new Vue({
+ el: nestedBreadcrumbEl,
+ router,
+ apolloProvider,
+ render(createElement) {
+ return createElement(BreadcrumbsComponent, {
+ class: breadcrumbEl.className,
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index cca4cf68f5e..7d16af003e4 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -86,7 +86,6 @@ export const handleLocationHash = () => {
const performanceBar = document.querySelector('#js-peek');
const topPadding = 8;
const diffFileHeader = document.querySelector('.js-file-title');
- const versionMenusContainer = document.querySelector('.mr-version-menus-container');
const fixedIssuableTitle = document.querySelector('.issue-sticky-header');
let adjustment = 0;
@@ -97,7 +96,6 @@ export const handleLocationHash = () => {
adjustment -= getElementOffsetHeight(fixedTopBar);
adjustment -= getElementOffsetHeight(performanceBar);
adjustment -= getElementOffsetHeight(diffFileHeader);
- adjustment -= getElementOffsetHeight(versionMenusContainer);
if (isInIssuePage()) {
adjustment -= getElementOffsetHeight(fixedIssuableTitle);
@@ -731,3 +729,11 @@ export const isCurrentUser = (userId) => {
return Number(userId) === currentUserId;
};
+
+/**
+ * Clones an object via JSON stringifying and re-parsing.
+ * This ensures object references are not persisted (e.g. unlike lodash cloneDeep)
+ */
+export const cloneWithoutReferences = (obj) => {
+ return JSON.parse(JSON.stringify(obj));
+};
diff --git a/app/assets/javascripts/lib/utils/constants.js b/app/assets/javascripts/lib/utils/constants.js
index aceae188b73..da5fb831ae5 100644
--- a/app/assets/javascripts/lib/utils/constants.js
+++ b/app/assets/javascripts/lib/utils/constants.js
@@ -3,15 +3,6 @@ export const DEFAULT_DEBOUNCE_AND_THROTTLE_MS = 250;
export const THOUSAND = 1000;
export const TRUNCATE_WIDTH_DEFAULT_WIDTH = 80;
export const TRUNCATE_WIDTH_DEFAULT_FONT_SIZE = 12;
-
-export const DATETIME_RANGE_TYPES = {
- fixed: 'fixed',
- anchored: 'anchored',
- rolling: 'rolling',
- open: 'open',
- invalid: 'invalid',
-};
-
export const BV_SHOW_MODAL = 'bv::show::modal';
export const BV_HIDE_MODAL = 'bv::hide::modal';
export const BV_HIDE_TOOLTIP = 'bv::hide::tooltip';
diff --git a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
index d52672b9d08..4e0d19f2c2a 100644
--- a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
@@ -133,7 +133,8 @@ export const dayInQuarter = (date, quarter) => {
return quarter.reduce((acc, month) => {
if (dateValues.month > month.getMonth()) {
return acc + totalDaysInMonth(month);
- } else if (dateValues.month === month.getMonth()) {
+ }
+ if (dateValues.month === month.getMonth()) {
return acc + dateValues.date;
}
return acc + 0;
@@ -562,9 +563,11 @@ export const approximateDuration = (seconds = 0) => {
if (seconds < 30) {
return __('less than a minute');
- } else if (seconds < MINUTES_LIMIT) {
+ }
+ if (seconds < MINUTES_LIMIT) {
return n__('1 minute', '%d minutes', seconds < ONE_MINUTE_LIMIT ? 1 : minutes);
- } else if (seconds < HOURS_LIMIT) {
+ }
+ if (seconds < HOURS_LIMIT) {
return n__('about 1 hour', 'about %d hours', seconds < ONE_HOUR_LIMIT ? 1 : hours);
}
return n__('1 day', '%d days', seconds < ONE_DAY_LIMIT ? 1 : days);
diff --git a/app/assets/javascripts/lib/utils/datetime/date_format_utility.js b/app/assets/javascripts/lib/utils/datetime/date_format_utility.js
index b0264796d90..c4b8f95e99f 100644
--- a/app/assets/javascripts/lib/utils/datetime/date_format_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime/date_format_utility.js
@@ -93,10 +93,12 @@ export const humanizeTimeInterval = (intervalInSeconds) => {
if (intervalInSeconds < 60 /* = 1 minute */) {
const seconds = Math.round(intervalInSeconds * 10) / 10;
return n__('%d second', '%d seconds', seconds);
- } else if (intervalInSeconds < 3600 /* = 1 hour */) {
+ }
+ if (intervalInSeconds < 3600 /* = 1 hour */) {
const minutes = Math.round(intervalInSeconds / 6) / 10;
return n__('%d minute', '%d minutes', minutes);
- } else if (intervalInSeconds < 86400 /* = 1 day */) {
+ }
+ if (intervalInSeconds < 86400 /* = 1 day */) {
const hours = Math.round(intervalInSeconds / 360) / 10;
return n__('%d hour', '%d hours', hours);
}
@@ -378,19 +380,24 @@ export const formatTimeAsSummary = ({ seconds, hours, days, minutes, weeks, mont
return sprintf(s__('ValueStreamAnalytics|%{value}M'), {
value: roundToNearestHalf(months),
});
- } else if (weeks) {
+ }
+ if (weeks) {
return sprintf(s__('ValueStreamAnalytics|%{value}w'), {
value: roundToNearestHalf(weeks),
});
- } else if (days) {
+ }
+ if (days) {
return sprintf(s__('ValueStreamAnalytics|%{value}d'), {
value: roundToNearestHalf(days),
});
- } else if (hours) {
+ }
+ if (hours) {
return sprintf(s__('ValueStreamAnalytics|%{value}h'), { value: hours });
- } else if (minutes) {
+ }
+ if (minutes) {
return sprintf(s__('ValueStreamAnalytics|%{value}m'), { value: minutes });
- } else if (seconds) {
+ }
+ if (seconds) {
return unescape(sanitize(s__('ValueStreamAnalytics|&lt;1m'), { ALLOWED_TAGS: [] }));
}
return '-';
@@ -441,11 +448,13 @@ export const humanTimeframe = (startDate, dueDate) => {
startDate: startDateInWords,
dueDate: dueDateInWords,
});
- } else if (startDate && !dueDate) {
+ }
+ if (startDate && !dueDate) {
return sprintf(__('%{startDate} – No due date'), {
startDate: dateInWords(start, true, false),
});
- } else if (!startDate && dueDate) {
+ }
+ if (!startDate && dueDate) {
return sprintf(__('No start date – %{dueDate}'), {
dueDate: dateInWords(due, true, false),
});
diff --git a/app/assets/javascripts/lib/utils/datetime_range.js b/app/assets/javascripts/lib/utils/datetime_range.js
index 548f5a438df..f0a03874949 100644
--- a/app/assets/javascripts/lib/utils/datetime_range.js
+++ b/app/assets/javascripts/lib/utils/datetime_range.js
@@ -1,27 +1,6 @@
-import { pick, omit, isEqual, isEmpty } from 'lodash';
import dateformat from '~/lib/dateformat';
-import { DATETIME_RANGE_TYPES } from './constants';
-import { secondsToMilliseconds } from './datetime_utility';
-const MINIMUM_DATE = new Date(0);
-
-const DEFAULT_DIRECTION = 'before';
-
-const durationToMillis = (duration) => {
- if (Object.entries(duration).length === 1 && Number.isFinite(duration.seconds)) {
- return secondsToMilliseconds(duration.seconds);
- }
- // eslint-disable-next-line @gitlab/require-i18n-strings
- throw new Error('Invalid duration: only `seconds` is supported');
-};
-
-const dateMinusDuration = (date, duration) => new Date(date.getTime() - durationToMillis(duration));
-
-const datePlusDuration = (date, duration) => new Date(date.getTime() + durationToMillis(duration));
-
-const isValidDuration = (duration) => Boolean(duration && Number.isFinite(duration.seconds));
-
-const isValidDateString = (dateString) => {
+export const isValidDateString = (dateString) => {
if (typeof dateString !== 'string' || !dateString.trim()) {
return false;
}
@@ -38,291 +17,3 @@ const isValidDateString = (dateString) => {
}
return !Number.isNaN(Date.parse(isoFormatted));
};
-
-const handleRangeDirection = ({ direction = DEFAULT_DIRECTION, anchorDate, minDate, maxDate }) => {
- let startDate;
- let endDate;
-
- if (direction === DEFAULT_DIRECTION) {
- startDate = minDate;
- endDate = anchorDate;
- } else {
- startDate = anchorDate;
- endDate = maxDate;
- }
-
- return {
- startDate,
- endDate,
- };
-};
-
-/**
- * Converts a fixed range to a fixed range
- * @param {Object} fixedRange - A range with fixed start and
- * end (e.g. "midnight January 1st 2020 to midday January31st 2020")
- */
-const convertFixedToFixed = ({ start, end }) => ({
- start,
- end,
-});
-
-/**
- * Converts an anchored range to a fixed range
- * @param {Object} anchoredRange - A duration of time
- * relative to a fixed point in time (e.g., "the 30 minutes
- * before midnight January 1st 2020", or "the 2 days
- * after midday on the 11th of May 2019")
- */
-const convertAnchoredToFixed = ({ anchor, duration, direction }) => {
- const anchorDate = new Date(anchor);
-
- const { startDate, endDate } = handleRangeDirection({
- minDate: dateMinusDuration(anchorDate, duration),
- maxDate: datePlusDuration(anchorDate, duration),
- direction,
- anchorDate,
- });
-
- return {
- start: startDate.toISOString(),
- end: endDate.toISOString(),
- };
-};
-
-/**
- * Converts a rolling change to a fixed range
- *
- * @param {Object} rollingRange - A time range relative to
- * now (e.g., "last 2 minutes", or "next 2 days")
- */
-const convertRollingToFixed = ({ duration, direction }) => {
- // Use Date.now internally for easier mocking in tests
- const now = new Date(Date.now());
-
- return convertAnchoredToFixed({
- duration,
- direction,
- anchor: now.toISOString(),
- });
-};
-
-/**
- * Converts an open range to a fixed range
- *
- * @param {Object} openRange - A time range relative
- * to an anchor (e.g., "before midnight on the 1st of
- * January 2020", or "after midday on the 11th of May 2019")
- */
-const convertOpenToFixed = ({ anchor, direction }) => {
- // Use Date.now internally for easier mocking in tests
- const now = new Date(Date.now());
-
- const { startDate, endDate } = handleRangeDirection({
- minDate: MINIMUM_DATE,
- maxDate: now,
- direction,
- anchorDate: new Date(anchor),
- });
-
- return {
- start: startDate.toISOString(),
- end: endDate.toISOString(),
- };
-};
-
-/**
- * Handles invalid date ranges
- */
-const handleInvalidRange = () => {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- throw new Error('The input range does not have the right format.');
-};
-
-const handlers = {
- invalid: handleInvalidRange,
- fixed: convertFixedToFixed,
- anchored: convertAnchoredToFixed,
- rolling: convertRollingToFixed,
- open: convertOpenToFixed,
-};
-
-/**
- * Validates and returns the type of range
- *
- * @param {Object} Date time range
- * @returns {String} `key` value for one of the handlers
- */
-export function getRangeType(range) {
- const { start, end, anchor, duration } = range;
-
- if ((start || end) && !anchor && !duration) {
- return isValidDateString(start) && isValidDateString(end)
- ? DATETIME_RANGE_TYPES.fixed
- : DATETIME_RANGE_TYPES.invalid;
- }
- if (anchor && duration) {
- return isValidDateString(anchor) && isValidDuration(duration)
- ? DATETIME_RANGE_TYPES.anchored
- : DATETIME_RANGE_TYPES.invalid;
- }
- if (duration && !anchor) {
- return isValidDuration(duration) ? DATETIME_RANGE_TYPES.rolling : DATETIME_RANGE_TYPES.invalid;
- }
- if (anchor && !duration) {
- return isValidDateString(anchor) ? DATETIME_RANGE_TYPES.open : DATETIME_RANGE_TYPES.invalid;
- }
- return DATETIME_RANGE_TYPES.invalid;
-}
-
-/**
- * convertToFixedRange Transforms a `range of time` into a `fixed range of time`.
- *
- * The following types of a `ranges of time` can be represented:
- *
- * Fixed Range: A range with fixed start and end (e.g. "midnight January 1st 2020 to midday January 31st 2020")
- * Anchored Range: A duration of time relative to a fixed point in time (e.g., "the 30 minutes before midnight January 1st 2020", or "the 2 days after midday on the 11th of May 2019")
- * Rolling Range: A time range relative to now (e.g., "last 2 minutes", or "next 2 days")
- * Open Range: A time range relative to an anchor (e.g., "before midnight on the 1st of January 2020", or "after midday on the 11th of May 2019")
- *
- * @param {Object} dateTimeRange - A Time Range representation
- * It contains the data needed to create a fixed time range plus
- * a label (recommended) to indicate the range that is covered.
- *
- * A definition via a TypeScript notation is presented below:
- *
- *
- * type Duration = { // A duration of time, always in seconds
- * seconds: number;
- * }
- *
- * type Direction = 'before' | 'after'; // Direction of time relative to an anchor
- *
- * type FixedRange = {
- * start: ISO8601;
- * end: ISO8601;
- * label: string;
- * }
- *
- * type AnchoredRange = {
- * anchor: ISO8601;
- * duration: Duration;
- * direction: Direction; // defaults to 'before'
- * label: string;
- * }
- *
- * type RollingRange = {
- * duration: Duration;
- * direction: Direction; // defaults to 'before'
- * label: string;
- * }
- *
- * type OpenRange = {
- * anchor: ISO8601;
- * direction: Direction; // defaults to 'before'
- * label: string;
- * }
- *
- * type DateTimeRange = FixedRange | AnchoredRange | RollingRange | OpenRange;
- *
- *
- * @returns {FixedRange} An object with a start and end in ISO8601 format.
- */
-export const convertToFixedRange = (dateTimeRange) =>
- handlers[getRangeType(dateTimeRange)](dateTimeRange);
-
-/**
- * Returns a copy of the object only with time range
- * properties relevant to time range calculation.
- *
- * Filtered properties are:
- * - 'start'
- * - 'end'
- * - 'anchor'
- * - 'duration'
- * - 'direction': if direction is already the default, its removed.
- *
- * @param {Object} timeRange - A time range object
- * @returns Copy of time range
- */
-const pruneTimeRange = (timeRange) => {
- const res = pick(timeRange, ['start', 'end', 'anchor', 'duration', 'direction']);
- if (res.direction === DEFAULT_DIRECTION) {
- return omit(res, 'direction');
- }
- return res;
-};
-
-/**
- * Returns true if the time ranges are equal according to
- * the time range calculation properties
- *
- * @param {Object} timeRange - A time range object
- * @param {Object} other - Time range object to compare with.
- * @returns true if the time ranges are equal, false otherwise
- */
-export const isEqualTimeRanges = (timeRange, other) => {
- const tr1 = pruneTimeRange(timeRange);
- const tr2 = pruneTimeRange(other);
- return isEqual(tr1, tr2);
-};
-
-/**
- * Searches for a time range in a array of time ranges using
- * only the properies relevant to time ranges calculation.
- *
- * @param {Object} timeRange - Time range to search (needle)
- * @param {Array} timeRanges - Array of time tanges (haystack)
- */
-export const findTimeRange = (timeRange, timeRanges) =>
- timeRanges.find((element) => isEqualTimeRanges(element, timeRange));
-
-// Time Ranges as URL Parameters Utils
-
-/**
- * List of possible time ranges parameters
- */
-export const timeRangeParamNames = ['start', 'end', 'anchor', 'duration_seconds', 'direction'];
-
-/**
- * Converts a valid time range to a flat key-value pairs object.
- *
- * Duration is flatted to avoid having nested objects.
- *
- * @param {Object} A time range
- * @returns key-value pairs object that can be used as parameters in a URL.
- */
-export const timeRangeToParams = (timeRange) => {
- let params = pruneTimeRange(timeRange);
- if (timeRange.duration) {
- const durationParms = {};
- Object.keys(timeRange.duration).forEach((key) => {
- durationParms[`duration_${key}`] = timeRange.duration[key].toString();
- });
- params = { ...durationParms, ...params };
- params = omit(params, 'duration');
- }
- return params;
-};
-
-/**
- * Converts a valid set of flat params to a time range object
- *
- * Parameters that are not part of time range object are ignored.
- *
- * @param {params} params - key-value pairs object.
- */
-export const timeRangeFromParams = (params) => {
- const timeRangeParams = pick(params, timeRangeParamNames);
- let range = Object.entries(timeRangeParams).reduce((acc, [key, val]) => {
- // unflatten duration
- if (key.startsWith('duration_')) {
- acc.duration = acc.duration || {};
- acc.duration[key.slice('duration_'.length)] = parseInt(val, 10);
- return acc;
- }
- return { [key]: val, ...acc };
- }, {});
- range = pruneTimeRange(range);
- return !isEmpty(range) ? range : null;
-};
diff --git a/app/assets/javascripts/lib/utils/grammar.js b/app/assets/javascripts/lib/utils/grammar.js
index 6d6361d19b6..64ba151d829 100644
--- a/app/assets/javascripts/lib/utils/grammar.js
+++ b/app/assets/javascripts/lib/utils/grammar.js
@@ -19,9 +19,11 @@ import { sprintf, s__ } from '~/locale';
export const toNounSeriesText = (items, { onlyCommas = false } = {}) => {
if (items.length === 0) {
return '';
- } else if (items.length === 1) {
+ }
+ if (items.length === 1) {
return sprintf(s__(`nounSeries|%{item}`), { item: items[0] }, false);
- } else if (items.length === 2 && !onlyCommas) {
+ }
+ if (items.length === 2 && !onlyCommas) {
return sprintf(
s__('nounSeries|%{firstItem} and %{lastItem}'),
{
diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js
index 0e943cdb623..d17719c0bc0 100644
--- a/app/assets/javascripts/lib/utils/number_utils.js
+++ b/app/assets/javascripts/lib/utils/number_utils.js
@@ -84,9 +84,11 @@ export function numberToHumanSizeSplit(size, digits = 2) {
if (abs < BYTES_IN_KIB) {
return [size.toString(), BYTES_FORMAT_BYTES];
- } else if (abs < BYTES_IN_KIB ** 2) {
+ }
+ if (abs < BYTES_IN_KIB ** 2) {
return [bytesToKiB(size).toFixed(digits), BYTES_FORMAT_KIB];
- } else if (abs < BYTES_IN_KIB ** 3) {
+ }
+ if (abs < BYTES_IN_KIB ** 3) {
return [bytesToMiB(size).toFixed(digits), BYTES_FORMAT_MIB];
}
return [bytesToGiB(size).toFixed(digits), BYTES_FORMAT_GIB];
diff --git a/app/assets/javascripts/lib/utils/secret_detection.js b/app/assets/javascripts/lib/utils/secret_detection.js
index 8e673855631..49de7b3a081 100644
--- a/app/assets/javascripts/lib/utils/secret_detection.js
+++ b/app/assets/javascripts/lib/utils/secret_detection.js
@@ -24,6 +24,10 @@ export const containsSensitiveToken = (message) => {
name: 'Feed Token',
regex: 'feed_token=((glft-)?[0-9a-zA-Z_-]{20}|glft-[a-h0-9]+-[0-9]+_)',
},
+ {
+ name: 'GitLab OAuth Application Secret',
+ regex: `gloas-[0-9a-zA-Z_-]{64}`,
+ },
];
for (const rule of sensitiveDataPatterns) {
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index e6eb74834c0..d48e0217fd8 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -202,7 +202,8 @@ function moveCursor({
const startPosition = textArea.selectionStart - (tag.length - tag.indexOf(select));
const endPosition = startPosition + select.length;
return textArea.setSelectionRange(startPosition, endPosition);
- } else if (editor) {
+ }
+ if (editor) {
editor.selectWithinSelection(select, tag);
return;
}
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index 31e16f7b4db..638ee1f7e5a 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -178,18 +178,6 @@ export function capitalizeFirstCharacter(text) {
}
/**
- * Returns the first character capitalized
- *
- * If falsey, returns empty string.
- *
- * @param {String} text
- * @return {String}
- */
-export function getFirstCharacterCapitalized(text) {
- return text ? text.charAt(0).toUpperCase() : '';
-}
-
-/**
* Replaces all html tags from a string with the given replacement.
*
* @param {String} string
@@ -529,9 +517,11 @@ export const humanizeBranchValidationErrors = (invalidChars = []) => {
if (chars.length && !chars.includes(' ')) {
return sprintf(__("Can't contain %{chars}"), { chars: chars.join(', ') });
- } else if (chars.includes(' ') && chars.length <= 1) {
+ }
+ if (chars.includes(' ') && chars.length <= 1) {
return __("Can't contain spaces");
- } else if (chars.includes(' ') && chars.length > 1) {
+ }
+ if (chars.includes(' ') && chars.length > 1) {
return sprintf(__("Can't contain spaces, %{chars}"), {
chars: chars.filter((c) => c !== ' ').join(', '),
});
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 08c98298121..ea0520e3157 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -1,5 +1,3 @@
-import * as Sentry from '@sentry/browser';
-
export const DASH_SCOPE = '-';
export const PATH_SEPARATOR = '/';
@@ -705,11 +703,7 @@ export function visitUrl(destination, external = false) {
}
if (!isSafeURL(url)) {
- // For now log this to Sentry and do not block the execution.
- // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121551#note_1408873600
- // for more context. Once we're sure that it's not breaking functionality, we can use
- // a RangeError here (throw new RangeError('Only http and https protocols are allowed')).
- Sentry.captureException(new RangeError(`Only http and https protocols are allowed: ${url}`));
+ throw new RangeError(`Only http and https protocols are allowed: ${url}`);
}
if (external) {
diff --git a/app/assets/javascripts/lib/utils/webpack.js b/app/assets/javascripts/lib/utils/webpack.js
index 38d2f3d7551..f1e87145406 100644
--- a/app/assets/javascripts/lib/utils/webpack.js
+++ b/app/assets/javascripts/lib/utils/webpack.js
@@ -5,10 +5,11 @@ import { joinPaths } from '~/lib/utils/url_utility';
* See https://gitlab.com/gitlab-org/gitlab/-/issues/321656 for a fix
*/
export function resetServiceWorkersPublicPath() {
+ // No-op if we're running Vite instead of Webpack
+ if (typeof __webpack_public_path__ === 'undefined') return; // eslint-disable-line camelcase
// __webpack_public_path__ is a global variable that can be used to adjust
// the webpack publicPath setting at runtime.
// see: https://webpack.js.org/guides/public-path/
const relativeRootPath = (gon && gon.relative_url_root) || '';
- const webpackAssetPath = joinPaths(relativeRootPath, '/assets/webpack/');
- __webpack_public_path__ = webpackAssetPath; // eslint-disable-line camelcase
+ __webpack_public_path__ = joinPaths(relativeRootPath, '/assets/webpack/'); // eslint-disable-line camelcase
}
diff --git a/app/assets/javascripts/locale/ensure_single_line.cjs b/app/assets/javascripts/locale/ensure_single_line.cjs
index f7790cadc48..abdd56c3589 100644
--- a/app/assets/javascripts/locale/ensure_single_line.cjs
+++ b/app/assets/javascripts/locale/ensure_single_line.cjs
@@ -1,15 +1,11 @@
const SPLIT_REGEX = /\s*[\r\n]+\s*/;
/**
- *
- * strips newlines from strings and replaces them with a single space
- *
+ * Strips newlines from strings and replaces them with a single space.
* @example
- *
* ensureSingleLine('foo \n bar') === 'foo bar'
- *
- * @param {String} str
- * @returns {String}
+ * @param {string} - str
+ * @returns {string}
*/
module.exports = function ensureSingleLine(str) {
// This guard makes the function significantly faster
diff --git a/app/assets/javascripts/locale/index.js b/app/assets/javascripts/locale/index.js
index 600654794a5..48cf06e0793 100644
--- a/app/assets/javascripts/locale/index.js
+++ b/app/assets/javascripts/locale/index.js
@@ -19,22 +19,22 @@ if (hasTranslations) {
}
/**
- Translates `text`
- @param text The text to be translated
- @returns {String} The translated text
-*/
+ * Translates `text`.
+ * @param {string} text - The text to be translated
+ * @returns {string} The translated text
+ */
const gettext = (text) => locale.gettext(ensureSingleLine(text));
/**
- Translate the text with a number
- if the number is more than 1 it will use the `pluralText` translation.
- This method allows for contexts, see below re. contexts
-
- @param text Singular text to translate (eg. '%d day')
- @param pluralText Plural text to translate (eg. '%d days')
- @param count Number to decide which translation to use (eg. 2)
- @returns {String} Translated text with the number replaced (eg. '2 days')
-*/
+ * Translate the text with a number.
+ *
+ * If the number is more than 1 it will use the `pluralText` translation.
+ * This method allows for contexts, see below re. contexts
+ * @param {string} text - Singular text to translate (e.g. '%d day')
+ * @param {string} pluralText - Plural text to translate (e.g. '%d days')
+ * @param {number} count - Number to decide which translation to use (e.g. 2)
+ * @returns {string} Translated text with the number replaced (e.g. '2 days')
+ */
const ngettext = (text, pluralText, count) => {
const translated = locale
.ngettext(ensureSingleLine(text), ensureSingleLine(pluralText), count)
@@ -45,16 +45,16 @@ const ngettext = (text, pluralText, count) => {
};
/**
- Translate context based text
- Either pass in the context translation like `Context|Text to translate`
- or allow for dynamic text by doing passing in the context first & then the text to translate
-
- @param keyOrContext Can be either the key to translate including the context
- (eg. 'Context|Text') or just the context for the translation
- (eg. 'Context')
- @param key Is the dynamic variable you want to be translated
- @returns {String} Translated context based text
-*/
+ * Translate context based text.
+ * @example
+ * s__('Context|Text to translate');
+ * @example
+ * s__('Context', 'Text to translate');
+ * @param {string} keyOrContext - Context and a key to translation (e.g. 'Context|Text')
+ * or just a context (e.g. 'Context')
+ * @param {string} [key] - if `keyOrContext` is just a context, this is the key to translation
+ * @returns {string} Translated context based text
+ */
const pgettext = (keyOrContext, key) => {
const normalizedKey = ensureSingleLine(key ? `${keyOrContext}|${key}` : keyOrContext);
const translated = gettext(normalizedKey).split('|');
@@ -102,21 +102,19 @@ export const getPreferredLocales = () => {
};
/**
- Creates an instance of Intl.DateTimeFormat for the current locale.
-
- @param formatOptions for available options, please see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
- @returns {Intl.DateTimeFormat}
-*/
+ * Creates an instance of Intl.DateTimeFormat for the current locale.
+ * @param {Intl.DateTimeFormatOptions} [formatOptions] - for available options, please see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
+ * @returns {Intl.DateTimeFormat}
+ */
const createDateTimeFormat = (formatOptions) =>
Intl.DateTimeFormat(getPreferredLocales(), formatOptions);
/**
* Formats a number as a string using `toLocaleString`.
- *
- * @param {Number} value - number to be converted
- * @param {options?} options - options to be passed to
- * `toLocaleString` such as `unit` and `style`.
- * @param {langCode?} langCode - If set, forces a different
+ * @param {number} value - number to be converted
+ * @param {Intl.NumberFormatOptions} [options] - options to be passed to
+ * `toLocaleString`.
+ * @param {string|string[]} [langCode] - If set, forces a different
* language code from the one currently in the document.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
*
diff --git a/app/assets/javascripts/locale/sprintf.js b/app/assets/javascripts/locale/sprintf.js
index 12df67670f9..7faf9390684 100644
--- a/app/assets/javascripts/locale/sprintf.js
+++ b/app/assets/javascripts/locale/sprintf.js
@@ -1,17 +1,15 @@
import { escape } from 'lodash';
/**
- Very limited implementation of sprintf supporting only named parameters.
-
- @param input (translated) text with parameters (e.g. '%{num_users} users use us')
- @param {Object} parameters object mapping parameter names to values (e.g. { num_users: 5 })
- @param {Boolean} escapeParameters whether parameter values should be escaped (see https://lodash.com/docs/4.17.15#escape)
- @returns {String} the text with parameters replaces (e.g. '5 users use us')
-
- @see https://ruby-doc.org/core-2.3.3/Kernel.html#method-i-sprintf
- @see https://gitlab.com/gitlab-org/gitlab-foss/issues/37992
-*/
-export default (input, parameters, escapeParameters = true) => {
+ * Very limited implementation of sprintf supporting only named parameters.
+ * @param {string} input - (translated) text with parameters (e.g. '%{num_users} users use us')
+ * @param {Object.<string, string|number>} [parameters] - object mapping parameter names to values (e.g. { num_users: 5 })
+ * @param {boolean} [escapeParameters=true] - whether parameter values should be escaped (see https://lodash.com/docs/4.17.15#escape)
+ * @returns {string} the text with parameters replaces (e.g. '5 users use us')
+ * @see https://ruby-doc.org/core-2.3.3/Kernel.html#method-i-sprintf
+ * @see https://gitlab.com/gitlab-org/gitlab-foss/issues/37992
+ */
+export default function sprintf(input, parameters, escapeParameters = true) {
let output = input;
output = output.replace(/%+/g, '%');
@@ -29,4 +27,4 @@ export default (input, parameters, escapeParameters = true) => {
}
return output;
-};
+}
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index fd002e29afc..5bfdd174694 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -8,7 +8,6 @@ import './commons';
import './behaviors';
// lib/utils
-import applyGitLabUIConfig from '@gitlab/ui/dist/config';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import { initRails } from '~/lib/utils/rails_ujs';
import * as popovers from '~/popovers';
@@ -44,8 +43,6 @@ import 'jh_else_ce/main_jh';
logHelloDeferred();
-applyGitLabUIConfig();
-
// expose jQuery as global (TODO: remove these)
window.jQuery = jQuery;
window.$ = jQuery;
diff --git a/app/assets/javascripts/members/components/action_buttons/approve_access_request_button.vue b/app/assets/javascripts/members/components/action_buttons/approve_access_request_button.vue
index 1ae341820d1..2f9acc96923 100644
--- a/app/assets/javascripts/members/components/action_buttons/approve_access_request_button.vue
+++ b/app/assets/javascripts/members/components/action_buttons/approve_access_request_button.vue
@@ -40,7 +40,7 @@ export default {
v-gl-tooltip.hover
:title="$options.title"
:aria-label="$options.title"
- data-qa-selector="approve_access_request_button"
+ data-testid="approve-access-request-button"
icon="check"
type="submit"
/>
diff --git a/app/assets/javascripts/members/components/action_buttons/remove_member_button.vue b/app/assets/javascripts/members/components/action_buttons/remove_member_button.vue
index caa292b37ce..1f134fe3f5d 100644
--- a/app/assets/javascripts/members/components/action_buttons/remove_member_button.vue
+++ b/app/assets/javascripts/members/components/action_buttons/remove_member_button.vue
@@ -71,7 +71,7 @@ export default {
:title="title"
:aria-label="title"
icon="remove"
- data-qa-selector="delete_member_button"
+ data-testid="delete-member-button"
@click="showRemoveMemberModal(modalData)"
/>
</template>
diff --git a/app/assets/javascripts/members/components/modals/remove_member_modal.vue b/app/assets/javascripts/members/components/modals/remove_member_modal.vue
index c7bd1525558..ecc769174f4 100644
--- a/app/assets/javascripts/members/components/modals/remove_member_modal.vue
+++ b/app/assets/javascripts/members/components/modals/remove_member_modal.vue
@@ -56,7 +56,8 @@ export default {
actionText() {
if (this.isAccessRequest) {
return __('Deny access request');
- } else if (this.isInvite) {
+ }
+ if (this.isInvite) {
return s__('Member|Revoke invite');
}
diff --git a/app/assets/javascripts/members/components/table/members_table_cell.vue b/app/assets/javascripts/members/components/table/members_table_cell.vue
index 407cbc55dd3..cac8c9fb4db 100644
--- a/app/assets/javascripts/members/components/table/members_table_cell.vue
+++ b/app/assets/javascripts/members/components/table/members_table_cell.vue
@@ -32,9 +32,11 @@ export default {
memberType() {
if (this.isGroup) {
return MEMBER_TYPES.group;
- } else if (this.isInvite) {
+ }
+ if (this.isInvite) {
return MEMBER_TYPES.invite;
- } else if (this.isAccessRequest) {
+ }
+ if (this.isAccessRequest) {
return MEMBER_TYPES.accessRequest;
}
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 09fe611262c..1bc67522e82 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -93,7 +93,11 @@ function mountPipelines() {
const { mrWidgetData } = gl;
const table = new Vue({
components: {
- CommitPipelinesTable: () => import('~/commit/pipelines/pipelines_table.vue'),
+ CommitPipelinesTable: () => {
+ return gon.features.mrPipelinesGraphql
+ ? import('~/ci/merge_requests/components/pipelines_table_wrapper.vue')
+ : import('~/commit/pipelines/legacy_pipelines_table_wrapper.vue');
+ },
},
apolloProvider,
provide: {
@@ -103,6 +107,8 @@ function mountPipelines() {
fullPath: pipelineTableViewEl.dataset.fullPath,
graphqlPath: pipelineTableViewEl.dataset.graphqlPath,
manualActionsLimit: 50,
+ mergeRequestId: mrWidgetData ? mrWidgetData.iid : null,
+ sourceProjectFullPath: mrWidgetData?.source_project_full_path || '',
withFailedJobsDetails: true,
},
render(createElement) {
@@ -573,10 +579,12 @@ export default class MergeRequestTabs {
expandViewContainer() {
this.contentWrapper.classList.remove('container-limited');
+ this.contentWrapper.classList.add('diffs-container-limited');
}
resetViewContainer() {
this.contentWrapper.classList.toggle('container-limited', this.isFixedLayoutPreferred);
+ this.contentWrapper.classList.remove('diffs-container-limited');
}
// Expand the issuable sidebar unless the user explicitly collapsed it
diff --git a/app/assets/javascripts/merge_requests/components/compare_app.vue b/app/assets/javascripts/merge_requests/components/compare_app.vue
index 8e02048f494..c7c16e91e4c 100644
--- a/app/assets/javascripts/merge_requests/components/compare_app.vue
+++ b/app/assets/javascripts/merge_requests/components/compare_app.vue
@@ -23,9 +23,6 @@ export default {
currentProject: {
default: () => ({}),
},
- currentBranch: {
- default: () => ({}),
- },
inputs: {
default: () => ({}),
},
@@ -35,8 +32,12 @@ export default {
toggleClass: {
default: () => ({}),
},
- branchQaSelector: {
- default: '',
+ },
+ props: {
+ currentBranch: {
+ type: Object,
+ required: false,
+ default: () => ({}),
},
},
data() {
@@ -57,6 +58,12 @@ export default {
return this.commitHtml || this.loading || !this.selectedBranch.value;
},
},
+ watch: {
+ currentBranch(newVal) {
+ this.selectedBranch = newVal;
+ this.fetchCommit();
+ },
+ },
mounted() {
this.fetchCommit();
},
@@ -67,6 +74,7 @@ export default {
selectBranch(branch) {
this.selectedBranch = branch;
this.fetchCommit();
+ this.$emit('select-branch', branch.value);
},
async fetchCommit() {
if (!this.selectedBranch.value) return;
@@ -108,7 +116,7 @@ export default {
:input-name="inputs.branch.name"
:default="currentBranch"
:toggle-class="toggleClass.branch"
- :qa-selector="branchQaSelector"
+ data-testid="compare-dropdown"
@selected="selectBranch"
/>
</div>
diff --git a/app/assets/javascripts/merge_requests/components/compare_dropdown.vue b/app/assets/javascripts/merge_requests/components/compare_dropdown.vue
index a5a4e683214..2855d704507 100644
--- a/app/assets/javascripts/merge_requests/components/compare_dropdown.vue
+++ b/app/assets/javascripts/merge_requests/components/compare_dropdown.vue
@@ -46,11 +46,6 @@ export default {
required: false,
default: '',
},
- qaSelector: {
- type: String,
- required: false,
- default: null,
- },
},
data() {
return {
@@ -70,6 +65,12 @@ export default {
);
},
},
+ watch: {
+ default(newVal) {
+ this.current = newVal;
+ this.selected = newVal.value;
+ },
+ },
methods: {
async fetchData() {
if (!this.endpoint) return;
@@ -136,7 +137,7 @@ export default {
'gl-align-items-flex-start! gl-justify-content-start! mr-compare-dropdown',
toggleClass,
]"
- :data-qa-selector="qaSelector"
+ data-testid="source-branch-dropdown"
@shown="fetchData"
@search="searchData"
@select="selectItem"
diff --git a/app/assets/javascripts/merge_requests/components/header_metadata.vue b/app/assets/javascripts/merge_requests/components/header_metadata.vue
new file mode 100644
index 00000000000..fce7ba385b4
--- /dev/null
+++ b/app/assets/javascripts/merge_requests/components/header_metadata.vue
@@ -0,0 +1,69 @@
+<script>
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
+// eslint-disable-next-line no-restricted-imports
+import { mapGetters } from 'vuex';
+import { __ } from '~/locale';
+import { TYPE_ISSUE, WORKSPACE_PROJECT } from '~/issues/constants';
+import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
+
+export default {
+ TYPE_ISSUE,
+ WORKSPACE_PROJECT,
+ components: {
+ GlIcon,
+ ConfidentialityBadge,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ inject: ['hidden'],
+ computed: {
+ ...mapGetters(['getNoteableData']),
+ isLocked() {
+ return this.getNoteableData.discussion_locked;
+ },
+ isConfidential() {
+ return this.getNoteableData.confidential;
+ },
+ warningIconsMeta() {
+ return [
+ {
+ iconName: 'lock',
+ visible: this.isLocked,
+ dataTestId: 'locked',
+ tooltip: __('This merge request is locked. Only project members can comment.'),
+ },
+ {
+ iconName: 'spam',
+ visible: this.hidden,
+ dataTestId: 'hidden',
+ tooltip: __('This merge request is hidden because its author has been banned'),
+ },
+ ];
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-inline-block">
+ <confidentiality-badge
+ v-if="isConfidential"
+ class="gl-mr-3"
+ :issuable-type="$options.TYPE_ISSUE"
+ :workspace-type="$options.WORKSPACE_PROJECT"
+ />
+ <template v-for="meta in warningIconsMeta">
+ <div
+ v-if="meta.visible"
+ :key="meta.iconName"
+ v-gl-tooltip.bottom
+ :data-testid="meta.dataTestId"
+ :title="meta.tooltip || null"
+ class="issuable-warning-icon gl-mr-3 gl-mt-2 gl-display-flex gl-justify-content-center gl-align-items-center"
+ >
+ <gl-icon :name="meta.iconName" class="icon" />
+ </div>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/merge_requests/components/merge_request_status_badge.vue b/app/assets/javascripts/merge_requests/components/merge_request_status_badge.vue
new file mode 100644
index 00000000000..3d5478757a8
--- /dev/null
+++ b/app/assets/javascripts/merge_requests/components/merge_request_status_badge.vue
@@ -0,0 +1,74 @@
+<script>
+import Vue from 'vue';
+import { fetchPolicies } from '~/lib/graphql';
+import StatusBadge from '~/issuable/components/status_badge.vue';
+
+export const badgeState = Vue.observable({
+ state: '',
+ updateStatus: null,
+});
+
+export default {
+ components: {
+ StatusBadge,
+ },
+ inject: {
+ query: { default: null },
+ projectPath: { default: null },
+ iid: { default: null },
+ },
+ props: {
+ initialState: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ issuableType: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ if (!this.iid) {
+ return {
+ state: this.initialState,
+ };
+ }
+
+ if (!badgeState.state && this.initialState) {
+ badgeState.state = this.initialState;
+ }
+
+ return badgeState;
+ },
+ created() {
+ if (!badgeState.updateStatus) {
+ badgeState.updateStatus = this.fetchState;
+ }
+ },
+ beforeDestroy() {
+ if (badgeState.updateStatus && this.query) {
+ badgeState.updateStatus = null;
+ }
+ },
+ methods: {
+ async fetchState() {
+ const { data } = await this.$apollo.query({
+ query: this.query,
+ variables: {
+ projectPath: this.projectPath,
+ iid: this.iid,
+ },
+ fetchPolicy: fetchPolicies.NO_CACHE,
+ });
+
+ badgeState.state = data?.workspace?.issuable?.state;
+ },
+ },
+};
+</script>
+
+<template>
+ <status-badge class="gl-align-self-center gl-mr-3" :issuable-type="issuableType" :state="state" />
+</template>
diff --git a/app/assets/javascripts/merge_requests/components/sticky_header.vue b/app/assets/javascripts/merge_requests/components/sticky_header.vue
index 3c3bee9b108..c1e88a901c4 100644
--- a/app/assets/javascripts/merge_requests/components/sticky_header.vue
+++ b/app/assets/javascripts/merge_requests/components/sticky_header.vue
@@ -7,13 +7,15 @@ import { TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { isLoggedIn } from '~/lib/utils/common_utils';
-import StatusBox from '~/issuable/components/status_box.vue';
+import StatusBadge from '~/issuable/components/status_badge.vue';
+import { TYPE_MERGE_REQUEST } from '~/issues/constants';
import DiscussionCounter from '~/notes/components/discussion_counter.vue';
import TodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import titleSubscription from '../queries/title.subscription.graphql';
export default {
+ TYPE_MERGE_REQUEST,
apollo: {
$subscribe: {
title: {
@@ -41,8 +43,8 @@ export default {
GlLink,
GlSprintf,
GlBadge,
- StatusBox,
DiscussionCounter,
+ StatusBadge,
TodoWidget,
ClipboardButton,
},
@@ -115,7 +117,11 @@ export default {
:class="{ 'gl-max-w-container-xl': !isFluidLayout }"
>
<div class="gl-w-full gl-display-flex gl-align-items-baseline">
- <status-box :initial-state="getNoteableData.state" issuable-type="merge_request" />
+ <status-badge
+ class="gl-align-self-center gl-mr-3"
+ :issuable-type="$options.TYPE_MERGE_REQUEST"
+ :state="getNoteableData.state"
+ />
<a
v-safe-html:[$options.safeHtmlConfig]="titleHtml"
href="#top"
diff --git a/app/assets/javascripts/merge_requests/index.js b/app/assets/javascripts/merge_requests/index.js
new file mode 100644
index 00000000000..29218eb53e0
--- /dev/null
+++ b/app/assets/javascripts/merge_requests/index.js
@@ -0,0 +1,19 @@
+import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import HeaderMetadata from './components/header_metadata.vue';
+
+export function mountHeaderMetadata(store) {
+ const el = document.querySelector('.js-header-metadata-root');
+
+ if (!el) {
+ return null;
+ }
+
+ return new Vue({
+ el,
+ name: 'HeaderMetadataRoot',
+ store,
+ provide: { hidden: parseBoolean(el.dataset.hidden) },
+ render: (createElement) => createElement(HeaderMetadata),
+ });
+}
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index c8268b1a9ae..a7b753b7ca8 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -33,19 +33,26 @@ export default {
outputType(output) {
if (output.text) {
return 'text/plain';
- } else if (output.output_type === ERROR_OUTPUT_TYPE) {
+ }
+ if (output.output_type === ERROR_OUTPUT_TYPE) {
return 'error';
- } else if (output.data['image/png']) {
+ }
+ if (output.data['image/png']) {
return 'image/png';
- } else if (output.data['image/jpeg']) {
+ }
+ if (output.data['image/jpeg']) {
return 'image/jpeg';
- } else if (output.data['text/html']) {
+ }
+ if (output.data['text/html']) {
return 'text/html';
- } else if (output.data['text/latex']) {
+ }
+ if (output.data['text/latex']) {
return 'text/latex';
- } else if (output.data['image/svg+xml']) {
+ }
+ if (output.data['image/svg+xml']) {
return 'image/svg+xml';
- } else if (output.data[TEXT_MARKDOWN]) {
+ }
+ if (output.data[TEXT_MARKDOWN]) {
return TEXT_MARKDOWN;
}
@@ -63,21 +70,29 @@ export default {
getComponent(output) {
if (output.text) {
return CodeOutput;
- } else if (output.output_type === ERROR_OUTPUT_TYPE) {
+ }
+ if (output.output_type === ERROR_OUTPUT_TYPE) {
return ErrorOutput;
- } else if (output.data['image/png']) {
+ }
+ if (output.data['image/png']) {
return ImageOutput;
- } else if (output.data['image/jpeg']) {
+ }
+ if (output.data['image/jpeg']) {
return ImageOutput;
- } else if (isDataframe(output)) {
+ }
+ if (isDataframe(output)) {
return DataframeOutput;
- } else if (output.data['text/html']) {
+ }
+ if (output.data['text/html']) {
return HtmlOutput;
- } else if (output.data['text/latex']) {
+ }
+ if (output.data['text/latex']) {
return LatexOutput;
- } else if (output.data['image/svg+xml']) {
+ }
+ if (output.data['image/svg+xml']) {
return HtmlOutput;
- } else if (output.data[TEXT_MARKDOWN]) {
+ }
+ if (output.data[TEXT_MARKDOWN]) {
return MarkdownOutput;
}
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index a009f2975bb..144cfa4295b 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -5,7 +5,6 @@ import $ from 'jquery';
import { mapActions, mapGetters, mapState } from 'vuex';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import { createAlert } from '~/alert';
-import { badgeState } from '~/issuable/components/status_box.vue';
import { STATUS_CLOSED, STATUS_MERGED, STATUS_OPEN, STATUS_REOPENED } from '~/issues/constants';
import { containsSensitiveToken, confirmSensitiveAction } from '~/lib/utils/secret_detection';
import {
@@ -14,6 +13,7 @@ import {
slugifyWithUnderscore,
} from '~/lib/utils/text_utility';
import { sprintf } from '~/locale';
+import { badgeState } from '~/merge_requests/components/merge_request_status_badge.vue';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -210,8 +210,6 @@ export default {
methods: {
...mapActions([
'saveNote',
- 'stopPolling',
- 'restartPolling',
'removePlaceholderNotes',
'closeIssuable',
'reopenIssuable',
@@ -253,7 +251,6 @@ export default {
}
this.note = ''; // Empty textarea while being requested. Repopulate in catch
- this.stopPolling();
this.isSubmitting = true;
@@ -264,7 +261,6 @@ export default {
this.saveNote(noteData)
.then(() => {
- this.restartPolling();
this.discard();
if (withIssueAction) {
@@ -381,7 +377,10 @@ export default {
@input="onInput"
/>
</comment-field-layout>
- <div class="note-form-actions">
+ <div
+ class="note-form-actions gl-font-size-0"
+ :class="{ 'gl-display-flex gl-gap-3': hasDrafts }"
+ >
<template v-if="hasDrafts">
<gl-button
:disabled="disableSubmitButton"
@@ -404,7 +403,7 @@ export default {
<gl-form-checkbox
v-if="canSetInternalNote"
v-model="noteIsInternal"
- class="gl-mb-2"
+ class="gl-mb-2 gl-flex-basis-full"
data-testid="internal-note-checkbox"
>
{{ $options.i18n.internal }}
diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue
index 7266cdb6405..90f7a6862f0 100644
--- a/app/assets/javascripts/notes/components/discussion_filter.vue
+++ b/app/assets/javascripts/notes/components/discussion_filter.vue
@@ -137,7 +137,8 @@ export default {
filterType(value) {
if (value === 0) {
return DISCUSSION_FILTER_TYPES.ALL;
- } else if (value === 1) {
+ }
+ if (value === 1) {
return DISCUSSION_FILTER_TYPES.COMMENTS;
}
return DISCUSSION_FILTER_TYPES.HISTORY;
diff --git a/app/assets/javascripts/notes/components/mr_discussion_filter.vue b/app/assets/javascripts/notes/components/mr_discussion_filter.vue
index 08d3670ae6a..c2ac95ca56e 100644
--- a/app/assets/javascripts/notes/components/mr_discussion_filter.vue
+++ b/app/assets/javascripts/notes/components/mr_discussion_filter.vue
@@ -36,7 +36,8 @@ export default {
if (length === MR_FILTER_OPTIONS.length) {
return __('All activity');
- } else if (length > 1) {
+ }
+ if (length > 1) {
return `%{strongStart}${firstSelected.text}%{strongEnd} +${length - 1} more`;
}
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 8b43f068f11..363383fd7ad 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -160,12 +160,14 @@ export default {
filePath: this.diffFile.file_path,
refs: this.diffFile.diff_refs,
};
- } else if (this.note && this.note.position) {
+ }
+ if (this.note && this.note.position) {
return {
filePath: this.note.position.new_path,
refs: this.note.position,
};
- } else if (this.discussion && this.discussion.diff_file) {
+ }
+ if (this.discussion && this.discussion.diff_file) {
return {
filePath: this.discussion.diff_file.file_path,
refs: this.discussion.diff_file.diff_refs,
@@ -381,8 +383,8 @@ export default {
@handleSuggestDismissed="() => $emit('handleSuggestDismissed')"
/>
</comment-field-layout>
- <div class="note-form-actions">
- <p v-if="showResolveDiscussionToggle">
+ <div class="note-form-actions gl-font-size-0">
+ <template v-if="showResolveDiscussionToggle">
<label>
<template v-if="discussionResolved">
<gl-form-checkbox v-model="isUnresolving" class="js-unresolve-checkbox">
@@ -395,7 +397,7 @@ export default {
</gl-form-checkbox>
</template>
</label>
- </p>
+ </template>
<template v-if="showBatchCommentsActions">
<div class="gl-display-flex gl-flex-wrap gl-mb-n3">
@@ -432,7 +434,7 @@ export default {
</div>
</template>
<template v-else>
- <div class="gl-display-sm-flex gl-flex-wrap">
+ <div class="gl-display-sm-flex gl-flex-wrap gl-font-size-0">
<gl-button
:disabled="isDisabled"
category="primary"
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index 6fb958e810b..2524b9efdb6 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -169,7 +169,6 @@ export default {
});
},
beforeDestroy() {
- this.stopPolling();
window.removeEventListener('hashchange', this.handleHashChanged);
eventHub.$off('notesApp.updateIssuableConfidentiality', this.setConfidentiality);
},
@@ -182,7 +181,6 @@ export default {
'expandDiscussion',
'startTaskList',
'convertToDiscussion',
- 'stopPolling',
'setConfidentiality',
'fetchNotes',
]),
diff --git a/app/assets/javascripts/notes/components/sidebar_subscription.vue b/app/assets/javascripts/notes/components/sidebar_subscription.vue
index f60a17eb36b..c02c7a57dfa 100644
--- a/app/assets/javascripts/notes/components/sidebar_subscription.vue
+++ b/app/assets/javascripts/notes/components/sidebar_subscription.vue
@@ -3,7 +3,7 @@
import { mapActions } from 'vuex';
import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
import { fetchPolicies } from '~/lib/graphql';
-import { confidentialityQueries } from '~/sidebar/constants';
+import { confidentialityQueries } from '~/sidebar/queries/constants';
import { defaultClient as gqlClient } from '~/graphql_shared/issuable_client';
export default {
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 0444eca9aa7..7eb01897296 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -1,5 +1,4 @@
import $ from 'jquery';
-import Visibility from 'visibilityjs';
import Vue from 'vue';
import actionCable from '~/actioncable_consumer';
import Api from '~/api';
@@ -14,8 +13,6 @@ import updateIssueLockMutation from '~/sidebar/queries/update_issue_lock.mutatio
import updateMergeRequestLockMutation from '~/sidebar/queries/update_merge_request_lock.mutation.graphql';
import loadAwardsHandler from '~/awards_handler';
import { isInViewport, scrollToElement, isInMRPage } from '~/lib/utils/common_utils';
-import Poll from '~/lib/utils/poll';
-import { create } from '~/lib/utils/recurrence';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import sidebarTimeTrackingEventHub from '~/sidebar/event_hub';
import TaskList from '~/task_list';
@@ -30,9 +27,6 @@ import * as constants from '../constants';
import * as types from './mutation_types';
import * as utils from './utils';
-const NOTES_POLLING_INTERVAL = 6000;
-let eTagPoll;
-
export const updateLockedAttribute = ({ commit, getters }, { locked, fullPath }) => {
const { iid, targetType } = getters.getNoteableData;
@@ -152,29 +146,25 @@ export const initPolling = ({ state, dispatch, getters, commit }) => {
dispatch('setLastFetchedAt', getters.getNotesDataByProp('lastFetchedAt'));
- if (gon.features?.actionCableNotes) {
- actionCable.subscriptions.create(
- {
- channel: 'Noteable::NotesChannel',
- project_id: state.notesData.projectId,
- group_id: state.notesData.groupId,
- noteable_type: state.notesData.noteableType,
- noteable_id: state.notesData.noteableId,
+ actionCable.subscriptions.create(
+ {
+ channel: 'Noteable::NotesChannel',
+ project_id: state.notesData.projectId,
+ group_id: state.notesData.groupId,
+ noteable_type: state.notesData.noteableType,
+ noteable_id: state.notesData.noteableId,
+ },
+ {
+ connected() {
+ dispatch('fetchUpdatedNotes');
},
- {
- connected() {
+ received(data) {
+ if (data.event === 'updated') {
dispatch('fetchUpdatedNotes');
- },
- received(data) {
- if (data.event === 'updated') {
- dispatch('fetchUpdatedNotes');
- }
- },
+ }
},
- );
- } else {
- dispatch('poll');
- }
+ },
+ );
commit(types.SET_IS_POLLING_INITIALIZED, true);
};
@@ -386,7 +376,8 @@ export const resolveDiscussion = ({ state, dispatch, getters }, { discussionId }
if (!discussion) {
return Promise.reject();
- } else if (isResolved) {
+ }
+ if (isResolved) {
return Promise.resolve();
}
@@ -515,8 +506,6 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
{"commands_changes":{},"valid":false,"errors":{"commands_only":["Commands applied"]}}
*/
if (hasQuickActions && message) {
- if (eTagPoll) eTagPoll.makeRequest();
-
// synchronizing the quick action with the sidebar widget
// this is a temporary solution until we have confidentiality real-time updates
if (
@@ -624,69 +613,7 @@ export const fetchUpdatedNotes = ({ commit, state, getters, dispatch }) => {
.then(({ data }) => {
pollSuccessCallBack(data, commit, state, getters, dispatch);
})
- .catch(() => {
- createAlert({
- message: __('Something went wrong while fetching latest comments.'),
- });
- });
-};
-
-export const poll = ({ commit, state, getters, dispatch }) => {
- const notePollOccurrenceTracking = create();
- let alert;
-
- notePollOccurrenceTracking.handle(1, () => {
- // Since polling halts internally after 1 failure, we manually try one more time
- setTimeout(() => eTagPoll.restart(), NOTES_POLLING_INTERVAL);
- });
- notePollOccurrenceTracking.handle(2, () => {
- // On the second failure in a row, show the alert and try one more time (hoping to succeed and clear the error)
- alert = createAlert({
- message: __('Something went wrong while fetching latest comments.'),
- });
- setTimeout(() => eTagPoll.restart(), NOTES_POLLING_INTERVAL);
- });
-
- eTagPoll = new Poll({
- resource: {
- poll: () => {
- const { endpoint, options } = getFetchDataParams(state);
- return axios.get(endpoint, options);
- },
- },
- method: 'poll',
- successCallback: ({ data }) => {
- pollSuccessCallBack(data, commit, state, getters, dispatch);
-
- if (notePollOccurrenceTracking.count) {
- notePollOccurrenceTracking.reset();
- }
- alert?.dismiss();
- },
- errorCallback: () => notePollOccurrenceTracking.occur(),
- });
-
- if (!Visibility.hidden()) {
- eTagPoll.makeDelayedRequest(2500);
- } else {
- eTagPoll.makeRequest();
- }
-
- Visibility.change(() => {
- if (!Visibility.hidden()) {
- eTagPoll.restart();
- } else {
- eTagPoll.stop();
- }
- });
-};
-
-export const stopPolling = () => {
- if (eTagPoll) eTagPoll.stop();
-};
-
-export const restartPolling = () => {
- if (eTagPoll) eTagPoll.restart();
+ .catch(() => {});
};
export const toggleAward = ({ commit, getters }, { awardName, noteId }) => {
@@ -766,7 +693,6 @@ export const submitSuggestion = (
dispatch('resolveDiscussion', { discussionId }).catch(() => {});
commit(types.SET_RESOLVING_DISCUSSION, true);
- dispatch('stopPolling');
return Api.applySuggestion(suggestionId, message)
.then(dispatchResolveDiscussion)
@@ -786,7 +712,6 @@ export const submitSuggestion = (
})
.finally(() => {
commit(types.SET_RESOLVING_DISCUSSION, false);
- dispatch('restartPolling');
});
};
@@ -801,7 +726,6 @@ export const submitSuggestionBatch = ({ commit, dispatch, state }, { message, fl
commit(types.SET_APPLYING_BATCH_STATE, true);
commit(types.SET_RESOLVING_DISCUSSION, true);
- dispatch('stopPolling');
return Api.applySuggestionBatch(suggestionIds, message)
.then(() => Promise.all(resolveAllDiscussions()))
@@ -823,7 +747,6 @@ export const submitSuggestionBatch = ({ commit, dispatch, state }, { message, fl
.finally(() => {
commit(types.SET_APPLYING_BATCH_STATE, false);
commit(types.SET_RESOLVING_DISCUSSION, false);
- dispatch('restartPolling');
});
};
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index 3fb9913bdcb..c43430639ad 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -1,8 +1,8 @@
import { flattenDeep, clone } from 'lodash';
import { match } from '~/diffs/utils/diff_file';
-import { badgeState } from '~/issuable/components/status_box.vue';
import { isInMRPage } from '~/lib/utils/common_utils';
import { doesHashExistInUrl } from '~/lib/utils/url_utility';
+import { badgeState } from '~/merge_requests/components/merge_request_status_badge.vue';
import * as constants from '../constants';
import { collapseSystemNotes } from './collapse_utils';
diff --git a/app/assets/javascripts/observability/client.js b/app/assets/javascripts/observability/client.js
index c55600f3db2..718001e98fe 100644
--- a/app/assets/javascripts/observability/client.js
+++ b/app/assets/javascripts/observability/client.js
@@ -1,57 +1,62 @@
+import * as Sentry from '@sentry/browser';
import axios from '~/lib/utils/axios_utils';
-// import mockData from './mock_traces.json';
-
-function enableTraces() {
- // TODO remove mocks https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2271
- return new Promise((resolve) => {
- setTimeout(() => {
- resolve();
- }, 1000);
- });
-}
-function isTracingEnabled() {
- // TODO remove mocks https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2271
- return new Promise((resolve) => {
- setTimeout(() => {
- // Currently relying on manual provisioning, hence assuming tracing is enabled
- resolve(true);
- }, 1000);
- });
+function reportErrorAndThrow(e) {
+ Sentry.captureException(e);
+ throw e;
}
-
-function traceWithDuration(trace) {
- // aggregating duration on the client for now, but expecting to be coming from the backend
- // https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2274
- const duration = trace.spans[0].duration_nano;
- return {
- ...trace,
- duration: duration / 1000,
- };
+// Provisioning API spec: https://gitlab.com/gitlab-org/opstrace/opstrace/-/blob/main/provisioning-api/pkg/provisioningapi/routes.go#L59
+async function enableTraces(provisioningUrl) {
+ try {
+ // Note: axios.put(url, undefined, {withCredentials: true}) does not send cookies properly, so need to use the API below for the correct behaviour
+ return await axios(provisioningUrl, {
+ method: 'put',
+ withCredentials: true,
+ });
+ } catch (e) {
+ return reportErrorAndThrow(e);
+ }
}
-async function fetchTrace(tracingUrl, traceId) {
- if (!traceId) {
- throw new Error('traceId is required.');
+// Provisioning API spec: https://gitlab.com/gitlab-org/opstrace/opstrace/-/blob/main/provisioning-api/pkg/provisioningapi/routes.go#L37
+async function isTracingEnabled(provisioningUrl) {
+ try {
+ const { data } = await axios.get(provisioningUrl, { withCredentials: true });
+ if (data && data.status) {
+ // we currently ignore the 'status' payload and just check if the request was successful
+ // We might improve this as part of https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2315
+ return true;
+ }
+ } catch (e) {
+ if (e.response.status === 404) {
+ return false;
+ }
+ return reportErrorAndThrow(e);
}
+ return reportErrorAndThrow(new Error('Failed to check provisioning')); // eslint-disable-line @gitlab/require-i18n-strings
+}
- const { data } = await axios.get(tracingUrl, {
- withCredentials: true,
- params: {
- trace_id: traceId,
- },
- });
+async function fetchTrace(tracingUrl, traceId) {
+ try {
+ if (!traceId) {
+ throw new Error('traceId is required.');
+ }
+
+ const { data } = await axios.get(tracingUrl, {
+ withCredentials: true,
+ params: {
+ trace_id: traceId,
+ },
+ });
- // TODO: Improve local GDK dev experience with tracing https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2308
- // const data = mockData;
- // const trace = data.traces.find((t) => t.trace_id === traceId);
+ if (!Array.isArray(data.traces) || data.traces.length === 0) {
+ throw new Error('traces are missing/invalid in the response'); // eslint-disable-line @gitlab/require-i18n-strings
+ }
- if (!Array.isArray(data.traces) || data.traces.length === 0) {
- throw new Error('traces are missing/invalid in the response.'); // eslint-disable-line @gitlab/require-i18n-strings
+ return data.traces[0];
+ } catch (e) {
+ return reportErrorAndThrow(e);
}
-
- const trace = data.traces[0];
- return traceWithDuration(trace);
}
/**
@@ -164,18 +169,18 @@ function filterObjToQueryParams(filterObj) {
async function fetchTraces(tracingUrl, filters = {}) {
const filterParams = filterObjToQueryParams(filters);
- const { data } = await axios.get(tracingUrl, {
- withCredentials: true,
- params: filterParams,
- });
- // TODO: Improve local GDK dev experience with tracing https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2308
- // Uncomment the line below to test this locally
- // const data = mockData;
-
- if (!Array.isArray(data.traces)) {
- throw new Error('traces are missing/invalid in the response.'); // eslint-disable-line @gitlab/require-i18n-strings
+ try {
+ const { data } = await axios.get(tracingUrl, {
+ withCredentials: true,
+ params: filterParams,
+ });
+ if (!Array.isArray(data.traces)) {
+ throw new Error('traces are missing/invalid in the response'); // eslint-disable-line @gitlab/require-i18n-strings
+ }
+ return data.traces;
+ } catch (e) {
+ return reportErrorAndThrow(e);
}
- return data.traces.map(traceWithDuration);
}
export function buildClient({ provisioningUrl, tracingUrl }) {
diff --git a/app/assets/javascripts/observability/mock_traces.json b/app/assets/javascripts/observability/mock_traces.json
index ee59258e591..cd7dfb40af6 100644
--- a/app/assets/javascripts/observability/mock_traces.json
+++ b/app/assets/javascripts/observability/mock_traces.json
@@ -1,348 +1,107 @@
{
- "project_id": "10141740",
+ "project_id": 123,
"traces": [
{
- "timestamp": "2023-07-18T10:31:23.661285Z",
- "trace_id": "08a1b018-e1b9-88b2-094b-ca5fd40783ad",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:23.661285Z",
- "span_id": "30A9220B254C42B1",
- "trace_id": "08a1b018-e1b9-88b2-094b-ca5fd40783ad",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 250,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:17.026724Z",
- "trace_id": "1c2099e0-6da8-d5fb-a91d-bdd5a5bea82c",
- "service_name": "my-service-name2",
- "operation": "Addition",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:17.026724Z",
- "span_id": "154925D3DA2C1307",
- "trace_id": "1c2099e0-6da8-d5fb-a91d-bdd5a5bea82c",
- "service_name": "my-service-name",
- "operation": "Addition",
- "duration_nano": 208,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:21.602132Z",
- "trace_id": "f4c2f964-afee-cc2e-bd1a-c654ff55db4e",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:21.602132Z",
- "span_id": "53A4AE94DFF72A28",
- "trace_id": "f4c2f964-afee-cc2e-bd1a-c654ff55db4e",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 5125,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:14.772009Z",
- "trace_id": "fa6302ad-7214-7c05-40f7-91195356774e",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:14.772009Z",
- "span_id": "5BB240D099656820",
- "trace_id": "fa6302ad-7214-7c05-40f7-91195356774e",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 1584,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:22.623552Z",
- "trace_id": "54021e57-a25c-c6fe-1f53-542bbdbcb16c",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:22.623552Z",
- "span_id": "C5AE65D0C26BF3FD",
- "trace_id": "54021e57-a25c-c6fe-1f53-542bbdbcb16c",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 750,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:21.602156Z",
- "trace_id": "34d455cc-e518-fb4e-513f-e88030d4ccc8",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:21.602156Z",
- "span_id": "5288B61252594EB2",
- "trace_id": "34d455cc-e518-fb4e-513f-e88030d4ccc8",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 750,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:20.567364Z",
- "trace_id": "3892a93a-f4eb-b416-372e-3c9237be97e3",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:20.567364Z",
- "span_id": "1D690E5094345C98",
- "trace_id": "3892a93a-f4eb-b416-372e-3c9237be97e3",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 958,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:23.661289Z",
- "trace_id": "9d0630d5-21b5-686f-57cb-d97c647fc31f",
- "service_name": "my-service-name",
- "operation": "Addition",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:23.661289Z",
- "span_id": "8F548EE08F9C2EAC",
- "trace_id": "9d0630d5-21b5-686f-57cb-d97c647fc31f",
- "service_name": "my-service-name",
- "operation": "Addition",
- "duration_nano": 167,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:14.77197Z",
- "trace_id": "f2470b0e-3bbb-8af2-68f8-c97343fba7ee",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:14.77197Z",
- "span_id": "6B5AB710CE8A4471",
- "trace_id": "f2470b0e-3bbb-8af2-68f8-c97343fba7ee",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 5583,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:17.026712Z",
- "trace_id": "f4e64ee0-ee32-0edb-c4d1-a15f4047bdc4",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:17.026712Z",
- "span_id": "199D402DE1A29F3F",
- "trace_id": "f4e64ee0-ee32-0edb-c4d1-a15f4047bdc4",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 6959,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:20.567337Z",
- "trace_id": "344b4db1-c890-514c-b94f-425fff3a795b",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:20.567337Z",
- "span_id": "CAC38748150E5A0C",
- "trace_id": "344b4db1-c890-514c-b94f-425fff3a795b",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 3917,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:22.623559Z",
- "trace_id": "40b933be-11d7-7b41-e63a-ff7e7c5d50ab",
- "service_name": "my-service-name",
- "operation": "Addition",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:22.623559Z",
- "span_id": "3485100A27958F59",
- "trace_id": "40b933be-11d7-7b41-e63a-ff7e7c5d50ab",
- "service_name": "my-service-name",
- "operation": "Addition",
- "duration_nano": 709,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:17.026723Z",
- "trace_id": "c3347c43-316f-2b08-0b46-7d142d6764b7",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:17.026723Z",
- "span_id": "1CF28C36AB7EB3F9",
- "trace_id": "c3347c43-316f-2b08-0b46-7d142d6764b7",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 208,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:23.661272Z",
- "trace_id": "762f9104-d3db-c762-d6d7-0476ca21249f",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:23.661272Z",
- "span_id": "83D8D6D2BD99A4D1",
- "trace_id": "762f9104-d3db-c762-d6d7-0476ca21249f",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 10000,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:22.623524Z",
- "trace_id": "b46ded15-f900-fba7-7396-a6b453221038",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:22.623524Z",
- "span_id": "EB84455AE35DEAD5",
- "trace_id": "b46ded15-f900-fba7-7396-a6b453221038",
- "service_name": "my-service-name",
- "operation": "Multiplication",
- "duration_nano": 17666,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:21.60216Z",
- "trace_id": "8dcd7b90-7f94-6b19-4a8f-b681801568ba",
- "service_name": "my-service-name",
- "operation": "Addition",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:21.60216Z",
- "span_id": "A5C773414186949D",
- "trace_id": "8dcd7b90-7f94-6b19-4a8f-b681801568ba",
- "service_name": "my-service-name",
- "operation": "Addition",
- "duration_nano": 250,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:14.772014Z",
- "trace_id": "51e23c12-033d-a0db-d2b0-2f3f4e3d9fb3",
- "service_name": "my-service-name",
- "operation": "Addition",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:14.772014Z",
- "span_id": "3397060046FD4428",
- "trace_id": "51e23c12-033d-a0db-d2b0-2f3f4e3d9fb3",
- "service_name": "my-service-name",
- "operation": "Addition",
- "duration_nano": 291,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
- },
- {
- "timestamp": "2023-07-18T10:31:20.567369Z",
- "trace_id": "d54b5015-3938-ddf8-3aa1-49882503233e",
- "service_name": "my-service-name",
- "operation": "Addition",
- "statusCode": "STATUS_CODE_UNSET",
- "spans": [
- {
- "timestamp": "2023-07-18T10:31:20.567369Z",
- "span_id": "DAC36ACC2DBA8B11",
- "trace_id": "d54b5015-3938-ddf8-3aa1-49882503233e",
- "service_name": "my-service-name",
- "operation": "Addition",
- "duration_nano": 208,
- "statusCode": "STATUS_CODE_UNSET"
- }
- ],
- "totalSpans": 1
+ "timestamp": "2023-08-07T15:03:32.199806Z",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "tracegentracegentracegenttracegentracegentracegent",
+ "operation": "lets-golets-golets-goletslets-golets-golets-golets",
+ "statusCode": "STATUS_CODE_UNSET",
+ "duration_nano": 100120000,
+ "spans": [
+ {
+ "timestamp": "2023-08-07T15:03:32.199806Z",
+ "span_id": "A1FB81EB031B09E8",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "tracegentracegentracegentracegentracegentracegentracegentracegentracegentracegentracegentracegentracegen",
+ "operation": "lets-golets-golets-golets-golets-golets-golets-golets-golets-golets-golets-golets-go",
+ "duration_nano": 100120000,
+ "parent_span_id": "",
+ "statusCode": "STATUS_CODE_UNSET"
+ },
+ {
+ "timestamp": "2023-08-07T15:03:32.199871Z",
+ "span_id": "9C920500FE9C85E3",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "tracegen",
+ "operation": "okey-dokey",
+ "duration_nano": 100055000,
+ "parent_span_id": "A1FB81EB031B09E8",
+ "statusCode": "STATUS_CODE_UNSET"
+ },
+ {
+ "timestamp": "2023-08-07T15:03:53.199871Z",
+ "span_id": "FAKE",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "tracegen",
+ "operation": "okey-dokey",
+ "duration_nano": 50027500,
+ "parent_span_id": "9C920500FE9C85E3",
+ "statusCode": "STATUS_CODE_UNSET"
+ },
+ {
+ "timestamp": "2023-08-07T15:03:53.199871Z",
+ "span_id": "FAKE-2",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "fake-service-2",
+ "operation": "okey-dokey",
+ "duration_nano": 50027500,
+ "parent_span_id": "9C920500FE9C85E3",
+ "statusCode": "STATUS_CODE_UNSET"
+ },
+ {
+ "timestamp": "2023-08-07T15:04:13.199871Z",
+ "span_id": "FAKE-3",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "fake-service-3",
+ "operation": "okey-dokey",
+ "duration_nano": 30000000,
+ "parent_span_id": "FAKE-2",
+ "statusCode": "STATUS_CODE_UNSET"
+ },
+ {
+ "timestamp": "2023-08-07T15:04:13.199871Z",
+ "span_id": "FAKE-4",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "fake-service-4",
+ "operation": "okey-dokey",
+ "duration_nano": 25000000,
+ "parent_span_id": "FAKE-3",
+ "statusCode": "STATUS_CODE_UNSET"
+ },
+ {
+ "timestamp": "2023-08-07T15:04:13.199871Z",
+ "span_id": "FAKE-5",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "fake-service-5",
+ "operation": "okey-dokey",
+ "duration_nano": 10000000,
+ "parent_span_id": "FAKE-4",
+ "statusCode": "STATUS_CODE_UNSET"
+ },
+ {
+ "timestamp": "2023-08-07T15:04:13.199871Z",
+ "span_id": "FAKE-6",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "fake-service-6",
+ "operation": "okey-dokey",
+ "duration_nano": 10000000,
+ "parent_span_id": "FAKE-5",
+ "statusCode": "STATUS_CODE_UNSET"
+ },
+ {
+ "timestamp": "2023-08-07T15:04:13.199871Z",
+ "span_id": "FAKE-7",
+ "trace_id": "dabb7ae1-2501-8e57-18e1-30ab21a9ab19",
+ "service_name": "fake-service-7",
+ "operation": "okey-dokey",
+ "duration_nano": 5000000,
+ "parent_span_id": "FAKE-6",
+ "statusCode": "STATUS_CODE_UNSET"
+ }
+ ],
+ "totalSpans": 5
}
],
- "totalTraces": 18
+ "totalTraces": 50
}
diff --git a/app/assets/javascripts/organizations/constants.js b/app/assets/javascripts/organizations/constants.js
new file mode 100644
index 00000000000..8ade37b169e
--- /dev/null
+++ b/app/assets/javascripts/organizations/constants.js
@@ -0,0 +1,4 @@
+export const RESOURCE_TYPE_GROUPS = 'groups';
+export const RESOURCE_TYPE_PROJECTS = 'projects';
+
+export const ORGANIZATION_ROOT_ROUTE_NAME = 'root';
diff --git a/app/assets/javascripts/organizations/groups_and_projects/components/app.vue b/app/assets/javascripts/organizations/groups_and_projects/components/app.vue
index 10471cc1fdd..dba738de5e1 100644
--- a/app/assets/javascripts/organizations/groups_and_projects/components/app.vue
+++ b/app/assets/javascripts/organizations/groups_and_projects/components/app.vue
@@ -13,9 +13,10 @@ import {
FILTERED_SEARCH_TERM,
TOKEN_EMPTY_SEARCH_TERM,
} from '~/vue_shared/components/filtered_search_bar/constants';
+import { RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS } from '../../constants';
+import GroupsView from '../../shared/components/groups_view.vue';
+import ProjectsView from '../../shared/components/projects_view.vue';
import {
- DISPLAY_QUERY_GROUPS,
- DISPLAY_QUERY_PROJECTS,
DISPLAY_LISTBOX_ITEMS,
SORT_DIRECTION_ASC,
SORT_DIRECTION_DESC,
@@ -23,8 +24,6 @@ import {
SORT_ITEM_CREATED,
FILTERED_SEARCH_TERM_KEY,
} from '../constants';
-import GroupsPage from './groups_page.vue';
-import ProjectsPage from './projects_page.vue';
export default {
i18n: {
@@ -45,14 +44,14 @@ export default {
const { display } = this.$route.query;
switch (display) {
- case DISPLAY_QUERY_GROUPS:
- return GroupsPage;
+ case RESOURCE_TYPE_GROUPS:
+ return GroupsView;
- case DISPLAY_QUERY_PROJECTS:
- return ProjectsPage;
+ case RESOURCE_TYPE_PROJECTS:
+ return ProjectsView;
default:
- return GroupsPage;
+ return GroupsView;
}
},
activeSortItem() {
@@ -80,9 +79,9 @@ export default {
displayListboxSelected() {
const { display } = this.$route.query;
- return [DISPLAY_QUERY_GROUPS, DISPLAY_QUERY_PROJECTS].includes(display)
+ return [RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS].includes(display)
? display
- : DISPLAY_QUERY_GROUPS;
+ : RESOURCE_TYPE_GROUPS;
},
},
methods: {
diff --git a/app/assets/javascripts/organizations/groups_and_projects/components/groups_page.vue b/app/assets/javascripts/organizations/groups_and_projects/components/groups_page.vue
deleted file mode 100644
index 20db38403f7..00000000000
--- a/app/assets/javascripts/organizations/groups_and_projects/components/groups_page.vue
+++ /dev/null
@@ -1,43 +0,0 @@
-<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import { s__ } from '~/locale';
-import GroupsList from '~/vue_shared/components/groups_list/groups_list.vue';
-import groupsQuery from '../graphql/queries/groups.query.graphql';
-import { formatGroups } from '../utils';
-
-export default {
- i18n: {
- errorMessage: s__(
- 'Organization|An error occurred loading the groups. Please refresh the page to try again.',
- ),
- },
- components: { GlLoadingIcon, GroupsList },
- data() {
- return {
- groups: [],
- };
- },
- apollo: {
- groups: {
- query: groupsQuery,
- update(data) {
- return formatGroups(data.organization.groups.nodes);
- },
- error(error) {
- createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true });
- },
- },
- },
- computed: {
- isLoading() {
- return this.$apollo.queries.groups.loading;
- },
- },
-};
-</script>
-
-<template>
- <gl-loading-icon v-if="isLoading" class="gl-mt-5" size="md" />
- <groups-list v-else :groups="groups" show-group-icon />
-</template>
diff --git a/app/assets/javascripts/organizations/groups_and_projects/components/projects_page.vue b/app/assets/javascripts/organizations/groups_and_projects/components/projects_page.vue
deleted file mode 100644
index d6958ee996e..00000000000
--- a/app/assets/javascripts/organizations/groups_and_projects/components/projects_page.vue
+++ /dev/null
@@ -1,46 +0,0 @@
-<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import ProjectsList from '~/vue_shared/components/projects_list/projects_list.vue';
-import { createAlert } from '~/alert';
-import projectsQuery from '../graphql/queries/projects.query.graphql';
-import { formatProjects } from '../utils';
-
-export default {
- i18n: {
- errorMessage: s__(
- 'Organization|An error occurred loading the projects. Please refresh the page to try again.',
- ),
- },
- components: {
- ProjectsList,
- GlLoadingIcon,
- },
- data() {
- return {
- projects: [],
- };
- },
- apollo: {
- projects: {
- query: projectsQuery,
- update(data) {
- return formatProjects(data.organization.projects.nodes);
- },
- error(error) {
- createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true });
- },
- },
- },
- computed: {
- isLoading() {
- return this.$apollo.queries.projects.loading;
- },
- },
-};
-</script>
-
-<template>
- <gl-loading-icon v-if="isLoading" class="gl-mt-5" size="md" />
- <projects-list v-else :projects="projects" show-project-icon />
-</template>
diff --git a/app/assets/javascripts/organizations/groups_and_projects/constants.js b/app/assets/javascripts/organizations/groups_and_projects/constants.js
index 529caa666a0..d79b632f6fb 100644
--- a/app/assets/javascripts/organizations/groups_and_projects/constants.js
+++ b/app/assets/javascripts/organizations/groups_and_projects/constants.js
@@ -3,8 +3,6 @@ import { __ } from '~/locale';
export const DISPLAY_QUERY_GROUPS = 'groups';
export const DISPLAY_QUERY_PROJECTS = 'projects';
-export const ORGANIZATION_ROOT_ROUTE_NAME = 'root';
-
export const FILTERED_SEARCH_TERM_KEY = 'search';
export const DISPLAY_LISTBOX_ITEMS = [
diff --git a/app/assets/javascripts/organizations/groups_and_projects/graphql/resolvers.js b/app/assets/javascripts/organizations/groups_and_projects/graphql/resolvers.js
deleted file mode 100644
index 8a375b28797..00000000000
--- a/app/assets/javascripts/organizations/groups_and_projects/graphql/resolvers.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import {
- organization,
- organizationProjects,
- organizationGroups,
-} from 'jest/organizations/groups_and_projects/mock_data';
-
-export default {
- Query: {
- organization: async () => {
- // Simulate API loading
- await new Promise((resolve) => {
- setTimeout(resolve, 1000);
- });
-
- return {
- ...organization,
- projects: organizationProjects,
- groups: organizationGroups,
- };
- },
- },
-};
diff --git a/app/assets/javascripts/organizations/groups_and_projects/index.js b/app/assets/javascripts/organizations/groups_and_projects/index.js
index f3f15c635f1..3e05e4d0a4c 100644
--- a/app/assets/javascripts/organizations/groups_and_projects/index.js
+++ b/app/assets/javascripts/organizations/groups_and_projects/index.js
@@ -2,9 +2,10 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import VueRouter from 'vue-router';
import createDefaultClient from '~/lib/graphql';
-import resolvers from './graphql/resolvers';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { ORGANIZATION_ROOT_ROUTE_NAME } from '../constants';
+import resolvers from '../shared/graphql/resolvers';
import App from './components/app.vue';
-import { ORGANIZATION_ROOT_ROUTE_NAME } from './constants';
export const createRouter = () => {
const routes = [{ path: '/', name: ORGANIZATION_ROOT_ROUTE_NAME }];
@@ -23,6 +24,16 @@ export const initOrganizationsGroupsAndProjects = () => {
if (!el) return false;
+ const {
+ dataset: { appData },
+ } = el;
+ const {
+ projectsEmptyStateSvgPath,
+ groupsEmptyStateSvgPath,
+ newGroupPath,
+ newProjectPath,
+ } = convertObjectPropsToCamelCase(JSON.parse(appData));
+
Vue.use(VueRouter);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(resolvers),
@@ -34,6 +45,12 @@ export const initOrganizationsGroupsAndProjects = () => {
name: 'OrganizationsGroupsAndProjects',
apolloProvider,
router,
+ provide: {
+ projectsEmptyStateSvgPath,
+ groupsEmptyStateSvgPath,
+ newGroupPath,
+ newProjectPath,
+ },
render(createElement) {
return createElement(App);
},
diff --git a/app/assets/javascripts/organizations/groups_and_projects/utils.js b/app/assets/javascripts/organizations/groups_and_projects/utils.js
deleted file mode 100644
index d2a4e05e806..00000000000
--- a/app/assets/javascripts/organizations/groups_and_projects/utils.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/projects_list/constants';
-
-export const formatProjects = (projects) =>
- projects.map(({ id, nameWithNamespace, accessLevel, webUrl, ...project }) => ({
- ...project,
- id: getIdFromGraphQLId(id),
- name: nameWithNamespace,
- permissions: {
- projectAccess: {
- accessLevel: accessLevel.integerValue,
- },
- },
- webUrl,
- editPath: `${webUrl}/edit`,
- actions: [ACTION_EDIT, ACTION_DELETE],
- }));
-
-export const formatGroups = (groups) =>
- groups.map(({ id, ...group }) => ({
- ...group,
- id: getIdFromGraphQLId(id),
- }));
diff --git a/app/assets/javascripts/organizations/mock_data.js b/app/assets/javascripts/organizations/mock_data.js
new file mode 100644
index 00000000000..17ab7bd1d34
--- /dev/null
+++ b/app/assets/javascripts/organizations/mock_data.js
@@ -0,0 +1,258 @@
+/* eslint-disable @gitlab/require-i18n-strings */
+
+// This is temporary mock data that will be removed when completing the following:
+// https://gitlab.com/gitlab-org/gitlab/-/issues/420777
+// https://gitlab.com/gitlab-org/gitlab/-/issues/421441
+
+export const organization = {
+ id: 'gid://gitlab/Organization/1',
+ __typename: 'Organization',
+};
+
+export const organizationProjects = {
+ nodes: [
+ {
+ id: 'gid://gitlab/Project/8',
+ nameWithNamespace: 'Twitter / Typeahead.Js',
+ webUrl: 'http://127.0.0.1:3000/twitter/Typeahead.Js',
+ topics: ['JavaScript', 'Vue.js'],
+ forksCount: 4,
+ avatarUrl: null,
+ starCount: 0,
+ visibility: 'public',
+ openIssuesCount: 48,
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:59" dir="auto">Optio et reprehenderit enim doloremque deserunt et commodi.</p>',
+ issuesAccessLevel: 'enabled',
+ forkingAccessLevel: 'enabled',
+ isForked: true,
+ accessLevel: {
+ integerValue: 30,
+ },
+ },
+ {
+ id: 'gid://gitlab/Project/7',
+ nameWithNamespace: 'Flightjs / Flight',
+ webUrl: 'http://127.0.0.1:3000/flightjs/Flight',
+ topics: [],
+ forksCount: 0,
+ avatarUrl: null,
+ starCount: 0,
+ visibility: 'private',
+ openIssuesCount: 37,
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:49" dir="auto">Dolor dicta rerum et ut eius voluptate earum qui.</p>',
+ issuesAccessLevel: 'enabled',
+ forkingAccessLevel: 'enabled',
+ isForked: false,
+ accessLevel: {
+ integerValue: 20,
+ },
+ },
+ {
+ id: 'gid://gitlab/Project/6',
+ nameWithNamespace: 'Jashkenas / Underscore',
+ webUrl: 'http://127.0.0.1:3000/jashkenas/Underscore',
+ topics: [],
+ forksCount: 0,
+ avatarUrl: null,
+ starCount: 0,
+ visibility: 'private',
+ openIssuesCount: 34,
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:52" dir="auto">Incidunt est aliquam autem nihil eveniet quis autem.</p>',
+ issuesAccessLevel: 'enabled',
+ forkingAccessLevel: 'enabled',
+ isForked: false,
+ accessLevel: {
+ integerValue: 40,
+ },
+ },
+ {
+ id: 'gid://gitlab/Project/5',
+ nameWithNamespace: 'Commit451 / Lab Coat',
+ webUrl: 'http://127.0.0.1:3000/Commit451/lab-coat',
+ topics: [],
+ forksCount: 0,
+ avatarUrl: null,
+ starCount: 0,
+ visibility: 'internal',
+ openIssuesCount: 49,
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:34" dir="auto">Sint eos dolorem impedit rerum et.</p>',
+ issuesAccessLevel: 'enabled',
+ forkingAccessLevel: 'enabled',
+ isForked: false,
+ accessLevel: {
+ integerValue: 10,
+ },
+ },
+ {
+ id: 'gid://gitlab/Project/1',
+ nameWithNamespace: 'Toolbox / Gitlab Smoke Tests',
+ webUrl: 'http://127.0.0.1:3000/toolbox/gitlab-smoke-tests',
+ topics: [],
+ forksCount: 0,
+ avatarUrl: null,
+ starCount: 0,
+ visibility: 'internal',
+ openIssuesCount: 34,
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:40" dir="auto">Veritatis error laboriosam libero autem.</p>',
+ issuesAccessLevel: 'enabled',
+ forkingAccessLevel: 'enabled',
+ isForked: false,
+ accessLevel: {
+ integerValue: 30,
+ },
+ },
+ ],
+};
+
+export const organizationGroups = {
+ nodes: [
+ {
+ id: 'gid://gitlab/Group/29',
+ fullName: 'Commit451',
+ parent: null,
+ webUrl: 'http://127.0.0.1:3000/groups/Commit451',
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:52" dir="auto">Autem praesentium vel ut ratione itaque ullam culpa.</p>',
+ avatarUrl: null,
+ descendantGroupsCount: 0,
+ projectsCount: 3,
+ groupMembersCount: 2,
+ visibility: 'public',
+ accessLevel: {
+ integerValue: 30,
+ },
+ },
+ {
+ id: 'gid://gitlab/Group/33',
+ fullName: 'Flightjs',
+ parent: null,
+ webUrl: 'http://127.0.0.1:3000/groups/flightjs',
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:60" dir="auto">Ipsa reiciendis deleniti officiis illum nostrum quo aliquam.</p>',
+ avatarUrl: null,
+ descendantGroupsCount: 4,
+ projectsCount: 3,
+ groupMembersCount: 1,
+ visibility: 'private',
+ accessLevel: {
+ integerValue: 20,
+ },
+ },
+ {
+ id: 'gid://gitlab/Group/24',
+ fullName: 'Gitlab Org',
+ parent: null,
+ webUrl: 'http://127.0.0.1:3000/groups/gitlab-org',
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:64" dir="auto">Dolorem dolorem omnis impedit cupiditate pariatur officia velit.</p>',
+ avatarUrl: null,
+ descendantGroupsCount: 1,
+ projectsCount: 1,
+ groupMembersCount: 2,
+ visibility: 'internal',
+ accessLevel: {
+ integerValue: 10,
+ },
+ },
+ {
+ id: 'gid://gitlab/Group/27',
+ fullName: 'Gnuwget',
+ parent: null,
+ webUrl: 'http://127.0.0.1:3000/groups/gnuwgetf',
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:47" dir="auto">Culpa soluta aut eius dolores est vel sapiente.</p>',
+ avatarUrl: null,
+ descendantGroupsCount: 4,
+ projectsCount: 2,
+ groupMembersCount: 3,
+ visibility: 'public',
+ accessLevel: {
+ integerValue: 40,
+ },
+ },
+ {
+ id: 'gid://gitlab/Group/31',
+ fullName: 'Jashkenas',
+ parent: null,
+ webUrl: 'http://127.0.0.1:3000/groups/jashkenas',
+ descriptionHtml: '<p data-sourcepos="1:1-1:25" dir="auto">Ut ut id aliquid nostrum.</p>',
+ avatarUrl: null,
+ descendantGroupsCount: 3,
+ projectsCount: 3,
+ groupMembersCount: 10,
+ visibility: 'private',
+ accessLevel: {
+ integerValue: 10,
+ },
+ },
+ {
+ id: 'gid://gitlab/Group/22',
+ fullName: 'Toolbox',
+ parent: null,
+ webUrl: 'http://127.0.0.1:3000/groups/toolbox',
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:46" dir="auto">Quo voluptatem magnam facere voluptates alias.</p>',
+ avatarUrl: null,
+ descendantGroupsCount: 2,
+ projectsCount: 3,
+ groupMembersCount: 40,
+ visibility: 'internal',
+ accessLevel: {
+ integerValue: 30,
+ },
+ },
+ {
+ id: 'gid://gitlab/Group/35',
+ fullName: 'Twitter',
+ parent: null,
+ webUrl: 'http://127.0.0.1:3000/groups/twitter',
+ descriptionHtml:
+ '<p data-sourcepos="1:1-1:40" dir="auto">Quae nulla consequatur assumenda id quo.</p>',
+ avatarUrl: null,
+ descendantGroupsCount: 20,
+ projectsCount: 30,
+ groupMembersCount: 100,
+ visibility: 'public',
+ accessLevel: {
+ integerValue: 40,
+ },
+ },
+ {
+ id: 'gid://gitlab/Group/73',
+ fullName: 'test',
+ parent: null,
+ webUrl: 'http://127.0.0.1:3000/groups/test',
+ descriptionHtml: '',
+ avatarUrl: null,
+ descendantGroupsCount: 1,
+ projectsCount: 1,
+ groupMembersCount: 1,
+ visibility: 'private',
+ accessLevel: {
+ integerValue: 30,
+ },
+ },
+ {
+ id: 'gid://gitlab/Group/74',
+ fullName: 'Twitter / test subgroup',
+ parent: {
+ id: 'gid://gitlab/Group/35',
+ },
+ webUrl: 'http://127.0.0.1:3000/groups/twitter/test-subgroup',
+ descriptionHtml: '',
+ avatarUrl: null,
+ descendantGroupsCount: 4,
+ projectsCount: 4,
+ groupMembersCount: 4,
+ visibility: 'internal',
+ accessLevel: {
+ integerValue: 20,
+ },
+ },
+ ],
+};
diff --git a/app/assets/javascripts/organizations/shared/components/groups_view.vue b/app/assets/javascripts/organizations/shared/components/groups_view.vue
new file mode 100644
index 00000000000..eaa3017ef97
--- /dev/null
+++ b/app/assets/javascripts/organizations/shared/components/groups_view.vue
@@ -0,0 +1,82 @@
+<script>
+import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
+import { createAlert } from '~/alert';
+import { s__, __ } from '~/locale';
+import GroupsList from '~/vue_shared/components/groups_list/groups_list.vue';
+import groupsQuery from '../graphql/queries/groups.query.graphql';
+import { formatGroups } from '../utils';
+
+export default {
+ i18n: {
+ errorMessage: s__(
+ 'Organization|An error occurred loading the groups. Please refresh the page to try again.',
+ ),
+ emptyState: {
+ title: s__("Organization|You don't have any groups yet."),
+ description: s__(
+ 'Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder.',
+ ),
+ primaryButtonText: __('New group'),
+ },
+ },
+ components: { GlLoadingIcon, GlEmptyState, GroupsList },
+ inject: {
+ groupsEmptyStateSvgPath: {},
+ newGroupPath: {
+ default: null,
+ },
+ },
+ props: {
+ shouldShowEmptyStateButtons: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ groups: [],
+ };
+ },
+ apollo: {
+ groups: {
+ query: groupsQuery,
+ update(data) {
+ return formatGroups(data.organization.groups.nodes);
+ },
+ error(error) {
+ createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true });
+ },
+ },
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.groups.loading;
+ },
+ emptyStateProps() {
+ const baseProps = {
+ svgHeight: 144,
+ svgPath: this.groupsEmptyStateSvgPath,
+ title: this.$options.i18n.emptyState.title,
+ description: this.$options.i18n.emptyState.description,
+ };
+
+ if (this.shouldShowEmptyStateButtons && this.newGroupPath) {
+ return {
+ ...baseProps,
+ primaryButtonLink: this.newGroupPath,
+ primaryButtonText: this.$options.i18n.emptyState.primaryButtonText,
+ };
+ }
+
+ return baseProps;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-loading-icon v-if="isLoading" class="gl-mt-5" size="md" />
+ <groups-list v-else-if="groups.length" :groups="groups" show-group-icon />
+ <gl-empty-state v-else v-bind="emptyStateProps" />
+</template>
diff --git a/app/assets/javascripts/organizations/shared/components/projects_view.vue b/app/assets/javascripts/organizations/shared/components/projects_view.vue
new file mode 100644
index 00000000000..9bf4e597884
--- /dev/null
+++ b/app/assets/javascripts/organizations/shared/components/projects_view.vue
@@ -0,0 +1,86 @@
+<script>
+import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import ProjectsList from '~/vue_shared/components/projects_list/projects_list.vue';
+import { createAlert } from '~/alert';
+import projectsQuery from '../graphql/queries/projects.query.graphql';
+import { formatProjects } from '../utils';
+
+export default {
+ i18n: {
+ errorMessage: s__(
+ 'Organization|An error occurred loading the projects. Please refresh the page to try again.',
+ ),
+ emptyState: {
+ title: s__("Organization|You don't have any projects yet."),
+ description: s__(
+ 'GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab.',
+ ),
+ primaryButtonText: __('New project'),
+ },
+ },
+ components: {
+ ProjectsList,
+ GlLoadingIcon,
+ GlEmptyState,
+ },
+ inject: {
+ projectsEmptyStateSvgPath: {},
+ newProjectPath: {
+ default: null,
+ },
+ },
+ props: {
+ shouldShowEmptyStateButtons: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ projects: [],
+ };
+ },
+ apollo: {
+ projects: {
+ query: projectsQuery,
+ update(data) {
+ return formatProjects(data.organization.projects.nodes);
+ },
+ error(error) {
+ createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true });
+ },
+ },
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.projects.loading;
+ },
+ emptyStateProps() {
+ const baseProps = {
+ svgHeight: 144,
+ svgPath: this.projectsEmptyStateSvgPath,
+ title: this.$options.i18n.emptyState.title,
+ description: this.$options.i18n.emptyState.description,
+ };
+
+ if (this.shouldShowEmptyStateButtons && this.newProjectPath) {
+ return {
+ ...baseProps,
+ primaryButtonLink: this.newProjectPath,
+ primaryButtonText: this.$options.i18n.emptyState.primaryButtonText,
+ };
+ }
+
+ return baseProps;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-loading-icon v-if="isLoading" class="gl-mt-5" size="md" />
+ <projects-list v-else-if="projects.length" :projects="projects" show-project-icon />
+ <gl-empty-state v-else v-bind="emptyStateProps" />
+</template>
diff --git a/app/assets/javascripts/organizations/groups_and_projects/graphql/queries/groups.query.graphql b/app/assets/javascripts/organizations/shared/graphql/queries/groups.query.graphql
index 842c601e326..842c601e326 100644
--- a/app/assets/javascripts/organizations/groups_and_projects/graphql/queries/groups.query.graphql
+++ b/app/assets/javascripts/organizations/shared/graphql/queries/groups.query.graphql
diff --git a/app/assets/javascripts/organizations/groups_and_projects/graphql/queries/projects.query.graphql b/app/assets/javascripts/organizations/shared/graphql/queries/projects.query.graphql
index 2a7971e1106..2a7971e1106 100644
--- a/app/assets/javascripts/organizations/groups_and_projects/graphql/queries/projects.query.graphql
+++ b/app/assets/javascripts/organizations/shared/graphql/queries/projects.query.graphql
diff --git a/app/assets/javascripts/organizations/shared/graphql/resolvers.js b/app/assets/javascripts/organizations/shared/graphql/resolvers.js
new file mode 100644
index 00000000000..c78266b0476
--- /dev/null
+++ b/app/assets/javascripts/organizations/shared/graphql/resolvers.js
@@ -0,0 +1,18 @@
+import { organization, organizationProjects, organizationGroups } from '../../mock_data';
+
+export default {
+ Query: {
+ organization: async () => {
+ // Simulate API loading
+ await new Promise((resolve) => {
+ setTimeout(resolve, 1000);
+ });
+
+ return {
+ ...organization,
+ projects: organizationProjects,
+ groups: organizationGroups,
+ };
+ },
+ },
+};
diff --git a/app/assets/javascripts/organizations/shared/utils.js b/app/assets/javascripts/organizations/shared/utils.js
new file mode 100644
index 00000000000..c1aafefc553
--- /dev/null
+++ b/app/assets/javascripts/organizations/shared/utils.js
@@ -0,0 +1,26 @@
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+
+export const formatProjects = (projects) =>
+ projects.map(({ id, nameWithNamespace, accessLevel, webUrl, ...project }) => ({
+ ...project,
+ id: getIdFromGraphQLId(id),
+ name: nameWithNamespace,
+ permissions: {
+ projectAccess: {
+ accessLevel: accessLevel.integerValue,
+ },
+ },
+ webUrl,
+ editPath: `${webUrl}/edit`,
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+ }));
+
+export const formatGroups = (groups) =>
+ groups.map(({ id, webUrl, ...group }) => ({
+ ...group,
+ id: getIdFromGraphQLId(id),
+ webUrl,
+ editPath: `${webUrl}/-/edit`,
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+ }));
diff --git a/app/assets/javascripts/organizations/show/components/app.vue b/app/assets/javascripts/organizations/show/components/app.vue
new file mode 100644
index 00000000000..47264d80454
--- /dev/null
+++ b/app/assets/javascripts/organizations/show/components/app.vue
@@ -0,0 +1,37 @@
+<script>
+import OrganizationAvatar from './organization_avatar.vue';
+import GroupsAndProjects from './groups_and_projects.vue';
+import AssociationCounts from './association_counts.vue';
+
+export default {
+ name: 'OrganizationShowApp',
+ components: { OrganizationAvatar, GroupsAndProjects, AssociationCounts },
+ props: {
+ organization: {
+ type: Object,
+ required: true,
+ },
+ groupsAndProjectsOrganizationPath: {
+ type: String,
+ required: true,
+ },
+ associationCounts: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-py-6">
+ <organization-avatar :organization="organization" />
+ <association-counts
+ :association-counts="associationCounts"
+ :groups-and-projects-organization-path="groupsAndProjectsOrganizationPath"
+ />
+ <groups-and-projects
+ :groups-and-projects-organization-path="groupsAndProjectsOrganizationPath"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/organizations/show/components/association_count_card.vue b/app/assets/javascripts/organizations/show/components/association_count_card.vue
new file mode 100644
index 00000000000..0567f43132f
--- /dev/null
+++ b/app/assets/javascripts/organizations/show/components/association_count_card.vue
@@ -0,0 +1,54 @@
+<script>
+import { GlIcon, GlLink, GlCard } from '@gitlab/ui';
+import { numberToMetricPrefix } from '~/lib/utils/number_utils';
+import { __ } from '~/locale';
+
+export default {
+ name: 'AssociationCountCard',
+ components: { GlIcon, GlLink, GlCard },
+ props: {
+ title: {
+ type: String,
+ required: true,
+ },
+ iconName: {
+ type: String,
+ required: true,
+ },
+ count: {
+ type: Number,
+ required: true,
+ },
+ linkHref: {
+ type: String,
+ required: true,
+ },
+ linkText: {
+ type: String,
+ required: false,
+ default: __('View all'),
+ },
+ },
+ computed: {
+ formattedCount() {
+ return numberToMetricPrefix(this.count, 0);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-card>
+ <div class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
+ <div class="gl-display-flex gl-align-items-center gl-text-gray-700">
+ <gl-icon :name="iconName" />
+ <span class="gl-ml-2">{{ title }}</span>
+ </div>
+ <gl-link :href="linkHref">{{ linkText }}</gl-link>
+ </div>
+ <span
+ class="gl-font-size-h-display gl-font-weight-bold gl-line-height-ratio-1000 gl-mt-2 gl-display-block"
+ >{{ formattedCount }}</span
+ >
+ </gl-card>
+</template>
diff --git a/app/assets/javascripts/organizations/show/components/association_counts.vue b/app/assets/javascripts/organizations/show/components/association_counts.vue
new file mode 100644
index 00000000000..3b312924bd2
--- /dev/null
+++ b/app/assets/javascripts/organizations/show/components/association_counts.vue
@@ -0,0 +1,71 @@
+<script>
+import { __, s__ } from '~/locale';
+import { RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS } from '../../constants';
+import AssociationCountCard from './association_count_card.vue';
+
+export default {
+ name: 'AssociationCounts',
+ i18n: {
+ groups: __('Groups'),
+ projects: __('Projects'),
+ users: __('Users'),
+ viewAll: __('View all'),
+ manage: s__('Organization|Manage'),
+ },
+ components: { AssociationCountCard },
+ props: {
+ associationCounts: {
+ type: Object,
+ required: true,
+ },
+ groupsAndProjectsOrganizationPath: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ groupsLinkHref() {
+ return `${this.groupsAndProjectsOrganizationPath}?display=${RESOURCE_TYPE_GROUPS}`;
+ },
+ projectsLinkHref() {
+ return `${this.groupsAndProjectsOrganizationPath}?display=${RESOURCE_TYPE_PROJECTS}`;
+ },
+ associationCountCards() {
+ return [
+ {
+ title: this.$options.i18n.groups,
+ iconName: 'group',
+ count: this.associationCounts.groups,
+ linkHref: this.groupsLinkHref,
+ },
+ {
+ title: this.$options.i18n.projects,
+ iconName: 'project',
+ count: this.associationCounts.projects,
+ linkHref: this.projectsLinkHref,
+ },
+ {
+ title: this.$options.i18n.users,
+ iconName: 'users',
+ count: this.associationCounts.users,
+ linkText: this.$options.i18n.manage,
+ // TODO: update `linkHref` prop to point to users route
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/409313
+ linkHref: '/',
+ },
+ ];
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-grid gl-lg-grid-template-columns-4 gl-mt-5 gl-gap-5">
+ <association-count-card
+ v-for="props in associationCountCards"
+ :key="props.title"
+ v-bind="props"
+ class="gl-w-full"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/organizations/show/components/groups_and_projects.vue b/app/assets/javascripts/organizations/show/components/groups_and_projects.vue
new file mode 100644
index 00000000000..e8972f3b380
--- /dev/null
+++ b/app/assets/javascripts/organizations/show/components/groups_and_projects.vue
@@ -0,0 +1,110 @@
+<script>
+import { GlCollapsibleListbox, GlLink } from '@gitlab/ui';
+import { isEqual } from 'lodash';
+import { s__, __ } from '~/locale';
+import GroupsView from '../../shared/components/groups_view.vue';
+import ProjectsView from '../../shared/components/projects_view.vue';
+import { RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS } from '../../constants';
+import { FILTER_FREQUENTLY_VISITED } from '../constants';
+import { buildDisplayListboxItem } from '../utils';
+
+export default {
+ name: 'OrganizationFrontPageGroupsAndProjects',
+ i18n: {
+ displayListboxLabel: __('Display'),
+ viewAll: s__('Organization|View all'),
+ },
+ displayListboxLabelId: 'display-listbox-label',
+ components: { GlCollapsibleListbox, GlLink },
+ displayListboxItems: [
+ buildDisplayListboxItem({
+ filter: FILTER_FREQUENTLY_VISITED,
+ resourceType: RESOURCE_TYPE_PROJECTS,
+ text: s__('Organization|Frequently visited projects'),
+ }),
+ buildDisplayListboxItem({
+ filter: FILTER_FREQUENTLY_VISITED,
+ resourceType: RESOURCE_TYPE_GROUPS,
+ text: s__('Organization|Frequently visited groups'),
+ }),
+ ],
+ props: {
+ groupsAndProjectsOrganizationPath: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ displayListboxSelected() {
+ const { display } = this.$route.query;
+ const [{ value: fallbackSelected }] = this.$options.displayListboxItems;
+
+ return (
+ this.$options.displayListboxItems.find(({ value }) => value === display)?.value ||
+ fallbackSelected
+ );
+ },
+ resourceTypeSelected() {
+ return [RESOURCE_TYPE_PROJECTS, RESOURCE_TYPE_GROUPS].find((resourceType) =>
+ this.displayListboxSelected.endsWith(resourceType),
+ );
+ },
+ routerView() {
+ switch (this.resourceTypeSelected) {
+ case RESOURCE_TYPE_GROUPS:
+ return GroupsView;
+
+ case RESOURCE_TYPE_PROJECTS:
+ return ProjectsView;
+
+ default:
+ return ProjectsView;
+ }
+ },
+ groupsAndProjectsOrganizationPathWithQueryParam() {
+ return `${this.groupsAndProjectsOrganizationPath}?display=${this.resourceTypeSelected}`;
+ },
+ },
+ methods: {
+ pushQuery(query) {
+ const currentQuery = this.$route.query;
+
+ if (isEqual(currentQuery, query)) {
+ return;
+ }
+
+ this.$router.push({ query });
+ },
+ onDisplayListboxSelect(display) {
+ this.pushQuery({ display });
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-mt-7">
+ <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
+ <div>
+ <label
+ :id="$options.displayListboxLabelId"
+ class="gl-display-block gl-mb-2"
+ data-testid="label"
+ >{{ $options.i18n.displayListboxLabel }}</label
+ >
+ <gl-collapsible-listbox
+ block
+ toggle-class="gl-w-30"
+ :selected="displayListboxSelected"
+ :items="$options.displayListboxItems"
+ :toggle-aria-labelled-by="$options.displayListboxLabelId"
+ @select="onDisplayListboxSelect"
+ />
+ </div>
+ <gl-link class="gl-mt-5" :href="groupsAndProjectsOrganizationPathWithQueryParam">{{
+ $options.i18n.viewAll
+ }}</gl-link>
+ </div>
+ <component :is="routerView" should-show-empty-state-buttons class="gl-mt-5" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/organizations/show/components/organization_avatar.vue b/app/assets/javascripts/organizations/show/components/organization_avatar.vue
new file mode 100644
index 00000000000..c57ee0ea5b5
--- /dev/null
+++ b/app/assets/javascripts/organizations/show/components/organization_avatar.vue
@@ -0,0 +1,71 @@
+<script>
+import { GlAvatar, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import {
+ VISIBILITY_TYPE_ICON,
+ ORGANIZATION_VISIBILITY_TYPE,
+ VISIBILITY_LEVEL_PUBLIC_STRING,
+} from '~/visibility_level/constants';
+
+export default {
+ name: 'OrganizationAvatar',
+ AVATAR_SHAPE_OPTION_RECT,
+ i18n: {
+ copyButtonText: s__('Organization|Copy organization ID'),
+ orgId: s__('Organization|Org ID'),
+ },
+ components: { GlAvatar, GlIcon, ClipboardButton },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ organization: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ visibilityIcon() {
+ return VISIBILITY_TYPE_ICON[VISIBILITY_LEVEL_PUBLIC_STRING];
+ },
+ visibilityTooltip() {
+ return ORGANIZATION_VISIBILITY_TYPE[VISIBILITY_LEVEL_PUBLIC_STRING];
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-flex gl-align-items-center">
+ <gl-avatar
+ :entity-id="organization.id"
+ :entity-name="organization.name"
+ :shape="$options.AVATAR_SHAPE_OPTION_RECT"
+ :size="64"
+ />
+ <div class="gl-ml-3">
+ <div class="gl-display-flex gl-align-items-center">
+ <h1 class="gl-m-0 gl-font-size-h1">{{ organization.name }}</h1>
+ <gl-icon
+ v-gl-tooltip="visibilityTooltip"
+ :name="visibilityIcon"
+ class="gl-text-secondary gl-ml-3"
+ />
+ </div>
+ <div class="gl-display-flex gl-align-items-center">
+ <span class="gl-text-secondary gl-font-sm"
+ >{{ $options.i18n.orgId }}: {{ organization.id }}</span
+ >
+ <clipboard-button
+ class="gl-ml-2"
+ category="tertiary"
+ size="small"
+ :title="$options.i18n.copyButtonText"
+ :text="organization.id.toString()"
+ />
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/organizations/show/constants.js b/app/assets/javascripts/organizations/show/constants.js
new file mode 100644
index 00000000000..fe29af67f6b
--- /dev/null
+++ b/app/assets/javascripts/organizations/show/constants.js
@@ -0,0 +1 @@
+export const FILTER_FREQUENTLY_VISITED = 'frequently_visited';
diff --git a/app/assets/javascripts/organizations/show/index.js b/app/assets/javascripts/organizations/show/index.js
new file mode 100644
index 00000000000..83a9c37e325
--- /dev/null
+++ b/app/assets/javascripts/organizations/show/index.js
@@ -0,0 +1,63 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import VueApollo from 'vue-apollo';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import createDefaultClient from '~/lib/graphql';
+import { ORGANIZATION_ROOT_ROUTE_NAME } from '../constants';
+import resolvers from '../shared/graphql/resolvers';
+import App from './components/app.vue';
+
+export const createRouter = () => {
+ const routes = [{ path: '/', name: ORGANIZATION_ROOT_ROUTE_NAME }];
+
+ const router = new VueRouter({
+ routes,
+ base: '/',
+ mode: 'history',
+ });
+
+ return router;
+};
+
+export const initOrganizationsShow = () => {
+ const el = document.getElementById('js-organizations-show');
+
+ if (!el) return false;
+
+ const {
+ dataset: { appData },
+ } = el;
+ const {
+ organization,
+ groupsAndProjectsOrganizationPath,
+ projectsEmptyStateSvgPath,
+ groupsEmptyStateSvgPath,
+ newGroupPath,
+ newProjectPath,
+ associationCounts,
+ } = convertObjectPropsToCamelCase(JSON.parse(appData));
+
+ Vue.use(VueRouter);
+ const router = createRouter();
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(resolvers),
+ });
+
+ return new Vue({
+ el,
+ name: 'OrganizationShowRoot',
+ apolloProvider,
+ router,
+ provide: {
+ projectsEmptyStateSvgPath,
+ groupsEmptyStateSvgPath,
+ newGroupPath,
+ newProjectPath,
+ },
+ render(createElement) {
+ return createElement(App, {
+ props: { organization, groupsAndProjectsOrganizationPath, associationCounts },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/organizations/show/utils.js b/app/assets/javascripts/organizations/show/utils.js
new file mode 100644
index 00000000000..b4f935563aa
--- /dev/null
+++ b/app/assets/javascripts/organizations/show/utils.js
@@ -0,0 +1,4 @@
+export const buildDisplayListboxItem = ({ filter, resourceType, text }) => ({
+ text,
+ value: `${filter}_${resourceType}`,
+});
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js
index afddf78203d..7040f42398e 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/index.js
@@ -4,7 +4,7 @@ import { parseBoolean } from '~/lib/utils/common_utils';
import PerformancePlugin from '~/performance/vue_performance_plugin';
import Translate from '~/vue_shared/translate';
import RegistryBreadcrumb from '~/packages_and_registries/shared/components/registry_breadcrumb.vue';
-import { renderBreadcrumb } from '~/packages_and_registries/shared/utils';
+import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs';
import { apolloProvider } from './graphql/index';
import RegistryExplorer from './pages/index.vue';
import createRouter from './router';
@@ -88,7 +88,7 @@ export default () => {
});
return {
- attachBreadcrumb: renderBreadcrumb(router, apolloProvider, RegistryBreadcrumb),
+ attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb, apolloProvider),
attachMainComponent,
};
};
diff --git a/app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue b/app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue
index e18e6f7ed1a..6bb4a8797df 100644
--- a/app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue
+++ b/app/assets/javascripts/packages_and_registries/dependency_proxy/app.vue
@@ -2,8 +2,8 @@
import {
GlAlert,
GlButton,
- GlDropdown,
- GlDropdownItem,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
GlFormGroup,
GlFormInputGroup,
GlSkeletonLoader,
@@ -18,6 +18,8 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import ManifestsList from '~/packages_and_registries/dependency_proxy/components/manifests_list.vue';
import { GRAPHQL_PAGE_SIZE } from '~/packages_and_registries/dependency_proxy/constants';
+import { getPageParams } from '~/packages_and_registries/dependency_proxy/utils';
+import { extractPageInfo } from '~/packages_and_registries/shared/utils';
import getDependencyProxyDetailsQuery from '~/packages_and_registries/dependency_proxy/graphql/queries/get_dependency_proxy_details.query.graphql';
@@ -25,8 +27,8 @@ export default {
components: {
GlAlert,
GlButton,
- GlDropdown,
- GlDropdownItem,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
GlSkeletonLoader,
GlFormGroup,
GlFormInputGroup,
@@ -79,11 +81,15 @@ export default {
},
computed: {
queryVariables() {
- return { fullPath: this.groupPath, first: GRAPHQL_PAGE_SIZE };
+ return { fullPath: this.groupPath, first: GRAPHQL_PAGE_SIZE, ...this.pageParams };
},
pageInfo() {
return this.group.dependencyProxyManifests?.pageInfo;
},
+ pageParams() {
+ const pageInfo = extractPageInfo(this.$route.query);
+ return getPageParams(pageInfo);
+ },
manifests() {
return this.group.dependencyProxyManifests?.nodes ?? [];
},
@@ -123,25 +129,10 @@ export default {
},
methods: {
fetchNextPage() {
- this.fetchMore({
- first: GRAPHQL_PAGE_SIZE,
- after: this.pageInfo?.endCursor,
- });
+ this.$router.push({ query: { after: this.pageInfo?.endCursor } });
},
fetchPreviousPage() {
- this.fetchMore({
- first: null,
- last: GRAPHQL_PAGE_SIZE,
- before: this.pageInfo?.startCursor,
- });
- },
- fetchMore(variables) {
- this.$apollo.queries.group.fetchMore({
- variables: { ...this.queryVariables, ...variables },
- updateQuery(_, { fetchMoreResult }) {
- return fetchMoreResult;
- },
- });
+ this.$router.push({ query: { before: this.pageInfo?.startCursor } });
},
async submit() {
try {
@@ -165,20 +156,23 @@ export default {
</gl-alert>
<title-area :title="$options.i18n.pageTitle">
<template #right-actions>
- <gl-dropdown
+ <gl-disclosure-dropdown
v-if="showDeleteDropdown"
icon="ellipsis_v"
- text="More actions"
+ :toggle-text="__('More actions')"
:text-sr-only="true"
category="tertiary"
+ placement="right"
no-caret
>
- <gl-dropdown-item
- v-gl-modal-directive="$options.confirmClearCacheModal"
- variant="danger"
- >{{ $options.i18n.clearCache }}</gl-dropdown-item
- >
- </gl-dropdown>
+ <gl-disclosure-dropdown-item v-gl-modal-directive="$options.confirmClearCacheModal">
+ <template #list-item>
+ <span class="gl-text-red-500">
+ {{ $options.i18n.clearCache }}
+ </span>
+ </template>
+ </gl-disclosure-dropdown-item>
+ </gl-disclosure-dropdown>
<gl-button
v-if="canClearCache"
v-gl-tooltip="$options.i18n.settingsText"
@@ -198,14 +192,14 @@ export default {
<gl-form-input-group
id="proxy-url"
readonly
- :value="group.dependencyProxyImagePrefix"
+ :value="dependencyProxyImagePrefix"
select-on-click
class="gl-layout-w-limited"
data-testid="proxy-url"
>
<template #append>
<clipboard-button
- :text="group.dependencyProxyImagePrefix"
+ :text="dependencyProxyImagePrefix"
:title="$options.i18n.copyImagePrefixText"
/>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/dependency_proxy/index.js b/app/assets/javascripts/packages_and_registries/dependency_proxy/index.js
index 74444d2c7ec..c115898c75b 100644
--- a/app/assets/javascripts/packages_and_registries/dependency_proxy/index.js
+++ b/app/assets/javascripts/packages_and_registries/dependency_proxy/index.js
@@ -1,8 +1,8 @@
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
-import app from '~/packages_and_registries/dependency_proxy/app.vue';
import { apolloProvider } from '~/packages_and_registries/dependency_proxy/graphql';
import Translate from '~/vue_shared/translate';
+import createRouter from './router';
Vue.use(Translate);
@@ -11,10 +11,18 @@ export const initDependencyProxyApp = () => {
if (!el) {
return null;
}
- const { groupPath, groupId, noManifestsIllustration, canClearCache, settingsPath } = el.dataset;
+ const {
+ endpoint,
+ groupPath,
+ groupId,
+ noManifestsIllustration,
+ canClearCache,
+ settingsPath,
+ } = el.dataset;
return new Vue({
el,
apolloProvider,
+ router: createRouter(endpoint),
provide: {
groupPath,
groupId,
@@ -23,7 +31,7 @@ export const initDependencyProxyApp = () => {
settingsPath,
},
render(createElement) {
- return createElement(app);
+ return createElement('router-view');
},
});
};
diff --git a/app/assets/javascripts/packages_and_registries/dependency_proxy/router.js b/app/assets/javascripts/packages_and_registries/dependency_proxy/router.js
new file mode 100644
index 00000000000..087d8c189c4
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/dependency_proxy/router.js
@@ -0,0 +1,14 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import App from '~/packages_and_registries/dependency_proxy/app.vue';
+
+Vue.use(VueRouter);
+
+export default function createRouter(base) {
+ const routes = [{ path: '/', name: 'dependencyProxyApp', component: App }];
+ return new VueRouter({
+ mode: 'history',
+ base,
+ routes,
+ });
+}
diff --git a/app/assets/javascripts/packages_and_registries/dependency_proxy/utils.js b/app/assets/javascripts/packages_and_registries/dependency_proxy/utils.js
new file mode 100644
index 00000000000..e6b97fac896
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/dependency_proxy/utils.js
@@ -0,0 +1,24 @@
+import { GRAPHQL_PAGE_SIZE } from './constants';
+
+const getNextPageParams = (cursor) => ({
+ after: cursor,
+ first: GRAPHQL_PAGE_SIZE,
+});
+
+const getPreviousPageParams = (cursor) => ({
+ first: null,
+ before: cursor,
+ last: GRAPHQL_PAGE_SIZE,
+});
+
+export const getPageParams = (pageInfo = {}) => {
+ if (pageInfo.before) {
+ return getPreviousPageParams(pageInfo.before);
+ }
+
+ if (pageInfo.after) {
+ return getNextPageParams(pageInfo.after);
+ }
+
+ return {};
+};
diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/index.js b/app/assets/javascripts/packages_and_registries/harbor_registry/index.js
index 6185e4c7bc6..41a5a0e3797 100644
--- a/app/assets/javascripts/packages_and_registries/harbor_registry/index.js
+++ b/app/assets/javascripts/packages_and_registries/harbor_registry/index.js
@@ -4,7 +4,7 @@ import { parseBoolean } from '~/lib/utils/common_utils';
import PerformancePlugin from '~/performance/vue_performance_plugin';
import Translate from '~/vue_shared/translate';
import RegistryBreadcrumb from '~/packages_and_registries/harbor_registry/components/harbor_registry_breadcrumb.vue';
-import { renderBreadcrumb } from '~/packages_and_registries/shared/utils';
+import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs';
import createRouter from './router';
import HarborRegistryExplorer from './pages/index.vue';
@@ -79,7 +79,7 @@ export default (id) => {
};
return {
- attachBreadcrumb: renderBreadcrumb(router, null, RegistryBreadcrumb),
+ attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb),
attachMainComponent,
};
};
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue
index 0cf49b25bf2..1020cd0c533 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue
@@ -6,9 +6,7 @@ import {
TOKEN_TITLE_TYPE,
TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
-import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
-import UrlSync from '~/vue_shared/components/url_sync.vue';
-import { getQueryParams, extractFilterAndSorting } from '~/packages_and_registries/shared/utils';
+import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
import { LIST_KEY_CREATED_AT } from '~/packages_and_registries/package_registry/constants';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import PackageTypeToken from './tokens/package_type_token.vue';
@@ -24,7 +22,10 @@ export default {
operators: OPERATORS_IS,
},
],
- components: { RegistrySearch, UrlSync, LocalStorageSync },
+ components: {
+ LocalStorageSync,
+ PersistedSearch,
+ },
inject: ['isGroupPage'],
data() {
return {
@@ -40,17 +41,25 @@ export default {
sortableFields() {
return sortableFields(this.isGroupPage);
},
- parsedSorting() {
- const cleanOrderBy = this.sorting?.orderBy.replace('_at', '');
- return `${cleanOrderBy}_${this.sorting?.sort}`.toUpperCase();
- },
- parsedFilters() {
+ },
+ mounted() {
+ // local-storage-sync does not emit `input`
+ // event when key is not found, so set the
+ // flag if it hasn't been updated
+ this.$nextTick(() => {
+ if (!this.mountRegistrySearch) {
+ this.mountRegistrySearch = true;
+ }
+ });
+ },
+ methods: {
+ formatFilters(filters) {
const parsed = {
packageName: '',
packageType: undefined,
};
- return this.filters.reduce((acc, filter) => {
+ return filters.reduce((acc, filter) => {
if (filter.type === TOKEN_TYPE_TYPE && filter.value?.data) {
return {
...acc,
@@ -68,28 +77,17 @@ export default {
return acc;
}, parsed);
},
- },
- mounted() {
- const queryParams = getQueryParams(window.document.location.search);
- const { sorting, filters } = extractFilterAndSorting(queryParams);
- this.updateSorting(sorting);
- this.updateFilters(filters);
- this.mountRegistrySearch = true;
- this.emitUpdate();
- },
- methods: {
- updateFilters(newValue) {
- this.filters = newValue;
- },
updateSorting(newValue) {
this.sorting = { ...this.sorting, ...newValue };
},
- updateSortingAndEmitUpdate(newValue) {
+ updateSortingFromLocalStorage(newValue) {
this.updateSorting(newValue);
- this.emitUpdate();
+ this.mountRegistrySearch = true;
},
- emitUpdate() {
- this.$emit('update', { sort: this.parsedSorting, filters: this.parsedFilters });
+ emitUpdate(values) {
+ const { filters, sorting } = values;
+ this.updateSorting(sorting);
+ this.$emit('update', { ...values, filters: this.formatFilters(filters) });
},
},
};
@@ -99,22 +97,15 @@ export default {
<local-storage-sync
storage-key="package_registry_list_sorting"
:value="sorting"
- @input="updateSorting"
+ @input="updateSortingFromLocalStorage"
>
- <url-sync>
- <template #default="{ updateQuery }">
- <registry-search
- v-if="mountRegistrySearch"
- :filters="filters"
- :sorting="sorting"
- :tokens="$options.tokens"
- :sortable-fields="sortableFields"
- @sorting:changed="updateSortingAndEmitUpdate"
- @filter:changed="updateFilters"
- @filter:submit="emitUpdate"
- @query:changed="updateQuery"
- />
- </template>
- </url-sync>
+ <persisted-search
+ v-if="mountRegistrySearch"
+ :sortable-fields="sortableFields"
+ :default-order="sorting.orderBy"
+ :default-sort="sorting.sort"
+ :tokens="$options.tokens"
+ @update="emitUpdate"
+ />
</local-storage-sync>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue
index a7831ef2588..b892305055c 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue
@@ -48,10 +48,6 @@ export default {
required: false,
default: false,
},
- pageInfo: {
- type: Object,
- required: true,
- },
groupSettings: {
type: Object,
required: false,
@@ -179,11 +175,8 @@ export default {
:hidden-delete="!canDeletePackages"
:is-loading="isLoading"
:items="list"
- :pagination="pageInfo"
:title="listTitle"
@delete="setItemsToBeDeleted"
- @prev-page="$emit('prev-page')"
- @next-page="$emit('next-page')"
>
<template #default="{ selectItem, isSelected, item, first }">
<packages-list-row
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/index.js b/app/assets/javascripts/packages_and_registries/package_registry/index.js
index ae0f6d18d99..1a9b192e2c8 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/index.js
+++ b/app/assets/javascripts/packages_and_registries/package_registry/index.js
@@ -4,7 +4,7 @@ import { parseBoolean } from '~/lib/utils/common_utils';
import { apolloProvider } from '~/packages_and_registries/package_registry/graphql/index';
import PackageRegistry from '~/packages_and_registries/package_registry/pages/index.vue';
import RegistryBreadcrumb from '~/packages_and_registries/shared/components/registry_breadcrumb.vue';
-import { renderBreadcrumb } from '~/packages_and_registries/shared/utils';
+import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs';
import createRouter from './router';
Vue.use(Translate);
@@ -60,7 +60,7 @@ export default () => {
});
return {
- attachBreadcrumb: renderBreadcrumb(router, apolloProvider, RegistryBreadcrumb),
+ attachBreadcrumb: () => injectVueAppBreadcrumbs(router, RegistryBreadcrumb, apolloProvider),
attachMainComponent,
};
};
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue b/app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue
index 6de89748708..a187c7a70d2 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue
@@ -18,6 +18,12 @@ import DeletePackages from '~/packages_and_registries/package_registry/component
import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue';
import PackageSearch from '~/packages_and_registries/package_registry/components/list/package_search.vue';
import PackageList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
+import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue';
+import {
+ getPageParams,
+ getNextPageParams,
+ getPreviousPageParams,
+} from '~/packages_and_registries/package_registry/utils';
export default {
components: {
@@ -28,6 +34,7 @@ export default {
PackageList,
PackageTitle,
PackageSearch,
+ PersistedPagination,
DeletePackages,
},
directives: {
@@ -39,7 +46,7 @@ export default {
packagesResource: {},
sort: '',
filters: {},
- mutationLoading: false,
+ isDeleteInProgress: false,
pageParams: {},
};
},
@@ -100,7 +107,7 @@ export default {
: this.$options.i18n.noResultsTitle;
},
isLoading() {
- return this.$apollo.queries.packagesResource.loading || this.mutationLoading;
+ return this.$apollo.queries.packagesResource.loading || this.isDeleteInProgress;
},
refetchQueriesData() {
return [
@@ -124,23 +131,16 @@ export default {
historyReplaceState(cleanUrl);
}
},
- handleSearchUpdate({ sort, filters }) {
- this.pageParams = {};
+ handleSearchUpdate({ sort, filters, pageInfo }) {
+ this.pageParams = getPageParams(pageInfo);
this.sort = sort;
this.filters = { ...filters };
},
fetchNextPage() {
- this.pageParams = {
- first: GRAPHQL_PAGE_SIZE,
- after: this.pageInfo?.endCursor,
- };
+ this.pageParams = getNextPageParams(this.pageInfo.endCursor);
},
fetchPreviousPage() {
- this.pageParams = {
- first: null,
- last: GRAPHQL_PAGE_SIZE,
- before: this.pageInfo?.startCursor,
- };
+ this.pageParams = getPreviousPageParams(this.pageInfo.startCursor);
},
},
i18n: {
@@ -176,17 +176,14 @@ export default {
<delete-packages
:refetch-queries="refetchQueriesData"
show-success-alert
- @start="mutationLoading = true"
- @end="mutationLoading = false"
+ @start="isDeleteInProgress = true"
+ @end="isDeleteInProgress = false"
>
<template #default="{ deletePackages }">
<package-list
:group-settings="groupSettings"
:list="packages.nodes"
:is-loading="isLoading"
- :page-info="pageInfo"
- @prev-page="fetchPreviousPage"
- @next-page="fetchNextPage"
@delete="deletePackages"
>
<template #empty-state>
@@ -210,5 +207,13 @@ export default {
</package-list>
</template>
</delete-packages>
+ <div v-if="!isDeleteInProgress" class="gl-display-flex gl-justify-content-center">
+ <persisted-pagination
+ class="gl-mt-3"
+ :pagination="pageInfo"
+ @prev="fetchPreviousPage"
+ @next="fetchNextPage"
+ />
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/utils.js b/app/assets/javascripts/packages_and_registries/package_registry/utils.js
index 4ff8edb8f66..35ff3d5ea63 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/utils.js
+++ b/app/assets/javascripts/packages_and_registries/package_registry/utils.js
@@ -1,6 +1,7 @@
import { capitalize } from 'lodash';
import { s__ } from '~/locale';
import {
+ GRAPHQL_PAGE_SIZE,
PACKAGE_TYPE_CONAN,
PACKAGE_TYPE_MAVEN,
PACKAGE_TYPE_NPM,
@@ -46,3 +47,26 @@ export const packageTypeToTrackCategory = (type) => `UI::${capitalize(type)}Pack
export const sortableFields = (isGroupPage) =>
SORT_FIELDS.filter((f) => f.orderBy !== LIST_KEY_PROJECT || isGroupPage);
+
+export const getNextPageParams = (cursor) => ({
+ after: cursor,
+ first: GRAPHQL_PAGE_SIZE,
+});
+
+export const getPreviousPageParams = (cursor) => ({
+ first: null,
+ before: cursor,
+ last: GRAPHQL_PAGE_SIZE,
+});
+
+export const getPageParams = (pageInfo = {}) => {
+ if (pageInfo.before) {
+ return getPreviousPageParams(pageInfo.before);
+ }
+
+ if (pageInfo.after) {
+ return getNextPageParams(pageInfo.after);
+ }
+
+ return {};
+};
diff --git a/app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue b/app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue
index dc61f3c788c..e00681f4183 100644
--- a/app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue
+++ b/app/assets/javascripts/packages_and_registries/shared/components/cli_commands.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdown } from '@gitlab/ui';
+import { GlDisclosureDropdown } from '@gitlab/ui';
import Tracking from '~/tracking';
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
import {
@@ -16,8 +16,8 @@ const trackingLabel = 'quickstart_dropdown';
export default {
components: {
- GlDropdown,
CodeInstruction,
+ GlDisclosureDropdown,
},
mixins: [Tracking.mixin({ label: trackingLabel })],
props: {
@@ -47,14 +47,13 @@ export default {
};
</script>
<template>
- <gl-dropdown
- :text="$options.i18n.QUICK_START"
+ <gl-disclosure-dropdown
+ :toggle-text="$options.i18n.QUICK_START"
variant="confirm"
- right
+ placement="right"
@shown="track('click_dropdown')"
>
- <!-- This li is used as a container since gl-dropdown produces a root ul, this mimics the functionality exposed by b-dropdown-form -->
- <li role="presentation" class="px-2 py-1">
+ <div class="gl-px-3 gl-py-2">
<code-instruction
:label="$options.i18n.LOGIN_COMMAND_LABEL"
:instruction="dockerLoginCommand"
@@ -79,6 +78,6 @@ export default {
tracking-action="click_copy_push"
:tracking-label="$options.trackingLabel"
/>
- </li>
- </gl-dropdown>
+ </div>
+ </gl-disclosure-dropdown>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue b/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue
index 95343a3a09b..529086e7f8c 100644
--- a/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue
+++ b/app/assets/javascripts/packages_and_registries/shared/components/persisted_search.vue
@@ -87,6 +87,7 @@ export default {
sort: this.parsedSorting,
filters: this.filters,
pageInfo: this.pageInfo,
+ sorting: this.sorting,
});
},
},
diff --git a/app/assets/javascripts/packages_and_registries/shared/utils.js b/app/assets/javascripts/packages_and_registries/shared/utils.js
index bda0839092e..a19c8ed5866 100644
--- a/app/assets/javascripts/packages_and_registries/shared/utils.js
+++ b/app/assets/javascripts/packages_and_registries/shared/utils.js
@@ -1,4 +1,3 @@
-import Vue from 'vue';
import { queryToObject } from '~/lib/utils/url_utility';
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
@@ -47,28 +46,3 @@ export const getCommitLink = ({ project_path: projectPath, pipeline = {} }, isGr
return `../commit/${pipeline.sha}`;
};
-
-export const renderBreadcrumb = (router, apolloProvider, RegistryBreadcrumb) => () => {
- const breadCrumbEls = document.querySelectorAll('nav .js-breadcrumbs-list li');
- const breadCrumbEl = breadCrumbEls[breadCrumbEls.length - 1];
- const lastCrumb = breadCrumbEl.children[0];
- const crumbs = [lastCrumb];
- const nestedBreadcrumbEl = document.createElement('div');
- breadCrumbEl.replaceChild(nestedBreadcrumbEl, lastCrumb);
- return new Vue({
- el: nestedBreadcrumbEl,
- router,
- apolloProvider,
- components: {
- RegistryBreadcrumb,
- },
- render(createElement) {
- return createElement('registry-breadcrumb', {
- class: breadCrumbEl.className,
- props: {
- crumbs,
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
deleted file mode 100644
index 29e92a8abad..00000000000
--- a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import $ from 'jquery';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import { truncate } from '~/lib/utils/text_utility';
-
-const MAX_MESSAGE_LENGTH = 500;
-const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
-
-export default class AbuseReports {
- constructor() {
- $(MESSAGE_CELL_SELECTOR).each(this.truncateLongMessage);
- $(document)
- .off('click', MESSAGE_CELL_SELECTOR)
- .on('click', MESSAGE_CELL_SELECTOR, this.toggleMessageTruncation);
- }
-
- truncateLongMessage() {
- const $messageCellElement = $(this);
- const reportMessage = $messageCellElement.text();
- if (reportMessage.length > MAX_MESSAGE_LENGTH) {
- $messageCellElement.data('originalMessage', reportMessage);
- $messageCellElement.data('messageTruncated', 'true');
- $messageCellElement.text(truncate(reportMessage, MAX_MESSAGE_LENGTH));
- }
- }
-
- toggleMessageTruncation() {
- const $messageCellElement = $(this);
- const originalMessage = $messageCellElement.data('originalMessage');
- if (!originalMessage) return;
- if (parseBoolean($messageCellElement.data('messageTruncated'))) {
- $messageCellElement.data('messageTruncated', 'false');
- $messageCellElement.text(originalMessage);
- } else {
- $messageCellElement.data('messageTruncated', 'true');
- $messageCellElement.text(truncate(originalMessage, MAX_MESSAGE_LENGTH));
- }
- }
-}
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/index.js b/app/assets/javascripts/pages/admin/abuse_reports/index.js
index 7634f131e4d..78fef1b5531 100644
--- a/app/assets/javascripts/pages/admin/abuse_reports/index.js
+++ b/app/assets/javascripts/pages/admin/abuse_reports/index.js
@@ -1,10 +1,3 @@
import { initAbuseReportsApp } from '~/admin/abuse_reports';
-import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
-import UsersSelect from '~/users_select';
-import AbuseReports from './abuse_reports';
-new AbuseReports(); /* eslint-disable-line no-new */
-new UsersSelect(); /* eslint-disable-line no-new */
-
-initDeprecatedRemoveRowBehavior();
initAbuseReportsApp();
diff --git a/app/assets/javascripts/pages/admin/application_settings/general/index.js b/app/assets/javascripts/pages/admin/application_settings/general/index.js
index 8a810ca649c..d0593c82ac1 100644
--- a/app/assets/javascripts/pages/admin/application_settings/general/index.js
+++ b/app/assets/javascripts/pages/admin/application_settings/general/index.js
@@ -1,3 +1,4 @@
+import { initSilentModeSettings } from '~/silent_mode_settings';
import initAccountAndLimitsSection from '../account_and_limits';
import initGitpod from '../gitpod';
import initSignupRestrictions from '../signup_restrictions';
@@ -6,4 +7,5 @@ import initSignupRestrictions from '../signup_restrictions';
initAccountAndLimitsSection();
initGitpod();
initSignupRestrictions();
+ initSilentModeSettings();
})();
diff --git a/app/assets/javascripts/pages/admin/jobs/components/cancel_jobs.vue b/app/assets/javascripts/pages/admin/jobs/components/cancel_jobs.vue
deleted file mode 100644
index 72cfc005782..00000000000
--- a/app/assets/javascripts/pages/admin/jobs/components/cancel_jobs.vue
+++ /dev/null
@@ -1,37 +0,0 @@
-<script>
-import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
-import CancelJobsModal from './cancel_jobs_modal.vue';
-import { CANCEL_JOBS_MODAL_ID, CANCEL_JOBS_BUTTON_TEXT, CANCEL_BUTTON_TOOLTIP } from './constants';
-
-export default {
- name: 'CancelJobs',
- components: {
- GlButton,
- CancelJobsModal,
- },
- directives: {
- GlModal: GlModalDirective,
- GlTooltip: GlTooltipDirective,
- },
- props: {
- url: {
- type: String,
- required: true,
- },
- },
- modalId: CANCEL_JOBS_MODAL_ID,
- buttonText: CANCEL_JOBS_BUTTON_TEXT,
- buttonTooltip: CANCEL_BUTTON_TOOLTIP,
-};
-</script>
-<template>
- <div>
- <gl-button
- v-gl-modal="$options.modalId"
- v-gl-tooltip="$options.buttonTooltip"
- variant="danger"
- >{{ $options.buttonText }}</gl-button
- >
- <cancel-jobs-modal :modal-id="$options.modalId" :url="url" @confirm="$emit('confirm')" />
- </div>
-</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/components/cancel_jobs_modal.vue b/app/assets/javascripts/pages/admin/jobs/components/cancel_jobs_modal.vue
deleted file mode 100644
index b2c5326fefd..00000000000
--- a/app/assets/javascripts/pages/admin/jobs/components/cancel_jobs_modal.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-<script>
-import { GlModal } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import {
- CANCEL_TEXT,
- CANCEL_JOBS_FAILED_TEXT,
- CANCEL_JOBS_MODAL_TITLE,
- CANCEL_JOBS_WARNING,
- PRIMARY_ACTION_TEXT,
-} from './constants';
-
-export default {
- components: {
- GlModal,
- },
- props: {
- url: {
- type: String,
- required: true,
- },
- modalId: {
- type: String,
- required: true,
- },
- },
- methods: {
- onSubmit() {
- return axios
- .post(this.url)
- .then((response) => {
- // follow the rediect to refresh the page
- redirectTo(response.request.responseURL); // eslint-disable-line import/no-deprecated
- })
- .catch((error) => {
- createAlert({
- message: CANCEL_JOBS_FAILED_TEXT,
- });
- throw error;
- });
- },
- },
- primaryAction: {
- text: PRIMARY_ACTION_TEXT,
- attributes: { variant: 'danger' },
- },
- cancelAction: {
- text: CANCEL_TEXT,
- },
- CANCEL_JOBS_WARNING,
- CANCEL_JOBS_MODAL_TITLE,
-};
-</script>
-
-<template>
- <gl-modal
- :modal-id="modalId"
- :action-primary="$options.primaryAction"
- :action-cancel="$options.cancelAction"
- :title="$options.CANCEL_JOBS_MODAL_TITLE"
- @primary="onSubmit"
- >
- {{ $options.CANCEL_JOBS_WARNING }}
- </gl-modal>
-</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/components/constants.js b/app/assets/javascripts/pages/admin/jobs/components/constants.js
deleted file mode 100644
index 4af8cb355fc..00000000000
--- a/app/assets/javascripts/pages/admin/jobs/components/constants.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { s__, __ } from '~/locale';
-import { RAW_TEXT_WARNING } from '~/jobs/components/table/constants';
-
-export const JOBS_COUNT_ERROR_MESSAGE = __('There was an error fetching the number of jobs.');
-export const JOBS_FETCH_ERROR_MSG = __('There was an error fetching the jobs.');
-export const LOADING_ARIA_LABEL = __('Loading');
-export const CANCELABLE_JOBS_ERROR_MSG = __('There was an error fetching the cancelable jobs.');
-export const CANCEL_JOBS_MODAL_ID = 'cancel-jobs-modal';
-export const CANCEL_JOBS_MODAL_TITLE = s__('AdminArea|Are you sure?');
-export const CANCEL_JOBS_BUTTON_TEXT = s__('AdminArea|Cancel all jobs');
-export const CANCEL_BUTTON_TOOLTIP = s__('AdminArea|Cancel all running and pending jobs');
-export const CANCEL_TEXT = __('Cancel');
-export const CANCEL_JOBS_FAILED_TEXT = s__('AdminArea|Canceling jobs failed');
-export const PRIMARY_ACTION_TEXT = s__('AdminArea|Yes, proceed');
-export const CANCEL_JOBS_WARNING = s__(
- "AdminArea|You're about to cancel all running and pending jobs across this instance. Do you want to proceed?",
-);
-export const RUNNER_EMPTY_TEXT = __('None');
-export const RUNNER_NO_DESCRIPTION = s__('Runners|No description');
-
-/* Admin Table constants */
-/* The field list is based on app/assets/javascripts/jobs/components/table/constants.js */
-export const DEFAULT_FIELDS_ADMIN = [
- { key: 'status', label: __('Status'), columnClass: 'gl-w-15p' },
- { key: 'job', label: __('Job'), columnClass: 'gl-w-20p' },
- { key: 'project', label: __('Project'), columnClass: 'gl-w-20p' },
- { key: 'runner', label: __('Runner'), columnClass: 'gl-w-15p' },
- { key: 'pipeline', label: __('Pipeline'), columnClass: 'gl-w-10p' },
- { key: 'stage', label: __('Stage'), columnClass: 'gl-w-10p' },
- { key: 'name', label: __('Name'), columnClass: 'gl-w-15p' },
- { key: 'duration', label: __('Duration'), columnClass: 'gl-w-15p' },
- { key: 'actions', label: '', columnClass: 'gl-w-10p' },
-];
-
-export const RAW_TEXT_WARNING_ADMIN = RAW_TEXT_WARNING;
diff --git a/app/assets/javascripts/pages/admin/jobs/components/table/admin_jobs_table_app.vue b/app/assets/javascripts/pages/admin/jobs/components/table/admin_jobs_table_app.vue
deleted file mode 100644
index daa4119f44d..00000000000
--- a/app/assets/javascripts/pages/admin/jobs/components/table/admin_jobs_table_app.vue
+++ /dev/null
@@ -1,259 +0,0 @@
-<script>
-import { GlAlert, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
-import { setUrlParams, updateHistory, queryToObject } from '~/lib/utils/url_utility';
-import { validateQueryString } from '~/jobs/components/filtered_search/utils';
-import JobsTable from '~/jobs/components/table/jobs_table.vue';
-import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
-import JobsFilteredSearch from '~/jobs/components/filtered_search/jobs_filtered_search.vue';
-import JobsTableEmptyState from '~/jobs/components/table/jobs_table_empty_state.vue';
-import { createAlert } from '~/alert';
-import JobsSkeletonLoader from '../jobs_skeleton_loader.vue';
-import {
- DEFAULT_FIELDS_ADMIN,
- RAW_TEXT_WARNING_ADMIN,
- JOBS_COUNT_ERROR_MESSAGE,
- JOBS_FETCH_ERROR_MSG,
- LOADING_ARIA_LABEL,
- CANCELABLE_JOBS_ERROR_MSG,
-} from '../constants';
-import GetAllJobs from './graphql/queries/get_all_jobs.query.graphql';
-import GetAllJobsCount from './graphql/queries/get_all_jobs_count.query.graphql';
-import CancelableJobs from './graphql/queries/get_cancelable_jobs_count.query.graphql';
-
-export default {
- i18n: {
- jobsCountErrorMsg: JOBS_COUNT_ERROR_MESSAGE,
- jobsFetchErrorMsg: JOBS_FETCH_ERROR_MSG,
- loadingAriaLabel: LOADING_ARIA_LABEL,
- cancelableJobsErrorMsg: CANCELABLE_JOBS_ERROR_MSG,
- },
- filterSearchBoxStyles:
- 'gl-my-0 gl-p-5 gl-bg-gray-10 gl-text-gray-900 gl-border-b gl-border-gray-100',
- components: {
- JobsSkeletonLoader,
- JobsTableEmptyState,
- GlAlert,
- JobsFilteredSearch,
- JobsTable,
- JobsTableTabs,
- GlIntersectionObserver,
- GlLoadingIcon,
- },
- inject: {
- jobStatuses: {
- default: null,
- required: false,
- },
- url: {
- default: '',
- required: false,
- },
- emptyStateSvgPath: {
- default: '',
- required: false,
- },
- },
- apollo: {
- jobs: {
- query: GetAllJobs,
- variables() {
- return this.variables;
- },
- update(data) {
- const { jobs: { nodes: list = [], pageInfo = {} } = {} } = data || {};
- return {
- list,
- pageInfo,
- };
- },
- error() {
- this.error = this.$options.i18n.jobsFetchErrorMsg;
- },
- },
- jobsCount: {
- query: GetAllJobsCount,
- update(data) {
- return data?.jobs?.count || 0;
- },
- context: {
- isSingleRequest: true,
- },
- error() {
- this.error = this.$options.i18n.jobsCountErrorMsg;
- },
- },
- cancelable: {
- query: CancelableJobs,
- update(data) {
- this.isCancelable = data.cancelable.count !== 0;
- },
- error() {
- this.error = this.$options.i18n.cancelableJobsErrorMsg;
- },
- },
- },
- data() {
- return {
- jobs: {
- list: [],
- },
- error: '',
- count: 0,
- scope: null,
- infiniteScrollingTriggered: false,
- filterSearchTriggered: false,
- DEFAULT_FIELDS_ADMIN,
- isCancelable: false,
- jobsCount: null,
- };
- },
- computed: {
- loading() {
- return this.$apollo.queries.jobs.loading;
- },
- // Show when on All tab with no jobs
- // Show only when not loading and filtered search has not been triggered
- // So we don't show empty state when results are empty on a filtered search
- showEmptyState() {
- return (
- this.jobs.list.length === 0 && !this.scope && !this.loading && !this.filterSearchTriggered
- );
- },
- hasNextPage() {
- return this.jobs?.pageInfo?.hasNextPage;
- },
- variables() {
- return { ...this.validatedQueryString };
- },
- validatedQueryString() {
- const queryStringObject = queryToObject(window.location.search);
-
- return validateQueryString(queryStringObject);
- },
- showFilteredSearch() {
- return !this.scope;
- },
- showLoadingSpinner() {
- return this.loading && this.infiniteScrollingTriggered;
- },
- showSkeletonLoader() {
- return this.loading && !this.showLoadingSpinner;
- },
- },
- watch: {
- // this watcher ensures that the count on the all tab
- // is not updated when switching to the finished tab
- jobsCount(newCount) {
- if (this.scope) return;
-
- this.count = newCount;
- },
- },
- methods: {
- updateHistoryAndFetchCount(status = null) {
- this.$apollo.queries.jobsCount.refetch({ statuses: status });
-
- updateHistory({
- url: setUrlParams({ statuses: status }, window.location.href, true),
- });
- },
- fetchJobsByStatus(scope) {
- this.infiniteScrollingTriggered = false;
-
- if (this.scope === scope) return;
-
- this.scope = scope;
-
- if (!this.scope) this.updateHistoryAndFetchCount();
-
- this.$apollo.queries.jobs.refetch({ statuses: scope });
- },
- fetchMoreJobs() {
- if (!this.loading) {
- this.infiniteScrollingTriggered = true;
-
- const parameters = this.variables;
- parameters.after = this.jobs?.pageInfo?.endCursor;
-
- this.$apollo.queries.jobs.fetchMore({
- variables: parameters,
- });
- }
- },
- filterJobsBySearch(filters) {
- this.infiniteScrollingTriggered = false;
- this.filterSearchTriggered = true;
-
- // all filters have been cleared reset query param
- // and refetch jobs/count with defaults
- if (!filters.length) {
- this.updateHistoryAndFetchCount();
- this.$apollo.queries.jobs.refetch({ statuses: null });
-
- return;
- }
-
- // Eventually there will be more tokens available
- // this code is written to scale for those tokens
- filters.forEach((filter) => {
- // Raw text input in filtered search does not have a type
- // when a user enters raw text we alert them that it is
- // not supported and we do not make an additional API call
- if (!filter.type) {
- createAlert({
- message: RAW_TEXT_WARNING_ADMIN,
- type: 'warning',
- });
- }
-
- if (filter.type === 'status') {
- this.updateHistoryAndFetchCount(filter.value.data);
- this.$apollo.queries.jobs.refetch({ statuses: filter.value.data });
- }
- });
- },
- },
-};
-</script>
-
-<template>
- <div>
- <gl-alert v-if="error" class="gl-mt-2" variant="danger" dismissible @dismiss="error = ''">
- {{ error }}
- </gl-alert>
-
- <jobs-table-tabs
- :all-jobs-count="count"
- :loading="loading"
- :show-cancel-all-jobs-button="isCancelable"
- @fetchJobsByStatus="fetchJobsByStatus"
- />
-
- <div v-if="showFilteredSearch" :class="$options.filterSearchBoxStyles">
- <jobs-filtered-search
- :query-string="validatedQueryString"
- @filterJobsBySearch="filterJobsBySearch"
- />
- </div>
-
- <jobs-skeleton-loader v-if="showSkeletonLoader" class="gl-mt-5" />
-
- <jobs-table-empty-state v-else-if="showEmptyState" />
-
- <jobs-table
- v-else
- :jobs="jobs.list"
- :table-fields="DEFAULT_FIELDS_ADMIN"
- admin
- class="gl-table-no-top-border"
- />
-
- <gl-intersection-observer v-if="hasNextPage" @appear="fetchMoreJobs">
- <gl-loading-icon
- v-if="showLoadingSpinner"
- size="lg"
- :aria-label="$options.i18n.loadingAriaLabel"
- />
- </gl-intersection-observer>
- </div>
-</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/components/table/cells/runner_cell.vue b/app/assets/javascripts/pages/admin/jobs/components/table/cells/runner_cell.vue
deleted file mode 100644
index 33bcee5b34b..00000000000
--- a/app/assets/javascripts/pages/admin/jobs/components/table/cells/runner_cell.vue
+++ /dev/null
@@ -1,39 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-import { RUNNER_EMPTY_TEXT, RUNNER_NO_DESCRIPTION } from '~/pages/admin/jobs/components/constants';
-
-export default {
- i18n: {
- emptyRunnerText: RUNNER_EMPTY_TEXT,
- noRunnerDescription: RUNNER_NO_DESCRIPTION,
- },
- components: {
- GlLink,
- },
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- computed: {
- adminUrl() {
- return this.job.runner?.adminUrl;
- },
- description() {
- return this.job.runner?.description
- ? this.job.runner.description
- : this.$options.i18n.noRunnerDescription;
- },
- },
-};
-</script>
-
-<template>
- <div class="gl-text-truncate">
- <gl-link v-if="adminUrl" :href="adminUrl">
- {{ description }}
- </gl-link>
- <span v-else data-testid="empty-runner-text"> {{ $options.i18n.emptyRunnerText }}</span>
- </div>
-</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_all_jobs.query.graphql b/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_all_jobs.query.graphql
deleted file mode 100644
index 9e2795966e0..00000000000
--- a/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_all_jobs.query.graphql
+++ /dev/null
@@ -1,85 +0,0 @@
-query getAllJobs($after: String, $first: Int = 50, $statuses: [CiJobStatus!]) {
- jobs(after: $after, first: $first, statuses: $statuses) {
- pageInfo {
- endCursor
- hasNextPage
- hasPreviousPage
- startCursor
- }
- nodes {
- runner {
- id
- description
- adminUrl
- }
- artifacts {
- nodes {
- id
- downloadPath
- fileType
- }
- }
- allowFailure
- status
- scheduledAt
- manualJob
- triggered
- createdByTag
- detailedStatus {
- id
- detailsPath
- group
- icon
- label
- text
- tooltip
- action {
- id
- buttonTitle
- icon
- method
- path
- title
- }
- }
- id
- refName
- refPath
- tags
- shortSha
- commitPath
- pipeline {
- id
- project {
- id
- fullPath
- webUrl
- }
- path
- user {
- id
- webPath
- avatarUrl
- }
- }
- stage {
- id
- name
- }
- name
- duration
- finishedAt
- coverage
- retryable
- playable
- cancelable
- active
- stuck
- userPermissions {
- readBuild
- readJobArtifacts
- updateBuild
- }
- }
- }
-}
diff --git a/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_all_jobs_count.query.graphql b/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_all_jobs_count.query.graphql
deleted file mode 100644
index 8c59230b2b8..00000000000
--- a/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_all_jobs_count.query.graphql
+++ /dev/null
@@ -1,5 +0,0 @@
-query getAllJobsCount($statuses: [CiJobStatus!]) {
- jobs(statuses: $statuses) {
- count
- }
-}
diff --git a/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_cancelable_jobs_count.query.graphql b/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_cancelable_jobs_count.query.graphql
deleted file mode 100644
index 9b90abebbf7..00000000000
--- a/app/assets/javascripts/pages/admin/jobs/components/table/graphql/queries/get_cancelable_jobs_count.query.graphql
+++ /dev/null
@@ -1,5 +0,0 @@
-query canelableJobs {
- cancelable: jobs(statuses: [PENDING, RUNNING]) {
- count
- }
-}
diff --git a/app/assets/javascripts/pages/admin/jobs/index/index.js b/app/assets/javascripts/pages/admin/jobs/index/index.js
index 9c2a255a1a3..52e4d5dd19f 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/index.js
+++ b/app/assets/javascripts/pages/admin/jobs/index/index.js
@@ -1,12 +1,9 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
-import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import Translate from '~/vue_shared/translate';
import createDefaultClient from '~/lib/graphql';
-import { CANCEL_JOBS_MODAL_ID } from '../components/constants';
-import CancelJobsModal from '../components/cancel_jobs_modal.vue';
-import AdminJobsTableApp from '../components/table/admin_jobs_table_app.vue';
-import cacheConfig from '../components/table/graphql/cache_config';
+import AdminJobsTableApp from '~/ci/admin/jobs_table/admin_jobs_table_app.vue';
+import cacheConfig from '~/ci/admin/jobs_table/graphql/cache_config';
Vue.use(Translate);
Vue.use(VueApollo);
@@ -17,35 +14,7 @@ const apolloProvider = new VueApollo({
defaultClient: client,
});
-function initJobs() {
- const buttonId = 'js-stop-jobs-button';
- const cancelJobsButton = document.getElementById(buttonId);
- if (cancelJobsButton) {
- // eslint-disable-next-line no-new
- new Vue({
- el: `#js-${CANCEL_JOBS_MODAL_ID}`,
- components: {
- CancelJobsModal,
- },
- mounted() {
- cancelJobsButton.classList.remove('disabled');
- cancelJobsButton.addEventListener('click', () => {
- this.$root.$emit(BV_SHOW_MODAL, CANCEL_JOBS_MODAL_ID, `#${buttonId}`);
- });
- },
- render(createElement) {
- return createElement(CANCEL_JOBS_MODAL_ID, {
- props: {
- url: cancelJobsButton.dataset.url,
- modalId: CANCEL_JOBS_MODAL_ID,
- },
- });
- },
- });
- }
-}
-
-export function initAdminJobsApp() {
+const initAdminJobsApp = () => {
const containerEl = document.getElementById('admin-jobs-app');
if (!containerEl) return false;
@@ -64,10 +33,6 @@ export function initAdminJobsApp() {
return createElement(AdminJobsTableApp);
},
});
-}
+};
-if (gon.features.adminJobsVue) {
- initAdminJobsApp();
-} else {
- initJobs();
-}
+initAdminJobsApp();
diff --git a/app/assets/javascripts/pages/dashboard/groups/index/index.js b/app/assets/javascripts/pages/dashboard/groups/index/index.js
index c14848c4798..fbfc6c07904 100644
--- a/app/assets/javascripts/pages/dashboard/groups/index/index.js
+++ b/app/assets/javascripts/pages/dashboard/groups/index/index.js
@@ -1,3 +1,4 @@
+import EmptyState from '~/groups/components/empty_states/groups_dashboard_empty_state.vue';
import initGroupsList from '~/groups';
-initGroupsList();
+initGroupsList(EmptyState);
diff --git a/app/assets/javascripts/pages/explore/groups/index.js b/app/assets/javascripts/pages/explore/groups/index.js
index 9b60b1f51a8..c6a9cf50d9a 100644
--- a/app/assets/javascripts/pages/explore/groups/index.js
+++ b/app/assets/javascripts/pages/explore/groups/index.js
@@ -1,8 +1,9 @@
+import EmptyState from '~/groups/components/empty_states/groups_explore_empty_state.vue';
import initGroupsList from '~/groups';
import Landing from '~/groups/landing';
function exploreGroups() {
- initGroupsList();
+ initGroupsList(EmptyState);
const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) return;
const exploreGroupsLanding = new Landing(
diff --git a/app/assets/javascripts/pages/import/bitbucket_server/status/components/bitbucket_server_status_table.vue b/app/assets/javascripts/pages/import/bitbucket_server/status/components/bitbucket_server_status_table.vue
index f0c4ecbe3eb..3a73d0c9f40 100644
--- a/app/assets/javascripts/pages/import/bitbucket_server/status/components/bitbucket_server_status_table.vue
+++ b/app/assets/javascripts/pages/import/bitbucket_server/status/components/bitbucket_server_status_table.vue
@@ -19,9 +19,14 @@ export default {
<template>
<bitbucket-status-table v-bind="$attrs">
<template #actions>
- <gl-button variant="info" class="gl-ml-3" data-method="post" :href="reconfigurePath">{{
- __('Reconfigure')
- }}</gl-button>
+ <gl-button
+ category="secondary"
+ variant="confirm"
+ class="gl-ml-3"
+ data-method="post"
+ :href="reconfigurePath"
+ >{{ __('Reconfigure') }}</gl-button
+ >
</template>
</bitbucket-status-table>
</template>
diff --git a/app/assets/javascripts/pages/organizations/organizations/show/index.js b/app/assets/javascripts/pages/organizations/organizations/show/index.js
new file mode 100644
index 00000000000..f9f9d2db692
--- /dev/null
+++ b/app/assets/javascripts/pages/organizations/organizations/show/index.js
@@ -0,0 +1,3 @@
+import { initOrganizationsShow } from '~/organizations/show';
+
+initOrganizationsShow();
diff --git a/app/assets/javascripts/pages/projects/incidents/show/index.js b/app/assets/javascripts/pages/projects/incidents/show/index.js
index a83c4f1c0d2..a2ff45b454a 100644
--- a/app/assets/javascripts/pages/projects/incidents/show/index.js
+++ b/app/assets/javascripts/pages/projects/incidents/show/index.js
@@ -1,7 +1,3 @@
import { initShow } from '~/issues';
-import initSidebarBundle from '~/sidebar/sidebar_bundle';
-import initWorkItemLinks from '~/work_items/components/work_item_links';
initShow();
-initSidebarBundle();
-initWorkItemLinks();
diff --git a/app/assets/javascripts/pages/projects/issues/service_desk/index.js b/app/assets/javascripts/pages/projects/issues/service_desk/index.js
index 0844e322de2..ead15143072 100644
--- a/app/assets/javascripts/pages/projects/issues/service_desk/index.js
+++ b/app/assets/javascripts/pages/projects/issues/service_desk/index.js
@@ -1,5 +1,5 @@
import { initFilteredSearchServiceDesk } from '~/issues';
-import { mountServiceDeskListApp } from '~/service_desk';
+import { mountServiceDeskListApp } from '~/issues/service_desk';
initFilteredSearchServiceDesk();
diff --git a/app/assets/javascripts/pages/projects/issues/show/index.js b/app/assets/javascripts/pages/projects/issues/show/index.js
index c92958cd8c7..a2ff45b454a 100644
--- a/app/assets/javascripts/pages/projects/issues/show/index.js
+++ b/app/assets/javascripts/pages/projects/issues/show/index.js
@@ -1,10 +1,3 @@
import { initShow } from '~/issues';
-import { store } from '~/notes/stores';
-import { initRelatedIssues } from '~/related_issues';
-import initSidebarBundle from '~/sidebar/sidebar_bundle';
-import initWorkItemLinks from '~/work_items/components/work_item_links';
initShow();
-initSidebarBundle(store);
-initRelatedIssues();
-initWorkItemLinks();
diff --git a/app/assets/javascripts/pages/projects/jobs/index/index.js b/app/assets/javascripts/pages/projects/jobs/index/index.js
index eb3a24f38a8..9b5ad804750 100644
--- a/app/assets/javascripts/pages/projects/jobs/index/index.js
+++ b/app/assets/javascripts/pages/projects/jobs/index/index.js
@@ -1,3 +1,3 @@
-import initJobsTable from '~/jobs/components/table';
+import initJobsPage from '~/ci/jobs_page';
-initJobsTable();
+initJobsPage();
diff --git a/app/assets/javascripts/pages/projects/jobs/show/index.js b/app/assets/javascripts/pages/projects/jobs/show/index.js
index 6fef057dee0..cd83f2b7b64 100644
--- a/app/assets/javascripts/pages/projects/jobs/show/index.js
+++ b/app/assets/javascripts/pages/projects/jobs/show/index.js
@@ -1,3 +1,3 @@
-import initJobDetails from '~/jobs';
+import initJobDetails from '~/ci/job_details';
initJobDetails();
diff --git a/app/assets/javascripts/pages/projects/merge_requests/creations/new/branch_finder.js b/app/assets/javascripts/pages/projects/merge_requests/creations/new/branch_finder.js
new file mode 100644
index 00000000000..ee84f54978a
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/merge_requests/creations/new/branch_finder.js
@@ -0,0 +1 @@
+export const findTargetBranch = async () => {};
diff --git a/app/assets/javascripts/pages/projects/merge_requests/creations/new/index.js b/app/assets/javascripts/pages/projects/merge_requests/creations/new/index.js
index f71a1041068..d23a0615bb8 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/creations/new/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/creations/new/index.js
@@ -2,6 +2,8 @@ import Vue from 'vue';
import { mountMarkdownEditor } from 'ee_else_ce/vue_shared/components/markdown/mount_markdown_editor';
+import { findTargetBranch } from 'ee_else_ce/pages/projects/merge_requests/creations/new/branch_finder';
+
import initPipelines from '~/commit/pipelines/pipelines_bundle';
import MergeRequest from '~/merge_request';
import CompareApp from '~/merge_requests/components/compare_app.vue';
@@ -13,14 +15,15 @@ if (mrNewCompareNode) {
const targetCompareEl = document.getElementById('js-target-project-dropdown');
const sourceCompareEl = document.getElementById('js-source-project-dropdown');
const compareEl = document.querySelector('.js-merge-request-new-compare');
+ const targetBranch = Vue.observable({ name: '' });
+ const currentSourceBranch = JSON.parse(sourceCompareEl.dataset.currentBranch);
// eslint-disable-next-line no-new
new Vue({
el: sourceCompareEl,
name: 'SourceCompareApp',
provide: {
currentProject: JSON.parse(sourceCompareEl.dataset.currentProject),
- currentBranch: JSON.parse(sourceCompareEl.dataset.currentBranch),
branchCommitPath: compareEl.dataset.sourceBranchUrl,
inputs: {
project: {
@@ -40,20 +43,35 @@ if (mrNewCompareNode) {
project: 'js-source-project',
branch: 'js-source-branch gl-font-monospace',
},
- branchQaSelector: 'source_branch_dropdown',
+ },
+ methods: {
+ async selectedBranch(branchName) {
+ const targetBranchName = await findTargetBranch(branchName);
+
+ if (targetBranchName) {
+ targetBranch.name = targetBranchName;
+ }
+ },
},
render(h) {
- return h(CompareApp);
+ return h(CompareApp, {
+ props: {
+ currentBranch: currentSourceBranch,
+ },
+ on: {
+ 'select-branch': this.selectedBranch,
+ },
+ });
},
});
+ const currentTargetBranch = JSON.parse(targetCompareEl.dataset.currentBranch);
// eslint-disable-next-line no-new
new Vue({
el: targetCompareEl,
name: 'TargetCompareApp',
provide: {
currentProject: JSON.parse(targetCompareEl.dataset.currentProject),
- currentBranch: JSON.parse(targetCompareEl.dataset.currentBranch),
projectsPath: targetCompareEl.dataset.targetProjectsPath,
branchCommitPath: compareEl.dataset.targetBranchUrl,
inputs: {
@@ -75,8 +93,17 @@ if (mrNewCompareNode) {
branch: 'js-target-branch gl-font-monospace',
},
},
+ computed: {
+ currentBranch() {
+ if (targetBranch.name) {
+ return { text: targetBranch.name, value: targetBranch.name };
+ }
+
+ return currentTargetBranch;
+ },
+ },
render(h) {
- return h(CompareApp);
+ return h(CompareApp, { props: { currentBranch: this.currentBranch } });
},
});
} else {
diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
index 30734f0b698..2cdbf0fb830 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
@@ -4,7 +4,7 @@ import { s__ } from '~/locale';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import { initPipelineCountListener } from '~/commit/pipelines/utils';
import { initIssuableSidebar } from '~/issuable';
-import StatusBox from '~/issuable/components/status_box.vue';
+import MergeRequestStatusBadge from '~/merge_requests/components/merge_request_status_badge.vue';
import createDefaultClient from '~/lib/graphql';
import initSourcegraph from '~/sourcegraph';
import ZenMode from '~/zen_mode';
@@ -24,24 +24,24 @@ export default function initMergeRequestShow() {
initMrExperienceSurvey();
const el = document.querySelector('.js-mr-status-box');
- const { iid, issuableType, projectPath } = el.dataset;
- const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
- });
+ const { iid, issuableType, projectPath, state } = el.dataset;
+
// eslint-disable-next-line no-new
new Vue({
el,
name: 'IssuableStatusBoxRoot',
- apolloProvider,
+ apolloProvider: new VueApollo({
+ defaultClient: createDefaultClient(),
+ }),
provide: {
query: getStateQuery,
iid,
projectPath,
},
- render(h) {
- return h(StatusBox, {
+ render(createElement) {
+ return createElement(MergeRequestStatusBadge, {
props: {
- initialState: el.dataset.state,
+ initialState: state,
issuableType,
},
});
diff --git a/app/assets/javascripts/pages/projects/merge_requests/page.js b/app/assets/javascripts/pages/projects/merge_requests/page.js
index 75e308e706f..f7b522f7c85 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/page.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/page.js
@@ -1,8 +1,8 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import initMrNotes from 'ee_else_ce/mr_notes';
+import { mountHeaderMetadata } from '~/merge_requests';
import StickyHeader from '~/merge_requests/components/sticky_header.vue';
-import { initIssuableHeaderWarnings } from '~/issuable';
import { start as startCodeReviewMessaging } from '~/code_review/signals';
import diffsEventHub from '~/diffs/event_hub';
import store from '~/mr_notes/stores';
@@ -24,7 +24,7 @@ export function initMrPage() {
requestIdleCallback(() => {
initSidebarBundle(store);
- initIssuableHeaderWarnings(store);
+ mountHeaderMetadata(store);
const el = document.getElementById('js-merge-sticky-header');
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
index a51c2e9c47b..f48c38b776f 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
@@ -1,8 +1,3 @@
import initPipelineSchedulesFormApp from '~/ci/pipeline_schedules/mount_pipeline_schedules_form_app';
-import initForm from '../shared/init_form';
-if (gon.features?.pipelineSchedulesVue) {
- initPipelineSchedulesFormApp('#pipeline-schedules-form-edit', true);
-} else {
- initForm();
-}
+initPipelineSchedulesFormApp('#pipeline-schedules-form-edit', true);
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
index 4bdbb70d942..0eff9110412 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
@@ -1,75 +1,3 @@
-import Vue from 'vue';
-import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import initPipelineSchedulesApp from '~/ci/pipeline_schedules/mount_pipeline_schedules_app';
-import PipelineSchedulesTakeOwnershipModalLegacy from '~/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue';
-import PipelineSchedulesCallout from '../shared/components/pipeline_schedules_callout.vue';
-function initPipelineSchedulesCallout() {
- const el = document.getElementById('pipeline-schedules-callout');
-
- if (!el) {
- return;
- }
-
- const { docsUrl, illustrationUrl } = el.dataset;
-
- // eslint-disable-next-line no-new
- new Vue({
- el,
- name: 'PipelineSchedulesCalloutRoot',
- provide: {
- docsUrl,
- illustrationUrl,
- },
- render(createElement) {
- return createElement(PipelineSchedulesCallout);
- },
- });
-}
-
-// TODO: move take ownership feature into new Vue app
-// located in directory app/assets/javascripts/pipeline_schedules/components
-function initTakeownershipModal() {
- const modalId = 'pipeline-take-ownership-modal';
- const buttonSelector = 'js-take-ownership-button';
- const el = document.getElementById(modalId);
- const takeOwnershipButtons = document.querySelectorAll(`.${buttonSelector}`);
-
- if (!el) {
- return;
- }
-
- // eslint-disable-next-line no-new
- new Vue({
- el,
- data() {
- return {
- url: '',
- };
- },
- mounted() {
- takeOwnershipButtons.forEach((button) => {
- button.addEventListener('click', () => {
- const { url } = button.dataset;
-
- this.url = url;
- this.$root.$emit(BV_SHOW_MODAL, modalId, `.${buttonSelector}`);
- });
- });
- },
- render(createElement) {
- return createElement(PipelineSchedulesTakeOwnershipModalLegacy, {
- props: {
- ownershipUrl: this.url,
- },
- });
- },
- });
-}
-
-if (gon.features?.pipelineSchedulesVue) {
- initPipelineSchedulesApp();
-} else {
- initPipelineSchedulesCallout();
- initTakeownershipModal();
-}
+initPipelineSchedulesApp();
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
index d8ba7bbd752..672e3d014bd 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
@@ -1,8 +1,3 @@
import initPipelineSchedulesFormApp from '~/ci/pipeline_schedules/mount_pipeline_schedules_form_app';
-import initForm from '../shared/init_form';
-if (gon.features?.pipelineSchedulesVue) {
- initPipelineSchedulesFormApp('#pipeline-schedules-form-new');
-} else {
- initForm();
-}
+initPipelineSchedulesFormApp('#pipeline-schedules-form-new');
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
index 5f6a73782c3..642fd56eab1 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
@@ -69,7 +69,8 @@ export default {
formattedTime() {
if (this.randomHour > 12) {
return `${this.randomHour - 12}:00pm`;
- } else if (this.randomHour === 12) {
+ }
+ if (this.randomHour === 12) {
return `12:00pm`;
}
return `${this.randomHour}:00am`;
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
deleted file mode 100644
index b3ad50f395b..00000000000
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
+++ /dev/null
@@ -1,62 +0,0 @@
-<script>
-import { GlButton } from '@gitlab/ui';
-import Vue from 'vue';
-import { getCookie, setCookie, parseBoolean } from '~/lib/utils/common_utils';
-import Translate from '~/vue_shared/translate';
-
-Vue.use(Translate);
-
-const cookieKey = 'pipeline_schedules_callout_dismissed';
-
-export default {
- name: 'PipelineSchedulesCallout',
- components: {
- GlButton,
- },
- inject: ['docsUrl', 'illustrationUrl'],
- data() {
- return {
- calloutDismissed: parseBoolean(getCookie(cookieKey)),
- };
- },
- methods: {
- dismissCallout() {
- this.calloutDismissed = true;
- setCookie(cookieKey, this.calloutDismissed);
- },
- },
-};
-</script>
-<template>
- <div v-if="!calloutDismissed" class="pipeline-schedules-user-callout user-callout">
- <div class="bordered-box landing content-block gl-p-5!" data-testid="innerContent">
- <gl-button
- category="tertiary"
- icon="close"
- :aria-label="__('Dismiss')"
- class="gl-absolute gl-top-2 gl-right-2"
- @click="dismissCallout"
- />
- <div class="svg-content">
- <img :src="illustrationUrl" />
- </div>
- <div class="user-callout-copy">
- <h4>{{ __('Scheduling Pipelines') }}</h4>
- <p>
- {{
- __(`The pipelines schedule runs pipelines in the future,
-repeatedly, for specific branches or tags.
-Those scheduled pipelines will inherit limited project access based on their associated user.`)
- }}
- </p>
- <p>
- {{ __('Learn more in the') }}
- <a :href="docsUrl" target="_blank" rel="nofollow">
- {{ __('pipeline schedules documentation') }}</a
- >.
- <!-- oneline to prevent extra space before period -->
- </p>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
deleted file mode 100644
index 8440d0e77cd..00000000000
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import $ from 'jquery';
-import Vue from 'vue';
-import { __ } from '~/locale';
-import RefSelector from '~/ref/components/ref_selector.vue';
-import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants';
-import setupNativeFormVariableList from '~/ci/ci_variable_list/native_form_variable_list';
-import GlFieldErrors from '~/gl_field_errors';
-import Translate from '~/vue_shared/translate';
-import { initTimezoneDropdown } from '../../../profiles/init_timezone_dropdown';
-import IntervalPatternInput from './components/interval_pattern_input.vue';
-
-Vue.use(Translate);
-
-function initIntervalPatternInput() {
- const intervalPatternMount = document.getElementById('interval-pattern-input');
- const initialCronInterval = intervalPatternMount?.dataset?.initialInterval;
- const dailyLimit = intervalPatternMount.dataset?.dailyLimit;
-
- return new Vue({
- el: intervalPatternMount,
- components: {
- IntervalPatternInput,
- },
- render(createElement) {
- return createElement('interval-pattern-input', {
- props: {
- initialCronInterval,
- dailyLimit,
- },
- });
- },
- });
-}
-
-function getEnabledRefTypes() {
- return [REF_TYPE_BRANCHES, REF_TYPE_TAGS];
-}
-
-function initTargetRefDropdown() {
- const $refField = document.getElementById('schedule_ref');
- const el = document.querySelector('.js-target-ref-dropdown');
- const { projectId, defaultBranch } = el.dataset;
-
- if (!$refField.value) {
- $refField.value = defaultBranch;
- }
-
- const refDropdown = new Vue({
- el,
- render(h) {
- return h(RefSelector, {
- props: {
- enabledRefTypes: getEnabledRefTypes(),
- projectId,
- value: $refField.value,
- useSymbolicRefNames: true,
- translations: {
- dropdownHeader: __('Select target branch or tag'),
- },
- },
- class: 'gl-w-full',
- });
- },
- });
-
- refDropdown.$children[0].$on('input', (newRef) => {
- $refField.value = newRef;
- });
-
- return refDropdown;
-}
-
-export default () => {
- /* Most of the form is written in haml, but for fields with more complex behaviors,
- * you should mount individual Vue components here. If at some point components need
- * to share state, it may make sense to refactor the whole form to Vue */
-
- initIntervalPatternInput();
-
- // Initialize non-Vue JS components in the form
-
- const formElement = document.getElementById('new-pipeline-schedule-form');
-
- gl.pipelineScheduleFieldErrors = new GlFieldErrors(formElement);
-
- initTargetRefDropdown();
-
- setupNativeFormVariableList({
- container: $('.js-ci-variable-list-section'),
- formField: 'schedule',
- });
-};
-
-initTimezoneDropdown();
diff --git a/app/assets/javascripts/pages/projects/pipelines/index/index.js b/app/assets/javascripts/pages/projects/pipelines/index/index.js
index 63b1f2bf975..a0ddf96ede2 100644
--- a/app/assets/javascripts/pages/projects/pipelines/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/index/index.js
@@ -1,3 +1,3 @@
-import { initPipelinesIndex } from '~/pipelines/pipelines_index';
+import { initPipelinesIndex } from '~/ci/pipeline_details/pipelines_index';
initPipelinesIndex();
diff --git a/app/assets/javascripts/pages/projects/pipelines/show/index.js b/app/assets/javascripts/pages/projects/pipelines/show/index.js
index d3f46b7e025..225479c5194 100644
--- a/app/assets/javascripts/pages/projects/pipelines/show/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/show/index.js
@@ -1,4 +1,4 @@
-import initPipelineDetails from '~/pipelines/pipeline_details_bundle';
+import initPipelineDetails from '~/ci/pipeline_details/pipeline_details_bundle';
import initPipelines from '../init_pipelines';
initPipelines();
diff --git a/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js b/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
index 4a5d5580c08..dce40c1f322 100644
--- a/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
+++ b/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
@@ -12,7 +12,6 @@ import initSettingsPanels from '~/settings_panels';
import { initTokenAccess } from '~/token_access';
import { initCiSecureFiles } from '~/ci_secure_files';
import initDeployTokens from '~/deploy_tokens';
-import { initProjectRunners } from '~/ci/runner/project_runners';
import { initProjectRunnersRegistrationDropdown } from '~/ci/runner/project_runners/register';
import { initGeneralPipelinesOptions } from '~/ci_settings_general_pipeline';
@@ -45,7 +44,6 @@ initDeployFreeze();
initSettingsPipelinesTriggers();
initArtifactsSettings();
-initProjectRunners();
initProjectRunnersRegistrationDropdown();
initSharedRunnersToggle();
initRefSwitcherBadges();
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index c43a0eb597c..bee0731d711 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -1,13 +1,11 @@
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
-
import initClustersDeprecationAlert from '~/projects/clusters_deprecation_alert';
import leaveByUrl from '~/namespaces/leave_by_url';
import initVueNotificationsDropdown from '~/notifications';
-import Star from '~/projects/star';
+import { initStarButton } from '~/projects/project_star_button';
import initTerraformNotification from '~/projects/terraform_notification';
import { initUploadFileTrigger } from '~/projects/upload_file';
import initReadMore from '~/read_more';
-
import initForksButton from '~/forks/init_forks_button';
// Project show page loads different overview content based on user preferences
@@ -46,7 +44,7 @@ initClustersDeprecationAlert();
initTerraformNotification();
initReadMore();
-new Star(); // eslint-disable-line no-new
+initStarButton();
if (document.querySelector('.js-autodevops-banner')) {
import(/* webpackChunkName: 'userCallOut' */ '~/user_callout')
diff --git a/app/assets/javascripts/pages/projects/tracing/index/index.js b/app/assets/javascripts/pages/projects/tracing/index/index.js
deleted file mode 100644
index 64ca303f8ba..00000000000
--- a/app/assets/javascripts/pages/projects/tracing/index/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import { initSimpleApp } from '~/helpers/init_simple_app_helper';
-import ListIndex from '~/tracing/list_index.vue';
-
-initSimpleApp('#js-tracing', ListIndex);
diff --git a/app/assets/javascripts/pages/projects/tracing/show/index.js b/app/assets/javascripts/pages/projects/tracing/show/index.js
deleted file mode 100644
index 107c004aa5f..00000000000
--- a/app/assets/javascripts/pages/projects/tracing/show/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import { initSimpleApp } from '~/helpers/init_simple_app_helper';
-import DetailsIndex from '~/tracing/details_index.vue';
-
-initSimpleApp('#js-tracing-details', DetailsIndex);
diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
index 5bef7e6e322..b53e2709f83 100644
--- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
@@ -67,7 +67,8 @@ export default {
metricDetailsLabel() {
if (this.metricDetails.duration && this.metricDetails.calls) {
return `${this.metricDetails.duration} / ${this.metricDetails.calls}`;
- } else if (this.metricDetails.calls) {
+ }
+ if (this.metricDetails.calls) {
return this.metricDetails.calls;
}
diff --git a/app/assets/javascripts/persistent_user_callouts.js b/app/assets/javascripts/persistent_user_callouts.js
index e7f2662ae09..cea01852630 100644
--- a/app/assets/javascripts/persistent_user_callouts.js
+++ b/app/assets/javascripts/persistent_user_callouts.js
@@ -19,13 +19,11 @@ const PERSISTENT_USER_CALLOUTS = [
'.js-namespace-storage-alert',
'.js-web-hook-disabled-callout',
'.js-merge-request-settings-callout',
- '.js-ultimate-feature-removal-banner',
'.js-geo-enable-hashed-storage-callout',
'.js-geo-migrate-hashed-storage-callout',
'.js-unlimited-members-during-trial-alert',
'.js-branch-rules-info-callout',
'.js-new-navigation-callout',
- '.js-code-suggestions-third-party-callout',
'.js-namespace-over-storage-users-combined-alert',
];
diff --git a/app/assets/javascripts/pipelines/components/dag/dag.vue b/app/assets/javascripts/pipelines/components/dag/dag.vue
deleted file mode 100644
index afb5aa05098..00000000000
--- a/app/assets/javascripts/pipelines/components/dag/dag.vue
+++ /dev/null
@@ -1,249 +0,0 @@
-<!-- eslint-disable vue/multi-word-component-names -->
-<script>
-import { GlAlert, GlButton, GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
-import { isEmpty } from 'lodash';
-import { fetchPolicies } from '~/lib/graphql';
-import { __ } from '~/locale';
-import { DEFAULT, PARSE_FAILURE, LOAD_FAILURE, UNSUPPORTED_DATA } from '../../constants';
-import getDagVisData from '../../graphql/queries/get_dag_vis_data.query.graphql';
-import { parseData } from '../parsing_utils';
-import { ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from './constants';
-import DagAnnotations from './dag_annotations.vue';
-import DagGraph from './dag_graph.vue';
-
-export default {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- name: 'Dag',
- components: {
- DagAnnotations,
- DagGraph,
- GlAlert,
- GlButton,
- GlEmptyState,
- GlLink,
- GlSprintf,
- },
- inject: {
- aboutDagDocPath: {
- default: null,
- },
- dagDocPath: {
- default: null,
- },
- emptyDagSvgPath: {
- default: '',
- },
- pipelineIid: {
- default: '',
- },
- pipelineProjectPath: {
- default: '',
- },
- },
- apollo: {
- graphData: {
- fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
- query: getDagVisData,
- variables() {
- return {
- projectPath: this.pipelineProjectPath,
- iid: this.pipelineIid,
- };
- },
- update(data) {
- if (!data?.project?.pipeline) {
- return this.graphData;
- }
-
- const {
- stages: { nodes: stages },
- } = data.project.pipeline;
-
- const unwrappedGroups = stages
- .map(({ name, groups: { nodes: groups } }) => {
- return groups.map((group) => {
- return { category: name, ...group };
- });
- })
- .flat(2);
-
- const nodes = unwrappedGroups.map((group) => {
- const jobs = group.jobs.nodes.map(({ name, needs }) => {
- return { name, needs: needs.nodes.map((need) => need.name) };
- });
-
- return { ...group, jobs };
- });
-
- return nodes;
- },
- error() {
- this.reportFailure(LOAD_FAILURE);
- },
- },
- },
- data() {
- return {
- annotationsMap: {},
- failureType: null,
- graphData: null,
- showFailureAlert: false,
- hasNoDependentJobs: false,
- };
- },
- errorTexts: {
- [LOAD_FAILURE]: __('We are currently unable to fetch data for this graph.'),
- [PARSE_FAILURE]: __('There was an error parsing the data for this graph.'),
- [UNSUPPORTED_DATA]: __('DAG visualization requires at least 3 dependent jobs.'),
- [DEFAULT]: __('An unknown error occurred while loading this graph.'),
- },
- emptyStateTexts: {
- title: __('Speed up your pipelines with Needs relationships'),
- firstDescription: __(
- 'Using the %{codeStart}needs%{codeEnd} keyword makes jobs run before their stage is reached. Jobs run as soon as their %{codeStart}needs%{codeEnd} relationships are met, which speeds up your pipelines.',
- ),
- secondDescription: __(
- "If you add %{codeStart}needs%{codeEnd} to jobs in your pipeline you'll be able to view the %{codeStart}needs%{codeEnd} relationships between jobs in this tab as a %{linkStart}Directed Acyclic Graph (DAG)%{linkEnd}.",
- ),
- button: __('Learn more about Needs relationships'),
- },
- computed: {
- failure() {
- switch (this.failureType) {
- case LOAD_FAILURE:
- return {
- text: this.$options.errorTexts[LOAD_FAILURE],
- variant: 'danger',
- };
- case PARSE_FAILURE:
- return {
- text: this.$options.errorTexts[PARSE_FAILURE],
- variant: 'danger',
- };
- case UNSUPPORTED_DATA:
- return {
- text: this.$options.errorTexts[UNSUPPORTED_DATA],
- variant: 'info',
- };
- default:
- return {
- text: this.$options.errorTexts[DEFAULT],
- variant: 'danger',
- };
- }
- },
- processedData() {
- return this.processGraphData(this.graphData);
- },
- shouldDisplayAnnotations() {
- return !isEmpty(this.annotationsMap);
- },
- shouldDisplayGraph() {
- return Boolean(!this.showFailureAlert && !this.hasNoDependentJobs && this.graphData);
- },
- },
- methods: {
- addAnnotationToMap({ uid, source, target }) {
- this.$set(this.annotationsMap, uid, { source, target });
- },
- processGraphData(data) {
- let parsed;
-
- try {
- parsed = parseData(data);
- } catch {
- this.reportFailure(PARSE_FAILURE);
- return {};
- }
-
- if (parsed.links.length === 1) {
- this.reportFailure(UNSUPPORTED_DATA);
- return {};
- }
-
- // If there are no links, we don't report failure
- // as it simply means the user does not use job dependencies
- if (parsed.links.length === 0) {
- this.hasNoDependentJobs = true;
- return {};
- }
-
- return parsed;
- },
- hideAlert() {
- this.showFailureAlert = false;
- },
- removeAnnotationFromMap({ uid }) {
- this.$delete(this.annotationsMap, uid);
- },
- reportFailure(type) {
- this.showFailureAlert = true;
- this.failureType = type;
- },
- updateAnnotation({ type, data }) {
- switch (type) {
- case ADD_NOTE:
- this.addAnnotationToMap(data);
- break;
- case REMOVE_NOTE:
- this.removeAnnotationFromMap(data);
- break;
- case REPLACE_NOTES:
- this.annotationsMap = data;
- break;
- default:
- break;
- }
- },
- },
-};
-</script>
-<template>
- <div>
- <gl-alert v-if="showFailureAlert" :variant="failure.variant" @dismiss="hideAlert">
- {{ failure.text }}
- </gl-alert>
-
- <div class="gl-relative">
- <dag-annotations v-if="shouldDisplayAnnotations" :annotations="annotationsMap" />
- <dag-graph
- v-if="shouldDisplayGraph"
- :graph-data="processedData"
- @onFailure="reportFailure"
- @update-annotation="updateAnnotation"
- />
- <gl-empty-state
- v-else-if="hasNoDependentJobs"
- :svg-path="emptyDagSvgPath"
- :title="$options.emptyStateTexts.title"
- >
- <template #description>
- <div class="gl-text-left">
- <p>
- <gl-sprintf :message="$options.emptyStateTexts.firstDescription">
- <template #code="{ content }">
- <code>{{ content }}</code>
- </template>
- </gl-sprintf>
- </p>
- <p>
- <gl-sprintf :message="$options.emptyStateTexts.secondDescription">
- <template #code="{ content }">
- <code>{{ content }}</code>
- </template>
- <template #link="{ content }">
- <gl-link :href="aboutDagDocPath">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- </div>
- </template>
- <template v-if="dagDocPath" #actions>
- <gl-button :href="dagDocPath" target="_blank" variant="confirm">
- {{ $options.emptyStateTexts.button }}
- </gl-button>
- </template>
- </gl-empty-state>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/dag/dag_graph.vue b/app/assets/javascripts/pipelines/components/dag/dag_graph.vue
deleted file mode 100644
index 7646c11773c..00000000000
--- a/app/assets/javascripts/pipelines/components/dag/dag_graph.vue
+++ /dev/null
@@ -1,329 +0,0 @@
-<script>
-import * as d3 from 'd3';
-import { uniqueId } from 'lodash';
-import { PARSE_FAILURE } from '../../constants';
-import { getMaxNodes, removeOrphanNodes } from '../parsing_utils';
-import { LINK_SELECTOR, NODE_SELECTOR, ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from './constants';
-import { calculateClip, createLinkPath, createSankey, labelPosition } from './drawing_utils';
-import {
- currentIsLive,
- getLiveLinksAsDict,
- highlightLinks,
- restoreLinks,
- toggleLinkHighlight,
- togglePathHighlights,
-} from './interactions';
-
-export default {
- viewOptions: {
- baseHeight: 300,
- baseWidth: 1000,
- minNodeHeight: 60,
- nodeWidth: 16,
- nodePadding: 25,
- paddingForLabels: 100,
- labelMargin: 8,
-
- baseOpacity: 0.8,
- containerClasses: ['dag-graph-container', 'gl-display-flex', 'gl-flex-direction-column'].join(
- ' ',
- ),
- hoverFadeClasses: [
- 'gl-cursor-pointer',
- 'gl-transition-duration-slow',
- 'gl-transition-timing-function-ease',
- ].join(' '),
- },
- gitLabColorRotation: [
- '#e17223',
- '#83ab4a',
- '#5772ff',
- '#b24800',
- '#25d2d2',
- '#006887',
- '#487900',
- '#d84280',
- '#3547de',
- '#6f3500',
- '#006887',
- '#275600',
- '#b31756',
- ],
- props: {
- graphData: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- color: () => {},
- height: 0,
- width: 0,
- };
- },
- mounted() {
- let countedAndTransformed;
-
- try {
- countedAndTransformed = this.transformData(this.graphData);
- } catch {
- this.$emit('on-failure', PARSE_FAILURE);
- return;
- }
-
- this.drawGraph(countedAndTransformed);
- },
- methods: {
- addSvg() {
- return d3
- .select('.dag-graph-container')
- .append('svg')
- .attr('viewBox', [0, 0, this.width, this.height])
- .attr('width', this.width)
- .attr('height', this.height);
- },
-
- appendLinks(link) {
- return (
- link
- .append('path')
- .attr('d', (d, i) => createLinkPath(d, i, this.$options.viewOptions.nodeWidth))
- .attr('stroke', ({ gradId }) => `url(#${gradId})`)
- .style('stroke-linejoin', 'round')
- // minus two to account for the rounded nodes
- .attr('stroke-width', ({ width }) => Math.max(1, width - 2))
- .attr('clip-path', ({ clipId }) => `url(#${clipId})`)
- );
- },
-
- appendLinkInteractions(link) {
- const { baseOpacity } = this.$options.viewOptions;
- return link
- .on('mouseover', (d, idx, collection) => {
- if (currentIsLive(idx, collection)) {
- return;
- }
- this.$emit('update-annotation', { type: ADD_NOTE, data: d });
- highlightLinks(d, idx, collection);
- })
- .on('mouseout', (d, idx, collection) => {
- if (currentIsLive(idx, collection)) {
- return;
- }
- this.$emit('update-annotation', { type: REMOVE_NOTE, data: d });
- restoreLinks(baseOpacity);
- })
- .on('click', (d, idx, collection) => {
- toggleLinkHighlight(baseOpacity, d, idx, collection);
- this.$emit('update-annotation', { type: REPLACE_NOTES, data: getLiveLinksAsDict() });
- });
- },
-
- appendNodeInteractions(node) {
- return node.on('click', (d, idx, collection) => {
- togglePathHighlights(this.$options.viewOptions.baseOpacity, d, idx, collection);
- this.$emit('update-annotation', { type: REPLACE_NOTES, data: getLiveLinksAsDict() });
- });
- },
-
- appendLabelAsForeignObject(d, i, n) {
- const currentNode = n[i];
- const { height, wrapperWidth, width, x, y, textAlign } = labelPosition(d, {
- ...this.$options.viewOptions,
- width: this.width,
- });
-
- const labelClasses = [
- 'gl-display-flex',
- 'gl-pointer-events-none',
- 'gl-flex-direction-column',
- 'gl-justify-content-center',
- 'gl-overflow-wrap-break',
- ].join(' ');
-
- return (
- d3
- .select(currentNode)
- .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
- .attr('height', height)
- /*
- items with a 'max-content' width will have a wrapperWidth for the foreignObject
- */
- .attr('width', wrapperWidth || width)
- .attr('x', x)
- .attr('y', y)
- .classed('gl-overflow-visible', true)
- .append('xhtml:div')
- .classed(labelClasses, true)
- .style('height', height)
- .style('width', width)
- .style('text-align', textAlign)
- .text(({ name }) => name)
- );
- },
-
- createAndAssignId(datum, field, modifier = '') {
- const id = uniqueId(modifier);
- /* eslint-disable-next-line no-param-reassign */
- datum[field] = id;
- return id;
- },
-
- createClip(link) {
- return link
- .append('clipPath')
- .attr('id', (d) => {
- return this.createAndAssignId(d, 'clipId', 'dag-clip');
- })
- .append('path')
- .attr('d', calculateClip);
- },
-
- createGradient(link) {
- const gradient = link
- .append('linearGradient')
- .attr('id', (d) => {
- return this.createAndAssignId(d, 'gradId', 'dag-grad');
- })
- .attr('gradientUnits', 'userSpaceOnUse')
- .attr('x1', ({ source }) => source.x1)
- .attr('x2', ({ target }) => target.x0);
-
- gradient
- .append('stop')
- .attr('offset', '0%')
- .attr('stop-color', ({ source }) => this.color(source));
-
- gradient
- .append('stop')
- .attr('offset', '100%')
- .attr('stop-color', ({ target }) => this.color(target));
- },
-
- createLinks(svg, linksData) {
- const links = this.generateLinks(svg, linksData);
- this.createGradient(links);
- this.createClip(links);
- this.appendLinks(links);
- this.appendLinkInteractions(links);
- },
-
- createNodes(svg, nodeData) {
- const nodes = this.generateNodes(svg, nodeData);
- this.labelNodes(svg, nodeData);
- this.appendNodeInteractions(nodes);
- },
-
- drawGraph({ maxNodesPerLayer, linksAndNodes }) {
- const {
- baseWidth,
- baseHeight,
- minNodeHeight,
- nodeWidth,
- nodePadding,
- paddingForLabels,
- } = this.$options.viewOptions;
-
- this.width = baseWidth;
- this.height = baseHeight + maxNodesPerLayer * minNodeHeight;
- this.color = this.initColors();
-
- const { links, nodes } = createSankey({
- width: this.width,
- height: this.height,
- nodeWidth,
- nodePadding,
- paddingForLabels,
- })(linksAndNodes);
-
- const svg = this.addSvg();
- this.createLinks(svg, links);
- this.createNodes(svg, nodes);
- },
-
- generateLinks(svg, linksData) {
- return svg
- .append('g')
- .attr('fill', 'none')
- .attr('stroke-opacity', this.$options.viewOptions.baseOpacity)
- .selectAll(`.${LINK_SELECTOR}`)
- .data(linksData)
- .enter()
- .append('g')
- .attr('id', (d) => {
- return this.createAndAssignId(d, 'uid', LINK_SELECTOR);
- })
- .classed(
- `${LINK_SELECTOR} gl-transition-property-stroke-opacity ${this.$options.viewOptions.hoverFadeClasses}`,
- true,
- );
- },
-
- generateNodes(svg, nodeData) {
- const { nodeWidth } = this.$options.viewOptions;
-
- return svg
- .append('g')
- .selectAll(`.${NODE_SELECTOR}`)
- .data(nodeData)
- .enter()
- .append('line')
- .classed(
- `${NODE_SELECTOR} gl-transition-property-stroke ${this.$options.viewOptions.hoverFadeClasses}`,
- true,
- )
- .attr('id', (d) => {
- return this.createAndAssignId(d, 'uid', NODE_SELECTOR);
- })
- .attr('stroke', (d) => {
- const color = this.color(d);
- /* eslint-disable-next-line no-param-reassign */
- d.color = color;
- return color;
- })
- .attr('stroke-width', nodeWidth)
- .attr('stroke-linecap', 'round')
- .attr('x1', (d) => Math.floor((d.x1 + d.x0) / 2))
- .attr('x2', (d) => Math.floor((d.x1 + d.x0) / 2))
- .attr('y1', (d) => d.y0 + 4)
- .attr('y2', (d) => d.y1 - 4);
- },
-
- initColors() {
- const colorFn = d3.scaleOrdinal(this.$options.gitLabColorRotation);
- return ({ name }) => colorFn(name);
- },
-
- labelNodes(svg, nodeData) {
- return svg
- .append('g')
- .classed('gl-font-sm', true)
- .selectAll('text')
- .data(nodeData)
- .enter()
- .append('foreignObject')
- .each(this.appendLabelAsForeignObject);
- },
-
- transformData(parsed) {
- const baseLayout = createSankey()(parsed);
- const cleanedNodes = removeOrphanNodes(baseLayout.nodes);
- const maxNodesPerLayer = getMaxNodes(cleanedNodes);
-
- return {
- maxNodesPerLayer,
- linksAndNodes: {
- links: parsed.links,
- nodes: cleanedNodes,
- },
- };
- },
- },
-};
-</script>
-<template>
- <div :class="$options.viewOptions.containerClasses" data-testid="dag-graph-container">
- <!-- graph goes here -->
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/dag/interactions.js b/app/assets/javascripts/pipelines/components/dag/interactions.js
deleted file mode 100644
index 69f36feeee4..00000000000
--- a/app/assets/javascripts/pipelines/components/dag/interactions.js
+++ /dev/null
@@ -1,154 +0,0 @@
-import * as d3 from 'd3';
-import { LINK_SELECTOR, NODE_SELECTOR, IS_HIGHLIGHTED } from './constants';
-
-export const highlightIn = 1;
-export const highlightOut = 0.2;
-
-const getCurrent = (idx, collection) => d3.select(collection[idx]);
-const getLiveLinks = () => d3.selectAll(`.${LINK_SELECTOR}.${IS_HIGHLIGHTED}`);
-const getOtherLinks = () => d3.selectAll(`.${LINK_SELECTOR}:not(.${IS_HIGHLIGHTED})`);
-const getNodesNotLive = () => d3.selectAll(`.${NODE_SELECTOR}:not(.${IS_HIGHLIGHTED})`);
-
-export const getLiveLinksAsDict = () => {
- return Object.fromEntries(
- getLiveLinks()
- .data()
- .map((d) => [d.uid, d]),
- );
-};
-export const currentIsLive = (idx, collection) =>
- getCurrent(idx, collection).classed(IS_HIGHLIGHTED);
-
-const backgroundLinks = (selection) => selection.style('stroke-opacity', highlightOut);
-const backgroundNodes = (selection) => selection.attr('stroke', '#f2f2f2');
-const foregroundLinks = (selection) => selection.style('stroke-opacity', highlightIn);
-const foregroundNodes = (selection) => selection.attr('stroke', (d) => d.color);
-const renewLinks = (selection, baseOpacity) => selection.style('stroke-opacity', baseOpacity);
-const renewNodes = (selection) => selection.attr('stroke', (d) => d.color);
-
-export const getAllLinkAncestors = (node) => {
- if (node.targetLinks) {
- return node.targetLinks.flatMap((n) => {
- return [n, ...getAllLinkAncestors(n.source)];
- });
- }
-
- return [];
-};
-
-const getAllNodeAncestors = (node) => {
- let allNodes = [];
-
- if (node.targetLinks) {
- allNodes = node.targetLinks.flatMap((n) => {
- return getAllNodeAncestors(n.source);
- });
- }
-
- return [...allNodes, node.uid];
-};
-
-export const highlightLinks = (d, idx, collection) => {
- const currentLink = getCurrent(idx, collection);
- const currentSourceNode = d3.select(`#${d.source.uid}`);
- const currentTargetNode = d3.select(`#${d.target.uid}`);
-
- /* Higlight selected link, de-emphasize others */
- backgroundLinks(getOtherLinks());
- foregroundLinks(currentLink);
-
- /* Do the same to related nodes */
- backgroundNodes(getNodesNotLive());
- foregroundNodes(currentSourceNode);
- foregroundNodes(currentTargetNode);
-};
-
-const highlightPath = (parentLinks, parentNodes) => {
- /* de-emphasize everything else */
- backgroundLinks(getOtherLinks());
- backgroundNodes(getNodesNotLive());
-
- /* highlight correct links */
- parentLinks.forEach(({ uid }) => {
- foregroundLinks(d3.select(`#${uid}`)).classed(IS_HIGHLIGHTED, true);
- });
-
- /* highlight correct nodes */
- parentNodes.forEach((id) => {
- foregroundNodes(d3.select(`#${id}`)).classed(IS_HIGHLIGHTED, true);
- });
-};
-
-const restoreNodes = () => {
- /*
- When paths are unclicked, they can take down nodes that
- are still in use for other paths. This checks the live paths and
- rehighlights their nodes.
- */
-
- getLiveLinks().each((d) => {
- foregroundNodes(d3.select(`#${d.source.uid}`)).classed(IS_HIGHLIGHTED, true);
- foregroundNodes(d3.select(`#${d.target.uid}`)).classed(IS_HIGHLIGHTED, true);
- });
-};
-
-const restorePath = (parentLinks, parentNodes, baseOpacity) => {
- parentLinks.forEach(({ uid }) => {
- renewLinks(d3.select(`#${uid}`), baseOpacity).classed(IS_HIGHLIGHTED, false);
- });
-
- parentNodes.forEach((id) => {
- d3.select(`#${id}`).classed(IS_HIGHLIGHTED, false);
- });
-
- if (d3.selectAll(`.${IS_HIGHLIGHTED}`).empty()) {
- renewLinks(getOtherLinks(), baseOpacity);
- renewNodes(getNodesNotLive());
- return;
- }
-
- backgroundLinks(getOtherLinks());
- backgroundNodes(getNodesNotLive());
- restoreNodes();
-};
-
-export const restoreLinks = (baseOpacity) => {
- /*
- if there exist live links, reset to highlight out / pale
- otherwise, reset to base
- */
-
- if (d3.selectAll(`.${IS_HIGHLIGHTED}`).empty()) {
- renewLinks(d3.selectAll(`.${LINK_SELECTOR}`), baseOpacity);
- renewNodes(d3.selectAll(`.${NODE_SELECTOR}`));
- return;
- }
-
- backgroundLinks(getOtherLinks());
- backgroundNodes(getNodesNotLive());
-};
-
-export const toggleLinkHighlight = (baseOpacity, d, idx, collection) => {
- if (currentIsLive(idx, collection)) {
- restorePath([d], [d.source.uid, d.target.uid], baseOpacity);
- restoreNodes();
- return;
- }
-
- highlightPath([d], [d.source.uid, d.target.uid]);
-};
-
-export const togglePathHighlights = (baseOpacity, d, idx, collection) => {
- const parentLinks = getAllLinkAncestors(d);
- const parentNodes = getAllNodeAncestors(d);
- const currentNode = getCurrent(idx, collection);
-
- /* if this node is already live, make it unlive and reset its path */
- if (currentIsLive(idx, collection)) {
- currentNode.classed(IS_HIGHLIGHTED, false);
- restorePath(parentLinks, parentNodes, baseOpacity);
- return;
- }
-
- highlightPath(parentLinks, parentNodes);
-};
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
deleted file mode 100644
index 49df71beeec..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue
+++ /dev/null
@@ -1,261 +0,0 @@
-<script>
-import { reportToSentry } from '../../utils';
-import LinkedGraphWrapper from '../graph_shared/linked_graph_wrapper.vue';
-import LinksLayer from '../graph_shared/links_layer.vue';
-import {
- generateColumnsFromLayersListMemoized,
- keepLatestDownstreamPipelines,
-} from '../parsing_utils';
-import { DOWNSTREAM, MAIN, UPSTREAM, ONE_COL_WIDTH, STAGE_VIEW } from './constants';
-import LinkedPipelinesColumn from './linked_pipelines_column.vue';
-import StageColumnComponent from './stage_column_component.vue';
-import { validateConfigPaths } from './utils';
-
-export default {
- name: 'PipelineGraph',
- components: {
- LinksLayer,
- LinkedGraphWrapper,
- LinkedPipelinesColumn,
- StageColumnComponent,
- },
- props: {
- configPaths: {
- type: Object,
- required: true,
- validator: validateConfigPaths,
- },
- pipeline: {
- type: Object,
- required: true,
- },
- showLinks: {
- type: Boolean,
- required: true,
- },
- viewType: {
- type: String,
- required: true,
- },
- isLinkedPipeline: {
- type: Boolean,
- required: false,
- default: false,
- },
- computedPipelineInfo: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- skipRetryModal: {
- type: Boolean,
- required: false,
- default: false,
- },
- type: {
- type: String,
- required: false,
- default: MAIN,
- },
- },
- pipelineTypeConstants: {
- DOWNSTREAM,
- UPSTREAM,
- },
- CONTAINER_REF: 'PIPELINE_LINKS_CONTAINER_REF',
- BASE_CONTAINER_ID: 'pipeline-links-container',
- data() {
- return {
- hoveredJobName: '',
- hoveredSourceJobName: '',
- highlightedJobs: [],
- measurements: {
- width: 0,
- height: 0,
- },
- pipelineExpanded: {
- jobName: '',
- expanded: false,
- },
- };
- },
- computed: {
- containerId() {
- return `${this.$options.BASE_CONTAINER_ID}-${this.pipeline.id}`;
- },
- downstreamPipelines() {
- return this.hasDownstreamPipelines
- ? keepLatestDownstreamPipelines(this.pipeline.downstream)
- : [];
- },
- layout() {
- return this.isStageView
- ? this.pipeline.stages
- : generateColumnsFromLayersListMemoized(
- this.pipeline,
- this.computedPipelineInfo.pipelineLayers,
- );
- },
- hasDownstreamPipelines() {
- return Boolean(this.pipeline?.downstream?.length > 0);
- },
- hasUpstreamPipelines() {
- return Boolean(this.pipeline?.upstream?.length > 0);
- },
- isStageView() {
- return this.viewType === STAGE_VIEW;
- },
- linksData() {
- return this.computedPipelineInfo?.linksData ?? null;
- },
- metricsConfig() {
- return {
- path: this.configPaths.metricsPath,
- collectMetrics: true,
- };
- },
- showJobLinks() {
- return !this.isStageView && this.showLinks;
- },
- // The show downstream check prevents showing redundant linked columns
- showDownstreamPipelines() {
- return (
- this.hasDownstreamPipelines && this.type !== this.$options.pipelineTypeConstants.UPSTREAM
- );
- },
- // The show upstream check prevents showing redundant linked columns
- showUpstreamPipelines() {
- return (
- this.hasUpstreamPipelines && this.type !== this.$options.pipelineTypeConstants.DOWNSTREAM
- );
- },
- upstreamPipelines() {
- return this.hasUpstreamPipelines ? this.pipeline.upstream : [];
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
- },
- mounted() {
- this.getMeasurements();
- },
- methods: {
- getMeasurements() {
- this.measurements = {
- width: this.$refs[this.containerId].scrollWidth,
- height: this.$refs[this.containerId].scrollHeight,
- };
- },
- onError(payload) {
- this.$emit('error', payload);
- },
- setJob(jobName) {
- this.hoveredJobName = jobName;
- },
- setSourceJob(jobName) {
- this.hoveredSourceJobName = jobName;
- },
- slidePipelineContainer() {
- this.$refs.mainPipelineContainer.scrollBy({
- left: ONE_COL_WIDTH,
- top: 0,
- behavior: 'smooth',
- });
- },
- togglePipelineExpanded(jobName, expanded) {
- this.pipelineExpanded = {
- expanded,
- jobName: expanded ? jobName : '',
- };
- },
- updateHighlightedJobs(jobs) {
- this.highlightedJobs = jobs;
- },
- },
-};
-</script>
-<template>
- <div class="js-pipeline-graph">
- <div
- ref="mainPipelineContainer"
- class="gl-display-flex gl-position-relative gl-bg-gray-10 gl-white-space-nowrap"
- :class="{
- 'gl-pipeline-min-h gl-py-5 gl-overflow-auto': !isLinkedPipeline,
- }"
- >
- <linked-graph-wrapper>
- <template #upstream>
- <linked-pipelines-column
- v-if="showUpstreamPipelines"
- :config-paths="configPaths"
- :linked-pipelines="upstreamPipelines"
- :column-title="__('Upstream')"
- :show-links="showJobLinks"
- :skip-retry-modal="skipRetryModal"
- :type="$options.pipelineTypeConstants.UPSTREAM"
- :view-type="viewType"
- @error="onError"
- @setSkipRetryModal="$emit('setSkipRetryModal')"
- />
- </template>
- <template #main>
- <div :id="containerId" :ref="containerId">
- <links-layer
- :pipeline-data="layout"
- :pipeline-id="pipeline.id"
- :container-id="containerId"
- :container-measurements="measurements"
- :highlighted-job="hoveredJobName"
- :links-data="linksData"
- :metrics-config="metricsConfig"
- :show-links="showJobLinks"
- :view-type="viewType"
- @error="onError"
- @highlightedJobsChange="updateHighlightedJobs"
- >
- <stage-column-component
- v-for="column in layout"
- :key="column.id || column.name"
- :name="column.name"
- :groups="column.groups"
- :action="column.status.action"
- :highlighted-jobs="highlightedJobs"
- :is-stage-view="isStageView"
- :job-hovered="hoveredJobName"
- :skip-retry-modal="skipRetryModal"
- :source-job-hovered="hoveredSourceJobName"
- :pipeline-expanded="pipelineExpanded"
- :pipeline-id="pipeline.id"
- :user-permissions="pipeline.userPermissions"
- @refreshPipelineGraph="$emit('refreshPipelineGraph')"
- @setSkipRetryModal="$emit('setSkipRetryModal')"
- @jobHover="setJob"
- @updateMeasurements="getMeasurements"
- />
- </links-layer>
- </div>
- </template>
- <template #downstream>
- <linked-pipelines-column
- v-if="showDownstreamPipelines"
- class="gl-mr-6"
- :config-paths="configPaths"
- :linked-pipelines="downstreamPipelines"
- :column-title="__('Downstream')"
- :skip-retry-modal="skipRetryModal"
- :show-links="showJobLinks"
- :type="$options.pipelineTypeConstants.DOWNSTREAM"
- :view-type="viewType"
- data-testid="downstream-pipelines"
- @downstreamHovered="setSourceJob"
- @pipelineExpandToggle="togglePipelineExpanded"
- @refreshPipelineGraph="$emit('refreshPipelineGraph')"
- @setSkipRetryModal="$emit('setSkipRetryModal')"
- @scrollContainer="slidePipelineContainer"
- @error="onError"
- />
- </template>
- </linked-graph-wrapper>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue b/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue
deleted file mode 100644
index b2cef7c37b9..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue
+++ /dev/null
@@ -1,345 +0,0 @@
-<script>
-import { GlAlert, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
-import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
-import getUserCallouts from '~/graphql_shared/queries/get_user_callouts.query.graphql';
-import { __, s__ } from '~/locale';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants';
-import DismissPipelineGraphCallout from '../../graphql/mutations/dismiss_pipeline_notification.graphql';
-import getPipelineQuery from '../../graphql/queries/get_pipeline_header_data.query.graphql';
-import { reportToSentry, reportMessageToSentry } from '../../utils';
-import {
- ACTION_FAILURE,
- IID_FAILURE,
- LAYER_VIEW,
- SKIP_RETRY_MODAL_KEY,
- STAGE_VIEW,
- VIEW_TYPE_KEY,
-} from './constants';
-import PipelineGraph from './graph_component.vue';
-import GraphViewSelector from './graph_view_selector.vue';
-import {
- calculatePipelineLayersInfo,
- getQueryHeaders,
- serializeLoadErrors,
- toggleQueryPollingByVisibility,
- unwrapPipelineData,
-} from './utils';
-
-const featureName = 'pipeline_needs_hover_tip';
-const enumFeatureName = featureName.toUpperCase();
-
-export default {
- name: 'PipelineGraphWrapper',
- components: {
- GlAlert,
- GlLoadingIcon,
- GlSprintf,
- GraphViewSelector,
- LocalStorageSync,
- PipelineGraph,
- },
- inject: {
- graphqlResourceEtag: {
- default: '',
- },
- metricsPath: {
- default: '',
- },
- pipelineIid: {
- default: '',
- },
- pipelineProjectPath: {
- default: '',
- },
- },
- data() {
- return {
- alertType: null,
- callouts: [],
- computedPipelineInfo: null,
- currentViewType: STAGE_VIEW,
- canRefetchHeaderPipeline: false,
- pipeline: null,
- skipRetryModal: false,
- showAlert: false,
- showJobCountWarning: false,
- showLinks: false,
- };
- },
- errors: {
- [ACTION_FAILURE]: {
- text: __('An error occurred while performing this action.'),
- variant: 'danger',
- },
- [DRAW_FAILURE]: {
- text: __('An error occurred while drawing job relationship links.'),
- variant: 'danger',
- },
- [IID_FAILURE]: {
- text: __(
- 'The data in this pipeline is too old to be rendered as a graph. Please check the Jobs tab to access historical data.',
- ),
- variant: 'info',
- },
- [LOAD_FAILURE]: {
- text: __('Currently unable to fetch data for this pipeline.'),
- variant: 'danger',
- },
- [DEFAULT]: {
- text: __('An unknown error occurred while loading this graph.'),
- variant: 'danger',
- },
- },
- apollo: {
- callouts: {
- query: getUserCallouts,
- update(data) {
- return data?.currentUser?.callouts?.nodes.map((callout) => callout.featureName) || [];
- },
- error(err) {
- reportToSentry(
- this.$options.name,
- `type: callout_load_failure, info: ${serializeLoadErrors(err)}`,
- );
- },
- },
- headerPipeline: {
- query: getPipelineQuery,
- // this query is already being called in pipeline_details_header.vue, which shares the same cache as this component
- // the skip here is to prevent sending double network requests on page load
- skip() {
- return !this.canRefetchHeaderPipeline;
- },
- variables() {
- return {
- fullPath: this.pipelineProjectPath,
- iid: this.pipelineIid,
- };
- },
- update(data) {
- return data.project?.pipeline || {};
- },
- error() {
- this.reportFailure({ type: LOAD_FAILURE, skipSentry: true });
- },
- },
- pipeline: {
- context() {
- return getQueryHeaders(this.graphqlResourceEtag);
- },
- query: getPipelineDetails,
- pollInterval: 10000,
- variables() {
- return {
- projectPath: this.pipelineProjectPath,
- iid: this.pipelineIid,
- };
- },
- skip() {
- return !(this.pipelineProjectPath && this.pipelineIid);
- },
- update(data) {
- /*
- This check prevents the pipeline from being overwritten
- when a poll times out and the data returned is empty.
- This can be removed once the timeout behavior is updated.
- See: https://gitlab.com/gitlab-org/gitlab/-/issues/323213.
- */
-
- if (!data?.project?.pipeline) {
- return this.pipeline;
- }
-
- return unwrapPipelineData(this.pipelineProjectPath, JSON.parse(JSON.stringify(data)));
- },
- error(err) {
- this.reportFailure({ type: LOAD_FAILURE, skipSentry: true });
-
- reportMessageToSentry(
- this.$options.name,
- `| type: ${LOAD_FAILURE} , info: ${JSON.stringify(err)}`,
- {
- graphViewType: this.graphViewType,
- graphqlResourceEtag: this.graphqlResourceEtag,
- metricsPath: this.metricsPath,
- projectPath: this.pipelineProjectPath,
- pipelineIid: this.pipelineIid,
- },
- );
- },
- result({ data, error }) {
- const stages = data?.project?.pipeline?.stages?.nodes || [];
-
- this.showJobCountWarning = stages.some((stage) => {
- return stage.groups.nodes.length >= 100;
- });
- /*
- If there is a successful load after a failure, clear
- the failure notification to avoid confusion.
- */
- if (!error && this.alertType === LOAD_FAILURE) {
- this.hideAlert();
- }
- },
- },
- },
- computed: {
- alert() {
- const { errors } = this.$options;
-
- return {
- text: errors[this.alertType]?.text ?? errors[DEFAULT].text,
- variant: errors[this.alertType]?.variant ?? errors[DEFAULT].variant,
- };
- },
- configPaths() {
- return {
- graphqlResourceEtag: this.graphqlResourceEtag,
- metricsPath: this.metricsPath,
- };
- },
- graphViewType() {
- /* This prevents reading view type off the localStorage value if it does not apply. */
- return this.showGraphViewSelector ? this.currentViewType : STAGE_VIEW;
- },
- hoverTipPreviouslyDismissed() {
- return this.callouts.includes(enumFeatureName);
- },
- showLoadingIcon() {
- /*
- Shows the icon only when the graph is empty, not when it is is
- being refetched, for instance, on action completion
- */
- return this.$apollo.queries.pipeline.loading && !this.pipeline;
- },
- showGraphViewSelector() {
- return this.pipeline?.usesNeeds;
- },
- },
- mounted() {
- if (!this.pipelineIid) {
- this.reportFailure({ type: IID_FAILURE, skipSentry: true });
- }
- toggleQueryPollingByVisibility(this.$apollo.queries.pipeline);
- this.skipRetryModal = Boolean(JSON.parse(localStorage.getItem(SKIP_RETRY_MODAL_KEY)));
- },
- errorCaptured(err, _vm, info) {
- reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
- },
- methods: {
- getPipelineInfo() {
- if (this.currentViewType === LAYER_VIEW && !this.computedPipelineInfo) {
- this.computedPipelineInfo = calculatePipelineLayersInfo(
- this.pipeline,
- this.$options.name,
- this.metricsPath,
- );
- }
-
- return this.computedPipelineInfo;
- },
- handleTipDismissal() {
- try {
- this.$apollo.mutate({
- mutation: DismissPipelineGraphCallout,
- variables: {
- featureName,
- },
- });
- } catch (err) {
- reportToSentry(this.$options.name, `type: callout_dismiss_failure, info: ${err}`);
- }
- },
- hideAlert() {
- this.showAlert = false;
- this.alertType = null;
- },
- refreshPipelineGraph() {
- this.$apollo.queries.pipeline.refetch();
-
- // this will update the status in header_component since they share the same cache
- this.canRefetchHeaderPipeline = true;
- this.$apollo.queries.headerPipeline.refetch();
- },
- // eslint-disable-next-line @gitlab/require-i18n-strings
- reportFailure({ type, err = 'No error string passed.', skipSentry = false }) {
- this.showAlert = true;
- this.alertType = type;
- if (!skipSentry) {
- reportToSentry(this.$options.name, `type: ${type}, info: ${err}`);
- }
- },
- updateShowLinksState(val) {
- this.showLinks = val;
- },
- setSkipRetryModal() {
- this.skipRetryModal = true;
- },
- updateViewType(type) {
- this.currentViewType = type;
- },
- },
- i18n: {
- jobLimitWarning: {
- title: s__('Pipeline|Only the first 100 jobs per stage are displayed'),
- desc: s__('Pipeline|To see the remaining jobs, go to the %{boldStart}Jobs%{boldEnd} tab.'),
- },
- },
- viewTypeKey: VIEW_TYPE_KEY,
-};
-</script>
-<template>
- <div>
- <gl-alert
- v-if="showAlert"
- :variant="alert.variant"
- data-testid="error-alert"
- @dismiss="hideAlert"
- >
- {{ alert.text }}
- </gl-alert>
- <gl-alert
- v-if="showJobCountWarning"
- variant="warning"
- :dismissible="false"
- :title="$options.i18n.jobLimitWarning.title"
- data-testid="job-count-warning"
- >
- <gl-sprintf :message="$options.i18n.jobLimitWarning.desc">
- <template #bold="{ content }">
- <b>{{ content }}</b>
- </template>
- </gl-sprintf>
- </gl-alert>
- <local-storage-sync
- :storage-key="$options.viewTypeKey"
- :value="currentViewType"
- as-string
- @input="updateViewType"
- >
- <graph-view-selector
- v-if="showGraphViewSelector"
- :type="graphViewType"
- :show-links="showLinks"
- :tip-previously-dismissed="hoverTipPreviouslyDismissed"
- @dismissHoverTip="handleTipDismissal"
- @updateViewType="updateViewType"
- @updateShowLinksState="updateShowLinksState"
- />
- </local-storage-sync>
- <gl-loading-icon v-if="showLoadingIcon" class="gl-mx-auto gl-my-4" size="lg" />
- <pipeline-graph
- v-if="pipeline"
- :config-paths="configPaths"
- :pipeline="pipeline"
- :computed-pipeline-info="getPipelineInfo()"
- :skip-retry-modal="skipRetryModal"
- :show-links="showLinks"
- :view-type="graphViewType"
- @error="reportFailure"
- @refreshPipelineGraph="refreshPipelineGraph"
- @setSkipRetryModal="setSkipRetryModal"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue b/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue
deleted file mode 100644
index 73143c981ed..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue
+++ /dev/null
@@ -1,176 +0,0 @@
-<script>
-import { GlAlert, GlButton, GlButtonGroup, GlLoadingIcon, GlToggle } from '@gitlab/ui';
-import { __, s__ } from '~/locale';
-import { STAGE_VIEW, LAYER_VIEW } from './constants';
-
-export default {
- name: 'GraphViewSelector',
-
- components: {
- GlAlert,
- GlButton,
- GlButtonGroup,
- GlLoadingIcon,
- GlToggle,
- },
-
- props: {
- showLinks: {
- type: Boolean,
- required: true,
- },
- tipPreviouslyDismissed: {
- type: Boolean,
- required: true,
- },
- type: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- hoverTipDismissed: false,
- isToggleLoading: false,
- isSwitcherLoading: false,
- segmentSelectedType: this.type,
- showLinksActive: false,
- };
- },
- i18n: {
- hoverTipText: __('Tip: Hover over a job to see the jobs it depends on to run.'),
- linksLabelText: s__('GraphViewType|Show dependencies'),
- viewLabelText: __('Group jobs by'),
- },
- views: {
- [STAGE_VIEW]: {
- type: STAGE_VIEW,
- text: {
- primary: s__('GraphViewType|Stage'),
- },
- },
- [LAYER_VIEW]: {
- type: LAYER_VIEW,
- text: {
- primary: s__('GraphViewType|Job dependencies'),
- },
- },
- },
- computed: {
- showLinksToggle() {
- return this.segmentSelectedType === LAYER_VIEW;
- },
- showTip() {
- return (
- this.showLinksToggle &&
- this.showLinks &&
- this.showLinksActive &&
- !this.tipPreviouslyDismissed &&
- !this.hoverTipDismissed
- );
- },
- viewTypesList() {
- return Object.keys(this.$options.views).map((key) => {
- return {
- value: key,
- text: this.$options.views[key].text.primary,
- };
- });
- },
- },
- watch: {
- /*
- How does this reset the loading? As we note in the methods comment below,
- the loader is set to on before the update work is undertaken (in the parent).
- Once the work is complete, one of these values will change, since that's the
- point of the work. When that happens, the related value will update and we are done.
-
- The bonus for this approach is that it works the same whichever "direction"
- the work goes in.
- */
- showLinks() {
- this.isToggleLoading = false;
- },
- type() {
- this.isSwitcherLoading = false;
- },
- },
- methods: {
- dismissTip() {
- this.hoverTipDismissed = true;
- this.$emit('dismissHoverTip');
- },
- isCurrentType(type) {
- return this.segmentSelectedType === type;
- },
- /*
- In both toggle methods, we use setTimeout so that the loading indicator displays,
- then the work is done to update the DOM. The process is:
- → user clicks
- → call stack: set loading to true
- → render: the loading icon appears on the screen
- → callback queue: now do the work to calculate the new view / links
- (note: this work is done in the parent after the event is emitted)
-
- setTimeout is how we move the work to the callback queue.
- We can't use nextTick because that is called before the render loop.
-
- See https://www.hesselinkwebdesign.nl/2019/nexttick-vs-settimeout-in-vue/ for more details.
- */
- setViewType(type) {
- if (!this.isCurrentType(type)) {
- this.isSwitcherLoading = true;
- this.segmentSelectedType = type;
- setTimeout(() => {
- this.$emit('updateViewType', type);
- });
- }
- },
- toggleShowLinksActive(val) {
- this.isToggleLoading = true;
- setTimeout(() => {
- this.$emit('updateShowLinksState', val);
- });
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div class="gl-relative gl-display-flex gl-align-items-center gl-w-max-content gl-my-4">
- <gl-loading-icon
- v-if="isSwitcherLoading"
- data-testid="switcher-loading-state"
- class="gl-absolute gl-w-full gl-bg-white gl-opacity-5 gl-z-index-2"
- size="lg"
- />
- <span class="gl-font-weight-bold">{{ $options.i18n.viewLabelText }}</span>
- <gl-button-group class="gl-mx-4">
- <gl-button
- v-for="viewType in viewTypesList"
- :key="viewType.value"
- :selected="isCurrentType(viewType.value)"
- @click="setViewType(viewType.value)"
- >
- {{ viewType.text }}
- </gl-button>
- </gl-button-group>
-
- <div v-if="showLinksToggle" class="gl-display-flex gl-align-items-center">
- <gl-toggle
- v-model="showLinksActive"
- data-testid="show-links-toggle"
- class="gl-mx-4"
- :label="$options.i18n.linksLabelText"
- :is-loading="isToggleLoading"
- label-position="left"
- @change="toggleShowLinksActive"
- />
- </div>
- </div>
- <gl-alert v-if="showTip" class="gl-my-5" variant="tip" @dismiss="dismissTip">
- {{ $options.i18n.hoverTipText }}
- </gl-alert>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
deleted file mode 100644
index d4852224df5..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
+++ /dev/null
@@ -1,110 +0,0 @@
-<script>
-import { reportToSentry } from '../../utils';
-import { JOB_DROPDOWN, SINGLE_JOB } from './constants';
-import JobItem from './job_item.vue';
-
-/**
- * Renders the dropdown for the pipeline graph.
- *
- * The object provided as `group` corresponds to app/serializers/job_group_entity.rb.
- *
- */
-export default {
- components: {
- JobItem,
- },
- props: {
- group: {
- type: Object,
- required: true,
- },
- pipelineId: {
- type: Number,
- required: false,
- default: -1,
- },
- cssClassJobName: {
- type: [String, Array],
- required: false,
- default: '',
- },
- stageName: {
- type: String,
- required: false,
- default: '',
- },
- },
- jobItemTypes: {
- jobDropdown: JOB_DROPDOWN,
- singleJob: SINGLE_JOB,
- },
- computed: {
- computedJobId() {
- return this.pipelineId > -1 ? `${this.group.name}-${this.pipelineId}` : '';
- },
- tooltipText() {
- const { name, status } = this.group;
- return `${name} - ${status.label}`;
- },
- jobGroupClasses() {
- return [this.cssClassJobName, `job-${this.group.status.group}`];
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry('job_group_dropdown', `error: ${err}, info: ${info}`);
- },
- methods: {
- pipelineActionRequestComplete() {
- this.$emit('pipelineActionRequestComplete');
- },
- },
-};
-</script>
-<template>
- <!-- eslint-disable @gitlab/vue-no-data-toggle -->
- <div
- :id="computedJobId"
- class="ci-job-dropdown-container dropdown dropright"
- data-qa-selector="job_dropdown_container"
- >
- <button
- type="button"
- data-toggle="dropdown"
- data-display="static"
- :class="jobGroupClasses"
- class="dropdown-menu-toggle gl-pipeline-job-width! gl-pr-4!"
- >
- <div class="gl-display-flex gl-align-items-stretch gl-justify-content-space-between">
- <job-item
- :type="$options.jobItemTypes.jobDropdown"
- :group-tooltip="tooltipText"
- :job="group"
- :stage-name="stageName"
- />
-
- <div class="gl-font-weight-100 gl-font-size-lg gl-ml-n4 gl-align-self-center">
- {{ group.size }}
- </div>
- </div>
- </button>
-
- <ul
- class="dropdown-menu big-pipeline-graph-dropdown-menu js-grouped-pipeline-dropdown"
- data-qa-selector="jobs_dropdown_menu"
- >
- <li class="scrollable-menu">
- <ul>
- <li v-for="job in group.jobs" :key="job.id">
- <job-item
- :dropdown-length="group.size"
- :job="job"
- :type="$options.jobItemTypes.singleJob"
- css-class-job-name="pipeline-job-item"
- @pipelineActionRequestComplete="pipelineActionRequestComplete"
- />
- </li>
- </ul>
- </li>
- </ul>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue
deleted file mode 100644
index 22895a31082..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/job_item.vue
+++ /dev/null
@@ -1,396 +0,0 @@
-<script>
-import { GlBadge, GlForm, GlFormCheckbox, GlLink, GlModal, GlTooltipDirective } from '@gitlab/ui';
-import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
-import { __, s__, sprintf } from '~/locale';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { reportToSentry } from '../../utils';
-import ActionComponent from '../jobs_shared/action_component.vue';
-import JobNameComponent from '../jobs_shared/job_name_component.vue';
-import { BRIDGE_KIND, RETRY_ACTION_TITLE, SINGLE_JOB, SKIP_RETRY_MODAL_KEY } from './constants';
-
-/**
- * Renders the badge for the pipeline graph and the job's dropdown.
- *
- * The following object should be provided as `job`:
- *
- * {
- * "id": 4256,
- * "name": "test",
- * "status": {
- * "icon": "status_success",
- * "text": "passed",
- * "label": "passed",
- * "group": "success",
- * "tooltip": "passed",
- * "details_path": "/root/ci-mock/builds/4256",
- * "action": {
- * "icon": "retry",
- * "title": "Retry",
- * "path": "/root/ci-mock/builds/4256/retry",
- * "method": "post"
- * }
- * }
- * }
- */
-
-export default {
- confirmationModalDocLink: helpPagePath('/ci/pipelines/downstream_pipelines'),
- i18n: {
- bridgeBadgeText: __('Trigger job'),
- bridgeRetryText: s__(
- 'PipelineGraph|Downstream pipeline might not display in the graph while the new downstream pipeline is being created.',
- ),
- unauthorizedTooltip: __('You are not authorized to run this manual job'),
- confirmationModal: {
- title: s__('PipelineGraph|Are you sure you want to retry %{jobName}?'),
- description: s__(
- 'PipelineGraph|Retrying a trigger job will create a new downstream pipeline.',
- ),
- linkText: s__('PipelineGraph|What is a downstream pipeline?'),
- footer: __("Don't show this again"),
- actionPrimary: { text: __('Retry') },
- actionCancel: { text: __('Cancel') },
- },
- runAgainTooltipText: __('Run again'),
- },
- hoverClass: 'gl-shadow-x0-y0-b3-s1-blue-500',
- components: {
- ActionComponent,
- CiIcon,
- GlBadge,
- GlForm,
- GlFormCheckbox,
- GlLink,
- GlModal,
- JobNameComponent,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [delayedJobMixin],
- props: {
- job: {
- type: Object,
- required: true,
- },
- cssClassJobName: {
- type: [String, Array, Object],
- required: false,
- default: '',
- },
- dropdownLength: {
- type: Number,
- required: false,
- default: Infinity,
- },
- groupTooltip: {
- type: String,
- required: false,
- default: '',
- },
- jobHovered: {
- type: String,
- required: false,
- default: '',
- },
- pipelineExpanded: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- pipelineId: {
- type: Number,
- required: false,
- default: -1,
- },
- skipRetryModal: {
- type: Boolean,
- required: false,
- default: false,
- },
- sourceJobHovered: {
- type: String,
- required: false,
- default: '',
- },
- stageName: {
- type: String,
- required: false,
- default: '',
- },
- type: {
- type: String,
- required: false,
- default: SINGLE_JOB,
- },
- },
- data() {
- return {
- currentSkipModalValue: this.skipRetryModal,
- showConfirmationModal: false,
- shouldTriggerActionClick: false,
- };
- },
- computed: {
- boundary() {
- return this.dropdownLength === 1 ? 'viewport' : 'scrollParent';
- },
- computedJobId() {
- return this.pipelineId > -1 ? `${this.job.name}-${this.pipelineId}` : '';
- },
- detailsPath() {
- return this.status.detailsPath;
- },
- hasDetails() {
- return this.status.hasDetails;
- },
- hasRetryAction() {
- return Boolean(this.job?.status?.action?.title === RETRY_ACTION_TITLE);
- },
- isRetryableBridge() {
- return this.isBridge && this.hasRetryAction;
- },
- isSingleItem() {
- return this.type === SINGLE_JOB;
- },
- isBridge() {
- return this.kind === BRIDGE_KIND;
- },
- kind() {
- return this.job?.kind || '';
- },
- nameComponent() {
- return this.hasDetails ? 'gl-link' : 'div';
- },
- retryTriggerJobWarningText() {
- return sprintf(this.$options.i18n.confirmationModal.title, {
- jobName: this.job.name,
- });
- },
- showStageName() {
- return Boolean(this.stageName);
- },
- status() {
- return this.job && this.job.status ? this.job.status : {};
- },
- testId() {
- return this.hasDetails ? 'job-with-link' : 'job-without-link';
- },
- tooltipText() {
- if (this.groupTooltip) {
- return this.groupTooltip;
- }
-
- const textBuilder = [];
- const { name: jobName } = this.job;
-
- if (jobName) {
- textBuilder.push(jobName);
- }
-
- const { tooltip: statusTooltip } = this.status;
- if (jobName && statusTooltip) {
- textBuilder.push('-');
- }
-
- if (statusTooltip) {
- if (this.isDelayedJob) {
- textBuilder.push(sprintf(statusTooltip, { remainingTime: this.remainingTime }));
- } else {
- textBuilder.push(statusTooltip);
- }
- }
-
- return textBuilder.join(' ');
- },
- /**
- * Verifies if the provided job has an action path
- *
- * @return {Boolean}
- */
- hasAction() {
- return this.job.status && this.job.status.action && this.job.status.action.path;
- },
- hasUnauthorizedManualAction() {
- return (
- !this.hasAction &&
- this.job.status?.group === 'manual' &&
- this.job.status?.label?.includes('(not allowed)')
- );
- },
- unauthorizedManualActionIcon() {
- /*
- The action object is not available when the user cannot run the action.
- So we can show the correct icon, extract the action name from the label instead:
- "manual play action (not allowed)" or "manual stop action (not allowed)"
- */
- return this.job.status?.label?.split(' ')[1];
- },
- relatedDownstreamHovered() {
- return this.job.name === this.sourceJobHovered;
- },
- relatedDownstreamExpanded() {
- return this.job.name === this.pipelineExpanded.jobName && this.pipelineExpanded.expanded;
- },
- jobClasses() {
- return [
- {
- [this.$options.hoverClass]:
- this.relatedDownstreamHovered || this.relatedDownstreamExpanded,
- },
- { 'gl-rounded-lg': this.isBridge },
- this.cssClassJobName,
- {
- [`job-${this.status.group}`]: this.isSingleItem,
- },
- ];
- },
- withConfirmationModal() {
- return this.isRetryableBridge && !this.skipRetryModal;
- },
- jobActionTooltipText() {
- const { group } = this.status;
- const { title, icon } = this.status.action;
-
- return icon === 'retry' && group === 'success'
- ? this.$options.i18n.runAgainTooltipText
- : title;
- },
- },
- watch: {
- skipRetryModal(val) {
- this.currentSkipModalValue = val;
- this.shouldTriggerActionClick = false;
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry('job_item', `error: ${err}, info: ${info}`);
- },
- methods: {
- handleConfirmationModalPreferences() {
- if (this.currentSkipModalValue) {
- this.$emit('setSkipRetryModal');
- localStorage.setItem(SKIP_RETRY_MODAL_KEY, String(this.currentSkipModalValue));
- }
- },
- hideTooltips() {
- this.$root.$emit(BV_HIDE_TOOLTIP);
- },
- jobItemClick(evt) {
- if (this.isSingleItem) {
- /*
- This is so the jobDropdown still toggles. Issue to refactor:
- https://gitlab.com/gitlab-org/gitlab/-/issues/267117
- */
- evt.stopPropagation();
- }
-
- this.hideTooltips();
- },
- pipelineActionRequestComplete() {
- this.$emit('pipelineActionRequestComplete');
-
- if (this.isBridge) {
- this.$toast.show(this.$options.i18n.bridgeRetryText);
- }
- },
- executePendingAction() {
- this.shouldTriggerActionClick = true;
- },
- showActionConfirmationModal() {
- this.showConfirmationModal = true;
- },
- toggleSkipRetryModalCheckbox() {
- this.currentSkipModalValue = !this.currentSkipModalValue;
- },
- },
-};
-</script>
-<template>
- <div
- :id="computedJobId"
- class="ci-job-component gl-display-flex gl-justify-content-space-between gl-pipeline-job-width"
- data-qa-selector="job_item_container"
- >
- <component
- :is="nameComponent"
- v-gl-tooltip="{
- boundary: 'viewport',
- placement: 'bottom',
- customClass: 'gl-pointer-events-none',
- }"
- :title="tooltipText"
- :class="jobClasses"
- :href="detailsPath"
- class="js-pipeline-graph-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none gl-focus-text-decoration-none gl-hover-text-decoration-none gl-w-full"
- :data-testid="testId"
- data-qa-selector="job_link"
- @click="jobItemClick"
- @mouseout="hideTooltips"
- >
- <div class="gl-display-flex gl-align-items-center gl-flex-grow-1">
- <ci-icon :size="24" :status="job.status" class="gl-line-height-0" />
- <div class="gl-pl-3 gl-pr-3 gl-display-flex gl-flex-direction-column gl-pipeline-job-width">
- <div class="gl-text-truncate gl-pr-9 gl-line-height-normal">{{ job.name }}</div>
- <div
- v-if="showStageName"
- data-testid="stage-name-in-job"
- class="gl-text-truncate gl-pr-9 gl-font-sm gl-text-gray-500 gl-line-height-normal"
- >
- {{ stageName }}
- </div>
- </div>
- </div>
- <gl-badge v-if="isBridge" class="gl-mt-3" variant="info" size="sm">
- {{ $options.i18n.bridgeBadgeText }}
- </gl-badge>
- </component>
-
- <action-component
- v-if="hasAction"
- :tooltip-text="jobActionTooltipText"
- :link="status.action.path"
- :action-icon="status.action.icon"
- class="gl-mr-1"
- :should-trigger-click="shouldTriggerActionClick"
- :with-confirmation-modal="withConfirmationModal"
- data-qa-selector="job_action_button"
- @actionButtonClicked="handleConfirmationModalPreferences"
- @pipelineActionRequestComplete="pipelineActionRequestComplete"
- @showActionConfirmationModal="showActionConfirmationModal"
- />
- <action-component
- v-if="hasUnauthorizedManualAction"
- disabled
- :tooltip-text="$options.i18n.unauthorizedTooltip"
- :action-icon="unauthorizedManualActionIcon"
- :link="`unauthorized-${computedJobId}`"
- class="gl-mr-1"
- />
- <gl-modal
- v-if="showConfirmationModal"
- ref="modal"
- v-model="showConfirmationModal"
- modal-id="action-confirmation-modal"
- :title="retryTriggerJobWarningText"
- :action-cancel="$options.i18n.confirmationModal.actionCancel"
- :action-primary="$options.i18n.confirmationModal.actionPrimary"
- @primary="executePendingAction"
- @close="handleConfirmationModalPreferences"
- @hide="handleConfirmationModalPreferences"
- >
- <p class="gl-mb-1">{{ $options.i18n.confirmationModal.description }}</p>
- <gl-link :href="$options.confirmationModalDocLink" target="_blank">{{
- $options.i18n.confirmationModal.linkText
- }}</gl-link>
- <div class="gl-mt-4 gl-display-flex">
- <gl-form>
- <gl-form-checkbox class="gl-min-h-0" @input="toggleSkipRetryModalCheckbox" />
- </gl-form>
- <p class="gl-m-0">{{ $options.i18n.confirmationModal.footer }}</p>
- </div>
- </gl-modal>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue
deleted file mode 100644
index d8b843bdfb0..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue
+++ /dev/null
@@ -1,304 +0,0 @@
-<script>
-import {
- GlBadge,
- GlButton,
- GlLink,
- GlLoadingIcon,
- GlTooltip,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import { TYPENAME_CI_PIPELINE } from '~/graphql_shared/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
-import { __, sprintf } from '~/locale';
-import CancelPipelineMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql';
-import RetryPipelineMutation from '~/pipelines/graphql/mutations/retry_pipeline.mutation.graphql';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { reportToSentry } from '../../utils';
-import { ACTION_FAILURE, DOWNSTREAM, UPSTREAM } from './constants';
-
-export default {
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- CiIcon,
- GlBadge,
- GlButton,
- GlLink,
- GlLoadingIcon,
- GlTooltip,
- },
- styles: {
- actionSizeClasses: ['gl-h-7 gl-w-7'],
- flatLeftBorder: ['gl-rounded-bottom-left-none!', 'gl-rounded-top-left-none!'],
- flatRightBorder: ['gl-rounded-bottom-right-none!', 'gl-rounded-top-right-none!'],
- },
- props: {
- columnTitle: {
- type: String,
- required: true,
- },
- expanded: {
- type: Boolean,
- required: true,
- },
- isLoading: {
- type: Boolean,
- required: true,
- },
- pipeline: {
- type: Object,
- required: true,
- },
- type: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- hasActionTooltip: false,
- isActionLoading: false,
- isExpandBtnFocus: false,
- };
- },
- computed: {
- action() {
- if (this.isDownstream) {
- if (this.isCancelable) {
- return {
- icon: 'cancel',
- method: this.cancelPipeline,
- ariaLabel: __('Cancel downstream pipeline'),
- };
- } else if (this.isRetryable) {
- return {
- icon: 'retry',
- method: this.retryPipeline,
- ariaLabel: __('Retry downstream pipeline'),
- };
- }
- }
-
- return {};
- },
- buttonBorderClasses() {
- return this.isUpstream
- ? ['gl-border-r-0!', ...this.$options.styles.flatRightBorder]
- : ['gl-border-l-0!', ...this.$options.styles.flatLeftBorder];
- },
- buttonShadowClass() {
- return this.isExpandBtnFocus ? '' : 'gl-shadow-none!';
- },
- buttonId() {
- return `js-linked-pipeline-${this.pipeline.id}`;
- },
- cardClasses() {
- return this.isDownstream
- ? this.$options.styles.flatRightBorder
- : this.$options.styles.flatLeftBorder;
- },
- expandedIcon() {
- if (this.isUpstream) {
- return this.expanded ? 'chevron-lg-right' : 'chevron-lg-left';
- }
- return this.expanded ? 'chevron-lg-left' : 'chevron-lg-right';
- },
- expandBtnText() {
- return this.expanded ? __('Collapse jobs') : __('Expand jobs');
- },
- childPipeline() {
- return this.isDownstream && this.isSameProject;
- },
- downstreamTitle() {
- return this.childPipeline ? this.sourceJobName : this.pipeline.project.name;
- },
- flexDirection() {
- return this.isUpstream ? 'gl-flex-direction-row-reverse' : 'gl-flex-direction-row';
- },
- graphqlPipelineId() {
- return convertToGraphQLId(TYPENAME_CI_PIPELINE, this.pipeline.id);
- },
- hasUpdatePipelinePermissions() {
- return Boolean(this.pipeline?.userPermissions?.updatePipeline);
- },
- isCancelable() {
- return Boolean(this.pipeline?.cancelable && this.hasUpdatePipelinePermissions);
- },
- isDownstream() {
- return this.type === DOWNSTREAM;
- },
- isRetryable() {
- return Boolean(this.pipeline?.retryable && this.hasUpdatePipelinePermissions);
- },
- isSameProject() {
- return !this.pipeline.multiproject;
- },
- isUpstream() {
- return this.type === UPSTREAM;
- },
- label() {
- if (this.parentPipeline) {
- return __('Parent');
- } else if (this.childPipeline) {
- return __('Child');
- }
- return __('Multi-project');
- },
- parentPipeline() {
- return this.isUpstream && this.isSameProject;
- },
- pipelineIsLoading() {
- return Boolean(this.isLoading || this.pipeline.isLoading);
- },
- pipelineStatus() {
- return this.pipeline.status;
- },
- projectName() {
- return this.pipeline.project.name;
- },
- showAction() {
- return Boolean(this.action?.method && this.action?.icon && this.action?.ariaLabel);
- },
- showCardTooltip() {
- return !this.hasActionTooltip && !this.isExpandBtnFocus;
- },
- sourceJobName() {
- return this.pipeline.sourceJob?.name ?? '';
- },
- sourceJobInfo() {
- return this.isDownstream ? sprintf(__('Created by %{job}'), { job: this.sourceJobName }) : '';
- },
- cardTooltipText() {
- return `${this.downstreamTitle} #${this.pipeline.id} - ${this.pipelineStatus.label} -
- ${this.sourceJobInfo}`;
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry('linked_pipeline', `error: ${err}, info: ${info}`);
- },
- methods: {
- cancelPipeline() {
- this.executePipelineAction(CancelPipelineMutation);
- },
- async executePipelineAction(mutation) {
- try {
- this.isActionLoading = true;
-
- await this.$apollo.mutate({
- mutation,
- variables: {
- id: this.graphqlPipelineId,
- },
- });
- this.$emit('refreshPipelineGraph');
- } catch {
- this.$emit('error', { type: ACTION_FAILURE });
- } finally {
- this.isActionLoading = false;
- }
- },
- hideTooltips() {
- this.$root.$emit(BV_HIDE_TOOLTIP);
- },
- onClickLinkedPipeline() {
- this.hideTooltips();
- this.$emit('pipelineClicked', this.$refs.linkedPipeline);
- this.$emit('pipelineExpandToggle', this.sourceJobName, !this.expanded);
- },
- onDownstreamHovered() {
- this.$emit('downstreamHovered', this.sourceJobName);
- },
- onDownstreamHoverLeave() {
- this.$emit('downstreamHovered', '');
- },
- retryPipeline() {
- this.executePipelineAction(RetryPipelineMutation);
- },
- setActionTooltip(flag) {
- this.hasActionTooltip = flag;
- },
- setExpandBtnActiveState(flag) {
- this.isExpandBtnFocus = flag;
- },
- },
-};
-</script>
-
-<template>
- <div
- ref="linkedPipeline"
- class="gl-h-full gl-display-flex! gl-px-2"
- :class="flexDirection"
- data-qa-selector="linked_pipeline_container"
- @mouseover="onDownstreamHovered"
- @mouseleave="onDownstreamHoverLeave"
- >
- <gl-tooltip v-if="showCardTooltip" :target="() => $refs.linkedPipeline">
- {{ cardTooltipText }}
- </gl-tooltip>
- <div class="gl-bg-white gl-border gl-p-3 gl-rounded-lg gl-w-full" :class="cardClasses">
- <div class="gl-display-flex gl-gap-x-3">
- <ci-icon v-if="!pipelineIsLoading" :status="pipelineStatus" :size="24" />
- <div v-else class="gl-pr-3"><gl-loading-icon size="sm" inline /></div>
- <div
- class="gl-display-flex gl-downstream-pipeline-job-width gl-flex-direction-column gl-line-height-normal"
- >
- <span
- class="gl-text-truncate"
- data-testid="downstream-title"
- data-qa-selector="downstream_title_content"
- >
- {{ downstreamTitle }}
- </span>
- <div class="gl-text-truncate">
- <gl-link
- class="gl-text-blue-500! gl-font-sm"
- :href="pipeline.path"
- data-testid="pipelineLink"
- >#{{ pipeline.id }}</gl-link
- >
- </div>
- </div>
- <gl-button
- v-if="showAction"
- v-gl-tooltip
- :title="action.ariaLabel"
- :loading="isActionLoading"
- :icon="action.icon"
- class="gl-rounded-full!"
- :class="$options.styles.actionSizeClasses"
- :aria-label="action.ariaLabel"
- @click="action.method"
- @mouseover="setActionTooltip(true)"
- @mouseout="setActionTooltip(false)"
- />
- <div v-else :class="$options.styles.actionSizeClasses"></div>
- </div>
- <div class="gl-pt-2">
- <gl-badge size="sm" variant="info" data-testid="downstream-pipeline-label">
- {{ label }}
- </gl-badge>
- </div>
- </div>
- <div class="gl-display-flex">
- <gl-button
- :id="buttonId"
- v-gl-tooltip
- :title="expandBtnText"
- class="gl-border! gl-rounded-lg!"
- :class="[`js-pipeline-expand-${pipeline.id}`, buttonBorderClasses, buttonShadowClass]"
- :icon="expandedIcon"
- :aria-label="expandBtnText"
- data-testid="expand-pipeline-button"
- data-qa-selector="expand_linked_pipeline_button"
- @mouseover="setExpandBtnActiveState(true)"
- @mouseout="setExpandBtnActiveState(false)"
- @focus="setExpandBtnActiveState(true)"
- @blur="setExpandBtnActiveState(false)"
- @click="onClickLinkedPipeline"
- />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
deleted file mode 100644
index 02e426064c9..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/linked_pipelines_column.vue
+++ /dev/null
@@ -1,247 +0,0 @@
-<script>
-import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
-import { LOAD_FAILURE } from '../../constants';
-import { reportToSentry } from '../../utils';
-import { ONE_COL_WIDTH, UPSTREAM, LAYER_VIEW, STAGE_VIEW } from './constants';
-import LinkedPipeline from './linked_pipeline.vue';
-import {
- calculatePipelineLayersInfo,
- getQueryHeaders,
- serializeLoadErrors,
- toggleQueryPollingByVisibility,
- unwrapPipelineData,
- validateConfigPaths,
-} from './utils';
-
-export default {
- components: {
- LinkedPipeline,
- PipelineGraph: () => import('./graph_component.vue'),
- },
- props: {
- columnTitle: {
- type: String,
- required: true,
- },
- configPaths: {
- type: Object,
- required: true,
- validator: validateConfigPaths,
- },
- linkedPipelines: {
- type: Array,
- required: true,
- },
- showLinks: {
- type: Boolean,
- required: true,
- },
- skipRetryModal: {
- type: Boolean,
- required: false,
- default: false,
- },
- type: {
- type: String,
- required: true,
- },
- viewType: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- currentPipeline: null,
- loadingPipelineId: null,
- pipelineLayers: {},
- pipelineExpanded: false,
- };
- },
- titleClasses: [
- 'gl-font-weight-bold',
- 'gl-pipeline-job-width',
- 'gl-text-truncate',
- 'gl-line-height-36',
- 'gl-pl-3',
- 'gl-mb-5',
- ],
- minWidth: `${ONE_COL_WIDTH}px`,
- computed: {
- columnClass() {
- const positionValues = {
- right: 'gl-ml-6',
- left: 'gl-mx-6',
- };
-
- return `graph-position-${this.graphPosition} ${positionValues[this.graphPosition]}`;
- },
- computedTitleClasses() {
- const positionalClasses = this.isUpstream ? ['gl-w-full', 'gl-linked-pipeline-padding'] : [];
-
- return [...this.$options.titleClasses, ...positionalClasses];
- },
- graphPosition() {
- return this.isUpstream ? 'left' : 'right';
- },
- graphViewType() {
- return this.currentPipeline?.usesNeeds ? this.viewType : STAGE_VIEW;
- },
- isUpstream() {
- return this.type === UPSTREAM;
- },
- minWidth() {
- return this.isUpstream ? 0 : this.$options.minWidth;
- },
- },
- methods: {
- getPipelineData(pipeline) {
- const projectPath = pipeline.project.fullPath;
-
- this.$apollo.addSmartQuery('currentPipeline', {
- query: getPipelineDetails,
- pollInterval: 10000,
- context() {
- return getQueryHeaders(this.configPaths.graphqlResourceEtag);
- },
- variables() {
- return {
- projectPath,
- iid: pipeline.iid,
- };
- },
- update(data) {
- /*
- This check prevents the pipeline from being overwritten
- when a poll times out and the data returned is empty.
- This can be removed once the timeout behavior is updated.
- See: https://gitlab.com/gitlab-org/gitlab/-/issues/323213.
- */
-
- if (!data?.project?.pipeline) {
- return this.currentPipeline;
- }
-
- return unwrapPipelineData(projectPath, JSON.parse(JSON.stringify(data)));
- },
- result() {
- this.loadingPipelineId = null;
- this.$emit('scrollContainer');
- },
- error(err) {
- this.$emit('error', { type: LOAD_FAILURE, skipSentry: true });
-
- reportToSentry(
- 'linked_pipelines_column',
- `error type: ${LOAD_FAILURE}, error: ${serializeLoadErrors(err)}`,
- );
- },
- });
-
- toggleQueryPollingByVisibility(this.$apollo.queries.currentPipeline);
- },
- getPipelineLayers(id) {
- if (this.viewType === LAYER_VIEW && !this.pipelineLayers[id]) {
- this.pipelineLayers[id] = calculatePipelineLayersInfo(
- this.currentPipeline,
- this.$options.name,
- this.configPaths.metricsPath,
- );
- }
-
- return this.pipelineLayers[id];
- },
- isExpanded(id) {
- return Boolean(this.currentPipeline?.id && id === this.currentPipeline.id);
- },
- isLoadingPipeline(id) {
- return this.loadingPipelineId === id;
- },
- onPipelineClick(pipeline) {
- /* If the clicked pipeline has been expanded already, close it, clear, exit */
- if (this.currentPipeline?.id === pipeline.id) {
- this.pipelineExpanded = false;
- this.currentPipeline = null;
- return;
- }
-
- /* Set the loading id */
- this.loadingPipelineId = pipeline.id;
-
- /*
- Expand the pipeline.
- If this was not a toggle close action, and
- it was already showing a different pipeline, then
- this will be a no-op, but that doesn't matter.
- */
- this.pipelineExpanded = true;
-
- this.getPipelineData(pipeline);
- },
- onDownstreamHovered(jobName) {
- this.$emit('downstreamHovered', jobName);
- },
- onPipelineExpandToggle(jobName, expanded) {
- // Highlighting only applies to downstream pipelines
- if (this.isUpstream) {
- return;
- }
-
- this.$emit('pipelineExpandToggle', jobName, expanded);
- },
- showContainer(id) {
- return this.isExpanded(id) || this.isLoadingPipeline(id);
- },
- },
-};
-</script>
-
-<template>
- <div class="gl-display-flex">
- <div :class="columnClass" class="linked-pipelines-column">
- <div data-testid="linked-column-title" :class="computedTitleClasses">
- {{ columnTitle }}
- </div>
- <ul class="gl-pl-0">
- <li
- v-for="pipeline in linkedPipelines"
- :key="pipeline.id"
- class="gl-display-flex gl-mb-3"
- :class="{ 'gl-flex-direction-row-reverse': isUpstream }"
- >
- <linked-pipeline
- class="gl-display-inline-block"
- :is-loading="isLoadingPipeline(pipeline.id)"
- :pipeline="pipeline"
- :column-title="columnTitle"
- :type="type"
- :expanded="isExpanded(pipeline.id)"
- @downstreamHovered="onDownstreamHovered"
- @pipelineClicked="onPipelineClick(pipeline)"
- @pipelineExpandToggle="onPipelineExpandToggle"
- @refreshPipelineGraph="$emit('refreshPipelineGraph')"
- />
- <div
- v-if="showContainer(pipeline.id)"
- :style="{ minWidth }"
- class="gl-display-inline-block"
- >
- <pipeline-graph
- v-if="isExpanded(pipeline.id)"
- :type="type"
- class="gl-inline-block gl-mt-n2"
- :config-paths="configPaths"
- :pipeline="currentPipeline"
- :computed-pipeline-info="getPipelineLayers(pipeline.id)"
- :show-links="showLinks"
- :skip-retry-modal="skipRetryModal"
- :is-linked-pipeline="true"
- :view-type="graphViewType"
- @setSkipRetryModal="$emit('setSkipRetryModal')"
- />
- </div>
- </li>
- </ul>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/perf_utils.js b/app/assets/javascripts/pipelines/components/graph/perf_utils.js
deleted file mode 100644
index 3737a209f5c..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/perf_utils.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import {
- PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START,
- PIPELINES_DETAIL_LINKS_MARK_CALCULATE_END,
- PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION,
- PIPELINES_DETAIL_LINK_DURATION,
- PIPELINES_DETAIL_LINKS_TOTAL,
- PIPELINES_DETAIL_LINKS_JOB_RATIO,
-} from '~/performance/constants';
-
-import { performanceMarkAndMeasure } from '~/performance/utils';
-import { reportPerformance } from '../graph_shared/api';
-
-export const beginPerfMeasure = () => {
- performanceMarkAndMeasure({ mark: PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START });
-};
-
-export const finishPerfMeasureAndSend = (numLinks, numGroups, metricsPath) => {
- performanceMarkAndMeasure({
- mark: PIPELINES_DETAIL_LINKS_MARK_CALCULATE_END,
- measures: [
- {
- name: PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION,
- start: PIPELINES_DETAIL_LINKS_MARK_CALCULATE_START,
- },
- ],
- });
-
- window.requestAnimationFrame(() => {
- const duration = window.performance.getEntriesByName(
- PIPELINES_DETAIL_LINKS_MEASURE_CALCULATION,
- )[0]?.duration;
-
- if (!duration) {
- return;
- }
-
- const data = {
- histograms: [
- { name: PIPELINES_DETAIL_LINK_DURATION, value: duration / 1000 },
- { name: PIPELINES_DETAIL_LINKS_TOTAL, value: numLinks },
- {
- name: PIPELINES_DETAIL_LINKS_JOB_RATIO,
- value: numLinks / numGroups,
- },
- ],
- };
-
- reportPerformance(metricsPath, data);
- });
-};
diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
deleted file mode 100644
index ffd0fec2ca8..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
+++ /dev/null
@@ -1,196 +0,0 @@
-<script>
-import { escape, isEmpty } from 'lodash';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { reportToSentry } from '../../utils';
-import MainGraphWrapper from '../graph_shared/main_graph_wrapper.vue';
-import ActionComponent from '../jobs_shared/action_component.vue';
-import JobGroupDropdown from './job_group_dropdown.vue';
-import JobItem from './job_item.vue';
-
-export default {
- components: {
- ActionComponent,
- JobGroupDropdown,
- JobItem,
- MainGraphWrapper,
- },
- mixins: [glFeatureFlagMixin()],
- props: {
- groups: {
- type: Array,
- required: true,
- },
- name: {
- type: String,
- required: true,
- },
- pipelineId: {
- type: Number,
- required: true,
- },
- action: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- highlightedJobs: {
- type: Array,
- required: false,
- default: () => [],
- },
- isStageView: {
- type: Boolean,
- required: false,
- default: false,
- },
- jobHovered: {
- type: String,
- required: false,
- default: '',
- },
- pipelineExpanded: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- skipRetryModal: {
- type: Boolean,
- required: false,
- default: false,
- },
- sourceJobHovered: {
- type: String,
- required: false,
- default: '',
- },
- userPermissions: {
- type: Object,
- required: true,
- },
- },
- jobClasses: [
- 'gl-p-3',
- 'gl-border-gray-100',
- 'gl-border-solid',
- 'gl-border-1',
- 'gl-bg-white',
- 'gl-rounded-7',
- 'gl-hover-bg-gray-50',
- 'gl-focus-bg-gray-50',
- 'gl-hover-text-gray-900',
- 'gl-focus-text-gray-900',
- 'gl-hover-border-gray-200',
- 'gl-focus-border-gray-200',
- ],
- titleClasses: [
- 'gl-font-weight-bold',
- 'gl-pipeline-job-width',
- 'gl-text-truncate',
- 'gl-line-height-36',
- 'gl-pl-3',
- ],
- computed: {
- canUpdatePipeline() {
- return this.userPermissions.updatePipeline;
- },
- columnSpacingClass() {
- return this.isStageView ? 'gl-px-6' : 'gl-px-9';
- },
- hasAction() {
- return !isEmpty(this.action);
- },
- showStageName() {
- return !this.isStageView;
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry('stage_column_component', `error: ${err}, info: ${info}`);
- },
- mounted() {
- this.$emit('updateMeasurements');
- },
- methods: {
- getGroupId(group) {
- return group.name;
- },
- groupId(group) {
- return `ci-badge-${escape(group.name)}`;
- },
- isFadedOut(jobName) {
- return this.highlightedJobs.length > 1 && !this.highlightedJobs.includes(jobName);
- },
- isParallel(group) {
- return group.size > 1 && group.jobs.length > 1;
- },
- singleJobExists(group) {
- const firstJobDefined = Boolean(group.jobs?.[0]);
-
- if (!firstJobDefined) {
- reportToSentry('stage_column_component', 'undefined_job_hunt');
- }
-
- return group.size === 1 && firstJobDefined;
- },
- },
-};
-</script>
-<template>
- <main-graph-wrapper :class="columnSpacingClass" data-testid="stage-column">
- <template #stages>
- <div
- data-testid="stage-column-title"
- class="gl-display-flex gl-justify-content-space-between gl-relative"
- :class="$options.titleClasses"
- >
- <span :title="name" class="gl-text-truncate gl-pr-3 gl-w-85p">
- {{ name }}
- </span>
- <action-component
- v-if="hasAction && canUpdatePipeline"
- :action-icon="action.icon"
- :tooltip-text="action.title"
- :link="action.path"
- class="js-stage-action"
- @pipelineActionRequestComplete="$emit('refreshPipelineGraph')"
- />
- </div>
- </template>
- <template #jobs>
- <div
- v-for="group in groups"
- :id="groupId(group)"
- :key="getGroupId(group)"
- data-testid="stage-column-group"
- class="gl-relative gl-mb-3 gl-white-space-normal gl-pipeline-job-width"
- @mouseenter="$emit('jobHover', group.name)"
- @mouseleave="$emit('jobHover', '')"
- >
- <job-item
- v-if="singleJobExists(group)"
- :job="group.jobs[0]"
- :job-hovered="jobHovered"
- :skip-retry-modal="skipRetryModal"
- :source-job-hovered="sourceJobHovered"
- :pipeline-expanded="pipelineExpanded"
- :pipeline-id="pipelineId"
- :stage-name="showStageName ? group.stageName : ''"
- :css-class-job-name="$options.jobClasses"
- :class="[
- { 'gl-opacity-3': isFadedOut(group.name) },
- 'gl-transition-duration-slow gl-transition-timing-function-ease',
- ]"
- @pipelineActionRequestComplete="$emit('refreshPipelineGraph')"
- @setSkipRetryModal="$emit('setSkipRetryModal')"
- />
- <div v-else-if="isParallel(group)" :class="{ 'gl-opacity-3': isFadedOut(group.name) }">
- <job-group-dropdown
- :group="group"
- :stage-name="showStageName ? group.stageName : ''"
- :pipeline-id="pipelineId"
- :css-class-job-name="$options.jobClasses"
- />
- </div>
- </div>
- </template>
- </main-graph-wrapper>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/utils.js b/app/assets/javascripts/pipelines/components/graph/utils.js
deleted file mode 100644
index c888c8a5537..00000000000
--- a/app/assets/javascripts/pipelines/components/graph/utils.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import { isEmpty } from 'lodash';
-import { getIdFromGraphQLId, etagQueryHeaders } from '~/graphql_shared/utils';
-import { reportToSentry } from '../../utils';
-import { listByLayers } from '../parsing_utils';
-import { unwrapStagesWithNeedsAndLookup } from '../unwrapping_utils';
-import { beginPerfMeasure, finishPerfMeasureAndSend } from './perf_utils';
-
-export { toggleQueryPollingByVisibility } from '~/graphql_shared/utils';
-
-const addMulti = (mainPipelineProjectPath, linkedPipeline) => {
- return {
- ...linkedPipeline,
- multiproject: mainPipelineProjectPath !== linkedPipeline.project.fullPath,
- };
-};
-
-const calculatePipelineLayersInfo = (pipeline, componentName, metricsPath) => {
- const shouldCollectMetrics = Boolean(metricsPath);
-
- if (shouldCollectMetrics) {
- beginPerfMeasure();
- }
-
- let layers = null;
-
- try {
- layers = listByLayers(pipeline);
-
- if (shouldCollectMetrics) {
- finishPerfMeasureAndSend(layers.linksData.length, layers.numGroups, metricsPath);
- }
- } catch (err) {
- reportToSentry(componentName, err);
- }
-
- return layers;
-};
-
-const getQueryHeaders = (etagResource) =>
- etagQueryHeaders('verify/ci/pipeline-graph', etagResource);
-
-const serializeGqlErr = (gqlError) => {
- const { locations = [], message = '', path = [] } = gqlError;
-
- // eslint-disable-next-line @gitlab/require-i18n-strings
- return `
- ${message}.
- Locations: ${locations
- .flatMap((loc) => Object.entries(loc))
- .flat(2)
- .join(' ')}.
- Path: ${path.join(', ')}.
- `;
-};
-
-const serializeLoadErrors = (errors) => {
- const { gqlError, graphQLErrors, networkError, message } = errors;
-
- if (!isEmpty(graphQLErrors)) {
- return graphQLErrors.map((err) => serializeGqlErr(err)).join('; ');
- }
-
- if (!isEmpty(gqlError)) {
- return serializeGqlErr(gqlError);
- }
-
- if (!isEmpty(networkError)) {
- return `Network error: ${networkError.message}`; // eslint-disable-line @gitlab/require-i18n-strings
- }
-
- return message;
-};
-
-const transformId = (linkedPipeline) => {
- return { ...linkedPipeline, id: getIdFromGraphQLId(linkedPipeline.id) };
-};
-
-const unwrapPipelineData = (mainPipelineProjectPath, data) => {
- if (!data?.project?.pipeline) {
- return null;
- }
-
- const { pipeline } = data.project;
-
- const {
- upstream,
- downstream,
- stages: { nodes: stages },
- } = pipeline;
-
- const { stages: updatedStages, lookup } = unwrapStagesWithNeedsAndLookup(stages);
-
- return {
- ...pipeline,
- id: getIdFromGraphQLId(pipeline.id),
- stages: updatedStages,
- stagesLookup: lookup,
- upstream: upstream
- ? [upstream].map(addMulti.bind(null, mainPipelineProjectPath)).map(transformId)
- : [],
- downstream: downstream
- ? downstream.nodes.map(addMulti.bind(null, mainPipelineProjectPath)).map(transformId)
- : [],
- };
-};
-
-const validateConfigPaths = (value) => value.graphqlResourceEtag?.length > 0;
-
-export {
- calculatePipelineLayersInfo,
- getQueryHeaders,
- serializeGqlErr,
- serializeLoadErrors,
- unwrapPipelineData,
- validateConfigPaths,
-};
diff --git a/app/assets/javascripts/pipelines/components/graph_shared/api.js b/app/assets/javascripts/pipelines/components/graph_shared/api.js
deleted file mode 100644
index 0fe7d9ffda3..00000000000
--- a/app/assets/javascripts/pipelines/components/graph_shared/api.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import axios from '~/lib/utils/axios_utils';
-import { reportToSentry } from '../../utils';
-
-export const reportPerformance = (path, stats) => {
- // FIXME: https://gitlab.com/gitlab-org/gitlab/-/issues/330245
- if (!path) {
- return;
- }
-
- axios.post(path, stats).catch((err) => {
- reportToSentry('links_inner_perf', `error: ${err}`);
- });
-};
diff --git a/app/assets/javascripts/pipelines/components/graph_shared/links_inner.vue b/app/assets/javascripts/pipelines/components/graph_shared/links_inner.vue
deleted file mode 100644
index 1189c2ebad8..00000000000
--- a/app/assets/javascripts/pipelines/components/graph_shared/links_inner.vue
+++ /dev/null
@@ -1,161 +0,0 @@
-<script>
-import { isEmpty } from 'lodash';
-import { DRAW_FAILURE } from '../../constants';
-import { createJobsHash, generateJobNeedsDict, reportToSentry } from '../../utils';
-import { STAGE_VIEW } from '../graph/constants';
-import { generateLinksData } from './drawing_utils';
-
-export default {
- name: 'LinksInner',
- STROKE_WIDTH: 2,
- props: {
- containerId: {
- type: String,
- required: true,
- },
- containerMeasurements: {
- type: Object,
- required: true,
- },
- linksData: {
- type: Array,
- required: true,
- },
- pipelineId: {
- type: Number,
- required: true,
- },
- pipelineData: {
- type: Array,
- required: true,
- },
- defaultLinkColor: {
- type: String,
- required: false,
- default: 'gl-stroke-gray-200',
- },
- highlightedJob: {
- type: String,
- required: false,
- default: '',
- },
- viewType: {
- type: String,
- required: false,
- default: STAGE_VIEW,
- },
- },
- data() {
- return {
- links: [],
- needsObject: null,
- };
- },
- computed: {
- hasHighlightedJob() {
- return Boolean(this.highlightedJob);
- },
- isPipelineDataEmpty() {
- return isEmpty(this.pipelineData);
- },
- highlightedJobs() {
- // If you are hovering on a job, then the jobs we want to highlight are:
- // The job you are currently hovering + all of its needs.
- return this.hasHighlightedJob
- ? [this.highlightedJob, ...this.needsObject[this.highlightedJob]]
- : [];
- },
- highlightedLinks() {
- // If you are hovering on a job, then the links we want to highlight are:
- // All the links whose `source` and `target` are highlighted jobs.
- if (this.hasHighlightedJob) {
- const filteredLinks = this.links.filter((link) => {
- return (
- this.highlightedJobs.includes(link.source) && this.highlightedJobs.includes(link.target)
- );
- });
-
- return filteredLinks.map((link) => link.ref);
- }
-
- return [];
- },
- viewBox() {
- return [0, 0, this.containerMeasurements.width, this.containerMeasurements.height];
- },
- },
- watch: {
- highlightedJob() {
- // On first hover, generate the needs reference
- if (!this.needsObject) {
- const jobs = createJobsHash(this.pipelineData);
- this.needsObject = generateJobNeedsDict(jobs) ?? {};
- }
- },
- highlightedJobs(jobs) {
- this.$emit('highlightedJobsChange', jobs);
- },
- linksData() {
- this.calculateLinkData();
- },
- viewType() {
- /*
- We need to wait a tick so that the layout reflows
- before the links refresh.
- */
- this.$nextTick(() => {
- this.calculateLinkData();
- });
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
- },
- mounted() {
- if (!isEmpty(this.linksData)) {
- this.calculateLinkData();
- }
- },
- methods: {
- isLinkHighlighted(linkRef) {
- return this.highlightedLinks.includes(linkRef);
- },
- calculateLinkData() {
- try {
- this.links = generateLinksData(this.linksData, this.containerId, `-${this.pipelineId}`);
- } catch (err) {
- this.$emit('error', { type: DRAW_FAILURE, reportToSentry: false });
- reportToSentry(this.$options.name, err);
- }
- },
- getLinkClasses(link) {
- return [
- this.isLinkHighlighted(link.ref) ? 'gl-stroke-blue-400' : this.defaultLinkColor,
- { 'gl-opacity-3': this.hasHighlightedJob && !this.isLinkHighlighted(link.ref) },
- ];
- },
- },
-};
-</script>
-<template>
- <div class="gl-display-flex gl-relative">
- <svg
- id="link-svg"
- class="gl-absolute gl-pointer-events-none"
- :viewBox="viewBox"
- :width="`${containerMeasurements.width}px`"
- :height="`${containerMeasurements.height}px`"
- >
- <path
- v-for="link in links"
- :key="link.path"
- :ref="link.ref"
- :d="link.path"
- class="gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease"
- :class="getLinkClasses(link)"
- :stroke-width="$options.STROKE_WIDTH"
- />
- </svg>
- <slot></slot>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/graph_shared/links_layer.vue b/app/assets/javascripts/pipelines/components/graph_shared/links_layer.vue
deleted file mode 100644
index ef24694e494..00000000000
--- a/app/assets/javascripts/pipelines/components/graph_shared/links_layer.vue
+++ /dev/null
@@ -1,75 +0,0 @@
-<script>
-import { memoize } from 'lodash';
-import { reportToSentry } from '../../utils';
-import { parseData } from '../parsing_utils';
-import LinksInner from './links_inner.vue';
-
-const parseForLinksBare = (pipeline) => {
- const arrayOfJobs = pipeline.flatMap(({ groups }) => groups);
- return parseData(arrayOfJobs).links;
-};
-
-const parseForLinks = memoize(parseForLinksBare);
-
-export default {
- name: 'LinksLayer',
- components: {
- LinksInner,
- },
- props: {
- containerMeasurements: {
- type: Object,
- required: true,
- },
- pipelineData: {
- type: Array,
- required: true,
- },
- linksData: {
- type: Array,
- required: false,
- default: () => [],
- },
- showLinks: {
- type: Boolean,
- required: false,
- default: true,
- },
- },
- computed: {
- containerZero() {
- return !this.containerMeasurements.width || !this.containerMeasurements.height;
- },
- getLinksData() {
- if (this.linksData.length > 0) {
- return this.linksData;
- }
-
- return parseForLinks(this.pipelineData);
- },
- showLinkedLayers() {
- return this.showLinks && !this.containerZero;
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry(this.$options.name, `error: ${err}, info: ${info}`);
- },
-};
-</script>
-<template>
- <links-inner
- v-if="showLinkedLayers"
- :container-measurements="containerMeasurements"
- :links-data="getLinksData"
- :pipeline-data="pipelineData"
- v-bind="$attrs"
- v-on="$listeners"
- >
- <slot></slot>
- </links-inner>
- <div v-else>
- <div class="gl-display-flex gl-relative">
- <slot></slot>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue
deleted file mode 100644
index c24862f828b..00000000000
--- a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_app.vue
+++ /dev/null
@@ -1,65 +0,0 @@
-<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { createAlert } from '~/alert';
-import GetFailedJobsQuery from '../../graphql/queries/get_failed_jobs.query.graphql';
-import FailedJobsTable from './failed_jobs_table.vue';
-
-export default {
- components: {
- GlLoadingIcon,
- FailedJobsTable,
- },
- inject: {
- projectPath: {
- default: '',
- },
- pipelineIid: {
- default: '',
- },
- },
- apollo: {
- failedJobs: {
- query: GetFailedJobsQuery,
- variables() {
- return {
- fullPath: this.projectPath,
- pipelineIid: this.pipelineIid,
- };
- },
- update({ project }) {
- const jobNodes = project?.pipeline?.jobs?.nodes || [];
-
- return jobNodes.map((job) => {
- return {
- ...job,
- // this field is needed for the slot row-details
- // on the failed_jobs_table.vue component
- _showDetails: true,
- };
- });
- },
- error() {
- createAlert({ message: s__('Jobs|There was a problem fetching the failed jobs.') });
- },
- },
- },
- data() {
- return {
- failedJobs: [],
- };
- },
- computed: {
- loading() {
- return this.$apollo.queries.failedJobs.loading;
- },
- },
-};
-</script>
-
-<template>
- <div>
- <gl-loading-icon v-if="loading" size="lg" class="gl-mt-4" />
- <failed-jobs-table v-else :failed-jobs="failedJobs" />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue b/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
deleted file mode 100644
index f84ae13180d..00000000000
--- a/app/assets/javascripts/pipelines/components/jobs/failed_jobs_table.vue
+++ /dev/null
@@ -1,125 +0,0 @@
-<script>
-import { GlButton, GlLink, GlTableLite } from '@gitlab/ui';
-import SafeHtml from '~/vue_shared/directives/safe_html';
-import { __, s__ } from '~/locale';
-import { createAlert } from '~/alert';
-import Tracking from '~/tracking';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import RetryFailedJobMutation from '../../graphql/mutations/retry_failed_job.mutation.graphql';
-import { DEFAULT_FIELDS, TRACKING_CATEGORIES } from '../../constants';
-
-export default {
- fields: DEFAULT_FIELDS,
- retry: __('Retry'),
- components: {
- CiBadgeLink,
- GlButton,
- GlLink,
- GlTableLite,
- },
- directives: {
- SafeHtml,
- },
- mixins: [Tracking.mixin()],
- props: {
- failedJobs: {
- type: Array,
- required: true,
- },
- },
- methods: {
- async retryJob(id) {
- this.track('click_retry', { label: TRACKING_CATEGORIES.failed });
-
- try {
- const {
- data: {
- jobRetry: { errors, job },
- },
- } = await this.$apollo.mutate({
- mutation: RetryFailedJobMutation,
- variables: { id },
- });
- if (errors.length > 0) {
- this.showErrorMessage();
- } else {
- redirectTo(job.detailedStatus.detailsPath); // eslint-disable-line import/no-deprecated
- }
- } catch {
- this.showErrorMessage();
- }
- },
- canRetryJob(job) {
- return job.retryable && job.userPermissions.updateBuild;
- },
- showErrorMessage() {
- createAlert({ message: s__('Job|There was a problem retrying the failed job.') });
- },
- failureSummary(trace) {
- return trace ? trace.htmlSummary : s__('Job|No job log');
- },
- },
-};
-</script>
-
-<template>
- <gl-table-lite
- :items="failedJobs"
- :fields="$options.fields"
- stacked="lg"
- fixed
- data-testId="tab-failures"
- >
- <template #table-colgroup="{ fields }">
- <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
- </template>
-
- <template #cell(name)="{ item }">
- <div
- class="gl-display-flex gl-align-items-center gl-lg-justify-content-start gl-justify-content-end"
- >
- <ci-badge-link :status="item.detailedStatus" :show-text="false" class="gl-mr-3" />
- <div class="gl-text-truncate">
- <gl-link
- :href="item.detailedStatus.detailsPath"
- class="gl-font-weight-bold gl-text-gray-900!"
- >
- {{ item.name }}
- </gl-link>
- </div>
- </div>
- </template>
-
- <template #cell(stage)="{ item }">
- <div class="gl-text-truncate">
- <span>{{ item.stage.name }}</span>
- </div>
- </template>
-
- <template #cell(failureMessage)="{ item }">
- <span data-testid="job-failure-message">{{ item.failureMessage }}</span>
- </template>
-
- <template #cell(actions)="{ item }">
- <gl-button
- v-if="canRetryJob(item)"
- icon="retry"
- :title="$options.retry"
- :aria-label="$options.retry"
- @click="retryJob(item.id)"
- />
- </template>
-
- <template #row-details="{ item }">
- <pre
- v-if="item.userPermissions.readBuild"
- class="gl-w-full gl-text-left gl-border-none"
- data-testid="job-log"
- >
- <code v-safe-html="failureSummary(item.trace)" class="gl-reset-bg gl-p-0" data-testid="job-trace-summary">
- </code>
- </pre>
- </template>
- </gl-table-lite>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
deleted file mode 100644
index 61748860983..00000000000
--- a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
+++ /dev/null
@@ -1,133 +0,0 @@
-<script>
-import { GlIntersectionObserver, GlLoadingIcon, GlSkeletonLoader } from '@gitlab/ui';
-import produce from 'immer';
-import { createAlert } from '~/alert';
-import { __ } from '~/locale';
-import eventHub from '~/jobs/components/table/event_hub';
-import JobsTable from '~/jobs/components/table/jobs_table.vue';
-import { JOBS_TAB_FIELDS } from '~/jobs/components/table/constants';
-import getPipelineJobs from '../../graphql/queries/get_pipeline_jobs.query.graphql';
-
-export default {
- fields: JOBS_TAB_FIELDS,
- components: {
- GlIntersectionObserver,
- GlLoadingIcon,
- GlSkeletonLoader,
- JobsTable,
- },
- inject: {
- projectPath: {
- default: '',
- },
- pipelineIid: {
- default: '',
- },
- },
- apollo: {
- jobs: {
- query: getPipelineJobs,
- variables() {
- return {
- ...this.queryVariables,
- };
- },
- update(data) {
- return data.project?.pipeline?.jobs?.nodes || [];
- },
- result({ data }) {
- if (!data) {
- return;
- }
- this.jobsPageInfo = data.project?.pipeline?.jobs?.pageInfo || {};
- },
- error() {
- createAlert({ message: __('An error occurred while fetching the pipelines jobs.') });
- },
- },
- },
- data() {
- return {
- jobs: [],
- jobsPageInfo: {},
- firstLoad: true,
- };
- },
- computed: {
- queryVariables() {
- return {
- fullPath: this.projectPath,
- iid: this.pipelineIid,
- };
- },
- loading() {
- return this.$apollo.queries.jobs.loading;
- },
- showSkeletonLoader() {
- return this.firstLoad && this.loading;
- },
- showLoadingSpinner() {
- return !this.firstLoad && this.loading;
- },
- },
- mounted() {
- eventHub.$on('jobActionPerformed', this.handleJobAction);
- },
- beforeDestroy() {
- eventHub.$off('jobActionPerformed', this.handleJobAction);
- },
- methods: {
- handleJobAction() {
- this.firstLoad = false;
-
- this.$apollo.queries.jobs.refetch();
- },
- fetchMoreJobs() {
- this.firstLoad = false;
-
- this.$apollo.queries.jobs.fetchMore({
- variables: {
- ...this.queryVariables,
- after: this.jobsPageInfo.endCursor,
- },
- updateQuery: (previousResult, { fetchMoreResult }) => {
- const results = produce(fetchMoreResult, (draftData) => {
- draftData.project.pipeline.jobs.nodes = [
- ...previousResult.project.pipeline.jobs.nodes,
- ...draftData.project.pipeline.jobs.nodes,
- ];
- });
- return results;
- },
- });
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div v-if="showSkeletonLoader" class="gl-mt-5">
- <gl-skeleton-loader :width="1248" :height="73">
- <circle cx="748.031" cy="37.7193" r="15.0307" />
- <circle cx="787.241" cy="37.7193" r="15.0307" />
- <circle cx="827.759" cy="37.7193" r="15.0307" />
- <circle cx="866.969" cy="37.7193" r="15.0307" />
- <circle cx="380" cy="37" r="18" />
- <rect x="432" y="19" width="126.587" height="15" />
- <rect x="432" y="41" width="247" height="15" />
- <rect x="158" y="19" width="86.1" height="15" />
- <rect x="158" y="41" width="168" height="15" />
- <rect x="22" y="19" width="96" height="36" />
- <rect x="924" y="30" width="96" height="15" />
- <rect x="1057" y="20" width="166" height="35" />
- </gl-skeleton-loader>
- </div>
-
- <jobs-table v-else :jobs="jobs" :table-fields="$options.fields" data-testid="jobs-tab-table" />
-
- <gl-intersection-observer v-if="jobsPageInfo.hasNextPage" @appear="fetchMoreJobs">
- <gl-loading-icon v-if="showLoadingSpinner" size="lg" />
- </gl-intersection-observer>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue b/app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue
deleted file mode 100644
index ffb6ab71b22..00000000000
--- a/app/assets/javascripts/pipelines/components/jobs_shared/action_component.vue
+++ /dev/null
@@ -1,136 +0,0 @@
-<script>
-import { GlTooltipDirective, GlButton, GlLoadingIcon, GlIcon } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
-import { dasherize } from '~/lib/utils/text_utility';
-import { __ } from '~/locale';
-import { reportToSentry } from '../../utils';
-
-/**
- * Renders either a cancel, retry or play icon button and handles the post request
- *
- * Used in:
- * - mr widget mini pipeline graph: `mr_widget_pipeline.vue`
- * - pipelines table
- * - pipelines table in merge request page
- * - pipelines table in commit page
- * - pipelines detail page in big graph
- */
-export default {
- components: {
- GlIcon,
- GlButton,
- GlLoadingIcon,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- tooltipText: {
- type: String,
- required: true,
- },
- link: {
- type: String,
- required: true,
- },
- actionIcon: {
- type: String,
- required: true,
- },
- withConfirmationModal: {
- type: Boolean,
- required: false,
- default: false,
- },
- shouldTriggerClick: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- data() {
- return {
- isDisabled: false,
- isLoading: false,
- };
- },
- computed: {
- cssClass() {
- const actionIconDash = dasherize(this.actionIcon);
- return `${actionIconDash} js-icon-${actionIconDash}`;
- },
- },
- watch: {
- shouldTriggerClick(flag) {
- if (flag && this.withConfirmationModal) {
- this.executeAction();
- this.$emit('actionButtonClicked');
- }
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry('action_component', `error: ${err}, info: ${info}`);
- },
- methods: {
- /**
- * The request should not be handled here.
- * However due to this component being used in several
- * different apps it avoids repetition & complexity.
- *
- */
- onClickAction() {
- if (this.withConfirmationModal) {
- this.$emit('showActionConfirmationModal');
- } else {
- this.executeAction();
- }
- },
- executeAction() {
- this.$root.$emit(BV_HIDE_TOOLTIP, `js-ci-action-${this.link}`);
- this.isDisabled = true;
- this.isLoading = true;
-
- axios
- .post(`${this.link}.json`)
- .then(() => {
- this.isLoading = false;
-
- this.$emit('pipelineActionRequestComplete');
- })
- .catch((err) => {
- this.isDisabled = false;
- this.isLoading = false;
-
- reportToSentry('action_component', err);
-
- createAlert({
- message: __('An error occurred while making the request.'),
- });
- });
- },
- },
-};
-</script>
-<template>
- <gl-button
- :id="`js-ci-action-${link}`"
- ref="button"
- :class="cssClass"
- :disabled="isDisabled"
- class="js-ci-action gl-ci-action-icon-container ci-action-icon-container ci-action-icon-wrapper gl-display-flex gl-align-items-center gl-justify-content-center"
- data-testid="ci-action-component"
- @click.stop="onClickAction"
- >
- <div
- v-gl-tooltip.viewport
- :title="tooltipText"
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-h-full"
- data-testid="ci-action-icon-tooltip-wrapper"
- >
- <gl-loading-icon v-if="isLoading" size="sm" class="js-action-icon-loading" />
- <gl-icon v-else :name="actionIcon" class="gl-mr-0!" :aria-label="actionIcon" />
- </div>
- </gl-button>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/parsing_utils.js b/app/assets/javascripts/pipelines/components/parsing_utils.js
deleted file mode 100644
index e158f8809b5..00000000000
--- a/app/assets/javascripts/pipelines/components/parsing_utils.js
+++ /dev/null
@@ -1,182 +0,0 @@
-import { memoize } from 'lodash';
-import { createNodeDict } from '../utils';
-import { EXPLICIT_NEEDS_PROPERTY, NEEDS_PROPERTY } from '../constants';
-import { createSankey } from './dag/drawing_utils';
-
-/*
- A peformant alternative to lodash's isEqual. Because findIndex always finds
- the first instance of a match, if the found index is not the first, we know
- it is in fact a duplicate.
-*/
-const deduplicate = (item, itemIndex, arr) => {
- const foundIdx = arr.findIndex((test) => {
- return test.source === item.source && test.target === item.target;
- });
-
- return foundIdx === itemIndex;
-};
-
-export const makeLinksFromNodes = (nodes, nodeDict, { needsKey = NEEDS_PROPERTY } = {}) => {
- const constantLinkValue = 10; // all links are the same weight
- return nodes
- .map(({ jobs, name: groupName }) =>
- jobs.map((job) => {
- const needs = job[needsKey] || [];
-
- return needs.reduce((acc, needed) => {
- // It's possible that we have an optional job, which
- // is being needed by another job. In that scenario,
- // the needed job doesn't exist, so we don't want to
- // create link for it.
- if (nodeDict[needed]?.name) {
- acc.push({
- source: nodeDict[needed].name,
- target: groupName,
- value: constantLinkValue,
- });
- }
-
- return acc;
- }, []);
- }),
- )
- .flat(2);
-};
-
-export const getAllAncestors = (nodes, nodeDict) => {
- const needs = nodes
- .map((node) => {
- return nodeDict[node]?.needs || '';
- })
- .flat()
- .filter(Boolean)
- .filter(deduplicate);
-
- if (needs.length) {
- return [...needs, ...getAllAncestors(needs, nodeDict)];
- }
-
- return [];
-};
-
-export const filterByAncestors = (links, nodeDict) =>
- links.filter(({ target, source }) => {
- /*
-
- for every link, check out it's target
- for every target, get the target node's needs
- then drop the current link source from that list
-
- call a function to get all ancestors, recursively
- is the current link's source in the list of all parents?
- then we drop this link
-
- */
- const targetNode = target;
- const targetNodeNeeds = nodeDict[targetNode].needs;
- const targetNodeNeedsMinusSource = targetNodeNeeds.filter((need) => need !== source);
- const allAncestors = getAllAncestors(targetNodeNeedsMinusSource, nodeDict);
- return !allAncestors.includes(source);
- });
-
-export const parseData = (nodes, { needsKey = NEEDS_PROPERTY } = {}) => {
- const nodeDict = createNodeDict(nodes, { needsKey });
- const allLinks = makeLinksFromNodes(nodes, nodeDict, { needsKey });
- const filteredLinks = allLinks.filter(deduplicate);
- const links = filterByAncestors(filteredLinks, nodeDict);
-
- return { nodes, links };
-};
-
-/*
- The number of nodes in the most populous generation drives the height of the graph.
-*/
-
-export const getMaxNodes = (nodes) => {
- const counts = nodes.reduce((acc, { layer }) => {
- if (!acc[layer]) {
- acc[layer] = 0;
- }
-
- acc[layer] += 1;
-
- return acc;
- }, []);
-
- return Math.max(...counts);
-};
-
-/*
- Because we cannot know if a node is part of a relationship until after we
- generate the links with createSankey, this function is used after the first call
- to find nodes that have no relations.
-*/
-
-export const removeOrphanNodes = (sankeyfiedNodes) => {
- return sankeyfiedNodes.filter((node) => node.sourceLinks.length || node.targetLinks.length);
-};
-
-/*
- This utility accepts unwrapped pipeline data in the format returned from
- our standard pipeline GraphQL query and returns a list of names by layer
- for the layer view. It can be combined with the stageLookup on the pipeline
- to generate columns by layer.
-*/
-
-export const listByLayers = ({ stages }) => {
- const arrayOfJobs = stages.flatMap(({ groups }) => groups);
- const parsedData = parseData(arrayOfJobs);
- const explicitParsedData = parseData(arrayOfJobs, { needsKey: EXPLICIT_NEEDS_PROPERTY });
- const dataWithLayers = createSankey()(explicitParsedData);
-
- const pipelineLayers = dataWithLayers.nodes.reduce((acc, { layer, name }) => {
- /* sort groups by layer */
-
- if (!acc[layer]) {
- acc[layer] = [];
- }
-
- acc[layer].push(name);
-
- return acc;
- }, []);
-
- return {
- linksData: parsedData.links,
- numGroups: arrayOfJobs.length,
- pipelineLayers,
- };
-};
-
-export const generateColumnsFromLayersListBare = ({ stages, stagesLookup }, pipelineLayers) => {
- return pipelineLayers.map((layers, idx) => {
- /*
- Look up the groups in each layer,
- then add each set of layer groups to a stage-like object.
- */
-
- const groups = layers.map((id) => {
- const { stageIdx, groupIdx } = stagesLookup[id];
- return stages[stageIdx]?.groups?.[groupIdx];
- });
-
- return {
- name: '',
- id: `layer-${idx}`,
- status: { action: null },
- groups: groups.filter(Boolean),
- };
- });
-};
-
-export const generateColumnsFromLayersListMemoized = memoize(generateColumnsFromLayersListBare);
-
-export const keepLatestDownstreamPipelines = (downstreamPipelines = []) => {
- return downstreamPipelines.filter((pipeline) => {
- if (pipeline.source_job) {
- return !pipeline?.source_job?.retried || false;
- }
-
- return !pipeline?.sourceJob?.retried || false;
- });
-};
diff --git a/app/assets/javascripts/pipelines/components/pipeline_details_header.vue b/app/assets/javascripts/pipelines/components/pipeline_details_header.vue
deleted file mode 100644
index c53321f82bd..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_details_header.vue
+++ /dev/null
@@ -1,631 +0,0 @@
-<script>
-import {
- GlAlert,
- GlBadge,
- GlButton,
- GlIcon,
- GlLink,
- GlLoadingIcon,
- GlModal,
- GlModalDirective,
- GlSprintf,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
-import { setUrlFragment, redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import { __, s__, sprintf, formatNumber } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import SafeHtml from '~/vue_shared/directives/safe_html';
-import {
- LOAD_FAILURE,
- POST_FAILURE,
- DELETE_FAILURE,
- DEFAULT,
- BUTTON_TOOLTIP_RETRY,
- BUTTON_TOOLTIP_CANCEL,
-} from '../constants';
-import cancelPipelineMutation from '../graphql/mutations/cancel_pipeline.mutation.graphql';
-import deletePipelineMutation from '../graphql/mutations/delete_pipeline.mutation.graphql';
-import retryPipelineMutation from '../graphql/mutations/retry_pipeline.mutation.graphql';
-import getPipelineQuery from '../graphql/queries/get_pipeline_header_data.query.graphql';
-import { getQueryHeaders } from './graph/utils';
-
-const DELETE_MODAL_ID = 'pipeline-delete-modal';
-const POLL_INTERVAL = 10000;
-
-export default {
- name: 'PipelineDetailsHeader',
- BUTTON_TOOLTIP_RETRY,
- BUTTON_TOOLTIP_CANCEL,
- pipelineCancel: 'pipelineCancel',
- pipelineRetry: 'pipelineRetry',
- finishedStatuses: ['FAILED', 'SUCCESS', 'CANCELED'],
- components: {
- CiBadgeLink,
- ClipboardButton,
- GlAlert,
- GlBadge,
- GlButton,
- GlIcon,
- GlLink,
- GlLoadingIcon,
- GlModal,
- GlSprintf,
- TimeAgoTooltip,
- },
- directives: {
- GlModal: GlModalDirective,
- GlTooltip: GlTooltipDirective,
- SafeHtml,
- },
- i18n: {
- scheduleBadgeText: s__('Pipelines|Scheduled'),
- scheduleBadgeTooltip: __('This pipeline was triggered by a schedule'),
- childBadgeText: s__('Pipelines|Child pipeline (%{linkStart}parent%{linkEnd})'),
- childBadgeTooltip: __('This is a child pipeline within the parent pipeline'),
- latestBadgeText: s__('Pipelines|latest'),
- latestBadgeTooltip: __('Latest pipeline for the most recent commit on this branch'),
- mergeTrainBadgeText: s__('Pipelines|merge train'),
- mergeTrainBadgeTooltip: s__(
- 'Pipelines|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch.',
- ),
- invalidBadgeText: s__('Pipelines|yaml invalid'),
- failedBadgeText: s__('Pipelines|error'),
- autoDevopsBadgeText: s__('Pipelines|Auto DevOps'),
- autoDevopsBadgeTooltip: __(
- 'This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps.',
- ),
- detachedBadgeText: s__('Pipelines|merge request'),
- detachedBadgeTooltip: s__(
- "Pipelines|This pipeline ran on the contents of this merge request's source branch, not the target branch.",
- ),
- stuckBadgeText: s__('Pipelines|stuck'),
- stuckBadgeTooltip: s__('Pipelines|This pipeline is stuck'),
- computeMinutesTooltip: s__('Pipelines|Total amount of compute minutes used for the pipeline'),
- totalJobsTooltip: s__('Pipelines|Total number of jobs for the pipeline'),
- retryPipelineText: __('Retry'),
- cancelPipelineText: __('Cancel pipeline'),
- deletePipelineText: __('Delete'),
- clipboardTooltip: __('Copy commit SHA'),
- createdText: s__('Pipelines|created'),
- finishedText: s__('Pipelines|finished'),
- },
- errorTexts: {
- [LOAD_FAILURE]: __('We are currently unable to fetch data for the pipeline header.'),
- [POST_FAILURE]: __('An error occurred while making the request.'),
- [DELETE_FAILURE]: __('An error occurred while deleting the pipeline.'),
- [DEFAULT]: __('An unknown error occurred.'),
- },
- modal: {
- id: DELETE_MODAL_ID,
- title: __('Delete pipeline'),
- deleteConfirmationText: __(
- 'Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone.',
- ),
- actionPrimary: {
- text: __('Delete pipeline'),
- attributes: {
- variant: 'danger',
- },
- },
- actionCancel: {
- text: __('Cancel'),
- },
- },
- inject: {
- graphqlResourceEtag: {
- default: '',
- },
- paths: {
- default: {},
- },
- pipelineIid: {
- default: '',
- },
- },
- props: {
- name: {
- type: String,
- required: false,
- default: '',
- },
- totalJobs: {
- type: String,
- required: false,
- default: '',
- },
- computeMinutes: {
- type: String,
- required: false,
- default: '',
- },
- yamlErrors: {
- type: String,
- required: false,
- default: '',
- },
- failureReason: {
- type: String,
- required: false,
- default: '',
- },
- refText: {
- type: String,
- required: false,
- default: '',
- },
- badges: {
- type: Object,
- required: false,
- default: () => {},
- },
- },
- apollo: {
- pipeline: {
- context() {
- return getQueryHeaders(this.graphqlResourceEtag);
- },
- query: getPipelineQuery,
- variables() {
- return {
- fullPath: this.paths.fullProject,
- iid: this.pipelineIid,
- };
- },
- update(data) {
- return data.project.pipeline;
- },
- error() {
- this.reportFailure(LOAD_FAILURE);
- },
- pollInterval: POLL_INTERVAL,
- watchLoading(isLoading) {
- if (!isLoading) {
- // To ensure apollo has updated the cache,
- // we only remove the loading state in sync with GraphQL
- this.isCanceling = false;
- this.isRetrying = false;
- }
- },
- },
- },
- data() {
- return {
- pipeline: null,
- failureMessages: [],
- failureType: null,
- isCanceling: false,
- isRetrying: false,
- isDeleting: false,
- };
- },
- computed: {
- loading() {
- return this.$apollo.queries.pipeline.loading;
- },
- hasError() {
- return this.failureType;
- },
- hasPipelineData() {
- return Boolean(this.pipeline);
- },
- isLoadingInitialQuery() {
- return this.$apollo.queries.pipeline.loading && !this.hasPipelineData;
- },
- detailedStatus() {
- return this.pipeline?.detailedStatus || {};
- },
- status() {
- return this.pipeline?.status;
- },
- isFinished() {
- return this.$options.finishedStatuses.includes(this.status);
- },
- shouldRenderContent() {
- return !this.isLoadingInitialQuery && this.hasPipelineData;
- },
- failure() {
- switch (this.failureType) {
- case LOAD_FAILURE:
- return {
- text: this.$options.errorTexts[LOAD_FAILURE],
- variant: 'danger',
- };
- case POST_FAILURE:
- return {
- text: this.$options.errorTexts[POST_FAILURE],
- variant: 'danger',
- };
- case DELETE_FAILURE:
- return {
- text: this.$options.errorTexts[DELETE_FAILURE],
- variant: 'danger',
- };
- default:
- return {
- text: this.$options.errorTexts[DEFAULT],
- variant: 'danger',
- };
- }
- },
- user() {
- return this.pipeline?.user;
- },
- userId() {
- return getIdFromGraphQLId(this.user?.id);
- },
- shortId() {
- return this.pipeline?.commit?.shortId || '';
- },
- commitPath() {
- return this.pipeline?.commit?.webPath || '';
- },
- commitTitle() {
- return this.pipeline?.commit?.title || '';
- },
- totalJobsText() {
- return sprintf(__('%{jobs} Jobs'), {
- jobs: this.totalJobs,
- });
- },
- triggeredText() {
- return sprintf(__('triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}'), {
- shortId: this.shortId,
- });
- },
- inProgress() {
- return this.status === 'RUNNING';
- },
- duration() {
- return this.pipeline?.duration || 0;
- },
- showDuration() {
- return this.duration && this.isFinished;
- },
- durationFormatted() {
- return timeIntervalInWords(this.duration);
- },
- queuedDuration() {
- return this.pipeline?.queuedDuration || 0;
- },
- inProgressText() {
- return sprintf(__('In progress, queued for %{queuedDuration} seconds'), {
- queuedDuration: formatNumber(this.queuedDuration),
- });
- },
- durationText() {
- return sprintf(__('%{duration}, queued for %{queuedDuration} seconds'), {
- duration: this.durationFormatted,
- queuedDuration: formatNumber(this.queuedDuration),
- });
- },
- canRetryPipeline() {
- const { retryable, userPermissions } = this.pipeline;
-
- return retryable && userPermissions.updatePipeline;
- },
- canCancelPipeline() {
- const { cancelable, userPermissions } = this.pipeline;
-
- return cancelable && userPermissions.updatePipeline;
- },
- showComputeMinutes() {
- return this.isFinished && this.computeMinutes !== '0.0';
- },
- },
- methods: {
- reportFailure(errorType, errorMessages = []) {
- this.failureType = errorType;
- this.failureMessages = errorMessages;
- },
- async postPipelineAction(name, mutation) {
- try {
- const {
- data: {
- [name]: { errors },
- },
- } = await this.$apollo.mutate({
- mutation,
- variables: { id: this.pipeline.id },
- });
-
- if (errors.length > 0) {
- this.isRetrying = false;
-
- this.reportFailure(POST_FAILURE, errors);
- } else {
- await this.$apollo.queries.pipeline.refetch();
- if (!this.isFinished) {
- this.$apollo.queries.pipeline.startPolling(POLL_INTERVAL);
- }
- }
- } catch {
- this.isRetrying = false;
-
- this.reportFailure(POST_FAILURE);
- }
- },
- cancelPipeline() {
- this.isCanceling = true;
- this.postPipelineAction(this.$options.pipelineCancel, cancelPipelineMutation);
- },
- retryPipeline() {
- this.isRetrying = true;
- this.postPipelineAction(this.$options.pipelineRetry, retryPipelineMutation);
- },
- async deletePipeline() {
- this.isDeleting = true;
- this.$apollo.queries.pipeline.stopPolling();
-
- try {
- const {
- data: {
- pipelineDestroy: { errors },
- },
- } = await this.$apollo.mutate({
- mutation: deletePipelineMutation,
- variables: {
- id: this.pipeline.id,
- },
- });
-
- if (errors.length > 0) {
- this.reportFailure(DELETE_FAILURE, errors);
- this.isDeleting = false;
- } else {
- redirectTo(setUrlFragment(this.paths.pipelinesPath, 'delete_success')); // eslint-disable-line import/no-deprecated
- }
- } catch {
- this.$apollo.queries.pipeline.startPolling(POLL_INTERVAL);
- this.reportFailure(DELETE_FAILURE);
- this.isDeleting = false;
- }
- },
- },
-};
-</script>
-
-<template>
- <div class="gl-my-4" data-testid="pipeline-details-header">
- <gl-alert
- v-if="hasError"
- class="gl-mb-4"
- :title="failure.text"
- :variant="failure.variant"
- :dismissible="false"
- >
- <div v-for="(failureMessage, index) in failureMessages" :key="`failure-message-${index}`">
- {{ failureMessage }}
- </div>
- </gl-alert>
- <gl-loading-icon v-if="loading" class="gl-text-left" size="lg" />
- <div
- v-else
- class="gl-display-flex gl-justify-content-space-between gl-flex-wrap"
- data-qa-selector="pipeline_details_header"
- >
- <div>
- <h3 v-if="name" class="gl-mt-0 gl-mb-3" data-testid="pipeline-name">{{ name }}</h3>
- <h3 v-else class="gl-mt-0 gl-mb-3" data-testid="pipeline-commit-title">
- {{ commitTitle }}
- </h3>
- <div>
- <ci-badge-link :status="detailedStatus" />
- <div class="gl-ml-2 gl-mb-3 gl-display-inline-block gl-h-6">
- <gl-link
- v-if="user"
- :href="user.webUrl"
- class="gl-display-inline-block gl-text-gray-900 gl-font-weight-bold js-user-link"
- :data-user-id="userId"
- :data-username="user.username"
- data-testid="pipeline-user-link"
- >
- {{ user.name }}
- </gl-link>
- <gl-sprintf :message="triggeredText">
- <template #link="{ content }">
- <gl-link
- :href="commitPath"
- class="gl-bg-blue-50 gl-rounded-base gl-px-2 gl-mx-2"
- data-testid="commit-link"
- target="_blank"
- >
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- <clipboard-button
- :text="shortId"
- category="tertiary"
- :title="$options.i18n.clipboardTooltip"
- size="small"
- />
- <span v-if="inProgress" data-testid="pipeline-created-time-ago">
- {{ $options.i18n.createdText }}
- <time-ago-tooltip :time="pipeline.createdAt" />
- </span>
- <span v-if="isFinished" data-testid="pipeline-finished-time-ago">
- {{ $options.i18n.finishedText }}
- <time-ago-tooltip :time="pipeline.finishedAt" />
- </span>
- </div>
- </div>
- <div v-safe-html="refText" class="gl-mb-3" data-testid="pipeline-ref-text"></div>
- <div>
- <gl-badge
- v-if="badges.schedule"
- v-gl-tooltip
- :title="$options.i18n.scheduleBadgeTooltip"
- variant="info"
- size="sm"
- >
- {{ $options.i18n.scheduleBadgeText }}
- </gl-badge>
- <gl-badge
- v-if="badges.child"
- v-gl-tooltip
- :title="$options.i18n.childBadgeTooltip"
- variant="info"
- size="sm"
- >
- <gl-sprintf :message="$options.i18n.childBadgeText">
- <template #link="{ content }">
- <gl-link :href="paths.triggeredByPath" target="_blank">
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </gl-badge>
- <gl-badge
- v-if="badges.latest"
- v-gl-tooltip
- :title="$options.i18n.latestBadgeTooltip"
- variant="success"
- size="sm"
- >
- {{ $options.i18n.latestBadgeText }}
- </gl-badge>
- <gl-badge
- v-if="badges.mergeTrainPipeline"
- v-gl-tooltip
- :title="$options.i18n.mergeTrainBadgeTooltip"
- variant="info"
- size="sm"
- >
- {{ $options.i18n.mergeTrainBadgeText }}
- </gl-badge>
- <gl-badge
- v-if="badges.invalid"
- v-gl-tooltip
- :title="yamlErrors"
- variant="danger"
- size="sm"
- >
- {{ $options.i18n.invalidBadgeText }}
- </gl-badge>
- <gl-badge
- v-if="badges.failed"
- v-gl-tooltip
- :title="failureReason"
- variant="danger"
- size="sm"
- >
- {{ $options.i18n.failedBadgeText }}
- </gl-badge>
- <gl-badge
- v-if="badges.autoDevops"
- v-gl-tooltip
- :title="$options.i18n.autoDevopsBadgeTooltip"
- variant="info"
- size="sm"
- >
- {{ $options.i18n.autoDevopsBadgeText }}
- </gl-badge>
- <gl-badge
- v-if="badges.detached"
- v-gl-tooltip
- :title="$options.i18n.detachedBadgeTooltip"
- variant="info"
- size="sm"
- >
- {{ $options.i18n.detachedBadgeText }}
- </gl-badge>
- <gl-badge
- v-if="badges.stuck"
- v-gl-tooltip
- :title="$options.i18n.stuckBadgeTooltip"
- variant="warning"
- size="sm"
- >
- {{ $options.i18n.stuckBadgeText }}
- </gl-badge>
- <span
- v-gl-tooltip
- :title="$options.i18n.totalJobsTooltip"
- class="gl-ml-2"
- data-testid="total-jobs"
- >
- <gl-icon name="pipeline" />
- {{ totalJobsText }}
- </span>
- <span
- v-if="showComputeMinutes"
- v-gl-tooltip
- :title="$options.i18n.computeMinutesTooltip"
- class="gl-ml-2"
- data-testid="compute-minutes"
- >
- <gl-icon name="quota" />
- {{ computeMinutes }}
- </span>
- <span v-if="inProgress" class="gl-ml-2" data-testid="pipeline-running-text">
- <gl-icon name="timer" />
- {{ inProgressText }}
- </span>
- <span v-if="showDuration" class="gl-ml-2" data-testid="pipeline-duration-text">
- <gl-icon name="timer" />
- {{ durationText }}
- </span>
- </div>
- </div>
- <div class="gl-mt-5 gl-lg-mt-0">
- <gl-button
- v-if="canRetryPipeline"
- v-gl-tooltip
- :aria-label="$options.BUTTON_TOOLTIP_RETRY"
- :title="$options.BUTTON_TOOLTIP_RETRY"
- :loading="isRetrying"
- :disabled="isRetrying"
- variant="confirm"
- data-testid="retry-pipeline"
- class="js-retry-button"
- @click="retryPipeline()"
- >
- {{ $options.i18n.retryPipelineText }}
- </gl-button>
-
- <gl-button
- v-if="canCancelPipeline"
- v-gl-tooltip
- :aria-label="$options.BUTTON_TOOLTIP_CANCEL"
- :title="$options.BUTTON_TOOLTIP_CANCEL"
- :loading="isCanceling"
- :disabled="isCanceling"
- class="gl-ml-3"
- variant="danger"
- data-testid="cancel-pipeline"
- @click="cancelPipeline()"
- >
- {{ $options.i18n.cancelPipelineText }}
- </gl-button>
-
- <gl-button
- v-if="pipeline.userPermissions.destroyPipeline"
- v-gl-modal="$options.modal.id"
- :loading="isDeleting"
- :disabled="isDeleting"
- class="gl-ml-3"
- variant="danger"
- category="secondary"
- data-testid="delete-pipeline"
- >
- {{ $options.i18n.deletePipelineText }}
- </gl-button>
- </div>
- </div>
- <gl-modal
- :modal-id="$options.modal.id"
- :title="$options.modal.title"
- :action-primary="$options.modal.actionPrimary"
- :action-cancel="$options.modal.actionCancel"
- @primary="deletePipeline()"
- >
- <p>
- {{ $options.modal.deleteConfirmationText }}
- </p>
- </gl-modal>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue
deleted file mode 100644
index 8daf85e2b2e..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue
+++ /dev/null
@@ -1,174 +0,0 @@
-<script>
-import { GlAlert } from '@gitlab/ui';
-import { __ } from '~/locale';
-import { DRAW_FAILURE, DEFAULT } from '../../constants';
-import LinksLayer from '../graph_shared/links_layer.vue';
-import JobPill from './job_pill.vue';
-import StageName from './stage_name.vue';
-
-export default {
- components: {
- GlAlert,
- JobPill,
- LinksLayer,
- StageName,
- },
- CONTAINER_REF: 'PIPELINE_GRAPH_CONTAINER_REF',
- BASE_CONTAINER_ID: 'pipeline-graph-container',
- PIPELINE_ID: 0,
- STROKE_WIDTH: 2,
- errorTexts: {
- [DRAW_FAILURE]: __('Could not draw the lines for job relationships'),
- [DEFAULT]: __('An unknown error occurred.'),
- },
- // The combination of gl-w-full gl-min-w-full and gl-max-w-15 is necessary.
- // The max width and the width make sure the ellipsis to work and the min width
- // is for when there is less text than the stage column width (which the width 100% does not fix)
- jobWrapperClasses:
- 'gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full gl-px-8 gl-min-w-full gl-max-w-15',
- props: {
- pipelineData: {
- required: true,
- type: Object,
- },
- },
- data() {
- return {
- failureType: null,
- highlightedJob: null,
- highlightedJobs: [],
- measurements: {
- height: 0,
- width: 0,
- },
- };
- },
- computed: {
- containerId() {
- return `${this.$options.BASE_CONTAINER_ID}-${this.$options.PIPELINE_ID}`;
- },
- failure() {
- switch (this.failureType) {
- case DRAW_FAILURE:
- return {
- text: this.$options.errorTexts[DRAW_FAILURE],
- variant: 'danger',
- dismissible: true,
- };
- default:
- return {
- text: this.$options.errorTexts[DEFAULT],
- variant: 'danger',
- dismissible: true,
- };
- }
- },
- hasError() {
- return this.failureType;
- },
- hasHighlightedJob() {
- return Boolean(this.highlightedJob);
- },
- pipelineStages() {
- return this.pipelineData?.stages || [];
- },
- },
- watch: {
- pipelineData: {
- immediate: true,
- handler() {
- this.$nextTick(() => {
- this.computeGraphDimensions();
- });
- },
- },
- },
- methods: {
- computeGraphDimensions() {
- this.measurements = {
- width: this.$refs[this.$options.CONTAINER_REF].scrollWidth,
- height: this.$refs[this.$options.CONTAINER_REF].scrollHeight,
- };
- },
- isFadedOut(jobName) {
- return this.highlightedJobs.length > 1 && !this.isJobHighlighted(jobName);
- },
- isJobHighlighted(jobName) {
- return this.highlightedJobs.includes(jobName);
- },
- onError(error) {
- this.reportFailure(error.type);
- },
- removeHoveredJob() {
- this.highlightedJob = null;
- },
- reportFailure(errorType) {
- this.failureType = errorType;
- },
- resetFailure() {
- this.failureType = null;
- },
- setHoveredJob(jobName) {
- this.highlightedJob = jobName;
- },
- updateHighlightedJobs(jobs) {
- this.highlightedJobs = jobs;
- },
- },
-};
-</script>
-<template>
- <div>
- <gl-alert
- v-if="hasError"
- :variant="failure.variant"
- :dismissible="failure.dismissible"
- @dismiss="resetFailure"
- >
- {{ failure.text }}
- </gl-alert>
- <div
- :id="containerId"
- :ref="$options.CONTAINER_REF"
- class="gl-bg-gray-10 gl-overflow-auto"
- data-testid="graph-container"
- data-qa-selector="pipeline_graph_container"
- >
- <links-layer
- :pipeline-data="pipelineStages"
- :pipeline-id="$options.PIPELINE_ID"
- :container-id="containerId"
- :container-measurements="measurements"
- :highlighted-job="highlightedJob"
- @highlightedJobsChange="updateHighlightedJobs"
- @error="onError"
- >
- <div
- v-for="(stage, index) in pipelineStages"
- :key="`${stage.name}-${index}`"
- class="gl-flex-direction-column"
- >
- <div
- class="gl-display-flex gl-align-items-center gl-w-full gl-px-9 gl-py-4 gl-mb-5"
- data-qa-selector="stage_container"
- >
- <stage-name :stage-name="stage.name" />
- </div>
- <div :class="$options.jobWrapperClasses">
- <job-pill
- v-for="group in stage.groups"
- :key="group.name"
- :job-name="group.name"
- :pipeline-id="$options.PIPELINE_ID"
- :is-hovered="highlightedJob === group.name"
- :is-faded-out="isFadedOut(group.name)"
- data-qa-selector="job_container"
- @on-mouse-enter="setHoveredJob"
- @on-mouse-leave="removeHoveredJob"
- />
- </div>
- </div>
- </links-layer>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_job_item.vue b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_job_item.vue
deleted file mode 100644
index d6e585d093b..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_job_item.vue
+++ /dev/null
@@ -1,168 +0,0 @@
-<script>
-import { GlTooltipDirective, GlLink } from '@gitlab/ui';
-import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
-import { s__, sprintf } from '~/locale';
-import { reportToSentry } from '../../utils';
-import ActionComponent from '../jobs_shared/action_component.vue';
-import JobNameComponent from '../jobs_shared/job_name_component.vue';
-import { ICONS } from '../../constants';
-
-/**
- * Renders the badge for the pipeline graph and the job's dropdown.
- *
- * The following object should be provided as `job`:
- *
- * {
- * "id": 4256,
- * "name": "test",
- * "status": {
- * "icon": "status_success",
- * "text": "passed",
- * "label": "passed",
- * "group": "success",
- * "tooltip": "passed",
- * "details_path": "/root/ci-mock/builds/4256",
- * "action": {
- * "icon": "retry",
- * "title": "Retry",
- * "path": "/root/ci-mock/builds/4256/retry",
- * "method": "post"
- * }
- * }
- * }
- */
-
-export default {
- i18n: {
- runAgainTooltipText: s__('Pipeline|Run again'),
- },
- tooltipConfig: {
- boundary: 'viewport',
- placement: 'bottom',
- customClass: 'gl-pointer-events-none',
- },
- components: {
- ActionComponent,
- JobNameComponent,
- GlLink,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [delayedJobMixin],
- props: {
- job: {
- type: Object,
- required: true,
- },
- cssClassJobName: {
- type: String,
- required: false,
- default: '',
- },
- dropdownLength: {
- type: Number,
- required: false,
- default: Infinity,
- },
- pipelineId: {
- type: Number,
- required: false,
- default: -1,
- },
- },
- computed: {
- boundary() {
- return this.dropdownLength === 1 ? 'viewport' : 'scrollParent';
- },
- detailsPath() {
- return this.status?.details_path;
- },
- hasDetails() {
- return this.status?.has_details;
- },
- status() {
- return this.job?.status ? this.job.status : {};
- },
- tooltipText() {
- const textBuilder = [];
- const { name: jobName } = this.job;
-
- if (jobName) {
- textBuilder.push(jobName);
- }
-
- const { tooltip: statusTooltip } = this.status;
- if (jobName && statusTooltip) {
- textBuilder.push('-');
- }
-
- if (statusTooltip) {
- if (this.isDelayedJob) {
- textBuilder.push(sprintf(statusTooltip, { remainingTime: this.remainingTime }));
- } else {
- textBuilder.push(statusTooltip);
- }
- }
-
- return textBuilder.join(' ');
- },
- /**
- * Verifies if the provided job has an action path
- *
- * @return {Boolean}
- */
- hasJobAction() {
- return Boolean(this.job?.status?.action?.path);
- },
- jobActionTooltipText() {
- const { group } = this.status;
- const { title, icon } = this.status.action;
-
- return icon === ICONS.RETRY && group === ICONS.SUCCESS
- ? this.$options.i18n.runAgainTooltipText
- : title;
- },
- },
- errorCaptured(err, _vm, info) {
- reportToSentry('pipelines_job_item', `pipelines_job_item error: ${err}, info: ${info}`);
- },
-};
-</script>
-<template>
- <div
- class="ci-job-component gl-display-flex gl-align-items-center gl-justify-content-space-between"
- data-qa-selector="job_item_container"
- >
- <gl-link
- v-if="hasDetails"
- v-gl-tooltip="$options.tooltipConfig"
- :href="detailsPath"
- :title="tooltipText"
- :class="cssClassJobName"
- class="js-pipeline-graph-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none gl-focus-text-decoration-none gl-hover-text-decoration-none"
- data-testid="job-with-link"
- >
- <job-name-component :name="job.name" :status="job.status" />
- </gl-link>
-
- <div
- v-else
- v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }"
- :title="tooltipText"
- :class="cssClassJobName"
- class="js-job-component-tooltip non-details-job-component menu-item"
- data-testid="job-without-link"
- >
- <job-name-component :name="job.name" :status="job.status" />
- </div>
-
- <action-component
- v-if="hasJobAction"
- :tooltip-text="jobActionTooltipText"
- :link="status.action.path"
- :action-icon="status.action.icon"
- data-qa-selector="action_button"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage.vue b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage.vue
deleted file mode 100644
index 048e42731c7..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage.vue
+++ /dev/null
@@ -1,176 +0,0 @@
-<script>
-/**
- * Renders each stage of the pipeline mini graph.
- *
- * Given the provided endpoint will make a request to
- * fetch the dropdown data when the stage is clicked.
- *
- * Request is made inside this component to make it reusable between:
- * 1. Pipelines main table
- * 2. Pipelines table in commit and Merge request views
- * 3. Merge request widget
- * 4. Commit widget
- */
-
-import { GlDropdown, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { __, s__, sprintf } from '~/locale';
-import eventHub from '../../event_hub';
-import LegacyJobItem from './legacy_job_item.vue';
-
-export default {
- i18n: {
- errorMessage: __('Something went wrong on our end.'),
- loadingText: __('Loading...'),
- mergeTrainMessage: s__('Pipeline|Merge train pipeline jobs can not be retried'),
- stage: __('Stage:'),
- viewStageLabel: __('View Stage: %{title}'),
- },
- dropdownPopperOpts: {
- placement: 'bottom',
- positionFixed: true,
- },
- components: {
- CiIcon,
- GlLoadingIcon,
- GlDropdown,
- LegacyJobItem,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- stage: {
- type: Object,
- required: true,
- },
- updateDropdown: {
- type: Boolean,
- required: false,
- default: false,
- },
- isMergeTrain: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- data() {
- return {
- isDropdownOpen: false,
- isLoading: false,
- dropdownContent: [],
- stageName: '',
- };
- },
- watch: {
- updateDropdown() {
- if (this.updateDropdown && this.isDropdownOpen && !this.isLoading) {
- this.fetchJobs();
- }
- },
- },
- methods: {
- onHideDropdown() {
- this.isDropdownOpen = false;
- },
- onShowDropdown() {
- eventHub.$emit('clickedDropdown');
- this.isDropdownOpen = true;
- this.isLoading = true;
- this.fetchJobs();
-
- // used for tracking and is separate from event hub
- // to avoid complexity with mixin
- this.$emit('miniGraphStageClick');
- },
- fetchJobs() {
- axios
- .get(this.stage.dropdown_path)
- .then(({ data }) => {
- this.dropdownContent = data.latest_statuses;
- this.stageName = data.name;
- this.isLoading = false;
- })
- .catch(() => {
- this.$refs.dropdown.hide();
- this.isLoading = false;
-
- createAlert({
- message: this.$options.i18n.errorMessage,
- });
- });
- },
- stageAriaLabel(title) {
- return sprintf(this.$options.i18n.viewStageLabel, { title });
- },
- },
-};
-</script>
-
-<template>
- <gl-dropdown
- ref="dropdown"
- v-gl-tooltip.hover.ds0
- v-gl-tooltip="stage.title"
- data-testid="mini-pipeline-graph-dropdown"
- variant="link"
- :aria-label="stageAriaLabel(stage.title)"
- :lazy="true"
- :popper-opts="$options.dropdownPopperOpts"
- :toggle-class="['gl-rounded-full!']"
- menu-class="mini-pipeline-graph-dropdown-menu"
- @hide="onHideDropdown"
- @show="onShowDropdown"
- >
- <template #button-content>
- <ci-icon
- is-borderless
- is-interactive
- css-classes="gl-rounded-full"
- :is-active="isDropdownOpen"
- :size="24"
- :status="stage.status"
- class="gl-display-inline-flex gl-align-items-center gl-border gl-z-index-1"
- />
- </template>
- <div v-if="isLoading" class="gl--flex-center gl-p-2" data-testid="pipeline-stage-loading-state">
- <gl-loading-icon size="sm" class="gl-mr-3" />
- <p class="gl-line-height-normal gl-mb-0">{{ $options.i18n.loadingText }}</p>
- </div>
- <ul
- v-else
- class="js-builds-dropdown-list scrollable-menu"
- data-testid="mini-pipeline-graph-dropdown-menu-list"
- >
- <div class="gl--flex-center gl-border-b gl-font-weight-bold gl-mb-3 gl-pb-3">
- <span class="gl-mr-1">{{ $options.i18n.stage }}</span>
- <span data-testid="pipeline-stage-dropdown-menu-title">{{ stageName }}</span>
- </div>
- <li v-for="job in dropdownContent" :key="job.id">
- <legacy-job-item
- :dropdown-length="dropdownContent.length"
- :job="job"
- css-class-job-name="pipeline-job-item"
- />
- </li>
- <template v-if="isMergeTrain">
- <li class="gl-dropdown-divider" role="presentation">
- <hr role="separator" aria-orientation="horizontal" class="dropdown-divider" />
- </li>
- <li>
- <div
- class="gl-display-flex gl-align-items-center"
- data-testid="warning-message-merge-trains"
- >
- <div class="menu-item gl-font-sm gl-text-gray-300!">
- {{ $options.i18n.mergeTrainMessage }}
- </div>
- </div>
- </li>
- </template>
- </ul>
- </gl-dropdown>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list.vue b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list.vue
deleted file mode 100644
index a5c6dc98694..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list.vue
+++ /dev/null
@@ -1,132 +0,0 @@
-<script>
-import { GlTooltipDirective } from '@gitlab/ui';
-import { sprintf, s__ } from '~/locale';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { accessValue } from './accessors/linked_pipelines_accessors';
-/**
- * Renders the upstream/downstream portions of the pipeline mini graph.
- */
-export default {
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- CiIcon,
- },
- inject: {
- dataMethod: {
- default: 'rest',
- },
- },
- props: {
- triggeredBy: {
- type: Array,
- required: false,
- default: () => [],
- },
- triggered: {
- type: Array,
- required: false,
- default: () => [],
- },
- pipelinePath: {
- type: String,
- required: false,
- default: '',
- },
- },
- data() {
- return {
- maxRenderedPipelines: 3,
- };
- },
- computed: {
- // Exactly one of these (triggeredBy and triggered) must be truthy. Never both. Never neither.
- isUpstream() {
- return Boolean(this.triggeredBy.length) && !this.triggered.length;
- },
- isDownstream() {
- return !this.triggeredBy.length && Boolean(this.triggered.length);
- },
- linkedPipelines() {
- return this.isUpstream ? this.triggeredBy : this.triggered;
- },
- totalPipelineCount() {
- return this.linkedPipelines.length;
- },
- linkedPipelinesTrimmed() {
- return this.totalPipelineCount > this.maxRenderedPipelines
- ? this.linkedPipelines.slice(0, this.maxRenderedPipelines)
- : this.linkedPipelines;
- },
- shouldRenderCounter() {
- return this.isDownstream && this.linkedPipelines.length > this.maxRenderedPipelines;
- },
- counterLabel() {
- return `+${this.linkedPipelines.length - this.maxRenderedPipelines}`;
- },
- counterTooltipText() {
- return sprintf(s__('LinkedPipelines|%{counterLabel} more downstream pipelines'), {
- counterLabel: this.counterLabel,
- });
- },
- },
- methods: {
- pipelineTooltipText(pipeline) {
- const { label } = accessValue(pipeline, this.dataMethod, 'detailedStatus');
-
- return `${pipeline.project.name} - ${label}`;
- },
- pipelineStatus(pipeline) {
- // detailedStatus is graphQL, details.status is REST
- return pipeline?.detailedStatus || pipeline?.details?.status;
- },
- triggerButtonClass(pipeline) {
- const { group } = accessValue(pipeline, this.dataMethod, 'detailedStatus');
-
- return `ci-status-icon-${group}`;
- },
- },
-};
-</script>
-
-<template>
- <span
- v-if="linkedPipelines"
- :class="{
- 'is-upstream': isUpstream,
- 'is-downstream': isDownstream,
- }"
- class="linked-pipeline-mini-list gl-display-inline gl-vertical-align-middle"
- >
- <a
- v-for="pipeline in linkedPipelinesTrimmed"
- :key="pipeline.id"
- v-gl-tooltip="{ title: pipelineTooltipText(pipeline) }"
- :href="pipeline.path"
- :class="triggerButtonClass(pipeline)"
- class="linked-pipeline-mini-item gl-display-inline-block gl-h-6 gl-mr-2 gl-my-2 gl-rounded-full gl-vertical-align-middle"
- data-testid="linked-pipeline-mini-item"
- >
- <ci-icon
- is-borderless
- is-interactive
- css-classes="gl-rounded-full"
- :size="24"
- :status="pipelineStatus(pipeline)"
- class="gl-align-items-center gl-border gl-display-inline-flex"
- />
- </a>
-
- <a
- v-if="shouldRenderCounter"
- v-gl-tooltip="{ title: counterTooltipText }"
- :title="counterTooltipText"
- :href="pipelinePath"
- class="gl-align-items-center gl-bg-gray-50 gl-display-inline-flex gl-font-sm gl-h-6 gl-justify-content-center gl-rounded-pill gl-text-decoration-none gl-text-gray-500 gl-w-7 linked-pipelines-counter linked-pipeline-mini-item"
- data-testid="linked-pipeline-counter"
- >
- {{ counterLabel }}
- </a>
- </span>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue
deleted file mode 100644
index 7cdaec81466..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue
+++ /dev/null
@@ -1,150 +0,0 @@
-<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import { __ } from '~/locale';
-import { keepLatestDownstreamPipelines } from '~/pipelines/components/parsing_utils';
-import {
- getQueryHeaders,
- toggleQueryPollingByVisibility,
-} from '~/pipelines/components/graph/utils';
-import { PIPELINE_MINI_GRAPH_POLL_INTERVAL } from '~/pipelines/constants';
-import getLinkedPipelinesQuery from '~/pipelines/graphql/queries/get_linked_pipelines.query.graphql';
-import getPipelineStagesQuery from '~/pipelines/graphql/queries/get_pipeline_stages.query.graphql';
-import LegacyPipelineMiniGraph from './legacy_pipeline_mini_graph.vue';
-
-export default {
- i18n: {
- linkedPipelinesFetchError: __('There was a problem fetching linked pipelines.'),
- stagesFetchError: __('There was a problem fetching the pipeline stages.'),
- },
- components: {
- GlLoadingIcon,
- LegacyPipelineMiniGraph,
- },
- props: {
- pipelineEtag: {
- type: String,
- required: true,
- },
- fullPath: {
- type: String,
- required: true,
- },
- iid: {
- type: String,
- required: true,
- },
- isMergeTrain: {
- type: Boolean,
- required: false,
- default: false,
- },
- pollInterval: {
- type: Number,
- required: false,
- default: PIPELINE_MINI_GRAPH_POLL_INTERVAL,
- },
- },
- data() {
- return {
- linkedPipelines: null,
- pipelineStages: [],
- };
- },
- apollo: {
- linkedPipelines: {
- context() {
- return getQueryHeaders(this.pipelineEtag);
- },
- query: getLinkedPipelinesQuery,
- pollInterval() {
- return this.pollInterval;
- },
- variables() {
- return {
- fullPath: this.fullPath,
- iid: this.iid,
- };
- },
- update({ project }) {
- return project?.pipeline || this.linkedpipelines;
- },
- error() {
- createAlert({ message: this.$options.i18n.linkedPipelinesFetchError });
- },
- },
- pipelineStages: {
- context() {
- return getQueryHeaders(this.pipelineEtag);
- },
- query: getPipelineStagesQuery,
- pollInterval() {
- return this.pollInterval;
- },
- variables() {
- return {
- fullPath: this.fullPath,
- iid: this.iid,
- };
- },
- update({ project }) {
- return project?.pipeline?.stages?.nodes || this.pipelineStages;
- },
- error() {
- createAlert({ message: this.$options.i18n.stagesFetchError });
- },
- },
- },
- computed: {
- downstreamPipelines() {
- return keepLatestDownstreamPipelines(this.linkedPipelines?.downstream?.nodes);
- },
- formattedStages() {
- return this.pipelineStages.map((stage) => {
- const { name, detailedStatus } = stage;
- return {
- // TODO: Once we fetch stage by ID with GraphQL,
- // this method will change.
- // see https://gitlab.com/gitlab-org/gitlab/-/issues/384853
- id: stage.id,
- dropdown_path: `${this.pipelinePath}/stage.json?stage=${name}`,
- name,
- path: `${this.pipelinePath}#${name}`,
- status: {
- details_path: `${this.pipelinePath}#${name}`,
- has_details: detailedStatus?.hasDetails || false,
- ...detailedStatus,
- },
- title: `${name}: ${detailedStatus?.text || ''}`,
- };
- });
- },
- pipelinePath() {
- return this.linkedPipelines?.path || '';
- },
- upstreamPipeline() {
- return this.linkedPipelines?.upstream;
- },
- },
- mounted() {
- toggleQueryPollingByVisibility(this.$apollo.queries.linkedPipelines);
- toggleQueryPollingByVisibility(this.$apollo.queries.pipelineStages);
- },
-};
-</script>
-
-<template>
- <div>
- <gl-loading-icon v-if="$apollo.queries.pipelineStages.loading" />
- <legacy-pipeline-mini-graph
- v-else
- data-testid="pipeline-mini-graph"
- is-graphql
- :downstream-pipelines="downstreamPipelines"
- :is-merge-train="isMergeTrain"
- :pipeline-path="pipelinePath"
- :stages="formattedStages"
- :upstream-pipeline="upstreamPipeline"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue
deleted file mode 100644
index 8e22f440089..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue
+++ /dev/null
@@ -1,84 +0,0 @@
-<script>
-import { createAlert } from '~/alert';
-import { __ } from '~/locale';
-import { PIPELINE_MINI_GRAPH_POLL_INTERVAL } from '~/pipelines/constants';
-import {
- getQueryHeaders,
- toggleQueryPollingByVisibility,
-} from '~/pipelines/components/graph/utils';
-import getPipelineStageQuery from '~/pipelines/graphql/queries/get_pipeline_stage.query.graphql';
-import JobItem from './job_item.vue';
-
-export default {
- i18n: {
- stageFetchError: __('There was a problem fetching the pipeline stage.'),
- },
-
- components: {
- JobItem,
- },
- props: {
- isMergeTrain: {
- type: Boolean,
- required: false,
- default: false,
- },
- pipelineEtag: {
- type: String,
- required: true,
- },
- pollInterval: {
- type: Number,
- required: false,
- default: PIPELINE_MINI_GRAPH_POLL_INTERVAL,
- },
- stageId: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- jobs: [],
- stage: null,
- };
- },
- apollo: {
- stage: {
- context() {
- return getQueryHeaders(this.pipelineEtag);
- },
- query: getPipelineStageQuery,
- pollInterval() {
- return this.pollInterval;
- },
- variables() {
- return {
- id: this.stageId,
- };
- },
- skip() {
- return !this.stageId;
- },
- update(data) {
- this.jobs = data?.ciPipelineStage?.jobs.nodes;
- return data?.ciPipelineStage;
- },
- error() {
- createAlert({ message: this.$options.i18n.stageFetchError });
- },
- },
- },
- mounted() {
- toggleQueryPollingByVisibility(this.$apollo.queries.stage);
- },
-};
-</script>
-
-<template>
- <div data-testid="pipeline-stage">
- <ul v-for="job in jobs" :key="job.id">
- <job-item :job="job" />
- </ul>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stages.vue b/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stages.vue
deleted file mode 100644
index 02dba9ba30f..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stages.vue
+++ /dev/null
@@ -1,63 +0,0 @@
-<script>
-import PipelineStage from './pipeline_stage.vue';
-import LegacyPipelineStage from './legacy_pipeline_stage.vue';
-/**
- * Renders the pipeline stages portion of the pipeline mini graph.
- */
-export default {
- components: {
- LegacyPipelineStage,
- PipelineStage,
- },
- props: {
- stages: {
- type: Array,
- required: true,
- },
- updateDropdown: {
- type: Boolean,
- required: false,
- default: false,
- },
- isGraphql: {
- type: Boolean,
- required: false,
- default: false,
- },
- isMergeTrain: {
- type: Boolean,
- required: false,
- default: false,
- },
- pipelineEtag: {
- type: String,
- required: false,
- default: '',
- },
- },
-};
-</script>
-<template>
- <div class="gl-display-inline gl-vertical-align-middle">
- <div
- v-for="stage in stages"
- :key="stage.name"
- class="pipeline-mini-graph-stage-container dropdown gl-display-inline-block gl-mr-2 gl-my-2 gl-vertical-align-middle"
- >
- <pipeline-stage
- v-if="isGraphql"
- :stage-id="stage.id"
- :is-merge-train="isMergeTrain"
- :pipeline-etag="pipelineEtag"
- @miniGraphStageClick="$emit('miniGraphStageClick')"
- />
- <legacy-pipeline-stage
- v-else
- :stage="stage"
- :update-dropdown="updateDropdown"
- :is-merge-train="isMergeTrain"
- @miniGraphStageClick="$emit('miniGraphStageClick')"
- />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
deleted file mode 100644
index 35dde6379dd..00000000000
--- a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
+++ /dev/null
@@ -1,138 +0,0 @@
-<script>
-import { GlBadge, GlTabs, GlTab } from '@gitlab/ui';
-import { __ } from '~/locale';
-import Tracking from '~/tracking';
-import {
- failedJobsTabName,
- jobsTabName,
- needsTabName,
- pipelineTabName,
- testReportTabName,
- TRACKING_CATEGORIES,
-} from '../constants';
-
-export default {
- i18n: {
- tabs: {
- failedJobsTitle: __('Failed Jobs'),
- jobsTitle: __('Jobs'),
- needsTitle: __('Needs'),
- pipelineTitle: __('Pipeline'),
- testsTitle: __('Tests'),
- },
- },
- tabNames: {
- pipeline: pipelineTabName,
- needs: needsTabName,
- jobs: jobsTabName,
- failures: failedJobsTabName,
- tests: testReportTabName,
- },
- components: {
- GlBadge,
- GlTab,
- GlTabs,
- },
- mixins: [Tracking.mixin()],
- inject: ['defaultTabValue', 'failedJobsCount', 'totalJobCount', 'testsCount'],
- data() {
- return {
- activeTab: this.defaultTabValue,
- };
- },
- computed: {
- showFailedJobsTab() {
- return this.failedJobsCount > 0;
- },
- },
- watch: {
- $route(to) {
- this.activeTab = to.name;
- },
- },
- methods: {
- isActive(tabName) {
- return tabName === this.activeTab;
- },
- navigateTo(tabName) {
- if (this.isActive(tabName)) return;
-
- this.$router.push({ name: tabName });
- },
- failedJobsTabClick() {
- this.track('click_tab', { label: TRACKING_CATEGORIES.failed });
-
- this.navigateTo(this.$options.tabNames.failures);
- },
- testsTabClick() {
- this.track('click_tab', { label: TRACKING_CATEGORIES.tests });
-
- this.navigateTo(this.$options.tabNames.tests);
- },
- },
-};
-</script>
-
-<template>
- <gl-tabs>
- <gl-tab
- ref="pipelineTab"
- :title="$options.i18n.tabs.pipelineTitle"
- :active="isActive($options.tabNames.pipeline)"
- data-testid="pipeline-tab"
- lazy
- @click="navigateTo($options.tabNames.pipeline)"
- >
- <router-view />
- </gl-tab>
- <gl-tab
- ref="dagTab"
- :title="$options.i18n.tabs.needsTitle"
- :active="isActive($options.tabNames.needs)"
- data-testid="dag-tab"
- lazy
- @click="navigateTo($options.tabNames.needs)"
- >
- <router-view />
- </gl-tab>
- <gl-tab
- :active="isActive($options.tabNames.jobs)"
- data-testid="jobs-tab"
- lazy
- @click="navigateTo($options.tabNames.jobs)"
- >
- <template #title>
- <span class="gl-mr-2">{{ $options.i18n.tabs.jobsTitle }}</span>
- <gl-badge size="sm" data-testid="builds-counter">{{ totalJobCount }}</gl-badge>
- </template>
- <router-view />
- </gl-tab>
- <gl-tab
- v-if="showFailedJobsTab"
- :title="$options.i18n.tabs.failedJobsTitle"
- :active="isActive($options.tabNames.failures)"
- data-testid="failed-jobs-tab"
- lazy
- @click="failedJobsTabClick"
- >
- <template #title>
- <span class="gl-mr-2">{{ $options.i18n.tabs.failedJobsTitle }}</span>
- <gl-badge size="sm" data-testid="failed-builds-counter">{{ failedJobsCount }}</gl-badge>
- </template>
- <router-view />
- </gl-tab>
- <gl-tab
- :active="isActive($options.tabNames.tests)"
- data-testid="tests-tab"
- lazy
- @click="testsTabClick"
- >
- <template #title>
- <span class="gl-mr-2">{{ $options.i18n.tabs.testsTitle }}</span>
- <gl-badge size="sm" data-testid="tests-counter">{{ testsCount }}</gl-badge>
- </template>
- <router-view />
- </gl-tab>
- <slot></slot>
- </gl-tabs>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue
deleted file mode 100644
index 3bbdfc73e1b..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue
+++ /dev/null
@@ -1,53 +0,0 @@
-<script>
-import { GlEmptyState } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
-import PipelinesCiTemplates from './empty_state/pipelines_ci_templates.vue';
-import IosTemplates from './empty_state/ios_templates.vue';
-
-export default {
- i18n: {
- noCiDescription: s__('Pipelines|This project is not currently set up to run pipelines.'),
- },
- name: 'PipelinesEmptyState',
- components: {
- GlEmptyState,
- GitlabExperiment,
- PipelinesCiTemplates,
- IosTemplates,
- },
- props: {
- emptyStateSvgPath: {
- type: String,
- required: true,
- },
- canSetCi: {
- type: Boolean,
- required: true,
- },
- registrationToken: {
- type: String,
- required: false,
- default: null,
- },
- },
-};
-</script>
-<template>
- <div>
- <gitlab-experiment v-if="canSetCi" name="ios_specific_templates">
- <template #control>
- <pipelines-ci-templates />
- </template>
- <template #candidate>
- <ios-templates :registration-token="registrationToken" />
- </template>
- </gitlab-experiment>
- <gl-empty-state
- v-else
- title=""
- :svg-path="emptyStateSvgPath"
- :description="$options.i18n.noCiDescription"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ios_templates.vue b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ios_templates.vue
deleted file mode 100644
index 5208f9a3ce7..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ios_templates.vue
+++ /dev/null
@@ -1,220 +0,0 @@
-<script>
-import { GlButton, GlCard, GlSprintf, GlLink, GlPopover, GlModalDirective } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { mergeUrlParams, DOCS_URL } from '~/lib/utils/url_utility';
-import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
-import apolloProvider from '~/pipelines/graphql/provider';
-import CiTemplates from './ci_templates.vue';
-
-export default {
- components: {
- GlButton,
- GlCard,
- GlSprintf,
- GlLink,
- GlPopover,
- RunnerInstructionsModal,
- CiTemplates,
- },
- directives: {
- GlModalDirective,
- },
- inject: ['pipelineEditorPath', 'iosRunnersAvailable'],
- props: {
- registrationToken: {
- type: String,
- required: false,
- default: null,
- },
- },
- apolloProvider,
- iOSTemplateName: 'iOS-Fastlane',
- modalId: 'runner-instructions-modal',
- runnerDocsLink: `${DOCS_URL}/runner/install/osx`,
- whatElseLink: helpPagePath('ci/index.md'),
- i18n: {
- title: s__('Pipelines|Get started with GitLab CI/CD'),
- subtitle: s__('Pipelines|Building for iOS?'),
- explanation: s__("Pipelines|We'll walk you through how to deploy to iOS in two easy steps."),
- runnerSetupTitle: s__('Pipelines|1. Set up a runner'),
- runnerSetupButton: s__('Pipelines|Set up a runner'),
- runnerSetupBodyUnfinished: s__(
- 'Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline.',
- ),
- runnerSetupBodyFinished: s__(
- 'Pipelines|You have runners available to run your job now. No need to do anything else.',
- ),
- runnerSetupPopoverTitle: s__(
- "Pipelines|Let's get that runner set up! %{emojiStart}tada%{emojiEnd}",
- ),
- runnerSetupPopoverBodyLine1: s__(
- 'Pipelines|Follow these instructions to install GitLab Runner on macOS.',
- ),
- runnerSetupPopoverBodyLine2: s__(
- 'Pipelines|Need more information to set up your runner? %{linkStart}Check out our documentation%{linkEnd}.',
- ),
- configurePipelineTitle: s__('Pipelines|2. Configure deployment pipeline'),
- configurePipelineBody: s__("Pipelines|We'll guide you through a simple pipeline set-up."),
- configurePipelineButton: s__('Pipelines|Configure pipeline'),
- noWalkthroughTitle: s__("Pipelines|Don't need a guide? Jump in right away with a template."),
- noWalkthroughExplanation: s__('Pipelines|Based on your project, we recommend this template:'),
- notBuildingForIos: s__(
- "Pipelines|Not building for iOS or not what you're looking for? %{linkStart}See what else%{linkEnd} GitLab CI/CD has to offer.",
- ),
- },
- data() {
- return {
- isModalShown: false,
- isPopoverShown: false,
- isRunnerSetupFinished: this.iosRunnersAvailable,
- popoverTarget: `${this.$options.modalId}___BV_modal_content_`,
- configurePipelineLink: mergeUrlParams(
- { template: this.$options.iOSTemplateName },
- this.pipelineEditorPath,
- ),
- };
- },
- computed: {
- runnerSetupBodyText() {
- return this.iosRunnersAvailable
- ? this.$options.i18n.runnerSetupBodyFinished
- : this.$options.i18n.runnerSetupBodyUnfinished;
- },
- },
- methods: {
- showModal() {
- this.isModalShown = true;
- },
- hideModal() {
- this.togglePopover();
- this.isRunnerSetupFinished = true;
- },
- togglePopover() {
- this.isPopoverShown = !this.isPopoverShown;
- },
- },
-};
-</script>
-
-<template>
- <div>
- <h2 class="gl-font-size-h2 gl-text-gray-900">{{ $options.i18n.title }}</h2>
- <h3 class="gl-font-lg gl-text-gray-900 gl-mt-1">{{ $options.i18n.subtitle }}</h3>
- <p>{{ $options.i18n.explanation }}</p>
-
- <div class="gl-lg-display-flex">
- <div class="gl-lg-display-flex gl-lg-w-25p gl-lg-pr-4 gl-mb-4">
- <gl-card body-class="gl-display-flex gl-flex-grow-1">
- <div
- class="gl-display-flex gl-flex-grow-1 gl-flex-direction-column gl-justify-content-space-between gl-align-items-flex-start"
- >
- <div>
- <div class="gl-py-5">
- <gl-emoji
- v-show="isRunnerSetupFinished"
- class="gl-font-size-h2-xl"
- data-name="white_check_mark"
- data-testid="runner-setup-marked-completed"
- />
- <gl-emoji
- v-show="!isRunnerSetupFinished"
- class="gl-font-size-h2-xl"
- data-name="tools"
- data-testid="runner-setup-marked-todo"
- />
- </div>
- <span class="gl-text-gray-800 gl-font-weight-bold">
- {{ $options.i18n.runnerSetupTitle }}
- </span>
- <p class="gl-font-sm gl-mt-3">{{ runnerSetupBodyText }}</p>
- </div>
-
- <gl-button
- v-if="!iosRunnersAvailable"
- v-gl-modal-directive="$options.modalId"
- category="primary"
- variant="confirm"
- @click="showModal"
- >
- {{ $options.i18n.runnerSetupButton }}
- </gl-button>
- <runner-instructions-modal
- v-if="isModalShown"
- :modal-id="$options.modalId"
- :registration-token="registrationToken"
- default-platform-name="osx"
- @shown="togglePopover"
- @hide="hideModal"
- />
- <gl-popover
- v-if="isPopoverShown"
- :show="true"
- :show-close-button="true"
- :target="popoverTarget"
- triggers="manual"
- placement="left"
- fallback-placement="clockwise"
- >
- <template #title>
- <gl-sprintf :message="$options.i18n.runnerSetupPopoverTitle">
- <template #emoji="{ content }">
- <gl-emoji class="gl-ml-2" :data-name="content" />
- </template>
- </gl-sprintf>
- </template>
- <div class="gl-mb-5">
- {{ $options.i18n.runnerSetupPopoverBodyLine1 }}
- </div>
- <gl-sprintf :message="$options.i18n.runnerSetupPopoverBodyLine2">
- <template #link="{ content }">
- <gl-link :href="$options.runnerDocsLink" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </gl-popover>
- </div>
- </gl-card>
- </div>
- <div class="gl-lg-display-flex gl-lg-w-25p gl-lg-pr-4 gl-mb-4">
- <gl-card body-class="gl-display-flex gl-flex-grow-1">
- <div
- class="gl-display-flex gl-flex-grow-1 gl-flex-direction-column gl-justify-content-space-between gl-align-items-flex-start"
- >
- <div>
- <div class="gl-py-5"><gl-emoji class="gl-font-size-h2-xl" data-name="tools" /></div>
- <span class="gl-text-gray-800 gl-font-weight-bold">
- {{ $options.i18n.configurePipelineTitle }}
- </span>
- <p class="gl-font-sm gl-mt-3">{{ $options.i18n.configurePipelineBody }}</p>
- </div>
-
- <gl-button
- :disabled="!isRunnerSetupFinished"
- category="primary"
- variant="confirm"
- data-testid="configure-pipeline-link"
- :href="configurePipelineLink"
- >
- {{ $options.i18n.configurePipelineButton }}
- </gl-button>
- </div>
- </gl-card>
- </div>
- </div>
- <h3 class="gl-font-lg gl-text-gray-900 gl-mt-5">{{ $options.i18n.noWalkthroughTitle }}</h3>
- <p>{{ $options.i18n.noWalkthroughExplanation }}</p>
- <ci-templates
- :filter-templates="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [
- $options.iOSTemplateName,
- ] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
- :disabled="!isRunnerSetupFinished"
- />
- <p>
- <gl-sprintf :message="$options.i18n.notBuildingForIos">
- <template #link="{ content }">
- <gl-link :href="$options.whatElseLink">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/failed_job_details.vue b/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/failed_job_details.vue
deleted file mode 100644
index edf4cc87a87..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/failed_job_details.vue
+++ /dev/null
@@ -1,165 +0,0 @@
-<script>
-import { GlButton, GlIcon, GlLink, GlTooltip } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import { __, s__, sprintf } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import SafeHtml from '~/vue_shared/directives/safe_html';
-import { BRIDGE_KIND } from '~/pipelines/components/graph/constants';
-import RetryMrFailedJobMutation from '../../../graphql/mutations/retry_mr_failed_job.mutation.graphql';
-
-export default {
- components: {
- CiIcon,
- GlButton,
- GlIcon,
- GlLink,
- GlTooltip,
- },
- directives: {
- SafeHtml,
- },
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- isHovered: false,
- isJobLogVisible: false,
- isLoadingAction: false,
- };
- },
- computed: {
- canReadBuild() {
- return this.job.userPermissions.readBuild;
- },
- canRetryJob() {
- return this.job.retryable && this.job.userPermissions.updateBuild && !this.isBridgeJob;
- },
- isBridgeJob() {
- return this.job.kind === BRIDGE_KIND;
- },
- jobChevronName() {
- return this.isJobLogVisible ? 'chevron-down' : 'chevron-right';
- },
- jobTrace() {
- if (this.canReadBuild) {
- return this.job?.trace?.htmlSummary || this.$options.i18n.noTraceText;
- }
-
- return this.$options.i18n.cannotReadBuild;
- },
- parsedJobId() {
- return getIdFromGraphQLId(this.job.id);
- },
- tooltipErrorText() {
- return this.isBridgeJob
- ? this.$options.i18n.cannotRetryTrigger
- : this.$options.i18n.cannotRetry;
- },
- tooltipText() {
- return sprintf(this.$options.i18n.jobActionTooltipText, { jobName: this.job.name });
- },
- },
- methods: {
- setActiveRow() {
- this.isHovered = true;
- },
- resetActiveRow() {
- this.isHovered = false;
- },
- async retryJob() {
- try {
- this.isLoadingAction = true;
-
- const {
- data: {
- jobRetry: { errors },
- },
- } = await this.$apollo.mutate({
- mutation: RetryMrFailedJobMutation,
- variables: { id: this.job.id },
- });
-
- if (errors.length > 0) {
- throw new Error(errors[0]);
- }
-
- this.$emit('job-retried', this.job.name);
- } catch (error) {
- createAlert({ message: error?.message || this.$options.i18n.retryError });
- } finally {
- this.isLoadingAction = false;
- }
- },
- toggleJobLog(event) {
- // Do not toggle the log visibility when clicking on a link
- if (event.target.tagName === 'A') {
- return;
- }
- this.isJobLogVisible = !this.isJobLogVisible;
- },
- },
- i18n: {
- cannotReadBuild: s__("Job|You do not have permission to read this job's log."),
- cannotRetry: s__('Job|You do not have permission to run this job again.'),
- cannotRetryTrigger: s__('Job|You cannot rerun trigger jobs from this list.'),
- jobActionTooltipText: s__('Pipelines|Retry %{jobName} Job'),
- noTraceText: s__('Job|No job log'),
- retry: __('Retry'),
- retryError: __('There was an error while retrying this job'),
- },
-};
-</script>
-<template>
- <div class="container-fluid gl-grid-tpl-rows-auto">
- <div
- class="row gl-my-3 gl-cursor-pointer gl-display-flex gl-align-items-center"
- :aria-pressed="isJobLogVisible"
- role="button"
- tabindex="0"
- data-testid="widget-row"
- @click="toggleJobLog"
- @keyup.enter="toggleJobLog"
- @keyup.space="toggleJobLog"
- @mouseover="setActiveRow"
- @mouseout="resetActiveRow"
- >
- <div class="col-6 gl-text-gray-900 gl-font-weight-bold gl-text-left">
- <gl-icon :name="jobChevronName" />
- <ci-icon :status="job.detailedStatus" />
- {{ job.name }}
- </div>
- <div class="col-2 gl-text-left">{{ job.stage.name }}</div>
- <div class="col-2 gl-text-left">
- <gl-link :href="job.detailedStatus.detailsPath">#{{ parsedJobId }}</gl-link>
- </div>
- <gl-tooltip v-if="!canRetryJob" :target="() => $refs.retryBtn" placement="top">
- {{ tooltipErrorText }}
- </gl-tooltip>
- <div class="col-2 gl-text-right">
- <span ref="retryBtn">
- <gl-button
- :disabled="!canRetryJob"
- icon="retry"
- category="tertiary"
- :loading="isLoadingAction"
- :title="$options.i18n.retry"
- :aria-label="$options.i18n.retry"
- @click.stop="retryJob"
- />
- </span>
- </div>
- </div>
- <div v-if="isJobLogVisible" class="row">
- <pre
- v-safe-html="jobTrace"
- class="gl-bg-gray-900 gl-text-white gl-w-full"
- data-testid="job-log"
- ></pre>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/failed_jobs_list.vue b/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/failed_jobs_list.vue
deleted file mode 100644
index 2c5aa84bc4f..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/failed_jobs_list.vue
+++ /dev/null
@@ -1,179 +0,0 @@
-<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import { __, s__, sprintf } from '~/locale';
-import { getQueryHeaders } from '~/pipelines/components/graph/utils';
-import getPipelineFailedJobs from '../../../graphql/queries/get_pipeline_failed_jobs.query.graphql';
-import { graphqlEtagPipelinePath, sortJobsByStatus } from './utils';
-import FailedJobDetails from './failed_job_details.vue';
-
-const POLL_INTERVAL = 10000;
-
-const JOB_ID_HEADER = __('ID');
-const JOB_NAME_HEADER = __('Name');
-const STAGE_HEADER = __('Stage');
-
-export default {
- components: {
- GlLoadingIcon,
- FailedJobDetails,
- },
- inject: ['graphqlPath'],
- props: {
- failedJobsCount: {
- required: true,
- type: Number,
- },
- isPipelineActive: {
- required: true,
- type: Boolean,
- },
- pipelineIid: {
- type: Number,
- required: true,
- },
- projectPath: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- failedJobs: [],
- isActive: false,
- isLoadingMore: false,
- };
- },
- apollo: {
- failedJobs: {
- context() {
- return getQueryHeaders(this.graphqlResourceEtag);
- },
- query: getPipelineFailedJobs,
- pollInterval: POLL_INTERVAL,
- variables() {
- return {
- fullPath: this.projectPath,
- pipelineIid: this.pipelineIid,
- };
- },
- update(data) {
- const jobs = data?.project?.pipeline?.jobs?.nodes || [];
- return sortJobsByStatus(jobs);
- },
- result({ data }) {
- const pipeline = data?.project?.pipeline;
-
- if (pipeline?.jobs?.count) {
- this.$emit('failed-jobs-count', pipeline.jobs.count);
- this.isActive = pipeline.active;
- }
- },
- error(e) {
- createAlert({ message: e?.message || this.$options.i18n.fetchError, variant: 'danger' });
- },
- },
- },
- computed: {
- graphqlResourceEtag() {
- return graphqlEtagPipelinePath(this.graphqlPath, this.pipelineIid);
- },
- hasFailedJobs() {
- return this.failedJobs.length > 0;
- },
- isInitialLoading() {
- return this.isLoading && !this.isLoadingMore;
- },
- isLoading() {
- return this.$apollo.queries.failedJobs.loading;
- },
- },
- watch: {
- isPipelineActive(flag) {
- // Turn polling on and off based on REST actions
- // By refetching jobs, we will get the graphql `active`
- // field to update properly and cascade the polling changes
- this.refetchJobs();
- this.handlePolling(flag);
- },
- isActive(flag) {
- this.handlePolling(flag);
- },
- failedJobsCount(count) {
- // If the REST data is updated first, we force a refetch
- // to keep them in sync
- if (this.failedJobs.length !== count) {
- this.$apollo.queries.failedJobs.refetch();
- }
- },
- },
- mounted() {
- if (!this.isActive && !this.isPipelineActive) {
- this.handlePolling(false);
- }
- },
- methods: {
- handlePolling(isActive) {
- // If the pipeline status has changed and the widget is not expanded,
- // We start polling.
- if (isActive) {
- this.$apollo.queries.failedJobs.startPolling(POLL_INTERVAL);
- } else {
- this.$apollo.queries.failedJobs.stopPolling();
- }
- },
- async retryJob(jobName) {
- await this.refetchJobs();
-
- this.$toast.show(sprintf(this.$options.i18n.retriedJobsSuccess, { jobName }));
- },
- async refetchJobs() {
- this.isLoadingMore = true;
-
- try {
- await this.$apollo.queries.failedJobs.refetch();
- } catch {
- createAlert(this.$options.i18n.fetchError);
- } finally {
- this.isLoadingMore = false;
- }
- },
- },
- columns: [
- { text: JOB_NAME_HEADER, class: 'col-6' },
- { text: STAGE_HEADER, class: 'col-2' },
- { text: JOB_ID_HEADER, class: 'col-2' },
- ],
- i18n: {
- fetchError: __('There was a problem fetching failed jobs'),
- noFailedJobs: s__('Pipeline|No failed jobs in this pipeline 🎉'),
- retriedJobsSuccess: __('%{jobName} job is being retried'),
- },
-};
-</script>
-
-<template>
- <div>
- <gl-loading-icon v-if="isInitialLoading" class="gl-p-4" />
- <div v-else-if="!hasFailedJobs" class="gl-p-4">{{ $options.i18n.noFailedJobs }}</div>
- <div v-else class="container-fluid gl-grid-tpl-rows-auto">
- <div class="row gl-my-4 gl-text-gray-900">
- <div
- v-for="col in $options.columns"
- :key="col.text"
- class="gl-font-weight-bold gl-text-left"
- :class="col.class"
- data-testid="header"
- >
- {{ col.text }}
- </div>
- </div>
- </div>
- <failed-job-details
- v-for="job in failedJobs"
- :key="job.id"
- :job="job"
- @job-retried="retryJob"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget.vue b/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget.vue
deleted file mode 100644
index 60c429459bf..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget.vue
+++ /dev/null
@@ -1,121 +0,0 @@
-<script>
-import { GlButton, GlCard, GlIcon, GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
-import { __, s__, sprintf } from '~/locale';
-import FailedJobsList from './failed_jobs_list.vue';
-
-export default {
- components: {
- GlButton,
- GlCard,
- GlIcon,
- GlLink,
- GlPopover,
- GlSprintf,
- FailedJobsList,
- },
- inject: ['fullPath'],
- props: {
- failedJobsCount: {
- required: true,
- type: Number,
- },
- isPipelineActive: {
- required: true,
- type: Boolean,
- },
- pipelineIid: {
- required: true,
- type: Number,
- },
- pipelinePath: {
- required: true,
- type: String,
- },
- projectPath: {
- required: true,
- type: String,
- },
- },
- data() {
- return {
- currentFailedJobsCount: this.failedJobsCount,
- isActive: false,
- isExpanded: false,
- };
- },
- computed: {
- bodyClasses() {
- return this.isExpanded ? '' : 'gl-display-none';
- },
- failedJobsCountText() {
- return sprintf(this.$options.i18n.failedJobsLabel, { count: this.currentFailedJobsCount });
- },
- iconName() {
- return this.isExpanded ? 'chevron-down' : 'chevron-right';
- },
- popoverId() {
- return `popover-${this.pipelineIid}`;
- },
- },
- watch: {
- failedJobsCount(val) {
- this.currentFailedJobsCount = val;
- },
- },
- methods: {
- setFailedJobsCount(count) {
- this.currentFailedJobsCount = count;
- },
- toggleWidget() {
- this.isExpanded = !this.isExpanded;
- },
- },
- i18n: {
- additionalInfoPopover: s__(
- 'Pipelines|You will see a maximum of 100 jobs in this list. To view all failed jobs, %{linkStart}go to the details page%{linkEnd} of this pipeline.',
- ),
- additionalInfoTitle: __('Limitation on this view'),
- failedJobsLabel: __('Failed jobs (%{count})'),
- },
-};
-</script>
-<template>
- <gl-card
- class="gl-new-card"
- :class="{ 'gl-border-white gl-hover-border-gray-100': !isExpanded }"
- header-class="gl-new-card-header gl-px-3 gl-py-3"
- body-class="gl-new-card-body"
- data-testid="failed-jobs-card"
- :aria-expanded="isExpanded.toString()"
- >
- <template #header>
- <gl-button
- variant="link"
- class="gl-text-gray-700! gl-font-weight-semibold"
- @click="toggleWidget"
- >
- <gl-icon :name="iconName" />
- {{ failedJobsCountText }}
- <gl-icon :id="popoverId" name="information-o" class="gl-ml-2" />
- <gl-popover :target="popoverId" placement="top">
- <template #title> {{ $options.i18n.additionalInfoTitle }} </template>
- <slot>
- <gl-sprintf :message="$options.i18n.additionalInfoPopover">
- <template #link="{ content }">
- <gl-link class="gl-font-sm" :href="pipelinePath">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </slot>
- </gl-popover>
- </gl-button>
- </template>
- <failed-jobs-list
- v-if="isExpanded"
- :failed-jobs-count="failedJobsCount"
- :is-pipeline-active="isPipelineActive"
- :pipeline-iid="pipelineIid"
- :project-path="projectPath"
- @failed-jobs-count="setFailedJobsCount"
- />
- </gl-card>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/utils.js b/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/utils.js
deleted file mode 100644
index 2d0c467c54f..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/failure_widget/utils.js
+++ /dev/null
@@ -1,19 +0,0 @@
-export const isFailedJob = (job = {}) => {
- return job?.detailedStatus?.group === 'failed' || false;
-};
-
-export const sortJobsByStatus = (jobs = []) => {
- const newJobs = [...jobs];
-
- return newJobs.sort((a) => {
- if (isFailedJob(a)) {
- return -1;
- }
-
- return 1;
- });
-};
-
-export const graphqlEtagPipelinePath = (graphqlPath, pipelineId) => {
- return `${graphqlPath}pipelines/id/${pipelineId}`;
-};
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_labels.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_labels.vue
deleted file mode 100644
index 40b2454b8c1..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_labels.vue
+++ /dev/null
@@ -1,170 +0,0 @@
-<script>
-import { GlLink, GlPopover, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { SCHEDULE_ORIGIN } from '../../constants';
-
-export default {
- components: {
- GlBadge,
- GlLink,
- GlPopover,
- GlSprintf,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- inject: {
- targetProjectFullPath: {
- default: '',
- },
- },
- props: {
- pipeline: {
- type: Object,
- required: true,
- },
- pipelineScheduleUrl: {
- type: String,
- required: true,
- },
- },
- computed: {
- isScheduled() {
- return this.pipeline.source === SCHEDULE_ORIGIN;
- },
- isInFork() {
- return Boolean(
- this.targetProjectFullPath &&
- this.pipeline?.project?.full_path !== `/${this.targetProjectFullPath}`,
- );
- },
- autoDevopsTagId() {
- return `pipeline-url-autodevops-${this.pipeline.id}`;
- },
- autoDevopsHelpPath() {
- return helpPagePath('topics/autodevops/index.md');
- },
- },
-};
-</script>
-<template>
- <div class="label-container gl-mt-1">
- <gl-badge
- v-if="isScheduled"
- v-gl-tooltip
- :href="pipelineScheduleUrl"
- target="__blank"
- :title="__('This pipeline was triggered by a schedule.')"
- variant="info"
- size="sm"
- data-testid="pipeline-url-scheduled"
- >{{ __('Scheduled') }}</gl-badge
- >
- <gl-badge
- v-if="pipeline.flags.latest"
- v-gl-tooltip
- :title="__('Latest pipeline for the most recent commit on this branch')"
- variant="success"
- size="sm"
- data-testid="pipeline-url-latest"
- >{{ __('latest') }}</gl-badge
- >
- <gl-badge
- v-if="pipeline.flags.merge_train_pipeline"
- v-gl-tooltip
- :title="
- s__(
- 'Pipeline|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch.',
- )
- "
- variant="info"
- size="sm"
- data-testid="pipeline-url-train"
- >{{ s__('Pipeline|merge train') }}</gl-badge
- >
- <gl-badge
- v-if="pipeline.flags.yaml_errors"
- v-gl-tooltip
- :title="pipeline.yaml_errors"
- variant="danger"
- size="sm"
- data-testid="pipeline-url-yaml"
- >{{ __('yaml invalid') }}</gl-badge
- >
- <gl-badge
- v-if="pipeline.flags.failure_reason"
- v-gl-tooltip
- :title="pipeline.failure_reason"
- variant="danger"
- size="sm"
- data-testid="pipeline-url-failure"
- >{{ __('error') }}</gl-badge
- >
- <template v-if="pipeline.flags.auto_devops">
- <gl-link
- :id="autoDevopsTagId"
- tabindex="0"
- data-testid="pipeline-url-autodevops"
- role="button"
- >
- <gl-badge variant="info" size="sm">
- {{ __('Auto DevOps') }}
- </gl-badge>
- </gl-link>
- <gl-popover :target="autoDevopsTagId" triggers="focus" placement="top">
- <template #title>
- <div class="gl-font-weight-normal gl-line-height-normal">
- <gl-sprintf
- :message="
- __(
- 'This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}',
- )
- "
- >
- <template #strong="{ content }">
- <b>{{ content }}</b>
- </template>
- </gl-sprintf>
- </div>
- </template>
- <gl-link
- :href="autoDevopsHelpPath"
- data-testid="pipeline-url-autodevops-link"
- target="_blank"
- >
- {{ __('Learn more about Auto DevOps') }}
- </gl-link>
- </gl-popover>
- </template>
-
- <gl-badge
- v-if="pipeline.flags.stuck"
- variant="warning"
- size="sm"
- data-testid="pipeline-url-stuck"
- >{{ __('stuck') }}</gl-badge
- >
- <gl-badge
- v-if="pipeline.flags.detached_merge_request_pipeline"
- v-gl-tooltip
- :title="
- s__(
- `Pipeline|This pipeline ran on the contents of this merge request's source branch, not the target branch.`,
- )
- "
- variant="info"
- size="sm"
- data-testid="pipeline-url-detached"
- >{{ s__('Pipeline|merge request') }}</gl-badge
- >
- <gl-badge
- v-if="isInFork"
- v-gl-tooltip
- :title="__('Pipeline ran in fork of project')"
- variant="info"
- size="sm"
- data-testid="pipeline-url-fork"
- >{{ __('fork') }}</gl-badge
- >
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_multi_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_multi_actions.vue
deleted file mode 100644
index 747d94d92f2..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_multi_actions.vue
+++ /dev/null
@@ -1,172 +0,0 @@
-<script>
-import {
- GlAlert,
- GlDropdown,
- GlDropdownItem,
- GlSearchBoxByType,
- GlLoadingIcon,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import fuzzaldrinPlus from 'fuzzaldrin-plus';
-import axios from '~/lib/utils/axios_utils';
-import { __, s__ } from '~/locale';
-import Tracking from '~/tracking';
-import { TRACKING_CATEGORIES } from '../../constants';
-
-export const i18n = {
- downloadArtifacts: __('Download artifacts'),
- artifactsFetchErrorMessage: s__('Pipelines|Could not load artifacts.'),
- artifactsFetchWarningMessage: s__(
- 'Pipelines|Failed to update. Please reload page to update the list of artifacts.',
- ),
- emptyArtifactsMessage: __('No artifacts found'),
-};
-
-export default {
- i18n,
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- GlAlert,
- GlDropdown,
- GlDropdownItem,
- GlSearchBoxByType,
- GlLoadingIcon,
- },
- mixins: [Tracking.mixin()],
- inject: {
- artifactsEndpoint: {
- default: '',
- },
- artifactsEndpointPlaceholder: {
- default: '',
- },
- },
- props: {
- pipelineId: {
- type: Number,
- required: true,
- },
- },
- data() {
- return {
- artifacts: [],
- hasError: false,
- isLoading: false,
- searchQuery: '',
- isNewPipeline: false,
- };
- },
- computed: {
- hasArtifacts() {
- return this.artifacts.length > 0;
- },
- filteredArtifacts() {
- return this.searchQuery.length > 0
- ? fuzzaldrinPlus.filter(this.artifacts, this.searchQuery, { key: 'name' })
- : this.artifacts;
- },
- },
- watch: {
- pipelineId() {
- this.isNewPipeline = true;
- },
- },
- methods: {
- fetchArtifacts() {
- // refactor tracking based on action once this dropdown supports
- // actions other than artifacts
- this.track('click_artifacts_dropdown', { label: TRACKING_CATEGORIES.table });
-
- // Preserve the last good list and present it if a request fails
- const oldArtifacts = [...this.artifacts];
- this.artifacts = [];
-
- this.hasError = false;
- this.isLoading = true;
-
- // Replace the placeholder with the ID of the pipeline we are viewing
- const endpoint = this.artifactsEndpoint.replace(
- this.artifactsEndpointPlaceholder,
- this.pipelineId,
- );
- return axios
- .get(endpoint)
- .then(({ data }) => {
- this.artifacts = data.artifacts;
- this.isNewPipeline = false;
- })
- .catch(() => {
- this.hasError = true;
- if (!this.isNewPipeline) {
- this.artifacts = oldArtifacts;
- }
- })
- .finally(() => {
- this.isLoading = false;
- });
- },
- handleDropdownShown() {
- if (this.hasArtifacts) {
- this.$refs.searchInput.focusInput();
- }
- },
- },
-};
-</script>
-<template>
- <gl-dropdown
- v-gl-tooltip
- :title="$options.i18n.downloadArtifacts"
- :text="$options.i18n.downloadArtifacts"
- :aria-label="$options.i18n.downloadArtifacts"
- :header-text="$options.i18n.downloadArtifacts"
- icon="download"
- data-testid="pipeline-multi-actions-dropdown"
- right
- lazy
- text-sr-only
- @show="fetchArtifacts"
- @shown="handleDropdownShown"
- >
- <gl-alert v-if="hasError && !hasArtifacts" variant="danger" :dismissible="false">
- {{ $options.i18n.artifactsFetchErrorMessage }}
- </gl-alert>
-
- <gl-loading-icon v-else-if="isLoading" size="sm" />
-
- <gl-dropdown-item v-else-if="!hasArtifacts" data-testid="artifacts-empty-message">
- {{ $options.i18n.emptyArtifactsMessage }}
- </gl-dropdown-item>
-
- <template #header>
- <gl-search-box-by-type v-if="hasArtifacts" ref="searchInput" v-model.trim="searchQuery" />
- </template>
-
- <gl-dropdown-item
- v-for="(artifact, i) in filteredArtifacts"
- :key="i"
- :href="artifact.path"
- rel="nofollow"
- download
- class="gl-word-break-word"
- data-testid="artifact-item"
- >
- {{ artifact.name }}
- </gl-dropdown-item>
-
- <template #footer>
- <gl-dropdown-item
- v-if="hasError && hasArtifacts"
- class="gl-list-style-none"
- disabled
- data-testid="artifacts-fetch-warning"
- >
- <span class="gl-font-sm">
- {{ $options.i18n.artifactsFetchWarningMessage }}
- </span>
- </gl-dropdown-item>
- </template>
- </gl-dropdown>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue
deleted file mode 100644
index caeee7edefe..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue
+++ /dev/null
@@ -1,113 +0,0 @@
-<script>
-import { GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui';
-import Tracking from '~/tracking';
-import eventHub from '../../event_hub';
-import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL, TRACKING_CATEGORIES } from '../../constants';
-import PipelineMultiActions from './pipeline_multi_actions.vue';
-import PipelinesManualActions from './pipelines_manual_actions.vue';
-
-export default {
- BUTTON_TOOLTIP_RETRY,
- BUTTON_TOOLTIP_CANCEL,
- directives: {
- GlTooltip: GlTooltipDirective,
- GlModalDirective,
- },
- components: {
- GlButton,
- PipelineMultiActions,
- PipelinesManualActions,
- },
- mixins: [Tracking.mixin()],
- props: {
- pipeline: {
- type: Object,
- required: true,
- },
- cancelingPipeline: {
- type: Number,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- isRetrying: false,
- };
- },
- computed: {
- hasActions() {
- return (
- this.pipeline?.details?.has_manual_actions || this.pipeline?.details?.has_scheduled_actions
- );
- },
- isCancelling() {
- return this.cancelingPipeline === this.pipeline.id;
- },
- },
- watch: {
- pipeline() {
- this.isRetrying = false;
- },
- },
- methods: {
- handleCancelClick() {
- this.trackClick('click_cancel_button');
- eventHub.$emit('openConfirmationModal', {
- pipeline: this.pipeline,
- endpoint: this.pipeline.cancel_path,
- });
- },
- handleRetryClick() {
- this.isRetrying = true;
- this.trackClick('click_retry_button');
- eventHub.$emit('retryPipeline', this.pipeline.retry_path);
- },
- trackClick(action) {
- this.track(action, { label: TRACKING_CATEGORIES.table });
- },
- },
-};
-</script>
-
-<template>
- <div class="gl-text-right">
- <div class="btn-group">
- <pipelines-manual-actions v-if="hasActions" :iid="pipeline.iid" />
-
- <gl-button
- v-if="pipeline.flags.retryable"
- v-gl-tooltip.hover
- :aria-label="$options.BUTTON_TOOLTIP_RETRY"
- :title="$options.BUTTON_TOOLTIP_RETRY"
- :disabled="isRetrying"
- :loading="isRetrying"
- class="js-pipelines-retry-button"
- data-qa-selector="pipeline_retry_button"
- data-testid="pipelines-retry-button"
- icon="retry"
- variant="default"
- category="secondary"
- @click="handleRetryClick"
- />
-
- <gl-button
- v-if="pipeline.flags.cancelable"
- v-gl-tooltip.hover
- v-gl-modal-directive="'confirmation-modal'"
- :aria-label="$options.BUTTON_TOOLTIP_CANCEL"
- :title="$options.BUTTON_TOOLTIP_CANCEL"
- :loading="isCancelling"
- :disabled="isCancelling"
- icon="cancel"
- variant="danger"
- category="primary"
- class="js-pipelines-cancel-button gl-ml-1"
- data-testid="pipelines-cancel-button"
- @click="handleCancelClick"
- />
-
- <pipeline-multi-actions :pipeline-id="pipeline.id" />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
deleted file mode 100644
index ff1a01d5037..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
+++ /dev/null
@@ -1,239 +0,0 @@
-<script>
-import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
-import { __ } from '~/locale';
-import Tracking from '~/tracking';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
-import { ICONS, TRACKING_CATEGORIES } from '../../constants';
-import PipelineLabels from './pipeline_labels.vue';
-
-export default {
- components: {
- GlIcon,
- GlLink,
- PipelineLabels,
- TooltipOnTruncate,
- UserAvatarLink,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [Tracking.mixin()],
- props: {
- pipeline: {
- type: Object,
- required: true,
- },
- pipelineScheduleUrl: {
- type: String,
- required: true,
- },
- pipelineKey: {
- type: String,
- required: true,
- },
- refClass: {
- type: String,
- required: false,
- default: '',
- },
- },
- computed: {
- mergeRequestRef() {
- return this.pipeline?.merge_request;
- },
- commitRef() {
- return this.pipeline?.ref;
- },
- commitTag() {
- return this.commitRef?.tag;
- },
- commitUrl() {
- return this.pipeline?.commit?.commit_path;
- },
- commitShortSha() {
- return this.pipeline?.commit?.short_id;
- },
- refUrl() {
- return this.commitRef?.ref_url || this.commitRef?.path;
- },
- tooltipTitle() {
- return this.mergeRequestRef?.title || this.commitRef?.name;
- },
- commitAuthor() {
- let commitAuthorInformation;
- const pipelineCommit = this.pipeline?.commit;
- const pipelineCommitAuthor = pipelineCommit?.author;
-
- if (!pipelineCommit) {
- return null;
- }
-
- // 1. person who is an author of a commit might be a GitLab user
- if (pipelineCommitAuthor) {
- // 2. if person who is an author of a commit is a GitLab user
- // they can have a GitLab avatar
- if (pipelineCommitAuthor?.avatar_url) {
- commitAuthorInformation = pipelineCommitAuthor;
-
- // 3. If GitLab user does not have avatar, they might have a Gravatar
- } else if (pipelineCommit.author_gravatar_url) {
- commitAuthorInformation = {
- ...pipelineCommitAuthor,
- avatar_url: pipelineCommit.author_gravatar_url,
- };
- }
- // 4. If committer is not a GitLab User, they can have a Gravatar
- } else {
- commitAuthorInformation = {
- avatar_url: pipelineCommit.author_gravatar_url,
- path: `mailto:${pipelineCommit.author_email}`,
- username: pipelineCommit.author_name,
- };
- }
-
- return commitAuthorInformation;
- },
- commitIcon() {
- let name = '';
-
- if (this.commitTag) {
- name = ICONS.TAG;
- } else if (this.mergeRequestRef) {
- name = ICONS.MR;
- } else {
- name = ICONS.BRANCH;
- }
-
- return name;
- },
- commitIconTooltipTitle() {
- switch (this.commitIcon) {
- case ICONS.TAG:
- return __('Tag');
- case ICONS.MR:
- return __('Merge Request');
- default:
- return __('Branch');
- }
- },
- commitTitle() {
- return this.pipeline?.commit?.title;
- },
- pipelineName() {
- return this.pipeline?.name;
- },
- },
- methods: {
- trackClick(action) {
- this.track(action, { label: TRACKING_CATEGORIES.table });
- },
- },
-};
-</script>
-<template>
- <div class="pipeline-tags" data-testid="pipeline-url-table-cell">
- <div v-if="pipelineName" class="gl-mb-2" data-testid="pipeline-name-container">
- <span class="gl-display-flex">
- <tooltip-on-truncate
- :title="pipelineName"
- class="gl-flex-grow-1 gl-text-truncate gl-text-gray-900"
- >
- <gl-link
- :href="pipeline.path"
- class="gl-text-blue-600!"
- data-testid="pipeline-url-link"
- >{{ pipelineName }}</gl-link
- >
- </tooltip-on-truncate>
- </span>
- </div>
-
- <div v-if="!pipelineName" class="commit-title gl-mb-2" data-testid="commit-title-container">
- <span v-if="commitTitle" class="gl-display-flex">
- <tooltip-on-truncate :title="commitTitle" class="gl-flex-grow-1 gl-text-truncate">
- <gl-link
- :href="commitUrl"
- class="commit-row-message gl-text-blue-600!"
- data-testid="commit-title"
- @click="trackClick('click_commit_title')"
- >{{ commitTitle }}</gl-link
- >
- </tooltip-on-truncate>
- </span>
- <span v-else class="gl-text-gray-500">{{
- __("Can't find HEAD commit for this branch")
- }}</span>
- </div>
- <div class="gl-mb-2">
- <gl-link
- :href="pipeline.path"
- class="gl-mr-1 gl-text-blue-500!"
- data-testid="pipeline-url-link"
- data-qa-selector="pipeline_url_link"
- @click="trackClick('click_pipeline_id')"
- >#{{ pipeline[pipelineKey] }}</gl-link
- >
- <!--Commit row-->
- <div class="gl-display-inline-flex gl-rounded-base gl-px-2 gl-bg-gray-50 gl-text-gray-700">
- <tooltip-on-truncate :title="tooltipTitle" truncate-target="child" placement="top">
- <gl-icon
- v-gl-tooltip
- :name="commitIcon"
- :title="commitIconTooltipTitle"
- :size="12"
- data-testid="commit-icon-type"
- />
- <gl-link
- v-if="mergeRequestRef"
- :href="mergeRequestRef.path"
- class="gl-font-sm gl-font-monospace gl-text-gray-700! gl-hover-text-gray-900!"
- :class="refClass"
- data-testid="merge-request-ref"
- @click="trackClick('click_mr_ref')"
- >{{ mergeRequestRef.iid }}</gl-link
- >
- <gl-link
- v-else
- :href="refUrl"
- class="gl-font-sm gl-font-monospace gl-text-gray-700! gl-hover-text-gray-900!"
- :class="refClass"
- data-testid="commit-ref-name"
- @click="trackClick('click_commit_name')"
- >{{ commitRef.name }}</gl-link
- >
- </tooltip-on-truncate>
- </div>
- <div
- class="gl-display-inline-block gl-rounded-base gl-font-sm gl-px-2 gl-bg-gray-50 gl-text-black-normal"
- >
- <gl-icon
- v-gl-tooltip
- name="commit"
- class="commit-icon gl-mr-1"
- :title="__('Commit')"
- :size="12"
- data-testid="commit-icon"
- />
- <gl-link
- :href="commitUrl"
- class="gl-font-sm gl-font-monospace gl-mr-0 gl-text-gray-700!"
- data-testid="commit-short-sha"
- @click="trackClick('click_commit_sha')"
- >{{ commitShortSha }}</gl-link
- >
- </div>
- <user-avatar-link
- v-if="commitAuthor"
- :link-href="commitAuthor.path"
- :img-src="commitAuthor.avatar_url"
- :img-size="16"
- :img-alt="commitAuthor.name"
- :tooltip-text="commitAuthor.name"
- class="gl-ml-1"
- />
- <!--End of commit row-->
- </div>
- <pipeline-labels :pipeline-schedule-url="pipelineScheduleUrl" :pipeline="pipeline" />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue
deleted file mode 100644
index 574d291a767..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue
+++ /dev/null
@@ -1,449 +0,0 @@
-<!-- eslint-disable vue/multi-word-component-names -->
-<script>
-import { GlEmptyState, GlIcon, GlLoadingIcon, GlCollapsibleListbox } from '@gitlab/ui';
-import { isEqual } from 'lodash';
-import * as Sentry from '@sentry/browser';
-import { createAlert, VARIANT_INFO, VARIANT_WARNING } from '~/alert';
-import { getParameterByName } from '~/lib/utils/url_utility';
-import { __, s__ } from '~/locale';
-import Tracking from '~/tracking';
-import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
-import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
-import { isLoggedIn } from '~/lib/utils/common_utils';
-import setSortPreferenceMutation from '~/issues/list/queries/set_sort_preference.mutation.graphql';
-import {
- ANY_TRIGGER_AUTHOR,
- RAW_TEXT_WARNING,
- FILTER_TAG_IDENTIFIER,
- PipelineKeyOptions,
- TRACKING_CATEGORIES,
-} from '../../constants';
-import PipelinesMixin from '../../mixins/pipelines_mixin';
-import PipelinesService from '../../services/pipelines_service';
-import { validateParams } from '../../utils';
-import EmptyState from './empty_state.vue';
-import NavigationControls from './nav_controls.vue';
-import PipelinesFilteredSearch from './pipelines_filtered_search.vue';
-import PipelinesTableComponent from './pipelines_table.vue';
-
-export default {
- PipelineKeyOptions,
- components: {
- EmptyState,
- GlCollapsibleListbox,
- GlEmptyState,
- GlIcon,
- GlLoadingIcon,
- NavigationTabs,
- NavigationControls,
- PipelinesFilteredSearch,
- PipelinesTableComponent,
- TablePagination,
- },
- mixins: [PipelinesMixin, Tracking.mixin()],
- props: {
- store: {
- type: Object,
- required: true,
- },
- // Can be rendered in 3 different places, with some visual differences
- // Accepts root | child
- // `root` -> main view
- // `child` -> rendered inside MR or Commit View
- viewType: {
- type: String,
- required: false,
- default: 'root',
- },
- endpoint: {
- type: String,
- required: true,
- },
- pipelineScheduleUrl: {
- type: String,
- required: false,
- default: '',
- },
- emptyStateSvgPath: {
- type: String,
- required: true,
- },
- errorStateSvgPath: {
- type: String,
- required: true,
- },
- noPipelinesSvgPath: {
- type: String,
- required: true,
- },
- hasGitlabCi: {
- type: Boolean,
- required: true,
- },
- canCreatePipeline: {
- type: Boolean,
- required: true,
- },
- ciLintPath: {
- type: String,
- required: false,
- default: null,
- },
- resetCachePath: {
- type: String,
- required: false,
- default: null,
- },
- newPipelinePath: {
- type: String,
- required: false,
- default: null,
- },
- projectId: {
- type: String,
- required: true,
- },
- defaultBranchName: {
- type: String,
- required: false,
- default: null,
- },
- params: {
- type: Object,
- required: true,
- },
- registrationToken: {
- type: String,
- required: false,
- default: null,
- },
- defaultVisibilityPipelineIdType: {
- type: String,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- // Start with loading state to avoid a glitch when the empty state will be rendered
- isLoading: true,
- state: this.store.state,
- scope: getParameterByName('scope') || 'all',
- page: getParameterByName('page') || '1',
- requestData: {},
- isResetCacheButtonLoading: false,
- visibilityPipelineIdType: this.defaultVisibilityPipelineIdType,
- };
- },
- stateMap: {
- // with tabs
- loading: 'loading',
- tableList: 'tableList',
- error: 'error',
- emptyTab: 'emptyTab',
-
- // without tabs
- emptyState: 'emptyState',
- },
- scopes: {
- all: 'all',
- finished: 'finished',
- branches: 'branches',
- tags: 'tags',
- },
- computed: {
- /**
- * `hasGitlabCi` handles both internal and external CI.
- * The order on which the checks are made in this method is
- * important to guarantee we handle all the corner cases.
- */
- stateToRender() {
- const { stateMap } = this.$options;
-
- if (this.isLoading) {
- return stateMap.loading;
- }
-
- if (this.hasError) {
- return stateMap.error;
- }
-
- if (this.state.pipelines.length) {
- return stateMap.tableList;
- }
-
- if ((this.scope !== 'all' && this.scope !== null) || this.hasGitlabCi) {
- return stateMap.emptyTab;
- }
-
- return stateMap.emptyState;
- },
- /**
- * Tabs are rendered in all states except empty state.
- * They are not rendered before the first request to avoid a flicker on first load.
- */
- shouldRenderTabs() {
- const { stateMap } = this.$options;
- return (
- this.hasMadeRequest &&
- [stateMap.loading, stateMap.tableList, stateMap.error, stateMap.emptyTab].includes(
- this.stateToRender,
- )
- );
- },
-
- shouldRenderButtons() {
- return (
- (this.newPipelinePath || this.resetCachePath || this.ciLintPath) && this.shouldRenderTabs
- );
- },
-
- shouldRenderPagination() {
- return !this.isLoading && !this.hasError;
- },
-
- emptyTabMessage() {
- if (this.scope === this.$options.scopes.finished) {
- return s__('Pipelines|There are currently no finished pipelines.');
- }
-
- return s__('Pipelines|There are currently no pipelines.');
- },
-
- tabs() {
- const { count } = this.state;
- const { scopes } = this.$options;
-
- return [
- {
- name: __('All'),
- scope: scopes.all,
- count: count.all,
- isActive: this.scope === 'all',
- },
- {
- name: __('Finished'),
- scope: scopes.finished,
- isActive: this.scope === 'finished',
- },
- {
- name: __('Branches'),
- scope: scopes.branches,
- isActive: this.scope === 'branches',
- },
- {
- name: __('Tags'),
- scope: scopes.tags,
- isActive: this.scope === 'tags',
- },
- ];
- },
- validatedParams() {
- return validateParams(this.params);
- },
- selectedPipelineKeyOption() {
- return (
- this.$options.PipelineKeyOptions.find((e) => this.visibilityPipelineIdType === e.value) ||
- this.$options.PipelineKeyOptions[0]
- );
- },
- },
- created() {
- this.service = new PipelinesService(this.endpoint);
- this.requestData = { page: this.page, scope: this.scope, ...this.validatedParams };
- },
- methods: {
- onChangeTab(scope) {
- if (this.scope === scope) {
- return;
- }
-
- let params = {
- scope,
- page: '1',
- };
-
- params = this.onChangeWithFilter(params);
-
- this.updateContent(params);
-
- this.track('click_filter_tabs', { label: TRACKING_CATEGORIES.tabs, property: scope });
- },
- successCallback(resp) {
- // Because we are polling & the user is interacting verify if the response received
- // matches the last request made
- if (isEqual(resp.config.params, this.requestData)) {
- this.store.storeCount(resp.data.count);
- this.store.storePagination(resp.headers);
- this.setCommonData(resp.data.pipelines);
- }
- },
- handleResetRunnersCache(endpoint) {
- this.isResetCacheButtonLoading = true;
-
- this.service
- .postAction(endpoint)
- .then(() => {
- this.isResetCacheButtonLoading = false;
- createAlert({
- message: s__('Pipelines|Project cache successfully reset.'),
- variant: VARIANT_INFO,
- });
- })
- .catch(() => {
- this.isResetCacheButtonLoading = false;
- createAlert({
- message: s__('Pipelines|Something went wrong while cleaning runners cache.'),
- });
- });
- },
- resetRequestData() {
- this.requestData = { page: this.page, scope: this.scope };
- },
- filterPipelines(filters) {
- this.resetRequestData();
-
- filters.forEach((filter) => {
- // do not add Any for username query param, so we
- // can fetch all trigger authors
- if (
- filter.type &&
- filter.value.data !== ANY_TRIGGER_AUTHOR &&
- filter.type !== FILTER_TAG_IDENTIFIER
- ) {
- this.requestData[filter.type] = filter.value.data;
- }
-
- if (filter.type === FILTER_TAG_IDENTIFIER) {
- this.requestData.ref = filter.value.data;
- }
-
- if (!filter.type) {
- createAlert({
- message: RAW_TEXT_WARNING,
- variant: VARIANT_WARNING,
- });
- }
- });
-
- if (filters.length === 0) {
- this.resetRequestData();
- }
-
- this.updateContent({ ...this.requestData, page: '1' });
- },
- changeVisibilityPipelineIDType(idType) {
- this.visibilityPipelineIdType = idType;
- this.saveVisibilityPipelineIDType(idType);
- },
- saveVisibilityPipelineIDType(idType) {
- if (!isLoggedIn()) return;
-
- this.$apollo
- .mutate({
- mutation: setSortPreferenceMutation,
- variables: { input: { visibilityPipelineIdType: idType.toUpperCase() } },
- })
- .then(({ data }) => {
- if (data.userPreferencesUpdate.errors.length) {
- throw new Error(data.userPreferencesUpdate.errors);
- }
- })
- .catch((error) => {
- Sentry.captureException(error);
- });
- },
- },
-};
-</script>
-<template>
- <div class="pipelines-container">
- <div
- v-if="shouldRenderTabs || shouldRenderButtons"
- class="top-area scrolling-tabs-container inner-page-scroll-tabs gl-border-none"
- >
- <div class="fade-left"><gl-icon name="chevron-lg-left" :size="12" /></div>
- <div class="fade-right"><gl-icon name="chevron-lg-right" :size="12" /></div>
-
- <navigation-tabs
- v-if="shouldRenderTabs"
- :tabs="tabs"
- scope="pipelines"
- @onChangeTab="onChangeTab"
- />
-
- <navigation-controls
- v-if="shouldRenderButtons"
- :new-pipeline-path="newPipelinePath"
- :reset-cache-path="resetCachePath"
- :ci-lint-path="ciLintPath"
- :is-reset-cache-button-loading="isResetCacheButtonLoading"
- @resetRunnersCache="handleResetRunnersCache"
- />
- </div>
-
- <div v-if="stateToRender !== $options.stateMap.emptyState" class="gl-display-flex">
- <div class="row-content-block gl-display-flex gl-flex-grow-1 gl-border-b-0">
- <pipelines-filtered-search
- class="gl-display-flex gl-flex-grow-1 gl-mr-4"
- :project-id="projectId"
- :default-branch-name="defaultBranchName"
- :params="validatedParams"
- @filterPipelines="filterPipelines"
- />
- <gl-collapsible-listbox
- v-model="visibilityPipelineIdType"
- data-testid="pipeline-key-collapsible-box"
- :toggle-text="selectedPipelineKeyOption.text"
- :items="$options.PipelineKeyOptions"
- @select="changeVisibilityPipelineIDType"
- />
- </div>
- </div>
-
- <div class="content-list pipelines">
- <gl-loading-icon
- v-if="stateToRender === $options.stateMap.loading"
- :label="s__('Pipelines|Loading Pipelines')"
- size="lg"
- class="prepend-top-20"
- />
-
- <empty-state
- v-else-if="stateToRender === $options.stateMap.emptyState"
- :empty-state-svg-path="emptyStateSvgPath"
- :can-set-ci="canCreatePipeline"
- :registration-token="registrationToken"
- />
-
- <gl-empty-state
- v-else-if="stateToRender === $options.stateMap.error"
- :svg-path="errorStateSvgPath"
- :title="s__('Pipelines|There was an error fetching the pipelines.')"
- :description="s__('Pipelines|Try again in a few moments or contact your support team.')"
- />
-
- <gl-empty-state
- v-else-if="stateToRender === $options.stateMap.emptyTab"
- :svg-path="noPipelinesSvgPath"
- :title="emptyTabMessage"
- />
-
- <div v-else-if="stateToRender === $options.stateMap.tableList">
- <pipelines-table-component
- :pipelines="state.pipelines"
- :pipeline-schedule-url="pipelineScheduleUrl"
- :update-graph-dropdown="updateGraphDropdown"
- :view-type="viewType"
- :pipeline-key-option="selectedPipelineKeyOption"
- />
- </div>
-
- <table-pagination
- v-if="shouldRenderPagination"
- :change="onChangePage"
- :page-info="state.pageInfo"
- />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_artifacts.vue
deleted file mode 100644
index 4452db64b0a..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_artifacts.vue
+++ /dev/null
@@ -1,72 +0,0 @@
-<script>
-import { GlDisclosureDropdown, GlTooltipDirective } from '@gitlab/ui';
-import { __ } from '~/locale';
-
-export const i18n = {
- artifacts: __('Artifacts'),
- artifactSectionHeader: __('Download artifacts'),
-};
-
-export default {
- i18n,
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- GlDisclosureDropdown,
- },
- inject: {
- artifactsEndpoint: {
- default: '',
- },
- artifactsEndpointPlaceholder: {
- default: '',
- },
- },
- props: {
- pipelineId: {
- type: Number,
- required: true,
- },
- artifacts: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- computed: {
- items() {
- return [
- {
- name: this.$options.i18n.artifactSectionHeader,
- items: this.artifacts.map(({ name, path }) => ({
- text: name,
- href: path,
- extraAttrs: {
- download: '',
- rel: 'nofollow',
- },
- })),
- },
- ];
- },
- shouldShowDropdown() {
- return this.artifacts?.length;
- },
- },
-};
-</script>
-<template>
- <gl-disclosure-dropdown
- v-if="shouldShowDropdown"
- v-gl-tooltip
- class="build-artifacts js-pipeline-dropdown-download"
- :title="$options.i18n.artifacts"
- :toggle-text="$options.i18n.artifacts"
- :aria-label="$options.i18n.artifacts"
- icon="download"
- placement="right"
- text-sr-only
- :items="items"
- />
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue
deleted file mode 100644
index 7dc1e60610e..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_filtered_search.vue
+++ /dev/null
@@ -1,130 +0,0 @@
-<script>
-import { GlFilteredSearch } from '@gitlab/ui';
-import { map } from 'lodash';
-import { s__ } from '~/locale';
-import Tracking from '~/tracking';
-import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
-import { TRACKING_CATEGORIES } from '../../constants';
-import PipelineBranchNameToken from './tokens/pipeline_branch_name_token.vue';
-import PipelineSourceToken from './tokens/pipeline_source_token.vue';
-import PipelineStatusToken from './tokens/pipeline_status_token.vue';
-import PipelineTagNameToken from './tokens/pipeline_tag_name_token.vue';
-import PipelineTriggerAuthorToken from './tokens/pipeline_trigger_author_token.vue';
-
-export default {
- userType: 'username',
- branchType: 'ref',
- tagType: 'tag',
- statusType: 'status',
- sourceType: 'source',
- defaultTokensLength: 1,
- components: {
- GlFilteredSearch,
- },
- mixins: [Tracking.mixin()],
- props: {
- projectId: {
- type: String,
- required: true,
- },
- defaultBranchName: {
- type: String,
- required: false,
- default: null,
- },
- params: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- internalValue: [],
- };
- },
- computed: {
- selectedTypes() {
- return this.value.map((i) => i.type);
- },
- tokens() {
- return [
- {
- type: this.$options.userType,
- icon: 'user',
- title: s__('Pipeline|Trigger author'),
- unique: true,
- token: PipelineTriggerAuthorToken,
- operators: OPERATORS_IS,
- projectId: this.projectId,
- },
- {
- type: this.$options.branchType,
- icon: 'branch',
- title: s__('Pipeline|Branch name'),
- unique: true,
- token: PipelineBranchNameToken,
- operators: OPERATORS_IS,
- projectId: this.projectId,
- defaultBranchName: this.defaultBranchName,
- disabled: this.selectedTypes.includes(this.$options.tagType),
- },
- {
- type: this.$options.tagType,
- icon: 'tag',
- title: s__('Pipeline|Tag name'),
- unique: true,
- token: PipelineTagNameToken,
- operators: OPERATORS_IS,
- projectId: this.projectId,
- disabled: this.selectedTypes.includes(this.$options.branchType),
- },
- {
- type: this.$options.statusType,
- icon: 'status',
- title: s__('Pipeline|Status'),
- unique: true,
- token: PipelineStatusToken,
- operators: OPERATORS_IS,
- },
- {
- type: this.$options.sourceType,
- icon: 'trigger-source',
- title: s__('Pipeline|Source'),
- unique: true,
- token: PipelineSourceToken,
- operators: OPERATORS_IS,
- },
- ];
- },
- parsedParams() {
- return map(this.params, (val, key) => ({
- type: key,
- value: { data: val, operator: '=' },
- }));
- },
- value: {
- get() {
- return this.internalValue.length > 0 ? this.internalValue : this.parsedParams;
- },
- set(value) {
- this.internalValue = value;
- },
- },
- },
- methods: {
- onSubmit(filters) {
- this.track('click_filtered_search', { label: TRACKING_CATEGORIES.search });
- this.$emit('filterPipelines', filters);
- },
- },
-};
-</script>
-
-<template>
- <gl-filtered-search
- v-model="value"
- :placeholder="__('Filter pipelines')"
- :available-tokens="tokens"
- @submit="onSubmit"
- />
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions.vue
deleted file mode 100644
index 262e82677a7..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_manual_actions.vue
+++ /dev/null
@@ -1,159 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownItem, GlIcon, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
-import { s__, __, sprintf } from '~/locale';
-import Tracking from '~/tracking';
-import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
-import eventHub from '../../event_hub';
-import { TRACKING_CATEGORIES } from '../../constants';
-import getPipelineActionsQuery from '../../graphql/queries/get_pipeline_actions.query.graphql';
-
-export default {
- name: 'PipelinesManualActions',
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- GlCountdown,
- GlDropdown,
- GlDropdownItem,
- GlIcon,
- GlLoadingIcon,
- },
- mixins: [Tracking.mixin()],
- inject: ['fullPath', 'manualActionsLimit'],
- props: {
- iid: {
- type: Number,
- required: true,
- },
- },
- apollo: {
- actions: {
- query: getPipelineActionsQuery,
- variables() {
- return {
- fullPath: this.fullPath,
- iid: this.iid,
- limit: this.manualActionsLimit,
- };
- },
- skip() {
- return !this.hasDropdownBeenShown;
- },
- update({ project }) {
- return project?.pipeline?.jobs?.nodes || [];
- },
- },
- },
- data() {
- return {
- isLoading: false,
- actions: [],
- hasDropdownBeenShown: false,
- };
- },
- computed: {
- isActionsLoading() {
- return this.$apollo.queries.actions.loading;
- },
- isDropdownLimitReached() {
- return this.actions.length === this.manualActionsLimit;
- },
- },
- methods: {
- async onClickAction(action) {
- if (action.scheduledAt) {
- const confirmationMessage = sprintf(
- s__(
- 'DelayedJobs|Are you sure you want to run %{jobName} immediately? Otherwise this job will run automatically after its timer finishes.',
- ),
- { jobName: action.name },
- );
-
- const confirmed = await confirmAction(confirmationMessage);
-
- if (!confirmed) {
- return;
- }
- }
-
- this.isLoading = true;
-
- /**
- * Ideally, the component would not make an api call directly.
- * However, in order to use the eventhub and know when to
- * toggle back the `isLoading` property we'd need an ID
- * to track the request with a watcher - since this component
- * is rendered at least 20 times in the same page, moving the
- * api call directly here is the most performant solution
- */
- axios
- .post(`${action.playPath}.json`)
- .then(() => {
- this.isLoading = false;
- eventHub.$emit('updateTable');
- })
- .catch(() => {
- this.isLoading = false;
- createAlert({ message: __('An error occurred while making the request.') });
- });
- },
- fetchActions() {
- this.hasDropdownBeenShown = true;
-
- this.$apollo.queries.actions.refetch();
-
- this.trackClick();
- },
- trackClick() {
- this.track('click_manual_actions', { label: TRACKING_CATEGORIES.table });
- },
- },
-};
-</script>
-<template>
- <gl-dropdown
- v-gl-tooltip
- :title="__('Run manual or delayed jobs')"
- :loading="isLoading"
- data-testid="pipelines-manual-actions-dropdown"
- right
- lazy
- icon="play"
- @shown="fetchActions"
- >
- <gl-dropdown-item v-if="isActionsLoading">
- <div class="gl-display-flex">
- <gl-loading-icon class="mr-2" />
- <span>{{ __('Loading...') }}</span>
- </div>
- </gl-dropdown-item>
-
- <gl-dropdown-item
- v-for="action in actions"
- v-else
- :key="action.id"
- :disabled="!action.canPlayJob"
- @click="onClickAction(action)"
- >
- <div class="gl-display-flex gl-justify-content-space-between gl-flex-wrap">
- {{ action.name }}
- <span v-if="action.scheduledAt">
- <gl-icon name="clock" />
- <gl-countdown :end-date-string="action.scheduledAt" />
- </span>
- </div>
- </gl-dropdown-item>
-
- <template #footer>
- <gl-dropdown-item v-if="isDropdownLimitReached">
- <span class="gl-font-sm gl-text-gray-300!" data-testid="limit-reached-msg">
- {{ __('Showing first 50 actions.') }}
- </span>
- </gl-dropdown-item>
- </template>
- </gl-dropdown>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue
deleted file mode 100644
index 00ab8a25ca1..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-<script>
-import { CHILD_VIEW, TRACKING_CATEGORIES } from '~/pipelines/constants';
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import Tracking from '~/tracking';
-import PipelinesTimeago from './time_ago.vue';
-
-export default {
- components: {
- CiBadgeLink,
- PipelinesTimeago,
- },
- mixins: [Tracking.mixin()],
- props: {
- pipeline: {
- type: Object,
- required: true,
- },
- viewType: {
- type: String,
- required: true,
- },
- },
- computed: {
- pipelineStatus() {
- return this.pipeline?.details?.status ?? {};
- },
- isChildView() {
- return this.viewType === CHILD_VIEW;
- },
- },
- methods: {
- trackClick() {
- this.track('click_ci_status_badge', { label: TRACKING_CATEGORIES.table });
- },
- },
-};
-</script>
-
-<template>
- <div>
- <ci-badge-link
- class="gl-mb-3"
- :status="pipelineStatus"
- :show-text="!isChildView"
- data-qa-selector="pipeline_commit_status"
- @ciStatusBadgeClick="trackClick"
- />
- <pipelines-timeago :pipeline="pipeline" />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
deleted file mode 100644
index c03085e6419..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
+++ /dev/null
@@ -1,240 +0,0 @@
-<script>
-import { GlTableLite, GlTooltipDirective } from '@gitlab/ui';
-import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
-import { s__, __ } from '~/locale';
-import Tracking from '~/tracking';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { keepLatestDownstreamPipelines } from '~/pipelines/components/parsing_utils';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
-import PipelineFailedJobsWidget from '~/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget.vue';
-import eventHub from '../../event_hub';
-import { TRACKING_CATEGORIES } from '../../constants';
-import PipelineOperations from './pipeline_operations.vue';
-import PipelineStopModal from './pipeline_stop_modal.vue';
-import PipelineTriggerer from './pipeline_triggerer.vue';
-import PipelineUrl from './pipeline_url.vue';
-import PipelinesStatusBadge from './pipelines_status_badge.vue';
-
-const HIDE_TD_ON_MOBILE = 'gl-display-none! gl-lg-display-table-cell!';
-const DEFAULT_TH_CLASSES =
- 'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-100! gl-p-5! gl-border-b-1!';
-
-export default {
- components: {
- GlTableLite,
- LegacyPipelineMiniGraph,
- PipelineFailedJobsWidget,
- PipelineOperations,
- PipelinesStatusBadge,
- PipelineStopModal,
- PipelineTriggerer,
- PipelineUrl,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [Tracking.mixin(), glFeatureFlagMixin()],
- inject: {
- withFailedJobsDetails: {
- default: false,
- },
- },
- props: {
- pipelines: {
- type: Array,
- required: true,
- },
- pipelineScheduleUrl: {
- type: String,
- required: false,
- default: '',
- },
- updateGraphDropdown: {
- type: Boolean,
- required: false,
- default: false,
- },
- viewType: {
- type: String,
- required: true,
- },
- pipelineKeyOption: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- pipelineId: 0,
- pipeline: {},
- endpoint: '',
- cancelingPipeline: null,
- };
- },
- computed: {
- showFailedJobsWidget() {
- return this.glFeatures.ciJobFailuresInMr;
- },
- tableFields() {
- return [
- {
- key: 'status',
- label: s__('Pipeline|Status'),
- thClass: DEFAULT_TH_CLASSES,
- columnClass: 'gl-w-15p',
- tdClass: this.tdClasses,
- thAttr: { 'data-testid': 'status-th' },
- },
- {
- key: 'pipeline',
- label: __('Pipeline'),
- thClass: DEFAULT_TH_CLASSES,
- tdClass: `${this.tdClasses}`,
- columnClass: 'gl-w-30p',
- thAttr: { 'data-testid': 'pipeline-th' },
- },
- {
- key: 'triggerer',
- label: s__('Pipeline|Triggerer'),
- thClass: DEFAULT_TH_CLASSES,
- tdClass: `${this.tdClasses} ${HIDE_TD_ON_MOBILE}`,
- columnClass: 'gl-w-10p',
- thAttr: { 'data-testid': 'triggerer-th' },
- },
- {
- key: 'stages',
- label: s__('Pipeline|Stages'),
- thClass: DEFAULT_TH_CLASSES,
- tdClass: this.tdClasses,
- columnClass: 'gl-w-quarter',
- thAttr: { 'data-testid': 'stages-th' },
- },
- {
- key: 'actions',
- thClass: DEFAULT_TH_CLASSES,
- tdClass: this.tdClasses,
- columnClass: 'gl-w-15p',
- thAttr: { 'data-testid': 'actions-th' },
- },
- ];
- },
- tdClasses() {
- return this.withFailedJobsDetails ? 'gl-pb-0! gl-border-none!' : 'pl-p-5!';
- },
- pipelinesWithDetails() {
- if (this.withFailedJobsDetails) {
- return this.pipelines.map((p) => {
- return { ...p, _showDetails: true };
- });
- }
-
- return this.pipelines;
- },
- },
- watch: {
- pipelines() {
- this.cancelingPipeline = null;
- },
- },
- created() {
- eventHub.$on('openConfirmationModal', this.setModalData);
- },
- beforeDestroy() {
- eventHub.$off('openConfirmationModal', this.setModalData);
- },
- methods: {
- getDownstreamPipelines(pipeline) {
- const downstream = pipeline.triggered;
- return keepLatestDownstreamPipelines(downstream);
- },
- getProjectPath(item) {
- return cleanLeadingSeparator(item.project.full_path);
- },
- failedJobsCount(pipeline) {
- return pipeline?.failed_builds?.length || 0;
- },
- setModalData(data) {
- this.pipelineId = data.pipeline.id;
- this.pipeline = data.pipeline;
- this.endpoint = data.endpoint;
- },
- onSubmit() {
- eventHub.$emit('postAction', this.endpoint);
- this.cancelingPipeline = this.pipelineId;
- },
- trackPipelineMiniGraph() {
- this.track('click_minigraph', { label: TRACKING_CATEGORIES.table });
- },
- },
- TBODY_TR_ATTR: {
- 'data-testid': 'pipeline-table-row',
- 'data-qa-selector': 'pipeline_row_container',
- },
-};
-</script>
-<template>
- <div class="ci-table">
- <gl-table-lite
- :fields="tableFields"
- :items="pipelinesWithDetails"
- :tbody-tr-attr="$options.TBODY_TR_ATTR"
- stacked="lg"
- fixed
- >
- <template #head(actions)>
- <span class="gl-display-block gl-lg-display-none!">{{ s__('Pipeline|Actions') }}</span>
- <slot name="table-header-actions"></slot>
- </template>
-
- <template #table-colgroup="{ fields }">
- <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
- </template>
-
- <template #cell(status)="{ item }">
- <pipelines-status-badge :pipeline="item" :view-type="viewType" />
- </template>
-
- <template #cell(pipeline)="{ item }">
- <pipeline-url
- :pipeline="item"
- :pipeline-schedule-url="pipelineScheduleUrl"
- :pipeline-key="pipelineKeyOption.value"
- ref-color="gl-text-black-normal"
- />
- </template>
-
- <template #cell(triggerer)="{ item }">
- <pipeline-triggerer :pipeline="item" />
- </template>
-
- <template #cell(stages)="{ item }">
- <legacy-pipeline-mini-graph
- :downstream-pipelines="getDownstreamPipelines(item)"
- :pipeline-path="item.path"
- :stages="item.details.stages"
- :update-dropdown="updateGraphDropdown"
- :upstream-pipeline="item.triggered_by"
- @miniGraphStageClick="trackPipelineMiniGraph"
- />
- </template>
-
- <template #cell(actions)="{ item }">
- <pipeline-operations :pipeline="item" :canceling-pipeline="cancelingPipeline" />
- </template>
-
- <template #row-details="{ item }">
- <pipeline-failed-jobs-widget
- v-if="showFailedJobsWidget"
- :failed-jobs-count="failedJobsCount(item)"
- :is-pipeline-active="item.active"
- :pipeline-iid="item.iid"
- :pipeline-path="item.path"
- :project-path="getProjectPath(item)"
- class="gl-ml-n4 gl-mt-n3 gl-mb-n1"
- />
- </template>
- </gl-table-lite>
-
- <pipeline-stop-modal :pipeline="pipeline" @submit="onSubmit" />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue
deleted file mode 100644
index 81f46d5f2f9..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue
+++ /dev/null
@@ -1,82 +0,0 @@
-<script>
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
-import { debounce } from 'lodash';
-import Api from '~/api';
-import { createAlert } from '~/alert';
-import { FETCH_BRANCH_ERROR_MESSAGE, FILTER_PIPELINES_SEARCH_DELAY } from '../../../constants';
-
-export default {
- components: {
- GlFilteredSearchToken,
- GlFilteredSearchSuggestion,
- GlLoadingIcon,
- },
- props: {
- config: {
- type: Object,
- required: true,
- },
- value: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- branches: null,
- loading: true,
- };
- },
- created() {
- this.fetchBranches();
- },
- methods: {
- fetchBranches(searchterm) {
- Api.branches(this.config.projectId, searchterm)
- .then(({ data }) => {
- this.branches = data.map((branch) => branch.name);
- if (!searchterm && this.config.defaultBranchName) {
- // Shift the default branch to the top of the list
- this.branches = this.branches.filter(
- (branch) => branch !== this.config.defaultBranchName,
- );
- this.branches.unshift(this.config.defaultBranchName);
- }
- this.loading = false;
- })
- .catch((err) => {
- createAlert({
- message: FETCH_BRANCH_ERROR_MESSAGE,
- });
- this.loading = false;
- throw err;
- });
- },
- searchBranches: debounce(function debounceSearch({ data }) {
- this.fetchBranches(data);
- }, FILTER_PIPELINES_SEARCH_DELAY),
- },
-};
-</script>
-
-<template>
- <gl-filtered-search-token
- :config="config"
- v-bind="{ ...$props, ...$attrs }"
- v-on="$listeners"
- @input="searchBranches"
- >
- <template #suggestions>
- <gl-loading-icon v-if="loading" size="sm" />
- <template v-else>
- <gl-filtered-search-suggestion
- v-for="(branch, index) in branches"
- :key="index"
- :value="branch"
- >
- {{ branch }}
- </gl-filtered-search-suggestion>
- </template>
- </template>
- </gl-filtered-search-token>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_source_token.vue b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_source_token.vue
deleted file mode 100644
index 9643ddfbd21..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_source_token.vue
+++ /dev/null
@@ -1,47 +0,0 @@
-<script>
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { PIPELINE_SOURCES } from 'ee_else_ce/pipelines/components/pipelines_list/tokens/constants';
-
-export default {
- PIPELINE_SOURCES,
- components: {
- GlFilteredSearchToken,
- GlFilteredSearchSuggestion,
- },
- props: {
- config: {
- type: Object,
- required: true,
- },
- value: {
- type: Object,
- required: true,
- },
- },
- computed: {
- activeSource() {
- return PIPELINE_SOURCES.find((source) => source.value === this.value.data);
- },
- },
-};
-</script>
-
-<template>
- <gl-filtered-search-token v-bind="{ ...$props, ...$attrs }" v-on="$listeners">
- <template #view>
- <div class="gl-display-flex gl-align-items-center">
- <span>{{ activeSource.text }}</span>
- </div>
- </template>
-
- <template #suggestions>
- <gl-filtered-search-suggestion
- v-for="source in $options.PIPELINE_SOURCES"
- :key="source.value"
- :value="source.value"
- >
- {{ source.text }}
- </gl-filtered-search-suggestion>
- </template>
- </gl-filtered-search-token>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_tag_name_token.vue b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_tag_name_token.vue
deleted file mode 100644
index b32f5de2d7e..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_tag_name_token.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-<script>
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
-import { debounce } from 'lodash';
-import Api from '~/api';
-import { createAlert } from '~/alert';
-import { FETCH_TAG_ERROR_MESSAGE, FILTER_PIPELINES_SEARCH_DELAY } from '../../../constants';
-
-export default {
- components: {
- GlFilteredSearchToken,
- GlFilteredSearchSuggestion,
- GlLoadingIcon,
- },
- props: {
- config: {
- type: Object,
- required: true,
- },
- value: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- tags: null,
- loading: true,
- };
- },
- created() {
- this.fetchTags();
- },
- methods: {
- fetchTags(searchTerm) {
- Api.tags(this.config.projectId, searchTerm)
- .then(({ data }) => {
- this.tags = data.map((tag) => tag.name);
- this.loading = false;
- })
- .catch((err) => {
- createAlert({
- message: FETCH_TAG_ERROR_MESSAGE,
- });
- this.loading = false;
- throw err;
- });
- },
- searchTags: debounce(function debounceSearch({ data }) {
- this.fetchTags(data);
- }, FILTER_PIPELINES_SEARCH_DELAY),
- },
-};
-</script>
-
-<template>
- <gl-filtered-search-token v-bind="{ ...$props, ...$attrs }" v-on="$listeners" @input="searchTags">
- <template #suggestions>
- <gl-loading-icon v-if="loading" size="sm" />
- <template v-else>
- <gl-filtered-search-suggestion v-for="(tag, index) in tags" :key="index" :value="tag">
- {{ tag }}
- </gl-filtered-search-suggestion>
- </template>
- </template>
- </gl-filtered-search-token>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
deleted file mode 100644
index a89354c671a..00000000000
--- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
+++ /dev/null
@@ -1,113 +0,0 @@
-<script>
-import {
- GlFilteredSearchToken,
- GlAvatar,
- GlFilteredSearchSuggestion,
- GlDropdownDivider,
- GlLoadingIcon,
-} from '@gitlab/ui';
-import { debounce } from 'lodash';
-import Api from '~/api';
-import { createAlert } from '~/alert';
-import {
- ANY_TRIGGER_AUTHOR,
- FETCH_AUTHOR_ERROR_MESSAGE,
- FILTER_PIPELINES_SEARCH_DELAY,
-} from '../../../constants';
-
-export default {
- anyTriggerAuthor: ANY_TRIGGER_AUTHOR,
- components: {
- GlFilteredSearchToken,
- GlAvatar,
- GlFilteredSearchSuggestion,
- GlDropdownDivider,
- GlLoadingIcon,
- },
- props: {
- config: {
- type: Object,
- required: true,
- },
- value: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- users: [],
- loading: true,
- };
- },
- computed: {
- currentValue() {
- return this.value.data.toLowerCase();
- },
- activeUser() {
- return this.users.find((user) => {
- return user.username.toLowerCase() === this.currentValue;
- });
- },
- },
- created() {
- this.fetchProjectUsers();
- },
- methods: {
- fetchProjectUsers(searchTerm) {
- Api.projectUsers(this.config.projectId, searchTerm)
- .then((users) => {
- this.users = users;
- this.loading = false;
- })
- .catch((err) => {
- createAlert({
- message: FETCH_AUTHOR_ERROR_MESSAGE,
- });
- this.loading = false;
- throw err;
- });
- },
- searchAuthors: debounce(function debounceSearch({ data }) {
- this.fetchProjectUsers(data);
- }, FILTER_PIPELINES_SEARCH_DELAY),
- },
-};
-</script>
-
-<template>
- <gl-filtered-search-token
- :config="config"
- v-bind="{ ...$props, ...$attrs }"
- v-on="$listeners"
- @input="searchAuthors"
- >
- <template #view="{ inputValue }">
- <gl-avatar v-if="activeUser" :size="16" :src="activeUser.avatar_url" class="gl-mr-2" />
- <span>{{ activeUser ? activeUser.name : inputValue }}</span>
- </template>
- <template #suggestions>
- <gl-filtered-search-suggestion :value="$options.anyTriggerAuthor">{{
- $options.anyTriggerAuthor
- }}</gl-filtered-search-suggestion>
- <gl-dropdown-divider />
-
- <gl-loading-icon v-if="loading" size="sm" />
- <template v-else>
- <gl-filtered-search-suggestion
- v-for="user in users"
- :key="user.username"
- :value="user.username"
- >
- <div class="d-flex">
- <gl-avatar :size="32" :src="user.avatar_url" />
- <div>
- <div>{{ user.name }}</div>
- <div>@{{ user.username }}</div>
- </div>
- </div>
- </gl-filtered-search-suggestion>
- </template>
- </template>
- </gl-filtered-search-token>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/test_reports/empty_state.vue b/app/assets/javascripts/pipelines/components/test_reports/empty_state.vue
deleted file mode 100644
index 3e7827dc416..00000000000
--- a/app/assets/javascripts/pipelines/components/test_reports/empty_state.vue
+++ /dev/null
@@ -1,60 +0,0 @@
-<script>
-import { GlEmptyState } from '@gitlab/ui';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { s__ } from '~/locale';
-
-export const i18n = {
- noTestsButton: s__('TestReports|Learn more about pipeline test reports'),
- noTestsDescription: s__('TestReports|No test cases were found in the test report.'),
- noTestsTitle: s__('TestReports|There are no tests to display'),
- noReportsButton: s__('TestReports|Learn how to upload pipeline test reports'),
- noReportsDescription: s__(
- 'TestReports|You can configure your job to use unit test reports, and GitLab displays a report here and in the related merge request.',
- ),
- noReportsTitle: s__('TestReports|There are no test reports for this pipeline'),
-};
-
-export default {
- i18n,
- components: {
- GlEmptyState,
- },
- inject: {
- emptyStateImagePath: {
- default: '',
- },
- hasTestReport: {
- default: false,
- },
- },
- computed: {
- emptyStateText() {
- if (this.hasTestReport) {
- return {
- button: this.$options.i18n.noTestsButton,
- description: this.$options.i18n.noTestsDescription,
- title: this.$options.i18n.noTestsTitle,
- };
- }
- return {
- button: this.$options.i18n.noReportsButton,
- description: this.$options.i18n.noReportsDescription,
- title: this.$options.i18n.noReportsTitle,
- };
- },
- testReportDocPath() {
- return helpPagePath('ci/testing/unit_test_reports');
- },
- },
-};
-</script>
-
-<template>
- <gl-empty-state
- :title="emptyStateText.title"
- :description="emptyStateText.description"
- :svg-path="emptyStateImagePath"
- :primary-button-link="testReportDocPath"
- :primary-button-text="emptyStateText.button"
- />
-</template>
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue b/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue
deleted file mode 100644
index 10db3e1c56b..00000000000
--- a/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue
+++ /dev/null
@@ -1,145 +0,0 @@
-<script>
-import { GlBadge, GlFriendlyWrap, GlLink, GlModal, GlTooltipDirective } from '@gitlab/ui';
-import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
-import { __, n__, s__, sprintf } from '~/locale';
-import CodeBlock from '~/vue_shared/components/code_block.vue';
-
-export default {
- name: 'TestCaseDetails',
- components: {
- CodeBlock,
- GlBadge,
- GlFriendlyWrap,
- GlLink,
- GlModal,
- ModalCopyButton,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- modalId: {
- type: String,
- required: true,
- },
- testCase: {
- type: Object,
- required: false,
- default: () => {
- return {};
- },
- },
- },
- computed: {
- failureHistoryMessage() {
- if (!this.hasRecentFailures) {
- return null;
- }
-
- return sprintf(
- n__(
- 'Reports|Failed %{count} time in %{baseBranch} in the last 14 days',
- 'Reports|Failed %{count} times in %{baseBranch} in the last 14 days',
- this.recentFailures.count,
- ),
- {
- count: this.recentFailures.count,
- baseBranch: this.recentFailures.base_branch,
- },
- );
- },
- hasRecentFailures() {
- return Boolean(this.recentFailures);
- },
- recentFailures() {
- return this.testCase.recent_failures;
- },
- },
- text: {
- name: __('Name'),
- file: __('File'),
- duration: __('Execution time'),
- history: __('History'),
- trace: __('System output'),
- attachment: s__('TestReports|Attachment'),
- copyTestName: s__('TestReports|Copy test name to rerun locally'),
- },
- modalCloseButton: {
- text: __('Close'),
- attributes: { variant: 'confirm' },
- },
-};
-</script>
-
-<template>
- <gl-modal
- data-testid="test-case-details-modal"
- :modal-id="modalId"
- :title="testCase.classname"
- :action-primary="$options.modalCloseButton"
- >
- <div class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
- <strong class="gl-text-right col-sm-3">{{ $options.text.name }}</strong>
- <div class="col-sm-9" data-testid="test-case-name">
- {{ testCase.name }}
- </div>
- </div>
-
- <div v-if="testCase.file" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
- <strong class="gl-text-right col-sm-3">{{ $options.text.file }}</strong>
- <div class="col-sm-9" data-testid="test-case-file">
- <gl-link v-if="testCase.filePath" :href="testCase.filePath">
- {{ testCase.file }}
- </gl-link>
- <span v-else>{{ testCase.file }}</span>
- <modal-copy-button
- :title="$options.text.copyTestName"
- :text="testCase.file"
- :modal-id="modalId"
- category="tertiary"
- class="gl-ml-1"
- />
- </div>
- </div>
-
- <div class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
- <strong class="gl-text-right col-sm-3">{{ $options.text.duration }}</strong>
- <div v-if="testCase.formattedTime" class="col-sm-9" data-testid="test-case-duration">
- {{ testCase.formattedTime }}
- </div>
- <div v-else-if="testCase.execution_time" class="col-sm-9" data-testid="test-case-duration">
- {{ sprintf('%{value} s', { value: testCase.execution_time }) }}
- </div>
- </div>
-
- <div v-if="testCase.recent_failures" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
- <strong class="gl-text-right col-sm-3">{{ $options.text.history }}</strong>
- <div class="col-sm-9" data-testid="test-case-recent-failures">
- <gl-badge variant="warning">{{ failureHistoryMessage }}</gl-badge>
- </div>
- </div>
-
- <div v-if="testCase.attachment_url" class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3">
- <strong class="gl-text-right col-sm-3">{{ $options.text.attachment }}</strong>
- <gl-link
- class="col-sm-9"
- :href="testCase.attachment_url"
- target="_blank"
- data-testid="test-case-attachment-url"
- >
- <gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.attachment_url" />
- </gl-link>
- </div>
-
- <div
- v-if="testCase.system_output"
- class="gl-display-flex gl-flex-wrap gl-mx-n4 gl-my-3"
- data-testid="test-case-trace"
- >
- <strong class="gl-text-right col-sm-3">{{ $options.text.trace }}</strong>
- <div class="col-sm-9">
- <code-block :code="testCase.system_output" />
- </div>
- </div>
- </gl-modal>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_summary.vue b/app/assets/javascripts/pipelines/components/test_reports/test_summary.vue
deleted file mode 100644
index 6b723ad5481..00000000000
--- a/app/assets/javascripts/pipelines/components/test_reports/test_summary.vue
+++ /dev/null
@@ -1,117 +0,0 @@
-<script>
-import { GlButton, GlProgressBar } from '@gitlab/ui';
-import { __ } from '~/locale';
-import { formattedTime } from '../../stores/test_reports/utils';
-
-export default {
- name: 'TestSummary',
- components: {
- GlButton,
- GlProgressBar,
- },
- props: {
- report: {
- type: Object,
- required: true,
- },
- showBack: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- computed: {
- heading() {
- return this.report.name || __('Summary');
- },
- successPercentage() {
- // Returns a full number when the decimals equal .00.
- // Otherwise returns a float to two decimal points
- // Do not include skipped tests as part of the total when doing success calculations.
-
- const totalCompletedCount = this.report.total_count - this.report.skipped_count;
-
- if (totalCompletedCount > 0) {
- return Number(((this.report.success_count / totalCompletedCount) * 100 || 0).toFixed(2));
- }
- return 0;
- },
- formattedDuration() {
- return formattedTime(this.report.total_time);
- },
- progressBarVariant() {
- if (this.successPercentage < 33) {
- return 'danger';
- }
-
- if (this.successPercentage >= 33 && this.successPercentage < 66) {
- return 'warning';
- }
-
- if (this.successPercentage >= 66 && this.successPercentage < 90) {
- return 'primary';
- }
-
- return 'success';
- },
- },
- methods: {
- onBackClick() {
- this.$emit('on-back-click');
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div class="gl-w-full gl-display-flex gl-mt-3 gl-align-items-center">
- <gl-button
- v-if="showBack"
- size="small"
- class="gl-mr-3 js-back-button"
- icon="chevron-lg-left"
- :aria-label="__('Go back')"
- @click="onBackClick"
- />
-
- <h4>{{ heading }}</h4>
- </div>
-
- <div
- class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-w-full gl-mt-3"
- >
- <div class="gl-display-flex gl-justify-content-space-between gl-flex-basis-half">
- <span class="js-total-tests gl-flex-grow-1">{{
- sprintf(s__('TestReports|%{count} tests'), { count: report.total_count })
- }}</span>
-
- <span class="js-failed-tests gl-flex-grow-1">{{
- sprintf(s__('TestReports|%{count} failures'), { count: report.failed_count })
- }}</span>
-
- <span class="js-errored-tests">{{
- sprintf(s__('TestReports|%{count} errors'), { count: report.error_count })
- }}</span>
- </div>
- <div class="gl-display-flex gl-justify-content-space-between gl-flex-grow-1">
- <div class="gl-display-none gl-md-display-block gl-flex-grow-1"></div>
- <span class="js-success-rate gl-flex-grow-1">{{
- sprintf(s__('TestReports|%{rate}%{sign} success rate'), {
- rate: successPercentage,
- sign: '%',
- })
- }}</span>
-
- <span class="js-duration">{{ formattedDuration }}</span>
- </div>
- </div>
-
- <gl-progress-bar
- class="gl-mt-5"
- :value="successPercentage"
- :variant="progressBarVariant"
- height="10px"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/unwrapping_utils.js b/app/assets/javascripts/pipelines/components/unwrapping_utils.js
deleted file mode 100644
index d42a11c3aba..00000000000
--- a/app/assets/javascripts/pipelines/components/unwrapping_utils.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import { reportToSentry } from '../utils';
-import { EXPLICIT_NEEDS_PROPERTY, NEEDS_PROPERTY } from '../constants';
-
-const unwrapGroups = (stages) => {
- return stages.map((stage, idx) => {
- const {
- groups: { nodes: groups },
- } = stage;
-
- /*
- Being peformance conscious here means we don't want to spread and copy the
- group value just to add one parameter.
- */
- /* eslint-disable no-param-reassign */
- const groupsWithStageName = groups.map((group) => {
- group.stageName = stage.name;
- return group;
- });
- /* eslint-enable no-param-reassign */
-
- return { node: { ...stage, groups: groupsWithStageName }, lookup: { stageIdx: idx } };
- });
-};
-
-const unwrapNodesWithName = (jobArray, prop, field = 'name') => {
- if (jobArray.length < 1) {
- reportToSentry('unwrapping_utils', 'undefined_job_hunt, array empty from backend');
- }
-
- return jobArray.map((job) => {
- if (job[prop]) {
- return { ...job, [prop]: job[prop].nodes.map((item) => item[field] || '') };
- }
- return job;
- });
-};
-
-const unwrapJobWithNeeds = (denodedJobArray) => {
- const explicitNeedsUnwrapped = unwrapNodesWithName(denodedJobArray, EXPLICIT_NEEDS_PROPERTY);
- return unwrapNodesWithName(explicitNeedsUnwrapped, NEEDS_PROPERTY);
-};
-
-const unwrapStagesWithNeedsAndLookup = (denodedStages) => {
- const unwrappedNestedGroups = unwrapGroups(denodedStages);
-
- const lookupMap = {};
-
- const nodes = unwrappedNestedGroups.map(({ node, lookup }) => {
- const { groups } = node;
- const groupsWithJobs = groups.map((group, idx) => {
- const jobs = unwrapJobWithNeeds(group.jobs.nodes);
-
- lookupMap[group.name] = { ...lookup, groupIdx: idx };
- return { ...group, jobs };
- });
-
- return { ...node, groups: groupsWithJobs };
- });
-
- return { stages: nodes, lookup: lookupMap };
-};
-
-const unwrapStagesWithNeeds = (denodedStages) => {
- return unwrapStagesWithNeedsAndLookup(denodedStages).stages;
-};
-
-export {
- unwrapGroups,
- unwrapJobWithNeeds,
- unwrapNodesWithName,
- unwrapStagesWithNeeds,
- unwrapStagesWithNeedsAndLookup,
-};
diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js
deleted file mode 100644
index 93ca3738ff0..00000000000
--- a/app/assets/javascripts/pipelines/constants.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import { s__, __ } from '~/locale';
-
-export const CANCEL_REQUEST = 'CANCEL_REQUEST';
-export const FILTER_PIPELINES_SEARCH_DELAY = 200;
-export const ANY_TRIGGER_AUTHOR = 'Any';
-export const SUPPORTED_FILTER_PARAMETERS = ['username', 'ref', 'status', 'source'];
-export const FILTER_TAG_IDENTIFIER = 'tag';
-export const SCHEDULE_ORIGIN = 'schedule';
-export const NEEDS_PROPERTY = 'needs';
-export const EXPLICIT_NEEDS_PROPERTY = 'previousStageJobsOrNeeds';
-
-export const ICONS = {
- TAG: 'tag',
- MR: 'git-merge',
- BRANCH: 'branch',
- RETRY: 'retry',
- SUCCESS: 'success',
-};
-
-export const TestStatus = {
- FAILED: 'failed',
- SKIPPED: 'skipped',
- SUCCESS: 'success',
- ERROR: 'error',
- UNKNOWN: 'unknown',
-};
-
-export const FETCH_AUTHOR_ERROR_MESSAGE = __('There was a problem fetching project users.');
-export const FETCH_BRANCH_ERROR_MESSAGE = __('There was a problem fetching project branches.');
-export const FETCH_TAG_ERROR_MESSAGE = __('There was a problem fetching project tags.');
-export const RAW_TEXT_WARNING = s__(
- 'Pipeline|Raw text search is not currently supported. Please use the available search tokens.',
-);
-
-/* Error constants shared across graphs */
-export const DEFAULT = 'default';
-export const DELETE_FAILURE = 'delete_pipeline_failure';
-export const DRAW_FAILURE = 'draw_failure';
-export const LOAD_FAILURE = 'load_failure';
-export const PARSE_FAILURE = 'parse_failure';
-export const POST_FAILURE = 'post_failure';
-export const UNSUPPORTED_DATA = 'unsupported_data';
-
-export const CHILD_VIEW = 'child';
-
-// Pipeline tabs
-
-export const pipelineTabName = 'graph';
-export const needsTabName = 'dag';
-export const jobsTabName = 'builds';
-export const failedJobsTabName = 'failures';
-export const testReportTabName = 'test_report';
-export const securityTabName = 'security';
-export const licensesTabName = 'licenses';
-export const codeQualityTabName = 'codequality_report';
-
-export const validPipelineTabNames = [
- needsTabName,
- jobsTabName,
- failedJobsTabName,
- testReportTabName,
- securityTabName,
- licensesTabName,
- codeQualityTabName,
-];
-
-// Constants for the ID and IID selection dropdown
-export const PipelineKeyOptions = [
- {
- text: __('Show Pipeline ID'),
- label: __('Pipeline ID'),
- value: 'id',
- },
- {
- text: __('Show Pipeline IID'),
- label: __('Pipeline IID'),
- value: 'iid',
- },
-];
-
-export const TOAST_MESSAGE = s__('Pipeline|Creating pipeline.');
-
-export const BUTTON_TOOLTIP_RETRY = __('Retry all failed or cancelled jobs');
-export const BUTTON_TOOLTIP_CANCEL = __('Cancel the running pipeline');
-
-export const DEFAULT_FIELDS = [
- {
- key: 'name',
- label: __('Name'),
- columnClass: 'gl-w-20p',
- },
- {
- key: 'stage',
- label: __('Stage'),
- columnClass: 'gl-w-20p',
- },
- {
- key: 'failureMessage',
- label: __('Failure'),
- columnClass: 'gl-w-40p',
- },
- {
- key: 'actions',
- label: '',
- tdClass: 'gl-text-right',
- columnClass: 'gl-w-20p',
- },
-];
-
-export const TRACKING_CATEGORIES = {
- table: 'pipelines_table_component',
- tabs: 'pipelines_filter_tabs',
- search: 'pipelines_filtered_search',
- failed: 'pipeline_failed_jobs_tab',
- tests: 'pipeline_tests_tab',
-};
-
-// Pipeline Mini Graph
-
-export const PIPELINE_MINI_GRAPH_POLL_INTERVAL = 5000;
diff --git a/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js b/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js
deleted file mode 100644
index 481953608e9..00000000000
--- a/app/assets/javascripts/pipelines/mixins/pipelines_mixin.js
+++ /dev/null
@@ -1,237 +0,0 @@
-import Visibility from 'visibilityjs';
-import { createAlert } from '~/alert';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { historyPushState, buildUrlWithCurrentLocation } from '~/lib/utils/common_utils';
-import { HTTP_STATUS_UNAUTHORIZED } from '~/lib/utils/http_status';
-import Poll from '~/lib/utils/poll';
-import { __ } from '~/locale';
-import { validateParams } from '~/pipelines/utils';
-import { CANCEL_REQUEST, TOAST_MESSAGE } from '../constants';
-import eventHub from '../event_hub';
-
-export default {
- data() {
- return {
- isLoading: false,
- hasError: false,
- isMakingRequest: false,
- updateGraphDropdown: false,
- hasMadeRequest: false,
- };
- },
- computed: {
- shouldRenderPagination() {
- return !this.isLoading;
- },
- },
- beforeMount() {
- this.poll = new Poll({
- resource: this.service,
- method: 'getPipelines',
- data: this.requestData ? this.requestData : undefined,
- successCallback: this.successCallback,
- errorCallback: this.errorCallback,
- notificationCallback: this.setIsMakingRequest,
- });
-
- if (!Visibility.hidden()) {
- this.isLoading = true;
- this.poll.makeRequest();
- } else {
- // If tab is not visible we need to make the first request so we don't show the empty
- // state without knowing if there are any pipelines
- this.fetchPipelines();
- }
-
- Visibility.change(() => {
- if (!Visibility.hidden()) {
- this.poll.restart();
- } else {
- this.poll.stop();
- }
- });
-
- eventHub.$on('postAction', this.postAction);
- eventHub.$on('retryPipeline', this.postAction);
- eventHub.$on('clickedDropdown', this.updateTable);
- eventHub.$on('updateTable', this.updateTable);
- eventHub.$on('runMergeRequestPipeline', this.runMergeRequestPipeline);
- },
- beforeDestroy() {
- eventHub.$off('postAction', this.postAction);
- eventHub.$off('retryPipeline', this.postAction);
- eventHub.$off('clickedDropdown', this.updateTable);
- eventHub.$off('updateTable', this.updateTable);
- eventHub.$off('runMergeRequestPipeline', this.runMergeRequestPipeline);
- },
- destroyed() {
- this.poll.stop();
- },
- methods: {
- updateInternalState(parameters) {
- this.poll.stop();
-
- const queryString = Object.keys(parameters)
- .map((parameter) => {
- const value = parameters[parameter];
- // update internal state for UI
- this[parameter] = value;
- return `${parameter}=${encodeURIComponent(value)}`;
- })
- .join('&');
-
- // update polling parameters
- this.requestData = parameters;
-
- historyPushState(buildUrlWithCurrentLocation(`?${queryString}`));
-
- this.isLoading = true;
- },
- /**
- * Handles URL and query parameter changes.
- * When the user uses the pagination or the tabs,
- * - update URL
- * - Make API request to the server with new parameters
- * - Update the polling function
- * - Update the internal state
- */
- updateContent(parameters) {
- this.updateInternalState(parameters);
-
- // fetch new data
- return this.service
- .getPipelines(this.requestData)
- .then((response) => {
- this.isLoading = false;
- this.successCallback(response);
-
- this.poll.enable({ data: this.requestData, response });
- })
- .catch(() => {
- this.isLoading = false;
- this.errorCallback();
-
- // restart polling
- this.poll.restart({ data: this.requestData });
- });
- },
- updateTable() {
- // Cancel ongoing request
- if (this.isMakingRequest) {
- this.service.cancelationSource.cancel(CANCEL_REQUEST);
- }
- // Stop polling
- this.poll.stop();
- // Restarting the poll also makes an initial request
- return this.poll.restart();
- },
- fetchPipelines() {
- if (!this.isMakingRequest) {
- this.isLoading = true;
-
- this.getPipelines();
- }
- },
- getPipelines() {
- return this.service
- .getPipelines(this.requestData)
- .then((response) => this.successCallback(response))
- .catch((error) => this.errorCallback(error));
- },
- setCommonData(pipelines) {
- this.store.storePipelines(pipelines);
- this.isLoading = false;
- this.updateGraphDropdown = true;
- this.hasMadeRequest = true;
-
- // In case the previous polling request returned an error, we need to reset it
- if (this.hasError) {
- this.hasError = false;
- }
- },
- errorCallback(error) {
- this.hasMadeRequest = true;
- this.isLoading = false;
-
- if (error && error.message && error.message !== CANCEL_REQUEST) {
- this.hasError = true;
- this.updateGraphDropdown = false;
- }
- },
- setIsMakingRequest(isMakingRequest) {
- this.isMakingRequest = isMakingRequest;
-
- if (isMakingRequest) {
- this.updateGraphDropdown = false;
- }
- },
- postAction(endpoint) {
- this.service
- .postAction(endpoint)
- .then(() => this.updateTable())
- .catch(() =>
- createAlert({
- message: __('An error occurred while making the request.'),
- }),
- );
- },
-
- /**
- * When the user clicks on the run pipeline button
- * we toggle the state of the button to be disabled
- *
- * Once the post request has finished, we fetch the
- * pipelines again to show the most recent data
- *
- * Once the pipeline has been updated, we toggle back the
- * loading state and re-enable the run pipeline button
- */
- runMergeRequestPipeline(options) {
- this.store.toggleIsRunningPipeline(true);
-
- this.service
- .runMRPipeline(options)
- .then(() => {
- this.$toast.show(TOAST_MESSAGE);
- this.updateTable();
- })
- .catch((e) => {
- const unauthorized = e.response.status === HTTP_STATUS_UNAUTHORIZED;
- let errorMessage = __(
- 'An error occurred while trying to run a new pipeline for this merge request.',
- );
-
- if (unauthorized) {
- errorMessage = __('You do not have permission to run a pipeline on this branch.');
- }
-
- createAlert({
- message: errorMessage,
- primaryButton: {
- text: __('Learn more'),
- link: helpPagePath('ci/pipelines/merge_request_pipelines.md'),
- },
- });
- })
- .finally(() => this.store.toggleIsRunningPipeline(false));
- },
- onChangePage(page) {
- /* URLS parameters are strings, we need to parse to match types */
- let params = {
- page: Number(page).toString(),
- };
-
- if (this.scope) {
- params.scope = this.scope;
- }
-
- params = this.onChangeWithFilter(params);
-
- this.updateContent(params);
- },
-
- onChangeWithFilter(params) {
- return { ...params, ...validateParams(this.requestData) };
- },
- },
-};
diff --git a/app/assets/javascripts/pipelines/mixins/stage_column_mixin.js b/app/assets/javascripts/pipelines/mixins/stage_column_mixin.js
deleted file mode 100644
index 578ff498358..00000000000
--- a/app/assets/javascripts/pipelines/mixins/stage_column_mixin.js
+++ /dev/null
@@ -1,14 +0,0 @@
-export default {
- props: {
- hasUpstream: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- methods: {
- buildConnnectorClass(index) {
- return index === 0 && (!this.isFirstColumn || this.hasUpstream) ? 'left-connector' : '';
- },
- },
-};
diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
deleted file mode 100644
index f9c027539f2..00000000000
--- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import VueRouter from 'vue-router';
-import { createAlert } from '~/alert';
-import { __ } from '~/locale';
-import { pipelineTabName } from './constants';
-import { createPipelineDetailsHeaderApp } from './pipeline_details_header';
-import { apolloProvider } from './pipeline_shared_client';
-
-const SELECTORS = {
- PIPELINE_DETAILS_HEADER: '#js-pipeline-details-header-vue',
- PIPELINE_TABS: '#js-pipeline-tabs',
-};
-
-export default async function initPipelineDetailsBundle() {
- const headerSelector = SELECTORS.PIPELINE_DETAILS_HEADER;
-
- const headerApp = createPipelineDetailsHeaderApp;
-
- const headerEl = document.querySelector(headerSelector);
-
- if (headerEl) {
- const { dataset: headerDataset } = headerEl;
-
- try {
- headerApp(headerSelector, apolloProvider, headerDataset.graphqlResourceEtag);
- } catch {
- createAlert({
- message: __('An error occurred while loading a section of this page.'),
- });
- }
- }
-
- const tabsEl = document.querySelector(SELECTORS.PIPELINE_TABS);
-
- if (tabsEl) {
- const { dataset } = tabsEl;
- const { createAppOptions } = await import('ee_else_ce/pipelines/pipeline_tabs');
- const { createPipelineTabs } = await import('./pipeline_tabs');
- const { routes } = await import('ee_else_ce/pipelines/routes');
-
- const router = new VueRouter({
- mode: 'history',
- base: dataset.pipelinePath,
- routes,
- });
-
- // We handle the shortcut `pipelines/latest` by forwarding the user to the pipeline graph
- // tab and changing the route to the correct `pipelines/:id`
- if (window.location.pathname.endsWith('latest')) {
- router.replace({ name: pipelineTabName });
- }
-
- try {
- const appOptions = createAppOptions(SELECTORS.PIPELINE_TABS, apolloProvider, router);
- createPipelineTabs(appOptions);
- } catch {
- createAlert({
- message: __('An error occurred while loading a section of this page.'),
- });
- }
- }
-}
diff --git a/app/assets/javascripts/pipelines/pipeline_details_header.js b/app/assets/javascripts/pipelines/pipeline_details_header.js
deleted file mode 100644
index c79aaef23e8..00000000000
--- a/app/assets/javascripts/pipelines/pipeline_details_header.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import PipelineDetailsHeader from './components/pipeline_details_header.vue';
-
-Vue.use(VueApollo);
-
-export const createPipelineDetailsHeaderApp = (elSelector, apolloProvider, graphqlResourceEtag) => {
- const el = document.querySelector(elSelector);
-
- if (!el) {
- return;
- }
-
- const {
- fullPath,
- pipelineIid,
- pipelinesPath,
- name,
- totalJobs,
- computeMinutes,
- yamlErrors,
- failureReason,
- triggeredByPath,
- schedule,
- child,
- latest,
- mergeTrainPipeline,
- invalid,
- failed,
- autoDevops,
- detached,
- stuck,
- refText,
- } = el.dataset;
-
- // eslint-disable-next-line no-new
- new Vue({
- el,
- name: 'PipelineDetailsHeaderApp',
- apolloProvider,
- provide: {
- paths: {
- fullProject: fullPath,
- graphqlResourceEtag,
- pipelinesPath,
- triggeredByPath,
- },
- pipelineIid,
- },
- render(createElement) {
- return createElement(PipelineDetailsHeader, {
- props: {
- name,
- totalJobs,
- computeMinutes,
- yamlErrors,
- failureReason,
- refText,
- badges: {
- schedule: parseBoolean(schedule),
- child: parseBoolean(child),
- latest: parseBoolean(latest),
- mergeTrainPipeline: parseBoolean(mergeTrainPipeline),
- invalid: parseBoolean(invalid),
- failed: parseBoolean(failed),
- autoDevops: parseBoolean(autoDevops),
- detached: parseBoolean(detached),
- stuck: parseBoolean(stuck),
- },
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/pipelines/pipeline_tabs.js b/app/assets/javascripts/pipelines/pipeline_tabs.js
deleted file mode 100644
index 00a1810926c..00000000000
--- a/app/assets/javascripts/pipelines/pipeline_tabs.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import Vue from 'vue';
-import VueRouter from 'vue-router';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import VueApollo from 'vue-apollo';
-import { GlToast } from '@gitlab/ui';
-import PipelineTabs from 'ee_else_ce/pipelines/components/pipeline_tabs.vue';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import createTestReportsStore from './stores/test_reports';
-import { getPipelineDefaultTab, reportToSentry } from './utils';
-
-Vue.use(GlToast);
-Vue.use(VueApollo);
-Vue.use(VueRouter);
-Vue.use(Vuex);
-
-export const createAppOptions = (selector, apolloProvider, router) => {
- const el = document.querySelector(selector);
-
- if (!el) return null;
-
- const { dataset } = el;
- const {
- canGenerateCodequalityReports,
- codequalityReportDownloadPath,
- codequalityBlobPath,
- codequalityProjectPath,
- downloadablePathForReportType,
- exposeSecurityDashboard,
- exposeLicenseScanningData,
- failedJobsCount,
- projectPath,
- graphqlResourceEtag,
- pipelineIid,
- pipelineProjectPath,
- totalJobCount,
- licenseManagementApiUrl,
- licenseScanCount,
- licensesApiPath,
- canManageLicenses,
- summaryEndpoint,
- suiteEndpoint,
- blobPath,
- hasTestReport,
- emptyDagSvgPath,
- emptyStateImagePath,
- artifactsExpiredImagePath,
- isFullCodequalityReportAvailable,
- securityPoliciesPath,
- testsCount,
- } = dataset;
-
- const defaultTabValue = getPipelineDefaultTab(window.location.href);
-
- return {
- el,
- components: {
- PipelineTabs,
- },
- apolloProvider,
- store: new Vuex.Store({
- modules: {
- testReports: createTestReportsStore({
- blobPath,
- summaryEndpoint,
- suiteEndpoint,
- }),
- },
- }),
- router,
- provide: {
- canGenerateCodequalityReports: parseBoolean(canGenerateCodequalityReports),
- codequalityReportDownloadPath,
- codequalityBlobPath,
- codequalityProjectPath,
- isFullCodequalityReportAvailable: parseBoolean(isFullCodequalityReportAvailable),
- projectPath,
- defaultTabValue,
- downloadablePathForReportType,
- exposeSecurityDashboard: parseBoolean(exposeSecurityDashboard),
- exposeLicenseScanningData: parseBoolean(exposeLicenseScanningData),
- failedJobsCount,
- graphqlResourceEtag,
- pipelineIid,
- pipelineProjectPath,
- totalJobCount,
- licenseManagementApiUrl,
- licenseScanCount,
- licensesApiPath,
- canManageLicenses: parseBoolean(canManageLicenses),
- summaryEndpoint,
- suiteEndpoint,
- blobPath,
- hasTestReport,
- emptyDagSvgPath,
- emptyStateImagePath,
- artifactsExpiredImagePath,
- securityPoliciesPath,
- testsCount,
- },
- errorCaptured(err, _vm, info) {
- reportToSentry('pipeline_tabs', `error: ${err}, info: ${info}`);
- },
- render(createElement) {
- return createElement(PipelineTabs);
- },
- };
-};
-
-export const createPipelineTabs = (options) => {
- if (!options) return;
-
- // eslint-disable-next-line no-new
- new Vue(options);
-};
diff --git a/app/assets/javascripts/pipelines/pipelines_index.js b/app/assets/javascripts/pipelines/pipelines_index.js
deleted file mode 100644
index 20fd0915e28..00000000000
--- a/app/assets/javascripts/pipelines/pipelines_index.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import { GlToast } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createDefaultClient from '~/lib/graphql';
-import {
- parseBoolean,
- historyReplaceState,
- buildUrlWithCurrentLocation,
-} from '~/lib/utils/common_utils';
-import { doesHashExistInUrl } from '~/lib/utils/url_utility';
-import { __ } from '~/locale';
-import Translate from '~/vue_shared/translate';
-import Pipelines from './components/pipelines_list/pipelines.vue';
-import PipelinesStore from './stores/pipelines_store';
-
-Vue.use(Translate);
-Vue.use(GlToast);
-Vue.use(VueApollo);
-
-const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
-});
-
-export const initPipelinesIndex = (selector = '#pipelines-list-vue') => {
- const el = document.querySelector(selector);
- if (!el) {
- return null;
- }
-
- const {
- endpoint,
- artifactsEndpoint,
- artifactsEndpointPlaceholder,
- pipelineScheduleUrl,
- emptyStateSvgPath,
- errorStateSvgPath,
- noPipelinesSvgPath,
- newPipelinePath,
- pipelineEditorPath,
- suggestedCiTemplates,
- canCreatePipeline,
- hasGitlabCi,
- ciLintPath,
- resetCachePath,
- projectId,
- defaultBranchName,
- params,
- iosRunnersAvailable,
- registrationToken,
- fullPath,
- visibilityPipelineIdType,
- } = el.dataset;
-
- return new Vue({
- el,
- apolloProvider,
- provide: {
- pipelineEditorPath,
- artifactsEndpoint,
- artifactsEndpointPlaceholder,
- suggestedCiTemplates: JSON.parse(suggestedCiTemplates),
- iosRunnersAvailable: parseBoolean(iosRunnersAvailable),
- fullPath,
- manualActionsLimit: 50,
- },
- data() {
- return {
- store: new PipelinesStore(),
- };
- },
- created() {
- if (doesHashExistInUrl('delete_success')) {
- this.$toast.show(__('The pipeline has been deleted'));
- historyReplaceState(buildUrlWithCurrentLocation());
- }
- },
- render(createElement) {
- return createElement(Pipelines, {
- props: {
- store: this.store,
- endpoint,
- pipelineScheduleUrl,
- emptyStateSvgPath,
- errorStateSvgPath,
- noPipelinesSvgPath,
- newPipelinePath,
- canCreatePipeline: parseBoolean(canCreatePipeline),
- hasGitlabCi: parseBoolean(hasGitlabCi),
- ciLintPath,
- resetCachePath,
- projectId,
- defaultBranchName,
- params: JSON.parse(params),
- registrationToken,
- defaultVisibilityPipelineIdType: visibilityPipelineIdType,
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/pipelines/routes.js b/app/assets/javascripts/pipelines/routes.js
deleted file mode 100644
index 0e1414ec390..00000000000
--- a/app/assets/javascripts/pipelines/routes.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import PipelineGraphWrapper from './components/graph/graph_component_wrapper.vue';
-import Dag from './components/dag/dag.vue';
-import FailedJobsApp from './components/jobs/failed_jobs_app.vue';
-import JobsApp from './components/jobs/jobs_app.vue';
-import TestReports from './components/test_reports/test_reports.vue';
-import {
- pipelineTabName,
- needsTabName,
- jobsTabName,
- failedJobsTabName,
- testReportTabName,
-} from './constants';
-
-export const routes = [
- { name: pipelineTabName, path: '/', component: PipelineGraphWrapper },
- { name: needsTabName, path: '/dag', component: Dag },
- { name: jobsTabName, path: '/builds', component: JobsApp },
- { name: failedJobsTabName, path: '/failures', component: FailedJobsApp },
- { name: testReportTabName, path: '/test_report', component: TestReports },
-];
diff --git a/app/assets/javascripts/pipelines/services/pipelines_service.js b/app/assets/javascripts/pipelines/services/pipelines_service.js
deleted file mode 100644
index 3ec563c95bb..00000000000
--- a/app/assets/javascripts/pipelines/services/pipelines_service.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import Api from '~/api';
-import axios from '~/lib/utils/axios_utils';
-import { validateParams } from '../utils';
-
-export default class PipelinesService {
- /**
- * Commits and merge request endpoints need to be requested with `.json`.
- *
- * The url provided to request the pipelines in the new merge request
- * page already has `.json`.
- *
- * @param {String} root
- */
- constructor(root) {
- if (root.indexOf('.json') === -1) {
- this.endpoint = `${root}.json`;
- } else {
- this.endpoint = root;
- }
- }
-
- getPipelines(data = {}) {
- const { scope, page } = data;
- const { CancelToken } = axios;
-
- const queryParams = { scope, page, ...validateParams(data) };
-
- this.cancelationSource = CancelToken.source();
-
- return axios.get(this.endpoint, {
- params: queryParams,
- cancelToken: this.cancelationSource.token,
- });
- }
-
- /**
- * Post request for all pipelines actions.
- *
- * @param {String} endpoint
- * @return {Promise}
- */
- // eslint-disable-next-line class-methods-use-this
- postAction(endpoint) {
- return axios.post(`${endpoint}.json`);
- }
-
- // eslint-disable-next-line class-methods-use-this
- runMRPipeline({ projectId, mergeRequestId }) {
- return Api.postMergeRequestPipeline(projectId, { mergeRequestId });
- }
-}
diff --git a/app/assets/javascripts/pipelines/utils.js b/app/assets/javascripts/pipelines/utils.js
deleted file mode 100644
index 38be5becfb8..00000000000
--- a/app/assets/javascripts/pipelines/utils.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import * as Sentry from '@sentry/browser';
-import { pickBy } from 'lodash';
-import { parseUrlPathname } from '~/lib/utils/url_utility';
-import {
- NEEDS_PROPERTY,
- SUPPORTED_FILTER_PARAMETERS,
- validPipelineTabNames,
- pipelineTabName,
-} from './constants';
-/*
- The following functions are the main engine in transforming the data as
- received from the endpoint into the format the d3 graph expects.
-
- Input is of the form:
- [nodes]
- nodes: [{category, name, jobs, size}]
- category is the stage name
- name is a group name; in the case that the group has one job, it is
- also the job name
- size is the number of parallel jobs
- jobs: [{ name, needs}]
- job name is either the same as the group name or group x/y
- needs: [job-names]
- needs is an array of job-name strings
-
- Output is of the form:
- { nodes: [node], links: [link] }
- node: { name, category }, + unused info passed through
- link: { source, target, value }, with source & target being node names
- and value being a constant
-
- We create nodes in the GraphQL update function, and then here we create the node dictionary,
- then create links, and then dedupe the links, so that in the case where
- job 4 depends on job 1 and job 2, and job 2 depends on job 1, we show only a single link
- from job 1 to job 2 then another from job 2 to job 4.
-
- CREATE LINKS
- nodes.name -> target
- nodes.name.needs.each -> source (source is the name of the group, not the parallel job)
- 10 -> value (constant)
- */
-
-export const createNodeDict = (nodes, { needsKey = NEEDS_PROPERTY } = {}) => {
- return nodes.reduce((acc, node) => {
- const newNode = {
- ...node,
- needs: node.jobs.map((job) => job[needsKey] || []).flat(),
- };
-
- if (node.size > 1) {
- node.jobs.forEach((job) => {
- acc[job.name] = newNode;
- });
- }
-
- acc[node.name] = newNode;
- return acc;
- }, {});
-};
-
-export const validateParams = (params) => {
- return pickBy(params, (val, key) => SUPPORTED_FILTER_PARAMETERS.includes(key) && val);
-};
-
-/**
- * This function takes the stages array and transform it
- * into a hash where each key is a job name and the job data
- * is associated to that key.
- * @param {Array} stages
- * @returns {Object} - Hash of jobs
- */
-export const createJobsHash = (stages = []) => {
- const nodes = stages.flatMap(({ groups }) => groups);
- return createNodeDict(nodes);
-};
-
-/**
- * This function takes the jobs hash generated by
- * `createJobsHash` function and returns an easier
- * structure to work with for needs relationship
- * where the key is the job name and the value is an
- * array of all the needs this job has recursively
- * (includes the needs of the needs)
- * @param {Object} jobs
- * @returns {Object} - Hash of jobs and array of needs
- */
-export const generateJobNeedsDict = (jobs = {}) => {
- const arrOfJobNames = Object.keys(jobs);
-
- return arrOfJobNames.reduce((acc, value) => {
- const recursiveNeeds = (jobName) => {
- if (!jobs[jobName]?.needs) {
- return [];
- }
-
- return jobs[jobName].needs
- .reduce((needsAcc, job) => {
- // It's possible that a needs refer to an optional job
- // that is not defined in which case we don't add that entry
- if (!jobs[job]) {
- return needsAcc;
- }
-
- // If we already have the needs of a job in the accumulator,
- // then we use the memoized data instead of the recursive call
- // to save some performance.
- const newNeeds = acc[job] ?? recursiveNeeds(job);
-
- // In case it's a parallel job (size > 1), the name of the group
- // and the job will be different. This mean we also need to add the group name
- // to the list of `needs` to ensure we can properly reference it.
- const group = jobs[job];
- if (group.size > 1) {
- return [...needsAcc, job, group.name, newNeeds];
- }
-
- return [...needsAcc, job, newNeeds];
- }, [])
- .flat(Infinity);
- };
-
- // To ensure we don't have duplicates job relationship when 2 jobs
- // needed by another both depends on the same jobs, we remove any
- // duplicates from the array.
- const uniqueValues = Array.from(new Set(recursiveNeeds(value)));
-
- return { ...acc, [value]: uniqueValues };
- }, {});
-};
-
-export const reportToSentry = (component, failureType) => {
- Sentry.withScope((scope) => {
- scope.setTag('component', component);
- Sentry.captureException(failureType);
- });
-};
-
-export const reportMessageToSentry = (component, message, context) => {
- Sentry.withScope((scope) => {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- scope.setContext('Vue data', context);
- scope.setTag('component', component);
- Sentry.captureMessage(message);
- });
-};
-
-export const getPipelineDefaultTab = (url) => {
- const strippedUrl = parseUrlPathname(url);
- const regexp = /\w*$/;
- const [tabName] = strippedUrl.match(regexp);
-
- if (tabName && validPipelineTabNames.includes(tabName)) return tabName;
- if (tabName === '') return pipelineTabName;
-
- return null;
-};
diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js
index e21f8557d68..947bf7acd5c 100644
--- a/app/assets/javascripts/profile/profile.js
+++ b/app/assets/javascripts/profile/profile.js
@@ -30,7 +30,6 @@ export default class Profile {
bindEvents() {
$('.js-preferences-form').on('change.preference', 'input[type=radio]', this.submitForm);
- $('#user_email_opted_in').on('change', this.submitForm);
$('#user_notified_of_own_activity').on('change', this.submitForm);
this.form.on('submit', this.onSubmitForm);
}
diff --git a/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue b/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue
index 6ff9bd7390f..b7355b909a1 100644
--- a/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue
+++ b/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue
@@ -2,16 +2,13 @@
import { GlLoadingIcon } from '@gitlab/ui';
import { createAlert } from '~/alert';
import { __ } from '~/locale';
-import {
- getQueryHeaders,
- toggleQueryPollingByVisibility,
-} from '~/pipelines/components/graph/utils';
-import { keepLatestDownstreamPipelines } from '~/pipelines/components/parsing_utils';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
+import { getQueryHeaders, toggleQueryPollingByVisibility } from '~/ci/pipeline_details/graph/utils';
+import { keepLatestDownstreamPipelines } from '~/ci/pipeline_details/utils/parsing_utils';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import PipelineMiniGraph from '~/ci/pipeline_mini_graph/pipeline_mini_graph.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import getLinkedPipelinesQuery from '~/pipelines/graphql/queries/get_linked_pipelines.query.graphql';
-import getPipelineStagesQuery from '~/pipelines/graphql/queries/get_pipeline_stages.query.graphql';
+import getLinkedPipelinesQuery from '~/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql';
+import getPipelineStagesQuery from '~/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stages.query.graphql';
import { formatStages } from '../utils';
import { COMMIT_BOX_POLL_INTERVAL } from '../constants';
diff --git a/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_status.vue b/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_status.vue
index 71f53613a3b..ccecc914cf1 100644
--- a/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_status.vue
+++ b/app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_status.vue
@@ -2,10 +2,7 @@
import { GlLoadingIcon, GlLink } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import { createAlert } from '~/alert';
-import {
- getQueryHeaders,
- toggleQueryPollingByVisibility,
-} from '~/pipelines/components/graph/utils';
+import { getQueryHeaders, toggleQueryPollingByVisibility } from '~/ci/pipeline_details/graph/utils';
import getLatestPipelineStatusQuery from '../graphql/queries/get_latest_pipeline_status.query.graphql';
import { COMMIT_BOX_POLL_INTERVAL, PIPELINE_STATUS_FETCH_ERROR } from '../constants';
diff --git a/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue b/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue
deleted file mode 100644
index 034bae3066d..00000000000
--- a/app/assets/javascripts/projects/compare/components/revision_dropdown_legacy.vue
+++ /dev/null
@@ -1,156 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlDropdownSectionHeader } from '@gitlab/ui';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { s__ } from '~/locale';
-
-export default {
- components: {
- GlDropdown,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlSearchBoxByType,
- },
- props: {
- refsProjectPath: {
- type: String,
- required: true,
- },
- revisionText: {
- type: String,
- required: true,
- },
- paramsName: {
- type: String,
- required: true,
- },
- paramsBranch: {
- type: String,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- branches: [],
- tags: [],
- loading: true,
- searchTerm: '',
- selectedRevision: this.getDefaultBranch(),
- };
- },
- computed: {
- filteredBranches() {
- return this.branches.filter((branch) =>
- branch.toLowerCase().includes(this.searchTerm.toLowerCase()),
- );
- },
- hasFilteredBranches() {
- return this.filteredBranches.length;
- },
- filteredTags() {
- return this.tags.filter((tag) => tag.toLowerCase().includes(this.searchTerm.toLowerCase()));
- },
- hasFilteredTags() {
- return this.filteredTags.length;
- },
- },
- watch: {
- paramsBranch(newBranch) {
- this.setSelectedRevision(newBranch);
- },
- },
- mounted() {
- this.fetchBranchesAndTags();
- },
- methods: {
- fetchBranchesAndTags() {
- const endpoint = this.refsProjectPath;
-
- return axios
- .get(endpoint)
- .then(({ data }) => {
- this.branches = data.Branches || [];
- this.tags = data.Tags || [];
- })
- .catch(() => {
- createAlert({
- message: `${s__(
- 'CompareRevisions|There was an error while updating the branch/tag list. Please try again.',
- )}`,
- });
- })
- .finally(() => {
- this.loading = false;
- });
- },
- getDefaultBranch() {
- return this.paramsBranch || s__('CompareRevisions|Select branch/tag');
- },
- onClick(revision) {
- this.setSelectedRevision(revision);
- },
- onSearchEnter() {
- this.setSelectedRevision(this.searchTerm);
- },
- setSelectedRevision(revision) {
- this.selectedRevision = revision || s__('CompareRevisions|Select branch/tag');
- this.$emit('selectRevision', { direction: this.paramsName, revision });
- },
- },
-};
-</script>
-
-<template>
- <div class="form-group compare-form-group" :class="`js-compare-${paramsName}-dropdown`">
- <div class="input-group inline-input-group">
- <span class="input-group-prepend">
- <div class="input-group-text">
- {{ revisionText }}
- </div>
- </span>
- <input type="hidden" :name="paramsName" :value="selectedRevision" />
- <gl-dropdown
- class="gl-flex-grow-1 gl-flex-basis-0 gl-min-w-0 gl-font-monospace"
- toggle-class="form-control compare-dropdown-toggle gl-min-w-0 gl-rounded-top-left-none! gl-rounded-bottom-left-none!"
- :text="selectedRevision"
- header-text="Select Git revision"
- :loading="loading"
- >
- <template #header>
- <gl-search-box-by-type
- v-model.trim="searchTerm"
- :placeholder="s__('CompareRevisions|Filter by Git revision')"
- @keyup.enter="onSearchEnter"
- />
- </template>
- <gl-dropdown-section-header v-if="hasFilteredBranches">
- {{ s__('CompareRevisions|Branches') }}
- </gl-dropdown-section-header>
- <gl-dropdown-item
- v-for="(branch, index) in filteredBranches"
- :key="`branch${index}`"
- is-check-item
- :is-checked="selectedRevision === branch"
- data-testid="branches-dropdown-item"
- @click="onClick(branch)"
- >
- {{ branch }}
- </gl-dropdown-item>
- <gl-dropdown-section-header v-if="hasFilteredTags">
- {{ s__('CompareRevisions|Tags') }}
- </gl-dropdown-section-header>
- <gl-dropdown-item
- v-for="(tag, index) in filteredTags"
- :key="`tag${index}`"
- is-check-item
- :is-checked="selectedRevision === tag"
- data-testid="tags-dropdown-item"
- @click="onClick(tag)"
- >
- {{ tag }}
- </gl-dropdown-item>
- </gl-dropdown>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/projects/pipelines/charts/constants.js b/app/assets/javascripts/projects/pipelines/charts/constants.js
index c13824a9952..dcec77ac6a4 100644
--- a/app/assets/javascripts/projects/pipelines/charts/constants.js
+++ b/app/assets/javascripts/projects/pipelines/charts/constants.js
@@ -21,5 +21,5 @@ export const LOAD_PIPELINES_FAILURE = 'load_analytics_failure';
export const UNSUPPORTED_DATA = 'unsupported_data';
export const SNOWPLOW_LABEL = 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly';
-export const SNOWPLOW_SCHEMA = 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-0';
+export const SNOWPLOW_SCHEMA = 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-1';
export const SNOWPLOW_DATA_SOURCE = 'redis_hll';
diff --git a/app/assets/javascripts/projects/project_star_button.js b/app/assets/javascripts/projects/project_star_button.js
new file mode 100644
index 00000000000..06f982b500d
--- /dev/null
+++ b/app/assets/javascripts/projects/project_star_button.js
@@ -0,0 +1,46 @@
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { spriteIcon } from '~/lib/utils/common_utils';
+import { __, s__ } from '~/locale';
+
+export function initStarButton(containerSelector = '.project-home-panel') {
+ const container = document.querySelector(containerSelector);
+ const starToggle = container?.querySelector('.toggle-star');
+
+ if (!starToggle) {
+ return;
+ }
+
+ starToggle.addEventListener('click', function toggleStarClickCallback() {
+ const starSpan = starToggle.querySelector('span');
+ const starIcon = starToggle.querySelector('svg');
+ const iconClasses = Array.from(starIcon.classList.values());
+
+ axios
+ .post(starToggle.dataset.endpoint)
+ .then(({ data }) => {
+ const isStarred = starSpan.classList.contains('starred');
+ starToggle.parentNode.querySelector('.count').textContent = data.star_count;
+
+ if (isStarred) {
+ starSpan.classList.remove('starred');
+ starSpan.textContent = s__('StarProject|Star');
+ starIcon.remove();
+ // eslint-disable-next-line no-unsanitized/method
+ starSpan.insertAdjacentHTML('beforebegin', spriteIcon('star-o', iconClasses));
+ } else {
+ starSpan.classList.add('starred');
+ starSpan.textContent = __('Unstar');
+ starIcon.remove();
+
+ // eslint-disable-next-line no-unsanitized/method
+ starSpan.insertAdjacentHTML('beforebegin', spriteIcon('star', iconClasses));
+ }
+ })
+ .catch(() =>
+ createAlert({
+ message: __('Star toggle failed. Try again later.'),
+ }),
+ );
+ });
+}
diff --git a/app/assets/javascripts/projects/settings/access_dropdown.js b/app/assets/javascripts/projects/settings/access_dropdown.js
deleted file mode 100644
index 75d72f719e5..00000000000
--- a/app/assets/javascripts/projects/settings/access_dropdown.js
+++ /dev/null
@@ -1,611 +0,0 @@
-/* eslint-disable no-underscore-dangle, class-methods-use-this */
-import { escape, find, countBy } from 'lodash';
-import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import { createAlert } from '~/alert';
-import { n__, s__, __, sprintf } from '~/locale';
-import { renderAvatar } from '~/helpers/avatar_helper';
-import { getUsers, getGroups, getDeployKeys } from './api/access_dropdown_api';
-import { LEVEL_TYPES, LEVEL_ID_PROP, ACCESS_LEVELS, ACCESS_LEVEL_NONE } from './constants';
-
-export default class AccessDropdown {
- constructor(options) {
- const { $dropdown, accessLevel, accessLevelsData, hasLicense = true } = options;
- this.options = options;
- this.hasLicense = hasLicense;
- this.groups = [];
- this.accessLevel = accessLevel;
- this.accessLevelsData = accessLevelsData.roles;
- this.$dropdown = $dropdown;
- this.$wrap = this.$dropdown.closest(`.${this.accessLevel}-container`);
- this.defaultLabel = this.$dropdown.data('defaultLabel');
-
- this.setSelectedItems([]);
- this.persistPreselectedItems();
-
- this.noOneObj = this.accessLevelsData.find((level) => level.id === ACCESS_LEVEL_NONE);
-
- this.initDropdown();
- }
-
- initDropdown() {
- const { onSelect, onHide } = this.options;
- initDeprecatedJQueryDropdown(this.$dropdown, {
- data: this.getData.bind(this),
- selectable: true,
- filterable: true,
- filterRemote: true,
- multiSelect: this.$dropdown.hasClass('js-multiselect'),
- renderRow: this.renderRow.bind(this),
- toggleLabel: this.toggleLabel.bind(this),
- hidden() {
- if (onHide) {
- onHide();
- }
- },
- clicked: (options) => {
- const { $el, e } = options;
- const item = options.selectedObj;
- const fossWithMergeAccess = !this.hasLicense && this.accessLevel === ACCESS_LEVELS.MERGE;
-
- e.preventDefault();
-
- if (fossWithMergeAccess) {
- // We're not multiselecting quite yet in "Merge" access dropdown, on FOSS:
- // remove all preselected items before selecting this item
- // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37499
- this.accessLevelsData.forEach((level) => {
- this.removeSelectedItem(level);
- });
- }
-
- if ($el.is('.is-active')) {
- if (this.noOneObj) {
- if (item.id === this.noOneObj.id && !fossWithMergeAccess) {
- // remove all others selected items
- this.accessLevelsData.forEach((level) => {
- if (level.id !== item.id) {
- this.removeSelectedItem(level);
- }
- });
-
- // remove selected item visually
- this.$wrap.find(`.item-${item.type}`).removeClass('is-active');
- } else {
- const $noOne = this.$wrap.find(
- `.is-active.item-${item.type}[data-role-id="${this.noOneObj.id}"]`,
- );
- if ($noOne.length) {
- $noOne.removeClass('is-active');
- this.removeSelectedItem(this.noOneObj);
- }
- }
- }
-
- // make element active right away
- $el.addClass(`is-active item-${item.type}`);
-
- // Add "No one"
- this.addSelectedItem(item);
- } else {
- this.removeSelectedItem(item);
- }
-
- if (onSelect) {
- onSelect(item, $el, this);
- }
- },
- });
-
- this.$dropdown.find('.dropdown-toggle-text').text(this.toggleLabel());
- }
-
- persistPreselectedItems() {
- const itemsToPreselect = this.$dropdown.data('preselectedItems');
-
- if (!itemsToPreselect || !itemsToPreselect.length) {
- return;
- }
-
- const persistedItems = itemsToPreselect.map((item) => {
- const persistedItem = { ...item };
- persistedItem.persisted = true;
- return persistedItem;
- });
-
- this.setSelectedItems(persistedItems);
- }
-
- setSelectedItems(items = []) {
- this.items = items;
- }
-
- getSelectedItems() {
- return this.items.filter((item) => !item._destroy);
- }
-
- getAllSelectedItems() {
- return this.items;
- }
-
- // Return dropdown as input data ready to submit
- getInputData() {
- const selectedItems = this.getAllSelectedItems();
-
- const accessLevels = selectedItems.map((item) => {
- const obj = {};
-
- if (typeof item.id !== 'undefined') {
- obj.id = item.id;
- }
-
- if (typeof item._destroy !== 'undefined') {
- obj._destroy = item._destroy;
- }
-
- if (item.type === LEVEL_TYPES.ROLE) {
- obj.access_level = item.access_level;
- } else if (item.type === LEVEL_TYPES.USER) {
- obj.user_id = item.user_id;
- } else if (item.type === LEVEL_TYPES.DEPLOY_KEY) {
- obj.deploy_key_id = item.deploy_key_id;
- } else if (item.type === LEVEL_TYPES.GROUP) {
- obj.group_id = item.group_id;
- }
-
- return obj;
- });
-
- return accessLevels;
- }
-
- addSelectedItem(selectedItem) {
- let itemToAdd = {};
-
- let index = -1;
- let alreadyAdded = false;
- const selectedItems = this.getAllSelectedItems();
-
- // Compare IDs based on selectedItem.type
- selectedItems.forEach((item, i) => {
- let comparator;
- switch (selectedItem.type) {
- case LEVEL_TYPES.ROLE:
- comparator = LEVEL_ID_PROP.ROLE;
- // If the item already exists, just use it
- if (item[comparator] === selectedItem.id) {
- alreadyAdded = true;
- }
- break;
- case LEVEL_TYPES.GROUP:
- comparator = LEVEL_ID_PROP.GROUP;
- break;
- case LEVEL_TYPES.DEPLOY_KEY:
- comparator = LEVEL_ID_PROP.DEPLOY_KEY;
- break;
- case LEVEL_TYPES.USER:
- comparator = LEVEL_ID_PROP.USER;
- break;
- default:
- break;
- }
-
- if (selectedItem.id === item[comparator]) {
- index = i;
- }
- });
-
- if (alreadyAdded) {
- return;
- }
-
- if (index !== -1 && selectedItems[index]._destroy) {
- delete selectedItems[index]._destroy;
- return;
- }
-
- itemToAdd.type = selectedItem.type;
-
- if (selectedItem.type === LEVEL_TYPES.USER) {
- itemToAdd = {
- user_id: selectedItem.id,
- name: selectedItem.name || '_name1',
- username: selectedItem.username || '_username1',
- avatar_url: selectedItem.avatar_url || '_avatar_url1',
- type: LEVEL_TYPES.USER,
- };
- } else if (selectedItem.type === LEVEL_TYPES.ROLE) {
- itemToAdd = {
- access_level: selectedItem.id,
- type: LEVEL_TYPES.ROLE,
- };
- } else if (selectedItem.type === LEVEL_TYPES.GROUP) {
- itemToAdd = {
- group_id: selectedItem.id,
- type: LEVEL_TYPES.GROUP,
- };
- } else if (selectedItem.type === LEVEL_TYPES.DEPLOY_KEY) {
- itemToAdd = {
- deploy_key_id: selectedItem.id,
- type: LEVEL_TYPES.DEPLOY_KEY,
- };
- }
-
- this.items.push(itemToAdd);
- }
-
- removeSelectedItem(itemToDelete) {
- let index = -1;
- const selectedItems = this.getAllSelectedItems();
-
- // To find itemToDelete on selectedItems, first we need the index
- selectedItems.every((item, i) => {
- if (item.type !== itemToDelete.type) {
- return true;
- }
-
- if (
- (item.type === LEVEL_TYPES.USER && item.user_id === itemToDelete.id) ||
- (item.type === LEVEL_TYPES.ROLE && item.access_level === itemToDelete.id) ||
- (item.type === LEVEL_TYPES.DEPLOY_KEY && item.deploy_key_id === itemToDelete.id) ||
- (item.type === LEVEL_TYPES.GROUP && item.group_id === itemToDelete.id)
- ) {
- index = i;
- }
-
- // Break once we have index set
- return !(index > -1);
- });
-
- // if ItemToDelete is not really selected do nothing
- if (index === -1) {
- return;
- }
-
- if (selectedItems[index].persisted) {
- // If we toggle an item that has been already marked with _destroy
- if (selectedItems[index]._destroy) {
- delete selectedItems[index]._destroy;
- } else {
- selectedItems[index]._destroy = '1';
- }
- } else {
- selectedItems.splice(index, 1);
- }
- }
-
- toggleLabel() {
- const currentItems = this.getSelectedItems();
- const $dropdownToggleText = this.$dropdown.find('.dropdown-toggle-text');
-
- if (currentItems.length === 0) {
- $dropdownToggleText.addClass('is-default');
- return this.defaultLabel;
- }
-
- $dropdownToggleText.removeClass('is-default');
-
- if (currentItems.length === 1 && currentItems[0].type === LEVEL_TYPES.ROLE) {
- const roleData = this.accessLevelsData.find(
- (data) => data.id === currentItems[0].access_level,
- );
- return roleData.text;
- }
-
- const labelPieces = [];
- const counts = countBy(currentItems, (item) => item.type);
-
- if (counts[LEVEL_TYPES.ROLE] > 0) {
- labelPieces.push(n__('1 role', '%d roles', counts[LEVEL_TYPES.ROLE]));
- }
-
- if (counts[LEVEL_TYPES.USER] > 0) {
- labelPieces.push(n__('1 user', '%d users', counts[LEVEL_TYPES.USER]));
- }
-
- if (counts[LEVEL_TYPES.DEPLOY_KEY] > 0) {
- labelPieces.push(n__('1 deploy key', '%d deploy keys', counts[LEVEL_TYPES.DEPLOY_KEY]));
- }
-
- if (counts[LEVEL_TYPES.GROUP] > 0) {
- labelPieces.push(n__('1 group', '%d groups', counts[LEVEL_TYPES.GROUP]));
- }
-
- return labelPieces.join(', ');
- }
-
- getData(query, callback) {
- if (this.hasLicense) {
- Promise.all([
- getDeployKeys(query),
- getUsers(query),
- this.groupsData ? Promise.resolve(this.groupsData) : getGroups(),
- ])
- .then(([deployKeysResponse, usersResponse, groupsResponse]) => {
- this.groupsData = groupsResponse;
- callback(
- this.consolidateData(deployKeysResponse.data, usersResponse.data, groupsResponse.data),
- );
- })
- .catch(() => {
- createAlert({ message: __('Failed to load groups, users and deploy keys.') });
- });
- } else {
- getDeployKeys(query)
- .then((deployKeysResponse) => callback(this.consolidateData(deployKeysResponse.data)))
- .catch(() => createAlert({ message: __('Failed to load deploy keys.') }));
- }
- }
-
- consolidateData(deployKeysResponse, usersResponse = [], groupsResponse = []) {
- let consolidatedData = [];
-
- // ID property is handled differently locally from the server
- //
- // For Groups
- // In dropdown: `id`
- // For submit: `group_id`
- //
- // For Roles
- // In dropdown: `id`
- // For submit: `access_level`
- //
- // For Users
- // In dropdown: `id`
- // For submit: `user_id`
- //
- // For Deploy Keys
- // In dropdown: `id`
- // For submit: `deploy_key_id`
-
- /*
- * Build roles
- */
- const roles = this.accessLevelsData.map((level) => {
- /* eslint-disable no-param-reassign */
- // This re-assignment is intentional as
- // level.type property is being used in removeSelectedItem()
- // for comparision, and accessLevelsData is provided by
- // gon.create_access_levels which doesn't have `type` included.
- // See this discussion https://gitlab.com/gitlab-org/gitlab/merge_requests/1629#note_31285823
- level.type = LEVEL_TYPES.ROLE;
- return level;
- });
-
- if (roles.length) {
- consolidatedData = consolidatedData.concat(
- [{ type: 'header', content: s__('AccessDropdown|Roles') }],
- roles,
- );
- }
-
- if (this.hasLicense) {
- const map = [];
- const selectedItems = this.getSelectedItems();
- /*
- * Build groups
- */
- const groups = groupsResponse.map((group) => ({
- ...group,
- type: LEVEL_TYPES.GROUP,
- }));
-
- /*
- * Build users
- */
- const users = selectedItems
- .filter((item) => item.type === LEVEL_TYPES.USER)
- .map((item) => {
- // Save identifiers for easy-checking more later
- map.push(LEVEL_TYPES.USER + item.user_id);
-
- return {
- id: item.user_id,
- name: item.name,
- username: item.username,
- avatar_url: item.avatar_url,
- type: LEVEL_TYPES.USER,
- };
- });
-
- // Has to be checked against server response
- // because the selected item can be in filter results
- if (gon.current_project_id) {
- usersResponse.forEach((response) => {
- // Add is it has not been added
- if (map.indexOf(LEVEL_TYPES.USER + response.id) === -1) {
- const user = { ...response };
- user.type = LEVEL_TYPES.USER;
- users.push(user);
- }
- });
- }
-
- if (groups.length) {
- if (roles.length) {
- consolidatedData = consolidatedData.concat([{ type: 'divider' }]);
- }
-
- consolidatedData = consolidatedData.concat(
- [{ type: 'header', content: s__('AccessDropdown|Groups') }],
- groups,
- );
- }
-
- if (users.length) {
- consolidatedData = consolidatedData.concat(
- [{ type: 'divider' }],
- [{ type: 'header', content: s__('AccessDropdown|Users') }],
- users,
- );
- }
- }
-
- const deployKeys = deployKeysResponse.map((response) => {
- const {
- id,
- fingerprint,
- fingerprint_sha256: fingerprintSha256,
- title,
- owner: { avatar_url, name, username },
- } = response;
-
- const availableFingerprint = fingerprintSha256 || fingerprint;
- const shortFingerprint = `(${availableFingerprint.substring(0, 14)}...)`;
-
- return {
- id,
- title: title.concat(' ', shortFingerprint),
- avatar_url,
- fullname: name,
- username,
- type: LEVEL_TYPES.DEPLOY_KEY,
- };
- });
-
- if (this.accessLevel === ACCESS_LEVELS.PUSH) {
- if (deployKeys.length) {
- consolidatedData = consolidatedData.concat(
- [{ type: 'divider' }],
- [{ type: 'header', content: s__('AccessDropdown|Deploy Keys') }],
- deployKeys,
- );
- }
- }
-
- if (this.accessLevel === ACCESS_LEVELS.CREATE && deployKeys.length) {
- consolidatedData = consolidatedData.concat(
- [{ type: 'divider' }],
- [{ type: 'header', content: s__('AccessDropdown|Deploy Keys') }],
- deployKeys,
- );
- }
-
- return consolidatedData;
- }
-
- renderRow(item) {
- let criteria = {};
- let groupRowEl;
-
- // Dectect if the current item is already saved so we can add
- // the `is-active` class so the item looks as marked
- switch (item.type) {
- case LEVEL_TYPES.USER:
- criteria = { user_id: item.id };
- break;
- case LEVEL_TYPES.ROLE:
- criteria = { access_level: item.id };
- break;
- case LEVEL_TYPES.DEPLOY_KEY:
- criteria = { deploy_key_id: item.id };
- break;
- case LEVEL_TYPES.GROUP:
- criteria = { group_id: item.id };
- break;
- default:
- break;
- }
-
- const isActive = find(this.getSelectedItems(), criteria) ? 'is-active' : '';
-
- switch (item.type) {
- case LEVEL_TYPES.USER:
- groupRowEl = this.userRowHtml(item, isActive);
- break;
- case LEVEL_TYPES.ROLE:
- groupRowEl = this.roleRowHtml(item, isActive);
- break;
- case LEVEL_TYPES.DEPLOY_KEY:
- groupRowEl =
- this.accessLevel === ACCESS_LEVELS.PUSH || this.accessLevel === ACCESS_LEVELS.CREATE
- ? this.deployKeyRowHtml(item, isActive)
- : '';
-
- break;
- case LEVEL_TYPES.GROUP:
- groupRowEl = this.groupRowHtml(item, isActive);
- break;
- default:
- groupRowEl = '';
- break;
- }
-
- return groupRowEl;
- }
-
- userRowHtml(user, isActive) {
- const isActiveClass = isActive || '';
- const avatarEl = renderAvatar(user, {
- sizeClass: 's32',
- });
-
- return `
- <li>
- <a href="#" class="${isActiveClass}">
- <div class="gl-avatar-labeled">
- ${avatarEl}
- <div>
- <strong class="dropdown-menu-user-full-name">${escape(user.name)}</strong>
- <span class="gl-avatar-labeled-sublabel dropdown-menu-user-username">@${
- user.username
- }</span>
- </div>
- </div>
- </a>
- </li>
- `;
- }
-
- deployKeyRowHtml(key, isActive) {
- const isActiveClass = isActive || '';
-
- return `
- <li>
- <a href="#" class="${isActiveClass}">
- <strong>${escape(key.title)}</strong>
- <p>
- ${sprintf(
- __('Owned by %{image_tag}'),
- {
- image_tag: `<img src="${key.avatar_url}" class="avatar avatar-inline s26" width="30">`,
- },
- false,
- )}
- <strong class="dropdown-menu-user-full-name gl-display-inline">${escape(
- key.fullname,
- )}</strong>
- <span class="dropdown-menu-user-username gl-display-inline">${key.username}</span>
- </p>
- </a>
- </li>
- `;
- }
-
- groupRowHtml(group, isActive) {
- const isActiveClass = isActive || '';
- const avatarEl = group.avatar_url
- ? `<img src="${group.avatar_url}" class="avatar avatar-inline" width="30">`
- : '';
-
- return `
- <li>
- <a href="#" class="${isActiveClass}">
- ${avatarEl}
- <span class="dropdown-menu-group-groupname">${group.name}</span>
- </a>
- </li>
- `;
- }
-
- roleRowHtml(role, isActive) {
- const isActiveClass = isActive || '';
-
- return `
- <li>
- <a href="#" class="${isActiveClass} item-${role.type}" data-role-id="${role.id}">
- ${escape(role.text)}
- </a>
- </li>
- `;
- }
-}
diff --git a/app/assets/javascripts/projects/settings/api/access_dropdown_api.js b/app/assets/javascripts/projects/settings/api/access_dropdown_api.js
index df99aac6b9e..b886bf43b57 100644
--- a/app/assets/javascripts/projects/settings/api/access_dropdown_api.js
+++ b/app/assets/javascripts/projects/settings/api/access_dropdown_api.js
@@ -1,7 +1,9 @@
+import Api from '~/api';
import axios from '~/lib/utils/axios_utils';
+import { ACCESS_LEVEL_DEVELOPER_INTEGER } from '~/access_level/constants';
-const USERS_PATH = '/-/autocomplete/users.json';
const GROUPS_PATH = '/-/autocomplete/project_groups.json';
+const USERS_PATH = '/-/autocomplete/users.json';
const DEPLOY_KEYS_PATH = '/-/autocomplete/deploy_keys_with_owners.json';
const buildUrl = (urlRoot, url) => {
@@ -26,10 +28,14 @@ export const getUsers = (query, states) => {
};
export const getGroups = () => {
- return axios.get(buildUrl(gon.relative_url_root || '', GROUPS_PATH), {
- params: {
- project_id: gon.current_project_id,
- },
+ if (gon.current_project_id) {
+ return Api.projectGroups(gon.current_project_id, {
+ with_shared: true,
+ shared_min_access_level: ACCESS_LEVEL_DEVELOPER_INTEGER,
+ });
+ }
+ return axios.get(buildUrl(gon.relative_url_root || '', GROUPS_PATH)).then(({ data }) => {
+ return data;
});
};
diff --git a/app/assets/javascripts/projects/settings/components/access_dropdown.vue b/app/assets/javascripts/projects/settings/components/access_dropdown.vue
index a2e4827cbfa..ca24e948f69 100644
--- a/app/assets/javascripts/projects/settings/components/access_dropdown.vue
+++ b/app/assets/javascripts/projects/settings/components/access_dropdown.vue
@@ -12,13 +12,14 @@ import { debounce, intersectionWith, groupBy, differenceBy, intersectionBy } fro
import { createAlert } from '~/alert';
import { __, s__, n__ } from '~/locale';
import { getUsers, getGroups, getDeployKeys } from '../api/access_dropdown_api';
-import { LEVEL_TYPES, ACCESS_LEVELS } from '../constants';
+import { LEVEL_TYPES, ACCESS_LEVELS, ACCESS_LEVEL_NONE } from '../constants';
export const i18n = {
- selectUsers: s__('ProtectedEnvironment|Select users'),
+ defaultLabel: s__('AccessDropdown|Select'),
rolesSectionHeader: s__('AccessDropdown|Roles'),
groupsSectionHeader: s__('AccessDropdown|Groups'),
usersSectionHeader: s__('AccessDropdown|Users'),
+ noRole: s__('AccessDropdown|No role'),
deployKeysSectionHeader: s__('AccessDropdown|Deploy Keys'),
ownedBy: __('Owned by %{image_tag}'),
};
@@ -51,7 +52,7 @@ export default {
label: {
type: String,
required: false,
- default: i18n.selectUsers,
+ default: i18n.defaultLabel,
},
disabled: {
type: Boolean,
@@ -68,6 +69,31 @@ export default {
required: false,
default: () => [],
},
+ toggleClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ searchEnabled: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ block: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ testId: {
+ type: String,
+ required: false,
+ default: undefined,
+ },
+ showUsers: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
@@ -96,6 +122,9 @@ export default {
this.deployKeys.length
);
},
+ isAccessesLevelNoneSelected() {
+ return this.selected.role[0].id === ACCESS_LEVEL_NONE;
+ },
toggleLabel() {
const counts = Object.entries(this.selected).reduce((acc, [key, value]) => {
acc[key] = value.length;
@@ -115,7 +144,11 @@ export default {
const labelPieces = [];
if (counts[LEVEL_TYPES.ROLE] > 0) {
- labelPieces.push(n__('1 role', '%d roles', counts[LEVEL_TYPES.ROLE]));
+ if (this.isAccessesLevelNoneSelected) {
+ labelPieces.push(this.$options.i18n.noRole);
+ } else {
+ labelPieces.push(n__('1 role', '%d roles', counts[LEVEL_TYPES.ROLE]));
+ }
}
if (counts[LEVEL_TYPES.USER] > 0) {
@@ -132,8 +165,14 @@ export default {
return labelPieces.join(', ') || this.label;
},
- toggleClass() {
- return this.toggleLabel === this.label ? 'gl-text-gray-500!' : '';
+ fossWithMergeAccess() {
+ return !this.hasLicense && this.accessLevel === ACCESS_LEVELS.MERGE;
+ },
+ dropdownToggleClass() {
+ return {
+ 'gl-text-gray-500!': this.toggleLabel === this.label,
+ [this.toggleClass]: true,
+ };
},
selection() {
return [
@@ -180,7 +219,7 @@ export default {
);
},
focusInput() {
- this.$refs.search.focusInput();
+ this.$refs.search?.focusInput();
},
getData({ initial = false } = {}) {
this.initialLoading = initial;
@@ -190,10 +229,10 @@ export default {
Promise.all([
getDeployKeys(this.query),
getUsers(this.query),
- this.groups.length ? Promise.resolve({ data: this.groups }) : getGroups(),
+ this.groups.length ? Promise.resolve(this.groups) : getGroups(),
])
.then(([deployKeysResponse, usersResponse, groupsResponse]) => {
- this.consolidateData(deployKeysResponse.data, usersResponse.data, groupsResponse.data);
+ this.consolidateData(deployKeysResponse.data, usersResponse.data, groupsResponse);
this.setSelected({ initial });
})
.catch(() =>
@@ -224,13 +263,18 @@ export default {
if (this.hasLicense) {
this.groups = groupsResponse.map((group) => ({ ...group, type: LEVEL_TYPES.GROUP }));
- this.users = usersResponse.map(({ id, name, username, avatar_url }) => ({
- id,
- name,
- username,
- avatar_url,
- type: LEVEL_TYPES.USER,
- }));
+
+ // Has to be checked against server response
+ // because the selected item can be in filter results
+ if (this.showUsers) {
+ this.users = usersResponse.map(({ id, name, username, avatar_url }) => ({
+ id,
+ name,
+ username,
+ avatar_url,
+ type: LEVEL_TYPES.USER,
+ }));
+ }
}
this.deployKeys = deployKeysResponse.map((response) => {
@@ -328,14 +372,38 @@ export default {
return [...added, ...removed, ...preserved];
},
onItemClick(item) {
- this.toggleSelection(this.selected[item.type], item);
+ this.toggleSelection(item);
this.emitUpdate();
},
- toggleSelection(arr, item) {
- const itemIndex = arr.findIndex(({ id }) => id === item.id);
- if (itemIndex > -1) {
- arr.splice(itemIndex, 1);
- } else arr.push(item);
+ toggleSelection(item) {
+ if (item.id === ACCESS_LEVEL_NONE) {
+ this.selected[LEVEL_TYPES.ROLE] = [item];
+ return;
+ }
+
+ const itemSelected = this.isSelected(item);
+ if (itemSelected) {
+ this.selected[item.type] = this.selected[item.type].filter(({ id }) => id !== item.id);
+ return;
+ }
+
+ // We're not multiselecting quite yet in "Merge" access dropdown, on FOSS:
+ // remove all preselected items before selecting this item
+ // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37499
+ if (this.fossWithMergeAccess) this.clearSelection();
+ else if (item.type === LEVEL_TYPES.ROLE) this.unselectNone();
+
+ this.selected[item.type].push(item);
+ },
+ unselectNone() {
+ this.selected[LEVEL_TYPES.ROLE] = this.selected[LEVEL_TYPES.ROLE].filter(
+ ({ id }) => id !== ACCESS_LEVEL_NONE,
+ );
+ },
+ clearSelection() {
+ Object.values(LEVEL_TYPES).forEach((level) => {
+ this.selected[level] = [];
+ });
},
isSelected(item) {
return this.selected[item.type].some((selected) => selected.id === item.id);
@@ -346,6 +414,10 @@ export default {
onHide() {
this.$emit('hidden', this.selection);
},
+ onShown() {
+ this.$emit('shown');
+ this.focusInput();
+ },
},
};
</script>
@@ -354,13 +426,15 @@ export default {
<gl-dropdown
:disabled="disabled || initialLoading"
:text="toggleLabel"
- class="gl-min-w-20"
- :toggle-class="toggleClass"
+ :block="block"
+ class="gl-min-w-20 gl-p-0!"
+ :toggle-class="dropdownToggleClass"
aria-labelledby="allowed-users-label"
- @shown="focusInput"
+ :data-testid="testId"
+ @shown="onShown"
@hidden="onHide"
>
- <template #header>
+ <template v-if="searchEnabled" #header>
<gl-search-box-by-type ref="search" v-model.trim="query" :is-loading="loading" />
</template>
<template v-if="roles.length">
diff --git a/app/assets/javascripts/projects/settings/constants.js b/app/assets/javascripts/projects/settings/constants.js
index 595cbc9c991..37a9fe0c741 100644
--- a/app/assets/javascripts/projects/settings/constants.js
+++ b/app/assets/javascripts/projects/settings/constants.js
@@ -7,13 +7,6 @@ export const LEVEL_TYPES = {
GROUP: 'group',
};
-export const LEVEL_ID_PROP = {
- ROLE: 'access_level',
- USER: 'user_id',
- DEPLOY_KEY: 'deploy_key_id',
- GROUP: 'group_id',
-};
-
export const ACCESS_LEVELS = {
MERGE: 'merge_access_levels',
PUSH: 'push_access_levels',
diff --git a/app/assets/javascripts/projects/settings/init_access_dropdown.js b/app/assets/javascripts/projects/settings/init_access_dropdown.js
index 941efaef3bc..67afbee3854 100644
--- a/app/assets/javascripts/projects/settings/init_access_dropdown.js
+++ b/app/assets/javascripts/projects/settings/init_access_dropdown.js
@@ -7,8 +7,8 @@ export const initAccessDropdown = (el, options) => {
return null;
}
- const { accessLevelsData, accessLevel } = options;
- const { label, disabled, preselectedItems } = el.dataset;
+ const { accessLevelsData, ...props } = options;
+ const { label, disabled, preselectedItems } = el.dataset || {};
let preselected = [];
try {
preselected = JSON.parse(preselectedItems);
@@ -18,20 +18,35 @@ export const initAccessDropdown = (el, options) => {
return new Vue({
el,
+ name: 'AccessDropdownRoot',
+ data() {
+ return { preselected };
+ },
+ methods: {
+ setPreselectedItems(items) {
+ this.preselected = items;
+ },
+ },
render(createElement) {
const vm = this;
return createElement(AccessDropdown, {
props: {
- accessLevel,
- accessLevelsData: accessLevelsData.roles,
- preselectedItems: preselected,
label,
disabled,
+ accessLevelsData: accessLevelsData.roles,
+ preselectedItems: this.preselected,
+ ...props,
},
on: {
select(selected) {
vm.$emit('select', selected);
},
+ shown() {
+ vm.$emit('shown');
+ },
+ hidden() {
+ vm.$emit('hidden');
+ },
},
});
},
diff --git a/app/assets/javascripts/projects/settings_service_desk/components/custom_email_form.vue b/app/assets/javascripts/projects/settings_service_desk/components/custom_email_form.vue
index 4affcd926d4..09bc275cbd4 100644
--- a/app/assets/javascripts/projects/settings_service_desk/components/custom_email_form.vue
+++ b/app/assets/javascripts/projects/settings_service_desk/components/custom_email_form.vue
@@ -1,5 +1,14 @@
<script>
-import { GlButton, GlForm, GlFormGroup, GlFormInputGroup, GlFormInput } from '@gitlab/ui';
+import {
+ GlButton,
+ GlForm,
+ GlFormGroup,
+ GlFormInputGroup,
+ GlFormInput,
+ GlLink,
+ GlSprintf,
+} from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
import { isEmptyValue, hasMinimumLength, isIntegerGreaterThan, isEmail } from '~/lib/utils/forms';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import {
@@ -23,6 +32,9 @@ import {
} from '../custom_email_constants';
export default {
+ customEmailHelpUrl: helpPagePath('user/project/service_desk/configure.html', {
+ anchor: 'custom-email-address',
+ }),
components: {
ClipboardButton,
GlButton,
@@ -30,6 +42,8 @@ export default {
GlFormGroup,
GlFormInputGroup,
GlFormInput,
+ GlLink,
+ GlSprintf,
},
I18N_FORM_INTRODUCTION_PARAGRAPH,
I18N_FORM_CUSTOM_EMAIL_LABEL,
@@ -137,7 +151,19 @@ export default {
<template>
<div>
- <p>{{ $options.I18N_FORM_INTRODUCTION_PARAGRAPH }}</p>
+ <p>
+ <gl-sprintf :message="$options.I18N_FORM_INTRODUCTION_PARAGRAPH">
+ <template #link="{ content }">
+ <gl-link
+ :href="$options.customEmailHelpUrl"
+ class="gl-display-inline-block"
+ target="_blank"
+ >
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
<gl-form class="js-quick-submit" @submit.prevent="onSubmit">
<gl-form-group
:label="$options.I18N_FORM_FORWARDING_LABEL"
@@ -149,7 +175,6 @@ export default {
id="custom-email-form-forwarding"
ref="service-desk-incoming-email"
type="text"
- data-testid="custom-email-form-forwarding"
:aria-label="$options.I18N_FORM_FORWARDING_LABEL"
:value="incomingEmail"
:disabled="true"
@@ -167,7 +192,6 @@ export default {
<gl-form-group
:label="$options.I18N_FORM_CUSTOM_EMAIL_LABEL"
label-for="custom-email-form-custom-email"
- data-testid="form-group-custom-email"
:invalid-feedback="$options.I18N_FORM_INVALID_FEEDBACK_CUSTOM_EMAIL"
class="gl-mt-3"
:description="$options.I18N_FORM_CUSTOM_EMAIL_DESCRIPTION"
@@ -191,7 +215,6 @@ export default {
<gl-form-group
:label="$options.I18N_FORM_SMTP_ADDRESS_LABEL"
label-for="custom-email-form-smtp-address"
- data-testid="form-group-smtp-address"
:invalid-feedback="$options.I18N_FORM_INVALID_FEEDBACK_SMTP_ADDRESS"
class="gl-mt-3"
>
diff --git a/app/assets/javascripts/projects/settings_service_desk/components/custom_email_wrapper.vue b/app/assets/javascripts/projects/settings_service_desk/components/custom_email_wrapper.vue
index 7e040e6001a..03ba99bcf71 100644
--- a/app/assets/javascripts/projects/settings_service_desk/components/custom_email_wrapper.vue
+++ b/app/assets/javascripts/projects/settings_service_desk/components/custom_email_wrapper.vue
@@ -233,6 +233,7 @@ export default {
<gl-link
:href="$options.FEEDBACK_ISSUE_URL"
target="_blank"
+ data-testid="feedback-link"
class="gl-text-blue-600 font-size-inherit"
>{{ content }}
</gl-link>
diff --git a/app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js b/app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js
index cdf2e53982e..aafd77bd25e 100644
--- a/app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js
+++ b/app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js
@@ -17,7 +17,7 @@ export const I18N_TOAST_ENABLED = s__('ServiceDesk|Custom email enabled.');
export const I18N_TOAST_DISABLED = s__('ServiceDesk|Custom email disabled.');
export const I18N_FORM_INTRODUCTION_PARAGRAPH = s__(
- 'ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials.',
+ 'ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials. %{linkStart}Learn more about prerequisites and the verification process%{linkEnd}.',
);
export const I18N_FORM_FORWARDING_LABEL = s__(
'ServiceDesk|Service Desk email address to forward emails to',
diff --git a/app/assets/javascripts/projects/star.js b/app/assets/javascripts/projects/star.js
deleted file mode 100644
index f294811dfff..00000000000
--- a/app/assets/javascripts/projects/star.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { spriteIcon } from '~/lib/utils/common_utils';
-import { __, s__ } from '~/locale';
-
-export default class Star {
- constructor(containerSelector = '.project-home-panel') {
- const container = document.querySelector(containerSelector);
- const starToggle = container.querySelector('.toggle-star');
- starToggle?.addEventListener('click', function toggleStarClickCallback() {
- const starSpan = starToggle.querySelector('span');
- const starIcon = starToggle.querySelector('svg');
- const iconClasses = Array.from(starIcon.classList.values());
-
- axios
- .post(starToggle.dataset.endpoint)
- .then(({ data }) => {
- const isStarred = starSpan.classList.contains('starred');
- starToggle.parentNode.querySelector('.count').textContent = data.star_count;
-
- if (isStarred) {
- starSpan.classList.remove('starred');
- starSpan.textContent = s__('StarProject|Star');
- starIcon.remove();
- // eslint-disable-next-line no-unsanitized/method
- starSpan.insertAdjacentHTML('beforebegin', spriteIcon('star-o', iconClasses));
- } else {
- starSpan.classList.add('starred');
- starSpan.textContent = __('Unstar');
- starIcon.remove();
-
- // eslint-disable-next-line no-unsanitized/method
- starSpan.insertAdjacentHTML('beforebegin', spriteIcon('star', iconClasses));
- }
- })
- .catch(() =>
- createAlert({
- message: __('Star toggle failed. Try again later.'),
- }),
- );
- });
- }
-}
diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js b/app/assets/javascripts/protected_branches/protected_branch_create.js
index a11201627a4..49c55efca7b 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_create.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_create.js
@@ -4,16 +4,15 @@ import { createAlert, VARIANT_SUCCESS } from '~/alert';
import AccessorUtilities from '~/lib/utils/accessor';
import axios from '~/lib/utils/axios_utils';
import { __, s__ } from '~/locale';
-import AccessDropdown from '~/projects/settings/access_dropdown';
import { initToggle } from '~/toggles';
import { expandSection } from '~/settings_panels';
import { scrollToElement } from '~/lib/utils/common_utils';
+import { initAccessDropdown } from '~/projects/settings/init_access_dropdown';
import {
BRANCH_RULES_ANCHOR,
PROTECTED_BRANCHES_ANCHOR,
IS_PROTECTED_BRANCH_CREATED,
ACCESS_LEVELS,
- LEVEL_TYPES,
} from './constants';
export default class ProtectedBranchCreate {
@@ -21,14 +20,17 @@ export default class ProtectedBranchCreate {
this.hasLicense = options.hasLicense;
this.$form = $('.js-new-protected-branch');
this.isLocalStorageAvailable = AccessorUtilities.canUseLocalStorage();
- this.currentProjectUserDefaults = {};
- this.buildDropdowns();
-
this.forcePushToggle = initToggle(document.querySelector('.js-force-push-toggle'));
-
if (this.hasLicense) {
this.codeOwnerToggle = initToggle(document.querySelector('.js-code-owner-toggle'));
}
+
+ this.selectedItems = {
+ [ACCESS_LEVELS.PUSH]: [],
+ [ACCESS_LEVELS.MERGE]: [],
+ };
+ this.initDropdowns();
+
this.showSuccessAlertIfNeeded();
this.bindEvents();
}
@@ -37,29 +39,26 @@ export default class ProtectedBranchCreate {
this.$form.on('submit', this.onFormSubmit.bind(this));
}
- buildDropdowns() {
- const $allowedToMergeDropdown = this.$form.find('.js-allowed-to-merge');
- const $allowedToPushDropdown = this.$form.find('.js-allowed-to-push');
-
+ initDropdowns() {
// Cache callback
this.onSelectCallback = this.onSelect.bind(this);
// Allowed to Merge dropdown
- this[`${ACCESS_LEVELS.MERGE}_dropdown`] = new AccessDropdown({
- $dropdown: $allowedToMergeDropdown,
- accessLevelsData: gon.merge_access_levels,
- onSelect: this.onSelectCallback,
+ const allowedToMergeSelector = 'js-allowed-to-merge';
+ this[`${ACCESS_LEVELS.MERGE}_dropdown`] = this.buildDropdown({
+ selector: allowedToMergeSelector,
accessLevel: ACCESS_LEVELS.MERGE,
- hasLicense: this.hasLicense,
+ accessLevelsData: gon.merge_access_levels,
+ testId: 'allowed-to-merge-dropdown',
});
// Allowed to Push dropdown
- this[`${ACCESS_LEVELS.PUSH}_dropdown`] = new AccessDropdown({
- $dropdown: $allowedToPushDropdown,
- accessLevelsData: gon.push_access_levels,
- onSelect: this.onSelectCallback,
+ const allowedToPushSelector = 'js-allowed-to-push';
+ this[`${ACCESS_LEVELS.PUSH}_dropdown`] = this.buildDropdown({
+ selector: allowedToPushSelector,
accessLevel: ACCESS_LEVELS.PUSH,
- hasLicense: this.hasLicense,
+ accessLevelsData: gon.push_access_levels,
+ testId: 'allowed-to-push-dropdown',
});
this.createItemDropdown = new CreateItemDropdown({
@@ -71,14 +70,40 @@ export default class ProtectedBranchCreate {
});
}
+ buildDropdown({ selector, accessLevel, accessLevelsData, testId }) {
+ const [el] = this.$form.find(`.${selector}`);
+ if (!el) return undefined;
+
+ const projectId = gon.current_project_id;
+ const dropdown = initAccessDropdown(el, {
+ toggleClass: `${selector} gl-form-input-lg`,
+ hasLicense: this.hasLicense,
+ searchEnabled: el.dataset.filter !== undefined,
+ showUsers: projectId !== undefined,
+ block: true,
+ accessLevel,
+ accessLevelsData,
+ testId,
+ });
+
+ dropdown.$on('select', (selected) => {
+ this.selectedItems[accessLevel] = selected;
+ this.onSelectCallback();
+ });
+
+ dropdown.$on('shown', () => {
+ this.createItemDropdown.close();
+ });
+
+ return dropdown;
+ }
+
// Enable submit button after selecting an option
onSelect() {
- const $allowedToMerge = this[`${ACCESS_LEVELS.MERGE}_dropdown`].getSelectedItems();
- const $allowedToPush = this[`${ACCESS_LEVELS.PUSH}_dropdown`].getSelectedItems();
const toggle = !(
this.$form.find('input[name="protected_branch[name]"]').val() &&
- $allowedToMerge.length &&
- $allowedToPush.length
+ this.selectedItems[ACCESS_LEVELS.MERGE].length &&
+ this.selectedItems[ACCESS_LEVELS.PUSH].length
);
this.$form.find('button[type="submit"]').attr('disabled', toggle);
@@ -137,32 +162,8 @@ export default class ProtectedBranchCreate {
},
};
- Object.keys(ACCESS_LEVELS).forEach((level) => {
- const accessLevel = ACCESS_LEVELS[level];
- const selectedItems = this[`${accessLevel}_dropdown`].getSelectedItems();
- const levelAttributes = [];
-
- selectedItems.forEach((item) => {
- if (item.type === LEVEL_TYPES.USER) {
- levelAttributes.push({
- user_id: item.user_id,
- });
- } else if (item.type === LEVEL_TYPES.ROLE) {
- levelAttributes.push({
- access_level: item.access_level,
- });
- } else if (item.type === LEVEL_TYPES.GROUP) {
- levelAttributes.push({
- group_id: item.group_id,
- });
- } else if (item.type === LEVEL_TYPES.DEPLOY_KEY) {
- levelAttributes.push({
- deploy_key_id: item.deploy_key_id,
- });
- }
- });
-
- formData.protected_branch[`${accessLevel}_attributes`] = levelAttributes;
+ Object.values(ACCESS_LEVELS).forEach((level) => {
+ formData.protected_branch[`${level}_attributes`] = this.selectedItems[level];
});
return formData;
diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit.js b/app/assets/javascripts/protected_branches/protected_branch_edit.js
index b6c86750723..29034b3bc0e 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_edit.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_edit.js
@@ -2,28 +2,23 @@ import { find } from 'lodash';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
-import AccessDropdown from '~/projects/settings/access_dropdown';
import { initToggle } from '~/toggles';
+import { initAccessDropdown } from '~/projects/settings/init_access_dropdown';
import { ACCESS_LEVELS, LEVEL_TYPES } from './constants';
export default class ProtectedBranchEdit {
constructor(options) {
this.hasLicense = options.hasLicense;
- this.$wraps = {};
this.hasChanges = false;
this.$wrap = options.$wrap;
- this.$allowedToMergeDropdown = this.$wrap.find('.js-allowed-to-merge');
- this.$allowedToPushDropdown = this.$wrap.find('.js-allowed-to-push');
- this.$wraps[ACCESS_LEVELS.MERGE] = this.$allowedToMergeDropdown.closest(
- `.${ACCESS_LEVELS.MERGE}-container`,
- );
- this.$wraps[ACCESS_LEVELS.PUSH] = this.$allowedToPushDropdown.closest(
- `.${ACCESS_LEVELS.PUSH}-container`,
- );
+ this.selectedItems = {
+ [ACCESS_LEVELS.PUSH]: [],
+ [ACCESS_LEVELS.MERGE]: [],
+ };
+ this.initDropdowns();
- this.buildDropdowns();
this.initToggles();
}
@@ -67,90 +62,96 @@ export default class ProtectedBranchEdit {
}
}
- updateProtectedBranch(formData, callback) {
- axios
- .patch(this.$wrap.data('url'), {
- protected_branch: formData,
- })
- .then(callback)
- .catch(() => {
- createAlert({ message: __('Failed to update branch!') });
- });
+ initDropdowns() {
+ // Allowed to Merge dropdown
+ this[`${ACCESS_LEVELS.MERGE}_dropdown`] = this.buildDropdown(
+ 'js-allowed-to-merge',
+ ACCESS_LEVELS.MERGE,
+ gon.merge_access_levels,
+ 'protected-branch-allowed-to-merge',
+ );
+
+ // Allowed to Push dropdown
+ this[`${ACCESS_LEVELS.PUSH}_dropdown`] = this.buildDropdown(
+ 'js-allowed-to-push',
+ ACCESS_LEVELS.PUSH,
+ gon.push_access_levels,
+ 'protected-branch-allowed-to-push',
+ );
}
- buildDropdowns() {
- // Allowed to merge dropdown
- this[`${ACCESS_LEVELS.MERGE}_dropdown`] = new AccessDropdown({
- accessLevel: ACCESS_LEVELS.MERGE,
- accessLevelsData: gon.merge_access_levels,
- $dropdown: this.$allowedToMergeDropdown,
- onSelect: this.onSelectOption.bind(this),
- onHide: this.onDropdownHide.bind(this),
+ buildDropdown(selector, accessLevel, accessLevelsData, testId) {
+ const [el] = this.$wrap.find(`.${selector}`);
+ if (!el) return undefined;
+
+ const projectId = gon.current_project_id;
+ const dropdown = initAccessDropdown(el, {
+ toggleClass: selector,
hasLicense: this.hasLicense,
+ searchEnabled: el.dataset.filter !== undefined,
+ showUsers: projectId !== undefined,
+ block: true,
+ accessLevel,
+ accessLevelsData,
+ testId,
});
- // Allowed to push dropdown
- this[`${ACCESS_LEVELS.PUSH}_dropdown`] = new AccessDropdown({
- accessLevel: ACCESS_LEVELS.PUSH,
- accessLevelsData: gon.push_access_levels,
- $dropdown: this.$allowedToPushDropdown,
- onSelect: this.onSelectOption.bind(this),
- onHide: this.onDropdownHide.bind(this),
- hasLicense: this.hasLicense,
+ dropdown.$on('select', (selected) => this.onSelectItems(accessLevel, selected));
+ dropdown.$on('hidden', () => this.onDropdownHide());
+
+ this.initSelectedItems(dropdown, accessLevel);
+ return dropdown;
+ }
+
+ initSelectedItems(dropdown, accessLevel) {
+ this.selectedItems[accessLevel] = dropdown.preselected.map((item) => {
+ if (item.type === LEVEL_TYPES.USER) return { id: item.id, user_id: item.user_id };
+ if (item.type === LEVEL_TYPES.ROLE) return { id: item.id, access_level: item.access_level };
+ if (item.type === LEVEL_TYPES.GROUP) return { id: item.id, group_id: item.group_id };
+ return { id: item.id, deploy_key_id: item.deploy_key_id };
});
}
- onSelectOption() {
+ onSelectItems(accessLevel, selected) {
+ this.selectedItems[accessLevel] = selected;
this.hasChanges = true;
}
onDropdownHide() {
- if (!this.hasChanges) {
- return;
- }
-
- this.hasChanges = true;
+ if (!this.hasChanges) return;
this.updatePermissions();
}
- updatePermissions() {
- const formData = Object.keys(ACCESS_LEVELS).reduce((acc, level) => {
- const accessLevelName = ACCESS_LEVELS[level];
- const inputData = this[`${accessLevelName}_dropdown`].getInputData(accessLevelName);
- acc[`${accessLevelName}_attributes`] = inputData;
-
- return acc;
- }, {});
-
+ updateProtectedBranch(formData, callback) {
axios
.patch(this.$wrap.data('url'), {
protected_branch: formData,
})
- .then(({ data }) => {
- this.hasChanges = false;
-
- Object.keys(ACCESS_LEVELS).forEach((level) => {
- const accessLevelName = ACCESS_LEVELS[level];
-
- // The data coming from server will be the new persisted *state* for each dropdown
- this.setSelectedItemsToDropdown(data[accessLevelName], `${accessLevelName}_dropdown`);
- });
- this.$allowedToMergeDropdown.enable();
- this.$allowedToPushDropdown.enable();
- })
+ .then(callback)
.catch(() => {
- this.$allowedToMergeDropdown.enable();
- this.$allowedToPushDropdown.enable();
createAlert({ message: __('Failed to update branch!') });
});
}
- setSelectedItemsToDropdown(items = [], dropdownName) {
+ updatePermissions() {
+ const formData = Object.values(ACCESS_LEVELS).reduce((acc, level) => {
+ acc[`${level}_attributes`] = this.selectedItems[level];
+ return acc;
+ }, {});
+ this.updateProtectedBranch(formData, ({ data }) => {
+ this.hasChanges = false;
+ Object.values(ACCESS_LEVELS).forEach((level) => {
+ this.setSelectedItemsToDropdown(data[level], level);
+ });
+ });
+ }
+
+ setSelectedItemsToDropdown(items = [], accessLevel) {
const itemsToAdd = items.map((currentItem) => {
if (currentItem.user_id) {
// Do this only for users for now
// get the current data for selected items
- const selectedItems = this[dropdownName].getSelectedItems();
+ const selectedItems = this.selectedItems[accessLevel];
const currentSelectedItem = find(selectedItems, {
user_id: currentItem.user_id,
});
@@ -164,7 +165,8 @@ export default class ProtectedBranchEdit {
username: currentSelectedItem.username,
avatar_url: currentSelectedItem.avatar_url,
};
- } else if (currentItem.group_id) {
+ }
+ if (currentItem.group_id) {
return {
id: currentItem.id,
group_id: currentItem.group_id,
@@ -181,6 +183,7 @@ export default class ProtectedBranchEdit {
};
});
- this[dropdownName].setSelectedItems(itemsToAdd);
+ this.selectedItems[accessLevel] = itemsToAdd;
+ this[`${accessLevel}_dropdown`]?.setPreselectedItems(itemsToAdd);
}
}
diff --git a/app/assets/javascripts/protected_tags/constants.js b/app/assets/javascripts/protected_tags/constants.js
index 758b820c4c4..d332ba1635f 100644
--- a/app/assets/javascripts/protected_tags/constants.js
+++ b/app/assets/javascripts/protected_tags/constants.js
@@ -1,7 +1,3 @@
-import { s__ } from '~/locale';
-
-export const FAILED_TO_UPDATE_TAG_MESSAGE = s__('ProjectSettings|Failed to update tag!');
-
export const ACCESS_LEVELS = {
CREATE: 'create_access_levels',
};
diff --git a/app/assets/javascripts/protected_tags/protected_tag_create.js b/app/assets/javascripts/protected_tags/protected_tag_create.js
index 365b9a3b142..b5661af352c 100644
--- a/app/assets/javascripts/protected_tags/protected_tag_create.js
+++ b/app/assets/javascripts/protected_tags/protected_tag_create.js
@@ -3,8 +3,8 @@ import CreateItemDropdown from '~/create_item_dropdown';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { s__, __ } from '~/locale';
-import AccessDropdown from '~/projects/settings/access_dropdown';
-import { ACCESS_LEVELS, LEVEL_TYPES } from './constants';
+import { initAccessDropdown } from '~/projects/settings/init_access_dropdown';
+import { ACCESS_LEVELS } from './constants';
export default class ProtectedTagCreate {
constructor({ hasLicense }) {
@@ -12,6 +12,7 @@ export default class ProtectedTagCreate {
this.$form = $('.js-new-protected-tag');
this.buildDropdowns();
this.bindEvents();
+ this.selectedItems = [];
}
bindEvents() {
@@ -19,20 +20,9 @@ export default class ProtectedTagCreate {
}
buildDropdowns() {
- const $allowedToCreateDropdown = this.$form.find('.js-allowed-to-create');
-
// Cache callback
this.onSelectCallback = this.onSelect.bind(this);
- // Allowed to Create dropdown
- this.protectedTagAccessDropdown = new AccessDropdown({
- $dropdown: $allowedToCreateDropdown,
- accessLevelsData: gon.create_access_levels,
- onSelect: this.onSelectCallback,
- accessLevel: ACCESS_LEVELS.CREATE,
- hasLicense: this.hasLicense,
- });
-
// Protected tag dropdown
this.createItemDropdown = new CreateItemDropdown({
$dropdown: this.$form.find('.js-protected-tag-select'),
@@ -41,17 +31,36 @@ export default class ProtectedTagCreate {
onSelect: this.onSelectCallback,
getData: ProtectedTagCreate.getProtectedTags,
});
+
+ // Allowed to Create dropdown
+ const createTagSelector = 'js-allowed-to-create';
+ const [dropdownEl] = this.$form.find(`.${createTagSelector}`);
+ this.protectedTagAccessDropdown = initAccessDropdown(dropdownEl, {
+ toggleClass: createTagSelector,
+ hasLicense: this.hasLicense,
+ accessLevel: ACCESS_LEVELS.CREATE,
+ accessLevelsData: gon.create_access_levels,
+ searchEnabled: dropdownEl.dataset.filter !== undefined,
+ testId: 'allowed_to_create_dropdown',
+ });
+
+ this.protectedTagAccessDropdown.$on('select', (selected) => {
+ this.selectedItems = selected;
+ this.onSelectCallback();
+ });
+
+ this.protectedTagAccessDropdown.$on('shown', () => {
+ this.createItemDropdown.close();
+ });
}
// This will run after clicked callback
onSelect() {
// Enable submit button
const $tagInput = this.$form.find('input[name="protected_tag[name]"]');
- const $allowedToCreateInput = this.protectedTagAccessDropdown.getSelectedItems();
-
this.$form
.find('button[type="submit"]')
- .prop('disabled', !($tagInput.val() && $allowedToCreateInput.length));
+ .prop('disabled', !($tagInput.val() && this.selectedItems.length));
}
static getProtectedTags(term, callback) {
@@ -65,35 +74,7 @@ export default class ProtectedTagCreate {
name: this.$form.find('input[name="protected_tag[name]"]').val(),
},
};
-
- Object.keys(ACCESS_LEVELS).forEach((level) => {
- const accessLevel = ACCESS_LEVELS[level];
- const selectedItems = this.protectedTagAccessDropdown.getSelectedItems();
- const levelAttributes = [];
-
- selectedItems.forEach((item) => {
- if (item.type === LEVEL_TYPES.USER) {
- levelAttributes.push({
- user_id: item.user_id,
- });
- } else if (item.type === LEVEL_TYPES.ROLE) {
- levelAttributes.push({
- access_level: item.access_level,
- });
- } else if (item.type === LEVEL_TYPES.GROUP) {
- levelAttributes.push({
- group_id: item.group_id,
- });
- } else if (item.type === LEVEL_TYPES.DEPLOY_KEY) {
- levelAttributes.push({
- deploy_key_id: item.deploy_key_id,
- });
- }
- });
-
- formData.protected_tag[`${accessLevel}_attributes`] = levelAttributes;
- });
-
+ formData.protected_tag[`${ACCESS_LEVELS.CREATE}_attributes`] = this.selectedItems;
return formData;
}
diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit.js b/app/assets/javascripts/protected_tags/protected_tag_edit.js
deleted file mode 100644
index 4fa3ac3be4b..00000000000
--- a/app/assets/javascripts/protected_tags/protected_tag_edit.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import { find } from 'lodash';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import AccessDropdown from '~/projects/settings/access_dropdown';
-import { ACCESS_LEVELS, LEVEL_TYPES, FAILED_TO_UPDATE_TAG_MESSAGE } from './constants';
-
-export default class ProtectedTagEdit {
- constructor(options) {
- this.hasLicense = options.hasLicense;
- this.hasChanges = false;
- this.$wrap = options.$wrap;
- this.$allowedToCreateDropdownButton = this.$wrap.find('.js-allowed-to-create');
-
- this.$allowedToCreateDropdownContainer = this.$allowedToCreateDropdownButton.closest(
- '.create_access_levels-container',
- );
-
- this.buildDropdowns();
- }
-
- buildDropdowns() {
- // Allowed to create dropdown
- this.protectedTagAccessDropdown = new AccessDropdown({
- accessLevel: ACCESS_LEVELS.CREATE,
- accessLevelsData: gon.create_access_levels,
- $dropdown: this.$allowedToCreateDropdownButton,
- onSelect: this.onSelectOption.bind(this),
- onHide: this.onDropdownHide.bind(this),
- hasLicense: this.hasLicense,
- });
- }
-
- onSelectOption() {
- this.hasChanges = true;
- }
-
- onDropdownHide() {
- if (!this.hasChanges) {
- return;
- }
-
- this.hasChanges = true;
- this.updatePermissions();
- }
-
- updatePermissions() {
- const formData = Object.keys(ACCESS_LEVELS).reduce((acc, level) => {
- const accessLevelName = ACCESS_LEVELS[level];
- const inputData = this.protectedTagAccessDropdown.getInputData(accessLevelName);
- acc[`${accessLevelName}_attributes`] = inputData;
-
- return acc;
- }, {});
-
- axios
- .patch(this.$wrap.data('url'), {
- protected_tag: formData,
- })
- .then(({ data }) => {
- this.hasChanges = false;
-
- Object.keys(ACCESS_LEVELS).forEach((level) => {
- const accessLevelName = ACCESS_LEVELS[level];
-
- // The data coming from server will be the new persisted *state* for each dropdown
- this.setSelectedItemsToDropdown(data[accessLevelName], `${accessLevelName}_dropdown`);
- });
- })
- .catch(() => {
- window.scrollTo({ top: 0, behavior: 'smooth' });
- createAlert({
- message: FAILED_TO_UPDATE_TAG_MESSAGE,
- });
- });
- }
-
- setSelectedItemsToDropdown(items = []) {
- const itemsToAdd = items.map((currentItem) => {
- if (currentItem.user_id) {
- // Do this only for users for now
- // get the current data for selected items
- const selectedItems = this.protectedTagAccessDropdown.getSelectedItems();
- const currentSelectedItem = find(selectedItems, {
- user_id: currentItem.user_id,
- });
-
- return {
- id: currentItem.id,
- user_id: currentItem.user_id,
- type: LEVEL_TYPES.USER,
- persisted: true,
- name: currentSelectedItem.name,
- username: currentSelectedItem.username,
- avatar_url: currentSelectedItem.avatar_url,
- };
- } else if (currentItem.group_id) {
- return {
- id: currentItem.id,
- group_id: currentItem.group_id,
- type: LEVEL_TYPES.GROUP,
- persisted: true,
- };
- }
-
- return {
- id: currentItem.id,
- access_level: currentItem.access_level,
- type: LEVEL_TYPES.ROLE,
- persisted: true,
- };
- });
-
- this.protectedTagAccessDropdown.setSelectedItems(itemsToAdd);
- }
-}
diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit.vue b/app/assets/javascripts/protected_tags/protected_tag_edit.vue
new file mode 100644
index 00000000000..82b2ecc5f5c
--- /dev/null
+++ b/app/assets/javascripts/protected_tags/protected_tag_edit.vue
@@ -0,0 +1,113 @@
+<script>
+import AccessDropdown from '~/projects/settings/components/access_dropdown.vue';
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { s__ } from '~/locale';
+import { ACCESS_LEVELS, LEVEL_TYPES } from './constants';
+
+export const i18n = {
+ failureMessage: s__('ProjectSettings|Failed to update tag!'),
+};
+
+export default {
+ i18n,
+ ACCESS_LEVELS,
+ name: 'ProtectedTagEdit',
+ components: {
+ AccessDropdown,
+ },
+ props: {
+ url: {
+ type: String,
+ required: true,
+ },
+ accessLevelsData: {
+ type: Array,
+ required: true,
+ },
+ hasLicense: {
+ required: false,
+ type: Boolean,
+ default: true,
+ },
+ preselectedItems: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ searchEnabled: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ },
+ data() {
+ return {
+ selected: this.preselectedItems,
+ };
+ },
+ methods: {
+ hasChanges(permissions) {
+ return permissions.some(({ id, _destroy }) => id === undefined || _destroy);
+ },
+ updatePermissions(permissions) {
+ if (!this.hasChanges(permissions)) return;
+ axios
+ .patch(this.url, {
+ protected_tag: {
+ [`${ACCESS_LEVELS.CREATE}_attributes`]: permissions,
+ },
+ })
+ .then(this.setSelected)
+ .catch(() => {
+ createAlert({
+ message: i18n.failureMessage,
+ parent: this.parentContainer,
+ });
+ });
+ },
+ setSelected({ data }) {
+ if (!data) return;
+ this.selected = data[ACCESS_LEVELS.CREATE].map(
+ ({ id, user_id: userId, group_id: groupId, access_level: accessLevel }) => {
+ if (userId) {
+ return {
+ id,
+ user_id: userId,
+ type: LEVEL_TYPES.USER,
+ };
+ }
+
+ if (groupId) {
+ return {
+ id,
+ group_id: groupId,
+ type: LEVEL_TYPES.GROUP,
+ };
+ }
+
+ return {
+ id,
+ access_level: accessLevel,
+ type: LEVEL_TYPES.ROLE,
+ };
+ },
+ );
+ },
+ },
+};
+</script>
+
+<template>
+ <access-dropdown
+ toggle-class="js-allowed-to-create gl-max-w-34"
+ test-id="allowed_to_create_dropdown"
+ :has-license="hasLicense"
+ :access-level="$options.ACCESS_LEVELS.CREATE"
+ :access-levels-data="accessLevelsData"
+ :preselected-items="selected"
+ :search-enabled="searchEnabled"
+ :block="true"
+ @hidden="updatePermissions"
+ />
+</template>
diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit_list.js b/app/assets/javascripts/protected_tags/protected_tag_edit_list.js
index 8ceb970bf03..444d6e9cf76 100644
--- a/app/assets/javascripts/protected_tags/protected_tag_edit_list.js
+++ b/app/assets/javascripts/protected_tags/protected_tag_edit_list.js
@@ -1,21 +1,49 @@
-/* eslint-disable no-new */
-
-import $ from 'jquery';
-import ProtectedTagEdit from './protected_tag_edit';
+import Vue from 'vue';
+import * as Sentry from '@sentry/browser';
+import ProtectedTagEdit from './protected_tag_edit.vue';
export default class ProtectedTagEditList {
constructor(options) {
this.hasLicense = options.hasLicense;
- this.$wrap = $('.protected-tags-list');
this.initEditForm();
}
initEditForm() {
- this.$wrap.find('.js-protected-tag-edit-form').each((i, el) => {
- new ProtectedTagEdit({
- $wrap: $(el),
- hasLicense: this.hasLicense,
+ document
+ .querySelector('.protected-tags-list')
+ .querySelectorAll('.js-protected-tag-edit-form')
+ ?.forEach((el) => {
+ const accessDropdownEl = el.querySelector('.js-allowed-to-create');
+ this.initAccessDropdown(accessDropdownEl, {
+ url: el.dataset.url,
+ hasLicense: this.hasLicense,
+ accessLevelsData: gon.create_access_levels.roles,
+ });
});
+ }
+
+ // eslint-disable-next-line class-methods-use-this
+ initAccessDropdown(el, options) {
+ if (!el) return null;
+
+ let preselected = [];
+ try {
+ preselected = JSON.parse(el.dataset.preselectedItems);
+ } catch (e) {
+ Sentry.captureException(e);
+ }
+
+ return new Vue({
+ el,
+ render(createElement) {
+ return createElement(ProtectedTagEdit, {
+ props: {
+ preselectedItems: preselected,
+ searchEnabled: el.dataset.filter !== undefined,
+ ...options,
+ },
+ });
+ },
});
}
}
diff --git a/app/assets/javascripts/related_issues/components/add_issuable_form.vue b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
index b3033ddf3b6..d36b29f69a5 100644
--- a/app/assets/javascripts/related_issues/components/add_issuable_form.vue
+++ b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
@@ -115,7 +115,8 @@ export default {
addRelatedErrorMessage() {
if (this.itemAddFailureMessage) {
return this.itemAddFailureMessage;
- } else if (this.itemAddFailureType === itemAddFailureTypesMap.NOT_FOUND) {
+ }
+ if (this.itemAddFailureType === itemAddFailureTypesMap.NOT_FOUND) {
return addRelatedIssueErrorMap[this.issuableType];
}
// Only other failure is MAX_NUMBER_OF_CHILD_EPICS at the moment
diff --git a/app/assets/javascripts/related_issues/index.js b/app/assets/javascripts/related_issues/index.js
index 23620432feb..cc0dae355b6 100644
--- a/app/assets/javascripts/related_issues/index.js
+++ b/app/assets/javascripts/related_issues/index.js
@@ -1,10 +1,9 @@
import Vue from 'vue';
-import { TYPE_ISSUE } from '~/issues/constants';
import { apolloProvider } from '~/graphql_shared/issuable_client';
import { parseBoolean } from '~/lib/utils/common_utils';
import RelatedIssuesRoot from './components/related_issues_root.vue';
-export function initRelatedIssues(issueType = TYPE_ISSUE) {
+export function initRelatedIssues() {
const el = document.querySelector('.js-related-issues-root');
if (!el) {
@@ -28,7 +27,7 @@ export function initRelatedIssues(issueType = TYPE_ISSUE) {
canAdmin: parseBoolean(el.dataset.canAddRelatedIssues),
helpPath: el.dataset.helpPath,
showCategorizedIssues: parseBoolean(el.dataset.showCategorizedIssues),
- issuableType: issueType,
+ issuableType: el.dataset.issuableType,
autoCompleteEpics: false,
},
}),
diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue
index 6f9f0a81dfd..6565c84fa11 100644
--- a/app/assets/javascripts/repository/components/blob_content_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue
@@ -7,11 +7,9 @@ import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constant
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { isLoggedIn, handleLocationHash } from '~/lib/utils/common_utils';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import { redirectTo, getLocationHash } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import WebIdeLink from 'ee_else_ce/vue_shared/components/web_ide_link.vue';
import CodeIntelligence from '~/code_navigation/components/app.vue';
import LineHighlighter from '~/blob/line_highlighter';
import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql';
@@ -19,15 +17,7 @@ import { addBlameLink } from '~/blob/blob_blame_link';
import highlightMixin from '~/repository/mixins/highlight_mixin';
import projectInfoQuery from '../queries/project_info.query.graphql';
import getRefMixin from '../mixins/get_ref';
-import userInfoQuery from '../queries/user_info.query.graphql';
-import applicationInfoQuery from '../queries/application_info.query.graphql';
-import {
- DEFAULT_BLOB_INFO,
- TEXT_FILE_TYPE,
- LFS_STORAGE,
- LEGACY_FILE_TYPES,
- CODEOWNERS_FILE_NAME,
-} from '../constants';
+import { DEFAULT_BLOB_INFO, TEXT_FILE_TYPE, LFS_STORAGE, LEGACY_FILE_TYPES } from '../constants';
import BlobButtonGroup from './blob_button_group.vue';
import ForkSuggestion from './fork_suggestion.vue';
import { loadViewer } from './blob_viewers';
@@ -38,10 +28,8 @@ export default {
BlobButtonGroup,
BlobContent,
GlLoadingIcon,
- CodeownersValidation: () => import('ee_component/blob/components/codeowners_validation.vue'),
GlButton,
ForkSuggestion,
- WebIdeLink,
CodeIntelligence,
AiGenie: () => import('ee_component/ai/components/ai_genie.vue'),
},
@@ -68,18 +56,6 @@ export default {
this.userPermissions = project.userPermissions;
},
},
- gitpodEnabled: {
- query: applicationInfoQuery,
- error() {
- this.displayError();
- },
- },
- currentUser: {
- query: userInfoQuery,
- error() {
- this.displayError();
- },
- },
project: {
query: blobInfoQuery,
variables() {
@@ -94,32 +70,17 @@ export default {
return queryVariables;
},
result({ data }) {
- const blob = data.project?.repository?.blobs?.nodes[0] || {};
- this.initHighlightWorker(blob);
+ const repository = data.project?.repository || {};
+ this.blobInfo = repository.blobs?.nodes[0] || {};
+ this.isEmptyRepository = repository.empty;
+ this.projectId = data.project?.id;
- const urlHash = getLocationHash();
- const plain = this.$route?.query?.plain;
+ const usePlain = this.$route?.query?.plain === '1'; // When the 'plain' URL param is present, its value determines which viewer to render
+ const urlHash = getLocationHash(); // If there is a code line hash in the URL we render with the simple viewer
+ const useSimpleViewer = usePlain || urlHash?.startsWith('L') || !this.hasRichViewer;
- // When the 'plain' URL param is present, its value determines which viewer to render:
- // - when 0 and the rich viewer is available we render with it
- // - otherwise we render the simple viewer
- if (plain !== undefined) {
- if (plain === '0' && this.hasRichViewer) {
- this.switchViewer(RICH_BLOB_VIEWER);
- } else {
- this.switchViewer(SIMPLE_BLOB_VIEWER);
- }
- return;
- }
-
- // If there is a code line hash in the URL we render with the simple viewer
- if (urlHash && urlHash.startsWith('L')) {
- this.switchViewer(SIMPLE_BLOB_VIEWER);
- return;
- }
-
- // By default, if present, use the rich viewer to render
- this.switchViewer(this.hasRichViewer ? RICH_BLOB_VIEWER : SIMPLE_BLOB_VIEWER);
+ this.initHighlightWorker(this.blobInfo);
+ this.switchViewer(useSimpleViewer ? SIMPLE_BLOB_VIEWER : RICH_BLOB_VIEWER); // By default, if present, use the rich viewer to render
},
error() {
this.displayError();
@@ -127,9 +88,7 @@ export default {
},
},
provide() {
- return {
- blobHash: uniqueId(),
- };
+ return { blobHash: uniqueId() };
},
props: {
path: {
@@ -156,11 +115,13 @@ export default {
isRenderingLegacyTextViewer: false,
activeViewerType: SIMPLE_BLOB_VIEWER,
project: DEFAULT_BLOB_INFO.project,
- gitpodEnabled: DEFAULT_BLOB_INFO.gitpodEnabled,
currentUser: DEFAULT_BLOB_INFO.currentUser,
useFallback: false,
pathLocks: DEFAULT_BLOB_INFO.pathLocks,
userPermissions: DEFAULT_BLOB_INFO.userPermissions,
+ blobInfo: {},
+ isEmptyRepository: false,
+ projectId: null,
};
},
computed: {
@@ -173,17 +134,9 @@ export default {
isBinaryFileType() {
return this.isBinary || this.blobInfo.simpleViewer?.fileType !== TEXT_FILE_TYPE;
},
- blobInfo() {
- const nodes = this.project?.repository?.blobs?.nodes || [];
-
- return nodes[0] || {};
- },
currentRef() {
return this.originalBranch || this.ref;
},
- isCodeownersFile() {
- return this.path.includes(CODEOWNERS_FILE_NAME);
- },
viewer() {
const { richViewer, simpleViewer } = this.blobInfo;
return this.activeViewerType === RICH_BLOB_VIEWER ? richViewer : simpleViewer;
@@ -249,22 +202,14 @@ export default {
isUsingLfs() {
return this.blobInfo.storedExternally && this.blobInfo.externalStorage === LFS_STORAGE;
},
- projectIdAsNumber() {
- return getIdFromGraphQLId(this.project?.id);
- },
},
watch: {
// Watch the URL 'plain' query value to know if the viewer needs changing.
- // This is the case when the user switches the viewer and then goes back
- // through the hystory.
+ // This is the case when the user switches the viewer and then goes back through the history
'$route.query.plain': {
handler(plainValue) {
- this.switchViewer(
- this.hasRichViewer && (plainValue === undefined || plainValue === '0')
- ? RICH_BLOB_VIEWER
- : SIMPLE_BLOB_VIEWER,
- plainValue !== undefined,
- );
+ const useSimpleViewer = plainValue === '1' || !this.hasRichViewer;
+ this.switchViewer(useSimpleViewer ? SIMPLE_BLOB_VIEWER : RICH_BLOB_VIEWER);
},
},
},
@@ -323,21 +268,11 @@ export default {
this.loadLegacyViewer();
}
},
- updateRouteQuery() {
- const plain = this.activeViewerType === SIMPLE_BLOB_VIEWER ? '1' : '0';
-
- if (this.$route?.query?.plain === plain) {
- return;
- }
-
- this.$router.push({
- path: this.$route.path,
- query: { ...this.$route.query, plain },
- });
- },
handleViewerChanged(newViewer) {
this.switchViewer(newViewer);
- this.updateRouteQuery();
+ const plain = newViewer === SIMPLE_BLOB_VIEWER ? '1' : '0';
+ if (this.$route?.query?.plain === plain) return;
+ this.$router.push({ path: this.$route.path, query: { ...this.$route.query, plain } });
},
editBlob(target) {
if (this.showForkSuggestion) {
@@ -370,31 +305,15 @@ export default {
:has-render-error="hasRenderError"
:show-path="false"
:override-copy="true"
+ :show-fork-suggestion="showForkSuggestion"
+ :project-path="projectPath"
+ :project-id="projectId"
@viewer-changed="handleViewerChanged"
@copy="onCopy"
+ @edit="editBlob"
+ @error="displayError"
>
<template #actions>
- <web-ide-link
- v-if="!blobInfo.archived"
- :show-edit-button="!isBinaryFileType"
- class="gl-mr-3"
- :edit-url="blobInfo.editBlobPath"
- :web-ide-url="blobInfo.ideEditPath"
- :needs-to-fork="showForkSuggestion"
- :show-pipeline-editor-button="Boolean(blobInfo.pipelineEditorPath)"
- :pipeline-editor-url="blobInfo.pipelineEditorPath"
- :gitpod-url="blobInfo.gitpodBlobUrl"
- :show-gitpod-button="gitpodEnabled"
- :gitpod-enabled="currentUser && currentUser.gitpodEnabled"
- :project-path="projectPath"
- :project-id="projectIdAsNumber"
- :user-preferences-gitpod-path="currentUser && currentUser.preferencesGitpodPath"
- :user-profile-enable-gitpod-path="currentUser && currentUser.profileEnableGitpodPath"
- is-blob
- disable-fork-modal
- @edit="editBlob"
- />
-
<blob-button-group
v-if="isLoggedIn && !blobInfo.archived"
:path="path"
@@ -403,7 +322,7 @@ export default {
:delete-path="blobInfo.webPath"
:can-push-code="userPermissions.pushCode"
:can-push-to-branch="blobInfo.canCurrentUserPushToBranch"
- :empty-repo="project.repository.empty"
+ :empty-repo="isEmptyRepository"
:project-path="projectPath"
:is-locked="Boolean(pathLockedByUser)"
:can-lock="canLock"
@@ -418,12 +337,6 @@ export default {
:fork-path="forkPath"
@cancel="setForkTarget(null)"
/>
- <codeowners-validation
- v-if="isCodeownersFile"
- :current-ref="currentRef"
- :project-path="projectPath"
- :file-path="path"
- />
<blob-content
v-if="!blobViewer"
class="js-syntax-highlight"
@@ -441,6 +354,8 @@ export default {
v-else
:blob="blobInfo"
:chunks="chunks"
+ :project-path="projectPath"
+ :current-ref="currentRef"
class="blob-viewer"
@error="onError"
/>
diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue
index fa51ef30546..12edeeb0d2f 100644
--- a/app/assets/javascripts/repository/components/last_commit.vue
+++ b/app/assets/javascripts/repository/components/last_commit.vue
@@ -4,7 +4,7 @@ import SafeHtml from '~/vue_shared/directives/safe_html';
import defaultAvatarUrl from 'images/no_avatar.png';
import pathLastCommitQuery from 'shared_queries/repository/path_last_commit.query.graphql';
import { sprintf, s__ } from '~/locale';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
@@ -20,13 +20,13 @@ export default {
UserAvatarLink,
TimeagoTooltip,
ClipboardButton,
- CiIcon,
GlButton,
GlButtonGroup,
GlLink,
GlLoadingIcon,
UserAvatarImage,
SignatureBadge,
+ CiBadgeLink,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -191,18 +191,14 @@ export default {
>
<signature-badge v-if="commit.signature" :signature="commit.signature" />
<div v-if="commit.pipeline" class="ci-status-link">
- <gl-link
- v-gl-tooltip.left
- :href="commit.pipeline.detailedStatus.detailsPath"
- :title="statusTitle"
+ <ci-badge-link
+ :status="commit.pipeline.detailedStatus"
+ :details-path="commit.pipeline.detailedStatus.detailsPath"
+ :aria-label="statusTitle"
+ size="lg"
+ :show-text="false"
class="js-commit-pipeline"
- >
- <ci-icon
- :status="commit.pipeline.detailedStatus"
- :size="24"
- :aria-label="statusTitle"
- />
- </gl-link>
+ />
</div>
<gl-button-group class="gl-ml-4 js-commit-sha-group">
<gl-button label class="gl-font-monospace" data-testid="last-commit-id-label">{{
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index c839d7a53cd..a76d822317a 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -123,7 +123,8 @@ export default {
path: joinPaths('/-/blob', this.escapedRef, this.path),
refType: this.refType,
});
- } else if (this.isFolder) {
+ }
+ if (this.isFolder) {
return buildURLwithRefType({
path: joinPaths('/-/tree', this.escapedRef, this.path),
refType: this.refType,
@@ -260,7 +261,9 @@ export default {
</gl-intersection-observer>
</td>
<td class="tree-time-ago text-right cursor-default gl-text-secondary">
- <timeago-tooltip v-if="commitData" :time="commitData.committedDate" />
+ <gl-intersection-observer @appear="rowAppeared" @disappear="rowDisappeared">
+ <timeago-tooltip v-if="commitData" :time="commitData.committedDate" />
+ </gl-intersection-observer>
<gl-skeleton-loader v-if="showSkeletonLoader" :lines="1" />
</td>
</tr>
diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js
index 3079ef0bfbb..c4d03120c2e 100644
--- a/app/assets/javascripts/repository/constants.js
+++ b/app/assets/javascripts/repository/constants.js
@@ -27,12 +27,6 @@ export const PDF_MAX_PAGE_LIMIT = 50;
export const ROW_APPEAR_DELAY = 150;
export const DEFAULT_BLOB_INFO = {
- gitpodEnabled: false,
- currentUser: {
- gitpodEnabled: false,
- preferencesGitpodPath: null,
- profileEnableGitpodPath: null,
- },
userPermissions: {
pushCode: false,
downloadCode: false,
@@ -116,5 +110,3 @@ export const POLLING_INTERVAL_BACKOFF = 2;
export const CONFLICTS_MODAL_ID = 'fork-sync-conflicts-modal';
export const FORK_UPDATED_EVENT = 'fork:updated';
-
-export const CODEOWNERS_FILE_NAME = 'CODEOWNERS';
diff --git a/app/assets/javascripts/rest_api.js b/app/assets/javascripts/rest_api.js
index 87996d0bb85..2b9ec7b63d7 100644
--- a/app/assets/javascripts/rest_api.js
+++ b/app/assets/javascripts/rest_api.js
@@ -8,6 +8,7 @@ export * from './api/tags_api';
export * from './api/alert_management_alerts_api';
export * from './api/harbor_registry';
export * from './api/environments_api';
+export * from './api/application_settings_api';
// Note: It's not possible to spy on methods imported from this file in
// Jest tests.
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 58e4553d00d..bc1f32930e7 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -64,15 +64,12 @@ Sidebar.prototype.addEventListeners = function () {
};
Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
- const $this = $(this);
-
- if ($this.hasClass('right-sidebar-merge-requests')) return;
-
+ const $toggleButtons = $('.js-sidebar-toggle');
const $collapseIcon = $('.js-sidebar-collapse');
const $expandIcon = $('.js-sidebar-expand');
const $toggleContainer = $('.js-sidebar-toggle-container');
const isExpanded = $toggleContainer.data('is-expanded');
- const tooltipLabel = isExpanded ? __('Collapse sidebar') : __('Expand sidebar');
+ const tooltipLabel = isExpanded ? __('Expand sidebar') : __('Collapse sidebar');
e.preventDefault();
if (isExpanded) {
@@ -93,10 +90,10 @@ Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
$('.layout-page').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
}
- $this.attr('data-original-title', tooltipLabel);
- $this.attr('title', tooltipLabel);
- fixTitle($this);
- hide($this);
+ $toggleButtons.attr('data-original-title', tooltipLabel);
+ $toggleButtons.attr('title', tooltipLabel);
+ fixTitle($toggleButtons);
+ hide($toggleButtons);
if (!triggered) {
setCookie('collapsed_gutter', $('.right-sidebar').hasClass('right-sidebar-collapsed'));
diff --git a/app/assets/javascripts/run_modules.js b/app/assets/javascripts/run_modules.js
new file mode 100644
index 00000000000..fabdff9bb76
--- /dev/null
+++ b/app/assets/javascripts/run_modules.js
@@ -0,0 +1,9 @@
+export const runModules = (modules, prefix) => {
+ document
+ .querySelector('meta[name="controller-path"]')
+ .content.split('/')
+ .forEach((part, index, arr) => {
+ const path = `${prefix}${[...arr.slice(0, index), part].join('/')}/index.js`;
+ modules[path]?.();
+ });
+};
diff --git a/app/assets/javascripts/search/index.js b/app/assets/javascripts/search/index.js
index f5684cebbf9..f83130213f2 100644
--- a/app/assets/javascripts/search/index.js
+++ b/app/assets/javascripts/search/index.js
@@ -10,12 +10,13 @@ import { initBlobRefSwitcher } from './under_topbar';
export const initSearchApp = () => {
syntaxHighlight(document.querySelectorAll('.js-search-results'));
const query = queryToObject(window.location.search, { gatherArrays: true });
- const { navigationJsonParsed: navigation } = sidebarInitState() || {};
+ const { navigationJsonParsed: navigation, searchType } = sidebarInitState() || {};
const store = createStore({
query,
navigation,
useSidebarNavigation: gon.use_new_navigation,
+ searchType,
});
initTopbar(store);
diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue
index 9962f711892..532a66affd8 100644
--- a/app/assets/javascripts/search/sidebar/components/app.vue
+++ b/app/assets/javascripts/search/sidebar/components/app.vue
@@ -3,29 +3,46 @@
import { mapState, mapGetters } from 'vuex';
import ScopeLegacyNavigation from '~/search/sidebar/components/scope_legacy_navigation.vue';
import ScopeSidebarNavigation from '~/search/sidebar/components/scope_sidebar_navigation.vue';
+import SmallScreenDrawerNavigation from '~/search/sidebar/components/small_screen_drawer_navigation.vue';
import SidebarPortal from '~/super_sidebar/components/sidebar_portal.vue';
+import { toggleSuperSidebarCollapsed } from '~/super_sidebar/super_sidebar_collapsed_state_manager';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { SCOPE_ISSUES, SCOPE_MERGE_REQUESTS, SCOPE_BLOB, SCOPE_PROJECTS } from '../constants';
+import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
+import {
+ SCOPE_ISSUES,
+ SCOPE_MERGE_REQUESTS,
+ SCOPE_BLOB,
+ SCOPE_PROJECTS,
+ SCOPE_NOTES,
+ SCOPE_COMMITS,
+ SEARCH_TYPE_ADVANCED,
+} from '../constants';
import IssuesFilters from './issues_filters.vue';
import MergeRequestsFilters from './merge_requests_filters.vue';
import BlobsFilters from './blobs_filters.vue';
import ProjectsFilters from './projects_filters.vue';
+import NotesFilters from './notes_filters.vue';
+import CommitsFilters from './commits_filters.vue';
export default {
name: 'GlobalSearchSidebar',
components: {
IssuesFilters,
- ScopeLegacyNavigation,
- ScopeSidebarNavigation,
- SidebarPortal,
MergeRequestsFilters,
BlobsFilters,
ProjectsFilters,
+ NotesFilters,
+ ScopeLegacyNavigation,
+ ScopeSidebarNavigation,
+ SidebarPortal,
+ DomElementListener,
+ SmallScreenDrawerNavigation,
+ CommitsFilters,
},
mixins: [glFeatureFlagsMixin()],
computed: {
// useSidebarNavigation refers to whether the new left sidebar navigation is enabled
- ...mapState(['useSidebarNavigation']),
+ ...mapState(['useSidebarNavigation', 'searchType']),
...mapGetters(['currentScope']),
showIssuesFilters() {
return this.currentScope === SCOPE_ISSUES;
@@ -34,11 +51,25 @@ export default {
return this.currentScope === SCOPE_MERGE_REQUESTS;
},
showBlobFilters() {
- return this.currentScope === SCOPE_BLOB;
+ return this.currentScope === SCOPE_BLOB && this.searchType === SEARCH_TYPE_ADVANCED;
},
showProjectsFilters() {
- // for now the feature flag is here. Since we have only one filter in projects scope
- return this.currentScope === SCOPE_PROJECTS && this.glFeatures.searchProjectsHideArchived;
+ return this.currentScope === SCOPE_PROJECTS;
+ },
+ showNotesFilters() {
+ return (
+ this.currentScope === SCOPE_NOTES &&
+ this.searchType === SEARCH_TYPE_ADVANCED &&
+ this.glFeatures.searchNotesHideArchivedProjects
+ );
+ },
+ showCommitsFilters() {
+ // for now, the feature flag is placed here. Since we have only one filter in commits scope
+ return (
+ this.currentScope === SCOPE_COMMITS &&
+ this.searchType === SEARCH_TYPE_ADVANCED &&
+ this.glFeatures.searchCommitsHideArchivedProjects
+ );
},
showScopeNavigation() {
// showScopeNavigation refers to whether the scope navigation should be shown
@@ -47,27 +78,49 @@ export default {
return Boolean(this.currentScope);
},
},
+ methods: {
+ toggleFiltersFromSidebar() {
+ toggleSuperSidebarCollapsed();
+ },
+ },
};
</script>
<template>
<section v-if="useSidebarNavigation">
+ <dom-element-listener selector="#js-open-mobile-filters" @click="toggleFiltersFromSidebar" />
<sidebar-portal>
<scope-sidebar-navigation />
<issues-filters v-if="showIssuesFilters" />
<merge-requests-filters v-if="showMergeRequestFilters" />
<blobs-filters v-if="showBlobFilters" />
<projects-filters v-if="showProjectsFilters" />
+ <notes-filters v-if="showNotesFilters" />
+ <commits-filters v-if="showCommitsFilters" />
</sidebar-portal>
</section>
+
<section
v-else-if="showScopeNavigation"
- class="search-sidebar gl-display-flex gl-flex-direction-column gl-md-mr-5 gl-mb-6 gl-mt-5"
+ class="gl-display-flex gl-flex-direction-column gl-lg-mr-0 gl-md-mr-5 gl-lg-mb-6 gl-lg-mt-5"
>
- <scope-legacy-navigation />
- <issues-filters v-if="showIssuesFilters" />
- <merge-requests-filters v-if="showMergeRequestFilters" />
- <blobs-filters v-if="showBlobFilters" />
- <projects-filters v-if="showProjectsFilters" />
+ <div class="search-sidebar gl-display-none gl-lg-display-block">
+ <scope-legacy-navigation />
+ <issues-filters v-if="showIssuesFilters" />
+ <merge-requests-filters v-if="showMergeRequestFilters" />
+ <blobs-filters v-if="showBlobFilters" />
+ <projects-filters v-if="showProjectsFilters" />
+ <notes-filters v-if="showNotesFilters" />
+ <commits-filters v-if="showCommitsFilters" />
+ </div>
+ <small-screen-drawer-navigation class="gl-lg-display-none">
+ <scope-legacy-navigation />
+ <issues-filters v-if="showIssuesFilters" />
+ <merge-requests-filters v-if="showMergeRequestFilters" />
+ <blobs-filters v-if="showBlobFilters" />
+ <projects-filters v-if="showProjectsFilters" />
+ <notes-filters v-if="showNotesFilters" />
+ <commits-filters v-if="showCommitsFilters" />
+ </small-screen-drawer-navigation>
</section>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/archived_filter/data.js b/app/assets/javascripts/search/sidebar/components/archived_filter/data.js
index 77efbdd9e60..5cddf5e744f 100644
--- a/app/assets/javascripts/search/sidebar/components/archived_filter/data.js
+++ b/app/assets/javascripts/search/sidebar/components/archived_filter/data.js
@@ -7,6 +7,11 @@ export const TRACKING_LABEL_CHECKBOX = 'checkbox';
const scopes = {
PROJECTS: 'projects',
+ ISSUES: 'issues',
+ MERGE_REQUESTS: 'merge_requests',
+ NOTES: 'notes',
+ BLOBS: 'blobs',
+ COMMITS: 'commits',
};
const filterParam = 'include_archived';
diff --git a/app/assets/javascripts/search/sidebar/components/archived_filter/index.vue b/app/assets/javascripts/search/sidebar/components/archived_filter/index.vue
index 1984e3a36c4..c31c46f2e6a 100644
--- a/app/assets/javascripts/search/sidebar/components/archived_filter/index.vue
+++ b/app/assets/javascripts/search/sidebar/components/archived_filter/index.vue
@@ -14,7 +14,7 @@ export default {
GlFormCheckbox,
},
computed: {
- ...mapState(['urlQuery']),
+ ...mapState(['urlQuery', 'useSidebarNavigation']),
selectedFilter: {
get() {
return [parseBoolean(this.urlQuery?.include_archived)];
@@ -41,7 +41,9 @@ export default {
<template>
<gl-form-checkbox-group v-model="selectedFilter">
- <h5>{{ $options.archivedFilterData.headerLabel }}</h5>
+ <h5 class="gl-mt-0 gl-mb-5" :class="{ 'gl-font-sm': useSidebarNavigation }">
+ {{ $options.archivedFilterData.headerLabel }}
+ </h5>
<gl-form-checkbox
class="gl-flex-grow-1 gl-display-inline-flex gl-justify-content-space-between gl-w-full"
:class="$options.LABEL_DEFAULT_CLASSES"
diff --git a/app/assets/javascripts/search/sidebar/components/blobs_filters.vue b/app/assets/javascripts/search/sidebar/components/blobs_filters.vue
index 5f4d6fbd56c..ac36ae6b366 100644
--- a/app/assets/javascripts/search/sidebar/components/blobs_filters.vue
+++ b/app/assets/javascripts/search/sidebar/components/blobs_filters.vue
@@ -1,5 +1,10 @@
<script>
+// eslint-disable-next-line no-restricted-imports
+import { mapGetters, mapState } from 'vuex';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { HR_DEFAULT_CLASSES } from '../constants';
import LanguageFilter from './language_filter/index.vue';
+import ArchivedFilter from './archived_filter/index.vue';
import FiltersTemplate from './filters_template.vue';
export default {
@@ -7,6 +12,21 @@ export default {
components: {
LanguageFilter,
FiltersTemplate,
+ ArchivedFilter,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ computed: {
+ ...mapGetters(['currentScope']),
+ ...mapState(['useSidebarNavigation', 'searchType']),
+ showArchivedFilter() {
+ return this.glFeatures.searchBlobsHideArchivedProjects;
+ },
+ showDivider() {
+ return !this.useSidebarNavigation && this.showArchivedFilter;
+ },
+ hrClasses() {
+ return [...HR_DEFAULT_CLASSES, 'gl-display-none', 'gl-md-display-block'];
+ },
},
};
</script>
@@ -14,5 +34,7 @@ export default {
<template>
<filters-template>
<language-filter class="gl-mb-5" />
+ <hr v-if="showDivider" :class="hrClasses" />
+ <archived-filter v-if="showArchivedFilter" class="gl-mb-5" />
</filters-template>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/commits_filters.vue b/app/assets/javascripts/search/sidebar/components/commits_filters.vue
new file mode 100644
index 00000000000..4f9fdbe9551
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/commits_filters.vue
@@ -0,0 +1,18 @@
+<script>
+import ArchivedFilter from './archived_filter/index.vue';
+import FiltersTemplate from './filters_template.vue';
+
+export default {
+ name: 'CommitsFilters',
+ components: {
+ ArchivedFilter,
+ FiltersTemplate,
+ },
+};
+</script>
+
+<template>
+ <filters-template>
+ <archived-filter class="gl-mb-5" />
+ </filters-template>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/components/filters_template.vue b/app/assets/javascripts/search/sidebar/components/filters_template.vue
index 3dae05ccc69..0f68bf92048 100644
--- a/app/assets/javascripts/search/sidebar/components/filters_template.vue
+++ b/app/assets/javascripts/search/sidebar/components/filters_template.vue
@@ -21,9 +21,6 @@ export default {
computed: {
...mapState(['sidebarDirty', 'useSidebarNavigation']),
...mapGetters(['currentScope']),
- hrClasses() {
- return [...HR_DEFAULT_CLASSES, 'gl-display-none', 'gl-md-display-block'];
- },
},
methods: {
...mapActions(['applyQuery', 'resetQuery']),
@@ -40,14 +37,15 @@ export default {
this.resetQuery();
},
},
+ HR_DEFAULT_CLASSES,
};
</script>
<template>
<gl-form class="issue-filters gl-px-5 gl-pt-0" @submit.prevent="applyQueryWithTracking">
- <hr v-if="!useSidebarNavigation" :class="hrClasses" />
+ <hr v-if="!useSidebarNavigation" :class="$options.HR_DEFAULT_CLASSES" />
<slot></slot>
- <hr v-if="!useSidebarNavigation" :class="hrClasses" />
+ <hr v-if="!useSidebarNavigation" :class="$options.HR_DEFAULT_CLASSES" />
<div class="gl-display-flex gl-align-items-center gl-mt-4">
<gl-button category="primary" variant="confirm" type="submit" :disabled="!sidebarDirty">
{{ __('Apply') }}
diff --git a/app/assets/javascripts/search/sidebar/components/issues_filters.vue b/app/assets/javascripts/search/sidebar/components/issues_filters.vue
index 919bd2b2e49..dbd52978163 100644
--- a/app/assets/javascripts/search/sidebar/components/issues_filters.vue
+++ b/app/assets/javascripts/search/sidebar/components/issues_filters.vue
@@ -2,13 +2,15 @@
// eslint-disable-next-line no-restricted-imports
import { mapGetters, mapState } from 'vuex';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { HR_DEFAULT_CLASSES } from '../constants/index';
+import { HR_DEFAULT_CLASSES, SEARCH_TYPE_ADVANCED } from '../constants';
import { confidentialFilterData } from './confidentiality_filter/data';
import { statusFilterData } from './status_filter/data';
import ConfidentialityFilter from './confidentiality_filter/index.vue';
import { labelFilterData } from './label_filter/data';
+import { archivedFilterData } from './archived_filter/data';
import LabelFilter from './label_filter/index.vue';
import StatusFilter from './status_filter/index.vue';
+import ArchivedFilter from './archived_filter/index.vue';
import FiltersTemplate from './filters_template.vue';
@@ -19,11 +21,12 @@ export default {
ConfidentialityFilter,
LabelFilter,
FiltersTemplate,
+ ArchivedFilter,
},
mixins: [glFeatureFlagsMixin()],
computed: {
...mapGetters(['currentScope']),
- ...mapState(['useSidebarNavigation']),
+ ...mapState(['useSidebarNavigation', 'searchType']),
showConfidentialityFilter() {
return Object.values(confidentialFilterData.scopes).includes(this.currentScope);
},
@@ -33,7 +36,15 @@ export default {
showLabelFilter() {
return (
Object.values(labelFilterData.scopes).includes(this.currentScope) &&
- this.glFeatures.searchIssueLabelAggregation
+ this.glFeatures.searchIssueLabelAggregation &&
+ this.searchType === SEARCH_TYPE_ADVANCED
+ );
+ },
+ showArchivedFilter() {
+ return (
+ Object.values(archivedFilterData.scopes).includes(this.currentScope) &&
+ this.glFeatures.searchIssuesHideArchivedProjects &&
+ this.searchType === SEARCH_TYPE_ADVANCED
);
},
showDivider() {
@@ -52,6 +63,8 @@ export default {
<hr v-if="showConfidentialityFilter && showDivider" :class="hrClasses" />
<confidentiality-filter v-if="showConfidentialityFilter" class="gl-mb-5" />
<hr v-if="showLabelFilter && showDivider" :class="hrClasses" />
- <label-filter v-if="showLabelFilter" />
+ <label-filter v-if="showLabelFilter" class="gl-mb-5" />
+ <hr v-if="showArchivedFilter && showDivider" :class="hrClasses" />
+ <archived-filter v-if="showArchivedFilter" class="gl-mb-5" />
</filters-template>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/language_filter/index.vue b/app/assets/javascripts/search/sidebar/components/language_filter/index.vue
index ca1503d7c64..784207cc702 100644
--- a/app/assets/javascripts/search/sidebar/components/language_filter/index.vue
+++ b/app/assets/javascripts/search/sidebar/components/language_filter/index.vue
@@ -74,7 +74,7 @@ export default {
</script>
<template>
- <div v-if="hasBuckets" class="gl-my-0 language-filter-checkbox">
+ <div v-if="hasBuckets" class="language-filter-checkbox">
<h5 class="gl-mt-0 gl-mb-5" :class="{ 'gl-font-sm': useSidebarNavigation }">
{{ $options.languageFilterData.header }}
</h5>
diff --git a/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue b/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue
index bc5b797dd56..2845eb2049b 100644
--- a/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue
+++ b/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue
@@ -1,18 +1,49 @@
<script>
+// eslint-disable-next-line no-restricted-imports
+import { mapGetters, mapState } from 'vuex';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { HR_DEFAULT_CLASSES, SEARCH_TYPE_ADVANCED } from '../constants';
+import { statusFilterData } from './status_filter/data';
import StatusFilter from './status_filter/index.vue';
import FiltersTemplate from './filters_template.vue';
+import { archivedFilterData } from './archived_filter/data';
+import ArchivedFilter from './archived_filter/index.vue';
export default {
name: 'MergeRequestsFilters',
components: {
StatusFilter,
FiltersTemplate,
+ ArchivedFilter,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ computed: {
+ ...mapGetters(['currentScope']),
+ ...mapState(['useSidebarNavigation', 'searchType']),
+ showArchivedFilter() {
+ return (
+ Object.values(archivedFilterData.scopes).includes(this.currentScope) &&
+ this.glFeatures.searchMergeRequestsHideArchivedProjects &&
+ this.searchType === SEARCH_TYPE_ADVANCED
+ );
+ },
+ showStatusFilter() {
+ return Object.values(statusFilterData.scopes).includes(this.currentScope);
+ },
+ showDivider() {
+ return !this.useSidebarNavigation;
+ },
+ hrClasses() {
+ return [...HR_DEFAULT_CLASSES, 'gl-display-none', 'gl-md-display-block'];
+ },
},
};
</script>
<template>
<filters-template>
- <status-filter class="gl-mb-5" />
+ <status-filter v-if="showStatusFilter" class="gl-mb-5" />
+ <hr v-if="showArchivedFilter && showDivider" :class="hrClasses" />
+ <archived-filter v-if="showArchivedFilter" class="gl-mb-5" />
</filters-template>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/notes_filters.vue b/app/assets/javascripts/search/sidebar/components/notes_filters.vue
new file mode 100644
index 00000000000..3a9f582d554
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/notes_filters.vue
@@ -0,0 +1,18 @@
+<script>
+import ArchivedFilter from './archived_filter/index.vue';
+import FiltersTemplate from './filters_template.vue';
+
+export default {
+ name: 'NotesFilters',
+ components: {
+ ArchivedFilter,
+ FiltersTemplate,
+ },
+};
+</script>
+
+<template>
+ <filters-template>
+ <archived-filter class="gl-mb-5" />
+ </filters-template>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/components/scope_legacy_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_legacy_navigation.vue
index e8d5de4d769..a4c1119736f 100644
--- a/app/assets/javascripts/search/sidebar/components/scope_legacy_navigation.vue
+++ b/app/assets/javascripts/search/sidebar/components/scope_legacy_navigation.vue
@@ -57,7 +57,7 @@ export default {
</script>
<template>
- <nav data-testid="search-filter">
+ <nav data-testid="search-filter" class="gl-border-none">
<gl-nav vertical pills>
<gl-nav-item
v-for="(item, scope) in navigation"
@@ -81,6 +81,5 @@ export default {
</span>
</gl-nav-item>
</gl-nav>
- <hr class="gl-mt-5 gl-mx-5 gl-mb-0 gl-border-gray-100 gl-md-display-none" />
</nav>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/small_screen_drawer_navigation.vue b/app/assets/javascripts/search/sidebar/components/small_screen_drawer_navigation.vue
new file mode 100644
index 00000000000..e966b8d877e
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/small_screen_drawer_navigation.vue
@@ -0,0 +1,61 @@
+<script>
+import { GlDrawer } from '@gitlab/ui';
+import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
+import { DRAWER_Z_INDEX } from '~/lib/utils/constants';
+import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
+import { s__ } from '~/locale';
+
+export default {
+ name: 'SmallScreenDrawerNavigation',
+ components: {
+ GlDrawer,
+ DomElementListener,
+ },
+ i18n: {
+ smallScreenFiltersDrawerHeader: s__('GlobalSearch|Filters'),
+ },
+ data() {
+ return {
+ openSmallScreenFilters: false,
+ };
+ },
+ computed: {
+ getDrawerHeaderHeight() {
+ if (!this.openSmallScreenFilters) return '0';
+ return getContentWrapperHeight();
+ },
+ },
+ methods: {
+ closeSmallScreenFilters() {
+ this.openSmallScreenFilters = false;
+ },
+ toggleSmallScreenFilters() {
+ this.openSmallScreenFilters = !this.openSmallScreenFilters;
+ },
+ },
+ DRAWER_Z_INDEX,
+};
+</script>
+<template>
+ <dom-element-listener selector="#js-open-mobile-filters" @click="toggleSmallScreenFilters">
+ <gl-drawer
+ :header-height="getDrawerHeaderHeight"
+ :z-index="$options.DRAWER_Z_INDEX"
+ variant="sidebar"
+ class="small-screen-drawer-navigation"
+ :open="openSmallScreenFilters"
+ @close="closeSmallScreenFilters"
+ >
+ <template #title>
+ <h2 class="gl-my-0 gl-font-size-h2 gl-line-height-24">
+ {{ $options.i18n.smallScreenFiltersDrawerHeader }}
+ </h2>
+ </template>
+ <template #default>
+ <div>
+ <slot></slot>
+ </div>
+ </template>
+ </gl-drawer>
+ </dom-element-listener>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/constants/index.js b/app/assets/javascripts/search/sidebar/constants/index.js
index 01d0aad206c..19df875c292 100644
--- a/app/assets/javascripts/search/sidebar/constants/index.js
+++ b/app/assets/javascripts/search/sidebar/constants/index.js
@@ -2,6 +2,8 @@ export const SCOPE_ISSUES = 'issues';
export const SCOPE_MERGE_REQUESTS = 'merge_requests';
export const SCOPE_BLOB = 'blobs';
export const SCOPE_PROJECTS = 'projects';
+export const SCOPE_NOTES = 'notes';
+export const SCOPE_COMMITS = 'commits';
export const LABEL_DEFAULT_CLASSES = [
'gl-display-flex',
'gl-flex-direction-row',
@@ -19,3 +21,7 @@ export const ONLY_SHOW_MD = ['gl-display-none', 'gl-md-display-block'];
export const TRACKING_ACTION_CLICK = 'search:filters:click';
export const TRACKING_LABEL_APPLY = 'Apply Filters';
export const TRACKING_LABEL_RESET = 'Reset Filters';
+
+export const SEARCH_TYPE_BASIC = 'basic';
+export const SEARCH_TYPE_ADVANCED = 'advanced';
+export const SEARCH_TYPE_ZOEKT = 'zoekt';
diff --git a/app/assets/javascripts/search/sidebar/index.js b/app/assets/javascripts/search/sidebar/index.js
index 415f6f7454c..3a699355dc9 100644
--- a/app/assets/javascripts/search/sidebar/index.js
+++ b/app/assets/javascripts/search/sidebar/index.js
@@ -8,9 +8,11 @@ export const sidebarInitState = () => {
const el = document.getElementById('js-search-sidebar');
if (!el) return {};
- const { navigationJson } = el.dataset;
+ const { navigationJson, searchType } = el.dataset;
+
const navigationJsonParsed = JSON.parse(navigationJson);
- return { navigationJsonParsed };
+
+ return { navigationJsonParsed, searchType };
};
export const initSidebar = (store) => {
diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js
index a68a0f75a2f..211bbaf82cd 100644
--- a/app/assets/javascripts/search/store/actions.js
+++ b/app/assets/javascripts/search/store/actions.js
@@ -138,7 +138,7 @@ export const setLabelFilterSearch = ({ commit }, { value }) => {
export const fetchSidebarCount = ({ commit, state }) => {
const promises = Object.values(state.navigation).map((navItem) => {
// active nav item has count already so we skip it
- if (!navItem.active) {
+ if (!navItem.active && navItem.count_link) {
return axios
.get(navItem.count_link)
.then(({ data: { count } }) => {
diff --git a/app/assets/javascripts/search/store/mutations.js b/app/assets/javascripts/search/store/mutations.js
index 65bb21f1b8a..b248681f053 100644
--- a/app/assets/javascripts/search/store/mutations.js
+++ b/app/assets/javascripts/search/store/mutations.js
@@ -33,7 +33,7 @@ export default {
state.frequentItems[key] = data;
},
[types.RECEIVE_NAVIGATION_COUNT](state, { key, count }) {
- const item = { ...state.navigation[key], count };
+ const item = { ...state.navigation[key], count, count_link: null };
state.navigation = { ...state.navigation, [key]: item };
},
[types.REQUEST_AGGREGATIONS](state) {
diff --git a/app/assets/javascripts/search/store/state.js b/app/assets/javascripts/search/store/state.js
index 5407b08fa83..b4cd2af65ba 100644
--- a/app/assets/javascripts/search/store/state.js
+++ b/app/assets/javascripts/search/store/state.js
@@ -1,7 +1,7 @@
import { cloneDeep } from 'lodash';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants';
-const createState = ({ query, navigation, useSidebarNavigation }) => ({
+const createState = ({ query, navigation, useSidebarNavigation, searchType }) => ({
urlQuery: cloneDeep(query),
query,
groups: [],
@@ -21,6 +21,7 @@ const createState = ({ query, navigation, useSidebarNavigation }) => ({
data: [],
},
searchLabelString: '',
+ searchType,
});
export default createState;
diff --git a/app/assets/javascripts/search/store/utils.js b/app/assets/javascripts/search/store/utils.js
index 2f02ef3475c..b15f89fc6a2 100644
--- a/app/assets/javascripts/search/store/utils.js
+++ b/app/assets/javascripts/search/store/utils.js
@@ -68,7 +68,8 @@ export const setFrequentItemToLS = (key, data, itemData) => {
frequentItems.sort((a, b) => {
if (a.frequency > b.frequency) {
return -1;
- } else if (a.frequency < b.frequency) {
+ }
+ if (a.frequency < b.frequency) {
return 1;
}
return b.lastUsed - a.lastUsed;
diff --git a/app/assets/javascripts/security_configuration/components/app.vue b/app/assets/javascripts/security_configuration/components/app.vue
index c7d89113895..32d46a0d4af 100644
--- a/app/assets/javascripts/security_configuration/components/app.vue
+++ b/app/assets/javascripts/security_configuration/components/app.vue
@@ -1,13 +1,18 @@
<script>
import { GlTab, GlTabs, GlSprintf, GlLink, GlAlert } from '@gitlab/ui';
+import Api from '~/api';
import { __, s__ } from '~/locale';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
import SectionLayout from '~/vue_shared/security_configuration/components/section_layout.vue';
import SafeHtml from '~/vue_shared/directives/safe_html';
+import { SERVICE_PING_SECURITY_CONFIGURATION_THREAT_MANAGEMENT_VISIT } from '~/tracking/constants';
import AutoDevOpsAlert from './auto_dev_ops_alert.vue';
import AutoDevOpsEnabledAlert from './auto_dev_ops_enabled_alert.vue';
-import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY } from './constants';
+import {
+ AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY,
+ TAB_VULNERABILITY_MANAGEMENT_INDEX,
+} from './constants';
import FeatureCard from './feature_card.vue';
import TrainingProviderList from './training_provider_list.vue';
@@ -123,6 +128,11 @@ export default {
dismissAlert() {
this.errorMessage = '';
},
+ tabChange(value) {
+ if (value === TAB_VULNERABILITY_MANAGEMENT_INDEX) {
+ Api.trackRedisHllUserEvent(SERVICE_PING_SECURITY_CONFIGURATION_THREAT_MANAGEMENT_VISIT);
+ }
+ },
},
autoDevopsEnabledAlertStorageKey: AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY,
};
@@ -167,6 +177,7 @@ export default {
data-testid="security-configuration-container"
sync-active-tab-with-query-params
lazy
+ @input="tabChange"
>
<gl-tab
data-testid="security-testing-tab"
diff --git a/app/assets/javascripts/security_configuration/components/constants.js b/app/assets/javascripts/security_configuration/components/constants.js
index b427820144d..da213b0ed43 100644
--- a/app/assets/javascripts/security_configuration/components/constants.js
+++ b/app/assets/javascripts/security_configuration/components/constants.js
@@ -1,5 +1,6 @@
import { helpPagePath } from '~/helpers/help_page_helper';
import { __, s__ } from '~/locale';
+import ContinuousVulnerabilityScan from '~/security_configuration/components/continuous_vulnerability_scan.vue';
import {
REPORT_TYPE_SAST,
@@ -210,6 +211,7 @@ export const securityFeatures = [
configurationHelpPath: DEPENDENCY_SCANNING_CONFIG_HELP_PATH,
type: REPORT_TYPE_DEPENDENCY_SCANNING,
anchor: 'dependency-scanning',
+ slotComponent: ContinuousVulnerabilityScan,
},
{
name: CONTAINER_SCANNING_NAME,
@@ -326,3 +328,5 @@ export const TEMP_PROVIDER_URLS = {
[__('Secure Code Warrior')]: 'https://www.securecodewarrior.com/',
SecureFlag: 'https://www.secureflag.com/',
};
+
+export const TAB_VULNERABILITY_MANAGEMENT_INDEX = 1;
diff --git a/app/assets/javascripts/security_configuration/components/continuous_vulnerability_scan.vue b/app/assets/javascripts/security_configuration/components/continuous_vulnerability_scan.vue
new file mode 100644
index 00000000000..61cbde2107c
--- /dev/null
+++ b/app/assets/javascripts/security_configuration/components/continuous_vulnerability_scan.vue
@@ -0,0 +1,127 @@
+<script>
+import { GlBadge, GlIcon, GlToggle, GlLink, GlSprintf, GlAlert } from '@gitlab/ui';
+import ProjectSetContinuousVulnerabilityScanning from '~/security_configuration/graphql/project_set_continuous_vulnerability_scanning.graphql';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { __, s__ } from '~/locale';
+import { helpPagePath } from '~/helpers/help_page_helper';
+
+export default {
+ name: 'ContinuousVulnerabilityscan',
+ components: { GlBadge, GlIcon, GlToggle, GlLink, GlSprintf, GlAlert },
+ mixins: [glFeatureFlagsMixin()],
+ inject: ['continuousVulnerabilityScansEnabled', 'projectFullPath'],
+ i18n: {
+ badgeLabel: __('Experiment'),
+ title: s__('CVS|Continuous Vulnerability Scan'),
+ description: s__(
+ 'CVS|Detect vulnerabilities outside a pipeline as new data is added to the GitLab Advisory Database.',
+ ),
+ learnMore: __('Learn more'),
+ testingAgreementMessage: s__(
+ 'CVS|By enabling this feature, you accept the %{linkStart}Testing Terms of Use%{linkEnd}',
+ ),
+ },
+ props: {
+ feature: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ toggleValue: this.continuousVulnerabilityScansEnabled,
+ errorMessage: '',
+ isAlertDismissed: false,
+ };
+ },
+ computed: {
+ isFeatureConfigured() {
+ return this.feature.available && this.feature.configured;
+ },
+ shouldShowAlert() {
+ return this.errorMessage && !this.isAlertDismissed;
+ },
+ },
+ methods: {
+ reportError(error) {
+ this.errorMessage = error;
+ this.isAlertDismissed = false;
+ },
+ async toggleCVS(checked) {
+ try {
+ const { data } = await this.$apollo.mutate({
+ mutation: ProjectSetContinuousVulnerabilityScanning,
+ variables: {
+ input: {
+ projectPath: this.projectFullPath,
+ enable: checked,
+ },
+ },
+ });
+
+ const { errors } = data.projectSetContinuousVulnerabilityScanning;
+
+ if (errors.length > 0) {
+ this.reportError(errors[0].message);
+ }
+ if (data.projectSetContinuousVulnerabilityScanning !== null) {
+ this.toggleValue = checked;
+ }
+ } catch (error) {
+ this.reportError(error);
+ }
+ },
+ },
+ CVSHelpPagePath: helpPagePath(
+ 'user/application_security/continuous_vulnerability_scanning/index',
+ ),
+ experimentHelpPagePath: helpPagePath('policy/experiment-beta-support', { anchor: 'experiment' }),
+};
+</script>
+
+<template>
+ <div v-if="glFeatures.dependencyScanningOnAdvisoryIngestion">
+ <h4 class="gl-font-base gl-m-0 gl-mt-6">
+ {{ $options.i18n.title }}
+ <gl-badge
+ ref="badge"
+ :href="$options.experimentHelpPagePath"
+ target="_blank"
+ size="sm"
+ variant="neutral"
+ class="gl-cursor-pointer"
+ >{{ $options.i18n.badgeLabel }}</gl-badge
+ >
+ </h4>
+ <gl-alert
+ v-if="shouldShowAlert"
+ class="gl-mb-5 gl-mt-2"
+ variant="danger"
+ @dismiss="isAlertDismissed = true"
+ >{{ errorMessage }}</gl-alert
+ >
+ <gl-toggle
+ class="gl-mt-5"
+ :disabled="!isFeatureConfigured"
+ :value="toggleValue"
+ :label="s__('CVS|Toggle CVS')"
+ label-position="hidden"
+ @change="toggleCVS"
+ />
+
+ <p class="gl-mb-0 gl-mt-5">
+ {{ $options.i18n.description }}
+ <gl-link :href="$options.CVSHelpPagePath" target="_blank">{{
+ $options.i18n.learnMore
+ }}</gl-link>
+ <br />
+ <gl-sprintf :message="$options.i18n.testingAgreementMessage">
+ <template #link="{ content }">
+ <gl-link href="https://about.gitlab.com/handbook/legal/testing-agreement" target="_blank">
+ {{ content }} <gl-icon name="external-link" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </div>
+</template>
diff --git a/app/assets/javascripts/security_configuration/components/feature_card.vue b/app/assets/javascripts/security_configuration/components/feature_card.vue
index a757657339b..7f0a049a6ad 100644
--- a/app/assets/javascripts/security_configuration/components/feature_card.vue
+++ b/app/assets/javascripts/security_configuration/components/feature_card.vue
@@ -73,6 +73,9 @@ export default {
hasSecondary() {
return Boolean(this.feature.secondary);
},
+ hasSlotComponent() {
+ return Boolean(this.feature.slotComponent);
+ },
// This condition is a temporary hack to not display any wrong information
// until this BE Bug is fixed: https://gitlab.com/gitlab-org/gitlab/-/issues/350307.
// More Information: https://gitlab.com/gitlab-org/gitlab/-/issues/350307#note_825447417
@@ -215,5 +218,9 @@ export default {
{{ $options.i18n.configurationGuide }}
</gl-button>
</div>
+
+ <div v-if="hasSlotComponent">
+ <component :is="feature.slotComponent" :feature="feature" />
+ </div>
</gl-card>
</template>
diff --git a/app/assets/javascripts/security_configuration/graphql/project_set_continuous_vulnerability_scanning.graphql b/app/assets/javascripts/security_configuration/graphql/project_set_continuous_vulnerability_scanning.graphql
new file mode 100644
index 00000000000..79f4316d106
--- /dev/null
+++ b/app/assets/javascripts/security_configuration/graphql/project_set_continuous_vulnerability_scanning.graphql
@@ -0,0 +1,8 @@
+mutation ProjectSetContinuousVulnerabilityScanning(
+ $input: ProjectSetContinuousVulnerabilityScanningInput!
+) {
+ projectSetContinuousVulnerabilityScanning(input: $input) {
+ continuousVulnerabilityScanningEnabled
+ errors
+ }
+}
diff --git a/app/assets/javascripts/security_configuration/index.js b/app/assets/javascripts/security_configuration/index.js
index aa3c9c87622..4b498091134 100644
--- a/app/assets/javascripts/security_configuration/index.js
+++ b/app/assets/javascripts/security_configuration/index.js
@@ -26,6 +26,7 @@ export const initSecurityConfiguration = (el) => {
autoDevopsHelpPagePath,
autoDevopsPath,
vulnerabilityTrainingDocsPath,
+ continuousVulnerabilityScansEnabled,
} = el.dataset;
const { augmentedSecurityFeatures } = augmentFeatures(
@@ -43,6 +44,7 @@ export const initSecurityConfiguration = (el) => {
autoDevopsHelpPagePath,
autoDevopsPath,
vulnerabilityTrainingDocsPath,
+ continuousVulnerabilityScansEnabled,
},
render(createElement) {
return createElement(SecurityConfigurationApp, {
diff --git a/app/assets/javascripts/security_configuration/utils.js b/app/assets/javascripts/security_configuration/utils.js
index 72e6d870e13..7f0caf1af46 100644
--- a/app/assets/javascripts/security_configuration/utils.js
+++ b/app/assets/javascripts/security_configuration/utils.js
@@ -1,5 +1,6 @@
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { SCANNER_NAMES_MAP } from '~/security_configuration/components/constants';
+import { REPORT_TYPE_DAST } from '~/vue_shared/security_reports/constants';
/**
* This function takes in 3 arrays of objects, securityFeatures and features.
@@ -29,6 +30,10 @@ export const augmentFeatures = (securityFeatures, features = []) => {
augmented.secondary = { ...augmented.secondary, ...featuresByType[feature.secondary.type] };
}
+ if (augmented.type === REPORT_TYPE_DAST && !augmented.onDemandAvailable) {
+ delete augmented.badge;
+ }
+
if (augmented.badge && augmented.metaInfoPath) {
augmented.badge.badgeHref = augmented.metaInfoPath;
}
diff --git a/app/assets/javascripts/sentry/index.js b/app/assets/javascripts/sentry/index.js
index cf6a79fe939..940caea3322 100644
--- a/app/assets/javascripts/sentry/index.js
+++ b/app/assets/javascripts/sentry/index.js
@@ -1,35 +1,4 @@
import '../webpack';
+import { initSentry } from './init_sentry';
-import * as Sentry from 'sentrybrowser7';
-import SentryConfig from './sentry_config';
-
-const index = function index() {
- // Configuration for newer versions of Sentry SDK (v7)
- SentryConfig.init({
- dsn: gon.sentry_dsn,
- environment: gon.sentry_environment,
- currentUserId: gon.current_user_id,
- allowUrls:
- process.env.NODE_ENV === 'production'
- ? [gon.gitlab_url]
- : [gon.gitlab_url, 'webpack-internal://'],
- release: gon?.version,
- tags: {
- revision: gon?.revision,
- feature_category: gon?.feature_category,
- page: document?.body?.dataset?.page,
- },
- });
-};
-
-index();
-
-// The _Sentry object is globally exported so it can be used by
-// ./sentry_browser_wrapper.js
-// This hack allows us to load a single version of `@sentry/browser`
-// in the browser, see app/views/layouts/_head.html.haml to find how it is imported.
-
-// eslint-disable-next-line no-underscore-dangle
-window._Sentry = Sentry;
-
-export default index;
+initSentry();
diff --git a/app/assets/javascripts/sentry/init_sentry.js b/app/assets/javascripts/sentry/init_sentry.js
new file mode 100644
index 00000000000..dbd12dc36ce
--- /dev/null
+++ b/app/assets/javascripts/sentry/init_sentry.js
@@ -0,0 +1,77 @@
+import {
+ BrowserClient,
+ getCurrentHub,
+ defaultStackParser,
+ makeFetchTransport,
+ defaultIntegrations,
+
+ // exports
+ captureException,
+ captureMessage,
+ withScope,
+ SDK_VERSION,
+} from 'sentrybrowser';
+
+const initSentry = () => {
+ if (!gon?.sentry_dsn) {
+ return;
+ }
+
+ const hub = getCurrentHub();
+
+ const client = new BrowserClient({
+ // Sentry.init(...) options
+ dsn: gon.sentry_dsn,
+ release: gon.version,
+ allowUrls:
+ process.env.NODE_ENV === 'production'
+ ? [gon.gitlab_url]
+ : [gon.gitlab_url, 'webpack-internal://'],
+ environment: gon.sentry_environment,
+
+ // Browser tracing configuration
+ tracePropagationTargets: [/^\//], // only trace internal requests
+ tracesSampleRate: gon.sentry_clientside_traces_sample_rate || 0,
+
+ // This configuration imitates the Sentry.init() default configuration
+ // https://github.com/getsentry/sentry-javascript/blob/7.66.0/MIGRATION.md#explicit-client-options
+ transport: makeFetchTransport,
+ stackParser: defaultStackParser,
+ integrations: defaultIntegrations,
+ });
+
+ hub.bindClient(client);
+
+ hub.setTags({
+ revision: gon.revision,
+ feature_category: gon.feature_category,
+ page: document?.body?.dataset?.page,
+ });
+
+ if (gon.current_user_id) {
+ hub.setUser({
+ id: gon.current_user_id,
+ });
+ }
+
+ // The option `autoSessionTracking` is only avaialble on Sentry.init
+ // this manually starts a session in a similar way.
+ // See: https://github.com/getsentry/sentry-javascript/blob/7.66.0/packages/browser/src/sdk.ts#L204
+ hub.startSession({ ignoreDuration: true }); // `ignoreDuration` counts only the page view.
+ hub.captureSession();
+
+ // The _Sentry object is globally exported so it can be used by
+ // ./sentry_browser_wrapper.js
+ // This hack allows us to load a single version of `@sentry/browser`
+ // in the browser, see app/views/layouts/_head.html.haml to find how it is imported.
+
+ // eslint-disable-next-line no-underscore-dangle
+ window._Sentry = {
+ captureException,
+ captureMessage,
+ withScope,
+ SDK_VERSION, // used to verify compatibility with the Sentry instance
+ };
+};
+
+export { initSentry };
diff --git a/app/assets/javascripts/sentry/sentry_browser_wrapper.js b/app/assets/javascripts/sentry/sentry_browser_wrapper.js
index 0382827f82c..fbfd5d4f458 100644
--- a/app/assets/javascripts/sentry/sentry_browser_wrapper.js
+++ b/app/assets/javascripts/sentry/sentry_browser_wrapper.js
@@ -5,6 +5,8 @@
// This module wraps methods used by our production code.
// Each export is names as we cannot export the entire namespace from *.
+
+/** @type {import('@sentry/core').captureException} */
export const captureException = (...args) => {
// eslint-disable-next-line no-underscore-dangle
const Sentry = window._Sentry;
@@ -12,6 +14,7 @@ export const captureException = (...args) => {
Sentry?.captureException(...args);
};
+/** @type {import('@sentry/core').captureMessage} */
export const captureMessage = (...args) => {
// eslint-disable-next-line no-underscore-dangle
const Sentry = window._Sentry;
@@ -19,6 +22,7 @@ export const captureMessage = (...args) => {
Sentry?.captureMessage(...args);
};
+/** @type {import('@sentry/core').withScope} */
export const withScope = (...args) => {
// eslint-disable-next-line no-underscore-dangle
const Sentry = window._Sentry;
diff --git a/app/assets/javascripts/sentry/sentry_config.js b/app/assets/javascripts/sentry/sentry_config.js
deleted file mode 100644
index 80f087691f4..00000000000
--- a/app/assets/javascripts/sentry/sentry_config.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import * as Sentry from 'sentrybrowser7';
-
-const SentryConfig = {
- init(options = {}) {
- this.options = options;
-
- this.configure();
- if (this.options.currentUserId) this.setUser();
- },
-
- configure() {
- const { dsn, release, tags, allowUrls, environment } = this.options;
-
- Sentry.init({
- dsn,
- release,
- allowUrls,
- environment,
- });
-
- Sentry.setTags(tags);
- },
-
- setUser() {
- Sentry.setUser({
- id: this.options.currentUserId,
- });
- },
-};
-
-export default SentryConfig;
diff --git a/app/assets/javascripts/service_desk/components/empty_state_with_any_issues.vue b/app/assets/javascripts/service_desk/components/empty_state_with_any_issues.vue
deleted file mode 100644
index a15c8ee2e9f..00000000000
--- a/app/assets/javascripts/service_desk/components/empty_state_with_any_issues.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-<script>
-import { GlEmptyState } from '@gitlab/ui';
-import {
- noSearchResultsTitle,
- noSearchResultsDescription,
- infoBannerUserNote,
- noOpenIssuesTitle,
- noClosedIssuesTitle,
-} from '../constants';
-
-export default {
- i18n: {
- noSearchResultsTitle,
- noSearchResultsDescription,
- infoBannerUserNote,
- noOpenIssuesTitle,
- noClosedIssuesTitle,
- },
- components: {
- GlEmptyState,
- },
- inject: ['emptyStateSvgPath'],
- props: {
- hasSearch: {
- type: Boolean,
- required: true,
- },
- isOpenTab: {
- type: Boolean,
- required: true,
- },
- },
- computed: {
- content() {
- if (this.hasSearch) {
- return {
- title: noSearchResultsTitle,
- description: noSearchResultsDescription,
- svgHeight: 150,
- };
- } else if (this.isOpenTab) {
- return { title: noOpenIssuesTitle, description: infoBannerUserNote };
- }
-
- return { title: noClosedIssuesTitle, svgHeight: 150 };
- },
- },
-};
-</script>
-
-<template>
- <gl-empty-state
- :description="content.description"
- :title="content.title"
- :svg-path="emptyStateSvgPath"
- :svg-height="content.svgHeight"
- />
-</template>
diff --git a/app/assets/javascripts/service_desk/components/service_desk_list_app.vue b/app/assets/javascripts/service_desk/components/service_desk_list_app.vue
deleted file mode 100644
index 56cd21d7ea9..00000000000
--- a/app/assets/javascripts/service_desk/components/service_desk_list_app.vue
+++ /dev/null
@@ -1,443 +0,0 @@
-<script>
-import * as Sentry from '@sentry/browser';
-import fuzzaldrinPlus from 'fuzzaldrin-plus';
-import { isEmpty } from 'lodash';
-import { fetchPolicies } from '~/lib/graphql';
-import { isPositiveInteger } from '~/lib/utils/number_utils';
-import axios from '~/lib/utils/axios_utils';
-import { getParameterByName } from '~/lib/utils/url_utility';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { DEFAULT_PAGE_SIZE, issuableListTabs } from '~/vue_shared/issuable/list/constants';
-import {
- convertToSearchQuery,
- convertToApiParams,
- getInitialPageParams,
- getFilterTokens,
- isSortKey,
-} from '~/issues/list/utils';
-import {
- OPERATORS_IS_NOT,
- OPERATORS_IS_NOT_OR,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import {
- MAX_LIST_SIZE,
- ISSUE_REFERENCE,
- PARAM_STATE,
- PARAM_FIRST_PAGE_SIZE,
- PARAM_LAST_PAGE_SIZE,
- PARAM_PAGE_AFTER,
- PARAM_PAGE_BEFORE,
- PARAM_SORT,
- CREATED_DESC,
- UPDATED_DESC,
- urlSortParams,
-} from '~/issues/list/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import { TYPENAME_USER } from '~/graphql_shared/constants';
-import searchProjectMembers from '~/graphql_shared/queries/project_user_members_search.query.graphql';
-import getServiceDeskIssuesQuery from 'ee_else_ce/service_desk/queries/get_service_desk_issues.query.graphql';
-import getServiceDeskIssuesCounts from 'ee_else_ce/service_desk/queries/get_service_desk_issues_counts.query.graphql';
-import searchProjectLabelsQuery from '../queries/search_project_labels.query.graphql';
-import searchProjectMilestonesQuery from '../queries/search_project_milestones.query.graphql';
-import {
- errorFetchingCounts,
- errorFetchingIssues,
- searchPlaceholder,
- SERVICE_DESK_BOT_USERNAME,
- STATUS_OPEN,
- STATUS_CLOSED,
- STATUS_ALL,
- WORKSPACE_PROJECT,
-} from '../constants';
-import { convertToUrlParams } from '../utils';
-import {
- searchWithinTokenBase,
- assigneeTokenBase,
- milestoneTokenBase,
- labelTokenBase,
- releaseTokenBase,
- reactionTokenBase,
- confidentialityTokenBase,
-} from '../search_tokens';
-import InfoBanner from './info_banner.vue';
-import EmptyStateWithAnyIssues from './empty_state_with_any_issues.vue';
-import EmptyStateWithoutAnyIssues from './empty_state_without_any_issues.vue';
-
-export default {
- i18n: {
- errorFetchingCounts,
- errorFetchingIssues,
- searchPlaceholder,
- },
- issuableListTabs,
- components: {
- IssuableList,
- InfoBanner,
- EmptyStateWithAnyIssues,
- EmptyStateWithoutAnyIssues,
- },
- mixins: [glFeatureFlagMixin()],
- inject: [
- 'releasesPath',
- 'autocompleteAwardEmojisPath',
- 'hasIterationsFeature',
- 'hasIssueWeightsFeature',
- 'hasIssuableHealthStatusFeature',
- 'groupPath',
- 'emptyStateSvgPath',
- 'isProject',
- 'isSignedIn',
- 'fullPath',
- 'isServiceDeskSupported',
- 'hasAnyIssues',
- 'initialSort',
- ],
- props: {
- eeSearchTokens: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- data() {
- return {
- serviceDeskIssues: [],
- serviceDeskIssuesCounts: {},
- sortOptions: [],
- filterTokens: [],
- pageInfo: {},
- pageParams: {},
- sortKey: CREATED_DESC,
- state: STATUS_OPEN,
- pageSize: DEFAULT_PAGE_SIZE,
- issuesError: null,
- };
- },
- apollo: {
- serviceDeskIssues: {
- query: getServiceDeskIssuesQuery,
- variables() {
- return this.queryVariables;
- },
- update(data) {
- return data.project.issues.nodes ?? [];
- },
- fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
- // We need this for handling loading state when using frontend cache
- // See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106004#note_1217325202 for details
- notifyOnNetworkStatusChange: true,
- result({ data }) {
- if (!data) {
- return;
- }
- this.pageInfo = data?.project.issues.pageInfo ?? {};
- },
- error(error) {
- this.issuesError = this.$options.i18n.errorFetchingIssues;
- Sentry.captureException(error);
- },
- skip() {
- return this.shouldSkipQuery;
- },
- },
- serviceDeskIssuesCounts: {
- query: getServiceDeskIssuesCounts,
- variables() {
- return this.queryVariables;
- },
- update(data) {
- return data?.project ?? {};
- },
- error(error) {
- this.issuesError = this.$options.i18n.errorFetchingCounts;
- Sentry.captureException(error);
- },
- skip() {
- return this.shouldSkipQuery;
- },
- context: {
- isSingleRequest: true,
- },
- },
- },
- computed: {
- queryVariables() {
- const isIidSearch = ISSUE_REFERENCE.test(this.searchQuery);
- return {
- fullPath: this.fullPath,
- iid: isIidSearch ? this.searchQuery.slice(1) : undefined,
- isProject: this.isProject,
- isSignedIn: this.isSignedIn,
- authorUsername: SERVICE_DESK_BOT_USERNAME,
- sort: this.sortKey,
- state: this.state,
- ...this.pageParams,
- ...this.apiFilterParams,
- search: isIidSearch ? undefined : this.searchQuery,
- };
- },
- shouldSkipQuery() {
- return !this.hasAnyIssues || isEmpty(this.pageParams);
- },
- tabCounts() {
- const { openedIssues, closedIssues, allIssues } = this.serviceDeskIssuesCounts;
- return {
- [STATUS_OPEN]: openedIssues?.count,
- [STATUS_CLOSED]: closedIssues?.count,
- [STATUS_ALL]: allIssues?.count,
- };
- },
- isLoading() {
- return this.$apollo.queries.serviceDeskIssues.loading;
- },
- isOpenTab() {
- return this.state === STATUS_OPEN;
- },
- urlParams() {
- return {
- sort: urlSortParams[this.sortKey],
- state: this.state,
- ...this.urlFilterParams,
- first_page_size: this.pageParams.firstPageSize,
- last_page_size: this.pageParams.lastPageSize,
- page_after: this.pageParams.afterCursor ?? undefined,
- page_before: this.pageParams.beforeCursor ?? undefined,
- };
- },
- isInfoBannerVisible() {
- return this.isServiceDeskSupported && this.hasAnyServiceDeskIssues;
- },
- hasAnyServiceDeskIssues() {
- return this.hasSearch || Boolean(this.tabCounts.all);
- },
- hasOrFeature() {
- return this.glFeatures.orIssuableQueries;
- },
- hasSearch() {
- return Boolean(
- this.searchQuery ||
- Object.keys(this.urlFilterParams).length ||
- this.pageParams.afterCursor ||
- this.pageParams.beforeCursor,
- );
- },
- apiFilterParams() {
- return convertToApiParams(this.filterTokens);
- },
- urlFilterParams() {
- return convertToUrlParams(this.filterTokens);
- },
- searchQuery() {
- return convertToSearchQuery(this.filterTokens);
- },
- searchTokens() {
- const preloadedUsers = [];
-
- if (gon.current_user_id) {
- preloadedUsers.push({
- id: convertToGraphQLId(TYPENAME_USER, gon.current_user_id),
- name: gon.current_user_fullname,
- username: gon.current_username,
- avatar_url: gon.current_user_avatar_url,
- });
- }
-
- const tokens = [
- {
- ...searchWithinTokenBase,
- },
- {
- ...assigneeTokenBase,
- operators: this.hasOrFeature ? OPERATORS_IS_NOT_OR : OPERATORS_IS_NOT,
- fetchUsers: this.fetchUsers,
- recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-assignee`,
- preloadedUsers,
- },
- {
- ...milestoneTokenBase,
- fetchMilestones: this.fetchMilestones,
- recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-milestone`,
- },
- {
- ...labelTokenBase,
- operators: this.hasOrFeature ? OPERATORS_IS_NOT_OR : OPERATORS_IS_NOT,
- fetchLabels: this.fetchLabels,
- fetchLatestLabels: this.glFeatures.frontendCaching ? this.fetchLatestLabels : null,
- recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-label`,
- },
- ];
-
- if (this.isProject) {
- tokens.push({
- ...releaseTokenBase,
- fetchReleases: this.fetchReleases,
- recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-release`,
- });
- }
-
- if (this.isSignedIn) {
- tokens.push({
- ...reactionTokenBase,
- fetchEmojis: this.fetchEmojis,
- recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-my_reaction`,
- });
-
- tokens.push({
- ...confidentialityTokenBase,
- });
- }
-
- if (this.eeSearchTokens.length) {
- tokens.push(...this.eeSearchTokens);
- }
-
- tokens.sort((a, b) => a.title.localeCompare(b.title));
-
- return tokens;
- },
- },
- watch: {
- $route(newValue, oldValue) {
- if (newValue.fullPath !== oldValue.fullPath) {
- this.updateData(getParameterByName(PARAM_SORT));
- }
- },
- },
- created() {
- this.updateData(this.initialSort);
- this.cache = {};
- },
- methods: {
- fetchWithCache(path, cacheName, searchKey, search) {
- if (this.cache[cacheName]) {
- const data = search
- ? fuzzaldrinPlus.filter(this.cache[cacheName], search, { key: searchKey })
- : this.cache[cacheName].slice(0, MAX_LIST_SIZE);
- return Promise.resolve(data);
- }
-
- return axios.get(path).then(({ data }) => {
- this.cache[cacheName] = data;
- return data.slice(0, MAX_LIST_SIZE);
- });
- },
- fetchUsers(search) {
- return this.$apollo
- .query({
- query: searchProjectMembers,
- variables: { fullPath: this.fullPath, search },
- })
- .then(({ data }) =>
- data[WORKSPACE_PROJECT]?.[`${WORKSPACE_PROJECT}Members`].nodes.map(
- (member) => member.user,
- ),
- );
- },
- fetchMilestones(search) {
- return this.$apollo
- .query({
- query: searchProjectMilestonesQuery,
- variables: { fullPath: this.fullPath, search },
- })
- .then(({ data }) => data[WORKSPACE_PROJECT]?.milestones.nodes);
- },
- fetchEmojis(search) {
- return this.fetchWithCache(this.autocompleteAwardEmojisPath, 'emojis', 'name', search);
- },
- fetchReleases(search) {
- return this.fetchWithCache(this.releasesPath, 'releases', 'tag', search);
- },
- fetchLabelsWithFetchPolicy(search, fetchPolicy = fetchPolicies.CACHE_FIRST) {
- return this.$apollo
- .query({
- query: searchProjectLabelsQuery,
- variables: { fullPath: this.fullPath, search },
- fetchPolicy,
- })
- .then(({ data }) => data[WORKSPACE_PROJECT]?.labels.nodes)
- .then((labels) =>
- // TODO remove once we can search by title-only on the backend
- // https://gitlab.com/gitlab-org/gitlab/-/issues/346353
- labels.filter((label) => label.title.toLowerCase().includes(search.toLowerCase())),
- );
- },
- fetchLabels(search) {
- return this.fetchLabelsWithFetchPolicy(search);
- },
- fetchLatestLabels(search) {
- return this.fetchLabelsWithFetchPolicy(search, fetchPolicies.NETWORK_ONLY);
- },
- handleClickTab(state) {
- if (this.state === state) {
- return;
- }
- this.state = state;
- this.pageParams = getInitialPageParams(this.pageSize);
-
- this.$router.push({ query: this.urlParams });
- },
- handleFilter(tokens) {
- this.filterTokens = tokens;
- this.pageParams = getInitialPageParams(this.pageSize);
-
- this.$router.push({ query: this.urlParams });
- },
- updateData(sortValue) {
- const firstPageSize = getParameterByName(PARAM_FIRST_PAGE_SIZE);
- const lastPageSize = getParameterByName(PARAM_LAST_PAGE_SIZE);
- const state = getParameterByName(PARAM_STATE);
-
- const defaultSortKey = state === STATUS_CLOSED ? UPDATED_DESC : CREATED_DESC;
- const graphQLSortKey = isSortKey(sortValue?.toUpperCase()) && sortValue.toUpperCase();
-
- const sortKey = graphQLSortKey || defaultSortKey;
-
- this.filterTokens = getFilterTokens(window.location.search);
-
- this.pageParams = getInitialPageParams(
- this.pageSize,
- isPositiveInteger(firstPageSize) ? parseInt(firstPageSize, 10) : undefined,
- isPositiveInteger(lastPageSize) ? parseInt(lastPageSize, 10) : undefined,
- getParameterByName(PARAM_PAGE_AFTER),
- getParameterByName(PARAM_PAGE_BEFORE),
- );
- this.sortKey = sortKey;
- this.state = state || STATUS_OPEN;
- },
- },
-};
-</script>
-
-<template>
- <section>
- <info-banner v-if="isInfoBannerVisible" />
- <issuable-list
- v-if="isLoading || hasAnyServiceDeskIssues"
- namespace="service-desk"
- recent-searches-storage-key="service-desk-issues"
- :error="issuesError"
- :search-input-placeholder="$options.i18n.searchPlaceholder"
- :search-tokens="searchTokens"
- :issuables-loading="isLoading"
- :initial-filter-value="filterTokens"
- :show-filtered-search-friendly-text="hasOrFeature"
- :sort-options="sortOptions"
- :initial-sort-by="sortKey"
- :issuables="serviceDeskIssues"
- :tabs="$options.issuableListTabs"
- :tab-counts="tabCounts"
- :current-tab="state"
- :default-page-size="pageSize"
- sync-filter-and-sort
- @click-tab="handleClickTab"
- @filter="handleFilter"
- >
- <template #empty-state>
- <empty-state-with-any-issues :has-search="hasSearch" :is-open-tab="isOpenTab" />
- </template>
- </issuable-list>
-
- <empty-state-without-any-issues v-else />
- </section>
-</template>
diff --git a/app/assets/javascripts/service_desk/constants.js b/app/assets/javascripts/service_desk/constants.js
deleted file mode 100644
index a83c0d9ca57..00000000000
--- a/app/assets/javascripts/service_desk/constants.js
+++ /dev/null
@@ -1,251 +0,0 @@
-import { __, s__ } from '~/locale';
-import {
- FILTERED_SEARCH_TERM,
- OPERATOR_IS,
- OPERATOR_NOT,
- OPERATOR_OR,
- TOKEN_TYPE_ASSIGNEE,
- TOKEN_TYPE_CONFIDENTIAL,
- TOKEN_TYPE_EPIC,
- TOKEN_TYPE_HEALTH,
- TOKEN_TYPE_ITERATION,
- TOKEN_TYPE_LABEL,
- TOKEN_TYPE_MILESTONE,
- TOKEN_TYPE_MY_REACTION,
- TOKEN_TYPE_RELEASE,
- TOKEN_TYPE_TYPE,
- TOKEN_TYPE_WEIGHT,
- TOKEN_TYPE_SEARCH_WITHIN,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import {
- ALTERNATIVE_FILTER,
- API_PARAM,
- NORMAL_FILTER,
- SPECIAL_FILTER,
- URL_PARAM,
-} from '~/issues/list/constants';
-
-export const SERVICE_DESK_BOT_USERNAME = 'support-bot';
-export const ISSUE_REFERENCE = /^#\d+$/;
-
-export const STATUS_ALL = 'all';
-export const STATUS_CLOSED = 'closed';
-export const STATUS_OPEN = 'opened';
-
-export const WORKSPACE_PROJECT = 'project';
-
-export const filtersMap = {
- [FILTERED_SEARCH_TERM]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'search',
- },
- [URL_PARAM]: {
- [undefined]: {
- [NORMAL_FILTER]: 'search',
- },
- },
- },
- [TOKEN_TYPE_SEARCH_WITHIN]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'in',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'in',
- },
- },
- },
- [TOKEN_TYPE_ASSIGNEE]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'assigneeUsernames',
- [SPECIAL_FILTER]: 'assigneeId',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'assignee_username[]',
- [SPECIAL_FILTER]: 'assignee_id',
- [ALTERNATIVE_FILTER]: 'assignee_username',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[assignee_username][]',
- },
- [OPERATOR_OR]: {
- [NORMAL_FILTER]: 'or[assignee_username][]',
- },
- },
- },
- [TOKEN_TYPE_MILESTONE]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'milestoneTitle',
- [SPECIAL_FILTER]: 'milestoneWildcardId',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'milestone_title',
- [SPECIAL_FILTER]: 'milestone_title',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[milestone_title]',
- [SPECIAL_FILTER]: 'not[milestone_title]',
- },
- },
- },
- [TOKEN_TYPE_LABEL]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'labelName',
- [SPECIAL_FILTER]: 'labelName',
- [ALTERNATIVE_FILTER]: 'labelNames',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'label_name[]',
- [SPECIAL_FILTER]: 'label_name[]',
- [ALTERNATIVE_FILTER]: 'label_name',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[label_name][]',
- },
- [OPERATOR_OR]: {
- [ALTERNATIVE_FILTER]: 'or[label_name][]',
- },
- },
- },
- [TOKEN_TYPE_TYPE]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'types',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'type[]',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[type][]',
- },
- },
- },
- [TOKEN_TYPE_RELEASE]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'releaseTag',
- [SPECIAL_FILTER]: 'releaseTagWildcardId',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'release_tag',
- [SPECIAL_FILTER]: 'release_tag',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[release_tag]',
- },
- },
- },
- [TOKEN_TYPE_MY_REACTION]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'myReactionEmoji',
- [SPECIAL_FILTER]: 'myReactionEmoji',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'my_reaction_emoji',
- [SPECIAL_FILTER]: 'my_reaction_emoji',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[my_reaction_emoji]',
- },
- },
- },
- [TOKEN_TYPE_CONFIDENTIAL]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'confidential',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'confidential',
- },
- },
- },
- [TOKEN_TYPE_ITERATION]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'iterationId',
- [SPECIAL_FILTER]: 'iterationWildcardId',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'iteration_id',
- [SPECIAL_FILTER]: 'iteration_id',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[iteration_id]',
- [SPECIAL_FILTER]: 'not[iteration_id]',
- },
- },
- },
- [TOKEN_TYPE_EPIC]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'epicId',
- [SPECIAL_FILTER]: 'epicId',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'epic_id',
- [SPECIAL_FILTER]: 'epic_id',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[epic_id]',
- },
- },
- },
- [TOKEN_TYPE_WEIGHT]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'weight',
- [SPECIAL_FILTER]: 'weight',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'weight',
- [SPECIAL_FILTER]: 'weight',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[weight]',
- },
- },
- },
- [TOKEN_TYPE_HEALTH]: {
- [API_PARAM]: {
- [NORMAL_FILTER]: 'healthStatusFilter',
- [SPECIAL_FILTER]: 'healthStatusFilter',
- },
- [URL_PARAM]: {
- [OPERATOR_IS]: {
- [NORMAL_FILTER]: 'health_status',
- [SPECIAL_FILTER]: 'health_status',
- },
- [OPERATOR_NOT]: {
- [NORMAL_FILTER]: 'not[health_status]',
- },
- },
- },
-};
-
-export const errorFetchingCounts = __('An error occurred while getting issue counts');
-export const errorFetchingIssues = __('An error occurred while loading issues');
-export const noOpenIssuesTitle = __('There are no open issues');
-export const noClosedIssuesTitle = __('There are no closed issues');
-export const noIssuesSignedOutButtonText = __('Register / Sign In');
-export const noSearchResultsDescription = __(
- 'To widen your search, change or remove filters above',
-);
-export const noSearchResultsTitle = __('Sorry, your filter produced no results');
-export const searchPlaceholder = __('Search or filter results...');
-export const infoBannerTitle = s__(
- 'ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab',
-);
-export const infoBannerAdminNote = s__('ServiceDesk|Your users can send emails to this address:');
-export const infoBannerUserNote = s__(
- 'ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation.',
-);
-export const enableServiceDesk = s__('ServiceDesk|Enable Service Desk');
-export const learnMore = __('Learn more about Service Desk');
-export const titles = __('Titles');
-export const descriptions = __('Descriptions');
-export const no = __('No');
-export const yes = __('Yes');
diff --git a/app/assets/javascripts/service_desk/index.js b/app/assets/javascripts/service_desk/index.js
deleted file mode 100644
index afb2d0e8de3..00000000000
--- a/app/assets/javascripts/service_desk/index.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import VueRouter from 'vue-router';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import ServiceDeskListApp from 'ee_else_ce/service_desk/components/service_desk_list_app.vue';
-import { gqlClient } from './graphql';
-
-export async function mountServiceDeskListApp() {
- const el = document.querySelector('.js-service-desk-list');
-
- if (!el) {
- return null;
- }
-
- const {
- projectDataReleasesPath,
- projectDataAutocompleteAwardEmojisPath,
- projectDataHasIterationsFeature,
- projectDataHasIssueWeightsFeature,
- projectDataHasIssuableHealthStatusFeature,
- projectDataGroupPath,
- projectDataEmptyStateSvgPath,
- projectDataFullPath,
- projectDataIsProject,
- projectDataIsSignedIn,
- projectDataSignInPath,
- projectDataHasAnyIssues,
- projectDataInitialSort,
- serviceDeskEmailAddress,
- canAdminIssues,
- canEditProjectSettings,
- serviceDeskCalloutSvgPath,
- serviceDeskSettingsPath,
- serviceDeskHelpPath,
- isServiceDeskSupported,
- isServiceDeskEnabled,
- } = el.dataset;
-
- Vue.use(VueApollo);
- Vue.use(VueRouter);
-
- return new Vue({
- el,
- name: 'ServiceDeskListRoot',
- apolloProvider: new VueApollo({
- defaultClient: await gqlClient(),
- }),
- router: new VueRouter({
- base: window.location.pathname,
- mode: 'history',
- routes: [{ path: '/' }],
- }),
- provide: {
- releasesPath: projectDataReleasesPath,
- autocompleteAwardEmojisPath: projectDataAutocompleteAwardEmojisPath,
- hasIterationsFeature: parseBoolean(projectDataHasIterationsFeature),
- hasIssueWeightsFeature: parseBoolean(projectDataHasIssueWeightsFeature),
- hasIssuableHealthStatusFeature: parseBoolean(projectDataHasIssuableHealthStatusFeature),
- groupPath: projectDataGroupPath,
- emptyStateSvgPath: projectDataEmptyStateSvgPath,
- fullPath: projectDataFullPath,
- isProject: parseBoolean(projectDataIsProject),
- isSignedIn: parseBoolean(projectDataIsSignedIn),
- serviceDeskEmailAddress,
- canAdminIssues: parseBoolean(canAdminIssues),
- canEditProjectSettings: parseBoolean(canEditProjectSettings),
- serviceDeskCalloutSvgPath,
- serviceDeskSettingsPath,
- serviceDeskHelpPath,
- isServiceDeskSupported: parseBoolean(isServiceDeskSupported),
- isServiceDeskEnabled: parseBoolean(isServiceDeskEnabled),
- signInPath: projectDataSignInPath,
- hasAnyIssues: parseBoolean(projectDataHasAnyIssues),
- initialSort: projectDataInitialSort,
- },
- render: (createComponent) => createComponent(ServiceDeskListApp),
- });
-}
diff --git a/app/assets/javascripts/service_desk/queries/get_service_desk_issues.query.graphql b/app/assets/javascripts/service_desk/queries/get_service_desk_issues.query.graphql
deleted file mode 100644
index c678b8dd8ab..00000000000
--- a/app/assets/javascripts/service_desk/queries/get_service_desk_issues.query.graphql
+++ /dev/null
@@ -1,72 +0,0 @@
-#import "~/graphql_shared/fragments/page_info.fragment.graphql"
-#import "./issue.fragment.graphql"
-
-query getServiceDeskIssues(
- $hideUsers: Boolean = false
- $isProject: Boolean = false
- $isSignedIn: Boolean = false
- $fullPath: ID!
- $iid: String
- $search: String
- $sort: IssueSort
- $state: IssuableState
- $in: [IssuableSearchableField!]
- $assigneeId: String
- $assigneeUsernames: [String!]
- $authorUsername: String
- $confidential: Boolean
- $labelName: [String]
- $milestoneTitle: [String]
- $milestoneWildcardId: MilestoneWildcardId
- $myReactionEmoji: String
- $releaseTag: [String!]
- $releaseTagWildcardId: ReleaseTagWildcardId
- $types: [IssueType!]
- $crmContactId: String
- $crmOrganizationId: String
- $not: NegatedIssueFilterInput
- $or: UnionedIssueFilterInput
- $beforeCursor: String
- $afterCursor: String
- $firstPageSize: Int
- $lastPageSize: Int
-) {
- project(fullPath: $fullPath) @include(if: $isProject) @persist {
- id
- issues(
- iid: $iid
- search: $search
- sort: $sort
- state: $state
- in: $in
- assigneeId: $assigneeId
- assigneeUsernames: $assigneeUsernames
- authorUsername: $authorUsername
- confidential: $confidential
- labelName: $labelName
- milestoneTitle: $milestoneTitle
- milestoneWildcardId: $milestoneWildcardId
- myReactionEmoji: $myReactionEmoji
- releaseTag: $releaseTag
- releaseTagWildcardId: $releaseTagWildcardId
- types: $types
- crmContactId: $crmContactId
- crmOrganizationId: $crmOrganizationId
- not: $not
- or: $or
- before: $beforeCursor
- after: $afterCursor
- first: $firstPageSize
- last: $lastPageSize
- ) {
- __persist
- pageInfo {
- ...PageInfo
- }
- nodes {
- __persist
- ...IssueFragment
- }
- }
- }
-}
diff --git a/app/assets/javascripts/service_desk/queries/get_service_desk_issues_counts.query.graphql b/app/assets/javascripts/service_desk/queries/get_service_desk_issues_counts.query.graphql
deleted file mode 100644
index c2ba397d76f..00000000000
--- a/app/assets/javascripts/service_desk/queries/get_service_desk_issues_counts.query.graphql
+++ /dev/null
@@ -1,91 +0,0 @@
-query getServiceDeskIssuesCount(
- $isProject: Boolean = false
- $fullPath: ID!
- $iid: String
- $search: String
- $assigneeId: String
- $assigneeUsernames: [String!]
- $authorUsername: String
- $confidential: Boolean
- $labelName: [String]
- $milestoneTitle: [String]
- $milestoneWildcardId: MilestoneWildcardId
- $myReactionEmoji: String
- $releaseTag: [String!]
- $releaseTagWildcardId: ReleaseTagWildcardId
- $types: [IssueType!]
- $crmContactId: String
- $crmOrganizationId: String
- $not: NegatedIssueFilterInput
- $or: UnionedIssueFilterInput
-) {
- project(fullPath: $fullPath) @include(if: $isProject) {
- id
- openedIssues: issues(
- state: opened
- iid: $iid
- search: $search
- assigneeId: $assigneeId
- assigneeUsernames: $assigneeUsernames
- authorUsername: $authorUsername
- confidential: $confidential
- labelName: $labelName
- milestoneTitle: $milestoneTitle
- milestoneWildcardId: $milestoneWildcardId
- myReactionEmoji: $myReactionEmoji
- releaseTag: $releaseTag
- releaseTagWildcardId: $releaseTagWildcardId
- types: $types
- crmContactId: $crmContactId
- crmOrganizationId: $crmOrganizationId
- not: $not
- or: $or
- ) {
- count
- }
- closedIssues: issues(
- state: closed
- iid: $iid
- search: $search
- assigneeId: $assigneeId
- assigneeUsernames: $assigneeUsernames
- authorUsername: $authorUsername
- confidential: $confidential
- labelName: $labelName
- milestoneTitle: $milestoneTitle
- milestoneWildcardId: $milestoneWildcardId
- myReactionEmoji: $myReactionEmoji
- releaseTag: $releaseTag
- releaseTagWildcardId: $releaseTagWildcardId
- types: $types
- crmContactId: $crmContactId
- crmOrganizationId: $crmOrganizationId
- not: $not
- or: $or
- ) {
- count
- }
- allIssues: issues(
- state: all
- iid: $iid
- search: $search
- assigneeId: $assigneeId
- assigneeUsernames: $assigneeUsernames
- authorUsername: $authorUsername
- confidential: $confidential
- labelName: $labelName
- milestoneTitle: $milestoneTitle
- milestoneWildcardId: $milestoneWildcardId
- myReactionEmoji: $myReactionEmoji
- releaseTag: $releaseTag
- releaseTagWildcardId: $releaseTagWildcardId
- types: $types
- crmContactId: $crmContactId
- crmOrganizationId: $crmOrganizationId
- not: $not
- or: $or
- ) {
- count
- }
- }
-}
diff --git a/app/assets/javascripts/service_desk/queries/issue.fragment.graphql b/app/assets/javascripts/service_desk/queries/issue.fragment.graphql
deleted file mode 100644
index 3b49c0efb14..00000000000
--- a/app/assets/javascripts/service_desk/queries/issue.fragment.graphql
+++ /dev/null
@@ -1,60 +0,0 @@
-fragment IssueFragment on Issue {
- id
- iid
- confidential
- createdAt
- downvotes
- dueDate
- hidden
- humanTimeEstimate
- mergeRequestsCount
- moved
- state
- title
- updatedAt
- closedAt
- upvotes
- userDiscussionsCount @include(if: $isSignedIn)
- webPath
- webUrl
- type
- assignees @skip(if: $hideUsers) {
- nodes {
- __persist
- id
- avatarUrl
- name
- username
- webUrl
- }
- }
- author @skip(if: $hideUsers) {
- __persist
- id
- avatarUrl
- name
- username
- webUrl
- }
- labels {
- nodes {
- __persist
- id
- color
- title
- description
- }
- }
- milestone {
- __persist
- id
- dueDate
- startDate
- webPath
- title
- }
- taskCompletionStatus {
- completedCount
- count
- }
-}
diff --git a/app/assets/javascripts/settings_panels.js b/app/assets/javascripts/settings_panels.js
index fe5b21713a2..da948cc85b6 100644
--- a/app/assets/javascripts/settings_panels.js
+++ b/app/assets/javascripts/settings_panels.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { InternalEvents } from '~/tracking';
import { __ } from './locale';
/**
@@ -47,6 +48,15 @@ export function toggleSection($section) {
}
}
+export function initTrackProductAnalyticsExpanded() {
+ const $analyticsSection = $('#js-product-analytics-settings');
+ $analyticsSection.on('click.toggleSection', '.js-settings-toggle', () => {
+ if (isExpanded($analyticsSection)) {
+ InternalEvents.track_event('user_viewed_cluster_configuration');
+ }
+ });
+}
+
export default function initSettingsPanels() {
$('.settings').each((i, elm) => {
const $section = $(elm);
@@ -64,4 +74,6 @@ export default function initSettingsPanels() {
}
}
});
+
+ initTrackProductAnalyticsExpanded();
}
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue b/app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue
index 319699b88f3..cf77a5ca82c 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees_realtime.vue
@@ -1,6 +1,6 @@
<script>
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { assigneesQueries } from '../../constants';
+import { assigneesQueries } from '../../queries/constants';
export default {
subscription: null,
diff --git a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue
index 577c01c50ff..8a912b00df1 100644
--- a/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/collapsed_assignee_list.vue
@@ -84,7 +84,8 @@ export default {
if (mergeLength === this.users.length) {
return '';
- } else if (mergeLength > 0) {
+ }
+ if (mergeLength > 0) {
return sprintf(__('%{mergeLength}/%{usersLength} can merge'), {
mergeLength,
usersLength: this.users.length,
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue
index ae81dcb95de..4ff12824008 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue
@@ -6,7 +6,7 @@ import { TYPE_ALERT, TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { __, n__ } from '~/locale';
import UserSelect from '~/vue_shared/components/user_select/user_select.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { assigneesQueries } from '../../constants';
+import { assigneesQueries } from '../../queries/constants';
import SidebarEditableItem from '../sidebar_editable_item.vue';
import SidebarAssigneesRealtime from './assignees_realtime.vue';
import IssuableAssignees from './issuable_assignees.vue';
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_invite_members.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_invite_members.vue
index b41d126be68..232cdcd2198 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_invite_members.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_invite_members.vue
@@ -15,7 +15,7 @@ export default {
},
computed: {
triggerSource() {
- return `${this.issuableType}-assignee-dropdown`;
+ return `${this.issuableType}_assignee_dropdown`;
},
},
};
diff --git a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
index 930e7ff12d9..ef7f12f273f 100644
--- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
@@ -1,4 +1,5 @@
<script>
+import { GlButton } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { __, sprintf } from '~/locale';
@@ -9,6 +10,7 @@ const DEFAULT_RENDER_COUNT = 5;
export default {
components: {
+ GlButton,
AssigneeAvatarLink,
UserNameWithStatus,
},
@@ -97,10 +99,11 @@ export default {
</assignee-avatar-link>
</div>
</div>
- <div v-if="renderShowMoreSection" class="user-list-more gl-hover-text-blue-800">
- <button
- type="button"
- class="btn-link gl-button gl-reset-color!"
+ <div v-if="renderShowMoreSection" class="gl-hover-text-blue-800" data-testid="user-list-more">
+ <gl-button
+ category="tertiary"
+ size="small"
+ data-testid="user-list-more-button"
data-qa-selector="more_assignees_link"
@click="toggleShowLess"
>
@@ -108,7 +111,7 @@ export default {
{{ hiddenAssigneesLabel }}
</template>
<template v-else>{{ __('- show less') }}</template>
- </button>
+ </gl-button>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue
index 3038cec03eb..7a1853b1b46 100644
--- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue
@@ -1,9 +1,9 @@
<script>
import { GlSprintf, GlButton } from '@gitlab/ui';
import { createAlert } from '~/alert';
-import { TYPE_ISSUE } from '~/issues/constants';
+import { TYPE_ISSUE, TYPE_TEST_CASE, IssuableTypeText } from '~/issues/constants';
import { __, sprintf } from '~/locale';
-import { confidentialityQueries } from '../../constants';
+import { confidentialityQueries } from '../../queries/constants';
export default {
i18n: {
@@ -11,7 +11,7 @@ export default {
'You are going to turn on confidentiality. Only %{context} members with %{strongStart}%{permissions}%{strongEnd} can view or be notified about this %{issuableType}.',
),
confidentialityOffWarning: __(
- 'You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}.',
+ 'You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see%{commentText} this %{issuableType}.',
),
},
components: {
@@ -56,11 +56,17 @@ export default {
isIssue() {
return this.issuableType === TYPE_ISSUE;
},
+ isTestCase() {
+ return this.issuableType === TYPE_TEST_CASE;
+ },
+ isIssueOrTestCase() {
+ return this.isIssue || this.isTestCase;
+ },
context() {
- return this.isIssue ? __('project') : __('group');
+ return this.isIssueOrTestCase ? __('project') : __('group');
},
workspacePath() {
- return this.isIssue
+ return this.isIssueOrTestCase
? {
projectPath: this.fullPath,
}
@@ -73,6 +79,12 @@ export default {
? __('at least the Reporter role, the author, and assignees')
: __('at least the Reporter role');
},
+ issuableTypeText() {
+ return IssuableTypeText[this.issuableType];
+ },
+ commentText() {
+ return this.isTestCase ? '' : __(' and leave a comment on');
+ },
},
methods: {
submitForm() {
@@ -108,7 +120,7 @@ export default {
message: sprintf(
__('Something went wrong while setting %{issuableType} confidentiality.'),
{
- issuableType: this.issuableType,
+ issuableType: this.issuableTypeText,
},
),
});
@@ -135,7 +147,8 @@ export default {
</strong>
</template>
<template #context>{{ context }}</template>
- <template #issuableType>{{ issuableType }}</template>
+ <template #commentText>{{ commentText }}</template>
+ <template #issuableType>{{ issuableTypeText }}</template>
</gl-sprintf>
</p>
<div class="sidebar-item-warning-message-actions">
diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue
index 9177baec246..295d37671cc 100644
--- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue
@@ -3,7 +3,8 @@ import produce from 'immer';
import Vue from 'vue';
import { createAlert } from '~/alert';
import { __, sprintf } from '~/locale';
-import { confidentialityQueries, Tracking } from '../../constants';
+import { Tracking } from '../../constants';
+import { confidentialityQueries } from '../../queries/constants';
import SidebarEditableItem from '../sidebar_editable_item.vue';
import SidebarConfidentialityContent from './sidebar_confidentiality_content.vue';
import SidebarConfidentialityForm from './sidebar_confidentiality_form.vue';
diff --git a/app/assets/javascripts/sidebar/components/copy/sidebar_reference_widget.vue b/app/assets/javascripts/sidebar/components/copy/sidebar_reference_widget.vue
index 3287539e502..7a488bb379f 100644
--- a/app/assets/javascripts/sidebar/components/copy/sidebar_reference_widget.vue
+++ b/app/assets/javascripts/sidebar/components/copy/sidebar_reference_widget.vue
@@ -1,6 +1,6 @@
<script>
import { __ } from '~/locale';
-import { referenceQueries } from '../../constants';
+import { referenceQueries } from '../../queries/constants';
import CopyableField from './copyable_field.vue';
export default {
diff --git a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
index 5a9545f3460..89bc4b126d6 100644
--- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
+++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
@@ -4,7 +4,8 @@ import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
import { dateInWords, formatDate, parsePikadayDate } from '~/lib/utils/datetime_utility';
import { __, sprintf } from '~/locale';
-import { dateFields, dateTypes, dueDateQueries, startDateQueries, Tracking } from '../../constants';
+import { dateFields, dateTypes, Tracking } from '../../constants';
+import { dueDateQueries, startDateQueries } from '../../queries/constants';
import SidebarEditableItem from '../sidebar_editable_item.vue';
import SidebarFormattedDate from './sidebar_formatted_date.vue';
import SidebarInheritDate from './sidebar_inherit_date.vue';
diff --git a/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue b/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue
index 6db332a82da..576043963de 100644
--- a/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue
+++ b/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue
@@ -3,11 +3,8 @@ import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { createAlert } from '~/alert';
import { logError } from '~/lib/logger';
import EscalationStatus from 'ee_else_ce/sidebar/components/incidents/escalation_status.vue';
-import {
- escalationStatusQuery,
- escalationStatusMutation,
- INCIDENTS_I18N as i18n,
-} from '../../constants';
+import { INCIDENTS_I18N as i18n } from '../../constants';
+import { escalationStatusQuery, escalationStatusMutation } from '../../queries/constants';
import { getStatusLabel } from '../../utils';
import SidebarEditableItem from '../sidebar_editable_item.vue';
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/getters.js b/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/getters.js
index 03ace6286e0..3ab7757d34d 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/getters.js
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/getters.js
@@ -19,7 +19,8 @@ export const dropdownButtonText = (state, getters) => {
if (!selectedLabels.length) {
return state.dropdownButtonText || __('Label');
- } else if (selectedLabels.length > 1) {
+ }
+ if (selectedLabels.length > 1) {
return sprintf(s__('LabelSelect|%{firstLabelName} +%{remainingLabelCount} more'), {
firstLabelName: selectedLabels[0].title,
remainingLabelCount: selectedLabels.length - 1,
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue
index 53582aacabd..a513c247be7 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue
@@ -101,7 +101,8 @@ export default {
buttonText() {
if (!this.localSelectedLabels.length) {
return this.dropdownButtonText || __('Label');
- } else if (this.localSelectedLabels.length > 1) {
+ }
+ if (this.localSelectedLabels.length > 1) {
return sprintf(s__('LabelSelect|%{firstLabelName} +%{remainingLabelCount} more'), {
firstLabelName: this.localSelectedLabels[0].title,
remainingLabelCount: this.localSelectedLabels.length - 1,
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue
index 45778640957..93e3cfba309 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue
@@ -1,4 +1,5 @@
<script>
+import { get } from 'lodash';
import {
GlAlert,
GlTooltipDirective,
@@ -11,8 +12,7 @@ import produce from 'immer';
import { createAlert } from '~/alert';
import { WORKSPACE_GROUP } from '~/issues/constants';
import { __ } from '~/locale';
-import { workspaceLabelsQueries } from '../../../constants';
-import createLabelMutation from './graphql/create_label.mutation.graphql';
+import { workspaceLabelsQueries, workspaceCreateLabelMutation } from '../../../queries/constants';
import { DEFAULT_LABEL_COLOR } from './constants';
const errorMessage = __('Error creating label.');
@@ -68,13 +68,19 @@ export default {
return Object.keys(colorsMap).map((color) => ({ [color]: colorsMap[color] }));
},
mutationVariables() {
- const attributePath = this.labelCreateType === WORKSPACE_GROUP ? 'groupPath' : 'projectPath';
-
- return {
+ const variables = {
title: this.labelTitle,
color: this.selectedColor,
- [attributePath]: this.attrWorkspacePath,
};
+
+ if (this.labelCreateType) {
+ const attributePath =
+ this.labelCreateType === WORKSPACE_GROUP ? 'groupPath' : 'projectPath';
+
+ return { ...variables, [attributePath]: this.attrWorkspacePath };
+ }
+
+ return variables;
},
},
methods: {
@@ -88,7 +94,7 @@ export default {
this.selectedColor = this.getColorCode(color);
},
updateLabelsInCache(store, label) {
- const { query } = workspaceLabelsQueries[this.workspaceType];
+ const { query, dataPath } = workspaceLabelsQueries[this.workspaceType];
const sourceData = store.readQuery({
query,
@@ -97,7 +103,7 @@ export default {
const collator = new Intl.Collator('en');
const data = produce(sourceData, (draftData) => {
- const { nodes } = draftData.workspace.labels;
+ const { nodes } = get(draftData, dataPath);
nodes.push(label);
nodes.sort((a, b) => collator.compare(a.title, b.title));
});
@@ -114,7 +120,7 @@ export default {
const {
data: { labelCreate },
} = await this.$apollo.mutate({
- mutation: createLabelMutation,
+ mutation: workspaceCreateLabelMutation[this.workspaceType],
variables: this.mutationVariables,
update: (
store,
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue
index 19fe78aca87..fc8834a97d4 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue
@@ -4,7 +4,7 @@ import fuzzaldrinPlus from 'fuzzaldrin-plus';
import { createAlert } from '~/alert';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
-import { workspaceLabelsQueries } from '../../../constants';
+import { workspaceLabelsQueries } from '../../../queries/constants';
import LabelItem from './label_item.vue';
export default {
@@ -135,6 +135,16 @@ export default {
this.handleLabelClick(this.visibleLabels[0]);
}
},
+ handleFocus(event, index) {
+ if (index === 0 && event.target.classList.contains('is-focused')) {
+ event.target.classList.remove('is-focused');
+
+ // Focus next element (if available) as the first item was already focused.
+ if (event.target.parentNode?.nextElementSibling?.querySelector('button')) {
+ event.target.parentNode.nextElementSibling.querySelector('button').focus();
+ }
+ }
+ },
},
};
</script>
@@ -157,6 +167,7 @@ export default {
:active="shouldHighlightFirstItem && index === 0"
active-class="is-focused"
data-testid="labels-list"
+ @focus.native.capture="handleFocus($event, index)"
@click.native.capture.stop="handleLabelClick(label)"
>
<label-item :label="label" />
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_footer.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_footer.vue
index e67e704ffb8..d6b43698766 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_footer.vue
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_footer.vue
@@ -13,7 +13,13 @@ export default {
},
footerManageLabelTitle: {
type: String,
- required: true,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ showManageLabelsItem() {
+ return this.footerManageLabelTitle && this.labelsManagePath;
},
},
};
@@ -28,7 +34,12 @@ export default {
>
{{ footerCreateLabelTitle }}
</gl-dropdown-item>
- <gl-dropdown-item :href="labelsManagePath" @click.capture.native.stop>
+ <gl-dropdown-item
+ v-if="showManageLabelsItem"
+ data-testid="manage-labels-button"
+ :href="labelsManagePath"
+ @click.capture.native.stop
+ >
{{ footerManageLabelTitle }}
</gl-dropdown-item>
</div>
diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue
index 74c3f08a47b..f9a9cc316c1 100644
--- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue
+++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue
@@ -7,7 +7,7 @@ import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST, TYPE_TEST_CASE } from '~/issues/constants';
import { __ } from '~/locale';
-import { issuableLabelsQueries } from '../../../constants';
+import { issuableLabelsQueries } from '../../../queries/constants';
import SidebarEditableItem from '../../sidebar_editable_item.vue';
import { DEBOUNCE_DROPDOWN_DELAY, VARIANT_SIDEBAR } from './constants';
import DropdownContents from './dropdown_contents.vue';
diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue
index 7b288e15a3e..99d36a61632 100644
--- a/app/assets/javascripts/sidebar/components/participants/participants.vue
+++ b/app/assets/javascripts/sidebar/components/participants/participants.vue
@@ -138,13 +138,10 @@ export default {
</a>
</div>
</div>
- <div v-if="hasMoreParticipants" class="participants-more hide-collapsed">
- <gl-button
- variant="link"
- button-text-classes="gl-text-secondary"
- @click="toggleMoreParticipants"
- >{{ toggleLabel }}</gl-button
- >
+ <div v-if="hasMoreParticipants" class="hide-collapsed">
+ <gl-button category="tertiary" size="small" @click="toggleMoreParticipants">{{
+ toggleLabel
+ }}</gl-button>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/participants/sidebar_participants_widget.vue b/app/assets/javascripts/sidebar/components/participants/sidebar_participants_widget.vue
index b0556e22a8d..b764d660d63 100644
--- a/app/assets/javascripts/sidebar/components/participants/sidebar_participants_widget.vue
+++ b/app/assets/javascripts/sidebar/components/participants/sidebar_participants_widget.vue
@@ -1,6 +1,6 @@
<script>
import { __ } from '~/locale';
-import { participantsQueries } from '../../constants';
+import { participantsQueries } from '../../queries/constants';
import Participants from './participants.vue';
export default {
diff --git a/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue b/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue
index 88a74784dd2..415c40b4779 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue
@@ -52,7 +52,8 @@ export default {
if (mergeLength === this.users.length) {
return '';
- } else if (mergeLength > 0) {
+ }
+ if (mergeLength > 0) {
return sprintf(__('%{mergeLength}/%{usersLength} can merge'), {
mergeLength,
usersLength: this.users.length,
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
index 50b4284cde0..c9450244b40 100644
--- a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
@@ -20,13 +20,13 @@ import {
defaultEpicSort,
dropdowni18nText,
epicIidPattern,
- issuableAttributesQueries,
IssuableAttributeState,
IssuableAttributeType,
IssuableAttributeTypeKeyMap,
LocalizedIssuableAttributeType,
noAttributeId,
} from 'ee_else_ce/sidebar/constants';
+import { issuableAttributesQueries } from 'ee_else_ce/sidebar/queries/constants';
import { createAlert } from '~/alert';
import { PathIdSeparator } from '~/related_issues/constants';
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
index 4721c6fee61..7fde43a360d 100644
--- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
@@ -11,10 +11,10 @@ import {
dropdowni18nText,
LocalizedIssuableAttributeType,
IssuableAttributeTypeKeyMap,
- issuableAttributesQueries,
IssuableAttributeType,
Tracking,
} from 'ee_else_ce/sidebar/constants';
+import { issuableAttributesQueries } from 'ee_else_ce/sidebar/queries/constants';
import SidebarDropdown from './sidebar_dropdown.vue';
import SidebarEditableItem from './sidebar_editable_item.vue';
diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue
index d6e1847aecb..568962cddc7 100644
--- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue
+++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue
@@ -13,7 +13,8 @@ import { isLoggedIn } from '~/lib/utils/common_utils';
import { __, sprintf } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import toast from '~/vue_shared/plugins/global_toast';
-import { subscribedQueries, Tracking } from '../../constants';
+import { Tracking } from '../../constants';
+import { subscribedQueries } from '../../queries/constants';
import SidebarEditableItem from '../sidebar_editable_item.vue';
const ICON_ON = 'notifications';
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
index 465f971717f..ac05ae3896b 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
@@ -42,11 +42,14 @@ export default {
divClass() {
if (this.showComparisonState) {
return 'compare';
- } else if (this.showEstimateOnlyState) {
+ }
+ if (this.showEstimateOnlyState) {
return 'estimate-only';
- } else if (this.showSpentOnlyState) {
+ }
+ if (this.showSpentOnlyState) {
return 'spend-only';
- } else if (this.showNoTimeTrackingState) {
+ }
+ if (this.showNoTimeTrackingState) {
return 'no-tracking';
}
@@ -55,9 +58,11 @@ export default {
spanClass() {
if (this.showComparisonState) {
return '';
- } else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
+ }
+ if (this.showEstimateOnlyState || this.showSpentOnlyState) {
return 'bold';
- } else if (this.showNoTimeTrackingState) {
+ }
+ if (this.showNoTimeTrackingState) {
return 'no-value collapse-truncated-title gl-pt-2 gl-px-3 gl-font-sm';
}
@@ -66,11 +71,14 @@ export default {
text() {
if (this.showComparisonState) {
return `${this.timeSpentHumanReadable} / ${this.timeEstimateHumanReadable}`;
- } else if (this.showEstimateOnlyState) {
+ }
+ if (this.showEstimateOnlyState) {
return `-- / ${this.timeEstimateHumanReadable}`;
- } else if (this.showSpentOnlyState) {
+ }
+ if (this.showSpentOnlyState) {
return `${this.timeSpentHumanReadable} / --`;
- } else if (this.showNoTimeTrackingState) {
+ }
+ if (this.showNoTimeTrackingState) {
return __('None');
}
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/report.vue b/app/assets/javascripts/sidebar/components/time_tracking/report.vue
index 70d8024f46a..9bd4c7f5c68 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/report.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/report.vue
@@ -7,7 +7,7 @@ import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPE_ISSUE } from '~/issues/constants';
import { formatDate, parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
import { __, s__ } from '~/locale';
-import { timelogQueries } from '../../constants';
+import { timelogQueries } from '../../queries/constants';
import deleteTimelogMutation from '../../queries/delete_timelog.mutation.graphql';
const TIME_DATE_FORMAT = 'mmmm d, yyyy, HH:MM ("UTC:" o)';
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
index 1d427a871e1..aff592d48e0 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
@@ -12,7 +12,8 @@ import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import { s__, __ } from '~/locale';
-import { HOW_TO_TRACK_TIME, timeTrackingQueries } from '../../constants';
+import { HOW_TO_TRACK_TIME } from '../../constants';
+import { timeTrackingQueries } from '../../queries/constants';
import eventHub from '../../event_hub';
import TimeTrackingCollapsedState from './collapsed_state.vue';
import TimeTrackingComparisonPane from './comparison_pane.vue';
@@ -122,9 +123,11 @@ export default {
// 3. issuableIid and fullPath are not provided
if (!this.issuableType || !timeTrackingQueries[this.issuableType]) {
return true;
- } else if (this.initialTimeTracking) {
+ }
+ if (this.initialTimeTracking) {
return true;
- } else if (!this.issuableIid || !this.fullPath) {
+ }
+ if (!this.issuableIid || !this.fullPath) {
return true;
}
return false;
diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue b/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue
index 551d306a9c4..1099dcb832f 100644
--- a/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue
+++ b/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue
@@ -6,7 +6,8 @@ import { TYPE_MERGE_REQUEST } from '~/issues/constants';
import { __, sprintf } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import Tracking from '~/tracking';
-import { todoQueries, TodoMutationTypes, todoMutations } from '../../constants';
+import { TodoMutationTypes } from '../../constants';
+import { todoQueries, todoMutations } from '../../queries/constants';
import { todoLabel } from '../../utils';
import TodoButton from './todo_button.vue';
diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js
index 0f82182c6e2..f13f613733b 100644
--- a/app/assets/javascripts/sidebar/constants.js
+++ b/app/assets/javascripts/sidebar/constants.js
@@ -1,173 +1,10 @@
import { invert } from 'lodash';
import { s__, __, sprintf } from '~/locale';
-import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql';
-import userSearchQuery from '~/graphql_shared/queries/users_search.query.graphql';
-import userSearchWithMRPermissionsQuery from '~/graphql_shared/queries/users_search_with_mr_permissions.graphql';
-import {
- TYPE_ALERT,
- TYPE_EPIC,
- TYPE_ISSUE,
- TYPE_MERGE_REQUEST,
- TYPE_TEST_CASE,
- WORKSPACE_GROUP,
- WORKSPACE_PROJECT,
-} from '~/issues/constants';
-import updateAlertAssigneesMutation from '~/vue_shared/alert_details/graphql/mutations/alert_set_assignees.mutation.graphql';
-import issuableDatesUpdatedSubscription from '../graphql_shared/subscriptions/work_item_dates.subscription.graphql';
-import updateTestCaseLabelsMutation from './components/labels/labels_select_widget/graphql/update_test_case_labels.mutation.graphql';
-import epicLabelsQuery from './components/labels/labels_select_widget/graphql/epic_labels.query.graphql';
-import updateEpicLabelsMutation from './components/labels/labels_select_widget/graphql/epic_update_labels.mutation.graphql';
-import groupLabelsQuery from './components/labels/labels_select_widget/graphql/group_labels.query.graphql';
-import issueLabelsQuery from './components/labels/labels_select_widget/graphql/issue_labels.query.graphql';
-import mergeRequestLabelsQuery from './components/labels/labels_select_widget/graphql/merge_request_labels.query.graphql';
-import projectLabelsQuery from './components/labels/labels_select_widget/graphql/project_labels.query.graphql';
-import epicConfidentialQuery from './queries/epic_confidential.query.graphql';
-import epicDueDateQuery from './queries/epic_due_date.query.graphql';
-import epicParticipantsQuery from './queries/epic_participants.query.graphql';
-import epicReferenceQuery from './queries/epic_reference.query.graphql';
-import epicStartDateQuery from './queries/epic_start_date.query.graphql';
-import epicSubscribedQuery from './queries/epic_subscribed.query.graphql';
-import epicTodoQuery from './queries/epic_todo.query.graphql';
-import issuableAssigneesSubscription from './queries/issuable_assignees.subscription.graphql';
-import issueConfidentialQuery from './queries/issue_confidential.query.graphql';
-import issueDueDateQuery from './queries/issue_due_date.query.graphql';
-import issueReferenceQuery from './queries/issue_reference.query.graphql';
-import issueSubscribedQuery from './queries/issue_subscribed.query.graphql';
-import issueTimeTrackingQuery from './queries/issue_time_tracking.query.graphql';
-import issueTodoQuery from './queries/issue_todo.query.graphql';
-import mergeRequestMilestone from './queries/merge_request_milestone.query.graphql';
-import mergeRequestReferenceQuery from './queries/merge_request_reference.query.graphql';
-import mergeRequestSubscribed from './queries/merge_request_subscribed.query.graphql';
-import mergeRequestTimeTrackingQuery from './queries/merge_request_time_tracking.query.graphql';
-import mergeRequestTodoQuery from './queries/merge_request_todo.query.graphql';
-import todoCreateMutation from './queries/todo_create.mutation.graphql';
-import todoMarkDoneMutation from './queries/todo_mark_done.mutation.graphql';
-import updateEpicConfidentialMutation from './queries/update_epic_confidential.mutation.graphql';
-import updateEpicDueDateMutation from './queries/update_epic_due_date.mutation.graphql';
-import updateEpicStartDateMutation from './queries/update_epic_start_date.mutation.graphql';
-import updateEpicSubscriptionMutation from './queries/update_epic_subscription.mutation.graphql';
-import updateIssueConfidentialMutation from './queries/update_issue_confidential.mutation.graphql';
-import updateIssueDueDateMutation from './queries/update_issue_due_date.mutation.graphql';
-import updateIssueSubscriptionMutation from './queries/update_issue_subscription.mutation.graphql';
-import mergeRequestMilestoneMutation from './queries/update_merge_request_milestone.mutation.graphql';
-import updateMergeRequestLabelsMutation from './queries/update_merge_request_labels.mutation.graphql';
-import updateMergeRequestSubscriptionMutation from './queries/update_merge_request_subscription.mutation.graphql';
-import getAlertAssignees from './queries/get_alert_assignees.query.graphql';
-import getIssueAssignees from './queries/get_issue_assignees.query.graphql';
-import issueParticipantsQuery from './queries/get_issue_participants.query.graphql';
-import getIssueTimelogsQuery from './queries/get_issue_timelogs.query.graphql';
-import getMergeRequestAssignees from './queries/get_mr_assignees.query.graphql';
-import getMergeRequestParticipants from './queries/get_mr_participants.query.graphql';
-import getMrTimelogsQuery from './queries/get_mr_timelogs.query.graphql';
-import updateIssueAssigneesMutation from './queries/update_issue_assignees.mutation.graphql';
-import updateMergeRequestAssigneesMutation from './queries/update_mr_assignees.mutation.graphql';
-import getEscalationStatusQuery from './queries/escalation_status.query.graphql';
-import updateEscalationStatusMutation from './queries/update_escalation_status.mutation.graphql';
-import groupMilestonesQuery from './queries/group_milestones.query.graphql';
-import projectIssueMilestoneMutation from './queries/project_issue_milestone.mutation.graphql';
-import projectIssueMilestoneQuery from './queries/project_issue_milestone.query.graphql';
-import projectMilestonesQuery from './queries/project_milestones.query.graphql';
export const defaultEpicSort = 'TITLE_ASC';
export const epicIidPattern = /^&(?<iid>\d+)$/;
-export const assigneesQueries = {
- [TYPE_ISSUE]: {
- query: getIssueAssignees,
- subscription: issuableAssigneesSubscription,
- mutation: updateIssueAssigneesMutation,
- },
- [TYPE_MERGE_REQUEST]: {
- query: getMergeRequestAssignees,
- mutation: updateMergeRequestAssigneesMutation,
- },
- [TYPE_ALERT]: {
- query: getAlertAssignees,
- mutation: updateAlertAssigneesMutation,
- },
-};
-
-export const participantsQueries = {
- [TYPE_ISSUE]: {
- query: issueParticipantsQuery,
- },
- [TYPE_MERGE_REQUEST]: {
- query: getMergeRequestParticipants,
- },
- [TYPE_EPIC]: {
- query: epicParticipantsQuery,
- },
- [TYPE_ALERT]: {
- query: '',
- skipQuery: true,
- },
-};
-
-export const userSearchQueries = {
- [TYPE_ISSUE]: {
- query: userSearchQuery,
- },
- [TYPE_MERGE_REQUEST]: {
- query: userSearchWithMRPermissionsQuery,
- },
-};
-
-export const confidentialityQueries = {
- [TYPE_ISSUE]: {
- query: issueConfidentialQuery,
- mutation: updateIssueConfidentialMutation,
- },
- [TYPE_EPIC]: {
- query: epicConfidentialQuery,
- mutation: updateEpicConfidentialMutation,
- },
-};
-
-export const referenceQueries = {
- [TYPE_ISSUE]: {
- query: issueReferenceQuery,
- },
- [TYPE_MERGE_REQUEST]: {
- query: mergeRequestReferenceQuery,
- },
- [TYPE_EPIC]: {
- query: epicReferenceQuery,
- },
-};
-
-export const workspaceLabelsQueries = {
- [WORKSPACE_PROJECT]: {
- query: projectLabelsQuery,
- },
- [WORKSPACE_GROUP]: {
- query: groupLabelsQuery,
- },
-};
-
-export const issuableLabelsQueries = {
- [TYPE_ISSUE]: {
- issuableQuery: issueLabelsQuery,
- mutation: updateIssueLabelsMutation,
- mutationName: 'updateIssue',
- },
- [TYPE_MERGE_REQUEST]: {
- issuableQuery: mergeRequestLabelsQuery,
- mutation: updateMergeRequestLabelsMutation,
- mutationName: 'mergeRequestSetLabels',
- },
- [TYPE_EPIC]: {
- issuableQuery: epicLabelsQuery,
- mutation: updateEpicLabelsMutation,
- mutationName: 'updateEpic',
- },
- [TYPE_TEST_CASE]: {
- issuableQuery: issueLabelsQuery,
- mutation: updateTestCaseLabelsMutation,
- mutationName: 'updateTestCaseLabels',
- },
-};
-
export const dateTypes = {
start: 'startDate',
due: 'dueDate',
@@ -186,91 +23,13 @@ export const dateFields = {
},
};
-export const subscribedQueries = {
- [TYPE_ISSUE]: {
- query: issueSubscribedQuery,
- mutation: updateIssueSubscriptionMutation,
- },
- [TYPE_EPIC]: {
- query: epicSubscribedQuery,
- mutation: updateEpicSubscriptionMutation,
- },
- [TYPE_MERGE_REQUEST]: {
- query: mergeRequestSubscribed,
- mutation: updateMergeRequestSubscriptionMutation,
- },
-};
-
export const Tracking = {
editEvent: 'click_edit_button',
rightSidebarLabel: 'right_sidebar',
};
-export const timeTrackingQueries = {
- [TYPE_ISSUE]: {
- query: issueTimeTrackingQuery,
- },
- [TYPE_MERGE_REQUEST]: {
- query: mergeRequestTimeTrackingQuery,
- },
-};
-
-export const dueDateQueries = {
- [TYPE_ISSUE]: {
- query: issueDueDateQuery,
- mutation: updateIssueDueDateMutation,
- subscription: issuableDatesUpdatedSubscription,
- },
- [TYPE_EPIC]: {
- query: epicDueDateQuery,
- mutation: updateEpicDueDateMutation,
- },
-};
-
-export const startDateQueries = {
- [TYPE_EPIC]: {
- query: epicStartDateQuery,
- mutation: updateEpicStartDateMutation,
- },
-};
-
-export const timelogQueries = {
- [TYPE_ISSUE]: {
- query: getIssueTimelogsQuery,
- },
- [TYPE_MERGE_REQUEST]: {
- query: getMrTimelogsQuery,
- },
-};
-
export const noAttributeId = null;
-export const issuableMilestoneQueries = {
- [TYPE_ISSUE]: {
- query: projectIssueMilestoneQuery,
- mutation: projectIssueMilestoneMutation,
- },
- [TYPE_MERGE_REQUEST]: {
- query: mergeRequestMilestone,
- mutation: mergeRequestMilestoneMutation,
- },
-};
-
-export const milestonesQueries = {
- [TYPE_ISSUE]: {
- query: {
- [WORKSPACE_GROUP]: groupMilestonesQuery,
- [WORKSPACE_PROJECT]: projectMilestonesQuery,
- },
- },
- [TYPE_MERGE_REQUEST]: {
- query: {
- [WORKSPACE_GROUP]: groupMilestonesQuery,
- [WORKSPACE_PROJECT]: projectMilestonesQuery,
- },
- },
-};
-
export const IssuableAttributeType = {
Milestone: 'milestone',
};
@@ -285,35 +44,11 @@ export const IssuableAttributeState = {
[IssuableAttributeType.Milestone]: 'active',
};
-export const issuableAttributesQueries = {
- [IssuableAttributeType.Milestone]: {
- current: issuableMilestoneQueries,
- list: milestonesQueries,
- },
-};
-
-export const todoQueries = {
- [TYPE_EPIC]: {
- query: epicTodoQuery,
- },
- [TYPE_ISSUE]: {
- query: issueTodoQuery,
- },
- [TYPE_MERGE_REQUEST]: {
- query: mergeRequestTodoQuery,
- },
-};
-
export const TodoMutationTypes = {
Create: 'create',
MarkDone: 'mark-done',
};
-export const todoMutations = {
- [TodoMutationTypes.Create]: todoCreateMutation,
- [TodoMutationTypes.MarkDone]: todoMarkDoneMutation,
-};
-
export function dropdowni18nText(issuableAttribute, issuableType) {
return {
noAttribute: sprintf(s__('DropdownWidget|No %{issuableAttribute}'), {
@@ -362,9 +97,6 @@ export function dropdowni18nText(issuableAttribute, issuableType) {
};
}
-export const escalationStatusQuery = getEscalationStatusQuery;
-export const escalationStatusMutation = updateEscalationStatusMutation;
-
export const HOW_TO_TRACK_TIME = __('How to track time');
export const statusDropdownOptions = [
diff --git a/app/assets/javascripts/sidebar/queries/constants.js b/app/assets/javascripts/sidebar/queries/constants.js
new file mode 100644
index 00000000000..0844abc4599
--- /dev/null
+++ b/app/assets/javascripts/sidebar/queries/constants.js
@@ -0,0 +1,291 @@
+import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql';
+import userAutocompleteQuery from '~/graphql_shared/queries/project_autocomplete_users.query.graphql';
+import userAutocompleteWithMRPermissionsQuery from '~/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql';
+import issuableDatesUpdatedSubscription from '~/graphql_shared/subscriptions/work_item_dates.subscription.graphql';
+import {
+ TYPE_ALERT,
+ TYPE_EPIC,
+ TYPE_ISSUE,
+ TYPE_MERGE_REQUEST,
+ TYPE_TEST_CASE,
+ WORKSPACE_GROUP,
+ WORKSPACE_PROJECT,
+} from '~/issues/constants';
+import updateAlertAssigneesMutation from '~/vue_shared/alert_details/graphql/mutations/alert_set_assignees.mutation.graphql';
+import abuseReportLabelsQuery from '~/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql';
+import createAbuseReportLabelMutation from '~/admin/abuse_report/components/graphql/create_abuse_report_label.mutation.graphql';
+import createGroupOrProjectLabelMutation from '../components/labels/labels_select_widget/graphql/create_label.mutation.graphql';
+import updateTestCaseLabelsMutation from '../components/labels/labels_select_widget/graphql/update_test_case_labels.mutation.graphql';
+import epicLabelsQuery from '../components/labels/labels_select_widget/graphql/epic_labels.query.graphql';
+import updateEpicLabelsMutation from '../components/labels/labels_select_widget/graphql/epic_update_labels.mutation.graphql';
+import groupLabelsQuery from '../components/labels/labels_select_widget/graphql/group_labels.query.graphql';
+import issueLabelsQuery from '../components/labels/labels_select_widget/graphql/issue_labels.query.graphql';
+import mergeRequestLabelsQuery from '../components/labels/labels_select_widget/graphql/merge_request_labels.query.graphql';
+import projectLabelsQuery from '../components/labels/labels_select_widget/graphql/project_labels.query.graphql';
+import { IssuableAttributeType, TodoMutationTypes } from '../constants';
+import epicConfidentialQuery from './epic_confidential.query.graphql';
+import epicDueDateQuery from './epic_due_date.query.graphql';
+import epicParticipantsQuery from './epic_participants.query.graphql';
+import epicReferenceQuery from './epic_reference.query.graphql';
+import epicStartDateQuery from './epic_start_date.query.graphql';
+import epicSubscribedQuery from './epic_subscribed.query.graphql';
+import epicTodoQuery from './epic_todo.query.graphql';
+import issuableAssigneesSubscription from './issuable_assignees.subscription.graphql';
+import issueConfidentialQuery from './issue_confidential.query.graphql';
+import issueDueDateQuery from './issue_due_date.query.graphql';
+import issueReferenceQuery from './issue_reference.query.graphql';
+import issueSubscribedQuery from './issue_subscribed.query.graphql';
+import issueTimeTrackingQuery from './issue_time_tracking.query.graphql';
+import issueTodoQuery from './issue_todo.query.graphql';
+import mergeRequestMilestone from './merge_request_milestone.query.graphql';
+import mergeRequestReferenceQuery from './merge_request_reference.query.graphql';
+import mergeRequestSubscribed from './merge_request_subscribed.query.graphql';
+import mergeRequestTimeTrackingQuery from './merge_request_time_tracking.query.graphql';
+import mergeRequestTodoQuery from './merge_request_todo.query.graphql';
+import todoCreateMutation from './todo_create.mutation.graphql';
+import todoMarkDoneMutation from './todo_mark_done.mutation.graphql';
+import updateEpicConfidentialMutation from './update_epic_confidential.mutation.graphql';
+import updateEpicDueDateMutation from './update_epic_due_date.mutation.graphql';
+import updateEpicStartDateMutation from './update_epic_start_date.mutation.graphql';
+import updateEpicSubscriptionMutation from './update_epic_subscription.mutation.graphql';
+import updateIssueConfidentialMutation from './update_issue_confidential.mutation.graphql';
+import updateIssueDueDateMutation from './update_issue_due_date.mutation.graphql';
+import updateIssueSubscriptionMutation from './update_issue_subscription.mutation.graphql';
+import mergeRequestMilestoneMutation from './update_merge_request_milestone.mutation.graphql';
+import updateMergeRequestLabelsMutation from './update_merge_request_labels.mutation.graphql';
+import updateMergeRequestSubscriptionMutation from './update_merge_request_subscription.mutation.graphql';
+import getAlertAssignees from './get_alert_assignees.query.graphql';
+import getIssueAssignees from './get_issue_assignees.query.graphql';
+import issueParticipantsQuery from './get_issue_participants.query.graphql';
+import getIssueTimelogsQuery from './get_issue_timelogs.query.graphql';
+import getMergeRequestAssignees from './get_mr_assignees.query.graphql';
+import getMergeRequestParticipants from './get_mr_participants.query.graphql';
+import getMrTimelogsQuery from './get_mr_timelogs.query.graphql';
+import updateIssueAssigneesMutation from './update_issue_assignees.mutation.graphql';
+import updateMergeRequestAssigneesMutation from './update_mr_assignees.mutation.graphql';
+import getEscalationStatusQuery from './escalation_status.query.graphql';
+import updateEscalationStatusMutation from './update_escalation_status.mutation.graphql';
+import groupMilestonesQuery from './group_milestones.query.graphql';
+import projectIssueMilestoneMutation from './project_issue_milestone.mutation.graphql';
+import projectIssueMilestoneQuery from './project_issue_milestone.query.graphql';
+import projectMilestonesQuery from './project_milestones.query.graphql';
+import testCaseConfidentialQuery from './test_case_confidential.query.graphql';
+import updateTestCaseConfidentialMutation from './update_test_case_confidential.mutation.graphql';
+
+export const assigneesQueries = {
+ [TYPE_ISSUE]: {
+ query: getIssueAssignees,
+ subscription: issuableAssigneesSubscription,
+ mutation: updateIssueAssigneesMutation,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: getMergeRequestAssignees,
+ mutation: updateMergeRequestAssigneesMutation,
+ },
+ [TYPE_ALERT]: {
+ query: getAlertAssignees,
+ mutation: updateAlertAssigneesMutation,
+ },
+};
+
+export const participantsQueries = {
+ [TYPE_ISSUE]: {
+ query: issueParticipantsQuery,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: getMergeRequestParticipants,
+ },
+ [TYPE_EPIC]: {
+ query: epicParticipantsQuery,
+ },
+ [TYPE_ALERT]: {
+ query: '',
+ skipQuery: true,
+ },
+};
+
+export const userSearchQueries = {
+ [TYPE_ISSUE]: {
+ query: userAutocompleteQuery,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: userAutocompleteWithMRPermissionsQuery,
+ },
+};
+
+export const confidentialityQueries = {
+ [TYPE_ISSUE]: {
+ query: issueConfidentialQuery,
+ mutation: updateIssueConfidentialMutation,
+ },
+ [TYPE_EPIC]: {
+ query: epicConfidentialQuery,
+ mutation: updateEpicConfidentialMutation,
+ },
+ [TYPE_TEST_CASE]: {
+ query: testCaseConfidentialQuery,
+ mutation: updateTestCaseConfidentialMutation,
+ },
+};
+
+export const referenceQueries = {
+ [TYPE_ISSUE]: {
+ query: issueReferenceQuery,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: mergeRequestReferenceQuery,
+ },
+ [TYPE_EPIC]: {
+ query: epicReferenceQuery,
+ },
+};
+
+export const workspaceLabelsQueries = {
+ [WORKSPACE_PROJECT]: {
+ query: projectLabelsQuery,
+ dataPath: 'workspace.labels',
+ },
+ [WORKSPACE_GROUP]: {
+ query: groupLabelsQuery,
+ dataPath: 'workspace.labels',
+ },
+ abuseReport: {
+ query: abuseReportLabelsQuery,
+ dataPath: 'labels',
+ },
+};
+
+export const workspaceCreateLabelMutation = {
+ [WORKSPACE_PROJECT]: createGroupOrProjectLabelMutation,
+ [WORKSPACE_GROUP]: createGroupOrProjectLabelMutation,
+ abuseReport: createAbuseReportLabelMutation,
+};
+
+export const issuableLabelsQueries = {
+ [TYPE_ISSUE]: {
+ issuableQuery: issueLabelsQuery,
+ mutation: updateIssueLabelsMutation,
+ mutationName: 'updateIssue',
+ },
+ [TYPE_MERGE_REQUEST]: {
+ issuableQuery: mergeRequestLabelsQuery,
+ mutation: updateMergeRequestLabelsMutation,
+ mutationName: 'mergeRequestSetLabels',
+ },
+ [TYPE_EPIC]: {
+ issuableQuery: epicLabelsQuery,
+ mutation: updateEpicLabelsMutation,
+ mutationName: 'updateEpic',
+ },
+ [TYPE_TEST_CASE]: {
+ issuableQuery: issueLabelsQuery,
+ mutation: updateTestCaseLabelsMutation,
+ mutationName: 'updateTestCaseLabels',
+ },
+};
+
+export const subscribedQueries = {
+ [TYPE_ISSUE]: {
+ query: issueSubscribedQuery,
+ mutation: updateIssueSubscriptionMutation,
+ },
+ [TYPE_EPIC]: {
+ query: epicSubscribedQuery,
+ mutation: updateEpicSubscriptionMutation,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: mergeRequestSubscribed,
+ mutation: updateMergeRequestSubscriptionMutation,
+ },
+};
+
+export const timeTrackingQueries = {
+ [TYPE_ISSUE]: {
+ query: issueTimeTrackingQuery,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: mergeRequestTimeTrackingQuery,
+ },
+};
+
+export const dueDateQueries = {
+ [TYPE_ISSUE]: {
+ query: issueDueDateQuery,
+ mutation: updateIssueDueDateMutation,
+ subscription: issuableDatesUpdatedSubscription,
+ },
+ [TYPE_EPIC]: {
+ query: epicDueDateQuery,
+ mutation: updateEpicDueDateMutation,
+ },
+};
+
+export const startDateQueries = {
+ [TYPE_EPIC]: {
+ query: epicStartDateQuery,
+ mutation: updateEpicStartDateMutation,
+ },
+};
+
+export const timelogQueries = {
+ [TYPE_ISSUE]: {
+ query: getIssueTimelogsQuery,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: getMrTimelogsQuery,
+ },
+};
+
+export const issuableMilestoneQueries = {
+ [TYPE_ISSUE]: {
+ query: projectIssueMilestoneQuery,
+ mutation: projectIssueMilestoneMutation,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: mergeRequestMilestone,
+ mutation: mergeRequestMilestoneMutation,
+ },
+};
+
+export const milestonesQueries = {
+ [TYPE_ISSUE]: {
+ query: {
+ [WORKSPACE_GROUP]: groupMilestonesQuery,
+ [WORKSPACE_PROJECT]: projectMilestonesQuery,
+ },
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: {
+ [WORKSPACE_GROUP]: groupMilestonesQuery,
+ [WORKSPACE_PROJECT]: projectMilestonesQuery,
+ },
+ },
+};
+
+export const issuableAttributesQueries = {
+ [IssuableAttributeType.Milestone]: {
+ current: issuableMilestoneQueries,
+ list: milestonesQueries,
+ },
+};
+
+export const todoQueries = {
+ [TYPE_EPIC]: {
+ query: epicTodoQuery,
+ },
+ [TYPE_ISSUE]: {
+ query: issueTodoQuery,
+ },
+ [TYPE_MERGE_REQUEST]: {
+ query: mergeRequestTodoQuery,
+ },
+};
+
+export const todoMutations = {
+ [TodoMutationTypes.Create]: todoCreateMutation,
+ [TodoMutationTypes.MarkDone]: todoMarkDoneMutation,
+};
+
+export const escalationStatusQuery = getEscalationStatusQuery;
+
+export const escalationStatusMutation = updateEscalationStatusMutation;
diff --git a/app/assets/javascripts/sidebar/queries/test_case_confidential.query.graphql b/app/assets/javascripts/sidebar/queries/test_case_confidential.query.graphql
new file mode 100644
index 00000000000..d8959b5ce3f
--- /dev/null
+++ b/app/assets/javascripts/sidebar/queries/test_case_confidential.query.graphql
@@ -0,0 +1,9 @@
+query testCaseConfidential($fullPath: ID!, $iid: String) {
+ workspace: project(fullPath: $fullPath) {
+ id
+ issuable: issue(iid: $iid) {
+ id
+ confidential
+ }
+ }
+}
diff --git a/app/assets/javascripts/sidebar/queries/update_test_case_confidential.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_test_case_confidential.mutation.graphql
new file mode 100644
index 00000000000..4094907cb95
--- /dev/null
+++ b/app/assets/javascripts/sidebar/queries/update_test_case_confidential.mutation.graphql
@@ -0,0 +1,9 @@
+mutation updateTestCaseConfidential($input: IssueSetConfidentialInput!) {
+ issuableSetConfidential: issueSetConfidential(input: $input) {
+ issuable: issue {
+ id
+ confidential
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/silent_mode_settings/components/app.vue b/app/assets/javascripts/silent_mode_settings/components/app.vue
new file mode 100644
index 00000000000..2dd0449448c
--- /dev/null
+++ b/app/assets/javascripts/silent_mode_settings/components/app.vue
@@ -0,0 +1,70 @@
+<script>
+import { GlToggle, GlBadge } from '@gitlab/ui';
+import { updateApplicationSettings } from '~/rest_api';
+import { createAlert } from '~/alert';
+import toast from '~/vue_shared/plugins/global_toast';
+import { sprintf, __, s__ } from '~/locale';
+
+export default {
+ name: 'SilentModeSettingsApp',
+ i18n: {
+ toggleLabel: s__('SilentMode|Enable silent mode'),
+ saveSuccess: s__('SilentMode|Silent mode %{status}'),
+ saveError: s__('SilentMode|There was an error updating the Silent Mode Settings.'),
+ enabled: __('enabled'),
+ disabled: __('disabled'),
+ experiment: __('Experiment'),
+ },
+ components: {
+ GlToggle,
+ GlBadge,
+ },
+ props: {
+ isSilentModeEnabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ isLoading: false,
+ silentModeEnabled: this.isSilentModeEnabled,
+ };
+ },
+ methods: {
+ updateSilentModeSettings() {
+ this.isLoading = true;
+
+ updateApplicationSettings({
+ silent_mode_enabled: this.silentModeEnabled,
+ })
+ .then(() => {
+ const status = this.silentModeEnabled
+ ? this.$options.i18n.enabled
+ : this.$options.i18n.disabled;
+ toast(sprintf(this.$options.i18n.saveSuccess, { status }));
+ })
+ .catch(() => {
+ createAlert({ message: this.$options.i18n.saveError });
+ })
+ .finally(() => {
+ this.isLoading = false;
+ });
+ },
+ },
+};
+</script>
+<template>
+ <gl-toggle
+ v-model="silentModeEnabled"
+ label-id="silent-mode-toggle"
+ :label="$options.i18n.toggleLabel"
+ :is-loading="isLoading"
+ @change="updateSilentModeSettings"
+ >
+ <template #label
+ >{{ $options.i18n.toggleLabel }} <gl-badge>{{ $options.i18n.experiment }}</gl-badge></template
+ >
+ </gl-toggle>
+</template>
diff --git a/app/assets/javascripts/silent_mode_settings/index.js b/app/assets/javascripts/silent_mode_settings/index.js
new file mode 100644
index 00000000000..b18f9c02964
--- /dev/null
+++ b/app/assets/javascripts/silent_mode_settings/index.js
@@ -0,0 +1,27 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import SilentModeSettingsApp from './components/app.vue';
+
+Vue.use(Translate);
+
+export const initSilentModeSettings = () => {
+ const el = document.getElementById('js-silent-mode-settings');
+
+ if (!el) {
+ return false;
+ }
+
+ const { silentModeEnabled } = el.dataset;
+
+ return new Vue({
+ el,
+ render(createElement) {
+ return createElement(SilentModeSettingsApp, {
+ props: {
+ isSilentModeEnabled: parseBoolean(silentModeEnabled),
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/snippets/components/embed_dropdown.vue b/app/assets/javascripts/snippets/components/embed_dropdown.vue
index 0fdbc89a038..17312c2373b 100644
--- a/app/assets/javascripts/snippets/components/embed_dropdown.vue
+++ b/app/assets/javascripts/snippets/components/embed_dropdown.vue
@@ -1,12 +1,5 @@
<script>
-import {
- GlButton,
- GlDropdown,
- GlDropdownSectionHeader,
- GlDropdownText,
- GlFormInputGroup,
- GlTooltipDirective,
-} from '@gitlab/ui';
+import { GlButton, GlDisclosureDropdown, GlFormInputGroup, GlTooltipDirective } from '@gitlab/ui';
import { escape as esc } from 'lodash';
import { __ } from '~/locale';
@@ -17,9 +10,7 @@ const MSG_COPY = __('Copy');
export default {
components: {
GlButton,
- GlDropdown,
- GlDropdownSectionHeader,
- GlDropdownText,
+ GlDisclosureDropdown,
GlFormInputGroup,
},
directives: {
@@ -45,22 +36,16 @@ export default {
};
</script>
<template>
- <gl-dropdown
- right
- :text="$options.MSG_EMBED"
- menu-class="gl-px-1! gl-pb-5! gl-dropdown-menu-wide"
+ <gl-disclosure-dropdown
+ :auto-close="false"
+ fluid-width
+ placement="right"
+ :toggle-text="$options.MSG_EMBED"
>
<template v-for="{ name, value } in sections">
- <gl-dropdown-section-header :key="`header_${name}`" data-testid="header">{{
- name
- }}</gl-dropdown-section-header>
- <gl-dropdown-text
- :key="`input_${name}`"
- tag="div"
- class="gl-dropdown-text-py-0 gl-dropdown-text-block"
- data-testid="input"
- >
- <gl-form-input-group :value="value" readonly select-on-click :label="name">
+ <div :key="name" :data-testid="`section-${name}`" class="gl-px-4 gl-py-2">
+ <h5 class="gl-font-sm gl-mt-1 gl-mb-2" data-testid="header">{{ name }}</h5>
+ <gl-form-input-group class="gl-w-31" :value="value" readonly select-on-click :label="name">
<template #append>
<gl-button
v-gl-tooltip.hover
@@ -73,7 +58,7 @@ export default {
/>
</template>
</gl-form-input-group>
- </gl-dropdown-text>
+ </div>
</template>
- </gl-dropdown>
+ </gl-disclosure-dropdown>
</template>
diff --git a/app/assets/javascripts/snippets/utils/blob.js b/app/assets/javascripts/snippets/utils/blob.js
index a228d6111ce..97f21654aae 100644
--- a/app/assets/javascripts/snippets/utils/blob.js
+++ b/app/assets/javascripts/snippets/utils/blob.js
@@ -34,7 +34,8 @@ const diff = ({ content, path }, origBlob) => {
content,
filePath: path,
};
- } else if (origBlob.path !== path || origBlob.content !== content) {
+ }
+ if (origBlob.path !== path || origBlob.content !== content) {
return {
action: origBlob.path === path ? SNIPPET_BLOB_ACTION_UPDATE : SNIPPET_BLOB_ACTION_MOVE,
previousPath: origBlob.path,
diff --git a/app/assets/javascripts/super_sidebar/components/brand_logo.vue b/app/assets/javascripts/super_sidebar/components/brand_logo.vue
index 1589f4978e1..02cf36fb053 100644
--- a/app/assets/javascripts/super_sidebar/components/brand_logo.vue
+++ b/app/assets/javascripts/super_sidebar/components/brand_logo.vue
@@ -26,20 +26,28 @@ export default {
<template>
<a
- v-gl-tooltip:super-sidebar.hover.noninteractive.bottom.ds500="$options.i18n.homepage"
+ v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.homepage"
class="brand-logo"
:href="rootPath"
- :title="$options.i18n.homepage"
data-track-action="click_link"
data-track-label="gitlab_logo_link"
data-track-property="nav_core_menu"
>
+ <span class="gl-sr-only">{{ $options.i18n.homepage }}</span>
+ <!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings -->
<img
v-if="logoUrl"
+ alt=""
data-testid="brand-header-custom-logo"
:src="logoUrl"
class="gl-h-6 gl-max-w-full"
/>
- <span v-else v-safe-html="$options.logo" data-testid="brand-header-default-logo"></span>
+ <!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings -->
+ <span
+ v-else
+ v-safe-html="$options.logo"
+ aria-hidden
+ data-testid="brand-header-default-logo"
+ ></span>
</a>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/context_header.vue b/app/assets/javascripts/super_sidebar/components/context_header.vue
deleted file mode 100644
index 11b9840a409..00000000000
--- a/app/assets/javascripts/super_sidebar/components/context_header.vue
+++ /dev/null
@@ -1,56 +0,0 @@
-<script>
-import { GlTruncate, GlAvatar, GlIcon } from '@gitlab/ui';
-
-export default {
- components: {
- GlTruncate,
- GlAvatar,
- GlIcon,
- },
- props: {
- /*
- * Contains metadata about the current view, e.g. `id`, `title` and `avatar`
- */
- context: {
- type: Object,
- required: true,
- },
- tag: {
- type: String,
- required: false,
- default: 'div',
- },
- },
- computed: {
- avatarShape() {
- return this.context.avatar_shape || 'rect';
- },
- },
-};
-</script>
-
-<template>
- <component
- :is="tag"
- class="border-top border-bottom gl-border-gray-a-08! gl-display-flex gl-align-items-center gl-gap-3 gl-font-weight-bold gl-w-full gl-h-8 gl-px-4 gl-flex-shrink-0"
- >
- <span
- v-if="context.icon"
- class="gl-avatar avatar-container gl-bg-t-gray-a-08 icon-avatar rect-avatar s24"
- >
- <gl-icon class="gl-text-gray-700" :name="context.icon" :size="16" />
- </span>
- <gl-avatar
- v-else
- :size="24"
- :shape="avatarShape"
- :entity-name="context.title"
- :entity-id="context.id"
- :src="context.avatar"
- />
- <div class="gl-flex-grow-1 gl-overflow-auto gl-text-gray-900">
- <gl-truncate :text="context.title" />
- </div>
- <slot name="end"></slot>
- </component>
-</template>
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher.vue b/app/assets/javascripts/super_sidebar/components/context_switcher.vue
deleted file mode 100644
index d4aa11b6e04..00000000000
--- a/app/assets/javascripts/super_sidebar/components/context_switcher.vue
+++ /dev/null
@@ -1,209 +0,0 @@
-<script>
-import * as Sentry from '@sentry/browser';
-import { GlDisclosureDropdown, GlSearchBoxByType, GlLoadingIcon, GlAlert } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import searchUserProjectsAndGroups from '../graphql/queries/search_user_groups_and_projects.query.graphql';
-import { trackContextAccess, formatContextSwitcherItems } from '../utils';
-import NavItem from './nav_item.vue';
-import ProjectsList from './projects_list.vue';
-import GroupsList from './groups_list.vue';
-import ContextSwitcherToggle from './context_switcher_toggle.vue';
-
-export default {
- i18n: {
- contextNavigation: s__('Navigation|Context navigation'),
- switchTo: s__('Navigation|Switch context'),
- searchPlaceholder: s__('Navigation|Search your projects or groups'),
- searchingLabel: s__('Navigation|Retrieving search results'),
- searchError: s__('Navigation|There was an error fetching search results.'),
- },
- apollo: {
- groupsAndProjects: {
- query: searchUserProjectsAndGroups,
- manual: true,
- variables() {
- return {
- username: this.username,
- search: this.searchString,
- };
- },
- result(response) {
- this.hasError = false;
- try {
- const {
- data: {
- projects: { nodes: projects },
- user: {
- groups: { nodes: groups },
- },
- },
- } = response;
-
- this.projects = formatContextSwitcherItems(projects);
- this.groups = formatContextSwitcherItems(groups);
- } catch (e) {
- this.handleError(e);
- }
- },
- error(e) {
- this.handleError(e);
- },
- skip() {
- return !this.searchString;
- },
- },
- },
- components: {
- GlDisclosureDropdown,
- ContextSwitcherToggle,
- GlSearchBoxByType,
- GlLoadingIcon,
- GlAlert,
- NavItem,
- ProjectsList,
- GroupsList,
- },
- inject: ['contextSwitcherLinks'],
- props: {
- username: {
- type: String,
- required: true,
- },
- projectsPath: {
- type: String,
- required: true,
- },
- groupsPath: {
- type: String,
- required: true,
- },
- currentContext: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- contextHeader: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- searchString: '',
- projects: [],
- groups: [],
- hasError: false,
- isOpen: false,
- };
- },
- computed: {
- isSearch() {
- return Boolean(this.searchString);
- },
- isSearching() {
- return this.$apollo.queries.groupsAndProjects.loading;
- },
- },
- watch: {
- isOpen(isOpen) {
- this.$emit('toggle', isOpen);
-
- if (isOpen) {
- this.focusInput();
- }
- },
- },
- created() {
- if (this.currentContext.namespace) {
- trackContextAccess(this.username, this.currentContext);
- }
- },
- methods: {
- close() {
- this.$refs['disclosure-dropdown'].close();
- },
- focusInput() {
- this.$refs['search-box'].focusInput();
- },
- handleError(e) {
- Sentry.captureException(e);
- this.hasError = true;
- },
- onDisclosureDropdownShown() {
- this.isOpen = true;
- },
- onDisclosureDropdownHidden() {
- this.isOpen = false;
- },
- },
- DEFAULT_DEBOUNCE_AND_THROTTLE_MS,
-};
-</script>
-
-<template>
- <gl-disclosure-dropdown
- ref="disclosure-dropdown"
- class="context-switcher gl-w-full"
- placement="center"
- @shown="onDisclosureDropdownShown"
- @hidden="onDisclosureDropdownHidden"
- >
- <template #toggle>
- <context-switcher-toggle :context="contextHeader" :expanded="isOpen" />
- </template>
- <div aria-hidden="true" class="gl-font-sm gl-font-weight-bold gl-px-4 gl-pt-3 gl-pb-4">
- {{ $options.i18n.switchTo }}
- </div>
- <div class="gl-p-1 gl-border-t gl-border-b gl-border-gray-50 gl-bg-white">
- <gl-search-box-by-type
- ref="search-box"
- v-model="searchString"
- class="context-switcher-search-box"
- :placeholder="$options.i18n.searchPlaceholder"
- :debounce="$options.DEFAULT_DEBOUNCE_AND_THROTTLE_MS"
- borderless
- />
- </div>
- <gl-loading-icon
- v-if="isSearching"
- class="gl-mt-5"
- size="md"
- :label="$options.i18n.searchingLabel"
- />
- <gl-alert v-else-if="hasError" variant="danger" :dismissible="false" class="gl-m-2">
- {{ $options.i18n.searchError }}
- </gl-alert>
- <nav v-else :aria-label="$options.i18n.contextNavigation" data-testid="context-navigation">
- <ul class="gl-p-0 gl-m-0 gl-list-style-none">
- <li v-if="!isSearch">
- <ul
- :aria-label="$options.i18n.switchTo"
- class="gl-border-b gl-border-gray-50 gl-px-0 gl-py-2"
- >
- <nav-item
- v-for="item in contextSwitcherLinks"
- :key="item.link"
- :item="item"
- :link-classes="{ [item.link_classes]: item.link_classes }"
- is-subitem
- />
- </ul>
- </li>
- <projects-list
- :username="username"
- :view-all-link="projectsPath"
- :is-search="isSearch"
- :search-results="projects"
- />
- <groups-list
- class="gl-border-t gl-border-gray-50"
- :username="username"
- :view-all-link="groupsPath"
- :is-search="isSearch"
- :search-results="groups"
- />
- </ul>
- </nav>
- </gl-disclosure-dropdown>
-</template>
diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue b/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
deleted file mode 100644
index faa7eba6470..00000000000
--- a/app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue
+++ /dev/null
@@ -1,43 +0,0 @@
-<script>
-import { GlIcon } from '@gitlab/ui';
-import ContextHeader from './context_header.vue';
-
-export default {
- components: {
- GlIcon,
- ContextHeader,
- },
- props: {
- /*
- * Contains metadata about the current view, e.g. `id`, `title` and `avatar`
- */
- context: {
- type: Object,
- required: true,
- },
- expanded: {
- type: Boolean,
- required: true,
- },
- },
- computed: {
- collapseIcon() {
- return this.expanded ? 'chevron-up' : 'chevron-down';
- },
- },
-};
-</script>
-
-<template>
- <context-header
- :context="context"
- tag="button"
- type="button"
- class="context-switcher-toggle gl-p-0 gl-bg-transparent gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-border-0 gl-box-shadow-none gl-text-left"
- data-testid="context-switcher"
- >
- <template #end>
- <gl-icon class="gl-text-gray-400" :name="collapseIcon" />
- </template>
- </context-header>
-</template>
diff --git a/app/assets/javascripts/super_sidebar/components/create_menu.vue b/app/assets/javascripts/super_sidebar/components/create_menu.vue
index 3645606515f..d1e96479631 100644
--- a/app/assets/javascripts/super_sidebar/components/create_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/create_menu.vue
@@ -1,7 +1,7 @@
<script>
import {
GlDisclosureDropdown,
- GlTooltip,
+ GlTooltipDirective,
GlDisclosureDropdownGroup,
GlDisclosureDropdownItem,
} from '@gitlab/ui';
@@ -14,7 +14,7 @@ import {
import { DROPDOWN_Y_OFFSET, IMPERSONATING_OFFSET } from '../constants';
// Left offset required for the dropdown to be aligned with the super sidebar
-const DROPDOWN_X_OFFSET_BASE = -147;
+const DROPDOWN_X_OFFSET_BASE = -179;
const DROPDOWN_X_OFFSET_IMPERSONATING = DROPDOWN_X_OFFSET_BASE + IMPERSONATING_OFFSET;
export default {
@@ -22,9 +22,11 @@ export default {
GlDisclosureDropdown,
GlDisclosureDropdownGroup,
GlDisclosureDropdownItem,
- GlTooltip,
InviteMembersTrigger,
},
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
i18n: {
createNew: __('Create new...'),
},
@@ -59,45 +61,35 @@ export default {
</script>
<template>
- <div>
- <gl-disclosure-dropdown
- category="tertiary"
- icon="plus"
- no-caret
- text-sr-only
- :toggle-text="$options.i18n.createNew"
- :toggle-id="$options.toggleId"
- :dropdown-offset="dropdownOffset"
- data-qa-selector="new_menu_toggle"
- data-testid="new-menu-toggle"
- @shown="dropdownOpen = true"
- @hidden="dropdownOpen = false"
- >
- <gl-disclosure-dropdown-group
- v-for="(group, index) in groups"
- :key="group.name"
- :bordered="index !== 0"
- :group="group"
- >
- <template v-for="groupItem in group.items">
- <invite-members-trigger
- v-if="isInvitedMembers(groupItem)"
- :key="`${groupItem.text}-trigger`"
- trigger-source="top-nav"
- :trigger-element="$options.TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN"
- />
- <gl-disclosure-dropdown-item v-else :key="groupItem.text" :item="groupItem" />
- </template>
- </gl-disclosure-dropdown-group>
- </gl-disclosure-dropdown>
- <gl-tooltip
- v-if="!dropdownOpen"
- :target="`#${$options.toggleId}`"
- placement="bottom"
- container="#super-sidebar"
- noninteractive
+ <gl-disclosure-dropdown
+ v-gl-tooltip:super-sidebar.hover.bottom="dropdownOpen ? '' : $options.i18n.createNew"
+ category="tertiary"
+ icon="plus"
+ no-caret
+ text-sr-only
+ :toggle-text="$options.i18n.createNew"
+ :toggle-id="$options.toggleId"
+ :dropdown-offset="dropdownOffset"
+ data-qa-selector="new_menu_toggle"
+ data-testid="new-menu-toggle"
+ @shown="dropdownOpen = true"
+ @hidden="dropdownOpen = false"
+ >
+ <gl-disclosure-dropdown-group
+ v-for="(group, index) in groups"
+ :key="group.name"
+ :bordered="index !== 0"
+ :group="group"
>
- {{ $options.i18n.createNew }}
- </gl-tooltip>
- </div>
+ <template v-for="groupItem in group.items">
+ <invite-members-trigger
+ v-if="isInvitedMembers(groupItem)"
+ :key="`${groupItem.text}-trigger`"
+ trigger-source="top_nav"
+ :trigger-element="$options.TRIGGER_ELEMENT_DISCLOSURE_DROPDOWN"
+ />
+ <gl-disclosure-dropdown-item v-else :key="groupItem.text" :item="groupItem" />
+ </template>
+ </gl-disclosure-dropdown-group>
+ </gl-disclosure-dropdown>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/flyout_menu.vue b/app/assets/javascripts/super_sidebar/components/flyout_menu.vue
index fa7960da2f4..e73b9b275ee 100644
--- a/app/assets/javascripts/super_sidebar/components/flyout_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/flyout_menu.vue
@@ -2,6 +2,23 @@
import { computePosition, autoUpdate, offset, flip, shift } from '@floating-ui/dom';
import NavItem from './nav_item.vue';
+// Flyout menus are shown when the MenuSection's title is hovered with the mouse.
+// Their position is dynamically calculated with floating-ui.
+//
+// Since flyout menus show all NavItems of a section, they can be very long and
+// a user might want to move their mouse diagonally from the section title down
+// to last nav item in the flyout. But this mouse movement over other sections
+// would loose hover and close the flyout, opening another section's flyout.
+// To avoid this annoyance, our flyouts come with a "diagonal tolerance". This
+// is an area between the current mouse position and the top- and bottom-left
+// corner of the flyout itself. While the mouse stays within this area and
+// reaches the flyout before a timer expires, the native browser hover stays
+// within the component.
+// This is done with an transparent SVG positioned left of the flyout menu,
+// overlapping the sidebar. The SVG itself ignores pointer events but its two
+// triangles, one above the section title, one below, do listen to events,
+// keeping hover.
+
export default {
name: 'FlyoutMenu',
components: { NavItem },
@@ -15,13 +32,45 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ currentMouseX: 0,
+ flyoutX: 0,
+ flyoutY: 0,
+ flyoutHeight: 0,
+ hoverTimeoutId: null,
+ showSVG: true,
+ targetRect: null,
+ };
+ },
cleanupFunction: undefined,
+ computed: {
+ topSVGPoints() {
+ const x = (this.currentMouseX / this.targetRect.width) * 100;
+ let y = ((this.targetRect.top - this.flyoutY) / this.flyoutHeight) * 100;
+ y += 1; // overlap title to not loose hover
+
+ return `${x}, ${y} 100, 0 100, ${y}`;
+ },
+ bottomSVGPoints() {
+ const x = (this.currentMouseX / this.targetRect.width) * 100;
+ let y = ((this.targetRect.bottom - this.flyoutY) / this.flyoutHeight) * 100;
+ y -= 1; // overlap title to not loose hover
+
+ return `${x}, ${y} 100, ${y} 100, 100`;
+ },
+ },
+ created() {
+ const target = document.querySelector(`#${this.targetId}`);
+ target.addEventListener('mousemove', this.onMouseMove);
+ },
mounted() {
const target = document.querySelector(`#${this.targetId}`);
const flyout = document.querySelector(`#${this.targetId}-flyout`);
+ const sidebar = document.querySelector('#super-sidebar');
- function updatePosition() {
- return computePosition(target, flyout, {
+ const updatePosition = () =>
+ computePosition(target, flyout, {
middleware: [offset({ alignmentAxis: -12 }), flip(), shift()],
placement: 'right-start',
strategy: 'fixed',
@@ -30,13 +79,46 @@ export default {
left: `${x}px`,
top: `${y}px`,
});
+ this.flyoutX = x;
+ this.flyoutY = y;
+ this.flyoutHeight = flyout.clientHeight;
+
+ // Flyout coordinates are relative to the sidebar which can be
+ // shifted down by the performance-bar etc.
+ // Adjust viewport coordinates from getBoundingClientRect:
+ const targetRect = target.getBoundingClientRect();
+ const sidebarRect = sidebar.getBoundingClientRect();
+ this.targetRect = {
+ top: targetRect.top - sidebarRect.top,
+ bottom: targetRect.bottom - sidebarRect.top,
+ width: targetRect.width,
+ };
});
- }
this.$options.cleanupFunction = autoUpdate(target, flyout, updatePosition);
},
beforeUnmount() {
this.$options.cleanupFunction();
+ clearTimeout(this.hoverTimeoutId);
+ },
+ beforeDestroy() {
+ const target = document.querySelector(`#${this.targetId}`);
+ target.removeEventListener('mousemove', this.onMouseMove);
+ },
+ methods: {
+ startHoverTimeout() {
+ this.hoverTimeoutId = setTimeout(() => {
+ this.showSVG = false;
+ this.$emit('mouseleave');
+ }, 1000);
+ },
+ stopHoverTimeout() {
+ clearTimeout(this.hoverTimeoutId);
+ },
+ onMouseMove(e) {
+ // add some wiggle room to the left of mouse cursor
+ this.currentMouseX = Math.max(0, e.clientX - 5);
+ },
},
};
</script>
@@ -49,8 +131,8 @@ export default {
@mouseleave="$emit('mouseleave')"
>
<ul
- v-if="items.length > 0"
class="gl-min-w-20 gl-max-w-34 gl-border-1 gl-rounded-base gl-border-solid gl-border-gray-100 gl-shadow-md gl-bg-white gl-p-2 gl-pb-1 gl-list-style-none"
+ @mouseenter="showSVG = false"
>
<nav-item
v-for="item of items"
@@ -61,5 +143,44 @@ export default {
@pin-remove="(itemId) => $emit('pin-remove', itemId)"
/>
</ul>
+ <svg
+ v-if="targetRect && showSVG"
+ :width="flyoutX"
+ :height="flyoutHeight"
+ viewBox="0 0 100 100"
+ preserveAspectRatio="none"
+ :style="{
+ top: flyoutY + 'px',
+ }"
+ >
+ <polygon
+ ref="topSVG"
+ :points="topSVGPoints"
+ fill="transparent"
+ @mouseenter="startHoverTimeout"
+ @mouseleave="stopHoverTimeout"
+ />
+ <polygon
+ ref="bottomSVG"
+ :points="bottomSVGPoints"
+ fill="transparent"
+ @mouseenter="startHoverTimeout"
+ @mouseleave="stopHoverTimeout"
+ />
+ </svg>
</div>
</template>
+
+<style scoped>
+svg {
+ pointer-events: none;
+
+ position: fixed;
+ right: 0;
+}
+
+svg polygon,
+svg rect {
+ pointer-events: auto;
+}
+</style>
diff --git a/app/assets/javascripts/super_sidebar/components/frequent_items_list.vue b/app/assets/javascripts/super_sidebar/components/frequent_items_list.vue
deleted file mode 100644
index fe1a907bd91..00000000000
--- a/app/assets/javascripts/super_sidebar/components/frequent_items_list.vue
+++ /dev/null
@@ -1,106 +0,0 @@
-<script>
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-import { __ } from '~/locale';
-import {
- getItemsFromLocalStorage,
- removeItemFromLocalStorage,
- formatContextSwitcherItems,
-} from '../utils';
-import ItemsList from './items_list.vue';
-
-export default {
- components: {
- GlButton,
- ItemsList,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- title: {
- type: String,
- required: true,
- },
- pristineText: {
- type: String,
- required: true,
- },
- storageKey: {
- type: String,
- required: true,
- },
- maxItems: {
- type: Number,
- required: true,
- },
- },
- data() {
- return {
- cachedFrequentItems: [],
- };
- },
- computed: {
- isEmpty() {
- return !this.cachedFrequentItems.length;
- },
- },
- created() {
- this.cachedFrequentItems = formatContextSwitcherItems(
- getItemsFromLocalStorage({
- storageKey: this.storageKey,
- maxItems: this.maxItems,
- }),
- );
- },
- methods: {
- handleItemRemove(item) {
- removeItemFromLocalStorage({
- storageKey: this.storageKey,
- item,
- });
-
- this.cachedFrequentItems = this.cachedFrequentItems.filter((i) => i.id !== item.id);
- },
- },
- i18n: {
- removeItem: __('Remove'),
- },
-};
-</script>
-
-<template>
- <li class="gl-py-3">
- <div
- data-testid="list-title"
- aria-hidden="true"
- class="gl-display-flex gl-align-items-center gl-text-transform-uppercase gl-text-secondary gl-font-weight-semibold gl-font-xs gl-line-height-12 gl-letter-spacing-06em gl-my-3"
- >
- <span class="gl-flex-grow-1 gl-px-3">{{ title }}</span>
- </div>
- <div
- v-if="isEmpty"
- data-testid="empty-text"
- class="gl-text-gray-500 gl-font-sm gl-my-3 gl-mx-3"
- >
- {{ pristineText }}
- </div>
- <items-list :aria-label="title" :items="cachedFrequentItems">
- <template #actions="{ item }">
- <gl-button
- v-gl-tooltip.right.viewport
- size="small"
- category="tertiary"
- icon="dash"
- class="show-on-focus-or-hover--target"
- :aria-label="$options.i18n.removeItem"
- :title="$options.i18n.removeItem"
- data-testid="item-remove"
- @click.stop.prevent="handleItemRemove(item)"
- />
- </template>
- <template #view-all-items>
- <slot name="view-all-items"></slot>
- </template>
- </items-list>
- </li>
-</template>
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue
index bd79962f1a1..b85b163cea9 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue
+++ b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue
@@ -5,6 +5,7 @@ import { GlDisclosureDropdownGroup, GlLoadingIcon } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import axios from '~/lib/utils/axios_utils';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+import Tracking from '~/tracking';
import { getFormattedItem } from '../utils';
import {
@@ -18,6 +19,8 @@ import {
PATH_GROUP_TITLE,
GROUP_TITLES,
MAX_ROWS,
+ TRACKING_ACTIVATE_COMMAND_PALETTE,
+ TRACKING_HANDLE_LABEL_MAP,
} from './constants';
import SearchItem from './search_item.vue';
import { commandMapper, linksReducer, autocompleteQuery, fileMapper } from './utils';
@@ -29,6 +32,7 @@ export default {
GlLoadingIcon,
SearchItem,
},
+ mixins: [Tracking.mixin()],
inject: [
'commandPaletteCommands',
'commandPaletteLinks',
@@ -134,10 +138,15 @@ export default {
immediate: true,
},
handle: {
- handler() {
- this.debouncedSearch();
+ handler(value, oldValue) {
+ // Do not run search immediately on component creation
+ if (oldValue !== undefined) this.debouncedSearch();
+
+ // Track immediately on component creation
+ const label = TRACKING_HANDLE_LABEL_MAP[value] ?? 'unknown';
+ this.track(TRACKING_ACTIVATE_COMMAND_PALETTE, { label });
},
- immediate: false,
+ immediate: true,
},
},
updated() {
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js
index a43e621da44..f6f4e36e43a 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js
+++ b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js
@@ -6,6 +6,16 @@ export const PROJECT_HANDLE = ':';
export const ISSUE_HANDLE = '#';
export const PATH_HANDLE = '/';
+export const TRACKING_ACTIVATE_COMMAND_PALETTE = 'activate_command_palette';
+export const TRACKING_CLICK_COMMAND_PALETTE_ITEM = 'click_command_palette_item';
+export const TRACKING_HANDLE_LABEL_MAP = {
+ [COMMAND_HANDLE]: 'command',
+ [USER_HANDLE]: 'user',
+ [PROJECT_HANDLE]: 'project',
+ [PATH_HANDLE]: 'path',
+ // No ISSUE_HANDLE. See https://gitlab.com/gitlab-org/gitlab/-/issues/417434.
+};
+
export const COMMON_HANDLES = [COMMAND_HANDLE, USER_HANDLE, PROJECT_HANDLE];
export const SEARCH_OR_COMMAND_MODE_PLACEHOLDER = sprintf(
s__(
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/utils.js b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/utils.js
index 347a8ffb0b4..32abbbfd3c2 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/utils.js
+++ b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/utils.js
@@ -1,6 +1,11 @@
import { isNil, omitBy } from 'lodash';
import { objectToQuery, joinPaths } from '~/lib/utils/url_utility';
-import { SEARCH_SCOPE, GLOBAL_COMMANDS_GROUP_TITLE } from './constants';
+import { TRACKING_UNKNOWN_ID } from '~/super_sidebar/constants';
+import {
+ SEARCH_SCOPE,
+ GLOBAL_COMMANDS_GROUP_TITLE,
+ TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+} from './constants';
export const commandMapper = ({ name, items }) => {
// TODO: we filter out invite_members for now, because it is complicated to add the invite members modal here
@@ -12,18 +17,34 @@ export const commandMapper = ({ name, items }) => {
};
export const linksReducer = (acc, menuItem) => {
+ const trackingAttrs = ({ id, title }) => {
+ return {
+ extraAttrs: {
+ 'data-track-action': TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+ 'data-track-label': id || TRACKING_UNKNOWN_ID,
+ ...(id
+ ? {}
+ : {
+ 'data-track-extra': JSON.stringify({ title }),
+ }),
+ },
+ };
+ };
+
acc.push({
text: menuItem.title,
keywords: menuItem.title,
icon: menuItem.icon,
href: menuItem.link,
+ ...trackingAttrs(menuItem),
});
if (menuItem.items?.length) {
- const items = menuItem.items.map(({ title, link }) => ({
- keywords: title,
- text: [menuItem.title, title].join(' > '),
- href: link,
+ const items = menuItem.items.map((item) => ({
+ keywords: item.title,
+ text: [menuItem.title, item.title].join(' > '),
+ href: item.link,
icon: menuItem.icon,
+ ...trackingAttrs(item),
}));
/* eslint-disable-next-line no-param-reassign */
@@ -37,6 +58,10 @@ export const fileMapper = (projectBlobPath, file) => {
icon: 'doc-code',
text: file,
href: joinPaths(projectBlobPath, file),
+ extraAttrs: {
+ 'data-track-action': TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+ 'data-track-label': 'file',
+ },
};
};
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/components/frequent_items.vue b/app/assets/javascripts/super_sidebar/components/global_search/components/frequent_items.vue
index 382d844ceee..ddadd6856ca 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/components/frequent_items.vue
+++ b/app/assets/javascripts/super_sidebar/components/global_search/components/frequent_items.vue
@@ -2,6 +2,8 @@
import { GlDisclosureDropdownGroup, GlDisclosureDropdownItem, GlIcon } from '@gitlab/ui';
import { truncateNamespace } from '~/lib/utils/text_utility';
import { getItemsFromLocalStorage, removeItemFromLocalStorage } from '~/super_sidebar/utils';
+import { TRACKING_UNKNOWN_PANEL } from '~/super_sidebar/constants';
+import { TRACKING_CLICK_COMMAND_PALETTE_ITEM } from '../command_palette/constants';
import FrequentItem from './frequent_item.vue';
export default {
@@ -65,6 +67,12 @@ export default {
// validator, and the href field ensures it renders a link.
text: item.name,
href: item.webUrl,
+ extraAttrs: {
+ 'data-track-action': TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+ 'data-track-label': item.id,
+ 'data-track-property': TRACKING_UNKNOWN_PANEL,
+ 'data-track-extra': JSON.stringify({ title: item.name }),
+ },
},
forRenderer: {
id: item.id,
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue
index b64f3ac52b2..4cfc329f8b8 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue
+++ b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue
@@ -18,14 +18,12 @@ import { sprintf } from '~/locale';
import { ARROW_DOWN_KEY, ARROW_UP_KEY, END_KEY, HOME_KEY, ESC_KEY } from '~/lib/utils/keys';
import {
MIN_SEARCH_TERM,
- SEARCH_GITLAB,
SEARCH_DESCRIBED_BY_WITH_RESULTS,
SEARCH_DESCRIBED_BY_DEFAULT,
SEARCH_DESCRIBED_BY_UPDATED,
SEARCH_RESULTS_LOADING,
SEARCH_RESULTS_SCOPE,
} from '~/vue_shared/global_search/constants';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { darkModeEnabled } from '~/lib/utils/color_utils';
import {
SEARCH_INPUT_DESCRIPTION,
@@ -52,10 +50,10 @@ export default {
name: 'GlobalSearchModal',
SEARCH_MODAL_ID,
i18n: {
- SEARCH_GITLAB,
SEARCH_DESCRIBED_BY_WITH_RESULTS,
SEARCH_DESCRIBED_BY_DEFAULT,
SEARCH_DESCRIBED_BY_UPDATED,
+ SEARCH_OR_COMMAND_MODE_PLACEHOLDER,
SEARCH_RESULTS_LOADING,
SEARCH_RESULTS_SCOPE,
MIN_SEARCH_TERM,
@@ -72,7 +70,6 @@ export default {
CommandPaletteItems,
FakeSearchInput,
},
- mixins: [glFeatureFlagMixin()],
data() {
return {
nextFocusedItemIndex: null,
@@ -89,9 +86,6 @@ export default {
this.setSearch(value);
},
},
- searchPlaceholder() {
- return this.glFeatures?.commandPalette ? SEARCH_OR_COMMAND_MODE_PLACEHOLDER : SEARCH_GITLAB;
- },
showDefaultItems() {
return !this.searchText;
},
@@ -146,9 +140,8 @@ export default {
},
isCommandMode() {
return (
- this.glFeatures?.commandPalette &&
- (COMMON_HANDLES.includes(this.searchTextFirstChar) ||
- (this.searchContext.project && this.searchTextFirstChar === PATH_HANDLE))
+ COMMON_HANDLES.includes(this.searchTextFirstChar) ||
+ (this.searchContext?.project && this.searchTextFirstChar === PATH_HANDLE)
);
},
commandPaletteQuery() {
@@ -294,7 +287,7 @@ export default {
>
<form
role="search"
- :aria-label="searchPlaceholder"
+ :aria-label="$options.i18n.SEARCH_OR_COMMAND_MODE_PLACEHOLDER"
class="gl-relative gl-rounded-base gl-w-full gl-pb-0"
>
<div class="gl-relative gl-bg-white gl-border-b gl-mb-n1 gl-p-3">
@@ -305,7 +298,7 @@ export default {
role="searchbox"
data-testid="global-search-input"
autocomplete="off"
- :placeholder="searchPlaceholder"
+ :placeholder="$options.i18n.SEARCH_OR_COMMAND_MODE_PLACEHOLDER"
:aria-describedby="$options.SEARCH_INPUT_DESCRIPTION"
borderless
@input="getAutocompleteOptions"
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_places.vue b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_places.vue
index 9a375837102..9167be5c1cc 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_places.vue
+++ b/app/assets/javascripts/super_sidebar/components/global_search/components/global_search_default_places.vue
@@ -1,6 +1,8 @@
<script>
import { GlDisclosureDropdownGroup } from '@gitlab/ui';
import { PLACES } from '~/vue_shared/global_search/constants';
+import { TRACKING_UNKNOWN_ID, TRACKING_UNKNOWN_PANEL } from '~/super_sidebar/constants';
+import { TRACKING_CLICK_COMMAND_PALETTE_ITEM } from '../command_palette/constants';
export default {
name: 'DefaultPlaces',
@@ -18,7 +20,23 @@ export default {
group() {
return {
name: this.$options.i18n.PLACES,
- items: this.contextSwitcherLinks.map(({ title, link }) => ({ text: title, href: link })),
+ items: this.contextSwitcherLinks.map(({ title, link }) => ({
+ text: title,
+ href: link,
+ extraAttrs: {
+ 'data-track-action': TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+ // The label and property are hard-coded as unknown for now for
+ // parity with the existing corresponding context switcher items.
+ // Once the context switcher is removed, these can be changed.
+ 'data-track-label': TRACKING_UNKNOWN_ID,
+ 'data-track-property': TRACKING_UNKNOWN_PANEL,
+ 'data-track-extra': JSON.stringify({ title }),
+
+ // QA attributes
+ 'data-testid': 'places-item-link',
+ 'data-qa-places-item': title,
+ },
+ })),
};
},
},
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js b/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js
index 6871dabc9a1..79be56f1427 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js
+++ b/app/assets/javascripts/super_sidebar/components/global_search/store/getters.js
@@ -14,6 +14,7 @@ import {
SEARCH_RESULTS_ORDER,
} from '~/vue_shared/global_search/constants';
import { getFormattedItem } from '../utils';
+import { TRACKING_CLICK_COMMAND_PALETTE_ITEM } from '../command_palette/constants';
import {
ICON_GROUP,
@@ -172,6 +173,10 @@ export const scopedSearchOptions = (state, getters) => {
scopeCategory: PROJECTS_CATEGORY,
icon: ICON_PROJECT,
href: getters.projectUrl,
+ extraAttrs: {
+ 'data-track-action': TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+ 'data-track-label': 'scoped_in_project',
+ },
});
}
@@ -182,6 +187,10 @@ export const scopedSearchOptions = (state, getters) => {
scopeCategory: GROUPS_CATEGORY,
icon: state.searchContext.group?.full_name?.includes('/') ? ICON_SUBGROUP : ICON_GROUP,
href: getters.groupUrl,
+ extraAttrs: {
+ 'data-track-action': TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+ 'data-track-label': 'scoped_in_group',
+ },
});
}
@@ -189,6 +198,10 @@ export const scopedSearchOptions = (state, getters) => {
text: 'scoped-in-all',
description: MSG_IN_ALL_GITLAB,
href: getters.allUrl,
+ extraAttrs: {
+ 'data-track-action': TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+ 'data-track-label': 'scoped_in_all',
+ },
});
return items;
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/utils.js b/app/assets/javascripts/super_sidebar/components/global_search/utils.js
index 11d1fa1ab95..2c369cbdf5f 100644
--- a/app/assets/javascripts/super_sidebar/components/global_search/utils.js
+++ b/app/assets/javascripts/super_sidebar/components/global_search/utils.js
@@ -1,5 +1,5 @@
import { pickBy } from 'lodash';
-import { truncateNamespace } from '~/lib/utils/text_utility';
+import { slugify, truncateNamespace } from '~/lib/utils/text_utility';
import {
GROUPS_CATEGORY,
PROJECTS_CATEGORY,
@@ -7,6 +7,7 @@ import {
ISSUES_CATEGORY,
RECENT_EPICS_CATEGORY,
} from '~/vue_shared/global_search/constants';
+import { TRACKING_CLICK_COMMAND_PALETTE_ITEM } from './command_palette/constants';
import { LARGE_AVATAR_PX, SMALL_AVATAR_PX } from './constants';
const getTruncatedNamespace = (string) => {
@@ -61,6 +62,15 @@ export const getFormattedItem = (item, searchContext) => {
const avatarSize = getAvatarSize(category);
const entityId = getEntityId(item, searchContext);
const entityName = getEntityName(item, searchContext);
+ const trackingLabel = slugify(category ?? '');
+ const trackingAttrs = trackingLabel
+ ? {
+ extraAttrs: {
+ 'data-track-action': TRACKING_CLICK_COMMAND_PALETTE_ITEM,
+ 'data-track-label': slugify(category, '_'),
+ },
+ }
+ : {};
return pickBy(
{
@@ -75,6 +85,7 @@ export const getFormattedItem = (item, searchContext) => {
namespace,
entity_id: entityId,
entity_name: entityName,
+ ...trackingAttrs,
},
(val) => val !== undefined,
);
diff --git a/app/assets/javascripts/super_sidebar/components/groups_list.vue b/app/assets/javascripts/super_sidebar/components/groups_list.vue
deleted file mode 100644
index 48becacebb7..00000000000
--- a/app/assets/javascripts/super_sidebar/components/groups_list.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-<script>
-import { s__ } from '~/locale';
-import { MAX_FREQUENT_GROUPS_COUNT } from '../constants';
-import FrequentItemsList from './frequent_items_list.vue';
-import SearchResults from './search_results.vue';
-import NavItem from './nav_item.vue';
-
-export default {
- MAX_FREQUENT_GROUPS_COUNT,
- components: {
- FrequentItemsList,
- SearchResults,
- NavItem,
- },
- props: {
- username: {
- type: String,
- required: true,
- },
- viewAllLink: {
- type: String,
- required: true,
- },
- isSearch: {
- type: Boolean,
- required: false,
- default: false,
- },
- searchResults: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- computed: {
- storageKey() {
- return `${this.username}/frequent-groups`;
- },
- viewAllProps() {
- return {
- item: {
- link: this.viewAllLink,
- title: s__('Navigation|View all your groups'),
- icon: 'group',
- },
- linkClasses: { 'dashboard-shortcuts-groups': true },
- };
- },
- },
- i18n: {
- title: s__('Navigation|Frequently visited groups'),
- searchTitle: s__('Navigation|Groups'),
- pristineText: s__('Navigation|Groups you visit often will appear here.'),
- noResultsText: s__('Navigation|No group matches found'),
- },
-};
-</script>
-
-<template>
- <search-results
- v-if="isSearch"
- :title="$options.i18n.searchTitle"
- :no-results-text="$options.i18n.noResultsText"
- :search-results="searchResults"
- >
- <template #view-all-items>
- <nav-item v-bind="viewAllProps" is-subitem />
- </template>
- </search-results>
- <frequent-items-list
- v-else
- :title="$options.i18n.title"
- :storage-key="storageKey"
- :max-items="$options.MAX_FREQUENT_GROUPS_COUNT"
- :pristine-text="$options.i18n.pristineText"
- >
- <template #view-all-items>
- <nav-item v-bind="viewAllProps" is-subitem />
- </template>
- </frequent-items-list>
-</template>
diff --git a/app/assets/javascripts/super_sidebar/components/items_list.vue b/app/assets/javascripts/super_sidebar/components/items_list.vue
deleted file mode 100644
index 1bad13f91e8..00000000000
--- a/app/assets/javascripts/super_sidebar/components/items_list.vue
+++ /dev/null
@@ -1,44 +0,0 @@
-<script>
-import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
-import NavItem from './nav_item.vue';
-
-export default {
- components: {
- ProjectAvatar,
- NavItem,
- },
- props: {
- items: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
-};
-</script>
-
-<template>
- <ul class="gl-p-0 gl-list-style-none">
- <nav-item
- v-for="item in items"
- :key="item.id"
- :item="item"
- is-subitem
- class="show-on-focus-or-hover--context"
- >
- <template #icon>
- <project-avatar
- :project-id="item.id"
- :project-name="item.title"
- :project-avatar-url="item.avatar"
- :size="24"
- aria-hidden="true"
- />
- </template>
- <template #actions>
- <slot name="actions" :item="item"></slot>
- </template>
- </nav-item>
- <slot name="view-all-items"></slot>
- </ul>
-</template>
diff --git a/app/assets/javascripts/super_sidebar/components/menu_section.vue b/app/assets/javascripts/super_sidebar/components/menu_section.vue
index d2d45ca7b6e..6b5002e1aa8 100644
--- a/app/assets/javascripts/super_sidebar/components/menu_section.vue
+++ b/app/assets/javascripts/super_sidebar/components/menu_section.vue
@@ -79,15 +79,26 @@ export default {
isExpanded(newIsExpanded) {
this.$emit('collapse-toggle', newIsExpanded);
this.keepFlyoutClosed = !this.newIsExpanded;
+ if (!newIsExpanded) {
+ this.isMouseOverFlyout = false;
+ }
},
},
methods: {
handlePointerover(e) {
+ if (!this.hasFlyout) return;
+
this.isMouseOverSection = e.pointerType === 'mouse';
},
handlePointerleave() {
- this.isMouseOverSection = false;
+ if (!this.hasFlyout) return;
+
this.keepFlyoutClosed = false;
+ // delay state change. otherwise the flyout menu gets removed before it
+ // has a chance to emit its mouseover event.
+ setTimeout(() => {
+ this.isMouseOverSection = false;
+ }, 5);
},
},
};
@@ -129,8 +140,7 @@ export default {
</button>
<flyout-menu
- v-if="hasFlyout"
- v-show="isMouseOver && !isExpanded && !keepFlyoutClosed"
+ v-if="hasFlyout && isMouseOver && !isExpanded && !keepFlyoutClosed && item.items.length > 0"
:target-id="`menu-section-button-${itemId}`"
:items="item.items"
@mouseover="isMouseOverFlyout = true"
diff --git a/app/assets/javascripts/super_sidebar/components/nav_item.vue b/app/assets/javascripts/super_sidebar/components/nav_item.vue
index 36803a885e7..5e0f8fffb0e 100644
--- a/app/assets/javascripts/super_sidebar/components/nav_item.vue
+++ b/app/assets/javascripts/super_sidebar/components/nav_item.vue
@@ -1,6 +1,6 @@
<script>
-import { GlButton, GlIcon, GlBadge, GlTooltipDirective } from '@gitlab/ui';
-import { s__ } from '~/locale';
+import { GlAvatar, GlButton, GlIcon, GlBadge, GlTooltipDirective } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
import {
CLICK_MENU_ITEM_ACTION,
CLICK_PINNED_MENU_ITEM_ACTION,
@@ -12,11 +12,14 @@ import NavItemRouterLink from './nav_item_router_link.vue';
export default {
i18n: {
+ pin: s__('Navigation|Pin %{title}'),
pinItem: s__('Navigation|Pin item'),
+ unpin: s__('Navigation|Unpin %{title}'),
unpinItem: s__('Navigation|Unpin item'),
},
name: 'NavItem',
components: {
+ GlAvatar,
GlButton,
GlIcon,
GlBadge,
@@ -62,6 +65,12 @@ export default {
default: false,
},
},
+ data() {
+ return {
+ isMouseIn: false,
+ canClickPinButton: false,
+ };
+ },
computed: {
pillData() {
return this.item.pill_count;
@@ -96,12 +105,27 @@ export default {
...extraData,
};
},
+ /**
+ * Some QA specs rely on a stable "Project overview"/"Group overview" nav
+ * item data-qa-submenu-item attribute value.
+ *
+ * This computed ensures that those particular nav items use the `id` of
+ * the item rather than its title for that QA attribute.
+ *
+ * In future, probably all nav items should do this, for consistency.
+ * See https://gitlab.com/gitlab-org/gitlab/-/issues/422925.
+ */
+ qaSubMenuItem() {
+ const { id } = this.item;
+ if (id === 'project_overview' || id === 'group_overview') return id.replace(/_/g, '-');
+ return this.item.title;
+ },
linkProps() {
return {
...this.$attrs,
...this.trackingProps,
item: this.item,
- 'data-qa-submenu-item': this.item.title,
+ 'data-qa-submenu-item': this.qaSubMenuItem,
'data-method': this.item.data_method ?? null,
};
},
@@ -118,26 +142,73 @@ export default {
navItemLinkComponent() {
return this.item.to ? NavItemRouterLink : NavItemLink;
},
+ hasAvatar() {
+ return Boolean(this.item.entity_id);
+ },
+ avatarShape() {
+ return this.item.avatar_shape || 'rect';
+ },
+ pinAriaLabel() {
+ return sprintf(this.$options.i18n.pin, {
+ title: this.item.title,
+ });
+ },
+ unpinAriaLabel() {
+ return sprintf(this.$options.i18n.unpin, {
+ title: this.item.title,
+ });
+ },
+ activeIndicatorStyle() {
+ const style = {
+ width: '3px',
+ borderRadius: '3px',
+ marginRight: '1px',
+ };
+
+ // The active indicator is too close to the avatar for items with one, so shift
+ // it left by 1px.
+ //
+ // The indicator is absolutely positioned using rem units. This tweak for this
+ // edge case is in pixel units, so that it does not scale with root font size.
+ if (this.hasAvatar) style.transform = 'translateX(-1px)';
+
+ return style;
+ },
+ },
+ mounted() {
+ if (this.item.is_active) {
+ this.$el.scrollIntoView(false);
+ }
+ },
+ methods: {
+ togglePointerEvents() {
+ this.canClickPinButton = this.isMouseIn;
+ },
},
};
</script>
<template>
- <li>
+ <li
+ class="gl-relative show-on-focus-or-hover--context hide-on-focus-or-hover--context transition-opacity-on-hover--context"
+ data-testid="nav-item"
+ @mouseenter="isMouseIn = true"
+ @mouseleave="isMouseIn = false"
+ >
<component
:is="navItemLinkComponent"
#default="{ isActive }"
v-bind="linkProps"
- class="nav-item-link gl-relative gl-display-flex gl-align-items-center gl-min-h-7 gl-gap-3 gl-mb-1 gl-py-2 gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-text-decoration-none! gl-focus--focus show-on-focus-or-hover--context"
+ class="gl-relative gl-display-flex gl-align-items-center gl-min-h-7 gl-gap-3 gl-mb-1 gl-py-2 gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-text-decoration-none! gl-focus--focus show-on-focus-or-hover--control hide-on-focus-or-hover--control"
:class="computedLinkClasses"
- data-qa-selector="nav_item_link"
data-testid="nav-item-link"
+ data-qa-selector="nav_item_link"
>
<div
:class="[isActive ? 'gl-opacity-10' : 'gl-opacity-0']"
class="active-indicator gl-bg-blue-500 gl-absolute gl-left-2 gl-top-2 gl-bottom-2 gl-transition-slow"
aria-hidden="true"
- style="width: 3px; border-radius: 3px; margin-right: 1px"
+ :style="activeIndicatorStyle"
data-testid="active-indicator"
></div>
<div v-if="!isFlyout" class="gl-flex-shrink-0 gl-w-6 gl-display-flex">
@@ -148,6 +219,14 @@ export default {
name="grip"
class="gl-m-auto gl-text-gray-400 js-draggable-icon gl-cursor-grab show-on-focus-or-hover--target"
/>
+ <gl-avatar
+ v-else-if="hasAvatar"
+ :size="24"
+ :shape="avatarShape"
+ :entity-name="item.title"
+ :entity-id="item.entity_id"
+ :src="item.avatar"
+ />
</slot>
</div>
<div class="gl-flex-grow-1 gl-text-gray-900 gl-truncate-end">
@@ -157,36 +236,47 @@ export default {
</div>
</div>
<slot name="actions"></slot>
- <span v-if="hasPill || isPinnable" class="gl-text-right gl-relative">
+ <span v-if="hasPill || isPinnable" class="gl-text-right gl-relative gl-min-w-8">
<gl-badge
v-if="hasPill"
size="sm"
variant="neutral"
- :class="{ 'nav-item-badge gl-absolute gl-right-0 gl-top-2': isPinnable }"
+ class="gl-bg-t-gray-a-08!"
+ :class="{
+ 'hide-on-focus-or-hover--target transition-opacity-on-hover--target': isPinnable,
+ }"
>
{{ pillData }}
</gl-badge>
- <gl-button
- v-if="isPinnable && !isPinned"
- v-gl-tooltip.noninteractive.ds500.right.viewport="$options.i18n.pinItem"
- size="small"
- category="tertiary"
- icon="thumbtack"
- class="show-on-focus-or-hover--target"
- :aria-label="$options.i18n.pinItem"
- @click.prevent="$emit('pin-add', item.id)"
- />
- <gl-button
- v-else-if="isPinnable && isPinned"
- v-gl-tooltip.noninteractive.ds500.right.viewport="$options.i18n.unpinItem"
- size="small"
- category="tertiary"
- :aria-label="$options.i18n.unpinItem"
- icon="thumbtack-solid"
- class="show-on-focus-or-hover--target"
- @click.prevent="$emit('pin-remove', item.id)"
- />
</span>
</component>
+ <template v-if="isPinnable">
+ <gl-button
+ v-if="isPinned"
+ v-gl-tooltip.noninteractive.right.viewport="$options.i18n.unpinItem"
+ :aria-label="unpinAriaLabel"
+ category="tertiary"
+ class="show-on-focus-or-hover--target transition-opacity-on-hover--target always-animate gl-absolute gl-right-3 gl-top-2"
+ :class="{ 'gl-pointer-events-none': !canClickPinButton }"
+ data-testid="nav-item-unpin"
+ icon="thumbtack-solid"
+ size="small"
+ @click="$emit('pin-remove', item.id)"
+ @transitionend="togglePointerEvents"
+ />
+ <gl-button
+ v-else
+ v-gl-tooltip.noninteractive.right.viewport="$options.i18n.pinItem"
+ :aria-label="pinAriaLabel"
+ category="tertiary"
+ class="show-on-focus-or-hover--target transition-opacity-on-hover--target always-animate gl-absolute gl-right-3 gl-top-2"
+ :class="{ 'gl-pointer-events-none': !canClickPinButton }"
+ data-testid="nav-item-pin"
+ icon="thumbtack"
+ size="small"
+ @click="$emit('pin-add', item.id)"
+ @transitionend="togglePointerEvents"
+ />
+ </template>
</li>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/pinned_section.vue b/app/assets/javascripts/super_sidebar/components/pinned_section.vue
index 1e2201fbdff..5da45b52bf4 100644
--- a/app/assets/javascripts/super_sidebar/components/pinned_section.vue
+++ b/app/assets/javascripts/super_sidebar/components/pinned_section.vue
@@ -6,6 +6,13 @@ import { SIDEBAR_PINS_EXPANDED_COOKIE, SIDEBAR_COOKIE_EXPIRATION } from '../cons
import MenuSection from './menu_section.vue';
import NavItem from './nav_item.vue';
+const AMBIGUOUS_SETTINGS = {
+ ci_cd: s__('Navigation|CI/CD settings'),
+ merge_request_settings: s__('Navigation|Merge requests settings'),
+ monitor: s__('Navigation|Monitor settings'),
+ repository: s__('Navigation|Repository settings'),
+};
+
export default {
i18n: {
pinned: s__('Navigation|Pinned'),
@@ -23,11 +30,6 @@ export default {
required: false,
default: () => [],
},
- separated: {
- type: Boolean,
- required: false,
- default: false,
- },
hasFlyout: {
type: Boolean,
required: false,
@@ -37,7 +39,7 @@ export default {
data() {
return {
expanded: getCookie(SIDEBAR_PINS_EXPANDED_COOKIE) !== 'false',
- draggableItems: this.items,
+ draggableItems: this.renameSettings(this.items),
};
},
computed: {
@@ -63,7 +65,7 @@ export default {
});
},
items(newItems) {
- this.draggableItems = newItems;
+ this.draggableItems = this.renameSettings(newItems);
},
},
methods: {
@@ -76,6 +78,15 @@ export default {
event.oldIndex < event.newIndex,
);
},
+ renameSettings(items) {
+ return items.map((i) => {
+ const title = AMBIGUOUS_SETTINGS[i.id] || i.title;
+ return { ...i, title };
+ });
+ },
+ onPinRemove(itemId) {
+ this.$emit('pin-remove', itemId);
+ },
},
};
</script>
@@ -84,10 +95,9 @@ export default {
<menu-section
:item="sectionItem"
:expanded="expanded"
- :separated="separated"
:has-flyout="hasFlyout"
@collapse-toggle="expanded = !expanded"
- @pin-remove="(itemId) => $emit('pin-remove', itemId)"
+ @pin-remove="onPinRemove"
>
<draggable
v-if="items.length > 0"
@@ -103,7 +113,7 @@ export default {
:key="item.id"
:item="item"
is-in-pinned-section
- @pin-remove="(itemId) => $emit('pin-remove', itemId)"
+ @pin-remove="onPinRemove"
/>
</draggable>
<li v-else class="gl-text-secondary gl-font-sm gl-py-3" style="margin-left: 2.5rem">
diff --git a/app/assets/javascripts/super_sidebar/components/projects_list.vue b/app/assets/javascripts/super_sidebar/components/projects_list.vue
deleted file mode 100644
index 8d1a5c825b5..00000000000
--- a/app/assets/javascripts/super_sidebar/components/projects_list.vue
+++ /dev/null
@@ -1,82 +0,0 @@
-<script>
-import { s__ } from '~/locale';
-import { MAX_FREQUENT_PROJECTS_COUNT } from '../constants';
-import FrequentItemsList from './frequent_items_list.vue';
-import SearchResults from './search_results.vue';
-import NavItem from './nav_item.vue';
-
-export default {
- MAX_FREQUENT_PROJECTS_COUNT,
- components: {
- FrequentItemsList,
- SearchResults,
- NavItem,
- },
- props: {
- username: {
- type: String,
- required: true,
- },
- viewAllLink: {
- type: String,
- required: true,
- },
- isSearch: {
- type: Boolean,
- required: false,
- default: false,
- },
- searchResults: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- computed: {
- storageKey() {
- return `${this.username}/frequent-projects`;
- },
- viewAllProps() {
- return {
- item: {
- link: this.viewAllLink,
- title: s__('Navigation|View all your projects'),
- icon: 'project',
- },
- linkClasses: { 'dashboard-shortcuts-projects': true },
- };
- },
- },
- i18n: {
- title: s__('Navigation|Frequently visited projects'),
- searchTitle: s__('Navigation|Projects'),
- pristineText: s__('Navigation|Projects you visit often will appear here.'),
- noResultsText: s__('Navigation|No project matches found'),
- },
-};
-</script>
-
-<template>
- <search-results
- v-if="isSearch"
- class="gl-border-t-0"
- :title="$options.i18n.searchTitle"
- :no-results-text="$options.i18n.noResultsText"
- :search-results="searchResults"
- >
- <template #view-all-items>
- <nav-item v-bind="viewAllProps" is-subitem />
- </template>
- </search-results>
- <frequent-items-list
- v-else
- :title="$options.i18n.title"
- :storage-key="storageKey"
- :max-items="$options.MAX_FREQUENT_PROJECTS_COUNT"
- :pristine-text="$options.i18n.pristineText"
- >
- <template #view-all-items>
- <nav-item v-bind="viewAllProps" is-subitem />
- </template>
- </frequent-items-list>
-</template>
diff --git a/app/assets/javascripts/super_sidebar/components/search_results.vue b/app/assets/javascripts/super_sidebar/components/search_results.vue
deleted file mode 100644
index ff933f341af..00000000000
--- a/app/assets/javascripts/super_sidebar/components/search_results.vue
+++ /dev/null
@@ -1,99 +0,0 @@
-<script>
-import { GlCollapse, GlCollapseToggleDirective, GlIcon } from '@gitlab/ui';
-import uniqueId from 'lodash/uniqueId';
-import ItemsList from './items_list.vue';
-
-export default {
- components: {
- GlCollapse,
- GlIcon,
- ItemsList,
- },
- directives: {
- CollapseToggle: GlCollapseToggleDirective,
- },
- props: {
- title: {
- type: String,
- required: true,
- },
- noResultsText: {
- type: String,
- required: true,
- },
- searchResults: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
- data() {
- return {
- expanded: true,
- };
- },
- computed: {
- isEmpty() {
- return !this.searchResults.length;
- },
- collapseIcon() {
- return this.expanded ? 'chevron-up' : 'chevron-down';
- },
- },
- created() {
- this.collapseId = uniqueId('expandable-section-');
- },
- buttonClasses: [
- // Reset user agent styles
- 'gl-appearance-none',
- 'gl-border-0',
- 'gl-bg-transparent',
- // Text styles
- 'gl-text-left',
- 'gl-text-transform-uppercase',
- 'gl-text-secondary',
- 'gl-font-weight-semibold',
- 'gl-font-xs',
- 'gl-line-height-12',
- 'gl-letter-spacing-06em',
- // Border
- 'gl-border-t',
- 'gl-border-gray-50',
- // Spacing
- 'gl-my-3',
- 'gl-pt-2',
- // Layout
- 'gl-display-flex',
- 'gl-justify-content-space-between',
- 'gl-align-items-center',
- ],
-};
-</script>
-
-<template>
- <li class="gl-border-t gl-border-gray-50">
- <button
- v-collapse-toggle="collapseId"
- :class="$options.buttonClasses"
- class="gl-mx-3"
- data-testid="search-results-toggle"
- >
- {{ title }}
- <gl-icon :name="collapseIcon" :size="16" />
- </button>
- <gl-collapse :id="collapseId" v-model="expanded">
- <div
- v-if="isEmpty"
- data-testid="empty-text"
- class="gl-text-gray-500 gl-font-sm gl-mb-3 gl-mx-4"
- >
- {{ noResultsText }}
- </div>
- <items-list :aria-label="title" :items="searchResults">
- <template #view-all-items>
- <slot name="view-all-items"></slot>
- </template>
- </items-list>
- </gl-collapse>
- </li>
-</template>
diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_hover_peek_behavior.vue b/app/assets/javascripts/super_sidebar/components/sidebar_hover_peek_behavior.vue
new file mode 100644
index 00000000000..df432a1928a
--- /dev/null
+++ b/app/assets/javascripts/super_sidebar/components/sidebar_hover_peek_behavior.vue
@@ -0,0 +1,126 @@
+<script>
+import { getCssClassDimensions } from '~/lib/utils/css_utils';
+import Tracking from '~/tracking';
+import {
+ JS_TOGGLE_EXPAND_CLASS,
+ SUPER_SIDEBAR_PEEK_OPEN_DELAY,
+ SUPER_SIDEBAR_PEEK_CLOSE_DELAY,
+ SUPER_SIDEBAR_PEEK_STATE_CLOSED as STATE_CLOSED,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_OPEN as STATE_WILL_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_OPEN as STATE_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_CLOSE as STATE_WILL_CLOSE,
+} from '../constants';
+
+export default {
+ name: 'SidebarHoverPeek',
+ mixins: [Tracking.mixin()],
+ props: {
+ isMouseOverSidebar: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ created() {
+ // Nothing needs to observe these properties, so they are not reactive.
+ this.state = null;
+ this.openTimer = null;
+ this.closeTimer = null;
+ this.xSidebarEdge = null;
+ this.isMouseWithinSidebarArea = false;
+ },
+ async mounted() {
+ await this.$nextTick();
+ this.xSidebarEdge = getCssClassDimensions('super-sidebar').width;
+ document.addEventListener('mousemove', this.onMouseMove);
+ document.documentElement.addEventListener('mouseleave', this.onDocumentLeave);
+ document
+ .querySelector(`.${JS_TOGGLE_EXPAND_CLASS}`)
+ .addEventListener('mouseenter', this.onMouseEnter);
+ document
+ .querySelector(`.${JS_TOGGLE_EXPAND_CLASS}`)
+ .addEventListener('mouseleave', this.onMouseLeave);
+ this.changeState(STATE_CLOSED);
+ },
+ beforeDestroy() {
+ document.removeEventListener('mousemove', this.onMouseMove);
+ document.documentElement.removeEventListener('mouseleave', this.onDocumentLeave);
+ document
+ .querySelector(`.${JS_TOGGLE_EXPAND_CLASS}`)
+ .removeEventListener('mouseenter', this.onMouseEnter);
+ document
+ .querySelector(`.${JS_TOGGLE_EXPAND_CLASS}`)
+ .removeEventListener('mouseleave', this.onMouseLeave);
+ this.clearTimers();
+ },
+ methods: {
+ onMouseMove({ clientX }) {
+ if (clientX < this.xSidebarEdge) {
+ this.isMouseWithinSidebarArea = true;
+ } else {
+ this.isMouseWithinSidebarArea = false;
+ if (!this.isMouseOverSidebar && this.state === STATE_OPEN) {
+ this.willClose();
+ }
+ }
+ },
+ onDocumentLeave() {
+ this.isMouseWithinSidebarArea = false;
+ if (this.state === STATE_OPEN) {
+ this.willClose();
+ } else if (this.state === STATE_WILL_OPEN) {
+ this.close();
+ }
+ },
+ onMouseEnter() {
+ clearTimeout(this.closeTimer);
+ this.willOpen();
+ },
+ onMouseLeave() {
+ clearTimeout(this.openTimer);
+ if (this.isMouseWithinSidebarArea || this.isMouseOverSidebar) return;
+ this.willClose();
+ },
+ willClose() {
+ this.changeState(STATE_WILL_CLOSE);
+ this.closeTimer = setTimeout(this.close, SUPER_SIDEBAR_PEEK_CLOSE_DELAY);
+ },
+ willOpen() {
+ this.changeState(STATE_WILL_OPEN);
+ this.openTimer = setTimeout(this.open, SUPER_SIDEBAR_PEEK_OPEN_DELAY);
+ },
+ open() {
+ this.changeState(STATE_OPEN);
+ this.clearTimers();
+ this.track('nav_hover_peek', {
+ label: 'nav_sidebar_toggle',
+ property: 'nav_sidebar',
+ });
+ },
+ close() {
+ if (this.isMouseWithinSidebarArea) return;
+ this.changeState(STATE_CLOSED);
+ this.clearTimers();
+ },
+ clearTimers() {
+ clearTimeout(this.closeTimer);
+ clearTimeout(this.openTimer);
+ },
+ /**
+ * Switches to the new state, and emits a change event.
+ *
+ * If the given state is the current state, do nothing.
+ *
+ * @param {string} state The state to transition to.
+ */
+ changeState(state) {
+ if (this.state === state) return;
+ this.state = state;
+ this.$emit('change', state);
+ },
+ },
+ render() {
+ return null;
+ },
+};
+</script>
diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue b/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue
index 821b9dbcb7b..02488e99c0e 100644
--- a/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue
@@ -2,7 +2,6 @@
import * as Sentry from '@sentry/browser';
import { GlBreakpointInstance, breakpoints } from '@gitlab/ui/dist/utils';
import axios from '~/lib/utils/axios_utils';
-import { s__ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { PANELS_WITH_PINS } from '../constants';
import NavItem from './nav_item.vue';
@@ -51,10 +50,6 @@ export default {
},
},
- i18n: {
- mainNavigation: s__('Navigation|Main navigation'),
- },
-
data() {
return {
showFlyoutMenus: false,
@@ -109,10 +104,8 @@ export default {
},
},
mounted() {
- if (this.glFeatures.superSidebarFlyoutMenus) {
- this.decideFlyoutState();
- window.addEventListener('resize', this.decideFlyoutState);
- }
+ this.decideFlyoutState();
+ window.addEventListener('resize', this.decideFlyoutState);
},
beforeDestroy() {
window.removeEventListener('resize', this.decideFlyoutState);
@@ -164,13 +157,12 @@ export default {
</script>
<template>
- <nav :aria-label="$options.i18n.mainNavigation" class="gl-p-2 gl-relative">
+ <div class="gl-p-2 gl-relative">
<ul v-if="hasStaticItems" class="gl-p-0 gl-m-0" data-testid="static-items-section">
<nav-item v-for="item in staticItems" :key="item.id" :item="item" is-static />
</ul>
<pinned-section
v-if="supportsPins"
- separated
:items="pinnedItems"
:has-flyout="showFlyoutMenus"
@pin-remove="destroyPin"
@@ -203,5 +195,5 @@ export default {
/>
</template>
</ul>
- </nav>
+ </div>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue b/app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue
index ec728b4af9e..a20e37b945a 100644
--- a/app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue
+++ b/app/assets/javascripts/super_sidebar/components/sidebar_peek_behavior.vue
@@ -1,12 +1,14 @@
<script>
import { getCssClassDimensions } from '~/lib/utils/css_utils';
import Tracking from '~/tracking';
-import { SUPER_SIDEBAR_PEEK_OPEN_DELAY, SUPER_SIDEBAR_PEEK_CLOSE_DELAY } from '../constants';
-
-export const STATE_CLOSED = 'closed';
-export const STATE_WILL_OPEN = 'will-open';
-export const STATE_OPEN = 'open';
-export const STATE_WILL_CLOSE = 'will-close';
+import {
+ SUPER_SIDEBAR_PEEK_OPEN_DELAY,
+ SUPER_SIDEBAR_PEEK_CLOSE_DELAY,
+ SUPER_SIDEBAR_PEEK_STATE_CLOSED as STATE_CLOSED,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_OPEN as STATE_WILL_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_OPEN as STATE_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_CLOSE as STATE_WILL_CLOSE,
+} from '../constants';
export default {
name: 'SidebarPeek',
diff --git a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
index 29a3147e949..fe3e4a8199e 100644
--- a/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
+++ b/app/assets/javascripts/super_sidebar/components/super_sidebar.vue
@@ -2,27 +2,31 @@
import { GlButton } from '@gitlab/ui';
import { Mousetrap } from '~/lib/mousetrap';
import { keysFor, TOGGLE_SUPER_SIDEBAR } from '~/behaviors/shortcuts/keybindings';
-import { __ } from '~/locale';
+import { __, s__ } from '~/locale';
import Tracking from '~/tracking';
-import { sidebarState } from '../constants';
+import {
+ sidebarState,
+ SUPER_SIDEBAR_PEEK_STATE_CLOSED as STATE_CLOSED,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_OPEN as STATE_WILL_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_OPEN as STATE_OPEN,
+} from '../constants';
import { isCollapsed, toggleSuperSidebarCollapsed } from '../super_sidebar_collapsed_state_manager';
+import { trackContextAccess } from '../utils';
import UserBar from './user_bar.vue';
import SidebarPortalTarget from './sidebar_portal_target.vue';
-import ContextHeader from './context_header.vue';
-import ContextSwitcher from './context_switcher.vue';
import HelpCenter from './help_center.vue';
import SidebarMenu from './sidebar_menu.vue';
-import SidebarPeekBehavior, { STATE_CLOSED, STATE_WILL_OPEN } from './sidebar_peek_behavior.vue';
+import SidebarPeekBehavior from './sidebar_peek_behavior.vue';
+import SidebarHoverPeekBehavior from './sidebar_hover_peek_behavior.vue';
export default {
components: {
GlButton,
UserBar,
- ContextHeader,
- ContextSwitcher,
HelpCenter,
SidebarMenu,
SidebarPeekBehavior,
+ SidebarHoverPeekBehavior,
SidebarPortalTarget,
TrialStatusWidget: () =>
import('ee_component/contextual_sidebar/components/trial_status_widget.vue'),
@@ -32,6 +36,7 @@ export default {
mixins: [Tracking.mixin()],
i18n: {
skipToMainContent: __('Skip to main content'),
+ primary: s__('Navigation|Primary'),
},
inject: ['showTrialStatusWidget'],
props: {
@@ -45,25 +50,34 @@ export default {
sidebarState,
showPeekHint: false,
isMouseover: false,
+ breakpoint: null,
};
},
computed: {
+ showOverlay() {
+ return this.sidebarState.isPeek || this.sidebarState.isHoverPeek;
+ },
menuItems() {
return this.sidebarData.current_menu_items || [];
},
peekClasses() {
return {
'super-sidebar-peek-hint': this.showPeekHint,
- 'super-sidebar-peek': this.sidebarState.isPeek,
+ 'super-sidebar-peek': this.showOverlay,
+ 'super-sidebar-has-peeked': this.sidebarState.hasPeeked,
};
},
},
- watch: {
- 'sidebarState.isCollapsed': function isCollapsedWatcher(newIsCollapsed) {
- if (newIsCollapsed && this.$refs['context-switcher']) {
- this.$refs['context-switcher'].close();
- }
- },
+ created() {
+ const {
+ is_logged_in: isLoggedIn,
+ current_context: currentContext,
+ username,
+ track_visits_path: trackVisitsPath,
+ } = this.sidebarData;
+ if (isLoggedIn && currentContext.namespace) {
+ trackContextAccess(username, currentContext, trackVisitsPath);
+ }
},
mounted() {
Mousetrap.bind(keysFor(TOGGLE_SUPER_SIDEBAR), this.toggleSidebar);
@@ -88,6 +102,7 @@ export default {
this.sidebarState.isCollapsed = true;
this.showPeekHint = false;
} else if (state === STATE_WILL_OPEN) {
+ this.sidebarState.hasPeeked = true;
this.sidebarState.isPeek = false;
this.sidebarState.isCollapsed = true;
this.showPeekHint = true;
@@ -97,8 +112,15 @@ export default {
this.showPeekHint = false;
}
},
- onContextSwitcherToggled(open) {
- this.sidebarState.contextSwitcherOpen = open;
+ onHoverPeekChange(state) {
+ if (state === STATE_OPEN) {
+ this.sidebarState.hasPeeked = true;
+ this.sidebarState.isHoverPeek = true;
+ this.sidebarState.isCollapsed = false;
+ } else if (state === STATE_CLOSED) {
+ this.sidebarState.isHoverPeek = false;
+ this.sidebarState.isCollapsed = true;
+ }
},
},
};
@@ -114,8 +136,9 @@ export default {
>
{{ $options.i18n.skipToMainContent }}
</gl-button>
- <aside
+ <nav
id="super-sidebar"
+ :aria-label="$options.i18n.primary"
class="super-sidebar"
:class="peekClasses"
data-testid="super-sidebar"
@@ -124,32 +147,23 @@ export default {
@mouseenter="isMouseover = true"
@mouseleave="isMouseover = false"
>
- <user-bar :has-collapse-button="!sidebarState.isPeek" :sidebar-data="sidebarData" />
+ <user-bar :has-collapse-button="!showOverlay" :sidebar-data="sidebarData" />
<div v-if="showTrialStatusWidget" class="gl-px-2 gl-py-2">
<trial-status-widget
- class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-mb-1 gl-px-3 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-text-decoration-none! nav-item-link gl-py-3"
+ class="gl-rounded-base gl-relative gl-display-flex gl-align-items-center gl-mb-1 gl-px-3 gl-line-height-normal gl-text-black-normal! gl-hover-bg-t-gray-a-08 gl-focus-bg-t-gray-a-08 gl-text-decoration-none! gl-py-3"
/>
<trial-status-popover />
</div>
<div
class="contextual-nav gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-overflow-hidden"
>
- <div
- class="gl-flex-grow-1"
- :class="{ 'gl-overflow-auto': !sidebarState.contextSwitcherOpen }"
- data-testid="nav-container"
- >
- <context-switcher
- v-if="sidebarData.is_logged_in"
- ref="context-switcher"
- :username="sidebarData.username"
- :projects-path="sidebarData.projects_path"
- :groups-path="sidebarData.groups_path"
- :current-context="sidebarData.current_context"
- :context-header="sidebarData.current_context_header"
- @toggle="onContextSwitcherToggled"
- />
- <context-header v-else :context="sidebarData.current_context_header" />
+ <div class="gl-flex-grow-1 gl-overflow-auto" data-testid="nav-container">
+ <h2
+ class="gl-px-5 gl-pt-3 gl-pb-2 gl-m-0 gl-reset-line-height gl-font-sm super-sidebar-context-header"
+ >
+ {{ sidebarData.current_context_header }}
+ </h2>
+
<sidebar-menu
v-if="menuItems.length"
:items="menuItems"
@@ -164,7 +178,7 @@ export default {
<help-center :sidebar-data="sidebarData" />
</div>
</div>
- </aside>
+ </nav>
<a
v-for="shortcutLink in sidebarData.shortcut_links"
:key="shortcutLink.href"
@@ -176,13 +190,18 @@ export default {
</a>
<!--
- Only mount SidebarPeekBehavior if the sidebar is peekable, to avoid
+ Only mount peek behavior components if the sidebar is peekable, to avoid
setting up event listeners unnecessarily.
-->
<sidebar-peek-behavior
- v-if="sidebarState.isPeekable"
+ v-if="sidebarState.isPeekable && !sidebarState.isHoverPeek"
:is-mouse-over-sidebar="isMouseover"
@change="onPeekChange"
/>
+ <sidebar-hover-peek-behavior
+ v-if="sidebarState.isPeekable && !sidebarState.isPeek"
+ :is-mouse-over-sidebar="isMouseover"
+ @change="onHoverPeekChange"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue b/app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue
index 7d5e87805d5..30ee18cc369 100644
--- a/app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue
+++ b/app/assets/javascripts/super_sidebar/components/super_sidebar_toggle.vue
@@ -27,19 +27,18 @@ export default {
},
i18n: {
collapseSidebar: __('Hide sidebar'),
- expandSidebar: __('Show sidebar'),
- navigationSidebar: __('Navigation sidebar'),
+ expandSidebar: __('Keep sidebar visible'),
+ primaryNavigationSidebar: __('Primary navigation sidebar'),
},
data() {
return sidebarState;
},
computed: {
+ canOpen() {
+ return this.isCollapsed || this.isPeek || this.isHoverPeek;
+ },
tooltipTitle() {
- if (this.isPeek) return '';
-
- return this.isCollapsed
- ? this.$options.i18n.expandSidebar
- : this.$options.i18n.collapseSidebar;
+ return this.canOpen ? this.$options.i18n.expandSidebar : this.$options.i18n.collapseSidebar;
},
tooltip() {
return {
@@ -49,21 +48,21 @@ export default {
};
},
ariaExpanded() {
- return String(!this.isCollapsed);
+ return String(!this.canOpen);
},
},
methods: {
toggle() {
- this.track(this.isCollapsed ? 'nav_show' : 'nav_hide', {
+ this.track(this.canOpen ? 'nav_show' : 'nav_hide', {
label: 'nav_toggle',
property: 'nav_sidebar',
});
- toggleSuperSidebarCollapsed(!this.isCollapsed, true);
+ toggleSuperSidebarCollapsed(!this.canOpen, true);
this.focusOtherToggle();
},
focusOtherToggle() {
this.$nextTick(() => {
- const classSelector = this.isCollapsed ? JS_TOGGLE_EXPAND_CLASS : JS_TOGGLE_COLLAPSE_CLASS;
+ const classSelector = this.canOpen ? JS_TOGGLE_EXPAND_CLASS : JS_TOGGLE_COLLAPSE_CLASS;
const otherToggle = document.querySelector(`.${classSelector}`);
otherToggle?.focus();
});
@@ -74,13 +73,12 @@ export default {
<template>
<gl-button
- v-gl-tooltip.hover.noninteractive.ds500="tooltip"
+ v-gl-tooltip.hover="tooltip"
aria-controls="super-sidebar"
:aria-expanded="ariaExpanded"
- :aria-label="$options.i18n.navigationSidebar"
+ :aria-label="$options.i18n.primaryNavigationSidebar"
icon="sidebar"
category="tertiary"
- :disabled="isPeek"
@click="toggle"
/>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_bar.vue b/app/assets/javascripts/super_sidebar/components/user_bar.vue
index b76ef91b768..49aee4f3470 100644
--- a/app/assets/javascripts/super_sidebar/components/user_bar.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_bar.vue
@@ -1,5 +1,5 @@
<script>
-import { GlBadge, GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
+import { GlBadge, GlButton, GlModalDirective, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { __, s__, sprintf } from '~/locale';
import {
destroyUserCountsManager,
@@ -34,20 +34,19 @@ export default {
),
SuperSidebarToggle,
BrandLogo,
+ GlIcon,
},
i18n: {
- createNew: __('Create new...'),
- homepage: __('Homepage'),
issues: __('Issues'),
mergeRequests: __('Merge requests'),
- search: __('Search'),
searchKbdHelp: sprintf(
- s__('GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}'),
+ s__('GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search'),
{ kbdOpen: '<kbd>', kbdClose: '</kbd>' },
false,
),
todoList: __('To-Do list'),
stopImpersonating: __('Stop impersonating'),
+ searchBtnText: __('Search or go to…'),
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -103,8 +102,14 @@ export default {
</script>
<template>
- <div class="user-bar">
- <div class="gl-display-flex gl-align-items-center gl-px-3 gl-py-2">
+ <div
+ class="user-bar gl-display-flex gl-p-3 gl-gap-1"
+ :class="{ 'gl-flex-direction-column gl-gap-3': sidebarData.is_logged_in }"
+ >
+ <div
+ v-if="hasCollapseButton || sidebarData.is_logged_in"
+ class="gl-display-flex gl-align-items-center gl-gap-1"
+ >
<template v-if="sidebarData.is_logged_in">
<brand-logo :logo-url="sidebarData.logo_url" />
<gl-badge
@@ -112,7 +117,6 @@ export default {
variant="success"
:href="sidebarData.canary_toggle_com_url"
size="sm"
- class="gl-ml-2"
>
{{ $options.NEXT_LABEL }}
</gl-badge>
@@ -126,24 +130,16 @@ export default {
tooltip-container="super-sidebar"
data-testid="super-sidebar-collapse-button"
/>
- <create-menu v-if="sidebarData.is_logged_in" :groups="sidebarData.create_new_menu_groups" />
-
- <gl-button
- id="super-sidebar-search"
- v-gl-tooltip.bottom.hover.noninteractive.ds500.html="searchTooltip"
- v-gl-modal="$options.SEARCH_MODAL_ID"
- data-testid="super-sidebar-search-button"
- icon="search"
- :aria-label="$options.i18n.search"
- category="tertiary"
+ <create-menu
+ v-if="sidebarData.is_logged_in && sidebarData.create_new_menu_groups.length > 0"
+ :groups="sidebarData.create_new_menu_groups"
/>
- <search-modal @shown="hideSearchTooltip" @hidden="showSearchTooltip" />
<user-menu v-if="sidebarData.is_logged_in" :data="sidebarData" />
<gl-button
v-if="isImpersonating"
- v-gl-tooltip.noninteractive.ds500.bottom
+ v-gl-tooltip.bottom
:href="sidebarData.stop_impersonation_path"
:title="$options.i18n.stopImpersonating"
:aria-label="$options.i18n.stopImpersonating"
@@ -155,10 +151,10 @@ export default {
</div>
<div
v-if="sidebarData.is_logged_in"
- class="gl-display-flex gl-justify-content-space-between gl-px-3 gl-py-2 gl-gap-2"
+ class="gl-display-flex gl-justify-content-space-between gl-gap-2"
>
<counter
- v-gl-tooltip:super-sidebar.hover.noninteractive.ds500.bottom="$options.i18n.issues"
+ v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.issues"
class="gl-flex-basis-third dashboard-shortcuts-issues"
icon="issues"
:count="userCounts.assigned_issues"
@@ -176,9 +172,7 @@ export default {
@hidden="mrMenuShown = false"
>
<counter
- v-gl-tooltip:super-sidebar.hover.noninteractive.ds500.bottom="
- mrMenuShown ? '' : $options.i18n.mergeRequests
- "
+ v-gl-tooltip:super-sidebar.hover.bottom="mrMenuShown ? '' : $options.i18n.mergeRequests"
class="gl-w-full"
icon="merge-request-open"
:count="mergeRequestTotalCount"
@@ -190,7 +184,7 @@ export default {
/>
</merge-request-menu>
<counter
- v-gl-tooltip:super-sidebar.hover.noninteractive.ds500.bottom="$options.i18n.todoList"
+ v-gl-tooltip:super-sidebar.hover.bottom="$options.i18n.todoList"
class="gl-flex-basis-third shortcuts-todos js-todos-count"
icon="todo-done"
:count="userCounts.todos"
@@ -202,5 +196,16 @@ export default {
data-track-property="nav_core_menu"
/>
</div>
+ <button
+ id="super-sidebar-search"
+ v-gl-tooltip.bottom.hover.html="searchTooltip"
+ v-gl-modal="$options.SEARCH_MODAL_ID"
+ class="counter gl-display-block gl-py-3 gl-bg-gray-10 gl-rounded-base gl-text-gray-900 gl-border-none gl-inset-border-1-gray-a-08 gl-line-height-1 gl-focus--focus gl-w-full"
+ data-testid="super-sidebar-search-button"
+ >
+ <gl-icon name="search" />
+ {{ $options.i18n.searchBtnText }}
+ </button>
+ <search-modal @shown="hideSearchTooltip" @hidden="showSearchTooltip" />
</div>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue
index 869f07520a2..ed6c41e85c6 100644
--- a/app/assets/javascripts/super_sidebar/components/user_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue
@@ -19,7 +19,6 @@ const DROPDOWN_X_OFFSET_BASE = -211;
const DROPDOWN_X_OFFSET_IMPERSONATING = DROPDOWN_X_OFFSET_BASE + IMPERSONATING_OFFSET;
export default {
- feedbackUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/409005',
i18n: {
newNavigation: {
sectionTitle: s__('NorthstarNavigation|Navigation redesign'),
@@ -31,7 +30,6 @@ export default {
buyPipelineMinutes: s__('CurrentUser|Buy Pipeline minutes'),
oneOfGroupsRunningOutOfPipelineMinutes: s__('CurrentUser|One of your groups is running out'),
gitlabNext: s__('CurrentUser|Switch to GitLab Next'),
- provideFeedback: s__('NorthstarNavigation|Provide feedback'),
startTrial: s__('CurrentUser|Start an Ultimate trial'),
signOut: __('Sign out'),
},
@@ -131,17 +129,6 @@ export default {
},
};
},
- feedbackItem() {
- return {
- text: this.$options.i18n.provideFeedback,
- href: this.$options.feedbackUrl,
- extraAttrs: {
- target: '_blank',
- ...USER_MENU_TRACKING_DEFAULTS,
- 'data-track-label': 'provide_nav_feedback',
- },
- };
- },
signOutGroup() {
return {
items: [
@@ -316,7 +303,6 @@ export default {
<span class="gl-font-sm">{{ $options.i18n.newNavigation.sectionTitle }}</span>
</template>
<new-nav-toggle :endpoint="toggleNewNavEndpoint" enabled new-navigation />
- <gl-disclosure-dropdown-item :item="feedbackItem" data-testid="feedback-item" />
</gl-disclosure-dropdown-group>
<gl-disclosure-dropdown-group
diff --git a/app/assets/javascripts/super_sidebar/components/user_name_group.vue b/app/assets/javascripts/super_sidebar/components/user_name_group.vue
index 13f19338610..3c8059387fa 100644
--- a/app/assets/javascripts/super_sidebar/components/user_name_group.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_name_group.vue
@@ -71,7 +71,7 @@ export default {
v-if="user.status.customized"
ref="statusTooltipTarget"
data-testid="user-menu-status"
- class="gl-display-flex gl-align-items-center gl-mt-2 gl-font-sm"
+ class="gl-display-flex gl-align-items-baseline gl-mt-2 gl-font-sm"
>
<gl-emoji :data-name="user.status.emoji" class="gl-mr-1" />
<span v-safe-html="user.status.message_html" class="gl-text-truncate"></span>
diff --git a/app/assets/javascripts/super_sidebar/constants.js b/app/assets/javascripts/super_sidebar/constants.js
index 757bf9c7459..77bd8b4a734 100644
--- a/app/assets/javascripts/super_sidebar/constants.js
+++ b/app/assets/javascripts/super_sidebar/constants.js
@@ -13,10 +13,12 @@ export const portalState = Vue.observable({
});
export const sidebarState = Vue.observable({
- contextSwitcherOpen: false,
isCollapsed: false,
+ hasPeeked: false,
isPeek: false,
isPeekable: false,
+ isHoverPeek: false,
+ wasHoverPeek: false,
});
export const helpCenterState = Vue.observable({
@@ -28,13 +30,17 @@ export const MAX_FREQUENT_GROUPS_COUNT = 3;
export const SUPER_SIDEBAR_PEEK_OPEN_DELAY = 200;
export const SUPER_SIDEBAR_PEEK_CLOSE_DELAY = 500;
+export const SUPER_SIDEBAR_PEEK_STATE_CLOSED = 'closed';
+export const SUPER_SIDEBAR_PEEK_STATE_WILL_OPEN = 'will-open';
+export const SUPER_SIDEBAR_PEEK_STATE_OPEN = 'open';
+export const SUPER_SIDEBAR_PEEK_STATE_WILL_CLOSE = 'will-close';
export const TRACKING_UNKNOWN_ID = 'item_without_id';
export const TRACKING_UNKNOWN_PANEL = 'nav_panel_unknown';
export const CLICK_MENU_ITEM_ACTION = 'click_menu_item';
export const CLICK_PINNED_MENU_ITEM_ACTION = 'click_pinned_menu_item';
-export const PANELS_WITH_PINS = ['group', 'project'];
+export const PANELS_WITH_PINS = ['group', 'project', 'organization'];
export const USER_MENU_TRACKING_DEFAULTS = {
'data-track-property': 'nav_user_menu',
diff --git a/app/assets/javascripts/super_sidebar/graphql/queries/search_user_groups_and_projects.query.graphql b/app/assets/javascripts/super_sidebar/graphql/queries/search_user_groups_and_projects.query.graphql
deleted file mode 100644
index 4b1e65be3fa..00000000000
--- a/app/assets/javascripts/super_sidebar/graphql/queries/search_user_groups_and_projects.query.graphql
+++ /dev/null
@@ -1,24 +0,0 @@
-query searchUserProjectsAndGroups($username: String!, $search: String) {
- projects(search: $search, sort: "latest_activity_desc", membership: true, first: 20) {
- nodes {
- id
- name
- namespace: nameWithNamespace
- webUrl
- avatarUrl
- }
- }
-
- user(username: $username) {
- id
- groups(search: $search, first: 20) {
- nodes {
- id
- name
- namespace: fullPath
- webUrl
- avatarUrl
- }
- }
- }
-}
diff --git a/app/assets/javascripts/super_sidebar/super_sidebar_bundle.js b/app/assets/javascripts/super_sidebar/super_sidebar_bundle.js
index 2b62e7a6ede..de16161efb5 100644
--- a/app/assets/javascripts/super_sidebar/super_sidebar_bundle.js
+++ b/app/assets/javascripts/super_sidebar/super_sidebar_bundle.js
@@ -1,6 +1,4 @@
import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createDefaultClient from '~/lib/graphql';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import { initStatusTriggers } from '../header';
import { JS_TOGGLE_EXPAND_CLASS } from './constants';
@@ -12,12 +10,6 @@ import {
import SuperSidebar from './components/super_sidebar.vue';
import SuperSidebarToggle from './components/super_sidebar_toggle.vue';
-Vue.use(VueApollo);
-
-const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
-});
-
const getTrialStatusWidgetData = (sidebarData) => {
if (sidebarData.trial_status_widget_data_attrs && sidebarData.trial_status_popover_data_attrs) {
const {
@@ -97,7 +89,6 @@ export const initSuperSidebar = () => {
return new Vue({
el,
name: 'SuperSidebarRoot',
- apolloProvider,
provide: {
rootPath,
toggleNewNavEndpoint,
diff --git a/app/assets/javascripts/super_sidebar/super_sidebar_collapsed_state_manager.js b/app/assets/javascripts/super_sidebar/super_sidebar_collapsed_state_manager.js
index feb7e274b07..9ee78a657b6 100644
--- a/app/assets/javascripts/super_sidebar/super_sidebar_collapsed_state_manager.js
+++ b/app/assets/javascripts/super_sidebar/super_sidebar_collapsed_state_manager.js
@@ -26,6 +26,9 @@ export const toggleSuperSidebarCollapsed = (collapsed, saveCookie) => {
sidebarState.isPeek = false;
sidebarState.isPeekable = collapsed;
+ sidebarState.hasPeeked = false;
+ sidebarState.isHoverPeek = false;
+ sidebarState.wasHoverPeek = false;
sidebarState.isCollapsed = collapsed;
if (saveCookie && isDesktopBreakpoint()) {
diff --git a/app/assets/javascripts/super_sidebar/utils.js b/app/assets/javascripts/super_sidebar/utils.js
index cbf93155fb6..97830a32d78 100644
--- a/app/assets/javascripts/super_sidebar/utils.js
+++ b/app/assets/javascripts/super_sidebar/utils.js
@@ -1,7 +1,7 @@
import * as Sentry from '@sentry/browser';
import AccessorUtilities from '~/lib/utils/accessor';
import { FREQUENT_ITEMS, FIFTEEN_MINUTES_IN_MS } from '~/frequent_items/constants';
-import { truncateNamespace } from '~/lib/utils/text_utility';
+import axios from '~/lib/utils/axios_utils';
/**
* This takes an array of project or groups that were stored in the local storage, to be shown in
@@ -18,7 +18,8 @@ const sortItemsByFrequencyAndLastAccess = (items) =>
// and then by lastAccessedOn with recent most first
if (itemA.frequency !== itemB.frequency) {
return itemB.frequency - itemA.frequency;
- } else if (itemA.lastAccessedOn !== itemB.lastAccessedOn) {
+ }
+ if (itemA.lastAccessedOn !== itemB.lastAccessedOn) {
return itemB.lastAccessedOn - itemA.lastAccessedOn;
}
@@ -36,11 +37,43 @@ export const getTopFrequentItems = (items, maxCount) => {
return frequentItems.slice(0, maxCount);
};
-const updateItemAccess = (contextItem, { lastAccessedOn, frequency = 0 } = {}) => {
+/**
+ * This tracks projects' and groups' visits in order to suggest a list of frequently visited
+ * entities to the user. Currently, this track visits in two ways:
+ * - The legacy approach uses a simple counting algorithm and stores the data in the local storage.
+ * - The above approach is being migrated to a backend-based one, where visits will be stored in the
+ * DB, and suggestions will be made through a smarter algorithm. When we are ready to transition
+ * to the newer approach, the legacy one will be cleaned up.
+ * @param {object} item The project/group item being tracked.
+ * @param {string} namespace A string indicating whether the tracked entity is a project or a group.
+ * @param {string} trackVisitsPath The API endpoint to track visits server-side.
+ * @returns {void}
+ */
+const updateItemAccess = (
+ contextItem,
+ { lastAccessedOn, frequency = 0 } = {},
+ namespace,
+ trackVisitsPath,
+) => {
const now = Date.now();
const neverAccessed = !lastAccessedOn;
const shouldUpdate = neverAccessed || Math.abs(now - lastAccessedOn) / FIFTEEN_MINUTES_IN_MS > 1;
+ if (shouldUpdate && gon.features?.serverSideFrecentNamespaces) {
+ try {
+ axios({
+ url: trackVisitsPath,
+ method: 'POST',
+ data: {
+ type: namespace,
+ id: contextItem.id,
+ },
+ });
+ } catch (e) {
+ Sentry.captureException(e);
+ }
+ }
+
return {
...contextItem,
frequency: shouldUpdate ? frequency + 1 : frequency,
@@ -48,7 +81,7 @@ const updateItemAccess = (contextItem, { lastAccessedOn, frequency = 0 } = {}) =
};
};
-export const trackContextAccess = (username, context) => {
+export const trackContextAccess = (username, context, trackVisitsPath) => {
if (!AccessorUtilities.canUseLocalStorage()) {
return false;
}
@@ -61,9 +94,19 @@ export const trackContextAccess = (username, context) => {
);
if (existingItemIndex > -1) {
- storedItems[existingItemIndex] = updateItemAccess(context.item, storedItems[existingItemIndex]);
+ storedItems[existingItemIndex] = updateItemAccess(
+ context.item,
+ storedItems[existingItemIndex],
+ context.namespace,
+ trackVisitsPath,
+ );
} else {
- const newItem = updateItemAccess(context.item);
+ const newItem = updateItemAccess(
+ context.item,
+ storedItems[existingItemIndex],
+ context.namespace,
+ trackVisitsPath,
+ );
if (storedItems.length === FREQUENT_ITEMS.MAX_COUNT) {
sortItemsByFrequencyAndLastAccess(storedItems);
storedItems.pop();
@@ -74,15 +117,6 @@ export const trackContextAccess = (username, context) => {
return localStorage.setItem(storageKey, JSON.stringify(storedItems));
};
-export const formatContextSwitcherItems = (items) =>
- items.map(({ id, name: title, namespace, avatarUrl: avatar, webUrl: link }) => ({
- id,
- title,
- subtitle: truncateNamespace(namespace),
- avatar,
- link,
- }));
-
export const getItemsFromLocalStorage = ({ storageKey, maxItems }) => {
if (!AccessorUtilities.canUseLocalStorage()) {
return [];
diff --git a/app/assets/javascripts/time_tracking/components/queries/get_timelogs.query.graphql b/app/assets/javascripts/time_tracking/components/queries/get_timelogs.query.graphql
index 3ba0ab29530..0de76e25d01 100644
--- a/app/assets/javascripts/time_tracking/components/queries/get_timelogs.query.graphql
+++ b/app/assets/javascripts/time_tracking/components/queries/get_timelogs.query.graphql
@@ -1,8 +1,8 @@
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query timeTrackingReport(
- $startDate: Time
- $endDate: Time
+ $startTime: Time
+ $endTime: Time
$projectId: ProjectID
$groupId: GroupID
$username: String
@@ -12,8 +12,8 @@ query timeTrackingReport(
$after: String
) {
timelogs(
- startDate: $startDate
- endDate: $endDate
+ startTime: $startTime
+ endTime: $endTime
projectId: $projectId
groupId: $groupId
username: $username
diff --git a/app/assets/javascripts/time_tracking/components/timelogs_app.vue b/app/assets/javascripts/time_tracking/components/timelogs_app.vue
index 2069e4a6722..7bb9b6c52a5 100644
--- a/app/assets/javascripts/time_tracking/components/timelogs_app.vue
+++ b/app/assets/javascripts/time_tracking/components/timelogs_app.vue
@@ -17,11 +17,11 @@ import TimelogsTable from './timelogs_table.vue';
const ENTRIES_PER_PAGE = 20;
// Define initial dates to current date and time
-const INITIAL_TO_DATE = new Date();
-const INITIAL_FROM_DATE = new Date();
+const INITIAL_TO_DATE_TIME = new Date(new Date().setHours(0, 0, 0, 0));
+const INITIAL_FROM_DATE_TIME = new Date(new Date().setHours(0, 0, 0, 0));
// Set the initial 'from' date to 30 days before the current date
-INITIAL_FROM_DATE.setDate(INITIAL_TO_DATE.getDate() - 30);
+INITIAL_FROM_DATE_TIME.setDate(INITIAL_TO_DATE_TIME.getDate() - 30);
export default {
components: {
@@ -45,8 +45,8 @@ export default {
projectId: null,
groupId: null,
username: null,
- timeSpentFrom: INITIAL_FROM_DATE,
- timeSpentTo: INITIAL_TO_DATE,
+ timeSpentFrom: INITIAL_FROM_DATE_TIME,
+ timeSpentTo: INITIAL_TO_DATE_TIME,
cursor: {
first: ENTRIES_PER_PAGE,
after: null,
@@ -54,8 +54,8 @@ export default {
before: null,
},
queryVariables: {
- startDate: INITIAL_FROM_DATE,
- endDate: INITIAL_TO_DATE,
+ startTime: INITIAL_FROM_DATE_TIME,
+ endTime: INITIAL_TO_DATE_TIME,
projectId: null,
groupId: null,
username: null,
@@ -108,9 +108,15 @@ export default {
before: null,
};
+ const { timeSpentTo } = this;
+
+ if (timeSpentTo) {
+ timeSpentTo.setDate(timeSpentTo.getDate() + 1);
+ }
+
this.queryVariables = {
- startDate: this.nullIfBlank(this.timeSpentFrom),
- endDate: this.nullIfBlank(this.timeSpentTo),
+ startTime: this.nullIfBlank(this.timeSpentFrom),
+ endTime: this.nullIfBlank(timeSpentTo),
projectId: this.nullIfBlank(this.projectId),
groupId: this.nullIfBlank(this.groupId),
username: this.nullIfBlank(this.username),
@@ -141,8 +147,8 @@ export default {
},
i18n: {
username: s__('TimeTrackingReport|Username'),
- from: s__('TimeTrackingReport|From'),
- to: s__('TimeTrackingReport|To'),
+ from: s__('TimeTrackingReport|From the start of'),
+ to: s__('TimeTrackingReport|To the end of'),
runReport: s__('TimeTrackingReport|Run report'),
totalTimeSpentText: s__('TimeTrackingReport|Total time spent: '),
},
diff --git a/app/assets/javascripts/token_access/components/outbound_token_access.vue b/app/assets/javascripts/token_access/components/outbound_token_access.vue
index 7e1e6cc445c..43aa9b94b3a 100644
--- a/app/assets/javascripts/token_access/components/outbound_token_access.vue
+++ b/app/assets/javascripts/token_access/components/outbound_token_access.vue
@@ -27,7 +27,7 @@ export default {
'CICD|Limit access %{italicStart}from%{italicEnd} this project (Deprecated)',
),
toggleHelpText: s__(
- `CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}`,
+ `CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}.`,
),
cardHeaderTitle: s__('CICD|Add an existing project to the scope'),
settingDisabledMessage: s__(
@@ -258,12 +258,12 @@ export default {
<template #help>
<gl-sprintf :message="$options.i18n.toggleHelpText">
<template #link="{ content }">
- <gl-link :href="ciJobTokenHelpPage" class="inline-link" target="_blank">
- {{ content }}
- </gl-link>
- <strong>{{ $options.i18n.disableToggleWarning }} </strong>
+ <gl-link :href="ciJobTokenHelpPage" class="inline-link" target="_blank">{{
+ content
+ }}</gl-link>
</template>
</gl-sprintf>
+ <strong>{{ $options.i18n.disableToggleWarning }} </strong>
</template>
</gl-toggle>
diff --git a/app/assets/javascripts/tracing/components/tracing_details.vue b/app/assets/javascripts/tracing/components/tracing_details.vue
deleted file mode 100644
index d8b2cbc9469..00000000000
--- a/app/assets/javascripts/tracing/components/tracing_details.vue
+++ /dev/null
@@ -1,90 +0,0 @@
-<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { createAlert } from '~/alert';
-import { visitUrl, isSafeURL } from '~/lib/utils/url_utility';
-
-export default {
- components: {
- GlLoadingIcon,
- },
- i18n: {
- error: s__('Tracing|Failed to load trace details.'),
- },
- props: {
- observabilityClient: {
- required: true,
- type: Object,
- },
- traceId: {
- required: true,
- type: String,
- },
- tracingIndexUrl: {
- required: true,
- type: String,
- validator: (val) => isSafeURL(val),
- },
- },
- data() {
- return {
- trace: null,
- loading: false,
- };
- },
- created() {
- this.validateAndFetch();
- },
- methods: {
- async validateAndFetch() {
- if (!this.traceId) {
- createAlert({
- message: this.$options.i18n.error,
- });
- }
- this.loading = true;
- try {
- const enabled = await this.observabilityClient.isTracingEnabled();
- if (enabled) {
- await this.fetchTrace();
- } else {
- this.goToTracingIndex();
- }
- } catch (e) {
- createAlert({
- message: this.$options.i18n.error,
- });
- } finally {
- this.loading = false;
- }
- },
- async fetchTrace() {
- this.loading = true;
- try {
- this.trace = await this.observabilityClient.fetchTrace(this.traceId);
- } catch (e) {
- createAlert({
- message: this.$options.i18n.error,
- });
- } finally {
- this.loading = false;
- }
- },
- goToTracingIndex() {
- visitUrl(this.tracingIndexUrl);
- },
- },
-};
-</script>
-
-<template>
- <div v-if="loading" class="gl-py-5">
- <gl-loading-icon size="lg" />
- </div>
-
- <!-- TODO Replace with actual trace-details component-->
- <div v-else-if="trace" data-testid="trace-details">
- <p>{{ tracingIndexUrl }}</p>
- <p>{{ trace }}</p>
- </div>
-</template>
diff --git a/app/assets/javascripts/tracing/components/tracing_empty_state.vue b/app/assets/javascripts/tracing/components/tracing_empty_state.vue
deleted file mode 100644
index f17060db6bc..00000000000
--- a/app/assets/javascripts/tracing/components/tracing_empty_state.vue
+++ /dev/null
@@ -1,35 +0,0 @@
-<script>
-import EMPTY_TRACING_SVG from '@gitlab/svgs/dist/illustrations/monitoring/tracing.svg?url';
-import { GlEmptyState, GlButton } from '@gitlab/ui';
-import { s__ } from '~/locale';
-
-export default {
- EMPTY_TRACING_SVG,
- name: 'TracingEmptyState',
- i18n: {
- title: s__('Tracing|Get started with Tracing'),
- description: s__('Tracing|Monitor your applications with GitLab Distributed Tracing.'),
- enableButtonText: s__('Tracing|Enable'),
- },
- components: {
- GlEmptyState,
- GlButton,
- },
-};
-</script>
-
-<template>
- <gl-empty-state :title="$options.i18n.title" :svg-path="$options.EMPTY_TRACING_SVG">
- <template #description>
- <div>
- <span>{{ $options.i18n.description }}</span>
- </div>
- </template>
-
- <template #actions>
- <gl-button variant="confirm" class="gl-mx-2 gl-mb-3" @click="$emit('enable-tracing')">
- {{ $options.i18n.enableButtonText }}
- </gl-button>
- </template>
- </gl-empty-state>
-</template>
diff --git a/app/assets/javascripts/tracing/components/tracing_list.vue b/app/assets/javascripts/tracing/components/tracing_list.vue
deleted file mode 100644
index 21d1353a86d..00000000000
--- a/app/assets/javascripts/tracing/components/tracing_list.vue
+++ /dev/null
@@ -1,125 +0,0 @@
-<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { createAlert } from '~/alert';
-import { visitUrl, joinPaths } from '~/lib/utils/url_utility';
-import UrlSync from '~/vue_shared/components/url_sync.vue';
-import {
- queryToFilterObj,
- filterObjToQuery,
- filterObjToFilterToken,
- filterTokensToFilterObj,
-} from '../filters';
-import TracingEmptyState from './tracing_empty_state.vue';
-import TracingTableList from './tracing_table_list.vue';
-import FilteredSearch from './tracing_list_filtered_search.vue';
-
-export default {
- components: {
- GlLoadingIcon,
- TracingTableList,
- TracingEmptyState,
- FilteredSearch,
- UrlSync,
- },
- props: {
- observabilityClient: {
- required: true,
- type: Object,
- },
- },
- data() {
- return {
- loading: true,
- /**
- * tracingEnabled: boolean | null.
- * null identifies a state where we don't know if tracing is enabled or not (e.g. when fetching the status from the API fails)
- */
- tracingEnabled: null,
- traces: [],
- filters: queryToFilterObj(window.location.search),
- };
- },
- computed: {
- query() {
- return filterObjToQuery(this.filters);
- },
- initialFilterValue() {
- return filterObjToFilterToken(this.filters);
- },
- },
- async created() {
- this.checkEnabled();
- },
- methods: {
- async checkEnabled() {
- this.loading = true;
- try {
- this.tracingEnabled = await this.observabilityClient.isTracingEnabled();
- if (this.tracingEnabled) {
- await this.fetchTraces();
- }
- } catch (e) {
- createAlert({
- message: s__('Tracing|Failed to load page.'),
- });
- } finally {
- this.loading = false;
- }
- },
- async enableTracing() {
- this.loading = true;
- try {
- await this.observabilityClient.enableTraces();
- this.tracingEnabled = true;
- await this.fetchTraces();
- } catch (e) {
- createAlert({
- message: s__('Tracing|Failed to enable tracing.'),
- });
- } finally {
- this.loading = false;
- }
- },
- async fetchTraces() {
- this.loading = true;
- try {
- const traces = await this.observabilityClient.fetchTraces(this.filters);
- this.traces = traces;
- } catch (e) {
- createAlert({
- message: s__('Tracing|Failed to load traces.'),
- });
- } finally {
- this.loading = false;
- }
- },
- selectTrace(trace) {
- visitUrl(joinPaths(window.location.pathname, trace.trace_id));
- },
- handleFilters(filterTokens) {
- this.filters = filterTokensToFilterObj(filterTokens);
- this.fetchTraces();
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div v-if="loading" class="gl-py-5">
- <gl-loading-icon size="lg" />
- </div>
-
- <template v-else-if="tracingEnabled !== null">
- <tracing-empty-state v-if="tracingEnabled === false" @enable-tracing="enableTracing" />
-
- <template v-else>
- <filtered-search :initial-filters="initialFilterValue" @submit="handleFilters" />
- <url-sync :query="query" />
-
- <tracing-table-list :traces="traces" @reload="fetchTraces" @trace-selected="selectTrace" />
- </template>
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/tracing/components/tracing_list_filtered_search.vue b/app/assets/javascripts/tracing/components/tracing_list_filtered_search.vue
deleted file mode 100644
index d086f2d03ff..00000000000
--- a/app/assets/javascripts/tracing/components/tracing_list_filtered_search.vue
+++ /dev/null
@@ -1,87 +0,0 @@
-<script>
-import { GlFilteredSearch, GlFilteredSearchToken } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import {
- OPERATORS_IS,
- OPERATORS_IS_NOT,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import {
- PERIOD_FILTER_TOKEN_TYPE,
- SERVICE_NAME_FILTER_TOKEN_TYPE,
- OPERATION_FILTER_TOKEN_TYPE,
- TRACE_ID_FILTER_TOKEN_TYPE,
- DURATION_MS_FILTER_TOKEN_TYPE,
-} from '../filters';
-
-export default {
- availableTokens: [
- {
- title: s__('Tracing|Period'),
- icon: 'clock',
- type: PERIOD_FILTER_TOKEN_TYPE,
- token: GlFilteredSearchToken,
- operators: OPERATORS_IS,
- unique: true,
- options: [
- { value: '1m', title: s__('Tracing|Last 1 minute') },
- { value: '15m', title: s__('Tracing|Last 15 minutes') },
- { value: '30m', title: s__('Tracing|Last 30 minutes') },
- { value: '1h', title: s__('Tracing|Last 1 hour') },
- { value: '24h', title: s__('Tracing|Last 24 hours') },
- { value: '7d', title: s__('Tracing|Last 7 days') },
- { value: '14d', title: s__('Tracing|Last 14 days') },
- { value: '30d', title: s__('Tracing|Last 30 days') },
- ],
- },
- {
- title: s__('Tracing|Service'),
- type: SERVICE_NAME_FILTER_TOKEN_TYPE,
- token: GlFilteredSearchToken,
- operators: OPERATORS_IS_NOT,
- },
- {
- title: s__('Tracing|Operation'),
- type: OPERATION_FILTER_TOKEN_TYPE,
- token: GlFilteredSearchToken,
- operators: OPERATORS_IS_NOT,
- },
- {
- title: s__('Tracing|Trace ID'),
- type: TRACE_ID_FILTER_TOKEN_TYPE,
- token: GlFilteredSearchToken,
- operators: OPERATORS_IS_NOT,
- },
- {
- title: s__('Tracing|Duration (ms)'),
- type: DURATION_MS_FILTER_TOKEN_TYPE,
- token: GlFilteredSearchToken,
- operators: [
- { value: '>', description: s__('Tracing|longer than') },
- { value: '<', description: s__('Tracing|shorter than') },
- ],
- },
- ],
- components: {
- GlFilteredSearch,
- },
- props: {
- initialFilters: {
- type: Array,
- required: false,
- default: () => [],
- },
- },
-};
-</script>
-
-<template>
- <div class="vue-filtered-search-bar-container row-content-block gl-border-t-none">
- <gl-filtered-search
- :value="initialFilters"
- terms-as-tokens
- :placeholder="s__('Tracing|Filter Traces')"
- :available-tokens="$options.availableTokens"
- @submit="$emit('submit', $event)"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/tracing/components/tracing_table_list.vue b/app/assets/javascripts/tracing/components/tracing_table_list.vue
deleted file mode 100644
index abb1f3ae88c..00000000000
--- a/app/assets/javascripts/tracing/components/tracing_table_list.vue
+++ /dev/null
@@ -1,101 +0,0 @@
-<script>
-import { GlTable, GlLink } from '@gitlab/ui';
-import { s__ } from '~/locale';
-
-export const tableDataClass = 'gl-display-flex gl-md-display-table-cell gl-align-items-center';
-export default {
- name: 'TracingTableList',
- i18n: {
- title: s__('Tracing|Traces'),
- emptyText: s__('Tracing|No traces to display.'),
- emptyLinkText: s__('Tracing|Check again'),
- },
- fields: [
- {
- key: 'timestamp',
- label: s__('Tracing|Date'),
- tdClass: tableDataClass,
- sortable: true,
- },
- {
- key: 'service_name',
- label: s__('Tracing|Service'),
- tdClass: tableDataClass,
- sortable: true,
- },
- {
- key: 'operation',
- label: s__('Tracing|Operation'),
- tdClass: tableDataClass,
- sortable: true,
- },
- {
- key: 'duration',
- label: s__('Tracing|Duration'),
- thClass: 'gl-w-15p',
- tdClass: tableDataClass,
- sortable: true,
- },
- ],
- components: {
- GlTable,
- GlLink,
- },
- props: {
- traces: {
- required: true,
- type: Array,
- },
- },
- methods: {
- onSelect(items) {
- if (items[0]) {
- this.$emit('trace-selected', items[0]);
- }
- },
- },
-};
-</script>
-
-<template>
- <div>
- <h4 class="gl-display-block gl-md-display-none! gl-my-5">{{ $options.i18n.title }}</h4>
-
- <gl-table
- :items="traces"
- :fields="$options.fields"
- show-empty
- sort-by="timestamp"
- :sort-desc="true"
- fixed
- stacked="md"
- tbody-tr-class="table-row"
- selectable
- select-mode="single"
- selected-variant=""
- @row-selected="onSelect"
- >
- <template #cell(timestamp)="data">
- {{ data.item.timestamp }}
- </template>
-
- <template #cell(service_name)="data">
- {{ data.item.service_name }}
- </template>
-
- <template #cell(operation)="data">
- {{ data.item.operation }}
- </template>
-
- <template #cell(duration)="data">
- <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings -->
- {{ `${data.item.duration} ms` }}
- </template>
-
- <template #empty>
- {{ $options.i18n.emptyText }}
- <gl-link @click="$emit('reload')">{{ $options.i18n.emptyLinkText }}</gl-link>
- </template>
- </gl-table>
- </div>
-</template>
diff --git a/app/assets/javascripts/tracing/details_index.vue b/app/assets/javascripts/tracing/details_index.vue
deleted file mode 100644
index 5702a88766c..00000000000
--- a/app/assets/javascripts/tracing/details_index.vue
+++ /dev/null
@@ -1,49 +0,0 @@
-<script>
-import ObservabilityContainer from '~/observability/components/observability_container.vue';
-import TracingDetails from './components/tracing_details.vue';
-
-export default {
- components: {
- ObservabilityContainer,
- TracingDetails,
- },
- props: {
- traceId: {
- type: String,
- required: true,
- },
- oauthUrl: {
- type: String,
- required: true,
- },
- tracingUrl: {
- type: String,
- required: true,
- },
- provisioningUrl: {
- type: String,
- required: true,
- },
- tracingIndexUrl: {
- required: true,
- type: String,
- },
- },
-};
-</script>
-
-<template>
- <observability-container
- :oauth-url="oauthUrl"
- :tracing-url="tracingUrl"
- :provisioning-url="provisioningUrl"
- >
- <template #default="{ observabilityClient }">
- <tracing-details
- :trace-id="traceId"
- :tracing-index-url="tracingIndexUrl"
- :observability-client="observabilityClient"
- />
- </template>
- </observability-container>
-</template>
diff --git a/app/assets/javascripts/tracing/filters.js b/app/assets/javascripts/tracing/filters.js
deleted file mode 100644
index 88a54b2e69f..00000000000
--- a/app/assets/javascripts/tracing/filters.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import {
- filterToQueryObject,
- urlQueryToFilter,
- prepareTokens,
- processFilters,
-} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
-import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
-
-export const PERIOD_FILTER_TOKEN_TYPE = 'period';
-export const SERVICE_NAME_FILTER_TOKEN_TYPE = 'service-name';
-export const OPERATION_FILTER_TOKEN_TYPE = 'operation';
-export const TRACE_ID_FILTER_TOKEN_TYPE = 'trace-id';
-export const DURATION_MS_FILTER_TOKEN_TYPE = 'duration-ms';
-
-export function queryToFilterObj(url) {
- const filter = urlQueryToFilter(url, {
- filteredSearchTermKey: 'search',
- customOperators: [
- {
- operator: '>',
- prefix: 'gt',
- },
- {
- operator: '<',
- prefix: 'lt',
- },
- ],
- });
- const {
- period = null,
- service = null,
- operation = null,
- trace_id: traceId = null,
- durationMs = null,
- } = filter;
- const search = filter[FILTERED_SEARCH_TERM];
- return {
- period,
- service,
- operation,
- traceId,
- durationMs,
- search,
- };
-}
-
-export function filterObjToQuery(filters) {
- return filterToQueryObject(
- {
- period: filters.period,
- service: filters.serviceName,
- operation: filters.operation,
- trace_id: filters.traceId,
- durationMs: filters.durationMs,
- [FILTERED_SEARCH_TERM]: filters.search,
- },
- {
- filteredSearchTermKey: 'search',
- customOperators: [
- {
- operator: '>',
- prefix: 'gt',
- applyOnlyToKey: 'durationMs',
- },
- {
- operator: '<',
- prefix: 'lt',
- applyOnlyToKey: 'durationMs',
- },
- ],
- },
- );
-}
-
-export function filterObjToFilterToken(filters) {
- return prepareTokens({
- [PERIOD_FILTER_TOKEN_TYPE]: filters.period,
- [SERVICE_NAME_FILTER_TOKEN_TYPE]: filters.serviceName,
- [OPERATION_FILTER_TOKEN_TYPE]: filters.operation,
- [TRACE_ID_FILTER_TOKEN_TYPE]: filters.traceId,
- [DURATION_MS_FILTER_TOKEN_TYPE]: filters.durationMs,
- [FILTERED_SEARCH_TERM]: filters.search,
- });
-}
-
-export function filterTokensToFilterObj(tokens) {
- const {
- [SERVICE_NAME_FILTER_TOKEN_TYPE]: serviceName,
- [PERIOD_FILTER_TOKEN_TYPE]: period,
- [OPERATION_FILTER_TOKEN_TYPE]: operation,
- [TRACE_ID_FILTER_TOKEN_TYPE]: traceId,
- [DURATION_MS_FILTER_TOKEN_TYPE]: durationMs,
- [FILTERED_SEARCH_TERM]: search,
- } = processFilters(tokens);
-
- return {
- serviceName,
- period,
- operation,
- traceId,
- durationMs,
- search,
- };
-}
diff --git a/app/assets/javascripts/tracing/list_index.vue b/app/assets/javascripts/tracing/list_index.vue
deleted file mode 100644
index 432fbb81506..00000000000
--- a/app/assets/javascripts/tracing/list_index.vue
+++ /dev/null
@@ -1,37 +0,0 @@
-<script>
-import ObservabilityContainer from '~/observability/components/observability_container.vue';
-import TracingList from './components/tracing_list.vue';
-
-export default {
- components: {
- ObservabilityContainer,
- TracingList,
- },
- props: {
- oauthUrl: {
- type: String,
- required: true,
- },
- tracingUrl: {
- type: String,
- required: true,
- },
- provisioningUrl: {
- type: String,
- required: true,
- },
- },
-};
-</script>
-
-<template>
- <observability-container
- :oauth-url="oauthUrl"
- :tracing-url="tracingUrl"
- :provisioning-url="provisioningUrl"
- >
- <template #default="{ observabilityClient }">
- <tracing-list :observability-client="observabilityClient" />
- </template>
- </observability-container>
-</template>
diff --git a/app/assets/javascripts/tracking/constants.js b/app/assets/javascripts/tracking/constants.js
index 114587bb363..88b7f6d3532 100644
--- a/app/assets/javascripts/tracking/constants.js
+++ b/app/assets/javascripts/tracking/constants.js
@@ -30,4 +30,10 @@ export const GOOGLE_ANALYTICS_ID_COOKIE_NAME = '_ga';
export const GITLAB_INTERNAL_EVENT_CATEGORY = 'InternalEventTracking';
-export const SERVICE_PING_SCHEMA = 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-0';
+export const SERVICE_PING_SCHEMA = 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-1';
+
+export const SERVICE_PING_SECURITY_CONFIGURATION_THREAT_MANAGEMENT_VISIT =
+ 'users_visiting_security_configuration_threat_management';
+
+export const SERVICE_PING_PIPELINE_SECURITY_VISIT = 'users_visiting_pipeline_security';
+export const USER_CONTEXT_SCHEMA = 'iglu:com.gitlab/user_context/jsonschema/1-0-0';
diff --git a/app/assets/javascripts/tracking/dispatch_snowplow_event.js b/app/assets/javascripts/tracking/dispatch_snowplow_event.js
index 89d90cf89be..99e4a6aa3c7 100644
--- a/app/assets/javascripts/tracking/dispatch_snowplow_event.js
+++ b/app/assets/javascripts/tracking/dispatch_snowplow_event.js
@@ -15,10 +15,14 @@ export function dispatchSnowplowEvent(
let { value } = data;
const standardContext = getStandardContext({ extra });
- const contexts = [standardContext];
+ let contexts = [standardContext];
if (data.context) {
- contexts.push(data.context);
+ if (Array.isArray(data.context)) {
+ contexts = [...contexts, ...data.context];
+ } else {
+ contexts.push(data.context);
+ }
}
if (value !== undefined) {
diff --git a/app/assets/javascripts/tracking/index.js b/app/assets/javascripts/tracking/index.js
index ffbd932c02b..2ee4703aa0b 100644
--- a/app/assets/javascripts/tracking/index.js
+++ b/app/assets/javascripts/tracking/index.js
@@ -72,4 +72,5 @@ export function initDefaultTrackers() {
InternalEvents.bindInternalEventDocument();
InternalEvents.trackInternalLoadEvents();
+ InternalEvents.initBrowserSDK();
}
diff --git a/app/assets/javascripts/tracking/internal_events.js b/app/assets/javascripts/tracking/internal_events.js
index a5fbb55ff63..9bd0200cad1 100644
--- a/app/assets/javascripts/tracking/internal_events.js
+++ b/app/assets/javascripts/tracking/internal_events.js
@@ -1,10 +1,12 @@
import API from '~/api';
+import getStandardContext from './get_standard_context';
import Tracking from './tracking';
import {
GITLAB_INTERNAL_EVENT_CATEGORY,
LOAD_INTERNAL_EVENTS_SELECTOR,
SERVICE_PING_SCHEMA,
+ USER_CONTEXT_SCHEMA,
} from './constants';
import { Tracker } from './tracker';
import { InternalEventHandler, createInternalEventPayload } from './utils';
@@ -13,17 +15,24 @@ const InternalEvents = {
/**
*
* @param {string} event
+ * @param {object} data
*/
- track_event(event) {
+ track_event(event, data = {}) {
+ const { context, ...rest } = data;
+
+ const defaultContext = {
+ schema: SERVICE_PING_SCHEMA,
+ data: {
+ event_name: event,
+ data_source: 'redis_hll',
+ },
+ };
+ const mergedContext = context ? [defaultContext, context] : defaultContext;
+
API.trackInternalEvent(event);
Tracking.event(GITLAB_INTERNAL_EVENT_CATEGORY, event, {
- context: {
- schema: SERVICE_PING_SCHEMA,
- data: {
- event_name: event,
- data_source: 'redis_hll',
- },
- },
+ context: mergedContext,
+ ...rest,
});
},
/**
@@ -33,8 +42,8 @@ const InternalEvents = {
mixin() {
return {
methods: {
- track_event(event) {
- InternalEvents.track_event(event);
+ track_event(event, data = {}) {
+ InternalEvents.track_event(event, data);
},
},
};
@@ -78,6 +87,25 @@ const InternalEvents = {
return loadEvents;
},
+ /**
+ * Initialize browser sdk for product analytics
+ */
+ initBrowserSDK() {
+ const standardContext = getStandardContext();
+
+ if (window.glClient) {
+ window.glClient.setDocumentTitle('GitLab');
+ window.glClient.page({
+ title: 'GitLab',
+ context: [
+ {
+ schema: USER_CONTEXT_SCHEMA,
+ data: standardContext?.data || {},
+ },
+ ],
+ });
+ }
+ },
};
export default InternalEvents;
diff --git a/app/assets/javascripts/tracking/tracker.js b/app/assets/javascripts/tracking/tracker.js
index b69b1714952..b74078475b0 100644
--- a/app/assets/javascripts/tracking/tracker.js
+++ b/app/assets/javascripts/tracking/tracker.js
@@ -257,12 +257,20 @@ export const Tracker = {
const customUrl = `${pageUrl}${appendHash ? window.location.hash : ''}`;
window.snowplow('setCustomUrl', customUrl);
+ // If Browser SDK is enabled set Custom url and Referrer url
+ if (window.glClient) {
+ window.glClient?.setCustomUrl(customUrl);
+ }
if (document.referrer) {
const node = referrers.find((links) => links.originalUrl === document.referrer);
if (node) {
pageLinks.referrer = node.url;
window.snowplow('setReferrerUrl', pageLinks.referrer);
+
+ if (window.glClient) {
+ window.glClient?.setReferrerUrl(pageLinks.referrer);
+ }
}
}
diff --git a/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.stories.js b/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.stories.js
new file mode 100644
index 00000000000..9bf6d27235c
--- /dev/null
+++ b/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.stories.js
@@ -0,0 +1,64 @@
+import { mockGetProjectStorageStatisticsGraphQLResponse } from 'jest/usage_quotas/storage/mock_data';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import getProjectStorageStatisticsQuery from '../queries/project_storage.query.graphql';
+import ProjectStorageApp from './project_storage_app.vue';
+
+const meta = {
+ title: 'usage_quotas/storage/project_storage_app',
+ component: ProjectStorageApp,
+};
+
+export default meta;
+
+const createTemplate = (config = {}) => {
+ let { provide, apolloProvider } = config;
+
+ if (provide == null) {
+ provide = {};
+ }
+
+ if (apolloProvider == null) {
+ const requestHandlers = [
+ [
+ getProjectStorageStatisticsQuery,
+ () => Promise.resolve(mockGetProjectStorageStatisticsGraphQLResponse),
+ ],
+ ];
+ apolloProvider = createMockApollo(requestHandlers);
+ }
+
+ return (args, { argTypes }) => ({
+ components: { ProjectStorageApp },
+ apolloProvider,
+ provide: {
+ projectPath: '/namespace/project',
+ ...provide,
+ },
+ props: Object.keys(argTypes),
+ template: '<project-storage-app />',
+ });
+};
+
+export const Default = {
+ render: createTemplate(),
+};
+
+export const Loading = {
+ render(...args) {
+ const requestHandlers = [[getProjectStorageStatisticsQuery, () => new Promise(() => {})]];
+ const apolloProvider = createMockApollo(requestHandlers);
+ return createTemplate({
+ apolloProvider,
+ })(...args);
+ },
+};
+
+export const LoadingError = {
+ render(...args) {
+ const requestHandlers = [[getProjectStorageStatisticsQuery, () => Promise.reject()]];
+ const apolloProvider = createMockApollo(requestHandlers);
+ return createTemplate({
+ apolloProvider,
+ })(...args);
+ },
+};
diff --git a/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue b/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue
index f271b284d78..a5e1cc398e3 100644
--- a/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue
+++ b/app/assets/javascripts/usage_quotas/storage/components/project_storage_app.vue
@@ -3,6 +3,7 @@ import { GlAlert, GlButton, GlLink, GlLoadingIcon } from '@gitlab/ui';
import { sprintf } from '~/locale';
import { updateRepositorySize } from '~/api/projects_api';
import { numberToHumanSize } from '~/lib/utils/number_utils';
+import SectionedPercentageBar from '~/usage_quotas/components/sectioned_percentage_bar.vue';
import {
ERROR_MESSAGE,
LEARN_MORE_LABEL,
@@ -19,7 +20,6 @@ import {
} from '../constants';
import getProjectStorageStatistics from '../queries/project_storage.query.graphql';
import { getStorageTypesFromProjectStatistics, descendingStorageUsageSort } from '../utils';
-import UsageGraph from './usage_graph.vue';
import ProjectStorageDetail from './project_storage_detail.vue';
export default {
@@ -29,8 +29,8 @@ export default {
GlButton,
GlLink,
GlLoadingIcon,
- UsageGraph,
ProjectStorageDetail,
+ SectionedPercentageBar,
},
inject: ['projectPath'],
apollo: {
@@ -88,6 +88,67 @@ export default {
storageTypeHelpPaths,
);
},
+
+ sections() {
+ if (!this.project?.statistics) {
+ return null;
+ }
+
+ const {
+ buildArtifactsSize,
+ lfsObjectsSize,
+ packagesSize,
+ repositorySize,
+ storageSize,
+ wikiSize,
+ snippetsSize,
+ } = this.project.statistics;
+
+ if (storageSize === 0) {
+ return null;
+ }
+
+ return [
+ {
+ id: 'repository',
+ value: repositorySize,
+ },
+ {
+ id: 'lfsObjects',
+ value: lfsObjectsSize,
+ },
+ {
+ id: 'packages',
+ value: packagesSize,
+ },
+ {
+ id: 'buildArtifacts',
+ value: buildArtifactsSize,
+ },
+ {
+ id: 'wiki',
+ value: wikiSize,
+ },
+ {
+ id: 'snippets',
+ value: snippetsSize,
+ },
+ ]
+ .filter((data) => data.value !== 0)
+ .sort(descendingStorageUsageSort('value'))
+ .map((storageType) => {
+ const storageTypeExtraData = PROJECT_STORAGE_TYPES.find(
+ (type) => storageType.id === type.id,
+ );
+ const label = storageTypeExtraData?.name;
+
+ return {
+ label,
+ formattedValue: numberToHumanSize(storageType.value),
+ ...storageType,
+ };
+ });
+ },
},
methods: {
clearError() {
@@ -123,11 +184,11 @@ export default {
{{ error }}
</gl-alert>
<div v-else>
- <div class="gl-pt-5 gl-px-3">
- <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
+ <div class="gl-pt-5">
+ <div class="gl-display-flex gl-justify-content-space-between">
<div>
- <h2 class="gl-m-0 gl-font-lg gl-font-weight-bold">{{ $options.TOTAL_USAGE_TITLE }}</h2>
- <p class="gl-m-0 gl-text-gray-400">
+ <h4 class="gl-font-lg gl-mb-3 gl-mt-0">{{ $options.TOTAL_USAGE_TITLE }}</h4>
+ <p>
{{ $options.TOTAL_USAGE_SUBTITLE }}
<gl-link
:href="$options.usageQuotasHelpPaths.usageQuotas"
@@ -137,13 +198,16 @@ export default {
>
</p>
</div>
- <p class="gl-m-0 gl-font-size-h-display gl-font-weight-bold" data-testid="total-usage">
+ <p
+ class="gl-m-0 gl-font-size-h-display gl-font-weight-bold gl-white-space-nowrap"
+ data-testid="total-usage"
+ >
{{ totalUsage }}
</p>
</div>
</div>
<div v-if="!isStatisticsEmpty" class="gl-w-full">
- <usage-graph :root-storage-statistics="project.statistics" :limit="0" />
+ <sectioned-percentage-bar class="gl-mt-5" :sections="sections" />
</div>
<div class="gl-w-full gl-my-5">
<gl-button
diff --git a/app/assets/javascripts/usage_quotas/storage/components/usage_graph.vue b/app/assets/javascripts/usage_quotas/storage/components/usage_graph.vue
deleted file mode 100644
index 33f202e69db..00000000000
--- a/app/assets/javascripts/usage_quotas/storage/components/usage_graph.vue
+++ /dev/null
@@ -1,136 +0,0 @@
-<script>
-import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { PROJECT_STORAGE_TYPES } from '../constants';
-import { descendingStorageUsageSort } from '../utils';
-
-export default {
- name: 'UsageGraph',
- props: {
- rootStorageStatistics: {
- required: true,
- type: Object,
- },
- limit: {
- required: true,
- type: Number,
- },
- },
- computed: {
- storageTypes() {
- const {
- buildArtifactsSize,
- lfsObjectsSize,
- packagesSize,
- repositorySize,
- storageSize,
- wikiSize,
- snippetsSize,
- } = this.rootStorageStatistics;
-
- if (storageSize === 0) {
- return null;
- }
-
- return [
- {
- id: 'repository',
- style: this.usageStyle(this.barRatio(repositorySize)),
- class: 'gl-bg-data-viz-blue-500',
- size: repositorySize,
- },
- {
- id: 'lfsObjects',
- style: this.usageStyle(this.barRatio(lfsObjectsSize)),
- class: 'gl-bg-data-viz-orange-600',
- size: lfsObjectsSize,
- },
- {
- id: 'packages',
- style: this.usageStyle(this.barRatio(packagesSize)),
- class: 'gl-bg-data-viz-aqua-500',
- size: packagesSize,
- },
- {
- id: 'buildArtifacts',
- style: this.usageStyle(this.barRatio(buildArtifactsSize)),
- class: 'gl-bg-data-viz-green-500',
- size: buildArtifactsSize,
- },
- {
- id: 'wiki',
- style: this.usageStyle(this.barRatio(wikiSize)),
- class: 'gl-bg-data-viz-magenta-500',
- size: wikiSize,
- },
- {
- id: 'snippets',
- style: this.usageStyle(this.barRatio(snippetsSize)),
- class: 'gl-bg-data-viz-orange-800',
- size: snippetsSize,
- },
- ]
- .filter((data) => data.size !== 0)
- .sort(descendingStorageUsageSort('size'))
- .map((storageType) => {
- const storageTypeExtraData = PROJECT_STORAGE_TYPES.find(
- (type) => storageType.id === type.id,
- );
- const name = storageTypeExtraData?.name;
-
- return {
- name,
- ...storageType,
- };
- });
- },
- },
- methods: {
- formatSize(size) {
- return numberToHumanSize(size);
- },
- usageStyle(ratio) {
- return { flex: ratio };
- },
- barRatio(size) {
- let max = this.rootStorageStatistics.storageSize;
-
- if (this.limit !== 0 && max <= this.limit) {
- max = this.limit;
- }
-
- return size / max;
- },
- },
-};
-</script>
-<template>
- <div v-if="storageTypes" class="gl-display-flex gl-flex-direction-column w-100">
- <div class="gl-h-6 gl-my-5 gl-bg-gray-50 gl-rounded-base gl-display-flex">
- <div
- v-for="storageType in storageTypes"
- :key="storageType.name"
- class="storage-type-usage gl-h-full gl-display-inline-block"
- :class="storageType.class"
- :style="storageType.style"
- data-testid="storage-type-usage"
- ></div>
- </div>
- <div class="row gl-mb-4">
- <div
- v-for="storageType in storageTypes"
- :key="storageType.name"
- class="col-md-auto gl-display-flex gl-align-items-center"
- data-testid="storage-type-legend"
- data-qa-selector="storage_type_legend"
- >
- <div class="gl-h-2 gl-w-5 gl-mr-2 gl-display-inline-block" :class="storageType.class"></div>
- <span class="gl-mr-2 gl-font-weight-bold gl-font-sm">
- {{ storageType.name }}
- </span>
- <span class="gl-text-gray-500 gl-font-sm">
- {{ formatSize(storageType.size) }}
- </span>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/user_lists/components/user_list.vue b/app/assets/javascripts/user_lists/components/user_list.vue
index 29b9b68883b..d4601d1f736 100644
--- a/app/assets/javascripts/user_lists/components/user_list.vue
+++ b/app/assets/javascripts/user_lists/components/user_list.vue
@@ -39,7 +39,7 @@ export default {
),
userIdLabel: s__('UserLists|User IDs'),
userIdColumnHeader: s__('UserLists|User ID'),
- errorMessage: __('Something went wrong on our end. Please try again!'),
+ errorMessage: __('Unable to load user list. Reload the page and try again.'),
editButtonLabel: s__('UserLists|Edit'),
},
classes: {
diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js
index ab707e7e69c..aa68cf5a161 100644
--- a/app/assets/javascripts/users_select/index.js
+++ b/app/assets/javascripts/users_select/index.js
@@ -32,45 +32,46 @@ function UsersSelect(currentUser, els, options = {}) {
const { handleClick, states } = options;
- $els.each((i, dropdown) => {
- const userSelect = this;
- const $dropdown = $(dropdown);
- const options = {
- states,
- projectId: $dropdown.data('projectId'),
- groupId: $dropdown.data('groupId'),
- showCurrentUser: $dropdown.data('currentUser'),
- todoFilter: $dropdown.data('todoFilter'),
- todoStateFilter: $dropdown.data('todoStateFilter'),
- iid: $dropdown.data('iid'),
- issuableType: $dropdown.data('issuableType'),
- targetBranch: $dropdown.data('targetBranch'),
- authorId: $dropdown.data('authorId'),
- showSuggested: $dropdown.data('showSuggested'),
- };
- const showNullUser = $dropdown.data('nullUser');
- const defaultNullUser = $dropdown.data('nullUserDefault');
- const showMenuAbove = $dropdown.data('showMenuAbove');
- const showAnyUser = $dropdown.data('anyUser');
- const firstUser = $dropdown.data('firstUser');
- const defaultLabel = $dropdown.data('defaultLabel');
- const issueURL = $dropdown.data('issueUpdate');
- const $selectbox = $dropdown.closest('.selectbox');
- const $assignToMeLink = $selectbox.next('.assign-to-me-link');
- let $block = $selectbox.closest('.block');
- const abilityName = $dropdown.data('abilityName');
- let $value = $block.find('.value');
- const $collapsedSidebar = $block.find('.sidebar-collapsed-user');
- const $loading = $block.find('.block-loading').addClass('gl-display-none');
- const selectedIdDefault = defaultNullUser && showNullUser ? 0 : null;
- let selectedId = $dropdown.data('selected');
- let assignTo;
- let assigneeTemplate;
- let collapsedAssigneeTemplate;
-
- const suggestedReviewersHelpPath = $dropdown.data('suggestedReviewersHelpPath');
- const suggestedReviewersHeaderTemplate = template(
- `<div class="gl-display-flex gl-align-items-center">
+ this.dropdowns = $els
+ .map((i, dropdown) => {
+ const userSelect = this;
+ const $dropdown = $(dropdown);
+ const options = {
+ states,
+ projectId: $dropdown.data('projectId'),
+ groupId: $dropdown.data('groupId'),
+ showCurrentUser: $dropdown.data('currentUser'),
+ todoFilter: $dropdown.data('todoFilter'),
+ todoStateFilter: $dropdown.data('todoStateFilter'),
+ iid: $dropdown.data('iid'),
+ issuableType: $dropdown.data('issuableType'),
+ targetBranch: $dropdown.data('targetBranch'),
+ authorId: $dropdown.data('authorId'),
+ showSuggested: $dropdown.data('showSuggested'),
+ };
+ const showNullUser = $dropdown.data('nullUser');
+ const defaultNullUser = $dropdown.data('nullUserDefault');
+ const showMenuAbove = $dropdown.data('showMenuAbove');
+ const showAnyUser = $dropdown.data('anyUser');
+ const firstUser = $dropdown.data('firstUser');
+ const defaultLabel = $dropdown.data('defaultLabel');
+ const issueURL = $dropdown.data('issueUpdate');
+ const $selectbox = $dropdown.closest('.selectbox');
+ const $assignToMeLink = $selectbox.next('.assign-to-me-link');
+ let $block = $selectbox.closest('.block');
+ const abilityName = $dropdown.data('abilityName');
+ let $value = $block.find('.value');
+ const $collapsedSidebar = $block.find('.sidebar-collapsed-user');
+ const $loading = $block.find('.block-loading').addClass('gl-display-none');
+ const selectedIdDefault = defaultNullUser && showNullUser ? 0 : null;
+ let selectedId = $dropdown.data('selected');
+ let assignTo;
+ let assigneeTemplate;
+ let collapsedAssigneeTemplate;
+
+ const suggestedReviewersHelpPath = $dropdown.data('suggestedReviewersHelpPath');
+ const suggestedReviewersHeaderTemplate = template(
+ `<div class="gl-display-flex gl-align-items-center">
<%- header %>
<a
title="${s__('SuggestedReviewers|Learn about suggested reviewers')}"
@@ -82,562 +83,568 @@ function UsersSelect(currentUser, els, options = {}) {
${spriteIcon('question-o', 'gl-ml-3 gl-icon s16')}
</a>
</div>`,
- );
+ );
- if (selectedId === undefined) {
- selectedId = selectedIdDefault;
- }
+ if (selectedId === undefined) {
+ selectedId = selectedIdDefault;
+ }
- const assignYourself = function () {
- const unassignedSelected = $dropdown
- .closest('.selectbox')
- .find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
+ const assignYourself = function () {
+ const unassignedSelected = $dropdown
+ .closest('.selectbox')
+ .find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
- if (unassignedSelected) {
- unassignedSelected.remove();
- }
+ if (unassignedSelected) {
+ unassignedSelected.remove();
+ }
- // Save current selected user to the DOM
- const currentUserInfo = $dropdown.data('currentUserInfo') || {};
- const currentUser = userSelect.currentUser || {};
- const fieldName = $dropdown.data('fieldName');
- const userName = currentUserInfo.name;
- const userId = currentUserInfo.id || currentUser.id;
+ // Save current selected user to the DOM
+ const currentUserInfo = $dropdown.data('currentUserInfo') || {};
+ const currentUser = userSelect.currentUser || {};
+ const fieldName = $dropdown.data('fieldName');
+ const userName = currentUserInfo.name;
+ const userId = currentUserInfo.id || currentUser.id;
- const inputHtmlString = template(`
+ const inputHtmlString = template(`
<input type="hidden" name="<%- fieldName %>"
data-meta="<%- userName %>"
value="<%- userId %>" />
`)({ fieldName, userName, userId });
- if ($selectbox) {
- $dropdown.parent().before(inputHtmlString);
- } else {
- $dropdown.after(inputHtmlString);
+ if ($selectbox) {
+ $dropdown.parent().before(inputHtmlString);
+ } else {
+ $dropdown.after(inputHtmlString);
+ }
+ };
+
+ if ($block[0]) {
+ $block[0].addEventListener('assignYourself', assignYourself);
}
- };
- if ($block[0]) {
- $block[0].addEventListener('assignYourself', assignYourself);
- }
+ const getSelectedUserInputs = function () {
+ return $selectbox.find(`input[name="${$dropdown.data('fieldName')}"]`);
+ };
- const getSelectedUserInputs = function () {
- return $selectbox.find(`input[name="${$dropdown.data('fieldName')}"]`);
- };
-
- const getSelected = function () {
- return getSelectedUserInputs()
- .map((index, input) => parseInt(input.value, 10))
- .get();
- };
-
- const checkMaxSelect = function () {
- const maxSelect = $dropdown.data('maxSelect');
- if (maxSelect) {
- const selected = getSelected();
-
- if (selected.length > maxSelect) {
- const firstSelectedId = selected[0];
- const firstSelected = $dropdown
- .closest('.selectbox')
- .find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`);
-
- firstSelected.remove();
-
- if ($dropdown.hasClass(elsClassName)) {
- emitSidebarEvent('sidebar.removeReviewer', {
- id: firstSelectedId,
- });
- } else {
- emitSidebarEvent('sidebar.removeAssignee', {
- id: firstSelectedId,
- });
+ const getSelected = function () {
+ return getSelectedUserInputs()
+ .map((index, input) => parseInt(input.value, 10))
+ .get();
+ };
+
+ const checkMaxSelect = function () {
+ const maxSelect = $dropdown.data('maxSelect');
+ if (maxSelect) {
+ const selected = getSelected();
+
+ if (selected.length > maxSelect) {
+ const firstSelectedId = selected[0];
+ const firstSelected = $dropdown
+ .closest('.selectbox')
+ .find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`);
+
+ firstSelected.remove();
+
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.removeReviewer', {
+ id: firstSelectedId,
+ });
+ } else {
+ emitSidebarEvent('sidebar.removeAssignee', {
+ id: firstSelectedId,
+ });
+ }
}
}
- }
- };
-
- const getMultiSelectDropdownTitle = function (selectedUser, isSelected) {
- const selectedUsers = getSelected().filter((u) => u !== 0);
-
- const firstUser = getSelectedUserInputs()
- .map((index, input) => ({
- name: input.dataset.meta,
- value: parseInt(input.value, 10),
- }))
- .filter((u) => u.id !== 0)
- .get(0);
-
- if (selectedUsers.length === 0) {
- return s__('UsersSelect|Unassigned');
- } else if (selectedUsers.length === 1) {
- return firstUser.name;
- } else if (isSelected) {
- const otherSelected = selectedUsers.filter((s) => s !== selectedUser.id);
+ };
+
+ const getMultiSelectDropdownTitle = function (selectedUser, isSelected) {
+ const selectedUsers = getSelected().filter((u) => u !== 0);
+
+ const firstUser = getSelectedUserInputs()
+ .map((index, input) => ({
+ name: input.dataset.meta,
+ value: parseInt(input.value, 10),
+ }))
+ .filter((u) => u.id !== 0)
+ .get(0);
+
+ if (selectedUsers.length === 0) {
+ return s__('UsersSelect|Unassigned');
+ }
+ if (selectedUsers.length === 1) {
+ return firstUser.name;
+ }
+ if (isSelected) {
+ const otherSelected = selectedUsers.filter((s) => s !== selectedUser.id);
+ return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
+ name: selectedUser.name,
+ length: otherSelected.length,
+ });
+ }
return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
- name: selectedUser.name,
- length: otherSelected.length,
+ name: firstUser.name,
+ length: selectedUsers.length - 1,
});
- }
- return sprintf(s__('UsersSelect|%{name} + %{length} more'), {
- name: firstUser.name,
- length: selectedUsers.length - 1,
- });
- };
-
- $assignToMeLink.on('click', (e) => {
- e.preventDefault();
- $(e.currentTarget).hide();
-
- if ($dropdown.data('multiSelect')) {
- assignYourself();
- checkMaxSelect();
-
- const currentUserInfo = $dropdown.data('currentUserInfo');
- $dropdown
- .find('.dropdown-toggle-text')
- .text(getMultiSelectDropdownTitle(currentUserInfo))
- .removeClass('is-default');
- } else {
- const $input = $(`input[name="${$dropdown.data('fieldName')}"]`);
- $input.val(gon.current_user_id);
- selectedId = $input.val();
- $dropdown
- .find('.dropdown-toggle-text')
- .text(gon.current_user_fullname)
- .removeClass('is-default');
- }
- });
-
- $block.on('click', '.js-assign-yourself', (e) => {
- e.preventDefault();
- return assignTo(userSelect.currentUser.id);
- });
-
- assignTo = function (selected) {
- const data = {};
- data[abilityName] = {};
- data[abilityName].assignee_id = selected != null ? selected : null;
- $loading.removeClass('gl-display-none');
- $dropdown.trigger('loading.gl.dropdown');
-
- return axios.put(issueURL, data).then(({ data }) => {
- let user = {};
- let tooltipTitle;
- $dropdown.trigger('loaded.gl.dropdown');
- $loading.addClass('gl-display-none');
- if (data.assignee) {
- user = {
- name: data.assignee.name,
- username: data.assignee.username,
- avatar: data.assignee.avatar_url,
- };
- tooltipTitle = escape(user.name);
+ };
+
+ $assignToMeLink.on('click', (e) => {
+ e.preventDefault();
+ $(e.currentTarget).hide();
+
+ if ($dropdown.data('multiSelect')) {
+ assignYourself();
+ checkMaxSelect();
+
+ const currentUserInfo = $dropdown.data('currentUserInfo');
+ $dropdown
+ .find('.dropdown-toggle-text')
+ .text(getMultiSelectDropdownTitle(currentUserInfo))
+ .removeClass('is-default');
} else {
- user = {
- name: s__('UsersSelect|Unassigned'),
- username: '',
- avatar: '',
- };
- tooltipTitle = s__('UsersSelect|Assignee');
+ const $input = $(`input[name="${$dropdown.data('fieldName')}"]`);
+ $input.val(gon.current_user_id);
+ selectedId = $input.val();
+ $dropdown
+ .find('.dropdown-toggle-text')
+ .text(gon.current_user_fullname)
+ .removeClass('is-default');
}
- $value.html(assigneeTemplate(user));
- $collapsedSidebar.attr('title', tooltipTitle);
- fixTitle($collapsedSidebar);
+ });
- return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
+ $block.on('click', '.js-assign-yourself', (e) => {
+ e.preventDefault();
+ return assignTo(userSelect.currentUser.id);
});
- };
- collapsedAssigneeTemplate = template(
- `<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> ${spriteIcon(
- 'user',
- )} <% } %>`,
- );
- assigneeTemplate = template(
- `<% if (username) { %> <a class="author-link gl-font-weight-bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
+
+ assignTo = function (selected) {
+ const data = {};
+ data[abilityName] = {};
+ data[abilityName].assignee_id = selected != null ? selected : null;
+ $loading.removeClass('gl-display-none');
+ $dropdown.trigger('loading.gl.dropdown');
+
+ return axios.put(issueURL, data).then(({ data }) => {
+ let user = {};
+ let tooltipTitle;
+ $dropdown.trigger('loaded.gl.dropdown');
+ $loading.addClass('gl-display-none');
+ if (data.assignee) {
+ user = {
+ name: data.assignee.name,
+ username: data.assignee.username,
+ avatar: data.assignee.avatar_url,
+ };
+ tooltipTitle = escape(user.name);
+ } else {
+ user = {
+ name: s__('UsersSelect|Unassigned'),
+ username: '',
+ avatar: '',
+ };
+ tooltipTitle = s__('UsersSelect|Assignee');
+ }
+ $value.html(assigneeTemplate(user));
+ $collapsedSidebar.attr('title', tooltipTitle);
+ fixTitle($collapsedSidebar);
+
+ return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
+ });
+ };
+ collapsedAssigneeTemplate = template(
+ `<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> ${spriteIcon(
+ 'user',
+ )} <% } %>`,
+ );
+ assigneeTemplate = template(
+ `<% if (username) { %> <a class="author-link gl-font-weight-bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
${sprintf(s__('UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}'), {
openingTag: '<a href="#" class="js-assign-yourself">',
closingTag: '</a>',
})}</span> <% } %>`,
- );
- return initDeprecatedJQueryDropdown($dropdown, {
- showMenuAbove,
- data(term, callback) {
- return userSelect.users(term, options, (users) => {
- // GitLabDropdownFilter returns this.instance
- // GitLabDropdownRemote returns this.options.instance
- const deprecatedJQueryDropdown = this.instance || this.options.instance;
- deprecatedJQueryDropdown.options.processData(term, users, callback);
- });
- },
- processData(term, dataArg, callback) {
- // Sometimes the `dataArg` can contain special dropdown items like
- // dividers which we don't want to consider here.
- const data = dataArg.filter((x) => !x.type);
-
- let users = data;
-
- // Only show assigned user list when there is no search term
- if ($dropdown.hasClass('js-multiselect') && term.length === 0) {
- const selectedInputs = getSelectedUserInputs();
-
- // Potential duplicate entries when dealing with issue board
- // because issue board is also managed by vue
- const selectedUsers = uniqBy(selectedInputs, (a) => a.value)
- .filter((input) => {
- const userId = parseInt(input.value, 10);
- const inUsersArray = users.find((u) => u.id === userId);
-
- return !inUsersArray && userId !== 0;
- })
- .map((input) => {
- const userId = parseInt(input.value, 10);
- const { avatarUrl, avatar_url, name, username, canMerge } = input.dataset;
- return {
- avatar_url: avatarUrl || avatar_url || gon.default_avatar_url,
- id: userId,
- name,
- username,
- can_merge: parseBoolean(canMerge),
- };
- });
+ );
+
+ return initDeprecatedJQueryDropdown($dropdown, {
+ showMenuAbove,
+ data(term, callback) {
+ return userSelect.users(term, options, (users) => {
+ // GitLabDropdownFilter returns this.instance
+ // GitLabDropdownRemote returns this.options.instance
+ const deprecatedJQueryDropdown = this.instance || this.options.instance;
+ deprecatedJQueryDropdown.options.processData(term, users, callback);
+ });
+ },
+ processData(term, dataArg, callback) {
+ // Sometimes the `dataArg` can contain special dropdown items like
+ // dividers which we don't want to consider here.
+ const data = dataArg.filter((x) => !x.type);
+
+ let users = data;
+
+ // Only show assigned user list when there is no search term
+ if ($dropdown.hasClass('js-multiselect') && term.length === 0) {
+ const selectedInputs = getSelectedUserInputs();
+
+ // Potential duplicate entries when dealing with issue board
+ // because issue board is also managed by vue
+ const selectedUsers = uniqBy(selectedInputs, (a) => a.value)
+ .filter((input) => {
+ const userId = parseInt(input.value, 10);
+ const inUsersArray = users.find((u) => u.id === userId);
+
+ return !inUsersArray && userId !== 0;
+ })
+ .map((input) => {
+ const userId = parseInt(input.value, 10);
+ const { avatarUrl, avatar_url, name, username, canMerge } = input.dataset;
+ return {
+ avatar_url: avatarUrl || avatar_url || gon.default_avatar_url,
+ id: userId,
+ name,
+ username,
+ can_merge: parseBoolean(canMerge),
+ };
+ });
- users = data.concat(selectedUsers);
- }
+ users = data.concat(selectedUsers);
+ }
- let anyUser;
- let index;
- let len;
- let name;
- let obj;
- let showDivider;
- if (term.length === 0) {
- showDivider = 0;
- if (firstUser) {
- // Move current user to the front of the list
- for (index = 0, len = users.length; index < len; index += 1) {
- obj = users[index];
- if (obj.username === firstUser) {
- users.splice(index, 1);
- users.unshift(obj);
- break;
+ let anyUser;
+ let index;
+ let len;
+ let name;
+ let obj;
+ let showDivider;
+ if (term.length === 0) {
+ showDivider = 0;
+ if (firstUser) {
+ // Move current user to the front of the list
+ for (index = 0, len = users.length; index < len; index += 1) {
+ obj = users[index];
+ if (obj.username === firstUser) {
+ users.splice(index, 1);
+ users.unshift(obj);
+ break;
+ }
}
}
- }
- if (showNullUser) {
- showDivider += 1;
- users.unshift({
- beforeDivider: true,
- name: s__('UsersSelect|Unassigned'),
- id: 0,
- });
- }
- if (showAnyUser) {
- showDivider += 1;
- name = showAnyUser;
- if (name === true) {
- name = s__('UsersSelect|Any User');
+ if (showNullUser) {
+ showDivider += 1;
+ users.unshift({
+ beforeDivider: true,
+ name: s__('UsersSelect|Unassigned'),
+ id: 0,
+ });
}
- anyUser = {
- beforeDivider: true,
- name,
- id: null,
- };
- users.unshift(anyUser);
- }
-
- if (showDivider) {
- users.splice(showDivider, 0, { type: 'divider' });
- }
-
- if ($dropdown.hasClass('js-multiselect')) {
- const selected = getSelected().filter((i) => i !== 0);
-
- if ($dropdown.data('showSuggested')) {
- const suggested = this.suggestedUsers(users);
- if (suggested.length) {
- users = users.filter(
- (u) => !u.suggested || (u.suggested && selected.indexOf(u.id) !== -1),
- );
- users.splice(showDivider + 1, 0, ...suggested);
+ if (showAnyUser) {
+ showDivider += 1;
+ name = showAnyUser;
+ if (name === true) {
+ name = s__('UsersSelect|Any User');
}
+ anyUser = {
+ beforeDivider: true,
+ name,
+ id: null,
+ };
+ users.unshift(anyUser);
}
- if (selected.length > 0) {
- if ($dropdown.data('dropdownHeader')) {
- showDivider += 1;
- users.splice(showDivider, 0, {
- type: 'header',
- content: $dropdown.data('dropdownHeader'),
- });
+ if (showDivider) {
+ users.splice(showDivider, 0, { type: 'divider' });
+ }
+
+ if ($dropdown.hasClass('js-multiselect')) {
+ const selected = getSelected().filter((i) => i !== 0);
+
+ if ($dropdown.data('showSuggested')) {
+ const suggested = this.suggestedUsers(users);
+ if (suggested.length) {
+ users = users.filter(
+ (u) => !u.suggested || (u.suggested && selected.indexOf(u.id) !== -1),
+ );
+ users.splice(showDivider + 1, 0, ...suggested);
+ }
}
- const selectedUsers = users
- .filter((u) => selected.indexOf(u.id) !== -1)
- .sort((a, b) => a.name > b.name);
+ if (selected.length > 0) {
+ if ($dropdown.data('dropdownHeader')) {
+ showDivider += 1;
+ users.splice(showDivider, 0, {
+ type: 'header',
+ content: $dropdown.data('dropdownHeader'),
+ });
+ }
- users = users.filter((u) => selected.indexOf(u.id) === -1);
+ const selectedUsers = users
+ .filter((u) => selected.indexOf(u.id) !== -1)
+ .sort((a, b) => a.name > b.name);
- selectedUsers.forEach((selectedUser) => {
- showDivider += 1;
- users.splice(showDivider, 0, selectedUser);
- });
+ users = users.filter((u) => selected.indexOf(u.id) === -1);
- users.splice(showDivider + 1, 0, { type: 'divider' });
+ selectedUsers.forEach((selectedUser) => {
+ showDivider += 1;
+ users.splice(showDivider, 0, selectedUser);
+ });
+
+ users.splice(showDivider + 1, 0, { type: 'divider' });
+ }
}
}
- }
- callback(users);
- if (showMenuAbove) {
- $dropdown.data('deprecatedJQueryDropdown').positionMenuAbove();
- }
- },
- suggestedUsers(users) {
- const selected = getSelected().filter((i) => i !== 0);
- const suggestedUsers = users.filter((u) => u.suggested && selected.indexOf(u.id) === -1);
-
- if (!suggestedUsers.length) return [];
-
- const items = [
- {
- type: 'header',
- content: suggestedReviewersHeaderTemplate({
- header: $dropdown.data('suggestedReviewersHeader'),
- }),
- },
- ...suggestedUsers,
- { type: 'header', content: $dropdown.data('allMembersHeader') },
- ];
- return items;
- },
- filterable: true,
- filterRemote: true,
- search: {
- fields: ['name', 'username'],
- },
- selectable: true,
- fieldName: $dropdown.data('fieldName'),
- toggleLabel(selected, el, deprecatedJQueryDropdown) {
- const inputValue = deprecatedJQueryDropdown.filterInput.val();
-
- if (this.multiSelect && inputValue === '') {
- // Remove non-users from the fullData array
- const users = deprecatedJQueryDropdown.filteredFullData();
- const callback = deprecatedJQueryDropdown.parseData.bind(deprecatedJQueryDropdown);
-
- // Update the data model
- this.processData(inputValue, users, callback);
- }
+ callback(users);
+ if (showMenuAbove) {
+ $dropdown.data('deprecatedJQueryDropdown').positionMenuAbove();
+ }
+ },
+ suggestedUsers(users) {
+ const selected = getSelected().filter((i) => i !== 0);
+ const suggestedUsers = users.filter((u) => u.suggested && selected.indexOf(u.id) === -1);
+
+ if (!suggestedUsers.length) return [];
+
+ const items = [
+ {
+ type: 'header',
+ content: suggestedReviewersHeaderTemplate({
+ header: $dropdown.data('suggestedReviewersHeader'),
+ }),
+ },
+ ...suggestedUsers,
+ { type: 'header', content: $dropdown.data('allMembersHeader') },
+ ];
+ return items;
+ },
+ filterable: true,
+ filterRemote: true,
+ search: {
+ fields: ['name', 'username'],
+ },
+ selectable: true,
+ fieldName: $dropdown.data('fieldName'),
+ toggleLabel(selected, el, deprecatedJQueryDropdown) {
+ const inputValue = deprecatedJQueryDropdown.filterInput.val();
+
+ if (this.multiSelect && inputValue === '') {
+ // Remove non-users from the fullData array
+ const users = deprecatedJQueryDropdown.filteredFullData();
+ const callback = deprecatedJQueryDropdown.parseData.bind(deprecatedJQueryDropdown);
+
+ // Update the data model
+ this.processData(inputValue, users, callback);
+ }
- if (this.multiSelect) {
- return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active'));
- }
+ if (this.multiSelect) {
+ return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active'));
+ }
- if (selected && 'id' in selected && $(el).hasClass('is-active')) {
- $dropdown.find('.dropdown-toggle-text').removeClass('is-default');
- if (selected.text) {
- return selected.text;
+ if (selected && 'id' in selected && $(el).hasClass('is-active')) {
+ $dropdown.find('.dropdown-toggle-text').removeClass('is-default');
+ if (selected.text) {
+ return selected.text;
+ }
+ return selected.name;
}
- return selected.name;
- }
- $dropdown.find('.dropdown-toggle-text').addClass('is-default');
- return defaultLabel;
- },
- defaultLabel,
- hidden() {
- if ($dropdown.hasClass('js-multiselect')) {
- if ($dropdown.hasClass(elsClassName)) {
- if (!$dropdown.closest('.merge-request-form').length) {
- $dropdown.data('deprecatedJQueryDropdown').clearMenu();
- $dropdown.closest('.selectbox').children('input[type="hidden"]').remove();
+ $dropdown.find('.dropdown-toggle-text').addClass('is-default');
+ return defaultLabel;
+ },
+ defaultLabel,
+ hidden() {
+ if ($dropdown.hasClass('js-multiselect')) {
+ if ($dropdown.hasClass(elsClassName)) {
+ if (!$dropdown.closest('.merge-request-form').length) {
+ $dropdown.data('deprecatedJQueryDropdown').clearMenu();
+ $dropdown.closest('.selectbox').children('input[type="hidden"]').remove();
+ }
+ emitSidebarEvent('sidebar.saveReviewers');
+ } else {
+ emitSidebarEvent('sidebar.saveAssignees');
}
- emitSidebarEvent('sidebar.saveReviewers');
- } else {
- emitSidebarEvent('sidebar.saveAssignees');
}
- }
- if (!$dropdown.data('alwaysShowSelectbox')) {
- $selectbox.hide();
+ if (!$dropdown.data('alwaysShowSelectbox')) {
+ $selectbox.hide();
- // Recalculate where .value is because vue might have changed it
- $block = $selectbox.closest('.block');
- $value = $block.find('.value');
- // display:block overrides the hide-collapse rule
- $value.css('display', '');
- }
+ // Recalculate where .value is because vue might have changed it
+ $block = $selectbox.closest('.block');
+ $value = $block.find('.value');
+ // display:block overrides the hide-collapse rule
+ $value.css('display', '');
+ }
- $('.dropdown-input-field', $block).val('');
- },
- multiSelect: $dropdown.hasClass('js-multiselect'),
- inputMeta: $dropdown.data('inputMeta'),
- clicked(options) {
- const { $el, e, isMarking } = options;
- const user = options.selectedObj;
+ $('.dropdown-input-field', $block).val('');
+ },
+ multiSelect: $dropdown.hasClass('js-multiselect'),
+ inputMeta: $dropdown.data('inputMeta'),
+ clicked(options) {
+ const { $el, e, isMarking } = options;
+ const user = options.selectedObj;
- dispose($el);
+ dispose($el);
- if ($dropdown.hasClass('js-multiselect')) {
- const isActive = $el.hasClass('is-active');
- const previouslySelected = $dropdown
- .closest('.selectbox')
- .find(`input[name='${$dropdown.data('fieldName')}'][value!=0]`);
+ if ($dropdown.hasClass('js-multiselect')) {
+ const isActive = $el.hasClass('is-active');
+ const previouslySelected = $dropdown
+ .closest('.selectbox')
+ .find(`input[name='${$dropdown.data('fieldName')}'][value!=0]`);
- // Enables support for limiting the number of users selected
- // Automatically removes the first on the list if more users are selected
- checkMaxSelect();
+ // Enables support for limiting the number of users selected
+ // Automatically removes the first on the list if more users are selected
+ checkMaxSelect();
- if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
- // Unassigned selected
- previouslySelected.each((index, element) => {
- element.remove();
- });
- if ($dropdown.hasClass(elsClassName)) {
- emitSidebarEvent('sidebar.removeAllReviewers');
+ if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
+ // Unassigned selected
+ previouslySelected.each((index, element) => {
+ element.remove();
+ });
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.removeAllReviewers');
+ } else {
+ emitSidebarEvent('sidebar.removeAllAssignees');
+ }
+ } else if (isActive) {
+ // user selected
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.addReviewer', user);
+ } else {
+ emitSidebarEvent('sidebar.addAssignee', user);
+ }
+
+ // Remove unassigned selection (if it was previously selected)
+ const unassignedSelected = $dropdown
+ .closest('.selectbox')
+ .find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
+
+ if (unassignedSelected) {
+ unassignedSelected.remove();
+ }
} else {
- emitSidebarEvent('sidebar.removeAllAssignees');
+ if (previouslySelected.length === 0) {
+ // Select unassigned because there is no more selected users
+ this.addInput($dropdown.data('fieldName'), 0, {});
+ }
+
+ // User unselected
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.removeReviewer', user);
+ } else {
+ emitSidebarEvent('sidebar.removeAssignee', user);
+ }
}
- } else if (isActive) {
- // user selected
- if ($dropdown.hasClass(elsClassName)) {
- emitSidebarEvent('sidebar.addReviewer', user);
+
+ if (getSelected().find((u) => u === gon.current_user_id)) {
+ $assignToMeLink.hide();
} else {
- emitSidebarEvent('sidebar.addAssignee', user);
+ $assignToMeLink.show();
}
+ }
- // Remove unassigned selection (if it was previously selected)
- const unassignedSelected = $dropdown
- .closest('.selectbox')
- .find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
+ const page = $('body').attr('data-page');
+ const isIssueIndex = page === 'projects:issues:index';
+ const isMRIndex = page === page && page === 'projects:merge_requests:index';
+ if (
+ $dropdown.hasClass('js-filter-bulk-update') ||
+ $dropdown.hasClass('js-issuable-form-dropdown')
+ ) {
+ e.preventDefault();
- if (unassignedSelected) {
- unassignedSelected.remove();
- }
- } else {
- if (previouslySelected.length === 0) {
- // Select unassigned because there is no more selected users
- this.addInput($dropdown.data('fieldName'), 0, {});
- }
+ const isSelecting = user.id !== selectedId;
+ selectedId = isSelecting ? user.id : selectedIdDefault;
- // User unselected
- if ($dropdown.hasClass(elsClassName)) {
- emitSidebarEvent('sidebar.removeReviewer', user);
+ if (selectedId === gon.current_user_id) {
+ $('.assign-to-me-link').hide();
} else {
- emitSidebarEvent('sidebar.removeAssignee', user);
+ $('.assign-to-me-link').show();
}
+ return;
}
-
- if (getSelected().find((u) => u === gon.current_user_id)) {
- $assignToMeLink.hide();
- } else {
- $assignToMeLink.show();
+ if (handleClick) {
+ e.preventDefault();
+ handleClick(user, isMarking);
+ } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
+ return Issuable.filterResults($dropdown.closest('form'));
+ } else if ($dropdown.hasClass('js-filter-submit')) {
+ return $dropdown.closest('form').submit();
+ } else if (!$dropdown.hasClass('js-multiselect')) {
+ const selected = $dropdown
+ .closest('.selectbox')
+ .find(`input[name='${$dropdown.data('fieldName')}']`)
+ .val();
+ return assignTo(selected);
}
- }
-
- const page = $('body').attr('data-page');
- const isIssueIndex = page === 'projects:issues:index';
- const isMRIndex = page === page && page === 'projects:merge_requests:index';
- if (
- $dropdown.hasClass('js-filter-bulk-update') ||
- $dropdown.hasClass('js-issuable-form-dropdown')
- ) {
- e.preventDefault();
- const isSelecting = user.id !== selectedId;
- selectedId = isSelecting ? user.id : selectedIdDefault;
+ // Automatically close dropdown after assignee is selected
+ // since CE has no multiple assignees
+ // EE does not have a max-select
+ if ($dropdown.data('maxSelect') && getSelected().length === $dropdown.data('maxSelect')) {
+ // Close the dropdown
+ $dropdown.dropdown('toggle');
+ }
+ },
+ id(user) {
+ return user.id;
+ },
+ opened(e) {
+ const $el = $(e.currentTarget);
+ const selected = getSelected();
+ $el.find('.is-active').removeClass('is-active');
+
+ function highlightSelected(id) {
+ $el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
+ }
- if (selectedId === gon.current_user_id) {
- $('.assign-to-me-link').hide();
+ if (selected.length > 0) {
+ getSelected().forEach((selectedId) => highlightSelected(selectedId));
} else {
- $('.assign-to-me-link').show();
+ highlightSelected(selectedId);
}
- return;
- }
- if (handleClick) {
- e.preventDefault();
- handleClick(user, isMarking);
- } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
- return Issuable.filterResults($dropdown.closest('form'));
- } else if ($dropdown.hasClass('js-filter-submit')) {
- return $dropdown.closest('form').submit();
- } else if (!$dropdown.hasClass('js-multiselect')) {
- const selected = $dropdown
- .closest('.selectbox')
- .find(`input[name='${$dropdown.data('fieldName')}']`)
- .val();
- return assignTo(selected);
- }
+ },
+ updateLabel: $dropdown.data('dropdownTitle'),
+ renderRow(user) {
+ const username = user.username ? `@${user.username}` : '';
+ const avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
- // Automatically close dropdown after assignee is selected
- // since CE has no multiple assignees
- // EE does not have a max-select
- if ($dropdown.data('maxSelect') && getSelected().length === $dropdown.data('maxSelect')) {
- // Close the dropdown
- $dropdown.dropdown('toggle');
- }
- },
- id(user) {
- return user.id;
- },
- opened(e) {
- const $el = $(e.currentTarget);
- const selected = getSelected();
- $el.find('.is-active').removeClass('is-active');
-
- function highlightSelected(id) {
- $el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
- }
-
- if (selected.length > 0) {
- getSelected().forEach((selectedId) => highlightSelected(selectedId));
- } else {
- highlightSelected(selectedId);
- }
- },
- updateLabel: $dropdown.data('dropdownTitle'),
- renderRow(user) {
- const username = user.username ? `@${user.username}` : '';
- const avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
-
- let selected = false;
+ let selected = false;
- if (this.multiSelect) {
- selected = getSelected().find((u) => user.id === u);
+ if (this.multiSelect) {
+ selected = getSelected().find((u) => user.id === u);
- const { fieldName } = this;
- const field = $dropdown
- .closest('.selectbox')
- .find(`input[name='${fieldName}'][value='${user.id}']`);
+ const { fieldName } = this;
+ const field = $dropdown
+ .closest('.selectbox')
+ .find(`input[name='${fieldName}'][value='${user.id}']`);
- if (field.length) {
- selected = true;
+ if (field.length) {
+ selected = true;
+ }
+ } else {
+ selected = user.id === selectedId;
}
- } else {
- selected = user.id === selectedId;
- }
- let img = '';
- if (user.beforeDivider != null) {
- `<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${escape(
- user.name,
- )}</a></li>`;
- } else {
- // 0 margin, because it's now handled by a wrapper
- img = `<img src='${avatar}' class='avatar avatar-inline gl-m-0!' width='32' />`;
- }
+ let img = '';
+ if (user.beforeDivider != null) {
+ `<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${escape(
+ user.name,
+ )}</a></li>`;
+ } else {
+ // 0 margin, because it's now handled by a wrapper
+ img = `<img src='${avatar}' class='avatar avatar-inline gl-m-0!' width='32' />`;
+ }
- return userSelect.renderRow(
- options.issuableType,
- user,
- selected,
- username,
- img,
- elsClassName,
- );
- },
- });
- });
+ return userSelect.renderRow(
+ options.issuableType,
+ user,
+ selected,
+ username,
+ img,
+ elsClassName,
+ );
+ },
+ })
+ .get()
+ .map((dropdown) => dropdown.GitLabDropdownInstance);
+ })
+ .get();
}
// Return users list. Filtered by query
diff --git a/app/assets/javascripts/visibility_level/constants.js b/app/assets/javascripts/visibility_level/constants.js
index e30982985b3..0d9ededc550 100644
--- a/app/assets/javascripts/visibility_level/constants.js
+++ b/app/assets/javascripts/visibility_level/constants.js
@@ -1,4 +1,4 @@
-import { __ } from '~/locale';
+import { __, s__ } from '~/locale';
export const VISIBILITY_LEVEL_PRIVATE_STRING = 'private';
export const VISIBILITY_LEVEL_INTERNAL_STRING = 'internal';
@@ -45,6 +45,12 @@ export const PROJECT_VISIBILITY_TYPE = {
),
};
+export const ORGANIZATION_VISIBILITY_TYPE = {
+ [VISIBILITY_LEVEL_PUBLIC_STRING]: s__(
+ 'Organization|Public - The organization can be accessed without any authentication.',
+ ),
+};
+
export const VISIBILITY_TYPE_ICON = {
[VISIBILITY_LEVEL_PUBLIC_STRING]: 'earth',
[VISIBILITY_LEVEL_INTERNAL_STRING]: 'shield',
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue b/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue
index 952ff9b18e9..c49c1316b1b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue
@@ -4,32 +4,26 @@ import {
GlPopover,
GlSprintf,
GlLink,
- GlDropdown,
- GlDropdownItem,
+ GlDisclosureDropdown,
GlTooltipDirective,
} from '@gitlab/ui';
-import { sprintf, __ } from '~/locale';
export default {
+ name: 'ActionButtons',
components: {
GlButton,
GlPopover,
GlSprintf,
GlLink,
- GlDropdown,
- GlDropdownItem,
+ GlDisclosureDropdown,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
- widget: {
- type: String,
- required: false,
- default: '',
- },
tertiaryButtons: {
type: Array,
+ // fix `spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js` before making this required
required: false,
default: () => [],
},
@@ -41,17 +35,26 @@ export default {
};
},
computed: {
- dropdownLabel() {
- if (!this.widget) return undefined;
-
- return sprintf(__('%{widget} options'), { widget: this.widget });
- },
hasOneOption() {
return this.tertiaryButtons.length === 1;
},
hasMultipleOptions() {
return this.tertiaryButtons.length > 1;
},
+ dropdownItems() {
+ return this.tertiaryButtons.map((item) => {
+ return {
+ ...item,
+ text: item.text,
+ href: item.href,
+ extraAttrs: {
+ dataClipboardText: item.dataClipboardText,
+ dataMethod: item.dataMethod,
+ target: item.target,
+ },
+ };
+ });
+ },
},
methods: {
onClickAction(action) {
@@ -135,32 +138,18 @@ export default {
</span>
</template>
<template v-if="hasMultipleOptions">
- <gl-dropdown
+ <gl-disclosure-dropdown
v-gl-tooltip
+ :items="dropdownItems"
:title="__('Options')"
- :text="dropdownLabel"
icon="ellipsis_v"
no-caret
category="tertiary"
- right
- lazy
text-sr-only
size="small"
- toggle-class="gl-p-2!"
class="gl-display-block gl-md-display-none!"
- >
- <gl-dropdown-item
- v-for="(btn, index) in tertiaryButtons"
- :key="index"
- :href="btn.href"
- :target="btn.target"
- :data-clipboard-text="btn.dataClipboardText"
- :data-method="btn.dataMethod"
- @click="onClickAction(btn)"
- >
- {{ btn.text }}
- </gl-dropdown-item>
- </gl-dropdown>
+ @action="onClickAction"
+ />
<span v-for="(btn, index) in tertiaryButtons" :key="index">
<gl-button
:id="btn.id"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue b/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue
index 5090081d281..3b62345b969 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/added_commit_message.vue
@@ -70,7 +70,8 @@ export default {
message() {
if (this.state === STATUS_CLOSED) {
return s__('mrWidgetCommitsAdded|The changes were not merged into %{targetBranch}.');
- } else if (this.isMerged) {
+ }
+ if (this.isMerged) {
return s__(
'mrWidgetCommitsAdded|Changes merged into %{targetBranch} with %{mergeCommitSha}%{squashedCommits}.',
);
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue
index 95fa01c23f1..4ed470440cc 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue
@@ -131,7 +131,8 @@ export default {
variant: 'confirm',
action: () => this.approve(),
};
- } else if (this.showUnapprove) {
+ }
+ if (this.showUnapprove) {
return {
text: s__('mrWidget|Revoke approval'),
variant: 'default',
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue
index e79d2db4b5a..7a3dd4ca35e 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue
@@ -1,9 +1,7 @@
<script>
import { createAlert } from '~/alert';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
-import { visitUrl } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../../event_hub';
import MRWidgetService from '../../services/mr_widget_service';
import {
@@ -25,7 +23,6 @@ export default {
DeploymentActionButton,
DeploymentViewButton,
},
- mixins: [glFeatureFlagsMixin()],
props: {
computedDeploymentStatus: {
type: String,
@@ -71,10 +68,7 @@ export default {
return this.deployment.details?.playable_build?.play_path;
},
redeployPath() {
- if (this.redeployMrWidgetFeatureFlagEnabled) {
- return this.deployment.retry_url;
- }
- return this.deployment.details?.playable_build?.retry_path;
+ return this.deployment.retry_url;
},
stopUrl() {
return this.deployment.stop_url;
@@ -82,13 +76,8 @@ export default {
environmentAvailable() {
return Boolean(this.deployment.environment_available);
},
- redeployMrWidgetFeatureFlagEnabled() {
- return this.glFeatures.reviewAppsRedeployMrWidget;
- },
showDeploymentActionButton() {
- return (
- this.redeployPath && !this.environmentAvailable && this.redeployMrWidgetFeatureFlagEnabled
- );
+ return this.redeployPath && !this.environmentAvailable;
},
},
actionsConfiguration: {
@@ -137,16 +126,6 @@ export default {
this.actionInProgress = actionName;
MRWidgetService.executeInlineAction(endpoint)
- .then((resp) => {
- if (this.redeployMrWidgetFeatureFlagEnabled) {
- return;
- }
-
- const redirectUrl = resp?.data?.redirect_url;
- if (redirectUrl) {
- visitUrl(redirectUrl);
- }
- })
.catch(() => {
createAlert({
message: errorMessage,
@@ -184,17 +163,6 @@ export default {
>
<span>{{ $options.actionsConfiguration[constants.DEPLOYING].buttonText }}</span>
</deployment-action-button>
- <deployment-action-button
- v-if="canBeManuallyRedeployed && !redeployMrWidgetFeatureFlagEnabled"
- :action-in-progress="actionInProgress"
- :actions-configuration="$options.actionsConfiguration[constants.REDEPLOYING]"
- :computed-deployment-status="computedDeploymentStatus"
- :icon="$options.btnIcons.repeat"
- container-classes="js-manual-redeploy-action"
- @click="redeploy"
- >
- <span>{{ $options.actionsConfiguration[constants.REDEPLOYING].buttonText }}</span>
- </deployment-action-button>
<deployment-view-button
v-if="hasExternalUrls && environmentAvailable"
:app-button-text="appButtonText"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/memory_usage.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/memory_usage.vue
index c7d34d45f06..efe71ed569a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/memory_usage.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/memory_usage.vue
@@ -58,7 +58,8 @@ export default {
return s__(
'mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} increased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB',
);
- } else if (memoryTo < memoryFrom) {
+ }
+ if (memoryTo < memoryFrom) {
return s__(
'mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} decreased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB',
);
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
index 31bf62b7e52..3e2f3ab4103 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
@@ -305,11 +305,7 @@ export default {
</script>
<template>
- <section
- class="media-section"
- data-testid="widget-extension"
- data-qa-selector="mr_widget_extension"
- >
+ <section class="media-section" data-testid="widget-extension">
<state-container
:status="statusIconName"
:is-loading="isLoadingSummary"
@@ -346,11 +342,7 @@ export default {
</template>
</template>
</div>
- <actions
- :widget="$options.label || $options.name"
- :tertiary-buttons="tertiaryActionsButtons"
- @clickedAction="onClickedAction"
- />
+ <actions :tertiary-buttons="tertiaryActionsButtons" @clickedAction="onClickedAction" />
<div
v-if="isCollapsible"
class="gl-border-l-1 gl-border-l-solid gl-border-gray-100 gl-ml-3 gl-pl-3 gl-h-6"
@@ -363,7 +355,6 @@ export default {
:icon="isCollapsed ? 'chevron-lg-down' : 'chevron-lg-up'"
category="tertiary"
data-testid="toggle-button"
- data-qa-selector="toggle_button"
size="small"
@click="toggleCollapsed"
/>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue
index fa369d23b6c..5f0fd973e84 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/child_content.vue
@@ -108,7 +108,6 @@ export default {
</gl-badge>
</div>
<actions
- :widget="widgetLabel"
:tertiary-buttons="data.actions"
class="gl-ml-auto gl-pl-3"
@clickedAction="onClickedAction"
@@ -128,7 +127,6 @@ export default {
:modal-id="modalId"
:level="3"
data-testid="child-content"
- data-qa-selector="child_content"
@clickedAction="onClickedAction"
/>
</li>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js
index 4f8f8d6cb58..b6bcc68e5e0 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js
@@ -8,8 +8,10 @@ import {
function simplifyWidgetName(componentName) {
const noWidget = componentName.replace(/^Widget/, '');
+ const camelName = noWidget.charAt(0).toLowerCase() + noWidget.slice(1);
+ const tierlessName = camelName.replace(/(CE|EE)$/, '');
- return noWidget.charAt(0).toLowerCase() + noWidget.slice(1);
+ return tierlessName;
}
function baseRedisEventName(extensionName) {
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js
index 757178ee336..83f5c1490e2 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/utils.js
@@ -65,11 +65,8 @@ const createText = (text) => {
export const generateText = (text) => {
if (typeof text === 'string') {
return createText(escapeText(text));
- } else if (
- typeof text === 'object' &&
- typeof text.text === 'string' &&
- typeof text.href === 'string'
- ) {
+ }
+ if (typeof text === 'object' && typeof text.text === 'string' && typeof text.href === 'string') {
return createText(
`${
text.prependText ? `${escapeText(text.prependText)} ` : ''
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
index e94e0fbe6dc..bfcd4610379 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
@@ -11,9 +11,9 @@ import {
import SafeHtml from '~/vue_shared/directives/safe_html';
import { s__, n__ } from '~/locale';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { keepLatestDownstreamPipelines } from '~/pipelines/components/parsing_utils';
-import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import { keepLatestDownstreamPipelines } from '~/ci/pipeline_details/utils/parsing_utils';
+import PipelineArtifacts from '~/ci/pipelines_page/components/pipelines_artifacts.vue';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import { MT_MERGE_STRATEGY } from '../constants';
@@ -183,7 +183,7 @@ export default {
v-gl-tooltip
:href="ciTroubleshootingDocsPath"
target="_blank"
- :title="__('About this feature')"
+ :title="__('Get more information about troubleshooting pipelines')"
class="gl-display-flex gl-align-items-center gl-ml-2"
>
<gl-icon
@@ -205,9 +205,7 @@ export default {
data-qa-selector="merge_request_pipeline_info_content"
class="gl-display-flex gl-flex-wrap gl-align-items-center gl-justify-content-space-between"
>
- <p
- class="mr-pipeline-title gl-m-0! gl-mr-3! gl-font-weight-bold gl-line-height-32 gl-text-gray-900"
- >
+ <p class="mr-pipeline-title gl-m-0! gl-mr-3! gl-font-weight-bold gl-text-gray-900">
{{ pipeline.details.event_type_name }}
<gl-link
:href="pipeline.path"
@@ -253,7 +251,7 @@ export default {
v-safe-html="sourceBranchLink"
:title="sourceBranch"
truncate-target="child"
- class="label-branch label-truncate gl-font-weight-normal gl-vertical-align-text-bottom"
+ class="label-branch label-truncate gl-font-weight-normal"
/>
</template>
<template v-if="finishedAt">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
index 400759aa086..4f39bd1d972 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/commits_header.vue
@@ -38,7 +38,7 @@ export default {
},
modifyLinkMessage() {
if (this.isFastForwardEnabled) return __('Modify commit message');
- else if (this.isSquashEnabled) return __('Modify commit messages');
+ if (this.isSquashEnabled) return __('Modify commit messages');
return __('Modify merge commit');
},
ariaLabel() {
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue
index 61eec503951..bf2c5e52184 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue
@@ -30,9 +30,11 @@ export default {
failedText() {
if (this.mr.approvals && !this.mr.isApproved) {
return this.$options.i18n.approvalNeeded;
- } else if (this.mr.detailedMergeStatus === DETAILED_MERGE_STATUS.BLOCKED_STATUS) {
+ }
+ if (this.mr.detailedMergeStatus === DETAILED_MERGE_STATUS.BLOCKED_STATUS) {
return this.$options.i18n.blockingMergeRequests;
- } else if (this.mr.detailedMergeStatus === DETAILED_MERGE_STATUS.EXTERNAL_STATUS_CHECKS) {
+ }
+ if (this.mr.detailedMergeStatus === DETAILED_MERGE_STATUS.EXTERNAL_STATUS_CHECKS) {
return this.$options.i18n.externalStatusChecksFailed;
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
index 7071759b8bb..0ce8389579d 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
@@ -488,7 +488,7 @@ export default {
mergeAndSquashCommitTemplatesHintText: s__(
'mrWidget|To change these default messages, edit the templates for both the merge and squash commit messages. %{linkStart}Learn more%{linkEnd}.',
),
- sourceDivergedFromTargetText: s__('mrWidget|The source branch is %{link} the target branch'),
+ sourceDivergedFromTargetText: s__('mrWidget|The source branch is %{link} the target branch.'),
divergedCommits: (count) => n__('%d commit behind', '%d commits behind', count),
},
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue
index 9bb39ba22e0..8249dffcc27 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue
@@ -5,6 +5,7 @@ export default {
import(
'~/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue'
),
+ MrTestReportWidget: () => import('~/vue_merge_request_widget/extensions/test_report/index.vue'),
MrTerraformWidget: () => import('~/vue_merge_request_widget/extensions/terraform/index.vue'),
MrCodeQualityWidget: () =>
import('~/vue_merge_request_widget/extensions/code_quality/index.vue'),
@@ -18,6 +19,10 @@ export default {
},
computed: {
+ testReportWidget() {
+ return this.mr.testResultsPath && 'MrTestReportWidget';
+ },
+
terraformPlansWidget() {
return this.mr.terraformReportsPath && 'MrTerraformWidget';
},
@@ -27,9 +32,12 @@ export default {
},
widgets() {
- return [this.codeQualityWidget, this.terraformPlansWidget, 'MrSecurityWidget'].filter(
- (w) => w,
- );
+ return [
+ this.codeQualityWidget,
+ this.testReportWidget,
+ this.terraformPlansWidget,
+ 'MrSecurityWidget',
+ ].filter((w) => w);
},
},
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue
index 618d1e71f81..72c041759d9 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue
@@ -92,7 +92,6 @@ export default {
</div>
<actions
v-if="hasActionButtons"
- :widget="widgetName"
:tertiary-buttons="data.actions"
class="gl-ml-auto gl-pl-3"
@clickedAction="onClickedAction"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
index 2c8bf90064e..d17be3e4037 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
@@ -368,7 +368,6 @@ export default {
<slot name="action-buttons">
<action-buttons
v-if="actionButtons.length > 0"
- :widget="widgetName"
:tertiary-buttons="actionButtons"
@clickedAction="onActionClick"
/>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue
index e67924d28ab..bb82da7796a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue
@@ -128,11 +128,7 @@ export default {
>
</template>
</help-popover>
- <action-buttons
- v-if="hasActionButtons"
- :widget="widgetName"
- :tertiary-buttons="actionButtons"
- />
+ <action-buttons v-if="hasActionButtons" :tertiary-buttons="actionButtons" />
</div>
</div>
<div class="gl-display-flex gl-align-items-baseline">
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js b/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js
index 713c9e610b3..3af984dcf6c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.js
@@ -23,14 +23,17 @@ export default {
const { newErrors, resolvedErrors, parsingInProgress } = data;
if (parsingInProgress) {
return i18n.loading;
- } else if (newErrors.length >= 1 && resolvedErrors.length >= 1) {
+ }
+ if (newErrors.length >= 1 && resolvedErrors.length >= 1) {
return i18n.improvementAndDegradationCopy(
i18n.findings(resolvedErrors, codeQualityPrefixes.fixed),
i18n.findings(newErrors, codeQualityPrefixes.new),
);
- } else if (resolvedErrors.length >= 1) {
+ }
+ if (resolvedErrors.length >= 1) {
return i18n.singularCopy(i18n.findings(resolvedErrors, codeQualityPrefixes.fixed));
- } else if (newErrors.length >= 1) {
+ }
+ if (newErrors.length >= 1) {
return i18n.singularCopy(i18n.findings(newErrors, codeQualityPrefixes.new));
}
return i18n.noChanges;
@@ -38,7 +41,8 @@ export default {
statusIcon() {
if (this.collapsedData.newErrors.length >= 1) {
return EXTENSION_ICONS.warning;
- } else if (this.collapsedData.resolvedErrors.length >= 1) {
+ }
+ if (this.collapsedData.resolvedErrors.length >= 1) {
return EXTENSION_ICONS.success;
}
return EXTENSION_ICONS.neutral;
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.vue b/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.vue
index d30acf24684..cd3a98effa3 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/code_quality/index.vue
@@ -36,9 +36,11 @@ export default {
if (!this.pollingFinished) {
return { title: i18n.loading };
- } else if (this.hasError) {
+ }
+ if (this.hasError) {
return { title: i18n.error };
- } else if (
+ }
+ if (
this.collapsedData?.new_errors?.length >= 1 &&
this.collapsedData?.resolved_errors?.length >= 1
) {
@@ -48,11 +50,13 @@ export default {
i18n.findings(new_errors, codeQualityPrefixes.new),
),
};
- } else if (this.collapsedData?.resolved_errors?.length >= 1) {
+ }
+ if (this.collapsedData?.resolved_errors?.length >= 1) {
return {
title: i18n.singularCopy(i18n.findings(resolved_errors, codeQualityPrefixes.fixed)),
};
- } else if (this.collapsedData?.new_errors?.length >= 1) {
+ }
+ if (this.collapsedData?.new_errors?.length >= 1) {
return { title: i18n.singularCopy(i18n.findings(new_errors, codeQualityPrefixes.new)) };
}
return { title: i18n.noChanges };
@@ -95,7 +99,8 @@ export default {
statusIcon() {
if (this.collapsedData?.new_errors?.length >= 1) {
return EXTENSION_ICONS.warning;
- } else if (this.collapsedData?.resolved_errors?.length >= 1) {
+ }
+ if (this.collapsedData?.resolved_errors?.length >= 1) {
return EXTENSION_ICONS.success;
}
return EXTENSION_ICONS.neutral;
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js
deleted file mode 100644
index 6ac462d4ad5..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js
+++ /dev/null
@@ -1,189 +0,0 @@
-import { uniqueId } from 'lodash';
-import { __ } from '~/locale';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_NO_CONTENT } from '~/lib/utils/http_status';
-import TestCaseDetails from '~/pipelines/components/test_reports/test_case_details.vue';
-import { EXTENSION_ICONS } from '../../constants';
-import {
- summaryTextBuilder,
- reportTextBuilder,
- reportSubTextBuilder,
- countRecentlyFailedTests,
- recentFailuresTextBuilder,
- formatFilePath,
-} from './utils';
-import { i18n, TESTS_FAILED_STATUS, ERROR_STATUS } from './constants';
-
-export default {
- name: 'WidgetTestSummary',
- enablePolling: true,
- i18n,
- props: ['testResultsPath', 'headBlobPath', 'pipeline'],
- modalComponent: TestCaseDetails,
- computed: {
- failedTestNames() {
- if (!this.collapsedData?.suites) {
- return '';
- }
-
- const newFailures = this.collapsedData?.suites.flatMap((suite) => [suite.new_failures || []]);
- const fileNames = newFailures.flatMap((newFailure) => {
- return newFailure.map((failure) => {
- return failure.file;
- });
- });
-
- return fileNames.join(' ').trim();
- },
- summary(data) {
- if (data.parsingInProgress) {
- return this.$options.i18n.loading;
- }
- if (data.hasSuiteError) {
- return this.$options.i18n.error;
- }
- return {
- subject: summaryTextBuilder(this.$options.i18n.label, data.summary),
- meta: recentFailuresTextBuilder(data.summary),
- };
- },
- statusIcon(data) {
- if (data.status === TESTS_FAILED_STATUS) {
- return EXTENSION_ICONS.warning;
- }
- if (data.hasSuiteError) {
- return EXTENSION_ICONS.failed;
- }
- return EXTENSION_ICONS.success;
- },
- tertiaryButtons() {
- const actionButtons = [];
-
- if (this.failedTestNames().length > 0) {
- actionButtons.push({
- dataClipboardText: this.failedTestNames(),
- id: uniqueId('copy-to-clipboard'),
- icon: 'copy-to-clipboard',
- testId: 'copy-failed-specs-btn',
- text: this.$options.i18n.copyFailedSpecs,
- tooltipText: this.$options.i18n.copyFailedSpecsTooltip,
- tooltipOnClick: __('Copied'),
- });
- }
-
- actionButtons.push({
- text: this.$options.i18n.fullReport,
- href: `${this.pipeline.path}/test_report`,
- target: '_blank',
- trackFullReportClicked: true,
- testId: 'full-report-link',
- });
-
- return actionButtons;
- },
- },
- methods: {
- fetchCollapsedData() {
- return axios.get(this.testResultsPath).then((response) => {
- const { data = {}, status } = response;
- const { suites = [], summary = {} } = data;
-
- return {
- ...response,
- data: {
- hasSuiteError: suites.some((suite) => suite.status === ERROR_STATUS),
- parsingInProgress: status === HTTP_STATUS_NO_CONTENT,
- ...data,
- summary: {
- recentlyFailed: countRecentlyFailedTests(suites),
- ...summary,
- },
- },
- };
- });
- },
- fetchFullData() {
- return Promise.resolve(this.prepareReports());
- },
- suiteIcon(suite) {
- if (suite.status === ERROR_STATUS) {
- return EXTENSION_ICONS.error;
- }
- if (suite.status === TESTS_FAILED_STATUS) {
- return EXTENSION_ICONS.failed;
- }
- return EXTENSION_ICONS.success;
- },
- testHeader(test, sectionHeader, index) {
- const headers = [];
- if (index === 0) {
- headers.push(sectionHeader);
- }
- if (test.recent_failures?.count && test.recent_failures?.base_branch) {
- headers.push(i18n.recentFailureCount(test.recent_failures));
- }
- return headers;
- },
- mapTestAsChild({ iconName, sectionHeader }) {
- return (test, index) => {
- return {
- id: uniqueId('test-'),
- header: this.testHeader(test, sectionHeader, index),
- modal: {
- text: test.name,
- onClick: () => {
- this.modalData = {
- testCase: {
- filePath: test.file && `${this.headBlobPath}/${formatFilePath(test.file)}`,
- ...test,
- },
- };
- },
- },
- icon: { name: iconName },
- };
- };
- },
- prepareReports() {
- return this.collapsedData.suites
- .map((suite) => {
- return {
- ...suite,
- summary: {
- recentlyFailed: countRecentlyFailedTests(suite),
- ...suite.summary,
- },
- };
- })
- .map((suite) => {
- return {
- id: uniqueId('suite-'),
- text: reportTextBuilder(suite),
- subtext: reportSubTextBuilder(suite),
- icon: {
- name: this.suiteIcon(suite),
- },
- children: [
- ...[...suite.new_failures, ...suite.new_errors].map(
- this.mapTestAsChild({
- sectionHeader: i18n.newHeader,
- iconName: EXTENSION_ICONS.failed,
- }),
- ),
- ...[...suite.existing_failures, ...suite.existing_errors].map(
- this.mapTestAsChild({
- iconName: EXTENSION_ICONS.failed,
- }),
- ),
- ...[...suite.resolved_failures, ...suite.resolved_errors].map(
- this.mapTestAsChild({
- sectionHeader: i18n.fixedHeader,
- iconName: EXTENSION_ICONS.success,
- }),
- ),
- ],
- };
- });
- },
- },
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.vue b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.vue
new file mode 100644
index 00000000000..1b03b9c04e1
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.vue
@@ -0,0 +1,313 @@
+<script>
+import { uniqueId, uniq } from 'lodash';
+import { __ } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_NO_CONTENT } from '~/lib/utils/http_status';
+import TestCaseDetails from '~/ci/pipeline_details/test_reports/test_case_details.vue';
+import MrWidget from '~/vue_merge_request_widget/components/widget/widget.vue';
+import MrWidgetRow from '~/vue_merge_request_widget/components/widget/widget_content_row.vue';
+import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller';
+import { EXTENSION_ICONS } from '../../constants';
+import {
+ summaryTextBuilder,
+ reportTextBuilder,
+ reportSubTextBuilder,
+ countRecentlyFailedTests,
+ recentFailuresTextBuilder,
+ formatFilePath,
+} from './utils';
+import { i18n, TESTS_FAILED_STATUS, ERROR_STATUS } from './constants';
+
+export default {
+ name: 'WidgetTestReport',
+ components: {
+ MrWidget,
+ MrWidgetRow,
+ DynamicScroller,
+ DynamicScrollerItem,
+ TestCaseDetails,
+ },
+ i18n,
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ collapsedData: {},
+ suites: [],
+ modalData: null,
+ };
+ },
+ computed: {
+ failedTestNames() {
+ const { data: { suites = [] } = {} } = this.collapsedData;
+
+ if (!this.hasSuites) {
+ return '';
+ }
+
+ const newFailures = suites.flatMap((suite) => [suite.new_failures || []]);
+ const fileNames = newFailures.flatMap((newFailure) => {
+ return newFailure.map((failure) => {
+ return failure.file;
+ });
+ });
+
+ return uniq(fileNames).join(' ').trim();
+ },
+ summary() {
+ const {
+ data: { parsingInProgress = false, hasSuiteError = false, summary = {} } = {},
+ } = this.collapsedData;
+
+ if (parsingInProgress) {
+ return { title: this.$options.i18n.loading };
+ }
+ if (hasSuiteError) {
+ return { title: this.$options.i18n.error };
+ }
+ return {
+ title: summaryTextBuilder(this.$options.i18n.label, summary),
+ subtitle: recentFailuresTextBuilder(summary),
+ };
+ },
+ statusIcon() {
+ const { data: { status = null, hasSuiteError = false } = {} } = this.collapsedData;
+
+ if (status === TESTS_FAILED_STATUS) {
+ return EXTENSION_ICONS.warning;
+ }
+ if (hasSuiteError) {
+ return EXTENSION_ICONS.failed;
+ }
+ return EXTENSION_ICONS.success;
+ },
+ tertiaryButtons() {
+ const actionButtons = [];
+
+ if (this.failedTestNames.length > 0) {
+ actionButtons.push({
+ dataClipboardText: this.failedTestNames,
+ id: uniqueId('copy-to-clipboard'),
+ icon: 'copy-to-clipboard',
+ testId: 'copy-failed-specs-btn',
+ text: this.$options.i18n.copyFailedSpecs,
+ tooltipText: this.$options.i18n.copyFailedSpecsTooltip,
+ tooltipOnClick: __('Copied'),
+ });
+ }
+
+ actionButtons.push({
+ text: this.$options.i18n.fullReport,
+ href: `${this.mr.pipeline.path}/test_report`,
+ target: '_blank',
+ trackFullReportClicked: true,
+ testId: 'full-report-link',
+ });
+
+ return actionButtons;
+ },
+ testResultsPath() {
+ return this.mr.testResultsPath;
+ },
+ hasSuites() {
+ return this.suites.length > 0;
+ },
+ },
+ methods: {
+ fetchCollapsedData() {
+ return axios.get(this.testResultsPath).then((response) => {
+ const { data = {}, status } = response;
+ const { suites = [], summary = {} } = data;
+
+ this.collapsedData = {
+ ...response,
+ data: {
+ hasSuiteError: suites.some((suite) => suite.status === ERROR_STATUS),
+ parsingInProgress: status === HTTP_STATUS_NO_CONTENT,
+ ...data,
+ summary: {
+ recentlyFailed: countRecentlyFailedTests(suites),
+ ...summary,
+ },
+ },
+ };
+ this.suites = this.prepareSuites(this.collapsedData);
+
+ return response;
+ });
+ },
+ suiteIcon(suite) {
+ if (suite.status === ERROR_STATUS) {
+ return EXTENSION_ICONS.error;
+ }
+ if (suite.status === TESTS_FAILED_STATUS) {
+ return EXTENSION_ICONS.failed;
+ }
+ return EXTENSION_ICONS.success;
+ },
+ testHeader(test, sectionHeader, index) {
+ const headers = [];
+ if (index === 0) {
+ headers.push(sectionHeader);
+ }
+ if (test.recent_failures?.count && test.recent_failures?.base_branch) {
+ headers.push(i18n.recentFailureCount(test.recent_failures));
+ }
+ return headers;
+ },
+ mapTestAsChild({ iconName, sectionHeader }) {
+ return (test, index) => {
+ return {
+ id: uniqueId('test-'),
+ header: this.testHeader(test, sectionHeader, index),
+ text: test.name,
+ actions: [
+ {
+ text: __('View details'),
+ onClick: () => {
+ this.modalData = {
+ testCase: {
+ filePath: test.file && `${this.mr.headBlobPath}/${formatFilePath(test.file)}`,
+ ...test,
+ },
+ };
+ },
+ },
+ ],
+ icon: { name: iconName },
+ };
+ };
+ },
+ onModalHidden() {
+ this.modalData = null;
+ },
+ prepareSuites(collapsedData) {
+ const {
+ data: { suites = [] },
+ } = collapsedData;
+
+ return suites
+ .map((suite) => {
+ return {
+ ...suite,
+ summary: {
+ recentlyFailed: countRecentlyFailedTests(suite),
+ ...suite.summary,
+ },
+ };
+ })
+ .map((suite) => {
+ return {
+ id: uniqueId('suite-'),
+ text: reportTextBuilder(suite),
+ subtext: reportSubTextBuilder(suite),
+ icon: {
+ name: this.suiteIcon(suite),
+ },
+ children: [
+ ...[...suite.new_failures, ...suite.new_errors].map(
+ this.mapTestAsChild({
+ sectionHeader: i18n.newHeader,
+ iconName: EXTENSION_ICONS.failed,
+ }),
+ ),
+ ...[...suite.existing_failures, ...suite.existing_errors].map(
+ this.mapTestAsChild({
+ iconName: EXTENSION_ICONS.failed,
+ }),
+ ),
+ ...[...suite.resolved_failures, ...suite.resolved_errors].map(
+ this.mapTestAsChild({
+ sectionHeader: i18n.fixedHeader,
+ iconName: EXTENSION_ICONS.success,
+ }),
+ ),
+ ],
+ };
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <mr-widget
+ :error-text="$options.i18n.error"
+ :status-icon-name="statusIcon"
+ :loading-text="$options.i18n.loading"
+ :action-buttons="tertiaryButtons"
+ :help-popover="$options.helpPopover"
+ :widget-name="$options.name"
+ :summary="summary"
+ :fetch-collapsed-data="fetchCollapsedData"
+ :is-collapsible="hasSuites"
+ >
+ <template #content>
+ <mr-widget-row
+ v-for="suite in suites"
+ :key="suite.id"
+ :level="2"
+ :status-icon-name="suite.icon.name"
+ :widget-name="$options.name"
+ data-testid="extension-list-item"
+ >
+ <template #header>
+ <div class="gl-flex-direction-column">
+ <div>{{ suite.text }}</div>
+ <div
+ v-for="(subtext, i) in suite.subtext"
+ :key="`${suite.id}-subtext-${i}`"
+ class="gl-font-sm gl-text-gray-700"
+ >
+ {{ subtext }}
+ </div>
+ </div>
+ </template>
+ <template #body>
+ <div v-if="suite.children.length > 0" class="gl-mt-2 gl-w-full">
+ <dynamic-scroller
+ :items="suite.children"
+ :min-item-size="32"
+ :style="{ maxHeight: '170px' }"
+ key-field="id"
+ class="gl-pr-5"
+ >
+ <template #default="{ item, active }">
+ <dynamic-scroller-item :item="item" :active="active">
+ <strong
+ v-for="(headerText, i) in item.header"
+ :key="`${item.id}-headerText-${i}`"
+ class="gl-display-block gl-mt-2"
+ >
+ {{ headerText }}
+ </strong>
+ <mr-widget-row
+ :key="item.id"
+ :level="3"
+ :widget-name="$options.name"
+ :status-icon-name="item.icon.name"
+ :action-buttons="item.actions"
+ class="gl-mt-2"
+ >
+ <template #header>{{ item.text }}</template>
+ </mr-widget-row>
+ </dynamic-scroller-item>
+ </template>
+ </dynamic-scroller>
+ </div>
+ </template>
+ </mr-widget-row>
+ </template>
+ </mr-widget>
+ <test-case-details
+ :modal-id="`modal${$options.name}`"
+ :visible="modalData !== null"
+ v-bind="modalData"
+ @hidden="onModalHidden"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js
index 37f9964d23a..24f6b3e69ff 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/utils.js
@@ -62,7 +62,7 @@ export const reportSubTextBuilder = ({ suite_errors: suiteErrors, summary }) =>
}
return errors;
}
- return recentFailuresTextBuilder(summary);
+ return [recentFailuresTextBuilder(summary)];
};
export const countRecentlyFailedTests = (subject) => {
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index acdcbf7afd7..175a0b0563f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -56,7 +56,6 @@ import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variab
import getStateQuery from './queries/get_state.query.graphql';
import getStateSubscription from './queries/get_state.subscription.graphql';
import accessibilityExtension from './extensions/accessibility';
-import testReportExtension from './extensions/test_report';
import ReportWidgetContainer from './components/report_widget_container.vue';
import MrWidgetReadyToMerge from './components/states/new_ready_to_merge.vue';
@@ -225,9 +224,6 @@ export default {
this.mr.mergePipelinesEnabled && this.mr.sourceProjectId !== this.mr.targetProjectId,
);
},
- shouldRenderTestReport() {
- return Boolean(this.mr?.testResultsPath);
- },
mergeError() {
let { mergeError } = this.mr;
@@ -281,11 +277,6 @@ export default {
this.registerAccessibilityExtension();
}
},
- shouldRenderTestReport(newVal) {
- if (newVal) {
- this.registerTestReportExtension();
- }
- },
},
mounted() {
MRWidgetService.fetchInitialData()
@@ -525,11 +516,6 @@ export default {
registerExtension(accessibilityExtension);
}
},
- registerTestReportExtension() {
- if (this.shouldRenderTestReport) {
- registerExtension(testReportExtension);
- }
- },
},
};
</script>
@@ -569,7 +555,7 @@ export default {
v-if="hasMergeError"
type="danger"
dismissible
- data-testid="merge_error"
+ data-testid="merge-error"
>
<span v-safe-html="mergeError"></span>
</mr-widget-alert-message>
@@ -577,6 +563,7 @@ export default {
v-if="showMergePipelineForkWarning"
type="warning"
:help-path="mr.mergeRequestPipelinesHelpPath"
+ data-testid="merge-pipeline-fork-warning"
>
{{
s__(
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
index f90056a8e1a..d6bab074f3f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js
@@ -4,31 +4,44 @@ import { stateKey } from './state_maps';
export default function deviseState() {
if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.PREPARING) {
return stateKey.preparing;
- } else if (!this.commitsCount) {
+ }
+ if (!this.commitsCount) {
return stateKey.nothingToMerge;
- } else if (this.projectArchived) {
+ }
+ if (this.projectArchived) {
return stateKey.archived;
- } else if (this.branchMissing) {
+ }
+ if (this.branchMissing) {
return stateKey.missingBranch;
- } else if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.CHECKING) {
+ }
+ if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.CHECKING) {
return stateKey.checking;
- } else if (this.hasConflicts) {
+ }
+ if (this.hasConflicts) {
return stateKey.conflicts;
- } else if (this.shouldBeRebased) {
+ }
+ if (this.shouldBeRebased) {
return stateKey.rebase;
- } else if (this.hasMergeChecksFailed && !this.autoMergeEnabled) {
+ }
+ if (this.hasMergeChecksFailed && !this.autoMergeEnabled) {
return stateKey.mergeChecksFailed;
- } else if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.CI_MUST_PASS) {
+ }
+ if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.CI_MUST_PASS) {
return stateKey.pipelineFailed;
- } else if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.DRAFT_STATUS) {
+ }
+ if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.DRAFT_STATUS) {
return stateKey.draft;
- } else if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.DISCUSSIONS_NOT_RESOLVED) {
+ }
+ if (this.detailedMergeStatus === DETAILED_MERGE_STATUS.DISCUSSIONS_NOT_RESOLVED) {
return stateKey.unresolvedDiscussions;
- } else if (this.canMerge && this.isSHAMismatch) {
+ }
+ if (this.canMerge && this.isSHAMismatch) {
return stateKey.shaMismatch;
- } else if (this.autoMergeEnabled && !this.mergeError) {
+ }
+ if (this.autoMergeEnabled && !this.mergeError) {
return stateKey.autoMergeEnabled;
- } else if (
+ }
+ if (
this.detailedMergeStatus === DETAILED_MERGE_STATUS.MERGEABLE ||
this.detailedMergeStatus === DETAILED_MERGE_STATUS.CI_STILL_RUNNING
) {
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index b1c069d9b1e..bb74f82145f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -1,8 +1,8 @@
import getStateKey from 'ee_else_ce/vue_merge_request_widget/stores/get_state_key';
-import { badgeState } from '~/issuable/components/status_box.vue';
import { STATUS_CLOSED, STATUS_MERGED, STATUS_OPEN } from '~/issues/constants';
import { formatDate, getTimeago, timeagoLanguageCode } from '~/lib/utils/datetime_utility';
import { machine } from '~/lib/utils/finite_state_machine';
+import { badgeState } from '~/merge_requests/components/merge_request_status_badge.vue';
import {
MTWPS_MERGE_STRATEGY,
MT_MERGE_STRATEGY,
@@ -351,11 +351,14 @@ export default class MergeRequestStore {
if (availableAutoMergeStrategies.includes(MTWPS_MERGE_STRATEGY)) {
return MTWPS_MERGE_STRATEGY;
- } else if (availableAutoMergeStrategies.includes(MT_MERGE_STRATEGY)) {
+ }
+ if (availableAutoMergeStrategies.includes(MT_MERGE_STRATEGY)) {
return MT_MERGE_STRATEGY;
- } else if (availableAutoMergeStrategies.includes(MWCP_MERGE_STRATEGY)) {
+ }
+ if (availableAutoMergeStrategies.includes(MWCP_MERGE_STRATEGY)) {
return MWCP_MERGE_STRATEGY;
- } else if (availableAutoMergeStrategies.includes(MWPS_MERGE_STRATEGY)) {
+ }
+ if (availableAutoMergeStrategies.includes(MWPS_MERGE_STRATEGY)) {
return MWPS_MERGE_STRATEGY;
}
diff --git a/app/assets/javascripts/vue_shared/components/blob_viewers/constants.js b/app/assets/javascripts/vue_shared/components/blob_viewers/constants.js
index 106dd7a3b97..957e642fcb8 100644
--- a/app/assets/javascripts/vue_shared/components/blob_viewers/constants.js
+++ b/app/assets/javascripts/vue_shared/components/blob_viewers/constants.js
@@ -1 +1,5 @@
export const HIGHLIGHT_CLASS_NAME = 'hll';
+export const MARKUP_FILE_TYPE = 'markup';
+export const MARKUP_CONTENT_SELECTOR = '.js-markup-content';
+export const ELEMENTS_PER_CHUNK = 20;
+export const CONTENT_LOADED_EVENT = 'richContentLoaded';
diff --git a/app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue b/app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue
index 11ce6afbb1d..27bdcc69120 100644
--- a/app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue
@@ -3,7 +3,14 @@ import SafeHtml from '~/vue_shared/directives/safe_html';
import { handleBlobRichViewer } from '~/blob/viewer';
import MarkdownFieldView from '~/vue_shared/components/markdown/field_view.vue';
import { handleLocationHash } from '~/lib/utils/common_utils';
+import { sanitize } from '~/lib/dompurify';
import ViewerMixin from './mixins';
+import {
+ MARKUP_FILE_TYPE,
+ MARKUP_CONTENT_SELECTOR,
+ ELEMENTS_PER_CHUNK,
+ CONTENT_LOADED_EVENT,
+} from './constants';
export default {
components: {
@@ -16,21 +23,77 @@ export default {
data() {
return {
isLoading: true,
+ initialContent: null,
+ remainingContent: [],
};
},
+ computed: {
+ rawContent() {
+ return this.initialContent || this.richViewer || this.content;
+ },
+ isMarkup() {
+ return this.type === MARKUP_FILE_TYPE;
+ },
+ },
+ created() {
+ this.optimizeMarkupRendering();
+ },
mounted() {
- window.requestIdleCallback(async () => {
+ this.renderRemainingMarkup();
+ handleBlobRichViewer(this.$refs.content, this.type);
+ handleLocationHash();
+ },
+ methods: {
+ optimizeMarkupRendering() {
+ /**
+ * If content is markup we optimize rendering by splitting it into two parts:
+ * - initialContent (top section of the file - is rendered right away)
+ * - remainingContent (remaining content - is rendered over a longer time period)
+ *
+ * This is done so that the browser doesn't render the whole file at once (improves TBT)
+ */
+
+ if (!this.isMarkup) return;
+
+ const tmpWrapper = document.createElement('div');
+ tmpWrapper.innerHTML = sanitize(this.rawContent, this.$options.safeHtmlConfig);
+
+ const fileContent = tmpWrapper.querySelector(MARKUP_CONTENT_SELECTOR);
+ if (!fileContent) return;
+
+ const initialContent = [...fileContent.childNodes].slice(0, ELEMENTS_PER_CHUNK);
+ this.remainingContent = [...fileContent.childNodes].slice(ELEMENTS_PER_CHUNK);
+
+ fileContent.innerHTML = '';
+ fileContent.append(...initialContent);
+ this.initialContent = tmpWrapper.outerHTML;
+ },
+ renderRemainingMarkup() {
/**
- * Rendering Markdown usually takes long due to the amount of HTML being parsed.
- * This ensures that content is loaded only when the browser goes into idle.
+ * Rendering large Markdown files can block the main thread due to the amount of HTML being parsed.
+ * The optimization below ensures that content is rendered over a longer time period instead of all at once.
* More details here: https://gitlab.com/gitlab-org/gitlab/-/issues/331448
* */
- this.isLoading = false;
- await this.$nextTick();
- handleBlobRichViewer(this.$refs.content, this.type);
- handleLocationHash();
- this.$emit('richContentLoaded');
- });
+
+ if (!this.isMarkup || !this.remainingContent.length) {
+ this.$emit(CONTENT_LOADED_EVENT);
+ this.isLoading = false;
+ return;
+ }
+
+ const fileContent = this.$refs.content.$el.querySelector(MARKUP_CONTENT_SELECTOR);
+
+ for (let i = 0; i < this.remainingContent.length; i += ELEMENTS_PER_CHUNK) {
+ const nextChunkEnd = i + ELEMENTS_PER_CHUNK;
+ const content = this.remainingContent.slice(i, nextChunkEnd);
+ setTimeout(() => {
+ fileContent.append(...content);
+ if (nextChunkEnd < this.remainingContent.length) return;
+ this.$emit(CONTENT_LOADED_EVENT);
+ this.isLoading = false;
+ }, i);
+ }
+ },
},
safeHtmlConfig: {
ADD_TAGS: ['gl-emoji', 'copy-code'],
@@ -39,8 +102,8 @@ export default {
</script>
<template>
<markdown-field-view
- v-if="!isLoading"
ref="content"
- v-safe-html:[$options.safeHtmlConfig]="richViewer || content"
+ v-safe-html:[$options.safeHtmlConfig]="rawContent"
+ :is-loading="isLoading"
/>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
index 14e99977a85..2a47e96b2e2 100644
--- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
@@ -50,11 +50,14 @@ export default {
tooltipTitle() {
if (!this.showTooltip) {
return undefined;
- } else if (this.file.deleted) {
+ }
+ if (this.file.deleted) {
return __('Deleted');
- } else if (this.file.tempFile) {
+ }
+ if (this.file.tempFile) {
return __('Added');
- } else if (this.file.changed) {
+ }
+ if (this.file.changed) {
return __('Modified');
}
diff --git a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
index 9aa7a7d6c49..1f45b4c5c9d 100644
--- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
@@ -1,6 +1,7 @@
<script>
import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
import CiIcon from './ci_icon.vue';
+
/**
* Renders CI Badge link with CI icon and status text based on
* API response shared between all places where it is used.
@@ -48,7 +49,7 @@ export default {
required: false,
default: true,
},
- badgeSize: {
+ size: {
type: String,
required: false,
default: badgeSizeOptions.md,
@@ -59,7 +60,7 @@ export default {
},
computed: {
isSmallBadgeSize() {
- return this.badgeSize === badgeSizeOptions.sm;
+ return this.size === badgeSizeOptions.sm;
},
title() {
return !this.showText ? this.status?.text : '';
@@ -120,13 +121,12 @@ export default {
<template>
<gl-badge
v-gl-tooltip
- :class="{ 'gl-pl-0!': isSmallBadgeSize }"
+ :class="{ 'gl-pl-2': isSmallBadgeSize }"
:title="title"
:href="detailsPath"
- :size="badgeSize"
+ :size="size"
:variant="badgeStyles.variant"
- :data-testid="`ci-badge-${status.text}`"
- data-qa-selector="status_badge_link"
+ data-testid="ci-badge-link"
@click="$emit('ciStatusBadgeClick')"
>
<ci-icon :status="status" />
diff --git a/app/assets/javascripts/vue_shared/components/confidentiality_badge.vue b/app/assets/javascripts/vue_shared/components/confidentiality_badge.vue
index 31c98d1e3a7..025e38a55ad 100644
--- a/app/assets/javascripts/vue_shared/components/confidentiality_badge.vue
+++ b/app/assets/javascripts/vue_shared/components/confidentiality_badge.vue
@@ -1,10 +1,11 @@
<script>
-import { GlBadge, GlTooltipDirective } from '@gitlab/ui';
+import { GlBadge, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { confidentialityInfoText } from '../constants';
export default {
components: {
GlBadge,
+ GlIcon,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -18,22 +19,31 @@ export default {
type: String,
required: true,
},
+ hideTextInSmallScreens: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
confidentialTooltip() {
return confidentialityInfoText(this.workspaceType, this.issuableType);
},
+ confidentialTextClass() {
+ return {
+ 'gl-display-none gl-sm-display-block': this.hideTextInSmallScreens,
+ 'gl-ml-2': true,
+ };
+ },
},
};
</script>
<template>
- <gl-badge
- v-gl-tooltip.bottom
- :title="confidentialTooltip"
- icon="eye-slash"
- variant="warning"
- class="gl-display-inline gl-mr-3"
- >{{ __('Confidential') }}</gl-badge
- >
+ <gl-badge v-gl-tooltip :title="confidentialTooltip" variant="warning">
+ <gl-icon name="eye-slash" :size="16" />
+ <span data-testid="confidential-badge-text" :class="confidentialTextClass">{{
+ __('Confidential')
+ }}</span>
+ </gl-badge>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
index 65a601ed927..a1ef1f30ebb 100644
--- a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.vue
@@ -38,7 +38,16 @@ export default {
default: CONFIRM_DANGER_MODAL_CANCEL,
},
},
+ model: {
+ prop: 'visible',
+ event: 'change',
+ },
props: {
+ visible: {
+ type: Boolean,
+ required: false,
+ default: null,
+ },
modalId: {
type: String,
required: true,
@@ -89,12 +98,15 @@ export default {
<template>
<gl-modal
ref="modal"
+ :visible="visible"
:modal-id="modalId"
:data-testid="modalId"
:title="$options.i18n.CONFIRM_DANGER_MODAL_TITLE"
:action-primary="actionPrimary"
:action-cancel="actionCancel"
+ size="sm"
@primary="$emit('confirm')"
+ @change="$emit('change', $event)"
>
<gl-alert
v-if="confirmDangerMessage"
diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
deleted file mode 100644
index d8a2789a419..00000000000
--- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue
+++ /dev/null
@@ -1,283 +0,0 @@
-<script>
-import { GlIcon, GlButton, GlDropdown, GlDropdownItem, GlFormGroup } from '@gitlab/ui';
-import { convertToFixedRange, isEqualTimeRanges, findTimeRange } from '~/lib/utils/datetime_range';
-import { __, sprintf } from '~/locale';
-
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import DateTimePickerInput from './date_time_picker_input.vue';
-import {
- defaultTimeRanges,
- defaultTimeRange,
- isValidInputString,
- inputStringToIsoDate,
- isoDateToInputString,
-} from './date_time_picker_lib';
-
-const events = {
- input: 'input',
- invalid: 'invalid',
-};
-
-export default {
- components: {
- GlIcon,
- GlButton,
- GlDropdown,
- GlDropdownItem,
- GlFormGroup,
- TooltipOnTruncate,
- DateTimePickerInput,
- },
- props: {
- value: {
- type: Object,
- required: false,
- default: () => defaultTimeRange,
- },
- options: {
- type: Array,
- required: false,
- default: () => defaultTimeRanges,
- },
- customEnabled: {
- type: Boolean,
- required: false,
- default: true,
- },
- utc: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- data() {
- return {
- timeRange: this.value,
-
- /**
- * Valid start iso date string, null if not valid value
- */
- startDate: null,
- /**
- * Invalid start date string as input by the user
- */
- startFallbackVal: '',
-
- /**
- * Valid end iso date string, null if not valid value
- */
- endDate: null,
- /**
- * Invalid end date string as input by the user
- */
- endFallbackVal: '',
- };
- },
- computed: {
- startInputValid() {
- return isValidInputString(this.startDate);
- },
- endInputValid() {
- return isValidInputString(this.endDate);
- },
- isValid() {
- return this.startInputValid && this.endInputValid;
- },
-
- startInput: {
- get() {
- return this.dateToInput(this.startDate) || this.startFallbackVal;
- },
- set(val) {
- try {
- this.startDate = this.inputToDate(val);
- this.startFallbackVal = null;
- } catch (e) {
- this.startDate = null;
- this.startFallbackVal = val;
- }
- this.timeRange = null;
- },
- },
- endInput: {
- get() {
- return this.dateToInput(this.endDate) || this.endFallbackVal;
- },
- set(val) {
- try {
- this.endDate = this.inputToDate(val);
- this.endFallbackVal = null;
- } catch (e) {
- this.endDate = null;
- this.endFallbackVal = val;
- }
- this.timeRange = null;
- },
- },
-
- timeWindowText() {
- try {
- const timeRange = findTimeRange(this.value, this.options);
- if (timeRange) {
- return timeRange.label;
- }
-
- const { start, end } = convertToFixedRange(this.value);
- if (isValidInputString(start) && isValidInputString(end)) {
- return sprintf(__('%{start} to %{end}'), {
- start: this.stripZerosInDateTime(this.dateToInput(start)),
- end: this.stripZerosInDateTime(this.dateToInput(end)),
- });
- }
- } catch {
- return __('Invalid date range');
- }
- return '';
- },
-
- customLabel() {
- if (this.utc) {
- return __('Custom range (UTC)');
- }
- return __('Custom range');
- },
- },
- watch: {
- value(newValue) {
- const { start, end } = convertToFixedRange(newValue);
- this.timeRange = this.value;
- this.startDate = start;
- this.endDate = end;
- },
- },
- mounted() {
- try {
- const { start, end } = convertToFixedRange(this.timeRange);
- this.startDate = start;
- this.endDate = end;
- } catch {
- // when dates cannot be parsed, emit error.
- this.$emit(events.invalid);
- }
-
- // Validate on mounted, and trigger an update if needed
- if (!this.isValid) {
- this.$emit(events.invalid);
- }
- },
- methods: {
- dateToInput(date) {
- if (date === null) {
- return null;
- }
- return isoDateToInputString(date, this.utc);
- },
- inputToDate(value) {
- return inputStringToIsoDate(value, this.utc);
- },
- stripZerosInDateTime(str = '') {
- return str.replace(' 00:00:00', '');
- },
- closeDropdown() {
- this.$refs.dropdown.hide();
- },
- isOptionActive(option) {
- return isEqualTimeRanges(option, this.timeRange);
- },
- setQuickRange(option) {
- this.timeRange = option;
- this.$emit(events.input, this.timeRange);
- },
- setFixedRange() {
- this.timeRange = convertToFixedRange({
- start: this.startDate,
- end: this.endDate,
- });
- this.$emit(events.input, this.timeRange);
- },
- },
-};
-</script>
-<template>
- <tooltip-on-truncate
- :title="timeWindowText"
- :truncate-target="(elem) => elem.querySelector('.gl-dropdown-toggle-text')"
- placement="top"
- class="d-inline-block"
- >
- <gl-dropdown
- ref="dropdown"
- :text="timeWindowText"
- v-bind="$attrs"
- class="date-time-picker w-100"
- menu-class="date-time-picker-menu"
- toggle-class="date-time-picker-toggle text-truncate"
- >
- <template #button-content>
- <span class="gl-flex-grow-1 text-truncate">{{ timeWindowText }}</span>
- <span v-if="utc" class="gl-text-gray-500 gl-font-weight-bold gl-font-sm">{{
- __('UTC')
- }}</span>
- <gl-icon class="gl-dropdown-caret" name="chevron-down" />
- </template>
-
- <div class="d-flex justify-content-between gl-p-2">
- <gl-form-group
- v-if="customEnabled"
- :label="customLabel"
- label-for="custom-from-time"
- label-class="gl-pb-2"
- class="custom-time-range-form-group col-md-7 gl-pl-2 gl-pr-0 m-0"
- >
- <div class="gl-pt-3">
- <date-time-picker-input
- id="custom-time-from"
- v-model="startInput"
- :label="__('From')"
- :state="startInputValid"
- />
- <date-time-picker-input
- id="custom-time-to"
- v-model="endInput"
- :label="__('To')"
- :state="endInputValid"
- />
- </div>
- <gl-form-group>
- <gl-button data-testid="cancelButton" @click="closeDropdown">{{
- __('Cancel')
- }}</gl-button>
- <gl-button
- variant="confirm"
- category="primary"
- :disabled="!isValid"
- @click="setFixedRange()"
- >
- {{ __('Apply') }}
- </gl-button>
- </gl-form-group>
- </gl-form-group>
- <gl-form-group label-for="group-id-dropdown" class="col-md-5 gl-px-2 m-0">
- <template #label>
- <span class="gl-pl-7">{{ __('Quick range') }}</span>
- </template>
-
- <gl-dropdown-item
- v-for="(option, index) in options"
- :key="index"
- :active="isOptionActive(option)"
- active-class="active"
- @click="setQuickRange(option)"
- >
- <gl-icon
- name="mobile-issue-close"
- class="align-bottom"
- :class="{ invisible: !isOptionActive(option) }"
- />
- {{ option.label }}
- </gl-dropdown-item>
- </gl-form-group>
- </div>
- </gl-dropdown>
- </tooltip-on-truncate>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_input.vue b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_input.vue
deleted file mode 100644
index 190d4e1f104..00000000000
--- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_input.vue
+++ /dev/null
@@ -1,77 +0,0 @@
-<script>
-import { GlFormGroup, GlFormInput } from '@gitlab/ui';
-import { uniqueId } from 'lodash';
-import { __, sprintf } from '~/locale';
-import { dateFormats } from './date_time_picker_lib';
-
-const inputGroupText = {
- invalidFeedback: sprintf(__('Format: %{dateFormat}'), {
- dateFormat: dateFormats.inputFormat,
- }),
- placeholder: dateFormats.inputFormat,
-};
-
-export default {
- components: {
- GlFormGroup,
- GlFormInput,
- },
- props: {
- state: {
- default: null,
- required: true,
- validator: (prop) => typeof prop === 'boolean' || prop === null,
- },
- value: {
- default: null,
- required: false,
- validator: (prop) => typeof prop === 'string' || prop === null,
- },
- label: {
- type: String,
- default: '',
- required: true,
- },
- id: {
- type: String,
- required: false,
- default: () => uniqueId('dateTimePicker_'),
- },
- },
- data() {
- return {
- inputGroupText,
- };
- },
- computed: {
- invalidFeedback() {
- return this.state ? '' : this.inputGroupText.invalidFeedback;
- },
- inputState() {
- // When the state is valid we want to show no
- // green outline. Hence passing null and not true.
- if (this.state === true) {
- return null;
- }
- return this.state;
- },
- },
- methods: {
- onInputBlur(e) {
- this.$emit('input', e.target.value.trim() || null);
- },
- },
-};
-</script>
-
-<template>
- <gl-form-group :label="label" label-size="sm" :label-for="id" :invalid-feedback="invalidFeedback">
- <gl-form-input
- :id="id"
- :value="value"
- :state="inputState"
- :placeholder="inputGroupText.placeholder"
- @blur="onInputBlur"
- />
- </gl-form-group>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_lib.js b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_lib.js
deleted file mode 100644
index 38b1a587b34..00000000000
--- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_lib.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import dateformat from '~/lib/dateformat';
-import { __ } from '~/locale';
-
-/**
- * Default time ranges for the date picker.
- * @see app/assets/javascripts/lib/utils/datetime_range.js
- */
-export const defaultTimeRanges = [
- {
- duration: { seconds: 60 * 30 },
- label: __('30 minutes'),
- },
- {
- duration: { seconds: 60 * 60 * 3 },
- label: __('3 hours'),
- },
- {
- duration: { seconds: 60 * 60 * 8 },
- label: __('8 hours'),
- default: true,
- },
- {
- duration: { seconds: 60 * 60 * 24 * 1 },
- label: __('1 day'),
- },
-];
-
-export const defaultTimeRange = defaultTimeRanges.find((tr) => tr.default);
-
-export const dateFormats = {
- /**
- * Format used by users to input dates
- *
- * Note: Should be a format that can be parsed by Date.parse.
- */
- inputFormat: 'yyyy-mm-dd HH:MM:ss',
- /**
- * Format used to strip timezone from inputs
- */
- stripTimezoneFormat: "yyyy-mm-dd'T'HH:MM:ss'Z'",
-};
-
-/**
- * Returns true if the date can be parsed succesfully after
- * being typed by a user.
- *
- * It allows some ambiguity so validation is not strict.
- *
- * @param {string} value - Value as typed by the user
- * @returns true if the value can be parsed as a valid date, false otherwise
- */
-export const isValidInputString = (value) => {
- try {
- // dateformat throws error that can be caught.
- // This is better than using `new Date()`
- if (value && value.trim()) {
- dateformat(value, 'isoDateTime');
- return true;
- }
- return false;
- } catch (e) {
- return false;
- }
-};
-
-/**
- * Convert the input in time picker component to an ISO date.
- *
- * @param {string} value
- * @param {Boolean} utc - If true, it forces the date to by
- * formatted using UTC format, ignoring the local time.
- * @returns {Date}
- */
-export const inputStringToIsoDate = (value, utc = false) => {
- let date = new Date(value);
- if (utc) {
- // Forces date to be interpreted as UTC by stripping the timezone
- // by formatting to a string with 'Z' and skipping timezone
- date = dateformat(date, dateFormats.stripTimezoneFormat);
- }
- return dateformat(date, 'isoUtcDateTime');
-};
-
-/**
- * Converts a iso date string to a formatted string for the Time picker component.
- *
- * @param {String} ISO Formatted date
- * @returns {string}
- */
-export const isoDateToInputString = (date, utc = false) =>
- dateformat(date, dateFormats.inputFormat, utc);
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
index 7080e046b30..535f1c5f645 100644
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
@@ -65,7 +65,8 @@ export default {
viewer() {
if (this.diffViewerMode === diffViewerModes.renamed) {
return RenamedFile;
- } else if (this.diffMode === diffModes.mode_changed) {
+ }
+ if (this.diffMode === diffModes.mode_changed) {
return ModeChanged;
}
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/empty_file.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/empty_file.vue
deleted file mode 100644
index 53210cbcc93..00000000000
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/empty_file.vue
+++ /dev/null
@@ -1,3 +0,0 @@
-<template>
- <div class="nothing-here-block">{{ __('Empty file') }}</div>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
index 3bb168e9051..b34a6b11092 100644
--- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
@@ -64,6 +64,11 @@ export default {
required: false,
default: undefined,
},
+ noOptionsText: {
+ type: String,
+ required: false,
+ default: __('No options found'),
+ },
},
computed: {
isSearchEmpty() {
@@ -72,6 +77,9 @@ export default {
noOptionsFound() {
return !this.isSearchEmpty && this.options.length === 0;
},
+ noOptions() {
+ return this.isSearchEmpty && this.options.length === 0;
+ },
},
methods: {
selectOption(option) {
@@ -177,6 +185,9 @@ export default {
<gl-dropdown-item v-if="noOptionsFound" class="gl-pl-6!">
{{ $options.i18n.noMatchingResults }}
</gl-dropdown-item>
+ <gl-dropdown-item v-if="noOptions">
+ {{ noOptionsText }}
+ </gl-dropdown-item>
</template>
</gl-dropdown-form>
</slot>
diff --git a/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue b/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue
index 71e3bf4ff63..eb7b20fa4c1 100644
--- a/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue
+++ b/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue
@@ -19,6 +19,11 @@ export default {
EntitySelect,
},
props: {
+ apiParams: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
label: {
type: String,
required: false,
@@ -48,7 +53,7 @@ export default {
default: null,
},
groupsFilter: {
- type: String,
+ type: String, // Two supported values: `descendant_groups` and `subgroups` See app/assets/javascripts/vue_shared/components/entity_select/utils.js.
required: false,
default: null,
},
@@ -62,17 +67,15 @@ export default {
async fetchGroups(searchString = '', page = 1) {
let groups = [];
let totalPages = 0;
+ const params = {
+ search: searchString,
+ per_page: DEFAULT_PER_PAGE,
+ page,
+ ...this.apiParams,
+ };
try {
- const { data = [], headers } = await axios.get(
- Api.buildUrl(groupsPath(this.groupsFilter, this.parentGroupID)),
- {
- params: {
- search: searchString,
- per_page: DEFAULT_PER_PAGE,
- page,
- },
- },
- );
+ const url = groupsPath(this.groupsFilter, this.parentGroupID);
+ const { data = [], headers } = await axios.get(url, { params });
groups = data.map((group) => ({
...group,
text: group.full_name,
diff --git a/app/assets/javascripts/vue_shared/components/entity_select/utils.js b/app/assets/javascripts/vue_shared/components/entity_select/utils.js
index 0a4622269f4..857a3ab4c74 100644
--- a/app/assets/javascripts/vue_shared/components/entity_select/utils.js
+++ b/app/assets/javascripts/vue_shared/components/entity_select/utils.js
@@ -1,15 +1,26 @@
import Api from '~/api';
+/**
+ * @param {'descendant_groups'|'subgroups'|null} [groupsFilter] - type of group filtering
+ * @param {string|null} [parentGroupID] - parent group is needed for 'descendant_groups' and 'subgroups' filtering.
+ */
export const groupsPath = (groupsFilter, parentGroupID) => {
- if (groupsFilter !== undefined && parentGroupID === undefined) {
+ if (groupsFilter && !parentGroupID) {
throw new Error('Cannot use groupsFilter without a parentGroupID');
}
+
+ let url = '';
switch (groupsFilter) {
case 'descendant_groups':
- return Api.descendantGroupsPath.replace(':id', parentGroupID);
+ url = Api.descendantGroupsPath.replace(':id', parentGroupID);
+ break;
case 'subgroups':
- return Api.subgroupsPath.replace(':id', parentGroupID);
+ url = Api.subgroupsPath.replace(':id', parentGroupID);
+ break;
default:
- return Api.groupsPath;
+ url = Api.groupsPath;
+ break;
}
+
+ return Api.buildUrl(url);
};
diff --git a/app/assets/javascripts/vue_shared/components/file_finder/index.vue b/app/assets/javascripts/vue_shared/components/file_finder/index.vue
index db0b0ea185b..226f44a1541 100644
--- a/app/assets/javascripts/vue_shared/components/file_finder/index.vue
+++ b/app/assets/javascripts/vue_shared/components/file_finder/index.vue
@@ -145,7 +145,8 @@ export default {
el.classList.contains('inputarea')
) {
return true;
- } else if (combo === 'mod+p') {
+ }
+ if (combo === 'mod+p') {
return false;
}
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 721f87ff4d6..cecd1be82e9 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -141,7 +141,6 @@ export default {
ref="textOutput"
class="file-row-name"
:title="file.name"
- data-qa-selector="file_name_content"
:data-qa-file-name="file.name"
data-testid="file-row-name-container"
:class="[fileClasses, { 'str-truncated': !truncateMiddle, 'gl-min-w-0': truncateMiddle }]"
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
index 2b3d1b2c1f5..c698b94749d 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
@@ -73,6 +73,7 @@ export const TOKEN_TITLE_RELEASE = __('Release');
export const TOKEN_TITLE_REVIEWER = s__('SearchToken|Reviewer');
export const TOKEN_TITLE_SOURCE_BRANCH = __('Source Branch');
export const TOKEN_TITLE_STATUS = __('Status');
+export const TOKEN_TITLE_JOBS_RUNNER_TYPE = s__('Job|Runner type');
export const TOKEN_TITLE_TARGET_BRANCH = __('Target Branch');
export const TOKEN_TITLE_TYPE = __('Type');
export const TOKEN_TITLE_SEARCH_WITHIN = __('Search Within');
@@ -100,6 +101,7 @@ export const TOKEN_TYPE_RELEASE = 'release';
export const TOKEN_TYPE_REVIEWER = 'reviewer';
export const TOKEN_TYPE_SOURCE_BRANCH = 'source-branch';
export const TOKEN_TYPE_STATUS = 'status';
+export const TOKEN_TYPE_JOBS_RUNNER_TYPE = 'jobs-runner-type';
export const TOKEN_TYPE_TARGET_BRANCH = 'target-branch';
export const TOKEN_TYPE_TYPE = 'type';
export const TOKEN_TYPE_WEIGHT = 'weight';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
index f31d4d53a23..346384e3023 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
@@ -73,7 +73,8 @@ export default {
},
searchInputPlaceholder: {
type: String,
- required: true,
+ required: false,
+ default: __('Search or filter results…'),
},
suggestionsListClass: {
type: String,
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue
index 8322fe92de4..77108ad3628 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue
@@ -2,6 +2,8 @@
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
import { createAlert } from '~/alert';
import { __ } from '~/locale';
+import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
+import searchMilestonesQuery from '~/issues/list/queries/search_milestones.query.graphql';
import { sortMilestonesByDueDate } from '~/milestones/utils';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { stripQuotes } from '~/lib/utils/text_utility';
@@ -36,6 +38,14 @@ export default {
defaultMilestones() {
return this.config.defaultMilestones || DEFAULT_MILESTONES;
},
+ namespace() {
+ return this.config.isProject ? WORKSPACE_PROJECT : WORKSPACE_GROUP;
+ },
+ fetchMilestonesQuery() {
+ return this.config.fetchMilestones
+ ? this.config.fetchMilestones
+ : this.fetchMilestonesBySearchTerm;
+ },
},
methods: {
getActiveMilestone(milestones, data) {
@@ -51,10 +61,17 @@ export default {
) || this.defaultMilestones.find(({ value }) => value === data)
);
},
+ fetchMilestonesBySearchTerm(search) {
+ return this.$apollo
+ .query({
+ query: searchMilestonesQuery,
+ variables: { fullPath: this.config.fullPath, search, isProject: this.config.isProject },
+ })
+ .then(({ data }) => data[this.namespace]?.milestones.nodes);
+ },
fetchMilestones(searchTerm) {
this.loading = true;
- this.config
- .fetchMilestones(searchTerm)
+ this.fetchMilestonesQuery(searchTerm)
.then((response) => {
const data = Array.isArray(response) ? response : response.data;
diff --git a/app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue b/app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue
index 7da45169fee..a375a167c68 100644
--- a/app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue
+++ b/app/assets/javascripts/vue_shared/components/groups_list/groups_list.vue
@@ -24,6 +24,7 @@ export default {
:key="group.id"
:group="group"
:show-group-icon="showGroupIcon"
+ @delete="$emit('delete', $event)"
/>
</ul>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue b/app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue
index 8a301cd0dd0..ca1e7400f2d 100644
--- a/app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue
+++ b/app/assets/javascripts/vue_shared/components/groups_list/groups_list_item.vue
@@ -1,5 +1,6 @@
<script>
import { GlAvatarLabeled, GlIcon, GlTooltipDirective, GlTruncateText } from '@gitlab/ui';
+import uniqueId from 'lodash/uniqueId';
import { VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE } from '~/visibility_level/constants';
import { ACCESS_LEVEL_LABELS } from '~/access_level/constants';
@@ -7,6 +8,9 @@ import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.
import { __ } from '~/locale';
import { numberToMetricPrefix } from '~/lib/utils/number_utils';
import SafeHtml from '~/vue_shared/directives/safe_html';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+import ListActions from '~/vue_shared/components/list_actions/list_actions.vue';
+import DangerConfirmModal from '~/vue_shared/components/confirm_danger/confirm_danger_modal.vue';
export default {
i18n: {
@@ -25,6 +29,8 @@ export default {
GlIcon,
UserAccessRoleBadge,
GlTruncateText,
+ ListActions,
+ DangerConfirmModal,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -41,6 +47,12 @@ export default {
default: false,
},
},
+ data() {
+ return {
+ isDeleteModalVisible: false,
+ modalId: uniqueId('groups-list-item-modal-id-'),
+ };
+ },
computed: {
visibility() {
return this.group.visibility;
@@ -75,94 +87,131 @@ export default {
groupMembersCount() {
return numberToMetricPrefix(this.group.groupMembersCount);
},
+ actions() {
+ return {
+ [ACTION_EDIT]: {
+ href: this.group.editPath,
+ },
+ [ACTION_DELETE]: {
+ action: this.onActionDelete,
+ },
+ };
+ },
+ hasActions() {
+ return this.group.availableActions?.length;
+ },
+ hasActionDelete() {
+ return this.group.availableActions?.includes(ACTION_DELETE);
+ },
+ },
+ methods: {
+ onActionDelete() {
+ this.isDeleteModalVisible = true;
+ },
},
};
</script>
<template>
- <li class="groups-list-item gl-py-5 gl-md-display-flex gl-align-items-center gl-border-b">
- <div class="gl-display-flex gl-flex-grow-1">
- <gl-icon
- v-if="showGroupIcon"
- class="gl-mr-3 gl-mt-3 gl-md-mt-5 gl-flex-shrink-0 gl-text-secondary"
- :name="groupIconName"
- />
- <gl-avatar-labeled
- :entity-id="group.id"
- :entity-name="group.fullName"
- :label="group.fullName"
- :label-link="group.webUrl"
- shape="rect"
- :size="$options.avatarSize"
- >
- <template #meta>
- <div class="gl-px-2">
- <div class="gl-mx-n2 gl-display-flex gl-align-items-center gl-flex-wrap">
- <div class="gl-px-2">
- <gl-icon
- v-if="visibility"
- v-gl-tooltip="visibilityTooltip"
- :name="visibilityIcon"
- class="gl-text-secondary"
- />
- </div>
- <div class="gl-px-2">
- <user-access-role-badge v-if="shouldShowAccessLevel">{{
- accessLevelLabel
- }}</user-access-role-badge>
+ <li class="groups-list-item gl-py-5 gl-border-b gl-display-flex gl-align-items-flex-start">
+ <div class="gl-md-display-flex gl-align-items-center gl-flex-grow-1">
+ <div class="gl-display-flex gl-flex-grow-1">
+ <gl-icon
+ v-if="showGroupIcon"
+ class="gl-mr-3 gl-mt-3 gl-md-mt-5 gl-flex-shrink-0 gl-text-secondary"
+ :name="groupIconName"
+ />
+ <gl-avatar-labeled
+ :entity-id="group.id"
+ :entity-name="group.fullName"
+ :label="group.fullName"
+ :label-link="group.webUrl"
+ shape="rect"
+ :size="$options.avatarSize"
+ >
+ <template #meta>
+ <div class="gl-px-2">
+ <div class="gl-mx-n2 gl-display-flex gl-align-items-center gl-flex-wrap">
+ <div class="gl-px-2">
+ <gl-icon
+ v-if="visibility"
+ v-gl-tooltip="visibilityTooltip"
+ :name="visibilityIcon"
+ class="gl-text-secondary"
+ />
+ </div>
+ <div class="gl-px-2">
+ <user-access-role-badge v-if="shouldShowAccessLevel">{{
+ accessLevelLabel
+ }}</user-access-role-badge>
+ </div>
</div>
</div>
+ </template>
+ <gl-truncate-text
+ v-if="group.descriptionHtml"
+ :lines="2"
+ :mobile-lines="2"
+ :show-more-text="$options.i18n.showMore"
+ :show-less-text="$options.i18n.showLess"
+ class="gl-mt-2"
+ >
+ <div
+ v-safe-html:[$options.safeHtmlConfig]="group.descriptionHtml"
+ class="gl-font-sm md"
+ data-testid="group-description"
+ ></div>
+ </gl-truncate-text>
+ </gl-avatar-labeled>
+ </div>
+ <div
+ class="gl-md-display-flex gl-flex-direction-column gl-align-items-flex-end gl-flex-shrink-0 gl-mt-3 gl-md-pl-0 gl-md-mt-0 gl-md-ml-3"
+ :class="statsPadding"
+ >
+ <div class="gl-display-flex gl-align-items-center gl-gap-x-3">
+ <div
+ v-gl-tooltip="$options.i18n.subgroups"
+ :aria-label="$options.i18n.subgroups"
+ class="gl-text-secondary"
+ data-testid="subgroups-count"
+ >
+ <gl-icon name="subgroup" />
+ <span>{{ descendantGroupsCount }}</span>
</div>
- </template>
- <gl-truncate-text
- v-if="group.descriptionHtml"
- :lines="2"
- :mobile-lines="2"
- :show-more-text="$options.i18n.showMore"
- :show-less-text="$options.i18n.showLess"
- class="gl-mt-2"
- >
<div
- v-safe-html:[$options.safeHtmlConfig]="group.descriptionHtml"
- class="gl-font-sm md"
- data-testid="group-description"
- ></div>
- </gl-truncate-text>
- </gl-avatar-labeled>
- </div>
- <div
- class="gl-md-display-flex gl-flex-direction-column gl-align-items-flex-end gl-flex-shrink-0 gl-mt-3 gl-md-pl-0 gl-md-mt-0 gl-md-ml-3"
- :class="statsPadding"
- >
- <div class="gl-display-flex gl-align-items-center gl-gap-x-3">
- <div
- v-gl-tooltip="$options.i18n.subgroups"
- :aria-label="$options.i18n.subgroups"
- class="gl-text-secondary"
- data-testid="subgroups-count"
- >
- <gl-icon name="subgroup" />
- <span>{{ descendantGroupsCount }}</span>
- </div>
- <div
- v-gl-tooltip="$options.i18n.projects"
- :aria-label="$options.i18n.projects"
- class="gl-text-secondary"
- data-testid="projects-count"
- >
- <gl-icon name="project" />
- <span>{{ projectsCount }}</span>
- </div>
- <div
- v-gl-tooltip="$options.i18n.directMembers"
- :aria-label="$options.i18n.directMembers"
- class="gl-text-secondary"
- data-testid="members-count"
- >
- <gl-icon name="users" />
- <span>{{ groupMembersCount }}</span>
+ v-gl-tooltip="$options.i18n.projects"
+ :aria-label="$options.i18n.projects"
+ class="gl-text-secondary"
+ data-testid="projects-count"
+ >
+ <gl-icon name="project" />
+ <span>{{ projectsCount }}</span>
+ </div>
+ <div
+ v-gl-tooltip="$options.i18n.directMembers"
+ :aria-label="$options.i18n.directMembers"
+ class="gl-text-secondary"
+ data-testid="members-count"
+ >
+ <gl-icon name="users" />
+ <span>{{ groupMembersCount }}</span>
+ </div>
</div>
</div>
</div>
+ <list-actions
+ v-if="hasActions"
+ class="gl-ml-3 gl-md-align-self-center"
+ :actions="actions"
+ :available-actions="group.availableActions"
+ />
+
+ <danger-confirm-modal
+ v-if="hasActionDelete"
+ v-model="isDeleteModalVisible"
+ :modal-id="modalId"
+ :phrase="group.fullName"
+ @confirm="$emit('delete', group)"
+ />
</li>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
deleted file mode 100644
index 1adda905006..00000000000
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ /dev/null
@@ -1,172 +0,0 @@
-<script>
-import { GlTooltipDirective, GlButton, GlAvatarLink, GlAvatarLabeled, GlTooltip } from '@gitlab/ui';
-import SafeHtml from '~/vue_shared/directives/safe_html';
-import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { glEmojiTag } from '~/emoji';
-import { __, sprintf } from '~/locale';
-import CiBadgeLink from './ci_badge_link.vue';
-import TimeagoTooltip from './time_ago_tooltip.vue';
-
-/**
- * Renders header component for job and pipeline page based on UI mockups
- *
- * Used in:
- * - job show page
- * - pipeline show page
- */
-export default {
- components: {
- CiBadgeLink,
- TimeagoTooltip,
- GlButton,
- GlAvatarLink,
- GlAvatarLabeled,
- GlTooltip,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- SafeHtml,
- },
- EMOJI_REF: 'EMOJI_REF',
- props: {
- status: {
- type: Object,
- required: true,
- },
- itemName: {
- type: String,
- required: true,
- },
- itemId: {
- type: String,
- required: false,
- default: '',
- },
- time: {
- type: String,
- required: true,
- },
- user: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- hasSidebarButton: {
- type: Boolean,
- required: false,
- default: false,
- },
- shouldRenderTriggeredLabel: {
- type: Boolean,
- required: false,
- default: true,
- },
- },
-
- computed: {
- userAvatarAltText() {
- return sprintf(__(`%{username}'s avatar`), { username: this.user.name });
- },
- userPath() {
- // GraphQL returns `webPath` and Rest `path`
- return this.user?.webPath || this.user?.path;
- },
- avatarUrl() {
- // GraphQL returns `avatarUrl` and Rest `avatar_url`
- return this.user?.avatarUrl || this.user?.avatar_url;
- },
- webUrl() {
- // GraphQL returns `webUrl` and Rest `web_url`
- return this.user?.webUrl || this.user?.web_url;
- },
- statusTooltipHTML() {
- // Rest `status_tooltip_html` which is a ready to work
- // html for the emoji and the status text inside a tooltip.
- // GraphQL returns `status.emoji` and `status.message` which
- // needs to be combined to make the html we want.
- const { emoji } = this.user?.status || {};
- const emojiHtml = emoji ? glEmojiTag(emoji) : '';
-
- return emojiHtml || this.user?.status_tooltip_html;
- },
- message() {
- return this.user?.status?.message;
- },
- item() {
- if (this.itemId) {
- return `${this.itemName} #${this.itemId}`;
- }
-
- return this.itemName;
- },
- userId() {
- return isGid(this.user?.id) ? getIdFromGraphQLId(this.user?.id) : this.user?.id;
- },
- },
-
- methods: {
- onClickSidebarButton() {
- this.$emit('clickedSidebarButton');
- },
- },
- safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
-};
-</script>
-
-<template>
- <header class="page-content-header gl-md-display-flex gl-min-h-7" data-testid="ci-header-content">
- <section class="header-main-content gl-mr-3">
- <ci-badge-link class="gl-mr-3" :status="status" />
-
- <strong data-testid="ci-header-item-text">{{ item }}</strong>
-
- <template v-if="shouldRenderTriggeredLabel">{{ __('triggered') }}</template>
- <template v-else>{{ __('created') }}</template>
-
- <timeago-tooltip :time="time" />
-
- {{ __('by') }}
-
- <template v-if="user">
- <gl-avatar-link
- :data-user-id="userId"
- :data-username="user.username"
- :data-name="user.name"
- :href="webUrl"
- target="_blank"
- class="js-user-link gl-vertical-align-middle gl-mx-2 gl-align-items-center"
- >
- <gl-avatar-labeled
- :size="24"
- :src="avatarUrl"
- :label="user.name"
- class="gl-display-none gl-sm-display-inline-flex gl-mx-1"
- />
- <strong class="author gl-display-inline gl-sm-display-none!">@{{ user.username }}</strong>
- <gl-tooltip v-if="message" :target="() => $refs[$options.EMOJI_REF]">
- {{ message }}
- </gl-tooltip>
- <span
- v-if="statusTooltipHTML"
- :ref="$options.EMOJI_REF"
- v-safe-html:[$options.safeHtmlConfig]="statusTooltipHTML"
- class="gl-ml-2"
- :data-testid="message"
- ></span>
- </gl-avatar-link>
- </template>
- </section>
-
- <!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots -->
- <section v-if="$slots.default" data-testid="ci-header-action-buttons" class="gl-display-flex">
- <slot></slot>
- </section>
- <gl-button
- v-if="hasSidebarButton"
- class="gl-md-display-none gl-ml-auto gl-align-self-start js-sidebar-build-toggle"
- icon="chevron-double-lg-left"
- :aria-label="__('Toggle sidebar')"
- @click="onClickSidebarButton"
- />
- </header>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/incidents/utils.js b/app/assets/javascripts/vue_shared/components/incidents/utils.js
deleted file mode 100644
index bcb578a6ba6..00000000000
--- a/app/assets/javascripts/vue_shared/components/incidents/utils.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import { noop } from 'lodash';
-
-export const isValidSlaDueAt = noop;
diff --git a/app/assets/javascripts/vue_shared/components/list_actions/constants.js b/app/assets/javascripts/vue_shared/components/list_actions/constants.js
new file mode 100644
index 00000000000..b1506ae1e93
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/list_actions/constants.js
@@ -0,0 +1,16 @@
+import { __ } from '~/locale';
+
+export const ACTION_EDIT = 'edit';
+export const ACTION_DELETE = 'delete';
+
+export const BASE_ACTIONS = {
+ [ACTION_EDIT]: {
+ text: __('Edit'),
+ },
+ [ACTION_DELETE]: {
+ text: __('Delete'),
+ extraAttrs: {
+ class: 'gl-text-red-500!',
+ },
+ },
+};
diff --git a/app/assets/javascripts/vue_shared/components/list_actions/list_actions.stories.js b/app/assets/javascripts/vue_shared/components/list_actions/list_actions.stories.js
new file mode 100644
index 00000000000..d34729c2373
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/list_actions/list_actions.stories.js
@@ -0,0 +1,44 @@
+import { makeContainer } from 'storybook_addons/make_container';
+import ListActions from './list_actions.vue';
+import { ACTION_DELETE, ACTION_EDIT } from './constants';
+
+export default {
+ component: ListActions,
+ title: 'vue_shared/list_actions',
+ decorators: [makeContainer({ height: '115px' })],
+ parameters: {
+ docs: {
+ description: {
+ component: `
+This component renders actions used by lists of resources such as groups and projects.
+Currently it is used by \`ProjectsListItem\`. There are base actions defined in \`~/vue_shared/components/list_actions\`
+that help reduce the amount of boilerplate needed for common actions such as edit and delete. This component accepts an
+\`actions\` prop that can extend the base actions and/or add custom actions. These actions should follow the format of
+a [disclosure dropdown item](https://gitlab-org.gitlab.io/gitlab-ui/?path=/docs/base-new-dropdowns-disclosure--docs#setting-disclosure-dropdown-items).
+The \`availableActions\` prop defines what actions to render and in what order. This prop will generally be set by checking
+permissions of the current user.
+`,
+ },
+ },
+ },
+};
+
+const Template = (args, { argTypes }) => ({
+ components: { ListActions },
+ props: Object.keys(argTypes),
+ template: '<list-actions v-bind="$props" />',
+});
+
+export const Default = Template.bind({});
+Default.args = {
+ actions: {
+ [ACTION_EDIT]: {
+ href: '/?path=/story/vue-shared-list-actions--default',
+ },
+ [ACTION_DELETE]: {
+ // eslint-disable-next-line no-console
+ action: () => console.log('Deleted'),
+ },
+ },
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+};
diff --git a/app/assets/javascripts/vue_shared/components/list_actions/list_actions.vue b/app/assets/javascripts/vue_shared/components/list_actions/list_actions.vue
new file mode 100644
index 00000000000..7b78cc1da8f
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/list_actions/list_actions.vue
@@ -0,0 +1,52 @@
+<script>
+import { GlDisclosureDropdown } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { BASE_ACTIONS } from './constants';
+
+export default {
+ name: 'ListActions',
+ i18n: {
+ actions: __('Actions'),
+ },
+ components: {
+ GlDisclosureDropdown,
+ },
+ props: {
+ // Can extend `BASE_ACTIONS` and/or add new actions.
+ // Expected format: https://gitlab-org.gitlab.io/gitlab-ui/?path=/docs/base-new-dropdowns-disclosure--docs#setting-disclosure-dropdown-items
+ actions: {
+ type: Object,
+ required: true,
+ },
+ availableActions: {
+ type: Array,
+ required: true,
+ },
+ },
+ computed: {
+ items() {
+ return this.availableActions.reduce((accumulator, action) => {
+ return [
+ ...accumulator,
+ {
+ ...BASE_ACTIONS[action],
+ ...this.actions[action],
+ },
+ ];
+ }, []);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-disclosure-dropdown
+ :items="items"
+ icon="ellipsis_v"
+ no-caret
+ :toggle-text="$options.i18n.actions"
+ text-sr-only
+ placement="right"
+ category="tertiary"
+ />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue b/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue
index a570abae9d3..05ce007e615 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/apply_suggestion.vue
@@ -1,9 +1,9 @@
<script>
-import { GlDropdown, GlDropdownForm, GlFormTextarea, GlButton, GlAlert } from '@gitlab/ui';
+import { GlDisclosureDropdown, GlForm, GlFormTextarea, GlButton, GlAlert } from '@gitlab/ui';
import { __, n__ } from '~/locale';
export default {
- components: { GlDropdown, GlDropdownForm, GlFormTextarea, GlButton, GlAlert },
+ components: { GlDisclosureDropdown, GlForm, GlFormTextarea, GlButton, GlAlert },
props: {
disabled: {
type: Boolean,
@@ -39,43 +39,58 @@ export default {
return n__('Apply %d suggestion', 'Apply %d suggestions', this.batchSuggestionsCount);
},
+ helperText() {
+ if (this.batchSuggestionsCount <= 1) {
+ return __('This also resolves this thread');
+ }
+
+ return __('This also resolves all related threads');
+ },
},
methods: {
onApply() {
this.$emit('apply', this.message);
},
+ focusCommitMessageInput() {
+ this.$refs.commitMessage.$el.focus();
+ },
},
};
</script>
<template>
- <gl-dropdown
- :text="dropdownText"
- :disabled="disabled"
- size="small"
- boundary="window"
- right
- lazy
- menu-class="gl-w-full!"
+ <gl-disclosure-dropdown
data-qa-selector="apply_suggestion_dropdown"
- @shown="$refs.commitMessage.$el.focus()"
+ fluid-width
+ placement="right"
+ size="small"
+ :disabled="disabled"
+ :toggle-text="dropdownText"
+ @shown="focusCommitMessageInput"
>
- <gl-dropdown-form class="gl-px-4! gl-m-0!">
+ <gl-form class="gl-display-flex gl-flex-direction-column gl-px-4! gl-mx-0! gl-my-2!">
<label for="commit-message">{{ __('Commit message') }}</label>
<gl-alert v-if="errorMessage" variant="danger" :dismissible="false" class="gl-mb-4">
{{ errorMessage }}
</gl-alert>
+
<gl-form-textarea
id="commit-message"
ref="commitMessage"
v-model="message"
+ class="apply-suggestions-input-min-width"
:placeholder="defaultCommitMessage"
submit-on-enter
data-qa-selector="commit_message_field"
@submit="onApply"
/>
+
+ <span class="gl-mt-2 gl-text-secondary">
+ {{ helperText }}
+ </span>
+
<gl-button
- class="gl-w-auto! gl-mt-3 gl-text-center! gl-transition-medium! float-right"
+ class="gl-w-auto! gl-mt-3 gl-align-self-end"
category="primary"
variant="confirm"
data-qa-selector="commit_with_custom_message_button"
@@ -83,6 +98,6 @@ export default {
>
{{ __('Apply') }}
</gl-button>
- </gl-dropdown-form>
- </gl-dropdown>
+ </gl-form>
+ </gl-disclosure-dropdown>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/comment_templates_dropdown.vue b/app/assets/javascripts/vue_shared/components/markdown/comment_templates_dropdown.vue
index b1c6f5e6056..f7f5ccdbf31 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/comment_templates_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/comment_templates_dropdown.vue
@@ -4,7 +4,11 @@ import fuzzaldrinPlus from 'fuzzaldrin-plus';
import { getDerivedMergeRequestInformation } from '~/diffs/utils/merge_request';
import { InternalEvents } from '~/tracking';
import savedRepliesQuery from './saved_replies.query.graphql';
-import { TRACKING_SAVED_REPLIES_USE, TRACKING_SAVED_REPLIES_USE_IN_MR } from './constants';
+import {
+ TRACKING_SAVED_REPLIES_USE,
+ TRACKING_SAVED_REPLIES_USE_IN_MR,
+ TRACKING_SAVED_REPLIES_USE_IN_OTHER,
+} from './constants';
export default {
apollo: {
@@ -61,9 +65,9 @@ export default {
if (savedReply) {
this.$emit('select', savedReply.content);
this.track_event(TRACKING_SAVED_REPLIES_USE);
- if (isInMr) {
- this.track_event(TRACKING_SAVED_REPLIES_USE_IN_MR);
- }
+ this.track_event(
+ isInMr ? TRACKING_SAVED_REPLIES_USE_IN_MR : TRACKING_SAVED_REPLIES_USE_IN_OTHER,
+ );
}
},
},
diff --git a/app/assets/javascripts/vue_shared/components/markdown/constants.js b/app/assets/javascripts/vue_shared/components/markdown/constants.js
index 47ef7cccbc2..7b31c4a59e3 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/constants.js
+++ b/app/assets/javascripts/vue_shared/components/markdown/constants.js
@@ -1,2 +1,3 @@
export const TRACKING_SAVED_REPLIES_USE = 'i_code_review_saved_replies_use';
export const TRACKING_SAVED_REPLIES_USE_IN_MR = 'i_code_review_saved_replies_use_in_mr';
+export const TRACKING_SAVED_REPLIES_USE_IN_OTHER = 'i_code_review_saved_replies_use_in_other';
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field_view.vue b/app/assets/javascripts/vue_shared/components/markdown/field_view.vue
index 84d40db07bb..c70197c6715 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field_view.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field_view.vue
@@ -2,8 +2,26 @@
import { renderGFM } from '~/behaviors/markdown/render_gfm';
export default {
+ props: {
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ watch: {
+ isLoading() {
+ this.handleGFM();
+ },
+ },
mounted() {
- renderGFM(this.$el);
+ this.handleGFM();
+ },
+ methods: {
+ handleGFM() {
+ if (this.isLoading) return;
+ renderGFM(this.$el);
+ },
},
};
</script>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
index 493b329f1b1..fc7e0a7c732 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
@@ -119,9 +119,11 @@ export default {
},
},
data() {
+ const editingMode =
+ localStorage.getItem(this.$options.EDITING_MODE_KEY) || EDITING_MODE_MARKDOWN_FIELD;
return {
markdown: this.value || (this.autosaveKey ? getDraft(this.autosaveKey) : '') || '',
- editingMode: EDITING_MODE_MARKDOWN_FIELD,
+ editingMode,
autofocused: false,
};
},
diff --git a/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js b/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js
index 0b0867ae84c..6c2f084591e 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js
+++ b/app/assets/javascripts/vue_shared/components/markdown/mount_markdown_editor.js
@@ -72,7 +72,7 @@ export function mountMarkdownEditor(options = {}) {
quickActionsDocsPath,
formFieldPlaceholder,
formFieldClasses,
- qaSelector,
+ testid,
newIssuePath,
} = el.dataset;
@@ -115,7 +115,7 @@ export function mountMarkdownEditor(options = {}) {
id: formFieldId,
name: formFieldName,
class: formFieldClasses,
- 'data-qa-selector': qaSelector,
+ 'data-testid': testid,
},
autosaveKey,
enableAutocomplete,
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
index 855c7a449c4..8a0ca8ebac1 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
@@ -77,9 +77,7 @@ export default {
return this.inapplicableReason;
}
- return this.batchSuggestionsCount > 1
- ? __('This also resolves all related threads')
- : __('This also resolves this thread');
+ return false;
},
isDisableButton() {
return this.isApplying || !this.canApply;
diff --git a/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue b/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue
index 9179331cdec..0ec8b6e2a0a 100644
--- a/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/noteable_warning.vue
@@ -6,6 +6,9 @@ const noteableTypeText = {
Issue: __('issue'),
Epic: __('epic'),
MergeRequest: __('merge request'),
+ Task: __('task'),
+ KeyResult: __('key result'),
+ Objective: __('objective'),
};
export default {
diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js
index df1188d365b..77fd197978f 100644
--- a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js
+++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js
@@ -1,5 +1,3 @@
-import { __ } from '~/locale';
-
export const tdClass =
'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
export const thClass = 'gl-hover-bg-blue-50';
@@ -15,7 +13,3 @@ export const initialPaginationState = {
firstPageSize: defaultPageSize,
lastPageSize: null,
};
-
-export const defaultI18n = {
- searchPlaceholder: __('Search or filter results…'),
-};
diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue
index ab9e6e092d9..0c3d175684c 100644
--- a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue
+++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue
@@ -14,11 +14,10 @@ import {
} from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import UserToken from '~/vue_shared/components/filtered_search_bar/tokens/user_token.vue';
-import { initialPaginationState, defaultI18n, defaultPageSize } from './constants';
+import { initialPaginationState, defaultPageSize } from './constants';
import { isAny } from './utils';
export default {
- defaultI18n,
components: {
GlAlert,
GlBadge,
@@ -300,7 +299,6 @@ export default {
<div class="filtered-search-wrapper">
<filtered-search-bar
:namespace="projectPath"
- :search-input-placeholder="$options.defaultI18n.searchPlaceholder"
:tokens="filteredSearchTokens"
:initial-filter-value="filteredSearchValue"
initial-sortby="created_desc"
diff --git a/app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue b/app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue
index e1f042f78ab..76bedc0feeb 100644
--- a/app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue
+++ b/app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue
@@ -64,7 +64,7 @@ export default {
<template>
<gl-pagination
v-if="showPagination"
- class="gl-mt-3"
+ class="gl-mt-5"
v-bind="$attrs"
align="center"
:value="pageInfo.page"
diff --git a/app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.vue b/app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.vue
index c1246b2bf44..4f580d4a848 100644
--- a/app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.vue
+++ b/app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.vue
@@ -1,5 +1,11 @@
<script>
-import { GlDropdown, GlDropdownItem, GlIcon, GlSprintf } from '@gitlab/ui';
+import {
+ GlButton,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlIcon,
+ GlSprintf,
+} from '@gitlab/ui';
import { __ } from '~/locale';
import PaginationLinks from '~/vue_shared/components/pagination_links.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
@@ -9,8 +15,9 @@ const DEFAULT_PAGE_SIZES = [20, 50, 100];
export default {
components: {
PaginationLinks,
- GlDropdown,
- GlDropdownItem,
+ GlButton,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
GlIcon,
GlSprintf,
LocalStorageSync,
@@ -80,25 +87,31 @@ export default {
@input="setPageSize"
/>
<pagination-links :change="setPage" :page-info="pageInfo" class="gl-m-0" />
- <gl-dropdown category="tertiary" class="gl-ml-auto" data-testid="page-size">
- <template #button-content>
- <span class="gl-font-weight-bold">
+ <gl-disclosure-dropdown category="tertiary" class="gl-ml-auto" data-testid="page-size">
+ <template #toggle>
+ <gl-button class="gl-font-weight-bold" category="tertiary">
<gl-sprintf :message="__('%{count} items per page')">
<template #count>
{{ pageInfo.perPage }}
</template>
</gl-sprintf>
- </span>
- <gl-icon class="gl-button-icon dropdown-chevron" name="chevron-down" />
+ <gl-icon class="gl-button-icon dropdown-chevron" name="chevron-down" />
+ </gl-button>
</template>
- <gl-dropdown-item v-for="size in pageSizes" :key="size" @click="setPageSize(size)">
- <gl-sprintf :message="__('%{count} items per page')">
- <template #count>
- {{ size }}
- </template>
- </gl-sprintf>
- </gl-dropdown-item>
- </gl-dropdown>
+ <gl-disclosure-dropdown-item
+ v-for="size in pageSizes"
+ :key="size"
+ @action="setPageSize(size)"
+ >
+ <template #list-item>
+ <gl-sprintf :message="__('%{count} items per page')">
+ <template #count>
+ {{ size }}
+ </template>
+ </gl-sprintf>
+ </template>
+ </gl-disclosure-dropdown-item>
+ </gl-disclosure-dropdown>
<div class="gl-ml-2" data-testid="information">
<gl-sprintf :message="s__('BulkImport|Showing %{start}-%{end} of %{total}')">
<template #start>
diff --git a/app/assets/javascripts/vue_shared/components/projects_list/constants.js b/app/assets/javascripts/vue_shared/components/projects_list/constants.js
deleted file mode 100644
index aa0b1418a06..00000000000
--- a/app/assets/javascripts/vue_shared/components/projects_list/constants.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export const ACTION_EDIT = 'edit';
-export const ACTION_DELETE = 'delete';
diff --git a/app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue b/app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue
index 9fc4571b0dc..ce75e305473 100644
--- a/app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue
+++ b/app/assets/javascripts/vue_shared/components/projects_list/projects_list_item.vue
@@ -7,7 +7,6 @@ import {
GlTooltipDirective,
GlPopover,
GlSprintf,
- GlDisclosureDropdown,
} from '@gitlab/ui';
import uniqueId from 'lodash/uniqueId';
@@ -20,8 +19,9 @@ import { numberToMetricPrefix } from '~/lib/utils/number_utils';
import { truncate } from '~/lib/utils/text_utility';
import SafeHtml from '~/vue_shared/directives/safe_html';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import ListActions from '~/vue_shared/components/list_actions/list_actions.vue';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
import DeleteModal from '~/projects/components/shared/delete_modal.vue';
-import { ACTION_EDIT, ACTION_DELETE } from './constants';
const MAX_TOPICS_TO_SHOW = 3;
const MAX_TOPIC_TITLE_LENGTH = 15;
@@ -51,8 +51,8 @@ export default {
GlPopover,
GlSprintf,
TimeAgoTooltip,
- GlDisclosureDropdown,
DeleteModal,
+ ListActions,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -163,30 +163,21 @@ export default {
return numberToMetricPrefix(this.project.openIssuesCount);
},
- actionsDropdownItems() {
- return [
- {
- id: ACTION_EDIT,
- text: __('Edit'),
+ actions() {
+ return {
+ [ACTION_EDIT]: {
href: this.project.editPath,
},
- {
- id: ACTION_DELETE,
- text: __('Delete'),
- extraAttrs: {
- class: 'gl-text-red-500!',
- },
- action: () => {
- this.isDeleteModalVisible = true;
- },
+ [ACTION_DELETE]: {
+ action: this.onActionDelete,
},
- ].filter(({ id }) => this.project.actions?.includes(id));
+ };
},
hasActions() {
- return this.actionsDropdownItems.length;
+ return this.project.availableActions?.length;
},
- hasDeleteAction() {
- return this.actionsDropdownItems.find((action) => action.id === ACTION_DELETE);
+ hasActionDelete() {
+ return this.project.availableActions?.includes(ACTION_DELETE);
},
},
methods: {
@@ -204,6 +195,9 @@ export default {
return null;
},
+ onActionDelete() {
+ this.isDeleteModalVisible = true;
+ },
},
};
</script>
@@ -336,20 +330,15 @@ export default {
</div>
</div>
</div>
- <gl-disclosure-dropdown
+ <list-actions
v-if="hasActions"
class="gl-ml-3 gl-md-align-self-center"
- :items="actionsDropdownItems"
- icon="ellipsis_v"
- no-caret
- :toggle-text="$options.i18n.actions"
- text-sr-only
- placement="right"
- category="tertiary"
+ :actions="actions"
+ :available-actions="project.availableActions"
/>
<delete-modal
- v-if="hasDeleteAction"
+ v-if="hasActionDelete"
v-model="isDeleteModalVisible"
:confirm-phrase="project.name"
:is-fork="project.isForked"
diff --git a/app/assets/javascripts/vue_shared/components/source_editor.vue b/app/assets/javascripts/vue_shared/components/source_editor.vue
index 7b7d3d48d9e..53c16fccba1 100644
--- a/app/assets/javascripts/vue_shared/components/source_editor.vue
+++ b/app/assets/javascripts/vue_shared/components/source_editor.vue
@@ -104,7 +104,7 @@ export default {
:id="`source-editor-${fileGlobalId}`"
ref="editor"
data-editor-loading
- data-qa-selector="source_editor_container"
+ data-testid="source-editor-container"
@[$options.readyEvent]="$emit($options.readyEvent, $event)"
>
<pre class="editor-loading-content">{{ value }}</pre>
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_new.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_new.vue
index b89fa3f8292..8dac6327a99 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_new.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_new.vue
@@ -82,6 +82,7 @@ export default {
methods: {
handleChunkAppear() {
this.hasAppeared = true;
+ this.$emit('appear');
},
calculateLineNumber(index) {
return this.startingFrom + index + 1;
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue
index a4d50466f8f..797a38d8171 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue
@@ -33,6 +33,7 @@ export default {
components: {
GlLoadingIcon,
Chunk,
+ CodeownersValidation: () => import('ee_component/blob/components/codeowners_validation.vue'),
},
mixins: [Tracking.mixin()],
props: {
@@ -40,6 +41,14 @@ export default {
type: Object,
required: true,
},
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ currentRef: {
+ type: String,
+ required: true,
+ },
},
data() {
return {
@@ -49,7 +58,6 @@ export default {
firstChunk: null,
chunks: {},
isLoading: true,
- isLineSelected: false,
lineHighlighter: null,
};
},
@@ -66,7 +74,8 @@ export default {
if (this.blob.name && this.blob.name.endsWith(`.${SVELTE_LANGUAGE}`)) {
// override for svelte files until https://github.com/rouge-ruby/rouge/issues/1717 is resolved
return SVELTE_LANGUAGE;
- } else if (this.blob.name === this.$options.codeownersFileName) {
+ }
+ if (this.isCodeownersFile) {
// override for codeowners files
return this.$options.codeownersLanguage;
}
@@ -87,6 +96,9 @@ export default {
totalChunks() {
return Object.keys(this.chunks).length;
},
+ isCodeownersFile() {
+ return this.blob.name === CODEOWNERS_FILE_NAME;
+ },
},
async created() {
if (this.isLfsBlob) {
@@ -121,7 +133,7 @@ export default {
this.generateRemainingChunks();
this.isLoading = false;
await this.$nextTick();
- this.lineHighlighter = new LineHighlighter({ scrollBehavior: 'auto' });
+ this.selectLine();
});
},
methods: {
@@ -227,18 +239,16 @@ export default {
return languageDefinition;
},
async selectLine() {
- if (this.isLineSelected || !this.lineHighlighter) {
- return;
+ if (!this.lineHighlighter) {
+ this.lineHighlighter = new LineHighlighter({ scrollBehavior: 'auto' });
}
-
- this.isLineSelected = true;
await this.$nextTick();
- this.lineHighlighter.highlightHash(this.$route.hash);
+ const scrollEnabled = false;
+ this.lineHighlighter.highlightHash(this.$route.hash, scrollEnabled);
},
},
userColorScheme: window.gon.user_color_scheme,
currentlySelectedLine: null,
- codeownersFileName: CODEOWNERS_FILE_NAME,
codeownersLanguage: CODEOWNERS_LANGUAGE,
};
</script>
@@ -250,6 +260,13 @@ export default {
:data-path="blob.path"
data-qa-selector="blob_viewer_file_content"
>
+ <codeowners-validation
+ v-if="isCodeownersFile"
+ class="gl-text-black-normal"
+ :current-ref="currentRef"
+ :project-path="projectPath"
+ :file-path="blob.path"
+ />
<chunk
v-if="firstChunk"
:lines="firstChunk.lines"
@@ -263,20 +280,21 @@ export default {
/>
<gl-loading-icon v-if="isLoading" size="sm" class="gl-my-5" />
- <chunk
- v-for="(chunk, key, index) in chunks"
- v-else
- :key="key"
- :lines="chunk.lines"
- :content="chunk.content"
- :total-lines="chunk.totalLines"
- :starting-from="chunk.startingFrom"
- :is-highlighted="chunk.isHighlighted"
- :chunk-index="index"
- :language="chunk.language"
- :blame-path="blob.blamePath"
- :total-chunks="totalChunks"
- @appear="highlightChunk"
- />
+ <template v-else>
+ <chunk
+ v-for="(chunk, key, index) in chunks"
+ :key="key"
+ :lines="chunk.lines"
+ :content="chunk.content"
+ :total-lines="chunk.totalLines"
+ :starting-from="chunk.startingFrom"
+ :is-highlighted="chunk.isHighlighted"
+ :chunk-index="index"
+ :language="chunk.language"
+ :blame-path="blob.blamePath"
+ :total-chunks="totalChunks"
+ @appear="highlightChunk"
+ />
+ </template>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
index 0fb6e577f32..c7353ed6785 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer_new.vue
@@ -41,8 +41,14 @@ export default {
addBlobLinksTracking();
},
mounted() {
- const { hash } = this.$route;
- this.lineHighlighter.highlightHash(hash);
+ this.selectLine();
+ },
+ methods: {
+ async selectLine() {
+ await this.$nextTick();
+ const scrollEnabled = false;
+ this.lineHighlighter.highlightHash(this.$route.hash, scrollEnabled);
+ },
},
userColorScheme: window.gon.user_color_scheme,
};
@@ -66,6 +72,7 @@ export default {
:total-lines="chunk.totalLines"
:starting-from="chunk.startingFrom"
:blame-path="blob.blamePath"
+ @appear="selectLine"
/>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/split_button.vue b/app/assets/javascripts/vue_shared/components/split_button.vue
deleted file mode 100644
index c0aef42b0f2..00000000000
--- a/app/assets/javascripts/vue_shared/components/split_button.vue
+++ /dev/null
@@ -1,85 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownDivider, GlDropdownItem } from '@gitlab/ui';
-import { isString } from 'lodash';
-
-const isValidItem = (item) =>
- isString(item.eventName) && isString(item.title) && isString(item.description);
-
-export default {
- components: {
- GlDropdown,
- GlDropdownDivider,
- GlDropdownItem,
- },
-
- props: {
- actionItems: {
- type: Array,
- required: true,
- validator(value) {
- return value.length > 1 && value.every(isValidItem);
- },
- },
- menuClass: {
- type: String,
- required: false,
- default: '',
- },
- variant: {
- type: String,
- required: false,
- default: 'default',
- },
- },
-
- data() {
- return {
- selectedItem: this.actionItems[0],
- };
- },
-
- computed: {
- dropdownToggleText() {
- return this.selectedItem.title;
- },
- },
-
- methods: {
- triggerEvent() {
- this.$emit(this.selectedItem.eventName);
- },
- changeSelectedItem(item) {
- this.selectedItem = item;
- this.$emit('change', item);
- },
- },
-};
-</script>
-
-<template>
- <gl-dropdown
- :menu-class="menuClass"
- split
- :text="dropdownToggleText"
- :variant="variant"
- v-bind="$attrs"
- @click="triggerEvent"
- >
- <template v-for="(item, itemIndex) in actionItems">
- <gl-dropdown-item
- :key="item.eventName"
- is-check-item
- :is-checked="selectedItem === item"
- @click="changeSelectedItem(item)"
- >
- <strong>{{ item.title }}</strong>
- <div>{{ item.description }}</div>
- </gl-dropdown-item>
-
- <gl-dropdown-divider
- v-if="itemIndex < actionItems.length - 1"
- :key="`${item.eventName}-divider`"
- />
- </template>
- </gl-dropdown>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue
index bda88a48e48..9ba5e8724f9 100644
--- a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue
@@ -70,7 +70,8 @@ export default {
selectTarget() {
if (isFunction(this.truncateTarget)) {
return this.truncateTarget(this.$el);
- } else if (this.truncateTarget === 'child') {
+ }
+ if (this.truncateTarget === 'child') {
return this.$el.childNodes[0];
}
return this.$el;
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
index 446c8c97df0..30f616dd8e1 100644
--- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -83,9 +83,11 @@ export default {
if (this.user.status.emoji && this.user.status.message_html) {
return `${glEmojiTag(this.user.status.emoji)} ${this.user.status.message_html}`;
- } else if (this.user.status.message_html) {
+ }
+ if (this.user.status.message_html) {
return this.user.status.message_html;
- } else if (this.user.status.emoji) {
+ }
+ if (this.user.status.emoji) {
return glEmojiTag(this.user.status.emoji);
}
diff --git a/app/assets/javascripts/vue_shared/components/user_select/user_select.vue b/app/assets/javascripts/vue_shared/components/user_select/user_select.vue
index 4879baced0d..863c43b0e55 100644
--- a/app/assets/javascripts/vue_shared/components/user_select/user_select.vue
+++ b/app/assets/javascripts/vue_shared/components/user_select/user_select.vue
@@ -13,7 +13,7 @@ import { __ } from '~/locale';
import SidebarParticipant from '~/sidebar/components/assignees/sidebar_participant.vue';
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import { participantsQueries, userSearchQueries } from '~/sidebar/constants';
+import { participantsQueries, userSearchQueries } from '~/sidebar/queries/constants';
import { TYPENAME_MERGE_REQUEST } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
@@ -130,11 +130,11 @@ export default {
},
update(data) {
return (
- data.workspace?.users?.nodes
- .filter((x) => x?.user)
- .map((node) => ({
- ...node.user,
- canMerge: node.mergeRequestInteraction?.canMerge || false,
+ data.workspace?.users
+ .filter((user) => user)
+ .map((user) => ({
+ ...user,
+ canMerge: user.mergeRequestInteraction?.canMerge || false,
})) || []
);
},
diff --git a/app/assets/javascripts/vue_shared/components/web_ide_link.vue b/app/assets/javascripts/vue_shared/components/web_ide_link.vue
index 79d14b5f2d0..beb8321a271 100644
--- a/app/assets/javascripts/vue_shared/components/web_ide_link.vue
+++ b/app/assets/javascripts/vue_shared/components/web_ide_link.vue
@@ -195,9 +195,11 @@ export default {
webIdeActionText() {
if (this.webIdeText) {
return this.webIdeText;
- } else if (this.isBlob) {
+ }
+ if (this.isBlob) {
return __('Open in Web IDE');
- } else if (this.isFork) {
+ }
+ if (this.isFork) {
return __('Edit fork in Web IDE');
}
diff --git a/app/assets/javascripts/vue_shared/constants.js b/app/assets/javascripts/vue_shared/constants.js
index d9bc2c82688..9c001fa2e9a 100644
--- a/app/assets/javascripts/vue_shared/constants.js
+++ b/app/assets/javascripts/vue_shared/constants.js
@@ -86,7 +86,7 @@ export const confidentialityInfoText = (workspaceType, issuableType) =>
),
{
workspaceType: workspaceType === WORKSPACE_PROJECT ? __('project') : __('group'),
- issuableType: issuableType.toLowerCase(),
+ issuableType: issuableType.toLowerCase().replaceAll('_', ' '),
permissions:
issuableType === TYPE_ISSUE
? __('at least the Reporter role, the author, and assignees')
diff --git a/app/assets/javascripts/vue_shared/issuable/create/components/issuable_form.vue b/app/assets/javascripts/vue_shared/issuable/create/components/issuable_form.vue
index 699b41f3bf3..1cfa3f6d3d7 100644
--- a/app/assets/javascripts/vue_shared/issuable/create/components/issuable_form.vue
+++ b/app/assets/javascripts/vue_shared/issuable/create/components/issuable_form.vue
@@ -36,7 +36,7 @@ export default {
ariaLabel: __('Description'),
class: 'rspec-issuable-form-description',
placeholder: __('Write a comment or drag your files here…'),
- dataQaSelector: 'issuable_form_description_field',
+ dataTestid: 'issuable-form-description-field',
id: 'issuable-description',
name: 'issuable-description',
},
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
index 31dd49ca415..690d9523a63 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
@@ -8,6 +8,7 @@ import { isExternal, setUrlFragment } from '~/lib/utils/url_utility';
import { __, n__, sprintf } from '~/locale';
import IssuableAssignees from '~/issuable/components/issue_assignees.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
+import SafeHtml from '~/vue_shared/directives/safe_html';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
import { STATE_CLOSED } from '~/work_items/constants';
import { isAssigneesWidget, isLabelsWidget } from '~/work_items/utils';
@@ -24,6 +25,7 @@ export default {
},
directives: {
GlTooltip: GlTooltipDirective,
+ SafeHtml,
},
mixins: [timeagoMixin],
props: {
@@ -80,14 +82,20 @@ export default {
author() {
return this.issuable.author || {};
},
+ externalAuthor() {
+ return this.issuable.externalAuthor;
+ },
webUrl() {
return this.issuable.gitlabWebUrl || this.issuable.webUrl;
},
authorId() {
return getIdFromGraphQLId(this.author.id);
},
+ isIssueTrackerExternal() {
+ return Boolean(this.issuable.externalTracker);
+ },
isIssuableUrlExternal() {
- return isExternal(this.webUrl);
+ return isExternal(this.webUrl ?? '');
},
reference() {
return this.issuable.reference || `${this.issuableSymbol}${this.issuable.iid}`;
@@ -130,7 +138,8 @@ export default {
return sprintf(__('closed %{timeago}'), {
timeago: this.timeFormatted(this.issuable.closedAt),
});
- } else if (this.issuable.updatedAt !== this.issuable.createdAt) {
+ }
+ if (this.issuable.updatedAt !== this.issuable.createdAt) {
return sprintf(__('updated %{timeAgo}'), {
timeAgo: this.timeFormatted(this.issuable.updatedAt),
});
@@ -242,6 +251,7 @@ export default {
<div data-testid="issuable-title" class="issue-title title">
<work-item-type-icon
v-if="showWorkItemTypeIcon"
+ class="gl-mr-2"
:work-item-type="type"
show-tooltip-on-hover
/>
@@ -259,18 +269,33 @@ export default {
:title="__('This issue is hidden because its author has been banned')"
:aria-label="__('Hidden')"
/>
- <gl-link
- class="issue-title-text"
- dir="auto"
- :href="webUrl"
- data-qa-selector="issuable_title_link"
- data-testid="issuable-title-link"
- v-bind="issuableTitleProps"
- @click="handleIssuableItemClick"
- >
- {{ issuable.title }}
+ <template v-if="isIssueTrackerExternal">
+ <gl-link
+ class="issue-title-text"
+ dir="auto"
+ :href="webUrl"
+ data-qa-selector="issuable_title_link"
+ data-testid="issuable-title-link"
+ v-bind="issuableTitleProps"
+ @click="handleIssuableItemClick"
+ >
+ {{ issuable.title }}
+ <gl-icon v-if="isIssuableUrlExternal" name="external-link" class="gl-ml-2" />
+ </gl-link>
+ </template>
+ <template v-else>
+ <gl-link
+ v-safe-html="issuable.titleHtml || issuable.title"
+ class="issue-title-text"
+ dir="auto"
+ :href="webUrl"
+ data-qa-selector="issuable_title_link"
+ data-testid="issuable-title-link"
+ v-bind="issuableTitleProps"
+ @click="handleIssuableItemClick"
+ />
<gl-icon v-if="isIssuableUrlExternal" name="external-link" class="gl-ml-2" />
- </gl-link>
+ </template>
<span
v-if="taskStatus"
class="task-status gl-display-none gl-sm-display-inline-block! gl-ml-2 gl-font-sm"
@@ -298,6 +323,9 @@ export default {
</span>
</template>
<template #author>
+ <span v-if="externalAuthor" data-testid="external-author"
+ >{{ externalAuthor }} {{ __('via') }}</span
+ >
<slot v-if="hasSlotContents('author')" name="author"></slot>
<gl-link
v-else
@@ -344,7 +372,7 @@ export default {
</div>
<div class="issuable-meta">
<ul v-if="showIssuableMeta" class="controls">
- <li v-if="hasSlotContents('status')" class="issuable-status">
+ <li v-if="hasSlotContents('status')">
<slot name="status"></slot>
</li>
<li v-if="assignees.length">
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
index 7a9404e06c7..0db7417cebc 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
@@ -5,6 +5,7 @@ import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import PageSizeSelector from '~/vue_shared/components/page_size_selector.vue';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { updateHistory, setUrlParams } from '~/lib/utils/url_utility';
+import { __ } from '~/locale';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -51,7 +52,8 @@ export default {
},
searchInputPlaceholder: {
type: String,
- required: true,
+ required: false,
+ default: __('Search or filter results…'),
},
searchTokens: {
type: Array,
@@ -344,7 +346,7 @@ export default {
:show-friendly-text="showFilteredSearchFriendlyText"
terms-as-tokens
class="gl-flex-grow-1 gl-border-t-none row-content-block"
- data-qa-selector="issuable_search_container"
+ data-testid="issuable-search-container"
@checked-input="handleAllIssuablesCheckedInput"
@onFilter="$emit('filter', $event)"
@onSort="$emit('sort', $event)"
@@ -377,7 +379,7 @@ export default {
v-for="issuable in issuables"
:key="issuableId(issuable)"
:class="{ 'gl-cursor-grab': isManualOrdering }"
- data-qa-selector="issuable_container"
+ data-testid="issuable-container"
:data-qa-issuable-title="issuable.title"
:has-scoped-labels-feature="hasScopedLabelsFeature"
:issuable-symbol="issuableSymbol"
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_tabs.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_tabs.vue
index 0691bc02b5c..ab71842ae13 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_tabs.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_tabs.vue
@@ -56,7 +56,7 @@ export default {
@click="$emit('click', tab.name)"
>
<template #title>
- <span :title="tab.titleTooltip" :data-qa-selector="`${tab.name}_issuables_tab`">
+ <span :title="tab.titleTooltip" :data-testid="`${tab.name}-issuables-tab`">
{{ tab.title }}
</span>
<gl-badge
diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_description.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_description.vue
index ce1851ab873..01389cd90a9 100644
--- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_description.vue
+++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_description.vue
@@ -34,7 +34,7 @@ export default {
<div
class="description"
:class="{ 'js-task-list-container': canEdit && enableTaskList }"
- data-qa-selector="description_content"
+ data-testid="description-content"
>
<div ref="gfmContainer" v-safe-html="issuable.descriptionHtml" class="md"></div>
<textarea
diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
index 29aef89a991..c4b92454ac0 100644
--- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
+++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue
@@ -162,8 +162,8 @@ export default {
<template>
<div class="detail-page-header gl-flex-direction-column gl-sm-flex-direction-row">
- <div class="detail-page-header-body gl-flex-wrap">
- <gl-badge class="gl-mr-2" :variant="badgeVariant">
+ <div class="detail-page-header-body gl-flex-wrap gl-gap-2">
+ <gl-badge :variant="badgeVariant" data-testid="issue-state-badge">
<gl-icon v-if="statusIcon" :name="statusIcon" :class="statusIconClass" />
<span class="gl-display-none gl-sm-display-block" :class="{ 'gl-ml-2': statusIcon }">
<slot name="status-badge">{{ badgeText }}</slot>
@@ -193,18 +193,18 @@ export default {
<work-item-type-icon
v-if="shouldShowWorkItemTypeIcon"
show-text
- :work-item-type="issuableType.toUpperCase()"
+ :work-item-type="issuableType"
/>
<gl-sprintf :message="createdMessage">
<template #timeAgo>
- <time-ago-tooltip class="gl-mx-2" :time="createdAt" />
+ <time-ago-tooltip :time="createdAt" />
</template>
<template #email>
{{ serviceDeskReplyTo }}
</template>
<template #author>
<gl-link
- class="gl-font-weight-bold gl-mx-2 js-user-link"
+ class="gl-font-weight-bold js-user-link"
:href="author.webUrl"
:data-user-id="authorId"
>
@@ -225,7 +225,6 @@ export default {
<gl-icon
v-if="isFirstContribution"
v-gl-tooltip
- class="gl-mr-2"
name="first-contribution"
:title="__('1st contribution!')"
:aria-label="__('1st contribution!')"
diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_show_root.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_show_root.vue
index 2bc57ecba55..3878c16c8d0 100644
--- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_show_root.vue
+++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_show_root.vue
@@ -92,6 +92,11 @@ export default {
required: false,
default: false,
},
+ workspaceType: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
methods: {
handleKeydownTitle(e, issuableMeta) {
@@ -105,7 +110,7 @@ export default {
</script>
<template>
- <div class="issuable-show-container" data-qa-selector="issuable_show_container">
+ <div class="issuable-show-container" data-testid="issuable-show-container">
<issuable-header
:issuable-state="issuable.state"
:status-icon="statusIcon"
@@ -116,6 +121,7 @@ export default {
:author="issuable.author"
:task-completion-status="taskCompletionStatus"
:issuable-type="issuable.type"
+ :workspace-type="workspaceType"
:show-work-item-type-icon="showWorkItemTypeIcon"
>
<template #status-badge>
diff --git a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue
index 841d92fd63d..da71adc8abd 100644
--- a/app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue
+++ b/app/assets/javascripts/vue_shared/issuable/show/components/issuable_title.vue
@@ -60,8 +60,7 @@ export default {
v-safe-html="issuable.titleHtml || issuable.title"
class="title gl-font-size-h-display"
dir="auto"
- data-qa-selector="title_content"
- data-testid="title"
+ data-testid="issuable-title"
></h1>
<gl-button
v-if="enableEdit"
diff --git a/app/assets/javascripts/vue_shared/new_namespace/new_namespace_page.vue b/app/assets/javascripts/vue_shared/new_namespace/new_namespace_page.vue
index 4503ba6e561..f54c4c52743 100644
--- a/app/assets/javascripts/vue_shared/new_namespace/new_namespace_page.vue
+++ b/app/assets/javascripts/vue_shared/new_namespace/new_namespace_page.vue
@@ -88,6 +88,10 @@ export default {
showSuperSidebarToggle() {
return gon.use_new_navigation && sidebarState.isCollapsed;
},
+
+ topBarClasses() {
+ return gon.use_new_navigation ? 'top-bar-fixed container-fluid' : '';
+ },
},
created() {
@@ -120,15 +124,17 @@ export default {
<template>
<div>
- <div
- class="top-bar-container gl-display-flex gl-align-items-center gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid"
- >
- <super-sidebar-toggle
- v-if="showSuperSidebarToggle"
- class="gl-mr-2"
- :class="$options.JS_TOGGLE_EXPAND_CLASS"
- />
- <gl-breadcrumb :items="breadcrumbs" data-testid="breadcrumb-links" />
+ <div :class="topBarClasses" data-testid="top-bar">
+ <div
+ class="top-bar-container gl-display-flex gl-align-items-center gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid"
+ >
+ <super-sidebar-toggle
+ v-if="showSuperSidebarToggle"
+ class="gl-mr-2"
+ :class="$options.JS_TOGGLE_EXPAND_CLASS"
+ />
+ <gl-breadcrumb :items="breadcrumbs" data-testid="breadcrumb-links" />
+ </div>
</div>
<template v-if="activePanel">
diff --git a/app/assets/javascripts/vue_shared/security_reports/components/security_report_download_dropdown.vue b/app/assets/javascripts/vue_shared/security_reports/components/security_report_download_dropdown.vue
index 28618cb96a3..61bca18b050 100644
--- a/app/assets/javascripts/vue_shared/security_reports/components/security_report_download_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/security_reports/components/security_report_download_dropdown.vue
@@ -1,15 +1,11 @@
<script>
-import { GlDropdown, GlDropdownItem, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
+import { GlDisclosureDropdown } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
export default {
name: 'SecurityReportDownloadDropdown',
components: {
- GlDropdown,
- GlDropdownItem,
- },
- directives: {
- GlTooltip,
+ GlDisclosureDropdown,
},
props: {
artifacts: {
@@ -26,19 +22,23 @@ export default {
required: false,
default: '',
},
- title: {
- type: String,
- required: false,
- default: '',
- },
},
computed: {
showDropdown() {
return this.loading || this.artifacts.length > 0;
},
+ items() {
+ return this.artifacts.map(({ name, path }) => ({
+ text: this.artifactText(name),
+ href: path,
+ extraAttrs: {
+ download: '',
+ },
+ }));
+ },
},
methods: {
- artifactText({ name }) {
+ artifactText(name) {
return sprintf(s__('SecurityReports|Download %{artifactName}'), {
artifactName: name,
});
@@ -48,23 +48,13 @@ export default {
</script>
<template>
- <gl-dropdown
+ <gl-disclosure-dropdown
v-if="showDropdown"
- v-gl-tooltip
- :text="text"
- :title="title"
+ :items="items"
+ :toggle-text="text"
:loading="loading"
icon="download"
size="small"
- right
- >
- <gl-dropdown-item
- v-for="artifact in artifacts"
- :key="artifact.path"
- :href="artifact.path"
- download
- >
- {{ artifactText(artifact) }}
- </gl-dropdown-item>
- </gl-dropdown>
+ placement="right"
+ />
</template>
diff --git a/app/assets/javascripts/vuex_shared/bindings.js b/app/assets/javascripts/vuex_shared/bindings.js
index bc3741a3880..07b16a13e68 100644
--- a/app/assets/javascripts/vuex_shared/bindings.js
+++ b/app/assets/javascripts/vuex_shared/bindings.js
@@ -20,7 +20,8 @@ export const mapComputed = (list, defaultUpdateFn, root) => {
get() {
if (getter) {
return this.$store.getters[getter];
- } else if (root) {
+ }
+ if (root) {
if (typeof root === 'function') {
return root(this.$store.state)[key];
}
diff --git a/app/assets/javascripts/webpack.js b/app/assets/javascripts/webpack.js
index 1c6e632135d..ef82142289d 100644
--- a/app/assets/javascripts/webpack.js
+++ b/app/assets/javascripts/webpack.js
@@ -7,6 +7,7 @@
* e.g. the `window` scope, because it needs to be executed in the scope of webpack.
*/
-if (gon && gon.webpack_public_path) {
+// eslint-disable-next-line camelcase
+if (gon && gon.webpack_public_path && typeof __webpack_public_path__ !== 'undefined') {
__webpack_public_path__ = gon.webpack_public_path; // eslint-disable-line camelcase
}
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_activity_sort_filter.vue b/app/assets/javascripts/work_items/components/notes/work_item_activity_sort_filter.vue
index 1ead16c944b..425679c1400 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_activity_sort_filter.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_activity_sort_filter.vue
@@ -1,13 +1,12 @@
<script>
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlCollapsibleListbox } from '@gitlab/ui';
import Tracking from '~/tracking';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
export default {
components: {
- GlDropdown,
- GlDropdownItem,
+ GlCollapsibleListbox,
LocalStorageSync,
},
mixins: [Tracking.mixin()],
@@ -25,7 +24,7 @@ export default {
type: String,
required: true,
},
- filterOptions: {
+ items: {
type: Array,
required: true,
},
@@ -63,8 +62,7 @@ export default {
},
selectedSortOption() {
return (
- this.filterOptions.find(({ key }) => this.sortFilterProp === key) ||
- this.defaultSortFilterProp
+ this.items.find(({ key }) => this.sortFilterProp === key) || this.defaultSortFilterProp
);
},
},
@@ -94,23 +92,14 @@ export default {
as-string
@input="setDiscussionFilterOption"
/>
- <gl-dropdown
- class="gl-xs-w-full"
- size="small"
- :text="getDropdownSelectedText"
+ <gl-collapsible-listbox
+ :toggle-text="getDropdownSelectedText"
:disabled="loading"
- right
- >
- <gl-dropdown-item
- v-for="{ text, key, testid } in filterOptions"
- :key="text"
- :data-testid="testid"
- is-check-item
- :is-checked="isSortDropdownItemActive(key)"
- @click="fetchFilteredDiscussions(key)"
- >
- {{ text }}
- </gl-dropdown-item>
- </gl-dropdown>
+ :items="items"
+ :selected="sortFilterProp"
+ placement="right"
+ size="small"
+ @select="fetchFilteredDiscussions"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue b/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
index 66ad3d50287..57faed61280 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_add_note.vue
@@ -74,6 +74,11 @@ export default {
required: false,
default: false,
},
+ isWorkItemConfidential: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -263,6 +268,7 @@ export default {
:work-item-id="workItemId"
:autofocus="autofocus"
:comment-button-text="commentButtonText"
+ :is-work-item-confidential="isWorkItemConfidential"
@submitForm="updateWorkItem"
@cancelEditing="cancelEditing"
@error="$emit('error', $event)"
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue
index b143c529014..a79169bde1e 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue
@@ -3,11 +3,13 @@ import { GlButton, GlFormCheckbox, GlIcon, GlTooltipDirective } from '@gitlab/ui
import { helpPagePath } from '~/helpers/help_page_helper';
import { s__, __ } from '~/locale';
import Tracking from '~/tracking';
-import { STATE_OPEN, TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import { STATE_OPEN, TRACKING_CATEGORY_SHOW, TASK_TYPE_NAME } from '~/work_items/constants';
import { getDraft, clearDraft, updateDraft } from '~/lib/utils/autosave';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import WorkItemStateToggleButton from '~/work_items/components/work_item_state_toggle_button.vue';
+import CommentFieldLayout from '~/notes/components/comment_field_layout.vue';
export default {
i18n: {
@@ -22,6 +24,7 @@ export default {
markdownDocsPath: helpPagePath('user/markdown'),
},
components: {
+ CommentFieldLayout,
GlButton,
MarkdownEditor,
GlFormCheckbox,
@@ -89,6 +92,11 @@ export default {
required: false,
default: false,
},
+ isWorkItemConfidential: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -119,6 +127,23 @@ export default {
commentButtonTextComputed() {
return this.isNoteInternal ? this.$options.i18n.addInternalNote : this.commentButtonText;
},
+ workItemDocPath() {
+ return this.workItemType === TASK_TYPE_NAME ? 'user/tasks.html' : 'user/okrs.html';
+ },
+ workItemDocAnchor() {
+ return this.workItemType === TASK_TYPE_NAME ? 'confidential-tasks' : 'confidential-okrs';
+ },
+ getWorkItemData() {
+ return {
+ confidential: this.isWorkItemConfidential,
+ confidential_issues_docs_path: helpPagePath(this.workItemDocPath, {
+ anchor: this.workItemDocAnchor,
+ }),
+ };
+ },
+ workItemTypeKey() {
+ return capitalizeFirstCharacter(this.workItemType).replace(' ', '');
+ },
},
methods: {
setCommentText(newText) {
@@ -158,66 +183,73 @@ export default {
<template>
<div class="timeline-discussion-body gl-overflow-visible!">
<div class="note-body gl-p-0! gl-overflow-visible!">
- <form class="common-note-form gfm-form js-main-target-form gl-flex-grow-1">
- <markdown-editor
- :value="commentText"
- :render-markdown-path="markdownPreviewPath"
- :markdown-docs-path="$options.constantOptions.markdownDocsPath"
- :autocomplete-data-sources="autocompleteDataSources"
- :form-field-props="formFieldProps"
- :add-spacing-classes="false"
- data-testid="work-item-add-comment"
- class="gl-mb-5"
- use-bottom-toolbar
- supports-quick-actions
- :autofocus="autofocus"
- @input="setCommentText"
- @keydown.meta.enter="$emit('submitForm', { commentText, isNoteInternal })"
- @keydown.ctrl.enter="$emit('submitForm', { commentText, isNoteInternal })"
- @keydown.esc.stop="cancelEditing"
- />
- <gl-form-checkbox
- v-if="isNewDiscussion"
- v-model="isNoteInternal"
- class="gl-mb-2"
- data-testid="internal-note-checkbox"
+ <form class="common-note-form gfm-form js-main-target-form gl-flex-grow-1 new-note">
+ <comment-field-layout
+ :with-alert-container="isWorkItemConfidential"
+ :noteable-data="getWorkItemData"
+ :noteable-type="workItemTypeKey"
>
- {{ $options.i18n.internal }}
- <gl-icon
- v-gl-tooltip:tooltipcontainer.bottom
- name="question-o"
- :size="16"
- :title="$options.i18n.internalVisibility"
- class="gl-text-blue-500"
+ <markdown-editor
+ :value="commentText"
+ :render-markdown-path="markdownPreviewPath"
+ :markdown-docs-path="$options.constantOptions.markdownDocsPath"
+ :autocomplete-data-sources="autocompleteDataSources"
+ :form-field-props="formFieldProps"
+ :add-spacing-classes="false"
+ data-testid="work-item-add-comment"
+ use-bottom-toolbar
+ supports-quick-actions
+ :autofocus="autofocus"
+ @input="setCommentText"
+ @keydown.meta.enter="$emit('submitForm', { commentText, isNoteInternal })"
+ @keydown.ctrl.enter="$emit('submitForm', { commentText, isNoteInternal })"
+ @keydown.esc.stop="cancelEditing"
+ />
+ </comment-field-layout>
+ <div class="note-form-actions">
+ <gl-form-checkbox
+ v-if="isNewDiscussion"
+ v-model="isNoteInternal"
+ class="gl-mb-2"
+ data-testid="internal-note-checkbox"
+ >
+ {{ $options.i18n.internal }}
+ <gl-icon
+ v-gl-tooltip:tooltipcontainer.bottom
+ name="question-o"
+ :size="16"
+ :title="$options.i18n.internalVisibility"
+ class="gl-text-blue-500"
+ />
+ </gl-form-checkbox>
+ <gl-button
+ category="primary"
+ variant="confirm"
+ data-testid="confirm-button"
+ :disabled="!commentText.length"
+ :loading="isSubmitting"
+ @click="$emit('submitForm', { commentText, isNoteInternal })"
+ >{{ commentButtonTextComputed }}
+ </gl-button>
+ <work-item-state-toggle-button
+ v-if="isNewDiscussion"
+ class="gl-ml-3"
+ :work-item-id="workItemId"
+ :work-item-state="workItemState"
+ :work-item-type="workItemType"
+ can-update
+ @error="$emit('error', $event)"
/>
- </gl-form-checkbox>
- <gl-button
- category="primary"
- variant="confirm"
- data-testid="confirm-button"
- :disabled="!commentText.length"
- :loading="isSubmitting"
- @click="$emit('submitForm', { commentText, isNoteInternal })"
- >{{ commentButtonTextComputed }}
- </gl-button>
- <work-item-state-toggle-button
- v-if="isNewDiscussion"
- class="gl-ml-3"
- :work-item-id="workItemId"
- :work-item-state="workItemState"
- :work-item-type="workItemType"
- can-update
- @error="$emit('error', $event)"
- />
- <gl-button
- v-else
- data-testid="cancel-button"
- category="primary"
- class="gl-ml-3"
- :loading="updateInProgress"
- @click="cancelEditing"
- >{{ $options.i18n.cancelButtonText }}
- </gl-button>
+ <gl-button
+ v-else
+ data-testid="cancel-button"
+ category="primary"
+ class="gl-ml-3"
+ :loading="updateInProgress"
+ @click="cancelEditing"
+ >{{ $options.i18n.cancelButtonText }}
+ </gl-button>
+ </div>
</form>
</div>
</div>
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue b/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
index f030363664f..fd8842aa01a 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
@@ -65,6 +65,11 @@ export default {
required: false,
default: false,
},
+ isWorkItemConfidential: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -235,6 +240,7 @@ export default {
:autocomplete-data-sources="autocompleteDataSources"
:markdown-preview-path="markdownPreviewPath"
:is-internal-thread="note.internal"
+ :is-work-item-confidential="isWorkItemConfidential"
@startReplying="showReplyForm"
@cancelEditing="hideReplyForm"
@replied="onReplied"
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note.vue b/app/assets/javascripts/work_items/components/notes/work_item_note.vue
index 92560f2da9e..b5e3ea68725 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_note.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_note.vue
@@ -163,6 +163,9 @@ export default {
projectName() {
return this.workItem?.project?.name;
},
+ isWorkItemConfidential() {
+ return this.workItem?.confidential;
+ },
},
apollo: {
workItem: {
@@ -314,6 +317,7 @@ export default {
:markdown-preview-path="markdownPreviewPath"
:work-item-id="workItemId"
:autofocus="isEditing"
+ :is-work-item-confidential="isWorkItemConfidential"
class="gl-pl-3 gl-mt-3"
@cancelEditing="isEditing = false"
@submitForm="updateNote"
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_notes_activity_header.vue b/app/assets/javascripts/work_items/components/notes/work_item_notes_activity_header.vue
index 0c1419e983f..1578c78ac4f 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_notes_activity_header.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_notes_activity_header.vue
@@ -64,7 +64,7 @@ export default {
:work-item-type="workItemType"
:loading="disableActivityFilterSort"
:sort-filter-prop="discussionFilter"
- :filter-options="$options.WORK_ITEM_ACTIVITY_FILTER_OPTIONS"
+ :items="$options.WORK_ITEM_ACTIVITY_FILTER_OPTIONS"
:storage-key="$options.WORK_ITEM_NOTES_FILTER_KEY"
:default-sort-filter-prop="$options.WORK_ITEM_NOTES_FILTER_ALL_NOTES"
tracking-action="work_item_notes_filter_changed"
@@ -77,7 +77,7 @@ export default {
:work-item-type="workItemType"
:loading="disableActivityFilterSort"
:sort-filter-prop="sortOrder"
- :filter-options="$options.WORK_ITEM_ACTIVITY_SORT_OPTIONS"
+ :items="$options.WORK_ITEM_ACTIVITY_SORT_OPTIONS"
:storage-key="$options.WORK_ITEM_NOTES_SORT_ORDER_KEY"
:default-sort-filter-prop="$options.ASC"
tracking-action="work_item_notes_sort_order_changed"
diff --git a/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue b/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
index 0a38dcb77f6..f50cfac90f7 100644
--- a/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
+++ b/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
@@ -43,15 +43,6 @@ export default {
type: Boolean,
required: true,
},
- parentWorkItemId: {
- type: String,
- required: true,
- },
- workItemType: {
- type: String,
- required: false,
- default: '',
- },
childPath: {
type: String,
required: true,
@@ -158,7 +149,7 @@ export default {
</span>
<gl-link
:href="childPath"
- class="gl-text-truncate gl-text-black-normal! gl-font-weight-semibold"
+ class="gl-text-truncate gl-font-weight-semibold"
data-testid="item-title"
@click="$emit('click', $event)"
@mouseover="$emit('mouseover')"
diff --git a/app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue b/app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue
index ddeac2b92ae..38d8d239a7e 100644
--- a/app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue
+++ b/app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue
@@ -42,7 +42,8 @@ export default {
assigneesContainerClass() {
if (this.assignees.length === 2) {
return 'fixed-width-avatars-2';
- } else if (this.assignees.length > 2) {
+ }
+ if (this.assignees.length > 2) {
return 'fixed-width-avatars-3';
}
return '';
diff --git a/app/assets/javascripts/work_items/components/shared/work_item_links_menu.vue b/app/assets/javascripts/work_items/components/shared/work_item_links_menu.vue
index 53e8eedf060..12b7bade31d 100644
--- a/app/assets/javascripts/work_items/components/shared/work_item_links_menu.vue
+++ b/app/assets/javascripts/work_items/components/shared/work_item_links_menu.vue
@@ -1,29 +1,28 @@
<script>
-import { GlIcon, GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
export default {
components: {
- GlDropdownItem,
- GlDropdown,
- GlIcon,
+ GlDisclosureDropdownItem,
+ GlDisclosureDropdown,
},
};
</script>
<template>
<div class="gl-ml-5">
- <gl-dropdown
+ <gl-disclosure-dropdown
category="tertiary"
toggle-class="btn-icon btn-sm"
- :right="true"
+ icon="ellipsis_v"
data-testid="work_items_links_menu"
+ :aria-label="__(`More actions`)"
+ text-sr-only
+ no-caret
>
- <template #button-content>
- <gl-icon name="ellipsis_v" :size="14" />
- </template>
- <gl-dropdown-item @click="$emit('removeChild')">
- {{ s__('WorkItem|Remove') }}
- </gl-dropdown-item>
- </gl-dropdown>
+ <gl-disclosure-dropdown-item @action="$emit('removeChild')">
+ <template #list-item>{{ s__('WorkItem|Remove') }}</template>
+ </gl-disclosure-dropdown-item>
+ </gl-disclosure-dropdown>
</div>
</template>
diff --git a/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue b/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue
new file mode 100644
index 00000000000..7b38e838033
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue
@@ -0,0 +1,145 @@
+<script>
+import { GlTokenSelector } from '@gitlab/ui';
+import { debounce } from 'lodash';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+
+import projectWorkItemsQuery from '../../graphql/project_work_items.query.graphql';
+import {
+ WORK_ITEMS_TYPE_MAP,
+ WORK_ITEM_TYPE_ENUM_TASK,
+ I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER,
+ sprintfWorkItem,
+} from '../../constants';
+
+export default {
+ components: {
+ GlTokenSelector,
+ },
+ props: {
+ value: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ fullPath: {
+ type: String,
+ required: true,
+ },
+ childrenType: {
+ type: String,
+ required: false,
+ default: WORK_ITEM_TYPE_ENUM_TASK,
+ },
+ childrenIds: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ parentWorkItemId: {
+ type: String,
+ required: true,
+ },
+ areWorkItemsToAddValid: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ apollo: {
+ availableWorkItems: {
+ query: projectWorkItemsQuery,
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ searchTerm: this.search?.title || this.search,
+ types: [this.childrenType],
+ in: this.search ? 'TITLE' : undefined,
+ };
+ },
+ skip() {
+ return !this.searchStarted;
+ },
+ update(data) {
+ return data.workspace.workItems.nodes.filter(
+ (wi) => !this.childrenIds.includes(wi.id) && this.parentWorkItemId !== wi.id,
+ );
+ },
+ },
+ },
+ data() {
+ return {
+ availableWorkItems: [],
+ search: '',
+ searchStarted: false,
+ };
+ },
+ computed: {
+ workItemsToAdd: {
+ get() {
+ return this.value;
+ },
+ set(workItemsToAdd) {
+ this.$emit('input', workItemsToAdd);
+ },
+ },
+ isLoading() {
+ return this.$apollo.queries.availableWorkItems.loading;
+ },
+ addInputPlaceholder() {
+ return sprintfWorkItem(I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER, this.childrenTypeName);
+ },
+ childrenTypeName() {
+ return WORK_ITEMS_TYPE_MAP[this.childrenType]?.name;
+ },
+ tokenSelectorContainerClass() {
+ return !this.areWorkItemsToAddValid ? 'gl-inset-border-1-red-500!' : '';
+ },
+ },
+ created() {
+ this.debouncedSearchKeyUpdate = debounce(this.setSearchKey, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
+ },
+ methods: {
+ getIdFromGraphQLId,
+ setSearchKey(value) {
+ this.search = value;
+ },
+ handleFocus() {
+ this.searchStarted = true;
+ },
+ handleMouseOver() {
+ this.timeout = setTimeout(() => {
+ this.searchStarted = true;
+ }, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
+ },
+ handleMouseOut() {
+ clearTimeout(this.timeout);
+ },
+ },
+};
+</script>
+<template>
+ <gl-token-selector
+ v-model="workItemsToAdd"
+ :dropdown-items="availableWorkItems"
+ :loading="isLoading"
+ :placeholder="addInputPlaceholder"
+ menu-class="gl-dropdown-menu-wide dropdown-reduced-height gl-min-h-7!"
+ :container-class="tokenSelectorContainerClass"
+ data-testid="work-item-token-select-input"
+ @text-input="debouncedSearchKeyUpdate"
+ @focus="handleFocus"
+ @mouseover.native="handleMouseOver"
+ @mouseout.native="handleMouseOut"
+ >
+ <template #token-content="{ token }">
+ {{ token.title }}
+ </template>
+ <template #dropdown-item-content="{ dropdownItem }">
+ <div class="gl-display-flex">
+ <div class="gl-text-secondary gl-mr-4">{{ getIdFromGraphQLId(dropdownItem.id) }}</div>
+ <div class="gl-text-truncate">{{ dropdownItem.title }}</div>
+ </div>
+ </template>
+ </gl-token-selector>
+</template>
diff --git a/app/assets/javascripts/work_items/components/widget_wrapper.vue b/app/assets/javascripts/work_items/components/widget_wrapper.vue
index f343f787358..27de858fe4e 100644
--- a/app/assets/javascripts/work_items/components/widget_wrapper.vue
+++ b/app/assets/javascripts/work_items/components/widget_wrapper.vue
@@ -14,6 +14,11 @@ export default {
required: false,
default: '',
},
+ widgetName: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
return {
@@ -30,6 +35,12 @@ export default {
isOpenString() {
return this.isOpen ? 'true' : 'false';
},
+ anchorLink() {
+ return `#${this.widgetName}`;
+ },
+ anchorLinkId() {
+ return `user-content-${this.widgetName}-links`;
+ },
},
methods: {
hide() {
@@ -46,14 +57,14 @@ export default {
</script>
<template>
- <div id="tasks" class="gl-new-card" :aria-expanded="isOpenString">
+ <div :id="widgetName" class="gl-new-card" :aria-expanded="isOpenString">
<div class="gl-new-card-header">
<div class="gl-new-card-title-wrapper">
<h3 class="gl-new-card-title">
<gl-link
- id="user-content-tasks-links"
- class="anchor position-absolute gl-text-decoration-none"
- href="#tasks"
+ :id="anchorLinkId"
+ class="gl-text-decoration-none"
+ :href="anchorLink"
aria-hidden="true"
/>
<slot name="header"></slot>
diff --git a/app/assets/javascripts/work_items/components/work_item_actions.vue b/app/assets/javascripts/work_items/components/work_item_actions.vue
index e8fe64c932b..18aa4d55086 100644
--- a/app/assets/javascripts/work_items/components/work_item_actions.vue
+++ b/app/assets/javascripts/work_items/components/work_item_actions.vue
@@ -1,8 +1,7 @@
<script>
import {
- GlDropdown,
- GlDropdownItem,
- GlDropdownForm,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
GlDropdownDivider,
GlModal,
GlModalDirective,
@@ -53,9 +52,8 @@ export default {
emailAddressCopied: __('Email address copied'),
},
components: {
- GlDropdown,
- GlDropdownItem,
- GlDropdownForm,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
GlDropdownDivider,
GlModal,
GlToggle,
@@ -180,13 +178,16 @@ export default {
navigator.clipboard.writeText(text);
}
toast(message);
+ this.closeDropdown();
},
handleToggleWorkItemConfidentiality() {
this.track('click_toggle_work_item_confidentiality');
this.$emit('toggleWorkItemConfidentiality', !this.isConfidential);
+ this.closeDropdown();
},
handleDelete() {
this.$refs.modal.show();
+ this.closeDropdown();
},
handleDeleteWorkItem() {
this.track('click_delete_work_item');
@@ -275,6 +276,9 @@ export default {
throwConvertError() {
this.$emit('error', this.i18n.convertError);
},
+ closeDropdown() {
+ this.$refs.workItemsMoreActions.close();
+ },
async promoteToObjective() {
try {
const {
@@ -300,6 +304,8 @@ export default {
} catch (error) {
this.throwConvertError();
Sentry.captureException(error);
+ } finally {
+ this.closeDropdown();
}
},
},
@@ -308,77 +314,87 @@ export default {
<template>
<div>
- <gl-dropdown
+ <gl-disclosure-dropdown
+ ref="workItemsMoreActions"
icon="ellipsis_v"
data-testid="work-item-actions-dropdown"
text-sr-only
:text="__('More actions')"
category="tertiary"
+ :auto-close="false"
no-caret
right
>
<template v-if="$options.isLoggedIn">
- <gl-dropdown-form
- class="work-item-notifications-form"
+ <gl-disclosure-dropdown-item
+ class="gl-display-flex gl-justify-content-end gl-w-full"
:data-testid="$options.notificationsToggleFormTestId"
>
- <div class="gl-px-5 gl-pb-2 gl-pt-1">
+ <template #list-item>
<gl-toggle
:value="subscribedToNotifications"
:label="$options.i18n.notifications"
:data-testid="$options.notificationsToggleTestId"
+ class="work-item-notification-toggle"
label-position="left"
label-id="notifications-toggle"
@change="toggleNotifications($event)"
/>
- </div>
- </gl-dropdown-form>
+ </template>
+ </gl-disclosure-dropdown-item>
<gl-dropdown-divider />
</template>
- <gl-dropdown-item
+
+ <gl-disclosure-dropdown-item
v-if="canPromoteToObjective"
:data-testid="$options.promoteActionTestId"
- @click="promoteToObjective"
+ @action="promoteToObjective"
>
- {{ __('Promote to objective') }}
- </gl-dropdown-item>
+ <template #list-item>{{ __('Promote to objective') }}</template>
+ </gl-disclosure-dropdown-item>
<template v-if="canUpdate && !isParentConfidential">
- <gl-dropdown-item
+ <gl-disclosure-dropdown-item
:data-testid="$options.confidentialityTestId"
- @click="handleToggleWorkItemConfidentiality"
- >{{
+ @action="handleToggleWorkItemConfidentiality"
+ ><template #list-item>{{
isConfidential
? $options.i18n.disableTaskConfidentiality
: $options.i18n.enableTaskConfidentiality
- }}</gl-dropdown-item
+ }}</template></gl-disclosure-dropdown-item
>
</template>
- <gl-dropdown-item
+ <gl-disclosure-dropdown-item
ref="workItemReference"
:data-testid="$options.copyReferenceTestId"
:data-clipboard-text="workItemReference"
- @click="copyToClipboard(workItemReference, $options.i18n.referenceCopied)"
- >{{ $options.i18n.copyReference }}</gl-dropdown-item
+ @action="copyToClipboard(workItemReference, $options.i18n.referenceCopied)"
+ ><template #list-item>{{
+ $options.i18n.copyReference
+ }}</template></gl-disclosure-dropdown-item
>
<template v-if="$options.isLoggedIn && workItemCreateNoteEmail">
- <gl-dropdown-item
+ <gl-disclosure-dropdown-item
ref="workItemCreateNoteEmail"
:data-testid="$options.copyCreateNoteEmailTestId"
:data-clipboard-text="workItemCreateNoteEmail"
- @click="copyToClipboard(workItemCreateNoteEmail, $options.i18n.emailAddressCopied)"
- >{{ i18n.copyCreateNoteEmail }}</gl-dropdown-item
+ @action="copyToClipboard(workItemCreateNoteEmail, $options.i18n.emailAddressCopied)"
+ ><template #list-item>{{
+ i18n.copyCreateNoteEmail
+ }}</template></gl-disclosure-dropdown-item
>
- <gl-dropdown-divider v-if="canDelete" />
</template>
- <gl-dropdown-item
+ <gl-dropdown-divider v-if="canDelete" />
+ <gl-disclosure-dropdown-item
v-if="canDelete"
:data-testid="$options.deleteActionTestId"
variant="danger"
- @click="handleDelete"
+ @action="handleDelete"
>
- {{ i18n.deleteWorkItem }}
- </gl-dropdown-item>
- </gl-dropdown>
+ <template #list-item
+ ><span class="text-danger">{{ i18n.deleteWorkItem }}</span></template
+ >
+ </gl-disclosure-dropdown-item>
+ </gl-disclosure-dropdown>
<gl-modal
ref="modal"
modal-id="work-item-confirm-delete"
diff --git a/app/assets/javascripts/work_items/components/work_item_assignees.vue b/app/assets/javascripts/work_items/components/work_item_assignees.vue
index 4b4aa7f96ca..f9527884adc 100644
--- a/app/assets/javascripts/work_items/components/work_item_assignees.vue
+++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue
@@ -388,7 +388,7 @@ export default {
:display-text="__('Invite members')"
trigger-element="side-nav"
icon="plus"
- trigger-source="work-item-assignees-dropdown"
+ trigger-source="work_item_assignees_dropdown"
classes="gl-display-block gl-text-body! gl-hover-text-decoration-none gl-pb-2"
/>
</gl-dropdown-item>
diff --git a/app/assets/javascripts/work_items/components/work_item_created_updated.vue b/app/assets/javascripts/work_items/components/work_item_created_updated.vue
index f93ea4a0753..14e55134048 100644
--- a/app/assets/javascripts/work_items/components/work_item_created_updated.vue
+++ b/app/assets/javascripts/work_items/components/work_item_created_updated.vue
@@ -84,13 +84,13 @@ export default {
<gl-loading-icon v-if="updateInProgress" :inline="true" class="gl-mr-3" />
<confidentiality-badge
v-if="isWorkItemConfidential"
- class="gl-vertical-align-middle gl-display-inline-flex!"
- data-testid="confidential"
- :workspace-type="$options.WORKSPACE_PROJECT"
+ class="gl-vertical-align-middle gl-display-inline-flex! gl-mr-2"
:issuable-type="workItemType"
+ :workspace-type="$options.WORKSPACE_PROJECT"
+ hide-text-in-small-screens
/>
<work-item-type-icon
- class="gl-vertical-align-middle gl-mr-0!"
+ class="gl-vertical-align-middle"
:work-item-icon-name="workItemIconName"
:work-item-type="workItemType"
show-text
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index d826ef9cbe7..edecd7addcc 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -31,6 +31,7 @@ import {
WORK_ITEM_TYPE_VALUE_ISSUE,
WORK_ITEM_TYPE_VALUE_OBJECTIVE,
WIDGET_TYPE_NOTES,
+ WIDGET_TYPE_LINKED_ITEMS,
} from '../constants';
import workItemUpdatedSubscription from '../graphql/work_item_updated.subscription.graphql';
@@ -50,6 +51,7 @@ import WorkItemNotes from './work_item_notes.vue';
import WorkItemDetailModal from './work_item_detail_modal.vue';
import WorkItemAwardEmoji from './work_item_award_emoji.vue';
import WorkItemStateToggleButton from './work_item_state_toggle_button.vue';
+import WorkItemRelationships from './work_item_relationships/work_item_relationships.vue';
export default {
i18n,
@@ -79,6 +81,7 @@ export default {
AbuseCategorySelector,
GlIntersectionObserver,
ConfidentialityBadge,
+ WorkItemRelationships,
},
mixins: [glFeatureFlagMixin()],
inject: ['fullPath', 'reportAbusePath'],
@@ -259,6 +262,15 @@ export default {
showIntersectionObserver() {
return !this.isModal && this.workItemsMvc2Enabled;
},
+ hasLinkedWorkItems() {
+ return this.glFeatures.linkedWorkItems;
+ },
+ workItemLinkedItems() {
+ return this.isWidgetPresent(WIDGET_TYPE_LINKED_ITEMS);
+ },
+ showWorkItemLinkedItems() {
+ return this.hasLinkedWorkItems && this.workItemLinkedItems;
+ },
},
mounted() {
if (this.modalWorkItemIid) {
@@ -515,9 +527,9 @@ export default {
<gl-loading-icon v-if="updateInProgress" class="gl-mr-3" />
<confidentiality-badge
v-if="workItem.confidential"
- data-testid="confidential"
- :workspace-type="$options.WORKSPACE_PROJECT"
+ class="gl-mr-3"
:issuable-type="workItemType"
+ :workspace-type="$options.WORKSPACE_PROJECT"
/>
<work-item-todos
v-if="showWorkItemCurrentUserTodos"
@@ -591,6 +603,12 @@ export default {
@show-modal="openInModal"
@addChild="$emit('addChild')"
/>
+ <work-item-relationships
+ v-if="showWorkItemLinkedItems"
+ :work-item-iid="workItemIid"
+ :work-item-full-path="workItem.project.fullPath"
+ @showModal="openInModal"
+ />
<work-item-notes
v-if="workItemNotes"
:work-item-id="workItem.id"
@@ -600,6 +618,7 @@ export default {
:assignees="workItemAssignees && workItemAssignees.assignees.nodes"
:can-set-work-item-metadata="canAssignUnassignUser"
:report-abuse-path="reportAbusePath"
+ :is-work-item-confidential="workItem.confidential"
class="gl-pt-5"
@error="updateError = $event"
@has-notes="updateHasNotes"
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_children_wrapper.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_children_wrapper.vue
index bf427feaa35..9d9414b5399 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_children_wrapper.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_children_wrapper.vue
@@ -56,14 +56,14 @@ export default {
return isLoggedIn() && this.canUpdate;
},
treeRootWrapper() {
- return this.canReorder ? Draggable : 'div';
+ return this.canReorder ? Draggable : 'ul';
},
treeRootOptions() {
const options = {
...defaultSortableOptions,
fallbackOnBody: false,
group: 'sortable-container',
- tag: 'div',
+ tag: 'ul',
'ghost-class': 'tree-item-drag-active',
'data-parent-id': this.workItemId,
value: this.children,
@@ -248,6 +248,7 @@ export default {
<component
:is="treeRootWrapper"
v-bind="treeRootOptions"
+ class="content-list"
:class="{ 'gl-cursor-grab sortable-container': canReorder }"
@end="handleDragOnEnd"
>
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue
index a9b0c2b98bf..679287338c8 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue
@@ -13,6 +13,7 @@ import {
WIDGET_TYPE_HIERARCHY,
WORK_ITEM_NAME_TO_ICON_MAP,
} from '../../constants';
+import { workItemPath } from '../../utils';
import getWorkItemTreeQuery from '../../graphql/work_item_tree.query.graphql';
import WorkItemLinkChildContents from '../shared/work_item_link_child_contents.vue';
import WorkItemTreeChildren from './work_item_tree_children.vue';
@@ -90,7 +91,7 @@ export default {
return this.isItemOpen ? __('Created') : __('Closed');
},
childPath() {
- return `${gon?.relative_url_root || ''}/${this.fullPath}/-/work_items/${this.childItem.iid}`;
+ return workItemPath(this.fullPath, this.childItem.iid);
},
chevronType() {
return this.isExpanded ? 'chevron-down' : 'chevron-right';
@@ -212,7 +213,7 @@ export default {
</script>
<template>
- <div class="tree-item">
+ <li class="tree-item">
<div
class="gl-display-flex gl-align-items-flex-start"
:class="{ 'gl-ml-6': canHaveChildren && !hasChildren && hasIndirectChildren }"
@@ -249,5 +250,5 @@ export default {
@removeChild="removeChild"
@click="$emit('click', $event)"
/>
- </div>
+ </li>
</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
index a0ff693e156..eb836007e75 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
@@ -103,6 +103,7 @@ export default {
isReportDrawerOpen: false,
reportedUserId: 0,
reportedUrl: '',
+ widgetName: 'tasks',
};
},
computed: {
@@ -166,7 +167,6 @@ export default {
this.updateWorkItemIdUrlQuery(child);
},
async closeModal() {
- this.activeChild = {};
this.updateWorkItemIdUrlQuery();
},
handleWorkItemDeleted(child) {
@@ -206,6 +206,7 @@ export default {
<widget-wrapper
ref="wrapper"
:error="error"
+ :widget-name="widgetName"
data-testid="work-item-links"
@dismissAlert="error = undefined"
>
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue
index 4960189fb48..55440e1603c 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue
@@ -3,19 +3,15 @@ import {
GlAlert,
GlFormGroup,
GlForm,
- GlTokenSelector,
GlButton,
GlFormInput,
GlFormCheckbox,
GlTooltip,
} from '@gitlab/ui';
-import { debounce } from 'lodash';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { __, s__, sprintf } from '~/locale';
+import WorkItemTokenInput from '../shared/work_item_token_input.vue';
import { addHierarchyChild } from '../../graphql/cache_utils';
import projectWorkItemTypesQuery from '../../graphql/project_work_item_types.query.graphql';
-import projectWorkItemsQuery from '../../graphql/project_work_items.query.graphql';
import updateWorkItemMutation from '../../graphql/update_work_item.mutation.graphql';
import createWorkItemMutation from '../../graphql/create_work_item.mutation.graphql';
import {
@@ -23,7 +19,6 @@ import {
WORK_ITEMS_TYPE_MAP,
WORK_ITEM_TYPE_ENUM_TASK,
I18N_WORK_ITEM_CREATE_BUTTON_LABEL,
- I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER,
I18N_WORK_ITEM_ADD_BUTTON_LABEL,
I18N_WORK_ITEM_ADD_MULTIPLE_BUTTON_LABEL,
I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL,
@@ -35,12 +30,12 @@ export default {
components: {
GlAlert,
GlForm,
- GlTokenSelector,
GlButton,
GlFormGroup,
GlFormInput,
GlFormCheckbox,
GlTooltip,
+ WorkItemTokenInput,
},
inject: ['fullPath', 'hasIterationsFeature'],
props: {
@@ -101,35 +96,14 @@ export default {
return data.workspace?.workItemTypes?.nodes;
},
},
- availableWorkItems: {
- query: projectWorkItemsQuery,
- variables() {
- return {
- fullPath: this.fullPath,
- searchTerm: this.search?.title || this.search,
- types: [this.childrenType],
- in: this.search ? 'TITLE' : undefined,
- };
- },
- skip() {
- return !this.searchStarted;
- },
- update(data) {
- return data.workspace.workItems.nodes.filter(
- (wi) => !this.childrenIds.includes(wi.id) && this.issuableGid !== wi.id,
- );
- },
- },
},
data() {
return {
workItemTypes: [],
- availableWorkItems: [],
- search: '',
- searchStarted: false,
+ workItemsToAdd: [],
error: null,
+ search: '',
childToCreateTitle: null,
- workItemsToAdd: [],
confidential: this.parentConfidential,
};
},
@@ -177,7 +151,8 @@ export default {
addOrCreateButtonLabel() {
if (this.isCreateForm) {
return sprintfWorkItem(I18N_WORK_ITEM_CREATE_BUTTON_LABEL, this.childrenTypeName);
- } else if (this.workItemsToAdd.length > 1) {
+ }
+ if (this.workItemsToAdd.length > 1) {
return sprintfWorkItem(I18N_WORK_ITEM_ADD_MULTIPLE_BUTTON_LABEL, this.childrenTypeName);
}
return sprintfWorkItem(I18N_WORK_ITEM_ADD_BUTTON_LABEL, this.childrenTypeName);
@@ -216,15 +191,6 @@ export default {
}
return this.workItemsToAdd.length === 0 || !this.areWorkItemsToAddValid;
},
- isLoading() {
- return this.$apollo.queries.availableWorkItems.loading;
- },
- addInputPlaceholder() {
- return sprintfWorkItem(I18N_WORK_ITEM_SEARCH_INPUT_PLACEHOLDER, this.childrenTypeName);
- },
- tokenSelectorContainerClass() {
- return !this.areWorkItemsToAddValid ? 'gl-inset-border-1-red-500!' : '';
- },
invalidWorkItemsToAdd() {
return this.parentConfidential
? this.workItemsToAdd.filter((workItem) => !workItem.confidential)
@@ -249,11 +215,7 @@ export default {
);
},
},
- created() {
- this.debouncedSearchKeyUpdate = debounce(this.setSearchKey, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
- },
methods: {
- getIdFromGraphQLId,
getConfidentialityTooltipTarget() {
// We want tooltip to be anchored to `input` within checkbox component
// but `$el.querySelector('input')` doesn't work. 🤷â€â™‚ï¸
@@ -317,20 +279,6 @@ export default {
this.childToCreateTitle = null;
});
},
- setSearchKey(value) {
- this.search = value;
- },
- handleFocus() {
- this.searchStarted = true;
- },
- handleMouseOver() {
- this.timeout = setTimeout(() => {
- this.searchStarted = true;
- }, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
- },
- handleMouseOut() {
- clearTimeout(this.timeout);
- },
},
i18n: {
inputLabel: __('Title'),
@@ -385,30 +333,16 @@ export default {
>{{ confidentialityCheckboxTooltip }}</gl-tooltip
>
<div class="gl-mb-4">
- <gl-token-selector
+ <work-item-token-input
v-if="!isCreateForm"
v-model="workItemsToAdd"
- :dropdown-items="availableWorkItems"
- :loading="isLoading"
- :placeholder="addInputPlaceholder"
- menu-class="gl-dropdown-menu-wide dropdown-reduced-height gl-min-h-7!"
- :container-class="tokenSelectorContainerClass"
- data-testid="work-item-token-select-input"
- @text-input="debouncedSearchKeyUpdate"
- @focus="handleFocus"
- @mouseover.native="handleMouseOver"
- @mouseout.native="handleMouseOut"
- >
- <template #token-content="{ token }">
- {{ token.title }}
- </template>
- <template #dropdown-item-content="{ dropdownItem }">
- <div class="gl-display-flex">
- <div class="gl-text-secondary gl-mr-4">{{ getIdFromGraphQLId(dropdownItem.id) }}</div>
- <div class="gl-text-truncate">{{ dropdownItem.title }}</div>
- </div>
- </template>
- </gl-token-selector>
+ :is-create-form="isCreateForm"
+ :parent-work-item-id="issuableGid"
+ :children-type="childrenType"
+ :children-ids="childrenIds"
+ :are-work-items-to-add-valid="areWorkItemsToAddValid"
+ :full-path="fullPath"
+ />
<div
v-if="showWorkItemsToAddInvalidMessage"
class="gl-text-red-500"
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
index 246eac82c78..bc3f5201fb8 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue
@@ -64,6 +64,7 @@ export default {
isShownAddForm: false,
formType: null,
childType: null,
+ widgetName: 'tasks',
};
},
computed: {
@@ -101,6 +102,7 @@ export default {
<template>
<widget-wrapper
ref="wrapper"
+ :widget-name="widgetName"
:error="error"
data-testid="work-item-tree"
@dismissAlert="error = undefined"
diff --git a/app/assets/javascripts/work_items/components/work_item_notes.vue b/app/assets/javascripts/work_items/components/work_item_notes.vue
index 8fc460294e6..256f8ed53d1 100644
--- a/app/assets/javascripts/work_items/components/work_item_notes.vue
+++ b/app/assets/javascripts/work_items/components/work_item_notes.vue
@@ -79,6 +79,11 @@ export default {
type: String,
required: true,
},
+ isWorkItemConfidential: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -124,6 +129,7 @@ export default {
isNewDiscussion: true,
markdownPreviewPath: this.markdownPreviewPath,
autocompleteDataSources: this.autocompleteDataSources,
+ isWorkItemConfidential: this.isWorkItemConfidential,
};
},
notesArray() {
@@ -366,6 +372,7 @@ export default {
:markdown-preview-path="markdownPreviewPath"
:assignees="assignees"
:can-set-work-item-metadata="canSetWorkItemMetadata"
+ :is-work-item-confidential="isWorkItemConfidential"
@deleteNote="showDeleteNoteModal($event, discussion)"
@reportAbuse="reportAbuse(true, $event)"
@error="$emit('error', $event)"
diff --git a/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationship_list.vue b/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationship_list.vue
new file mode 100644
index 00000000000..cbe830f9565
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationship_list.vue
@@ -0,0 +1,61 @@
+<script>
+import WorkItemLinkChildContents from '../shared/work_item_link_child_contents.vue';
+import { workItemPath } from '../../utils';
+
+export default {
+ components: {
+ WorkItemLinkChildContents,
+ },
+ props: {
+ linkedItems: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ heading: {
+ type: String,
+ required: true,
+ },
+ canUpdate: {
+ type: Boolean,
+ required: true,
+ },
+ workItemFullPath: {
+ type: String,
+ required: true,
+ },
+ },
+ methods: {
+ linkedItemPath(fullPath, id) {
+ return workItemPath(fullPath, id);
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <h4
+ v-if="heading"
+ data-testid="work-items-list-heading"
+ class="gl-font-sm gl-font-weight-semibold gl-text-gray-700 gl-mx-2 gl-mt-3 gl-mb-2"
+ >
+ {{ heading }}
+ </h4>
+ <div class="work-items-list-body">
+ <ul ref="list" class="work-items-list content-list">
+ <li
+ v-for="linkedItem in linkedItems"
+ :key="linkedItem.workItem.id"
+ class="gl-pt-0! gl-pb-0! gl-border-b-0!"
+ >
+ <work-item-link-child-contents
+ :child-item="linkedItem.workItem"
+ :can-update="canUpdate"
+ :child-path="linkedItemPath(workItemFullPath, linkedItem.workItem.iid)"
+ @click="$emit('showModal', { event: $event, child: linkedItem.workItem })"
+ />
+ </li>
+ </ul>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationships.vue b/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationships.vue
new file mode 100644
index 00000000000..4f6879e9605
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationships.vue
@@ -0,0 +1,185 @@
+<script>
+import { GlLoadingIcon, GlIcon, GlButton } from '@gitlab/ui';
+
+import { s__ } from '~/locale';
+
+import workItemByIidQuery from '../../graphql/work_item_by_iid.query.graphql';
+import { WIDGET_TYPE_LINKED_ITEMS, LINKED_CATEGORIES_MAP } from '../../constants';
+
+import WidgetWrapper from '../widget_wrapper.vue';
+import WorkItemRelationshipList from './work_item_relationship_list.vue';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ GlIcon,
+ GlButton,
+ WidgetWrapper,
+ WorkItemRelationshipList,
+ },
+ props: {
+ workItemIid: {
+ type: String,
+ required: true,
+ },
+ workItemFullPath: {
+ type: String,
+ required: true,
+ },
+ },
+ apollo: {
+ workItem: {
+ query: workItemByIidQuery,
+ variables() {
+ return {
+ fullPath: this.workItemFullPath,
+ iid: this.workItemIid,
+ };
+ },
+ update(data) {
+ return data.workspace.workItems.nodes[0] ?? {};
+ },
+ context: {
+ isSingleRequest: true,
+ },
+ skip() {
+ return !this.workItemIid;
+ },
+ error(e) {
+ this.error = e.message || this.$options.i18n.fetchError;
+ },
+ async result() {
+ // When work items are switched in a modal, the data props are not getting reset.
+ // Thus, duplicating the work items in the list.
+ // Here, the existing list are cleared before the new items are pushed.
+ this.linksRelatesTo = [];
+ this.linksIsBlockedBy = [];
+ this.linksBlocks = [];
+
+ this.linkedWorkItems.forEach((item) => {
+ if (item.linkType === LINKED_CATEGORIES_MAP.RELATES_TO) {
+ this.linksRelatesTo.push(item);
+ } else if (item.linkType === LINKED_CATEGORIES_MAP.IS_BLOCKED_BY) {
+ this.linksIsBlockedBy.push(item);
+ } else if (item.linkType === LINKED_CATEGORIES_MAP.BLOCKS) {
+ this.linksBlocks.push(item);
+ }
+ });
+ },
+ },
+ },
+ data() {
+ return {
+ error: '',
+ linksRelatesTo: [],
+ linksIsBlockedBy: [],
+ linksBlocks: [],
+ widgetName: 'linkeditems',
+ };
+ },
+ computed: {
+ canUpdate() {
+ // This will be false untill we implement remove item mutation
+ return false;
+ },
+ isLoading() {
+ return this.$apollo.queries.workItem.loading;
+ },
+ linkedWorkItemsWidget() {
+ return this.workItem?.widgets?.find((widget) => widget.type === WIDGET_TYPE_LINKED_ITEMS);
+ },
+ linkedWorkItems() {
+ return this.linkedWorkItemsWidget?.linkedItems?.nodes || [];
+ },
+ linkedWorkItemsCount() {
+ return this.linkedWorkItems.length;
+ },
+ isEmptyRelatedWorkItems() {
+ return !this.error && this.linkedWorkItems.length === 0;
+ },
+ },
+ i18n: {
+ title: s__('WorkItem|Linked Items'),
+ fetchError: s__('WorkItem|Something went wrong when fetching tasks. Please refresh this page.'),
+ emptyStateMessage: s__(
+ "WorkItem|Link work items together to show that they're related or that one is blocking others.",
+ ),
+ addChildButtonLabel: s__('WorkItem|Add'),
+ relatedToTitle: s__('WorkItem|Related to'),
+ blockingTitle: s__('WorkItem|Blocking'),
+ blockedByTitle: s__('WorkItem|Blocked by'),
+ addLinkedWorkItemButtonLabel: s__('WorkItem|Add'),
+ },
+};
+</script>
+<template>
+ <widget-wrapper
+ :error="error"
+ class="work-item-relationships"
+ :widget-name="widgetName"
+ @dismissAlert="error = undefined"
+ >
+ <template #header>
+ <div class="gl-new-card-title-wrapper">
+ <h3 class="gl-new-card-title">
+ {{ $options.i18n.title }}
+ </h3>
+ <div v-if="linkedWorkItemsCount" class="gl-new-card-count">
+ <gl-icon name="link" class="gl-mr-2" />
+ <span data-testid="linked-items-count">{{ linkedWorkItemsCount }}</span>
+ </div>
+ </div>
+ </template>
+ <template #header-right>
+ <gl-button size="small" class="gl-ml-3">
+ <slot name="add-button-text">{{ $options.i18n.addLinkedWorkItemButtonLabel }}</slot>
+ </gl-button>
+ </template>
+ <template #body>
+ <div class="gl-new-card-content">
+ <gl-loading-icon v-if="isLoading" color="dark" class="gl-my-2" />
+ <template v-else>
+ <div v-if="isEmptyRelatedWorkItems" data-testid="links-empty">
+ <p class="gl-new-card-empty">
+ {{ $options.i18n.emptyStateMessage }}
+ </p>
+ </div>
+ <template v-else>
+ <work-item-relationship-list
+ v-if="linksBlocks.length"
+ :class="{
+ 'gl-pb-3 gl-mb-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100':
+ linksIsBlockedBy.length,
+ }"
+ :linked-items="linksBlocks"
+ :heading="$options.i18n.blockingTitle"
+ :work-item-full-path="workItemFullPath"
+ :can-update="canUpdate"
+ @showModal="$emit('showModal', { event: $event.event, modalWorkItem: $event.child })"
+ />
+ <work-item-relationship-list
+ v-if="linksIsBlockedBy.length"
+ :class="{
+ 'gl-pb-3 gl-mb-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100':
+ linksRelatesTo.length,
+ }"
+ :linked-items="linksIsBlockedBy"
+ :heading="$options.i18n.blockedByTitle"
+ :work-item-full-path="workItemFullPath"
+ :can-update="canUpdate"
+ @showModal="$emit('showModal', { event: $event.event, modalWorkItem: $event.child })"
+ />
+ <work-item-relationship-list
+ v-if="linksRelatesTo.length"
+ :linked-items="linksRelatesTo"
+ :heading="$options.i18n.relatedToTitle"
+ :work-item-full-path="workItemFullPath"
+ :can-update="canUpdate"
+ @showModal="$emit('showModal', { event: $event.event, modalWorkItem: $event.child })"
+ />
+ </template>
+ </template>
+ </div>
+ </template>
+ </widget-wrapper>
+</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_state_badge.vue b/app/assets/javascripts/work_items/components/work_item_state_badge.vue
index 1d1bc7352b1..5c5b41b38e6 100644
--- a/app/assets/javascripts/work_items/components/work_item_state_badge.vue
+++ b/app/assets/javascripts/work_items/components/work_item_state_badge.vue
@@ -1,11 +1,12 @@
<script>
-import { GlBadge } from '@gitlab/ui';
+import { GlBadge, GlIcon } from '@gitlab/ui';
import { __ } from '~/locale';
import { STATE_OPEN } from '../constants';
export default {
components: {
GlBadge,
+ GlIcon,
},
props: {
workItemState: {
@@ -31,11 +32,8 @@ export default {
</script>
<template>
- <gl-badge
- :icon="workItemStateIcon"
- :variant="workItemStateVariant"
- class="gl-mr-2 gl-vertical-align-middle"
- >
- {{ stateText }}
+ <gl-badge :variant="workItemStateVariant" class="gl-mr-2 gl-vertical-align-middle">
+ <gl-icon :name="workItemStateIcon" :size="16" />
+ <span class="gl-display-none gl-sm-display-block gl-ml-2">{{ stateText }}</span>
</gl-badge>
</template>
diff --git a/app/assets/javascripts/work_items/components/work_item_type_icon.vue b/app/assets/javascripts/work_items/components/work_item_type_icon.vue
index f27ae5f4e6d..5426f3965b3 100644
--- a/app/assets/javascripts/work_items/components/work_item_type_icon.vue
+++ b/app/assets/javascripts/work_items/components/work_item_type_icon.vue
@@ -53,7 +53,7 @@ export default {
</script>
<template>
- <span class="gl-mr-2">
+ <span>
<gl-icon
v-gl-tooltip.hover="showTooltipOnHover"
:name="iconName"
diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js
index 57206550328..2b118247426 100644
--- a/app/assets/javascripts/work_items/constants.js
+++ b/app/assets/javascripts/work_items/constants.js
@@ -26,6 +26,7 @@ export const WIDGET_TYPE_MILESTONE = 'MILESTONE';
export const WIDGET_TYPE_ITERATION = 'ITERATION';
export const WIDGET_TYPE_NOTES = 'NOTES';
export const WIDGET_TYPE_HEALTH_STATUS = 'HEALTH_STATUS';
+export const WIDGET_TYPE_LINKED_ITEMS = 'LINKED_ITEMS';
export const WORK_ITEM_TYPE_ENUM_INCIDENT = 'INCIDENT';
export const WORK_ITEM_TYPE_ENUM_ISSUE = 'ISSUE';
@@ -35,6 +36,7 @@ export const WORK_ITEM_TYPE_ENUM_REQUIREMENTS = 'REQUIREMENTS';
export const WORK_ITEM_TYPE_ENUM_OBJECTIVE = 'OBJECTIVE';
export const WORK_ITEM_TYPE_ENUM_KEY_RESULT = 'KEY_RESULT';
+export const WORK_ITEM_TYPE_VALUE_EPIC = 'Epic';
export const WORK_ITEM_TYPE_VALUE_INCIDENT = 'Incident';
export const WORK_ITEM_TYPE_VALUE_ISSUE = 'Issue';
export const WORK_ITEM_TYPE_VALUE_TASK = 'Task';
@@ -57,6 +59,9 @@ export const i18n = {
export const I18N_WORK_ITEM_ERROR_FETCHING_LABELS = s__(
'WorkItem|Something went wrong when fetching labels. Please try again.',
);
+export const I18N_WORK_ITEM_ERROR_FETCHING_TYPES = s__(
+ 'WorkItem|Something went wrong when fetching work item types. Please try again',
+);
export const I18N_WORK_ITEM_ERROR_CREATING = s__(
'WorkItem|Something went wrong when creating %{workItemType}. Please try again.',
);
@@ -208,24 +213,22 @@ export const WORK_ITEM_NOTES_FILTER_KEY = 'filter_key_work_item';
export const WORK_ITEM_ACTIVITY_FILTER_OPTIONS = [
{
- key: WORK_ITEM_NOTES_FILTER_ALL_NOTES,
+ value: WORK_ITEM_NOTES_FILTER_ALL_NOTES,
text: s__('WorkItem|All activity'),
},
{
- key: WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS,
+ value: WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS,
text: s__('WorkItem|Comments only'),
- testid: 'comments-activity',
},
{
- key: WORK_ITEM_NOTES_FILTER_ONLY_HISTORY,
+ value: WORK_ITEM_NOTES_FILTER_ONLY_HISTORY,
text: s__('WorkItem|History only'),
- testid: 'history-activity',
},
];
export const WORK_ITEM_ACTIVITY_SORT_OPTIONS = [
- { key: DESC, text: __('Newest first'), testid: 'newest-first' },
- { key: ASC, text: __('Oldest first') },
+ { value: DESC, text: __('Newest first') },
+ { value: ASC, text: __('Oldest first') },
];
export const TEST_ID_CONFIDENTIALITY_TOGGLE_ACTION = 'confidentiality-toggle-action';
@@ -241,10 +244,6 @@ export const TODO_DONE_ICON = 'todo-done';
export const TODO_DONE_STATE = 'done';
export const TODO_PENDING_STATE = 'pending';
-export const CURRENT_USER_TODOS_TYPENAME = 'WorkItemWidgetCurrentUserTodos';
-
-export const EMOJI_ACTION_ADD = 'ADD';
-export const EMOJI_ACTION_REMOVE = 'REMOVE';
export const EMOJI_THUMBSUP = 'thumbsup';
export const EMOJI_THUMBSDOWN = 'thumbsdown';
@@ -257,3 +256,9 @@ export const WORK_ITEM_TO_ISSUE_MAP = {
[WIDGET_TYPE_HEALTH_STATUS]: 'healthStatus',
[WIDGET_TYPE_AWARD_EMOJI]: 'awardEmoji',
};
+
+export const LINKED_CATEGORIES_MAP = {
+ RELATES_TO: 'relates_to',
+ IS_BLOCKED_BY: 'is_blocked_by',
+ BLOCKS: 'blocks',
+};
diff --git a/app/assets/javascripts/work_items/graphql/group_work_item_types.query.graphql b/app/assets/javascripts/work_items/graphql/group_work_item_types.query.graphql
new file mode 100644
index 00000000000..30757f57234
--- /dev/null
+++ b/app/assets/javascripts/work_items/graphql/group_work_item_types.query.graphql
@@ -0,0 +1,11 @@
+query groupWorkItemTypes($fullPath: ID!) {
+ workspace: group(fullPath: $fullPath) {
+ id
+ workItemTypes {
+ nodes {
+ id
+ name
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql b/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
index 383d003e78c..ffc9fe2f7f7 100644
--- a/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
+++ b/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
@@ -100,4 +100,31 @@ fragment WorkItemWidgets on WorkItemWidget {
... on WorkItemWidgetAwardEmoji {
type
}
+
+ ... on WorkItemWidgetLinkedItems {
+ type
+ linkedItems {
+ nodes {
+ linkId
+ linkType
+ workItem {
+ id
+ iid
+ confidential
+ workItemType {
+ id
+ name
+ iconName
+ }
+ title
+ state
+ createdAt
+ closedAt
+ widgets {
+ ...WorkItemMetadataWidgets
+ }
+ }
+ }
+ }
+ }
}
diff --git a/app/assets/javascripts/work_items/list/components/work_items_list_app.vue b/app/assets/javascripts/work_items/list/components/work_items_list_app.vue
index fe7cb719bbb..a853018a931 100644
--- a/app/assets/javascripts/work_items/list/components/work_items_list_app.vue
+++ b/app/assets/javascripts/work_items/list/components/work_items_list_app.vue
@@ -1,5 +1,7 @@
<script>
import * as Sentry from '@sentry/browser';
+import IssueCardStatistics from 'ee_else_ce/issues/list/components/issue_card_statistics.vue';
+import IssueCardTimeInfo from 'ee_else_ce/issues/list/components/issue_card_time_info.vue';
import { STATUS_OPEN } from '~/issues/constants';
import { __, s__ } from '~/locale';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
@@ -8,12 +10,11 @@ import { STATE_CLOSED } from '../../constants';
import getWorkItemsQuery from '../queries/get_work_items.query.graphql';
export default {
- i18n: {
- searchPlaceholder: __('Search or filter results...'),
- },
issuableListTabs,
components: {
IssuableList,
+ IssueCardStatistics,
+ IssueCardTimeInfo,
},
inject: ['fullPath'],
data() {
@@ -57,17 +58,33 @@ export default {
:current-tab="state"
:error="error"
:issuables="workItems"
+ :issuables-loading="$apollo.queries.workItems.loading"
namespace="work-items"
recent-searches-storage-key="issues"
- :search-input-placeholder="$options.i18n.searchPlaceholder"
:search-tokens="searchTokens"
show-work-item-type-icon
:sort-options="sortOptions"
:tabs="$options.issuableListTabs"
@dismiss-alert="error = undefined"
>
+ <template #nav-actions>
+ <slot name="nav-actions"></slot>
+ </template>
+
+ <template #timeframe="{ issuable = {} }">
+ <issue-card-time-info :issue="issuable" />
+ </template>
+
<template #status="{ issuable }">
{{ getStatus(issuable) }}
</template>
+
+ <template #statistics="{ issuable = {} }">
+ <issue-card-statistics :issue="issuable" />
+ </template>
+
+ <template #list-body>
+ <slot name="list-body"></slot>
+ </template>
</issuable-list>
</template>
diff --git a/app/assets/javascripts/work_items/list/index.js b/app/assets/javascripts/work_items/list/index.js
index 5cd38600779..885cea2c1d6 100644
--- a/app/assets/javascripts/work_items/list/index.js
+++ b/app/assets/javascripts/work_items/list/index.js
@@ -1,7 +1,8 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
-import WorkItemsListApp from './components/work_items_list_app.vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import WorkItemsListApp from 'ee_else_ce/work_items/list/components/work_items_list_app.vue';
export const mountWorkItemsListApp = () => {
const el = document.querySelector('.js-work-items-list-root');
@@ -12,6 +13,13 @@ export const mountWorkItemsListApp = () => {
Vue.use(VueApollo);
+ const {
+ fullPath,
+ hasEpicsFeature,
+ hasIssuableHealthStatusFeature,
+ hasIssueWeightsFeature,
+ } = el.dataset;
+
return new Vue({
el,
name: 'WorkItemsListRoot',
@@ -19,7 +27,10 @@ export const mountWorkItemsListApp = () => {
defaultClient: createDefaultClient(),
}),
provide: {
- fullPath: el.dataset.fullPath,
+ fullPath,
+ hasEpicsFeature: parseBoolean(hasEpicsFeature),
+ hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature),
+ hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature),
},
render: (createComponent) => createComponent(WorkItemsListApp),
});
diff --git a/app/assets/javascripts/work_items/list/queries/base_work_item_widgets.fragment.graphql b/app/assets/javascripts/work_items/list/queries/base_work_item_widgets.fragment.graphql
new file mode 100644
index 00000000000..1198973d184
--- /dev/null
+++ b/app/assets/javascripts/work_items/list/queries/base_work_item_widgets.fragment.graphql
@@ -0,0 +1,38 @@
+#import "~/graphql_shared/fragments/user.fragment.graphql"
+
+fragment BaseWorkItemWidgets on WorkItemWidget {
+ ... on WorkItemWidgetAssignees {
+ type
+ assignees {
+ nodes {
+ ...User
+ }
+ }
+ }
+ ... on WorkItemWidgetLabels {
+ type
+ allowsScopedLabels
+ labels {
+ nodes {
+ id
+ color
+ description
+ title
+ }
+ }
+ }
+ ... on WorkItemWidgetMilestone {
+ type
+ milestone {
+ id
+ dueDate
+ startDate
+ title
+ webPath
+ }
+ }
+ ... on WorkItemWidgetStartAndDueDate {
+ type
+ dueDate
+ }
+}
diff --git a/app/assets/javascripts/work_items/list/queries/get_work_items.query.graphql b/app/assets/javascripts/work_items/list/queries/get_work_items.query.graphql
index 7ada2cf12dd..623527302f1 100644
--- a/app/assets/javascripts/work_items/list/queries/get_work_items.query.graphql
+++ b/app/assets/javascripts/work_items/list/queries/get_work_items.query.graphql
@@ -1,3 +1,5 @@
+#import "ee_else_ce/work_items/list/queries/work_item_widgets.fragment.graphql"
+
query getWorkItems($fullPath: ID!) {
group(fullPath: $fullPath) {
id
@@ -21,30 +23,7 @@ query getWorkItems($fullPath: ID!) {
updatedAt
webUrl
widgets {
- ... on WorkItemWidgetAssignees {
- assignees {
- nodes {
- id
- avatarUrl
- name
- username
- webUrl
- }
- }
- type
- }
- ... on WorkItemWidgetLabels {
- allowsScopedLabels
- labels {
- nodes {
- id
- color
- description
- title
- }
- }
- type
- }
+ ...WorkItemWidgets
}
workItemType {
id
diff --git a/app/assets/javascripts/work_items/list/queries/work_item_widgets.fragment.graphql b/app/assets/javascripts/work_items/list/queries/work_item_widgets.fragment.graphql
new file mode 100644
index 00000000000..6862df5d330
--- /dev/null
+++ b/app/assets/javascripts/work_items/list/queries/work_item_widgets.fragment.graphql
@@ -0,0 +1,5 @@
+#import "./base_work_item_widgets.fragment.graphql"
+
+fragment WorkItemWidgets on WorkItemWidget {
+ ...BaseWorkItemWidgets
+}
diff --git a/app/assets/javascripts/work_items/pages/create_work_item.vue b/app/assets/javascripts/work_items/pages/create_work_item.vue
index 49ec12db4e1..b5705b21b5a 100644
--- a/app/assets/javascripts/work_items/pages/create_work_item.vue
+++ b/app/assets/javascripts/work_items/pages/create_work_item.vue
@@ -3,7 +3,11 @@ import { GlButton, GlAlert, GlLoadingIcon, GlFormSelect } from '@gitlab/ui';
import { TYPENAME_PROJECT } from '~/graphql_shared/constants';
import { getPreferredLocales, s__ } from '~/locale';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
-import { sprintfWorkItem, I18N_WORK_ITEM_ERROR_CREATING } from '../constants';
+import {
+ I18N_WORK_ITEM_ERROR_CREATING,
+ I18N_WORK_ITEM_ERROR_FETCHING_TYPES,
+ sprintfWorkItem,
+} from '../constants';
import createWorkItemMutation from '../graphql/create_work_item.mutation.graphql';
import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query.graphql';
import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql';
@@ -11,9 +15,6 @@ import workItemByIidQuery from '../graphql/work_item_by_iid.query.graphql';
import ItemTitle from '../components/item_title.vue';
export default {
- fetchTypesErrorText: s__(
- 'WorkItem|Something went wrong when fetching work item types. Please try again',
- ),
components: {
GlButton,
GlAlert,
@@ -53,7 +54,7 @@ export default {
}));
},
error() {
- this.error = this.$options.fetchTypesErrorText;
+ this.error = I18N_WORK_ITEM_ERROR_FETCHING_TYPES;
},
},
},
diff --git a/app/assets/javascripts/work_items/utils.js b/app/assets/javascripts/work_items/utils.js
index 5a882977bc2..1443e4b509d 100644
--- a/app/assets/javascripts/work_items/utils.js
+++ b/app/assets/javascripts/work_items/utils.js
@@ -1,9 +1,26 @@
-import { WIDGET_TYPE_ASSIGNEES, WIDGET_TYPE_HIERARCHY, WIDGET_TYPE_LABELS } from './constants';
+import { joinPaths } from '~/lib/utils/url_utility';
+import {
+ WIDGET_TYPE_ASSIGNEES,
+ WIDGET_TYPE_HEALTH_STATUS,
+ WIDGET_TYPE_HIERARCHY,
+ WIDGET_TYPE_LABELS,
+ WIDGET_TYPE_MILESTONE,
+ WIDGET_TYPE_START_AND_DUE_DATE,
+ WIDGET_TYPE_WEIGHT,
+} from './constants';
export const isAssigneesWidget = (widget) => widget.type === WIDGET_TYPE_ASSIGNEES;
+export const isHealthStatusWidget = (widget) => widget.type === WIDGET_TYPE_HEALTH_STATUS;
+
export const isLabelsWidget = (widget) => widget.type === WIDGET_TYPE_LABELS;
+export const isMilestoneWidget = (widget) => widget.type === WIDGET_TYPE_MILESTONE;
+
+export const isStartAndDueDateWidget = (widget) => widget.type === WIDGET_TYPE_START_AND_DUE_DATE;
+
+export const isWeightWidget = (widget) => widget.type === WIDGET_TYPE_WEIGHT;
+
export const findHierarchyWidgets = (widgets) =>
widgets?.find((widget) => widget.type === WIDGET_TYPE_HIERARCHY);
@@ -26,3 +43,7 @@ export const markdownPreviewPath = (fullPath, iid) =>
`${
gon.relative_url_root || ''
}/${fullPath}/preview_markdown?target_type=WorkItem&target_id=${iid}`;
+
+export const workItemPath = (fullPath, workItemIid) => {
+ return joinPaths(gon?.relative_url_root || '/', fullPath, '-', 'work_items', workItemIid);
+};
diff --git a/app/assets/javascripts/work_items_hierarchy/hierarchy_util.js b/app/assets/javascripts/work_items_hierarchy/hierarchy_util.js
index 61d93acdb91..57f4783955c 100644
--- a/app/assets/javascripts/work_items_hierarchy/hierarchy_util.js
+++ b/app/assets/javascripts/work_items_hierarchy/hierarchy_util.js
@@ -3,7 +3,8 @@ import { LICENSE_PLAN } from './constants';
export function inferLicensePlan({ hasSubEpics, hasEpics }) {
if (hasSubEpics) {
return LICENSE_PLAN.ULTIMATE;
- } else if (hasEpics) {
+ }
+ if (hasEpics) {
return LICENSE_PLAN.PREMIUM;
}
return LICENSE_PLAN.FREE;
diff --git a/app/assets/stylesheets/disable_animations.scss b/app/assets/stylesheets/disable_animations.scss
index 1e63cdcfa39..7472340896f 100644
--- a/app/assets/stylesheets/disable_animations.scss
+++ b/app/assets/stylesheets/disable_animations.scss
@@ -1,4 +1,7 @@
-* {
+*:not(
+ /* Keep transition enabled where it would otherwise break specs */
+ .always-animate
+) {
/* stylelint-disable property-no-vendor-prefix */
-o-transition: none !important;
-moz-transition: none !important;
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 7b8d9281148..514247d2913 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -2,6 +2,7 @@
:root {
--performance-bar-height: 0px;
--system-header-height: 0px;
+ --header-height: 0px;
--top-bar-height: 0px;
--system-footer-height: 0px;
--mr-review-bar-height: 0px;
@@ -22,6 +23,10 @@
--system-header-height: #{$system-header-height};
}
+.with-header {
+ --header-height: #{$header-height};
+}
+
.with-top-bar {
--top-bar-height: #{$top-bar-height};
}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 884cb70cb9f..a467d9e8c8a 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -287,6 +287,23 @@
}
}
+ .non-blocking-loader & {
+ &.is-loading{
+ .dropdown-content {
+ display: block;
+ height: 2rem;
+
+ ul{
+ display: none;
+ }
+ }
+ }
+
+ .dropdown-loading{
+ position: relative;
+ }
+ }
+
ul {
margin: 0;
padding: 0;
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index b78b07f953b..67e96f08cb0 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -369,22 +369,6 @@
.board-labels-toggle-wrapper {
margin-bottom: $gl-input-padding;
}
-
- .board-swimlanes-toggle-wrapper {
- @include gl-h-auto;
- margin-bottom: $gl-input-padding;
-
- > span,
- > .dropdown,
- .gl-dropdown-toggle {
- @include gl-w-full;
- @include gl-m-0;
- }
-
- > .dropdown {
- @include gl-mt-2;
- }
- }
}
}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index b9fbcfb642c..32735679ded 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -5,7 +5,7 @@ $search-input-field-x-min-width: 200px;
padding: 0 16px;
z-index: $header-zindex;
margin-bottom: 0;
- min-height: $header-height;
+ min-height: var(--header-height);
border: 0;
position: fixed;
top: $calc-system-headers-height;
@@ -22,7 +22,7 @@ $search-input-field-x-min-width: 200px;
display: flex;
justify-content: space-between;
position: relative;
- min-height: $header-height;
+ min-height: var(--header-height);
padding-left: 0;
.title {
@@ -505,7 +505,7 @@ $search-input-field-x-min-width: 200px;
.navbar-empty {
justify-content: center;
- height: $header-height;
+ height: var(--header-height);
background: $white;
border-bottom: 1px solid $gray-100;
@@ -642,7 +642,7 @@ header.navbar-gitlab.super-sidebar-logged-out {
&:focus,
&:active {
- box-shadow: inset 0 0 0 $gl-border-size-1 $white;
+ @include gl-focus;
}
&:active {
diff --git a/app/assets/stylesheets/framework/job_log.scss b/app/assets/stylesheets/framework/job_log.scss
index f77f64f1d76..e409facd081 100644
--- a/app/assets/stylesheets/framework/job_log.scss
+++ b/app/assets/stylesheets/framework/job_log.scss
@@ -6,7 +6,7 @@
word-break: break-all;
word-wrap: break-word;
color: color-yiq($builds-log-bg);
- border-radius: $border-radius-small;
+ border-radius: 0 0 $border-radius-default $border-radius-default;
min-height: 42px;
background-color: $builds-log-bg;
}
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 086a16edda2..171f070d776 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -4,6 +4,12 @@ html {
&.touch .tooltip {
display: none !important;
}
+
+ @include media-breakpoint-up(sm) {
+ &.logged-out-marketing-header {
+ --header-height: 72px;
+ }
+ }
}
body {
@@ -197,9 +203,3 @@ body {
padding-right: 0;
}
}
-
-@include media-breakpoint-up(sm) {
- .logged-out-marketing-header {
- --header-height: 72px;
- }
-}
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index b953ff3024b..b87fd3e67d4 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -76,7 +76,7 @@
.referenced-users {
color: $gl-text-color;
- padding-top: 10px;
+ padding: 0 $gl-padding $gl-padding-8;
}
.referenced-commands {
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index edebe9c95ad..a32663b17d3 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -263,7 +263,7 @@
@mixin build-log-top-bar($height) {
@include build-log-bar($height);
position: sticky;
- top: $calc-application-header-height;
+ top: calc(#{$calc-application-header-height} - 1px);
}
/*
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index 5f90dd62426..f2afa94e000 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -231,18 +231,6 @@
}
}
-.health-status {
- .dropdown-body {
- .health-divider {
- border-top-color: $gray-100;
- }
-
- .dropdown-item:not(.health-dropdown-item) {
- padding: 0;
- }
- }
-}
-
.toggle-right-sidebar-button {
@include side-panel-toggle;
border-bottom: 1px solid $border-color;
@@ -799,29 +787,6 @@
}
}
-.participants-more,
-.user-list-more {
- margin-left: 5px;
-
- a,
- .btn-link {
- color: $gl-text-color-secondary;
- }
-
- .btn-link {
- padding: 0;
- }
-
- .btn-link:hover {
- color: $blue-800;
- text-decoration: none;
- }
-
- .btn-link:focus {
- text-decoration: none;
- }
-}
-
.sidebar-help-wrap {
.sidebar-help-state {
margin: 16px -20px -20px;
diff --git a/app/assets/stylesheets/framework/super_sidebar.scss b/app/assets/stylesheets/framework/super_sidebar.scss
index 8610c41b43f..fbf9d8c8ca6 100644
--- a/app/assets/stylesheets/framework/super_sidebar.scss
+++ b/app/assets/stylesheets/framework/super_sidebar.scss
@@ -104,27 +104,6 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4;
box-shadow: none;
}
- .context-switcher .gl-new-dropdown-custom-toggle {
- width: 100%;
- }
-
- .context-switcher .gl-new-dropdown-panel {
- overflow-y: auto;
- }
-
- .context-switcher-search-box input {
- @include gl-font-sm;
- }
-
- .gl-new-dropdown-custom-toggle .context-switcher-toggle {
- &[aria-expanded='true'] {
- background-color: $t-gray-a-08;
- }
-
- &:focus {
- @include gl-focus($inset: true); }
- }
-
.btn-with-notification {
position: relative;
@@ -158,15 +137,6 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4;
}
}
- .nav-item-link {
- &:hover,
- &:focus-within {
- .nav-item-badge {
- opacity: 0;
- }
- }
- }
-
#trial-status-sidebar-widget:hover {
text-decoration: none;
@include gl-text-contrast-light;
@@ -177,6 +147,15 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4;
display: none;
}
+.super-sidebar-has-peeked {
+ margin-top: calc(#{$header-height} - #{$gl-spacing-scale-2});
+ margin-bottom: #{$gl-spacing-scale-2};
+}
+
+.super-sidebar-peek {
+ margin-left: #{$gl-spacing-scale-2};
+}
+
.super-sidebar-peek,
.super-sidebar-peek-hint {
@include gl-shadow;
@@ -189,6 +168,14 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4;
}
}
+.super-sidebar-peek {
+ border-radius: $border-radius-default;
+
+ .user-bar {
+ border-radius: $border-radius-default $border-radius-default 0 0;
+ }
+}
+
.page-with-super-sidebar {
padding-left: 0;
@@ -295,19 +282,71 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4;
}
}
+.transition-opacity-on-hover--context {
+ .transition-opacity-on-hover--target {
+ transition: opacity $gl-transition-duration-fast linear;
+
+ &:hover {
+ transition-delay: $gl-transition-duration-slow;
+ }
+ }
+
+ &:hover {
+ .transition-opacity-on-hover--target {
+ transition-delay: $gl-transition-duration-slow;
+ }
+ }
+}
+
.show-on-focus-or-hover--context {
.show-on-focus-or-hover--target {
opacity: 0;
+
+ &:hover,
+ &:focus {
+ opacity: 1;
+ }
}
&:hover,
- &:focus {
+ &:focus-within {
+ .show-on-focus-or-hover--control {
+ @include gl-bg-t-gray-a-08;
+ }
+
.show-on-focus-or-hover--target {
opacity: 1;
}
}
- .show-on-focus-or-hover--target:focus {
+ .show-on-focus-or-hover--control {
+ &:hover,
+ &:focus {
+ + .show-on-focus-or-hover--target {
+ opacity: 1;
+ }
+ }
+ }
+}
+
+.hide-on-focus-or-hover--context {
+ .hide-on-focus-or-hover--target {
opacity: 1;
}
+
+ &:hover,
+ &:focus-within {
+ .hide-on-focus-or-hover--target {
+ opacity: 0;
+ }
+ }
+
+ .hide-on-focus-or-hover--control {
+ &:hover,
+ &:focus {
+ .hide-on-focus-or-hover--target {
+ opacity: 0;
+ }
+ }
+ }
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index d632689a4f6..e83f6af603a 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -283,75 +283,79 @@ $color-ranges: (
// GitLab themes
-$indigo-50: #f7f7ff;
-$indigo-100: #ebebfa;
-$indigo-200: #d1d1f0;
-$indigo-300: #a6a6de;
-$indigo-400: #7c7ccc;
+$indigo-50: #f1f1ff;
+$indigo-100: #dbdbf8;
+$indigo-200: #c7c7f2;
+$indigo-300: #a2a2e6;
+$indigo-400: #8181d7;
$indigo-500: #6666c4;
-$indigo-600: #5b5bbd;
-$indigo-700: #4b4ba3;
-$indigo-800: #393982;
-$indigo-900: #292961;
-$indigo-950: #1a1a40;
+$indigo-600: #5252b5;
+$indigo-700: #41419f;
+$indigo-800: #303083;
+$indigo-900: #222261;
+$indigo-950: #14143d;
// To do this variant right for darkmode, we need to create a variable for it.
$indigo-900-alpha-008: rgba($indigo-900, 0.08);
-$theme-blue-50: #f4f8fc;
-$theme-blue-100: #e6edf5;
-$theme-blue-200: #c8d7e6;
-$theme-blue-300: #97b3cf;
-$theme-blue-400: #648cb4;
-$theme-blue-500: #4a79a8;
-$theme-blue-600: #3e6fa0;
-$theme-blue-700: #305c88;
-$theme-blue-800: #25496e;
-$theme-blue-900: #1a3652;
-$theme-blue-950: #0f2235;
-
-$theme-light-blue-50: #f2f7fc;
-$theme-light-blue-100: #ebf1f7;
-$theme-light-blue-200: #c9dcf2;
-$theme-light-blue-300: #83abd4;
-$theme-light-blue-400: #4d86bf;
-$theme-light-blue-500: #367cc2;
-$theme-light-blue-600: #3771ab;
-$theme-light-blue-700: #2261a1;
-
-$theme-green-50: #f2faf6;
-$theme-green-100: #e4f3ea;
-$theme-green-200: #c0dfcd;
-$theme-green-300: #8ac2a1;
-$theme-green-400: #52a274;
-$theme-green-500: #35935c;
-$theme-green-600: #288a50;
-$theme-green-700: #1c7441;
-$theme-green-800: #145d33;
-$theme-green-900: #0d4524;
-$theme-green-950: #072d16;
-
-$theme-light-green-700: #156b39;
-
-$theme-red-50: #fcf4f2;
-$theme-red-100: #fae9e6;
-$theme-red-200: #ebcac5;
-$theme-red-300: #d99b91;
-$theme-red-400: #b0655a;
+$theme-blue-50: #cdd8e3;
+$theme-blue-100: #b9cadc;
+$theme-blue-200: #a6bdd5;
+$theme-blue-300: #81a5c9;
+$theme-blue-400: #628eb9;
+$theme-blue-500: #4977a5;
+$theme-blue-600: #346596;
+$theme-blue-700: #235180;
+$theme-blue-800: #153c63;
+$theme-blue-900: #0b2640;
+$theme-blue-950: #04101c;
+
+$theme-light-blue-50: #dde6ee;
+$theme-light-blue-100: #c1d4e6;
+$theme-light-blue-200: #a0bedc;
+$theme-light-blue-300: #74a3d3;
+$theme-light-blue-400: #4f8bc7;
+$theme-light-blue-500: #3476b9;
+$theme-light-blue-600: #2268ae;
+$theme-light-blue-700: #145aa1;
+$theme-light-blue-800: #0e4d8d;
+$theme-light-blue-900: #0c4277;
+$theme-light-blue-950: #0a3764;
+
+$theme-green-50: #dde9de;
+$theme-green-100: #b1d6b5;
+$theme-green-200: #8cc497;
+$theme-green-300: #69af7d;
+$theme-green-400: #499767;
+$theme-green-500: #308258;
+$theme-green-600: #25744c;
+$theme-green-700: #1b653f;
+$theme-green-800: #155635;
+$theme-green-900: #0e4328;
+$theme-green-950: #052e19;
+
+$theme-red-50: #f4e9e7;
+$theme-red-100: #ecd3d0;
+$theme-red-200: #e3bab5;
+$theme-red-300: #d59086;
+$theme-red-400: #c66e60;
$theme-red-500: #ad4a3b;
-$theme-red-600: #9e4133;
-$theme-red-700: #912f20;
-$theme-red-800: #78291d;
-$theme-red-900: #691a16;
-$theme-red-950: #36140f;
-
-$theme-light-red-50: #fff6f5;
-$theme-light-red-100: #fae2de;
-$theme-light-red-200: #f7d5d0;
-$theme-light-red-300: #d9796a;
-$theme-light-red-400: #cf604e;
+$theme-red-600: #a13322;
+$theme-red-700: #8f2110;
+$theme-red-800: #761405;
+$theme-red-900: #580d02;
+$theme-red-950: #380700;
+
+$theme-light-red-50: #faf2f1;
+$theme-light-red-100: #f6d9d5;
+$theme-light-red-200: #ebada2;
+$theme-light-red-300: #e07f6f;
+$theme-light-red-400: #d36250;
$theme-light-red-500: #c24b38;
-$theme-light-red-600: #b03927;
-$theme-light-red-700: #a62e21;
+$theme-light-red-600: #b53a26;
+$theme-light-red-700: #a02e1c;
+$theme-light-red-800: #8b2212;
+$theme-light-red-900: #751709;
+$theme-light-red-950: #5c1105;
// Data visualization color palette
@@ -459,7 +463,7 @@ $browser-scrollbar-size: 10px;
/*
* Misc
*/
-$header-height: var(--header-height, 48px);
+$header-height: 48px;
$content-wrapper-padding: 100px;
$header-zindex: 1000;
$zindex-dropdown-menu: 300;
@@ -501,7 +505,7 @@ $pages-group-name-color: #4c4e54;
* Calculated heights
*/
$calc-system-headers-height: calc(var(--system-header-height) + var(--performance-bar-height));
-$calc-application-bars-height: calc(#{$header-height} + #{$calc-system-headers-height});
+$calc-application-bars-height: calc(var(--header-height) + #{$calc-system-headers-height});
$calc-application-header-height: calc(#{$calc-application-bars-height} + var(--top-bar-height));
$calc-application-footer-height: var(--system-footer-height);
$calc-application-viewport-height: calc(100vh - #{$calc-application-header-height} - #{$calc-application-footer-height});
@@ -692,14 +696,6 @@ $ci-skipped-color: #888;
*/
$issue-boards-font-size: 14px;
$issue-boards-card-shadow: rgba(0, 0, 0, 0.1);
-/*
- The following heights are used in environment_logs.scss and are used for calculation of the log viewer height.
-*/
-$environment-logs-breadcrumbs-height: 63px;
-$environment-logs-breadcrumbs-height-md: $top-bar-height;
-
-$environment-logs-difference-xs-up: calc(#{$header-height} + #{$environment-logs-breadcrumbs-height});
-$environment-logs-difference-md-up: calc(#{$header-height} + #{$environment-logs-breadcrumbs-height-md});
/*
* Avatar
@@ -845,12 +841,6 @@ $perf-bar-bucket-box-shadow-to: rgba($black, 0.25);
$perf-bar-canary-text: $orange-400;
/*
-Issuable warning
-*/
-$issuable-warning-size: 24px;
-$issuable-warning-icon-margin: 4px;
-
-/*
Image Commenting cursor
*/
$image-comment-cursor-left-offset: 12;
diff --git a/app/assets/stylesheets/page_bundles/admin/jobs_index.scss b/app/assets/stylesheets/page_bundles/admin/jobs_index.scss
deleted file mode 100644
index 7844cae5f87..00000000000
--- a/app/assets/stylesheets/page_bundles/admin/jobs_index.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-.admin-builds-table {
- td:last-child {
- min-width: 120px;
- }
-}
diff --git a/app/assets/stylesheets/page_bundles/build.scss b/app/assets/stylesheets/page_bundles/build.scss
index 5114f484e53..09c4d184f3f 100644
--- a/app/assets/stylesheets/page_bundles/build.scss
+++ b/app/assets/stylesheets/page_bundles/build.scss
@@ -15,6 +15,9 @@
.top-bar {
@include build-log-top-bar(50px);
+ z-index: 2;
+ border-radius: $border-radius-default $border-radius-default 0 0;
+ box-shadow: 0 -2px 0 0 var(--white);
&.has-archived-block {
top: calc(#{$calc-application-header-height} + 28px);
@@ -86,8 +89,6 @@
}
.right-sidebar.build-sidebar {
- padding: 0;
-
&.right-sidebar-collapsed {
display: none;
}
@@ -100,29 +101,6 @@
-webkit-overflow-scrolling: touch;
}
- .blocks-container {
- padding: 0 $gl-padding;
- width: 289px;
- }
-
- .trigger-variables-btn-container {
- justify-content: space-between;
- align-items: center;
-
- .trigger-variables-btn {
- margin-top: -5px;
- margin-bottom: -5px;
- }
- }
-
- .trigger-build-variables {
- margin: 0;
- overflow-x: auto;
- width: 100%;
- -ms-overflow-style: scrollbar;
- -webkit-overflow-scrolling: touch;
- }
-
.trigger-build-variable {
font-weight: $gl-font-weight-normal;
color: var(--gray-950, $gray-950);
@@ -142,38 +120,20 @@
vertical-align: top;
}
- .badge.badge-pill {
- margin-left: 2px;
+ .blocks-container {
+ width: 289px;
}
- .stage-item {
- cursor: pointer;
-
- &:hover {
- color: var(--gl-text-color, $gl-text-color);
- }
+ .block {
+ width: 262px;
}
.builds-container {
- background-color: var(--white, $white);
- border-top: 1px solid var(--border-color, $border-color);
- border-bottom: 1px solid var(--border-color, $border-color);
- max-height: 300px;
- width: 289px;
overflow: auto;
- a {
- padding: $gl-padding 10px $gl-padding 40px;
- width: 270px;
-
- &:hover {
- color: var(--gl-text-color, $gl-text-color);
- }
- }
-
.icon-arrow-right {
- left: 15px;
- top: 20px;
+ left: 8px;
+ top: 12px;
}
.build-job {
@@ -192,9 +152,15 @@
.container-fluid.container-limited {
max-width: 100%;
}
+}
- .content-wrapper {
- padding-bottom: 6px;
+.build-sidebar-item {
+ display: grid;
+ grid-template-columns: 1fr 2fr;
+ grid-gap: $gl-padding-8;
+
+ &:last-of-type {
+ @include gl-mb-0;
}
}
@@ -205,12 +171,3 @@
margin-bottom: 0;
}
}
-
-@include media-breakpoint-down(md) {
- .content-list {
- &.builds-content-list {
- width: 100%;
- overflow: auto;
- }
- }
-}
diff --git a/app/assets/stylesheets/page_bundles/incidents.scss b/app/assets/stylesheets/page_bundles/incidents.scss
index fde35ab3d39..c7873473b86 100644
--- a/app/assets/stylesheets/page_bundles/incidents.scss
+++ b/app/assets/stylesheets/page_bundles/incidents.scss
@@ -43,8 +43,7 @@
}
}
- &:last-child,
- &.create-timeline-event {
+ &:last-child {
&::before {
top: - #{$gl-spacing-scale-5} !important; // Override default positioning
@include gl-h-8;
diff --git a/app/assets/stylesheets/page_bundles/issuable.scss b/app/assets/stylesheets/page_bundles/issuable.scss
index 1b5da0368c6..5397f3d8895 100644
--- a/app/assets/stylesheets/page_bundles/issuable.scss
+++ b/app/assets/stylesheets/page_bundles/issuable.scss
@@ -1,15 +1,6 @@
@import 'mixins_and_variables_and_functions';
-.status-box {
- padding: 0 $gl-btn-padding;
- border-radius: $border-radius-default;
- display: block;
- float: left;
- margin-right: $gl-padding-8;
- color: var(--white, $white);
- font-size: $gl-font-size;
- line-height: $gl-line-height-24;
-}
+$issuable-warning-size: 24px;
.issuable-warning-icon {
background-color: var(--orange-50, $orange-50);
@@ -18,7 +9,6 @@
width: $issuable-warning-size;
height: $issuable-warning-size;
text-align: center;
- margin-right: $issuable-warning-icon-margin;
line-height: $gl-line-height-24;
flex: 0 0 auto;
}
diff --git a/app/assets/stylesheets/page_bundles/merge_request.scss b/app/assets/stylesheets/page_bundles/merge_request.scss
index 113a50c4efa..f03efb82860 100644
--- a/app/assets/stylesheets/page_bundles/merge_request.scss
+++ b/app/assets/stylesheets/page_bundles/merge_request.scss
@@ -3,6 +3,12 @@
$tabs-holder-z-index: 250;
$comparison-empty-state-height: 62px;
+.apply-suggestions-input-min-width {
+ @include media-breakpoint-up(lg) {
+ width: $gl-dropdown-width-wide;
+ }
+}
+
.space-children {
@include clearfix;
@@ -199,6 +205,7 @@ $comparison-empty-state-height: 62px;
top: $calc-application-header-height;
z-index: $tabs-holder-z-index;
border-bottom: 1px solid var(--border-color, $border-color);
+ background-color: var(--gray-10, $white);
@include media-breakpoint-up(md) {
position: sticky;
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index f39247f06c2..b00e1813696 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -372,7 +372,6 @@ $tabs-holder-z-index: 250;
white-space: nowrap;
}
- /* stylelint-disable scss/at-rule-no-unknown */
@container mr-widget-extension (max-width: 600px) {
flex-direction: column;
align-items: flex-start;
@@ -417,7 +416,7 @@ $tabs-holder-z-index: 250;
.media-body {
min-width: 0;
- font-size: 12px;
+ font-size: $gl-font-size-sm;
margin-left: 32px;
}
@@ -548,6 +547,7 @@ $tabs-holder-z-index: 250;
}
.mr-widget-section:not(:first-child) > div,
+ .mr-widget-section:not(:first-child) > section,
.mr-widget-section .mr-widget-section > div {
border-top: solid 1px var(--border-color, $border-color);
}
@@ -649,7 +649,6 @@ $tabs-holder-z-index: 250;
.label-branch {
@include gl-font-monospace;
- font-size: 95%;
overflow: hidden;
word-break: break-all;
}
@@ -663,7 +662,7 @@ $tabs-holder-z-index: 250;
> span {
display: inline-block;
max-width: 12.5em;
- margin-bottom: -5px;
+ margin-bottom: px-to-rem(-5px);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
@@ -987,6 +986,14 @@ $tabs-holder-z-index: 250;
}
}
+.container-fluid.diffs-container-limited {
+ .flash-container {
+ @include gl-mx-auto;
+ @include gl-max-w-container-xl;
+ @include gl-px-5;
+ }
+}
+
.submit-review-dropdown {
&.show .dropdown-menu {
width: calc(100vw - 20px);
diff --git a/app/assets/stylesheets/page_bundles/pipeline_schedules.scss b/app/assets/stylesheets/page_bundles/pipeline_schedules.scss
deleted file mode 100644
index af2dac7739e..00000000000
--- a/app/assets/stylesheets/page_bundles/pipeline_schedules.scss
+++ /dev/null
@@ -1,82 +0,0 @@
-@import 'mixins_and_variables_and_functions';
-
-.ci-variable-list {
- margin-left: 0;
- margin-bottom: 0;
- padding-left: 0;
- list-style: none;
- clear: both;
-}
-
-.ci-variable-row {
- display: flex;
- align-items: flex-start;
-
- @include media-breakpoint-down(xs) {
- align-items: flex-end;
- }
-
- &:not(:last-child) {
- margin-bottom: $gl-btn-padding;
-
- @include media-breakpoint-down(xs) {
- margin-bottom: 3 * $gl-btn-padding;
- }
- }
-
- &:last-child {
- .ci-variable-body-item:last-child {
- margin-right: $ci-variable-remove-button-width;
-
- @include media-breakpoint-down(xs) {
- margin-right: 0;
- }
- }
-
- .ci-variable-row-remove-button {
- display: none;
- }
-
- @include media-breakpoint-down(xs) {
- .ci-variable-row-body {
- margin-right: $ci-variable-remove-button-width;
- }
- }
- }
-}
-
-.ci-variable-row-body {
- display: flex;
- align-items: flex-start;
- width: 100%;
- padding-bottom: $gl-padding;
-
- @include media-breakpoint-down(xs) {
- display: block;
- }
-}
-
-.ci-variable-body-item {
- flex: 1;
-
- &:not(:last-child) {
- margin-right: $gl-btn-padding;
-
- @include media-breakpoint-down(xs) {
- margin-right: 0;
- margin-bottom: $gl-btn-padding;
- }
- }
-}
-
-.pipeline-schedule-form {
- .gl-field-error {
- margin: 10px 0 0;
- }
-}
-
-.pipeline-schedule-table-row {
- a {
- color: var(--gl-text-color, $gl-text-color);
- }
-}
diff --git a/app/assets/stylesheets/page_bundles/profiles/preferences.scss b/app/assets/stylesheets/page_bundles/profiles/preferences.scss
index 1a59f96c6ee..d09ad42a722 100644
--- a/app/assets/stylesheets/page_bundles/profiles/preferences.scss
+++ b/app/assets/stylesheets/page_bundles/profiles/preferences.scss
@@ -1,9 +1,9 @@
@import 'page_bundles/mixins_and_variables_and_functions';
.application-theme {
- $ui-gray-bg: #303030;
- $ui-light-gray-bg: #f0f0f0;
- $ui-dark-mode-bg: #1f1f1f;
+ $ui-gray-bg: $gray-900;
+ $ui-light-gray-bg: $gray-50;
+ $ui-dark-mode-bg: $gray-950;
.preview {
font-size: 0;
@@ -33,7 +33,7 @@
}
&.ui-light-green {
- background-color: $theme-light-green-700;
+ background-color: $theme-green-700;
}
&.ui-red {
diff --git a/app/assets/stylesheets/page_bundles/projects_usage_quotas.scss b/app/assets/stylesheets/page_bundles/projects_usage_quotas.scss
deleted file mode 100644
index 8f2cbc402c9..00000000000
--- a/app/assets/stylesheets/page_bundles/projects_usage_quotas.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-@import 'mixins_and_variables_and_functions';
-
-.storage-type-usage {
- &:first-child {
- @include gl-rounded-top-left-base;
- @include gl-rounded-bottom-left-base;
- }
-
- &:last-child {
- @include gl-rounded-top-right-base;
- @include gl-rounded-bottom-right-base;
- }
-
- &:not(:last-child) {
- @include gl-border-r-2;
- @include gl-border-r-solid;
- border-right-color: var(--white, $white);
- }
-}
diff --git a/app/assets/stylesheets/page_bundles/work_items.scss b/app/assets/stylesheets/page_bundles/work_items.scss
index e8fa93e1504..f36cbc129a7 100644
--- a/app/assets/stylesheets/page_bundles/work_items.scss
+++ b/app/assets/stylesheets/page_bundles/work_items.scss
@@ -173,3 +173,13 @@ $work-item-sticky-header-height: 52px;
min-width: 100%;
}
}
+
+.work-item-notification-toggle {
+ .gl-toggle {
+ margin-left: auto;
+ }
+
+ .gl-toggle-label {
+ font-weight: normal;
+ }
+}
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 0c9d151e3cd..38686d5e713 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -136,7 +136,7 @@
}
.icon {
- margin-right: $issuable-warning-icon-margin;
+ margin-right: $gl-padding-4;
vertical-align: text-bottom;
fill: $orange-600;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index b9cae28537d..9ce470dbcf2 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -306,8 +306,6 @@
}
.project-details {
- max-width: 625px;
-
p,
.commit-row-message {
@include gl-mb-0;
diff --git a/app/assets/stylesheets/themes/dark_mode_overrides.scss b/app/assets/stylesheets/themes/dark_mode_overrides.scss
index 030e41046d3..7616f573412 100644
--- a/app/assets/stylesheets/themes/dark_mode_overrides.scss
+++ b/app/assets/stylesheets/themes/dark_mode_overrides.scss
@@ -235,7 +235,7 @@ body.gl-dark {
}
- .navbar-gitlab {
+ .navbar.navbar-gitlab {
background-color: var(--gray-50);
box-shadow: 0 1px 0 0 var(--gray-100);
diff --git a/app/assets/stylesheets/themes/theme_helper.scss b/app/assets/stylesheets/themes/theme_helper.scss
index 8f0e0781918..db20034419a 100644
--- a/app/assets/stylesheets/themes/theme_helper.scss
+++ b/app/assets/stylesheets/themes/theme_helper.scss
@@ -20,7 +20,7 @@
// Header
- .navbar-gitlab {
+ .navbar-gitlab:not(.super-sidebar-logged-out) {
background-color: $navbar-theme-color;
.navbar-collapse {
@@ -283,11 +283,12 @@
$theme-color,
$theme-color-darkest,
) {
+ --sidebar-background: #{mix(white, $theme-color-lightest, 50%)};
--transparent-white-16: rgba(255, 255, 255, 0.16);
--transparent-white-24: rgba(255, 255, 255, 0.24);
.super-sidebar {
- background-color: $theme-color-lightest;
+ background-color: var(--sidebar-background);
}
.super-sidebar .user-bar {
@@ -335,4 +336,8 @@
.active-indicator {
background-color: $theme-color;
}
+
+ .super-sidebar-context-header {
+ color: $theme-color;
+ }
}
diff --git a/app/assets/stylesheets/themes/theme_light_gray.scss b/app/assets/stylesheets/themes/theme_light_gray.scss
index 9b7fc10e769..e8357647f48 100644
--- a/app/assets/stylesheets/themes/theme_light_gray.scss
+++ b/app/assets/stylesheets/themes/theme_light_gray.scss
@@ -10,7 +10,7 @@ body {
$gray-500
);
- .navbar-gitlab {
+ .navbar-gitlab:not(.super-sidebar-logged-out) {
background-color: $gray-50;
box-shadow: 0 1px 0 0 $border-color;
diff --git a/app/assets/stylesheets/themes/theme_light_green.scss b/app/assets/stylesheets/themes/theme_light_green.scss
index 720a0ec58b8..6b058b2dd7b 100644
--- a/app/assets/stylesheets/themes/theme_light_green.scss
+++ b/app/assets/stylesheets/themes/theme_light_green.scss
@@ -6,7 +6,7 @@ body {
$theme-green-200,
$theme-green-500,
$theme-green-500,
- $theme-light-green-700,
+ $theme-green-700,
$white
);
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index d5e9d35983a..b756e0ed704 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -132,19 +132,6 @@
fill: $red-500;
}
-// Will be moved to @gitlab/ui in https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/3569
-.gl-mb-n5 {
- margin-bottom: -$gl-spacing-scale-5;
-}
-
-.gl-mb-n7 {
- margin-bottom: -$gl-spacing-scale-7;
-}
-
-.gl-mb-n8 {
- margin-bottom: -$gl-spacing-scale-8;
-}
-
.gl-hover-border-gray-100:hover {
border-color: $gray-100;
}
diff --git a/app/channels/noteable/notes_channel.rb b/app/channels/noteable/notes_channel.rb
index 021bc3ccd1b..8ce6c15e123 100644
--- a/app/channels/noteable/notes_channel.rb
+++ b/app/channels/noteable/notes_channel.rb
@@ -13,7 +13,6 @@ module Noteable
}).target
return reject if noteable.nil?
- return reject if Feature.disabled?(:action_cable_notes, project || noteable.try(:group))
stream_for noteable
rescue ActiveRecord::RecordNotFound
diff --git a/app/components/pajamas/banner_component.html.haml b/app/components/pajamas/banner_component.html.haml
index c2eeae2d8c9..8a177edddb5 100644
--- a/app/components/pajamas/banner_component.html.haml
+++ b/app/components/pajamas/banner_component.html.haml
@@ -19,5 +19,4 @@
- actions.each do |action|
= action
- %button.gl-button.gl-banner-close.btn-sm.btn-icon.js-close{ @close_options, class: close_class, type: 'button' }
- = sprite_icon('close', size: 16, css_class: 'dismiss-icon')
+ = render Pajamas::ButtonComponent.new(category: :tertiary, variant: close_button_variant, size: :small, icon: 'close', button_options: @close_options)
diff --git a/app/components/pajamas/banner_component.rb b/app/components/pajamas/banner_component.rb
index 1a03f3fdd58..5291db91fb2 100644
--- a/app/components/pajamas/banner_component.rb
+++ b/app/components/pajamas/banner_component.rb
@@ -27,7 +27,7 @@ module Pajamas
@svg_path = svg_path.to_s
@banner_options = banner_options
@button_options = button_options
- @close_options = close_options
+ @close_options = format_options(options: close_options, css_classes: %w[js-close gl-banner-close])
end
VARIANT_OPTIONS = [:introduction, :promotion].freeze
@@ -41,11 +41,11 @@ module Pajamas
classes.join(' ')
end
- def close_class
+ def close_button_variant
if introduction?
- 'btn-confirm btn-confirm-tertiary'
+ :confirm
else
- 'btn-default btn-default-tertiary'
+ :default
end
end
diff --git a/app/controllers/activity_pub/application_controller.rb b/app/controllers/activity_pub/application_controller.rb
new file mode 100644
index 00000000000..f9c2b14fe77
--- /dev/null
+++ b/app/controllers/activity_pub/application_controller.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class ApplicationController < ::ApplicationController
+ include RoutableActions
+
+ before_action :ensure_feature_flag
+ skip_before_action :authenticate_user!
+ after_action :set_content_type
+
+ def can?(object, action, subject = :global)
+ Ability.allowed?(object, action, subject)
+ end
+
+ def route_not_found
+ head :not_found
+ end
+
+ def set_content_type
+ self.content_type = "application/activity+json"
+ end
+
+ def ensure_feature_flag
+ not_found unless ::Feature.enabled?(:activity_pub)
+ end
+ end
+end
diff --git a/app/controllers/activity_pub/projects/application_controller.rb b/app/controllers/activity_pub/projects/application_controller.rb
new file mode 100644
index 00000000000..e54a457743d
--- /dev/null
+++ b/app/controllers/activity_pub/projects/application_controller.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ module Projects
+ class ApplicationController < ::ActivityPub::ApplicationController
+ before_action :project
+ before_action :ensure_project_feature_flag
+
+ private
+
+ def project
+ return unless params[:project_id] || params[:id]
+
+ path = File.join(params[:namespace_id], params[:project_id] || params[:id])
+
+ @project = find_routable!(Project, path, request.fullpath, extra_authorization_proc: auth_proc)
+ end
+
+ def auth_proc
+ ->(project) { project.public? && !project.pending_delete? }
+ end
+
+ def ensure_project_feature_flag
+ not_found unless ::Feature.enabled?(:activity_pub_project, project)
+ end
+ end
+ end
+end
diff --git a/app/controllers/activity_pub/projects/releases_controller.rb b/app/controllers/activity_pub/projects/releases_controller.rb
new file mode 100644
index 00000000000..7c4c2a0322b
--- /dev/null
+++ b/app/controllers/activity_pub/projects/releases_controller.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ module Projects
+ class ReleasesController < ApplicationController
+ feature_category :release_orchestration
+
+ def index
+ opts = {
+ inbox: nil,
+ outbox: outbox_project_releases_url(@project)
+ }
+
+ render json: ActivityPub::ReleasesActorSerializer.new.represent(@project, opts)
+ end
+
+ def outbox
+ serializer = ActivityPub::ReleasesOutboxSerializer.new.with_pagination(request, response)
+ render json: serializer.represent(releases)
+ end
+
+ private
+
+ def releases(params = {})
+ ReleasesFinder.new(@project, current_user, params).execute
+ end
+ end
+ end
+end
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index 329c4e4921a..b48d6f4f7c2 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -3,8 +3,11 @@
class Admin::AbuseReportsController < Admin::ApplicationController
feature_category :insider_threat
- before_action :set_status_param, only: :index, if: -> { Feature.enabled?(:abuse_reports_list) }
+ before_action :set_status_param, only: :index
before_action :find_abuse_report, only: [:show, :moderate_user, :update, :destroy]
+ before_action only: :show do
+ push_frontend_feature_flag(:abuse_report_labels)
+ end
def index
@abuse_reports = AbuseReportsFinder.new(params).execute
@@ -12,14 +15,11 @@ class Admin::AbuseReportsController < Admin::ApplicationController
def show; end
- # Kept for backwards compatibility.
- # TODO: See https://gitlab.com/gitlab-org/modelops/anti-abuse/team-tasks/-/issues/167?work_item_iid=443
- # In 16.4 remove or re-use this endpoint after frontend has migrated to using moderate_user endpoint
def update
- response = Admin::AbuseReports::ModerateUserService.new(@abuse_report, current_user, permitted_params).execute
+ response = Admin::AbuseReports::UpdateService.new(@abuse_report, current_user, permitted_params).execute
if response.success?
- render json: { message: response.message }
+ head :ok
else
render json: { message: response.message }, status: :unprocessable_entity
end
@@ -53,6 +53,6 @@ class Admin::AbuseReportsController < Admin::ApplicationController
end
def permitted_params
- params.permit(:user_action, :close, :reason, :comment)
+ params.permit(:user_action, :close, :reason, :comment, { label_ids: [] })
end
end
diff --git a/app/controllers/admin/jobs_controller.rb b/app/controllers/admin/jobs_controller.rb
index 5ea8c672993..d0ade3e6024 100644
--- a/app/controllers/admin/jobs_controller.rb
+++ b/app/controllers/admin/jobs_controller.rb
@@ -7,18 +7,10 @@ class Admin::JobsController < Admin::ApplicationController
urgency :low
before_action do
- push_frontend_feature_flag(:admin_jobs_vue)
+ push_frontend_feature_flag(:admin_jobs_filter_runner_type, type: :ops)
end
- def index
- # We need all builds for tabs counters
- @all_builds = Ci::JobsFinder.new(current_user: current_user).execute
-
- @scope = params[:scope]
- @builds = Ci::JobsFinder.new(current_user: current_user, params: params).execute
- @builds = @builds.eager_load_everything
- @builds = @builds.page(params[:page]).per(BUILDS_PER_PAGE).without_count
- end
+ def index; end
def cancel_all
Ci::Build.running_or_pending.each(&:cancel)
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index f05b03c2787..1f05e4e7b21 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -221,8 +221,7 @@ class Admin::UsersController < Admin::ApplicationController
respond_to do |format|
result = Users::UpdateService.new(current_user, user_params_with_pass.merge(user: user)).execute do |user|
- user.skip_reconfirmation!
- user.send_only_admin_changed_your_password_notification! if admin_making_changes_for_another_user?
+ prepare_user_for_update(user)
end
if result[:status] == :success
@@ -393,6 +392,12 @@ class Admin::UsersController < Admin::ApplicationController
@can_impersonate = helpers.can_impersonate_user(user, impersonation_in_progress?)
@impersonation_error_text = @can_impersonate ? nil : helpers.impersonation_error_text(user, impersonation_in_progress?)
end
+
+ # method overriden in EE
+ def prepare_user_for_update(user)
+ user.skip_reconfirmation!
+ user.send_only_admin_changed_your_password_notification! if admin_making_changes_for_another_user?
+ end
end
Admin::UsersController.prepend_mod_with('Admin::UsersController')
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 08e4f4956df..7c69f43fa3d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -38,7 +38,6 @@ class ApplicationController < ActionController::Base
before_action :active_user_check, unless: :devise_controller?
before_action :set_usage_stats_consent_flag
before_action :check_impersonation_availability
- before_action :required_signup_info
# Make sure the `auth_user` is memoized so it can be logged, we do this after
# all other before filters that could have set the user.
@@ -115,6 +114,24 @@ class ApplicationController < ActionController::Base
content_security_policy do |p|
next if p.directives.blank?
+
+ if Rails.env.development? && Feature.enabled?(:vite)
+ vite_host = ViteRuby.instance.config.host
+ vite_port = ViteRuby.instance.config.port
+ vite_origin = "#{vite_host}:#{vite_port}"
+ http_origin = "http://#{vite_origin}"
+ ws_origin = "ws://#{vite_origin}"
+ wss_origin = "wss://#{vite_origin}"
+ gitlab_ws_origin = Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'vite-dev/')
+ http_path = Gitlab::Utils.append_path(http_origin, 'vite-dev/')
+
+ connect_sources = p.directives['connect-src']
+ p.connect_src(*(Array.wrap(connect_sources) | [ws_origin, wss_origin, http_path]))
+
+ worker_sources = p.directives['worker-src']
+ p.worker_src(*(Array.wrap(worker_sources) | [gitlab_ws_origin, http_path]))
+ end
+
next unless Gitlab::CurrentSettings.snowplow_enabled? && !Gitlab::CurrentSettings.snowplow_collector_hostname.blank?
default_connect_src = p.directives['connect-src'] || p.directives['default-src']
@@ -326,9 +343,12 @@ class ApplicationController < ActionController::Base
end
def check_password_expiration
- return if session[:impersonator_id] || !current_user&.allow_password_authentication?
+ return if session[:impersonator_id]
+ return if current_user.nil?
- redirect_to new_profile_password_path if current_user&.password_expired?
+ if current_user.password_expired? && current_user.allow_password_authentication?
+ redirect_to new_profile_password_path
+ end
end
def active_user_check
@@ -555,15 +575,6 @@ class ApplicationController < ActionController::Base
def context_user
auth_user if strong_memoized?(:auth_user)
end
-
- def required_signup_info
- return unless current_user
- return unless current_user.role_required?
-
- store_location_for :user, request.fullpath
-
- redirect_to users_sign_up_welcome_path
- end
end
ApplicationController.prepend_mod
diff --git a/app/controllers/clusters/agents/dashboard_controller.rb b/app/controllers/clusters/agents/dashboard_controller.rb
new file mode 100644
index 00000000000..1f72aaa4775
--- /dev/null
+++ b/app/controllers/clusters/agents/dashboard_controller.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Agents
+ class DashboardController < ApplicationController
+ include KasCookie
+
+ before_action :check_feature_flag!
+ before_action :find_agent
+ before_action :authorize_read_cluster_agent!
+ before_action :set_kas_cookie, only: [:show], if: -> { current_user }
+
+ feature_category :deployment_management
+
+ def show
+ head :ok
+ end
+
+ private
+
+ def find_agent
+ @agent = ::Clusters::Agent.find(params[:agent_id])
+ end
+
+ def check_feature_flag!
+ not_found unless ::Feature.enabled?(:k8s_dashboard, current_user)
+ end
+
+ def authorize_read_cluster_agent!
+ not_found unless can?(current_user, :read_cluster_agent, @agent)
+ end
+ end
+ end
+end
diff --git a/app/controllers/concerns/access_tokens_actions.rb b/app/controllers/concerns/access_tokens_actions.rb
index 84cbdda1581..de53fd4d835 100644
--- a/app/controllers/concerns/access_tokens_actions.rb
+++ b/app/controllers/concerns/access_tokens_actions.rb
@@ -69,6 +69,7 @@ module AccessTokensActions
resource.members.load
@scopes = Gitlab::Auth.available_scopes_for(resource)
+ @scopes.delete(Gitlab::Auth::K8S_PROXY_SCOPE) unless Feature.enabled?(:k8s_proxy_pat, current_user)
@active_access_tokens = active_access_tokens
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
diff --git a/app/controllers/concerns/harbor/access.rb b/app/controllers/concerns/harbor/access.rb
index 211566aeda7..9466952e98e 100644
--- a/app/controllers/concerns/harbor/access.rb
+++ b/app/controllers/concerns/harbor/access.rb
@@ -5,21 +5,13 @@ module Harbor
extend ActiveSupport::Concern
included do
- before_action :harbor_registry_enabled!
before_action :authorize_read_harbor_registry!
- before_action do
- push_frontend_feature_flag(:harbor_registry_integration)
- end
feature_category :integrations
end
private
- def harbor_registry_enabled!
- render_404 unless Feature.enabled?(:harbor_registry_integration, defined?(group) ? group : project)
- end
-
def authorize_read_harbor_registry!
raise NotImplementedError
end
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index 1b49cffd408..28e1056092d 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -174,22 +174,11 @@ module IssuableActions
if Gitlab::Database.read_only? || params[:persist_filter] == 'false'
notes_filter_param || current_user&.notes_filter_for(issuable)
else
- notes_filter = current_user&.set_notes_filter(notes_filter_param, issuable) || notes_filter_param
-
- # We need to invalidate the cache for polling notes otherwise it will
- # ignore the filter.
- # The ideal would be to invalidate the cache for each user.
- issuable.expire_note_etag_cache if notes_filter_updated?
-
- notes_filter
+ current_user&.set_notes_filter(notes_filter_param, issuable) || notes_filter_param
end
end
end
- def notes_filter_updated?
- current_user&.user_preference&.previous_changes&.any?
- end
-
def discussion_cache_context
[current_user&.cache_key, project.team.human_max_access(current_user&.id), 'v2'].join(':')
end
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index b02a636ff74..5479154f667 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -20,26 +20,10 @@ module IssuableCollections
set_pagination
return if redirect_out_of_range(@issuables, @total_pages)
-
- if params[:label_name].present? && @project
- labels_params = { project_id: @project.id, title: params[:label_name] }
- @labels = LabelsFinder.new(current_user, labels_params).execute
- end
-
- @users = []
- if params[:assignee_id].present?
- assignee = User.find_by_id(params[:assignee_id])
- @users.push(assignee) if assignee
- end
-
- if params[:author_id].present?
- author = User.find_by_id(params[:author_id])
- @users.push(author) if author
- end
end
def set_pagination
- row_count = finder.row_count
+ row_count = request.format.atom? ? -1 : finder.row_count
@issuables = @issuables.page(params[:page])
@issuables = per_page_for_relative_position if params[:sort] == 'relative_position'
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index 93cf1d15086..31b3d311865 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -33,9 +33,6 @@ module NotesActions
notes.map { |note| note_json(note) }
end
- # Only present an ETag for the empty response
- ::Gitlab::EtagCaching::Middleware.skip!(response) if notes.present?
-
render json: meta.merge(notes: notes)
end
diff --git a/app/controllers/concerns/onboarding/status.rb b/app/controllers/concerns/onboarding/status.rb
index 5112ebb3b5d..8a99f5a6c12 100644
--- a/app/controllers/concerns/onboarding/status.rb
+++ b/app/controllers/concerns/onboarding/status.rb
@@ -31,12 +31,6 @@ module Onboarding
last_invited_member&.source
end
- def invite_with_tasks_to_be_done?
- return false if members.empty?
-
- MemberTask.for_members(members).exists?
- end
-
private
attr_reader :user
diff --git a/app/controllers/concerns/preferred_language_switcher.rb b/app/controllers/concerns/preferred_language_switcher.rb
index 872652100c9..529d1fb78bd 100644
--- a/app/controllers/concerns/preferred_language_switcher.rb
+++ b/app/controllers/concerns/preferred_language_switcher.rb
@@ -2,6 +2,8 @@
module PreferredLanguageSwitcher
extend ActiveSupport::Concern
+ include Gitlab::Utils::StrongMemoize
+ include PreferredLanguageSwitcherHelper
private
@@ -11,8 +13,37 @@ module PreferredLanguageSwitcher
def preferred_language
cookies[:preferred_language].presence_in(Gitlab::I18n.available_locales) ||
+ selectable_language(marketing_site_language) ||
+ selectable_language(browser_languages) ||
Gitlab::CurrentSettings.default_preferred_language
end
+
+ def selectable_language(language_options)
+ language_options.find { |lan| ordered_selectable_locales_codes.include?(lan) }
+ end
+
+ def ordered_selectable_locales_codes
+ ordered_selectable_locales.pluck(:value) # rubocop:disable CodeReuse/ActiveRecord
+ end
+
+ def browser_languages
+ formatted_http_language_header = request.env['HTTP_ACCEPT_LANGUAGE']&.tr('-', '_')
+
+ return [] unless formatted_http_language_header
+
+ formatted_http_language_header.split(%r{[;,]}).reject { |str| str.start_with?('q') }
+ end
+ strong_memoize_attr :browser_languages
+
+ def marketing_site_language
+ return [] unless params[:glm_source]
+
+ locale = params[:glm_source].scan(%r{(\w{2})-(\w{2})}).flatten
+
+ return [] if locale.empty?
+
+ [locale[0], "#{locale[0]}_#{locale[1]}"]
+ end
end
PreferredLanguageSwitcher.prepend_mod
diff --git a/app/controllers/concerns/search_rate_limitable.rb b/app/controllers/concerns/search_rate_limitable.rb
index 1105e9bbbfd..e32fc2f4dd6 100644
--- a/app/controllers/concerns/search_rate_limitable.rb
+++ b/app/controllers/concerns/search_rate_limitable.rb
@@ -11,7 +11,8 @@ module SearchRateLimitable
# scopes to get counts, we apply rate limits on the search scope if it is present.
#
# If abusive search is detected, we have stricter limits and ignore the search scope.
- check_rate_limit!(:search_rate_limit, scope: [current_user, safe_search_scope].compact)
+ check_rate_limit!(:search_rate_limit, scope: [current_user, safe_search_scope].compact,
+ users_allowlist: Gitlab::CurrentSettings.current_application_settings.search_rate_limit_allowlist)
else
check_rate_limit!(:search_rate_limit_unauthenticated, scope: [request.ip])
end
diff --git a/app/controllers/concerns/verifies_with_email.rb b/app/controllers/concerns/verifies_with_email.rb
index 6affd7bb4cc..cb8aef11e8d 100644
--- a/app/controllers/concerns/verifies_with_email.rb
+++ b/app/controllers/concerns/verifies_with_email.rb
@@ -9,7 +9,6 @@ module VerifiesWithEmail
included do
prepend_before_action :verify_with_email, only: :create, unless: -> { skip_verify_with_email? }
- skip_before_action :required_signup_info, only: :successful_verification
end
# rubocop:disable Metrics/PerceivedComplexity
diff --git a/app/controllers/concerns/web_hooks/hook_log_actions.rb b/app/controllers/concerns/web_hooks/hook_log_actions.rb
index 321cee5a452..dcea7596790 100644
--- a/app/controllers/concerns/web_hooks/hook_log_actions.rb
+++ b/app/controllers/concerns/web_hooks/hook_log_actions.rb
@@ -20,8 +20,13 @@ module WebHooks
end
def retry
- execute_hook
- redirect_to after_retry_redirect_path
+ if hook_log.url_current?
+ execute_hook
+ redirect_to after_retry_redirect_path
+ else
+ flash[:warning] = _('The hook URL has changed, and this log entry cannot be retried')
+ redirect_back(fallback_location: after_retry_redirect_path)
+ end
end
private
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index f7c7ee62c1a..5ceabaa734a 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -7,7 +7,6 @@ class ConfirmationsController < Devise::ConfirmationsController
include GoogleAnalyticsCSP
include GoogleSyndicationCSP
- skip_before_action :required_signup_info
prepend_before_action :check_recaptcha, only: :create
before_action :load_recaptcha, only: :new
diff --git a/app/controllers/groups/email_campaigns_controller.rb b/app/controllers/groups/email_campaigns_controller.rb
deleted file mode 100644
index 8ae429de490..00000000000
--- a/app/controllers/groups/email_campaigns_controller.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# frozen_string_literal: true
-
-class Groups::EmailCampaignsController < Groups::ApplicationController
- EMAIL_CAMPAIGNS_SCHEMA_URL = 'iglu:com.gitlab/email_campaigns/jsonschema/1-0-0'
-
- feature_category :experimentation_activation
- urgency :low
-
- before_action :check_params
-
- def index
- track_click
- redirect_to redirect_link
- end
-
- private
-
- def track_click
- if Gitlab.com?
- message = Gitlab::Email::Message::InProductMarketing.for(@track).new(group: group, user: current_user, series: @series)
-
- data = {
- namespace_id: group.id,
- track: @track.to_s,
- series: @series,
- subject_line: message.subject_line
- }
- context = SnowplowTracker::SelfDescribingJson.new(EMAIL_CAMPAIGNS_SCHEMA_URL, data)
-
- ::Gitlab::Tracking.event(self.class.name, 'click', context: [context], user: current_user, namespace: group)
- else
- ::Users::InProductMarketingEmail.save_cta_click(current_user, @track, @series)
- end
- end
-
- def redirect_link
- case @track
- when :create
- create_track_url
- when :verify
- project_pipelines_url(group.projects.first)
- when :trial, :trial_short
- 'https://about.gitlab.com/free-trial/'
- when :team, :team_short
- group_group_members_url(group)
- when :admin_verify
- project_settings_ci_cd_path(group.projects.first, anchor: 'js-runners-settings')
- end
- end
-
- def create_track_url
- [
- new_project_url,
- new_project_url(anchor: 'import_project'),
- help_page_url('user/project/repository/repository_mirroring')
- ][@series]
- end
-
- def check_params
- @track = params[:track]&.to_sym
- @series = params[:series]&.to_i
-
- track_valid = @track.in?(Namespaces::InProductMarketingEmailsService::TRACKS.keys)
- return render_404 unless track_valid
-
- series_valid = @series.in?(0..Namespaces::InProductMarketingEmailsService::TRACKS[@track][:interval_days].size - 1)
- render_404 unless series_valid
- end
-end
diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb
index f927cae90b1..9535b83e769 100644
--- a/app/controllers/groups/labels_controller.rb
+++ b/app/controllers/groups/labels_controller.rb
@@ -98,7 +98,10 @@ class Groups::LabelsController < Groups::ApplicationController
end
def label_params
- params.require(:label).permit(:title, :description, :color)
+ allowed = [:title, :description, :color]
+ allowed << :lock_on_merge if @group.supports_lock_on_merge?
+
+ params.require(:label).permit(allowed)
end
def redirect_back_or_group_labels_path(options = {})
diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb
index b3539da8429..3600a0fbed5 100644
--- a/app/controllers/groups/runners_controller.rb
+++ b/app/controllers/groups/runners_controller.rb
@@ -42,6 +42,8 @@ class Groups::RunnersController < Groups::ApplicationController
@runner ||= Ci::RunnersFinder.new(current_user: current_user, params: group_params).execute
.except(:limit, :offset)
.find(params[:id])
+ rescue Gitlab::Access::AccessDeniedError
+ nil
end
def runner_params
diff --git a/app/controllers/groups/work_items_controller.rb b/app/controllers/groups/work_items_controller.rb
index d1e15c81471..bd85f12119b 100644
--- a/app/controllers/groups/work_items_controller.rb
+++ b/app/controllers/groups/work_items_controller.rb
@@ -7,5 +7,9 @@ module Groups
def index
not_found unless Feature.enabled?(:namespace_level_work_items, group)
end
+
+ def show
+ not_found unless Feature.enabled?(:namespace_level_work_items, group)
+ end
end
end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 344de886a93..edc590e1370 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -37,7 +37,6 @@ class GroupsController < Groups::ApplicationController
push_frontend_feature_flag(:frontend_caching, group)
push_force_frontend_feature_flag(:work_items, group.work_items_feature_flag_enabled?)
push_frontend_feature_flag(:issues_grid_view)
- push_frontend_feature_flag(:new_graphql_users_autocomplete, group)
end
before_action only: :merge_requests do
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index 9635e476510..df8128f24fe 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -9,7 +9,7 @@ class HelpController < ApplicationController
# Taken from Jekyll
# https://github.com/jekyll/jekyll/blob/3.5-stable/lib/jekyll/document.rb#L13
- YAML_FRONT_MATTER_REGEXP = /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m.freeze
+ YAML_FRONT_MATTER_REGEXP = /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
def index
@help_index = get_markdown_without_frontmatter(path_to_doc('index.md'))
diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb
index e17cd00d053..ba2743e1002 100644
--- a/app/controllers/import/bitbucket_server_controller.rb
+++ b/app/controllers/import/bitbucket_server_controller.rb
@@ -22,8 +22,8 @@ class Import::BitbucketServerController < Import::BaseController
# (https://community.atlassian.com/t5/Answers-Developer-Questions/stash-repository-names/qaq-p/499054)
#
# Bitbucket Server starts personal project names with a tilde.
- VALID_BITBUCKET_PROJECT_CHARS = /\A~?[\w\-\.\s]+\z/.freeze
- VALID_BITBUCKET_CHARS = /\A[\w\-\.\s]+\z/.freeze
+ VALID_BITBUCKET_PROJECT_CHARS = /\A~?[\w\-\.\s]+\z/
+ VALID_BITBUCKET_CHARS = /\A[\w\-\.\s]+\z/
def new
end
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index 8a8ae38c6f3..c058329680a 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -83,8 +83,6 @@ class InvitesController < ApplicationController
def authenticate_user!
return if current_user
- store_location_for(:user, invite_details[:path]) if member
-
if user_sign_up?
set_session_invite_params
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
index a1d4df6ff48..a541e7e703f 100644
--- a/app/controllers/oauth/authorizations_controller.rb
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -14,7 +14,7 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
# include the call to session.delete
def new
if pre_auth.authorizable?
- if skip_authorization? || matching_token?
+ if skip_authorization? || (matching_token? && pre_auth.client.application.confidential?)
auth = authorization.authorize
parsed_redirect_uri = URI.parse(auth.redirect_uri)
session.delete(:user_return_to)
diff --git a/app/controllers/organizations/application_controller.rb b/app/controllers/organizations/application_controller.rb
index 568cfe6399d..d3c3e878bdf 100644
--- a/app/controllers/organizations/application_controller.rb
+++ b/app/controllers/organizations/application_controller.rb
@@ -2,7 +2,7 @@
module Organizations
class ApplicationController < ::ApplicationController
- skip_before_action :authenticate_user!
+ before_action :check_feature_flag!
before_action :organization
layout 'organization'
@@ -16,11 +16,16 @@ module Organizations
end
strong_memoize_attr :organization
- def authorize_action!(action)
- return if Feature.enabled?(:ui_for_organizations, current_user) &&
- can?(current_user, action, organization)
+ def check_feature_flag!
+ access_denied! unless Feature.enabled?(:ui_for_organizations, current_user)
+ end
+
+ def authorize_create_organization!
+ access_denied! unless can?(current_user, :create_organization)
+ end
- access_denied!
+ def authorize_read_organization!
+ access_denied! unless can?(current_user, :read_organization, organization)
end
end
end
diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb
index 650ec97c264..88c6c9b3cef 100644
--- a/app/controllers/organizations/organizations_controller.rb
+++ b/app/controllers/organizations/organizations_controller.rb
@@ -4,10 +4,20 @@ module Organizations
class OrganizationsController < ApplicationController
feature_category :cell
- before_action { authorize_action!(:read_organization) }
+ skip_before_action :authenticate_user!, except: [:index, :new]
- def show; end
+ def index; end
- def groups_and_projects; end
+ def new
+ authorize_create_organization!
+ end
+
+ def show
+ authorize_read_organization!
+ end
+
+ def groups_and_projects
+ authorize_read_organization!
+ end
end
end
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index 38839497fb6..d1ca16bd8fb 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -43,6 +43,7 @@ class PasswordsController < Devise::PasswordsController
resource.password_expires_at = nil
resource.save(validate: false) if resource.changed?
else
+ log_audit_reset_failure(@user)
track_weak_password_error(@user, self.class.name, 'create')
end
end
@@ -50,6 +51,9 @@ class PasswordsController < Devise::PasswordsController
protected
+ # overriden in EE
+ def log_audit_reset_failure(_user); end
+
def resource_from_email
email = resource_params[:email]
self.resource = resource_class.find_by_email(email)
diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb
index 02f7dbf8e6f..57e5ca4d55a 100644
--- a/app/controllers/profiles/notifications_controller.rb
+++ b/app/controllers/profiles/notifications_controller.rb
@@ -25,7 +25,7 @@ class Profiles::NotificationsController < Profiles::ApplicationController
end
def user_params
- params.require(:user).permit(:notification_email, :email_opted_in, :notified_of_own_activity)
+ params.require(:user).permit(:notification_email, :notified_of_own_activity)
end
private
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index 4b6e2f768fa..0e4d9f3c154 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -61,6 +61,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
def set_index_vars
@scopes = Gitlab::Auth.available_scopes_for(current_user)
+ @scopes.delete(Gitlab::Auth::K8S_PROXY_SCOPE) unless Feature.enabled?(:k8s_proxy_pat, current_user)
@active_access_tokens = active_access_tokens
end
diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb
index 3e8555a4ed1..931070ecdd4 100644
--- a/app/controllers/profiles/preferences_controller.rb
+++ b/app/controllers/profiles/preferences_controller.rb
@@ -55,6 +55,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:gitpod_enabled,
:render_whitespace_in_code,
:project_shortcut_buttons,
+ :keyboard_shortcuts_enabled,
:markdown_surround_selection,
:markdown_automatic_lists,
:use_new_navigation,
diff --git a/app/controllers/projects/alerting/notifications_controller.rb b/app/controllers/projects/alerting/notifications_controller.rb
index 281ac14d3ce..b596cd74b03 100644
--- a/app/controllers/projects/alerting/notifications_controller.rb
+++ b/app/controllers/projects/alerting/notifications_controller.rb
@@ -66,15 +66,11 @@ module Projects
def integration
AlertManagement::HttpIntegrationsFinder.new(
project,
- endpoint_identifier: endpoint_identifier,
+ endpoint_identifier: params[:endpoint_identifier],
active: true
).execute.first
end
- def endpoint_identifier
- params[:endpoint_identifier] || AlertManagement::HttpIntegration::LEGACY_IDENTIFIERS
- end
-
def notification_payload
@notification_payload ||= params.permit![:notification]
end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 94cd324f312..2d2712ebe4d 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -45,6 +45,8 @@ class Projects::CommitsController < Projects::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord
def signatures
+ Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/424527')
+
respond_to do |format|
format.json do
render json: {
diff --git a/app/controllers/projects/environments/sample_metrics_controller.rb b/app/controllers/projects/environments/sample_metrics_controller.rb
deleted file mode 100644
index 80344c83ab7..00000000000
--- a/app/controllers/projects/environments/sample_metrics_controller.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-class Projects::Environments::SampleMetricsController < Projects::ApplicationController
- feature_category :metrics
- urgency :low
-
- def query
- result = Metrics::SampleMetricsService.new(params[:identifier], range_start: params[:start], range_end: params[:end]).query
-
- if result
- render json: { "status": "success", "data": { "resultType": "matrix", "result": result } }
- else
- render_404
- end
- end
-end
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 127fe40b0e3..aabea122fb6 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -8,14 +8,6 @@ class Projects::EnvironmentsController < Projects::ApplicationController
layout 'project'
- before_action only: [:show] do
- push_frontend_feature_flag(:environment_details_vue, @project)
- end
-
- before_action only: [:index, :edit, :new] do
- push_frontend_feature_flag(:flux_resource_for_environment)
- end
-
before_action :authorize_read_environment!
before_action :authorize_create_environment!, only: [:new, :create]
before_action :authorize_stop_environment!, only: [:stop]
@@ -113,10 +105,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController
job = stop_actions.first if stop_actions&.count == 1
action_or_env_url =
- if job.instance_of?(::Ci::Build)
- polymorphic_url([project, job])
- elsif job.instance_of?(::Ci::Bridge)
- project_pipeline_url(project, job.pipeline_id)
+ if job
+ project_job_url(project, job)
else
project_environment_url(project, @environment)
end
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index e73e2a38149..fce7de4c0de 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -34,7 +34,7 @@ class Projects::GraphsController < Projects::ApplicationController
{
author_name: commit.author_name,
author_email: commit.author_email,
- date: commit.committed_date.strftime("%Y-%m-%d")
+ date: commit.committed_date.to_date.iso8601
}
end
diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb
index 6109e29b169..69d349b1f1d 100644
--- a/app/controllers/projects/incidents_controller.rb
+++ b/app/controllers/projects/incidents_controller.rb
@@ -12,6 +12,7 @@ class Projects::IncidentsController < Projects::ApplicationController
push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?)
push_frontend_feature_flag(:moved_mr_sidebar, project)
push_frontend_feature_flag(:move_close_into_dropdown, project)
+ push_force_frontend_feature_flag(:linked_work_items, @project&.linked_work_items_feature_flag_enabled?)
end
feature_category :incident_management
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 83947c443f4..9abcc108ace 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -62,7 +62,6 @@ class Projects::IssuesController < Projects::ApplicationController
before_action only: [:index, :service_desk] do
push_frontend_feature_flag(:or_issuable_queries, project)
push_frontend_feature_flag(:frontend_caching, project&.group)
- push_frontend_feature_flag(:new_graphql_users_autocomplete, project)
end
before_action only: :show do
@@ -73,7 +72,7 @@ class Projects::IssuesController < Projects::ApplicationController
push_frontend_feature_flag(:epic_widget_edit_confirmation, project)
push_frontend_feature_flag(:moved_mr_sidebar, project)
push_frontend_feature_flag(:move_close_into_dropdown, project)
- push_frontend_feature_flag(:action_cable_notes, project)
+ push_force_frontend_feature_flag(:linked_work_items, project.linked_work_items_feature_flag_enabled?)
end
around_action :allow_gitaly_ref_name_caching, only: [:discussions]
@@ -114,12 +113,6 @@ class Projects::IssuesController < Projects::ApplicationController
respond_to do |format|
format.html
format.atom { render layout: 'xml' }
- format.json do
- render json: {
- html: view_to_html_string("projects/issues/_issues"),
- labels: @labels.as_json(methods: :text_color)
- }
- end
end
end
@@ -282,7 +275,6 @@ class Projects::IssuesController < Projects::ApplicationController
def service_desk
@issues = @issuables
- @users.push(User.support_bot)
end
protected
@@ -433,7 +425,7 @@ class Projects::IssuesController < Projects::ApplicationController
if service_desk?
options.reject! { |key| key == 'author_username' || key == 'author_id' }
- options[:author_id] = User.support_bot
+ options[:author_id] = Users::Internal.support_bot
end
options
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index 4e0b304a2ee..802ffd99e41 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -8,8 +8,8 @@ class Projects::JobsController < Projects::ApplicationController
urgency :low, [:index, :show, :trace, :retry, :play, :cancel, :unschedule, :erase, :raw]
- before_action :find_job_as_build, except: [:index, :play, :retry]
- before_action :find_job_as_processable, only: [:play, :retry]
+ before_action :find_job_as_build, except: [:index, :play, :retry, :show]
+ before_action :find_job_as_processable, only: [:play, :retry, :show]
before_action :authorize_read_build_trace!, only: [:trace, :raw]
before_action :authorize_read_build!
before_action :authorize_update_build!,
@@ -27,17 +27,13 @@ class Projects::JobsController < Projects::ApplicationController
feature_category :continuous_integration
urgency :low
- def index
- # We need all builds for tabs counters
- @all_builds = Ci::JobsFinder.new(current_user: current_user, project: @project).execute
-
- @scope = params[:scope]
- @builds = Ci::JobsFinder.new(current_user: current_user, project: @project, params: params).execute
- @builds = @builds.eager_load_everything
- @builds = @builds.page(params[:page]).per(30).without_count
- end
+ def index; end
def show
+ if @build.instance_of?(::Ci::Bridge)
+ redirect_to project_pipeline_path(@build.downstream_pipeline.project, @build.downstream_pipeline.id)
+ end
+
respond_to do |format|
format.html
format.json do
@@ -74,6 +70,8 @@ class Projects::JobsController < Projects::ApplicationController
end
def retry
+ Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/424184')
+
response = Ci::RetryJobService.new(project, current_user).execute(@build)
if response.success?
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 67cff16a76b..e62f912e0f7 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -155,7 +155,10 @@ class Projects::LabelsController < Projects::ApplicationController
protected
def label_params
- params.require(:label).permit(:title, :description, :color)
+ allowed = [:title, :description, :color]
+ allowed << :lock_on_merge if @project.supports_lock_on_merge?
+
+ params.require(:label).permit(allowed)
end
def label
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index 6d1b1ced4eb..81ff6c215f9 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -14,6 +14,18 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
private
+ # Normally the methods with `check_(\w+)_available!` pattern are
+ # handled by the `method_missing` defined in `ProjectsController::ApplicationController`
+ # but that logic does not take the member roles into account, therefore, we handle this
+ # case here manually.
+ def check_merge_requests_available!
+ render_404 if project_policy.merge_requests_disabled?
+ end
+
+ def project_policy
+ ProjectPolicy.new(current_user, project)
+ end
+
def merge_request
@issuable =
@merge_request ||=
diff --git a/app/controllers/projects/merge_requests/conflicts_controller.rb b/app/controllers/projects/merge_requests/conflicts_controller.rb
index 66a358963e2..26f4286233a 100644
--- a/app/controllers/projects/merge_requests/conflicts_controller.rb
+++ b/app/controllers/projects/merge_requests/conflicts_controller.rb
@@ -67,7 +67,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
flash[:notice] = _('All merge conflicts were resolved. The merge request can now be merged.')
- render json: { redirect_to: project_merge_request_url(@project, @merge_request, resolved_conflicts: true) }
+ render json: { redirect_to: project_merge_request_path(@project, @merge_request, resolved_conflicts: true) }
rescue Gitlab::Git::Conflict::Resolver::ResolutionError => e
render status: :bad_request, json: { message: e.message }
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 30168558eff..53fd7256b19 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -45,12 +45,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:sast_reports_in_inline_diff, project)
push_frontend_feature_flag(:mr_experience_survey, project)
push_frontend_feature_flag(:saved_replies, current_user)
- push_frontend_feature_flag(:code_quality_inline_drawer, project)
push_force_frontend_feature_flag(:summarize_my_code_review, summarize_my_code_review_enabled?)
push_frontend_feature_flag(:mr_activity_filters, current_user)
- push_frontend_feature_flag(:review_apps_redeploy_mr_widget, project)
push_frontend_feature_flag(:ci_job_failures_in_mr, project)
- push_frontend_feature_flag(:action_cable_notes, project)
+ push_frontend_feature_flag(:mr_pipelines_graphql, project)
end
before_action only: [:edit] do
@@ -106,11 +104,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
respond_to do |format|
format.html
format.atom { render layout: 'xml' }
- format.json do
- render json: {
- html: view_to_html_string("projects/merge_requests/_merge_requests")
- }
- end
end
end
@@ -389,20 +382,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
private
- # NOTE: Remove this disable with add_prepared_state_to_mr FF removal
- # rubocop: disable Metrics/AbcSize
def show_merge_request
close_merge_request_if_no_source_project
@merge_request.check_mergeability(async: true)
- # NOTE: Remove the created_at check when removing the FF check
- if ::Feature.enabled?(:add_prepared_state_to_mr, @merge_request.project) &&
- @merge_request.created_at < 5.minutes.ago &&
- !@merge_request.prepared?
-
- @merge_request.prepare
- end
-
respond_to do |format|
format.html do
# use next to appease Rubocop
@@ -446,7 +429,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
end
end
- # rubocop: enable Metrics/AbcSize
def render_html_page
preload_assignees_for_render(@merge_request)
diff --git a/app/controllers/projects/mirrors_controller.rb b/app/controllers/projects/mirrors_controller.rb
index acbd26cbdf6..a24273488fb 100644
--- a/app/controllers/projects/mirrors_controller.rb
+++ b/app/controllers/projects/mirrors_controller.rb
@@ -81,6 +81,7 @@ class Projects::MirrorsController < Projects::ApplicationController
only_protected_branches
keep_divergent_refs
auth_method
+ user
password
ssh_known_hosts
regenerate_ssh_private_key
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 7fcdf220bd2..3d8a787afcb 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -14,8 +14,7 @@ class Projects::NotesController < Projects::ApplicationController
feature_category :team_planning, [:index, :create, :update, :destroy, :delete_attachment, :toggle_award_emoji]
feature_category :code_review_workflow, [:resolve, :unresolve, :outdated_line_change]
- urgency :medium, [:index]
- urgency :low, [:create, :update, :destroy, :resolve, :unresolve, :toggle_award_emoji, :outdated_line_change]
+ urgency :low
override :feature_category
def feature_category
diff --git a/app/controllers/projects/pages_controller.rb b/app/controllers/projects/pages_controller.rb
index 02579cd4283..5b32eb8e58e 100644
--- a/app/controllers/projects/pages_controller.rb
+++ b/app/controllers/projects/pages_controller.rb
@@ -65,7 +65,15 @@ class Projects::PagesController < Projects::ApplicationController
end
def project_params_attributes
- [:pages_https_only, { project_setting_attributes: [:pages_unique_domain_enabled] }]
+ [
+ :pages_https_only,
+ { project_setting_attributes: project_setting_attributes }
+ ]
+ end
+
+ # overridden in EE
+ def project_setting_attributes
+ [:pages_unique_domain_enabled]
end
end
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
index 42b6d83ee85..83a64579446 100644
--- a/app/controllers/projects/pipeline_schedules_controller.rb
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -9,7 +9,6 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
before_action :authorize_create_pipeline_schedule!, only: [:new, :create]
before_action :authorize_update_pipeline_schedule!, only: [:edit, :update]
before_action :authorize_admin_pipeline_schedule!, only: [:take_ownership, :destroy]
- before_action :push_schedule_feature_flag, only: [:index, :new, :edit]
feature_category :continuous_integration
urgency :low
@@ -120,8 +119,4 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
def authorize_admin_pipeline_schedule!
return access_denied! unless can?(current_user, :admin_pipeline_schedule, schedule)
end
-
- def push_schedule_feature_flag
- push_frontend_feature_flag(:pipeline_schedules_vue, @project)
- end
end
diff --git a/app/controllers/projects/pipelines/tests_controller.rb b/app/controllers/projects/pipelines/tests_controller.rb
index d77cf095a4f..4b522c88023 100644
--- a/app/controllers/projects/pipelines/tests_controller.rb
+++ b/app/controllers/projects/pipelines/tests_controller.rb
@@ -50,7 +50,7 @@ module Projects
end
def test_suite
- suite = builds.sum do |build|
+ suite = builds.sum(Gitlab::Ci::Reports::TestSuite.new) do |build|
test_report = build.collect_test_reports!(Gitlab::Ci::Reports::TestReport.new)
test_report.get_suite(build.test_suite_name)
end
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index a96ee2215c2..036ea45cc78 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -3,7 +3,6 @@
class Projects::PipelinesController < Projects::ApplicationController
include ::Gitlab::Utils::StrongMemoize
include ProductAnalyticsTracking
- include ProductAnalyticsTracking
include ProjectStatsRefreshConflictsGuard
urgency :low, [
@@ -34,9 +33,9 @@ class Projects::PipelinesController < Projects::ApplicationController
label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly',
destinations: %i[redis_hll snowplow]
- track_event :charts, name: 'p_analytics_ci_cd_pipelines', conditions: -> { should_track_ci_cd_pipelines? }
- track_event :charts, name: 'p_analytics_ci_cd_deployment_frequency', conditions: -> { should_track_ci_cd_deployment_frequency? }
- track_event :charts, name: 'p_analytics_ci_cd_lead_time', conditions: -> { should_track_ci_cd_lead_time? }
+ track_internal_event :charts, name: 'p_analytics_ci_cd_pipelines', conditions: -> { should_track_ci_cd_pipelines? }
+ track_internal_event :charts, name: 'p_analytics_ci_cd_deployment_frequency', conditions: -> { should_track_ci_cd_deployment_frequency? }
+ track_internal_event :charts, name: 'p_analytics_ci_cd_lead_time', conditions: -> { should_track_ci_cd_lead_time? }
track_event :charts, name: 'p_analytics_ci_cd_time_to_restore_service', conditions: -> { should_track_ci_cd_time_to_restore_service? }
track_event :charts, name: 'p_analytics_ci_cd_change_failure_rate', conditions: -> { should_track_ci_cd_change_failure_rate? }
diff --git a/app/controllers/projects/prometheus/alerts_controller.rb b/app/controllers/projects/prometheus/alerts_controller.rb
deleted file mode 100644
index 80a8dbf4729..00000000000
--- a/app/controllers/projects/prometheus/alerts_controller.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-module Projects
- module Prometheus
- class AlertsController < Projects::ApplicationController
- respond_to :json
-
- protect_from_forgery except: [:notify]
-
- skip_before_action :project, only: [:notify]
-
- prepend_before_action :repository, :project_without_auth, only: [:notify]
-
- before_action :authorize_read_prometheus_alerts!, except: [:notify]
-
- feature_category :incident_management
- urgency :low
-
- def notify
- token = extract_alert_manager_token(request)
- result = notify_service.execute(token)
-
- head result.http_status
- end
-
- private
-
- def notify_service
- Projects::Prometheus::Alerts::NotifyService
- .new(project, params.permit!)
- end
-
- def extract_alert_manager_token(request)
- Doorkeeper::OAuth::Token.from_bearer_authorization(request)
- end
-
- def project_without_auth
- @project ||= Project
- .find_by_full_path("#{params[:namespace_id]}/#{params[:project_id]}")
- end
- end
- end
-end
diff --git a/app/controllers/projects/service_desk_controller.rb b/app/controllers/projects/service_desk_controller.rb
index b1e30e7a45b..ca3cecf5949 100644
--- a/app/controllers/projects/service_desk_controller.rb
+++ b/app/controllers/projects/service_desk_controller.rb
@@ -36,7 +36,7 @@ class Projects::ServiceDeskController < Projects::ApplicationController
service_desk_settings = project.service_desk_setting
{
- service_desk_address: project.service_desk_address,
+ service_desk_address: project.service_desk_system_address,
service_desk_enabled: project.service_desk_enabled,
issue_template_key: service_desk_settings&.issue_template_key,
template_file_missing: service_desk_settings&.issue_template_missing?,
diff --git a/app/controllers/projects/tracing_controller.rb b/app/controllers/projects/tracing_controller.rb
deleted file mode 100644
index 45e773bf62b..00000000000
--- a/app/controllers/projects/tracing_controller.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module Projects
- class TracingController < Projects::ApplicationController
- include ::Observability::ContentSecurityPolicy
-
- feature_category :tracing
-
- before_action :check_tracing_enabled
-
- def index; end
-
- def show
- @trace_id = params[:id]
- end
-
- private
-
- def check_tracing_enabled
- render_404 unless Gitlab::Observability.tracing_enabled?(project)
- end
- end
-end
diff --git a/app/controllers/projects/work_items_controller.rb b/app/controllers/projects/work_items_controller.rb
index 7da31c199a1..c3986be31b0 100644
--- a/app/controllers/projects/work_items_controller.rb
+++ b/app/controllers/projects/work_items_controller.rb
@@ -12,6 +12,7 @@ class Projects::WorkItemsController < Projects::ApplicationController
push_force_frontend_feature_flag(:work_items_mvc, project&.work_items_mvc_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?)
push_force_frontend_feature_flag(:saved_replies, current_user)
+ push_force_frontend_feature_flag(:linked_work_items, project&.linked_work_items_feature_flag_enabled?)
end
feature_category :team_planning
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 2ad0f11dc91..6a246219f7d 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -46,6 +46,7 @@ class ProjectsController < Projects::ApplicationController
push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_mvc, @project&.work_items_mvc_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?)
+ push_force_frontend_feature_flag(:linked_work_items, @project&.linked_work_items_feature_flag_enabled?)
end
layout :determine_layout
diff --git a/app/controllers/pwa_controller.rb b/app/controllers/pwa_controller.rb
index bb47bdc8050..8de1b10e1f1 100644
--- a/app/controllers/pwa_controller.rb
+++ b/app/controllers/pwa_controller.rb
@@ -6,7 +6,7 @@ class PwaController < ApplicationController # rubocop:disable Gitlab/NamespacedC
feature_category :navigation
urgency :low
- skip_before_action :authenticate_user!, :required_signup_info
+ skip_before_action :authenticate_user!
def manifest
end
diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb
index 68f8248d114..f7a601ec0bd 100644
--- a/app/controllers/registrations/welcome_controller.rb
+++ b/app/controllers/registrations/welcome_controller.rb
@@ -8,7 +8,9 @@ module Registrations
include ::Gitlab::Utils::StrongMemoize
layout 'minimal'
- skip_before_action :required_signup_info, :check_two_factor_requirement
+ # TODO: Once this is an ee + SaaS only feature, we can remove this.
+ # To be completed in https://gitlab.com/gitlab-org/gitlab/-/issues/411858
+ skip_before_action :check_two_factor_requirement
helper_method :welcome_update_params
helper_method :onboarding_status
@@ -43,7 +45,7 @@ module Registrations
end
def completed_welcome_step?
- current_user.role.present? && !current_user.setup_for_company.nil?
+ !current_user.setup_for_company.nil?
end
def update_params
@@ -61,9 +63,7 @@ module Registrations
end
def update_success_path
- if onboarding_status.invite_with_tasks_to_be_done?
- issues_dashboard_path(assignee_username: current_user.username)
- elsif onboarding_status.continue_full_onboarding? # trials/regular registration on .com
+ if onboarding_status.continue_full_onboarding? # trials/regular registration on .com
signup_onboarding_path
elsif onboarding_status.single_invite? # invites w/o tasks due to order
flash[:notice] = helpers.invite_accepted_notice(onboarding_status.last_invited_member)
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index d8064bbbe82..a8b5ca81f49 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -12,6 +12,8 @@ class RegistrationsController < Devise::RegistrationsController
include PreferredLanguageSwitcher
include Gitlab::Tracking::Helpers::WeakPasswordErrorEvent
include SkipsAlreadySignedInMessage
+ include Gitlab::RackLoadBalancingHelpers
+ include ::Gitlab::Utils::StrongMemoize
layout 'devise'
@@ -46,7 +48,6 @@ class RegistrationsController < Devise::RegistrationsController
accept_pending_invitations if new_user.persisted?
persist_accepted_terms_if_required(new_user)
- set_role_required(new_user)
send_custom_confirmation_instructions
track_weak_password_error(new_user, self.class.name, 'create')
@@ -89,10 +90,6 @@ class RegistrationsController < Devise::RegistrationsController
Users::RespondToTermsService.new(new_user, terms).execute(accepted: true)
end
- def set_role_required(new_user)
- new_user.set_role_required! if new_user.persisted?
- end
-
def destroy_confirmation_valid?
if current_user.confirm_deletion_with_password?
current_user.valid_password?(params[:password])
@@ -138,7 +135,7 @@ class RegistrationsController < Devise::RegistrationsController
if identity_verification_enabled?
session[:verification_user_id] = resource.id # This is needed to find the user on the identity verification page
- User.sticking.stick_or_unstick_request(request.env, :user, resource.id)
+ load_balancer_stick_request(::User, :user, resource.id)
return identity_verification_redirect_path
end
@@ -251,6 +248,7 @@ class RegistrationsController < Devise::RegistrationsController
sign_up_params[:email] == invite_email
end
+ strong_memoize_attr :registered_with_invite_email?
def load_recaptcha
Gitlab::Recaptcha.load_configurations!
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 6c1d9a20570..d247490402f 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -35,10 +35,6 @@ class SearchController < ApplicationController
update_scope_for_code_search
end
- before_action only: :show do
- push_frontend_feature_flag(:search_projects_hide_archived, current_user)
- end
-
rescue_from ActiveRecord::QueryCanceled, with: :render_timeout
layout 'search'
diff --git a/app/controllers/sent_notifications_controller.rb b/app/controllers/sent_notifications_controller.rb
index 6c5e709a98a..4f61088ab17 100644
--- a/app/controllers/sent_notifications_controller.rb
+++ b/app/controllers/sent_notifications_controller.rb
@@ -29,7 +29,7 @@ class SentNotificationsController < ApplicationController
def unsubscribe_and_redirect
noteable.unsubscribe(@sent_notification.recipient, @sent_notification.project)
- if noteable.is_a?(Issue) && @sent_notification.recipient_id == User.support_bot.id
+ if noteable.is_a?(Issue) && @sent_notification.recipient_id == Users::Internal.support_bot.id
noteable.unsubscribe_email_participant(noteable.external_author)
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 66ace16400a..afbadc7f4ac 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -16,6 +16,8 @@ class SessionsController < Devise::SessionsController
include GoogleSyndicationCSP
include PreferredLanguageSwitcher
include SkipsAlreadySignedInMessage
+ include AcceptsPendingInvitations
+ extend ::Gitlab::Utils::Override
skip_before_action :check_two_factor_requirement, only: [:destroy]
skip_before_action :check_password_expiration, only: [:destroy]
@@ -78,6 +80,8 @@ class SessionsController < Devise::SessionsController
flash[:notice] = nil
end
+ accept_pending_invitations
+
log_audit_event(current_user, resource, with: authentication_method)
log_user_activity(current_user)
end
@@ -94,6 +98,13 @@ class SessionsController < Devise::SessionsController
private
+ override :after_pending_invitations_hook
+ def after_pending_invitations_hook
+ member = resource.members.last
+
+ store_location_for(:user, member.source.activity_path) if member
+ end
+
def captcha_enabled?
request.headers[CAPTCHA_HEADER] && helpers.recaptcha_enabled?
end
diff --git a/app/controllers/users/namespace_visits_controller.rb b/app/controllers/users/namespace_visits_controller.rb
new file mode 100644
index 00000000000..7c96d78e26e
--- /dev/null
+++ b/app/controllers/users/namespace_visits_controller.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Users
+ class NamespaceVisitsController < ApplicationController
+ feature_category :navigation
+
+ def create
+ return head :not_found unless Feature.enabled?(:server_side_frecent_namespaces, current_user)
+ return head :bad_request unless params[:type].present? && params[:id].present?
+
+ Users::TrackNamespaceVisitsWorker.perform_async(params[:type], params[:id], current_user.id, DateTime.now) # rubocop:disable CodeReuse/Worker
+ head :ok
+ end
+ end
+end
diff --git a/app/experiments/ios_specific_templates_experiment.rb b/app/experiments/ios_specific_templates_experiment.rb
index 1731fa87be8..5bd4a3d0287 100644
--- a/app/experiments/ios_specific_templates_experiment.rb
+++ b/app/experiments/ios_specific_templates_experiment.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class IosSpecificTemplatesExperiment < ApplicationExperiment
+ control
+
before_run(if: :skip_experiment) { throw(:abort) } # rubocop:disable Cop/BanCatchThrow
private
diff --git a/app/finders/abuse_reports_finder.rb b/app/finders/abuse_reports_finder.rb
index 43cebd16d92..ee14372fcd9 100644
--- a/app/finders/abuse_reports_finder.rb
+++ b/app/finders/abuse_reports_finder.rb
@@ -17,6 +17,8 @@ class AbuseReportsFinder
end
def execute
+ @reports = reports.with_labels if Feature.enabled?(:abuse_report_labels)
+
filter_reports
aggregate_reports
sort_reports
@@ -27,30 +29,16 @@ class AbuseReportsFinder
private
def filter_reports
- if Feature.disabled?(:abuse_reports_list)
- filter_by_user_id
- return
- end
-
filter_by_status
filter_by_user
filter_by_reporter
filter_by_category
end
- def filter_by_user_id
- return unless params[:user_id].present?
-
- @reports = @reports.by_user_id(params[:user_id])
- end
-
def filter_by_status
return unless params[:status].present?
- status = params[:status]
- status = STATUS_OPEN unless status.in?(AbuseReport.statuses.keys)
-
- case status
+ case status_filter
when 'open'
@reports = @reports.open
when 'closed'
@@ -92,11 +80,6 @@ class AbuseReportsFinder
end
def sort_reports
- if Feature.disabled?(:abuse_reports_list)
- @reports = @reports.with_order_id_desc
- return
- end
-
# let sub_query in aggregate_reports do the sorting if sorting by number of reports
return if sort_key.in?(SORT_BY_COUNT)
@@ -107,15 +90,6 @@ class AbuseReportsFinder
User.by_username(username).pick(:id)
end
- def status_open?
- return unless Feature.enabled?(:abuse_reports_list) && params[:status].present?
-
- status = params[:status]
- status = STATUS_OPEN unless status.in?(AbuseReport.statuses.keys)
-
- status == STATUS_OPEN
- end
-
def aggregate_reports
if status_open?
sort_by_count = sort_key.in?(SORT_BY_COUNT)
@@ -124,4 +98,19 @@ class AbuseReportsFinder
@reports
end
+
+ def status_filter
+ @status_filter ||=
+ if params[:status].in?(AbuseReport.statuses.keys)
+ params[:status]
+ else
+ STATUS_OPEN
+ end
+ end
+
+ def status_open?
+ return false if params[:status].blank?
+
+ status_filter == STATUS_OPEN
+ end
end
diff --git a/app/finders/ci/jobs_finder.rb b/app/finders/ci/jobs_finder.rb
index 8620dff6973..efacd8143bc 100644
--- a/app/finders/ci/jobs_finder.rb
+++ b/app/finders/ci/jobs_finder.rb
@@ -5,8 +5,8 @@ module Ci
include Gitlab::Allowable
def initialize(current_user:, pipeline: nil, project: nil, runner: nil, params: {}, type: ::Ci::Build)
- @pipeline = pipeline
@current_user = current_user
+ @pipeline = pipeline
@project = project
@runner = runner
@params = params
@@ -16,8 +16,7 @@ module Ci
def execute
builds = init_collection.order_id_desc
- builds = filter_by_with_artifacts(builds)
- filter_by_scope(builds)
+ filter_builds(builds)
rescue Gitlab::Access::AccessDeniedError
type.none
end
@@ -58,6 +57,13 @@ module Ci
params[:include_retried] ? jobs_scope : jobs_scope.latest
end
+ # Overriden in EE
+ def filter_builds(builds)
+ builds = filter_by_with_artifacts(builds)
+ builds = filter_by_runner_types(builds)
+ filter_by_scope(builds)
+ end
+
def filter_by_scope(builds)
return filter_by_statuses!(builds) if params[:scope].is_a?(Array)
@@ -73,12 +79,21 @@ module Ci
end
end
+ def filter_by_runner_types(builds)
+ return builds unless use_runner_type_filter?
+
+ builds.with_runner_type(params[:runner_type])
+ end
+
+ # Overriden in EE
+ def use_runner_type_filter?
+ params[:runner_type].present? && Feature.enabled?(:admin_jobs_filter_runner_type, project, type: :ops)
+ end
+
def filter_by_with_artifacts(builds)
- if params[:with_artifacts]
- builds.with_any_artifacts
- else
- builds
- end
+ return builds.with_any_artifacts if params[:with_artifacts]
+
+ builds
end
def filter_by_statuses!(builds)
@@ -100,3 +115,5 @@ module Ci
end
end
end
+
+Ci::JobsFinder.prepend_mod
diff --git a/app/finders/ci/runners_finder.rb b/app/finders/ci/runners_finder.rb
index 630be17e64b..331f732bff7 100644
--- a/app/finders/ci/runners_finder.rb
+++ b/app/finders/ci/runners_finder.rb
@@ -24,9 +24,6 @@ module Ci
request_tag_list!
@runners
-
- rescue Gitlab::Access::AccessDeniedError
- Ci::Runner.none
end
def sort_key
diff --git a/app/finders/ci/triggers_finder.rb b/app/finders/ci/triggers_finder.rb
new file mode 100644
index 00000000000..a4b429539d6
--- /dev/null
+++ b/app/finders/ci/triggers_finder.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Ci
+ class TriggersFinder
+ def initialize(current_user, project)
+ @current_user = current_user
+ @project = project
+ end
+
+ def execute
+ return Ci::Trigger.none unless Ability.allowed?(@current_user, :admin_build, @project)
+
+ @project.triggers
+ end
+ end
+end
diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb
index 639db58b00d..0336135835a 100644
--- a/app/finders/group_members_finder.rb
+++ b/app/finders/group_members_finder.rb
@@ -20,6 +20,8 @@ class GroupMembersFinder < UnionFinder
# search: string
# created_after: datetime
# created_before: datetime
+ # non_invite: boolean
+ # with_custom_role: boolean
attr_reader :params
def initialize(group, user = nil, params: {})
@@ -34,7 +36,10 @@ class GroupMembersFinder < UnionFinder
Group.shared_into_ancestors(group).public_or_visible_to_user(user)
end
- members = all_group_members(groups, shared_from_groups).distinct_on_user_with_max_access_level
+ members = all_group_members(groups, shared_from_groups)
+ if static_roles_only?
+ members = members.distinct_on_user_with_max_access_level
+ end
filter_members(members)
end
@@ -70,7 +75,10 @@ class GroupMembersFinder < UnionFinder
members = filter_by_user_type(members)
members = apply_additional_filters(members)
- by_created_at(members)
+ members = by_created_at(members)
+ members = members.non_invite if params[:non_invite]
+
+ members
end
def can_manage_members
@@ -137,6 +145,10 @@ class GroupMembersFinder < UnionFinder
# overridden in EE to include additional filtering conditions.
members
end
+
+ def static_roles_only?
+ true
+ end
end
GroupMembersFinder.prepend_mod_with('GroupMembersFinder')
diff --git a/app/finders/groups/accepting_group_transfers_finder.rb b/app/finders/groups/accepting_group_transfers_finder.rb
index c95318d0098..e757ecff015 100644
--- a/app/finders/groups/accepting_group_transfers_finder.rb
+++ b/app/finders/groups/accepting_group_transfers_finder.rb
@@ -14,7 +14,9 @@ module Groups
return Group.none unless can_transfer_group?
items = find_all_groups
- items = by_search(items)
+
+ # Search will perform an ORDER BY to ensure exact matches are returned first.
+ return by_search(items, exact_matches_first: true) if params[:search].present?
sort(items)
end
diff --git a/app/finders/groups/base.rb b/app/finders/groups/base.rb
index 9d2f9f60a63..26d2ad85fd4 100644
--- a/app/finders/groups/base.rb
+++ b/app/finders/groups/base.rb
@@ -8,10 +8,10 @@ module Groups
items.reorder(Group.arel_table[:path].asc, Group.arel_table[:id].asc) # rubocop: disable CodeReuse/ActiveRecord
end
- def by_search(items)
+ def by_search(items, exact_matches_first: false)
return items if params[:search].blank?
- items.search(params[:search], include_parents: true)
+ items.search(params[:search], include_parents: true, exact_matches_first: exact_matches_first)
end
end
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index bbbf14bb0d0..93b7292bb69 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -48,7 +48,7 @@ class IssuableFinder
requires_cross_project_access unless: -> { params.project? }
FULL_TEXT_SEARCH_TERM_PATTERN = '[\u0000-\u02FF\u1E00-\u1EFF\u2070-\u218F]*'
- FULL_TEXT_SEARCH_TERM_REGEX = /\A#{FULL_TEXT_SEARCH_TERM_PATTERN}\z/.freeze
+ FULL_TEXT_SEARCH_TERM_REGEX = /\A#{FULL_TEXT_SEARCH_TERM_PATTERN}\z/
NEGATABLE_PARAMS_HELPER_KEYS = %i[project_id scope status include_subgroups].freeze
attr_accessor :current_user, :params
diff --git a/app/finders/organizations/groups_finder.rb b/app/finders/organizations/groups_finder.rb
new file mode 100644
index 00000000000..2b59a3106a3
--- /dev/null
+++ b/app/finders/organizations/groups_finder.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+# Organizations::GroupsFinder
+#
+# Used to find Groups within an Organization
+module Organizations
+ class GroupsFinder
+ # @param organization [Organizations::Organization]
+ # @param current_user [User]
+ # @param params [{ sort: { field: [String], direction: [String] }, search: [String] }]
+ def initialize(organization:, current_user:, params: {})
+ @organization = organization
+ @current_user = current_user
+ @params = params
+ end
+
+ def execute
+ return Group.none if organization.nil? || !authorized?
+
+ filter_groups(all_accessible_groups)
+ .then { |groups| sort(groups) }
+ .then(&:with_route)
+ end
+
+ private
+
+ attr_reader :organization, :params, :current_user
+
+ def all_accessible_groups
+ current_user.authorized_groups.in_organization(organization)
+ end
+
+ def filter_groups(groups)
+ by_search(groups)
+ end
+
+ def by_search(groups)
+ return groups unless params[:search].present?
+
+ groups.search(params[:search])
+ end
+
+ def sort(groups)
+ return default_sort_order(groups) if params[:sort].blank?
+
+ field = params[:sort][:field]
+ direction = params[:sort][:direction]
+ groups.reorder(field => direction) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ def default_sort_order(groups)
+ groups.sort_by_attribute('name_asc')
+ end
+
+ def authorized?
+ Ability.allowed?(current_user, :read_organization, organization)
+ end
+ end
+end
diff --git a/app/finders/organizations/organization_users_finder.rb b/app/finders/organizations/organization_users_finder.rb
new file mode 100644
index 00000000000..899cda7487c
--- /dev/null
+++ b/app/finders/organizations/organization_users_finder.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+# Organizations::OrganizationUsersFinder
+#
+# Used to find Users of an Organization
+module Organizations
+ class OrganizationUsersFinder
+ # @param organization [Organizations::Organization]
+ # @param current_user [User]
+ def initialize(organization:, current_user:)
+ @organization = organization
+ @current_user = current_user
+ end
+
+ def execute
+ return User.none if organization.nil? || !authorized?
+
+ all_organization_users
+ end
+
+ private
+
+ attr_reader :organization, :current_user
+
+ def all_organization_users
+ organization.organization_users
+ end
+
+ def authorized?
+ Ability.allowed?(current_user, :read_organization_user, organization)
+ end
+ end
+end
diff --git a/app/finders/packages/npm/packages_for_user_finder.rb b/app/finders/packages/npm/packages_for_user_finder.rb
new file mode 100644
index 00000000000..f42e49f9184
--- /dev/null
+++ b/app/finders/packages/npm/packages_for_user_finder.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Packages
+ module Npm
+ class PackagesForUserFinder < ::Packages::GroupOrProjectPackageFinder
+ def execute
+ packages
+ end
+
+ private
+
+ def packages
+ base.npm
+ .with_name(@params[:package_name])
+ end
+ end
+ end
+end
diff --git a/app/finders/packages/nuget/package_finder.rb b/app/finders/packages/nuget/package_finder.rb
index 064698d3c37..684b99f8647 100644
--- a/app/finders/packages/nuget/package_finder.rb
+++ b/app/finders/packages/nuget/package_finder.rb
@@ -32,8 +32,7 @@ module Packages
result
.with_nuget_version_or_normalized_version(
@params[:package_version],
- with_normalized: Feature.enabled?(:nuget_normalized_version, @project_or_group) &&
- client_forces_normalized_version?
+ with_normalized: client_forces_normalized_version?
)
end
diff --git a/app/finders/repositories/changelog_commits_finder.rb b/app/finders/repositories/changelog_commits_finder.rb
index b80b8e94e59..863a1186205 100644
--- a/app/finders/repositories/changelog_commits_finder.rb
+++ b/app/finders/repositories/changelog_commits_finder.rb
@@ -21,7 +21,7 @@ module Repositories
COMMITS_PER_PAGE = 1024
# The regex to use for extracting the SHA of a reverted commit.
- REVERT_REGEX = /^This reverts commit (?<sha>[0-9a-f]{40})/i.freeze
+ REVERT_REGEX = /^This reverts commit (?<sha>[0-9a-f]{40})/i
# The `project` argument specifies the project for which to obtain the
# commits.
diff --git a/app/finders/work_items/namespace_work_items_finder.rb b/app/finders/work_items/namespace_work_items_finder.rb
index aad99d710b6..da6437e0907 100644
--- a/app/finders/work_items/namespace_work_items_finder.rb
+++ b/app/finders/work_items/namespace_work_items_finder.rb
@@ -2,19 +2,14 @@
module WorkItems
class NamespaceWorkItemsFinder < WorkItemsFinder
+ FilterNotAvailableError = Class.new(ArgumentError)
+
def initialize(...)
super
self.parent_param = namespace
end
- def execute
- items = init_collection
- items = by_namespace(items)
-
- sort(items)
- end
-
override :with_confidentiality_access_check
def with_confidentiality_access_check
return model_class.all if params.user_can_see_all_issuables?
@@ -31,6 +26,12 @@ module WorkItems
private
+ def filter_items(items)
+ items = super(items)
+
+ by_namespace(items)
+ end
+
def by_namespace(items)
if namespace.blank? || !Ability.allowed?(current_user, "read_#{namespace.to_ability_name}".to_sym, namespace)
return klass.none
@@ -39,11 +40,23 @@ module WorkItems
items.in_namespaces(namespace)
end
+ override :by_search
+ def by_search(items)
+ return items unless search
+
+ raise FilterNotAvailableError, 'Searching is not available for work items at the namespace level yet'
+ end
+
def namespace
return if params[:namespace_id].blank?
params[:namespace_id].is_a?(Namespace) ? params[:namespace_id] : Namespace.find_by_id(params[:namespace_id])
end
strong_memoize_attr :namespace
+
+ override :by_project
+ def by_project(items)
+ items
+ end
end
end
diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb
index 0c7195c5be3..0b56d6f4a90 100644
--- a/app/graphql/gitlab_schema.rb
+++ b/app/graphql/gitlab_schema.rb
@@ -147,6 +147,12 @@ class GitlabSchema < GraphQL::Schema
global_ids.map { |gid| parse_gid(gid, ctx) }
end
+ def unauthorized_field(error)
+ return error.field.if_unauthorized if error.field.respond_to?(:if_unauthorized) && error.field.if_unauthorized
+
+ super
+ end
+
private
def max_query_complexity(ctx)
diff --git a/app/graphql/mutations/admin/abuse_report_labels/create.rb b/app/graphql/mutations/admin/abuse_report_labels/create.rb
new file mode 100644
index 00000000000..6ec96297da4
--- /dev/null
+++ b/app/graphql/mutations/admin/abuse_report_labels/create.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Admin
+ module AbuseReportLabels
+ class Create < BaseMutation
+ graphql_name 'AbuseReportLabelCreate'
+
+ field :label, Types::LabelType, null: true, description: 'Label after mutation.'
+
+ argument :title, GraphQL::Types::String, required: true, description: 'Title of the label.'
+
+ argument :color, GraphQL::Types::String, required: false, default_value: Label::DEFAULT_COLOR,
+ see: {
+ 'List of color keywords at mozilla.org' =>
+ 'https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#Color_keywords'
+ },
+ description: <<~DESC
+ The color of the label given in 6-digit hex notation with leading '#' sign
+ (for example, `#FFAABB`) or one of the CSS color names.
+ DESC
+
+ def resolve(args)
+ raise_resource_not_available_error! unless current_user.can?(:admin_all_resources)
+
+ label = ::Admin::AbuseReportLabels::CreateService.new(args).execute
+
+ {
+ label: label.persisted? ? label : nil,
+ errors: errors_on_object(label)
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/project_ci_cd_settings_update.rb b/app/graphql/mutations/ci/project_ci_cd_settings_update.rb
index 082c345adf6..7df277641bf 100644
--- a/app/graphql/mutations/ci/project_ci_cd_settings_update.rb
+++ b/app/graphql/mutations/ci/project_ci_cd_settings_update.rb
@@ -6,6 +6,7 @@ module Mutations
graphql_name 'ProjectCiCdSettingsUpdate'
include FindsProject
+ include Gitlab::Utils::StrongMemoize
authorize :admin_project
@@ -37,13 +38,11 @@ module Mutations
description: 'CI/CD settings after mutation.'
def resolve(full_path:, **args)
- project = authorized_find!(full_path)
-
if args[:job_token_scope_enabled]
raise Gitlab::Graphql::Errors::ArgumentError, 'job_token_scope_enabled can only be set to false'
end
- settings = project.ci_cd_settings
+ settings = project(full_path).ci_cd_settings
settings.update(args)
{
@@ -51,6 +50,14 @@ module Mutations
errors: errors_on_object(settings)
}
end
+
+ private
+
+ def project(full_path)
+ strong_memoize_with(:project, full_path) do
+ authorized_find!(full_path)
+ end
+ end
end
end
end
diff --git a/app/graphql/mutations/issues/bulk_update.rb b/app/graphql/mutations/issues/bulk_update.rb
index 9c9dd3cf2fc..05e83fc82bb 100644
--- a/app/graphql/mutations/issues/bulk_update.rb
+++ b/app/graphql/mutations/issues/bulk_update.rb
@@ -15,7 +15,7 @@ module Mutations
argument :parent_id, ::Types::GlobalIDType[::IssueParent],
required: true,
description: 'Global ID of the parent to which the bulk update will be scoped. ' \
- 'The parent can be a project **(FREE)** or a group **(PREMIUM)**. ' \
+ 'The parent can be a project **(FREE ALL)** or a group **(PREMIUM ALL)**. ' \
'Example `IssueParentID` are `"gid://gitlab/Project/1"` and `"gid://gitlab/Group/1"`.'
argument :ids, [::Types::GlobalIDType[::Issue]],
diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb
index 35deb9e0af8..cd02c96e000 100644
--- a/app/graphql/mutations/issues/update.rb
+++ b/app/graphql/mutations/issues/update.rb
@@ -34,7 +34,8 @@ module Mutations
argument :time_estimate, GraphQL::Types::String,
required: false,
- description: 'Estimated time to complete the issue, or `0` to remove the current estimate.'
+ description: 'Estimated time to complete the issue. ' \
+ 'Use `null` or `0` to remove the current estimate.'
def resolve(project_path:, iid:, **args)
issue = authorized_find!(project_path: project_path, iid: iid)
@@ -67,8 +68,9 @@ module Mutations
args[:remove_label_ids] = parse_label_ids(args[:remove_label_ids])
args[:label_ids] = parse_label_ids(args[:label_ids])
- unless args[:time_estimate].nil?
- args[:time_estimate] = Gitlab::TimeTrackingFormatter.parse(args[:time_estimate], keep_zero: true)
+ if args.key?(:time_estimate)
+ args[:time_estimate] =
+ args[:time_estimate].nil? ? 0 : Gitlab::TimeTrackingFormatter.parse(args[:time_estimate], keep_zero: true)
end
args
diff --git a/app/graphql/mutations/merge_requests/update.rb b/app/graphql/mutations/merge_requests/update.rb
index 470292df86c..427e07e4a70 100644
--- a/app/graphql/mutations/merge_requests/update.rb
+++ b/app/graphql/mutations/merge_requests/update.rb
@@ -28,7 +28,8 @@ module Mutations
argument :time_estimate, GraphQL::Types::String,
required: false,
- description: 'Estimated time to complete the merge request, or `0` to remove the current estimate.'
+ description: 'Estimated time to complete the merge request. ' \
+ 'Use `null` or `0` to remove the current estimate.'
def resolve(project_path:, iid:, **args)
merge_request = authorized_find!(project_path: project_path, iid: iid)
@@ -55,8 +56,9 @@ module Mutations
private
def parse_arguments(args)
- unless args[:time_estimate].nil?
- args[:time_estimate] = Gitlab::TimeTrackingFormatter.parse(args[:time_estimate], keep_zero: true)
+ if args.key?(:time_estimate)
+ args[:time_estimate] =
+ args[:time_estimate].nil? ? 0 : Gitlab::TimeTrackingFormatter.parse(args[:time_estimate], keep_zero: true)
end
args.compact
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/base.rb b/app/graphql/mutations/metrics/dashboard/annotations/base.rb
deleted file mode 100644
index ad52f84378d..00000000000
--- a/app/graphql/mutations/metrics/dashboard/annotations/base.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Mutations
- module Metrics
- module Dashboard
- module Annotations
- class Base < BaseMutation
- private
-
- # This method is defined here in order to be used by `authorized_find!` in the subclasses.
- def find_object(id:)
- GitlabSchema.object_from_id(id, expected_type: ::Metrics::Dashboard::Annotation)
- end
- end
- end
- end
- end
-end
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
index 59ddffe3aad..e544b96f679 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
@@ -70,28 +70,8 @@ module Mutations
private
- def ready?(**args)
- raise_resource_not_available_error! if Feature.enabled?(:remove_monitor_metrics)
-
- # Raise error if both cluster_id and environment_id are present or neither is present
- unless args[:cluster_id].present? ^ args[:environment_id].present?
- raise Gitlab::Graphql::Errors::ArgumentError, ANNOTATION_SOURCE_ARGUMENT_ERROR
- end
-
- super(**args)
- end
-
- def annotation_create_params(args)
- annotation_source = AnnotationSource.new(object: annotation_source(args))
-
- args[annotation_source.type] = annotation_source.object
-
- args
- end
-
- def annotation_source(args)
- annotation_source_id = args[:cluster_id] || args[:environment_id]
- authorized_find!(id: annotation_source_id)
+ def ready?(**_args)
+ raise_resource_not_available_error!
end
end
end
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/delete.rb b/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
index 61fcf8e0b13..d2f2d9a0e32 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
@@ -4,12 +4,12 @@ module Mutations
module Metrics
module Dashboard
module Annotations
- class Delete < Base
+ class Delete < BaseMutation
graphql_name 'DeleteAnnotation'
authorize :admin_metrics_dashboard_annotation
- argument :id, ::Types::GlobalIDType[::Metrics::Dashboard::Annotation],
+ argument :id, GraphQL::Types::String,
required: true,
description: 'Global ID of the annotation to delete.'
diff --git a/app/graphql/mutations/work_items/linked_items/add.rb b/app/graphql/mutations/work_items/linked_items/add.rb
index b346b074e85..e0c17a61205 100644
--- a/app/graphql/mutations/work_items/linked_items/add.rb
+++ b/app/graphql/mutations/work_items/linked_items/add.rb
@@ -9,6 +9,9 @@ module Mutations
argument :link_type, ::Types::WorkItems::RelatedLinkTypeEnum,
required: false, description: 'Type of link. Defaults to `RELATED`.'
+ argument :work_items_ids, [::Types::GlobalIDType[::WorkItem]],
+ required: true,
+ description: "Global IDs of the items to link. Maximum number of IDs you can provide: #{MAX_WORK_ITEMS}."
private
diff --git a/app/graphql/mutations/work_items/linked_items/base.rb b/app/graphql/mutations/work_items/linked_items/base.rb
index 1d8d74b02ac..a1d9bced930 100644
--- a/app/graphql/mutations/work_items/linked_items/base.rb
+++ b/app/graphql/mutations/work_items/linked_items/base.rb
@@ -10,9 +10,6 @@ module Mutations
argument :id, ::Types::GlobalIDType[::WorkItem],
required: true, description: 'Global ID of the work item.'
- argument :work_items_ids, [::Types::GlobalIDType[::WorkItem]],
- required: true,
- description: "Global IDs of the items to link. Maximum number of IDs you can provide: #{MAX_WORK_ITEMS}."
field :work_item, Types::WorkItemType,
null: true, description: 'Updated work item.'
@@ -26,7 +23,7 @@ module Mutations
if args[:work_items_ids].size > MAX_WORK_ITEMS
raise Gitlab::Graphql::Errors::ArgumentError,
format(
- _('No more than %{max_work_items} work items can be linked at the same time.'),
+ _('No more than %{max_work_items} work items can be modified at the same time.'),
max_work_items: MAX_WORK_ITEMS
)
end
@@ -50,7 +47,7 @@ module Mutations
private
def update_links(work_item, params)
- raise NotImplementedError
+ raise NotImplementedError, "#{self.class} does not implement #{__method__}"
end
end
end
diff --git a/app/graphql/mutations/work_items/linked_items/remove.rb b/app/graphql/mutations/work_items/linked_items/remove.rb
new file mode 100644
index 00000000000..078f05d2025
--- /dev/null
+++ b/app/graphql/mutations/work_items/linked_items/remove.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Mutations
+ module WorkItems
+ module LinkedItems
+ class Remove < Base
+ graphql_name 'WorkItemRemoveLinkedItems'
+ description 'Remove items linked to the work item.'
+
+ argument :work_items_ids, [::Types::GlobalIDType[::WorkItem]],
+ required: true,
+ description: "Global IDs of the items to unlink. Maximum number of IDs you can provide: #{MAX_WORK_ITEMS}."
+
+ private
+
+ def update_links(work_item, params)
+ gids = params.delete(:work_items_ids)
+ raise Gitlab::Graphql::Errors::ArgumentError, "workItemsIds cannot be empty" if gids.empty?
+
+ work_item_ids = gids.filter_map { |gid| gid.model_id.to_i }
+ ::WorkItems::RelatedWorkItemLinks::DestroyService
+ .new(work_item, current_user, { item_ids: work_item_ids })
+ .execute
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/blame_resolver.rb b/app/graphql/resolvers/blame_resolver.rb
new file mode 100644
index 00000000000..f8b985e6582
--- /dev/null
+++ b/app/graphql/resolvers/blame_resolver.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class BlameResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::Blame::BlameType, null: true
+ calls_gitaly!
+
+ argument :from_line, GraphQL::Types::Int,
+ required: false,
+ default_value: 1,
+ description: 'Range starting from the line. Cannot be less than 1 or greater than `to_line`.'
+ argument :to_line, GraphQL::Types::Int,
+ required: false,
+ default_value: 1,
+ description: 'Range ending on the line. Cannot be less than 1 or less than `to_line`.'
+
+ alias_method :blob, :object
+
+ def ready?(**args)
+ validate_line_params!(args) if feature_enabled?
+
+ super
+ end
+
+ def resolve(from_line:, to_line:)
+ return unless feature_enabled?
+
+ authorize!
+
+ Gitlab::Blame.new(blob, blob.repository.commit(blob.commit_id),
+ range: (from_line..to_line))
+ end
+
+ private
+
+ def authorize!
+ read_code? || raise_resource_not_available_error!
+ end
+
+ def read_code?
+ Ability.allowed?(current_user, :read_code, blob.repository.project)
+ end
+
+ def feature_enabled?
+ Feature.enabled?(:graphql_git_blame, blob.repository.project)
+ end
+
+ def validate_line_params!(args)
+ if args[:from_line] <= 0 || args[:to_line] <= 0
+ raise Gitlab::Graphql::Errors::ArgumentError,
+ '`from_line` and `to_line` must be greater than or equal to 1'
+ end
+
+ return unless args[:from_line] > args[:to_line]
+
+ raise Gitlab::Graphql::Errors::ArgumentError,
+ '`to_line` must be greater than or equal to `from_line`'
+ end
+ end
+end
diff --git a/app/graphql/resolvers/ci/all_jobs_resolver.rb b/app/graphql/resolvers/ci/all_jobs_resolver.rb
index 5d0193e0e1c..3012a7defa6 100644
--- a/app/graphql/resolvers/ci/all_jobs_resolver.rb
+++ b/app/graphql/resolvers/ci/all_jobs_resolver.rb
@@ -11,14 +11,24 @@ module Resolvers
required: false,
description: 'Filter jobs by status.'
- def resolve_with_lookahead(statuses: nil)
- jobs = ::Ci::JobsFinder.new(current_user: current_user, params: { scope: statuses }).execute
+ argument :runner_types, [::Types::Ci::RunnerTypeEnum],
+ required: false,
+ alpha: { milestone: '16.4' },
+ description: 'Filter jobs by runner type if ' \
+ 'feature flag `:admin_jobs_filter_runner_type` is enabled.'
+
+ def resolve_with_lookahead(**args)
+ jobs = ::Ci::JobsFinder.new(current_user: current_user, params: params_data(args)).execute
apply_lookahead(jobs)
end
private
+ def params_data(args)
+ { scope: args[:statuses], runner_type: args[:runner_types] }
+ end
+
def preloads
{
previous_stage_jobs_or_needs: [:needs, :pipeline],
@@ -32,9 +42,21 @@ module Resolvers
browse_artifacts_path: [{ project: { namespace: [:route] } }],
play_path: [{ project: { namespace: [:route] } }],
web_path: [{ project: { namespace: [:route] } }],
- tags: [:tags]
+ tags: [:tags],
+ ai_failure_analysis: [{ project: [:project_feature, :namespace] }],
+ trace: [{ project: [:namespace] }, :job_artifacts_trace]
}
end
+
+ def nested_preloads
+ super.merge({
+ trace: {
+ html_summary: [:trace_chunks]
+ }
+ })
+ end
end
end
end
+
+Resolvers::Ci::AllJobsResolver.prepend_mod
diff --git a/app/graphql/resolvers/ci/pipeline_triggers_resolver.rb b/app/graphql/resolvers/ci/pipeline_triggers_resolver.rb
index 3d6e3b3e75d..ecbae1f7b55 100644
--- a/app/graphql/resolvers/ci/pipeline_triggers_resolver.rb
+++ b/app/graphql/resolvers/ci/pipeline_triggers_resolver.rb
@@ -10,7 +10,8 @@ module Resolvers
type Types::Ci::PipelineTriggerType.connection_type, null: false
def resolve_with_lookahead
- apply_lookahead(object.triggers)
+ triggers = ::Ci::TriggersFinder.new(current_user, object).execute
+ apply_lookahead(triggers)
end
private
diff --git a/app/graphql/resolvers/ci/runner_jobs_resolver.rb b/app/graphql/resolvers/ci/runner_jobs_resolver.rb
index 9fe25a4d13d..b005702a71d 100644
--- a/app/graphql/resolvers/ci/runner_jobs_resolver.rb
+++ b/app/graphql/resolvers/ci/runner_jobs_resolver.rb
@@ -18,6 +18,8 @@ module Resolvers
alias_method :runner, :object
def resolve_with_lookahead(statuses: nil)
+ context[:job_field_authorization] = :read_build # Instruct JobType to perform field-level authorization
+
jobs = ::Ci::JobsFinder.new(current_user: current_user, runner: runner, params: { scope: statuses }).execute
apply_lookahead(jobs)
@@ -30,7 +32,7 @@ module Resolvers
previous_stage_jobs_or_needs: [:needs, :pipeline],
artifacts: [:job_artifacts],
pipeline: [:user],
- project: [{ project: [:route, { namespace: [:route] }] }],
+ project: [{ project: [:route, { namespace: [:route] }, :project_feature] }],
detailed_status: [
:metadata,
{ pipeline: [:merge_request] },
@@ -42,9 +44,19 @@ module Resolvers
play_path: [{ project: { namespace: [:route] } }],
web_path: [{ project: { namespace: [:route] } }],
short_sha: [:pipeline],
- tags: [:tags]
+ tags: [:tags],
+ ai_failure_analysis: [{ project: [:project_feature, :namespace] }],
+ trace: [{ project: [:namespace] }, :job_artifacts_trace]
}
end
+
+ def nested_preloads
+ super.merge({
+ trace: {
+ html_summary: [:trace_chunks]
+ }
+ })
+ end
end
end
end
diff --git a/app/graphql/resolvers/ci/runners_resolver.rb b/app/graphql/resolvers/ci/runners_resolver.rb
index 632655d3681..3289f1d0056 100644
--- a/app/graphql/resolvers/ci/runners_resolver.rb
+++ b/app/graphql/resolvers/ci/runners_resolver.rb
@@ -46,10 +46,16 @@ module Resolvers
::Ci::RunnersFinder
.new(current_user: current_user, params: runners_finder_params(args))
.execute)
+ rescue Gitlab::Access::AccessDeniedError
+ handle_access_denied_error!
end
protected
+ def handle_access_denied_error!
+ raise_resource_not_available_error!
+ end
+
def runners_finder_params(params)
# Give preference to paused argument over the deprecated 'active' argument
paused = params.fetch(:paused, params[:active] ? !params[:active] : nil)
@@ -85,24 +91,6 @@ module Resolvers
tag_list: [:tags]
})
end
-
- def nested_preloads
- {
- created_by: {
- creator: {
- full_path: [:route],
- web_path: [:route],
- web_url: [:route]
- }
- },
- owner_project: {
- owner_project: {
- full_path: [:route, { namespace: [:route] }],
- web_url: [:route, { namespace: [:route] }]
- }
- }
- }
- end
end
end
end
diff --git a/app/graphql/resolvers/ci/test_suite_resolver.rb b/app/graphql/resolvers/ci/test_suite_resolver.rb
index a2d3af9c664..cccf77452e3 100644
--- a/app/graphql/resolvers/ci/test_suite_resolver.rb
+++ b/app/graphql/resolvers/ci/test_suite_resolver.rb
@@ -27,7 +27,7 @@ module Resolvers
private
def load_test_suite_data(builds)
- suite = builds.sum do |build|
+ suite = builds.sum(Gitlab::Ci::Reports::TestSuite.new) do |build|
test_report = build.collect_test_reports!(Gitlab::Ci::Reports::TestReport.new)
test_report.get_suite(build.test_suite_name)
end
diff --git a/app/graphql/resolvers/codequality_reports_comparer_resolver.rb b/app/graphql/resolvers/codequality_reports_comparer_resolver.rb
new file mode 100644
index 00000000000..1c034887c0d
--- /dev/null
+++ b/app/graphql/resolvers/codequality_reports_comparer_resolver.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class CodequalityReportsComparerResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type ::Types::Security::CodequalityReportsComparerType, null: true
+
+ authorize :read_build
+
+ def resolve
+ return unless Feature.enabled?(:sast_reports_in_inline_diff, object.project)
+
+ authorize!(object.actual_head_pipeline)
+
+ object.compare_codequality_reports
+ end
+ end
+end
diff --git a/app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb b/app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb
index b967460c7ff..946f10a10fa 100644
--- a/app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb
+++ b/app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb
@@ -17,8 +17,6 @@ module Resolvers
alias_method :dashboard, :object
def resolve(**_args)
- return if Feature.enabled?(:remove_monitor_metrics)
-
[]
end
end
diff --git a/app/graphql/resolvers/namespaces/work_item_resolver.rb b/app/graphql/resolvers/namespaces/work_item_resolver.rb
new file mode 100644
index 00000000000..d49ef3f53af
--- /dev/null
+++ b/app/graphql/resolvers/namespaces/work_item_resolver.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Namespaces
+ class WorkItemResolver < Resolvers::BaseResolver
+ type ::Types::WorkItemType, null: true
+
+ argument :iid, GraphQL::Types::String, required: true, description: 'IID of the work item.'
+
+ def ready?(**args)
+ return false if Feature.disabled?(:namespace_level_work_items, resource_parent)
+
+ super
+ end
+
+ def resolve(iid:)
+ ::WorkItem.find_by_namespace_id_and_iid(resource_parent.id, iid)
+ end
+
+ private
+
+ def resource_parent
+ # The namespace could have been loaded in batch by `BatchLoader`.
+ # At this point we need the `id` of the namespace to query for work items, so
+ # make sure it's loaded and not `nil` before continuing.
+ object.respond_to?(:sync) ? object.sync : object
+ end
+ strong_memoize_attr :resource_parent
+ end
+ end
+end
diff --git a/app/graphql/resolvers/namespaces/work_items_resolver.rb b/app/graphql/resolvers/namespaces/work_items_resolver.rb
index 54bb8392071..6985a7a898a 100644
--- a/app/graphql/resolvers/namespaces/work_items_resolver.rb
+++ b/app/graphql/resolvers/namespaces/work_items_resolver.rb
@@ -2,33 +2,31 @@
module Resolvers
module Namespaces
- class WorkItemsResolver < BaseResolver
- prepend ::WorkItems::LookAheadPreloads
+ # rubocop:disable Graphql/ResolverType (inherited from Resolvers::WorkItemsResolver)
+ class WorkItemsResolver < ::Resolvers::WorkItemsResolver
+ def ready?(**args)
+ return false if Feature.disabled?(:namespace_level_work_items, resource_parent)
- type Types::WorkItemType.connection_type, null: true
-
- def resolve_with_lookahead(**args)
- return unless Feature.enabled?(:namespace_level_work_items, resource_parent)
- return WorkItem.none if resource_parent.nil?
-
- finder = ::WorkItems::NamespaceWorkItemsFinder.new(current_user, args.merge(
- namespace_id: resource_parent
- ))
+ super
+ end
- Gitlab::Graphql::Loaders::IssuableLoader.new(resource_parent, finder).batching_find_all do |q|
- apply_lookahead(q)
- end
+ override :resolve_with_lookahead
+ def resolve_with_lookahead(...)
+ super
+ rescue ::WorkItems::NamespaceWorkItemsFinder::FilterNotAvailableError => e
+ raise Gitlab::Graphql::Errors::ArgumentError, e.message
end
private
- def resource_parent
- # The project could have been loaded in batch by `BatchLoader`.
- # At this point we need the `id` of the project to query for work items, so
- # make sure it's loaded and not `nil` before continuing.
- object.respond_to?(:sync) ? object.sync : object
+ override :finder
+ def finder(args)
+ ::WorkItems::NamespaceWorkItemsFinder.new(
+ current_user,
+ args.merge(namespace_id: resource_parent)
+ )
end
- strong_memoize_attr :resource_parent
end
+ # rubocop:enable Graphql/ResolverType
end
end
diff --git a/app/graphql/resolvers/organizations/groups_resolver.rb b/app/graphql/resolvers/organizations/groups_resolver.rb
new file mode 100644
index 00000000000..0f50713b9b4
--- /dev/null
+++ b/app/graphql/resolvers/organizations/groups_resolver.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Organizations
+ class GroupsResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+ include ResolvesGroups
+
+ type Types::GroupType.connection_type, null: true
+
+ authorize :read_group
+
+ argument :search,
+ GraphQL::Types::String,
+ required: false,
+ description: 'Search query for group name or full path.',
+ alpha: { milestone: '16.4' }
+
+ argument :sort,
+ Types::Organizations::GroupSortEnum,
+ description: 'Criteria to sort organization groups by.',
+ required: false,
+ default_value: { field: 'name', direction: :asc },
+ alpha: { milestone: '16.4' }
+
+ private
+
+ def resolve_groups(**args)
+ return Group.none if Feature.disabled?(:resolve_organization_groups, context[:current_user])
+
+ ::Organizations::GroupsFinder
+ .new(organization: object, current_user: context[:current_user], params: args)
+ .execute
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/organizations/organization_resolver.rb b/app/graphql/resolvers/organizations/organization_resolver.rb
new file mode 100644
index 00000000000..9194d9a32c5
--- /dev/null
+++ b/app/graphql/resolvers/organizations/organization_resolver.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Organizations
+ class OrganizationResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ authorize :read_organization
+
+ type Types::Organizations::OrganizationType, null: true
+
+ argument :id,
+ Types::GlobalIDType[::Organizations::Organization],
+ required: true,
+ description: 'ID of the organization.'
+
+ def resolve(id:)
+ authorized_find!(id: id)
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/organizations/organization_users_resolver.rb b/app/graphql/resolvers/organizations/organization_users_resolver.rb
new file mode 100644
index 00000000000..b4790da6c0a
--- /dev/null
+++ b/app/graphql/resolvers/organizations/organization_users_resolver.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Organizations
+ class OrganizationUsersResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+ include LooksAhead
+
+ type Types::Organizations::OrganizationUserType.connection_type, null: true
+
+ authorize :read_organization_user
+
+ alias_method :organization, :object
+
+ def resolve_with_lookahead
+ authorize!(object)
+
+ apply_lookahead(organization_users)
+ end
+
+ private
+
+ def organization_users
+ ::Organizations::OrganizationUsersFinder
+ .new(organization: organization, current_user: context[:current_user])
+ .execute
+ end
+
+ def preloads
+ {
+ user: [:user]
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/work_items/linked_items_resolver.rb b/app/graphql/resolvers/work_items/linked_items_resolver.rb
index 9c71cd7c0c9..35a6974163a 100644
--- a/app/graphql/resolvers/work_items/linked_items_resolver.rb
+++ b/app/graphql/resolvers/work_items/linked_items_resolver.rb
@@ -5,10 +5,16 @@ module Resolvers
class LinkedItemsResolver < BaseResolver
alias_method :linked_items_widget, :object
+ argument :filter, Types::WorkItems::RelatedLinkTypeEnum,
+ required: false,
+ description: "Filter by link type. " \
+ "Supported values: #{Types::WorkItems::RelatedLinkTypeEnum.values.keys.to_sentence}. " \
+ 'Returns all types if omitted.'
+
type Types::WorkItems::LinkedItemType.connection_type, null: true
- def resolve
- related_work_items.map do |related_work_item|
+ def resolve(filter: nil)
+ related_work_items(filter).map do |related_work_item|
{
link_id: related_work_item.issue_link_id,
link_type: related_work_item.issue_link_type,
@@ -21,10 +27,10 @@ module Resolvers
private
- def related_work_items
+ def related_work_items(type)
return [] unless work_item.project.linked_work_items_feature_flag_enabled?
- work_item.related_issues(current_user, preload: { project: [:project_feature, :group] })
+ work_item.linked_work_items(current_user, preload: { project: [:project_feature, :group] }, link_type: type)
end
def work_item
diff --git a/app/graphql/resolvers/work_items_resolver.rb b/app/graphql/resolvers/work_items_resolver.rb
index d4f73361e05..995f54f35d8 100644
--- a/app/graphql/resolvers/work_items_resolver.rb
+++ b/app/graphql/resolvers/work_items_resolver.rb
@@ -21,13 +21,18 @@ module Resolvers
def resolve_with_lookahead(**args)
return WorkItem.none if resource_parent.nil?
- finder = ::WorkItems::WorkItemsFinder.new(current_user, prepare_finder_params(args))
-
- Gitlab::Graphql::Loaders::IssuableLoader.new(resource_parent, finder).batching_find_all { |q| apply_lookahead(q) }
+ Gitlab::Graphql::Loaders::IssuableLoader.new(
+ resource_parent,
+ finder(prepare_finder_params(args))
+ ).batching_find_all { |q| apply_lookahead(q) }
end
private
+ def finder(args)
+ ::WorkItems::WorkItemsFinder.new(current_user, args)
+ end
+
def prepare_finder_params(args)
params = super(args)
params[:iids] ||= [params.delete(:iid)].compact if params[:iid]
diff --git a/app/graphql/types/blame/blame_type.rb b/app/graphql/types/blame/blame_type.rb
new file mode 100644
index 00000000000..7e7ba14988d
--- /dev/null
+++ b/app/graphql/types/blame/blame_type.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Types
+ module Blame
+ # rubocop: disable Graphql/AuthorizeTypes
+ class BlameType < BaseObject
+ # This is presented through `Repository` that has its own authorization
+ graphql_name 'Blame'
+
+ present_using Gitlab::BlamePresenter
+
+ field :first_line, GraphQL::Types::String, null: true,
+ description: 'First line of Git Blame for given range.', calls_gitaly: true
+ field :groups, [Types::Blame::GroupsType], null: true,
+ description: 'Git Blame grouped by contiguous lines for commit.', calls_gitaly: true,
+ method: :groups_commit_data
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/blame/commit_data_type.rb b/app/graphql/types/blame/commit_data_type.rb
new file mode 100644
index 00000000000..faac34b06f4
--- /dev/null
+++ b/app/graphql/types/blame/commit_data_type.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Types
+ module Blame
+ # rubocop: disable Graphql/AuthorizeTypes
+ class CommitDataType < BaseObject
+ # This is presented through `Repository` that has its own authorization
+ graphql_name 'CommitData'
+
+ field :age_map_class, GraphQL::Types::String, null: false, description: 'CSS class for age of commit.'
+ field :author_avatar, GraphQL::Types::String, null: false, description: 'Link to author avatar.'
+ field :commit_author_link, GraphQL::Types::String, null: false, description: 'Link to the commit author.'
+ field :commit_link, GraphQL::Types::String, null: false, description: 'Link to the commit.'
+ field :project_blame_link, GraphQL::Types::String,
+ null: true, description: 'Link to blame prior to the change.'
+ field :time_ago_tooltip, GraphQL::Types::String, null: false, description: 'Time of commit.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/blame/groups_type.rb b/app/graphql/types/blame/groups_type.rb
new file mode 100644
index 00000000000..754f3f95364
--- /dev/null
+++ b/app/graphql/types/blame/groups_type.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Types
+ module Blame
+ # rubocop: disable Graphql/AuthorizeTypes
+ class GroupsType < BaseObject
+ # This is presented through `Repository` that has its own authorization
+ graphql_name 'Groups'
+
+ field :commit, Types::CommitType, null: false, description: 'Commit responsible for specified group.'
+ field :commit_data, Types::Blame::CommitDataType, null: true,
+ description: 'HTML data derived from commit needed to present blame.', calls_gitaly: true
+ field :lineno, GraphQL::Types::Int, null: false, description: 'Starting line number for the commit group.'
+ field :lines, [GraphQL::Types::String], null: false, description: 'Array of lines added for the commit group.'
+ field :span, GraphQL::Types::Int, null: false,
+ description: 'Number of contiguous lines which the blame spans for the commit group.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/ci/ci_cd_setting_type.rb b/app/graphql/types/ci/ci_cd_setting_type.rb
index 45ecbf5c084..8a49c5a6a95 100644
--- a/app/graphql/types/ci/ci_cd_setting_type.rb
+++ b/app/graphql/types/ci/ci_cd_setting_type.rb
@@ -29,6 +29,7 @@ module Types
null: true,
description: 'Whether merge pipelines are enabled.',
method: :merge_pipelines_enabled?
+ # TODO(Issue 422295): this is EE only and should be moved to the EE file
field :merge_trains_enabled,
GraphQL::Types::Boolean,
null: true,
@@ -41,3 +42,5 @@ module Types
end
end
end
+
+Types::Ci::CiCdSettingType.prepend_mod_with('Types::Ci::CiCdSettingType')
diff --git a/app/graphql/types/ci/job_base_field.rb b/app/graphql/types/ci/job_base_field.rb
new file mode 100644
index 00000000000..979f1748494
--- /dev/null
+++ b/app/graphql/types/ci/job_base_field.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ # JobBaseField ensures that only allow-listed fields can be returned without a permission check.
+ # All other fields go through a permissions check based on the :job_field_authorization value passed in the context.
+ # rubocop: disable Graphql/AuthorizeTypes
+ class JobBaseField < ::Types::BaseField
+ PUBLIC_FIELDS = %i[allow_failure duration id kind status created_at finished_at queued_at queued_duration
+ updated_at runner].freeze
+
+ attr_accessor :if_unauthorized
+
+ def initialize(**kwargs, &block)
+ @if_unauthorized = kwargs.delete(:if_unauthorized)
+
+ super
+ end
+
+ def authorized?(object, args, ctx)
+ current_user = ctx[:current_user]
+ permission = ctx[:job_field_authorization]
+
+ if permission.nil? ||
+ PUBLIC_FIELDS.include?(ctx[:current_field].original_name) ||
+ current_user.can?(permission, object)
+ return super
+ end
+
+ false
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/ci/job_failure_reason_enum.rb b/app/graphql/types/ci/job_failure_reason_enum.rb
new file mode 100644
index 00000000000..3b9c13536d6
--- /dev/null
+++ b/app/graphql/types/ci/job_failure_reason_enum.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ class JobFailureReasonEnum < BaseEnum
+ graphql_name 'CiJobFailureReason'
+
+ ::Enums::Ci::CommitStatus.failure_reasons.each_key do |reason|
+ value reason.to_s.upcase,
+ description: "A job that failed due to #{reason.to_s.tr('_', ' ')}.",
+ value: reason
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/ci/job_trace_type.rb b/app/graphql/types/ci/job_trace_type.rb
index a68e26106b8..405c640115d 100644
--- a/app/graphql/types/ci/job_trace_type.rb
+++ b/app/graphql/types/ci/job_trace_type.rb
@@ -5,13 +5,24 @@ module Types
module Ci
class JobTraceType < BaseObject
graphql_name 'CiJobTrace'
+ MAX_SIZE_KB = 16
+ MAX_SIZE_B = MAX_SIZE_KB * 1024
field :html_summary, GraphQL::Types::String, null: false,
- alpha: { milestone: '15.11' }, # As we want the option to change from 10 if needed
- description: "HTML summary containing the last 10 lines of the trace."
+ alpha: { milestone: '15.11' },
+ description: 'HTML summary that contains the tail lines of the trace. ' \
+ "Returns at most #{MAX_SIZE_KB}KB of raw bytes from the trace. " \
+ 'The returned string might start with an unexpected invalid UTF-8 code point due to truncation.' do
+ argument :last_lines, Integer,
+ required: false, default_value: 10,
+ description: 'Number of tail lines to return, up to a maximum of 100 lines.'
+ end
- def html_summary
- object.html(last_lines: 10).html_safe
+ def html_summary(last_lines:)
+ object.html(
+ last_lines: last_lines.clamp(1, 100),
+ max_size: Feature.enabled?(:graphql_job_trace_html_summary_max_size) ? MAX_SIZE_B : nil
+ ).html_safe
end
end
end
diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb
index 22eb32993c5..5956d372fe4 100644
--- a/app/graphql/types/ci/job_type.rb
+++ b/app/graphql/types/ci/job_type.rb
@@ -8,6 +8,7 @@ module Types
graphql_name 'CiJob'
present_using ::Ci::BuildPresenter
+ field_class Types::Ci::JobBaseField
connection_type_class Types::LimitedCountableConnectionType
@@ -87,10 +88,14 @@ module Types
description: 'Play path of the job.'
field :playable, GraphQL::Types::Boolean, null: false, method: :playable?,
description: 'Indicates the job can be played.'
+ field :previous_stage_jobs, Types::Ci::JobType.connection_type,
+ null: true,
+ description: 'Jobs from the previous stage.'
field :previous_stage_jobs_or_needs, Types::Ci::JobNeedUnion.connection_type,
null: true,
description: 'Jobs that must complete before the job runs. Returns `BuildNeed`, ' \
- 'which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise.'
+ 'which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise.',
+ deprecated: { reason: 'Replaced by previousStageJobs and needs fields', milestone: '16.4' }
field :ref_name, GraphQL::Types::String, null: true,
description: 'Ref name of the job.'
field :ref_path, GraphQL::Types::String, null: true,
@@ -104,7 +109,8 @@ module Types
field :scheduling_type, GraphQL::Types::String, null: true,
description: 'Type of job scheduling. Value is `dag` if the job uses the `needs` keyword, and `stage` otherwise.'
field :short_sha, type: GraphQL::Types::String, null: false,
- description: 'Short SHA1 ID of the commit.'
+ description: 'Short SHA1 ID of the commit.',
+ if_unauthorized: 'Unauthorized'
field :stuck, GraphQL::Types::Boolean, null: false, method: :stuck?,
description: 'Indicates the job is stuck.'
field :trace, Types::Ci::JobTraceType, null: true,
@@ -174,17 +180,17 @@ module Types
end
def previous_stage_jobs
- BatchLoader::GraphQL.for([object.pipeline, object.stage_idx - 1]).batch(default_value: []) do |tuples, loader|
- tuples.group_by(&:first).each do |pipeline, keys|
- positions = keys.map(&:second)
+ BatchLoader::GraphQL.for([object.pipeline_id, object.stage_idx - 1]).batch(default_value: []) do |tuples, loader|
+ pipeline_ids = tuples.map(&:first).uniq
+ stage_idxs = tuples.map(&:second).uniq
- stages = pipeline.stages.by_position(positions)
+ # This query can fetch unneeded jobs when querying for more than one pipeline.
+ # It was decided that fetching and discarding the jobs is preferable to making a more complex query.
+ jobs = CommitStatus.in_pipelines(pipeline_ids).for_stage(stage_idxs).latest
+ grouped_jobs = jobs.group_by { |job| [job.pipeline_id, job.stage_idx] }
- stages.each do |stage|
- # Without `.to_a`, the memoization will only preserve the activerecord relation object. And when there is
- # a call, the SQL query will be executed again.
- loader.call([pipeline, stage.position], stage.latest_statuses.to_a)
- end
+ tuples.each do |tuple|
+ loader.call(tuple, grouped_jobs.fetch(tuple, []))
end
end
end
diff --git a/app/graphql/types/ci/pipeline_schedule_type.rb b/app/graphql/types/ci/pipeline_schedule_type.rb
index 71a1f28ea38..e2e3bd8cfbd 100644
--- a/app/graphql/types/ci/pipeline_schedule_type.rb
+++ b/app/graphql/types/ci/pipeline_schedule_type.rb
@@ -68,7 +68,10 @@ module Types
null: false, description: 'Timestamp of when the pipeline schedule was last updated.'
def ref_path
- ::Gitlab::Routing.url_helpers.project_commits_path(object.project, object.ref_for_display)
+ ref_for_display = object.ref_for_display
+ return unless ref_for_display
+
+ ::Gitlab::Routing.url_helpers.project_commits_path(object.project, ref_for_display)
end
def edit_path
diff --git a/app/graphql/types/ci/runner_job_execution_status_enum.rb b/app/graphql/types/ci/runner_job_execution_status_enum.rb
index 686ea085199..0db79c56a93 100644
--- a/app/graphql/types/ci/runner_job_execution_status_enum.rb
+++ b/app/graphql/types/ci/runner_job_execution_status_enum.rb
@@ -8,12 +8,12 @@ module Types
value 'IDLE',
description: "Runner is idle.",
value: :idle,
- deprecated: { milestone: '15.7', reason: :alpha }
+ alpha: { milestone: '15.7' }
value 'RUNNING',
description: 'Runner is executing jobs.',
value: :running,
- deprecated: { milestone: '15.7', reason: :alpha }
+ alpha: { milestone: '15.7' }
end
end
end
diff --git a/app/graphql/types/ci/runner_membership_filter_enum.rb b/app/graphql/types/ci/runner_membership_filter_enum.rb
index d59a68b427b..eb691166944 100644
--- a/app/graphql/types/ci/runner_membership_filter_enum.rb
+++ b/app/graphql/types/ci/runner_membership_filter_enum.rb
@@ -21,7 +21,7 @@ module Types
"Include all runners. This list includes runners for all projects in the group " \
"and subgroups, as well as for the parent groups and instance.",
value: :all_available,
- deprecated: { milestone: '15.5', reason: :alpha }
+ alpha: { milestone: '15.5' }
end
end
end
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 258cf1539fb..74e7f256b44 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -268,6 +268,12 @@ module Types
alpha: { milestone: '16.3' },
resolver: ::Resolvers::Namespaces::WorkItemsResolver
+ field :work_item, Types::WorkItemType,
+ resolver: Resolvers::Namespaces::WorkItemResolver,
+ alpha: { milestone: '16.4' },
+ description: 'Find a work item by IID directly associated with the group. Returns `null` if the ' \
+ '`namespace_level_work_items` feature flag is disabled.'
+
field :autocomplete_users,
null: true,
resolver: Resolvers::AutocompleteUsersResolver,
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index 4b7118d75a5..1c8a654a841 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -171,6 +171,8 @@ module Types
field :escalation_status, Types::IncidentManagement::EscalationStatusEnum, null: true,
description: 'Escalation status of the issue.'
+ field :external_author, GraphQL::Types::String, null: true, description: 'Email address of non-GitLab user reporting the issue. For guests, the email address is obfuscated.'
+
markdown_field :title_html, null: true
markdown_field :description_html, null: true
diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb
index 4848ee30950..d4fac949c93 100644
--- a/app/graphql/types/label_type.rb
+++ b/app/graphql/types/label_type.rb
@@ -18,6 +18,9 @@ module Types
description: 'Description of the label (Markdown rendered as HTML for caching).'
field :id, GraphQL::Types::ID, null: false,
description: 'Label ID.'
+ field :lock_on_merge, GraphQL::Types::Boolean, null: false,
+ description: 'Indicates this label is locked for merge requests ' \
+ 'that have been merged.'
field :text_color, GraphQL::Types::String, null: false,
description: 'Text color of the label.'
field :title, GraphQL::Types::String, null: false,
diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb
index 3fe8a05b311..4fd2b245de9 100644
--- a/app/graphql/types/merge_request_type.rb
+++ b/app/graphql/types/merge_request_type.rb
@@ -185,6 +185,8 @@ module Types
description: 'Users from whom a review has been requested.'
field :subscribed, GraphQL::Types::Boolean, method: :subscribed?, null: false, complexity: 5,
description: 'Indicates if the currently logged in user is subscribed to this merge request.'
+ field :supports_lock_on_merge, GraphQL::Types::Boolean, null: false, method: :supports_lock_on_merge?,
+ description: 'Indicates if the merge request supports locked labels.'
field :task_completion_status, Types::TaskCompletionStatus, null: false,
description: Types::TaskCompletionStatus.description
field :time_estimate, GraphQL::Types::Int, null: false,
@@ -231,6 +233,14 @@ module Types
field :prepared_at, Types::TimeType, null: true,
description: 'Timestamp of when the merge request was prepared.'
+ field :codequality_reports_comparer,
+ type: ::Types::Security::CodequalityReportsComparerType,
+ null: true,
+ alpha: { milestone: '16.4' },
+ description: 'Code quality reports comparison reported on the merge request. Returns `null` ' \
+ 'if `sast_reports_in_inline_diff` feature flag is disabled.',
+ resolver: ::Resolvers::CodequalityReportsComparerResolver
+
markdown_field :title_html, null: true
markdown_field :description_html, null: true
@@ -297,7 +307,7 @@ module Types
end
def security_auto_fix
- object.author == User.security_bot
+ object.author == ::Users::Internal.security_bot
end
def merge_user
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 957fd10690f..445f26e2fcf 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -181,6 +181,7 @@ module Types
mount_mutation Mutations::WorkItems::Export, alpha: { milestone: '15.10' }
mount_mutation Mutations::WorkItems::Convert, alpha: { milestone: '15.11' }
mount_mutation Mutations::WorkItems::LinkedItems::Add, alpha: { milestone: '16.3' }
+ mount_mutation Mutations::WorkItems::LinkedItems::Remove, alpha: { milestone: '16.3' }
mount_mutation Mutations::SavedReplies::Create
mount_mutation Mutations::SavedReplies::Update
mount_mutation Mutations::Pages::MarkOnboardingComplete
@@ -188,6 +189,7 @@ module Types
mount_mutation Mutations::Uploads::Delete
mount_mutation Mutations::Users::SetNamespaceCommitEmail
mount_mutation Mutations::WorkItems::Subscribe, alpha: { milestone: '16.3' }
+ mount_mutation Mutations::Admin::AbuseReportLabels::Create, alpha: { milestone: '16.4' }
end
end
diff --git a/app/graphql/types/organizations/group_sort_enum.rb b/app/graphql/types/organizations/group_sort_enum.rb
new file mode 100644
index 00000000000..8fb2f553539
--- /dev/null
+++ b/app/graphql/types/organizations/group_sort_enum.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Types
+ module Organizations
+ class GroupSortEnum < BaseEnum
+ graphql_name 'OrganizationGroupSort'
+ description 'Values for sorting organization groups'
+
+ sortable_fields = ['ID', 'Name', 'Path', 'Updated at', 'Created at']
+
+ sortable_fields.each do |field|
+ value "#{field.upcase.tr(' ', '_')}_ASC",
+ value: { field: field.downcase.tr(' ', '_'), direction: :asc },
+ description: "#{field} in ascending order.",
+ alpha: { milestone: '16.4' }
+
+ value "#{field.upcase.tr(' ', '_')}_DESC",
+ value: { field: field.downcase.tr(' ', '_'), direction: :desc },
+ description: "#{field} in descending order.",
+ alpha: { milestone: '16.4' }
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/organizations/organization_type.rb b/app/graphql/types/organizations/organization_type.rb
new file mode 100644
index 00000000000..cae0ef2232e
--- /dev/null
+++ b/app/graphql/types/organizations/organization_type.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Types
+ module Organizations
+ class OrganizationType < BaseObject
+ graphql_name 'Organization'
+
+ authorize :read_organization
+
+ field :groups,
+ Types::GroupType.connection_type,
+ null: false,
+ description: 'Groups within this organization that the user has access to.',
+ alpha: { milestone: '16.4' },
+ resolver: ::Resolvers::Organizations::GroupsResolver
+ field :id,
+ GraphQL::Types::ID,
+ null: false,
+ description: 'ID of the organization.',
+ alpha: { milestone: '16.4' }
+ field :name,
+ GraphQL::Types::String,
+ null: false,
+ description: 'Name of the organization.',
+ alpha: { milestone: '16.4' }
+ field :organization_users,
+ null: false,
+ description: 'Users with access to the organization.',
+ alpha: { milestone: '16.4' },
+ resolver: ::Resolvers::Organizations::OrganizationUsersResolver
+ field :path,
+ GraphQL::Types::String,
+ null: false,
+ description: 'Path of the organization.',
+ alpha: { milestone: '16.4' }
+ end
+ end
+end
diff --git a/app/graphql/types/organizations/organization_user_type.rb b/app/graphql/types/organizations/organization_user_type.rb
new file mode 100644
index 00000000000..41924586f38
--- /dev/null
+++ b/app/graphql/types/organizations/organization_user_type.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Types
+ module Organizations
+ class OrganizationUserType < BaseObject
+ graphql_name 'OrganizationUser'
+ description 'A user with access to the organization.'
+
+ include UsersHelper
+
+ authorize :read_organization_user
+
+ alias_method :organization_user, :object
+
+ field :badges,
+ [GraphQL::Types::String],
+ null: true,
+ description: 'Badges describing the user within the organization.',
+ alpha: { milestone: '16.4' }
+ field :id,
+ GraphQL::Types::ID,
+ null: false,
+ description: 'ID of the organization user.',
+ alpha: { milestone: '16.4' }
+ field :user,
+ ::Types::UserType,
+ null: false,
+ description: 'User that is associated with the organization.',
+ alpha: { milestone: '16.4' }
+
+ def badges
+ user_badges_in_admin_section(organization_user.user).pluck(:text) # rubocop:disable CodeReuse/ActiveRecord
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/permission_types/work_item.rb b/app/graphql/types/permission_types/work_item.rb
index d9946fc4ea6..40b708a7885 100644
--- a/app/graphql/types/permission_types/work_item.rb
+++ b/app/graphql/types/permission_types/work_item.rb
@@ -8,7 +8,7 @@ module Types
abilities :read_work_item, :update_work_item, :delete_work_item,
:admin_work_item, :admin_parent_link, :set_work_item_metadata,
- :create_note
+ :create_note, :admin_work_item_link
end
end
end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 38b8973034d..d02b3e4136f 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -96,6 +96,12 @@ module Types
required: true,
description: 'Global ID of the note.'
end
+ field :organization,
+ Types::Organizations::OrganizationType,
+ null: true,
+ resolver: Resolvers::Organizations::OrganizationResolver,
+ description: "Find an organization.",
+ alpha: { milestone: '16.4' }
field :package,
description: 'Find a package. This field can only be resolved for one query in any single request. Returns `null` if a package has no `default` status.',
resolver: Resolvers::PackageDetailsResolver
@@ -122,7 +128,8 @@ module Types
field :runners, Types::Ci::RunnerType.connection_type,
null: true,
resolver: Resolvers::Ci::RunnersResolver,
- description: "Find runners visible to the current user."
+ description: "Get all runners in the GitLab instance (project and shared). " \
+ "Access is restricted to users with administrator access."
field :snippets,
Types::SnippetType.connection_type,
null: true,
diff --git a/app/graphql/types/repository/blob_type.rb b/app/graphql/types/repository/blob_type.rb
index c5d6e26e94b..3959118631f 100644
--- a/app/graphql/types/repository/blob_type.rb
+++ b/app/graphql/types/repository/blob_type.rb
@@ -86,6 +86,9 @@ module Types
field :blame_path, GraphQL::Types::String, null: true,
description: 'Web path to blob blame page.'
+ field :blame, Types::Blame::BlameType, null: true,
+ description: 'Blob blame. Available only when feature flag `graphql_git_blame` is enabled.', alpha: { milestone: '16.3' }, resolver: Resolvers::BlameResolver
+
field :history_path, GraphQL::Types::String, null: true,
description: 'Web path to blob history page.'
diff --git a/app/graphql/types/security/codequality_reports_comparer/degradation_type.rb b/app/graphql/types/security/codequality_reports_comparer/degradation_type.rb
new file mode 100644
index 00000000000..fb7d722069f
--- /dev/null
+++ b/app/graphql/types/security/codequality_reports_comparer/degradation_type.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Types
+ module Security
+ module CodequalityReportsComparer
+ # rubocop: disable Graphql/AuthorizeTypes (The resolver authorizes the request)
+ class DegradationType < BaseObject
+ graphql_name 'CodequalityReportsComparerReportDegradation'
+
+ description 'Represents a degradation on the compared codequality report.'
+
+ field :description, GraphQL::Types::String,
+ null: false,
+ description: 'Description of the code quality degradation.'
+
+ field :fingerprint, GraphQL::Types::String,
+ null: false,
+ description: 'Unique fingerprint to identify the code quality degradation. For example, an MD5 hash.'
+
+ field :severity, Types::Ci::CodeQualityDegradationSeverityEnum,
+ null: false,
+ description:
+ "Severity of the code quality degradation " \
+ "(#{::Gitlab::Ci::Reports::CodequalityReports::SEVERITY_PRIORITIES.keys.map(&:upcase).join(', ')})."
+
+ field :file_path, GraphQL::Types::String,
+ null: false,
+ description: 'Relative path to the file containing the code quality degradation.'
+
+ field :line, GraphQL::Types::Int,
+ null: false,
+ description: 'Line on which the code quality degradation occurred.'
+
+ field :web_url, GraphQL::Types::String,
+ null: true,
+ description: 'URL to the file along with line number.'
+
+ field :engine_name, GraphQL::Types::String,
+ null: false,
+ description: 'Code quality plugin that reported the degradation.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/graphql/types/security/codequality_reports_comparer/report_type.rb b/app/graphql/types/security/codequality_reports_comparer/report_type.rb
new file mode 100644
index 00000000000..8a41160141a
--- /dev/null
+++ b/app/graphql/types/security/codequality_reports_comparer/report_type.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module Types
+ module Security
+ module CodequalityReportsComparer
+ # rubocop: disable Graphql/AuthorizeTypes (Parent node applies authorization)
+ class ReportType < BaseObject
+ graphql_name 'CodequalityReportsComparerReport'
+
+ description 'Represents compared code quality report.'
+
+ field :status,
+ type: CodequalityReportsComparer::StatusEnum,
+ null: false,
+ description: 'Status of report.'
+
+ field :new_errors,
+ type: [CodequalityReportsComparer::DegradationType],
+ null: false,
+ description: 'New code quality degradations.'
+
+ field :resolved_errors,
+ type: [CodequalityReportsComparer::DegradationType],
+ null: true,
+ description: 'Resolved code quality degradations.'
+
+ field :existing_errors,
+ type: [CodequalityReportsComparer::DegradationType],
+ null: true,
+ description: 'All code quality degradations.'
+
+ field :summary,
+ type: CodequalityReportsComparer::SummaryType,
+ null: false,
+ description: 'Codequality report summary.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/graphql/types/security/codequality_reports_comparer/status_enum.rb b/app/graphql/types/security/codequality_reports_comparer/status_enum.rb
new file mode 100644
index 00000000000..9cab2664db8
--- /dev/null
+++ b/app/graphql/types/security/codequality_reports_comparer/status_enum.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Types
+ module Security
+ module CodequalityReportsComparer
+ class StatusEnum < BaseEnum
+ graphql_name 'CodequalityReportsComparerReportStatus'
+ description 'Report comparison status'
+
+ value 'SUCCESS', value: 'success', description: 'Report successfully generated.'
+ value 'FAILED', value: 'failed', description: 'Report failed to generate.'
+ value 'NOT_FOUND', value: 'not_found', description: 'Head report or base report not found.'
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/security/codequality_reports_comparer/summary_type.rb b/app/graphql/types/security/codequality_reports_comparer/summary_type.rb
new file mode 100644
index 00000000000..cd4a594c193
--- /dev/null
+++ b/app/graphql/types/security/codequality_reports_comparer/summary_type.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Types
+ module Security
+ module CodequalityReportsComparer
+ # rubocop: disable Graphql/AuthorizeTypes (The resolver authorizes the request)
+ class SummaryType < BaseObject
+ graphql_name 'CodequalityReportsComparerReportSummary'
+
+ description 'Represents a summary of the compared codequality report.'
+
+ field :total,
+ type: GraphQL::Types::Int,
+ null: true,
+ description: 'Total count of code quality degradations.'
+
+ field :resolved,
+ type: GraphQL::Types::Int,
+ null: true,
+ description: 'Count of resolved code quality degradations.'
+
+ field :errored,
+ type: GraphQL::Types::Int,
+ null: true,
+ description: 'Count of code quality errors.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/graphql/types/security/codequality_reports_comparer_type.rb b/app/graphql/types/security/codequality_reports_comparer_type.rb
new file mode 100644
index 00000000000..3b0f790af81
--- /dev/null
+++ b/app/graphql/types/security/codequality_reports_comparer_type.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Types
+ module Security
+ # rubocop: disable Graphql/AuthorizeTypes (The resolver authorizes the request)
+ class CodequalityReportsComparerType < BaseObject
+ graphql_name 'CodequalityReportsComparer'
+
+ description 'Represents reports comparison for code quality.'
+
+ field :report,
+ type: CodequalityReportsComparer::ReportType,
+ null: true,
+ hash_key: 'data',
+ description: 'Compared codequality report.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb
index a6f5b7e7456..170f28103eb 100644
--- a/app/graphql/types/user_type.rb
+++ b/app/graphql/types/user_type.rb
@@ -3,7 +3,7 @@
module Types
class UserType < ::Types::BaseObject
graphql_name 'UserCore'
- description 'Core represention of a GitLab user.'
+ description 'Core representation of a GitLab user.'
implements ::Types::UserInterface
authorize :read_user
diff --git a/app/graphql/types/work_items/award_emoji_update_action_enum.rb b/app/graphql/types/work_items/award_emoji_update_action_enum.rb
index 5b2512a215f..e068e231af3 100644
--- a/app/graphql/types/work_items/award_emoji_update_action_enum.rb
+++ b/app/graphql/types/work_items/award_emoji_update_action_enum.rb
@@ -8,6 +8,7 @@ module Types
value 'ADD', 'Adds the emoji.', value: :add
value 'REMOVE', 'Removes the emoji.', value: :remove
+ value 'TOGGLE', 'Toggles the status of the emoji.', value: :toggle
end
end
end
diff --git a/app/graphql/types/work_items/widgets/linked_items_type.rb b/app/graphql/types/work_items/widgets/linked_items_type.rb
index fa51742b9c1..2611c2456c5 100644
--- a/app/graphql/types/work_items/widgets/linked_items_type.rb
+++ b/app/graphql/types/work_items/widgets/linked_items_type.rb
@@ -13,7 +13,7 @@ module Types
field :linked_items, Types::WorkItems::LinkedItemType.connection_type,
null: true, complexity: 5,
alpha: { milestone: '16.3' },
- description: 'Linked items for the work item. Returns `null`' \
+ description: 'Linked items for the work item. Returns `null` ' \
'if `linked_work_items` feature flag is disabled.',
resolver: Resolvers::WorkItems::LinkedItemsResolver
end
diff --git a/app/helpers/admin/abuse_reports_helper.rb b/app/helpers/admin/abuse_reports_helper.rb
index 275bed406f1..015d4513091 100644
--- a/app/helpers/admin/abuse_reports_helper.rb
+++ b/app/helpers/admin/abuse_reports_helper.rb
@@ -18,7 +18,8 @@ module Admin
def abuse_report_data(report)
{
- abuse_report_data: Admin::AbuseReportDetailsSerializer.new.represent(report).to_json
+ abuse_report_data: Admin::AbuseReportDetailsSerializer.new.represent(report).to_json,
+ abuse_reports_list_path: admin_abuse_reports_path
}
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 2bf239979f7..e3a630024d9 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -315,7 +315,8 @@ module ApplicationHelper
class_names << 'issue-boards-page gl-overflow-auto' if current_controller?(:boards)
class_names << 'epic-boards-page gl-overflow-auto' if current_controller?(:epic_boards)
class_names << 'with-performance-bar' if performance_bar_enabled?
- class_names << 'with-top-bar' if show_super_sidebar? && !@hide_top_bar
+ class_names << 'with-header' if !show_super_sidebar? || !current_user
+ class_names << 'with-top-bar' if show_super_sidebar? && !@hide_top_bar_padding
class_names << system_message_class
class_names << 'logged-out-marketing-header' if !current_user && ::Gitlab.com? && !show_super_sidebar?
@@ -485,6 +486,15 @@ module ApplicationHelper
end
end
+ def controller_full_path
+ action = case controller.action_name
+ when 'create' then 'new'
+ when 'update' then 'edit'
+ else controller.action_name
+ end
+ "#{controller.controller_path}/#{action}"
+ end
+
private
def browser_id
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index a45425474b5..ef91915ce38 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -238,6 +238,7 @@ module ApplicationSettingsHelper
:container_expiration_policies_enable_historic_entries,
:container_registry_expiration_policies_caching,
:container_registry_token_expire_delay,
+ :decompress_archive_file_timeout,
:default_artifacts_expire_in,
:default_branch_name,
:default_branch_protection,
@@ -306,7 +307,6 @@ module ApplicationSettingsHelper
:housekeeping_optimize_repository_period,
:html_emails_enabled,
:import_sources,
- :in_product_marketing_emails_enabled,
:inactive_projects_delete_after_months,
:inactive_projects_min_size_mb,
:inactive_projects_send_warning_email_after_months,
@@ -413,6 +413,7 @@ module ApplicationSettingsHelper
:throttle_protected_paths_period_in_seconds,
:throttle_protected_paths_requests_per_period,
:protected_paths_raw,
+ :protected_paths_for_get_request_raw,
:time_tracking_limit_to_hours,
:two_factor_grace_period,
:update_runner_versions_enabled,
@@ -436,6 +437,7 @@ module ApplicationSettingsHelper
:mailgun_events_enabled,
:snowplow_collector_hostname,
:snowplow_cookie_domain,
+ :snowplow_database_collector_hostname,
:snowplow_enabled,
:snowplow_app_id,
:push_event_hooks_limit,
@@ -478,12 +480,14 @@ module ApplicationSettingsHelper
:sentry_dsn,
:sentry_clientside_dsn,
:sentry_environment,
+ :sentry_clientside_traces_sample_rate,
:sidekiq_job_limiter_mode,
:sidekiq_job_limiter_compression_threshold_bytes,
:sidekiq_job_limiter_limit_bytes,
:suggest_pipeline_enabled,
:search_rate_limit,
:search_rate_limit_unauthenticated,
+ :search_rate_limit_allowlist_raw,
:users_get_by_id_limit,
:users_get_by_id_limit_allowlist_raw,
:runner_token_expiration_interval,
diff --git a/app/helpers/artifacts_helper.rb b/app/helpers/artifacts_helper.rb
index f90d59409ed..10d2714840d 100644
--- a/app/helpers/artifacts_helper.rb
+++ b/app/helpers/artifacts_helper.rb
@@ -5,8 +5,7 @@ module ArtifactsHelper
{
project_path: project.full_path,
project_id: project.id,
- can_destroy_artifacts: can?(current_user, :destroy_artifacts, project).to_s,
- artifacts_management_feedback_image_path: image_path('illustrations/chat-bubble-sm.svg')
+ can_destroy_artifacts: can?(current_user, :destroy_artifacts, project).to_s
}
end
end
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index c928c6479de..b7acc562be5 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module AuthHelper
- PROVIDERS_WITH_ICONS = %w(
+ PROVIDERS_WITH_ICONS = %w[
alicloud
atlassian_oauth2
auth0
@@ -15,12 +15,11 @@ module AuthHelper
google_oauth2
jwt
openid_connect
- salesforce
shibboleth
twitter
- ).freeze
- LDAP_PROVIDER = /\Aldap/.freeze
- POPULAR_PROVIDERS = %w(google_oauth2 github).freeze
+ ].freeze
+ LDAP_PROVIDER = /\Aldap/
+ POPULAR_PROVIDERS = %w[google_oauth2 github].freeze
delegate :slack_app_id, to: :'Gitlab::CurrentSettings.current_application_settings'
diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb
index 6e0ba748d85..e6212ee7d8d 100644
--- a/app/helpers/button_helper.rb
+++ b/app/helpers/button_helper.rb
@@ -7,6 +7,15 @@ module ButtonHelper
# :text - Text to copy (optional)
# :gfm - GitLab Flavored Markdown to copy, if different from `text` (optional)
# :target - Selector for target element to copy from (optional)
+ # :class - CSS classes to be applied to the button (optional)
+ # :title - Button's title attribute (used for the tooltip) (optional)
+ # :button_text - Button's displayed label (optional)
+ # :hide_tooltip - Whether the tooltip should be hidden (optional, default: false)
+ # :hide_button_icon - Whether the icon should be hidden (optional, default: false)
+ # :item_prop - itemprop attribute
+ # :variant - Button variant (optional, default: :default)
+ # :category - Button category (optional, default: :tertiary)
+ # :size - Button size (optional, default: :small)
#
# Examples:
#
@@ -20,6 +29,65 @@ module ButtonHelper
#
# See http://clipboardjs.com/#usage
def clipboard_button(data = {})
+ css_class = data.delete(:class)
+ title = data.delete(:title) || _('Copy')
+ button_text = data[:button_text] || nil
+ hide_tooltip = data[:hide_tooltip] || false
+ hide_button_icon = data[:hide_button_icon] || false
+ item_prop = data[:itemprop] || nil
+ variant = data[:variant] || :default
+ category = data[:category] || :tertiary
+ size = data[:size] || :small
+
+ # This supports code in app/assets/javascripts/copy_to_clipboard.js that
+ # works around ClipboardJS limitations to allow the context-specific copy/pasting of plain text or GFM.
+ if text = data.delete(:text)
+ data[:clipboard_text] =
+ if gfm = data.delete(:gfm)
+ { text: text, gfm: gfm }
+ else
+ text
+ end
+ end
+
+ target = data.delete(:target)
+ data[:clipboard_target] = target if target
+
+ unless hide_tooltip
+ data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data)
+ end
+
+ render ::Pajamas::ButtonComponent.new(
+ icon: hide_button_icon ? nil : 'copy-to-clipboard',
+ variant: variant,
+ category: category,
+ size: size,
+ button_options: { class: css_class, title: title, aria: { label: title, live: 'polite' }, data: data, itemprop: item_prop }) do
+ button_text
+ end
+ end
+
+ # Output a "Copy to Clipboard" button
+ # Note: This is being replaced by a Pajamas-compliant helper that renders the button
+ # via ::Pajamas::ButtonComponent. Please use clipboard_button instead.
+ #
+ # data - Data attributes passed to `content_tag` (default: {}):
+ # :text - Text to copy (optional)
+ # :gfm - GitLab Flavored Markdown to copy, if different from `text` (optional)
+ # :target - Selector for target element to copy from (optional)
+ #
+ # Examples:
+ #
+ # # Define the clipboard's text
+ # clipboard_button(text: "Foo")
+ # # => "<button class='...' data-clipboard-text='Foo'>...</button>"
+ #
+ # # Define the target element
+ # clipboard_button(target: "div#foo")
+ # # => "<button class='...' data-clipboard-target='div#foo'>...</button>"
+ #
+ # See http://clipboardjs.com/#usage
+ def deprecated_clipboard_button(data = {})
css_class = data.delete(:class) || 'btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm'
title = data.delete(:title) || _('Copy')
button_text = data[:button_text] || nil
diff --git a/app/helpers/ci/status_helper.rb b/app/helpers/ci/status_helper.rb
index ea5b613cb78..5d526a6abb6 100644
--- a/app/helpers/ci/status_helper.rb
+++ b/app/helpers/ci/status_helper.rb
@@ -9,55 +9,6 @@
#
module Ci
module StatusHelper
- def ci_label_for_status(status)
- if detailed_status?(status)
- return status.label
- end
-
- label = case status
- when 'success'
- 'passed'
- when 'success-with-warnings'
- 'passed with warnings'
- when 'manual'
- 'waiting for manual action'
- when 'scheduled'
- 'waiting for delayed job'
- else
- status
- end
- translation = "CiStatusLabel|#{label}"
- s_(translation)
- end
-
- def ci_text_for_status(status)
- if detailed_status?(status)
- return status.text
- end
-
- case status
- when 'success'
- s_('CiStatusText|passed')
- when 'success-with-warnings'
- s_('CiStatusText|passed')
- when 'manual'
- s_('CiStatusText|blocked')
- when 'scheduled'
- s_('CiStatusText|delayed')
- else
- # All states are already being translated inside the detailed statuses:
- # :running => Gitlab::Ci::Status::Running
- # :skipped => Gitlab::Ci::Status::Skipped
- # :failed => Gitlab::Ci::Status::Failed
- # :success => Gitlab::Ci::Status::Success
- # :canceled => Gitlab::Ci::Status::Canceled
- # The following states are customized above:
- # :manual => Gitlab::Ci::Status::Manual
- status_translation = "CiStatusText|#{status}"
- s_(status_translation)
- end
- end
-
def ci_status_for_statuseable(subject)
status = subject.try(:status) || 'not found'
status.humanize
@@ -138,11 +89,34 @@ module Ci
end
end
+ private
+
def detailed_status?(status)
status.respond_to?(:text) &&
status.respond_to?(:group) &&
status.respond_to?(:label) &&
status.respond_to?(:icon)
end
+
+ def ci_label_for_status(status)
+ if detailed_status?(status)
+ return status.label
+ end
+
+ label = case status
+ when 'success'
+ 'passed'
+ when 'success-with-warnings'
+ 'passed with warnings'
+ when 'manual'
+ 'waiting for manual action'
+ when 'scheduled'
+ 'waiting for delayed job'
+ else
+ status
+ end
+ translation = "CiStatusLabel|#{label}"
+ s_(translation)
+ end
end
end
diff --git a/app/helpers/ci/variables_helper.rb b/app/helpers/ci/variables_helper.rb
index a492c48e58c..0dbd1adeb71 100644
--- a/app/helpers/ci/variables_helper.rb
+++ b/app/helpers/ci/variables_helper.rb
@@ -42,8 +42,8 @@ module Ci
def ci_variable_type_options
[
- %w(Variable env_var),
- %w(File file)
+ %w[Variable env_var],
+ %w[File file]
]
end
diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb
index 5c410a28229..1989d6ab3d5 100644
--- a/app/helpers/clusters_helper.rb
+++ b/app/helpers/clusters_helper.rb
@@ -92,7 +92,7 @@ module ClustersHelper
end
def cluster_created?(cluster)
- !cluster.status_name.in?(%i/scheduled creating/)
+ !cluster.status_name.in?(%i[scheduled creating])
end
def can_admin_cluster?(user, cluster)
diff --git a/app/helpers/colors_helper.rb b/app/helpers/colors_helper.rb
index 80cf6f197e5..3cd7263c39e 100644
--- a/app/helpers/colors_helper.rb
+++ b/app/helpers/colors_helper.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module ColorsHelper
- HEX_COLOR_PATTERN = /\A\#(?:[0-9A-Fa-f]{3}){1,2}\Z/.freeze
+ HEX_COLOR_PATTERN = /\A\#(?:[0-9A-Fa-f]{3}){1,2}\Z/
def hex_color_to_rgb_array(hex_color)
unless hex_color.is_a?(String) && HEX_COLOR_PATTERN.match?(hex_color)
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index c5df53ec606..9a78d4d9ad5 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -16,7 +16,7 @@ module DiffHelper
def diff_view
@diff_view ||= begin
- diff_views = %w(inline parallel)
+ diff_views = %w[inline parallel]
diff_view = params[:view] || cookies[:diff_view]
diff_view = diff_views.first unless diff_views.include?(diff_view)
diff_view.to_sym
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index af0f1bd6808..69b3fdc2271 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -16,7 +16,7 @@ module EmailsHelper
def action_title(url)
return unless url
- %w(merge_requests issues commit).each do |action|
+ %w[merge_requests issues commit].each do |action|
if url.split("/").include?(action)
return "View #{action.humanize.singularize}"
end
diff --git a/app/helpers/environment_helper.rb b/app/helpers/environment_helper.rb
index 8140ee97291..6e9379a5926 100644
--- a/app/helpers/environment_helper.rb
+++ b/app/helpers/environment_helper.rb
@@ -62,7 +62,7 @@ module EnvironmentHelper
klass = "ci-status ci-#{status.dasherize} #{ci_icon_utilities}"
text = "#{ci_icon_for_status(status)} <span class=\"gl-ml-2\">#{status_text}</span>".html_safe
- if deployment.deployable
+ if deployment.deployable.instance_of?(::Ci::Build)
link_to(text, deployment_path(deployment), class: klass)
else
content_tag(:span, text, class: klass)
diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb
index cd768ba8a7b..80a56493653 100644
--- a/app/helpers/environments_helper.rb
+++ b/app/helpers/environments_helper.rb
@@ -57,11 +57,9 @@ module EnvironmentsHelper
'default_branch' => project.default_branch,
'project_path' => project_path(project),
'tags_path' => project_tags_path(project),
- 'external_dashboard_url' => project.metrics_setting_external_dashboard_url,
'custom_metrics_path' => project_prometheus_metrics_path(project),
'validate_query_path' => validate_query_project_prometheus_metrics_path(project),
- 'custom_metrics_available' => custom_metrics_available?(project).to_s,
- 'dashboard_timezone' => project.metrics_setting_dashboard_timezone.to_s.upcase
+ 'custom_metrics_available' => custom_metrics_available?(project).to_s
}
end
@@ -93,8 +91,7 @@ module EnvironmentsHelper
'empty_loading_svg_path' => image_path('illustrations/monitoring/loading.svg'),
'empty_no_data_svg_path' => image_path('illustrations/monitoring/no_data.svg'),
'empty_no_data_small_svg_path' => image_path('illustrations/chart-empty-state-small.svg'),
- 'empty_unable_to_connect_svg_path' => image_path('illustrations/monitoring/unable_to_connect.svg'),
- 'custom_dashboard_base_path' => Gitlab::Metrics::Dashboard::RepoDashboardFinder::DASHBOARD_ROOT
+ 'empty_unable_to_connect_svg_path' => image_path('illustrations/monitoring/unable_to_connect.svg')
}
end
end
diff --git a/app/helpers/external_link_helper.rb b/app/helpers/external_link_helper.rb
index 53dacfe0566..40079c0803d 100644
--- a/app/helpers/external_link_helper.rb
+++ b/app/helpers/external_link_helper.rb
@@ -7,6 +7,6 @@ module ExternalLinkHelper
link = link_to url, { target: '_blank', rel: 'noopener noreferrer' }.merge(options) do
"#{body}#{sprite_icon('external-link', css_class: 'gl-ml-2')}".html_safe
end
- sanitize(link, tags: %w(a svg use), attributes: %w(target rel data-testid class href).concat(options.stringify_keys.keys))
+ sanitize(link, tags: %w[a svg use], attributes: %w[target rel data-testid class href].concat(options.stringify_keys.keys))
end
end
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index bba3fac7468..ebebdfa56e6 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -29,9 +29,10 @@ module IconsHelper
ActionController::Base.helpers.image_path('file_icons/file_icons.svg', host: sprite_base_url)
end
- def sprite_icon(icon_name, size: DEFAULT_ICON_SIZE, css_class: nil)
+ def sprite_icon(icon_name, size: DEFAULT_ICON_SIZE, css_class: nil, file_icon: false)
memoized_icon("#{icon_name}_#{size}_#{css_class}") do
- if known_sprites&.exclude?(icon_name)
+ unknown_icon = file_icon ? unknown_file_icon_sprite(icon_name) : unknown_icon_sprite(icon_name)
+ if unknown_icon
exception = ArgumentError.new("#{icon_name} is not a known icon in @gitlab-org/gitlab-svg")
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(exception)
end
@@ -39,10 +40,11 @@ module IconsHelper
css_classes = []
css_classes << "s#{size}" if size
css_classes << css_class.to_s unless css_class.blank?
+ sprite_path = file_icon ? sprite_file_icons_path : sprite_icon_path
content_tag(
:svg,
- content_tag(:use, '', { 'href' => "#{sprite_icon_path}##{icon_name}" }),
+ content_tag(:use, '', { 'href' => "#{sprite_path}##{icon_name}" }),
class: css_classes.empty? ? nil : css_classes.join(' '),
data: { testid: "#{icon_name}-icon" }
)
@@ -123,61 +125,73 @@ module IconsHelper
def file_type_icon_class(type, mode, name)
if type == 'folder'
- icon_class = 'folder-o'
+ 'folder-o'
elsif type == 'archive'
- icon_class = 'archive'
+ 'archive'
elsif mode == '120000'
- icon_class = 'share'
+ 'share'
else
# Guess which icon to choose based on file extension.
# If you think a file extension is missing, feel free to add it on PR
case File.extname(name).downcase
when '.pdf'
- icon_class = 'document'
+ 'document'
when '.jpg', '.jpeg', '.jif', '.jfif',
- '.jp2', '.jpx', '.j2k', '.j2c',
- '.apng', '.png', '.gif', '.tif', '.tiff',
- '.svg', '.ico', '.bmp', '.webp'
- icon_class = 'doc-image'
+ '.jp2', '.jpx', '.j2k', '.j2c',
+ '.apng', '.png', '.gif', '.tif', '.tiff',
+ '.svg', '.ico', '.bmp', '.webp'
+ 'doc-image'
when '.zip', '.zipx', '.tar', '.gz', '.gzip', '.tgz', '.bz', '.bzip',
- '.bz2', '.bzip2', '.car', '.tbz', '.xz', 'txz', '.rar', '.7z',
- '.lz', '.lzma', '.tlz'
- icon_class = 'doc-compressed'
+ '.bz2', '.bzip2', '.car', '.tbz', '.xz', 'txz', '.rar', '.7z',
+ '.lz', '.lzma', '.tlz'
+ 'doc-compressed'
when '.mp3', '.wma', '.ogg', '.oga', '.wav', '.flac', '.aac', '.3ga',
- '.ac3', '.midi', '.m4a', '.ape', '.mpa'
- icon_class = 'volume-up'
+ '.ac3', '.midi', '.m4a', '.ape', '.mpa'
+ 'volume-up'
when '.mp4', '.m4p', '.m4v',
- '.mpg', '.mp2', '.mpeg', '.mpe', '.mpv',
- '.mpg', '.mpeg', '.m2v', '.m2ts',
- '.avi', '.mkv', '.flv', '.ogv', '.mov',
- '.3gp', '.3g2'
- icon_class = 'live-preview'
+ '.mpg', '.mp2', '.mpeg', '.mpe', '.mpv',
+ '.mpg', '.mpeg', '.m2v', '.m2ts',
+ '.avi', '.mkv', '.flv', '.ogv', '.mov',
+ '.3gp', '.3g2'
+ 'live-preview'
when '.doc', '.dot', '.docx', '.docm', '.dotx', '.dotm', '.docb',
- '.odt', '.ott', '.uot', '.rtf'
- icon_class = 'doc-text'
+ '.odt', '.ott', '.uot', '.rtf'
+ 'doc-text'
when '.xls', '.xlt', '.xlm', '.xlsx', '.xlsm', '.xltx', '.xltm',
- '.xlsb', '.xla', '.xlam', '.xll', '.xlw', '.ots', '.ods', '.uos'
- icon_class = 'document'
+ '.xlsb', '.xla', '.xlam', '.xll', '.xlw', '.ots', '.ods', '.uos'
+ 'document'
when '.ppt', '.pot', '.pps', '.pptx', '.pptm', '.potx', '.potm',
- '.ppam', '.ppsx', '.ppsm', '.sldx', '.sldm', '.odp', '.otp', '.uop'
- icon_class = 'doc-chart'
+ '.ppam', '.ppsx', '.ppsm', '.sldx', '.sldm', '.odp', '.otp', '.uop'
+ 'doc-chart'
else
- icon_class = 'doc-text'
+ 'doc-text'
end
end
-
- icon_class
end
private
+ def unknown_icon_sprite(icon_name)
+ known_sprites&.exclude?(icon_name)
+ end
+
+ def unknown_file_icon_sprite(icon_name)
+ known_file_icon_sprites&.exclude?(icon_name)
+ end
+
def known_sprites
return if Rails.env.production?
@known_sprites ||= Gitlab::Json.parse(File.read(Rails.root.join('node_modules/@gitlab/svgs/dist/icons.json')))['icons']
end
+ def known_file_icon_sprites
+ return if Rails.env.production?
+
+ @known_file_icon_sprites ||= Gitlab::Json.parse(File.read(Rails.root.join('node_modules/@gitlab/svgs/dist/file_icons/file_icons.json')))['icons']
+ end
+
def memoized_icon(key)
@rendered_icons ||= {}
diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb
index 645a08bfcc0..a88be976337 100644
--- a/app/helpers/integrations_helper.rb
+++ b/app/helpers/integrations_helper.rb
@@ -277,11 +277,11 @@ module IntegrationsHelper
s_("ProjectService|Trigger event for new comments.")
when "confidential_note", "confidential_note_events"
s_("ProjectService|Trigger event for new comments on confidential issues.")
- when "issue", "issue_events"
+ when "issue", "issue_events", "issues_events"
s_("ProjectService|Trigger event when an issue is created, updated, or closed.")
- when "confidential_issue", "confidential_issue_events"
+ when "confidential_issue", "confidential_issue_events", "confidential_issues_events"
s_("ProjectService|Trigger event when a confidential issue is created, updated, or closed.")
- when "merge_request", "merge_request_events"
+ when "merge_request", "merge_request_events", "merge_requests_events"
s_("ProjectService|Trigger event when a merge request is created, updated, or merged.")
when "pipeline", "pipeline_events"
s_("ProjectService|Trigger event when a pipeline status changes.")
@@ -289,16 +289,20 @@ module IntegrationsHelper
s_("ProjectService|Trigger event when a wiki page is created or updated.")
when "commit", "commit_events"
s_("ProjectService|Trigger event when a commit is created or updated.")
- when "deployment"
+ when "deployment", "deployment_events"
s_("ProjectService|Trigger event when a deployment starts or finishes.")
- when "alert"
+ when "alert", "alert_events"
s_("ProjectService|Trigger event when a new, unique alert is recorded.")
- when "incident"
+ when "incident", "incident_events"
s_("ProjectService|Trigger event when an incident is created.")
when "group_mention"
s_("ProjectService|Trigger event when a group is mentioned in a public context.")
when "group_confidential_mention"
s_("ProjectService|Trigger event when a group is mentioned in a confidential context.")
+ when "build_events"
+ s_("ProjectService|Trigger event when a build is created.")
+ when "archive_trace_events"
+ s_('When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces.')
end
end
# rubocop:enable Metrics/CyclomaticComplexity
@@ -323,12 +327,15 @@ module IntegrationsHelper
def serialize_integration(integration, group: nil, project: nil)
{
- active: integration.operating?,
+ id: integration.id,
+ active: integration.activated?,
+ configured: integration.persisted?,
title: integration.title,
description: integration.description,
updated_at: integration.updated_at,
edit_path: scoped_edit_integration_path(integration, group: group, project: project),
- name: integration.to_param
+ name: integration.to_param,
+ icon: integration.try(:avatar_url)
}
end
end
diff --git a/app/helpers/invite_members_helper.rb b/app/helpers/invite_members_helper.rb
index 422380f3cc6..0443861903b 100644
--- a/app/helpers/invite_members_helper.rb
+++ b/app/helpers/invite_members_helper.rb
@@ -37,23 +37,13 @@ module InviteMembersHelper
# Overridden in EE
def common_invite_modal_dataset(source)
- dataset = {
+ {
id: source.id,
root_id: source.root_ancestor&.id,
name: source.name,
default_access_level: Gitlab::Access::GUEST,
full_path: source.full_path
}
-
- if current_user && show_invite_members_for_task?
- dataset.merge!(
- tasks_to_be_done_options: tasks_to_be_done_options.to_json,
- projects: projects_for_source(source).to_json,
- new_project_path: source.is_a?(Group) ? new_project_path(namespace_id: source.id) : ''
- )
- end
-
- dataset
end
private
@@ -70,19 +60,6 @@ module InviteMembersHelper
def users_filter_data(group)
{}
end
-
- def show_invite_members_for_task?
- params[:open_modal] == 'invite_members_for_task'
- end
-
- def tasks_to_be_done_options
- ::MemberTask::TASKS.keys.map { |task| { value: task, text: localized_tasks_to_be_done_choices[task] } }
- end
-
- def projects_for_source(source)
- projects = source.is_a?(Project) ? [source] : source.projects
- projects.map { |project| { id: project.id, title: project.title } }
- end
end
InviteMembersHelper.prepend_mod_with('InviteMembersHelper')
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index c83545fa7a7..7f948db2f71 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -33,22 +33,6 @@ module IssuablesHelper
end
end
- def sidebar_milestone_tooltip_label(milestone)
- return _('Milestone') unless milestone.present?
-
- [escape_once(milestone[:title]), sidebar_milestone_remaining_days(milestone) || _('Milestone')].join('<br/>')
- end
-
- def sidebar_milestone_remaining_days(milestone)
- due_date_with_remaining_days(milestone[:due_date], milestone[:start_date])
- end
-
- def due_date_with_remaining_days(due_date, start_date = nil)
- return unless due_date
-
- "#{due_date.to_fs(:medium)} (#{remaining_days_in_words(due_date, start_date)})"
- end
-
def multi_label_name(current_labels, default_label)
return default_label if current_labels.blank?
@@ -131,46 +115,6 @@ module IssuablesHelper
end
# rubocop: enable CodeReuse/ActiveRecord
- def issuable_meta_author_status(author)
- return "" unless author&.status&.customized? && status = user_status(author)
-
- status.to_s.html_safe
- end
-
- def issuable_meta(issuable, project)
- output = []
-
- if issuable.respond_to?(:work_item_type) && WorkItems::Type::WI_TYPES_WITH_CREATED_HEADER.include?(issuable.issue_type)
- output << content_tag(:span, sprite_icon(issuable.work_item_type.icon_name.to_s, css_class: 'gl-icon gl-vertical-align-middle gl-text-gray-500'), class: 'gl-mr-2', aria: { hidden: 'true' })
- output << content_tag(:span, s_('IssuableStatus|%{wi_type} created %{created_at} by ').html_safe % { wi_type: IntegrationsHelper.integration_issue_type(issuable.issue_type), created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2')
- else
- output << content_tag(:span, s_('IssuableStatus|Created %{created_at} by').html_safe % { created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2')
- end
-
- if issuable.is_a?(Issue) && issuable.service_desk_reply_to
- output << "#{html_escape(issuable.present(current_user: current_user).service_desk_reply_to)} via "
- end
-
- output << content_tag(:strong) do
- author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "d-none d-sm-inline-block")
- author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "d-inline d-sm-none")
-
- author_output << issuable_meta_author_status(issuable.author)
-
- author_output
- end
-
- if access = project.team.human_max_access(issuable.author_id)
- output << content_tag(:span, access, class: "user-access-role has-tooltip d-none d-xl-inline-block gl-ml-3 ", title: _("This user has the %{access} role in the %{name} project.") % { access: access.downcase, name: project.name })
- elsif project.team.contributor?(issuable.author_id)
- output << content_tag(:span, _("Contributor"), class: "user-access-role has-tooltip d-none d-xl-inline-block gl-ml-3", title: _("This user has previously committed to the %{name} project.") % { name: project.name })
- end
-
- output << content_tag(:span, (sprite_icon('first-contribution', css_class: 'gl-icon gl-vertical-align-middle') if issuable.first_contribution?), class: 'has-tooltip gl-ml-2', title: _('1st contribution!'))
-
- output.join.html_safe
- end
-
def issuables_state_counter_text(issuable_type, state, display_count)
titles = {
opened: _("Open"),
@@ -248,71 +192,6 @@ module IssuablesHelper
data
end
- def issue_only_initial_data(issuable)
- return {} unless issuable.is_a?(Issue)
-
- data = {
- authorId: issuable.author.id,
- authorName: issuable.author.name,
- authorUsername: issuable.author.username,
- authorWebUrl: url_for(user_path(issuable.author)),
- createdAt: issuable.created_at.to_time.iso8601,
- hasClosingMergeRequest: issuable.merge_requests_count(current_user) != 0,
- isFirstContribution: issuable.first_contribution?,
- issueType: issuable.issue_type,
- serviceDeskReplyTo: issuable.present(current_user: current_user).service_desk_reply_to,
- zoomMeetingUrl: ZoomMeeting.canonical_meeting_url(issuable),
- sentryIssueIdentifier: SentryIssue.find_by(issue: issuable)&.sentry_issue_identifier, # rubocop:disable CodeReuse/ActiveRecord
- iid: issuable.iid.to_s,
- isHidden: issue_hidden?(issuable),
- canCreateIncident: create_issue_type_allowed?(issuable.project, :incident),
- **incident_only_initial_data(issuable)
- }
-
- data.tap do |d|
- if issuable.duplicated? && can?(current_user, :read_issue, issuable.duplicated_to)
- d[:duplicatedToIssueUrl] = url_for([issuable.duplicated_to.project, issuable.duplicated_to, { only_path: false }])
- end
-
- if issuable.moved? && can?(current_user, :read_issue, issuable.moved_to)
- d[:movedToIssueUrl] = url_for([issuable.moved_to.project, issuable.moved_to, { only_path: false }])
- end
- end
- end
-
- def incident_only_initial_data(issue)
- return {} unless issue.incident_type_issue?
-
- {
- hasLinkedAlerts: issue.alert_management_alerts.any?,
- canUpdateTimelineEvent: can?(current_user, :admin_incident_management_timeline_event, issue),
- currentPath: url_for(safe_params),
- currentTab: safe_params[:incident_tab]
- }
- end
-
- def path_data(parent)
- return { groupPath: parent.path } if parent.is_a?(Group)
-
- {
- projectPath: ref_project.path,
- projectId: ref_project.id,
- projectNamespace: ref_project.namespace.full_path
- }
- end
-
- def updated_at_by(issuable)
- return {} unless issuable.edited?
-
- {
- updatedAt: issuable.last_edited_at.to_time.iso8601,
- updatedBy: {
- name: issuable.last_edited_by.name,
- path: user_path(issuable.last_edited_by)
- }
- }
- end
-
def issuables_count_for_state(issuable_type, state)
Gitlab::IssuablesCountForState.new(finder, fast_fail: true, store_in_redis_cache: true)[state]
end
@@ -333,15 +212,6 @@ module IssuablesHelper
issuable.author == current_user
end
- def issuable_display_type(issuable)
- case issuable
- when Issue
- issuable.issue_type.downcase
- when MergeRequest
- issuable.model_name.human.downcase
- end
- end
-
def has_filter_bar_param?
finder.class.scalar_params.any? { |p| params[p].present? }
end
@@ -353,12 +223,6 @@ module IssuablesHelper
end
end
- def reviewer_sidebar_data(reviewer, merge_request: nil)
- { avatar_url: reviewer.avatar_url, name: reviewer.name, username: reviewer.username }.tap do |data|
- data[:can_merge] = merge_request.can_be_merged_by?(reviewer) if merge_request
- end
- end
-
def issuable_squash_option?(issuable, project)
if issuable.persisted?
issuable.squash
@@ -428,27 +292,6 @@ module IssuablesHelper
cookies[:collapsed_gutter] == 'true'
end
- def issuable_todo_button_data(issuable, is_collapsed)
- {
- todo_text: _('Add a to do'),
- mark_text: _('Mark as done'),
- todo_icon: sprite_icon('todo-add'),
- mark_icon: sprite_icon('todo-done', css_class: 'todo-undone'),
- issuable_id: issuable[:id],
- issuable_type: issuable[:type],
- create_path: issuable[:create_todo_path],
- delete_path: issuable.dig(:current_user, :todo, :delete_path),
- placement: is_collapsed ? 'left' : nil,
- container: is_collapsed ? 'body' : nil,
- boundary: 'viewport',
- is_collapsed: is_collapsed,
- track_label: "right_sidebar",
- track_property: "update_todo",
- track_action: "click_button",
- track_value: ""
- }
- end
-
def close_reopen_params(issuable, action)
{
issuable.model_name.to_s.underscore => { state_event: action }
@@ -520,6 +363,86 @@ module IssuablesHelper
number_with_delimiter(count)
end
end
+
+ def issue_only_initial_data(issuable)
+ return {} unless issuable.is_a?(Issue)
+
+ {
+ canCreateIncident: create_issue_type_allowed?(issuable.project, :incident),
+ fullPath: issuable.project.full_path,
+ iid: issuable.iid,
+ issuableId: issuable.id,
+ issueType: issuable.issue_type,
+ isHidden: issue_hidden?(issuable),
+ sentryIssueIdentifier: SentryIssue.find_by(issue: issuable)&.sentry_issue_identifier, # rubocop:disable CodeReuse/ActiveRecord
+ zoomMeetingUrl: ZoomMeeting.canonical_meeting_url(issuable),
+ **incident_only_initial_data(issuable),
+ **issue_header_data(issuable),
+ **work_items_data
+ }
+ end
+
+ def incident_only_initial_data(issue)
+ return {} unless issue.incident_type_issue?
+
+ {
+ hasLinkedAlerts: issue.alert_management_alerts.any?,
+ canUpdateTimelineEvent: can?(current_user, :admin_incident_management_timeline_event, issue),
+ currentPath: url_for(safe_params),
+ currentTab: safe_params[:incident_tab]
+ }
+ end
+
+ def issue_header_data(issuable)
+ data = {
+ authorId: issuable.author.id,
+ authorName: issuable.author.name,
+ authorUsername: issuable.author.username,
+ authorWebUrl: url_for(user_path(issuable.author)),
+ createdAt: issuable.created_at.to_time.iso8601,
+ isFirstContribution: issuable.first_contribution?,
+ serviceDeskReplyTo: issuable.present(current_user: current_user).service_desk_reply_to
+ }
+
+ data.tap do |d|
+ if issuable.duplicated? && can?(current_user, :read_issue, issuable.duplicated_to)
+ d[:duplicatedToIssueUrl] = url_for([issuable.duplicated_to.project, issuable.duplicated_to, { only_path: false }])
+ end
+
+ if issuable.moved? && can?(current_user, :read_issue, issuable.moved_to)
+ d[:movedToIssueUrl] = url_for([issuable.moved_to.project, issuable.moved_to, { only_path: false }])
+ end
+ end
+ end
+
+ def work_items_data
+ {
+ registerPath: new_user_registration_path(redirect_to_referer: 'yes'),
+ signInPath: new_session_path(:user, redirect_to_referer: 'yes')
+ }
+ end
+
+ def path_data(parent)
+ return { groupPath: parent.path } if parent.is_a?(Group)
+
+ {
+ projectPath: ref_project.path,
+ projectId: ref_project.id,
+ projectNamespace: ref_project.namespace.full_path
+ }
+ end
+
+ def updated_at_by(issuable)
+ return {} unless issuable.edited?
+
+ {
+ updatedAt: issuable.last_edited_at.to_time.iso8601,
+ updatedBy: {
+ name: issuable.last_edited_by.name,
+ path: user_path(issuable.last_edited_by)
+ }
+ }
+ end
end
IssuablesHelper.prepend_mod_with('IssuablesHelper')
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index ed655b562c2..4419b573701 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -35,15 +35,6 @@ module IssuesHelper
end
end
- def issue_status_visibility(issue, status_box:)
- case status_box
- when :open
- 'hidden' if issue.closed?
- when :closed
- 'hidden' unless issue.closed?
- end
- end
-
def confidential_icon(issue)
sprite_icon('eye-slash', css_class: 'gl-vertical-align-text-bottom') if issue.confidential?
end
@@ -128,24 +119,6 @@ module IssuesHelper
can?(current_user, :create_merge_request_in, @project)
end
- def issue_closed_link(issue, current_user, css_class: '')
- if issue.moved? && can?(current_user, :read_issue, issue.moved_to)
- link_to(s_('IssuableStatus|moved'), issue.moved_to, class: css_class)
- elsif issue.duplicated? && can?(current_user, :read_issue, issue.duplicated_to)
- link_to(s_('IssuableStatus|duplicated'), issue.duplicated_to, class: css_class)
- end
- end
-
- def issue_closed_text(issue, current_user)
- link = issue_closed_link(issue, current_user, css_class: 'text-underline gl-reset-color!')
-
- if link
- s_('IssuableStatus|Closed (%{link})').html_safe % { link: link }
- else
- s_('IssuableStatus|Closed')
- end
- end
-
def show_moved_service_desk_issue_warning?(issue)
return false unless issue.moved_from
return false unless issue.from_service_desk?
@@ -167,11 +140,8 @@ module IssuesHelper
can_reopen_issue: can?(current_user, :reopen_issue, issuable).to_s,
can_report_spam: issuable.submittable_as_spam_by?(current_user).to_s,
can_update_issue: can?(current_user, :update_issue, issuable).to_s,
- iid: issuable.iid,
- issuable_id: issuable.id,
is_issue_author: (issuable.author == current_user).to_s,
issue_path: issuable_path(issuable),
- issue_type: issuable_display_type(issuable),
new_issue_path: new_project_issue_path(project, new_issuable_params),
project_path: project.full_path,
report_abuse_path: add_category_abuse_reports_path,
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 79bab0969d1..a6bc9bcf205 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -68,7 +68,7 @@ module LabelsHelper
# We need the `label` argument here for EE
def wrap_label_html(label_html, small:, label:)
- wrapper_classes = %w(gl-label)
+ wrapper_classes = %w[gl-label]
wrapper_classes << 'gl-label-sm' if small
%(<span class="#{wrapper_classes.join(' ')}">#{label_html}</span>).html_safe
@@ -220,10 +220,16 @@ module LabelsHelper
project || group&.subgroup?
end
+ def label_lock_on_merge_help_text
+ _('IMPORTANT: Use this setting only for VERY strict auditing purposes. ' \
+ 'When turned on, nobody will be able to remove the label from any merge requests after they are merged. ' \
+ 'In addition, nobody will be able to turn off this setting or delete this label.')
+ end
+
private
def render_label_link(label_html, link:, title:, dataset:)
- classes = %w(gl-link gl-label-link)
+ classes = %w[gl-link gl-label-link]
dataset ||= {}
if title.present?
diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb
index 1a44f3554b0..1bd5cc41961 100644
--- a/app/helpers/markup_helper.rb
+++ b/app/helpers/markup_helper.rb
@@ -63,7 +63,7 @@ module MarkupHelper
md = markdown_field(object, attribute, options.merge(post_process: false))
return unless md.present?
- tags = %w(a gl-emoji b strong i em pre code p span)
+ tags = %w[a gl-emoji b strong i em pre code p span]
context = markdown_field_render_context(object, attribute, options)
context.reverse_merge!(truncate_visible_max_chars: max_chars || md.length)
@@ -73,11 +73,11 @@ module MarkupHelper
text,
tags: tags,
attributes: Rails::Html::WhiteListSanitizer.allowed_attributes +
- %w(
+ %w[
style data-src data-name data-unicode-version data-html
data-reference-type data-project-path data-iid data-mr-title
data-user
- )
+ ]
)
render_links(text)
diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb
index 42ffe338367..e4c1d7932aa 100644
--- a/app/helpers/members_helper.rb
+++ b/app/helpers/members_helper.rb
@@ -54,14 +54,6 @@ module MembersHelper
end
end
- def localized_tasks_to_be_done_choices
- {
- code: s_('TasksToBeDone|Create/import code into a project (repository)'),
- ci: s_('TasksToBeDone|Set up CI/CD pipelines to build, test, deploy, and monitor code'),
- issues: s_('TasksToBeDone|Create/import issues (tickets) to collaborate on ideas and plan work')
- }.freeze
- end
-
private
def source_text(member)
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 32a183d6cd8..a90a16e120c 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -226,6 +226,13 @@ module MergeRequestsHelper
}
end
+ def mr_compare_form_data(_, merge_request)
+ {
+ source_branch_url: project_new_merge_request_branch_from_path(merge_request.source_project),
+ target_branch_url: project_new_merge_request_branch_to_path(merge_request.source_project)
+ }
+ end
+
private
def review_requested_merge_requests_count
@@ -269,7 +276,7 @@ module MergeRequestsHelper
def merge_request_header(project, merge_request)
link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold gl-mr-2', avatar: false)
- copy_button = clipboard_button(text: merge_request.source_branch, title: _('Copy branch name'), class: 'btn btn-default btn-sm gl-button btn-default-tertiary btn-icon gl-display-none! gl-md-display-inline-block! js-source-branch-copy')
+ copy_button = clipboard_button(text: merge_request.source_branch, title: _('Copy branch name'), class: 'gl-display-none! gl-md-display-inline-block! js-source-branch-copy')
target_branch = link_to merge_request.target_branch, project_tree_path(merge_request.target_project, merge_request.target_branch), title: merge_request.target_branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mx-2'
diff --git a/app/helpers/nav/new_dropdown_helper.rb b/app/helpers/nav/new_dropdown_helper.rb
index 306c4d8694e..5274ace3d8a 100644
--- a/app/helpers/nav/new_dropdown_helper.rb
+++ b/app/helpers/nav/new_dropdown_helper.rb
@@ -157,7 +157,7 @@ module Nav
partial: partial,
component: 'invite_members',
data: {
- trigger_source: 'top-nav',
+ trigger_source: 'top_nav',
trigger_element: 'text-emoji'
}
)
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 4cbd5029ac9..d3707183964 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -79,11 +79,11 @@ module NavHelper
end
def admin_monitoring_nav_links
- %w(system_info background_migrations background_jobs health_check)
+ %w[system_info background_migrations background_jobs health_check]
end
def admin_analytics_nav_links
- %w(dev_ops_report usage_trends)
+ %w[dev_ops_report usage_trends]
end
def show_super_sidebar?(user = current_user)
diff --git a/app/helpers/organizations/organization_helper.rb b/app/helpers/organizations/organization_helper.rb
new file mode 100644
index 00000000000..6b5c4342c5c
--- /dev/null
+++ b/app/helpers/organizations/organization_helper.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Organizations
+ module OrganizationHelper
+ def organization_show_app_data(organization)
+ {
+ organization: organization.slice(:id, :name),
+ groups_and_projects_organization_path: groups_and_projects_organization_path(organization),
+ # TODO: Update counts to use real data
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/424531
+ association_counts: {
+ groups: 10,
+ projects: 5,
+ users: 1050
+ }
+ }.merge(shared_groups_and_projects_app_data).to_json
+ end
+
+ def organization_groups_and_projects_app_data
+ shared_groups_and_projects_app_data.to_json
+ end
+
+ private
+
+ def shared_groups_and_projects_app_data
+ {
+ projects_empty_state_svg_path: image_path('illustrations/empty-state/empty-projects-md.svg'),
+ groups_empty_state_svg_path: image_path('illustrations/empty-state/empty-groups-md.svg'),
+ new_group_path: new_group_path,
+ new_project_path: new_project_path
+ }
+ end
+ end
+end
diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb
index 05605394d57..8d260d5e455 100644
--- a/app/helpers/profiles_helper.rb
+++ b/app/helpers/profiles_helper.rb
@@ -34,7 +34,7 @@ module ProfilesHelper
def middle_dot_divider_classes(stacking, breakpoint)
['gl-mb-3'].tap do |classes|
if stacking
- classes.concat(%w(middle-dot-divider-sm gl-display-block gl-sm-display-inline-block))
+ classes.concat(%w[middle-dot-divider-sm gl-display-block gl-sm-display-inline-block])
else
classes << 'gl-display-inline-block'
classes << if breakpoint.nil?
diff --git a/app/helpers/projects/observability_helper.rb b/app/helpers/projects/observability_helper.rb
deleted file mode 100644
index 4515fdb1bc3..00000000000
--- a/app/helpers/projects/observability_helper.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module Projects
- module ObservabilityHelper
- def observability_tracing_view_model(project)
- Gitlab::Json.generate({
- tracingUrl: Gitlab::Observability.tracing_url(project),
- provisioningUrl: Gitlab::Observability.provisioning_url(project),
- oauthUrl: Gitlab::Observability.oauth_url
- })
- end
-
- def observability_tracing_details_model(project, trace_id)
- Gitlab::Json.generate({
- tracingIndexUrl: namespace_project_tracing_index_path(project.group, project),
- traceId: trace_id,
- tracingUrl: Gitlab::Observability.tracing_url(project),
- provisioningUrl: Gitlab::Observability.provisioning_url(project),
- oauthUrl: Gitlab::Observability.oauth_url
- })
- end
- end
-end
diff --git a/app/helpers/projects/pipeline_helper.rb b/app/helpers/projects/pipeline_helper.rb
index 42e8e44c94c..0c3b7d26fe2 100644
--- a/app/helpers/projects/pipeline_helper.rb
+++ b/app/helpers/projects/pipeline_helper.rb
@@ -18,7 +18,7 @@ module Projects
suite_endpoint: project_pipeline_test_path(project, pipeline, suite_name: 'suite', format: :json),
blob_path: project_blob_path(project, pipeline.sha),
has_test_report: pipeline.has_test_reports?,
- empty_state_image_path: image_path('illustrations/empty-state/empty-test-cases-lg.svg'),
+ empty_state_image_path: image_path('illustrations/empty-todos-md.svg'),
empty_dag_svg_path: image_path('illustrations/empty-state/empty-dag-md.svg'),
artifacts_expired_image_path: image_path('illustrations/pipeline.svg'),
tests_count: pipeline.test_report_summary.total[:count]
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 754e1b7c2a2..e45b38f2266 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -373,14 +373,6 @@ module ProjectsHelper
false
end
- def metrics_external_dashboard_url
- @project.metrics_setting_external_dashboard_url
- end
-
- def metrics_dashboard_timezone
- @project.metrics_setting_dashboard_timezone
- end
-
def grafana_integration_url
@project.grafana_integration&.grafana_url
end
diff --git a/app/helpers/registrations_helper.rb b/app/helpers/registrations_helper.rb
index 4acba9b68d7..c2c142bca4d 100644
--- a/app/helpers/registrations_helper.rb
+++ b/app/helpers/registrations_helper.rb
@@ -7,7 +7,7 @@ module RegistrationsHelper
min_length_message: s_('SignUp|Username is too short (minimum is %{min_length} characters).') % { min_length: User::MIN_USERNAME_LENGTH },
max_length: User::MAX_USERNAME_LENGTH,
max_length_message: s_('SignUp|Username is too long (maximum is %{max_length} characters).') % { max_length: User::MAX_USERNAME_LENGTH },
- qa_selector: 'new_user_username_field'
+ testid: 'new-user-username-field'
}
end
diff --git a/app/helpers/routing/projects_helper.rb b/app/helpers/routing/projects_helper.rb
index 9b4aafe49b4..06de9022be4 100644
--- a/app/helpers/routing/projects_helper.rb
+++ b/app/helpers/routing/projects_helper.rb
@@ -43,12 +43,11 @@ module Routing
end
def work_item_url(entity, *args)
- # TODO: we do not have a route to access group level work items yet.
- # That is to be done as part of view group level work item issue:
- # see https://gitlab.com/gitlab-org/gitlab/-/work_items/393987
- return unless entity.project.present?
-
- project_work_items_url(entity.project, entity.iid, *args)
+ if entity.project.present?
+ project_work_items_url(entity.project, entity.iid, *args)
+ else
+ group_work_item_url(entity.namespace, entity.iid, *args)
+ end
end
def merge_request_url(entity, *args)
@@ -94,6 +93,8 @@ module Routing
private
def use_work_items_path?(issue)
+ return true if issue.project.blank? && issue.namespace.present?
+
issue.issue_type == 'task'
end
end
diff --git a/app/helpers/safe_format_helper.rb b/app/helpers/safe_format_helper.rb
index d39a972f3f3..71bfc9ecb40 100644
--- a/app/helpers/safe_format_helper.rb
+++ b/app/helpers/safe_format_helper.rb
@@ -36,7 +36,7 @@ module SafeFormatHelper
# Returns an empty Hash if +tag+ is not a valid paired tag (e.g. <p>foo</p>).
# an empty Hash is returned.
#
- # @param [String] tag is a HTML-safe output from tag helper
+ # @param [String] html_tag is a HTML-safe output from tag helper
# @param [Symbol,Object] open_name name of opening tag
# @param [Symbol,Object] close_name name of closing tag
# @raise [ArgumentError] if +tag+ is not HTML-safe
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index cd32023adb6..f002a0c454d 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -242,7 +242,7 @@ module SearchHelper
elsif current_controller?(:commits)
'commits'
elsif current_controller?(:groups)
- if %w(issues merge_requests).include?(controller.action_name)
+ if %w[issues merge_requests].include?(controller.action_name)
controller.action_name
end
end
@@ -479,7 +479,7 @@ module SearchHelper
end.to_json
end
- def search_filter_input_options(type, placeholder = _('Search or filter results...'))
+ def search_filter_input_options(type, placeholder = _('Search or filter results…'))
opts =
{
id: "filtered-search-#{type}",
@@ -537,14 +537,14 @@ module SearchHelper
source,
count_tags: false,
count_tail: false,
- filtered_tags: %w(img),
+ filtered_tags: %w[img],
max_length: 200
)
end
def search_sanitize(html)
# Truncato's filtered_tags and filtered_attributes are not quite the same
- sanitize(html, tags: %w(a p ol ul li pre code))
+ sanitize(html, tags: %w[a p ol ul li pre code])
end
# _search_highlight is used in EE override
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index 1bd7da0a352..33ca5ad584e 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -64,7 +64,8 @@ module SidebarsHelper
gitlab_version: Gitlab.version_info,
gitlab_version_check: gitlab_version_check,
search: search_data,
- panel_type: panel_type
+ panel_type: panel_type,
+ shortcut_links: shortcut_links
}
end
@@ -106,7 +107,8 @@ module SidebarsHelper
update_pins_url: pins_path,
is_impersonating: impersonating?,
stop_impersonation_path: admin_impersonation_path,
- shortcut_links: shortcut_links(user, project: project)
+ shortcut_links: shortcut_links(user: user, project: project),
+ track_visits_path: track_namespace_visits_path
})
end
@@ -114,32 +116,43 @@ module SidebarsHelper
nav: nil, project: nil, user: nil, group: nil, current_ref: nil, ref_type: nil,
viewed_user: nil, organization: nil)
context_adds = { route_is_active: method(:active_nav_link?), is_super_sidebar: true }
- case nav
- when 'project'
- context = project_sidebar_context(project, user, current_ref, ref_type: ref_type, **context_adds)
- Sidebars::Projects::SuperSidebarPanel.new(context)
- when 'group'
- context = group_sidebar_context(group, user, **context_adds)
- Sidebars::Groups::SuperSidebarPanel.new(context)
- when 'profile'
- context = Sidebars::Context.new(current_user: user, container: user, **context_adds)
- Sidebars::UserSettings::Panel.new(context)
- when 'user_profile'
- context = Sidebars::Context.new(current_user: user, container: viewed_user, **context_adds)
- Sidebars::UserProfile::Panel.new(context)
- when 'explore'
- Sidebars::Explore::Panel.new(Sidebars::Context.new(current_user: user, container: nil, **context_adds))
- when 'search'
- context = Sidebars::Context.new(current_user: user, container: nil, **context_adds)
- Sidebars::Search::Panel.new(context)
- when 'admin'
- Sidebars::Admin::Panel.new(Sidebars::Context.new(current_user: user, container: nil, **context_adds))
- when 'organization'
- context = organization_sidebar_context(organization, user, **context_adds)
- Sidebars::Organizations::SuperSidebarPanel.new(context)
- else
+ panel = case nav
+ when 'project'
+ context = project_sidebar_context(project, user, current_ref, ref_type: ref_type, **context_adds)
+ Sidebars::Projects::SuperSidebarPanel.new(context)
+ when 'group'
+ context = group_sidebar_context(group, user, **context_adds)
+ Sidebars::Groups::SuperSidebarPanel.new(context)
+ when 'profile'
+ context = Sidebars::Context.new(current_user: user, container: user, **context_adds)
+ Sidebars::UserSettings::Panel.new(context)
+ when 'user_profile'
+ context = Sidebars::Context.new(current_user: user, container: viewed_user, **context_adds)
+ Sidebars::UserProfile::Panel.new(context)
+ when 'explore'
+ Sidebars::Explore::Panel.new(Sidebars::Context.new(current_user: user, container: nil, **context_adds))
+ when 'search'
+ context = Sidebars::Context.new(current_user: user, container: nil, **context_adds)
+ Sidebars::Search::Panel.new(context)
+ when 'admin'
+ Sidebars::Admin::Panel.new(Sidebars::Context.new(current_user: user, container: nil, **context_adds))
+ when 'organization'
+ context = organization_sidebar_context(organization, user, **context_adds)
+ Sidebars::Organizations::SuperSidebarPanel.new(context)
+ when 'your_work'
+ context = your_work_sidebar_context(user, **context_adds)
+ Sidebars::YourWork::Panel.new(context)
+ end
+
+ # We only return the panel if any menu item is rendered, otherwise fallback
+ return panel if panel&.render?
+
+ # Fallback menu "Your work" for logged-in users, "Explore" for logged-out
+ if user
context = your_work_sidebar_context(user, **context_adds)
Sidebars::YourWork::Panel.new(context)
+ else
+ Sidebars::Explore::Panel.new(Sidebars::Context.new(current_user: nil, container: nil, **context_adds))
end
end
@@ -387,7 +400,29 @@ module SidebarsHelper
!!session[:impersonator_id]
end
- def shortcut_links(user, project: nil)
+ def shortcut_links_anonymous
+ [
+ {
+ title: _('Snippets'),
+ href: explore_snippets_path,
+ css_class: 'dashboard-shortcuts-snippets'
+ },
+ {
+ title: _('Groups'),
+ href: explore_groups_path,
+ css_class: 'dashboard-shortcuts-groups'
+ },
+ {
+ title: _('Projects'),
+ href: explore_projects_path,
+ css_class: 'dashboard-shortcuts-projects'
+ }
+ ]
+ end
+
+ def shortcut_links(user: nil, project: nil)
+ return shortcut_links_anonymous unless user
+
shortcut_links = [
{
title: _('Milestones'),
@@ -403,6 +438,16 @@ module SidebarsHelper
title: _('Activity'),
href: activity_dashboard_path,
css_class: 'dashboard-shortcuts-activity'
+ },
+ {
+ title: _('Groups'),
+ href: dashboard_groups_path,
+ css_class: 'dashboard-shortcuts-groups'
+ },
+ {
+ title: _('Projects'),
+ href: dashboard_projects_path,
+ css_class: 'dashboard-shortcuts-projects'
}
]
diff --git a/app/helpers/sidekiq_helper.rb b/app/helpers/sidekiq_helper.rb
index 07d83b8d850..21aa82aff1c 100644
--- a/app/helpers/sidekiq_helper.rb
+++ b/app/helpers/sidekiq_helper.rb
@@ -8,7 +8,7 @@ module SidekiqHelper
(?<state>[DIEKNRSTVWXZLpsl\+<>/\d]+)\s+
(?<start>.+?)\s+
(?<command>(?:ruby\d+:\s+)?sidekiq.*\].*)
- \z}x.freeze
+ \z}x
def parse_sidekiq_ps(line)
match = line.strip.match(SIDEKIQ_PS_REGEXP)
diff --git a/app/helpers/stat_anchors_helper.rb b/app/helpers/stat_anchors_helper.rb
index d9429f28be7..957985d6953 100644
--- a/app/helpers/stat_anchors_helper.rb
+++ b/app/helpers/stat_anchors_helper.rb
@@ -3,7 +3,7 @@
module StatAnchorsHelper
def stat_anchor_attrs(anchor)
{}.tap do |attrs|
- attrs[:class] = %w(nav-link gl-display-flex gl-align-items-center) << extra_classes(anchor)
+ attrs[:class] = %w[nav-link gl-display-flex gl-align-items-center] << extra_classes(anchor)
attrs[:itemprop] = anchor.itemprop if anchor.itemprop
attrs[:data] = anchor.data if anchor.data
end
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 4f17634f3e4..0d885621b6c 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -272,9 +272,9 @@ module TodosHelper
def show_todo_state?(todo)
case todo.target
when MergeRequest, Issue
- %w(closed merged).include?(todo.target.state)
+ %w[closed merged].include?(todo.target.state)
when AlertManagement::Alert
- %i(resolved).include?(todo.target.state)
+ %i[resolved].include?(todo.target.state)
else
false
end
diff --git a/app/helpers/users/callouts_helper.rb b/app/helpers/users/callouts_helper.rb
index 12f78d9bd16..1b5d0b276a3 100644
--- a/app/helpers/users/callouts_helper.rb
+++ b/app/helpers/users/callouts_helper.rb
@@ -14,7 +14,6 @@ module Users
PAGES_MOVED_CALLOUT = 'pages_moved_callout'
REGISTRATION_ENABLED_CALLOUT_ALLOWED_CONTROLLER_PATHS = [/^root/, /^dashboard\S*/, /^admin\S*/].freeze
WEB_HOOK_DISABLED = 'web_hook_disabled'
- ULTIMATE_FEATURE_REMOVAL_BANNER = 'ultimate_feature_removal_banner'
BRANCH_RULES_INFO_CALLOUT = 'branch_rules_info_callout'
NEW_NAVIGATION_CALLOUT = 'new_navigation_callout'
@@ -94,12 +93,6 @@ module Users
Gitlab.com? && current_user.created_at >= Date.new(2023, 6, 2)
end
- def ultimate_feature_removal_banner_dismissed?(project)
- return false unless project
-
- user_dismissed?(ULTIMATE_FEATURE_REMOVAL_BANNER, object: project)
- end
-
private
def user_dismissed?(feature_name, ignore_dismissal_earlier_than = nil, object: nil)
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index ac279904fd2..30f8f6fdfe5 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -164,7 +164,7 @@ module UsersHelper
messageHtml: message,
actionPrimary: {
text: s_('AdminUsers|Confirm user'),
- attributes: [{ variant: 'confirm', 'data-qa-selector': 'confirm_user_confirm_button' }]
+ attributes: [{ variant: 'confirm', 'data-testid': 'confirm-user-confirm-button' }]
},
actionSecondary: {
text: _('Cancel'),
@@ -176,7 +176,7 @@ module UsersHelper
path: confirm_admin_user_path(user),
method: 'put',
modal_attributes: modal_attributes,
- qa_selector: 'confirm_user_button'
+ testid: 'confirm-user-button'
}
end
diff --git a/app/helpers/version_check_helper.rb b/app/helpers/version_check_helper.rb
index dc8ef4e44be..45a4b292eb5 100644
--- a/app/helpers/version_check_helper.rb
+++ b/app/helpers/version_check_helper.rb
@@ -5,9 +5,8 @@ module VersionCheckHelper
def show_version_check?
return false unless Gitlab::CurrentSettings.version_check_enabled
- return false if User.single_user&.requires_usage_stats_consent?
- current_user&.can_read_all_resources?
+ current_user&.can_read_all_resources? && !User.single_user&.requires_usage_stats_consent?
end
def gitlab_version_check
diff --git a/app/helpers/vite_helper.rb b/app/helpers/vite_helper.rb
new file mode 100644
index 00000000000..4d1085a5169
--- /dev/null
+++ b/app/helpers/vite_helper.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module ViteHelper
+ def universal_javascript_include_tag(*args)
+ if vite_enabled
+ vite_javascript_tag(*args)
+ else
+ javascript_include_tag(*args)
+ end
+ end
+
+ def universal_asset_path(*args)
+ if vite_enabled
+ vite_asset_path(*args)
+ else
+ asset_path(*args)
+ end
+ end
+
+ private
+
+ def vite_enabled
+ Feature.enabled?(:vite) && !Rails.env.test? && vite_running
+ end
+
+ def vite_running
+ ViteRuby.instance.dev_server_running?
+ end
+end
diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb
index ba3c232bec4..92874168798 100644
--- a/app/helpers/webpack_helper.rb
+++ b/app/helpers/webpack_helper.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module WebpackHelper
+ include ViteHelper
+
def prefetch_link_tag(source)
href = asset_path(source)
@@ -14,7 +16,11 @@ module WebpackHelper
end
def webpack_bundle_tag(bundle)
- javascript_include_tag(*webpack_entrypoint_paths(bundle))
+ if vite_running
+ vite_javascript_tag bundle
+ else
+ javascript_include_tag(*webpack_entrypoint_paths(bundle))
+ end
end
def webpack_preload_asset_tag(asset, options = {})
@@ -32,6 +38,8 @@ module WebpackHelper
end
def webpack_controller_bundle_tags
+ return if Feature.enabled?(:vite) && !Rails.env.test?
+
chunks = []
action = case controller.action_name
diff --git a/app/helpers/work_items_helper.rb b/app/helpers/work_items_helper.rb
index 9036c7c8347..1969c98de8b 100644
--- a/app/helpers/work_items_helper.rb
+++ b/app/helpers/work_items_helper.rb
@@ -11,4 +11,10 @@ module WorkItemsHelper
report_abuse_path: add_category_abuse_reports_path
}
end
+
+ def work_items_list_data(group)
+ {
+ full_path: group.full_path
+ }
+ end
end
diff --git a/app/mailers/emails/in_product_marketing.rb b/app/mailers/emails/in_product_marketing.rb
index 972c1da065a..92743dc1926 100644
--- a/app/mailers/emails/in_product_marketing.rb
+++ b/app/mailers/emails/in_product_marketing.rb
@@ -12,15 +12,6 @@ module Emails
'X-Mailgun-Tag' => 'marketing'
}.freeze
- def in_product_marketing_email(recipient_id, group_id, track, series)
- group = Group.find(group_id)
- user = User.find(recipient_id)
- email = user.notification_email_for(group)
- @message = Gitlab::Email::Message::InProductMarketing.for(track).new(group: group, user: user, series: series)
-
- mail_to(to: email, subject: @message.subject_line)
- end
-
def build_ios_app_guide_email(recipient_email)
@message = ::Gitlab::Email::Message::BuildIosAppGuide.new
diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb
index 25d68d47228..a9e1efbdd5d 100644
--- a/app/mailers/emails/profile.rb
+++ b/app/mailers/emails/profile.rb
@@ -2,6 +2,8 @@
module Emails
module Profile
+ include SafeFormatHelper
+
def new_user_email(user_id, token = nil)
@current_user = @user = User.find(user_id)
@target_url = user_url(@user)
@@ -58,6 +60,28 @@ module Emails
end
# rubocop: enable CodeReuse/ActiveRecord
+ def resource_access_tokens_about_to_expire_email(recipient, resource, token_names)
+ @user = recipient
+ @token_names = token_names
+ @days_to_expire = PersonalAccessToken::DAYS_TO_EXPIRE
+ @resource = resource
+ @target_url = if resource.is_a?(Group)
+ group_settings_access_tokens_url(resource)
+ else
+ project_settings_access_tokens_url(resource)
+ end
+
+ mail_with_locale(
+ to: recipient.notification_email_or_default,
+ subject: subject(
+ safe_format(
+ _("Your resource access tokens will expire in %{days_to_expire} or less"),
+ days_to_expire: pluralize(@days_to_expire, _('day'))
+ )
+ )
+ )
+ end
+
def access_token_created_email(user, token_name)
return unless user&.active?
@@ -155,7 +179,7 @@ module Emails
@user = user
@email = email
- mail_with_locale(to: @user.notification_email_or_default, subject: subject(_("New email address added")))
+ email_with_layout(to: @user.notification_email_or_default, subject: subject(_("New email address added")))
end
def new_achievement_email(user, achievement)
diff --git a/app/mailers/emails/service_desk.rb b/app/mailers/emails/service_desk.rb
index f609c9318da..9f3611df2cc 100644
--- a/app/mailers/emails/service_desk.rb
+++ b/app/mailers/emails/service_desk.rb
@@ -4,6 +4,7 @@ module Emails
module ServiceDesk
extend ActiveSupport::Concern
include MarkupHelper
+ include ::ServiceDesk::CustomEmails::Logger
EMAIL_ATTACHMENTS_SIZE_LIMIT = 10.megabytes.freeze
@@ -61,9 +62,10 @@ module Emails
def service_desk_custom_email_verification_email(service_desk_setting)
@service_desk_setting = service_desk_setting
+ @project = @service_desk_setting.project
email_sender = sender(
- User.support_bot.id,
+ Users::Internal.support_bot.id,
send_from_user_email: false,
sender_name: @service_desk_setting.outgoing_name,
sender_email: @service_desk_setting.custom_email
@@ -73,7 +75,7 @@ module Emails
subject = format(s_("Notify|Verify custom email address %{email} for %{project_name}"),
email: @service_desk_setting.custom_email,
- project_name: @service_desk_setting.project.name
+ project_name: @project.name
)
options = {
@@ -119,7 +121,7 @@ module Emails
def setup_service_desk_mail(issue_id)
@issue = Issue.find(issue_id)
@project = @issue.project
- @support_bot = User.support_bot
+ @support_bot = Users::Internal.support_bot
@service_desk_setting = @project.service_desk_setting
@@ -139,6 +141,11 @@ module Emails
return mail if !service_desk_custom_email_enabled? && !force
return mail unless @service_desk_setting.custom_email_credential.present?
+ # Only set custom email reply address if it's enabled, not when we force it.
+ inject_service_desk_custom_email_reply_address unless force
+
+ log_info(project: @project)
+
mail.delivery_method(::Mail::SMTP, @service_desk_setting.custom_email_credential.delivery_options)
end
@@ -146,6 +153,15 @@ module Emails
Feature.enabled?(:service_desk_custom_email, @project) && @service_desk_setting&.custom_email_enabled?
end
+ def inject_service_desk_custom_email_reply_address
+ return unless Feature.enabled?(:service_desk_custom_email_reply, @project)
+
+ reply_address = Gitlab::Email::ServiceDesk::CustomEmail.reply_address(@issue, reply_key)
+ headers['Reply-To'] = Mail::Address.new(reply_address).tap do |address|
+ address.display_name = reply_display_name(@issue)
+ end
+ end
+
def service_desk_sender_email_address
return unless service_desk_custom_email_enabled?
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 4180e76e1a0..77d32a55941 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -208,6 +208,7 @@ class Notify < ApplicationMailer
headers["#{prefix}-ID"] = object.id
headers["#{prefix}-IID"] = object.iid if object.respond_to?(:iid)
+ headers["#{prefix}-State"] = object.state if object.respond_to?(:state)
end
def add_project_headers
diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb
index f43f4511913..638df56b770 100644
--- a/app/mailers/previews/notify_preview.rb
+++ b/app/mailers/previews/notify_preview.rb
@@ -64,6 +64,10 @@ class NotifyPreview < ActionMailer::Preview
end
end
+ def resource_access_token_about_to_expire_email
+ Notify.resource_access_tokens_about_to_expire_email(user, group, ['token_name'])
+ end
+
def access_token_created_email
Notify.access_token_created_email(user, 'token_name').message
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 4da4d113a7f..d8510524c1f 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -46,6 +46,7 @@ class Ability
issues.select { |issue| issue.visible_to_user?(user) }
end
end
+ alias_method :work_items_readable_by_user, :issues_readable_by_user
# Returns an Array of MergeRequests that can be read by the given user.
#
diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb
index 75c90d370c3..bf25c539830 100644
--- a/app/models/abuse_report.rb
+++ b/app/models/abuse_report.rb
@@ -61,10 +61,11 @@ class AbuseReport < ApplicationRecord
validates :screenshot, file_size: { maximum: MAX_FILE_SIZE }
validate :validate_screenshot_is_image
- scope :by_user_id, ->(id) { where(user_id: id) }
- scope :by_reporter_id, ->(id) { where(reporter_id: id) }
+ scope :by_user_id, ->(user_id) { where(user_id: user_id) }
+ scope :by_reporter_id, ->(reporter_id) { where(reporter_id: reporter_id) }
scope :by_category, ->(category) { where(category: category) }
scope :with_users, -> { includes(:reporter, :user) }
+ scope :with_labels, -> { includes(:labels) }
enum category: {
spam: 1,
@@ -141,8 +142,14 @@ class AbuseReport < ApplicationRecord
end
end
- def other_reports_for_user
- user.abuse_reports.id_not_in(id)
+ def past_closed_reports_for_user
+ user.abuse_reports.closed.id_not_in(id)
+ end
+
+ def similar_open_reports_for_user
+ return AbuseReport.none unless open?
+
+ user.abuse_reports.open.by_category(category).id_not_in(id).includes(:reporter)
end
private
diff --git a/app/models/active_session.rb b/app/models/active_session.rb
index 7d025fb7738..e42f9eeef23 100644
--- a/app/models/active_session.rb
+++ b/app/models/active_session.rb
@@ -102,17 +102,16 @@ class ActiveSession
# set marketing cookie when user has active session
def self.set_active_user_cookie(auth)
- auth.cookies[:about_gitlab_active_user] =
+ expiration_time = 2.weeks.from_now
+
+ auth.cookies[:gitlab_user] =
{
value: true,
- domain: Gitlab.config.gitlab.host
+ domain: Gitlab.config.gitlab.host,
+ expires: expiration_time
}
end
- def self.unset_active_user_cookie(auth)
- auth.cookies.delete :about_gitlab_active_user
- end
-
def self.list(user)
Gitlab::Redis::Sessions.with do |redis|
cleaned_up_lookup_entries(redis, user).map do |raw_session|
diff --git a/app/models/alerting/project_alerting_setting.rb b/app/models/alerting/project_alerting_setting.rb
index 34fa27eb29b..7e94d41137f 100644
--- a/app/models/alerting/project_alerting_setting.rb
+++ b/app/models/alerting/project_alerting_setting.rb
@@ -14,6 +14,8 @@ module Alerting
algorithm: 'aes-256-gcm'
before_validation :ensure_token
+ after_create :create_http_integration
+ after_update :sync_http_integration
private
@@ -24,5 +26,31 @@ module Alerting
def generate_token
SecureRandom.hex
end
+
+ # Remove in next required stop after %16.4
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/338838
+ def sync_http_integration
+ project.alert_management_http_integrations
+ .for_endpoint_identifier('legacy-prometheus')
+ .take
+ &.update_columns(
+ encrypted_token: encrypted_token,
+ encrypted_token_iv: encrypted_token_iv
+ )
+ end
+
+ # Remove in next required stop after %16.4
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/338838
+ def create_http_integration
+ AlertManagement::HttpIntegration.insert({
+ project_id: project_id,
+ encrypted_token: encrypted_token,
+ encrypted_token_iv: encrypted_token_iv,
+ active: true,
+ name: 'Prometheus',
+ endpoint_identifier: 'legacy-prometheus',
+ type_identifier: :prometheus
+ })
+ end
end
end
diff --git a/app/models/analytics/cycle_analytics/runtime_limiter.rb b/app/models/analytics/cycle_analytics/runtime_limiter.rb
new file mode 100644
index 00000000000..063377c3ddb
--- /dev/null
+++ b/app/models/analytics/cycle_analytics/runtime_limiter.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Analytics
+ module CycleAnalytics
+ class RuntimeLimiter
+ delegate :monotonic_time, to: :'Gitlab::Metrics::System'
+
+ DEFAULT_MAX_RUNTIME = 200.seconds
+
+ attr_reader :max_runtime, :start_time
+
+ def initialize(max_runtime = DEFAULT_MAX_RUNTIME)
+ @start_time = monotonic_time
+ @max_runtime = max_runtime
+ end
+
+ def elapsed_time
+ monotonic_time - start_time
+ end
+
+ def over_time?
+ @last_check = elapsed_time >= max_runtime
+ end
+
+ def was_over_time?
+ !!@last_check
+ end
+ end
+ end
+end
diff --git a/app/models/analytics/cycle_analytics/stage_event_hash.rb b/app/models/analytics/cycle_analytics/stage_event_hash.rb
index 6443a970945..7dcabd01ebf 100644
--- a/app/models/analytics/cycle_analytics/stage_event_hash.rb
+++ b/app/models/analytics/cycle_analytics/stage_event_hash.rb
@@ -13,7 +13,7 @@ module Analytics
# Atomic, safe insert without retrying
query = <<~SQL
- WITH insert_cte AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH insert_cte AS MATERIALIZED (
INSERT INTO #{quoted_table_name} (hash_sha256) VALUES (#{casted_hash_code}) ON CONFLICT DO NOTHING RETURNING ID
)
SELECT ids.id FROM (
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index f67efaf4f58..153257636ba 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -14,38 +14,30 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
ignore_column :send_user_confirmation_email, remove_with: '15.8', remove_after: '2022-12-18'
ignore_column :web_ide_clientside_preview_enabled, remove_with: '15.11', remove_after: '2023-04-22'
ignore_columns %i[instance_administration_project_id instance_administrators_group_id], remove_with: '16.2', remove_after: '2023-06-22'
- ignore_columns %i[
- encrypted_tofa_access_token_expires_in
- encrypted_tofa_access_token_expires_in_iv
- encrypted_tofa_client_library_args
- encrypted_tofa_client_library_args_iv
- encrypted_tofa_client_library_class
- encrypted_tofa_client_library_class_iv
- encrypted_tofa_client_library_create_credentials_method
- encrypted_tofa_client_library_create_credentials_method_iv
- encrypted_tofa_client_library_fetch_access_token_method
- encrypted_tofa_client_library_fetch_access_token_method_iv
- encrypted_tofa_credentials
- encrypted_tofa_credentials_iv
- encrypted_tofa_host
- encrypted_tofa_host_iv
- encrypted_tofa_request_json_keys
- encrypted_tofa_request_json_keys_iv
- encrypted_tofa_request_payload
- encrypted_tofa_request_payload_iv
- encrypted_tofa_response_json_keys
- encrypted_tofa_response_json_keys_iv
- encrypted_tofa_url
- encrypted_tofa_url_iv
- vertex_project
- ], remove_with: '16.3', remove_after: '2023-07-22'
ignore_column :database_apdex_settings, remove_with: '16.4', remove_after: '2023-08-22'
+
ignore_columns %i[
dashboard_notification_limit
dashboard_enforcement_limit
dashboard_limit_new_namespace_creation_enforcement_date
], remove_with: '16.5', remove_after: '2023-08-22'
+ ignore_column %i[
+ relay_state_domain_allowlist
+ in_product_marketing_emails_enabled
+ ], remove_with: '16.6', remove_after: '2023-10-22'
+
+ ignore_columns %i[
+ encrypted_product_analytics_clickhouse_connection_string
+ encrypted_product_analytics_clickhouse_connection_string_iv
+ encrypted_jitsu_administrator_password
+ encrypted_jitsu_administrator_password_iv
+ jitsu_host
+ jitsu_project_xid
+ jitsu_administrator_email
+ ], remove_with: '16.5', remove_after: '2023-09-22'
+ ignore_columns %i[ai_access_token ai_access_token_iv], remove_with: '16.6', remove_after: '2023-10-22'
+
INSTANCE_REVIEW_MIN_USERS = 50
GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
'Admin Area > Settings > Metrics and profiling > Metrics - Grafana'
@@ -244,6 +236,11 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
hostname: true,
if: :snowplow_enabled
+ validates :snowplow_database_collector_hostname,
+ allow_blank: true,
+ hostname: true,
+ length: { maximum: 255 }
+
validates :max_attachment_size,
presence: true,
numericality: { only_integer: true, greater_than: 0 }
@@ -300,6 +297,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
presence: true,
numericality: { only_integer: true, greater_than: 0 }
+ validates :decompress_archive_file_timeout,
+ presence: true,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+
validates :repository_storages, presence: true
validate :check_repository_storages
validate :check_repository_storages_weighted
@@ -310,7 +311,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
if: :auto_devops_enabled?
validates :enabled_git_access_protocol,
- inclusion: { in: %w(ssh http), allow_blank: true }
+ inclusion: { in: %w[ssh http], allow_blank: true }
validates :domain_denylist,
presence: { message: 'Domain denylist cannot be empty if denylist is enabled.' },
@@ -551,7 +552,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
if: :external_authorization_service_enabled
validates :spam_check_endpoint_url,
- addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({ schemes: %w(tls grpc) }), allow_blank: true
+ addressable_url: ADDRESSABLE_URL_VALIDATION_OPTIONS.merge({ schemes: %w[tls grpc] }), allow_blank: true
validates :spam_check_endpoint_url,
presence: true,
@@ -666,6 +667,10 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
validates :gitlab_shell_operation_limit
end
+ validates :search_rate_limit_allowlist,
+ length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
+ allow_nil: false
+
validates :notes_create_limit_allowlist,
length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') },
allow_nil: false
@@ -794,18 +799,20 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
attr_encrypted :arkose_labs_public_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :arkose_labs_private_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :cube_api_key, encryption_options_base_32_aes_256_gcm
- attr_encrypted :jitsu_administrator_password, encryption_options_base_32_aes_256_gcm
attr_encrypted :telesign_customer_xid, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :telesign_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
- attr_encrypted :product_analytics_clickhouse_connection_string, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :product_analytics_configurator_connection_string, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :openai_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :anthropic_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
- attr_encrypted :ai_access_token, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :vertex_ai_credentials, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ # Restricting the validation to `on: :update` only to avoid cyclical dependencies with
+ # License <--> ApplicationSetting. This method calls a license check when we create
+ # ApplicationSetting from defaults which in turn depends on ApplicationSetting record.
+ # The currect default is defined in the `defaults` method so we don't need to validate
+ # it here.
validates :disable_feed_token,
- inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ inclusion: { in: [true, false], message: N_('must be a boolean value') }, on: :update
validates :disable_admin_oauth_scopes,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
@@ -962,7 +969,7 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
end
def parsed_kroki_url
- @parsed_kroki_url ||= Gitlab::UrlBlocker.validate!(kroki_url, schemes: %w(http https), enforce_sanitization: true)[0]
+ @parsed_kroki_url ||= Gitlab::UrlBlocker.validate!(kroki_url, schemes: %w[http https], enforce_sanitization: true)[0]
rescue Gitlab::UrlBlocker::BlockedUrlError => e
self.errors.add(
:kroki_url,
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index f6bf535158a..5a90e246499 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -9,12 +9,12 @@ module ApplicationSettingImplementation
\s # any whitespace character
| # or
[\r\n] # any number of newline characters
- }x.freeze
+ }x
# Setting a key restriction to `-1` means that all keys of this type are
# forbidden.
FORBIDDEN_KEY_VALUE = KeyRestrictionValidator::FORBIDDEN
- VALID_RUNNER_REGISTRAR_TYPES = %w(project group).freeze
+ VALID_RUNNER_REGISTRAR_TYPES = %w[project group].freeze
DEFAULT_PROTECTED_PATHS = [
'/users/password',
@@ -37,7 +37,6 @@ module ApplicationSettingImplementation
{
admin_mode: false,
after_sign_up_text: nil,
- ai_access_token: nil,
akismet_enabled: false,
akismet_api_key: nil,
allow_local_requests_from_system_hooks: true,
@@ -53,6 +52,7 @@ module ApplicationSettingImplementation
container_registry_vendor: '',
container_registry_version: '',
custom_http_clone_url_root: nil,
+ decompress_archive_file_timeout: 210,
default_artifacts_expire_in: '30 days',
default_branch_name: nil,
default_branch_protection: Settings.gitlab['default_branch_protection'],
@@ -171,6 +171,7 @@ module ApplicationSettingImplementation
snowplow_app_id: nil,
snowplow_collector_hostname: nil,
snowplow_cookie_domain: nil,
+ snowplow_database_collector_hostname: nil,
snowplow_enabled: false,
sourcegraph_enabled: false,
sourcegraph_public_only: true,
@@ -254,6 +255,7 @@ module ApplicationSettingImplementation
user_deactivation_emails_enabled: true,
search_rate_limit: 30,
search_rate_limit_unauthenticated: 10,
+ search_rate_limit_allowlist: [],
users_get_by_id_limit: 300,
users_get_by_id_limit_allowlist: [],
can_create_group: true,
@@ -380,6 +382,14 @@ module ApplicationSettingImplementation
self.protected_paths = strings_to_array(values)
end
+ def protected_paths_for_get_request_raw
+ array_to_string(protected_paths_for_get_request)
+ end
+
+ def protected_paths_for_get_request_raw=(values)
+ self.protected_paths_for_get_request = strings_to_array(values)
+ end
+
def notes_create_limit_allowlist_raw
array_to_string(notes_create_limit_allowlist)
end
@@ -396,6 +406,14 @@ module ApplicationSettingImplementation
self.users_get_by_id_limit_allowlist = strings_to_array(values).map(&:downcase)
end
+ def search_rate_limit_allowlist_raw
+ array_to_string(search_rate_limit_allowlist)
+ end
+
+ def search_rate_limit_allowlist_raw=(values)
+ self.search_rate_limit_allowlist = strings_to_array(values).map(&:downcase)
+ end
+
def asset_proxy_whitelist=(values)
values = strings_to_array(values) if values.is_a?(String)
diff --git a/app/models/approval.rb b/app/models/approval.rb
index 9ded44fe425..ecc15077c8d 100644
--- a/app/models/approval.rb
+++ b/app/models/approval.rb
@@ -3,10 +3,13 @@
class Approval < ApplicationRecord
include CreatedAtFilterable
include Importable
+ include ShaAttribute
belongs_to :user
belongs_to :merge_request
+ sha_attribute :patch_id_sha
+
validates :merge_request_id, presence: true, unless: :importing?
validates :user_id, presence: true, uniqueness: { scope: [:merge_request_id] }
diff --git a/app/models/award_emoji.rb b/app/models/award_emoji.rb
index ebc43b04b1b..73e3fa709b0 100644
--- a/app/models/award_emoji.rb
+++ b/app/models/award_emoji.rb
@@ -78,7 +78,7 @@ class AwardEmoji < ApplicationRecord
end
def broadcast_note_update
- awardable.expire_etag_cache
+ awardable.broadcast_noteable_notes_changed
awardable.trigger_note_subscription_update
end
diff --git a/app/models/badge.rb b/app/models/badge.rb
index 23e6f305c32..f4e719887ba 100644
--- a/app/models/badge.rb
+++ b/app/models/badge.rb
@@ -18,7 +18,7 @@ class Badge < ApplicationRecord
# This regex is built dynamically using the keys from the PLACEHOLDER struct.
# So, we can easily add new placeholder just by modifying the PLACEHOLDER hash.
# This regex will build the new PLACEHOLDER_REGEX with the new information
- PLACEHOLDERS_REGEX = /(#{PLACEHOLDERS.keys.join('|')})/.freeze
+ PLACEHOLDERS_REGEX = /(#{PLACEHOLDERS.keys.join('|')})/
default_scope { order_created_at_asc } # rubocop:disable Cop/DefaultScope
diff --git a/app/models/blob_viewer/binary_stl.rb b/app/models/blob_viewer/binary_stl.rb
index 425f72decae..6ccf75200e5 100644
--- a/app/models/blob_viewer/binary_stl.rb
+++ b/app/models/blob_viewer/binary_stl.rb
@@ -6,7 +6,7 @@ module BlobViewer
include ClientSide
self.partial_name = 'stl'
- self.extensions = %w(stl)
+ self.extensions = %w[stl]
self.binary = true
end
end
diff --git a/app/models/blob_viewer/cargo_toml.rb b/app/models/blob_viewer/cargo_toml.rb
index 2f1ebd25b4f..eb2a6f4433d 100644
--- a/app/models/blob_viewer/cargo_toml.rb
+++ b/app/models/blob_viewer/cargo_toml.rb
@@ -4,7 +4,7 @@ module BlobViewer
class CargoToml < DependencyManager
include Static
- self.file_types = %i(cargo_toml)
+ self.file_types = %i[cargo_toml]
def manager_name
'Cargo'
diff --git a/app/models/blob_viewer/cartfile.rb b/app/models/blob_viewer/cartfile.rb
index ea0494033bf..58fc97a9ffc 100644
--- a/app/models/blob_viewer/cartfile.rb
+++ b/app/models/blob_viewer/cartfile.rb
@@ -4,7 +4,7 @@ module BlobViewer
class Cartfile < DependencyManager
include Static
- self.file_types = %i(cartfile)
+ self.file_types = %i[cartfile]
def manager_name
'Carthage'
diff --git a/app/models/blob_viewer/changelog.rb b/app/models/blob_viewer/changelog.rb
index 8810bd25809..7992fbf542c 100644
--- a/app/models/blob_viewer/changelog.rb
+++ b/app/models/blob_viewer/changelog.rb
@@ -6,7 +6,7 @@ module BlobViewer
include Static
self.partial_name = 'changelog'
- self.file_types = %i(changelog)
+ self.file_types = %i[changelog]
self.binary = false
def render_error
diff --git a/app/models/blob_viewer/composer_json.rb b/app/models/blob_viewer/composer_json.rb
index aac7271242e..3449780f50f 100644
--- a/app/models/blob_viewer/composer_json.rb
+++ b/app/models/blob_viewer/composer_json.rb
@@ -4,7 +4,7 @@ module BlobViewer
class ComposerJson < DependencyManager
include ServerSide
- self.file_types = %i(composer_json)
+ self.file_types = %i[composer_json]
def manager_name
'Composer'
diff --git a/app/models/blob_viewer/contributing.rb b/app/models/blob_viewer/contributing.rb
index fa224309e31..524104f176a 100644
--- a/app/models/blob_viewer/contributing.rb
+++ b/app/models/blob_viewer/contributing.rb
@@ -6,7 +6,7 @@ module BlobViewer
include Static
self.partial_name = 'contributing'
- self.file_types = %i(contributing)
+ self.file_types = %i[contributing]
self.binary = false
end
end
diff --git a/app/models/blob_viewer/csv.rb b/app/models/blob_viewer/csv.rb
index 633e3bd63d8..97fa890653d 100644
--- a/app/models/blob_viewer/csv.rb
+++ b/app/models/blob_viewer/csv.rb
@@ -6,7 +6,7 @@ module BlobViewer
include ClientSide
self.binary = false
- self.extensions = %w(csv)
+ self.extensions = %w[csv]
self.partial_name = 'csv'
self.switcher_icon = 'table'
end
diff --git a/app/models/blob_viewer/gemfile.rb b/app/models/blob_viewer/gemfile.rb
index 77220cdbd08..84edacb32bd 100644
--- a/app/models/blob_viewer/gemfile.rb
+++ b/app/models/blob_viewer/gemfile.rb
@@ -4,7 +4,7 @@ module BlobViewer
class Gemfile < DependencyManager
include Static
- self.file_types = %i(gemfile gemfile_lock)
+ self.file_types = %i[gemfile gemfile_lock]
def manager_name
'Bundler'
diff --git a/app/models/blob_viewer/gemspec.rb b/app/models/blob_viewer/gemspec.rb
index 274859a7710..645458467f4 100644
--- a/app/models/blob_viewer/gemspec.rb
+++ b/app/models/blob_viewer/gemspec.rb
@@ -4,7 +4,7 @@ module BlobViewer
class Gemspec < DependencyManager
include ServerSide
- self.file_types = %i(gemspec)
+ self.file_types = %i[gemspec]
def manager_name
'RubyGems'
diff --git a/app/models/blob_viewer/gitlab_ci_yml.rb b/app/models/blob_viewer/gitlab_ci_yml.rb
index e255b6d15d2..9cee536d15b 100644
--- a/app/models/blob_viewer/gitlab_ci_yml.rb
+++ b/app/models/blob_viewer/gitlab_ci_yml.rb
@@ -7,7 +7,7 @@ module BlobViewer
self.partial_name = 'gitlab_ci_yml'
self.loading_partial_name = 'gitlab_ci_yml_loading'
- self.file_types = %i(gitlab_ci)
+ self.file_types = %i[gitlab_ci]
self.binary = false
def validation_message(opts)
diff --git a/app/models/blob_viewer/go_mod.rb b/app/models/blob_viewer/go_mod.rb
index d4d117f899c..eebf057c6dc 100644
--- a/app/models/blob_viewer/go_mod.rb
+++ b/app/models/blob_viewer/go_mod.rb
@@ -11,9 +11,9 @@ module BlobViewer
(?<name>.*?) (?# module name)
\s*(?://.*)? (?# comment)
(?:\n|\z) (?# newline or end of file)
- }x.freeze
+ }x
- self.file_types = %i(go_mod go_sum)
+ self.file_types = %i[go_mod go_sum]
def manager_name
'Go Modules'
diff --git a/app/models/blob_viewer/godeps_json.rb b/app/models/blob_viewer/godeps_json.rb
index 743c759aea5..37a133848a0 100644
--- a/app/models/blob_viewer/godeps_json.rb
+++ b/app/models/blob_viewer/godeps_json.rb
@@ -4,7 +4,7 @@ module BlobViewer
class GodepsJson < DependencyManager
include Static
- self.file_types = %i(godeps_json)
+ self.file_types = %i[godeps_json]
def manager_name
'godep'
diff --git a/app/models/blob_viewer/license.rb b/app/models/blob_viewer/license.rb
index 3427227ad26..489b29380d0 100644
--- a/app/models/blob_viewer/license.rb
+++ b/app/models/blob_viewer/license.rb
@@ -6,7 +6,7 @@ module BlobViewer
include Static
self.partial_name = 'license'
- self.file_types = %i(license)
+ self.file_types = %i[license]
self.binary = false
def license
diff --git a/app/models/blob_viewer/markup.rb b/app/models/blob_viewer/markup.rb
index 6f002a6b224..4b04d8425fd 100644
--- a/app/models/blob_viewer/markup.rb
+++ b/app/models/blob_viewer/markup.rb
@@ -7,7 +7,7 @@ module BlobViewer
self.partial_name = 'markup'
self.extensions = Gitlab::MarkupHelper::EXTENSIONS
- self.file_types = %i(readme)
+ self.file_types = %i[readme]
self.binary = false
def banzai_render_context
diff --git a/app/models/blob_viewer/notebook.rb b/app/models/blob_viewer/notebook.rb
index 351502d451f..e6f1988d7a6 100644
--- a/app/models/blob_viewer/notebook.rb
+++ b/app/models/blob_viewer/notebook.rb
@@ -6,7 +6,7 @@ module BlobViewer
include ClientSide
self.partial_name = 'notebook'
- self.extensions = %w(ipynb)
+ self.extensions = %w[ipynb]
self.binary = false
self.switcher_icon = 'doc-text'
self.switcher_title = 'notebook'
diff --git a/app/models/blob_viewer/open_api.rb b/app/models/blob_viewer/open_api.rb
index 0551f3bb1e3..5d9c5bea8dc 100644
--- a/app/models/blob_viewer/open_api.rb
+++ b/app/models/blob_viewer/open_api.rb
@@ -6,7 +6,7 @@ module BlobViewer
include ClientSide
self.partial_name = 'openapi'
- self.file_types = %i(openapi)
+ self.file_types = %i[openapi]
self.binary = false
self.switcher_icon = 'api'
end
diff --git a/app/models/blob_viewer/package_json.rb b/app/models/blob_viewer/package_json.rb
index 5350b6b0626..c205c10b536 100644
--- a/app/models/blob_viewer/package_json.rb
+++ b/app/models/blob_viewer/package_json.rb
@@ -4,7 +4,7 @@ module BlobViewer
class PackageJson < DependencyManager
include ServerSide
- self.file_types = %i(package_json)
+ self.file_types = %i[package_json]
def manager_name
yarn? ? 'yarn' : 'npm'
diff --git a/app/models/blob_viewer/pdf.rb b/app/models/blob_viewer/pdf.rb
index e3542b91d5c..61957ef4228 100644
--- a/app/models/blob_viewer/pdf.rb
+++ b/app/models/blob_viewer/pdf.rb
@@ -6,7 +6,7 @@ module BlobViewer
include ClientSide
self.partial_name = 'pdf'
- self.extensions = %w(pdf)
+ self.extensions = %w[pdf]
self.binary = true
self.switcher_icon = 'document'
self.switcher_title = 'PDF'
diff --git a/app/models/blob_viewer/podfile.rb b/app/models/blob_viewer/podfile.rb
index 73d714f48ca..dcabcfc4d57 100644
--- a/app/models/blob_viewer/podfile.rb
+++ b/app/models/blob_viewer/podfile.rb
@@ -4,7 +4,7 @@ module BlobViewer
class Podfile < DependencyManager
include Static
- self.file_types = %i(podfile)
+ self.file_types = %i[podfile]
def manager_name
'CocoaPods'
diff --git a/app/models/blob_viewer/podspec.rb b/app/models/blob_viewer/podspec.rb
index 2303471583d..50ca3f5bd16 100644
--- a/app/models/blob_viewer/podspec.rb
+++ b/app/models/blob_viewer/podspec.rb
@@ -4,7 +4,7 @@ module BlobViewer
class Podspec < DependencyManager
include ServerSide
- self.file_types = %i(podspec)
+ self.file_types = %i[podspec]
def manager_name
'CocoaPods'
diff --git a/app/models/blob_viewer/podspec_json.rb b/app/models/blob_viewer/podspec_json.rb
index d606f72376d..03e680e2a8b 100644
--- a/app/models/blob_viewer/podspec_json.rb
+++ b/app/models/blob_viewer/podspec_json.rb
@@ -2,7 +2,7 @@
module BlobViewer
class PodspecJson < Podspec
- self.file_types = %i(podspec_json)
+ self.file_types = %i[podspec_json]
def package_name
@package_name ||= fetch_from_json('name')
diff --git a/app/models/blob_viewer/readme.rb b/app/models/blob_viewer/readme.rb
index f1a5c6a6acc..ec84977d8c5 100644
--- a/app/models/blob_viewer/readme.rb
+++ b/app/models/blob_viewer/readme.rb
@@ -6,7 +6,7 @@ module BlobViewer
include Static
self.partial_name = 'readme'
- self.file_types = %i(readme)
+ self.file_types = %i[readme]
self.binary = false
def visible_to?(current_user)
diff --git a/app/models/blob_viewer/requirements_txt.rb b/app/models/blob_viewer/requirements_txt.rb
index 58161e83493..7322e416c4c 100644
--- a/app/models/blob_viewer/requirements_txt.rb
+++ b/app/models/blob_viewer/requirements_txt.rb
@@ -4,7 +4,7 @@ module BlobViewer
class RequirementsTxt < DependencyManager
include Static
- self.file_types = %i(requirements_txt)
+ self.file_types = %i[requirements_txt]
def manager_name
'pip'
diff --git a/app/models/blob_viewer/route_map.rb b/app/models/blob_viewer/route_map.rb
index 6731536dfe1..a8c64bd5e6a 100644
--- a/app/models/blob_viewer/route_map.rb
+++ b/app/models/blob_viewer/route_map.rb
@@ -7,7 +7,7 @@ module BlobViewer
self.partial_name = 'route_map'
self.loading_partial_name = 'route_map_loading'
- self.file_types = %i(route_map)
+ self.file_types = %i[route_map]
self.binary = false
def validation_message
diff --git a/app/models/blob_viewer/sketch.rb b/app/models/blob_viewer/sketch.rb
index 90bc9be29f4..b7b1d412eff 100644
--- a/app/models/blob_viewer/sketch.rb
+++ b/app/models/blob_viewer/sketch.rb
@@ -6,7 +6,7 @@ module BlobViewer
include ClientSide
self.partial_name = 'sketch'
- self.extensions = %w(sketch)
+ self.extensions = %w[sketch]
self.binary = true
self.switcher_icon = 'doc-image'
self.switcher_title = 'preview'
diff --git a/app/models/blob_viewer/svg.rb b/app/models/blob_viewer/svg.rb
index 60a11fbd97e..afcd3a7c735 100644
--- a/app/models/blob_viewer/svg.rb
+++ b/app/models/blob_viewer/svg.rb
@@ -6,7 +6,7 @@ module BlobViewer
include ServerSide
self.partial_name = 'svg'
- self.extensions = %w(svg)
+ self.extensions = %w[svg]
self.binary = false
self.switcher_icon = 'doc-image'
self.switcher_title = 'image'
diff --git a/app/models/blob_viewer/yarn_lock.rb b/app/models/blob_viewer/yarn_lock.rb
index 196d9f96f23..75369370602 100644
--- a/app/models/blob_viewer/yarn_lock.rb
+++ b/app/models/blob_viewer/yarn_lock.rb
@@ -4,7 +4,7 @@ module BlobViewer
class YarnLock < DependencyManager
include Static
- self.file_types = %i(yarn_lock)
+ self.file_types = %i[yarn_lock]
def manager_name
'Yarn'
diff --git a/app/models/bulk_imports/batch_tracker.rb b/app/models/bulk_imports/batch_tracker.rb
index 2e79d41d46e..eb7fe9f9913 100644
--- a/app/models/bulk_imports/batch_tracker.rb
+++ b/app/models/bulk_imports/batch_tracker.rb
@@ -18,6 +18,8 @@ module BulkImports
event :start do
transition created: :started
+ # To avoid errors when re-starting a pipeline in case of network errors
+ transition started: :started
end
event :retry do
diff --git a/app/models/bulk_imports/entity.rb b/app/models/bulk_imports/entity.rb
index 644673e249e..437118c36e8 100644
--- a/app/models/bulk_imports/entity.rb
+++ b/app/models/bulk_imports/entity.rb
@@ -196,6 +196,10 @@ class BulkImports::Entity < ApplicationRecord
update!(has_failures: true)
end
+ def source_version
+ @source_version ||= bulk_import.source_version_info
+ end
+
private
def validate_parent_is_a_group
@@ -240,7 +244,9 @@ class BulkImports::Entity < ApplicationRecord
errors.add(
:source_full_path,
- Gitlab::Regex.bulk_import_source_full_path_regex_message
+ s_('BulkImport|must have a relative path structure with no HTTP ' \
+ 'protocol characters, or leading or trailing forward slashes. Path segments must not start or ' \
+ 'end with a special character, and must not contain consecutive special characters')
)
end
end
diff --git a/app/models/bulk_imports/file_transfer/group_config.rb b/app/models/bulk_imports/file_transfer/group_config.rb
index 6766c00246b..67d53056444 100644
--- a/app/models/bulk_imports/file_transfer/group_config.rb
+++ b/app/models/bulk_imports/file_transfer/group_config.rb
@@ -3,7 +3,7 @@
module BulkImports
module FileTransfer
class GroupConfig < BaseConfig
- SKIPPED_RELATIONS = %w(members).freeze
+ SKIPPED_RELATIONS = %w[members].freeze
def import_export_yaml
::Gitlab::ImportExport.group_config_file
diff --git a/app/models/bulk_imports/file_transfer/project_config.rb b/app/models/bulk_imports/file_transfer/project_config.rb
index 8d4c68f7b5a..890a0fb6ee4 100644
--- a/app/models/bulk_imports/file_transfer/project_config.rb
+++ b/app/models/bulk_imports/file_transfer/project_config.rb
@@ -3,10 +3,10 @@
module BulkImports
module FileTransfer
class ProjectConfig < BaseConfig
- SKIPPED_RELATIONS = %w(
+ SKIPPED_RELATIONS = %w[
project_members
group_members
- ).freeze
+ ].freeze
LFS_OBJECTS_RELATION = 'lfs_objects'
REPOSITORY_BUNDLE_RELATION = 'repository'
diff --git a/app/models/chat_name.rb b/app/models/chat_name.rb
index cda19273f52..d3fbfe3aa55 100644
--- a/app/models/chat_name.rb
+++ b/app/models/chat_name.rb
@@ -3,9 +3,6 @@
class ChatName < ApplicationRecord
LAST_USED_AT_INTERVAL = 1.hour
- include IgnorableColumns
- ignore_column :integration_id, remove_with: '16.0', remove_after: '2023-04-22'
-
belongs_to :user
validates :user, presence: true
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 7a623b0cefb..2abb8e4be48 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -165,7 +165,10 @@ module Ci
scope :with_live_trace, -> { where('EXISTS (?)', Ci::BuildTraceChunk.where("#{quoted_table_name}.id = #{Ci::BuildTraceChunk.quoted_table_name}.build_id").select(1)) }
scope :with_stale_live_trace, -> { with_live_trace.finished_before(12.hours.ago) }
scope :finished_before, -> (date) { finished.where('finished_at < ?', date) }
- scope :license_management_jobs, -> { where(name: %i(license_management license_scanning)) } # handle license rename https://gitlab.com/gitlab-org/gitlab/issues/8911
+ scope :license_management_jobs, -> { where(name: %i[license_management license_scanning]) } # handle license rename https://gitlab.com/gitlab-org/gitlab/issues/8911
+ # WARNING: This scope could lead to performance implications for large size of tables `ci_builds` and ci_runners`.
+ # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123131
+ scope :with_runner_type, -> (runner_type) { joins(:runner).where(runner: { runner_type: runner_type }) }
scope :with_secure_reports_from_config_options, -> (job_types) do
joins(:metadata).where("#{Ci::BuildMetadata.quoted_table_name}.config_options -> 'artifacts' -> 'reports' ?| array[:job_types]", job_types: job_types)
@@ -388,6 +391,9 @@ module Ci
name == 'pages'
end
+ # overridden on EE
+ def pages_path_prefix; end
+
def runnable?
true
end
@@ -408,7 +414,7 @@ module Ci
end
def options_scheduled_at
- ChronicDuration.parse(options[:start_in])&.seconds&.from_now
+ ChronicDuration.parse(options[:start_in], use_complete_matcher: true)&.seconds&.from_now
end
def action?
@@ -487,10 +493,7 @@ module Ci
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless persisted? && persisted_environment.present?
- variables.concat(persisted_environment.predefined_variables)
-
- variables.append(key: 'CI_ENVIRONMENT_ACTION', value: environment_action)
- variables.append(key: 'CI_ENVIRONMENT_TIER', value: environment_tier)
+ variables.append(key: 'CI_ENVIRONMENT_SLUG', value: environment_slug)
# Here we're passing unexpanded environment_url for runner to expand,
# and we need to make sure that CI_ENVIRONMENT_NAME and
@@ -735,7 +738,7 @@ module Ci
def artifacts_expire_in=(value)
self.artifacts_expire_at =
if value
- ChronicDuration.parse(value)&.seconds&.from_now
+ ChronicDuration.parse(value, use_complete_matcher: true)&.seconds&.from_now
end
end
@@ -1039,6 +1042,13 @@ module Ci
end
end
+ def time_in_queue_seconds
+ return if queued_at.nil?
+
+ (::Time.current - queued_at).seconds.to_i
+ end
+ strong_memoize_attr :time_in_queue_seconds
+
protected
def run_status_commit_hooks!
diff --git a/app/models/ci/build_need.rb b/app/models/ci/build_need.rb
index 317f2523f69..00241908644 100644
--- a/app/models/ci/build_need.rb
+++ b/app/models/ci/build_need.rb
@@ -7,15 +7,16 @@ module Ci
include SafelyChangeColumnDefault
include BulkInsertSafe
+ MAX_JOB_NAME_LENGTH = 128
+
columns_changing_default :partition_id
- ignore_column :id_convert_to_bigint, remove_with: '16.4', remove_after: '2023-09-22'
belongs_to :build, class_name: "Ci::Processable", foreign_key: :build_id, inverse_of: :needs
partitionable scope: :build
validates :build, presence: true
- validates :name, presence: true, length: { maximum: 128 }
+ validates :name, presence: true, length: { maximum: MAX_JOB_NAME_LENGTH }
validates :optional, inclusion: { in: [true, false] }
scope :scoped_build, -> { where("#{Ci::Build.quoted_table_name}.id = #{quoted_table_name}.build_id") }
diff --git a/app/models/ci/build_runner_session.rb b/app/models/ci/build_runner_session.rb
index eaa2e1c428e..e197217bb70 100644
--- a/app/models/ci/build_runner_session.rb
+++ b/app/models/ci/build_runner_session.rb
@@ -20,7 +20,7 @@ module Ci
partitionable scope: :build
validates :build, presence: true
- validates :url, public_url: { schemes: %w(https) }
+ validates :url, public_url: { schemes: %w[https] }
def terminal_specification
wss_url = Gitlab::UrlHelpers.as_wss(Addressable::URI.escape(url))
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 3a5db04a687..5bf4e846304 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -162,7 +162,7 @@ module Ci
validates :status, presence: { unless: :importing? }
validate :valid_commit_sha, unless: :importing?
- validates :source, exclusion: { in: %w(unknown), unless: :importing? }, on: :create
+ validates :source, exclusion: { in: %w[unknown], unless: :importing? }, on: :create
after_create :keep_around_commits, unless: :importing?
after_find :observe_age_in_minutes, unless: :importing?
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 8d93429fd24..91c919dc662 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -52,7 +52,7 @@ module Ci
RUNNER_QUEUE_EXPIRY_TIME = 1.hour
# The `UPDATE_CONTACT_COLUMN_EVERY` defines how often the Runner DB entry can be updated
- UPDATE_CONTACT_COLUMN_EVERY = (40.minutes..55.minutes).freeze
+ UPDATE_CONTACT_COLUMN_EVERY = (40.minutes..55.minutes)
# The `STALE_TIMEOUT` constant defines the how far past the last contact or creation date a runner will be considered stale
STALE_TIMEOUT = 3.months
@@ -532,7 +532,9 @@ module Ci
'virtualbox' => :virtualbox,
'docker+machine' => :docker_machine,
'docker-ssh+machine' => :docker_ssh_machine,
- 'kubernetes' => :kubernetes
+ 'kubernetes' => :kubernetes,
+ 'docker-autoscaler' => :docker_autoscaler,
+ 'instance' => :instance
}.freeze
EXECUTOR_TYPE_TO_NAMES = EXECUTOR_NAME_TO_TYPES.invert.freeze
@@ -552,9 +554,7 @@ module Ci
end
def cleanup_runner_queue
- Gitlab::Redis::SharedState.with do |redis|
- redis.del(runner_queue_key)
- end
+ ::Gitlab::Workhorse.cleanup_key(runner_queue_key)
end
def runner_queue_key
diff --git a/app/models/clusters/agent.rb b/app/models/clusters/agent.rb
index 8dc866929f3..cbea7efc70e 100644
--- a/app/models/clusters/agent.rb
+++ b/app/models/clusters/agent.rb
@@ -50,7 +50,7 @@ module Clusters
end
def connected?
- agent_tokens.active.where("last_used_at > ?", INACTIVE_AFTER.ago).exists?
+ agent_tokens.connected.exists?
end
def activity_event_deletion_cutoff
diff --git a/app/models/clusters/agent_token.rb b/app/models/clusters/agent_token.rb
index b2b13f6cef7..f4c497a42cc 100644
--- a/app/models/clusters/agent_token.rb
+++ b/app/models/clusters/agent_token.rb
@@ -2,10 +2,15 @@
module Clusters
class AgentToken < ApplicationRecord
+ TOKEN_PREFIX = "glagent-"
+
include RedisCacheable
include TokenAuthenticatable
- add_authentication_token_field :token, encrypted: :required, token_generator: -> { Devise.friendly_token(50) }
+ add_authentication_token_field :token,
+ encrypted: :required,
+ token_generator: -> { Devise.friendly_token(50) },
+ format_with_prefix: :glagent_prefix
cached_attr_reader :last_used_at
self.table_name = 'cluster_agent_tokens'
@@ -21,6 +26,7 @@ module Clusters
scope :order_last_used_at_desc, -> { order(arel_table[:last_used_at].desc.nulls_last) }
scope :with_status, -> (status) { where(status: status) }
scope :active, -> { where(status: :active) }
+ scope :connected, -> { active.where("last_used_at > ?", Clusters::Agent::INACTIVE_AFTER.ago) }
enum status: {
active: 0,
@@ -30,5 +36,9 @@ module Clusters
def to_ability_name
:cluster
end
+
+ def glagent_prefix
+ TOKEN_PREFIX
+ end
end
end
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 123ad0ebfaf..5efbec45561 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -8,7 +8,7 @@ module Clusters
include ReactiveCaching
include NullifyIfBlank
- RESERVED_NAMESPACES = %w(gitlab-managed-apps).freeze
+ RESERVED_NAMESPACES = %w[gitlab-managed-apps].freeze
REQUIRED_K8S_MIN_VERSION = 23
IGNORED_CONNECTION_EXCEPTIONS = [
diff --git a/app/models/commit.rb b/app/models/commit.rb
index d7aa66588d3..39e12b53f21 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -30,10 +30,10 @@ class Commit
MIN_SHA_LENGTH = Gitlab::Git::Commit::MIN_SHA_LENGTH
MAX_SHA_LENGTH = Gitlab::Git::Commit::MAX_SHA_LENGTH
- COMMIT_SHA_PATTERN = Gitlab::Git::Commit::SHA_PATTERN.freeze
- EXACT_COMMIT_SHA_PATTERN = /\A#{COMMIT_SHA_PATTERN}\z/.freeze
+ COMMIT_SHA_PATTERN = Gitlab::Git::Commit::SHA_PATTERN
+ EXACT_COMMIT_SHA_PATTERN = /\A#{COMMIT_SHA_PATTERN}\z/
# Used by GFM to match and present link extensions on node texts and hrefs.
- LINK_EXTENSION_PATTERN = /(patch)/.freeze
+ LINK_EXTENSION_PATTERN = /(patch)/
DEFAULT_MAX_DIFF_LINES_SETTING = 50_000
DEFAULT_MAX_DIFF_FILES_SETTING = 1_000
@@ -432,7 +432,7 @@ class Commit
end
def cherry_pick_message(user)
- %{#{message}\n\n#{cherry_pick_description(user)}}
+ %(#{message}\n\n#{cherry_pick_description(user)})
end
def revert_description(user)
@@ -444,7 +444,7 @@ class Commit
end
def revert_message(user)
- %{Revert "#{title.strip}"\n\n#{revert_description(user)}}
+ %(Revert "#{title.strip}"\n\n#{revert_description(user)})
end
def reverts_commit?(commit, user)
@@ -539,7 +539,7 @@ class Commit
# added by `git commit --fixup` which is used by some community members.
# https://gitlab.com/gitlab-org/gitlab/-/issues/342937#note_892065311
#
- DRAFT_REGEX = /\A\s*#{Gitlab::Regex.merge_request_draft}|(fixup!|squash!)\s/.freeze
+ DRAFT_REGEX = /\A\s*#{Gitlab::Regex.merge_request_draft}|(fixup!|squash!)\s/
def draft?
!!(title =~ DRAFT_REGEX)
@@ -554,10 +554,10 @@ class Commit
"commit:#{sha}"
end
- def expire_note_etag_cache
+ def broadcast_notes_changed
super
- expire_note_etag_cache_for_related_mrs
+ broadcast_notes_changed_for_related_mrs
end
def readable_by?(user)
@@ -614,8 +614,8 @@ class Commit
end
end
- def expire_note_etag_cache_for_related_mrs
- MergeRequest.includes(target_project: :namespace).by_commit_sha(id).find_each(&:expire_note_etag_cache)
+ def broadcast_notes_changed_for_related_mrs
+ MergeRequest.includes(target_project: :namespace).by_commit_sha(id).find_each(&:broadcast_notes_changed)
end
def commit_reference(from, referable_commit_id, full: false)
diff --git a/app/models/commit_range.rb b/app/models/commit_range.rb
index d882a185464..cb24297f2c8 100644
--- a/app/models/commit_range.rb
+++ b/app/models/commit_range.rb
@@ -28,11 +28,11 @@ class CommitRange
# The beginning and ending refs can be named or SHAs, and
# the range notation can be double- or triple-dot.
- REF_PATTERN = /[0-9a-zA-Z][0-9a-zA-Z_.-]*[0-9a-zA-Z\^]/.freeze
- PATTERN = /#{REF_PATTERN}\.{2,3}#{REF_PATTERN}/.freeze
+ REF_PATTERN = /[0-9a-zA-Z][0-9a-zA-Z_.-]*[0-9a-zA-Z\^]/
+ PATTERN = /#{REF_PATTERN}\.{2,3}#{REF_PATTERN}/
# In text references, the beginning and ending refs can only be valid SHAs.
- STRICT_PATTERN = /#{Gitlab::Git::Commit::RAW_SHA_PATTERN}\.{2,3}#{Gitlab::Git::Commit::RAW_SHA_PATTERN}/.freeze
+ STRICT_PATTERN = /#{Gitlab::Git::Commit::RAW_SHA_PATTERN}\.{2,3}#{Gitlab::Git::Commit::RAW_SHA_PATTERN}/
def self.reference_prefix
'@'
diff --git a/app/models/commit_signatures/gpg_signature.rb b/app/models/commit_signatures/gpg_signature.rb
index a9e8ca2dd33..45937b68691 100644
--- a/app/models/commit_signatures/gpg_signature.rb
+++ b/app/models/commit_signatures/gpg_signature.rb
@@ -3,6 +3,7 @@ module CommitSignatures
class GpgSignature < ApplicationRecord
include CommitSignature
include SignatureType
+ include EachBatch
sha_attribute :gpg_key_primary_keyid
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index c2425e9460a..3761aa81bf7 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -9,16 +9,19 @@ class CommitStatus < Ci::ApplicationRecord
include BulkInsertableAssociations
include TaggableQueries
- ROUTING_FEATURE_FLAG = :ci_partitioning_use_ci_builds_routing_table
+ def self.switch_table_names
+ if Gitlab::Utils.to_boolean(ENV['USE_CI_BUILDS_ROUTING_TABLE'])
+ :p_ci_builds
+ else
+ :ci_builds
+ end
+ end
- self.table_name = 'ci_builds'
- self.sequence_name = 'ci_builds_id_seq'
+ self.table_name = self.switch_table_names
+ self.sequence_name = :ci_builds_id_seq
self.primary_key = :id
- partitionable scope: :pipeline, through: {
- table: :p_ci_builds,
- flag: ROUTING_FEATURE_FLAG
- }
+ partitionable scope: :pipeline
belongs_to :user
belongs_to :project
diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb
index f419fa8518e..e342939b3d6 100644
--- a/app/models/concerns/avatarable.rb
+++ b/app/models/concerns/avatarable.rb
@@ -48,12 +48,6 @@ module Avatarable
end
end
- class_methods do
- def bot_avatar(image:)
- Rails.root.join('lib', 'assets', 'images', 'bot_avatars', image).open
- end
- end
-
def avatar_type
unless self.avatar.image?
errors.add :avatar, "file format is not supported. Please try one of the following supported formats: #{AvatarUploader::SAFE_IMAGE_EXT.join(', ')}"
diff --git a/app/models/concerns/chronic_duration_attribute.rb b/app/models/concerns/chronic_duration_attribute.rb
index af4905115b1..7b7b61fdf06 100644
--- a/app/models/concerns/chronic_duration_attribute.rb
+++ b/app/models/concerns/chronic_duration_attribute.rb
@@ -17,7 +17,12 @@ module ChronicDurationAttribute
chronic_duration_attributes[virtual_attribute] = value.presence || parameters[:default].presence.to_s
begin
- new_value = value.present? ? ChronicDuration.parse(value).to_i : parameters[:default].presence
+ new_value = if value.present?
+ ChronicDuration.parse(value, use_complete_matcher: true).to_i
+ else
+ parameters[:default].presence
+ end
+
assign_attributes(source_attribute => new_value)
rescue ChronicDuration::DurationParseError
# ignore error as it will be caught by validation
diff --git a/app/models/concerns/ci/deployable.rb b/app/models/concerns/ci/deployable.rb
index b3b80989410..d25151f9a34 100644
--- a/app/models/concerns/ci/deployable.rb
+++ b/app/models/concerns/ci/deployable.rb
@@ -138,7 +138,11 @@ module Ci
end
def environment_url
- options&.dig(:environment, :url) || persisted_environment&.external_url
+ options&.dig(:environment, :url) || persisted_environment.try(:external_url)
+ end
+
+ def environment_slug
+ persisted_environment.try(:slug)
end
def environment_status
diff --git a/app/models/concerns/ci/has_runner_executor.rb b/app/models/concerns/ci/has_runner_executor.rb
index dc70cdb2018..6d4622945fe 100644
--- a/app/models/concerns/ci/has_runner_executor.rb
+++ b/app/models/concerns/ci/has_runner_executor.rb
@@ -17,7 +17,9 @@ module Ci
virtualbox: 8,
docker_machine: 9,
docker_ssh_machine: 10,
- kubernetes: 11
+ kubernetes: 11,
+ docker_autoscaler: 12,
+ instance: 13
}, _suffix: true
end
end
diff --git a/app/models/concerns/ci/maskable.rb b/app/models/concerns/ci/maskable.rb
index e2cef0981d1..15240385dd8 100644
--- a/app/models/concerns/ci/maskable.rb
+++ b/app/models/concerns/ci/maskable.rb
@@ -11,12 +11,12 @@ module Ci
# * Minimal length of 8 characters
# * Characters must be from the Base64 alphabet (RFC4648) with the addition of '@', ':', '.', and '~'
# * Absolutely no fun is allowed
- REGEX = %r{\A[a-zA-Z0-9_+=/@:.~-]{8,}\z}.freeze
+ REGEX = %r{\A[a-zA-Z0-9_+=/@:.~-]{8,}\z}
# * Single line
# * No spaces
# * Minimal length of 8 characters
# * Some fun is allowed
- MASK_AND_RAW_REGEX = %r{\A\S{8,}\z}.freeze
+ MASK_AND_RAW_REGEX = %r{\A\S{8,}\z}
included do
validates :masked, inclusion: { in: [true, false] }
diff --git a/app/models/concerns/ci/partitionable.rb b/app/models/concerns/ci/partitionable.rb
index ec6c85d888d..c4b1281fa72 100644
--- a/app/models/concerns/ci/partitionable.rb
+++ b/app/models/concerns/ci/partitionable.rb
@@ -107,7 +107,10 @@ module Ci
partitioned_by :partition_id,
strategy: :ci_sliding_list,
next_partition_if: proc { false },
- detach_partition_if: proc { false }
+ detach_partition_if: proc { false },
+ # Most of the db tasks are run in a weekly basis, e.g. execute_batched_migrations.
+ # Therefore, let's start with 1.week and see how it'd go.
+ analyze_interval: 1.week
end
end
end
diff --git a/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb b/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb
index eef68bfd349..9528a708ee1 100644
--- a/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb
+++ b/app/models/concerns/clusters/agents/authorizations/ci_access/config_scopes.rb
@@ -17,7 +17,7 @@ module Clusters
class_methods do
def available_ci_access_fields(_project)
- %w(agent)
+ %w[agent]
end
end
end
diff --git a/app/models/concerns/cross_database_ignored_tables.rb b/app/models/concerns/cross_database_ignored_tables.rb
index c97e405cce4..14a9703a734 100644
--- a/app/models/concerns/cross_database_ignored_tables.rb
+++ b/app/models/concerns/cross_database_ignored_tables.rb
@@ -4,6 +4,12 @@ module CrossDatabaseIgnoredTables
extend ActiveSupport::Concern
class_methods do
+ def temporary_ignore_cross_database_tables(tables, url:, &blk)
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ tables, url: url, &blk
+ )
+ end
+
def cross_database_ignore_tables(tables, options = {})
raise "missing issue url" if options[:url].blank?
@@ -40,8 +46,7 @@ module CrossDatabaseIgnoredTables
return yield unless options[:if].nil? || instance_eval(&options[:if])
url = options[:url]
- Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
- tables, url: url, &blk
- )
+
+ self.class.temporary_ignore_cross_database_tables(tables, url: url, &blk)
end
end
diff --git a/app/models/concerns/diff_positionable_note.rb b/app/models/concerns/diff_positionable_note.rb
index b10b318fb7c..2f64129b65f 100644
--- a/app/models/concerns/diff_positionable_note.rb
+++ b/app/models/concerns/diff_positionable_note.rb
@@ -14,7 +14,7 @@ module DiffPositionableNote
validates :position, json_schema: { filename: "position", hash_conversion: true }
end
- %i(original_position position change_position).each do |meth|
+ %i[original_position position change_position].each do |meth|
define_method "#{meth}=" do |new_position|
if new_position.is_a?(String)
new_position = begin
diff --git a/app/models/concerns/each_batch.rb b/app/models/concerns/each_batch.rb
index 945d286a2fd..0c8cf861c38 100644
--- a/app/models/concerns/each_batch.rb
+++ b/app/models/concerns/each_batch.rb
@@ -54,7 +54,7 @@ module EachBatch
'the column: argument must be set to a column name to use for ordering rows'
end
- start = except(:select)
+ start = except(:select, :includes, :preload)
.select(column)
.reorder(column => order)
@@ -69,7 +69,7 @@ module EachBatch
1.step do |index|
start_cond = arel_table[column].gteq(start_id)
start_cond = arel_table[column].lteq(start_id) if order == :desc
- stop = except(:select)
+ stop = except(:select, :includes, :preload)
.select(column)
.where(start_cond)
.reorder(column => order)
diff --git a/app/models/concerns/editable.rb b/app/models/concerns/editable.rb
index 2e49e720ac9..be9858bf49b 100644
--- a/app/models/concerns/editable.rb
+++ b/app/models/concerns/editable.rb
@@ -8,6 +8,6 @@ module Editable
end
def last_edited_by
- super || User.ghost
+ super || Users::Internal.ghost
end
end
diff --git a/app/models/concerns/enums/prometheus_metric.rb b/app/models/concerns/enums/prometheus_metric.rb
index e65a01990a3..2cc765b7a3c 100644
--- a/app/models/concerns/enums/prometheus_metric.rb
+++ b/app/models/concerns/enums/prometheus_metric.rb
@@ -30,37 +30,37 @@ module Enums
# built-in groups
nginx_ingress_vts: {
group_title: _('Response metrics (NGINX Ingress VTS)'),
- required_metrics: %w(nginx_upstream_responses_total nginx_upstream_response_msecs_avg),
+ required_metrics: %w[nginx_upstream_responses_total nginx_upstream_response_msecs_avg],
priority: 10
}.freeze,
nginx_ingress: {
group_title: _('Response metrics (NGINX Ingress)'),
- required_metrics: %w(nginx_ingress_controller_requests nginx_ingress_controller_ingress_upstream_latency_seconds_sum),
+ required_metrics: %w[nginx_ingress_controller_requests nginx_ingress_controller_ingress_upstream_latency_seconds_sum],
priority: 10
}.freeze,
ha_proxy: {
group_title: _('Response metrics (HA Proxy)'),
- required_metrics: %w(haproxy_frontend_http_requests_total haproxy_frontend_http_responses_total),
+ required_metrics: %w[haproxy_frontend_http_requests_total haproxy_frontend_http_responses_total],
priority: 10
}.freeze,
aws_elb: {
group_title: _('Response metrics (AWS ELB)'),
- required_metrics: %w(aws_elb_request_count_sum aws_elb_latency_average aws_elb_httpcode_backend_5_xx_sum),
+ required_metrics: %w[aws_elb_request_count_sum aws_elb_latency_average aws_elb_httpcode_backend_5_xx_sum],
priority: 10
}.freeze,
nginx: {
group_title: _('Response metrics (NGINX)'),
- required_metrics: %w(nginx_server_requests nginx_server_requestMsec),
+ required_metrics: %w[nginx_server_requests nginx_server_requestMsec],
priority: 10
}.freeze,
kubernetes: {
group_title: _('System metrics (Kubernetes)'),
- required_metrics: %w(container_memory_usage_bytes container_cpu_usage_seconds_total),
+ required_metrics: %w[container_memory_usage_bytes container_cpu_usage_seconds_total],
priority: 5
}.freeze,
cluster_health: {
group_title: _('Cluster Health'),
- required_metrics: %w(container_memory_usage_bytes container_cpu_usage_seconds_total),
+ required_metrics: %w[container_memory_usage_bytes container_cpu_usage_seconds_total],
priority: 10
}.freeze
}.merge(custom_group_details).freeze
diff --git a/app/models/concerns/has_unique_internal_users.rb b/app/models/concerns/has_unique_internal_users.rb
deleted file mode 100644
index 25b56f6d70f..00000000000
--- a/app/models/concerns/has_unique_internal_users.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-module HasUniqueInternalUsers
- extend ActiveSupport::Concern
-
- class_methods do
- private
-
- def unique_internal(scope, username, email_pattern, &block)
- scope.first || create_unique_internal(scope, username, email_pattern, &block)
- end
-
- def create_unique_internal(scope, username, email_pattern, &creation_block)
- # Since we only want a single one of these in an instance, we use an
- # exclusive lease to ensure than this block is never run concurrently.
- lease_key = "user:unique_internal:#{username}"
- lease = Gitlab::ExclusiveLease.new(lease_key, timeout: 1.minute.to_i)
-
- until uuid = lease.try_obtain
- # Keep trying until we obtain the lease. To prevent hammering Redis too
- # much we'll wait for a bit between retries.
- sleep(1)
- end
-
- # Recheck if the user is already present. One might have been
- # added between the time we last checked (first line of this method)
- # and the time we acquired the lock.
- existing_user = uncached { scope.first }
- return existing_user if existing_user.present?
-
- uniquify = Gitlab::Utils::Uniquify.new
-
- username = uniquify.string(username) { |s| User.find_by_username(s) }
-
- email = uniquify.string(-> (n) { Kernel.sprintf(email_pattern, n) }) do |s|
- User.find_by_email(s)
- end
-
- user = scope.build(
- username: username,
- email: email,
- &creation_block
- )
-
- Users::UpdateService.new(user, user: user).execute(validate: false)
- user
- ensure
- Gitlab::ExclusiveLease.cancel(lease_key, uuid)
- end
- end
-end
diff --git a/app/models/concerns/has_user_type.rb b/app/models/concerns/has_user_type.rb
index 2d0ff82e624..c3f702a4e69 100644
--- a/app/models/concerns/has_user_type.rb
+++ b/app/models/concerns/has_user_type.rb
@@ -74,4 +74,21 @@ module HasUserType
# https://gitlab.com/gitlab-org/gitlab/-/issues/346058
'****'
end
+
+ def resource_bot_resource
+ return unless project_bot?
+
+ projects&.first || groups&.first
+ end
+
+ def resource_bot_owners
+ return [] unless project_bot?
+
+ resource = resource_bot_resource
+ return [] unless resource
+
+ return resource.maintainers if resource.is_a?(Project)
+
+ resource.owners
+ end
end
diff --git a/app/models/concerns/integrations/enable_ssl_verification.rb b/app/models/concerns/integrations/enable_ssl_verification.rb
index 11dc8a76a2b..9735a9bf5f6 100644
--- a/app/models/concerns/integrations/enable_ssl_verification.rb
+++ b/app/models/concerns/integrations/enable_ssl_verification.rb
@@ -19,13 +19,16 @@ module Integrations
url_index = fields.index { |field| field[:name].ends_with?('_url') }
insert_index = url_index ? url_index + 1 : -1
- fields.insert(insert_index, {
- type: 'checkbox',
- name: 'enable_ssl_verification',
- title: s_('Integrations|SSL verification'),
- checkbox_label: s_('Integrations|Enable SSL verification'),
- help: s_('Integrations|Clear if using a self-signed certificate.')
- })
+ fields.insert(insert_index,
+ Field.new(
+ name: 'enable_ssl_verification',
+ integration_class: self,
+ type: :checkbox,
+ title: s_('Integrations|SSL verification'),
+ checkbox_label: s_('Integrations|Enable SSL verification'),
+ help: s_('Integrations|Clear if using a self-signed certificate.')
+ )
+ )
end
end
end
diff --git a/app/models/concerns/integrations/reset_secret_fields.rb b/app/models/concerns/integrations/reset_secret_fields.rb
index f79c4392f19..24d716fe5dd 100644
--- a/app/models/concerns/integrations/reset_secret_fields.rb
+++ b/app/models/concerns/integrations/reset_secret_fields.rb
@@ -12,9 +12,7 @@ module Integrations
end
def exposing_secrets_fields
- # TODO: Once all integrations use `Integrations::Field` we can remove the `.try` here.
- # See: https://gitlab.com/groups/gitlab-org/-/epics/7652
- fields.select { _1.try(:exposes_secrets) }.pluck(:name)
+ fields.select(&:exposes_secrets).pluck(:name)
end
private
diff --git a/app/models/concerns/integrations/slack_mattermost_fields.rb b/app/models/concerns/integrations/slack_mattermost_fields.rb
new file mode 100644
index 00000000000..a8e63c4e405
--- /dev/null
+++ b/app/models/concerns/integrations/slack_mattermost_fields.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Integrations
+ module SlackMattermostFields
+ extend ActiveSupport::Concern
+
+ included do
+ field :webhook,
+ help: -> { webhook_help },
+ required: true,
+ if: -> { requires_webhook? }
+
+ field :username,
+ placeholder: 'GitLab-integration',
+ if: -> { requires_webhook? }
+
+ field :notify_only_broken_pipelines,
+ type: :checkbox,
+ section: Integration::SECTION_TYPE_CONFIGURATION,
+ help: 'Do not send notifications for successful pipelines.'
+
+ field :branches_to_be_notified,
+ type: :select,
+ section: Integration::SECTION_TYPE_CONFIGURATION,
+ title: -> { s_('Integration|Branches for which notifications are to be sent') },
+ choices: -> { branch_choices }
+
+ field :labels_to_be_notified,
+ section: Integration::SECTION_TYPE_CONFIGURATION,
+ placeholder: '~backend,~frontend',
+ help: 'Send notifications for issue, merge request, and comment events with the listed labels only. ' \
+ 'Leave blank to receive notifications for all events.'
+
+ field :labels_to_be_notified_behavior,
+ type: :select,
+ section: Integration::SECTION_TYPE_CONFIGURATION,
+ choices: [
+ ['Match any of the labels', Integrations::BaseChatNotification::MATCH_ANY_LABEL],
+ ['Match all of the labels', Integrations::BaseChatNotification::MATCH_ALL_LABELS]
+ ]
+ end
+ end
+end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 9a513ea0e5b..a9a00ab1c44 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -19,6 +19,7 @@ module Issuable
include Awardable
include Taskable
include Importable
+ include Transitionable
include Editable
include AfterCommitQueue
include Sortable
@@ -33,7 +34,7 @@ module Issuable
TITLE_HTML_LENGTH_MAX = 800
DESCRIPTION_LENGTH_MAX = 1.megabyte
DESCRIPTION_HTML_LENGTH_MAX = 5.megabytes
- SEARCHABLE_FIELDS = %w(title description).freeze
+ SEARCHABLE_FIELDS = %w[title description].freeze
MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS = 200
STATE_ID_MAP = {
@@ -225,6 +226,10 @@ module Issuable
false
end
+ def supports_lock_on_merge?
+ false
+ end
+
def severity
return IssuableSeverity::DEFAULT unless supports_severity?
@@ -235,6 +240,10 @@ module Issuable
super + [:notes]
end
+ def importing_or_transitioning?
+ importing? || transitioning?
+ end
+
private
def validate_description_length?
@@ -408,14 +417,14 @@ module Issuable
sort = sort.to_s
grouping_columns = [arel_table[:id]]
- if %w(milestone_due_desc milestone_due_asc milestone).include?(sort)
+ if %w[milestone_due_desc milestone_due_asc milestone].include?(sort)
milestone_table = Milestone.arel_table
grouping_columns << milestone_table[:id]
grouping_columns << milestone_table[:due_date]
- elsif %w(merged_at_desc merged_at_asc merged_at).include?(sort)
+ elsif %w[merged_at_desc merged_at_asc merged_at].include?(sort)
grouping_columns << MergeRequest::Metrics.arel_table[:id]
grouping_columns << MergeRequest::Metrics.arel_table[:merged_at]
- elsif %w(closed_at_desc closed_at_asc closed_at).include?(sort)
+ elsif %w[closed_at_desc closed_at_asc closed_at].include?(sort)
grouping_columns << MergeRequest::Metrics.arel_table[:id]
grouping_columns << MergeRequest::Metrics.arel_table[:latest_closed_at]
end
diff --git a/app/models/concerns/issue_available_features.rb b/app/models/concerns/issue_available_features.rb
index 3f65e701da7..2969f1e1928 100644
--- a/app/models/concerns/issue_available_features.rb
+++ b/app/models/concerns/issue_available_features.rb
@@ -10,10 +10,10 @@ module IssueAvailableFeatures
# EE only features are listed on EE::IssueAvailableFeatures
def available_features_for_issue_types
{
- assignee: %w(issue incident),
- confidentiality: %w(issue incident),
- time_tracking: %w(issue incident),
- move_and_clone: %w(issue incident)
+ assignee: %w[issue incident],
+ confidentiality: %w[issue incident objective key_result],
+ time_tracking: %w[issue incident],
+ move_and_clone: %w[issue incident]
}.with_indifferent_access
end
end
diff --git a/app/models/concerns/linkable_item.rb b/app/models/concerns/linkable_item.rb
index 135252727ab..c91e3615ba7 100644
--- a/app/models/concerns/linkable_item.rb
+++ b/app/models/concerns/linkable_item.rb
@@ -16,6 +16,7 @@ module LinkableItem
scope :for_source, ->(item) { where(source_id: item.id) }
scope :for_target, ->(item) { where(target_id: item.id) }
+ scope :for_source_and_target, ->(source, target) { where(source: source, target: target) }
scope :for_items, ->(source, target) do
where(source: source, target: target).or(where(source: target, target: source))
end
diff --git a/app/models/concerns/mentionable/reference_regexes.rb b/app/models/concerns/mentionable/reference_regexes.rb
index 0b6075fbeb8..b5634ba3b6d 100644
--- a/app/models/concerns/mentionable/reference_regexes.rb
+++ b/app/models/concerns/mentionable/reference_regexes.rb
@@ -28,7 +28,7 @@ module Mentionable
def self.external_pattern
strong_memoize(:external_pattern) do
issue_pattern = Integrations::BaseIssueTracker.base_reference_pattern
- link_patterns = URI::DEFAULT_PARSER.make_regexp(%w(http https))
+ link_patterns = URI::DEFAULT_PARSER.make_regexp(%w[http https])
reference_pattern(link_patterns, issue_pattern)
end
end
diff --git a/app/models/concerns/noteable.rb b/app/models/concerns/noteable.rb
index 40a91c8ac94..06cee46645b 100644
--- a/app/models/concerns/noteable.rb
+++ b/app/models/concerns/noteable.rb
@@ -12,17 +12,17 @@ module Noteable
class_methods do
# `Noteable` class names that support replying to individual notes.
def replyable_types
- %w(Issue MergeRequest)
+ %w[Issue MergeRequest]
end
# `Noteable` class names that support resolvable notes.
def resolvable_types
- %w(Issue MergeRequest DesignManagement::Design)
+ %w[Issue MergeRequest DesignManagement::Design]
end
# `Noteable` class names that support creating/forwarding individual notes.
def email_creatable_types
- %w(Issue)
+ %w[Issue]
end
end
@@ -164,28 +164,15 @@ module Noteable
[MergeRequest, Issue].include?(self.class)
end
- def etag_caching_enabled?
+ def real_time_notes_enabled?
false
end
- def expire_note_etag_cache
+ def broadcast_notes_changed
return unless discussions_rendered_on_frontend?
- return unless etag_caching_enabled?
+ return unless real_time_notes_enabled?
- # TODO: We need to figure out a way to make ETag caching work for group-level work items
- Gitlab::EtagCaching::Store.new.touch(note_etag_key) unless is_a?(Issue) && project.nil?
-
- Noteable::NotesChannel.broadcast_to(self, event: 'updated') if Feature.enabled?(:action_cable_notes, project || try(:group))
- end
-
- def note_etag_key
- return Gitlab::Routing.url_helpers.designs_project_issue_path(project, issue, { vueroute: filename }) if self.is_a?(DesignManagement::Design)
-
- Gitlab::Routing.url_helpers.project_noteable_notes_path(
- project,
- target_type: noteable_target_type_name,
- target_id: id
- )
+ Noteable::NotesChannel.broadcast_to(self, event: 'updated')
end
def after_note_created(_note)
diff --git a/app/models/concerns/packages/nuget/version_normalizable.rb b/app/models/concerns/packages/nuget/version_normalizable.rb
index 473e5f07811..4bcfec89570 100644
--- a/app/models/concerns/packages/nuget/version_normalizable.rb
+++ b/app/models/concerns/packages/nuget/version_normalizable.rb
@@ -13,7 +13,7 @@ module Packages
private
def set_normalized_version
- return unless package && Feature.enabled?(:nuget_normalized_version, package.project)
+ return unless package
self.normalized_version = normalize
end
diff --git a/app/models/concerns/pg_full_text_searchable.rb b/app/models/concerns/pg_full_text_searchable.rb
index 562c8cf23f3..b7ca6f61573 100644
--- a/app/models/concerns/pg_full_text_searchable.rb
+++ b/app/models/concerns/pg_full_text_searchable.rb
@@ -21,11 +21,11 @@
module PgFullTextSearchable
extend ActiveSupport::Concern
- LONG_WORDS_REGEX = %r([A-Za-z0-9+/@]{50,}).freeze
+ LONG_WORDS_REGEX = %r([A-Za-z0-9+/@]{50,})
TSVECTOR_MAX_LENGTH = 1.megabyte.freeze
TEXT_SEARCH_DICTIONARY = 'english'
- URL_SCHEME_REGEX = %r{(?<=\A|\W)\w+://(?=\w+)}.freeze
- TSQUERY_DISALLOWED_CHARACTERS_REGEX = %r{[^a-zA-Z0-9 .@/\-_"]}.freeze
+ URL_SCHEME_REGEX = %r{(?<=\A|\W)\w+://(?=\w+)}
+ TSQUERY_DISALLOWED_CHARACTERS_REGEX = %r{[^a-zA-Z0-9 .@/\-_"]}
def update_search_data!
tsvector_sql_nodes = self.class.pg_full_text_searchable_columns.map do |column, weight|
diff --git a/app/models/concerns/protected_ref.rb b/app/models/concerns/protected_ref.rb
index a87eadb9332..ea8a1640bea 100644
--- a/app/models/concerns/protected_ref.rb
+++ b/app/models/concerns/protected_ref.rb
@@ -3,6 +3,8 @@
module ProtectedRef
extend ActiveSupport::Concern
+ include Importable
+
included do
belongs_to :project, touch: true
@@ -32,12 +34,13 @@ module ProtectedRef
# to fail.
has_many :"#{type}_access_levels", inverse_of: self.model_name.singular
+ # Overridden in EE with `if: -> { false }` so this validation does not apply on an EE instance.
validates :"#{type}_access_levels",
length: {
is: 1,
message: "are restricted to a single instance per #{self.model_name.human}."
},
- unless: -> { allow_multiple?(type) }
+ unless: -> { allow_multiple?(type) || importing? }
accepts_nested_attributes_for :"#{type}_access_levels", allow_destroy: true
end
diff --git a/app/models/concerns/redactable.rb b/app/models/concerns/redactable.rb
index 53ae300ee2d..5ad96d6cc46 100644
--- a/app/models/concerns/redactable.rb
+++ b/app/models/concerns/redactable.rb
@@ -10,7 +10,7 @@
module Redactable
extend ActiveSupport::Concern
- UNSUBSCRIBE_PATTERN = %r{/sent_notifications/\h{32}/unsubscribe}.freeze
+ UNSUBSCRIBE_PATTERN = %r{/sent_notifications/\h{32}/unsubscribe}
class_methods do
def redact_field(field)
diff --git a/app/models/concerns/require_email_verification.rb b/app/models/concerns/require_email_verification.rb
index d7182778b36..6581928f637 100644
--- a/app/models/concerns/require_email_verification.rb
+++ b/app/models/concerns/require_email_verification.rb
@@ -7,10 +7,7 @@ module RequireEmailVerification
extend ActiveSupport::Concern
include Gitlab::Utils::StrongMemoize
- # This value is twice the amount we want it to be, because due to a bug in the devise-two-factor
- # gem every failed login attempt increments the value of failed_attempts by 2 instead of 1.
- # See: https://github.com/tinfoil/devise-two-factor/issues/127
- MAXIMUM_ATTEMPTS = 3 * 2
+ MAXIMUM_ATTEMPTS = 3
UNLOCK_IN = 24.hours
included do
diff --git a/app/models/concerns/resolvable_discussion.rb b/app/models/concerns/resolvable_discussion.rb
index e967c78154d..5c2f0aa04ac 100644
--- a/app/models/concerns/resolvable_discussion.rb
+++ b/app/models/concerns/resolvable_discussion.rb
@@ -116,7 +116,7 @@ module ResolvableDiscussion
# Set the notes array to the updated notes
@notes = notes_relation.fresh.to_a # rubocop:disable Gitlab/ModuleWithInstanceVariables
- noteable.expire_note_etag_cache
+ noteable.broadcast_notes_changed
clear_memoized_values
end
diff --git a/app/models/concerns/resolvable_note.rb b/app/models/concerns/resolvable_note.rb
index 7f9a7faa3f5..23abc5d5c22 100644
--- a/app/models/concerns/resolvable_note.rb
+++ b/app/models/concerns/resolvable_note.rb
@@ -4,7 +4,7 @@ module ResolvableNote
extend ActiveSupport::Concern
# Names of all subclasses of `Note` that can be resolvable.
- RESOLVABLE_TYPES = %w(DiffNote DiscussionNote).freeze
+ RESOLVABLE_TYPES = %w[DiffNote DiscussionNote].freeze
included do
belongs_to :resolved_by, class_name: "User"
diff --git a/app/models/concerns/restricted_signup.rb b/app/models/concerns/restricted_signup.rb
index cf97be21165..6af9ede5e8b 100644
--- a/app/models/concerns/restricted_signup.rb
+++ b/app/models/concerns/restricted_signup.rb
@@ -84,3 +84,5 @@ module RestrictedSignup
end
end
end
+
+::RestrictedSignup.prepend_mod
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index f2badfe48dd..ef14ff5fbe2 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -14,7 +14,17 @@ module Routable
# Routable.find_by_full_path('groupname/projectname') # -> Project
#
# Returns a single object, or nil.
- def self.find_by_full_path(path, follow_redirects: false, route_scope: Route, redirect_route_scope: RedirectRoute)
+
+ # rubocop:disable Metrics/CyclomaticComplexity
+ # rubocop:disable Metrics/PerceivedComplexity
+ def self.find_by_full_path(
+ path,
+ follow_redirects: false,
+ route_scope: Route,
+ redirect_route_scope: RedirectRoute,
+ optimize_routable: Routable.optimize_routable_enabled?
+ )
+
return unless path.present?
# Convert path to string to prevent DB error: function lower(integer) does not exist
@@ -25,20 +35,50 @@ module Routable
#
# We need to qualify the columns with the table name, to support both direct lookups on
# Route/RedirectRoute, and scoped lookups through the Routable classes.
- Gitlab::Database.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/420046") do
+ if optimize_routable
+ path_condition = { path: path }
+
+ source_type_condition = if route_scope == Route
+ {}
+ else
+ { source_type: route_scope.klass.base_class }
+ end
+
route =
- route_scope.find_by(routes: { path: path }) ||
- route_scope.iwhere(Route.arel_table[:path] => path).take
+ Route.where(source_type_condition).find_by(path_condition) ||
+ Route.where(source_type_condition).iwhere(path_condition).take
if follow_redirects
- route ||= redirect_route_scope.iwhere(RedirectRoute.arel_table[:path] => path).take
+ route ||= RedirectRoute.where(source_type_condition).iwhere(path_condition).take
end
- next unless route
+ return unless route
+ return route.source if route_scope == Route
+
+ route_scope.find_by(id: route.source_id)
+ else
+ Gitlab::Database.allow_cross_joins_across_databases(url:
+ "https://gitlab.com/gitlab-org/gitlab/-/issues/420046") do
+ route =
+ route_scope.find_by(routes: { path: path }) ||
+ route_scope.iwhere(Route.arel_table[:path] => path).take
+
+ if follow_redirects
+ route ||= redirect_route_scope.iwhere(RedirectRoute.arel_table[:path] => path).take
+ end
- route.is_a?(Routable) ? route : route.source
+ next unless route
+
+ route.is_a?(Routable) ? route : route.source
+ end
end
end
+ # rubocop:enable Metrics/PerceivedComplexity
+ # rubocop:enable Metrics/CyclomaticComplexity
+
+ def self.optimize_routable_enabled?
+ Feature.enabled?(:optimize_routable)
+ end
included do
# Remove `inverse_of: source` when upgraded to rails 5.2
@@ -67,13 +107,22 @@ module Routable
#
# Returns a single object, or nil.
def find_by_full_path(path, follow_redirects: false)
- # TODO: Optimize these queries by avoiding joins
- # https://gitlab.com/gitlab-org/gitlab/-/issues/292252
+ optimize_routable = Routable.optimize_routable_enabled?
+
+ if optimize_routable
+ route_scope = all
+ redirect_route_scope = RedirectRoute
+ else
+ route_scope = includes(:route).references(:routes)
+ redirect_route_scope = joins(:redirect_routes)
+ end
+
Routable.find_by_full_path(
path,
follow_redirects: follow_redirects,
- route_scope: includes(:route).references(:routes),
- redirect_route_scope: joins(:redirect_routes)
+ route_scope: route_scope,
+ redirect_route_scope: redirect_route_scope,
+ optimize_routable: optimize_routable
)
end
diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb
index b73ed937b5d..5455a2159cd 100644
--- a/app/models/concerns/storage/legacy_namespace.rb
+++ b/app/models/concerns/storage/legacy_namespace.rb
@@ -17,8 +17,6 @@ module Storage
Namespace.find(parent_id_before_last_save) # raise NotFound early if needed
end
- move_repositories
-
if saved_change_to_parent?
former_parent_full_path = parent_was&.full_path
parent_full_path = parent&.full_path
diff --git a/app/models/concerns/taskable.rb b/app/models/concerns/taskable.rb
index bf645e99b5e..96f684522d2 100644
--- a/app/models/concerns/taskable.rb
+++ b/app/models/concerns/taskable.rb
@@ -11,8 +11,8 @@ require 'task_list/filter'
module Taskable
COMPLETED = 'completed'
INCOMPLETE = 'incomplete'
- COMPLETE_PATTERN = /\[[xX]\]/.freeze
- INCOMPLETE_PATTERN = /\[[[:space:]]\]/.freeze
+ COMPLETE_PATTERN = /\[[xX]\]/
+ INCOMPLETE_PATTERN = /\[[[:space:]]\]/
ITEM_PATTERN = %r{
^
(?:(?:>\s{0,4})*) # optional blockquote characters
@@ -22,7 +22,7 @@ module Taskable
#{COMPLETE_PATTERN}|#{INCOMPLETE_PATTERN}
)
(\s.+) # followed by whitespace and some text.
- }x.freeze
+ }x
ITEM_PATTERN_UNTRUSTED =
'^' \
diff --git a/app/models/concerns/transitionable.rb b/app/models/concerns/transitionable.rb
new file mode 100644
index 00000000000..70e1fc8b78a
--- /dev/null
+++ b/app/models/concerns/transitionable.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Transitionable
+ extend ActiveSupport::Concern
+
+ attr_accessor :transitioning
+
+ def transitioning?
+ return false unless transitioning && Feature.enabled?(:skip_validations_during_transitions, project)
+
+ true
+ end
+
+ def enable_transitioning
+ self.transitioning = true
+ end
+
+ def disable_transitioning
+ self.transitioning = false
+ end
+end
diff --git a/app/models/concerns/users/visitable.rb b/app/models/concerns/users/visitable.rb
new file mode 100644
index 00000000000..cb8e5fdc682
--- /dev/null
+++ b/app/models/concerns/users/visitable.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Users
+ module Visitable
+ extend ActiveSupport::Concern
+
+ included do
+ def self.visited_around?(entity_id:, user_id:, time:)
+ visits_around(entity_id: entity_id, user_id: user_id, time: time).any?
+ end
+
+ def self.visits_around(entity_id:, user_id:, time:)
+ time = time.to_datetime
+ where(entity_id: entity_id, user_id: user_id, visited_at: (time - 15.minutes)..(time + 15.minutes))
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/with_uploads.rb b/app/models/concerns/with_uploads.rb
index caaf2b33ef0..319509ea69a 100644
--- a/app/models/concerns/with_uploads.rb
+++ b/app/models/concerns/with_uploads.rb
@@ -22,7 +22,7 @@ module WithUploads
# Currently there is no simple way how to select only not-mounted
# uploads, it should be all FileUploaders so we select them by
# `uploader` class
- FILE_UPLOADERS = %w(PersonalFileUploader NamespaceFileUploader FileUploader).freeze
+ FILE_UPLOADERS = %w[PersonalFileUploader NamespaceFileUploader FileUploader].freeze
included do
around_destroy :ignore_uploads_table_in_transaction
diff --git a/app/models/container_expiration_policy.rb b/app/models/container_expiration_policy.rb
index aecb47f7a03..f643fa7730b 100644
--- a/app/models/container_expiration_policy.rb
+++ b/app/models/container_expiration_policy.rb
@@ -80,7 +80,9 @@ class ContainerExpirationPolicy < ApplicationRecord
end
def set_next_run_at
- self.next_run_at = Time.zone.now + ChronicDuration.parse(cadence).seconds
+ cadence_seconds = ChronicDuration.parse(cadence, use_complete_matcher: true).seconds
+
+ self.next_run_at = Time.zone.now + cadence_seconds
end
def disable!
diff --git a/app/models/container_registry/event.rb b/app/models/container_registry/event.rb
index dd2675e17d8..9f7724c052c 100644
--- a/app/models/container_registry/event.rb
+++ b/app/models/container_registry/event.rb
@@ -4,25 +4,25 @@ module ContainerRegistry
class Event
include Gitlab::Utils::StrongMemoize
- ALLOWED_ACTIONS = %w(push delete).freeze
+ ALLOWED_ACTIONS = %w[push delete].freeze
PUSH_ACTION = 'push'
DELETE_ACTION = 'delete'
EVENT_TRACKING_CATEGORY = 'container_registry:notification'
EVENT_PREFIX = 'i_container_registry'
- ALLOWED_ACTOR_TYPES = %w(
+ ALLOWED_ACTOR_TYPES = %w[
personal_access_token
build
gitlab_or_ldap
- ).freeze
+ ].freeze
- TRACKABLE_ACTOR_EVENTS = %w(
+ TRACKABLE_ACTOR_EVENTS = %w[
push_tag
delete_tag
push_repository
delete_repository
create_repository
- ).freeze
+ ].freeze
attr_reader :event
@@ -60,7 +60,7 @@ module ContainerRegistry
def target_tag?
# There is no clear indication in the event structure when we delete a top-level manifest
- # except existance of "tag" key
+ # except existence of "tag" key
event['target'].has_key?('tag')
end
diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb
index 625d68925c6..c704795130b 100644
--- a/app/models/custom_emoji.rb
+++ b/app/models/custom_emoji.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class CustomEmoji < ApplicationRecord
- NAME_REGEXP = /[a-z0-9_-]+/.freeze
+ NAME_REGEXP = /[a-z0-9_-]+/
belongs_to :namespace, inverse_of: :custom_emoji
diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb
index f9fa4bd212c..de777b8ae53 100644
--- a/app/models/deploy_key.rb
+++ b/app/models/deploy_key.rb
@@ -43,7 +43,7 @@ class DeployKey < Key
end
def user
- super || User.ghost
+ super || Users::Internal.ghost
end
def audit_details
diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb
index 498ca9c4f30..920321a1699 100644
--- a/app/models/deploy_token.rb
+++ b/app/models/deploy_token.rb
@@ -8,8 +8,8 @@ class DeployToken < ApplicationRecord
add_authentication_token_field :token, encrypted: :required
- AVAILABLE_SCOPES = %i(read_repository read_registry write_registry
- read_package_registry write_package_registry).freeze
+ AVAILABLE_SCOPES = %i[read_repository read_registry write_registry
+ read_package_registry write_package_registry].freeze
GITLAB_DEPLOY_TOKEN_NAME = 'gitlab-deploy-token'
REQUIRED_DEPENDENCY_PROXY_SCOPES = %i[read_registry write_registry].freeze
diff --git a/app/models/description_version.rb b/app/models/description_version.rb
index fb61b7f5fde..05cca9f931f 100644
--- a/app/models/description_version.rb
+++ b/app/models/description_version.rb
@@ -9,7 +9,7 @@ class DescriptionVersion < ApplicationRecord
delegate :resource_parent, to: :issuable
def self.issuable_attrs
- %i(issue merge_request).freeze
+ %i[issue merge_request].freeze
end
def issuable
diff --git a/app/models/design_management.rb b/app/models/design_management.rb
index 81e170f7e59..20ada71755b 100644
--- a/app/models/design_management.rb
+++ b/app/models/design_management.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module DesignManagement
- DESIGN_IMAGE_SIZES = %w(v432x230).freeze
+ DESIGN_IMAGE_SIZES = %w[v432x230].freeze
def self.designs_directory
'designs'
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index 02979d5f804..d680d0e334f 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -9,7 +9,7 @@ class DiffNote < Note
include Gitlab::Utils::StrongMemoize
def self.noteable_types
- %w(MergeRequest Commit DesignManagement::Design)
+ %w[MergeRequest Commit DesignManagement::Design]
end
validates :original_position, presence: true
diff --git a/app/models/discussion_note.rb b/app/models/discussion_note.rb
index 6621b30b645..a1dfa0e72ec 100644
--- a/app/models/discussion_note.rb
+++ b/app/models/discussion_note.rb
@@ -9,7 +9,7 @@ class DiscussionNote < Note
# Names of all implementers of `Noteable` that support discussions.
def self.noteable_types
- %w(MergeRequest Issue Commit Snippet)
+ %w[MergeRequest Issue Commit Snippet]
end
validates :noteable_type, inclusion: { in: noteable_types }
diff --git a/app/models/draft_note.rb b/app/models/draft_note.rb
index ffc04f9bf90..f95eec742d8 100644
--- a/app/models/draft_note.rb
+++ b/app/models/draft_note.rb
@@ -5,8 +5,8 @@ class DraftNote < ApplicationRecord
include Sortable
include ShaAttribute
- PUBLISH_ATTRS = %i(noteable_id noteable_type type note).freeze
- DIFF_ATTRS = %i(position original_position change_position commit_id).freeze
+ PUBLISH_ATTRS = %i[noteable_id noteable_type type note].freeze
+ DIFF_ATTRS = %i[position original_position change_position commit_id].freeze
sha_attribute :commit_id
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 36445279b86..29394c37e2c 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -25,7 +25,6 @@ class Environment < ApplicationRecord
has_many :successful_deployments, -> { success }, class_name: 'Deployment'
has_many :active_deployments, -> { active }, class_name: 'Deployment'
has_many :prometheus_alerts, inverse_of: :environment
- has_many :self_managed_prometheus_alert_events, inverse_of: :environment
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :environment
# NOTE: If you preload multiple last deployments of environments, use Preloaders::Environments::DeploymentPreloader.
@@ -108,11 +107,11 @@ class Environment < ApplicationRecord
scope :deployed_and_updated_before, -> (project_id, before) do
# this query joins deployments and filters out any environment that has recent deployments
- joins = %{
+ joins = %(
LEFT JOIN "deployments" on "deployments".environment_id = "environments".id
AND "deployments".project_id = #{project_id}
AND "deployments".updated_at >= #{connection.quote(before)}
- }
+ )
Environment.joins(joins)
.where(project_id: project_id, updated_at: ...before)
.group('id', 'deployments.id')
@@ -193,7 +192,7 @@ class Environment < ApplicationRecord
end
event :stop_complete do
- transition %i(available stopping) => :stopped
+ transition %i[available stopping] => :stopped
end
state :available
diff --git a/app/models/environment_status.rb b/app/models/environment_status.rb
index 7687bc2be60..f31615f2b3b 100644
--- a/app/models/environment_status.rb
+++ b/app/models/environment_status.rb
@@ -79,7 +79,7 @@ class EnvironmentStatus
private
- PAGE_EXTENSIONS = /\A\.(s?html?|php|asp|cgi|pl)\z/i.freeze
+ PAGE_EXTENSIONS = /\A\.(s?html?|php|asp|cgi|pl)\z/i
def deployment_metrics
@deployment_metrics ||= DeploymentMetrics.new(project, deployment)
@@ -102,7 +102,6 @@ class EnvironmentStatus
return [] unless pipeline
environments = pipeline.environments_in_self_and_project_descendants.includes(:project)
- environments = environments.available if Feature.disabled?(:review_apps_redeploy_mr_widget, mr.project)
environments.map do |environment|
next unless Ability.allowed?(user, :read_environment, environment)
diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb
index c52f8a58c00..318538be645 100644
--- a/app/models/error_tracking/project_error_tracking_setting.rb
+++ b/app/models/error_tracking/project_error_tracking_setting.rb
@@ -19,7 +19,7 @@ module ErrorTracking
(?<project>[^/]+)/*
)?
\z
- }x.freeze
+ }x
self.reactive_cache_key = ->(setting) { [setting.class.model_name.singular, setting.project_id] }
self.reactive_cache_work_type = :external_dependency
diff --git a/app/models/event.rb b/app/models/event.rb
index 4547d7b9e60..9e4a662aaa5 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -10,6 +10,7 @@ class Event < ApplicationRecord
include UsageStatistics
include ShaAttribute
include IgnorableColumns
+ include EachBatch
ignore_column :target_id_convert_to_bigint, remove_with: '16.4', remove_after: '2023-09-22'
@@ -69,7 +70,7 @@ class Event < ApplicationRecord
# If the association for "target" defines an "author" association we want to
# eager-load this so Banzai & friends don't end up performing N+1 queries to
# get the authors of notes, issues, etc. (likewise for "noteable").
- incs = %i(author noteable work_item_type).select do |a|
+ incs = %i[author noteable work_item_type].select do |a|
reflections['events'].active_record.reflect_on_association(a)
end
@@ -137,7 +138,7 @@ class Event < ApplicationRecord
where(
'action IN (?) OR (target_type IN (?) AND action IN (?))',
[actions[:pushed], actions[:commented]],
- %w(MergeRequest Issue WorkItem), [actions[:created], actions[:closed], actions[:merged]]
+ %w[MergeRequest Issue WorkItem], [actions[:created], actions[:closed], actions[:merged]]
)
end
diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb
index 1bf35179393..f0cae9c88ca 100644
--- a/app/models/gpg_key.rb
+++ b/app/models/gpg_key.rb
@@ -10,7 +10,7 @@ class GpgKey < ApplicationRecord
sha_attribute :fingerprint
belongs_to :user
- has_many :gpg_signatures
+ has_many :gpg_signatures, class_name: 'CommitSignatures::GpgSignature'
has_many :subkeys, class_name: 'GpgKeySubkey'
scope :with_subkeys, -> { includes(:subkeys) }
diff --git a/app/models/group.rb b/app/models/group.rb
index 9df3c143e0c..9330ffef156 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -35,11 +35,12 @@ class Group < Namespace
foreign_key: :member_namespace_id, inverse_of: :group, class_name: 'GroupMember'
alias_method :members, :group_members
- has_many :users, through: :group_members
- has_many :owners,
- -> { where(members: { access_level: Gitlab::Access::OWNER }) },
- through: :all_group_members,
- source: :user
+ has_many :users, -> { allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/422405") },
+ through: :group_members
+ has_many :owners, -> {
+ where(members: { access_level: Gitlab::Access::OWNER })
+ .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/422405")
+ }, through: :all_group_members, source: :user
has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent
has_many :namespace_requesters, -> { where.not(requested_at: nil).unscope(where: %i[source_id source_type]) },
@@ -785,8 +786,6 @@ class Group < Namespace
end
def execute_integrations(data, hooks_scope)
- return unless Feature.enabled?(:group_mentions, self)
-
integrations.public_send(hooks_scope).each do |integration| # rubocop:disable GitlabSecurity/PublicSend
integration.async_execute(data)
end
@@ -800,7 +799,9 @@ class Group < Namespace
end
def first_owner
- owners.first || parent&.first_owner || owner
+ first_owner_member = all_group_members.all_owners.order(:user_id).first
+
+ first_owner_member&.user || parent&.first_owner || owner
end
def default_branch_name
@@ -898,6 +899,10 @@ class Group < Namespace
feature_flag_enabled_for_self_or_ancestor?(:linked_work_items)
end
+ def supports_lock_on_merge?
+ feature_flag_enabled_for_self_or_ancestor?(:enforce_locked_labels_on_merge, type: :ops)
+ end
+
def usage_quotas_enabled?
::Feature.enabled?(:usage_quotas_for_all_editions, self) && root?
end
@@ -939,12 +944,12 @@ class Group < Namespace
private
- def feature_flag_enabled_for_self_or_ancestor?(feature_flag)
+ def feature_flag_enabled_for_self_or_ancestor?(feature_flag, type: :development)
actors = [root_ancestor]
actors << self if root_ancestor != self
actors.any? do |actor|
- ::Feature.enabled?(feature_flag, actor)
+ ::Feature.enabled?(feature_flag, actor, type: type)
end
end
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index d7a95363337..c0bfe31fb38 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -103,7 +103,7 @@ class WebHook < ApplicationRecord
end
# See app/validators/json_schemas/web_hooks_url_variables.json
- VARIABLE_REFERENCE_RE = /\{([A-Za-z]+[0-9]*(?:[._-][A-Za-z0-9]+)*)\}/.freeze
+ VARIABLE_REFERENCE_RE = /\{([A-Za-z]+[0-9]*(?:[._-][A-Za-z0-9]+)*)\}/
def interpolated_url(url = self.url, url_variables = self.url_variables)
return url unless url.include?('{')
diff --git a/app/models/hooks/web_hook_log.rb b/app/models/hooks/web_hook_log.rb
index 4c35f699468..3e0c8e7c472 100644
--- a/app/models/hooks/web_hook_log.rb
+++ b/app/models/hooks/web_hook_log.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
class WebHookLog < ApplicationRecord
- include SafeUrl
include Presentable
include DeleteWithLimit
include CreatedAtFilterable
@@ -58,10 +57,18 @@ class WebHookLog < ApplicationRecord
self[:request_headers].merge('X-Gitlab-Token' => _('[REDACTED]'))
end
+ def url_current?
+ # URL hash hasn't been set, so we must assume there's no prior value to
+ # compare to.
+ return true if url_hash.nil?
+
+ Gitlab::CryptoHelper.sha256(web_hook.interpolated_url) == url_hash
+ end
+
private
def obfuscate_basic_auth
- self.url = safe_url
+ self.url = Gitlab::UrlSanitizer.sanitize_masked_url(url)
end
def redact_user_emails
diff --git a/app/models/instance_configuration.rb b/app/models/instance_configuration.rb
index 57638356362..7b2036a9def 100644
--- a/app/models/instance_configuration.rb
+++ b/app/models/instance_configuration.rb
@@ -3,7 +3,7 @@
require 'resolv'
class InstanceConfiguration
- SSH_ALGORITHMS = %w(DSA ECDSA ED25519 RSA).freeze
+ SSH_ALGORITHMS = %w[DSA ECDSA ED25519 RSA].freeze
SSH_ALGORITHMS_PATH = '/etc/ssh/'
CACHE_KEY = 'instance_configuration'
EXPIRATION_TIME = 24.hours
diff --git a/app/models/integration.rb b/app/models/integration.rb
index bc86b08018f..d4c76f743a3 100644
--- a/app/models/integration.rb
+++ b/app/models/integration.rb
@@ -63,6 +63,7 @@ class Integration < ApplicationRecord
encode: false,
encode_iv: false
+ alias_attribute :name, :title
# Handle assignment of props with symbol keys.
# To do this correctly, we need to call the method generated by attr_encrypted.
alias_method :attr_encrypted_props=, :properties=
@@ -468,11 +469,8 @@ class Integration < ApplicationRecord
[]
end
- # TODO: Once all integrations use `Integrations::Field` we can
- # use `#secret?` here.
- # See: https://gitlab.com/groups/gitlab-org/-/epics/7652
def secret_fields
- fields.select { |f| f[:type] == :password }.pluck(:name)
+ fields.select(&:secret?).pluck(:name)
end
# Expose a list of fields in the JSON endpoint.
diff --git a/app/models/integrations/apple_app_store.rb b/app/models/integrations/apple_app_store.rb
index 6f96626718f..ef12fc6bf6f 100644
--- a/app/models/integrations/apple_app_store.rb
+++ b/app/models/integrations/apple_app_store.rb
@@ -4,8 +4,8 @@ require 'app_store_connect'
module Integrations
class AppleAppStore < Integration
- ISSUER_ID_REGEX = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/.freeze
- KEY_ID_REGEX = /\A(?=.*[A-Z])(?=.*[0-9])[A-Z0-9]+\z/.freeze
+ ISSUER_ID_REGEX = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/
+ KEY_ID_REGEX = /\A(?=.*[A-Z])(?=.*[0-9])[A-Z0-9]+\z/
IS_KEY_CONTENT_BASE64 = "true"
SECTION_TYPE_APPLE_APP_STORE = 'apple_app_store'
diff --git a/app/models/integrations/asana.rb b/app/models/integrations/asana.rb
index 7436c08aa38..859522670ef 100644
--- a/app/models/integrations/asana.rb
+++ b/app/models/integrations/asana.rb
@@ -12,8 +12,7 @@ module Integrations
help: -> { s_('AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user.') },
non_empty_password_title: -> { s_('ProjectService|Enter new API key') },
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current API key.') },
- # Example Personal Access Token from Asana docs
- placeholder: '0/68a9e79b868c6789e79a124c30b0',
+ placeholder: '0/68a9e79b868c6789e79a124c30b0', # Example Personal Access Token from Asana docs
required: true
field :restrict_to_branch,
@@ -38,7 +37,7 @@ module Integrations
end
def self.supported_events
- %w(push)
+ %w[push]
end
def client
diff --git a/app/models/integrations/assembla.rb b/app/models/integrations/assembla.rb
index 6831fac32e6..1d3616b4c3b 100644
--- a/app/models/integrations/assembla.rb
+++ b/app/models/integrations/assembla.rb
@@ -28,7 +28,7 @@ module Integrations
end
def self.supported_events
- %w(push)
+ %w[push]
end
def execute(data)
diff --git a/app/models/integrations/base_chat_notification.rb b/app/models/integrations/base_chat_notification.rb
index 4d207574ca7..2c929dc2cb3 100644
--- a/app/models/integrations/base_chat_notification.rb
+++ b/app/models/integrations/base_chat_notification.rb
@@ -31,12 +31,12 @@ module Integrations
# Custom serialized properties initialization
prop_accessor(*SUPPORTED_EVENTS.map { |event| EVENT_CHANNEL[event] })
- boolean_accessor :notify_only_broken_pipelines, :notify_only_default_branch
+ boolean_accessor :notify_only_default_branch
validates :webhook,
presence: true,
public_url: true,
- if: -> (integration) { integration.activated? && integration.requires_webhook? }
+ if: -> (integration) { integration.activated? && integration.class.requires_webhook? }
validates :labels_to_be_notified_behavior, inclusion: { in: LABEL_NOTIFICATION_BEHAVIOURS }, allow_blank: true, if: :activated?
validate :validate_channel_limit, if: :activated?
@@ -44,7 +44,7 @@ module Integrations
super
if properties.empty?
- self.notify_only_broken_pipelines = true
+ self.notify_only_broken_pipelines = true if self.respond_to?(:notify_only_broken_pipelines)
self.branches_to_be_notified = "default"
self.labels_to_be_notified_behavior = MATCH_ANY_LABEL
elsif !self.notify_only_default_branch.nil?
@@ -72,48 +72,7 @@ module Integrations
end
def fields
- default_fields + build_event_channels
- end
-
- def default_fields
- [
- {
- type: :checkbox,
- section: SECTION_TYPE_CONFIGURATION,
- name: 'notify_only_broken_pipelines',
- help: 'Do not send notifications for successful pipelines.'
- }.freeze,
- {
- type: :select,
- section: SECTION_TYPE_CONFIGURATION,
- name: 'branches_to_be_notified',
- title: s_('Integrations|Branches for which notifications are to be sent'),
- choices: self.class.branch_choices
- }.freeze,
- {
- type: :text,
- section: SECTION_TYPE_CONFIGURATION,
- name: 'labels_to_be_notified',
- placeholder: '~backend,~frontend',
- help: 'Send notifications for issue, merge request, and comment events with the listed labels only. Leave blank to receive notifications for all events.'
- }.freeze,
- {
- type: :select,
- section: SECTION_TYPE_CONFIGURATION,
- name: 'labels_to_be_notified_behavior',
- choices: [
- ['Match any of the labels', MATCH_ANY_LABEL],
- ['Match all of the labels', MATCH_ALL_LABELS]
- ]
- }.freeze
- ].tap do |fields|
- next unless requires_webhook?
-
- fields.unshift(
- { type: :text, name: 'webhook', help: webhook_help, required: true }.freeze,
- { type: :text, name: 'username', placeholder: 'GitLab-integration' }.freeze
- )
- end.freeze
+ self.class.fields + build_event_channels
end
def execute(data)
@@ -154,6 +113,15 @@ module Integrations
supported_events.map { |event| event_channel_name(event) }
end
+ override :api_field_names
+ def api_field_names
+ if mask_configurable_channels?
+ super - event_channel_names
+ else
+ super
+ end
+ end
+
def form_fields
super.reject { |field| field[:name].end_with?('channel') }
end
@@ -166,6 +134,10 @@ module Integrations
raise NotImplementedError
end
+ def help
+ raise NotImplementedError
+ end
+
# With some integrations the webhook is already tied to a specific channel,
# for others the channels are configurable for each event.
def configurable_channels?
@@ -181,7 +153,7 @@ module Integrations
self.public_send(field_name) # rubocop:disable GitlabSecurity/PublicSend
end
- def requires_webhook?
+ def self.requires_webhook?
true
end
@@ -193,11 +165,32 @@ module Integrations
false
end
+ override :sections
+ def sections
+ [
+ {
+ type: SECTION_TYPE_CONNECTION,
+ title: s_('Integrations|Connection details'),
+ description: help
+ },
+ {
+ type: SECTION_TYPE_TRIGGER,
+ title: s_('Integrations|Trigger'),
+ description: s_('Integrations|An event will be triggered when one of the following items happen.')
+ },
+ {
+ type: SECTION_TYPE_CONFIGURATION,
+ title: s_('Integrations|Notification settings'),
+ description: s_('Integrations|Configure the scope of notifications.')
+ }
+ ]
+ end
+
private
def should_execute?(object_kind)
supported_events.include?(object_kind) &&
- (!requires_webhook? || webhook.present?)
+ (!self.class.requires_webhook? || webhook.present?)
end
def log_usage(_, _)
@@ -264,7 +257,7 @@ module Integrations
def build_event_channels
event_channel_names.map do |channel_field|
- { type: :text, name: channel_field, placeholder: default_channel_placeholder }
+ Field.new(name: channel_field, type: :text, placeholder: default_channel_placeholder, integration_class: self)
end
end
diff --git a/app/models/integrations/base_issue_tracker.rb b/app/models/integrations/base_issue_tracker.rb
index 7a54d354007..b59aee6743d 100644
--- a/app/models/integrations/base_issue_tracker.rb
+++ b/app/models/integrations/base_issue_tracker.rb
@@ -88,7 +88,7 @@ module Integrations
end
def self.supported_events
- %w(push)
+ %w[push]
end
def execute(data)
diff --git a/app/models/integrations/base_monitoring.rb b/app/models/integrations/base_monitoring.rb
index b0bebb5a859..12ea57f59a3 100644
--- a/app/models/integrations/base_monitoring.rb
+++ b/app/models/integrations/base_monitoring.rb
@@ -9,7 +9,7 @@ module Integrations
attribute :category, default: 'monitoring'
def self.supported_events
- %w()
+ %w[]
end
def can_query?
diff --git a/app/models/integrations/base_slack_notification.rb b/app/models/integrations/base_slack_notification.rb
index 29a20419809..65aec8b278f 100644
--- a/app/models/integrations/base_slack_notification.rb
+++ b/app/models/integrations/base_slack_notification.rb
@@ -25,20 +25,24 @@ module Integrations
override :supported_events
def supported_events
- additional = %w[alert]
-
- if group_level? && Feature.enabled?(:group_mentions, group)
- additional += %w[group_mention group_confidential_mention]
- end
+ additional = group_level? ? %w[group_mention group_confidential_mention] : []
(super + additional).freeze
end
+ def self.supported_events
+ super + %w[alert]
+ end
+
override :configurable_channels?
def configurable_channels?
true
end
+ def help
+ # noop
+ end
+
private
override :log_usage
diff --git a/app/models/integrations/base_slash_commands.rb b/app/models/integrations/base_slash_commands.rb
index 7662da933ba..58821e5fb4e 100644
--- a/app/models/integrations/base_slash_commands.rb
+++ b/app/models/integrations/base_slash_commands.rb
@@ -13,7 +13,7 @@ module Integrations
end
def self.supported_events
- %w()
+ %w[]
end
def testable?
diff --git a/app/models/integrations/base_third_party_wiki.rb b/app/models/integrations/base_third_party_wiki.rb
index 8df172e9a53..dee3706c518 100644
--- a/app/models/integrations/base_third_party_wiki.rb
+++ b/app/models/integrations/base_third_party_wiki.rb
@@ -9,7 +9,7 @@ module Integrations
after_commit :cache_project_has_integration
def self.supported_events
- %w()
+ %w[]
end
private
diff --git a/app/models/integrations/buildkite.rb b/app/models/integrations/buildkite.rb
index 6cd36e545a5..82a5142e8c2 100644
--- a/app/models/integrations/buildkite.rb
+++ b/app/models/integrations/buildkite.rb
@@ -29,7 +29,7 @@ module Integrations
validates :token, presence: true, if: :activated?
def self.supported_events
- %w(push merge_request tag_push)
+ %w[push merge_request tag_push]
end
# This is a stub method to work with deprecated API response
diff --git a/app/models/integrations/campfire.rb b/app/models/integrations/campfire.rb
index 007578e5830..8b5797a9d24 100644
--- a/app/models/integrations/campfire.rb
+++ b/app/models/integrations/campfire.rb
@@ -2,7 +2,7 @@
module Integrations
class Campfire < Integration
- SUBDOMAIN_REGEXP = %r{\A[a-z](?:[a-z0-9-]*[a-z0-9])?\z}i.freeze
+ SUBDOMAIN_REGEXP = %r{\A[a-z](?:[a-z0-9-]*[a-z0-9])?\z}i
validates :token, presence: true, if: :activated?
validates :room,
@@ -26,12 +26,9 @@ module Integrations
placeholder: '',
exposes_secrets: true,
help: -> do
- ERB::Util.html_escape(
+ format(ERB::Util.html_escape(
s_('CampfireService|The %{code_open}.campfirenow.com%{code_close} subdomain.')
- ) % {
- code_open: '<code>'.html_safe,
- code_close: '</code>'.html_safe
- }
+ ), code_open: '<code>'.html_safe, code_close: '</code>'.html_safe)
end
field :room,
@@ -48,13 +45,16 @@ module Integrations
end
def help
- docs_link = ActionController::Base.helpers.link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('api/services', anchor: 'campfire'), target: '_blank', rel: 'noopener noreferrer'
-
- ERB::Util.html_escape(
+ docs_link = ActionController::Base.helpers.link_to(
+ _('Learn more.'),
+ Rails.application.routes.url_helpers.help_page_url('api/integrations', anchor: 'campfire'),
+ target: '_blank',
+ rel: 'noopener noreferrer'
+ )
+
+ format(ERB::Util.html_escape(
s_('CampfireService|Send notifications about push events to Campfire chat rooms. %{docs_link}')
- ) % {
- docs_link: docs_link.html_safe
- }
+ ), docs_link: docs_link.html_safe)
end
def self.to_param
@@ -62,14 +62,14 @@ module Integrations
end
def self.supported_events
- %w(push)
+ %w[push]
end
def execute(data)
return unless supported_events.include?(data[:object_kind])
message = create_message(data)
- speak(self.room, message, auth)
+ speak(room, message, auth)
end
private
@@ -96,7 +96,7 @@ module Integrations
room = rooms(auth).find { |r| r["name"] == room_name }
return unless room
- path = "/room/#{room["id"]}/speak.json"
+ path = "/room/#{room['id']}/speak.json"
body = {
body: {
message: {
diff --git a/app/models/integrations/chat_message/base_message.rb b/app/models/integrations/chat_message/base_message.rb
index 501b214a769..600f07b97f1 100644
--- a/app/models/integrations/chat_message/base_message.rb
+++ b/app/models/integrations/chat_message/base_message.rb
@@ -3,7 +3,7 @@
module Integrations
module ChatMessage
class BaseMessage
- RELATIVE_LINK_REGEX = %r{!\[[^\]]*\]\((/uploads/[^\)]*)\)}.freeze
+ RELATIVE_LINK_REGEX = %r{!\[[^\]]*\]\((/uploads/[^\)]*)\)}
attr_reader :markdown
attr_reader :user_full_name
diff --git a/app/models/integrations/chat_message/deployment_message.rb b/app/models/integrations/chat_message/deployment_message.rb
index b28edeecb4d..0367459dfcb 100644
--- a/app/models/integrations/chat_message/deployment_message.rb
+++ b/app/models/integrations/chat_message/deployment_message.rb
@@ -26,8 +26,10 @@ module Integrations
end
def attachments
+ return description_message if markdown
+
[{
- text: "#{project_link} with job #{deployment_link} by #{user_link}\n#{commit_link}: #{strip_markup(commit_title)}",
+ text: format(description_message),
color: color
}]
end
@@ -82,6 +84,10 @@ module Integrations
def running?
status == 'running'
end
+
+ def description_message
+ "#{project_link} with job #{deployment_link} by #{user_link}\n#{commit_link}: #{strip_markup(commit_title)}"
+ end
end
end
end
diff --git a/app/models/integrations/confluence.rb b/app/models/integrations/confluence.rb
index 31e9a171d1b..eda8c37fc72 100644
--- a/app/models/integrations/confluence.rb
+++ b/app/models/integrations/confluence.rb
@@ -2,9 +2,9 @@
module Integrations
class Confluence < BaseThirdPartyWiki
- VALID_SCHEME_MATCH = %r{\Ahttps?\Z}.freeze
- VALID_HOST_MATCH = %r{\A.+\.atlassian\.net\Z}.freeze
- VALID_PATH_MATCH = %r{\A/wiki(/|\Z)}.freeze
+ VALID_SCHEME_MATCH = %r{\Ahttps?\Z}
+ VALID_HOST_MATCH = %r{\A.+\.atlassian\.net\Z}
+ VALID_PATH_MATCH = %r{\A/wiki(/|\Z)}
validates :confluence_url, presence: true, if: :activated?
validate :validate_confluence_url_is_cloud, if: :activated?
@@ -14,6 +14,10 @@ module Integrations
placeholder: 'https://example.atlassian.net/wiki',
required: true
+ def avatar_url
+ ActionController::Base.helpers.image_path('confluence.svg')
+ end
+
def self.to_param
'confluence'
end
diff --git a/app/models/integrations/datadog.rb b/app/models/integrations/datadog.rb
index 1a56763fe57..b1f1361afcd 100644
--- a/app/models/integrations/datadog.rb
+++ b/app/models/integrations/datadog.rb
@@ -12,7 +12,7 @@ module Integrations
pipeline build archive_trace
].freeze
- TAG_KEY_VALUE_RE = %r{\A [\w-]+ : .*\S.* \z}x.freeze
+ TAG_KEY_VALUE_RE = %r{\A [\w-]+ : .*\S.* \z}x
field :datadog_site,
exposes_secrets: true,
@@ -40,7 +40,7 @@ module Integrations
ERB::Util.html_escape(
s_('DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog.')
) % {
- linkOpen: %{<a href="#{URL_API_KEYS_DOCS}" target="_blank" rel="noopener noreferrer">}.html_safe,
+ linkOpen: %(<a href="#{URL_API_KEYS_DOCS}" target="_blank" rel="noopener noreferrer">).html_safe,
linkClose: '</a>'.html_safe
}
end,
diff --git a/app/models/integrations/discord.rb b/app/models/integrations/discord.rb
index 7cae3ca20f9..815e3669d78 100644
--- a/app/models/integrations/discord.rb
+++ b/app/models/integrations/discord.rb
@@ -4,9 +4,7 @@ require "discordrb/webhooks"
module Integrations
class Discord < BaseChatNotification
- ATTACHMENT_REGEX = /: (?<entry>.*?)\n - (?<name>.*)\n*/.freeze
-
- undef :notify_only_broken_pipelines
+ ATTACHMENT_REGEX = /: (?<entry>.*?)\n - (?<name>.*)\n*/
field :webhook,
section: SECTION_TYPE_CONNECTION,
@@ -35,10 +33,6 @@ module Integrations
"discord"
end
- def fields
- self.class.fields + build_event_channels
- end
-
def help
docs_link = ActionController::Base.helpers.link_to _('How do I set up this service?'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/discord_notifications'), target: '_blank', rel: 'noopener noreferrer'
s_('Send notifications about project events to a Discord channel. %{docs_link}').html_safe % { docs_link: docs_link.html_safe }
@@ -52,26 +46,6 @@ module Integrations
%w[push issue confidential_issue merge_request note confidential_note tag_push pipeline wiki_page]
end
- def sections
- [
- {
- type: SECTION_TYPE_CONNECTION,
- title: s_('Integrations|Connection details'),
- description: help
- },
- {
- type: SECTION_TYPE_TRIGGER,
- title: s_('Integrations|Trigger'),
- description: s_('Integrations|An event will be triggered when one of the following items happen.')
- },
- {
- type: SECTION_TYPE_CONFIGURATION,
- title: s_('Integrations|Notification settings'),
- description: s_('Integrations|Configure the scope of notifications.')
- }
- ]
- end
-
def configurable_channels?
true
end
diff --git a/app/models/integrations/drone_ci.rb b/app/models/integrations/drone_ci.rb
index ac464c020dd..f6a12c4bb1a 100644
--- a/app/models/integrations/drone_ci.rb
+++ b/app/models/integrations/drone_ci.rb
@@ -43,7 +43,7 @@ module Integrations
end
def self.supported_events
- %w(push merge_request tag_push)
+ %w[push merge_request tag_push]
end
def commit_status_path(sha, ref)
diff --git a/app/models/integrations/emails_on_push.rb b/app/models/integrations/emails_on_push.rb
index eb893ae45d0..144d1a07b04 100644
--- a/app/models/integrations/emails_on_push.rb
+++ b/app/models/integrations/emails_on_push.rb
@@ -52,7 +52,7 @@ module Integrations
end
def self.supported_events
- %w(push tag_push)
+ %w[push tag_push]
end
def initialize_properties
diff --git a/app/models/integrations/external_wiki.rb b/app/models/integrations/external_wiki.rb
index 75fe6b6f164..acacab2528e 100644
--- a/app/models/integrations/external_wiki.rb
+++ b/app/models/integrations/external_wiki.rb
@@ -47,7 +47,7 @@ module Integrations
end
def self.supported_events
- %w()
+ %w[]
end
end
end
diff --git a/app/models/integrations/gitlab_slack_application.rb b/app/models/integrations/gitlab_slack_application.rb
index b0f54f39e8c..2d520eaf7e7 100644
--- a/app/models/integrations/gitlab_slack_application.rb
+++ b/app/models/integrations/gitlab_slack_application.rb
@@ -20,6 +20,8 @@ module Integrations
has_one :slack_integration, foreign_key: :integration_id, inverse_of: :integration
delegate :bot_access_token, :bot_user_id, to: :slack_integration, allow_nil: true
+ include SlackMattermostFields
+
def update_active_status
update(active: !!slack_integration)
end
@@ -66,18 +68,7 @@ module Integrations
def sections
return [] unless editable?
- [
- {
- type: SECTION_TYPE_TRIGGER,
- title: s_('Integrations|Trigger'),
- description: s_('Integrations|An event will be triggered when one of the following items happen.')
- },
- {
- type: SECTION_TYPE_CONFIGURATION,
- title: s_('Integrations|Notification settings'),
- description: s_('Integrations|Configure the scope of notifications.')
- }
- ]
+ super.drop(1)
end
override :configurable_events
@@ -88,7 +79,7 @@ module Integrations
end
override :requires_webhook?
- def requires_webhook?
+ def self.requires_webhook?
false
end
diff --git a/app/models/integrations/hangouts_chat.rb b/app/models/integrations/hangouts_chat.rb
index 037c689c75e..680752c3d56 100644
--- a/app/models/integrations/hangouts_chat.rb
+++ b/app/models/integrations/hangouts_chat.rb
@@ -2,8 +2,6 @@
module Integrations
class HangoutsChat < BaseChatNotification
- undef :notify_only_broken_pipelines
-
field :webhook,
section: SECTION_TYPE_CONNECTION,
help: 'https://chat.googleapis.com/v1/spaces…',
@@ -36,10 +34,6 @@ module Integrations
s_('Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}').html_safe % { docs_link: docs_link.html_safe }
end
- def fields
- self.class.fields + build_event_channels
- end
-
def default_channel_placeholder
end
diff --git a/app/models/integrations/jenkins.rb b/app/models/integrations/jenkins.rb
index 7769ea7d2dd..0683c8408bc 100644
--- a/app/models/integrations/jenkins.rb
+++ b/app/models/integrations/jenkins.rb
@@ -66,7 +66,7 @@ module Integrations
end
def self.supported_events
- %w(push merge_request tag_push)
+ %w[push merge_request tag_push]
end
def title
diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb
index faf0a378a17..d8d1f860e9a 100644
--- a/app/models/integrations/jira.rb
+++ b/app/models/integrations/jira.rb
@@ -126,7 +126,7 @@ module Integrations
# When these are false GitLab does not create cross reference
# comments on Jira except when an issue gets transitioned.
def self.supported_events
- %w(commit merge_request)
+ %w[commit merge_request]
end
# {PROJECT-KEY}-{NUMBER} Examples: JIRA-1, PROJECT-1
diff --git a/app/models/integrations/mattermost.rb b/app/models/integrations/mattermost.rb
index e3c5c22ad3a..7e391b11d82 100644
--- a/app/models/integrations/mattermost.rb
+++ b/app/models/integrations/mattermost.rb
@@ -3,6 +3,7 @@
module Integrations
class Mattermost < BaseChatNotification
include SlackMattermostNotifier
+ include SlackMattermostFields
def title
_('Mattermost notifications')
@@ -25,7 +26,7 @@ module Integrations
'my-channel'
end
- def webhook_help
+ def self.webhook_help
'http://mattermost.example.com/hooks/'
end
diff --git a/app/models/integrations/microsoft_teams.rb b/app/models/integrations/microsoft_teams.rb
index 25308948d51..208172d6303 100644
--- a/app/models/integrations/microsoft_teams.rb
+++ b/app/models/integrations/microsoft_teams.rb
@@ -2,8 +2,6 @@
module Integrations
class MicrosoftTeams < BaseChatNotification
- undef :notify_only_broken_pipelines
-
field :webhook,
section: SECTION_TYPE_CONNECTION,
help: 'https://outlook.office.com/webhook/…',
@@ -44,30 +42,6 @@ module Integrations
pipeline wiki_page]
end
- def fields
- self.class.fields + build_event_channels
- end
-
- def sections
- [
- {
- type: SECTION_TYPE_CONNECTION,
- title: s_('Integrations|Connection details'),
- description: help
- },
- {
- type: SECTION_TYPE_TRIGGER,
- title: s_('Integrations|Trigger'),
- description: s_('Integrations|An event will be triggered when one of the following items happen.')
- },
- {
- type: SECTION_TYPE_CONFIGURATION,
- title: s_('Integrations|Notification settings'),
- description: s_('Integrations|Configure the scope of notifications.')
- }
- ]
- end
-
private
def notify(message, opts)
diff --git a/app/models/integrations/packagist.rb b/app/models/integrations/packagist.rb
index c9c08ec9771..c0acb6c87b4 100644
--- a/app/models/integrations/packagist.rb
+++ b/app/models/integrations/packagist.rb
@@ -42,7 +42,7 @@ module Integrations
end
def self.supported_events
- %w(push merge_request tag_push)
+ %w[push merge_request tag_push]
end
def execute(data)
diff --git a/app/models/integrations/pivotaltracker.rb b/app/models/integrations/pivotaltracker.rb
index 0d9a3f05a86..f42a872c49e 100644
--- a/app/models/integrations/pivotaltracker.rb
+++ b/app/models/integrations/pivotaltracker.rb
@@ -38,7 +38,7 @@ module Integrations
end
def self.supported_events
- %w(push)
+ %w[push]
end
def execute(data)
diff --git a/app/models/integrations/prometheus.rb b/app/models/integrations/prometheus.rb
index 736318ed707..8474a5b7adf 100644
--- a/app/models/integrations/prometheus.rb
+++ b/app/models/integrations/prometheus.rb
@@ -41,6 +41,7 @@ module Integrations
before_save :synchronize_service_state
after_save :clear_reactive_cache!
+ after_commit :sync_http_integration!
after_commit :track_events
@@ -180,5 +181,16 @@ module Integrations
nil
end
strong_memoize_attr :iap_client
+
+ # Remove in next required stop after %16.4
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/338838
+ def sync_http_integration!
+ return unless manual_configuration_changed?
+
+ project.alert_management_http_integrations
+ .for_endpoint_identifier('legacy-prometheus')
+ .take
+ &.update_columns(active: manual_configuration)
+ end
end
end
diff --git a/app/models/integrations/pumble.rb b/app/models/integrations/pumble.rb
index 8f0dddcc5c5..09e011023ed 100644
--- a/app/models/integrations/pumble.rb
+++ b/app/models/integrations/pumble.rb
@@ -2,8 +2,6 @@
module Integrations
class Pumble < BaseChatNotification
- undef :notify_only_broken_pipelines
-
field :webhook,
section: SECTION_TYPE_CONNECTION,
help: 'https://api.pumble.com/workspaces/x/...',
@@ -52,10 +50,6 @@ module Integrations
pipeline wiki_page]
end
- def fields
- self.class.fields + build_event_channels
- end
-
private
def notify(message, opts)
diff --git a/app/models/integrations/pushover.rb b/app/models/integrations/pushover.rb
index 006b731c6c2..e97c7e5e738 100644
--- a/app/models/integrations/pushover.rb
+++ b/app/models/integrations/pushover.rb
@@ -47,19 +47,19 @@ module Integrations
[
['Device default sound', nil],
['Pushover (default)', 'pushover'],
- %w(Bike bike),
- %w(Bugle bugle),
+ %w[Bike bike],
+ %w[Bugle bugle],
['Cash Register', 'cashregister'],
- %w(Classical classical),
- %w(Cosmic cosmic),
- %w(Falling falling),
- %w(Gamelan gamelan),
- %w(Incoming incoming),
- %w(Intermission intermission),
- %w(Magic magic),
- %w(Mechanical mechanical),
+ %w[Classical classical],
+ %w[Cosmic cosmic],
+ %w[Falling falling],
+ %w[Gamelan gamelan],
+ %w[Incoming incoming],
+ %w[Intermission intermission],
+ %w[Magic magic],
+ %w[Mechanical mechanical],
['Piano Bar', 'pianobar'],
- %w(Siren siren),
+ %w[Siren siren],
['Space Alarm', 'spacealarm'],
['Tug Boat', 'tugboat'],
['Alien Alarm (long)', 'alien'],
@@ -84,7 +84,7 @@ module Integrations
end
def self.supported_events
- %w(push)
+ %w[push]
end
def execute(data)
diff --git a/app/models/integrations/shimo.rb b/app/models/integrations/shimo.rb
index f5b6595fff2..227fdca5c91 100644
--- a/app/models/integrations/shimo.rb
+++ b/app/models/integrations/shimo.rb
@@ -8,6 +8,10 @@ module Integrations
title: -> { s_('Shimo|Shimo Workspace URL') },
required: true
+ def avatar_url
+ ActionController::Base.helpers.image_path('logos/shimo.svg')
+ end
+
def render?
valid? && activated?
end
diff --git a/app/models/integrations/slack.rb b/app/models/integrations/slack.rb
index 07d2d802915..f70376e2f0d 100644
--- a/app/models/integrations/slack.rb
+++ b/app/models/integrations/slack.rb
@@ -3,6 +3,7 @@
module Integrations
class Slack < BaseSlackNotification
include SlackMattermostNotifier
+ include SlackMattermostFields
def title
'Slack notifications'
@@ -16,8 +17,7 @@ module Integrations
'slack'
end
- override :webhook_help
- def webhook_help
+ def self.webhook_help
'https://hooks.slack.com/services/…'
end
diff --git a/app/models/integrations/teamcity.rb b/app/models/integrations/teamcity.rb
index c74e0aab030..575c3b8a334 100644
--- a/app/models/integrations/teamcity.rb
+++ b/app/models/integrations/teamcity.rb
@@ -6,7 +6,7 @@ module Integrations
include ReactivelyCached
prepend EnableSslVerification
- TEAMCITY_SAAS_HOSTNAME = /\A[^\.]+\.teamcity\.com\z/i.freeze
+ TEAMCITY_SAAS_HOSTNAME = /\A[^\.]+\.teamcity\.com\z/i
field :teamcity_url,
title: -> { s_('ProjectService|TeamCity server URL') },
@@ -43,7 +43,7 @@ module Integrations
end
def supported_events
- %w(push merge_request)
+ %w[push merge_request]
end
end
diff --git a/app/models/integrations/telegram.rb b/app/models/integrations/telegram.rb
index 9af12c712c6..7c196720386 100644
--- a/app/models/integrations/telegram.rb
+++ b/app/models/integrations/telegram.rb
@@ -21,6 +21,11 @@ module Integrations
placeholder: '@channelusername',
required: true
+ field :notify_only_broken_pipelines,
+ type: :checkbox,
+ section: SECTION_TYPE_CONFIGURATION,
+ help: 'If selected, successful pipelines do not trigger a notification event.'
+
with_options if: :activated? do
validates :token, :room, presence: true
end
@@ -51,34 +56,10 @@ module Integrations
)
end
- def fields
- self.class.fields + build_event_channels
- end
-
def self.supported_events
super - ['deployment']
end
- def sections
- [
- {
- type: SECTION_TYPE_CONNECTION,
- title: s_('Integrations|Connection details'),
- description: help
- },
- {
- type: SECTION_TYPE_TRIGGER,
- title: s_('Integrations|Trigger'),
- description: s_('Integrations|An event will be triggered when one of the following items happen.')
- },
- {
- type: SECTION_TYPE_CONFIGURATION,
- title: s_('Integrations|Notification settings'),
- description: s_('Integrations|Configure the scope of notifications.')
- }
- ]
- end
-
private
def set_webhook
diff --git a/app/models/integrations/unify_circuit.rb b/app/models/integrations/unify_circuit.rb
index 6de693b5278..3b4bcfa28d3 100644
--- a/app/models/integrations/unify_circuit.rb
+++ b/app/models/integrations/unify_circuit.rb
@@ -2,8 +2,6 @@
module Integrations
class UnifyCircuit < BaseChatNotification
- undef :notify_only_broken_pipelines
-
field :webhook,
section: SECTION_TYPE_CONNECTION,
help: 'https://yourcircuit.com/rest/v2/webhooks/incoming/…',
@@ -31,10 +29,6 @@ module Integrations
'unify_circuit'
end
- def fields
- self.class.fields + build_event_channels
- end
-
def help
docs_link = ActionController::Base.helpers.link_to _('How do I set up this service?'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/unify_circuit'), target: '_blank', rel: 'noopener noreferrer'
s_('Integrations|Send notifications about project events to a Unify Circuit conversation. %{docs_link}').html_safe % { docs_link: docs_link.html_safe }
diff --git a/app/models/integrations/webex_teams.rb b/app/models/integrations/webex_teams.rb
index 21c65cc2b32..3ef8ab39352 100644
--- a/app/models/integrations/webex_teams.rb
+++ b/app/models/integrations/webex_teams.rb
@@ -2,8 +2,6 @@
module Integrations
class WebexTeams < BaseChatNotification
- undef :notify_only_broken_pipelines
-
field :webhook,
section: SECTION_TYPE_CONNECTION,
help: 'https://api.ciscospark.com/v1/webhooks/incoming/...',
@@ -31,10 +29,6 @@ module Integrations
'webex_teams'
end
- def fields
- self.class.fields + build_event_channels
- end
-
def help
docs_link = ActionController::Base.helpers.link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('user/project/integrations/webex_teams'), target: '_blank', rel: 'noopener noreferrer'
s_("WebexTeamsService|Send notifications about project events to a Webex Teams conversation. %{docs_link}") % { docs_link: docs_link.html_safe }
diff --git a/app/models/integrations/zentao.rb b/app/models/integrations/zentao.rb
index fd2c741bd6b..58ec4abf30c 100644
--- a/app/models/integrations/zentao.rb
+++ b/app/models/integrations/zentao.rb
@@ -34,6 +34,10 @@ module Integrations
validates :api_token, presence: true, if: :activated?
validates :zentao_product_xid, presence: true, if: :activated?
+ def avatar_url
+ ActionController::Base.helpers.image_path('logos/zentao.svg')
+ end
+
def self.issues_license_available?(project)
project&.licensed_feature_available?(:zentao_issues_integration)
end
@@ -82,7 +86,7 @@ module Integrations
end
def self.supported_events
- %w()
+ %w[]
end
private
diff --git a/app/models/issuable_severity.rb b/app/models/issuable_severity.rb
index cd7e5fafb60..08984bbb723 100644
--- a/app/models/issuable_severity.rb
+++ b/app/models/issuable_severity.rb
@@ -11,11 +11,11 @@ class IssuableSeverity < ApplicationRecord
}.freeze
SEVERITY_QUICK_ACTION_PARAMS = {
- unknown: %w(Unknown 0),
- low: %w(Low S4 4),
- medium: %w(Medium S3 3),
- high: %w(High S2 2),
- critical: %w(Critical S1 1)
+ unknown: %w[Unknown 0],
+ low: %w[Low S4 4],
+ medium: %w[Medium S3 3],
+ high: %w[High S2 2],
+ critical: %w[Critical S1 1]
}.freeze
belongs_to :issue
diff --git a/app/models/issue.rb b/app/models/issue.rb
index d227448961a..58383a6a329 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -14,7 +14,6 @@ class Issue < ApplicationRecord
include TimeTrackable
include ThrottledTouch
include LabelEventable
- include IgnorableColumns
include MilestoneEventable
include WhereComposite
include StateEventable
@@ -48,16 +47,14 @@ class Issue < ApplicationRecord
#
# This should be kept consistent with the enums used for the GraphQL issue list query in
# https://gitlab.com/gitlab-org/gitlab/-/blob/1379c2d7bffe2a8d809f23ac5ef9b4114f789c07/app/assets/javascripts/issues/list/constants.js#L154-158
- TYPES_FOR_LIST = %w(issue incident test_case task objective key_result).freeze
+ TYPES_FOR_LIST = %w[issue incident test_case task objective key_result].freeze
# Types of issues that should be displayed on issue board lists
- TYPES_FOR_BOARD_LIST = %w(issue incident).freeze
+ TYPES_FOR_BOARD_LIST = %w[issue incident].freeze
# This default came from the enum `issue_type` column. Defined as default in the DB
DEFAULT_ISSUE_TYPE = :issue
- ignore_column :issue_type, remove_with: '16.4', remove_after: '2023-08-22'
-
belongs_to :project
belongs_to :namespace, inverse_of: :issues
@@ -112,7 +109,6 @@ class Issue < ApplicationRecord
has_one :sentry_issue
has_one :alert_management_alert, class_name: 'AlertManagement::Alert'
has_one :incident_management_issuable_escalation_status, class_name: 'IncidentManagement::IssuableEscalationStatus'
- has_and_belongs_to_many :self_managed_prometheus_alert_events, join_table: :issues_self_managed_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany
has_and_belongs_to_many :prometheus_alert_events, join_table: :issues_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :issue, validate: false
has_many :prometheus_alerts, through: :prometheus_alert_events
@@ -190,7 +186,6 @@ class Issue < ApplicationRecord
scope :preload_awardable, -> { preload(:award_emoji) }
scope :with_alert_management_alerts, -> { joins(:alert_management_alert) }
scope :with_prometheus_alert_events, -> { joins(:issues_prometheus_alert_events) }
- scope :with_self_managed_prometheus_alert_events, -> { joins(:issues_self_managed_prometheus_alert_events) }
scope :with_api_entity_associations, -> {
preload(:work_item_type, :timelogs, :closed_by, :assignees, :author, :labels, :issuable_severity,
namespace: [{ parent: :route }, :route], milestone: { project: [:route, { namespace: :route }] },
@@ -223,8 +218,11 @@ class Issue < ApplicationRecord
scope :counts_by_state, -> { reorder(nil).group(:state_id).count }
- scope :service_desk, -> { where(author: ::User.support_bot) }
- scope :inc_relations_for_view, -> { includes(author: :status, assignees: :status) }
+ scope :service_desk, -> { where(author: ::Users::Internal.support_bot) }
+ scope :inc_relations_for_view, -> do
+ includes(author: :status, assignees: :status)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422155')
+ end
# An issue can be uniquely identified by project_id and iid
# Takes one or more sets of composite IDs, expressed as hash-like records of
@@ -546,18 +544,14 @@ class Issue < ApplicationRecord
end
def related_issues(current_user, preload: nil)
- related_issues = self.class
- .select(['issues.*', 'issue_links.id AS issue_link_id',
- 'issue_links.link_type as issue_link_type_value',
- 'issue_links.target_id as issue_link_source_id',
- 'issue_links.created_at as issue_link_created_at',
- 'issue_links.updated_at as issue_link_updated_at'])
- .joins("INNER JOIN issue_links ON
- (issue_links.source_id = issues.id AND issue_links.target_id = #{id})
- OR
- (issue_links.target_id = issues.id AND issue_links.source_id = #{id})")
- .preload(preload)
- .reorder('issue_link_id')
+ related_issues =
+ linked_issues_select
+ .joins("INNER JOIN issue_links ON
+ (issue_links.source_id = issues.id AND issue_links.target_id = #{id})
+ OR
+ (issue_links.target_id = issues.id AND issue_links.source_id = #{id})")
+ .preload(preload)
+ .reorder('issue_link_id')
related_issues = yield related_issues if block_given?
@@ -607,7 +601,7 @@ class Issue < ApplicationRecord
end
end
- def etag_caching_enabled?
+ def real_time_notes_enabled?
true
end
@@ -642,7 +636,7 @@ class Issue < ApplicationRecord
end
def from_service_desk?
- author.id == User.support_bot.id
+ author.id == Users::Internal.support_bot.id
end
def issue_link_type
@@ -716,8 +710,8 @@ class Issue < ApplicationRecord
end
def expire_etag_cache
- # TODO: Fix this for the case when issues is created at group level
- # TODO: https://gitlab.com/gitlab-org/gitlab/-/work_items/395814
+ # We don't expire the cache for issues that don't have a project, since they are created at the group level
+ # and they are only displayed in the new work item view that uses GraphQL subscriptions for real-time updates
return unless project
key = Gitlab::Routing.url_helpers.realtime_changes_project_issue_path(project, self)
@@ -789,7 +783,7 @@ class Issue < ApplicationRecord
# TODO: https://gitlab.com/gitlab-org/gitlab/-/work_items/393126
return unless project
- Issues::SearchData.upsert({ namespace_id: namespace_id, project_id: project_id, issue_id: id, search_vector: search_vector }, unique_by: %i(project_id issue_id))
+ Issues::SearchData.upsert({ namespace_id: namespace_id, project_id: project_id, issue_id: id, search_vector: search_vector }, unique_by: %i[project_id issue_id])
end
def ensure_metrics!
@@ -833,6 +827,14 @@ class Issue < ApplicationRecord
errors.add(:work_item_type_id, format(_('can not be changed to %{new_type}'), new_type: work_item_type&.name))
end
+
+ def linked_issues_select
+ self.class.select(['issues.*', 'issue_links.id AS issue_link_id',
+ 'issue_links.link_type as issue_link_type_value',
+ 'issue_links.target_id as issue_link_source_id',
+ 'issue_links.created_at as issue_link_created_at',
+ 'issue_links.updated_at as issue_link_updated_at'])
+ end
end
Issue.prepend_mod_with('Issue')
diff --git a/app/models/label_link.rb b/app/models/label_link.rb
index d326b07ad31..0c2d205c641 100644
--- a/app/models/label_link.rb
+++ b/app/models/label_link.rb
@@ -24,3 +24,5 @@ class LabelLink < ApplicationRecord
relation
end
end
+
+LabelLink.prepend_mod_with('LabelLink')
diff --git a/app/models/lfs_download_object.rb b/app/models/lfs_download_object.rb
index 3df6742fbc9..046e47262dd 100644
--- a/app/models/lfs_download_object.rb
+++ b/app/models/lfs_download_object.rb
@@ -9,7 +9,7 @@ class LfsDownloadObject
validates :oid, format: { with: /\A\h{64}\z/ }
validates :size, numericality: { greater_than_or_equal_to: 0 }
- validates :link, public_url: { protocols: %w(http https) }
+ validates :link, public_url: { protocols: %w[http https] }
validate :headers_must_be_hash
def initialize(oid:, size:, link:, headers: {})
diff --git a/app/models/license_template.rb b/app/models/license_template.rb
index 548066107c1..bfe2a8d379e 100644
--- a/app/models/license_template.rb
+++ b/app/models/license_template.rb
@@ -5,12 +5,12 @@ class LicenseTemplate
%r{[\<\{\[]
(project|description|
one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here
- [\>\}\]]}xi.freeze
- YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze
+ [\>\}\]]}xi
+ YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i
FULLNAME_TEMPLATE_REGEX =
%r{[\<\{\[]
(fullname|name\sof\s(author|copyright\sowner))
- [\>\}\]]}xi.freeze
+ [\>\}\]]}xi
attr_reader :key, :name, :project, :category, :nickname, :url, :meta
diff --git a/app/models/loose_foreign_keys/modification_tracker.rb b/app/models/loose_foreign_keys/modification_tracker.rb
index 72a596d2114..eec9b8ad285 100644
--- a/app/models/loose_foreign_keys/modification_tracker.rb
+++ b/app/models/loose_foreign_keys/modification_tracker.rb
@@ -2,10 +2,6 @@
module LooseForeignKeys
class ModificationTracker
- MAX_DELETES = 100_000
- MAX_UPDATES = 50_000
- MAX_RUNTIME = 30.seconds # must be less than the scheduling frequency of the LooseForeignKeys::CleanupWorker cron worker
-
delegate :monotonic_time, to: :'Gitlab::Metrics::System'
def initialize
@@ -22,6 +18,18 @@ module LooseForeignKeys
)
end
+ def max_runtime
+ 30.seconds
+ end
+
+ def max_deletes
+ 100_000
+ end
+
+ def max_updates
+ 50_000
+ end
+
def add_deletions(table, count)
@delete_count_by_table[table] += count
@deletes_counter.increment({ table: table }, count)
@@ -33,9 +41,9 @@ module LooseForeignKeys
end
def over_limit?
- @delete_count_by_table.values.sum >= MAX_DELETES ||
- @update_count_by_table.values.sum >= MAX_UPDATES ||
- monotonic_time - @start_time >= MAX_RUNTIME
+ @delete_count_by_table.values.sum >= max_deletes ||
+ @update_count_by_table.values.sum >= max_updates ||
+ monotonic_time - @start_time >= max_runtime
end
def stats
diff --git a/app/models/loose_foreign_keys/turbo_modification_tracker.rb b/app/models/loose_foreign_keys/turbo_modification_tracker.rb
new file mode 100644
index 00000000000..5229b17e971
--- /dev/null
+++ b/app/models/loose_foreign_keys/turbo_modification_tracker.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module LooseForeignKeys
+ # This is a modification tracker with the additional limits that can be enabled
+ # for some database via an OPS Feature Flag.
+
+ class TurboModificationTracker < ModificationTracker
+ extend ::Gitlab::Utils::Override
+
+ override :max_runtime
+ def max_runtime
+ 45.seconds
+ end
+
+ override :max_deletes
+ def max_deletes
+ 200_000
+ end
+
+ override :max_updates
+ def max_updates
+ 150_000
+ end
+ end
+end
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index ada89345a7f..52b9c3a80e3 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -5,11 +5,10 @@ class GroupMember < Member
include CreatedAtFilterable
SOURCE_TYPE = 'Namespace'
- SOURCE_TYPE_FORMAT = /\ANamespace\z/.freeze
+ SOURCE_TYPE_FORMAT = /\ANamespace\z/
belongs_to :group, foreign_key: 'source_id'
alias_attribute :namespace_id, :source_id
- delegate :update_two_factor_requirement, to: :user, allow_nil: true
# Make sure group member points only to group as it source
attribute :source_type, default: SOURCE_TYPE
@@ -26,6 +25,16 @@ class GroupMember < Member
attr_accessor :last_owner
+ def update_two_factor_requirement
+ return unless user
+
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[users user_details user_preferences], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424288'
+ ) do
+ user.update_two_factor_requirement
+ end
+ end
+
# For those who get to see a modal with a role dropdown, here are the options presented
def self.permissible_access_level_roles(_, _)
# This method is a stopgap in preparation for https://gitlab.com/gitlab-org/gitlab/-/issues/364087
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index e0fecf702de..d07e4f9e298 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -2,7 +2,7 @@
class ProjectMember < Member
SOURCE_TYPE = 'Project'
- SOURCE_TYPE_FORMAT = /\AProject\z/.freeze
+ SOURCE_TYPE_FORMAT = /\AProject\z/
belongs_to :project, foreign_key: 'source_id'
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 469dba42952..6a72ed6476e 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -66,7 +66,7 @@ class MergeRequest < ApplicationRecord
belongs_to :latest_merge_request_diff, class_name: 'MergeRequestDiff'
manual_inverse_association :latest_merge_request_diff, :merge_request
- # method overriden in EE
+ # method overridden in EE
def suggested_reviewer_users
User.none
end
@@ -162,7 +162,7 @@ class MergeRequest < ApplicationRecord
# Keep states definition to be evaluated before the state_machine block to
# avoid spec failures. If this gets evaluated after, the `merged` and `locked`
- # states (which are overriden) can be nil.
+ # states (which are overridden) can be nil.
#
def self.available_state_names
super + [:merged, :locked]
@@ -279,6 +279,12 @@ class MergeRequest < ApplicationRecord
def check_state?(merge_status)
[:unchecked, :cannot_be_merged_recheck, :checking, :cannot_be_merged_rechecking].include?(merge_status.to_sym)
end
+
+ # rubocop: disable Style/SymbolProc
+ before_transition { |merge_request| merge_request.enable_transitioning }
+
+ after_transition { |merge_request| merge_request.disable_transitioning }
+ # rubocop: enable Style/SymbolProc
end
# Returns current merge_status except it returns `cannot_be_merged_rechecking` as `checking`
@@ -292,10 +298,14 @@ class MergeRequest < ApplicationRecord
validates :target_project, presence: true
validates :target_branch, presence: true
validates :merge_user, presence: true, if: :auto_merge_enabled?, unless: :importing?
- validate :validate_branches, unless: [:allow_broken, :importing?, :closed_or_merged_without_fork?]
+ validate :validate_branches, unless: [
+ :allow_broken,
+ :importing_or_transitioning?,
+ :closed_or_merged_without_fork?
+ ]
validate :validate_fork, unless: :closed_or_merged_without_fork?
- validate :validate_target_project, on: :create, unless: :importing?
- validate :validate_reviewer_size_length, unless: :importing?
+ validate :validate_target_project, on: :create, unless: :importing_or_transitioning?
+ validate :validate_reviewer_size_length, unless: :importing_or_transitioning?
scope :by_source_or_target_branch, ->(branch_name) do
where("source_branch = :branch OR target_branch = :branch", branch: branch_name)
@@ -371,6 +381,7 @@ class MergeRequest < ApplicationRecord
scope :with_csv_entity_associations, -> { preload(:assignees, :approved_by_users, :author, :milestone, metrics: [:merged_by]) }
scope :with_jira_integration_associations, -> { preload_routables.preload(:metrics, :assignees, :author) }
+ scope :recently_unprepared, -> { where(prepared_at: nil).where(created_at: 2.hours.ago..).order(:created_at, :id) } # id is the tie-breaker
scope :by_target_branch_wildcard, ->(wildcard_branch_name) do
where("target_branch LIKE ?", ApplicationRecord.sanitize_sql_like(wildcard_branch_name).tr('*', '%'))
@@ -550,13 +561,9 @@ class MergeRequest < ApplicationRecord
end
def merge_pipeline
- return unless merged?
-
- # When the merge_method is :merge there will be a merge_commit_sha, however
- # when it is fast-forward there is no merge commit, so we must fall back to
- # either the squash commit (if the MR was squashed) or the diff head commit.
- sha = merge_commit_sha || squash_commit_sha || diff_head_sha
- target_project.latest_pipeline(target_branch, sha)
+ if sha = merged_commit_sha
+ target_project.latest_pipeline(target_branch, sha)
+ end
end
def head_pipeline_active?
@@ -632,7 +639,7 @@ class MergeRequest < ApplicationRecord
end
end
- DRAFT_REGEX = /\A*#{Gitlab::Regex.merge_request_draft}+\s*/i.freeze
+ DRAFT_REGEX = /\A*#{Gitlab::Regex.merge_request_draft}+\s*/i
def self.draft?(title)
!!(title =~ DRAFT_REGEX)
@@ -734,6 +741,12 @@ class MergeRequest < ApplicationRecord
true
end
+ def supports_lock_on_merge?
+ return false unless merged?
+
+ project.supports_lock_on_merge?
+ end
+
# Calls `MergeWorker` to proceed with the merge process and
# updates `merge_jid` with the MergeWorker#jid.
# This helps tracking enqueued and ongoing merge jobs.
@@ -1218,7 +1231,7 @@ class MergeRequest < ApplicationRecord
}
end
- def mergeable?(skip_ci_check: false, skip_discussions_check: false, skip_approved_check: false, check_mergeability_retry_lease: false)
+ def mergeable?(skip_ci_check: false, skip_discussions_check: false, skip_approved_check: false, check_mergeability_retry_lease: false, skip_rebase_check: false)
return false unless mergeable_state?(
skip_ci_check: skip_ci_check,
skip_discussions_check: skip_discussions_check,
@@ -1227,7 +1240,7 @@ class MergeRequest < ApplicationRecord
check_mergeability(sync_retry_lease: check_mergeability_retry_lease)
- can_be_merged? && !should_be_rebased?
+ can_be_merged? && (!should_be_rebased? || skip_rebase_check)
end
def mergeability_checks
@@ -1593,7 +1606,7 @@ class MergeRequest < ApplicationRecord
# Since another process checks for matching merge request, we need
# to make it possible to detect whether the query should go to the
# primary.
- target_project.mark_primary_write_location
+ target_project.sticking.stick(:project, target_project.id)
end
def diverged_commits_count
@@ -1654,6 +1667,7 @@ class MergeRequest < ApplicationRecord
variables.append(key: 'CI_MERGE_REQUEST_ASSIGNEES', value: assignee_username_list) if assignees.present?
variables.append(key: 'CI_MERGE_REQUEST_MILESTONE', value: milestone.title) if milestone
variables.append(key: 'CI_MERGE_REQUEST_LABELS', value: label_names.join(',')) if labels.present?
+ variables.append(key: 'CI_MERGE_REQUEST_SQUASH_ON_MERGE', value: squash_on_merge?.to_s)
variables.concat(source_project_variables)
end
end
@@ -1831,7 +1845,7 @@ class MergeRequest < ApplicationRecord
def merged_commit_sha
return unless merged?
- sha = merge_commit_sha || squash_commit_sha || diff_head_sha
+ sha = super || merge_commit_sha || squash_commit_sha || diff_head_sha
sha.presence
end
@@ -1996,7 +2010,7 @@ class MergeRequest < ApplicationRecord
all_pipelines.for_sha_or_source_sha(diff_head_sha).first
end
- def etag_caching_enabled?
+ def real_time_notes_enabled?
true
end
@@ -2097,6 +2111,10 @@ class MergeRequest < ApplicationRecord
spammable_attribute_changed? && project.public?
end
+ def missing_required_squash?
+ !squash && target_project.squash_always?
+ end
+
private
attr_accessor :skip_fetch_ref
@@ -2141,6 +2159,7 @@ class MergeRequest < ApplicationRecord
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_PROJECT_PATH', value: source_project.full_path)
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_PROJECT_URL', value: source_project.web_url)
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_NAME', value: source_branch.to_s)
+ variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED', value: ProtectedBranch.protected?(source_project, source_branch).to_s)
end
end
diff --git a/app/models/metrics/dashboard/annotation.rb b/app/models/metrics/dashboard/annotation.rb
deleted file mode 100644
index ac0fcb41089..00000000000
--- a/app/models/metrics/dashboard/annotation.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-module Metrics
- module Dashboard
- class Annotation < ApplicationRecord
- include DeleteWithLimit
-
- self.table_name = 'metrics_dashboard_annotations'
-
- validates :starting_at, presence: true
- validates :description, presence: true, length: { maximum: 255 }
- validates :dashboard_path, presence: true, length: { maximum: 255 }
- validates :panel_xid, length: { maximum: 255 }
- validate :ending_at_after_starting_at
-
- scope :after, ->(after) { where('starting_at >= ?', after) }
- scope :before, ->(before) { where('starting_at <= ?', before) }
-
- scope :for_dashboard, ->(dashboard_path) { where(dashboard_path: dashboard_path) }
- scope :ending_before, ->(timestamp) { where('COALESCE(ending_at, starting_at) < ?', timestamp) }
-
- private
-
- # If annotation has NULL in ending_at column that indicates, that this annotation IS TIED TO SINGLE POINT
- # IN TIME designated by starting_at timestamp. It does NOT mean that annotation is ever going starting from
- # stating_at timestamp
- def ending_at_after_starting_at
- return if ending_at.blank? || starting_at.blank? || starting_at <= ending_at
-
- errors.add(:ending_at, s_("MetricsDashboardAnnotation|can't be before starting_at time"))
- end
- end
- end
-end
diff --git a/app/models/metrics/users_starred_dashboard.rb b/app/models/metrics/users_starred_dashboard.rb
deleted file mode 100644
index 07748eb1431..00000000000
--- a/app/models/metrics/users_starred_dashboard.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Metrics
- class UsersStarredDashboard < ApplicationRecord
- self.table_name = 'metrics_users_starred_dashboards'
-
- belongs_to :user, inverse_of: :metrics_users_starred_dashboards
- belongs_to :project, inverse_of: :metrics_users_starred_dashboards
-
- validates :user_id, presence: true
- validates :project_id, presence: true
- validates :dashboard_path, presence: true, length: { maximum: 255 }
- validates :dashboard_path, uniqueness: { scope: %i[user_id project_id] }
-
- scope :for_project, ->(project) { where(project: project) }
- scope :for_project_dashboard, ->(project, path) { for_project(project).where(dashboard_path: path) }
- end
-end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 8de717fb61d..eb0da368c7b 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -134,7 +134,9 @@ class Milestone < ApplicationRecord
end
def participants
- User.joins(assigned_issues: :milestone).where(milestones: { id: id }).distinct
+ User.joins(assigned_issues: :milestone)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422155')
+ .where(milestones: { id: id }).distinct
end
def self.sort_by_attribute(method)
diff --git a/app/models/ml/model_version.rb b/app/models/ml/model_version.rb
index 6d0e7c35865..e7fcde2cb5c 100644
--- a/app/models/ml/model_version.rb
+++ b/app/models/ml/model_version.rb
@@ -14,7 +14,7 @@ module Ml
belongs_to :model, class_name: 'Ml::Model'
belongs_to :project
- belongs_to :package, class_name: 'Packages::Package', optional: true
+ belongs_to :package, class_name: 'Packages::MlModel::Package', optional: true
delegate :name, to: :model
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index a7d03c3688a..ea0ea4de5b5 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -17,6 +17,9 @@ class Namespace < ApplicationRecord
include BlocksUnsafeSerialization
include Ci::NamespaceSettings
include Referable
+ include CrossDatabaseIgnoredTables
+
+ cross_database_ignore_tables %w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424277'
# Tells ActiveRecord not to store the full class name, in order to save some space
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69794
@@ -145,7 +148,6 @@ class Namespace < ApplicationRecord
after_update :force_share_with_group_lock_on_descendants, if: -> { saved_change_to_share_with_group_lock? && share_with_group_lock? }
after_update :expire_first_auto_devops_config_cache, if: -> { saved_change_to_auto_devops_enabled? }
after_update :move_dir, if: :saved_change_to_path_or_parent?, unless: -> { is_a?(Namespaces::ProjectNamespace) }
- after_destroy :rm_dir
after_save :reload_namespace_details
@@ -155,7 +157,6 @@ class Namespace < ApplicationRecord
# Legacy Storage specific hooks
- before_destroy(prepend: true) { prepare_for_destroy }
after_commit :expire_child_caches, on: :update, if: -> {
Feature.enabled?(:cached_route_lookups, self, type: :ops) &&
saved_change_to_name? || saved_change_to_path? || saved_change_to_parent_id?
@@ -166,7 +167,9 @@ class Namespace < ApplicationRecord
scope :sort_by_type, -> { order(arel_table[:type].asc.nulls_first) }
scope :include_route, -> { includes(:route) }
scope :by_parent, -> (parent) { where(parent_id: parent) }
+ scope :by_root_id, -> (root_id) { where('traversal_ids[1] IN (?)', root_id) }
scope :filter_by_path, -> (query) { where('lower(path) = :query', query: query.downcase) }
+ scope :in_organization, -> (organization) { where(organization: organization) }
scope :with_statistics, -> do
joins('LEFT JOIN project_statistics ps ON ps.namespace_id = namespaces.id')
@@ -231,16 +234,26 @@ class Namespace < ApplicationRecord
# query - The search query as a String.
#
# Returns an ActiveRecord::Relation.
- def search(query, include_parents: false, use_minimum_char_limit: true)
+ def search(query, include_parents: false, use_minimum_char_limit: true, exact_matches_first: false)
if include_parents
- without_project_namespaces
+ route_columns = [Route.arel_table[:path], Route.arel_table[:name]]
+ namespaces = without_project_namespaces
.where(id: Route.for_routable_type(Namespace.name)
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/420046")
- .fuzzy_search(query, [Route.arel_table[:path], Route.arel_table[:name]],
+ .fuzzy_search(query, route_columns,
use_minimum_char_limit: use_minimum_char_limit)
.select(:source_id))
+
+ if exact_matches_first
+ namespaces = namespaces
+ .joins(:route)
+ .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/420046")
+ .order(exact_matches_first_sql(query, route_columns))
+ end
+
+ namespaces
else
- without_project_namespaces.fuzzy_search(query, [:path, :name], use_minimum_char_limit: use_minimum_char_limit)
+ without_project_namespaces.fuzzy_search(query, [:path, :name], use_minimum_char_limit: use_minimum_char_limit, exact_matches_first: exact_matches_first)
end
end
@@ -465,7 +478,7 @@ class Namespace < ApplicationRecord
return { scope: :group, status: auto_devops_enabled } unless auto_devops_enabled.nil?
strong_memoize(:first_auto_devops_config) do
- if has_parent?
+ if parent.present?
Rails.cache.fetch(first_auto_devops_config_cache_key_for(id), expires_in: 1.day) do
parent.first_auto_devops_config
end
@@ -751,7 +764,7 @@ class Namespace < ApplicationRecord
end
def reload_namespace_details
- return unless !project_namespace? && (previous_changes.keys & %w(description description_html cached_markdown_version)).any? && namespace_details.present?
+ return unless !project_namespace? && (previous_changes.keys & %w[description description_html cached_markdown_version]).any? && namespace_details.present?
namespace_details.reset
end
diff --git a/app/models/namespace/detail.rb b/app/models/namespace/detail.rb
index 6c825b5364f..a65027733e9 100644
--- a/app/models/namespace/detail.rb
+++ b/app/models/namespace/detail.rb
@@ -3,7 +3,6 @@
class Namespace::Detail < ApplicationRecord
include IgnorableColumns
- ignore_column :free_user_cap_over_limt_notified_at, remove_with: '15.7', remove_after: '2022-11-22'
ignore_column :dashboard_notification_at, remove_with: '16.5', remove_after: '2023-08-22'
ignore_column :dashboard_enforcement_at, remove_with: '16.5', remove_after: '2023-08-22'
ignore_column :next_over_limit_check_at, remove_with: '16.5', remove_after: '2023-08-22'
diff --git a/app/models/namespace/root_storage_statistics.rb b/app/models/namespace/root_storage_statistics.rb
index 8af0cf2767c..1d11bcb574c 100644
--- a/app/models/namespace/root_storage_statistics.rb
+++ b/app/models/namespace/root_storage_statistics.rb
@@ -2,7 +2,7 @@
class Namespace::RootStorageStatistics < ApplicationRecord
SNIPPETS_SIZE_STAT_NAME = 'snippets_size'
- STATISTICS_ATTRIBUTES = %W(
+ STATISTICS_ATTRIBUTES = %W[
storage_size
repository_size
wiki_size
@@ -12,7 +12,7 @@ class Namespace::RootStorageStatistics < ApplicationRecord
#{SNIPPETS_SIZE_STAT_NAME}
pipeline_artifacts_size
uploads_size
- ).freeze
+ ].freeze
self.primary_key = :namespace_id
@@ -36,7 +36,7 @@ class Namespace::RootStorageStatistics < ApplicationRecord
end
def self.namespace_statistics_attributes
- %w(storage_size dependency_proxy_size)
+ %w[storage_size dependency_proxy_size]
end
private
diff --git a/app/models/namespace/traversal_hierarchy.rb b/app/models/namespace/traversal_hierarchy.rb
index d2de85b5dd4..86fb562f4f4 100644
--- a/app/models/namespace/traversal_hierarchy.rb
+++ b/app/models/namespace/traversal_hierarchy.rb
@@ -39,9 +39,16 @@ class Namespace
AND namespaces.traversal_ids::bigint[] <> cte.traversal_ids
SQL
- Namespace.transaction do
- @root.lock!("FOR NO KEY UPDATE")
- Namespace.connection.exec_query(sql)
+ # Hint: when a user is created, it also creates a Namespaces::UserNamespace in
+ # `ensure_namespace_correct`. This method is then called within the same
+ # transaction of the user INSERT.
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[namespaces], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424279'
+ ) do
+ Namespace.transaction do
+ @root.lock!("FOR NO KEY UPDATE")
+ Namespace.connection.exec_query(sql)
+ end
end
rescue ActiveRecord::Deadlocked
db_deadlock_counter.increment(source: 'Namespace#sync_traversal_ids!')
diff --git a/app/models/namespaces/randomized_suffix_path.rb b/app/models/namespaces/randomized_suffix_path.rb
index 586d7bff5c3..b22ba789688 100644
--- a/app/models/namespaces/randomized_suffix_path.rb
+++ b/app/models/namespaces/randomized_suffix_path.rb
@@ -3,7 +3,7 @@
module Namespaces
class RandomizedSuffixPath
MAX_TRIES = 4
- LEADING_ZEROS = /^0+/.freeze
+ LEADING_ZEROS = /^0+/
def initialize(path)
@path = path
diff --git a/app/models/note.rb b/app/models/note.rb
index f1760a8dc4a..8fc45436dc7 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -28,7 +28,7 @@ class Note < ApplicationRecord
ignore_column :id_convert_to_bigint, remove_with: '16.3', remove_after: '2023-08-22'
- ISSUE_TASK_SYSTEM_NOTE_PATTERN = /\A.*marked\sthe\stask.+as\s(completed|incomplete).*\z/.freeze
+ ISSUE_TASK_SYSTEM_NOTE_PATTERN = /\A.*marked\sthe\stask.+as\s(completed|incomplete).*\z/
cache_markdown_field :note, pipeline: :note, issuable_reference_expansion_enabled: true
@@ -74,6 +74,7 @@ class Note < ApplicationRecord
attr_mentionable :note, pipeline: :note
participant :author
+ belongs_to :namespace
belongs_to :project
belongs_to :noteable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
belongs_to :author, class_name: "User"
@@ -104,6 +105,7 @@ class Note < ApplicationRecord
validates :note, presence: true
validates :note, length: { maximum: Gitlab::Database::MAX_TEXT_SIZE_LIMIT }
validates :project, presence: true, if: :for_project_noteable?
+ validates :namespace, presence: true
# Attachments are deprecated and are handled by Markdown uploader
validates :attachment, file_size: { maximum: :max_attachment_size }
@@ -169,7 +171,7 @@ class Note < ApplicationRecord
end
end
- scope :diff_notes, -> { where(type: %w(LegacyDiffNote DiffNote)) }
+ scope :diff_notes, -> { where(type: %w[LegacyDiffNote DiffNote]) }
scope :new_diff_notes, -> { where(type: 'DiffNote') }
scope :non_diff_notes, -> { where(type: NON_DIFF_NOTE_TYPES) }
@@ -193,7 +195,7 @@ class Note < ApplicationRecord
scope :for_note_or_capitalized_note, ->(text) { where(note: [text, text.capitalize]) }
scope :like_note_or_capitalized_note, ->(text) { where('(note LIKE ? OR note LIKE ?)', text, text.capitalize) }
- before_validation :nullify_blank_type, :nullify_blank_line_code
+ before_validation :ensure_namespace_id, :nullify_blank_type, :nullify_blank_line_code
# Syncs `confidential` with `internal` as we rename the column.
# https://gitlab.com/gitlab-org/gitlab/-/issues/367923
before_create :set_internal_flag
@@ -205,7 +207,7 @@ class Note < ApplicationRecord
after_commit :trigger_note_subscription_create, on: :create
after_commit :trigger_note_subscription_update, on: :update
after_commit :trigger_note_subscription_destroy, on: :destroy
- after_commit :expire_etag_cache, unless: :importing?
+ after_commit :broadcast_noteable_notes_changed, unless: :importing?
def trigger_note_subscription_create
return unless trigger_note_subscription?
@@ -589,8 +591,8 @@ class Note < ApplicationRecord
update_columns(attributes_to_update)
end
- def expire_etag_cache
- noteable&.expire_note_etag_cache
+ def broadcast_noteable_notes_changed
+ noteable&.broadcast_notes_changed
end
def touch(*args, **kwargs)
@@ -825,6 +827,16 @@ class Note < ApplicationRecord
project.repository.keep_around(self.commit_id)
end
+ def ensure_namespace_id
+ return if namespace_id.present? && !noteable_changed? && !project_changed?
+
+ self.namespace_id = if for_project_noteable?
+ project&.project_namespace_id
+ elsif for_personal_snippet?
+ noteable&.author&.namespace&.id
+ end
+ end
+
def nullify_blank_type
self.type = nil if self.type.blank?
end
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index cde7b92e74a..eb4fa9ac474 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -60,7 +60,7 @@ class NotificationSetting < ApplicationRecord
end
def self.allowed_fields(source = nil)
- NotificationSetting.email_events(source).dup + %i(level notification_email)
+ NotificationSetting.email_events(source).dup + %i[level notification_email]
end
def email_events
diff --git a/app/models/operations/feature_flag.rb b/app/models/operations/feature_flag.rb
index 01db0a5cf8b..b93537e0d1e 100644
--- a/app/models/operations/feature_flag.rb
+++ b/app/models/operations/feature_flag.rb
@@ -52,7 +52,7 @@ module Operations
class << self
def preload_relations
- preload(strategies: :scopes)
+ preload(strategies: [:scopes, :user_list])
end
def for_unleash_client(project, environment)
diff --git a/app/models/organizations/organization.rb b/app/models/organizations/organization.rb
index 9f2119949fb..893b08d7872 100644
--- a/app/models/organizations/organization.rb
+++ b/app/models/organizations/organization.rb
@@ -10,6 +10,7 @@ module Organizations
has_many :namespaces
has_many :groups
+ has_many :projects
has_one :settings, class_name: "OrganizationSetting"
@@ -38,7 +39,7 @@ module Organizations
end
def user?(user)
- users.exists?(user.id)
+ organization_users.exists?(user: user)
end
private
diff --git a/app/models/packages/debian.rb b/app/models/packages/debian.rb
index 2b8d0a4f51e..1fe4e28146e 100644
--- a/app/models/packages/debian.rb
+++ b/app/models/packages/debian.rb
@@ -4,13 +4,13 @@ module Packages
module Debian
TEMPORARY_PACKAGE_NAME = 'debian-temporary-package'
- DISTRIBUTION_REGEX = %r{[a-z0-9][a-z0-9.-]*}i.freeze
+ DISTRIBUTION_REGEX = %r{[a-z0-9][a-z0-9.-]*}i
COMPONENT_REGEX = DISTRIBUTION_REGEX.freeze
- ARCHITECTURE_REGEX = %r{[a-z0-9][-a-z0-9]*}.freeze
+ ARCHITECTURE_REGEX = %r{[a-z0-9][-a-z0-9]*}
- LETTER_REGEX = %r{(lib)?[a-z0-9]}.freeze
+ LETTER_REGEX = %r{(lib)?[a-z0-9]}
- EMPTY_FILE_SHA256 = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'.freeze
+ EMPTY_FILE_SHA256 = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
INCOMING_PACKAGE_NAME = 'incoming'
diff --git a/app/models/packages/debian/file_entry.rb b/app/models/packages/debian/file_entry.rb
index 7ea0dfe8765..4ac621dcbd4 100644
--- a/app/models/packages/debian/file_entry.rb
+++ b/app/models/packages/debian/file_entry.rb
@@ -6,7 +6,7 @@ module Packages
include ActiveModel::Model
DIGESTS = %i[md5 sha1 sha256].freeze
- FILENAME_REGEX = %r{\A[a-zA-Z0-9][a-zA-Z0-9_.~+-]*\z}.freeze
+ FILENAME_REGEX = %r{\A[a-zA-Z0-9][a-zA-Z0-9_.~+-]*\z}
attr_accessor :filename,
:size,
diff --git a/app/models/packages/dependency_link.rb b/app/models/packages/dependency_link.rb
index 51018602bdc..400b4cce208 100644
--- a/app/models/packages/dependency_link.rb
+++ b/app/models/packages/dependency_link.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
class Packages::DependencyLink < ApplicationRecord
+ include EachBatch
+
belongs_to :package, inverse_of: :dependency_links
belongs_to :dependency, inverse_of: :dependency_links, class_name: 'Packages::Dependency'
has_one :nuget_metadatum, inverse_of: :dependency_link, class_name: 'Packages::Nuget::DependencyLinkMetadatum'
@@ -14,6 +16,32 @@ class Packages::DependencyLink < ApplicationRecord
scope :with_dependency_type, ->(dependency_type) { where(dependency_type: dependency_type) }
scope :includes_dependency, -> { includes(:dependency) }
scope :for_package, ->(package) { where(package_id: package.id) }
+ scope :for_packages, ->(packages) { where(package: packages) }
scope :preload_dependency, -> { preload(:dependency) }
scope :preload_nuget_metadatum, -> { preload(:nuget_metadatum) }
+ scope :select_dependency_id, -> { select(:dependency_id) }
+
+ def self.dependency_ids_grouped_by_type(packages)
+ inner_query = where(package_id: packages)
+ .select('
+ package_id,
+ dependency_type,
+ ARRAY_AGG(dependency_id) as dependency_ids
+ ')
+ .group(:package_id, :dependency_type)
+
+ cte = Gitlab::SQL::CTE.new(:dependency_links_cte, inner_query)
+ cte_alias = cte.table.alias(table_name)
+
+ with(cte.to_arel)
+ .select('
+ package_id,
+ JSON_OBJECT_AGG(
+ dependency_type,
+ dependency_ids
+ ) AS dependency_ids_by_type
+ ')
+ .from(cte_alias)
+ .group(:package_id)
+ end
end
diff --git a/app/models/packages/ml_model/package.rb b/app/models/packages/ml_model/package.rb
new file mode 100644
index 00000000000..de2b5f8f2a8
--- /dev/null
+++ b/app/models/packages/ml_model/package.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Packages
+ module MlModel
+ class Package < Packages::Package
+ has_one :model_version, class_name: "Ml::ModelVersion", inverse_of: :package
+
+ validates :name,
+ format: Gitlab::Regex.ml_model_name_regex,
+ presence: true,
+ length: { maximum: 255 }
+
+ validates :version,
+ format: Gitlab::Regex.semver_regex,
+ presence: true,
+ length: { maximum: 255 }
+ end
+ end
+end
diff --git a/app/models/packages/nuget/metadatum.rb b/app/models/packages/nuget/metadatum.rb
index e7cf4528f16..1025af0fd24 100644
--- a/app/models/packages/nuget/metadatum.rb
+++ b/app/models/packages/nuget/metadatum.rb
@@ -15,8 +15,7 @@ class Packages::Nuget::Metadatum < ApplicationRecord
validates :icon_url, public_url: { allow_blank: true }, length: { maximum: MAX_URL_LENGTH }
validates :authors, presence: true, length: { maximum: MAX_AUTHORS_LENGTH }
validates :description, presence: true, length: { maximum: MAX_DESCRIPTION_LENGTH }
- validates :normalized_version, presence: true,
- if: -> { Feature.enabled?(:nuget_normalized_version, package&.project) }
+ validates :normalized_version, presence: true
validate :ensure_nuget_package_type
diff --git a/app/models/packages/nuget/symbol.rb b/app/models/packages/nuget/symbol.rb
new file mode 100644
index 00000000000..643b5552d84
--- /dev/null
+++ b/app/models/packages/nuget/symbol.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Packages
+ module Nuget
+ class Symbol < ApplicationRecord
+ include FileStoreMounter
+
+ belongs_to :package, -> { where(package_type: :nuget) }, inverse_of: :nuget_symbols
+
+ delegate :project_id, to: :package
+
+ validates :package, :file, :file_path, :signature, :object_storage_key, :size, presence: true
+ validates :signature, uniqueness: { scope: :file_path }
+ validates :object_storage_key, uniqueness: true
+
+ mount_file_store_uploader SymbolUploader
+
+ before_validation :set_object_storage_key, on: :create
+
+ private
+
+ def set_object_storage_key
+ return unless project_id && signature
+
+ self.object_storage_key = Gitlab::HashedPath.new(
+ 'packages', 'nuget', package_id, 'symbols', OpenSSL::Digest::SHA256.hexdigest(signature),
+ root_hash: project_id
+ ).to_s
+ end
+ end
+ end
+end
diff --git a/app/models/packages/package.rb b/app/models/packages/package.rb
index b09911f4216..02e3908b3bf 100644
--- a/app/models/packages/package.rb
+++ b/app/models/packages/package.rb
@@ -7,6 +7,7 @@ class Packages::Package < ApplicationRecord
include Gitlab::Utils::StrongMemoize
include Packages::Installable
include Packages::Downloadable
+ include EnumInheritance
DISPLAYABLE_STATUSES = [:default, :error].freeze
INSTALLABLE_STATUSES = [:default, :hidden].freeze
@@ -48,6 +49,7 @@ class Packages::Package < ApplicationRecord
has_one :pypi_metadatum, inverse_of: :package, class_name: 'Packages::Pypi::Metadatum'
has_one :maven_metadatum, inverse_of: :package, class_name: 'Packages::Maven::Metadatum'
has_one :nuget_metadatum, inverse_of: :package, class_name: 'Packages::Nuget::Metadatum'
+ has_many :nuget_symbols, inverse_of: :package, class_name: 'Packages::Nuget::Symbol'
has_one :composer_metadatum, inverse_of: :package, class_name: 'Packages::Composer::Metadatum'
has_one :rubygems_metadatum, inverse_of: :package, class_name: 'Packages::Rubygems::Metadatum'
has_one :rpm_metadatum, inverse_of: :package, class_name: 'Packages::Rpm::Metadatum'
@@ -179,11 +181,7 @@ class Packages::Package < ApplicationRecord
scope :preload_conan_metadatum, -> { preload(:conan_metadatum) }
scope :with_npm_scope, ->(scope) do
- if Feature.enabled?(:npm_package_registry_fix_group_path_validation)
- npm.where("position('/' in packages_packages.name) > 0 AND split_part(packages_packages.name, '/', 1) = :package_scope", package_scope: "@#{sanitize_sql_like(scope)}")
- else
- npm.where("name ILIKE :package_name", package_name: "@#{sanitize_sql_like(scope)}/%")
- end
+ npm.where("position('/' in packages_packages.name) > 0 AND split_part(packages_packages.name, '/', 1) = :package_scope", package_scope: "@#{sanitize_sql_like(scope)}")
end
scope :without_nuget_temporary_name, -> { where.not(name: Packages::Nuget::TEMPORARY_PACKAGE_NAME) }
@@ -220,6 +218,12 @@ class Packages::Package < ApplicationRecord
joins(:project).reorder(keyset_order)
end
+ def self.inheritance_column = 'package_type'
+
+ def self.inheritance_column_to_class_map = {
+ ml_model: 'Packages::MlModel::Package'
+ }.freeze
+
def self.only_maven_packages_with_path(path, use_cte: false)
if use_cte
# This is an optimization fence which assumes that looking up the Metadatum record by path (globally)
diff --git a/app/models/packages/protection.rb b/app/models/packages/protection.rb
new file mode 100644
index 00000000000..ebaecf89992
--- /dev/null
+++ b/app/models/packages/protection.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Packages
+ module Protection
+ def self.table_name_prefix
+ 'packages_protection_'
+ end
+ end
+end
diff --git a/app/models/packages/protection/rule.rb b/app/models/packages/protection/rule.rb
new file mode 100644
index 00000000000..bb65be92b90
--- /dev/null
+++ b/app/models/packages/protection/rule.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Packages
+ module Protection
+ class Rule < ApplicationRecord
+ enum package_type: Packages::Package.package_types.slice(:npm)
+
+ belongs_to :project, inverse_of: :package_protection_rules
+
+ validates :package_name_pattern, presence: true, uniqueness: { scope: [:project_id, :package_type] },
+ length: { maximum: 255 }
+ validates :package_type, presence: true
+ validates :push_protected_up_to_access_level, presence: true,
+ inclusion: { in: [
+ Gitlab::Access::DEVELOPER,
+ Gitlab::Access::MAINTAINER,
+ Gitlab::Access::OWNER
+ ] }
+ end
+ end
+end
diff --git a/app/models/pages/lookup_path.rb b/app/models/pages/lookup_path.rb
index 2ffb2e84cbf..e8becc833ca 100644
--- a/app/models/pages/lookup_path.rb
+++ b/app/models/pages/lookup_path.rb
@@ -35,7 +35,7 @@ module Pages
{
type: 'zip',
path: deployment.file.url_or_file_path(
- expire_at: ::Gitlab::Pages::CacheControl::DEPLOYMENT_EXPIRATION.from_now
+ expire_at: ::Gitlab::Pages::DEPLOYMENT_EXPIRATION.from_now
),
global_id: global_id,
sha256: deployment.file_sha256,
diff --git a/app/models/pages/virtual_domain.rb b/app/models/pages/virtual_domain.rb
index fafbe449c8c..0a64e91bf60 100644
--- a/app/models/pages/virtual_domain.rb
+++ b/app/models/pages/virtual_domain.rb
@@ -2,9 +2,8 @@
module Pages
class VirtualDomain
- def initialize(projects:, cache: nil, trim_prefix: nil, domain: nil)
+ def initialize(projects:, trim_prefix: nil, domain: nil)
@projects = projects
- @cache = cache
@trim_prefix = trim_prefix
@domain = domain
end
@@ -18,23 +17,19 @@ module Pages
end
def lookup_paths
- paths = projects.map do |project|
- project.pages_lookup_path(trim_prefix: trim_prefix, domain: domain)
- end
-
- # TODO: remove in https://gitlab.com/gitlab-org/gitlab/-/issues/328715
- paths = paths.select(&:source)
-
- paths.sort_by(&:prefix).reverse
- end
-
- # cache_key is required by #present_cached in ::API::Internal::Pages
- def cache_key
- @cache_key ||= cache&.cache_key
+ projects
+ .map { |project| lookup_paths_for(project) }
+ .select(&:source) # TODO: remove in https://gitlab.com/gitlab-org/gitlab/-/issues/328715
+ .sort_by(&:prefix)
+ .reverse
end
private
- attr_reader :projects, :trim_prefix, :domain, :cache
+ attr_reader :projects, :trim_prefix, :domain
+
+ def lookup_paths_for(project)
+ Pages::LookupPath.new(project, trim_prefix: trim_prefix, domain: domain)
+ end
end
end
diff --git a/app/models/pages_deployment.rb b/app/models/pages_deployment.rb
index ec2293fa032..de7b2416258 100644
--- a/app/models/pages_deployment.rb
+++ b/app/models/pages_deployment.rb
@@ -11,13 +11,16 @@ class PagesDeployment < ApplicationRecord
attribute :file_store, :integer, default: -> { ::Pages::DeploymentUploader.default_store }
belongs_to :project, optional: false
+
+ # ci_build is optional, because PagesDeployment must live even if its build/pipeline is removed.
belongs_to :ci_build, class_name: 'Ci::Build', optional: true
- scope :older_than, -> (id) { where('id < ?', id) }
+ scope :older_than, ->(id) { where('id < ?', id) }
scope :migrated_from_legacy_storage, -> { where(file: MIGRATED_FILE_NAME) }
scope :with_files_stored_locally, -> { where(file_store: ::ObjectStorage::Store::LOCAL) }
scope :with_files_stored_remotely, -> { where(file_store: ::ObjectStorage::Store::REMOTE) }
scope :project_id_in, ->(ids) { where(project_id: ids) }
+ scope :active, -> { where(deleted_at: nil) }
validates :file, presence: true
validates :file_store, presence: true, inclusion: { in: ObjectStorage::SUPPORTED_STORES }
@@ -32,6 +35,14 @@ class PagesDeployment < ApplicationRecord
skip_callback :save, :after, :store_file!
after_commit :store_file_after_commit!, on: [:create, :update]
+ def self.deactivate_deployments_older_than(deployment, time: nil)
+ now = Time.now.utc
+ active
+ .older_than(deployment.id)
+ .where(project_id: deployment.project_id, path_prefix: deployment.path_prefix)
+ .update_all(updated_at: now, deleted_at: time || now)
+ end
+
def migrated?
file.filename == MIGRATED_FILE_NAME
end
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index 88d7f0f972a..b86bc761cc1 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -9,6 +9,8 @@ class PagesDomain < ApplicationRecord
VERIFICATION_THRESHOLD = 3.days.freeze
SSL_RENEWAL_THRESHOLD = 30.days.freeze
+ MAX_CERTIFICATE_KEY_LENGTH = 8192
+
enum certificate_source: { user_provided: 0, gitlab_provided: 1 }, _prefix: :certificate
enum scope: { instance: 0, group: 1, project: 2 }, _prefix: :scope, _default: :project
enum usage: { pages: 0, serverless: 1 }, _prefix: :usage, _default: :pages
@@ -34,6 +36,7 @@ class PagesDomain < ApplicationRecord
validate :validate_matching_key, if: ->(domain) { domain.certificate.present? || domain.key.present? }
validate :validate_intermediates, if: ->(domain) { domain.certificate.present? && domain.certificate_changed? }
validate :validate_custom_domain_count_per_project, on: :create
+ validate :max_certificate_key_length, if: ->(domain) { domain.key.present? }
attribute :auto_ssl_enabled, default: -> { ::Gitlab::LetsEncrypt.enabled? }
attribute :wildcard, default: false
@@ -234,6 +237,16 @@ class PagesDomain < ApplicationRecord
private
+ def max_certificate_key_length
+ return unless pkey.is_a?(OpenSSL::PKey::RSA)
+ return if pkey.to_s.bytesize <= MAX_CERTIFICATE_KEY_LENGTH
+
+ errors.add(
+ :key,
+ s_("PagesDomain|Certificate Key is too long. (Max %d bytes)") % MAX_CERTIFICATE_KEY_LENGTH
+ )
+ end
+
def set_verification_code
return if self.verification_code.present?
diff --git a/app/models/performance_monitoring/prometheus_metric.rb b/app/models/performance_monitoring/prometheus_metric.rb
deleted file mode 100644
index d67b1809d93..00000000000
--- a/app/models/performance_monitoring/prometheus_metric.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module PerformanceMonitoring
- class PrometheusMetric
- include ActiveModel::Model
-
- attr_accessor :id, :unit, :label, :query, :query_range
-
- validates :unit, presence: true
- validates :query, presence: true, unless: :query_range
- validates :query_range, presence: true, unless: :query
-
- class << self
- def from_json(json_content)
- build_from_hash(json_content).tap(&:validate!)
- end
-
- private
-
- def build_from_hash(attributes)
- return new unless attributes.is_a?(Hash)
-
- new(
- id: attributes['id'],
- unit: attributes['unit'],
- label: attributes['label'],
- query: attributes['query'],
- query_range: attributes['query_range']
- )
- end
- end
- end
-end
diff --git a/app/models/performance_monitoring/prometheus_panel.rb b/app/models/performance_monitoring/prometheus_panel.rb
deleted file mode 100644
index b33c09001ae..00000000000
--- a/app/models/performance_monitoring/prometheus_panel.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-module PerformanceMonitoring
- class PrometheusPanel
- include ActiveModel::Model
-
- attr_accessor :type, :title, :y_label, :weight, :metrics, :y_axis, :max_value
-
- validates :title, presence: true
- validates :metrics, array_members: { member_class: PerformanceMonitoring::PrometheusMetric }
-
- class << self
- def from_json(json_content)
- build_from_hash(json_content).tap(&:validate!)
- end
-
- private
-
- def build_from_hash(attributes)
- return new unless attributes.is_a?(Hash)
-
- new(
- type: attributes['type'],
- title: attributes['title'],
- y_label: attributes['y_label'],
- weight: attributes['weight'],
- metrics: initialize_children_collection(attributes['metrics'])
- )
- end
-
- def initialize_children_collection(children)
- return unless children.is_a?(Array)
-
- children.map { |metrics| PerformanceMonitoring::PrometheusMetric.from_json(metrics) }
- end
- end
-
- def id(group_title)
- Digest::SHA2.hexdigest([group_title, type, title].join)
- end
- end
-end
diff --git a/app/models/performance_monitoring/prometheus_panel_group.rb b/app/models/performance_monitoring/prometheus_panel_group.rb
deleted file mode 100644
index 7f3d2a1b8f4..00000000000
--- a/app/models/performance_monitoring/prometheus_panel_group.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-module PerformanceMonitoring
- class PrometheusPanelGroup
- include ActiveModel::Model
-
- attr_accessor :group, :priority, :panels
-
- validates :group, presence: true
- validates :panels, array_members: { member_class: PerformanceMonitoring::PrometheusPanel }
-
- class << self
- def from_json(json_content)
- build_from_hash(json_content).tap(&:validate!)
- end
-
- private
-
- def build_from_hash(attributes)
- return new unless attributes.is_a?(Hash)
-
- new(
- group: attributes['group'],
- priority: attributes['priority'],
- panels: initialize_children_collection(attributes['panels'])
- )
- end
-
- def initialize_children_collection(children)
- return unless children.is_a?(Array)
-
- children.map { |panels| PerformanceMonitoring::PrometheusPanel.from_json(panels) }
- end
- end
- end
-end
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index 08f725de980..4dfe7252a0c 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -14,7 +14,7 @@ class PersonalAccessToken < ApplicationRecord
format_with_prefix: :prefix_from_application_current_settings
# PATs are 20 characters + optional configurable settings prefix (0..20)
- TOKEN_LENGTH_RANGE = (20..40).freeze
+ TOKEN_LENGTH_RANGE = (20..40)
MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS = 365
serialize :scopes, Array # rubocop:disable Cop/ActiveRecordSerialize
diff --git a/app/models/plan.rb b/app/models/plan.rb
index 22c1201421c..9ab22bc045a 100644
--- a/app/models/plan.rb
+++ b/app/models/plan.rb
@@ -5,6 +5,8 @@ class Plan < MainClusterwide::ApplicationRecord
has_one :limits, class_name: 'PlanLimits'
+ scope :by_name, ->(name) { where(name: name) }
+
ALL_PLANS = [DEFAULT].freeze
DEFAULT_PLANS = [DEFAULT].freeze
private_constant :ALL_PLANS, :DEFAULT_PLANS
diff --git a/app/models/pool_repository.rb b/app/models/pool_repository.rb
index bc3898fafe7..7d043bae91c 100644
--- a/app/models/pool_repository.rb
+++ b/app/models/pool_repository.rb
@@ -8,15 +8,15 @@ class PoolRepository < ApplicationRecord
include AfterCommitQueue
belongs_to :source_project, class_name: 'Project'
- validates :source_project, presence: true
has_many :member_projects, class_name: 'Project'
after_create :set_disk_path
scope :by_source_project, ->(project) { where(source_project: project) }
- scope :by_source_project_and_shard_name, ->(project, shard_name) do
- by_source_project(project)
+ scope :by_disk_path, ->(disk_path) { where(disk_path: disk_path) }
+ scope :by_disk_path_and_shard_name, ->(disk_path, shard_name) do
+ by_disk_path(disk_path)
.for_repository_storage(shard_name)
end
@@ -101,8 +101,8 @@ class PoolRepository < ApplicationRecord
@object_pool ||= Gitlab::Git::ObjectPool.new(
shard.name,
disk_path + '.git',
- source_project.repository.raw,
- source_project.full_path
+ source_project&.repository&.raw,
+ source_project&.full_path
)
end
diff --git a/app/models/project.rb b/app/models/project.rb
index ad8757880fd..68196f0a757 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -44,9 +44,12 @@ class Project < ApplicationRecord
include IssueParent
include UpdatedAtFilterable
include IgnorableColumns
+ include CrossDatabaseIgnoredTables
ignore_column :emails_disabled, remove_with: '16.3', remove_after: '2023-08-22'
+ cross_database_ignore_tables %w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424277'
+
extend Gitlab::Cache::RequestCache
extend Gitlab::Utils::Override
@@ -68,10 +71,10 @@ class Project < ApplicationRecord
}.freeze
VALID_IMPORT_PORTS = [80, 443].freeze
- VALID_IMPORT_PROTOCOLS = %w(http https git).freeze
+ VALID_IMPORT_PROTOCOLS = %w[http https git].freeze
VALID_MIRROR_PORTS = [22, 80, 443].freeze
- VALID_MIRROR_PROTOCOLS = %w(http https ssh git).freeze
+ VALID_MIRROR_PROTOCOLS = %w[http https ssh git].freeze
SORTING_PREFERENCE_FIELD = :projects_sort
MAX_BUILD_TIMEOUT = 1.month
@@ -81,6 +84,8 @@ class Project < ApplicationRecord
MAX_SUGGESTIONS_TEMPLATE_LENGTH = 255
MAX_COMMIT_TEMPLATE_LENGTH = 500
+ INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET = 5
+
DEFAULT_MERGE_COMMIT_TEMPLATE = <<~MSG.rstrip.freeze
Merge branch '%{source_branch}' into '%{target_branch}'
@@ -163,6 +168,7 @@ class Project < ApplicationRecord
# Relations
belongs_to :pool_repository
belongs_to :creator, class_name: 'User'
+ belongs_to :organization, class_name: 'Organizations::Organization'
belongs_to :group, -> { where(type: Group.sti_name) }, foreign_key: 'namespace_id'
belongs_to :namespace
# Sync deletion via DB Trigger to ensure we do not have
@@ -265,6 +271,9 @@ class Project < ApplicationRecord
dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :npm_metadata_caches, class_name: 'Packages::Npm::MetadataCache'
has_one :packages_cleanup_policy, class_name: 'Packages::Cleanup::Policy', inverse_of: :project
+ has_many :package_protection_rules,
+ class_name: 'Packages::Protection::Rule',
+ inverse_of: :project
has_one :import_state, autosave: true, class_name: 'ProjectImportState', inverse_of: :project
has_one :import_export_upload, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -273,7 +282,6 @@ class Project < ApplicationRecord
has_one :project_repository, inverse_of: :project
has_one :incident_management_setting, inverse_of: :project, class_name: 'IncidentManagement::ProjectIncidentManagementSetting'
has_one :error_tracking_setting, inverse_of: :project, class_name: 'ErrorTracking::ProjectErrorTrackingSetting'
- has_one :metrics_setting, inverse_of: :project, class_name: 'ProjectMetricsSetting'
has_one :grafana_integration, inverse_of: :project
has_one :project_setting, inverse_of: :project, autosave: true
has_one :alerting_setting, inverse_of: :project, class_name: 'Alerting::ProjectAlertingSetting'
@@ -336,7 +344,15 @@ class Project < ApplicationRecord
primary_key: :project_namespace_id, foreign_key: :member_namespace_id, inverse_of: :project,
class_name: 'ProjectMember'
- has_many :users, through: :project_members
+ has_many :users, -> { allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/422405") },
+ through: :project_members
+ has_many :maintainers,
+ -> do
+ allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/422405")
+ .where(members: { access_level: Gitlab::Access::MAINTAINER })
+ end,
+ through: :project_members,
+ source: :user
has_many :project_callouts, class_name: 'Users::ProjectCallout', foreign_key: :project_id
@@ -370,8 +386,6 @@ class Project < ApplicationRecord
has_many :prometheus_metrics
has_many :prometheus_alerts, inverse_of: :project
has_many :prometheus_alert_events, inverse_of: :project
- has_many :self_managed_prometheus_alert_events, inverse_of: :project
- has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :project
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :project
has_many :alert_management_http_integrations, class_name: 'AlertManagement::HttpIntegration', inverse_of: :project
@@ -476,7 +490,6 @@ class Project < ApplicationRecord
accepts_nested_attributes_for :incident_management_setting, update_only: true
accepts_nested_attributes_for :error_tracking_setting, update_only: true
- accepts_nested_attributes_for :metrics_setting, update_only: true, allow_destroy: true
accepts_nested_attributes_for :grafana_integration, update_only: true, allow_destroy: true
accepts_nested_attributes_for :prometheus_integration, update_only: true
accepts_nested_attributes_for :alerting_setting, update_only: true
@@ -492,11 +505,6 @@ class Project < ApplicationRecord
delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_owner, :add_role
end
- with_options to: :metrics_setting, allow_nil: true, prefix: true do
- delegate :external_dashboard_url
- delegate :dashboard_timezone
- end
-
with_options to: :namespace do
delegate :actual_limits, :actual_plan_name, :actual_plan, :root_ancestor, allow_nil: true
delegate :maven_package_requests_forwarding, :pypi_package_requests_forwarding, :npm_package_requests_forwarding
@@ -1282,7 +1290,7 @@ class Project < ApplicationRecord
def design_repository
strong_memoize(:design_repository) do
- Gitlab::GlRepository::DESIGN.repository_for(self)
+ find_or_create_design_management_repository.repository
end
end
@@ -1665,7 +1673,7 @@ class Project < ApplicationRecord
return unless Gitlab::Email::IncomingEmail.supports_issue_creation? && author
# check since this can come from a request parameter
- return unless %w(issue merge_request).include?(address_type)
+ return unless %w[issue merge_request].include?(address_type)
author.ensure_incoming_email_token!
@@ -2757,10 +2765,6 @@ class Project < ApplicationRecord
[]
end
- def mark_primary_write_location
- self.class.sticking.mark_primary_write_location(:project, self.id)
- end
-
def toggle_ci_cd_settings!(settings_attribute)
ci_cd_settings.toggle!(settings_attribute)
end
@@ -2842,7 +2846,7 @@ class Project < ApplicationRecord
return if old_pool_repository.blank?
return if pool_repository_shard_matches_repository?(old_pool_repository)
- new_pool_repository = PoolRepository.by_source_project_and_shard_name(old_pool_repository.source_project, repository_storage).take!
+ new_pool_repository = PoolRepository.by_disk_path_and_shard_name(old_pool_repository.disk_path, repository_storage).take!
update!(pool_repository: new_pool_repository)
old_pool_repository.unlink_repository(repository, disconnect: !pending_delete?)
@@ -2871,10 +2875,6 @@ class Project < ApplicationRecord
recipients
end
- def pages_lookup_path(trim_prefix: nil, domain: nil)
- Pages::LookupPath.new(self, trim_prefix: trim_prefix, domain: domain)
- end
-
def closest_setting(name)
setting = read_attribute(name)
setting = closest_namespace_setting(name) if setting.nil?
@@ -2954,10 +2954,6 @@ class Project < ApplicationRecord
jira_imports.last
end
- def metrics_setting
- super || build_metrics_setting
- end
-
def service_desk_enabled
Gitlab::ServiceDesk.enabled?(project: self)
end
@@ -2965,7 +2961,11 @@ class Project < ApplicationRecord
alias_method :service_desk_enabled?, :service_desk_enabled
def service_desk_address
- service_desk_custom_address || service_desk_incoming_address
+ service_desk_custom_address || service_desk_system_address
+ end
+
+ def service_desk_system_address
+ service_desk_alias_address || service_desk_incoming_address
end
def service_desk_incoming_address
@@ -2977,7 +2977,7 @@ class Project < ApplicationRecord
config.address&.gsub(wildcard, "#{full_path_slug}-#{default_service_desk_suffix}")
end
- def service_desk_custom_address
+ def service_desk_alias_address
return unless Gitlab::Email::ServiceDeskEmail.enabled?
key = service_desk_setting&.project_key || default_service_desk_suffix
@@ -2985,6 +2985,13 @@ class Project < ApplicationRecord
Gitlab::Email::ServiceDeskEmail.address_for_key("#{full_path_slug}-#{key}")
end
+ def service_desk_custom_address
+ return unless Feature.enabled?(:service_desk_custom_email, self)
+ return unless service_desk_setting&.custom_email_enabled?
+
+ service_desk_setting.custom_email
+ end
+
def default_service_desk_suffix
"#{id}-issue-"
end
@@ -3261,6 +3268,10 @@ class Project < ApplicationRecord
group.crm_enabled?
end
+ def supports_lock_on_merge?
+ group&.supports_lock_on_merge? || ::Feature.enabled?(:enforce_locked_labels_on_merge, self, type: :ops)
+ end
+
def path_availability
base, _, host = path.partition('.')
@@ -3270,6 +3281,13 @@ class Project < ApplicationRecord
errors.add(:path, s_('Project|already in use'))
end
+ def instance_runner_running_jobs_count
+ # excluding currently started job
+ ::Ci::RunningBuild.instance_type.where(project_id: self.id)
+ .limit(INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET + 1).count - 1
+ end
+ strong_memoize_attr :instance_runner_running_jobs_count
+
private
# overridden in EE
@@ -3483,11 +3501,11 @@ class Project < ApplicationRecord
end
def sync_project_namespace?
- (changes.keys & %w(name path namespace_id namespace visibility_level shared_runners_enabled)).any? && project_namespace.present?
+ (changes.keys & %w[name path namespace_id namespace visibility_level shared_runners_enabled]).any? && project_namespace.present?
end
def reload_project_namespace_details
- return unless (previous_changes.keys & %w(description description_html cached_markdown_version)).any? && project_namespace.namespace_details.present?
+ return unless (previous_changes.keys & %w[description description_html cached_markdown_version]).any? && project_namespace.namespace_details.present?
project_namespace.namespace_details.reset
end
diff --git a/app/models/project_authorization.rb b/app/models/project_authorization.rb
index 99128d3cddf..c328e7d37c8 100644
--- a/app/models/project_authorization.rb
+++ b/app/models/project_authorization.rb
@@ -11,6 +11,11 @@ class ProjectAuthorization < ApplicationRecord
validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true
validates :user, uniqueness: { scope: :project }, presence: true
+ scope :non_guests, -> { where('access_level > ?', ::Gitlab::Access::GUEST) }
+
+ # TODO: To be removed after https://gitlab.com/gitlab-org/gitlab/-/issues/418205
+ before_create :assign_is_unique
+
def self.select_from_union(relations)
from_union(relations)
.select(['project_id', 'MAX(access_level) AS access_level'])
@@ -25,6 +30,12 @@ class ProjectAuthorization < ApplicationRecord
def self.insert_all(attributes)
super(attributes, unique_by: connection.schema_cache.primary_keys(table_name))
end
+
+ private
+
+ def assign_is_unique
+ self.is_unique = true
+ end
end
ProjectAuthorization.prepend_mod_with('ProjectAuthorization')
diff --git a/app/models/project_authorizations/changes.rb b/app/models/project_authorizations/changes.rb
index 1d717950c1c..1f0cec1a50c 100644
--- a/app/models/project_authorizations/changes.rb
+++ b/app/models/project_authorizations/changes.rb
@@ -90,6 +90,8 @@ module ProjectAuthorizations
log_details(entire_size: attributes.size, batch_size: BATCH_SIZE) if add_delay
attributes.each_slice(BATCH_SIZE) do |attributes_batch|
+ attributes_batch.each { |attrs| attrs[:is_unique] = true }
+
ProjectAuthorization.insert_all(attributes_batch)
perform_delay if add_delay
end
diff --git a/app/models/project_ci_cd_setting.rb b/app/models/project_ci_cd_setting.rb
index cc9003423be..8d049b8d1b1 100644
--- a/app/models/project_ci_cd_setting.rb
+++ b/app/models/project_ci_cd_setting.rb
@@ -19,6 +19,7 @@ class ProjectCiCdSetting < ApplicationRecord
attribute :forward_deployment_enabled, default: true
attribute :separated_caches, default: true
+ validates :merge_trains_skip_train_allowed, inclusion: { in: [true, false] }
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index 92ba02ec777..36f1e09b2ba 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -173,6 +173,10 @@ class ProjectFeature < ApplicationRecord
package_registry_access_level == PUBLIC || project.public?
end
+ def private?(feature)
+ access_level(feature) == PRIVATE
+ end
+
private
def set_pages_access_level
@@ -201,11 +205,11 @@ class ProjectFeature < ApplicationRecord
self.errors.add(field, "cannot have higher visibility level than repository access level") if not_allowed
end
- %i(merge_requests_access_level builds_access_level).each(&validator)
+ %i[merge_requests_access_level builds_access_level].each(&validator)
end
def feature_validation_exclusion
- %i(pages package_registry)
+ %i[pages package_registry]
end
override :resource_member?
diff --git a/app/models/project_import_state.rb b/app/models/project_import_state.rb
index f16d661d4bb..a7b2c40557a 100644
--- a/app/models/project_import_state.rb
+++ b/app/models/project_import_state.rb
@@ -132,10 +132,17 @@ class ProjectImportState < ApplicationRecord
alias_method :no_import?, :none?
+ # This method is coupled to the repository mirror domain.
+ # Use with caution in the importers domain. As an alternative, use the `#completed?` method.
+ # See EE-override and https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4697
def in_progress?
scheduled? || started?
end
+ def completed?
+ finished? || failed? || canceled?
+ end
+
def started?
# import? does SQL work so only run it if it looks like there's an import running
status == 'started' && project.import?
diff --git a/app/models/project_metrics_setting.rb b/app/models/project_metrics_setting.rb
deleted file mode 100644
index c66d0f52f4c..00000000000
--- a/app/models/project_metrics_setting.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-class ProjectMetricsSetting < ApplicationRecord
- belongs_to :project
-
- validates :external_dashboard_url,
- allow_nil: true,
- length: { maximum: 255 },
- addressable_url: { enforce_sanitization: true, ascii_only: true }
-
- enum dashboard_timezone: { local: 0, utc: 1 }
-
- def dashboard_timezone=(val)
- super(val&.downcase)
- end
-end
diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb
index fec951eb7fe..69d1a9f4aeb 100644
--- a/app/models/project_setting.rb
+++ b/app/models/project_setting.rb
@@ -3,28 +3,25 @@
class ProjectSetting < ApplicationRecord
include ::Gitlab::Utils::StrongMemoize
include EachBatch
+ include IgnorableColumns
- ALLOWED_TARGET_PLATFORMS = %w(ios osx tvos watchos android).freeze
+ ALLOWED_TARGET_PLATFORMS = %w[ios osx tvos watchos android].freeze
belongs_to :project, inverse_of: :project_setting
scope :for_projects, ->(projects) { where(project_id: projects) }
- attr_encrypted :cube_api_key,
- mode: :per_attribute_iv,
- key: Settings.attr_encrypted_db_key_base_32,
- algorithm: 'aes-256-gcm',
- encode: false,
- encode_iv: false
+ ignore_columns %i[
+ encrypted_product_analytics_clickhouse_connection_string
+ encrypted_product_analytics_clickhouse_connection_string_iv
+ encrypted_jitsu_administrator_password
+ encrypted_jitsu_administrator_password_iv
+ jitsu_host
+ jitsu_project_xid
+ jitsu_administrator_email
+ ], remove_with: '16.5', remove_after: '2023-09-22'
- attr_encrypted :jitsu_administrator_password,
- mode: :per_attribute_iv,
- key: Settings.attr_encrypted_db_key_base_32,
- algorithm: 'aes-256-gcm',
- encode: false,
- encode_iv: false
-
- attr_encrypted :product_analytics_clickhouse_connection_string,
+ attr_encrypted :cube_api_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_32,
algorithm: 'aes-256-gcm',
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 3b9b82ee094..34754f4fc95 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -80,6 +80,7 @@ class ProjectTeam
# so we filter out only members of project or project's group
def members_in_project_and_ancestors
members.where(id: member_user_ids)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422405')
end
def members_with_access_levels(access_levels = [])
diff --git a/app/models/releases/link.rb b/app/models/releases/link.rb
index 67d765a15c0..e088fe81f6e 100644
--- a/app/models/releases/link.rb
+++ b/app/models/releases/link.rb
@@ -8,10 +8,10 @@ module Releases
# See https://gitlab.com/gitlab-org/gitlab/-/issues/218753
# Regex modified to prevent catastrophic backtracking
- FILEPATH_REGEX = %r{\A\/[^\/](?!.*\/\/.*)[\-\.\w\/]+[\da-zA-Z]+\z}.freeze
+ FILEPATH_REGEX = %r{\A\/[^\/](?!.*\/\/.*)[\-\.\w\/]+[\da-zA-Z]+\z}
FILEPATH_MAX_LENGTH = 128
- validates :url, presence: true, addressable_url: { schemes: %w(http https ftp) }, uniqueness: { scope: :release }
+ validates :url, presence: true, addressable_url: { schemes: %w[http https ftp] }, uniqueness: { scope: :release }
validates :name, presence: true, uniqueness: { scope: :release }
validates :filepath, uniqueness: { scope: :release }, allow_blank: true
validate :filepath_format_valid?
diff --git a/app/models/repository.rb b/app/models/repository.rb
index b8a46f80bc7..1c27a7a64cf 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -47,27 +47,26 @@ class Repository
#
# For example, for entry `:commit_count` there's a method called `commit_count` which
# stores its data in the `commit_count` cache key.
- CACHED_METHODS = %i(size recent_objects_size commit_count readme_path contribution_guide
+ CACHED_METHODS = %i[size recent_objects_size commit_count readme_path contribution_guide
changelog license_blob license_gitaly gitignore
gitlab_ci_yml branch_names tag_names branch_count
tag_count avatar exists? root_ref merged_branch_names
has_visible_content? issue_template_names_hash merge_request_template_names_hash
- user_defined_metrics_dashboard_paths xcode_project? has_ambiguous_refs?).freeze
+ xcode_project? has_ambiguous_refs?].freeze
# Certain method caches should be refreshed when certain types of files are
# changed. This Hash maps file types (as returned by Gitlab::FileDetector) to
# the corresponding methods to call for refreshing caches.
METHOD_CACHES_FOR_FILE_TYPES = {
- readme: %i(readme_path),
+ readme: %i[readme_path],
changelog: :changelog,
- license: %i(license_blob license_gitaly),
+ license: %i[license_blob license_gitaly],
contributing: :contribution_guide,
gitignore: :gitignore,
gitlab_ci: :gitlab_ci_yml,
avatar: :avatar,
issue_template: :issue_template_names_hash,
merge_request_template: :merge_request_template_names_hash,
- metrics_dashboard: :user_defined_metrics_dashboard_paths,
xcode_config: :xcode_project?
}.freeze
@@ -344,13 +343,13 @@ class Repository
end
def expire_tags_cache
- expire_method_caches(%i(tag_names tag_count has_ambiguous_refs?))
+ expire_method_caches(%i[tag_names tag_count has_ambiguous_refs?])
@tags = nil
@tag_names_include = nil
end
def expire_branches_cache
- expire_method_caches(%i(branch_names merged_branch_names branch_count has_visible_content? has_ambiguous_refs?))
+ expire_method_caches(%i[branch_names merged_branch_names branch_count has_visible_content? has_ambiguous_refs?])
expire_protected_branches_cache
@local_branches = nil
@@ -363,7 +362,7 @@ class Repository
end
def expire_statistics_caches
- expire_method_caches(%i(size recent_objects_size commit_count))
+ expire_method_caches(%i[size recent_objects_size commit_count])
end
def expire_all_method_caches
@@ -371,7 +370,7 @@ class Repository
end
def expire_avatar_cache
- expire_method_caches(%i(avatar))
+ expire_method_caches(%i[avatar])
end
# Refreshes the method caches of this repository.
@@ -412,19 +411,19 @@ class Repository
end
def expire_root_ref_cache
- expire_method_caches(%i(root_ref))
+ expire_method_caches(%i[root_ref])
end
# Expires the cache(s) used to determine if a repository is empty or not.
def expire_emptiness_caches
return unless empty?
- expire_method_caches(%i(has_visible_content?))
+ expire_method_caches(%i[has_visible_content?])
raw_repository.expire_has_local_branches_cache
end
def expire_exists_cache
- expire_method_caches(%i(exists?))
+ expire_method_caches(%i[exists?])
end
# expire cache that doesn't depend on repository data (when expiring)
@@ -628,11 +627,6 @@ class Repository
end
cache_method :merge_request_template_names_hash, fallback: {}
- def user_defined_metrics_dashboard_paths
- Gitlab::Metrics::Dashboard::RepoDashboardFinder.list_dashboards(project)
- end
- cache_method :user_defined_metrics_dashboard_paths, fallback: []
-
def readme
head_tree&.readme
end
@@ -1250,6 +1244,8 @@ class Repository
def get_patch_id(old_revision, new_revision)
raw_repository.get_patch_id(old_revision, new_revision)
+ rescue Gitlab::Git::CommandError
+ nil
end
def object_pool
diff --git a/app/models/resource_label_event.rb b/app/models/resource_label_event.rb
index 13610d37a74..d5c839724d4 100644
--- a/app/models/resource_label_event.rb
+++ b/app/models/resource_label_event.rb
@@ -13,8 +13,7 @@ class ResourceLabelEvent < ResourceEvent
validates :label, presence: { unless: :importing? }, on: :create
validate :exactly_one_issuable, unless: :importing?
- after_destroy :expire_etag_cache
- after_save :expire_etag_cache
+ after_commit :broadcast_notes_changed, unless: :importing?
enum action: {
add: 1,
@@ -22,7 +21,7 @@ class ResourceLabelEvent < ResourceEvent
}
def self.issuable_attrs
- %i(issue merge_request).freeze
+ %i[issue merge_request].freeze
end
def self.preload_label_subjects(events)
@@ -97,8 +96,8 @@ class ResourceLabelEvent < ResourceEvent
issuable.is_a?(MergeRequest) ? :project_merge_requests_url : :project_issues_url
end
- def expire_etag_cache
- issuable.expire_note_etag_cache
+ def broadcast_notes_changed
+ issuable.broadcast_notes_changed
end
def local_label?
diff --git a/app/models/resource_state_event.rb b/app/models/resource_state_event.rb
index 134f71e35ad..88a86258b0a 100644
--- a/app/models/resource_state_event.rb
+++ b/app/models/resource_state_event.rb
@@ -14,7 +14,7 @@ class ResourceStateEvent < ResourceEvent
after_create :issue_usage_metrics
def self.issuable_attrs
- %i(issue merge_request).freeze
+ %i[issue merge_request].freeze
end
def issuable
diff --git a/app/models/resource_timebox_event.rb b/app/models/resource_timebox_event.rb
index 1cc77501d8d..644ffae5749 100644
--- a/app/models/resource_timebox_event.rb
+++ b/app/models/resource_timebox_event.rb
@@ -16,7 +16,7 @@ class ResourceTimeboxEvent < ResourceEvent
after_create :issue_usage_metrics
def self.issuable_attrs
- %i(issue merge_request).freeze
+ %i[issue merge_request].freeze
end
def issuable
diff --git a/app/models/review.rb b/app/models/review.rb
index d47aaf027ce..98e9a314df7 100644
--- a/app/models/review.rb
+++ b/app/models/review.rb
@@ -31,6 +31,10 @@ class Review < ApplicationRecord
def user_mentions
merge_request.user_mentions.where.not(note_id: nil)
end
+
+ def from_merge_request_author?
+ merge_request.author_id == author_id
+ end
end
Review.prepend_mod
diff --git a/app/models/self_managed_prometheus_alert_event.rb b/app/models/self_managed_prometheus_alert_event.rb
deleted file mode 100644
index cf26563e92d..00000000000
--- a/app/models/self_managed_prometheus_alert_event.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-class SelfManagedPrometheusAlertEvent < ApplicationRecord
- include AlertEventLifecycle
-
- belongs_to :project, validate: true, inverse_of: :self_managed_prometheus_alert_events
- belongs_to :environment, validate: true, inverse_of: :self_managed_prometheus_alert_events
- has_and_belongs_to_many :related_issues, class_name: 'Issue', join_table: :issues_self_managed_prometheus_alert_events # rubocop:disable Rails/HasAndBelongsToMany
-
- validates :started_at, presence: true
- validates :payload_key, uniqueness: { scope: :project_id }
-
- def self.find_or_initialize_by_payload_key(project, payload_key)
- find_or_initialize_by(project: project, payload_key: payload_key) do |event|
- yield event if block_given?
- end
- end
-end
diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb
index f3a0479d3b7..30c53b978f8 100644
--- a/app/models/sent_notification.rb
+++ b/app/models/sent_notification.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
class SentNotification < ApplicationRecord
+ include IgnorableColumns
+
+ ignore_column %i[id_convert_to_bigint], remove_with: '16.5', remove_after: '2023-09-22'
+
belongs_to :project
belongs_to :noteable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
belongs_to :recipient, class_name: "User"
diff --git a/app/models/snippet_repository.rb b/app/models/snippet_repository.rb
index 9139dc22a94..a262802c8af 100644
--- a/app/models/snippet_repository.rb
+++ b/app/models/snippet_repository.rb
@@ -5,7 +5,7 @@ class SnippetRepository < ApplicationRecord
include Shardable
DEFAULT_EMPTY_FILE_NAME = 'snippetfile'
- EMPTY_FILE_PATTERN = /^#{DEFAULT_EMPTY_FILE_NAME}(\d+)\.txt$/.freeze
+ EMPTY_FILE_PATTERN = /^#{DEFAULT_EMPTY_FILE_NAME}(\d+)\.txt$/
CommitError = Class.new(StandardError)
InvalidPathError = Class.new(CommitError)
diff --git a/app/models/terraform/state.rb b/app/models/terraform/state.rb
index ecd3e27a9c4..7caf3a1040b 100644
--- a/app/models/terraform/state.rb
+++ b/app/models/terraform/state.rb
@@ -5,7 +5,7 @@ module Terraform
include UsageStatistics
include AfterCommitQueue
- HEX_REGEXP = %r{\A\h+\z}.freeze
+ HEX_REGEXP = %r{\A\h+\z}
UUID_LENGTH = 32
self.locking_column = :activerecord_lock_version
diff --git a/app/models/user.rb b/app/models/user.rb
index 9f85d41b133..c4e867ab571 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -22,7 +22,6 @@ class User < MainClusterwide::ApplicationRecord
include FromUnion
include BatchDestroyDependentAssociations
include BatchNullifyDependentAssociations
- include HasUniqueInternalUsers
include IgnorableColumns
include UpdateHighestRole
include HasUserType
@@ -31,7 +30,28 @@ class User < MainClusterwide::ApplicationRecord
include RestrictedSignup
include StripAttribute
include EachBatch
- include SafelyChangeColumnDefault
+ include CrossDatabaseIgnoredTables
+ include IgnorableColumns
+
+ ignore_column %i[
+ email_opted_in
+ email_opted_in_ip
+ email_opted_in_source_id
+ email_opted_in_at
+ ], remove_with: '16.6', remove_after: '2023-10-22'
+
+ # `ensure_namespace_correct` needs to be moved to an after_commit (?)
+ cross_database_ignore_tables %w[namespaces namespace_settings], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424279'
+
+ # `notification_settings_for` is called, and elsewhere `save` is then called.
+ cross_database_ignore_tables %w[notification_settings], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424284'
+
+ # Associations with dependent: option
+ cross_database_ignore_tables(
+ %w[namespaces projects project_authorizations issues merge_requests merge_requests issues issues merge_requests],
+ url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424285',
+ on: :destroy
+ )
DEFAULT_NOTIFICATION_LEVEL = :participating
@@ -55,13 +75,11 @@ class User < MainClusterwide::ApplicationRecord
:public_email
].freeze
- FORBIDDEN_SEARCH_STATES = %w(blocked banned ldap_blocked).freeze
+ FORBIDDEN_SEARCH_STATES = %w[blocked banned ldap_blocked].freeze
INCOMING_MAIL_TOKEN_PREFIX = 'glimt-'
FEED_TOKEN_PREFIX = 'glft-'
- columns_changing_default :project_view
-
# lib/tasks/tokens.rake needs to be updated when changing mail and feed tokens
add_authentication_token_field :incoming_email_token, token_generator: -> { self.generate_incoming_mail_token }
add_authentication_token_field :feed_token, format_with_prefix: :prefix_for_feed_token
@@ -262,8 +280,6 @@ class User < MainClusterwide::ApplicationRecord
has_many :organization_users, class_name: 'Organizations::OrganizationUser', inverse_of: :user
has_many :organizations, through: :organization_users, class_name: 'Organizations::Organization', inverse_of: :users
- has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :user
-
has_one :status, class_name: 'UserStatus'
has_one :user_preference
has_one :user_detail
@@ -346,7 +362,9 @@ class User < MainClusterwide::ApplicationRecord
email_to_confirm.confirm
end
else
- add_primary_email_to_emails!
+ ignore_cross_database_tables_if_factory_bot(%w[emails]) do
+ add_primary_email_to_emails!
+ end
end
end
after_commit(on: :update) do
@@ -378,6 +396,7 @@ class User < MainClusterwide::ApplicationRecord
:gitpod_enabled, :gitpod_enabled=,
:setup_for_company, :setup_for_company=,
:project_shortcut_buttons, :project_shortcut_buttons=,
+ :keyboard_shortcuts_enabled, :keyboard_shortcuts_enabled=,
:render_whitespace_in_code, :render_whitespace_in_code=,
:markdown_surround_selection, :markdown_surround_selection=,
:markdown_automatic_lists, :markdown_automatic_lists=,
@@ -501,11 +520,19 @@ class User < MainClusterwide::ApplicationRecord
end
after_transition any => :active do |user|
- user.starred_projects.update_counters(star_count: 1)
+ user.class.temporary_ignore_cross_database_tables(
+ %w[projects], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424278'
+ ) do
+ user.starred_projects.update_counters(star_count: 1)
+ end
end
after_transition active: any do |user|
- user.starred_projects.update_counters(star_count: -1)
+ user.class.temporary_ignore_cross_database_tables(
+ %w[projects], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424278'
+ ) do
+ user.starred_projects.update_counters(star_count: -1)
+ end
end
end
@@ -884,92 +911,6 @@ class User < MainClusterwide::ApplicationRecord
}x
end
- # Return (create if necessary) the ghost user. The ghost user
- # owns records previously belonging to deleted users.
- def ghost
- email = 'ghost%s@example.com'
- unique_internal(where(user_type: :ghost), 'ghost', email) do |u|
- u.bio = _('This is a "Ghost User", created to hold all issues authored by users that have since been deleted. This user cannot be removed.')
- u.name = 'Ghost User'
- end
- end
-
- def alert_bot
- email_pattern = "alert%s@#{Settings.gitlab.host}"
-
- unique_internal(where(user_type: :alert_bot), 'alert-bot', email_pattern) do |u|
- u.bio = 'The GitLab alert bot'
- u.name = 'GitLab Alert Bot'
- u.avatar = bot_avatar(image: 'alert-bot.png')
- end
- end
-
- def migration_bot
- email_pattern = "noreply+gitlab-migration-bot%s@#{Settings.gitlab.host}"
-
- unique_internal(where(user_type: :migration_bot), 'migration-bot', email_pattern) do |u|
- u.bio = 'The GitLab migration bot'
- u.name = 'GitLab Migration Bot'
- u.confirmed_at = Time.zone.now
- end
- end
-
- def security_bot
- email_pattern = "security-bot%s@#{Settings.gitlab.host}"
-
- unique_internal(where(user_type: :security_bot), 'GitLab-Security-Bot', email_pattern) do |u|
- u.bio = 'System bot that monitors detected vulnerabilities for solutions and creates merge requests with the fixes.'
- u.name = 'GitLab Security Bot'
- u.website_url = Gitlab::Routing.url_helpers.help_page_url('user/application_security/security_bot/index.md')
- u.avatar = bot_avatar(image: 'security-bot.png')
- u.confirmed_at = Time.zone.now
- end
- end
-
- def support_bot
- email_pattern = "support%s@#{Settings.gitlab.host}"
-
- unique_internal(where(user_type: :support_bot), 'support-bot', email_pattern) do |u|
- u.bio = 'The GitLab support bot used for Service Desk'
- u.name = 'GitLab Support Bot'
- u.avatar = bot_avatar(image: 'support-bot.png')
- u.confirmed_at = Time.zone.now
- end
- end
-
- def automation_bot
- email_pattern = "automation%s@#{Settings.gitlab.host}"
-
- unique_internal(where(user_type: :automation_bot), 'automation-bot', email_pattern) do |u|
- u.bio = 'The GitLab automation bot used for automated workflows and tasks'
- u.name = 'GitLab Automation Bot'
- u.avatar = bot_avatar(image: 'support-bot.png') # todo: add an avatar for automation-bot
- end
- end
-
- def llm_bot
- email_pattern = "llm-bot%s@#{Settings.gitlab.host}"
-
- unique_internal(where(user_type: :llm_bot), 'GitLab-Llm-Bot', email_pattern) do |u|
- u.bio = 'The Gitlab LLM bot used for fetching LLM-generated content'
- u.name = 'GitLab LLM Bot'
- u.avatar = bot_avatar(image: 'support-bot.png') # todo: add an avatar for llm-bot
- u.confirmed_at = Time.zone.now
- end
- end
-
- def admin_bot
- email_pattern = "admin-bot%s@#{Settings.gitlab.host}"
-
- unique_internal(where(user_type: :admin_bot), 'GitLab-Admin-Bot', email_pattern) do |u|
- u.bio = 'Admin bot used for tasks that require admin privileges'
- u.name = 'GitLab Admin Bot'
- u.avatar = bot_avatar(image: 'admin-bot.png')
- u.admin = true
- u.confirmed_at = Time.zone.now
- end
- end
-
# Return true if there is only single non-internal user in the deployment,
# ghost user is ignored.
def single_user?
@@ -2009,7 +1950,7 @@ class User < MainClusterwide::ApplicationRecord
def access_level=(new_level)
new_level = new_level.to_s
- return unless %w(admin regular).include?(new_level)
+ return unless %w[admin regular].include?(new_level)
self.admin = (new_level == 'admin')
end
@@ -2175,16 +2116,6 @@ class User < MainClusterwide::ApplicationRecord
[last_activity, last_sign_in].compact.max
end
- REQUIRES_ROLE_VALUE = 99
-
- def role_required?
- role_before_type_cast == REQUIRES_ROLE_VALUE
- end
-
- def set_role_required!
- update_column(:role, REQUIRES_ROLE_VALUE)
- end
-
def dismissed_callout?(feature_name:, ignore_dismissal_earlier_than: nil)
callout = callouts_by_feature_name[feature_name]
@@ -2354,7 +2285,7 @@ class User < MainClusterwide::ApplicationRecord
def ban_and_report
msg = 'Potential spammer account deletion'
- attrs = { user_id: id, reporter: User.security_bot, category: 'spam' }
+ attrs = { user_id: id, reporter: Users::Internal.security_bot, category: 'spam' }
abuse_report = AbuseReport.find_by(attrs)
if abuse_report.nil?
@@ -2519,7 +2450,7 @@ class User < MainClusterwide::ApplicationRecord
def update_highest_role?
return false unless persisted?
- (previous_changes.keys & %w(state user_type)).any?
+ (previous_changes.keys & %w[state user_type]).any?
end
def update_highest_role_attribute
diff --git a/app/models/user_custom_attribute.rb b/app/models/user_custom_attribute.rb
index 425f2cc062b..15d50071bf6 100644
--- a/app/models/user_custom_attribute.rb
+++ b/app/models/user_custom_attribute.rb
@@ -15,6 +15,7 @@ class UserCustomAttribute < ApplicationRecord
UNBLOCKED_BY = 'unblocked_by'
ARKOSE_RISK_BAND = 'arkose_risk_band'
AUTO_BANNED_BY_ABUSE_REPORT_ID = 'auto_banned_by_abuse_report_id'
+ AUTO_BANNED_BY_SPAM_LOG_ID = 'auto_banned_by_spam_log_id'
ALLOW_POSSIBLE_SPAM = 'allow_possible_spam'
IDENTITY_VERIFICATION_PHONE_EXEMPT = 'identity_verification_phone_exempt'
@@ -45,6 +46,14 @@ class UserCustomAttribute < ApplicationRecord
upsert_custom_attributes([custom_attribute])
end
+ def set_banned_by_spam_log(spam_log)
+ return unless spam_log
+
+ custom_attribute = { user_id: spam_log.user_id, key: AUTO_BANNED_BY_SPAM_LOG_ID, value: spam_log.id }
+
+ upsert_custom_attributes([custom_attribute])
+ end
+
private
def blocked_users
diff --git a/app/models/user_interacted_project.rb b/app/models/user_interacted_project.rb
index 1c7515894fe..73bca362960 100644
--- a/app/models/user_interacted_project.rb
+++ b/app/models/user_interacted_project.rb
@@ -24,7 +24,7 @@ class UserInteractedProject < ApplicationRecord
}
cached_exists?(**attributes) do
- where(attributes).exists? || UserInteractedProject.insert_all([attributes], unique_by: %w(project_id user_id))
+ where(attributes).exists? || UserInteractedProject.insert_all([attributes], unique_by: %w[project_id user_id])
true
end
end
diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb
index eac66905d0c..8fc9f4617d0 100644
--- a/app/models/user_preference.rb
+++ b/app/models/user_preference.rb
@@ -35,6 +35,7 @@ class UserPreference < MainClusterwide::ApplicationRecord
attribute :time_display_relative, default: true
attribute :render_whitespace_in_code, default: false
attribute :project_shortcut_buttons, default: true
+ attribute :keyboard_shortcuts_enabled, default: true
enum visibility_pipeline_id_type: { id: 0, iid: 1 }
diff --git a/app/models/users/callout.rb b/app/models/users/callout.rb
index 0d3262b2474..def0765560e 100644
--- a/app/models/users/callout.rb
+++ b/app/models/users/callout.rb
@@ -62,7 +62,7 @@ module Users
project_quality_summary_feedback: 59, # EE-only
merge_request_settings_moved_callout: 60,
new_top_level_group_alert: 61,
- artifacts_management_page_feedback_banner: 62,
+ # 62, removed in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131314
# 63 and 64 were removed with https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120233
branch_rules_info_callout: 65,
create_runner_workflow_banner: 66,
@@ -71,9 +71,11 @@ module Users
project_repository_limit_alert_alert_threshold: 69, # EE-only
project_repository_limit_alert_error_threshold: 70, # EE-only
new_navigation_callout: 71,
- code_suggestions_third_party_callout: 72, # EE-only
+ # 72 removed in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129022
namespace_over_storage_users_combined_alert: 73, # EE-only
- rich_text_editor: 74
+ rich_text_editor: 74,
+ vsd_feedback_banner: 75, # EE-only
+ security_policy_protected_branch_modification: 76 # EE-only
}
validates :feature_name,
diff --git a/app/models/users/credit_card_validation.rb b/app/models/users/credit_card_validation.rb
index 1b0fd8682db..086943884a5 100644
--- a/app/models/users/credit_card_validation.rb
+++ b/app/models/users/credit_card_validation.rb
@@ -16,6 +16,12 @@ module Users
greater_than_or_equal_to: 0, less_than_or_equal_to: 9999
}
+ validates :last_digits_hash, length: { maximum: 44 }
+ validates :holder_name_hash, length: { maximum: 44 }
+ validates :expiration_date_hash, length: { maximum: 44 }
+ validates :network_hash, length: { maximum: 44 }
+
+ scope :find_or_initialize_by_user, ->(user_id) { where(user_id: user_id).first_or_initialize }
scope :by_banned_user, -> { joins(:banned_user) }
scope :similar_by_holder_name, ->(holder_name) do
if holder_name.present?
@@ -32,6 +38,11 @@ module Users
)
end
+ before_save :set_last_digits_hash, if: -> { last_digits.present? }
+ before_save :set_holder_name_hash, if: -> { holder_name.present? }
+ before_save :set_network_hash, if: -> { network.present? }
+ before_save :set_expiration_date_hash, if: -> { expiration_date.present? }
+
def similar_records
self.class.similar_to(self).order(credit_card_validated_at: :desc).includes(:user)
end
@@ -43,5 +54,21 @@ module Users
def used_by_banned_user?
self.class.by_banned_user.similar_to(self).similar_by_holder_name(holder_name).exists?
end
+
+ def set_last_digits_hash
+ self.last_digits_hash = Gitlab::CryptoHelper.sha256(last_digits)
+ end
+
+ def set_holder_name_hash
+ self.holder_name_hash = Gitlab::CryptoHelper.sha256(holder_name.downcase)
+ end
+
+ def set_network_hash
+ self.network_hash = Gitlab::CryptoHelper.sha256(network.downcase)
+ end
+
+ def set_expiration_date_hash
+ self.expiration_date_hash = Gitlab::CryptoHelper.sha256(expiration_date.to_s)
+ end
end
end
diff --git a/app/models/users/group_visit.rb b/app/models/users/group_visit.rb
new file mode 100644
index 00000000000..0bcfda049fc
--- /dev/null
+++ b/app/models/users/group_visit.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Users
+ class GroupVisit < ApplicationRecord
+ include Users::Visitable
+ include PartitionedTable
+
+ self.table_name = "groups_visits"
+ self.primary_key = :id
+
+ partitioned_by :visited_at, strategy: :monthly, retain_for: 3.months
+
+ validates :entity_id, presence: true
+ validates :user_id, presence: true
+ validates :visited_at, presence: true
+ end
+end
diff --git a/app/models/users/project_callout.rb b/app/models/users/project_callout.rb
index 3964f202be6..6affe5b5030 100644
--- a/app/models/users/project_callout.rb
+++ b/app/models/users/project_callout.rb
@@ -11,10 +11,10 @@ module Users
enum feature_name: {
awaiting_members_banner: 1, # EE-only
web_hook_disabled: 2,
- ultimate_feature_removal_banner: 3,
+ # 3 was removed https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129703,
+ # and cleaned up https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129924, it can be replaced
namespace_storage_pre_enforcement_banner: 4, # EE-only
- # 5,6,7 were unused and removed with https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118330,
- # they can be replaced.
+ # 5,6,7 were removed https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118330, they can be replaced
license_check_deprecation_alert: 8 # EE-only
}
diff --git a/app/models/users/project_visit.rb b/app/models/users/project_visit.rb
new file mode 100644
index 00000000000..1d076e0be56
--- /dev/null
+++ b/app/models/users/project_visit.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Users
+ class ProjectVisit < ApplicationRecord
+ include Users::Visitable
+ include PartitionedTable
+
+ self.table_name = "projects_visits"
+ self.primary_key = :id
+
+ partitioned_by :visited_at, strategy: :monthly, retain_for: 3.months
+
+ validates :entity_id, presence: true
+ validates :user_id, presence: true
+ validates :visited_at, presence: true
+ end
+end
diff --git a/app/models/work_item.rb b/app/models/work_item.rb
index 73156b2f040..62b837eeeb6 100644
--- a/app/models/work_item.rb
+++ b/app/models/work_item.rb
@@ -4,7 +4,8 @@ class WorkItem < Issue
include Gitlab::Utils::StrongMemoize
COMMON_QUICK_ACTIONS_COMMANDS = [
- :title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to
+ :title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to, :checkin_reminder,
+ :subscribe, :unsubscribe, :confidential, :award
].freeze
self.table_name = 'issues'
@@ -146,6 +147,18 @@ class WorkItem < Issue
{ common: common_params, widgets: widget_params }
end
+ def linked_work_items(current_user = nil, authorize: true, preload: nil, link_type: nil)
+ linked_work_items = linked_work_items_query(link_type).preload(preload).reorder('issue_link_id')
+ return linked_work_items unless authorize
+
+ cross_project_filter = ->(work_items) { work_items.where(project: project) }
+ Ability.work_items_readable_by_user(
+ linked_work_items,
+ current_user,
+ filters: { read_cross_project: cross_project_filter }
+ )
+ end
+
private
override :parent_link_confidentiality
@@ -241,6 +254,21 @@ class WorkItem < Issue
errors.add(:work_item_type_id, _('reached maximum depth'))
end
end
+
+ def linked_work_items_query(link_type)
+ type_condition =
+ if link_type == WorkItems::RelatedWorkItemLink::TYPE_RELATES_TO
+ " AND issue_links.link_type = #{WorkItems::RelatedWorkItemLink.link_types[link_type]}"
+ else
+ ""
+ end
+
+ linked_issues_select
+ .joins("INNER JOIN issue_links ON
+ (issue_links.source_id = issues.id AND issue_links.target_id = #{id}#{type_condition})
+ OR
+ (issue_links.target_id = issues.id AND issue_links.source_id = #{id}#{type_condition})")
+ end
end
WorkItem.prepend_mod
diff --git a/app/models/work_items/parent_link.rb b/app/models/work_items/parent_link.rb
index d9e3690b6fc..ea7755b03b4 100644
--- a/app/models/work_items/parent_link.rb
+++ b/app/models/work_items/parent_link.rb
@@ -7,7 +7,6 @@ module WorkItems
self.table_name = 'work_item_parent_links'
MAX_CHILDREN = 100
- PARENT_TYPES = [:issue, :incident].freeze
belongs_to :work_item
belongs_to :work_item_parent, class_name: 'WorkItem'
@@ -122,3 +121,5 @@ module WorkItems
end
end
end
+
+WorkItems::ParentLink.prepend_mod
diff --git a/app/models/work_items/related_work_item_link.rb b/app/models/work_items/related_work_item_link.rb
index 4de197d3d35..a911ef5f05d 100644
--- a/app/models/work_items/related_work_item_link.rb
+++ b/app/models/work_items/related_work_item_link.rb
@@ -6,9 +6,13 @@ module WorkItems
self.table_name = 'issue_links'
+ MAX_LINKS_COUNT = 100
+
belongs_to :source, class_name: 'WorkItem'
belongs_to :target, class_name: 'WorkItem'
+ validate :validate_max_number_of_links, on: :create
+
class << self
extend ::Gitlab::Utils::Override
@@ -23,5 +27,15 @@ module WorkItems
'work item'
end
end
+
+ def validate_max_number_of_links
+ if source && source.linked_work_items(authorize: false).size >= MAX_LINKS_COUNT
+ errors.add :source, s_('WorkItems|This work item would exceed the maximum number of linked items.')
+ end
+
+ return unless target && target.linked_work_items(authorize: false).size >= MAX_LINKS_COUNT
+
+ errors.add :target, s_('WorkItems|This work item would exceed the maximum number of linked items.')
+ end
end
end
diff --git a/app/models/work_items/type.rb b/app/models/work_items/type.rb
index 369ffc660aa..b7ceeecbc7f 100644
--- a/app/models/work_items/type.rb
+++ b/app/models/work_items/type.rb
@@ -44,8 +44,6 @@ module WorkItems
# where it's possible to switch between issue and incident.
CHANGEABLE_BASE_TYPES = %w[issue incident test_case].freeze
- WI_TYPES_WITH_CREATED_HEADER = %w[issue incident ticket].freeze
-
cache_markdown_field :description, pipeline: :single_line
enum base_type: BASE_TYPES.transform_values { |value| value[:enum_value] }
diff --git a/app/models/work_items/widgets/linked_items.rb b/app/models/work_items/widgets/linked_items.rb
index 06a0f6db964..b405555c038 100644
--- a/app/models/work_items/widgets/linked_items.rb
+++ b/app/models/work_items/widgets/linked_items.rb
@@ -3,7 +3,7 @@
module WorkItems
module Widgets
class LinkedItems < Base
- delegate :related_issues, to: :work_item
+ delegate :linked_work_items, to: :work_item
end
end
end
diff --git a/app/models/x509_certificate.rb b/app/models/x509_certificate.rb
index 7c2581b8bb2..90f3bd69c47 100644
--- a/app/models/x509_certificate.rb
+++ b/app/models/x509_certificate.rb
@@ -17,8 +17,6 @@ class X509Certificate < ApplicationRecord
# rfc 5280 - 4.2.1.2 Subject Key Identifier
validates :subject_key_identifier, presence: true, format: { with: Gitlab::Regex.x509_subject_key_identifier_regex }
- # rfc 5280 - 4.1.2.6 Subject
- validates :subject, presence: true
# rfc 5280 - 4.1.2.6 Subject (subjectAltName contains the email address)
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
# rfc 5280 - 4.1.2.2 Serial number
diff --git a/app/models/x509_issuer.rb b/app/models/x509_issuer.rb
index 81491d8e507..769d56a9838 100644
--- a/app/models/x509_issuer.rb
+++ b/app/models/x509_issuer.rb
@@ -6,13 +6,16 @@ class X509Issuer < ApplicationRecord
# rfc 5280 - 4.2.1.1 Authority Key Identifier
validates :subject_key_identifier, presence: true, format: { with: Gitlab::Regex.x509_subject_key_identifier_regex }
# rfc 5280 - 4.1.2.4 Issuer
- validates :subject, presence: true
# rfc 5280 - 4.2.1.13 CRL Distribution Points
# cRLDistributionPoints extension using URI:http
- validates :crl_url, presence: true, public_url: true
+ validates :crl_url, allow_nil: true, public_url: true
def self.safe_create!(attributes)
create_with(attributes)
.safe_find_or_create_by!(subject_key_identifier: attributes[:subject_key_identifier])
end
+
+ def self.with_crl_url
+ where.not(crl_url: nil)
+ end
end
diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb
index d6aaa3e983d..1ec2495a661 100644
--- a/app/policies/base_policy.rb
+++ b/app/policies/base_policy.rb
@@ -57,6 +57,12 @@ class BasePolicy < DeclarativePolicy::Base
with_options scope: :user, score: 0
condition(:can_create_group) { @user&.can_create_group }
+ # TODO: update to check application setting
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/423302
+ desc 'User can create an organization'
+ with_options scope: :user, score: 0
+ condition(:can_create_organization) { true }
+
desc "The application is restricted from public visibility"
condition(:restricted_public_level, scope: :global) do
Gitlab::CurrentSettings.current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC)
diff --git a/app/policies/ci/bridge_policy.rb b/app/policies/ci/bridge_policy.rb
index 5f9e8eab08a..9cf3a017b39 100644
--- a/app/policies/ci/bridge_policy.rb
+++ b/app/policies/ci/bridge_policy.rb
@@ -5,8 +5,12 @@ module Ci
include Ci::DeployablePolicy
condition(:can_update_downstream_branch) do
- ::Gitlab::UserAccess.new(@user, container: @subject.downstream_project)
- .can_update_branch?(@subject.target_revision_ref)
+ # `bridge.downstream_project` could be `nil` if the downstream project was removed after the pipeline creation,
+ # which raises an error in `UserAccess` class because `container` arg must be present.
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/424145 for more information.
+ @subject.downstream_project.present? &&
+ ::Gitlab::UserAccess.new(@user, container: @subject.downstream_project)
+ .can_update_branch?(@subject.target_revision_ref)
end
rule { can_update_downstream_branch }.enable :play_job
diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb
index 4d21da0226b..1d60b1e79de 100644
--- a/app/policies/ci/pipeline_policy.rb
+++ b/app/policies/ci/pipeline_policy.rb
@@ -18,6 +18,10 @@ module Ci
@subject.triggered_by?(@user)
end
+ condition(:project_allows_read_dependency) do
+ can?(:read_dependency, @subject.project)
+ end
+
# Disallow users without permissions from accessing internal pipelines
rule { ~can?(:read_build) & ~external_pipeline }.policy do
prevent :read_pipeline
@@ -41,6 +45,10 @@ module Ci
enable :read_pipeline_variable
end
+ rule { project_allows_read_dependency }.policy do
+ enable :read_dependency
+ end
+
def ref_protected?(user, project, tag, ref)
access = ::Gitlab::UserAccess.new(user, container: project)
diff --git a/app/policies/design_management/repository_policy.rb b/app/policies/design_management/repository_policy.rb
new file mode 100644
index 00000000000..404f363a03a
--- /dev/null
+++ b/app/policies/design_management/repository_policy.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module DesignManagement
+ class RepositoryPolicy < ::BasePolicy
+ delegate { @subject.project }
+ end
+end
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index bf7bfe36254..7594360a91c 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -29,6 +29,7 @@ class GlobalPolicy < BasePolicy
prevent :receive_notifications
prevent :use_quick_actions
prevent :create_group
+ prevent :create_organization
prevent :execute_graphql_mutation
end
@@ -93,6 +94,10 @@ class GlobalPolicy < BasePolicy
enable :create_group
end
+ rule { can_create_organization }.policy do
+ enable :create_organization
+ end
+
rule { can?(:create_group) }.policy do
enable :create_group_with_default_branch_protection
end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index c50f74f2b35..faa83019bda 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -217,6 +217,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :update_cluster
enable :admin_cluster
enable :read_deploy_token
+ enable :read_group_runners
enable :create_jira_connect_subscription
enable :maintainer_access
enable :read_upload
diff --git a/app/policies/organizations/organization_policy.rb b/app/policies/organizations/organization_policy.rb
index 1c0d996c7d4..401aa45786d 100644
--- a/app/policies/organizations/organization_policy.rb
+++ b/app/policies/organizations/organization_policy.rb
@@ -14,10 +14,12 @@ module Organizations
rule { admin }.policy do
enable :admin_organization
enable :read_organization
+ enable :read_organization_user
end
rule { organization_user }.policy do
enable :read_organization
+ enable :read_organization_user
end
end
end
diff --git a/app/policies/organizations/organization_user_policy.rb b/app/policies/organizations/organization_user_policy.rb
new file mode 100644
index 00000000000..91d542378c8
--- /dev/null
+++ b/app/policies/organizations/organization_user_policy.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module Organizations
+ class OrganizationUserPolicy < BasePolicy
+ delegate :organization
+ end
+end
diff --git a/app/policies/project_member_policy.rb b/app/policies/project_member_policy.rb
index ace74dca448..9d6a8c22e6d 100644
--- a/app/policies/project_member_policy.rb
+++ b/app/policies/project_member_policy.rb
@@ -37,3 +37,5 @@ class ProjectMemberPolicy < BasePolicy
enable :withdraw_member_access_request
end
end
+
+ProjectMemberPolicy.prepend_mod_with('ProjectMemberPolicy')
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 25495bb0221..38e6360f81d 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -862,7 +862,11 @@ class ProjectPolicy < BasePolicy
enable :set_pipeline_variables
end
- rule { ~security_and_compliance_disabled & can?(:developer_access) }.policy do
+ rule { security_and_compliance_disabled }.policy do
+ prevent :access_security_and_compliance
+ end
+
+ rule { can?(:developer_access) }.policy do
enable :access_security_and_compliance
end
diff --git a/app/presenters/blob_presenter.rb b/app/presenters/blob_presenter.rb
index bc12d210334..6f32f4de62c 100644
--- a/app/presenters/blob_presenter.rb
+++ b/app/presenters/blob_presenter.rb
@@ -76,7 +76,7 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
end
def pipeline_editor_path
- project_ci_pipeline_editor_path(project, branch_name: blob.commit_id) if can_collaborate_with_project?(project) && blob.path == project.ci_config_path_or_default
+ project_ci_pipeline_editor_path(project, branch_name: commit_id) if can_collaborate_with_project?(project) && blob.path == project.ci_config_path_or_default
end
def gitpod_blob_url
diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb
index 79c1946f3d2..838196e96ac 100644
--- a/app/presenters/ci/build_runner_presenter.rb
+++ b/app/presenters/ci/build_runner_presenter.rb
@@ -61,6 +61,16 @@ module Ci
end
# rubocop: enable CodeReuse/ActiveRecord
+ def project_jobs_running_on_instance_runners_count
+ # if not instance runner we don't care about that value and present `+Inf` as a placeholder for Prometheus
+ return '+Inf' unless runner.instance_type?
+
+ return project.instance_runner_running_jobs_count.to_s if
+ project.instance_runner_running_jobs_count < Project::INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET
+
+ "#{Project::INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET}+"
+ end
+
private
def create_archive(artifacts)
diff --git a/app/presenters/dev_ops_report/metric_presenter.rb b/app/presenters/dev_ops_report/metric_presenter.rb
index 1a5b12fa408..75dbbb63f76 100644
--- a/app/presenters/dev_ops_report/metric_presenter.rb
+++ b/app/presenters/dev_ops_report/metric_presenter.rb
@@ -93,52 +93,52 @@ module DevOpsReport
IdeaToProductionStep.new(
metric: metric,
title: 'Idea',
- features: %w(issues)
+ features: %w[issues]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Issue',
- features: %w(issues notes)
+ features: %w[issues notes]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Plan',
- features: %w(milestones boards)
+ features: %w[milestones boards]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Code',
- features: %w(merge_requests)
+ features: %w[merge_requests]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Commit',
- features: %w(merge_requests)
+ features: %w[merge_requests]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Test',
- features: %w(ci_pipelines)
+ features: %w[ci_pipelines]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Review',
- features: %w(ci_pipelines environments)
+ features: %w[ci_pipelines environments]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Staging',
- features: %w(environments deployments)
+ features: %w[environments deployments]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Production',
- features: %w(deployments)
+ features: %w[deployments]
),
IdeaToProductionStep.new(
metric: metric,
title: 'Feedback',
- features: %w(projects_prometheus_active service_desk_issues)
+ features: %w[projects_prometheus_active service_desk_issues]
)
]
end
diff --git a/app/presenters/event_presenter.rb b/app/presenters/event_presenter.rb
index a098db7fbbc..8f7b2d5868e 100644
--- a/app/presenters/event_presenter.rb
+++ b/app/presenters/event_presenter.rb
@@ -54,4 +54,29 @@ class EventPresenter < Gitlab::View::Presenter::Delegated
target.noteable_type.titleize
end.downcase
end
+
+ def push_activity_description
+ return unless push_action?
+
+ if batch_push?
+ "#{action_name} #{ref_count} #{ref_type.pluralize(ref_count)}"
+ else
+ "#{action_name} #{ref_type}"
+ end
+ end
+
+ def batch_push?
+ push_action? && ref_count.to_i > 0
+ end
+
+ def linked_to_reference?
+ return false unless push_action?
+ return false if event.project.nil?
+
+ if tag?
+ project.repository.tag_exists?(ref_name)
+ else
+ project.repository.branch_exists?(ref_name)
+ end
+ end
end
diff --git a/app/presenters/gitlab/blame_presenter.rb b/app/presenters/gitlab/blame_presenter.rb
index 6230e61d2be..0a2738bea5f 100644
--- a/app/presenters/gitlab/blame_presenter.rb
+++ b/app/presenters/gitlab/blame_presenter.rb
@@ -40,6 +40,10 @@ module Gitlab
@commits[commit.id] ||= get_commit_data(commit, previous_path)
end
+ def groups_commit_data
+ groups.each { |group| group[:commit_data] = commit_data(group[:commit]) }
+ end
+
private
# Huge source files with a high churn rate (e.g. 'locale/gitlab.pot') could have
@@ -86,5 +90,17 @@ module Gitlab
def mail_to(*args, &block)
ActionController::Base.helpers.mail_to(*args, &block)
end
+
+ def project
+ return super.project if defined?(super.project)
+
+ blame.commit.repository.project
+ end
+
+ def page
+ return super.page if defined?(super.page)
+
+ nil
+ end
end
end
diff --git a/app/presenters/issue_presenter.rb b/app/presenters/issue_presenter.rb
index 42ecbc9988e..9403dd0814b 100644
--- a/app/presenters/issue_presenter.rb
+++ b/app/presenters/issue_presenter.rb
@@ -28,6 +28,9 @@ class IssuePresenter < Gitlab::View::Presenter::Delegated
Gitlab::Utils::Email.obfuscated_email(super, deform: true)
end
+ delegator_override :external_author
+ alias_method :external_author, :service_desk_reply_to
+
delegator_override :issue_email_participants
def issue_email_participants
issue.issue_email_participants.present(current_user: current_user)
diff --git a/app/presenters/projects/security/configuration_presenter.rb b/app/presenters/projects/security/configuration_presenter.rb
index 8a6569e7bf3..f248652befc 100644
--- a/app/presenters/projects/security/configuration_presenter.rb
+++ b/app/presenters/projects/security/configuration_presenter.rb
@@ -25,7 +25,8 @@ module Projects
auto_fix_enabled: autofix_enabled,
can_toggle_auto_fix_settings: can_toggle_autofix,
auto_fix_user_path: auto_fix_user_path,
- security_training_enabled: project.security_training_available?
+ security_training_enabled: project.security_training_available?,
+ continuous_vulnerability_scans_enabled: continuous_vulnerability_scans_enabled
}
end
@@ -83,7 +84,8 @@ module Projects
configuration_path: scan.configuration_path,
available: scan.available?,
can_enable_by_merge_request: scan.can_enable_by_merge_request?,
- meta_info_path: scan.meta_info_path
+ meta_info_path: scan.meta_info_path,
+ on_demand_available: scan.on_demand_available?
}
end
@@ -94,6 +96,8 @@ module Projects
def project_settings
project.security_setting
end
+
+ def continuous_vulnerability_scans_enabled; end
end
end
end
diff --git a/app/presenters/search_service_presenter.rb b/app/presenters/search_service_presenter.rb
index 91e67c379c4..d79736a6e52 100644
--- a/app/presenters/search_service_presenter.rb
+++ b/app/presenters/search_service_presenter.rb
@@ -17,7 +17,7 @@ class SearchServicePresenter < Gitlab::View::Presenter::Delegated
blobs: :with_web_entity_associations
}.freeze
- SORT_ENABLED_SCOPES = %w(issues merge_requests epics).freeze
+ SORT_ENABLED_SCOPES = %w[issues merge_requests epics].freeze
delegator_override :search_objects
def search_objects
diff --git a/app/serializers/activity_pub/activity_streams_serializer.rb b/app/serializers/activity_pub/activity_streams_serializer.rb
new file mode 100644
index 00000000000..39caa4a6d10
--- /dev/null
+++ b/app/serializers/activity_pub/activity_streams_serializer.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class ActivityStreamsSerializer < ::BaseSerializer
+ MissingIdentifierError = Class.new(StandardError)
+ MissingTypeError = Class.new(StandardError)
+ MissingOutboxError = Class.new(StandardError)
+
+ alias_method :base_represent, :represent
+
+ def represent(resource, opts = {}, entity_class = nil)
+ response = if respond_to?(:paginated?) && paginated?
+ represent_paginated(resource, opts, entity_class)
+ else
+ represent_whole(resource, opts, entity_class)
+ end
+
+ validate_response(HashWithIndifferentAccess.new(response))
+ end
+
+ private
+
+ def validate_response(response)
+ unless response[:id].present?
+ raise MissingIdentifierError, "The serializer does not provide the mandatory 'id' field."
+ end
+
+ unless response[:type].present?
+ raise MissingTypeError, "The serializer does not provide the mandatory 'type' field."
+ end
+
+ response
+ end
+
+ def represent_whole(resource, opts, entity_class)
+ raise MissingOutboxError, 'Please provide an :outbox option for this actor' unless opts[:outbox].present?
+
+ serialized = base_represent(resource, opts, entity_class)
+
+ {
+ :@context => "https://www.w3.org/ns/activitystreams",
+ inbox: opts[:inbox],
+ outbox: opts[:outbox]
+ }.merge(serialized)
+ end
+
+ def represent_paginated(resources, opts, entity_class)
+ if paginator.params['page'].present?
+ represent_page(resources, resources.current_page, opts, entity_class)
+ else
+ represent_pagination_index(resources)
+ end
+ end
+
+ def represent_page(resources, page, opts, entity_class)
+ opts[:page] = page
+ serialized = base_represent(resources, opts, entity_class)
+
+ {
+ :@context => 'https://www.w3.org/ns/activitystreams',
+ type: 'OrderedCollectionPage',
+ id: collection_url(page),
+ prev: page > 1 ? collection_url(page - 1) : nil,
+ next: page < resources.total_pages ? collection_url(page + 1) : nil,
+ partOf: collection_url,
+ orderedItems: serialized
+ }
+ end
+
+ def represent_pagination_index(resources)
+ {
+ :@context => 'https://www.w3.org/ns/activitystreams',
+ type: 'OrderedCollection',
+ id: collection_url,
+ totalItems: resources.total_count,
+ first: collection_url(1),
+ last: collection_url(resources.total_pages)
+ }
+ end
+
+ def collection_url(page = nil)
+ uri = URI.parse(paginator.request.url)
+ uri.query ||= ""
+ parts = uri.query.split('&').reject { |part| part =~ /^page=/ }
+ parts << "page=#{page}" if page
+ uri.query = parts.join('&')
+ uri.to_s.sub(/\?$/, '')
+ end
+ end
+end
diff --git a/app/serializers/activity_pub/project_entity.rb b/app/serializers/activity_pub/project_entity.rb
new file mode 100644
index 00000000000..02ed0cdc047
--- /dev/null
+++ b/app/serializers/activity_pub/project_entity.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class ProjectEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id do |project|
+ project_url(project)
+ end
+
+ expose :type do |*|
+ "Application"
+ end
+
+ expose :name
+
+ expose :description, as: :summary
+
+ expose :url do |project|
+ project_url(project)
+ end
+ end
+end
diff --git a/app/serializers/activity_pub/release_entity.rb b/app/serializers/activity_pub/release_entity.rb
new file mode 100644
index 00000000000..9e3e5397034
--- /dev/null
+++ b/app/serializers/activity_pub/release_entity.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class ReleaseEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id do |release, opts|
+ "#{opts[:url]}##{release.tag}"
+ end
+
+ expose :type do |*|
+ "Create"
+ end
+
+ expose :to do |*|
+ 'https://www.w3.org/ns/activitystreams#Public'
+ end
+
+ expose :author, as: :actor, using: UserEntity
+
+ expose :object do
+ expose :id do |release|
+ project_release_url(release.project, release)
+ end
+
+ expose :type do |*|
+ "Application"
+ end
+
+ expose :name
+
+ expose :url do |release|
+ project_release_url(release.project, release)
+ end
+
+ expose :description, as: :content
+ expose :project, as: :context, using: ProjectEntity
+ end
+ end
+end
diff --git a/app/serializers/activity_pub/releases_actor_entity.rb b/app/serializers/activity_pub/releases_actor_entity.rb
new file mode 100644
index 00000000000..c52741c73a5
--- /dev/null
+++ b/app/serializers/activity_pub/releases_actor_entity.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class ReleasesActorEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id do |project|
+ project_releases_url(project)
+ end
+
+ expose :type do |*|
+ "Application"
+ end
+
+ expose :path, as: :preferredUsername do |project|
+ "#{project.path}-releases"
+ end
+
+ expose :name do |project|
+ "#{_('Releases')} - #{project.name}"
+ end
+
+ expose :description, as: :content
+
+ expose nil, using: ProjectEntity, as: :context do |project|
+ project
+ end
+ end
+end
diff --git a/app/serializers/activity_pub/releases_actor_serializer.rb b/app/serializers/activity_pub/releases_actor_serializer.rb
new file mode 100644
index 00000000000..5bae83f2dc7
--- /dev/null
+++ b/app/serializers/activity_pub/releases_actor_serializer.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class ReleasesActorSerializer < ActivityStreamsSerializer
+ entity ReleasesActorEntity
+ end
+end
diff --git a/app/serializers/activity_pub/releases_outbox_serializer.rb b/app/serializers/activity_pub/releases_outbox_serializer.rb
new file mode 100644
index 00000000000..b6d4e633fb0
--- /dev/null
+++ b/app/serializers/activity_pub/releases_outbox_serializer.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class ReleasesOutboxSerializer < ActivityStreamsSerializer
+ include WithPagination
+
+ entity ReleaseEntity
+ end
+end
diff --git a/app/serializers/activity_pub/user_entity.rb b/app/serializers/activity_pub/user_entity.rb
new file mode 100644
index 00000000000..bd0886db5b2
--- /dev/null
+++ b/app/serializers/activity_pub/user_entity.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class UserEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id do |user|
+ user_url(user)
+ end
+
+ expose :type do |*|
+ 'Person'
+ end
+
+ expose :name
+ expose :username, as: :preferredUsername
+
+ expose :url do |user|
+ user_url(user)
+ end
+ end
+end
diff --git a/app/serializers/admin/abuse_report_details_entity.rb b/app/serializers/admin/abuse_report_details_entity.rb
index 3efb8508e5e..8a67aabda9e 100644
--- a/app/serializers/admin/abuse_report_details_entity.rb
+++ b/app/serializers/admin/abuse_report_details_entity.rb
@@ -8,17 +8,21 @@ module Admin
expose :details, merge: true do |report|
UserEntity.represent(report.user, only: [:name, :username, :avatar_url, :email, :created_at, :last_activity_on])
end
+
expose :path do |report|
user_path(report.user)
end
+
expose :admin_path do |report|
admin_user_path(report.user)
end
+
expose :plan do |report|
if Gitlab::CurrentSettings.current_application_settings.try(:should_check_namespace_plan?)
report.user.namespace&.actual_plan&.title
end
end
+
expose :verification_state do
expose :email do |report|
report.user.confirmed?
@@ -30,6 +34,7 @@ module Admin
report.user.credit_card_validation.present?
end
end
+
expose :credit_card, if: ->(report) { report.user.credit_card_validation&.holder_name } do
expose :name do |report|
report.user.credit_card_validation.holder_name
@@ -41,55 +46,38 @@ module Admin
card_match_admin_user_path(report.user) if Gitlab.ee?
end
end
- expose :other_reports do |report|
- AbuseReportEntity.represent(report.other_reports_for_user, only: [:created_at, :category, :report_path])
+
+ expose :past_closed_reports do |report|
+ AbuseReportEntity.represent(report.past_closed_reports_for_user, only: [:created_at, :category, :report_path])
+ end
+
+ expose :similar_open_reports, if: ->(report) { report.open? } do |report|
+ ReportedContentEntity.represent(report.similar_open_reports_for_user)
end
+
expose :most_used_ip do |report|
AuthenticationEvent.most_used_ip_address_for_user(report.user)
end
+
expose :last_sign_in_ip do |report|
report.user.last_sign_in_ip
end
+
expose :snippets_count do |report|
report.user.snippets.count
end
+
expose :groups_count do |report|
report.user.groups.count
end
+
expose :notes_count do |report|
report.user.notes.count
end
end
- expose :reporter, if: ->(report) { report.reporter } do
- expose :details, merge: true do |report|
- UserEntity.represent(report.reporter, only: [:name, :username, :avatar_url])
- end
- expose :path do |report|
- user_path(report.reporter)
- end
- end
-
- expose :report do
- expose :status
- expose :message
- expose :created_at, as: :reported_at
- expose :category
- expose :report_type, as: :type
- expose :reported_content, as: :content
- expose :reported_from_url, as: :url
- expose :screenshot_path, as: :screenshot
-
- # Kept for backwards compatibility.
- # TODO: See https://gitlab.com/gitlab-org/modelops/anti-abuse/team-tasks/-/issues/167?work_item_iid=443
- # In 16.4 remove or re-use this field after frontend has migrated to using moderate_user_path
- expose :update_path do |report|
- admin_abuse_report_path(report)
- end
-
- expose :moderate_user_path do |report|
- moderate_user_admin_abuse_report_path(report)
- end
+ expose :report do |report|
+ ReportedContentEntity.represent(report)
end
end
end
diff --git a/app/serializers/admin/abuse_report_entity.rb b/app/serializers/admin/abuse_report_entity.rb
index 22395a2fe91..f8bd851cd1e 100644
--- a/app/serializers/admin/abuse_report_entity.rb
+++ b/app/serializers/admin/abuse_report_entity.rb
@@ -8,6 +8,7 @@ module Admin
expose :created_at
expose :updated_at
expose :count
+ expose :labels, using: LabelEntity, if: ->(*) { Feature.enabled?(:abuse_report_labels) }
expose :reported_user do |report|
UserEntity.represent(report.user, only: [:name])
diff --git a/app/serializers/admin/reported_content_entity.rb b/app/serializers/admin/reported_content_entity.rb
new file mode 100644
index 00000000000..bf690647672
--- /dev/null
+++ b/app/serializers/admin/reported_content_entity.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Admin
+ class ReportedContentEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id
+ expose :global_id do |report|
+ Gitlab::GlobalId.build(report, id: report.id).to_s
+ end
+ expose :status
+ expose :message
+ expose :created_at, as: :reported_at
+ expose :category
+ expose :report_type, as: :type
+ expose :reported_content, as: :content
+ expose :reported_from_url, as: :url
+ expose :screenshot_path, as: :screenshot
+
+ expose :reporter, if: ->(report) { report.reporter } do
+ expose :details, merge: true do |report|
+ UserEntity.represent(report.reporter, only: [:name, :username, :avatar_url])
+ end
+
+ expose :path do |report|
+ user_path(report.reporter)
+ end
+ end
+
+ expose :update_path do |report|
+ admin_abuse_report_path(report)
+ end
+
+ expose :moderate_user_path do |report|
+ moderate_user_admin_abuse_report_path(report)
+ end
+ end
+end
diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb
index a34f329e9ec..741643f7989 100644
--- a/app/serializers/build_details_entity.rb
+++ b/app/serializers/build_details_entity.rb
@@ -57,6 +57,10 @@ class BuildDetailsEntity < Ci::JobEntity
using: JobArtifactReportEntity,
if: -> (*) { can?(current_user, :read_build, build) }
+ expose :job_annotations,
+ as: :annotations,
+ using: Ci::JobAnnotationEntity
+
expose :erased_by, if: -> (*) { build.erased? }, using: UserEntity
expose :erase_path, if: -> (*) { build.erasable? && can?(current_user, :erase_build, build) } do |build|
erase_project_job_path(project, build)
diff --git a/app/serializers/ci/job_annotation_entity.rb b/app/serializers/ci/job_annotation_entity.rb
new file mode 100644
index 00000000000..8d7b2e21460
--- /dev/null
+++ b/app/serializers/ci/job_annotation_entity.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module Ci
+ class JobAnnotationEntity < Grape::Entity
+ expose :name
+ expose :data
+ end
+end
diff --git a/app/serializers/codequality_degradation_entity.rb b/app/serializers/codequality_degradation_entity.rb
index 15a26739c51..9f90a30bd2d 100644
--- a/app/serializers/codequality_degradation_entity.rb
+++ b/app/serializers/codequality_degradation_entity.rb
@@ -2,6 +2,9 @@
class CodequalityDegradationEntity < Grape::Entity
expose :description
+ expose :fingerprint, if: ->(_, options) do
+ Feature.enabled?(:sast_reports_in_inline_diff, options[:request]&.project)
+ end
expose :severity do |degradation|
degradation.dig(:severity)&.downcase
end
diff --git a/app/serializers/issue_serializer.rb b/app/serializers/issue_serializer.rb
index 0fa76f098cd..b459997cc69 100644
--- a/app/serializers/issue_serializer.rb
+++ b/app/serializers/issue_serializer.rb
@@ -5,18 +5,23 @@ class IssueSerializer < BaseSerializer
# to serialize the `issue` based on `serializer` key in `opts` param.
# Hence, `entity` doesn't need to be declared on the class scope.
def represent(issue, opts = {})
- entity =
- case opts[:serializer]
- when 'sidebar'
- IssueSidebarBasicEntity
- when 'sidebar_extras'
- IssueSidebarExtrasEntity
- when 'board'
- IssueBoardEntity
- else
- IssueEntity
- end
+ entity = choose_entity(opts)
super(issue, opts, entity)
end
+
+ def choose_entity(opts)
+ case opts[:serializer]
+ when 'sidebar'
+ IssueSidebarBasicEntity
+ when 'sidebar_extras'
+ IssueSidebarExtrasEntity
+ when 'board'
+ IssueBoardEntity
+ else
+ IssueEntity
+ end
+ end
end
+
+IssueSerializer.prepend_mod_with('IssueSerializer')
diff --git a/app/serializers/pipeline_serializer.rb b/app/serializers/pipeline_serializer.rb
index b738438a78f..a3e842d348e 100644
--- a/app/serializers/pipeline_serializer.rb
+++ b/app/serializers/pipeline_serializer.rb
@@ -50,7 +50,7 @@ class PipelineSerializer < BaseSerializer
{
manual_actions: :metadata,
scheduled_actions: :metadata,
- failed_builds: %i(project metadata),
+ failed_builds: %i[project metadata],
merge_request: {
source_project: [:route, { namespace: :route }],
target_project: [:route, { namespace: :route }]
diff --git a/app/serializers/profile/event_entity.rb b/app/serializers/profile/event_entity.rb
index f3c1a927084..93c5be32de3 100644
--- a/app/serializers/profile/event_entity.rb
+++ b/app/serializers/profile/event_entity.rb
@@ -47,23 +47,26 @@ module Profile
end
end
- expose :target, if: ->(event) { event.target && event.visible_to_user?(current_user) } do
- expose(:id) { |event| event.target.id }
+ expose :target, if: ->(event) { event.visible_to_user?(current_user) } do
expose(:target_type, as: :type)
- expose(:target_title, as: :title)
- expose(:issue_type, if: ->(event) { event.work_item? || event.issue? }) do |event|
- event.target.issue_type
- end
- expose :reference_link_text, if: ->(event) { event.target.respond_to?(:reference_link_text) } do |event|
- event.target.reference_link_text
- end
+ with_options if: ->(event) { event.target } do
+ expose(:id) { |event| event.target.id }
+ expose(:target_title, as: :title)
+ expose(:issue_type, if: ->(event) { event.work_item? || event.issue? }) do |event|
+ event.target.issue_type
+ end
+
+ expose :reference_link_text, if: ->(event) { event.target.respond_to?(:reference_link_text) } do |event|
+ event.target.reference_link_text
+ end
- expose :web_url do |event|
- if event.wiki_page?
- event_wiki_page_target_url(event)
- else
- Gitlab::UrlBuilder.build(event.target)
+ expose :web_url do |event|
+ if event.wiki_page?
+ event_wiki_page_target_url(event)
+ else
+ Gitlab::UrlBuilder.build(event.target)
+ end
end
end
end
diff --git a/app/services/admin/abuse_report_labels/create_service.rb b/app/services/admin/abuse_report_labels/create_service.rb
new file mode 100644
index 00000000000..937890a9f51
--- /dev/null
+++ b/app/services/admin/abuse_report_labels/create_service.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Admin
+ module AbuseReportLabels
+ class CreateService < Labels::BaseService
+ def initialize(params = {})
+ @params = params
+ end
+
+ def execute
+ params[:color] = convert_color_name_to_hex if params[:color].present?
+
+ ::Admin::AbuseReportLabel.create(params)
+ end
+ end
+ end
+end
diff --git a/app/services/admin/abuse_reports/moderate_user_service.rb b/app/services/admin/abuse_reports/moderate_user_service.rb
index da61a4dc8f6..823568d9db8 100644
--- a/app/services/admin/abuse_reports/moderate_user_service.rb
+++ b/app/services/admin/abuse_reports/moderate_user_service.rb
@@ -61,10 +61,17 @@ module Admin
def close_report
return error('Report already closed') if abuse_report.closed?
+ close_similar_open_reports
abuse_report.closed!
success
end
+ def close_similar_open_reports
+ # admins see the abuse report and other open reports for the same user in one page
+ # hence, if the request is to close the report, close other open reports for the same user too
+ abuse_report.similar_open_reports_for_user.update_all(status: 'closed')
+ end
+
def close_report_and_record_event
event = action
diff --git a/app/services/admin/abuse_reports/update_service.rb b/app/services/admin/abuse_reports/update_service.rb
new file mode 100644
index 00000000000..36992e1aa25
--- /dev/null
+++ b/app/services/admin/abuse_reports/update_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Admin
+ module AbuseReports
+ class UpdateService < BaseService
+ attr_reader :abuse_report, :params, :current_user
+
+ def initialize(abuse_report, current_user, params)
+ @abuse_report = abuse_report
+ @current_user = current_user
+ @params = params
+ end
+
+ def execute
+ return ServiceResponse.error(message: 'Admin is required') unless current_user&.can_admin_all_resources?
+
+ abuse_report.label_ids = label_ids
+
+ ServiceResponse.success
+ end
+
+ private
+
+ def label_ids
+ params[:label_ids].filter_map do |id|
+ GitlabSchema.parse_gid(id, expected_type: ::Admin::AbuseReportLabel).model_id
+ rescue Gitlab::Graphql::Errors::ArgumentError
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/application_settings/update_service.rb b/app/services/application_settings/update_service.rb
index 6d484c4fa22..a46ecc3eee6 100644
--- a/app/services/application_settings/update_service.rb
+++ b/app/services/application_settings/update_service.rb
@@ -6,7 +6,7 @@ module ApplicationSettings
attr_reader :params, :application_setting
- MARKDOWN_CACHE_INVALIDATING_PARAMS = %w(asset_proxy_enabled asset_proxy_url asset_proxy_secret_key asset_proxy_whitelist).freeze
+ MARKDOWN_CACHE_INVALIDATING_PARAMS = %w[asset_proxy_enabled asset_proxy_url asset_proxy_secret_key asset_proxy_whitelist].freeze
def execute
result = update_settings
diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb
index eaee5ce70fc..9b010272995 100644
--- a/app/services/auth/container_registry_authentication_service.rb
+++ b/app/services/auth/container_registry_authentication_service.rb
@@ -39,11 +39,11 @@ module Auth
end
def self.full_access_token(*names)
- access_token(%w(*), names)
+ access_token(%w[*], names)
end
def self.import_access_token
- access_token(%w(*), ['import'], 'registry')
+ access_token(%w[*], ['import'], 'registry')
end
def self.pull_access_token(*names)
diff --git a/app/services/auto_merge/base_service.rb b/app/services/auto_merge/base_service.rb
index 1660ddb934f..77ed0369624 100644
--- a/app/services/auto_merge/base_service.rb
+++ b/app/services/auto_merge/base_service.rb
@@ -20,6 +20,10 @@ module AutoMerge
:failed
end
+ def process(_)
+ raise NotImplementedError
+ end
+
def update(merge_request)
assign_allowed_merge_params(merge_request, params.merge(auto_merge_strategy: strategy))
@@ -87,16 +91,21 @@ module AutoMerge
merge_request.auto_merge_enabled = false
merge_request.merge_user = nil
- merge_request.merge_params&.except!(
- 'should_remove_source_branch',
- 'commit_message',
- 'squash_commit_message',
- 'auto_merge_strategy'
- )
+ merge_request.merge_params&.except!(*clearable_auto_merge_parameters)
merge_request.save!
end
+ # Overridden in EE child classes
+ def clearable_auto_merge_parameters
+ %w[
+ should_remove_source_branch
+ commit_message
+ squash_commit_message
+ auto_merge_strategy
+ ]
+ end
+
def track_exception(error, merge_request)
Gitlab::ErrorTracking.track_exception(error, merge_request_id: merge_request&.id)
end
diff --git a/app/services/boards/update_service.rb b/app/services/boards/update_service.rb
index 6ba8f68a4cb..c702398e89e 100644
--- a/app/services/boards/update_service.rb
+++ b/app/services/boards/update_service.rb
@@ -2,7 +2,7 @@
module Boards
class UpdateService < Boards::BaseService
- PERMITTED_PARAMS = %i(name hide_backlog_list hide_closed_list).freeze
+ PERMITTED_PARAMS = %i[name hide_backlog_list hide_closed_list].freeze
def execute(board)
filter_params
diff --git a/app/services/bulk_imports/create_pipeline_trackers_service.rb b/app/services/bulk_imports/create_pipeline_trackers_service.rb
deleted file mode 100644
index 7fa62e0ce8a..00000000000
--- a/app/services/bulk_imports/create_pipeline_trackers_service.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# frozen_string_literal: true
-
-module BulkImports
- class CreatePipelineTrackersService
- def initialize(entity)
- @entity = entity
- end
-
- def execute!
- entity.class.transaction do
- entity.pipelines.each do |pipeline|
- status = skip_pipeline?(pipeline) ? -2 : 0
-
- entity.trackers.create!(
- stage: pipeline[:stage],
- pipeline_name: pipeline[:pipeline],
- status: status
- )
- end
- end
- end
-
- private
-
- attr_reader :entity
-
- def skip_pipeline?(pipeline)
- return false unless source_version.valid?
-
- minimum_version, maximum_version = pipeline.values_at(:minimum_source_version, :maximum_source_version)
-
- if minimum_version && non_patch_source_version < Gitlab::VersionInfo.parse(minimum_version)
- log_skipped_pipeline(pipeline, minimum_version, maximum_version)
- return true
- end
-
- if maximum_version && non_patch_source_version > Gitlab::VersionInfo.parse(maximum_version)
- log_skipped_pipeline(pipeline, minimum_version, maximum_version)
- return true
- end
-
- false
- end
-
- def source_version
- @source_version ||= entity.bulk_import.source_version_info
- end
-
- def non_patch_source_version
- source_version.without_patch
- end
-
- def log_skipped_pipeline(pipeline, minimum_version, maximum_version)
- logger.info(
- message: 'Pipeline skipped as source instance version not compatible with pipeline',
- bulk_import_entity_id: entity.id,
- bulk_import_id: entity.bulk_import_id,
- bulk_import_entity_type: entity.source_type,
- source_full_path: entity.source_full_path,
- pipeline_name: pipeline[:pipeline],
- minimum_source_version: minimum_version,
- maximum_source_version: maximum_version,
- source_version: source_version.to_s,
- importer: 'gitlab_migration'
- )
- end
-
- def logger
- @logger ||= Gitlab::Import::Logger.build
- end
- end
-end
diff --git a/app/services/bulk_imports/create_service.rb b/app/services/bulk_imports/create_service.rb
index 7fc3511a253..d58620eb089 100644
--- a/app/services/bulk_imports/create_service.rb
+++ b/app/services/bulk_imports/create_service.rb
@@ -118,11 +118,6 @@ module BulkImports
end
client.get("/#{entity_type}/#{source_entity_identifier}/export_relations/status")
- rescue BulkImports::NetworkError => e
- # the source instance will return a 404 if the feature is disabled as the endpoint won't be available
- return if e.cause.is_a?(Gitlab::HTTP::BlockedUrlError)
-
- raise ::BulkImports::Error.setting_not_enabled
end
def track_access_level(entity_params)
diff --git a/app/services/bulk_imports/file_download_service.rb b/app/services/bulk_imports/file_download_service.rb
index 48adb90fb4c..1f2437d783d 100644
--- a/app/services/bulk_imports/file_download_service.rb
+++ b/app/services/bulk_imports/file_download_service.rb
@@ -15,7 +15,7 @@ module BulkImports
ServiceError = Class.new(StandardError)
- DEFAULT_ALLOWED_CONTENT_TYPES = %w(application/gzip application/octet-stream).freeze
+ DEFAULT_ALLOWED_CONTENT_TYPES = %w[application/gzip application/octet-stream].freeze
def initialize(
configuration:,
@@ -83,6 +83,8 @@ module BulkImports
end
def raise_error(message)
+ logger.warn(message: message, response_headers: response_headers, importer: 'gitlab_migration')
+
raise ServiceError, message
end
@@ -109,12 +111,16 @@ module BulkImports
@filename.presence || remote_filename
end
+ def logger
+ @logger ||= Gitlab::Import::Logger.build
+ end
+
def validate_url
::Gitlab::UrlBlocker.validate!(
http_client.resource_url(relative_url),
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- schemes: %w(http https)
+ schemes: %w[http https]
)
end
diff --git a/app/services/ci/create_commit_status_service.rb b/app/services/ci/create_commit_status_service.rb
new file mode 100644
index 00000000000..e5b446a07e2
--- /dev/null
+++ b/app/services/ci/create_commit_status_service.rb
@@ -0,0 +1,158 @@
+# frozen_string_literal: true
+
+module Ci
+ class CreateCommitStatusService < BaseService
+ include ::Gitlab::ExclusiveLeaseHelpers
+ include ::Gitlab::Utils::StrongMemoize
+ include ::Services::ReturnServiceResponses
+
+ delegate :sha, to: :commit
+
+ def execute(optional_commit_status_params:)
+ in_lock(pipeline_lock_key, **pipeline_lock_params) do
+ @optional_commit_status_params = optional_commit_status_params
+ unsafe_execute
+ end
+ end
+
+ private
+
+ attr_reader :pipeline, :stage, :commit_status, :optional_commit_status_params
+
+ def unsafe_execute
+ return not_found('Commit') if commit.blank?
+ return bad_request('State is required') if params[:state].blank?
+ return not_found('References for commit') if ref.blank?
+
+ @pipeline = first_matching_pipeline || create_pipeline
+ return forbidden unless ::Ability.allowed?(current_user, :update_pipeline, pipeline)
+
+ @stage = find_or_create_external_stage
+ @commit_status = find_or_build_external_commit_status
+
+ return bad_request(commit_status.errors.messages) if commit_status.invalid?
+
+ response = add_or_update_external_job
+
+ return bad_request(response.message) if response.error?
+
+ update_merge_request_head_pipeline
+ response
+ end
+
+ def ref
+ params[:ref] || first_matching_pipeline&.ref ||
+ repository.branch_names_contains(sha).first
+ end
+ strong_memoize_attr :ref
+
+ def commit
+ project.commit(params[:sha])
+ end
+ strong_memoize_attr :commit
+
+ def first_matching_pipeline
+ pipelines = project.ci_pipelines.newest_first(sha: sha)
+ pipelines = pipelines.for_ref(params[:ref]) if params[:ref]
+ pipelines = pipelines.id_in(params[:pipeline_id]) if params[:pipeline_id]
+ pipelines.first
+ end
+ strong_memoize_attr :first_matching_pipeline
+
+ def name
+ params[:name] || params[:context] || 'default'
+ end
+
+ def create_pipeline
+ project.ci_pipelines.build(
+ source: :external,
+ sha: sha,
+ ref: ref,
+ user: current_user,
+ protected: project.protected_for?(ref)
+ ).tap do |new_pipeline|
+ new_pipeline.ensure_project_iid!
+ new_pipeline.save!
+ end
+ end
+
+ def find_or_create_external_stage
+ pipeline.stages.safe_find_or_create_by!(name: 'external') do |stage| # rubocop:disable Performance/ActiveRecordSubtransactionMethods
+ stage.position = ::GenericCommitStatus::EXTERNAL_STAGE_IDX
+ stage.project = project
+ end
+ end
+
+ def find_or_build_external_commit_status
+ ::GenericCommitStatus.running_or_pending.find_or_initialize_by( # rubocop:disable CodeReuse/ActiveRecord
+ project: project,
+ pipeline: pipeline,
+ name: name,
+ ref: ref,
+ user: current_user,
+ protected: project.protected_for?(ref),
+ ci_stage: stage,
+ stage_idx: stage.position,
+ stage: 'external'
+ ).tap do |new_commit_status|
+ new_commit_status.assign_attributes(optional_commit_status_params)
+ end
+ end
+
+ def add_or_update_external_job
+ ::Ci::Pipelines::AddJobService.new(pipeline).execute!(commit_status) do |job|
+ apply_job_state!(job)
+ end
+ end
+
+ def update_merge_request_head_pipeline
+ return unless pipeline.latest?
+
+ ::MergeRequest
+ .from_project(project).from_source_branches(ref)
+ .update_all(head_pipeline_id: pipeline.id)
+ end
+
+ def apply_job_state!(job)
+ case params[:state]
+ when 'pending'
+ job.enqueue!
+ when 'running'
+ job.enqueue
+ job.run!
+ when 'success'
+ job.success!
+ when 'failed'
+ job.drop!(:api_failure)
+ when 'canceled'
+ job.cancel!
+ else
+ raise('invalid state')
+ end
+ end
+
+ def pipeline_lock_key
+ "api:commit_statuses:project:#{project.id}:sha:#{params[:sha]}"
+ end
+
+ def pipeline_lock_params
+ {
+ ttl: 5.seconds,
+ sleep_sec: 0.1.seconds,
+ retries: 20
+ }
+ end
+
+ def not_found(message)
+ error("404 #{message} Not Found", :not_found)
+ end
+
+ def bad_request(message)
+ error(message, :bad_request)
+ end
+
+ def forbidden
+ error("403 Forbidden", :forbidden)
+ end
+ end
+end
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index fe0e842f542..2231b1dd6bd 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -154,13 +154,6 @@ module Ci
duration >= LOG_MAX_CREATION_THRESHOLD
end
-
- l.log_when do |observations|
- pipeline_includes_count = observations['pipeline_includes_count']
- next false unless pipeline_includes_count
-
- pipeline_includes_count.to_i > Gitlab::Ci::Config::External::Context::TEMP_MAX_INCLUDES
- end
end
end
end
diff --git a/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb b/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb
index 953432a9dd3..05cd20a152b 100644
--- a/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb
+++ b/app/services/ci/pipeline_creation/cancel_redundant_pipelines_service.rb
@@ -105,11 +105,7 @@ module Ci
end
def pipelines_created_after
- if Feature.enabled?(:lower_interval_for_canceling_redundant_pipelines, project)
- 3.days.ago
- else
- 1.week.ago
- end
+ 3.days.ago
end
# Finding the pipelines to cancel is an expensive task that is not well
diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb
index 68ebb376ccd..470a1d3951b 100644
--- a/app/services/ci/register_job_service.rb
+++ b/app/services/ci/register_job_service.rb
@@ -10,7 +10,7 @@ module Ci
TEMPORARY_LOCK_TIMEOUT = 3.seconds
- Result = Struct.new(:build, :build_json, :valid?)
+ Result = Struct.new(:build, :build_json, :build_presented, :valid?)
##
# The queue depth limit number has been determined by observing 95
@@ -25,8 +25,8 @@ module Ci
end
def execute(params = {})
- db_all_caught_up =
- ::Ci::Runner.sticking.all_caught_up?(:runner, runner.id)
+ replica_caught_up =
+ ::Ci::Runner.sticking.find_caught_up_replica(:runner, runner.id, use_primary_on_failure: false)
@metrics.increment_queue_operation(:queue_attempt)
@@ -40,10 +40,10 @@ module Ci
# we might still have some CI builds to be picked. Instead we should say to runner:
# "Hi, we don't have any more builds now, but not everything is right anyway, so try again".
# Runner will retry, but again, against replica, and again will check if replication lag did catch-up.
- if !db_all_caught_up && !result.build
+ if !replica_caught_up && !result.build
metrics.increment_queue_operation(:queue_replication_lag)
- ::Ci::RegisterJobService::Result.new(nil, nil, false) # rubocop:disable Cop/AvoidReturnFromBlocks
+ ::Ci::RegisterJobService::Result.new(nil, nil, nil, false) # rubocop:disable Cop/AvoidReturnFromBlocks
else
result
end
@@ -86,7 +86,7 @@ module Ci
next unless result
if result.valid?
- @metrics.register_success(result.build)
+ @metrics.register_success(result.build_presented)
@metrics.observe_queue_depth(:found, depth)
return result # rubocop:disable Cop/AvoidReturnFromBlocks
@@ -102,7 +102,7 @@ module Ci
@metrics.observe_queue_depth(:not_found, depth) if valid
@metrics.register_failure
- Result.new(nil, nil, valid)
+ Result.new(nil, nil, nil, valid)
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -159,7 +159,7 @@ module Ci
# this operation.
#
if ::Ci::UpdateBuildQueueService.new.remove!(build)
- return Result.new(nil, nil, false)
+ return Result.new(nil, nil, nil, false)
end
return
@@ -190,11 +190,11 @@ module Ci
# to make sure that this is properly handled by runner.
@metrics.increment_queue_operation(:build_conflict_lock)
- Result.new(nil, nil, false)
+ Result.new(nil, nil, nil, false)
rescue StateMachines::InvalidTransition
@metrics.increment_queue_operation(:build_conflict_transition)
- Result.new(nil, nil, false)
+ Result.new(nil, nil, nil, false)
rescue StandardError => ex
@metrics.increment_queue_operation(:build_conflict_exception)
@@ -221,7 +221,7 @@ module Ci
log_build_dependencies_size(presented_build)
build_json = Gitlab::Json.dump(::API::Entities::Ci::JobRequest::Response.new(presented_build))
- Result.new(build, build_json, true)
+ Result.new(build, build_json, presented_build, true)
end
def log_build_dependencies_size(presented_build)
diff --git a/app/services/ci/update_instance_variables_service.rb b/app/services/ci/update_instance_variables_service.rb
index ee513647d08..2f941118a1c 100644
--- a/app/services/ci/update_instance_variables_service.rb
+++ b/app/services/ci/update_instance_variables_service.rb
@@ -5,7 +5,7 @@
module Ci
class UpdateInstanceVariablesService
- UNASSIGNABLE_KEYS = %w(id _destroy).freeze
+ UNASSIGNABLE_KEYS = %w[id _destroy].freeze
def initialize(params)
@params = params[:variables_attributes]
diff --git a/app/services/clusters/agent_tokens/track_usage_service.rb b/app/services/clusters/agent_tokens/track_usage_service.rb
index fdc79ac0f8b..18fe236c44d 100644
--- a/app/services/clusters/agent_tokens/track_usage_service.rb
+++ b/app/services/clusters/agent_tokens/track_usage_service.rb
@@ -4,7 +4,7 @@ module Clusters
module AgentTokens
class TrackUsageService
# The `UPDATE_USED_COLUMN_EVERY` defines how often the token DB entry can be updated
- UPDATE_USED_COLUMN_EVERY = (40.minutes..55.minutes).freeze
+ UPDATE_USED_COLUMN_EVERY = (40.minutes..55.minutes)
delegate :agent, to: :token
diff --git a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
index e87640f4c76..94781422686 100644
--- a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
+++ b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
@@ -137,9 +137,9 @@ module Clusters
name: Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME,
namespace: service_account_namespace,
rules: [{
- apiGroups: %w(serving.knative.dev),
- resources: %w(configurations configurationgenerations routes revisions revisionuids autoscalers services),
- verbs: %w(get list create update delete patch watch)
+ apiGroups: %w[serving.knative.dev],
+ resources: %w[configurations configurationgenerations routes revisions revisionuids autoscalers services],
+ verbs: %w[get list create update delete patch watch]
}]
).generate
end
@@ -159,9 +159,9 @@ module Clusters
name: Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_NAME,
namespace: service_account_namespace,
rules: [{
- apiGroups: %w(database.crossplane.io),
- resources: %w(postgresqlinstances),
- verbs: %w(get list create watch)
+ apiGroups: %w[database.crossplane.io],
+ resources: %w[postgresqlinstances],
+ verbs: %w[get list create watch]
}]
).generate
end
diff --git a/app/services/commits/create_service.rb b/app/services/commits/create_service.rb
index a498d39d34e..89370bd8abb 100644
--- a/app/services/commits/create_service.rb
+++ b/app/services/commits/create_service.rb
@@ -39,7 +39,12 @@ module Commits
Gitlab::Git::PreReceiveError,
Gitlab::Git::CommandError => ex
Gitlab::ErrorTracking.log_exception(ex)
- error(ex.message)
+
+ if Feature.enabled?(:errors_utf_8_encoding)
+ error(Gitlab::EncodingHelper.encode_utf8_no_detect(ex.message))
+ else
+ error(ex.message)
+ end
end
private
diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb
index 569b91de73e..b02cfea151d 100644
--- a/app/services/compare_service.rb
+++ b/app/services/compare_service.rb
@@ -17,9 +17,6 @@ class CompareService
return unless raw_compare && raw_compare.base && raw_compare.head
- Compare.new(raw_compare,
- start_project,
- base_sha: base_sha,
- straight: straight)
+ Compare.new(raw_compare, start_project, base_sha: base_sha, straight: straight)
end
end
diff --git a/app/services/concerns/alert_management/alert_processing.rb b/app/services/concerns/alert_management/alert_processing.rb
index 9fe82507edd..5d35658a2b3 100644
--- a/app/services/concerns/alert_management/alert_processing.rb
+++ b/app/services/concerns/alert_management/alert_processing.rb
@@ -36,7 +36,7 @@ module AlertManagement
SystemNoteService.log_resolving_alert(alert, alert_source)
if alert.resolve(incoming_payload.ends_at)
- SystemNoteService.change_alert_status(alert, User.alert_bot)
+ SystemNoteService.change_alert_status(alert, Users::Internal.alert_bot)
close_issue(alert.issue_id) if auto_close_incident?
end
diff --git a/app/services/concerns/rate_limited_service.rb b/app/services/concerns/rate_limited_service.rb
index fa366c1ccd0..79be952ac14 100644
--- a/app/services/concerns/rate_limited_service.rb
+++ b/app/services/concerns/rate_limited_service.rb
@@ -61,9 +61,11 @@ module RateLimitedService
cattr_accessor :rate_limiter_scoped_and_keyed
def self.rate_limit(key:, opts:, rate_limiter: ::Gitlab::ApplicationRateLimiter)
- self.rate_limiter_scoped_and_keyed = RateLimiterScopedAndKeyed.new(key: key,
- opts: opts,
- rate_limiter: rate_limiter)
+ self.rate_limiter_scoped_and_keyed = RateLimiterScopedAndKeyed.new(
+ key: key,
+ opts: opts,
+ rate_limiter: rate_limiter
+ )
end
end
diff --git a/app/services/concerns/service_desk/custom_emails/logger.rb b/app/services/concerns/service_desk/custom_emails/logger.rb
new file mode 100644
index 00000000000..1817933c3d0
--- /dev/null
+++ b/app/services/concerns/service_desk/custom_emails/logger.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module ServiceDesk
+ module CustomEmails
+ module Logger
+ private
+
+ def log_warning(error_message: nil)
+ with_context do
+ Gitlab::AppLogger.warn(build_log_message(error_message: error_message))
+ end
+ end
+
+ def log_info(error_message: nil, project: nil)
+ with_context(project: project) do
+ Gitlab::AppLogger.info(build_log_message(error_message: error_message))
+ end
+ end
+
+ def with_context(project: nil, &block)
+ Gitlab::ApplicationContext.with_context(
+ related_class: self.class.to_s,
+ user: current_user,
+ project: project || self.project,
+ &block
+ )
+ end
+
+ def log_category
+ 'custom_email'
+ end
+
+ def build_log_message(error_message: nil)
+ {
+ category: log_category,
+ error_message: error_message
+ }.compact
+ end
+ end
+ end
+end
diff --git a/app/services/concerns/update_repository_storage_methods.rb b/app/services/concerns/update_repository_storage_methods.rb
index dca38abf7af..f14c79ecd7e 100644
--- a/app/services/concerns/update_repository_storage_methods.rb
+++ b/app/services/concerns/update_repository_storage_methods.rb
@@ -69,7 +69,17 @@ module UpdateRepositoryStorageMethods
raise Error, s_('UpdateRepositoryStorage|Timeout waiting for %{type} repository pushes') % { type: type.name }
end
- repository = type.repository_for(container)
+ # `Projects::UpdateRepositoryStorageService`` expects the repository it is
+ # moving to have a `Project` as a container.
+ # This hack allows design repos to also be moved as part of a project move
+ # as before.
+ # The alternative to this hack is to setup a service like
+ # `Snippets::UpdateRepositoryStorageService' and a corresponding worker like
+ # `Snippets::UpdateRepositoryStorageWorker` for snippets.
+ #
+ # Gitlab issue: https://gitlab.com/gitlab-org/gitlab/-/issues/423429
+
+ repository = type.repository_for(type.design? ? container.design_management_repository : container)
full_path = repository.full_path
raw_repository = repository.raw
checksum = repository.checksum
diff --git a/app/services/design_management/copy_design_collection/copy_service.rb b/app/services/design_management/copy_design_collection/copy_service.rb
index 8074a193bbf..d391c13696f 100644
--- a/app/services/design_management/copy_design_collection/copy_service.rb
+++ b/app/services/design_management/copy_design_collection/copy_service.rb
@@ -58,8 +58,8 @@ module DesignManagement
private
attr_reader :designs, :event_enum_map, :git_user, :sha_attribute, :shas,
- :temporary_branch, :target_design_collection, :target_issue,
- :target_repository, :target_project, :versions
+ :temporary_branch, :target_design_collection, :target_issue,
+ :target_repository, :target_project, :versions
alias_method :merge_branch, :target_branch
diff --git a/app/services/design_management/delete_designs_service.rb b/app/services/design_management/delete_designs_service.rb
index 921c904d8de..a6a0f5e0252 100644
--- a/app/services/design_management/delete_designs_service.rb
+++ b/app/services/design_management/delete_designs_service.rb
@@ -16,8 +16,10 @@ module DesignManagement
version = delete_designs!
EventCreateService.new.destroy_designs(designs, current_user)
- Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_designs_removed_action(author: current_user,
- project: project)
+ Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_designs_removed_action(
+ author: current_user,
+ project: project
+ )
TodosDestroyer::DestroyedDesignsWorker.perform_async(designs.map(&:id))
success(version: version)
diff --git a/app/services/design_management/runs_design_actions.rb b/app/services/design_management/runs_design_actions.rb
index 267ed6bf29f..62db7824592 100644
--- a/app/services/design_management/runs_design_actions.rb
+++ b/app/services/design_management/runs_design_actions.rb
@@ -15,10 +15,12 @@ module DesignManagement
def run_actions(actions, skip_system_notes: false)
raise NoActions if actions.empty?
- sha = repository.commit_files(current_user,
- branch_name: target_branch,
- message: commit_message,
- actions: actions.map(&:gitaly_action))
+ sha = repository.commit_files(
+ current_user,
+ branch_name: target_branch,
+ message: commit_message,
+ actions: actions.map(&:gitaly_action)
+ )
::DesignManagement::Version
.create_for_designs(actions, sha, current_user)
diff --git a/app/services/design_management/save_designs_service.rb b/app/services/design_management/save_designs_service.rb
index ea5675c6ddd..4c4e34862e8 100644
--- a/app/services/design_management/save_designs_service.rb
+++ b/app/services/design_management/save_designs_service.rb
@@ -131,11 +131,11 @@ module DesignManagement
def track_usage_metrics(action)
if action == :update
- ::Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_designs_modified_action(author: current_user,
- project: project)
+ ::Gitlab::UsageDataCounters::IssueActivityUniqueCounter
+ .track_issue_designs_modified_action(author: current_user, project: project)
else
- ::Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_designs_added_action(author: current_user,
- project: project)
+ ::Gitlab::UsageDataCounters::IssueActivityUniqueCounter
+ .track_issue_designs_added_action(author: current_user, project: project)
end
::Gitlab::UsageDataCounters::DesignsCounter.count(action)
diff --git a/app/services/error_tracking/base_service.rb b/app/services/error_tracking/base_service.rb
index 8458eb1f3b8..e95d4eec3c8 100644
--- a/app/services/error_tracking/base_service.rb
+++ b/app/services/error_tracking/base_service.rb
@@ -17,8 +17,7 @@ module ErrorTracking
private
def perform
- raise NotImplementedError,
- "#{self.class} does not implement #{__method__}"
+ raise NotImplementedError, "#{self.class} does not implement #{__method__}"
end
def compose_response(response, &block)
@@ -33,8 +32,7 @@ module ErrorTracking
end
def parse_response(response)
- raise NotImplementedError,
- "#{self.class} does not implement #{__method__}"
+ raise NotImplementedError, "#{self.class} does not implement #{__method__}"
end
def unauthorized
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index 1893cfcfcff..b755f512772 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -190,10 +190,14 @@ class EventCreateService
private
def create_record_event(record, current_user, status, fingerprint = nil)
- create_event(record.resource_parent, current_user, status,
- fingerprint: fingerprint,
- target_id: record.id,
- target_type: record.class.name)
+ create_event(
+ record.resource_parent,
+ current_user,
+ status,
+ fingerprint: fingerprint,
+ target_id: record.id,
+ target_type: record.class.name
+ )
end
# If creating several events, this method will insert them all in a single
diff --git a/app/services/feature_flags/base_service.rb b/app/services/feature_flags/base_service.rb
index 834409bf3c4..961e8d54efa 100644
--- a/app/services/feature_flags/base_service.rb
+++ b/app/services/feature_flags/base_service.rb
@@ -4,7 +4,7 @@ module FeatureFlags
class BaseService < ::BaseService
include Gitlab::Utils::StrongMemoize
- AUDITABLE_ATTRIBUTES = %w(name description active).freeze
+ AUDITABLE_ATTRIBUTES = %w[name description active].freeze
def success(**args)
sync_to_jira(args[:feature_flag])
diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb
index dd09ecafb4f..a7be73aa04c 100644
--- a/app/services/files/multi_service.rb
+++ b/app/services/files/multi_service.rb
@@ -2,7 +2,7 @@
module Files
class MultiService < Files::BaseService
- UPDATE_FILE_ACTIONS = %w(update move delete chmod).freeze
+ UPDATE_FILE_ACTIONS = %w[update move delete chmod].freeze
def create_commit!
transformer = Lfs::FileTransformer.new(project, repository, @branch_name)
diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb
index 9fa966bb8a8..c11917b92ec 100644
--- a/app/services/files/update_service.rb
+++ b/app/services/files/update_service.rb
@@ -3,15 +3,19 @@
module Files
class UpdateService < Files::BaseService
def create_commit!
- repository.update_file(current_user, @file_path, @file_content,
- message: @commit_message,
- branch_name: @branch_name,
- previous_path: @previous_path,
- author_email: @author_email,
- author_name: @author_name,
- start_project: @start_project,
- start_branch_name: @start_branch,
- execute_filemode: @execute_filemode)
+ repository.update_file(
+ current_user,
+ @file_path,
+ @file_content,
+ message: @commit_message,
+ branch_name: @branch_name,
+ previous_path: @previous_path,
+ author_email: @author_email,
+ author_name: @author_name,
+ start_project: @start_project,
+ start_branch_name: @start_branch,
+ execute_filemode: @execute_filemode
+ )
end
private
diff --git a/app/services/google_cloud/create_cloudsql_instance_service.rb b/app/services/google_cloud/create_cloudsql_instance_service.rb
index 8d040c6c908..9a1263f0796 100644
--- a/app/services/google_cloud/create_cloudsql_instance_service.rb
+++ b/app/services/google_cloud/create_cloudsql_instance_service.rb
@@ -17,26 +17,30 @@ module GoogleCloud
private
def create_cloud_instance
- google_api_client.create_cloudsql_instance(gcp_project_id,
- instance_name,
- root_password,
- database_version,
- region,
- tier)
+ google_api_client.create_cloudsql_instance(
+ gcp_project_id,
+ instance_name,
+ root_password,
+ database_version,
+ region,
+ tier
+ )
end
def trigger_instance_setup_worker
- GoogleCloud::CreateCloudsqlInstanceWorker.perform_in(WORKER_INTERVAL,
- current_user.id,
- project.id,
- {
- 'google_oauth2_token': google_oauth2_token,
- 'gcp_project_id': gcp_project_id,
- 'instance_name': instance_name,
- 'database_version': database_version,
- 'environment_name': environment_name,
- 'is_protected': protected?
- })
+ GoogleCloud::CreateCloudsqlInstanceWorker.perform_in(
+ WORKER_INTERVAL,
+ current_user.id,
+ project.id,
+ {
+ 'google_oauth2_token': google_oauth2_token,
+ 'gcp_project_id': gcp_project_id,
+ 'instance_name': instance_name,
+ 'database_version': database_version,
+ 'environment_name': environment_name,
+ 'is_protected': protected?
+ }
+ )
end
def protected?
diff --git a/app/services/google_cloud/fetch_google_ip_list_service.rb b/app/services/google_cloud/fetch_google_ip_list_service.rb
index f7739971603..54af841d002 100644
--- a/app/services/google_cloud/fetch_google_ip_list_service.rb
+++ b/app/services/google_cloud/fetch_google_ip_list_service.rb
@@ -18,9 +18,11 @@ module GoogleCloud
subnets = fetch_and_update_cache!
- Gitlab::AppJsonLogger.info(class: self.class.name,
- message: 'Successfully retrieved Google IP list',
- subnet_count: subnets.count)
+ Gitlab::AppJsonLogger.info(
+ class: self.class.name,
+ message: 'Successfully retrieved Google IP list',
+ subnet_count: subnets.count
+ )
success({ subnets: subnets })
rescue IpListNotRetrievedError => err
diff --git a/app/services/google_cloud/generate_pipeline_service.rb b/app/services/google_cloud/generate_pipeline_service.rb
index 95de1fa21b7..30c358687aa 100644
--- a/app/services/google_cloud/generate_pipeline_service.rb
+++ b/app/services/google_cloud/generate_pipeline_service.rb
@@ -71,8 +71,12 @@ module GoogleCloud
end
def pipeline_content(include_path)
- gitlab_ci_yml = ::Gitlab::Ci::Config::Yaml.load!(default_branch_gitlab_ci_yml || '{}')
- append_remote_include(gitlab_ci_yml, "https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library/-/raw/main/#{include_path}")
+ gitlab_ci_yml = ::Gitlab::Ci::Config::Yaml::Loader.new(default_branch_gitlab_ci_yml || '{}').load
+
+ append_remote_include(
+ gitlab_ci_yml.content,
+ "https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library/-/raw/main/#{include_path}"
+ )
end
def append_remote_include(gitlab_ci_yml, include_url)
diff --git a/app/services/gpg_keys/destroy_service.rb b/app/services/gpg_keys/destroy_service.rb
index 2e82509897e..c8ee90db9f6 100644
--- a/app/services/gpg_keys/destroy_service.rb
+++ b/app/services/gpg_keys/destroy_service.rb
@@ -2,9 +2,24 @@
module GpgKeys
class DestroyService < Keys::BaseService
+ BATCH_SIZE = 1000
+
def execute(key)
+ nullify_signatures(key)
key.destroy
end
+
+ private
+
+ # When a GPG key is deleted, the related signatures have their gpg_key_id column nullified
+ # However, when the number of signatures is large, then a timeout may happen
+ # The signatures are processed in batches before GPG key delete is attempted in order to
+ # avoid timeouts
+ def nullify_signatures(key)
+ key.gpg_signatures.each_batch(of: BATCH_SIZE) do |batch|
+ batch.update_all(gpg_key_id: nil)
+ end
+ end
end
end
diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb
index 0f74b2d9349..21d3c6499a0 100644
--- a/app/services/groups/create_service.rb
+++ b/app/services/groups/create_service.rb
@@ -35,10 +35,14 @@ module Groups
@group.build_chat_team(name: response['name'], team_id: response['id'])
end
- Group.transaction do
- if @group.save
- @group.add_owner(current_user)
- Integration.create_from_active_default_integrations(@group, :group_id)
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424281'
+ ) do
+ Group.transaction do
+ if @group.save
+ @group.add_owner(current_user)
+ Integration.create_from_active_default_integrations(@group, :group_id)
+ end
end
end
diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb
index 45e8972213e..a896ca5cabc 100644
--- a/app/services/groups/destroy_service.rb
+++ b/app/services/groups/destroy_service.rb
@@ -14,8 +14,6 @@ module Groups
# TODO - add a policy check here https://gitlab.com/gitlab-org/gitlab/-/issues/353082
raise DestroyError, "You can't delete this group because you're blocked." if current_user.blocked?
- group.prepare_for_destroy
-
group.projects.includes(:project_feature).each do |project|
# Execute the destruction of the models immediately to ensure atomic cleanup.
success = ::Projects::DestroyService.new(project, current_user).execute
@@ -83,7 +81,10 @@ module Groups
# rubocop:disable CodeReuse/ActiveRecord
def destroy_group_bots
- bot_ids = group.members_and_requesters.joins(:user).merge(User.project_bot).pluck(:user_id)
+ bot_ids = group.members_and_requesters.joins(:user)
+ .merge(User.project_bot)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422405')
+ .pluck(:user_id)
current_user_id = current_user.id
group.run_after_commit do
diff --git a/app/services/groups/ssh_certificates/create_service.rb b/app/services/groups/ssh_certificates/create_service.rb
new file mode 100644
index 00000000000..6890901c306
--- /dev/null
+++ b/app/services/groups/ssh_certificates/create_service.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Groups
+ module SshCertificates
+ class CreateService
+ def initialize(group, params)
+ @group = group
+ @params = params
+ end
+
+ def execute
+ key = params[:key]
+ fingerprint = generate_fingerprint(key)
+
+ return ServiceResponse.error(message: 'Group', reason: :forbidden) if group.has_parent?
+
+ # return a key error instead of fingerprint error, as the user has no knowledge of fingerprint.
+ unless fingerprint
+ return ServiceResponse.error(message: 'Validation failed: Invalid key',
+ reason: :unprocessable_entity)
+ end
+
+ result = group.ssh_certificates.create!(
+ key: key,
+ title: params[:title],
+ fingerprint: fingerprint
+ )
+
+ # title and key attributes are returned as [FILTERED]
+ # by config/application.rb#L181-233
+ # make attributes unfiltered by running find
+ ssh_certificate = group.ssh_certificates.find(result.id)
+ ServiceResponse.success(payload: ssh_certificate)
+
+ rescue ActiveRecord::RecordInvalid, ArgumentError => e
+ ServiceResponse.error(
+ message: e.message,
+ reason: :unprocessable_entity
+ )
+ end
+
+ private
+
+ attr_reader :group, :params
+
+ def generate_fingerprint(key)
+ Gitlab::SSHPublicKey.new(key).fingerprint_sha256&.delete_prefix('SHA256:')
+ end
+ end
+ end
+end
diff --git a/app/services/groups/ssh_certificates/destroy_service.rb b/app/services/groups/ssh_certificates/destroy_service.rb
new file mode 100644
index 00000000000..7a450d5bee6
--- /dev/null
+++ b/app/services/groups/ssh_certificates/destroy_service.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Groups
+ module SshCertificates
+ class DestroyService
+ def initialize(group, params)
+ @group = group
+ @params = params
+ end
+
+ def execute
+ ssh_certificate = group.ssh_certificates.find(params[:ssh_certificates_id])
+
+ ssh_certificate.destroy!
+ ServiceResponse.success
+
+ rescue ActiveRecord::RecordNotFound
+ ServiceResponse.error(
+ message: 'SSH Certificate not found',
+ reason: :not_found
+ )
+
+ rescue ActiveRecord::RecordNotDestroyed
+ ServiceResponse.error(
+ message: 'SSH Certificate could not be deleted',
+ reason: :method_not_allowed
+ )
+ end
+
+ private
+
+ attr_reader :group, :params
+ end
+ end
+end
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
index 64256e43ce3..6b979308d26 100644
--- a/app/services/groups/transfer_service.rb
+++ b/app/services/groups/transfer_service.rb
@@ -60,13 +60,17 @@ module Groups
old_root_ancestor_id = @group.root_ancestor.id
was_root_group = @group.root?
- Group.transaction do
- update_group_attributes
- ensure_ownership
- update_integrations
- remove_issue_contacts(old_root_ancestor_id, was_root_group)
- update_crm_objects(was_root_group)
- remove_namespace_commit_emails(was_root_group)
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424280'
+ ) do
+ Group.transaction do
+ update_group_attributes
+ ensure_ownership
+ update_integrations
+ remove_issue_contacts(old_root_ancestor_id, was_root_group)
+ update_crm_objects(was_root_group)
+ remove_namespace_commit_emails(was_root_group)
+ end
end
post_update_hooks(@updated_project_ids, old_root_ancestor_id)
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index 7d0142fc067..d91e09d212a 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -47,10 +47,6 @@ module Groups
private
def valid_path_change?
- unless Feature.enabled?(:npm_package_registry_fix_group_path_validation)
- return valid_path_change_with_npm_packages?
- end
-
return true unless group.packages_feature_enabled?
return true if params[:path].blank?
return true if group.has_parent?
@@ -68,21 +64,6 @@ module Groups
false
end
- # TODO: delete this function along with npm_package_registry_fix_group_path_validation
- def valid_path_change_with_npm_packages?
- return true unless group.packages_feature_enabled?
- return true if params[:path].blank?
- return true if !group.has_parent? && group.path == params[:path]
-
- npm_packages = ::Packages::GroupPackagesFinder.new(current_user, group, package_type: :npm).execute
- if npm_packages.exists?
- group.errors.add(:path, s_('GroupSettings|cannot change when group contains projects with NPM packages'))
- return
- end
-
- true
- end
-
def before_assignment_hook(group, params)
@full_path_before = group.full_path
@path_before = group.path
diff --git a/app/services/import/bitbucket_server_service.rb b/app/services/import/bitbucket_server_service.rb
index 5d496dc7cc3..3d961780889 100644
--- a/app/services/import/bitbucket_server_service.rb
+++ b/app/services/import/bitbucket_server_service.rb
@@ -83,7 +83,7 @@ module Import
url,
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- schemes: %w(http https)
+ schemes: %w[http https]
)
end
diff --git a/app/services/import/fogbugz_service.rb b/app/services/import/fogbugz_service.rb
index 9a8def43312..2f63e4e6fb7 100644
--- a/app/services/import/fogbugz_service.rb
+++ b/app/services/import/fogbugz_service.rb
@@ -88,7 +88,7 @@ module Import
url,
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- schemes: %w(http https)
+ schemes: %w[http https]
)
end
diff --git a/app/services/import/github/cancel_project_import_service.rb b/app/services/import/github/cancel_project_import_service.rb
index 62cd0c95eaf..740b9e5c2e7 100644
--- a/app/services/import/github/cancel_project_import_service.rb
+++ b/app/services/import/github/cancel_project_import_service.rb
@@ -7,13 +7,13 @@ module Import
return error('Not Found', :not_found) unless authorized_to_read?
return error('Unauthorized access', :forbidden) unless authorized_to_cancel?
- if project.import_in_progress?
+ if project.import_state.completed?
+ error(cannot_cancel_error_message, :bad_request)
+ else
project.import_state.cancel
metrics.track_canceled_import
success(project: project)
- else
- error(cannot_cancel_error_message, :bad_request)
end
end
diff --git a/app/services/import/github_service.rb b/app/services/import/github_service.rb
index df255a7ae24..73e0c229a9c 100644
--- a/app/services/import/github_service.rb
+++ b/app/services/import/github_service.rb
@@ -91,7 +91,7 @@ module Import
url,
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
- schemes: %w(http https)
+ schemes: %w[http https]
)
end
diff --git a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb
index e30818cc5d2..ed99d20d67f 100644
--- a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb
+++ b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file.rb
@@ -11,7 +11,7 @@ module Import
end
validates :file_url, addressable_url: {
- schemes: %w(https),
+ schemes: %w[https],
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
dns_rebind_protection: true
diff --git a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb
index 7599343d4e1..57ed717b966 100644
--- a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb
+++ b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb
@@ -13,7 +13,7 @@ module Import
validates_presence_of :region, :bucket_name, :file_key, :access_key_id, :secret_access_key
validates :file_url, addressable_url: {
- schemes: %w(https),
+ schemes: %w[https],
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
dns_rebind_protection: true
diff --git a/app/services/import/validate_remote_git_endpoint_service.rb b/app/services/import/validate_remote_git_endpoint_service.rb
index 2886bd5c9b7..a994072c4aa 100644
--- a/app/services/import/validate_remote_git_endpoint_service.rb
+++ b/app/services/import/validate_remote_git_endpoint_service.rb
@@ -8,7 +8,7 @@ module Import
GIT_SERVICE_NAME = "git-upload-pack"
GIT_EXPECTED_FIRST_PACKET_LINE = "# service=#{GIT_SERVICE_NAME}"
- GIT_BODY_MESSAGE_REGEXP = /^[0-9a-f]{4}#{GIT_EXPECTED_FIRST_PACKET_LINE}/.freeze
+ GIT_BODY_MESSAGE_REGEXP = /^[0-9a-f]{4}#{GIT_EXPECTED_FIRST_PACKET_LINE}/
# https://github.com/git/git/blob/master/Documentation/technical/protocol-common.txt#L56-L59
GIT_PROTOCOL_PKT_LEN = 4
GIT_MINIMUM_RESPONSE_LENGTH = GIT_PROTOCOL_PKT_LEN + GIT_EXPECTED_FIRST_PACKET_LINE.length
diff --git a/app/services/import_export_clean_up_service.rb b/app/services/import_export_clean_up_service.rb
index 567ac065cf7..5ee2f70ec4c 100644
--- a/app/services/import_export_clean_up_service.rb
+++ b/app/services/import_export_clean_up_service.rb
@@ -60,7 +60,7 @@ class ImportExportCleanUpService
end
def directories_cmd
- %W(find #{path} -mindepth #{DIR_DEPTH} -maxdepth #{DIR_DEPTH} -type d -not -path #{path} -mmin +#{mmin})
+ %W[find #{path} -mindepth #{DIR_DEPTH} -maxdepth #{DIR_DEPTH} -type d -not -path #{path} -mmin +#{mmin}]
end
def logger
diff --git a/app/services/incident_management/pager_duty/create_incident_issue_service.rb b/app/services/incident_management/pager_duty/create_incident_issue_service.rb
index 0c9ca2c0add..58c3a062910 100644
--- a/app/services/incident_management/pager_duty/create_incident_issue_service.rb
+++ b/app/services/incident_management/pager_duty/create_incident_issue_service.rb
@@ -6,7 +6,7 @@ module IncidentManagement
include IncidentManagement::Settings
def initialize(project, incident_payload)
- super(project, User.alert_bot, incident_payload)
+ super(project, Users::Internal.alert_bot, incident_payload)
end
def execute
diff --git a/app/services/incident_management/pager_duty/process_webhook_service.rb b/app/services/incident_management/pager_duty/process_webhook_service.rb
index 3ce2674616e..6f779bfdb18 100644
--- a/app/services/incident_management/pager_duty/process_webhook_service.rb
+++ b/app/services/incident_management/pager_duty/process_webhook_service.rb
@@ -10,7 +10,7 @@ module IncidentManagement
PAGER_DUTY_PAYLOAD_SIZE_LIMIT = 55.kilobytes
# https://developer.pagerduty.com/docs/db0fa8c8984fc-overview#event-types
- PAGER_DUTY_PROCESSABLE_EVENT_TYPES = %w(incident.triggered).freeze
+ PAGER_DUTY_PROCESSABLE_EVENT_TYPES = %w[incident.triggered].freeze
def initialize(project, payload)
super(project: project)
diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb
index 166452968f4..e996aecdf97 100644
--- a/app/services/issuable/bulk_update_service.rb
+++ b/app/services/issuable/bulk_update_service.rb
@@ -43,7 +43,7 @@ module Issuable
end
def permitted_attrs(type)
- attrs = %i(state_event milestone_id add_label_ids remove_label_ids subscription_event)
+ attrs = %i[state_event milestone_id add_label_ids remove_label_ids subscription_event]
if type == 'issue'
attrs.push(:assignee_ids, :confidential)
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 3b007d4dba7..27cfaef2db2 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -169,7 +169,7 @@ class IssuableBaseService < ::BaseContainerService
params[:incident_management_issuable_escalation_status_attributes] = result[:escalation_status]
end
- def process_label_ids(attributes, existing_label_ids: nil, extra_label_ids: [])
+ def process_label_ids(attributes, issuable:, existing_label_ids: nil, extra_label_ids: []) # rubocop:disable Lint/UnusedMethodArgument
label_ids = attributes.delete(:label_ids)
add_label_ids = attributes.delete(:add_label_ids)
remove_label_ids = attributes.delete(:remove_label_ids)
@@ -180,15 +180,29 @@ class IssuableBaseService < ::BaseContainerService
new_label_ids |= add_label_ids if add_label_ids
new_label_ids -= remove_label_ids if remove_label_ids
- new_label_ids.uniq
+ filter_locked_labels(issuable, new_label_ids.uniq, existing_label_ids)
+ end
+
+ # Filter out any locked labels that are attempting to be removed
+ def filter_locked_labels(issuable, ids, existing_label_ids)
+ return ids unless issuable.supports_lock_on_merge?
+ return ids unless existing_label_ids.present?
+
+ removed_label_ids = existing_label_ids - ids
+ removed_locked_label_ids = labels_service.filter_locked_label_ids(removed_label_ids)
+
+ ids + removed_locked_label_ids
end
def process_assignee_ids(attributes, existing_assignee_ids: nil, extra_assignee_ids: [])
- process = Issuable::ProcessAssignees.new(assignee_ids: attributes.delete(:assignee_ids),
- add_assignee_ids: attributes.delete(:add_assignee_ids),
- remove_assignee_ids: attributes.delete(:remove_assignee_ids),
- existing_assignee_ids: existing_assignee_ids,
- extra_assignee_ids: extra_assignee_ids)
+ process = Issuable::ProcessAssignees.new(
+ assignee_ids: attributes.delete(:assignee_ids),
+ add_assignee_ids: attributes.delete(:add_assignee_ids),
+ remove_assignee_ids: attributes.delete(:remove_assignee_ids),
+ existing_assignee_ids: existing_assignee_ids,
+ extra_assignee_ids: extra_assignee_ids
+ )
+
process.execute
end
@@ -221,7 +235,7 @@ class IssuableBaseService < ::BaseContainerService
params.delete(:state_event)
params[:author] ||= current_user
- params[:label_ids] = process_label_ids(params, extra_label_ids: issuable.label_ids.to_a)
+ params[:label_ids] = process_label_ids(params, issuable: issuable, extra_label_ids: issuable.label_ids.to_a)
if issuable.respond_to?(:assignee_ids)
params[:assignee_ids] = process_assignee_ids(params, extra_assignee_ids: issuable.assignee_ids.to_a)
@@ -373,9 +387,11 @@ class IssuableBaseService < ::BaseContainerService
filter_params(issuable)
if issuable.changed? || params.present?
- issuable.assign_attributes(params.merge(updated_by: current_user,
- last_edited_at: Time.current,
- last_edited_by: current_user))
+ issuable.assign_attributes(params.merge(
+ updated_by: current_user,
+ last_edited_at: Time.current,
+ last_edited_by: current_user
+ ))
before_update(issuable, skip_spam_check: true)
@@ -404,10 +420,13 @@ class IssuableBaseService < ::BaseContainerService
update_task_params = params.delete(:update_task)
return unless update_task_params
- tasklist_toggler = TaskListToggleService.new(issuable.description, issuable.description_html,
- line_source: update_task_params[:line_source],
- line_number: update_task_params[:line_number].to_i,
- toggle_as_checked: update_task_params[:checked])
+ tasklist_toggler = TaskListToggleService.new(
+ issuable.description,
+ issuable.description_html,
+ line_source: update_task_params[:line_source],
+ line_number: update_task_params[:line_number].to_i,
+ toggle_as_checked: update_task_params[:checked]
+ )
unless tasklist_toggler.execute
# if we make it here, the data is much newer than we thought it was - fail fast
@@ -469,7 +488,7 @@ class IssuableBaseService < ::BaseContainerService
# rubocop: enable CodeReuse/ActiveRecord
def assign_requested_labels(issuable)
- label_ids = process_label_ids(params, existing_label_ids: issuable.label_ids)
+ label_ids = process_label_ids(params, issuable: issuable, existing_label_ids: issuable.label_ids)
return unless ids_changing?(issuable.label_ids, label_ids)
params[:label_ids] = label_ids
diff --git a/app/services/issuable_links/create_service.rb b/app/services/issuable_links/create_service.rb
index 533e92f6225..761ba3f74aa 100644
--- a/app/services/issuable_links/create_service.rb
+++ b/app/services/issuable_links/create_service.rb
@@ -76,13 +76,13 @@ module IssuableLinks
target_issuables.map do |referenced_object|
link = relate_issuables(referenced_object)
- if link.valid?
- after_create_for(link)
- else
+ if link.errors.any?
@errors << _("%{ref} cannot be added: %{error}") % {
ref: referenced_object.to_reference,
error: link.errors.messages.values.flatten.to_sentence
}
+ else
+ after_create_for(link)
end
link
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index b9b7cd08b68..a5ae5854e33 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -21,7 +21,7 @@ module Issues
Issues::CloseService
end
- NO_REBALANCING_NEEDED = ((RelativePositioning::MIN_POSITION * 0.9999)..(RelativePositioning::MAX_POSITION * 0.9999)).freeze
+ NO_REBALANCING_NEEDED = ((RelativePositioning::MIN_POSITION * 0.9999)..(RelativePositioning::MAX_POSITION * 0.9999))
def rebalance_if_needed(issue)
return unless issue
@@ -111,9 +111,6 @@ module Issues
issue.namespace.execute_integrations(issue_data, hooks_scope)
execute_incident_hooks(issue, issue_data) if issue.work_item_type&.incident?
-
- return unless Feature.enabled?(:group_mentions, issue.project)
-
execute_group_mention_hooks(issue, issue_data) if action == 'open'
end
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index f848a8db12a..ef43e707a21 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -6,10 +6,12 @@ module Issues
def execute(issue, commit: nil, notifications: true, system_note: true, skip_authorization: false)
return issue unless can_close?(issue, skip_authorization: skip_authorization)
- close_issue(issue,
- closed_via: commit,
- notifications: notifications,
- system_note: system_note)
+ close_issue(
+ issue,
+ closed_via: commit,
+ notifications: notifications,
+ system_note: system_note
+ )
end
# Closes the supplied issue without checking if the user is authorized to
@@ -86,7 +88,7 @@ module Issues
issue = alert.issue
if alert.resolve
- SystemNoteService.change_alert_status(alert, User.alert_bot, " because #{current_user.to_reference} closed incident #{issue.to_reference(project)}")
+ SystemNoteService.change_alert_status(alert, Users::Internal.alert_bot, " because #{current_user.to_reference} closed incident #{issue.to_reference(project)}")
else
Gitlab::AppLogger.warn(
message: 'Cannot resolve an associated Alert Management alert',
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index e1ddfe47439..c828c156d50 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -7,7 +7,7 @@ module Issues
include ::Services::ReturnServiceResponses
rate_limit key: :issues_create,
- opts: { scope: [:project, :current_user, :external_author] }
+ opts: { scope: [:project, :current_user, :external_author] }
def initialize(container:, current_user: nil, params: {}, build_service: nil, perform_spam_check: true)
@extra_params = params.delete(:extra_params) || {}
@@ -90,9 +90,12 @@ module Issues
def resolve_discussions_with_issue(issue)
return if discussions_to_resolve.empty?
- Discussions::ResolveService.new(project, current_user,
- one_or_more_discussions: discussions_to_resolve,
- follow_up_issue: issue).execute
+ Discussions::ResolveService.new(
+ project,
+ current_user,
+ one_or_more_discussions: discussions_to_resolve,
+ follow_up_issue: issue
+ ).execute
end
private
diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb
index e26e3d0835b..c3ddf7b6709 100644
--- a/app/services/issues/move_service.rb
+++ b/app/services/issues/move_service.rb
@@ -141,15 +141,23 @@ module Issues
end
def add_note_from
- SystemNoteService.noteable_moved(new_entity, target_project,
- original_entity, current_user,
- direction: :from)
+ SystemNoteService.noteable_moved(
+ new_entity,
+ target_project,
+ original_entity,
+ current_user,
+ direction: :from
+ )
end
def add_note_to
- SystemNoteService.noteable_moved(original_entity, old_project,
- new_entity, current_user,
- direction: :to)
+ SystemNoteService.noteable_moved(
+ original_entity,
+ old_project,
+ new_entity,
+ current_user,
+ direction: :to
+ )
end
end
end
diff --git a/app/services/issues/relative_position_rebalancing_service.rb b/app/services/issues/relative_position_rebalancing_service.rb
index a8d0ae01176..e165cb36634 100644
--- a/app/services/issues/relative_position_rebalancing_service.rb
+++ b/app/services/issues/relative_position_rebalancing_service.rb
@@ -141,7 +141,7 @@ module Issues
def run_update_query(values, query_name)
Issue.connection.exec_query(<<~SQL, query_name)
- WITH cte(cte_id, new_pos) AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH cte(cte_id, new_pos) AS MATERIALIZED (
SELECT *
FROM (VALUES #{values}) as t (id, pos)
)
diff --git a/app/services/labels/available_labels_service.rb b/app/services/labels/available_labels_service.rb
index 21f92eeaf09..7809f263eb6 100644
--- a/app/services/labels/available_labels_service.rb
+++ b/app/services/labels/available_labels_service.rb
@@ -40,19 +40,8 @@ module Labels
ids.map(&:to_i) & existing_ids
end
- def filter_locked_labels_ids_in_param(key)
- ids = Array.wrap(params[key])
- return [] if ids.empty?
-
- params = finder_params
- params[:locked_labels] = true
- existing_labels = LabelsFinder.new(current_user, params).execute
-
- # rubocop:disable CodeReuse/ActiveRecord
- existing_ids = existing_labels.id_in(ids).pluck(:id)
- # rubocop:enable CodeReuse/ActiveRecord
-
- ids.map(&:to_i) & existing_ids
+ def filter_locked_label_ids(ids)
+ available_labels.with_lock_on_merge.id_in(ids).pluck(:id) # rubocop:disable CodeReuse/ActiveRecord
end
def available_labels
diff --git a/app/services/labels/create_service.rb b/app/services/labels/create_service.rb
index 675439b2f64..c69b9bd8de7 100644
--- a/app/services/labels/create_service.rb
+++ b/app/services/labels/create_service.rb
@@ -13,9 +13,7 @@ module Labels
project_or_group = target_params[:project] || target_params[:group]
if project_or_group.present?
- if Feature.disabled?(:enforce_locked_labels_on_merge, project_or_group, type: :ops)
- params.delete(:lock_on_merge)
- end
+ params.delete(:lock_on_merge) unless project_or_group.supports_lock_on_merge?
project_or_group.labels.create(params)
elsif target_params[:template]
diff --git a/app/services/labels/update_service.rb b/app/services/labels/update_service.rb
index 4ac54959e84..0ffb0fabf21 100644
--- a/app/services/labels/update_service.rb
+++ b/app/services/labels/update_service.rb
@@ -21,8 +21,12 @@ module Labels
def allow_lock_on_merge?(label)
return if label.template?
return unless label.respond_to?(:parent_container)
+ return unless label.parent_container.supports_lock_on_merge?
- Feature.enabled?(:enforce_locked_labels_on_merge, label.parent_container, type: :ops)
+ # If we've made it here, then we're allowed to turn it on. However, we do _not_
+ # want to allow it to be turned off. So if it's already set, then don't allow the possibility
+ # that it could be turned off.
+ !label.lock_on_merge
end
end
end
diff --git a/app/services/loose_foreign_keys/process_deleted_records_service.rb b/app/services/loose_foreign_keys/process_deleted_records_service.rb
index 8700276c982..e0c9c19f5b9 100644
--- a/app/services/loose_foreign_keys/process_deleted_records_service.rb
+++ b/app/services/loose_foreign_keys/process_deleted_records_service.rb
@@ -4,13 +4,13 @@ module LooseForeignKeys
class ProcessDeletedRecordsService
BATCH_SIZE = 1000
- def initialize(connection:)
+ def initialize(connection:, modification_tracker: LooseForeignKeys::ModificationTracker.new)
@connection = connection
+ @modification_tracker = modification_tracker
end
def execute
raised_error = false
- modification_tracker = ModificationTracker.new
tracked_tables.cycle do |table|
records = load_batch_for_table(table)
@@ -54,7 +54,7 @@ module LooseForeignKeys
private
- attr_reader :connection
+ attr_reader :connection, :modification_tracker
def db_config_name
::Gitlab::Database.db_config_name(connection)
diff --git a/app/services/members/creator_service.rb b/app/services/members/creator_service.rb
index a6fff3003ac..cc18aae7446 100644
--- a/app/services/members/creator_service.rb
+++ b/app/services/members/creator_service.rb
@@ -39,31 +39,34 @@ module Members
sources = Array.wrap(sources) if sources.is_a?(ApplicationRecord) # For single source
- Member.transaction do
- sources.flat_map do |source|
- # If this user is attempting to manage Owner members and doesn't have permission, do not allow
- if managing_owners?(args[:current_user], access_level) && cannot_manage_owners?(source, args[:current_user])
- next []
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[users user_preferences user_details emails identities], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424276'
+ ) do
+ Member.transaction do
+ sources.flat_map do |source|
+ # If this user is attempting to manage Owner members and doesn't have permission, do not allow
+ current_user = args[:current_user]
+ next [] if managing_owners?(current_user, access_level) && cannot_manage_owners?(source, current_user)
+
+ emails, users, existing_members = parse_users_list(source, invitees)
+
+ common_arguments = {
+ source: source,
+ access_level: access_level,
+ existing_members: existing_members,
+ tasks_to_be_done: args[:tasks_to_be_done] || []
+ }.merge(parsed_args(args))
+
+ members = emails.map do |email|
+ new(invitee: email, builder: InviteMemberBuilder, **common_arguments).execute
+ end
+
+ members += users.map do |user|
+ new(invitee: user, **common_arguments).execute
+ end
+
+ members
end
-
- emails, users, existing_members = parse_users_list(source, invitees)
-
- common_arguments = {
- source: source,
- access_level: access_level,
- existing_members: existing_members,
- tasks_to_be_done: args[:tasks_to_be_done] || []
- }.merge(parsed_args(args))
-
- members = emails.map do |email|
- new(invitee: email, builder: InviteMemberBuilder, **common_arguments).execute
- end
-
- members += users.map do |user|
- new(invitee: user, **common_arguments).execute
- end
-
- members
end
end
end
diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb
index e432016795d..d4cc60c6de0 100644
--- a/app/services/members/destroy_service.rb
+++ b/app/services/members/destroy_service.rb
@@ -47,6 +47,10 @@ module Members
def enqueue_jobs_that_needs_to_be_run_only_once_per_hierarchy(member, unassign_issuables)
return if recursive_call?
+ enqueue_cleanup_jobs_once_per_heirarchy(member, unassign_issuables)
+ end
+
+ def enqueue_cleanup_jobs_once_per_heirarchy(member, unassign_issuables)
enqueue_delete_todos(member)
enqueue_unassign_issuables(member) if unassign_issuables
end
diff --git a/app/services/merge_requests/approval_service.rb b/app/services/merge_requests/approval_service.rb
index 8560a15b7c4..dbe5567cbc5 100644
--- a/app/services/merge_requests/approval_service.rb
+++ b/app/services/merge_requests/approval_service.rb
@@ -5,12 +5,17 @@ module MergeRequests
def execute(merge_request)
return unless eligible_for_approval?(merge_request)
- approval = merge_request.approvals.new(user: current_user)
+ approval = merge_request.approvals.new(
+ user: current_user,
+ patch_id_sha: fetch_patch_id_sha(merge_request)
+ )
return success unless save_approval(approval)
reset_approvals_cache(merge_request)
+
merge_request_activity_counter.track_approve_mr_action(user: current_user, merge_request: merge_request)
+
trigger_merge_request_merge_status_updated(merge_request)
trigger_merge_request_reviewers_updated(merge_request)
trigger_merge_request_approval_state_updated(merge_request)
@@ -31,6 +36,17 @@ module MergeRequests
private
+ def fetch_patch_id_sha(merge_request)
+ diff_refs = merge_request.diff_refs
+ base_sha = diff_refs&.base_sha
+ head_sha = diff_refs&.head_sha
+
+ return unless base_sha && head_sha
+ return if base_sha == head_sha
+
+ merge_request.project.repository.get_patch_id(base_sha, head_sha)
+ end
+
def eligible_for_approval?(merge_request)
merge_request.eligible_for_approval_by?(current_user)
end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 0fc85675e49..f36cad7139a 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -36,10 +36,7 @@ module MergeRequests
merge_request.project.execute_integrations(merge_data, :merge_request_hooks)
execute_external_hooks(merge_request, merge_data)
-
- if action == 'open' && Feature.enabled?(:group_mentions, merge_request.project)
- execute_group_mention_hooks(merge_request, merge_data)
- end
+ execute_group_mention_hooks(merge_request, merge_data) if action == 'open'
enqueue_jira_connect_messages_for(merge_request)
end
@@ -113,7 +110,7 @@ module MergeRequests
# Don't try to print expensive instance variables.
def inspect
- return "#<#{self.class}>" unless respond_to?(:merge_request)
+ return "#<#{self.class}>" unless respond_to?(:merge_request) && merge_request
"#<#{self.class} #{merge_request.to_reference(full: true)}>"
end
@@ -176,21 +173,10 @@ module MergeRequests
params.delete(:allow_collaboration)
end
- filter_locked_labels(merge_request)
filter_reviewer(merge_request)
filter_suggested_reviewers
end
- # Filter out any locked labels that are requested to be removed.
- # Only supported for merged MRs.
- def filter_locked_labels(merge_request)
- return unless params[:remove_label_ids].present?
- return unless merge_request.merged?
- return unless Feature.enabled?(:enforce_locked_labels_on_merge, merge_request.project, type: :ops)
-
- params[:remove_label_ids] -= labels_service.filter_locked_labels_ids_in_param(:remove_label_ids)
- end
-
def filter_reviewer(merge_request)
return if params[:reviewer_ids].blank?
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index b8853e8bcbc..bb347096274 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -74,7 +74,7 @@ module MergeRequests
# IssuableBaseService#process_label_ids and
# IssuableBaseService#process_assignee_ids take care
# of the removal.
- params[:label_ids] = process_label_ids(params, extra_label_ids: merge_request.label_ids.to_a)
+ params[:label_ids] = process_label_ids(params, issuable: merge_request, extra_label_ids: merge_request.label_ids.to_a)
params[:assignee_ids] = process_assignee_ids(params, extra_assignee_ids: merge_request.assignee_ids.to_a)
@@ -130,10 +130,14 @@ module MergeRequests
if source_branch_default? && !target_branch_specified?
merge_request.target_branch = nil
else
- merge_request.target_branch ||= target_project.default_branch
+ merge_request.target_branch ||= get_target_branch
end
end
+ def get_target_branch
+ target_project.default_branch
+ end
+
def source_branch_specified?
params[:source_branch].present?
end
diff --git a/app/services/merge_requests/create_ref_service.rb b/app/services/merge_requests/create_ref_service.rb
index e0f10183bac..eae6845335a 100644
--- a/app/services/merge_requests/create_ref_service.rb
+++ b/app/services/merge_requests/create_ref_service.rb
@@ -9,101 +9,117 @@ module MergeRequests
CreateRefError = Class.new(StandardError)
def initialize(
- current_user:, merge_request:, target_ref:, first_parent_ref:,
- source_sha: nil, merge_commit_message: nil)
-
+ current_user:, merge_request:, target_ref:, first_parent_ref:, source_sha: nil
+ )
@current_user = current_user
@merge_request = merge_request
- @initial_source_sha = source_sha
+ @source_sha = source_sha
@target_ref = target_ref
- @merge_commit_message = merge_commit_message
+ @first_parent_ref = first_parent_ref
@first_parent_sha = target_project.commit(first_parent_ref)&.sha
end
def execute
- commit_sha = initial_source_sha # the SHA to be at HEAD of target_ref
- source_sha = initial_source_sha # the SHA to be the merged result of the source (minus the merge commit)
- expected_old_oid = "" # the SHA we expect target_ref to be at prior to an update (an optimistic lock)
-
# TODO: Update this message with the removal of FF merge_trains_create_ref_service and update tests
# This is for compatibility with MergeToRefService during the rollout.
return ServiceResponse.error(message: '3:Invalid merge source') unless first_parent_sha.present?
- commit_sha, source_sha, expected_old_oid = maybe_squash!(commit_sha, source_sha, expected_old_oid)
- commit_sha, source_sha, expected_old_oid = maybe_rebase!(commit_sha, source_sha, expected_old_oid)
- commit_sha, source_sha = maybe_merge!(commit_sha, source_sha, expected_old_oid)
-
- ServiceResponse.success(
- payload: {
- commit_sha: commit_sha,
- target_sha: first_parent_sha,
- source_sha: source_sha
- }
- )
+ result = {
+ commit_sha: source_sha, # the SHA to be at HEAD of target_ref
+ expected_old_oid: "", # the SHA we expect target_ref to be at prior to an update (an optimistic lock)
+ source_sha: source_sha, # for pipeline.source_sha
+ target_sha: first_parent_sha # for pipeline.target_sha
+ }
+
+ result = maybe_squash!(**result)
+ result = maybe_rebase!(**result)
+ result = maybe_merge!(**result)
+
+ update_merge_request!(merge_request, result)
+
+ ServiceResponse.success(payload: result)
rescue CreateRefError => error
ServiceResponse.error(message: error.message)
end
private
- attr_reader :current_user, :merge_request, :target_ref, :first_parent_sha, :initial_source_sha
+ attr_reader :current_user, :merge_request, :target_ref, :first_parent_ref, :first_parent_sha, :source_sha
delegate :target_project, to: :merge_request
delegate :repository, to: :target_project
- def maybe_squash!(commit_sha, source_sha, expected_old_oid)
+ def maybe_squash!(commit_sha:, **rest)
if merge_request.squash_on_merge?
squash_result = MergeRequests::SquashService.new(
merge_request: merge_request,
current_user: current_user,
commit_message: squash_commit_message
).execute
+
raise CreateRefError, squash_result[:message] if squash_result[:status] == :error
commit_sha = squash_result[:squash_sha]
- source_sha = commit_sha
+ squash_commit_sha = commit_sha
end
# squash does not overwrite target_ref, so expected_old_oid remains the same
- [commit_sha, source_sha, expected_old_oid]
+ rest.merge(
+ commit_sha: commit_sha,
+ squash_commit_sha: squash_commit_sha
+ ).compact
end
- def maybe_rebase!(commit_sha, source_sha, expected_old_oid)
+ def maybe_rebase!(commit_sha:, expected_old_oid:, squash_commit_sha: nil, **rest)
if target_project.ff_merge_must_be_possible?
commit_sha = safe_gitaly_operation do
repository.rebase_to_ref(
current_user,
- source_sha: source_sha,
+ source_sha: commit_sha,
target_ref: target_ref,
- first_parent_ref: first_parent_sha
+ first_parent_ref: first_parent_sha,
+ expected_old_oid: expected_old_oid || ""
)
end
- source_sha = commit_sha
+ squash_commit_sha = commit_sha if squash_commit_sha # rebase rewrites commit SHAs after first_parent_sha
expected_old_oid = commit_sha
end
- [commit_sha, source_sha, expected_old_oid]
+ rest.merge(
+ commit_sha: commit_sha,
+ squash_commit_sha: squash_commit_sha,
+ expected_old_oid: expected_old_oid
+ ).compact
end
- def maybe_merge!(commit_sha, source_sha, expected_old_oid)
+ def maybe_merge!(commit_sha:, expected_old_oid:, **rest)
unless target_project.merge_requests_ff_only_enabled
commit_sha = safe_gitaly_operation do
repository.merge_to_ref(
current_user,
- source_sha: source_sha,
+ source_sha: commit_sha,
target_ref: target_ref,
message: merge_commit_message,
first_parent_ref: first_parent_sha,
branch: nil,
- expected_old_oid: expected_old_oid
+ expected_old_oid: expected_old_oid || ""
)
end
- commit = target_project.commit(commit_sha)
- _, source_sha = commit.parent_ids
+
+ expected_old_oid = commit_sha
+ merge_commit_sha = commit_sha
end
- [commit_sha, source_sha]
+ rest.merge(
+ commit_sha: commit_sha,
+ merge_commit_sha: merge_commit_sha,
+ expected_old_oid: expected_old_oid
+ ).compact
+ end
+
+ def update_merge_request!(merge_request, result)
+ # overridden in EE
end
def safe_gitaly_operation
@@ -119,12 +135,10 @@ module MergeRequests
strong_memoize_attr :squash_commit_message
def merge_commit_message
- return @merge_commit_message if @merge_commit_message.present?
-
- @merge_commit_message = (
- merge_request.merge_params['commit_message'].presence ||
+ merge_request.merge_params['commit_message'].presence ||
merge_request.default_merge_commit_message(user: current_user)
- )
end
end
end
+
+MergeRequests::CreateRefService.prepend_mod_with('MergeRequests::CreateRefService')
diff --git a/app/services/merge_requests/ff_merge_service.rb b/app/services/merge_requests/ff_merge_service.rb
deleted file mode 100644
index 1a83bbf9de6..00000000000
--- a/app/services/merge_requests/ff_merge_service.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module MergeRequests
- # MergeService class
- #
- # Do git fast-forward merge and in case of success
- # mark merge request as merged and execute all hooks and notifications
- # Executed when you do fast-forward merge via GitLab UI
- #
- class FfMergeService < MergeRequests::MergeService
- extend ::Gitlab::Utils::Override
-
- private
-
- override :execute_git_merge
- def execute_git_merge
- repository.ff_merge(
- current_user,
- source,
- merge_request.target_branch,
- merge_request: merge_request
- )
- end
-
- override :merge_success_data
- def merge_success_data(commit_id)
- # There is no merge commit to update, so this is just blank.
- {}
- end
- end
-end
diff --git a/app/services/merge_requests/merge_base_service.rb b/app/services/merge_requests/merge_base_service.rb
index fa0a4f808e2..0c8795cfd61 100644
--- a/app/services/merge_requests/merge_base_service.rb
+++ b/app/services/merge_requests/merge_base_service.rb
@@ -18,24 +18,8 @@ module MergeRequests
# No-op
end
- def source
- strong_memoize(:source) do
- if merge_request.squash_on_merge?
- squash_sha!
- else
- merge_request.diff_head_sha
- end
- end
- end
-
private
- def check_source
- unless source
- raise_error('No source for merge')
- end
- end
-
# Overridden in EE.
def check_size_limit
# No-op
@@ -53,26 +37,6 @@ module MergeRequests
def handle_merge_error(*args)
# No-op
end
-
- def commit_message
- params[:commit_message] ||
- merge_request.default_merge_commit_message(user: current_user)
- end
-
- def squash_sha!
- squash_result = ::MergeRequests::SquashService.new(
- merge_request: merge_request,
- current_user: current_user,
- commit_message: params[:squash_commit_message]
- ).execute
-
- case squash_result[:status]
- when :success
- squash_result[:squash_sha]
- when :error
- raise ::MergeRequests::MergeService::MergeError, squash_result[:message]
- end
- end
end
end
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index 1398a6dbb67..29aba3c8679 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -16,38 +16,6 @@ module MergeRequests
delegate :merge_jid, :state, to: :@merge_request
def execute(merge_request, options = {})
- return execute_v2(merge_request, options) if Feature.enabled?(:refactor_merge_service, project)
-
- if project.merge_requests_ff_only_enabled && !self.is_a?(FfMergeService)
- FfMergeService.new(project: project, current_user: current_user, params: params).execute(merge_request)
- return
- end
-
- return if merge_request.merged?
- return unless exclusive_lease(merge_request.id).try_obtain
-
- @merge_request = merge_request
- @options = options
- jid = merge_jid
-
- validate!
-
- merge_request.in_locked_state do
- if commit
- after_merge
- clean_merge_jid
- success
- end
- end
-
- log_info("Merge process finished on JID #{jid} with state #{state}")
- rescue MergeError => e
- handle_merge_error(log_message: e.message, save_message_on_model: true)
- ensure
- exclusive_lease(merge_request.id).cancel
- end
-
- def execute_v2(merge_request, options = {})
return if merge_request.merged?
return unless exclusive_lease(merge_request.id).try_obtain
@@ -61,7 +29,7 @@ module MergeRequests
validate!
merge_request.in_locked_state do
- if commit_v2
+ if commit
after_merge
clean_merge_jid
success
@@ -90,28 +58,8 @@ module MergeRequests
end
end
- # Can remove this entire method when :refactor_merge_service is enabled
- def error_check!
- super
-
- return if Feature.enabled?(:refactor_merge_service, project)
-
- check_source
-
- error =
- if @merge_request.should_be_rebased?
- 'Only fast-forward merge is allowed for your project. Please update your source branch'
- elsif !@merge_request.mergeable?(skip_discussions_check: @options[:skip_discussions_check], check_mergeability_retry_lease: @options[:check_mergeability_retry_lease])
- 'Merge request is not mergeable'
- elsif !@merge_request.squash && project.squash_always?
- 'This project requires squashing commits when merge requests are accepted.'
- end
-
- raise_error(error) if error
- end
-
def validate_strategy!
- @merge_strategy.validate! if Feature.enabled?(:refactor_merge_service, project)
+ @merge_strategy.validate!
end
def updated_check!
@@ -121,7 +69,7 @@ module MergeRequests
end
end
- def commit_v2
+ def commit
log_info("Git merge started on JID #{merge_jid}")
merge_result = try_merge { @merge_strategy.execute_git_merge! }
@@ -131,7 +79,11 @@ module MergeRequests
log_info("Git merge finished on JID #{merge_jid} commit #{commit_sha}")
- new_merge_request_attributes = merge_result.slice(:merge_commit_sha, :squash_commit_sha)
+ new_merge_request_attributes = {
+ merged_commit_sha: commit_sha,
+ merge_commit_sha: merge_result[:merge_commit_sha],
+ squash_commit_sha: merge_result[:squash_commit_sha]
+ }.compact
merge_request.update!(new_merge_request_attributes) if new_merge_request_attributes.present?
commit_sha
@@ -140,35 +92,6 @@ module MergeRequests
log_info("Merge request marked in progress")
end
- def commit
- log_info("Git merge started on JID #{merge_jid}")
- commit_id = try_merge { execute_git_merge }
-
- if commit_id
- log_info("Git merge finished on JID #{merge_jid} commit #{commit_id}")
- else
- raise_error(GENERIC_ERROR_MESSAGE)
- end
-
- update_merge_sha_metadata(commit_id)
-
- commit_id
- ensure
- merge_request.update_and_mark_in_progress_merge_commit_sha(nil)
- log_info("Merge request marked in progress")
- end
-
- def update_merge_sha_metadata(commit_id)
- data_to_update = merge_success_data(commit_id)
- data_to_update[:squash_commit_sha] = source if merge_request.squash_on_merge?
-
- merge_request.update!(**data_to_update) if data_to_update.present?
- end
-
- def merge_success_data(commit_id)
- { merge_commit_sha: commit_id }
- end
-
def try_merge
yield
rescue Gitlab::Git::PreReceiveError => e
@@ -178,10 +101,6 @@ module MergeRequests
raise_error(GENERIC_ERROR_MESSAGE)
end
- def execute_git_merge
- repository.merge(current_user, source, merge_request, commit_message)
- end
-
def after_merge
log_info("Post merge started on JID #{merge_jid} with state #{state}")
MergeRequests::PostMergeService.new(project: project, current_user: current_user).execute(merge_request)
diff --git a/app/services/merge_requests/merge_strategies/from_source_branch.rb b/app/services/merge_requests/merge_strategies/from_source_branch.rb
index 9fe5fc5160b..fe0e4d8a90c 100644
--- a/app/services/merge_requests/merge_strategies/from_source_branch.rb
+++ b/app/services/merge_requests/merge_strategies/from_source_branch.rb
@@ -28,7 +28,7 @@ module MergeRequests
check_mergeability_retry_lease: @options[:check_mergeability_retry_lease]
)
'Merge request is not mergeable'
- elsif !merge_request.squash && project.squash_always?
+ elsif merge_request.missing_required_squash?
'This project requires squashing commits when merge requests are accepted.'
end
@@ -110,3 +110,5 @@ module MergeRequests
end
end
end
+
+::MergeRequests::MergeStrategies::FromSourceBranch.prepend_mod
diff --git a/app/services/merge_requests/merge_to_ref_service.rb b/app/services/merge_requests/merge_to_ref_service.rb
index 8b79feb5e0f..6e1b56d9651 100644
--- a/app/services/merge_requests/merge_to_ref_service.rb
+++ b/app/services/merge_requests/merge_to_ref_service.rb
@@ -31,14 +31,13 @@ module MergeRequests
private
- override :source
def source
merge_request.diff_head_sha
end
override :error_check!
def error_check!
- check_source
+ raise_error('No source for merge') unless source
end
##
@@ -55,6 +54,11 @@ module MergeRequests
params[:first_parent_ref] || merge_request.target_branch_ref
end
+ def commit_message
+ params[:commit_message] ||
+ merge_request.default_merge_commit_message(user: current_user)
+ end
+
def extracted_merge_to_ref
repository.merge_to_ref(current_user,
source_sha: source,
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 447f4f9428c..7a7d0dbfef2 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -94,7 +94,9 @@ module MergeRequests
)
merge_requests.each do |merge_request|
- merge_request.merge_commit_sha = analyzer.get_merge_commit(merge_request.diff_head_sha)
+ sha = analyzer.get_merge_commit(merge_request.diff_head_sha)
+ merge_request.merge_commit_sha = sha
+ merge_request.merged_commit_sha = sha
MergeRequests::PostMergeService
.new(project: merge_request.target_project, current_user: @current_user)
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 598dbaf93a9..c435048e343 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -94,7 +94,7 @@ module MergeRequests
end
def track_title_and_desc_edits(changed_fields)
- tracked_fields = %w(title description)
+ tracked_fields = %w[title description]
return unless changed_fields.any? { |field| tracked_fields.include?(field) }
diff --git a/app/services/metrics/global_metrics_update_service.rb b/app/services/metrics/global_metrics_update_service.rb
deleted file mode 100644
index 356de58ba2e..00000000000
--- a/app/services/metrics/global_metrics_update_service.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-module Metrics
- # Update metrics regarding GitLab instance wide
- #
- # Anything that is not specific to a machine, process, request or any other context
- # can be updated from this services.
- #
- # Examples of metrics that qualify:
- # * Global counters (instance users, instance projects...)
- # * State of settings stored in the database (whether a feature is active or not, tuning values...)
- #
- class GlobalMetricsUpdateService
- def execute
- return unless ::Gitlab::Metrics.prometheus_metrics_enabled?
-
- maintenance_mode_metric.set({}, (::Gitlab.maintenance_mode? ? 1 : 0))
- end
-
- def maintenance_mode_metric
- ::Gitlab::Metrics.gauge(:gitlab_maintenance_mode, 'Is GitLab Maintenance Mode enabled?')
- end
- end
-end
diff --git a/app/services/metrics/sample_metrics_service.rb b/app/services/metrics/sample_metrics_service.rb
deleted file mode 100644
index 9bf32b295e2..00000000000
--- a/app/services/metrics/sample_metrics_service.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-module Metrics
- class SampleMetricsService
- DIRECTORY = "sample_metrics"
-
- attr_reader :identifier, :range_minutes
-
- def initialize(identifier, range_start:, range_end:)
- @identifier = identifier
- @range_minutes = convert_range_minutes(range_start, range_end)
- end
-
- def query
- return unless identifier && File.exist?(file_location)
-
- query_interval
- end
-
- private
-
- def file_location
- sanitized_string = identifier.gsub(/[^0-9A-Za-z_]/, '')
- File.join(Rails.root, DIRECTORY, "#{sanitized_string}.yml")
- end
-
- def query_interval
- result = YAML.load_file(File.expand_path(file_location, __dir__))
- result[range_minutes]
- end
-
- def convert_range_minutes(range_start, range_end)
- ((range_end.to_time - range_start.to_time) / 1.minute).to_i
- end
- end
-end
diff --git a/app/services/namespaces/in_product_marketing_emails_service.rb b/app/services/namespaces/in_product_marketing_emails_service.rb
index 1ce7e4cae16..14e670126c6 100644
--- a/app/services/namespaces/in_product_marketing_emails_service.rb
+++ b/app/services/namespaces/in_product_marketing_emails_service.rb
@@ -44,108 +44,6 @@ module Namespaces
interval_days = TRACKS.dig(track.to_sym, :interval_days)
interval_days&.count || 0
end
-
- def self.send_for_all_tracks_and_intervals
- TRACKS.each_key do |track|
- TRACKS[track][:interval_days].each do |interval|
- new(track, interval).execute
- end
- end
- end
-
- def initialize(track, interval)
- @track = track
- @interval = interval
- @sent_email_records = ::Users::InProductMarketingEmailRecords.new
- end
-
- def execute
- raise ArgumentError, "Track #{track} not defined" unless TRACKS.key?(track)
-
- groups_for_track.each_batch do |groups|
- groups.each do |group|
- send_email_for_group(group)
- end
- end
- end
-
- private
-
- attr_reader :track, :interval, :sent_email_records
-
- def send_email(user, group)
- NotificationService.new.in_product_marketing(user.id, group.id, track, series)
- end
-
- def send_email_for_group(group)
- users_for_group(group).each do |user|
- if can_perform_action?(user, group)
- send_email(user, group)
- sent_email_records.add(user, track: track, series: series)
- end
- end
-
- sent_email_records.save!
- end
-
- def groups_for_track
- onboarding_progress_scope = Onboarding::Progress
- .completed_actions_with_latest_in_range(completed_actions, range)
- .incomplete_actions(incomplete_actions)
-
- # Filtering out sub-groups is a temporary fix to prevent calling
- # `.root_ancestor` on groups that are not root groups.
- # See https://gitlab.com/groups/gitlab-org/-/epics/5594 for more information.
- Group
- .top_most
- .with_onboarding_progress
- .merge(onboarding_progress_scope)
- .merge(subscription_scope)
- end
-
- def subscription_scope
- {}
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def users_for_group(group)
- group.users
- .where(email_opted_in: true)
- .merge(Users::InProductMarketingEmail.without_track_and_series(track, series))
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def can_perform_action?(user, group)
- case track
- when :create, :verify
- user.can?(:create_projects, group)
- when :trial, :trial_short
- user.can?(:start_trial, group)
- when :team, :team_short
- user.can?(:admin_group_member, group)
- when :admin_verify
- user.can?(:admin_group, group)
- when :experience
- true
- end
- end
-
- def completed_actions
- TRACKS[track][:completed_actions]
- end
-
- def range
- date = (interval + 1).days.ago
- date.beginning_of_day..date.end_of_day
- end
-
- def incomplete_actions
- TRACKS[track][:incomplete_actions]
- end
-
- def series
- TRACKS[track][:interval_days].index(interval)
- end
end
end
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index fdab2a07990..1af26377b71 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -187,12 +187,12 @@ module Notes
namespace: project&.namespace,
user: user,
label: metric_key_path,
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: metric_key_path).to_context]
+ context: [Gitlab::Usage::MetricDefinition.context_for(metric_key_path).to_context]
)
end
def tracking_data_for(note)
- label = Gitlab.ee? && note.author == User.visual_review_bot ? 'anonymous_visual_review_note' : 'note'
+ label = Gitlab.ee? && note.author == Users::Internal.visual_review_bot ? 'anonymous_visual_review_note' : 'note'
{
label: label,
diff --git a/app/services/notes/post_process_service.rb b/app/services/notes/post_process_service.rb
index 9465b5218b0..6e92a887cdd 100644
--- a/app/services/notes/post_process_service.rb
+++ b/app/services/notes/post_process_service.rb
@@ -42,8 +42,6 @@ module Notes
note.project.execute_hooks(note_data, hooks_scope)
note.project.execute_integrations(note_data, hooks_scope)
- return unless Feature.enabled?(:group_mentions, note.project)
-
execute_group_mention_hooks(note, note_data, is_confidential)
end
diff --git a/app/services/notification_recipients/builder/base.rb b/app/services/notification_recipients/builder/base.rb
index 3fabec29c0d..afbf5747429 100644
--- a/app/services/notification_recipients/builder/base.rb
+++ b/app/services/notification_recipients/builder/base.rb
@@ -44,6 +44,7 @@ module NotificationRecipients
def add_recipients(users, type, reason)
if users.is_a?(ActiveRecord::Relation)
users = users.includes(:notification_settings)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421821')
end
users = Array(users).compact
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 648067e3452..f1781b3d3c5 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -75,6 +75,19 @@ class NotificationService
end
end
+ def resource_access_tokens_about_to_expire(bot_user, token_names)
+ recipients = bot_user.resource_bot_owners.select { |owner| owner.can?(:receive_notifications) }
+ resource = bot_user.resource_bot_resource
+
+ recipients.each do |recipient|
+ mailer.resource_access_tokens_about_to_expire_email(
+ recipient,
+ resource,
+ token_names
+ ).deliver_later
+ end
+ end
+
# Notify the owner of the account when a new personal access token is created
def access_token_created(user, token_name)
return unless user.can?(:receive_notifications)
@@ -430,13 +443,14 @@ class NotificationService
def send_service_desk_notification(note)
return unless note.noteable_type == 'Issue'
return if note.confidential
+ return unless note.project.service_desk_enabled?
issue = note.noteable
recipients = issue.email_participants_emails
return unless recipients.any?
- support_bot = User.support_bot
+ support_bot = Users::Internal.support_bot
recipients.delete(issue.external_author) if note.author == support_bot
recipients.each do |recipient|
@@ -755,10 +769,6 @@ class NotificationService
end
end
- def in_product_marketing(user_id, group_id, track, series)
- mailer.in_product_marketing_email(user_id, group_id, track, series).deliver_later
- end
-
def approve_mr(merge_request, current_user)
approve_mr_email(merge_request, merge_request.target_project, current_user)
end
diff --git a/app/services/packages/debian/generate_distribution_service.rb b/app/services/packages/debian/generate_distribution_service.rb
index 9feb860ae87..05f6d9af581 100644
--- a/app/services/packages/debian/generate_distribution_service.rb
+++ b/app/services/packages/debian/generate_distribution_service.rb
@@ -12,7 +12,7 @@ module Packages
DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
# From https://salsa.debian.org/ftp-team/dak/-/blob/991aaa27a7f7aa773bb9c0cf2d516e383d9cffa0/setup/core-init.d/080_metadatakeys#L9
- METADATA_KEYS = %w(
+ METADATA_KEYS = %w[
Package
Source
Binary
@@ -60,7 +60,7 @@ module Packages
Tag
Package-Type
Installer-Menu-Item
- ).freeze
+ ].freeze
def initialize(distribution)
@distribution = distribution
diff --git a/app/services/packages/npm/generate_metadata_service.rb b/app/services/packages/npm/generate_metadata_service.rb
index e1795079513..8eaac547f7e 100644
--- a/app/services/packages/npm/generate_metadata_service.rb
+++ b/app/services/packages/npm/generate_metadata_service.rb
@@ -4,6 +4,7 @@ module Packages
module Npm
class GenerateMetadataService
include API::Helpers::RelatedResourcesHelpers
+ include Gitlab::Utils::StrongMemoize
# Allowed fields are those defined in the abbreviated form
# defined here: https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md#abbreviated-version-object
@@ -13,6 +14,8 @@ module Packages
def initialize(name, packages)
@name = name
@packages = packages
+ @dependencies = {}
+ @dependency_ids = Hash.new { |h, key| h[key] = {} }
end
def execute(only_dist_tags: false)
@@ -21,7 +24,7 @@ module Packages
private
- attr_reader :name, :packages
+ attr_reader :name, :packages, :dependencies, :dependency_ids
def metadata(only_dist_tags)
result = { dist_tags: dist_tags }
@@ -38,9 +41,11 @@ module Packages
package_versions = {}
packages.each_batch do |relation|
- batched_packages = relation.including_dependency_links
- .preload_files
- .preload_npm_metadatum
+ load_dependencies(relation)
+ load_dependency_ids(relation)
+
+ batched_packages = relation.preload_files
+ .preload_npm_metadatum
batched_packages.each do |package|
package_file = package.installable_package_files.last
@@ -82,15 +87,17 @@ module Packages
end
def build_package_dependencies(package)
- dependencies = Hash.new { |h, key| h[key] = {} }
-
- package.dependency_links.each do |dependency_link|
- dependency = dependency_link.dependency
- dependencies[dependency_link.dependency_type][dependency.name] = dependency.version_pattern
+ dependency_ids[package.id].each_with_object(Hash.new { |h, key| h[key] = {} }) do |(type, ids), memo|
+ ids.each do |id|
+ memo[inverted_dependency_types[type]].merge!(dependencies[id])
+ end
end
+ end
- dependencies
+ def inverted_dependency_types
+ Packages::DependencyLink.dependency_types.invert.stringify_keys
end
+ strong_memoize_attr :inverted_dependency_types
def sorted_versions
versions = packages.pluck_versions.compact
@@ -106,6 +113,31 @@ module Packages
json = package.npm_metadatum&.package_json || {}
json.slice(*PACKAGE_JSON_ALLOWED_FIELDS)
end
+
+ def load_dependencies(packages)
+ Packages::Dependency
+ .id_in(
+ Packages::DependencyLink
+ .for_packages(packages)
+ .select_dependency_id
+ )
+ .id_not_in(dependencies.keys)
+ .each_batch do |relation|
+ relation.each do |dependency|
+ dependencies[dependency.id] = { dependency.name => dependency.version_pattern }
+ end
+ end
+ end
+
+ def load_dependency_ids(packages)
+ Packages::DependencyLink
+ .dependency_ids_grouped_by_type(packages)
+ .each_batch(column: :package_id) do |relation|
+ relation.each do |dependency_link|
+ dependency_ids[dependency_link.package_id] = dependency_link.dependency_ids_by_type
+ end
+ end
+ end
end
end
end
diff --git a/app/services/packages/nuget/check_duplicates_service.rb b/app/services/packages/nuget/check_duplicates_service.rb
new file mode 100644
index 00000000000..7ad9038d7c1
--- /dev/null
+++ b/app/services/packages/nuget/check_duplicates_service.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Packages
+ module Nuget
+ class CheckDuplicatesService < BaseService
+ include Gitlab::Utils::StrongMemoize
+
+ ExtractionError = Class.new(StandardError)
+
+ def execute
+ return ServiceResponse.success if package_settings_allow_duplicates? || !target_package_is_duplicate?
+
+ ServiceResponse.error(
+ message: 'A package with the same name and version already exists',
+ reason: :conflict
+ )
+ rescue ExtractionError => e
+ ServiceResponse.error(message: e.message, reason: :bad_request)
+ end
+
+ private
+
+ def package_settings_allow_duplicates?
+ package_settings.nuget_duplicates_allowed? || package_settings.class.duplicates_allowed?(existing_package)
+ end
+
+ def target_package_is_duplicate?
+ existing_package.name.casecmp(metadata[:package_name]) == 0 &&
+ (existing_package.version.casecmp(metadata[:package_version]) == 0 ||
+ existing_package.normalized_nuget_version&.casecmp(metadata[:package_version]) == 0)
+ end
+
+ def package_settings
+ project.namespace.package_settings
+ end
+ strong_memoize_attr :package_settings
+
+ def existing_package
+ ::Packages::Nuget::PackageFinder
+ .new(
+ current_user,
+ project,
+ package_name: metadata[:package_name],
+ package_version: metadata[:package_version]
+ )
+ .execute
+ .first
+ end
+ strong_memoize_attr :existing_package
+
+ def metadata
+ if remote_package_file?
+ ExtractMetadataContentService
+ .new(nuspec_file_content)
+ .execute
+ .payload
+ else # to cover the case when package file is on disk not in object storage
+ MetadataExtractionService
+ .new(mock_package_file)
+ .execute
+ .payload
+ end
+ end
+ strong_memoize_attr :metadata
+
+ def remote_package_file?
+ params[:remote_url].present?
+ end
+
+ def nuspec_file_content
+ ExtractRemoteMetadataFileService
+ .new(params[:remote_url])
+ .execute
+ .payload
+ rescue ExtractRemoteMetadataFileService::ExtractionError => e
+ raise ExtractionError, e.message
+ end
+
+ def mock_package_file
+ ::Packages::PackageFile.new(
+ params
+ .slice(:file, :file_name)
+ .merge(package: ::Packages::Package.nuget.build)
+ )
+ end
+ end
+ end
+end
diff --git a/app/services/packages/nuget/extract_metadata_file_service.rb b/app/services/packages/nuget/extract_metadata_file_service.rb
index 61e4892fee7..cc040a45016 100644
--- a/app/services/packages/nuget/extract_metadata_file_service.rb
+++ b/app/services/packages/nuget/extract_metadata_file_service.rb
@@ -3,14 +3,12 @@
module Packages
module Nuget
class ExtractMetadataFileService
- include Gitlab::Utils::StrongMemoize
-
ExtractionError = Class.new(StandardError)
MAX_FILE_SIZE = 4.megabytes.freeze
- def initialize(package_file_id)
- @package_file_id = package_file_id
+ def initialize(package_file)
+ @package_file = package_file
end
def execute
@@ -21,12 +19,7 @@ module Packages
private
- attr_reader :package_file_id
-
- def package_file
- ::Packages::PackageFile.find_by_id(package_file_id)
- end
- strong_memoize_attr :package_file
+ attr_reader :package_file
def valid_package_file?
package_file &&
@@ -41,7 +34,7 @@ module Packages
raise ExtractionError, 'nuspec file not found' unless entry
raise ExtractionError, 'nuspec file too big' if MAX_FILE_SIZE < entry.size
- Tempfile.open("nuget_extraction_package_file_#{package_file_id}") do |file|
+ Tempfile.open("nuget_extraction_package_file_#{package_file.id}") do |file|
entry.extract(file.path) { true } # allow #extract to overwrite the file
file.unlink
file.read
diff --git a/app/services/packages/nuget/extract_remote_metadata_file_service.rb b/app/services/packages/nuget/extract_remote_metadata_file_service.rb
new file mode 100644
index 00000000000..37624002ce7
--- /dev/null
+++ b/app/services/packages/nuget/extract_remote_metadata_file_service.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+module Packages
+ module Nuget
+ class ExtractRemoteMetadataFileService
+ include Gitlab::Utils::StrongMemoize
+
+ ExtractionError = Class.new(StandardError)
+
+ MAX_FILE_SIZE = 4.megabytes.freeze
+ METADATA_FILE_EXTENSION = '.nuspec'
+ MAX_FRAGMENTS = 5 # nuspec file is usually in the first 2 fragments but we buffer 5 max
+
+ def initialize(remote_url)
+ @remote_url = remote_url
+ end
+
+ def execute
+ raise ExtractionError, 'invalid file url' if remote_url.blank?
+
+ if nuspec_file_content.blank? || !nuspec_file_content.instance_of?(String)
+ raise ExtractionError, 'nuspec file not found'
+ end
+
+ ServiceResponse.success(payload: nuspec_file_content)
+ end
+
+ private
+
+ attr_reader :remote_url
+
+ def nuspec_file_content
+ fragments = []
+
+ Gitlab::HTTP.get(remote_url, stream_body: true, allow_object_storage: true) do |fragment|
+ break if fragments.size >= MAX_FRAGMENTS
+
+ fragments << fragment
+ joined_fragments = fragments.join
+
+ next if joined_fragments.exclude?(METADATA_FILE_EXTENSION)
+
+ nuspec_content = extract_nuspec_file(joined_fragments)
+
+ break nuspec_content if nuspec_content.present?
+ end
+ end
+ strong_memoize_attr :nuspec_file_content
+
+ def extract_nuspec_file(fragments)
+ StringIO.open(fragments) do |io|
+ Zip::InputStream.open(io) do |zip|
+ process_zip_entries(zip)
+ end
+ rescue Zip::Error => e
+ raise ExtractionError, "Error opening zip stream: #{e.message}"
+ end
+ end
+
+ def process_zip_entries(zip)
+ while (entry = zip.get_next_entry) # rubocop:disable Lint/AssignmentInCondition
+ next unless entry.name.end_with?(METADATA_FILE_EXTENSION)
+
+ raise ExtractionError, 'nuspec file too big' if entry.size > MAX_FILE_SIZE
+
+ return extract_file_content(entry)
+ end
+ end
+
+ def extract_file_content(entry)
+ Tempfile.create('extract_remote_metadata_file_service') do |file|
+ entry.extract(file.path) { true } # allow #extract to overwrite the file
+ file.read
+ end
+ rescue Zip::DecompressionError
+ '' # Ignore decompression errors and continue reading the next fragment
+ rescue Zip::EntrySizeError => e
+ raise ExtractionError, "nuspec file has the wrong entry size: #{e.message}"
+ end
+ end
+ end
+end
diff --git a/app/services/packages/nuget/metadata_extraction_service.rb b/app/services/packages/nuget/metadata_extraction_service.rb
index e1ee29ef2c6..2c758a5ec20 100644
--- a/app/services/packages/nuget/metadata_extraction_service.rb
+++ b/app/services/packages/nuget/metadata_extraction_service.rb
@@ -3,8 +3,8 @@
module Packages
module Nuget
class MetadataExtractionService
- def initialize(package_file_id)
- @package_file_id = package_file_id
+ def initialize(package_file)
+ @package_file = package_file
end
def execute
@@ -13,18 +13,18 @@ module Packages
private
- attr_reader :package_file_id
+ attr_reader :package_file
- def nuspec_file_content
- ExtractMetadataFileService
- .new(package_file_id)
+ def metadata
+ ExtractMetadataContentService
+ .new(nuspec_file_content)
.execute
.payload
end
- def metadata
- ExtractMetadataContentService
- .new(nuspec_file_content)
+ def nuspec_file_content
+ ExtractMetadataFileService
+ .new(package_file)
.execute
.payload
end
diff --git a/app/services/packages/nuget/odata_package_entry_service.rb b/app/services/packages/nuget/odata_package_entry_service.rb
new file mode 100644
index 00000000000..0cdcc38de16
--- /dev/null
+++ b/app/services/packages/nuget/odata_package_entry_service.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Packages
+ module Nuget
+ class OdataPackageEntryService
+ include API::Helpers::RelatedResourcesHelpers
+
+ SEMVER_LATEST_VERSION_PLACEHOLDER = '0.0.0-latest-version'
+ LATEST_VERSION_FOR_V2_DOWNLOAD_ENDPOINT = 'latest'
+
+ def initialize(project, params)
+ @project = project
+ @params = params
+ end
+
+ def execute
+ ServiceResponse.success(payload: package_entry)
+ end
+
+ private
+
+ attr_reader :project, :params
+
+ def package_entry
+ <<-XML.squish
+ <entry xmlns='http://www.w3.org/2005/Atom' xmlns:d='http://schemas.microsoft.com/ado/2007/08/dataservices' xmlns:georss='http://www.georss.org/georss' xmlns:gml='http://www.opengis.net/gml' xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' xml:base="#{xml_base}">
+ <id>#{id_url}</id>
+ <category term='V2FeedPackage' scheme='http://schemas.microsoft.com/ado/2007/08/dataservices/scheme'/>
+ <title type='text'>#{params[:package_name]}</title>
+ <content type='application/zip' src="#{download_url}"/>
+ <m:properties>
+ <d:Version>#{package_version}</d:Version>
+ </m:properties>
+ </entry>
+ XML
+ end
+
+ def package_version
+ params[:package_version] || SEMVER_LATEST_VERSION_PLACEHOLDER
+ end
+
+ def id_url
+ expose_url "#{api_v4_projects_packages_nuget_v2_path(id: project.id)}" \
+ "/Packages(Id='#{params[:package_name]}',Version='#{package_version}')"
+ end
+
+ # TODO: use path helper when download endpoint is merged
+ def download_url
+ expose_url "#{api_v4_projects_packages_nuget_v2_path(id: project.id)}" \
+ "/download/#{params[:package_name]}/#{download_url_package_version}"
+ end
+
+ def download_url_package_version
+ if latest_version?
+ LATEST_VERSION_FOR_V2_DOWNLOAD_ENDPOINT
+ else
+ params[:package_version]
+ end
+ end
+
+ def latest_version?
+ params[:package_version].nil? || params[:package_version] == SEMVER_LATEST_VERSION_PLACEHOLDER
+ end
+
+ def xml_base
+ expose_url api_v4_projects_packages_nuget_v2_path(id: project.id)
+ end
+ end
+ end
+end
diff --git a/app/services/packages/nuget/update_package_from_metadata_service.rb b/app/services/packages/nuget/update_package_from_metadata_service.rb
index 73a52ea569f..258f8c8f6aa 100644
--- a/app/services/packages/nuget/update_package_from_metadata_service.rb
+++ b/app/services/packages/nuget/update_package_from_metadata_service.rb
@@ -148,7 +148,7 @@ module Packages
end
def metadata
- ::Packages::Nuget::MetadataExtractionService.new(@package_file.id).execute.payload
+ ::Packages::Nuget::MetadataExtractionService.new(@package_file).execute.payload
end
strong_memoize_attr :metadata
diff --git a/app/services/preview_markdown_service.rb b/app/services/preview_markdown_service.rb
index c8ccbe1465e..10aef87332a 100644
--- a/app/services/preview_markdown_service.rb
+++ b/app/services/preview_markdown_service.rb
@@ -17,7 +17,7 @@ class PreviewMarkdownService < BaseService
private
def quick_action_types
- %w(Issue MergeRequest Commit WorkItem)
+ %w[Issue MergeRequest Commit WorkItem]
end
def explain_quick_actions(text)
diff --git a/app/services/projects/apple_target_platform_detector_service.rb b/app/services/projects/apple_target_platform_detector_service.rb
index ec4c16a1416..087bb1f22e1 100644
--- a/app/services/projects/apple_target_platform_detector_service.rb
+++ b/app/services/projects/apple_target_platform_detector_service.rb
@@ -20,7 +20,7 @@ module Projects
# > AppleTargetPlatformDetectorService.new(multiplatform_project).execute
# => [:ios, :osx, :tvos, :watchos]
class AppleTargetPlatformDetectorService < BaseService
- BUILD_CONFIG_FILENAMES = %w(project.pbxproj *.xcconfig).freeze
+ BUILD_CONFIG_FILENAMES = %w[project.pbxproj *.xcconfig].freeze
# For the current iteration, we only want to detect when the project targets
# iOS. In the future, we can use the same logic to detect projects that
diff --git a/app/services/projects/container_repository/cleanup_tags_base_service.rb b/app/services/projects/container_repository/cleanup_tags_base_service.rb
index 45557d03502..61b09de1643 100644
--- a/app/services/projects/container_repository/cleanup_tags_base_service.rb
+++ b/app/services/projects/container_repository/cleanup_tags_base_service.rb
@@ -100,7 +100,7 @@ module Projects
def older_than_in_seconds
strong_memoize(:older_than_in_seconds) do
- ChronicDuration.parse(older_than).seconds
+ ChronicDuration.parse(older_than, use_complete_matcher: true).seconds
end
end
end
diff --git a/app/services/projects/container_repository/gitlab/delete_tags_service.rb b/app/services/projects/container_repository/gitlab/delete_tags_service.rb
index 530cf87c338..a5b7f4bbb6f 100644
--- a/app/services/projects/container_repository/gitlab/delete_tags_service.rb
+++ b/app/services/projects/container_repository/gitlab/delete_tags_service.rb
@@ -39,7 +39,7 @@ module Projects
end
end
- @deleted_tags.any? ? success(deleted: @deleted_tags) : error('could not delete tags')
+ @deleted_tags.any? ? success(deleted: @deleted_tags) : error("could not delete tags: #{@tag_names.join(', ')}".truncate(1000))
end
end
end
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index bca78b88630..e4987438c57 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -144,6 +144,8 @@ module Projects
end
def create_project_settings
+ Gitlab::Pages.add_unique_domain_to(project)
+
@project.project_setting.save if @project.project_setting.changed?
end
@@ -223,22 +225,26 @@ module Projects
end
def save_project_and_import_data
- ApplicationRecord.transaction do
- @project.create_or_update_import_data(data: @import_data[:data], credentials: @import_data[:credentials]) if @import_data
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424281'
+ ) do
+ ApplicationRecord.transaction do
+ @project.create_or_update_import_data(data: @import_data[:data], credentials: @import_data[:credentials]) if @import_data
- # Avoid project callbacks being triggered multiple times by saving the parent first.
- # See https://github.com/rails/rails/issues/41701.
- Namespaces::ProjectNamespace.create_from_project!(@project) if @project.valid?
+ # Avoid project callbacks being triggered multiple times by saving the parent first.
+ # See https://github.com/rails/rails/issues/41701.
+ Namespaces::ProjectNamespace.create_from_project!(@project) if @project.valid?
- if @project.saved?
- Integration.create_from_active_default_integrations(@project, :project_id)
+ if @project.saved?
+ Integration.create_from_active_default_integrations(@project, :project_id)
- @project.create_labels unless @project.gitlab_project_import?
+ @project.create_labels unless @project.gitlab_project_import?
- next if @project.import?
+ next if @project.import?
- unless @project.create_repository(default_branch: default_branch)
- raise 'Failed to create repository'
+ unless @project.create_repository(default_branch: default_branch)
+ raise 'Failed to create repository'
+ end
end
end
end
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 0ae6fcb4d97..a2a2f9d2800 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -255,7 +255,11 @@ module Projects
# We need to remove them when a project is deleted
# rubocop: disable CodeReuse/ActiveRecord
def destroy_project_bots!
- project.members.includes(:user).references(:user).merge(User.project_bot).each do |member|
+ members = project.members
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422405')
+ .includes(:user).references(:user).merge(User.project_bot)
+
+ members.each do |member|
Users::DestroyService.new(current_user).execute(member.user, skip_authorization: true)
end
end
diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb
index 22104409199..d67b7832bf8 100644
--- a/app/services/projects/download_service.rb
+++ b/app/services/projects/download_service.rb
@@ -28,7 +28,7 @@ module Projects
end
def http?(url)
- url =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/
+ url =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/
end
def valid_domain?(url)
diff --git a/app/services/projects/hashed_storage/migrate_attachments_service.rb b/app/services/projects/hashed_storage/migrate_attachments_service.rb
index 023f8494d99..40c4fd5376c 100644
--- a/app/services/projects/hashed_storage/migrate_attachments_service.rb
+++ b/app/services/projects/hashed_storage/migrate_attachments_service.rb
@@ -6,7 +6,7 @@ module Projects
extend ::Gitlab::Utils::Override
# List of paths that can be excluded while evaluation if a target can be discarded
- DISCARDABLE_PATHS = %w(tmp tmp/cache tmp/work).freeze
+ DISCARDABLE_PATHS = %w[tmp tmp/cache tmp/work].freeze
def initialize(project:, old_disk_path:, logger: nil)
super
diff --git a/app/services/projects/import_error_filter.rb b/app/services/projects/import_error_filter.rb
index 737b794484d..a0fc5149bb4 100644
--- a/app/services/projects/import_error_filter.rb
+++ b/app/services/projects/import_error_filter.rb
@@ -4,7 +4,7 @@ module Projects
# Used by project imports, it removes any potential paths
# included in an error message that could be stored in the DB
class ImportErrorFilter
- ERROR_MESSAGE_FILTER = /[^\s]*#{File::SEPARATOR}[^\s]*(?=(\s|\z))/.freeze
+ ERROR_MESSAGE_FILTER = /[^\s]*#{File::SEPARATOR}[^\s]*(?=(\s|\z))/
FILTER_MESSAGE = '[FILTERED]'
def self.filter_message(message)
diff --git a/app/services/projects/in_product_marketing_campaign_emails_service.rb b/app/services/projects/in_product_marketing_campaign_emails_service.rb
index 249a2d89fc1..a549d8f594e 100644
--- a/app/services/projects/in_product_marketing_campaign_emails_service.rb
+++ b/app/services/projects/in_product_marketing_campaign_emails_service.rb
@@ -26,13 +26,9 @@ module Projects
sent_email_records.save!
end
- # rubocop: disable CodeReuse/ActiveRecord
def project_users
- @project_users ||= project.users
- .where(email_opted_in: true)
- .merge(Users::InProductMarketingEmail.without_campaign(campaign))
+ @project_users ||= project.users.merge(Users::InProductMarketingEmail.without_campaign(campaign))
end
- # rubocop: enable CodeReuse/ActiveRecord
def project_users_max_access_levels
ids = project_users.map(&:id)
diff --git a/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb b/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
index 09fec9939b9..0efe9fb16f6 100644
--- a/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb
@@ -9,7 +9,7 @@ module Projects
include Gitlab::Utils::StrongMemoize
HEAD_REV = 'HEAD'
- LFS_ENDPOINT_PATTERN = /^\t?url\s*=\s*(.+)$/.freeze
+ LFS_ENDPOINT_PATTERN = /^\t?url\s*=\s*(.+)$/
LFS_BATCH_API_ENDPOINT = '/info/lfs/objects/batch'
LfsObjectDownloadListError = Class.new(StandardError)
@@ -101,7 +101,7 @@ module Projects
# The import url must end with '.git' here we ensure it is
def default_endpoint_uri
@default_endpoint_uri ||= import_uri.dup.tap do |uri|
- path = uri.path.gsub(%r(/$), '')
+ path = uri.path.gsub(%r{/$}, '')
path += '.git' unless path.ends_with?('.git')
uri.path = path + LFS_BATCH_API_ENDPOINT
end
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 642ec37619f..3d08039942b 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -110,36 +110,40 @@ module Projects
end
def proceed_to_transfer
- Project.transaction do
- project.expire_caches_before_rename(@old_path)
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424282'
+ ) do
+ Project.transaction do
+ project.expire_caches_before_rename(@old_path)
- # Apply changes to the project
- update_namespace_and_visibility(@new_namespace)
- project.reconcile_shared_runners_setting!
- project.save!
+ # Apply changes to the project
+ update_namespace_and_visibility(@new_namespace)
+ project.reconcile_shared_runners_setting!
+ project.save!
- # Notifications
- project.send_move_instructions(@old_path)
+ # Notifications
+ project.send_move_instructions(@old_path)
- # Directories on disk
- move_project_folders(project)
+ # Directories on disk
+ move_project_folders(project)
- transfer_missing_group_resources(@old_group)
+ transfer_missing_group_resources(@old_group)
- # Move uploads
- move_project_uploads(project)
+ # Move uploads
+ move_project_uploads(project)
- update_integrations
+ update_integrations
- remove_paid_features
+ remove_paid_features
- project.old_path_with_namespace = @old_path
+ project.old_path_with_namespace = @old_path
- update_repository_configuration(@new_path)
+ update_repository_configuration(@new_path)
- remove_issue_contacts
+ remove_issue_contacts
- execute_system_hooks
+ execute_system_hooks
+ end
end
update_pending_builds
diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb
index 403f645392c..dc92c501b8c 100644
--- a/app/services/projects/update_pages_service.rb
+++ b/app/services/projects/update_pages_service.rb
@@ -2,10 +2,12 @@
module Projects
class UpdatePagesService < BaseService
+ include Gitlab::Utils::StrongMemoize
+
# old deployment can be cached by pages daemon
# so we need to give pages daemon some time update cache
# 10 minutes is enough, but 30 feels safer
- OLD_DEPLOYMENTS_DESTRUCTION_DELAY = 30.minutes.freeze
+ OLD_DEPLOYMENTS_DESTRUCTION_DELAY = 30.minutes
attr_reader :build, :deployment_update
@@ -18,9 +20,7 @@ module Projects
def execute
register_attempt
- # Create status notifying the deployment of pages
- @commit_status = build_commit_status
- ::Ci::Pipelines::AddJobService.new(@build.pipeline).execute!(@commit_status) do |job|
+ ::Ci::Pipelines::AddJobService.new(@build.pipeline).execute!(commit_status) do |job|
job.enqueue!
job.run!
end
@@ -31,13 +31,10 @@ module Projects
deployment = create_pages_deployment(artifacts_path, build)
break error('The uploaded artifact size does not match the expected value') unless deployment
+ break error(deployment_update.errors.first.full_message) unless deployment_update.valid?
- if deployment_update.valid?
- update_project_pages_deployment(deployment)
- success
- else
- error(deployment_update.errors.first.full_message)
- end
+ update_project_pages_deployment(deployment)
+ success
end
rescue StandardError => e
error(e.message)
@@ -47,7 +44,7 @@ module Projects
private
def success
- @commit_status.success
+ commit_status.success
@project.mark_pages_as_deployed
publish_deployed_event
super
@@ -56,15 +53,14 @@ module Projects
def error(message)
register_failure
log_error("Projects::UpdatePagesService: #{message}")
- @commit_status.allow_failure = !deployment_update.latest?
- @commit_status.description = message
- @commit_status.drop(:script_failure)
+ commit_status.allow_failure = !deployment_update.latest?
+ commit_status.description = message
+ commit_status.drop(:script_failure)
super
end
- def build_commit_status
- stage = create_stage
-
+ # Create status notifying the deployment of pages
+ def commit_status
GenericCommitStatus.new(
user: build.user,
ci_stage: stage,
@@ -73,26 +69,22 @@ module Projects
stage_idx: stage.position
)
end
+ strong_memoize_attr :commit_status
# rubocop: disable Performance/ActiveRecordSubtransactionMethods
- def create_stage
+ def stage
build.pipeline.stages.safe_find_or_create_by(name: 'deploy', pipeline_id: build.pipeline.id) do |stage|
stage.position = GenericCommitStatus::EXTERNAL_STAGE_IDX
stage.project = build.project
end
end
+ strong_memoize_attr :commit_status
# rubocop: enable Performance/ActiveRecordSubtransactionMethods
def create_pages_deployment(artifacts_path, build)
- sha256 = build.job_artifacts_archive.file_sha256
File.open(artifacts_path) do |file|
- deployment = project.pages_deployments.create!(
- file: file,
- file_count: deployment_update.entries_count,
- file_sha256: sha256,
- ci_build_id: build.id,
- root_directory: build.options[:publish]
- )
+ attributes = pages_deployment_attributes(file, build)
+ deployment = project.pages_deployments.create!(**attributes)
break if deployment.size != file.size || deployment.file.size != file.size
@@ -100,21 +92,28 @@ module Projects
end
end
+ # overridden on EE
+ def pages_deployment_attributes(file, build)
+ {
+ file: file,
+ file_count: deployment_update.entries_count,
+ file_sha256: build.job_artifacts_archive.file_sha256,
+ ci_build_id: build.id,
+ root_directory: build.options[:publish]
+ }
+ end
+
def update_project_pages_deployment(deployment)
project.update_pages_deployment!(deployment)
+
+ PagesDeployment.deactivate_deployments_older_than(
+ deployment,
+ time: OLD_DEPLOYMENTS_DESTRUCTION_DELAY.from_now)
+
DestroyPagesDeploymentsWorker.perform_in(
OLD_DEPLOYMENTS_DESTRUCTION_DELAY,
project.id,
- deployment.id
- )
- end
-
- def ref
- build.ref
- end
-
- def artifacts
- build.artifacts_file.path
+ deployment.id)
end
def register_attempt
@@ -126,12 +125,14 @@ module Projects
end
def pages_deployments_total_counter
- @pages_deployments_total_counter ||= Gitlab::Metrics.counter(:pages_deployments_total, "Counter of GitLab Pages deployments triggered")
+ Gitlab::Metrics.counter(:pages_deployments_total, "Counter of GitLab Pages deployments triggered")
end
+ strong_memoize_attr :pages_deployments_total_counter
def pages_deployments_failed_total_counter
- @pages_deployments_failed_total_counter ||= Gitlab::Metrics.counter(:pages_deployments_failed_total, "Counter of GitLab Pages deployments which failed")
+ Gitlab::Metrics.counter(:pages_deployments_failed_total, "Counter of GitLab Pages deployments which failed")
end
+ strong_memoize_attr :pages_deployments_failed_total_counter
def publish_deployed_event
event = ::Pages::PageDeployedEvent.new(data: {
@@ -144,3 +145,5 @@ module Projects
end
end
end
+
+::Projects::UpdatePagesService.prepend_mod
diff --git a/app/services/projects/update_repository_storage_service.rb b/app/services/projects/update_repository_storage_service.rb
index f5f6bb85995..799ae5677c3 100644
--- a/app/services/projects/update_repository_storage_service.rb
+++ b/app/services/projects/update_repository_storage_service.rb
@@ -80,8 +80,8 @@ module Projects
end
def pool_repository_exists_for?(shard_name:, pool_repository:)
- PoolRepository.by_source_project_and_shard_name(
- pool_repository.source_project,
+ PoolRepository.by_disk_path_and_shard_name(
+ pool_repository.disk_path,
shard_name
).exists?
end
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 8639e2f833f..e5e39247dbf 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -53,13 +53,7 @@ module Projects
def add_pages_unique_domain
return unless params.dig(:project_setting_attributes, :pages_unique_domain_enabled)
- # If the project used a unique domain once, it'll always use the same
- return if project.project_setting.pages_unique_domain_in_database.present?
-
- params[:project_setting_attributes][:pages_unique_domain] = Gitlab::Pages::RandomDomain.generate(
- project_path: project.path,
- namespace_path: project.parent.full_path
- )
+ Gitlab::Pages.add_unique_domain_to(project)
end
def validate!
@@ -112,6 +106,7 @@ module Projects
# overridden by EE module
end
+ # overridden by EE module
def remove_unallowed_params
params.delete(:emails_enabled) unless can?(current_user, :set_emails_disabled, project)
@@ -119,11 +114,11 @@ module Projects
end
def after_update
- todos_features_changes = %w(
+ todos_features_changes = %w[
issues_access_level
merge_requests_access_level
repository_access_level
- )
+ ]
project_changed_feature_keys = project.project_feature.previous_changes.keys
if project.visibility_level_previous_changes && project.private?
diff --git a/app/services/releases/destroy_service.rb b/app/services/releases/destroy_service.rb
index ff2b3a7bd18..41b421662ef 100644
--- a/app/services/releases/destroy_service.rb
+++ b/app/services/releases/destroy_service.rb
@@ -7,6 +7,8 @@ module Releases
return error(_('Access Denied'), 403) unless allowed?
if release.destroy
+ update_catalog_resource!
+
success(tag: existing_tag, release: release)
else
error(release.errors.messages || '400 Bad request', 400)
@@ -15,6 +17,14 @@ module Releases
private
+ def update_catalog_resource!
+ return unless project.catalog_resource
+
+ return unless project.catalog_resource.versions.none?
+
+ project.catalog_resource.update!(state: 'draft')
+ end
+
def allowed?
Ability.allowed?(current_user, :destroy_release, release)
end
diff --git a/app/services/repositories/base_service.rb b/app/services/repositories/base_service.rb
index b262b4a1f7b..bf7ac2e5fd8 100644
--- a/app/services/repositories/base_service.rb
+++ b/app/services/repositories/base_service.rb
@@ -29,7 +29,7 @@ class Repositories::BaseService < BaseService
end
def move_error(path)
- error = %{Repository "#{path}" could not be moved}
+ error = %(Repository "#{path}" could not be moved)
log_error(error)
error(error)
diff --git a/app/services/repository_archive_clean_up_service.rb b/app/services/repository_archive_clean_up_service.rb
index 0fb7dfdb85f..4258898c665 100644
--- a/app/services/repository_archive_clean_up_service.rb
+++ b/app/services/repository_archive_clean_up_service.rb
@@ -37,7 +37,7 @@ class RepositoryArchiveCleanUpService
private
def clean_up_old_archives
- run(%W(find #{path} -mindepth 1 -maxdepth #{MAX_ARCHIVE_DEPTH} -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -mmin +#{mmin} -delete))
+ run(%W[find #{path} -mindepth 1 -maxdepth #{MAX_ARCHIVE_DEPTH} -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -mmin +#{mmin} -delete])
end
def clean_up_empty_directories
@@ -45,7 +45,7 @@ class RepositoryArchiveCleanUpService
end
def clean_up_empty_directories_with_depth(depth)
- run(%W(find #{path} -mindepth #{depth} -maxdepth #{depth} -type d -empty -delete))
+ run(%W[find #{path} -mindepth #{depth} -maxdepth #{depth} -type d -empty -delete])
end
def run(cmd)
diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb
index 1fea894a599..1c496aa5e77 100644
--- a/app/services/resource_access_tokens/create_service.rb
+++ b/app/services/resource_access_tokens/create_service.rb
@@ -60,7 +60,7 @@ module ResourceAccessTokens
strong_memoize_attr :username_and_email_generator
def has_permission_to_create?
- %w(project group).include?(resource_type) && can?(current_user, :create_resource_access_tokens, resource)
+ %w[project group].include?(resource_type) && can?(current_user, :create_resource_access_tokens, resource)
end
def create_user
diff --git a/app/services/resource_access_tokens/revoke_service.rb b/app/services/resource_access_tokens/revoke_service.rb
index 2aaf4cc31d2..46c71b04632 100644
--- a/app/services/resource_access_tokens/revoke_service.rb
+++ b/app/services/resource_access_tokens/revoke_service.rb
@@ -38,7 +38,7 @@ module ResourceAccessTokens
end
def can_destroy_token?
- %w(project group).include?(resource.class.name.downcase) && can?(current_user, :destroy_resource_access_tokens, resource)
+ %w[project group].include?(resource.class.name.downcase) && can?(current_user, :destroy_resource_access_tokens, resource)
end
def find_member
diff --git a/app/services/resource_events/base_change_timebox_service.rb b/app/services/resource_events/base_change_timebox_service.rb
index ba7c9d90713..d0b0f635ed2 100644
--- a/app/services/resource_events/base_change_timebox_service.rb
+++ b/app/services/resource_events/base_change_timebox_service.rb
@@ -14,7 +14,7 @@ module ResourceEvents
track_event
- resource.expire_note_etag_cache
+ resource.broadcast_notes_changed
end
private
diff --git a/app/services/resource_events/change_labels_service.rb b/app/services/resource_events/change_labels_service.rb
index 69e68922b91..f0ebf7fb40b 100644
--- a/app/services/resource_events/change_labels_service.rb
+++ b/app/services/resource_events/change_labels_service.rb
@@ -31,7 +31,7 @@ module ResourceEvents
end
create_timeline_events_from(added_labels: added_labels, removed_labels: removed_labels)
- resource.expire_note_etag_cache
+ resource.broadcast_notes_changed
return unless resource.is_a?(Issue)
diff --git a/app/services/resource_events/change_state_service.rb b/app/services/resource_events/change_state_service.rb
index a396f7a1907..303d666c8e2 100644
--- a/app/services/resource_events/change_state_service.rb
+++ b/app/services/resource_events/change_state_service.rb
@@ -23,7 +23,7 @@ module ResourceEvents
created_at: resource.system_note_timestamp
)
- resource.expire_note_etag_cache
+ resource.broadcast_notes_changed
end
private
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index f4c0a743ef0..24549b1498b 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -6,7 +6,7 @@ module Search
include Gitlab::Utils::StrongMemoize
DEFAULT_SCOPE = 'projects'
- ALLOWED_SCOPES = %w(projects issues merge_requests milestones users).freeze
+ ALLOWED_SCOPES = %w[projects issues merge_requests milestones users].freeze
attr_accessor :current_user, :params
diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb
index 73d46a9ba70..24613dc2564 100644
--- a/app/services/search/project_service.rb
+++ b/app/services/search/project_service.rb
@@ -5,7 +5,7 @@ module Search
include Search::Filter
include Gitlab::Utils::StrongMemoize
- ALLOWED_SCOPES = %w(blobs issues merge_requests wiki_blobs commits notes milestones users).freeze
+ ALLOWED_SCOPES = %w[blobs issues merge_requests wiki_blobs commits notes milestones users].freeze
attr_accessor :project, :current_user, :params
diff --git a/app/services/service_desk/custom_email_verifications/base_service.rb b/app/services/service_desk/custom_email_verifications/base_service.rb
index fe456e4d3f3..e92700022f1 100644
--- a/app/services/service_desk/custom_email_verifications/base_service.rb
+++ b/app/services/service_desk/custom_email_verifications/base_service.rb
@@ -3,6 +3,8 @@
module ServiceDesk
module CustomEmailVerifications
class BaseService < ::BaseProjectService
+ include ::ServiceDesk::CustomEmails::Logger
+
attr_reader :settings
def initialize(project:, current_user: nil, params: {})
@@ -35,15 +37,21 @@ module ServiceDesk
end
def error_response(message)
+ log_warning(error_message: message)
ServiceResponse.error(message: message)
end
def error_not_verified(error_identifier)
+ log_info(error_message: error_identifier.to_s)
ServiceResponse.error(
message: _('ServiceDesk|Custom email address could not be verified.'),
reason: error_identifier.to_s
)
end
+
+ def log_category
+ 'custom_email_verification'
+ end
end
end
end
diff --git a/app/services/service_desk/custom_email_verifications/create_service.rb b/app/services/service_desk/custom_email_verifications/create_service.rb
index db518bfdf24..9c5721446a1 100644
--- a/app/services/service_desk/custom_email_verifications/create_service.rb
+++ b/app/services/service_desk/custom_email_verifications/create_service.rb
@@ -17,6 +17,7 @@ module ServiceDesk
if ramp_up_error
handle_error_case
else
+ log_info
ServiceResponse.success
end
end
@@ -63,11 +64,11 @@ module ServiceDesk
end
def error_settings_missing
- error_response(_('ServiceDesk|Service Desk setting missing'))
+ error_response(s_('ServiceDesk|Service Desk setting missing'))
end
def error_user_not_authorized
- error_response(_('ServiceDesk|User cannot manage project.'))
+ error_response(s_('ServiceDesk|User cannot manage project.'))
end
end
end
diff --git a/app/services/service_desk/custom_email_verifications/update_service.rb b/app/services/service_desk/custom_email_verifications/update_service.rb
index 813624cde23..5ef36ce0576 100644
--- a/app/services/service_desk/custom_email_verifications/update_service.rb
+++ b/app/services/service_desk/custom_email_verifications/update_service.rb
@@ -24,6 +24,7 @@ module ServiceDesk
else
verification.mark_as_finished!
+ log_info
ServiceResponse.success
end
end
@@ -75,15 +76,15 @@ module ServiceDesk
end
def error_parameter_missing
- error_response(_('ServiceDesk|Service Desk setting or verification object missing'))
+ error_response(s_('ServiceDesk|Service Desk setting or verification object missing'))
end
def error_already_finished
- error_response(_('ServiceDesk|Custom email address has already been verified.'))
+ error_response(s_('ServiceDesk|Custom email address has already been verified.'))
end
def error_already_failed
- error_response(_('ServiceDesk|Custom email address verification has already been processed and failed.'))
+ error_response(s_('ServiceDesk|Custom email address verification has already been processed and failed.'))
end
end
end
diff --git a/app/services/service_desk/custom_emails/base_service.rb b/app/services/service_desk/custom_emails/base_service.rb
index 62152f31012..91f4100a8ca 100644
--- a/app/services/service_desk/custom_emails/base_service.rb
+++ b/app/services/service_desk/custom_emails/base_service.rb
@@ -3,6 +3,8 @@
module ServiceDesk
module CustomEmails
class BaseService < ::BaseProjectService
+ include Logger
+
private
def legitimate_user?
@@ -34,6 +36,7 @@ module ServiceDesk
end
def error_response(message)
+ log_warning(error_message: message)
ServiceResponse.error(message: message)
end
end
diff --git a/app/services/service_desk/custom_emails/create_service.rb b/app/services/service_desk/custom_emails/create_service.rb
index c3ca98a0259..305f5b3fa11 100644
--- a/app/services/service_desk/custom_emails/create_service.rb
+++ b/app/services/service_desk/custom_emails/create_service.rb
@@ -25,6 +25,7 @@ module ServiceDesk
# we don't use its response here.
create_verification
+ log_info
ServiceResponse.success
end
diff --git a/app/services/service_desk/custom_emails/destroy_service.rb b/app/services/service_desk/custom_emails/destroy_service.rb
index 1aa5994edd8..abbe39646aa 100644
--- a/app/services/service_desk/custom_emails/destroy_service.rb
+++ b/app/services/service_desk/custom_emails/destroy_service.rb
@@ -13,6 +13,7 @@ module ServiceDesk
project.reset
project.service_desk_setting&.update!(custom_email: nil, custom_email_enabled: false)
+ log_info
ServiceResponse.success
end
diff --git a/app/services/service_desk_settings/update_service.rb b/app/services/service_desk_settings/update_service.rb
index 61cb6fce11f..182022beb1d 100644
--- a/app/services/service_desk_settings/update_service.rb
+++ b/app/services/service_desk_settings/update_service.rb
@@ -2,12 +2,19 @@
module ServiceDeskSettings
class UpdateService < BaseService
+ include ::ServiceDesk::CustomEmails::Logger
+
def execute
settings = ServiceDeskSetting.safe_find_or_create_by!(project_id: project.id)
params[:project_key] = nil if params[:project_key].blank?
+ # We want to know when custom email got enabled
+ write_log_message = params[:custom_email_enabled].present? && !settings.custom_email_enabled?
+
if settings.update(params)
+ log_info if write_log_message
+
ServiceResponse.success
else
ServiceResponse.error(message: settings.errors.full_messages.to_sentence)
diff --git a/app/services/service_response.rb b/app/services/service_response.rb
index 86efc01bd30..fbc5660315b 100644
--- a/app/services/service_response.rb
+++ b/app/services/service_response.rb
@@ -2,18 +2,22 @@
class ServiceResponse
def self.success(message: nil, payload: {}, http_status: :ok)
- new(status: :success,
- message: message,
- payload: payload,
- http_status: http_status)
+ new(
+ status: :success,
+ message: message,
+ payload: payload,
+ http_status: http_status
+ )
end
def self.error(message:, payload: {}, http_status: nil, reason: nil)
- new(status: :error,
- message: message,
- payload: payload,
- http_status: http_status,
- reason: reason)
+ new(
+ status: :error,
+ message: message,
+ payload: payload,
+ http_status: http_status,
+ reason: reason
+ )
end
attr_reader :status, :message, :http_status, :payload, :reason
diff --git a/app/services/snippets/update_service.rb b/app/services/snippets/update_service.rb
index 662e31a93aa..8cc6458227f 100644
--- a/app/services/snippets/update_service.rb
+++ b/app/services/snippets/update_service.rb
@@ -2,7 +2,7 @@
module Snippets
class UpdateService < Snippets::BaseService
- COMMITTABLE_ATTRIBUTES = %w(file_name content).freeze
+ COMMITTABLE_ATTRIBUTES = %w[file_name content].freeze
UpdateError = Class.new(StandardError)
diff --git a/app/services/spam/akismet_service.rb b/app/services/spam/akismet_service.rb
index d31b904f549..fd2b3c9a441 100644
--- a/app/services/spam/akismet_service.rb
+++ b/app/services/spam/akismet_service.rb
@@ -50,8 +50,10 @@ module Spam
attr_accessor :owner_name, :owner_email
def akismet_client
- @akismet_client ||= ::Akismet::Client.new(Gitlab::CurrentSettings.akismet_api_key,
- Gitlab.config.gitlab.url)
+ @akismet_client ||= ::Akismet::Client.new(
+ Gitlab::CurrentSettings.akismet_api_key,
+ Gitlab.config.gitlab.url
+ )
end
def akismet_enabled?
diff --git a/app/services/spam/spam_action_service.rb b/app/services/spam/spam_action_service.rb
index 5c510990b2d..6ec8d09c37c 100644
--- a/app/services/spam/spam_action_service.rb
+++ b/app/services/spam/spam_action_service.rb
@@ -76,10 +76,9 @@ module Spam
spam_verdict_service.execute.tap do |result|
case result
when BLOCK_USER
- # TODO: improve BLOCK_USER handling, non-existent until now
- # https://gitlab.com/gitlab-org/gitlab/-/issues/329666
target.spam!
create_spam_log
+ ban_user!
when DISALLOW
target.spam!
create_spam_log
@@ -119,6 +118,12 @@ module Spam
target.spam_log = spam_log
end
+ def ban_user!
+ UserCustomAttribute.set_banned_by_spam_log(target.spam_log)
+
+ user.ban!
+ end
+
def spam_verdict_service
context = {
action: action,
@@ -131,12 +136,13 @@ module Spam
referer: spam_params&.referer
}
- SpamVerdictService.new(target: target,
- user: user,
- options: options,
- context: context,
- extra_features: extra_features
- )
+ SpamVerdictService.new(
+ target: target,
+ user: user,
+ options: options,
+ context: context,
+ extra_features: extra_features
+ )
end
def noteable_type
diff --git a/app/services/spam/spam_verdict_service.rb b/app/services/spam/spam_verdict_service.rb
index 639d99ad906..9efe51b43b8 100644
--- a/app/services/spam/spam_verdict_service.rb
+++ b/app/services/spam/spam_verdict_service.rb
@@ -36,16 +36,17 @@ module Spam
# The target can override the verdict via the `allow_possible_spam` application setting
final_verdict = OVERRIDE_VIA_ALLOW_POSSIBLE_SPAM if override_via_allow_possible_spam?(verdict: final_verdict)
- logger.info(class: self.class.name,
- akismet_verdict: akismet_verdict,
- spam_check_verdict: spamcheck_verdict,
- spam_check_rtt: external_spam_check_round_trip_time.real,
- final_verdict: final_verdict,
- username: user.username,
- user_id: user.id,
- target_type: target.class.to_s,
- project_id: target.project_id
- )
+ logger.info(
+ class: self.class.name,
+ akismet_verdict: akismet_verdict,
+ spam_check_verdict: spamcheck_verdict,
+ spam_check_rtt: external_spam_check_round_trip_time.real,
+ final_verdict: final_verdict,
+ username: user.username,
+ user_id: user.id,
+ target_type: target.class.to_s,
+ project_id: target.project_id
+ )
final_verdict
end
diff --git a/app/services/submodules/update_service.rb b/app/services/submodules/update_service.rb
index a6011a920bd..4a573e595ce 100644
--- a/app/services/submodules/update_service.rb
+++ b/app/services/submodules/update_service.rb
@@ -26,11 +26,13 @@ module Submodules
end
def create_commit!
- repository.update_submodule(current_user,
- @submodule,
- @commit_sha,
- message: @commit_message,
- branch: @branch_name)
+ repository.update_submodule(
+ current_user,
+ @submodule,
+ @commit_sha,
+ message: @commit_message,
+ branch: @branch_name
+ )
rescue ArgumentError, TypeError
raise ValidationError, 'Invalid parameters'
end
diff --git a/app/services/suggestions/create_service.rb b/app/services/suggestions/create_service.rb
index 239cd86e0ec..d7c261f1c25 100644
--- a/app/services/suggestions/create_service.rb
+++ b/app/services/suggestions/create_service.rb
@@ -9,20 +9,22 @@ module Suggestions
def execute
return unless @note.supports_suggestion?
- suggestions = Gitlab::Diff::SuggestionsParser.parse(@note.note,
- project: @note.project,
- position: @note.position)
+ suggestions = Gitlab::Diff::SuggestionsParser.parse(
+ @note.note,
+ project: @note.project,
+ position: @note.position
+ )
- rows =
- suggestions.map.with_index do |suggestion, index|
- creation_params =
- suggestion.to_hash.slice(:from_content,
- :to_content,
- :lines_above,
- :lines_below)
+ rows = suggestions.map.with_index do |suggestion, index|
+ creation_params = suggestion.to_hash.slice(
+ :from_content,
+ :to_content,
+ :lines_above,
+ :lines_below
+ )
- creation_params.merge!(note_id: @note.id, relative_order: index)
- end
+ creation_params.merge!(note_id: @note.id, relative_order: index)
+ end
rows.in_groups_of(100, false) do |rows|
ApplicationRecord.legacy_bulk_insert('suggestions', rows) # rubocop:disable Gitlab/BulkInsert
diff --git a/app/services/system_notes/alert_management_service.rb b/app/services/system_notes/alert_management_service.rb
index 994e3174668..1a1dd84491a 100644
--- a/app/services/system_notes/alert_management_service.rb
+++ b/app/services/system_notes/alert_management_service.rb
@@ -14,7 +14,7 @@ module SystemNotes
def create_new_alert(monitoring_tool)
body = "logged an alert from **#{monitoring_tool}**"
- create_note(NoteSummary.new(noteable, project, User.alert_bot, body, action: 'new_alert_added'))
+ create_note(NoteSummary.new(noteable, project, Users::Internal.alert_bot, body, action: 'new_alert_added'))
end
# Called when the status of an AlertManagement::Alert has changed
@@ -61,7 +61,7 @@ module SystemNotes
def log_resolving_alert(monitoring_tool)
body = "logged a recovery alert from **#{monitoring_tool}**"
- create_note(NoteSummary.new(noteable, project, User.alert_bot, body, action: 'new_alert_added'))
+ create_note(NoteSummary.new(noteable, project, Users::Internal.alert_bot, body, action: 'new_alert_added'))
end
end
end
diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb
index 61a4316e8ae..04ae734a8fe 100644
--- a/app/services/system_notes/issuables_service.rb
+++ b/app/services/system_notes/issuables_service.rb
@@ -32,8 +32,7 @@ module SystemNotes
#
# Returns the created Note object
def relate_issuable(noteable_ref)
- issuable_type = noteable.to_ability_name.humanize(capitalize: false)
- body = "marked this #{issuable_type} as related to #{noteable_ref.to_reference(noteable.resource_parent)}"
+ body = "marked this #{noteable_name} as related to #{noteable_ref.to_reference(noteable.resource_parent)}"
track_issue_event(:track_issue_related_action)
@@ -351,12 +350,12 @@ module SystemNotes
# Returns the created Note object
def change_issue_confidentiality
if noteable.confidential
- body = 'made the issue confidential'
+ body = "made the #{noteable_name} confidential"
action = 'confidential'
track_issue_event(:track_issue_made_confidential_action)
else
- body = 'made the issue visible to everyone'
+ body = "made the #{noteable_name} visible to everyone"
action = 'visible'
track_issue_event(:track_issue_made_visible_action)
@@ -534,6 +533,12 @@ module SystemNotes
issue_activity_counter.public_send(event_name, author: author, project: project || noteable.project) # rubocop: disable GitlabSecurity/PublicSend
end
+
+ def noteable_name
+ name = noteable.try(:issue_type) || noteable.to_ability_name
+
+ name.humanize(capitalize: false)
+ end
end
end
diff --git a/app/services/todos/destroy/destroyed_issuable_service.rb b/app/services/todos/destroy/destroyed_issuable_service.rb
index 759c430ec7a..6ba286458df 100644
--- a/app/services/todos/destroy/destroyed_issuable_service.rb
+++ b/app/services/todos/destroy/destroyed_issuable_service.rb
@@ -8,7 +8,7 @@ module Todos
# Since we are moving towards work items, in some instances we create todos with
# `target_type: WorkItem` in other instances we still create todos with `target_type: Issue`
# So when an issue/work item is deleted, we just make sure to delete todos for both target types
- BOUND_TARGET_TYPES = %w(Issue WorkItem).freeze
+ BOUND_TARGET_TYPES = %w[Issue WorkItem].freeze
def initialize(target_id, target_type)
@target_id = target_id
diff --git a/app/services/todos/destroy/entity_leave_service.rb b/app/services/todos/destroy/entity_leave_service.rb
index 5b04d2fd3af..387c5ce063a 100644
--- a/app/services/todos/destroy/entity_leave_service.rb
+++ b/app/services/todos/destroy/entity_leave_service.rb
@@ -8,7 +8,7 @@ module Todos
attr_reader :user, :entity
def initialize(user_id, entity_id, entity_type)
- unless %w(Group Project).include?(entity_type)
+ unless %w[Group Project].include?(entity_type)
raise ArgumentError, "#{entity_type} is not an entity user can leave"
end
diff --git a/app/services/users/activity_service.rb b/app/services/users/activity_service.rb
index 24aa4aa1061..b490df6a134 100644
--- a/app/services/users/activity_service.rb
+++ b/app/services/users/activity_service.rb
@@ -30,11 +30,9 @@ module Users
return if Gitlab::Database.read_only?
today = Date.today
-
return if user.last_activity_on == today
- lease = Gitlab::ExclusiveLease.new("activity_service:#{user.id}",
- timeout: LEASE_TIMEOUT)
+ lease = Gitlab::ExclusiveLease.new("activity_service:#{user.id}", timeout: LEASE_TIMEOUT)
return unless lease.try_obtain
user.update_attribute(:last_activity_on, today)
diff --git a/app/services/users/authorized_build_service.rb b/app/services/users/authorized_build_service.rb
index 5029105b087..446c897fe5a 100644
--- a/app/services/users/authorized_build_service.rb
+++ b/app/services/users/authorized_build_service.rb
@@ -12,7 +12,7 @@ module Users
end
def signup_params
- super + [:skip_confirmation]
+ super + [:skip_confirmation, :external]
end
end
end
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index 04a11f41eb1..b51684c6899 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -5,8 +5,8 @@ module Users
ALLOWED_USER_TYPES = %i[project_bot security_policy_bot].freeze
delegate :user_default_internal_regex_enabled?,
- :user_default_internal_regex_instance,
- to: :'Gitlab::CurrentSettings.current_application_settings'
+ :user_default_internal_regex_instance,
+ to: :'Gitlab::CurrentSettings.current_application_settings'
def initialize(current_user, params = {})
@current_user = current_user
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index d4c00a4dcec..a0e1167836b 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -59,9 +59,6 @@ module Users
Groups::DestroyService.new(group, current_user).execute
end
- namespace = user.namespace
- namespace.prepare_for_destroy
-
user.personal_projects.each do |project|
success = ::Projects::DestroyService.new(project, current_user).execute
raise DestroyError, "Project #{project.id} can't be deleted" unless success
@@ -70,9 +67,11 @@ module Users
yield(user) if block_given?
hard_delete = options.fetch(:hard_delete, false)
- Users::GhostUserMigration.create!(user: user,
- initiator_user: current_user,
- hard_delete: hard_delete)
+ Users::GhostUserMigration.create!(
+ user: user,
+ initiator_user: current_user,
+ hard_delete: hard_delete
+ )
update_metrics
end
diff --git a/app/services/users/migrate_records_to_ghost_user_in_batches_service.rb b/app/services/users/migrate_records_to_ghost_user_in_batches_service.rb
index d294312cc30..e05f308343d 100644
--- a/app/services/users/migrate_records_to_ghost_user_in_batches_service.rb
+++ b/app/services/users/migrate_records_to_ghost_user_in_batches_service.rb
@@ -12,9 +12,11 @@ module Users
ghost_user_migrations.each do |job|
break if execution_tracker.over_limit?
- service = Users::MigrateRecordsToGhostUserService.new(job.user,
- job.initiator_user,
- execution_tracker)
+ service = Users::MigrateRecordsToGhostUserService.new(
+ job.user,
+ job.initiator_user,
+ execution_tracker
+ )
service.execute(hard_delete: job.hard_delete)
rescue Gitlab::Utils::ExecutionTracker::ExecutionTimeOutError
# no-op
diff --git a/app/services/users/migrate_records_to_ghost_user_service.rb b/app/services/users/migrate_records_to_ghost_user_service.rb
index 5d518803315..06950292fea 100644
--- a/app/services/users/migrate_records_to_ghost_user_service.rb
+++ b/app/services/users/migrate_records_to_ghost_user_service.rb
@@ -18,7 +18,7 @@ module Users
@user = user
@initiator_user = initiator_user
@execution_tracker = execution_tracker
- @ghost_user = User.ghost
+ @ghost_user = Users::Internal.ghost
end
def execute(hard_delete: false)
diff --git a/app/services/users/refresh_authorized_projects_service.rb b/app/services/users/refresh_authorized_projects_service.rb
index 197260a80ca..32acc3f170d 100644
--- a/app/services/users/refresh_authorized_projects_service.rb
+++ b/app/services/users/refresh_authorized_projects_service.rb
@@ -82,15 +82,17 @@ module Users
attr_reader :incorrect_auth_found_callback, :missing_auth_found_callback
def log_refresh_details(remove, add)
- Gitlab::AppJsonLogger.info(event: 'authorized_projects_refresh',
- user_id: user.id,
- 'authorized_projects_refresh.source': source,
- 'authorized_projects_refresh.rows_deleted_count': remove.length,
- 'authorized_projects_refresh.rows_added_count': add.length,
- # most often there's only a few entries in remove and add, but limit it to the first 5
- # entries to avoid flooding the logs
- 'authorized_projects_refresh.rows_deleted_slice': remove.first(5),
- 'authorized_projects_refresh.rows_added_slice': add.first(5).map(&:values))
+ Gitlab::AppJsonLogger.info(
+ event: 'authorized_projects_refresh',
+ user_id: user.id,
+ 'authorized_projects_refresh.source': source,
+ 'authorized_projects_refresh.rows_deleted_count': remove.length,
+ 'authorized_projects_refresh.rows_added_count': add.length,
+ # most often there's only a few entries in remove and add, but limit it to the first 5
+ # entries to avoid flooding the logs
+ 'authorized_projects_refresh.rows_deleted_slice': remove.first(5),
+ 'authorized_projects_refresh.rows_added_slice': add.first(5).map(&:values)
+ )
end
end
end
diff --git a/app/services/users/upsert_credit_card_validation_service.rb b/app/services/users/upsert_credit_card_validation_service.rb
index 61cf598f178..62df676db25 100644
--- a/app/services/users/upsert_credit_card_validation_service.rb
+++ b/app/services/users/upsert_credit_card_validation_service.rb
@@ -7,8 +7,10 @@ module Users
end
def execute
+ user_id = params.fetch(:user_id)
+
@params = {
- user_id: params.fetch(:user_id),
+ user_id: user_id,
credit_card_validated_at: params.fetch(:credit_card_validated_at),
expiration_date: get_expiration_date(params),
last_digits: Integer(params.fetch(:credit_card_mask_number), 10),
@@ -16,7 +18,9 @@ module Users
holder_name: params.fetch(:credit_card_holder_name)
}
- ::Users::CreditCardValidation.upsert(@params)
+ credit_card = Users::CreditCardValidation.find_or_initialize_by_user(user_id)
+
+ credit_card.update(@params.except(:user_id))
ServiceResponse.success(message: 'CreditCardValidation was set')
rescue ActiveRecord::InvalidForeignKey, ActiveRecord::NotNullViolation => e
diff --git a/app/services/webauthn/authenticate_service.rb b/app/services/webauthn/authenticate_service.rb
index 52437a77df8..7855b509595 100644
--- a/app/services/webauthn/authenticate_service.rb
+++ b/app/services/webauthn/authenticate_service.rb
@@ -40,8 +40,8 @@ module Webauthn
# (which is done in #verify_webauthn_credential)
def validate_webauthn_credential(webauthn_credential)
webauthn_credential.type == WebAuthn::TYPE_PUBLIC_KEY &&
- webauthn_credential.raw_id && webauthn_credential.id &&
- webauthn_credential.raw_id == WebAuthn.standard_encoder.decode(webauthn_credential.id)
+ webauthn_credential.raw_id && webauthn_credential.id &&
+ webauthn_credential.raw_id == WebAuthn.standard_encoder.decode(webauthn_credential.id)
end
##
@@ -53,9 +53,10 @@ module Webauthn
rp_id = webauthn_credential.client_extension_outputs['appid'] ? WebAuthn.configuration.origin : URI(WebAuthn.configuration.origin).host
webauthn_credential.response.verify(
encoder.decode(challenge),
- public_key: encoder.decode(stored_credential.public_key),
- sign_count: stored_credential.counter,
- rp_id: rp_id)
+ public_key: encoder.decode(stored_credential.public_key),
+ sign_count: stored_credential.counter,
+ rp_id: rp_id
+ )
end
end
end
diff --git a/app/services/work_items/callbacks/award_emoji.rb b/app/services/work_items/callbacks/award_emoji.rb
index 6344813d4b9..9ff5b6d049d 100644
--- a/app/services/work_items/callbacks/award_emoji.rb
+++ b/app/services/work_items/callbacks/award_emoji.rb
@@ -15,7 +15,8 @@ module WorkItems
def execute_emoji_service(action, name)
class_name = {
add: ::AwardEmojis::AddService,
- remove: ::AwardEmojis::DestroyService
+ remove: ::AwardEmojis::DestroyService,
+ toggle: ::AwardEmojis::ToggleService
}
raise_error(invalid_action_error(action)) unless class_name.key?(action)
diff --git a/app/services/work_items/create_service.rb b/app/services/work_items/create_service.rb
index 903736cf662..354a33a0384 100644
--- a/app/services/work_items/create_service.rb
+++ b/app/services/work_items/create_service.rb
@@ -32,8 +32,11 @@ module WorkItems
end
def before_create(work_item)
- execute_widgets(work_item: work_item, callback: :before_create_callback,
- widget_params: @widget_params)
+ execute_widgets(
+ work_item: work_item,
+ callback: :before_create_callback,
+ widget_params: @widget_params
+ )
super
end
@@ -41,8 +44,11 @@ module WorkItems
def transaction_create(work_item)
super.tap do |save_result|
if save_result
- execute_widgets(work_item: work_item, callback: :after_create_in_transaction,
- widget_params: @widget_params)
+ execute_widgets(
+ work_item: work_item,
+ callback: :after_create_in_transaction,
+ widget_params: @widget_params
+ )
end
end
end
diff --git a/app/services/work_items/related_work_item_links/create_service.rb b/app/services/work_items/related_work_item_links/create_service.rb
index 6a9ddd5c83d..f313881470a 100644
--- a/app/services/work_items/related_work_item_links/create_service.rb
+++ b/app/services/work_items/related_work_item_links/create_service.rb
@@ -25,7 +25,7 @@ module WorkItems
end
def previous_related_issuables
- @related_issues ||= issuable.related_issues(current_user).to_a
+ @related_issues ||= issuable.linked_work_items(authorize: false).to_a
end
private
diff --git a/app/services/work_items/related_work_item_links/destroy_service.rb b/app/services/work_items/related_work_item_links/destroy_service.rb
new file mode 100644
index 00000000000..6d1920d01b2
--- /dev/null
+++ b/app/services/work_items/related_work_item_links/destroy_service.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module RelatedWorkItemLinks
+ class DestroyService < BaseService
+ def initialize(work_item, user, params)
+ @work_item = work_item
+ @current_user = user
+ @params = params.dup
+ @failed_ids = []
+ @removed_ids = []
+ end
+
+ def execute
+ return error(_('No work item found.'), 403) unless can?(current_user, :admin_work_item_link, work_item)
+ return error(_('No work item IDs provided.'), 409) if params[:item_ids].empty?
+
+ destroy_links_for(params[:item_ids])
+
+ if removed_ids.any?
+ success(message: response_message, items_removed: removed_ids, items_with_errors: failed_ids.flatten)
+ else
+ error(error_message)
+ end
+ end
+
+ private
+
+ attr_reader :work_item, :current_user, :failed_ids, :removed_ids
+
+ def destroy_links_for(item_ids)
+ destroy_links(source: work_item, target: item_ids, direction: :target)
+ destroy_links(source: item_ids, target: work_item, direction: :source)
+ end
+
+ def destroy_links(source:, target:, direction:)
+ WorkItems::RelatedWorkItemLink.for_source_and_target(source, target).each do |link|
+ linked_item = link.try(direction)
+
+ if can?(current_user, :admin_work_item_link, linked_item)
+ link.destroy!
+ removed_ids << linked_item.id
+ create_notes(link)
+ else
+ failed_ids << linked_item.id
+ end
+ end
+ end
+
+ def create_notes(link)
+ SystemNoteService.unrelate_issuable(link.source, link.target, current_user)
+ SystemNoteService.unrelate_issuable(link.target, link.source, current_user)
+ end
+
+ def error_message
+ not_linked = params[:item_ids] - (removed_ids + failed_ids)
+ error_messages = []
+
+ if failed_ids.any?
+ error_messages << format(
+ _('%{item_ids} could not be removed due to insufficient permissions'), item_ids: failed_ids.to_sentence
+ )
+ end
+
+ if not_linked.any?
+ error_messages << format(
+ _('%{item_ids} could not be removed due to not being linked'), item_ids: not_linked.to_sentence
+ )
+ end
+
+ return '' unless error_messages.any?
+
+ format(_('IDs with errors: %{error_messages}.'), error_messages: error_messages.join(', '))
+ end
+
+ def response_message
+ success_message = format(_('Successfully unlinked IDs: %{item_ids}.'), item_ids: removed_ids.to_sentence)
+
+ return success_message unless error_message.present?
+
+ "#{success_message} #{error_message}"
+ end
+ end
+ end
+end
diff --git a/app/uploaders/design_management/design_v432x230_uploader.rb b/app/uploaders/design_management/design_v432x230_uploader.rb
index 975050c26e4..0f1ebfed4aa 100644
--- a/app/uploaders/design_management/design_v432x230_uploader.rb
+++ b/app/uploaders/design_management/design_v432x230_uploader.rb
@@ -20,7 +20,7 @@ module DesignManagement
#
# We currently choose not to resize `image/svg+xml` for security reasons.
# See https://gitlab.com/gitlab-org/gitlab/issues/207740#note_302766171
- MIME_TYPE_ALLOWLIST = %w(image/png image/jpeg image/bmp image/gif).freeze
+ MIME_TYPE_ALLOWLIST = %w[image/png image/jpeg image/bmp image/gif].freeze
process resize_to_fit: [432, 230]
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index 87a624ddb60..c28f0893c56 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -20,8 +20,8 @@ class FileUploader < GitlabUploader
'!?\[.*?\]\(/uploads/(?P<secret>[0-9a-f]{32})/(?P<file>.*?)\)'
)
- DYNAMIC_PATH_PATTERN = %r{.*(?<secret>\b(\h{10}|\h{32}))\/(?<identifier>.*)}.freeze
- VALID_SECRET_PATTERN = %r{\A\h{10,32}\z}.freeze
+ DYNAMIC_PATH_PATTERN = %r{.*(?<secret>\b(\h{10}|\h{32}))\/(?<identifier>.*)}
+ VALID_SECRET_PATTERN = %r{\A\h{10,32}\z}
InvalidSecret = Class.new(StandardError)
diff --git a/app/uploaders/gitlab_uploader.rb b/app/uploaders/gitlab_uploader.rb
index 06bf742a22d..c1ca535b336 100644
--- a/app/uploaders/gitlab_uploader.rb
+++ b/app/uploaders/gitlab_uploader.rb
@@ -5,7 +5,7 @@ class GitlabUploader < CarrierWave::Uploader::Base
class_attribute :storage_location_identifier
- PROTECTED_METHODS = %i(filename cache_dir work_dir store_dir).freeze
+ PROTECTED_METHODS = %i[filename cache_dir work_dir store_dir].freeze
ObjectNotReadyError = Class.new(StandardError)
diff --git a/app/uploaders/packages/nuget/symbol_uploader.rb b/app/uploaders/packages/nuget/symbol_uploader.rb
new file mode 100644
index 00000000000..1d6ec9a8de8
--- /dev/null
+++ b/app/uploaders/packages/nuget/symbol_uploader.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Packages
+ module Nuget
+ class SymbolUploader < GitlabUploader
+ include ObjectStorage::Concern
+
+ storage_location :packages
+
+ alias_method :upload, :model
+
+ def store_dir
+ dynamic_segment
+ end
+
+ private
+
+ def dynamic_segment
+ raise ObjectNotReadyError, 'Packages::Nuget::Symbol model not ready' unless model.object_storage_key
+
+ model.object_storage_key
+ end
+ end
+ end
+end
diff --git a/app/validators/addressable_url_validator.rb b/app/validators/addressable_url_validator.rb
index 3e6ec0b6f29..6dcc089fa73 100644
--- a/app/validators/addressable_url_validator.rb
+++ b/app/validators/addressable_url_validator.rb
@@ -51,7 +51,7 @@ class AddressableUrlValidator < ActiveModel::EachValidator
# tasks that uses that url won't work.
# See https://gitlab.com/gitlab-org/gitlab-foss/issues/66723
BLOCKER_VALIDATE_OPTIONS = {
- schemes: %w(http https),
+ schemes: %w[http https],
ports: [],
allow_localhost: true,
allow_local_network: true,
diff --git a/app/validators/certificate_fingerprint_validator.rb b/app/validators/certificate_fingerprint_validator.rb
index 79d78653ec7..c4e317c3e79 100644
--- a/app/validators/certificate_fingerprint_validator.rb
+++ b/app/validators/certificate_fingerprint_validator.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class CertificateFingerprintValidator < ActiveModel::EachValidator
- FINGERPRINT_PATTERN = /\A([a-zA-Z0-9]{2}[\s\-:]?){16,}\z/.freeze
+ FINGERPRINT_PATTERN = /\A([a-zA-Z0-9]{2}[\s\-:]?){16,}\z/
def validate_each(record, attribute, value)
unless value.try(:match, FINGERPRINT_PATTERN)
diff --git a/app/validators/duration_validator.rb b/app/validators/duration_validator.rb
index defd28d7d3b..bcdcf665cba 100644
--- a/app/validators/duration_validator.rb
+++ b/app/validators/duration_validator.rb
@@ -12,7 +12,7 @@
#
class DurationValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
- ChronicDuration.parse(value)
+ ChronicDuration.parse(value, use_complete_matcher: true)
rescue ChronicDuration::DurationParseError
if options[:message]
record.errors.add(:base, options[:message])
diff --git a/app/validators/gitlab/zoom_url_validator.rb b/app/validators/gitlab/zoom_url_validator.rb
index c752cec07c2..d3da3977697 100644
--- a/app/validators/gitlab/zoom_url_validator.rb
+++ b/app/validators/gitlab/zoom_url_validator.rb
@@ -8,7 +8,7 @@ module Gitlab
# @example usage
# validates :url, 'gitlab/zoom_url': true
class ZoomUrlValidator < ActiveModel::EachValidator
- ALLOWED_SCHEMES = %w(https).freeze
+ ALLOWED_SCHEMES = %w[https].freeze
def validate_each(record, attribute, value)
links_count = Gitlab::ZoomLinkExtractor.new(value).links.size
diff --git a/app/validators/json_schema_validator.rb b/app/validators/json_schema_validator.rb
index 9c246a114f6..2ef011df73e 100644
--- a/app/validators/json_schema_validator.rb
+++ b/app/validators/json_schema_validator.rb
@@ -10,9 +10,9 @@
# end
#
class JsonSchemaValidator < ActiveModel::EachValidator
- FILENAME_ALLOWED = /\A[a-z0-9_-]*\Z/.freeze
+ FILENAME_ALLOWED = /\A[a-z0-9_-]*\Z/
FilenameError = Class.new(StandardError)
- BASE_DIRECTORY = %w(app validators json_schemas).freeze
+ BASE_DIRECTORY = %w[app validators json_schemas].freeze
def initialize(options)
raise ArgumentError, "Expected 'filename' as an argument" unless options[:filename]
diff --git a/app/validators/json_schemas/pinned_nav_items.json b/app/validators/json_schemas/pinned_nav_items.json
index 60dee5cc463..aaeb2fe8bda 100644
--- a/app/validators/json_schemas/pinned_nav_items.json
+++ b/app/validators/json_schemas/pinned_nav_items.json
@@ -16,6 +16,13 @@
"type": "string"
},
"uniqueItems": true
+ },
+ "organization": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true
}
},
"additionalProperties": false
diff --git a/app/validators/json_schemas/scan_result_policy_project_approval_settings.json b/app/validators/json_schemas/scan_result_policy_project_approval_settings.json
new file mode 100644
index 00000000000..5a81c61ede4
--- /dev/null
+++ b/app/validators/json_schemas/scan_result_policy_project_approval_settings.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "description": "Scan result policy project_approval_settings",
+ "type": "object",
+ "properties": {
+ "prevent_approval_by_author": {
+ "type": "boolean"
+ },
+ "prevent_approval_by_commit_author": {
+ "type": "boolean"
+ },
+ "remove_approvals_with_new_commit": {
+ "type": "boolean"
+ },
+ "require_password_to_approve": {
+ "type": "boolean"
+ },
+ "block_unprotecting_branches": {
+ "type": "boolean"
+ }
+ }
+}
diff --git a/app/validators/line_code_validator.rb b/app/validators/line_code_validator.rb
index e1abccc1dff..54f9272a2ae 100644
--- a/app/validators/line_code_validator.rb
+++ b/app/validators/line_code_validator.rb
@@ -4,7 +4,7 @@
#
# Custom validator for GitLab line codes.
class LineCodeValidator < ActiveModel::EachValidator
- PATTERN = /\A[a-z0-9]+_\d+_\d+\z/.freeze
+ PATTERN = /\A[a-z0-9]+_\d+_\d+\z/
def validate_each(record, attribute, value)
unless PATTERN.match?(value)
diff --git a/app/views/admin/abuse_reports/_abuse_report.html.haml b/app/views/admin/abuse_reports/_abuse_report.html.haml
deleted file mode 100644
index aa5543700a7..00000000000
--- a/app/views/admin/abuse_reports/_abuse_report.html.haml
+++ /dev/null
@@ -1,39 +0,0 @@
-- reporter = abuse_report.reporter
-- user = abuse_report.user
-%tr
- %th.d-block.d-sm-none
- %strong= _('User')
- %td
- - if user
- = link_to user.name, user
- .light.small
- = html_escape(_('Joined %{time_ago}')) % { time_ago: time_ago_with_tooltip(user.created_at).html_safe }
- - else
- = _('(removed)')
- %td
- - if reporter
- %strong.subheading.d-block.d-sm-none
- = _('Reported by %{reporter}').html_safe % { reporter: reporter ? link_to(reporter.name, reporter) : _('(removed)') }
- .light.gl-display-none.gl-sm-display-block
- = link_to(reporter.name, reporter)
- .light.small
- = time_ago_with_tooltip(abuse_report.created_at)
- - else
- = _('(removed)')
- %td
- %strong.subheading.d-block.d-sm-none
- = _('Message')
- .message
- = markdown_field(abuse_report, :message)
- %td
- - if user && user != current_user
- = render Pajamas::ButtonComponent.new(href: admin_abuse_report_path(abuse_report, remove_user: true), variant: :danger, block: true, button_options: { data: { confirm: _("USER %{user} WILL BE REMOVED! Are you sure?") % { user: user.name }, confirm_btn_variant: "danger", remote: true, method: :delete }, class: "js-remove-tr" }) do
- = _('Remove user & report')
- - if user.blocked?
- = render Pajamas::ButtonComponent.new(href: block_admin_user_path(user), block: true, disabled: true, button_options: { data: { confirm: _('USER WILL BE BLOCKED! Are you sure?'), method: :put } }) do
- = _('Already blocked')
- - else
- = render Pajamas::ButtonComponent.new(href: block_admin_user_path(user), block: true, button_options: { data: { confirm: _('USER WILL BE BLOCKED! Are you sure?'), method: :put } }) do
- = _('Block user')
- = render Pajamas::ButtonComponent.new(href: [:admin, abuse_report], block: true, button_options: { data: { remote: true, method: :delete }, class: "js-remove-tr" }) do
- = _('Remove report')
diff --git a/app/views/admin/abuse_reports/index.html.haml b/app/views/admin/abuse_reports/index.html.haml
index fee3a846849..ea2d4f3b4af 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -2,35 +2,5 @@
%h1.page-title.gl-font-size-h-display= _('Abuse Reports')
-- if Feature.enabled?(:abuse_reports_list)
- #js-abuse-reports-list-app{ data: abuse_reports_list_data(@abuse_reports) }
- = gl_loading_icon(css_class: 'gl-my-5', size: 'md')
-- else
- .row-content-block.second-block
- = form_tag admin_abuse_reports_path, method: :get, class: 'filter-form' do
- .filter-categories.flex-fill
- .filter-item.inline
- = dropdown_tag(user_dropdown_label(params[:user_id], 'User'),
- options: { toggle_class: 'js-filter-submit js-user-search',
- title: _('Filter by user'), filter: true, filterInput: 'input#user-search',
- dropdown_class: 'dropdown-menu-selectable dropdown-menu-user js-filter-submit',
- placeholder: _('Search users'),
- data: { current_user: true, field_name: 'user_id' }})
-
- .abuse-reports
- - if @abuse_reports.present?
- .table-holder
- %table.table.responsive-table
- %thead.d-none.d-md-table-header-group
- %tr
- %th= _('User')
- %th= _('Reported by')
- %th.wide= _('Message')
- %th= _('Action')
- = render @abuse_reports
- = paginate @abuse_reports, theme: 'gitlab'
- - else
- .empty-state
- .text-center
- %h4= _("There are no abuse reports!")
- %h3= emoji_icon('tada')
+#js-abuse-reports-list-app{ data: abuse_reports_list_data(@abuse_reports) }
+ = gl_loading_icon(css_class: 'gl-my-5', size: 'md')
diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml
index d8d6af606ac..b65649b5a07 100644
--- a/app/views/admin/application_settings/_account_and_limit.html.haml
+++ b/app/views/admin/application_settings/_account_and_limit.html.haml
@@ -19,25 +19,6 @@
= f.label :receive_max_input_size, _('Maximum push size (MiB)'), class: 'label-light'
= f.number_field :receive_max_input_size, class: 'form-control gl-form-input', title: _('Maximum size limit for a single commit.'), data: { toggle: 'tooltip', container: 'body', qa_selector: 'receive_max_input_size_field' }
.form-group
- = f.label :max_export_size, _('Maximum export size (MiB)'), class: 'label-light'
- = f.number_field :max_export_size, class: 'form-control gl-form-input', title: _('Maximum size of export files.'), data: { toggle: 'tooltip', container: 'body' }
- %span.form-text.text-muted= _('Set to 0 for no size limit.')
- .form-group
- = f.label :max_import_size, _('Maximum import size (MiB)'), class: 'label-light'
- = f.number_field :max_import_size, class: 'form-control gl-form-input', title: _('Maximum size of import files.'), data: { toggle: 'tooltip', container: 'body' }
- %span.form-text.text-muted= _('Only effective when remote storage is enabled. Set to 0 for no size limit.')
- .form-group
- = f.label :max_import_remote_file_size, s_('Import|Maximum import remote file size (MB)'), class: 'label-light'
- = f.number_field :max_import_remote_file_size, class: 'form-control gl-form-input', title: s_('Import|Maximum remote file size for imports from external object storages. For example, AWS S3.'), data: { toggle: 'tooltip', container: 'body' }
- %span.form-text.text-muted= _('Set to 0 for no size limit.')
- .form-group
- = f.label :bulk_import_max_download_file_size, s_('BulkImport|Direct transfer maximum download file size (MB)'), class: 'label-light'
- = f.number_field :bulk_import_max_download_file_size, class: 'form-control gl-form-input', title: s_('BulkImport|Maximum download file size when importing from source GitLab instances by direct transfer.'), data: { toggle: 'tooltip', container: 'body' }
- .form-group
- = f.label :max_decompressed_archive_size, s_('Import|Maximum decompressed size (MiB)'), class: 'label-light'
- = f.number_field :max_decompressed_archive_size, class: 'form-control gl-form-input', title: s_('Import|Maximum size of decompressed archive.'), data: { toggle: 'tooltip', container: 'body' }
- %span.form-text.text-muted= _('Set to 0 for no size limit.')
- .form-group
= f.label :session_expire_delay, _('Session duration (minutes)'), class: 'label-light'
= f.number_field :session_expire_delay, class: 'form-control gl-form-input', title: _('Maximum duration of a session.'), data: { toggle: 'tooltip', container: 'body' }
%span.form-text.text-muted#session_expire_delay_help_block= _('Restart GitLab to apply changes.')
@@ -53,7 +34,7 @@
.form-group
= f.label :user_oauth_applications, _('User OAuth applications'), class: 'label-bold'
- = f.gitlab_ui_checkbox_component :user_oauth_applications, _('Allow users to register any application to use GitLab as an OAuth provider')
+ = f.gitlab_ui_checkbox_component :user_oauth_applications, _('Allow users to register any application to use GitLab as an OAuth provider. This setting does not affect group-level OAuth applications.')
.form-group
= f.label :user_default_external, _('New users set to external'), class: 'label-bold'
= f.gitlab_ui_checkbox_component :user_default_external, _('Newly-registered users are external by default')
diff --git a/app/views/admin/application_settings/_email.html.haml b/app/views/admin/application_settings/_email.html.haml
index 2f31eb5f6d1..65049fa5466 100644
--- a/app/views/admin/application_settings/_email.html.haml
+++ b/app/views/admin/application_settings/_email.html.haml
@@ -16,9 +16,6 @@
= render_if_exists 'admin/application_settings/email_additional_text_setting', form: f
.form-group
- = f.gitlab_ui_checkbox_component :in_product_marketing_emails_enabled, _('Enable in-product marketing emails'), help_text: _('Send emails to help guide new users through the onboarding process.')
-
- .form-group
= f.gitlab_ui_checkbox_component :user_deactivation_emails_enabled, _('Enable user deactivation emails'), help_text: _('Send emails to users upon account deactivation.')
- if Feature.enabled?(:deactivation_email_additional_text)
diff --git a/app/views/admin/application_settings/_gitpod.html.haml b/app/views/admin/application_settings/_gitpod.html.haml
index 988153d45a4..1f56487cea4 100644
--- a/app/views/admin/application_settings/_gitpod.html.haml
+++ b/app/views/admin/application_settings/_gitpod.html.haml
@@ -6,7 +6,7 @@
= _('Gitpod')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded ? _('Collapse') : _('Expand')
- .gl-text-secondary
+ .gl-text-secondary.gl-mb-5
#js-gitpod-settings-help-text{ data: {"message" => gitpod_enable_description, "message-url" => "https://gitpod.io/" } }
= link_to sprite_icon('question-o'), help_page_path('integration/gitpod.md'), target: '_blank', class: 'has-tooltip', title: _('More information')
diff --git a/app/views/admin/application_settings/_import_and_export.html.haml b/app/views/admin/application_settings/_import_and_export.html.haml
new file mode 100644
index 00000000000..8e321406bf8
--- /dev/null
+++ b/app/views/admin/application_settings/_import_and_export.html.haml
@@ -0,0 +1,43 @@
+= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-import-export-settings'), html: { class: 'fieldset-form', id: 'import-export-settings' } do |f|
+ = form_errors(@application_setting)
+
+ %fieldset
+ .form-group
+ = f.label :import_sources, s_('AdminSettings|Import sources'), class: 'label-bold gl-mb-0'
+ %span.form-text.gl-mt-0.gl-mb-3#import-sources-help
+ - tag_pair_github_docs = tag_pair(link_to('', help_page_path('integration/github'), target: '_blank', rel: 'noopener noreferrer'), :github_docs_link_start, :github_docs_link_end)
+ - tag_pair_bitbucket_docs = tag_pair(link_to('', help_page_path('integration/bitbucket'), target: '_blank', rel: 'noopener noreferrer'), :bitbucket_docs_link_start, :bitbucket_docs_link_end)
+ = safe_format(s_('AdminSettings|Code can be imported from enabled sources during project creation. OmniAuth must be configured for GitHub %{github_docs_link_start}%{icon}%{github_docs_link_end} and Bitbucket %{bitbucket_docs_link_start}%{icon}%{bitbucket_docs_link_end}.'), tag_pair_github_docs, tag_pair_bitbucket_docs, icon: sprite_icon('question-o'))
+ = hidden_field_tag 'application_setting[import_sources][]'
+ - import_sources_checkboxes(f).each do |source|
+ = source
+ .form-group{ data: { testid: 'project-export' } }
+ = f.label :project_export, s_('AdminSettings|Project export'), class: 'label-bold'
+ = f.gitlab_ui_checkbox_component :project_export_enabled, s_('AdminSettings|Enabled')
+ .form-group{ data: { testid: 'bulk-import' } }
+ = f.label :bulk_import, s_('AdminSettings|Allow migrating GitLab groups and projects by direct transfer'), class: 'gl-font-weight-bold'
+ = f.gitlab_ui_checkbox_component :bulk_import_enabled, s_('AdminSettings|Enabled')
+ .form-group
+ = f.label :max_export_size, _('Maximum export size (MiB)'), class: 'label-light'
+ = f.number_field :max_export_size, class: 'form-control gl-form-input', title: _('Maximum size of export files.'), data: { toggle: 'tooltip', container: 'body' }
+ %span.form-text.text-muted= _('Set to 0 for no size limit.')
+ .form-group
+ = f.label :max_import_size, _('Maximum import size (MiB)'), class: 'label-light'
+ = f.number_field :max_import_size, class: 'form-control gl-form-input', title: _('Maximum size of import files.'), data: { toggle: 'tooltip', container: 'body' }
+ %span.form-text.text-muted= _('Only effective when remote storage is enabled. Set to 0 for no size limit.')
+ .form-group
+ = f.label :max_import_remote_file_size, s_('Import|Maximum import remote file size (MiB)'), class: 'label-light'
+ = f.number_field :max_import_remote_file_size, class: 'form-control gl-form-input', title: s_('Import|Maximum remote file size for imports from external object storages. For example, AWS S3.'), data: { toggle: 'tooltip', container: 'body' }
+ %span.form-text.text-muted= _('Set to 0 for no size limit.')
+ .form-group
+ = f.label :bulk_import_max_download_file_size, s_('BulkImport|Direct transfer maximum download file size (MiB)'), class: 'label-light'
+ = f.number_field :bulk_import_max_download_file_size, class: 'form-control gl-form-input', title: s_('BulkImport|Maximum download file size when importing from source GitLab instances by direct transfer.'), data: { toggle: 'tooltip', container: 'body' }
+ .form-group
+ = f.label :max_decompressed_archive_size, s_('Import|Maximum decompressed file size for archives from imports (MiB)'), class: 'label-light'
+ = f.number_field :max_decompressed_archive_size, class: 'form-control gl-form-input', title: s_('Import|Maximum size of decompressed archive.'), data: { toggle: 'tooltip', container: 'body' }
+ %span.form-text.text-muted= _('Set to 0 for no size limit.')
+ .form-group
+ = f.label :decompress_archive_file_timeout, s_('Import|Timeout for decompressing archived files (seconds)'), class: 'label-light'
+ = f.number_field :decompress_archive_file_timeout, class: 'form-control gl-form-input', title: s_('Import|Timeout for decompressing archived files.'), data: { toggle: 'tooltip', container: 'body' }
+ %span.form-text.text-muted= _('Set to 0 to disable timeout.')
+ = f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/_pages.html.haml b/app/views/admin/application_settings/_pages.html.haml
index 1eb6b747704..d5f2c6afee3 100644
--- a/app/views/admin/application_settings/_pages.html.haml
+++ b/app/views/admin/application_settings/_pages.html.haml
@@ -19,28 +19,25 @@
= f.label :max_pages_size, _('Maximum size of pages (MiB)'), class: 'label-bold'
= f.number_field :max_pages_size, class: 'form-control gl-form-input'
.form-text.text-muted
- - pages_link_url = help_page_path('administration/pages/index', anchor: 'set-maximum-size-of-gitlab-pages-site-in-a-project')
- - pages_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: pages_link_url }
- = s_('AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}').html_safe % { link_start: pages_link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('administration/pages/index', anchor: 'set-maximum-size-of-gitlab-pages-site-in-a-project'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}'), tag_pair(link, :link_start, :link_end))
.form-group
= f.label :max_pages_custom_domains_per_project, s_('AdminSettings|Maximum number of custom domains per project'), class: 'label-bold'
= f.number_field :max_pages_custom_domains_per_project, class: 'form-control gl-form-input'
.form-text.text-muted
- - pages_link_url = help_page_path('administration/pages/index', anchor: 'set-maximum-number-of-gitlab-pages-custom-domains-for-a-project')
- - pages_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: pages_link_url }
- = s_('AdminSettings|Set the maximum number of GitLab Pages custom domains per project (0 for unlimited). %{link_start}Learn more.%{link_end}').html_safe % { link_start: pages_link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('administration/pages/index', anchor: 'set-maximum-number-of-gitlab-pages-custom-domains-for-a-project'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('AdminSettings|Set the maximum number of GitLab Pages custom domains per project (0 for unlimited). %{link_start}Learn more.%{link_end}'), tag_pair(link, :link_start, :link_end))
%h5
= s_("AdminSettings|Configure Let's Encrypt")
%p
- - lets_encrypt_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: "https://letsencrypt.org/" }
- = _("%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA) that issues digital certificates to enable HTTPS (SSL/TLS) for sites.").html_safe % { lets_encrypt_link_start: lets_encrypt_link_start, lets_encrypt_link_end: '</a>'.html_safe }
+ - link = link_to('', "https://letsencrypt.org/", target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_("%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA) that issues digital certificates to enable HTTPS (SSL/TLS) for sites."), tag_pair(link, :lets_encrypt_link_start, :lets_encrypt_link_end))
.form-group
= f.label :lets_encrypt_notification_email, s_("AdminSettings|Let's Encrypt email"), class: 'label-bold'
= f.text_field :lets_encrypt_notification_email, class: 'form-control gl-form-input'
.form-text.text-muted
- - pages_link_url = help_page_path('administration/pages/index', anchor: 'lets-encrypt-integration')
- - pages_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: pages_link_url }
- = s_("AdminSettings|A Let's Encrypt account will be configured for this GitLab instance using this email address. You will receive emails to warn of expiring certificates. %{link_start}Learn more.%{link_end}").html_safe % { link_start: pages_link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('administration/pages/index', anchor: 'lets-encrypt-integration'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_("AdminSettings|A Let's Encrypt account will be configured for this GitLab instance using this email address. You will receive emails to warn of expiring certificates. %{link_start}Learn more.%{link_end}"), tag_pair(link, :link_start, :link_end))
.form-group
- terms_of_service_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: lets_encrypt_terms_of_service_admin_application_settings_path }
= f.gitlab_ui_checkbox_component :lets_encrypt_terms_of_service_accepted,
diff --git a/app/views/admin/application_settings/_protected_paths.html.haml b/app/views/admin/application_settings/_protected_paths.html.haml
index 3a7a951d137..cd17e4bdec3 100644
--- a/app/views/admin/application_settings/_protected_paths.html.haml
+++ b/app/views/admin/application_settings/_protected_paths.html.haml
@@ -4,7 +4,7 @@
%fieldset
.form-group
= f.gitlab_ui_checkbox_component :throttle_protected_paths_enabled,
- _('Enable rate limiting for POST requests to the specified paths'),
+ _('Enable rate limiting for requests to the specified paths'),
help_text: _('Helps reduce request volume for protected paths.')
.form-group
= f.label :throttle_protected_paths_requests_per_period, 'Maximum requests per period per user', class: 'label-bold'
@@ -14,11 +14,14 @@
= f.number_field :throttle_protected_paths_period_in_seconds, class: 'form-control gl-form-input'
.form-group
= f.label :protected_paths, class: 'label-bold' do
- = _('Paths to protect with rate limiting')
+ = _('Paths with rate limiting for POST requests')
= f.text_area :protected_paths_raw, placeholder: '/users/sign_in,/users/password', class: 'form-control gl-form-input', rows: 10
+ .form-group
+ = f.label :protected_paths_for_get_request, class: 'label-bold' do
+ = _('Paths with rate limiting for GET requests')
+ = f.text_area :protected_paths_for_get_request_raw, class: 'form-control gl-form-input', rows: 10
%span.form-text.text-muted
- - relative_url_link = 'https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-a-relative-url-for-gitlab'
- - relative_url_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: relative_url_link }
- = _('All paths are relative to the GitLab URL. Do not include %{relative_url_link_start}relative URLs%{relative_url_link_end}.').html_safe % { relative_url_link_start: relative_url_link_start, relative_url_link_end: '</a>'.html_safe }
+ - link = link_to('', 'https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-a-relative-url-for-gitlab', target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_('All paths are relative to the GitLab URL. Do not include %{relative_url_link_start}relative URLs%{relative_url_link_end}.'), tag_pair(link, :relative_url_link_start, :relative_url_link_end))
= f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/_search_limits.html.haml b/app/views/admin/application_settings/_search_limits.html.haml
index 396c263dd5d..b318f7e5a20 100644
--- a/app/views/admin/application_settings/_search_limits.html.haml
+++ b/app/views/admin/application_settings/_search_limits.html.haml
@@ -12,5 +12,11 @@
= f.label :search_rate_limit_unauthenticated, _('Maximum number of requests per minute for an unauthenticated IP address'), class: 'label-bold'
= f.number_field :search_rate_limit_unauthenticated, class: 'form-control gl-form-input'
+ .form-group
+ = f.label :search_rate_limit_allowlist, _('Users to exclude from the rate limit'), class: 'label-bold'
+ = f.text_area :search_rate_limit_allowlist_raw, class: 'form-control gl-form-input', rows: 5, aria: { describedBy: 'search-rate-limit-allowlist-field-description' }
+ .form-text.text-muted{ id: 'search-rate-limit-allowlist-field-description' }
+ = _('List of users who are allowed to exceed the rate limit. Example: username1, username2')
+
= f.submit _('Save changes'), data: { qa_selector: 'save_changes_button' }, pajamas_button: true
diff --git a/app/views/admin/application_settings/_sentry.html.haml b/app/views/admin/application_settings/_sentry.html.haml
index 20164cfe88d..9f2a40e4e54 100644
--- a/app/views/admin/application_settings/_sentry.html.haml
+++ b/app/views/admin/application_settings/_sentry.html.haml
@@ -17,4 +17,12 @@
= f.label :sentry_environment, _('Environment'), class: 'label-light'
= f.text_field :sentry_environment, class: 'form-control gl-form-input', placeholder: Rails.env
+ %p.text-muted
+ = _("Changing any setting bellow doesn't require an application restart")
+
+ %fieldset
+ .form-group
+ = f.label :sentry_clientside_traces_sample_rate, _('Clientside traces sample rate'), class: 'label-light'
+ = f.number_field :sentry_clientside_traces_sample_rate, class: 'form-control gl-form-input', placeholder: '0.5', min: 0, max: 1, step: 0.001
+
= f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/_silent_mode_settings_form.html.haml b/app/views/admin/application_settings/_silent_mode_settings_form.html.haml
new file mode 100644
index 00000000000..92b4174842f
--- /dev/null
+++ b/app/views/admin/application_settings/_silent_mode_settings_form.html.haml
@@ -0,0 +1,11 @@
+%section.settings.no-animate#js-silent-mode-toggle{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
+ = s_('SilentMode|Silent mode')
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p.gl-text-secondary
+ = s_('SilentMode|Suppress outbound communication, such as emails, from GitLab.')
+ = link_to _('Learn more.'), help_page_path('administration/silent_mode/index'), target: '_blank', rel: 'noopener noreferrer'
+ .settings-content
+ #js-silent-mode-settings{ data: { "silent-mode-enabled" => @application_setting.silent_mode_enabled.to_s } }
diff --git a/app/views/admin/application_settings/_snowplow.html.haml b/app/views/admin/application_settings/_snowplow.html.haml
index 6f9aad56ce8..1b90432e1f3 100644
--- a/app/views/admin/application_settings/_snowplow.html.haml
+++ b/app/views/admin/application_settings/_snowplow.html.haml
@@ -6,7 +6,7 @@
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded ? _('Collapse') : _('Expand')
%p.gl-text-secondary
- - help_link = link_to('', help_page_path('development/snowplow/index'), target: '_blank', rel: 'noopener noreferrer')
+ - help_link = link_to('', help_page_path('development/internal_analytics/snowplow/index'), target: '_blank', rel: 'noopener noreferrer')
- snowplow_link = link_to('', 'https://snowplow.io/', target: '_blank', rel: 'noopener noreferrer')
= safe_format(_('Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}'), tag_pair(snowplow_link, :snowplow_link_start, :snowplow_link_end), tag_pair(help_link, :help_link_start, :help_link_end))
.settings-content
diff --git a/app/views/admin/application_settings/_usage.html.haml b/app/views/admin/application_settings/_usage.html.haml
index 0455394444c..5a3814ca83d 100644
--- a/app/views/admin/application_settings/_usage.html.haml
+++ b/app/views/admin/application_settings/_usage.html.haml
@@ -12,7 +12,7 @@
help_text: _("GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}").html_safe % { link_start: help_link_start, link_end: link_end }
.form-group
- can_be_configured = @application_setting.usage_ping_can_be_configured?
- - service_ping_link_start = link_start % { url: help_page_path('development/service_ping/index') }
+ - service_ping_link_start = link_start % { url: help_page_path('development/internal_analytics/service_ping/index') }
- deactivating_service_ping_link_start = link_start % { url: help_page_path('administration/settings/usage_statistics', anchor: 'disable-usage-statistics-with-the-configuration-file') }
- usage_ping_help_text = s_('AdminSettings|To help improve GitLab and its user experience, GitLab periodically collects usage information. %{link_start}What information is shared with GitLab Inc.?%{link_end}').html_safe % { link_start: service_ping_link_start, link_end: link_end }
- disabled_help_text = s_('AdminSettings|Service ping is disabled in your configuration file, and cannot be enabled through this form. For more information, see the documentation on %{link_start}deactivating service ping%{link_end}.').html_safe % { link_start: deactivating_service_ping_link_start, link_end: link_end }
@@ -35,19 +35,10 @@
checkbox_options: { id: 'application_setting_usage_ping_features_enabled' },
label_options: { id: 'service_ping_features_label' }
.form-text.gl-text-gray-500.gl-pl-6
- %p.gl-mb-3= s_('AdminSettings|Registration Features include:')
- - email_from_gitlab_path = help_page_path('administration/email_from_gitlab')
- - repo_size_limit_path = help_page_path('administration/settings/account_and_limit_settings', anchor: 'repository-size-limit')
- - restrict_ip_path = help_page_path('user/group/access_and_permissions', anchor: 'restrict-group-access-by-ip-address')
- - email_from_gitlab_link = link_start % { url: email_from_gitlab_path }
- - repo_size_limit_link = link_start % { url: repo_size_limit_path }
- - restrict_ip_link = link_start % { url: restrict_ip_path }
- %ul
- %li
- = s_('AdminSettings|Email from GitLab - email users right from the Admin Area. %{link_start}Learn more%{link_end}.').html_safe % { link_start: email_from_gitlab_link, link_end: link_end }
- %li
- = s_('AdminSettings|Limit project size at a global, group, and project level. %{link_start}Learn more%{link_end}.').html_safe % { link_start: repo_size_limit_link, link_end: link_end }
- %li
- = s_('AdminSettings|Restrict group access by IP address. %{link_start}Learn more%{link_end}.').html_safe % { link_start: restrict_ip_link, link_end: link_end }
+ %p.gl-mb-3
+ - registration_features_gitlab_path = help_page_path('administration/settings/usage_statistics', anchor: 'registration-features-program')
+ - registration_features_gitlab_link = link_to('', registration_features_gitlab_path, target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('AdminSettings|For a list of included Registration Features, see %{link_start}the documentation%{link_end}.'), tag_pair(registration_features_gitlab_link, :link_start, :link_end))
+
= f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/_visibility_and_access.html.haml b/app/views/admin/application_settings/_visibility_and_access.html.haml
index 7142128d2cd..624f5a48c3a 100644
--- a/app/views/admin/application_settings/_visibility_and_access.html.haml
+++ b/app/views/admin/application_settings/_visibility_and_access.html.haml
@@ -19,33 +19,17 @@
= s_('AdminSettings|Restricted visibility levels')
%small.form-text.text-gl-muted
= s_('AdminSettings|Prevent non-administrators from using the selected visibility levels for groups, projects and snippets.')
+ = s_('AdminSettings|The selected level must be different from the selected default group and project visibility.')
+ = link_to _('Learn more.'), help_page_path('administration/settings/visibility_and_access_controls', anchor: 'restrict-visibility-levels'), target: '_blank', rel: 'noopener noreferrer'
= hidden_field_tag 'application_setting[restricted_visibility_levels][]'
.gl-form-checkbox-group
- restricted_level_checkboxes(f).each do |checkbox|
= checkbox
- .form-group
- = f.label :import_sources, s_('AdminSettings|Import sources'), class: 'label-bold gl-mb-0'
- %span.form-text.gl-mt-0.gl-mb-3#import-sources-help
- = _('Code can be imported from enabled sources during project creation. OmniAuth must be configured for GitHub')
- = link_to sprite_icon('question-o'), help_page_path("integration/github")
- and Bitbucket
- = link_to sprite_icon('question-o'), help_page_path("integration/bitbucket")
- = hidden_field_tag 'application_setting[import_sources][]'
- - import_sources_checkboxes(f).each do |source|
- = source
= render_if_exists 'admin/application_settings/ldap_access_setting', form: f
= render_if_exists 'admin/application_settings/saml_group_locks_setting', form: f
- .form-group{ data: { testid: 'project-export' } }
- = f.label :project_export, s_('AdminSettings|Project export'), class: 'label-bold'
- = f.gitlab_ui_checkbox_component :project_export_enabled, s_('AdminSettings|Enabled')
-
- .form-group{ data: { testid: 'bulk-import' } }
- = f.label :bulk_import, s_('AdminSettings|Allow migrating GitLab groups and projects by direct transfer'), class: 'gl-font-weight-bold'
- = f.gitlab_ui_checkbox_component :bulk_import_enabled, s_('AdminSettings|Enabled')
-
.form-group
%label.label-bold= _('Enabled Git access protocols')
= select(:application_setting, :enabled_git_access_protocol, [['Both SSH and HTTP(S)', nil], ['Only SSH', 'ssh'], ['Only HTTP(S)', 'http']], {}, class: 'form-control')
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index 6ae9c58ffcd..5aa2684f084 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -10,7 +10,7 @@
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
%p.gl-text-secondary
- = _('Set visibility of project contents. Configure import sources and Git access protocols.')
+ = s_('AdminSettings|Set visibility of project contents and configure Git access protocols.')
.settings-content
= render 'visibility_and_access'
@@ -25,6 +25,17 @@
.settings-content
= render 'account_and_limit'
+%section.settings.as-import-export.no-animate#js-import-export-settings{ class: ('expanded' if expanded_by_default?), data: { testid: 'admin-import-export-settings' } }
+ .settings-header
+ %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
+ = _('Import and export settings')
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle '}) do
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p.gl-text-secondary
+ = _('Configure import sources and settings related to import and export features.')
+ .settings-content
+ = render 'import_and_export'
+
%section.settings.as-diff-limits.no-animate#js-merge-request-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
@@ -89,6 +100,7 @@
= render 'terminal'
= render_if_exists 'admin/application_settings/maintenance_mode_settings_form'
+= render 'admin/application_settings/silent_mode_settings_form'
= render 'admin/application_settings/gitpod'
= render 'admin/application_settings/kroki'
= render 'admin/application_settings/mailgun'
diff --git a/app/views/admin/dev_ops_report/_score.html.haml b/app/views/admin/dev_ops_report/_score.html.haml
index 208afefc73b..a504563ad91 100644
--- a/app/views/admin/dev_ops_report/_score.html.haml
+++ b/app/views/admin/dev_ops_report/_score.html.haml
@@ -1,6 +1,6 @@
- service_ping_enabled = Gitlab::CurrentSettings.usage_ping_enabled
- if !service_ping_enabled
- #js-devops-service-ping-disabled{ data: { is_admin: current_user&.admin.to_s, empty_state_svg_path: image_path('illustrations/convdev/convdev_no_index.svg'), enable_service_ping_path: metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), docs_link: help_page_path('development/service_ping/index.md') } }
+ #js-devops-service-ping-disabled{ data: { is_admin: current_user&.admin.to_s, empty_state_svg_path: image_path('illustrations/convdev/convdev_no_index.svg'), enable_service_ping_path: metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), docs_link: help_page_path('development/internal_analytics/service_ping/index.md') } }
- else
#js-devops-score{ data: { devops_score_metrics: devops_score_metrics(@metric).to_json, no_data_image_path: image_path('dev_ops_report_no_data.svg'), devops_score_intro_image_path: image_path('dev_ops_report_overview.svg') } }
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index b708564e23a..2da28910af3 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -41,6 +41,6 @@
- else
.gl-mt-5
- = f.submit _('Save changes'), data: { qa_selector: 'save_changes_button' }, pajamas_button: true
+ = f.submit _('Save changes'), data: { testid: 'save-changes-button' }, pajamas_button: true
= render Pajamas::ButtonComponent.new(href: admin_group_path(@group)) do
= _('Cancel')
diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml
index 20d24161c57..0c4bf91f545 100644
--- a/app/views/admin/groups/_group.html.haml
+++ b/app/views/admin/groups/_group.html.haml
@@ -1,11 +1,11 @@
- group = local_assigns.fetch(:group)
-%li.group-row.gl-py-3.gl-align-items-center{ class: 'gl-display-flex!', data: { qa_selector: 'group_row_content' } }
+%li.group-row.gl-py-3.gl-align-items-center{ class: 'gl-display-flex!', data: { testid: 'group-row-content' } }
= render Pajamas::AvatarComponent.new(group, size: 32, alt: '')
.gl-min-w-0.gl-flex-grow-1.gl-ml-3
.title
- = link_to [:admin, group], class: 'group-name', data: { qa_selector: 'group_name_link' } do
+ = link_to [:admin, group], class: 'group-name', data: { testid: 'group-name-link' } do
= group.full_name
- if group.description.present?
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 2a49b9c5ad8..9f42897d1da 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -7,7 +7,7 @@
= hidden_field_tag :sort, @sort
.search-holder
.search-field-holder
- = search_field_tag :name, params[:name].presence, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name', data: { qa_selector: 'group_search_field' }
+ = search_field_tag :name, params[:name].presence, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name', data: { testid: 'group-search-field' }
= sprite_icon('search', css_class: 'search-icon')
= render "shared/groups/dropdown", options_hash: admin_groups_sort_options_hash
= render Pajamas::ButtonComponent.new(variant: :confirm, href: new_admin_group_path) do
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 5f5f6c98663..f7a49c88d78 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -8,7 +8,7 @@
= _('Group: %{group_name}') % { group_name: @group.full_name }
= render Pajamas::ButtonComponent.new(href: admin_group_edit_path(@group),
- button_options: { class: 'gl-float-right', data: { qa_selector: 'edit_group_link' }},
+ button_options: { class: 'gl-float-right', data: { testid: 'edit-group-link' }},
icon: 'pencil') do
= _('Edit')
%hr
diff --git a/app/views/admin/hook_logs/show.html.haml b/app/views/admin/hook_logs/show.html.haml
index 0ccde159905..096fae8d457 100644
--- a/app/views/admin/hook_logs/show.html.haml
+++ b/app/views/admin/hook_logs/show.html.haml
@@ -1,5 +1,5 @@
- page_title _('Request details')
-%h1.page-title.gl-font-size-h-display
+%h2.page-title.gl-font-size-h-display
= _("Request details")
%hr
diff --git a/app/views/admin/identities/_identity.html.haml b/app/views/admin/identities/_identity.html.haml
index a24cd000464..921232125ff 100644
--- a/app/views/admin/identities/_identity.html.haml
+++ b/app/views/admin/identities/_identity.html.haml
@@ -7,6 +7,8 @@
= saml_group_link(identity)
%td
= identity.extern_uid
+ %td
+ = '-'
%td{ class: 'gl-py-0!' }
- button_classes = 'has-tooltip gl-my-3'
= render Pajamas::ButtonComponent.new(category: :tertiary,
diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml
index 1bb14969939..8077f0e15ca 100644
--- a/app/views/admin/identities/index.html.haml
+++ b/app/views/admin/identities/index.html.haml
@@ -10,6 +10,7 @@
%th{ class: 'gl-border-t-0!' }= s_('Identity|Provider ID')
%th{ class: 'gl-border-t-0!' }= _('Group')
%th{ class: 'gl-border-t-0!' }= _('Identifier')
+ %th{ class: 'gl-border-t-0!' }= s_('Identity|Active')
%th{ class: 'gl-border-t-0!' }= _('Actions')
- if identity_cells_to_render?(@identities, @user)
= render_if_exists partial: 'admin/identities/scim_identity', collection: scim_identities_collection(@user)
@@ -17,6 +18,6 @@
- else
%tbody
%tr
- %td{ colspan: '5' }
+ %td{ colspan: '6' }
.text-center.my-2
= _('This user has no identities')
diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml
index c5632e0d70b..b8a9ad32259 100644
--- a/app/views/admin/jobs/index.html.haml
+++ b/app/views/admin/jobs/index.html.haml
@@ -1,30 +1,7 @@
- add_page_specific_style 'page_bundles/ci_status'
-- add_page_specific_style 'page_bundles/admin/jobs_index'
- breadcrumb_title _("Jobs")
- page_title _("Jobs")
-- if Feature.enabled?(:admin_jobs_vue)
- #admin-jobs-app{ data: { job_statuses: job_statuses.to_json, empty_state_svg_path: image_path('jobs-empty-state.svg'), url: cancel_all_admin_jobs_path } }
-- else
- .top-area
- .scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
- %button.fade-left{ type: 'button', title: _('Scroll left'), 'aria-label': _('Scroll left') }
- = sprite_icon('chevron-lg-left', size: 12)
- %button.fade-right{ type: 'button', title: _('Scroll right'), 'aria-label': _('Scroll right') }
- = sprite_icon('chevron-lg-right', size: 12)
- - build_path_proc = ->(scope) { admin_jobs_path(scope: scope) }
- = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
-
- - if @all_builds.running_or_pending.any?
- #js-stop-jobs-modal
- .nav-controls
- = render Pajamas::ButtonComponent.new(variant: :danger, button_options: { id: 'js-stop-jobs-button', data: { url: cancel_all_admin_jobs_path } }) do
- = s_('AdminArea|Stop all jobs')
-
- .row-content-block.second-block
- #{(@scope || 'all').capitalize} jobs
-
- %ul.content-list.builds-content-list.admin-builds-table
- = render "projects/jobs/table", builds: @builds, admin: true
+#admin-jobs-app{ data: { job_statuses: job_statuses.to_json, empty_state_svg_path: image_path('jobs-empty-state.svg'), url: cancel_all_admin_jobs_path } }
diff --git a/app/views/admin/topics/_form.html.haml b/app/views/admin/topics/_form.html.haml
index c3b5161d617..2638e45c9eb 100644
--- a/app/views/admin/topics/_form.html.haml
+++ b/app/views/admin/topics/_form.html.haml
@@ -20,7 +20,7 @@
= f.label :description, _("Description")
.js-markdown-editor{ data: { render_markdown_path: preview_markdown_admin_topics_path,
markdown_docs_path: help_page_path('user/markdown'),
- qa_selector: 'topic_form_description',
+ testid: 'topic-form-description',
form_field_placeholder: _('Write a description…'),
supports_quick_actions: 'false',
enable_autocomplete: 'false',
diff --git a/app/views/admin/users/_access_levels.html.haml b/app/views/admin/users/_access_levels.html.haml
index 4979f7e28e7..5c80b3b4352 100644
--- a/app/views/admin/users/_access_levels.html.haml
+++ b/app/views/admin/users/_access_levels.html.haml
@@ -9,7 +9,7 @@
= f.number_field :projects_limit, min: 0, max: Gitlab::Database::MAX_INT_VALUE, class: 'form-control gl-form-input gl-form-input-sm'
.form-group.gl-form-group{ role: 'group' }
- = f.gitlab_ui_checkbox_component :can_create_group, s_('AdminUsers|Can create group')
+ = f.gitlab_ui_checkbox_component :can_create_group, s_('AdminUsers|Can create top level group')
= f.gitlab_ui_checkbox_component :private_profile, s_('AdminUsers|Private profile')
%fieldset.form-group.gl-form-group
diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml
index 8f7741b8a32..f6b7db2032f 100644
--- a/app/views/admin/users/_head.html.haml
+++ b/app/views/admin/users/_head.html.haml
@@ -31,7 +31,7 @@
- if impersonation_enabled?
.gl-p-2
%span.btn-group{ class: !@can_impersonate ? 'has-tooltip' : nil, title: @impersonation_error_text }
- = render Pajamas::ButtonComponent.new(disabled: !@can_impersonate, method: :post, href: impersonate_admin_user_path(@user), button_options: { data: { qa_selector: 'impersonate_user_link', testid: 'impersonate_user_link' } }) do
+ = render Pajamas::ButtonComponent.new(disabled: !@can_impersonate, method: :post, href: impersonate_admin_user_path(@user), button_options: { data: { testid: 'impersonate-user-link' } }) do
= _('Impersonate')
- if can_force_email_confirmation?(@user)
.gl-p-2
@@ -48,5 +48,5 @@
= gl_tab_link_to _("SSH keys"), keys_admin_user_path(@user)
= gl_tab_link_to _("Identities"), admin_user_identities_path(@user)
- if impersonation_enabled?
- = gl_tab_link_to _("Impersonation Tokens"), admin_user_impersonation_tokens_path(@user), data: { qa_selector: 'impersonation_tokens_tab' }
+ = gl_tab_link_to _("Impersonation Tokens"), admin_user_impersonation_tokens_path(@user), data: { testid: 'impersonation-tokens-tab' }
.gl-mb-3
diff --git a/app/views/admin/users/_users.html.haml b/app/views/admin/users/_users.html.haml
index 213d5847986..d4a9009a0cf 100644
--- a/app/views/admin/users/_users.html.haml
+++ b/app/views/admin/users/_users.html.haml
@@ -35,7 +35,7 @@
= gl_tab_link_to admin_users_path(filter: "banned"), { item_active: active_when(params[:filter] == 'banned'), class: 'gl-border-0!' } do
= s_('AdminUsers|Banned')
= gl_tab_counter_badge(limited_counter_with_delimiter(User.banned))
- = gl_tab_link_to admin_users_path(filter: "blocked_pending_approval"), { item_active: active_when(params[:filter] == 'blocked_pending_approval'), class: 'filter-blocked-pending-approval gl-border-0!', data: { qa_selector: 'pending_approval_tab' } } do
+ = gl_tab_link_to admin_users_path(filter: "blocked_pending_approval"), { item_active: active_when(params[:filter] == 'blocked_pending_approval'), class: 'filter-blocked-pending-approval gl-border-0!', data: { testid: 'pending-approval-tab' } } do
= s_('AdminUsers|Pending approval')
= gl_tab_counter_badge(limited_counter_with_delimiter(User.blocked_pending_approval))
= gl_tab_link_to admin_users_path(filter: "deactivated"), { item_active: active_when(params[:filter] == 'deactivated'), class: 'gl-border-0!' } do
@@ -56,7 +56,7 @@
= hidden_field_tag "filter", h(params[:filter])
.search-holder
.search-field-holder.gl-mb-4
- = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email, or username'), class: 'form-control search-text-input js-search-input', spellcheck: false, data: { qa_selector: 'user_search_field' }
+ = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email, or username'), class: 'form-control search-text-input js-search-input', spellcheck: false, data: { testid: 'user-search-field' }
- if @sort.present?
= hidden_field_tag :sort, @sort
= sprite_icon('search', css_class: 'search-icon')
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index a4ae29bed81..4cc3e12a8ad 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -45,7 +45,7 @@
= link_button_to nil, remove_email_admin_user_path(@user, email), data: { confirm: _("Are you sure you want to remove %{email}?") % { email: email.email }, 'confirm-btn-variant': 'danger' }, method: :delete, class: 'float-right', title: _('Remove secondary email'), id: "remove_email_#{email.id}", variant: :danger, size: :small, icon: 'close'
%li
%span.light ID:
- %strong{ data: { qa_selector: 'user_id_content' } }
+ %strong{ data: { testid: 'user-id-content' } }
= @user.id
%li
%span.light= _('Namespace ID:')
@@ -71,7 +71,7 @@
= render_if_exists 'admin/users/provisioned_by', user: @user
%li
- %span.light= _('Can create groups:')
+ %span.light= _('Can create top level groups:')
%strong
= @user.can_create_group ? _('Yes') : _('No')
%li
diff --git a/app/views/ci/runner/_how_to_setup_runner.html.haml b/app/views/ci/runner/_how_to_setup_runner.html.haml
index cdf25a9348c..c46aabf2604 100644
--- a/app/views/ci/runner/_how_to_setup_runner.html.haml
+++ b/app/views/ci/runner/_how_to_setup_runner.html.haml
@@ -8,13 +8,13 @@
= _("Register the runner with this URL:")
%br
%code#coordinator_address= root_url(only_path: false)
- = clipboard_button(target: '#coordinator_address', title: _("Copy URL"))
+ = deprecated_clipboard_button(target: '#coordinator_address', title: _("Copy URL"))
%br
%br
= _("And this registration token:")
%br
%code#registration_token{ data: {testid: 'registration_token' } }= registration_token
- = clipboard_button(target: '#registration_token', title: _("Copy token"))
+ = deprecated_clipboard_button(target: '#registration_token', title: _("Copy token"))
.gl-mt-3.gl-mb-3
= render Pajamas::ButtonComponent.new(variant: :default, method: :put, href: reset_token_url, button_options: { id: 'Reset registration token', data: { confirm: _("Are you sure you want to reset the registration token?") } }) do
diff --git a/app/views/ci/variables/_variable_row.html.haml b/app/views/ci/variables/_variable_row.html.haml
deleted file mode 100644
index a710655aa20..00000000000
--- a/app/views/ci/variables/_variable_row.html.haml
+++ /dev/null
@@ -1,36 +0,0 @@
-- form_field = local_assigns.fetch(:form_field, nil)
-- variable = local_assigns.fetch(:variable, nil)
-
-- id = variable&.id
-- variable_type = variable&.variable_type
-- key = variable&.key
-- value = variable&.value
-
-- id_input_name = "#{form_field}[variables_attributes][][id]"
-- destroy_input_name = "#{form_field}[variables_attributes][][_destroy]"
-- variable_type_input_name = "#{form_field}[variables_attributes][][variable_type]"
-- key_input_name = "#{form_field}[variables_attributes][][key]"
-- value_input_name = "#{form_field}[variables_attributes][][secret_value]"
-
-%li.js-row.ci-variable-row{ data: { is_persisted: "#{!id.nil?}" } }
- .ci-variable-row-body.border-bottom
- %input.js-ci-variable-input-id{ type: "hidden", name: id_input_name, value: id }
- %input.js-ci-variable-input-destroy{ type: "hidden", name: destroy_input_name }
- %select.js-ci-variable-input-variable-type.ci-variable-body-item.form-control.select-control.custom-select.table-section.section-15{ name: variable_type_input_name }
- = options_for_select(ci_variable_type_options, variable_type)
- %input.js-ci-variable-input-key.ci-variable-body-item.form-control.gl-form-input.table-section.section-15{ type: "text",
- name: key_input_name,
- value: key,
- placeholder: s_('CiVariables|Input variable key') }
- .ci-variable-body-item.gl-show-field-errors.table-section.section-15.border-top-0.p-0
- .form-control.js-secret-value-placeholder.overflow-hidden{ class: ('hide' unless id) }
- = '*' * 17
- %textarea.js-ci-variable-input-value.js-secret-value.form-control.gl-form-input{ class: ('hide' if id),
- rows: 1,
- name: value_input_name,
- placeholder: s_('CiVariables|Input variable value') }
- = value
- %p.masking-validation-error.gl-field-error.hide
- = s_("CiVariables|Cannot use Masked Variable with current value")
- = link_to sprite_icon('question-o'), help_page_path('ci/variables/index', anchor: 'mask-a-cicd-variable'), target: '_blank', rel: 'noopener noreferrer'
- = render Pajamas::ButtonComponent.new(icon: 'close', button_options: { class: 'js-row-remove-button ci-variable-row-remove-button table-section', 'aria-label': s_('CiVariables|Remove variable row') })
diff --git a/app/views/clusters/clusters/_provider_details_form.html.haml b/app/views/clusters/clusters/_provider_details_form.html.haml
index 59706b6d8c4..4b7164f9845 100644
--- a/app/views/clusters/clusters/_provider_details_form.html.haml
+++ b/app/views/clusters/clusters/_provider_details_form.html.haml
@@ -1,7 +1,7 @@
= gitlab_ui_form_for cluster, url: update_cluster_url_path, html: { class: 'js-provider-details gl-show-field-errors', role: 'form' },
as: :cluster do |field|
.form-group
- - copy_name_btn = clipboard_button(text: cluster.name, title: s_('ClusterIntegration|Copy Kubernetes cluster name'),
+ - copy_name_btn = deprecated_clipboard_button(text: cluster.name, title: s_('ClusterIntegration|Copy Kubernetes cluster name'),
class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields?
= field.label :name, s_('ClusterIntegration|Kubernetes cluster name'), class: 'label-bold required'
.input-group.gl-field-error-anchor
@@ -12,7 +12,7 @@
= field.fields_for :platform_kubernetes, platform do |platform_field|
.form-group
- - copy_api_url = clipboard_button(text: platform.api_url, title: s_('ClusterIntegration|Copy API URL'),
+ - copy_api_url = deprecated_clipboard_button(text: platform.api_url, title: s_('ClusterIntegration|Copy API URL'),
class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields?
= platform_field.label :api_url, s_('ClusterIntegration|API URL'), class: 'label-bold required'
.input-group.gl-field-error-anchor
@@ -22,7 +22,7 @@
append: copy_api_url
.form-group
- - copy_ca_cert_btn = clipboard_button(text: platform.ca_cert, title: s_('ClusterIntegration|Copy CA Certificate'),
+ - copy_ca_cert_btn = deprecated_clipboard_button(text: platform.ca_cert, title: s_('ClusterIntegration|Copy CA Certificate'),
class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields?
= platform_field.label :ca_cert, s_('ClusterIntegration|CA Certificate'), class: 'label-bold'
.input-group.gl-field-error-anchor
diff --git a/app/views/dashboard/groups/_groups.html.haml b/app/views/dashboard/groups/_groups.html.haml
index ea7cd75152d..ddf3bd5ae07 100644
--- a/app/views/dashboard/groups/_groups.html.haml
+++ b/app/views/dashboard/groups/_groups.html.haml
@@ -1,2 +1,2 @@
.js-groups-list-holder
- #js-groups-tree{ data: { endpoint: dashboard_groups_path(format: :json), path: dashboard_groups_path, form_sel: 'form#group-filter-form', filter_sel: '.js-groups-list-filter', holder_sel: '.js-groups-list-holder', dropdown_sel: '.js-group-filter-dropdown-wrap' } }
+ #js-groups-tree{ data: { endpoint: dashboard_groups_path(format: :json), path: dashboard_groups_path, form_sel: 'form#group-filter-form', filter_sel: '.js-groups-list-filter', holder_sel: '.js-groups-list-holder', dropdown_sel: '.js-group-filter-dropdown-wrap', groups_empty_state_illustration: image_path('illustrations/empty-state/empty-groups-md.svg') } }
diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml
index 7f004e405a7..c5abc964fda 100644
--- a/app/views/dashboard/groups/index.html.haml
+++ b/app/views/dashboard/groups/index.html.haml
@@ -3,8 +3,4 @@
= render_dashboard_ultimate_trial(current_user)
= render 'dashboard/groups_head'
-- if params[:filter].blank? && @groups.empty?
- .empty-state
- = render 'shared/groups/empty_state'
-- else
- = render 'groups'
+= render 'groups'
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index 1cd8015934e..181c79e7bd0 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -1,11 +1,11 @@
%li.todo.gl-hover-border-blue-200.gl-hover-bg-blue-50.gl-hover-cursor-pointer.gl-relative{ class: "todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo) }
.gl-display-flex.gl-flex-direction-column.gl-sm-flex-direction-row.gl-sm-align-items-center
- .todo-item.gl-overflow-hidden.gl-overflow-x-auto.gl-align-self-center.gl-w-full{ data: { qa_selector: "todo_item_container" } }
+ .todo-item.gl-overflow-hidden.gl-overflow-x-auto.gl-align-self-center.gl-w-full{ data: { testid: "todo-item-container" } }
.todo-title.gl-pt-2.gl-pb-3.gl-px-2.gl-md-mb-1.gl-font-sm.gl-text-secondary
= todo_target_state_pill(todo)
- %span.todo-target-title{ data: { qa_selector: "todo_target_title_content" }, :id => dom_id(todo) + "_describer" }
+ %span.todo-target-title{ :id => dom_id(todo) + "_describer" }
= todo_target_title(todo)
- if !todo.for_design? && !todo.member_access_requested?
@@ -25,7 +25,7 @@
= author_avatar(todo, size: 24)
.todo-note
- if todo_author_display?(todo)
- .author-name.bold.gl-display-inline{ data: { qa_selector: "todo_author_name_content" } }<
+ .author-name.bold.gl-display-inline{ data: { testid: "todo-author-name-content" } }<
- if todo.author
= link_to_author(todo, self_added: todo.self_added?)
- else
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index c5f70397fad..3feb30085c0 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -36,7 +36,7 @@
.filter-item.gl-m-2
- if params[:group_id].present?
= hidden_field_tag(:group_id, params[:group_id])
- = dropdown_tag(group_dropdown_label(params[:group_id], _("Group")), options: { toggle_class: 'js-group-search js-filter-submit gl-xs-w-full!', title: s_("Todos|Filter by group"), filter: true, filterInput: 'input#group-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-group js-filter-submit', placeholder: _("Search groups"), data: { default_label: _("Group"), display: 'static', qa_selector: 'group_dropdown' } })
+ = dropdown_tag(group_dropdown_label(params[:group_id], _("Group")), options: { toggle_class: 'js-group-search js-filter-submit gl-xs-w-full!', title: s_("Todos|Filter by group"), filter: true, filterInput: 'input#group-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-group js-filter-submit', placeholder: _("Search groups"), data: { default_label: _("Group"), display: 'static', testid: 'group-dropdown' } })
.filter-item.gl-m-2
- if params[:project_id].present?
= hidden_field_tag(:project_id, params[:project_id])
diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml
index 345a1cc0225..e6551adffde 100644
--- a/app/views/devise/sessions/_new_base.html.haml
+++ b/app/views/devise/sessions/_new_base.html.haml
@@ -1,6 +1,6 @@
= gitlab_ui_form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'gl-p-5 gl-show-field-errors js-arkose-labs-form', aria: { live: 'assertive' }, data: { testid: 'sign-in-form' }}) do |f|
.form-group
- = f.label :login, _('Username or email')
+ = f.label :login, _('Username or primary email')
= f.text_field :login, value: @invite_email, class: 'form-control gl-form-input js-username-field', autocomplete: 'username', autofocus: 'autofocus', autocapitalize: 'off', autocorrect: 'off', required: true, title: _('This field is required.'), data: { qa_selector: 'login_field', testid: 'username-field' }
.form-group
= f.label :password, _('Password')
diff --git a/app/views/devise/shared/_email_opted_in.html.haml b/app/views/devise/shared/_email_opted_in.html.haml
deleted file mode 100644
index d8ed0028222..00000000000
--- a/app/views/devise/shared/_email_opted_in.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- return unless Gitlab.com?
-
-.gl-mb-3.js-email-opt-in.hidden
- .gl-font-weight-bold.gl-mb-3
- = _('Email updates (optional)')
- = f.gitlab_ui_checkbox_component :email_opted_in, _("I'd like to receive updates about GitLab via email")
diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
index 8f2c2c58790..73b9a3d5c5a 100644
--- a/app/views/devise/shared/_omniauth_box.html.haml
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -3,7 +3,7 @@
- if restyle_login_page_enabled && (any_form_based_providers_enabled? || password_authentication_enabled_for_web?)
.omniauth-divider.gl-display-flex.gl-align-items-center
- = _("or")
+ = _("or sign in with")
.gl-mt-5.gl-px-5{ class: restyle_login_page_enabled ? 'omniauth-container gl-text-center gl-ml-auto gl-mr-auto' : 'omniauth-container gl-py-5' }
- if !restyle_login_page_enabled
diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml
index 6d37257232b..bf1b604465b 100644
--- a/app/views/devise/shared/_signup_box.html.haml
+++ b/app/views/devise/shared/_signup_box.html.haml
@@ -17,7 +17,7 @@
class: 'form-control gl-form-input top js-block-emoji js-validate-length',
data: { max_length: max_first_name_length,
max_length_message: s_('SignUp|First name is too long (maximum is %{max_length} characters).') % { max_length: max_first_name_length },
- qa_selector: 'new_user_first_name_field' },
+ testid: 'new-user-first-name-field' },
required: true,
title: _('This field is required.')
.col.form-group
@@ -26,7 +26,7 @@
class: 'form-control gl-form-input top js-block-emoji js-validate-length',
data: { max_length: max_last_name_length,
max_length_message: s_('SignUp|Last name is too long (maximum is %{max_length} characters).') % { max_length: max_last_name_length },
- qa_selector: 'new_user_last_name_field' },
+ testid: 'new-user-last-name-field' },
required: true,
title: _('This field is required.')
.username.form-group
@@ -44,7 +44,7 @@
= f.label :email, _('Email')
= f.email_field :email,
class: 'form-control gl-form-input middle js-validate-email',
- data: { qa_selector: 'new_user_email_field' },
+ data: { testid: 'new-user-email-field' },
required: true,
title: _('Please provide a valid email address.')
%p.validation-hint.gl-field-hint.text-secondary= _('We recommend a work email address.')
@@ -56,7 +56,7 @@
%input.form-control.gl-form-input.js-password{ data: { id: "#{form_resource_name}_password",
title: s_('SignUp|Minimum length is %{minimum_password_length} characters.') % { minimum_password_length: @minimum_password_length },
minimum_password_length: @minimum_password_length,
- qa_selector: 'new_user_password_field',
+ testid: 'new-user-password-field',
autocomplete: 'new-password',
name: "#{form_resource_name}[password]" } }
%p.gl-field-hint-valid.text-secondary= s_('SignUp|Minimum length is %{minimum_password_length} characters.') % { minimum_password_length: @minimum_password_length }
@@ -69,7 +69,7 @@
- elsif show_recaptcha_sign_up?
= recaptcha_tags nonce: content_security_policy_nonce
- = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { qa_selector: 'new_user_register_button' }}) do
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true, button_options: { data: { testid: 'new-user-register-button' }}) do
= button_text
= render 'devise/shared/terms_of_service_notice', button_text: button_text
diff --git a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
index fcd52f33121..76a805d4d1b 100644
--- a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
+++ b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
@@ -5,4 +5,5 @@
= form_tag path do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/
- = submit_tag _('Revoke'), class: 'gl-button btn btn-danger btn-sm', aria: { label: s_('AuthorizedApplication|Revoke application') }, data: { confirm: s_('AuthorizedApplication|Are you sure you want to revoke this application?'), confirm_btn_variant: 'danger' }
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :danger, size: :small, button_options: { aria: { label: s_('AuthorizedApplication|Revoke application') }, data: { confirm: s_('AuthorizedApplication|Are you sure you want to revoke this application?'), confirm_btn_variant: 'danger' } }) do
+ = _('Revoke')
diff --git a/app/views/events/_event.atom.builder b/app/views/events/_event.atom.builder
index c429bbbb610..43a545c4b4e 100644
--- a/app/views/events/_event.atom.builder
+++ b/app/views/events/_event.atom.builder
@@ -6,7 +6,7 @@ event = event.present
event_url = event_feed_url(event)
xml.entry do
- xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
+ xml.id "tag:#{request.host},#{event.created_at.to_date.iso8601}:#{event.id}"
xml.link href: event_url if event_url
xml.title truncate(event_feed_title(event), length: 80)
xml.updated event.updated_at.xmlschema
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index 4a6b7fcfa84..0ad969116e0 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -6,13 +6,11 @@
.event-title.d-flex.flex-wrap
= inline_event_icon(event)
- - many_refs = event.ref_count.to_i > 1
- %span.event-type.d-inline-block.gl-mr-2.pushed= many_refs ? "#{event.action_name} #{event.ref_count} #{event.ref_type.pluralize}" : "#{event.action_name} #{event.ref_type}"
- - unless many_refs
+ %span.event-type.d-inline-block.gl-mr-2.pushed= event.push_activity_description
+ - unless event.batch_push?
%span.gl-mr-2.text-truncate
- commits_link = project_commits_path(project, event.ref_name)
- - should_link = event.tag? ? project.repository.tag_exists?(event.ref_name) : project.repository.branch_exists?(event.ref_name)
- = link_to_if should_link, event.ref_name, commits_link, class: 'ref-name'
+ = link_to_if event.linked_to_reference?, event.ref_name, commits_link, class: 'ref-name'
= render "events/event_scope", event: event
diff --git a/app/views/explore/groups/_groups.html.haml b/app/views/explore/groups/_groups.html.haml
index 3291129fd69..37e5be521b4 100644
--- a/app/views/explore/groups/_groups.html.haml
+++ b/app/views/explore/groups/_groups.html.haml
@@ -1,3 +1,3 @@
.js-groups-list-holder
- #js-groups-tree{ data: { endpoint: explore_groups_path(format: :json), path: explore_groups_path, form_sel: 'form#group-filter-form', filter_sel: '.js-groups-list-filter', holder_sel: '.js-groups-list-holder', dropdown_sel: '.js-group-filter-dropdown-wrap' } }
+ #js-groups-tree{ data: { endpoint: explore_groups_path(format: :json), path: explore_groups_path, form_sel: 'form#group-filter-form', filter_sel: '.js-groups-list-filter', holder_sel: '.js-groups-list-holder', dropdown_sel: '.js-group-filter-dropdown-wrap', groups_empty_state_illustration: image_path('illustrations/empty-state/empty-groups-md.svg') } }
= gl_loading_icon(size: 'md', css_class: 'gl-mt-6')
diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml
index 213346b4cc2..ddb82411add 100644
--- a/app/views/explore/groups/index.html.haml
+++ b/app/views/explore/groups/index.html.haml
@@ -22,7 +22,4 @@
%p= _("Below you will find all the groups that are public.")
%p= _("You can easily contribute to them by requesting to join these groups.")
-- if params[:filter].blank? && @groups.empty?
- .nothing-here-block= _("No public groups")
-- else
- = render 'groups'
+= render 'groups'
diff --git a/app/views/groups/_import_group_from_another_instance_panel.html.haml b/app/views/groups/_import_group_from_another_instance_panel.html.haml
index 8c2434ca4a0..c35bbce6ba7 100644
--- a/app/views/groups/_import_group_from_another_instance_panel.html.haml
+++ b/app/views/groups/_import_group_from_another_instance_panel.html.haml
@@ -13,10 +13,9 @@
= s_('GroupsNew|Importing groups by direct transfer is currently disabled.')
- if current_user.admin?
- - admin_link_start = '<a href="%{url}">'.html_safe % { url: general_admin_application_settings_path(anchor: 'js-visibility-settings') }
- - admin_link_end = '</a>'.html_safe
+ - admin_link = link_to('', general_admin_application_settings_path(anchor: 'js-visibility-settings'))
- = s_('GroupsNew|Please %{admin_link_start}enable it in the Admin settings%{admin_link_end}.').html_safe % { admin_link_start: admin_link_start, admin_link_end: admin_link_end }
+ = safe_format(s_('GroupsNew|Please %{admin_link_start}enable it in the Admin settings%{admin_link_end}.'), tag_pair(admin_link, :admin_link_start, :admin_link_end))
- else
= s_('GroupsNew|Please ask your Administrator to enable it in the Admin settings.')
@@ -25,9 +24,8 @@
= render Pajamas::AlertComponent.new(dismissible: false,
variant: :warning) do |c|
- c.with_body do
- - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index.md', anchor: 'migrated-group-items') }
- - docs_link_end = '</a>'.html_safe
- = s_('GroupsNew|Not all group items are migrated. %{docs_link_start}What items are migrated%{docs_link_end}?').html_safe % { docs_link_start: docs_link_start, docs_link_end: docs_link_end }
+ - docs_link = link_to('', help_page_path('user/group/import/index.md', anchor: 'migrated-group-items'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('GroupsNew|Not all group items are migrated. %{docs_link_start}What items are migrated%{docs_link_end}?'), tag_pair(docs_link, :docs_link_start, :docs_link_end))
%p.gl-mt-3
= s_('GroupsNew|Provide credentials for the source instance to import from. You can provide this instance as a source to move groups in this instance.')
@@ -41,9 +39,9 @@
.form-group.gl-display-flex.gl-flex-direction-column
= f.label :bulk_import_gitlab_access_token, s_('GroupsNew|Personal access token'), for: 'import_gitlab_token'
.gl-font-weight-normal
- - pat_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: help_page_path('user/profile/personal_access_tokens') }
- - short_living_link_start = '<a href="%{url}" target="_blank">'.html_safe % { url: help_page_path('security/token_overview', anchor: 'security-considerations') }
- = s_('GroupsNew|Create a token with %{code_start}api%{code_end} and %{code_start}read_repository%{code_end} scopes in the %{pat_link_start}user settings%{pat_link_end} of the source GitLab instance. For %{short_living_link_start}security reasons%{short_living_link_end}, set a short expiration date for the token. Keep in mind that large migrations take more time.').html_safe % { code_start: '<code>'.html_safe, code_end: '</code>'.html_safe, pat_link_start: pat_link_start, pat_link_end: '</a>'.html_safe, short_living_link_start: short_living_link_start, short_living_link_end: '</a>'.html_safe }
+ - pat_link = link_to('', help_page_path('user/profile/personal_access_tokens'), target: '_blank')
+ - short_living_link = link_to('', help_page_path('security/token_overview', anchor: 'security-considerations'), target: '_blank')
+ = safe_format(s_('GroupsNew|Create a token with %{code_start}api%{code_end} and %{code_start}read_repository%{code_end} scopes in the %{pat_link_start}user settings%{pat_link_end} of the source GitLab instance. For %{short_living_link_start}security reasons%{short_living_link_end}, set a short expiration date for the token. Keep in mind that large migrations take more time.'), tag_pair('<code></code>'.html_safe, :code_start , :code_end), tag_pair(pat_link, :pat_link_start, :pat_link_end), tag_pair(short_living_link, :short_living_link_start, :short_living_link_end))
= f.text_field :bulk_import_gitlab_access_token, placeholder: s_('GroupsNew|e.g. h8d3f016698e...'), class: 'gl-form-input gl-mt-3 col-xs-12 col-sm-8',
required: true,
disabled: bulk_imports_disabled,
diff --git a/app/views/groups/dependency_proxies/show.html.haml b/app/views/groups/dependency_proxies/show.html.haml
index 8416cb81c95..02a024ed3b5 100644
--- a/app/views/groups/dependency_proxies/show.html.haml
+++ b/app/views/groups/dependency_proxies/show.html.haml
@@ -1,6 +1,7 @@
- page_title _("Dependency Proxy")
#js-dependency-proxy{ data: { group_path: @group.full_path,
+ endpoint: group_dependency_proxy_path(@group),
no_manifests_illustration: image_path('illustrations/docker-empty-state.svg'),
group_id: @group.id,
settings_path: group_settings_packages_and_registries_path(@group),
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index c11154cbd75..8d6eebc27b0 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -28,8 +28,8 @@
.settings-content
= render 'groups/settings/permissions'
-= render_if_exists 'groups/merge_requests', expanded: expanded, group: @group
-= render_if_exists 'groups/merge_request_approval_settings', expanded: expanded, group: @group, user: current_user
+= render_if_exists 'groups/settings/merge_requests/merge_requests', expanded: expanded, group: @group
+= render_if_exists 'groups/settings/merge_requests/merge_request_approval_settings', expanded: expanded, group: @group, user: current_user
= render_if_exists 'groups/analytics', expanded: expanded
%section.settings.no-animate#js-badge-settings{ class: ('expanded' if expanded) }
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index e5c66c2c432..fbfaaa49b39 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -15,7 +15,7 @@
= render_if_exists 'groups/group_members/create_service_account'
.js-invite-members-trigger{ data: { variant: 'confirm',
classes: 'gl-md-w-auto gl-w-full',
- trigger_source: 'group-members-page',
+ trigger_source: 'group_members_page',
display_text: _('Invite members') } }
= render 'groups/invite_groups_modal', group: @group, reload_page_on_submit: true
diff --git a/app/views/groups/labels/edit.html.haml b/app/views/groups/labels/edit.html.haml
index 9af842b01df..1a64ba0c27d 100644
--- a/app/views/groups/labels/edit.html.haml
+++ b/app/views/groups/labels/edit.html.haml
@@ -1,8 +1,9 @@
- add_to_breadcrumbs _("Labels"), group_labels_path(@group)
- breadcrumb_title _("Edit")
- page_title _("Edit"), @label.name, _("Labels")
+- show_lock_on_merge = @group.supports_lock_on_merge?
%h1.page-title.gl-font-size-h-display
= _('Edit Label')
-= render 'shared/labels/form', url: group_label_path(@group, @label), back_path: @previous_labels_path
+= render 'shared/labels/form', url: group_label_path(@group, @label), back_path: @previous_labels_path, show_lock_on_merge: show_lock_on_merge
diff --git a/app/views/groups/milestones/_form.html.haml b/app/views/groups/milestones/_form.html.haml
index e84fd7a8692..7665da08582 100644
--- a/app/views/groups/milestones/_form.html.haml
+++ b/app/views/groups/milestones/_form.html.haml
@@ -13,7 +13,7 @@
- @gfm_form = true
.js-markdown-editor{ data: { render_markdown_path: group_preview_markdown_path,
markdown_docs_path: help_page_path('user/markdown'),
- qa_selector: 'milestone_description_field',
+ testid: 'milestone-description-field',
form_field_placeholder: _('Write milestone description...'),
supports_quick_actions: 'false',
enable_autocomplete: 'true',
diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml
index f4749617463..45fd98adbb9 100644
--- a/app/views/groups/settings/_permissions.html.haml
+++ b/app/views/groups/settings/_permissions.html.haml
@@ -37,7 +37,7 @@
= render_if_exists 'groups/settings/wiki', f: f, group: @group
= render 'groups/settings/lfs', f: f
= render_if_exists 'groups/settings/code_suggestions', f: f, group: @group
- = render_if_exists 'groups/settings/ai_related_settings', f: f, group: @group
+ = render_if_exists 'groups/settings/experimental_settings', f: f, group: @group
= render_if_exists 'groups/settings/ai_third_party_settings', f: f, group: @group
= render 'groups/settings/git_access_protocols', f: f, group: @group
= render 'groups/settings/project_creation_level', f: f, group: @group
diff --git a/app/views/groups/settings/applications/index.html.haml b/app/views/groups/settings/applications/index.html.haml
index da3257ca27d..595336d8abb 100644
--- a/app/views/groups/settings/applications/index.html.haml
+++ b/app/views/groups/settings/applications/index.html.haml
@@ -3,7 +3,7 @@
- @force_desktop_expanded_sidebar = true
= render 'shared/doorkeeper/applications/index',
- oauth_applications_enabled: user_oauth_applications?,
+ oauth_applications_enabled: true,
oauth_authorized_applications_enabled: false,
form_url: group_settings_applications_path(@group),
application_url: ->(application) { group_settings_application_path(@group, application) },
diff --git a/app/views/groups/work_items/index.html.haml b/app/views/groups/work_items/index.html.haml
index 2e3d3dda941..299a90b362d 100644
--- a/app/views/groups/work_items/index.html.haml
+++ b/app/views/groups/work_items/index.html.haml
@@ -1,4 +1,4 @@
- page_title s_('WorkItem|Work items')
- add_page_specific_style 'page_bundles/issuable_list'
-.js-work-items-list-root{ data: { full_path: @group.full_path } }
+.js-work-items-list-root{ data: work_items_list_data(@group) }
diff --git a/app/views/groups/work_items/show.html.haml b/app/views/groups/work_items/show.html.haml
new file mode 100644
index 00000000000..eb962cc0b69
--- /dev/null
+++ b/app/views/groups/work_items/show.html.haml
@@ -0,0 +1 @@
+.h1 Work Item
diff --git a/app/views/help/instance_configuration/_size_limits.html.haml b/app/views/help/instance_configuration/_size_limits.html.haml
index add484feac9..1f6379314b9 100644
--- a/app/views/help/instance_configuration/_size_limits.html.haml
+++ b/app/views/help/instance_configuration/_size_limits.html.haml
@@ -42,8 +42,8 @@
%td= _('Maximum snippet size')
%td= instance_configuration_human_size_cell(size_limits[:snippet_size_limit])
%tr
- %td= s_('Import|Maximum import remote file size (MB)')
+ %td= s_('Import|Maximum import remote file size (MiB)')
%td= instance_configuration_human_size_cell(size_limits[:max_import_remote_file_size])
%tr
- %td= s_('BulkImport|Direct transfer maximum download file size (MB)')
+ %td= s_('BulkImport|Direct transfer maximum download file size (MiB)')
%td= instance_configuration_human_size_cell(size_limits[:bulk_import_max_download_file_size])
diff --git a/app/views/import/bitbucket_server/new.html.haml b/app/views/import/bitbucket_server/new.html.haml
index 292dd9d071c..de94f142a40 100644
--- a/app/views/import/bitbucket_server/new.html.haml
+++ b/app/views/import/bitbucket_server/new.html.haml
@@ -24,4 +24,5 @@
.col-md-4
= password_field_tag :personal_access_token, '', class: 'form-control gl-form-input gl-mr-3', placeholder: _('Personal Access Token'), size: 40
.form-actions
- = submit_tag _('List your Bitbucket Server repositories'), class: 'gl-button btn btn-confirm'
+ = render Pajamas::ButtonComponent.new(type: 'submit', variant: :confirm) do
+ = _('List your Bitbucket Server repositories')
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 53ecad1b474..bbde5f2843b 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -4,7 +4,7 @@
%head{ omit_og ? { } : { prefix: "og: http://ogp.me/ns#" } }
%meta{ charset: "utf-8" }
%meta{ 'http-equiv' => 'X-UA-Compatible', content: 'IE=edge' }
- %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1' }
+ %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
%title= page_title(site_name)
= Gon::Base.render_data(nonce: content_security_policy_nonce)
= yield :project_javascripts
@@ -48,6 +48,16 @@
= webpack_bundle_tag 'legacy_sentry'
= webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
+ - if vite_enabled
+ %meta{ name: 'controller-path', content: controller_full_path }
+ - if Rails.env.development?
+ = vite_client_tag
+ = vite_javascript_tag "main"
+ - if Gitlab.ee?
+ = vite_javascript_tag "main_ee"
+ - if Gitlab.jh?
+ = vite_javascript_tag "main_jh"
+
= yield :page_specific_javascripts
= webpack_bundle_tag 'super_sidebar' if show_super_sidebar?
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 95627c2884a..f52ea801eef 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -20,7 +20,6 @@
.mobile-overlay
= dispensable_render_if_exists 'layouts/header/verification_reminder'
.alert-wrapper.gl-force-block-formatting-context
- = yield :code_suggestions_third_party_alert
= dispensable_render 'shared/new_nav_announcement'
= dispensable_render 'shared/outdated_browser'
= dispensable_render_if_exists "layouts/header/licensed_user_count_threshold"
@@ -37,6 +36,7 @@
= dispensable_render_if_exists "layouts/header/seat_count_alert"
= dispensable_render_if_exists "shared/namespace_user_cap_reached_alert"
= dispensable_render_if_exists "shared/new_user_signups_cap_reached_alert"
+ = dispensable_render_if_exists "shared/silent_mode_banner"
= yield :page_level_alert
= yield :group_invite_members_banner
- unless @hide_top_bar
diff --git a/app/views/layouts/_snowplow.html.haml b/app/views/layouts/_snowplow.html.haml
index 399a826d611..10b2002dfef 100644
--- a/app/views/layouts/_snowplow.html.haml
+++ b/app/views/layouts/_snowplow.html.haml
@@ -2,6 +2,8 @@
- namespace = @group || @project&.namespace || @namespace
= webpack_bundle_tag 'tracker'
+- if Gitlab.com? && Feature.enabled?(:browsersdk_tracking)
+ = webpack_bundle_tag 'analytics'
= javascript_tag do
:plain
window.snowplowOptions = #{Gitlab::Tracking.options(@group).to_json}
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 28cbdf0a7a1..451c66b074b 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -12,13 +12,8 @@
= render 'peek/bar'
= header_message
- - if show_super_sidebar? # TODO: Move this CSS to a better place
- - if current_user
- :css
- body {
- --header-height: 0px;
- }
- - else
+ - if show_super_sidebar?
+ - if !current_user
= render partial: "layouts/header/super_sidebar_logged_out"
- else
= render partial: "layouts/header/default", locals: { project: @project, group: @group }
diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml
index 5ad20478f51..d07daf0aab9 100644
--- a/app/views/layouts/errors.html.haml
+++ b/app/views/layouts/errors.html.haml
@@ -1,7 +1,7 @@
!!! 5
%html{ lang: I18n.locale }
%head
- %meta{ :content => "width=device-width, initial-scale=1, maximum-scale=1", :name => "viewport" }
+ %meta{ :content => "width=device-width, initial-scale=1", :name => "viewport" }
%title= yield(:title)
%style
= Rails.application.assets_manifest.find_sources('errors.css').first.to_s.html_safe
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 83641fbb184..1d67ac942fa 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -21,7 +21,6 @@
= render 'groups/invite_members_modal', group: @group
= dispensable_render_if_exists "shared/web_hooks/group_web_hook_disabled_alert"
-= dispensable_render_if_exists "shared/code_suggestions_third_party_alert", source: @group
= dispensable_render_if_exists "shared/free_user_cap_alert", source: @group
= dispensable_render_if_exists "shared/unlimited_members_during_trial_alert", resource: @group
diff --git a/app/views/layouts/header/_current_user_dropdown.html.haml b/app/views/layouts/header/_current_user_dropdown.html.haml
index 7ce914cf660..75de13d4862 100644
--- a/app/views/layouts/header/_current_user_dropdown.html.haml
+++ b/app/views/layouts/header/_current_user_dropdown.html.haml
@@ -43,7 +43,7 @@
= link_to _("Switch to GitLab Next"), Gitlab::Saas.canary_toggle_com_url, data: { track_action: "click_link", track_label: "switch_to_canary", track_property: "navigation_top" }
%li.divider
- .js-new-nav-toggle{ data: { enabled: show_super_sidebar?.to_s, endpoint: profile_preferences_url} }
+ .js-new-nav-toggle{ data: { enabled: show_super_sidebar?.to_s, endpoint: profile_preferences_path} }
- if current_user_menu?(:sign_out)
%li.divider
diff --git a/app/views/layouts/header/_super_sidebar_logged_out.haml b/app/views/layouts/header/_super_sidebar_logged_out.haml
index 67322aced74..31dfdfb2bb3 100644
--- a/app/views/layouts/header/_super_sidebar_logged_out.haml
+++ b/app/views/layouts/header/_super_sidebar_logged_out.haml
@@ -44,4 +44,4 @@
- if allow_signup?
%li
= render Pajamas::ButtonComponent.new(href: new_user_registration_path, variant: :confirm) do
- = _('Register')
+ = Gitlab.com? ? _('Get free trial') : _('Register')
diff --git a/app/views/layouts/minimal.html.haml b/app/views/layouts/minimal.html.haml
index 5531c0ab23a..8b6a2a2f2a7 100644
--- a/app/views/layouts/minimal.html.haml
+++ b/app/views/layouts/minimal.html.haml
@@ -3,7 +3,7 @@
!!! 5
%html{ lang: I18n.locale, class: page_classes }
= render "layouts/head"
- %body{ data: body_data }
+ %body{ data: body_data, class: system_message_class }
= header_message
= render 'peek/bar'
= render 'layouts/published_experiments'
diff --git a/app/views/layouts/oauth_error.html.haml b/app/views/layouts/oauth_error.html.haml
index d5e0e8e9c1d..697bd9b5864 100644
--- a/app/views/layouts/oauth_error.html.haml
+++ b/app/views/layouts/oauth_error.html.haml
@@ -1,7 +1,7 @@
!!! 5
%html{ lang: I18n.locale }
%head
- %meta{ :content => "width=device-width, initial-scale=1, maximum-scale=1", :name => "viewport" }
+ %meta{ :content => "width=device-width, initial-scale=1", :name => "viewport" }
%title= yield(:title)
= stylesheet_link_tag 'application_utilities'
%style
diff --git a/app/views/layouts/organization.html.haml b/app/views/layouts/organization.html.haml
index 5a357c6f805..7e1bf228876 100644
--- a/app/views/layouts/organization.html.haml
+++ b/app/views/layouts/organization.html.haml
@@ -1,6 +1,6 @@
-- page_title @organization.name
-- header_title @organization.name, organization_path(@organization)
-- nav "organization"
+- page_title @organization.name if @organization
+- header_title @organization.name, organization_path(@organization) if @organization
+- nav(%w[index new].include?(params[:action]) ? "your_work" : "organization")
- @left_sidebar = true
= render template: "layouts/application"
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 18ae3353f4d..1e85bb6cc3a 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -23,7 +23,6 @@
= render 'projects/invite_members_modal', project: @project
= dispensable_render_if_exists "shared/web_hooks/web_hook_disabled_alert"
-= dispensable_render_if_exists "projects/code_suggestions_third_party_alert", project: @project
= dispensable_render_if_exists "projects/free_user_cap_alert", project: @project
= dispensable_render_if_exists 'shared/unlimited_members_during_trial_alert', resource: @project
diff --git a/app/views/layouts/service_desk.html.haml b/app/views/layouts/service_desk.html.haml
index 13e9785317c..e9c5d51c674 100644
--- a/app/views/layouts/service_desk.html.haml
+++ b/app/views/layouts/service_desk.html.haml
@@ -24,11 +24,5 @@
%br
= link_to "Unsubscribe", @unsubscribe_url
- -# EE-specific start
- - if Gitlab::CurrentSettings.email_additional_text.present?
- %br
- %br
- = Gitlab::Utils.nlbr(Gitlab::CurrentSettings.email_additional_text)
- -# EE-specific end
-
+ = render_if_exists 'layouts/email_additional_text'
= html_footer_message
diff --git a/app/views/layouts/terms.html.haml b/app/views/layouts/terms.html.haml
index 9a50e3e2eb2..29a561ae1a9 100644
--- a/app/views/layouts/terms.html.haml
+++ b/app/views/layouts/terms.html.haml
@@ -1,6 +1,7 @@
!!! 5
- add_page_specific_style 'page_bundles/terms'
- @hide_top_bar = true
+- @hide_top_bar_padding = true
- body_classes = [user_application_theme]
%html{ lang: I18n.locale, class: page_class }
= render "layouts/head"
diff --git a/app/views/notify/in_product_marketing_email.html.haml b/app/views/notify/in_product_marketing_email.html.haml
deleted file mode 100644
index a88d581c5de..00000000000
--- a/app/views/notify/in_product_marketing_email.html.haml
+++ /dev/null
@@ -1,51 +0,0 @@
-- if @message.series?
- %tr{ style: "background-color: #ffffff;" }
- %td{ style: "color: #424242; padding: 10px 30px; text-align: center; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;font-size: 16px; line-height: 22px; border: 1px solid #dddddd" }
- %p
- = @message.progress.html_safe
-%tr
- %td{ bgcolor: "#ffffff", height: "auto", style: "max-width: 600px; width: 100%; text-align: center; height: 200px; padding: 25px 15px; mso-line-height-rule: exactly; min-height: 40px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;", valign: "middle", width: "100%" }
- = inline_image_link(@message.logo_path, { width: '150', style: 'width: 150px;' })
- %h1{ style: "font-size: 40px; line-height: 46x; color: #000000; padding: 20px 0 0 0; font-weight: normal;" }
- = @message.title
- %h2{ style: "font-size: 28px; line-height: 34px; color: #000000; padding: 0; font-weight: 400;" }
- = @message.subtitle
-%tr
- %td{ style: "padding: 10px 20px 30px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#000000; font-size: 18px; line-height: 24px;" }
- %p{ style: "margin: 0 0 20px 0;" }
- = @message.body_line1.html_safe
- - @message.body_line2&.tap do |line|
- %p{ style: "margin: 0 0 20px 0;" }
- = line.html_safe
-- if @message.cta_text
- %tr
- %td{ align: "center", style: "padding: 10px 20px 80px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" }
- .cta_link.cta_link_primary= @message.cta_link
-- else
- %tr
- %td{ style: "padding: 10px 20px 10px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#000000; font-size: 16px; line-height: 20px;" }
- %table{ border: "0", cellpadding: "0", cellspacing: "0", width: "100%", style: "width: 100%; min-width: 100%;" }
- %tr
- %td{ width: "50%", style: "width: 50%; min-width: 50%; color: #000000; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; font-size: 16px; line-height: 100%; padding-bottom: 16px; text-align: left;", align: "left" }
- = @message.feedback_ratings(1)
- %td{ width: "50%", style: "width: 50%; min-width: 50%; color: #000000; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; font-size: 16px; line-height: 100%; padding-bottom: 16px; text-align: right;", align: "right" }
- = @message.feedback_ratings(5)
- %tr
- %td{ align: "center", style: "padding: 10px 1px 30px 1px;" }
- %table{ align: "center", cellpadding: "5", cellspacing: "0", width: "100%", style: "width: 100%; min-width: 100%; border: 1px solid #dae0ea; border-radius: 0; min-width: 100%; text-align: center; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; font-size: 16px;" }
- %tr
- - (1..5).each do |rating|
- %td{ height: "54", style: "border-left: 1px solid #dae0ea; padding-bottom: 0; width: 9% !important;", width: "9%" }
- %a{ href: @message.feedback_link(rating), style: "color: #424242; display: block; text-decoration: none;" }
- %span{ height: "54", style: "display: block; font-size: 18px; height: 22px; line-height: 22px; padding: 16px 0; width: 100%; text-decoration: none;" }
- = rating
- %tr
- %td{ style: "padding: 10px 20px 30px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#000000; font-size: 18px; line-height: 24px;" }
- %p{ style: "margin: 0 0 50px 0;" }
- = @message.feedback_thanks
-- if @message.invite_members?
- %tr
- %td{ align: "center", style: "padding: 0 20px 80px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" }
- = @message.invite_text
- %br
- = @message.invite_link
diff --git a/app/views/notify/in_product_marketing_email.text.erb b/app/views/notify/in_product_marketing_email.text.erb
deleted file mode 100644
index 79a366eb1cc..00000000000
--- a/app/views/notify/in_product_marketing_email.text.erb
+++ /dev/null
@@ -1,36 +0,0 @@
-<%= @message.tagline %>
-
-<%= @message.title %>
-<%= @message.subtitle %>
-
-
-<%= @message.body_line1 %>
-
-<%= @message.body_line2 %>
-
-<% if @message.cta_text %>
-<%= @message.cta_link %>
-
-
-
-<% else %>
-<% (1..5).each do |rating| %>
-<%= "#{rating} - #{@message.feedback_ratings(rating).upcase} - #{@message.feedback_link(rating)}" %>
-<% end %>
-
-
-<%= @message.feedback_thanks %>
-<% end %>
-<% if @message.invite_members? %>
-<%= @message.invite_text %>
-<%= @message.invite_link %>
-<% end %>
-
-
-
-
-<%= @message.footer_links %>
-
-<%= @message.address %>
-
-<%= @message.unsubscribe %>
diff --git a/app/views/notify/member_access_granted_email.html.haml b/app/views/notify/member_access_granted_email.html.haml
index cce36f7b8a6..49a571f154e 100644
--- a/app/views/notify/member_access_granted_email.html.haml
+++ b/app/views/notify/member_access_granted_email.html.haml
@@ -8,11 +8,6 @@
%td.text-content
%p
= _('You have been granted %{access_level} access to the %{source_link} %{source_type}.').html_safe % { access_level: access_level, source_link: source_link, source_type: source_type }
- - if member.tasks_to_be_done.present?
- = s_("InviteEmail|You were assigned the following tasks:")
- %ul.list-style-position-inside
- - member.tasks_to_be_done.each do |task|
- %li= localized_tasks_to_be_done_choices[task]
%p
- leave_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: leave_link }
= _('If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}.').html_safe % { source_type: source_type, leave_link_start: leave_link_start, link_end: link_end }
diff --git a/app/views/notify/member_invited_email.html.haml b/app/views/notify/member_invited_email.html.haml
index 6d5207510da..21d0f8b9108 100644
--- a/app/views/notify/member_invited_email.html.haml
+++ b/app/views/notify/member_invited_email.html.haml
@@ -22,11 +22,6 @@
%p
- if member.created_by
= html_escape(s_("InviteEmail|%{inviter} invited you to join the %{strong_start}%{project_or_group_name}%{strong_end}%{br_tag}%{project_or_group} as a %{role}")) % placeholders.merge({ inviter: (link_to inviter_name, user_url(member.created_by)).html_safe })
- - if member.tasks_to_be_done.present?
- = s_("InviteEmail|and has assigned you the following tasks:")
- %ul.list-style-position-inside
- - member.tasks_to_be_done.each do |task|
- %li= localized_tasks_to_be_done_choices[task]
- else
= html_escape(s_("InviteEmail|You are invited to join the %{strong_start}%{project_or_group_name}%{strong_end}%{br_tag}%{project_or_group} as a %{role}")) % placeholders
%p.invite-actions
diff --git a/app/views/notify/new_email_address_added_email.haml b/app/views/notify/new_email_address_added_email.html.haml
index 6d00aaedfd5..6d00aaedfd5 100644
--- a/app/views/notify/new_email_address_added_email.haml
+++ b/app/views/notify/new_email_address_added_email.html.haml
diff --git a/app/views/notify/new_email_address_added_email.erb b/app/views/notify/new_email_address_added_email.text.erb
index 3af1953c902..3af1953c902 100644
--- a/app/views/notify/new_email_address_added_email.erb
+++ b/app/views/notify/new_email_address_added_email.text.erb
diff --git a/app/views/notify/resource_access_tokens_about_to_expire_email.html.haml b/app/views/notify/resource_access_tokens_about_to_expire_email.html.haml
new file mode 100644
index 00000000000..e4e34f6c8ee
--- /dev/null
+++ b/app/views/notify/resource_access_tokens_about_to_expire_email.html.haml
@@ -0,0 +1,13 @@
+%p
+ = _('Hi %{username}!') % { username: sanitize_name(@user.name) }
+%p
+ = _('One or more of your resource access tokens will expire in %{days_to_expire} or less:') % { days_to_expire: pluralize(@days_to_expire, _('day')) }
+%p
+ #{@resource.class.name.titleize}: #{@resource.full_path}
+%p
+ %ul
+ - @token_names.each do |token|
+ %li= token
+%p
+ - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: @target_url }
+ = html_escape(_('You can create a new one or check them in your %{link_start}access tokens%{link_end} settings.')) % { link_start: link_start, link_end: '</a>'.html_safe }
diff --git a/app/views/notify/resource_access_tokens_about_to_expire_email.text.erb b/app/views/notify/resource_access_tokens_about_to_expire_email.text.erb
new file mode 100644
index 00000000000..bea74f09129
--- /dev/null
+++ b/app/views/notify/resource_access_tokens_about_to_expire_email.text.erb
@@ -0,0 +1,11 @@
+<%= _('Hi %{username}!') % { username: sanitize_name(@user.name) } %>
+
+<%= _('One or more of your resource access tokens will expire in %{days_to_expire} or less:') % { days_to_expire: pluralize(@days_to_expire, _('day')) } %>
+
+<%= "#{@resource.class.name.titleize}: #{@resource.full_path}" %>
+
+<% @token_names.each do |token| %>
+ - <%= token %>
+<% end %>
+
+<%= _('You can create a new one or check them in your access token settings: %{target_url}') % { target_url: @target_url } %>
diff --git a/app/views/organizations/organizations/groups_and_projects.html.haml b/app/views/organizations/organizations/groups_and_projects.html.haml
index 8890f4b1ce5..a993e1c9404 100644
--- a/app/views/organizations/organizations/groups_and_projects.html.haml
+++ b/app/views/organizations/organizations/groups_and_projects.html.haml
@@ -1,3 +1,3 @@
- page_title _('Groups and projects')
-#js-organizations-groups-and-projects
+#js-organizations-groups-and-projects{ data: { app_data: organization_groups_and_projects_app_data } }
diff --git a/app/views/organizations/organizations/index.html.haml b/app/views/organizations/organizations/index.html.haml
new file mode 100644
index 00000000000..04a90b7589f
--- /dev/null
+++ b/app/views/organizations/organizations/index.html.haml
@@ -0,0 +1,2 @@
+- page_title s_('Organization|Organizations')
+- header_title _("Your work"), root_path
diff --git a/app/views/organizations/organizations/new.html.haml b/app/views/organizations/organizations/new.html.haml
new file mode 100644
index 00000000000..4d7f552c87b
--- /dev/null
+++ b/app/views/organizations/organizations/new.html.haml
@@ -0,0 +1,3 @@
+- page_title s_('Organization|New organization')
+- header_title _("Your work"), root_path
+- add_to_breadcrumbs s_('Organization|Organizations'), organizations_path
diff --git a/app/views/organizations/organizations/show.html.haml b/app/views/organizations/organizations/show.html.haml
index 8ba2a3d96ac..2ce4c0688ae 100644
--- a/app/views/organizations/organizations/show.html.haml
+++ b/app/views/organizations/organizations/show.html.haml
@@ -1,2 +1,4 @@
- page_title s_('Organization|Organization overview')
- @skip_current_level_breadcrumb = true
+
+#js-organizations-show{ data: { app_data: organization_show_app_data(@organization) } }
diff --git a/app/views/profiles/gpg_keys/index.html.haml b/app/views/profiles/gpg_keys/index.html.haml
index 2714193d1d1..982199d3d6f 100644
--- a/app/views/profiles/gpg_keys/index.html.haml
+++ b/app/views/profiles/gpg_keys/index.html.haml
@@ -28,7 +28,7 @@
%h4.gl-mt-0
= _('Add a GPG key')
%p
- - help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/repository/gpg_signed_commits/index.md') }
+ - help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/repository/signed_commits/gpg.md') }
= _('Add a GPG key for secure access to GitLab. %{help_link_start}Learn more%{help_link_end}.').html_safe % {help_link_start: help_link_start, help_link_end: '</a>'.html_safe }
= render 'form'
diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml
index d5193a424ef..1307c388041 100644
--- a/app/views/profiles/keys/_key_details.html.haml
+++ b/app/views/profiles/keys/_key_details.html.haml
@@ -46,7 +46,7 @@
.gl-display-flex
%pre.well-pre.gl-pl-5.gl-mb-0.gl-border-0
= @key.key
- = clipboard_button(title: s_('Profiles|Copy SSH key'), text: @key.key, class: 'gl-bg-gray-10 gl-px-3! gl-border-none! gl-rounded-top-left-none! gl-rounded-bottom-left-none!')
+ = deprecated_clipboard_button(title: s_('Profiles|Copy SSH key'), text: @key.key, class: 'gl-bg-gray-10 gl-px-3! gl-border-none! gl-rounded-top-left-none! gl-rounded-bottom-left-none!')
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, header_options: { class: 'gl-new-card-header' }, body_options: { class: 'gl-new-card-body gl-px-0'}) do |c|
- c.with_header do
diff --git a/app/views/profiles/notifications/_email_settings.html.haml b/app/views/profiles/notifications/_email_settings.html.haml
index 60f366f8878..6848426306b 100644
--- a/app/views/profiles/notifications/_email_settings.html.haml
+++ b/app/views/profiles/notifications/_email_settings.html.haml
@@ -1,6 +1,3 @@
-- form = local_assigns.fetch(:form)
.js-notification-email-listbox-input.gl-mb-3{ data: { label: _('Global notification email'), name: 'user[notification_email]', emails: @user.public_verified_emails.to_json, empty_value_text: _('Use primary email (%{email})') % { email: @user.email }, value: @user.notification_email, disabled: local_assigns.fetch(:email_change_disabled, nil) } }
.help-block
= local_assigns.fetch(:help_text, nil)
-.form-group
- = form.gitlab_ui_checkbox_component :email_opted_in, _('Receive product marketing emails')
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 2c7ef2b7e0e..87945f66ae7 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -19,8 +19,8 @@
= _('You can specify notification level per group or per project.')
.gl-mt-0
- = gitlab_ui_form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications gl-mt-3' } do |f|
- = render_if_exists 'profiles/notifications/email_settings', form: f
+ = gitlab_ui_form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications gl-mt-3 gl-mb-6' } do |f|
+ = render_if_exists 'profiles/notifications/email_settings'
= label_tag :global_notification_level, _('Global notification level'), class: "label-bold gl-mb-0"
.gl-text-secondary.gl-mb-3
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index 681d4e087f3..a6534a16e86 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -67,6 +67,13 @@
= link_to _('Learn more'), help_page_path('user/profile/preferences', anchor: 'behavior'), target: '_blank', rel: 'noopener noreferrer'
.form-group
= f.label :layout, class: 'label-bold' do
+ = s_('Preferences|Keyboard shortcuts')
+ - shortcuts_help_link = link_to('', help_page_path('user/shortcuts'), target: '_blank', rel: 'noopener noreferrer')
+ = f.gitlab_ui_checkbox_component :keyboard_shortcuts_enabled,
+ s_('Preferences|Enable keyboard shortcuts'),
+ help_text: safe_format(s_('Preferences|%{link_start}List of keyboard shortcuts%{link_end}'), tag_pair(shortcuts_help_link, :link_start, :link_end))
+ .form-group
+ = f.label :layout, class: 'label-bold' do
= s_('Preferences|Layout width')
= f.gitlab_ui_radio_component :layout, layout_choices[0][1], layout_choices[0][0], help_text: fixed_help_text
= f.gitlab_ui_radio_component :layout, layout_choices[1][1], layout_choices[1][0], help_text: fluid_help_text
@@ -140,7 +147,7 @@
%p.gl-text-secondary
= s_('Preferences|Configure how dates and times display for you.')
= succeed '.' do
- = link_to _('Learn more'), help_page_path('user/profile/preferences', anchor: 'time-preferences'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('Learn more'), help_page_path('user/profile/preferences', anchor: 'show-exact-times-instead-of-relative-times'), target: '_blank', rel: 'noopener noreferrer'
.form-group
= f.gitlab_ui_checkbox_component :time_display_relative,
s_('Preferences|Use relative times'),
diff --git a/app/views/projects/_export.html.haml b/app/views/projects/_export.html.haml
index 20fb2b43c63..58c760c54e8 100644
--- a/app/views/projects/_export.html.haml
+++ b/app/views/projects/_export.html.haml
@@ -9,8 +9,8 @@
- c.with_body do
%p
- - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/settings/import_export') }
- = _('Export this project with all its related data in order to move it to a new GitLab instance. When the exported file is ready, you can download it from this page or from the download link in the email notification you will receive. You can then import it when creating a new project. %{link_start}Learn more.%{link_end}').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('user/project/settings/import_export'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_('Export this project with all its related data in order to move it to a new GitLab instance. When the exported file is ready, you can download it from this page or from the download link in the email notification you will receive. You can then import it when creating a new project. %{link_start}Learn more.%{link_end}'), tag_pair(link, :link_start, :link_end))
.gl-mb-0
%p.gl-font-weight-bold= _('The following items will be exported:')
%ul
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 4ac30547ce3..759ec541af5 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -18,7 +18,7 @@
- if can?(current_user, :read_project, @project)
%span.gl-display-inline-block.gl-vertical-align-middle
= s_('ProjectPage|Project ID: %{project_id}') % { project_id: @project.id }
- = clipboard_button(title: s_('ProjectPage|Copy project ID'), text: @project.id)
+ = deprecated_clipboard_button(title: s_('ProjectPage|Copy project ID'), text: @project.id)
- if current_user
%span.gl-ml-3.gl-mb-3
= render 'shared/members/access_request_links', source: @project
diff --git a/app/views/projects/_invite_members_empty_project.html.haml b/app/views/projects/_invite_members_empty_project.html.haml
index 18d06c7d0bb..d6cab06f773 100644
--- a/app/views/projects/_invite_members_empty_project.html.haml
+++ b/app/views/projects/_invite_members_empty_project.html.haml
@@ -6,4 +6,4 @@
.js-invite-members-trigger{ data: { variant: 'confirm',
classes: 'gl-mb-8 gl-xs-w-full',
display_text: s_('InviteMember|Invite members'),
- trigger_source: 'project-empty-page' } }
+ trigger_source: 'project_empty_page' } }
diff --git a/app/views/projects/_merge_request_merge_checks_settings.html.haml b/app/views/projects/_merge_request_merge_checks_settings.html.haml
deleted file mode 100644
index bb7a7731067..00000000000
--- a/app/views/projects/_merge_request_merge_checks_settings.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-- form = local_assigns.fetch(:form)
-
-.form-group
- %b= s_('ProjectSettings|Merge checks')
- %p.text-secondary= s_('ProjectSettings|These checks must pass before merge requests can be merged.')
- = render 'projects/merge_request_pipelines_and_threads_options', form: form, project: @project
- = render_if_exists 'projects/merge_request_merge_checks_status_checks', form: form, project: @project
- = render_if_exists 'projects/merge_request_merge_checks_jira_enforcement', form: form, project: @project
diff --git a/app/views/projects/_merge_request_merge_commit_template.html.haml b/app/views/projects/_merge_request_merge_commit_template.html.haml
deleted file mode 100644
index 502014b7279..00000000000
--- a/app/views/projects/_merge_request_merge_commit_template.html.haml
+++ /dev/null
@@ -1,14 +0,0 @@
-- form = local_assigns.fetch(:form)
-
-.form-group
- %b= s_('ProjectSettings|Merge commit message template')
- %p.text-secondary
- = s_('ProjectSettings|The commit message used when merging, if the merge method creates a merge commit.')
- .mb-2
- = form.text_area :merge_commit_template_or_default, class: 'form-control gl-form-input', rows: 8, maxlength: Project::MAX_COMMIT_TEMPLATE_LENGTH, placeholder: s_('ProjectSettings|The default template will be applied on save.')
- %p.form-text.text-muted
- = s_('ProjectSettings|Leave empty to use default template.')
- = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_COMMIT_TEMPLATE_LENGTH })
- - configure_the_merge_commit_message_help_link_url = help_page_path('user/project/merge_requests/commit_templates.md')
- - configure_the_merge_commit_message_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: configure_the_merge_commit_message_help_link_url }
- = s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}').html_safe % { link_start: configure_the_merge_commit_message_help_link_start, link_end: '</a>'.html_safe }
diff --git a/app/views/projects/_merge_request_merge_options_settings.html.haml b/app/views/projects/_merge_request_merge_options_settings.html.haml
deleted file mode 100644
index e91c001ea3d..00000000000
--- a/app/views/projects/_merge_request_merge_options_settings.html.haml
+++ /dev/null
@@ -1,14 +0,0 @@
-- form = local_assigns.fetch(:form)
-
-.form-group#project-merge-options{ data: { project_full_path: @project.full_path } }
- %b= s_('ProjectSettings|Merge options')
- %p.text-secondary= s_('ProjectSettings|Additional settings that influence how and when merges are done.')
- = render_if_exists 'projects/merge_pipelines_settings', form: form
- = render_if_exists 'projects/merge_trains_settings', form: form
- = form.gitlab_ui_checkbox_component :resolve_outdated_diff_discussions,
- s_('ProjectSettings|Automatically resolve merge request diff threads when they become outdated')
- = form.gitlab_ui_checkbox_component :printing_merge_request_link_enabled,
- s_('ProjectSettings|Show link to create or view a merge request when pushing from the command line')
- = form.gitlab_ui_checkbox_component :remove_source_branch_after_merge,
- s_('ProjectSettings|Enable "Delete source branch" option by default'),
- help_text: s_('ProjectSettings|Existing merge requests and protected branches are not affected.')
diff --git a/app/views/projects/_merge_request_merge_suggestions_settings.html.haml b/app/views/projects/_merge_request_merge_suggestions_settings.html.haml
deleted file mode 100644
index eb2fc05686c..00000000000
--- a/app/views/projects/_merge_request_merge_suggestions_settings.html.haml
+++ /dev/null
@@ -1,14 +0,0 @@
-- form = local_assigns.fetch(:form)
-
-.form-group
- %b= s_('ProjectSettings|Merge suggestions')
- %p.text-secondary
- = s_('ProjectSettings|The commit message used when applying merge request suggestions.')
- .mb-2
- = form.text_field :suggestion_commit_message, class: 'form-control mb-2', placeholder: Gitlab::Suggestions::CommitMessage::DEFAULT_SUGGESTION_COMMIT_MESSAGE
- %p.form-text.text-muted
- = s_('ProjectSettings|Leave empty to use default template.')
- = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_SUGGESTIONS_TEMPLATE_LENGTH })
- - configure_the_commit_message_for_applied_suggestions_help_link_url = help_page_path('user/project/merge_requests/reviews/suggestions.md', anchor: 'configure-the-commit-message-for-applied-suggestions')
- - configure_the_commit_message_for_applied_suggestions_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: configure_the_commit_message_for_applied_suggestions_help_link_url }
- = s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}').html_safe % { link_start: configure_the_commit_message_for_applied_suggestions_help_link_start, link_end: '</a>'.html_safe }
diff --git a/app/views/projects/_merge_request_settings.html.haml b/app/views/projects/_merge_request_settings.html.haml
deleted file mode 100644
index 728ff597860..00000000000
--- a/app/views/projects/_merge_request_settings.html.haml
+++ /dev/null
@@ -1,18 +0,0 @@
-- form = local_assigns.fetch(:form)
-
-= render 'projects/merge_request_merge_method_settings', project: @project, form: form
-
-= render 'projects/merge_request_merge_options_settings', project: @project, form: form
-
-= render 'projects/merge_request_squash_options_settings', form: form
-
-= render 'projects/merge_request_merge_checks_settings', project: @project, form: form
-
-= render 'projects/merge_request_merge_suggestions_settings', project: @project, form: form
-
-= render 'projects/merge_request_merge_commit_template', project: @project, form: form
-
-= render 'projects/merge_request_squash_commit_template', project: @project, form: form
-
-- if @project.forked?
- = render 'projects/merge_request_target_project_settings', project: @project, form: form
diff --git a/app/views/projects/_merge_request_squash_commit_template.html.haml b/app/views/projects/_merge_request_squash_commit_template.html.haml
deleted file mode 100644
index 4d1b89bea83..00000000000
--- a/app/views/projects/_merge_request_squash_commit_template.html.haml
+++ /dev/null
@@ -1,14 +0,0 @@
-- form = local_assigns.fetch(:form)
-
-.form-group
- %b= s_('ProjectSettings|Squash commit message template')
- %p.text-secondary
- = s_('ProjectSettings|The commit message used when squashing commits.')
- .mb-2
- = form.text_area :squash_commit_template_or_default, class: 'form-control gl-form-input', rows: 8, maxlength: Project::MAX_COMMIT_TEMPLATE_LENGTH, placeholder: s_('ProjectSettings|The default template will be applied on save.')
- %p.form-text.text-muted
- = s_('ProjectSettings|Leave empty to use default template.')
- = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_COMMIT_TEMPLATE_LENGTH })
- - configure_the_squash_commit_message_help_link_url = help_page_path('user/project/merge_requests/commit_templates.md')
- - configure_the_squash_commit_message_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: configure_the_squash_commit_message_help_link_url }
- = s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}').html_safe % { link_start: configure_the_squash_commit_message_help_link_start, link_end: '</a>'.html_safe }
diff --git a/app/views/projects/_service_desk_settings.html.haml b/app/views/projects/_service_desk_settings.html.haml
index c2382a66132..3dbc4c0fad7 100644
--- a/app/views/projects/_service_desk_settings.html.haml
+++ b/app/views/projects/_service_desk_settings.html.haml
@@ -12,7 +12,7 @@
enabled: "#{@project.service_desk_enabled}",
issue_tracker_enabled: "#{@project.project_feature.issues_enabled?}",
incoming_email: (@project.service_desk_incoming_address if @project.service_desk_enabled),
- service_desk_email: (@project.service_desk_custom_address if @project.service_desk_enabled),
+ service_desk_email: (@project.service_desk_alias_address if @project.service_desk_enabled),
service_desk_email_enabled: "#{Gitlab::Email::ServiceDeskEmail.enabled?}",
selected_template: "#{@project.service_desk_setting&.issue_template_key}",
selected_file_template_project_id: "#{@project.service_desk_setting&.file_template_project_id}",
diff --git a/app/views/projects/_transfer.html.haml b/app/views/projects/_transfer.html.haml
index fe84a83c43c..cf0634ee411 100644
--- a/app/views/projects/_transfer.html.haml
+++ b/app/views/projects/_transfer.html.haml
@@ -8,15 +8,15 @@
.gl-new-card-title-wrapper
%h4.gl-new-card-title.warning-title= _('Transfer project')
%p.gl-new-card-description
- - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/settings/index', anchor: 'transfer-a-project-to-another-namespace') }
- = _("Transfer your project into another namespace. %{link_start}Learn more.%{link_end}").html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('user/project/settings/index', anchor: 'transfer-a-project-to-another-namespace'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_("Transfer your project into another namespace. %{link_start}Learn more.%{link_end}"), tag_pair(link, :link_start, :link_end))
- c.with_body do
= form_for @project, url: transfer_project_path(@project), method: :put, html: { class: 'js-project-transfer-form', id: form_id } do |f|
.form-group.gl-mb-0
%p
- - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/settings/index', anchor: 'rename-a-repository') }
- = _("A project’s repository name defines its URL (the one you use to access the project via a browser) and its place on the file disk where GitLab is installed. %{link_start}Learn more.%{link_end}").html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('user/project/settings/index', anchor: 'rename-a-repository'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_("A project’s repository name defines its URL (the one you use to access the project via a browser) and its place on the file disk where GitLab is installed. %{link_start}Learn more.%{link_end}"), tag_pair(link, :link_start, :link_end))
%p= _('When you transfer your project to a group, you can easily manage multiple projects, view usage quotas for storage, pipeline minutes, and users, and start a trial or upgrade to a paid tier.')
%p
= _("Don't have a group?")
diff --git a/app/views/projects/activity.html.haml b/app/views/projects/activity.html.haml
index 674b21b66b9..6a4760c3954 100644
--- a/app/views/projects/activity.html.haml
+++ b/app/views/projects/activity.html.haml
@@ -1,6 +1,4 @@
- page_title _("Activity")
-= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
-
= render 'projects/last_push'
= render 'projects/activity'
diff --git a/app/views/projects/artifacts/_tree_directory.html.haml b/app/views/projects/artifacts/_tree_directory.html.haml
index c68cc19f6c1..56105c4cac3 100644
--- a/app/views/projects/artifacts/_tree_directory.html.haml
+++ b/app/views/projects/artifacts/_tree_directory.html.haml
@@ -3,6 +3,6 @@
%tr.tree-item{ 'data-link' => path_to_directory }
%td.tree-item-file-name
= tree_icon('folder', '755', directory.name)
- = link_to path_to_directory, class: 'str-truncated', data: { qa_selector: 'directory_name_link', qa_directory_name: directory.name } do
+ = link_to path_to_directory, class: 'str-truncated', data: { testid: 'directory-name-link', qa_directory_name: directory.name } do
%span= directory.name
%td
diff --git a/app/views/projects/blob/_header_content.html.haml b/app/views/projects/blob/_header_content.html.haml
index 9cd2f583fdd..8c132a16797 100644
--- a/app/views/projects/blob/_header_content.html.haml
+++ b/app/views/projects/blob/_header_content.html.haml
@@ -3,7 +3,7 @@
.js-table-contents
= blob_icon blob.mode, blob.name
- %strong.file-title-name.gl-word-break-all{ data: { qa_selector: 'file_name_content' } }
+ %strong.file-title-name.gl-word-break-all{ data: { testid: 'file-name-content' } }
= blob.name
= copy_file_path_button(blob.path)
diff --git a/app/views/projects/blob/viewers/_markup.html.haml b/app/views/projects/blob/viewers/_markup.html.haml
index 703ffa8896e..01f730db33e 100644
--- a/app/views/projects/blob/viewers/_markup.html.haml
+++ b/app/views/projects/blob/viewers/_markup.html.haml
@@ -1,3 +1,3 @@
- blob = viewer.blob
-.file-content.md
+.file-content.js-markup-content.md
= markup(blob.name, blob.data, viewer.banzai_render_context)
diff --git a/app/views/projects/blob/viewers/_metrics_dashboard_yml.html.haml b/app/views/projects/blob/viewers/_metrics_dashboard_yml.html.haml
index 9c3f9b6c9fd..b7bc43d08d8 100644
--- a/app/views/projects/blob/viewers/_metrics_dashboard_yml.html.haml
+++ b/app/views/projects/blob/viewers/_metrics_dashboard_yml.html.haml
@@ -7,5 +7,3 @@
%ul
- viewer.errors.each do |error|
%li= error
-
-= link_to _('Learn more'), help_page_path('operations/metrics/dashboards/index.md')
diff --git a/app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml b/app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml
index 5e355ecc4b8..1f5086dc3bd 100644
--- a/app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml
+++ b/app/views/projects/blob/viewers/_metrics_dashboard_yml_loading.html.haml
@@ -1,4 +1,2 @@
= gl_loading_icon(inline: true, css_class: "mr-1")
= _('Metrics Dashboard YAML definition') + '…'
-
-= link_to _('Learn more'), help_page_path('operations/metrics/dashboards/yaml.md')
diff --git a/app/views/projects/branch_defaults/_branch_names_fields.html.haml b/app/views/projects/branch_defaults/_branch_names_fields.html.haml
index 4e4a72c154f..3e77cb51a85 100644
--- a/app/views/projects/branch_defaults/_branch_names_fields.html.haml
+++ b/app/views/projects/branch_defaults/_branch_names_fields.html.haml
@@ -6,7 +6,7 @@
.form-group
.gl-mb-2
- = f.text_field :issue_branch_template, class: 'form-control gl-mb-2', placeholder: "%{id}-%{title}"
+ = f.text_field :issue_branch_template, class: 'form-control gl-mb-2 gl-form-input-xl', placeholder: "%{id}-%{title}"
%p.form-text.text-muted
= s_('ProjectSettings|Leave empty to use default template.')
= sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Issue::MAX_BRANCH_TEMPLATE })
diff --git a/app/views/projects/branch_defaults/_default_branch_fields.html.haml b/app/views/projects/branch_defaults/_default_branch_fields.html.haml
index e4f51725f1a..2c59e187d30 100644
--- a/app/views/projects/branch_defaults/_default_branch_fields.html.haml
+++ b/app/views/projects/branch_defaults/_default_branch_fields.html.haml
@@ -6,7 +6,8 @@
.form-group
= f.label :default_branch, _("Default branch"), class: 'label-bold'
%p= s_('ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one.')
- .js-select-default-branch{ data: { default_branch: @project.default_branch, project_id: @project.id } }
+ .gl-form-input-xl
+ .js-select-default-branch{ data: { default_branch: @project.default_branch, project_id: @project.id } }
.form-group
- help_text = _("When merge requests and commits in the default branch close, any issues they reference also close.")
diff --git a/app/views/projects/buttons/_clone.html.haml b/app/views/projects/buttons/_clone.html.haml
index db5d1ff5693..b5679bc512c 100644
--- a/app/views/projects/buttons/_clone.html.haml
+++ b/app/views/projects/buttons/_clone.html.haml
@@ -15,7 +15,7 @@
.input-group.btn-group
= text_field_tag :ssh_project_clone, ssh_clone_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true, aria: { label: _('Repository clone URL') }, data: { qa_selector: 'ssh_clone_url_content' }
.input-group-append
- = clipboard_button(target: '#ssh_project_clone', title: _("Copy URL"), class: "input-group-text gl-button btn btn-icon btn-default")
+ = deprecated_clipboard_button(target: '#ssh_project_clone', title: _("Copy URL"), class: "input-group-text gl-button btn btn-icon btn-default")
= render_if_exists 'projects/buttons/geo'
- if http_enabled?
%li.pt-2{ class: 'gl-px-4!' }
@@ -24,7 +24,7 @@
.input-group.btn-group
= text_field_tag :http_project_clone, http_clone_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true, aria: { label: _('Repository clone URL') }, data: { qa_selector: 'http_clone_url_content' }
.input-group-append
- = clipboard_button(target: '#http_project_clone', title: _("Copy URL"), class: "input-group-text gl-button btn btn-icon btn-default")
+ = deprecated_clipboard_button(target: '#http_project_clone', title: _("Copy URL"), class: "input-group-text gl-button btn btn-icon btn-default")
= render_if_exists 'projects/buttons/geo'
= render_if_exists 'projects/buttons/kerberos_clone_field'
%li.divider.mt-2
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 24d063d3b4d..e79a91eddaf 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -45,11 +45,12 @@
= gl_loading_icon(inline: true, css_class: 'gl-vertical-align-middle')
- if can?(current_user, :read_pipeline, @last_pipeline)
+ - status = @last_pipeline.detailed_status(current_user)
.well-segment.pipeline-info
.js-commit-pipeline-status{ data: { full_path: @project.full_path, iid: @last_pipeline.iid, graphql_resource_etag: graphql_etag_pipeline_path(@last_pipeline) } }
#{ _('Pipeline') }
= link_to "##{@last_pipeline.id}", project_pipeline_path(@project, @last_pipeline.id)
- = ci_label_for_status(@last_pipeline.status)
+ = status&.label
- if @last_pipeline.stages_count.nonzero?
#{ n_(s_('Pipeline|with stage'), s_('Pipeline|with stages'), @last_pipeline.stages_count) }
.js-commit-pipeline-mini-graph{ data: { stages: @last_pipeline_stages.to_json.html_safe, full_path: @project.full_path, iid: @last_pipeline.iid, graphql_resource_etag: graphql_etag_pipeline_path(@last_pipeline) } }
diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml
index 5b99a88f29e..6aefc2eaa8b 100644
--- a/app/views/projects/commit/_signature_badge.html.haml
+++ b/app/views/projects/commit/_signature_badge.html.haml
@@ -17,17 +17,17 @@
- if signature.x509?
= render partial: "projects/commit/x509/certificate_details", locals: { signature: signature }
- = link_to(_('Learn more about X.509 signed commits'), help_page_path('user/project/repository/x509_signed_commits/index.md'), class: 'gl-link gl-display-block')
+ = link_to(_('Learn more about X.509 signed commits'), help_page_path('user/project/repository/signed_commits/x509.md'), class: 'gl-link gl-display-block')
- elsif signature.ssh?
= _('SSH key fingerprint:')
%span.gl-font-monospace= signature.key_fingerprint_sha256 || _('Unknown')
- = link_to(_('Learn about signing commits with SSH keys.'), help_page_path('user/project/repository/ssh_signed_commits/index.md'), class: 'gl-link gl-display-block gl-mt-3')
+ = link_to(_('Learn about signing commits with SSH keys.'), help_page_path('user/project/repository/signed_commits/ssh.md'), class: 'gl-link gl-display-block gl-mt-3')
- else
= _('GPG Key ID:')
%span.gl-font-monospace= signature.gpg_key_primary_keyid
- = link_to(_('Learn about signing commits'), help_page_path('user/project/repository/gpg_signed_commits/index.md'), class: 'gl-link gl-display-block gl-mt-3')
+ = link_to(_('Learn about signing commits'), help_page_path('user/project/repository/signed_commits/index.md'), class: 'gl-link gl-display-block gl-mt-3')
%a.signature-badge.gl-display-inline-block.gl-ml-4{ role: 'button', tabindex: 0, data: { toggle: 'popover', html: 'true', placement: 'top', title: title, content: content } }
= gl_badge_tag label, variant: variant
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 13a406d442d..c42d0fe9931 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -76,5 +76,5 @@
.commit-sha-group.btn-group.d-none.d-sm-flex
.label.label-monospace.monospace
= commit.short_id
- = clipboard_button(text: commit.id, title: _("Copy commit SHA"), class: "gl-button btn btn-default btn-icon", container: "body")
+ = clipboard_button(text: commit.id, category: :primary, size: :medium, title: _("Copy commit SHA"))
= link_to_browse_code(project, commit)
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index 4a29402bfe7..38633c9e5f1 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,6 +1,6 @@
- breadcrumb_title s_("CompareRevisions|Compare revisions")
-- page_title _("CompareRevisions|Compare revisions")
+- page_title s_("CompareRevisions|Compare revisions")
.prepend-top-20
#js-compare-selector{ data: project_compare_selector_data(@project, @merge_request, @compare_params) }
diff --git a/app/views/projects/deployments/_commit.html.haml b/app/views/projects/deployments/_commit.html.haml
deleted file mode 100644
index 509ed62b39d..00000000000
--- a/app/views/projects/deployments/_commit.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-.table-mobile-content
- .branch-commit.cgray
- - if deployment.ref
- %span.icon-container.gl-display-inline-block
- = deployment.tag? ? sprite_icon('tag', css_class: 'sprite') : sprite_icon('fork', css_class: 'sprite')
- = link_to deployment.ref, project_ref_path(@project, deployment.ref), class: "ref-name"
- .icon-container.commit-icon
- = custom_icon("icon_commit")
- = link_to deployment.short_sha, project_commit_path(@project, deployment.sha), class: "commit-sha mr-0"
-
- %p.commit-title.flex-truncate-parent
- %span.flex-truncate-child
- - if commit_title = deployment.commit_title
- = author_avatar(deployment.commit, size: 20)
- = link_to_markdown commit_title, project_commit_path(@project, deployment.sha), class: "commit-row-message cgray"
- - else
- = _("Can't find HEAD commit for this branch")
diff --git a/app/views/projects/deployments/_deployment.html.haml b/app/views/projects/deployments/_deployment.html.haml
deleted file mode 100644
index e3688c8d323..00000000000
--- a/app/views/projects/deployments/_deployment.html.haml
+++ /dev/null
@@ -1,49 +0,0 @@
-.gl-responsive-table-row.deployment{ role: 'row' }
- .table-section.section-15{ role: 'gridcell' }
- .table-mobile-header{ role: 'rowheader' }= _("Status")
- .table-mobile-content
- = render_deployment_status(deployment)
-
- .table-section.section-10{ role: 'gridcell' }
- .table-mobile-header{ role: 'rowheader' }= _("ID")
- %strong.table-mobile-content{ data: { testid: 'deployment-id' } } ##{deployment.iid}
-
- .table-section.section-10{ role: 'gridcell' }
- .table-mobile-header{ role: 'rowheader' }= _("Triggerer")
- .table-mobile-content
- - if deployment.deployed_by
- = user_avatar(user: deployment.deployed_by, size: 26, css_class: "mr-0 float-none")
-
- .table-section.section-25{ role: 'gridcell' }
- .table-mobile-header{ role: 'rowheader' }= _("Commit")
- = render 'projects/deployments/commit', deployment: deployment
-
- .table-section.section-10.build-column{ role: 'gridcell' }
- .table-mobile-header{ role: 'rowheader' }= _("Job")
- - if deployment.deployable
- .table-mobile-content
- .flex-truncate-parent
- .flex-truncate-child.has-tooltip.gl-white-space-normal.gl-md-white-space-nowrap{ :title => "#{deployment.deployable.name} (##{deployment.deployable.id})", data: { container: 'body' } }
- = link_to deployment_path(deployment), class: 'build-link' do
- #{deployment.deployable.name} (##{deployment.deployable.id})
- - else
- = gl_badge_tag s_('Deployment|API'), { variant: :info }, { class: 'gl-cursor-help', data: { toggle: 'tooltip' }, title: s_('Deployment|This deployment was created using the API') }
-
- .table-section.section-10{ role: 'gridcell' }
- .table-mobile-header{ role: 'rowheader' }= _("Created")
- %span.table-mobile-content.flex-truncate-parent
- %span.flex-truncate-child
- = time_ago_with_tooltip(deployment.created_at)
-
- .table-section.section-10{ role: 'gridcell' }
- .table-mobile-header{ role: 'rowheader' }= _("Deployed")
- - if deployment.deployed_at
- %span.table-mobile-content.flex-truncate-parent
- %span.flex-truncate-child
- = time_ago_with_tooltip(deployment.deployed_at)
-
- .table-section.section-10.table-button-footer{ role: 'gridcell' }
- .btn-group.table-action-buttons
- = render 'projects/deployments/actions', deployment: deployment
- = render 'projects/deployments/rollback', deployment: deployment
- = render_if_exists 'projects/deployments/approvals', deployment: deployment
diff --git a/app/views/projects/deployments/_rollback.haml b/app/views/projects/deployments/_rollback.haml
deleted file mode 100644
index e50fa1fa0f7..00000000000
--- a/app/views/projects/deployments/_rollback.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-- if deployment.deployable && can?(current_user, :play_job, deployment.deployable)
- - tooltip = deployment.last? ? s_('Environments|Re-deploy to environment') : s_('Environments|Rollback environment')
- - icon = deployment.last? ? 'repeat' : 'redo'
- = render Pajamas::ButtonComponent.new(icon: icon, button_options: { title: tooltip, class: 'js-confirm-rollback-modal-button has-tooltip', data: { environment_name: @environment.name, commit_short_sha: deployment.short_sha, commit_url: project_commit_path(@project, deployment.sha), is_last_deployment: deployment.last?.to_s, retry_path: retry_project_job_path(@environment.project, deployment.deployable) } })
diff --git a/app/views/projects/diffs/_file_header.html.haml b/app/views/projects/diffs/_file_header.html.haml
index afca27c5430..17e55699615 100644
--- a/app/views/projects/diffs/_file_header.html.haml
+++ b/app/views/projects/diffs/_file_header.html.haml
@@ -5,7 +5,7 @@
- if diff_file.submodule?
%span
- = sprite_icon('archive')
+ = sprite_icon('folder-git', file_icon: true)
%strong.file-title-name
= submodule_link(diff_file.blob, diff_file.content_sha, diff_file.repository)
@@ -23,7 +23,7 @@
%strong.file-title-name.has-tooltip.gl-word-break-all{ data: { title: diff_file.new_path, container: 'body' } }
= new_path
- else
- %strong.file-title-name.has-tooltip.gl-word-break-all{ data: { title: diff_file.file_path, container: 'body', qa_selector: 'file_name_content' } }
+ %strong.file-title-name.has-tooltip.gl-word-break-all{ data: { title: diff_file.file_path, container: 'body', testid: 'file-name-content' } }
= diff_file.file_path
- if diff_file.deleted_file?
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 662f1bb158d..0158018ecc0 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -5,8 +5,6 @@
- reduce_visibility_form_id = 'reduce-visibility-form'
- @force_desktop_expanded_sidebar = true
-= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
-
= render Pajamas::AlertComponent.new(title: _('GitLab Pages has moved'),
alert_options: { class: 'gl-my-5', data: { feature_id: Users::CalloutsHelper::PAGES_MOVED_CALLOUT, dismiss_endpoint: callouts_path, defer_links: 'true' } }) do |c|
- c.with_body do
@@ -91,8 +89,8 @@
.gl-new-card-title-wrapper
%h4.gl-new-card-title.warning-title= _('Change path')
%p.gl-new-card-description
- - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/settings/index', anchor: 'rename-a-repository') }
- = _("A project’s repository name defines its URL (the one you use to access the project via a browser) and its place on the file disk where GitLab is installed. %{link_start}Learn more.%{link_end}").html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('user/project/settings/index', anchor: 'rename-a-repository'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_("A project’s repository name defines its URL (the one you use to access the project via a browser) and its place on the file disk where GitLab is installed. %{link_start}Learn more.%{link_end}"), tag_pair(link, :link_start, :link_end))
- c.with_body do
= render 'projects/errors'
diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml
index e97cae911d9..46ec430cadb 100644
--- a/app/views/projects/environments/show.html.haml
+++ b/app/views/projects/environments/show.html.haml
@@ -8,33 +8,4 @@
#environments-detail-view{ data: { details: environments_detail_data_json(current_user, @project, @environment) } }
#environments-detail-view-header
- - if Feature.enabled?(:environment_details_vue, @project)
- #environment_details_page
- - else
- .environments-container
- - if @deployments.blank?
- .empty-state
- .text-content
- %h4.state-title
- = _("You don't have any deployments right now.")
- %p
- = html_escape(_("Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
- .text-center
- = render Pajamas::ButtonComponent.new(variant: :confirm, href: help_page_path("ci/environments/index.md")) do
- = _('Read more')
-
- - else
- .table-holder.gl-overflow-visible
- .ci-table.environments{ role: 'grid' }
- .gl-responsive-table-row.table-row-header{ role: 'row' }
- .table-section.section-15{ role: 'columnheader' }= _('Status')
- .table-section.section-10{ role: 'columnheader' }= _('ID')
- .table-section.section-10{ role: 'columnheader' }= _('Triggerer')
- .table-section.section-25{ role: 'columnheader' }= _('Commit')
- .table-section.section-10{ role: 'columnheader' }= _('Job')
- .table-section.section-10{ role: 'columnheader' }= _('Created')
- .table-section.section-10{ role: 'columnheader' }= _('Deployed')
-
- = render @deployments
-
- = paginate @deployments, theme: 'gitlab'
+ #environment_details_page
diff --git a/app/views/projects/hook_logs/show.html.haml b/app/views/projects/hook_logs/show.html.haml
index 2eaf89be4ef..f8025f7c462 100644
--- a/app/views/projects/hook_logs/show.html.haml
+++ b/app/views/projects/hook_logs/show.html.haml
@@ -1,7 +1,7 @@
- add_to_breadcrumbs _('Webhook Settings'), namespace_project_hooks_path
- page_title _('Webhook Logs')
-%h1.page-title.gl-font-size-h-display
+%h2.page-title.gl-font-size-h-display
= _("Request details")
%hr
diff --git a/app/views/projects/incidents/show.html.haml b/app/views/projects/incidents/show.html.haml
index 6d733dc46df..400c07835cd 100644
--- a/app/views/projects/incidents/show.html.haml
+++ b/app/views/projects/incidents/show.html.haml
@@ -1,9 +1,17 @@
-- @content_class = "limit-container-width" unless fluid_layout
- add_to_breadcrumbs _("Incidents"), project_incidents_path(@project)
- breadcrumb_title @issue.to_reference
+
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Incidents")
+- page_description @issue.description_html
+- page_card_attributes @issue.card_attributes
+- if @issue.relocation_target
+ - page_canonical_link @issue.relocation_target.present(current_user: current_user).web_url
+
- add_page_specific_style 'page_bundles/design_management'
- add_page_specific_style 'page_bundles/incidents'
+- add_page_specific_style 'page_bundles/issuable'
- add_page_specific_style 'page_bundles/issues_show'
-= render 'projects/issuable/show', issuable: @issue
+- @content_class = "limit-container-width" unless fluid_layout
+
+= render 'projects/issues/details_content', issuable: @issue
diff --git a/app/views/projects/issuable/_show.html.haml b/app/views/projects/issuable/_show.html.haml
deleted file mode 100644
index e502457808d..00000000000
--- a/app/views/projects/issuable/_show.html.haml
+++ /dev/null
@@ -1,10 +0,0 @@
-- api_awards_path = local_assigns.fetch(:api_awards_path, nil)
-- page_description issuable.description_html
-- page_card_attributes issuable.card_attributes
-- if issuable.relocation_target
- - page_canonical_link issuable.relocation_target.present(current_user: current_user).web_url
-- add_page_specific_style 'page_bundles/issuable'
-
-= render "projects/issues/service_desk/alert_moved_from_service_desk", issue: issuable
-
-= render 'shared/issue_type/details_content', issuable: issuable, api_awards_path: api_awards_path
diff --git a/app/views/projects/issues/_details_content.html.haml b/app/views/projects/issues/_details_content.html.haml
new file mode 100644
index 00000000000..51ffb68f4e5
--- /dev/null
+++ b/app/views/projects/issues/_details_content.html.haml
@@ -0,0 +1,47 @@
+- related_branches_path = related_branches_project_issue_path(@project, issuable)
+- api_awards_path = local_assigns.fetch(:api_awards_path, nil)
+
+= render "projects/issues/service_desk/alert_moved_from_service_desk", issue: issuable
+
+.issue-details.issuable-details.js-issue-details
+ .detail-page-description.content-block.js-detail-page-description.gl-pt-3.gl-pb-0.gl-border-none
+ #js-issuable-app{ data: { initial: issuable_initial_data(issuable).to_json,
+ header_actions_data: issue_header_actions_data(@project, issuable, current_user, @issuable_sidebar).to_json } }
+ .title-container
+ %h1.title.page-title.gl-font-size-h-display= markdown_field(issuable, :title)
+ - if issuable.description.present?
+ .description
+ .md= markdown_field(issuable, :description)
+
+ = edited_time_ago_with_tooltip(issuable, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago')
+
+ .js-issue-widgets
+ = render 'projects/issues/emoji_block', issuable: issuable, api_awards_path: api_awards_path
+
+ .js-issue-widgets
+ = render 'projects/issues/sentry_stack_trace', issuable: issuable
+
+ = render 'projects/issues/design_management'
+
+ = render_if_exists 'projects/issues/work_item_links'
+ = render_if_exists 'projects/issues/linked_resources'
+ = render 'projects/issues/related_issues'
+
+ #js-related-merge-requests{ data: { endpoint: expose_path(api_v4_projects_issues_related_merge_requests_path(id: @project.id, issue_iid: issuable.iid)),
+ has_closing_merge_request: (issuable.merge_requests_count(current_user) != 0).to_s,
+ project_namespace: @project.namespace.path,
+ project_path: @project.path } }
+
+ - if can?(current_user, :read_code, @project)
+ - add_page_startup_api_call related_branches_path
+ #related-branches{ data: { url: related_branches_path } }
+ -# This element is filled in using JavaScript.
+
+ - if can?(current_user, :admin_feature_flags_issue_links, @project)
+ = render_if_exists 'projects/issues/related_feature_flags'
+
+ .js-issue-widgets
+
+ = render 'projects/issues/discussion'
+
+= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @issue.assignees
diff --git a/app/views/shared/issue_type/_emoji_block.html.haml b/app/views/projects/issues/_emoji_block.html.haml
index 7eb3c0f5c9f..7eb3c0f5c9f 100644
--- a/app/views/shared/issue_type/_emoji_block.html.haml
+++ b/app/views/projects/issues/_emoji_block.html.haml
diff --git a/app/views/projects/issues/_related_issues.html.haml b/app/views/projects/issues/_related_issues.html.haml
index 2409c61fbf2..73a88e63a4e 100644
--- a/app/views/projects/issues/_related_issues.html.haml
+++ b/app/views/projects/issues/_related_issues.html.haml
@@ -4,6 +4,7 @@
full_path: @project.full_path,
has_issue_weights_feature: @project.licensed_feature_available?(:issue_weights).to_s,
help_path: help_page_path('user/project/issues/related_issues'),
+ issuable_type: @issue.issue_type,
show_categorized_issues: @project.licensed_feature_available?(:blocked_issues).to_s,
has_iterations_feature: @project.licensed_feature_available?(:iterations).to_s,
report_abuse_path: add_category_abuse_reports_path } }
diff --git a/app/views/shared/issue_type/_sentry_stack_trace.html.haml b/app/views/projects/issues/_sentry_stack_trace.html.haml
index 40b29a74b53..40b29a74b53 100644
--- a/app/views/shared/issue_type/_sentry_stack_trace.html.haml
+++ b/app/views/projects/issues/_sentry_stack_trace.html.haml
diff --git a/app/views/projects/issues/service_desk.html.haml b/app/views/projects/issues/service_desk.html.haml
index 2d17719a8c2..4453cb2e538 100644
--- a/app/views/projects/issues/service_desk.html.haml
+++ b/app/views/projects/issues/service_desk.html.haml
@@ -2,10 +2,11 @@
- page_title _("Service Desk")
- add_page_specific_style 'page_bundles/issuable_list'
+- add_page_specific_style 'page_bundles/issues_list'
- content_for :breadcrumbs_extra do
= render "projects/issues/service_desk/nav_btns", show_export_button: false, show_rss_button: false
-- support_bot_attrs = { service_desk_enabled: @project.service_desk_enabled?, **UserSerializer.new.represent(User.support_bot) }.to_json
+- support_bot_attrs = { service_desk_enabled: @project.service_desk_enabled?, **UserSerializer.new.represent(Users::Internal.support_bot) }.to_json
.js-service-desk-issues.service-desk-issues{ data: { support_bot: support_bot_attrs } }
- if ::Feature.enabled?(:service_desk_vue_list, @project)
diff --git a/app/views/projects/issues/service_desk/_issue.html.haml b/app/views/projects/issues/service_desk/_issue.html.haml
index 5b98712d3eb..66b2eabac9d 100644
--- a/app/views/projects/issues/service_desk/_issue.html.haml
+++ b/app/views/projects/issues/service_desk/_issue.html.haml
@@ -48,10 +48,10 @@
.issuable-meta
%ul.controls
- if issue.closed? && issue.moved?
- %li.issuable-status
+ %li
= render Pajamas::BadgeComponent.new(_('Closed (moved)'), size: 'sm', variant: 'info')
- elsif issue.closed?
- %li.issuable-status
+ %li
= render Pajamas::BadgeComponent.new(_('Closed'), size: 'sm', variant: 'info')
- if issue.assignees.any?
%li.gl-display-flex
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 7e8bf4ae57f..457eaf5e194 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,10 +1,18 @@
-- @content_class = "limit-container-width" unless fluid_layout
- add_to_breadcrumbs _("Issues"), project_issues_path(@project)
- breadcrumb_title @issue.to_reference
+
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues")
+- page_description @issue.description_html
+- page_card_attributes @issue.card_attributes
+- if @issue.relocation_target
+ - page_canonical_link @issue.relocation_target.present(current_user: current_user).web_url
+
- add_page_specific_style 'page_bundles/design_management'
- add_page_specific_style 'page_bundles/incidents'
+- add_page_specific_style 'page_bundles/issuable'
- add_page_specific_style 'page_bundles/issues_show'
- add_page_specific_style 'page_bundles/work_items'
-= render 'projects/issuable/show', issuable: @issue, api_awards_path: award_emoji_issue_api_path(@issue)
+- @content_class = "limit-container-width" unless fluid_layout
+
+= render 'projects/issues/details_content', issuable: @issue, api_awards_path: award_emoji_issue_api_path(@issue)
diff --git a/app/views/projects/jobs/_table.html.haml b/app/views/projects/jobs/_table.html.haml
deleted file mode 100644
index 0bb512b4035..00000000000
--- a/app/views/projects/jobs/_table.html.haml
+++ /dev/null
@@ -1,37 +0,0 @@
-- admin = local_assigns.fetch(:admin, false)
-
-- if builds.blank?
- - if @project
- .row.empty-state
- .col-12
- .svg-content.svg-250
- = image_tag('jobs-empty-state.svg')
- .col-12
- .text-content.gl-text-center
- %h4
- = s_('Jobs|Use jobs to automate your tasks')
- %p
- = s_('Jobs|Jobs are the building blocks of a GitLab CI/CD pipeline. Each job has a specific task, like testing code. To set up jobs in a CI/CD pipeline, add a CI/CD configuration file to your project.')
- = link_button_to s_('Jobs|Create CI/CD configuration file'), project_ci_pipeline_editor_path(project), class: 'js-empty-state-button', variant: :confirm
- - else
- .nothing-here-block= s_('Jobs|No jobs to show')
-- else
- .table-holder
- %table.table.ci-table.builds-page
- %thead
- %tr
- %th= _('Status')
- %th= _('Name')
- %th= _('Job')
- %th= _('Pipeline')
- - if admin
- %th= _('Project')
- %th= _('Runner')
- %th= _('Stage')
- %th= _('Duration')
- %th= _('Coverage')
- %th
-
- = render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, pipeline_link: true, stage: true, allow_retry: true, admin: admin }
-
- = paginate_collection(builds)
diff --git a/app/views/projects/labels/edit.html.haml b/app/views/projects/labels/edit.html.haml
index 4f4609e6016..ce8b3f70204 100644
--- a/app/views/projects/labels/edit.html.haml
+++ b/app/views/projects/labels/edit.html.haml
@@ -1,8 +1,9 @@
- add_to_breadcrumbs _("Labels"), project_labels_path(@project)
- breadcrumb_title _("Edit")
- page_title _("Edit"), @label.name, _("Labels")
+- show_lock_on_merge = @project.supports_lock_on_merge?
%h1.page-title.gl-font-size-h-display
= _('Edit Label')
-= render 'shared/labels/form', url: project_label_path(@project, @label), back_path: project_labels_path(@project)
+= render 'shared/labels/form', url: project_label_path(@project, @label), back_path: project_labels_path(@project), show_lock_on_merge: show_lock_on_merge
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 8855e8024b3..4b27b344498 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -3,7 +3,6 @@
- search = params[:search]
- subscribed = params[:subscribed]
- labels_or_filters = @labels.exists? || @prioritized_labels.exists? || search.present? || subscribed.present?
-= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
- if labels_or_filters
#js-promote-label-modal
diff --git a/app/views/projects/merge_requests/_code_dropdown.html.haml b/app/views/projects/merge_requests/_code_dropdown.html.haml
index 4cab6fac388..bfa33f26453 100644
--- a/app/views/projects/merge_requests/_code_dropdown.html.haml
+++ b/app/views/projects/merge_requests/_code_dropdown.html.haml
@@ -1,6 +1,6 @@
.gl-md-ml-3.dropdown.gl-dropdown{ class: "gl-display-none! gl-md-display-flex!" }
#js-check-out-modal{ data: how_merge_modal_data(@merge_request) }
- = button_tag type: 'button', class: "btn dropdown-toggle btn-confirm gl-button gl-dropdown-toggle", data: { toggle: 'dropdown', qa_selector: 'mr_code_dropdown' } do
+ = button_tag type: 'button', class: "btn dropdown-toggle btn-confirm gl-button gl-dropdown-toggle", data: { toggle: 'dropdown', testid: 'mr-code-dropdown' } do
%span.gl-dropdown-button-text= _('Code')
= sprite_icon "chevron-down", size: 16, css_class: "dropdown-icon gl-icon gl-ml-2 gl-mr-0!"
.dropdown-menu.dropdown-menu-right
@@ -16,7 +16,7 @@
= _('Check out branch')
- if current_user
%li.gl-dropdown-item
- = link_to ide_merge_request_path(@merge_request), class: 'dropdown-item', target: '_blank', data: { qa_selector: 'open_in_web_ide_button' } do
+ = link_to ide_merge_request_path(@merge_request), class: 'dropdown-item', target: '_blank', data: { testid: 'open-in-web-ide-button' } do
.gl-dropdown-item-text-wrapper
= _('Open in Web IDE')
- if Gitlab::CurrentSettings.gitpod_enabled && current_user&.gitpod_enabled
@@ -30,10 +30,10 @@
%header.dropdown-header
= _('Download')
%li.gl-dropdown-item
- = link_to merge_request_path(@merge_request, format: :patch), class: 'dropdown-item', download: '', data: { qa_selector: 'download_email_patches_menu_item' } do
+ = link_to merge_request_path(@merge_request, format: :patch), class: 'dropdown-item', download: '', data: { testid: 'download-email-patches-menu-item' } do
.gl-dropdown-item-text-wrapper
= _('Patches')
%li.gl-dropdown-item
- = link_to merge_request_path(@merge_request, format: :diff), class: 'dropdown-item', download: '', data: { qa_selector: 'download_plain_diff_menu_item' } do
+ = link_to merge_request_path(@merge_request, format: :diff), class: 'dropdown-item', download: '', data: { testid: 'download-plain-diff-menu-item' } do
.gl-dropdown-item-text-wrapper
= _('Plain diff')
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 7b815d996e0..4a7aa9a86ab 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -45,8 +45,10 @@
.issuable-meta
%ul.controls.d-flex.align-items-end
- if merge_request.merged?
+ - merged_at = merge_request.merged_at ? l(merge_request.merged_at.to_time) : _("Merge date & time could not be determined")
%li.d-none.d-sm-flex
- = render Pajamas::BadgeComponent.new(_('Merged'), size: 'sm', variant: 'info')
+ %a.has-tooltip{ href: "#{merge_request_path(merge_request)}#widget-state", title: merged_at }
+ = render Pajamas::BadgeComponent.new(_('Merged'), size: 'sm', variant: 'info')
- elsif merge_request.closed?
%li.d-none.d-sm-flex
= render Pajamas::BadgeComponent.new(_('Closed'), size: 'sm', variant: 'danger')
diff --git a/app/views/projects/merge_requests/_mr_title.html.haml b/app/views/projects/merge_requests/_mr_title.html.haml
index dfa582f4c60..f0e7df8a379 100644
--- a/app/views/projects/merge_requests/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/_mr_title.html.haml
@@ -15,7 +15,7 @@
.detail-page-header.border-bottom-0.gl-display-block.gl-pt-5{ class: "gl-md-display-flex! #{'is-merge-request' if moved_mr_sidebar_enabled? && !fluid_layout}" }
.detail-page-header-body
.issuable-meta.gl-display-flex
- #js-issuable-header-warnings{ data: { hidden: @merge_request.hidden?.to_s } }
+ .js-header-metadata-root{ data: { hidden: @merge_request.hidden?.to_s } }
%h1.title.page-title.gl-font-size-h-display.gl-my-0.gl-display-inline-block{ data: { qa_selector: 'title_content' } }
= markdown_field(@merge_request, :title)
diff --git a/app/views/projects/merge_requests/_page.html.haml b/app/views/projects/merge_requests/_page.html.haml
index 69e2487152e..dfb18b52021 100644
--- a/app/views/projects/merge_requests/_page.html.haml
+++ b/app/views/projects/merge_requests/_page.html.haml
@@ -28,12 +28,12 @@
.merge-request-tabs-holder{ class: "#{'js-tabs-affix' unless ENV['RAILS_ENV'] == 'test'} #{'gl-static' if moved_mr_sidebar_enabled?}" }
.merge-request-tabs-container.gl-display-flex.gl-justify-content-space-between{ class: "#{'is-merge-request' if Feature.enabled?(:moved_mr_sidebar, @project) && !fluid_layout}" }
%ul.merge-request-tabs.nav-tabs.nav.nav-links.gl-display-flex.gl-flex-nowrap.gl-m-0.gl-p-0{ class: "#{'gl-w-full gl-lg-w-auto!' if Feature.enabled?(:moved_mr_sidebar, @project)}" }
- = render "projects/merge_requests/tabs/tab", class: "notes-tab", qa_selector: "notes_tab" do
+ = render "projects/merge_requests/tabs/tab", class: "notes-tab", testid: "notes-tab" do
= tab_link_for @merge_request, :show, force_link: @commit.present? do
= _("Overview")
= gl_badge_tag @merge_request.related_notes.user.count, { size: :sm }, { class: 'js-discussions-count' }
- if @merge_request.source_project
- = render "projects/merge_requests/tabs/tab", name: "commits", class: "commits-tab", qa_selector: "commits_tab" do
+ = render "projects/merge_requests/tabs/tab", name: "commits", class: "commits-tab", testid: "commits-tab" do
= tab_link_for @merge_request, :commits do
= _("Commits")
= gl_badge_tag tab_count_display(@merge_request, @commits_count), { size: :sm }, { class: 'js-commits-count' }
@@ -42,7 +42,7 @@
= tab_link_for @merge_request, :pipelines do
= _("Pipelines")
= gl_badge_tag @number_of_pipelines, { size: :sm }, { class: 'js-pipelines-mr-count' }
- = render "projects/merge_requests/tabs/tab", name: "diffs", class: "diffs-tab js-diffs-tab", id: "diffs-tab", qa_selector: "diffs_tab" do
+ = render "projects/merge_requests/tabs/tab", name: "diffs", class: "diffs-tab js-diffs-tab", id: "diffs-tab", testid: "diffs-tab" do
= tab_link_for @merge_request, :diffs do
= _("Changes")
= gl_badge_tag tab_count_display(@merge_request, @diffs_count), { size: :sm }
@@ -61,6 +61,7 @@
= render "projects/merge_requests/tabs/pane", id: "notes", class: "notes voting_notes" do
%div{ class: "#{'merge-request-overview' if moved_mr_sidebar_enabled?}" }
%section
+ = render_if_exists "projects/merge_requests/diff_summary"
.issuable-discussion.js-vue-notes-event
- if @merge_request.description.present?
.detail-page-description.gl-pb-0
diff --git a/app/views/projects/merge_requests/creations/_new_compare.html.haml b/app/views/projects/merge_requests/creations/_new_compare.html.haml
index 07bae4d2396..e6bd0b05f00 100644
--- a/app/views/projects/merge_requests/creations/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_compare.html.haml
@@ -14,7 +14,7 @@
= gitlab_ui_form_for [@project, @merge_request], url: project_new_merge_request_path(@project), method: :get, html: { class: "merge-request-form js-requires-input" } do |f|
- if params[:nav_source].present?
= hidden_field_tag(:nav_source, params[:nav_source])
- .js-merge-request-new-compare.row{ 'data-source-branch-url': project_new_merge_request_branch_from_path(@source_project), 'data-target-branch-url': project_new_merge_request_branch_to_path(@source_project) }
+ .js-merge-request-new-compare.row{ data: mr_compare_form_data(current_user, @merge_request) }
.col-lg-6
.card-new-merge-request
%h2.gl-font-size-h2
@@ -31,4 +31,4 @@
= form_errors(@merge_request)
.row
.col-12
- = f.submit _('Compare branches and continue'), data: { qa_selector: 'compare_branches_button' }, pajamas_button: true
+ = f.submit _('Compare branches and continue'), data: { testid: 'compare-branches-button' }, pajamas_button: true
diff --git a/app/views/projects/merge_requests/creations/_new_submit.html.haml b/app/views/projects/merge_requests/creations/_new_submit.html.haml
index a7151421acb..996928ba377 100644
--- a/app/views/projects/merge_requests/creations/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_submit.html.haml
@@ -50,7 +50,7 @@
= _("Pipelines")
= gl_badge_tag @pipelines.size, { size: :sm }, { class: 'gl-tab-counter-badge' }
%li.diffs-tab
- = link_to url_for(safe_params.merge(action: 'diffs')), data: {target: 'div#diffs', action: 'diffs', toggle: 'tabvue', qa_selector: 'diffs_tab'} do
+ = link_to url_for(safe_params.merge(action: 'diffs')), data: {target: 'div#diffs', action: 'diffs', toggle: 'tabvue', testid: 'diffs-tab'} do
= _("Changes")
= gl_badge_tag @merge_request.diff_size, { size: :sm }, { class: 'gl-tab-counter-badge' }
diff --git a/app/views/projects/merge_requests/tabs/_tab.html.haml b/app/views/projects/merge_requests/tabs/_tab.html.haml
index 9d942da8098..f6c8f4cd87b 100644
--- a/app/views/projects/merge_requests/tabs/_tab.html.haml
+++ b/app/views/projects/merge_requests/tabs/_tab.html.haml
@@ -1,8 +1,8 @@
- tab_name = local_assigns.fetch(:name, nil)
- tab_class = local_assigns.fetch(:class, nil)
-- qa_selector = local_assigns.fetch(:qa_selector, nil)
+- testid = local_assigns.fetch(:testid, nil)
- id = local_assigns.fetch(:id, nil)
-- attrs = { class: [tab_class, ("active" if params[:tab] == tab_name)], data: { qa_selector: qa_selector } }
+- attrs = { class: [tab_class, ("active" if params[:tab] == tab_name)], data: { testid: testid } }
- attrs[:id] = id if id.present?
%li{ attrs }
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index a592062a17d..abf2949938c 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -15,7 +15,7 @@
- @gfm_form = true
.js-markdown-editor{ data: { render_markdown_path: preview_markdown_path(@project),
markdown_docs_path: help_page_path('user/markdown'),
- qa_selector: 'milestone_description_field',
+ testid: 'milestone-description-field',
form_field_placeholder: _('Write milestone description...'),
supports_quick_actions: 'false',
enable_autocomplete: 'true',
diff --git a/app/views/projects/mirrors/_authentication_method.html.haml b/app/views/projects/mirrors/_authentication_method.html.haml
index 54e1f1a8b20..c4cf128a62a 100644
--- a/app/views/projects/mirrors/_authentication_method.html.haml
+++ b/app/views/projects/mirrors/_authentication_method.html.haml
@@ -1,14 +1,17 @@
- mirror = f.object
-- auth_options = [[_('Password'), 'password'], [_('SSH public key'), 'ssh_public_key']]
+- auth_options = [[_('Username and Password'), 'password'], [_('SSH public key'), 'ssh_public_key']]
.form-group
= f.label :auth_method, _('Authentication method'), class: 'label-bold'
= f.select :auth_method,
options_for_select(auth_options, mirror.auth_method),
- {}, { class: "custom-select gl-form-select js-mirror-auth-type", data: { qa_selector: 'authentication_method_field' } }
+ {}, { class: "custom-select gl-form-select js-mirror-auth-type gl-max-w-34 gl-display-block", data: { qa_selector: 'authentication_method_field' } }
= f.hidden_field :auth_method, value: "password", class: "js-hidden-mirror-auth-type"
.form-group
- .well-password-auth.collapse.js-well-password-auth
+ = f.label :user, _('Username'), class: 'label-bold'
+ = f.text_field :user, class: 'form-control gl-form-input gl-form-input-xl', value: nil, autocomplete: 'off', required: false, autocorrect: 'off', autocapitalize: 'off', spellcheck: false, data: { testid: 'username-field' }
+.well-password-auth.collapse.js-well-password-auth
+ .form-group
= f.label :password, _("Password"), class: "label-bold"
- = f.password_field :password, class: 'form-control gl-form-input js-mirror-password-field', autocomplete: 'off', data: { qa_selector: 'password_field' }
+ = f.password_field :password, class: 'form-control gl-form-input js-mirror-password-field gl-form-input-xl', autocomplete: 'off', data: { testid: 'password-field' }
diff --git a/app/views/projects/mirrors/_instructions.html.haml b/app/views/projects/mirrors/_instructions.html.haml
index 2bd2c7cac44..5a8710a64b0 100644
--- a/app/views/projects/mirrors/_instructions.html.haml
+++ b/app/views/projects/mirrors/_instructions.html.haml
@@ -4,7 +4,7 @@
= html_escape(_('The repository must be accessible over %{code_open}http://%{code_close},
%{code_open}https://%{code_close}, %{code_open}ssh://%{code_close} or %{code_open}git://%{code_close}.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li= html_escape(_('When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, please provide the exact URL to the repository. HTTP redirects will not be followed.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
- %li= html_escape(_('Include the username in the URL if required: %{code_open}https://username@gitlab.company.com/group/project.git%{code_close}.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
+ %li= html_escape(_('Do not include the username in the URL, use the username field below if required: %{code_open}https://gitlab.company.com/group/project.git%{code_close}.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
- minutes = Gitlab.config.gitlab_shell.git_timeout / 60
= _("The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination.") % { number_of_minutes: minutes }
diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml
index a1c89a9dd30..00837ce1c73 100644
--- a/app/views/projects/mirrors/_mirror_repos.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos.html.haml
@@ -35,7 +35,7 @@
%div= form_errors(@project)
.form-group.has-feedback
= label_tag :url, _('Git repository URL'), class: 'label-light'
- = text_field_tag :url, nil, class: 'form-control gl-form-input js-mirror-url js-repo-url', placeholder: _('Input the remote repository URL'), required: true, pattern: "(#{protocols}):\/\/.+", autocomplete: 'new-password', data: { qa_selector: 'mirror_repository_url_field' }
+ = text_field_tag :url, nil, class: 'form-control gl-form-input js-mirror-url js-repo-url gl-form-input-xl', placeholder: _('Input the remote repository URL'), required: true, pattern: "(#{protocols}):\/\/.+", autocomplete: 'new-password', data: { qa_selector: 'mirror_repository_url_field' }
= render 'projects/mirrors/instructions'
diff --git a/app/views/projects/mirrors/_mirror_repos_form.html.haml b/app/views/projects/mirrors/_mirror_repos_form.html.haml
index 1322e677d5a..8378a74311f 100644
--- a/app/views/projects/mirrors/_mirror_repos_form.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos_form.html.haml
@@ -1,7 +1,7 @@
.form-group
= label_tag :mirror_direction, _('Mirror direction'), class: 'label-light'
.select-wrapper
- = select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control gl-form-select select-control js-mirror-direction', disabled: true, data: { qa_selector: 'mirror_direction_field' }
+ = select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control gl-form-select select-control js-mirror-direction gl-max-w-34 gl-display-block', disabled: true, data: { qa_selector: 'mirror_direction_field' }
= sprite_icon('chevron-down', css_class: "gl-icon gl-absolute gl-top-3 gl-right-3 gl-text-gray-200")
= render partial: "projects/mirrors/mirror_repos_push", locals: { f: f }
diff --git a/app/views/projects/mirrors/_mirror_repos_list.html.haml b/app/views/projects/mirrors/_mirror_repos_list.html.haml
index 0debd13709d..59611db941f 100644
--- a/app/views/projects/mirrors/_mirror_repos_list.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos_list.html.haml
@@ -34,7 +34,7 @@
- if mirror_settings_enabled
.btn-group.mirror-actions-group{ role: 'group' }
- if mirror.ssh_key_auth?
- = clipboard_button(text: mirror.ssh_public_key, class: 'gl-button btn btn-default btn-icon', title: _('Copy SSH public key'), qa_selector: 'copy_public_key_button')
+ = clipboard_button(text: mirror.ssh_public_key, variant: :default, category: :primary, size: :medium, title: _('Copy SSH public key'), testid: 'copy_public_key_button')
= render 'shared/remote_mirror_update_button', remote_mirror: mirror
= render Pajamas::ButtonComponent.new(variant: :danger,
icon: 'remove',
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 59a21cecd39..bf288d3601b 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -29,9 +29,8 @@
= render Pajamas::CardComponent.new(card_options: { class: 'gl-my-5' }) do |c|
- c.with_body do
%div
- - contributing_templates_url = 'https://gitlab.com/gitlab-org/project-templates/contributing'
- - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: contributing_templates_url }
- = _('Learn how to %{link_start}contribute to the built-in templates%{link_end}').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', 'https://gitlab.com/gitlab-org/project-templates/contributing', target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_('Learn how to %{link_start}contribute to the built-in templates%{link_end}'), tag_pair(link, :link_start, :link_end))
= gitlab_ui_form_for @project, html: { class: 'new_project' } do |f|
.project-template
.form-group
diff --git a/app/views/projects/notes/_more_actions_dropdown.html.haml b/app/views/projects/notes/_more_actions_dropdown.html.haml
index e3cc9199352..54d1bf012f3 100644
--- a/app/views/projects/notes/_more_actions_dropdown.html.haml
+++ b/app/views/projects/notes/_more_actions_dropdown.html.haml
@@ -5,7 +5,7 @@
= render Pajamas::ButtonComponent.new(icon: 'ellipsis_v', category: :tertiary, button_options: { class: 'note-action-button more-actions-toggle has-tooltip', data: { title: 'More actions', toggle: 'dropdown', container: 'body', qa_selector: 'more_actions_dropdown' }})
%ul.dropdown-menu.more-actions-dropdown.dropdown-open-left
%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)
+ = deprecated_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
.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) } }
diff --git a/app/views/projects/pages/_pages_settings.html.haml b/app/views/projects/pages/_pages_settings.html.haml
index b1ec7a362b7..1aa8148dfed 100644
--- a/app/views/projects/pages/_pages_settings.html.haml
+++ b/app/views/projects/pages/_pages_settings.html.haml
@@ -1,11 +1,7 @@
-- can_edit_max_page_size = can?(current_user, :update_max_pages_size)
-- can_enforce_https_only = Gitlab.config.pages.external_http || Gitlab.config.pages.external_https
-
= gitlab_ui_form_for @project, url: project_pages_path(@project), html: { class: 'inline', title: pages_https_only_title } do |f|
- - if can_edit_max_page_size
- = render_if_exists 'shared/pages/max_pages_size_input', form: f
+ = render_if_exists 'shared/pages/max_pages_size_input', form: f
- - if can_enforce_https_only
+ - if Gitlab.config.pages.external_http || Gitlab.config.pages.external_https
.form-group
= f.gitlab_ui_checkbox_component :pages_https_only,
s_('GitLabPages|Force HTTPS (requires valid certificates)'),
@@ -24,5 +20,14 @@
%p.gl-pl-6
= s_("GitLabPages|When enabled, a unique domain is generated to access pages.").html_safe
+ - if can?(current_user, :pages_multiple_versions, @project)
+ .form-group
+ = f.fields_for :project_setting do |settings|
+ = settings.gitlab_ui_checkbox_component :pages_multiple_versions_enabled,
+ s_('GitLabPages|Use multiple versions'),
+ label_options: { class: 'label-bold' }
+ %p.gl-pl-6
+ = s_("GitLabPages|When enabled, you can create multiple versions of your pages site.").html_safe
+
.gl-mt-3
= f.submit s_('GitLabPages|Save changes'), pajamas_button: true
diff --git a/app/views/projects/pages_domains/_dns.html.haml b/app/views/projects/pages_domains/_dns.html.haml
index 0edce28bb9d..9ca9360199d 100644
--- a/app/views/projects/pages_domains/_dns.html.haml
+++ b/app/views/projects/pages_domains/_dns.html.haml
@@ -9,7 +9,7 @@
.input-group
= text_field_tag :domain_dns, dns_record , class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append
- = clipboard_button(target: '#domain_dns', class: 'btn-default input-group-text d-none d-sm-block')
+ = deprecated_clipboard_button(target: '#domain_dns', class: 'btn-default input-group-text d-none d-sm-block')
%p.form-text.text-muted
= _("To access this domain create a new DNS record")
- if verification_enabled
@@ -25,7 +25,7 @@
.input-group
= text_field_tag :domain_verification, domain_presenter.verification_record, class: "monospace js-select-on-focus form-control", readonly: true
.input-group-append
- = clipboard_button(target: '#domain_verification', class: 'btn-default d-none d-sm-block')
+ = deprecated_clipboard_button(target: '#domain_verification', class: 'btn-default d-none d-sm-block')
%p.form-text.text-muted
- link_to_help = link_to(_('verify ownership'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership'))
= _("To %{link_to_help} of your domain, add the above key to a TXT record within your DNS configuration within seven days.").html_safe % { link_to_help: link_to_help }
diff --git a/app/views/projects/pipeline_schedules/_form.html.haml b/app/views/projects/pipeline_schedules/_form.html.haml
deleted file mode 100644
index df85963218d..00000000000
--- a/app/views/projects/pipeline_schedules/_form.html.haml
+++ /dev/null
@@ -1,43 +0,0 @@
-= gitlab_ui_form_for [@project, @schedule], as: :schedule, html: { id: "new-pipeline-schedule-form", class: "js-pipeline-schedule-form pipeline-schedule-form" } do |f|
- = form_errors(@schedule)
- .form-group.row
- .col-md-9
- = f.label :description, _('Description'), class: 'label-bold'
- = f.text_field :description, class: 'form-control gl-form-input', required: true, autofocus: true, placeholder: s_('PipelineSchedules|Provide a short description for this pipeline')
- .form-group.row
- .col-md-9
- = f.label :cron, _('Interval Pattern'), class: 'label-bold'
- #interval-pattern-input{ data: { initial_interval: @schedule.cron, daily_limit: @schedule.daily_limit } }
- .form-group.row
- .col-md-9{ data: { testid: 'schedule-timezone' } }
- = f.label :cron_timezone, _("Cron Timezone")
- .js-timezone-dropdown{ data: { timezone_data: timezone_data.to_json, initial_value: @schedule.cron_timezone, name: 'schedule[cron_timezone]' } }
-
- .form-group.row
- .col-md-9
- = f.label :ref, _('Target branch or tag'), class: 'label-bold'
- %div{ data: { testid: 'schedule-target-ref' } }
- .js-target-ref-dropdown{ data: { project_id: @project.id, default_branch: @project.default_branch } }
- = f.text_field :ref, value: @schedule.ref, id: 'schedule_ref', class: 'hidden', name: 'schedule[ref]', required: true
- .form-group.row.js-ci-variable-list-section
- .col-md-9
- %label.label-bold
- #{ s_('PipelineSchedules|Variables') }
- %ul.ci-variable-list
- - @schedule.variables.each do |variable|
- = render 'ci/variables/variable_row', form_field: 'schedule', variable: variable
- = render 'ci/variables/variable_row', form_field: 'schedule'
- - if @schedule.variables.size > 0
- = render Pajamas::ButtonComponent.new(category: :secondary, variant: :confirm, button_options: { class: 'gl-mt-3 js-secret-value-reveal-button', data: { secret_reveal_status: "#{@schedule.variables.size == 0}" }}) do
- - if @schedule.variables.size == 0
- = n_('Hide value', 'Hide values', @schedule.variables.size)
- - else
- = n_('Reveal value', 'Reveal values', @schedule.variables.size)
- .form-group.row
- .col-md-9
- = f.label :active, s_('PipelineSchedules|Activated'), class: 'label-bold'
- %div
- = f.gitlab_ui_checkbox_component :active, _('Active'), checkbox_options: { value: @schedule.active, required: false }
- .footer-block
- = f.submit _('Save pipeline schedule'), pajamas_button: true
- = link_button_to _('Cancel'), pipeline_schedules_path(@project)
diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
deleted file mode 100644
index a050808f13c..00000000000
--- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
+++ /dev/null
@@ -1,45 +0,0 @@
-- if pipeline_schedule
- %tr.pipeline-schedule-table-row
- %td{ role: 'cell', data: { label: _('Description') } }
- %div
- = pipeline_schedule.description
- %td.branch-name-cell.gl-text-truncate{ role: 'cell', data: { label: s_("PipelineSchedules|Target") } }
- %div
- - if pipeline_schedule.for_tag?
- = sprite_icon('tag', size: 12, css_class: 'gl-vertical-align-middle!')
- - else
- = sprite_icon('fork', size: 12, css_class: 'gl-vertical-align-middle!')
- - if pipeline_schedule.ref.present?
- = link_to pipeline_schedule.ref_for_display, project_ref_path(@project, pipeline_schedule.ref_for_display), class: "ref-name"
- %td{ role: 'cell', data: { label: _("Last Pipeline") } }
- %div
- - if pipeline_schedule.last_pipeline
- .status-icon-container{ class: "ci-status-icon-#{pipeline_schedule.last_pipeline.status}" }
- = link_to project_pipeline_path(@project, pipeline_schedule.last_pipeline.id) do
- = ci_icon_for_status(pipeline_schedule.last_pipeline.status)
- %span.gl-text-blue-500! ##{pipeline_schedule.last_pipeline.id}
- - else
- = s_("PipelineSchedules|None")
- %td.gl-text-gray-500{ role: 'cell', data: { label: s_("PipelineSchedules|Next Run") }, 'data-testid': 'next-run-cell' }
- %div
- - if pipeline_schedule.active? && pipeline_schedule.next_run_at
- = time_ago_with_tooltip(pipeline_schedule.real_next_run)
- - else
- = s_("PipelineSchedules|Inactive")
- %td{ role: 'cell', data: { label: _("Owner") } }
- %div
- - if pipeline_schedule.owner
- = render Pajamas::AvatarComponent.new(pipeline_schedule.owner, size: 24, class: "gl-mr-2")
- = link_to user_path(pipeline_schedule.owner) do
- = pipeline_schedule.owner&.name
- %td{ role: 'cell', data: { label: _('Actions') } }
- .float-right.btn-group
- - if can?(current_user, :play_pipeline_schedule, pipeline_schedule)
- = link_button_to nil, play_pipeline_schedule_path(pipeline_schedule), method: :post, title: _('Play'), icon: 'play'
- - if can?(current_user, :admin_pipeline_schedule, pipeline_schedule) && pipeline_schedule.owner != current_user
- = render Pajamas::ButtonComponent.new(button_options: { class: 'js-take-ownership-button has-tooltip', title: s_('PipelineSchedule|Take ownership to edit'), data: { url: take_ownership_pipeline_schedule_path(pipeline_schedule) } }) do
- = s_('PipelineSchedules|Take ownership')
- - if can?(current_user, :update_pipeline_schedule, pipeline_schedule)
- = link_button_to nil, edit_pipeline_schedule_path(pipeline_schedule), title: _('Edit'), icon: 'pencil'
- - if can?(current_user, :admin_pipeline_schedule, pipeline_schedule)
- = link_button_to nil, pipeline_schedule_path(pipeline_schedule), title: _('Delete'), method: :delete, aria: { label: _('Delete pipeline schedule') }, data: { confirm: _("Are you sure you want to delete this pipeline schedule?"), confirm_btn_variant: 'danger' }, variant: :danger, icon: 'remove'
diff --git a/app/views/projects/pipeline_schedules/_table.html.haml b/app/views/projects/pipeline_schedules/_table.html.haml
deleted file mode 100644
index 2f96ac6a534..00000000000
--- a/app/views/projects/pipeline_schedules/_table.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-.table-holder
- %table.table.ci-table.responsive-table.b-table.gl-table.b-table-stacked-md{ role: 'table' }
- %thead{ role: 'rowgroup' }
- %tr{ role: 'row' }
- %th.table-th-transparent.border-bottom{ role: 'cell', style: 'width: 34%' }= _("Description")
- %th.table-th-transparent.border-bottom{ role: 'cell' }= s_("PipelineSchedules|Target")
- %th.table-th-transparent.border-bottom{ role: 'cell' }= _("Last Pipeline")
- %th.table-th-transparent.border-bottom{ role: 'cell' }= s_("PipelineSchedules|Next Run")
- %th.table-th-transparent.border-bottom{ role: 'cell' }= _("Owner")
- %th.table-th-transparent.border-bottom{ role: 'cell' }
- %tbody{ role: 'rowgroup' }
- = render partial: "pipeline_schedule", collection: @schedules
diff --git a/app/views/projects/pipeline_schedules/_tabs.html.haml b/app/views/projects/pipeline_schedules/_tabs.html.haml
deleted file mode 100644
index f825ef35902..00000000000
--- a/app/views/projects/pipeline_schedules/_tabs.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-= gl_tabs_nav({ class: 'gl-display-flex gl-flex-grow-1 gl-border-0' }) do
- = gl_tab_link_to schedule_path_proc.call(nil), { item_active: active_when(scope.nil?) } do
- = s_("PipelineSchedules|All")
- = gl_tab_counter_badge(number_with_delimiter(all_schedules.count(:id)), { class: 'js-totalbuilds-count' })
-
- = gl_tab_link_to schedule_path_proc.call('active'), { item_active: active_when(scope == 'active') } do
- = s_("PipelineSchedules|Active")
- = gl_tab_counter_badge(number_with_delimiter(all_schedules.active.count(:id)))
-
- = gl_tab_link_to schedule_path_proc.call('inactive'), { item_active: active_when(scope == 'inactive') } do
- = s_("PipelineSchedules|Inactive")
- = gl_tab_counter_badge(number_with_delimiter(all_schedules.inactive.count(:id)))
diff --git a/app/views/projects/pipeline_schedules/edit.html.haml b/app/views/projects/pipeline_schedules/edit.html.haml
index 4e1ae53a101..647c0272852 100644
--- a/app/views/projects/pipeline_schedules/edit.html.haml
+++ b/app/views/projects/pipeline_schedules/edit.html.haml
@@ -1,12 +1,8 @@
- add_to_breadcrumbs _("Schedules"), pipeline_schedules_path(@project)
- breadcrumb_title "##{@schedule.id}"
- page_title _("Edit"), @schedule.description, _("Pipeline Schedule")
-- add_page_specific_style 'page_bundles/pipeline_schedules'
%h1.page-title.gl-font-size-h-display
= _("Edit Pipeline Schedule")
-- if Feature.enabled?(:pipeline_schedules_vue, @project)
- #pipeline-schedules-form-edit{ data: js_pipeline_schedules_form_data(@project, @schedule) }
-- else
- = render "form"
+#pipeline-schedules-form-edit{ data: js_pipeline_schedules_form_data(@project, @schedule) }
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index 5051fc6a5f5..15a80b6c7b1 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -1,28 +1,4 @@
- breadcrumb_title _("Schedules")
- page_title _("Pipeline Schedules")
-- add_page_specific_style 'page_bundles/pipeline_schedules'
-- add_page_specific_style 'page_bundles/ci_status'
-- add_page_specific_style 'page_bundles/merge_request'
-#pipeline-schedules-callout{ data: { docs_url: help_page_path('ci/pipelines/schedules'), illustration_url: image_path('illustrations/pipeline_schedule_callout.svg') } }
-
-- if Feature.enabled?(:pipeline_schedules_vue, @project)
- #pipeline-schedules-app{ data: { full_path: @project.full_path, pipelines_path: project_pipelines_path(@project), new_schedule_path: new_project_pipeline_schedule_path(@project) } }
-- else
- .top-area
- - schedule_path_proc = ->(scope) { pipeline_schedules_path(@project, scope: scope) }
- = render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
-
- - if can?(current_user, :create_pipeline_schedule, @project)
- .nav-controls
- = link_button_to new_project_pipeline_schedule_path(@project), variant: :confirm do
- = _('New schedule')
-
- - if @schedules.present?
- %ul.content-list
- = render partial: "table"
- - else
- .nothing-here-block
- = _("No schedules")
-
- #pipeline-take-ownership-modal
+#pipeline-schedules-app{ data: { full_path: @project.full_path, pipelines_path: project_pipelines_path(@project), new_schedule_path: new_project_pipeline_schedule_path(@project) } }
diff --git a/app/views/projects/pipeline_schedules/new.html.haml b/app/views/projects/pipeline_schedules/new.html.haml
index ef99a79b06f..2cd65521ae9 100644
--- a/app/views/projects/pipeline_schedules/new.html.haml
+++ b/app/views/projects/pipeline_schedules/new.html.haml
@@ -1,14 +1,10 @@
- breadcrumb_title _('Schedules')
- @breadcrumb_link = namespace_project_pipeline_schedules_path(@project.namespace, @project)
- page_title _("New Pipeline Schedule")
-- add_page_specific_style 'page_bundles/pipeline_schedules'
- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
%h1.page-title.gl-font-size-h-display
= _("Schedule a new pipeline")
-- if Feature.enabled?(:pipeline_schedules_vue, @project)
- #pipeline-schedules-form-new{ data: js_pipeline_schedules_form_data(@project, @schedule) }
-- else
- = render "form"
+#pipeline-schedules-form-new{ data: js_pipeline_schedules_form_data(@project, @schedule) }
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index 6b6aaaad802..3eb24873daf 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -1,8 +1,6 @@
- add_page_specific_style 'page_bundles/members'
- page_title _("Members")
-= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
-
.row.gl-mt-3
.col-lg-12
.gl-display-flex.gl-flex-wrap
@@ -26,7 +24,7 @@
- if can_admin_project_member?(@project)
.js-invite-members-trigger{ data: { variant: 'confirm',
classes: 'gl-md-w-auto gl-w-full gl-md-ml-3 gl-md-mt-0 gl-mt-3',
- trigger_source: 'project-members-page',
+ trigger_source: 'project_members_page',
display_text: _('Invite members') } }
- else
- if project_can_be_shared?
diff --git a/app/views/projects/protected_tags/_create_protected_tag.html.haml b/app/views/projects/protected_tags/_create_protected_tag.html.haml
index ef3974b04b5..1dc31503db9 100644
--- a/app/views/projects/protected_tags/_create_protected_tag.html.haml
+++ b/app/views/projects/protected_tags/_create_protected_tag.html.haml
@@ -1,9 +1,5 @@
- content_for :create_access_levels do
.create_access_levels-container
- = dropdown_tag('Select',
- options: { toggle_class: 'js-allowed-to-create js-multiselect wide',
- dropdown_class: 'dropdown-menu-selectable capitalize-header',
- dropdown_qa_selector: 'access_levels_content', dropdown_testid: 'allowed-to-create-dropdown',
- data: { field_name: 'protected_tag[create_access_levels_attributes][0][access_level]', input_id: 'create_access_levels_attributes', qa_selector: 'access_levels_dropdown' }})
+ .js-allowed-to-create
= render 'projects/protected_tags/shared/create_protected_tag'
diff --git a/app/views/projects/protected_tags/_protected_tag_create_access_levels.haml b/app/views/projects/protected_tags/_protected_tag_create_access_levels.haml
index 30b9e3e9005..389a88293a5 100644
--- a/app/views/projects/protected_tags/_protected_tag_create_access_levels.haml
+++ b/app/views/projects/protected_tags/_protected_tag_create_access_levels.haml
@@ -1,8 +1,5 @@
- protected_tag = local_assigns.fetch(:protected_tag)
- create_access_level = local_assigns.fetch(:create_access_level)
-- dropdown_label = create_access_level.first&.humanize || 'Select'
= hidden_field_tag "allowed_to_create_#{protected_tag.id}", create_access_level.first&.access_level
-= dropdown_tag(dropdown_label,
- options: { toggle_class: 'js-allowed-to-create js-multiselect', dropdown_class: 'dropdown-menu-selectable capitalize-header js-allowed-to-create-container',
- data: { field_name: "allowed_to_create_#{protected_tag.id}", preselected_items: access_levels_data(create_access_level) }})
+.js-allowed-to-create{ data: { preselected_items: access_levels_data(create_access_level).to_json } }
diff --git a/app/views/projects/settings/access_tokens/index.html.haml b/app/views/projects/settings/access_tokens/index.html.haml
index b81c3bc9704..ea3ad370fb5 100644
--- a/app/views/projects/settings/access_tokens/index.html.haml
+++ b/app/views/projects/settings/access_tokens/index.html.haml
@@ -18,9 +18,8 @@
= _('Project access token creation is disabled in this group.')
- root_group = @project.group.root_ancestor
- if current_user.can?(:admin_group, root_group)
- - group_settings_link = edit_group_path(root_group)
- - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: group_settings_link }
- = _('You can enable project access token creation in %{link_start}group settings%{link_end}.').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', edit_group_path(root_group), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_('You can enable project access token creation in %{link_start}group settings%{link_end}.'), tag_pair(link, :link_start, :link_end))
= html_escape(_('You can still use and manage existing tokens. %{link_start}Learn more.%{link_end}')) % { link_start: help_link_start, link_end: '</a>'.html_safe }
#js-new-access-token-app{ data: { access_token_type: type } }
diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml
index 6de39058455..17953e3bc14 100644
--- a/app/views/projects/settings/ci_cd/show.html.haml
+++ b/app/views/projects/settings/ci_cd/show.html.haml
@@ -25,9 +25,9 @@
%p.gl-text-secondary
- auto_devops_url = help_page_path('topics/autodevops/index')
- quickstart_url = help_page_path('topics/autodevops/cloud_deployments/auto_devops_with_gke')
- - auto_devops_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: auto_devops_url }
- - quickstart_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: quickstart_url }
- = s_('AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}').html_safe % { auto_devops_start: auto_devops_start, auto_devops_end: '</a>'.html_safe, quickstart_start: quickstart_start, quickstart_end: '</a>'.html_safe }
+ - auto_devops_link = link_to('', auto_devops_url, target: '_blank', rel: 'noopener noreferrer')
+ - quickstart_link = link_to('', quickstart_url, target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}'), tag_pair(auto_devops_link, :auto_devops_start, :auto_devops_end), tag_pair(quickstart_link, :quickstart_start, :quickstart_end))
.settings-content
= render 'autodevops_form', auto_devops_enabled: @project.auto_devops_enabled?
@@ -44,10 +44,7 @@
= _("Runners are processes that pick up and execute CI/CD jobs for GitLab.")
= link_to s_('What is GitLab Runner?'), 'https://docs.gitlab.com/runner/', target: '_blank', rel: 'noopener noreferrer'
.settings-content
- - if Feature.enabled?(:project_runners_vue_ui, @project)
- #js-project-runners{ data: { project_full_path: @project.full_path } }
- - else
- = render 'projects/runners/settings'
+ = render 'projects/runners/settings'
- if Gitlab::CurrentSettings.current_application_settings.keep_latest_artifact?
%section.settings.no-animate#js-artifacts-settings{ class: ('expanded' if expanded) }
diff --git a/app/views/projects/settings/integrations/_form.html.haml b/app/views/projects/settings/integrations/_form.html.haml
index 97c7729de44..d2df01c22bb 100644
--- a/app/views/projects/settings/integrations/_form.html.haml
+++ b/app/views/projects/settings/integrations/_form.html.haml
@@ -15,9 +15,12 @@
= render 'shared/integrations/slack_notifications_deprecation_alert'
%h2.gl-mb-0.gl-display-flex.gl-align-items-center.gl-gap-3
+ = render Pajamas::AvatarComponent.new(integration, size: 64, alt: '')
= integration.title
- if integration.operating?
- = render Pajamas::BadgeComponent.new(s_('FeatureFlags|Active'), variant: 'success')
+ = render Pajamas::BadgeComponent.new(_('Active'), variant: 'success', icon: 'status-success')
+ - elsif integration.persisted?
+ = render Pajamas::BadgeComponent.new(_('Inactive'), variant: 'neutral', icon: 'status-paused')
= render 'shared/integration_settings', integration: integration
- if lookup_context.template_exists?('show', "shared/integrations/#{integration.to_param}", true)
diff --git a/app/views/projects/settings/integrations/index.html.haml b/app/views/projects/settings/integrations/index.html.haml
index 6c0c99543cc..dca028d6167 100644
--- a/app/views/projects/settings/integrations/index.html.haml
+++ b/app/views/projects/settings/integrations/index.html.haml
@@ -6,7 +6,7 @@
%section.js-search-settings-section
%h3= _('Integrations')
- - integrations_link_start = '<a href="%{url}">'.html_safe % { url: help_page_url('user/project/integrations/index') }
- - webhooks_link_start = '<a href="%{url}">'.html_safe % { url: project_hooks_path(@project) }
- %p.gl-text-secondary= _("%{integrations_link_start}Integrations%{link_end} enable you to make third-party applications part of your GitLab workflow. If the available integrations don't meet your needs, consider using a %{webhooks_link_start}webhook%{link_end}.").html_safe % { integrations_link_start: integrations_link_start, webhooks_link_start: webhooks_link_start, link_end: '</a>'.html_safe }
+ - integrations_link = link_to('', help_page_url('user/project/integrations/index'))
+ - webhooks_link = link_to('', project_hooks_path(@project))
+ %p.gl-text-secondary= safe_format(_("%{integrations_link_start}Integrations%{link_end} enable you to make third-party applications part of your GitLab workflow. If the available integrations don't meet your needs, consider using a %{webhooks_link_start}webhook%{link_end}."), tag_pair(integrations_link, :integrations_link_start, :link_end), tag_pair(webhooks_link, :webhooks_link_start, :link_end))
= render 'shared/integrations/index', integrations: @integrations
diff --git a/app/views/projects/settings/merge_requests/_merge_request_merge_checks_settings.html.haml b/app/views/projects/settings/merge_requests/_merge_request_merge_checks_settings.html.haml
new file mode 100644
index 00000000000..fa9b39e0846
--- /dev/null
+++ b/app/views/projects/settings/merge_requests/_merge_request_merge_checks_settings.html.haml
@@ -0,0 +1,8 @@
+- form = local_assigns.fetch(:form)
+
+.form-group
+ %b= s_('ProjectSettings|Merge checks')
+ %p.text-secondary= s_('ProjectSettings|These checks must pass before merge requests can be merged.')
+ = render 'projects/settings/merge_requests/merge_request_pipelines_and_threads_options', form: form, project: @project
+ = render_if_exists 'projects/settings/merge_requests/merge_request_merge_checks_status_checks', form: form, project: @project
+ = render_if_exists 'projects/settings/merge_requests/merge_request_merge_checks_jira_enforcement', form: form, project: @project
diff --git a/app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml b/app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml
new file mode 100644
index 00000000000..da1965f549c
--- /dev/null
+++ b/app/views/projects/settings/merge_requests/_merge_request_merge_commit_template.html.haml
@@ -0,0 +1,13 @@
+- form = local_assigns.fetch(:form)
+
+.form-group
+ %b= s_('ProjectSettings|Merge commit message template')
+ %p.text-secondary
+ = s_('ProjectSettings|The commit message used when merging, if the merge method creates a merge commit.')
+ .mb-2
+ = form.text_area :merge_commit_template_or_default, class: 'form-control gl-form-input', rows: 8, maxlength: Project::MAX_COMMIT_TEMPLATE_LENGTH, placeholder: s_('ProjectSettings|The default template will be applied on save.')
+ %p.form-text.text-muted
+ = s_('ProjectSettings|Leave empty to use default template.')
+ = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_COMMIT_TEMPLATE_LENGTH })
+ - link = link_to('', help_page_path('user/project/merge_requests/commit_templates.md'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}'), tag_pair(link, :link_start, :link_end))
diff --git a/app/views/projects/_merge_request_merge_method_settings.html.haml b/app/views/projects/settings/merge_requests/_merge_request_merge_method_settings.html.haml
index dd32d3f9d92..dd32d3f9d92 100644
--- a/app/views/projects/_merge_request_merge_method_settings.html.haml
+++ b/app/views/projects/settings/merge_requests/_merge_request_merge_method_settings.html.haml
diff --git a/app/views/projects/settings/merge_requests/_merge_request_merge_options_settings.html.haml b/app/views/projects/settings/merge_requests/_merge_request_merge_options_settings.html.haml
new file mode 100644
index 00000000000..db7e59d6e2a
--- /dev/null
+++ b/app/views/projects/settings/merge_requests/_merge_request_merge_options_settings.html.haml
@@ -0,0 +1,14 @@
+- form = local_assigns.fetch(:form)
+
+.form-group#project-merge-options{ data: { project_full_path: @project.full_path } }
+ %b= s_('ProjectSettings|Merge options')
+ %p.text-secondary= s_('ProjectSettings|Additional settings that influence how and when merges are done.')
+ = render_if_exists 'projects/settings/merge_requests/merge_pipelines_settings', form: form
+ = render_if_exists 'projects/settings/merge_requests/merge_trains_settings', form: form
+ = form.gitlab_ui_checkbox_component :resolve_outdated_diff_discussions,
+ s_('ProjectSettings|Automatically resolve merge request diff threads when they become outdated')
+ = form.gitlab_ui_checkbox_component :printing_merge_request_link_enabled,
+ s_('ProjectSettings|Show link to create or view a merge request when pushing from the command line')
+ = form.gitlab_ui_checkbox_component :remove_source_branch_after_merge,
+ s_('ProjectSettings|Enable "Delete source branch" option by default'),
+ help_text: s_('ProjectSettings|Existing merge requests and protected branches are not affected.')
diff --git a/app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml b/app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml
new file mode 100644
index 00000000000..501288f727b
--- /dev/null
+++ b/app/views/projects/settings/merge_requests/_merge_request_merge_suggestions_settings.html.haml
@@ -0,0 +1,13 @@
+- form = local_assigns.fetch(:form)
+
+.form-group
+ %b= s_('ProjectSettings|Merge suggestions')
+ %p.text-secondary
+ = s_('ProjectSettings|The commit message used when applying merge request suggestions.')
+ .mb-2
+ = form.text_field :suggestion_commit_message, class: 'form-control mb-2', placeholder: Gitlab::Suggestions::CommitMessage::DEFAULT_SUGGESTION_COMMIT_MESSAGE
+ %p.form-text.text-muted
+ = s_('ProjectSettings|Leave empty to use default template.')
+ = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_SUGGESTIONS_TEMPLATE_LENGTH })
+ - link = link_to('', help_page_path('user/project/merge_requests/reviews/suggestions.md', anchor: 'configure-the-commit-message-for-applied-suggestions'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}'), tag_pair(link, :link_start, :link_end))
diff --git a/app/views/projects/_merge_request_pipelines_and_threads_options.html.haml b/app/views/projects/settings/merge_requests/_merge_request_pipelines_and_threads_options.html.haml
index a9609434f15..a9609434f15 100644
--- a/app/views/projects/_merge_request_pipelines_and_threads_options.html.haml
+++ b/app/views/projects/settings/merge_requests/_merge_request_pipelines_and_threads_options.html.haml
diff --git a/app/views/projects/settings/merge_requests/_merge_request_settings.html.haml b/app/views/projects/settings/merge_requests/_merge_request_settings.html.haml
new file mode 100644
index 00000000000..9449fc7f4ae
--- /dev/null
+++ b/app/views/projects/settings/merge_requests/_merge_request_settings.html.haml
@@ -0,0 +1,18 @@
+- form = local_assigns.fetch(:form)
+
+= render 'projects/settings/merge_requests/merge_request_merge_method_settings', project: @project, form: form
+
+= render 'projects/settings/merge_requests/merge_request_merge_options_settings', project: @project, form: form
+
+= render 'projects/settings/merge_requests/merge_request_squash_options_settings', form: form
+
+= render 'projects/settings/merge_requests/merge_request_merge_checks_settings', project: @project, form: form
+
+= render 'projects/settings/merge_requests/merge_request_merge_suggestions_settings', project: @project, form: form
+
+= render 'projects/settings/merge_requests/merge_request_merge_commit_template', project: @project, form: form
+
+= render 'projects/settings/merge_requests/merge_request_squash_commit_template', project: @project, form: form
+
+- if @project.forked?
+ = render 'projects/settings/merge_requests/merge_request_target_project_settings', project: @project, form: form
diff --git a/app/views/projects/_merge_request_settings_description_text.html.haml b/app/views/projects/settings/merge_requests/_merge_request_settings_description_text.html.haml
index 123520acad8..123520acad8 100644
--- a/app/views/projects/_merge_request_settings_description_text.html.haml
+++ b/app/views/projects/settings/merge_requests/_merge_request_settings_description_text.html.haml
diff --git a/app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml b/app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml
new file mode 100644
index 00000000000..bc6530b927c
--- /dev/null
+++ b/app/views/projects/settings/merge_requests/_merge_request_squash_commit_template.html.haml
@@ -0,0 +1,13 @@
+- form = local_assigns.fetch(:form)
+
+.form-group
+ %b= s_('ProjectSettings|Squash commit message template')
+ %p.text-secondary
+ = s_('ProjectSettings|The commit message used when squashing commits.')
+ .mb-2
+ = form.text_area :squash_commit_template_or_default, class: 'form-control gl-form-input', rows: 8, maxlength: Project::MAX_COMMIT_TEMPLATE_LENGTH, placeholder: s_('ProjectSettings|The default template will be applied on save.')
+ %p.form-text.text-muted
+ = s_('ProjectSettings|Leave empty to use default template.')
+ = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Project::MAX_COMMIT_TEMPLATE_LENGTH })
+ - link = link_to('', help_page_path('user/project/merge_requests/commit_templates.md'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('ProjectSettings|%{link_start}What variables can I use?%{link_end}'), tag_pair(link, :link_start, :link_end))
diff --git a/app/views/projects/_merge_request_squash_options_settings.html.haml b/app/views/projects/settings/merge_requests/_merge_request_squash_options_settings.html.haml
index 372c0723600..372c0723600 100644
--- a/app/views/projects/_merge_request_squash_options_settings.html.haml
+++ b/app/views/projects/settings/merge_requests/_merge_request_squash_options_settings.html.haml
diff --git a/app/views/projects/_merge_request_target_project_settings.html.haml b/app/views/projects/settings/merge_requests/_merge_request_target_project_settings.html.haml
index 6f2917f24e0..6f2917f24e0 100644
--- a/app/views/projects/_merge_request_target_project_settings.html.haml
+++ b/app/views/projects/settings/merge_requests/_merge_request_target_project_settings.html.haml
diff --git a/app/views/projects/settings/merge_requests/show.html.haml b/app/views/projects/settings/merge_requests/show.html.haml
index ef528d17fc9..01af028f30c 100644
--- a/app/views/projects/settings/merge_requests/show.html.haml
+++ b/app/views/projects/settings/merge_requests/show.html.haml
@@ -5,15 +5,16 @@
%section.rspec-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings.expanded{ class: [('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)], data: { qa_selector: 'merge_request_settings_content' } }
.settings-header
%h4= _('Merge requests')
- = render_if_exists 'projects/merge_request_settings_description_text'
+ = render_if_exists 'projects/settings/merge_requests/merge_request_settings_description_text'
.settings-content
= render_if_exists 'shared/promotions/promote_mr_features'
= gitlab_ui_form_for @project, url: project_settings_merge_requests_path(@project), html: { multipart: true, class: "merge-request-settings-form js-mr-settings-form" }, authenticity_token: true do |f|
%input{ name: 'update_section', type: 'hidden', value: 'js-merge-request-settings' }
- = render 'projects/merge_request_settings', form: f
+ = render 'projects/settings/merge_requests/merge_request_settings', form: f
= f.submit _('Save changes'), class: "rspec-save-merge-request-changes", data: { qa_selector: 'save_merge_request_changes_button' }, pajamas_button: true
= render_if_exists 'projects/settings/merge_requests/merge_request_approvals_settings', expanded: true
= render_if_exists 'projects/settings/merge_requests/suggested_reviewers_settings', expanded: true
+= render_if_exists 'projects/settings/merge_requests/target_branch_rules_settings'
diff --git a/app/views/projects/settings/operations/_alert_management.html.haml b/app/views/projects/settings/operations/_alert_management.html.haml
index 398c7758d66..c29cedd8250 100644
--- a/app/views/projects/settings/operations/_alert_management.html.haml
+++ b/app/views/projects/settings/operations/_alert_management.html.haml
@@ -3,7 +3,7 @@
- add_page_specific_style 'page_bundles/alert_management_settings'
- add_page_specific_style 'page_bundles/incident_management_list'
-%section.settings.no-animate#js-alert-management-settings{ class: ('expanded' if expanded), data: { qa_selector: 'alerts_settings_content' } }
+%section.settings.no-animate#js-alert-management-settings{ class: ('expanded' if expanded), data: { testid: 'alerts-settings-content' } }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Alerts')
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 8a35db357ee..c76fa5e2220 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -6,7 +6,6 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_path(@project, rss_url_options), title: "#{@project.name} activity")
-= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
= render_if_exists 'shared/promotions/promote_mobile_devops', project: @project
= render partial: 'flash_messages', locals: { project: @project }
diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml
index 53c3d16ee64..281eac6c773 100644
--- a/app/views/projects/tags/new.html.haml
+++ b/app/views/projects/tags/new.html.haml
@@ -11,9 +11,8 @@
= s_('TagsPage|New Tag')
%p.gl-text-secondary
- - link_start = '<a href="%{url}">'.html_safe % { url: new_namespace_project_release_path }
- - link_end = '</a>'.html_safe
- = s_('TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}.').html_safe % { link_start: link_start, link_end: link_end }
+ - link = link_to('', new_namespace_project_release_path)
+ = safe_format(s_('TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}.'), tag_pair(link, :link_start, :link_end))
= form_tag namespace_project_tags_path, method: :post, id: "new-tag-form", class: "common-note-form tag-form js-quick-submit js-requires-input" do
.form-group.row
diff --git a/app/views/projects/tracing/index.html.haml b/app/views/projects/tracing/index.html.haml
deleted file mode 100644
index ae6608cf343..00000000000
--- a/app/views/projects/tracing/index.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-- page_title _('Tracing')
-
-#js-tracing{ data: { view_model: observability_tracing_view_model(@project) } }
-
diff --git a/app/views/projects/tracing/show.html.haml b/app/views/projects/tracing/show.html.haml
deleted file mode 100644
index 4ba316a0b5c..00000000000
--- a/app/views/projects/tracing/show.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-- page_title _('Trace Details')
-- add_to_breadcrumbs _('Tracing'), project_tracing_index_path(@project)
-
-#js-tracing-details{ data: { view_model: observability_tracing_details_model(@project, @trace_id) } }
-
diff --git a/app/views/projects/usage_quotas/index.html.haml b/app/views/projects/usage_quotas/index.html.haml
index 616af3f3338..6f2a2aacf66 100644
--- a/app/views/projects/usage_quotas/index.html.haml
+++ b/app/views/projects/usage_quotas/index.html.haml
@@ -1,9 +1,6 @@
- page_title s_("UsageQuota|Usage")
-- add_page_specific_style 'page_bundles/projects_usage_quotas'
- @force_desktop_expanded_sidebar = true
-= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
-
= render Pajamas::AlertComponent.new(title: _('Repository usage recalculation started'),
variant: :info,
alert_options: { class: 'js-recalculation-started-alert gl-mt-4 gl-mb-5 gl-display-none' }) do |c|
diff --git a/app/views/protected_branches/_create_protected_branch.html.haml b/app/views/protected_branches/_create_protected_branch.html.haml
index 799f6aa6031..bc5da1653bf 100644
--- a/app/views/protected_branches/_create_protected_branch.html.haml
+++ b/app/views/protected_branches/_create_protected_branch.html.haml
@@ -1,14 +1,9 @@
- content_for :merge_access_levels do
.merge_access_levels-container
- = dropdown_tag(_('Select'),
- options: { toggle_class: 'js-allowed-to-merge wide',
- dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_qa_selector: 'allowed_to_merge_dropdown_content', dropdown_testid: 'allowed-to-merge-dropdown',
- data: { field_name: 'protected_branch[merge_access_levels_attributes][0][access_level]', input_id: 'merge_access_levels_attributes', qa_selector: 'select_allowed_to_merge_dropdown' }})
+ .js-allowed-to-merge
+
- content_for :push_access_levels do
.push_access_levels-container
- = dropdown_tag(_('Select'),
- options: { toggle_class: "js-allowed-to-push js-multiselect wide",
- dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_qa_selector: 'allowed_to_push_dropdown_content' , dropdown_testid: 'allowed-to-push-dropdown',
- data: { field_name: 'protected_branch[push_access_levels_attributes][0][access_level]', input_id: 'push_access_levels_attributes', qa_selector: 'select_allowed_to_push_dropdown' }})
+ .js-allowed-to-push
= render 'protected_branches/shared/create_protected_branch', protected_branch_entity: protected_branch_entity
diff --git a/app/views/protected_branches/shared/_index.html.haml b/app/views/protected_branches/shared/_index.html.haml
index dccfefc1cb8..8e72563182c 100644
--- a/app/views/protected_branches/shared/_index.html.haml
+++ b/app/views/protected_branches/shared/_index.html.haml
@@ -13,6 +13,13 @@
.settings-content
.js-alert-protected-branch-created-container.gl-mt-5
+ = render Pajamas::AlertComponent.new(variant: :warning,
+ alert_options: { class: 'gl-mb-5' },
+ dismissible: false) do |c|
+ - c.with_body do
+ = s_("ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features.")
+ = link_to s_("ProtectedBranch|What are the security implications?"), help_page_path('ci/pipelines/index', anchor: 'pipeline-security-on-protected-branches'), target: '_blank', rel: 'noopener noreferrer'
+
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card js-toggle-container' }, header_options: { class: 'gl-new-card-header gl-flex-direction-column' }, body_options: { class: 'gl-new-card-body gl-px-0' }) do |c|
- c.with_header do
.gl-new-card-title-wrapper.gl-justify-content-space-between
diff --git a/app/views/protected_branches/shared/_update_protected_branch.html.haml b/app/views/protected_branches/shared/_update_protected_branch.html.haml
index ad61f557bb8..e4c8b779447 100644
--- a/app/views/protected_branches/shared/_update_protected_branch.html.haml
+++ b/app/views/protected_branches/shared/_update_protected_branch.html.haml
@@ -3,17 +3,13 @@
%td.merge_access_levels-container
= hidden_field_tag "allowed_to_merge_#{protected_branch.id}", merge_access_levels.first&.access_level
- = dropdown_tag((merge_access_levels.first&.humanize || 'Select') ,
- options: { toggle_class: 'js-allowed-to-merge', dropdown_class: 'dropdown-menu-selectable js-allowed-to-merge-container capitalize-header',
- data: { field_name: "allowed_to_merge_#{protected_branch.id}", preselected_items: access_levels_data(merge_access_levels) }})
+ .js-allowed-to-merge{ data: { preselected_items: access_levels_data(merge_access_levels).to_json } }
= render_if_exists 'protected_branches/shared/user_merge_access_levels', protected_branch: protected_branch
= render_if_exists 'protected_branches/shared/group_merge_access_levels', protected_branch: protected_branch
%td.push_access_levels-container
= hidden_field_tag "allowed_to_push_#{protected_branch.id}", push_access_levels.first&.access_level
- = dropdown_tag((push_access_levels.first&.humanize || 'Select') ,
- options: { toggle_class: "js-allowed-to-push js-multiselect", dropdown_class: 'dropdown-menu-selectable js-allowed-to-push-container capitalize-header',
- data: { field_name: "allowed_to_push_#{protected_branch.id}", preselected_items: access_levels_data(push_access_levels) }})
+ .js-allowed-to-push{ data: { preselected_items: access_levels_data(push_access_levels).to_json } }
= render_if_exists 'protected_branches/shared/user_push_access_levels', protected_branch: protected_branch
= render_if_exists 'protected_branches/shared/group_push_access_levels', protected_branch: protected_branch
diff --git a/app/views/registrations/welcome/show.html.haml b/app/views/registrations/welcome/show.html.haml
index caaa209a702..0f161855cdb 100644
--- a/app/views/registrations/welcome/show.html.haml
+++ b/app/views/registrations/welcome/show.html.haml
@@ -33,7 +33,7 @@
= render_if_exists "registrations/welcome/jobs_to_be_done", f: f
= render_if_exists "registrations/welcome/setup_for_company", f: f
= render_if_exists "registrations/welcome/joining_project"
- = render 'devise/shared/email_opted_in', f: f
+ = render_if_exists "registrations/welcome/opt_in_to_email"
.row
.form-group.col-sm-12.gl-mb-0
- if partial_exists? "registrations/welcome/button"
diff --git a/app/views/repository_check_mailer/notify.html.haml b/app/views/repository_check_mailer/notify.html.haml
index dfcd1c6b19f..d6c57b98ea9 100644
--- a/app/views/repository_check_mailer/notify.html.haml
+++ b/app/views/repository_check_mailer/notify.html.haml
@@ -7,4 +7,4 @@
%p
= _("You are receiving this message because you are a GitLab administrator for %{url}.") % { url: Gitlab.config.gitlab.url }
-= render_if_exists 'repository_check_mailer/email_additional_text'
+= render_if_exists 'shared/additional_email_text'
diff --git a/app/views/repository_check_mailer/notify.text.haml b/app/views/repository_check_mailer/notify.text.haml
index a2e04fa710f..dc316d3e2be 100644
--- a/app/views/repository_check_mailer/notify.text.haml
+++ b/app/views/repository_check_mailer/notify.text.haml
@@ -4,4 +4,4 @@
= _("You are receiving this message because you are a GitLab administrator for %{url}.") % { url: Gitlab.config.gitlab.url }
-= render_if_exists 'repository_check_mailer/email_additional_text'
+= render_if_exists 'shared/additional_email_text'
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 7399f51d7f8..a1839b3dd39 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,3 +1,3 @@
.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
- = render partial: 'search/results_status' unless @search_objects.to_a.empty?
+ = render partial: 'search/results_status'
= render partial: 'search/results_list'
diff --git a/app/views/search/_results_list.html.haml b/app/views/search/_results_list.html.haml
index ff79f003e7d..fb96672cf99 100644
--- a/app/views/search/_results_list.html.haml
+++ b/app/views/search/_results_list.html.haml
@@ -8,7 +8,7 @@
- elsif @search_objects.blank?
= render partial: "search/results/empty"
- else
- - statusBarClass = !show_super_sidebar? ? 'gl-md-pl-5' : ''
+ - statusBarClass = !show_super_sidebar? ? 'gl-lg-pl-5' : ''
.section{ class: statusBarClass }
- if @scope == 'commits'
diff --git a/app/views/search/_results_status.html.haml b/app/views/search/_results_status.html.haml
index 6fc07d35296..8417b66eb34 100644
--- a/app/views/search/_results_status.html.haml
+++ b/app/views/search/_results_status.html.haml
@@ -1,28 +1,33 @@
-- return unless @search_service_presenter.show_results_status?
-- statusBarClass = !show_super_sidebar? ? 'gl-md-pl-5' : ''
+- statusBarClass = !show_super_sidebar? ? 'gl-lg-pl-5' : ''
+- statusBarClass = statusBarClass + ' gl-lg-display-none' if @search_objects.to_a.empty?
.section{ class: statusBarClass }
.search-results-status
.gl-display-flex.gl-flex-direction-column
- .gl-p-5.gl-display-flex
- .gl-md-display-flex.gl-text-left.gl-align-items-center.gl-flex-grow-1.gl-white-space-nowrap.gl-max-w-full
- - unless @search_service_presenter.without_count?
- .gl-text-truncate
- = search_entries_info(@search_objects, @scope, @search_term)
- - unless @search_service_presenter.show_snippets?
- - if @project
- - link_to_project = link_to(@project.full_name, @project, class: 'ml-md-1 gl-text-truncate search-wrap-f-md-down')
- - if @scope == 'blobs'
- = _("in")
- .mx-md-1
- #js-blob-ref-switcher{ data: { "project-id" => @project.id, "ref" => repository_ref(@project), "field-name": "repository_ref" } }
- = s_('SearchCodeResults|of %{link_to_project}').html_safe % { link_to_project: link_to_project }
- - else
- = _("in project %{link_to_project}").html_safe % { link_to_project: link_to_project }
- - elsif @group
- - link_to_group = link_to(@group.name, @group, class: 'ml-md-1')
- = _("in group %{link_to_group}").html_safe % { link_to_group: link_to_group }
- - if @search_service_presenter.show_sort_dropdown?
- .gl-md-display-flex.gl-flex-direction-column
- #js-search-sort{ data: { "search-sort-options" => search_sort_options.to_json } }
- %hr.gl-mb-5.gl-mt-0.gl-border-gray-100.gl-w-full
+ .gl-p-5.gl-display-flex.gl-flex-wrap
+ - unless @search_objects.to_a.empty?
+ .gl-display-flex.gl-text-left.gl-flex-grow-1.gl-flex-shrink-1.gl-white-space-nowrap.gl-flex-wrap.gl-sm-w-half
+ %p.gl-text-truncate.gl-my-auto
+ - unless @search_service_presenter.without_count?
+ = search_entries_info(@search_objects, @scope, @search_term)
+ - unless @search_service_presenter.show_snippets?
+ - if @project
+ - link_to_project = link_to(@project.full_name, @project, class: 'search-wrap-f-md-down')
+ - if @scope == 'blobs'
+ = _("in")
+ .mx-md-1.gl-my-auto
+ #js-blob-ref-switcher{ data: { "project-id" => @project.id, "ref" => repository_ref(@project), "field-name": "repository_ref" } }
+ %p.gl-text-truncate.gl-my-auto
+ = s_('SearchCodeResults|of %{link_to_project}').html_safe % { link_to_project: link_to_project }
+ - else
+ = _("in project %{link_to_project}").html_safe % { link_to_project: link_to_project }
+ - elsif @group
+ - link_to_group = link_to(@group.name, @group, class: 'ml-md-1')
+ = _("in group %{link_to_group}").html_safe % { link_to_group: link_to_group }
+ .gl-display-flex.gl-my-3.gl-flex-grow-1.gl-flex-shrink-1.gl-justify-content-end
+ = render Pajamas::ButtonComponent.new(category: 'primary', icon: 'filter', button_options: {id: 'js-open-mobile-filters', class: 'gl-lg-display-none'}) do
+ = s_('GlobalSearch|Filters')
+ - if @search_service_presenter.show_sort_dropdown? && !@search_objects.to_a.empty?
+ .gl-ml-3
+ #js-search-sort{ data: { "search-sort-options" => search_sort_options.to_json } }
+ %hr.gl-mb-5.gl-mt-0.gl-border-gray-100.gl-w-full
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 16ca829a6d4..2fd6e4a5ca5 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -22,7 +22,7 @@
= render_if_exists 'search/form_elasticsearch', attrs: { class: 'mb-2 mb-sm-0 align-self-center' }
#js-search-topbar{ data: { "group-initial-json": group_attributes.to_json, "project-initial-json": project_attributes.to_json, "elasticsearch-enabled": @search_service_presenter.advanced_search_enabled?.to_s, "default-branch-name": @project&.default_branch } }
-.results.gl-md-display-flex.gl-mt-0
- #js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json } }
+.results.gl-lg-display-flex.gl-mt-0
+ #js-search-sidebar{ class: search_bar_classes, data: { navigation_json: search_navigation_json, search_type: search_service.search_type } }
- if @search_term
= render 'search/results'
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 48ae1f7eb1d..dde4ec3cf52 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -18,5 +18,5 @@
= text_field_tag :clone_url, default_url_to_repo(container), class: "js-select-on-focus btn gl-button", readonly: true, aria: { label: _('Repository clone URL') }, data: { qa_selector: 'clone_url_content' }
.input-group-append
- = clipboard_button(target: '#clone_url', title: _("Copy URL"), class: "input-group-text gl-button btn-default btn-clipboard")
+ = clipboard_button(target: '#clone_url', title: _("Copy URL"), variant: :default, category: :primary, size: :medium)
diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml
index 5058455dcd7..05b376003bc 100644
--- a/app/views/shared/_label_row.html.haml
+++ b/app/views/shared/_label_row.html.haml
@@ -15,6 +15,9 @@
.gl-my-1
= markdown_field(label, :description)
%ul.label-links.gl-m-0.gl-p-0.gl-white-space-nowrap
+ - if label.lock_on_merge
+ %li.inline.gl-mr-3.gl-mt-1
+ .label-badge.gl-bg-orange-50= _('Lock on merge')
- if force_priority
%li.js-priority-badge.inline.gl-mr-3.gl-mt-1
.label-badge.gl-bg-blue-50= _('Prioritized')
diff --git a/app/views/shared/_logo.svg b/app/views/shared/_logo.svg
index 83f6fe5c16c..dfc35856366 100644
--- a/app/views/shared/_logo.svg
+++ b/app/views/shared/_logo.svg
@@ -1,4 +1,4 @@
-<svg class="tanuki-logo" width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<svg role="img" class="tanuki-logo" width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path class="tanuki-shape tanuki" d="m24.507 9.5-.034-.09L21.082.562a.896.896 0 0 0-1.694.091l-2.29 7.01H7.825L5.535.653a.898.898 0 0 0-1.694-.09L.451 9.411.416 9.5a6.297 6.297 0 0 0 2.09 7.278l.012.01.03.022 5.16 3.867 2.56 1.935 1.554 1.176a1.051 1.051 0 0 0 1.268 0l1.555-1.176 2.56-1.935 5.197-3.89.014-.01A6.297 6.297 0 0 0 24.507 9.5Z"
fill="#E24329"/>
<path class="tanuki-shape right-cheek" d="m24.507 9.5-.034-.09a11.44 11.44 0 0 0-4.56 2.051l-7.447 5.632 4.742 3.584 5.197-3.89.014-.01A6.297 6.297 0 0 0 24.507 9.5Z"
diff --git a/app/views/shared/_mobile_clone_panel.html.haml b/app/views/shared/_mobile_clone_panel.html.haml
index aa3043b8fd6..c594cee326e 100644
--- a/app/views/shared/_mobile_clone_panel.html.haml
+++ b/app/views/shared/_mobile_clone_panel.html.haml
@@ -3,7 +3,7 @@
- http_copy_label = _('Copy %{http_label} clone URL') % { http_label: gitlab_config.protocol.upcase }
.btn-group.mobile-git-clone.js-mobile-git-clone.btn-block
- = clipboard_button(button_text: default_clone_label, text: default_url_to_repo(project), hide_button_icon: true, class: "gl-button btn-confirm flex-fill bold justify-content-center input-group-text clone-dropdown-btn js-clone-dropdown-label")
+ = clipboard_button(button_text: default_clone_label, size: :medium, category: :primary, variant: :confirm, text: default_url_to_repo(project), hide_button_icon: true, class: "clone-dropdown-btn js-clone-dropdown-label")
%button.btn.gl-button.btn-confirm.dropdown-toggle.js-dropdown-toggle.flex-grow-0.d-flex-center.w-auto.ml-0{ type: "button", data: { toggle: "dropdown" } }
= sprite_icon("chevron-down", css_class: "dropdown-btn-icon icon")
%ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown{ data: { dropdown: true } }
diff --git a/app/views/shared/_outdated_browser.html.haml b/app/views/shared/_outdated_browser.html.haml
index 79d0231536b..e62e3bb4a6c 100644
--- a/app/views/shared/_outdated_browser.html.haml
+++ b/app/views/shared/_outdated_browser.html.haml
@@ -3,5 +3,5 @@
- c.with_body do
= s_('OutdatedBrowser|GitLab may not work properly, because you are using an outdated web browser.')
%br
- - browser_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('install/requirements', anchor: 'supported-web-browsers') }
- = s_('OutdatedBrowser|Please install a %{browser_link_start}supported web browser%{browser_link_end} for a better experience.').html_safe % { browser_link_start: browser_link_start, browser_link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('install/requirements', anchor: 'supported-web-browsers'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('OutdatedBrowser|Please install a %{browser_link_start}supported web browser%{browser_link_end} for a better experience.'), tag_pair(link, :browser_link_start, :browser_link_end))
diff --git a/app/views/shared/_silent_mode_banner.html.haml b/app/views/shared/_silent_mode_banner.html.haml
new file mode 100644
index 00000000000..10e5d05fad2
--- /dev/null
+++ b/app/views/shared/_silent_mode_banner.html.haml
@@ -0,0 +1,9 @@
+- return unless ::Gitlab::SilentMode.enabled?
+
+= content_for :page_level_alert do
+ %div{ class: [container_class, @content_class, 'gl-pt-5!'] }
+ = render Pajamas::AlertComponent.new(title: s_('SilentMode|Silent mode is enabled'),
+ dismissible: false,
+ variant: :warning) do |c|
+ - c.with_body do
+ = s_('SilentMode|All outbound communications are blocked. %{link_start}Learn more%{link_end}.').html_safe % { link_start: "<a href='#{help_page_path('administration/silent_mode/index')}' target='_blank' rel='noopener noreferrer'>".html_safe, link_end: '</a>'.html_safe }
diff --git a/app/views/shared/_visibility_level.html.haml b/app/views/shared/_visibility_level.html.haml
index 763ae5a498b..3cf13222f4e 100644
--- a/app/views/shared/_visibility_level.html.haml
+++ b/app/views/shared/_visibility_level.html.haml
@@ -5,9 +5,8 @@
= f.label :visibility_level, _('Visibility level'), class: 'label-bold gl-mb-0'
%p
= _('Who can see this group?')
- - visibility_docs_path = help_page_path('user/public_access')
- - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: visibility_docs_path }
- = _('%{docs_link_start}Learn about visibility levels.%{docs_link_end}').html_safe % { docs_link_start: docs_link_start, docs_link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('user/public_access'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_('%{docs_link_start}Learn about visibility levels.%{docs_link_end}'), tag_pair(link, :docs_link_start, :docs_link_end))
- if can_change_visibility_level
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
- else
diff --git a/app/views/shared/builds/_build_output.html.haml b/app/views/shared/builds/_build_output.html.haml
deleted file mode 100644
index a3b7d4926f8..00000000000
--- a/app/views/shared/builds/_build_output.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-%pre.build-log
- %code.bash.js-build-output
- .build-loader-animation.js-build-refresh
- .dot
- .dot
- .dot
diff --git a/app/views/shared/builds/_tabs.html.haml b/app/views/shared/builds/_tabs.html.haml
deleted file mode 100644
index 8f2b9fc06e3..00000000000
--- a/app/views/shared/builds/_tabs.html.haml
+++ /dev/null
@@ -1,15 +0,0 @@
-- count_badge_classes = 'gl-display-none gl-sm-display-inline-flex'
-
-= gl_tabs_nav({class: 'scrolling-tabs nav-links gl-display-flex gl-flex-grow-1 gl-w-full nav gl-border-b-0', data: { testid: 'jobs-tabs' } }) do
- = gl_tab_link_to build_path_proc.call(nil), { item_active: scope.nil? } do
- = _('All')
- = gl_tab_counter_badge(limited_counter_with_delimiter(all_builds), { class: count_badge_classes })
- = gl_tab_link_to build_path_proc.call('pending'), { item_active: scope == 'pending' } do
- = _('Pending')
- = gl_tab_counter_badge(limited_counter_with_delimiter(all_builds.pending), { class: count_badge_classes })
- = gl_tab_link_to build_path_proc.call('running'), { item_active: scope == 'running' } do
- = _('Running')
- = gl_tab_counter_badge(limited_counter_with_delimiter(all_builds.running), { class: count_badge_classes })
- = gl_tab_link_to build_path_proc.call('finished'), { item_active: scope == 'finished' } do
- = _('Finished')
- = gl_tab_counter_badge(limited_counter_with_delimiter(all_builds.finished), { class: count_badge_classes })
diff --git a/app/views/shared/deploy_keys/_index.html.haml b/app/views/shared/deploy_keys/_index.html.haml
index 650e50e0312..5188c530672 100644
--- a/app/views/shared/deploy_keys/_index.html.haml
+++ b/app/views/shared/deploy_keys/_index.html.haml
@@ -5,8 +5,8 @@
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded ? _('Collapse') : _('Expand')
%p.gl-text-secondary
- - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/deploy_keys/index') }
- = _("Add deploy keys to grant read/write access to this repository. %{link_start}What are deploy keys?%{link_end}").html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('user/project/deploy_keys/index'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_("Add deploy keys to grant read/write access to this repository. %{link_start}What are deploy keys?%{link_end}"), tag_pair(link, :link_start, :link_end))
.settings-content
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card js-toggle-container' }, body_options: { class: 'gl-new-card-body gl-px-0' }) do |c|
- c.with_body do
diff --git a/app/views/shared/deploy_keys/_project_group_form.html.haml b/app/views/shared/deploy_keys/_project_group_form.html.haml
index c633088b26a..bb4295779cd 100644
--- a/app/views/shared/deploy_keys/_project_group_form.html.haml
+++ b/app/views/shared/deploy_keys/_project_group_form.html.haml
@@ -1,30 +1,30 @@
-= gitlab_ui_form_for [@project.namespace, @project, @deploy_keys.new_key], url: namespace_project_deploy_keys_path, html: { class: "js-requires-input container" } do |f|
+= gitlab_ui_form_for [@project.namespace, @project, @deploy_keys.new_key], url: namespace_project_deploy_keys_path, html: { class: "js-requires-input" } do |f|
= form_errors(@deploy_keys.new_key)
- .form-group.row
+ .form-group
%h4.gl-my-0= s_('DeployKeys|Add new deploy key')
- .form-group.row
+ .form-group
= f.label :title, class: "label-bold"
- = f.text_field :title, class: 'form-control gl-form-input', required: true, data: { testid: 'deploy-key-title-field' }
- .form-group.row
+ = f.text_field :title, class: 'form-control gl-form-input gl-form-input-xl', required: true, data: { testid: 'deploy-key-title-field' }
+ .form-group
= f.label :key, class: "label-bold"
- = f.text_area :key, class: 'form-control gl-form-input', rows: 5, required: true, data: { testid: 'deploy-key-field' }
- .form-group.row
- %p.light.gl-mb-0
+ = f.text_area :key, class: 'form-control gl-form-input gl-form-input-xl gl-h-auto!', rows: 5, required: true, data: { testid: 'deploy-key-field' }
+ .form-text.text-muted
= _('Paste a public key here.')
= link_to _('How do I generate it?'), help_page_path("user/ssh")
= f.fields_for :deploy_keys_projects do |deploy_keys_project_form|
- .form-group.row
+ .form-group
= deploy_keys_project_form.gitlab_ui_checkbox_component :can_push, _('Grant write permissions to this key'),
help_text: _('Allow this key to push to this repository')
- .form-group.row
+ .form-group
= f.label :expires_at, _('Expiration date (optional)'), class: 'label-bold'
- = f.gitlab_ui_datepicker :expires_at, data: { testid: 'deploy-key-expires-at-field' }, value: f.object.expires_at
- %p.form-text.text-muted= ssh_key_expires_field_description
+ .gl-form-input-xl
+ = f.gitlab_ui_datepicker :expires_at, data: { testid: 'deploy-key-expires-at-field' }, value: f.object.expires_at
+ .form-text.text-muted= ssh_key_expires_field_description
- .form-group.row.gl-mb-0
+ .form-group.gl-mb-0
= f.submit _("Add key"), data: { testid: "add-deploy-key-button"}, pajamas_button: true
= render Pajamas::ButtonComponent.new(button_options: { type: 'reset', class: 'gl-ml-3 js-toggle-button' }) do
= _('Cancel')
diff --git a/app/views/shared/deploy_tokens/_form.html.haml b/app/views/shared/deploy_tokens/_form.html.haml
index 8821804ce6b..bb7e0d774cc 100644
--- a/app/views/shared/deploy_tokens/_form.html.haml
+++ b/app/views/shared/deploy_tokens/_form.html.haml
@@ -1,7 +1,6 @@
%p
- - group_deploy_tokens_help_link_url = help_page_path('user/project/deploy_tokens/index.md')
- - group_deploy_tokens_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: group_deploy_tokens_help_link_url }
- = s_('DeployTokens|Create a new deploy token for all projects in this group. %{link_start}What are deploy tokens?%{link_end}').html_safe % { link_start: group_deploy_tokens_help_link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('user/project/deploy_tokens/index.md'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('DeployTokens|Create a new deploy token for all projects in this group. %{link_start}What are deploy tokens?%{link_end}'), tag_pair(link, :link_start, :link_end))
= gitlab_ui_form_for token, url: create_deploy_token_path(group_or_project, anchor: 'js-deploy-tokens'), method: :post, remote: true do |f|
diff --git a/app/views/shared/deploy_tokens/_new_deploy_token.html.haml b/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
index 9c82d5685f8..25c277ea0ea 100644
--- a/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
+++ b/app/views/shared/deploy_tokens/_new_deploy_token.html.haml
@@ -7,7 +7,7 @@
.input-group
= text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { qa_selector: 'deploy_token_user_field' }
.input-group-append
- = clipboard_button(text: deploy_token.username, title: s_('DeployTokens|Copy username'), placement: 'left')
+ = deprecated_clipboard_button(text: deploy_token.username, title: s_('DeployTokens|Copy username'), placement: 'left')
%span.deploy-token-help-block.gl-mt-2.text-success
- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/project/deploy_tokens/index.md') }
- link_end = "</a>".html_safe
@@ -17,7 +17,7 @@
.input-group
= text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus', data: { qa_selector: 'deploy_token_field' }
.input-group-append
- = clipboard_button(text: deploy_token.token, title: s_('DeployTokens|Copy deploy token'), placement: 'left')
+ = deprecated_clipboard_button(text: deploy_token.token, title: s_('DeployTokens|Copy deploy token'), placement: 'left')
%span.deploy-token-help-block.gl-mt-2.text-danger
- i_start = "<i>".html_safe
- i_end = "</i>".html_safe
diff --git a/app/views/shared/doorkeeper/applications/_show.html.haml b/app/views/shared/doorkeeper/applications/_show.html.haml
index 4101a456f32..d309a335166 100644
--- a/app/views/shared/doorkeeper/applications/_show.html.haml
+++ b/app/views/shared/doorkeeper/applications/_show.html.haml
@@ -10,7 +10,7 @@
.input-group
%input.label.label-monospace.monospace{ id: "application_id", type: "text", autocomplete: 'off', value: @application.uid, readonly: true, data: { qa_selector: 'application_id_field' } }
.input-group-append
- = clipboard_button(target: '#application_id', title: _("Copy ID"), class: "gl-button btn btn-default")
+ = clipboard_button(target: "#application_id", title: _("Copy ID"), category: :primary, size: :medium)
%tr
%td
= _('Secret')
diff --git a/app/views/shared/form_elements/_description.html.haml b/app/views/shared/form_elements/_description.html.haml
index 75f678dea5c..b05befce24e 100644
--- a/app/views/shared/form_elements/_description.html.haml
+++ b/app/views/shared/form_elements/_description.html.haml
@@ -21,7 +21,7 @@
.js-markdown-editor{ data: { render_markdown_path: preview_url,
markdown_docs_path: help_page_path('user/markdown'),
quick_actions_docs_path: help_page_path('user/project/quick_actions'),
- qa_selector: 'issuable_form_description_field',
+ testid: 'issuable-form-description-field',
form_field_placeholder: placeholder,
autofocus: 'false',
form_field_classes: 'js-gfm-input markdown-area note-textarea rspec-issuable-form-description' } }
diff --git a/app/views/shared/groups/_empty_state.html.haml b/app/views/shared/groups/_empty_state.html.haml
deleted file mode 100644
index aaba9697fea..00000000000
--- a/app/views/shared/groups/_empty_state.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-.row.gl-align-items-center.gl-justify-content-center
- .order-md-2
- = custom_icon("icon_empty_groups")
-
- .text-content.order-md-1{ class: 'gl-m-0!' }
- %h4= s_("GroupsEmptyState|A group is a collection of several projects.")
- %p= s_("GroupsEmptyState|If you organize your projects under a group, it works like a folder.")
- %p= s_("GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group.")
diff --git a/app/views/shared/hook_logs/_content.html.haml b/app/views/shared/hook_logs/_content.html.haml
index 1971c2da913..e8cb93f8037 100644
--- a/app/views/shared/hook_logs/_content.html.haml
+++ b/app/views/shared/hook_logs/_content.html.haml
@@ -1,6 +1,6 @@
%span.gl-display-flex.gl-align-items-center
- %h4
- POST
+ %h5
+ = gl_badge_tag "POST", { size: :sm }, { variant: :info }
= hook_log.url
= gl_badge_tag hook_log.trigger.singularize.titleize, { size: :sm }, { class: 'gl-ml-3' }
@@ -16,19 +16,28 @@
- c.with_body do
= _('Error: %{error}') % { error: hook_log.internal_error_message }
-%h4= _('Response')
-= render partial: 'shared/hook_logs/status_label', locals: { hook_log: hook_log }
+%span.gl-display-flex.gl-align-items-center
+ %h3
+ = _('Response')
+ = render partial: 'shared/hook_logs/status_label', locals: { hook_log: hook_log }
+
%pre.gl-mt-3
- :escaped
- #{hook_log.response_body}
+ - if hook_log.response_body.blank?
+ = s_('Webhooks|Response body is empty')
+ - else
+ :escaped
+ #{hook_log.response_body}
-%h5= _('Headers')
+%h4= _('Headers')
%pre
- - hook_log.response_headers.each do |k, v|
- <span class="gl-font-weight-bold">#{k}:</span> #{v}
- %br
+ - if hook_log.response_headers.blank?
+ = s_('Webhooks|Response headers data is empty')
+ - else
+ - hook_log.response_headers.each do |k, v|
+ <span class="gl-font-weight-bold">#{k}:</span> #{v}
+ %br
-%h4.gl-mt-6= _('Request')
+%h3.gl-mt-6= _('Request')
%pre
- if hook_log.oversize?
= _('Request data is too large')
@@ -36,7 +45,7 @@
:escaped
#{Gitlab::Json.pretty_generate(hook_log.request_data)}
-%h5= _('Headers')
+%h4= _('Headers')
%pre
- hook_log.request_headers.each do |k, v|
<span class="gl-font-weight-bold">#{k}:</span> #{v}
diff --git a/app/views/shared/icons/_icon_empty_groups.svg b/app/views/shared/icons/_icon_empty_groups.svg
deleted file mode 100644
index cf378145e59..00000000000
--- a/app/views/shared/icons/_icon_empty_groups.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="249" height="368" viewBox="891 156 249 368" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="a" width="131" height="162" rx="10"/><mask id="e" x="0" y="0" width="131" height="162" fill="#fff"><use xlink:href="#a"/></mask><path d="M223.616 127.958V108.96c0-4.416-3.584-8-8.005-8h-23.985c-2.778 0-5.98 2.014-7.18 4.5l-5.07 10.5h-49.763c-5.527 0-9.996 4.475-9.996 9.997v53.005c0 5.513 4.475 9.997 9.996 9.997h84.01c5.525 0 9.994-4.477 9.994-9.998v-51.004z" id="b"/><mask id="f" x="0" y="0" width="104" height="88" fill="#fff"><use xlink:href="#b"/></mask><path d="M47 25h.996C53.52 25 58 29.472 58 34.99v20.02C58 60.526 53.52 65 47.996 65H10.004C4.48 65 0 60.528 0 55.01V34.99C0 29.474 4.48 25 10.004 25H11v-7c0-9.94 8.06-18 18-18s18 8.06 18 18v7zm-6 0H17v-7c0-6.627 5.373-12 12-12s12 5.373 12 12v7z" id="c"/><mask id="g" x="0" y="0" width="58" height="65" fill="#fff"><use xlink:href="#c"/></mask><path d="M0 10.008C0 4.48 4.476 0 10 0h218c5.523 0 10 4.473 10 10.008v140.94c0 5.53-4.062 11.882-9.08 14.196l-100.84 46.5c-5.015 2.31-13.142 2.312-18.16 0l-100.84-46.5C4.064 162.832 0 156.484 0 150.95V10.007z" id="d"/><mask id="h" x="0" y="0" width="238" height="213.417" fill="#fff"><use xlink:href="#d"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(891 156)"><g transform="rotate(8 -266.528 490.3)"><use stroke="#E5E5E5" mask="url(#e)" stroke-width="8" fill="#FFF" xlink:href="#a"/><rect fill="#FC8A51" x="20" y="31" width="12" height="4" rx="2"/><rect fill="#FC8A51" x="60" y="31" width="12" height="4" rx="2"/><rect fill="#FDE5D8" x="36" y="31" width="20" height="4" rx="2"/><rect fill="#6B4FBB" x="20" y="65" width="20" height="4" rx="2"/><rect fill="#FDE5D8" x="44" y="65" width="20" height="4" rx="2"/><rect fill="#FC8A51" x="36" y="80" width="20" height="4" rx="2"/><rect fill="#FDE5D8" x="20" y="80" width="12" height="4" rx="2"/><rect fill="#FDE5D8" x="20" y="48" width="12" height="4" rx="2"/><rect fill="#FC8A51" x="36" y="48" width="12" height="4" rx="2"/><rect fill="#FDE5D8" x="60" y="80" width="12" height="4" rx="2"/><rect fill="#6B4FBB" x="52" y="48" width="12" height="4" rx="2"/><rect fill="#FDE5D8" x="68" y="48" width="12" height="4" rx="2"/></g><use stroke="#B5A7DD" mask="url(#f)" stroke-width="8" fill="#FFF" transform="rotate(5 171.616 144.96)" xlink:href="#b"/><path d="M58 132c0-9.94 8.06-18 18-18s18 8.06 18 18-8.06 18-18 18-18-8.06-18-18z" fill="#C1E7D0"/><path d="M90.143 132c0-7.81-6.332-14.143-14.143-14.143-7.81 0-14.143 6.332-14.143 14.143 0 7.81 6.332 14.143 14.143 14.143 7.81 0 14.143-6.332 14.143-14.143z" fill="#FFF"/><path d="M74.686 133.875l-3.18-3.18c-.29-.29-.77-.296-1.06-.005l-1.55 1.55c-.287.287-.29.766.004 1.06l4.92 4.92c.504.504 1.32.504 1.823 0l.654-.653 7.804-7.804c.3-.3.29-.77-.005-1.067l-1.578-1.58c-.302-.3-.775-.298-1.068-.004l-6.764 6.763z" fill="#31AF64"/><path d="M4 66c0-9.94 8.06-18 18-18s18 8.06 18 18-8.06 18-18 18S4 75.94 4 66z" fill="#D5ECF7"/><path d="M36.143 66c0-7.81-6.332-14.143-14.143-14.143-7.81 0-14.143 6.332-14.143 14.143 0 7.81 6.332 14.143 14.143 14.143 7.81 0 14.143-6.332 14.143-14.143z" fill="#FFF"/><path d="M22 55.714c5.68 0 10.286 4.605 10.286 10.286 0 5.68-4.605 10.286-10.286 10.286-3.45 0-6.505-1.7-8.37-4.307L22 66V55.714z" fill="#2D9FD8"/><g transform="rotate(-8 748.533 18.147)"><use stroke="#FDE5D8" mask="url(#g)" stroke-width="8" fill="#FFF" xlink:href="#c"/><path d="M31 46.584c1.766-.772 3-2.534 3-4.584 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.05 1.234 3.812 3 4.584v3.42c0 1.1.895 1.996 2 1.996 1.112 0 2-.894 2-1.997v-3.42z" fill="#FC8A51"/></g><g transform="translate(0 154)"><use stroke="#E5E5E5" mask="url(#h)" stroke-width="8" fill="#FFF" xlink:href="#d"/><g opacity=".3"><path d="M141.837 104.53l-2.56-7.993-5.074-15.843c-.26-.815-1.398-.815-1.66 0l-5.074 15.843h-16.85l-5.075-15.843c-.26-.815-1.398-.815-1.66 0l-5.073 15.843-2.56 7.993c-.234.73.022 1.528.633 1.98l22.16 16.33 22.16-16.33c.61-.452.866-1.25.632-1.98" fill="#A1A1A1"/><path fill="#5C5C5C" d="M119.044 122.84l8.425-26.303h-16.85l8.424 26.304"/><path fill="#787878" d="M119.044 122.84l-8.425-26.303H98.81l20.232 26.304"/><path fill="#787878" d="M119.044 122.84l8.425-26.303h11.807l-20.233 26.304"/><path d="M98.812 96.537l-2.56 7.993c-.234.73.022 1.528.633 1.98l22.16 16.33L98.81 96.538z" fill="#A1A1A1"/><path d="M98.812 96.537h11.807l-5.075-15.843c-.26-.815-1.398-.815-1.66 0l-5.073 15.843z" fill="#5C5C5C"/><path d="M139.277 96.537l2.56 7.993c.234.73-.022 1.528-.634 1.98l-22.16 16.33 20.234-26.303z" fill="#A1A1A1"/><path d="M139.277 96.537H127.47l5.074-15.843c.26-.815 1.398-.815 1.66 0l5.073 15.843z" fill="#5C5C5C"/></g><path d="M57 18.29c1.105 0 2-.818 2-1.828 0-1.01-.895-1.83-2-1.83H41c-1.105 0-2 .82-2 1.83 0 1.01.895 1.83 2 1.83h16zm36 0c1.105 0 2-.818 2-1.828 0-1.01-.895-1.83-2-1.83H77c-1.105 0-2 .82-2 1.83 0 1.01.895 1.83 2 1.83h16zm36 0c1.105 0 2-.818 2-1.828 0-1.01-.895-1.83-2-1.83h-16c-1.105 0-2 .82-2 1.83 0 1.01.895 1.83 2 1.83h16zm36 0c1.105 0 2-.818 2-1.828 0-1.01-.895-1.83-2-1.83h-16c-1.105 0-2 .82-2 1.83 0 1.01.895 1.83 2 1.83h16zm36 0c1.105 0 2-.818 2-1.828 0-1.01-.895-1.83-2-1.83h-16c-1.105 0-2 .82-2 1.83 0 1.01.895 1.83 2 1.83h16zm17 24.693c0 1.01.895 1.83 2 1.83s2-.82 2-1.83V28.35c0-1.01-.895-1.83-2-1.83s-2 .82-2 1.83v14.633zm-202 0c0 1.01.895 1.83 2 1.83s2-.82 2-1.83V28.35c0-1.01-.895-1.83-2-1.83s-2 .82-2 1.83v14.633zm202 32.923c0 1.01.895 1.83 2 1.83s2-.82 2-1.83V61.274c0-1.01-.895-1.83-2-1.83s-2 .82-2 1.83v14.632zm-202 0c0 1.01.895 1.83 2 1.83s2-.82 2-1.83V61.274c0-1.01-.895-1.83-2-1.83s-2 .82-2 1.83v14.632zm202 32.923c0 1.01.895 1.828 2 1.828s2-.82 2-1.83V94.2c0-1.012-.895-1.83-2-1.83s-2 .818-2 1.83v14.63zm-202 0c0 1.01.895 1.828 2 1.828s2-.82 2-1.83V94.2c0-1.012-.895-1.83-2-1.83s-2 .818-2 1.83v14.63zm202 32.922c0 1.01.895 1.83 2 1.83s2-.82 2-1.83V127.12c0-1.01-.895-1.83-2-1.83s-2 .82-2 1.83v14.632zm-202 0c0 1.01.895 1.83 2 1.83s2-.82 2-1.83V127.12c0-1.01-.895-1.83-2-1.83s-2 .82-2 1.83v14.632zm179.023 19.555c-.988.452-1.388 1.55-.894 2.454.493.904 1.694 1.27 2.682.82l14.31-6.545c.99-.452 1.39-1.55.896-2.454-.494-.902-1.696-1.27-2.684-.817l-14.31 6.544zm-32.2 14.723c-.987.452-1.388 1.55-.894 2.454.493.904 1.695 1.27 2.683.818l14.31-6.544c.99-.45 1.39-1.55.895-2.454-.494-.903-1.695-1.27-2.683-.818l-14.31 6.544zm-32.2 14.724c-.987.45-1.387 1.55-.893 2.454.494.903 1.695 1.27 2.683.818l14.31-6.544c.99-.452 1.39-1.55.896-2.454-.495-.904-1.697-1.27-2.685-.818l-14.31 6.544zm-23.67-2.023l-12.186-5.57c-.987-.452-2.19-.086-2.683.817-.494.904-.093 2.003.895 2.454l12.185 5.573c.754.345 1.57.645 2.438.898 1.052.307 2.177-.224 2.513-1.187.335-.962-.246-1.99-1.298-2.298-.677-.197-1.302-.426-1.864-.684zM62.57 168.437c-.988-.452-2.19-.086-2.683.818-.494.903-.094 2.002.894 2.454l14.31 6.544c.988.45 2.19.085 2.683-.818.494-.904.094-2.003-.894-2.454l-14.312-6.544zm-32.2-14.723c-.988-.452-2.19-.086-2.683.818-.494.904-.093 2.003.895 2.454l14.31 6.544c.988.452 2.19.086 2.684-.818.494-.903.093-2.002-.895-2.454l-14.312-6.543z" fill="#EEE"/></g><g><path d="M104 18c0-9.94 8.06-18 18-18s18 8.06 18 18-8.06 18-18 18-18-8.06-18-18z" fill="#FADFD9"/><path d="M136.143 18c0-7.81-6.332-14.143-14.143-14.143-7.81 0-14.143 6.332-14.143 14.143 0 7.81 6.332 14.143 14.143 14.143 7.81 0 14.143-6.332 14.143-14.143z" fill="#FFF"/><path d="M119.43 8.994c0-.707.57-1.28 1.283-1.28h2.574c.71 0 1.284.57 1.284 1.28v10.298c0 .706-.57 1.28-1.283 1.28h-2.574c-.71 0-1.284-.57-1.284-1.28V8.994zm0 15.433c0-.71.57-1.284 1.283-1.284h2.574c.71 0 1.284.57 1.284 1.284V27c0 .71-.57 1.286-1.283 1.286h-2.574c-.71 0-1.284-.57-1.284-1.285v-2.573z" fill="#E75E40"/></g><g><path d="M213 89c0-9.94 8.06-18 18-18s18 8.06 18 18-8.06 18-18 18-18-8.06-18-18z" fill="#F6D4DC"/><path d="M245.143 89c0-7.81-6.332-14.143-14.143-14.143-7.81 0-14.143 6.332-14.143 14.143 0 7.81 6.332 14.143 14.143 14.143 7.81 0 14.143-6.332 14.143-14.143z" fill="#FFF"/><path d="M231 86.348l-3.603-3.602c-.288-.29-.766-.286-1.063.01l-1.578 1.578c-.3.302-.3.773-.01 1.063L228.348 89l-3.602 3.603c-.29.288-.286.766.01 1.063l1.578 1.578c.302.3.773.3 1.063.01L231 91.652l3.603 3.602c.288.29.766.286 1.063-.01l1.578-1.578c.3-.302.3-.773.01-1.063L233.652 89l3.602-3.603c.29-.288.286-.766-.01-1.063l-1.578-1.578c-.302-.3-.773-.3-1.063-.01L231 86.348z" fill="#D22852"/></g></g></svg>
diff --git a/app/views/shared/integrations/mattermost_slash_commands/_detailed_help.html.haml b/app/views/shared/integrations/mattermost_slash_commands/_detailed_help.html.haml
index db1754c1864..5aaae5eb4ec 100644
--- a/app/views/shared/integrations/mattermost_slash_commands/_detailed_help.html.haml
+++ b/app/views/shared/integrations/mattermost_slash_commands/_detailed_help.html.haml
@@ -1,30 +1,21 @@
- pretty_name = @project&.full_name ? html_escape(@project&.full_name) : '<' + _('project name') + '>'
- run_actions_text = html_escape(s_("ProjectService|Perform common operations on GitLab project: %{project_name}")) % { project_name: pretty_name }
+- external_link_icon = sprite_icon('external-link')
%p= s_("ProjectService|To configure this integration, you should:")
-%ul.list-unstyled.indent-list
+%ol.indent-list
%li
- 1.
- = link_to help_page_url('user/project/integrations/mattermost_slash_commands', anchor: 'enable-custom-slash-commands-in-mattermost'), target: '_blank', rel: 'noopener noreferrer nofollow' do
- Enable custom slash commands
- = sprite_icon('external-link')
- on your Mattermost installation.
+ - enable_slash_commands_link_url = help_page_url('user/project/integrations/mattermost_slash_commands', anchor: 'enable-custom-slash-commands-in-mattermost')
+ - enable_slash_commands_link = link_to '', enable_slash_commands_link_url, target: '_blank', rel: 'noopener noreferrer'
+ = safe_format(s_('MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation.'), tag_pair(enable_slash_commands_link, :link_start, :link_end), icon: external_link_icon)
%li
- 2.
- = link_to help_page_url('user/project/integrations/mattermost_slash_commands', anchor: 'create-a-slash-command-in-mattermost'), target: '_blank', rel: 'noopener noreferrer nofollow' do
- Add a slash command
- = sprite_icon('external-link')
- in your Mattermost team with the options listed below.
+ - create_slash_commands_link_url = help_page_url('user/project/integrations/mattermost_slash_commands', anchor: 'create-a-slash-command-in-mattermost')
+ - create_slash_commands_link = link_to '', create_slash_commands_link_url, target: '_blank', rel: 'noopener noreferrer'
+ = safe_format(s_('MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below.'), tag_pair(create_slash_commands_link, :link_start, :link_end), icon: external_link_icon)
%li
- 3. Paste the token into the
- %strong Token
- field.
+ = safe_format(s_('MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field.'), tag_pair(tag.strong, :strong_start, :strong_end))
%li
- 4. Select the
- %strong Active
- check box, then select
- %strong Save changes
- to start using GitLab inside Mattermost!
+ = safe_format(s_('MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!'), tag_pair(tag.strong, :strong_start, :strong_end))
%hr
@@ -34,14 +25,14 @@
.col-12.input-group
= text_field_tag :display_name, "GitLab / #{pretty_name}".html_safe, class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#display_name', class: 'gl-button btn-default btn-icon input-group-text')
+ = clipboard_button(target: '#display_name', category: :primary, size: :medium)
.form-group
= label_tag :description, _('Description'), class: 'col-12 col-form-label label-bold'
.col-12.input-group
= text_field_tag :description, run_actions_text, class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#description', class: 'gl-button btn-default btn-icon input-group-text')
+ = clipboard_button(target: '#description', category: :primary, size: :medium)
.form-group
= label_tag nil, s_('MattermostService|Command trigger word'), class: 'col-12 col-form-label label-bold'
@@ -59,7 +50,7 @@
.col-12.input-group
= text_field_tag :request_url, service_trigger_url(integration), class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#request_url', class: 'gl-button btn-default btn-icon input-group-text')
+ = clipboard_button(target: '#request_url', category: :primary, size: :medium)
.form-group
= label_tag nil, s_('MattermostService|Request method'), class: 'col-12 col-form-label label-bold'
@@ -70,14 +61,14 @@
.col-12.input-group
= text_field_tag :response_username, 'GitLab', class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#response_username', class: 'gl-button btn-default btn-icon input-group-text')
+ = clipboard_button(target: '#response_username', category: :primary, size: :medium)
.form-group
= label_tag :response_icon, s_('MattermostService|Response icon'), class: 'col-12 col-form-label label-bold'
.col-12.input-group
= text_field_tag :response_icon, asset_url('gitlab_logo.png'), class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#response_icon', class: 'gl-button btn-default btn-icon input-group-text')
+ = clipboard_button(target: '#response_icon', category: :primary, size: :medium)
.form-group
= label_tag nil, _('Autocomplete'), class: 'col-12 col-form-label label-bold'
@@ -88,11 +79,11 @@
.col-12.input-group
= text_field_tag :autocomplete_hint, '[help]', class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#autocomplete_hint', class: 'gl-button btn-default btn-icon input-group-text')
+ = clipboard_button(target: '#autocomplete_hint', category: :primary, size: :medium)
.form-group
= label_tag :autocomplete_description, _('Autocomplete description'), class: 'col-12 col-form-label label-bold'
.col-12.input-group
= text_field_tag :autocomplete_description, run_actions_text, class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#autocomplete_description', class: 'gl-button btn-default btn-icon input-group-text')
+ = clipboard_button(target: '#autocomplete_description', category: :primary, size: :medium)
diff --git a/app/views/shared/integrations/mattermost_slash_commands/_installation_info.html.haml b/app/views/shared/integrations/mattermost_slash_commands/_installation_info.html.haml
index 38adc69dd5e..ac14e1a6cd7 100644
--- a/app/views/shared/integrations/mattermost_slash_commands/_installation_info.html.haml
+++ b/app/views/shared/integrations/mattermost_slash_commands/_installation_info.html.haml
@@ -1,7 +1,5 @@
.services-installation-info
- unless integration.activated?
- .row
- .col-sm-9.offset-sm-3
- = link_to new_project_mattermost_path(@project), class: 'btn gl-button btn-lg' do
- = custom_icon('mattermost_logo', size: 15)
- = s_("MattermostService|Add to Mattermost")
+ = render Pajamas::ButtonComponent.new(href: new_project_mattermost_path(@project), button_text_classes: 'gl-display-flex gl-gap-2') do
+ = custom_icon('mattermost_logo')
+ = s_("MattermostService|Add to Mattermost")
diff --git a/app/views/shared/integrations/prometheus/_custom_metrics.html.haml b/app/views/shared/integrations/prometheus/_custom_metrics.html.haml
index a7a650aa95d..080d4b37354 100644
--- a/app/views/shared/integrations/prometheus/_custom_metrics.html.haml
+++ b/app/views/shared/integrations/prometheus/_custom_metrics.html.haml
@@ -3,7 +3,6 @@
.col-lg-3
%p
= s_('PrometheusService|Custom metrics require Prometheus installed on a cluster with environment scope "*" OR a manually configured Prometheus to be available.')
- = link_to s_('PrometheusService|More information'), help_page_path('operations/metrics/index.md'), target: '_blank', rel: "noopener noreferrer"
.col-lg-9
= render Pajamas::CardComponent.new(header_options: { class: 'gl-display-flex gl-align-items-center' }, body_options: { class: 'gl-p-0' }, card_options: { class: 'gl-mb-5 custom-monitored-metrics js-panel-custom-monitored-metrics', data: { active_custom_metrics: project_prometheus_metrics_path(project), environments_data: environments_list_data, service_active: "#{integration.active}" } }) do |c|
diff --git a/app/views/shared/integrations/prometheus/_metrics.html.haml b/app/views/shared/integrations/prometheus/_metrics.html.haml
index cb78faa383a..36e4c0d4b13 100644
--- a/app/views/shared/integrations/prometheus/_metrics.html.haml
+++ b/app/views/shared/integrations/prometheus/_metrics.html.haml
@@ -5,10 +5,9 @@
.col-lg-3
%p
= s_('PrometheusService|Common metrics are automatically monitored based on a library of metrics from popular exporters.')
- = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus'), target: '_blank', rel: "noopener noreferrer"
.col-lg-9
- = render Pajamas::CardComponent.new(body_options: { class: 'gl-p-0' }, card_options: { class: 'gl-mb-5 js-panel-monitored-metrics', data: { active_metrics: active_common_project_prometheus_metrics_path(project, :json), metrics_help_path: help_page_path('user/project/integrations/prometheus_library/index') }}) do |c|
+ = render Pajamas::CardComponent.new(body_options: { class: 'gl-p-0' }, card_options: { class: 'gl-mb-5 js-panel-monitored-metrics', data: { active_metrics: active_common_project_prometheus_metrics_path(project, :json) }}) do |c|
- c.with_header do
%strong
= s_('PrometheusService|Common metrics')
@@ -34,5 +33,4 @@
.flash-notice
.flash-text
= html_escape(s_("PrometheusService|To set up automatic monitoring, add the environment variable %{variable} to exporter's queries.")) % { variable: "<code>$CI_ENVIRONMENT_SLUG</code>".html_safe }
- = link_to s_('PrometheusService|More information'), help_page_path('operations/metrics/index.md')
%ul.list-unstyled.metrics-list.js-missing-var-metrics-list
diff --git a/app/views/shared/integrations/slack_slash_commands/_help.html.haml b/app/views/shared/integrations/slack_slash_commands/_help.html.haml
index 43a240fa6fe..defaf50efea 100644
--- a/app/views/shared/integrations/slack_slash_commands/_help.html.haml
+++ b/app/views/shared/integrations/slack_slash_commands/_help.html.haml
@@ -40,7 +40,7 @@
.col-12.input-group
= text_field_tag :url, service_trigger_url(integration), class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#url', class: 'input-group-text')
+ = deprecated_clipboard_button(target: '#url', class: 'input-group-text')
.form-group
= label_tag nil, _('Method'), class: 'col-12 col-form-label label-bold'
@@ -51,7 +51,7 @@
.col-12.input-group
= text_field_tag :customize_name, 'GitLab', class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#customize_name', class: 'input-group-text')
+ = deprecated_clipboard_button(target: '#customize_name', class: 'input-group-text')
.form-group
= label_tag nil, _('Customize icon'), class: 'col-12 col-form-label label-bold'
@@ -68,21 +68,21 @@
.col-12.input-group
= text_field_tag :autocomplete_description, run_actions_text.html_safe, class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#autocomplete_description', class: 'input-group-text')
+ = deprecated_clipboard_button(target: '#autocomplete_description', class: 'input-group-text')
.form-group
= label_tag :autocomplete_usage_hint, _('Autocomplete usage hint'), class: 'col-12 col-form-label label-bold'
.col-12.input-group
= text_field_tag :autocomplete_usage_hint, '[help]', class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#autocomplete_usage_hint', class: 'input-group-text')
+ = deprecated_clipboard_button(target: '#autocomplete_usage_hint', class: 'input-group-text')
.form-group
= label_tag :descriptive_label, _('Descriptive label'), class: 'col-12 col-form-label label-bold'
.col-12.input-group
= text_field_tag :descriptive_label, _('Perform common operations on GitLab project'), class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
- = clipboard_button(target: '#descriptive_label', class: 'input-group-text')
+ = deprecated_clipboard_button(target: '#descriptive_label', class: 'input-group-text')
%hr
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 42f035b99aa..f8d07a2f6de 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -51,12 +51,11 @@
.gl-mt-5{ class: (is_footer ? "footer-block" : "middle-block") }
- if !issuable.persisted? && !issuable.project.empty_repo? && (guide_url = issuable.project.present.contribution_guide_path)
.gl-mb-5
- - contribution_guidelines_start = '<strong><a href="%{url}">'.html_safe % {url: strip_tags(guide_url)}
- - contribution_guidelines_end = '</a></strong>'.html_safe
- = sanitize(html_escape(_('Please review the %{linkStart}contribution guidelines%{linkEnd} for this project.')) % { linkStart: contribution_guidelines_start, linkEnd: contribution_guidelines_end })
+ - contribution_guidelines = link_to('', strip_tags(guide_url))
+ = safe_format(_('Please review the %{strong_start}%{contribution_guidelines_start}contribution guidelines%{contribution_guidelines_end}%{strong_end} for this project.'), tag_pair('<strong></strong>'.html_safe, :strong_start, :strong_end), tag_pair(contribution_guidelines, :contribution_guidelines_start, :contribution_guidelines_end))
- if issuable.new_record?
- = form.submit "#{_('Create')} #{issuable.class.model_name.human.downcase}", pajamas_button: true, class: 'gl-mr-2 js-issuable-submit-button js-reset-autosave', data: { qa_selector: 'issuable_create_button', track_action: 'click_button', track_label: 'submit_mr', track_value: 0 }
+ = form.submit "#{_('Create')} #{issuable.class.model_name.human.downcase}", pajamas_button: true, class: 'gl-mr-2 js-issuable-submit-button js-reset-autosave', data: { testid: 'issuable-create-button', track_action: 'click_button', track_label: 'submit_mr', track_value: 0 }
- else
= form.submit _('Save changes'), pajamas_button: true, class: 'gl-mr-2 js-issuable-submit-button js-reset-autosave', data: { track_action: 'click_button', track_label: 'submit_mr', track_value: 0 }
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index d590c859945..86aaa5128a8 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -1,7 +1,7 @@
- type = local_assigns.fetch(:type)
- show_sorting_dropdown = local_assigns.fetch(:show_sorting_dropdown, true)
- disable_target_branch = local_assigns.fetch(:disable_target_branch, false)
-- placeholder = local_assigns[:placeholder] || _('Search or filter results...')
+- placeholder = local_assigns[:placeholder] || _('Search or filter results…')
- block_css_class = type != :productivity_analytics ? 'row-content-block second-block' : ''
.issues-filters
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 46710081307..93e1a53ccb4 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -46,7 +46,7 @@
.js-sidebar-milestone-widget-root{ data: { can_edit: can_edit_issuable.to_s, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid] } }
- if in_group_context_with_iterations
- .block.gl-collapse-empty{ data: { testid: 'iteration_container' } }<
+ .block.gl-collapse-empty{ data: { testid: 'iteration-container' } }<
= render_if_exists 'shared/issuable/iteration_select', can_edit: can_edit_issuable.to_s, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type
- if issuable_sidebar[:show_crm_contacts]
@@ -88,11 +88,11 @@
- if is_merge_request && !moved_sidebar_enabled
.sub-block.js-sidebar-source-branch
.sidebar-collapsed-icon.js-dont-change-state
- = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport', class: 'btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm js-source-branch-copy')
+ = deprecated_clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport', class: 'btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm js-source-branch-copy')
.gl-display-flex.gl-align-items-center.gl-justify-content-space-between.gl-mb-2.hide-collapsed
%span.gl-overflow-hidden.gl-text-overflow-ellipsis.gl-white-space-nowrap
= _('Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}').html_safe % { source_branch_open: "<span class='gl-font-monospace' data-testid='ref-name' title='#{html_escape(source_branch)}'>".html_safe, source_branch_close: "</span>".html_safe, source_branch: html_escape(source_branch) }
- = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport', class: 'btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm js-source-branch-copy')
+ = deprecated_clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport', class: 'btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm js-source-branch-copy')
- if show_forwarding_email && !moved_sidebar_enabled
.block
diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml
index a27bb506c87..0ffce0ac571 100644
--- a/app/views/shared/issuable/_sidebar_assignees.html.haml
+++ b/app/views/shared/issuable/_sidebar_assignees.html.haml
@@ -45,4 +45,4 @@
options: options,
wrapper_class: 'js-sidebar-assignee-dropdown',
track_label: 'edit_assignee',
- trigger_source: "#{issuable_type}-assignee-dropdown"
+ trigger_source: "#{issuable_type}_assignee_dropdown"
diff --git a/app/views/shared/issuable/_sidebar_reviewers.html.haml b/app/views/shared/issuable/_sidebar_reviewers.html.haml
index b360fac0a55..4b07d8d0850 100644
--- a/app/views/shared/issuable/_sidebar_reviewers.html.haml
+++ b/app/views/shared/issuable/_sidebar_reviewers.html.haml
@@ -42,4 +42,4 @@
options: options,
wrapper_class: 'js-sidebar-reviewer-dropdown',
track_label: 'edit_reviewer',
- trigger_source: "#{issuable_type}-reviewer-dropdown"
+ trigger_source: "#{issuable_type}_reviewer_dropdown"
diff --git a/app/views/shared/issuable/_status_box.html.haml b/app/views/shared/issuable/_status_box.html.haml
index cca51b48322..f2e4e22788a 100644
--- a/app/views/shared/issuable/_status_box.html.haml
+++ b/app/views/shared/issuable/_status_box.html.haml
@@ -1,8 +1,7 @@
- badge_text = state_name_with_icon(issuable)[0]
- badge_icon = state_name_with_icon(issuable)[1]
- badge_variant = issuable.open? ? :success : issuable.merged? ? :info : :danger
-- badge_status_class = issuable.open? ? 'issuable-status-badge-open' : issuable.merged? ? 'issuable-status-badge-merged' : 'issuable-status-badge-closed'
-- badge_classes = "js-mr-status-box issuable-status-badge gl-mr-3 gl-align-self-center #{badge_status_class} #{'gl-vertical-align-bottom' if issuable.is_a?(MergeRequest)}"
+- badge_classes = "js-mr-status-box gl-mr-3 gl-align-self-center"
= gl_badge_tag({ variant: badge_variant, icon: badge_icon, icon_classes: 'gl-mr-0!' }, { class: badge_classes, data: { project_path: issuable.project.path_with_namespace, iid: issuable.iid, issuable_type: 'merge_request', state: issuable.state } }) do
%span.gl-display-none.gl-sm-display-block.gl-ml-2
diff --git a/app/views/shared/issuable/form/_default_templates.html.haml b/app/views/shared/issuable/form/_default_templates.html.haml
index 2dda0049c09..be6ca475f5c 100644
--- a/app/views/shared/issuable/form/_default_templates.html.haml
+++ b/app/views/shared/issuable/form/_default_templates.html.haml
@@ -1,5 +1,4 @@
.gl-mt-3.gl-text-secondary
- - template_link_url = help_page_path('user/project/description_templates')
- - template_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: template_link_url }
- = s_('Promotions|Add %{link_start} description templates %{link_end} to help your contributors to communicate effectively!').html_safe % { link_start: template_link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('user/project/description_templates'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(s_('Promotions|Add %{link_start} description templates %{link_end} to help your contributors to communicate effectively!'), tag_pair(link, :link_start, :link_end))
diff --git a/app/views/shared/issuable/form/_title.html.haml b/app/views/shared/issuable/form/_title.html.haml
index 36000f3cc67..242342d365e 100644
--- a/app/views/shared/issuable/form/_title.html.haml
+++ b/app/views/shared/issuable/form/_title.html.haml
@@ -3,7 +3,7 @@
%div{ data: { testid: 'issue-title-input-field' } }
= form.text_field :title, required: true, aria: { required: true }, maxlength: 255, autofocus: true,
- autocomplete: 'off', class: 'form-control pad', dir: 'auto', data: { qa_selector: 'issuable_form_title_field' }
+ autocomplete: 'off', class: 'form-control pad', dir: 'auto', data: { testid: 'issuable-form-title-field' }
- if issuable.respond_to?(:draft?)
.gl-pt-3
diff --git a/app/views/shared/issue_type/_details_content.html.haml b/app/views/shared/issue_type/_details_content.html.haml
deleted file mode 100644
index 249e296b41a..00000000000
--- a/app/views/shared/issue_type/_details_content.html.haml
+++ /dev/null
@@ -1,46 +0,0 @@
-- related_branches_path = related_branches_project_issue_path(@project, issuable)
-- api_awards_path = local_assigns.fetch(:api_awards_path, nil)
-
-.issue-details.issuable-details.js-issue-details
- .detail-page-description.content-block.js-detail-page-description.gl-pt-3.gl-pb-0.gl-border-none
- #js-issuable-app{ data: { initial: issuable_initial_data(issuable).to_json,
- header_actions_data: issue_header_actions_data(@project, issuable, current_user, @issuable_sidebar).to_json,
- issuable_id: issuable.id,
- full_path: @project.full_path,
- register_path: new_user_registration_path(redirect_to_referer: 'yes'),
- sign_in_path: new_session_path(:user, redirect_to_referer: 'yes') } }
- .title-container
- %h1.title.page-title.gl-font-size-h-display= markdown_field(issuable, :title)
- - if issuable.description.present?
- .description
- .md= markdown_field(issuable, :description)
-
- = edited_time_ago_with_tooltip(issuable, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago')
-
- .js-issue-widgets
- = render 'shared/issue_type/emoji_block', issuable: issuable, api_awards_path: api_awards_path
-
- .js-issue-widgets
- = render 'shared/issue_type/sentry_stack_trace', issuable: issuable
-
- = render 'projects/issues/design_management'
-
- = render_if_exists 'projects/issues/work_item_links'
- = render_if_exists 'projects/issues/linked_resources'
- = render 'projects/issues/related_issues'
-
- #js-related-merge-requests{ data: { endpoint: expose_path(api_v4_projects_issues_related_merge_requests_path(id: @project.id, issue_iid: issuable.iid)), project_namespace: @project.namespace.path, project_path: @project.path } }
-
- - if can?(current_user, :read_code, @project)
- - add_page_startup_api_call related_branches_path
- #related-branches{ data: { url: related_branches_path } }
- -# This element is filled in using JavaScript.
-
- - if can?(current_user, :admin_feature_flags_issue_links, @project)
- = render_if_exists 'projects/issues/related_feature_flags'
-
- .js-issue-widgets
-
- = render 'projects/issues/discussion'
-
-= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @issue.assignees
diff --git a/app/views/shared/issue_type/_details_header.html.haml b/app/views/shared/issue_type/_details_header.html.haml
deleted file mode 100644
index 558287480e1..00000000000
--- a/app/views/shared/issue_type/_details_header.html.haml
+++ /dev/null
@@ -1,21 +0,0 @@
-- link = issue_closed_link(@issue, current_user, css_class: 'text-underline gl-reset-color!')
-- badge_classes = 'issuable-status-badge gl-mr-3'
-
-.detail-page-header
- .detail-page-header-body.gl-flex-wrap
- = gl_badge_tag({ variant: :info, icon: 'issue-closed', icon_classes: 'gl-mr-0!' }, { class: "#{issue_status_visibility(issuable, status_box: :closed)} #{badge_classes} issuable-status-badge-closed" }) do
- .gl-display-none.gl-sm-display-block.gl-ml-2
- = issue_closed_text(issuable, current_user)
- - if link
- %span.gl-pl-2.gl-sm-display-none
- = "(#{link})"
- = gl_badge_tag({ variant: :success, icon: 'issues', icon_classes: 'gl-mr-0!' }, { class: "#{issue_status_visibility(issuable, status_box: :open)} #{badge_classes} issuable-status-badge-open" }) do
- %span.gl-display-none.gl-sm-display-block.gl-ml-2
- = _('Open')
-
- #js-issuable-header-warnings{ data: { hidden: issue_hidden?(issuable).to_s } }
- = issuable_meta(issuable, @project)
-
- = render Pajamas::ButtonComponent.new(href: '#', icon: 'chevron-double-lg-left', button_options: { class: 'gl-ml-auto gl-display-block gl-sm-display-none! js-sidebar-toggle' })
-
- .js-issue-header-actions{ data: issue_header_actions_data(@project, issuable, current_user, @issuable_sidebar) }
diff --git a/app/views/shared/labels/_form.html.haml b/app/views/shared/labels/_form.html.haml
index 899b2ed832e..53fbe3dac03 100644
--- a/app/views/shared/labels/_form.html.haml
+++ b/app/views/shared/labels/_form.html.haml
@@ -1,3 +1,5 @@
+- show_lock_on_merge = local_assigns.fetch(:show_lock_on_merge, false)
+
= gitlab_ui_form_for @label, as: :label, url: url, html: { class: 'label-form js-quick-submit js-requires-input' } do |f|
= form_errors(@label)
@@ -21,6 +23,13 @@
.form-text.text-muted
= _('Select a color from the color picker or from the presets below.')
= render_suggested_colors
+ - if show_lock_on_merge
+ .form-group.row
+ .col-12
+ = f.gitlab_ui_checkbox_component :lock_on_merge,
+ _('Lock label after a merge request is merged'),
+ help_text: label_lock_on_merge_help_text,
+ checkbox_options: { disabled: @label.lock_on_merge }
.gl-display-flex.gl-justify-content-space-between
%div
- if @label.persisted?
diff --git a/app/views/shared/members/_access_request_links.html.haml b/app/views/shared/members/_access_request_links.html.haml
index 94086636d5a..0d692ee753a 100644
--- a/app/views/shared/members/_access_request_links.html.haml
+++ b/app/views/shared/members/_access_request_links.html.haml
@@ -15,4 +15,4 @@
- elsif source.request_access_enabled && can?(current_user, :request_access, source)
= link_to _('Request Access'), polymorphic_path([:request_access, source, :members]),
method: :post,
- data: { qa_selector: 'request_access_link' }
+ data: { testid: 'request-access-link' }
diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml
index 1b0eeb424c2..9387d8d3ad1 100644
--- a/app/views/shared/milestones/_sidebar.html.haml
+++ b/app/views/shared/milestones/_sidebar.html.haml
@@ -162,10 +162,10 @@
- if milestone_ref.present?
.block.reference
.sidebar-collapsed-icon.js-dont-change-state
- = clipboard_button(text: milestone_ref, title: s_('MilestoneSidebar|Copy reference'), placement: "left", boundary: 'viewport')
+ = deprecated_clipboard_button(text: milestone_ref, title: s_('MilestoneSidebar|Copy reference'), placement: "left", boundary: 'viewport')
.gl-display-flex.gl-align-items-center.gl-justify-content-space-between.gl-mb-2.hide-collapsed
%span.gl-overflow-hidden.gl-text-overflow-ellipsis.gl-white-space-nowrap
= s_('MilestoneSidebar|Reference:')
%span{ title: milestone_ref }
= milestone_ref
- = clipboard_button(text: milestone_ref, title: s_('MilestoneSidebar|Copy reference'), placement: "left", boundary: 'viewport')
+ = deprecated_clipboard_button(text: milestone_ref, title: s_('MilestoneSidebar|Copy reference'), placement: "left", boundary: 'viewport')
diff --git a/app/views/shared/packages/_no_packages.html.haml b/app/views/shared/packages/_no_packages.html.haml
index 7cc8110fb6b..9f165a198d6 100644
--- a/app/views/shared/packages/_no_packages.html.haml
+++ b/app/views/shared/packages/_no_packages.html.haml
@@ -3,6 +3,5 @@
.text-content
%h4.text-center= _('There are no packages yet')
%p
- - no_packages_url = help_page_path('administration/packages/index')
- - no_packages_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: no_packages_url }
- = _('Learn how to %{no_packages_link_start}publish and share your packages%{no_packages_link_end} with GitLab.').html_safe % { no_packages_link_start: no_packages_link_start, no_packages_link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path('administration/packages/index'), target: '_blank', rel: 'noopener noreferrer')
+ = safe_format(_('Learn how to %{no_packages_link_start}publish and share your packages%{no_packages_link_end} with GitLab.'), tag_pair(link, :no_packages_link_start, :no_packages_link_end))
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index 95188cefdd1..ac5e65747d5 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -26,8 +26,8 @@
.project-cell{ class: css_class }
.project-details.gl-pr-9.gl-sm-pr-0.gl-w-full.gl-display-flex.gl-flex-direction-column{ data: { qa_selector: 'project_content', qa_project_name: project.name } }
.gl-display-flex.gl-align-items-center.gl-flex-wrap
- %h2.gl-font-base.gl-line-height-20.gl-my-0
- = link_to project_path(project), class: 'text-plain gl-mr-3 js-prefetch-document' do
+ %h2.gl-font-base.gl-line-height-20.gl-my-0.gl-overflow-wrap-anywhere
+ = link_to project_path(project), class: 'text-plain gl-mr-3 js-prefetch-document', title: project.name do
%span.namespace-name.gl-font-weight-normal
- if project.namespace && !skip_namespace
= project.namespace.human_name
diff --git a/app/views/shared/web_hooks/_hook_errors.html.haml b/app/views/shared/web_hooks/_hook_errors.html.haml
index 0e5f6d844cd..bac2f1d7cb0 100644
--- a/app/views/shared/web_hooks/_hook_errors.html.haml
+++ b/app/views/shared/web_hooks/_hook_errors.html.haml
@@ -1,8 +1,5 @@
-- strong_start = '<strong>'.html_safe
-- strong_end = '</strong>'.html_safe
-- link_start = '<a href="%{url}">'.html_safe
-- link_end = '</a>'.html_safe
-
+- strong = { strong_start: '<strong>'.html_safe,
+ strong_end: '</strong>'.html_safe }
- if hook.rate_limited?
- placeholders = { limit: number_with_delimiter(hook.rate_limit),
root_namespace: hook.parent.root_namespace.path }
@@ -14,15 +11,11 @@
= render Pajamas::AlertComponent.new(title: s_('Webhooks|Webhook failed to connect'),
variant: :danger) do |c|
- c.with_body do
- = s_('Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below.').html_safe % { strong_start: strong_start, strong_end: strong_end }
+ = safe_format(s_('Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below.'), strong)
- elsif hook.temporarily_disabled?
- - help_path = help_page_path('user/project/integrations/webhooks', anchor: 'webhook-fails-or-multiple-webhook-requests-are-triggered')
- - placeholders = { strong_start: strong_start,
- strong_end: strong_end,
- retry_time: time_interval_in_words(hook.disabled_until - Time.now),
- help_link_start: link_start % { url: help_path },
- help_link_end: link_end }
+ - help_link = link_to('', help_page_path('user/project/integrations/webhooks', anchor: 'webhook-fails-or-multiple-webhook-requests-are-triggered'), target: '_blank', rel: 'noopener noreferrer')
+ - retry_time = { retry_time: time_interval_in_words(hook.disabled_until - Time.now) }
= render Pajamas::AlertComponent.new(title: s_('Webhooks|Webhook fails to connect'),
variant: :warning) do |c|
- c.with_body do
- = s_('Webhooks|The webhook %{help_link_start}failed to connect%{help_link_end}, and will retry in %{retry_time}. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below.').html_safe % placeholders
+ = safe_format(s_('Webhooks|The webhook %{help_link_start}failed to connect%{help_link_end}, and will retry in %{retry_time}. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below.'), retry_time, strong, tag_pair(help_link, :help_link_start, :help_link_end))
diff --git a/app/views/shared/web_hooks/_title_and_docs.html.haml b/app/views/shared/web_hooks/_title_and_docs.html.haml
index ae32dcea7cb..8ff41b6a1ca 100644
--- a/app/views/shared/web_hooks/_title_and_docs.html.haml
+++ b/app/views/shared/web_hooks/_title_and_docs.html.haml
@@ -1,4 +1,4 @@
-- webhooks_link_start = '<a href="%{url}">'.html_safe % { url: help_page_path(hook.help_path) }
+- webhooks_link = tag_pair(link_to('', help_page_path(hook.help_path), target: '_blank', rel: 'noopener noreferrer'), :webhooks_link_start, :webhooks_link_end)
.settings-sticky-header
.settings-sticky-header-inner
@@ -6,7 +6,7 @@
= page_title
- if @project
- - integrations_link_start = '<a href="%{url}">'.html_safe % { url: scoped_integrations_path(project: @project) }
- %p.gl-text-secondary= _("%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook.").html_safe % { webhooks_link_start: webhooks_link_start, webhook_type: hook.pluralized_name, integrations_link_start: integrations_link_start, link_end: '</a>'.html_safe }
+ - integrations_link = tag_pair(link_to('', scoped_integrations_path(project: @project)), :integrations_link_start, :integrations_link_end)
+ %p.gl-text-secondary= safe_format(_("%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."), webhooks_link, integrations_link, webhook_type: hook.pluralized_name)
- else
- %p.gl-text-secondary= _("%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project.").html_safe % { webhooks_link_start: webhooks_link_start, webhook_type: hook.pluralized_name, link_end: '</a>'.html_safe }
+ %p.gl-text-secondary= safe_format(_("%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."), webhooks_link, webhook_type: hook.pluralized_name)
diff --git a/app/views/users/_deletion_guidance.html.haml b/app/views/users/_deletion_guidance.html.haml
index 507fe126acb..64b4a8e1ae2 100644
--- a/app/views/users/_deletion_guidance.html.haml
+++ b/app/views/users/_deletion_guidance.html.haml
@@ -3,8 +3,8 @@
%ul
%li
%p
- - link_start = '<a href="%{url}">'.html_safe % { url: help_page_path("user/profile/account/delete_account", anchor: "associated-records") }
- = _('Certain user content will be moved to a system-wide "Ghost User" in order to maintain content for posterity. For further information, please refer to the %{link_start}user account deletion documentation.%{link_end}').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ - link = link_to('', help_page_path("user/profile/account/delete_account", anchor: "associated-records"))
+ = safe_format(_('Certain user content will be moved to a system-wide "Ghost User" in order to maintain content for posterity. For further information, please refer to the %{link_start}user account deletion documentation.%{link_end}'), tag_pair(link, :link_start, :link_end))
- personal_projects_count = user.personal_projects.count
- unless personal_projects_count == 0
%li
diff --git a/app/views/users/_profile_basic_info.html.haml b/app/views/users/_profile_basic_info.html.haml
index 6de9e80008e..fb9721028d5 100644
--- a/app/views/users/_profile_basic_info.html.haml
+++ b/app/views/users/_profile_basic_info.html.haml
@@ -5,6 +5,6 @@
- unless Feature.enabled?(:user_profile_overflow_menu_vue)
= render 'middle_dot_divider', stacking: true do
= s_('UserProfile|User ID: %{id}') % { id: @user.id }
- = clipboard_button(title: s_('UserProfile|Copy user ID'), text: @user.id)
+ = deprecated_clipboard_button(title: s_('UserProfile|Copy user ID'), text: @user.id)
= render 'middle_dot_divider', stacking: true do
= s_('Member since %{date}') % { date: l(@user.created_at.to_date, format: :long) }
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index e2ddbb90213..a2f6b3da746 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -71,7 +71,7 @@
%p.gl-mb-4.gl-text-gray-500= s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation }
- if @user.status&.customized?
- .cover-status.gl-display-inline-flex.gl-align-items-center.gl-mb-3
+ .cover-status.gl-display-inline-flex.gl-align-items-baseline.gl-mb-3
= emoji_icon(@user.status.emoji, class: 'gl-mr-2')
= markdown_field(@user.status, :message)
= render "users/profile_basic_info"
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 60f233b8289..6ef7447b9da 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -570,23 +570,23 @@
:weight: 1
:idempotent: false
:tags: []
-- :name: cronjob:metrics_global_metrics_update
- :worker_name: Metrics::GlobalMetricsUpdateWorker
- :feature_category: :metrics
+- :name: cronjob:merge_requests_ensure_prepared
+ :worker_name: MergeRequests::EnsurePreparedWorker
+ :feature_category: :code_review_workflow
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:tags: []
-- :name: cronjob:namespaces_in_product_marketing_emails
- :worker_name: Namespaces::InProductMarketingEmailsWorker
- :feature_category: :experimentation_activation
+- :name: cronjob:metrics_global_metrics_update
+ :worker_name: Metrics::GlobalMetricsUpdateWorker
+ :feature_category: :metrics
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent: false
+ :idempotent: true
:tags: []
- :name: cronjob:namespaces_prune_aggregation_schedules
:worker_name: Namespaces::PruneAggregationSchedulesWorker
@@ -2343,6 +2343,51 @@
:weight: 1
:idempotent: true
:tags: []
+- :name: bitbucket_import_advance_stage
+ :worker_name: Gitlab::BitbucketImport::AdvanceStageWorker
+ :feature_category: :importers
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
+- :name: bitbucket_import_import_pull_request
+ :worker_name: Gitlab::BitbucketImport::ImportPullRequestWorker
+ :feature_category: :importers
+ :has_external_dependencies: true
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
+- :name: bitbucket_import_stage_finish_import
+ :worker_name: Gitlab::BitbucketImport::Stage::FinishImportWorker
+ :feature_category: :importers
+ :has_external_dependencies: true
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
+- :name: bitbucket_import_stage_import_pull_requests
+ :worker_name: Gitlab::BitbucketImport::Stage::ImportPullRequestsWorker
+ :feature_category: :importers
+ :has_external_dependencies: true
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
+- :name: bitbucket_import_stage_import_repository
+ :worker_name: Gitlab::BitbucketImport::Stage::ImportRepositoryWorker
+ :feature_category: :importers
+ :has_external_dependencies: true
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
- :name: bitbucket_server_import_advance_stage
:worker_name: Gitlab::BitbucketServerImport::AdvanceStageWorker
:feature_category: :importers
@@ -2469,6 +2514,15 @@
:weight: 1
:idempotent: true
:tags: []
+- :name: bulk_imports_finish_project_import
+ :worker_name: BulkImports::FinishProjectImportWorker
+ :feature_category: :importers
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: bulk_imports_pipeline
:worker_name: BulkImports::PipelineWorker
:feature_category: :importers
@@ -2613,6 +2667,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: database_lock_tables
+ :worker_name: Database::LockTablesWorker
+ :feature_category: :cell
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: default
:worker_name:
:feature_category: :not_owned
@@ -3306,15 +3369,6 @@
:weight: 1
:idempotent: false
:tags: []
-- :name: pages_invalidate_domain_cache
- :worker_name: Pages::InvalidateDomainCacheWorker
- :feature_category: :pages
- :has_external_dependencies: false
- :urgency: :low
- :resource_boundary: :unknown
- :weight: 1
- :idempotent: true
- :tags: []
- :name: post_receive
:worker_name: PostReceive
:feature_category: :source_code_management
@@ -3470,7 +3524,7 @@
:tags: []
- :name: projects_record_target_platforms
:worker_name: Projects::RecordTargetPlatformsWorker
- :feature_category: :groups_and_projects
+ :feature_category: :experimentation_activation
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -3729,6 +3783,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: users_track_namespace_visits
+ :worker_name: Users::TrackNamespaceVisitsWorker
+ :feature_category: :navigation
+ :has_external_dependencies: false
+ :urgency: :throttled
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: web_hook
:worker_name: WebHookWorker
:feature_category: :webhooks
diff --git a/app/workers/background_migration/single_database_worker.rb b/app/workers/background_migration/single_database_worker.rb
index 2f797a24468..56800c03bbb 100644
--- a/app/workers/background_migration/single_database_worker.rb
+++ b/app/workers/background_migration/single_database_worker.rb
@@ -45,7 +45,10 @@ module BackgroundMigration
# lease on the class before giving up. See MR for more discussion.
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45298#note_434304956
def perform(class_name, arguments = [], lease_attempts = MAX_LEASE_ATTEMPTS)
- unless Feature.enabled?(:execute_background_migrations, type: :ops)
+ should_skip = Feature.enabled?(:disallow_database_ddl_feature_flags, type: :ops) ||
+ Feature.disabled?(:execute_background_migrations, type: :ops)
+
+ if should_skip
# Delay execution of background migrations
self.class.perform_in(BACKGROUND_MIGRATIONS_DELAY, class_name, arguments, lease_attempts)
diff --git a/app/workers/build_success_worker.rb b/app/workers/build_success_worker.rb
index f5baa220715..b937dbf298a 100644
--- a/app/workers/build_success_worker.rb
+++ b/app/workers/build_success_worker.rb
@@ -13,15 +13,5 @@ class BuildSuccessWorker # rubocop:disable Scalability/IdempotentWorker
queue_namespace :pipeline_processing
urgency :high
- def perform(build_id)
- Ci::Build.find_by_id(build_id).try do |build|
- stop_environment(build) if build.stops_environment? && build.stop_action_successful?
- end
- end
-
- private
-
- def stop_environment(build)
- build.persisted_environment.fire_state_event(:stop_complete)
- end
+ def perform(build_id); end
end
diff --git a/app/workers/bulk_import_worker.rb b/app/workers/bulk_import_worker.rb
index 6bce13c5ff0..83b881ee525 100644
--- a/app/workers/bulk_import_worker.rb
+++ b/app/workers/bulk_import_worker.rb
@@ -22,7 +22,7 @@ class BulkImportWorker # rubocop:disable Scalability/IdempotentWorker
@bulk_import.start! if @bulk_import.created?
created_entities.first(next_batch_size).each do |entity|
- BulkImports::CreatePipelineTrackersService.new(entity).execute!
+ create_tracker(entity)
entity.start!
@@ -51,7 +51,7 @@ class BulkImportWorker # rubocop:disable Scalability/IdempotentWorker
end
def all_entities_failed?
- entities.all? { |entity| entity.failed? }
+ entities.all?(&:failed?)
end
# A new BulkImportWorker job is enqueued to either
@@ -72,4 +72,55 @@ class BulkImportWorker # rubocop:disable Scalability/IdempotentWorker
def next_batch_size
[DEFAULT_BATCH_SIZE - started_entities.count, 0].max
end
+
+ def create_tracker(entity)
+ entity.class.transaction do
+ entity.pipelines.each do |pipeline|
+ status = skip_pipeline?(pipeline, entity) ? :skipped : :created
+
+ entity.trackers.create!(
+ stage: pipeline[:stage],
+ pipeline_name: pipeline[:pipeline],
+ status: BulkImports::Tracker.state_machine.states[status].value
+ )
+ end
+ end
+ end
+
+ def skip_pipeline?(pipeline, entity)
+ return false unless entity.source_version.valid?
+
+ minimum_version, maximum_version = pipeline.values_at(:minimum_source_version, :maximum_source_version)
+
+ if source_version_out_of_range?(minimum_version, maximum_version, entity.source_version.without_patch)
+ log_skipped_pipeline(pipeline, entity, minimum_version, maximum_version)
+ return true
+ end
+
+ false
+ end
+
+ def source_version_out_of_range?(minimum_version, maximum_version, non_patch_source_version)
+ (minimum_version && non_patch_source_version < Gitlab::VersionInfo.parse(minimum_version)) ||
+ (maximum_version && non_patch_source_version > Gitlab::VersionInfo.parse(maximum_version))
+ end
+
+ def log_skipped_pipeline(pipeline, entity, minimum_version, maximum_version)
+ logger.info(
+ message: 'Pipeline skipped as source instance version not compatible with pipeline',
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
+ pipeline_name: pipeline[:pipeline],
+ minimum_source_version: minimum_version,
+ maximum_source_version: maximum_version,
+ source_version: entity.source_version.to_s,
+ importer: 'gitlab_migration'
+ )
+ end
+
+ def logger
+ @logger ||= Gitlab::Import::Logger.build
+ end
end
diff --git a/app/workers/bulk_imports/finish_project_import_worker.rb b/app/workers/bulk_imports/finish_project_import_worker.rb
new file mode 100644
index 00000000000..815101c89f3
--- /dev/null
+++ b/app/workers/bulk_imports/finish_project_import_worker.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module BulkImports
+ class FinishProjectImportWorker
+ include ApplicationWorker
+
+ feature_category :importers
+ sidekiq_options retry: 5
+ data_consistency :sticky
+
+ idempotent!
+
+ def perform(project_id)
+ project = Project.find_by_id(project_id)
+ return unless project
+
+ project.after_import
+ end
+ end
+end
diff --git a/app/workers/click_house/events_sync_worker.rb b/app/workers/click_house/events_sync_worker.rb
index 054e7763297..5b7398cb071 100644
--- a/app/workers/click_house/events_sync_worker.rb
+++ b/app/workers/click_house/events_sync_worker.rb
@@ -12,6 +12,47 @@ module ClickHouse
# the job is scheduled every 3 minutes and we will allow maximum 2.5 minutes runtime
MAX_TTL = 2.5.minutes.to_i
+ MAX_RUNTIME = 120.seconds
+ BATCH_SIZE = 500
+ INSERT_BATCH_SIZE = 5000
+ CSV_MAPPING = {
+ id: :id,
+ path: :path,
+ author_id: :author_id,
+ target_id: :target_id,
+ target_type: :target_type,
+ action: :raw_action,
+ created_at: :casted_created_at,
+ updated_at: :casted_updated_at
+ }.freeze
+
+ # transforms the traversal_ids to a String:
+ # Example: group_id/subgroup_id/group_or_projectnamespace_id/
+ PATH_COLUMN = <<~SQL
+ (
+ CASE
+ WHEN project_id IS NOT NULL THEN (SELECT array_to_string(traversal_ids, '/') || '/' FROM namespaces WHERE id = (SELECT project_namespace_id FROM projects WHERE id = events.project_id LIMIT 1) LIMIT 1)
+ WHEN group_id IS NOT NULL THEN (SELECT array_to_string(traversal_ids, '/') || '/' FROM namespaces WHERE id = events.group_id LIMIT 1)
+ ELSE ''
+ END
+ ) AS path
+ SQL
+
+ EVENT_PROJECTIONS = [
+ :id,
+ PATH_COLUMN,
+ :author_id,
+ :target_id,
+ :target_type,
+ 'action AS raw_action',
+ 'EXTRACT(epoch FROM created_at) AS casted_created_at',
+ 'EXTRACT(epoch FROM updated_at) AS casted_updated_at'
+ ].freeze
+
+ INSERT_EVENTS_QUERY = <<~SQL.squish
+ INSERT INTO events (#{CSV_MAPPING.keys.join(', ')})
+ SETTINGS async_insert=1, wait_for_async_insert=1 FORMAT CSV
+ SQL
def perform
unless enabled?
@@ -22,12 +63,15 @@ module ClickHouse
metadata = { status: :processed }
- # Prevent parallel jobs
begin
+ # Prevent parallel jobs
in_lock(self.class.to_s, ttl: MAX_TTL, retries: 0) do
- true
- end
+ loop { break unless next_batch }
+
+ metadata.merge!(records_inserted: context.total_record_count, reached_end_of_table: context.no_more_records?)
+ ClickHouse::SyncCursor.update_cursor_for(:events, context.last_processed_id) if context.last_processed_id
+ end
rescue Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError
# Skip retrying, just let the next worker to start after a few minutes
metadata = { status: :skipped }
@@ -38,8 +82,51 @@ module ClickHouse
private
+ def context
+ @context ||= ClickHouse::RecordSyncContext.new(
+ last_record_id: ClickHouse::SyncCursor.cursor_for(:events),
+ max_records_per_batch: INSERT_BATCH_SIZE,
+ runtime_limiter: Analytics::CycleAnalytics::RuntimeLimiter.new(MAX_RUNTIME)
+ )
+ end
+
def enabled?
ClickHouse::Client.configuration.databases[:main].present? && Feature.enabled?(:event_sync_worker_for_click_house)
end
+
+ def next_batch
+ context.new_batch!
+
+ CsvBuilder::Gzip.new(process_batch(context), CSV_MAPPING).render do |tempfile, rows_written|
+ unless rows_written == 0
+ ClickHouse::Client.insert_csv(INSERT_EVENTS_QUERY, File.open(tempfile.path),
+ :main)
+ end
+ end
+
+ !(context.over_time? || context.no_more_records?)
+ end
+
+ def process_batch(context)
+ Enumerator.new do |yielder|
+ has_data = false
+ # rubocop: disable CodeReuse/ActiveRecord
+ Event.where(Event.arel_table[:id].gt(context.last_record_id)).each_batch(of: BATCH_SIZE) do |relation|
+ has_data = true
+
+ relation.select(*EVENT_PROJECTIONS).each do |row|
+ yielder << row
+ context.last_processed_id = row.id
+
+ break if context.record_limit_reached?
+ end
+
+ break if context.over_time? || context.record_limit_reached?
+ end
+
+ context.no_more_records! if has_data == false
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+ end
end
end
diff --git a/app/workers/concerns/gitlab/bitbucket_import/object_importer.rb b/app/workers/concerns/gitlab/bitbucket_import/object_importer.rb
new file mode 100644
index 00000000000..26e6e2675ed
--- /dev/null
+++ b/app/workers/concerns/gitlab/bitbucket_import/object_importer.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ # ObjectImporter defines the base behaviour for every Sidekiq worker that
+ # imports a single resource such as a note or pull request.
+ module ObjectImporter
+ extend ActiveSupport::Concern
+
+ included do
+ include ApplicationWorker
+
+ data_consistency :always
+
+ feature_category :importers
+
+ worker_has_external_dependencies!
+
+ sidekiq_retries_exhausted do |msg|
+ args = msg['args']
+ jid = msg['jid']
+
+ # If a job is being exhausted we still want to notify the
+ # Gitlab::Import::AdvanceStageWorker to prevent the entire import from getting stuck
+ key = args.last
+ JobWaiter.notify(key, jid) if args.length == 3 && key && key.is_a?(String)
+ end
+ end
+
+ def perform(project_id, hash, notify_key)
+ project = Project.find_by_id(project_id)
+
+ return unless project
+
+ if project.import_state&.canceled?
+ info(project.id, message: 'project import canceled')
+ return
+ end
+
+ import(project, hash)
+ ensure
+ notify_waiter(notify_key)
+ end
+
+ private
+
+ # project - An instance of `Project` to import the data into.
+ # hash - A Hash containing the details of the object to import.
+ def import(project, hash)
+ info(project.id, message: 'importer started')
+
+ importer_class.new(project, hash).execute
+
+ info(project.id, message: 'importer finished')
+ rescue ActiveRecord::RecordInvalid => e
+ # We do not raise exception to prevent job retry
+ track_exception(project, e)
+ rescue StandardError => e
+ track_and_raise_exception(project, e)
+ end
+
+ def notify_waiter(key)
+ JobWaiter.notify(key, jid)
+ end
+
+ # Returns the class to use for importing the object.
+ def importer_class
+ raise NotImplementedError
+ end
+
+ def info(project_id, extra = {})
+ Logger.info(log_attributes(project_id, extra))
+ end
+
+ def log_attributes(project_id, extra = {})
+ extra.merge(
+ project_id: project_id,
+ importer: importer_class.name
+ )
+ end
+
+ def track_exception(project, exception, fail_import: false)
+ Gitlab::Import::ImportFailureService.track(
+ project_id: project.id,
+ error_source: importer_class.name,
+ exception: exception,
+ fail_import: fail_import
+ )
+ end
+
+ def track_and_raise_exception(project, exception, fail_import: false)
+ track_exception(project, exception, fail_import: fail_import)
+
+ raise(exception)
+ end
+ end
+ end
+end
diff --git a/app/workers/concerns/gitlab/bitbucket_import/stage_methods.rb b/app/workers/concerns/gitlab/bitbucket_import/stage_methods.rb
new file mode 100644
index 00000000000..2885cc29532
--- /dev/null
+++ b/app/workers/concerns/gitlab/bitbucket_import/stage_methods.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module StageMethods
+ extend ActiveSupport::Concern
+
+ included do
+ include ApplicationWorker
+
+ worker_has_external_dependencies!
+
+ feature_category :importers
+
+ data_consistency :always
+
+ sidekiq_options dead: false, retry: 3
+
+ sidekiq_retries_exhausted do |msg, e|
+ Gitlab::Import::ImportFailureService.track(
+ project_id: msg['args'][0],
+ exception: e,
+ fail_import: true
+ )
+ end
+ end
+
+ # project_id - The ID of the GitLab project to import the data into.
+ def perform(project_id)
+ info(project_id, message: 'starting stage')
+
+ project = find_project(project_id)
+
+ return unless project
+
+ import(project)
+
+ info(project_id, message: 'stage finished')
+ rescue StandardError => e
+ Gitlab::Import::ImportFailureService.track(
+ project_id: project_id,
+ exception: e,
+ error_source: self.class.name,
+ fail_import: abort_on_failure
+ )
+
+ raise(e)
+ end
+
+ def find_project(id)
+ # If the project has been marked as failed we want to bail out
+ # automatically.
+ # rubocop: disable CodeReuse/ActiveRecord
+ Project.joins_import_state.where(import_state: { status: :started }).find_by_id(id)
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+
+ def abort_on_failure
+ false
+ end
+
+ private
+
+ def info(project_id, extra = {})
+ Logger.info(log_attributes(project_id, extra))
+ end
+
+ def log_attributes(project_id, extra = {})
+ extra.merge(
+ project_id: project_id,
+ import_stage: self.class.name
+ )
+ end
+ end
+ end
+end
diff --git a/app/workers/concerns/gitlab/bitbucket_server_import/object_importer.rb b/app/workers/concerns/gitlab/bitbucket_server_import/object_importer.rb
index b209719479b..1090d82c922 100644
--- a/app/workers/concerns/gitlab/bitbucket_server_import/object_importer.rb
+++ b/app/workers/concerns/gitlab/bitbucket_server_import/object_importer.rb
@@ -23,7 +23,7 @@ module Gitlab
# If a job is being exhausted we still want to notify the
# Gitlab::Import::AdvanceStageWorker to prevent the entire import from getting stuck
if args.length == 3 && (key = args.last) && key.is_a?(String)
- JobWaiter.notify(key, jid)
+ JobWaiter.notify(key, jid, ttl: Gitlab::Import::JOB_WAITER_TTL)
end
end
end
@@ -61,7 +61,7 @@ module Gitlab
end
def notify_waiter(key)
- JobWaiter.notify(key, jid)
+ JobWaiter.notify(key, jid, ttl: Gitlab::Import::JOB_WAITER_TTL)
end
# Returns the class to use for importing the object.
diff --git a/app/workers/concerns/gitlab/github_import/object_importer.rb b/app/workers/concerns/gitlab/github_import/object_importer.rb
index 6cb9bd34969..e190ced5073 100644
--- a/app/workers/concerns/gitlab/github_import/object_importer.rb
+++ b/app/workers/concerns/gitlab/github_import/object_importer.rb
@@ -27,7 +27,7 @@ module Gitlab
# If a job is being exhausted we still want to notify the
# Gitlab::Import::AdvanceStageWorker to prevent the entire import from getting stuck
if args.length == 3 && (key = args.last) && key.is_a?(String)
- JobWaiter.notify(key, jid)
+ JobWaiter.notify(key, jid, ttl: Gitlab::Import::JOB_WAITER_TTL)
end
end
end
@@ -38,7 +38,7 @@ module Gitlab
# client - An instance of `Gitlab::GithubImport::Client`
# hash - A Hash containing the details of the object to import.
def import(project, client, hash)
- unless project.import_state&.in_progress?
+ if project.import_state&.completed?
info(
project.id,
message: 'Project import is no longer running. Stopping worker.',
diff --git a/app/workers/concerns/gitlab/github_import/rescheduling_methods.rb b/app/workers/concerns/gitlab/github_import/rescheduling_methods.rb
index b40914770b5..f6feb6d1598 100644
--- a/app/workers/concerns/gitlab/github_import/rescheduling_methods.rb
+++ b/app/workers/concerns/gitlab/github_import/rescheduling_methods.rb
@@ -39,7 +39,7 @@ module Gitlab
end
def notify_waiter(key = nil)
- JobWaiter.notify(key, jid) if key
+ JobWaiter.notify(key, jid, ttl: Gitlab::Import::JOB_WAITER_TTL) if key
end
def reschedule_job(project, client, hash, notify_key)
diff --git a/app/workers/concerns/gitlab/github_import/stage_methods.rb b/app/workers/concerns/gitlab/github_import/stage_methods.rb
index a5287fcfbe2..75db5589415 100644
--- a/app/workers/concerns/gitlab/github_import/stage_methods.rb
+++ b/app/workers/concerns/gitlab/github_import/stage_methods.rb
@@ -9,7 +9,7 @@ module Gitlab
return unless (project = find_project(project_id))
- unless project.import_state&.in_progress?
+ if project.import_state&.completed?
info(
project_id,
message: 'Project import is no longer running. Stopping worker.',
diff --git a/app/workers/concerns/gitlab/import/notify_upon_death.rb b/app/workers/concerns/gitlab/import/notify_upon_death.rb
new file mode 100644
index 00000000000..ae726a673c2
--- /dev/null
+++ b/app/workers/concerns/gitlab/import/notify_upon_death.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+# NotifyUponDeath can be included into a worker class if it should
+# notify any JobWaiter instances upon being moved to the Sidekiq dead queue.
+#
+# Note that this will only notify the waiter upon graceful termination, a
+# SIGKILL will still result in the waiter _not_ being notified.
+#
+# Workers including this module must have jobs passed where the last
+# argument is the key to notify, as a String.
+module Gitlab
+ module Import
+ module NotifyUponDeath
+ extend ActiveSupport::Concern
+
+ included do
+ # If a job is being exhausted we still want to notify the
+ # Gitlab::Import::AdvanceStageWorker. This prevents the entire import from getting stuck
+ # just because 1 job threw too many errors.
+ sidekiq_retries_exhausted do |job|
+ args = job['args']
+ jid = job['jid']
+ key = args.last
+
+ next unless args.length == 3 && key.is_a?(String)
+
+ JobWaiter.notify(key, jid, ttl: Gitlab::Import::JOB_WAITER_TTL)
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/concerns/gitlab/notify_upon_death.rb b/app/workers/concerns/gitlab/notify_upon_death.rb
deleted file mode 100644
index 66dc6270637..00000000000
--- a/app/workers/concerns/gitlab/notify_upon_death.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- # NotifyUponDeath can be included into a worker class if it should
- # notify any JobWaiter instances upon being moved to the Sidekiq dead queue.
- #
- # Note that this will only notify the waiter upon graceful termination, a
- # SIGKILL will still result in the waiter _not_ being notified.
- #
- # Workers including this module must have jobs passed where the last
- # argument is the key to notify, as a String.
- module NotifyUponDeath
- extend ActiveSupport::Concern
-
- included do
- # If a job is being exhausted we still want to notify the
- # Gitlab::Import::AdvanceStageWorker. This prevents the entire import from getting stuck
- # just because 1 job threw too many errors.
- sidekiq_retries_exhausted do |job|
- args = job['args']
- jid = job['jid']
-
- if args.length == 3 && (key = args.last) && key.is_a?(String)
- JobWaiter.notify(key, jid)
- end
- end
- end
- end
-end
diff --git a/app/workers/database/batched_background_migration/execution_worker.rb b/app/workers/database/batched_background_migration/execution_worker.rb
index 1bdc829418a..75798f0ab73 100644
--- a/app/workers/database/batched_background_migration/execution_worker.rb
+++ b/app/workers/database/batched_background_migration/execution_worker.rb
@@ -64,6 +64,8 @@ module Database
attr_accessor :database_name, :migration
def enabled?
+ return false if Feature.enabled?(:disallow_database_ddl_feature_flags, type: :ops)
+
Feature.enabled?(:execute_batched_migrations_on_schedule, type: :ops)
end
diff --git a/app/workers/database/batched_background_migration/single_database_worker.rb b/app/workers/database/batched_background_migration/single_database_worker.rb
index ebf63d34cbf..f73f8fd751b 100644
--- a/app/workers/database/batched_background_migration/single_database_worker.rb
+++ b/app/workers/database/batched_background_migration/single_database_worker.rb
@@ -27,6 +27,8 @@ module Database
# :nocov:
def enabled?
+ return false if Feature.enabled?(:disallow_database_ddl_feature_flags, type: :ops)
+
Feature.enabled?(:execute_batched_migrations_on_schedule, type: :ops)
end
diff --git a/app/workers/database/lock_tables_worker.rb b/app/workers/database/lock_tables_worker.rb
new file mode 100644
index 00000000000..12c8e508ad5
--- /dev/null
+++ b/app/workers/database/lock_tables_worker.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Database
+ class LockTablesWorker
+ include ApplicationWorker
+
+ TableShouldNotBeLocked = Class.new(StandardError)
+
+ sidekiq_options retry: false
+ feature_category :cell
+ data_consistency :always # rubocop:disable SidekiqLoadBalancing/WorkerDataConsistency
+ idempotent!
+
+ version 1
+
+ def perform(database_name, tables)
+ check_if_should_lock_database(database_name)
+
+ connection = ::Gitlab::Database.database_base_models_with_gitlab_shared[database_name].connection
+ check_if_should_lock_tables(tables, database_name, connection)
+
+ performed_actions = tables.map do |table_name|
+ lock_writes_manager(table_name, connection, database_name).lock_writes
+ end
+
+ log_extra_metadata_on_done(:performed_actions, performed_actions)
+ end
+
+ private
+
+ def check_if_should_lock_database(database_name)
+ raise TableShouldNotBeLocked, 'GitLab is not running in multiple database mode' unless
+ Gitlab::Database.database_mode == Gitlab::Database::MODE_MULTIPLE_DATABASES
+
+ raise TableShouldNotBeLocked, "database '#{database_name}' does not support locking writes on tables" unless
+ ::Gitlab::Database.database_base_models_with_gitlab_shared.include?(database_name)
+ end
+
+ def check_if_should_lock_tables(tables, database_name, connection)
+ tables.each do |table_name|
+ unless should_lock_writes_on_table?(connection, database_name, table_name)
+ raise TableShouldNotBeLocked, "table '#{table_name}' should not be locked on the database '#{database_name}'"
+ end
+ end
+ end
+
+ def should_lock_writes_on_table?(connection, database_name, table_name)
+ db_info = Gitlab::Database.all_database_connections.fetch(database_name)
+ table_schema = Gitlab::Database::GitlabSchema.table_schema!(table_name.to_s)
+
+ Gitlab::Database.gitlab_schemas_for_connection(connection).exclude?(table_schema) &&
+ db_info.lock_gitlab_schemas.include?(table_schema)
+ end
+
+ def lock_writes_manager(table_name, connection, database_name)
+ Gitlab::Database::LockWritesManager.new(
+ table_name: table_name,
+ connection: connection,
+ database_name: database_name,
+ with_retries: !connection.transaction_open?,
+ logger: nil,
+ dry_run: false
+ )
+ end
+ end
+end
diff --git a/app/workers/database/monitor_locked_tables_worker.rb b/app/workers/database/monitor_locked_tables_worker.rb
index 66296ea1c0d..4a23d25edf4 100644
--- a/app/workers/database/monitor_locked_tables_worker.rb
+++ b/app/workers/database/monitor_locked_tables_worker.rb
@@ -33,6 +33,13 @@ module Database
handle_lock_writes_result(tables_lock_info_per_db, result)
end
+ tables_lock_info_per_db.each do |database_name, database_results|
+ next if database_results[:tables_need_lock].empty?
+ break if Feature.disabled?(:lock_tables_in_monitoring, type: :ops)
+
+ LockTablesWorker.perform_async(database_name, database_results[:tables_need_lock])
+ end
+
log_extra_metadata_on_done(:results, tables_lock_info_per_db)
end
diff --git a/app/workers/environments/stop_job_success_worker.rb b/app/workers/environments/stop_job_success_worker.rb
index cc7d83512f3..93b743ee602 100644
--- a/app/workers/environments/stop_job_success_worker.rb
+++ b/app/workers/environments/stop_job_success_worker.rb
@@ -9,15 +9,15 @@ module Environments
feature_category :continuous_delivery
def perform(job_id, _params = {})
- Ci::Build.find_by_id(job_id).try do |build|
- stop_environment(build) if build.stops_environment? && build.stop_action_successful?
+ Ci::Processable.find_by_id(job_id).try do |job|
+ stop_environment(job) if job.stops_environment? && job.stop_action_successful?
end
end
private
- def stop_environment(build)
- build.persisted_environment.fire_state_event(:stop_complete)
+ def stop_environment(job)
+ job.persisted_environment.fire_state_event(:stop_complete)
end
end
end
diff --git a/app/workers/gitlab/bitbucket_import/advance_stage_worker.rb b/app/workers/gitlab/bitbucket_import/advance_stage_worker.rb
new file mode 100644
index 00000000000..7f281352a1b
--- /dev/null
+++ b/app/workers/gitlab/bitbucket_import/advance_stage_worker.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ # AdvanceStageWorker is a worker used by the BitBucket Importer to wait for a
+ # number of jobs to complete, without blocking a thread. Once all jobs have
+ # been completed this worker will advance the import process to the next
+ # stage.
+ class AdvanceStageWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+ include ::Gitlab::Import::AdvanceStage
+
+ data_consistency :delayed
+
+ sidekiq_options dead: false, retry: 3
+
+ feature_category :importers
+
+ loggable_arguments 1, 2
+
+ # The known importer stages and their corresponding Sidekiq workers.
+ STAGES = {
+ finish: Stage::FinishImportWorker
+ }.freeze
+
+ def find_import_state(project_id)
+ ProjectImportState.jid_by(project_id: project_id, status: :started)
+ end
+
+ private
+
+ def next_stage_worker(next_stage)
+ STAGES.fetch(next_stage.to_sym)
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab/bitbucket_import/import_pull_request_worker.rb b/app/workers/gitlab/bitbucket_import/import_pull_request_worker.rb
new file mode 100644
index 00000000000..5b06ddf7079
--- /dev/null
+++ b/app/workers/gitlab/bitbucket_import/import_pull_request_worker.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ class ImportPullRequestWorker # rubocop:disable Scalability/IdempotentWorker
+ include ObjectImporter
+
+ def importer_class
+ Importers::PullRequestImporter
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab/bitbucket_import/stage/finish_import_worker.rb b/app/workers/gitlab/bitbucket_import/stage/finish_import_worker.rb
new file mode 100644
index 00000000000..a1c5f5787be
--- /dev/null
+++ b/app/workers/gitlab/bitbucket_import/stage/finish_import_worker.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module Stage
+ class FinishImportWorker # rubocop:disable Scalability/IdempotentWorker
+ include StageMethods
+
+ private
+
+ def import(project)
+ project.after_import
+
+ Gitlab::Import::Metrics.new(:bitbucket_importer, project).track_finished_import
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker.rb b/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker.rb
new file mode 100644
index 00000000000..e1f3b5ab79a
--- /dev/null
+++ b/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module Stage
+ class ImportPullRequestsWorker # rubocop:disable Scalability/IdempotentWorker
+ include StageMethods
+
+ private
+
+ # project - An instance of Project.
+ def import(project)
+ waiter = importer_class.new(project).execute
+
+ project.import_state.refresh_jid_expiration
+
+ AdvanceStageWorker.perform_async(
+ project.id,
+ { waiter.key => waiter.jobs_remaining },
+ :finish
+ )
+ end
+
+ def importer_class
+ Importers::PullRequestsImporter
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab/bitbucket_import/stage/import_repository_worker.rb b/app/workers/gitlab/bitbucket_import/stage/import_repository_worker.rb
new file mode 100644
index 00000000000..7c6503ae38f
--- /dev/null
+++ b/app/workers/gitlab/bitbucket_import/stage/import_repository_worker.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module Stage
+ class ImportRepositoryWorker # rubocop:disable Scalability/IdempotentWorker
+ include StageMethods
+
+ private
+
+ def import(project)
+ importer = importer_class.new(project)
+
+ importer.execute
+
+ ImportPullRequestsWorker.perform_async(project.id)
+ end
+
+ def importer_class
+ Importers::RepositoryImporter
+ end
+
+ def abort_on_failure
+ true
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab/github_gists_import/import_gist_worker.rb b/app/workers/gitlab/github_gists_import/import_gist_worker.rb
index 1f17c98dff9..60e4c8fdad6 100644
--- a/app/workers/gitlab/github_gists_import/import_gist_worker.rb
+++ b/app/workers/gitlab/github_gists_import/import_gist_worker.rb
@@ -25,7 +25,7 @@ module Gitlab
# Gitlab::GithubGistsImport::FinishImportWorker to prevent
# the entire import from getting stuck
if args.length == 3 && (key = args.last) && key.is_a?(String)
- JobWaiter.notify(key, jid)
+ JobWaiter.notify(key, jid, ttl: Gitlab::Import::JOB_WAITER_TTL)
end
end
@@ -48,7 +48,7 @@ module Gitlab
)
end
- JobWaiter.notify(notify_key, jid)
+ JobWaiter.notify(notify_key, jid, ttl: Gitlab::Import::JOB_WAITER_TTL)
end
rescue StandardError => e
log_and_track_error(user_id, e, github_identifiers)
diff --git a/app/workers/gitlab/import/advance_stage.rb b/app/workers/gitlab/import/advance_stage.rb
index 9fc03efe9d0..5d5abc88388 100644
--- a/app/workers/gitlab/import/advance_stage.rb
+++ b/app/workers/gitlab/import/advance_stage.rb
@@ -15,7 +15,15 @@ module Gitlab
# next_stage - The name of the next stage to start when all jobs have been
# completed.
def perform(project_id, waiters, next_stage)
- return unless import_state = find_import_state(project_id)
+ import_state = find_import_state(project_id)
+
+ # If the import state is nil the project may have been deleted or the import
+ # may have failed or been canceled. In this case we tidy up the cache data and no
+ # longer attempt to advance to the next stage.
+ if import_state.nil?
+ clear_waiter_caches(waiters)
+ return
+ end
new_waiters = wait_for_jobs(waiters)
@@ -56,6 +64,12 @@ module Gitlab
def next_stage_worker(next_stage)
raise NotImplementedError
end
+
+ def clear_waiter_caches(waiters)
+ waiters.each_key do |key|
+ JobWaiter.delete_key(key)
+ end
+ end
end
end
end
diff --git a/app/workers/gitlab/jira_import/import_issue_worker.rb b/app/workers/gitlab/jira_import/import_issue_worker.rb
index eabe988dfc2..2b676238a37 100644
--- a/app/workers/gitlab/jira_import/import_issue_worker.rb
+++ b/app/workers/gitlab/jira_import/import_issue_worker.rb
@@ -8,9 +8,9 @@ module Gitlab
data_consistency :always
sidekiq_options retry: 3
- include NotifyUponDeath
include Gitlab::JiraImport::QueueOptions
include Gitlab::Import::DatabaseHelpers
+ include Gitlab::Import::NotifyUponDeath
loggable_arguments 3
@@ -27,7 +27,7 @@ module Gitlab
JiraImport.increment_issue_failures(project_id)
ensure
# ensure we notify job waiter that the job has finished
- JobWaiter.notify(waiter_key, jid) if waiter_key
+ JobWaiter.notify(waiter_key, jid, ttl: Gitlab::Import::JOB_WAITER_TTL) if waiter_key
end
private
diff --git a/app/workers/incident_management/close_incident_worker.rb b/app/workers/incident_management/close_incident_worker.rb
index c820a8a97bf..011cb76442b 100644
--- a/app/workers/incident_management/close_incident_worker.rb
+++ b/app/workers/incident_management/close_incident_worker.rb
@@ -25,7 +25,7 @@ module IncidentManagement
private
def user
- @user ||= User.alert_bot
+ @user ||= Users::Internal.alert_bot
end
def close_incident(incident)
diff --git a/app/workers/incident_management/process_alert_worker_v2.rb b/app/workers/incident_management/process_alert_worker_v2.rb
index 04c02d17704..12434671527 100644
--- a/app/workers/incident_management/process_alert_worker_v2.rb
+++ b/app/workers/incident_management/process_alert_worker_v2.rb
@@ -32,7 +32,7 @@ module IncidentManagement
def create_issue_for(alert)
AlertManagement::CreateAlertIssueService
- .new(alert, User.alert_bot)
+ .new(alert, Users::Internal.alert_bot)
.execute
end
diff --git a/app/workers/loose_foreign_keys/cleanup_worker.rb b/app/workers/loose_foreign_keys/cleanup_worker.rb
index e6d0261b7f1..e1233a449e7 100644
--- a/app/workers/loose_foreign_keys/cleanup_worker.rb
+++ b/app/workers/loose_foreign_keys/cleanup_worker.rb
@@ -12,18 +12,23 @@ module LooseForeignKeys
idempotent!
def perform
+ connection_name, base_model = current_connection_name_and_base_model
+ modification_tracker, turbo_mode = initialize_modification_tracker_for(connection_name)
+
# Add small buffer on MAX_RUNTIME to account for single long running
# query or extra worker time after the cleanup.
- lock_ttl = ModificationTracker::MAX_RUNTIME + 20.seconds
+ lock_ttl = modification_tracker.max_runtime + 10.seconds
in_lock(self.class.name.underscore, ttl: lock_ttl, retries: 0) do
stats = {}
- connection_name, base_model = current_connection_name_and_base_model
-
Gitlab::Database::SharedModel.using_connection(base_model.connection) do
- stats = ProcessDeletedRecordsService.new(connection: base_model.connection).execute
+ stats = ProcessDeletedRecordsService.new(
+ connection: base_model.connection,
+ modification_tracker: modification_tracker
+ ).execute
stats[:connection] = connection_name
+ stats[:turbo_mode] = turbo_mode
end
log_extra_metadata_on_done(:stats, stats)
@@ -41,5 +46,16 @@ module LooseForeignKeys
connections_with_name = Gitlab::Database.database_base_models_with_gitlab_shared.to_a # this will never be empty
connections_with_name[minutes_since_epoch % connections_with_name.count]
end
+
+ def initialize_modification_tracker_for(connection_name)
+ turbo_mode = turbo_mode?(connection_name)
+ modification_tracker ||= turbo_mode ? TurboModificationTracker.new : ModificationTracker.new
+ [modification_tracker, turbo_mode]
+ end
+
+ def turbo_mode?(connection_name)
+ %w[main ci].include?(connection_name) &&
+ Feature.enabled?(:"loose_foreign_keys_turbo_mode_#{connection_name}", type: :ops)
+ end
end
end
diff --git a/app/workers/members_destroyer/unassign_issuables_worker.rb b/app/workers/members_destroyer/unassign_issuables_worker.rb
index 2e6ce0005fc..677a1be25ca 100644
--- a/app/workers/members_destroyer/unassign_issuables_worker.rb
+++ b/app/workers/members_destroyer/unassign_issuables_worker.rb
@@ -8,7 +8,7 @@ module MembersDestroyer
sidekiq_options retry: 3
- ENTITY_TYPES = %w(Group Project).freeze
+ ENTITY_TYPES = %w[Group Project].freeze
queue_namespace :unassign_issuables
feature_category :user_management
diff --git a/app/workers/merge_requests/ensure_prepared_worker.rb b/app/workers/merge_requests/ensure_prepared_worker.rb
new file mode 100644
index 00000000000..6dfe888f408
--- /dev/null
+++ b/app/workers/merge_requests/ensure_prepared_worker.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module MergeRequests
+ class EnsurePreparedWorker
+ include ApplicationWorker
+ include CronjobQueue
+
+ feature_category :code_review_workflow
+ idempotent!
+ deduplicate :until_executed
+ data_consistency :sticky
+
+ JOBS_PER_10_SECONDS = 5
+
+ def perform
+ return unless Feature.enabled?(:ensure_merge_requests_prepared)
+
+ scope = MergeRequest.recently_unprepared
+
+ iterator = Gitlab::Pagination::Keyset::Iterator.new(scope: scope)
+
+ index = 0
+ iterator.each_batch(of: JOBS_PER_10_SECONDS) do |merge_requests|
+ index += 1
+
+ NewMergeRequestWorker.bulk_perform_in_with_contexts(index * 10.seconds,
+ merge_requests,
+ arguments_proc: ->(merge_request) { [merge_request.id, merge_request.author_id] },
+ context_proc: ->(merge_request) { { project: merge_request.project } }
+ )
+ end
+ end
+ end
+end
diff --git a/app/workers/merge_worker.rb b/app/workers/merge_worker.rb
index 3fcd7a3ad7a..a0594b15e31 100644
--- a/app/workers/merge_worker.rb
+++ b/app/workers/merge_worker.rb
@@ -29,3 +29,5 @@ class MergeWorker # rubocop:disable Scalability/IdempotentWorker
.execute(merge_request)
end
end
+
+MergeWorker.prepend_mod
diff --git a/app/workers/metrics/global_metrics_update_worker.rb b/app/workers/metrics/global_metrics_update_worker.rb
index 326403a2f8f..9b196f7213f 100644
--- a/app/workers/metrics/global_metrics_update_worker.rb
+++ b/app/workers/metrics/global_metrics_update_worker.rb
@@ -16,9 +16,7 @@ module Metrics
LEASE_TIMEOUT = 2.minutes
- def perform
- try_obtain_lease { ::Metrics::GlobalMetricsUpdateService.new.execute }
- end
+ def perform; end
def lease_timeout
LEASE_TIMEOUT
diff --git a/app/workers/namespaces/in_product_marketing_emails_worker.rb b/app/workers/namespaces/in_product_marketing_emails_worker.rb
deleted file mode 100644
index 470fba1227d..00000000000
--- a/app/workers/namespaces/in_product_marketing_emails_worker.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module Namespaces
- class InProductMarketingEmailsWorker # rubocop:disable Scalability/IdempotentWorker
- include ApplicationWorker
-
- data_consistency :always
-
- include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
-
- feature_category :experimentation_activation
- urgency :low
-
- def perform
- return if paid_self_managed_instance?
- return if setting_disabled?
-
- Namespaces::InProductMarketingEmailsService.send_for_all_tracks_and_intervals
- end
-
- private
-
- def paid_self_managed_instance?
- false
- end
-
- def setting_disabled?
- !Gitlab::CurrentSettings.in_product_marketing_emails_enabled
- end
- end
-end
-
-Namespaces::InProductMarketingEmailsWorker.prepend_mod_with('Namespaces::InProductMarketingEmailsWorker')
diff --git a/app/workers/new_merge_request_worker.rb b/app/workers/new_merge_request_worker.rb
index 74239c5d968..e2e738f79a5 100644
--- a/app/workers/new_merge_request_worker.rb
+++ b/app/workers/new_merge_request_worker.rb
@@ -2,22 +2,23 @@
class NewMergeRequestWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
+ include NewIssuable
data_consistency :always
-
sidekiq_options retry: 3
- include NewIssuable
idempotent!
deduplicate :until_executed
feature_category :code_review_workflow
urgency :high
+
worker_resource_boundary :cpu
weight 2
def perform(merge_request_id, user_id)
return unless objects_found?(merge_request_id, user_id)
+ return if issuable.prepared?
MergeRequests::AfterCreateService
.new(project: issuable.target_project, current_user: user)
diff --git a/app/workers/pages/invalidate_domain_cache_worker.rb b/app/workers/pages/invalidate_domain_cache_worker.rb
deleted file mode 100644
index 1700b681b94..00000000000
--- a/app/workers/pages/invalidate_domain_cache_worker.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-module Pages
- class InvalidateDomainCacheWorker
- include Gitlab::EventStore::Subscriber
-
- idempotent!
-
- feature_category :pages
-
- def handle_event(event)
- domain_ids(event).each do |domain_id|
- ::Gitlab::Pages::CacheControl
- .for_domain(domain_id)
- .clear_cache
- end
-
- event.data.values_at(
- :root_namespace_id,
- :old_root_namespace_id,
- :new_root_namespace_id
- ).compact.uniq.each do |namespace_id|
- ::Gitlab::Pages::CacheControl
- .for_namespace(namespace_id)
- .clear_cache
- end
- end
-
- def domain_ids(event)
- ids = PagesDomain.ids_for_project(event.data[:project_id])
-
- ids << event.data[:domain_id] if event.data[:domain_id]
-
- ids
- end
- end
-end
diff --git a/app/workers/personal_access_tokens/expiring_worker.rb b/app/workers/personal_access_tokens/expiring_worker.rb
index de0bda82573..5f8316d184d 100644
--- a/app/workers/personal_access_tokens/expiring_worker.rb
+++ b/app/workers/personal_access_tokens/expiring_worker.rb
@@ -29,9 +29,21 @@ module PersonalAccessTokens
# rubocop: enable CodeReuse/ActiveRecord
- notification_service.access_token_about_to_expire(user, token_names)
+ message = if user.project_bot?
+ notification_service.resource_access_tokens_about_to_expire(user, token_names)
- Gitlab::AppLogger.info "#{self.class}: Notifying User #{user.id} about expiring tokens"
+ "Notifying Bot User resource owners about expiring tokens"
+ else
+ notification_service.access_token_about_to_expire(user, token_names)
+
+ "Notifying User about expiring tokens"
+ end
+
+ Gitlab::AppLogger.info(
+ message: message,
+ class: self.class,
+ user_id: user.id
+ )
expiring_user_tokens.each_batch do |expiring_tokens|
expiring_tokens.update_all(expire_notification_delivered: true)
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 4971dc3775f..5345714a010 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -164,7 +164,7 @@ class PostReceive
user: user,
property: 'source_code_pushes',
label: metric_path,
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: metric_path).to_context]
+ context: [Gitlab::Usage::MetricDefinition.context_for(metric_path).to_context]
)
end
end
diff --git a/app/workers/projects/inactive_projects_deletion_cron_worker.rb b/app/workers/projects/inactive_projects_deletion_cron_worker.rb
index 31fdb3d9615..f16415af830 100644
--- a/app/workers/projects/inactive_projects_deletion_cron_worker.rb
+++ b/app/workers/projects/inactive_projects_deletion_cron_worker.rb
@@ -22,7 +22,7 @@ module Projects
return unless ::Gitlab::CurrentSettings.delete_inactive_projects?
@start_time ||= ::Gitlab::Metrics::System.monotonic_time
- admin_bot = ::User.admin_bot
+ admin_bot = ::Users::Internal.admin_bot
return unless admin_bot
diff --git a/app/workers/projects/record_target_platforms_worker.rb b/app/workers/projects/record_target_platforms_worker.rb
index 9ebc52f77d3..bbe0c63cfd1 100644
--- a/app/workers/projects/record_target_platforms_worker.rb
+++ b/app/workers/projects/record_target_platforms_worker.rb
@@ -6,9 +6,9 @@ module Projects
include ExclusiveLeaseGuard
LEASE_TIMEOUT = 1.hour.to_i
- APPLE_PLATFORM_LANGUAGES = %w(swift objective-c).freeze
+ APPLE_PLATFORM_LANGUAGES = %w[swift objective-c].freeze
- feature_category :groups_and_projects
+ feature_category :experimentation_activation
data_consistency :always
deduplicate :until_executed
urgency :low
diff --git a/app/workers/users/deactivate_dormant_users_worker.rb b/app/workers/users/deactivate_dormant_users_worker.rb
index 87566bff467..33c54f07521 100644
--- a/app/workers/users/deactivate_dormant_users_worker.rb
+++ b/app/workers/users/deactivate_dormant_users_worker.rb
@@ -15,7 +15,7 @@ module Users
return unless ::Gitlab::CurrentSettings.current_application_settings.deactivate_dormant_users
- admin_bot = User.admin_bot
+ admin_bot = Users::Internal.admin_bot
return unless admin_bot
deactivate_users(User.dormant, admin_bot)
diff --git a/app/workers/users/track_namespace_visits_worker.rb b/app/workers/users/track_namespace_visits_worker.rb
new file mode 100644
index 00000000000..5b2a7b7d0fa
--- /dev/null
+++ b/app/workers/users/track_namespace_visits_worker.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Users
+ class TrackNamespaceVisitsWorker
+ include ApplicationWorker
+
+ feature_category :navigation
+ data_consistency :delayed
+ urgency :throttled
+ idempotent!
+
+ GROUPS = 'groups'
+ PROJECTS = 'projects'
+
+ def perform(entity_type, entity_id, user_id, time)
+ return unless entity_id && user_id
+
+ case entity_type
+ when GROUPS
+ unless GroupVisit.visited_around?(entity_id: entity_id, user_id: user_id, time: time)
+ GroupVisit.create!(entity_id: entity_id, user_id: user_id, visited_at: time)
+ end
+ when PROJECTS
+ unless ProjectVisit.visited_around?(entity_id: entity_id, user_id: user_id, time: time)
+ ProjectVisit.create!(entity_id: entity_id, user_id: user_id, visited_at: time)
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/x509_issuer_crl_check_worker.rb b/app/workers/x509_issuer_crl_check_worker.rb
index 58084405769..71d2c398ca7 100644
--- a/app/workers/x509_issuer_crl_check_worker.rb
+++ b/app/workers/x509_issuer_crl_check_worker.rb
@@ -18,7 +18,7 @@ class X509IssuerCrlCheckWorker
def perform
@logger = Gitlab::GitLogger.build
- X509Issuer.all.find_each do |issuer|
+ X509Issuer.with_crl_url.find_each do |issuer|
with_context(related_class: X509IssuerCrlCheckWorker) do
update_certificates(issuer)
end
diff --git a/bin/vite b/bin/vite
new file mode 100755
index 00000000000..7527d097eb6
--- /dev/null
+++ b/bin/vite
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+#
+# This file was generated by Bundler.
+#
+# The application 'vite' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
+
+bundle_binstub = File.expand_path("bundle", __dir__)
+
+if File.file?(bundle_binstub)
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
+ load(bundle_binstub)
+ else
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
+Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
+ end
+end
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("vite_ruby", "vite")
diff --git a/config/application.rb b/config/application.rb
index 8753d3304a5..552a68f6046 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -41,7 +41,6 @@ module Gitlab
config.active_support.executor_around_test_case = nil # New default is true
config.active_support.isolation_level = nil # New default is thread
config.active_support.key_generator_hash_digest_class = nil # New default is OpenSSL::Digest::SHA256
- config.active_support.remove_deprecated_time_with_zone_name = nil # New default is true
config.active_support.use_rfc4122_namespaced_uuids = nil # New default is true
# Rails 6.1
@@ -214,7 +213,7 @@ module Gitlab
/^title$/,
/^hook$/
]
- config.filter_parameters += %i(
+ config.filter_parameters += %i[
certificate
encrypted_key
import_url
@@ -230,7 +229,8 @@ module Gitlab
content
sharedSecret
redirect
- )
+ question
+ ]
# This config option can be removed after Rails 7.1 by https://gitlab.com/gitlab-org/gitlab/-/issues/416270
config.active_support.use_rfc4122_namespaced_uuids = true
@@ -258,6 +258,9 @@ module Gitlab
# Enable the asset pipeline
config.assets.enabled = true
+ # Disable adding field_with_errors wrapper to form elements
+ config.action_view.field_error_proc = proc { |html_tag, instance| html_tag }
+
# Support legacy unicode file named img emojis, `1F939.png`
config.assets.paths << TanukiEmoji.images_path
config.assets.paths << "#{config.root}/vendor/assets/fonts"
@@ -279,7 +282,6 @@ module Gitlab
config.assets.precompile << "page_bundles/admin/elasticsearch_form.css"
config.assets.precompile << "page_bundles/admin/geo_sites.css"
config.assets.precompile << "page_bundles/admin/geo_replicable.css"
- config.assets.precompile << "page_bundles/admin/jobs_index.css"
config.assets.precompile << "page_bundles/alert_management_details.css"
config.assets.precompile << "page_bundles/alert_management_settings.css"
config.assets.precompile << "page_bundles/billings.css"
@@ -337,7 +339,6 @@ module Gitlab
config.assets.precompile << "page_bundles/profiles/preferences.css"
config.assets.precompile << "page_bundles/project.css"
config.assets.precompile << "page_bundles/projects_edit.css"
- config.assets.precompile << "page_bundles/projects_usage_quotas.css"
config.assets.precompile << "page_bundles/promotions.css"
config.assets.precompile << "page_bundles/releases.css"
config.assets.precompile << "page_bundles/remote_development.css"
@@ -457,30 +458,30 @@ module Gitlab
allow do
origins { |source, env| source == Gitlab::CurrentSettings.jira_connect_proxy_url }
- resource '/-/jira_connect/oauth_application_id', headers: :any, credentials: false, methods: %i(get options)
+ resource '/-/jira_connect/oauth_application_id', headers: :any, credentials: false, methods: %i[get options]
end
allow do
origins { |source, env| source == Gitlab::CurrentSettings.jira_connect_proxy_url }
- resource '/-/jira_connect/subscriptions.json', headers: :any, credentials: false, methods: %i(get options)
+ resource '/-/jira_connect/subscriptions.json', headers: :any, credentials: false, methods: %i[get options]
end
allow do
origins { |source, env| source == Gitlab::CurrentSettings.jira_connect_proxy_url }
- resource '/-/jira_connect/subscriptions/*', headers: :any, credentials: false, methods: %i(delete options)
+ resource '/-/jira_connect/subscriptions/*', headers: :any, credentials: false, methods: %i[delete options]
end
# Cross-origin requests must be enabled for the Authorization code with PKCE OAuth flow when used from a browser.
- %w(/oauth/token /oauth/revoke).each do |oauth_path|
+ %w[/oauth/token /oauth/revoke].each do |oauth_path|
allow do
origins '*'
resource oauth_path,
# These headers are added as defaults to axios.
# See: https://gitlab.com/gitlab-org/gitlab/-/blob/dd1e70d3676891025534dc4a1e89ca9383178fe7/app/assets/javascripts/lib/utils/axios_utils.js#L8)
# It's added to declare that this is a XHR request and add the CSRF token without which Rails may reject the request from the frontend.
- headers: %w(Authorization X-CSRF-Token X-Requested-With),
+ headers: %w[Authorization X-CSRF-Token X-Requested-With],
credentials: false,
- methods: %i(post options)
+ methods: %i[post options]
end
end
@@ -489,19 +490,28 @@ module Gitlab
allow do
origins '*'
resource '/oauth/userinfo',
- headers: %w(Authorization),
+ headers: %w[Authorization],
credentials: false,
- methods: %i(get head post options)
+ methods: %i[get head post options]
end
- %w(/oauth/discovery/keys /.well-known/openid-configuration /.well-known/webfinger).each do |openid_path|
+ %w[/oauth/discovery/keys /.well-known/openid-configuration /.well-known/webfinger].each do |openid_path|
allow do
origins '*'
resource openid_path,
credentials: false,
- methods: %i(get head)
+ methods: %i[get head]
end
end
+
+ # Allow assets to be loaded to web-ide
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/421177
+ allow do
+ origins 'https://*.web-ide.gitlab-static.net'
+ resource '/assets/webpack/*',
+ credentials: false,
+ methods: %i[get head]
+ end
end
# Use caching across all environments
diff --git a/config/boot.rb b/config/boot.rb
index ec9470bc506..1b3f2935e3f 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -3,4 +3,4 @@
require_relative 'bundler_setup'
enable_bootsnap_default_value = ENV['RAILS_ENV'] != 'production' ? '1' : '0'
-require 'bootsnap/setup' if %w(1 yes true).include?(ENV.fetch('ENABLE_BOOTSNAP', enable_bootsnap_default_value))
+require 'bootsnap/setup' if %w[1 yes true].include?(ENV.fetch('ENABLE_BOOTSNAP', enable_bootsnap_default_value))
diff --git a/config/database.yml.decomposed-clusterwide-postgresql b/config/database.yml.decomposed-clusterwide-postgresql
index 6439788524e..63d35184953 100644
--- a/config/database.yml.decomposed-clusterwide-postgresql
+++ b/config/database.yml.decomposed-clusterwide-postgresql
@@ -60,6 +60,7 @@ test:
username: postgres
password:
prepared_statements: false
+ reaping_frequency: nil
variables:
statement_timeout: 15s
ci:
@@ -68,19 +69,23 @@ test:
username: postgres
password:
prepared_statements: false
+ reaping_frequency: nil
variables:
statement_timeout: 15s
main_clusterwide:
<<: *main
database_tasks: false
+ reaping_frequency: nil
geo:
<<: *defaults
database: gitlabhq_geo_test
username: postgres
password:
+ reaping_frequency: nil
embedding:
<<: *defaults
database: gitlabhq_embedding_test
username: postgres
password:
+ reaping_frequency: nil
diff --git a/config/database.yml.decomposed-postgresql b/config/database.yml.decomposed-postgresql
index 3b5d1ff2ed5..a2f9e42d620 100644
--- a/config/database.yml.decomposed-postgresql
+++ b/config/database.yml.decomposed-postgresql
@@ -84,6 +84,7 @@ test: &test
password:
host: localhost
prepared_statements: false
+ reaping_frequency: nil
variables:
statement_timeout: 15s
ci:
@@ -94,6 +95,7 @@ test: &test
password:
host: localhost
prepared_statements: false
+ reaping_frequency: nil
variables:
statement_timeout: 15s
geo:
@@ -103,6 +105,7 @@ test: &test
username: postgres
password:
host: localhost
+ reaping_frequency: nil
embedding:
adapter: postgresql
encoding: unicode
@@ -110,3 +113,4 @@ test: &test
username: postgres
password:
host: localhost
+ reaping_frequency: nil
diff --git a/config/database.yml.postgresql b/config/database.yml.postgresql
index b210b9c412b..da9f458ff09 100644
--- a/config/database.yml.postgresql
+++ b/config/database.yml.postgresql
@@ -104,6 +104,7 @@ test: &test
password:
host: localhost
prepared_statements: false
+ reaping_frequency: nil
variables:
statement_timeout: 15s
ci:
@@ -115,6 +116,7 @@ test: &test
password:
host: localhost
prepared_statements: false
+ reaping_frequency: nil
variables:
statement_timeout: 15s
geo:
@@ -124,6 +126,7 @@ test: &test
username: postgres
password:
host: localhost
+ reaping_frequency: nil
embedding:
adapter: postgresql
encoding: unicode
@@ -131,3 +134,4 @@ test: &test
username: postgres
password:
host: localhost
+ reaping_frequency: nil
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 8372331024f..931677b4ad7 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -43,7 +43,7 @@ Rails.application.configure do
# Suppress 'Rendered template ...' messages in the log
# source: http://stackoverflow.com/a/16369363
- %w{render_template render_partial render_collection}.each do |event|
+ %w[render_template render_partial render_collection].each do |event|
ActiveSupport::Notifications.unsubscribe "#{event}.action_view"
end
diff --git a/config/events/202109151015_groups__email_campaigns_controller_click.yml b/config/events/202109151015_groups__email_campaigns_controller_click.yml
deleted file mode 100644
index 2604a65e9c6..00000000000
--- a/config/events/202109151015_groups__email_campaigns_controller_click.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-description: Marketing email campaigns
-category: Groups::EmailCampaignsController
-action: click
-label_description:
-property_description:
-value_description:
-extra_properties:
-identifiers:
-product_section: growth
-product_stage: growth
-product_group: group::activation
-milestone: "13.11"
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56015
-distributions:
-- ce
-- ee
-tiers:
-- free
-- premium
-- ultimate
diff --git a/config/events/p_analytics_ci_cd_deployment_frequency.yml b/config/events/p_analytics_ci_cd_deployment_frequency.yml
new file mode 100644
index 00000000000..47b71758921
--- /dev/null
+++ b/config/events/p_analytics_ci_cd_deployment_frequency.yml
@@ -0,0 +1,24 @@
+---
+description: Project level CI CD Analytics deployment frequency tab has been visited
+category: InternalEventTracking
+action: p_analytics_ci_cd_deployment_frequency
+label_description:
+property_description:
+value_description:
+extra_properties:
+identifiers:
+- project
+- user
+- namespace
+product_section: dev
+product_stage: manage
+product_group: optimize
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130854
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
diff --git a/config/events/p_analytics_ci_cd_lead_time.yml b/config/events/p_analytics_ci_cd_lead_time.yml
new file mode 100644
index 00000000000..d45b6bec225
--- /dev/null
+++ b/config/events/p_analytics_ci_cd_lead_time.yml
@@ -0,0 +1,24 @@
+---
+description: Project level CI CD Analytics lead time tab has been visited
+category: InternalEventTracking
+action: p_analytics_ci_cd_lead_time
+label_description:
+property_description:
+value_description:
+extra_properties:
+identifiers:
+- project
+- user
+- namespace
+product_section: dev
+product_stage: manage
+product_group: optimize
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130854
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
diff --git a/config/events/p_analytics_ci_cd_pipelines.yml b/config/events/p_analytics_ci_cd_pipelines.yml
new file mode 100644
index 00000000000..2f14fcc0057
--- /dev/null
+++ b/config/events/p_analytics_ci_cd_pipelines.yml
@@ -0,0 +1,24 @@
+---
+description: Project level CI CD Analytics pipelines tab has been visited
+category: InternalEventTracking
+action: p_analytics_ci_cd_pipelines
+label_description:
+property_description:
+value_description:
+extra_properties:
+identifiers:
+- project
+- user
+- namespace
+product_section: dev
+product_stage: manage
+product_group: optimize
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130854
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
diff --git a/config/feature_categories.yml b/config/feature_categories.yml
index 5095fa36dd1..8c436313e5f 100644
--- a/config/feature_categories.yml
+++ b/config/feature_categories.yml
@@ -9,6 +9,8 @@
---
- advisory_database
- ai_abstraction_layer
+- ai_evaluation
+- ai_research
- api
- api_security
- application_instrumentation
@@ -50,6 +52,7 @@
- devops_reports
- disaster_recovery
- dora_metrics
+- duo_chat
- dynamic_application_security_testing
- editor_extensions
- environment_management
@@ -68,7 +71,6 @@
- gitaly
- gitlab_cli
- gitlab_docs
-- gitlab_duo_chat
- global_search
- groups_and_projects
- helm_chart_registry
@@ -79,7 +81,6 @@
- insider_threat
- instance_resiliency
- integrations
-- intel_code_security
- interactive_application_security_testing
- internationalization
- logging
@@ -110,7 +111,6 @@
- remote_development
- requirements_management
- review_apps
-- runbooks
- runner
- runner_fleet
- runner_saas
@@ -140,4 +140,3 @@
- web_ide
- webhooks
- wiki
-- workflow_automation
diff --git a/config/feature_flags/development/abuse_report_labels.yml b/config/feature_flags/development/abuse_report_labels.yml
new file mode 100644
index 00000000000..4a600b08230
--- /dev/null
+++ b/config/feature_flags/development/abuse_report_labels.yml
@@ -0,0 +1,8 @@
+---
+name: abuse_report_labels
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128701/
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421373
+milestone: '16.4'
+type: development
+group: group::anti-abuse
+default_enabled: false
diff --git a/config/feature_flags/development/abuse_reports_list.yml b/config/feature_flags/development/abuse_reports_list.yml
deleted file mode 100644
index 21954797720..00000000000
--- a/config/feature_flags/development/abuse_reports_list.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: abuse_reports_list
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110205
-rollout_issue_url:
-milestone: '15.10'
-type: development
-group: group::anti-abuse
-default_enabled: false
diff --git a/config/feature_flags/development/action_cable_notes.yml b/config/feature_flags/development/action_cable_notes.yml
deleted file mode 100644
index d41b1e444eb..00000000000
--- a/config/feature_flags/development/action_cable_notes.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: action_cable_notes
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127964
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/412823
-milestone: '16.3'
-type: development
-group: group::project management
-default_enabled: false
diff --git a/config/feature_flags/development/activity_pub.yml b/config/feature_flags/development/activity_pub.yml
new file mode 100644
index 00000000000..0a7cf9862a5
--- /dev/null
+++ b/config/feature_flags/development/activity_pub.yml
@@ -0,0 +1,8 @@
+---
+name: activity_pub
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424008
+milestone: '16.4'
+type: development
+group: group::source code
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/activity_pub_project.yml b/config/feature_flags/development/activity_pub_project.yml
new file mode 100644
index 00000000000..6630333ad5e
--- /dev/null
+++ b/config/feature_flags/development/activity_pub_project.yml
@@ -0,0 +1,8 @@
+---
+name: activity_pub_project
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424008
+milestone: '16.4'
+type: development
+group: group::source code
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/add_prepared_state_to_mr.yml b/config/feature_flags/development/add_prepared_state_to_mr.yml
deleted file mode 100644
index 49db6d92ae0..00000000000
--- a/config/feature_flags/development/add_prepared_state_to_mr.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: add_prepared_state_to_mr
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109967
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389249
-milestone: '15.9'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/admin_jobs_vue.yml b/config/feature_flags/development/admin_jobs_vue.yml
deleted file mode 100644
index 3c8402a83f4..00000000000
--- a/config/feature_flags/development/admin_jobs_vue.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: admin_jobs_vue
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98769
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/391194
-milestone: '15.9'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/advanced_search_decrease_indexing_timeout.yml b/config/feature_flags/development/advanced_search_decrease_indexing_timeout.yml
deleted file mode 100644
index bb6b4914b9e..00000000000
--- a/config/feature_flags/development/advanced_search_decrease_indexing_timeout.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: advanced_search_decrease_indexing_timeout
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111902
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/391570
-milestone: '15.9'
-type: development
-group: group::global search
-default_enabled: true
diff --git a/config/feature_flags/development/ai_tool_info.yml b/config/feature_flags/development/ai_tool_info.yml
new file mode 100644
index 00000000000..7fb41f05ab7
--- /dev/null
+++ b/config/feature_flags/development/ai_tool_info.yml
@@ -0,0 +1,8 @@
+---
+name: ai_tool_info
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128501
+rollout_issue_url:
+milestone: '16.3'
+type: development
+group: group::ai framework
+default_enabled: false
diff --git a/config/feature_flags/development/anthropic_experimentation.yml b/config/feature_flags/development/anthropic_experimentation.yml
deleted file mode 100644
index 8d4f2200532..00000000000
--- a/config/feature_flags/development/anthropic_experimentation.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: anthropic_experimentation
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119729
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/409939
-milestone: '16.0'
-type: development
-group: group::ai-enablement
-default_enabled: false
diff --git a/config/feature_flags/development/api_keyset_pagination_multi_order.yml b/config/feature_flags/development/api_keyset_pagination_multi_order.yml
new file mode 100644
index 00000000000..6fa174e9814
--- /dev/null
+++ b/config/feature_flags/development/api_keyset_pagination_multi_order.yml
@@ -0,0 +1,8 @@
+---
+name: api_keyset_pagination_multi_order
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130019
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422999
+milestone: '16.5'
+type: development
+group: group::authentication and authorization
+default_enabled: false
diff --git a/config/feature_flags/development/batched_api_mergeability_checks.yml b/config/feature_flags/development/batched_api_mergeability_checks.yml
deleted file mode 100644
index 92c681cb2c7..00000000000
--- a/config/feature_flags/development/batched_api_mergeability_checks.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: batched_api_mergeability_checks
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121980
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/413232
-milestone: '16.1'
-type: development
-group: group::code review
-default_enabled: true
diff --git a/config/feature_flags/development/bitbucket_parallel_importer.yml b/config/feature_flags/development/bitbucket_parallel_importer.yml
new file mode 100644
index 00000000000..6edadec4d3b
--- /dev/null
+++ b/config/feature_flags/development/bitbucket_parallel_importer.yml
@@ -0,0 +1,8 @@
+---
+name: bitbucket_parallel_importer
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130731
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423530
+milestone: '16.4'
+type: development
+group: group::import and integrate
+default_enabled: false
diff --git a/config/feature_flags/development/bitbucket_server_parallel_importer.yml b/config/feature_flags/development/bitbucket_server_parallel_importer.yml
deleted file mode 100644
index be553a5e6da..00000000000
--- a/config/feature_flags/development/bitbucket_server_parallel_importer.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: bitbucket_server_parallel_importer
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120931
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/411796
-milestone: '16.1'
-type: development
-group: group::import and integrate
-default_enabled: true
diff --git a/config/feature_flags/development/browsersdk_tracking.yml b/config/feature_flags/development/browsersdk_tracking.yml
new file mode 100644
index 00000000000..688d559904b
--- /dev/null
+++ b/config/feature_flags/development/browsersdk_tracking.yml
@@ -0,0 +1,8 @@
+---
+name: browsersdk_tracking
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129517
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422264
+milestone: '16.4'
+type: development
+group: group::analytics instrumentation
+default_enabled: false
diff --git a/config/feature_flags/development/cache_pages_domain_api.yml b/config/feature_flags/development/cache_pages_domain_api.yml
deleted file mode 100644
index 409497aa22d..00000000000
--- a/config/feature_flags/development/cache_pages_domain_api.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: cache_pages_domain_api
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88956
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364127
-milestone: '15.2'
-type: development
-group: group::editor
-default_enabled: false
diff --git a/config/feature_flags/development/ci_editor_assistant_tool.yml b/config/feature_flags/development/ci_editor_assistant_tool.yml
new file mode 100644
index 00000000000..433fae3aed6
--- /dev/null
+++ b/config/feature_flags/development/ci_editor_assistant_tool.yml
@@ -0,0 +1,8 @@
+---
+name: ci_editor_assistant_tool
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130162
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423524
+milestone: '16.4'
+type: development
+group: group::environments
+default_enabled: false
diff --git a/config/feature_flags/development/ci_partitioning_use_ci_builds_routing_table.yml b/config/feature_flags/development/ci_partitioning_use_ci_builds_routing_table.yml
deleted file mode 100644
index 97bacb21e38..00000000000
--- a/config/feature_flags/development/ci_partitioning_use_ci_builds_routing_table.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_partitioning_use_ci_builds_routing_table
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122919
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421180
-milestone: '16.3'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/ci_refactor_external_rules.yml b/config/feature_flags/development/ci_refactor_external_rules.yml
deleted file mode 100644
index 117bff63648..00000000000
--- a/config/feature_flags/development/ci_refactor_external_rules.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_refactor_external_rules
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129145
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421731
-milestone: '16.3'
-type: development
-group: group::pipeline authoring
-default_enabled: false
diff --git a/config/feature_flags/development/clickhouse_ci_analytics.yml b/config/feature_flags/development/clickhouse_ci_analytics.yml
new file mode 100644
index 00000000000..e56d2e19036
--- /dev/null
+++ b/config/feature_flags/development/clickhouse_ci_analytics.yml
@@ -0,0 +1,8 @@
+---
+name: clickhouse_ci_analytics
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130211
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424498
+milestone: '16.4'
+type: development
+group: group::runner
+default_enabled: false
diff --git a/config/feature_flags/development/code_quality_inline_drawer.yml b/config/feature_flags/development/code_quality_inline_drawer.yml
deleted file mode 100644
index 0af4c98ada8..00000000000
--- a/config/feature_flags/development/code_quality_inline_drawer.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: code_quality_inline_drawer
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114649
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/397037
-milestone: '15.11'
-type: development
-group: group::static analysis
-default_enabled: false
diff --git a/config/feature_flags/development/code_suggestions_tokens_from_customers_dot.yml b/config/feature_flags/development/code_suggestions_tokens_from_customers_dot.yml
deleted file mode 100644
index e91d069ba3c..00000000000
--- a/config/feature_flags/development/code_suggestions_tokens_from_customers_dot.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: code_suggestions_tokens_from_customers_dot
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125405
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/417762
-milestone: '16.3'
-type: development
-group: group::application performance
-default_enabled: true
diff --git a/config/feature_flags/development/collect_all_diff_paths.yml b/config/feature_flags/development/collect_all_diff_paths.yml
new file mode 100644
index 00000000000..d382889fe16
--- /dev/null
+++ b/config/feature_flags/development/collect_all_diff_paths.yml
@@ -0,0 +1,8 @@
+---
+name: collect_all_diff_paths
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124907
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421460
+milestone: '16.4'
+type: development
+group: "group::gitaly"
+default_enabled: false
diff --git a/config/feature_flags/development/combined_analytics_visualization_editor.yml b/config/feature_flags/development/combined_analytics_visualization_editor.yml
new file mode 100644
index 00000000000..7d465952c3d
--- /dev/null
+++ b/config/feature_flags/development/combined_analytics_visualization_editor.yml
@@ -0,0 +1,8 @@
+---
+name: combined_analytics_visualization_editor
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131634
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/425048
+milestone: '16.4'
+type: development
+group: group::product analytics
+default_enabled: false
diff --git a/config/feature_flags/development/command_palette.yml b/config/feature_flags/development/command_palette.yml
deleted file mode 100644
index 3a7935e6bf5..00000000000
--- a/config/feature_flags/development/command_palette.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: command_palette
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121932
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/413060
-milestone: '16.1'
-type: development
-group: group::foundations
-default_enabled: true
diff --git a/config/feature_flags/development/compliance_pipeline_in_policies.yml b/config/feature_flags/development/compliance_pipeline_in_policies.yml
new file mode 100644
index 00000000000..97432fe2872
--- /dev/null
+++ b/config/feature_flags/development/compliance_pipeline_in_policies.yml
@@ -0,0 +1,8 @@
+---
+name: compliance_pipeline_in_policies
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126457
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424185
+milestone: '16.4'
+type: development
+group: group::security policies
+default_enabled: false
diff --git a/config/feature_flags/development/composer_use_ssh_source_urls.yml b/config/feature_flags/development/composer_use_ssh_source_urls.yml
new file mode 100644
index 00000000000..26111623ea3
--- /dev/null
+++ b/config/feature_flags/development/composer_use_ssh_source_urls.yml
@@ -0,0 +1,8 @@
+---
+name: composer_use_ssh_source_urls
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119739
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422171
+milestone: '16.4'
+type: development
+group: group::package registry
+default_enabled: false
diff --git a/config/feature_flags/development/copy_additional_properties_approval_rules.yml b/config/feature_flags/development/copy_additional_properties_approval_rules.yml
new file mode 100644
index 00000000000..0f8e076620a
--- /dev/null
+++ b/config/feature_flags/development/copy_additional_properties_approval_rules.yml
@@ -0,0 +1,8 @@
+---
+name: copy_additional_properties_approval_rules
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128259
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423517
+milestone: '16.4'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/create_embeddings_with_vertex_ai.yml b/config/feature_flags/development/create_embeddings_with_vertex_ai.yml
new file mode 100644
index 00000000000..327961d971e
--- /dev/null
+++ b/config/feature_flags/development/create_embeddings_with_vertex_ai.yml
@@ -0,0 +1,8 @@
+---
+name: create_embeddings_with_vertex_ai
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129930
+rollout_issue_url:
+milestone: '16.4'
+type: development
+group: group::duo chat
+default_enabled: false
diff --git a/config/feature_flags/development/custom_roles_in_members_page.yml b/config/feature_flags/development/custom_roles_in_members_page.yml
new file mode 100644
index 00000000000..cb6bea5ca42
--- /dev/null
+++ b/config/feature_flags/development/custom_roles_in_members_page.yml
@@ -0,0 +1,8 @@
+---
+name: custom_roles_in_members_page
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128491
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422897
+milestone: '16.3'
+type: development
+group: group::authentication and authorization
+default_enabled: false
diff --git a/config/feature_flags/development/custom_roles_ui_saas.yml b/config/feature_flags/development/custom_roles_ui_saas.yml
new file mode 100644
index 00000000000..ea4925eb322
--- /dev/null
+++ b/config/feature_flags/development/custom_roles_ui_saas.yml
@@ -0,0 +1,8 @@
+---
+name: custom_roles_ui_saas
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130089
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423077
+milestone: '16.4'
+type: development
+group: group::authentication and authorization
+default_enabled: true
diff --git a/config/feature_flags/development/database_analyze_on_partitioned_tables.yml b/config/feature_flags/development/database_analyze_on_partitioned_tables.yml
new file mode 100644
index 00000000000..1d11d3dade3
--- /dev/null
+++ b/config/feature_flags/development/database_analyze_on_partitioned_tables.yml
@@ -0,0 +1,8 @@
+---
+name: database_analyze_on_partitioned_tables
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130599
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423959
+milestone: '16.4'
+type: development
+group: group::database
+default_enabled: false
diff --git a/config/feature_flags/development/emoji_webhooks.yml b/config/feature_flags/development/emoji_webhooks.yml
index 98d1918d365..3c84f19ab48 100644
--- a/config/feature_flags/development/emoji_webhooks.yml
+++ b/config/feature_flags/development/emoji_webhooks.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/417288
milestone: '16.2'
type: development
group: group::import and integrate
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/ensure_merge_requests_prepared.yml b/config/feature_flags/development/ensure_merge_requests_prepared.yml
new file mode 100644
index 00000000000..cedfe69b552
--- /dev/null
+++ b/config/feature_flags/development/ensure_merge_requests_prepared.yml
@@ -0,0 +1,8 @@
+---
+name: ensure_merge_requests_prepared
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121999
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/413884
+milestone: '16.4'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/environment_details_vue.yml b/config/feature_flags/development/environment_details_vue.yml
deleted file mode 100644
index c90038a600c..00000000000
--- a/config/feature_flags/development/environment_details_vue.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: environment_details_vue
-introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105527"
-rollout_issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/384914"
-milestone: '15.7'
-type: development
-group: group::configure
-default_enabled: true
diff --git a/config/feature_flags/development/epic_relations_for_non_members.yml b/config/feature_flags/development/epic_relations_for_non_members.yml
new file mode 100644
index 00000000000..3e0d3fdb577
--- /dev/null
+++ b/config/feature_flags/development/epic_relations_for_non_members.yml
@@ -0,0 +1,8 @@
+---
+name: epic_relations_for_non_members
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128242
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424704
+milestone: '16.4'
+type: development
+group: group::product planning
+default_enabled: false
diff --git a/config/feature_flags/development/errors_utf_8_encoding.yml b/config/feature_flags/development/errors_utf_8_encoding.yml
new file mode 100644
index 00000000000..50ecd0ad664
--- /dev/null
+++ b/config/feature_flags/development/errors_utf_8_encoding.yml
@@ -0,0 +1,8 @@
+---
+name: errors_utf_8_encoding
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129217
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422061
+milestone: '16.4'
+type: development
+group: group::source code
+default_enabled: true
diff --git a/config/feature_flags/development/explain_vulnerability_anthropic.yml b/config/feature_flags/development/explain_vulnerability_anthropic.yml
new file mode 100644
index 00000000000..8e5ee714046
--- /dev/null
+++ b/config/feature_flags/development/explain_vulnerability_anthropic.yml
@@ -0,0 +1,8 @@
+---
+name: explain_vulnerability_anthropic
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128118
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420608
+milestone: '16.4'
+type: development
+group: group::threat insights
+default_enabled: false
diff --git a/config/feature_flags/development/explain_vulnerability_vertex.yml b/config/feature_flags/development/explain_vulnerability_vertex.yml
deleted file mode 100644
index f93be4fc22c..00000000000
--- a/config/feature_flags/development/explain_vulnerability_vertex.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: explain_vulnerability_vertex
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118754
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/409182
-milestone: '16.0'
-type: development
-group: group::threat insights
-default_enabled: false
diff --git a/config/feature_flags/development/fill_in_mr_template.yml b/config/feature_flags/development/fill_in_mr_template.yml
index 871d2d09f2e..a40ddc24ed2 100644
--- a/config/feature_flags/development/fill_in_mr_template.yml
+++ b/config/feature_flags/development/fill_in_mr_template.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/412796
milestone: '16.1'
type: development
group: group::code review
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/flux_resource_for_environment.yml b/config/feature_flags/development/flux_resource_for_environment.yml
deleted file mode 100644
index bcc6afbf63b..00000000000
--- a/config/feature_flags/development/flux_resource_for_environment.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: flux_resource_for_environment
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128857
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421416
-milestone: '16.3'
-type: development
-group: group::environments
-default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/graphql_git_blame.yml b/config/feature_flags/development/graphql_git_blame.yml
new file mode 100644
index 00000000000..c6aad748ef8
--- /dev/null
+++ b/config/feature_flags/development/graphql_git_blame.yml
@@ -0,0 +1,8 @@
+---
+name: graphql_git_blame
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128103
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419808
+milestone: "16.3"
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/graphql_job_trace_html_summary_max_size.yml b/config/feature_flags/development/graphql_job_trace_html_summary_max_size.yml
new file mode 100644
index 00000000000..88e99afddf3
--- /dev/null
+++ b/config/feature_flags/development/graphql_job_trace_html_summary_max_size.yml
@@ -0,0 +1,7 @@
+name: graphql_job_trace_html_summary_max_size
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130984
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/425196
+milestone: '16.5'
+group: group::pipeline execution
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/group_mentions.yml b/config/feature_flags/development/group_mentions.yml
deleted file mode 100644
index 4f536b2b583..00000000000
--- a/config/feature_flags/development/group_mentions.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: group_mentions
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96684
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414856
-milestone: '16.2'
-type: development
-group: group::import and integrate
-default_enabled: false
diff --git a/config/feature_flags/development/harbor_registry_integration.yml b/config/feature_flags/development/harbor_registry_integration.yml
deleted file mode 100644
index f1786f53c19..00000000000
--- a/config/feature_flags/development/harbor_registry_integration.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: harbor_registry_integration
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81593
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/353595
-milestone: '14.9'
-type: development
-group: group::container registry
-default_enabled: false
diff --git a/config/feature_flags/development/introduce_ci_max_total_yaml_size_bytes.yml b/config/feature_flags/development/introduce_ci_max_total_yaml_size_bytes.yml
deleted file mode 100644
index e52eac5d748..00000000000
--- a/config/feature_flags/development/introduce_ci_max_total_yaml_size_bytes.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: introduce_ci_max_total_yaml_size_bytes
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123129
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419561
-milestone: '16.3'
-type: development
-group: group::pipeline authoring
-default_enabled: false
diff --git a/config/feature_flags/development/k8s_dashboard.yml b/config/feature_flags/development/k8s_dashboard.yml
new file mode 100644
index 00000000000..1969dce4c2d
--- /dev/null
+++ b/config/feature_flags/development/k8s_dashboard.yml
@@ -0,0 +1,8 @@
+---
+name: k8s_dashboard
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130953"
+rollout_issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/424237"
+milestone: '16.4'
+type: development
+group: group::environments
+default_enabled: false
diff --git a/config/feature_flags/development/k8s_proxy_pat.yml b/config/feature_flags/development/k8s_proxy_pat.yml
new file mode 100644
index 00000000000..ef9101b9354
--- /dev/null
+++ b/config/feature_flags/development/k8s_proxy_pat.yml
@@ -0,0 +1,8 @@
+---
+name: k8s_proxy_pat
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129661
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422961
+milestone: '16.4'
+type: development
+group: group::environments
+default_enabled: true
diff --git a/config/feature_flags/development/keep_merge_commits_for_approvals.yml b/config/feature_flags/development/keep_merge_commits_for_approvals.yml
deleted file mode 100644
index a4791219dff..00000000000
--- a/config/feature_flags/development/keep_merge_commits_for_approvals.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: keep_merge_commits_for_approvals
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127744
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419921
-milestone: '16.3'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/limited_access_modal.yml b/config/feature_flags/development/limited_access_modal.yml
new file mode 100644
index 00000000000..c9800da0d6c
--- /dev/null
+++ b/config/feature_flags/development/limited_access_modal.yml
@@ -0,0 +1,8 @@
+---
+name: limited_access_modal
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129790
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424877
+milestone: '16.4'
+type: development
+group: group::billing and subscription management
+default_enabled: false
diff --git a/config/feature_flags/development/loose_foreign_keys_batch_load_using_union.yml b/config/feature_flags/development/loose_foreign_keys_batch_load_using_union.yml
index 0b0ed16c1cd..4e4a1e262b0 100644
--- a/config/feature_flags/development/loose_foreign_keys_batch_load_using_union.yml
+++ b/config/feature_flags/development/loose_foreign_keys_batch_load_using_union.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421422
milestone: '16.3'
type: development
group: group::tenant scale
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/lower_interval_for_canceling_redundant_pipelines.yml b/config/feature_flags/development/lower_interval_for_canceling_redundant_pipelines.yml
deleted file mode 100644
index 49f79bbf36f..00000000000
--- a/config/feature_flags/development/lower_interval_for_canceling_redundant_pipelines.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: lower_interval_for_canceling_redundant_pipelines
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129256
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421925
-milestone: '16.3'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/member_expiring_email_notification.yml b/config/feature_flags/development/member_expiring_email_notification.yml
index 1775cc67b52..36a15c27daf 100644
--- a/config/feature_flags/development/member_expiring_email_notification.yml
+++ b/config/feature_flags/development/member_expiring_email_notification.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/416581
milestone: '16.3'
type: development
group: group::authentication and authorization
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/merge_request_refs_cleanup.yml b/config/feature_flags/development/merge_request_refs_cleanup.yml
index 7df06ccc52f..e306dd89c93 100644
--- a/config/feature_flags/development/merge_request_refs_cleanup.yml
+++ b/config/feature_flags/development/merge_request_refs_cleanup.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/336070
milestone: '13.8'
type: development
group: group::code review
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/merge_trains_create_ref_service.yml b/config/feature_flags/development/merge_trains_create_ref_service.yml
index cd649589a93..cdbe6813210 100644
--- a/config/feature_flags/development/merge_trains_create_ref_service.yml
+++ b/config/feature_flags/development/merge_trains_create_ref_service.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420161
milestone: '16.3'
type: development
group: group::pipeline execution
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/merge_trains_skip_train.yml b/config/feature_flags/development/merge_trains_skip_train.yml
new file mode 100644
index 00000000000..3d60acef457
--- /dev/null
+++ b/config/feature_flags/development/merge_trains_skip_train.yml
@@ -0,0 +1,8 @@
+---
+name: merge_trains_skip_train
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129422
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422111
+milestone: '16.4'
+type: development
+group: group::pipeline execution
+default_enabled: false
diff --git a/config/feature_flags/development/mr_pipelines_graphql.yml b/config/feature_flags/development/mr_pipelines_graphql.yml
new file mode 100644
index 00000000000..749de057e21
--- /dev/null
+++ b/config/feature_flags/development/mr_pipelines_graphql.yml
@@ -0,0 +1,8 @@
+---
+name: mr_pipelines_graphql
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128929
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419726
+milestone: '16.4'
+type: development
+group: group::pipeline authoring
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/namespace_storage_forks_cost_factor.yml b/config/feature_flags/development/namespace_storage_forks_cost_factor.yml
deleted file mode 100644
index 60b4980389b..00000000000
--- a/config/feature_flags/development/namespace_storage_forks_cost_factor.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: namespace_storage_forks_cost_factor
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126775
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419181
-milestone: '16.3'
-type: development
-group: group::utilization
-default_enabled: false
diff --git a/config/feature_flags/development/new_graphql_users_autocomplete.yml b/config/feature_flags/development/new_graphql_users_autocomplete.yml
deleted file mode 100644
index 3347c17a777..00000000000
--- a/config/feature_flags/development/new_graphql_users_autocomplete.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: new_graphql_users_autocomplete
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129348
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/417757
-milestone: '16.3'
-type: development
-group: group::project management
-default_enabled: false
diff --git a/config/feature_flags/development/npm_package_registry_fix_group_path_validation.yml b/config/feature_flags/development/npm_package_registry_fix_group_path_validation.yml
deleted file mode 100644
index 36132703d28..00000000000
--- a/config/feature_flags/development/npm_package_registry_fix_group_path_validation.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: npm_package_registry_fix_group_path_validation
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127164
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420160
-milestone: '16.3'
-type: development
-group: group::package registry
-default_enabled: false
diff --git a/config/feature_flags/development/nuget_normalized_version.yml b/config/feature_flags/development/nuget_normalized_version.yml
deleted file mode 100644
index a99a8dbc752..00000000000
--- a/config/feature_flags/development/nuget_normalized_version.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: nuget_normalized_version
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121260
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420290
-milestone: '16.3'
-type: development
-group: group::package registry
-default_enabled: false
diff --git a/config/feature_flags/development/okr_checkin_reminders.yml b/config/feature_flags/development/okr_checkin_reminders.yml
new file mode 100644
index 00000000000..c1941700919
--- /dev/null
+++ b/config/feature_flags/development/okr_checkin_reminders.yml
@@ -0,0 +1,8 @@
+---
+name: okr_checkin_reminders
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130371
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424235
+milestone: '16.4'
+type: development
+group: group::incubation
+default_enabled: false
diff --git a/config/feature_flags/development/optimize_group_template_query.yml b/config/feature_flags/development/optimize_group_template_query.yml
new file mode 100644
index 00000000000..68cd7bb1e03
--- /dev/null
+++ b/config/feature_flags/development/optimize_group_template_query.yml
@@ -0,0 +1,8 @@
+---
+name: optimize_group_template_query
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129399
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422390
+milestone: '16.4'
+type: development
+group: group::source code
+default_enabled: true
diff --git a/config/feature_flags/development/optimize_routable.yml b/config/feature_flags/development/optimize_routable.yml
new file mode 100644
index 00000000000..1191d389fa2
--- /dev/null
+++ b/config/feature_flags/development/optimize_routable.yml
@@ -0,0 +1,8 @@
+---
+name: optimize_routable
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130842
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424138
+milestone: '16.4'
+type: development
+group: group::tenant scale
+default_enabled: false
diff --git a/config/feature_flags/development/pages_multiple_versions_setting.yml b/config/feature_flags/development/pages_multiple_versions_setting.yml
new file mode 100644
index 00000000000..96fc1350b59
--- /dev/null
+++ b/config/feature_flags/development/pages_multiple_versions_setting.yml
@@ -0,0 +1,8 @@
+---
+name: pages_multiple_versions_setting
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127142
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422145
+milestone: '16.4'
+type: development
+group: group::knowledge
+default_enabled: false
diff --git a/config/feature_flags/development/pipeline_schedules_vue.yml b/config/feature_flags/development/pipeline_schedules_vue.yml
deleted file mode 100644
index 69106660c35..00000000000
--- a/config/feature_flags/development/pipeline_schedules_vue.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: pipeline_schedules_vue
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99155
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375139
-milestone: '15.5'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/post_import_repository_size_check.yml b/config/feature_flags/development/post_import_repository_size_check.yml
deleted file mode 100644
index a51e9085b9b..00000000000
--- a/config/feature_flags/development/post_import_repository_size_check.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: post_import_repository_size_check
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122814
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414530
-milestone: '16.1'
-type: development
-group: group::import and integrate
-default_enabled: false
diff --git a/config/feature_flags/development/prevent_visibility_restriction.yml b/config/feature_flags/development/prevent_visibility_restriction.yml
index 9f5b82b6f69..09b082952c3 100644
--- a/config/feature_flags/development/prevent_visibility_restriction.yml
+++ b/config/feature_flags/development/prevent_visibility_restriction.yml
@@ -5,4 +5,4 @@ rollout_issue_url:
milestone: '16.3'
type: development
group: group::acquisition
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/product_analytics_snowplow_support.yml b/config/feature_flags/development/product_analytics_snowplow_support.yml
deleted file mode 100644
index f3684a3f26b..00000000000
--- a/config/feature_flags/development/product_analytics_snowplow_support.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: product_analytics_snowplow_support
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116317
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/403418
-milestone: '15.11'
-type: development
-group: group::product analytics
-default_enabled: false
diff --git a/config/feature_flags/development/project_runners_vue_ui.yml b/config/feature_flags/development/project_runners_vue_ui.yml
deleted file mode 100644
index a628b1a4ac3..00000000000
--- a/config/feature_flags/development/project_runners_vue_ui.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: project_runners_vue_ui
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107646
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386573
-milestone: '15.8'
-type: development
-group: group::runner
-default_enabled: false
diff --git a/config/feature_flags/development/refactor_merge_service.yml b/config/feature_flags/development/refactor_merge_service.yml
deleted file mode 100644
index cb0734cf71c..00000000000
--- a/config/feature_flags/development/refactor_merge_service.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: refactor_merge_service
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128177
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420949
-milestone: '16.3'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/resolvable_issue_threads.yml b/config/feature_flags/development/resolvable_issue_threads.yml
index f08c4950800..f3c2911ac4c 100644
--- a/config/feature_flags/development/resolvable_issue_threads.yml
+++ b/config/feature_flags/development/resolvable_issue_threads.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419893
milestone: '16.3'
type: development
group: group::project management
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/resolve_organization_groups.yml b/config/feature_flags/development/resolve_organization_groups.yml
new file mode 100644
index 00000000000..7a70c8568a6
--- /dev/null
+++ b/config/feature_flags/development/resolve_organization_groups.yml
@@ -0,0 +1,8 @@
+---
+name: resolve_organization_groups
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128733
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421673
+milestone: '16.3'
+type: development
+group: group::tenant scale
+default_enabled: true
diff --git a/config/feature_flags/development/review_apps_redeploy_mr_widget.yml b/config/feature_flags/development/review_apps_redeploy_mr_widget.yml
deleted file mode 100644
index c533e8abd9a..00000000000
--- a/config/feature_flags/development/review_apps_redeploy_mr_widget.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: review_apps_redeploy_mr_widget
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118260
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/407456
-milestone: '15.11'
-type: development
-group: group::pipeline execution
-default_enabled: true
diff --git a/config/feature_flags/development/scan_execution_bot_users.yml b/config/feature_flags/development/scan_execution_bot_users.yml
deleted file mode 100644
index ca06e666e67..00000000000
--- a/config/feature_flags/development/scan_execution_bot_users.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: scan_execution_bot_users
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118089
-rollout_issue_url:
-milestone: '16.0'
-type: development
-group: group::security policies
-default_enabled: true
diff --git a/config/feature_flags/development/search_index_integrity.yml b/config/feature_flags/development/search_index_integrity.yml
deleted file mode 100644
index 87a9536fede..00000000000
--- a/config/feature_flags/development/search_index_integrity.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: search_index_integrity
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112369
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/392981
-milestone: '15.10'
-type: development
-group: group::global search
-default_enabled: true
diff --git a/config/feature_flags/development/search_issues_hide_archived_projects.yml b/config/feature_flags/development/search_issues_hide_archived_projects.yml
new file mode 100644
index 00000000000..68a6d058e81
--- /dev/null
+++ b/config/feature_flags/development/search_issues_hide_archived_projects.yml
@@ -0,0 +1,8 @@
+---
+name: search_issues_hide_archived_projects
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124846
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/416483
+milestone: '16.2'
+type: development
+group: group::global search
+default_enabled: false
diff --git a/config/feature_flags/development/search_milestones_hide_archived_projects.yml b/config/feature_flags/development/search_milestones_hide_archived_projects.yml
new file mode 100644
index 00000000000..859a92e5dec
--- /dev/null
+++ b/config/feature_flags/development/search_milestones_hide_archived_projects.yml
@@ -0,0 +1,9 @@
+---
+name: search_milestones_hide_archived_projects
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130937
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424256
+milestone: '16.4'
+type: development
+group: group::global search
+default_enabled: false
+
diff --git a/config/feature_flags/development/search_projects_hide_archived.yml b/config/feature_flags/development/search_projects_hide_archived.yml
deleted file mode 100644
index 9d2e5b1a74c..00000000000
--- a/config/feature_flags/development/search_projects_hide_archived.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: search_projects_hide_archived
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122332
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/413821
-milestone: '16.1'
-type: development
-group: group::global search
-default_enabled: false
diff --git a/config/feature_flags/development/self_managed_code_suggestions_completion_api.yml b/config/feature_flags/development/self_managed_code_suggestions_completion_api.yml
deleted file mode 100644
index a0321e1f145..00000000000
--- a/config/feature_flags/development/self_managed_code_suggestions_completion_api.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: self_managed_code_suggestions_completion_api
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125563
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/418795
-milestone: '16.3'
-type: development
-group: group::application performance
-default_enabled: true
diff --git a/config/feature_flags/development/server_side_frecent_namespaces.yml b/config/feature_flags/development/server_side_frecent_namespaces.yml
new file mode 100644
index 00000000000..d9d4c37789c
--- /dev/null
+++ b/config/feature_flags/development/server_side_frecent_namespaces.yml
@@ -0,0 +1,8 @@
+---
+name: server_side_frecent_namespaces
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123554
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/417256
+milestone: '16.4'
+type: development
+group: group::foundations
+default_enabled: false
diff --git a/config/feature_flags/development/service_desk_custom_email.yml b/config/feature_flags/development/service_desk_custom_email.yml
index 42bac76033c..c23dd713da1 100644
--- a/config/feature_flags/development/service_desk_custom_email.yml
+++ b/config/feature_flags/development/service_desk_custom_email.yml
@@ -5,5 +5,5 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/329990
milestone: '15.9'
type: development
group: group::incubation
-default_enabled: false
+default_enabled: true
log_state_changes: true
diff --git a/config/feature_flags/development/service_desk_custom_email_reply.yml b/config/feature_flags/development/service_desk_custom_email_reply.yml
new file mode 100644
index 00000000000..37720f9d682
--- /dev/null
+++ b/config/feature_flags/development/service_desk_custom_email_reply.yml
@@ -0,0 +1,8 @@
+---
+name: service_desk_custom_email_reply
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130336
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423880
+milestone: '16.4'
+type: development
+group: group::incubation
+default_enabled: true
diff --git a/config/feature_flags/development/skip_validations_during_transitions.yml b/config/feature_flags/development/skip_validations_during_transitions.yml
new file mode 100644
index 00000000000..53cf5f5ee71
--- /dev/null
+++ b/config/feature_flags/development/skip_validations_during_transitions.yml
@@ -0,0 +1,8 @@
+---
+name: skip_validations_during_transitions
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129848
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423092
+milestone: '16.4'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/ssh_certificates_rest_endpoints.yml b/config/feature_flags/development/ssh_certificates_rest_endpoints.yml
new file mode 100644
index 00000000000..29087a8631f
--- /dev/null
+++ b/config/feature_flags/development/ssh_certificates_rest_endpoints.yml
@@ -0,0 +1,8 @@
+---
+name: ssh_certificates_rest_endpoints
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130866
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424501
+milestone: '16.4'
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/standard_merge_train_ref_merge_commit.yml b/config/feature_flags/development/standard_merge_train_ref_merge_commit.yml
new file mode 100644
index 00000000000..a9fba90a264
--- /dev/null
+++ b/config/feature_flags/development/standard_merge_train_ref_merge_commit.yml
@@ -0,0 +1,8 @@
+---
+name: standard_merge_train_ref_merge_commit
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129820
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422724
+milestone: '16.4'
+type: development
+group: group::pipeline execution
+default_enabled: true
diff --git a/config/feature_flags/development/summarize_review_vertex.yml b/config/feature_flags/development/summarize_review_vertex.yml
deleted file mode 100644
index 57ceae2e7e8..00000000000
--- a/config/feature_flags/development/summarize_review_vertex.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: summarize_review_vertex
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127190
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419374
-milestone: '16.3'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/super_sidebar_flyout_menus.yml b/config/feature_flags/development/super_sidebar_flyout_menus.yml
deleted file mode 100644
index 6bec0ef60df..00000000000
--- a/config/feature_flags/development/super_sidebar_flyout_menus.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: super_sidebar_flyout_menus
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124863
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/417237
-milestone: '16.2'
-type: development
-group: group::foundations
-default_enabled: false
diff --git a/config/feature_flags/development/ultimate_feature_removal_banner.yml b/config/feature_flags/development/ultimate_feature_removal_banner.yml
deleted file mode 100644
index 933e8ace9cc..00000000000
--- a/config/feature_flags/development/ultimate_feature_removal_banner.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ultimate_feature_removal_banner
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94271
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371690
-milestone: '15.4'
-type: development
-group: group::tenant scale
-default_enabled: false
diff --git a/config/feature_flags/development/unbatch_graphql_queries.yml b/config/feature_flags/development/unbatch_graphql_queries.yml
index c5bc8c3033a..8a78a46c109 100644
--- a/config/feature_flags/development/unbatch_graphql_queries.yml
+++ b/config/feature_flags/development/unbatch_graphql_queries.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/406765
milestone: '16.0'
type: development
group: group::project management
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/use_merge_approval_rules_when_merged.yml b/config/feature_flags/development/use_merge_approval_rules_when_merged.yml
new file mode 100644
index 00000000000..1b7007a96df
--- /dev/null
+++ b/config/feature_flags/development/use_merge_approval_rules_when_merged.yml
@@ -0,0 +1,8 @@
+---
+name: use_merge_approval_rules_when_merged
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129165
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422380
+milestone: '16.4'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml b/config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml
index d4bb13550f8..72475948793 100644
--- a/config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml
+++ b/config/feature_flags/development/use_offset_pagination_for_canceling_redundant_pipelines.yml
@@ -1,8 +1,8 @@
---
name: use_offset_pagination_for_canceling_redundant_pipelines
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122764
-rollout_issue_url: use_offset_pagination_for_canceling_redundant_pipelines
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414459
milestone: '16.1'
type: development
group: group::optimize
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/use_primary_and_secondary_stores_for_action_cable.yml b/config/feature_flags/development/use_primary_and_secondary_stores_for_action_cable.yml
new file mode 100644
index 00000000000..50ffddd2c0c
--- /dev/null
+++ b/config/feature_flags/development/use_primary_and_secondary_stores_for_action_cable.yml
@@ -0,0 +1,8 @@
+---
+name: use_primary_and_secondary_stores_for_action_cable
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126451
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423216
+milestone: '16.4'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/feature_flags/development/use_primary_and_secondary_stores_for_etag_cache.yml b/config/feature_flags/development/use_primary_and_secondary_stores_for_etag_cache.yml
deleted file mode 100644
index dda420b590f..00000000000
--- a/config/feature_flags/development/use_primary_and_secondary_stores_for_etag_cache.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: use_primary_and_secondary_stores_for_etag_cache
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127705
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419889
-milestone: '16.3'
-type: development
-group: group::scalability
-default_enabled: false
diff --git a/config/feature_flags/development/use_primary_and_secondary_stores_for_queues_metadata.yml b/config/feature_flags/development/use_primary_and_secondary_stores_for_queues_metadata.yml
new file mode 100644
index 00000000000..abbeb5fcf57
--- /dev/null
+++ b/config/feature_flags/development/use_primary_and_secondary_stores_for_queues_metadata.yml
@@ -0,0 +1,8 @@
+---
+name: use_primary_and_secondary_stores_for_queues_metadata
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131736
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/425508
+milestone: '16.5'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/feature_flags/development/use_primary_and_secondary_stores_for_workhorse.yml b/config/feature_flags/development/use_primary_and_secondary_stores_for_workhorse.yml
new file mode 100644
index 00000000000..a5577c5d5d0
--- /dev/null
+++ b/config/feature_flags/development/use_primary_and_secondary_stores_for_workhorse.yml
@@ -0,0 +1,8 @@
+---
+name: use_primary_and_secondary_stores_for_workhorse
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127577
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423420
+milestone: '16.4'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/feature_flags/development/use_primary_store_as_default_for_action_cable.yml b/config/feature_flags/development/use_primary_store_as_default_for_action_cable.yml
new file mode 100644
index 00000000000..d5606516820
--- /dev/null
+++ b/config/feature_flags/development/use_primary_store_as_default_for_action_cable.yml
@@ -0,0 +1,8 @@
+---
+name: use_primary_store_as_default_for_action_cable
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126451
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423216
+milestone: '16.4'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/feature_flags/development/use_primary_store_as_default_for_etag_cache.yml b/config/feature_flags/development/use_primary_store_as_default_for_etag_cache.yml
deleted file mode 100644
index 889b64de068..00000000000
--- a/config/feature_flags/development/use_primary_store_as_default_for_etag_cache.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: use_primary_store_as_default_for_etag_cache
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127705
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419889
-milestone: '16.3'
-type: development
-group: group::scalability
-default_enabled: false
diff --git a/config/feature_flags/development/use_primary_store_as_default_for_queues_metadata.yml b/config/feature_flags/development/use_primary_store_as_default_for_queues_metadata.yml
new file mode 100644
index 00000000000..5c79998fd6a
--- /dev/null
+++ b/config/feature_flags/development/use_primary_store_as_default_for_queues_metadata.yml
@@ -0,0 +1,8 @@
+---
+name: use_primary_store_as_default_for_queues_metadata
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131736
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/425508
+milestone: '16.5'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/feature_flags/development/use_primary_store_as_default_for_workhorse.yml b/config/feature_flags/development/use_primary_store_as_default_for_workhorse.yml
new file mode 100644
index 00000000000..e6d21627035
--- /dev/null
+++ b/config/feature_flags/development/use_primary_store_as_default_for_workhorse.yml
@@ -0,0 +1,8 @@
+---
+name: use_primary_store_as_default_for_workhorse
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127577
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423420
+milestone: '16.4'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/feature_flags/development/value_stream_dashboard_on_off_setting.yml b/config/feature_flags/development/value_stream_dashboard_on_off_setting.yml
index 351cd72779d..a6023199d05 100644
--- a/config/feature_flags/development/value_stream_dashboard_on_off_setting.yml
+++ b/config/feature_flags/development/value_stream_dashboard_on_off_setting.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/411223
milestone: '16.1'
type: development
group: group::optimize
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/vite.yml b/config/feature_flags/development/vite.yml
new file mode 100644
index 00000000000..10242a665e7
--- /dev/null
+++ b/config/feature_flags/development/vite.yml
@@ -0,0 +1,8 @@
+---
+name: vite
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129392
+rollout_issue_url:
+milestone: '16.4'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/vulnerability_report_grouping.yml b/config/feature_flags/development/vulnerability_report_grouping.yml
new file mode 100644
index 00000000000..f5c445a3518
--- /dev/null
+++ b/config/feature_flags/development/vulnerability_report_grouping.yml
@@ -0,0 +1,8 @@
+---
+name: vulnerability_report_grouping
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129709
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/422509
+milestone: '16.4'
+type: development
+group: group::threat insights
+default_enabled: false
diff --git a/config/feature_flags/ops/admin_jobs_filter_runner_type.yml b/config/feature_flags/ops/admin_jobs_filter_runner_type.yml
new file mode 100644
index 00000000000..a7d45c5907c
--- /dev/null
+++ b/config/feature_flags/ops/admin_jobs_filter_runner_type.yml
@@ -0,0 +1,8 @@
+---
+name: admin_jobs_filter_runner_type
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123131
+rollout_issue_url: # No rollout: This is an ops-flag
+milestone: '16.4'
+type: ops
+group: group::runner
+default_enabled: false
diff --git a/config/feature_flags/ops/disallow_database_ddl_feature_flags.yml b/config/feature_flags/ops/disallow_database_ddl_feature_flags.yml
new file mode 100644
index 00000000000..4591c6aaf63
--- /dev/null
+++ b/config/feature_flags/ops/disallow_database_ddl_feature_flags.yml
@@ -0,0 +1,8 @@
+---
+name: disallow_database_ddl_feature_flags
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130554
+rollout_issue_url:
+milestone: '16.4'
+type: ops
+group: group::database
+default_enabled: false
diff --git a/config/feature_flags/ops/lock_tables_in_monitoring.yml b/config/feature_flags/ops/lock_tables_in_monitoring.yml
new file mode 100644
index 00000000000..5f6ffdff77b
--- /dev/null
+++ b/config/feature_flags/ops/lock_tables_in_monitoring.yml
@@ -0,0 +1,8 @@
+---
+name: lock_tables_in_monitoring
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129748
+rollout_issue_url:
+milestone: '16.4'
+type: ops
+group: group::tenant scale
+default_enabled: true
diff --git a/config/feature_flags/ops/loose_foreign_keys_turbo_mode_ci.yml b/config/feature_flags/ops/loose_foreign_keys_turbo_mode_ci.yml
new file mode 100644
index 00000000000..6858e90e1a5
--- /dev/null
+++ b/config/feature_flags/ops/loose_foreign_keys_turbo_mode_ci.yml
@@ -0,0 +1,8 @@
+---
+name: loose_foreign_keys_turbo_mode_ci
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128538
+rollout_issue_url:
+milestone: '16.4'
+type: ops
+group: group::tenant scale
+default_enabled: false
diff --git a/config/feature_flags/ops/loose_foreign_keys_turbo_mode_main.yml b/config/feature_flags/ops/loose_foreign_keys_turbo_mode_main.yml
new file mode 100644
index 00000000000..d6ca513e262
--- /dev/null
+++ b/config/feature_flags/ops/loose_foreign_keys_turbo_mode_main.yml
@@ -0,0 +1,8 @@
+---
+name: loose_foreign_keys_turbo_mode_main
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128538
+rollout_issue_url:
+milestone: '16.4'
+type: ops
+group: group::tenant scale
+default_enabled: false
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index bbdbd68a78b..07be2bbf57b 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -510,7 +510,7 @@ production: &base
## Sidekiq
sidekiq:
- log_format: json # (default is the original format)
+ log_format: json # (text is the original format)
# An array of tuples indicating the rules for re-routing a worker to a
# desirable queue before scheduling. For example:
# routing_rules:
diff --git a/config/gitlab_loose_foreign_keys.yml b/config/gitlab_loose_foreign_keys.yml
index bf99eeceb2d..54ebf8d3562 100644
--- a/config/gitlab_loose_foreign_keys.yml
+++ b/config/gitlab_loose_foreign_keys.yml
@@ -227,6 +227,17 @@ external_pull_requests:
- table: projects
column: project_id
on_delete: async_delete
+groups_visits:
+ - table: namespaces
+ column: entity_id
+ on_delete: async_delete
+ - table: users
+ column: user_id
+ on_delete: async_delete
+members:
+ - table: users
+ column: user_id
+ on_delete: async_delete
merge_request_metrics:
- table: ci_pipelines
column: pipeline_id
@@ -250,6 +261,10 @@ namespaces:
- table: organizations
column: organization_id
on_delete: async_nullify
+notification_settings:
+ - table: users
+ column: user_id
+ on_delete: async_delete
p_ci_builds:
- table: users
column: user_id
@@ -283,6 +298,17 @@ pages_deployments:
- table: p_ci_builds
column: ci_build_id
on_delete: async_nullify
+projects:
+ - table: organizations
+ column: organization_id
+ on_delete: async_nullify
+projects_visits:
+ - table: projects
+ column: entity_id
+ on_delete: async_delete
+ - table: users
+ column: user_id
+ on_delete: async_delete
requirements_management_test_reports:
- table: ci_builds
column: build_id
@@ -290,6 +316,10 @@ requirements_management_test_reports:
- table: p_ci_builds
column: build_id
on_delete: async_nullify
+routes:
+ - table: namespaces
+ column: namespace_id
+ on_delete: async_delete
sbom_occurrences:
- table: ci_pipelines
column: pipeline_id
@@ -330,4 +360,4 @@ vulnerability_state_transitions:
vulnerability_statistics:
- table: ci_pipelines
column: latest_pipeline_id
- on_delete: async_nullify
+ on_delete: async_nullify \ No newline at end of file
diff --git a/config/initializers/00_active_record_disable_cross_database.rb b/config/initializers/00_active_record_disable_cross_database.rb
new file mode 100644
index 00000000000..82f1a253d63
--- /dev/null
+++ b/config/initializers/00_active_record_disable_cross_database.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module ActiveRecordBaseCrossDatabaseIgnoreFactoryBot
+ def ignore_cross_database_tables_if_factory_bot(...)
+ # this method is implemented in:
+ # spec/support/database/prevent_cross_database_modification.rb
+ yield
+ end
+end
+
+ActiveRecord::Base.prepend(ActiveRecordBaseCrossDatabaseIgnoreFactoryBot)
diff --git a/config/initializers/00_deprecations.rb b/config/initializers/00_deprecations.rb
index 3d6a6491176..e254da5b8c6 100644
--- a/config/initializers/00_deprecations.rb
+++ b/config/initializers/00_deprecations.rb
@@ -44,10 +44,13 @@ else
# https://gitlab.com/gitlab-org/gitlab/-/issues/414556
/Merging .* no longer maintain both conditions, and will be replaced by the latter in Rails 7\.0/,
# https://gitlab.com/gitlab-org/gitlab/-/issues/415890
- /(Date|Time|TimeWithZone)#to_s.+ is deprecated/
+ /(Date|Time|TimeWithZone)#to_s.+ is deprecated/,
+ # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129686
+ /Sum of non-numeric elements requires an initial argument/
]
view_component_3_warnings = [
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/408988
/Setting a slot with `#\w+` is deprecated and will be removed from ViewComponent 3.0.0/
]
ActiveSupport::Deprecation.disallowed_warnings = rails7_deprecation_warnings + view_component_3_warnings
diff --git a/config/initializers/1_database_single_connection.rb b/config/initializers/1_database_single_connection.rb
new file mode 100644
index 00000000000..d71c82c2ea7
--- /dev/null
+++ b/config/initializers/1_database_single_connection.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+Gitlab::DatabaseWarnings.check_single_connection_and_print_warning
diff --git a/config/initializers/1_postgresql_only.rb b/config/initializers/1_postgresql_only.rb
index 3be55255ddd..f0bdbbd1884 100644
--- a/config/initializers/1_postgresql_only.rb
+++ b/config/initializers/1_postgresql_only.rb
@@ -3,4 +3,4 @@
raise "PostgreSQL is the only supported database from GitLab 12.1" unless
ApplicationRecord.database.postgresql?
-Gitlab::Database.check_postgres_version_and_print_warning
+Gitlab::DatabaseWarnings.check_postgres_version_and_print_warning
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index e4fd776f066..bdc5f48f485 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -121,7 +121,7 @@ Gitlab.ee do
Settings.omniauth.providers.delete_if { |p| p.name == 'kerberos' }
kerberos_spnego['name'] = 'kerberos'
- omniauth_keys = %w(allow_single_sign_on auto_link_user external_providers sync_profile_from_provider allow_bypass_two_factor)
+ omniauth_keys = %w[allow_single_sign_on auto_link_user external_providers sync_profile_from_provider allow_bypass_two_factor]
omniauth_keys.each do |key|
next unless Settings.omniauth[key].is_a?(Array)
@@ -160,6 +160,10 @@ if github_settings
end
end
+# Fill out default Settings for omniauth-saml
+
+OmniAuth::Strategies::SAML.default_options['message_max_bytesize'] = Settings.omniauth['saml_message_max_byte_size']
+
# SAML should be enabled for the tests automatically, but only for EE.
saml_provider_enabled = Settings.omniauth.providers.any? do |provider|
provider['name'] == 'group_saml'
@@ -465,7 +469,7 @@ if Gitlab.ee? && Settings['ee_cron_jobs']
Settings.cron_jobs.merge!(Settings.ee_cron_jobs)
end
-Settings.cron_jobs['poll_interval'] ||= nil
+Settings.cron_jobs['poll_interval'] ||= ENV["GITLAB_CRON_JOBS_POLL_INTERVAL"] ? ENV["GITLAB_CRON_JOBS_POLL_INTERVAL"].to_i : nil
Settings.cron_jobs['stuck_ci_jobs_worker'] ||= {}
Settings.cron_jobs['stuck_ci_jobs_worker']['cron'] ||= '0 * * * *'
Settings.cron_jobs['stuck_ci_jobs_worker']['job_class'] = 'StuckCiJobsWorker'
@@ -634,9 +638,6 @@ Settings.cron_jobs['user_status_cleanup_batch_worker']['job_class'] = 'UserStatu
Settings.cron_jobs['ssh_keys_expired_notification_worker'] ||= {}
Settings.cron_jobs['ssh_keys_expired_notification_worker']['cron'] ||= '0 2,14 * * *'
Settings.cron_jobs['ssh_keys_expired_notification_worker']['job_class'] = 'SshKeys::ExpiredNotificationWorker'
-Settings.cron_jobs['namespaces_in_product_marketing_emails_worker'] ||= {}
-Settings.cron_jobs['namespaces_in_product_marketing_emails_worker']['cron'] ||= '0 16 * * *'
-Settings.cron_jobs['namespaces_in_product_marketing_emails_worker']['job_class'] = 'Namespaces::InProductMarketingEmailsWorker'
Settings.cron_jobs['ssh_keys_expiring_soon_notification_worker'] ||= {}
Settings.cron_jobs['ssh_keys_expiring_soon_notification_worker']['cron'] ||= '0 1 * * *'
Settings.cron_jobs['ssh_keys_expiring_soon_notification_worker']['job_class'] = 'SshKeys::ExpiringSoonNotificationWorker'
@@ -682,15 +683,15 @@ Settings.cron_jobs['packages_cleanup_delete_orphaned_dependencies_worker']['job_
Settings.cron_jobs['cleanup_dangling_debian_package_files_worker'] ||= {}
Settings.cron_jobs['cleanup_dangling_debian_package_files_worker']['cron'] ||= '20 21 * * *'
Settings.cron_jobs['cleanup_dangling_debian_package_files_worker']['job_class'] = 'Packages::Debian::CleanupDanglingPackageFilesWorker'
-Settings.cron_jobs['global_metrics_update_worker'] ||= {}
-Settings.cron_jobs['global_metrics_update_worker']['cron'] ||= '*/1 * * * *'
-Settings.cron_jobs['global_metrics_update_worker']['job_class'] ||= 'Metrics::GlobalMetricsUpdateWorker'
Settings.cron_jobs['object_storage_delete_stale_direct_uploads_worker'] ||= {}
Settings.cron_jobs['object_storage_delete_stale_direct_uploads_worker']['cron'] ||= '*/6 * * * *'
Settings.cron_jobs['object_storage_delete_stale_direct_uploads_worker']['job_class'] = 'ObjectStorage::DeleteStaleDirectUploadsWorker'
Settings.cron_jobs['service_desk_custom_email_verification_cleanup'] ||= {}
Settings.cron_jobs['service_desk_custom_email_verification_cleanup']['cron'] ||= '*/2 * * * *'
Settings.cron_jobs['service_desk_custom_email_verification_cleanup']['job_class'] = 'ServiceDesk::CustomEmailVerificationCleanupWorker'
+Settings.cron_jobs['ensure_merge_requests_prepared_worker'] ||= {}
+Settings.cron_jobs['ensure_merge_requests_prepared_worker']['cron'] ||= '*/30 * * * *'
+Settings.cron_jobs['ensure_merge_requests_prepared_worker']['job_class'] ||= 'MergeRequests::EnsurePreparedWorker'
Gitlab.ee do
Settings.cron_jobs['analytics_devops_adoption_create_all_snapshots_worker'] ||= {}
@@ -705,6 +706,9 @@ Gitlab.ee do
Settings.cron_jobs['analytics_cycle_analytics_reaggregation_worker'] ||= {}
Settings.cron_jobs['analytics_cycle_analytics_reaggregation_worker']['cron'] ||= '44 * * * *'
Settings.cron_jobs['analytics_cycle_analytics_reaggregation_worker']['job_class'] = 'Analytics::CycleAnalytics::ReaggregationWorker'
+ Settings.cron_jobs['analytics_value_stream_dashboard_count_worker'] ||= {}
+ Settings.cron_jobs['analytics_value_stream_dashboard_count_worker']['cron'] ||= '*/7 * * * *'
+ Settings.cron_jobs['analytics_value_stream_dashboard_count_worker']['job_class'] = 'Analytics::ValueStreamDashboard::CountWorker'
Settings.cron_jobs['active_user_count_threshold_worker'] ||= {}
Settings.cron_jobs['active_user_count_threshold_worker']['cron'] ||= '0 12 * * *'
Settings.cron_jobs['active_user_count_threshold_worker']['job_class'] = 'ActiveUserCountThresholdWorker'
@@ -798,9 +802,15 @@ Gitlab.ee do
Settings.cron_jobs['sync_seat_link_worker'] ||= {}
Settings.cron_jobs['sync_seat_link_worker']['cron'] ||= "#{rand(60)} #{rand(3..4)} * * * UTC"
Settings.cron_jobs['sync_seat_link_worker']['job_class'] = 'SyncSeatLinkWorker'
+ Settings.cron_jobs['llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker'] ||= {}
+ Settings.cron_jobs['llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker']['cron'] ||= '0 5 * * 1,2,3,4,5'
+ Settings.cron_jobs['llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker']['job_class'] ||= 'Llm::Embedding::GitlabDocumentation::CreateEmptyEmbeddingsRecordsWorker'
Settings.cron_jobs['tanuki_bot_recreate_records_worker'] ||= {}
Settings.cron_jobs['tanuki_bot_recreate_records_worker']['cron'] ||= '0 5 * * 1,2,3,4,5'
Settings.cron_jobs['tanuki_bot_recreate_records_worker']['job_class'] ||= 'Llm::TanukiBot::RecreateRecordsWorker'
+ Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker'] ||= {}
+ Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker']['cron'] ||= '0 0 * * *'
+ Settings.cron_jobs['llm_embedding_gitlab_documentation_cleanup_previous_versions_records_worker']['job_class'] ||= 'Llm::Embedding::GitlabDocumentation::CleanupPreviousVersionsRecordsWorker'
Settings.cron_jobs['tanuki_bot_remove_previous_records_worker'] ||= {}
Settings.cron_jobs['tanuki_bot_remove_previous_records_worker']['cron'] ||= '0 0 * * *'
Settings.cron_jobs['tanuki_bot_remove_previous_records_worker']['job_class'] ||= 'Llm::TanukiBot::RemovePreviousRecordsWorker'
@@ -866,12 +876,6 @@ Gitlab.ee do
Settings.cron_jobs['package_metadata_advisories_sync_worker']['job_class'] = 'PackageMetadata::AdvisoriesSyncWorker'
Gitlab.com do
- Settings.cron_jobs['free_user_cap_backfill_notification_jobs_worker'] ||= {}
- Settings.cron_jobs['free_user_cap_backfill_notification_jobs_worker']['cron'] ||= '*/5 * * * *'
- Settings.cron_jobs['free_user_cap_backfill_notification_jobs_worker']['job_class'] = 'Namespaces::FreeUserCap::BackfillNotificationJobsWorker'
- Settings.cron_jobs['free_user_cap_backfill_clear_notified_flag'] ||= {}
- Settings.cron_jobs['free_user_cap_backfill_clear_notified_flag']['cron'] ||= '*/5 * * * *'
- Settings.cron_jobs['free_user_cap_backfill_clear_notified_flag']['job_class'] ||= 'Namespaces::FreeUserCap::BackfillNotificationClearingJobsWorker'
Settings.cron_jobs['disable_legacy_open_source_license_for_inactive_projects'] ||= {}
Settings.cron_jobs['disable_legacy_open_source_license_for_inactive_projects']['cron'] ||= "30 5 * * 0"
Settings.cron_jobs['disable_legacy_open_source_license_for_inactive_projects']['job_class'] = 'Projects::DisableLegacyOpenSourceLicenseForInactiveProjectsWorker'
@@ -1080,7 +1084,7 @@ Settings.extra['maximum_text_highlight_size_kilobytes'] = Settings.extra.fetch('
Settings['rack_attack'] ||= {}
Settings.rack_attack['git_basic_auth'] ||= {}
Settings.rack_attack.git_basic_auth['enabled'] = false if Settings.rack_attack.git_basic_auth['enabled'].nil?
-Settings.rack_attack.git_basic_auth['ip_whitelist'] ||= %w{127.0.0.1}
+Settings.rack_attack.git_basic_auth['ip_whitelist'] ||= %w[127.0.0.1]
Settings.rack_attack.git_basic_auth['maxretry'] ||= 10
Settings.rack_attack.git_basic_auth['findtime'] ||= 1.minute
Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour
diff --git a/config/initializers/8_devise.rb b/config/initializers/8_devise.rb
index 237231f544f..3682a391033 100644
--- a/config/initializers/8_devise.rb
+++ b/config/initializers/8_devise.rb
@@ -1,11 +1,15 @@
# frozen_string_literal: true
+require_dependency 'gitlab/auth/devise/strategies/combined_two_factor_authenticatable'
+
# Use this hook to configure devise mailer, warden hooks and so forth. The first
# four configuration values can also be set straight in your models.
Devise.setup do |config|
config.warden do |manager|
- manager.default_strategies(scope: :user).unshift :two_factor_authenticatable
- manager.default_strategies(scope: :user).unshift :two_factor_backupable
+ user_scoped_strategies = manager.default_strategies(scope: :user)
+ user_scoped_strategies.delete :two_factor_backupable
+ user_scoped_strategies.delete :two_factor_authenticatable
+ user_scoped_strategies.unshift :combined_two_factor_authenticatable
end
# This is the default. This makes it explicit that Devise loads routes
diff --git a/config/initializers/action_cable.rb b/config/initializers/action_cable.rb
index 0d2073586be..6d7f0497cd0 100644
--- a/config/initializers/action_cable.rb
+++ b/config/initializers/action_cable.rb
@@ -16,7 +16,10 @@ ActionCable::SubscriptionAdapter::Redis.redis_connector = lambda do |config|
args = config.except(:adapter, :channel_prefix)
.merge(instrumentation_class: ::Gitlab::Instrumentation::Redis::ActionCable)
- ::Redis.new(args)
+ primary_store = ::Redis.new(Gitlab::Redis::Pubsub.params)
+ secondary_store = ::Redis.new(args)
+
+ Gitlab::Redis::MultiStore.new(primary_store, secondary_store, "ActionCable")
end
Gitlab::ActionCable::RequestStoreCallbacks.install
diff --git a/config/initializers/click_house.rb b/config/initializers/click_house.rb
index 481942d775e..ecf1ccb97bf 100644
--- a/config/initializers/click_house.rb
+++ b/config/initializers/click_house.rb
@@ -17,15 +17,34 @@ ClickHouse::Client.configure do |config|
)
end
+ if Rails.env.development? || Rails.env.test?
+ config.logger = ::ClickHouse::Logger.build
+ config.log_proc = ->(query) do
+ structured_log(query.to_sql)
+ end
+ else
+ config.logger = Logger.new('/dev/null')
+ config.log_proc = ->(query) do
+ structured_log(query.to_redacted_sql)
+ end
+ end
+
config.json_parser = Gitlab::Json
config.http_post_proc = ->(url, headers, body) do
options = {
+ multipart: true,
headers: headers,
- body: ActiveSupport::Gzip.compress(body),
allow_local_requests: Rails.env.development? || Rails.env.test?
}
+ body_key = body.is_a?(IO) ? :body_stream : :body
+ options[body_key] = body
+
response = Gitlab::HTTP.post(url, options)
ClickHouse::Client::Response.new(response.body, response.code, response.headers)
end
end
+
+def structured_log(query_string)
+ { query: query_string, correlation_id: Labkit::Correlation::CorrelationId.current_id.to_s }
+end
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index f7c3f4e98b5..4ab94797f26 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -15,5 +15,5 @@ if csp_settings['enabled']
Rails.application.config.content_security_policy_report_only = csp_settings['report_only']
Rails.application.config.content_security_policy_nonce_generator = ->(request) { SecureRandom.base64(16) }
- Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
+ Rails.application.config.content_security_policy_nonce_directives = %w[script-src]
end
diff --git a/config/initializers/declarative_policy_cached_attributes.rb b/config/initializers/declarative_policy_cached_attributes.rb
new file mode 100644
index 00000000000..c05a7609fec
--- /dev/null
+++ b/config/initializers/declarative_policy_cached_attributes.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+# This module memoizes some attributes to reduce memory allocations.
+#
+# See https://gitlab.com/gitlab-org/gitlab/-/issues/420623
+# See https://gitlab.com/gitlab-org/ruby/gems/declarative-policy/-/merge_requests/52
+module DeclarativePolicyCachedAttributes
+ def ability_map
+ @ability_map ||= super
+ end
+
+ def conditions
+ @conditions ||= super
+ end
+
+ def global_actions
+ @global_actions ||= super
+ end
+
+ def delegations
+ @delegations ||= super
+ end
+end
+
+DeclarativePolicy::Base.singleton_class.prepend(DeclarativePolicyCachedAttributes)
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index 918b2767c4d..f343c20dfe4 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -101,7 +101,7 @@ Doorkeeper.configure do
# "password" => Resource Owner Password Credentials Grant Flow
# "client_credentials" => Client Credentials Grant Flow
#
- grant_flows %w(authorization_code password client_credentials)
+ grant_flows %w[authorization_code password client_credentials]
# Under some circumstances you might want to have applications auto-approved,
# so that the user skips the authorization step.
@@ -120,4 +120,12 @@ Doorkeeper.configure do
#
# We might want to disable this in the future, see https://gitlab.com/gitlab-org/gitlab/-/issues/323615
skip_client_authentication_for_password_grant true
+
+ # 2 hours in seconds
+ # This is also the database default value
+ access_token_expires_in 7200
+
+ # Use a custom class for generating the application secret.
+ # https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-application-secret-generator
+ application_secret_generator 'Gitlab::DoorkeeperSecretStoring::Token::UniqueApplicationToken'
end
diff --git a/config/initializers/enumerator_next_patch.rb b/config/initializers/enumerator_next_patch.rb
index e1fc04731ae..3771864fb91 100644
--- a/config/initializers/enumerator_next_patch.rb
+++ b/config/initializers/enumerator_next_patch.rb
@@ -4,7 +4,7 @@
# when an error is raised from within a Fiber.
# https://bugs.ruby-lang.org/issues/16829
module EnumeratorNextPatch
- %w(next next_values peek peek_values).each do |name|
+ %w[next next_values peek peek_values].each do |name|
define_method(name) do |*args|
gitlab_patch_backtrace_marker { super(*args) }
rescue Exception => err # rubocop: disable Lint/RescueException
@@ -27,7 +27,7 @@ module EnumeratorNextPatch
# #gitlab_patch_backtrace_marker calls a block, which in turn calls #next.) If it's generated
# by the Fiber that #next invokes, then it won't contain this marker.
def has_gitlab_patch_backtrace_marker?(backtrace)
- match = %r(^(.*):[0-9]+:in `gitlab_patch_backtrace_marker'$).match(backtrace[2])
+ match = %r{^(.*):[0-9]+:in `gitlab_patch_backtrace_marker'$}.match(backtrace[2])
!!match && match[1] == __FILE__
end
diff --git a/config/initializers/fog_core_patch.rb b/config/initializers/fog_core_patch.rb
index f7d81f26be5..d0868116a7a 100644
--- a/config/initializers/fog_core_patch.rb
+++ b/config/initializers/fog_core_patch.rb
@@ -31,7 +31,7 @@
module Fog
module ServicesMixin
# Gems that have not yet updated with the new fog-core namespace
- LEGACY_FOG_PROVIDERS = %w(google aliyun).freeze
+ LEGACY_FOG_PROVIDERS = %w[google aliyun].freeze
# rubocop:disable Gitlab/ConstGetInheritFalse
def service_provider_constant(service_name, provider_name)
diff --git a/config/initializers/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb
index c96524b824d..6dd12c28515 100644
--- a/config/initializers/forbid_sidekiq_in_transactions.rb
+++ b/config/initializers/forbid_sidekiq_in_transactions.rb
@@ -36,7 +36,7 @@ module Sidekiq
module ClassMethods
module NoEnqueueingFromTransactions
- %i(perform_async perform_at perform_in).each do |name|
+ %i[perform_async perform_at perform_in].each do |name|
define_method(name) do |*args|
if Sidekiq::Worker.raise_exception_for_being_inside_a_transaction?
begin
@@ -65,7 +65,7 @@ end
module ActiveJob
module QueueAdapters
module NoEnqueueingFromTransactions
- %i(enqueue enqueue_at).each do |name|
+ %i[enqueue enqueue_at].each do |name|
define_method(name) do |*args|
if Sidekiq::Worker.raise_exception_for_being_inside_a_transaction?
begin
diff --git a/config/initializers/health_check.rb b/config/initializers/health_check.rb
index 0b35aaf115b..a35c757c6fa 100644
--- a/config/initializers/health_check.rb
+++ b/config/initializers/health_check.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
HealthCheck.setup do |config|
- config.standard_checks = %w(database migrations cache)
- config.full_checks = %w(database migrations cache)
+ config.standard_checks = %w[database migrations cache]
+ config.full_checks = %w[database migrations cache]
Gitlab.ee do
config.add_custom_check('geo') do
diff --git a/config/initializers/invisible_captcha.rb b/config/initializers/invisible_captcha.rb
index 5177c730596..499217a6d56 100644
--- a/config/initializers/invisible_captcha.rb
+++ b/config/initializers/invisible_captcha.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
InvisibleCaptcha.setup do |config|
- config.honeypots = %w(firstname lastname)
+ config.honeypots = %w[firstname lastname]
config.timestamp_enabled = true
config.timestamp_threshold = 4
end
diff --git a/config/initializers/licensee_license_patch.rb b/config/initializers/licensee_license_patch.rb
deleted file mode 100644
index d4680db5071..00000000000
--- a/config/initializers/licensee_license_patch.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-require 'licensee/license'
-
-module Licensee
- module LicensePatch
- # Patch from https://github.com/licensee/licensee/pull/589
- def ==(other)
- other.is_a?(self.class) && key == other.key
- end
- end
-
- License.prepend LicensePatch
-end
diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb
index 5ea3b553713..6ed3fff7f46 100644
--- a/config/initializers/lograge.rb
+++ b/config/initializers/lograge.rb
@@ -23,7 +23,7 @@ unless Gitlab::Runtime.sidekiq?
# Remove empty hashes to prevent type mismatches
# These are set to empty hashes in Lograge's ActionCable subscriber
# https://github.com/roidrage/lograge/blob/v0.11.2/lib/lograge/log_subscribers/action_cable.rb#L14-L16
- %i(method path format).each do |key|
+ %i[method path format].each do |key|
data[key] = nil if data[key] == {}
end
diff --git a/config/initializers/mail_starttls_patch.rb b/config/initializers/mail_starttls_patch.rb
index c4fe102edfb..51d454238ca 100644
--- a/config/initializers/mail_starttls_patch.rb
+++ b/config/initializers/mail_starttls_patch.rb
@@ -9,7 +9,7 @@ require 'mail/network/delivery_methods/smtp'
module Mail
class SMTP
def initialize(values)
- self.settings = DEFAULTS
+ self.settings = DEFAULTS.dup
settings[:enable_starttls_auto] = nil
settings.merge!(values)
end
diff --git a/config/initializers/postgres_partitioning.rb b/config/initializers/postgres_partitioning.rb
index bfd737baec9..a7728bf51b3 100644
--- a/config/initializers/postgres_partitioning.rb
+++ b/config/initializers/postgres_partitioning.rb
@@ -8,7 +8,9 @@ Gitlab::Database::Partitioning.register_models(
Gitlab::Database::BackgroundMigration::BatchedJobTransitionLog,
Ci::RunnerManagerBuild,
Ci::JobAnnotation,
- BatchedGitRefUpdates::Deletion
+ BatchedGitRefUpdates::Deletion,
+ Users::ProjectVisit,
+ Users::GroupVisit
])
if Gitlab.ee?
diff --git a/config/initializers/rspec_profiling.rb b/config/initializers/rspec_profiling.rb
index 7cc2d6afb0f..b0b7ea85cae 100644
--- a/config/initializers/rspec_profiling.rb
+++ b/config/initializers/rspec_profiling.rb
@@ -5,8 +5,8 @@ return unless Rails.env.test?
module RspecProfilingExt
module Collectors
class CSVWithTimestamps < ::RspecProfiling::Collectors::CSV
- TIMESTAMP_FIELDS = %w(created_at updated_at).freeze
- METADATA_FIELDS = %w(feature_category).freeze
+ TIMESTAMP_FIELDS = %w[created_at updated_at].freeze
+ METADATA_FIELDS = %w[feature_category].freeze
HEADERS = (::RspecProfiling::Collectors::CSV::HEADERS + TIMESTAMP_FIELDS + METADATA_FIELDS).freeze
def insert(attributes)
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index a7754667320..733ad94240a 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -6,13 +6,23 @@ require 'gitlab/current_settings'
# allow it to fail: it may do so when create_from_defaults is executed before migrations are actually done
begin
- Settings.gitlab['session_expire_delay'] = Gitlab::CurrentSettings.current_application_settings.session_expire_delay || 10080
+ session_expire_delay = Gitlab::CurrentSettings.current_application_settings.session_expire_delay
+ Settings.gitlab['session_expire_delay'] = session_expire_delay || 10080
rescue StandardError
Settings.gitlab['session_expire_delay'] ||= 10080
end
+raw_config = if File.exist?(Rails.root.join('config/session_store.yml'))
+ Rails.application.config_for(:session_store)
+ else
+ {}
+ end
+
cookie_key = if Rails.env.development?
- "_gitlab_session_#{Digest::SHA256.hexdigest(Rails.root.to_s)}"
+ cookie_key_prefix = raw_config.fetch(:cookie_key, "_gitlab_session")
+ # If config doesn't exist we preserve the current default behaviour, which is a unique postfix per GDK
+ unique_key = raw_config.fetch(:unique_cookie_key_postfix, true)
+ unique_key ? "#{cookie_key_prefix}_#{Digest::SHA256.hexdigest(Rails.root.to_s)}" : cookie_key_prefix
elsif ::Gitlab.ee? && ::Gitlab::Geo.connected? && ::Gitlab::Geo.secondary?
"_gitlab_session_geo_#{Digest::SHA256.hexdigest(GeoNode.current_node_name)}"
else
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 03bdc6cf47a..57850e4e35c 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -34,7 +34,7 @@ unless Gitlab::Utils.to_boolean(ENV['SIDEKIQ_ENQUEUE_NON_NAMESPACED'])
queues_config_hash[:namespace] = Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE
end
-enable_json_logs = Gitlab.config.sidekiq.log_format == 'json'
+enable_json_logs = Gitlab.config.sidekiq.log_format != 'text'
Sidekiq.configure_server do |config|
config[:strict] = false
@@ -89,7 +89,7 @@ Sidekiq.configure_server do |config|
end
if enable_reliable_fetch?
- if Gitlab::Utils.to_boolean(ENV['SIDEKIQ_POLL_NON_NAMESPACED'])
+ if Gitlab::Utils.to_boolean(ENV['SIDEKIQ_ENABLE_DUAL_NAMESPACE_POLLING'], default: true)
# set non-namespaced store for fetcher to poll both namespaced and non-namespaced queues
config[:alternative_store] = ::Gitlab::Redis::Queues
config[:namespace] = Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE
@@ -123,6 +123,7 @@ Sidekiq.configure_client do |config|
config.client_middleware(&Gitlab::SidekiqMiddleware.client_configurator)
end
+Sidekiq::Scheduled::Enq.prepend Gitlab::Patch::SidekiqScheduledEnq
Sidekiq::Scheduled::Poller.prepend Gitlab::Patch::SidekiqPoller
Sidekiq::Cron::Poller.prepend Gitlab::Patch::SidekiqPoller
Sidekiq::Cron::Poller.prepend Gitlab::Patch::SidekiqCronPoller
diff --git a/config/initializers/warden.rb b/config/initializers/warden.rb
index 14bcaa80064..fd3e7fb6d18 100644
--- a/config/initializers/warden.rb
+++ b/config/initializers/warden.rb
@@ -38,8 +38,6 @@ Rails.application.configure do |config|
Warden::Manager.before_logout(scope: :user) do |user, auth, opts|
user ||= auth.user
- # deletes marketing cookie when user session ends
- ActiveSession.unset_active_user_cookie(auth) if ::Gitlab.com?
# Rails CSRF protection may attempt to log out a user before that
# user even logs in
next unless user
diff --git a/config/initializers_before_autoloader/000_inflections.rb b/config/initializers_before_autoloader/000_inflections.rb
index 178fb50b7f3..6f73dbb4d8a 100644
--- a/config/initializers_before_autoloader/000_inflections.rb
+++ b/config/initializers_before_autoloader/000_inflections.rb
@@ -12,13 +12,12 @@
# end
#
ActiveSupport::Inflector.inflections do |inflect|
- inflect.uncountable %w(
+ inflect.uncountable %w[
custom_emoji
award_emoji
ci_secure_file_registry
container_repository_registry
dependency_proxy_blob_registry
- design_registry
design_management_repository_registry
dependency_proxy_manifest_registry
event_log
@@ -41,7 +40,7 @@ ActiveSupport::Inflector.inflections do |inflect|
terraform_state_version_registry
vulnerabilities_feedback
vulnerability_feedback
- )
+ ]
inflect.acronym 'CDN'
inflect.acronym 'EE'
inflect.acronym 'JH'
diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml
index b571801c006..9568195bb6e 100644
--- a/config/locales/doorkeeper.en.yml
+++ b/config/locales/doorkeeper.en.yml
@@ -77,6 +77,8 @@ en:
email: Allows read-only access to the user's primary email address using OpenID Connect
admin_mode: Admin Mode is a functionality designed to limit the access level of administrator's personal access tokens.
create_runner: Grants create access to the runners
+ k8s_proxy: Grants permission to perform Kubernetes API calls using the agent for Kubernetes.
+ ai_features: Access to API endpoints needed for GitLab Duo features
scope_desc:
api:
Grants complete read/write access to the API, including all groups and projects, the container registry, and the package registry.
@@ -96,6 +98,8 @@ en:
Grants read-only access to GitLab Observability.
write_observability:
Grants write access to GitLab Observability.
+ ai_features:
+ Grants access to GitLab Duo related API endpoints.
openid:
Grants permission to authenticate with GitLab using OpenID Connect. Also gives read-only access to the user's profile and group memberships.
sudo:
@@ -108,6 +112,8 @@ en:
Grants permission to perform API actions as an administrator, when Admin Mode is enabled.
create_runner:
Grants create access to the runners.
+ k8s_proxy:
+ Grants permission to perform Kubernetes API calls using the agent for Kubernetes.
project_access_token_scope_desc:
api:
Grants complete read and write access to the scoped project API, including the Package Registry.
@@ -123,6 +129,8 @@ en:
Grants write access (push) to the Container Registry.
create_runner:
Grants create access to the runners.
+ k8s_proxy:
+ Grants permission to perform Kubernetes API calls using the agent for Kubernetes.
flash:
applications:
create:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index b47caa07589..fedeeef0e9a 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -10,8 +10,6 @@ en:
pwa_short_name: "PWA short name"
pwa_description: "PWA description"
pwa_icon: "Icon"
- application_setting:
- ai_access_token: "Personal access token"
incident_management/timeline_event:
note: 'Timeline text'
issue_link:
diff --git a/config/metrics/counts_28d/20210216175000_i_analytics_dev_ops_score_monthly.yml b/config/metrics/counts_28d/20210216175000_i_analytics_dev_ops_score_monthly.yml
index 8171a552c67..2e01a7cced1 100644
--- a/config/metrics/counts_28d/20210216175000_i_analytics_dev_ops_score_monthly.yml
+++ b/config/metrics/counts_28d/20210216175000_i_analytics_dev_ops_score_monthly.yml
@@ -8,11 +8,14 @@ product_group: optimize
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- i_analytics_dev_ops_score
+events:
+ - name: i_analytics_dev_ops_score
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216175004_g_analytics_merge_request_monthly.yml b/config/metrics/counts_28d/20210216175004_g_analytics_merge_request_monthly.yml
index f2716c0632c..ef3d62b42af 100644
--- a/config/metrics/counts_28d/20210216175004_g_analytics_merge_request_monthly.yml
+++ b/config/metrics/counts_28d/20210216175004_g_analytics_merge_request_monthly.yml
@@ -1,7 +1,7 @@
---
data_category: optional
key_path: redis_hll_counters.analytics.g_analytics_merge_request_monthly
-description:
+description: Removed metric without a description
product_section: dev
product_stage: manage
product_group: optimize
@@ -22,3 +22,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216175055_merge_requests.yml b/config/metrics/counts_28d/20210216175055_merge_requests.yml
index c71c83d7064..9e3f64553f6 100644
--- a/config/metrics/counts_28d/20210216175055_merge_requests.yml
+++ b/config/metrics/counts_28d/20210216175055_merge_requests.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216175109_suggestions.yml b/config/metrics/counts_28d/20210216175109_suggestions.yml
index d7e649ad7f8..e336c1def68 100644
--- a/config/metrics/counts_28d/20210216175109_suggestions.yml
+++ b/config/metrics/counts_28d/20210216175109_suggestions.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: '14.7'
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216175132_i_code_review_user_create_mr_monthly.yml b/config/metrics/counts_28d/20210216175132_i_code_review_user_create_mr_monthly.yml
index 400d7f2600d..6da19fb6a93 100644
--- a/config/metrics/counts_28d/20210216175132_i_code_review_user_create_mr_monthly.yml
+++ b/config/metrics/counts_28d/20210216175132_i_code_review_user_create_mr_monthly.yml
@@ -13,6 +13,9 @@ instrumentation_class: RedisHLLMetric
options:
events:
- i_code_review_user_create_mr
+events:
+ - name: i_code_review_user_create_mr
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216175405_clusters_applications_cert_managers.yml b/config/metrics/counts_28d/20210216175405_clusters_applications_cert_managers.yml
index 34cb10f08d0..6647ed6e3b8 100644
--- a/config/metrics/counts_28d/20210216175405_clusters_applications_cert_managers.yml
+++ b/config/metrics/counts_28d/20210216175405_clusters_applications_cert_managers.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216175407_clusters_applications_helm.yml b/config/metrics/counts_28d/20210216175407_clusters_applications_helm.yml
index 44b46f9c013..249e7d85bad 100644
--- a/config/metrics/counts_28d/20210216175407_clusters_applications_helm.yml
+++ b/config/metrics/counts_28d/20210216175407_clusters_applications_helm.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216175409_clusters_applications_ingress.yml b/config/metrics/counts_28d/20210216175409_clusters_applications_ingress.yml
index abf90e57eec..7a95f6e5ac7 100644
--- a/config/metrics/counts_28d/20210216175409_clusters_applications_ingress.yml
+++ b/config/metrics/counts_28d/20210216175409_clusters_applications_ingress.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216175411_clusters_applications_knative.yml b/config/metrics/counts_28d/20210216175411_clusters_applications_knative.yml
index 885f9903247..12c8dde9cff 100644
--- a/config/metrics/counts_28d/20210216175411_clusters_applications_knative.yml
+++ b/config/metrics/counts_28d/20210216175411_clusters_applications_knative.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216180319_action_monthly_active_users_web_ide_edit.yml b/config/metrics/counts_28d/20210216180319_action_monthly_active_users_web_ide_edit.yml
index 0e8e4741016..bcb6ce623f9 100644
--- a/config/metrics/counts_28d/20210216180319_action_monthly_active_users_web_ide_edit.yml
+++ b/config/metrics/counts_28d/20210216180319_action_monthly_active_users_web_ide_edit.yml
@@ -8,7 +8,7 @@ product_group: ide
value_type: number
status: removed
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111351
-milestone_removed: 15.9
+milestone_removed: "15.9"
time_frame: 28d
data_source: redis_hll
distribution:
diff --git a/config/metrics/counts_28d/20210216180321_action_monthly_active_users_sfe_edit.yml b/config/metrics/counts_28d/20210216180321_action_monthly_active_users_sfe_edit.yml
index 8ee0f7e9fc3..7794edd8b22 100644
--- a/config/metrics/counts_28d/20210216180321_action_monthly_active_users_sfe_edit.yml
+++ b/config/metrics/counts_28d/20210216180321_action_monthly_active_users_sfe_edit.yml
@@ -8,7 +8,7 @@ product_group: source_code
value_type: number
status: removed
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113551
-milestone_removed: 15.10
+milestone_removed: "15.10"
time_frame: 28d
data_source: redis_hll
distribution:
diff --git a/config/metrics/counts_28d/20210216180323_action_monthly_active_users_snippet_editor_edit.yml b/config/metrics/counts_28d/20210216180323_action_monthly_active_users_snippet_editor_edit.yml
index 52a16056ce1..0df0d7b8aef 100644
--- a/config/metrics/counts_28d/20210216180323_action_monthly_active_users_snippet_editor_edit.yml
+++ b/config/metrics/counts_28d/20210216180323_action_monthly_active_users_snippet_editor_edit.yml
@@ -8,7 +8,7 @@ product_group: source_code
value_type: number
status: removed
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113551
-milestone_removed: 15.10
+milestone_removed: "15.10"
time_frame: 28d
data_source: redis_hll
distribution:
diff --git a/config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml b/config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml
index 3c7acc92050..6953cbc2ce3 100644
--- a/config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml
+++ b/config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml
@@ -18,7 +18,6 @@ options:
- g_edit_by_web_ide
- g_edit_by_sfe
- g_edit_by_snippet_ide
- - g_edit_by_live_preview
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216180330_g_edit_by_web_ide_monthly.yml b/config/metrics/counts_28d/20210216180330_g_edit_by_web_ide_monthly.yml
index c4908d7739c..08ae78ceb3b 100644
--- a/config/metrics/counts_28d/20210216180330_g_edit_by_web_ide_monthly.yml
+++ b/config/metrics/counts_28d/20210216180330_g_edit_by_web_ide_monthly.yml
@@ -8,7 +8,7 @@ product_group: ide
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
diff --git a/config/metrics/counts_28d/20210216180338_g_edit_by_snippet_ide_monthly.yml b/config/metrics/counts_28d/20210216180338_g_edit_by_snippet_ide_monthly.yml
index 9c439d6a6a3..dc801b5c139 100644
--- a/config/metrics/counts_28d/20210216180338_g_edit_by_snippet_ide_monthly.yml
+++ b/config/metrics/counts_28d/20210216180338_g_edit_by_snippet_ide_monthly.yml
@@ -8,7 +8,7 @@ product_group: source_code
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
diff --git a/config/metrics/counts_28d/20210216180341_ide_edit_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216180341_ide_edit_total_unique_counts_monthly.yml
index 2e50156911d..02c0a290e9e 100644
--- a/config/metrics/counts_28d/20210216180341_ide_edit_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216180341_ide_edit_total_unique_counts_monthly.yml
@@ -18,7 +18,6 @@ options:
- g_edit_by_web_ide
- g_edit_by_sfe
- g_edit_by_snippet_ide
- - g_edit_by_live_preview
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216180955_projects_with_prometheus_alerts.yml b/config/metrics/counts_28d/20210216180955_projects_with_prometheus_alerts.yml
index 9faf6cf6a84..3940428db10 100644
--- a/config/metrics/counts_28d/20210216180955_projects_with_prometheus_alerts.yml
+++ b/config/metrics/counts_28d/20210216180955_projects_with_prometheus_alerts.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216180958_clusters_applications_prometheus.yml b/config/metrics/counts_28d/20210216180958_clusters_applications_prometheus.yml
index 69939472df6..19c12861873 100644
--- a/config/metrics/counts_28d/20210216180958_clusters_applications_prometheus.yml
+++ b/config/metrics/counts_28d/20210216180958_clusters_applications_prometheus.yml
@@ -19,3 +19,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216181304_g_project_management_issue_title_changed_monthly.yml b/config/metrics/counts_28d/20210216181304_g_project_management_issue_title_changed_monthly.yml
index ae28eb8e057..66ca4a56ef6 100644
--- a/config/metrics/counts_28d/20210216181304_g_project_management_issue_title_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181304_g_project_management_issue_title_changed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_title_changed
+events:
+ - name: g_project_management_issue_title_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181308_g_project_management_issue_description_changed_monthly.yml b/config/metrics/counts_28d/20210216181308_g_project_management_issue_description_changed_monthly.yml
index e00b7c18176..394b6264191 100644
--- a/config/metrics/counts_28d/20210216181308_g_project_management_issue_description_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181308_g_project_management_issue_description_changed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_description_changed
+events:
+ - name: g_project_management_issue_description_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181311_g_project_management_issue_assignee_changed_monthly.yml b/config/metrics/counts_28d/20210216181311_g_project_management_issue_assignee_changed_monthly.yml
index a548cf8ede7..97b0022a4f8 100644
--- a/config/metrics/counts_28d/20210216181311_g_project_management_issue_assignee_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181311_g_project_management_issue_assignee_changed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_assignee_changed
+events:
+ - name: g_project_management_issue_assignee_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181315_g_project_management_issue_made_confidential_monthly.yml b/config/metrics/counts_28d/20210216181315_g_project_management_issue_made_confidential_monthly.yml
index 0ff91cc6f9e..e0e88ba0c13 100644
--- a/config/metrics/counts_28d/20210216181315_g_project_management_issue_made_confidential_monthly.yml
+++ b/config/metrics/counts_28d/20210216181315_g_project_management_issue_made_confidential_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_made_confidential
+events:
+ - name: g_project_management_issue_made_confidential
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181319_g_project_management_issue_made_visible_monthly.yml b/config/metrics/counts_28d/20210216181319_g_project_management_issue_made_visible_monthly.yml
index 764acfd1720..bcf7829efc9 100644
--- a/config/metrics/counts_28d/20210216181319_g_project_management_issue_made_visible_monthly.yml
+++ b/config/metrics/counts_28d/20210216181319_g_project_management_issue_made_visible_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_made_visible
+events:
+ - name: g_project_management_issue_made_visible
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181326_g_project_management_issue_closed_monthly.yml b/config/metrics/counts_28d/20210216181326_g_project_management_issue_closed_monthly.yml
index 962c8d85417..31c7889f4e0 100644
--- a/config/metrics/counts_28d/20210216181326_g_project_management_issue_closed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181326_g_project_management_issue_closed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_closed
+events:
+ - name: g_project_management_issue_closed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181330_g_project_management_issue_reopened_monthly.yml b/config/metrics/counts_28d/20210216181330_g_project_management_issue_reopened_monthly.yml
index 6e1690afaba..f0db7f63c41 100644
--- a/config/metrics/counts_28d/20210216181330_g_project_management_issue_reopened_monthly.yml
+++ b/config/metrics/counts_28d/20210216181330_g_project_management_issue_reopened_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_reopened
+events:
+ - name: g_project_management_issue_reopened
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181334_g_project_management_issue_label_changed_monthly.yml b/config/metrics/counts_28d/20210216181334_g_project_management_issue_label_changed_monthly.yml
index cbf3795eb4e..1498b8bfe36 100644
--- a/config/metrics/counts_28d/20210216181334_g_project_management_issue_label_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181334_g_project_management_issue_label_changed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_label_changed
+events:
+ - name: g_project_management_issue_label_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml b/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml
index a653df04b24..105c05cf675 100644
--- a/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_milestone_changed
+events:
+ - name: g_project_management_issue_milestone_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181348_g_project_management_issue_cross_referenced_monthly.yml b/config/metrics/counts_28d/20210216181348_g_project_management_issue_cross_referenced_monthly.yml
index c476a738721..22dff1fb97f 100644
--- a/config/metrics/counts_28d/20210216181348_g_project_management_issue_cross_referenced_monthly.yml
+++ b/config/metrics/counts_28d/20210216181348_g_project_management_issue_cross_referenced_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_cross_referenced
+events:
+ - name: g_project_management_issue_cross_referenced
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181352_g_project_management_issue_moved_monthly.yml b/config/metrics/counts_28d/20210216181352_g_project_management_issue_moved_monthly.yml
index d7d432060d3..64a5362684a 100644
--- a/config/metrics/counts_28d/20210216181352_g_project_management_issue_moved_monthly.yml
+++ b/config/metrics/counts_28d/20210216181352_g_project_management_issue_moved_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_moved
+events:
+ - name: g_project_management_issue_moved
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181356_g_project_management_issue_related_monthly.yml b/config/metrics/counts_28d/20210216181356_g_project_management_issue_related_monthly.yml
index 62d58bb6da1..aa9cf1b373f 100644
--- a/config/metrics/counts_28d/20210216181356_g_project_management_issue_related_monthly.yml
+++ b/config/metrics/counts_28d/20210216181356_g_project_management_issue_related_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_related
+events:
+ - name: g_project_management_issue_related
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181400_g_project_management_issue_unrelated_monthly.yml b/config/metrics/counts_28d/20210216181400_g_project_management_issue_unrelated_monthly.yml
index 39b482d859b..1ade783a86c 100644
--- a/config/metrics/counts_28d/20210216181400_g_project_management_issue_unrelated_monthly.yml
+++ b/config/metrics/counts_28d/20210216181400_g_project_management_issue_unrelated_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_unrelated
+events:
+ - name: g_project_management_issue_unrelated
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181403_g_project_management_issue_marked_as_duplicate_monthly.yml b/config/metrics/counts_28d/20210216181403_g_project_management_issue_marked_as_duplicate_monthly.yml
index 8d6bb063089..2f74e5c02b1 100644
--- a/config/metrics/counts_28d/20210216181403_g_project_management_issue_marked_as_duplicate_monthly.yml
+++ b/config/metrics/counts_28d/20210216181403_g_project_management_issue_marked_as_duplicate_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_marked_as_duplicate
+events:
+ - name: g_project_management_issue_marked_as_duplicate
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181407_g_project_management_issue_locked_monthly.yml b/config/metrics/counts_28d/20210216181407_g_project_management_issue_locked_monthly.yml
index 290aa31ee18..3052d347ac3 100644
--- a/config/metrics/counts_28d/20210216181407_g_project_management_issue_locked_monthly.yml
+++ b/config/metrics/counts_28d/20210216181407_g_project_management_issue_locked_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_locked
+events:
+ - name: g_project_management_issue_locked
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181411_g_project_management_issue_unlocked_monthly.yml b/config/metrics/counts_28d/20210216181411_g_project_management_issue_unlocked_monthly.yml
index 0f990ee8dcd..6bbd951b728 100644
--- a/config/metrics/counts_28d/20210216181411_g_project_management_issue_unlocked_monthly.yml
+++ b/config/metrics/counts_28d/20210216181411_g_project_management_issue_unlocked_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_unlocked
+events:
+ - name: g_project_management_issue_unlocked
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181424_g_project_management_issue_designs_added_monthly.yml b/config/metrics/counts_28d/20210216181424_g_project_management_issue_designs_added_monthly.yml
index d7958ab29fe..cb7626f3d6a 100644
--- a/config/metrics/counts_28d/20210216181424_g_project_management_issue_designs_added_monthly.yml
+++ b/config/metrics/counts_28d/20210216181424_g_project_management_issue_designs_added_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_designs_added
+events:
+ - name: g_project_management_issue_designs_added
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181427_g_project_management_issue_designs_modified_monthly.yml b/config/metrics/counts_28d/20210216181427_g_project_management_issue_designs_modified_monthly.yml
index 953dbd9f7f0..ac5aeca179b 100644
--- a/config/metrics/counts_28d/20210216181427_g_project_management_issue_designs_modified_monthly.yml
+++ b/config/metrics/counts_28d/20210216181427_g_project_management_issue_designs_modified_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_designs_modified
+events:
+ - name: g_project_management_issue_designs_modified
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181431_g_project_management_issue_designs_removed_monthly.yml b/config/metrics/counts_28d/20210216181431_g_project_management_issue_designs_removed_monthly.yml
index 565f819fedb..a3c1c8659e7 100644
--- a/config/metrics/counts_28d/20210216181431_g_project_management_issue_designs_removed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181431_g_project_management_issue_designs_removed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_designs_removed
+events:
+ - name: g_project_management_issue_designs_removed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181435_g_project_management_issue_due_date_changed_monthly.yml b/config/metrics/counts_28d/20210216181435_g_project_management_issue_due_date_changed_monthly.yml
index cfdecbf45e2..7215fe72399 100644
--- a/config/metrics/counts_28d/20210216181435_g_project_management_issue_due_date_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181435_g_project_management_issue_due_date_changed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_due_date_changed
+events:
+ - name: g_project_management_issue_due_date_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181438_g_project_management_issue_time_estimate_changed_monthly.yml b/config/metrics/counts_28d/20210216181438_g_project_management_issue_time_estimate_changed_monthly.yml
index 0e4892865e1..59f7cf04dc2 100644
--- a/config/metrics/counts_28d/20210216181438_g_project_management_issue_time_estimate_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181438_g_project_management_issue_time_estimate_changed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_time_estimate_changed
+events:
+ - name: g_project_management_issue_time_estimate_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181442_g_project_management_issue_time_spent_changed_monthly.yml b/config/metrics/counts_28d/20210216181442_g_project_management_issue_time_spent_changed_monthly.yml
index c49dc9a076c..e83f0c531bf 100644
--- a/config/metrics/counts_28d/20210216181442_g_project_management_issue_time_spent_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181442_g_project_management_issue_time_spent_changed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_time_spent_changed
+events:
+ - name: g_project_management_issue_time_spent_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181446_g_project_management_issue_comment_added_monthly.yml b/config/metrics/counts_28d/20210216181446_g_project_management_issue_comment_added_monthly.yml
index 28850b5285b..9bc1680c659 100644
--- a/config/metrics/counts_28d/20210216181446_g_project_management_issue_comment_added_monthly.yml
+++ b/config/metrics/counts_28d/20210216181446_g_project_management_issue_comment_added_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_comment_added
+events:
+ - name: g_project_management_issue_comment_added
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181450_g_project_management_issue_comment_edited_monthly.yml b/config/metrics/counts_28d/20210216181450_g_project_management_issue_comment_edited_monthly.yml
index cdf12de3a38..1883c7e8c86 100644
--- a/config/metrics/counts_28d/20210216181450_g_project_management_issue_comment_edited_monthly.yml
+++ b/config/metrics/counts_28d/20210216181450_g_project_management_issue_comment_edited_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_comment_edited
+events:
+ - name: g_project_management_issue_comment_edited
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181453_g_project_management_issue_comment_removed_monthly.yml b/config/metrics/counts_28d/20210216181453_g_project_management_issue_comment_removed_monthly.yml
index 4327a7e60d7..ccc547dfe70 100644
--- a/config/metrics/counts_28d/20210216181453_g_project_management_issue_comment_removed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181453_g_project_management_issue_comment_removed_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_comment_removed
+events:
+ - name: g_project_management_issue_comment_removed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181501_g_project_management_issue_cloned_monthly.yml b/config/metrics/counts_28d/20210216181501_g_project_management_issue_cloned_monthly.yml
index de4fc157b43..bcacebdc77f 100644
--- a/config/metrics/counts_28d/20210216181501_g_project_management_issue_cloned_monthly.yml
+++ b/config/metrics/counts_28d/20210216181501_g_project_management_issue_cloned_monthly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_cloned
+events:
+ - name: g_project_management_issue_cloned
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181951_clusters_applications_runner.yml b/config/metrics/counts_28d/20210216181951_clusters_applications_runner.yml
index 2509db0052d..1c26a58c152 100644
--- a/config/metrics/counts_28d/20210216181951_clusters_applications_runner.yml
+++ b/config/metrics/counts_28d/20210216181951_clusters_applications_runner.yml
@@ -20,3 +20,4 @@ performance_indicator_type: []
milestone: "12.9"
introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26441"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216183203_product_analytics_test_metrics_union.yml b/config/metrics/counts_28d/20210216183203_product_analytics_test_metrics_union.yml
index c9c8673285a..d82ee32ee24 100644
--- a/config/metrics/counts_28d/20210216183203_product_analytics_test_metrics_union.yml
+++ b/config/metrics/counts_28d/20210216183203_product_analytics_test_metrics_union.yml
@@ -19,3 +19,4 @@ tier:
- free
- premium
- ultimate
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216183205_product_analytics_test_metrics_intersection.yml b/config/metrics/counts_28d/20210216183205_product_analytics_test_metrics_intersection.yml
index 5072ab05abe..4554ece2cec 100644
--- a/config/metrics/counts_28d/20210216183205_product_analytics_test_metrics_intersection.yml
+++ b/config/metrics/counts_28d/20210216183205_product_analytics_test_metrics_intersection.yml
@@ -19,3 +19,4 @@ tier:
- free
- premium
- ultimate
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216183640_gitlab.yml b/config/metrics/counts_28d/20210216183640_gitlab.yml
index 491e71844fd..137543ac9cb 100644
--- a/config/metrics/counts_28d/20210216183640_gitlab.yml
+++ b/config/metrics/counts_28d/20210216183640_gitlab.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183646_gitlab.yml b/config/metrics/counts_28d/20210216183646_gitlab.yml
index 0aa35644f9b..afc6a099bb3 100644
--- a/config/metrics/counts_28d/20210216183646_gitlab.yml
+++ b/config/metrics/counts_28d/20210216183646_gitlab.yml
@@ -22,3 +22,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216183712_total.yml b/config/metrics/counts_28d/20210216183712_total.yml
index c9b916cf2bd..6c610c91e95 100644
--- a/config/metrics/counts_28d/20210216183712_total.yml
+++ b/config/metrics/counts_28d/20210216183712_total.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183714_gitlab_project.yml b/config/metrics/counts_28d/20210216183714_gitlab_project.yml
index 3b9642da6ac..117101fdd85 100644
--- a/config/metrics/counts_28d/20210216183714_gitlab_project.yml
+++ b/config/metrics/counts_28d/20210216183714_gitlab_project.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183716_gitlab.yml b/config/metrics/counts_28d/20210216183716_gitlab.yml
index 0ac957a8b4b..5125e4734cb 100644
--- a/config/metrics/counts_28d/20210216183716_gitlab.yml
+++ b/config/metrics/counts_28d/20210216183716_gitlab.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183718_github.yml b/config/metrics/counts_28d/20210216183718_github.yml
index ad199ad3e30..6e41dcefa1f 100644
--- a/config/metrics/counts_28d/20210216183718_github.yml
+++ b/config/metrics/counts_28d/20210216183718_github.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183720_bitbucket.yml b/config/metrics/counts_28d/20210216183720_bitbucket.yml
index 04de804a4ac..25459551626 100644
--- a/config/metrics/counts_28d/20210216183720_bitbucket.yml
+++ b/config/metrics/counts_28d/20210216183720_bitbucket.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183722_bitbucket_server.yml b/config/metrics/counts_28d/20210216183722_bitbucket_server.yml
index 96aa85bd03d..43cdf486432 100644
--- a/config/metrics/counts_28d/20210216183722_bitbucket_server.yml
+++ b/config/metrics/counts_28d/20210216183722_bitbucket_server.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183724_gitea.yml b/config/metrics/counts_28d/20210216183724_gitea.yml
index ef967c52699..65687e9c77a 100644
--- a/config/metrics/counts_28d/20210216183724_gitea.yml
+++ b/config/metrics/counts_28d/20210216183724_gitea.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183726_git.yml b/config/metrics/counts_28d/20210216183726_git.yml
index 779485a9e3c..7083bd8d948 100644
--- a/config/metrics/counts_28d/20210216183726_git.yml
+++ b/config/metrics/counts_28d/20210216183726_git.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183728_manifest.yml b/config/metrics/counts_28d/20210216183728_manifest.yml
index 822ea1f9bfa..1595ca00598 100644
--- a/config/metrics/counts_28d/20210216183728_manifest.yml
+++ b/config/metrics/counts_28d/20210216183728_manifest.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183730_jira.yml b/config/metrics/counts_28d/20210216183730_jira.yml
index 2d54f765858..37c9b9a7b66 100644
--- a/config/metrics/counts_28d/20210216183730_jira.yml
+++ b/config/metrics/counts_28d/20210216183730_jira.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183731_fogbugz.yml b/config/metrics/counts_28d/20210216183731_fogbugz.yml
index 83c8e3771c0..b7321cdb765 100644
--- a/config/metrics/counts_28d/20210216183731_fogbugz.yml
+++ b/config/metrics/counts_28d/20210216183731_fogbugz.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183733_phabricator.yml b/config/metrics/counts_28d/20210216183733_phabricator.yml
index 8108a98f4fd..61bd88b547f 100644
--- a/config/metrics/counts_28d/20210216183733_phabricator.yml
+++ b/config/metrics/counts_28d/20210216183733_phabricator.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183735_csv.yml b/config/metrics/counts_28d/20210216183735_csv.yml
index a309a3d1f2d..52288129b53 100644
--- a/config/metrics/counts_28d/20210216183735_csv.yml
+++ b/config/metrics/counts_28d/20210216183735_csv.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216183737_groups_imported.yml b/config/metrics/counts_28d/20210216183737_groups_imported.yml
index 79e39cb214e..d9b572c7d45 100644
--- a/config/metrics/counts_28d/20210216183737_groups_imported.yml
+++ b/config/metrics/counts_28d/20210216183737_groups_imported.yml
@@ -18,3 +18,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml
index af835f558d1..21527d0cf3b 100644
--- a/config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184140_testing_total_unique_counts_monthly.yml
@@ -25,3 +25,5 @@ tier:
- free
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml
index 8ad0494e775..77b94b5ae13 100644
--- a/config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml
@@ -8,7 +8,7 @@ product_section: 'TBD'
value_type: number
status: removed
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113422
-milestone_removed: 15.10
+milestone_removed: "15.10"
time_frame: 28d
data_source: redis_hll
instrumentation_class: AggregatedMetric
diff --git a/config/metrics/counts_28d/20210216184502_p_ci_templates_implicit_auto_devops_build_monthly.yml b/config/metrics/counts_28d/20210216184502_p_ci_templates_implicit_auto_devops_build_monthly.yml
index b88fcc4d439..bf355b1b604 100644
--- a/config/metrics/counts_28d/20210216184502_p_ci_templates_implicit_auto_devops_build_monthly.yml
+++ b/config/metrics/counts_28d/20210216184502_p_ci_templates_implicit_auto_devops_build_monthly.yml
@@ -22,3 +22,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216184506_p_ci_templates_implicit_auto_devops_deploy_monthly.yml b/config/metrics/counts_28d/20210216184506_p_ci_templates_implicit_auto_devops_deploy_monthly.yml
index 33e3ef689d3..21348ba580b 100644
--- a/config/metrics/counts_28d/20210216184506_p_ci_templates_implicit_auto_devops_deploy_monthly.yml
+++ b/config/metrics/counts_28d/20210216184506_p_ci_templates_implicit_auto_devops_deploy_monthly.yml
@@ -22,3 +22,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216184517_p_ci_templates_5_min_production_app_monthly.yml b/config/metrics/counts_28d/20210216184517_p_ci_templates_5_min_production_app_monthly.yml
index c546fba8629..ee41e49bcad 100644
--- a/config/metrics/counts_28d/20210216184517_p_ci_templates_5_min_production_app_monthly.yml
+++ b/config/metrics/counts_28d/20210216184517_p_ci_templates_5_min_production_app_monthly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_5_min_production_app_mo
description: Number of projects using 5 min production app CI template in last 7 days.
product_section: seg
product_stage: deploy
-product_group: 5-min-app
+product_group: five_min_app
value_type: number
status: removed
milestone_removed: '14.6'
@@ -23,3 +23,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216184526_p_ci_templates_aws_cf_deploy_ec2_monthly.yml b/config/metrics/counts_28d/20210216184526_p_ci_templates_aws_cf_deploy_ec2_monthly.yml
index e59a9924647..230a99b1a0b 100644
--- a/config/metrics/counts_28d/20210216184526_p_ci_templates_aws_cf_deploy_ec2_monthly.yml
+++ b/config/metrics/counts_28d/20210216184526_p_ci_templates_aws_cf_deploy_ec2_monthly.yml
@@ -23,3 +23,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216184534_p_ci_templates_auto_devops_build_monthly.yml b/config/metrics/counts_28d/20210216184534_p_ci_templates_auto_devops_build_monthly.yml
index b31fae55802..801de933415 100644
--- a/config/metrics/counts_28d/20210216184534_p_ci_templates_auto_devops_build_monthly.yml
+++ b/config/metrics/counts_28d/20210216184534_p_ci_templates_auto_devops_build_monthly.yml
@@ -23,3 +23,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216184538_p_ci_templates_auto_devops_deploy_monthly.yml b/config/metrics/counts_28d/20210216184538_p_ci_templates_auto_devops_deploy_monthly.yml
index cc3747ae053..5ab6f0478e0 100644
--- a/config/metrics/counts_28d/20210216184538_p_ci_templates_auto_devops_deploy_monthly.yml
+++ b/config/metrics/counts_28d/20210216184538_p_ci_templates_auto_devops_deploy_monthly.yml
@@ -23,3 +23,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216184542_p_ci_templates_auto_devops_deploy_latest_monthly.yml b/config/metrics/counts_28d/20210216184542_p_ci_templates_auto_devops_deploy_latest_monthly.yml
index c5f9d63772f..633284ff05f 100644
--- a/config/metrics/counts_28d/20210216184542_p_ci_templates_auto_devops_deploy_latest_monthly.yml
+++ b/config/metrics/counts_28d/20210216184542_p_ci_templates_auto_devops_deploy_latest_monthly.yml
@@ -22,3 +22,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
index bfef9b0ed10..97ff6a51c48 100755
--- a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
@@ -30,6 +30,7 @@ options:
- p_ci_templates_rust
- p_ci_templates_elixir
- p_ci_templates_clojure
+ - p_ci_templates_cosign
- p_ci_templates_crystal
- p_ci_templates_getting_started
- p_ci_templates_code_quality
@@ -189,3 +190,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_28d/20210216184814_i_package_container_deploy_token_monthly.yml b/config/metrics/counts_28d/20210216184814_i_package_container_deploy_token_monthly.yml
index 3b7c46665cb..fb152f8ff60 100644
--- a/config/metrics/counts_28d/20210216184814_i_package_container_deploy_token_monthly.yml
+++ b/config/metrics/counts_28d/20210216184814_i_package_container_deploy_token_monthly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184818_i_package_debian_deploy_token_monthly.yml b/config/metrics/counts_28d/20210216184818_i_package_debian_deploy_token_monthly.yml
index 745c2ee2e5b..89c15abab51 100644
--- a/config/metrics/counts_28d/20210216184818_i_package_debian_deploy_token_monthly.yml
+++ b/config/metrics/counts_28d/20210216184818_i_package_debian_deploy_token_monthly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184826_i_package_golang_deploy_token_monthly.yml b/config/metrics/counts_28d/20210216184826_i_package_golang_deploy_token_monthly.yml
index 06d5ba1a1c9..61bc85e6891 100644
--- a/config/metrics/counts_28d/20210216184826_i_package_golang_deploy_token_monthly.yml
+++ b/config/metrics/counts_28d/20210216184826_i_package_golang_deploy_token_monthly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184846_i_package_tag_deploy_token_monthly.yml b/config/metrics/counts_28d/20210216184846_i_package_tag_deploy_token_monthly.yml
index cc15da4ab35..804bdf0fdd7 100644
--- a/config/metrics/counts_28d/20210216184846_i_package_tag_deploy_token_monthly.yml
+++ b/config/metrics/counts_28d/20210216184846_i_package_tag_deploy_token_monthly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184902_i_package_container_user_monthly.yml b/config/metrics/counts_28d/20210216184902_i_package_container_user_monthly.yml
index e415623ff53..3432e073b5d 100644
--- a/config/metrics/counts_28d/20210216184902_i_package_container_user_monthly.yml
+++ b/config/metrics/counts_28d/20210216184902_i_package_container_user_monthly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184906_i_package_debian_user_monthly.yml b/config/metrics/counts_28d/20210216184906_i_package_debian_user_monthly.yml
index 6b805cedbe4..12ccd12953f 100644
--- a/config/metrics/counts_28d/20210216184906_i_package_debian_user_monthly.yml
+++ b/config/metrics/counts_28d/20210216184906_i_package_debian_user_monthly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184913_i_package_golang_user_monthly.yml b/config/metrics/counts_28d/20210216184913_i_package_golang_user_monthly.yml
index 3c7e09e69fd..c506833515d 100644
--- a/config/metrics/counts_28d/20210216184913_i_package_golang_user_monthly.yml
+++ b/config/metrics/counts_28d/20210216184913_i_package_golang_user_monthly.yml
@@ -21,3 +21,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210216184933_i_package_tag_user_monthly.yml b/config/metrics/counts_28d/20210216184933_i_package_tag_user_monthly.yml
index f7a7af76999..d9064eb6f8d 100644
--- a/config/metrics/counts_28d/20210216184933_i_package_tag_user_monthly.yml
+++ b/config/metrics/counts_28d/20210216184933_i_package_tag_user_monthly.yml
@@ -21,3 +21,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml b/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
index 18f4ed24837..eeffe48b256 100644
--- a/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
+++ b/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
@@ -142,3 +142,4 @@ options:
- 'i_code_review_saved_replies_create'
- 'i_code_review_saved_replies_use'
- 'i_code_review_saved_replies_use_in_mr'
+ - 'i_code_review_saved_replies_use_in_other'
diff --git a/config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml b/config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml
index 796acd20d15..36115c9bcc2 100644
--- a/config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml
+++ b/config/metrics/counts_28d/20210427103119_code_review_group_monthly_active_users.yml
@@ -147,3 +147,4 @@ options:
- 'i_code_review_saved_replies_create'
- 'i_code_review_saved_replies_use'
- 'i_code_review_saved_replies_use_in_mr'
+ - 'i_code_review_saved_replies_use_in_other'
diff --git a/config/metrics/counts_28d/20210902000813_p_ci_templates_implicit_auto_devops_deploy_latest_monthly.yml b/config/metrics/counts_28d/20210902000813_p_ci_templates_implicit_auto_devops_deploy_latest_monthly.yml
index 66f66f4ef6a..072cd9b84e4 100644
--- a/config/metrics/counts_28d/20210902000813_p_ci_templates_implicit_auto_devops_deploy_latest_monthly.yml
+++ b/config/metrics/counts_28d/20210902000813_p_ci_templates_implicit_auto_devops_deploy_latest_monthly.yml
@@ -23,3 +23,4 @@ tier:
options:
events:
- p_ci_templates_implicit_auto_devops_deploy_latest
+removed_by_url:
diff --git a/config/metrics/counts_28d/20211126084446_p_analytics_ci_cd_pipelines_monthly.yml b/config/metrics/counts_28d/20211126084446_p_analytics_ci_cd_pipelines_monthly.yml
index 845500bff73..f84d9c7483a 100644
--- a/config/metrics/counts_28d/20211126084446_p_analytics_ci_cd_pipelines_monthly.yml
+++ b/config/metrics/counts_28d/20211126084446_p_analytics_ci_cd_pipelines_monthly.yml
@@ -13,6 +13,9 @@ data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
+events:
+ - name: p_analytics_ci_cd_pipelines
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20211126090835_p_analytics_ci_cd_deployment_frequency_monthly.yml b/config/metrics/counts_28d/20211126090835_p_analytics_ci_cd_deployment_frequency_monthly.yml
index d719ac3e5d1..6569027515f 100644
--- a/config/metrics/counts_28d/20211126090835_p_analytics_ci_cd_deployment_frequency_monthly.yml
+++ b/config/metrics/counts_28d/20211126090835_p_analytics_ci_cd_deployment_frequency_monthly.yml
@@ -13,6 +13,9 @@ data_source: redis_hll
data_category: operational
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
+events:
+ - name: p_analytics_ci_cd_deployment_frequency
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20211126091206_p_analytics_ci_cd_lead_time_monthly.yml b/config/metrics/counts_28d/20211126091206_p_analytics_ci_cd_lead_time_monthly.yml
index d0640d97d37..63d1ed5d0c6 100644
--- a/config/metrics/counts_28d/20211126091206_p_analytics_ci_cd_lead_time_monthly.yml
+++ b/config/metrics/counts_28d/20211126091206_p_analytics_ci_cd_lead_time_monthly.yml
@@ -13,6 +13,9 @@ data_source: redis_hll
data_category: operational
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
+events:
+ - name: p_analytics_ci_cd_lead_time
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20220428154012_live_preview.yml b/config/metrics/counts_28d/20220428154012_live_preview.yml
index e048398da57..91ad9718aad 100644
--- a/config/metrics/counts_28d/20220428154012_live_preview.yml
+++ b/config/metrics/counts_28d/20220428154012_live_preview.yml
@@ -6,7 +6,7 @@ product_section: dev
product_stage: create
product_group: ide
value_type: number
-status: active
+status: removed
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85420
time_frame: 28d
data_source: redis_hll
@@ -23,3 +23,5 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "15.0"
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131356
+milestone_removed: '16.4'
diff --git a/config/metrics/counts_28d/20220525231314_unique_monthly_active_users.yml b/config/metrics/counts_28d/20220525231314_unique_monthly_active_users.yml
index bb2e8bd8453..4749b9511bb 100644
--- a/config/metrics/counts_28d/20220525231314_unique_monthly_active_users.yml
+++ b/config/metrics/counts_28d/20220525231314_unique_monthly_active_users.yml
@@ -20,3 +20,4 @@ tier:
- free
- premium
- ultimate
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_28d/20221213182900_i_code_review_create_mr_monthly.yml b/config/metrics/counts_28d/20221213182900_i_code_review_create_mr_monthly.yml
index 252559b3b20..740183d7286 100644
--- a/config/metrics/counts_28d/20221213182900_i_code_review_create_mr_monthly.yml
+++ b/config/metrics/counts_28d/20221213182900_i_code_review_create_mr_monthly.yml
@@ -12,7 +12,8 @@ time_frame: 28d
data_source: redis_hll
data_category: operational
instrumentation_class: RedisHLLMetric
-performance_indicator_type: []
+performance_indicator_type:
+- customer_health_score
options:
events:
- i_code_review_create_mr
diff --git a/config/metrics/counts_28d/20230105222225_g_project_management_issue_design_comments_removed_monthly.yml b/config/metrics/counts_28d/20230105222225_g_project_management_issue_design_comments_removed_monthly.yml
index dc62055774b..c1506710e62 100644
--- a/config/metrics/counts_28d/20230105222225_g_project_management_issue_design_comments_removed_monthly.yml
+++ b/config/metrics/counts_28d/20230105222225_g_project_management_issue_design_comments_removed_monthly.yml
@@ -9,13 +9,16 @@ status: active
milestone: "15.9"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108307
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
options:
events:
- g_project_management_issue_design_comments_removed
+events:
+ - name: g_project_management_issue_design_comments_removed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20230531170613_ci_builds.yml b/config/metrics/counts_28d/20230531170613_ci_builds.yml
index c55ad452666..c8b0a5d8e75 100644
--- a/config/metrics/counts_28d/20230531170613_ci_builds.yml
+++ b/config/metrics/counts_28d/20230531170613_ci_builds.yml
@@ -12,7 +12,8 @@ time_frame: 28d
data_source: database
data_category: operational
instrumentation_class: CountAllCiBuildsMetric
-performance_indicator_type: []
+performance_indicator_type:
+- customer_health_score
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20230724140653_i_code_review_saved_replies_create_monthly.yml b/config/metrics/counts_28d/20230724140653_i_code_review_saved_replies_create_monthly.yml
index ac891dcc18c..2728c2b28ee 100644
--- a/config/metrics/counts_28d/20230724140653_i_code_review_saved_replies_create_monthly.yml
+++ b/config/metrics/counts_28d/20230724140653_i_code_review_saved_replies_create_monthly.yml
@@ -9,7 +9,7 @@ status: active
milestone: "16.3"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126884
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
@@ -23,3 +23,6 @@ tier:
options:
events:
- i_code_review_saved_replies_create
+events:
+ - name: i_code_review_saved_replies_create
+ unique: user.id
diff --git a/config/metrics/counts_28d/20230725194658_i_code_review_saved_replies_use_monthly.yml b/config/metrics/counts_28d/20230725194658_i_code_review_saved_replies_use_monthly.yml
index 5ccc10bb457..1be1b6f2c80 100644
--- a/config/metrics/counts_28d/20230725194658_i_code_review_saved_replies_use_monthly.yml
+++ b/config/metrics/counts_28d/20230725194658_i_code_review_saved_replies_use_monthly.yml
@@ -9,7 +9,7 @@ status: active
milestone: "16.3"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127442
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
@@ -23,3 +23,6 @@ tier:
options:
events:
- i_code_review_saved_replies_use
+events:
+ - name: i_code_review_saved_replies_use
+ unique: user.id
diff --git a/config/metrics/counts_28d/20230809194743_i_code_review_saved_replies_use_in_mr_monthly.yml b/config/metrics/counts_28d/20230809194743_i_code_review_saved_replies_use_in_mr_monthly.yml
index 490dbfadcd2..41274753ae8 100644
--- a/config/metrics/counts_28d/20230809194743_i_code_review_saved_replies_use_in_mr_monthly.yml
+++ b/config/metrics/counts_28d/20230809194743_i_code_review_saved_replies_use_in_mr_monthly.yml
@@ -9,7 +9,7 @@ status: active
milestone: "16.3"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128821
time_frame: 28d
-data_source: redis_hll
+data_source: internal_events
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
@@ -23,3 +23,6 @@ tier:
options:
events:
- i_code_review_saved_replies_use_in_mr
+events:
+ - name: i_code_review_saved_replies_use_in_mr
+ unique: user.id
diff --git a/config/metrics/counts_28d/20230810124157_count_cicd_component_usage_monthly.yml b/config/metrics/counts_28d/20230810124157_count_cicd_component_usage_monthly.yml
new file mode 100644
index 00000000000..d860dddef12
--- /dev/null
+++ b/config/metrics/counts_28d/20230810124157_count_cicd_component_usage_monthly.yml
@@ -0,0 +1,23 @@
+---
+key_path: redis_hll_counters.pipeline_authoring.count_cicd_component_usage_monthly
+description: Monthly count of CI/CD component usage
+product_section: ops
+product_stage: verify
+product_group: pipeline_authoring
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129016
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+- ce
+tier:
+- premium
+- ultimate
+options:
+ events:
+ - cicd_component_usage
diff --git a/config/metrics/counts_28d/20230815171559_i_code_review_saved_replies_use_in_other_monthly.yml b/config/metrics/counts_28d/20230815171559_i_code_review_saved_replies_use_in_other_monthly.yml
new file mode 100644
index 00000000000..a604a4f1955
--- /dev/null
+++ b/config/metrics/counts_28d/20230815171559_i_code_review_saved_replies_use_in_other_monthly.yml
@@ -0,0 +1,28 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_saved_replies_use_in_other_monthly
+description: Count of unique users who used the saved replies feature over a month
+product_section: dev
+product_stage: create
+product_group: code_review
+value_type: number
+status: active
+milestone: "16.3"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128822
+time_frame: 28d
+data_source: internal_events
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - i_code_review_saved_replies_use_in_other
+events:
+ - name: i_code_review_saved_replies_use_in_other
+ unique: user.id
diff --git a/config/metrics/counts_28d/20230816085153_k8s_api_proxy_requests_unique_agents_via_pat_access_monthly.yml b/config/metrics/counts_28d/20230816085153_k8s_api_proxy_requests_unique_agents_via_pat_access_monthly.yml
new file mode 100644
index 00000000000..72cbb938baf
--- /dev/null
+++ b/config/metrics/counts_28d/20230816085153_k8s_api_proxy_requests_unique_agents_via_pat_access_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_agents_via_pat_access_monthly
+description: MAU of the unique Agents using the KAS Kubernetes API proxy via Personal Access Token Access
+product_section: ops
+product_stage: deploy
+product_group: environment
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129463
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - k8s_api_proxy_requests_unique_agents_via_pat_access
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20230816085153_k8s_api_proxy_requests_unique_users_via_pat_access_monthly.yml b/config/metrics/counts_28d/20230816085153_k8s_api_proxy_requests_unique_users_via_pat_access_monthly.yml
new file mode 100644
index 00000000000..5f987f91425
--- /dev/null
+++ b/config/metrics/counts_28d/20230816085153_k8s_api_proxy_requests_unique_users_via_pat_access_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_users_via_pat_access_monthly
+description: MAU of the unique Users using the KAS Kubernetes API proxy via Personal Access Token Access
+product_section: ops
+product_stage: deploy
+product_group: environment
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129463
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - k8s_api_proxy_requests_unique_users_via_pat_access
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20230830153031_p_ci_templates_cosign_monthly.yml b/config/metrics/counts_28d/20230830153031_p_ci_templates_cosign_monthly.yml
new file mode 100644
index 00000000000..95071956e38
--- /dev/null
+++ b/config/metrics/counts_28d/20230830153031_p_ci_templates_cosign_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_cosign_monthly
+description: Count of pipelines using the Cosign CI template.
+product_section: ci
+product_stage: verify
+product_group: pipeline_security
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130339
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_cosign
diff --git a/config/metrics/counts_7d/20210201124931_g_project_management_issue_title_changed_weekly.yml b/config/metrics/counts_7d/20210201124931_g_project_management_issue_title_changed_weekly.yml
index a283ced7da8..0a02bafbcf8 100644
--- a/config/metrics/counts_7d/20210201124931_g_project_management_issue_title_changed_weekly.yml
+++ b/config/metrics/counts_7d/20210201124931_g_project_management_issue_title_changed_weekly.yml
@@ -10,11 +10,14 @@ status: active
milestone: "13.6"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_title_changed
+events:
+ - name: g_project_management_issue_title_changed
+ unique: user.id
distribution:
- ee
- ce
diff --git a/config/metrics/counts_7d/20210216174900_i_analytics_dev_ops_score.yml b/config/metrics/counts_7d/20210216174900_i_analytics_dev_ops_score.yml
index 370cf7a3f50..e8356d5395b 100644
--- a/config/metrics/counts_7d/20210216174900_i_analytics_dev_ops_score.yml
+++ b/config/metrics/counts_7d/20210216174900_i_analytics_dev_ops_score.yml
@@ -8,11 +8,14 @@ product_group: optimize
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- i_analytics_dev_ops_score
+events:
+ - name: i_analytics_dev_ops_score
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216174902_g_analytics_merge_request.yml b/config/metrics/counts_7d/20210216174902_g_analytics_merge_request.yml
index 8200576a27b..7bd4a0c21f3 100644
--- a/config/metrics/counts_7d/20210216174902_g_analytics_merge_request.yml
+++ b/config/metrics/counts_7d/20210216174902_g_analytics_merge_request.yml
@@ -21,3 +21,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216180328_g_edit_by_web_ide_weekly.yml b/config/metrics/counts_7d/20210216180328_g_edit_by_web_ide_weekly.yml
index 1be0ba4f96d..67c06a60d17 100644
--- a/config/metrics/counts_7d/20210216180328_g_edit_by_web_ide_weekly.yml
+++ b/config/metrics/counts_7d/20210216180328_g_edit_by_web_ide_weekly.yml
@@ -8,7 +8,7 @@ product_group: ide
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
diff --git a/config/metrics/counts_7d/20210216180336_g_edit_by_snippet_ide_weekly.yml b/config/metrics/counts_7d/20210216180336_g_edit_by_snippet_ide_weekly.yml
index afc3c9db8a0..faaf35cd648 100644
--- a/config/metrics/counts_7d/20210216180336_g_edit_by_snippet_ide_weekly.yml
+++ b/config/metrics/counts_7d/20210216180336_g_edit_by_snippet_ide_weekly.yml
@@ -8,7 +8,7 @@ product_group: source_code
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
diff --git a/config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml
index 413a032309e..035c17faef5 100644
--- a/config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216180339_ide_edit_total_unique_counts_weekly.yml
@@ -18,7 +18,6 @@ options:
- g_edit_by_web_ide
- g_edit_by_sfe
- g_edit_by_snippet_ide
- - g_edit_by_live_preview
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181306_g_project_management_issue_description_changed_weekly.yml b/config/metrics/counts_7d/20210216181306_g_project_management_issue_description_changed_weekly.yml
index 2af4e6523f1..e8122d51032 100644
--- a/config/metrics/counts_7d/20210216181306_g_project_management_issue_description_changed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181306_g_project_management_issue_description_changed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_description_changed
+events:
+ - name: g_project_management_issue_description_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181310_g_project_management_issue_assignee_changed_weekly.yml b/config/metrics/counts_7d/20210216181310_g_project_management_issue_assignee_changed_weekly.yml
index 933f1bf3e3b..a77403bc36c 100644
--- a/config/metrics/counts_7d/20210216181310_g_project_management_issue_assignee_changed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181310_g_project_management_issue_assignee_changed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_assignee_changed
+events:
+ - name: g_project_management_issue_assignee_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181313_g_project_management_issue_made_confidential_weekly.yml b/config/metrics/counts_7d/20210216181313_g_project_management_issue_made_confidential_weekly.yml
index 352c5e44d47..bae0105a84b 100644
--- a/config/metrics/counts_7d/20210216181313_g_project_management_issue_made_confidential_weekly.yml
+++ b/config/metrics/counts_7d/20210216181313_g_project_management_issue_made_confidential_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_made_confidential
+events:
+ - name: g_project_management_issue_made_confidential
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181317_g_project_management_issue_made_visible_weekly.yml b/config/metrics/counts_7d/20210216181317_g_project_management_issue_made_visible_weekly.yml
index 41ba3cc3f79..ea60d6448ad 100644
--- a/config/metrics/counts_7d/20210216181317_g_project_management_issue_made_visible_weekly.yml
+++ b/config/metrics/counts_7d/20210216181317_g_project_management_issue_made_visible_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_made_visible
+events:
+ - name: g_project_management_issue_made_visible
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181324_g_project_management_issue_closed_weekly.yml b/config/metrics/counts_7d/20210216181324_g_project_management_issue_closed_weekly.yml
index 0349cc014be..ef4de1fecbc 100644
--- a/config/metrics/counts_7d/20210216181324_g_project_management_issue_closed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181324_g_project_management_issue_closed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_closed
+events:
+ - name: g_project_management_issue_closed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181328_g_project_management_issue_reopened_weekly.yml b/config/metrics/counts_7d/20210216181328_g_project_management_issue_reopened_weekly.yml
index 3d7bd3888f7..88c4b06a85c 100644
--- a/config/metrics/counts_7d/20210216181328_g_project_management_issue_reopened_weekly.yml
+++ b/config/metrics/counts_7d/20210216181328_g_project_management_issue_reopened_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_reopened
+events:
+ - name: g_project_management_issue_reopened
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181332_g_project_management_issue_label_changed_weekly.yml b/config/metrics/counts_7d/20210216181332_g_project_management_issue_label_changed_weekly.yml
index cb2f31a2c26..7e6fbf1100d 100644
--- a/config/metrics/counts_7d/20210216181332_g_project_management_issue_label_changed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181332_g_project_management_issue_label_changed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_label_changed
+events:
+ - name: g_project_management_issue_label_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181336_g_project_management_issue_milestone_changed_weekly.yml b/config/metrics/counts_7d/20210216181336_g_project_management_issue_milestone_changed_weekly.yml
index bbe4d122847..2f22e39d755 100644
--- a/config/metrics/counts_7d/20210216181336_g_project_management_issue_milestone_changed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181336_g_project_management_issue_milestone_changed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_milestone_changed
+events:
+ - name: g_project_management_issue_milestone_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181347_g_project_management_issue_cross_referenced_weekly.yml b/config/metrics/counts_7d/20210216181347_g_project_management_issue_cross_referenced_weekly.yml
index b1c13ef367c..3a30243e957 100644
--- a/config/metrics/counts_7d/20210216181347_g_project_management_issue_cross_referenced_weekly.yml
+++ b/config/metrics/counts_7d/20210216181347_g_project_management_issue_cross_referenced_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_cross_referenced
+events:
+ - name: g_project_management_issue_cross_referenced
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181350_g_project_management_issue_moved_weekly.yml b/config/metrics/counts_7d/20210216181350_g_project_management_issue_moved_weekly.yml
index f72c83ab3df..0c1d763602a 100644
--- a/config/metrics/counts_7d/20210216181350_g_project_management_issue_moved_weekly.yml
+++ b/config/metrics/counts_7d/20210216181350_g_project_management_issue_moved_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_moved
+events:
+ - name: g_project_management_issue_moved
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181354_g_project_management_issue_related_weekly.yml b/config/metrics/counts_7d/20210216181354_g_project_management_issue_related_weekly.yml
index f42e99b4514..968fec1bcb6 100644
--- a/config/metrics/counts_7d/20210216181354_g_project_management_issue_related_weekly.yml
+++ b/config/metrics/counts_7d/20210216181354_g_project_management_issue_related_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_related
+events:
+ - name: g_project_management_issue_related
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181358_g_project_management_issue_unrelated_weekly.yml b/config/metrics/counts_7d/20210216181358_g_project_management_issue_unrelated_weekly.yml
index e8b06010a17..35ef8eeaded 100644
--- a/config/metrics/counts_7d/20210216181358_g_project_management_issue_unrelated_weekly.yml
+++ b/config/metrics/counts_7d/20210216181358_g_project_management_issue_unrelated_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_unrelated
+events:
+ - name: g_project_management_issue_unrelated
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181401_g_project_management_issue_marked_as_duplicate_weekly.yml b/config/metrics/counts_7d/20210216181401_g_project_management_issue_marked_as_duplicate_weekly.yml
index 13c783fd07f..9f0bec1398c 100644
--- a/config/metrics/counts_7d/20210216181401_g_project_management_issue_marked_as_duplicate_weekly.yml
+++ b/config/metrics/counts_7d/20210216181401_g_project_management_issue_marked_as_duplicate_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_marked_as_duplicate
+events:
+ - name: g_project_management_issue_marked_as_duplicate
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181405_g_project_management_issue_locked_weekly.yml b/config/metrics/counts_7d/20210216181405_g_project_management_issue_locked_weekly.yml
index 6a07d05d9ec..20d04fa08ac 100644
--- a/config/metrics/counts_7d/20210216181405_g_project_management_issue_locked_weekly.yml
+++ b/config/metrics/counts_7d/20210216181405_g_project_management_issue_locked_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_locked
+events:
+ - name: g_project_management_issue_locked
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181409_g_project_management_issue_unlocked_weekly.yml b/config/metrics/counts_7d/20210216181409_g_project_management_issue_unlocked_weekly.yml
index 69550cb65d1..e76cd94222f 100644
--- a/config/metrics/counts_7d/20210216181409_g_project_management_issue_unlocked_weekly.yml
+++ b/config/metrics/counts_7d/20210216181409_g_project_management_issue_unlocked_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_unlocked
+events:
+ - name: g_project_management_issue_unlocked
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181422_g_project_management_issue_designs_added_weekly.yml b/config/metrics/counts_7d/20210216181422_g_project_management_issue_designs_added_weekly.yml
index 1b686f6c0d4..d283b0e2356 100644
--- a/config/metrics/counts_7d/20210216181422_g_project_management_issue_designs_added_weekly.yml
+++ b/config/metrics/counts_7d/20210216181422_g_project_management_issue_designs_added_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_designs_added
+events:
+ - name: g_project_management_issue_designs_added
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181425_g_project_management_issue_designs_modified_weekly.yml b/config/metrics/counts_7d/20210216181425_g_project_management_issue_designs_modified_weekly.yml
index 06f3416d58e..f1a8f436bbf 100644
--- a/config/metrics/counts_7d/20210216181425_g_project_management_issue_designs_modified_weekly.yml
+++ b/config/metrics/counts_7d/20210216181425_g_project_management_issue_designs_modified_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_designs_modified
+events:
+ - name: g_project_management_issue_designs_modified
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181429_g_project_management_issue_designs_removed_weekly.yml b/config/metrics/counts_7d/20210216181429_g_project_management_issue_designs_removed_weekly.yml
index 9c573914f88..43ecbbfd127 100644
--- a/config/metrics/counts_7d/20210216181429_g_project_management_issue_designs_removed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181429_g_project_management_issue_designs_removed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_designs_removed
+events:
+ - name: g_project_management_issue_designs_removed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181433_g_project_management_issue_due_date_changed_weekly.yml b/config/metrics/counts_7d/20210216181433_g_project_management_issue_due_date_changed_weekly.yml
index 89e331307bc..b2b92df10fb 100644
--- a/config/metrics/counts_7d/20210216181433_g_project_management_issue_due_date_changed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181433_g_project_management_issue_due_date_changed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_due_date_changed
+events:
+ - name: g_project_management_issue_due_date_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181437_g_project_management_issue_time_estimate_changed_weekly.yml b/config/metrics/counts_7d/20210216181437_g_project_management_issue_time_estimate_changed_weekly.yml
index c1e2d542cdc..aab69e960d0 100644
--- a/config/metrics/counts_7d/20210216181437_g_project_management_issue_time_estimate_changed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181437_g_project_management_issue_time_estimate_changed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_time_estimate_changed
+events:
+ - name: g_project_management_issue_time_estimate_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181440_g_project_management_issue_time_spent_changed_weekly.yml b/config/metrics/counts_7d/20210216181440_g_project_management_issue_time_spent_changed_weekly.yml
index 48f4175f084..7cb085d24b4 100644
--- a/config/metrics/counts_7d/20210216181440_g_project_management_issue_time_spent_changed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181440_g_project_management_issue_time_spent_changed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_time_spent_changed
+events:
+ - name: g_project_management_issue_time_spent_changed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181444_g_project_management_issue_comment_added_weekly.yml b/config/metrics/counts_7d/20210216181444_g_project_management_issue_comment_added_weekly.yml
index 9303f4e69ff..fb7ac35af79 100644
--- a/config/metrics/counts_7d/20210216181444_g_project_management_issue_comment_added_weekly.yml
+++ b/config/metrics/counts_7d/20210216181444_g_project_management_issue_comment_added_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_comment_added
+events:
+ - name: g_project_management_issue_comment_added
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181448_g_project_management_issue_comment_edited_weekly.yml b/config/metrics/counts_7d/20210216181448_g_project_management_issue_comment_edited_weekly.yml
index 4bba82b80f6..7e18898086e 100644
--- a/config/metrics/counts_7d/20210216181448_g_project_management_issue_comment_edited_weekly.yml
+++ b/config/metrics/counts_7d/20210216181448_g_project_management_issue_comment_edited_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_comment_edited
+events:
+ - name: g_project_management_issue_comment_edited
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181451_g_project_management_issue_comment_removed_weekly.yml b/config/metrics/counts_7d/20210216181451_g_project_management_issue_comment_removed_weekly.yml
index 6bbfe60613e..6fb3f52f47e 100644
--- a/config/metrics/counts_7d/20210216181451_g_project_management_issue_comment_removed_weekly.yml
+++ b/config/metrics/counts_7d/20210216181451_g_project_management_issue_comment_removed_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_comment_removed
+events:
+ - name: g_project_management_issue_comment_removed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216181459_g_project_management_issue_cloned_weekly.yml b/config/metrics/counts_7d/20210216181459_g_project_management_issue_cloned_weekly.yml
index 66b1fc7fb46..545d66aec4f 100644
--- a/config/metrics/counts_7d/20210216181459_g_project_management_issue_cloned_weekly.yml
+++ b/config/metrics/counts_7d/20210216181459_g_project_management_issue_cloned_weekly.yml
@@ -8,11 +8,14 @@ product_group: project_management
value_type: number
status: active
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- g_project_management_issue_cloned
+events:
+ - name: g_project_management_issue_cloned
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216183213_product_analytics_test_metrics_union.yml b/config/metrics/counts_7d/20210216183213_product_analytics_test_metrics_union.yml
index 83ee5609107..f2d4909df3a 100644
--- a/config/metrics/counts_7d/20210216183213_product_analytics_test_metrics_union.yml
+++ b/config/metrics/counts_7d/20210216183213_product_analytics_test_metrics_union.yml
@@ -19,3 +19,4 @@ tier:
- free
- premium
- ultimate
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216183215_product_analytics_test_metrics_intersection.yml b/config/metrics/counts_7d/20210216183215_product_analytics_test_metrics_intersection.yml
index ed1944b4fc0..e8beab832d5 100644
--- a/config/metrics/counts_7d/20210216183215_product_analytics_test_metrics_intersection.yml
+++ b/config/metrics/counts_7d/20210216183215_product_analytics_test_metrics_intersection.yml
@@ -19,3 +19,4 @@ tier:
- free
- premium
- ultimate
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml b/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml
index fd639ed7840..d97e445d076 100644
--- a/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml
+++ b/config/metrics/counts_7d/20210216184301_o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: redis_hll_counters.pipeline_authoring.o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly
description: Weekly unique user count doing commits which contains the CI config file
product_section: ops
@@ -13,6 +13,8 @@ instrumentation_class: RedisHLLMetric
options:
events:
- o_pipeline_authoring_unique_users_committing_ciconfigfile
+performance_indicator_type:
+- customer_health_score
distribution:
- ee
- ce
diff --git a/config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml
index e8670a1fe1e..4f84f5b26b5 100644
--- a/config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml
@@ -8,7 +8,7 @@ product_section: 'TBD'
value_type: number
status: removed
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113422
-milestone_removed: 15.10
+milestone_removed: "15.10"
time_frame: 7d
data_source: redis_hll
instrumentation_class: AggregatedMetric
diff --git a/config/metrics/counts_7d/20210216184500_p_ci_templates_implicit_auto_devops_build_weekly.yml b/config/metrics/counts_7d/20210216184500_p_ci_templates_implicit_auto_devops_build_weekly.yml
index f4e33e53c61..3487a2306a2 100644
--- a/config/metrics/counts_7d/20210216184500_p_ci_templates_implicit_auto_devops_build_weekly.yml
+++ b/config/metrics/counts_7d/20210216184500_p_ci_templates_implicit_auto_devops_build_weekly.yml
@@ -23,3 +23,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216184504_p_ci_templates_implicit_auto_devops_deploy_weekly.yml b/config/metrics/counts_7d/20210216184504_p_ci_templates_implicit_auto_devops_deploy_weekly.yml
index 25609e951fb..07868d1be43 100644
--- a/config/metrics/counts_7d/20210216184504_p_ci_templates_implicit_auto_devops_deploy_weekly.yml
+++ b/config/metrics/counts_7d/20210216184504_p_ci_templates_implicit_auto_devops_deploy_weekly.yml
@@ -23,3 +23,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216184515_p_ci_templates_5_min_production_app_weekly.yml b/config/metrics/counts_7d/20210216184515_p_ci_templates_5_min_production_app_weekly.yml
index adf67977f9c..7be982f8ef2 100644
--- a/config/metrics/counts_7d/20210216184515_p_ci_templates_5_min_production_app_weekly.yml
+++ b/config/metrics/counts_7d/20210216184515_p_ci_templates_5_min_production_app_weekly.yml
@@ -4,7 +4,7 @@ key_path: redis_hll_counters.ci_templates.p_ci_templates_5_min_production_app_we
description: Number of projects using 5 min production app CI template in last 7 days.
product_section: seg
product_stage: deploy
-product_group: 5-min-app
+product_group: five_min_app
value_type: number
status: removed
milestone_removed: '14.6'
@@ -22,3 +22,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216184524_p_ci_templates_aws_cf_deploy_ec2_weekly.yml b/config/metrics/counts_7d/20210216184524_p_ci_templates_aws_cf_deploy_ec2_weekly.yml
index 7b2ebf820b1..d5da98fd021 100644
--- a/config/metrics/counts_7d/20210216184524_p_ci_templates_aws_cf_deploy_ec2_weekly.yml
+++ b/config/metrics/counts_7d/20210216184524_p_ci_templates_aws_cf_deploy_ec2_weekly.yml
@@ -23,3 +23,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216184536_p_ci_templates_auto_devops_deploy_weekly.yml b/config/metrics/counts_7d/20210216184536_p_ci_templates_auto_devops_deploy_weekly.yml
index 0ebcc00379b..855c1365589 100644
--- a/config/metrics/counts_7d/20210216184536_p_ci_templates_auto_devops_deploy_weekly.yml
+++ b/config/metrics/counts_7d/20210216184536_p_ci_templates_auto_devops_deploy_weekly.yml
@@ -24,3 +24,4 @@ tier:
- premium
- ultimate
performance_indicator_type: []
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216184540_p_ci_templates_auto_devops_deploy_latest_weekly.yml b/config/metrics/counts_7d/20210216184540_p_ci_templates_auto_devops_deploy_latest_weekly.yml
index 34ef4ef374c..3c3d297639c 100644
--- a/config/metrics/counts_7d/20210216184540_p_ci_templates_auto_devops_deploy_latest_weekly.yml
+++ b/config/metrics/counts_7d/20210216184540_p_ci_templates_auto_devops_deploy_latest_weekly.yml
@@ -23,3 +23,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
index 3e1becde7d7..3925f242efc 100755
--- a/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
@@ -30,6 +30,7 @@ options:
- p_ci_templates_rust
- p_ci_templates_elixir
- p_ci_templates_clojure
+ - p_ci_templates_cosign
- p_ci_templates_crystal
- p_ci_templates_getting_started
- p_ci_templates_code_quality
@@ -190,3 +191,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210216184805_i_package_composer_deploy_token_weekly.yml b/config/metrics/counts_7d/20210216184805_i_package_composer_deploy_token_weekly.yml
index e5d08397792..97965f8f7a0 100644
--- a/config/metrics/counts_7d/20210216184805_i_package_composer_deploy_token_weekly.yml
+++ b/config/metrics/counts_7d/20210216184805_i_package_composer_deploy_token_weekly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216184812_i_package_container_deploy_token_weekly.yml b/config/metrics/counts_7d/20210216184812_i_package_container_deploy_token_weekly.yml
index 57b851d7240..dbe77d0e88a 100644
--- a/config/metrics/counts_7d/20210216184812_i_package_container_deploy_token_weekly.yml
+++ b/config/metrics/counts_7d/20210216184812_i_package_container_deploy_token_weekly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216184816_i_package_debian_deploy_token_weekly.yml b/config/metrics/counts_7d/20210216184816_i_package_debian_deploy_token_weekly.yml
index 6a5f5010b3d..513371a05b4 100644
--- a/config/metrics/counts_7d/20210216184816_i_package_debian_deploy_token_weekly.yml
+++ b/config/metrics/counts_7d/20210216184816_i_package_debian_deploy_token_weekly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216184824_i_package_golang_deploy_token_weekly.yml b/config/metrics/counts_7d/20210216184824_i_package_golang_deploy_token_weekly.yml
index 4b9d7df0c7c..cfe9bf13702 100644
--- a/config/metrics/counts_7d/20210216184824_i_package_golang_deploy_token_weekly.yml
+++ b/config/metrics/counts_7d/20210216184824_i_package_golang_deploy_token_weekly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216184844_i_package_tag_deploy_token_weekly.yml b/config/metrics/counts_7d/20210216184844_i_package_tag_deploy_token_weekly.yml
index 9478f660aac..10a7c219917 100644
--- a/config/metrics/counts_7d/20210216184844_i_package_tag_deploy_token_weekly.yml
+++ b/config/metrics/counts_7d/20210216184844_i_package_tag_deploy_token_weekly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216184900_i_package_container_user_weekly.yml b/config/metrics/counts_7d/20210216184900_i_package_container_user_weekly.yml
index 1ddb6cdbfa4..74957ee656f 100644
--- a/config/metrics/counts_7d/20210216184900_i_package_container_user_weekly.yml
+++ b/config/metrics/counts_7d/20210216184900_i_package_container_user_weekly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216184904_i_package_debian_user_weekly.yml b/config/metrics/counts_7d/20210216184904_i_package_debian_user_weekly.yml
index 22e130b9969..6636498e590 100644
--- a/config/metrics/counts_7d/20210216184904_i_package_debian_user_weekly.yml
+++ b/config/metrics/counts_7d/20210216184904_i_package_debian_user_weekly.yml
@@ -21,3 +21,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216184911_i_package_golang_user_weekly.yml b/config/metrics/counts_7d/20210216184911_i_package_golang_user_weekly.yml
index 32270cd0e3b..e44104ebf6c 100644
--- a/config/metrics/counts_7d/20210216184911_i_package_golang_user_weekly.yml
+++ b/config/metrics/counts_7d/20210216184911_i_package_golang_user_weekly.yml
@@ -21,3 +21,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210216184931_i_package_tag_user_weekly.yml b/config/metrics/counts_7d/20210216184931_i_package_tag_user_weekly.yml
index 6ab0f4f992e..cec805a07b4 100644
--- a/config/metrics/counts_7d/20210216184931_i_package_tag_user_weekly.yml
+++ b/config/metrics/counts_7d/20210216184931_i_package_tag_user_weekly.yml
@@ -22,3 +22,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_7d/20210423005644_i_analytics_dev_ops_adoption.yml b/config/metrics/counts_7d/20210423005644_i_analytics_dev_ops_adoption.yml
index b6e1211d605..3fa819ec1d2 100644
--- a/config/metrics/counts_7d/20210423005644_i_analytics_dev_ops_adoption.yml
+++ b/config/metrics/counts_7d/20210423005644_i_analytics_dev_ops_adoption.yml
@@ -9,11 +9,14 @@ value_type: number
status: active
milestone: "13.11"
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
instrumentation_class: RedisHLLMetric
options:
events:
- i_analytics_dev_ops_adoption
+events:
+ - name: i_analytics_dev_ops_adoption
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml b/config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml
index b7a65d38ab3..f159184503c 100644
--- a/config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml
+++ b/config/metrics/counts_7d/20210427103328_code_review_group_monthly_active_users.yml
@@ -145,3 +145,4 @@ options:
- 'i_code_review_saved_replies_create'
- 'i_code_review_saved_replies_use'
- 'i_code_review_saved_replies_use_in_mr'
+ - 'i_code_review_saved_replies_use_in_other'
diff --git a/config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml b/config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml
index c7c7e248ea0..0b93ea59c3c 100644
--- a/config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml
+++ b/config/metrics/counts_7d/20210427103407_code_review_category_monthly_active_users.yml
@@ -140,3 +140,4 @@ options:
- 'i_code_review_saved_replies_create'
- 'i_code_review_saved_replies_use'
- 'i_code_review_saved_replies_use_in_mr'
+ - 'i_code_review_saved_replies_use_in_other'
diff --git a/config/metrics/counts_7d/20210902000809_p_ci_templates_implicit_auto_devops_deploy_latest_weekly.yml b/config/metrics/counts_7d/20210902000809_p_ci_templates_implicit_auto_devops_deploy_latest_weekly.yml
index de6e5b504fe..98951919e65 100644
--- a/config/metrics/counts_7d/20210902000809_p_ci_templates_implicit_auto_devops_deploy_latest_weekly.yml
+++ b/config/metrics/counts_7d/20210902000809_p_ci_templates_implicit_auto_devops_deploy_latest_weekly.yml
@@ -23,3 +23,4 @@ tier:
options:
events:
- p_ci_templates_implicit_auto_devops_deploy_latest
+removed_by_url:
diff --git a/config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml b/config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml
index 9f08bac4531..788652bf82a 100644
--- a/config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml
+++ b/config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml
@@ -20,3 +20,4 @@ tier:
- free
- premium
- ultimate
+removed_by_url:
diff --git a/config/metrics/counts_7d/20211126084441_p_analytics_ci_cd_pipelines_weekly.yml b/config/metrics/counts_7d/20211126084441_p_analytics_ci_cd_pipelines_weekly.yml
index 24b2e2c7ca0..e86741aedb2 100644
--- a/config/metrics/counts_7d/20211126084441_p_analytics_ci_cd_pipelines_weekly.yml
+++ b/config/metrics/counts_7d/20211126084441_p_analytics_ci_cd_pipelines_weekly.yml
@@ -13,6 +13,9 @@ data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
+events:
+ - name: p_analytics_ci_cd_pipelines
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20211126090829_p_analytics_ci_cd_deployment_frequency_weekly.yml b/config/metrics/counts_7d/20211126090829_p_analytics_ci_cd_deployment_frequency_weekly.yml
index 1f7cd61e3cd..f0bbdcbda62 100644
--- a/config/metrics/counts_7d/20211126090829_p_analytics_ci_cd_deployment_frequency_weekly.yml
+++ b/config/metrics/counts_7d/20211126090829_p_analytics_ci_cd_deployment_frequency_weekly.yml
@@ -13,6 +13,9 @@ data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
+events:
+ - name: p_analytics_ci_cd_deployment_frequency
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20211126091200_p_analytics_ci_cd_lead_time_weekly.yml b/config/metrics/counts_7d/20211126091200_p_analytics_ci_cd_lead_time_weekly.yml
index 164ecf8134f..d95376e277a 100644
--- a/config/metrics/counts_7d/20211126091200_p_analytics_ci_cd_lead_time_weekly.yml
+++ b/config/metrics/counts_7d/20211126091200_p_analytics_ci_cd_lead_time_weekly.yml
@@ -13,6 +13,9 @@ data_source: redis_hll
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
+events:
+ - name: p_analytics_ci_cd_lead_time
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20230105222224_g_project_management_issue_design_comments_removed_weekly.yml b/config/metrics/counts_7d/20230105222224_g_project_management_issue_design_comments_removed_weekly.yml
index e1d899d5193..3466b0a7f50 100644
--- a/config/metrics/counts_7d/20230105222224_g_project_management_issue_design_comments_removed_weekly.yml
+++ b/config/metrics/counts_7d/20230105222224_g_project_management_issue_design_comments_removed_weekly.yml
@@ -9,13 +9,16 @@ status: active
milestone: "15.9"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108307
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
options:
events:
- g_project_management_issue_design_comments_removed
+events:
+ - name: g_project_management_issue_design_comments_removed
+ unique: user.id
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20230714160504_batched_background_migration_failed_jobs_metric.yml b/config/metrics/counts_7d/20230714160504_batched_background_migration_failed_jobs_metric.yml
index fb8a0f24f7b..e5364020c4d 100644
--- a/config/metrics/counts_7d/20230714160504_batched_background_migration_failed_jobs_metric.yml
+++ b/config/metrics/counts_7d/20230714160504_batched_background_migration_failed_jobs_metric.yml
@@ -5,7 +5,7 @@ product_section: enablement
product_stage: data_stores
product_group: database
value_type: number
-status: active
+status: removed
milestone: "16.3"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126165
time_frame: 7d
@@ -20,4 +20,5 @@ tier:
- free
- premium
- ultimate
-value_json_schema: "config/metrics/objects_schemas/batched_background_migration_failed_jobs_metric.json"
+removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130760
+milestone_removed: "16.4"
diff --git a/config/metrics/counts_7d/20230724140652_i_code_review_saved_replies_create_weekly.yml b/config/metrics/counts_7d/20230724140652_i_code_review_saved_replies_create_weekly.yml
index 565b9292c01..29d097fa59e 100644
--- a/config/metrics/counts_7d/20230724140652_i_code_review_saved_replies_create_weekly.yml
+++ b/config/metrics/counts_7d/20230724140652_i_code_review_saved_replies_create_weekly.yml
@@ -9,7 +9,7 @@ status: active
milestone: "16.3"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126884
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
@@ -23,3 +23,6 @@ tier:
options:
events:
- i_code_review_saved_replies_create
+events:
+ - name: i_code_review_saved_replies_create
+ unique: user.id
diff --git a/config/metrics/counts_7d/20230725194657_i_code_review_saved_replies_use_weekly.yml b/config/metrics/counts_7d/20230725194657_i_code_review_saved_replies_use_weekly.yml
index 6b2684eec2a..162b26d7b9d 100644
--- a/config/metrics/counts_7d/20230725194657_i_code_review_saved_replies_use_weekly.yml
+++ b/config/metrics/counts_7d/20230725194657_i_code_review_saved_replies_use_weekly.yml
@@ -9,7 +9,7 @@ status: active
milestone: "16.3"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127442
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
@@ -23,3 +23,6 @@ tier:
options:
events:
- i_code_review_saved_replies_use
+events:
+ - name: i_code_review_saved_replies_use
+ unique: user.id
diff --git a/config/metrics/counts_7d/20230809194743_i_code_review_saved_replies_use_in_mr_weekly.yml b/config/metrics/counts_7d/20230809194743_i_code_review_saved_replies_use_in_mr_weekly.yml
index 81dc130397b..ea6af631c9f 100644
--- a/config/metrics/counts_7d/20230809194743_i_code_review_saved_replies_use_in_mr_weekly.yml
+++ b/config/metrics/counts_7d/20230809194743_i_code_review_saved_replies_use_in_mr_weekly.yml
@@ -9,7 +9,7 @@ status: active
milestone: "16.3"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128821
time_frame: 7d
-data_source: redis_hll
+data_source: internal_events
data_category: optional
instrumentation_class: RedisHLLMetric
performance_indicator_type: []
@@ -23,3 +23,6 @@ tier:
options:
events:
- i_code_review_saved_replies_use_in_mr
+events:
+ - name: i_code_review_saved_replies_use_in_mr
+ unique: user.id
diff --git a/config/metrics/counts_7d/20230810124157_count_cicd_component_usage_weekly.yml b/config/metrics/counts_7d/20230810124157_count_cicd_component_usage_weekly.yml
new file mode 100644
index 00000000000..e8c528dde67
--- /dev/null
+++ b/config/metrics/counts_7d/20230810124157_count_cicd_component_usage_weekly.yml
@@ -0,0 +1,23 @@
+---
+key_path: redis_hll_counters.pipeline_authoring.count_cicd_component_usage_weekly
+description: Weekly count of CI/CD component usage
+product_section: ops
+product_stage: verify
+product_group: pipeline_authoring
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129016
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+- ce
+tier:
+- premium
+- ultimate
+options:
+ events:
+ - cicd_component_usage
diff --git a/config/metrics/counts_7d/20230815171559_i_code_review_saved_replies_use_in_other_weekly.yml b/config/metrics/counts_7d/20230815171559_i_code_review_saved_replies_use_in_other_weekly.yml
new file mode 100644
index 00000000000..d913cbd7fc7
--- /dev/null
+++ b/config/metrics/counts_7d/20230815171559_i_code_review_saved_replies_use_in_other_weekly.yml
@@ -0,0 +1,28 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_saved_replies_use_in_other_weekly
+description: Count of unique users who used the saved replies feature over a week
+product_section: dev
+product_stage: create
+product_group: code_review
+value_type: number
+status: active
+milestone: "16.3"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128822
+time_frame: 7d
+data_source: internal_events
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - i_code_review_saved_replies_use_in_other
+events:
+ - name: i_code_review_saved_replies_use_in_other
+ unique: user.id
diff --git a/config/metrics/counts_7d/20230816085153_k8s_api_proxy_requests_unique_agents_via_pat_access_weekly.yml b/config/metrics/counts_7d/20230816085153_k8s_api_proxy_requests_unique_agents_via_pat_access_weekly.yml
new file mode 100644
index 00000000000..e5c3ef62d4d
--- /dev/null
+++ b/config/metrics/counts_7d/20230816085153_k8s_api_proxy_requests_unique_agents_via_pat_access_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_agents_via_pat_access_weekly
+description: WAU of the unique Agents using the KAS Kubernetes API proxy via Personal Access Token Access
+product_section: ops
+product_stage: deploy
+product_group: environment
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129463
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - k8s_api_proxy_requests_unique_agents_via_pat_access
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20230816085153_k8s_api_proxy_requests_unique_users_via_pat_access_weekly.yml b/config/metrics/counts_7d/20230816085153_k8s_api_proxy_requests_unique_users_via_pat_access_weekly.yml
new file mode 100644
index 00000000000..5f3d0dc8912
--- /dev/null
+++ b/config/metrics/counts_7d/20230816085153_k8s_api_proxy_requests_unique_users_via_pat_access_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.kubernetes_agent.k8s_api_proxy_requests_unique_users_via_pat_access_weekly
+description: WAU of the unique Users using the KAS Kubernetes API proxy via Personal Access Token Access
+product_section: ops
+product_stage: deploy
+product_group: environment
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129463
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - k8s_api_proxy_requests_unique_users_via_pat_access
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20230822210848_i_quickactions_checkin_reminder_weekly.yml b/config/metrics/counts_7d/20230822210848_i_quickactions_checkin_reminder_weekly.yml
new file mode 100644
index 00000000000..4c98cda8616
--- /dev/null
+++ b/config/metrics/counts_7d/20230822210848_i_quickactions_checkin_reminder_weekly.yml
@@ -0,0 +1,23 @@
+---
+key_path: redis_hll_counters.quickactions.i_quickactions_checkin_reminder_weekly
+name: quickactions_checkin_reminder_weekly
+description: Count of WAU using the `/checkin_reminder` quick action
+product_section: dev
+product_stage: plan
+product_group: team_planning
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130371
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_quickactions_checkin_reminder
+performance_indicator_type: []
+distribution:
+- ee
+tier:
+- ultimate
diff --git a/config/metrics/counts_7d/20230830153031_p_ci_templates_cosign_weekly.yml b/config/metrics/counts_7d/20230830153031_p_ci_templates_cosign_weekly.yml
new file mode 100644
index 00000000000..2de155a0406
--- /dev/null
+++ b/config/metrics/counts_7d/20230830153031_p_ci_templates_cosign_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_cosign_weekly
+description: Count of pipelines using the Cosign CI template.
+product_section: ci
+product_stage: verify
+product_group: pipeline_security
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130339
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_cosign
diff --git a/config/metrics/counts_7d/20230905083259_batched_background_migration_count_failed_jobs_metric.yml b/config/metrics/counts_7d/20230905083259_batched_background_migration_count_failed_jobs_metric.yml
new file mode 100644
index 00000000000..633a5b17967
--- /dev/null
+++ b/config/metrics/counts_7d/20230905083259_batched_background_migration_count_failed_jobs_metric.yml
@@ -0,0 +1,23 @@
+---
+key_path: counts_weekly.batched_background_migration_count_failed_jobs_metric
+description: Count the number of failed jobs per batched background migration
+product_section: enablement
+product_stage: data_stores
+product_group: database
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130826
+time_frame: 7d
+data_source: database
+data_category: optional
+instrumentation_class: BatchedBackgroundMigrationFailedJobsMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+value_json_schema: "config/metrics/objects_schemas/batched_background_migration_failed_jobs_metric.json"
diff --git a/config/metrics/counts_all/20210216175019_projects_with_prometheus_alerts.yml b/config/metrics/counts_all/20210216175019_projects_with_prometheus_alerts.yml
index 8b0fb9db517..c22277c98aa 100644
--- a/config/metrics/counts_all/20210216175019_projects_with_prometheus_alerts.yml
+++ b/config/metrics/counts_all/20210216175019_projects_with_prometheus_alerts.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175021_pod_logs_usages_total.yml b/config/metrics/counts_all/20210216175021_pod_logs_usages_total.yml
index 676308f9fc4..81157c0e40b 100644
--- a/config/metrics/counts_all/20210216175021_pod_logs_usages_total.yml
+++ b/config/metrics/counts_all/20210216175021_pod_logs_usages_total.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175045_merge_requests.yml b/config/metrics/counts_all/20210216175045_merge_requests.yml
index 0b10593be23..16f70b8851b 100644
--- a/config/metrics/counts_all/20210216175045_merge_requests.yml
+++ b/config/metrics/counts_all/20210216175045_merge_requests.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175053_suggestions.yml b/config/metrics/counts_all/20210216175053_suggestions.yml
index f42c47d9142..34b3ddb8976 100644
--- a/config/metrics/counts_all/20210216175053_suggestions.yml
+++ b/config/metrics/counts_all/20210216175053_suggestions.yml
@@ -18,3 +18,4 @@ tier:
- ultimate
milestone: "<13.9"
milestone_removed: '14.7'
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175255_clusters_applications_helm.yml b/config/metrics/counts_all/20210216175255_clusters_applications_helm.yml
index 075cddb387e..16c1f26bf8e 100644
--- a/config/metrics/counts_all/20210216175255_clusters_applications_helm.yml
+++ b/config/metrics/counts_all/20210216175255_clusters_applications_helm.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175257_clusters_applications_ingress.yml b/config/metrics/counts_all/20210216175257_clusters_applications_ingress.yml
index cb308890bd4..885de6e75a0 100644
--- a/config/metrics/counts_all/20210216175257_clusters_applications_ingress.yml
+++ b/config/metrics/counts_all/20210216175257_clusters_applications_ingress.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175259_clusters_applications_cert_managers.yml b/config/metrics/counts_all/20210216175259_clusters_applications_cert_managers.yml
index cad1d25e732..9ff2585d09d 100644
--- a/config/metrics/counts_all/20210216175259_clusters_applications_cert_managers.yml
+++ b/config/metrics/counts_all/20210216175259_clusters_applications_cert_managers.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175301_clusters_applications_crossplane.yml b/config/metrics/counts_all/20210216175301_clusters_applications_crossplane.yml
index e7ab1a3f950..63d06eb1af8 100644
--- a/config/metrics/counts_all/20210216175301_clusters_applications_crossplane.yml
+++ b/config/metrics/counts_all/20210216175301_clusters_applications_crossplane.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175303_clusters_applications_prometheus.yml b/config/metrics/counts_all/20210216175303_clusters_applications_prometheus.yml
index 033d912d880..29df1ab8ff3 100644
--- a/config/metrics/counts_all/20210216175303_clusters_applications_prometheus.yml
+++ b/config/metrics/counts_all/20210216175303_clusters_applications_prometheus.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175305_clusters_applications_runner.yml b/config/metrics/counts_all/20210216175305_clusters_applications_runner.yml
index a460b40ed81..02ddd07636f 100644
--- a/config/metrics/counts_all/20210216175305_clusters_applications_runner.yml
+++ b/config/metrics/counts_all/20210216175305_clusters_applications_runner.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175307_clusters_applications_knative.yml b/config/metrics/counts_all/20210216175307_clusters_applications_knative.yml
index bc142676e6a..ee95e2812dc 100644
--- a/config/metrics/counts_all/20210216175307_clusters_applications_knative.yml
+++ b/config/metrics/counts_all/20210216175307_clusters_applications_knative.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175309_clusters_applications_elastic_stack.yml b/config/metrics/counts_all/20210216175309_clusters_applications_elastic_stack.yml
index 54c96b5bea7..20afc0b4acf 100644
--- a/config/metrics/counts_all/20210216175309_clusters_applications_elastic_stack.yml
+++ b/config/metrics/counts_all/20210216175309_clusters_applications_elastic_stack.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175310_clusters_applications_jupyter.yml b/config/metrics/counts_all/20210216175310_clusters_applications_jupyter.yml
index b7d202d4c33..101167e45d3 100644
--- a/config/metrics/counts_all/20210216175310_clusters_applications_jupyter.yml
+++ b/config/metrics/counts_all/20210216175310_clusters_applications_jupyter.yml
@@ -20,3 +20,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175312_clusters_applications_cilium.yml b/config/metrics/counts_all/20210216175312_clusters_applications_cilium.yml
index 3126519fb36..0deff066abb 100644
--- a/config/metrics/counts_all/20210216175312_clusters_applications_cilium.yml
+++ b/config/metrics/counts_all/20210216175312_clusters_applications_cilium.yml
@@ -21,3 +21,4 @@ performance_indicator_type:
- customer_health_score
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175318_kubernetes_agents_with_token.yml b/config/metrics/counts_all/20210216175318_kubernetes_agents_with_token.yml
index 48564ce63a1..978f8984f2e 100644
--- a/config/metrics/counts_all/20210216175318_kubernetes_agents_with_token.yml
+++ b/config/metrics/counts_all/20210216175318_kubernetes_agents_with_token.yml
@@ -17,6 +17,5 @@ tier:
- free
- premium
- ultimate
-performance_indicator_type:
-- smau
+performance_indicator_type: []
milestone: "<13.9"
diff --git a/config/metrics/counts_all/20210216175329_clusters_applications_cert_managers.yml b/config/metrics/counts_all/20210216175329_clusters_applications_cert_managers.yml
index 82bfacffaf3..90347bb8207 100644
--- a/config/metrics/counts_all/20210216175329_clusters_applications_cert_managers.yml
+++ b/config/metrics/counts_all/20210216175329_clusters_applications_cert_managers.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175331_clusters_applications_helm.yml b/config/metrics/counts_all/20210216175331_clusters_applications_helm.yml
index 52c023961f9..2a1f18295df 100644
--- a/config/metrics/counts_all/20210216175331_clusters_applications_helm.yml
+++ b/config/metrics/counts_all/20210216175331_clusters_applications_helm.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175333_clusters_applications_ingress.yml b/config/metrics/counts_all/20210216175333_clusters_applications_ingress.yml
index 8d9897318a4..fb3707aed9a 100644
--- a/config/metrics/counts_all/20210216175333_clusters_applications_ingress.yml
+++ b/config/metrics/counts_all/20210216175333_clusters_applications_ingress.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175335_clusters_applications_knative.yml b/config/metrics/counts_all/20210216175335_clusters_applications_knative.yml
index 1cab6eeee45..4c6f0ce629c 100644
--- a/config/metrics/counts_all/20210216175335_clusters_applications_knative.yml
+++ b/config/metrics/counts_all/20210216175335_clusters_applications_knative.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175403_projects_with_prometheus_alerts.yml b/config/metrics/counts_all/20210216175403_projects_with_prometheus_alerts.yml
index 4192eb5c3f8..9b66261f91c 100644
--- a/config/metrics/counts_all/20210216175403_projects_with_prometheus_alerts.yml
+++ b/config/metrics/counts_all/20210216175403_projects_with_prometheus_alerts.yml
@@ -19,3 +19,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml b/config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml
index 6e39dfdcfc9..603de7f0a08 100644
--- a/config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml
+++ b/config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml
@@ -8,7 +8,7 @@ product_stage: protect_stage_was_removed
product_group: container_security_group_was_removed
value_type: number
status: removed
-milestone_removed: 14.0
+milestone_removed: "14.0"
time_frame: all
data_source: database
distribution:
@@ -20,3 +20,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml b/config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml
index 23485e5d7d2..5b4594093ca 100644
--- a/config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml
+++ b/config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml
@@ -8,7 +8,7 @@ product_stage: protect_stage_was_removed
product_group: container_security_group_was_removed
value_type: number
status: removed
-milestone_removed: 14.0
+milestone_removed: "14.0"
time_frame: all
data_source: database
distribution:
@@ -20,3 +20,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175446_network_policy_forwards.yml b/config/metrics/counts_all/20210216175446_network_policy_forwards.yml
index d0fa2c434d2..78eedfb785a 100644
--- a/config/metrics/counts_all/20210216175446_network_policy_forwards.yml
+++ b/config/metrics/counts_all/20210216175446_network_policy_forwards.yml
@@ -9,7 +9,7 @@ product_group: container_security_group_was_removed
value_type: number
status: removed
removed_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86351
-milestone_removed: 15.0
+milestone_removed: "15.0"
time_frame: all
data_source: redis
distribution:
diff --git a/config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml b/config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml
index 3b28b7e3c93..106543cc586 100644
--- a/config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml
+++ b/config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml
@@ -7,7 +7,7 @@ product_stage: protect_stage_was_removed
product_group: container_security_group_was_removed
value_type: number
status: removed
-milestone_removed: 14.0
+milestone_removed: "14.0"
time_frame: all
data_source: database
distribution:
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml b/config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml
index 5bc509d3b12..92562f636a2 100644
--- a/config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml
+++ b/config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml
@@ -7,7 +7,7 @@ product_stage: protect_stage_was_removed
product_group: container_security_group_was_removed
value_type: number
status: removed
-milestone_removed: 14.0
+milestone_removed: "14.0"
time_frame: all
data_source: database
distribution:
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml b/config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml
index a440204f0aa..1aac4f05df8 100644
--- a/config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml
+++ b/config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml
@@ -7,7 +7,7 @@ product_stage: protect_stage_was_removed
product_group: container_security_group_was_removed
value_type: number
status: removed
-milestone_removed: 14.0
+milestone_removed: "14.0"
time_frame: all
data_source: database
distribution:
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml b/config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml
index 27ed192f1cc..df267d8c965 100644
--- a/config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml
+++ b/config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml
@@ -7,7 +7,7 @@ product_stage: protect_stage_was_removed
product_group: container_security_group_was_removed
value_type: number
status: removed
-milestone_removed: 14.0
+milestone_removed: "14.0"
time_frame: all
data_source: database
distribution:
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175518_ci_pipeline_config_repository.yml b/config/metrics/counts_all/20210216175518_ci_pipeline_config_repository.yml
index 4f78883ef1e..1db7c0b912a 100644
--- a/config/metrics/counts_all/20210216175518_ci_pipeline_config_repository.yml
+++ b/config/metrics/counts_all/20210216175518_ci_pipeline_config_repository.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.ci_pipeline_config_repository
description: Total Pipelines from CI files in repository
product_section: ops
@@ -16,5 +16,6 @@ tier:
- free
- premium
- ultimate
-performance_indicator_type: []
+performance_indicator_type:
+- customer_health_score
milestone: "<13.9"
diff --git a/config/metrics/counts_all/20210216175523_ci_pipeline_schedules.yml b/config/metrics/counts_all/20210216175523_ci_pipeline_schedules.yml
index 3f736cf96d6..fa69683490d 100644
--- a/config/metrics/counts_all/20210216175523_ci_pipeline_schedules.yml
+++ b/config/metrics/counts_all/20210216175523_ci_pipeline_schedules.yml
@@ -16,5 +16,6 @@ tier:
- free
- premium
- ultimate
-performance_indicator_type: []
+performance_indicator_type:
+- customer_health_score
milestone: "<13.9"
diff --git a/config/metrics/counts_all/20210216175533_ci_pipeline_config_repository.yml b/config/metrics/counts_all/20210216175533_ci_pipeline_config_repository.yml
index ebb0e3584c3..d49b5625b4b 100644
--- a/config/metrics/counts_all/20210216175533_ci_pipeline_config_repository.yml
+++ b/config/metrics/counts_all/20210216175533_ci_pipeline_config_repository.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage.verify.ci_pipeline_config_repository
description: Total count of unique users creating pipelines from CI files in the repository
product_section: ops
@@ -9,6 +9,8 @@ value_type: number
status: active
time_frame: all
data_source: database
+performance_indicator_type:
+- customer_health_score
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210216175535_ci_pipeline_schedules.yml b/config/metrics/counts_all/20210216175535_ci_pipeline_schedules.yml
index 7b78b52d913..65799428e7e 100644
--- a/config/metrics/counts_all/20210216175535_ci_pipeline_schedules.yml
+++ b/config/metrics/counts_all/20210216175535_ci_pipeline_schedules.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage.verify.ci_pipeline_schedules
description: Distinct users creating pipeline schedules
product_section: ops
@@ -9,6 +9,8 @@ value_type: number
status: active
time_frame: all
data_source: database
+performance_indicator_type:
+- customer_health_score
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210216175627_templates_asana_active.yml b/config/metrics/counts_all/20210216175627_templates_asana_active.yml
index 78fcd3d5a17..1011147e4a7 100644
--- a/config/metrics/counts_all/20210216175627_templates_asana_active.yml
+++ b/config/metrics/counts_all/20210216175627_templates_asana_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175638_templates_assembla_active.yml b/config/metrics/counts_all/20210216175638_templates_assembla_active.yml
index 04dde10ae73..d874954dc57 100644
--- a/config/metrics/counts_all/20210216175638_templates_assembla_active.yml
+++ b/config/metrics/counts_all/20210216175638_templates_assembla_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175649_templates_bamboo_active.yml b/config/metrics/counts_all/20210216175649_templates_bamboo_active.yml
index 30e1af14ed4..c732830f584 100644
--- a/config/metrics/counts_all/20210216175649_templates_bamboo_active.yml
+++ b/config/metrics/counts_all/20210216175649_templates_bamboo_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml b/config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml
index a520b0b0eff..dbf797cca73 100644
--- a/config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml
+++ b/config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175712_templates_buildkite_active.yml b/config/metrics/counts_all/20210216175712_templates_buildkite_active.yml
index f8a8d5e7c8d..b9681581c80 100644
--- a/config/metrics/counts_all/20210216175712_templates_buildkite_active.yml
+++ b/config/metrics/counts_all/20210216175712_templates_buildkite_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175723_templates_campfire_active.yml b/config/metrics/counts_all/20210216175723_templates_campfire_active.yml
index 561e1ed76cd..755bbea11b5 100644
--- a/config/metrics/counts_all/20210216175723_templates_campfire_active.yml
+++ b/config/metrics/counts_all/20210216175723_templates_campfire_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175734_templates_confluence_active.yml b/config/metrics/counts_all/20210216175734_templates_confluence_active.yml
index a0be5b61109..d5564464e7a 100644
--- a/config/metrics/counts_all/20210216175734_templates_confluence_active.yml
+++ b/config/metrics/counts_all/20210216175734_templates_confluence_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml b/config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml
index 2216d415bf2..66a5a94d99d 100644
--- a/config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml
+++ b/config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175756_templates_discord_active.yml b/config/metrics/counts_all/20210216175756_templates_discord_active.yml
index 156185b3ae7..25049d1497a 100644
--- a/config/metrics/counts_all/20210216175756_templates_discord_active.yml
+++ b/config/metrics/counts_all/20210216175756_templates_discord_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml b/config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml
index 8d400caff33..b8b9ab1aa08 100644
--- a/config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml
+++ b/config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml b/config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml
index b99cff392ad..81a9ba24425 100644
--- a/config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml
+++ b/config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml b/config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml
index a531b187420..0e6cd4a4169 100644
--- a/config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml
+++ b/config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175840_templates_flowdock_active.yml b/config/metrics/counts_all/20210216175840_templates_flowdock_active.yml
index 68d3ed10346..01df00739d4 100644
--- a/config/metrics/counts_all/20210216175840_templates_flowdock_active.yml
+++ b/config/metrics/counts_all/20210216175840_templates_flowdock_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml b/config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml
index 5d92d0b81b6..b6fbd660657 100644
--- a/config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml
+++ b/config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175910_projects_hipchat_active.yml b/config/metrics/counts_all/20210216175910_projects_hipchat_active.yml
index 737e9696f14..dbe69e2f99c 100644
--- a/config/metrics/counts_all/20210216175910_projects_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175910_projects_hipchat_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175912_groups_hipchat_active.yml b/config/metrics/counts_all/20210216175912_groups_hipchat_active.yml
index ac3d2ebe91a..e65499a9402 100644
--- a/config/metrics/counts_all/20210216175912_groups_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175912_groups_hipchat_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175913_templates_hipchat_active.yml b/config/metrics/counts_all/20210216175913_templates_hipchat_active.yml
index 2be621c6d35..9349ea24ecf 100644
--- a/config/metrics/counts_all/20210216175913_templates_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175913_templates_hipchat_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175915_instances_hipchat_active.yml b/config/metrics/counts_all/20210216175915_instances_hipchat_active.yml
index 591fd17e33e..c160b7a45d8 100644
--- a/config/metrics/counts_all/20210216175915_instances_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175915_instances_hipchat_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml b/config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml
index ca710cb7edc..8baaa6c1b77 100644
--- a/config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml b/config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml
index e0da8100b3a..08741934c75 100644
--- a/config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175924_templates_irker_active.yml b/config/metrics/counts_all/20210216175924_templates_irker_active.yml
index d88a90223eb..16a730af3fe 100644
--- a/config/metrics/counts_all/20210216175924_templates_irker_active.yml
+++ b/config/metrics/counts_all/20210216175924_templates_irker_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175935_templates_jenkins_active.yml b/config/metrics/counts_all/20210216175935_templates_jenkins_active.yml
index bf8d582550c..8dd6b51e36e 100644
--- a/config/metrics/counts_all/20210216175935_templates_jenkins_active.yml
+++ b/config/metrics/counts_all/20210216175935_templates_jenkins_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175946_templates_jira_active.yml b/config/metrics/counts_all/20210216175946_templates_jira_active.yml
index 3f5a28774a0..ecfc4963f98 100644
--- a/config/metrics/counts_all/20210216175946_templates_jira_active.yml
+++ b/config/metrics/counts_all/20210216175946_templates_jira_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216175957_templates_mattermost_active.yml b/config/metrics/counts_all/20210216175957_templates_mattermost_active.yml
index 2c568ebcbac..743e03f21a5 100644
--- a/config/metrics/counts_all/20210216175957_templates_mattermost_active.yml
+++ b/config/metrics/counts_all/20210216175957_templates_mattermost_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml b/config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml
index 3691f524c22..2d5277cdbc4 100644
--- a/config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml b/config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml
index 78ee7a08864..1dcb7c25598 100644
--- a/config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml
+++ b/config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180030_templates_packagist_active.yml b/config/metrics/counts_all/20210216180030_templates_packagist_active.yml
index a498548b841..a6419bd2c6b 100644
--- a/config/metrics/counts_all/20210216180030_templates_packagist_active.yml
+++ b/config/metrics/counts_all/20210216180030_templates_packagist_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml b/config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml
index 14335a4a6c6..ececb5c7003 100644
--- a/config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml
+++ b/config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml b/config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml
index 0f33662ab50..d78e1fd6694 100644
--- a/config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml
+++ b/config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180104_templates_pushover_active.yml b/config/metrics/counts_all/20210216180104_templates_pushover_active.yml
index 10fd599f612..a864846893b 100644
--- a/config/metrics/counts_all/20210216180104_templates_pushover_active.yml
+++ b/config/metrics/counts_all/20210216180104_templates_pushover_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180115_templates_redmine_active.yml b/config/metrics/counts_all/20210216180115_templates_redmine_active.yml
index 380c4a29475..0abf8da3254 100644
--- a/config/metrics/counts_all/20210216180115_templates_redmine_active.yml
+++ b/config/metrics/counts_all/20210216180115_templates_redmine_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180126_templates_slack_active.yml b/config/metrics/counts_all/20210216180126_templates_slack_active.yml
index 5b6ae8cd466..46a50bd77c5 100644
--- a/config/metrics/counts_all/20210216180126_templates_slack_active.yml
+++ b/config/metrics/counts_all/20210216180126_templates_slack_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml b/config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml
index d79ab237338..9d8fe1485ec 100644
--- a/config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180148_templates_teamcity_active.yml b/config/metrics/counts_all/20210216180148_templates_teamcity_active.yml
index d6f5fde5cb2..d41f1c2cb73 100644
--- a/config/metrics/counts_all/20210216180148_templates_teamcity_active.yml
+++ b/config/metrics/counts_all/20210216180148_templates_teamcity_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml b/config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml
index abea902b74a..237fc2df1dc 100644
--- a/config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml
+++ b/config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml b/config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml
index fb08834235e..ad7c2c42acb 100644
--- a/config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml
+++ b/config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180221_templates_youtrack_active.yml b/config/metrics/counts_all/20210216180221_templates_youtrack_active.yml
index d3dc6ecc2c5..a5a4b17a6c0 100644
--- a/config/metrics/counts_all/20210216180221_templates_youtrack_active.yml
+++ b/config/metrics/counts_all/20210216180221_templates_youtrack_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180451_incident_labeled_issues.yml b/config/metrics/counts_all/20210216180451_incident_labeled_issues.yml
index 14e7c87c780..4f988259a5a 100644
--- a/config/metrics/counts_all/20210216180451_incident_labeled_issues.yml
+++ b/config/metrics/counts_all/20210216180451_incident_labeled_issues.yml
@@ -19,3 +19,4 @@ tier:
performance_indicator_type: []
milestone: "<13.9"
milestone_removed: "14.8"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180456_projects_with_alerts_service_enabled.yml b/config/metrics/counts_all/20210216180456_projects_with_alerts_service_enabled.yml
index bfa644092b7..cc7d6db5d97 100644
--- a/config/metrics/counts_all/20210216180456_projects_with_alerts_service_enabled.yml
+++ b/config/metrics/counts_all/20210216180456_projects_with_alerts_service_enabled.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180634_gitlab.yml b/config/metrics/counts_all/20210216180634_gitlab.yml
index f7f99d39208..d0a331e5510 100644
--- a/config/metrics/counts_all/20210216180634_gitlab.yml
+++ b/config/metrics/counts_all/20210216180634_gitlab.yml
@@ -18,3 +18,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180639_gitlab.yml b/config/metrics/counts_all/20210216180639_gitlab.yml
index d8622818173..59430960626 100644
--- a/config/metrics/counts_all/20210216180639_gitlab.yml
+++ b/config/metrics/counts_all/20210216180639_gitlab.yml
@@ -22,3 +22,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180705_total.yml b/config/metrics/counts_all/20210216180705_total.yml
index beac0d6acc5..0e573f05944 100644
--- a/config/metrics/counts_all/20210216180705_total.yml
+++ b/config/metrics/counts_all/20210216180705_total.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180707_gitlab_project.yml b/config/metrics/counts_all/20210216180707_gitlab_project.yml
index b6f189f2908..f994ca94cb3 100644
--- a/config/metrics/counts_all/20210216180707_gitlab_project.yml
+++ b/config/metrics/counts_all/20210216180707_gitlab_project.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180709_gitlab.yml b/config/metrics/counts_all/20210216180709_gitlab.yml
index defb43f9de3..83d2a8a5a74 100644
--- a/config/metrics/counts_all/20210216180709_gitlab.yml
+++ b/config/metrics/counts_all/20210216180709_gitlab.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180711_github.yml b/config/metrics/counts_all/20210216180711_github.yml
index fb434d09013..4c40181f136 100644
--- a/config/metrics/counts_all/20210216180711_github.yml
+++ b/config/metrics/counts_all/20210216180711_github.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180713_bitbucket.yml b/config/metrics/counts_all/20210216180713_bitbucket.yml
index c6132dd7bc3..3fde5dcc250 100644
--- a/config/metrics/counts_all/20210216180713_bitbucket.yml
+++ b/config/metrics/counts_all/20210216180713_bitbucket.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180715_bitbucket_server.yml b/config/metrics/counts_all/20210216180715_bitbucket_server.yml
index 3fff679d5c6..20b7ea74be8 100644
--- a/config/metrics/counts_all/20210216180715_bitbucket_server.yml
+++ b/config/metrics/counts_all/20210216180715_bitbucket_server.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180716_gitea.yml b/config/metrics/counts_all/20210216180716_gitea.yml
index 7d727ceab3e..1e6c6924cab 100644
--- a/config/metrics/counts_all/20210216180716_gitea.yml
+++ b/config/metrics/counts_all/20210216180716_gitea.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180718_git.yml b/config/metrics/counts_all/20210216180718_git.yml
index fccc694ba81..714264c78ac 100644
--- a/config/metrics/counts_all/20210216180718_git.yml
+++ b/config/metrics/counts_all/20210216180718_git.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180720_manifest.yml b/config/metrics/counts_all/20210216180720_manifest.yml
index 2347510d8d1..c5486138cc6 100644
--- a/config/metrics/counts_all/20210216180720_manifest.yml
+++ b/config/metrics/counts_all/20210216180720_manifest.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180722_jira.yml b/config/metrics/counts_all/20210216180722_jira.yml
index a8b10bea3ca..1bb5bff89c1 100644
--- a/config/metrics/counts_all/20210216180722_jira.yml
+++ b/config/metrics/counts_all/20210216180722_jira.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180724_fogbugz.yml b/config/metrics/counts_all/20210216180724_fogbugz.yml
index 9914a143603..3095c40a8f8 100644
--- a/config/metrics/counts_all/20210216180724_fogbugz.yml
+++ b/config/metrics/counts_all/20210216180724_fogbugz.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180726_phabricator.yml b/config/metrics/counts_all/20210216180726_phabricator.yml
index 76ac173e021..166ae62dfb6 100644
--- a/config/metrics/counts_all/20210216180726_phabricator.yml
+++ b/config/metrics/counts_all/20210216180726_phabricator.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180727_csv.yml b/config/metrics/counts_all/20210216180727_csv.yml
index 9341f5cbb0d..f1279933c39 100644
--- a/config/metrics/counts_all/20210216180727_csv.yml
+++ b/config/metrics/counts_all/20210216180727_csv.yml
@@ -18,3 +18,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180729_groups_imported.yml b/config/metrics/counts_all/20210216180729_groups_imported.yml
index 6d52117d7f0..94cb0e1d46d 100644
--- a/config/metrics/counts_all/20210216180729_groups_imported.yml
+++ b/config/metrics/counts_all/20210216180729_groups_imported.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216180750_groups.yml b/config/metrics/counts_all/20210216180750_groups.yml
index 904aa534ed6..329af5bf53c 100644
--- a/config/metrics/counts_all/20210216180750_groups.yml
+++ b/config/metrics/counts_all/20210216180750_groups.yml
@@ -16,5 +16,6 @@ tier:
- free
- premium
- ultimate
-performance_indicator_type: []
+performance_indicator_type:
+- customer_health_score
milestone: "<13.9"
diff --git a/config/metrics/counts_all/20210216180934_templates_prometheus_active.yml b/config/metrics/counts_all/20210216180934_templates_prometheus_active.yml
index b8836be2107..ba06004d6ec 100644
--- a/config/metrics/counts_all/20210216180934_templates_prometheus_active.yml
+++ b/config/metrics/counts_all/20210216180934_templates_prometheus_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216180947_clusters_applications_prometheus.yml b/config/metrics/counts_all/20210216180947_clusters_applications_prometheus.yml
index 76497d1a020..212f8c21133 100644
--- a/config/metrics/counts_all/20210216180947_clusters_applications_prometheus.yml
+++ b/config/metrics/counts_all/20210216180947_clusters_applications_prometheus.yml
@@ -18,3 +18,4 @@ tier:
- ultimate
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216181949_clusters_applications_runner.yml b/config/metrics/counts_all/20210216181949_clusters_applications_runner.yml
index 8e5acdf5ce3..9baa428c72d 100644
--- a/config/metrics/counts_all/20210216181949_clusters_applications_runner.yml
+++ b/config/metrics/counts_all/20210216181949_clusters_applications_runner.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
milestone: "<13.9"
milestone_removed: "14.4"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182551_templates_datadog_active.yml b/config/metrics/counts_all/20210216182551_templates_datadog_active.yml
index 965a797a426..f45b4a93270 100644
--- a/config/metrics/counts_all/20210216182551_templates_datadog_active.yml
+++ b/config/metrics/counts_all/20210216182551_templates_datadog_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182618_templates_ewm_active.yml b/config/metrics/counts_all/20210216182618_templates_ewm_active.yml
index 0b4bd1d8bbd..1791805d8d8 100644
--- a/config/metrics/counts_all/20210216182618_templates_ewm_active.yml
+++ b/config/metrics/counts_all/20210216182618_templates_ewm_active.yml
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml b/config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml
index b2ca56dae60..f19e8a6526d 100644
--- a/config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml b/config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml
index d9cd14d9603..32e8801c337 100644
--- a/config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml b/config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml
index 3a9afd94991..296afe272e4 100644
--- a/config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml b/config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml
index 1067c8b781a..35d6b38a8b3 100644
--- a/config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml b/config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml
index c1498b0afd4..0b84bac064c 100644
--- a/config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml b/config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml
index f8fb07787c3..89fb814fc94 100644
--- a/config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml
index 375afffabb6..21d025e3d15 100644
--- a/config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml
index e363a531363..f77c12657ff 100644
--- a/config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml
index fdd9cedf0bf..375abe3cd5a 100644
--- a/config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml
index 2bd63d7909e..79542fd6574 100644
--- a/config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml
index f3e55e49f18..5f9a2360034 100644
--- a/config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml
index c4798be2f30..b071cc680cc 100644
--- a/config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182907_package_events_i_package_container_delete_package.yml b/config/metrics/counts_all/20210216182907_package_events_i_package_container_delete_package.yml
index 682ec3917ff..18c7bae85e2 100644
--- a/config/metrics/counts_all/20210216182907_package_events_i_package_container_delete_package.yml
+++ b/config/metrics/counts_all/20210216182907_package_events_i_package_container_delete_package.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182909_package_events_i_package_container_pull_package.yml b/config/metrics/counts_all/20210216182909_package_events_i_package_container_pull_package.yml
index 71b6eb6df2d..60f25e8cd60 100644
--- a/config/metrics/counts_all/20210216182909_package_events_i_package_container_pull_package.yml
+++ b/config/metrics/counts_all/20210216182909_package_events_i_package_container_pull_package.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182911_package_events_i_package_container_push_package.yml b/config/metrics/counts_all/20210216182911_package_events_i_package_container_push_package.yml
index a1a4a856bce..9093f5e9563 100644
--- a/config/metrics/counts_all/20210216182911_package_events_i_package_container_push_package.yml
+++ b/config/metrics/counts_all/20210216182911_package_events_i_package_container_push_package.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216182917_package_events_i_package_debian_push_package.yml b/config/metrics/counts_all/20210216182917_package_events_i_package_debian_push_package.yml
index fde9ada1a4c..e1264ca45a3 100644
--- a/config/metrics/counts_all/20210216182917_package_events_i_package_debian_push_package.yml
+++ b/config/metrics/counts_all/20210216182917_package_events_i_package_debian_push_package.yml
@@ -18,3 +18,4 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
diff --git a/config/metrics/counts_all/20210216183017_package_events_i_package_tag_delete_package.yml b/config/metrics/counts_all/20210216183017_package_events_i_package_tag_delete_package.yml
index 6ff3af56c3d..658451f5fd3 100644
--- a/config/metrics/counts_all/20210216183017_package_events_i_package_tag_delete_package.yml
+++ b/config/metrics/counts_all/20210216183017_package_events_i_package_tag_delete_package.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216183019_package_events_i_package_tag_pull_package.yml b/config/metrics/counts_all/20210216183019_package_events_i_package_tag_pull_package.yml
index f071e1763c0..f2523e33a66 100644
--- a/config/metrics/counts_all/20210216183019_package_events_i_package_tag_pull_package.yml
+++ b/config/metrics/counts_all/20210216183019_package_events_i_package_tag_pull_package.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20210216183021_package_events_i_package_tag_push_package.yml b/config/metrics/counts_all/20210216183021_package_events_i_package_tag_push_package.yml
index 2c21127d1e8..f2f7731e846 100644
--- a/config/metrics/counts_all/20210216183021_package_events_i_package_tag_push_package.yml
+++ b/config/metrics/counts_all/20210216183021_package_events_i_package_tag_push_package.yml
@@ -17,3 +17,5 @@ tier:
- premium
- ultimate
milestone: "<13.9"
+removed_by_url:
+milestone_removed: "<16.4"
diff --git a/config/metrics/counts_all/20230809084619_connected_agents.yml b/config/metrics/counts_all/20230809084619_connected_agents.yml
new file mode 100644
index 00000000000..93d75329243
--- /dev/null
+++ b/config/metrics/counts_all/20230809084619_connected_agents.yml
@@ -0,0 +1,23 @@
+---
+key_path: counts.connected_agents
+description: Count of connected cluster agents
+product_section: ops
+product_stage: deploy
+product_group: environments
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128580
+time_frame: all
+data_source: database
+data_category: optional
+instrumentation_class: CountConnectedAgentsMetric
+performance_indicator_type:
+- smau
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20230815054809_i_code_review_saved_replies_use_in_other.yml b/config/metrics/counts_all/20230815054809_i_code_review_saved_replies_use_in_other.yml
new file mode 100644
index 00000000000..0ffa90cf458
--- /dev/null
+++ b/config/metrics/counts_all/20230815054809_i_code_review_saved_replies_use_in_other.yml
@@ -0,0 +1,25 @@
+---
+key_path: counts.i_code_review_saved_replies_use_in_other
+description: Total count of times a saved reply is selected when not in an MR
+product_section: dev
+product_stage: create
+product_group: code_review
+value_type: number
+status: active
+milestone: "16.3"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128822
+time_frame: all
+data_source: redis
+data_category: optional
+instrumentation_class: RedisMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ event: use_in_other
+ prefix: i_code_review_saved_replies
diff --git a/config/metrics/counts_all/20230816085929_kubernetes_agent_k8s_api_proxy_requests_via_pat_access.yml b/config/metrics/counts_all/20230816085929_kubernetes_agent_k8s_api_proxy_requests_via_pat_access.yml
new file mode 100644
index 00000000000..8c8b2ea2620
--- /dev/null
+++ b/config/metrics/counts_all/20230816085929_kubernetes_agent_k8s_api_proxy_requests_via_pat_access.yml
@@ -0,0 +1,25 @@
+---
+key_path: counts.kubernetes_agent_k8s_api_proxy_requests_via_pat_access
+description: Count of Kubernetes API proxy requests via Personal Access Token Access
+product_section: ops
+product_stage: deploy
+product_group: environments
+value_type: number
+status: active
+milestone: "16.4"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129463
+time_frame: all
+data_source: redis
+data_category: optional
+instrumentation_class: RedisMetric
+options:
+ prefix: kubernetes_agent
+ event: k8s_api_proxy_requests_via_pat_access
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/license/20230228110448_installation_creation_date.yml b/config/metrics/license/20230228110448_installation_creation_date.yml
index 4e1ccea4ac4..220bf6e051c 100644
--- a/config/metrics/license/20230228110448_installation_creation_date.yml
+++ b/config/metrics/license/20230228110448_installation_creation_date.yml
@@ -21,3 +21,4 @@ tier:
- free
- premium
- ultimate
+milestone_removed: "<16.4"
diff --git a/config/metrics/schema.json b/config/metrics/schema.json
index ddd13a6104a..3d081a8bca7 100644
--- a/config/metrics/schema.json
+++ b/config/metrics/schema.json
@@ -63,10 +63,9 @@
},
"milestone_removed": {
"type": [
- "string",
- "null"
+ "string"
],
- "pattern": "^[0-9]+\\.[0-9]+$"
+ "pattern": "^<?[0-9]+\\.[0-9]+$"
},
"introduced_by_url": {
"type": [
@@ -208,6 +207,35 @@
"repair_issue_url"
]
}
+ },
+ {
+ "if": {
+ "properties": {
+ "data_source": {
+ "const": "internal_events"
+ }
+ }
+ },
+ "then": {
+ "required": [
+ "events"
+ ]
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "status": {
+ "const": "removed"
+ }
+ }
+ },
+ "then": {
+ "required": [
+ "removed_by_url",
+ "milestone_removed"
+ ]
+ }
}
]
}
diff --git a/config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml b/config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml
index 9f136ba3cc1..9a3efcbee97 100644
--- a/config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml
+++ b/config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml
@@ -7,7 +7,7 @@ product_stage: protect_stage_was_removed
product_group: container_security_group_was_removed
value_type: boolean
status: removed
-milestone_removed: 14.0
+milestone_removed: "14.0"
time_frame: none
data_source: system
distribution:
@@ -19,3 +19,4 @@ tier:
- ultimate
performance_indicator_type: []
milestone: "<13.9"
+removed_by_url:
diff --git a/config/object_store_settings.rb b/config/object_store_settings.rb
index 4e8e950c797..283cd952c04 100644
--- a/config/object_store_settings.rb
+++ b/config/object_store_settings.rb
@@ -2,19 +2,19 @@
# Set default values for object_store settings
class ObjectStoreSettings
- SUPPORTED_TYPES = %w(artifacts external_diffs lfs uploads packages dependency_proxy terraform_state pages).freeze
- ALLOWED_OBJECT_STORE_OVERRIDES = %w(bucket enabled proxy_download cdn).freeze
+ SUPPORTED_TYPES = %w[artifacts external_diffs lfs uploads packages dependency_proxy terraform_state pages].freeze
+ ALLOWED_OBJECT_STORE_OVERRIDES = %w[bucket enabled proxy_download cdn].freeze
# To ensure the one Workhorse credential matches the Rails config, we
# enforce consolidated settings on those accelerated
# endpoints. Technically dependency_proxy and terraform_state fall
# into this category, but they will likely be handled by Workhorse in
# the future.
- WORKHORSE_ACCELERATED_TYPES = SUPPORTED_TYPES - %w(pages)
+ WORKHORSE_ACCELERATED_TYPES = SUPPORTED_TYPES - %w[pages]
# pages may be enabled but use legacy disk storage
# we don't need to raise an error in that case
- ALLOWED_INCOMPLETE_TYPES = %w(pages).freeze
+ ALLOWED_INCOMPLETE_TYPES = %w[pages].freeze
attr_accessor :settings
diff --git a/config/redis.yml.example b/config/redis.yml.example
index f4650f4b115..9d884038af7 100644
--- a/config/redis.yml.example
+++ b/config/redis.yml.example
@@ -15,6 +15,9 @@ development:
rate_limiting:
cluster:
- redis://localhost:7001
+ queues_metadata:
+ cluster:
+ - redis://localhost:7001
test:
chat:
@@ -32,3 +35,6 @@ test:
rate_limiting:
cluster:
- redis://localhost:7001
+ queues_metadata:
+ cluster:
+ - redis://localhost:7001
diff --git a/config/resque.yml.example b/config/resque.yml.example
index 656cd57a739..600b9c67d6f 100644
--- a/config/resque.yml.example
+++ b/config/resque.yml.example
@@ -3,6 +3,11 @@
#
development:
url: redis://localhost:6379
+ # ssl_params:
+ # ca_path: "/path/to/dir/with/certs"
+ # ca_file: "/path/to/ca.crt"
+ # cert_file: "/path/to/client.crt"
+ # key_file: "/path/to/client.key"
# sentinels:
# -
# host: localhost
diff --git a/config/routes.rb b/config/routes.rb
index 7e2f1f0027a..663828670dd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -67,7 +67,6 @@ InitializerConnections.raise_if_new_database_connection do
Gitlab.ee do
resource :company, only: [:new, :create], controller: 'company'
resources :groups, only: [:new, :create]
- draw :verification
end
end
@@ -118,6 +117,12 @@ InitializerConnections.raise_if_new_database_connection do
get 'offline' => "pwa#offline"
get 'manifest' => "pwa#manifest", constraints: lambda { |req| req.format == :json }
+ scope module: 'clusters' do
+ scope module: 'agents' do
+ get '/kubernetes/:agent_id', to: 'dashboard#show', as: 'kubernetes_dashboard'
+ end
+ end
+
# '/-/health' implemented by BasicHealthCheck middleware
get 'liveness' => 'health#liveness'
get 'readiness' => 'health#readiness'
@@ -223,6 +228,8 @@ InitializerConnections.raise_if_new_database_connection do
post '/members/mailgun/permanent_failures' => 'mailgun/webhooks#process_webhook'
get '/timelogs' => 'time_tracking/timelogs#index'
+
+ post '/track_namespace_visits' => 'users/namespace_visits#create'
end
# End of the /-/ scope.
@@ -265,6 +272,7 @@ InitializerConnections.raise_if_new_database_connection do
draw :git_http
draw :api
+ draw :activity_pub
draw :customers_dot
draw :sidekiq
draw :help
diff --git a/config/routes/activity_pub.rb b/config/routes/activity_pub.rb
new file mode 100644
index 00000000000..f400d722e76
--- /dev/null
+++ b/config/routes/activity_pub.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+constraints(::Constraints::ActivityPubConstrainer.new) do
+ scope(module: 'activity_pub') do
+ constraints(::Constraints::ProjectUrlConstrainer.new) do
+ # Emulating route structure from routes/project.rb since we want to serve
+ # ActivityPub content with the proper "Accept" header to the same urls. See
+ # project routes file for rational behind this structure.
+ scope(
+ path: '*namespace_id',
+ as: :namespace,
+ namespace_id: Gitlab::PathRegex.full_namespace_route_regex
+ ) do
+ scope(
+ path: ':project_id',
+ constraints: { project_id: Gitlab::PathRegex.project_route_regex },
+ module: :projects,
+ as: :project
+ ) do
+ scope '-' do
+ resources :releases, only: :index do
+ collection do
+ get 'outbox'
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 16371fca89e..87e885e59a2 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -128,7 +128,6 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
resources :container_registries, only: [:index, :show], controller: 'registry/repositories'
resource :dependency_proxy, only: [:show, :update]
- resources :email_campaigns, only: :index
namespace :observability do
get 'explore'
@@ -161,7 +160,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
resources :achievements, only: [:index, :new, :edit]
- resources :work_items, only: [:index]
+ resources :work_items, only: [:index, :show], param: :iid
end
scope(
diff --git a/config/routes/organizations.rb b/config/routes/organizations.rb
index 4a8c9c25363..6f44eeb0d82 100644
--- a/config/routes/organizations.rb
+++ b/config/routes/organizations.rb
@@ -1,6 +1,11 @@
# frozen_string_literal: true
-resources :organizations, only: [:show], param: :organization_path, controller: 'organizations/organizations' do
+resources(
+ :organizations,
+ only: [:show, :index, :new],
+ param: :organization_path,
+ controller: 'organizations/organizations'
+) do
member do
get :groups_and_projects
end
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 250371d1257..e7242f1ecee 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -320,8 +320,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get '/terminal.ws/authorize', to: 'environments#terminal_websocket_authorize', format: false
get '/prometheus/api/v1/*proxy_path', to: 'environments/prometheus_api#prometheus_proxy', as: :prometheus_api
-
- get '/sample_metrics', to: 'environments/sample_metrics#query'
end
collection do
@@ -385,8 +383,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
- resources :tracing, only: [:index, :show], controller: :tracing
-
namespace :design_management do
namespace :designs, path: 'designs/:design_id(/:sha)', constraints: -> (params) { params[:sha].nil? || Gitlab::Git.commit_id?(params[:sha]) } do
resource :raw_image, only: :show
@@ -525,20 +521,20 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
namespace :prometheus do
- resources :alerts, constraints: { id: /\d+/ }, only: [] do # rubocop: disable Cop/PutProjectRoutesUnderScope
- post :notify, on: :collection # rubocop:todo Cop/PutProjectRoutesUnderScope
- member do
- get :metrics_dashboard # rubocop:todo Cop/PutProjectRoutesUnderScope
- end
- end
-
resources :metrics, constraints: { id: %r{[^\/]+} }, only: [:index, :new, :create, :edit, :update, :destroy] do # rubocop: disable Cop/PutProjectRoutesUnderScope
get :active_common, on: :collection # rubocop:todo Cop/PutProjectRoutesUnderScope
post :validate_query, on: :collection # rubocop:todo Cop/PutProjectRoutesUnderScope
end
end
- post 'alerts/notify', to: 'alerting/notifications#create' # rubocop:todo Cop/PutProjectRoutesUnderScope
+ scope :prometheus, as: :prometheus do
+ resources :alerts, constraints: { id: /\d+/ }, only: [] do # rubocop: disable Cop/PutProjectRoutesUnderScope
+ post :notify, on: :collection, to: 'alerting/notifications#create', defaults: { endpoint_identifier: 'legacy-prometheus' } # rubocop: disable Cop/PutProjectRoutesUnderScope
+ get :metrics_dashboard, on: :member # rubocop:todo Cop/PutProjectRoutesUnderScope
+ end
+ end
+
+ post 'alerts/notify', to: 'alerting/notifications#create', defaults: { endpoint_identifier: 'legacy' } # rubocop:todo Cop/PutProjectRoutesUnderScope
post 'alerts/notify/:name/:endpoint_identifier', # rubocop:todo Cop/PutProjectRoutesUnderScope
to: 'alerting/notifications#create',
as: :alert_http_integration,
diff --git a/config/session_store.yml.example b/config/session_store.yml.example
new file mode 100644
index 00000000000..138d21d614e
--- /dev/null
+++ b/config/session_store.yml.example
@@ -0,0 +1,3 @@
+development:
+ unique_cookie_key_postfix: true
+ cookie_key: _gitlab_session
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index d494f8618b1..d14c20426df 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -79,6 +79,16 @@
- 1
- - batched_git_ref_updates_project_cleanup
- 1
+- - bitbucket_import_advance_stage
+ - 1
+- - bitbucket_import_import_pull_request
+ - 1
+- - bitbucket_import_stage_finish_import
+ - 1
+- - bitbucket_import_stage_import_pull_requests
+ - 1
+- - bitbucket_import_stage_import_repository
+ - 1
- - bitbucket_server_import_advance_stage
- 1
- - bitbucket_server_import_import_lfs_object
@@ -107,6 +117,8 @@
- 1
- - bulk_imports_finish_batched_relation_export
- 1
+- - bulk_imports_finish_project_import
+ - 1
- - bulk_imports_pipeline
- 1
- - bulk_imports_pipeline_batch
@@ -163,6 +175,8 @@
- 1
- - compliance_management_update_default_framework
- 1
+- - compliance_management_violation_export_mailer
+ - 1
- - container_repository
- 1
- - container_repository_delete
@@ -177,6 +191,8 @@
- 1
- - cronjob
- 1
+- - database_lock_tables
+ - 1
- - default
- 1
- - delete_diff_files
@@ -271,6 +287,10 @@
- 1
- - gitlab_shell
- 2
+- - gitlab_subscriptions_add_on_purchases_cleanup_user_add_on_assignment
+ - 1
+- - gitlab_subscriptions_add_on_purchases_refresh_user_assignments
+ - 1
- - gitlab_subscriptions_refresh_seats
- 1
- - gitlab_subscriptions_trials_apply_trial
@@ -291,6 +311,8 @@
- 1
- - groups_create_event
- 1
+- - groups_enterprise_users_associate
+ - 1
- - groups_enterprise_users_disassociate
- 1
- - groups_export_memberships
@@ -357,6 +379,10 @@
- 2
- - llm_completion
- 1
+- - llm_embedding_gitlab_documentation_create_db_embeddings_per_doc_file
+ - 1
+- - llm_embedding_gitlab_documentation_set_embeddings_on_the_record
+ - 1
- - llm_tanuki_bot_update
- 1
- - mail_scheduler
@@ -413,10 +439,6 @@
- 1
- - ml_experiment_tracking_associate_ml_candidate_to_package
- 1
-- - namespaces_free_user_cap_notification_clearing
- - 1
-- - namespaces_free_user_cap_over_limit_notification
- - 1
- - namespaces_process_sync_events
- 1
- - namespaces_sync_namespace_name
@@ -459,8 +481,6 @@
- 1
- - pages_domain_verification
- 1
-- - pages_invalidate_domain_cache
- - 1
- - personal_access_tokens
- 1
- - pipeline_background
@@ -581,10 +601,14 @@
- 1
- - search_wiki_elastic_delete_group_wiki
- 1
+- - search_zoekt_default_branch_changed
+ - 1
- - search_zoekt_delete_project
- 1
- - search_zoekt_namespace_indexer
- 1
+- - search_zoekt_project_transfer
+ - 1
- - security_auto_fix
- 1
- - security_generate_policy_violation_comment
@@ -595,6 +619,10 @@
- 1
- - security_process_scan_result_policy
- 1
+- - security_refresh_project_policies
+ - 1
+- - security_scan_execution_policies_rule_schedule
+ - 1
- - security_scan_result_policies_sync_opened_merge_requests
- 1
- - security_scan_result_policies_sync_project
@@ -645,6 +673,8 @@
- 1
- - upload_checksum
- 1
+- - users_track_namespace_visits
+ - 1
- - vulnerabilities_mark_dropped_as_resolved
- 1
- - vulnerabilities_statistics_adjustment
diff --git a/config/spring.rb b/config/spring.rb
index f06a707111c..8fb1ae1669d 100644
--- a/config/spring.rb
+++ b/config/spring.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-%w(
+%w[
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
-).each { |path| Spring.watch(path) }
+].each { |path| Spring.watch(path) }
Spring.after_fork do
if ENV['DEBUGGER_STORED_RUBYLIB']
diff --git a/config/vite.json b/config/vite.json
new file mode 100644
index 00000000000..b428b0daec0
--- /dev/null
+++ b/config/vite.json
@@ -0,0 +1,18 @@
+{
+ "all": {
+ "sourceCodeDir": "app/assets",
+ "entrypointsDir": "javascripts/entrypoints",
+ "devServerConnectTimeout": 3
+ },
+ "development": {
+ "autoBuild": true,
+ "publicOutputDir": "vite-dev",
+ "host": "localhost",
+ "port": 3038
+ },
+ "test": {
+ "autoBuild": true,
+ "publicOutputDir": "vite-test",
+ "port": 3037
+ }
+}
diff --git a/config/webpack.config.js b/config/webpack.config.js
index a4d2d188227..1ee681857a6 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -18,8 +18,6 @@ const fs = require('fs');
const path = require('path');
const BABEL_VERSION = require('@babel/core/package.json').version;
-const SOURCEGRAPH_VERSION = require('@sourcegraph/code-host-integration/package.json').version;
-const GITLAB_WEB_IDE_VERSION = require('@gitlab/web-ide/package.json').version;
const BABEL_LOADER_VERSION = require('babel-loader/package.json').version;
const CompressionPlugin = require('compression-webpack-plugin');
@@ -37,14 +35,23 @@ const { StatsWriterPlugin } = require('webpack-stats-plugin');
const WEBPACK_VERSION = require('webpack/package.json').version;
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
+const {
+ IS_EE,
+ IS_JH,
+ ROOT_PATH,
+ WEBPACK_OUTPUT_PATH,
+ WEBPACK_PUBLIC_PATH,
+ SOURCEGRAPH_PUBLIC_PATH,
+ SOURCEGRAPH_OUTPUT_PATH,
+ GITLAB_WEB_IDE_OUTPUT_PATH,
+ GITLAB_WEB_IDE_PUBLIC_PATH,
+} = require('./webpack.constants');
+
const createIncrementalWebpackCompiler = require('./helpers/incremental_webpack_compiler');
-const IS_EE = require('./helpers/is_ee_env');
-const IS_JH = require('./helpers/is_jh_env');
const vendorDllHash = require('./helpers/vendor_dll_hash');
const GraphqlKnownOperationsPlugin = require('./plugins/graphql_known_operations_plugin');
-const ROOT_PATH = path.resolve(__dirname, '..');
const SUPPORTED_BROWSERS = fs.readFileSync(path.join(ROOT_PATH, '.browserslistrc'), 'utf-8');
const SUPPORTED_BROWSERS_HASH = crypto
.createHash('sha256')
@@ -82,19 +89,9 @@ if (WEBPACK_REPORT) {
NO_HASHED_CHUNKS = true;
}
-const WEBPACK_OUTPUT_PATH = path.join(ROOT_PATH, 'public/assets/webpack');
-const WEBPACK_PUBLIC_PATH = '/assets/webpack/';
const SOURCEGRAPH_PACKAGE = '@sourcegraph/code-host-integration';
const GITLAB_WEB_IDE_PACKAGE = '@gitlab/web-ide';
-const SOURCEGRAPH_PATH = path.join('sourcegraph', SOURCEGRAPH_VERSION, '/');
-const SOURCEGRAPH_OUTPUT_PATH = path.join(WEBPACK_OUTPUT_PATH, SOURCEGRAPH_PATH);
-const SOURCEGRAPH_PUBLIC_PATH = path.join(WEBPACK_PUBLIC_PATH, SOURCEGRAPH_PATH);
-
-const GITLAB_WEB_IDE_PATH = path.join('gitlab-vscode', GITLAB_WEB_IDE_VERSION, '/');
-const GITLAB_WEB_IDE_OUTPUT_PATH = path.join(WEBPACK_OUTPUT_PATH, GITLAB_WEB_IDE_PATH);
-const GITLAB_WEB_IDE_PUBLIC_PATH = path.join(WEBPACK_PUBLIC_PATH, GITLAB_WEB_IDE_PATH);
-
const devtool = IS_PRODUCTION ? 'source-map' : 'cheap-module-eval-source-map';
let autoEntriesCount = 0;
@@ -178,6 +175,7 @@ function generateEntries() {
sandboxed_swagger: './lib/swagger.js',
super_sidebar: './entrypoints/super_sidebar.js',
tracker: './entrypoints/tracker.js',
+ analytics: './entrypoints/analytics.js',
};
return Object.assign(manualEntries, incrementalCompiler.filterEntryPoints(autoEntries));
diff --git a/config/webpack.constants.js b/config/webpack.constants.js
new file mode 100644
index 00000000000..0eb2ac70c82
--- /dev/null
+++ b/config/webpack.constants.js
@@ -0,0 +1,31 @@
+const path = require('path');
+
+const ROOT_PATH = path.resolve(__dirname, '..');
+const WEBPACK_OUTPUT_PATH = path.join(ROOT_PATH, 'public/assets/webpack');
+const WEBPACK_PUBLIC_PATH = '/assets/webpack/';
+const SOURCEGRAPH_VERSION = require('@sourcegraph/code-host-integration/package.json').version;
+
+const SOURCEGRAPH_PATH = path.join('sourcegraph', SOURCEGRAPH_VERSION, '/');
+const SOURCEGRAPH_OUTPUT_PATH = path.join(WEBPACK_OUTPUT_PATH, SOURCEGRAPH_PATH);
+const SOURCEGRAPH_PUBLIC_PATH = path.join(WEBPACK_PUBLIC_PATH, SOURCEGRAPH_PATH);
+
+const GITLAB_WEB_IDE_VERSION = require('@gitlab/web-ide/package.json').version;
+
+const GITLAB_WEB_IDE_PATH = path.join('gitlab-vscode', GITLAB_WEB_IDE_VERSION, '/');
+const GITLAB_WEB_IDE_OUTPUT_PATH = path.join(WEBPACK_OUTPUT_PATH, GITLAB_WEB_IDE_PATH);
+const GITLAB_WEB_IDE_PUBLIC_PATH = path.join(WEBPACK_PUBLIC_PATH, GITLAB_WEB_IDE_PATH);
+
+const IS_EE = require('./helpers/is_ee_env');
+const IS_JH = require('./helpers/is_jh_env');
+
+module.exports = {
+ IS_EE,
+ IS_JH,
+ ROOT_PATH,
+ WEBPACK_OUTPUT_PATH,
+ WEBPACK_PUBLIC_PATH,
+ SOURCEGRAPH_OUTPUT_PATH,
+ SOURCEGRAPH_PUBLIC_PATH,
+ GITLAB_WEB_IDE_OUTPUT_PATH,
+ GITLAB_WEB_IDE_PUBLIC_PATH,
+};
diff --git a/danger/architecture/Dangerfile b/danger/architecture/Dangerfile
index 148180247fe..a8cfbab394f 100644
--- a/danger/architecture/Dangerfile
+++ b/danger/architecture/Dangerfile
@@ -7,7 +7,7 @@ return unless helper.ci?
blueprint_changes = helper.changed_files(%r{^doc/architecture/blueprints/.*})
BLUEPRINT_SHORT_MESSAGE = <<~MSG
-This merge request requires a review from an [Architecture Evolution Coach](https://about.gitlab.com/handbook/engineering/architecture/workflow/).
+This merge request might require a review from a [Coach Engineer](https://about.gitlab.com/handbook/engineering/architecture/workflow/).
MSG
BLUEPRINT_LONG_MESSAGE = <<~MSG
diff --git a/danger/clickhouse/Dangerfile b/danger/clickhouse/Dangerfile
new file mode 100644
index 00000000000..91fa45541e7
--- /dev/null
+++ b/danger/clickhouse/Dangerfile
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+CH_MESSAGE = <<~MSG
+This merge request requires a ClickHouse review. To make sure these
+changes are reviewed, take the following steps:
+
+1. Ensure the merge request has ~clickhouse and ~"clickhouse::review pending" labels.
+1. Assign and mention a ClickHouse reviewer.
+MSG
+
+CH_UNREVIEWED_LABEL = 'clickhouse::review pending'
+CH_APPROVED_LABEL = 'clickhouse::approved'
+
+CH_URL =
+ 'https://gitlab.com/groups/gitlab-org/maintainers/clickhouse/-/group_members?with_inherited_permissions=exclude'
+
+return if stable_branch.valid_stable_branch?
+return if helper.mr_labels.include?(CH_UNREVIEWED_LABEL)
+
+helper.labels_to_add << 'clickhouse' if clickhouse.changes.any?
+
+if helper.mr_labels.include?('clickhouse') || clickhouse.changes.any?
+ message 'This merge request adds or changes files that require a ' \
+ 'review from the [GitLab ClickHouse team](CH_URL).'
+
+ markdown(CH_MESSAGE)
+
+ helper.labels_to_add << CH_UNREVIEWED_LABEL unless helper.has_scoped_label_with_scope?("clickhouse")
+end
diff --git a/danger/ignored_model_columns/Dangerfile b/danger/ignored_model_columns/Dangerfile
new file mode 100644
index 00000000000..e11566f90f2
--- /dev/null
+++ b/danger/ignored_model_columns/Dangerfile
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+ignored_model_columns.add_comment_for_ignored_model_columns
diff --git a/danger/plugins/clickhouse.rb b/danger/plugins/clickhouse.rb
new file mode 100644
index 00000000000..324a0e5c1a9
--- /dev/null
+++ b/danger/plugins/clickhouse.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require_relative '../../tooling/danger/clickhouse'
+
+module Danger
+ class Clickhouse < ::Danger::Plugin
+ # Put the helper code somewhere it can be tested
+ include Tooling::Danger::Clickhouse
+ end
+end
diff --git a/danger/plugins/ignored_model_columns.rb b/danger/plugins/ignored_model_columns.rb
new file mode 100644
index 00000000000..8e0024a94d6
--- /dev/null
+++ b/danger/plugins/ignored_model_columns.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require_relative '../../tooling/danger/ignored_model_columns'
+
+module Danger
+ class IgnoredModelColumns < ::Danger::Plugin
+ include Tooling::Danger::IgnoredModelColumns
+ end
+end
diff --git a/danger/qa_selector/Dangerfile b/danger/qa_selector/Dangerfile
index 57f992ec160..c8450bffe27 100644
--- a/danger/qa_selector/Dangerfile
+++ b/danger/qa_selector/Dangerfile
@@ -2,13 +2,15 @@
return if helper.stable_branch?
-data_testids = /testid|data-testid|find_by_testid|within_testid/
+data_testids = /testid/
deprecated_qa_selectors = /(?=qa_selector|data-qa-selector)|(?!.*\bdata-qa-)(?=class=.*qa-.*|class: .*qa-.*)/
def filter_changed_lines(files, pattern)
lines = []
files.each do |file|
+ next if file.start_with?('spec/', 'ee/spec/', 'qa/')
+
testid_changed_lines = helper.changed_lines(file).select { |line| line =~ pattern }
next unless testid_changed_lines.any?
diff --git a/danger/roulette/Dangerfile b/danger/roulette/Dangerfile
index 33fcb6cb807..ba0efcc720e 100644
--- a/danger/roulette/Dangerfile
+++ b/danger/roulette/Dangerfile
@@ -16,11 +16,14 @@ MARKDOWN
POST_TABLE_MESSAGE = <<MARKDOWN
-To spread load more evenly across eligible reviewers, Danger has picked a candidate for each
-review slot, based on their timezone. Feel free to
-[override these selections](https://about.gitlab.com/handbook/engineering/projects/#gitlab)
+**Please check reviewer's status!**
+- ![available](https://gitlab-org.gitlab.io/gitlab-roulette/status-svg/_success.svg) Reviewer is available!
+- ![unavailable](https://gitlab-org.gitlab.io/gitlab-roulette/status-svg/_alert.svg) Reviewer is unavailable!
+
+Feel free to [override these selections](https://about.gitlab.com/handbook/engineering/projects/#gitlab)
if you think someone else would be better-suited
-or use the [GitLab Review Workload Dashboard](https://gitlab-org.gitlab.io/gitlab-roulette/) to find other available reviewers.
+or use the [GitLab Review Workload Dashboard](https://gitlab-org.gitlab.io/gitlab-roulette/)
+to find other available reviewers.
To read more on how to use the reviewer roulette, please take a look at the
[Engineering workflow](https://about.gitlab.com/handbook/engineering/workflow/#basics)
diff --git a/data/deprecations/14-8-graphql-project-network-policies.yml b/data/deprecations/14-8-graphql-project-network-policies.yml
new file mode 100644
index 00000000000..e9d68987ebe
--- /dev/null
+++ b/data/deprecations/14-8-graphql-project-network-policies.yml
@@ -0,0 +1,9 @@
+- title: "GraphQL networkPolicies resource deprecated" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters."
+ removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
+ announcement_milestone: "14.8" # (required) The milestone when this feature was first announced as deprecated.
+ breaking_change: true # (required) Change to false if this is not a breaking change.
+ reporter: g.hickman # (required) GitLab username of the person reporting the change
+ stage: Govern # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/421440 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ The `networkPolicies` [GraphQL resource](https://docs.gitlab.com/ee/api/graphql/reference/#projectnetworkpolicies) has been deprecated and will be removed in GitLab 17.0. Since GitLab 15.0 this field has returned no data.
diff --git a/data/deprecations/15-0-oauth-noexpiry.yml b/data/deprecations/15-0-oauth-noexpiry.yml
index 1eeb912a588..36f59e90908 100644
--- a/data/deprecations/15-0-oauth-noexpiry.yml
+++ b/data/deprecations/15-0-oauth-noexpiry.yml
@@ -7,7 +7,7 @@
had no expiration. In GitLab 15.0, an expiry will be automatically generated for any existing token that does not
already have one.
- You should [opt in](https://docs.gitlab.com/ee/integration/oauth_provider.html#expiring-access-tokens) to expiring
+ You should [opt in](https://docs.gitlab.com/ee/integration/oauth_provider.html#access-token-expiration) to expiring
tokens before GitLab 15.0 is released:
1. Edit the application.
diff --git a/data/deprecations/15-6-deprecate-runner-reg-token-helm.yml b/data/deprecations/15-6-deprecate-runner-reg-token-helm.yml
index 0882d8ac894..f9409bf4c62 100644
--- a/data/deprecations/15-6-deprecate-runner-reg-token-helm.yml
+++ b/data/deprecations/15-6-deprecate-runner-reg-token-helm.yml
@@ -1,7 +1,7 @@
- title: "`runnerRegistrationToken` parameter for GitLab Runner Helm Chart" # (required) The name of the feature to be deprecated
announcement_milestone: "15.6" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
- removal_date: "2024-04-22"
+ removal_milestone: "18.0" # (required) The milestone when this feature is planned to be removed
+ removal_date: "2025-04-22"
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: pedropombeiro # (required) GitLab username of the person reporting the deprecation
stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
@@ -10,8 +10,8 @@
The [`runnerRegistrationToken`](https://docs.gitlab.com/runner/install/kubernetes.html#required-configuration) parameter to use the GitLab Helm Chart to install a runner on Kubernetes is deprecated.
We plan to implement a new method to bind runners to a GitLab instance leveraging `runnerToken`
- as part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/).
+ as part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/ci/runners/new_creation_workflow.html).
The work is planned in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/7633).
- From GitLab 17.0 and later, the methods to register runners introduced by the new GitLab Runner token architecture will be the only supported methods.
+ From GitLab 18.0 and later, the methods to register runners introduced by the new GitLab Runner token architecture will be the only supported methods.
end_of_support_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
diff --git a/data/deprecations/15-6-deprecate-runner-register-command.yml b/data/deprecations/15-6-deprecate-runner-register-command.yml
index 6443580d8f8..4fcde11ce16 100644
--- a/data/deprecations/15-6-deprecate-runner-register-command.yml
+++ b/data/deprecations/15-6-deprecate-runner-register-command.yml
@@ -1,7 +1,7 @@
- title: "Registration tokens and server-side runner arguments in `gitlab-runner register` command" # (required) The name of the feature to be deprecated
announcement_milestone: "15.6" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
- removal_date: "2024-04-22"
+ removal_milestone: "18.0" # (required) The milestone when this feature is planned to be removed
+ removal_date: "2025-04-22"
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: pedropombeiro # (required) GitLab username of the person reporting the deprecation
stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
@@ -9,7 +9,7 @@
body: | # (required) Do not modify this line, instead modify the lines below.
Registration tokens and certain configuration arguments in the command `gitlab-runner register` that [registers](https://docs.gitlab.com/runner/register/) a runner, are deprecated.
Authentication tokens will be used to register runners instead. Registration tokens, and support for certain configuration arguments,
- will be removed in GitLab 17.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
+ will be removed in GitLab 18.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
The configuration arguments disabled for authentication tokens are:
- `--locked`
diff --git a/data/deprecations/15-6-deprecate-runner-register-token-k8s-operator.yml b/data/deprecations/15-6-deprecate-runner-register-token-k8s-operator.yml
index c4910f72887..5bbe75efa42 100644
--- a/data/deprecations/15-6-deprecate-runner-register-token-k8s-operator.yml
+++ b/data/deprecations/15-6-deprecate-runner-register-token-k8s-operator.yml
@@ -1,14 +1,14 @@
- title: "GitLab Runner registration token in Runner Operator" # (required) The name of the feature to be deprecated
announcement_milestone: "15.6" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
- removal_date: "2024-04-22"
+ removal_milestone: "18.0" # (required) The milestone when this feature is planned to be removed
+ removal_date: "2025-04-22"
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: ratchade # (required) GitLab username of the person reporting the deprecation
stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382077 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The [`runner-registration-token`](https://docs.gitlab.com/runner/install/operator.html#install-the-kubernetes-operator) parameter that uses the OpenShift and Kubernetes Vanilla Operator to install a runner on Kubernetes is deprecated. Authentication tokens will be used to register runners instead. Registration tokens, and support for certain configuration arguments,
- will be removed in GitLab 17.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
+ will be removed in GitLab 18.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
The configuration arguments disabled for authentication tokens are:
- `--locked`
diff --git a/data/deprecations/15-7-deprecate-api-v4-runner-registration-token-reset-endpoints.yml b/data/deprecations/15-7-deprecate-api-v4-runner-registration-token-reset-endpoints.yml
index d617b5de531..bf383119f9f 100644
--- a/data/deprecations/15-7-deprecate-api-v4-runner-registration-token-reset-endpoints.yml
+++ b/data/deprecations/15-7-deprecate-api-v4-runner-registration-token-reset-endpoints.yml
@@ -1,14 +1,14 @@
- title: "Support for REST API endpoints that reset runner registration tokens" # (required) The name of the feature to be deprecated
announcement_milestone: "15.7" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
- removal_date: "2024-04-22"
+ removal_milestone: "18.0" # (required) The milestone when this feature is planned to be removed
+ removal_date: "2025-04-22"
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: pedropombeiro # (required) GitLab username of the person reporting the deprecation
stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/383341 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The support for runner registration tokens is deprecated. As a consequence, the REST API endpoints to reset a registration token are also deprecated and will
- return the HTTP `410 Gone` status code in GitLab 17.0.
+ return the HTTP `410 Gone` status code in GitLab 18.0.
The deprecated endpoints are:
- `POST /runners/reset_registration_token`
@@ -16,11 +16,11 @@
- `POST /groups/:id/runners/reset_registration_token`
We plan to implement a new method to bind runners to a GitLab instance
- as part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/).
+ as part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/ci/runners/new_creation_workflow.html).
The work is planned in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/7633).
This new architecture introduces a new method for registering runners and will eliminate the legacy
[runner registration token](https://docs.gitlab.com/ee/security/token_overview.html#runner-registration-tokens).
- From GitLab 17.0 and later, the runner registration methods implemented by the new GitLab Runner token architecture will be the only supported methods.
+ From GitLab 18.0 and later, the runner registration methods implemented by the new GitLab Runner token architecture will be the only supported methods.
end_of_support_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
documentation_url: https://docs.gitlab.com/ee/api/runners.html#register-a-new-runner # (optional) This is a link to the current documentation page
diff --git a/data/deprecations/15-9-JWT-OIDC.yml b/data/deprecations/15-9-JWT-OIDC.yml
index 48e1b862032..5ed2b27e539 100644
--- a/data/deprecations/15-9-JWT-OIDC.yml
+++ b/data/deprecations/15-9-JWT-OIDC.yml
@@ -1,7 +1,7 @@
---
- title: "Old versions of JSON web tokens are deprecated"
announcement_milestone: "15.9" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "16.5" # (required) The milestone when this feature is planned to be removed
+ removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
breaking_change: true # (required) Change to false if this is not a breaking change.
reporter: dhershkovitch # (required) GitLab username of the person reporting the change
stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
@@ -32,9 +32,9 @@
- CI/CD jobs that use the `id_tokens` keyword can use ID tokens with `secrets:vault`,
and will not have any `CI_JOB_JWT*` tokens available.
- Jobs that do not use the `id_tokens` keyword will continue to have the `CI_JOB_JWT*`
- tokens available until GitLab 16.5.
+ tokens available until GitLab 17.0.
- In GitLab 16.5, the deprecated tokens will be completely removed and will no longer
+ In GitLab 17.0, the deprecated tokens will be completely removed and will no longer
be available in CI/CD jobs.
#
diff --git a/data/deprecations/15-9-license-compliance-ci-template.yml b/data/deprecations/15-9-license-compliance-ci-template.yml
index 9b2ab1cbe90..2defcda89ee 100644
--- a/data/deprecations/15-9-license-compliance-ci-template.yml
+++ b/data/deprecations/15-9-license-compliance-ci-template.yml
@@ -6,9 +6,19 @@
stage: secure
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387561
body: |
- **Update:** We previously announced we would remove the existing License Compliance CI template in GitLab 16.0. However, due to performance issues with the [license scanning of CycloneDX files](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/) we will do this change in 16.3 instead.
+ **Update:** We previously announced we would remove the existing License Compliance CI template in GitLab 16.0. However, due to performance issues with the [license scanning of CycloneDX files](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/) we will do this in 16.3 instead.
- The GitLab [License Compliance](https://docs.gitlab.com/ee/user/compliance/license_compliance/) CI template is now deprecated and is scheduled for removal in the GitLab 16.1 release. Users who wish to continue using GitLab for License Compliance should remove the License Compliance template from their CI pipeline and add the [Dependency Scanning template](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuration). The Dependency Scanning template is now capable of gathering the required license information so it is no longer necessary to run a separate License Compliance job. The License Compliance CI template should not be removed prior to verifying that the `license_scanning_sbom_scanner` and `package_metadata_synchronization` flags are enabled for the instance and that the instance has been upgraded to a version that supports [the new method of license scanning](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/).
+ The GitLab [**License Compliance**](https://docs.gitlab.com/ee/user/compliance/license_compliance/) CI/CD template is now deprecated and is scheduled for removal in the GitLab 16.3 release.
+
+ To continue using GitLab for license compliance, remove the **License Compliance** template from your CI/CD pipeline and add the **Dependency Scanning** template. The **Dependency Scanning** template is now capable of gathering the required license information, so it is no longer necessary to run a separate license compliance job.
+
+ Before you remove the **License Compliance** CI/CD template, verify that the instance has been upgraded to a version that supports the new method of license scanning.
+
+ To begin using the Dependency Scanner quickly at scale, you may set up a scan execution policy at the group level to enforce the SBOM-based license scan for all projects in the group. Then, you may remove the inclusion of the `Jobs/License-Scanning.gitlab-ci.yml` template from your CI/CD configuration.
+
+ If you wish to continue using the legacy license compliance feature, you can do so by setting the `LICENSE_MANAGEMENT_VERSION CI` variable to `4`. This variable can be set at the project, group, or instance level. This configuration change will allow you to continue using an existing version of license compliance without having to adopt the new approach.
+
+ Bugs and vulnerabilities in this legacy analyzer will no longer be fixed.
| CI Pipeline Includes | GitLab <= 15.8 | 15.9 <= GitLab < 16.3 | GitLab >= 16.3 |
| ------------- | ------------- | ------------- | ------------- |
diff --git a/data/deprecations/16-0-Vault-integration.yml b/data/deprecations/16-0-Vault-integration.yml
index 987ac2bed3c..422852a5477 100644
--- a/data/deprecations/16-0-Vault-integration.yml
+++ b/data/deprecations/16-0-Vault-integration.yml
@@ -19,7 +19,7 @@
#
- title: "HashiCorp Vault integration will no longer use CI_JOB_JWT by default"
announcement_milestone: "15.9" # (required) The milestone when this feature was first announced as deprecated.
- removal_milestone: "16.5" # (required) The milestone when this feature is planned to be removed
+ removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
breaking_change: true # (required) Change to false if this is not a breaking change.
reporter: dhershkovitch # (required) GitLab username of the person reporting the change
stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
@@ -40,7 +40,7 @@
- CI/CD jobs that use the `id_tokens` keyword can use ID tokens with `secrets:vault`,
and will not have any `CI_JOB_JWT*` tokens available.
- Jobs that do not use the `id_tokens` keyword will continue to have the `CI_JOB_JWT*`
- tokens available until GitLab 16.5.
+ tokens available until GitLab 17.0.
# If an End of Support period applies, the announcement should be shared with GitLab Support
# in the `#spt_managers` channel in Slack, and mention `@gitlab-com/support` in this MR.
#
diff --git a/data/deprecations/16-3-CI-job-token-scope-update.yml b/data/deprecations/16-3-CI-job-token-scope-update.yml
new file mode 100644
index 00000000000..5867cedcc53
--- /dev/null
+++ b/data/deprecations/16-3-CI-job-token-scope-update.yml
@@ -0,0 +1,28 @@
+#
+# REQUIRED FIELDS
+#
+- title: "Job token allowlist covers public and internal projects" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters."
+ removal_milestone: "16.6" # (required) The milestone when this feature is planned to be removed
+ announcement_milestone: "16.3" # (required) The milestone when this feature was first announced as deprecated.
+ breaking_change: true # (required) Change to false if this is not a breaking change.
+ reporter: jocelynjane # (required) GitLab username of the person reporting the change
+ stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/420678 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ Starting in 16.6, projects that are **public** or **internal** will no longer authorize job token requests from projects that are **not** on the project's allowlist when [**Limit access to this project**](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#allow-access-to-your-project-with-a-job-token) is enabled.
+
+ If you have [public or internal](https://docs.gitlab.com/ee/user/public_access.html#change-project-visibility) projects with the **Limit access to this project** setting enabled, you must add any projects which make job token requests to your project's allowlist for continued authorization.
+#
+# OPTIONAL END OF SUPPORT FIELDS
+#
+# If an End of Support period applies, the announcement should be shared with GitLab Support
+# in the `#spt_managers` channel in Slack, and mention `@gitlab-com/support` in this MR.
+#
+ end_of_support_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ #
+ # OTHER OPTIONAL FIELDS
+ #
+ tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
+ documentation_url: # (optional) This is a link to the current documentation page
+ image_url: # (optional) This is a link to a thumbnail image depicting the feature
+ video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
diff --git a/data/deprecations/16-3-remove-rsa-key-size-larger-than-8k-support.yml b/data/deprecations/16-3-remove-rsa-key-size-larger-than-8k-support.yml
new file mode 100644
index 00000000000..8f6a547a1c1
--- /dev/null
+++ b/data/deprecations/16-3-remove-rsa-key-size-larger-than-8k-support.yml
@@ -0,0 +1,12 @@
+- title: "RSA key size limits"
+ removal_milestone: "16.3"
+ announcement_milestone: "16.3"
+ breaking_change: true
+ reporter: derekferguson
+ stage: Create
+ issue_url: https://gitlab.com/groups/gitlab-org/-/epics/11186
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ Go versions 1.20.7 and later add a `maxRSAKeySize` constant that limits RSA keys to a maximum of 8192 bits. As a result, RSA keys larger than 8192 bits will no longer work with GitLab. Any RSA keys larger than 8192 bits must be regenerated at a smaller size.
+
+ You might notice this issue because your logs include an error like `tls: server sent certificate containing RSA key larger than 8192 bits`. To test the length of your key, use this command: `openssl rsa -in <your-key-file> -text -noout | grep "Key:"`.
+ documentation_url: https://docs.gitlab.com/ee/user/ssh.html
diff --git a/data/deprecations/16-4-ci_job_token_scope_enabled-attribute-deprecation.yml b/data/deprecations/16-4-ci_job_token_scope_enabled-attribute-deprecation.yml
new file mode 100644
index 00000000000..57e42f17cc8
--- /dev/null
+++ b/data/deprecations/16-4-ci_job_token_scope_enabled-attribute-deprecation.yml
@@ -0,0 +1,26 @@
+#
+# REQUIRED FIELDS
+#
+- title: "The `ci_job_token_scope_enabled` projects API attribute is deprecated" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters."
+ removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
+ announcement_milestone: "16.4" # (required) The milestone when this feature was first announced as deprecated.
+ breaking_change: true # (required) Change to false if this is not a breaking change.
+ reporter: jocelynjane # (required) GitLab username of the person reporting the change
+ stage: verify # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423091 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ GitLab 16.1 introduced [API endpoints for the job token scope](https://gitlab.com/gitlab-org/gitlab/-/issues/351740). In the [projects API](https://docs.gitlab.com/ee/api/projects.html), the `ci_job_token_scope_enabled` attribute is deprecated, and will be removed in 17.0. You should use the [job token scope APIs](https://docs.gitlab.com/ee/api/project_job_token_scopes.html) instead.
+#
+# OPTIONAL END OF SUPPORT FIELDS
+#
+# If an End of Support period applies, the announcement should be shared with GitLab Support
+# in the `#spt_managers` channel in Slack, and mention `@gitlab-com/support` in this MR.
+#
+ end_of_support_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ #
+ # OTHER OPTIONAL FIELDS
+ #
+ tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
+ documentation_url: # (optional) This is a link to the current documentation page
+ image_url: # (optional) This is a link to a thumbnail image depicting the feature
+ video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
diff --git a/data/deprecations/16-4-deprecate-change-vulnerability-status-with-developer-role.yml b/data/deprecations/16-4-deprecate-change-vulnerability-status-with-developer-role.yml
new file mode 100644
index 00000000000..e35c755ba87
--- /dev/null
+++ b/data/deprecations/16-4-deprecate-change-vulnerability-status-with-developer-role.yml
@@ -0,0 +1,11 @@
+- title: "Deprecate change vulnerability status from the Developer role"
+ removal_milestone: "17.0"
+ announcement_milestone: "16.4"
+ breaking_change: true
+ reporter: abellucci
+ stage: govern
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424133
+ body: |
+ The ability for Developers to change the status of vulnerabilities is now deprecated. We plan to make a breaking change in the upcoming GitLab 17.0 release to remove this ability from the Developer role. Users who wish to continue to grant this permission to developers can [create a custom role](https://docs.gitlab.com/ee/user/permissions.html#custom-roles) for their developers and add in the `admin_vulnerability` permission to give them this access.
+ tiers: [Gold, Ultimate]
+ documentation_url: https://docs.gitlab.com/ee/user/permissions.html#custom-roles
diff --git a/data/deprecations/16-4-geo-legacy-component-routes-deprecation.yml b/data/deprecations/16-4-geo-legacy-component-routes-deprecation.yml
new file mode 100644
index 00000000000..83a9882c90f
--- /dev/null
+++ b/data/deprecations/16-4-geo-legacy-component-routes-deprecation.yml
@@ -0,0 +1,17 @@
+#
+# REQUIRED FIELDS
+#
+- title: "Geo: Legacy replication details routes for designs and projects deprecated" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters."
+ removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
+ announcement_milestone: "16.4" # (required) The milestone when this feature was first announced as deprecated.
+ breaking_change: true # (required) Change to false if this is not a breaking change.
+ reporter: sranasinghe # (required) GitLab username of the person reporting the change
+ stage: enablement # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424002 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ As part of the migration of legacy data types to the [Geo self-service framework](https://docs.gitlab.com/ee/development/geo/framework.html), the following replication details routes are deprecated:
+
+ - Designs `/admin/geo/replication/designs` replaced by `/admin/geo/sites/<Geo Node/Site ID>/replication/design_management_repositories`
+ - Projects `/admin/geo/replication/projects` replaced by `/admin/geo/sites/<Geo Node/Site ID>/replication/projects`
+
+ From GitLab 16.4 to 17.0, lookups for the legacy routes will automatically be redirected to the new routes. We will remove the redirections in 17.0. Please update any bookmarks or scripts that may use the legacy routes.
diff --git a/data/deprecations/16-4_support_for_delete_tags_endpoint.yml b/data/deprecations/16-4_support_for_delete_tags_endpoint.yml
new file mode 100644
index 00000000000..5805653c027
--- /dev/null
+++ b/data/deprecations/16-4_support_for_delete_tags_endpoint.yml
@@ -0,0 +1,21 @@
+- title: "Internal Container Registry API tag deletion endpoint" # (required) Actionable title. e.g., The `confidential` field for a `Note` is deprecated. Use `internal` instead.
+ announcement_milestone: "16.4" # (required) The milestone when this feature was first announced as deprecated.
+ removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
+ breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
+ reporter: trizzi # (required) GitLab username of the person reporting the deprecation
+ stage: Package # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/container-registry/-/issues/1094 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ The [Docker Registry HTTP API V2 Spec](https://docs.docker.com/registry/spec/api/), later replaced by the [OCI Distribution Spec](https://github.com/opencontainers/distribution-spec/blob/main/spec.md) did not include a tag delete operation, and an unsafe and slow workaround (involving deleting manifests, not tags) had to be used to achieve the same end.
+
+ Tag deletion is an important function, so we added a tag deletion operation to the GitLab Container Registry, extending the V2 API beyond the scope of the Docker and OCI distribution spec.
+
+ Since then, the OCI Distribution Spec has had some updates and it now has a tag delete operation, using the [`DELETE /v2/<name>/manifests/<tag>` endpoint](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#deleting-tags).
+
+ This leaves the container registry with two endpoints that provide the exact same functionality. `DELETE /v2/<name>/tags/reference/<tag>` is the custom GitLab tag delete endpoint and `DELETE /v2/<name>/manifests/<tag>`, the OCI compliant tag delete endpoint introduced in GitLab 16.4.
+
+ Support for the custom GitLab tag delete endpoint is deprecated in GitLab 16.4, and it will be removed in GitLab 17.0.
+
+ This endpoint is used by the **internal** Container Registry application API, not the public [GitLab Container Registry API](https://docs.gitlab.com/ee/api/container_registry.html). No action should be required by the majority of container registry users. All the GitLab UI and API functionality related to tag deletions will remain intact as we transition to the new OCI-compliant endpoint.
+
+ If you do access the internal container registry API and use the original tag deletion endpoint, you must update to the new endpoint.
diff --git a/data/deprecations/16-5-ci-job-token-limit-setting.yml b/data/deprecations/16-5-ci-job-token-limit-setting.yml
new file mode 100644
index 00000000000..aec19775513
--- /dev/null
+++ b/data/deprecations/16-5-ci-job-token-limit-setting.yml
@@ -0,0 +1,37 @@
+#
+# REQUIRED FIELDS
+#
+- title: "Default CI/CD job token (`CI_JOB_TOKEN`) scope changed" # (required) Clearly explain the change, or planned change. For example, "The `confidential` field for a `Note` is deprecated" or "CI/CD job names will be limited to 250 characters."
+ announcement_milestone: "15.9" # (required) The milestone when this feature was first announced as deprecated.
+ removal_milestone: "17.0" # (required) The milestone when this feature is planned to be removed
+ breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
+ reporter: jocelynjane # (required) GitLab username of the person reporting the deprecation
+ stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/383084 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ In GitLab 14.4 we introduced the ability to [limit your project's CI/CD job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#limit-your-projects-job-token-access) (`CI_JOB_TOKEN`) access to make it more secure. You can prevent job tokens **from your project's** pipelines from being used to **access other projects**. When enabled with no other configuration, your pipelines cannot access other projects. To use the job token to access other projects from your pipeline, you must list those projects explicitly in the **Limit CI_JOB_TOKEN access** setting's allowlist, and you must be a maintainer in all the projects.
+
+ The job token functionality was updated in 15.9 with a better security setting to [allow access to your project with a job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#allow-access-to-your-project-with-a-job-token). When enabled with no other configuration, job tokens **from other projects** cannot **access your project**. Similar to the older setting, you can optionally allow other projects to access your project with a job token if you list those projects explicitly in the **Allow access to this project with a CI_JOB_TOKEN** setting's allowlist. With this new setting, you must be a maintainer in your own project, but only need to have the Guest role in the other projects.
+
+ The **Limit** setting was deprecated in 16.0 in preference of the better **Allow access** setting and **Limit** setting was disabled by default for all new projects. From this point forward, if the **Limit** setting is disabled in any project, it will not be possible to re-enable this setting in 16.0 or later.
+
+ In 17.0, we will remove the **Limit** setting completely, and set the **Allow access** setting to enabled for all projects. This change ensures a higher level of security between projects. If you currently use the **Limit** setting, you should update your projects to use the **Allow access** setting instead. If other projects access your project with a job token, you must add them to the **Allow access** allowlist.
+
+ To prepare for this change, users on GitLab.com or self-managed GitLab 15.9 or later can enable the **Allow access** setting now and add the other projects. It will not be possible to disable the setting in 17.0 or later.
+
+ In 16.3, the names of these settings were changed to clarify their meanings: the deprecated **Limit CI_JOB_TOKEN access** setting is now called **Limit access _from_ this project**, and the newer **Allow access to this project with a CI_JOB_TOKEN** setting is now called **Limit access _to_ this project**.
+ #
+ # OPTIONAL END OF SUPPORT FIELDS
+ #
+ # If an End of Support period applies, the announcement should be shared with GitLab Support
+ # in the `#spt_managers` channel in Slack, and mention `@gitlab-com/support` in this MR.
+ #
+ end_of_support_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_date: # (optional) The date of the milestone release when support for this feature will end.
+ #
+ # OTHER OPTIONAL FIELDS
+ #
+ tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
+ documentation_url: "https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#configure-the-job-token-scope-limit" # (optional) This is a link to the current documentation page
+ image_url: # (optional) This is a link to a thumbnail image depicting the feature
+ video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
diff --git a/data/whats_new/202212200001_15_07.yml b/data/whats_new/202212200001_15_07.yml
index ebfcc0f16ad..465de395fdb 100644
--- a/data/whats_new/202212200001_15_07.yml
+++ b/data/whats_new/202212200001_15_07.yml
@@ -64,7 +64,7 @@
release: 15.7
- name: "Sign commits with your SSH key"
description: | # Do not modify this line, instead modify the lines below.
- Signing commits just got a lot simpler. Use SSH keys [to sign commits](https://docs.gitlab.com/ee/user/project/repository/ssh_signed_commits/), and provide others with confidence that a **Verified** commit was authored by you.
+ Signing commits just got a lot simpler. Use SSH keys [to sign commits](https://docs.gitlab.com/ee/user/project/repository/signed_commits/ssh.html), and provide others with confidence that a **Verified** commit was authored by you.
Previous methods for signing commits required a GPG key or an X.509 certificate, neither of which can be used to sign in to GitLab. Adding support for commit signing with SSH keys now makes it possible to reuse your authentication key pair to also sign your commits. If you already authenticate into GitLab with an SSH key, add three lines of code to your local Git configuration and all your future commits will be signed.
@@ -73,7 +73,7 @@
self-managed: true
gitlab-com: true
available_in: [Free, Premium, Ultimate]
- documentation_link: https://docs.gitlab.com/ee/user/project/repository/ssh_signed_commits/
+ documentation_link: https://docs.gitlab.com/ee/user/project/repository/signed_commits/ssh.html
image_url: https://img.youtube.com/vi/IrK83nKi8HA/hqdefault.jpg
published_at: 2022-12-22
release: 15.7
diff --git a/data/whats_new/202308220001_16_3.yml b/data/whats_new/202308220001_16_3.yml
new file mode 100644
index 00000000000..0e47c6a2eef
--- /dev/null
+++ b/data/whats_new/202308220001_16_3.yml
@@ -0,0 +1,74 @@
+- name: New velocity metrics in the Value Streams Dashboard
+ description: | # Do not modify this line, instead modify the lines below.
+ The [Value Streams Dashboard](https://about.gitlab.com/blog/2023/06/12/getting-started-with-value-streams-dashboard/) has been enhanced with new metrics: **Merge request (MR) throughput** and **Total closed issues** (Velocity). In GitLab, **MR throughput** is a count of the number of merge requests merged per month, and **Total closed issues** is the number of flow items closed at a point in time.
+
+ With these metrics, you can identify low or high productivity months and the efficiency of [merge request and code review processes](https://docs.gitlab.com/ee/user/analytics/merge_request_analytics.html). You can then gauge whether the [Value Stream delivery](https://docs.gitlab.com/ee/user/group/value_stream_analytics/) is accelerating or not.
+
+ Over time, the metrics accumulate historical data from MRs and issues. Teams can use the data to determine if delivery rates are accelerating or need improvement, and provide more accurate estimates or forecasts for how much work they can deliver.
+ stage: Plan
+ self-managed: true
+ gitlab-com: true
+ available_in: [Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/user/analytics/value_streams_dashboard.html
+ image_url: https://about.gitlab.com/images/16_3/16.3_vsd.mr_iss.png
+ published_at: 2023-08-22
+ release: 16.3
+
+- name: More powerful GitLab SaaS runners on Linux
+ description: | # Do not modify this line, instead modify the lines below.
+ Having recently upgraded all of our Linux SaaS runners, we are now introducing `xlarge` and `2xlarge` [SaaS runners on Linux](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html). Equipped with 16 and 32 vCPUs respectively and fully integrated with GitLab CI/CD, these runners will allow you to build and test your application faster than ever before.
+
+ We are determined to provide the industry's fastest CI/CD build speed and look forward to seeing teams achieve even shorter feedback cycles and ultimately deliver software faster.
+ stage: Verify
+ self-managed: false
+ gitlab-com: true
+ available_in: [Premium, Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html
+ image_url: https://about.gitlab.com/images/16_3/larger-runners.png
+ published_at: 2023-08-22
+ release: 16.3
+
+- name: Additional filtering for scan result policies
+ description: | # Do not modify this line, instead modify the lines below.
+ Determining which results from a security or compliance scan are actionable is a significant challenge for security and compliance teams. Granular filters for scan result policies will help you cut through the noise to identify which vulnerabilities or violations require your attention the most. These new filters and filter updates will streamline your workflows:
+
+ - Status: Status rule changes introduce more intuitive enforcement of "new" versus "previously existing" vulnerabilities. A new status field `new_needs_triage` allows you to filter only new vulnerabilities that need to be triaged.
+ - Age: Create policies to enforce approvals when a vulnerability is outside of SLA (days, months, or years) based on the detected date.
+ - Fix Available: Narrow the focus of your policy to address dependencies that have a fix available.
+ - False Positive: Filter out false positives that have been detected by our Vulnerability Extraction Tool, for SAST results, and via Rezilion for our Container Scanning and Dependency Scanning results.
+ stage: Govern
+ self-managed: true
+ gitlab-com: true
+ available_in: [Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/user/application_security/policies/scan-result-policies.html
+ image_url: https://about.gitlab.com/images/16_3/security-policy-filters-compressed.png
+ published_at: 2023-08-22
+ release: 16.3
+
+- name: Connect to a workspace with SSH
+ description: | # Do not modify this line, instead modify the lines below.
+ With workspaces, you can create reproducible, ephemeral, cloud-based runtime environments. Since the feature was introduced in GitLab 16.0, the only way to use a workspace was through the browser-based Web IDE running directly in the environment. The Web IDE, however, might not always be the right tool for you.
+
+ With GitLab 16.3, you can now securely connect to a workspace from your desktop with SSH and use your local tools and extensions. The first iteration supports SSH connections directly in VS Code or from the command line with editors like Vim or Emacs. Support for other editors such as JetBrains IDEs and JupyterLab is proposed in future iterations.
+ stage: Create
+ self-managed: true
+ gitlab-com: true
+ available_in: [Premium, Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/user/workspace/configuration.html#connect-to-a-workspace-with-ssh
+ image_url: https://about.gitlab.com/images/16_3/create-workspace-ssh.png
+ published_at: 2023-08-22
+ release: 16.3
+
+- name: Flux sync status visualization
+ description: | # Do not modify this line, instead modify the lines below.
+ In previous releases, you probably used `kubectl` or another third-party tool to check the status of your Flux deployments. From GitLab 16.3, you can check your deployments with the environments UI.
+
+ Deployments rely on Flux `Kustomization` and `HelmRelease` resources to gather the status of a given environment, which requires a namespace to be configured for the environment. By default, GitLab searches the `Kustomization` and `HelmRelease` resources for the name of the project slug. You can customize the name GitLab looks for in the environment settings.
+ stage: Deploy
+ self-managed: true
+ gitlab-com: true
+ available_in: [Free, Premium, Ultimate]
+ documentation_link: https://docs.gitlab.com/ee/ci/environments/kubernetes_dashboard.html#flux-sync-status
+ image_url: https://about.gitlab.com/images/16_3/flux-badges.png
+ published_at: 2023-08-22
+ release: 16.3
diff --git a/db/click_house/main/20230707151359_create_ci_finished_builds.sql b/db/click_house/main/20230707151359_create_ci_finished_builds.sql
new file mode 100644
index 00000000000..6b1b846518d
--- /dev/null
+++ b/db/click_house/main/20230707151359_create_ci_finished_builds.sql
@@ -0,0 +1,33 @@
+-- source table for CI analytics, almost useless on it's own, but it's a basis for creating materialized views
+CREATE TABLE ci_finished_builds
+(
+ id UInt64 DEFAULT 0,
+ project_id UInt64 DEFAULT 0,
+ pipeline_id UInt64 DEFAULT 0,
+ status LowCardinality(String) DEFAULT '',
+
+ --- Fields to calculate timings
+ created_at DateTime64(6, 'UTC') DEFAULT now(),
+ queued_at DateTime64(6, 'UTC') DEFAULT now(),
+ finished_at DateTime64(6, 'UTC') DEFAULT now(),
+ started_at DateTime64(6, 'UTC') DEFAULT now(),
+
+ runner_id UInt64 DEFAULT 0,
+ runner_manager_system_xid String DEFAULT '',
+
+ --- Runner fields
+ runner_run_untagged Boolean DEFAULT FALSE,
+ runner_type UInt8 DEFAULT 0,
+ runner_manager_version LowCardinality(String) DEFAULT '',
+ runner_manager_revision LowCardinality(String) DEFAULT '',
+ runner_manager_platform LowCardinality(String) DEFAULT '',
+ runner_manager_architecture LowCardinality(String) DEFAULT '',
+
+ --- Materialized columns
+ duration Int64 MATERIALIZED age('second', started_at, finished_at),
+ queueing_duration Int64 MATERIALIZED age('second', queued_at, started_at)
+ --- This table is incomplete, we'll add more fields before starting the data migration
+)
+ENGINE = ReplacingMergeTree -- Using ReplacingMergeTree just in case we accidentally insert the same data twice
+ORDER BY (status, runner_type, project_id, finished_at, id)
+PARTITION BY toYear(finished_at)
diff --git a/db/click_house/main/20230719101806_create_ci_finished_builds_aggregated_queueing_delay_percentiles.sql b/db/click_house/main/20230719101806_create_ci_finished_builds_aggregated_queueing_delay_percentiles.sql
new file mode 100644
index 00000000000..56889ffc0d4
--- /dev/null
+++ b/db/click_house/main/20230719101806_create_ci_finished_builds_aggregated_queueing_delay_percentiles.sql
@@ -0,0 +1,11 @@
+CREATE TABLE ci_finished_builds_aggregated_queueing_delay_percentiles
+(
+ status LowCardinality(String) DEFAULT '',
+ runner_type UInt8 DEFAULT 0,
+ started_at_bucket DateTime64(6, 'UTC') DEFAULT now(),
+
+ count_builds AggregateFunction(count),
+ queueing_duration_quantile AggregateFunction(quantile, Int64)
+)
+ENGINE = AggregatingMergeTree()
+ORDER BY (started_at_bucket, status, runner_type)
diff --git a/db/click_house/main/20230808070520_create_events_cursor.sql b/db/click_house/main/20230808070520_create_events_cursor.sql
new file mode 100644
index 00000000000..effc3c64f60
--- /dev/null
+++ b/db/click_house/main/20230808070520_create_events_cursor.sql
@@ -0,0 +1,9 @@
+CREATE TABLE sync_cursors
+(
+ table_name LowCardinality(String) DEFAULT '',
+ primary_key_value UInt64 DEFAULT 0,
+ recorded_at DateTime64(6, 'UTC') DEFAULT now()
+)
+ENGINE = ReplacingMergeTree(recorded_at)
+ORDER BY (table_name)
+PRIMARY KEY (table_name)
diff --git a/db/click_house/main/20230808140217_create_ci_finished_builds_aggregated_queueing_delay_percentiles_mv.sql b/db/click_house/main/20230808140217_create_ci_finished_builds_aggregated_queueing_delay_percentiles_mv.sql
new file mode 100644
index 00000000000..504e2d87609
--- /dev/null
+++ b/db/click_house/main/20230808140217_create_ci_finished_builds_aggregated_queueing_delay_percentiles_mv.sql
@@ -0,0 +1,12 @@
+CREATE MATERIALIZED VIEW ci_finished_builds_aggregated_queueing_delay_percentiles_mv
+TO ci_finished_builds_aggregated_queueing_delay_percentiles
+AS
+SELECT
+ status,
+ runner_type,
+ toStartOfInterval(started_at, INTERVAL 5 minute) AS started_at_bucket,
+
+ countState(*) as count_builds,
+ quantileState(queueing_duration) AS queueing_duration_quantile
+FROM ci_finished_builds
+GROUP BY status, runner_type, started_at_bucket
diff --git a/db/docs/audit_events_amazon_s3_configurations.yml b/db/docs/audit_events_amazon_s3_configurations.yml
new file mode 100644
index 00000000000..fa4945186ea
--- /dev/null
+++ b/db/docs/audit_events_amazon_s3_configurations.yml
@@ -0,0 +1,10 @@
+---
+table_name: audit_events_amazon_s3_configurations
+classes:
+ - AuditEvents::AmazonS3Configuration
+feature_categories:
+ - audit_events
+description: Stores Amazon S3 configurations associated used for audit event streaming.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/333371
+milestone: '16.4'
+gitlab_schema: gitlab_main
diff --git a/db/docs/audit_events_instance_google_cloud_logging_configurations.yml b/db/docs/audit_events_instance_google_cloud_logging_configurations.yml
new file mode 100644
index 00000000000..059ab59d860
--- /dev/null
+++ b/db/docs/audit_events_instance_google_cloud_logging_configurations.yml
@@ -0,0 +1,10 @@
+---
+table_name: audit_events_instance_google_cloud_logging_configurations
+classes:
+ - AuditEvents::Instance::GoogleCloudLoggingConfiguration
+feature_categories:
+ - audit_events
+description: Stores Instance level Google Cloud Logging configurations associated with IAM service accounts, used for generating access tokens.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/423036
+milestone: '16.4'
+gitlab_schema: gitlab_main
diff --git a/db/docs/batched_background_migrations/backfill_has_merge_request_of_vulnerability_reads.yml b/db/docs/batched_background_migrations/backfill_has_merge_request_of_vulnerability_reads.yml
new file mode 100644
index 00000000000..c6bf73622f6
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_has_merge_request_of_vulnerability_reads.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: BackfillHasMergeRequestOfVulnerabilityReads
+description: Backfills has_merge_request column for vulnerability_reads table.
+feature_category: database
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130952
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/backfill_nuget_normalized_version.yml b/db/docs/batched_background_migrations/backfill_nuget_normalized_version.yml
new file mode 100644
index 00000000000..b0ea13472d4
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_nuget_normalized_version.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: BackfillNugetNormalizedVersion
+description: Introduce a batched background migration to backfill the normalized_version column in packages_nuget_metadata table.
+feature_category: package_registry
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128675
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/backfill_project_statistics_storage_size_with_recent_size.yml b/db/docs/batched_background_migrations/backfill_project_statistics_storage_size_with_recent_size.yml
new file mode 100644
index 00000000000..1ff17fd4099
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_project_statistics_storage_size_with_recent_size.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: BackfillProjectStatisticsStorageSizeWithRecentSize
+description: Refreshes ProjectStatistics to use recent_objects_size for repository_size
+feature_category: consumables_cost_management
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128730
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/backfill_user_preferences_with_defaults.yml b/db/docs/batched_background_migrations/backfill_user_preferences_with_defaults.yml
new file mode 100644
index 00000000000..bee4b1f38a9
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_user_preferences_with_defaults.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: BackfillUserPreferencesWithDefaults
+description: Backfills the user_preferences table columns with their default values
+feature_category: user_profile
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125774
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/backfill_users_with_defaults.yml b/db/docs/batched_background_migrations/backfill_users_with_defaults.yml
new file mode 100644
index 00000000000..ecc86fd665c
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_users_with_defaults.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: BackfillUsersWithDefaults
+description: Backfills the users table columns with their default values
+feature_category: user_profile
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125881
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/backfill_workspace_personal_access_token.yml b/db/docs/batched_background_migrations/backfill_workspace_personal_access_token.yml
new file mode 100644
index 00000000000..53433fbb1c7
--- /dev/null
+++ b/db/docs/batched_background_migrations/backfill_workspace_personal_access_token.yml
@@ -0,0 +1,5 @@
+migration_job_name: BackfillWorkspacePersonalAccessToken
+description: Create personal access token for workspaces without one
+feature_category: remote_development
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131516
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/convert_credit_card_validation_data_to_hashes.yml b/db/docs/batched_background_migrations/convert_credit_card_validation_data_to_hashes.yml
new file mode 100644
index 00000000000..4835f0ac59f
--- /dev/null
+++ b/db/docs/batched_background_migrations/convert_credit_card_validation_data_to_hashes.yml
@@ -0,0 +1,8 @@
+---
+migration_job_name: ConvertCreditCardValidationDataToHashes
+description: |
+ This migration converts a credit card's expiration_date, last_digits, network & holder_name
+ to hash and store values in new columns.
+feature_category: user_profile
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129350
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/create_compliance_standards_adherence.yml b/db/docs/batched_background_migrations/create_compliance_standards_adherence.yml
new file mode 100644
index 00000000000..6ab1282358b
--- /dev/null
+++ b/db/docs/batched_background_migrations/create_compliance_standards_adherence.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: CreateComplianceStandardsAdherence
+description: This migration creates 'project_compliance_standards_adherence' table for existing projects
+feature_category: compliance_management
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/413235
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/fix_namespace_ids_of_vulnerability_reads.yml b/db/docs/batched_background_migrations/fix_namespace_ids_of_vulnerability_reads.yml
new file mode 100644
index 00000000000..1bee359aef5
--- /dev/null
+++ b/db/docs/batched_background_migrations/fix_namespace_ids_of_vulnerability_reads.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: FixNamespaceIdsOfVulnerabilityReads
+description: Fixes the data integrity issues for `namespace_id` attribute of `vulnerability_reads` table
+feature_category: vulnerability_management
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129244
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/populate_denormalized_columns_for_sbom_occurrences.yml b/db/docs/batched_background_migrations/populate_denormalized_columns_for_sbom_occurrences.yml
new file mode 100644
index 00000000000..b85ae1c22d6
--- /dev/null
+++ b/db/docs/batched_background_migrations/populate_denormalized_columns_for_sbom_occurrences.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: PopulateDenormalizedColumnsForSbomOccurrences
+description: Populates the denormalized columns for `sbom_occurrences` table.
+feature_category: dependency_management
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129486
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/sync_scan_result_policies.yml b/db/docs/batched_background_migrations/sync_scan_result_policies.yml
new file mode 100644
index 00000000000..16786572139
--- /dev/null
+++ b/db/docs/batched_background_migrations/sync_scan_result_policies.yml
@@ -0,0 +1,8 @@
+---
+migration_job_name: SyncScanResultPolicies
+description: Security policies are stored as YAML files in the security policy project. This migration
+ syncs existing policies to a DB table scan_result_policies by kicking off Sidekiq sync job
+ for all security policy configurations.
+feature_category: security_policy_management
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128378
+milestone: 16.4
diff --git a/db/docs/batched_background_migrations/update_users_set_external_if_service_account.yml b/db/docs/batched_background_migrations/update_users_set_external_if_service_account.yml
new file mode 100644
index 00000000000..1b89359b270
--- /dev/null
+++ b/db/docs/batched_background_migrations/update_users_set_external_if_service_account.yml
@@ -0,0 +1,6 @@
+---
+migration_job_name: UpdateUsersSetExternalIfServiceAccount
+description: Update external value for users of type Service Account
+feature_category: system_access
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130597
+milestone: 16.4
diff --git a/db/docs/groups_visits.yml b/db/docs/groups_visits.yml
new file mode 100644
index 00000000000..99e424d3946
--- /dev/null
+++ b/db/docs/groups_visits.yml
@@ -0,0 +1,10 @@
+---
+table_name: groups_visits
+classes:
+- Users::GroupVisit
+feature_categories:
+- navigation
+description: Tracks group visits so we can suggest groups that are recently and frequently visited.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123554
+milestone: '16.4'
+gitlab_schema: gitlab_main
diff --git a/db/docs/integrations.yml b/db/docs/integrations.yml
index 0619a59556f..d0246caaf12 100644
--- a/db/docs/integrations.yml
+++ b/db/docs/integrations.yml
@@ -62,4 +62,4 @@ description: |
https://gitlab.com/gitlab-org/gitlab/-/commit/1dab19d0d7b25cb5af27b8d10c8b615b2d38c2cf
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64562
milestone: '9.4'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
diff --git a/db/docs/issues.yml b/db/docs/issues.yml
index 369dc907d57..a7f24665677 100644
--- a/db/docs/issues.yml
+++ b/db/docs/issues.yml
@@ -8,4 +8,4 @@ feature_categories:
description: Information describing issues, which is also used by the WorkItem class
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9ba1224867665844b117fa037e1465bb706b3685
milestone: "<6.0"
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
diff --git a/db/docs/members.yml b/db/docs/members.yml
index 1a617d27a4b..0d756c18d74 100644
--- a/db/docs/members.yml
+++ b/db/docs/members.yml
@@ -10,4 +10,4 @@ feature_categories:
description: Stores members per namespace
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/3503b504eabf95487fc3fb49df953a7d694da4fe
milestone: '7.4'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
diff --git a/db/docs/merge_request_predictions.yml b/db/docs/merge_request_predictions.yml
index 9d1ef61c66a..eea738f9526 100644
--- a/db/docs/merge_request_predictions.yml
+++ b/db/docs/merge_request_predictions.yml
@@ -3,7 +3,7 @@ table_name: merge_request_predictions
classes:
- MergeRequest::Predictions
feature_categories:
-- workflow_automation
+- code_review_workflow
description: Includes machine learning model predictions
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97622
milestone: '15.4'
diff --git a/db/docs/notification_settings.yml b/db/docs/notification_settings.yml
index c048163a790..a59131b8fe5 100644
--- a/db/docs/notification_settings.yml
+++ b/db/docs/notification_settings.yml
@@ -7,4 +7,4 @@ feature_categories:
description: User preferences for receiving notifications related to various actions within the application
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/31b0e53015e38e51d9c02cca85c9279600b1bf85
milestone: '8.7'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
diff --git a/db/docs/p_ci_builds.yml b/db/docs/p_ci_builds.yml
index 757d609dd4b..ca01e89de09 100644
--- a/db/docs/p_ci_builds.yml
+++ b/db/docs/p_ci_builds.yml
@@ -2,15 +2,10 @@
table_name: p_ci_builds
classes:
- Ci::Bridge
-- Ci::Bridge::Partitioned
- Ci::Build
-- Ci::Build::Partitioned
- Ci::Processable
-- Ci::Processable::Partitioned
- CommitStatus
-- CommitStatus::Partitioned
- GenericCommitStatus
-- GenericCommitStatus::Partitioned
feature_categories:
- continuous_integration
description: Routing table for ci_builds
diff --git a/db/docs/packages_nuget_symbols.yml b/db/docs/packages_nuget_symbols.yml
new file mode 100644
index 00000000000..d78b52ce826
--- /dev/null
+++ b/db/docs/packages_nuget_symbols.yml
@@ -0,0 +1,10 @@
+---
+table_name: packages_nuget_symbols
+classes:
+- Packages::Nuget::Symbol
+feature_categories:
+- package_registry
+description: Nuget package symbols
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129916
+milestone: '16.4'
+gitlab_schema: gitlab_main
diff --git a/db/docs/packages_packages.yml b/db/docs/packages_packages.yml
index d2e08350ab7..b7abcf73ab2 100644
--- a/db/docs/packages_packages.yml
+++ b/db/docs/packages_packages.yml
@@ -1,6 +1,7 @@
---
table_name: packages_packages
classes:
+- Packages::MlModel::Package
- Packages::Package
feature_categories:
- package_registry
diff --git a/db/docs/packages_protection_rules.yml b/db/docs/packages_protection_rules.yml
new file mode 100644
index 00000000000..3007c956e26
--- /dev/null
+++ b/db/docs/packages_protection_rules.yml
@@ -0,0 +1,10 @@
+---
+table_name: packages_protection_rules
+classes:
+- Packages::Protection::Rule
+feature_categories:
+- package_registry
+description: Represents package protection rules for package registry.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124776
+milestone: '16.4'
+gitlab_schema: gitlab_main
diff --git a/db/docs/projects_visits.yml b/db/docs/projects_visits.yml
new file mode 100644
index 00000000000..23c10fd8568
--- /dev/null
+++ b/db/docs/projects_visits.yml
@@ -0,0 +1,10 @@
+---
+table_name: projects_visits
+classes:
+- Users::ProjectVisit
+feature_categories:
+- navigation
+description: Tracks project visits so we can suggest projects that are recently and frequently visited.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123554
+milestone: '16.4'
+gitlab_schema: gitlab_main
diff --git a/db/docs/web_hooks.yml b/db/docs/web_hooks.yml
index 6300a2f7c32..6ab83f4d775 100644
--- a/db/docs/web_hooks.yml
+++ b/db/docs/web_hooks.yml
@@ -11,4 +11,4 @@ feature_categories:
description: Webhooks data with the custom HTTP callbacks that a user defines.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/edab46e9fa5f568b1423c0021e81d30453d7dc1e
milestone: "<6.0"
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
diff --git a/db/docs/workspace_variables.yml b/db/docs/workspace_variables.yml
new file mode 100644
index 00000000000..f3eef551225
--- /dev/null
+++ b/db/docs/workspace_variables.yml
@@ -0,0 +1,10 @@
+---
+table_name: workspace_variables
+classes:
+- RemoteDevelopment::WorkspaceVariable
+feature_categories:
+- remote_development
+description: Remote Development Workspace variables
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129688
+milestone: '16.4'
+gitlab_schema: gitlab_main
diff --git a/db/gitlab_schemas/gitlab_main_cell.yaml b/db/gitlab_schemas/gitlab_main_cell.yaml
index 1119c10a9b8..53f6f30dfbd 100644
--- a/db/gitlab_schemas/gitlab_main_cell.yaml
+++ b/db/gitlab_schemas/gitlab_main_cell.yaml
@@ -7,8 +7,5 @@ allow_cross_transactions:
- gitlab_internal
- gitlab_shared
- gitlab_main
- # Temporarily allow cross-DB transactions between clusterwide and cell schemas
- # This is to be removed once we annotate all cross-DBs between those
- - gitlab_main_clusterwide
allow_cross_foreign_keys:
- gitlab_main
diff --git a/db/migrate/20220907124320_add_internal_to_notes.rb b/db/migrate/20220907124320_add_internal_to_notes.rb
deleted file mode 100644
index 081914f7830..00000000000
--- a/db/migrate/20220907124320_add_internal_to_notes.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-class AddInternalToNotes < Gitlab::Database::Migration[2.0]
- enable_lock_retries!
-
- def change
- add_column(:notes, :internal, :boolean, default: false, null: false)
- end
-end
diff --git a/db/migrate/20220907124320_add_internal_to_notes_renamed.rb b/db/migrate/20220907124320_add_internal_to_notes_renamed.rb
new file mode 100644
index 00000000000..e65bc503c04
--- /dev/null
+++ b/db/migrate/20220907124320_add_internal_to_notes_renamed.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+# Renamed from AddInternalToNotes to AddInternalToNotesRenamed to avoid collision with an Elasticsearch migration from
+# the same name. See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129012
+class AddInternalToNotesRenamed < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ def change
+ add_column(:notes, :internal, :boolean, default: false, null: false)
+ end
+end
diff --git a/db/migrate/20230728020644_add_snowplow_database_collector_hostname_to_application_settings.rb b/db/migrate/20230728020644_add_snowplow_database_collector_hostname_to_application_settings.rb
new file mode 100644
index 00000000000..edf27685b67
--- /dev/null
+++ b/db/migrate/20230728020644_add_snowplow_database_collector_hostname_to_application_settings.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddSnowplowDatabaseCollectorHostnameToApplicationSettings < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ add_column :application_settings, :snowplow_database_collector_hostname, :text, if_not_exists: true
+ end
+
+ add_text_limit :application_settings, :snowplow_database_collector_hostname, 255
+ end
+
+ def down
+ with_lock_retries do
+ remove_column :application_settings, :snowplow_database_collector_hostname, if_exists: true
+ end
+ end
+end
diff --git a/db/migrate/20230802205051_add_admin_merge_request_to_member_roles.rb b/db/migrate/20230802205051_add_admin_merge_request_to_member_roles.rb
new file mode 100644
index 00000000000..52560621c9a
--- /dev/null
+++ b/db/migrate/20230802205051_add_admin_merge_request_to_member_roles.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddAdminMergeRequestToMemberRoles < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ return if column_exists?(:member_roles, :admin_merge_request)
+
+ add_column :member_roles, :admin_merge_request, :boolean, default: false, null: false
+ end
+
+ def down
+ return unless column_exists?(:member_roles, :admin_merge_request)
+
+ remove_column :member_roles, :admin_merge_request
+ end
+end
diff --git a/db/migrate/20230804055559_add_rollup_progress_to_wi_progresses.rb b/db/migrate/20230804055559_add_rollup_progress_to_wi_progresses.rb
new file mode 100644
index 00000000000..53b8dd2b36f
--- /dev/null
+++ b/db/migrate/20230804055559_add_rollup_progress_to_wi_progresses.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddRollupProgressToWiProgresses < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :work_item_progresses, :rollup_progress, :boolean, default: true, null: false
+ end
+end
diff --git a/db/migrate/20230807035953_add_index_to_abuse_reports_on_user_id_status_and_category.rb b/db/migrate/20230807035953_add_index_to_abuse_reports_on_user_id_status_and_category.rb
new file mode 100644
index 00000000000..583a5471145
--- /dev/null
+++ b/db/migrate/20230807035953_add_index_to_abuse_reports_on_user_id_status_and_category.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexToAbuseReportsOnUserIdStatusAndCategory < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'idx_abuse_reports_user_id_status_and_category'
+
+ def up
+ add_concurrent_index :abuse_reports, [:user_id, :status, :category], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :abuse_reports, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230811144601_add_pages_multiple_versions_enabled_to_project_settings.rb b/db/migrate/20230811144601_add_pages_multiple_versions_enabled_to_project_settings.rb
new file mode 100644
index 00000000000..1da3348621e
--- /dev/null
+++ b/db/migrate/20230811144601_add_pages_multiple_versions_enabled_to_project_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddPagesMultipleVersionsEnabledToProjectSettings < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :project_settings, :pages_multiple_versions_enabled, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20230814181359_add_decompress_archive_file_timeout_to_application_setting.rb b/db/migrate/20230814181359_add_decompress_archive_file_timeout_to_application_setting.rb
new file mode 100644
index 00000000000..f57545424a6
--- /dev/null
+++ b/db/migrate/20230814181359_add_decompress_archive_file_timeout_to_application_setting.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddDecompressArchiveFileTimeoutToApplicationSetting < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def change
+ add_column :application_settings, :decompress_archive_file_timeout, :integer, default: 210, null: false
+ end
+end
diff --git a/db/migrate/20230814203548_add_merged_commit_sha_to_merge_requests.rb b/db/migrate/20230814203548_add_merged_commit_sha_to_merge_requests.rb
new file mode 100644
index 00000000000..4c5d2c5c994
--- /dev/null
+++ b/db/migrate/20230814203548_add_merged_commit_sha_to_merge_requests.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddMergedCommitShaToMergeRequests < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ add_column :merge_requests, :merged_commit_sha, :bytea unless column_exists?(:merge_requests, :merged_commit_sha)
+ end
+ end
+
+ def down
+ with_lock_retries do
+ remove_column :merge_requests, :merged_commit_sha if column_exists?(:merge_requests, :merged_commit_sha)
+ end
+ end
+end
diff --git a/db/migrate/20230815072912_add_hashes_to_credit_card_validations.rb b/db/migrate/20230815072912_add_hashes_to_credit_card_validations.rb
new file mode 100644
index 00000000000..46d14d64ad1
--- /dev/null
+++ b/db/migrate/20230815072912_add_hashes_to_credit_card_validations.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class AddHashesToCreditCardValidations < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ add_column :user_credit_card_validations, :last_digits_hash, :text, if_not_exists: true
+ add_column :user_credit_card_validations, :holder_name_hash, :text, if_not_exists: true
+ add_column :user_credit_card_validations, :expiration_date_hash, :text, if_not_exists: true
+ add_column :user_credit_card_validations, :network_hash, :text, if_not_exists: true
+ end
+
+ add_text_limit :user_credit_card_validations, :last_digits_hash, 44
+ add_text_limit :user_credit_card_validations, :holder_name_hash, 44
+ add_text_limit :user_credit_card_validations, :expiration_date_hash, 44
+ add_text_limit :user_credit_card_validations, :network_hash, 44
+ end
+
+ def down
+ with_lock_retries do
+ remove_column :user_credit_card_validations, :last_digits_hash, if_exists: true
+ remove_column :user_credit_card_validations, :holder_name_hash, if_exists: true
+ remove_column :user_credit_card_validations, :expiration_date_hash, if_exists: true
+ remove_column :user_credit_card_validations, :network_hash, if_exists: true
+ end
+ end
+end
diff --git a/db/migrate/20230816210052_add_licenses_to_sbom_occurrences.rb b/db/migrate/20230816210052_add_licenses_to_sbom_occurrences.rb
new file mode 100644
index 00000000000..e6c7dac4a78
--- /dev/null
+++ b/db/migrate/20230816210052_add_licenses_to_sbom_occurrences.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddLicensesToSbomOccurrences < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :sbom_occurrences, :licenses, :jsonb, default: []
+ end
+end
diff --git a/db/migrate/20230817040352_init_bigint_conversion_for_shared_runners_duration.rb b/db/migrate/20230817040352_init_bigint_conversion_for_shared_runners_duration.rb
new file mode 100644
index 00000000000..c941cf583fb
--- /dev/null
+++ b/db/migrate/20230817040352_init_bigint_conversion_for_shared_runners_duration.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class InitBigintConversionForSharedRunnersDuration < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ TABLE_NAMES = %i[ci_project_monthly_usages ci_namespace_monthly_usages]
+ COLUMN_NAMES = %i[shared_runners_duration]
+
+ def up
+ TABLE_NAMES.each do |table_name|
+ initialize_conversion_of_integer_to_bigint table_name, COLUMN_NAMES
+ end
+ end
+
+ def down
+ TABLE_NAMES.each do |table_name|
+ revert_initialize_conversion_of_integer_to_bigint table_name, COLUMN_NAMES
+ end
+ end
+end
diff --git a/db/migrate/20230821000001_create_workspace_variables.rb b/db/migrate/20230821000001_create_workspace_variables.rb
new file mode 100644
index 00000000000..fd23b48c3c3
--- /dev/null
+++ b/db/migrate/20230821000001_create_workspace_variables.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class CreateWorkspaceVariables < Gitlab::Database::Migration[2.1]
+ def change
+ create_table :workspace_variables do |t|
+ t.references :workspace, index: true, null: false, foreign_key: { on_delete: :cascade }
+ t.integer :variable_type, null: false, limit: 2
+ t.timestamps_with_timezone null: false
+ t.text :key, null: false, limit: 255
+ t.binary :encrypted_value, null: false
+ t.binary :encrypted_value_iv, null: false
+ end
+ end
+end
diff --git a/db/migrate/20230821000002_add_personal_access_token_id_to_workspaces.rb b/db/migrate/20230821000002_add_personal_access_token_id_to_workspaces.rb
new file mode 100644
index 00000000000..8b4d5f25959
--- /dev/null
+++ b/db/migrate/20230821000002_add_personal_access_token_id_to_workspaces.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class AddPersonalAccessTokenIdToWorkspaces < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = "index_workspaces_on_personal_access_token_id"
+
+ def up
+ with_lock_retries do
+ add_column :workspaces, :personal_access_token_id, :bigint
+ end
+
+ add_concurrent_index :workspaces, :personal_access_token_id, name: INDEX_NAME
+
+ # Personal Access Tokens are revokable and are soft deleted, so the record should never actually be deleted.
+ # Therefore, `restrict` is the appropriate choice, because if a record ever is attempted to be deleted
+ # outside of Rails, this should be prevented, because `nullify` would result in an invalid state for the workspace,
+ # and `cascade` would delete the workspace.
+ add_concurrent_foreign_key :workspaces,
+ :personal_access_tokens,
+ column: :personal_access_token_id,
+ on_delete: :restrict
+ end
+
+ def down
+ remove_concurrent_index_by_name :workspaces, INDEX_NAME
+ remove_foreign_key_if_exists :workspaces, column: :personal_access_tokens
+
+ with_lock_retries do
+ remove_column :workspaces, :personal_access_token_id, if_exists: true
+ end
+ end
+end
diff --git a/db/migrate/20230821000003_add_config_version_to_workspaces.rb b/db/migrate/20230821000003_add_config_version_to_workspaces.rb
new file mode 100644
index 00000000000..c9ddf53c785
--- /dev/null
+++ b/db/migrate/20230821000003_add_config_version_to_workspaces.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddConfigVersionToWorkspaces < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :workspaces, :config_version, :integer, default: 1, null: false
+ end
+end
diff --git a/db/migrate/20230821081508_add_mr_requires_saml_auth_for_approval_to_group_mr_approval_settings.rb b/db/migrate/20230821081508_add_mr_requires_saml_auth_for_approval_to_group_mr_approval_settings.rb
new file mode 100644
index 00000000000..b056ab02868
--- /dev/null
+++ b/db/migrate/20230821081508_add_mr_requires_saml_auth_for_approval_to_group_mr_approval_settings.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddMrRequiresSamlAuthForApprovalToGroupMrApprovalSettings < Gitlab::Database::Migration[2.1]
+ def change
+ add_column(
+ :group_merge_request_approval_settings,
+ :require_saml_auth_to_approve,
+ :boolean,
+ default: false,
+ null: false
+ )
+ end
+end
diff --git a/db/migrate/20230821101010_remove_crl_null.rb b/db/migrate/20230821101010_remove_crl_null.rb
new file mode 100644
index 00000000000..16fa512a65a
--- /dev/null
+++ b/db/migrate/20230821101010_remove_crl_null.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class RemoveCrlNull < Gitlab::Database::Migration[2.1]
+ def up
+ change_column_null :x509_certificates, :subject, true
+ change_column_null :x509_issuers, :subject, true
+ change_column_null :x509_issuers, :crl_url, true
+ end
+
+ def down
+ change_column_null :x509_certificates, :subject, false
+ change_column_null :x509_issuers, :subject, false
+ change_column_null :x509_issuers, :crl_url, false
+ end
+end
diff --git a/db/migrate/20230821133549_create_packages_nuget_symbols.rb b/db/migrate/20230821133549_create_packages_nuget_symbols.rb
new file mode 100644
index 00000000000..1ff43cdd93f
--- /dev/null
+++ b/db/migrate/20230821133549_create_packages_nuget_symbols.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class CreatePackagesNugetSymbols < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ create_table :packages_nuget_symbols do |t|
+ t.timestamps_with_timezone null: false
+
+ t.references :package,
+ foreign_key: { to_table: :packages_packages, on_delete: :nullify },
+ index: true,
+ type: :bigint
+ t.integer :size, null: false
+ t.integer :file_store, default: 1, limit: 2
+ t.text :file, null: false, limit: 255
+ t.text :file_path, null: false, limit: 255
+ t.text :signature, null: false, limit: 255
+ t.text :object_storage_key, null: false, limit: 255, index: { unique: true }
+
+ t.index [:signature, :file_path], unique: true
+ end
+ end
+end
diff --git a/db/migrate/20230822064649_add_organization_id_to_project.rb b/db/migrate/20230822064649_add_organization_id_to_project.rb
new file mode 100644
index 00000000000..9607f711981
--- /dev/null
+++ b/db/migrate/20230822064649_add_organization_id_to_project.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddOrganizationIdToProject < Gitlab::Database::Migration[2.1]
+ DEFAULT_ORGANIZATION_ID = 1
+
+ enable_lock_retries!
+
+ def change
+ add_column :projects, :organization_id, :bigint, default: DEFAULT_ORGANIZATION_ID, null: true # rubocop:disable Migration/AddColumnsToWideTables
+ end
+end
diff --git a/db/migrate/20230822151454_remove_free_user_cap_email_workers.rb b/db/migrate/20230822151454_remove_free_user_cap_email_workers.rb
new file mode 100644
index 00000000000..6baba8822ab
--- /dev/null
+++ b/db/migrate/20230822151454_remove_free_user_cap_email_workers.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RemoveFreeUserCapEmailWorkers < Gitlab::Database::Migration[2.1]
+ DEPRECATED_JOB_CLASSES = %w[
+ Namespaces::FreeUserCap::BackfillNotificationClearingJobsWorker
+ Namespaces::FreeUserCap::BackfillNotificationJobsWorker
+ Namespaces::FreeUserCap::NotificationClearingWorker
+ Namespaces::FreeUserCap::OverLimitNotificationWorker
+ ]
+ disable_ddl_transaction!
+ def up
+ sidekiq_remove_jobs(job_klasses: DEPRECATED_JOB_CLASSES)
+ end
+
+ def down
+ # This migration removes any instances of deprecated workers and cannot be undone.
+ end
+end
diff --git a/db/migrate/20230822175304_add_okr_reminder_fields_to_work_item_progresses.rb b/db/migrate/20230822175304_add_okr_reminder_fields_to_work_item_progresses.rb
new file mode 100644
index 00000000000..7ca2e690521
--- /dev/null
+++ b/db/migrate/20230822175304_add_okr_reminder_fields_to_work_item_progresses.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddOkrReminderFieldsToWorkItemProgresses < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :work_item_progresses, :reminder_frequency, :integer, limit: 2, null: false, default: 0
+ end
+end
diff --git a/db/migrate/20230823132142_create_instance_google_cloud_logging_configurations.rb b/db/migrate/20230823132142_create_instance_google_cloud_logging_configurations.rb
new file mode 100644
index 00000000000..c659264038d
--- /dev/null
+++ b/db/migrate/20230823132142_create_instance_google_cloud_logging_configurations.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class CreateInstanceGoogleCloudLoggingConfigurations < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ UNIQUE_INDEX_NAME = "unique_instance_google_cloud_logging_configurations"
+ UNIQUE_CONFIG_NAME_INDEX = "unique_instance_google_cloud_logging_configurations_name"
+
+ def change
+ create_table :audit_events_instance_google_cloud_logging_configurations do |t|
+ t.timestamps_with_timezone null: false
+ t.text :google_project_id_name, null: false, limit: 30
+ t.text :client_email, null: false, limit: 254
+ t.text :log_id_name, default: "audit_events", limit: 511
+ t.text :name, null: false, limit: 72
+ t.binary :encrypted_private_key, null: false
+ t.binary :encrypted_private_key_iv, null: false
+
+ t.index [:google_project_id_name, :log_id_name], unique: true, name: UNIQUE_INDEX_NAME
+ t.index :name, unique: true, name: UNIQUE_CONFIG_NAME_INDEX
+ end
+ end
+end
diff --git a/db/migrate/20230823174108_add_patch_id_sha_on_approvals.rb b/db/migrate/20230823174108_add_patch_id_sha_on_approvals.rb
new file mode 100644
index 00000000000..ef68b66d2e8
--- /dev/null
+++ b/db/migrate/20230823174108_add_patch_id_sha_on_approvals.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddPatchIdShaOnApprovals < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ add_column :approvals, :patch_id_sha, :binary
+ end
+
+ def down
+ remove_column :approvals, :patch_id_sha
+ end
+end
diff --git a/db/migrate/20230824015840_add_finding_id_to_vulnerabilities.rb b/db/migrate/20230824015840_add_finding_id_to_vulnerabilities.rb
new file mode 100644
index 00000000000..a8a8e8c8757
--- /dev/null
+++ b/db/migrate/20230824015840_add_finding_id_to_vulnerabilities.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddFindingIdToVulnerabilities < Gitlab::Database::Migration[2.1]
+ def up
+ add_column :vulnerabilities, :finding_id, :bigint, if_not_exists: true
+ end
+
+ def down
+ remove_column :vulnerabilities, :finding_id
+ end
+end
diff --git a/db/migrate/20230824022229_make_finding_id_on_vulnerabilities_invalid_foreign_key.rb b/db/migrate/20230824022229_make_finding_id_on_vulnerabilities_invalid_foreign_key.rb
new file mode 100644
index 00000000000..e6ac5ea95ab
--- /dev/null
+++ b/db/migrate/20230824022229_make_finding_id_on_vulnerabilities_invalid_foreign_key.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class MakeFindingIdOnVulnerabilitiesInvalidForeignKey < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :vulnerabilities, :vulnerability_occurrences,
+ column: :finding_id, on_delete: :cascade, validate: false
+ end
+
+ def down
+ remove_foreign_key_if_exists :vulnerabilities, column: :finding_id
+ end
+end
diff --git a/db/migrate/20230828153646_extend_push_rules_regex_limits.rb b/db/migrate/20230828153646_extend_push_rules_regex_limits.rb
new file mode 100644
index 00000000000..ba5e8e54f9f
--- /dev/null
+++ b/db/migrate/20230828153646_extend_push_rules_regex_limits.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+class ExtendPushRulesRegexLimits < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ REGEX_COLUMNS = %i[
+ force_push_regex
+ delete_branch_regex
+ commit_message_regex
+ author_email_regex
+ file_name_regex
+ branch_name_regex
+ ].freeze
+
+ LONG_REGEX_COLUMNS = %i[commit_message_negative_regex]
+
+ def up
+ REGEX_COLUMNS.each do |column_name|
+ add_check_constraint :push_rules, "char_length(#{column_name}) <= 511", "#{column_name}_size_constraint",
+ validate: false
+ end
+
+ LONG_REGEX_COLUMNS.each do |column_name|
+ add_check_constraint :push_rules, "char_length(#{column_name}) <= 2047", "#{column_name}_size_constraint",
+ validate: false
+ end
+ end
+
+ def down
+ REGEX_COLUMNS.each do |column_name|
+ remove_check_constraint :push_rules, "#{column_name}_size_constraint"
+ end
+
+ LONG_REGEX_COLUMNS.each do |column_name|
+ remove_check_constraint :push_rules, "#{column_name}_size_constraint"
+ end
+ end
+end
diff --git a/db/migrate/20230829045459_add_search_rate_limit_allowlist_to_application_settings.rb b/db/migrate/20230829045459_add_search_rate_limit_allowlist_to_application_settings.rb
new file mode 100644
index 00000000000..135f2d7ff10
--- /dev/null
+++ b/db/migrate/20230829045459_add_search_rate_limit_allowlist_to_application_settings.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddSearchRateLimitAllowlistToApplicationSettings < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :application_settings, :search_rate_limit_allowlist, :text, array: true, default: [], null: false
+ end
+end
diff --git a/db/migrate/20230830084959_validate_push_rules_constraints.rb b/db/migrate/20230830084959_validate_push_rules_constraints.rb
new file mode 100644
index 00000000000..99b5d680642
--- /dev/null
+++ b/db/migrate/20230830084959_validate_push_rules_constraints.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class ValidatePushRulesConstraints < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ REGEX_COLUMNS = %i[
+ force_push_regex
+ delete_branch_regex
+ commit_message_regex
+ commit_message_negative_regex
+ author_email_regex
+ file_name_regex
+ branch_name_regex
+ ].freeze
+
+ def up
+ REGEX_COLUMNS.each do |column_name|
+ validate_check_constraint :push_rules, "#{column_name}_size_constraint"
+ end
+ end
+
+ def down
+ # No op
+ end
+end
diff --git a/db/migrate/20230830085501_remove_push_rules_regex_limits.rb b/db/migrate/20230830085501_remove_push_rules_regex_limits.rb
new file mode 100644
index 00000000000..31d85e3ec11
--- /dev/null
+++ b/db/migrate/20230830085501_remove_push_rules_regex_limits.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class RemovePushRulesRegexLimits < Gitlab::Database::Migration[2.1]
+ def up
+ change_column :push_rules, :force_push_regex, :string, limit: nil
+ change_column :push_rules, :delete_branch_regex, :string, limit: nil
+ change_column :push_rules, :commit_message_regex, :string, limit: nil
+ change_column :push_rules, :commit_message_negative_regex, :string, limit: nil
+ change_column :push_rules, :author_email_regex, :string, limit: nil
+ change_column :push_rules, :file_name_regex, :string, limit: nil
+ change_column :push_rules, :branch_name_regex, :string, limit: nil
+ end
+
+ def down
+ # No op
+ end
+end
diff --git a/db/migrate/20230831111051_add_approval_settings_to_scan_result_policies.rb b/db/migrate/20230831111051_add_approval_settings_to_scan_result_policies.rb
new file mode 100644
index 00000000000..3bd3f58c2dd
--- /dev/null
+++ b/db/migrate/20230831111051_add_approval_settings_to_scan_result_policies.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddApprovalSettingsToScanResultPolicies < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :scan_result_policies, :project_approval_settings, :jsonb, default: {}, null: false
+ add_column :scan_result_policies, :commits, :smallint
+ end
+end
diff --git a/db/migrate/20230901170145_update_vulnerability_reads_trigger_to_set_has_merge_request.rb b/db/migrate/20230901170145_update_vulnerability_reads_trigger_to_set_has_merge_request.rb
new file mode 100644
index 00000000000..7b5a4645f85
--- /dev/null
+++ b/db/migrate/20230901170145_update_vulnerability_reads_trigger_to_set_has_merge_request.rb
@@ -0,0 +1,211 @@
+# frozen_string_literal: true
+
+class UpdateVulnerabilityReadsTriggerToSetHasMergeRequest < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ execute(<<~SQL)
+ CREATE OR REPLACE FUNCTION insert_or_update_vulnerability_reads()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+ DECLARE
+ severity smallint;
+ state smallint;
+ report_type smallint;
+ resolved_on_default_branch boolean;
+ present_on_default_branch boolean;
+ namespace_id bigint;
+ has_issues boolean;
+ has_merge_request boolean;
+ BEGIN
+ IF (NEW.vulnerability_id IS NULL AND (TG_OP = 'INSERT' OR TG_OP = 'UPDATE')) THEN
+ RETURN NULL;
+ END IF;
+
+ IF (TG_OP = 'UPDATE' AND OLD.vulnerability_id IS NOT NULL AND NEW.vulnerability_id IS NOT NULL) THEN
+ RETURN NULL;
+ END IF;
+
+ SELECT
+ vulnerabilities.severity, vulnerabilities.state, vulnerabilities.report_type, vulnerabilities.resolved_on_default_branch, vulnerabilities.present_on_default_branch
+ INTO
+ severity, state, report_type, resolved_on_default_branch, present_on_default_branch
+ FROM
+ vulnerabilities
+ WHERE
+ vulnerabilities.id = NEW.vulnerability_id;
+
+ IF present_on_default_branch IS NOT true THEN
+ RETURN NULL;
+ END IF;
+
+ SELECT
+ projects.namespace_id
+ INTO
+ namespace_id
+ FROM
+ projects
+ WHERE
+ projects.id = NEW.project_id;
+
+ SELECT
+ EXISTS (SELECT 1 FROM vulnerability_issue_links WHERE vulnerability_issue_links.vulnerability_id = NEW.vulnerability_id)
+ INTO
+ has_issues;
+
+ SELECT
+ EXISTS (SELECT 1 FROM vulnerability_merge_request_links WHERE vulnerability_merge_request_links.vulnerability_id = NEW.vulnerability_id)
+ INTO
+ has_merge_request;
+
+ INSERT INTO vulnerability_reads (vulnerability_id, namespace_id, project_id, scanner_id, report_type, severity, state, resolved_on_default_branch, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues, has_merge_request)
+ VALUES (NEW.vulnerability_id, namespace_id, NEW.project_id, NEW.scanner_id, report_type, severity, state, resolved_on_default_branch, NEW.uuid::uuid, NEW.location->>'image', NEW.location->'kubernetes_resource'->>'agent_id', CAST(NEW.location->'kubernetes_resource'->>'agent_id' AS bigint), has_issues, has_merge_request)
+ ON CONFLICT(vulnerability_id) DO NOTHING;
+ RETURN NULL;
+ END
+ $$
+ SQL
+
+ execute(<<~SQL)
+ CREATE OR REPLACE FUNCTION insert_vulnerability_reads_from_vulnerability()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+ DECLARE
+ scanner_id bigint;
+ uuid uuid;
+ location_image text;
+ cluster_agent_id text;
+ casted_cluster_agent_id bigint;
+ namespace_id bigint;
+ has_issues boolean;
+ has_merge_request boolean;
+ BEGIN
+ SELECT
+ v_o.scanner_id, v_o.uuid, v_o.location->>'image', v_o.location->'kubernetes_resource'->>'agent_id', CAST(v_o.location->'kubernetes_resource'->>'agent_id' AS bigint), projects.namespace_id
+ INTO
+ scanner_id, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, namespace_id
+ FROM
+ vulnerability_occurrences v_o
+ INNER JOIN projects ON projects.id = v_o.project_id
+ WHERE
+ v_o.vulnerability_id = NEW.id
+ LIMIT 1;
+
+ SELECT
+ EXISTS (SELECT 1 FROM vulnerability_issue_links WHERE vulnerability_issue_links.vulnerability_id = NEW.id)
+ INTO
+ has_issues;
+
+ SELECT
+ EXISTS (SELECT 1 FROM vulnerability_merge_request_links WHERE vulnerability_merge_request_links.vulnerability_id = NEW.id)
+ INTO
+ has_merge_request;
+
+ INSERT INTO vulnerability_reads (vulnerability_id, namespace_id, project_id, scanner_id, report_type, severity, state, resolved_on_default_branch, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues, has_merge_request)
+ VALUES (NEW.id, namespace_id, NEW.project_id, scanner_id, NEW.report_type, NEW.severity, NEW.state, NEW.resolved_on_default_branch, uuid::uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues, has_merge_request)
+ ON CONFLICT(vulnerability_id) DO NOTHING;
+ RETURN NULL;
+ END
+ $$
+ SQL
+ end
+
+ def down
+ execute(<<~SQL)
+ CREATE OR REPLACE FUNCTION insert_or_update_vulnerability_reads()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+ DECLARE
+ severity smallint;
+ state smallint;
+ report_type smallint;
+ resolved_on_default_branch boolean;
+ present_on_default_branch boolean;
+ namespace_id bigint;
+ has_issues boolean;
+ BEGIN
+ IF (NEW.vulnerability_id IS NULL AND (TG_OP = 'INSERT' OR TG_OP = 'UPDATE')) THEN
+ RETURN NULL;
+ END IF;
+
+ IF (TG_OP = 'UPDATE' AND OLD.vulnerability_id IS NOT NULL AND NEW.vulnerability_id IS NOT NULL) THEN
+ RETURN NULL;
+ END IF;
+
+ SELECT
+ vulnerabilities.severity, vulnerabilities.state, vulnerabilities.report_type, vulnerabilities.resolved_on_default_branch, vulnerabilities.present_on_default_branch
+ INTO
+ severity, state, report_type, resolved_on_default_branch, present_on_default_branch
+ FROM
+ vulnerabilities
+ WHERE
+ vulnerabilities.id = NEW.vulnerability_id;
+
+ IF present_on_default_branch IS NOT true THEN
+ RETURN NULL;
+ END IF;
+
+ SELECT
+ projects.namespace_id
+ INTO
+ namespace_id
+ FROM
+ projects
+ WHERE
+ projects.id = NEW.project_id;
+
+ SELECT
+ EXISTS (SELECT 1 FROM vulnerability_issue_links WHERE vulnerability_issue_links.vulnerability_id = NEW.vulnerability_id)
+ INTO
+ has_issues;
+
+ INSERT INTO vulnerability_reads (vulnerability_id, namespace_id, project_id, scanner_id, report_type, severity, state, resolved_on_default_branch, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues)
+ VALUES (NEW.vulnerability_id, namespace_id, NEW.project_id, NEW.scanner_id, report_type, severity, state, resolved_on_default_branch, NEW.uuid::uuid, NEW.location->>'image', NEW.location->'kubernetes_resource'->>'agent_id', CAST(NEW.location->'kubernetes_resource'->>'agent_id' AS bigint), has_issues)
+ ON CONFLICT(vulnerability_id) DO NOTHING;
+ RETURN NULL;
+ END
+ $$
+ SQL
+
+ execute(<<~SQL)
+ CREATE OR REPLACE FUNCTION insert_vulnerability_reads_from_vulnerability()
+ RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+ DECLARE
+ scanner_id bigint;
+ uuid uuid;
+ location_image text;
+ cluster_agent_id text;
+ casted_cluster_agent_id bigint;
+ namespace_id bigint;
+ has_issues boolean;
+ BEGIN
+ SELECT
+ v_o.scanner_id, v_o.uuid, v_o.location->>'image', v_o.location->'kubernetes_resource'->>'agent_id', CAST(v_o.location->'kubernetes_resource'->>'agent_id' AS bigint), projects.namespace_id
+ INTO
+ scanner_id, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, namespace_id
+ FROM
+ vulnerability_occurrences v_o
+ INNER JOIN projects ON projects.id = v_o.project_id
+ WHERE
+ v_o.vulnerability_id = NEW.id
+ LIMIT 1;
+
+ SELECT
+ EXISTS (SELECT 1 FROM vulnerability_issue_links WHERE vulnerability_issue_links.vulnerability_id = NEW.id)
+ INTO
+ has_issues;
+
+ INSERT INTO vulnerability_reads (vulnerability_id, namespace_id, project_id, scanner_id, report_type, severity, state, resolved_on_default_branch, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues)
+ VALUES (NEW.id, namespace_id, NEW.project_id, scanner_id, NEW.report_type, NEW.severity, NEW.state, NEW.resolved_on_default_branch, uuid::uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues)
+ ON CONFLICT(vulnerability_id) DO NOTHING;
+ RETURN NULL;
+ END
+ $$
+ SQL
+ end
+end
diff --git a/db/migrate/20230903170000_create_packages_protection_rules.rb b/db/migrate/20230903170000_create_packages_protection_rules.rb
new file mode 100644
index 00000000000..d5e8a4af558
--- /dev/null
+++ b/db/migrate/20230903170000_create_packages_protection_rules.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class CreatePackagesProtectionRules < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ create_table :packages_protection_rules do |t|
+ t.references :project, null: false, index: false, foreign_key: { on_delete: :cascade }
+ t.timestamps_with_timezone null: false
+ t.integer :push_protected_up_to_access_level, null: false
+ t.integer :package_type, limit: 2, null: false
+ t.text :package_name_pattern, limit: 255, null: false
+
+ t.index [:project_id, :package_type, :package_name_pattern], unique: true,
+ name: :i_packages_unique_project_id_package_type_package_name_pattern
+ end
+ end
+end
diff --git a/db/migrate/20230905040539_add_foreign_key_for_ci_pipeline_chat_data_for_pipeline_id_bigint.rb b/db/migrate/20230905040539_add_foreign_key_for_ci_pipeline_chat_data_for_pipeline_id_bigint.rb
new file mode 100644
index 00000000000..64d304b3727
--- /dev/null
+++ b/db/migrate/20230905040539_add_foreign_key_for_ci_pipeline_chat_data_for_pipeline_id_bigint.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class AddForeignKeyForCiPipelineChatDataForPipelineIdBigint < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_pipeline_chat_data
+ REFERENCING_TABLE_NAME = :ci_pipelines
+ COLUMN_NAME = :pipeline_id_convert_to_bigint
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key(
+ TABLE_NAME, REFERENCING_TABLE_NAME,
+ column: COLUMN_NAME, on_delete: :cascade, reverse_lock_order: true
+ )
+ end
+
+ def down
+ remove_foreign_key_if_exists TABLE_NAME, column: COLUMN_NAME
+ end
+end
diff --git a/db/migrate/20230905061815_add_foreign_key_for_ci_pipeline_messages_pipeline_id_bigint.rb b/db/migrate/20230905061815_add_foreign_key_for_ci_pipeline_messages_pipeline_id_bigint.rb
new file mode 100644
index 00000000000..72ff8399a16
--- /dev/null
+++ b/db/migrate/20230905061815_add_foreign_key_for_ci_pipeline_messages_pipeline_id_bigint.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class AddForeignKeyForCiPipelineMessagesPipelineIdBigint < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_pipeline_messages
+ REFERENCING_TABLE_NAME = :ci_pipelines
+ COLUMN_NAME = :pipeline_id_convert_to_bigint
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key(
+ TABLE_NAME, REFERENCING_TABLE_NAME,
+ column: COLUMN_NAME, on_delete: :cascade, validate: false, reverse_lock_order: true
+ )
+ end
+
+ def down
+ remove_foreign_key_if_exists TABLE_NAME, column: COLUMN_NAME
+ end
+end
diff --git a/db/migrate/20230905234948_create_projects_visits_tables.rb b/db/migrate/20230905234948_create_projects_visits_tables.rb
new file mode 100644
index 00000000000..b67615b6a22
--- /dev/null
+++ b/db/migrate/20230905234948_create_projects_visits_tables.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class CreateProjectsVisitsTables < Gitlab::Database::Migration[2.1]
+ def up
+ create_table :projects_visits, primary_key: [:id, :visited_at],
+ options: 'PARTITION BY RANGE (visited_at)' do |t|
+ t.bigserial :id, null: false
+ t.bigint :entity_id, null: false, index: true
+ t.bigint :user_id, null: false
+ t.datetime_with_timezone :visited_at, null: false
+ end
+
+ add_index(:projects_visits, [:user_id, :entity_id, :visited_at])
+ end
+
+ def down
+ drop_table :projects_visits
+ end
+end
diff --git a/db/migrate/20230905234949_create_groups_visits_tables.rb b/db/migrate/20230905234949_create_groups_visits_tables.rb
new file mode 100644
index 00000000000..f02e6e64220
--- /dev/null
+++ b/db/migrate/20230905234949_create_groups_visits_tables.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class CreateGroupsVisitsTables < Gitlab::Database::Migration[2.1]
+ def up
+ create_table :groups_visits, primary_key: [:id, :visited_at],
+ options: 'PARTITION BY RANGE (visited_at)' do |t|
+ t.bigserial :id, null: false
+ t.bigint :entity_id, null: false, index: true
+ t.bigint :user_id, null: false
+ t.datetime_with_timezone :visited_at, null: false
+ end
+
+ add_index(:groups_visits, [:user_id, :entity_id, :visited_at])
+ end
+
+ def down
+ drop_table :groups_visits
+ end
+end
diff --git a/db/migrate/20230906072349_create_audit_events_amazon_s3_configurations.rb b/db/migrate/20230906072349_create_audit_events_amazon_s3_configurations.rb
new file mode 100644
index 00000000000..6cdb4a0f0c2
--- /dev/null
+++ b/db/migrate/20230906072349_create_audit_events_amazon_s3_configurations.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class CreateAuditEventsAmazonS3Configurations < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ UNIQUE_NAME = "unique_amazon_s3_configurations_namespace_id_and_name"
+ UNIQUE_BUCKET_NAME = "unique_amazon_s3_configurations_namespace_id_and_bucket_name"
+
+ def change
+ create_table :audit_events_amazon_s3_configurations do |t|
+ t.timestamps_with_timezone null: false
+ t.references :namespace, index: false, null: false, foreign_key: { on_delete: :cascade }
+ t.text :access_key_xid, null: false, limit: 128
+ t.text :name, null: false, limit: 72
+ t.text :bucket_name, null: false, limit: 63
+ t.text :aws_region, null: false, limit: 50
+ t.binary :encrypted_secret_access_key, null: false
+ t.binary :encrypted_secret_access_key_iv, null: false
+
+ t.index [:namespace_id, :name], unique: true, name: UNIQUE_NAME
+ t.index [:namespace_id, :bucket_name], unique: true, name: UNIQUE_BUCKET_NAME
+ end
+ end
+end
diff --git a/db/migrate/20230906100001_add_metadata_columns_to_packages_py_pi_metadata.rb b/db/migrate/20230906100001_add_metadata_columns_to_packages_py_pi_metadata.rb
new file mode 100644
index 00000000000..4cbc0a5bf3e
--- /dev/null
+++ b/db/migrate/20230906100001_add_metadata_columns_to_packages_py_pi_metadata.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+class AddMetadataColumnsToPackagesPyPiMetadata < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ add_column :packages_pypi_metadata, :metadata_version, :text, null: true, if_not_exists: true
+ add_column :packages_pypi_metadata, :summary, :text, null: true, if_not_exists: true
+ add_column :packages_pypi_metadata, :keywords, :text, null: true, if_not_exists: true
+ add_column :packages_pypi_metadata, :author_email, :text, null: true, if_not_exists: true
+ add_column :packages_pypi_metadata, :description, :text, null: true, if_not_exists: true
+ add_column :packages_pypi_metadata, :description_content_type, :text, null: true, if_not_exists: true
+ end
+
+ add_text_limit :packages_pypi_metadata, :metadata_version, 16
+ add_text_limit :packages_pypi_metadata, :summary, 255
+ add_text_limit :packages_pypi_metadata, :keywords, 255
+ add_text_limit :packages_pypi_metadata, :author_email, 2048
+ add_text_limit :packages_pypi_metadata, :description, 4000
+ add_text_limit :packages_pypi_metadata, :description_content_type, 128
+ end
+
+ def down
+ with_lock_retries do
+ remove_column :packages_pypi_metadata, :metadata_version, if_exists: true
+ remove_column :packages_pypi_metadata, :summary, if_exists: true
+ remove_column :packages_pypi_metadata, :keywords, if_exists: true
+ remove_column :packages_pypi_metadata, :author_email, if_exists: true
+ remove_column :packages_pypi_metadata, :description, if_exists: true
+ remove_column :packages_pypi_metadata, :description_content_type, if_exists: true
+ end
+ end
+end
diff --git a/db/migrate/20230906105445_add_audit_events_amazon_s3_configuration_limit_to_plan_limits.rb b/db/migrate/20230906105445_add_audit_events_amazon_s3_configuration_limit_to_plan_limits.rb
new file mode 100644
index 00000000000..4d0a83a9948
--- /dev/null
+++ b/db/migrate/20230906105445_add_audit_events_amazon_s3_configuration_limit_to_plan_limits.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddAuditEventsAmazonS3ConfigurationLimitToPlanLimits < Gitlab::Database::Migration[2.1]
+ def change
+ add_column(:plan_limits, :audit_events_amazon_s3_configurations, :integer, default: 5, null: false)
+ end
+end
diff --git a/db/migrate/20230906175220_replace_sbom_occurrences_component_id_index.rb b/db/migrate/20230906175220_replace_sbom_occurrences_component_id_index.rb
new file mode 100644
index 00000000000..9f377675b80
--- /dev/null
+++ b/db/migrate/20230906175220_replace_sbom_occurrences_component_id_index.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class ReplaceSbomOccurrencesComponentIdIndex < Gitlab::Database::Migration[2.1]
+ REMOVED_INDEX_NAME = "index_sbom_occurrences_on_component_id"
+ ADDED_INDEX_NAME = "index_sbom_occurrences_on_component_id_and_id"
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :sbom_occurrences, %i[component_id id], name: ADDED_INDEX_NAME
+ remove_concurrent_index_by_name :sbom_occurrences, name: REMOVED_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :sbom_occurrences, :component_id, name: REMOVED_INDEX_NAME
+ remove_concurrent_index_by_name :sbom_occurrences, name: ADDED_INDEX_NAME
+ end
+end
diff --git a/db/migrate/20230906185552_add_markdown_fields_to_review_llm_summary.rb b/db/migrate/20230906185552_add_markdown_fields_to_review_llm_summary.rb
new file mode 100644
index 00000000000..6e0c0fa5675
--- /dev/null
+++ b/db/migrate/20230906185552_add_markdown_fields_to_review_llm_summary.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class AddMarkdownFieldsToReviewLlmSummary < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ # rubocop:disable Migration/AddLimitToTextColumns
+ add_column :merge_request_review_llm_summaries,
+ :cached_markdown_version,
+ :integer,
+ null: true
+ add_column :merge_request_review_llm_summaries,
+ :content_html,
+ :text,
+ null: true
+ # rubocop:enable Migration/AddLimitToTextColumns
+ end
+
+ def down
+ remove_column :merge_request_review_llm_summaries, :cached_markdown_version
+ remove_column :merge_request_review_llm_summaries, :content_html
+ end
+end
diff --git a/db/migrate/20230906204934_restart_self_hosted_sent_notifications_bigint_conversion.rb b/db/migrate/20230906204934_restart_self_hosted_sent_notifications_bigint_conversion.rb
new file mode 100644
index 00000000000..8dbeb873bab
--- /dev/null
+++ b/db/migrate/20230906204934_restart_self_hosted_sent_notifications_bigint_conversion.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+class RestartSelfHostedSentNotificationsBigintConversion < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE = :sent_notifications
+ COLUMNS = %i[id]
+
+ def up
+ return if should_skip? || id_is_bigint? || id_convert_to_bigint_exist?
+
+ initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+
+ def down
+ return if should_skip? || id_is_bigint?
+
+ revert_initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+
+ def should_skip?
+ com_or_dev_or_test_but_not_jh?
+ end
+
+ def id_is_bigint?
+ table_columns = columns(TABLE)
+ column_id = table_columns.find { |c| c.name == 'id' }
+ column_id.sql_type == 'bigint'
+ end
+
+ def id_convert_to_bigint_exist?
+ column_exists?(TABLE.to_s, 'id_convert_to_bigint')
+ end
+end
diff --git a/db/migrate/20230906204935_restart_self_hosted_sent_notifications_backfill.rb b/db/migrate/20230906204935_restart_self_hosted_sent_notifications_backfill.rb
new file mode 100644
index 00000000000..21c1798179f
--- /dev/null
+++ b/db/migrate/20230906204935_restart_self_hosted_sent_notifications_backfill.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+class RestartSelfHostedSentNotificationsBackfill < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ TABLE = :sent_notifications
+ COLUMNS = %i[id]
+
+ def up
+ return if should_skip? || id_is_bigint? || already_backfilled?
+
+ # rubocop: disable Migration/BatchMigrationsPostOnly
+ delete_batched_background_migration(
+ 'CopyColumnUsingBackgroundMigrationJob',
+ :sent_notifications,
+ :id,
+ [["id"], ["id_convert_to_bigint"]]
+ )
+ # rubocop: enable Migration/BatchMigrationsPostOnly
+
+ backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+
+ def down
+ return if should_skip? || id_is_bigint? || already_backfilled?
+
+ revert_backfill_conversion_of_integer_to_bigint(TABLE, COLUMNS)
+ end
+
+ def should_skip?
+ com_or_dev_or_test_but_not_jh?
+ end
+
+ def id_is_bigint?
+ table_columns = columns(TABLE)
+ column_id = table_columns.find { |c| c.name == 'id' }
+ column_id.sql_type == 'bigint'
+ end
+
+ def already_backfilled?
+ res = connection.execute <<~SQL
+ SELECT
+ id_convert_to_bigint
+ FROM
+ sent_notifications
+ ORDER BY
+ id ASC
+ LIMIT 1
+ SQL
+ return false if res.ntuples == 0
+
+ res.first['id_convert_to_bigint'].to_i != 0
+ end
+end
diff --git a/db/migrate/20230907162613_add_force_full_reconciliation_to_workspaces.rb b/db/migrate/20230907162613_add_force_full_reconciliation_to_workspaces.rb
new file mode 100644
index 00000000000..bd0b9b9bf69
--- /dev/null
+++ b/db/migrate/20230907162613_add_force_full_reconciliation_to_workspaces.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddForceFullReconciliationToWorkspaces < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :workspaces, :force_full_reconciliation, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20230908155831_add_continuous_vuln_scans_toggle_to_security_project_settings.rb b/db/migrate/20230908155831_add_continuous_vuln_scans_toggle_to_security_project_settings.rb
new file mode 100644
index 00000000000..3411e6b3ef2
--- /dev/null
+++ b/db/migrate/20230908155831_add_continuous_vuln_scans_toggle_to_security_project_settings.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddContinuousVulnScansToggleToSecurityProjectSettings < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+ TABLE_NAME = :project_security_settings
+ COLUMN_NAME = :continuous_vulnerability_scans_enabled
+
+ def up
+ add_column TABLE_NAME, COLUMN_NAME, :boolean, null: false,
+ default: false
+ end
+
+ def down
+ remove_column TABLE_NAME, COLUMN_NAME
+ end
+end
diff --git a/db/migrate/20230911095016_add_root_namespace_id_to_project_statistics.rb b/db/migrate/20230911095016_add_root_namespace_id_to_project_statistics.rb
new file mode 100644
index 00000000000..969aeb9bf9c
--- /dev/null
+++ b/db/migrate/20230911095016_add_root_namespace_id_to_project_statistics.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class AddRootNamespaceIdToProjectStatistics < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = "index_project_statistics_on_root_namespace_id"
+
+ def up
+ unless column_exists?(:project_statistics, :root_namespace_id)
+ add_column :project_statistics, :root_namespace_id, :bigint
+ end
+
+ add_concurrent_foreign_key :project_statistics, :namespaces,
+ column: :root_namespace_id,
+ on_delete: :nullify
+
+ add_concurrent_index :project_statistics, :root_namespace_id, name: INDEX_NAME
+ end
+
+ def down
+ return unless column_exists?(:project_statistics, :root_namespace_id)
+
+ remove_column :project_statistics, :root_namespace_id, :bigint
+ end
+end
diff --git a/db/migrate/20230913171402_add_deleted_at_to_pages_deployments.rb b/db/migrate/20230913171402_add_deleted_at_to_pages_deployments.rb
new file mode 100644
index 00000000000..15716f8fbfb
--- /dev/null
+++ b/db/migrate/20230913171402_add_deleted_at_to_pages_deployments.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddDeletedAtToPagesDeployments < Gitlab::Database::Migration[2.1]
+ def change
+ add_column :pages_deployments, :deleted_at, :datetime_with_timezone, null: true
+ end
+end
diff --git a/db/migrate/20230913171403_add_pages_deployments_deleted_at_index.rb b/db/migrate/20230913171403_add_pages_deployments_deleted_at_index.rb
new file mode 100644
index 00000000000..f519e54265f
--- /dev/null
+++ b/db/migrate/20230913171403_add_pages_deployments_deleted_at_index.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddPagesDeploymentsDeletedAtIndex < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX = 'pages_deployments_deleted_at_index'
+ COLUMNS = [:id, :project_id, :path_prefix]
+
+ def up
+ add_concurrent_index :pages_deployments,
+ COLUMNS,
+ where: 'deleted_at IS NULL',
+ name: INDEX
+ end
+
+ def down
+ remove_concurrent_index :pages_deployments, COLUMNS, name: INDEX
+ end
+end
diff --git a/db/migrate/20230913235822_change_geo_node_statuses_last_event_id_integer_to_big_int.rb b/db/migrate/20230913235822_change_geo_node_statuses_last_event_id_integer_to_big_int.rb
new file mode 100644
index 00000000000..618e6ce6ec9
--- /dev/null
+++ b/db/migrate/20230913235822_change_geo_node_statuses_last_event_id_integer_to_big_int.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class ChangeGeoNodeStatusesLastEventIdIntegerToBigInt < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ execute "ALTER TABLE geo_node_statuses ALTER COLUMN last_event_id TYPE bigint;"
+ end
+
+ execute "ANALYZE geo_node_statuses;"
+ end
+
+ def down
+ with_lock_retries do
+ execute "ALTER TABLE geo_node_statuses ALTER COLUMN last_event_id TYPE integer;"
+ end
+
+ execute "ANALYZE geo_node_statuses;"
+ end
+end
diff --git a/db/migrate/20230914001329_change_geo_node_statuses_cursor_last_event_id_integer_to_big_int.rb b/db/migrate/20230914001329_change_geo_node_statuses_cursor_last_event_id_integer_to_big_int.rb
new file mode 100644
index 00000000000..f36089f746f
--- /dev/null
+++ b/db/migrate/20230914001329_change_geo_node_statuses_cursor_last_event_id_integer_to_big_int.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class ChangeGeoNodeStatusesCursorLastEventIdIntegerToBigInt < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ execute "ALTER TABLE geo_node_statuses ALTER COLUMN cursor_last_event_id TYPE bigint;"
+ end
+
+ execute "ANALYZE geo_node_statuses;"
+ end
+
+ def down
+ with_lock_retries do
+ execute "ALTER TABLE geo_node_statuses ALTER COLUMN cursor_last_event_id TYPE integer;"
+ end
+
+ execute "ANALYZE geo_node_statuses;"
+ end
+end
diff --git a/db/migrate/20230914185814_add_keyboard_shortcuts_toggle_to_user_preferences.rb b/db/migrate/20230914185814_add_keyboard_shortcuts_toggle_to_user_preferences.rb
new file mode 100644
index 00000000000..b7de3f95c7f
--- /dev/null
+++ b/db/migrate/20230914185814_add_keyboard_shortcuts_toggle_to_user_preferences.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddKeyboardShortcutsToggleToUserPreferences < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ add_column :user_preferences, :keyboard_shortcuts_enabled, :boolean, default: true, null: false
+ end
+end
diff --git a/db/migrate/20230918194153_add_merge_immediately_to_ci_cd_settings.rb b/db/migrate/20230918194153_add_merge_immediately_to_ci_cd_settings.rb
new file mode 100644
index 00000000000..eee1ba6f781
--- /dev/null
+++ b/db/migrate/20230918194153_add_merge_immediately_to_ci_cd_settings.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddMergeImmediatelyToCiCdSettings < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ add_column :project_ci_cd_settings, :merge_trains_skip_train_allowed, :boolean, default: false, null: false
+ end
+
+ def down
+ remove_column :project_ci_cd_settings, :merge_trains_skip_train_allowed
+ end
+end
diff --git a/db/post_migrate/20220920124709_backfill_internal_on_notes.rb b/db/post_migrate/20220920124709_backfill_internal_on_notes.rb
deleted file mode 100644
index 0d737195907..00000000000
--- a/db/post_migrate/20220920124709_backfill_internal_on_notes.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-class BackfillInternalOnNotes < Gitlab::Database::Migration[2.0]
- MIGRATION = 'BackfillInternalOnNotes'
- DELAY_INTERVAL = 2.minutes
- TABLE = :notes
- BATCH_SIZE = 2000
- SUB_BATCH_SIZE = 10
-
- restrict_gitlab_migration gitlab_schema: :gitlab_main
-
- def up
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
- end
-
- def down
- delete_batched_background_migration(MIGRATION, TABLE, :id, [])
- end
-end
diff --git a/db/post_migrate/20220920124709_backfill_internal_on_notes_renamed.rb b/db/post_migrate/20220920124709_backfill_internal_on_notes_renamed.rb
new file mode 100644
index 00000000000..a9de69243f6
--- /dev/null
+++ b/db/post_migrate/20220920124709_backfill_internal_on_notes_renamed.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+# Renamed from BackfillInternalOnNotes to BackfillInternalOnNotesRenamed to avoid collision with an Elasticsearch
+# migration from the same name. See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129012
+class BackfillInternalOnNotesRenamed < Gitlab::Database::Migration[2.0]
+ MIGRATION = 'BackfillInternalOnNotes'
+ DELAY_INTERVAL = 2.minutes
+ TABLE = :notes
+ BATCH_SIZE = 2000
+ SUB_BATCH_SIZE = 10
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ TABLE,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, TABLE, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230125093723_rebalance_partition_id_ci_pipeline.rb b/db/post_migrate/20230125093723_rebalance_partition_id_ci_pipeline.rb
index aaea55ce331..c7a7d966911 100644
--- a/db/post_migrate/20230125093723_rebalance_partition_id_ci_pipeline.rb
+++ b/db/post_migrate/20230125093723_rebalance_partition_id_ci_pipeline.rb
@@ -1,30 +1,11 @@
# frozen_string_literal: true
class RebalancePartitionIdCiPipeline < Gitlab::Database::Migration[2.1]
- MIGRATION = 'RebalancePartitionId'
- DELAY_INTERVAL = 2.minutes
- TABLE = :ci_pipelines
- BATCH_SIZE = 2_000
- SUB_BATCH_SIZE = 200
-
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
def up
- return unless Gitlab.com?
-
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
+ # no-op
end
def down
- return unless Gitlab.com?
-
- delete_batched_background_migration(MIGRATION, TABLE, :id, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20230125093840_rebalance_partition_id_ci_build.rb b/db/post_migrate/20230125093840_rebalance_partition_id_ci_build.rb
index 6165c266a82..a4514e958f9 100644
--- a/db/post_migrate/20230125093840_rebalance_partition_id_ci_build.rb
+++ b/db/post_migrate/20230125093840_rebalance_partition_id_ci_build.rb
@@ -1,30 +1,11 @@
# frozen_string_literal: true
class RebalancePartitionIdCiBuild < Gitlab::Database::Migration[2.1]
- MIGRATION = 'RebalancePartitionId'
- DELAY_INTERVAL = 2.minutes.freeze
- TABLE = :ci_builds
- BATCH_SIZE = 5_000
- SUB_BATCH_SIZE = 500
-
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
def up
- return unless Gitlab.com?
-
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
+ # no-op
end
def down
- return unless Gitlab.com?
-
- delete_batched_background_migration(MIGRATION, TABLE, :id, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20230208100917_fix_partition_ids_for_ci_pipeline_variable.rb b/db/post_migrate/20230208100917_fix_partition_ids_for_ci_pipeline_variable.rb
index 9901e6af4ae..8bf1239146c 100644
--- a/db/post_migrate/20230208100917_fix_partition_ids_for_ci_pipeline_variable.rb
+++ b/db/post_migrate/20230208100917_fix_partition_ids_for_ci_pipeline_variable.rb
@@ -1,30 +1,11 @@
# frozen_string_literal: true
class FixPartitionIdsForCiPipelineVariable < Gitlab::Database::Migration[2.1]
- MIGRATION = 'RebalancePartitionId'
- DELAY_INTERVAL = 2.minutes.freeze
- TABLE = :ci_pipeline_variables
- BATCH_SIZE = 2_000
- SUB_BATCH_SIZE = 200
-
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
def up
- return unless Gitlab.com?
-
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
+ # no-op
end
def down
- return unless Gitlab.com?
-
- delete_batched_background_migration(MIGRATION, TABLE, :id, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20230208103009_fix_partition_ids_for_ci_job_artifact.rb b/db/post_migrate/20230208103009_fix_partition_ids_for_ci_job_artifact.rb
index d1b25639638..7c6ff6c3b4f 100644
--- a/db/post_migrate/20230208103009_fix_partition_ids_for_ci_job_artifact.rb
+++ b/db/post_migrate/20230208103009_fix_partition_ids_for_ci_job_artifact.rb
@@ -1,30 +1,11 @@
# frozen_string_literal: true
class FixPartitionIdsForCiJobArtifact < Gitlab::Database::Migration[2.1]
- MIGRATION = 'RebalancePartitionId'
- DELAY_INTERVAL = 2.minutes
- TABLE = :ci_job_artifacts
- BATCH_SIZE = 5_000
- SUB_BATCH_SIZE = 500
-
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
def up
- return unless Gitlab.com?
-
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
+ # no-op
end
def down
- return unless Gitlab.com?
-
- delete_batched_background_migration(MIGRATION, TABLE, :id, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20230208132608_fix_partition_ids_for_ci_stage.rb b/db/post_migrate/20230208132608_fix_partition_ids_for_ci_stage.rb
index c3ec614a37f..f05a53dda5f 100644
--- a/db/post_migrate/20230208132608_fix_partition_ids_for_ci_stage.rb
+++ b/db/post_migrate/20230208132608_fix_partition_ids_for_ci_stage.rb
@@ -1,30 +1,11 @@
# frozen_string_literal: true
class FixPartitionIdsForCiStage < Gitlab::Database::Migration[2.1]
- MIGRATION = 'RebalancePartitionId'
- DELAY_INTERVAL = 2.minutes.freeze
- TABLE = :ci_stages
- BATCH_SIZE = 3_000
- SUB_BATCH_SIZE = 300
-
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
def up
- return unless Gitlab.com?
-
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
+ # no-op
end
def down
- return unless Gitlab.com?
-
- delete_batched_background_migration(MIGRATION, TABLE, :id, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20230209090702_fix_partition_ids_for_ci_build_report_result.rb b/db/post_migrate/20230209090702_fix_partition_ids_for_ci_build_report_result.rb
index d21d986ee31..4ff3d1a2789 100644
--- a/db/post_migrate/20230209090702_fix_partition_ids_for_ci_build_report_result.rb
+++ b/db/post_migrate/20230209090702_fix_partition_ids_for_ci_build_report_result.rb
@@ -1,30 +1,11 @@
# frozen_string_literal: true
class FixPartitionIdsForCiBuildReportResult < Gitlab::Database::Migration[2.1]
- MIGRATION = 'RebalancePartitionId'
- DELAY_INTERVAL = 2.minutes.freeze
- TABLE = :ci_build_report_results
- BATCH_SIZE = 2_000
- SUB_BATCH_SIZE = 200
-
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
def up
- return unless Gitlab.com?
-
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :build_id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
+ # no-op
end
def down
- return unless Gitlab.com?
-
- delete_batched_background_migration(MIGRATION, TABLE, :build_id, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20230209092204_fix_partition_ids_for_ci_build_trace_metadata.rb b/db/post_migrate/20230209092204_fix_partition_ids_for_ci_build_trace_metadata.rb
index 25087dcbfa4..f682527a296 100644
--- a/db/post_migrate/20230209092204_fix_partition_ids_for_ci_build_trace_metadata.rb
+++ b/db/post_migrate/20230209092204_fix_partition_ids_for_ci_build_trace_metadata.rb
@@ -1,30 +1,11 @@
# frozen_string_literal: true
class FixPartitionIdsForCiBuildTraceMetadata < Gitlab::Database::Migration[2.1]
- MIGRATION = 'RebalancePartitionId'
- DELAY_INTERVAL = 2.minutes.freeze
- TABLE = :ci_build_trace_metadata
- BATCH_SIZE = 3_000
- SUB_BATCH_SIZE = 300
-
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
def up
- return unless Gitlab.com?
-
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :build_id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
+ # no-op
end
def down
- return unless Gitlab.com?
-
- delete_batched_background_migration(MIGRATION, TABLE, :build_id, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20230209140102_fix_partition_ids_for_ci_build_metadata.rb b/db/post_migrate/20230209140102_fix_partition_ids_for_ci_build_metadata.rb
index 07fcbcc3ad7..785db1be079 100644
--- a/db/post_migrate/20230209140102_fix_partition_ids_for_ci_build_metadata.rb
+++ b/db/post_migrate/20230209140102_fix_partition_ids_for_ci_build_metadata.rb
@@ -1,30 +1,11 @@
# frozen_string_literal: true
class FixPartitionIdsForCiBuildMetadata < Gitlab::Database::Migration[2.1]
- MIGRATION = 'RebalancePartitionId'
- DELAY_INTERVAL = 2.minutes
- TABLE = :p_ci_builds_metadata
- BATCH_SIZE = 5_000
- SUB_BATCH_SIZE = 500
-
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
def up
- return unless Gitlab.com?
-
- queue_batched_background_migration(
- MIGRATION,
- TABLE,
- :id,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE
- )
+ # no-op
end
def down
- return unless Gitlab.com?
-
- delete_batched_background_migration(MIGRATION, TABLE, :id, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20230214122717_fix_partition_ids_for_ci_job_variables.rb b/db/post_migrate/20230214122717_fix_partition_ids_for_ci_job_variables.rb
index 0a201c51467..64f5bc4bb5e 100644
--- a/db/post_migrate/20230214122717_fix_partition_ids_for_ci_job_variables.rb
+++ b/db/post_migrate/20230214122717_fix_partition_ids_for_ci_job_variables.rb
@@ -1,20 +1,8 @@
# frozen_string_literal: true
class FixPartitionIdsForCiJobVariables < Gitlab::Database::Migration[2.1]
- disable_ddl_transaction!
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
- BATCH_SIZE = 50
-
def up
- return unless Gitlab.com?
-
- define_batchable_model(:ci_job_variables)
- .where(partition_id: 101)
- .each_batch(of: BATCH_SIZE) do |batch|
- batch.update_all(partition_id: 100)
- sleep 0.1
- end
+ # no-op
end
def down
diff --git a/db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb b/db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb
index c05b759c2d0..bbacd13389b 100644
--- a/db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb
+++ b/db/post_migrate/20230214154101_fix_partition_ids_on_ci_sources_pipelines.rb
@@ -1,36 +1,11 @@
# frozen_string_literal: true
class FixPartitionIdsOnCiSourcesPipelines < Gitlab::Database::Migration[2.1]
- disable_ddl_transaction!
- restrict_gitlab_migration gitlab_schema: :gitlab_ci
-
- BATCH_SIZE = 50
-
def up
- return unless Gitlab.com?
-
- model = define_batchable_model(:ci_sources_pipelines)
-
- batch_update_records(model, :partition_id, from: 101, to: 100, source_partition_id: 100)
- batch_update_records(model, :source_partition_id, from: 101, to: 100)
+ # no-op
end
def down
# no-op
end
-
- private
-
- def batch_update_records(model, column, from:, to:, **updates)
- updates.reverse_merge!(column => to)
-
- model
- .where(model.arel_table[column].eq(from))
- .each_batch(of: BATCH_SIZE) { |batch| update_records(batch, updates) }
- end
-
- def update_records(relation, updates)
- relation.update_all(updates)
- sleep 0.1
- end
end
diff --git a/db/post_migrate/20230703024031_cleanup_project_pipeline_status_key.rb b/db/post_migrate/20230703024031_cleanup_project_pipeline_status_key.rb
index cb7fc04166f..a5a78dcbbd1 100644
--- a/db/post_migrate/20230703024031_cleanup_project_pipeline_status_key.rb
+++ b/db/post_migrate/20230703024031_cleanup_project_pipeline_status_key.rb
@@ -3,6 +3,9 @@
class CleanupProjectPipelineStatusKey < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
+ # TODO: to remove after feature-flag in duplicate-jobs client middleware is removed
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
MIGRATION_WORKER_CLASS = 'BackfillProjectPipelineStatusTtl'
def up
diff --git a/db/post_migrate/20230802212443_add_current_user_todos_widget_to_epic_work_item_type.rb b/db/post_migrate/20230802212443_add_current_user_todos_widget_to_epic_work_item_type.rb
new file mode 100644
index 00000000000..958a5d6edb9
--- /dev/null
+++ b/db/post_migrate/20230802212443_add_current_user_todos_widget_to_epic_work_item_type.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+class AddCurrentUserTodosWidgetToEpicWorkItemType < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ EPIC_ENUM_VALUE = 7
+ WIDGET_NAME = 'Current user todos'
+ WIDGET_ENUM_VALUE = 15
+
+ class MigrationWorkItemType < MigrationRecord
+ self.table_name = 'work_item_types'
+ end
+
+ class MigrationWidgetDefinition < MigrationRecord
+ self.table_name = 'work_item_widget_definitions'
+ end
+
+ def up
+ epic_work_item_type = MigrationWorkItemType.find_by(base_type: EPIC_ENUM_VALUE, namespace_id: nil)
+
+ # Epic type should exist in production applications, checking here to avoid failures
+ # if inconsistent data is present.
+ return say('Epic work item type does not exist, skipping widget creation') unless epic_work_item_type
+
+ widgets = [
+ {
+ work_item_type_id: epic_work_item_type.id,
+ name: WIDGET_NAME,
+ widget_type: WIDGET_ENUM_VALUE
+ }
+ ]
+
+ MigrationWidgetDefinition.upsert_all(
+ widgets,
+ unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
+ )
+ end
+
+ def down
+ epic_work_item_type = MigrationWorkItemType.find_by(base_type: EPIC_ENUM_VALUE, namespace_id: nil)
+
+ return say('Epic work item type does not exist, skipping widget removal') unless epic_work_item_type
+
+ widget_definition = MigrationWidgetDefinition.find_by(
+ work_item_type_id: epic_work_item_type.id,
+ widget_type: WIDGET_ENUM_VALUE,
+ name: WIDGET_NAME,
+ namespace_id: nil
+ )
+
+ return say('Widget definition not found, skipping widget removal') unless widget_definition
+
+ widget_definition.destroy
+ end
+end
diff --git a/db/post_migrate/20230804122825_add_unique_index_on_uuid_convert_string_to_uuid.rb b/db/post_migrate/20230804122825_add_unique_index_on_uuid_convert_string_to_uuid.rb
new file mode 100644
index 00000000000..ac94bca4de4
--- /dev/null
+++ b/db/post_migrate/20230804122825_add_unique_index_on_uuid_convert_string_to_uuid.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class AddUniqueIndexOnUuidConvertStringToUuid < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = "index_vulnerability_occurrences_on_uuid_1"
+
+ def up
+ add_concurrent_index(
+ :vulnerability_occurrences,
+ :uuid_convert_string_to_uuid,
+ unique: true,
+ name: INDEX_NAME
+ )
+ end
+
+ def down
+ remove_concurrent_index_by_name(
+ :vulnerability_occurrences,
+ INDEX_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230804123252_add_unique_index_on_uuid_convert_string_to_uuid_including_vulnerability_id.rb b/db/post_migrate/20230804123252_add_unique_index_on_uuid_convert_string_to_uuid_including_vulnerability_id.rb
new file mode 100644
index 00000000000..7906ed48db6
--- /dev/null
+++ b/db/post_migrate/20230804123252_add_unique_index_on_uuid_convert_string_to_uuid_including_vulnerability_id.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class AddUniqueIndexOnUuidConvertStringToUuidIncludingVulnerabilityId < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = "index_vuln_findings_on_uuid_including_vuln_id_1"
+
+ def up
+ execute <<~SQL
+ CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS #{INDEX_NAME}
+ ON vulnerability_occurrences(uuid_convert_string_to_uuid)
+ INCLUDE(vulnerability_id)
+ SQL
+ end
+
+ def down
+ remove_concurrent_index_by_name(
+ :vulnerability_occurrences,
+ INDEX_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230808200355_remove_application_settings_dashboard_columns.rb b/db/post_migrate/20230808200355_remove_application_settings_dashboard_columns.rb
new file mode 100644
index 00000000000..41a1074cbcf
--- /dev/null
+++ b/db/post_migrate/20230808200355_remove_application_settings_dashboard_columns.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+class RemoveApplicationSettingsDashboardColumns < Gitlab::Database::Migration[2.1]
+ def change
+ remove_column :application_settings, :dashboard_enforcement_limit, :integer, default: 0, null: false
+ remove_column :application_settings, :dashboard_limit_new_namespace_creation_enforcement_date, :date
+ end
+end
diff --git a/db/post_migrate/20230809170822_ensure_system_note_metadata_bigint_backfill_is_finished_for_self_managed.rb b/db/post_migrate/20230809170822_ensure_system_note_metadata_bigint_backfill_is_finished_for_self_managed.rb
new file mode 100644
index 00000000000..cf157a8b575
--- /dev/null
+++ b/db/post_migrate/20230809170822_ensure_system_note_metadata_bigint_backfill_is_finished_for_self_managed.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class EnsureSystemNoteMetadataBigintBackfillIsFinishedForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'system_note_metadata',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230809174702_swap_system_note_metadata_note_id_to_bigint_for_self_managed.rb b/db/post_migrate/20230809174702_swap_system_note_metadata_note_id_to_bigint_for_self_managed.rb
new file mode 100644
index 00000000000..65aec4dd5d9
--- /dev/null
+++ b/db/post_migrate/20230809174702_swap_system_note_metadata_note_id_to_bigint_for_self_managed.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+class SwapSystemNoteMetadataNoteIdToBigintForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'system_note_metadata'
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :note_id)
+ return if columns_swapped?(TABLE_NAME, :note_id)
+
+ swap
+ end
+
+ def down
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :note_id)
+ return unless columns_swapped?(TABLE_NAME, :note_id)
+
+ swap
+ end
+
+ private
+
+ def swap
+ # This will replace the existing index_system_note_metadata_on_note_id
+ add_concurrent_index TABLE_NAME, :note_id_convert_to_bigint, unique: true,
+ name: 'index_system_note_metadata_on_note_id_convert_to_bigint'
+
+ # This will replace the existing fk_d83a918cb1
+ add_concurrent_foreign_key TABLE_NAME, :notes, column: :note_id_convert_to_bigint,
+ name: 'fk_system_note_metadata_note_id_convert_to_bigint',
+ on_delete: :cascade
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE notes, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id TO note_id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_convert_to_bigint TO note_id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_tmp TO note_id_convert_to_bigint"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:note_id, :note_id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ # Swap defaults
+ change_column_default TABLE_NAME, :note_id, nil
+ change_column_default TABLE_NAME, :note_id_convert_to_bigint, 0
+
+ execute 'DROP INDEX IF EXISTS index_system_note_metadata_on_note_id'
+ rename_index TABLE_NAME, 'index_system_note_metadata_on_note_id_convert_to_bigint',
+ 'index_system_note_metadata_on_note_id'
+
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS fk_d83a918cb1"
+ rename_constraint(TABLE_NAME, 'fk_system_note_metadata_note_id_convert_to_bigint', 'fk_d83a918cb1')
+ end
+ end
+end
diff --git a/db/post_migrate/20230809203254_ensure_issue_user_mentions_bigint_backfill_is_finished_for_self_managed.rb b/db/post_migrate/20230809203254_ensure_issue_user_mentions_bigint_backfill_is_finished_for_self_managed.rb
new file mode 100644
index 00000000000..37d95697f56
--- /dev/null
+++ b/db/post_migrate/20230809203254_ensure_issue_user_mentions_bigint_backfill_is_finished_for_self_managed.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class EnsureIssueUserMentionsBigintBackfillIsFinishedForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'issue_user_mentions',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230809210550_swap_issue_user_mentions_note_id_to_bigint_for_self_managed.rb b/db/post_migrate/20230809210550_swap_issue_user_mentions_note_id_to_bigint_for_self_managed.rb
new file mode 100644
index 00000000000..f0502a2c08a
--- /dev/null
+++ b/db/post_migrate/20230809210550_swap_issue_user_mentions_note_id_to_bigint_for_self_managed.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+class SwapIssueUserMentionsNoteIdToBigintForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'issue_user_mentions'
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :note_id)
+ return if columns_swapped?(TABLE_NAME, :note_id)
+
+ swap
+ end
+
+ def down
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :note_id)
+ return unless columns_swapped?(TABLE_NAME, :note_id)
+
+ swap
+ end
+
+ def swap
+ # This will replace the existing index_issue_user_mentions_on_note_id
+ add_concurrent_index TABLE_NAME, :note_id_convert_to_bigint, unique: true,
+ name: 'index_issue_user_mentions_on_note_id_convert_to_bigint',
+ where: 'note_id_convert_to_bigint IS NOT NULL'
+
+ # This will replace the existing issue_user_mentions_on_issue_id_and_note_id_index
+ add_concurrent_index TABLE_NAME, [:issue_id, :note_id_convert_to_bigint], unique: true,
+ name: 'tmp_issue_user_mentions_on_issue_id_and_note_id_index'
+
+ # This will replace the existing issue_user_mentions_on_issue_id_index
+ add_concurrent_index TABLE_NAME, :issue_id, unique: true,
+ name: 'tmp_issue_user_mentions_on_issue_id_index',
+ where: 'note_id_convert_to_bigint IS NULL'
+
+ # This will replace the existing fk_rails_3861d9fefa
+ add_concurrent_foreign_key TABLE_NAME, :notes, column: :note_id_convert_to_bigint,
+ name: 'fk_issue_user_mentions_note_id_convert_to_bigint',
+ on_delete: :cascade
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE notes, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id TO note_id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_convert_to_bigint TO note_id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_tmp TO note_id_convert_to_bigint"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:note_id, :note_id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ execute 'DROP INDEX IF EXISTS index_issue_user_mentions_on_note_id'
+ rename_index TABLE_NAME, 'index_issue_user_mentions_on_note_id_convert_to_bigint',
+ 'index_issue_user_mentions_on_note_id'
+
+ execute 'DROP INDEX IF EXISTS issue_user_mentions_on_issue_id_and_note_id_index'
+ rename_index TABLE_NAME, 'tmp_issue_user_mentions_on_issue_id_and_note_id_index',
+ 'issue_user_mentions_on_issue_id_and_note_id_index'
+
+ execute 'DROP INDEX IF EXISTS issue_user_mentions_on_issue_id_index'
+ rename_index TABLE_NAME, 'tmp_issue_user_mentions_on_issue_id_index',
+ 'issue_user_mentions_on_issue_id_index'
+
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS fk_rails_3861d9fefa"
+ rename_constraint(TABLE_NAME, 'fk_issue_user_mentions_note_id_convert_to_bigint', 'fk_rails_3861d9fefa')
+ end
+ end
+end
diff --git a/db/post_migrate/20230810112715_ensure_note_diff_files_bigint_backfill_is_finished_for_self_hosts.rb b/db/post_migrate/20230810112715_ensure_note_diff_files_bigint_backfill_is_finished_for_self_hosts.rb
new file mode 100644
index 00000000000..f6be8be3008
--- /dev/null
+++ b/db/post_migrate/20230810112715_ensure_note_diff_files_bigint_backfill_is_finished_for_self_hosts.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class EnsureNoteDiffFilesBigintBackfillIsFinishedForSelfHosts < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'note_diff_files',
+ column_name: 'id',
+ job_arguments: [['diff_note_id'], ['diff_note_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230810113227_swap_note_diff_files_note_id_to_bigint_for_self_hosts.rb b/db/post_migrate/20230810113227_swap_note_diff_files_note_id_to_bigint_for_self_hosts.rb
new file mode 100644
index 00000000000..682996234d6
--- /dev/null
+++ b/db/post_migrate/20230810113227_swap_note_diff_files_note_id_to_bigint_for_self_hosts.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+class SwapNoteDiffFilesNoteIdToBigintForSelfHosts < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'note_diff_files'
+
+ def up
+ return if should_skip?
+ return if temp_column_removed?(TABLE_NAME, :diff_note_id)
+ return if columns_swapped?(TABLE_NAME, :diff_note_id)
+
+ swap
+ end
+
+ def down
+ return if should_skip?
+ return if temp_column_removed?(TABLE_NAME, :diff_note_id)
+ return unless columns_swapped?(TABLE_NAME, :diff_note_id)
+
+ swap
+ end
+
+ def swap
+ # This will replace the existing index_note_diff_files_on_diff_note_id
+ add_concurrent_index TABLE_NAME, :diff_note_id_convert_to_bigint, unique: true,
+ name: 'index_note_diff_files_on_diff_note_id_convert_to_bigint'
+
+ # This will replace the existing fk_rails_3d66047aeb
+ add_concurrent_foreign_key TABLE_NAME, :notes, column: :diff_note_id_convert_to_bigint,
+ name: 'fk_note_diff_files_diff_note_id_convert_to_bigint',
+ on_delete: :cascade
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE notes, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN diff_note_id TO diff_note_id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN diff_note_id_convert_to_bigint TO diff_note_id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN diff_note_id_tmp TO diff_note_id_convert_to_bigint"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:diff_note_id, :diff_note_id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ # Swap defaults
+ change_column_default TABLE_NAME, :diff_note_id, nil
+ change_column_default TABLE_NAME, :diff_note_id_convert_to_bigint, 0
+
+ execute 'DROP INDEX IF EXISTS index_note_diff_files_on_diff_note_id'
+ rename_index TABLE_NAME, 'index_note_diff_files_on_diff_note_id_convert_to_bigint',
+ 'index_note_diff_files_on_diff_note_id'
+
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS fk_rails_3d66047aeb"
+ rename_constraint(TABLE_NAME, 'fk_note_diff_files_diff_note_id_convert_to_bigint', 'fk_rails_3d66047aeb')
+ end
+ end
+
+ def should_skip?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230810124545_schedule_fixing_namespace_ids_of_vulnerability_reads.rb b/db/post_migrate/20230810124545_schedule_fixing_namespace_ids_of_vulnerability_reads.rb
new file mode 100644
index 00000000000..0ff461cc1d1
--- /dev/null
+++ b/db/post_migrate/20230810124545_schedule_fixing_namespace_ids_of_vulnerability_reads.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class ScheduleFixingNamespaceIdsOfVulnerabilityReads < Gitlab::Database::Migration[2.1]
+ MIGRATION = 'FixNamespaceIdsOfVulnerabilityReads'
+
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :vulnerability_reads,
+ :vulnerability_id,
+ job_interval: 2.minutes,
+ batch_size: 10_000,
+ sub_batch_size: 100
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :vulnerability_reads, :vulnerability_id, [])
+ end
+end
diff --git a/db/post_migrate/20230811103457_queue_backfill_nuget_normalized_version.rb b/db/post_migrate/20230811103457_queue_backfill_nuget_normalized_version.rb
new file mode 100644
index 00000000000..52e2b7c36eb
--- /dev/null
+++ b/db/post_migrate/20230811103457_queue_backfill_nuget_normalized_version.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class QueueBackfillNugetNormalizedVersion < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = "BackfillNugetNormalizedVersion"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 6000
+ SUB_BATCH_SIZE = 250
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :packages_nuget_metadata,
+ :package_id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :packages_nuget_metadata, :package_id, [])
+ end
+end
diff --git a/db/post_migrate/20230811185901_remove_application_settings_dashboard_notification_limit_column.rb b/db/post_migrate/20230811185901_remove_application_settings_dashboard_notification_limit_column.rb
new file mode 100644
index 00000000000..cfd112316ee
--- /dev/null
+++ b/db/post_migrate/20230811185901_remove_application_settings_dashboard_notification_limit_column.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class RemoveApplicationSettingsDashboardNotificationLimitColumn < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ remove_column :application_settings, :dashboard_notification_limit, :integer, default: 0, null: false
+ end
+end
diff --git a/db/post_migrate/20230811211544_backfill_alert_management_prometheus_integrations.rb b/db/post_migrate/20230811211544_backfill_alert_management_prometheus_integrations.rb
new file mode 100644
index 00000000000..96d098f2f0a
--- /dev/null
+++ b/db/post_migrate/20230811211544_backfill_alert_management_prometheus_integrations.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+# Migrate Integrations::Prometheus records to 'alert_management_http_integrations',
+# corresponding to Metrics Dashboard removal in 16.0.
+# See https://gitlab.com/gitlab-org/gitlab/-/issues/338838 for more details.
+class BackfillAlertManagementPrometheusIntegrations < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ BATCH_SIZE = 10
+
+ def up
+ each_batch_range(:project_alerting_settings, of: BATCH_SIZE) do |min, max|
+ execute <<~SQL
+ INSERT INTO alert_management_http_integrations (
+ project_id,
+ encrypted_token,
+ encrypted_token_iv,
+ active,
+ name,
+ endpoint_identifier,
+ type_identifier,
+ created_at,
+ updated_at
+ ) SELECT
+ project_alerting_settings.project_id,
+ project_alerting_settings.encrypted_token,
+ project_alerting_settings.encrypted_token_iv,
+ COALESCE(integrations.active, FALSE),
+ 'Prometheus',
+ 'legacy-prometheus',
+ 1, --type_identifiers { http: 0, prometheus: 1 }
+ CURRENT_TIMESTAMP,
+ CURRENT_TIMESTAMP
+ FROM project_alerting_settings
+ LEFT JOIN integrations
+ ON project_alerting_settings.project_id = integrations.project_id
+ AND integrations.type_new = 'Integrations::Prometheus'
+ WHERE project_alerting_settings.project_id BETWEEN #{min} AND #{max}
+ ON CONFLICT DO NOTHING
+ SQL
+ end
+ end
+
+ def down
+ execute <<~SQL
+ DELETE FROM alert_management_http_integrations
+ WHERE type_identifier = 1 --type_identifiers { http: 0, prometheus: 1 }
+ AND endpoint_identifier = 'legacy-prometheus'
+ SQL
+ end
+end
diff --git a/db/post_migrate/20230815140656_queue_populate_denormalized_columns_for_sbom_occurrences.rb b/db/post_migrate/20230815140656_queue_populate_denormalized_columns_for_sbom_occurrences.rb
new file mode 100644
index 00000000000..c27b12c55f0
--- /dev/null
+++ b/db/post_migrate/20230815140656_queue_populate_denormalized_columns_for_sbom_occurrences.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class QueuePopulateDenormalizedColumnsForSbomOccurrences < Gitlab::Database::Migration[2.1]
+ MIGRATION = "PopulateDenormalizedColumnsForSbomOccurrences"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 5_000
+ SUB_BATCH_SIZE = 100
+
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :sbom_occurrences,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :sbom_occurrences, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230815160428_rename_plans_titles_with_legacy_plan_names.rb b/db/post_migrate/20230815160428_rename_plans_titles_with_legacy_plan_names.rb
new file mode 100644
index 00000000000..3d4a8064a89
--- /dev/null
+++ b/db/post_migrate/20230815160428_rename_plans_titles_with_legacy_plan_names.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RenamePlansTitlesWithLegacyPlanNames < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main_clusterwide
+
+ def up
+ execute "UPDATE plans SET title = 'Premium' WHERE name = 'premium'"
+ execute "UPDATE plans SET title = 'Ultimate' WHERE name = 'ultimate'"
+ end
+
+ def down
+ # no-op
+
+ # We don't know or even want to revert back to the old plan titles.
+ end
+end
diff --git a/db/post_migrate/20230816111730_ensure_id_uniqueness_for_p_ci_builds_v3.rb b/db/post_migrate/20230816111730_ensure_id_uniqueness_for_p_ci_builds_v3.rb
new file mode 100644
index 00000000000..c91525e0998
--- /dev/null
+++ b/db/post_migrate/20230816111730_ensure_id_uniqueness_for_p_ci_builds_v3.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+class EnsureIdUniquenessForPCiBuildsV3 < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::SchemaHelpers
+
+ enable_lock_retries!
+
+ TABLE_NAME = :p_ci_builds
+ FUNCTION_NAME = :assign_p_ci_builds_id_value
+ TRIGGER_NAME = :assign_p_ci_builds_id_trigger
+
+ def up
+ return if trigger_exists?(:ci_builds, TRIGGER_NAME)
+
+ change_column_default(TABLE_NAME, :id, nil)
+
+ create_trigger_function(FUNCTION_NAME) do
+ <<~SQL
+ IF NEW."id" IS NOT NULL THEN
+ RAISE WARNING 'Manually assigning ids is not allowed, the value will be ignored';
+ END IF;
+ NEW."id" := nextval('ci_builds_id_seq'::regclass);
+ RETURN NEW;
+ SQL
+ end
+
+ Gitlab::Database::PostgresPartitionedTable.each_partition(TABLE_NAME) do |partition|
+ create_trigger(partition.identifier, TRIGGER_NAME, FUNCTION_NAME, fires: 'BEFORE INSERT')
+ end
+ end
+
+ def down
+ execute(<<~SQL.squish)
+ ALTER TABLE #{TABLE_NAME}
+ ALTER COLUMN id SET DEFAULT nextval('ci_builds_id_seq'::regclass);
+
+ DROP FUNCTION IF EXISTS #{FUNCTION_NAME} CASCADE;
+ SQL
+ end
+end
diff --git a/db/post_migrate/20230816152540_ensure_dum_note_id_bigint_backfill_is_finished_for_self_managed.rb b/db/post_migrate/20230816152540_ensure_dum_note_id_bigint_backfill_is_finished_for_self_managed.rb
new file mode 100644
index 00000000000..2379fa93ccc
--- /dev/null
+++ b/db/post_migrate/20230816152540_ensure_dum_note_id_bigint_backfill_is_finished_for_self_managed.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class EnsureDumNoteIdBigintBackfillIsFinishedForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ disable_ddl_transaction!
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'design_user_mentions',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230816152639_swap_design_user_mentions_note_id_to_big_int_for_self_managed.rb b/db/post_migrate/20230816152639_swap_design_user_mentions_note_id_to_big_int_for_self_managed.rb
new file mode 100644
index 00000000000..9c72bef752f
--- /dev/null
+++ b/db/post_migrate/20230816152639_swap_design_user_mentions_note_id_to_big_int_for_self_managed.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+class SwapDesignUserMentionsNoteIdToBigIntForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'design_user_mentions'
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :note_id)
+ return if columns_swapped?(TABLE_NAME, :note_id)
+
+ swap
+ end
+
+ def down
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :note_id)
+ return unless columns_swapped?(TABLE_NAME, :note_id)
+
+ swap
+ end
+
+ private
+
+ def swap
+ # This will replace the existing index_design_user_mentions_on_note_id
+ add_concurrent_index TABLE_NAME, :note_id_convert_to_bigint, unique: true,
+ name: 'index_design_user_mentions_on_note_id_convert_to_bigint'
+
+ # This will replace the existing fk_rails_8de8c6d632
+ add_concurrent_foreign_key TABLE_NAME, :notes, column: :note_id_convert_to_bigint,
+ name: 'fk_design_user_mentions_note_id_convert_to_bigint',
+ on_delete: :cascade
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE notes, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id TO note_id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_convert_to_bigint TO note_id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_tmp TO note_id_convert_to_bigint"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:note_id, :note_id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ # Swap defaults
+ change_column_default TABLE_NAME, :note_id, nil
+ change_column_default TABLE_NAME, :note_id_convert_to_bigint, 0
+
+ execute 'DROP INDEX IF EXISTS index_design_user_mentions_on_note_id'
+ rename_index TABLE_NAME, 'index_design_user_mentions_on_note_id_convert_to_bigint',
+ 'index_design_user_mentions_on_note_id'
+
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS fk_rails_8de8c6d632"
+ rename_constraint(TABLE_NAME, 'fk_design_user_mentions_note_id_convert_to_bigint', 'fk_rails_8de8c6d632')
+ end
+ end
+end
diff --git a/db/post_migrate/20230816210503_ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_self_managed.rb b/db/post_migrate/20230816210503_ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_self_managed.rb
new file mode 100644
index 00000000000..c3971e93526
--- /dev/null
+++ b/db/post_migrate/20230816210503_ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_self_managed.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class EnsureMrUserMentionsNoteIdBigintBackfillIsFinishedForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'merge_request_user_mentions',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230816213228_swap_merge_request_user_mentions_note_id_to_bigint_for_self_managed.rb b/db/post_migrate/20230816213228_swap_merge_request_user_mentions_note_id_to_bigint_for_self_managed.rb
new file mode 100644
index 00000000000..93765da66dd
--- /dev/null
+++ b/db/post_migrate/20230816213228_swap_merge_request_user_mentions_note_id_to_bigint_for_self_managed.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+class SwapMergeRequestUserMentionsNoteIdToBigintForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'merge_request_user_mentions'
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :note_id)
+ return if columns_swapped?(TABLE_NAME, :note_id)
+
+ swap
+ end
+
+ def down
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :note_id)
+ return unless columns_swapped?(TABLE_NAME, :note_id)
+
+ swap
+ end
+
+ def swap
+ # This will replace the existing index_merge_request_user_mentions_on_note_id
+ add_concurrent_index TABLE_NAME, :note_id_convert_to_bigint, unique: true,
+ name: 'index_merge_request_user_mentions_note_id_convert_to_bigint',
+ where: 'note_id_convert_to_bigint IS NOT NULL'
+
+ # This will replace the existing merge_request_user_mentions_on_mr_id_and_note_id_index
+ add_concurrent_index TABLE_NAME, [:merge_request_id, :note_id_convert_to_bigint], unique: true,
+ name: 'mr_user_mentions_on_mr_id_and_note_id_convert_to_bigint_index'
+
+ # This will replace the existing merge_request_user_mentions_on_mr_id_index
+ add_concurrent_index TABLE_NAME, :merge_request_id, unique: true,
+ name: 'merge_request_user_mentions_on_mr_id_index_convert_to_bigint',
+ where: 'note_id_convert_to_bigint IS NULL'
+
+ # This will replace the existing fk_rails_c440b9ea31
+ add_concurrent_foreign_key TABLE_NAME, :notes, column: :note_id_convert_to_bigint,
+ name: 'fk_merge_request_user_mentions_note_id_convert_to_bigint',
+ on_delete: :cascade
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE notes, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id TO note_id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_convert_to_bigint TO note_id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_tmp TO note_id_convert_to_bigint"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:note_id, :note_id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ execute 'DROP INDEX IF EXISTS index_merge_request_user_mentions_on_note_id'
+ rename_index TABLE_NAME, 'index_merge_request_user_mentions_note_id_convert_to_bigint',
+ 'index_merge_request_user_mentions_on_note_id'
+
+ execute 'DROP INDEX IF EXISTS merge_request_user_mentions_on_mr_id_and_note_id_index'
+ rename_index TABLE_NAME, 'mr_user_mentions_on_mr_id_and_note_id_convert_to_bigint_index',
+ 'merge_request_user_mentions_on_mr_id_and_note_id_index'
+
+ execute 'DROP INDEX IF EXISTS merge_request_user_mentions_on_mr_id_index'
+ rename_index TABLE_NAME, 'merge_request_user_mentions_on_mr_id_index_convert_to_bigint',
+ 'merge_request_user_mentions_on_mr_id_index'
+
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS fk_rails_c440b9ea31"
+ rename_constraint(TABLE_NAME, 'fk_merge_request_user_mentions_note_id_convert_to_bigint', 'fk_rails_c440b9ea31')
+ end
+ end
+end
diff --git a/db/post_migrate/20230817050946_backfill_shared_runners_duration_for_project_bigint_conversion.rb b/db/post_migrate/20230817050946_backfill_shared_runners_duration_for_project_bigint_conversion.rb
new file mode 100644
index 00000000000..9ad079efb47
--- /dev/null
+++ b/db/post_migrate/20230817050946_backfill_shared_runners_duration_for_project_bigint_conversion.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class BackfillSharedRunnersDurationForProjectBigintConversion < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ TABLE_NAME = :ci_project_monthly_usages
+ COLUMN_NAMES = %i[shared_runners_duration]
+
+ def up
+ backfill_conversion_of_integer_to_bigint(TABLE_NAME, COLUMN_NAMES, sub_batch_size: 250)
+ end
+
+ def down
+ revert_backfill_conversion_of_integer_to_bigint(TABLE_NAME, COLUMN_NAMES)
+ end
+end
diff --git a/db/post_migrate/20230817111753_ensure_events_bigint_backfill_is_finished_for_self_hosts.rb b/db/post_migrate/20230817111753_ensure_events_bigint_backfill_is_finished_for_self_hosts.rb
new file mode 100644
index 00000000000..e80676253db
--- /dev/null
+++ b/db/post_migrate/20230817111753_ensure_events_bigint_backfill_is_finished_for_self_hosts.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class EnsureEventsBigintBackfillIsFinishedForSelfHosts < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'events',
+ column_name: 'id',
+ job_arguments: [['target_id'], ['target_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230817111938_swap_events_target_id_to_bigint_for_self_hosts.rb b/db/post_migrate/20230817111938_swap_events_target_id_to_bigint_for_self_hosts.rb
new file mode 100644
index 00000000000..52165bf1dd7
--- /dev/null
+++ b/db/post_migrate/20230817111938_swap_events_target_id_to_bigint_for_self_hosts.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+class SwapEventsTargetIdToBigintForSelfHosts < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'events'
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :target_id)
+ return if columns_swapped?(TABLE_NAME, :target_id)
+
+ swap
+ end
+
+ def down
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :target_id)
+ return unless columns_swapped?(TABLE_NAME, :target_id)
+
+ swap
+ end
+
+ private
+
+ def swap
+ # This will replace the existing index_events_on_target_type_and_target_id_and_fingerprint
+ add_concurrent_index TABLE_NAME, [:target_type, :target_id_convert_to_bigint, :fingerprint],
+ name: :index_events_on_target_type_and_target_id_bigint_fingerprint,
+ unique: true
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN target_id TO target_id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN target_id_convert_to_bigint TO target_id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN target_id_tmp TO target_id_convert_to_bigint"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:target_id, :target_id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ execute 'DROP INDEX IF EXISTS index_events_on_target_type_and_target_id_and_fingerprint'
+ rename_index TABLE_NAME, 'index_events_on_target_type_and_target_id_bigint_fingerprint',
+ 'index_events_on_target_type_and_target_id_and_fingerprint'
+ end
+ end
+end
diff --git a/db/post_migrate/20230817143507_ensure_award_emoji_bigint_backfill_is_finished_for_self_hosts.rb b/db/post_migrate/20230817143507_ensure_award_emoji_bigint_backfill_is_finished_for_self_hosts.rb
new file mode 100644
index 00000000000..de25c03c0d5
--- /dev/null
+++ b/db/post_migrate/20230817143507_ensure_award_emoji_bigint_backfill_is_finished_for_self_hosts.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class EnsureAwardEmojiBigintBackfillIsFinishedForSelfHosts < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'award_emoji',
+ column_name: 'id',
+ job_arguments: [['awardable_id'], ['awardable_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230817143637_swap_award_emoji_note_id_to_bigint_for_self_hosts.rb b/db/post_migrate/20230817143637_swap_award_emoji_note_id_to_bigint_for_self_hosts.rb
new file mode 100644
index 00000000000..d5c28f8a066
--- /dev/null
+++ b/db/post_migrate/20230817143637_swap_award_emoji_note_id_to_bigint_for_self_hosts.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+class SwapAwardEmojiNoteIdToBigintForSelfHosts < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'award_emoji'
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :awardable_id)
+ return if columns_swapped?(TABLE_NAME, :awardable_id)
+
+ swap
+ end
+
+ def down
+ return if com_or_dev_or_test_but_not_jh?
+ return if temp_column_removed?(TABLE_NAME, :awardable_id)
+ return unless columns_swapped?(TABLE_NAME, :awardable_id)
+
+ swap
+ end
+
+ private
+
+ def swap
+ # This will replace the existing idx_award_emoji_on_user_emoji_name_awardable_type_awardable_id
+ add_concurrent_index TABLE_NAME, [:user_id, :name, :awardable_type, :awardable_id_convert_to_bigint],
+ name: 'tmp_award_emoji_on_user_emoji_name_awardable_type_awardable_id'
+
+ # This will replace the existing index_award_emoji_on_awardable_type_and_awardable_id
+ add_concurrent_index TABLE_NAME, [:awardable_type, :awardable_id_convert_to_bigint],
+ name: 'tmp_index_award_emoji_on_awardable_type_and_awardable_id'
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN awardable_id TO awardable_id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN awardable_id_convert_to_bigint TO awardable_id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN awardable_id_tmp TO awardable_id_convert_to_bigint"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:awardable_id, :awardable_id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ execute 'DROP INDEX IF EXISTS idx_award_emoji_on_user_emoji_name_awardable_type_awardable_id'
+ rename_index TABLE_NAME, 'tmp_award_emoji_on_user_emoji_name_awardable_type_awardable_id',
+ 'idx_award_emoji_on_user_emoji_name_awardable_type_awardable_id'
+
+ execute 'DROP INDEX IF EXISTS index_award_emoji_on_awardable_type_and_awardable_id'
+ rename_index TABLE_NAME, 'tmp_index_award_emoji_on_awardable_type_and_awardable_id',
+ 'index_award_emoji_on_awardable_type_and_awardable_id'
+ end
+ end
+end
diff --git a/db/post_migrate/20230818034041_prepare_removal_index_success_deployments_on_cluster_id_and_environment_id.rb b/db/post_migrate/20230818034041_prepare_removal_index_success_deployments_on_cluster_id_and_environment_id.rb
new file mode 100644
index 00000000000..39a45774676
--- /dev/null
+++ b/db/post_migrate/20230818034041_prepare_removal_index_success_deployments_on_cluster_id_and_environment_id.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class PrepareRemovalIndexSuccessDeploymentsOnClusterIdAndEnvironmentId < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_successful_deployments_on_cluster_id_and_environment_id'
+
+ # TODO: Index to be destroyed synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/402514
+ def up
+ prepare_async_index_removal :deployments, %i[cluster_id environment_id], name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index :deployments, %i[cluster_id environment_id], name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230818050946_backfill_shared_runners_duration_for_namespace_bigint_conversion.rb b/db/post_migrate/20230818050946_backfill_shared_runners_duration_for_namespace_bigint_conversion.rb
new file mode 100644
index 00000000000..3171008ee3a
--- /dev/null
+++ b/db/post_migrate/20230818050946_backfill_shared_runners_duration_for_namespace_bigint_conversion.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class BackfillSharedRunnersDurationForNamespaceBigintConversion < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ TABLE_NAME = :ci_namespace_monthly_usages
+ COLUMN_NAMES = %i[shared_runners_duration]
+
+ def up
+ backfill_conversion_of_integer_to_bigint(TABLE_NAME, COLUMN_NAMES, sub_batch_size: 250)
+ end
+
+ def down
+ revert_backfill_conversion_of_integer_to_bigint(TABLE_NAME, COLUMN_NAMES)
+ end
+end
diff --git a/db/post_migrate/20230818055517_prepare_removal_index_deployments_on_id_where_cluster_id_present.rb b/db/post_migrate/20230818055517_prepare_removal_index_deployments_on_id_where_cluster_id_present.rb
new file mode 100644
index 00000000000..c66143809d2
--- /dev/null
+++ b/db/post_migrate/20230818055517_prepare_removal_index_deployments_on_id_where_cluster_id_present.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class PrepareRemovalIndexDeploymentsOnIdWhereClusterIdPresent < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_deployments_on_id_where_cluster_id_present'
+
+ # TODO: Index to be destroyed synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/402510
+ def up
+ prepare_async_index_removal :deployments, :id, name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index :deployments, :id, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230818083610_queue_backfill_users_with_defaults.rb b/db/post_migrate/20230818083610_queue_backfill_users_with_defaults.rb
new file mode 100644
index 00000000000..b027ef10ddc
--- /dev/null
+++ b/db/post_migrate/20230818083610_queue_backfill_users_with_defaults.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class QueueBackfillUsersWithDefaults < Gitlab::Database::Migration[2.1]
+ MIGRATION = "BackfillUsersWithDefaults"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 3_000
+ SUB_BATCH_SIZE = 200
+ MAX_BATCH_SIZE = 10_000
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :users,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE,
+ max_batch_size: MAX_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :users, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230818085219_queue_backfill_user_preferences_with_defaults.rb b/db/post_migrate/20230818085219_queue_backfill_user_preferences_with_defaults.rb
new file mode 100644
index 00000000000..0651f21f240
--- /dev/null
+++ b/db/post_migrate/20230818085219_queue_backfill_user_preferences_with_defaults.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class QueueBackfillUserPreferencesWithDefaults < Gitlab::Database::Migration[2.1]
+ MIGRATION = "BackfillUserPreferencesWithDefaults"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 3_000
+ SUB_BATCH_SIZE = 200
+ MAX_BATCH_SIZE = 10_000
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :user_preferences,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE,
+ max_batch_size: MAX_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :user_preferences, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230818142801_queue_create_compliance_standards_adherence.rb b/db/post_migrate/20230818142801_queue_create_compliance_standards_adherence.rb
new file mode 100644
index 00000000000..33d6dd30e44
--- /dev/null
+++ b/db/post_migrate/20230818142801_queue_create_compliance_standards_adherence.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class QueueCreateComplianceStandardsAdherence < Gitlab::Database::Migration[2.1]
+ MIGRATION = "CreateComplianceStandardsAdherence"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 10_000
+ SUB_BATCH_SIZE = 500
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ return unless Gitlab.ee? # Standards adherence is available only in EE version
+
+ queue_batched_background_migration(
+ MIGRATION,
+ :projects,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :projects, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230821081603_queue_convert_credit_card_validation_data_to_hashes.rb b/db/post_migrate/20230821081603_queue_convert_credit_card_validation_data_to_hashes.rb
new file mode 100644
index 00000000000..00a1840366b
--- /dev/null
+++ b/db/post_migrate/20230821081603_queue_convert_credit_card_validation_data_to_hashes.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class QueueConvertCreditCardValidationDataToHashes < Gitlab::Database::Migration[2.1]
+ MIGRATION = "ConvertCreditCardValidationDataToHashes"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :user_credit_card_validations,
+ :user_id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :user_credit_card_validations, :user_id, [])
+ end
+end
diff --git a/db/post_migrate/20230822064841_prepare_index_for_org_id_on_projects.rb b/db/post_migrate/20230822064841_prepare_index_for_org_id_on_projects.rb
new file mode 100644
index 00000000000..1f822a440a4
--- /dev/null
+++ b/db/post_migrate/20230822064841_prepare_index_for_org_id_on_projects.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class PrepareIndexForOrgIdOnProjects < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_projects_on_organization_id'
+
+ def up
+ prepare_async_index :projects, :organization_id, name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index :projects, :organization_id, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230822104028_delete_project_callout_three.rb b/db/post_migrate/20230822104028_delete_project_callout_three.rb
new file mode 100644
index 00000000000..9ba9b3f806a
--- /dev/null
+++ b/db/post_migrate/20230822104028_delete_project_callout_three.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class DeleteProjectCalloutThree < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ BATCH_SIZE = 1000
+ ULTIMATE_FEATURE_REMOVAL_BANNER_FEATURE_NAME = 3
+
+ def up
+ each_batch_range('user_project_callouts', scope: ->(table) { table.all }, of: BATCH_SIZE) do |min, max|
+ execute <<~SQL
+ DELETE FROM user_project_callouts
+ WHERE feature_name = #{ULTIMATE_FEATURE_REMOVAL_BANNER_FEATURE_NAME}
+ AND id BETWEEN #{min} AND #{max}
+ SQL
+ end
+ end
+
+ def down
+ # NO-OP
+ end
+end
diff --git a/db/post_migrate/20230822125256_drop_temporary_index_on_vulnerability_reads_dismissal_reason.rb b/db/post_migrate/20230822125256_drop_temporary_index_on_vulnerability_reads_dismissal_reason.rb
new file mode 100644
index 00000000000..e1b74a1b46c
--- /dev/null
+++ b/db/post_migrate/20230822125256_drop_temporary_index_on_vulnerability_reads_dismissal_reason.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class DropTemporaryIndexOnVulnerabilityReadsDismissalReason < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = "tmp_idx_vuln_reads_where_dismissal_reason_null"
+ DISMISSED_STATE = 2
+
+ def up
+ remove_concurrent_index_by_name(
+ :vulnerability_reads,
+ INDEX_NAME
+ )
+ end
+
+ def down
+ add_concurrent_index(
+ :vulnerability_reads,
+ %i[id],
+ where: "state = #{DISMISSED_STATE} AND dismissal_reason IS NULL",
+ name: INDEX_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230822153124_remove_free_user_cap_email_workers_related_columns.rb b/db/post_migrate/20230822153124_remove_free_user_cap_email_workers_related_columns.rb
new file mode 100644
index 00000000000..3ae0459fcdc
--- /dev/null
+++ b/db/post_migrate/20230822153124_remove_free_user_cap_email_workers_related_columns.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class RemoveFreeUserCapEmailWorkersRelatedColumns < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'namespace_details'
+ OVER_LIMIT_CHECK_COLUMN_NAME = 'next_over_limit_check_at'
+ OVER_LIMIT_CHECK_INDEX = 'index_next_over_limit_check_at_asc_order'
+ OVER_LIMIT_NOTIFIED_AT_COLUMN_NAME = 'free_user_cap_over_limit_notified_at'
+ OVER_LIMIT_NOTIFIED_AT_INDEX = 'index_fuc_over_limit_notified_at'
+
+ def up
+ remove_columns TABLE_NAME, OVER_LIMIT_CHECK_COLUMN_NAME, OVER_LIMIT_NOTIFIED_AT_COLUMN_NAME
+ end
+
+ def down
+ unless column_exists?(TABLE_NAME, OVER_LIMIT_CHECK_COLUMN_NAME)
+ add_column TABLE_NAME, OVER_LIMIT_CHECK_COLUMN_NAME, :datetime_with_timezone
+ end
+
+ unless column_exists?(TABLE_NAME, OVER_LIMIT_NOTIFIED_AT_COLUMN_NAME)
+ add_column TABLE_NAME, OVER_LIMIT_NOTIFIED_AT_COLUMN_NAME, :datetime_with_timezone
+ end
+
+ add_concurrent_index TABLE_NAME, OVER_LIMIT_CHECK_COLUMN_NAME, name: OVER_LIMIT_CHECK_INDEX,
+ order: { next_over_limit_check_at: 'ASC NULLS FIRST' }
+ add_concurrent_index TABLE_NAME, OVER_LIMIT_NOTIFIED_AT_COLUMN_NAME, name: OVER_LIMIT_NOTIFIED_AT_INDEX
+ end
+end
diff --git a/db/post_migrate/20230822154640_add_async_index_on_merge_requests_target_project_id_and_merged_commit_sha.rb b/db/post_migrate/20230822154640_add_async_index_on_merge_requests_target_project_id_and_merged_commit_sha.rb
new file mode 100644
index 00000000000..148a9f4c073
--- /dev/null
+++ b/db/post_migrate/20230822154640_add_async_index_on_merge_requests_target_project_id_and_merged_commit_sha.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddAsyncIndexOnMergeRequestsTargetProjectIdAndMergedCommitSha < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_merge_requests_on_target_project_id_and_merged_commit_sha'
+ INDEX_COLUMNS = %i[target_project_id merged_commit_sha]
+
+ disable_ddl_transaction!
+
+ # TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/418822
+ def up
+ prepare_async_index :merge_requests, INDEX_COLUMNS, name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index :merge_requests, INDEX_COLUMNS, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230822195852_remove_pa_jitsu_related_settings.rb b/db/post_migrate/20230822195852_remove_pa_jitsu_related_settings.rb
new file mode 100644
index 00000000000..9d36cbac956
--- /dev/null
+++ b/db/post_migrate/20230822195852_remove_pa_jitsu_related_settings.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class RemovePaJitsuRelatedSettings < Gitlab::Database::Migration[2.1]
+ def up
+ # Changed to a no-op, this migration was reverted after
+ # an incident during a deploy to staging.gitlab.com
+ # https://gitlab.com/gitlab-com/gl-infra/production/-/issues/16274
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230823085627_add_temp_index_for_project_statistics_updated_at.rb b/db/post_migrate/20230823085627_add_temp_index_for_project_statistics_updated_at.rb
new file mode 100644
index 00000000000..a242413266d
--- /dev/null
+++ b/db/post_migrate/20230823085627_add_temp_index_for_project_statistics_updated_at.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddTempIndexForProjectStatisticsUpdatedAt < Gitlab::Database::Migration[2.1]
+ INDEX_PROJECT_STATISTICS_UPDATED_AT = 'tmp_index_project_statistics_updated_at'
+
+ disable_ddl_transaction!
+
+ def up
+ # Temporary index is to be used to trigger a refresh of project_statistics repository_size
+ add_concurrent_index :project_statistics, [:project_id, :updated_at],
+ name: INDEX_PROJECT_STATISTICS_UPDATED_AT,
+ where: "repository_size > 0"
+ end
+
+ def down
+ remove_concurrent_index_by_name :project_statistics, INDEX_PROJECT_STATISTICS_UPDATED_AT
+ end
+end
diff --git a/db/post_migrate/20230823090001_queue_backfill_project_statistics_storage_size_with_recent_size.rb b/db/post_migrate/20230823090001_queue_backfill_project_statistics_storage_size_with_recent_size.rb
new file mode 100644
index 00000000000..b841e912ebf
--- /dev/null
+++ b/db/post_migrate/20230823090001_queue_backfill_project_statistics_storage_size_with_recent_size.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class QueueBackfillProjectStatisticsStorageSizeWithRecentSize < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = "BackfillProjectStatisticsStorageSizeWithRecentSize"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :project_statistics,
+ :project_id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :project_statistics, :project_id, [])
+ end
+end
diff --git a/db/post_migrate/20230823140934_add_linked_items_widget_to_ticket_work_item_type.rb b/db/post_migrate/20230823140934_add_linked_items_widget_to_ticket_work_item_type.rb
new file mode 100644
index 00000000000..9f97bd8cc0d
--- /dev/null
+++ b/db/post_migrate/20230823140934_add_linked_items_widget_to_ticket_work_item_type.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class AddLinkedItemsWidgetToTicketWorkItemType < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ TICKET_ENUM_VALUE = 8
+ WIDGET_NAME = 'Linked items'
+ WIDGET_ENUM_VALUE = 17
+
+ class MigrationWorkItemType < MigrationRecord
+ self.table_name = 'work_item_types'
+ end
+
+ class MigrationWidgetDefinition < MigrationRecord
+ self.table_name = 'work_item_widget_definitions'
+ end
+
+ def up
+ # New instances will not run this migration and add this type via fixtures
+ # checking if record exists mostly because migration specs will run all migrations
+ # and that will conflict with the preloaded base work item types
+ ticket_work_item_type = MigrationWorkItemType.find_by(base_type: TICKET_ENUM_VALUE, namespace_id: nil)
+
+ return say('Ticket work item type does not exist, skipping widget creation') unless ticket_work_item_type
+
+ widgets = [
+ {
+ work_item_type_id: ticket_work_item_type.id,
+ name: WIDGET_NAME,
+ widget_type: WIDGET_ENUM_VALUE
+ }
+ ]
+
+ MigrationWidgetDefinition.upsert_all(
+ widgets,
+ unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
+ )
+ end
+
+ def down
+ ticket_work_item_type = MigrationWorkItemType.find_by(base_type: TICKET_ENUM_VALUE, namespace_id: nil)
+
+ return say('Ticket work item type does not exist, skipping widget removal') unless ticket_work_item_type
+
+ MigrationWidgetDefinition.where(work_item_type_id: ticket_work_item_type.id, widget_type: WIDGET_ENUM_VALUE)
+ .delete_all
+ end
+end
diff --git a/db/post_migrate/20230823143519_remove_users_notification_settings_user_id_fk.rb b/db/post_migrate/20230823143519_remove_users_notification_settings_user_id_fk.rb
new file mode 100644
index 00000000000..2e8b634e108
--- /dev/null
+++ b/db/post_migrate/20230823143519_remove_users_notification_settings_user_id_fk.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class RemoveUsersNotificationSettingsUserIdFk < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ FOREIGN_KEY_NAME = "fk_0c95e91db7"
+
+ def up
+ return unless foreign_key_exists?(:notification_settings, :users, name: FOREIGN_KEY_NAME)
+
+ with_lock_retries do
+ remove_foreign_key_if_exists(:notification_settings, :users,
+ name: FOREIGN_KEY_NAME, reverse_lock_order: true)
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(:notification_settings, :users,
+ name: FOREIGN_KEY_NAME, column: :user_id,
+ target_column: :id, on_delete: :cascade)
+ end
+end
diff --git a/db/post_migrate/20230823144846_remove_users_members_user_id_fk.rb b/db/post_migrate/20230823144846_remove_users_members_user_id_fk.rb
new file mode 100644
index 00000000000..59f97d7c26a
--- /dev/null
+++ b/db/post_migrate/20230823144846_remove_users_members_user_id_fk.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class RemoveUsersMembersUserIdFk < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ FOREIGN_KEY_NAME = "fk_2e88fb7ce9"
+
+ def up
+ return unless foreign_key_exists?(:members, :users, name: FOREIGN_KEY_NAME)
+
+ with_lock_retries do
+ remove_foreign_key_if_exists(:members, :users,
+ name: FOREIGN_KEY_NAME, reverse_lock_order: true)
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(:members, :users,
+ name: FOREIGN_KEY_NAME, column: :user_id,
+ target_column: :id, on_delete: :cascade)
+ end
+end
diff --git a/db/post_migrate/20230823145053_ensure_notes_bigint_backfill_is_finished_for_self_managed.rb b/db/post_migrate/20230823145053_ensure_notes_bigint_backfill_is_finished_for_self_managed.rb
new file mode 100644
index 00000000000..c16313bb27d
--- /dev/null
+++ b/db/post_migrate/20230823145053_ensure_notes_bigint_backfill_is_finished_for_self_managed.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class EnsureNotesBigintBackfillIsFinishedForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+
+ # Same as was defined in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119913
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'notes',
+ column_name: 'id',
+ job_arguments: [['id'], ['id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230823145126_swap_notes_id_to_bigint_for_self_managed.rb b/db/post_migrate/20230823145126_swap_notes_id_to_bigint_for_self_managed.rb
new file mode 100644
index 00000000000..ddfaefc452b
--- /dev/null
+++ b/db/post_migrate/20230823145126_swap_notes_id_to_bigint_for_self_managed.rb
@@ -0,0 +1,183 @@
+# frozen_string_literal: true
+
+class SwapNotesIdToBigintForSelfManaged < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'notes'
+ PK_INDEX_NAME = 'index_notes_on_id_convert_to_bigint'
+
+ SECONDARY_INDEXES = [
+ {
+ original_name: :index_notes_on_author_id_and_created_at_and_id,
+ temporary_name: :index_notes_on_author_id_created_at_id_convert_to_bigint,
+ columns: [:author_id, :created_at, :id_convert_to_bigint],
+ options: {}
+ },
+ {
+ original_name: :index_notes_on_id_where_confidential,
+ temporary_name: :index_notes_on_id_convert_to_bigint_where_confidential,
+ columns: [:id_convert_to_bigint],
+ options: { where: 'confidential = true' }
+ },
+ {
+ original_name: :index_notes_on_id_where_internal,
+ temporary_name: :index_notes_on_id_convert_to_bigint_where_internal,
+ columns: [:id_convert_to_bigint],
+ options: { where: 'internal = true' }
+ },
+ {
+ original_name: :index_notes_on_project_id_and_id_and_system_false,
+ temporary_name: :index_notes_on_project_id_id_convert_to_bigint_system_false,
+ columns: [:project_id, :id_convert_to_bigint],
+ options: { where: 'NOT system' }
+ },
+ {
+ original_name: :note_mentions_temp_index,
+ temporary_name: :note_mentions_temp_index_convert_to_bigint,
+ columns: [:id_convert_to_bigint, :noteable_type],
+ options: { where: "note ~~ '%@%'::text" }
+ }
+ ]
+
+ REFERENCING_FOREIGN_KEYS = [
+ [:todos, :fk_91d1f47b13, :note_id, :cascade],
+ [:incident_management_timeline_events, :fk_d606a2a890, :promoted_from_note_id, :nullify],
+ [:system_note_metadata, :fk_d83a918cb1, :note_id, :cascade],
+ [:diff_note_positions, :fk_rails_13c7212859, :note_id, :cascade],
+ [:epic_user_mentions, :fk_rails_1c65976a49, :note_id, :cascade],
+ [:suggestions, :fk_rails_33b03a535c, :note_id, :cascade],
+ [:issue_user_mentions, :fk_rails_3861d9fefa, :note_id, :cascade],
+ [:note_diff_files, :fk_rails_3d66047aeb, :diff_note_id, :cascade],
+ [:snippet_user_mentions, :fk_rails_4d3f96b2cb, :note_id, :cascade],
+ [:design_user_mentions, :fk_rails_8de8c6d632, :note_id, :cascade],
+ [:vulnerability_user_mentions, :fk_rails_a18600f210, :note_id, :cascade],
+ [:commit_user_mentions, :fk_rails_a6760813e0, :note_id, :cascade],
+ [:merge_request_user_mentions, :fk_rails_c440b9ea31, :note_id, :cascade],
+ [:note_metadata, :fk_rails_d853224d37, :note_id, :cascade],
+ [:alert_management_alert_user_mentions, :fk_rails_eb2de0cdef, :note_id, :cascade],
+ [:timelogs, :fk_timelogs_note_id, :note_id, :nullify]
+ ]
+
+ def up
+ return if com_or_dev_or_test_but_not_jh?
+
+ return if temp_column_removed?(TABLE_NAME, :id)
+
+ return if columns_swapped?(TABLE_NAME, :id)
+
+ swap
+ end
+
+ def down
+ return if com_or_dev_or_test_but_not_jh?
+
+ return if temp_column_removed?(TABLE_NAME, :id)
+
+ return unless columns_swapped?(TABLE_NAME, :id)
+
+ swap
+ end
+
+ private
+
+ def swap
+ create_indexes
+
+ create_referencing_foreign_keys
+
+ replace_referencing_foreign_keys
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ # Swap the original and new column names
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN id TO id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN id_convert_to_bigint TO id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN id_tmp TO id_convert_to_bigint"
+
+ # Reset the function so PG drops the plan cache for the incorrect integer type
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:id, :id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ # Swap defaults of the two columns, and change ownership of the sequence to the new id
+ execute "ALTER SEQUENCE notes_id_seq OWNED BY #{TABLE_NAME}.id"
+ change_column_default TABLE_NAME, :id, -> { "nextval('notes_id_seq'::regclass)" }
+ change_column_default TABLE_NAME, :id_convert_to_bigint, 0
+
+ # Swap the PK constraint from the original column to the new column.
+ # We deliberately don't CASCADE here because the old FKs should be removed already
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT notes_pkey"
+ rename_index TABLE_NAME, PK_INDEX_NAME, 'notes_pkey'
+ execute "ALTER TABLE #{TABLE_NAME} ADD CONSTRAINT notes_pkey PRIMARY KEY USING INDEX notes_pkey"
+
+ rename_secondary_indexes # rubocop:disable Migration/WithLockRetriesDisallowedMethod
+ end
+ end
+
+ # Copy existing indexes from the original column to the new column
+ def create_indexes
+ add_concurrent_index TABLE_NAME, :id_convert_to_bigint, unique: true, name: PK_INDEX_NAME
+
+ SECONDARY_INDEXES.each do |index_definition|
+ options = index_definition[:options]
+ options[:name] = index_definition[:temporary_name]
+
+ add_concurrent_index(TABLE_NAME, index_definition[:columns], options)
+ end
+ end
+
+ # Remove old column indexes and change new column indexes to have the original names
+ def rename_secondary_indexes
+ SECONDARY_INDEXES.each do |index_definition|
+ remove_index(TABLE_NAME, name: index_definition[:original_name], if_exists: true) # rubocop:disable Migration/RemoveIndex
+ rename_index(TABLE_NAME, index_definition[:temporary_name], index_definition[:original_name])
+ end
+ end
+
+ # Copy existing FKs from the original column to the new column
+ #
+ # @note Don't attempt to create the FK if one already exists from the table to the new column.
+ # The check in `add_concurrent_foreign_key` already checks for this, but it looks for the foreign key
+ # with the new name only (containing the `_tmp` suffix). Since we might partially rename FKs and re-run
+ # the migration, we also have to check and see if a FK exists on those columns that might not
+ # match the `_tmp` name.
+ def create_referencing_foreign_keys
+ REFERENCING_FOREIGN_KEYS.each do |(from_table, name, column, on_delete)|
+ next if foreign_key_exists?(from_table, TABLE_NAME, column: column,
+ primary_key: :id_convert_to_bigint, name: name)
+
+ add_concurrent_foreign_key(
+ from_table,
+ TABLE_NAME,
+ column: column,
+ target_column: :id_convert_to_bigint,
+ name: "#{name}_tmp",
+ on_delete: on_delete,
+ reverse_lock_order: true
+ )
+ end
+ end
+
+ # Remove existing FKs from the referencing tables, so we don't have to lock on them when we drop the existing PK
+ #
+ # @note Don't attempt to replace the FK unless it exists and points at the original column. This could happen if the
+ # migration is re-run due to failing midway.
+ def replace_referencing_foreign_keys
+ REFERENCING_FOREIGN_KEYS.each do |(from_table, name, column, _)|
+ next unless foreign_key_exists?(from_table, TABLE_NAME, column: column, primary_key: :id, name: name)
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ temporary_name = "#{name}_tmp"
+
+ # Explicitly lock table in order of parent, child to attempt to avoid deadlocks
+ execute "LOCK TABLE #{TABLE_NAME}, #{from_table} IN ACCESS EXCLUSIVE MODE"
+
+ remove_foreign_key(from_table, TABLE_NAME, column: column, primary_key: :id, name: name)
+
+ rename_constraint(from_table, temporary_name, name)
+ end
+ end
+ end
+end
diff --git a/db/post_migrate/20230823161514_remove_namespaces_routes_namespace_id_fk.rb b/db/post_migrate/20230823161514_remove_namespaces_routes_namespace_id_fk.rb
new file mode 100644
index 00000000000..a640ac686ed
--- /dev/null
+++ b/db/post_migrate/20230823161514_remove_namespaces_routes_namespace_id_fk.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class RemoveNamespacesRoutesNamespaceIdFk < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ FOREIGN_KEY_NAME = "fk_bb2e5b8968"
+
+ def up
+ return unless foreign_key_exists?(:routes, :namespaces, name: FOREIGN_KEY_NAME)
+
+ with_lock_retries do
+ remove_foreign_key_if_exists(:routes, :namespaces,
+ name: FOREIGN_KEY_NAME, reverse_lock_order: true)
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(:routes, :namespaces,
+ name: FOREIGN_KEY_NAME, column: :namespace_id,
+ target_column: :id, on_delete: :cascade)
+ end
+end
diff --git a/db/post_migrate/20230823194111_remove_pages_deployments_project_id_path_prefix_unique_index.rb b/db/post_migrate/20230823194111_remove_pages_deployments_project_id_path_prefix_unique_index.rb
new file mode 100644
index 00000000000..9390a06b0bb
--- /dev/null
+++ b/db/post_migrate/20230823194111_remove_pages_deployments_project_id_path_prefix_unique_index.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class RemovePagesDeploymentsProjectIdPathPrefixUniqueIndex < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :pages_deployments,
+ 'index_pages_deployments_unique_path_prefix_by_project'
+ end
+
+ def down
+ # no op
+ end
+end
diff --git a/db/post_migrate/20230825085648_ensure_backfill_for_ci_stages_pipeline_id_is_finished.rb b/db/post_migrate/20230825085648_ensure_backfill_for_ci_stages_pipeline_id_is_finished.rb
new file mode 100644
index 00000000000..3dabd352a1b
--- /dev/null
+++ b/db/post_migrate/20230825085648_ensure_backfill_for_ci_stages_pipeline_id_is_finished.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class EnsureBackfillForCiStagesPipelineIdIsFinished < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_stages
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: TABLE_NAME,
+ column_name: 'id',
+ job_arguments: [['pipeline_id'], ['pipeline_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230825085719_create_async_index_for_ci_stages_pipeline_id.rb b/db/post_migrate/20230825085719_create_async_index_for_ci_stages_pipeline_id.rb
new file mode 100644
index 00000000000..a517d96815a
--- /dev/null
+++ b/db/post_migrate/20230825085719_create_async_index_for_ci_stages_pipeline_id.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+class CreateAsyncIndexForCiStagesPipelineId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_stages
+ INDEXES = {
+ 'index_ci_stages_on_pipeline_id_convert_to_bigint_and_name' => [
+ [:pipeline_id_convert_to_bigint, :name], { unique: true }
+ ],
+ 'index_ci_stages_on_pipeline_id_convert_to_bigint' => [
+ [:pipeline_id_convert_to_bigint], {}
+ ],
+ 'index_ci_stages_on_pipeline_id_convert_to_bigint_and_id' => [
+ [:pipeline_id_convert_to_bigint, :id], { where: 'status = ANY (ARRAY[0, 1, 2, 8, 9, 10])' }
+ ],
+ 'index_ci_stages_on_pipeline_id_convert_to_bigint_and_position' => [
+ [:pipeline_id_convert_to_bigint, :position], {}
+ ]
+ }
+
+ def up
+ INDEXES.each do |index_name, (columns, options)|
+ prepare_async_index TABLE_NAME, columns, name: index_name, **options
+ end
+ end
+
+ def down
+ INDEXES.each do |index_name, (columns, options)|
+ unprepare_async_index TABLE_NAME, columns, name: index_name, **options
+ end
+ end
+end
diff --git a/db/post_migrate/20230829120720_index_finding_id_for_vulnerabilities.rb b/db/post_migrate/20230829120720_index_finding_id_for_vulnerabilities.rb
new file mode 100644
index 00000000000..2556134658f
--- /dev/null
+++ b/db/post_migrate/20230829120720_index_finding_id_for_vulnerabilities.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class IndexFindingIdForVulnerabilities < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_vulnerabilities_on_finding_id'
+
+ # TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/423541
+ def up
+ prepare_async_index :vulnerabilities, :finding_id, name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index :vulnerabilities, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230830121830_queue_update_users_set_external_if_service_account.rb b/db/post_migrate/20230830121830_queue_update_users_set_external_if_service_account.rb
new file mode 100644
index 00000000000..cffc9bfba39
--- /dev/null
+++ b/db/post_migrate/20230830121830_queue_update_users_set_external_if_service_account.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class QueueUpdateUsersSetExternalIfServiceAccount < Gitlab::Database::Migration[2.1]
+ MIGRATION = "UpdateUsersSetExternalIfServiceAccount"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :users,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :users, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230831084632_queue_sync_scan_result_policies.rb b/db/post_migrate/20230831084632_queue_sync_scan_result_policies.rb
new file mode 100644
index 00000000000..983c97d75f3
--- /dev/null
+++ b/db/post_migrate/20230831084632_queue_sync_scan_result_policies.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class QueueSyncScanResultPolicies < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = "SyncScanResultPolicies"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :security_orchestration_policy_configurations,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :security_orchestration_policy_configurations, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230831101144_index_org_id_and_id_on_organization_user.rb b/db/post_migrate/20230831101144_index_org_id_and_id_on_organization_user.rb
new file mode 100644
index 00000000000..0f835e08a54
--- /dev/null
+++ b/db/post_migrate/20230831101144_index_org_id_and_id_on_organization_user.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class IndexOrgIdAndIdOnOrganizationUser < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_organization_users_on_organization_id_and_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :organization_users, %i[organization_id id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :organization_users, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230901033401_ensure_backfill_for_ci_sources_pipelines_pipeline_id_is_finished.rb b/db/post_migrate/20230901033401_ensure_backfill_for_ci_sources_pipelines_pipeline_id_is_finished.rb
new file mode 100644
index 00000000000..686dcdc3585
--- /dev/null
+++ b/db/post_migrate/20230901033401_ensure_backfill_for_ci_sources_pipelines_pipeline_id_is_finished.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class EnsureBackfillForCiSourcesPipelinesPipelineIdIsFinished < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_sources_pipelines
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: TABLE_NAME,
+ column_name: 'id',
+ job_arguments: [
+ %w[pipeline_id source_pipeline_id],
+ %w[pipeline_id_convert_to_bigint source_pipeline_id_convert_to_bigint]
+ ]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230901044003_add_sync_foreign_key_for_ci_pipeline_variables_pipeline_id.rb b/db/post_migrate/20230901044003_add_sync_foreign_key_for_ci_pipeline_variables_pipeline_id.rb
new file mode 100644
index 00000000000..d640b68c118
--- /dev/null
+++ b/db/post_migrate/20230901044003_add_sync_foreign_key_for_ci_pipeline_variables_pipeline_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddSyncForeignKeyForCiPipelineVariablesPipelineId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_pipeline_variables
+ COLUMN_NAME = :pipeline_id
+ FK_NAME = :temp_fk_rails_8d3b04e3e1
+
+ def up
+ validate_foreign_key TABLE_NAME, COLUMN_NAME, name: FK_NAME
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230901050458_ensure_backfill_for_ci_pipelines_auto_canceled_by_id_is_finished.rb b/db/post_migrate/20230901050458_ensure_backfill_for_ci_pipelines_auto_canceled_by_id_is_finished.rb
new file mode 100644
index 00000000000..ce0da3707d0
--- /dev/null
+++ b/db/post_migrate/20230901050458_ensure_backfill_for_ci_pipelines_auto_canceled_by_id_is_finished.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class EnsureBackfillForCiPipelinesAutoCanceledByIdIsFinished < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_pipelines
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: TABLE_NAME,
+ column_name: 'id',
+ job_arguments: [
+ %w[auto_canceled_by_id],
+ %w[auto_canceled_by_id_convert_to_bigint]
+ ]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230901054536_ensure_backfill_for_ci_pipeline_chat_data_pipeline_id_is_finished.rb b/db/post_migrate/20230901054536_ensure_backfill_for_ci_pipeline_chat_data_pipeline_id_is_finished.rb
new file mode 100644
index 00000000000..e600456662e
--- /dev/null
+++ b/db/post_migrate/20230901054536_ensure_backfill_for_ci_pipeline_chat_data_pipeline_id_is_finished.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class EnsureBackfillForCiPipelineChatDataPipelineIdIsFinished < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_pipeline_chat_data
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: TABLE_NAME,
+ column_name: 'id',
+ job_arguments: [['pipeline_id'], ['pipeline_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230901064536_add_concurrent_index_for_ci_pipeline_chat_data_pipeline_id_convert_to_bigint.rb b/db/post_migrate/20230901064536_add_concurrent_index_for_ci_pipeline_chat_data_pipeline_id_convert_to_bigint.rb
new file mode 100644
index 00000000000..35b5fca789b
--- /dev/null
+++ b/db/post_migrate/20230901064536_add_concurrent_index_for_ci_pipeline_chat_data_pipeline_id_convert_to_bigint.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddConcurrentIndexForCiPipelineChatDataPipelineIdConvertToBigint < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = "index_ci_pipeline_chat_data_on_pipeline_id_convert_to_bigint"
+ TABLE_NAME = :ci_pipeline_chat_data
+ COLUMN_NAME = :pipeline_id_convert_to_bigint
+
+ def up
+ add_concurrent_index TABLE_NAME, COLUMN_NAME, name: INDEX_NAME, unique: true
+ end
+
+ def down
+ remove_concurrent_index_by_name TABLE_NAME, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230901064537_remove_namespace_details_dashboard_fields.rb b/db/post_migrate/20230901064537_remove_namespace_details_dashboard_fields.rb
new file mode 100644
index 00000000000..9dca08c90ef
--- /dev/null
+++ b/db/post_migrate/20230901064537_remove_namespace_details_dashboard_fields.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class RemoveNamespaceDetailsDashboardFields < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def change
+ remove_column :namespace_details, :dashboard_notification_at, :datetime_with_timezone
+ remove_column :namespace_details, :dashboard_enforcement_at, :datetime_with_timezone
+ end
+end
diff --git a/db/post_migrate/20230902033401_create_async_index_for_ci_sources_pipelines_pipeline_id.rb b/db/post_migrate/20230902033401_create_async_index_for_ci_sources_pipelines_pipeline_id.rb
new file mode 100644
index 00000000000..60d26bf1962
--- /dev/null
+++ b/db/post_migrate/20230902033401_create_async_index_for_ci_sources_pipelines_pipeline_id.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class CreateAsyncIndexForCiSourcesPipelinesPipelineId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_sources_pipelines
+ INDEXES = {
+ 'index_ci_sources_pipelines_on_pipeline_id_bigint' => [
+ [:pipeline_id_convert_to_bigint], {}
+ ],
+ 'index_ci_sources_pipelines_on_source_pipeline_id_bigint' => [
+ [:source_pipeline_id_convert_to_bigint], {}
+ ]
+ }
+
+ def up
+ INDEXES.each do |index_name, (columns, options)|
+ prepare_async_index TABLE_NAME, columns, name: index_name, **options
+ end
+ end
+
+ def down
+ INDEXES.each do |index_name, (columns, options)|
+ unprepare_async_index TABLE_NAME, columns, name: index_name, **options
+ end
+ end
+end
diff --git a/db/post_migrate/20230902050458_create_async_index_for_ci_pipelines_auto_canceled_by_id.rb b/db/post_migrate/20230902050458_create_async_index_for_ci_pipelines_auto_canceled_by_id.rb
new file mode 100644
index 00000000000..4eb8ea918b8
--- /dev/null
+++ b/db/post_migrate/20230902050458_create_async_index_for_ci_pipelines_auto_canceled_by_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class CreateAsyncIndexForCiPipelinesAutoCanceledById < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_pipelines
+ INDEX_NAME = 'index_ci_pipelines_on_auto_canceled_by_id_bigint'
+ COLUMN_NAME = :auto_canceled_by_id_convert_to_bigint
+
+ def up
+ prepare_async_index TABLE_NAME, COLUMN_NAME, name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index TABLE_NAME, COLUMN_NAME, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230902054536_ensure_backfill_for_ci_pipeline_messages_pipeline_id_is_finished.rb b/db/post_migrate/20230902054536_ensure_backfill_for_ci_pipeline_messages_pipeline_id_is_finished.rb
new file mode 100644
index 00000000000..41806f14c3d
--- /dev/null
+++ b/db/post_migrate/20230902054536_ensure_backfill_for_ci_pipeline_messages_pipeline_id_is_finished.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class EnsureBackfillForCiPipelineMessagesPipelineIdIsFinished < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_pipeline_messages
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: TABLE_NAME,
+ column_name: 'id',
+ job_arguments: [['pipeline_id'], ['pipeline_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230903064536_concurrent_index_for_ci_pipeline_messages_pipeline_id_convert_to_bigint.rb b/db/post_migrate/20230903064536_concurrent_index_for_ci_pipeline_messages_pipeline_id_convert_to_bigint.rb
new file mode 100644
index 00000000000..0444239d934
--- /dev/null
+++ b/db/post_migrate/20230903064536_concurrent_index_for_ci_pipeline_messages_pipeline_id_convert_to_bigint.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class ConcurrentIndexForCiPipelineMessagesPipelineIdConvertToBigint < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = "index_ci_pipeline_messages_on_pipeline_id_convert_to_bigint"
+ TABLE_NAME = :ci_pipeline_messages
+ COLUMN_NAME = :pipeline_id_convert_to_bigint
+
+ def up
+ add_concurrent_index TABLE_NAME, COLUMN_NAME, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230903064537_add_ci_job_artifacts_file_final_path_index.rb b/db/post_migrate/20230903064537_add_ci_job_artifacts_file_final_path_index.rb
new file mode 100644
index 00000000000..e1e5694f4d4
--- /dev/null
+++ b/db/post_migrate/20230903064537_add_ci_job_artifacts_file_final_path_index.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddCiJobArtifactsFileFinalPathIndex < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_ci_job_artifacts_on_file_final_path'
+ WHERE_CLAUSE = 'file_final_path IS NOT NULL'
+
+ # TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/423990
+ def up
+ prepare_async_index :ci_job_artifacts, :file_final_path, name: INDEX_NAME, where: WHERE_CLAUSE
+ end
+
+ def down
+ unprepare_async_index :ci_job_artifacts, :file_final_path, name: INDEX_NAME, where: WHERE_CLAUSE
+ end
+end
diff --git a/db/post_migrate/20230904100544_drop_index_deployments_on_id_where_cluster_id_present.rb b/db/post_migrate/20230904100544_drop_index_deployments_on_id_where_cluster_id_present.rb
new file mode 100644
index 00000000000..888fb7da9c3
--- /dev/null
+++ b/db/post_migrate/20230904100544_drop_index_deployments_on_id_where_cluster_id_present.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class DropIndexDeploymentsOnIdWhereClusterIdPresent < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_deployments_on_id_where_cluster_id_present'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :deployments, name: INDEX_NAME
+ end
+
+ def down
+ # This is based on the following `CREATE INDEX` command in db/init_structure.sql:
+ # CREATE INDEX index_deployments_on_id_where_cluster_id_present ON deployments
+ # USING btree (id) WHERE (cluster_id IS NOT NULL);
+ add_concurrent_index :deployments, :id, name: INDEX_NAME, where: 'cluster_id IS NOT NULL'
+ end
+end
diff --git a/db/post_migrate/20230904103804_drop_index_successful_deployments_on_cluster_id_and_environment_id.rb b/db/post_migrate/20230904103804_drop_index_successful_deployments_on_cluster_id_and_environment_id.rb
new file mode 100644
index 00000000000..e8f0a7b30b5
--- /dev/null
+++ b/db/post_migrate/20230904103804_drop_index_successful_deployments_on_cluster_id_and_environment_id.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class DropIndexSuccessfulDeploymentsOnClusterIdAndEnvironmentId < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_successful_deployments_on_cluster_id_and_environment_id'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :deployments, name: INDEX_NAME
+ end
+
+ def down
+ # This is based on the following `CREATE INDEX` command in db/init_structure.sql:
+ # CREATE INDEX index_successful_deployments_on_cluster_id_and_environment_id ON deployments
+ # USING btree (cluster_id, environment_id) WHERE (status = 2);
+ add_concurrent_index :deployments, %i[cluster_id environment_id], name: INDEX_NAME, where: 'status = 2'
+ end
+end
diff --git a/db/post_migrate/20230905071915_prepare_async_foreign_key_for_ci_pipeline_messages_pipeline_id_bigint.rb b/db/post_migrate/20230905071915_prepare_async_foreign_key_for_ci_pipeline_messages_pipeline_id_bigint.rb
new file mode 100644
index 00000000000..ce576704d4c
--- /dev/null
+++ b/db/post_migrate/20230905071915_prepare_async_foreign_key_for_ci_pipeline_messages_pipeline_id_bigint.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class PrepareAsyncForeignKeyForCiPipelineMessagesPipelineIdBigint < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :ci_pipeline_messages
+ COLUMN_NAME = :pipeline_id_convert_to_bigint
+ FK_NAME = :fk_0946fea681
+
+ def up
+ prepare_async_foreign_key_validation TABLE_NAME, COLUMN_NAME, name: FK_NAME
+ end
+
+ def down
+ unprepare_async_foreign_key_validation TABLE_NAME, COLUMN_NAME, name: FK_NAME
+ end
+end
diff --git a/db/post_migrate/20230905091059_sync_index_for_ci_stages_pipeline_id_bigint.rb b/db/post_migrate/20230905091059_sync_index_for_ci_stages_pipeline_id_bigint.rb
new file mode 100644
index 00000000000..2c42782c576
--- /dev/null
+++ b/db/post_migrate/20230905091059_sync_index_for_ci_stages_pipeline_id_bigint.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class SyncIndexForCiStagesPipelineIdBigint < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_stages
+ INDEXES = {
+ 'index_ci_stages_on_pipeline_id_convert_to_bigint_and_name' => [
+ [:pipeline_id_convert_to_bigint, :name], { unique: true }
+ ],
+ 'index_ci_stages_on_pipeline_id_convert_to_bigint' => [
+ [:pipeline_id_convert_to_bigint], {}
+ ],
+ 'index_ci_stages_on_pipeline_id_convert_to_bigint_and_id' => [
+ [:pipeline_id_convert_to_bigint, :id], { where: 'status = ANY (ARRAY[0, 1, 2, 8, 9, 10])' }
+ ],
+ 'index_ci_stages_on_pipeline_id_convert_to_bigint_and_position' => [
+ [:pipeline_id_convert_to_bigint, :position], {}
+ ]
+ }
+
+ def up
+ INDEXES.each do |index_name, (columns, options)|
+ add_concurrent_index TABLE_NAME, columns, name: index_name, **options
+ end
+ end
+
+ def down
+ INDEXES.each do |index_name, (_columns, _options)|
+ remove_concurrent_index_by_name TABLE_NAME, index_name
+ end
+ end
+end
diff --git a/db/post_migrate/20230906181457_add_index_to_violations_on_target_proj_id.rb b/db/post_migrate/20230906181457_add_index_to_violations_on_target_proj_id.rb
new file mode 100644
index 00000000000..13c76a3c2de
--- /dev/null
+++ b/db/post_migrate/20230906181457_add_index_to_violations_on_target_proj_id.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddIndexToViolationsOnTargetProjId < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = 'merge_requests_compliance_violations'
+ # Use funciton based naming as suggested in docs:
+ # https://docs.gitlab.com/ee/development/migration_style_guide.html#truncate-long-index-names
+ INDEX_NAME = 'i_compliance_violations_for_export'
+
+ def up
+ prepare_async_index TABLE_NAME, [:target_project_id, :id], name: INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index TABLE_NAME, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230907155247_queue_backfill_has_merge_request_of_vulnerability_reads.rb b/db/post_migrate/20230907155247_queue_backfill_has_merge_request_of_vulnerability_reads.rb
new file mode 100644
index 00000000000..fe939b4aaa0
--- /dev/null
+++ b/db/post_migrate/20230907155247_queue_backfill_has_merge_request_of_vulnerability_reads.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class QueueBackfillHasMergeRequestOfVulnerabilityReads < Gitlab::Database::Migration[2.1]
+ MIGRATION_NAME = 'BackfillHasMergeRequestOfVulnerabilityReads'
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 10_000
+ SUB_BATCH_SIZE = 200
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION_NAME,
+ :vulnerability_reads,
+ :vulnerability_id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION_NAME, :vulnerability_reads, :vulnerability_id, [])
+ end
+end
diff --git a/db/post_migrate/20230907204731_add_index_to_sbom_occurrences_licenses.rb b/db/post_migrate/20230907204731_add_index_to_sbom_occurrences_licenses.rb
new file mode 100644
index 00000000000..9ed60941c96
--- /dev/null
+++ b/db/post_migrate/20230907204731_add_index_to_sbom_occurrences_licenses.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class AddIndexToSbomOccurrencesLicenses < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = "index_sbom_occurrences_on_licenses_spdx_identifier"
+
+ disable_ddl_transaction!
+
+ def up
+ return if index_exists_by_name?(:sbom_occurrences, INDEX_NAME)
+
+ disable_statement_timeout do
+ execute <<~SQL
+ CREATE INDEX CONCURRENTLY #{INDEX_NAME}
+ ON sbom_occurrences
+ USING BTREE (project_id, (licenses#>'{0,spdx_identifier}'), (licenses#>'{1,spdx_identifier}'))
+ SQL
+ end
+ end
+
+ def down
+ remove_concurrent_index_by_name :sbom_occurrences, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230908072558_analyze_p_ci_runner_machine_builds.rb b/db/post_migrate/20230908072558_analyze_p_ci_runner_machine_builds.rb
new file mode 100644
index 00000000000..5fb99640764
--- /dev/null
+++ b/db/post_migrate/20230908072558_analyze_p_ci_runner_machine_builds.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AnalyzePCiRunnerMachineBuilds < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ disable_statement_timeout do
+ execute('ANALYZE VERBOSE p_ci_runner_machine_builds;')
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230908072612_analyze_p_ci_job_annotations.rb b/db/post_migrate/20230908072612_analyze_p_ci_job_annotations.rb
new file mode 100644
index 00000000000..7bdc1dcb58d
--- /dev/null
+++ b/db/post_migrate/20230908072612_analyze_p_ci_job_annotations.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AnalyzePCiJobAnnotations < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ disable_statement_timeout do
+ execute('ANALYZE VERBOSE p_ci_job_annotations;')
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230908072626_analyze_p_ci_builds_metadata.rb b/db/post_migrate/20230908072626_analyze_p_ci_builds_metadata.rb
new file mode 100644
index 00000000000..4ba75d9e6bd
--- /dev/null
+++ b/db/post_migrate/20230908072626_analyze_p_ci_builds_metadata.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AnalyzePCiBuildsMetadata < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ disable_statement_timeout do
+ execute('ANALYZE VERBOSE p_ci_builds_metadata;')
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230908072639_analyze_p_ci_builds.rb b/db/post_migrate/20230908072639_analyze_p_ci_builds.rb
new file mode 100644
index 00000000000..f1c68b657b9
--- /dev/null
+++ b/db/post_migrate/20230908072639_analyze_p_ci_builds.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AnalyzePCiBuilds < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ disable_statement_timeout do
+ execute('ANALYZE VERBOSE p_ci_builds;')
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20230909120000_queue_backfill_workspace_personal_access_token.rb b/db/post_migrate/20230909120000_queue_backfill_workspace_personal_access_token.rb
new file mode 100644
index 00000000000..5a746d97493
--- /dev/null
+++ b/db/post_migrate/20230909120000_queue_backfill_workspace_personal_access_token.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class QueueBackfillWorkspacePersonalAccessToken < Gitlab::Database::Migration[2.1]
+ MIGRATION = "BackfillWorkspacePersonalAccessToken"
+ DELAY_INTERVAL = 2.minutes
+ BATCH_SIZE = 100
+ SUB_BATCH_SIZE = 10
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :workspaces,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :workspaces, :id, [])
+ end
+end
diff --git a/db/post_migrate/20230913100953_create_supporting_index_for_uuid_type_casting.rb b/db/post_migrate/20230913100953_create_supporting_index_for_uuid_type_casting.rb
new file mode 100644
index 00000000000..232aca06bb2
--- /dev/null
+++ b/db/post_migrate/20230913100953_create_supporting_index_for_uuid_type_casting.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class CreateSupportingIndexForUuidTypeCasting < Gitlab::Database::Migration[2.1]
+ TABLE_NAME = :vulnerability_occurrences
+ INDEX_NAME = "tmp_index_vulnerability_occurrences_uuid_cast"
+
+ def up
+ index_sql = <<~SQL
+ CREATE INDEX CONCURRENTLY #{INDEX_NAME}
+ ON #{TABLE_NAME}((uuid::uuid))
+ SQL
+
+ # TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/425037
+ prepare_async_index_from_sql(index_sql)
+ end
+
+ def down
+ unprepare_async_index_by_name(
+ TABLE_NAME,
+ INDEX_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20230913115113_add_prepared_at_created_at_index_async.rb b/db/post_migrate/20230913115113_add_prepared_at_created_at_index_async.rb
new file mode 100644
index 00000000000..2e751463f8b
--- /dev/null
+++ b/db/post_migrate/20230913115113_add_prepared_at_created_at_index_async.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddPreparedAtCreatedAtIndexAsync < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_merge_requests_id_created_at_prepared_at'
+
+ def up
+ add_concurrent_index :merge_requests, [:created_at, :id], name: INDEX_NAME, where: "prepared_at IS NULL"
+ end
+
+ def down
+ remove_concurrent_index_by_name :merge_requests, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230913120111_remove_prepared_at_created_at_index_async.rb b/db/post_migrate/20230913120111_remove_prepared_at_created_at_index_async.rb
new file mode 100644
index 00000000000..8507ebfe1ec
--- /dev/null
+++ b/db/post_migrate/20230913120111_remove_prepared_at_created_at_index_async.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class RemovePreparedAtCreatedAtIndexAsync < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_merge_requests_on_id_and_prepared_at'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :merge_requests, name: INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :merge_requests, :id, name: INDEX_NAME, where: "prepared_at IS NULL"
+ end
+end
diff --git a/db/post_migrate/20230913130629_index_org_id_on_projects.rb b/db/post_migrate/20230913130629_index_org_id_on_projects.rb
new file mode 100644
index 00000000000..45186b900c6
--- /dev/null
+++ b/db/post_migrate/20230913130629_index_org_id_on_projects.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class IndexOrgIdOnProjects < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_projects_on_organization_id'
+
+ def up
+ add_concurrent_index :projects, :organization_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :projects, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230913175529_add_index_on_merge_requests_target_project_id_and_merged_commit_sha.rb b/db/post_migrate/20230913175529_add_index_on_merge_requests_target_project_id_and_merged_commit_sha.rb
new file mode 100644
index 00000000000..33fe6538f9b
--- /dev/null
+++ b/db/post_migrate/20230913175529_add_index_on_merge_requests_target_project_id_and_merged_commit_sha.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddIndexOnMergeRequestsTargetProjectIdAndMergedCommitSha < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_merge_requests_on_target_project_id_and_merged_commit_sha'
+ INDEX_COLUMNS = %i[target_project_id merged_commit_sha]
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :merge_requests, INDEX_COLUMNS, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :merge_requests, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20230914054914_index_finding_id_for_vulnerabilities_sync.rb b/db/post_migrate/20230914054914_index_finding_id_for_vulnerabilities_sync.rb
new file mode 100644
index 00000000000..37cd13a4dfa
--- /dev/null
+++ b/db/post_migrate/20230914054914_index_finding_id_for_vulnerabilities_sync.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class IndexFindingIdForVulnerabilitiesSync < Gitlab::Database::Migration[2.1]
+ INDEX_NAME = 'index_vulnerabilities_on_finding_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :vulnerabilities, :finding_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerabilities, INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20230728020644 b/db/schema_migrations/20230728020644
new file mode 100644
index 00000000000..6e3ee922f7e
--- /dev/null
+++ b/db/schema_migrations/20230728020644
@@ -0,0 +1 @@
+95970e866bfd4815f156b9392f8e975152f531edb91407e2b09eb817dcebd294 \ No newline at end of file
diff --git a/db/schema_migrations/20230802205051 b/db/schema_migrations/20230802205051
new file mode 100644
index 00000000000..3f09a569f68
--- /dev/null
+++ b/db/schema_migrations/20230802205051
@@ -0,0 +1 @@
+f682f6c1dd19fa508282bfcd30e61197652bf14b4f0717ef2313a920f0eb3516 \ No newline at end of file
diff --git a/db/schema_migrations/20230802212443 b/db/schema_migrations/20230802212443
new file mode 100644
index 00000000000..2d3b2e3b504
--- /dev/null
+++ b/db/schema_migrations/20230802212443
@@ -0,0 +1 @@
+ab5b2cd527a1eb799f7f1c3d2f48c850853e498e50693dbe8148c08d52465da8 \ No newline at end of file
diff --git a/db/schema_migrations/20230804055559 b/db/schema_migrations/20230804055559
new file mode 100644
index 00000000000..b6bdc60228b
--- /dev/null
+++ b/db/schema_migrations/20230804055559
@@ -0,0 +1 @@
+f450a78fe52af85d9e91c26b1e23d825e2a78f251173c801dcc6e9ebcc79437f \ No newline at end of file
diff --git a/db/schema_migrations/20230804122825 b/db/schema_migrations/20230804122825
new file mode 100644
index 00000000000..ec59e1dbb30
--- /dev/null
+++ b/db/schema_migrations/20230804122825
@@ -0,0 +1 @@
+9db599bb939f27e81035c8aa22ae7fbb4d1376f5a9075b684b109d15da312faf \ No newline at end of file
diff --git a/db/schema_migrations/20230804123252 b/db/schema_migrations/20230804123252
new file mode 100644
index 00000000000..5e1e5cf0c9d
--- /dev/null
+++ b/db/schema_migrations/20230804123252
@@ -0,0 +1 @@
+a0c3883429cee1f9a3f170d3a563f9390937dba5cab2b661dc583aa7ffe1479f \ No newline at end of file
diff --git a/db/schema_migrations/20230807035953 b/db/schema_migrations/20230807035953
new file mode 100644
index 00000000000..562bb05a5eb
--- /dev/null
+++ b/db/schema_migrations/20230807035953
@@ -0,0 +1 @@
+998695a3c22394e5e08ac61841ac2255e717b0cc5a50baeabb682d91b3f42f28 \ No newline at end of file
diff --git a/db/schema_migrations/20230808200355 b/db/schema_migrations/20230808200355
new file mode 100644
index 00000000000..7b8744f5de7
--- /dev/null
+++ b/db/schema_migrations/20230808200355
@@ -0,0 +1 @@
+00235898dc10fe690e99e6ab6b1b6da61806158ad0be2d4b714a8f8076f71cba \ No newline at end of file
diff --git a/db/schema_migrations/20230809170822 b/db/schema_migrations/20230809170822
new file mode 100644
index 00000000000..a9afcc9bc3e
--- /dev/null
+++ b/db/schema_migrations/20230809170822
@@ -0,0 +1 @@
+ef3db107d68a95cda1e0cd35e26b1fd8d60d7b514f178bc4220b31c33bd1d3ba \ No newline at end of file
diff --git a/db/schema_migrations/20230809174702 b/db/schema_migrations/20230809174702
new file mode 100644
index 00000000000..e9f189710b0
--- /dev/null
+++ b/db/schema_migrations/20230809174702
@@ -0,0 +1 @@
+3c6ee8e7ccb543776a5081c9bc15e64a6c1b3b66c7bf019c7d91e25ec05156f9 \ No newline at end of file
diff --git a/db/schema_migrations/20230809203254 b/db/schema_migrations/20230809203254
new file mode 100644
index 00000000000..3f290c4f595
--- /dev/null
+++ b/db/schema_migrations/20230809203254
@@ -0,0 +1 @@
+19058c7442d020d7db5f0a8ec386adc27ce157254a9e00b42b1fa49551c2e585 \ No newline at end of file
diff --git a/db/schema_migrations/20230809210550 b/db/schema_migrations/20230809210550
new file mode 100644
index 00000000000..2a946c5a417
--- /dev/null
+++ b/db/schema_migrations/20230809210550
@@ -0,0 +1 @@
+b9a09d4b6cdfe5ac7e380af43b9e9ee508f90aecdaf03dbfbc348a966a4332fc \ No newline at end of file
diff --git a/db/schema_migrations/20230810112715 b/db/schema_migrations/20230810112715
new file mode 100644
index 00000000000..db0284c512a
--- /dev/null
+++ b/db/schema_migrations/20230810112715
@@ -0,0 +1 @@
+2176e2862d6445962f34c537dd00025fb5efbb6a55af90ca54f41dd7de18b897 \ No newline at end of file
diff --git a/db/schema_migrations/20230810113227 b/db/schema_migrations/20230810113227
new file mode 100644
index 00000000000..4175be45260
--- /dev/null
+++ b/db/schema_migrations/20230810113227
@@ -0,0 +1 @@
+e18df398f3e6146fd59bde7070d9b082be66ea315976e85817dc7ef63b8ab3bd \ No newline at end of file
diff --git a/db/schema_migrations/20230810124545 b/db/schema_migrations/20230810124545
new file mode 100644
index 00000000000..d06862bc14d
--- /dev/null
+++ b/db/schema_migrations/20230810124545
@@ -0,0 +1 @@
+a625f5fcd0e2b98b2e239f3ca6cb98255385e0c0a7413c62fef647baf0ff16e5 \ No newline at end of file
diff --git a/db/schema_migrations/20230811103457 b/db/schema_migrations/20230811103457
new file mode 100644
index 00000000000..731c2f7c296
--- /dev/null
+++ b/db/schema_migrations/20230811103457
@@ -0,0 +1 @@
+6c252953fc80ec7618d2012c77064541ba522f77f7573130ca39ca7d915ae483 \ No newline at end of file
diff --git a/db/schema_migrations/20230811144601 b/db/schema_migrations/20230811144601
new file mode 100644
index 00000000000..081cfc6300e
--- /dev/null
+++ b/db/schema_migrations/20230811144601
@@ -0,0 +1 @@
+ae7064351489b677c9b70f308f32e6e78473c4c5814901eea14c5669bb55194e \ No newline at end of file
diff --git a/db/schema_migrations/20230811185901 b/db/schema_migrations/20230811185901
new file mode 100644
index 00000000000..5d8880e6d12
--- /dev/null
+++ b/db/schema_migrations/20230811185901
@@ -0,0 +1 @@
+7a773942b3b4364ff5148947795823ab0755339d23762e1002e8ab7887cacfb6 \ No newline at end of file
diff --git a/db/schema_migrations/20230811211544 b/db/schema_migrations/20230811211544
new file mode 100644
index 00000000000..4fe3af17b1b
--- /dev/null
+++ b/db/schema_migrations/20230811211544
@@ -0,0 +1 @@
+367b6768d68246169cabe9b618b2792eded9d8abcd61fb8ac40748cd83c01f9d \ No newline at end of file
diff --git a/db/schema_migrations/20230814181359 b/db/schema_migrations/20230814181359
new file mode 100644
index 00000000000..17086601248
--- /dev/null
+++ b/db/schema_migrations/20230814181359
@@ -0,0 +1 @@
+2765c209b9347c0c76257a1af473edd6aebdc3f8d6dce3eed4d089e700c36808 \ No newline at end of file
diff --git a/db/schema_migrations/20230814203548 b/db/schema_migrations/20230814203548
new file mode 100644
index 00000000000..d89fd043347
--- /dev/null
+++ b/db/schema_migrations/20230814203548
@@ -0,0 +1 @@
+0822d768380c459e390828924e6723a4a878cd217b1159f2d8ab12f78718fef7 \ No newline at end of file
diff --git a/db/schema_migrations/20230815072912 b/db/schema_migrations/20230815072912
new file mode 100644
index 00000000000..f6aa821b887
--- /dev/null
+++ b/db/schema_migrations/20230815072912
@@ -0,0 +1 @@
+7d72f7d7bc5e09cd47530f11b1f40046dd7285edc71739024633daf937731d7c \ No newline at end of file
diff --git a/db/schema_migrations/20230815140656 b/db/schema_migrations/20230815140656
new file mode 100644
index 00000000000..683b5ae1cf5
--- /dev/null
+++ b/db/schema_migrations/20230815140656
@@ -0,0 +1 @@
+bd13139ed2eb68087515102fa647fe870e69f1ad91a0f4a2db57d59d6ce4e308 \ No newline at end of file
diff --git a/db/schema_migrations/20230815160428 b/db/schema_migrations/20230815160428
new file mode 100644
index 00000000000..ebc6b6b181d
--- /dev/null
+++ b/db/schema_migrations/20230815160428
@@ -0,0 +1 @@
+df42fc7fca6b286929f74bec819d0a79df21c88a09b3e7b5c409666dacde7776 \ No newline at end of file
diff --git a/db/schema_migrations/20230816111730 b/db/schema_migrations/20230816111730
new file mode 100644
index 00000000000..dbced9d469e
--- /dev/null
+++ b/db/schema_migrations/20230816111730
@@ -0,0 +1 @@
+a9bf0899e31d9652a2db14f33b17d120354662b44c21931bf9d04287baf82890 \ No newline at end of file
diff --git a/db/schema_migrations/20230816152540 b/db/schema_migrations/20230816152540
new file mode 100644
index 00000000000..599d608ce7c
--- /dev/null
+++ b/db/schema_migrations/20230816152540
@@ -0,0 +1 @@
+29d6dd16a743370a09774a2ec1887ab1a82c69c3d8a41e1b4ad3f632c6d7c006 \ No newline at end of file
diff --git a/db/schema_migrations/20230816152639 b/db/schema_migrations/20230816152639
new file mode 100644
index 00000000000..a0ee85c0e5c
--- /dev/null
+++ b/db/schema_migrations/20230816152639
@@ -0,0 +1 @@
+10e1a3a85c6ce4fa2fca10c1b95b8ba2775c1abe98360f27638878dda282d6d0 \ No newline at end of file
diff --git a/db/schema_migrations/20230816210052 b/db/schema_migrations/20230816210052
new file mode 100644
index 00000000000..d9ea0cc5445
--- /dev/null
+++ b/db/schema_migrations/20230816210052
@@ -0,0 +1 @@
+1d3d6acf9ec3bac7a4878570db79d1e0771760ff503acd9d333a04d4725c7e8a \ No newline at end of file
diff --git a/db/schema_migrations/20230816210503 b/db/schema_migrations/20230816210503
new file mode 100644
index 00000000000..de91e24153a
--- /dev/null
+++ b/db/schema_migrations/20230816210503
@@ -0,0 +1 @@
+2cdfb4fa3c4798123c14995f5dfdb1b55e163d290a566e6c6de922e22c84316a \ No newline at end of file
diff --git a/db/schema_migrations/20230816213228 b/db/schema_migrations/20230816213228
new file mode 100644
index 00000000000..9b41353e15d
--- /dev/null
+++ b/db/schema_migrations/20230816213228
@@ -0,0 +1 @@
+c0726a34eb21a269b85290b4aa56d05abb83d293ba7b8c9a97ea62ccba6e31c6 \ No newline at end of file
diff --git a/db/schema_migrations/20230817040352 b/db/schema_migrations/20230817040352
new file mode 100644
index 00000000000..120154c123e
--- /dev/null
+++ b/db/schema_migrations/20230817040352
@@ -0,0 +1 @@
+0a51924454fb9fa8dbc4c7b757ef8f75afba9d45ade4b5a6afcc3885e95d3cdd \ No newline at end of file
diff --git a/db/schema_migrations/20230817050946 b/db/schema_migrations/20230817050946
new file mode 100644
index 00000000000..bfbc11fb3c5
--- /dev/null
+++ b/db/schema_migrations/20230817050946
@@ -0,0 +1 @@
+9c51f4c28764dcb2e6ed5edcb485e9ff2c17973e6aad114cbf4ea816b7c6adb7 \ No newline at end of file
diff --git a/db/schema_migrations/20230817111753 b/db/schema_migrations/20230817111753
new file mode 100644
index 00000000000..17457915ace
--- /dev/null
+++ b/db/schema_migrations/20230817111753
@@ -0,0 +1 @@
+707bddb67e80158cf8f6703a87b6b7a98a651db5df7c356142e8512b0e4d7cde \ No newline at end of file
diff --git a/db/schema_migrations/20230817111938 b/db/schema_migrations/20230817111938
new file mode 100644
index 00000000000..55498b7810e
--- /dev/null
+++ b/db/schema_migrations/20230817111938
@@ -0,0 +1 @@
+c59a6161044f4b75e031159e84028eb8c823dfc8f32b6b743fb7278820b41ed9 \ No newline at end of file
diff --git a/db/schema_migrations/20230817143507 b/db/schema_migrations/20230817143507
new file mode 100644
index 00000000000..ec53ef74b86
--- /dev/null
+++ b/db/schema_migrations/20230817143507
@@ -0,0 +1 @@
+318ae2c0b908b7d787d2df5908096d0f083091ef3d3b598ad3c84e66024b34cc \ No newline at end of file
diff --git a/db/schema_migrations/20230817143637 b/db/schema_migrations/20230817143637
new file mode 100644
index 00000000000..a9776491277
--- /dev/null
+++ b/db/schema_migrations/20230817143637
@@ -0,0 +1 @@
+eb9ba746c27c748a2e17d5e99303c8fae208e7252b79eec57ef3dc4b79a7ccb9 \ No newline at end of file
diff --git a/db/schema_migrations/20230818034041 b/db/schema_migrations/20230818034041
new file mode 100644
index 00000000000..440904ac7b5
--- /dev/null
+++ b/db/schema_migrations/20230818034041
@@ -0,0 +1 @@
+4b27c841210115277f4d49efc56ac834a7ba8b2afb351e0df45443f14cc01484 \ No newline at end of file
diff --git a/db/schema_migrations/20230818050946 b/db/schema_migrations/20230818050946
new file mode 100644
index 00000000000..bdcb018f789
--- /dev/null
+++ b/db/schema_migrations/20230818050946
@@ -0,0 +1 @@
+ad22f41707b094bd7002ddcfa378437c4599a55bbfef12bb66f2775678c3c785 \ No newline at end of file
diff --git a/db/schema_migrations/20230818055517 b/db/schema_migrations/20230818055517
new file mode 100644
index 00000000000..14c3821d426
--- /dev/null
+++ b/db/schema_migrations/20230818055517
@@ -0,0 +1 @@
+0dd37cf1da3ff0f56f24a41dd76ef7cb789e0833a6ea73b773f56a8a3793c465 \ No newline at end of file
diff --git a/db/schema_migrations/20230818083610 b/db/schema_migrations/20230818083610
new file mode 100644
index 00000000000..fb93a7be2a2
--- /dev/null
+++ b/db/schema_migrations/20230818083610
@@ -0,0 +1 @@
+f780f4f4229f73adf3c71436b793a5b5b5c03d8cb16941e2e1f2bc5e68b67f65 \ No newline at end of file
diff --git a/db/schema_migrations/20230818085219 b/db/schema_migrations/20230818085219
new file mode 100644
index 00000000000..f4e60ba7e60
--- /dev/null
+++ b/db/schema_migrations/20230818085219
@@ -0,0 +1 @@
+c69e2ffe6f6bec22fb182a5fc26c02717a1546f31777cc8167103639c0e48c65 \ No newline at end of file
diff --git a/db/schema_migrations/20230818142801 b/db/schema_migrations/20230818142801
new file mode 100644
index 00000000000..d79f1e996e5
--- /dev/null
+++ b/db/schema_migrations/20230818142801
@@ -0,0 +1 @@
+6f2bb9c136104e86929921263bd01315bf8acaf19ae05bf28cce3e973dce0020 \ No newline at end of file
diff --git a/db/schema_migrations/20230821000001 b/db/schema_migrations/20230821000001
new file mode 100644
index 00000000000..335a019ce21
--- /dev/null
+++ b/db/schema_migrations/20230821000001
@@ -0,0 +1 @@
+30eb1215fb4411780a722c0d49b7e30316200459dd91f67525f4ae5894aa1acc \ No newline at end of file
diff --git a/db/schema_migrations/20230821000002 b/db/schema_migrations/20230821000002
new file mode 100644
index 00000000000..ed24b64020d
--- /dev/null
+++ b/db/schema_migrations/20230821000002
@@ -0,0 +1 @@
+ff4aafeb32b4e09ec8344afa8684fda2fd2131a8d4b8f82806a0ca5341beef59 \ No newline at end of file
diff --git a/db/schema_migrations/20230821000003 b/db/schema_migrations/20230821000003
new file mode 100644
index 00000000000..395186ab4f1
--- /dev/null
+++ b/db/schema_migrations/20230821000003
@@ -0,0 +1 @@
+5ece2c99a97204a2888f5951d4cd2b16a75e47e395c8a09fa16f151e7d28e16c \ No newline at end of file
diff --git a/db/schema_migrations/20230821081508 b/db/schema_migrations/20230821081508
new file mode 100644
index 00000000000..de0d669afa0
--- /dev/null
+++ b/db/schema_migrations/20230821081508
@@ -0,0 +1 @@
+0ace0ef585fd504fb21c78eb991aacdd8594e241a88f19cf8ccf425543282291 \ No newline at end of file
diff --git a/db/schema_migrations/20230821081603 b/db/schema_migrations/20230821081603
new file mode 100644
index 00000000000..7c28a92d407
--- /dev/null
+++ b/db/schema_migrations/20230821081603
@@ -0,0 +1 @@
+b4d84617b843566df3e8470150affa3e3a5c0fdb5fa53fbdd8e86f4dbf25a128 \ No newline at end of file
diff --git a/db/schema_migrations/20230821101010 b/db/schema_migrations/20230821101010
new file mode 100644
index 00000000000..32ce19db417
--- /dev/null
+++ b/db/schema_migrations/20230821101010
@@ -0,0 +1 @@
+84586d94a586664bf049782d354b240998217fff131d3ab19b793da6333ee844 \ No newline at end of file
diff --git a/db/schema_migrations/20230821133549 b/db/schema_migrations/20230821133549
new file mode 100644
index 00000000000..5025710f689
--- /dev/null
+++ b/db/schema_migrations/20230821133549
@@ -0,0 +1 @@
+57f97aa12f9a41286512b32b1d038d246139cd7ae3852f1642960187643bffb3 \ No newline at end of file
diff --git a/db/schema_migrations/20230822064649 b/db/schema_migrations/20230822064649
new file mode 100644
index 00000000000..449dd984431
--- /dev/null
+++ b/db/schema_migrations/20230822064649
@@ -0,0 +1 @@
+b892940441125e854d08e24906e4b6287f8359b4ad374be5b141b43cfdcc1354 \ No newline at end of file
diff --git a/db/schema_migrations/20230822064841 b/db/schema_migrations/20230822064841
new file mode 100644
index 00000000000..2922af9c573
--- /dev/null
+++ b/db/schema_migrations/20230822064841
@@ -0,0 +1 @@
+e025eb64ab8b9ece1a18c845024db272a1859757734948609c134f6dfee93884 \ No newline at end of file
diff --git a/db/schema_migrations/20230822104028 b/db/schema_migrations/20230822104028
new file mode 100644
index 00000000000..9bb861f45de
--- /dev/null
+++ b/db/schema_migrations/20230822104028
@@ -0,0 +1 @@
+d37694e80d032f8bdfe25838ad7815bdafb0d901592f5e9dceb57e1b9d823680 \ No newline at end of file
diff --git a/db/schema_migrations/20230822125256 b/db/schema_migrations/20230822125256
new file mode 100644
index 00000000000..724b2e31bd4
--- /dev/null
+++ b/db/schema_migrations/20230822125256
@@ -0,0 +1 @@
+a80bf5eeb8bbcee7d751eb4cd68c3a9abd2e5e356c0677f1ed5bbf679bd1656c \ No newline at end of file
diff --git a/db/schema_migrations/20230822151454 b/db/schema_migrations/20230822151454
new file mode 100644
index 00000000000..1559d514b40
--- /dev/null
+++ b/db/schema_migrations/20230822151454
@@ -0,0 +1 @@
+8ff557100904684180b732d0ac50e1ac23029ef47d1ab8816cfc82108313ba37 \ No newline at end of file
diff --git a/db/schema_migrations/20230822153124 b/db/schema_migrations/20230822153124
new file mode 100644
index 00000000000..92ba1bb950d
--- /dev/null
+++ b/db/schema_migrations/20230822153124
@@ -0,0 +1 @@
+d113cced39c0307a7648325bedc0f78ebaa775fcdc1a8ff4ee8caa4fbf1c9c57 \ No newline at end of file
diff --git a/db/schema_migrations/20230822154640 b/db/schema_migrations/20230822154640
new file mode 100644
index 00000000000..c816a8c5633
--- /dev/null
+++ b/db/schema_migrations/20230822154640
@@ -0,0 +1 @@
+9d9a99ad2fb472d71f625cb7cc668d096b88b12064a9a14ac556f490127b1806 \ No newline at end of file
diff --git a/db/schema_migrations/20230822175304 b/db/schema_migrations/20230822175304
new file mode 100644
index 00000000000..f858b7074f3
--- /dev/null
+++ b/db/schema_migrations/20230822175304
@@ -0,0 +1 @@
+4feff19bb2ff05dbf4bc673ced92d1d7b7c5d337cd8895ab490634ea42a6a349 \ No newline at end of file
diff --git a/db/schema_migrations/20230822195852 b/db/schema_migrations/20230822195852
new file mode 100644
index 00000000000..2410010c76e
--- /dev/null
+++ b/db/schema_migrations/20230822195852
@@ -0,0 +1 @@
+a4550541c62863f6f0c90da330ec90f9a0b903dcc20ef697cc9f187124bdc9cc \ No newline at end of file
diff --git a/db/schema_migrations/20230823085627 b/db/schema_migrations/20230823085627
new file mode 100644
index 00000000000..484ba75de96
--- /dev/null
+++ b/db/schema_migrations/20230823085627
@@ -0,0 +1 @@
+16179991d3c17f0d74c82002ded6046675b27f5d7bfc9ad91cf9bf065543b7c2 \ No newline at end of file
diff --git a/db/schema_migrations/20230823090001 b/db/schema_migrations/20230823090001
new file mode 100644
index 00000000000..3c7a44ede56
--- /dev/null
+++ b/db/schema_migrations/20230823090001
@@ -0,0 +1 @@
+5eea44d2b1a595dbee2d36a445950282e7f647bfdda3d2884bcac252e9f865ce \ No newline at end of file
diff --git a/db/schema_migrations/20230823132142 b/db/schema_migrations/20230823132142
new file mode 100644
index 00000000000..2ea42285c0e
--- /dev/null
+++ b/db/schema_migrations/20230823132142
@@ -0,0 +1 @@
+438ce9b705e575c139724a2ad81e799bdda63b9428b4cf3bd21b9e47df36ece7 \ No newline at end of file
diff --git a/db/schema_migrations/20230823140934 b/db/schema_migrations/20230823140934
new file mode 100644
index 00000000000..2bc3734026b
--- /dev/null
+++ b/db/schema_migrations/20230823140934
@@ -0,0 +1 @@
+9dd2bca54c0f9560719887dae87b54edd10f01ea3a831141b80a3d2364a4eddf \ No newline at end of file
diff --git a/db/schema_migrations/20230823143519 b/db/schema_migrations/20230823143519
new file mode 100644
index 00000000000..9e6e12223cb
--- /dev/null
+++ b/db/schema_migrations/20230823143519
@@ -0,0 +1 @@
+91d69bff151e7bd0ea542199eaa3550b09c4ccbcff41714d31ceacc151c990ff \ No newline at end of file
diff --git a/db/schema_migrations/20230823144846 b/db/schema_migrations/20230823144846
new file mode 100644
index 00000000000..df570031dc0
--- /dev/null
+++ b/db/schema_migrations/20230823144846
@@ -0,0 +1 @@
+eee2ddb8ebb459f2d7cb8144786f373604e33f4aa31b70f9709e2422bbf5c896 \ No newline at end of file
diff --git a/db/schema_migrations/20230823145053 b/db/schema_migrations/20230823145053
new file mode 100644
index 00000000000..7f98e2ead36
--- /dev/null
+++ b/db/schema_migrations/20230823145053
@@ -0,0 +1 @@
+e7850fcaf7a1e95025d065fcb85a02872970cdfd3ab9886cb5e8dccd002735f6 \ No newline at end of file
diff --git a/db/schema_migrations/20230823145126 b/db/schema_migrations/20230823145126
new file mode 100644
index 00000000000..2809af86953
--- /dev/null
+++ b/db/schema_migrations/20230823145126
@@ -0,0 +1 @@
+dd3edcfd1b5e5079e68ce95257de1b216e5f791bfb5aa7f089cd1ffee8fbc78d \ No newline at end of file
diff --git a/db/schema_migrations/20230823161514 b/db/schema_migrations/20230823161514
new file mode 100644
index 00000000000..4cade8b0361
--- /dev/null
+++ b/db/schema_migrations/20230823161514
@@ -0,0 +1 @@
+606034ed6a64e2d2511e423a9311084ede66181cd1b47a4b3594229843c634e2 \ No newline at end of file
diff --git a/db/schema_migrations/20230823174108 b/db/schema_migrations/20230823174108
new file mode 100644
index 00000000000..32d7292f449
--- /dev/null
+++ b/db/schema_migrations/20230823174108
@@ -0,0 +1 @@
+ad75672df6de231df6d2702554e3416b0ba7c4c07cc4ace3d83595038f36b4e6 \ No newline at end of file
diff --git a/db/schema_migrations/20230823194111 b/db/schema_migrations/20230823194111
new file mode 100644
index 00000000000..1f59bc1e52a
--- /dev/null
+++ b/db/schema_migrations/20230823194111
@@ -0,0 +1 @@
+ecc37b7f9517923afa19a5e965819f70e73908e24c2f1d8cd5875137e6199966 \ No newline at end of file
diff --git a/db/schema_migrations/20230824015840 b/db/schema_migrations/20230824015840
new file mode 100644
index 00000000000..934f3dffb55
--- /dev/null
+++ b/db/schema_migrations/20230824015840
@@ -0,0 +1 @@
+14fee417b4fe7767f84068b2772e7fb9dd43df816af258d6b6d7e83bc3a2c176 \ No newline at end of file
diff --git a/db/schema_migrations/20230824022229 b/db/schema_migrations/20230824022229
new file mode 100644
index 00000000000..ba7506b7cb4
--- /dev/null
+++ b/db/schema_migrations/20230824022229
@@ -0,0 +1 @@
+cb2f7d874c5564c2aab48785043293abbd49803e39c466b1e1c2d47a3bc5cbfb \ No newline at end of file
diff --git a/db/schema_migrations/20230825085648 b/db/schema_migrations/20230825085648
new file mode 100644
index 00000000000..a6b1d8e1be1
--- /dev/null
+++ b/db/schema_migrations/20230825085648
@@ -0,0 +1 @@
+5e003d34a36320c53852ece7d0373ce99e7fc21b08f8edc5f5320256d4b3b3a2 \ No newline at end of file
diff --git a/db/schema_migrations/20230825085719 b/db/schema_migrations/20230825085719
new file mode 100644
index 00000000000..cf785c0a170
--- /dev/null
+++ b/db/schema_migrations/20230825085719
@@ -0,0 +1 @@
+4b7b8711a29a8a26ff9af42d73b95eb52b1791569771b1c34f6f51000059b10d \ No newline at end of file
diff --git a/db/schema_migrations/20230828153646 b/db/schema_migrations/20230828153646
new file mode 100644
index 00000000000..737645fba5d
--- /dev/null
+++ b/db/schema_migrations/20230828153646
@@ -0,0 +1 @@
+913b2384ea76d9169020253dacf14a51ccb7ebbaee9c9bc62b0e0473734ed981 \ No newline at end of file
diff --git a/db/schema_migrations/20230829045459 b/db/schema_migrations/20230829045459
new file mode 100644
index 00000000000..031eb2ea78f
--- /dev/null
+++ b/db/schema_migrations/20230829045459
@@ -0,0 +1 @@
+800d27ba92b45c193bbc8d487bec380fd06ef8660c41b2bef04b52f574ded406 \ No newline at end of file
diff --git a/db/schema_migrations/20230829120720 b/db/schema_migrations/20230829120720
new file mode 100644
index 00000000000..28155113a89
--- /dev/null
+++ b/db/schema_migrations/20230829120720
@@ -0,0 +1 @@
+2d40c98a720cb5bd9518b7c9ede223e23178199733352301a8400d1d387230fe \ No newline at end of file
diff --git a/db/schema_migrations/20230830084959 b/db/schema_migrations/20230830084959
new file mode 100644
index 00000000000..12a8dea429c
--- /dev/null
+++ b/db/schema_migrations/20230830084959
@@ -0,0 +1 @@
+3469c47c0cd4c86c7d1c9da450493a882d3a5f371fb7b78f49af64a837f989fb \ No newline at end of file
diff --git a/db/schema_migrations/20230830085501 b/db/schema_migrations/20230830085501
new file mode 100644
index 00000000000..92c45a647fc
--- /dev/null
+++ b/db/schema_migrations/20230830085501
@@ -0,0 +1 @@
+5756f155e295263ea8376b9161c523f9ee39628be289d1939c220852abd4d098 \ No newline at end of file
diff --git a/db/schema_migrations/20230830121830 b/db/schema_migrations/20230830121830
new file mode 100644
index 00000000000..55bfb10b349
--- /dev/null
+++ b/db/schema_migrations/20230830121830
@@ -0,0 +1 @@
+5ff2944a3e5100101b13f0aa4d69dc4ed6a4897cc28a90b45693ae3e3971a607 \ No newline at end of file
diff --git a/db/schema_migrations/20230831084632 b/db/schema_migrations/20230831084632
new file mode 100644
index 00000000000..2859ceb1691
--- /dev/null
+++ b/db/schema_migrations/20230831084632
@@ -0,0 +1 @@
+f523e00eeac359503976360c824582e8c9bd0e82cbf28ca02df17d0adacc90d8 \ No newline at end of file
diff --git a/db/schema_migrations/20230831101144 b/db/schema_migrations/20230831101144
new file mode 100644
index 00000000000..c2355043d68
--- /dev/null
+++ b/db/schema_migrations/20230831101144
@@ -0,0 +1 @@
+3e834879b1d896c1d4a9b8ee302f463f3cbcc8c79a8e93da31d6622f69b84b8d \ No newline at end of file
diff --git a/db/schema_migrations/20230831111051 b/db/schema_migrations/20230831111051
new file mode 100644
index 00000000000..36217b23759
--- /dev/null
+++ b/db/schema_migrations/20230831111051
@@ -0,0 +1 @@
+2058852d302266208a39c718d91a1d537c84330a7cee369d75d1a4e6420300b5 \ No newline at end of file
diff --git a/db/schema_migrations/20230901033401 b/db/schema_migrations/20230901033401
new file mode 100644
index 00000000000..e3ebeeb56ec
--- /dev/null
+++ b/db/schema_migrations/20230901033401
@@ -0,0 +1 @@
+8c19687f793a005ff83dfc1231c7ea0f44d6ad5ed363737615fc4e5c1074b5bd \ No newline at end of file
diff --git a/db/schema_migrations/20230901044003 b/db/schema_migrations/20230901044003
new file mode 100644
index 00000000000..a7d4f75a881
--- /dev/null
+++ b/db/schema_migrations/20230901044003
@@ -0,0 +1 @@
+2556dcb03527331710d4bf71c16983d04651c4bdf504b65e519ced213515555e \ No newline at end of file
diff --git a/db/schema_migrations/20230901050458 b/db/schema_migrations/20230901050458
new file mode 100644
index 00000000000..575e6a14be3
--- /dev/null
+++ b/db/schema_migrations/20230901050458
@@ -0,0 +1 @@
+747c396f78f3e34ee9c3cb9802e2cf8638f374f4fe2383fd7064fb378c1720d6 \ No newline at end of file
diff --git a/db/schema_migrations/20230901054536 b/db/schema_migrations/20230901054536
new file mode 100644
index 00000000000..2cc0bc00b20
--- /dev/null
+++ b/db/schema_migrations/20230901054536
@@ -0,0 +1 @@
+789900a0db2f180bdeebc5fcd7fcb446f23e2ea77bd7f62e682779e75c981290 \ No newline at end of file
diff --git a/db/schema_migrations/20230901064536 b/db/schema_migrations/20230901064536
new file mode 100644
index 00000000000..838df4adafc
--- /dev/null
+++ b/db/schema_migrations/20230901064536
@@ -0,0 +1 @@
+0097ccb7ec94655f8f455ae52f2a20089833a584f9f307ba554cd2c91f41e677 \ No newline at end of file
diff --git a/db/schema_migrations/20230901064537 b/db/schema_migrations/20230901064537
new file mode 100644
index 00000000000..e2c20f4889d
--- /dev/null
+++ b/db/schema_migrations/20230901064537
@@ -0,0 +1 @@
+a4aec1b330059217fc5f93be7c3e4a6369b402b4919a10a26de4ba8352dee9a7 \ No newline at end of file
diff --git a/db/schema_migrations/20230901170145 b/db/schema_migrations/20230901170145
new file mode 100644
index 00000000000..ae389df1a50
--- /dev/null
+++ b/db/schema_migrations/20230901170145
@@ -0,0 +1 @@
+86b17eb7dd562a935cea98c9a1e0815110dea9c6994f0c2fa9db5b37d5a3af27 \ No newline at end of file
diff --git a/db/schema_migrations/20230902033401 b/db/schema_migrations/20230902033401
new file mode 100644
index 00000000000..bc99e982a11
--- /dev/null
+++ b/db/schema_migrations/20230902033401
@@ -0,0 +1 @@
+11326885cf13eafa8c5042fac4749af0e2d6834608e03ad56a5587066100aea4 \ No newline at end of file
diff --git a/db/schema_migrations/20230902050458 b/db/schema_migrations/20230902050458
new file mode 100644
index 00000000000..ec40c06fbfd
--- /dev/null
+++ b/db/schema_migrations/20230902050458
@@ -0,0 +1 @@
+a036f2fa3148a3f5f64aefc420b04f8fb06530dfeac1df6fa70f42c6ba3e2ebf \ No newline at end of file
diff --git a/db/schema_migrations/20230902054536 b/db/schema_migrations/20230902054536
new file mode 100644
index 00000000000..1de79bf7c59
--- /dev/null
+++ b/db/schema_migrations/20230902054536
@@ -0,0 +1 @@
+037ff2b8993402c8aca75de43c92871a8248d79c11a57a312d028aeb6ac2d5bf \ No newline at end of file
diff --git a/db/schema_migrations/20230903064536 b/db/schema_migrations/20230903064536
new file mode 100644
index 00000000000..503c2335e13
--- /dev/null
+++ b/db/schema_migrations/20230903064536
@@ -0,0 +1 @@
+64257bd027fccbaff2cd0a785af54173fecfcb21bd05edb8a26fc32095a9fe98 \ No newline at end of file
diff --git a/db/schema_migrations/20230903064537 b/db/schema_migrations/20230903064537
new file mode 100644
index 00000000000..763aa7ff01c
--- /dev/null
+++ b/db/schema_migrations/20230903064537
@@ -0,0 +1 @@
+6eda15f0921c135f38f3d35edcdb8deefd8e1735abf537c94dd8c6475600060b \ No newline at end of file
diff --git a/db/schema_migrations/20230903170000 b/db/schema_migrations/20230903170000
new file mode 100644
index 00000000000..5189c60657a
--- /dev/null
+++ b/db/schema_migrations/20230903170000
@@ -0,0 +1 @@
+07fdd8579009aa1d68106cc9919d82cfca5702373d8b69c54ea7fa552209d540 \ No newline at end of file
diff --git a/db/schema_migrations/20230904100544 b/db/schema_migrations/20230904100544
new file mode 100644
index 00000000000..357a51ffee1
--- /dev/null
+++ b/db/schema_migrations/20230904100544
@@ -0,0 +1 @@
+773a845ec5b33a41cec6498e0fe5c4c033f2a011d0dcbe9feb9bed9779b3134d \ No newline at end of file
diff --git a/db/schema_migrations/20230904103804 b/db/schema_migrations/20230904103804
new file mode 100644
index 00000000000..30e0c5b280f
--- /dev/null
+++ b/db/schema_migrations/20230904103804
@@ -0,0 +1 @@
+daa7361dae1258a9fae12e7d0cc86e2484dd945f9cef26430817a761d198b34d \ No newline at end of file
diff --git a/db/schema_migrations/20230905040539 b/db/schema_migrations/20230905040539
new file mode 100644
index 00000000000..d707703c773
--- /dev/null
+++ b/db/schema_migrations/20230905040539
@@ -0,0 +1 @@
+f9bebf09d3265a506ab0f783cfd2a77415b05be27684c30998bd702a67ffc6b1 \ No newline at end of file
diff --git a/db/schema_migrations/20230905061815 b/db/schema_migrations/20230905061815
new file mode 100644
index 00000000000..12ea99e3e4a
--- /dev/null
+++ b/db/schema_migrations/20230905061815
@@ -0,0 +1 @@
+c32510034870dea5f26ab8fd64b034919355038a2e24f38bdd7c9051059346ec \ No newline at end of file
diff --git a/db/schema_migrations/20230905071915 b/db/schema_migrations/20230905071915
new file mode 100644
index 00000000000..8b4985f2141
--- /dev/null
+++ b/db/schema_migrations/20230905071915
@@ -0,0 +1 @@
+c3be3211b1b7a08cb93ca79b569a4ee4412fe42066573c938fd920d9aee9163a \ No newline at end of file
diff --git a/db/schema_migrations/20230905091059 b/db/schema_migrations/20230905091059
new file mode 100644
index 00000000000..a74c840b1c4
--- /dev/null
+++ b/db/schema_migrations/20230905091059
@@ -0,0 +1 @@
+c06fc36180c1b495eb800ba1c25bbe441f6973b0979d7fbc114ca7f128bd7c99 \ No newline at end of file
diff --git a/db/schema_migrations/20230905234948 b/db/schema_migrations/20230905234948
new file mode 100644
index 00000000000..0bbc72be5e5
--- /dev/null
+++ b/db/schema_migrations/20230905234948
@@ -0,0 +1 @@
+fb00789c87c9e9f2e794d9a7a8d15fd26cb66a3ca8d5a7ffc5ee42d99f961459 \ No newline at end of file
diff --git a/db/schema_migrations/20230905234949 b/db/schema_migrations/20230905234949
new file mode 100644
index 00000000000..5bde35409ed
--- /dev/null
+++ b/db/schema_migrations/20230905234949
@@ -0,0 +1 @@
+74ba712ab6dc155f7c0cf49e1c089e18033996553ff2d9c83b29bea19875ddfa \ No newline at end of file
diff --git a/db/schema_migrations/20230906072349 b/db/schema_migrations/20230906072349
new file mode 100644
index 00000000000..7aa3dccd8b4
--- /dev/null
+++ b/db/schema_migrations/20230906072349
@@ -0,0 +1 @@
+7b86070aa95bc9ad1671109d68abd2c8cb3d39134628f2acf7c85ce1685ea852 \ No newline at end of file
diff --git a/db/schema_migrations/20230906100001 b/db/schema_migrations/20230906100001
new file mode 100644
index 00000000000..fc8bd1af1ef
--- /dev/null
+++ b/db/schema_migrations/20230906100001
@@ -0,0 +1 @@
+ecd5d2beec391c9e9b0c396b3e8e7425ff250c417d2510d7d4a2d01266f12c5f \ No newline at end of file
diff --git a/db/schema_migrations/20230906105445 b/db/schema_migrations/20230906105445
new file mode 100644
index 00000000000..0c75909f0e7
--- /dev/null
+++ b/db/schema_migrations/20230906105445
@@ -0,0 +1 @@
+f378e1234e1ec61eabf1e183acfcefc53f3dec8ad12d1089a974e8b36724acdf \ No newline at end of file
diff --git a/db/schema_migrations/20230906175220 b/db/schema_migrations/20230906175220
new file mode 100644
index 00000000000..d063f2fb57f
--- /dev/null
+++ b/db/schema_migrations/20230906175220
@@ -0,0 +1 @@
+70e07f9790b7a9011fce37cc1376d61d84c98ef677fcce534dd97a78f892af86 \ No newline at end of file
diff --git a/db/schema_migrations/20230906181457 b/db/schema_migrations/20230906181457
new file mode 100644
index 00000000000..65e99ba4f0f
--- /dev/null
+++ b/db/schema_migrations/20230906181457
@@ -0,0 +1 @@
+183a4dd3ea67df81f38744550919d10d76b0a9e44eaf1cb949211d938b8c8f56 \ No newline at end of file
diff --git a/db/schema_migrations/20230906185552 b/db/schema_migrations/20230906185552
new file mode 100644
index 00000000000..a2c58d5f740
--- /dev/null
+++ b/db/schema_migrations/20230906185552
@@ -0,0 +1 @@
+114a9f959d66c7a5b0e31b3ab07bd08eb0ebcca7952359368facf35a5890eb3f \ No newline at end of file
diff --git a/db/schema_migrations/20230906204934 b/db/schema_migrations/20230906204934
new file mode 100644
index 00000000000..d15bd01b46f
--- /dev/null
+++ b/db/schema_migrations/20230906204934
@@ -0,0 +1 @@
+63b9153f085cb11279e84cb0e67a12987eaa6e20825e81d30d88054105b29825 \ No newline at end of file
diff --git a/db/schema_migrations/20230906204935 b/db/schema_migrations/20230906204935
new file mode 100644
index 00000000000..fa8c281171b
--- /dev/null
+++ b/db/schema_migrations/20230906204935
@@ -0,0 +1 @@
+9d1531d614e9a156f0d2aa9334aeab436ada293f37ef48223de76a360e85ed53 \ No newline at end of file
diff --git a/db/schema_migrations/20230907155247 b/db/schema_migrations/20230907155247
new file mode 100644
index 00000000000..6d709e8c35c
--- /dev/null
+++ b/db/schema_migrations/20230907155247
@@ -0,0 +1 @@
+969028a44aa3e656595c2af113fab7a82f8f28514337b97bfb467a5c5550dfc3 \ No newline at end of file
diff --git a/db/schema_migrations/20230907162613 b/db/schema_migrations/20230907162613
new file mode 100644
index 00000000000..f3442502b6e
--- /dev/null
+++ b/db/schema_migrations/20230907162613
@@ -0,0 +1 @@
+bad1a624184b8f0bfe57dbc36b4ec8478edeaa2dc6366eb5e5d31cdc7c0c8595 \ No newline at end of file
diff --git a/db/schema_migrations/20230907204731 b/db/schema_migrations/20230907204731
new file mode 100644
index 00000000000..9b10980eae0
--- /dev/null
+++ b/db/schema_migrations/20230907204731
@@ -0,0 +1 @@
+e5448d02414f99074a52337c271310277a1d76b386a9e2e1bd3c1b806a70c462 \ No newline at end of file
diff --git a/db/schema_migrations/20230908072558 b/db/schema_migrations/20230908072558
new file mode 100644
index 00000000000..887dcb04645
--- /dev/null
+++ b/db/schema_migrations/20230908072558
@@ -0,0 +1 @@
+bfde9336483cdfd75b4becdedcbaf8dd6aeb3edb87dde626204fff86085e94a0 \ No newline at end of file
diff --git a/db/schema_migrations/20230908072612 b/db/schema_migrations/20230908072612
new file mode 100644
index 00000000000..b1eef367968
--- /dev/null
+++ b/db/schema_migrations/20230908072612
@@ -0,0 +1 @@
+ee187bb2012e0af062610ad4b1026e5e12112d2964744922fb7087c14e7729a0 \ No newline at end of file
diff --git a/db/schema_migrations/20230908072626 b/db/schema_migrations/20230908072626
new file mode 100644
index 00000000000..923c8ea6fe4
--- /dev/null
+++ b/db/schema_migrations/20230908072626
@@ -0,0 +1 @@
+0fd8f7f580d9b7a5910f2aa838adf8d2f0a6fda7f112ac5cca6c50907590e610 \ No newline at end of file
diff --git a/db/schema_migrations/20230908072639 b/db/schema_migrations/20230908072639
new file mode 100644
index 00000000000..85baf65d9f4
--- /dev/null
+++ b/db/schema_migrations/20230908072639
@@ -0,0 +1 @@
+a8389b576d5abe741e9e1a9689f1c3c272a98a1aaec6173583b9ef41432b2540 \ No newline at end of file
diff --git a/db/schema_migrations/20230908155831 b/db/schema_migrations/20230908155831
new file mode 100644
index 00000000000..3264d9de079
--- /dev/null
+++ b/db/schema_migrations/20230908155831
@@ -0,0 +1 @@
+141c46587be646cb85c13ecfcae6c3123aa397e57f468f547ff43f93a35d8b37 \ No newline at end of file
diff --git a/db/schema_migrations/20230909120000 b/db/schema_migrations/20230909120000
new file mode 100644
index 00000000000..414065b3693
--- /dev/null
+++ b/db/schema_migrations/20230909120000
@@ -0,0 +1 @@
+75402594bdc333a34f7b49db4d5008fddad10f346dd15d65e4552cac20b442fb \ No newline at end of file
diff --git a/db/schema_migrations/20230911095016 b/db/schema_migrations/20230911095016
new file mode 100644
index 00000000000..02c9103db6c
--- /dev/null
+++ b/db/schema_migrations/20230911095016
@@ -0,0 +1 @@
+013462219a77c1ffcae41d657e00e70c9e79034f983b3857c312baf1cb454a2d \ No newline at end of file
diff --git a/db/schema_migrations/20230913100953 b/db/schema_migrations/20230913100953
new file mode 100644
index 00000000000..7bae2afbd02
--- /dev/null
+++ b/db/schema_migrations/20230913100953
@@ -0,0 +1 @@
+287ac58f06c12770a55e4965aab839ae2bae1eda34292234bda47c7ad90ce3cc \ No newline at end of file
diff --git a/db/schema_migrations/20230913115113 b/db/schema_migrations/20230913115113
new file mode 100644
index 00000000000..dc74f4f6ecd
--- /dev/null
+++ b/db/schema_migrations/20230913115113
@@ -0,0 +1 @@
+096cee5bd1d85a084e48f3868972cf727f44db85c000640ff840b48b4e9cf6ff \ No newline at end of file
diff --git a/db/schema_migrations/20230913120111 b/db/schema_migrations/20230913120111
new file mode 100644
index 00000000000..52162d8724f
--- /dev/null
+++ b/db/schema_migrations/20230913120111
@@ -0,0 +1 @@
+bddeb8b01a1228559237bc437810570041ea28f128b34d5f4130655eb01d7860 \ No newline at end of file
diff --git a/db/schema_migrations/20230913130629 b/db/schema_migrations/20230913130629
new file mode 100644
index 00000000000..26759217857
--- /dev/null
+++ b/db/schema_migrations/20230913130629
@@ -0,0 +1 @@
+4d5c78a1ebe2699831e1490c4df8ccbfbd1528af711ad67fc03232f34499e89e \ No newline at end of file
diff --git a/db/schema_migrations/20230913171402 b/db/schema_migrations/20230913171402
new file mode 100644
index 00000000000..686a7c6f570
--- /dev/null
+++ b/db/schema_migrations/20230913171402
@@ -0,0 +1 @@
+af511c9616f7f44474a8b4cd04f05c36f387a7b94badc4a5b1325a1e7425de46 \ No newline at end of file
diff --git a/db/schema_migrations/20230913171403 b/db/schema_migrations/20230913171403
new file mode 100644
index 00000000000..d0982b705eb
--- /dev/null
+++ b/db/schema_migrations/20230913171403
@@ -0,0 +1 @@
+91ac60df233911ad7d770eaeb4736b35dab7ba335eba11824cb114a1cfa97826 \ No newline at end of file
diff --git a/db/schema_migrations/20230913175529 b/db/schema_migrations/20230913175529
new file mode 100644
index 00000000000..f68678def20
--- /dev/null
+++ b/db/schema_migrations/20230913175529
@@ -0,0 +1 @@
+af8c6b5578c04d184f7f3768c5b06b3a252c10d8f158667ceab57eca74fb4341 \ No newline at end of file
diff --git a/db/schema_migrations/20230913235822 b/db/schema_migrations/20230913235822
new file mode 100644
index 00000000000..1dbfe5722cb
--- /dev/null
+++ b/db/schema_migrations/20230913235822
@@ -0,0 +1 @@
+2c5c8471a8c411a17fc7b4c7e5ab2f8e041e5edf3fb1428a3e146a80b836beaa \ No newline at end of file
diff --git a/db/schema_migrations/20230914001329 b/db/schema_migrations/20230914001329
new file mode 100644
index 00000000000..a8a05e4727f
--- /dev/null
+++ b/db/schema_migrations/20230914001329
@@ -0,0 +1 @@
+c21bcdb9bff2956c995fec964b9eefb16ec6e2fc819155df13103bb0202e46bd \ No newline at end of file
diff --git a/db/schema_migrations/20230914054914 b/db/schema_migrations/20230914054914
new file mode 100644
index 00000000000..c5cc5595ce6
--- /dev/null
+++ b/db/schema_migrations/20230914054914
@@ -0,0 +1 @@
+9702393eb6db18d5d3d106c0a77c21419af828fe5a422dd5c06a2621ef10cf03 \ No newline at end of file
diff --git a/db/schema_migrations/20230914185814 b/db/schema_migrations/20230914185814
new file mode 100644
index 00000000000..4a2f98bdd89
--- /dev/null
+++ b/db/schema_migrations/20230914185814
@@ -0,0 +1 @@
+11eea8818e233b09048e89bb4b56beceab4f8f9c5702bb4c167a5d7ac8d99ccc \ No newline at end of file
diff --git a/db/schema_migrations/20230918194153 b/db/schema_migrations/20230918194153
new file mode 100644
index 00000000000..2fd045aa9ed
--- /dev/null
+++ b/db/schema_migrations/20230918194153
@@ -0,0 +1 @@
+1ec3edbe609cd0142790b28c3b55e50ae36be4119f741ce970b36fd8a788a2ce \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 89917d13133..9283a0c4800 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -82,6 +82,7 @@ DECLARE
present_on_default_branch boolean;
namespace_id bigint;
has_issues boolean;
+ has_merge_request boolean;
BEGIN
IF (NEW.vulnerability_id IS NULL AND (TG_OP = 'INSERT' OR TG_OP = 'UPDATE')) THEN
RETURN NULL;
@@ -118,8 +119,13 @@ BEGIN
INTO
has_issues;
- INSERT INTO vulnerability_reads (vulnerability_id, namespace_id, project_id, scanner_id, report_type, severity, state, resolved_on_default_branch, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues)
- VALUES (NEW.vulnerability_id, namespace_id, NEW.project_id, NEW.scanner_id, report_type, severity, state, resolved_on_default_branch, NEW.uuid::uuid, NEW.location->>'image', NEW.location->'kubernetes_resource'->>'agent_id', CAST(NEW.location->'kubernetes_resource'->>'agent_id' AS bigint), has_issues)
+ SELECT
+ EXISTS (SELECT 1 FROM vulnerability_merge_request_links WHERE vulnerability_merge_request_links.vulnerability_id = NEW.vulnerability_id)
+ INTO
+ has_merge_request;
+
+ INSERT INTO vulnerability_reads (vulnerability_id, namespace_id, project_id, scanner_id, report_type, severity, state, resolved_on_default_branch, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues, has_merge_request)
+ VALUES (NEW.vulnerability_id, namespace_id, NEW.project_id, NEW.scanner_id, report_type, severity, state, resolved_on_default_branch, NEW.uuid::uuid, NEW.location->>'image', NEW.location->'kubernetes_resource'->>'agent_id', CAST(NEW.location->'kubernetes_resource'->>'agent_id' AS bigint), has_issues, has_merge_request)
ON CONFLICT(vulnerability_id) DO NOTHING;
RETURN NULL;
END
@@ -147,6 +153,7 @@ DECLARE
casted_cluster_agent_id bigint;
namespace_id bigint;
has_issues boolean;
+ has_merge_request boolean;
BEGIN
SELECT
v_o.scanner_id, v_o.uuid, v_o.location->>'image', v_o.location->'kubernetes_resource'->>'agent_id', CAST(v_o.location->'kubernetes_resource'->>'agent_id' AS bigint), projects.namespace_id
@@ -164,8 +171,13 @@ BEGIN
INTO
has_issues;
- INSERT INTO vulnerability_reads (vulnerability_id, namespace_id, project_id, scanner_id, report_type, severity, state, resolved_on_default_branch, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues)
- VALUES (NEW.id, namespace_id, NEW.project_id, scanner_id, NEW.report_type, NEW.severity, NEW.state, NEW.resolved_on_default_branch, uuid::uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues)
+ SELECT
+ EXISTS (SELECT 1 FROM vulnerability_merge_request_links WHERE vulnerability_merge_request_links.vulnerability_id = NEW.id)
+ INTO
+ has_merge_request;
+
+ INSERT INTO vulnerability_reads (vulnerability_id, namespace_id, project_id, scanner_id, report_type, severity, state, resolved_on_default_branch, uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues, has_merge_request)
+ VALUES (NEW.id, namespace_id, NEW.project_id, scanner_id, NEW.report_type, NEW.severity, NEW.state, NEW.resolved_on_default_branch, uuid::uuid, location_image, cluster_agent_id, casted_cluster_agent_id, has_issues, has_merge_request)
ON CONFLICT(vulnerability_id) DO NOTHING;
RETURN NULL;
END
@@ -341,6 +353,15 @@ BEGIN
END;
$$;
+CREATE FUNCTION trigger_bbb95b2d6929() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ NEW."shared_runners_duration_convert_to_bigint" := NEW."shared_runners_duration";
+ RETURN NEW;
+END;
+$$;
+
CREATE FUNCTION trigger_bfad0e2b9c86() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -350,6 +371,15 @@ BEGIN
END;
$$;
+CREATE FUNCTION trigger_c0353bbb6145() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ NEW."shared_runners_duration_convert_to_bigint" := NEW."shared_runners_duration";
+ RETURN NEW;
+END;
+$$;
+
CREATE FUNCTION unset_has_issues_on_vulnerability_reads() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -563,6 +593,14 @@ CREATE TABLE p_ci_runner_machine_builds (
)
PARTITION BY LIST (partition_id);
+CREATE TABLE groups_visits (
+ id bigint NOT NULL,
+ entity_id bigint NOT NULL,
+ user_id bigint NOT NULL,
+ visited_at timestamp with time zone NOT NULL
+)
+PARTITION BY RANGE (visited_at);
+
CREATE TABLE incident_management_pending_alert_escalations (
id bigint NOT NULL,
rule_id bigint NOT NULL,
@@ -608,6 +646,14 @@ CREATE TABLE p_batched_git_ref_updates_deletions (
)
PARTITION BY LIST (partition_id);
+CREATE TABLE projects_visits (
+ id bigint NOT NULL,
+ entity_id bigint NOT NULL,
+ user_id bigint NOT NULL,
+ visited_at timestamp with time zone NOT NULL
+)
+PARTITION BY RANGE (visited_at);
+
CREATE TABLE security_findings (
id bigint NOT NULL,
scan_id bigint NOT NULL,
@@ -11849,9 +11895,6 @@ CREATE TABLE application_settings (
encrypted_jitsu_administrator_password_iv bytea,
dashboard_limit_enabled boolean DEFAULT false NOT NULL,
dashboard_limit integer DEFAULT 0 NOT NULL,
- dashboard_notification_limit integer DEFAULT 0 NOT NULL,
- dashboard_enforcement_limit integer DEFAULT 0 NOT NULL,
- dashboard_limit_new_namespace_creation_enforcement_date date,
can_create_group boolean DEFAULT true NOT NULL,
lock_maven_package_requests_forwarding boolean DEFAULT false NOT NULL,
lock_pypi_package_requests_forwarding boolean DEFAULT false NOT NULL,
@@ -11927,11 +11970,14 @@ CREATE TABLE application_settings (
package_registry_allow_anyone_to_pull_option boolean DEFAULT true NOT NULL,
bulk_import_max_download_file_size bigint DEFAULT 5120 NOT NULL,
max_import_remote_file_size bigint DEFAULT 10240 NOT NULL,
- sentry_clientside_traces_sample_rate double precision DEFAULT 0.0 NOT NULL,
protected_paths_for_get_request text[] DEFAULT '{}'::text[] NOT NULL,
max_decompressed_archive_size integer DEFAULT 25600 NOT NULL,
- ci_max_total_yaml_size_bytes integer DEFAULT 157286400 NOT NULL,
+ sentry_clientside_traces_sample_rate double precision DEFAULT 0.0 NOT NULL,
prometheus_alert_db_indicators_settings jsonb,
+ ci_max_total_yaml_size_bytes integer DEFAULT 157286400 NOT NULL,
+ decompress_archive_file_timeout integer DEFAULT 210 NOT NULL,
+ search_rate_limit_allowlist text[] DEFAULT '{}'::text[] NOT NULL,
+ snowplow_database_collector_hostname text,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
@@ -11956,6 +12002,7 @@ CREATE TABLE application_settings (
CONSTRAINT check_32710817e9 CHECK ((char_length(static_objects_external_storage_auth_token_encrypted) <= 255)),
CONSTRAINT check_3455368420 CHECK ((char_length(database_grafana_api_url) <= 255)),
CONSTRAINT check_3559645ae5 CHECK ((char_length(container_registry_import_target_plan) <= 255)),
+ CONSTRAINT check_3b22213b72 CHECK ((char_length(snowplow_database_collector_hostname) <= 255)),
CONSTRAINT check_3def0f1829 CHECK ((char_length(sentry_clientside_dsn) <= 255)),
CONSTRAINT check_4847426287 CHECK ((char_length(jira_connect_proxy_url) <= 255)),
CONSTRAINT check_492cc1354d CHECK ((char_length(error_tracking_api_url) <= 255)),
@@ -12202,7 +12249,8 @@ CREATE TABLE approvals (
merge_request_id integer NOT NULL,
user_id integer NOT NULL,
created_at timestamp without time zone,
- updated_at timestamp without time zone
+ updated_at timestamp without time zone,
+ patch_id_sha bytea
);
CREATE SEQUENCE approvals_id_seq
@@ -12283,6 +12331,32 @@ CREATE SEQUENCE atlassian_identities_user_id_seq
ALTER SEQUENCE atlassian_identities_user_id_seq OWNED BY atlassian_identities.user_id;
+CREATE TABLE audit_events_amazon_s3_configurations (
+ id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ namespace_id bigint NOT NULL,
+ access_key_xid text NOT NULL,
+ name text NOT NULL,
+ bucket_name text NOT NULL,
+ aws_region text NOT NULL,
+ encrypted_secret_access_key bytea NOT NULL,
+ encrypted_secret_access_key_iv bytea NOT NULL,
+ CONSTRAINT check_3a41f4ea06 CHECK ((char_length(bucket_name) <= 63)),
+ CONSTRAINT check_72b5aaa71b CHECK ((char_length(aws_region) <= 50)),
+ CONSTRAINT check_90505816db CHECK ((char_length(name) <= 72)),
+ CONSTRAINT check_ec46f06e01 CHECK ((char_length(access_key_xid) <= 128))
+);
+
+CREATE SEQUENCE audit_events_amazon_s3_configurations_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE audit_events_amazon_s3_configurations_id_seq OWNED BY audit_events_amazon_s3_configurations.id;
+
CREATE TABLE audit_events_external_audit_event_destinations (
id bigint NOT NULL,
namespace_id bigint NOT NULL,
@@ -12361,6 +12435,31 @@ CREATE SEQUENCE audit_events_instance_external_audit_event_destinations_id_seq
ALTER SEQUENCE audit_events_instance_external_audit_event_destinations_id_seq OWNED BY audit_events_instance_external_audit_event_destinations.id;
+CREATE TABLE audit_events_instance_google_cloud_logging_configurations (
+ id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ google_project_id_name text NOT NULL,
+ client_email text NOT NULL,
+ log_id_name text DEFAULT 'audit_events'::text,
+ name text NOT NULL,
+ encrypted_private_key bytea NOT NULL,
+ encrypted_private_key_iv bytea NOT NULL,
+ CONSTRAINT check_0da5c76c49 CHECK ((char_length(client_email) <= 254)),
+ CONSTRAINT check_74fd943192 CHECK ((char_length(log_id_name) <= 511)),
+ CONSTRAINT check_ab65f57721 CHECK ((char_length(google_project_id_name) <= 30)),
+ CONSTRAINT check_ac42ad3ca2 CHECK ((char_length(name) <= 72))
+);
+
+CREATE SEQUENCE audit_events_instance_google_cloud_logging_configuration_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE audit_events_instance_google_cloud_logging_configuration_id_seq OWNED BY audit_events_instance_google_cloud_logging_configurations.id;
+
CREATE TABLE audit_events_streaming_event_type_filters (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -13709,6 +13808,7 @@ CREATE TABLE ci_namespace_monthly_usages (
shared_runners_duration integer DEFAULT 0 NOT NULL,
created_at timestamp with time zone,
amount_used numeric(18,4) DEFAULT 0.0 NOT NULL,
+ shared_runners_duration_convert_to_bigint bigint DEFAULT 0 NOT NULL,
CONSTRAINT ci_namespace_monthly_usages_year_month_constraint CHECK ((date = date_trunc('month'::text, (date)::timestamp with time zone)))
);
@@ -13995,6 +14095,7 @@ CREATE TABLE ci_project_monthly_usages (
shared_runners_duration integer DEFAULT 0 NOT NULL,
created_at timestamp with time zone,
amount_used numeric(18,4) DEFAULT 0.0 NOT NULL,
+ shared_runners_duration_convert_to_bigint bigint DEFAULT 0 NOT NULL,
CONSTRAINT ci_project_monthly_usages_year_month_constraint CHECK ((date = date_trunc('month'::text, (date)::timestamp with time zone)))
);
@@ -16416,9 +16517,7 @@ CREATE TABLE geo_node_statuses (
lfs_objects_count integer,
lfs_objects_synced_count integer,
lfs_objects_failed_count integer,
- last_event_id integer,
last_event_date timestamp without time zone,
- cursor_last_event_id integer,
cursor_last_event_date timestamp without time zone,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
@@ -16458,7 +16557,9 @@ CREATE TABLE geo_node_statuses (
design_repositories_synced_count integer,
design_repositories_failed_count integer,
design_repositories_registry_count integer,
- status jsonb DEFAULT '{}'::jsonb NOT NULL
+ status jsonb DEFAULT '{}'::jsonb NOT NULL,
+ last_event_id bigint,
+ cursor_last_event_id bigint
);
CREATE SEQUENCE geo_node_statuses_id_seq
@@ -16920,7 +17021,8 @@ CREATE TABLE group_merge_request_approval_settings (
allow_committer_approval boolean DEFAULT false NOT NULL,
allow_overrides_to_approver_list_per_merge_request boolean DEFAULT false NOT NULL,
retain_approvals_on_push boolean DEFAULT false NOT NULL,
- require_password_to_approve boolean DEFAULT false NOT NULL
+ require_password_to_approve boolean DEFAULT false NOT NULL,
+ require_saml_auth_to_approve boolean DEFAULT false NOT NULL
);
CREATE TABLE group_repository_storage_moves (
@@ -16993,6 +17095,15 @@ CREATE SEQUENCE group_wiki_repository_states_id_seq
ALTER SEQUENCE group_wiki_repository_states_id_seq OWNED BY group_wiki_repository_states.id;
+CREATE SEQUENCE groups_visits_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE groups_visits_id_seq OWNED BY groups_visits.id;
+
CREATE TABLE historical_data (
id integer NOT NULL,
date date,
@@ -18145,6 +18256,7 @@ CREATE TABLE member_roles (
read_dependency boolean DEFAULT false NOT NULL,
name text DEFAULT 'Custom'::text NOT NULL,
description text,
+ admin_merge_request boolean DEFAULT false NOT NULL,
CONSTRAINT check_4364846f58 CHECK ((char_length(description) <= 255)),
CONSTRAINT check_9907916995 CHECK ((char_length(name) <= 255))
);
@@ -18501,6 +18613,8 @@ CREATE TABLE merge_request_review_llm_summaries (
updated_at timestamp with time zone NOT NULL,
provider smallint NOT NULL,
content text NOT NULL,
+ cached_markdown_version integer,
+ content_html text,
CONSTRAINT check_72802358e9 CHECK ((char_length(content) <= 2056))
);
@@ -18592,6 +18706,7 @@ CREATE TABLE merge_requests (
merge_ref_sha bytea,
draft boolean DEFAULT false NOT NULL,
prepared_at timestamp with time zone,
+ merged_commit_sha bytea,
CONSTRAINT check_970d272570 CHECK ((lock_version IS NOT NULL))
);
@@ -18974,11 +19089,7 @@ CREATE TABLE namespace_details (
updated_at timestamp with time zone,
cached_markdown_version integer,
description text,
- description_html text,
- free_user_cap_over_limit_notified_at timestamp with time zone,
- dashboard_notification_at timestamp with time zone,
- dashboard_enforcement_at timestamp with time zone,
- next_over_limit_check_at timestamp with time zone
+ description_html text
);
CREATE TABLE namespace_ldap_settings (
@@ -20117,6 +20228,32 @@ CREATE TABLE packages_nuget_metadata (
CONSTRAINT packages_nuget_metadata_project_url_constraint CHECK ((char_length(project_url) <= 255))
);
+CREATE TABLE packages_nuget_symbols (
+ id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ package_id bigint,
+ size integer NOT NULL,
+ file_store smallint DEFAULT 1,
+ file text NOT NULL,
+ file_path text NOT NULL,
+ signature text NOT NULL,
+ object_storage_key text NOT NULL,
+ CONSTRAINT check_0e93ca58b7 CHECK ((char_length(file) <= 255)),
+ CONSTRAINT check_28b82b08fa CHECK ((char_length(object_storage_key) <= 255)),
+ CONSTRAINT check_30b0ef2ca2 CHECK ((char_length(file_path) <= 255)),
+ CONSTRAINT check_8dc7152679 CHECK ((char_length(signature) <= 255))
+);
+
+CREATE SEQUENCE packages_nuget_symbols_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE packages_nuget_symbols_id_seq OWNED BY packages_nuget_symbols.id;
+
CREATE TABLE packages_package_file_build_infos (
id bigint NOT NULL,
package_file_id bigint NOT NULL,
@@ -20187,11 +20324,43 @@ CREATE SEQUENCE packages_packages_id_seq
ALTER SEQUENCE packages_packages_id_seq OWNED BY packages_packages.id;
+CREATE TABLE packages_protection_rules (
+ id bigint NOT NULL,
+ project_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ push_protected_up_to_access_level integer NOT NULL,
+ package_type smallint NOT NULL,
+ package_name_pattern text NOT NULL,
+ CONSTRAINT check_d2d75d206d CHECK ((char_length(package_name_pattern) <= 255))
+);
+
+CREATE SEQUENCE packages_protection_rules_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE packages_protection_rules_id_seq OWNED BY packages_protection_rules.id;
+
CREATE TABLE packages_pypi_metadata (
package_id bigint NOT NULL,
required_python text DEFAULT ''::text,
+ metadata_version text,
+ summary text,
+ keywords text,
+ author_email text,
+ description text,
+ description_content_type text,
+ CONSTRAINT check_02be2c39af CHECK ((char_length(keywords) <= 255)),
CONSTRAINT check_0d9aed55b2 CHECK ((required_python IS NOT NULL)),
- CONSTRAINT check_379019d5da CHECK ((char_length(required_python) <= 255))
+ CONSTRAINT check_2d3ed32225 CHECK ((char_length(metadata_version) <= 16)),
+ CONSTRAINT check_379019d5da CHECK ((char_length(required_python) <= 255)),
+ CONSTRAINT check_65d8dbbd9f CHECK ((char_length(author_email) <= 2048)),
+ CONSTRAINT check_76afb6d4f3 CHECK ((char_length(summary) <= 255)),
+ CONSTRAINT check_80308aa9bd CHECK ((char_length(description) <= 4000)),
+ CONSTRAINT check_b1f32be96c CHECK ((char_length(description_content_type) <= 128))
);
CREATE TABLE packages_rpm_metadata (
@@ -20341,6 +20510,7 @@ CREATE TABLE pages_deployments (
root_directory text DEFAULT 'public'::text,
path_prefix text,
build_ref text,
+ deleted_at timestamp with time zone,
CONSTRAINT check_4d04b8dc9a CHECK ((char_length(path_prefix) <= 128)),
CONSTRAINT check_5f9132a958 CHECK ((size IS NOT NULL)),
CONSTRAINT check_7e938c810a CHECK ((char_length(root_directory) <= 255)),
@@ -20545,7 +20715,8 @@ CREATE TABLE plan_limits (
ci_max_artifact_size_annotations integer DEFAULT 0 NOT NULL,
ci_job_annotations_size integer DEFAULT 81920 NOT NULL,
ci_job_annotations_num integer DEFAULT 20 NOT NULL,
- file_size_limit_mb double precision DEFAULT 100.0 NOT NULL
+ file_size_limit_mb double precision DEFAULT 100.0 NOT NULL,
+ audit_events_amazon_s3_configurations integer DEFAULT 5 NOT NULL
);
CREATE SEQUENCE plan_limits_id_seq
@@ -21177,7 +21348,8 @@ CREATE TABLE project_ci_cd_settings (
separated_caches boolean DEFAULT true NOT NULL,
allow_fork_pipelines_to_run_in_parent_project boolean DEFAULT true NOT NULL,
inbound_job_token_scope_enabled boolean DEFAULT true NOT NULL,
- forward_deployment_rollback_allowed boolean DEFAULT true NOT NULL
+ forward_deployment_rollback_allowed boolean DEFAULT true NOT NULL,
+ merge_trains_skip_train_allowed boolean DEFAULT false NOT NULL
);
CREATE SEQUENCE project_ci_cd_settings_id_seq
@@ -21595,7 +21767,8 @@ CREATE TABLE project_security_settings (
auto_fix_container_scanning boolean DEFAULT true NOT NULL,
auto_fix_dast boolean DEFAULT true NOT NULL,
auto_fix_dependency_scanning boolean DEFAULT true NOT NULL,
- auto_fix_sast boolean DEFAULT true NOT NULL
+ auto_fix_sast boolean DEFAULT true NOT NULL,
+ continuous_vulnerability_scans_enabled boolean DEFAULT false NOT NULL
);
CREATE SEQUENCE project_security_settings_project_id_seq
@@ -21654,6 +21827,7 @@ CREATE TABLE project_settings (
encrypted_cube_api_key_iv bytea,
encrypted_product_analytics_configurator_connection_string bytea,
encrypted_product_analytics_configurator_connection_string_iv bytea,
+ pages_multiple_versions_enabled boolean DEFAULT false NOT NULL,
CONSTRAINT check_1a30456322 CHECK ((char_length(pages_unique_domain) <= 63)),
CONSTRAINT check_2981f15877 CHECK ((char_length(jitsu_key) <= 100)),
CONSTRAINT check_3a03e7557a CHECK ((char_length(previous_default_branch) <= 4096)),
@@ -21710,7 +21884,8 @@ CREATE TABLE project_statistics (
uploads_size bigint DEFAULT 0 NOT NULL,
container_registry_size bigint DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
- updated_at timestamp with time zone DEFAULT now() NOT NULL
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ root_namespace_id bigint
);
CREATE SEQUENCE project_statistics_id_seq
@@ -21837,7 +22012,8 @@ CREATE TABLE projects (
autoclose_referenced_issues boolean,
suggestion_commit_message character varying(255),
project_namespace_id bigint,
- hidden boolean DEFAULT false NOT NULL
+ hidden boolean DEFAULT false NOT NULL,
+ organization_id bigint DEFAULT 1
);
CREATE SEQUENCE projects_id_seq
@@ -21863,6 +22039,15 @@ CREATE SEQUENCE projects_sync_events_id_seq
ALTER SEQUENCE projects_sync_events_id_seq OWNED BY projects_sync_events.id;
+CREATE SEQUENCE projects_visits_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE projects_visits_id_seq OWNED BY projects_visits.id;
+
CREATE TABLE prometheus_alert_events (
id bigint NOT NULL,
project_id integer NOT NULL,
@@ -22142,7 +22327,14 @@ CREATE TABLE push_rules (
regexp_uses_re2 boolean DEFAULT true,
commit_message_negative_regex character varying,
reject_non_dco_commits boolean,
- commit_committer_name_check boolean DEFAULT false NOT NULL
+ commit_committer_name_check boolean DEFAULT false NOT NULL,
+ CONSTRAINT author_email_regex_size_constraint CHECK ((char_length((author_email_regex)::text) <= 511)),
+ CONSTRAINT branch_name_regex_size_constraint CHECK ((char_length((branch_name_regex)::text) <= 511)),
+ CONSTRAINT commit_message_negative_regex_size_constraint CHECK ((char_length((commit_message_negative_regex)::text) <= 2047)),
+ CONSTRAINT commit_message_regex_size_constraint CHECK ((char_length((commit_message_regex)::text) <= 511)),
+ CONSTRAINT delete_branch_regex_size_constraint CHECK ((char_length((delete_branch_regex)::text) <= 511)),
+ CONSTRAINT file_name_regex_size_constraint CHECK ((char_length((file_name_regex)::text) <= 511)),
+ CONSTRAINT force_push_regex_size_constraint CHECK ((char_length((force_push_regex)::text) <= 511))
);
CREATE SEQUENCE push_rules_id_seq
@@ -22649,6 +22841,7 @@ CREATE TABLE sbom_occurrences (
package_manager text,
component_name text,
input_file_path text,
+ licenses jsonb DEFAULT '[]'::jsonb,
CONSTRAINT check_3f2d2c7ffc CHECK ((char_length(package_manager) <= 255)),
CONSTRAINT check_9b29021fa8 CHECK ((char_length(component_name) <= 255)),
CONSTRAINT check_bd1367d4c1 CHECK ((char_length(input_file_path) <= 255))
@@ -22695,6 +22888,8 @@ CREATE TABLE scan_result_policies (
vulnerability_attributes jsonb DEFAULT '{}'::jsonb,
project_id bigint,
rule_idx smallint,
+ project_approval_settings jsonb DEFAULT '{}'::jsonb NOT NULL,
+ commits smallint,
CONSTRAINT age_value_null_or_positive CHECK (((age_value IS NULL) OR (age_value >= 0))),
CONSTRAINT check_scan_result_policies_rule_idx_positive CHECK (((rule_idx IS NULL) OR (rule_idx >= 0)))
);
@@ -23935,9 +24130,17 @@ CREATE TABLE user_credit_card_validations (
last_digits smallint,
holder_name text,
network text,
+ last_digits_hash text,
+ holder_name_hash text,
+ expiration_date_hash text,
+ network_hash text,
CONSTRAINT check_1765e2b30f CHECK ((char_length(network) <= 32)),
CONSTRAINT check_3eea080c91 CHECK (((last_digits >= 0) AND (last_digits <= 9999))),
- CONSTRAINT check_cc0c8dc0fe CHECK ((char_length(holder_name) <= 50))
+ CONSTRAINT check_7721e1961a CHECK ((char_length(network_hash) <= 44)),
+ CONSTRAINT check_83f1e2ace3 CHECK ((char_length(expiration_date_hash) <= 44)),
+ CONSTRAINT check_aca7c2607c CHECK ((char_length(holder_name_hash) <= 44)),
+ CONSTRAINT check_cc0c8dc0fe CHECK ((char_length(holder_name) <= 50)),
+ CONSTRAINT check_f5c35b1a6e CHECK ((char_length(last_digits_hash) <= 44))
);
CREATE TABLE user_custom_attributes (
@@ -24131,6 +24334,7 @@ CREATE TABLE user_preferences (
visibility_pipeline_id_type smallint DEFAULT 0 NOT NULL,
project_shortcut_buttons boolean DEFAULT true NOT NULL,
enabled_zoekt boolean DEFAULT true NOT NULL,
+ keyboard_shortcuts_enabled boolean DEFAULT true NOT NULL,
CONSTRAINT check_89bf269f41 CHECK ((char_length(diffs_deletion_color) <= 7)),
CONSTRAINT check_d07ccd35f7 CHECK ((char_length(diffs_addition_color) <= 7))
);
@@ -24404,7 +24608,8 @@ CREATE TABLE vulnerabilities (
dismissed_by_id bigint,
resolved_on_default_branch boolean DEFAULT false NOT NULL,
present_on_default_branch boolean DEFAULT true NOT NULL,
- detected_at timestamp with time zone DEFAULT now()
+ detected_at timestamp with time zone DEFAULT now(),
+ finding_id bigint
);
CREATE SEQUENCE vulnerabilities_id_seq
@@ -25055,7 +25260,9 @@ CREATE TABLE work_item_progresses (
progress smallint DEFAULT 0 NOT NULL,
start_value double precision DEFAULT 0.0 NOT NULL,
end_value double precision DEFAULT 100.0 NOT NULL,
- current_value double precision DEFAULT 0.0 NOT NULL
+ current_value double precision DEFAULT 0.0 NOT NULL,
+ rollup_progress boolean DEFAULT true NOT NULL,
+ reminder_frequency smallint DEFAULT 0 NOT NULL
);
CREATE TABLE work_item_types (
@@ -25101,6 +25308,27 @@ CREATE SEQUENCE work_item_widget_definitions_id_seq
ALTER SEQUENCE work_item_widget_definitions_id_seq OWNED BY work_item_widget_definitions.id;
+CREATE TABLE workspace_variables (
+ id bigint NOT NULL,
+ workspace_id bigint NOT NULL,
+ variable_type smallint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ key text NOT NULL,
+ encrypted_value bytea NOT NULL,
+ encrypted_value_iv bytea NOT NULL,
+ CONSTRAINT check_5545042100 CHECK ((char_length(key) <= 255))
+);
+
+CREATE SEQUENCE workspace_variables_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE workspace_variables_id_seq OWNED BY workspace_variables.id;
+
CREATE TABLE workspaces (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -25122,6 +25350,9 @@ CREATE TABLE workspaces (
processed_devfile text,
url text NOT NULL,
deployment_resource_version text,
+ personal_access_token_id bigint,
+ config_version integer DEFAULT 1 NOT NULL,
+ force_full_reconciliation boolean DEFAULT false NOT NULL,
CONSTRAINT check_15543fb0fa CHECK ((char_length(name) <= 64)),
CONSTRAINT check_157d5f955c CHECK ((char_length(namespace) <= 64)),
CONSTRAINT check_2b401b0034 CHECK ((char_length(deployment_resource_version) <= 64)),
@@ -25149,7 +25380,7 @@ CREATE TABLE x509_certificates (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
subject_key_identifier character varying(255) NOT NULL,
- subject character varying(512) NOT NULL,
+ subject character varying(512),
email character varying(255) NOT NULL,
serial_number bytea NOT NULL,
certificate_status smallint DEFAULT 0 NOT NULL,
@@ -25190,8 +25421,8 @@ CREATE TABLE x509_issuers (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
subject_key_identifier character varying(255) NOT NULL,
- subject character varying(255) NOT NULL,
- crl_url character varying(255) NOT NULL
+ subject character varying(255),
+ crl_url character varying(255)
);
CREATE SEQUENCE x509_issuers_id_seq
@@ -25361,12 +25592,16 @@ ALTER TABLE ONLY atlassian_identities ALTER COLUMN user_id SET DEFAULT nextval('
ALTER TABLE ONLY audit_events ALTER COLUMN id SET DEFAULT nextval('audit_events_id_seq'::regclass);
+ALTER TABLE ONLY audit_events_amazon_s3_configurations ALTER COLUMN id SET DEFAULT nextval('audit_events_amazon_s3_configurations_id_seq'::regclass);
+
ALTER TABLE ONLY audit_events_external_audit_event_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_external_audit_event_destinations_id_seq'::regclass);
ALTER TABLE ONLY audit_events_google_cloud_logging_configurations ALTER COLUMN id SET DEFAULT nextval('audit_events_google_cloud_logging_configurations_id_seq'::regclass);
ALTER TABLE ONLY audit_events_instance_external_audit_event_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_instance_external_audit_event_destinations_id_seq'::regclass);
+ALTER TABLE ONLY audit_events_instance_google_cloud_logging_configurations ALTER COLUMN id SET DEFAULT nextval('audit_events_instance_google_cloud_logging_configuration_id_seq'::regclass);
+
ALTER TABLE ONLY audit_events_streaming_event_type_filters ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_event_type_filters_id_seq'::regclass);
ALTER TABLE ONLY audit_events_streaming_headers ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_headers_id_seq'::regclass);
@@ -25755,6 +25990,8 @@ ALTER TABLE ONLY group_ssh_certificates ALTER COLUMN id SET DEFAULT nextval('gro
ALTER TABLE ONLY group_wiki_repository_states ALTER COLUMN id SET DEFAULT nextval('group_wiki_repository_states_id_seq'::regclass);
+ALTER TABLE ONLY groups_visits ALTER COLUMN id SET DEFAULT nextval('groups_visits_id_seq'::regclass);
+
ALTER TABLE ONLY historical_data ALTER COLUMN id SET DEFAULT nextval('historical_data_id_seq'::regclass);
ALTER TABLE ONLY identities ALTER COLUMN id SET DEFAULT nextval('identities_id_seq'::regclass);
@@ -26023,12 +26260,16 @@ ALTER TABLE ONLY packages_maven_metadata ALTER COLUMN id SET DEFAULT nextval('pa
ALTER TABLE ONLY packages_npm_metadata_caches ALTER COLUMN id SET DEFAULT nextval('packages_npm_metadata_caches_id_seq'::regclass);
+ALTER TABLE ONLY packages_nuget_symbols ALTER COLUMN id SET DEFAULT nextval('packages_nuget_symbols_id_seq'::regclass);
+
ALTER TABLE ONLY packages_package_file_build_infos ALTER COLUMN id SET DEFAULT nextval('packages_package_file_build_infos_id_seq'::regclass);
ALTER TABLE ONLY packages_package_files ALTER COLUMN id SET DEFAULT nextval('packages_package_files_id_seq'::regclass);
ALTER TABLE ONLY packages_packages ALTER COLUMN id SET DEFAULT nextval('packages_packages_id_seq'::regclass);
+ALTER TABLE ONLY packages_protection_rules ALTER COLUMN id SET DEFAULT nextval('packages_protection_rules_id_seq'::regclass);
+
ALTER TABLE ONLY packages_rpm_repository_files ALTER COLUMN id SET DEFAULT nextval('packages_rpm_repository_files_id_seq'::regclass);
ALTER TABLE ONLY packages_tags ALTER COLUMN id SET DEFAULT nextval('packages_tags_id_seq'::regclass);
@@ -26135,6 +26376,8 @@ ALTER TABLE ONLY projects ALTER COLUMN id SET DEFAULT nextval('projects_id_seq':
ALTER TABLE ONLY projects_sync_events ALTER COLUMN id SET DEFAULT nextval('projects_sync_events_id_seq'::regclass);
+ALTER TABLE ONLY projects_visits ALTER COLUMN id SET DEFAULT nextval('projects_visits_id_seq'::regclass);
+
ALTER TABLE ONLY prometheus_alert_events ALTER COLUMN id SET DEFAULT nextval('prometheus_alert_events_id_seq'::regclass);
ALTER TABLE ONLY prometheus_alerts ALTER COLUMN id SET DEFAULT nextval('prometheus_alerts_id_seq'::regclass);
@@ -26419,6 +26662,8 @@ ALTER TABLE ONLY work_item_types ALTER COLUMN id SET DEFAULT nextval('work_item_
ALTER TABLE ONLY work_item_widget_definitions ALTER COLUMN id SET DEFAULT nextval('work_item_widget_definitions_id_seq'::regclass);
+ALTER TABLE ONLY workspace_variables ALTER COLUMN id SET DEFAULT nextval('workspace_variables_id_seq'::regclass);
+
ALTER TABLE ONLY workspaces ALTER COLUMN id SET DEFAULT nextval('workspaces_id_seq'::regclass);
ALTER TABLE ONLY x509_certificates ALTER COLUMN id SET DEFAULT nextval('x509_certificates_id_seq'::regclass);
@@ -27149,6 +27394,9 @@ ALTER TABLE ONLY ar_internal_metadata
ALTER TABLE ONLY atlassian_identities
ADD CONSTRAINT atlassian_identities_pkey PRIMARY KEY (user_id);
+ALTER TABLE ONLY audit_events_amazon_s3_configurations
+ ADD CONSTRAINT audit_events_amazon_s3_configurations_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY audit_events_external_audit_event_destinations
ADD CONSTRAINT audit_events_external_audit_event_destinations_pkey PRIMARY KEY (id);
@@ -27158,6 +27406,9 @@ ALTER TABLE ONLY audit_events_google_cloud_logging_configurations
ALTER TABLE ONLY audit_events_instance_external_audit_event_destinations
ADD CONSTRAINT audit_events_instance_external_audit_event_destinations_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY audit_events_instance_google_cloud_logging_configurations
+ ADD CONSTRAINT audit_events_instance_google_cloud_logging_configurations_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY audit_events
ADD CONSTRAINT audit_events_pkey PRIMARY KEY (id, created_at);
@@ -27878,6 +28129,9 @@ ALTER TABLE ONLY group_wiki_repositories
ALTER TABLE ONLY group_wiki_repository_states
ADD CONSTRAINT group_wiki_repository_states_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY groups_visits
+ ADD CONSTRAINT groups_visits_pkey PRIMARY KEY (id, visited_at);
+
ALTER TABLE ONLY historical_data
ADD CONSTRAINT historical_data_pkey PRIMARY KEY (id);
@@ -28355,6 +28609,9 @@ ALTER TABLE ONLY packages_nuget_dependency_link_metadata
ALTER TABLE ONLY packages_nuget_metadata
ADD CONSTRAINT packages_nuget_metadata_pkey PRIMARY KEY (package_id);
+ALTER TABLE ONLY packages_nuget_symbols
+ ADD CONSTRAINT packages_nuget_symbols_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY packages_package_file_build_infos
ADD CONSTRAINT packages_package_file_build_infos_pkey PRIMARY KEY (id);
@@ -28364,6 +28621,9 @@ ALTER TABLE ONLY packages_package_files
ALTER TABLE ONLY packages_packages
ADD CONSTRAINT packages_packages_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY packages_protection_rules
+ ADD CONSTRAINT packages_protection_rules_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY packages_pypi_metadata
ADD CONSTRAINT packages_pypi_metadata_pkey PRIMARY KEY (package_id);
@@ -28553,6 +28813,9 @@ ALTER TABLE ONLY projects
ALTER TABLE ONLY projects_sync_events
ADD CONSTRAINT projects_sync_events_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY projects_visits
+ ADD CONSTRAINT projects_visits_pkey PRIMARY KEY (id, visited_at);
+
ALTER TABLE ONLY prometheus_alert_events
ADD CONSTRAINT prometheus_alert_events_pkey PRIMARY KEY (id);
@@ -29036,6 +29299,9 @@ ALTER TABLE ONLY work_item_types
ALTER TABLE ONLY work_item_widget_definitions
ADD CONSTRAINT work_item_widget_definitions_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY workspace_variables
+ ADD CONSTRAINT workspace_variables_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY workspaces
ADD CONSTRAINT workspaces_pkey PRIMARY KEY (id);
@@ -30324,6 +30590,8 @@ CREATE INDEX i_dast_profiles_tags_on_scanner_profiles_id ON dast_profiles_tags U
CREATE INDEX i_dast_scanner_profiles_tags_on_scanner_profiles_id ON dast_scanner_profiles_tags USING btree (dast_scanner_profile_id);
+CREATE UNIQUE INDEX i_packages_unique_project_id_package_type_package_name_pattern ON packages_protection_rules USING btree (project_id, package_type, package_name_pattern);
+
CREATE INDEX i_pkgs_deb_file_meta_on_updated_at_package_file_id_when_unknown ON packages_debian_file_metadata USING btree (updated_at, package_file_id) WHERE (file_type = 1);
CREATE UNIQUE INDEX i_pm_licenses_on_spdx_identifier ON pm_licenses USING btree (spdx_identifier);
@@ -30334,6 +30602,8 @@ CREATE UNIQUE INDEX i_pm_package_versions_on_package_id_and_version ON pm_packag
CREATE UNIQUE INDEX i_pm_packages_purl_type_and_name ON pm_packages USING btree (purl_type, name);
+CREATE INDEX idx_abuse_reports_user_id_status_and_category ON abuse_reports USING btree (user_id, status, category);
+
CREATE INDEX idx_alert_management_alerts_on_created_at_project_id_with_issue ON alert_management_alerts USING btree (created_at, project_id) WHERE (issue_id IS NOT NULL);
CREATE INDEX idx_analytics_devops_adoption_segments_on_namespace_id ON analytics_devops_adoption_segments USING btree (namespace_id);
@@ -31084,8 +31354,12 @@ CREATE INDEX index_ci_pipeline_chat_data_on_chat_name_id ON ci_pipeline_chat_dat
CREATE UNIQUE INDEX index_ci_pipeline_chat_data_on_pipeline_id ON ci_pipeline_chat_data USING btree (pipeline_id);
+CREATE UNIQUE INDEX index_ci_pipeline_chat_data_on_pipeline_id_convert_to_bigint ON ci_pipeline_chat_data USING btree (pipeline_id_convert_to_bigint);
+
CREATE INDEX index_ci_pipeline_messages_on_pipeline_id ON ci_pipeline_messages USING btree (pipeline_id);
+CREATE INDEX index_ci_pipeline_messages_on_pipeline_id_convert_to_bigint ON ci_pipeline_messages USING btree (pipeline_id_convert_to_bigint);
+
CREATE INDEX index_ci_pipeline_metadata_on_project_id ON ci_pipeline_metadata USING btree (project_id);
CREATE UNIQUE INDEX index_ci_pipeline_schedule_variables_on_schedule_id_and_key ON ci_pipeline_schedule_variables USING btree (pipeline_schedule_id, key);
@@ -31254,6 +31528,14 @@ CREATE UNIQUE INDEX index_ci_stages_on_pipeline_id_and_name ON ci_stages USING b
CREATE INDEX index_ci_stages_on_pipeline_id_and_position ON ci_stages USING btree (pipeline_id, "position");
+CREATE INDEX index_ci_stages_on_pipeline_id_convert_to_bigint ON ci_stages USING btree (pipeline_id_convert_to_bigint);
+
+CREATE INDEX index_ci_stages_on_pipeline_id_convert_to_bigint_and_id ON ci_stages USING btree (pipeline_id_convert_to_bigint, id) WHERE (status = ANY (ARRAY[0, 1, 2, 8, 9, 10]));
+
+CREATE UNIQUE INDEX index_ci_stages_on_pipeline_id_convert_to_bigint_and_name ON ci_stages USING btree (pipeline_id_convert_to_bigint, name);
+
+CREATE INDEX index_ci_stages_on_pipeline_id_convert_to_bigint_and_position ON ci_stages USING btree (pipeline_id_convert_to_bigint, "position");
+
CREATE INDEX index_ci_stages_on_project_id ON ci_stages USING btree (project_id);
CREATE INDEX index_ci_subscriptions_projects_author_id ON ci_subscriptions_projects USING btree (author_id);
@@ -31510,8 +31792,6 @@ CREATE INDEX index_deployments_on_environment_status_sha ON deployments USING bt
CREATE INDEX index_deployments_on_id_and_status_and_created_at ON deployments USING btree (id, status, created_at);
-CREATE INDEX index_deployments_on_id_where_cluster_id_present ON deployments USING btree (id) WHERE (cluster_id IS NOT NULL);
-
CREATE INDEX index_deployments_on_project_and_environment_and_updated_at_id ON deployments USING btree (project_id, environment_id, updated_at, id);
CREATE INDEX index_deployments_on_project_and_finished ON deployments USING btree (project_id, finished_at) WHERE (status = 2);
@@ -31746,8 +32026,6 @@ CREATE UNIQUE INDEX index_fork_network_members_on_project_id ON fork_network_mem
CREATE UNIQUE INDEX index_fork_networks_on_root_project_id ON fork_networks USING btree (root_project_id);
-CREATE INDEX index_fuc_over_limit_notified_at ON namespace_details USING btree (free_user_cap_over_limit_notified_at);
-
CREATE INDEX index_geo_event_log_on_cache_invalidation_event_id ON geo_event_log USING btree (cache_invalidation_event_id) WHERE (cache_invalidation_event_id IS NOT NULL);
CREATE INDEX index_geo_event_log_on_geo_event_id ON geo_event_log USING btree (geo_event_id) WHERE (geo_event_id IS NOT NULL);
@@ -31912,6 +32190,10 @@ CREATE INDEX index_groups_on_parent_id_id ON namespaces USING btree (parent_id,
CREATE INDEX index_groups_on_path_and_id ON namespaces USING btree (path, id) WHERE ((type)::text = 'Group'::text);
+CREATE INDEX index_groups_visits_on_entity_id ON ONLY groups_visits USING btree (entity_id);
+
+CREATE INDEX index_groups_visits_on_user_id_and_entity_id_and_visited_at ON ONLY groups_visits USING btree (user_id, entity_id, visited_at);
+
CREATE INDEX index_historical_data_on_recorded_at ON historical_data USING btree (recorded_at);
CREATE UNIQUE INDEX index_http_integrations_on_project_and_endpoint ON alert_management_http_integrations USING btree (project_id, endpoint_identifier);
@@ -32342,6 +32624,8 @@ CREATE INDEX index_merge_requests_compliance_violations_on_violating_user_id ON
CREATE UNIQUE INDEX index_merge_requests_compliance_violations_unique_columns ON merge_requests_compliance_violations USING btree (merge_request_id, violating_user_id, reason);
+CREATE INDEX index_merge_requests_id_created_at_prepared_at ON merge_requests USING btree (created_at, id) WHERE (prepared_at IS NULL);
+
CREATE INDEX index_merge_requests_on_assignee_id ON merge_requests USING btree (assignee_id);
CREATE INDEX index_merge_requests_on_author_id ON merge_requests USING btree (author_id);
@@ -32358,8 +32642,6 @@ CREATE INDEX index_merge_requests_on_description_trigram ON merge_requests USING
CREATE INDEX index_merge_requests_on_head_pipeline_id ON merge_requests USING btree (head_pipeline_id);
-CREATE INDEX index_merge_requests_on_id_and_prepared_at ON merge_requests USING btree (id) WHERE (prepared_at IS NULL);
-
CREATE INDEX index_merge_requests_on_latest_merge_request_diff_id ON merge_requests USING btree (latest_merge_request_diff_id);
CREATE INDEX index_merge_requests_on_merge_user_id ON merge_requests USING btree (merge_user_id) WHERE (merge_user_id IS NOT NULL);
@@ -32380,6 +32662,8 @@ CREATE UNIQUE INDEX index_merge_requests_on_target_project_id_and_iid ON merge_r
CREATE INDEX index_merge_requests_on_target_project_id_and_iid_and_state_id ON merge_requests USING btree (target_project_id, iid, state_id);
+CREATE INDEX index_merge_requests_on_target_project_id_and_merged_commit_sha ON merge_requests USING btree (target_project_id, merged_commit_sha);
+
CREATE INDEX index_merge_requests_on_target_project_id_and_source_branch ON merge_requests USING btree (target_project_id, source_branch);
CREATE INDEX index_merge_requests_on_target_project_id_and_squash_commit_sha ON merge_requests USING btree (target_project_id, squash_commit_sha);
@@ -32550,8 +32834,6 @@ CREATE INDEX index_namespaces_public_groups_name_id ON namespaces USING btree (n
CREATE INDEX index_namespaces_sync_events_on_namespace_id ON namespaces_sync_events USING btree (namespace_id);
-CREATE INDEX index_next_over_limit_check_at_asc_order ON namespace_details USING btree (next_over_limit_check_at NULLS FIRST);
-
CREATE INDEX index_non_requested_project_members_on_source_id_and_type ON members USING btree (source_id, source_type) WHERE ((requested_at IS NULL) AND ((type)::text = 'ProjectMember'::text));
CREATE UNIQUE INDEX index_note_diff_files_on_diff_note_id ON note_diff_files USING btree (diff_note_id);
@@ -32700,6 +32982,8 @@ CREATE UNIQUE INDEX index_ops_feature_flags_issues_on_feature_flag_id_and_issue_
CREATE UNIQUE INDEX index_ops_strategies_user_lists_on_strategy_id_and_user_list_id ON operations_strategies_user_lists USING btree (strategy_id, user_list_id);
+CREATE INDEX index_organization_users_on_organization_id_and_id ON organization_users USING btree (organization_id, id);
+
CREATE UNIQUE INDEX index_organization_users_on_organization_id_and_user_id ON organization_users USING btree (organization_id, user_id);
CREATE INDEX index_organization_users_on_user_id ON organization_users USING btree (user_id);
@@ -32758,6 +33042,12 @@ CREATE INDEX index_packages_npm_metadata_caches_on_project_id ON packages_npm_me
CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON packages_nuget_dependency_link_metadata USING btree (dependency_link_id);
+CREATE UNIQUE INDEX index_packages_nuget_symbols_on_object_storage_key ON packages_nuget_symbols USING btree (object_storage_key);
+
+CREATE INDEX index_packages_nuget_symbols_on_package_id ON packages_nuget_symbols USING btree (package_id);
+
+CREATE UNIQUE INDEX index_packages_nuget_symbols_on_signature_and_file_path ON packages_nuget_symbols USING btree (signature, file_path);
+
CREATE INDEX index_packages_on_available_pypi_packages ON packages_packages USING btree (project_id, id) WHERE ((status = ANY (ARRAY[0, 1])) AND (package_type = 5) AND (version IS NOT NULL));
CREATE INDEX index_packages_package_file_build_infos_on_package_file_id ON packages_package_file_build_infos USING btree (package_file_id);
@@ -32826,8 +33116,6 @@ CREATE INDEX index_pages_deployments_on_file_store_and_id ON pages_deployments U
CREATE INDEX index_pages_deployments_on_project_id ON pages_deployments USING btree (project_id);
-CREATE UNIQUE INDEX index_pages_deployments_unique_path_prefix_by_project ON pages_deployments USING btree (project_id, path_prefix);
-
CREATE INDEX index_pages_domain_acme_orders_on_challenge_token ON pages_domain_acme_orders USING btree (challenge_token);
CREATE INDEX index_pages_domain_acme_orders_on_pages_domain_id ON pages_domain_acme_orders USING btree (pages_domain_id);
@@ -33026,6 +33314,8 @@ CREATE UNIQUE INDEX index_project_statistics_on_project_id ON project_statistics
CREATE INDEX index_project_statistics_on_repository_size_and_project_id ON project_statistics USING btree (repository_size, project_id);
+CREATE INDEX index_project_statistics_on_root_namespace_id ON project_statistics USING btree (root_namespace_id);
+
CREATE INDEX index_project_statistics_on_storage_size_and_project_id ON project_statistics USING btree (storage_size, project_id);
CREATE INDEX index_project_statistics_on_wiki_size_and_project_id ON project_statistics USING btree (wiki_size, project_id);
@@ -33110,6 +33400,8 @@ CREATE INDEX index_projects_on_namespace_id_and_id ON projects USING btree (name
CREATE INDEX index_projects_on_namespace_id_and_repository_size_limit ON projects USING btree (namespace_id, repository_size_limit);
+CREATE INDEX index_projects_on_organization_id ON projects USING btree (organization_id);
+
CREATE INDEX index_projects_on_path_and_id ON projects USING btree (path, id);
CREATE INDEX index_projects_on_path_trigram ON projects USING gin (path gin_trgm_ops);
@@ -33128,6 +33420,10 @@ CREATE INDEX index_projects_on_updated_at_and_id ON projects USING btree (update
CREATE INDEX index_projects_sync_events_on_project_id ON projects_sync_events USING btree (project_id);
+CREATE INDEX index_projects_visits_on_entity_id ON ONLY projects_visits USING btree (entity_id);
+
+CREATE INDEX index_projects_visits_on_user_id_and_entity_id_and_visited_at ON ONLY projects_visits USING btree (user_id, entity_id, visited_at);
+
CREATE UNIQUE INDEX index_prometheus_alert_event_scoped_payload_key ON prometheus_alert_events USING btree (prometheus_alert_id, payload_key);
CREATE INDEX index_prometheus_alert_events_on_project_id_and_status ON prometheus_alert_events USING btree (project_id, status);
@@ -33352,10 +33648,12 @@ CREATE UNIQUE INDEX index_sbom_components_on_component_type_name_and_purl_type O
CREATE INDEX index_sbom_occurrences_for_input_file_path_search ON sbom_occurrences USING btree (project_id, component_id, input_file_path);
-CREATE INDEX index_sbom_occurrences_on_component_id ON sbom_occurrences USING btree (component_id);
+CREATE INDEX index_sbom_occurrences_on_component_id_and_id ON sbom_occurrences USING btree (component_id, id);
CREATE INDEX index_sbom_occurrences_on_component_version_id ON sbom_occurrences USING btree (component_version_id);
+CREATE INDEX index_sbom_occurrences_on_licenses_spdx_identifier ON sbom_occurrences USING btree (project_id, ((licenses #> '{0,spdx_identifier}'::text[])), ((licenses #> '{1,spdx_identifier}'::text[])));
+
CREATE INDEX index_sbom_occurrences_on_pipeline_id ON sbom_occurrences USING btree (pipeline_id);
CREATE INDEX index_sbom_occurrences_on_project_id ON sbom_occurrences USING btree (project_id);
@@ -33568,8 +33866,6 @@ CREATE UNIQUE INDEX index_subscriptions_on_subscribable_and_user_id_and_project_
CREATE INDEX index_successful_authentication_events_for_metrics ON authentication_events USING btree (user_id, provider, created_at) WHERE (result = 1);
-CREATE INDEX index_successful_deployments_on_cluster_id_and_environment_id ON deployments USING btree (cluster_id, environment_id) WHERE (status = 2);
-
CREATE UNIQUE INDEX index_suggestions_on_note_id_and_relative_order ON suggestions USING btree (note_id, relative_order);
CREATE UNIQUE INDEX index_system_access_microsoft_applications_on_namespace_id ON system_access_microsoft_applications USING btree (namespace_id);
@@ -33844,6 +34140,8 @@ COMMENT ON INDEX index_verification_codes_on_phone_and_visitor_id_code IS 'JiHu-
CREATE UNIQUE INDEX index_vuln_findings_on_uuid_including_vuln_id ON vulnerability_occurrences USING btree (uuid) INCLUDE (vulnerability_id);
+CREATE UNIQUE INDEX index_vuln_findings_on_uuid_including_vuln_id_1 ON vulnerability_occurrences USING btree (uuid_convert_string_to_uuid) INCLUDE (vulnerability_id);
+
CREATE UNIQUE INDEX index_vuln_historical_statistics_on_project_id_and_date ON vulnerability_historical_statistics USING btree (project_id, date);
CREATE INDEX index_vuln_reads_common_query_on_resolved_on_default_branch ON vulnerability_reads USING btree (project_id, state, report_type, vulnerability_id DESC) WHERE (resolved_on_default_branch IS TRUE);
@@ -33868,6 +34166,8 @@ CREATE INDEX index_vulnerabilities_on_due_date_sourcing_milestone_id ON vulnerab
CREATE INDEX index_vulnerabilities_on_epic_id ON vulnerabilities USING btree (epic_id);
+CREATE INDEX index_vulnerabilities_on_finding_id ON vulnerabilities USING btree (finding_id);
+
CREATE INDEX index_vulnerabilities_on_last_edited_by_id ON vulnerabilities USING btree (last_edited_by_id);
CREATE INDEX index_vulnerabilities_on_milestone_id ON vulnerabilities USING btree (milestone_id);
@@ -33962,6 +34262,8 @@ CREATE INDEX index_vulnerability_occurrences_on_scanner_id ON vulnerability_occu
CREATE UNIQUE INDEX index_vulnerability_occurrences_on_uuid ON vulnerability_occurrences USING btree (uuid);
+CREATE UNIQUE INDEX index_vulnerability_occurrences_on_uuid_1 ON vulnerability_occurrences USING btree (uuid_convert_string_to_uuid);
+
CREATE INDEX index_vulnerability_occurrences_on_vulnerability_id ON vulnerability_occurrences USING btree (vulnerability_id);
CREATE INDEX index_vulnerability_reads_common_finder_query_2 ON vulnerability_reads USING btree (project_id, state, report_type, severity, vulnerability_id DESC, dismissal_reason);
@@ -34064,10 +34366,14 @@ CREATE UNIQUE INDEX index_work_item_widget_definitions_on_namespace_type_and_nam
CREATE INDEX index_work_item_widget_definitions_on_work_item_type_id ON work_item_widget_definitions USING btree (work_item_type_id);
+CREATE INDEX index_workspace_variables_on_workspace_id ON workspace_variables USING btree (workspace_id);
+
CREATE INDEX index_workspaces_on_cluster_agent_id ON workspaces USING btree (cluster_agent_id);
CREATE UNIQUE INDEX index_workspaces_on_name ON workspaces USING btree (name);
+CREATE INDEX index_workspaces_on_personal_access_token_id ON workspaces USING btree (personal_access_token_id);
+
CREATE INDEX index_workspaces_on_project_id ON workspaces USING btree (project_id);
CREATE INDEX index_workspaces_on_user_id ON workspaces USING btree (user_id);
@@ -34132,6 +34438,8 @@ CREATE INDEX packages_packages_needs_verification ON packages_package_files USIN
CREATE INDEX packages_packages_pending_verification ON packages_package_files USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0);
+CREATE INDEX pages_deployments_deleted_at_index ON pages_deployments USING btree (id, project_id, path_prefix) WHERE (deleted_at IS NULL);
+
CREATE UNIQUE INDEX partial_index_bulk_import_exports_on_group_id_and_relation ON bulk_import_exports USING btree (group_id, relation) WHERE (group_id IS NOT NULL);
CREATE UNIQUE INDEX partial_index_bulk_import_exports_on_project_id_and_relation ON bulk_import_exports USING btree (project_id, relation) WHERE (project_id IS NOT NULL);
@@ -34192,8 +34500,6 @@ CREATE INDEX tmp_idx_orphaned_approval_project_rules ON approval_project_rules U
CREATE INDEX tmp_idx_packages_on_project_id_when_npm_not_pending_destruction ON packages_packages USING btree (project_id) WHERE ((package_type = 2) AND (status <> 4));
-CREATE INDEX tmp_idx_vuln_reads_where_dismissal_reason_null ON vulnerability_reads USING btree (id) WHERE ((state = 2) AND (dismissal_reason IS NULL));
-
CREATE INDEX tmp_idx_vulns_on_converted_uuid ON vulnerability_occurrences USING btree (id, uuid_convert_string_to_uuid) WHERE (uuid_convert_string_to_uuid = '00000000-0000-0000-0000-000000000000'::uuid);
CREATE INDEX tmp_index_ci_job_artifacts_on_expire_at_where_locked_unknown ON ci_job_artifacts USING btree (expire_at, job_id) WHERE ((locked = 2) AND (expire_at IS NOT NULL));
@@ -34212,6 +34518,8 @@ CREATE INDEX tmp_index_project_statistics_cont_registry_size ON project_statisti
CREATE INDEX tmp_index_project_statistics_pipeline_artifacts_size ON project_statistics USING btree (project_id) WHERE (pipeline_artifacts_size <> 0);
+CREATE INDEX tmp_index_project_statistics_updated_at ON project_statistics USING btree (project_id, updated_at) WHERE (repository_size > 0);
+
CREATE INDEX tmp_index_vulnerability_dismissal_info ON vulnerabilities USING btree (id) WHERE ((state = 2) AND ((dismissed_at IS NULL) OR (dismissed_by_id IS NULL)));
CREATE INDEX tmp_index_vulnerability_overlong_title_html ON vulnerabilities USING btree (id) WHERE (length(title_html) > 800);
@@ -34240,6 +34548,10 @@ CREATE UNIQUE INDEX uniq_pkgs_debian_project_distributions_project_id_and_codena
CREATE UNIQUE INDEX uniq_pkgs_debian_project_distributions_project_id_and_suite ON packages_debian_project_distributions USING btree (project_id, suite);
+CREATE UNIQUE INDEX unique_amazon_s3_configurations_namespace_id_and_bucket_name ON audit_events_amazon_s3_configurations USING btree (namespace_id, bucket_name);
+
+CREATE UNIQUE INDEX unique_amazon_s3_configurations_namespace_id_and_name ON audit_events_amazon_s3_configurations USING btree (namespace_id, name);
+
CREATE UNIQUE INDEX unique_ci_builds_token_encrypted_and_partition_id ON ci_builds USING btree (token_encrypted, partition_id) WHERE (token_encrypted IS NOT NULL);
CREATE UNIQUE INDEX unique_external_audit_event_destination_namespace_id_and_name ON audit_events_external_audit_event_destinations USING btree (namespace_id, name);
@@ -34258,6 +34570,10 @@ CREATE UNIQUE INDEX unique_index_sysaccess_ms_access_tokens_on_sysaccess_ms_app_
CREATE UNIQUE INDEX unique_instance_audit_event_destination_name ON audit_events_instance_external_audit_event_destinations USING btree (name);
+CREATE UNIQUE INDEX unique_instance_google_cloud_logging_configurations ON audit_events_instance_google_cloud_logging_configurations USING btree (google_project_id_name, log_id_name);
+
+CREATE UNIQUE INDEX unique_instance_google_cloud_logging_configurations_name ON audit_events_instance_google_cloud_logging_configurations USING btree (name);
+
CREATE UNIQUE INDEX unique_merge_request_diff_llm_summaries_on_mr_diff_id ON merge_request_diff_llm_summaries USING btree (merge_request_diff_id);
CREATE UNIQUE INDEX unique_merge_request_metrics_by_merge_request_id ON merge_request_metrics USING btree (merge_request_id);
@@ -35930,8 +36246,12 @@ CREATE TRIGGER trigger_7f3d66a7d7f5 BEFORE INSERT OR UPDATE ON ci_pipeline_varia
CREATE TRIGGER trigger_b2d852e1e2cb BEFORE INSERT OR UPDATE ON ci_pipelines FOR EACH ROW EXECUTE FUNCTION trigger_b2d852e1e2cb();
+CREATE TRIGGER trigger_bbb95b2d6929 BEFORE INSERT OR UPDATE ON ci_project_monthly_usages FOR EACH ROW EXECUTE FUNCTION trigger_bbb95b2d6929();
+
CREATE TRIGGER trigger_bfad0e2b9c86 BEFORE INSERT OR UPDATE ON ci_pipeline_messages FOR EACH ROW EXECUTE FUNCTION trigger_bfad0e2b9c86();
+CREATE TRIGGER trigger_c0353bbb6145 BEFORE INSERT OR UPDATE ON ci_namespace_monthly_usages FOR EACH ROW EXECUTE FUNCTION trigger_c0353bbb6145();
+
CREATE TRIGGER trigger_delete_project_namespace_on_project_delete AFTER DELETE ON projects FOR EACH ROW WHEN ((old.project_namespace_id IS NOT NULL)) EXECUTE FUNCTION delete_associated_project_namespace();
CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON integrations FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker();
@@ -36022,6 +36342,9 @@ ALTER TABLE ONLY user_interacted_projects
ALTER TABLE ONLY merge_request_assignment_events
ADD CONSTRAINT fk_08f7602bfd FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
+ALTER TABLE ONLY ci_pipeline_messages
+ ADD CONSTRAINT fk_0946fea681 FOREIGN KEY (pipeline_id_convert_to_bigint) REFERENCES ci_pipelines(id) ON DELETE CASCADE NOT VALID;
+
ALTER TABLE ONLY remote_development_agent_configs
ADD CONSTRAINT fk_0a3c0ada56 FOREIGN KEY (cluster_agent_id) REFERENCES cluster_agents(id) ON DELETE CASCADE;
@@ -36037,9 +36360,6 @@ ALTER TABLE ONLY ssh_signatures
ALTER TABLE ONLY web_hooks
ADD CONSTRAINT fk_0c8ca6d9d1 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-ALTER TABLE ONLY notification_settings
- ADD CONSTRAINT fk_0c95e91db7 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY lists
ADD CONSTRAINT fk_0d3f677137 FOREIGN KEY (board_id) REFERENCES boards(id) ON DELETE CASCADE;
@@ -36094,6 +36414,9 @@ ALTER TABLE ONLY ci_pipelines
ALTER TABLE ONLY analytics_devops_adoption_segments
ADD CONSTRAINT fk_190a24754d FOREIGN KEY (display_namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+ALTER TABLE ONLY project_statistics
+ ADD CONSTRAINT fk_198ad46fdc FOREIGN KEY (root_namespace_id) REFERENCES namespaces(id) ON DELETE SET NULL;
+
ALTER TABLE ONLY agent_project_authorizations
ADD CONSTRAINT fk_1d30bb4987 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -36172,9 +36495,6 @@ ALTER TABLE ONLY deployment_approvals
ALTER TABLE ONLY notes
ADD CONSTRAINT fk_2e82291620 FOREIGN KEY (review_id) REFERENCES reviews(id) ON DELETE SET NULL;
-ALTER TABLE ONLY members
- ADD CONSTRAINT fk_2e88fb7ce9 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY lfs_objects_projects
ADD CONSTRAINT fk_2eb33f7a78 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE NOT VALID;
@@ -36298,6 +36618,9 @@ ALTER TABLE ONLY sbom_occurrences
ALTER TABLE ONLY namespace_commit_emails
ADD CONSTRAINT fk_4d6ba63ba5 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+ALTER TABLE ONLY vulnerabilities
+ ADD CONSTRAINT fk_4e64972902 FOREIGN KEY (finding_id) REFERENCES vulnerability_occurrences(id) ON DELETE CASCADE NOT VALID;
+
ALTER TABLE ONLY ml_model_versions
ADD CONSTRAINT fk_4e8b59e7a8 FOREIGN KEY (model_id) REFERENCES ml_models(id) ON DELETE CASCADE;
@@ -36343,6 +36666,9 @@ ALTER TABLE ONLY approval_merge_request_rules
ALTER TABLE ONLY deploy_keys_projects
ADD CONSTRAINT fk_58a901ca7e FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY ci_pipeline_chat_data
+ ADD CONSTRAINT fk_5b21bde562 FOREIGN KEY (pipeline_id_convert_to_bigint) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY dependency_list_exports
ADD CONSTRAINT fk_5b3d11e1ef FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
@@ -36748,9 +37074,6 @@ ALTER TABLE ONLY deployments
ALTER TABLE ONLY project_compliance_standards_adherence
ADD CONSTRAINT fk_baf6f6f878 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-ALTER TABLE ONLY routes
- ADD CONSTRAINT fk_bb2e5b8968 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
-
ALTER TABLE p_ci_runner_machine_builds
ADD CONSTRAINT fk_bb490f12fe_p FOREIGN KEY (partition_id, build_id) REFERENCES p_ci_builds(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;
@@ -36979,6 +37302,9 @@ ALTER TABLE ONLY pages_domains
ALTER TABLE ONLY catalog_resource_components
ADD CONSTRAINT fk_ec417536da FOREIGN KEY (catalog_resource_id) REFERENCES catalog_resources(id) ON DELETE CASCADE;
+ALTER TABLE ONLY workspaces
+ ADD CONSTRAINT fk_ec70695b2c FOREIGN KEY (personal_access_token_id) REFERENCES personal_access_tokens(id) ON DELETE RESTRICT;
+
ALTER TABLE ONLY merge_requests_compliance_violations
ADD CONSTRAINT fk_ec881c1c6f FOREIGN KEY (violating_user_id) REFERENCES users(id) ON DELETE CASCADE;
@@ -37645,6 +37971,9 @@ ALTER TABLE ONLY elastic_group_index_statuses
ALTER TABLE ONLY bulk_import_configurations
ADD CONSTRAINT fk_rails_536b96bff1 FOREIGN KEY (bulk_import_id) REFERENCES bulk_imports(id) ON DELETE CASCADE;
+ALTER TABLE ONLY workspace_variables
+ ADD CONSTRAINT fk_rails_539844891e FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY x509_commit_signatures
ADD CONSTRAINT fk_rails_53fe41188f FOREIGN KEY (x509_certificate_id) REFERENCES x509_certificates(id) ON DELETE CASCADE;
@@ -37717,6 +38046,9 @@ ALTER TABLE ONLY ci_running_builds
ALTER TABLE ONLY epic_issues
ADD CONSTRAINT fk_rails_5d942936b4 FOREIGN KEY (epic_id) REFERENCES epics(id) ON DELETE CASCADE;
+ALTER TABLE ONLY packages_nuget_symbols
+ ADD CONSTRAINT fk_rails_5df972da14 FOREIGN KEY (package_id) REFERENCES packages_packages(id) ON DELETE SET NULL;
+
ALTER TABLE ONLY resource_weight_events
ADD CONSTRAINT fk_rails_5eb5cb92a1 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
@@ -37975,6 +38307,9 @@ ALTER TABLE ONLY security_trainings
ALTER TABLE ONLY zentao_tracker_data
ADD CONSTRAINT fk_rails_84efda7be0 FOREIGN KEY (integration_id) REFERENCES integrations(id) ON DELETE CASCADE;
+ALTER TABLE ONLY audit_events_amazon_s3_configurations
+ ADD CONSTRAINT fk_rails_84f4b10a16 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY boards_epic_user_preferences
ADD CONSTRAINT fk_rails_851fe1510a FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
@@ -38638,6 +38973,9 @@ ALTER TABLE ONLY clusters_integration_prometheus
ALTER TABLE ONLY vulnerability_occurrence_identifiers
ADD CONSTRAINT fk_rails_e4ef6d027c FOREIGN KEY (occurrence_id) REFERENCES vulnerability_occurrences(id) ON DELETE CASCADE;
+ALTER TABLE ONLY packages_protection_rules
+ ADD CONSTRAINT fk_rails_e52adb5267 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY vulnerability_flags
ADD CONSTRAINT fk_rails_e59393b48b FOREIGN KEY (vulnerability_occurrence_id) REFERENCES vulnerability_occurrences(id) ON DELETE CASCADE;
@@ -38855,7 +39193,7 @@ ALTER TABLE product_analytics_events_experimental
ADD CONSTRAINT product_analytics_events_experimental_project_id_fkey FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY ci_pipeline_variables
- ADD CONSTRAINT temp_fk_rails_8d3b04e3e1 FOREIGN KEY (pipeline_id_convert_to_bigint) REFERENCES ci_pipelines(id) ON DELETE CASCADE NOT VALID;
+ ADD CONSTRAINT temp_fk_rails_8d3b04e3e1 FOREIGN KEY (pipeline_id_convert_to_bigint) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
ALTER TABLE ONLY user_follow_users
ADD CONSTRAINT user_follow_users_followee_id_fkey FOREIGN KEY (followee_id) REFERENCES users(id) ON DELETE CASCADE;
diff --git a/doc/.vale/gitlab/BadgeCapitalization.yml b/doc/.vale/gitlab/BadgeCapitalization.yml
index 6e77c3fe822..a44bcbc0a7d 100644
--- a/doc/.vale/gitlab/BadgeCapitalization.yml
+++ b/doc/.vale/gitlab/BadgeCapitalization.yml
@@ -10,5 +10,5 @@ link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html
level: error
scope: raw
raw:
- - '(?!\*\*\((FREE|PREMIUM|ULTIMATE)( (SELF|SAAS))?\)\*\*)'
- - '(?i)\*\*\((free|premium|ultimate)( (self|saas))?\)\*\*'
+ - '(?!\*\*\((FREE|PREMIUM|ULTIMATE)( (SELF|SAAS|ALL) (BETA|EXPERIMENT))?\)\*\*)'
+ - '(?i)\*\*\((free|premium|ultimate)( (self|saas|all) (beta|experiment))?\)\*\*'
diff --git a/doc/.vale/gitlab/SubstitutionWarning.yml b/doc/.vale/gitlab/SubstitutionWarning.yml
index c081ca5a4f7..94befa9c0e6 100644
--- a/doc/.vale/gitlab/SubstitutionWarning.yml
+++ b/doc/.vale/gitlab/SubstitutionWarning.yml
@@ -59,6 +59,6 @@ swap:
sub-group: "subgroup"
sub-groups: "subgroups"
timezone: "time zone"
- utilize: "use"
+ utiliz(?:es?|ing): "use"
we recommend: "you should"
within: "in"
diff --git a/doc/.vale/gitlab/Substitutions.yml b/doc/.vale/gitlab/Substitutions.yml
index 10369669ca5..0d49ac583dd 100644
--- a/doc/.vale/gitlab/Substitutions.yml
+++ b/doc/.vale/gitlab/Substitutions.yml
@@ -14,6 +14,7 @@ swap:
codequality: code quality
Customer [Pp]ortal: Customers Portal
disallow: prevent
+ '(?<!GitLab )Duo': GitLab Duo
frontmatter: front matter
GitLabber: GitLab team member
GitLabbers: GitLab team members
diff --git a/doc/.vale/gitlab/Uppercase.yml b/doc/.vale/gitlab/Uppercase.yml
index 4730184b950..b13ebe2c0a8 100644
--- a/doc/.vale/gitlab/Uppercase.yml
+++ b/doc/.vale/gitlab/Uppercase.yml
@@ -16,6 +16,7 @@ second: '(?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)'
exceptions:
- ACL
- AJAX
+ - ALL
- AMI
- ANSI
- APAC
@@ -27,6 +28,7 @@ exceptions:
- ASG
- AST
- AWS
+ - BETA
- BMP
- BSD
- CAS
diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt
index 1e66d12adc9..575dc713b51 100644
--- a/doc/.vale/gitlab/spelling-exceptions.txt
+++ b/doc/.vale/gitlab/spelling-exceptions.txt
@@ -109,6 +109,7 @@ bugfixed
bugfixes
bugfixing
Bugzilla
+Buildah
Buildkite
buildpack
buildpacks
@@ -350,6 +351,7 @@ Fastly
Fastzip
favicon
favorited
+Fediverse
ffaker
Figma
Filebeat
@@ -525,6 +527,7 @@ LaunchDarkly
ldapsearch
Lefthook
Leiningen
+Lemmy
libFuzzer
Libgcrypt
Libravatar
@@ -644,6 +647,7 @@ OmniAuth
onboarding
OpenID
OpenShift
+OpenTelemetry
Opsgenie
Opstrace
ORMs
@@ -958,6 +962,7 @@ subqueried
subqueries
subquery
subquerying
+Subreddit
substring
substrings
subtask
diff --git a/doc/administration/admin_area.md b/doc/administration/admin_area.md
index 1e103bb55c8..a27fc04ff8f 100644
--- a/doc/administration/admin_area.md
+++ b/doc/administration/admin_area.md
@@ -10,7 +10,7 @@ type: reference
The Admin Area provides a web UI to manage and configure features of GitLab
self-managed instances. If you are an administrator,to access the Admin Area:
-- In GitLab 16.1 and later: on the left sidebar, expand the top-most chevron (**{chevron-down}**), then select **Admin Area**.
+- In GitLab 16.1 and later: on the left sidebar, select **Search or go to**, then select **Admin Area**.
- In GitLab 16.0 and earlier: on the top bar, select **Main menu > Admin**.
NOTE:
@@ -22,7 +22,7 @@ You can administer all projects in the GitLab instance from the Admin Area's Pro
To access the Projects page:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Projects**.
1. Select the **All**, **Private**, **Internal**, or **Public** tab to list only
@@ -74,7 +74,7 @@ You can combine the filter options. For example, to list only public projects wi
You can administer all users in the GitLab instance from the Admin Area's Users page:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
@@ -119,7 +119,7 @@ This allows the administrator to "see what the user sees," and take actions on b
You can impersonate a user in the following ways:
- Through the UI:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. From the list of users, select a user.
@@ -138,7 +138,7 @@ By default, impersonation is enabled. GitLab can be configured to [disable imper
When using authentication providers, administrators can see the identities for a user:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. From the list of users, select a user.
@@ -185,7 +185,7 @@ GitLab billing is based on the number of [**Billable users**](../subscriptions/s
You must be an administrator to manually add emails to users:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Locate the user and select them.
@@ -198,16 +198,16 @@ You must be an administrator to manually add emails to users:
The [Cohorts](user_cohorts.md) tab displays the monthly cohorts of new users and their activities over time.
-## Prevent a user from creating groups
+## Prevent a user from creating top level groups
-By default, users can create groups. To prevent a user from creating a top level group:
+By default, users can create top level groups. To prevent a user from creating a top level group:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Locate the user and select them.
1. Select **Edit**.
-1. Clear the **Can create group** checkbox.
+1. Clear the **Can create top level group** checkbox.
1. Select **Save changes**.
It is also possible to [limit which roles can create a subgroup within a group](../user/group/subgroups/index.md#change-who-can-create-subgroups).
@@ -218,7 +218,7 @@ You can administer all groups in the GitLab instance from the Admin Area's Group
To access the Groups page:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Groups**.
@@ -244,7 +244,7 @@ To [Create a new group](../user/group/index.md#create-a-group) select **New grou
To view all topics in the GitLab instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Topics**.
@@ -252,7 +252,7 @@ For each topic, the page displays its name and the number of projects labeled wi
### Search for topics
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Topics**.
1. In the search box, enter your search criteria.
@@ -262,7 +262,7 @@ For each topic, the page displays its name and the number of projects labeled wi
To create a topic:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Topics**.
1. Select **New topic**.
@@ -282,7 +282,7 @@ Do not include sensitive information in the name of a topic.
You can edit a topic's name, title, description, and avatar at any time.
To edit a topic:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Topics**.
1. Select **Edit** in that topic's row.
@@ -294,7 +294,7 @@ To edit a topic:
If you no longer need a topic, you can permanently remove it.
To remove a topic:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Topics**.
1. To remove a topic, select **Remove** in that topic's row.
@@ -307,7 +307,7 @@ After a merged topic is deleted, you cannot restore it.
To merge topics:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Topics**.
1. Select **Merge topics**.
@@ -322,7 +322,7 @@ page. For more details, see [Gitaly](gitaly/index.md).
To access the **Gitaly Servers** page:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Gitaly Servers**.
@@ -347,7 +347,7 @@ You can administer all runners in the GitLab instance from the Admin Area's **Ru
To access the **Runners** page:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Runners**.
@@ -374,7 +374,7 @@ You can also filter runners by status, type, and tag. To filter:
You can delete multiple runners at the same time.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Runners**.
1. To the left of the runners you want to delete, select the checkbox.
@@ -405,7 +405,7 @@ You can administer all jobs in the GitLab instance from the Admin Area's Jobs pa
To access the Jobs page:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **CI/CD > Jobs**. All jobs are listed, in descending order of job ID.
1. Select the **All** tab to list all jobs. Select the **Pending**, **Running**, or **Finished**
@@ -431,7 +431,7 @@ The following topics document the **Monitoring** section of the Admin Area.
### System Information
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/341248) in GitLab 15.2, support for relative time. "Uptime" statistic was renamed to "System started".
+> Support for relative time [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/341248) in GitLab 15.2. "Uptime" statistic was renamed to "System started".
The **System Info** page provides the following statistics:
diff --git a/doc/administration/analytics/dev_ops_reports.md b/doc/administration/analytics/dev_ops_reports.md
index 1dcee5ec03d..a5a3120489d 100644
--- a/doc/administration/analytics/dev_ops_reports.md
+++ b/doc/administration/analytics/dev_ops_reports.md
@@ -12,7 +12,7 @@ from planning to monitoring.
To see DevOps Reports:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Analytics > DevOps Reports**.
diff --git a/doc/administration/analytics/index.md b/doc/administration/analytics/index.md
index 6441cd866c8..5ba14222165 100644
--- a/doc/administration/analytics/index.md
+++ b/doc/administration/analytics/index.md
@@ -18,7 +18,7 @@ Prerequisite:
To view instance-level analytics:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Analytics**, then one of the available analytics:
diff --git a/doc/administration/analytics/usage_trends.md b/doc/administration/analytics/usage_trends.md
index 49e82f71a3a..20b732d028d 100644
--- a/doc/administration/analytics/usage_trends.md
+++ b/doc/administration/analytics/usage_trends.md
@@ -19,7 +19,7 @@ Usage Trends data refreshes daily.
To view Usage Trends:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Analytics > Usage Trends**.
diff --git a/doc/administration/appearance.md b/doc/administration/appearance.md
index c5c50d95eb6..ceb4a4a30e9 100644
--- a/doc/administration/appearance.md
+++ b/doc/administration/appearance.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Several options are available for customizing the appearance of a self-managed instance
of GitLab. To access these settings:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Appearance**.
@@ -29,7 +29,7 @@ supported by many email clients.
## Favicon
-By default, the favicon (used by the browser as the tab icon, as well as the CI status icon)
+By default, the favicon (used by the browser as the tab icon and the CI status icon)
uses the GitLab logo. This can be customized with any icon desired. It must be a
32x32 `.png` or `.ico` image.
@@ -42,7 +42,7 @@ of the page to activate it in the GitLab instance.
You can add a small header message, a small footer message, or both, to the interface
of your GitLab instance. These messages appear on all projects and pages of the
-instance, including the sign in / sign up page. The default color is white text on
+instance, including the sign-in/sign-up page. The default color is white text on
an orange background, but this can be customized by selecting **Customize colors**.
Limited [Markdown](../user/markdown.md) is supported, such as bold, italics, and links, for
@@ -55,9 +55,9 @@ the header and footer added to all emails sent by the GitLab instance.
After you add a message, select **Update appearance settings** at the bottom of the page
to activate it in the GitLab instance.
-## Sign in / Sign up pages
+## Sign-in / Sign-up pages
-You can replace the default message on the sign in / sign up page with your own message
+You can replace the default message on the sign-in/sign-up page with your own message
and logo. You can make full use of [Markdown](../user/markdown.md) in the description.
The optimal size for the logo is 128 x 128 pixels, but any image can be used (below 1 MB)
@@ -69,7 +69,7 @@ to activate it in the GitLab instance. You can also select **Sign-in page**,
to review the saved appearance settings:
NOTE:
-You can add also add a [customized hcelp message](settings/help_page.md) below the sign in message or add [a Sign in text message](settings/sign_in_restrictions.md#sign-in-information).
+You can add also add a [customized help message](settings/help_page.md) below the sign-in message or add [a Sign-in text message](settings/sign_in_restrictions.md#sign-in-information).
## Progressive Web App
@@ -83,7 +83,7 @@ description, and icon.
To configure the PWA settings:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Appearance**.
1. Scroll to the **Progressive Web App (PWA)** section.
diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md
index b69f1815394..5c27dabe378 100644
--- a/doc/administration/audit_event_streaming/audit_event_types.md
+++ b/doc/administration/audit_event_streaming/audit_event_types.md
@@ -9,18 +9,24 @@ info: "See the Technical Writers assigned to Development Guidelines: https://abo
Please do not edit this file directly. To update this file, run:
bundle exec rake gitlab:audit_event_types:compile_docs
+
+ To make changes to the output of the rake task,
+ edit `tooling/audit_events/docs/templates/audit_event_types.md.erb`.
--->
-# Audit event types **(ULTIMATE)**
+# Audit event types **(PREMIUM ALL)**
Audit event types are used to [filter streamed audit events](index.md#update-event-filters).
-Every audit event is associated with an event type. The association with the event type can mean that an audit event is:
+Every audit event is associated with an event type. Audit event types can allow audit events to be:
+
+- Saved to the database. Available in the Premium and Ultimate tier. You can retrieve audit events associated with these
+ types by using the audit events dashboard or the [audit events API](../../api/audit_events.md).
+- Streamed to external destinations. Available in the Ultimate tier. You can stream audit events associated with these
+ types [to external destinations](../index.md) if a destination is set.
-- Saved to database. Audit events associated with these types are retrievable by using the audit events dashboard or the [audit events API](../../api/audit_events.md).
-- Streamed. Audit events associated with these types are [streamed to external destinations](../index.md) if a
- destination is set.
-- Not streamed. Audit events associated with these types are not streamed to external destinations even if a destination is set.
+Some audit event types don't allow saving audit events to the database. Other audit event types don't allow streaming
+audit events to external destinations.
## Available audit event types
@@ -85,10 +91,11 @@ Every audit event is associated with an event type. The association with the eve
| [`destroy_compliance_framework`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74292) | Triggered on successful compliance framework deletion | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/340649) |
| [`destroy_event_streaming_destination`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74632) | Event triggered when an external audit event destination is deleted | **{check-circle}** Yes | **{check-circle}** Yes | `audit_events` | GitLab [14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/344664) |
| [`destroy_instance_event_streaming_destination`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125846) | Event triggered when an instance level external audit event destination is deleted | **{check-circle}** Yes | **{check-circle}** Yes | `audit_events` | GitLab [16.2](https://gitlab.com/gitlab-org/gitlab/-/issues/404730) |
+| [`email_confirmation_sent`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129261) | Triggered when users add or change and email address and it needs to be confirmed. | **{dotted-circle}** No | **{check-circle}** Yes | `user_profile` | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/377625) |
| [`email_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114546) | Event triggered when an email is created | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.11](https://gitlab.com/gitlab-org/gitlab/-/issues/374107) |
| [`email_destroyed`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114546) | Event triggered when an email is destroyed | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.11](https://gitlab.com/gitlab-org/gitlab/-/issues/374107) |
-| [`environment_protected`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108247) | This event is triggered when a protected environment is created. | **{check-circle}** Yes | **{dotted-circle}** No | `environment_management` | GitLab [15.8](https://gitlab.com/gitlab-org/gitlab/-/issues/216164) |
-| [`environment_unprotected`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108247) | This event is triggered when a protected environment is deleted. | **{check-circle}** Yes | **{dotted-circle}** No | `environment_management` | GitLab [15.8](https://gitlab.com/gitlab-org/gitlab/-/issues/216164) |
+| [`environment_protected`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108247) | This event is triggered when a protected environment is created. | **{check-circle}** Yes | **{check-circle}** Yes | `environment_management` | GitLab [15.8](https://gitlab.com/gitlab-org/gitlab/-/issues/216164) |
+| [`environment_unprotected`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108247) | This event is triggered when a protected environment is deleted. | **{check-circle}** Yes | **{check-circle}** Yes | `environment_management` | GitLab [15.8](https://gitlab.com/gitlab-org/gitlab/-/issues/216164) |
| [`epic_closed_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an epic is closed by a group access token | **{check-circle}** Yes | **{check-circle}** Yes | `portfolio_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`epic_created_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an epic is created by a group access token | **{check-circle}** Yes | **{check-circle}** Yes | `portfolio_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`epic_reopened_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an epic is reopened by a group access token | **{check-circle}** Yes | **{check-circle}** Yes | `portfolio_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
@@ -141,13 +148,19 @@ Every audit event is associated with an event type. The association with the eve
| [`group_shared_runners_minutes_limit_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106079) | Event triggered when a groups shared runners minutes limit is updated. | **{check-circle}** Yes | **{check-circle}** Yes | `groups_and_projects` | GitLab [15.7](https://gitlab.com/gitlab-org/gitlab/-/issues/369324) |
| [`group_two_factor_grace_period_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106079) | Event triggered when a groups two factor grace period is updated. | **{check-circle}** Yes | **{check-circle}** Yes | `groups_and_projects` | GitLab [15.7](https://gitlab.com/gitlab-org/gitlab/-/issues/369326) |
| [`group_visibility_level_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106079) | Event triggered when a groups visibility level is updated. | **{check-circle}** Yes | **{check-circle}** Yes | `groups_and_projects` | GitLab [15.7](https://gitlab.com/gitlab-org/gitlab/-/issues/369322) |
+| [`inactive_project_scheduled_for_deletion`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130699) | Triggered when inactive project is scheduled for deletion | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/423263) |
| [`incident_closed_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an incident is closed using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `incident_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`incident_created_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an incident is created using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `incident_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`incident_reopened_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an incident is reopened using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `incident_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
+| [`instance_google_cloud_logging_configuration_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130663) | Triggered when Instance level Google Cloud Logging configuration is created | **{check-circle}** Yes | **{check-circle}** Yes | `audit_events` | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/423038) |
+| [`instance_google_cloud_logging_configuration_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131752) | Triggered when instance level Google Cloud Logging configuration is deleted. | **{check-circle}** Yes | **{check-circle}** Yes | `audit_events` | GitLab [16.5](https://gitlab.com/gitlab-org/gitlab/-/issues/423040) |
| [`ip_restrictions_changed`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86037) | Event triggered on any changes in the IP AllowList | **{check-circle}** Yes | **{check-circle}** Yes | `system_access` | GitLab [15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/358986) |
| [`issue_closed_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an issue is closed using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `team_planning` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`issue_created_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an issue is created using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `team_planning` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
| [`issue_reopened_by_project_bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121485) | Triggered when an issue is reopened using a project access token | **{check-circle}** Yes | **{check-circle}** Yes | `team_planning` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/323299) |
+| [`login_failed_with_otp_authentication`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129595) | Triggered when the login fails due to an incorrect OTP | **{check-circle}** Yes | **{check-circle}** Yes | `system_access` | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/377758) |
+| [`login_failed_with_standard_authentication`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129595) | Triggered when login to GitLab fails with standard authentication like password. | **{check-circle}** Yes | **{check-circle}** Yes | `system_access` | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/377758) |
+| [`login_failed_with_webauthn_authentication`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129595) | Triggered when login fails via WebAuthn device | **{check-circle}** Yes | **{check-circle}** Yes | `system_access` | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/377758) |
| [`member_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109711) | Event triggered when a membership is created | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/issues/374112) |
| [`member_destroyed`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109711) | Event triggered when a membership is destroyed | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/issues/374112) |
| [`member_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109711) | Event triggered when a membership is updated | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/issues/374112) |
@@ -162,6 +175,7 @@ Every audit event is associated with an event type. The association with the eve
| [`merged_merge_request_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118793) | Audit event triggered when a merged merge request is deleted | **{dotted-circle}** No | **{check-circle}** Yes | `source_code_management` | GitLab [16.0](https://gitlab.com/gitlab-org/gitlab/-/issues/408288) |
| [`merged_merge_request_deletion_started`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118793) | Audit event triggered when a merged merge request's deletion is started | **{dotted-circle}** No | **{check-circle}** Yes | `source_code_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/408288) |
| [`omniauth_login_failed`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123080) | Event triggered when an OmniAuth login fails | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/374107) |
+| [`password_reset_failed`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129079) | Event triggered when a password reset fails for a user | **{dotted-circle}** No | **{check-circle}** Yes | `user_management` | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/377762) |
| [`password_reset_requested`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114548) | Event triggered when a user requests a password reset using a registered email address | **{check-circle}** Yes | **{dotted-circle}** No | `compliance_management` | GitLab [15.11](https://gitlab.com/gitlab-org/gitlab/-/issues/374107) |
| [`personal_access_token_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108952) | Event triggered when a user creates a personal access token | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/issues/374113) |
| [`personal_access_token_revoked`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108952) | Event triggered when a personal access token is revoked | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/issues/374113) |
@@ -283,6 +297,7 @@ Every audit event is associated with an event type. The association with the eve
| [`user_enable_admin_mode`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104754) | Event triggered on enabling admin mode | **{check-circle}** Yes | **{check-circle}** Yes | `system_access` | GitLab [15.7](https://gitlab.com/gitlab-org/gitlab/-/issues/362101) |
| [`user_impersonation`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79340) | Triggered when an instance administrator starts or stops impersonating a user | **{check-circle}** Yes | **{check-circle}** Yes | `user_management` | GitLab [14.8](https://gitlab.com/gitlab-org/gitlab/-/issues/300961) |
| [`user_password_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106086) | audit when user password is updated | **{check-circle}** Yes | **{check-circle}** Yes | `user_management` | GitLab [15.7](https://gitlab.com/gitlab-org/gitlab/-/issues/369330) |
+| [`user_profile_visiblity_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129149) | Triggered when user toggles private profile user setting | **{dotted-circle}** No | **{check-circle}** Yes | `user_profile` | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129149) |
| [`user_rejected`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113784) | Event triggered when a user registration is rejected | **{check-circle}** Yes | **{dotted-circle}** No | `user_management` | GitLab [15.11](https://gitlab.com/gitlab-org/gitlab/-/issues/374107) |
| [`user_username_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106086) | Event triggered on updating a user's username | **{check-circle}** Yes | **{check-circle}** Yes | `user_profile` | GitLab [15.7](https://gitlab.com/gitlab-org/gitlab/-/issues/369329) |
| [`feature_flag_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113453) | Triggered when a feature flag is created. | **{check-circle}** Yes | **{check-circle}** Yes | `feature_flags` | GitLab [15.10](https://gitlab.com/gitlab-org/gitlab/-/issues/374109) |
diff --git a/doc/administration/audit_event_streaming/examples.md b/doc/administration/audit_event_streaming/examples.md
index 1c9a14dbab0..b0d6190211c 100644
--- a/doc/administration/audit_event_streaming/examples.md
+++ b/doc/administration/audit_event_streaming/examples.md
@@ -13,7 +13,7 @@ The following sections provide examples of audit event streaming.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332747) in GitLab 14.9 [with a flag](../feature_flags.md) named `audit_event_streaming_git_operations`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/357211) in GitLab 15.0.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/357211) in GitLab 15.1 by default.
-> - [Added `details.author_class` field](https://gitlab.com/gitlab-org/gitlab/-/issues/363876) in GitLab 15.3.
+> - `details.author_class` field [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363876) in GitLab 15.3.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101583) in GitLab 15.6. Feature flag `audit_event_streaming_git_operations` removed.
Streaming audit events can be sent when authenticated users push, pull, or clone a project's remote Git repositories:
diff --git a/doc/administration/audit_event_streaming/graphql_api.md b/doc/administration/audit_event_streaming/graphql_api.md
index e6584369e5a..768b1f03bf3 100644
--- a/doc/administration/audit_event_streaming/graphql_api.md
+++ b/doc/administration/audit_event_streaming/graphql_api.md
@@ -6,9 +6,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Audit event streaming GraphQL API **(ULTIMATE ALL)**
-> - API [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332747) in GitLab 14.5 [with a flag](../feature_flags.md) named `ff_external_audit_events_namespace`. Disabled by default.
-> - API [Enabled on GitLab.com and by default on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/338939) in GitLab 14.7.
-> - API [Feature flag `ff_external_audit_events_namespace`](https://gitlab.com/gitlab-org/gitlab/-/issues/349588) removed in GitLab 14.8.
+> - API [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332747) in GitLab 14.5 [with a flag](../feature_flags.md) named `ff_external_audit_events_namespace`. Disabled by default.
+> - API [enabled on GitLab.com and by default on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/338939) in GitLab 14.7.
+> - API [feature flag `ff_external_audit_events_namespace`](https://gitlab.com/gitlab-org/gitlab/-/issues/349588) removed in GitLab 14.8.
> - Custom HTTP headers API [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/361216) in GitLab 15.1 [with a flag](../feature_flags.md) named `streaming_audit_event_headers`. Disabled by default.
> - Custom HTTP headers API [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/362941) in GitLab 15.2.
> - Custom HTTP headers API [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/366524) in GitLab 15.3. [Feature flag `streaming_audit_event_headers`](https://gitlab.com/gitlab-org/gitlab/-/issues/362941) removed.
@@ -16,6 +16,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - APIs for custom HTTP headers for instance level streaming destinations [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404560) in GitLab 16.1 [with a flag](../feature_flags.md) named `ff_external_audit_events`. Disabled by default.
> - [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) enabled by default in GitLab 16.2.
> - User-specified destination name API support [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/413894) in GitLab 16.2.
+> - API [feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/417708) removed in GitLab 16.4.
Audit event streaming destinations can be maintained using a GraphQL API.
@@ -331,7 +332,6 @@ mutation {
id
googleProjectIdName
logIdName
- privateKey
clientEmail
}
errors
@@ -364,7 +364,6 @@ query {
id
logIdName
googleProjectIdName
- privateKey
clientEmail
}
}
@@ -397,7 +396,6 @@ mutation {
googleCloudLoggingConfiguration {
id
logIdName
- privateKey
googleProjectIdName
clientEmail
}
@@ -441,10 +439,7 @@ Streaming configuration is deleted if:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335175) in GitLab 16.0 [with a flag](../feature_flags.md) named `ff_external_audit_events`. Disabled by default.
> - [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) enabled by default in GitLab 16.2.
-
-FLAG:
-On self-managed GitLab, by default this feature is enabled. To disable it, an administrator can [disable the feature flag](../feature_flags.md) named
-`ff_external_audit_events`. On GitLab.com, this feature is available but can be configured by GitLab.com administrators only. The feature is ready for production use.
+> - Instance streaming destinations [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) in GitLab 16.4. [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/417708) removed.
Manage HTTP streaming destinations for an entire instance.
diff --git a/doc/administration/audit_event_streaming/index.md b/doc/administration/audit_event_streaming/index.md
index ae566891ac7..8a1aa9a661c 100644
--- a/doc/administration/audit_event_streaming/index.md
+++ b/doc/administration/audit_event_streaming/index.md
@@ -46,7 +46,7 @@ Prerequisites:
To add streaming destinations to a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select **Streams** tab.
1. Select **Add streaming destination** and select **HTTP endpoint** to show the section for adding destinations.
@@ -66,7 +66,7 @@ Prerequisites:
To list the streaming destinations for a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select **Streams** tab.
1. Select the stream to expand it and see all the custom HTTP headers.
@@ -79,7 +79,7 @@ Prerequisites:
To update a streaming destination's name:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select **Streams** tab.
1. Select the stream to expand.
@@ -88,7 +88,7 @@ To update a streaming destination's name:
To update a streaming destination's custom HTTP headers:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select **Streams** tab.
1. Select the stream to expand.
@@ -111,7 +111,7 @@ Prerequisites:
To delete a streaming destination:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select the **Streams** tab.
1. Select the stream to expand.
@@ -120,7 +120,7 @@ To delete a streaming destination:
To delete only the custom HTTP headers for a streaming destination:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select the **Streams** tab.
1. Select the stream to expand.
@@ -145,7 +145,7 @@ Prerequisites:
To list streaming destinations and see the verification tokens:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select the **Streams**.
1. Select the stream to expand.
@@ -162,7 +162,7 @@ A streaming destination that has an event type filter set has a **filtered** (**
To update a streaming destination's event filters:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select the **Streams** tab.
1. Select the stream to expand.
@@ -203,11 +203,11 @@ Prerequisites:
To add Google Cloud Logging streaming destinations to a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select **Streams** tab.
1. Select **Add streaming destination** and select **Google Cloud Logging** to show the section for adding destinations.
-1. Enter the Google Project ID, Google Client Email, Log ID, and Google Private Key to add.
+1. Enter the Google project ID, Google client email, log ID, and Google private key to add.
1. Select **Add** to add the new streaming destination.
#### List Google Cloud Logging destinations
@@ -218,24 +218,27 @@ Prerequisites:
To list Google Cloud Logging streaming destinations for a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select **Streams** tab.
1. Select the Google Cloud Logging stream to expand and see all the fields.
#### Update a Google Cloud Logging destination
+> Button to add private key [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419675) in GitLab 16.3.
+
Prerequisites:
- Owner role for a top-level group.
To update Google Cloud Logging streaming destinations to a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select **Streams** tab.
1. Select the Google Cloud Logging stream to expand.
-1. Enter the Google Project ID, Google Client Email, Log ID, and Google Private Key to update.
+1. Enter the Google project ID, Google client email, and log ID to update.
+1. Select **Add a new private key** and enter a Google private key to update the private key.
1. Select **Save** to update the streaming destination.
#### Delete a Google Cloud Logging streaming destination
@@ -246,7 +249,7 @@ Prerequisites:
To delete Google Cloud Logging streaming destinations to a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Audit events**.
1. On the main area, select the **Streams** tab.
1. Select the Google Cloud Logging stream to expand.
@@ -257,10 +260,7 @@ To delete Google Cloud Logging streaming destinations to a top-level group:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398107) in GitLab 16.1 [with a flag](../feature_flags.md) named `ff_external_audit_events`. Disabled by default.
> - [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) enabled by default in GitLab 16.2.
-
-FLAG:
-On self-managed GitLab, by default this feature is enabled. To disable it, an administrator can [disable the feature flag](../feature_flags.md) named
-`ff_external_audit_events`. On GitLab.com, this feature is available but can be configured by GitLab.com administrators only. The feature is ready for production use.
+> - Instance streaming destinations [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) in GitLab 16.4. [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/417708) removed.
Manage HTTP streaming destinations for an entire instance.
@@ -274,7 +274,7 @@ Prerequisites:
To add a streaming destination for an instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. On the main area, select **Streams** tab.
@@ -295,7 +295,7 @@ Prerequisites:
To list the streaming destinations for an instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. On the main area, select **Streams** tab.
@@ -309,7 +309,7 @@ Prerequisites:
To update a instance streaming destination's name:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. On the main area, select **Streams** tab.
@@ -319,7 +319,7 @@ To update a instance streaming destination's name:
To update a instance streaming destination's custom HTTP headers:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. On the main area, select **Streams** tab.
@@ -343,7 +343,7 @@ Prerequisites:
To delete the streaming destinations for an instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. On the main area, select the **Streams** tab.
@@ -353,7 +353,7 @@ To delete the streaming destinations for an instance:
To delete only the custom HTTP headers for a streaming destination:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. On the main area, select the **Streams** tab.
@@ -367,10 +367,7 @@ To delete only the custom HTTP headers for a streaming destination:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398107) in GitLab 16.1 [with a flag](../feature_flags.md) named `ff_external_audit_events`. Disabled by default.
> - [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) enabled by default in GitLab 16.2.
-
-FLAG:
-On self-managed GitLab, by default this feature is enabled. To disable it, an administrator can [disable the feature flag](../feature_flags.md) named
-`ff_external_audit_events`. On GitLab.com, this feature is available but can be configured by GitLab.com administrators only. The feature is ready for production use.
+> - Instance streaming destinations [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/393772) in GitLab 16.4. [Feature flag `ff_external_audit_events`](https://gitlab.com/gitlab-org/gitlab/-/issues/417708) removed.
Each streaming destination has a unique verification token (`verificationToken`) that can be used to verify the authenticity of the event. This
token is either specified by the Owner or generated automatically when the event destination is created and cannot be changed.
@@ -384,7 +381,7 @@ Prerequisites:
To list streaming destinations for an instance and see the verification tokens:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. On the main area, select the **Streams** tab.
@@ -401,7 +398,7 @@ A streaming destination that has an event type filter set has a **filtered** (**
To update a streaming destination's event filters:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. On the main area, select the **Streams** tab.
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index 9657994ba8f..736f381e9d7 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -69,7 +69,7 @@ You can view audit events from user actions across an entire GitLab instance.
To view instance audit events:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
@@ -82,7 +82,7 @@ To view instance audit events:
You can export the current view (including filters) of your instance audit events as a CSV file. To export the instance
audit events to CSV:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Audit Events**.
1. Select the available search [filters](#filter-audit-events).
@@ -156,284 +156,7 @@ with additional details:
## Available audit events
-You can view different events depending on the version of GitLab you have.
-
-### Group events
-
-The following actions on groups generate group audit events:
-
-#### Group management
-
-- Group name or path changed.
-- Group repository size limit changed.
-- Group created or deleted.
-- Group changed visibility.
-- User was added to group and with which [permissions](../user/permissions.md).
-- Removed user from group.
-- Project repository imported into group.
-- [Project shared with group](../user/project/members/share_project_with_groups.md) and with which
- [permissions](../user/permissions.md).
-- Removal of a previously shared group with a project.
-- LFS enabled or disabled.
-- Membership lock enabled or disabled.
-- Request access enabled or disabled.
-- Roles allowed to create project changed.
-- Group deploy token was successfully created, revoked, or deleted.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353452) in GitLab 14.9.
-- Failed attempt to create a group deploy token. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353452)
- in GitLab 14.9.
-- [IP restrictions](../user/group/access_and_permissions.md#restrict-group-access-by-ip-address) changed.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358986) in GitLab 15.0.
-- Group had a security policy project linked, changed, or unlinked.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/377877) in GitLab 15.6.
-- An environment is protected or unprotected.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216164) in GitLab 15.8.
-
-#### Authentication and authorization
-
-- User sign-in using [Group SAML](../user/group/saml_sso/index.md).
-- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8071) in GitLab 14.5, changes to the following
- [group SAML](../user/group/saml_sso/index.md) configuration:
- - Enabled status.
- - Enforcing SSO-only authentication for web activity.
- - Enforcing SSO-only authentication for Git and Dependency Proxy activity.
- - Enforcing users to have dedicated group-managed accounts.
- - Prohibiting outer forks.
- - Identity provider SSO URL.
- - Certificate fingerprint.
- - Default membership role.
- - SSO-SAML group sync configuration.
-- Permissions changes of a user assigned to a group.
-- 2FA enforcement or grace period changed.
-
-#### Compliance and security
-
-- Compliance framework created, updated, or deleted.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340649) in GitLab 14.5.
-- Event streaming destination created, updated, or deleted.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344664) in GitLab 14.6.
-- Changes to push rules. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227629) in GitLab 15.0.
-- Changes to streaming audit destination custom HTTP headers.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366350) in GitLab 15.3.
-- Instance administrator started or stopped impersonation of a group member.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/300961) in GitLab 14.8.
-
-#### CI/CD
-
-- Shared runners minutes limit changed.
-- Group CI/CD variable added, removed, or protected status changed.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30857) in GitLab 13.3.
-
-#### Code collaboration
-
-- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356152) in GitLab 15.1, changes to the following merge
- request approvals settings:
- - Prevent approval by author.
- - Prevent approvals by users who add commits.
- - Prevent editing approval rules in projects and merge requests.
- - Require user password to approve.
- - Remove all approvals when commits are added to the source branch.
-- Changes to Code Suggestions.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/405295) in GitLab 15.11.
-
-### Project events
-
-The following actions on projects generate project audit events:
-
-#### Project management
-
-- Added or removed deploy keys.
-- Project created, deleted, renamed, moved (transferred), changed path.
-- Project changed visibility level.
-- Project export was downloaded.
-- Project repository was downloaded.
-- Project was archived.
-- Project was unarchived.
-- Project had a security policy project linked, changed, or unlinked.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/377877) in GitLab 15.6.
-- Project was scheduled for deletion due to inactivity.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85689) in GitLab 15.0.
-- Project deploy token was successfully created, revoked, or deleted. Introduced in GitLab 14.9.
- GitLab team members can view more information in this confidential issue: `https://gitlab.com/gitlab-org/gitlab/-/issues/353451`.
-- Failed attempt to create a project deploy token. Introduced in GitLab 14.9.
- GitLab team members can view more information in this confidential issue: `https://gitlab.com/gitlab-org/gitlab/-/issues/353451`.
-- When [strategies for feature flags](../operations/feature_flags.md#feature-flag-strategies) are changed.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68408) in GitLab 14.3.
-
-#### User management
-
-- User was added to project and with which [permissions](../user/permissions.md).
-- Permission changes of a user assigned to a project.
-- User was removed from project.
-- Users and groups allowed to merge and push to protected branch added or removed.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/338873) in GitLab 14.3.
-
-#### Access control
-
-- Branch protection was added, removed, or updated.
-- Failed attempt to create or revoke a project access token.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230007) in GitLab 13.9.
-- Allowing force push to protected branch changed.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/338873) in GitLab 14.3.
-- An environment is protected or unprotected.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216164) in GitLab 15.8.
-- User password required for approvals was updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336211) in GitLab 14.2.
-- Project access token was successfully created or revoked.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230007) in GitLab 13.9.
-
-#### Code collaboration
-
-- Default description template for merge requests is updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355805) in GitLab 15.0.
-- Merge commit message template is updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355805) in GitLab 15.0.
-- Squash commit message template is updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355805) in GitLab 15.0.
-- Delete source branch option by default enabled or disabled.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- Squash commits when merging is updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- All discussions must be resolved enabled or disabled.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- Commit message suggestion is updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- Automatically resolve merge request diff discussions enabled or disabled.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- Show link to create or view a merge request when pushing from the command line enabled or disabled.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- When merge method is updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- Merge trains enabled or disabled.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- Code owner approval requirement on merge requests targeting protected branch changed.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/338873) in GitLab 14.3.
-- Permission to modify merge requests approval rules in merge requests was updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336211) in GitLab 14.2.
-- New approvals requirement when new commits are added to an MR was updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336211) in GitLab 14.2.
-- Added or removed users and groups from project approval groups.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213603) in GitLab 13.2.
-- Permission to approve merge requests by committers was updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7531) in GitLab 12.9.
- - Message for event [changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72623/diffs) in GitLab 14.6.
-- Permission to approve merge requests by authors was updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7531) in GitLab 12.9.
-- Number of required approvals was updated.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7531) in GitLab 12.9.
-
-#### Release management
-
-- Release was added to a project.
-- Release was updated.
-- Release was deleted. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94793/) in GitLab 15.3.
-- Release milestone associations changed.
-
-#### CI/CD
-
-- Project CI/CD variable added, removed, or protected status changed.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30857) in GitLab 13.4.
-- When default branch changes for a project.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/52339) in GitLab 13.9.
-- Pipelines must succeed enabled or disabled.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- Skipped pipelines are considered successful enabled or disabled.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-- Status check is added, edited, or deleted.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355805) in GitLab 15.0.
-- Merged results pipelines enabled or disabled.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/301124) in GitLab 14.9.
-
-#### Compliance and security
-
-- Created, updated, or deleted DAST profiles, DAST scanner profiles, and DAST site profiles.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1.
-- Changed a project's compliance framework.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/329362) in GitLab 14.1.
-
-### GitLab agent for Kubernetes events
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/382133) in GitLab 15.10.
-
-GitLab generates audit events when a cluster agent token is created or revoked.
-
-### Instance events **(PREMIUM SELF)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16826) in GitLab 13.5, audit events for failed second-factor authentication attempt.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276250) in GitLab 13.6, audit events for when a user is approved using the Admin Area.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276921) in GitLab 13.6, audit events for when a user's personal access token is successfully or unsuccessfully created or revoked.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/298783) in GitLab 13.9, audit events for when a user requests access to an instance or is rejected using the Admin Area.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238177) in
- GitLab 15.1, audit events when a user's two-factor authentication is disabled.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124169) in GitLab 16.2, audit events when a user's access is locked.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124973) in GitLab 16.2, audit events when a user's access is unlocked.
-
-The following user actions on a GitLab instance generate instance audit events:
-
-#### Authentication
-
-- Sign-in events and the authentication type such as standard, LDAP, or OmniAuth.
-- Failed sign-ins.
-- Ask for password reset.
-- Grant OAuth access.
-- Failed second-factor authentication attempt.
-- A user's personal access token was successfully or unsuccessfully created or revoked.
-- A user's two-factor authentication was disabled.
-- A user's access is locked.
-- A user's access is unlocked.
-
-#### User management
-
-- Added SSH key.
-- Added or removed email.
-- Changed password.
-- Started or stopped user impersonation.
-- Changed username.
-- User was added or deleted.
-- User requests access to an instance.
-- User was approved, rejected, or blocked using the Admin Area.
-- User was blocked using the API.
-- Administrator added or removed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/323905) in GitLab 14.1.
-- Removed SSH key. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220127) in GitLab 14.1.
-- Added or removed GPG key. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220127) in GitLab 14.1.
-- Enabled Admin Mode. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/362101) in GitLab 15.7.
-- All [group events](#group-events) and [project events](#project-events).
-- User was unblocked using the Admin Area or API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115727) in GitLab 15.11.
-- User was banned using the Admin Area or API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116103) in GitLab 15.11.
-- User was unbanned using the Admin Area or API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116221) in GitLab 15.11.
-- User was deactivated using the Admin Area or API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117776) in GitLab 16.0.
-- User was activated using the Admin Area or API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121708) in GitLab 16.1.
-
-Instance events can also be accessed using the [Instance Audit Events API](../api/audit_events.md#instance-audit-events).
-
-#### Application settings **(PREMIUM ALL)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/282428) in GitLab 16.2.
-
-When a user changes an application setting in an instance, project, or group,
-that change and the user that made the change are recorded in the audit log.
-
-### GitLab Runner events
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335509) in GitLab 14.8, audit events for when a runner is registered.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/349540) in GitLab 14.9, audit events for when a runner is unregistered.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/349542) in GitLab 14.9, audit events for when a runner is assigned to or unassigned from a project.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355637) in GitLab 15.0, audit events for when a runner registration token is reset.
-
-GitLab generates audit events for the following GitLab Runner actions:
-
-- Instance, group, or project runner is registered.
-- Instance, group, or project runner is unregistered.
-- Runner is assigned to or unassigned from a project.
-- Instance, group, or project runner registration token is reset.
- [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102579) in GitLab 15.6.
-
-## "Deleted User" events
-
-Audit events created after users are deleted are created for "Deleted User". For example, if a deleted user's access to
-a project is removed automatically due to expiration.
-
-Issue [343933](https://gitlab.com/gitlab-org/gitlab/-/issues/343933) proposes to change this behavior.
+For a list of available audit events, see [Audit event types](../administration/audit_event_streaming/audit_event_types.md).
## Unsupported events
diff --git a/doc/administration/auditor_users.md b/doc/administration/auditor_users.md
index e8ed0eb4313..2befb01f096 100644
--- a/doc/administration/auditor_users.md
+++ b/doc/administration/auditor_users.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -31,7 +31,7 @@ To create a new user account with auditor access (or change an existing user):
To create a user account with auditor access:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. Create a new user or edit an existing one. Set **Access Level** to **Auditor**.
diff --git a/doc/administration/auth/atlassian.md b/doc/administration/auth/atlassian.md
index cbfb4921e14..639e285ead2 100644
--- a/doc/administration/auth/atlassian.md
+++ b/doc/administration/auth/atlassian.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/administration/auth/cognito.md b/doc/administration/auth/cognito.md
index 554b3d776ac..7d1b98d16d1 100644
--- a/doc/administration/auth/cognito.md
+++ b/doc/administration/auth/cognito.md
@@ -1,6 +1,6 @@
---
type: concepts, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/administration/auth/crowd.md b/doc/administration/auth/crowd.md
index 6ced9f844cd..590d38bf67a 100644
--- a/doc/administration/auth/crowd.md
+++ b/doc/administration/auth/crowd.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/administration/auth/index.md b/doc/administration/auth/index.md
index 4e96cdf0411..4526a74c1f8 100644
--- a/doc/administration/auth/index.md
+++ b/doc/administration/auth/index.md
@@ -1,6 +1,6 @@
---
type: index
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/administration/auth/jwt.md b/doc/administration/auth/jwt.md
index 9f95682fc47..0d33fca1fa2 100644
--- a/doc/administration/auth/jwt.md
+++ b/doc/administration/auth/jwt.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/administration/auth/ldap/google_secure_ldap.md b/doc/administration/auth/ldap/google_secure_ldap.md
index 388288bbe49..1d0b082a80f 100644
--- a/doc/administration/auth/ldap/google_secure_ldap.md
+++ b/doc/administration/auth/ldap/google_secure_ldap.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index 746d1f6b7fd..d2c27fe35b4 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -27,7 +27,7 @@ Users added through LDAP:
even if password authentication for Git
[is disabled](../../settings/sign_in_restrictions.md#password-authentication-enabled).
-The LDAP DN is associated with existing GitLab users when:
+The LDAP distinguished name (DN) is associated with existing GitLab users when:
- The existing user signs in to GitLab with LDAP for the first time.
- The LDAP email address is the primary email address of an existing GitLab user. If the LDAP email
@@ -40,9 +40,7 @@ If an existing GitLab user wants to enable LDAP sign-in for themselves, they sho
## Security
-GitLab has multiple mechanisms to verify a user is still active in LDAP. If the user is no longer active in
-LDAP, they are placed in an `ldap_blocked` status and are signed out. They are unable to sign in using any authentication provider until they are
-reactivated in LDAP.
+GitLab verifies if a user is still active in LDAP.
Users are considered inactive in LDAP when they:
@@ -51,7 +49,7 @@ Users are considered inactive in LDAP when they:
- Are marked as disabled or deactivated in Active Directory through the user account control attribute. This means attribute
`userAccountControl:1.2.840.113556.1.4.803` has bit 2 set.
-Status is checked for all LDAP users:
+GitLab checks LDAP users' status:
- When signing in using any authentication provider. [In GitLab 14.4 and earlier](https://gitlab.com/gitlab-org/gitlab/-/issues/343298), status was
checked only when signing in using LDAP directly.
@@ -59,6 +57,12 @@ Status is checked for all LDAP users:
- When performing Git over HTTP requests using LDAP username and password.
- Once per day during [User Sync](ldap_synchronization.md#user-sync).
+If the user is no longer active in LDAP, they are:
+
+- Signed out.
+- Placed in an `ldap_blocked` status.
+- Unable to sign in using any authentication provider until they are reactivated in LDAP.
+
### Security risks
You should only use LDAP integration if your LDAP users cannot:
@@ -70,10 +74,39 @@ You should only use LDAP integration if your LDAP users cannot:
## Configure LDAP
-LDAP users must have a set email address, regardless of whether or not it's used
+LDAP users must have an email address, regardless of whether or not it's used
to sign in.
-Here's an example of setting up LDAP with only the required options.
+After configuring LDAP, to test the configuration, use the
+[LDAP check Rake task](../../raketasks/ldap.md#check).
+
+### Basic configuration settings
+
+> The `hosts` configuration setting was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/139) in GitLab 14.7.
+
+The following configuration settings are available:
+
+| Setting | Required | Type | Description |
+|--------------------|-------------|------|-------------|
+| `label` | **{check-circle}** Yes | String | A human-friendly name for your LDAP server. It is displayed on your sign-in page. Example: `'Paris'` or `'Acme, Ltd.'` |
+| `host` | **{check-circle}** Yes | String | IP address or domain name of your LDAP server. Ignored when `hosts` is defined. Example: `'ldap.mydomain.com'` |
+| `port` | **{check-circle}** Yes | Integer | The port to connect with on your LDAP server. Ignored when `hosts` is defined. Example: `389` or `636` (for SSL) |
+| `uid` | **{check-circle}** Yes | String | The LDAP attribute that maps to the username that users use to sign in. Should be the attribute, not the value that maps to the `uid`. Does not affect the GitLab username (see [attributes section](#attribute-configuration-settings)). Example: `'sAMAccountName'` or `'uid'` or `'userPrincipalName'` |
+| `base` | **{check-circle}** Yes | String | Base where we can search for users. Example: `'ou=people,dc=gitlab,dc=example'` or `'DC=mydomain,DC=com'` |
+| `encryption` | **{check-circle}** Yes | String | Encryption method (the `method` key is deprecated in favor of `encryption`). It can have one of three values: `'start_tls'`, `'simple_tls'`, or `'plain'`. `simple_tls` corresponds to 'Simple TLS' in the LDAP library. `start_tls` corresponds to StartTLS, not to be confused with regular TLS. If you specify `simple_tls`, usually it's on port 636, while `start_tls` (StartTLS) would be on port 389. `plain` also operates on port 389. |
+| `hosts` | **{dotted-circle}** No | Array of strings and integers | An array of host and port pairs to open connections. Each configured server should have an identical data set. This is not meant to configure multiple distinct LDAP servers, but to configure failover. Hosts are tried in the order they are configured. Example: `[['ldap1.mydomain.com', 636], ['ldap2.mydomain.com', 636]]` |
+| `bind_dn` | **{dotted-circle}** No | String | The full DN of the user you bind with. Example: `'america\momo'` or `'CN=Gitlab,OU=Users,DC=domain,DC=com'` |
+| `password` | **{dotted-circle}** No | String | The password of the bind user. |
+| `verify_certificates` | **{dotted-circle}** No | Boolean | Defaults to `true`. Enables SSL certificate verification if encryption method is `start_tls` or `simple_tls`. If set to `false`, no validation of the LDAP server's SSL certificate is performed. |
+| `timeout` | **{dotted-circle}** No | Integer | Defaults to `10`. Set a timeout, in seconds, for LDAP queries. This helps avoid blocking a request if the LDAP server becomes unresponsive. A value of `0` means there is no timeout. |
+| `active_directory` | **{dotted-circle}** No | Boolean | This setting specifies if LDAP server is Active Directory LDAP server. For non-AD servers it skips the AD specific queries. If your LDAP server is not AD, set this to false. |
+| `allow_username_or_email_login` | **{dotted-circle}** No | Boolean | Defaults to `false`. If enabled, GitLab ignores everything after the first `@` in the LDAP username submitted by the user on sign-in. If you are using `uid: 'userPrincipalName'` on ActiveDirectory you must disable this setting, because the userPrincipalName contains an `@`. |
+| `block_auto_created_users` | **{dotted-circle}** No | Boolean | Defaults to `false`. To maintain tight control over the number of billable users on your GitLab installation, enable this setting to keep new users blocked until they have been cleared by an administrator . |
+| `user_filter` | **{dotted-circle}** No | String | Filter LDAP users. Follows the format of [RFC 4515](https://www.rfc-editor.org/rfc/rfc4515.html). GitLab does not support `omniauth-ldap`'s custom filter syntax. Examples of the `user_filter` field syntax:<br/><br/>- `'(employeeType=developer)'`<br/>- `'(&(objectclass=user)(|(samaccountname=momo)(samaccountname=toto)))'` |
+| `lowercase_usernames` | **{dotted-circle}** No | Boolean | If enabled, GitLab converts the name to lower case. |
+| `retry_empty_result_with_codes` | **{dotted-circle}** No | Array | An array of LDAP query response code that attempt to retry the operation if the result/content is empty. For Google Secure LDAP, set this value to `[80]`. |
+
+Here's an example of setting up LDAP with the basic configuration settings.
::Tabs
@@ -89,8 +122,18 @@ Here's an example of setting up LDAP with only the required options.
'host' => 'ldap.mydomain.com',
'port' => 636,
'uid' => 'sAMAccountName',
+ 'bind_dn' => 'CN=Gitlab,OU=Users,DC=domain,DC=com',
+ 'password' => '<bind_user_password>',
'encryption' => 'simple_tls',
- 'base' => 'dc=example,dc=com'
+ 'verify_certificates' => true,
+ 'timeout' => 10,
+ 'active_directory' => false,
+ 'user_filter' => '(employeeType=developer)',
+ 'base' => 'dc=example,dc=com',
+ 'lowercase_usernames' => 'false',
+ 'retry_empty_result_with_codes' => [80],
+ 'allow_username_or_email_login' => false,
+ 'block_auto_created_users' => false
}
}
```
@@ -122,7 +165,18 @@ Here's an example of setting up LDAP with only the required options.
port: 636
uid: 'sAMAccountName'
base: 'dc=example,dc=com'
+ bind_dn: 'CN=Gitlab,OU=Users,DC=domain,DC=com'
+ password: '<bind_user_password>'
encryption: 'simple_tls'
+ verify_certificates: true
+ timeout: 10
+ active_directory: false
+ user_filter: '(employeeType=developer)'
+ base: 'dc=example,dc=com'
+ lowercase_usernames: false
+ retry_empty_result_with_codes: [80]
+ allow_username_or_email_login: false
+ block_auto_created_users: false
```
1. Save the file and apply the new values:
@@ -154,8 +208,19 @@ For more information, see
'host' => 'ldap.mydomain.com',
'port' => 636,
'uid' => 'sAMAccountName',
- 'encryption' => 'simple_tls',
'base' => 'dc=example,dc=com'
+ 'bind_dn' => 'CN=Gitlab,OU=Users,DC=domain,DC=com',
+ 'password' => '<bind_user_password>',
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true,
+ 'timeout' => 10,
+ 'active_directory' => false,
+ 'user_filter' => '(employeeType=developer)',
+ 'base' => 'dc=example,dc=com',
+ 'lowercase_usernames' => 'false',
+ 'retry_empty_result_with_codes' => [80],
+ 'allow_username_or_email_login' => false,
+ 'block_auto_created_users' => false
}
}
```
@@ -180,8 +245,19 @@ For more information, see
host: 'ldap.mydomain.com'
port: 636
uid: 'sAMAccountName'
+ base: 'dc=example,dc=com'
+ bind_dn: 'CN=Gitlab,OU=Users,DC=domain,DC=com'
+ password: '<bind_user_password>'
encryption: 'simple_tls'
+ verify_certificates: true
+ timeout: 10
+ active_directory: false
+ user_filter: '(employeeType=developer)'
base: 'dc=example,dc=com'
+ lowercase_usernames: false
+ retry_empty_result_with_codes: [80]
+ allow_username_or_email_login: false
+ block_auto_created_users: false
```
1. Save the file and restart GitLab:
@@ -199,42 +275,6 @@ For more information about the various LDAP options, see the `ldap` setting in
::EndTabs
-After configuring LDAP, to test the configuration, use the
-[LDAP check Rake task](../../raketasks/ldap.md#check).
-
-### Basic configuration settings
-
-> `hosts` configuration setting [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/139) in GitLab 14.7.
-
-You can configure either:
-
-- A single LDAP server using `host` and `port`.
-- Many LDAP servers using `hosts`. This setting takes precedence over `host` and `port`. GitLab attempts to use the
- LDAP servers in the order specified, and the first reachable LDAP server is used.
-
-These configuration settings are available:
-
-| Setting | Description | Required | Examples |
-|--------------------|-------------|----------|----------|
-| `label` | A human-friendly name for your LDAP server. It is displayed on your sign-in page. | **{check-circle}** Yes | `'Paris'` or `'Acme, Ltd.'` |
-| `host` | IP address or domain name of your LDAP server. Ignored when `hosts` is defined. | **{check-circle}** Yes | `'ldap.mydomain.com'` |
-| `port` | The port to connect with on your LDAP server. Always an integer, not a string. Ignored when `hosts` is defined. | **{check-circle}** Yes | `389` or `636` (for SSL) |
-| `hosts` (GitLab 14.7 and later) | An array of host and port pairs to open connections. | **{dotted-circle}** No | `[['ldap1.mydomain.com', 636], ['ldap2.mydomain.com', 636]]` |
-| `uid` | The LDAP attribute that maps to the username that users use to sign in. Should be the attribute, not the value that maps to the `uid`. Does not affect the GitLab username (see [attributes section](#attribute-configuration-settings)). | **{check-circle}** Yes | `'sAMAccountName'` or `'uid'` or `'userPrincipalName'` |
-| `bind_dn` | The full DN of the user you bind with. | **{dotted-circle}** No | `'america\momo'` or `'CN=Gitlab,OU=Users,DC=domain,DC=com'` |
-| `password` | The password of the bind user. | **{dotted-circle}** No | `'your_great_password'` |
-| `encryption` | Encryption method. The `method` key is deprecated in favor of `encryption`. | **{check-circle}** Yes | `'start_tls'`, `'simple_tls'`, or `'plain'`. `simple_tls` corresponds to 'Simple TLS' in the LDAP library. `start_tls` corresponds to StartTLS, not to be confused with regular TLS. If you specify `simple_tls`, usually it's on port 636, while `start_tls` (StartTLS) would be on port 389. `plain` also operates on port 389. |
-| `verify_certificates` | Enables SSL certificate verification if encryption method is `start_tls` or `simple_tls`. If set to false, no validation of the LDAP server's SSL certificate is performed. Defaults to true. | **{dotted-circle}** No | boolean |
-| `timeout` | Set a timeout, in seconds, for LDAP queries. This helps avoid blocking a request if the LDAP server becomes unresponsive. A value of `0` means there is no timeout. (default: `10`) | **{dotted-circle}** No | `10` or `30` |
-| `active_directory` | This setting specifies if LDAP server is Active Directory LDAP server. For non-AD servers it skips the AD specific queries. If your LDAP server is not AD, set this to false. | **{dotted-circle}** No | boolean |
-| `allow_username_or_email_login` | If enabled, GitLab ignores everything after the first `@` in the LDAP username submitted by the user on sign-in. If you are using `uid: 'userPrincipalName'` on ActiveDirectory you must disable this setting, because the userPrincipalName contains an `@`. | **{dotted-circle}** No | boolean |
-| `block_auto_created_users` | To maintain tight control over the number of billable users on your GitLab installation, enable this setting to keep new users blocked until they have been cleared by an administrator (default: false). | **{dotted-circle}** No | boolean |
-| `base` | Base where we can search for users. | **{check-circle}** Yes | `'ou=people,dc=gitlab,dc=example'` or `'DC=mydomain,DC=com'` |
-| `user_filter` | Filter LDAP users. Format: [RFC 4515](https://www.rfc-editor.org/rfc/rfc4515.html) Note: GitLab does not support `omniauth-ldap`'s custom filter syntax. | **{dotted-circle}** No | Some examples of the `user_filter` field syntax:<br/><br/>- `'(employeeType=developer)'`<br/>- `'(&(objectclass=user)(|(samaccountname=momo)(samaccountname=toto)))'` |
-| `lowercase_usernames` | If enabled, GitLab converts the name to lower case. | **{dotted-circle}** No | boolean |
-| `retry_empty_result_with_codes` | An array of LDAP query response code that attempt to retry the operation if the result/content is empty. For Google Secure LDAP, set this value to `[80]`. | **{dotted-circle}** No | `[80]` |
-| `attributes` | A hash of attribute mappings to LDAP for GitLab to use ([see attributes section](#attribute-configuration-settings)). | **{dotted-circle}** No | `'attributes' => { 'username' => ['uid'], 'email' => ['mail', 'email'] },` |
-
### SSL configuration settings
SSL configuration settings can be configured under `tls_options` name/value
@@ -1107,7 +1147,7 @@ read about [Helm LDAP secrets](https://docs.gitlab.com/charts/installation/secre
## Updating LDAP DN and email
-When an LDAP server creates a user in GitLab, the user's LDAP distinguished name (DN) is linked to their GitLab account
+When an LDAP server creates a user in GitLab, the user's LDAP DN is linked to their GitLab account
as an identifier.
When a user tries to sign in with LDAP, GitLab tries to find the user using the DN saved on that user's account.
diff --git a/doc/administration/auth/ldap/ldap-troubleshooting.md b/doc/administration/auth/ldap/ldap-troubleshooting.md
index 8cffff7b725..c5624235a76 100644
--- a/doc/administration/auth/ldap/ldap-troubleshooting.md
+++ b/doc/administration/auth/ldap/ldap-troubleshooting.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -167,7 +167,7 @@ may see the following message: `Access denied for your LDAP account`.
We have a workaround, based on toggling the access level of affected users:
-1. As an administrator, on the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. As an administrator, on the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. Select the name of the affected user.
@@ -225,7 +225,7 @@ field contains no data:
To resolve this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, go to **Settings > General**.
1. Expand both of the following:
@@ -369,7 +369,7 @@ things to debug the situation.
- Ensure the correct [LDAP group link is added to the GitLab group](ldap_synchronization.md#add-group-links).
- Check that the user has an LDAP identity:
1. Sign in to GitLab as an administrator user.
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. Search for the user.
diff --git a/doc/administration/auth/ldap/ldap_synchronization.md b/doc/administration/auth/ldap/ldap_synchronization.md
index 9d9ed563fe5..e95876a8b3c 100644
--- a/doc/administration/auth/ldap/ldap_synchronization.md
+++ b/doc/administration/auth/ldap/ldap_synchronization.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -501,7 +501,7 @@ When global group memberships lock is enabled:
To enable global group memberships lock:
1. [Configure LDAP](index.md#configure-ldap).
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -514,7 +514,7 @@ By default, group members with the Owner role can manage [LDAP group synchroniza
GitLab administrators can remove this permission from group Owners:
1. [Configure LDAP](index.md#configure-ldap).
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Visibility and access controls**.
diff --git a/doc/administration/auth/oidc.md b/doc/administration/auth/oidc.md
index 8ef95872ad4..f3200aea67b 100644
--- a/doc/administration/auth/oidc.md
+++ b/doc/administration/auth/oidc.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -554,7 +554,7 @@ For your app, complete the following steps on Casdoor:
ensure the Casdoor app has the following
`Redirect URI`: `https://gitlab.example.com/users/auth/openid_connect/callback`.
-See the [Casdoor documentation](https://casdoor.org/docs/integration/ruby/gitlab) for more details.
+See the [Casdoor documentation](https://casdoor.org/docs/integration/ruby/gitlab/) for more details.
Example configuration for Linux package installations (file path: `/etc/gitlab/gitlab.rb`):
diff --git a/doc/administration/auth/smartcard.md b/doc/administration/auth/smartcard.md
index 1662639dd29..855157321d7 100644
--- a/doc/administration/auth/smartcard.md
+++ b/doc/administration/auth/smartcard.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
diff --git a/doc/administration/auth/test_oidc_oauth.md b/doc/administration/auth/test_oidc_oauth.md
index be0ea5c963e..eba911dcb33 100644
--- a/doc/administration/auth/test_oidc_oauth.md
+++ b/doc/administration/auth/test_oidc_oauth.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/administration/backup_restore/backup_gitlab.md b/doc/administration/backup_restore/backup_gitlab.md
index dc0724dc561..cd65bf67638 100644
--- a/doc/administration/backup_restore/backup_gitlab.md
+++ b/doc/administration/backup_restore/backup_gitlab.md
@@ -160,9 +160,9 @@ GitLab uses Redis both as a cache store and to hold persistent data for our back
Elasticsearch is an optional database for advanced search. It can improve search
in both source-code level, and user generated content in issues, merge requests, and discussions. The [backup command](#backup-command) does _not_ back up Elasticsearch data. Elasticsearch data can be regenerated from PostgreSQL data after a restore. It is possible to [manually back up Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-restore.html).
-## Command line interface
+## Command-line interface
-GitLab provides a command line interface to back up your entire instance,
+GitLab provides a command-line interface to back up your entire instance,
including:
- Database
@@ -301,7 +301,7 @@ the timestamp is `1493107454_2018_04_25_10.6.4-ce`.
### Backup options
-The command line tool GitLab provides to back up your instance can accept more
+The command-line tool GitLab provides to back up your instance can accept more
options.
#### Backup strategy option
@@ -435,6 +435,34 @@ sudo -u git -H bundle exec rake gitlab:backup:create SKIP=tar RAILS_ENV=producti
::EndTabs
+#### Create server-side repository backups
+
+> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4941) in GitLab 16.3.
+
+Instead of storing large repository backups in the backup archive, repository
+backups can be configured so that the Gitaly node that hosts each repository is
+responsible for creating the backup and streaming it to object storage. This
+helps reduce the network resources required to create and restore a backup.
+
+1. [Configure a server-side backup destination in Gitaly](../gitaly/configure_gitaly.md#configure-server-side-backups).
+1. Create a back up using the `REPOSITORIES_SERVER_SIDE` variable. See the following examples.
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+```shell
+sudo gitlab-backup create REPOSITORIES_SERVER_SIDE=true
+```
+
+:::TabTitle Self-compiled
+
+```shell
+sudo -u git -H bundle exec rake gitlab:backup:create REPOSITORIES_SERVER_SIDE=true
+```
+
+::EndTabs
+
#### Back up Git repositories concurrently
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37158) in GitLab 13.3.
diff --git a/doc/administration/backup_restore/index.md b/doc/administration/backup_restore/index.md
index 824fa56f443..56f080a5f9f 100644
--- a/doc/administration/backup_restore/index.md
+++ b/doc/administration/backup_restore/index.md
@@ -107,7 +107,7 @@ To prepare the new server:
```
1. Disable periodic background jobs:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. Under the Sidekiq dashboard, select **Cron** tab and then
@@ -188,7 +188,7 @@ To prepare the new server:
1. [Restore the GitLab backup](#restore-gitlab).
1. Verify that the Redis database restored correctly:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. Under the Sidekiq dashboard, verify that the numbers
diff --git a/doc/administration/backup_restore/restore_gitlab.md b/doc/administration/backup_restore/restore_gitlab.md
index 784a8708de6..c7439a88661 100644
--- a/doc/administration/backup_restore/restore_gitlab.md
+++ b/doc/administration/backup_restore/restore_gitlab.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Restore GitLab **(FREE SELF)**
-GitLab provides a command line interface to restore your entire installation,
+GitLab provides a command-line interface to restore your entire installation,
and is flexible enough to fit your needs.
The [restore prerequisites section](#restore-prerequisites) includes crucial
@@ -287,7 +287,7 @@ Each backup archive contains a full self-contained backup, including those creat
## Restore options
-The command line tool GitLab provides to restore from backup can accept more
+The command-line tool GitLab provides to restore from backup can accept more
options.
### Specify backup to restore when there are more than one
@@ -450,3 +450,19 @@ For more information, see:
- [Having different owners](https://www.postgresql.org/message-id/2039.1177339749@sss.pgh.pa.us).
- Stack Overflow: [Resulting errors](https://stackoverflow.com/questions/4368789/error-must-be-owner-of-language-plpgsql).
+
+### Restoring fails due to Git server hook
+
+While restoring from backup, you can encounter an error when the following are true:
+
+- A Git Server Hook (`custom_hook`) is configured using the method for [GitLab version 15.10 and earlier](../server_hooks.md)
+- Your GitLab version is on version 15.11 and later
+- You created symlinks to a directory outside of the GitLab-managed locations
+
+The error looks like:
+
+```plaintext
+{"level":"fatal","msg":"restore: pipeline: 1 failures encountered:\n - @hashed/path/to/hashed_repository.git (path/to_project): manager: restore custom hooks, \"@hashed/path/to/hashed_repository/<BackupTimestamp>_<GitLabVersion>-ee/001.custom_hooks.tar\": rpc error: code = Internal desc = setting custom hooks: generating prepared vote: walking directory: copying file to hash: read /mnt/gitlab-app/git-data/repositories/+gitaly/tmp/default-repositories.old.<timestamp>.<temporaryfolder>/custom_hooks/compliance-triggers.d: is a directory\n","pid":3256017,"time":"2023-08-10T20:09:44.395Z"}
+```
+
+To resolve this, you can update the Git [server hooks](../server_hooks.md) for GitLab version 15.11 and later, and create a new backup.
diff --git a/doc/administration/broadcast_messages.md b/doc/administration/broadcast_messages.md
index 78a4ec798d1..4ed80010220 100644
--- a/doc/administration/broadcast_messages.md
+++ b/doc/administration/broadcast_messages.md
@@ -57,7 +57,7 @@ To display messages to users on your GitLab instance, add a broadcast message.
To add a broadcast message:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Messages**.
1. Select **Add new message**.
@@ -86,7 +86,7 @@ If you must make changes to a broadcast message, you can edit it.
To edit a broadcast message:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Messages**.
1. From the list of broadcast messages, select the edit button for the message.
@@ -101,7 +101,7 @@ You can delete a broadcast message while it's active.
To delete a broadcast message:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Messages**.
1. From the list of broadcast messages, select the delete button for the message.
diff --git a/doc/administration/cicd.md b/doc/administration/cicd.md
index 4e98423ea60..7a6316a1e50 100644
--- a/doc/administration/cicd.md
+++ b/doc/administration/cicd.md
@@ -18,7 +18,7 @@ CI/CD to be disabled by default in new projects by modifying the settings in:
- `gitlab.rb` for Linux package installations.
Existing projects that already had CI/CD enabled are unchanged. Also, this setting only changes
-the project default, so project owners [can still enable CI/CD in the project settings](../ci/enable_or_disable_ci.md#enable-cicd-in-a-project).
+the project default, so project owners [can still enable CI/CD in the project settings](../ci/enable_or_disable_ci.md).
For self-compiled installations:
diff --git a/doc/administration/clusters/kas.md b/doc/administration/clusters/kas.md
index b7247e2251f..e291a162fb9 100644
--- a/doc/administration/clusters/kas.md
+++ b/doc/administration/clusters/kas.md
@@ -9,40 +9,38 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3834) in GitLab 13.10, the GitLab agent server (KAS) became available on GitLab.com at `wss://kas.gitlab.com`.
> - [Moved](https://gitlab.com/groups/gitlab-org/-/epics/6290) from GitLab Premium to GitLab Free in 14.5.
-The agent server is a component you install together with GitLab. It is required to
+The agent server is a component installed together with GitLab. It is required to
manage the [GitLab agent for Kubernetes](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent).
The KAS acronym refers to the former name, `Kubernetes agent server`.
The agent server for Kubernetes is installed and available on GitLab.com at `wss://kas.gitlab.com`.
-If you use self-managed GitLab, you must install an agent server or specify an external installation.
+If you use self-managed GitLab, by default the agent server is installed and available.
## Installation options
-As a GitLab administrator, you can install the agent server:
+As a GitLab administrator, you can control the agent server installation:
- For [Linux package installations](#for-linux-package-installations).
- For [GitLab Helm chart installations](#for-gitlab-helm-chart).
### For Linux package installations
-You can enable the agent server for Linux package installations on a single node, or on multiple nodes at once.
+The agent server for Linux package installations can be enabled on a single node, or on multiple nodes at once.
+By default, the agent server is enabled and available at `ws://gitlab.example.com/-/kubernetes-agent/`.
-#### Enable on a single node
+#### Disable on a single node
-To enable the agent server on a single node:
+To disable the agent server on a single node:
1. Edit `/etc/gitlab/gitlab.rb`:
```ruby
- gitlab_kas['enable'] = true
+ gitlab_kas['enable'] = false
```
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
-For additional configuration options, see the **Enable GitLab KAS** section of the
-[`gitlab.rb.template`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/be52c36c243a3422ec38b7d45d459682a07e195f/files/gitlab-config-template/gitlab.rb.template#L1951).
-
##### Configure KAS to listen on a UNIX socket
If you use GitLab behind a proxy, KAS might not work correctly. You can resolve this issue on a single-node installation, you can configure KAS to listen on a UNIX socket.
@@ -70,6 +68,9 @@ To configure KAS to listen on a UNIX socket:
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
+For additional configuration options, see the **GitLab Kubernetes Agent Server** section of the
+[`gitlab.rb.template`](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-config-template/gitlab.rb.template).
+
#### Enable on multiple nodes
To enable the agent server on multiple nodes:
@@ -79,7 +80,6 @@ To enable the agent server on multiple nodes:
```ruby
gitlab_kas_external_url 'wss://kas.gitlab.example.com/'
- gitlab_kas['enable'] = true
gitlab_kas['api_secret_key'] = '<32_bytes_long_base64_encoded_value>'
gitlab_kas['private_api_secret_key'] = '<32_bytes_long_base64_encoded_value>'
gitlab_kas['private_api_listen_address'] = '0.0.0.0:8155'
@@ -88,7 +88,6 @@ To enable the agent server on multiple nodes:
'OWN_PRIVATE_API_URL' => 'grpc://<ip_or_hostname_of_this_host>:8155'
}
- gitlab_rails['gitlab_kas_enabled'] = true
gitlab_rails['gitlab_kas_external_url'] = 'wss://gitlab.example.com/-/kubernetes-agent/'
gitlab_rails['gitlab_kas_internal_url'] = 'grpc://kas.internal.gitlab.example.com'
gitlab_rails['gitlab_kas_external_k8s_proxy_url'] = 'https://gitlab.example.com/-/kubernetes-agent/k8s-proxy/'
@@ -114,31 +113,7 @@ To enable the agent server on multiple nodes:
### For GitLab Helm Chart
-For GitLab [Helm Chart](https://docs.gitlab.com/charts/) installations:
-
-1. Set `global.kas.enabled` to `true`. For example, in a shell with `helm` and `kubectl`
- installed, run:
-
- ```shell
- helm repo add gitlab https://charts.gitlab.io/
- helm repo update
- helm upgrade --install gitlab gitlab/gitlab \
- --timeout 600s \
- --set global.hosts.domain=<YOUR_DOMAIN> \
- --set global.hosts.externalIP=<YOUR_IP> \
- --set certmanager-issuer.email=<YOUR_EMAIL> \
- --set global.kas.enabled=true # <-- without this setting, the agent server will not be installed
- ```
-
-1. To configure the agent server, use a `gitlab.kas` sub-section in your `values.yaml` file:
-
- ```yaml
- gitlab:
- kas:
- # put your custom options here
- ```
-
-For details, see [how to use the GitLab-KAS chart](https://docs.gitlab.com/charts/charts/gitlab/kas/).
+See [how to use the GitLab-KAS chart](https://docs.gitlab.com/charts/charts/gitlab/kas/).
## Kubernetes API proxy cookie
diff --git a/doc/administration/credentials_inventory.md b/doc/administration/credentials_inventory.md
index 482d46498e3..39cbf4e0dc8 100644
--- a/doc/administration/credentials_inventory.md
+++ b/doc/administration/credentials_inventory.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: howto
@@ -10,42 +10,45 @@ type: howto
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20912) in GitLab 12.6.
> - [Bot-created access tokens not displayed in personal access token list](https://gitlab.com/gitlab-org/gitlab/-/issues/351759) in GitLab 14.9.
-GitLab administrators are responsible for the overall security of their instance. To assist, GitLab
-provides a Credentials inventory to keep track of all the credentials that can be used to access
-their self-managed instance.
+As a GitLab administrator, you are responsible for the overall security of your instance.
+To assist, GitLab provides an inventory of all the credentials that can be used to access
+your self-managed instance.
-Use Credentials inventory to see for your GitLab instance all:
+In the credentials inventory, you can view all:
-- Personal access tokens (PAT).
-- Project access tokens (GitLab 14.8 and later).
+- Personal access tokens (PATs).
+- Project access tokens (introduced in GitLab 14.8).
+- Group access tokens ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102959) in GitLab 15.6).
- SSH keys.
- GPG keys.
-You can also [revoke](#revoke-a-users-personal-access-token) and [delete](#delete-a-users-ssh-key) and see:
+You can also [revoke](#revoke-a-users-personal-access-token), [delete](#delete-a-users-ssh-key), and view:
- Who they belong to.
- Their access scope.
- Their usage pattern.
-- When they expire. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214809) in GitLab 13.2.
-- When they were revoked. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214809) in GitLab 13.2.
-
-To access the Credentials inventory:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Credentials**.
+- [In GitLab 13.2 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/214809), when they:
+ - Expire.
+ - Were revoked.
## Revoke a user's personal access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214811) in GitLab 13.4.
-If you see a **Revoke** button, you can revoke that user's PAT. Whether you see a **Revoke** button depends on the token state, and if an expiration date has been set. For more information, see the following table:
+You can revoke a user's personal access token.
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Credentials**.
+1. By the personal access token, select **Revoke**.
-| Token state | Show Revoke button? | Comments |
-|-------------|---------------------|----------------------------------------------------------------------------|
-| Active | Yes | Allows administrators to revoke the PAT, such as for a compromised account |
-| Expired | No | Not applicable; token is already expired |
-| Revoked | No | Not applicable; token is already revoked |
+If a **Revoke** button is not available, the token may be expired or revoked, or an expiration date set.
+
+| Token state | Revoke button displayed? | Comments |
+|-------------|--------------------------|----------------------------------------------------------------------------|
+| Active | Yes | Allows administrators to revoke the PAT, such as for a compromised account |
+| Expired | No | Not applicable; token is already expired |
+| Revoked | No | Not applicable; token is already revoked |
When a PAT is revoked from the credentials inventory, the instance notifies the user by email.
@@ -55,10 +58,13 @@ 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 both:
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Credentials**.
+1. Select the **Project Access Tokens** tab.
+1. By the project access token, select **Revoke**.
-- Revokes the token project access token.
-- Enqueues a background worker to delete the project bot user.
+The project access token is revoked and a background worker is queued to delete the project bot user.
![Credentials inventory page - Project access tokens](img/credentials_inventory_project_access_tokens_v14_9.png)
@@ -66,8 +72,13 @@ The **Revoke** button next to a project access token can be selected to revoke t
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225248) in GitLab 13.5.
-You can **Delete** a user's SSH key by navigating to the credentials inventory's SSH Keys tab.
-The instance then notifies the user.
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Credentials**.
+1. Select the **SSH Keys** tab.
+1. By the SSH key, select **Delete**.
+
+The instance notifies the user.
![Credentials inventory page - SSH keys](img/credentials_inventory_ssh_keys_v14_9.png)
@@ -76,11 +87,11 @@ The instance then notifies the user.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/282429) in GitLab 13.10.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/292961) in GitLab 13.12.
-You can view all existing GPG in your GitLab instance by navigating to the
+You can view all existing GPG in your GitLab instance by going to the
credentials inventory GPG Keys tab, as well as the following properties:
- Who the GPG key belongs to.
- The ID of the GPG key.
-- Whether the GPG key is [verified or unverified](../user/project/repository/gpg_signed_commits/index.md)
+- Whether the GPG key is [verified or unverified](../user/project/repository/signed_commits/gpg.md).
![Credentials inventory page - GPG keys](img/credentials_inventory_gpg_keys_v14_9.png)
diff --git a/doc/administration/custom_project_templates.md b/doc/administration/custom_project_templates.md
index 2bbbb5649e6..a63201b721e 100644
--- a/doc/administration/custom_project_templates.md
+++ b/doc/administration/custom_project_templates.md
@@ -16,7 +16,7 @@ Every project in the group, but not its subgroups, can be selected when a new pr
is created, based on the user's access permissions:
- Public projects can be selected by any authenticated user as a template for a new project,
- if all enabled [project features](../user/project/settings/index.md#configure-project-visibility-features-and-permissions)
+ if all enabled [project features](../user/project/settings/index.md#configure-project-features-and-permissions)
except for **GitLab Pages** and **Security and Compliance** are set to **Everyone With Access**.
The same applies to internal projects.
- Private projects can be selected only by users who are members of the projects.
@@ -33,7 +33,7 @@ To set project templates at the group level, see [Custom group-level project tem
To select the group to use as the source for the project templates:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Templates**.
1. Expand **Custom project templates**.
diff --git a/doc/administration/dedicated/index.md b/doc/administration/dedicated/index.md
index b995c837136..9008b5dbc11 100644
--- a/doc/administration/dedicated/index.md
+++ b/doc/administration/dedicated/index.md
@@ -25,7 +25,7 @@ GitLab Dedicated Engineers also don't have direct access to tenant environments,
To request the creation of a new GitLab Dedicated environment for your organization, you must provide the following information to your account team:
- Expected number of users.
-- Desired primary region: Primary AWS region in which your data is stored (do note the [list of unsupported regions](../../subscriptions/gitlab_dedicated/index.md#aws-regions-not-supported)).
+- Desired primary region: Primary AWS region in which your data is stored (take note of [unavailable AWS regions](../../subscriptions/gitlab_dedicated/index.md#unavailable-aws-regions)).
- Desired secondary region: Secondary AWS region in which your data is stored. This region is used to recover your GitLab Dedicated instance in case of a disaster.
- Desired backup region: An AWS region where the primary backups of your data are replicated. This can be the same as the primary or secondary region or different.
- Desired instance subdomain: The main domain for GitLab Dedicated instances is `gitlab-dedicated.com`. You get to choose the subdomain name where your instance is accessible from (for example, `customer_name.gitlab-dedicated.com`).
@@ -39,13 +39,14 @@ When onboarding, you must also specify your preference for the weekly four-hour
Available scheduled maintenance windows, performed outside standard working hours:
-- APAC: Wednesday 1 AM - 5 AM UTC
+- APAC: Wednesday 1 PM - 5 PM UTC
- EU: Tuesday 1 AM - 5 AM UTC
- AMER Option 1: Tuesday 7 AM - 11 AM UTC
- AMER Option 2: Sunday 9 PM - Monday 1 AM UTC
Consider the following notes:
+- The Dedicated instance is not expected to be down the entire duration of the maintenance window. Occasionally, a small period of downtime (on the order of a few tens of seconds) can occur while compute resources restart after they are upgraded. If it occurs, this small period of downtime typically happens during the first half of the maintenance window. Long-running connections may be interrupted during this period. To mitigate this, clients should implement strategies like automatic recovery and retry. Longer periods of downtime during the maintenance window are rare, and GitLab provides notice if longer downtime is anticipated.
- In case of a performance degradation or downtime during the scheduled maintenance window,
the impact to [the system SLA](https://about.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/slas/) is not counted.
- The weekly scheduled maintenance window can be postponed into another window within the same week.
@@ -79,20 +80,30 @@ The turnaround time for processing configuration change requests is [documented
### Encrypted Data At Rest (BYOK)
-If you want your GitLab data to be encrypted at rest, the KMS keys used must be accessible by GitLab services. KMS keys can be used in two modes for this purpose:
+NOTE:
+To enable BYOK, you must do it during onboarding.
+
+You can opt to encrypt your GitLab data at rest with AWS KMS keys, which must be made accessible to GitLab Dedicated infrastructure. GitLab Dedicated only supports keys with AWS-managed key material (the [AWS_KMS](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-origin) origin type).
-1. Per-service KMS keys (Backup, EBS, RDS, S3), or
-1. One KMS key for all services.
+For instructions on how to create and manage KMS keys, see the [AWS KMS documentation](https://docs.aws.amazon.com/kms/latest/developerguide/getting-started.html).
-If you use a key per service, all services must be encrypted at rest. Selective enablement of this feature is not supported.
+In GitLab Dedicated, you can use KMS keys in two ways:
-The keys provided have to reside in the same primary, secondary and backup region specified during [onboarding](#onboarding).
+- One KMS key for all services
+- Per-service KMS keys (Backup, EBS, RDS, S3)
+ - Keys do not need to be unique to each service.
+ - All services must be encrypted at rest.
+ - Selective enablement of this feature is not supported.
+ - Keys do not need to be unique to each service.
-For instructions on how to create and manage KMS keys, visit [Managing keys](https://docs.aws.amazon.com/kms/latest/developerguide/getting-started.html) in the AWS KMS documentation.
+Make sure the AWS KMS keys are replicated to your desired primary, secondary, and backup region specified during [onboarding](#onboarding).
-GitLab Dedicated supports only AWS managed KMS keys with KMS [as key material](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-origin).
+#### Create KMS keys in AWS
-To create a KMS key using the AWS Console:
+To enable BYOK, indicate on your onboarding ticket that you'd like to use this functionality.
+GitLab will provide you with your AWS account ID which is necessary to enable BYOK.
+
+After you have received the AWS account ID, create your KMS keys using the AWS Console:
1. In `Configure key`, select:
1. Key type: **Symmetrical**
@@ -185,7 +196,7 @@ The last page asks you to confirm the KMS key policy. It should look similar to
}
```
-Make sure the AWS KMS keys are replicated to your desired primary, secondary and backup region specified during [onboarding](#onboarding).
+Make sure the AWS KMS keys are replicated to your desired primary, secondary and backup region specified during [onboarding](#onboarding). After you have created the keys, send GitLab the corresponding ARNs of each key so that GitLab can use to encrypt the data stored in your Dedicated instance.
### Inbound Private Link
@@ -206,14 +217,43 @@ To enable the Inbound Private Link:
### Outbound Private Link
-Outbound Private Links allow the GitLab Dedicated instance to securely communicate with services running in your VPC on AWS. This type of connection can execute [webhooks](../../user/project/integrations/webhooks.md) where the targeted services are running in your VPC, import or mirror projects and repositories, or use any other GitLab functionality to access private services.
+Consider the following when using Outbound Private Links:
+
+- Outbound Private Links allow the GitLab Dedicated instance to securely communicate with services running in your VPC on AWS. This type of connection
+ can execute [webhooks](../../user/project/integrations/webhooks.md) where the targeted services are running in your VPC, import or mirror projects
+ and repositories, or use any other GitLab functionality to access private services.
+- You can only establish Private Links between VPCs in the same region. Therefore, you can only establish a connection in the regions you selected for
+ your Dedicated instance.
+- The Network Load Balancer (NLB) that backs the Endpoint Service at your end must be enabled in at least one of the Availability Zones to which your Dedicated tenant was
+ deployed. This is not the user-facing name such as `us-east-1a`, but the underlying [Availability Zone ID](https://docs.aws.amazon.com/ram/latest/userguide/working-with-az-ids.html).
+ If you did not specify these during onboarding to Dedicated, you must either:
+ - Ask for the Availability Zone IDs in the ticket you raise to enable the link and ensure the NLB is enabled in those AZs, or
+ - Ensure the NLB has is enabled in every Availability Zone in the region.
To enable an Outbound Private Link:
-1. In your [support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650), GitLab provides you with an IAM role ARN that connects to your endpoint service. You can then add this ARN to the allowlist on your side to restrict connections to your endpoint service.
-1. [Create the Endpoint service](https://docs.aws.amazon.com/vpc/latest/privatelink/create-endpoint-service.html) through which your internal service is available to GitLab Dedicated. Provide the associated `Service Endpoint Name` on the [support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650).
-1. When creating the Endpoint service, you must provide GitLab with a [verified Private DNS Name](https://docs.aws.amazon.com/vpc/latest/privatelink/manage-dns-names.html#verify-domain-ownership) for your service. Optionally, if you would like GitLab Dedicated to reach your service via other aliases, you have the ability to specify a list of Private Hosted Zone (PHZ) entries. With this option, GitLab sets up a Private Hosted Zone with DNS names aliased to the verified Private DNS name. To enable this functionality, you must provide GitLab a list of PHZ entries on your support ticket. After the PHZ is created in the tenant environment, DNS resolution of any of the provided records correctly resolves to the PrivateLink endpoint.
-1. GitLab then configures the tenant instance to create the necessary Endpoint Interfaces based on the service names you provided. Any outbound calls made from the tenant GitLab instance are directed through the PrivateLink into your VPC.
+1. [Create the Endpoint service](https://docs.aws.amazon.com/vpc/latest/privatelink/create-endpoint-service.html) through which your internal service
+ will be available to GitLab Dedicated. Provide the associated `Service Endpoint Name` on a new
+ [support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650).
+1. In your [support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650), GitLab will provide you with the ARN of an
+ IAM role that will be initiating the connection to your endpoint service. You must ensure this ARN is included, or otherwise covered by other
+ entries, in the list of "Allowed Principals" on the Endpoint Service, as described by the [AWS documentation](https://docs.aws.amazon.com/vpc/latest/privatelink/configure-endpoint-service.html#add-remove-permissions).
+ Though it's optional, you should you add it explicitly, allowing you to set `Acceptance required` to No so that Dedicated can connect in a single operation.
+ If you leave `Acceptance required` as Yes, then you must manually accept the connection after Dedicated has initiated it.
+1. To connect to services using the Endpoint, the Dedicated services require a DNS name. Private Link automatically creates an internal name, but
+ it is machine-generated and not generally directly useful. There are two options available:
+ - In your Endpoint Service, enable [Private DNS name](https://docs.aws.amazon.com/vpc/latest/privatelink/manage-dns-names.html), perform the
+ required validation, and let GitLab know in the support ticket that you are using this option. If `Acceptance Required` is set to Yes on your
+ Endpoint Service, also note this on the support ticket because Dedicated will need to initiate the connection without Private DNS, wait for you
+ to confirm it has been accepted, and then update the connection to enable the use of Private DNS.
+ - Dedicated can manage a Private Hosted Zone (PHZ) within the Dedicated AWS Account and alias any arbitrary DNS names to the Endpoint, directing
+ requests for those names to your Endpoint Service. This may be useful if you have multiple DNS names/aliases that will be accessed using a
+ single Endpoint (for example, if you are running a reverse proxy to connect to more than one service in your environment), or if the domain you
+ want to use is not public and cannot be validated for use by Private DNS. Let GitLab know on the support ticket if you are using this option and
+ provide a list of DNS names that should resolve to the Private Link Endpoint. This list can be updated as needed in future.
+
+GitLab then configures the tenant instance to create the necessary Endpoint Interfaces based on the service names you provided. Any matching outbound
+connections made from the tenant GitLab instance are directed through the PrivateLink into your VPC.
#### Custom certificates
@@ -258,9 +298,9 @@ To activate SAML for your GitLab Dedicated instance:
"admin_groups": [
// optional
],
- "idp_cert_fingerprint": "43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8",
+ "idp_cert_fingerprint": "43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8",
"idp_sso_target_url": "https://login.example.com/idp",
- "label": "IDP Name",
+ "label": "IDP Name",
"name_identifier_format": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
"security": {
// optional
@@ -305,7 +345,8 @@ To enable group sync:
### Access to application logs
-GitLab [application logs](../../administration/logs/index.md) are delivered to an S3 bucket in the GitLab tenant account, which can be shared with you.
+GitLab [application logs](../../administration/logs/index.md) are delivered to an S3 bucket in the GitLab tenant account, which can be shared with you. Logs stored in the S3 bucket are retained indefinitely, until the 1 year retention policy is fully enforced. GitLab team members can view more information in this confidential issue:
+`https://gitlab.com/gitlab-com/gl-infra/gitlab-dedicated/team/-/issues/483`.
To gain read only access to this bucket:
diff --git a/doc/administration/diff_limits.md b/doc/administration/diff_limits.md
index 48b52950ee3..dcf5a2b1b32 100644
--- a/doc/administration/diff_limits.md
+++ b/doc/administration/diff_limits.md
@@ -33,7 +33,7 @@ set values are presented as **Too large** are cannot be expanded in the UI.
To configure these values:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Diff limits**.
diff --git a/doc/administration/email_from_gitlab.md b/doc/administration/email_from_gitlab.md
index 9272f58d2b9..ec231d25da2 100644
--- a/doc/administration/email_from_gitlab.md
+++ b/doc/administration/email_from_gitlab.md
@@ -22,7 +22,7 @@ For information about email notifications originating from GitLab, read
## Sending emails to users from GitLab
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select **Send email to users**.
diff --git a/doc/administration/encrypted_configuration.md b/doc/administration/encrypted_configuration.md
index b8e04b6fa08..4ffb1495ec8 100644
--- a/doc/administration/encrypted_configuration.md
+++ b/doc/administration/encrypted_configuration.md
@@ -13,7 +13,7 @@ GitLab can read settings for certain features from encrypted settings files. The
- [Incoming email `user` and `password`](incoming_email.md#use-encrypted-credentials).
- [LDAP `bind_dn` and `password`](auth/ldap/index.md#use-encrypted-credentials).
-- [Service Desk email `user` and `password`](../user/project/service_desk/index.md#use-encrypted-credentials).
+- [Service Desk email `user` and `password`](../user/project/service_desk/configure.md#use-encrypted-credentials).
- [SMTP `user_name` and `password`](raketasks/smtp.md#secrets).
To enable the encrypted configuration settings, a new base key must be generated for
diff --git a/doc/administration/external_users.md b/doc/administration/external_users.md
index 9be49fab95f..56a6debb7b1 100644
--- a/doc/administration/external_users.md
+++ b/doc/administration/external_users.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -30,7 +30,7 @@ For example, if an external user is added as Guest, and your project is internal
private, they do not have access to the code; you need to grant the external
user access at the Reporter level or above if you want them to have access to the code. You should
always take into account the
-[project's visibility and permissions settings](../user/project/settings/index.md#configure-project-visibility-features-and-permissions)
+[project's visibility](../user/public_access.md#change-project-visibility) and [permissions settings](../user/project/settings/index.md#configure-project-features-and-permissions)
as well as the permission level of the user.
NOTE:
@@ -40,7 +40,7 @@ An administrator can flag a user as external by either of the following methods:
- [Through the API](../api/users.md#user-modification).
- Using the GitLab UI:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users** to create a new user or edit an existing one.
There, you can find the option to flag the user as external.
@@ -56,7 +56,7 @@ Additionally, users can be set as external users using:
By default, new users are not set as external users. This behavior can be changed
by an administrator:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Account and limit** section.
diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md
index a67edc815c8..a31261892bb 100644
--- a/doc/administration/geo/disaster_recovery/background_verification.md
+++ b/doc/administration/geo/disaster_recovery/background_verification.md
@@ -49,7 +49,7 @@ Feature.enable('geo_repository_verification')
On the **primary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
1. Expand **Verification information** tab for that site to view automatic checksumming
@@ -60,7 +60,7 @@ On the **primary** site:
On the **secondary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
1. Expand **Verification information** tab for that site to view automatic checksumming
@@ -89,7 +89,7 @@ increase load and vice versa.
On the **primary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
1. Select **Edit** for the **primary** site to customize the minimum
@@ -138,7 +138,7 @@ sudo gitlab-rake geo:verification:wiki:reset
If the **primary** and **secondary** sites have a checksum verification mismatch, the cause may not be apparent. To find the cause of a checksum mismatch:
1. On the **primary** site:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Projects**.
1. Find the project that you want to check the checksum differences and
diff --git a/doc/administration/geo/disaster_recovery/index.md b/doc/administration/geo/disaster_recovery/index.md
index 151c0f7d9fb..0c160e85570 100644
--- a/doc/administration/geo/disaster_recovery/index.md
+++ b/doc/administration/geo/disaster_recovery/index.md
@@ -67,7 +67,7 @@ must disable the **primary** site.
- Physically disconnect a machine.
If you plan to [update the primary domain DNS record](#step-4-optional-updating-the-primary-domain-dns-record),
- you may wish to lower the TTL now to speed up propagation.
+ you may wish to maintain a low TTL to ensure fast propagation of DNS changes.
### Step 3. Promoting a **secondary** site
@@ -79,11 +79,7 @@ This issue has been fixed in GitLab 13.4 and later.
Note the following when promoting a secondary:
-- If replication was paused on the secondary site (for example as a part of
- upgrading, while you were running a version of GitLab earlier than 13.4), you
- _must_ [enable the site by using the database](../replication/troubleshooting.md#message-activerecordrecordinvalid-validation-failed-enabled-geo-primary-node-cannot-be-disabled)
- before proceeding. If the secondary site
- [has been paused](../../geo/index.md#pausing-and-resuming-replication), the promotion
+- If the secondary site [has been paused](../../geo/index.md#pausing-and-resuming-replication), the promotion
performs a point-in-time recovery to the last known state.
Data that was created on the primary while the secondary was paused is lost.
- A new **secondary** should not be added at this time. If you want to add a new
@@ -92,9 +88,6 @@ Note the following when promoting a secondary:
- If you encounter an `ActiveRecord::RecordInvalid: Validation failed: Name has already been taken`
error message during this process, for more information, see this
[troubleshooting advice](../replication/troubleshooting.md#fixing-errors-during-a-failover-or-when-promoting-a-secondary-to-a-primary-site).
-- If you run into errors when using `--force` or `--skip-preflight-checks` before 13.5 during this process,
- for more information, see this
- [troubleshooting advice](../replication/troubleshooting.md#errors-when-using---skip-preflight-checks-or---force).
#### Promoting a **secondary** site running on a single node running GitLab 14.5 and later
@@ -225,8 +218,6 @@ do this manually.
sudo gitlab-ctl promote-db
```
- In GitLab 12.8 and earlier, see [Message: `sudo: gitlab-pg-ctl: command not found`](../replication/troubleshooting.md#message-sudo-gitlab-pg-ctl-command-not-found).
-
1. Edit `/etc/gitlab/gitlab.rb` on every node in the **secondary** site to
reflect its new status as **primary** by removing any of the following
lines that might be present:
@@ -708,6 +699,13 @@ If you are running GitLab 14.5 and later:
kubectl --namespace gitlab exec -ti gitlab-geo-toolbox-XXX -- gitlab-rake geo:set_secondary_as_primary
```
+ Environment variables can be provided to modify the behavior of the task. The
+ available variables are:
+
+ | Name | Default value | Description |
+ | ---- | ------------- | ------- |
+ | `ENABLE_SILENT_MODE` | `false` | If `true`, enables [Silent Mode](../../silent_mode/index.md) before promotion (GitLab 16.4 and later) |
+
If you are running GitLab 14.4 and earlier:
1. SSH in to the database node in the **secondary** site and trigger PostgreSQL to
diff --git a/doc/administration/geo/disaster_recovery/planned_failover.md b/doc/administration/geo/disaster_recovery/planned_failover.md
index 6ac67c3d21e..cdc52b55c3e 100644
--- a/doc/administration/geo/disaster_recovery/planned_failover.md
+++ b/doc/administration/geo/disaster_recovery/planned_failover.md
@@ -90,6 +90,11 @@ gitlab-ctl promotion-preflight-checks
Each step is described in more detail below.
+### DNS TTL
+
+If you plan to [update the primary domain DNS record](index.md#step-4-optional-updating-the-primary-domain-dns-record),
+you may wish to maintain a low TTL to ensure fast propagation of DNS changes.
+
### Object storage
If you have a large GitLab installation or cannot tolerate downtime, consider
@@ -149,7 +154,7 @@ ensure these processes are close to 100% as possible during active use.
On the **secondary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
Replicated objects (shown in green) should be close to 100%,
@@ -178,7 +183,7 @@ This [content was moved to another location](background_verification.md).
On the **primary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Messages**.
1. Add a message notifying users on the maintenance window.
@@ -192,7 +197,7 @@ To ensure that all data is replicated to a secondary site, updates (write reques
be disabled on the **primary** site:
1. Enable [maintenance mode](../../maintenance_mode/index.md) on the **primary** site.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. On the Sidekiq dashboard, select **Cron**.
@@ -203,13 +208,10 @@ be disabled on the **primary** site:
## Finish replicating and verifying all data
-NOTE:
-GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary site statuses appears to stop updating and become unhealthy. For more information, see [Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode](../replication/troubleshooting.md#geo-admin-area-shows-unhealthy-after-enabling-maintenance-mode).
-
1. If you are manually replicating any data not managed by Geo, trigger the
final replication process now.
1. On the **primary** site:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. On the Sidekiq dashboard, select **Queues**, and wait for all queues except
@@ -225,7 +227,7 @@ GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary
- The Geo log cursor is up to date (0 events behind).
1. On the **secondary** site:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. On the Sidekiq dashboard, select **Queues**, and wait for all the `geo`
diff --git a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md
index a96963cfea1..787e7c4669e 100644
--- a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md
+++ b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md
@@ -63,12 +63,9 @@ Before following any of those steps, make sure you have `root` access to the
**secondary** to promote it, because there isn't provided an automated way to
promote a Geo replica and perform a failover.
-NOTE:
-GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary site statuses appear to stop updating and become unhealthy. For more information, see [Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode](../../replication/troubleshooting.md#geo-admin-area-shows-unhealthy-after-enabling-maintenance-mode).
-
On the **secondary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites** to see its status.
Replicated objects (shown in green) should be close to 100%,
@@ -108,7 +105,7 @@ follow these steps to avoid unnecessary data loss:
[data not managed by Geo](../../replication/datatypes.md#limitations-on-replicationverification),
trigger the final replication process now.
1. On the **primary** site:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. On the Sidekiq dashboard, select **Queues**, and wait for all queues except
@@ -124,7 +121,7 @@ follow these steps to avoid unnecessary data loss:
- The Geo log cursor is up to date (0 events behind).
1. On the **secondary** site:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. On the Sidekiq dashboard, select **Queues**, and wait for all the `geo`
@@ -257,8 +254,6 @@ Data that was created on the primary while the secondary was paused is lost.
sudo gitlab-ctl promote-db
```
- In GitLab 12.8 and earlier, see [Message: `sudo: gitlab-pg-ctl: command not found`](../../replication/troubleshooting.md#message-sudo-gitlab-pg-ctl-command-not-found).
-
1. Edit `/etc/gitlab/gitlab.rb` on every machine in the **secondary** to
reflect its new status as **primary** by removing any lines that enabled the
`geo_secondary_role`:
diff --git a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md
index 7f94d6e4c1a..e29b19ca040 100644
--- a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md
+++ b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md
@@ -51,9 +51,6 @@ Before following any of those steps, make sure you have `root` access to the
**secondary** to promote it, since there isn't provided an automated way to
promote a Geo replica and perform a failover.
-NOTE:
-GitLab 13.9 through GitLab 14.3 are affected by a bug in which the Geo secondary site statuses appears to stop updating and become unhealthy. For more information, see [Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode](../../replication/troubleshooting.md#geo-admin-area-shows-unhealthy-after-enabling-maintenance-mode).
-
On the **secondary** site, navigate to the **Admin Area > Geo** dashboard to
review its status. Replicated objects (shown in green) should be close to 100%,
and there should be no failures (shown in red). If a large proportion of
@@ -118,7 +115,7 @@ follow these steps to avoid unnecessary data loss:
connection.
1. On the **primary** site:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. On the Sidekiq dashboard, select **Cron**.
@@ -137,7 +134,7 @@ follow these steps to avoid unnecessary data loss:
[data not managed by Geo](../../replication/datatypes.md#limitations-on-replicationverification),
trigger the final replication process now.
1. On the **primary** site:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. On the Sidekiq dashboard, select **Queues**, and wait for all queues except
@@ -153,7 +150,7 @@ follow these steps to avoid unnecessary data loss:
- The Geo log cursor is up to date (0 events behind).
1. On the **secondary** site:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. On the Sidekiq dashboard, select **Queues**, and wait for all the `geo`
diff --git a/doc/administration/geo/glossary.md b/doc/administration/geo/glossary.md
index 2e9a637eb5c..d0f94ba39f5 100644
--- a/doc/administration/geo/glossary.md
+++ b/doc/administration/geo/glossary.md
@@ -14,8 +14,8 @@ these definitions yet.
These are the defined terms to describe all aspects of Geo. Using a set of clearly
defined terms helps us to communicate efficiently and avoids confusion. The language
- on this page aims to be [ubiquitous](https://about.gitlab.com/handbook/communication/#ubiquitous-language)
- and [as simple as possible](https://about.gitlab.com/handbook/communication/#simple-language).
+ on this page aims to be [ubiquitous](https://handbook.gitlab.com/handbook/communication/#ubiquitous-language)
+ and [as simple as possible](https://handbook.gitlab.com/handbook/communication/#simple-language).
We provide example diagrams and statements to demonstrate correct usage of terms.
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index f300549223a..78bd685e06f 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -161,7 +161,7 @@ public URL of the primary site is used.
To update the internal URL of the primary Geo site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
1. Select **Edit** on the primary site.
@@ -193,9 +193,12 @@ This new architecture allows GitLab to be resilient to connectivity issues betwe
WARNING:
This list of limitations only reflects the latest version of GitLab. If you are using an older version, extra limitations may be in place.
-- Pushing directly to a **secondary** site redirects (for HTTP) or proxies (for SSH) the request to the **primary** site instead of [handling it directly](https://gitlab.com/gitlab-org/gitlab/-/issues/1381), except when using Git over HTTP with credentials embedded in the URI. For example, `https://user:password@secondary.tld`.
+- Pushing directly to a **secondary** site redirects (for HTTP) or proxies (for SSH) the request to the **primary** site instead of [handling it directly](https://gitlab.com/gitlab-org/gitlab/-/issues/1381). The limitation is that you cannot use Git over HTTP with credentials embedded in the URI, for example, `https://user:personal-access-token@secondary.tld`. For more information, see how to [use a Geo Site](replication/usage.md).
- The **primary** site has to be online for OAuth login to happen. Existing sessions and Git are not affected. Support for the **secondary** site to use an OAuth provider independent from the primary is [being planned](https://gitlab.com/gitlab-org/gitlab/-/issues/208465).
-- The installation takes multiple manual steps that together can take about an hour depending on circumstances. Consider using [the GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) to deploy and operate production GitLab instances based on our [Reference Architectures](../reference_architectures/index.md), including automation of common daily tasks. We are planning to [improve Geo's installation even further](https://gitlab.com/groups/gitlab-org/-/epics/1465).
+- The installation takes multiple manual steps that together can take about an hour depending on circumstances. Consider using the
+ [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) Terraform and Ansible scripts to deploy and operate production
+ GitLab instances based on our [Reference Architectures](../reference_architectures/index.md), including automation of common daily tasks.
+ [Epic 1465](https://gitlab.com/groups/gitlab-org/-/epics/1465) proposes to improve Geo installation even more.
- Real-time updates of issues/merge requests (for example, via long polling) doesn't work on the **secondary** site.
- Using Geo secondary sites to accelerate runners is not officially supported. Support for this functionality is planned and can be tracked in [epic 9779](https://gitlab.com/groups/gitlab-org/-/epics/9779). If a replication lag occurs between the primary and secondary site, and the pipeline ref is not available on the secondary site when the job is executed, the job will fail.
- GitLab Runners cannot register with a **secondary** site. Support for this is [planned for the future](https://gitlab.com/gitlab-org/gitlab/-/issues/3294).
@@ -243,9 +246,9 @@ Linux package-managed database. External databases are not supported.
In some circumstances, like during [upgrades](replication/upgrading_the_geo_sites.md) or a
[planned failover](disaster_recovery/planned_failover.md), it is desirable to pause replication between the primary and secondary.
-Pausing and resuming replication is done via a command line tool from the node in the secondary site where the `postgresql` service is enabled.
+Pausing and resuming replication is done through a command-line tool from the node in the secondary site where the `postgresql` service is enabled.
-If `postgresql` is on a standalone database node, ensure that `gitlab.rb` on that node contains the configuration line `gitlab_rails['geo_node_name'] = 'node_name'`, where `node_name` is the same as the `geo_name_name` on the application node.
+If `postgresql` is on a standalone database node, ensure that `gitlab.rb` on that node contains the configuration line `gitlab_rails['geo_node_name'] = 'node_name'`, where `node_name` is the same as the `geo_node_name` on the application node.
**To Pause: (from secondary)**
diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md
index f63f8edbc72..8722ab574c3 100644
--- a/doc/administration/geo/replication/configuration.md
+++ b/doc/administration/geo/replication/configuration.md
@@ -95,7 +95,14 @@ This causes all SSH requests to the newly promoted **primary** site to
fail due to SSH host key mismatch. To prevent this, the primary SSH host
keys must be manually replicated to the **secondary** site.
-1. SSH into **each node on your secondary** site and login as the `root` user:
+The SSH host key path depends on the used software:
+
+- If you use OpenSSH, the path is `/etc/ssh`.
+- If you use [`gitlab-sshd`](../../operations/gitlab_sshd.md), the path is `/var/opt/gitlab/gitlab-sshd`.
+
+In the following steps, replace `<ssh_host_key_path>` with the one you're using:
+
+1. SSH into **each Rails node on your secondary** site and log in as the `root` user:
```shell
sudo -i
@@ -104,40 +111,40 @@ keys must be manually replicated to the **secondary** site.
1. Make a backup of any existing SSH host keys:
```shell
- find /etc/ssh -iname 'ssh_host_*' -exec cp {} {}.backup.`date +%F` \;
+ find <ssh_host_key_path> -iname 'ssh_host_*' -exec cp {} {}.backup.`date +%F` \;
```
-1. Copy OpenSSH host keys from the **primary** site:
+1. Copy the SSH host keys from the **primary** site:
If you can access one of the **nodes on your primary** site serving SSH traffic (usually, the main GitLab Rails application nodes) using the **root** user:
```shell
# Run this from the secondary site, change `<primary_site_fqdn>` for the IP or FQDN of the server
- scp root@<primary_node_fqdn>:/etc/ssh/ssh_host_*_key* /etc/ssh
+ scp root@<primary_node_fqdn>:<ssh_host_key_path>/ssh_host_*_key* <ssh_host_key_path>
```
If you only have access through a user with `sudo` privileges:
```shell
# Run this from the node on your primary site:
- sudo tar --transform 's/.*\///g' -zcvf ~/geo-host-key.tar.gz /etc/ssh/ssh_host_*_key*
+ sudo tar --transform 's/.*\///g' -zcvf ~/geo-host-key.tar.gz <ssh_host_key_path>/ssh_host_*_key*
# Run this on each node on your secondary site:
scp <user_with_sudo>@<primary_site_fqdn>:geo-host-key.tar.gz .
- tar zxvf ~/geo-host-key.tar.gz -C /etc/ssh
+ tar zxvf ~/geo-host-key.tar.gz -C <ssh_host_key_path>
```
-1. On **each node on your secondary** site, ensure the file permissions are correct:
+1. On **each Rails node on your secondary** site, ensure the file permissions are correct:
```shell
- chown root:root /etc/ssh/ssh_host_*_key*
- chmod 0600 /etc/ssh/ssh_host_*_key
+ chown root:root <ssh_host_key_path>/ssh_host_*_key*
+ chmod 0600 <ssh_host_key_path>/ssh_host_*_key
```
1. To verify key fingerprint matches, execute the following command on both primary and secondary nodes on each site:
```shell
- for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
+ for file in <ssh_host_key_path>/ssh_host_*_key; do ssh-keygen -lf $file; done
```
You should get an output similar to this one and they should be identical on both nodes:
@@ -153,24 +160,32 @@ keys must be manually replicated to the **secondary** site.
```shell
# This will print the fingerprint for private keys:
- for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
+ for file in <ssh_host_key_path>/ssh_host_*_key; do ssh-keygen -lf $file; done
# This will print the fingerprint for public keys:
- for file in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf $file; done
+ for file in <ssh_host_key_path>/ssh_host_*_key.pub; do ssh-keygen -lf $file; done
```
NOTE:
The output for private keys and public keys command should generate the same fingerprint.
-1. Restart `sshd` on **each node on your secondary** site:
+1. Restart either `sshd` for OpenSSH or the `gitlab-sshd` service on **each Rails node on your secondary** site:
- ```shell
- # Debian or Ubuntu installations
- sudo service ssh reload
+ - For OpenSSH:
- # CentOS installations
- sudo service sshd reload
- ```
+ ```shell
+ # Debian or Ubuntu installations
+ sudo service ssh reload
+
+ # CentOS installations
+ sudo service sshd reload
+ ```
+
+ - For `gitlab-sshd`:
+
+ ```shell
+ sudo gitlab-ctl restart gitlab-sshd
+ ```
1. Verify SSH is still functional.
@@ -202,7 +217,7 @@ keys must be manually replicated to the **secondary** site.
```
1. Navigate to the Primary Node GitLab Instance:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
1. Select **Add site**.
@@ -312,7 +327,7 @@ method to be enabled. This is enabled by default, but if converting an existing
On the **primary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Visibility and access controls**.
@@ -326,7 +341,7 @@ On the **primary** site:
You can sign in to the **secondary** site with the same credentials you used with
the **primary** site. After you sign in:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
1. Verify that it's correctly identified as a **secondary** Geo site, and that
diff --git a/doc/administration/geo/replication/container_registry.md b/doc/administration/geo/replication/container_registry.md
index 6dde611a20d..65ecba0d04a 100644
--- a/doc/administration/geo/replication/container_registry.md
+++ b/doc/administration/geo/replication/container_registry.md
@@ -166,7 +166,7 @@ For each application and Sidekiq node on the **secondary** site:
To verify Container Registry replication is working, on the **secondary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Nodes**.
The initial replication, or "backfill", is probably still in progress.
diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md
index cab3ef581cb..896501128f7 100644
--- a/doc/administration/geo/replication/datatypes.md
+++ b/doc/administration/geo/replication/datatypes.md
@@ -36,39 +36,40 @@ verification methods:
| Git | Personal Snippets | Geo with Gitaly | Gitaly Checksum |
| Git | Group wiki repository | Geo with Gitaly | Gitaly Checksum |
| Blobs | User uploads _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | User uploads _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | User uploads _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | LFS objects _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | LFS objects _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
-| Blobs | CI job artifacts _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | CI job artifacts _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | LFS objects _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
+| Blobs | CI job artifacts _(file system)_ | Geo with API | SHA256 checksum |
+| Blobs | CI job artifacts _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Archived CI build traces _(file system)_ | Geo with API | _Not implemented_ |
-| Blobs | Archived CI build traces _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Archived CI build traces _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Container registry _(file system)_ | Geo with API/Docker API | _SHA256 checksum_ |
-| Blobs | Container registry _(object storage)_ | Geo with API/Managed/Docker API (*2*) | _SHA256 checksum_ |
+| Blobs | Container registry _(object storage)_ | Geo with API/Managed/Docker API (*2*) | SHA256 checksum (*3*) |
| Blobs | Package registry _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | Package registry _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Package registry _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Terraform Module Registry _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | Terraform Module Registry _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Terraform Module Registry _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Versioned Terraform State _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | Versioned Terraform State _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Versioned Terraform State _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | External Merge Request Diffs _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | External Merge Request Diffs _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | External Merge Request Diffs _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Pipeline artifacts _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | Pipeline artifacts _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Pipeline artifacts _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Pages _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | Pages _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Pages _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | CI Secure Files _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | CI Secure Files _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | CI Secure Files _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Incident Metric Images _(file system)_ | Geo with API/Managed | SHA256 checksum |
-| Blobs | Incident Metric Images _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Incident Metric Images _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Alert Metric Images _(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | Alert Metric Images _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Alert Metric Images _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum (*3*) |
| Blobs | Dependency Proxy Images_(file system)_ | Geo with API | SHA256 checksum |
-| Blobs | Dependency Proxy Images _(object storage)_ | Geo with API/managed (*2*) | _Not implemented_ |
+| Blobs | Dependency Proxy Images _(object storage)_ | Geo with API/managed (*2*) | SHA256 checksum (*3*) |
- (*1*): Redis replication can be used as part of HA with Redis sentinel. It's not used between Geo sites.
- (*2*): Object storage replication can be performed by Geo or by your object storage provider/appliance
native replication feature.
+- (*3*): Object Storage verification is behind a [feature flag](../../feature_flags.md), `geo_object_storage_verification`, [introduced in 16.4](https://gitlab.com/groups/gitlab-org/-/epics/8056) and enabled by default. It uses a checksum of the file size to verify the files.
### Git repositories
@@ -188,31 +189,31 @@ successfully, you must replicate their data using some other means.
|Feature | Replicated (added in GitLab version) | Verified (added in GitLab version) | GitLab-managed object storage replication (added in GitLab version) | GitLab-managed object storage verification (added in GitLab version) | Notes |
|:--------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------|:---------------------------------------------------------------------------|:--------------------------------------------------------------------|:----------------------------------------------------------------|:------|
-|[Application data in PostgreSQL](../../postgresql/index.md) | **Yes** (10.2) | **Yes** (10.2) | N/A | N/A | |
-|[Project repository](../../../user/project/repository/index.md) | **Yes** (10.2) | **Yes** (10.7) | N/A | N/A | Migrated to [self-service framework](../../../development/geo/framework.md) in 16.2. See GitLab issue [#367925](https://gitlab.com/gitlab-org/gitlab/-/issues/367925) for more details.<br /><br />Behind feature flag `geo_project_repository_replication`, enabled by default in (16.3).<br /><br /> All projects, including [archived projects](../../../user/project/settings/index.md#archive-a-project), are replicated. |
-|[Project wiki repository](../../../user/project/wiki/index.md) | **Yes** (10.2)<sup>2</sup> | **Yes** (10.7)<sup>2</sup> | N/A | N/A | Migrated to [self-service framework](../../../development/geo/framework.md) in 15.11. See GitLab issue [#367925](https://gitlab.com/gitlab-org/gitlab/-/issues/367925) for more details.<br /><br />Behind feature flag `geo_project_wiki_repository_replication`, enabled by default in (15.11). |
-|[Group wiki repository](../../../user/project/wiki/group.md) | [**Yes** (13.10)](https://gitlab.com/gitlab-org/gitlab/-/issues/208147) | [**Yes** (16.3)](https://gitlab.com/gitlab-org/gitlab/-/issues/323897) | N/A | N/A | Behind feature flag `geo_group_wiki_repository_replication`, enabled by default. |
-|[Uploads](../../uploads.md) | **Yes** (10.2) | **Yes** (14.6) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | Replication is behind the feature flag `geo_upload_replication`, enabled by default. Verification was behind the feature flag `geo_upload_verification`, removed in 14.8. |
-|[LFS objects](../../lfs/index.md) | **Yes** (10.2) | **Yes** (14.6) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/-/issues/32696).<br /><br />Replication is behind the feature flag `geo_lfs_object_replication`, enabled by default. Verification was behind the feature flag `geo_lfs_object_verification`, removed in 14.7. |
-|[Personal snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | N/A | N/A | |
-|[Project snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | N/A | N/A | |
-|[CI job artifacts](../../../ci/jobs/job_artifacts.md) | **Yes** (10.4) | **Yes** (14.10) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | Verification is behind the feature flag `geo_job_artifact_replication`, enabled by default in 14.10. |
-|[CI Pipeline Artifacts](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/ci/pipeline_artifact.rb) | [**Yes** (13.11)](https://gitlab.com/gitlab-org/gitlab/-/issues/238464) | [**Yes** (13.11)](https://gitlab.com/gitlab-org/gitlab/-/issues/238464) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | Persists additional artifacts after a pipeline completes. |
-|[CI Secure Files](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/ci/secure_file.rb) | [**Yes** (15.3)](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91430) | [**Yes** (15.3)](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91430) | [**Yes** (15.3)](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91430) | [No](object_storage.md#verification-of-files-in-object-storage) | Verification is behind the feature flag `geo_ci_secure_file_replication`, enabled by default in 15.3. |
+|[Application data in PostgreSQL](../../postgresql/index.md) | **Yes** (10.2) | **Yes** (10.2) | Not applicable | Not applicable | |
+|[Project repository](../../../user/project/repository/index.md) | **Yes** (10.2) | **Yes** (10.7) | Not applicable | Not applicable | Migrated to [self-service framework](../../../development/geo/framework.md) in 16.2. See GitLab issue [#367925](https://gitlab.com/gitlab-org/gitlab/-/issues/367925) for more details.<br /><br />Behind feature flag `geo_project_repository_replication`, enabled by default in (16.3).<br /><br /> All projects, including [archived projects](../../../user/project/settings/index.md#archive-a-project), are replicated. |
+|[Project wiki repository](../../../user/project/wiki/index.md) | **Yes** (10.2)<sup>2</sup> | **Yes** (10.7)<sup>2</sup> | Not applicable | Not applicable | Migrated to [self-service framework](../../../development/geo/framework.md) in 15.11. See GitLab issue [#367925](https://gitlab.com/gitlab-org/gitlab/-/issues/367925) for more details.<br /><br />Behind feature flag `geo_project_wiki_repository_replication`, enabled by default in (15.11). |
+|[Group wiki repository](../../../user/project/wiki/group.md) | [**Yes** (13.10)](https://gitlab.com/gitlab-org/gitlab/-/issues/208147) | [**Yes** (16.3)](https://gitlab.com/gitlab-org/gitlab/-/issues/323897) | Not applicable | Not applicable | Behind feature flag `geo_group_wiki_repository_replication`, enabled by default. |
+|[Uploads](../../uploads.md) | **Yes** (10.2) | **Yes** (14.6) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | Replication is behind the feature flag `geo_upload_replication`, enabled by default. Verification was behind the feature flag `geo_upload_verification`, removed in 14.8. |
+|[LFS objects](../../lfs/index.md) | **Yes** (10.2) | **Yes** (14.6) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/-/issues/32696).<br /><br />Replication is behind the feature flag `geo_lfs_object_replication`, enabled by default. Verification was behind the feature flag `geo_lfs_object_verification`, removed in 14.7. |
+|[Personal snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | Not applicable | Not applicable | |
+|[Project snippets](../../../user/snippets.md) | **Yes** (10.2) | **Yes** (10.2) | Not applicable | Not applicable | |
+|[CI job artifacts](../../../ci/jobs/job_artifacts.md) | **Yes** (10.4) | **Yes** (14.10) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | Verification is behind the feature flag `geo_job_artifact_replication`, enabled by default in 14.10. |
+|[CI Pipeline Artifacts](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/ci/pipeline_artifact.rb) | [**Yes** (13.11)](https://gitlab.com/gitlab-org/gitlab/-/issues/238464) | [**Yes** (13.11)](https://gitlab.com/gitlab-org/gitlab/-/issues/238464) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | Persists additional artifacts after a pipeline completes. |
+|[CI Secure Files](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/ci/secure_file.rb) | [**Yes** (15.3)](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91430) | [**Yes** (15.3)](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91430) | [**Yes** (15.3)](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91430) | [**Yes** (16.4)](object_storage.md) | Verification is behind the feature flag `geo_ci_secure_file_replication`, enabled by default in 15.3. |
|[Container Registry](../../packages/container_registry.md) | **Yes** (12.3)<sup>1</sup> | **Yes** (15.10) | **Yes** (12.3)<sup>1</sup> | **Yes** (15.10) | See [instructions](container_registry.md) to set up the Container Registry replication. |
-|[Terraform Module Registry](../../../user/packages/terraform_module_registry/index.md) | **Yes** (14.0) | **Yes** (14.0) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | Behind feature flag `geo_package_file_replication`, enabled by default. |
-|[Project designs repository](../../../user/project/issues/design_management.md) | **Yes** (12.7) | **Yes** (16.1) | N/A | N/A | Designs also require replication of LFS objects and Uploads. Replication is behind the feature flag `geo_design_management_repository_replication`, enabled by default.|
-|[Package Registry](../../../user/packages/package_registry/index.md) | **Yes** (13.2) | **Yes** (13.10) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | Behind feature flag `geo_package_file_replication`, enabled by default. |
-|[Versioned Terraform State](../../terraform_state.md) | **Yes** (13.5) | **Yes** (13.12) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | Replication is behind the feature flag `geo_terraform_state_version_replication`, enabled by default. Verification was behind the feature flag `geo_terraform_state_version_verification`, which was removed in 14.0. |
-|[External merge request diffs](../../merge_request_diffs.md) | **Yes** (13.5) | **Yes** (14.6) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | Replication is behind the feature flag `geo_merge_request_diff_replication`, enabled by default. Verification was behind the feature flag `geo_merge_request_diff_verification`, removed in 14.7.|
-|[Versioned snippets](../../../user/snippets.md#versioned-snippets) | [**Yes** (13.7)](https://gitlab.com/groups/gitlab-org/-/epics/2809) | [**Yes** (14.2)](https://gitlab.com/groups/gitlab-org/-/epics/2810) | N/A | N/A | Verification was implemented behind the feature flag `geo_snippet_repository_verification` in 13.11, and the feature flag was removed in 14.2. |
-|[GitLab Pages](../../pages/index.md) | [**Yes** (14.3)](https://gitlab.com/groups/gitlab-org/-/epics/589) | **Yes** (14.6) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [No](object_storage.md#verification-of-files-in-object-storage) | Behind feature flag `geo_pages_deployment_replication`, enabled by default. Verification was behind the feature flag `geo_pages_deployment_verification`, removed in 14.7. |
-|[Project-level Secure files](../../../ci/secure_files/index.md) | **Yes** (15.3) | **Yes** (15.3) | **Yes** (15.3) | [No](object_storage.md#verification-of-files-in-object-storage) | |
-| [Incident Metric Images](../../../operations/incident_management/incidents.md#metrics) | **Yes** (15.5) | **Yes**(15.5) | **Yes** (15.5) | [No](object_storage.md#verification-of-files-in-object-storage) | Replication/Verification is handled via the Uploads data type. | |
-|[Alert Metric Images](../../../operations/incident_management/alerts.md#metrics-tab) | **Yes** (15.5) | **Yes** (15.5) | **Yes** (15.5) | [No](object_storage.md#verification-of-files-in-object-storage) | Replication/Verification is handled via the Uploads data type. |
-|[Server-side Git hooks](../../server_hooks.md) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/1867) | No | N/A | N/A | Not planned because of current implementation complexity, low customer interest, and availability of alternatives to hooks. |
+|[Terraform Module Registry](../../../user/packages/terraform_module_registry/index.md) | **Yes** (14.0) | **Yes** (14.0) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | Behind feature flag `geo_package_file_replication`, enabled by default. |
+|[Project designs repository](../../../user/project/issues/design_management.md) | **Yes** (12.7) | **Yes** (16.1) | Not applicable | Not applicable | Designs also require replication of LFS objects and Uploads. |
+|[Package Registry](../../../user/packages/package_registry/index.md) | **Yes** (13.2) | **Yes** (13.10) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | Behind feature flag `geo_package_file_replication`, enabled by default. |
+|[Versioned Terraform State](../../terraform_state.md) | **Yes** (13.5) | **Yes** (13.12) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | Replication is behind the feature flag `geo_terraform_state_version_replication`, enabled by default. Verification was behind the feature flag `geo_terraform_state_version_verification`, which was removed in 14.0. |
+|[External merge request diffs](../../merge_request_diffs.md) | **Yes** (13.5) | **Yes** (14.6) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | Replication is behind the feature flag `geo_merge_request_diff_replication`, enabled by default. Verification was behind the feature flag `geo_merge_request_diff_verification`, removed in 14.7.|
+|[Versioned snippets](../../../user/snippets.md#versioned-snippets) | [**Yes** (13.7)](https://gitlab.com/groups/gitlab-org/-/epics/2809) | [**Yes** (14.2)](https://gitlab.com/groups/gitlab-org/-/epics/2810) | Not applicable | Not applicable | Verification was implemented behind the feature flag `geo_snippet_repository_verification` in 13.11, and the feature flag was removed in 14.2. |
+|[GitLab Pages](../../pages/index.md) | [**Yes** (14.3)](https://gitlab.com/groups/gitlab-org/-/epics/589) | **Yes** (14.6) | [**Yes** (15.1)](https://gitlab.com/groups/gitlab-org/-/epics/5551) | [**Yes** (16.4)](object_storage.md) | Behind feature flag `geo_pages_deployment_replication`, enabled by default. Verification was behind the feature flag `geo_pages_deployment_verification`, removed in 14.7. |
+|[Project-level Secure files](../../../ci/secure_files/index.md) | **Yes** (15.3) | **Yes** (15.3) | **Yes** (15.3) | [**Yes** (16.4)](object_storage.md) | |
+| [Incident Metric Images](../../../operations/incident_management/incidents.md#metrics) | **Yes** (15.5) | **Yes**(15.5) | **Yes** (15.5) | [**Yes** (16.4)](object_storage.md) | Replication/Verification is handled via the Uploads data type. | |
+|[Alert Metric Images](../../../operations/incident_management/alerts.md#metrics-tab) | **Yes** (15.5) | **Yes** (15.5) | **Yes** (15.5) | [**Yes** (16.4)](object_storage.md) | Replication/Verification is handled via the Uploads data type. |
+|[Server-side Git hooks](../../server_hooks.md) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/1867) | No | Not applicable | Not applicable | Not planned because of current implementation complexity, low customer interest, and availability of alternatives to hooks. |
|[Elasticsearch integration](../../../integration/advanced_search/elasticsearch.md) | [Not planned](https://gitlab.com/gitlab-org/gitlab/-/issues/1186) | No | No | No | Not planned because further product discovery is required and Elasticsearch (ES) clusters can be rebuilt. Secondaries use the same ES cluster as the primary. |
-|[Dependency Proxy Images](../../../user/packages/dependency_proxy/index.md) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [No](object_storage.md#verification-of-files-in-object-storage) | |
+|[Dependency Proxy Images](../../../user/packages/dependency_proxy/index.md) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [**Yes** (15.7)](https://gitlab.com/groups/gitlab-org/-/epics/8833) | [**Yes** (16.4)](object_storage.md) | |
|[Vulnerability Export](../../../user/application_security/vulnerability_report/index.md#export-vulnerability-details) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/3111) | No | No | No | Not planned because they are ephemeral and sensitive information. They can be regenerated on demand. |
<sup>1</sup> Migrated to [self-service framework](../../../development/geo/framework.md) in 15.5. See GitLab issue [#337436](https://gitlab.com/gitlab-org/gitlab/-/issues/337436) for more details.
diff --git a/doc/administration/geo/replication/disable_geo.md b/doc/administration/geo/replication/disable_geo.md
index bedcca7e311..42c37a79ec2 100644
--- a/doc/administration/geo/replication/disable_geo.md
+++ b/doc/administration/geo/replication/disable_geo.md
@@ -36,7 +36,7 @@ to do that.
To remove the **primary** site:
1. [Remove all secondary Geo sites](remove_geo_site.md)
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Nodes**.
1. Select **Remove** for the **primary** node.
diff --git a/doc/administration/geo/replication/object_storage.md b/doc/administration/geo/replication/object_storage.md
index 86db8186a13..3b6b214d9e3 100644
--- a/doc/administration/geo/replication/object_storage.md
+++ b/doc/administration/geo/replication/object_storage.md
@@ -7,6 +7,8 @@ type: howto
# Geo with Object storage **(PREMIUM SELF)**
+> Verification of files stored in object storage was [introduced](https://gitlab.com/groups/gitlab-org/-/epics/8056) in GitLab 16.4 [with a flag](../../feature_flags.md) named `geo_object_storage_verification`. Enabled by default.
+
Geo can be used in combination with Object Storage (AWS S3, or other compatible object storage).
**Secondary** sites can use one of the following:
@@ -41,7 +43,7 @@ whether they are stored on the local file system or in object storage.
To enable GitLab replication:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Nodes**.
1. Select **Edit** on the **secondary** site.
@@ -86,7 +88,3 @@ For manual synchronization, or scheduled by `cron`, see:
- [`s3cmd sync`](https://s3tools.org/s3cmd-sync)
- [`gsutil rsync`](https://cloud.google.com/storage/docs/gsutil/commands/rsync)
-
-## Verification of files in object storage
-
-[Files stored in object storage are not verified.](https://gitlab.com/groups/gitlab-org/-/epics/8056)
diff --git a/doc/administration/geo/replication/remove_geo_site.md b/doc/administration/geo/replication/remove_geo_site.md
index de0ad3fe2fb..a55c05050a0 100644
--- a/doc/administration/geo/replication/remove_geo_site.md
+++ b/doc/administration/geo/replication/remove_geo_site.md
@@ -9,7 +9,7 @@ type: howto
**Secondary** sites can be removed from the Geo cluster using the Geo administration page of the **primary** site. To remove a **secondary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Nodes**.
1. For the **secondary** site you want to remove, select **Remove**.
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index ed11307f57b..dd2693f4ba7 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -20,14 +20,14 @@ Here is a list of steps you should take to attempt to fix problem:
Before attempting more advanced troubleshooting:
-- Check [the health of the **secondary** site](#check-the-health-of-the-secondary-site).
+- Check [the health of the Geo sites](#check-the-health-of-the-geo-sites).
- Check [if PostgreSQL replication is working](#check-if-postgresql-replication-is-working).
-### Check the health of the **secondary** site
+### Check the health of the Geo sites
On the **primary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
@@ -116,6 +116,38 @@ The following environment variables are supported.
|`NTP_PORT` | The NTP port the host listens on. |`ntp`|
|`NTP_TIMEOUT`| The NTP timeout in seconds. | The value defined in the `net-ntp` Ruby library ([60 seconds](https://github.com/zencoder/net-ntp/blob/3d0990214f439a5127782e0f50faeaf2c8ca7023/lib/net/ntp/ntp.rb#L6)). |
+If the Rake task skips the `OpenSSH configured to use AuthorizedKeysCommand` check, the
+following output displays:
+
+```plaintext
+OpenSSH configured to use AuthorizedKeysCommand ... skipped
+ Reason:
+ Cannot access OpenSSH configuration file
+ Try fixing it:
+ This is expected if you are using SELinux. You may want to check configuration manually
+ For more information see:
+ doc/administration/operations/fast_ssh_key_lookup.md
+```
+
+This issue may occur if:
+
+- You [use SELinux](../../operations/fast_ssh_key_lookup.md#selinux-support-and-limitations).
+- You don't use SELinux, and the `git` user cannot access the OpenSSH configuration file due to restricted file permissions.
+
+In the latter case, the following output shows that only the `root` user can read this file:
+
+```plaintext
+sudo stat -c '%G:%U %A %a %n' /etc/ssh/sshd_config
+
+root:root -rw------- 600 /etc/ssh/sshd_config
+```
+
+To allow the `git` user to read the OpenSSH configuration file, without changing the file owner or permissions, use `acl`:
+
+```plaintext
+sudo setfacl -m u:git:r /etc/ssh/sshd_config
+```
+
#### Sync status Rake task
Current sync information can be found manually by running this Rake task on any
@@ -142,11 +174,10 @@ http://secondary.example.com/
Health Status: Healthy
Repositories: succeeded 12345 / total 12345 (100%)
Verified Repositories: succeeded 12345 / total 12345 (100%)
- Wikis: succeeded 6789 / total 6789 (100%)
- Verified Wikis: succeeded 6789 / total 6789 (100%)
+ Project Wiki Repositories: succeeded 6789 / total 6789 (100%)
Attachments: succeeded 4 / total 4 (100%)
CI job artifacts: succeeded 0 / total 0 (0%)
- Design repositories: succeeded 1 / total 1 (100%)
+ Design management repositories: succeeded 1 / total 1 (100%)
LFS Objects: failed 1 / succeeded 2 / total 3 (67%)
Merge Request Diffs: succeeded 0 / total 0 (0%)
Package Files: failed 1 / succeeded 2 / total 3 (67%)
@@ -160,6 +191,7 @@ http://secondary.example.com/
Terraform State Versions Verified: succeeded 0 / total 10 (0%)
Snippet Repositories Verified: succeeded 99 / total 100 (99%)
Pipeline Artifacts Verified: succeeded 0 / total 10 (0%)
+ Project Wiki Repositories Verified: succeeded 6789 / total 6789 (100%)
Sync Settings: Full
Database replication lag: 0 seconds
Last event ID seen from primary: 12345 (about 2 minutes ago)
@@ -188,119 +220,7 @@ If you notice replication or verification failures, you can try to [resolve them
If there are Repository check failures, you can try to [resolve them](#find-repository-check-failures-in-a-geo-secondary-site).
-### Check if PostgreSQL replication is working
-
-To check if PostgreSQL replication is working, check if:
-
-- [Sites are pointing to the correct database node](#are-sites-pointing-to-the-correct-database-node).
-- [Geo can detect the current site correctly](#can-geo-detect-the-current-site-correctly).
-
-#### Are sites pointing to the correct database node?
-
-You should make sure your **primary** Geo [site](../glossary.md) points to
-the database node that has write permissions.
-
-Any **secondary** sites should point only to read-only database nodes.
-
-#### Can Geo detect the current site correctly?
-
-Geo finds the current Puma or Sidekiq node's Geo [site](../glossary.md) name in
-`/etc/gitlab/gitlab.rb` with the following logic:
-
-1. Get the "Geo node name" (there is
- [an issue to rename the settings to "Geo site name"](https://gitlab.com/gitlab-org/gitlab/-/issues/335944)):
- - Linux package: get the `gitlab_rails['geo_node_name']` setting.
- - GitLab Helm charts: get the `global.geo.nodeName` setting (see [Charts with GitLab Geo](https://docs.gitlab.com/charts/advanced/geo/index.html)).
-1. If that is not defined, then get the `external_url` setting.
-
-This name is used to look up the Geo site with the same **Name** in the **Geo Sites**
-dashboard.
-
-To check if the current machine has a site name that matches a site in the
-database, run the check task:
-
-```shell
-sudo gitlab-rake gitlab:geo:check
-```
-
-It displays the current machine's site name and whether the matching database
-record is a **primary** or **secondary** site.
-
-```plaintext
-This machine's Geo node name matches a database record ... yes, found a secondary node named "Shanghai"
-```
-
-```plaintext
-This machine's Geo node name matches a database record ... no
- Try fixing it:
- You could add or update a Geo node database record, setting the name to "https://example.com/".
- Or you could set this machine's Geo node name to match the name of an existing database record: "London", "Shanghai"
- For more information see:
- doc/administration/geo/replication/troubleshooting.md#can-geo-detect-the-current-node-correctly
-```
-
-For more information about recommended site names in the description of the Name field, see
-[Geo Admin Area Common Settings](../../../administration/geo_sites.md#common-settings).
-
-### Reverify all uploads (or any SSF data type which is verified)
-
-1. SSH into a GitLab Rails node in the primary Geo site.
-1. Open [Rails console](../../operations/rails_console.md).
-1. Mark all uploads as "pending verification":
-
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-
- ```ruby
- Upload.verification_state_table_class.each_batch do |relation|
- relation.update_all(verification_state: 0)
- end
- ```
-
-1. This causes the primary to start checksumming all Uploads.
-1. When a primary successfully checksums a record, then all secondaries recalculate the checksum as well, and they compare the values.
-
-A similar thing can be done for all Models handled by the [Geo Self-Service Framework](../../../development/geo/framework.md) which have implemented verification:
-
-- `LfsObject`
-- `MergeRequestDiff`
-- `Packages::PackageFile`
-- `Terraform::StateVersion`
-- `SnippetRepository`
-- `Ci::PipelineArtifact`
-- `PagesDeployment`
-- `Upload`
-- `Ci::JobArtifact`
-- `Ci::SecureFile`
-
-NOTE:
-`GroupWikiRepository` is not in the previous list since verification is not implemented.
-There is an [issue to implement this functionality in the Admin Area UI](https://gitlab.com/gitlab-org/gitlab/-/issues/364729).
-
-### Message: `WARNING: oldest xmin is far in the past` and `pg_wal` size growing
-
-If a replication slot is inactive,
-the `pg_wal` logs corresponding to the slot are reserved forever
-(or until the slot is active again). This causes continuous disk usage growth
-and the following messages appear repeatedly in the
-[PostgreSQL logs](../../logs/index.md#postgresql-logs):
-
-```plaintext
-WARNING: oldest xmin is far in the past
-HINT: Close open transactions soon to avoid wraparound problems.
-You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
-```
-
-To fix this:
-
-1. [Connect to the primary database](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database).
-
-1. Run `SELECT * FROM pg_replication_slots;`.
- Note the `slot_name` that reports `active` as `f` (false).
-
-1. Follow [the steps to remove that Geo site](remove_geo_site.md).
-
-## Fixing errors found when running the Geo check Rake task
+##### Fixing errors found when running the Geo check Rake task
When running this Rake task, you may see error messages if the nodes are not properly configured:
@@ -367,7 +287,7 @@ sudo gitlab-rake gitlab:geo:check
Checking Geo ... Finished
```
- Ensure you have added the secondary site in the **Main menu > Admin > Geo > Sites** on the web interface for the **primary** site.
+ Ensure you have added the secondary site in the Admin Area under **Geo > Sites** on the web interface for the **primary** site.
Also ensure you entered the `gitlab_rails['geo_node_name']`
when adding the secondary site in the Admin Area of the **primary** site.
In GitLab 12.3 and earlier, edit the secondary site in the Admin Area of the **primary**
@@ -423,7 +343,7 @@ sudo gitlab-rake gitlab:geo:check
- If you are running the secondary site's tracking database in an external database, then follow [Geo with external PostgreSQL instances](../setup/external_database.md#configure-the-tracking-database)
- If the Geo check task was run on a node which is not running a service which runs the GitLab Rails app (Puma, Sidekiq, or Geo Log Cursor), then this error can be ignored. The node does not need Rails to be configured.
-### Message: Machine clock is synchronized ... Exception
+##### Message: Machine clock is synchronized ... Exception
The Rake task attempts to verify that the server clock is synchronized with NTP. Synchronized clocks
are required for Geo to function correctly. As an example, for security, when the server time on the
@@ -457,7 +377,7 @@ generate an error because containers in Kubernetes do not have access to the hos
Machine clock is synchronized ... Exception: getaddrinfo: Servname not supported for ai_socktype
```
-### Message: `ActiveRecord::StatementInvalid: PG::ReadOnlySqlTransaction: ERROR: cannot execute INSERT in a read-only transaction`
+##### Message: `ActiveRecord::StatementInvalid: PG::ReadOnlySqlTransaction: ERROR: cannot execute INSERT in a read-only transaction`
When this error is encountered on a secondary site, it likely affects all usages of GitLab Rails such as `gitlab-rails` or `gitlab-rake` commands, as well the Puma, Sidekiq, and Geo Log Cursor services.
@@ -490,8 +410,122 @@ This situation can occur during initial configuration when a secondary site is n
To resolve the error, follow [Step 3. Add the secondary site](configuration.md#step-3-add-the-secondary-site).
+### Check if PostgreSQL replication is working
+
+To check if PostgreSQL replication is working, check if:
+
+- [Sites are pointing to the correct database node](#are-sites-pointing-to-the-correct-database-node).
+- [Geo can detect the current site correctly](#can-geo-detect-the-current-site-correctly).
+
+#### Are sites pointing to the correct database node?
+
+You should make sure your **primary** Geo [site](../glossary.md) points to
+the database node that has write permissions.
+
+Any **secondary** sites should point only to read-only database nodes.
+
+#### Can Geo detect the current site correctly?
+
+Geo finds the current Puma or Sidekiq node's Geo [site](../glossary.md) name in
+`/etc/gitlab/gitlab.rb` with the following logic:
+
+1. Get the "Geo node name" (there is
+ [an issue to rename the settings to "Geo site name"](https://gitlab.com/gitlab-org/gitlab/-/issues/335944)):
+ - Linux package: get the `gitlab_rails['geo_node_name']` setting.
+ - GitLab Helm charts: get the `global.geo.nodeName` setting (see [Charts with GitLab Geo](https://docs.gitlab.com/charts/advanced/geo/index.html)).
+1. If that is not defined, then get the `external_url` setting.
+
+This name is used to look up the Geo site with the same **Name** in the **Geo Sites**
+dashboard.
+
+To check if the current machine has a site name that matches a site in the
+database, run the check task:
+
+```shell
+sudo gitlab-rake gitlab:geo:check
+```
+
+It displays the current machine's site name and whether the matching database
+record is a **primary** or **secondary** site.
+
+```plaintext
+This machine's Geo node name matches a database record ... yes, found a secondary node named "Shanghai"
+```
+
+```plaintext
+This machine's Geo node name matches a database record ... no
+ Try fixing it:
+ You could add or update a Geo node database record, setting the name to "https://example.com/".
+ Or you could set this machine's Geo node name to match the name of an existing database record: "London", "Shanghai"
+ For more information see:
+ doc/administration/geo/replication/troubleshooting.md#can-geo-detect-the-current-node-correctly
+```
+
+For more information about recommended site names in the description of the Name field, see
+[Geo Admin Area Common Settings](../../../administration/geo_sites.md#common-settings).
+
+### Check OS locale data compatibility
+
+If different operating systems or different operating system versions are deployed across Geo sites, you should perform a locale data compatibility check before setting up Geo.
+
+Geo uses PostgreSQL and Streaming Replication to replicate data across Geo sites. PostgreSQL uses locale data provided by the operating system's C library for sorting text. If the locale data in the C library is incompatible across Geo sites, it can cause erroneous query results that lead to [incorrect behavior on secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/360723).
+
+For example, Ubuntu 18.04 (and earlier) and RHEL/Centos7 (and earlier) are incompatible with their later releases.
+See the [PostgreSQL wiki for more details](https://wiki.postgresql.org/wiki/Locale_data_changes).
+
+On all hosts running PostgreSQL, across all Geo sites, run the following shell command:
+
+```shell
+( echo "1-1"; echo "11" ) | LC_COLLATE=en_US.UTF-8 sort
+```
+
+The output looks like either:
+
+```plaintext
+1-1
+11
+```
+
+or the reverse order:
+
+```plaintext
+11
+1-1
+```
+
+If the output is identical on all hosts, then they running compatible versions of locale data.
+
+If the output differs on some hosts, PostgreSQL replication does not work properly: indexes are corrupted on the database replicas. You should select operating system versions that are compatible.
+
+A full index rebuild is required if the on-disk data is transferred 'at rest' to an operating system with an incompatible locale, or through replication.
+
+This check is also required when using a mixture of GitLab deployments. The locale might be different between an Linux package install, a GitLab Docker container, a Helm chart deployment, or external database services.
+
## Fixing PostgreSQL database replication errors
+### Message: `WARNING: oldest xmin is far in the past` and `pg_wal` size growing
+
+If a replication slot is inactive,
+the `pg_wal` logs corresponding to the slot are reserved forever
+(or until the slot is active again). This causes continuous disk usage growth
+and the following messages appear repeatedly in the
+[PostgreSQL logs](../../logs/index.md#postgresql-logs):
+
+```plaintext
+WARNING: oldest xmin is far in the past
+HINT: Close open transactions soon to avoid wraparound problems.
+You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
+```
+
+To fix this:
+
+1. [Connect to the primary database](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database).
+
+1. Run `SELECT * FROM pg_replication_slots;`.
+ Note the `slot_name` that reports `active` as `f` (false).
+
+1. Follow [the steps to remove that Geo site](remove_geo_site.md).
+
The following sections outline troubleshooting steps for fixing replication
error messages (indicated by `Database replication working? ... no` in the
[`geo:check` output](#health-check-rake-task).
@@ -645,6 +679,43 @@ In GitLab 13.4, a seed project is added when GitLab is first installed. This mak
on a new Geo secondary site. There is an [issue to account for seed projects](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5618)
when checking the database.
+## Synchronization errors
+
+### Reverify all uploads (or any SSF data type which is verified)
+
+1. SSH into a GitLab Rails node in the primary Geo site.
+1. Open [Rails console](../../operations/rails_console.md).
+1. Mark all uploads as "pending verification":
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+ ```ruby
+ Upload.verification_state_table_class.each_batch do |relation|
+ relation.update_all(verification_state: 0)
+ end
+ ```
+
+1. This causes the primary to start checksumming all Uploads.
+1. When a primary successfully checksums a record, then all secondaries recalculate the checksum as well, and they compare the values.
+
+You can perform a similar operation with other the Models handled by the [Geo Self-Service Framework](../../../development/geo/framework.md) which have implemented verification:
+
+- `LfsObject`
+- `MergeRequestDiff`
+- `Packages::PackageFile`
+- `Terraform::StateVersion`
+- `SnippetRepository`
+- `Ci::PipelineArtifact`
+- `PagesDeployment`
+- `Upload`
+- `Ci::JobArtifact`
+- `Ci::SecureFile`
+
+NOTE:
+`GroupWikiRepository` is not in the previous list since verification is not implemented.
+There is an [issue to implement this functionality in the Admin Area UI](https://gitlab.com/gitlab-org/gitlab/-/issues/364729).
+
### Message: `Synchronization failed - Error syncing repository`
WARNING:
@@ -686,7 +757,7 @@ To solve this:
1. Sign in on the web interface for the secondary Geo site.
-1. Back up [the `.git` folder](../../repository_storage_types.md#translate-hashed-storage-paths).
+1. Back up [the `.git` folder](../../repository_storage_paths.md#translate-hashed-storage-paths).
1. Optional. [Spot-check](../../logs/log_parsing.md#find-all-projects-affected-by-a-fatal-git-problem)
a few of those IDs whether they indeed correspond
@@ -717,212 +788,11 @@ To solve this:
end
```
-### Very large repositories never successfully synchronize on the **secondary** site
-
-#### GitLab 10.1 and earlier
-
-GitLab places a timeout on all repository clones, including project imports
-and Geo synchronization operations. If a fresh `git clone` of a repository
-on the **primary** takes more than the default three hours, you may be affected by this.
-
-To increase the timeout:
-
-1. On the **Sidekiq nodes on your secondary** site,
-add the following line to `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- gitlab_rails['gitlab_shell_git_timeout'] = 14400
- ```
-
-1. Reconfigure GitLab:
-
- ```shell
- sudo gitlab-ctl reconfigure
- ```
-
-This increases the timeout to four hours (14400 seconds). Choose a time
-long enough to accommodate a full clone of your largest repositories.
-
-#### GitLab 10.2 and later
-
-Geo [replicates Git repositories over HTTPS](../index.md#how-it-works). GitLab does not place a timeout on these requests. If a Git repository is failing to replicate, with a consistent job execution time, then you should check for timeouts applied by external components such as load balancers.
-
-### New LFS objects are never replicated
-
-If new LFS objects are never replicated to secondary Geo sites, check the version of
-GitLab you are running. GitLab versions 11.11.x or 12.0.x are affected by
-[a bug that results in new LFS objects not being replicated to Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/32696).
-
-To resolve the issue, upgrade to GitLab 12.1 or later.
-
### Failures during backfill
During a [backfill](../index.md#backfill), failures are scheduled to be retried at the end
of the backfill queue, therefore these failures only clear up **after** the backfill completes.
-### Resetting Geo **secondary** site replication
-
-If you get a **secondary** site in a broken state and want to reset the replication state,
-to start again from scratch, there are a few steps that can help you:
-
-1. Stop Sidekiq and the Geo LogCursor.
-
- It's possible to make Sidekiq stop gracefully, but making it stop getting new jobs and
- wait until the current jobs to finish processing.
-
- You need to send a **SIGTSTP** kill signal for the first phase and them a **SIGTERM**
- when all jobs have finished. Otherwise just use the `gitlab-ctl stop` commands.
-
- ```shell
- gitlab-ctl status sidekiq
- # run: sidekiq: (pid 10180) <- this is the PID you will use
- kill -TSTP 10180 # change to the correct PID
-
- gitlab-ctl stop sidekiq
- gitlab-ctl stop geo-logcursor
- ```
-
- You can watch the [Sidekiq logs](../../logs/index.md#sidekiq-logs) to know when Sidekiq jobs processing has finished:
-
- ```shell
- gitlab-ctl tail sidekiq
- ```
-
-1. Rename repository storage folders and create new ones. If you are not concerned about possible orphaned directories and files, you can skip this step.
-
- ```shell
- mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
- mkdir -p /var/opt/gitlab/git-data/repositories
- chown git:git /var/opt/gitlab/git-data/repositories
- ```
-
- NOTE:
- You may want to remove the `/var/opt/gitlab/git-data/repositories.old` in the future
- as soon as you confirmed that you don't need it anymore, to save disk space.
-
-1. Optional. Rename other data folders and create new ones.
-
- WARNING:
- You may still have files on the **secondary** site that have been removed from the **primary** site, but this
- removal has not been reflected. If you skip this step, these files are not removed from the Geo **secondary** site.
-
- Any uploaded content (like file attachments, avatars, or LFS objects) is stored in a
- subfolder in one of these paths:
-
- - `/var/opt/gitlab/gitlab-rails/shared`
- - `/var/opt/gitlab/gitlab-rails/uploads`
-
- To rename all of them:
-
- ```shell
- gitlab-ctl stop
-
- mv /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared.old
- mkdir -p /var/opt/gitlab/gitlab-rails/shared
-
- mv /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads.old
- mkdir -p /var/opt/gitlab/gitlab-rails/uploads
-
- gitlab-ctl start postgresql
- gitlab-ctl start geo-postgresql
- ```
-
- Reconfigure to recreate the folders and make sure permissions and ownership
- are correct:
-
- ```shell
- gitlab-ctl reconfigure
- ```
-
-1. Reset the Tracking Database.
-
- WARNING:
- If you skipped the optional step 3, be sure both `geo-postgresql` and `postgresql` services are running.
-
- ```shell
- gitlab-rake db:drop:geo DISABLE_DATABASE_ENVIRONMENT_CHECK=1 # on a secondary app node
- gitlab-ctl reconfigure # on the tracking database node
- gitlab-rake db:migrate:geo # on a secondary app node
- ```
-
-1. Restart previously stopped services.
-
- ```shell
- gitlab-ctl start
- ```
-
-### Design repository failures on mirrored projects and project imports
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. On the left sidebar, select **Geo > Sites**.
-
-If the Design repositories progress bar shows
-`Synced` and `Failed` greater than 100%, and negative `Queued`, the instance
-is likely affected by
-[a bug in GitLab 13.2 and 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/241668).
-It was [fixed in GitLab 13.4 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40643).
-
-To determine the actual replication status of design repositories in
-a [Rails console](../../operations/rails_console.md):
-
-```ruby
-secondary = Gitlab::Geo.current_node
-counts = {}
-secondary.designs.select("projects.id").find_each do |p|
- registry = Geo::DesignRegistry.find_by(project_id: p.id)
- state = registry ? "#{registry.state}" : "registry does not exist yet"
- # puts "Design ID##{p.id}: #{state}" # uncomment this for granular information
- counts[state] ||= 0
- counts[state] += 1
-end
-puts "\nCounts:", counts
-```
-
-Example output:
-
-```plaintext
-Design ID#5: started
-Design ID#6: synced
-Design ID#7: failed
-Design ID#8: pending
-Design ID#9: synced
-
-Counts:
-{"started"=>1, "synced"=>2, "failed"=>1, "pending"=>1}
-```
-
-Example output if there are actually zero design repository replication failures:
-
-```plaintext
-Design ID#5: synced
-Design ID#6: synced
-Design ID#7: synced
-
-Counts:
-{"synced"=>3}
-```
-
-#### If you are promoting a Geo secondary site running on a single node
-
-`gitlab-ctl promotion-preflight-checks` fails due to the existence of
-`failed` rows in the `geo_design_registry` table. Use the
-[previous snippet](#design-repository-failures-on-mirrored-projects-and-project-imports) to
-determine the actual replication status of Design repositories.
-
-`gitlab-ctl promote-to-primary-node` fails since it runs preflight checks.
-If the [previous snippet](#design-repository-failures-on-mirrored-projects-and-project-imports)
-shows that all designs are synced, you can use the
-`--skip-preflight-checks` option or the `--force` option to move forward with
-promotion.
-
-#### If you are promoting a Geo secondary site running on multiple servers
-
-`gitlab-ctl promotion-preflight-checks` fails due to the existence of
-`failed` rows in the `geo_design_registry` table. Use the
-[previous snippet](#design-repository-failures-on-mirrored-projects-and-project-imports) to
-determine the actual replication status of Design repositories.
-
### Sync failure message: "Verification failed with: Error during verification: File is not checksummable"
#### Missing files on the Geo primary site
@@ -1020,272 +890,280 @@ We recommend transferring each failing repository individually and checking for
after each transfer. Follow the [single target `rsync` instructions](../../operations/moving_repositories.md#single-rsync-to-another-server)
to transfer each affected repository from the primary to the secondary site.
-## Fixing errors during a failover or when promoting a secondary to a primary site
-
-The following are possible error messages that might be encountered during failover or
-when promoting a secondary to a primary site with strategies to resolve them.
+### Project or project wiki repositories
-### Message: `ActiveRecord::RecordInvalid: Validation failed: Name has already been taken`
+#### Find repository verification failures
-When [promoting a **secondary** site](../disaster_recovery/index.md#step-3-promoting-a-secondary-site),
-you might encounter the following error message:
+[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+**on the secondary Geo site** to gather more information.
-```plaintext
-Running gitlab-rake geo:set_secondary_as_primary...
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-rake aborted!
-ActiveRecord::RecordInvalid: Validation failed: Name has already been taken
-/opt/gitlab/embedded/service/gitlab-rails/ee/lib/tasks/geo.rake:236:in `block (3 levels) in <top (required)>'
-/opt/gitlab/embedded/service/gitlab-rails/ee/lib/tasks/geo.rake:221:in `block (2 levels) in <top (required)>'
-/opt/gitlab/embedded/bin/bundle:23:in `load'
-/opt/gitlab/embedded/bin/bundle:23:in `<main>'
-Tasks: TOP => geo:set_secondary_as_primary
-(See full trace by running task with --trace)
+##### Get the number of verification failed repositories
-You successfully promoted this node!
+```ruby
+Geo::ProjectRegistry.verification_failed('repository').count
```
-If you encounter this message when running `gitlab-rake geo:set_secondary_as_primary`
-or `gitlab-ctl promote-to-primary-node`, either:
+##### Find the verification failed repositories
-- Enter a Rails console and run:
+```ruby
+Geo::ProjectRegistry.verification_failed('repository')
+```
- ```ruby
- Rails.application.load_tasks; nil
- Gitlab::Geo.expire_cache!
- Rake::Task['geo:set_secondary_as_primary'].invoke
- ```
+##### Find repositories that failed to sync
-- Upgrade to GitLab 12.6.3 or later if it is safe to do so. For example,
- if the failover was just a test. A
- [caching-related bug](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22021) was fixed.
+```ruby
+Geo::ProjectRegistry.sync_failed('repository')
+```
-### Message: `ActiveRecord::RecordInvalid: Validation failed: Enabled Geo primary node cannot be disabled`
+#### Resync project and project wiki repositories
-If you disabled a secondary site, either with the [replication pause task](../index.md#pausing-and-resuming-replication)
-(GitLab 13.2) or by using the user interface (GitLab 13.1 and earlier), you must first
-re-enable the site before you can continue. This is fixed in GitLab 13.4.
+[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+**on the secondary Geo site** to perform the following changes.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-This can be fixed in the database.
+##### Queue up all repositories for resync
-1. Start a database console:
+When you run this, the sync is handled in the background by Sidekiq.
- In [GitLab 14.2 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/341210):
+```ruby
+Geo::ProjectRegistry.update_all(resync_repository: true, resync_wiki: true)
+```
- ```shell
- sudo gitlab-rails dbconsole --database main
- ```
+##### Sync individual repository now
- In GitLab 14.1 and earlier:
+```ruby
+project = Project.find_by_full_path('<group/project>')
- ```shell
- sudo gitlab-rails dbconsole
- ```
+Geo::RepositorySyncService.new(project).execute
+```
-1. Run the following command, replacing `https://<secondary url>/` with the URL
- for your secondary node. You can use either `http` or `https`, but ensure that you
- end the URL with a slash (`/`):
+##### Sync all failed repositories now
- ```sql
- UPDATE geo_nodes SET enabled = true WHERE url = 'https://<secondary url>/' AND enabled = false;"
- ```
+The following script:
- This should update one row.
+- Loops over all currently failed repositories.
+- Displays the project details and the reasons for the last failure.
+- Attempts to resync the repository.
+- Reports back if a failure occurs, and why.
-### Message: ``NoMethodError: undefined method `secondary?' for nil:NilClass``
+```ruby
+Geo::ProjectRegistry.sync_failed('repository').find_each do |p|
+ begin
+ project = p.project
+ puts "#{project.full_path} | id: #{p.project_id} | last error: '#{p.last_repository_sync_failure}'"
+ Geo::RepositorySyncService.new(project).execute
+ rescue => e
+ puts "ID: #{p.project_id} failed: '#{e}'", e.backtrace.join("\n")
+ end
+end ; nil
+```
-When [promoting a **secondary** site](../disaster_recovery/index.md#step-3-promoting-a-secondary-site),
-you might encounter the following error message:
+### Find repository check failures in a Geo secondary site
-```plaintext
-sudo gitlab-rake geo:set_secondary_as_primary
+When [enabled for all projects](../../repository_checks.md#enable-repository-checks-for-all-projects), [Repository checks](../../repository_checks.md) are also performed on Geo secondary sites. The metadata is stored in the Geo tracking database.
-rake aborted!
-NoMethodError: undefined method `secondary?' for nil:NilClass
-/opt/gitlab/embedded/service/gitlab-rails/ee/lib/tasks/geo.rake:232:in `block (3 levels) in <top (required)>'
-/opt/gitlab/embedded/service/gitlab-rails/ee/lib/tasks/geo.rake:221:in `block (2 levels) in <top (required)>'
-/opt/gitlab/embedded/bin/bundle:23:in `load'
-/opt/gitlab/embedded/bin/bundle:23:in `<main>'
-Tasks: TOP => geo:set_secondary_as_primary
-(See full trace by running task with --trace)
-```
+Repository check failures on a Geo secondary site do not necessarily imply a replication problem. Here is a general approach to resolve these failures.
-This command is intended to be executed on a secondary site only, and this error message
-is displayed if you attempt to run this command on a primary site.
+1. Find affected repositories as mentioned below, as well as their [logged errors](../../repository_checks.md#what-to-do-if-a-check-failed).
+1. Try to diagnose specific `git fsck` errors. The range of possible errors is wide, try putting them into search engines.
+1. Test typical functions of the affected repositories. Pull from the secondary, view the files.
+1. Check if the primary site's copy of the repository has an identical `git fsck` error. If you are planning a failover, then consider prioritizing that the secondary site has the same information that the primary site has. Ensure you have a backup of the primary, and follow [planned failover guidelines](../disaster_recovery/planned_failover.md).
+1. Push to the primary and check if the change gets replicated to the secondary site.
+1. If replication is not automatically working, try to manually sync the repository.
-### Message: `sudo: gitlab-pg-ctl: command not found`
+[Start a Rails console session](../../operations/rails_console.md#starting-a-rails-console-session)
+to enact the following, basic troubleshooting steps.
-When
-[promoting a **secondary** site with multiple nodes](../disaster_recovery/index.md#promoting-a-secondary-site-with-multiple-nodes-running-gitlab-144-and-earlier),
-you need to run the `gitlab-pg-ctl` command to promote the PostgreSQL
-read-replica database.
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-In GitLab 12.8 and earlier, this command fails with the message:
+#### Get the number of repositories that failed the repository check
-```plaintext
-sudo: gitlab-pg-ctl: command not found
+```ruby
+Geo::ProjectRegistry.where(last_repository_check_failed: true).count
```
-In this case, the workaround is to use the full path to the binary, for example:
+#### Find the repositories that failed the repository check
-```shell
-sudo /opt/gitlab/embedded/bin/gitlab-pg-ctl promote
+```ruby
+Geo::ProjectRegistry.where(last_repository_check_failed: true)
```
-GitLab 12.9 and later are [unaffected by this error message](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5147).
+#### Recheck repositories that failed the repository check
-### Message: `ERROR - Replication is not up-to-date` during `gitlab-ctl promotion-preflight-checks`
+When you run this, `fsck` is executed against each failed repository.
-In GitLab 13.7 and earlier, if you have a data type with zero items to sync,
-this command reports `ERROR - Replication is not up-to-date` even if
-replication is actually up-to-date. This bug was fixed in GitLab 13.8 and
-later.
+The [`fsck` Rake command](../../raketasks/check.md#check-project-code-repositories) can be used on the secondary site to understand why the repository check might be failing.
-### Message: `ERROR - Replication is not up-to-date` during `gitlab-ctl promote-to-primary-node`
+```ruby
+Geo::ProjectRegistry.where(last_repository_check_failed: true).each do |pr|
+ RepositoryCheck::SingleRepositoryWorker.new.perform(pr.project_id)
+end
+```
-In GitLab 13.7 and earlier, if you have a data type with zero items to sync,
-this command reports `ERROR - Replication is not up-to-date` even if
-replication is actually up-to-date. If replication and verification output
-shows that it is complete, you can add `--skip-preflight-checks` to make the command complete promotion. This bug was fixed in GitLab 13.8 and later.
+## Fixing non-PostgreSQL replication failures
-### Errors when using `--skip-preflight-checks` or `--force`
+If you notice replication failures in `Admin > Geo > Sites` or the [Sync status Rake task](#sync-status-rake-task), you can try to resolve the failures with the following general steps:
-In GitLab 13.4 and earlier, you could receive one of the following error messages when using
-`--skip-preflight-checks` or `--force`:
+1. Geo automatically retries failures. If the failures are new and few in number, or if you suspect the root cause is already resolved, then you can wait to see if the failures go away.
+1. If failures were present for a long time, then many retries have already occurred, and the interval between automatic retries has increased to up to 4 hours depending on the type of failure. If you suspect the root cause is already resolved, you can [manually retry replication or verification](#manually-retry-replication-or-verification).
+1. If the failures persist, use the following sections to try to resolve them.
-```plaintext
-get_ctl_options': invalid option: --skip-preflight-checks (OptionParser::InvalidOption)
+### Manually retry replication or verification
-get_ctl_options': invalid option: --force (OptionParser::InvalidOption)
-```
+Project Git repositories and Project Wiki Git repositories have the ability in `Admin > Geo > Replication` to `Resync all`, `Reverify all`, or for a single resource, `Resync` or `Reverify`.
-This can happen with XFS or file systems that list files in lexical order, because the
-load order of the Linux package command files can be different than expected, and a global function would get redefined.
-More details can be found in [the related issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/6076).
+Adding this ability to other data types is proposed in issue [364725](https://gitlab.com/gitlab-org/gitlab/-/issues/364725).
-The workaround is to manually run the preflight checks and promote the database, by running
-the following commands on the Geo secondary site:
+The following sections describe how to use internal application commands in the [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session) to cause replication or verification immediately.
-```shell
-sudo gitlab-ctl promotion-preflight-checks
-sudo /opt/gitlab/embedded/bin/gitlab-pg-ctl promote
-sudo gitlab-ctl reconfigure
-sudo gitlab-rake geo:set_secondary_as_primary
-```
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-## Expired artifacts
+### Blob types
-If you notice for some reason there are more artifacts on the Geo
-**secondary** site than on the Geo **primary** site, you can use the Rake task
-to [cleanup orphan artifact files](../../../raketasks/cleanup.md#remove-orphan-artifact-files).
+- `Ci::JobArtifact`
+- `Ci::PipelineArtifact`
+- `Ci::SecureFile`
+- `LfsObject`
+- `MergeRequestDiff`
+- `Packages::PackageFile`
+- `PagesDeployment`
+- `Terraform::StateVersion`
+- `Upload`
-On a Geo **secondary** site, this command also cleans up all Geo
-registry record related to the orphan files on disk.
+`Packages::PackageFile` is used in the following
+[Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+examples, but things generally work the same for the other types.
-## Fixing sign in errors
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-### Message: The redirect URI included is not valid
+### Repository types, except for project or project wiki repositories
-If you are able to sign in to the web interface for the **primary** site, but you receive this error message
-when attempting to sign in to a **secondary** web interface, you should verify the Geo
-site's URL matches its external URL.
+- `SnippetRepository`
+- `GroupWikiRepository`
-On the **primary** site:
+`SnippetRepository` is used in the examples below, but things generally work the same for the other Repository types.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. On the left sidebar, select **Geo > Sites**.
-1. Find the affected **secondary** site and select **Edit**.
-1. Ensure the **URL** field matches the value found in `/etc/gitlab/gitlab.rb`
- in `external_url "https://gitlab.example.com"` on the **Rails nodes of the secondary** site.
+[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+to enact the following, basic troubleshooting steps.
-### Authenticating with SAML on the secondary site always lands on the primary site
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-This [problem is usually encountered when upgrading to GitLab 15.1](version_specific_upgrades.md#upgrading-to-151). To fix this problem, see [configuring instance-wide SAML in Geo with Single Sign-On](single_sign_on.md#configuring-instance-wide-saml).
+#### The Replicator
-## Fixing common errors
+The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it):
-This section documents common error messages reported in the Admin Area on the web interface, and how to fix them.
+```ruby
+model_record = Packages::PackageFile.last
+model_record.replicator.registry.replicator.model_record # just showing that these methods exist
+```
-### Geo database configuration file is missing
+#### Replicate a package file, synchronously, given an ID
-GitLab cannot find or doesn't have permission to access the `database_geo.yml` configuration file.
+```ruby
+model_record = Packages::PackageFile.find(id)
+model_record.replicator.send(:download)
+```
-In a Linux package installation, the file should be in `/var/opt/gitlab/gitlab-rails/etc`.
-If it doesn't exist or inadvertent changes have been made to it, run `sudo gitlab-ctl reconfigure` to restore it to its correct state.
+#### Replicate a package file, synchronously, given a registry ID
-If this path is mounted on a remote volume, ensure your volume configuration
-has the correct permissions.
+```ruby
+registry = Geo::PackageFileRegistry.find(registry_id)
+registry.replicator.send(:download)
+```
-### An existing tracking database cannot be reused
+#### Find registry records of blobs that failed to sync
-Geo cannot reuse an existing tracking database.
+```ruby
+Geo::PackageFileRegistry.failed
+```
-It is safest to use a fresh secondary, or reset the whole secondary by following
-[Resetting Geo secondary site replication](#resetting-geo-secondary-site-replication).
+#### Find registry records of blobs that are missing on the primary site
-### Geo site has a database that is writable which is an indication it is not configured for replication with the primary site
+```ruby
+Geo::PackageFileRegistry.where(last_sync_failure: 'The file is missing on the Geo primary site')
+```
-This error message refers to a problem with the database replica on a **secondary** site,
-which Geo expects to have access to. It usually means, either:
+#### Verify package files on the secondary manually
-- An unsupported replication method was used (for example, logical replication).
-- The instructions to set up a [Geo database replication](../setup/database.md) were not followed correctly.
-- Your database connection details are incorrect, that is you have specified the wrong
- user in your `/etc/gitlab/gitlab.rb` file.
+This iterates over all package files on the secondary, looking at the
+`verification_checksum` stored in the database (which came from the primary)
+and then calculate this value on the secondary to check if they match. This
+does not change anything in the UI.
-Geo **secondary** sites require two separate PostgreSQL instances:
+For GitLab 14.4 and later:
-- A read-only replica of the **primary** site.
-- A regular, writable instance that holds replication metadata. That is, the Geo tracking database.
+```ruby
+# Run on secondary
+status = {}
-This error message indicates that the replica database in the **secondary** site is misconfigured and replication has stopped.
+Packages::PackageFile.find_each do |package_file|
+ primary_checksum = package_file.verification_checksum
+ secondary_checksum = Packages::PackageFile.sha256_hexdigest(package_file.file.path)
+ verification_status = (primary_checksum == secondary_checksum)
-To restore the database and resume replication, you can do one of the following:
+ status[verification_status.to_s] ||= []
+ status[verification_status.to_s] << package_file.id
+end
-- [Reset the Geo secondary site replication](#resetting-geo-secondary-site-replication).
-- [Set up a new Geo secondary using the Linux package](../setup/index.md#using-linux-package-installations).
+# Count how many of each value we get
+status.keys.each {|key| puts "#{key} count: #{status[key].count}"}
-If you set up a new secondary from scratch, you must also [remove the old site from the Geo cluster](remove_geo_site.md#removing-secondary-geo-sites).
+# See the output in its entirety
+status
+```
-### Geo site does not appear to be replicating the database from the primary site
+For GitLab 14.3 and earlier:
-The most common problems that prevent the database from replicating correctly are:
+```ruby
+# Run on secondary
+status = {}
-- **Secondary** sites cannot reach the **primary** site. Check credentials and
- [firewall rules](../index.md#firewall-rules).
-- SSL certificate problems. Make sure you copied `/etc/gitlab/gitlab-secrets.json` from the **primary** site.
-- Database storage disk is full.
-- Database replication slot is misconfigured.
-- Database is not using a replication slot or another alternative and cannot catch-up because WAL files were purged.
+Packages::PackageFile.find_each do |package_file|
+ primary_checksum = package_file.verification_checksum
+ secondary_checksum = Packages::PackageFile.hexdigest(package_file.file.path)
+ verification_status = (primary_checksum == secondary_checksum)
-Make sure you follow the [Geo database replication](../setup/database.md) instructions for supported configuration.
+ status[verification_status.to_s] ||= []
+ status[verification_status.to_s] << package_file.id
+end
-### Geo database version (...) does not match latest migration (...)
+# Count how many of each value we get
+status.keys.each {|key| puts "#{key} count: #{status[key].count}"}
-If you are using the Linux package installation, something might have failed during upgrade. You can:
+# See the output in its entirety
+status
+```
-- Run `sudo gitlab-ctl reconfigure`.
-- Manually trigger the database migration by running: `sudo gitlab-rake db:migrate:geo` as root on the **secondary** site.
+#### Reverify all uploads (or any SSF data type which is verified)
-### GitLab indicates that more than 100% of repositories were synced
+1. SSH into a GitLab Rails node in the primary Geo site.
+1. Open [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session).
+1. Mark all uploads as "pending verification":
-This can be caused by orphaned records in the project registry. You can clear them
-[using the Rake task to remove orphaned project registries](../../../administration/raketasks/geo.md#remove-orphaned-project-registries).
+ ```ruby
+ Upload.verification_state_table_class.each_batch do |relation|
+ relation.update_all(verification_state: 0)
+ end
+ ```
-### Geo Admin Area returns 404 error for a secondary site
+1. This causes the primary to start checksumming all Uploads.
+1. When a primary successfully checksums a record, then all secondaries recalculate the checksum as well, and they compare the values.
-Sometimes `sudo gitlab-rake gitlab:geo:check` indicates that **Rails nodes of the secondary** sites are
-healthy, but a 404 Not Found error message for the **secondary** site is returned in the Geo Admin Area on the web interface for
-the **primary** site.
+For other SSF data types replace `Upload` in the command above with the desired model class.
-To resolve this issue:
+NOTE:
+There is an [issue to implement this functionality in the Admin Area UI](https://gitlab.com/gitlab-org/gitlab/-/issues/364729).
-- Try restarting **each Rails, Sidekiq and Gitaly nodes on your secondary site** using `sudo gitlab-ctl restart`.
-- Check `/var/log/gitlab/gitlab-rails/geo.log` on Sidekiq nodes to see if the **secondary** site is
- using IPv6 to send its status to the **primary** site. If it is, add an entry to
- the **primary** site using IPv4 in the `/etc/hosts` file. Alternatively, you should
- [enable IPv6 on the **primary** site](https://docs.gitlab.com/omnibus/settings/nginx.html#setting-the-nginx-listen-address-or-addresses).
+## HTTP response code errors
### Secondary site returns 502 errors with Geo proxying
@@ -1311,14 +1189,6 @@ and changing the `8k` size, for example by doubling it to `16k`.
If using a load balancer, ensure that the load balancer's URL is set as the `external_url` in the
`/etc/gitlab/gitlab.rb` of the nodes behind the load balancer.
-### Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode
-
-In GitLab 13.9 through GitLab 14.3, when [GitLab Maintenance Mode](../../maintenance_mode/index.md) is enabled, the status of Geo secondary sites stops getting updated. After 10 minutes, the status changes to `Unhealthy`.
-
-Geo secondary sites continue to replicate and verify data, and the secondary sites should still be usable. You can use the [Sync status Rake task](#sync-status-rake-task) to determine the actual status of a secondary site during Maintenance Mode.
-
-This bug was [fixed in GitLab 14.4](https://gitlab.com/gitlab-org/gitlab/-/issues/292983).
-
### Primary site returns 500 error when accessing `/admin/geo/replication/projects`
Navigating to **Admin > Geo > Replication** (or `/admin/geo/replication/projects`) on a primary Geo site, shows a 500 error, while that same link on the secondary works fine. The primary's `production.log` has a similar entry to the following:
@@ -1379,340 +1249,219 @@ The bug causes all wildcard domains (`.example.com`) to be ignored except for th
You can have only one wildcard domain in the `no_proxy` list.
-### Secondary site shows "Unhealthy" in UI after changing the value of `external_url` for the primary site
-
-If you have updated the value of `external_url` in `/etc/gitlab/gitlab.rb` for the primary site or changed the protocol from `http` to `https`, you may see that secondary sites are shown as `Unhealthy`. You may also find the following error in `geo.log`:
-
-```plaintext
-"class": "Geo::NodeStatusRequestService",
-...
-"message": "Failed to Net::HTTP::Post to primary url: http://primary-site.gitlab.tld/api/v4/geo/status",
- "error": "Failed to open TCP connection to <PRIMARY_IP_ADDRESS>:80 (Connection refused - connect(2) for \"<PRIMARY_ID_ADDRESS>\" port 80)"
-```
-
-In this case, make sure to update the changed URL on all your sites:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. On the left sidebar, select **Geo > Sites**.
-1. Change the URL and save the change.
-
-### Message: `ERROR: canceling statement due to conflict with recovery` during backup
-
-Running a backup on a Geo **secondary** [is not supported](https://gitlab.com/gitlab-org/gitlab/-/issues/211668).
-
-When running a backup on a **secondary** you might encounter the following error message:
-
-```plaintext
-Dumping PostgreSQL database gitlabhq_production ...
-pg_dump: error: Dumping the contents of table "notes" failed: PQgetResult() failed.
-pg_dump: error: Error message from server: ERROR: canceling statement due to conflict with recovery
-DETAIL: User query might have needed to see row versions that must be removed.
-pg_dump: error: The command was: COPY public.notes (id, note, [...], last_edited_at) TO stdout;
-```
-
-To prevent a database backup being made automatically during GitLab upgrades on your Geo **secondaries**,
-create the following empty file:
-
-```shell
-sudo touch /etc/gitlab/skip-auto-backup
-```
-
-## Fixing non-PostgreSQL replication failures
-
-If you notice replication failures in `Admin > Geo > Sites` or the [Sync status Rake task](#sync-status-rake-task), you can try to resolve the failures with the following general steps:
-
-1. Geo automatically retries failures. If the failures are new and few in number, or if you suspect the root cause is already resolved, then you can wait to see if the failures go away.
-1. If failures were present for a long time, then many retries have already occurred, and the interval between automatic retries has increased to up to 4 hours depending on the type of failure. If you suspect the root cause is already resolved, you can [manually retry replication or verification](#manually-retry-replication-or-verification).
-1. If the failures persist, use the following sections to try to resolve them.
-
-### Manually retry replication or verification
+### Geo Admin Area returns 404 error for a secondary site
-Project Git repositories and Project Wiki Git repositories have the ability in `Admin > Geo > Replication` to `Resync all`, `Reverify all`, or for a single resource, `Resync` or `Reverify`.
+Sometimes `sudo gitlab-rake gitlab:geo:check` indicates that **Rails nodes of the secondary** sites are
+healthy, but a 404 Not Found error message for the **secondary** site is returned in the Geo Admin Area on the web interface for
+the **primary** site.
-Adding this ability to other data types is proposed in issue [364725](https://gitlab.com/gitlab-org/gitlab/-/issues/364725).
+To resolve this issue:
-The following sections describe how to use internal application commands in the [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session) to cause replication or verification immediately.
+- Try restarting **each Rails, Sidekiq and Gitaly nodes on your secondary site** using `sudo gitlab-ctl restart`.
+- Check `/var/log/gitlab/gitlab-rails/geo.log` on Sidekiq nodes to see if the **secondary** site is
+ using IPv6 to send its status to the **primary** site. If it is, add an entry to
+ the **primary** site using IPv4 in the `/etc/hosts` file. Alternatively, you should
+ [enable IPv6 on the **primary** site](https://docs.gitlab.com/omnibus/settings/nginx.html#setting-the-nginx-listen-address-or-addresses).
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+## Fixing common errors
-### Blob types
+This section documents common error messages reported in the Admin Area on the web interface, and how to fix them.
-- `Ci::JobArtifact`
-- `Ci::PipelineArtifact`
-- `Ci::SecureFile`
-- `LfsObject`
-- `MergeRequestDiff`
-- `Packages::PackageFile`
-- `PagesDeployment`
-- `Terraform::StateVersion`
-- `Upload`
+### Geo database configuration file is missing
-`Packages::PackageFile` is used in the following
-[Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-examples, but things generally work the same for the other types.
+GitLab cannot find or doesn't have permission to access the `database_geo.yml` configuration file.
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+In a Linux package installation, the file should be in `/var/opt/gitlab/gitlab-rails/etc`.
+If it doesn't exist or inadvertent changes have been made to it, run `sudo gitlab-ctl reconfigure` to restore it to its correct state.
-#### The Replicator
+If this path is mounted on a remote volume, ensure your volume configuration
+has the correct permissions.
-The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it):
+### An existing tracking database cannot be reused
-```ruby
-model_record = Packages::PackageFile.last
-model_record.replicator.registry.replicator.model_record # just showing that these methods exist
-```
+Geo cannot reuse an existing tracking database.
-#### Replicate a package file, synchronously, given an ID
+It is safest to use a fresh secondary, or reset the whole secondary by following
+[Resetting Geo secondary site replication](#resetting-geo-secondary-site-replication).
-```ruby
-model_record = Packages::PackageFile.find(id)
-model_record.replicator.send(:download)
-```
+### Geo site has a database that is writable which is an indication it is not configured for replication with the primary site
-#### Replicate a package file, synchronously, given a registry ID
+This error message refers to a problem with the database replica on a **secondary** site,
+which Geo expects to have access to. It usually means, either:
-```ruby
-registry = Geo::PackageFileRegistry.find(registry_id)
-registry.replicator.send(:download)
-```
+- An unsupported replication method was used (for example, logical replication).
+- The instructions to set up a [Geo database replication](../setup/database.md) were not followed correctly.
+- Your database connection details are incorrect, that is you have specified the wrong
+ user in your `/etc/gitlab/gitlab.rb` file.
-#### Find registry records of blobs that failed to sync
+Geo **secondary** sites require two separate PostgreSQL instances:
-```ruby
-Geo::PackageFileRegistry.failed
-```
+- A read-only replica of the **primary** site.
+- A regular, writable instance that holds replication metadata. That is, the Geo tracking database.
-#### Find registry records of blobs that are missing on the primary site
+This error message indicates that the replica database in the **secondary** site is misconfigured and replication has stopped.
-```ruby
-Geo::PackageFileRegistry.where(last_sync_failure: 'The file is missing on the Geo primary site')
-```
+To restore the database and resume replication, you can do one of the following:
-#### Verify package files on the secondary manually
+- [Reset the Geo secondary site replication](#resetting-geo-secondary-site-replication).
+- [Set up a new Geo secondary using the Linux package](../setup/index.md#using-linux-package-installations).
-This iterates over all package files on the secondary, looking at the
-`verification_checksum` stored in the database (which came from the primary)
-and then calculate this value on the secondary to check if they match. This
-does not change anything in the UI.
+If you set up a new secondary from scratch, you must also [remove the old site from the Geo cluster](remove_geo_site.md#removing-secondary-geo-sites).
-For GitLab 14.4 and later:
+### Geo site does not appear to be replicating the database from the primary site
-```ruby
-# Run on secondary
-status = {}
+The most common problems that prevent the database from replicating correctly are:
-Packages::PackageFile.find_each do |package_file|
- primary_checksum = package_file.verification_checksum
- secondary_checksum = Packages::PackageFile.sha256_hexdigest(package_file.file.path)
- verification_status = (primary_checksum == secondary_checksum)
+- **Secondary** sites cannot reach the **primary** site. Check credentials and
+ [firewall rules](../index.md#firewall-rules).
+- SSL certificate problems. Make sure you copied `/etc/gitlab/gitlab-secrets.json` from the **primary** site.
+- Database storage disk is full.
+- Database replication slot is misconfigured.
+- Database is not using a replication slot or another alternative and cannot catch-up because WAL files were purged.
- status[verification_status.to_s] ||= []
- status[verification_status.to_s] << package_file.id
-end
+Make sure you follow the [Geo database replication](../setup/database.md) instructions for supported configuration.
-# Count how many of each value we get
-status.keys.each {|key| puts "#{key} count: #{status[key].count}"}
+### Geo database version (...) does not match latest migration (...)
-# See the output in its entirety
-status
-```
+If you are using the Linux package installation, something might have failed during upgrade. You can:
-For GitLab 14.3 and earlier:
+- Run `sudo gitlab-ctl reconfigure`.
+- Manually trigger the database migration by running: `sudo gitlab-rake db:migrate:geo` as root on the **secondary** site.
-```ruby
-# Run on secondary
-status = {}
+### GitLab indicates that more than 100% of repositories were synced
-Packages::PackageFile.find_each do |package_file|
- primary_checksum = package_file.verification_checksum
- secondary_checksum = Packages::PackageFile.hexdigest(package_file.file.path)
- verification_status = (primary_checksum == secondary_checksum)
+This can be caused by orphaned records in the project registry. You can clear them
+[using the Rake task to remove orphaned project registries](../../../administration/raketasks/geo.md#remove-orphaned-project-registries).
- status[verification_status.to_s] ||= []
- status[verification_status.to_s] << package_file.id
-end
+### Secondary site shows "Unhealthy" in UI after changing the value of `external_url` for the primary site
-# Count how many of each value we get
-status.keys.each {|key| puts "#{key} count: #{status[key].count}"}
+If you have updated the value of `external_url` in `/etc/gitlab/gitlab.rb` for the primary site or changed the protocol from `http` to `https`, you may see that secondary sites are shown as `Unhealthy`. You may also find the following error in `geo.log`:
-# See the output in its entirety
-status
+```plaintext
+"class": "Geo::NodeStatusRequestService",
+...
+"message": "Failed to Net::HTTP::Post to primary url: http://primary-site.gitlab.tld/api/v4/geo/status",
+ "error": "Failed to open TCP connection to <PRIMARY_IP_ADDRESS>:80 (Connection refused - connect(2) for \"<PRIMARY_ID_ADDRESS>\" port 80)"
```
-#### Reverify all uploads (or any SSF data type which is verified)
-
-1. SSH into a GitLab Rails node in the primary Geo site.
-1. Open [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session).
-1. Mark all uploads as "pending verification":
-
- ```ruby
- Upload.verification_state_table_class.each_batch do |relation|
- relation.update_all(verification_state: 0)
- end
- ```
-
-1. This causes the primary to start checksumming all Uploads.
-1. When a primary successfully checksums a record, then all secondaries recalculate the checksum as well, and they compare the values.
-
-For other SSF data types replace `Upload` in the command above with the desired model class.
-
-NOTE:
-There is an [issue to implement this functionality in the Admin Area UI](https://gitlab.com/gitlab-org/gitlab/-/issues/364729).
-
-### Repository types, except for project or project wiki repositories
-
-- `SnippetRepository`
-- `GroupWikiRepository`
-
-`SnippetRepository` is used in the examples below, but things generally work the same for the other Repository types.
-
-[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-to enact the following, basic troubleshooting steps.
-
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+In this case, make sure to update the changed URL on all your sites:
-#### The Replicator
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. On the left sidebar, select **Geo > Sites**.
+1. Change the URL and save the change.
-The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it).
+### Message: `ERROR: canceling statement due to conflict with recovery` during backup
-```ruby
-model_record = SnippetRepository.last
-model_record.replicator.registry.replicator.model_record # just showing that these methods exist
-```
+Running a backup on a Geo **secondary** [is not supported](https://gitlab.com/gitlab-org/gitlab/-/issues/211668).
-#### Replicate a snippet repository, synchronously, given an ID
+When running a backup on a **secondary** you might encounter the following error message:
-```ruby
-model_record = SnippetRepository.find(id)
-model_record.replicator.send(:sync_repository)
+```plaintext
+Dumping PostgreSQL database gitlabhq_production ...
+pg_dump: error: Dumping the contents of table "notes" failed: PQgetResult() failed.
+pg_dump: error: Error message from server: ERROR: canceling statement due to conflict with recovery
+DETAIL: User query might have needed to see row versions that must be removed.
+pg_dump: error: The command was: COPY public.notes (id, note, [...], last_edited_at) TO stdout;
```
-#### Replicate a snippet repository, synchronously, given a registry ID
+To prevent a database backup being made automatically during GitLab upgrades on your Geo **secondaries**,
+create the following empty file:
-```ruby
-registry = Geo::SnippetRepositoryRegistry.find(registry_id)
-registry.replicator.send(:sync_repository)
+```shell
+sudo touch /etc/gitlab/skip-auto-backup
```
-### Project or project wiki repositories
-
-#### Find repository verification failures
-
-[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-**on the secondary Geo site** to gather more information.
-
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+## Fixing errors during a failover or when promoting a secondary to a primary site
-##### Get the number of verification failed repositories
+The following are possible error messages that might be encountered during failover or
+when promoting a secondary to a primary site with strategies to resolve them.
-```ruby
-Geo::ProjectRegistry.verification_failed('repository').count
-```
+### Message: `ActiveRecord::RecordInvalid: Validation failed: Name has already been taken`
-##### Find the verification failed repositories
+When [promoting a **secondary** site](../disaster_recovery/index.md#step-3-promoting-a-secondary-site),
+you might encounter the following error message:
-```ruby
-Geo::ProjectRegistry.verification_failed('repository')
-```
+```plaintext
+Running gitlab-rake geo:set_secondary_as_primary...
-##### Find repositories that failed to sync
+rake aborted!
+ActiveRecord::RecordInvalid: Validation failed: Name has already been taken
+/opt/gitlab/embedded/service/gitlab-rails/ee/lib/tasks/geo.rake:236:in `block (3 levels) in <top (required)>'
+/opt/gitlab/embedded/service/gitlab-rails/ee/lib/tasks/geo.rake:221:in `block (2 levels) in <top (required)>'
+/opt/gitlab/embedded/bin/bundle:23:in `load'
+/opt/gitlab/embedded/bin/bundle:23:in `<main>'
+Tasks: TOP => geo:set_secondary_as_primary
+(See full trace by running task with --trace)
-```ruby
-Geo::ProjectRegistry.sync_failed('repository')
+You successfully promoted this node!
```
-#### Resync project and project wiki repositories
-
-[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-**on the secondary Geo site** to perform the following changes.
-
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-
-##### Queue up all repositories for resync
-
-When you run this, the sync is handled in the background by Sidekiq.
-
-```ruby
-Geo::ProjectRegistry.update_all(resync_repository: true, resync_wiki: true)
-```
+If you encounter this message when running `gitlab-rake geo:set_secondary_as_primary`
+or `gitlab-ctl promote-to-primary-node`, either:
-##### Sync individual repository now
+- Enter a Rails console and run:
-```ruby
-project = Project.find_by_full_path('<group/project>')
+ ```ruby
+ Rails.application.load_tasks; nil
+ Gitlab::Geo.expire_cache!
+ Rake::Task['geo:set_secondary_as_primary'].invoke
+ ```
-Geo::RepositorySyncService.new(project).execute
-```
+- Upgrade to GitLab 12.6.3 or later if it is safe to do so. For example,
+ if the failover was just a test. A
+ [caching-related bug](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22021) was fixed.
-##### Sync all failed repositories now
+### Message: ``NoMethodError: undefined method `secondary?' for nil:NilClass``
-The following script:
+When [promoting a **secondary** site](../disaster_recovery/index.md#step-3-promoting-a-secondary-site),
+you might encounter the following error message:
-- Loops over all currently failed repositories.
-- Displays the project details and the reasons for the last failure.
-- Attempts to resync the repository.
-- Reports back if a failure occurs, and why.
+```plaintext
+sudo gitlab-rake geo:set_secondary_as_primary
-```ruby
-Geo::ProjectRegistry.sync_failed('repository').find_each do |p|
- begin
- project = p.project
- puts "#{project.full_path} | id: #{p.project_id} | last error: '#{p.last_repository_sync_failure}'"
- Geo::RepositorySyncService.new(project).execute
- rescue => e
- puts "ID: #{p.project_id} failed: '#{e}'", e.backtrace.join("\n")
- end
-end ; nil
+rake aborted!
+NoMethodError: undefined method `secondary?' for nil:NilClass
+/opt/gitlab/embedded/service/gitlab-rails/ee/lib/tasks/geo.rake:232:in `block (3 levels) in <top (required)>'
+/opt/gitlab/embedded/service/gitlab-rails/ee/lib/tasks/geo.rake:221:in `block (2 levels) in <top (required)>'
+/opt/gitlab/embedded/bin/bundle:23:in `load'
+/opt/gitlab/embedded/bin/bundle:23:in `<main>'
+Tasks: TOP => geo:set_secondary_as_primary
+(See full trace by running task with --trace)
```
-#### Find repository check failures in a Geo secondary site
-
-When [enabled for all projects](../../repository_checks.md#enable-repository-checks-for-all-projects), [Repository checks](../../repository_checks.md) are also performed on Geo secondary sites. The metadata is stored in the Geo tracking database.
-
-Repository check failures on a Geo secondary site do not necessarily imply a replication problem. Here is a general approach to resolve these failures.
-
-1. Find affected repositories as mentioned below, as well as their [logged errors](../../repository_checks.md#what-to-do-if-a-check-failed).
-1. Try to diagnose specific `git fsck` errors. The range of possible errors is wide, try putting them into search engines.
-1. Test typical functions of the affected repositories. Pull from the secondary, view the files.
-1. Check if the primary site's copy of the repository has an identical `git fsck` error. If you are planning a failover, then consider prioritizing that the secondary site has the same information that the primary site has. Ensure you have a backup of the primary, and follow [planned failover guidelines](../disaster_recovery/planned_failover.md).
-1. Push to the primary and check if the change gets replicated to the secondary site.
-1. If replication is not automatically working, try to manually sync the repository.
+This command is intended to be executed on a secondary site only, and this error message
+is displayed if you attempt to run this command on a primary site.
-[Start a Rails console session](../../operations/rails_console.md#starting-a-rails-console-session)
-to enact the following, basic troubleshooting steps.
+### Expired artifacts
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+If you notice for some reason there are more artifacts on the Geo
+**secondary** site than on the Geo **primary** site, you can use the Rake task
+to [cleanup orphan artifact files](../../../raketasks/cleanup.md#remove-orphan-artifact-files).
-##### Get the number of repositories that failed the repository check
+On a Geo **secondary** site, this command also cleans up all Geo
+registry record related to the orphan files on disk.
-```ruby
-Geo::ProjectRegistry.where(last_repository_check_failed: true).count
-```
+### Fixing sign in errors
-##### Find the repositories that failed the repository check
+#### Message: The redirect URI included is not valid
-```ruby
-Geo::ProjectRegistry.where(last_repository_check_failed: true)
-```
+If you are able to sign in to the web interface for the **primary** site, but you receive this error message
+when attempting to sign in to a **secondary** web interface, you should verify the Geo
+site's URL matches its external URL.
-##### Recheck repositories that failed the repository check
+On the **primary** site:
-When you run this, `fsck` is executed against each failed repository.
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. On the left sidebar, select **Geo > Sites**.
+1. Find the affected **secondary** site and select **Edit**.
+1. Ensure the **URL** field matches the value found in `/etc/gitlab/gitlab.rb`
+ in `external_url "https://gitlab.example.com"` on the **Rails nodes of the secondary** site.
-The [`fsck` Rake command](../../raketasks/check.md#check-project-code-repositories) can be used on the secondary site to understand why the repository check might be failing.
+#### Authenticating with SAML on the secondary site always lands on the primary site
-```ruby
-Geo::ProjectRegistry.where(last_repository_check_failed: true).each do |pr|
- RepositoryCheck::SingleRepositoryWorker.new.perform(pr.project_id)
-end
-```
+This [problem is usually encountered when upgrading to GitLab 15.1](../../../update/versions/gitlab_15_changes.md#1510). To fix this problem, see [configuring instance-wide SAML in Geo with Single Sign-On](single_sign_on.md#configuring-instance-wide-saml).
## Fixing client errors
@@ -1784,43 +1533,6 @@ If the above steps are **not successful**, proceed through the next steps:
1. Verify you can connect to the newly-promoted **primary** site using the URL used previously for the **secondary** site.
1. If successful, the **secondary** site is now promoted to the **primary** site.
-## Check OS locale data compatibility
-
-If different operating systems or different operating system versions are deployed across Geo sites, you should perform a locale data compatibility check before setting up Geo.
-
-Geo uses PostgreSQL and Streaming Replication to replicate data across Geo sites. PostgreSQL uses locale data provided by the operating system's C library for sorting text. If the locale data in the C library is incompatible across Geo sites, it can cause erroneous query results that lead to [incorrect behavior on secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/360723).
-
-For example, Ubuntu 18.04 (and earlier) and RHEL/Centos7 (and earlier) are incompatible with their later releases.
-See the [PostgreSQL wiki for more details](https://wiki.postgresql.org/wiki/Locale_data_changes).
-
-On all hosts running PostgreSQL, across all Geo sites, run the following shell command:
-
-```shell
-( echo "1-1"; echo "11" ) | LC_COLLATE=en_US.UTF-8 sort
-```
-
-The output looks like either:
-
-```plaintext
-1-1
-11
-```
-
-or the reverse order:
-
-```plaintext
-11
-1-1
-```
-
-If the output is identical on all hosts, then they running compatible versions of locale data.
-
-If the output differs on some hosts, PostgreSQL replication does not work properly: indexes are corrupted on the database replicas. You should select operating system versions that are compatible.
-
-A full index rebuild is required if the on-disk data is transferred 'at rest' to an operating system with an incompatible locale, or through replication.
-
-This check is also required when using a mixture of GitLab deployments. The locale might be different between an Linux package install, a GitLab Docker container, a Helm chart deployment, or external database services.
-
## Investigate causes of database replication lag
If the output of `sudo gitlab-rake geo:status` shows that `Database replication lag` remains significantly high over time, the primary node in database replication can be checked to determine the status of lag for
@@ -1847,3 +1559,94 @@ If one or more of these values is significantly high, this could indicate a prob
- The difference in time between `write_lag` and `flush_lag` indicates that WAL bytes have been sent to the underlying storage system, but it has not reported that they were flushed.
This data is most likely not fully written to a persistent storage, and likely held in some kind of volatile write cache.
- The difference between `flush_lag` and `replay_lag` indicates WAL bytes that have been successfully persisted to storage, but could not be replayed by the database system.
+
+## Resetting Geo **secondary** site replication
+
+If you get a **secondary** site in a broken state and want to reset the replication state,
+to start again from scratch, there are a few steps that can help you:
+
+1. Stop Sidekiq and the Geo LogCursor.
+
+ It's possible to make Sidekiq stop gracefully, but making it stop getting new jobs and
+ wait until the current jobs to finish processing.
+
+ You need to send a **SIGTSTP** kill signal for the first phase and them a **SIGTERM**
+ when all jobs have finished. Otherwise just use the `gitlab-ctl stop` commands.
+
+ ```shell
+ gitlab-ctl status sidekiq
+ # run: sidekiq: (pid 10180) <- this is the PID you will use
+ kill -TSTP 10180 # change to the correct PID
+
+ gitlab-ctl stop sidekiq
+ gitlab-ctl stop geo-logcursor
+ ```
+
+ You can watch the [Sidekiq logs](../../logs/index.md#sidekiq-logs) to know when Sidekiq jobs processing has finished:
+
+ ```shell
+ gitlab-ctl tail sidekiq
+ ```
+
+1. Rename repository storage folders and create new ones. If you are not concerned about possible orphaned directories and files, you can skip this step.
+
+ ```shell
+ mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
+ mkdir -p /var/opt/gitlab/git-data/repositories
+ chown git:git /var/opt/gitlab/git-data/repositories
+ ```
+
+ NOTE:
+ You may want to remove the `/var/opt/gitlab/git-data/repositories.old` in the future
+ as soon as you confirmed that you don't need it anymore, to save disk space.
+
+1. Optional. Rename other data folders and create new ones.
+
+ WARNING:
+ You may still have files on the **secondary** site that have been removed from the **primary** site, but this
+ removal has not been reflected. If you skip this step, these files are not removed from the Geo **secondary** site.
+
+ Any uploaded content (like file attachments, avatars, or LFS objects) is stored in a
+ subfolder in one of these paths:
+
+ - `/var/opt/gitlab/gitlab-rails/shared`
+ - `/var/opt/gitlab/gitlab-rails/uploads`
+
+ To rename all of them:
+
+ ```shell
+ gitlab-ctl stop
+
+ mv /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared.old
+ mkdir -p /var/opt/gitlab/gitlab-rails/shared
+
+ mv /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads.old
+ mkdir -p /var/opt/gitlab/gitlab-rails/uploads
+
+ gitlab-ctl start postgresql
+ gitlab-ctl start geo-postgresql
+ ```
+
+ Reconfigure to recreate the folders and make sure permissions and ownership
+ are correct:
+
+ ```shell
+ gitlab-ctl reconfigure
+ ```
+
+1. Reset the Tracking Database.
+
+ WARNING:
+ If you skipped the optional step 3, be sure both `geo-postgresql` and `postgresql` services are running.
+
+ ```shell
+ gitlab-rake db:drop:geo DISABLE_DATABASE_ENVIRONMENT_CHECK=1 # on a secondary app node
+ gitlab-ctl reconfigure # on the tracking database node
+ gitlab-rake db:migrate:geo # on a secondary app node
+ ```
+
+1. Restart previously stopped services.
+
+ ```shell
+ gitlab-ctl start
+ ```
diff --git a/doc/administration/geo/replication/tuning.md b/doc/administration/geo/replication/tuning.md
index 9e1638643cb..3a4366cfd63 100644
--- a/doc/administration/geo/replication/tuning.md
+++ b/doc/administration/geo/replication/tuning.md
@@ -14,7 +14,7 @@ in the background.
On the **primary** site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Geo > Sites**.
1. Select **Edit** of the secondary site you want to tune.
diff --git a/doc/administration/geo/replication/version_specific_upgrades.md b/doc/administration/geo/replication/version_specific_upgrades.md
index 7e3160822b9..13d00ced3cd 100644
--- a/doc/administration/geo/replication/version_specific_upgrades.md
+++ b/doc/administration/geo/replication/version_specific_upgrades.md
@@ -1,106 +1,11 @@
---
-stage: Systems
-group: Geo
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+redirect_to: '../../../update/index.md#version-specific-upgrading-instructions'
+remove_date: '2023-12-01'
---
-# Version-specific upgrade instructions **(PREMIUM SELF)**
+This document was moved to [another location](../../../update/index.md#version-specific-upgrading-instructions).
-NOTE:
-We're in the process of merging all the version-specific upgrade information
-into a single page. For more information,
-see [epic 9581](https://gitlab.com/groups/gitlab-org/-/epics/9581).
-For the latest Geo version-specific upgrade instructions,
-see the [general upgrade page](../../../update/index.md).
-
-Review this page for upgrade instructions for your version. These steps
-accompany the [general steps](upgrading_the_geo_sites.md#general-upgrade-steps)
-for upgrading Geo sites.
-
-## Upgrading to 15.1
-
-[Geo proxying](../secondary_proxy/index.md) was [enabled by default for different URLs](https://gitlab.com/gitlab-org/gitlab/-/issues/346112) in 15.1. This may be a breaking change. If needed, you may [disable Geo proxying](../secondary_proxy/index.md#disable-geo-proxying).
-
-If you are using SAML with different URLs, you must modify your SAML configuration and your Identity Provider configuration. For more information, see the [Geo with Single Sign-On (SSO) documentation](single_sign_on.md).
-
-## Upgrading to 14.9
-
-**Do not** upgrade to GitLab 14.9.0. Instead, use 14.9.1 or later.
-
-We've discovered an issue with Geo's CI verification feature that may [cause job traces to be lost](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/6664). This issue was fixed in [the GitLab 14.9.1 patch release](https://about.gitlab.com/releases/2022/03/23/gitlab-14-9-1-released/).
-
-If you have already upgraded to GitLab 14.9.0, you can disable the feature causing the issue by [disabling the `geo_job_artifact_replication` feature flag](../../feature_flags.md#how-to-enable-and-disable-features-behind-flags).
-
-## Upgrading to 14.2 through 14.7
-
-There is [an issue in GitLab 14.2 through 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/299819#note_822629467)
-that affects Geo when the GitLab-managed object storage replication is used, causing blob object types to fail synchronization.
-
-Since GitLab 14.2, verification failures result in synchronization failures and cause
-a resynchronization of these objects.
-
-As verification is not yet implemented for files stored in object storage (see
-[issue 13845](https://gitlab.com/gitlab-org/gitlab/-/issues/13845) for more details), this
-results in a loop that consistently fails for all objects stored in object storage.
-
-For information on how to fix this, see
-[Troubleshooting - Failed syncs with GitLab-managed object storage replication](troubleshooting.md#failed-syncs-with-gitlab-managed-object-storage-replication).
-
-## Upgrading to 14.4
-
-There is [an issue in GitLab 14.4.0 through 14.4.2](../../../update/index.md#1440) that can affect Geo and other features that rely on cronjobs. We recommend upgrading to GitLab 14.4.3 or later.
-
-## Upgrading to 14.1, 14.2, 14.3
-
-### Multi-arch images
-
-We found an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/336013) where the Container Registry replication wasn't fully working if you used multi-arch images. In case of a multi-arch image, only the primary architecture (for example `amd64`) would be replicated to the secondary site. This has been [fixed in GitLab 14.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67624) and was backported to 14.2 and 14.1, but manual steps are required to force a re-sync.
-
-You can check if you are affected by running:
-
-```shell
-docker manifest inspect <SECONDARY_IMAGE_LOCATION> | jq '.mediaType'
-```
-
-Where `<SECONDARY_IMAGE_LOCATION>` is a container image on your secondary site.
-If the output matches `application/vnd.docker.distribution.manifest.list.v2+json`
-(there can be a `mediaType` entry at several levels, we only care about the top level entry),
-then you don't need to do anything.
-
-Otherwise, for each **secondary** site, on a Rails application node, open a [Rails console](../../operations/rails_console.md), and run the following:
-
- ```ruby
- list_type = 'application/vnd.docker.distribution.manifest.list.v2+json'
-
- Geo::ContainerRepositoryRegistry.synced.each do |gcr|
- cr = gcr.container_repository
- primary = Geo::ContainerRepositorySync.new(cr)
- cr.tags.each do |tag|
- primary_manifest = JSON.parse(primary.send(:client).repository_raw_manifest(cr.path, tag.name))
- next unless primary_manifest['mediaType'].eql?(list_type)
-
- cr.delete_tag_by_name(tag.name)
- end
- primary.execute
- end
- ```
-
-If you are running a version prior to 14.1 and are using Geo and multi-arch containers in your Container Registry, we recommend [upgrading](upgrading_the_geo_sites.md) to at least GitLab 14.1.
-
-### Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode
-
-GitLab 13.9 through GitLab 14.3 are affected by a bug in which enabling [GitLab Maintenance Mode](../../maintenance_mode/index.md) causes Geo secondary site statuses to appear to stop upgrading and become unhealthy. For more information, see [Troubleshooting - Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode](troubleshooting.md#geo-admin-area-shows-unhealthy-after-enabling-maintenance-mode).
-
-## Upgrading to GitLab 14.0/14.1
-
-### Primary sites cannot be removed from the UI
-
-We found an issue where [Primary sites cannot be removed from the UI](https://gitlab.com/gitlab-org/gitlab/-/issues/338231).
-
-This bug only exists in the UI and does not block the removal of Primary sites using any other method.
-
-If you are running an affected version and need to remove your Primary site, you can manually remove the Primary site by using the [Geo Sites API](../../../api/geo_nodes.md#delete-a-geo-node).
-
-### Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode
-
-GitLab 13.9 through GitLab 14.3 are affected by a bug in which enabling [GitLab Maintenance Mode](../../maintenance_mode/index.md) causes Geo secondary site statuses to appear to stop upgrading and become unhealthy. For more information, see [Troubleshooting - Geo Admin Area shows 'Unhealthy' after enabling Maintenance Mode](troubleshooting.md#geo-admin-area-shows-unhealthy-after-enabling-maintenance-mode).
+<!-- This redirect file can be deleted after <2023-12-01>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/administration/geo/secondary_proxy/index.md b/doc/administration/geo/secondary_proxy/index.md
index 11e5cb1b7b8..f6572ded4a9 100644
--- a/doc/administration/geo/secondary_proxy/index.md
+++ b/doc/administration/geo/secondary_proxy/index.md
@@ -71,7 +71,7 @@ a single URL used by all Geo sites, including the primary.
is using the secondary proxying and set the `URL` field to the single URL.
Make sure the primary site is also using this URL.
-In Kubernetes, you can use the same domain under `global.hosts.domain` as for the primary site.
+In Kubernetes, you can [use the same domain under `global.hosts.domain` as for the primary site](https://docs.gitlab.com/charts/advanced/geo/index.html).
## Geo proxying with Separate URLs
diff --git a/doc/administration/geo/setup/external_database.md b/doc/administration/geo/setup/external_database.md
index 061ae2d4eb8..6083d7331b6 100644
--- a/doc/administration/geo/setup/external_database.md
+++ b/doc/administration/geo/setup/external_database.md
@@ -7,8 +7,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Geo with external PostgreSQL instances **(PREMIUM SELF)**
This document is relevant if you are using a PostgreSQL instance that is not
-managed by the Linux package. This includes cloud-managed instances like Amazon RDS, or
-manually installed and configured PostgreSQL instances.
+managed by the Linux package. This includes
+[cloud-managed instances](../../reference_architectures/index.md#recommendation-notes-for-the-database-services),
+or manually installed and configured PostgreSQL instances.
Ensure that you are using one of the PostgreSQL versions that
the [Linux package ships with](../../package_information/postgresql_versions.md)
diff --git a/doc/administration/geo/setup/two_single_node_sites.md b/doc/administration/geo/setup/two_single_node_sites.md
index 00002d501b2..da7ec455c6a 100644
--- a/doc/administration/geo/setup/two_single_node_sites.md
+++ b/doc/administration/geo/setup/two_single_node_sites.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Set up Geo for two single-node sites **(PREMIUM SELF)**
-The following guide provides concise instructions on how to deploy GitLab Geo for a two single-node site installation using two Linux package instances.
+The following guide provides concise instructions on how to deploy GitLab Geo for a two single-node site installation using two Linux package instances with no external services set up.
Prerequisites:
@@ -552,8 +552,9 @@ You must manually replicate the secret file across all of your secondary sites,
```
1. Navigate to the primary node GitLab instance:
- 1. On the top bar, select **Main menu > Admin**.
- 1. On the left sidebar, select **Geo > Sites**.
+ 1. On the left sidebar, select **Search or go to**.
+ 1. Select **Admin Area**.
+ 1. Select **Geo > Sites**.
1. Select **Add site**.
![Add secondary site](../replication/img/adding_a_secondary_v15_8.png)
@@ -607,8 +608,9 @@ If you convert an existing site to Geo, you should check that the clone method i
On the primary site:
-1. On the top bar, select **Main menu > Admin**.
-1. On the left sidebar, select **Settings > General**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
1. Expand **Visibility and access controls**.
1. If you use Git over SSH:
1. Ensure **Enabled Git access protocols** is set to **Both SSH and HTTP(S)**.
@@ -622,8 +624,9 @@ the primary site.
After you sign in:
-1. On the top bar, select **Main menu > Admin**.
-1. On the left sidebar, select **Geo > Sites**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Geo > Sites**.
1. Verify that the site is correctly identified as a secondary Geo site, and that
Geo is enabled.
diff --git a/doc/administration/geo_sites.md b/doc/administration/geo_sites.md
index 81cc3a87941..f0c3e24f643 100644
--- a/doc/administration/geo_sites.md
+++ b/doc/administration/geo_sites.md
@@ -11,7 +11,7 @@ You can configure various settings for GitLab Geo sites. For more information, s
On either the primary or secondary site:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Geo > Sites**.
@@ -72,7 +72,7 @@ the primary uses the secondary's internal URL to contact it directly.
The internal URL defaults to external URL. To change it:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Geo > Sites**.
1. Select **Edit** on the site you want to customize.
diff --git a/doc/administration/gitaly/configure_gitaly.md b/doc/administration/gitaly/configure_gitaly.md
index b26ae84eef0..9f3afae0e9f 100644
--- a/doc/administration/gitaly/configure_gitaly.md
+++ b/doc/administration/gitaly/configure_gitaly.md
@@ -276,11 +276,11 @@ Configure Gitaly server in one of two ways:
storage: [
{
name: 'default',
- path: '/var/opt/gitlab/git-data',
+ path: '/var/opt/gitlab/git-data/repositories',
},
{
name: 'storage1',
- path: '/mnt/gitlab/git-data',
+ path: '/mnt/gitlab/git-data/repositories',
},
],
}
@@ -294,7 +294,7 @@ Configure Gitaly server in one of two ways:
storage: [
{
name: 'storage2',
- path: '/srv/gitlab/git-data',
+ path: '/srv/gitlab/git-data/repositories',
},
],
}
@@ -517,7 +517,7 @@ gitaly['configuration'] = {
storage: [
{
name: 'storage1',
- path: '/mnt/gitlab/git-data',
+ path: '/mnt/gitlab/git-data/repositories',
},
],
}
@@ -786,13 +786,13 @@ gitaly['configuration'] = {
{
rpc: '/gitaly.SmartHTTPService/PostUploadPackWithSidechannel',
max_per_repo: 20,
- max_queue_time: '1s',
+ max_queue_wait: '1s',
max_queue_size: 10,
},
{
rpc: '/gitaly.SSHService/SSHUploadPackWithSidechannel',
max_per_repo: 20,
- max_queue_time: '1s',
+ max_queue_wait: '1s',
max_queue_size: 10,
},
],
@@ -801,7 +801,7 @@ gitaly['configuration'] = {
- `rpc` is the name of the RPC to set a concurrency limit for per repository.
- `max_per_repo` is the maximum number of in-flight RPC calls for the given RPC per repository.
-- `max_queue_time` is the maximum amount of time a request can wait in the concurrency queue to
+- `max_queue_wait` is the maximum amount of time a request can wait in the concurrency queue to
be picked up by Gitaly.
- `max_queue_size` is the maximum size the concurrency queue (per RPC method) can grow to before requests are rejected by
Gitaly.
@@ -822,6 +822,50 @@ When these limits are reached, users are disconnected.
You can observe the behavior of this queue using the Gitaly logs and Prometheus. For more
information, see the [relevant documentation](monitoring.md#monitor-gitaly-concurrency-limiting).
+## Limit pack-objects concurrency
+
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/7891) in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `gitaly_pack_objects_limiting_remote_ip`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5772) in GitLab 16.0. Feature flag `gitaly_pack_objects_limiting_remote_ip` removed.
+
+Gitaly triggers `git-pack-objects` processes when handling both SSH and HTTPS traffic to clone or pull repositories. These processes generate a `pack-file` and can
+consume a significant amount of resources, especially in situations such as unexpectedly high traffic or concurrent pulls from a large repository. On GitLab.com, we also
+observe problems with clients that have slow internet connections.
+
+You can limit these processes from overwhelming your Gitaly server by setting pack-objects concurrency limits in the Gitaly configuration file. This setting limits the
+number of in-flight pack-object processes per remote IP address.
+
+WARNING:
+Only enable these limits on your environment with caution and only in select circumstances, such as to protect against unexpected traffic. When reached, these limits
+disconnect users. For consistent and stable performance, you should first explore other options such as adjusting node specifications, and
+[reviewing large repositories](../../user/project/repository/managing_large_repositories.md) or workloads.
+
+Example configuration:
+
+```ruby
+# in /etc/gitlab/gitlab.rb
+gitaly['pack_objects_limiting'] = {
+ 'max_concurrency' => 15,
+ 'max_queue_length' => 200,
+ 'max_queue_wait' => '60s',
+}
+```
+
+- `max_concurrency` is the maximum number of in-flight pack-object processes per key.
+- `max_queue_length` is the maximum size the concurrency queue (per key) can grow to before requests are rejected by Gitaly.
+- `max_queue_wait` is the maximum amount of time a request can wait in the concurrency queue to be picked up by Gitaly.
+
+In the example above:
+
+- Each remote IP can have at most 15 simultaneous pack-object processes in flight on a Gitaly node.
+- If another request comes in from an IP that has used up its 15 slots, that request gets queued.
+- If a request waits in the queue for more than 1 minute, it is rejected with an error.
+- If the queue grows beyond 200, subsequent requests are rejected with an error.
+
+When the pack-object cache is enabled, pack-objects limiting kicks in only if the cache is missed. For more, see [Pack-objects cache](#pack-objects-cache).
+
+You can observe the behavior of this queue using Gitaly logs and Prometheus. For more information, see
+[Monitor Gitaly pack-objects concurrency limiting](monitoring.md#monitor-gitaly-pack-objects-concurrency-limiting).
+
## Control groups
WARNING:
@@ -831,10 +875,6 @@ When reached, limits _do_ result in disconnects that negatively impact users.
For consistent and stable performance, you should first explore other options such as
adjusting node specifications, and [reviewing large repositories](../../user/project/repository/managing_large_repositories.md) or workloads.
-FLAG:
-On self-managed GitLab, by default repository cgroups are not available. To make it available, an administrator can
-[enable the feature flag](../feature_flags.md) named `gitaly_run_cmds_in_cgroup`.
-
When enabling cgroups for memory, you should ensure that no swap is configured on the Gitaly nodes as
processes may switch to using that instead of being terminated. This situation could lead to notably compromised
performance.
@@ -1288,47 +1328,34 @@ the cache hit rate.
### Observe the cache
-The cache can be observed [using metrics](monitoring.md#pack-objects-cache) and in the following logged
-information:
+> Logs for pack-objects caching was [changed](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5719) in GitLab 16.0.
-|Message|Fields|Description|
-|:---|:---|:---|
-|`generated bytes`|`bytes`, `cache_key`|Logged when an entry was added to the cache|
-|`served bytes`|`bytes`, `cache_key`|Logged when an entry was read from the cache|
+You can observe the cache [using metrics](monitoring.md#pack-objects-cache) and in the following logged information. These logs are part of the gRPC logs and can
+be discovered when a call is executed.
+
+| Field | Description |
+|:---|:---|
+| `pack_objects_cache.hit` | Indicates whether the current pack-objects cache was hit (`true` or `false`) |
+| `pack_objects_cache.key` | Cache key used for the pack-objects cache |
+| `pack_objects_cache.generated_bytes` | Size (in bytes) of the new cache being written |
+| `pack_objects_cache.served_bytes` | Size (in bytes) of the cache being served |
+| `pack_objects.compression_statistics` | Statistics regarding pack-objects generation |
+| `pack_objects.enumerate_objects_ms` | Total time (in ms) spent enumerating objects sent by clients |
+| `pack_objects.prepare_pack_ms` | Total time (in ms) spent preparing the packfile before sending it back to the client |
+| `pack_objects.write_pack_file_ms` | Total time (in ms) spent sending back the packfile to the client. Highly dependent on the client's internet connection |
+| `pack_objects.written_object_count` | Total number of objects Gitaly sends back to the client |
In the case of a:
-- Cache miss, Gitaly logs both a `generated bytes` and a `served bytes` message.
-- Cache hit, Gitaly logs only a `served bytes` message.
+- Cache miss, Gitaly logs both a `pack_objects_cache.generated_bytes` and `pack_objects_cache.served_bytes` message. Gitaly also logs some more detailed statistics of
+ pack-object generation.
+- Cache hit, Gitaly logs only a `pack_objects_cache.served_bytes` message.
Example:
```json
{
"bytes":26186490,
- "cache_key":"1b586a2698ca93c2529962e85cda5eea8f0f2b0036592615718898368b462e19",
- "correlation_id":"01F1MY8JXC3FZN14JBG1H42G9F",
- "grpc.meta.deadline_type":"none",
- "grpc.method":"PackObjectsHook",
- "grpc.request.fullMethod":"/gitaly.HookService/PackObjectsHook",
- "grpc.request.glProjectPath":"root/gitlab-workhorse",
- "grpc.request.glRepository":"project-2",
- "grpc.request.repoPath":"@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.git",
- "grpc.request.repoStorage":"default",
- "grpc.request.topLevelGroup":"@hashed",
- "grpc.service":"gitaly.HookService",
- "grpc.start_time":"2021-03-25T14:57:52.747Z",
- "level":"info",
- "msg":"generated bytes",
- "peer.address":"@",
- "pid":20961,
- "span.kind":"server",
- "system":"grpc",
- "time":"2021-03-25T14:57:53.543Z"
-}
-{
- "bytes":26186490,
- "cache_key":"1b586a2698ca93c2529962e85cda5eea8f0f2b0036592615718898368b462e19",
"correlation_id":"01F1MY8JXC3FZN14JBG1H42G9F",
"grpc.meta.deadline_type":"none",
"grpc.method":"PackObjectsHook",
@@ -1341,12 +1368,23 @@ Example:
"grpc.service":"gitaly.HookService",
"grpc.start_time":"2021-03-25T14:57:52.747Z",
"level":"info",
- "msg":"served bytes",
+ "msg":"finished unary call with code OK",
"peer.address":"@",
"pid":20961,
"span.kind":"server",
"system":"grpc",
- "time":"2021-03-25T14:57:53.543Z"
+ "time":"2021-03-25T14:57:53.543Z",
+ "pack_objects.compression_statistics": "Total 145991 (delta 68), reused 6 (delta 2), pack-reused 145911",
+ "pack_objects.enumerate_objects_ms": 170,
+ "pack_objects.prepare_pack_ms": 7,
+ "pack_objects.write_pack_file_ms": 786,
+ "pack_objects.written_object_count": 145991,
+ "pack_objects_cache.generated_bytes": 49533030,
+ "pack_objects_cache.hit": "false",
+ "pack_objects_cache.key": "123456789",
+ "pack_objects_cache.served_bytes": 49533030,
+ "peer.address": "127.0.0.1",
+ "pid": 8813,
}
```
@@ -1496,7 +1534,13 @@ value = "/etc/gitlab/instance_wide_ignored_git_blobs.txt"
## Configure commit signing for GitLab UI commits
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/19185) in GitLab 15.4.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/19185) in GitLab 15.4.
+> - Displaying **Verified** badge for signed GitLab UI commits [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124218) in GitLab 16.3 [with a flag](../feature_flags.md) named `gitaly_gpg_signing`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flag](../feature_flags.md) named `gitaly_gpg_signing`.
+On GitLab.com, this feature is not available.
By default, Gitaly doesn't sign commits made using GitLab UI. For example, commits made using:
@@ -1513,13 +1557,21 @@ Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
:::TabTitle Linux package (Omnibus)
-1. [Create a GPG key](../../user/project/repository/gpg_signed_commits/index.md#create-a-gpg-key)
- and export it. For optimal performance, consider using an EdDSA key.
+1. [Create a GPG key](../../user/project/repository/signed_commits/gpg.md#create-a-gpg-key)
+ and export it, or [create an SSH key](../../user/ssh.md#generate-an-ssh-key-pair). For optimal performance, use an EdDSA key.
+
+ Export GPG key:
```shell
gpg --export-secret-keys <ID> > signing_key.gpg
```
+ Or create an SSH key (with no passphrase):
+
+ ```shell
+ ssh-keygen -t ed25519 -f signing_key.ssh
+ ```
+
1. On the Gitaly nodes, copy the key into `/etc/gitlab/gitaly/`.
1. Edit `/etc/gitlab/gitlab.rb` and configure `gitaly['gpg_signing_key_path']`:
@@ -1537,13 +1589,21 @@ Configure Gitaly to sign commits made with the GitLab UI in one of two ways:
:::TabTitle Self-compiled (source)
-1. [Create a GPG key](../../user/project/repository/gpg_signed_commits/index.md#create-a-gpg-key)
- and export it. For optimal performance, consider using an EdDSA key.
+1. [Create a GPG key](../../user/project/repository/signed_commits/gpg.md#create-a-gpg-key)
+ and export it, or [create an SSH key](../../user/ssh.md#generate-an-ssh-key-pair). For optimal performance, use an EdDSA key.
+
+ Export GPG key:
```shell
gpg --export-secret-keys <ID> > signing_key.gpg
```
+ Or create an SSH key (with no passphrase):
+
+ ```shell
+ ssh-keygen -t ed25519 -f signing_key.ssh
+ ```
+
1. On the Gitaly nodes, copy the key into `/etc/gitlab`.
1. Edit `/home/git/gitaly/config.toml` and configure `signing_key`:
@@ -1610,3 +1670,172 @@ Gitaly fails to start up if either:
- The configuration command fails.
- The output produced by the command cannot be parsed as valid JSON.
+
+## Configure server-side backups
+
+> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4941) in GitLab 16.3.
+
+Repository backups can be configured so that the Gitaly node that hosts each
+repository is responsible for creating the backup and streaming it to
+object storage. This helps reduce the network resources required to create and
+restore a backup.
+
+Each Gitaly node must be configured to connect to object storage for backups.
+
+After configuring server-side backups, you can
+[create a server-side repository backup](../backup_restore/backup_gitlab.md#create-server-side-repository-backups).
+
+### Configure Azure Blob storage
+
+How you configure Azure Blob storage for backups depends on the type of installation you have. For self-compiled installations, you must set
+the `AZURE_STORAGE_ACCOUNT` and `AZURE_STORAGE_KEY` environment variables outside of GitLab.
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+Edit `/etc/gitlab/gitlab.rb` and configure the `go_cloud_url`:
+
+```ruby
+gitaly['env'] = {
+ 'AZURE_STORAGE_ACCOUNT' => 'azure_storage_account',
+ 'AZURE_STORAGE_KEY' => 'azure_storage_key' # or 'AZURE_STORAGE_SAS_TOKEN'
+}
+gitaly['configuration'] = {
+ backup: {
+ go_cloud_url: 'azblob://gitaly-backups'
+ }
+}
+```
+
+:::TabTitle Self-compiled (source)
+
+Edit `/home/git/gitaly/config.toml` and configure `go_cloud_url`:
+
+```toml
+[backup]
+go_cloud_url = "azblob://gitaly-backups"
+```
+
+::EndTabs
+
+### Configure Google Cloud storage
+
+Google Cloud storage (GCP) authenticates using Application Default Credentials. Set up Application Default Credentials on each Gitaly server using either:
+
+- The [`gcloud auth application-default login`](https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login) command.
+- The `GOOGLE_APPLICATION_CREDENTIALS` environment variable. For self-compiled installations, set the environment
+ variable outside of GitLab.
+
+For more information, see [Application Default Credentials](https://cloud.google.com/docs/authentication/provide-credentials-adc).
+
+The destination bucket is configured using the `go_cloud_url` option.
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+Edit `/etc/gitlab/gitlab.rb` and configure the `go_cloud_url`:
+
+```ruby
+gitaly['env'] = {
+ 'GOOGLE_APPLICATION_CREDENTIALS' => '/path/to/service.json'
+}
+gitaly['configuration'] = {
+ backup: {
+ go_cloud_url: 'gs://gitaly-backups'
+ }
+}
+```
+
+:::TabTitle Self-compiled (source)
+
+Edit `/home/git/gitaly/config.toml` and configure `go_cloud_url`:
+
+```toml
+[backup]
+go_cloud_url = "gs://gitaly-backups"
+```
+
+::EndTabs
+
+### Configure S3 storage
+
+To configure S3 storage authentication:
+
+- If you authenticate with the AWS CLI, you can use the default AWS session.
+- Otherwise, you can use the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables. For self-compiled installations, set the environment
+ variables outside of GitLab.
+
+For more information, see [AWS Session documentation](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/).
+
+The destination bucket and region are configured using the `go_cloud_url` option.
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+Edit `/etc/gitlab/gitlab.rb` and configure the `go_cloud_url`:
+
+```ruby
+gitaly['env'] = {
+ 'AWS_ACCESS_KEY_ID' => 'aws_access_key_id',
+ 'AWS_SECRET_ACCESS_KEY' => 'aws_secret_access_key'
+}
+gitaly['configuration'] = {
+ backup: {
+ go_cloud_url: 's3://gitaly-backups?region=us-west-1'
+ }
+}
+```
+
+:::TabTitle Self-compiled (source)
+
+Edit `/home/git/gitaly/config.toml` and configure `go_cloud_url`:
+
+```toml
+[backup]
+go_cloud_url = "s3://gitaly-backups?region=us-west-1"
+```
+
+::EndTabs
+
+#### Configure S3-compatible servers
+
+S3-compatible servers such as MinIO are configured similarly to S3 with the addition of the `endpoint` parameter.
+
+The following parameters are supported:
+
+- `region`: The AWS region.
+- `endpoint`: The endpoint URL.
+- `disabledSSL`: A value of `true` disables SSL.
+- `s3ForcePathStyle`: A value of `true` forces path-style addressing.
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+Edit `/etc/gitlab/gitlab.rb` and configure the `go_cloud_url`:
+
+```ruby
+gitaly['env'] = {
+ 'AWS_ACCESS_KEY_ID' => 'minio_access_key_id',
+ 'AWS_SECRET_ACCESS_KEY' => 'minio_secret_access_key'
+}
+gitaly['configuration'] = {
+ backup: {
+ go_cloud_url: 's3://gitaly-backups?region=minio&endpoint=my.minio.local:8080&disableSSL=true&s3ForcePathStyle=true'
+ }
+}
+```
+
+:::TabTitle Self-compiled (source)
+
+Edit `/home/git/gitaly/config.toml` and configure `go_cloud_url`:
+
+```toml
+[backup]
+go_cloud_url = "s3://gitaly-backups?region=minio&endpoint=my.minio.local:8080&disableSSL=true&s3ForcePathStyle=true"
+```
+
+::EndTabs
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index db11ac8c769..46f6a5829c8 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -25,6 +25,7 @@ Gitaly implements a client-server architecture:
- [GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell)
- [GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse)
- [GitLab Elasticsearch Indexer](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer)
+ - [GitLab Zoekt Indexer](https://gitlab.com/gitlab-org/gitlab-zoekt-indexer)
Gitaly manages only Git repository access for GitLab. Other types of GitLab data aren't accessed
using Gitaly.
@@ -57,7 +58,7 @@ If you have not yet migrated to Gitaly Cluster, you have two options:
- A sharded Gitaly instance.
- Gitaly Cluster.
-Contact your [Customer Success Manager](https://about.gitlab.com/job-families/sales/customer-success-management/) or customer support if you have any questions.
+Contact your [Customer Success Manager](https://handbook.gitlab.com/job-families/sales/customer-success-management/) or customer support if you have any questions.
### Known issues
@@ -326,7 +327,7 @@ conflicts that could occur due to partially applied operations.
Repositories are stored in the storages at the relative path determined by the [Gitaly client](#gitaly-architecture). These paths can be
identified by them not beginning with the `@cluster` prefix. The relative paths
-follow the [hashed storage](../repository_storage_types.md#hashed-storage) schema.
+follow the [hashed storage](../repository_storage_paths.md#hashed-storage) schema.
#### Praefect-generated replica paths (GitLab 15.0 and later)
@@ -377,7 +378,7 @@ Use the [`praefect metadata`](troubleshooting.md#view-repository-metadata) subco
The repository on disk also contains the project path in the Git configuration file. The configuration
file can be used to determine the project path even if the repository's metadata has been deleted.
-Follow the [instructions in hashed storage's documentation](../repository_storage_types.md#from-hashed-path-to-project-name).
+Follow the [instructions in hashed storage's documentation](../repository_storage_paths.md#from-hashed-path-to-project-name).
#### Atomicity of operations
diff --git a/doc/administration/gitaly/monitoring.md b/doc/administration/gitaly/monitoring.md
index 00d0499faa2..cbf5722f2c5 100644
--- a/doc/administration/gitaly/monitoring.md
+++ b/doc/administration/gitaly/monitoring.md
@@ -31,18 +31,64 @@ of requests dropped due to request limiting. The `reason` label indicates why a
## Monitor Gitaly concurrency limiting
-You can observe specific behavior of [concurrency-queued requests](configure_gitaly.md#limit-rpc-concurrency) using
-the Gitaly logs and Prometheus:
-
-- In the [Gitaly logs](../logs/index.md#gitaly-logs), look for the string (or structured log field)
- `acquire_ms`. Messages that have this field are reporting about the concurrency limiter.
-- In Prometheus, look for the following metrics:
- - `gitaly_concurrency_limiting_in_progress` indicates how many concurrent requests are
- being processed.
- - `gitaly_concurrency_limiting_queued` indicates how many requests for an RPC for a given
- repository are waiting due to the concurrency limit being reached.
- - `gitaly_concurrency_limiting_acquiring_seconds` indicates how long a request has to
- wait due to concurrency limits before being processed.
+You can observe specific behavior of [concurrency-queued requests](configure_gitaly.md#limit-rpc-concurrency) using Gitaly logs and Prometheus.
+
+In the [Gitaly logs](../logs/index.md#gitaly-logs), you can identify logs related to the pack-objects concurrency limiting with entries such as:
+
+| Log Field | Description |
+| --- | --- |
+| `limit.concurrency_queue_length` | Indicates the current length of the queue specific to the RPC type of the ongoing call. It provides insight into the number of requests waiting to be processed due to concurrency limits. |
+| `limit.concurrency_queue_ms` | Represents the duration, in milliseconds, that a request has spent waiting in the queue due to the limit on concurrent RPCs. This field helps understand the impact of concurrency limits on request processing times. |
+| `limit.concurrency_dropped` | If the request is dropped due to limits being reached, this field specifies the reason: either `max_time` (request waited in the queue longer than the maximum allowed time) or `max_size` (the queue reached its maximum size). |
+| `limit.limiting_key` | Identifies the key used for limiting. |
+| `limit.limiting_type` | Specifies the type of process being limited. In this context, it's `per-rpc`, indicating that the concurrency limiting is applied on a per-RPC basis. |
+
+For example:
+
+```json
+{
+ "limit .concurrency_queue_length": 1,
+ "limit .concurrency_queue_ms": 0,
+ "limit.limiting_key": "@hashed/79/02/7902699be42c8a8e46fbbb450172651786b22c56a189f7625a6da49081b2451.git",
+ "limit.limiting_type": "per-rpc"
+}
+```
+
+In Prometheus, look for the following metrics:
+
+- `gitaly_concurrency_limiting_in_progress` indicates how many concurrent requests are being processed.
+- `gitaly_concurrency_limiting_queued` indicates how many requests for an RPC for a given repository are waiting due to the concurrency limit being reached.
+- `gitaly_concurrency_limiting_acquiring_seconds` indicates how long a request has to wait due to concurrency limits before being processed.
+
+## Monitor Gitaly pack-objects concurrency limiting
+
+You can observe specific behavior of [pack-objects limiting](configure_gitaly.md#limit-pack-objects-concurrency) using Gitaly logs and Prometheus.
+
+In the [Gitaly logs](../logs/index.md#gitaly-logs), you can identify logs related to the pack-objects concurrency limiting with entries such as:
+
+| Log Field | Description |
+|:---|:---|
+| `limit.concurrency_queue_length` | Current length of the queue for the pack-objects processes. Indicates the number of requests that are waiting to be processed because the limit on concurrent processes has been reached. |
+| `limit.concurrency_queue_ms` | Time a request has spent waiting in the queue, in milliseconds. Indicates how long a request has had to wait because of the limits on concurrency. |
+| `limit.limiting_key` | Remote IP of the sender. |
+| `limit.limiting_type` | Type of process being limited. In this case, `pack-objects`. |
+
+Example configuration:
+
+```json
+{
+ "limit .concurrency_queue_length": 1,
+ "limit .concurrency_queue_ms": 0,
+ "limit.limiting_key": "1.2.3.4",
+ "limit.limiting_type": "pack-objects"
+}
+```
+
+In Prometheus, look for the following metrics:
+
+- `gitaly_pack_objects_in_progress` indicates how many pack-objects processes are being processed concurrently.
+- `gitaly_pack_objects_queued` indicates how many requests for pack-objects processes are waiting due to the concurrency limit being reached.
+- `gitaly_pack_objects_acquiring_seconds` indicates how long a request for a pack-object process has to wait due to concurrency limits before being processed.
## Monitor Gitaly cgroups
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index 6eefd0a7bb5..0297f295e6f 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -1133,15 +1133,15 @@ For more information on Gitaly server configuration, see our
storage: [
{
name: 'gitaly-1',
- path: '/var/opt/gitlab/git-data',
+ path: '/var/opt/gitlab/git-data/repositories',
},
{
name: 'gitaly-2',
- path: '/var/opt/gitlab/git-data',
+ path: '/var/opt/gitlab/git-data/repositories',
},
{
name: 'gitaly-3',
- path: '/var/opt/gitlab/git-data',
+ path: '/var/opt/gitlab/git-data/repositories',
},
],
}
@@ -1337,7 +1337,7 @@ Particular attention should be shown to:
1. Check that the Praefect storage is configured to store new repositories:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Repository**.
1. Expand the **Repository storage** section.
@@ -1498,9 +1498,12 @@ For a replication factor:
> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4080) in GitLab 15.0.
Praefect stores metadata about the repositories in a database. If the repositories are modified on disk
-without going through Praefect, the metadata can become inaccurate. Because the metadata is used for replication
-and routing decisions, any inaccuracies may cause problems. Praefect contains a background worker that
-periodically verifies the metadata against the actual state on the disks. The worker:
+without going through Praefect, the metadata can become inaccurate. For example if a Gitaly node is
+rebuilt, rather than being replaced with a new node, repository verification ensures this is detected.
+
+The metadata is used for replication and routing decisions, so any inaccuracies may cause problems.
+Praefect contains a background worker that periodically verifies the metadata against the actual state on the disks.
+The worker:
1. Picks up a batch of replicas to verify on healthy storages. The replicas are either unverified or have exceeded
the configured verification interval. Replicas that have never been verified are prioritized, followed by
@@ -1512,8 +1515,8 @@ periodically verifies the metadata against the actual state on the disks. The wo
The worker acquires an exclusive verification lease on each of the replicas it is about to verify. This avoids multiple
workers from verifying the same replica concurrently. The worker releases the leases when it has completed its check.
-Praefect contains a background goroutine that releases stale leases every 10 seconds when workers are terminated for
-some reason without releasing the lease.
+If workers are terminated for some reason without releasing the lease, Praefect contains a background goroutine
+that releases stale leases every 10 seconds.
The worker logs each of the metadata removals prior to executing them. The `perform_deletions` key
indicates whether the invalid metadata records are actually deleted or not. For example:
diff --git a/doc/administration/gitaly/recovery.md b/doc/administration/gitaly/recovery.md
index aa487917ef0..45bde083a1a 100644
--- a/doc/administration/gitaly/recovery.md
+++ b/doc/administration/gitaly/recovery.md
@@ -39,7 +39,7 @@ To use a different name for the replacement node for a Gitaly Cluster that has [
For example:
```shell
- $ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml set-replication-factor -virtual-storage default -repository @hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git -replication-factor 2
+ $ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml set-replication-factor -virtual-storage default -relative-path @hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git -replication-factor 2
current assignments: gitaly-1, gitaly-2
```
@@ -224,7 +224,7 @@ repository so care must be taken.
```shell
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss
--virtual-storage <virtual-storage> -repository <relative-path> -authoritative-storage <storage-name>
+-virtual-storage <virtual-storage> -relative-path <relative-path> -authoritative-storage <storage-name>
```
### Enable writes or accept data loss
@@ -237,7 +237,7 @@ Praefect provides the following subcommands to re-enable writes or accept data l
of the up-to-date nodes back online, you might have to accept data loss:
```shell
-sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss -virtual-storage <virtual-storage> -repository <relative-path> -authoritative-storage <storage-name>
+sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss -virtual-storage <virtual-storage> -relative-path <relative-path> -authoritative-storage <storage-name>
```
When accepting data loss, Praefect:
@@ -338,7 +338,7 @@ The `remove-repository` Praefect sub-command removes a repository from a Gitaly
In GitLab 14.6 and later, by default, the command operates in dry-run mode. In earlier versions, the command didn't support dry-run mode. For example:
```shell
-sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml remove-repository -virtual-storage <virtual-storage> -repository <repository>
+sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml remove-repository -virtual-storage <virtual-storage> -relative-path <repository>
```
- Replace `<virtual-storage>` with the name of the virtual storage containing the repository.
@@ -349,7 +349,7 @@ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.t
- In GitLab 14.6 and later, add `-apply` to run the command outside of dry-run mode and remove the repository. For example:
```shell
- sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml remove-repository -virtual-storage <virtual-storage> -repository <repository> -apply
+ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml remove-repository -virtual-storage <virtual-storage> -relative-path <repository> -apply
```
- `-virtual-storage` is the virtual storage the repository is located in. Virtual storages are configured in `/etc/gitlab/gitlab.rb` under `praefect['configuration']['virtual_storage]` and looks like the following:
@@ -372,7 +372,7 @@ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.t
In this example, the virtual storage to specify is `default` or `storage-1`.
-- `-repository` is the repository's relative path in the storage [beginning with `@hashed`](../repository_storage_types.md#hashed-storage).
+- `-repository` is the repository's relative path in the storage [beginning with `@hashed`](../repository_storage_paths.md#hashed-storage).
For example:
```plaintext
@@ -440,7 +440,7 @@ inaccessible.
The `track-repository` Praefect sub-command adds repositories on disk to the Praefect tracking database to be tracked.
```shell
-sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml track-repository -virtual-storage <virtual-storage> -authoritative-storage <storage-name> -repository <repository> -replicate-immediately
+sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml track-repository -virtual-storage <virtual-storage> -authoritative-storage <storage-name> -relative-path <repository> -replica-path <disk_path> -replicate-immediately
```
- `-virtual-storage` is the virtual storage the repository is located in. Virtual storages are configured in `/etc/gitlab/gitlab.rb` under `praefect['configuration'][:virtual_storage]` and looks like the following:
@@ -463,13 +463,14 @@ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.t
In this example, the virtual storage to specify is `default` or `storage-1`.
-- `-repository` is the repository's relative path in the storage [beginning with `@hashed`](../repository_storage_types.md#hashed-storage).
+- `-relative-path` is the relative path in the virtual storage. Usually [beginning with `@hashed`](../repository_storage_paths.md#hashed-storage).
For example:
```plaintext
@hashed/f5/ca/f5ca38f748a1d6eaf726b8a42fb575c3c71f1864a8143301782de13da2d9202b.git
```
+- `-replica-path` is the relative path on physical storage. Can start with [`@cluster` or match `relative_path`](../repository_storage_paths.md#gitaly-cluster-storage).
- `-authoritative-storage` is the storage we want Praefect to treat as the primary. Required if
[per-repository replication](praefect.md#configure-replication-factor) is set as the replication strategy.
- `-replicate-immediately`, available in GitLab 14.6 and later, causes the command to replicate the repository to its secondaries immediately.
@@ -523,8 +524,8 @@ If any entry fails these checks, the command aborts prior to attempting to track
For example:
```json
- {"relative_path":"@hashed/f5/ca/f5ca38f748a1d6eaf726b8a42fb575c3c71f1864a8143301782de13da2d9202b.git","authoritative_storage":"gitaly-1","virtual_storage":"default"}
- {"relative_path":"@hashed/f8/9f/f89f8d0e735a91c5269ab08d72fa27670d000e7561698d6e664e7b603f5c4e40.git","authoritative_storage":"gitaly-2","virtual_storage":"default"}
+ {"relative_path":"@hashed/f5/ca/f5ca38f748a1d6eaf726b8a42fb575c3c71f1864a8143301782de13da2d9202b.git","replica_path":"@cluster/fe/d3/1","authoritative_storage":"gitaly-1","virtual_storage":"default"}
+ {"relative_path":"@hashed/f8/9f/f89f8d0e735a91c5269ab08d72fa27670d000e7561698d6e664e7b603f5c4e40.git","replica_path":"@cluster/7b/28/2","authoritative_storage":"gitaly-2","virtual_storage":"default"}
```
- `-replicate-immediately`, causes the command to replicate the repository to its secondaries immediately.
diff --git a/doc/administration/gitaly/reference.md b/doc/administration/gitaly/reference.md
index aa04c9a92c4..5b26c93cea8 100644
--- a/doc/administration/gitaly/reference.md
+++ b/doc/administration/gitaly/reference.md
@@ -155,25 +155,43 @@ Prometheus query to see the hit rate:
sum(rate(gitaly_catfile_cache_total{type="hit"}[5m])) / sum(rate(gitaly_catfile_cache_total{type=~"(hit)|(miss)"}[5m]))
```
-### GitLab Shell
+#### Custom Hooks
-For historical reasons
-[GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell) contains
-the Git hooks that allow GitLab to validate and react to Git pushes.
-Because Gitaly "owns" Git pushes, GitLab Shell must therefore be
-installed alongside Gitaly.
+> Method of configuring custom hooks directory documented here is preferred from GitLab 16.4. `[gitlab-shell] dir` configuration is no longer required.
+
+Gitaly supports [custom Git hooks](../server_hooks.md) that are
+used to perform tasks based on changes performed in any repository. The custom
+hooks directory is configured in the `[hooks]` section:
| Name | Type | Required | Description |
| ---- | ---- | -------- | ----------- |
-| `dir` | string | yes | The directory where GitLab Shell is installed.|
+| `custom_hooks_dir` | string | no | The directory where custom Git hooks are installed. |
Example:
```toml
-[gitlab-shell]
-dir = "/home/git/gitlab-shell"
+[hooks]
+custom_hooks_dir = "/home/git/custom-hooks"
```
+If left unset, no custom hooks are used.
+
+### GitLab
+
+> Method of configuring custom hooks directory documented here is preferred from GitLab 16.4. `[gitlab-shell] dir` configuration is no longer required.
+
+Gitaly must connect to the GitLab application to perform access
+checks when a user performs a change. The parameters to connect to GitLab must
+be configured in the `[gitlab]` section.
+
+| Name | Type | Required | Description |
+| ---- | ---- | -------- | ----------- |
+| `url` | string | yes | The URL of the GitLab server.
+| `secret` | string | no | The secret token used to authenticate with GitLab. |
+| `secret_file` | string | no | The path of the file containing the secret token used to authenticate with GitLab. |
+
+Only one of `secret` or `secret_file` can be configured.
+
### Prometheus
You can optionally configure Gitaly to record histogram latencies on GRPC method
diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md
index 3d8110e1dab..556bc29b76f 100644
--- a/doc/administration/gitaly/troubleshooting.md
+++ b/doc/administration/gitaly/troubleshooting.md
@@ -20,7 +20,7 @@ and our advice on [parsing the `gitaly/current` file](../logs/log_parsing.md#par
When using standalone Gitaly servers, you must make sure they are the same version
as GitLab to ensure full compatibility:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Gitaly Servers**.
1. Confirm all Gitaly servers indicate that they are up to date.
@@ -269,7 +269,7 @@ git push origin +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/*
Any other namespaces that the administrator wants to push can be included there as well via additional patterns.
-### Command line tools cannot connect to Gitaly
+### Command-line tools cannot connect to Gitaly
gRPC cannot reach your Gitaly server if:
@@ -556,6 +556,9 @@ You can retrieve a repository's metadata by its Praefect-assigned repository ID:
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml metadata -repository-id <repository-id>
```
+When the physical path on the physical storage starts with `@cluster`, you can
+[find the repository ID in the physical path](index.md#praefect-generated-replica-paths-gitlab-150-and-later).
+
You can also retrieve a repository's metadata by its virtual storage and relative path:
```shell
diff --git a/doc/administration/housekeeping.md b/doc/administration/housekeeping.md
index eed14fe1bf1..4b07b27d702 100644
--- a/doc/administration/housekeeping.md
+++ b/doc/administration/housekeeping.md
@@ -76,7 +76,7 @@ frequently.
You can change how often Gitaly is asked to optimize a repository.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Repository**.
1. Expand **Repository maintenance**.
@@ -109,7 +109,7 @@ housekeeping tasks. The manual trigger can be useful when either:
To trigger housekeeping tasks manually:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Advanced**.
1. Select **Run housekeeping**.
@@ -136,7 +136,7 @@ reduce the likelihood of such race conditions.
To trigger a manual prune of unreachable objects:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Advanced**.
1. Select **Run housekeeping**.
diff --git a/doc/administration/inactive_project_deletion.md b/doc/administration/inactive_project_deletion.md
index 278d585f2d9..b7f71505e70 100644
--- a/doc/administration/inactive_project_deletion.md
+++ b/doc/administration/inactive_project_deletion.md
@@ -23,7 +23,7 @@ For the default setting on GitLab.com, see the [GitLab.com settings page](../use
To configure deletion of inactive projects:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Repository**.
1. Expand **Repository maintenance**.
diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md
index 34f6da1d01d..112b296b96b 100644
--- a/doc/administration/instance_limits.md
+++ b/doc/administration/instance_limits.md
@@ -11,6 +11,31 @@ GitLab, like most large applications, enforces limits in certain features to mai
minimum quality of performance. Allowing some features to be limitless could affect security,
performance, data, or could even exhaust the allocated resources for the application.
+## Instance configuration
+
+In the instance configuration page, you can find information about some of the
+settings that are used in your current GitLab instance.
+
+Depending on which limits you have configured, you can see:
+
+- SSH host keys information
+- CI/CD limits
+- GitLab Pages limits
+- Package Registry limits
+- Rate limits
+- Size limits
+
+Because this page is visible to everybody, unauthenticated users only see the
+the information that is relevant to them.
+
+To visit the instance configuration page:
+
+1. On the left sidebar, select **Help** (**{question-o}**) > **Help**.
+1. On the Help page, select **Check the current instance configuration**.
+
+The direct URL is `<gitlab_url>/help/instance_configuration`. For GitLab.com,
+you can visit <https://gitlab.com/help/instance_configuration>.
+
## Rate limits
Rate limits can be used to improve the security and durability of GitLab.
@@ -600,6 +625,8 @@ Plan.default.actual_limits.update!(project_ci_variables: 10000)
### Maximum file size per type of artifact
+> `ci_max_artifact_size_annotations` limit [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38337) in GitLab 16.3.
+
Job artifacts defined with [`artifacts:reports`](../ci/yaml/index.md#artifactsreports)
that are uploaded by the runner are rejected if the file size exceeds the maximum
file size limit. The limit is determined by comparing the project's
@@ -615,6 +642,7 @@ setting is used:
| Artifact limit name | Default value |
|---------------------------------------------|---------------|
| `ci_max_artifact_size_accessibility` | 0 |
+| `ci_max_artifact_size_annotations` | 0 |
| `ci_max_artifact_size_api_fuzzing` | 0 |
| `ci_max_artifact_size_archive` | 0 |
| `ci_max_artifact_size_browser_performance` | 0 |
@@ -814,6 +842,37 @@ To set this limit to 5 KB on a self-managed installation, run the following in t
Plan.default.actual_limits.update!(dotenv_size: 5.kilobytes)
```
+### Limit CI/CD job annotations
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38337) in GitLab 16.3.
+
+You can set a limit on the maximum number of [annotations](../ci/yaml/artifacts_reports.md#artifactsreportsannotations)
+per CI/CD job.
+
+Set the limit to `0` to disable it. Defaults to `20` on self-managed instances.
+
+To set this limit to `100` on a self-managed instance, run the following command in the
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
+
+```ruby
+Plan.default.actual_limits.update!(ci_job_annotations_num: 100)
+```
+
+### Limit CI/CD job annotations file size
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38337) in GitLab 16.3.
+
+You can set a limit on the maximum size of a CI/CD job [annotation](../ci/yaml/artifacts_reports.md#artifactsreportsannotations).
+
+Set the limit to `0` to disable it. Defaults to 80 KB.
+
+To set this limit to 100 KB on a self-managed installation, run the following in the
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
+
+```ruby
+Plan.default.actual_limits.update!(ci_job_annotations_size: 100.kilobytes)
+```
+
## Instance monitoring and metrics
### Limit inbound incident management alerts
@@ -1045,7 +1104,7 @@ Issues and merge requests enforce these maximums:
## CDN-based limits on GitLab.com
-In addition to application-based limits, GitLab.com is configured to use Cloudflare's standard DDoS protection and Spectrum to protect Git over SSH. Cloudflare terminates client TLS connections but is not application aware and cannot be used for limits tied to users or groups. Cloudflare page rules and rate limits are configured with Terraform. These configurations are [not public](https://about.gitlab.com/handbook/communication/#not-public) because they include security and abuse implementations that detect malicious activities and making them public would undermine those operations.
+In addition to application-based limits, GitLab.com is configured to use Cloudflare's standard DDoS protection and Spectrum to protect Git over SSH. Cloudflare terminates client TLS connections but is not application aware and cannot be used for limits tied to users or groups. Cloudflare page rules and rate limits are configured with Terraform. These configurations are [not public](https://handbook.gitlab.com/handbook/communication/confidentiality-levels/#not-public) because they include security and abuse implementations that detect malicious activities and making them public would undermine those operations.
## Container Repository tag deletion limit
@@ -1074,6 +1133,20 @@ The [changelog API](../api/repositories.md#add-changelog-data-to-a-changelog-fil
- Each namespace (such as a group or a project) can have a maximum of 50 value streams.
- Each value stream can have a maximum of 15 stages.
+## Audit events streaming destination limits
+
+### Custom HTTP Endpoint
+
+- Each top-level group can have a maximum of 5 custom HTTP streaming destinations.
+
+### Google Cloud Logging
+
+- Each top-level group can have a maximum of 5 Google Cloud Logging streaming destinations.
+
+### Amazon S3
+
+- Each top-level group can have a maximum of 5 Amazon S3 streaming destinations.
+
## List all instance limits
To list all instance limit values, run the following from the [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
@@ -1168,7 +1241,8 @@ web_hook_calls: 0,
project_access_token_limit: 0,
google_cloud_logging_configurations: 5,
ml_model_max_file_size: 10737418240,
-limits_history: {}
+limits_history: {},
+audit_events_amazon_s3_configurations: 5
```
Some limit values display as `[FILTERED]` in the list due to
diff --git a/doc/administration/integration/diagrams_net.md b/doc/administration/integration/diagrams_net.md
index 7f8c01ad7bd..13be572d524 100644
--- a/doc/administration/integration/diagrams_net.md
+++ b/doc/administration/integration/diagrams_net.md
@@ -7,6 +7,9 @@ type: reference, howto
# Diagrams.net **(FREE SELF)**
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86206) in GitLab 15.10.
+> - Offline environment support [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116281) in GitLab 16.1.
+
With the [diagrams.net](https://www.diagrams.net/) integration, you can create and embed SVG diagrams in wikis.
The diagram editor is available in both the plain text editor and the rich text editor.
@@ -43,7 +46,7 @@ For more information, see [Run your own diagrams.net server with Docker](https:/
## Enable Diagrams.net integration
1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Diagrams.net**.
diff --git a/doc/administration/integration/kroki.md b/doc/administration/integration/kroki.md
index 0356212d6dd..926833cfa1a 100644
--- a/doc/administration/integration/kroki.md
+++ b/doc/administration/integration/kroki.md
@@ -36,9 +36,9 @@ Supported libraries include:
<!-- vale gitlab.Spelling = NO -->
-- [Bytefield](https://bytefield-svg.deepsymmetry.org/)
+- [Bytefield](https://bytefield-svg.deepsymmetry.org/bytefield-svg/intro.html)
- [D2](https://d2lang.com/tour/intro/)
-- [DBML](https://www.dbml.org/home/)
+- [DBML](https://dbml.dbdiagram.io/home/)
- [Ditaa](https://ditaa.sourceforge.net)
- [Erd](https://github.com/BurntSushi/erd)
- [GraphViz](https://www.graphviz.org/)
@@ -61,7 +61,7 @@ read the [Kroki installation](https://docs.kroki.io/kroki/setup/install/#_images
You need to enable Kroki integration from Settings under Admin Area.
To do that, sign in with an administrator account and follow these steps:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Go to **Settings > General**.
1. Expand the **Kroki** section.
diff --git a/doc/administration/integration/mailgun.md b/doc/administration/integration/mailgun.md
index 87428d27c66..4fe846e99a6 100644
--- a/doc/administration/integration/mailgun.md
+++ b/doc/administration/integration/mailgun.md
@@ -19,7 +19,7 @@ After completing the integration, Mailgun `temporary_failure` and `permanent_fai
## Configure your Mailgun domain
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/359113) the `/-/members/mailgun/permanent_failures` URL in GitLab 15.0.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/359113) the URL to handle both temporary and permanent failures in GitLab 15.0.
+> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/359113) the URL to handle both temporary and permanent failures in GitLab 15.0.
Before you can enable Mailgun in GitLab, set up your own Mailgun endpoints to receive the webhooks.
@@ -43,7 +43,7 @@ After configuring your Mailgun domain for the webhook endpoints,
you're ready to enable the Mailgun integration:
1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, go to **Settings > General** and expand the **Mailgun** section.
1. Select the **Enable Mailgun** checkbox.
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 5e499e302db..0155f0300d4 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -73,8 +73,6 @@ Inside the block you can add any of the diagrams PlantUML supports, such as:
You can add parameters to block definitions:
-- `format`: Can be either `png` (default) or `svg`. Use `svg` with care, as it's
- not supported by all browsers, and isn't supported by Markdown.
- `id`: A CSS ID added to the diagram HTML tag.
- `width`: Width attribute added to the image tag.
- `height`: Height attribute added to the image tag.
@@ -319,7 +317,7 @@ stop;
After configuring your local PlantUML server, you're ready to enable the PlantUML integration:
1. Sign in to GitLab as an [Administrator](../../user/permissions.md) user.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, go to **Settings > General** and expand the **PlantUML** section.
1. Select the **Enable PlantUML** checkbox.
diff --git a/doc/administration/integration/terminal.md b/doc/administration/integration/terminal.md
index 2939e227a04..6e39ab8015c 100644
--- a/doc/administration/integration/terminal.md
+++ b/doc/administration/integration/terminal.md
@@ -112,7 +112,7 @@ they receive a `Connection failed` message.
By default, terminal sessions do not expire. To limit the terminal session
lifetime in your GitLab instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Web terminal**.
1. Set a `max session time`.
diff --git a/doc/administration/job_artifacts_troubleshooting.md b/doc/administration/job_artifacts_troubleshooting.md
index ba60cbd7aba..c2be485a9ad 100644
--- a/doc/administration/job_artifacts_troubleshooting.md
+++ b/doc/administration/job_artifacts_troubleshooting.md
@@ -270,7 +270,7 @@ To change the number of job artifacts listed, change the number in `limit(50)`.
### Delete job artifacts from jobs completed before a specific date
WARNING:
-These commands remove data permanently from both the database and from disk. Before running them, we highly recommend seeking guidance from a Support Engineer, or running them in a test environment with a backup of the instance ready to be restored, just in case.
+These commands remove data permanently from database and storage. Before running them, we highly recommend seeking guidance from a Support Engineer, or running them in a test environment with a backup of the instance ready to be restored, just in case.
If you need to manually remove job artifacts associated with multiple jobs while
**retaining their job logs**, this can be done from the Rails console (`sudo gitlab-rails console`):
@@ -453,7 +453,16 @@ value for the total storage space used by artifacts. To recalculate the artifact
usage statistics for all projects in the instance, you can run this background script:
```shell
-bin/rake 'gitlab:refresh_project_statistics_build_artifacts_size[file.csv]'
+gitlab-rake gitlab:refresh_project_statistics_build_artifacts_size[https://example.com/path/file.csv]
+```
+
+The `https://example.com/path/file.csv` file must list the project IDs for
+all projects for which you want to recalculate artifact storage usage. Use this format for the file:
+
+```csv
+PROJECT_ID
+1
+2
```
The artifact usage value can fluctuate to `0` while the script is running. After
diff --git a/doc/administration/lfs/index.md b/doc/administration/lfs/index.md
index 4659917cf8b..26034ce1d01 100644
--- a/doc/administration/lfs/index.md
+++ b/doc/administration/lfs/index.md
@@ -453,7 +453,7 @@ settings to allow the GitLab domain. See the following documentation
for more details:
1. [AWS S3](https://repost.aws/knowledge-center/s3-configure-cors)
-1. [Google Cloud Storage](https://cloud.google.com/storage/docs/configuring-cors)
+1. [Google Cloud Storage](https://cloud.google.com/storage/docs/using-cors)
1. [Azure Storage](https://learn.microsoft.com/en-us/rest/api/storageservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services).
## Known limitations
diff --git a/doc/administration/license.md b/doc/administration/license.md
index 732c2840217..05b60955ed9 100644
--- a/doc/administration/license.md
+++ b/doc/administration/license.md
@@ -28,7 +28,7 @@ To activate your instance with an activation code:
- Your subscription confirmation email.
- The [Customers Portal](https://customers.gitlab.com/customers/sign_in), on the **Manage Purchases** page.
1. Sign in to your GitLab self-managed instance.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Subscription**.
1. Paste the activation code in **Activation code**.
@@ -65,19 +65,23 @@ This error occurs when you use an activation code to activate your instance, but
You may have connectivity issues due to the following reasons:
-- **You have an offline environment**:
- - Configure your setup to allow connection to GitLab servers. If connection to GitLab servers is not possible, contact your Sales Representative to request a license key. You can also contact [GitLab support](https://about.gitlab.com/support/#contact-support) if you need help finding your Sales Representative.
-- **Customers Portal is not operational**:
- - To check for performance or service disruptions, check the Customers Portal [status](https://status.gitlab.com/).
- **Firewall settings**:
- - Check if your GitLab instance has an encrypted connection to `customers.gitlab.com` (with IP addresses 172.64.146.11 and 104.18.41.245) on port 443:
+ - Confirm that GitLab instance can establish an encrypted connection to `https://customers.gitlab.com` on port 443.
+ Note: IP addresses for `https://customers.gitlab.com` are 172.64.146.11 and 104.18.41.245)
```shell
curl --verbose "https://customers.gitlab.com/"
- ```
+ ```
- - If the curl command returns a failure, either:
+ - If the curl command returns an error, either:
- [Configure a proxy](https://docs.gitlab.com/omnibus/settings/environment-variables.html) in `gitlab.rb` to point to your server.
- - Contact your network administrator to make changes to the proxy.
- - If an SSL inspection appliance is used, you must add the appliance's root CA certificate to `/etc/gitlab/trusted-certs` on the server, then run `gitlab-ctl reconfigure`.
- \ No newline at end of file
+ - Contact your network administrator to make changes to an existing proxy or firewall.
+ - If an SSL inspection appliance is used, you must add the appliance's root CA certificate to `/etc/gitlab/trusted-certs` on your instance, then run `gitlab-ctl reconfigure`.
+
+- **Customers Portal is not operational**:
+ - Check for any active disruptions to the Customers Portal on [status](https://status.gitlab.com/).
+
+- **You have an offline environment**:
+ - If you are unable to configure your setup to allow connection to GitLab servers, contact your Sales Representative to request an [Offline license](https://about.gitlab.com/pricing/licensing-faq/cloud-licensing/#what-is-an-offline-cloud-license).
+
+ For assistance finding your sales representative you can contact [GitLab support](https://about.gitlab.com/support/#contact-support).
diff --git a/doc/administration/license_file.md b/doc/administration/license_file.md
index 5f82536698b..2086e4888a7 100644
--- a/doc/administration/license_file.md
+++ b/doc/administration/license_file.md
@@ -18,7 +18,7 @@ link to the **Add license** page should be displayed.
Otherwise, to add your license:
1. Sign in to GitLab as an administrator.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. In the **Add License** area, add a license by either uploading the file or entering the key.
@@ -96,7 +96,7 @@ To go back to Free features, [delete all expired licenses](#remove-a-license).
To remove a license from a self-managed instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Subscription**.
1. Select **Remove license**.
@@ -107,7 +107,7 @@ Repeat these steps to remove all licenses, including those applied in the past.
To view your license details:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Subscription**.
diff --git a/doc/administration/load_balancer.md b/doc/administration/load_balancer.md
index a862fd46a3f..1662febc8cc 100644
--- a/doc/administration/load_balancer.md
+++ b/doc/administration/load_balancer.md
@@ -113,7 +113,7 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
## Readiness check
-It is strongly recommend that multi-node deployments configure load balancers to use the [readiness check](../administration/monitoring/health_check.md#readiness) to ensure a node is ready to accept traffic, before routing traffic to it. This is especially important when utilizing Puma, as there is a brief period during a restart where Puma doesn't accept requests.
+It is strongly recommend that multi-node deployments configure load balancers to use the [readiness check](../administration/monitoring/health_check.md#readiness) to ensure a node is ready to accept traffic, before routing traffic to it. This is especially important when using Puma, because there is a brief period during a restart where Puma doesn't accept requests.
WARNING:
Using the `all=1` parameter with the readiness check in GitLab versions 15.4 to 15.8 may cause [increased Praefect memory usage](https://gitlab.com/gitlab-org/gitaly/-/issues/4751) and lead to memory errors.
diff --git a/doc/administration/logs/index.md b/doc/administration/logs/index.md
index bfab17d37e8..e093c03a13e 100644
--- a/doc/administration/logs/index.md
+++ b/doc/administration/logs/index.md
@@ -505,22 +505,16 @@ and as follows.
### `sidekiq.log`
+> The default log format for Helm chart installations [changed from `text` to `json`](https://gitlab.com/gitlab-org/charts/gitlab/-/merge_requests/3169) in GitLab 16.0 and later.
+
This file is located at:
- `/var/log/gitlab/sidekiq/current` on Linux package installations.
- `/home/git/gitlab/log/sidekiq.log` on self-compiled installations.
GitLab uses background jobs for processing tasks which can take a long
-time. All information about processing these jobs are written down to
-this file. For example:
-
-```plaintext
-2014-06-10T07:55:20Z 2037 TID-tm504 ERROR: /opt/bitnami/apps/discourse/htdocs/vendor/bundle/ruby/1.9.1/gems/redis-3.0.7/lib/redis/client.rb:228:in `read'
-2014-06-10T18:18:26Z 14299 TID-55uqo INFO: Booting Sidekiq 3.0.0 with redis options {:url=>"redis://localhost:6379/0", :namespace=>"sidekiq"}
-```
-
-Instead of the previous format, you can opt to generate JSON logs for
-Sidekiq. For example:
+time. All information about processing these jobs are written to this
+file. For example:
```json
{
@@ -547,10 +541,25 @@ Sidekiq. For example:
}
```
+Instead of JSON logs, you can opt to generate text logs for Sidekiq. For example:
+
+```plaintext
+2023-05-16T16:08:55.272Z pid=82525 tid=23rl INFO: Initializing websocket
+2023-05-16T16:08:55.279Z pid=82525 tid=23rl INFO: Booted Rails 6.1.7.2 application in production environment
+2023-05-16T16:08:55.279Z pid=82525 tid=23rl INFO: Running in ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c5) [arm64-darwin22]
+2023-05-16T16:08:55.279Z pid=82525 tid=23rl INFO: See LICENSE and the LGPL-3.0 for licensing details.
+2023-05-16T16:08:55.279Z pid=82525 tid=23rl INFO: Upgrade to Sidekiq Pro for more features and support: https://sidekiq.org
+2023-05-16T16:08:55.286Z pid=82525 tid=7p4t INFO: Cleaning working queues
+2023-05-16T16:09:06.043Z pid=82525 tid=7p7d class=ScheduleMergeRequestCleanupRefsWorker jid=efcc73f169c09a514b06da3f INFO: start
+2023-05-16T16:09:06.050Z pid=82525 tid=7p7d class=ScheduleMergeRequestCleanupRefsWorker jid=efcc73f169c09a514b06da3f INFO: arguments: []
+2023-05-16T16:09:06.065Z pid=82525 tid=7p81 class=UserStatusCleanup::BatchWorker jid=e279aa6409ac33031a314822 INFO: start
+2023-05-16T16:09:06.066Z pid=82525 tid=7p81 class=UserStatusCleanup::BatchWorker jid=e279aa6409ac33031a314822 INFO: arguments: []
+```
+
For Linux package installations, add the configuration option:
```ruby
-sidekiq['log_format'] = 'json'
+sidekiq['log_format'] = 'text'
```
For self-compiled installations, edit the `gitlab.yml` and set the Sidekiq
@@ -559,7 +568,7 @@ For self-compiled installations, edit the `gitlab.yml` and set the Sidekiq
```yaml
## Sidekiq
sidekiq:
- log_format: json
+ log_format: text
```
### `sidekiq_client.log`
diff --git a/doc/administration/logs/tracing_correlation_id.md b/doc/administration/logs/tracing_correlation_id.md
index 45c0ce37102..79c8dcf4d81 100644
--- a/doc/administration/logs/tracing_correlation_id.md
+++ b/doc/administration/logs/tracing_correlation_id.md
@@ -25,7 +25,7 @@ You can use your browser's developer tools to monitor and inspect network
activity with the site that you're visiting. See the links below for network monitoring
documentation for some popular browsers.
-- [Network Monitor - Firefox Developer Tools](https://developer.mozilla.org/en-US/docs/Tools/Network_Monitor)
+- [Network Monitor - Firefox Developer Tools](https://firefox-source-docs.mozilla.org/devtools-user/network_monitor/index.html)
- [Inspect Network Activity In Chrome DevTools](https://developer.chrome.com/docs/devtools/network/)
- [Safari Web Development Tools](https://developer.apple.com/safari/tools/)
- [Microsoft Edge Network panel](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/network/)
diff --git a/doc/administration/maintenance_mode/index.md b/doc/administration/maintenance_mode/index.md
index c5674527291..36c702bbda1 100644
--- a/doc/administration/maintenance_mode/index.md
+++ b/doc/administration/maintenance_mode/index.md
@@ -21,7 +21,7 @@ Maintenance Mode allows most external actions that do not change internal state.
Enable Maintenance Mode as an administrator in one of these ways:
- **Web UI**:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Maintenance Mode**, and toggle **Enable Maintenance Mode**.
@@ -46,7 +46,7 @@ Enable Maintenance Mode as an administrator in one of these ways:
Disable Maintenance Mode in one of three ways:
- **Web UI**:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Maintenance Mode**, and toggle **Enable Maintenance Mode**.
@@ -181,7 +181,7 @@ you should disable all cron jobs except for those related to Geo.
To monitor queues and disable jobs:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. In the Sidekiq dashboard, select **Cron** and disable jobs individually or all at once by selecting **Disable All**.
diff --git a/doc/administration/merge_requests_approvals.md b/doc/administration/merge_requests_approvals.md
index 6cd0edf22eb..8c554b00048 100644
--- a/doc/administration/merge_requests_approvals.md
+++ b/doc/administration/merge_requests_approvals.md
@@ -19,7 +19,7 @@ and can no longer be changed:
To enable merge request approval settings for an instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Push Rules**.
1. Expand **Merge request approvals**.
diff --git a/doc/administration/moderate_users.md b/doc/administration/moderate_users.md
index 42f1f26586f..3095f696978 100644
--- a/doc/administration/moderate_users.md
+++ b/doc/administration/moderate_users.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: howto
@@ -42,7 +42,7 @@ sign in.
To view user sign ups pending approval:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Pending approval** tab.
@@ -53,7 +53,7 @@ A user sign up pending approval can be approved or rejected from the Admin Area.
To approve or reject a user sign up:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Pending approval** tab.
@@ -79,7 +79,7 @@ administrators can choose to block the user.
Users can be blocked [via an abuse report](../administration/review_abuse_reports.md#blocking-users),
by removing them in LDAP, or directly from the Admin Area. To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Optional. Select a user.
@@ -103,7 +103,7 @@ Users can also be blocked using the [GitLab API](../api/users.md#block-user).
A blocked user can be unblocked from the Admin Area. To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Blocked** tab.
@@ -120,7 +120,7 @@ Users can also be unblocked using the [GitLab API](../api/users.md#unblock-user)
The unblock option may be unavailable for LDAP users. To enable the unblock option,
the LDAP identity first needs to be deleted:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Blocked** tab.
@@ -160,7 +160,7 @@ Users are notified about account deactivation if
A user can be deactivated from the Admin Area. To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Optional. Select a user.
@@ -189,7 +189,7 @@ Administrators can enable automatic deactivation of users who either:
To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Account and limit** section.
@@ -240,7 +240,7 @@ A deactivated user can be activated from the Admin Area.
To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Deactivated** tab.
@@ -271,7 +271,7 @@ To block a user and hide their contributions, administrators can ban the user.
Users can be banned using the Admin Area. To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Optional. Select a user.
@@ -284,7 +284,7 @@ The banned user does not consume a [seat](../subscriptions/self_managed/index.md
A banned user can be unbanned using the Admin Area. To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Banned** tab.
@@ -299,7 +299,7 @@ The user's state is set to active and they consume a
Use the Admin Area to delete users.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Banned** tab.
@@ -314,7 +314,7 @@ You can only delete a user if there are inherited or direct owners of a group. Y
You can also delete a user and their contributions, such as merge requests, issues, and groups of which they are the only group owner.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Banned** tab.
diff --git a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
deleted file mode 100644
index dbdcdf22007..00000000000
--- a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../index.md'
----
-
-# Self-monitoring project (removed) **(FREE SELF)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/348909)
-in GitLab 14.9 and [removed](https://gitlab.com/groups/gitlab-org/-/epics/10030) in 16.0.
diff --git a/doc/administration/monitoring/performance/gitlab_configuration.md b/doc/administration/monitoring/performance/gitlab_configuration.md
index a1def4764f6..a32a38a11e5 100644
--- a/doc/administration/monitoring/performance/gitlab_configuration.md
+++ b/doc/administration/monitoring/performance/gitlab_configuration.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
GitLab Performance Monitoring is disabled by default. To enable it and change any of its
settings:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Metrics and profiling**
(`/admin/application_settings/metrics_and_profiling`).
diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md
index 72240be0b35..ba0fed0fac1 100644
--- a/doc/administration/monitoring/performance/grafana_configuration.md
+++ b/doc/administration/monitoring/performance/grafana_configuration.md
@@ -35,7 +35,7 @@ see the [GitLab Grafana dashboards](https://gitlab.com/gitlab-org/grafana-dashbo
After setting up Grafana, you can enable a link to access it from the
GitLab sidebar:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Metrics and profiling**
and expand **Metrics - Grafana**.
@@ -43,14 +43,14 @@ GitLab sidebar:
1. Configure the **Grafana URL**. Enter the full URL of the Grafana instance.
1. Select **Save changes**.
-GitLab displays your link in the **Main menu > Admin > Monitoring > Metrics Dashboard**.
+GitLab displays your link in the Admin Area under **Monitoring > Metrics Dashboard**.
## Required Scopes
> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5822) in GitLab 13.10.
-When setting up Grafana through the process above, no scope shows in the screen at
-**Main menu > Admin > Applications > GitLab Grafana**. However, the `read_user` scope is
+When setting up Grafana through the process above, no scope shows in the screen in
+the Admin Area under **Applications > GitLab Grafana**. However, the `read_user` scope is
required and is provided to the application automatically. Setting any scope other than
`read_user` without also including `read_user` leads to this error when you try to sign in using
GitLab as the OAuth provider:
diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md
index 8afec54dab2..65aa2208944 100644
--- a/doc/administration/monitoring/performance/performance_bar.md
+++ b/doc/administration/monitoring/performance/performance_bar.md
@@ -107,7 +107,7 @@ The performance bar is disabled by default for non-administrators. To enable it
for a given group:
1. Sign in as a user with administrator access.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Metrics and profiling**
(`admin/application_settings/metrics_and_profiling`), and expand
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index 6566def823c..d91fd5f8156 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
To enable the GitLab Prometheus metrics:
1. Log in to GitLab as a user with administrator access.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Metrics and profiling**.
1. Find the **Metrics - Prometheus** section, and select **Enable GitLab Prometheus metrics endpoint**.
@@ -107,8 +107,8 @@ The following metrics are available:
| `gitlab_transaction_db_<role>_cached_count_total` | Counter | 13.1 | Counter for total number of cached SQL calls, grouped by database roles (primary/replica) | `controller`, `action` |
| `gitlab_transaction_db_<role>_wal_count_total` | Counter | 14.0 | Counter for total number of WAL (write ahead log location) queries, grouped by database roles (primary/replica) | `controller`, `action` |
| `gitlab_transaction_db_<role>_wal_cached_count_total` | Counter | 14.1 | Counter for total number of cached WAL (write ahead log location) queries, grouped by database roles (primary/replica)| `controller`, `action` |
-| `http_elasticsearch_requests_duration_seconds` **(PREMIUM)** | Histogram | 13.1 | Elasticsearch requests duration during web transactions | `controller`, `action` |
-| `http_elasticsearch_requests_total` **(PREMIUM)** | Counter | 13.1 | Elasticsearch requests count during web transactions | `controller`, `action` |
+| `http_elasticsearch_requests_duration_seconds` **(PREMIUM ALL)** | Histogram | 13.1 | Elasticsearch requests duration during web transactions | `controller`, `action` |
+| `http_elasticsearch_requests_total` **(PREMIUM ALL)** | Counter | 13.1 | Elasticsearch requests count during web transactions | `controller`, `action` |
| `pipelines_created_total` | Counter | 9.4 | Counter of pipelines created | |
| `rack_uncaught_errors_total` | Counter | 9.4 | Rack connections handling uncaught errors count | |
| `user_session_logins_total` | Counter | 9.4 | Counter of how many users have logged in since GitLab was started or restarted | |
@@ -250,18 +250,12 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_job_artifacts_synced_missing_on_primary` | Gauge | 10.7 | Number of job artifacts marked as synced due to the file missing on the primary | `url` |
| `geo_repositories_checksummed` | Gauge | 10.7 | Number of repositories checksummed on primary | `url` |
| `geo_repositories_checksum_failed` | Gauge | 10.7 | Number of repositories failed to calculate the checksum on primary | `url` |
-| `geo_wikis_checksummed` | Gauge | 10.7 | Number of wikis checksummed on primary | `url` |
-| `geo_wikis_checksum_failed` | Gauge | 10.7 | Number of wikis failed to calculate the checksum on primary | `url` |
| `geo_repositories_verified` | Gauge | 10.7 | Number of repositories successfully verified on secondary | `url` |
| `geo_repositories_verification_failed` | Gauge | 10.7 | Number of repositories that failed verification on secondary | `url` |
| `geo_repositories_checksum_mismatch` | Gauge | 10.7 | Number of repositories that checksum mismatch on secondary | `url` |
-| `geo_wikis_verified` | Gauge | 10.7 | Number of wikis successfully verified on secondary | `url` |
-| `geo_wikis_verification_failed` | Gauge | 10.7 | Number of wikis that failed verification on secondary | `url` |
-| `geo_wikis_checksum_mismatch` | Gauge | 10.7 | Number of wikis that checksum mismatch on secondary | `url` |
| `geo_repositories_checked` | Gauge | 11.1 | Number of repositories that have been checked via `git fsck` | `url` |
| `geo_repositories_checked_failed` | Gauge | 11.1 | Number of repositories that have a failure from `git fsck` | `url` |
| `geo_repositories_retrying_verification` | Gauge | 11.2 | Number of repositories verification failures that Geo is actively trying to correct on secondary | `url` |
-| `geo_wikis_retrying_verification` | Gauge | 11.2 | Number of wikis verification failures that Geo is actively trying to correct on secondary | `url` |
| `geo_package_files` | Gauge | 13.0 | Number of package files on primary | `url` |
| `geo_package_files_checksummed` | Gauge | 13.0 | Number of package files checksummed on primary | `url` |
| `geo_package_files_checksum_failed` | Gauge | 13.0 | Number of package files failed to calculate the checksum on primary | `url` |
@@ -507,6 +501,7 @@ instance. For example, `cache` or `shared_state`.
| `gitlab_redis_client_requests_total` | Counter | 13.2 | Number of Redis client requests |
| `gitlab_redis_client_requests_duration_seconds` | Histogram | 13.2 | Redis request latency, excluding blocking commands |
| `gitlab_redis_client_redirections_total` | Counter | 15.10 | Number of Redis Cluster MOVED/ASK redirections, broken down by redirection type |
+| `gitlab_redis_client_requests_pipelined_commands` | Histogram | 16.4 | Number of commands per pipeline sent to a single Redis server |
## Metrics shared directory
diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md
index abdd2f1d0d3..df6dd87c896 100644
--- a/doc/administration/monitoring/prometheus/index.md
+++ b/doc/administration/monitoring/prometheus/index.md
@@ -109,7 +109,7 @@ prometheus['scrape_configs'] = [
### Standalone Prometheus using the Linux package
-The Linux package can be used to configure a standalone Monitoring node running Prometheus and [Grafana](../performance/grafana_configuration.md).
+The Linux package can be used to configure a standalone Monitoring node running Prometheus and [Grafana](../performance/grafana_configuration.md). A standalone Monitoring node is recommended for [GitLab deployments with multiple nodes](../../reference_architectures/index.md).
The steps below are the minimum necessary to configure a Monitoring node running Prometheus and Grafana with the Linux
package:
@@ -169,7 +169,7 @@ ensure that `prometheus['scrape_configs']` is not set in `/etc/gitlab/gitlab.rb`
WARNING:
Prometheus and most exporters don't support authentication. We don't recommend exposing them outside the local network.
-A few configuration changes are required to allow GitLab to be monitored by an external Prometheus server. External servers are recommended for [GitLab deployments with multiple nodes](../../reference_architectures/index.md).
+A few configuration changes are required to allow GitLab to be monitored by an external Prometheus server.
To use an external Prometheus server:
diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md
index aa17452f260..0b12d41eb4e 100644
--- a/doc/administration/object_storage.md
+++ b/doc/administration/object_storage.md
@@ -156,12 +156,12 @@ For the storage-specific form,
[direct upload may become the default](https://gitlab.com/gitlab-org/gitlab/-/issues/27331)
because it does not require a shared folder.
-For configuring object storage in GitLab 13.1 and earlier, or for storage types not
-supported by consolidated form, refer to the following guides:
+For configuring object storage in GitLab 13.1 and earlier, _or_ for storage types not
+For storage types not supported by the consolidated form, refer to the following guides:
| Object storage type | Supported by consolidated form? |
|---------------------|------------------------------------------|
-| [Project-level Secure Files](secure_files.md#using-object-storage) | **{dotted-circle}** No |
+| [Secure Files](secure_files.md#using-object-storage) | **{dotted-circle}** No |
| [Backups](../administration/backup_restore/backup_gitlab.md#upload-backups-to-a-remote-cloud-storage) | **{dotted-circle}** No |
| [Container Registry](packages/container_registry.md#use-object-storage) (optional feature) | **{dotted-circle}** No |
| [Mattermost](https://docs.mattermost.com/configure/file-storage-configuration-settings.html)| **{dotted-circle}** No |
@@ -237,7 +237,7 @@ To set up an instance profile:
}
```
-1. [Attach this role](https://aws.amazon.com/premiumsupport/knowledge-center/attach-replace-ec2-instance-profile/)
+1. [Attach this role](https://repost.aws/knowledge-center/attach-replace-ec2-instance-profile)
to the EC2 instance hosting your GitLab instance.
1. Set the `use_iam_profile` GitLab configuration option to `true`.
diff --git a/doc/administration/operations/fast_ssh_key_lookup.md b/doc/administration/operations/fast_ssh_key_lookup.md
index 270bd778ea3..888ec79d4b6 100644
--- a/doc/administration/operations/fast_ssh_key_lookup.md
+++ b/doc/administration/operations/fast_ssh_key_lookup.md
@@ -121,7 +121,7 @@ users as long as a large file exists.
To disable writes to the `authorized_keys` file:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Performance optimization**.
@@ -141,7 +141,7 @@ This overview is brief. Refer to the above instructions for more context.
1. [Rebuild the `authorized_keys` file](../raketasks/maintenance.md#rebuild-authorized_keys-file).
1. Enable writes to the `authorized_keys` file.
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Performance optimization**.
@@ -165,6 +165,8 @@ Additional technical documentation for `gitlab-sshd` may be found in the
## Troubleshooting
+### SSH traffic slow or high CPU load
+
If your SSH traffic is [slow](https://github.com/linux-pam/linux-pam/issues/270)
or causing high CPU load, be sure to check the size of `/var/log/btmp`, and ensure it is rotated on a regular basis or after reaching a certain size.
If this file is very large, GitLab SSH fast lookup can cause the bottleneck to be hit more frequently, thus decreasing performance even further.
diff --git a/doc/administration/operations/moving_repositories.md b/doc/administration/operations/moving_repositories.md
index c27bedd39de..49746c7cc72 100644
--- a/doc/administration/operations/moving_repositories.md
+++ b/doc/administration/operations/moving_repositories.md
@@ -264,9 +264,16 @@ sudo -u git sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \
git@newserver:/mnt/gitlab/repositories'
```
+<!--- start_remove The following content will be removed on remove_date: '2024-05-16' -->
+
### Thousands of Git repositories: use one `rsync` per repository
WARNING:
+The Rake task `gitlab:list_repos` was
+[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/384361) in GitLab 16.4 and is planned for
+removal in 17.0. Use [backup and restore](#recommended-approach-in-all-cases) instead.
+
+WARNING:
Using `rsync` to migrate Git data can cause data loss and repository corruption.
[These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422).
@@ -292,6 +299,11 @@ This process:
#### Parallel `rsync` for all repositories known to GitLab
WARNING:
+The Rake task `gitlab:list_repos` was
+[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/384361) in GitLab 16.4 and is planned for
+removal in 17.0. Use [backup and restore](#recommended-approach-in-all-cases) instead.
+
+WARNING:
Using `rsync` to migrate Git data can cause data loss and repository corruption.
[These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422).
@@ -353,6 +365,11 @@ cat /home/git/transfer-logs/* | sort | uniq -u |\
#### Parallel `rsync` only for repositories with recent activity
WARNING:
+The Rake task `gitlab:list_repos` was
+[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/384361) in GitLab 16.4 and is planned for
+removal in 17.0. Use [backup and restore](#recommended-approach-in-all-cases) instead.
+
+WARNING:
Using `rsync` to migrate Git data can cause data loss and repository corruption.
[These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422).
@@ -381,3 +398,5 @@ sudo -u git -H bundle exec rake gitlab:list_repos SINCE='2015-10-1 12:00 UTC' |\
/home/git/repositories \
/mnt/gitlab/repositories
```
+
+<!--- end_remove --> \ No newline at end of file
diff --git a/doc/administration/package_information/supported_os.md b/doc/administration/package_information/supported_os.md
index eea4b8035b7..4bc1861a22b 100644
--- a/doc/administration/package_information/supported_os.md
+++ b/doc/administration/package_information/supported_os.md
@@ -28,18 +28,19 @@ architecture.
| Debian 10 | GitLab CE / GitLab EE 12.2.0 | amd64, arm64 | [Debian Install Documentation](https://about.gitlab.com/install/#debian) | 2024 | <https://wiki.debian.org/LTS> |
| Debian 11 | GitLab CE / GitLab EE 14.6.0 | amd64, arm64 | [Debian Install Documentation](https://about.gitlab.com/install/#debian) | 2026 | <https://wiki.debian.org/LTS> |
| OpenSUSE 15.4 | GitLab CE / GitLab EE 15.7.0 | x86_64, aarch64 | [OpenSUSE Install Documentation](https://about.gitlab.com/install/#opensuse-leap) | Nov 2023 | <https://en.opensuse.org/Lifetime> |
+| OpenSUSE 15.5 | GitLab CE / GitLab EE 16.4.0 | x86_64, aarch64 | [OpenSUSE Install Documentation](https://about.gitlab.com/install/#opensuse-leap) | Dec 2024 | <https://en.opensuse.org/Lifetime> |
| RHEL 8 | GitLab CE / GitLab EE 12.8.1 | x86_64, arm64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | May 2029 | [RHEL Details](https://access.redhat.com/support/policy/updates/errata/#Life_Cycle_Dates) |
| RHEL 9 | GitLab CE / GitLab EE 16.0.0 | x86_64, arm64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | May 2032 | [RHEL Details](https://access.redhat.com/support/policy/updates/errata/#Life_Cycle_Dates) |
| SLES 12 | GitLab EE 9.0.0 | x86_64 | [Use OpenSUSE Install Documentation](https://about.gitlab.com/install/#opensuse-leap) | Oct 2027 | <https://www.suse.com/lifecycle/> |
| SLES 15 | GitLab EE 14.8.0 | x86_64 | [Use OpenSUSE Install Documentation](https://about.gitlab.com/install/#opensuse-leap) | Dec 2024 | <https://www.suse.com/lifecycle/> |
-| Oracle Linux | GitLab CE / GitLab EE 8.14.0 | x86_64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | Jul 2024 | <https://www.oracle.com/a/ocom/docs/elsp-lifetime-069338.pdf> |
+| Oracle Linux 7 | GitLab CE / GitLab EE 8.14.0 | x86_64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | Dec 2024 | <https://www.oracle.com/a/ocom/docs/elsp-lifetime-069338.pdf> |
| Scientific Linux | GitLab CE / GitLab EE 8.14.0 | x86_64 | [Use CentOS Install Documentation](https://about.gitlab.com/install/#centos-7) | June 2024 | <https://scientificlinux.org/downloads/sl-versions/sl7/> |
| Ubuntu 18.04 | GitLab CE / GitLab EE 10.7.0 | amd64 | [Ubuntu Install Documentation](https://about.gitlab.com/install/#ubuntu) | April 2023 | <https://wiki.ubuntu.com/Releases> |
| Ubuntu 20.04 | GitLab CE / GitLab EE 13.2.0 | amd64, arm64 | [Ubuntu Install Documentation](https://about.gitlab.com/install/#ubuntu) | April 2025 | <https://wiki.ubuntu.com/Releases> |
| Ubuntu 22.04 | GitLab CE / GitLab EE 15.5.0 | amd64, arm64 | [Ubuntu Install Documentation](https://about.gitlab.com/install/#ubuntu) | April 2027 | <https://wiki.ubuntu.com/Releases> |
| Amazon Linux 2 | GitLab CE / GitLab EE 14.9.0 | amd64, arm64 | [Amazon Linux 2 Install Documentation](https://about.gitlab.com/install/#amazonlinux-2) | June 2025 | <https://aws.amazon.com/amazon-linux-2/faqs/> |
-| Amazon Linux 2022 | GitLab CE / GitLab EE 15.9.0 | amd64, arm64 | [Amazon Linux 2022 Install Documentation](https://about.gitlab.com/install/#amazonlinux-2022) | October 2027 | <https://aws.amazon.com/linux/amazon-linux-2022/faqs/> |
-| Raspberry Pi OS (Buster) (formerly known as Raspbian Buster) | GitLab CE 12.2.0 | armhf | [Raspberry Pi Install Documentation](https://about.gitlab.com/install/#raspberry-pi-os) | 2024 | [Raspberry Pi Details](https://www.raspberrypi.com/news/new-old-functionality-with-raspberry-pi-os-legacy/) |
+| Amazon Linux 2023 | GitLab CE / GitLab EE 16.3.0 | amd64, arm64 | [Amazon Linux 2023 Install Documentation](https://about.gitlab.com/install/#amazonlinux-2023) | 2028 | <https://docs.aws.amazon.com/linux/al2023/ug/release-cadence.html> |
+| Raspberry Pi OS (Buster) (formerly known as Raspbian Buster) | GitLab CE 12.2.0 | armhf | [Raspberry Pi Install Documentation](https://about.gitlab.com/install/#raspberry-pi-os) | June 2024 | [Raspberry Pi Details](https://www.raspberrypi.com/news/new-old-functionality-with-raspberry-pi-os-legacy/) |
| Raspberry Pi OS (Bullseye) | GitLab CE 15.5.0 | armhf | [Raspberry Pi Install Documentation](https://about.gitlab.com/install/#raspberry-pi-os) | 2026 | [Raspberry Pi Details](https://www.raspberrypi.com/news/raspberry-pi-os-debian-bullseye/) |
NOTE:
diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md
index 384df9a6e6a..dcc6b768eed 100644
--- a/doc/administration/packages/container_registry.md
+++ b/doc/administration/packages/container_registry.md
@@ -343,7 +343,7 @@ the Container Registry by themselves, follow the steps below.
In GitLab, tokens for the Container Registry expire every five minutes.
To increase the token duration:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Container Registry**.
@@ -500,7 +500,7 @@ To configure the `s3` storage driver for a Linux package installation:
`bucket_name.host/object`. [Set to false for AWS S3](https://aws.amazon.com/blogs/aws/amazon-s3-path-deprecation-plan-the-rest-of-the-story/).
You can set a rate limit on connections to S3 to avoid 503 errors from the S3 API. To do this,
- set `maxrequestspersecond` to a number within the [S3 request rate threshold](https://repost.aws/knowledge-center/s3-503-within-request-rate-prefix):
+ set `maxrequestspersecond` to a number within the [S3 request rate threshold](https://repost.aws/knowledge-center/http-5xx-errors-s3):
```ruby
registry['storage'] = {
@@ -823,7 +823,7 @@ In the examples below we set the Registry's port to `5010`.
## Disable Container Registry per project
If Registry is enabled in your GitLab instance, but you don't need it for your
-project, you can [disable it from your project's settings](../../user/project/settings/index.md#configure-project-visibility-features-and-permissions).
+project, you can [disable it from your project's settings](../../user/project/settings/index.md#configure-project-features-and-permissions).
## Use an external container registry with GitLab as an auth endpoint
@@ -1252,6 +1252,16 @@ itself on the system so that the `gitlab-ctl` command can bring the registry ser
Also, there's no way to save progress or results during the mark phase of the process. Only once
blobs start being deleted is anything permanent done.
+### Continuous Zero Downtime Garbage Collection **(BETA)**
+
+You can run garbage collection in the background without the need to schedule it or require read-only mode,
+if you migrate to the [metadata database (beta)](#use-a-postgresql-database-for-metadata).
+
+NOTE:
+If you would like to try this [beta feature](../../policy/experiment-beta-support.md#beta),
+you should review the [known limitations](#known-limitations). If you have any feedback,
+you can let us know in the [feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/423459).
+
## Configure GitLab and Registry to run on separate nodes (Linux package installations)
By default, package assumes that both services are running on the same node.
@@ -1353,6 +1363,42 @@ including all the supported storage backends. To migrate to the GitLab Container
you can follow the instructions on this page, and use the same storage backend as the Distribution Registry.
The GitLab Container Registry should accept the same configuration that you are using for the Distribution Registry.
+## Use a PostgreSQL database for metadata **(FREE SELF BETA)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/423459) in GitLab 16.4 as a [Beta feature](../../policy/experiment-beta-support.md) for self-managed GitLab instances.
+
+WARNING:
+While the metadata database is already in use on GitLab.com, it is in early beta for self-managed GitLab instances.
+
+By default, the container registry uses object storage to persist metadata
+related to container images. This method to store metadata limits how efficiently
+the data can be accessed, especially data spanning multiple images, such as when listing tags.
+By using a database to store this data, many new features are possible, including
+[online garbage collection](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/db/online-garbage-collection.md)
+which removes old data automatically with zero downtime.
+
+This database works in conjunction with the object storage already used by the registry, but does not replace object storage.
+You must continue to maintain an object storage solution even after migrating to a metadata database.
+
+### Known Limitations
+
+- No support for online migrations.
+- Geo Support is not confirmed.
+- Registry database migrations must be ran manually when upgrading versions.
+
+### Migration Instructions and Feedback
+
+Instructions on how to migrate to the database may be found in the [feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/423459) for the beta period.
+This issue also serves as a place to report issues and to get an overview of the beta status.
+
+### Metadata database feature support
+
+You can migrate existing registries to the metadata database, and use online garbage collection.
+
+Some database-enabled features are only enabled for GitLab.com and automatic database provisioning for
+the registry database is not available. Review the feature support table in the [feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/423459#supported-feature-status)
+for the status of features related to the container registry database.
+
## Troubleshooting
Before diving in to the following sections, here's some basic troubleshooting:
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index c84e5eb8c8c..f64c53e28a2 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -141,8 +141,8 @@ The Pages daemon doesn't listen to the outside world.
1. Set the external URL for GitLab Pages in `/etc/gitlab/gitlab.rb`:
```ruby
- external_url "http://gitlab.example.com" # external_url here is only for reference
- pages_external_url "http://pages.example.com" # not a subdomain of external_url
+ external_url "http://example.com" # external_url here is only for reference
+ pages_external_url 'http://example.io' # Important: not a subdomain of external_url, so cannot be http://pages.example.com
```
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
@@ -163,12 +163,12 @@ URL scheme: `https://<namespace>.example.io/<project_slug>`
NGINX proxies all requests to the daemon. Pages daemon doesn't listen to the
outside world.
-1. Place the `example.io` certificate and key inside `/etc/gitlab/ssl`.
+1. Place the wildcard LTS certificate for `*.example.io` and the key inside `/etc/gitlab/ssl`.
1. In `/etc/gitlab/gitlab.rb` specify the following configuration:
```ruby
- external_url "https://gitlab.example.com" # external_url here is only for reference
- pages_external_url "https://pages.example.com" # not a subdomain of external_url
+ external_url "https://example.com" # external_url here is only for reference
+ pages_external_url 'https://example.io' # Important: not a subdomain of external_url, so cannot be https://pages.example.com
pages_nginx['redirect_http_to_https'] = true
```
@@ -211,8 +211,8 @@ This setup is primarily intended to be used when [installing a GitLab POC on Ama
1. In `/etc/gitlab/gitlab.rb` specify the following configuration:
```ruby
- external_url "https://gitlab.example.com" # external_url here is only for reference
- pages_external_url "https://pages.example.com" # not a subdomain of external_url
+ external_url "https://example.com" # external_url here is only for reference
+ pages_external_url 'https://example.io' # Important: not a subdomain of external_url, so cannot be https://pages.example.com
pages_nginx['enable'] = true
pages_nginx['listen_port'] = 80
@@ -334,8 +334,8 @@ world. Custom domains are supported, but no TLS.
1. In `/etc/gitlab/gitlab.rb` specify the following configuration:
```ruby
- external_url "http://gitlab.example.com" # external_url here is only for reference
- pages_external_url "http://pages.example.com" # not a subdomain of external_url
+ external_url "http://example.com" # external_url here is only for reference
+ pages_external_url 'http://example.io' # Important: not a subdomain of external_url, so cannot be http://pages.example.com
nginx['listen_addresses'] = ['192.0.2.1'] # The primary IP of the GitLab instance
pages_nginx['enable'] = false
gitlab_pages['external_http'] = ['192.0.2.2:80', '[2001:db8::2]:80'] # The secondary IPs for the GitLab Pages daemon
@@ -361,12 +361,12 @@ In that case, the Pages daemon is running, NGINX still proxies requests to
the daemon but the daemon is also able to receive requests from the outside
world. Custom domains and TLS are supported.
-1. Place the `example.io` certificate and key inside `/etc/gitlab/ssl`.
+1. Place the wildcard LTS certificate for `*.example.io` and the key inside `/etc/gitlab/ssl`.
1. In `/etc/gitlab/gitlab.rb` specify the following configuration:
```ruby
- external_url "https://gitlab.example.com" # external_url here is only for reference
- pages_external_url "https://pages.example.com" # not a subdomain of external_url
+ external_url "https://example.com" # external_url here is only for reference
+ pages_external_url 'https://example.io' # Important: not a subdomain of external_url, so cannot be https://pages.example.com
nginx['listen_addresses'] = ['192.0.2.1'] # The primary IP of the GitLab instance
pages_nginx['enable'] = false
gitlab_pages['external_http'] = ['192.0.2.2:80', '[2001:db8::2]:80'] # The secondary IPs for the GitLab Pages daemon
@@ -406,7 +406,7 @@ domain as a custom domain to their project.
If your user base is private or otherwise trusted, you can disable the
verification requirement:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Preferences**.
1. Expand **Pages**.
@@ -424,7 +424,7 @@ sites served under a custom domain.
To enable it:
1. Choose an email address on which you want to receive notifications about expiring domains.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Preferences**.
1. Expand **Pages**.
@@ -478,7 +478,7 @@ pre-existing applications must modify the GitLab Pages OAuth application. Follow
this:
1. Enable [access control](#access-control).
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Applications**.
1. Expand **GitLab Pages**.
@@ -498,7 +498,7 @@ This can be helpful to restrict information published with Pages websites to the
of your instance only.
To do that:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Preferences**.
1. Expand **Pages**.
@@ -689,7 +689,7 @@ Prerequisite:
To set the global maximum pages size for a project:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Preferences**.
1. Expand **Pages**.
@@ -704,7 +704,7 @@ Prerequisite:
To set the maximum size of each GitLab Pages site in a group, overriding the inherited setting:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Settings > General**.
1. Expand **Pages**.
1. Enter a value under **Maximum size** in MB.
@@ -718,7 +718,7 @@ Prerequisite:
To set the maximum size of GitLab Pages site in a project, overriding the inherited setting:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. In **Maximum size of pages**, enter the size in MB.
1. Select **Save changes**.
@@ -731,7 +731,7 @@ Prerequisite:
To set the maximum number of GitLab Pages custom domains for a project:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Preferences**, and expand **Pages**.
1. Enter a value for **Maximum number of custom domains per project**. Use `0` for unlimited domains.
diff --git a/doc/administration/pages/source.md b/doc/administration/pages/source.md
index 97dacfc1902..fcbc04ed0c3 100644
--- a/doc/administration/pages/source.md
+++ b/doc/administration/pages/source.md
@@ -479,7 +479,7 @@ The default for the maximum size of unpacked archives per project is 100 MB.
To change this value:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Preferences**.
1. Expand **Pages**.
diff --git a/doc/administration/pages/troubleshooting.md b/doc/administration/pages/troubleshooting.md
index a103c793763..be5b8ba27ee 100644
--- a/doc/administration/pages/troubleshooting.md
+++ b/doc/administration/pages/troubleshooting.md
@@ -152,7 +152,7 @@ This can happen to GitLab instances with multiple servers
running both the core GitLab application and GitLab Pages. This can also happen when a single
container is running both the core GitLab application and GitLab Pages.
-AWS [recommends using an IP target type](https://aws.amazon.com/premiumsupport/knowledge-center/target-connection-fails-load-balancer/)
+AWS [recommends using an IP target type](https://repost.aws/knowledge-center/target-connection-fails-load-balancer)
to resolve this issue.
Turning off [client IP preservation](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#client-ip-preservation)
@@ -170,7 +170,7 @@ Upgrading to an [officially supported operating system](https://about.gitlab.com
This problem comes from the permissions of the GitLab Pages OAuth application. To fix it:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Applications > GitLab Pages**.
1. Edit the application.
@@ -214,7 +214,7 @@ You may see this error if `pages_external_url` was updated at some point of time
1. Check the [System OAuth application](../../integration/oauth_provider.md#create-an-instance-wide-application):
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Applications** and then **Add new application**.
1. Ensure the **Callback URL/Redirect URI** is using the protocol (HTTP or HTTPS) that
diff --git a/doc/administration/polling.md b/doc/administration/polling.md
index 50dbc7467d3..b27613663da 100644
--- a/doc/administration/polling.md
+++ b/doc/administration/polling.md
@@ -26,7 +26,7 @@ The default value (`1`) is recommended for the majority of GitLab installations.
To adjust the polling interval multiplier:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Preferences**.
1. Expand **Polling interval multiplier**.
diff --git a/doc/administration/postgresql/database_load_balancing.md b/doc/administration/postgresql/database_load_balancing.md
index f8b6be1fb21..d640dbe9341 100644
--- a/doc/administration/postgresql/database_load_balancing.md
+++ b/doc/administration/postgresql/database_load_balancing.md
@@ -182,9 +182,9 @@ To configure these options with a hosts list, use the following example:
```ruby
gitlab_rails['db_load_balancing'] = {
- 'hosts' => ['primary.example.com', 'secondary1.example.com', 'secondary2.example.com']
- 'max_replication_difference' => 16777216 # 16 MB
- 'max_replication_lag_time' => 30
+ 'hosts' => ['primary.example.com', 'secondary1.example.com', 'secondary2.example.com'],
+ 'max_replication_difference' => 16777216, # 16 MB
+ 'max_replication_lag_time' => 30,
'replica_check_interval' => 30
}
```
diff --git a/doc/administration/postgresql/replication_and_failover.md b/doc/administration/postgresql/replication_and_failover.md
index c547e5c3638..a1fc8c49ee3 100644
--- a/doc/administration/postgresql/replication_and_failover.md
+++ b/doc/administration/postgresql/replication_and_failover.md
@@ -1086,7 +1086,7 @@ Reverting the PostgreSQL upgrade with `gitlab-ctl revert-pg-upgrade` has the sam
`gitlab-ctl pg-upgrade`. You should follow the same procedure by first stopping the replicas,
then reverting the leader, and finally reverting the replicas.
-### Near zero downtime upgrade of PostgreSQL in a Patroni cluster (Experimental)
+### Near zero downtime upgrade of PostgreSQL in a Patroni cluster **(EXPERIMENT)**
Patroni enables you to run a major PostgreSQL upgrade without shutting down the cluster. However, this
requires additional resources to host the new Patroni nodes with the upgraded PostgreSQL. In practice, with this
diff --git a/doc/administration/raketasks/github_import.md b/doc/administration/raketasks/github_import.md
index 1babafc902e..82f3ffa2193 100644
--- a/doc/administration/raketasks/github_import.md
+++ b/doc/administration/raketasks/github_import.md
@@ -18,6 +18,9 @@ Bear in mind that the syntax is very specific. Remove any spaces in the argument
before/after the brackets. Also, some shells (for example, Zsh) can interpret the open/close brackets
(`[]`) separately. You may want to either escape the brackets or use double quotes.
+You can only import repositories that are in the namespace of the owner of the GitHub personal access token being used to import. For more information, see
+[issue 424105](https://gitlab.com/gitlab-org/gitlab/-/issues/424105).
+
Prerequisite:
- At least the Maintainer role on the destination group to import to.
diff --git a/doc/administration/raketasks/ldap.md b/doc/administration/raketasks/ldap.md
index 4a657b04bdc..e6700288631 100644
--- a/doc/administration/raketasks/ldap.md
+++ b/doc/administration/raketasks/ldap.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index 87cce30723e..cdb70ca715b 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -176,13 +176,15 @@ Running? ... yes
Checking Sidekiq ... Finished
-Checking GitLab ...
+Checking GitLab App...
Database config exists? ... yes
Database is SQLite ... no
All migrations up? ... yes
GitLab config exists? ... yes
-GitLab config outdated? ... no
+GitLab config up to date? ... no
+Cable config exists? ... yes
+Resque config exists? ... yes
Log directory writable? ... yes
Tmp directory writable? ... yes
Init script exists? ... yes
@@ -359,7 +361,7 @@ status in the output of the `sudo gitlab-rake db:migrate:status` command.
sudo gitlab-ctl restart sidekiq
```
-## Rebuild database indexes (Experiment)
+## Rebuild database indexes **(EXPERIMENT)**
WARNING:
This feature is experimental, and isn't enabled by default. Use caution when
diff --git a/doc/administration/raketasks/service_desk_email.md b/doc/administration/raketasks/service_desk_email.md
index 8d8585bb171..21b4050a93b 100644
--- a/doc/administration/raketasks/service_desk_email.md
+++ b/doc/administration/raketasks/service_desk_email.md
@@ -12,7 +12,7 @@ The following are Service Desk email-related Rake tasks.
## Secrets
-GitLab can use [Service Desk email](../../user/project/service_desk/index.md#configure-service-desk-alias-email) secrets read from an encrypted file instead of storing them in plaintext in the file system. The following Rake tasks are provided for updating the contents of the encrypted file.
+GitLab can use [Service Desk email](../../user/project/service_desk/configure.md#configure-service-desk-alias-email) secrets read from an encrypted file instead of storing them in plaintext in the file system. The following Rake tasks are provided for updating the contents of the encrypted file.
### Show secret
diff --git a/doc/administration/raketasks/storage.md b/doc/administration/raketasks/storage.md
index 9e0a89fa7cb..ce931e78c2b 100644
--- a/doc/administration/raketasks/storage.md
+++ b/doc/administration/raketasks/storage.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
This is a collection of Rake tasks to help you list and migrate
existing projects and their attachments to the new
-[hashed storage](../repository_storage_types.md) that GitLab
+[hashed storage](../repository_storage_paths.md) that GitLab
uses to organize the Git data.
## List projects and attachments
@@ -75,7 +75,7 @@ To have a summary and then a list of projects and their attachments using hashed
## Migrate to hashed storage
WARNING:
-In GitLab 13.0, [hashed storage](../repository_storage_types.md#hashed-storage)
+In GitLab 13.0, [hashed storage](../repository_storage_paths.md#hashed-storage)
is enabled by default and the legacy storage is deprecated.
GitLab 14.0 eliminates support for legacy storage. If you're on GitLab
13.0 and later, switching new projects to legacy storage is not possible.
@@ -109,7 +109,7 @@ sudo gitlab-rake gitlab:storage:migrate_to_hashed ID_FROM=50 ID_TO=100
To monitor the progress in GitLab:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
1. Watch how long the `hashed_storage:hashed_storage_project_migrate` queue
@@ -129,7 +129,7 @@ You only need the `gitlab:storage:migrate_to_hashed` Rake task to migrate your r
## Rollback from hashed storage to legacy storage
WARNING:
-In GitLab 13.0, [hashed storage](../repository_storage_types.md#hashed-storage)
+In GitLab 13.0, [hashed storage](../repository_storage_paths.md#hashed-storage)
is enabled by default and the legacy storage is deprecated.
GitLab 14.0 eliminates support for legacy storage. If you're on GitLab
13.0 and later, switching new projects to legacy storage is not possible.
diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md
index c94c76c6532..92f9205e76d 100644
--- a/doc/administration/reference_architectures/10k_users.md
+++ b/doc/administration/reference_architectures/10k_users.md
@@ -500,7 +500,7 @@ cluster to be used with GitLab.
You can optionally use a [third party external service for PostgreSQL](../../administration/postgresql/external.md).
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
If you use a third party external service:
@@ -1277,7 +1277,7 @@ you are using Geo, where separate database instances are required for handling r
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
minimal.
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md
index 2b91d493145..87e2ff157ab 100644
--- a/doc/administration/reference_architectures/25k_users.md
+++ b/doc/administration/reference_architectures/25k_users.md
@@ -517,7 +517,7 @@ cluster to be used with GitLab.
You can optionally use a [third party external service for PostgreSQL](../../administration/postgresql/external.md).
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
If you use a third party external service:
@@ -1296,7 +1296,7 @@ you are using Geo, where separate database instances are required for handling r
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
minimal.
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md
index bd184c372b3..8f22343e770 100644
--- a/doc/administration/reference_architectures/2k_users.md
+++ b/doc/administration/reference_architectures/2k_users.md
@@ -249,7 +249,7 @@ to be used with GitLab.
You can optionally use a [third party external service for PostgreSQL](../../administration/postgresql/external.md).
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
If you use a third party external service:
diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md
index cf2d9667481..2d40adf8166 100644
--- a/doc/administration/reference_architectures/3k_users.md
+++ b/doc/administration/reference_architectures/3k_users.md
@@ -787,7 +787,7 @@ cluster to be used with GitLab.
You can optionally use a [third party external service for PostgreSQL](../../administration/postgresql/external.md).
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
If you use a third party external service:
@@ -1223,7 +1223,7 @@ you are using Geo, where separate database instances are required for handling r
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
minimal.
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md
index 2187b0ff02c..6f09077cab7 100644
--- a/doc/administration/reference_architectures/50k_users.md
+++ b/doc/administration/reference_architectures/50k_users.md
@@ -509,7 +509,7 @@ cluster to be used with GitLab.
You can optionally use a [third party external service for PostgreSQL](../../administration/postgresql/external.md).
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
If you use a third party external service:
@@ -1290,7 +1290,7 @@ you are using Geo, where separate database instances are required for handling r
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
minimal.
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
Examples of the above could include [Google's Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) or [Amazon RDS](https://aws.amazon.com/rds/).
diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md
index 2b85426de58..7666e7cc0b5 100644
--- a/doc/administration/reference_architectures/5k_users.md
+++ b/doc/administration/reference_architectures/5k_users.md
@@ -780,7 +780,7 @@ cluster to be used with GitLab.
You can optionally use a [third party external service for PostgreSQL](../../administration/postgresql/external.md).
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
If you use a third party external service:
@@ -1217,7 +1217,7 @@ you are using Geo, where separate database instances are required for handling r
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
minimal.
-A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/versions/gitlab_14_changes.md#1440). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
diff --git a/doc/administration/reference_architectures/index.md b/doc/administration/reference_architectures/index.md
index 98bbcc464b8..2ad9380a00f 100644
--- a/doc/administration/reference_architectures/index.md
+++ b/doc/administration/reference_architectures/index.md
@@ -107,9 +107,19 @@ This is an alternative and more **advanced** setup compared to a standard Refere
### GitLab Geo (Cross Regional Distribution / Disaster Recovery)
-With [GitLab Geo](../geo/index.md) you can have both distributed environments in different regions and a full Disaster Recovery (DR) setup in place. With this setup you would have 2 or more separate environments, with one being a primary that gets replicated to the others. In the rare event the primary site went down completely you could fail over to one of the other environments.
+With [GitLab Geo](../geo/index.md), you can achieve distributed environments in
+different regions with a full Disaster Recovery (DR) setup in place. GitLab Geo
+requires at least two separate environments:
-This is an **advanced and complex** setup and should only be undertaken if you have DR as a key requirement. Decisions then on how each environment are configured would also need to be taken, such as if each environment itself would be the full size and / or have HA.
+- One primary site.
+- One or more secondary sites that serve as replicas.
+
+If the primary site becomes unavailable, you can fail over to one of the secondary sites.
+
+This **advanced and complex** setup should only be undertaken if DR is
+a key requirement for your environment. You must also make additional decisions
+on how each site is configured, such as if each secondary site would be the
+same architecture as the primary, or if each site is configured for HA.
### Cloud provider services
@@ -194,7 +204,7 @@ However, additional workloads can multiply the impact of operations by triggerin
You may need to adjust the suggested specifications to compensate if you use, for example:
- Security software on the nodes.
-- Hundreds of concurrent CI jobs for [large repositories](../../ci/large_repositories/index.md).
+- Hundreds of concurrent CI jobs for [large repositories](../../user/project/repository/managing_large_repositories.md).
- Custom scripts that [run at high frequency](../logs/log_parsing.md#print-top-api-user-agents).
- [Integrations](../../integration/index.md) in many large projects.
- [Server hooks](../server_hooks.md).
@@ -334,7 +344,7 @@ If you choose to use a third party external service:
Several database cloud provider services are known not to support the above or have been found to have other issues and aren't recommended:
-- [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is incompatible and not supported. See [14.4.0](../../update/index.md#1440) for more details.
+- [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is incompatible and not supported. See [14.4.0](../../update/versions/gitlab_14_changes.md#1440) for more details.
- [Azure Database for PostgreSQL Single Server](https://azure.microsoft.com/en-gb/products/postgresql/#overview) is not supported for use due to notable performance / stability issues or missing functionality. See [Recommendation Notes for Azure](#recommendation-notes-for-azure) for more details.
- [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB cluster](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo.
- [Amazon RDS Multi-AZ DB instance](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZSingleStandby.html) is a separate product and is supported.
@@ -413,7 +423,7 @@ For more information, see our [handbook page](https://about.gitlab.com/handbook/
Testing occurs against all reference architectures and cloud providers in an automated and ad-hoc fashion. This is done by two tools:
-- The [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) for building the environments.
+- The [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) Terraform and Ansible scripts for building the environments.
- The [GitLab Performance Tool](https://gitlab.com/gitlab-org/quality/performance) for performance testing.
Network latency on the test environments between components on all Cloud Providers were measured at <5 ms. This is shared as an observation and not as an implicit recommendation.
diff --git a/doc/administration/reporting/git_abuse_rate_limit.md b/doc/administration/reporting/git_abuse_rate_limit.md
index 270a7cb4800..7e2c340f20d 100644
--- a/doc/administration/reporting/git_abuse_rate_limit.md
+++ b/doc/administration/reporting/git_abuse_rate_limit.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -21,7 +21,7 @@ GitLab team members can view more information in this confidential epic:
## Configure Git abuse rate limiting
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Reporting**.
1. Expand **Git abuse rate limit**.
@@ -41,7 +41,7 @@ If automatic banning is enabled, an email notification is sent when a user is ab
## Unban a user
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Banned** tab and search for the account you want to unban.
diff --git a/doc/administration/reporting/ip_addr_restrictions.md b/doc/administration/reporting/ip_addr_restrictions.md
index 5b749c62c30..2e152b0b176 100644
--- a/doc/administration/reporting/ip_addr_restrictions.md
+++ b/doc/administration/reporting/ip_addr_restrictions.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -19,7 +19,7 @@ unique IP addresses. Therefore, the IP addresses per user limit should take into
## Configure IP address restrictions
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Reporting**.
1. Expand **Spam and Anti-bot Protection**.
diff --git a/doc/administration/reporting/spamcheck.md b/doc/administration/reporting/spamcheck.md
index 8e478729299..c92336a39b9 100644
--- a/doc/administration/reporting/spamcheck.md
+++ b/doc/administration/reporting/spamcheck.md
@@ -40,7 +40,7 @@ Spamcheck is only available for package-based installations:
## Configure GitLab to use Spamcheck
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Reporting**.
1. Expand **Spam and Anti-bot Protection**.
diff --git a/doc/administration/repository_checks.md b/doc/administration/repository_checks.md
index 1a33b6b5746..241f88793ff 100644
--- a/doc/administration/repository_checks.md
+++ b/doc/administration/repository_checks.md
@@ -20,7 +20,7 @@ committed to a repository. GitLab administrators can:
To check a project's repository using GitLab UI:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Projects**.
1. Select the project to check.
@@ -33,7 +33,7 @@ project page in the Admin Area. If the checks fail, see [what to do](#what-to-do
Instead of checking repositories manually, GitLab can be configured to run the checks periodically:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Repository** (`/admin/application_settings/repository`).
1. Expand the **Repository maintenance** section.
@@ -65,7 +65,7 @@ You can run [`git fsck`](https://git-scm.com/docs/git-fsck) using the command li
by default.
- For GitLab Helm chart installations, repositories are stored in the `/home/git/repositories` directory inside the
Gitaly pod by default.
-1. [Identify the subdirectory that contains the repository](repository_storage_types.md#from-project-name-to-hashed-path)
+1. [Identify the subdirectory that contains the repository](repository_storage_paths.md#from-project-name-to-hashed-path)
that you need to check.
1. Run the check. For example:
@@ -87,7 +87,7 @@ If a repository check fails, locate the error in the [`repocheck.log` file](logs
If periodic repository checks cause false alarms, you can clear all repository check states:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Repository** (`/admin/application_settings/repository`).
1. Expand the **Repository maintenance** section.
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
index c09c88ee020..a3e0158fd24 100644
--- a/doc/administration/repository_storage_paths.md
+++ b/doc/administration/repository_storage_paths.md
@@ -9,144 +9,203 @@ info: To determine the technical writer assigned to the Stage/Group associated w
GitLab stores [repositories](../user/project/repository/index.md) on repository storage. Repository
storage is either:
-- A `gitaly_address`, which points to a [Gitaly node](gitaly/index.md).
-- A `path`, which points directly to the directory where the repositories are stored. GitLab
- directly accessing a directory containing repositories
- [is deprecated](https://gitlab.com/gitlab-org/gitaly/-/issues/1690).
- GitLab should be configured to access GitLab repositories through a `gitaly_address`.
-
-GitLab allows you to define multiple repository storages to distribute the storage load between
-several mount points. For example:
-
-- When using Gitaly (Linux package installation-style configuration):
-
- ```ruby
- git_data_dirs({
- 'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
- 'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
- })
- ```
-
-- When using direct repository storage (self-compiled installation-style configuration):
+- Physical storage configured with a `gitaly_address` that points to a [Gitaly node](gitaly/index.md).
+- [Virtual storage](gitaly/index.md#virtual-storage) that stores repositories on a Gitaly Cluster.
- ```plaintext
- default:
- gitaly_address: tcp://gitaly1.example:8075
- storage2:
- gitaly_address: tcp://gitaly2.example:8075
- ```
+WARNING:
+Repository storage could be configured as a `path` that points directly to the directory where the repositories are
+stored. GitLab directly accessing a directory containing repositories is deprecated. You should configure GitLab to
+access repositories through a physical or virtual storage.
For more information on:
-- Configuring Gitaly, see [Configure Gitaly](gitaly/index.md#configure-gitaly).
-- Configuring direct repository access, see the following section below.
+- Configuring Gitaly, see [Configure Gitaly](gitaly/configure_gitaly.md).
+- Configuring Gitaly Cluster, see [Configure Gitaly Cluster](gitaly/praefect.md).
-## Configure repository storage paths
+## Hashed storage
-WARNING:
-The following information is for configuring GitLab to directly access repositories. This
-configuration option is deprecated in favor of using [Gitaly](gitaly/index.md).
-[Issue 403318](https://gitlab.com/gitlab-org/gitlab/-/issues/403318) proposes to remove this configuration option.
+> **Storage name** field [renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128416) from **Gitaly storage name** and **Relative path** field [renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128416) from **Gitaly relative path** in GitLab 16.3.
-To configure repository storage paths:
+Hashed storage stores projects on disk in a location based on a hash of the project's ID. This makes the folder
+structure immutable and eliminates the need to synchronize state from URLs to disk structure. This means that renaming a
+group, user, or project:
-1. Edit the necessary configuration files:
- - `/etc/gitlab/gitlab.rb`, for Linux package installations.
- - `gitlab.yml`, for self-compiled installations.
-1. Add the required repository storage paths.
+- Costs only the database transaction.
+- Takes effect immediately.
-For repository storage paths:
+The hash also helps spread the repositories more evenly on the disk. The top-level directory
+contains fewer folders than the total number of top-level namespaces.
-- You must have at least one storage path called `default`.
-- The paths are defined in key-value pairs. Apart from `default`, the key can be any name you choose
- to name the file path.
-- The target directories and any of its sub paths must not be a symlink.
-- No target directory may be a sub-directory of another. That is, no nesting. For example, the
- following configuration is invalid:
+The hash format is based on the hexadecimal representation of a SHA256, calculated with
+`SHA256(project.id)`. The top-level folder uses the first two characters, followed by another folder
+with the next two characters. They are both stored in a special `@hashed` folder so they can
+co-exist with existing legacy storage projects. For example:
- ```plaintext
- default:
- path: /mnt/git-storage-1
- storage2:
- path: /mnt/git-storage-1/git-storage-2 # <- NOT OK because of nesting
- ```
+```ruby
+# Project's repository:
+"@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}.git"
-### Configure for backups
+# Wiki's repository:
+"@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}.wiki.git"
+```
-For [backups](../administration/backup_restore/index.md) to work correctly:
+### Translate hashed storage paths
-- The repository storage path cannot be a mount point.
-- The GitLab user must have correct permissions for the parent directory of the path.
+Troubleshooting problems with the Git repositories, adding hooks, and other tasks requires you
+translate between the human-readable project name and the hashed storage path. You can translate:
-The Linux package takes care of these issues for you but for self-compiled installations, you should be extra
-careful.
+- From a [project's name to its hashed path](#from-project-name-to-hashed-path).
+- From a [hashed path to a project's name](#from-hashed-path-to-project-name).
-While restoring a backup, the current contents of `/home/git/repositories` are moved to
-`/home/git/repositories.old`. If `/home/git/repositories` is a mount point, then `mv` would be
-moving things between mount points, and problems can occur.
+#### From project name to hashed path
-Ideally, `/home/git` is the mount point, so things remain inside the same mount point. Linux package
-installations guarantee this because they don't specify the full repository path but instead
-the parent path, but self-compiled installations do not.
+Administrators can look up a project's hashed path from its name or ID using:
-### Example configuration
+- The [Admin Area](../administration/admin_area.md#administering-projects).
+- A Rails console.
-In the examples below, we add two additional repository storage paths configured to two additional
-mount points.
+To look up a project's hash path in the Admin Area:
-For compatibility reasons `gitlab.yml` has a different structure than Linux package installation configuration:
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. On the left sidebar, select **Overview > Projects** and select the project.
+1. Locate the **Relative path** field. The value is similar to:
-- In `gitlab.yml`, you indicate the path for the repositories. For example, `/home/git/repositories`.
-- In Linux package installation configuration, you indicate `git_data_dirs`, which could be `/home/git` for
- example. The Linux package installation then creates a `repositories` directory under that path to use with
- `gitlab.yml`.
+ ```plaintext
+ "@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git"
+ ```
-For self-compiled installations:
+To look up a project's hash path using a Rails console:
-1. Edit `gitlab.yml` and add the storage paths:
+1. Start a [Rails console](operations/rails_console.md#starting-a-rails-console-session).
+1. Run a command similar to this example (use either the project's ID or its name):
- ```yaml
- repositories:
- # Paths where repositories can be stored. Give the canonicalized absolute pathname.
- # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!!
- storages: # You must have at least a 'default' repository storage path.
- default:
- path: /home/git/repositories
- storage1:
- path: /mnt/storage1/repositories
- storage2:
- path: /mnt/storage2/repositories
+ ```ruby
+ Project.find(16).disk_path
+ Project.find_by_full_path('group/project').disk_path
```
-1. [Restart GitLab](restart_gitlab.md#self-compiled-installations) for the changes to take effect.
+#### From hashed path to project name
-1. [Configure where new repositories are stored](#configure-where-new-repositories-are-stored).
+Administrators can look up a project's name from its hashed relative path using:
-For Linux package installations:
+- A Rails console.
+- The `config` file in the `*.git` directory.
-1. Edit `/etc/gitlab/gitlab.rb` by appending the rest of the paths to the default one:
+To look up a project's name using the Rails console:
+
+1. Start a [Rails console](operations/rails_console.md#starting-a-rails-console-session).
+1. Run a command similar to this example:
```ruby
- git_data_dirs({
- "default" => { "path" => "/var/opt/gitlab/git-data" },
- "storage1" => { "path" => "/mnt/storage1/git-data" },
- "storage2" => { "path" => "/mnt/storage2/git-data" }
- })
+ ProjectRepository.find_by(disk_path: '@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9').project
```
-1. [Restart GitLab](restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
+The quoted string in that command is the directory tree you can find on your GitLab server. For
+example, on a default Linux package installation this would be `/var/opt/gitlab/git-data/repositories/@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git`
+with `.git` from the end of the directory name removed.
-1. [Configure where new repositories are stored](#configure-where-new-repositories-are-stored).
+The output includes the project ID and the project name. For example:
-NOTE:
-Linux package installations store the repositories in a `repositories` subdirectory of the `git-data` directory.
+```plaintext
+=> #<Project id:16 it/supportteam/ticketsystem>
+```
+
+To look up a project's name using the `config` file in the `*.git` directory:
+
+1. Locate the `*.git` directory. This directory is located in `/var/opt/gitlab/git-data/repositories/@hashed/`, where the first four
+ characters of the hash are the first two directories in the path under `@hashed/`. For example, on a default Linux package installation the
+ `*.git` directory of the hash `b17eb17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9` would be
+ `/var/opt/gitlab/git-data/repositories/@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git`.
+1. Open the `config` file and locate the `fullpath=` key under `[gitlab]`.
+
+### Hashed object pools
+
+Object pools are repositories used to deduplicate forks of public and internal projects and
+contain the objects from the source project. Using `objects/info/alternates`, the source project and
+forks use the object pool for shared objects. For more information, see
+[How Git object deduplication works in GitLab](../development/git_object_deduplication.md).
+
+Objects are moved from the source project to the object pool when housekeeping is run on the source
+project. Object pool repositories are stored similarly to regular repositories in a directory called `@pools` instead of `@hashed`
+
+```ruby
+# object pool paths
+"@pools/#{hash[0..1]}/#{hash[2..3]}/#{hash}.git"
+```
+
+WARNING:
+Do not run `git prune` or `git gc` in object pool repositories, which are stored in the `@pools` directory.
+This can cause data loss in the regular repositories that depend on the object pool.
+
+### Group wiki storage
+
+Unlike project wikis that are stored in the `@hashed` directory, group wikis are stored in a directory called `@groups`.
+Like project wikis, group wikis follow the hashed storage folder convention, but use a hash of the group ID rather than the project ID.
+
+For example:
+
+```ruby
+# group wiki paths
+"@groups/#{hash[0..1]}/#{hash[2..3]}/#{hash}.wiki.git"
+```
+
+### Gitaly Cluster storage
+
+If Gitaly Cluster is used, Praefect manages storage locations. The internal path used by Praefect for the repository
+differs from the hashed path. For more information, see
+[Praefect-generated replica paths](gitaly/index.md#praefect-generated-replica-paths-gitlab-150-and-later).
+
+### Object storage support
+
+This table shows which storable objects are storable in each storage type:
+
+| Storable object | Hashed storage | S3 compatible |
+|:-----------------|:---------------|:--------------|
+| Repository | Yes | - |
+| Attachments | Yes | - |
+| Avatars | No | - |
+| Pages | No | - |
+| Docker Registry | No | - |
+| CI/CD job logs | No | - |
+| CI/CD artifacts | No | Yes |
+| CI/CD cache | No | Yes |
+| LFS objects | Similar | Yes |
+| Repository pools | Yes | - |
+
+Files stored in an S3-compatible endpoint can have the same advantages as
+[hashed storage](#hashed-storage), as long as they are not prefixed with
+`#{namespace}/#{project_name}`. This is true for CI/CD cache and LFS objects.
+
+#### Avatars
+
+Each file is stored in a directory that matches the `id` assigned to it in the database. The
+filename is always `avatar.png` for user avatars. When an avatar is replaced, the `Upload` model is
+destroyed and a new one takes place with a different `id`.
+
+#### CI/CD artifacts
+
+CI/CD artifacts are S3-compatible.
+
+#### LFS objects
+
+[LFS Objects in GitLab](../topics/git/lfs/index.md) implement a similar
+storage pattern using two characters and two-level folders, following the Git implementation:
+
+```ruby
+"shared/lfs-objects/#{oid[0..1}/#{oid[2..3]}/#{oid[4..-1]}"
+
+# Based on object `oid`: `8909029eb962194cfb326259411b22ae3f4a814b5be4f80651735aeef9f3229c`, path will be:
+"shared/lfs-objects/89/09/029eb962194cfb326259411b22ae3f4a814b5be4f80651735aeef9f3229c"
+```
+
+LFS objects are also [S3-compatible](lfs/index.md#storing-lfs-objects-in-remote-object-storage).
## Configure where new repositories are stored
-After you [configure](#configure-repository-storage-paths) multiple repository storage paths, you
-can choose where new repositories are stored:
+After you configure multiple repository storages, you can choose where new repositories are stored:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Repository** and expand the **Repository storage**
section.
@@ -157,8 +216,7 @@ Each repository storage path can be assigned a weight from 0-100. When a new pro
these weights are used to determine the storage location the repository is created on.
The higher the weight of a given repository storage path relative to other repository storages
-paths, the more often it is chosen. That is,
-`(storage weight) / (sum of all weights) * 100 = chance %`.
+paths, the more often it is chosen (`(storage weight) / (sum of all weights) * 100 = chance %`).
By default, if repository weights have not been configured earlier:
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index 6e47d3099bd..844dc76b23d 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -1,245 +1,8 @@
---
-stage: Systems
-group: Gitaly
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+redirect_to: 'repository_storage_paths.md'
+remove_date: '2023-11-29'
---
-# Repository storage types **(FREE SELF)**
+This document was moved to [another location](repository_storage_paths.md).
-GitLab can be configured to use one or multiple repository storages. These storages can be:
-
-- Accessed via [Gitaly](gitaly/index.md), optionally on
- [its own server](gitaly/configure_gitaly.md#run-gitaly-on-its-own-server).
-- Mounted to the local disk. This [method](repository_storage_paths.md#configure-repository-storage-paths)
- is deprecated and [scheduled to be removed](https://gitlab.com/groups/gitlab-org/-/epics/2320) in
- GitLab 14.0.
-- Exposed as an NFS shared volume. This method is deprecated and
- [scheduled to be removed](https://gitlab.com/groups/gitlab-org/-/epics/3371) in GitLab 14.0.
-
-In GitLab:
-
-- Repository storages are configured in:
- - `/etc/gitlab/gitlab.rb` by the `git_data_dirs({})` configuration hash for Linux package installations.
- - `gitlab.yml` by the `repositories.storages` key for self-compiled installations.
-- The `default` repository storage is available in any installations that haven't customized it. By
- default, it points to a Gitaly node.
-
-The repository storage types documented here apply to any repository storage defined in
-`git_data_dirs({})` or `repositories.storages`.
-
-## Hashed storage
-
-> **Storage name** field [renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128416) from **Gitaly storage name** and **Relative path** field [renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128416) from **Gitaly relative path** in GitLab 16.3.
-
-Hashed storage stores projects on disk in a location based on a hash of the project's ID. Hashed
-storage is different to [legacy storage](#legacy-storage) where a project is stored based on:
-
-- The project's URL.
-- The folder structure where the repository is stored on disk.
-
-This makes the folder structure immutable and eliminates the need to synchronize state from URLs to
-disk structure. This means that renaming a group, user, or project:
-
-- Costs only the database transaction.
-- Takes effect immediately.
-
-The hash also helps spread the repositories more evenly on the disk. The top-level directory
-contains fewer folders than the total number of top-level namespaces.
-
-The hash format is based on the hexadecimal representation of a SHA256, calculated with
-`SHA256(project.id)`. The top-level folder uses the first two characters, followed by another folder
-with the next two characters. They are both stored in a special `@hashed` folder so they can
-co-exist with existing legacy storage projects. For example:
-
-```ruby
-# Project's repository:
-"@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}.git"
-
-# Wiki's repository:
-"@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}.wiki.git"
-```
-
-### Translate hashed storage paths
-
-Troubleshooting problems with the Git repositories, adding hooks, and other tasks requires you
-translate between the human-readable project name and the hashed storage path. You can translate:
-
-- From a [project's name to its hashed path](#from-project-name-to-hashed-path).
-- From a [hashed path to a project's name](#from-hashed-path-to-project-name).
-
-#### From project name to hashed path
-
-Administrators can look up a project's hashed path from its name or ID using:
-
-- The [Admin Area](../administration/admin_area.md#administering-projects).
-- A Rails console.
-
-To look up a project's hash path in the Admin Area:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. On the left sidebar, select **Overview > Projects** and select the project.
-1. Locate the **Relative path** field. The value is similar to:
-
- ```plaintext
- "@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git"
- ```
-
-To look up a project's hash path using a Rails console:
-
-1. Start a [Rails console](operations/rails_console.md#starting-a-rails-console-session).
-1. Run a command similar to this example (use either the project's ID or its name):
-
- ```ruby
- Project.find(16).disk_path
- Project.find_by_full_path('group/project').disk_path
- ```
-
-#### From hashed path to project name
-
-Administrators can look up a project's name from its hashed relative path using:
-
-- A Rails console.
-- The `config` file in the `*.git` directory.
-
-To look up a project's name using the Rails console:
-
-1. Start a [Rails console](operations/rails_console.md#starting-a-rails-console-session).
-1. Run a command similar to this example:
-
- ```ruby
- ProjectRepository.find_by(disk_path: '@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9').project
- ```
-
-The quoted string in that command is the directory tree you can find on your GitLab server. For
-example, on a default Linux package installation this would be `/var/opt/gitlab/git-data/repositories/@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git`
-with `.git` from the end of the directory name removed.
-
-The output includes the project ID and the project name. For example:
-
-```plaintext
-=> #<Project id:16 it/supportteam/ticketsystem>
-```
-
-To look up a project's name using the `config` file in the `*.git` directory:
-
-1. Locate the `*.git` directory. This directory is located in `/var/opt/gitlab/git-data/repositories/@hashed/`, where the first four
- characters of the hash are the first two directories in the path under `@hashed/`. For example, on a default Linux package installation the
- `*.git` directory of the hash `b17eb17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9` would be
- `/var/opt/gitlab/git-data/repositories/@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git`.
-1. Open the `config` file and locate the `fullpath=` key under `[gitlab]`.
-
-### Hashed object pools
-
-> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/1606) in GitLab 12.1.
-
-Object pools are repositories used to deduplicate forks of public and internal projects and
-contain the objects from the source project. Using `objects/info/alternates`, the source project and
-forks use the object pool for shared objects. For more information, see
-[How Git object deduplication works in GitLab](../development/git_object_deduplication.md).
-
-Objects are moved from the source project to the object pool when housekeeping is run on the source
-project. Object pool repositories are stored similarly to regular repositories in a directory called `@pools` instead of `@hashed`
-
-```ruby
-# object pool paths
-"@pools/#{hash[0..1]}/#{hash[2..3]}/#{hash}.git"
-```
-
-WARNING:
-Do not run `git prune` or `git gc` in object pool repositories, which are stored in the `@pools` directory.
-This can cause data loss in the regular repositories that depend on the object pool.
-
-### Group wiki storage
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13195) in GitLab 13.5.
-
-Unlike project wikis that are stored in the `@hashed` directory, group wikis are stored in a directory called `@groups`.
-Like project wikis, group wikis follow the hashed storage folder convention, but use a hash of the group ID rather than the project ID.
-
-For example:
-
-```ruby
-# group wiki paths
-"@groups/#{hash[0..1]}/#{hash[2..3]}/#{hash}.wiki.git"
-```
-
-### Gitaly Cluster storage
-
-If Gitaly Cluster is used, Praefect manages storage locations. For more information, see [Praefect-generated replica paths](gitaly/index.md#praefect-generated-replica-paths-gitlab-150-and-later).
-
-### Object storage support
-
-This table shows which storable objects are storable in each storage type:
-
-| Storable object | Legacy storage | Hashed storage | S3 compatible | GitLab version |
-|:-----------------|:---------------|:---------------|:--------------|:---------------|
-| Repository | Yes | Yes | - | 10.0 |
-| Attachments | Yes | Yes | - | 10.2 |
-| Avatars | Yes | No | - | - |
-| Pages | Yes | No | - | - |
-| Docker Registry | Yes | No | - | - |
-| CI/CD job logs | No | No | - | - |
-| CI/CD artifacts | No | No | Yes | 9.4 / 10.6 |
-| CI/CD cache | No | No | Yes | - |
-| LFS objects | Yes | Similar | Yes | 10.0 / 10.7 |
-| Repository pools | No | Yes | - | 11.6 |
-
-Files stored in an S3-compatible endpoint can have the same advantages as
-[hashed storage](#hashed-storage), as long as they are not prefixed with
-`#{namespace}/#{project_name}`. This is true for CI/CD cache and LFS objects.
-
-#### Avatars
-
-Each file is stored in a directory that matches the `id` assigned to it in the database. The
-filename is always `avatar.png` for user avatars. When an avatar is replaced, the `Upload` model is
-destroyed and a new one takes place with a different `id`.
-
-#### CI/CD artifacts
-
-CI/CD artifacts are:
-
-- S3-compatible since GitLab 9.4, initially available in [GitLab Premium](https://about.gitlab.com/pricing/).
-- Available in [GitLab Free](https://about.gitlab.com/pricing/) since GitLab 10.6.
-
-#### LFS objects
-
-[LFS Objects in GitLab](../topics/git/lfs/index.md) implement a similar
-storage pattern using two characters and two-level folders, following the Git implementation:
-
-```ruby
-"shared/lfs-objects/#{oid[0..1}/#{oid[2..3]}/#{oid[4..-1]}"
-
-# Based on object `oid`: `8909029eb962194cfb326259411b22ae3f4a814b5be4f80651735aeef9f3229c`, path will be:
-"shared/lfs-objects/89/09/029eb962194cfb326259411b22ae3f4a814b5be4f80651735aeef9f3229c"
-```
-
-LFS objects are also [S3-compatible](lfs/index.md#storing-lfs-objects-in-remote-object-storage).
-
-## Legacy storage
-
-WARNING:
-In GitLab 13.0, legacy storage is deprecated. If you haven't migrated to hashed storage yet, check
-the [migration instructions](raketasks/storage.md#migrate-to-hashed-storage). Support for legacy
-storage is [scheduled to be removed](https://gitlab.com/gitlab-org/gitaly/-/issues/1690) in GitLab
-14.0. In GitLab 13.0 and later, switching new projects to legacy storage is not possible. The
-option to choose between hashed and legacy storage in the Admin Area is disabled.
-
-Legacy storage was the storage behavior prior to version GitLab 10.0. For historical reasons,
-GitLab replicated the same mapping structure from the projects URLs:
-
-- Project's repository: `#{namespace}/#{project_name}.git`.
-- Project's wiki: `#{namespace}/#{project_name}.wiki.git`.
-
-This structure enabled you to migrate from existing solutions to GitLab, and for Administrators to
-find where the repository was stored. This approach also had some drawbacks:
-
-- Storage location concentrated a large number of top-level namespaces. The impact could be
- reduced by [multiple repository storage paths](repository_storage_paths.md).
-- Because backups were a snapshot of the same URL mapping, if you tried to recover a very old
- backup, you needed to verify whether any project had taken the place of an old removed or renamed
- project sharing the same URL. This meant that `mygroup/myproject` from your backup may not have
- been the same original project that was at that same URL today.
-- Any change in the URL needed to be reflected on disk (when groups, users, or projects were
- renamed. This could add a lot of load in big installations, especially if using any type of
- network-based file system.
+<!-- This redirect file can be deleted after <2023-11-29>. -->
diff --git a/doc/administration/review_abuse_reports.md b/doc/administration/review_abuse_reports.md
index e3891cbe68a..4ff53a4e1b0 100644
--- a/doc/administration/review_abuse_reports.md
+++ b/doc/administration/review_abuse_reports.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference, howto
@@ -16,7 +16,7 @@ reports in the Admin Area.
To receive notifications of new abuse reports by email:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Reporting**.
1. Expand the **Abuse reports** section.
@@ -34,7 +34,7 @@ To find out more about reporting abuse, see
To access abuse reports:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Abuse Reports**.
diff --git a/doc/administration/secure_files.md b/doc/administration/secure_files.md
index d4a57ed5d51..6c61c390655 100644
--- a/doc/administration/secure_files.md
+++ b/doc/administration/secure_files.md
@@ -120,7 +120,7 @@ See [the available connection settings for different providers](object_storage.m
```ruby
gitlab_rails['ci_secure_files_object_store_enabled'] = true
- gitlab_rails['ci_secure_files_object_store_remote_directory'] = "terraform"
+ gitlab_rails['ci_secure_files_object_store_remote_directory'] = "ci_secure_files"
gitlab_rails['ci_secure_files_object_store_connection'] = {
'provider' => 'AWS',
'region' => 'eu-central-1',
diff --git a/doc/administration/server_hooks.md b/doc/administration/server_hooks.md
index 104eaafd8ad..4d8377b4117 100644
--- a/doc/administration/server_hooks.md
+++ b/doc/administration/server_hooks.md
@@ -39,7 +39,7 @@ Prerequisites:
- The [storage name](gitaly/configure_gitaly.md#gitlab-requires-a-default-repository-storage), path to the Gitaly configuration file
(default is `/var/opt/gitlab/gitaly/config.toml` on Linux package instances), and the
- [repository relative path](repository_storage_types.md#from-project-name-to-hashed-path) for the repository.
+ [repository relative path](repository_storage_paths.md#from-project-name-to-hashed-path) for the repository.
To set server hooks for a repository:
@@ -71,15 +71,15 @@ If you implemented the server hook code correctly, it should execute when the Gi
To create server hooks for a repository:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Go to **Overview > Projects** and select the project you want to add a server hook to.
1. On the page that appears, locate the value of **Relative path**. This path is where server
hooks must be located.
- - If you are using [hashed storage](repository_storage_types.md#hashed-storage), see
- [Translate hashed storage paths](repository_storage_types.md#translate-hashed-storage-paths) for information on
+ - If you are using [hashed storage](repository_storage_paths.md#hashed-storage), see
+ [Translate hashed storage paths](repository_storage_paths.md#translate-hashed-storage-paths) for information on
interpreting the relative path.
- - If you are not using [hashed storage](repository_storage_types.md#hashed-storage):
+ - If you are not using [hashed storage](repository_storage_paths.md#hashed-storage):
- For Linux package installations, the path is usually `/var/opt/gitlab/git-data/repositories/<group>/<project>.git`.
- For self-compiled installations, the path is usually `/home/git/repositories/<group>/<project>.git`.
1. On the file system, create a new directory in the correct location called `custom_hooks`.
@@ -109,7 +109,7 @@ To accomplish this, follow the same steps for setting custom repository hooks fo
The location to copy the scripts to depends on where repositories are stored:
-- In GitLab 15.2 and earlier, Gitaly Cluster uses the [hashed storage path](repository_storage_types.md#hashed-storage)
+- In GitLab 15.2 and earlier, Gitaly Cluster uses the [hashed storage path](repository_storage_paths.md#hashed-storage)
reported by the GitLab application.
- In GitLab 15.3 and later, new repositories are created using
[Praefect-generated replica paths](gitaly/index.md#praefect-generated-replica-paths-gitlab-150-and-later),
@@ -169,7 +169,7 @@ subdirectories.
Prerequisites:
-- The [storage name and relative path](repository_storage_types.md#from-project-name-to-hashed-path) for the repository.
+- The [storage name and relative path](repository_storage_paths.md#from-project-name-to-hashed-path) for the repository.
To remove server hooks, pass an empty tarball to `hook set` to indicate that the repository should contain no hooks. For example:
diff --git a/doc/administration/settings/account_and_limit_settings.md b/doc/administration/settings/account_and_limit_settings.md
index 3d632880113..930448b3bd3 100644
--- a/doc/administration/settings/account_and_limit_settings.md
+++ b/doc/administration/settings/account_and_limit_settings.md
@@ -16,7 +16,7 @@ the [project limits for existing users](#projects-limit-for-a-user).
To configure the maximum number of projects in personal namespaces for new users:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**.
@@ -30,7 +30,7 @@ in their users personal namespace. However, projects can still be created in a g
You can edit a specific user, and change the maximum number of projects this user
can create in their personal namespace:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview** > **Users**.
1. From the list of users, select a user.
@@ -44,7 +44,7 @@ can create in their personal namespace:
The maximum file size for attachments in GitLab comments and replies is 100 MB.
To change the maximum attachment size:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**.
@@ -60,7 +60,7 @@ For GitLab.com repository size limits, read [accounts and limit settings](../../
You can change the maximum push size for your instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**.
@@ -75,86 +75,6 @@ because the [web server](../../development/architecture.md#components)
must receive the file before GitLab can generate the commit.
Use [Git LFS](../../topics/git/lfs/index.md) to add large files to a repository.
-## Max export size
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86124) in GitLab 15.0.
-
-To modify the maximum file size for exports in GitLab:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**, then expand **Account and limit**.
-1. Increase or decrease by changing the value in **Maximum export size (MB)**.
-
-## Max import size
-
-> [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/251106) from 50 MB to unlimited in GitLab 13.8.
-
-To modify the maximum file size for imports in GitLab:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**.
-1. Expand **Account and limit**.
-1. Increase or decrease by changing the value in **Maximum import size (MB)**.
-
-This setting applies only to repositories
-[imported from a GitLab export file](../../user/project/settings/import_export.md#import-a-project-and-its-data).
-
-If you choose a size larger than the configured value for the web server,
-you may receive errors. See the [troubleshooting section](#troubleshooting) for more
-details.
-
-For GitLab.com repository size limits, read [accounts and limit settings](../../user/gitlab_com/index.md#account-and-limit-settings).
-
-## Maximum remote file size for imports
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384976) in GitLab 16.3.
-
-You can modify the maximum remote file size for imports from external object storages (for example, AWS) in GitLab.
-
-To modify the maximum import remote file size:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**.
-1. Expand **Account and limit**.
-1. Increase or decrease by changing the value in **Maximum import remote file size (MB)**. Set to `0` to set no file size limit.
-
-## Maximum download file size for imports by direct transfer
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384976) in GitLab 16.3.
-
-You can modify the maximum download file size for imports by direct transfer in GitLab.
-
-To modify the maximum download file size for imports by direct transfer:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**.
-1. Expand **Account and limit**.
-1. Increase or decrease by changing the value in **Direct transfer maximum download file size (MB)**. Set to `0` to set no download file size limit.
-
-## Maximum decompressed file size for imported archives
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128218) in GitLab 16.3.
-
-When you import a project using [file exports](../../user/project/settings/import_export.md) or [direct transfer](../../user/group/import/index.md#migrate-groups-by-direct-transfer-recommended), you can specify the maximum decompressed file size for imported archives. The default value is 25 GB.
-
-When you import a compressed file, the decompressed size cannot exceed the maximum decompressed file size limit. If the decompressed size exceeds the configured limit, the following error is returned:
-
-```plaintext
-Decompressed archive size validation failed.
-```
-
-To modify the maximum decompressed file size for imports in GitLab:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**.
-1. Expand **Account and limit**.
-1. Set another value for **Maximum decompressed size (MiB)**.
-
## Personal access token prefix
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20968) in GitLab 13.7.
@@ -172,7 +92,7 @@ The default prefix is `glpat-` but administrators can change it.
To change the default global prefix:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Account and limit** section.
@@ -219,7 +139,7 @@ These settings can be found in:
1. Fill in the **Repository size limit (MB)** field in the **Naming, visibility** section.
1. Select **Save changes**.
- GitLab global settings:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Account and limit** section.
@@ -242,7 +162,7 @@ For details on manually purging files, see [reducing the repository size using G
You can change how long users can remain signed in without activity.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**. The set duration is in **Session duration (minutes)**.
@@ -257,7 +177,7 @@ For details, see [cookies used for sign-in](../../user/profile/index.md#cookies-
Users can select the **Remember me** checkbox on sign-in, and their session will remain active for an indefinite period of time when accessed from that specific browser. You can turn off this setting if you need sessions to expire for security or compliance purposes. Turning off this setting will ensure users' sessions expire after the number of minutes of inactivity set when you [customize your session duration](#customize-the-default-session-duration).
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**.
@@ -275,7 +195,7 @@ GitLab administrators can choose to customize the session duration (in minutes)
To set a limit on how long these sessions are valid:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Account and limit** section.
@@ -303,7 +223,7 @@ there are no restrictions.
To set a lifetime on how long SSH keys are valid:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Account and limit** section.
@@ -340,7 +260,7 @@ there are no restrictions.
To set a lifetime on how long access tokens are valid:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Account and limit** section.
@@ -363,7 +283,7 @@ To maintain integrity of user details in [Audit Events](../../administration/aud
To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**.
@@ -385,7 +305,7 @@ By default, new users can create top-level groups. GitLab administrators can pre
- The [application setting API](../../api/settings.md#change-application-settings).
- In GitLab 15.4 and earlier, a [configuration file](../../administration/user_settings.md#use-configuration-files-to-prevent-new-users-from-creating-top-level-groups).
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**.
@@ -397,7 +317,7 @@ By default, new users can create top-level groups. GitLab administrators can pre
By default, newly created users have a public profile. GitLab administrators can set new users to have a private profile by default:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**.
@@ -410,7 +330,7 @@ By default, newly created users have a public profile. GitLab administrators can
By default, users can delete their own accounts. GitLab administrators can prevent
users from deleting their own accounts:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Account and limit**.
diff --git a/doc/administration/settings/continuous_integration.md b/doc/administration/settings/continuous_integration.md
index edf61701a33..f0423021e8b 100644
--- a/doc/administration/settings/continuous_integration.md
+++ b/doc/administration/settings/continuous_integration.md
@@ -15,7 +15,7 @@ job artifacts.
To enable (or disable) [Auto DevOps](../../topics/autodevops/index.md)
for all projects:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Check (or uncheck to disable) the box that says **Default to Auto DevOps pipeline for all projects**.
@@ -33,7 +33,7 @@ If you want to disable it for a specific project, you can do so in
You can set all new projects to have the instance's shared runners available by default.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**.
@@ -53,7 +53,7 @@ you can assign that runner to other projects.
To enable a project runner for more than one project:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. From the left sidebar, select **CI/CD > Runners**.
1. Select the runner you want to edit.
@@ -67,7 +67,7 @@ To enable a project runner for more than one project:
To display details about the instance's shared runners in all projects'
runner settings:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**.
@@ -77,7 +77,7 @@ runner settings:
To view the rendered details:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
@@ -85,19 +85,19 @@ To view the rendered details:
## Maximum artifacts size
-The maximum size of the [job artifacts](../../administration/job_artifacts.md)
-can be set at:
+An administrator can set the maximum size of the
+[job artifacts](../../administration/job_artifacts.md) at:
-- The instance level.
-- [From GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/issues/21688), the project and group level.
+- The instance level
+- The project and group level
For the setting on GitLab.com, see [Artifacts maximum size](../../user/gitlab_com/index.md#gitlab-cicd).
-The value is in MB and the default is 100 MB per job. To change it at the:
+The value is in MB, and the default is 100 MB per job. An administrator can change the default value at the:
- Instance level:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > CI/CD > Continuous Integration and Deployment**.
1. Change the value of **Maximum artifacts size (MB)**.
@@ -115,9 +115,6 @@ The value is in MB and the default is 100 MB per job. To change it at the:
1. Change the value of **maximum artifacts size** (in MB).
1. Select **Save changes** for the changes to take effect.
-NOTE:
-The setting at all levels is only available to GitLab administrators.
-
## Default artifacts expiration
The default expiration time of the [job artifacts](../../administration/job_artifacts.md)
@@ -125,7 +122,7 @@ can be set in the Admin Area of your GitLab instance. The syntax of duration is
described in [`artifacts:expire_in`](../../ci/yaml/index.md#artifactsexpire_in)
and the default value is `30 days`.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Change the value of default expiration time.
@@ -157,7 +154,7 @@ If disabled at the instance level, you cannot enable this per-project.
To disable the setting:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**.
@@ -181,7 +178,7 @@ blueprint for more details.
To set the duration for which the jobs are considered as old and expired:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand the **Continuous Integration and Deployment** section.
@@ -199,7 +196,7 @@ For the value set for GitLab.com, see [Scheduled job archiving](../../user/gitla
To set all new [CI/CD variables](../../ci/variables/index.md) as
[protected](../../ci/variables/index.md#protect-a-cicd-variable) by default:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Select **Protect CI/CD variables by default**.
@@ -211,7 +208,7 @@ To set all new [CI/CD variables](../../ci/variables/index.md) as
The maximum number of [includes](../../ci/yaml/includes.md) per pipeline can be set at the instance level.
The default is `150`.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Change the value of **Maximum includes**.
@@ -224,7 +221,7 @@ The default is `150`.
The default CI/CD configuration file and path for new projects can be set in the Admin Area
of your GitLab instance (`.gitlab-ci.yml` if not set):
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Input the new file and path in the **Default CI/CD configuration file** field.
@@ -239,7 +236,7 @@ It is also possible to specify a [custom CI/CD configuration file for a specific
You can configure some [CI/CD limits](../../administration/instance_limits.md#cicd-limits)
from the Admin Area:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand the **Continuous Integration and Deployment** section.
@@ -263,7 +260,7 @@ walkthrough on how to add one.
To enable or disable the banner:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Select or clear the **Enable pipeline suggestion banner** checkbox.
@@ -300,7 +297,7 @@ in the pipeline editor.
To select a CI/CD template for the required pipeline configuration:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand the **Required pipeline configuration** section.
@@ -315,7 +312,7 @@ GitLab administrators can disable the forwarding of Maven requests to [Maven Cen
To disable forwarding Maven requests:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand the **Package Registry** section.
@@ -328,7 +325,7 @@ GitLab administrators can disable the forwarding of npm requests to [npmjs.com](
To disable it:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand the **Package Registry** section.
@@ -341,7 +338,7 @@ GitLab administrators can disable the forwarding of PyPI requests to [pypi.org](
To disable it:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand the **Package Registry** section.
@@ -354,7 +351,7 @@ GitLab administrators can adjust the maximum allowed file size for each package
To set the maximum file size:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand the **Package Registry** section.
@@ -375,7 +372,7 @@ By default, all members of a project and group are able to register runners.
To restrict all users in an instance from registering runners:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
@@ -398,7 +395,7 @@ GitLab administrators can adjust group permissions to restrict runner registrati
To restrict runner registration by members in a specific group:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Groups** and find your group.
1. Select **Edit**.
@@ -413,7 +410,7 @@ By default, GitLab instances periodically fetch official runner version data fro
To disable your instance fetching this data:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
diff --git a/doc/administration/settings/deprecated_api_rate_limits.md b/doc/administration/settings/deprecated_api_rate_limits.md
index f8db0810af5..21385a6779d 100644
--- a/doc/administration/settings/deprecated_api_rate_limits.md
+++ b/doc/administration/settings/deprecated_api_rate_limits.md
@@ -34,7 +34,7 @@ Prerequisite:
To override the general user and IP rate limits for requests to deprecated API endpoints:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Deprecated API Rate Limits**.
diff --git a/doc/administration/settings/email.md b/doc/administration/settings/email.md
index e4972897aab..c79394ee407 100644
--- a/doc/administration/settings/email.md
+++ b/doc/administration/settings/email.md
@@ -21,7 +21,7 @@ address in the body of the email instead.
To include the author's email address in the email body:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Email**.
@@ -34,7 +34,7 @@ GitLab can send email in multipart format (HTML and plain text) or plain text on
To enable multipart email:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Email**.
@@ -50,7 +50,7 @@ This configuration option sets the email hostname for [private commit emails](..
To change the hostname used in private commit emails:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Email**.
@@ -69,7 +69,7 @@ can be used for legal, auditing, or compliance reasons, for example.
To add additional text to emails:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Email**.
@@ -82,7 +82,7 @@ GitLab sends email notifications to users when their account has been deactivate
To disable these notifications:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Email**.
@@ -105,7 +105,7 @@ setting.
To add additional text to deactivation emails:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Email**.
diff --git a/doc/administration/settings/external_authorization.md b/doc/administration/settings/external_authorization.md
index 45887fdccb8..2d110dc2ea7 100644
--- a/doc/administration/settings/external_authorization.md
+++ b/doc/administration/settings/external_authorization.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -45,7 +45,7 @@ Alternatively, learn where to install custom certificates by using
The external authorization service can be enabled by an administrator:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **External authorization**.
@@ -66,7 +66,7 @@ Prerequisites:
To allow authorization with deploy tokens and keys:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **External authorization**, and:
diff --git a/doc/administration/settings/files_api_rate_limits.md b/doc/administration/settings/files_api_rate_limits.md
index cb5442c957f..025f8c86993 100644
--- a/doc/administration/settings/files_api_rate_limits.md
+++ b/doc/administration/settings/files_api_rate_limits.md
@@ -30,7 +30,7 @@ Prerequisite:
To override the general user and IP rate limits for requests to the Repository files API:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Files API Rate Limits**.
diff --git a/doc/administration/settings/floc.md b/doc/administration/settings/floc.md
index 6bd5a6dfed4..f461472bfe7 100644
--- a/doc/administration/settings/floc.md
+++ b/doc/administration/settings/floc.md
@@ -22,7 +22,7 @@ Permissions-Policy: interest-cohort=()
To enable it:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Federated Learning of Cohorts (FLoC)**.
diff --git a/doc/administration/settings/git_lfs_rate_limits.md b/doc/administration/settings/git_lfs_rate_limits.md
index cb2cc80e397..acd3945750f 100644
--- a/doc/administration/settings/git_lfs_rate_limits.md
+++ b/doc/administration/settings/git_lfs_rate_limits.md
@@ -21,7 +21,7 @@ rate limits.
Git LFS rate limits are disabled by default. If enabled and configured, these limits
supersede the [general user and IP rate limits](../settings/user_and_ip_rate_limits.md):
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Git LFS Rate Limits**.
diff --git a/doc/administration/settings/gitaly_timeouts.md b/doc/administration/settings/gitaly_timeouts.md
index 49dc7763cd0..3304db3d148 100644
--- a/doc/administration/settings/gitaly_timeouts.md
+++ b/doc/administration/settings/gitaly_timeouts.md
@@ -11,7 +11,7 @@ configured to make sure that long-running Gitaly calls don't needlessly take up
To access Gitaly timeout settings:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand the **Gitaly timeouts** section.
diff --git a/doc/administration/settings/help_page.md b/doc/administration/settings/help_page.md
index 46c2c395102..23ca7d55cde 100644
--- a/doc/administration/settings/help_page.md
+++ b/doc/administration/settings/help_page.md
@@ -16,7 +16,7 @@ the GitLab sign-in page.
You can add a help message, which is shown at the top of the GitLab `/help` page (for example,
<https://gitlab.com/help>):
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Sign-in and Help page**.
@@ -34,7 +34,7 @@ is restricted, `/help` is visible only to authenticated users.
You can add a help message, which is shown on the GitLab sign-in page. The message appears on the sign-in page:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Sign-in and Help page**.
@@ -48,7 +48,7 @@ You can now see the message on the sign-in page.
GitLab marketing-related entries are occasionally shown on the Help page. To hide these entries:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Sign-in and Help page**.
@@ -62,7 +62,7 @@ You can specify a custom URL to which users are directed when they:
- Select **Support** from the Help dropdown list.
- Select **See our website for help** on the Help page.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Sign-in and Help page**.
@@ -77,7 +77,7 @@ You can specify a custom URL to which users are directed when they:
You can redirect all `/help` links to a destination that meets the [necessary requirements](#destination-requirements).
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Sign-in and Help page**.
diff --git a/doc/administration/settings/import_and_export_settings.md b/doc/administration/settings/import_and_export_settings.md
new file mode 100644
index 00000000000..af1729246ec
--- /dev/null
+++ b/doc/administration/settings/import_and_export_settings.md
@@ -0,0 +1,153 @@
+---
+stage: Manage
+group: Import and Integrate
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+type: reference
+---
+
+# Import and export settings **(FREE SELF)**
+
+Settings for import- and export-related features.
+
+## Configure allowed import sources
+
+Before you can import projects from other systems, you must enable the
+[import source](../../user/gitlab_com/index.md#default-import-sources) for that system.
+
+1. Sign in to GitLab as a user with Administrator access level.
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand the **Import and export settings** section.
+1. Select each of **Import sources** to allow.
+1. Select **Save changes**.
+
+## Enable project export
+
+To enable the export of
+[projects and their data](../../user/project/settings/import_export.md#export-a-project-and-its-data):
+
+1. Sign in to GitLab as a user with Administrator access level.
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand the **Import and export settings** section.
+1. Scroll to **Project export**.
+1. Select the **Enabled** checkbox.
+1. Select **Save changes**.
+
+## Enable migration of groups and projects by direct transfer
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383268) in GitLab 15.8.
+
+You can enable migration of groups by direct transfer using the UI.
+
+To enable migration of groups by direct transfer:
+
+1. Sign in to GitLab as a user with Administrator access level.
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand the **Import and export settings** section.
+1. Scroll to **Allow migrating GitLab groups and projects by direct transfer**.
+1. Select the **Enabled** checkbox.
+1. Select **Save changes**.
+
+The same setting
+[is available](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls) in the API as the
+`bulk_import_enabled` attribute.
+
+## Max export size
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/86124) in GitLab 15.0.
+
+To modify the maximum file size for exports in GitLab:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**, then expand **Import and export settings**.
+1. Increase or decrease by changing the value in **Maximum export size (MiB)**.
+
+## Max import size
+
+> [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/251106) from 50 MB to unlimited in GitLab 13.8.
+
+To modify the maximum file size for imports in GitLab:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand **Import and export settings**.
+1. Increase or decrease by changing the value in **Maximum import size (MiB)**.
+
+This setting applies only to repositories
+[imported from a GitLab export file](../../user/project/settings/import_export.md#import-a-project-and-its-data).
+
+If you choose a size larger than the configured value for the web server,
+you may receive errors. See the [troubleshooting section](../../administration/settings/account_and_limit_settings.md#troubleshooting) for more
+details.
+
+For GitLab.com repository size limits, read [accounts and limit settings](../../user/gitlab_com/index.md#account-and-limit-settings).
+
+## Maximum remote file size for imports
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384976) in GitLab 16.3.
+
+You can modify the maximum remote file size for imports from external object storages (for example, AWS) in GitLab.
+
+To modify the maximum import remote file size:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand **Import and export settings**.
+1. Increase or decrease by changing the value in **Maximum import remote file size (MiB)**. Set to `0` to set no file size limit.
+
+## Maximum download file size for imports by direct transfer
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384976) in GitLab 16.3.
+
+You can modify the maximum download file size for imports by direct transfer in GitLab.
+
+To modify the maximum download file size for imports by direct transfer:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand **Import and export settings**.
+1. Increase or decrease by changing the value in **Direct transfer maximum download file size (MiB)**. Set to `0` to set no download file size limit.
+
+## Maximum decompressed file size for imported archives
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128218) in GitLab 16.3.
+> - **Maximum decompressed file size for archives from imports** field [renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130081) from **Maximum decompressed size** in GitLab 16.4.
+
+When you import a project using [file exports](../../user/project/settings/import_export.md) or [direct transfer](../../user/group/import/index.md#migrate-groups-by-direct-transfer-recommended), you can specify the maximum decompressed file size for imported archives. The default value is 25 GB.
+
+When you import a compressed file, the decompressed size cannot exceed the maximum decompressed file size limit. If the decompressed size exceeds the configured limit, the following error is returned:
+
+```plaintext
+Decompressed archive size validation failed.
+```
+
+To modify the maximum decompressed file size for imports in GitLab:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand **Import and export settings**.
+1. Set another value for **Maximum decompressed file size for archives from imports (MiB)**.
+
+## Timeout for decompressing archived files
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128218) in GitLab 16.4.
+
+When you [import a project](../../user/project/settings/import_export.md), you can specify the maximum time out for decompressing imported archives. The default value is 210 seconds.
+
+To modify the maximum decompressed file size for imports in GitLab:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand **Import and export settings**.
+1. Set another value for **Timeout for decompressing archived files (seconds)**.
diff --git a/doc/administration/settings/import_export_rate_limits.md b/doc/administration/settings/import_export_rate_limits.md
index 99385c77cdf..dad72ffdf44 100644
--- a/doc/administration/settings/import_export_rate_limits.md
+++ b/doc/administration/settings/import_export_rate_limits.md
@@ -12,7 +12,7 @@ You can configure the rate limits for imports and exports of projects and groups
To change a rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Import and export rate limits**.
diff --git a/doc/administration/settings/incident_management_rate_limits.md b/doc/administration/settings/incident_management_rate_limits.md
index 2a74c843107..5a8b1b96c6d 100644
--- a/doc/administration/settings/incident_management_rate_limits.md
+++ b/doc/administration/settings/incident_management_rate_limits.md
@@ -30,7 +30,7 @@ Requests that exceed the limit are logged into `auth.log`.
To set inbound incident management alert limits:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Incident Management Limits**.
diff --git a/doc/administration/settings/index.md b/doc/administration/settings/index.md
index a5746ad26e4..77bac42d899 100644
--- a/doc/administration/settings/index.md
+++ b/doc/administration/settings/index.md
@@ -19,7 +19,7 @@ read [GitLab.com settings](../../user/gitlab_com/index.md).
To access the **Admin Area**:
1. Sign in to your GitLab instance as an administrator.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
## Change the default first day of the week
@@ -27,7 +27,7 @@ To access the **Admin Area**:
You can change the [Default first day of the week](../../user/profile/preferences.md)
for the entire GitLab instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Scroll to the **Localization** section, and select your desired first day of the week.
@@ -37,7 +37,7 @@ for the entire GitLab instance:
You can change the [Default language](../../user/profile/preferences.md)
for the entire GitLab instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Scroll to the **Localization** section, and select your desired default language.
diff --git a/doc/administration/settings/instance_template_repository.md b/doc/administration/settings/instance_template_repository.md
index 8c8c9f44998..510c88e7738 100644
--- a/doc/administration/settings/instance_template_repository.md
+++ b/doc/administration/settings/instance_template_repository.md
@@ -20,7 +20,7 @@ while the project remains secure.
To select a project to serve as the custom template repository:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Templates**.
1. Expand **Templates**
@@ -32,6 +32,9 @@ After you add templates, you can use them for the entire instance.
They are available in the [Web Editor](../../user/project/repository/web_editor.md)
and through the [API settings](../../api/settings.md).
+These templates cannot be used as a value of the
+[`include:template`](../../ci/yaml/index.md#includetemplate) key in `.gitlab-ci.yml`.
+
## Supported file types and locations
Templates must be added to a specific subdirectory in the repository,
diff --git a/doc/administration/settings/package_registry_rate_limits.md b/doc/administration/settings/package_registry_rate_limits.md
index ffba5bbf15a..2ddb6bfcd17 100644
--- a/doc/administration/settings/package_registry_rate_limits.md
+++ b/doc/administration/settings/package_registry_rate_limits.md
@@ -30,7 +30,7 @@ no difference in functionality compared to the general user and IP rate limits.
To enable the unauthenticated request rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Package registry rate limits**.
@@ -45,7 +45,7 @@ To enable the unauthenticated request rate limit:
To enable the authenticated API request rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**
1. Expand **Package registry rate limits**.
diff --git a/doc/administration/settings/project_integration_management.md b/doc/administration/settings/project_integration_management.md
index 95dddf34182..ad43c70e253 100644
--- a/doc/administration/settings/project_integration_management.md
+++ b/doc/administration/settings/project_integration_management.md
@@ -18,11 +18,15 @@ for all projects that didn't have it already enabled.
Only the entire settings for an integration can be inherited. Per-field inheritance
is proposed in [epic 2137](https://gitlab.com/groups/gitlab-org/-/epics/2137).
-## Manage instance-level default settings for a project integration **(FREE SELF)**
+## Manage instance-level default settings for a project integration
+
+Prerequisite:
+
+- You must have administrator access to the instance.
To manage instance-level default settings for a project integration:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Integrations**.
1. Select an integration.
@@ -58,9 +62,13 @@ is proposed in [epic 2137](https://gitlab.com/groups/gitlab-org/-/epics/2137).
### Remove an instance-level default setting
+Prerequisite:
+
+- You must have administrator access to the instance.
+
To remove an instance-level default setting:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Integrations**.
1. Select an integration.
@@ -72,19 +80,27 @@ Resetting an instance-level default setting removes the integration from all pro
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218252) in GitLab 14.2.
+Prerequisite:
+
+- You must have administrator access to the instance.
+
To view projects in your instance that [use custom settings](#use-custom-settings-for-a-project-or-group-integration):
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Integrations**.
1. Select an integration.
1. Select the **Projects using custom settings** tab.
-## Manage group-level default settings for a project integration
+## Manage group-level default settings for a project integration **(FREE ALL)**
+
+Prerequisite:
+
+- You must have at least the Maintainer role for the group.
To manage group-level default settings for a project integration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Integrations**.
1. Select an integration.
1. Complete the fields.
@@ -119,20 +135,28 @@ is proposed in [epic 2137](https://gitlab.com/groups/gitlab-org/-/epics/2137).
### Remove a group-level default setting
+Prerequisite:
+
+- You must have at least the Maintainer role for the group.
+
To remove a group-level default setting:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Integrations**.
1. Select an integration.
1. Select **Reset** and confirm.
Resetting a group-level default setting removes integrations that use default settings and belong to a project or subgroup of the group.
-## Use instance-level or group-level default settings for a project integration
+## Use instance-level or group-level default settings for a project integration **(FREE ALL)**
+
+Prerequisite:
+
+- You must have at least the Maintainer role for the project.
To use instance-level or group-level default settings for a project integration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select an integration.
1. On the right, from the dropdown list, select **Use default settings**.
@@ -140,11 +164,15 @@ To use instance-level or group-level default settings for a project integration:
1. Complete the fields.
1. Select **Save changes**.
-## Use custom settings for a project or group integration
+## Use custom settings for a project or group integration **(FREE ALL)**
+
+Prerequisite:
+
+- You must have at least the Maintainer role for the project or group.
To use custom settings for a project or group integration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > Integrations**.
1. Select an integration.
1. On the right, from the dropdown list, select **Use custom settings**.
diff --git a/doc/administration/settings/protected_paths.md b/doc/administration/settings/protected_paths.md
index 5deba7dca11..3244c25e906 100644
--- a/doc/administration/settings/protected_paths.md
+++ b/doc/administration/settings/protected_paths.md
@@ -34,7 +34,7 @@ See also:
Throttling of protected paths is enabled by default and can be disabled or
customized.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Protected paths**.
diff --git a/doc/administration/settings/push_event_activities_limit.md b/doc/administration/settings/push_event_activities_limit.md
index ff924e0d208..36aa1eec306 100644
--- a/doc/administration/settings/push_event_activities_limit.md
+++ b/doc/administration/settings/push_event_activities_limit.md
@@ -26,7 +26,7 @@ the activity feed.
To modify this setting:
- In the Admin Area:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Performance optimization**.
diff --git a/doc/administration/settings/rate_limit_on_issues_creation.md b/doc/administration/settings/rate_limit_on_issues_creation.md
index 20f3febbf28..14d484d91b1 100644
--- a/doc/administration/settings/rate_limit_on_issues_creation.md
+++ b/doc/administration/settings/rate_limit_on_issues_creation.md
@@ -18,7 +18,7 @@ action blocks requests that exceed a rate of 300 per minute. Access to the endpo
To limit the number of requests made to the issue and epic creation endpoints:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Issues Rate Limits**.
diff --git a/doc/administration/settings/rate_limit_on_notes_creation.md b/doc/administration/settings/rate_limit_on_notes_creation.md
index 59548836e78..3bd6eee8303 100644
--- a/doc/administration/settings/rate_limit_on_notes_creation.md
+++ b/doc/administration/settings/rate_limit_on_notes_creation.md
@@ -13,7 +13,7 @@ You can configure the per-user rate limit for requests to the note creation endp
To change the note creation rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Notes rate limit**.
diff --git a/doc/administration/settings/rate_limit_on_pipelines_creation.md b/doc/administration/settings/rate_limit_on_pipelines_creation.md
index 19e1410ef73..d083acb190e 100644
--- a/doc/administration/settings/rate_limit_on_pipelines_creation.md
+++ b/doc/administration/settings/rate_limit_on_pipelines_creation.md
@@ -26,7 +26,7 @@ Requests that exceed the limit are logged in the `application_json.log` file.
To limit the number of pipeline requests:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Pipelines Rate Limits**.
diff --git a/doc/administration/settings/rate_limit_on_projects_api.md b/doc/administration/settings/rate_limit_on_projects_api.md
index 2192e4355c0..33304e4f088 100644
--- a/doc/administration/settings/rate_limit_on_projects_api.md
+++ b/doc/administration/settings/rate_limit_on_projects_api.md
@@ -16,7 +16,7 @@ You can configure the rate limit per IP address for unauthenticated requests to
To change the rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Projects API rate limit**.
diff --git a/doc/administration/settings/rate_limit_on_users_api.md b/doc/administration/settings/rate_limit_on_users_api.md
index 9424e508d86..3669d79a953 100644
--- a/doc/administration/settings/rate_limit_on_users_api.md
+++ b/doc/administration/settings/rate_limit_on_users_api.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -13,7 +13,7 @@ You can configure the per user rate limit for requests to [Users API](../../api/
To change the rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Users API rate limit**.
diff --git a/doc/administration/settings/rate_limits_on_git_ssh_operations.md b/doc/administration/settings/rate_limits_on_git_ssh_operations.md
index 64acb15b8ac..cb0d5e2a136 100644
--- a/doc/administration/settings/rate_limits_on_git_ssh_operations.md
+++ b/doc/administration/settings/rate_limits_on_git_ssh_operations.md
@@ -24,6 +24,8 @@ Users on self-managed GitLab can disable this rate limit.
## Configure GitLab Shell operation limit
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123761) in GitLab 16.2.
+
`Git operations using SSH` is enabled by default. Defaults to 600 per user per minute.
1. On the left sidebar, select **Your work > Admin Area**.
diff --git a/doc/administration/settings/rate_limits_on_raw_endpoints.md b/doc/administration/settings/rate_limits_on_raw_endpoints.md
index 78e65f7ba7b..237b57f4436 100644
--- a/doc/administration/settings/rate_limits_on_raw_endpoints.md
+++ b/doc/administration/settings/rate_limits_on_raw_endpoints.md
@@ -11,7 +11,7 @@ type: reference
This setting defaults to `300` requests per minute, and allows you to rate limit the requests to raw endpoints:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **Performance optimization**.
diff --git a/doc/administration/settings/scim_setup.md b/doc/administration/settings/scim_setup.md
index 6a02a5b832c..6028abf6eab 100644
--- a/doc/administration/settings/scim_setup.md
+++ b/doc/administration/settings/scim_setup.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -13,6 +13,7 @@ You can use the open standard System for Cross-domain Identity Management (SCIM)
- Create users.
- Block users.
+- Re-add users (reactivate SCIM identity).
The [internal GitLab SCIM API](../../development/internal_api/index.md#instance-scim-api) implements part of [the RFC7644 protocol](https://www.rfc-editor.org/rfc/rfc7644).
@@ -26,7 +27,7 @@ Prerequisites:
To configure GitLab SCIM:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **SCIM Token** section and select **Generate a SCIM token**.
@@ -41,3 +42,14 @@ the GitLab instance, while the SCIM identity remains linked to the GitLab user.
To update the user SCIM identity, use the
[internal GitLab SCIM API](../../development/internal_api/index.md#update-a-single-scim-provisioned-user-1).
+
+### Reactivate access
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/379149) in GitLab 16.0 [with a flag](../feature_flags.md) named `skip_saml_identity_destroy_during_scim_deprovision`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121226) in GitLab 16.4. Feature flag `skip_saml_identity_destroy_during_scim_deprovision` removed.
+
+After a user is removed or deactivated through SCIM, you can reactivate that user by
+adding them to the SCIM identity provider.
+
+After the identity provider performs a sync based on its configured schedule,
+the user's SCIM identity is reactivated and their GitLab instance access is restored.
diff --git a/doc/administration/settings/security_and_compliance.md b/doc/administration/settings/security_and_compliance.md
index 2237866ad9c..78923b19b04 100644
--- a/doc/administration/settings/security_and_compliance.md
+++ b/doc/administration/settings/security_and_compliance.md
@@ -11,13 +11,9 @@ The settings for package metadata synchronization are located in the [Admin Area
## Choose package registry metadata to sync
-WARNING:
-The full package metadata sync can add up to 30 GB to the PostgreSQL database. Ensure you have provisioned enough disk space for the database before enabling this feature.
-We are actively working on reducing this data size in [epic 10415](https://gitlab.com/groups/gitlab-org/-/epics/10415).
+To choose the packages you want to synchronize with the GitLab Package Metadata Database for [License Compliance](../../user/compliance/license_scanning_of_cyclonedx_files/index.md) and [Continuous Vulnerability Scanning](../../user/application_security/continuous_vulnerability_scanning/index.md):
-To choose the packages you want to synchronize with the GitLab License Database for [License Compliance](../../user/compliance/license_scanning_of_cyclonedx_files/index.md):
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Security and Compliance**.
1. Expand **License Compliance**.
diff --git a/doc/administration/settings/sidekiq_job_limits.md b/doc/administration/settings/sidekiq_job_limits.md
index d5cd24c5237..6c5ff29e96b 100644
--- a/doc/administration/settings/sidekiq_job_limits.md
+++ b/doc/administration/settings/sidekiq_job_limits.md
@@ -17,7 +17,7 @@ Redis. To avoid excessive memory for Redis, we:
To access Sidekiq job size limits:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Sidekiq job size limits**.
diff --git a/doc/administration/settings/sign_in_restrictions.md b/doc/administration/settings/sign_in_restrictions.md
index 393c7dd6aeb..6d38610192b 100644
--- a/doc/administration/settings/sign_in_restrictions.md
+++ b/doc/administration/settings/sign_in_restrictions.md
@@ -12,7 +12,7 @@ You can use **Sign-in restrictions** to customize authentication restrictions fo
To access sign-in restriction settings:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Sign-in restrictions** section.
@@ -76,7 +76,7 @@ Open the [Rails console](../operations/rails_console.md) and run the following:
To enable Admin Mode through the UI:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Sign-in restrictions**.
@@ -86,7 +86,7 @@ To enable Admin Mode through the UI:
To turn on Admin Mode for your current session and access potentially dangerous resources:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Enter Admin Mode**.
1. Try to access any part of the UI with `/admin` in the URL (which requires administrator access).
@@ -104,7 +104,7 @@ authentication are supported by Admin Mode. Admin Mode status is stored in the c
To turn off Admin Mode for your current session:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Leave Admin Mode**.
### Limitations of Admin Mode
@@ -181,7 +181,7 @@ For example, if you include the following information in the noted text box:
To access this text box:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Sign-in restrictions** section.
diff --git a/doc/administration/settings/sign_up_restrictions.md b/doc/administration/settings/sign_up_restrictions.md
index f255e15c1be..da40a2bab05 100644
--- a/doc/administration/settings/sign_up_restrictions.md
+++ b/doc/administration/settings/sign_up_restrictions.md
@@ -22,7 +22,7 @@ you do not expect public users to sign up for an account.
To disable sign ups:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Sign-up restrictions**.
@@ -40,7 +40,7 @@ enabled by default for new GitLab instances. It is only applicable if sign ups a
To require administrator approval for new sign ups:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Sign-up restrictions**.
@@ -66,7 +66,7 @@ their email address before they are allowed to sign in.
To enforce confirmation of the email address used for new sign ups:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Sign-up restrictions**.
@@ -107,7 +107,7 @@ Prerequisite:
To set a user cap:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Sign-up restrictions**.
@@ -127,7 +127,7 @@ Prerequisite:
To remove the user cap:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Sign-up restrictions**.
@@ -153,7 +153,7 @@ You can add additional complexity requirements. Changes to password complexity r
Existing passwords are unaffected. To change password complexity requirements:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Sign-up restrictions**.
@@ -183,7 +183,7 @@ reduce the risk of malicious users creating spam accounts with disposable email
To create an email domain allowlist or denylist:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Sign-up restrictions**.
diff --git a/doc/administration/settings/slack_app.md b/doc/administration/settings/slack_app.md
index a8e672bc8fa..ef756dfeff7 100644
--- a/doc/administration/settings/slack_app.md
+++ b/doc/administration/settings/slack_app.md
@@ -26,7 +26,7 @@ To create a GitLab for Slack app:
- **In GitLab**:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **GitLab for Slack app**.
@@ -46,7 +46,7 @@ You're then redirected to Slack for the next steps.
After you've [created a GitLab for Slack app](#create-a-gitlab-for-slack-app), you can configure the settings in GitLab:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **GitLab for Slack app**.
@@ -80,7 +80,7 @@ To update your copy of the GitLab for Slack app:
- **In GitLab**:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **GitLab for Slack app**.
diff --git a/doc/administration/settings/terms.md b/doc/administration/settings/terms.md
index 4b4972acc8e..12678b6416a 100644
--- a/doc/administration/settings/terms.md
+++ b/doc/administration/settings/terms.md
@@ -17,7 +17,7 @@ for example `https://gitlab.example.com/-/users/terms`.
To enforce acceptance of a Terms of Service and Privacy Policy:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Terms of Service and Privacy Policy** section.
diff --git a/doc/administration/settings/terraform_limits.md b/doc/administration/settings/terraform_limits.md
index 5ba8bfe63e0..7f744b0a4e5 100644
--- a/doc/administration/settings/terraform_limits.md
+++ b/doc/administration/settings/terraform_limits.md
@@ -15,7 +15,7 @@ state file version, and is checked whenever a new version is created.
To add a storage limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Preferences**.
1. Expand **Terraform limits**.
diff --git a/doc/administration/settings/third_party_offers.md b/doc/administration/settings/third_party_offers.md
index 39e2275f411..b91f13a6a30 100644
--- a/doc/administration/settings/third_party_offers.md
+++ b/doc/administration/settings/third_party_offers.md
@@ -18,7 +18,7 @@ questions when creating a group.
To toggle the display of customer experience improvement content and third-party offers:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Customer experience improvement and third-party offers**.
diff --git a/doc/administration/settings/usage_statistics.md b/doc/administration/settings/usage_statistics.md
index f77298dd038..b8b87f42475 100644
--- a/doc/administration/settings/usage_statistics.md
+++ b/doc/administration/settings/usage_statistics.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -64,7 +64,7 @@ Registration is not yet required for participation, but may be added in a future
### Enable registration features
1. Sign in as a user with administrator access.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Metrics and profiling**.
1. Expand the **Usage statistics** section.
@@ -122,7 +122,7 @@ If your GitLab instance is behind a proxy, set the appropriate
To enable or disable Service Ping and version check:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Metrics and profiling**.
1. Expand **Usage statistics**.
@@ -184,10 +184,9 @@ the Admin Area.
You can view the exact JSON payload sent to GitLab Inc. in the Admin Area. To view the payload:
1. Sign in as a user with administrator access.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
-1. Select **Settings > Metrics and profiling**.
-1. Expand the **Usage statistics** section.
+1. Select **Settings > Service usage data**.
1. Select **Preview payload**.
For an example payload, see [Example Service Ping payload](../../development/internal_analytics/service_ping/index.md#example-service-ping-payload).
@@ -203,9 +202,9 @@ or if the Service Ping [cron job](../../development/internal_analytics/service_p
To upload the payload manually:
1. Sign in as a user with administrator access.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
-1. Select **Settings > Service** usage data.
+1. Select **Settings > Service usage data**.
1. Select **Download payload**.
1. Save the JSON file.
1. Visit [Service usage data center](https://version.gitlab.com/usage_data/new).
diff --git a/doc/administration/settings/user_and_ip_rate_limits.md b/doc/administration/settings/user_and_ip_rate_limits.md
index 822ba4dd03e..09ddb784191 100644
--- a/doc/administration/settings/user_and_ip_rate_limits.md
+++ b/doc/administration/settings/user_and_ip_rate_limits.md
@@ -31,7 +31,7 @@ counted as web traffic.
To enable the unauthenticated request rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **User and IP rate limits**.
@@ -46,7 +46,7 @@ To enable the unauthenticated request rate limit:
To enable the unauthenticated request rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **User and IP rate limits**.
@@ -61,7 +61,7 @@ To enable the unauthenticated request rate limit:
To enable the authenticated API request rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **User and IP rate limits**.
@@ -76,7 +76,7 @@ To enable the authenticated API request rate limit:
To enable the unauthenticated request rate limit:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **User and IP rate limits**.
@@ -96,7 +96,7 @@ plain-text body, which by default is `Retry later`.
To use a custom response:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Network**.
1. Expand **User and IP rate limits**.
diff --git a/doc/administration/settings/visibility_and_access_controls.md b/doc/administration/settings/visibility_and_access_controls.md
index 5e1e35db244..93dbfaaf990 100644
--- a/doc/administration/settings/visibility_and_access_controls.md
+++ b/doc/administration/settings/visibility_and_access_controls.md
@@ -13,7 +13,7 @@ specific controls on branches, projects, snippets, groups, and more.
To access the visibility and access control options:
1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -25,7 +25,7 @@ Instance-level protections for project creation define which roles can
on the instance. To alter which roles have permission to create projects:
1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -42,7 +42,7 @@ on the instance. To alter which roles have permission to create projects:
By default both administrators and anyone with the **Owner** role can delete a project. To restrict project deletion to only administrators:
1. Sign in to GitLab as a user with administrator access.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -80,7 +80,7 @@ then it gets automatically changed to `1` while also disabling deletion protecti
To configure delayed project deletion:
1. Sign in to GitLab as a user with administrator access.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -121,7 +121,7 @@ Alternatively, projects that are marked for removal can be deleted immediately.
To set the default [visibility levels for new projects](../../user/public_access.md):
1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -132,12 +132,15 @@ To set the default [visibility levels for new projects](../../user/public_access
- **Public** - The project can be accessed without any authentication.
1. Select **Save changes**.
+For more details on project visibility, see
+[Project visibility](../../user/public_access.md).
+
## Configure snippet visibility defaults
To set the default visibility levels for new [snippets](../../user/snippets.md):
1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -145,14 +148,14 @@ To set the default visibility levels for new [snippets](../../user/snippets.md):
1. Select **Save changes**.
For more details on snippet visibility, read
-[Project visibility](../../user/public_access.md).
+[Snippet visibility](../../user/snippets.md).
## Configure group visibility defaults
To set the default visibility levels for new groups:
1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -167,6 +170,9 @@ For more details on group visibility, see
## Restrict visibility levels
+> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124649) in GitLab 16.3 to prevent restricting default project and group visibility, [with a flag](../feature_flags.md) named `prevent_visibility_restriction`. Disabled by default.
+> - `prevent_visibility_restriction` [enabled](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131203) by default in GitLab 16.4.
+
When restricting visibility levels, consider how these restrictions interact
with permissions for subgroups and projects that inherit their visibility from
the item you're changing.
@@ -174,7 +180,7 @@ the item you're changing.
To restrict visibility levels for groups, projects, snippets, and selected pages:
1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -191,56 +197,8 @@ To restrict visibility levels for groups, projects, snippets, and selected pages
- Only administrators are able to create private groups, projects, and snippets.
1. Select **Save changes**.
-For more details on project visibility, see
-[Project visibility](../../user/public_access.md).
-
-## Configure allowed import sources
-
-Before you can import projects from other systems, you must enable the
-[import source](../../user/gitlab_com/index.md#default-import-sources) for that system.
-
-1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**.
-1. Expand the **Visibility and access controls** section.
-1. Select each of **Import sources** to allow.
-1. Select **Save changes**.
-
-## Enable project export
-
-To enable the export of
-[projects and their data](../../user/project/settings/import_export.md#export-a-project-and-its-data):
-
-1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**.
-1. Expand the **Visibility and access controls** section.
-1. Scroll to **Project export**.
-1. Select the **Enabled** checkbox.
-1. Select **Save changes**.
-
-## Enable migration of groups and projects by direct transfer
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383268) in GitLab 15.8.
-
-You can enable migration of groups by direct transfer using the UI.
-
-To enable migration of groups by direct transfer:
-
-1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**.
-1. Expand the **Visibility and access controls** section.
-1. Scroll to **Allow migrating GitLab groups and projects by direct transfer**.
-1. Select the **Enabled** checkbox.
-1. Select **Save changes**.
-
-The same setting
-[is available](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls) in the API as the
-`bulk_import_enabled` attribute.
+NOTE:
+You cannot select the restricted default visibility level for new projects and groups.
## Configure enabled Git access protocols
@@ -252,7 +210,7 @@ The GitLab restrictions apply at the application level.
To specify the enabled Git access protocols:
1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
@@ -339,7 +297,7 @@ include the `10.0.0.0/24` range.
To add a IP address range to the group-level allowlist:
1. Sign in to GitLab as a user with Administrator access level.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Visibility and access controls** section.
diff --git a/doc/administration/sidekiq/extra_sidekiq_processes.md b/doc/administration/sidekiq/extra_sidekiq_processes.md
index d85eae7a7f6..89de4cd6cf3 100644
--- a/doc/administration/sidekiq/extra_sidekiq_processes.md
+++ b/doc/administration/sidekiq/extra_sidekiq_processes.md
@@ -48,7 +48,7 @@ to all available queues:
To view the Sidekiq processes in GitLab:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Monitoring > Background Jobs**.
diff --git a/doc/administration/sidekiq/sidekiq_job_migration.md b/doc/administration/sidekiq/sidekiq_job_migration.md
index 89da174eb34..10a1faea850 100644
--- a/doc/administration/sidekiq/sidekiq_job_migration.md
+++ b/doc/administration/sidekiq/sidekiq_job_migration.md
@@ -26,7 +26,7 @@ If the Sidekiq routing rules are changed, administrators need to take care with
Step 4 involves rewriting some Sidekiq job data for jobs that are already stored in Redis, but due to run in future. There are two sets of jobs to run in future: scheduled jobs and jobs to be retried. We provide a separate Rake task to migrate each set:
- `gitlab:sidekiq:migrate_jobs:retry` for jobs to be retried.
-- `gitlab:sidekiq:migrate_jobs:scheduled` for scheduled jobs.
+- `gitlab:sidekiq:migrate_jobs:schedule` for scheduled jobs.
Queued jobs that are yet to be run can also be migrated with a Rake task ([available in GitLab 15.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101348) and later):
diff --git a/doc/administration/silent_mode/index.md b/doc/administration/silent_mode/index.md
index 005add1d2f4..379b00536f3 100644
--- a/doc/administration/silent_mode/index.md
+++ b/doc/administration/silent_mode/index.md
@@ -4,11 +4,12 @@ group: Geo
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# GitLab Silent Mode (Experiment) **(FREE SELF)**
+# GitLab Silent Mode **(FREE SELF EXPERIMENT)**
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/9826) in GitLab 15.11. This feature is an [Experiment](../../policy/experiment-beta-support.md#experiment).
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/9826) in GitLab 15.11. This feature is an [Experiment](../../policy/experiment-beta-support.md#experiment).
+> - Enabling and disabling Silent Mode through the web UI was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131090) in GitLab 16.4
-Silent Mode allows you to suppress outbound communication, such as emails, from GitLab. Silent Mode is not intended to be used on environments which are in-use. Two use-cases are:
+Silent Mode allows you to silence outbound communication, such as emails, from GitLab. Silent Mode is not intended to be used on environments which are in-use. Two use-cases are:
- Validating Geo site promotion. You have a secondary Geo site as part of your [disaster recovery](../geo/disaster_recovery/index.md) solution. You want to regularly test promoting it to become a primary Geo site, as a best practice to ensure your disaster recovery plan actually works. But you don't want to actually perform an entire failover, since the primary site lives in a region which provides the lowest latency to your users. And you don't want to take downtime during every regular test. So, you let the primary site remain up, while you promote the secondary site. You start smoke testing the promoted site. But, the promoted site starts emailing users, the push mirrors push changes to external Git repositories, etc. This is where Silent Mode comes in. You can enable it as part of site promotion, to avoid this issue.
- Validating GitLab backups. You set up a testing instance to test that your backups restore successfully. As part of the restore, you enable Silent Mode, for example to avoid sending invalid emails to users.
@@ -19,7 +20,15 @@ Prerequisites:
- You must have administrator access.
-There are two ways to enable Silent Mode:
+There are multiple ways to enable Silent Mode:
+
+- **Web UI**
+
+ 1. On the left sidebar, select **Search or go to**.
+ 1. Select **Admin Area**.
+ 1. On the left sidebar, select **Settings > General**.
+ 1. Expand **Silent Mode**, and toggle **Enable Silent Mode**.
+ 1. Changes are saved immediately.
- [**API**](../../api/settings.md):
@@ -41,7 +50,15 @@ Prerequisites:
- You must have administrator access.
-There are two ways to disable Silent Mode:
+There are multiple ways to disable Silent Mode:
+
+- **Web UI**
+
+ 1. On the left sidebar, select **Search or go to**.
+ 1. Select **Admin Area**.
+ 1. On the left sidebar, select **Settings > General**.
+ 1. Expand **Silent Mode**, and toggle **Enable Silent Mode**.
+ 1. Changes are saved immediately.
- [**API**](../../api/settings.md):
@@ -61,32 +78,32 @@ It may take up to a minute to take effect. [Issue 405433](https://gitlab.com/git
This section documents the current behavior of GitLab when Silent Mode is enabled. While Silent Mode is an Experiment, the behavior may change without notice. The work for the first iteration of Silent Mode is tracked by [Epic 9826](https://gitlab.com/groups/gitlab-org/-/epics/9826).
-### Service Desk
-
-Incoming emails still raise issues, but the users who sent the emails to [Service Desk](../../user/project/service_desk/index.md) are not notified of issue creation or comments on their issues.
-
-### Webhooks
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393639) in GitLab 16.3.
-
-[Project and group webhooks](../../user/project/integrations/webhooks.md) and [system hooks](../system_hooks.md) are suppressed.
-
-In GitLab 16.2 and earlier, webhooks were triggered when Silent Mode was enabled, but the [webhook HTTP request was blocked](#outbound-http-requests).
-
-Triggering webhook tests via the UI results in HTTP status 500 responses.
-
-### Remote mirrors
-
-Updates on [remote mirrors](../../user/project/repository/mirror/index.md) (pushing to, and pulling from them) are suppressed.
+When Silent Mode is enabled, a banner is displayed at the top of the page for all users stating the setting is enabled and **All outbound communications are blocked.**.
-### Integrations
+### Outbound communications that are silenced
-Executable [integrations](../../user/project/integrations/index.md) are suppressed.
+Outbound communications from the following features are silenced by Silent Mode.
-### Outbound emails
+| Feature | Notes |
+| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Project and group webhooks](../../user/project/integrations/webhooks.md) | Triggering webhook tests via the UI results in HTTP status 500 responses. |
+| [System hooks](../system_hooks.md) | |
+| [Remote mirrors](../../user/project/repository/mirror/index.md) | Pushes to remote mirrors are skipped. Pulls from remote mirrors is skipped. |
+| [Executable integrations](../../user/project/integrations/index.md) | The integrations are not executed. |
+| [Service Desk](../../user/project/service_desk/index.md) | Incoming emails still raise issues, but the users who sent the emails to Service Desk are not notified of issue creation or comments on their issues. |
+| Outbound emails | |
+| Outbound HTTP requests | Many HTTP requests are blocked where features are not blocked or skipped explicitly. These may produce errors. If a particular error is problematic for testing during Silent Mode, please consult [GitLab Support](https://about.gitlab.com/support/). |
-Outbound emails are suppressed.
+### Outbound communications that are not silenced
-### Outbound HTTP requests
+Outbound communications from the following features are not silenced by Silent Mode.
-Many outbound HTTP requests are suppressed. A list of unsuppressed requests does not exist at this time, since more suppression is planned.
+| Feature | Notes |
+| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Dependency proxy](../packages/dependency_proxy.md) | Pulling images that are not cached will fetch from the source as usual. Consider pull rate limits. |
+| [File hooks](../file_hooks.md) | |
+| [Server hooks](../server_hooks.md) | |
+| [Advanced search](../../integration/advanced_search/elasticsearch.md) | If two GitLab instances are using the same Advanced Search instance, then they can both modify Search data. This is a split-brain scenario which can occur for example after promoting a secondary Geo site while the primary Geo site is live. |
+| [Snowplow](../../user/product_analytics/index.md) | There is [a proposal to silence these requests](https://gitlab.com/gitlab-org/gitlab/-/issues/409661). |
+| [Deprecated Kubernetes Connections](../../user/clusters/agent/index.md) | There is [a proposal to silence these requests](https://gitlab.com/gitlab-org/gitlab/-/issues/396470). |
+| [Container registry webhooks](../packages/container_registry.md#configure-container-registry-notifications) | There is [a proposal to silence these requests](https://gitlab.com/gitlab-org/gitlab/-/issues/409682). |
diff --git a/doc/administration/static_objects_external_storage.md b/doc/administration/static_objects_external_storage.md
index 6b232ddc25f..203f59b60f7 100644
--- a/doc/administration/static_objects_external_storage.md
+++ b/doc/administration/static_objects_external_storage.md
@@ -16,7 +16,7 @@ storage such as a content delivery network (CDN).
To configure external storage for static objects:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Repository**.
1. Expand the **External storage for repository static objects** section.
diff --git a/doc/administration/system_hooks.md b/doc/administration/system_hooks.md
index 1c84d4fadb8..61f89bacd66 100644
--- a/doc/administration/system_hooks.md
+++ b/doc/administration/system_hooks.md
@@ -54,7 +54,7 @@ for Push and Tag events, but we never display commits.
To create a system hook:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **System Hooks**.
1. Select **Add new webhook**.
diff --git a/doc/administration/troubleshooting/postgresql.md b/doc/administration/troubleshooting/postgresql.md
index 53bde005232..e7965d451b6 100644
--- a/doc/administration/troubleshooting/postgresql.md
+++ b/doc/administration/troubleshooting/postgresql.md
@@ -18,14 +18,70 @@ If you're on a [paid tier](https://about.gitlab.com/pricing/) and aren't sure
how to use these commands, [contact Support](https://about.gitlab.com/support/)
for assistance with any issues you're having.
+## Start a database console
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+Recommended for:
+
+- Single-node instances.
+- Scaled out or hybrid environments, on the Patroni nodes, usually the leader.
+- Scaled out or hybrid environments, on the server running the PostgreSQL service.
+
+```shell
+sudo gitlab-psql
+```
+
+On a single-node instance, or a web or Sidekiq node you can also use the Rails database console, but
+it takes longer to initialize:
+
+- In [GitLab 14.2 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/341210):
+
+ ```shell
+ sudo gitlab-rails db-console --database main
+ ```
+
+- In GitLab 14.1 and earlier:
+
+ ```shell
+ sudo gitlab-rails db-console
+ ```
+
+:::TabTitle Docker
+
+```shell
+docker exec -it <container-id> gitlab-psql
+```
+
+:::TabTitle Self-compiled (source)
+
+Use the `psql` command that's part of [your PostgreSQL installation](../../install/installation.md#7-database).
+
+```shell
+sudo -u git -H psql -d gitlabhq_production
+```
+
+:::TabTitle Helm chart (Kubernetes)
+
+- If you run a hybrid environment, and PostgreSQL runs on a Linux packaged installation (Omnibus),
+ the recommended approach is to use the database console locally on those servers. Refer to the details
+ for Linux package.
+- Use the console that's part of your external third-party PostgreSQL service.
+- Run `gitlab-rails db-console` in the toolbox pod.
+ - Refer to our [Kubernetes cheat sheet](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html#gitlab-specific-kubernetes-information) for details.
+
+::EndTabs
+
+To exit the console, type: `quit`.
+
## Other GitLab PostgreSQL documentation
This section is for links to information elsewhere in the GitLab documentation.
### Procedures
-- [Connect to the PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database).
-
- [Database procedures for Linux package installations](https://docs.gitlab.com/omnibus/settings/database.html) including:
- SSL: enabling, disabling, and verifying.
- Enabling Write Ahead Log (WAL) archiving.
diff --git a/doc/administration/user_cohorts.md b/doc/administration/user_cohorts.md
index 6f2798f437c..c849d3115d2 100644
--- a/doc/administration/user_cohorts.md
+++ b/doc/administration/user_cohorts.md
@@ -34,7 +34,7 @@ How do we measure the activity of users? GitLab considers a user active if:
To view user cohorts:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select the **Cohorts** tab.
diff --git a/doc/administration/user_settings.md b/doc/administration/user_settings.md
index 43e88bf6eac..d1884bf179b 100644
--- a/doc/administration/user_settings.md
+++ b/doc/administration/user_settings.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -44,7 +44,7 @@ For self-compiled installations:
Administrators can:
-- Use the Admin Area to [prevent an existing user from creating top-level groups](../administration/admin_area.md#prevent-a-user-from-creating-groups).
+- Use the Admin Area to [prevent an existing user from creating top-level groups](../administration/admin_area.md#prevent-a-user-from-creating-top-level-groups).
- Use the [modify an existing user API endpoint](../api/users.md#user-modification) to change the `can_create_group` setting.
## Prevent users from changing their usernames
diff --git a/doc/administration/whats-new.md b/doc/administration/whats-new.md
index 8e1fc412a62..6d186ef0af5 100644
--- a/doc/administration/whats-new.md
+++ b/doc/administration/whats-new.md
@@ -31,7 +31,7 @@ To access the **What's new** feature:
You can configure **What's new** to display features based on the tier,
or you can hide it. To configure it:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Preferences**.
1. Expand **What's new**, and choose one of the following options:
diff --git a/doc/api/access_requests.md b/doc/api/access_requests.md
index 341cb768154..bd4c4df5660 100644
--- a/doc/api/access_requests.md
+++ b/doc/api/access_requests.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
---
diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md
index 5b918fa50ab..9f2a57dd84f 100644
--- a/doc/api/api_resources.md
+++ b/doc/api/api_resources.md
@@ -34,7 +34,7 @@ The following API resources are available in the project context:
| [Conan distributions](packages/conan.md) | `/projects/:id/packages/conan` (also available standalone) |
| [Debian distributions](packages/debian_project_distributions.md) | `/projects/:id/debian_distributions` (also available for groups) |
| [Debian packages](packages/debian.md) | `/projects/:id/packages/debian` (also available for groups) |
-| [Dependencies](dependencies.md) **(ULTIMATE)** | `/projects/:id/dependencies` |
+| [Dependencies](dependencies.md) **(ULTIMATE ALL)** | `/projects/:id/dependencies` |
| [Deploy keys](deploy_keys.md) | `/projects/:id/deploy_keys` (also available standalone) |
| [Deploy tokens](deploy_tokens.md) | `/projects/:id/deploy_tokens` (also available for groups and standalone) |
| [Deployments](deployments.md) | `/projects/:id/deployments` |
@@ -56,14 +56,14 @@ The following API resources are available in the project context:
| [Issue links](issue_links.md) | `/projects/:id/issues/.../links` |
| [Issues Statistics](issues_statistics.md) | `/projects/:id/issues_statistics` (also available for groups and standalone) |
| [Issues](issues.md) | `/projects/:id/issues` (also available for groups and standalone) |
-| [Iterations](iterations.md) **(PREMIUM)** | `/projects/:id/iterations` (also available for groups) |
+| [Iterations](iterations.md) **(PREMIUM ALL)** | `/projects/:id/iterations` (also available for groups) |
| [Project CI/CD job token scope](project_job_token_scopes.md) | `/projects/:id/job_token_scope` |
| [Jobs](jobs.md) | `/projects/:id/jobs`, `/projects/:id/pipelines/.../jobs` |
| [Jobs Artifacts](job_artifacts.md) | `/projects/:id/jobs/:job_id/artifacts` |
| [Labels](labels.md) | `/projects/:id/labels` |
| [Maven repository](packages/maven.md) | `/projects/:id/packages/maven` (also available for groups and standalone) |
| [Members](members.md) | `/projects/:id/members` (also available for groups) |
-| [Merge request approvals](merge_request_approvals.md) **(PREMIUM)** | `/projects/:id/approvals`, `/projects/:id/merge_requests/.../approvals` |
+| [Merge request approvals](merge_request_approvals.md) **(PREMIUM ALL)** | `/projects/:id/approvals`, `/projects/:id/merge_requests/.../approvals` |
| [Merge requests](merge_requests.md) | `/projects/:id/merge_requests` (also available for groups and standalone) |
| [Merge trains](merge_trains.md) | `/projects/:id/merge_trains` |
| [Metadata](metadata.md) | `/metadata` |
@@ -82,7 +82,7 @@ The following API resources are available in the project context:
| [Project milestones](milestones.md) | `/projects/:id/milestones` |
| [Project snippets](project_snippets.md) | `/projects/:id/snippets` |
| [Project templates](project_templates.md) | `/projects/:id/templates` |
-| [Project vulnerabilities](project_vulnerabilities.md) **(ULTIMATE)** | `/projects/:id/vulnerabilities` |
+| [Project vulnerabilities](project_vulnerabilities.md) **(ULTIMATE ALL)** | `/projects/:id/vulnerabilities` |
| [Project wikis](wikis.md) | `/projects/:id/wikis` |
| [Project-level variables](project_level_variables.md) | `/projects/:id/variables` |
| [Projects](projects.md) including setting Webhooks | `/projects`, `/projects/:id/hooks` (also available for users) |
@@ -103,46 +103,47 @@ The following API resources are available in the project context:
| [Tags](tags.md) | `/projects/:id/repository/tags` |
| [Terraform modules](packages/terraform-modules.md) | `/projects/:id/packages/terraform/modules` (also available standalone) |
| [User-starred metrics dashboards](metrics_user_starred_dashboards.md ) | `/projects/:id/metrics/user_starred_dashboards` |
-| [Visual Review discussions](visual_review_discussions.md) **(PREMIUM)** | `/projects/:id/merge_requests/:merge_request_id/visual_review_discussions` |
-| [Vulnerabilities](vulnerabilities.md) **(ULTIMATE)** | `/vulnerabilities/:id` |
-| [Vulnerability exports](vulnerability_exports.md) **(ULTIMATE)** | `/projects/:id/vulnerability_exports` |
-| [Vulnerability findings](vulnerability_findings.md) **(ULTIMATE)** | `/projects/:id/vulnerability_findings` |
+| [Visual Review discussions](visual_review_discussions.md) **(PREMIUM ALL)** | `/projects/:id/merge_requests/:merge_request_id/visual_review_discussions` |
+| [Vulnerabilities](vulnerabilities.md) **(ULTIMATE ALL)** | `/vulnerabilities/:id` |
+| [Vulnerability exports](vulnerability_exports.md) **(ULTIMATE ALL)** | `/projects/:id/vulnerability_exports` |
+| [Vulnerability findings](vulnerability_findings.md) **(ULTIMATE ALL)** | `/projects/:id/vulnerability_findings` |
## Group resources
The following API resources are available in the group context:
-| Resource | Available endpoints |
-|:-----------------------------------------------------------------|:--------------------|
-| [Access requests](access_requests.md) | `/groups/:id/access_requests/` (also available for projects) |
-| [Access tokens](group_access_tokens.md) | `/groups/:id/access_tokens` (also available for projects) |
-| [Custom attributes](custom_attributes.md) | `/groups/:id/custom_attributes` (also available for projects and users) |
-| [Debian distributions](packages/debian_group_distributions.md) | `/groups/:id/-/packages/debian` (also available for projects) |
-| [Deploy tokens](deploy_tokens.md) | `/groups/:id/deploy_tokens` (also available for projects and standalone) |
-| [Discussions](discussions.md) (comments and threads) | `/groups/:id/epics/.../discussions` (also available for projects) |
-| [Epic issues](epic_issues.md) **(PREMIUM)** | `/groups/:id/epics/.../issues` |
-| [Epic links](epic_links.md) **(PREMIUM)** | `/groups/:id/epics/.../epics` |
-| [Epics](epics.md) **(PREMIUM)** | `/groups/:id/epics` |
-| [Groups](groups.md) | `/groups`, `/groups/.../subgroups` |
-| [Group badges](group_badges.md) | `/groups/:id/badges` |
-| [Group issue boards](group_boards.md) | `/groups/:id/boards` |
-| [Group iterations](group_iterations.md) **(PREMIUM)** | `/groups/:id/iterations` (also available for projects) |
-| [Group labels](group_labels.md) | `/groups/:id/labels` |
-| [Group-level variables](group_level_variables.md) | `/groups/:id/variables` |
-| [Group milestones](group_milestones.md) | `/groups/:id/milestones` |
-| [Group releases](group_releases.md) | `/groups/:id/releases`|
-| [Group wikis](group_wikis.md) **(PREMIUM)** | `/groups/:id/wikis` |
-| [Invitations](invitations.md) | `/groups/:id/invitations` (also available for projects) |
-| [Issues](issues.md) | `/groups/:id/issues` (also available for projects and standalone) |
-| [Issues Statistics](issues_statistics.md) | `/groups/:id/issues_statistics` (also available for projects and standalone) |
-| [Linked epics](linked_epics.md) | `/groups/:id/epics/.../related_epics` |
-| [Member Roles](member_roles.md) | `/groups/:id/member_roles` |
-| [Members](members.md) | `/groups/:id/members` (also available for projects) |
-| [Merge requests](merge_requests.md) | `/groups/:id/merge_requests` (also available for projects and standalone) |
-| [Notes](notes.md) (comments) | `/groups/:id/epics/.../notes` (also available for projects) |
-| [Notification settings](notification_settings.md) | `/groups/:id/notification_settings` (also available for projects and standalone) |
-| [Resource label events](resource_label_events.md) | `/groups/:id/epics/.../resource_label_events` (also available for projects) |
-| [Search](search.md) | `/groups/:id/search` (also available for projects and standalone) |
+| Resource | Available endpoints |
+|:----------------------------------------------------------------------|:---------------------------------------------------------------------------------|
+| [Access requests](access_requests.md) | `/groups/:id/access_requests/` (also available for projects) |
+| [Access tokens](group_access_tokens.md) | `/groups/:id/access_tokens` (also available for projects) |
+| [Custom attributes](custom_attributes.md) | `/groups/:id/custom_attributes` (also available for projects and users) |
+| [Debian distributions](packages/debian_group_distributions.md) | `/groups/:id/-/packages/debian` (also available for projects) |
+| [Deploy tokens](deploy_tokens.md) | `/groups/:id/deploy_tokens` (also available for projects and standalone) |
+| [Discussions](discussions.md) (comments and threads) | `/groups/:id/epics/.../discussions` (also available for projects) |
+| [Epic issues](epic_issues.md) **(PREMIUM ALL)** | `/groups/:id/epics/.../issues` |
+| [Epic links](epic_links.md) **(PREMIUM ALL)** | `/groups/:id/epics/.../epics` |
+| [Epics](epics.md) **(PREMIUM ALL)** | `/groups/:id/epics` |
+| [Groups](groups.md) | `/groups`, `/groups/.../subgroups` |
+| [Group badges](group_badges.md) | `/groups/:id/badges` |
+| [Group issue boards](group_boards.md) | `/groups/:id/boards` |
+| [Group iterations](group_iterations.md) **(PREMIUM ALL)** | `/groups/:id/iterations` (also available for projects) |
+| [Group labels](group_labels.md) | `/groups/:id/labels` |
+| [Group-level variables](group_level_variables.md) | `/groups/:id/variables` |
+| [Group milestones](group_milestones.md) | `/groups/:id/milestones` |
+| [Group releases](group_releases.md) | `/groups/:id/releases` |
+| [Group SSH certificates](group_ssh_certificates.md) **(PREMIUM ALL)** | `/groups/:id/ssh_certificates` |
+| [Group wikis](group_wikis.md) **(PREMIUM ALL)** | `/groups/:id/wikis` |
+| [Invitations](invitations.md) | `/groups/:id/invitations` (also available for projects) |
+| [Issues](issues.md) | `/groups/:id/issues` (also available for projects and standalone) |
+| [Issues Statistics](issues_statistics.md) | `/groups/:id/issues_statistics` (also available for projects and standalone) |
+| [Linked epics](linked_epics.md) | `/groups/:id/epics/.../related_epics` |
+| [Member Roles](member_roles.md) | `/groups/:id/member_roles` |
+| [Members](members.md) | `/groups/:id/members` (also available for projects) |
+| [Merge requests](merge_requests.md) | `/groups/:id/merge_requests` (also available for projects and standalone) |
+| [Notes](notes.md) (comments) | `/groups/:id/epics/.../notes` (also available for projects) |
+| [Notification settings](notification_settings.md) | `/groups/:id/notification_settings` (also available for projects and standalone) |
+| [Resource label events](resource_label_events.md) | `/groups/:id/epics/.../resource_label_events` (also available for projects) |
+| [Search](search.md) | `/groups/:id/search` (also available for projects and standalone) |
## Standalone resources
@@ -156,8 +157,9 @@ The following API resources are available outside of project and group contexts
| [Avatar](avatar.md) | `/avatar` |
| [Broadcast messages](broadcast_messages.md) | `/broadcast_messages` |
| [Code snippets](snippets.md) | `/snippets` |
-| [Code suggestions](code_suggestions.md) | `/code_suggestions` |
+| [Code Suggestions](code_suggestions.md) | `/code_suggestions` |
| [Custom attributes](custom_attributes.md) | `/users/:id/custom_attributes` (also available for groups and projects) |
+| [Dependency list exports](dependency_list_export.md) **(ULTIMATE ALL)** | `/pipelines/:id/dependency_list_exports`, `/projects/:id/dependency_list_exports`, `/groups/:id/dependency_list_exports`, `/security/dependency_list_exports/:id`, `/security/dependency_list_exports/:id/download` |
| [Deploy keys](deploy_keys.md) | `/deploy_keys` (also available for projects) |
| [Deploy tokens](deploy_tokens.md) | `/deploy_tokens` (also available for projects and groups) |
| [Events](events.md) | `/events`, `/users/:id/events` (also available for projects) |
diff --git a/doc/api/appearance.md b/doc/api/appearance.md
index 94fb092c739..4018e787acf 100644
--- a/doc/api/appearance.md
+++ b/doc/api/appearance.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/applications.md b/doc/api/applications.md
index f597e1acc44..9875dfab96d 100644
--- a/doc/api/applications.md
+++ b/doc/api/applications.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/audit_events.md b/doc/api/audit_events.md
index 714c79c42c5..0e60fdbcd0a 100644
--- a/doc/api/audit_events.md
+++ b/doc/api/audit_events.md
@@ -11,8 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## Instance Audit Events **(PREMIUM SELF)**
-The Audit Events API allows you to retrieve [instance audit events](../administration/audit_events.md#instance-events).
-This API cannot retrieve group or project audit events.
+Use this API to retrieve instance audit events.
To retrieve audit events using the API, you must [authenticate yourself](rest/index.md#authentication) as an Administrator.
@@ -165,8 +164,7 @@ Example response:
> Support for keyset pagination [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333968) in GitLab 15.2.
-The Group Audit Events API allows you to retrieve [group audit events](../administration/audit_events.md#group-events).
-This API cannot retrieve project audit events.
+Use this API to retrieve group audit events.
A user with:
@@ -283,7 +281,7 @@ Example response:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/219238) in GitLab 13.1.
-The Project Audit Events API allows you to retrieve [project audit events](../administration/audit_events.md#project-events).
+Use this API to retrieve project audit events.
A user with a Maintainer role (or above) can retrieve project audit events of all users.
A user with a Developer role is limited to project audit events based on their individual actions.
diff --git a/doc/api/avatar.md b/doc/api/avatar.md
index 68031a05f43..98e644d9ae9 100644
--- a/doc/api/avatar.md
+++ b/doc/api/avatar.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/award_emoji.md b/doc/api/award_emoji.md
index 2591c6ea490..1ccc59601a0 100644
--- a/doc/api/award_emoji.md
+++ b/doc/api/award_emoji.md
@@ -13,7 +13,7 @@ An [emoji reaction](../user/award_emojis.md) tells a thousand words.
We call GitLab objects on which you can react with an emoji "awardables".
You can react with emoji on the following:
-- [Epics](../user/group/epics/index.md) ([API](epics.md)). **(PREMIUM)**
+- [Epics](../user/group/epics/index.md) ([API](epics.md)). **(PREMIUM ALL)**
- [Issues](../user/project/issues/index.md) ([API](issues.md)).
- [Merge requests](../user/project/merge_requests/index.md) ([API](merge_requests.md)).
- [Snippets](../user/snippets.md) ([API](snippets.md)).
diff --git a/doc/api/boards.md b/doc/api/boards.md
index 2438508f2f9..34aa7d6e68a 100644
--- a/doc/api/boards.md
+++ b/doc/api/boards.md
@@ -228,10 +228,10 @@ PUT /projects/:id/boards/:board_id
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `board_id` | integer | yes | The ID of a board |
| `name` | string | no | The new name of the board |
-| `assignee_id` **(PREMIUM)** | integer | no | The assignee the board should be scoped to |
-| `milestone_id` **(PREMIUM)** | integer | no | The milestone the board should be scoped to |
-| `labels` **(PREMIUM)** | string | no | Comma-separated list of label names which the board should be scoped to |
-| `weight` **(PREMIUM)** | integer | no | The weight range from 0 to 9, to which the board should be scoped to |
+| `assignee_id` **(PREMIUM ALL)** | integer | no | The assignee the board should be scoped to |
+| `milestone_id` **(PREMIUM ALL)** | integer | no | The milestone the board should be scoped to |
+| `labels` **(PREMIUM ALL)** | string | no | Comma-separated list of label names which the board should be scoped to |
+| `weight` **(PREMIUM ALL)** | integer | no | The weight range from 0 to 9, to which the board should be scoped to |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/boards/1?name=new_name&milestone_id=43&assignee_id=1&labels=Doing&weight=4"
@@ -421,8 +421,8 @@ POST /projects/:id/boards/:board_id/lists
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `board_id` | integer | yes | The ID of a board |
| `label_id` | integer | no | The ID of a label |
-| `assignee_id` **(PREMIUM)** | integer | no | The ID of a user |
-| `milestone_id` **(PREMIUM)** | integer | no | The ID of a milestone |
+| `assignee_id` **(PREMIUM ALL)** | integer | no | The ID of a user |
+| `milestone_id` **(PREMIUM ALL)** | integer | no | The ID of a milestone |
NOTE:
Label, assignee and milestone arguments are mutually exclusive,
diff --git a/doc/api/branches.md b/doc/api/branches.md
index b925d3ddadf..cd0266a05f1 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -50,19 +50,22 @@ Example response:
"can_push": true,
"web_url": "https://gitlab.example.com/my-group/my-project/-/tree/main",
"commit": {
- "author_email": "john@example.com",
- "author_name": "John Smith",
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00",
- "committer_email": "john@example.com",
- "committer_name": "John Smith",
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"short_id": "7b5c3cc",
- "title": "add projects API",
- "message": "add projects API",
+ "created_at": "2012-06-28T03:44:20-07:00",
"parent_ids": [
"4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- ]
+ ],
+ "title": "add projects API",
+ "message": "add projects API",
+ "author_name": "John Smith",
+ "author_email": "john@example.com",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committer_name": "John Smith",
+ "committer_email": "john@example.com",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "trailers": {},
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/commit/7b5c3cc8be40ee161ae89a06bba6229da1032a0c"
}
},
...
@@ -97,7 +100,7 @@ Example response:
```json
{
- "name": "master",
+ "name": "main",
"merged": false,
"protected": true,
"default": true,
@@ -106,19 +109,22 @@ Example response:
"can_push": true,
"web_url": "https://gitlab.example.com/my-group/my-project/-/tree/main",
"commit": {
- "author_email": "john@example.com",
- "author_name": "John Smith",
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00",
- "committer_email": "john@example.com",
- "committer_name": "John Smith",
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"short_id": "7b5c3cc",
- "title": "add projects API",
- "message": "add projects API",
+ "created_at": "2012-06-28T03:44:20-07:00",
"parent_ids": [
"4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- ]
+ ],
+ "title": "add projects API",
+ "message": "add projects API",
+ "author_name": "John Smith",
+ "author_email": "john@example.com",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committer_name": "John Smith",
+ "committer_email": "john@example.com",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "trailers": {},
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/commit/7b5c3cc8be40ee161ae89a06bba6229da1032a0c"
}
}
```
@@ -160,19 +166,22 @@ Example response:
```json
{
"commit": {
- "author_email": "john@example.com",
- "author_name": "John Smith",
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00",
- "committer_email": "john@example.com",
- "committer_name": "John Smith",
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
"short_id": "7b5c3cc",
- "title": "add projects API",
- "message": "add projects API",
+ "created_at": "2012-06-28T03:44:20-07:00",
"parent_ids": [
"4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- ]
+ ],
+ "title": "add projects API",
+ "message": "add projects API",
+ "author_name": "John Smith",
+ "author_email": "john@example.com",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committer_name": "John Smith",
+ "committer_email": "john@example.com",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "trailers": {},
+ "web_url": "https://gitlab.example.com/my-group/my-project/-/commit/7b5c3cc8be40ee161ae89a06bba6229da1032a0c"
},
"name": "newbranch",
"merged": false,
diff --git a/doc/api/bulk_imports.md b/doc/api/bulk_imports.md
index ec1a7d44253..db508d1edfa 100644
--- a/doc/api/bulk_imports.md
+++ b/doc/api/bulk_imports.md
@@ -42,19 +42,19 @@ POST /bulk_imports
| `configuration[access_token]` | String | yes | Access token to the source GitLab instance. |
| `entities` | Array | yes | List of entities to import. |
| `entities[source_type]` | String | yes | Source entity type. Valid values are `group_entity` (GitLab 14.2 and later) and `project_entity` (GitLab 15.11 and later). |
-| `entities[source_full_path]` | String | yes | Source full path of the entity to import. |
-| `entities[destination_slug]` | String | yes | Destination slug for the entity. |
+| `entities[source_full_path]` | String | yes | Source full path of the entity to import. For example, `gitlab-org/gitlab`. |
+| `entities[destination_slug]` | String | yes | Destination slug for the entity. GitLab uses the slug as the URL path to the entity. The name of the imported entity is copied from the name of the source entity and not the slug. |
| `entities[destination_name]` | String | no | Deprecated: Use `destination_slug` instead. Destination slug for the entity. |
-| `entities[destination_namespace]` | String | yes | Destination namespace for the entity. |
+| `entities[destination_namespace]` | String | yes | Full path of the destination group [namespace](../user/namespace/index.md) for the entity. Must be an existing group in the destination instance. |
| `entities[migrate_projects]` | Boolean | no | Also import all nested projects of the group (if `source_type` is `group_entity`). Defaults to `true`. |
```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/bulk_imports" \
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token_for_destination_gitlab_instance>" "https://destination-gitlab-instance.example.com/api/v4/bulk_imports" \
--header "Content-Type: application/json" \
--data '{
"configuration": {
- "url": "http://gitlab.example/",
- "access_token": "access_token"
+ "url": "https://source-gitlab-instance.example.com",
+ "access_token": "<your_access_token_for_source_gitlab_instance>"
},
"entities": [
{
@@ -250,7 +250,7 @@ curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
```json
{
- "id": 1,
+ "id": 2,
"status": "finished",
"source_type": "gitlab",
"created_at": "2021-06-18T09:45:55.358Z",
diff --git a/doc/api/code_suggestions.md b/doc/api/code_suggestions.md
index 528f7db067b..d9fc4de3c8e 100644
--- a/doc/api/code_suggestions.md
+++ b/doc/api/code_suggestions.md
@@ -1,6 +1,6 @@
---
-stage: Manage
-group: AI assisted
+stage: Create
+group: Code Creation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -19,7 +19,7 @@ POST /code_suggestions/tokens
```
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/code_suggestions/tokens"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/code_suggestions/tokens"
```
Example response:
@@ -32,7 +32,7 @@ Example response:
}
```
-## Generate code completions (Experiment)
+## Generate code completions **(EXPERIMENT)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/415581) in GitLab 16.2 [with a flag](../administration/feature_flags.md) named `code_suggestions_completion_api`. Disabled by default. This feature is an Experiment.
> - Requirement to generate a JWT before calling this endpoint was [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127863) in GitLab 16.3.
@@ -51,7 +51,7 @@ POST /code_suggestions/completions
Requests to this endpoint are proxied directly to the [model gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist#completions). The documentation for the endpoint is currently the SSoT for named parameters.
```shell
-curl --header "Authorization: Bearer <YOUR_ACCESS_TOKEN>" --data "<JSON_BODY>" https://gitlab.example.com/api/v4/code_suggestions/completions
+curl --request POST --header "Authorization: Bearer <YOUR_ACCESS_TOKEN>" --data "<JSON_BODY>" https://gitlab.example.com/api/v4/code_suggestions/completions
```
Example body:
diff --git a/doc/api/commits.md b/doc/api/commits.md
index cd955717e39..68c453aa317 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -120,7 +120,7 @@ POST /projects/:id/repository/commits
```shell
PAYLOAD=$(cat << 'JSON'
{
- "branch": "master",
+ "branch": "main",
"commit_message": "some commit message",
"actions": [
{
@@ -188,9 +188,9 @@ GitLab supports [form encoding](rest/index.md#encoding-api-parameters-of-array-a
```shell
curl --request POST \
- --form "branch=master" \
+ --form "branch=main" \
--form "commit_message=some commit message" \
- --form "start_branch=master" \
+ --form "start_branch=main" \
--form "actions[][action]=create" \
--form "actions[][file_path]=foo/bar" \
--form "actions[][content]=</path/to/local.file" \
@@ -227,7 +227,7 @@ Parameters:
| `stats` | boolean | no | Include commit stats. Default is true |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/main"
```
Example response:
@@ -250,7 +250,7 @@ Example response:
],
"last_pipeline" : {
"id": 8,
- "ref": "master",
+ "ref": "main",
"sha": "2dc6aa325a317eda67812f05600bdf0fcdc70ab0",
"status": "created"
},
@@ -317,7 +317,7 @@ Parameters:
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
- --form "branch=master" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/cherry_pick"
+ --form "branch=main" "https://gitlab.example.com/api/v4/projects/5/repository/commits/main/cherry_pick"
```
Example response:
@@ -388,7 +388,7 @@ Parameters:
| `dry_run` | boolean | no | Does not commit any changes. Default is false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231032) in GitLab 13.3 |
```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "branch=master" \
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "branch=main" \
"https://gitlab.example.com/api/v4/projects/5/repository/commits/a738f717824ff53aebad8b090c1b79a14f2bd9e8/revert"
```
@@ -454,7 +454,7 @@ Parameters:
| `sha` | string | yes | The commit hash or name of a repository branch or tag |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/diff"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/main/diff"
```
Example response:
@@ -462,7 +462,7 @@ Example response:
```json
[
{
- "diff": "--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files",
+ "diff": "@@ -71,6 +71,8 @@\n sudo -u git -H bundle exec rake migrate_keys RAILS_ENV=production\n sudo -u git -H bundle exec rake migrate_inline_notes RAILS_ENV=production\n \n+sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production\n+\n ```\n \n ### 6. Update config files",
"new_path": "doc/update/5.4-to-6.0.md",
"old_path": "doc/update/5.4-to-6.0.md",
"a_mode": null,
@@ -490,7 +490,7 @@ Parameters:
| `sha` | string | yes | The commit hash or name of a repository branch or tag |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/master/comments"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/commits/main/comments"
```
Example response:
@@ -679,7 +679,7 @@ Example response:
"target_url" : "https://gitlab.example.com/janedoe/gitlab-foss/builds/91",
"finished_at" : null,
"id" : 91,
- "ref" : "master"
+ "ref" : "main"
},
{
"started_at" : null,
@@ -690,7 +690,7 @@ Example response:
"target_url" : "https://gitlab.example.com/janedoe/gitlab-foss/builds/90",
"id" : 90,
"finished_at" : null,
- "ref" : "master",
+ "ref" : "main",
"sha" : "18f3e63d05582537db6d183d9d557be09e1f90c8",
"author" : {
"id" : 28,
@@ -789,7 +789,7 @@ Example response:
"state":"opened",
"created_at":"2018-03-26T17:26:30.916Z",
"updated_at":"2018-03-26T17:26:30.916Z",
- "target_branch":"master",
+ "target_branch":"main",
"source_branch":"test-branch",
"upvotes":0,
"downvotes":0,
@@ -830,7 +830,7 @@ Example response:
## Get GPG signature of a commit
-Get the [GPG signature from a commit](../user/project/repository/gpg_signed_commits/index.md),
+Get the [GPG signature from a commit](../user/project/repository/signed_commits/gpg.md),
if it is signed. For unsigned commits, it results in a 404 response.
```plaintext
diff --git a/doc/api/dependency_list_export.md b/doc/api/dependency_list_export.md
new file mode 100644
index 00000000000..083f7a640fc
--- /dev/null
+++ b/doc/api/dependency_list_export.md
@@ -0,0 +1,158 @@
+---
+stage: Govern
+group: Threat Insights
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Dependency list export API **(ULTIMATE ALL)**
+
+Every call to this endpoint requires authentication.
+
+## Create a pipeline-level dependency list export **(EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333463) in GitLab 16.4 [with a flag](../administration/feature_flags.md) named `merge_sbom_api`. Enabled by default. This feature is an [Experiment](../policy/experiment-beta-support.md#experiment).
+
+FLAG:
+On self-managed GitLab, by default this feature is available.
+To hide the feature, an administrator can [disable the feature flag](../administration/feature_flags.md) named `merge_sbom_api`.
+On GitLab.com, this feature is available.
+
+WARNING:
+This feature is an [Experiment](../policy/experiment-beta-support.md#experiment)
+and subject to change without notice.
+
+Create a new CycloneDX JSON export for all the project dependencies detected in a pipeline.
+
+If an authenticated user doesn't have permission to
+[read_dependency](../user/permissions.md#custom-role-requirements),
+this request returns a `403 Forbidden` status code.
+
+SBOM exports can be only accessed by the export's author.
+
+```plaintext
+POST /pipelines/:id/dependency_list_exports
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ----------------- | ---------- | -----------------------------------------------------------------------------------------------------------------------------|
+| `id` | integer | yes | The ID of the pipeline which the authenticated user has access to. |
+| `export_type` | string | yes | This must be set to `sbom`. |
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <private_token>" "https://gitlab.example.com/api/v4/pipelines/1/dependency_list_exports" --data "export_type=sbom"
+```
+
+The created dependency list export is automatically deleted after 1 hour.
+
+Example response:
+
+```json
+{
+ "id": 2,
+ "has_finished": false,
+ "self": "http://gitlab.example.com/api/v4/dependency_list_exports/2",
+ "download": "http://gitlab.example.com/api/v4/dependency_list_exports/2/download"
+}
+```
+
+## Get single dependency list export
+
+Get a single dependency list export.
+
+```plaintext
+GET /security/dependency_list_exports/:id
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of the dependency list export. |
+
+```shell
+curl --header "PRIVATE-TOKEN: <private_token>" "https://gitlab.example.com/api/v4/security/dependency_list_exports/2"
+```
+
+The status code is `202 Accepted` when the dependency list export is being generated, and `200 OK` when it's ready.
+
+Example response:
+
+```json
+{
+ "id": 4,
+ "has_finished": true,
+ "self": "http://gitlab.example.com/api/v4/dependency_list_exports/4",
+ "download": "http://gitlab.example.com/api/v4/dependency_list_exports/4/download"
+}
+```
+
+## Download dependency list export
+
+Download a single dependency list export.
+
+```plaintext
+GET /security/dependency_list_exports/:id/download
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of the dependency list export. |
+
+```shell
+curl --header "PRIVATE-TOKEN: <private_token>" "https://gitlab.example.com/api/v4/security/dependency_list_exports/2/download"
+```
+
+The response is `404 Not Found` if the dependency list export is not finished yet or was not found.
+
+Example response:
+
+```json
+{
+ "bomFormat": "CycloneDX",
+ "specVersion": "1.4",
+ "serialNumber": "urn:uuid:aec33827-20ae-40d0-ae83-18ee846364d2",
+ "version": 1,
+ "metadata": {
+ "tools": [
+ {
+ "vendor": "Gitlab",
+ "name": "Gemnasium",
+ "version": "2.34.0"
+ }
+ ],
+ "authors": [
+ {
+ "name": "Gitlab",
+ "email": "support@gitlab.com"
+ }
+ ],
+ "properties": [
+ {
+ "name": "gitlab:dependency_scanning:input_file",
+ "value": "package-lock.json"
+ }
+ ]
+ },
+ "components": [
+ {
+ "name": "com.fasterxml.jackson.core/jackson-core",
+ "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.9.2",
+ "version": "2.9.2",
+ "type": "library",
+ "licenses": [
+ {
+ "license": {
+ "id": "MIT",
+ "url": "https://spdx.org/licenses/MIT.html"
+ }
+ },
+ {
+ "license": {
+ "id": "BSD-3-Clause",
+ "url": "https://spdx.org/licenses/BSD-3-Clause.html"
+ }
+ }
+ ]
+ }
+ ]
+}
+
+```
diff --git a/doc/api/deploy_keys.md b/doc/api/deploy_keys.md
index 3d5fa092416..ee568b41832 100644
--- a/doc/api/deploy_keys.md
+++ b/doc/api/deploy_keys.md
@@ -26,7 +26,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
|:------------|:---------|:---------|:----------------------|
-| `public` | boolean | **{dotted-circle}** No | Only return deploy keys that are public. Defaults to `false`. |
+| `public` | boolean | No | Only return deploy keys that are public. Defaults to `false`. |
Example request:
diff --git a/doc/api/deploy_tokens.md b/doc/api/deploy_tokens.md
index bc0cee1d627..c0e6a57a9d7 100644
--- a/doc/api/deploy_tokens.md
+++ b/doc/api/deploy_tokens.md
@@ -20,7 +20,7 @@ Parameters:
| Attribute | Type | Required | Description |
|-----------|----------|------------------------|-------------|
-| `active` | boolean | **{dotted-circle}** No | Limit by active status. |
+| `active` | boolean | No | Limit by active status. |
Example request:
@@ -66,8 +66,8 @@ Parameters:
| Attribute | Type | Required | Description |
|:---------------|:---------------|:-----------------------|:------------|
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `active` | boolean | **{dotted-circle}** No | Limit by active status. |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `active` | boolean | No | Limit by active status. |
Example request:
@@ -108,8 +108,8 @@ Parameters:
| Attribute | Type | Required | Description |
| ---------- | -------------- | ---------------------- | ----------- |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `token_id` | integer | **{check-circle}** Yes | ID of the deploy token |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
+| `token_id` | integer | Yes | ID of the deploy token |
Example request:
@@ -148,11 +148,11 @@ Parameters:
| Attribute | Type | Required | Description |
| ------------ | ---------------- | ---------------------- | ----------- |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `name` | string | **{check-circle}** Yes | New deploy token's name |
-| `scopes` | array of strings | **{check-circle}** Yes | Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, `write_registry`, `read_package_registry`, or `write_package_registry`. |
-| `expires_at` | datetime | **{dotted-circle}** No | Expiration date for the deploy token. Does not expire if no value is provided. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
-| `username` | string | **{dotted-circle}** No | Username for deploy token. Default is `gitlab+deploy-token-{n}` |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
+| `name` | string | Yes | New deploy token's name |
+| `scopes` | array of strings | Yes | Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, `write_registry`, `read_package_registry`, or `write_package_registry`. |
+| `expires_at` | datetime | No | Expiration date for the deploy token. Does not expire if no value is provided. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
+| `username` | string | No | Username for deploy token. Default is `gitlab+deploy-token-{n}` |
Example request:
@@ -193,8 +193,8 @@ Parameters:
| Attribute | Type | Required | Description |
| ---------- | -------------- | ---------------------- | ----------- |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `token_id` | integer | **{check-circle}** Yes | ID of the deploy token |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
+| `token_id` | integer | Yes | ID of the deploy token |
Example request:
@@ -222,8 +222,8 @@ Parameters:
| Attribute | Type | Required | Description |
|:---------------|:---------------|:-----------------------|:------------|
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). |
-| `active` | boolean | **{dotted-circle}** No | Limit by active status. |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). |
+| `active` | boolean | No | Limit by active status. |
Example request:
@@ -264,8 +264,8 @@ Parameters:
| Attribute | Type | Required | Description |
| ----------- | -------------- | ---------------------- | ----------- |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `token_id` | integer | **{check-circle}** Yes | ID of the deploy token |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
+| `token_id` | integer | Yes | ID of the deploy token |
Example request:
@@ -304,11 +304,11 @@ Parameters:
| Attribute | Type | Required | Description |
| ------------ | ---- | --------- | ----------- |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `name` | string | **{check-circle}** Yes | New deploy token's name |
-| `scopes` | array of strings | **{check-circle}** Yes | Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, `write_registry`, `read_package_registry`, or `write_package_registry`. |
-| `expires_at` | datetime | **{dotted-circle}** No | Expiration date for the deploy token. Does not expire if no value is provided. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
-| `username` | string | **{dotted-circle}** No | Username for deploy token. Default is `gitlab+deploy-token-{n}` |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
+| `name` | string | Yes | New deploy token's name |
+| `scopes` | array of strings | Yes | Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, `write_registry`, `read_package_registry`, or `write_package_registry`. |
+| `expires_at` | datetime | No | Expiration date for the deploy token. Does not expire if no value is provided. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
+| `username` | string | No | Username for deploy token. Default is `gitlab+deploy-token-{n}` |
Example request:
@@ -349,8 +349,8 @@ Parameters:
| Attribute | Type | Required | Description |
| ----------- | -------------- | ---------------------- | ----------- |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `token_id` | integer | **{check-circle}** Yes | ID of the deploy token |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
+| `token_id` | integer | Yes | ID of the deploy token |
Example request:
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index 6b475473790..dac2c886166 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -990,7 +990,7 @@ For example, if a commit (`<COMMIT_ID>`) deletes line 463 in the README, you can
on the deletion by referencing line 463 in the *old* file:
```shell
-curl --request POST --header "PRIVATE-TOKEN: [ACCESS_TOKEN]" \
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--form "note=Very clever to remove this unnecessary line!" \
--form "path=README" --form "line=463" --form "line_type=old" \
"https://gitlab.com/api/v4/projects/47/repository/commits/<COMMIT_ID>/comments"
@@ -1000,7 +1000,7 @@ If a commit (`<COMMIT_ID>`) adds line 157 to `hello.rb`, you can comment on the
addition by referencing line 157 in the *new* file:
```shell
-curl --request POST --header "PRIVATE-TOKEN: [ACCESS_TOKEN]" \
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
--form "note=This is brilliant!" --form "path=hello.rb" \
--form "line=157" --form "line_type=new" \
"https://gitlab.com/api/v4/projects/47/repository/commits/<COMMIT_ID>/comments"
diff --git a/doc/api/error_tracking.md b/doc/api/error_tracking.md
index 0858e105a1f..fb22e96c20b 100644
--- a/doc/api/error_tracking.md
+++ b/doc/api/error_tracking.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Observability
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/events.md b/doc/api/events.md
index 9889e8d7701..8564b9b0942 100644
--- a/doc/api/events.md
+++ b/doc/api/events.md
@@ -185,7 +185,7 @@ Example response:
"ref_type": "branch",
"commit_from": "50d4420237a9de7be1304607147aec22e4a14af7",
"commit_to": "c5feabde2d8cd023215af4d2ceeb7a64839fc428",
- "ref": "master",
+ "ref": "main",
"commit_title": "Add simple search to projects in public area"
},
"target_title": null
diff --git a/doc/api/feature_flags.md b/doc/api/feature_flags.md
index d7bf4fe826e..824c892c17b 100644
--- a/doc/api/feature_flags.md
+++ b/doc/api/feature_flags.md
@@ -59,7 +59,8 @@ Example response:
"id": 1,
"environment_scope": "production"
}
- ]
+ ],
+ "user_list": null
}
]
},
@@ -81,7 +82,36 @@ Example response:
"id": 2,
"environment_scope": "staging"
}
- ]
+ ],
+ "user_list": null
+ }
+ ]
+ },
+ {
+ "name":"user_list",
+ "description":"This feature is about user list",
+ "active": true,
+ "version": "new_version_flag",
+ "created_at":"2019-11-04T08:13:10.507Z",
+ "updated_at":"2019-11-04T08:13:10.507Z",
+ "scopes":[],
+ "strategies": [
+ {
+ "id": 2,
+ "name": "gitlabUserList",
+ "parameters": {},
+ "scopes": [
+ {
+ "id": 2,
+ "environment_scope": "staging"
+ }
+ ],
+ "user_list": {
+ "id": 1,
+ "iid": 1,
+ "name": "My user list",
+ "user_xids": "user1,user2,user3"
+ }
}
]
}
@@ -126,7 +156,8 @@ Example response:
"id": 37,
"environment_scope": "production"
}
- ]
+ ],
+ "user_list": null
}
]
}
@@ -147,11 +178,12 @@ POST /projects/:id/feature_flags
| `version` | string | yes | The version of the feature flag. Must be `new_version_flag`. Omit to create a Legacy feature flag. |
| `description` | string | no | The description of the feature flag. |
| `active` | boolean | no | The active state of the flag. Defaults to true. [Supported](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38350) in GitLab 13.3 and later. |
-| `strategies` | JSON | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). |
+| `strategies` | array of strategy JSON objects | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). |
| `strategies:name` | JSON | no | The strategy name. Can be `default`, `gradualRolloutUserId`, `userWithId`, or `gitlabUserList`. In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/36380) and later, can be [`flexibleRollout`](https://docs.getunleash.io/user_guide/activation_strategy/#gradual-rollout). |
| `strategies:parameters` | JSON | no | The strategy parameters. |
| `strategies:scopes` | JSON | no | The scopes for the strategy. |
| `strategies:scopes:environment_scope` | string | no | The environment scope of the scope. |
+| `strategies:user_list_id` | integer/string | no | The ID of the feature flag user list. If strategy is `gitlabUserList`. |
```shell
curl "https://gitlab.example.com/api/v4/projects/1/feature_flags" \
@@ -208,7 +240,7 @@ PUT /projects/:id/feature_flags/:feature_flag_name
| `description` | string | no | The description of the feature flag. |
| `active` | boolean | no | The active state of the flag. [Supported](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38350) in GitLab 13.3 and later. |
| `name` | string | no | The new name of the feature flag. [Supported](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38350) in GitLab 13.3 and later. |
-| `strategies` | JSON | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). |
+| `strategies` | array of strategy JSON objects | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). |
| `strategies:id` | JSON | no | The feature flag strategy ID. |
| `strategies:name` | JSON | no | The strategy name. |
| `strategies:_destroy` | boolean | no | Delete the strategy when true. |
@@ -217,6 +249,7 @@ PUT /projects/:id/feature_flags/:feature_flag_name
| `strategies:scopes:id` | JSON | no | The environment scope ID. |
| `strategies:scopes:environment_scope` | string | no | The environment scope of the scope. |
| `strategies:scopes:_destroy` | boolean | no | Delete the scope when true. |
+| `strategies:user_list_id` | integer/string | no | The ID of the feature flag user list. If strategy is `gitlabUserList`. |
```shell
curl "https://gitlab.example.com/api/v4/projects/1/feature_flags/awesome_feature" \
diff --git a/doc/api/geo_nodes.md b/doc/api/geo_nodes.md
index 4ec57274bd7..e709a810255 100644
--- a/doc/api/geo_nodes.md
+++ b/doc/api/geo_nodes.md
@@ -334,19 +334,11 @@ Example response:
"job_artifacts_failed_count": null,
"job_artifacts_synced_missing_on_primary_count": 0,
"job_artifacts_synced_in_percentage": "0.00%",
- "design_repositories_count": 3,
- "design_repositories_synced_count": null,
- "design_repositories_failed_count": null,
- "design_repositories_synced_in_percentage": "0.00%",
"projects_count": 41,
"repositories_count": 41,
"repositories_failed_count": null,
"repositories_synced_count": null,
"repositories_synced_in_percentage": "0.00%",
- "wikis_count": 41,
- "wikis_failed_count": null,
- "wikis_synced_count": null,
- "wikis_synced_in_percentage": "0.00%",
"replication_slots_count": 1,
"replication_slots_used_count": 1,
"replication_slots_used_in_percentage": "100.00%",
@@ -357,19 +349,11 @@ Example response:
"repositories_checksummed_count": 20,
"repositories_checksum_failed_count": 5,
"repositories_checksummed_in_percentage": "48.78%",
- "wikis_checksummed_count": 10,
- "wikis_checksum_failed_count": 3,
- "wikis_checksummed_in_percentage": "24.39%",
"repositories_verified_count": 20,
"repositories_verification_failed_count": 5,
"repositories_verified_in_percentage": "48.78%",
"repositories_checksum_mismatch_count": 3,
- "wikis_verified_count": 10,
- "wikis_verification_failed_count": 3,
- "wikis_verified_in_percentage": "24.39%",
- "wikis_checksum_mismatch_count": 1,
"repositories_retrying_verification_count": 1,
- "wikis_retrying_verification_count": 3,
"last_event_id": 23,
"last_event_timestamp": 1509681166,
"cursor_last_event_id": null,
@@ -598,10 +582,6 @@ Example response:
"job_artifacts_failed_count": 1,
"job_artifacts_synced_missing_on_primary_count": 0,
"job_artifacts_synced_in_percentage": "50.00%",
- "design_repositories_count": 3,
- "design_repositories_synced_count": null,
- "design_repositories_failed_count": null,
- "design_repositories_synced_in_percentage": "0.00%",
"design_management_repositories_count": 5,
"design_management_repositories_synced_count": 5,
"design_management_repositories_failed_count": 5,
@@ -619,10 +599,6 @@ Example response:
"repositories_failed_count": 1,
"repositories_synced_count": 40,
"repositories_synced_in_percentage": "97.56%",
- "wikis_count": 41,
- "wikis_failed_count": 0,
- "wikis_synced_count": 41,
- "wikis_synced_in_percentage": "100.00%",
"replication_slots_count": null,
"replication_slots_used_count": null,
"replication_slots_used_in_percentage": "0.00%",
@@ -630,19 +606,11 @@ Example response:
"repositories_checksummed_count": 20,
"repositories_checksum_failed_count": 5,
"repositories_checksummed_in_percentage": "48.78%",
- "wikis_checksummed_count": 10,
- "wikis_checksum_failed_count": 3,
- "wikis_checksummed_in_percentage": "24.39%",
"repositories_verified_count": 20,
"repositories_verification_failed_count": 5,
"repositories_verified_in_percentage": "48.78%",
"repositories_checksum_mismatch_count": 3,
- "wikis_verified_count": 10,
- "wikis_verification_failed_count": 3,
- "wikis_verified_in_percentage": "24.39%",
- "wikis_checksum_mismatch_count": 1,
"repositories_retrying_verification_count": 4,
- "wikis_retrying_verification_count": 2,
"repositories_checked_count": 5,
"repositories_checked_failed_count": 1,
"repositories_checked_in_percentage": "12.20%",
@@ -841,19 +809,11 @@ Example response:
"job_artifacts_failed_count": 1,
"job_artifacts_synced_missing_on_primary_count": 0,
"job_artifacts_synced_in_percentage": "50.00%",
- "design_repositories_count": 3,
- "design_repositories_synced_count": null,
- "design_repositories_failed_count": null,
- "design_repositories_synced_in_percentage": "0.00%",
"projects_count": 41,
"repositories_count": 41,
"repositories_failed_count": 1,
"repositories_synced_count": 40,
"repositories_synced_in_percentage": "97.56%",
- "wikis_count": 41,
- "wikis_failed_count": 0,
- "wikis_synced_count": 41,
- "wikis_synced_in_percentage": "100.00%",
"replication_slots_count": null,
"replication_slots_used_count": null,
"replication_slots_used_in_percentage": "0.00%",
diff --git a/doc/api/geo_sites.md b/doc/api/geo_sites.md
index ff06f668514..2c0ceab62e2 100644
--- a/doc/api/geo_sites.md
+++ b/doc/api/geo_sites.md
@@ -296,31 +296,17 @@ Example response:
"repositories_replication_enabled": null,
"repositories_synced_count": null,
"repositories_failed_count": null,
- "wikis_synced_count": null,
- "wikis_failed_count": null,
"repositories_verified_count": null,
"repositories_verification_failed_count": null,
"repositories_verification_total_count": null,
- "wikis_verified_count": null,
- "wikis_verification_failed_count": null,
- "wikis_verification_total_count": null,
"job_artifacts_synced_missing_on_primary_count": null,
"repositories_checksummed_count": 19,
"repositories_checksum_failed_count": 0,
"repositories_checksum_mismatch_count": null,
"repositories_checksum_total_count": 19,
- "wikis_checksummed_count": 0,
- "wikis_checksum_failed_count": 0,
- "wikis_checksum_mismatch_count": null,
- "wikis_checksum_total_count": 19,
"repositories_retrying_verification_count": null,
- "wikis_retrying_verification_count": null,
"projects_count": 19,
"container_repositories_replication_enabled": null,
- "design_repositories_replication_enabled": null,
- "design_repositories_count": null,
- "design_repositories_synced_count": null,
- "design_repositories_failed_count": null,
"lfs_objects_count": 0,
"lfs_objects_checksum_total_count": 0,
"lfs_objects_checksummed_count": 0,
@@ -479,11 +465,7 @@ Example response:
"repositories_checksummed_in_percentage": "100.00%",
"repositories_verified_in_percentage": "0.00%",
"repositories_checked_in_percentage": "0.00%",
- "wikis_synced_in_percentage": "0.00%",
- "wikis_checksummed_in_percentage": "0.00%",
- "wikis_verified_in_percentage": "0.00%",
"replication_slots_used_in_percentage": "100.00%",
- "design_repositories_synced_in_percentage": "0.00%",
"lfs_objects_synced_in_percentage": "0.00%",
"lfs_objects_verified_in_percentage": "0.00%",
"merge_request_diffs_synced_in_percentage": "0.00%",
@@ -515,7 +497,6 @@ Example response:
"project_wiki_repositories_synced_in_percentage": "0.00%",
"project_wiki_repositories_verified_in_percentage": "0.00%",
"repositories_count": 19,
- "wikis_count": 19,
"replication_slots_count": 1,
"replication_slots_used_count": 1,
"healthy": true,
@@ -548,31 +529,17 @@ Example response:
"repositories_replication_enabled": true,
"repositories_synced_count": 18,
"repositories_failed_count": 0,
- "wikis_synced_count": 18,
- "wikis_failed_count": 0,
"repositories_verified_count": 0,
"repositories_verification_failed_count": 0,
"repositories_verification_total_count": 19,
- "wikis_verified_count": 0,
- "wikis_verification_failed_count": 0,
- "wikis_verification_total_count": 19,
"job_artifacts_synced_missing_on_primary_count": null,
"repositories_checksummed_count": null,
"repositories_checksum_failed_count": null,
"repositories_checksum_mismatch_count": 0,
"repositories_checksum_total_count": null,
- "wikis_checksummed_count": null,
- "wikis_checksum_failed_count": null,
- "wikis_checksum_mismatch_count": 0,
- "wikis_checksum_total_count": null,
"repositories_retrying_verification_count": 0,
- "wikis_retrying_verification_count": 0,
"projects_count": 19,
"container_repositories_replication_enabled": null,
- "design_repositories_replication_enabled": true,
- "design_repositories_count": 0,
- "design_repositories_synced_count": 0,
- "design_repositories_failed_count": 0,
"lfs_objects_count": 0,
"lfs_objects_checksum_total_count": null,
"lfs_objects_checksummed_count": null,
@@ -731,11 +698,7 @@ Example response:
"repositories_checksummed_in_percentage": "0.00%",
"repositories_verified_in_percentage": "0.00%",
"repositories_checked_in_percentage": "0.00%",
- "wikis_synced_in_percentage": "94.74%",
- "wikis_checksummed_in_percentage": "0.00%",
- "wikis_verified_in_percentage": "0.00%",
"replication_slots_used_in_percentage": "0.00%",
- "design_repositories_synced_in_percentage": "0.00%",
"lfs_objects_synced_in_percentage": "0.00%",
"lfs_objects_verified_in_percentage": "0.00%",
"merge_request_diffs_synced_in_percentage": "0.00%",
@@ -767,7 +730,6 @@ Example response:
"project_wiki_repositories_synced_in_percentage": "100.00%",
"project_wiki_repositories_verified_in_percentage": "100.00%",
"repositories_count": 19,
- "wikis_count": 19,
"replication_slots_count": null,
"replication_slots_used_count": null,
"healthy": false,
@@ -816,31 +778,17 @@ Example response:
"repositories_replication_enabled": true,
"repositories_synced_count": 18,
"repositories_failed_count": 0,
- "wikis_synced_count": 18,
- "wikis_failed_count": 0,
"repositories_verified_count": 0,
"repositories_verification_failed_count": 0,
"repositories_verification_total_count": 19,
- "wikis_verified_count": 0,
- "wikis_verification_failed_count": 0,
- "wikis_verification_total_count": 19,
"job_artifacts_synced_missing_on_primary_count": null,
"repositories_checksummed_count": null,
"repositories_checksum_failed_count": null,
"repositories_checksum_mismatch_count": 0,
"repositories_checksum_total_count": null,
- "wikis_checksummed_count": null,
- "wikis_checksum_failed_count": null,
- "wikis_checksum_mismatch_count": 0,
- "wikis_checksum_total_count": null,
"repositories_retrying_verification_count": 0,
- "wikis_retrying_verification_count": 0,
"projects_count": 19,
"container_repositories_replication_enabled": null,
- "design_repositories_replication_enabled": true,
- "design_repositories_count": 0,
- "design_repositories_synced_count": 0,
- "design_repositories_failed_count": 0,
"lfs_objects_count": 0,
"lfs_objects_checksum_total_count": null,
"lfs_objects_checksummed_count": null,
@@ -999,11 +947,7 @@ Example response:
"repositories_checksummed_in_percentage": "0.00%",
"repositories_verified_in_percentage": "0.00%",
"repositories_checked_in_percentage": "0.00%",
- "wikis_synced_in_percentage": "94.74%",
- "wikis_checksummed_in_percentage": "0.00%",
- "wikis_verified_in_percentage": "0.00%",
"replication_slots_used_in_percentage": "0.00%",
- "design_repositories_synced_in_percentage": "0.00%",
"lfs_objects_synced_in_percentage": "0.00%",
"lfs_objects_verified_in_percentage": "0.00%",
"merge_request_diffs_synced_in_percentage": "0.00%",
@@ -1035,7 +979,6 @@ Example response:
"project_wiki_repositories_synced_in_percentage": "100.00%",
"project_wiki_repositories_verified_in_percentage": "100.00%",
"repositories_count": 19,
- "wikis_count": 19,
"replication_slots_count": null,
"replication_slots_used_count": null,
"healthy": false,
diff --git a/doc/api/graphql/custom_emoji.md b/doc/api/graphql/custom_emoji.md
index a0a329ca4b5..7efadb7e9dd 100644
--- a/doc/api/graphql/custom_emoji.md
+++ b/doc/api/graphql/custom_emoji.md
@@ -20,9 +20,9 @@ Parameters:
| Attribute | Type | Required | Description |
| :----------- | :------------- | :--------------------- | :------------------------------------------------------------------------ |
-| `group_path` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the top-level group](../rest/index.md#namespaced-path-encoding) |
-| `name` | string | **{check-circle}** Yes | Name of the custom emoji. |
-| `file` | string | **{check-circle}** Yes | URL of the custom emoji image. |
+| `group_path` | integer/string | Yes | ID or [URL-encoded path of the top-level group](../rest/index.md#namespaced-path-encoding) |
+| `name` | string | Yes | Name of the custom emoji. |
+| `file` | string | Yes | URL of the custom emoji image. |
## Create a custom emoji
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index c9fc446303f..65736f10ba9 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -74,13 +74,13 @@ four standard [pagination arguments](#connection-pagination-arguments):
### `Query.aiMessages`
-Find AI messages.
+Find GitLab Duo Chat messages.
WARNING:
**Introduced** in 16.1.
This feature is an Experiment. It can be changed or removed at any time.
-Returns [`AiCachedMessageTypeConnection!`](#aicachedmessagetypeconnection).
+Returns [`AiChatMessageConnection!`](#aichatmessageconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
@@ -91,7 +91,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="queryaimessagesrequestids"></a>`requestIds` | [`[ID!]`](#id) | Array of request IDs to fetch. |
-| <a id="queryaimessagesroles"></a>`roles` | [`[AiCachedMessageRole!]`](#aicachedmessagerole) | Array of roles to fetch. |
+| <a id="queryaimessagesroles"></a>`roles` | [`[AiChatMessageRole!]`](#aichatmessagerole) | Array of roles to fetch. |
### `Query.auditEventDefinitions`
@@ -204,6 +204,24 @@ Returns [`CiStage`](#cistage).
| ---- | ---- | ----------- |
| <a id="querycipipelinestageid"></a>`id` | [`CiStageID!`](#cistageid) | Global ID of the CI stage. |
+### `Query.ciQueueingHistory`
+
+Time it took for ci job to be picked up by runner in percentiles.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`QueueingDelayHistory`](#queueingdelayhistory).
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="queryciqueueinghistoryfromtime"></a>`fromTime` | [`Time`](#time) | Start of the requested time frame. Defaults to 3 hours ago. |
+| <a id="queryciqueueinghistoryrunnertype"></a>`runnerType` | [`CiRunnerType`](#cirunnertype) | Filter jobs by the type of runner that executed them. |
+| <a id="queryciqueueinghistorytotime"></a>`toTime` | [`Time`](#time) | End of the requested time frame. Defaults to current time. |
+
### `Query.ciVariables`
List of the instance's CI/CD variables.
@@ -361,6 +379,16 @@ This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
`before: String`, `after: String`, `first: Int`, `last: Int`.
+### `Query.instanceGoogleCloudLoggingConfigurations`
+
+Instance level google cloud logging configurations.
+
+Returns [`InstanceGoogleCloudLoggingConfigurationTypeConnection`](#instancegooglecloudloggingconfigurationtypeconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
### `Query.instanceSecurityDashboard`
Fields related to Instance Security Dashboard.
@@ -462,6 +490,8 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="queryjobsfailurereason"></a>`failureReason` **{warning-solid}** | [`CiJobFailureReason`](#cijobfailurereason) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Filter jobs by failure reason. Currently only `RUNNER_SYSTEM_FAILURE` together with `runnerTypes: INSTANCE_TYPE` is supported. |
+| <a id="queryjobsrunnertypes"></a>`runnerTypes` **{warning-solid}** | [`[CiRunnerType!]`](#cirunnertype) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Filter jobs by runner type if feature flag `:admin_jobs_filter_runner_type` is enabled. |
| <a id="queryjobsstatuses"></a>`statuses` | [`[CiJobStatus!]`](#cijobstatus) | Filter jobs by status. |
### `Query.licenseHistoryEntries`
@@ -474,6 +504,16 @@ This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
`before: String`, `after: String`, `first: Int`, `last: Int`.
+### `Query.memberRolePermissions`
+
+List of all customizable permissions.
+
+Returns [`CustomizablePermissionConnection`](#customizablepermissionconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
### `Query.mergeRequest`
Find a merge request.
@@ -532,6 +572,22 @@ Returns [`Note`](#note).
| ---- | ---- | ----------- |
| <a id="querynoteid"></a>`id` | [`NoteID!`](#noteid) | Global ID of the note. |
+### `Query.organization`
+
+Find an organization.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`Organization`](#organization).
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="queryorganizationid"></a>`id` | [`OrganizationsOrganizationID!`](#organizationsorganizationid) | ID of the organization. |
+
### `Query.package`
Find a package. This field can only be resolved for one query in any single request. Returns `null` if a package has no `default` status.
@@ -632,7 +688,7 @@ Returns [`RunnerSetup`](#runnersetup).
### `Query.runners`
-Find runners visible to the current user.
+Get all runners in the GitLab instance (project and shared). Access is restricted to users with administrator access.
Returns [`CiRunnerConnection`](#cirunnerconnection).
@@ -821,6 +877,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="queryvulnerabilitiesclusterid"></a>`clusterId` | [`[ClustersClusterID!]`](#clustersclusterid) | Filter vulnerabilities by `cluster_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. |
| <a id="queryvulnerabilitiesdismissalreason"></a>`dismissalReason` | [`[VulnerabilityDismissalReason!]`](#vulnerabilitydismissalreason) | Filter by dismissal reason. Only dismissed Vulnerabilities will be included with the filter. |
| <a id="queryvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
+| <a id="queryvulnerabilitieshasmergerequest"></a>`hasMergeRequest` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked merge requests. |
| <a id="queryvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
| <a id="queryvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| <a id="queryvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
@@ -933,6 +990,30 @@ mutation($id: NoteableID!, $body: String!) {
}
```
+### `Mutation.abuseReportLabelCreate`
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Input type: `AbuseReportLabelCreateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationabusereportlabelcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationabusereportlabelcreatecolor"></a>`color` | [`String`](#string) | The color of the label given in 6-digit hex notation with leading '#' sign (for example, `#FFAABB`) or one of the CSS color names. |
+| <a id="mutationabusereportlabelcreatetitle"></a>`title` | [`String!`](#string) | Title of the label. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationabusereportlabelcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationabusereportlabelcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationabusereportlabelcreatelabel"></a>`label` | [`Label`](#label) | Label after mutation. |
+
### `Mutation.achievementsAward`
WARNING:
@@ -1128,13 +1209,13 @@ Input type: `AiActionInput`
| <a id="mutationaiactionanalyzecijobfailure"></a>`analyzeCiJobFailure` | [`AnalyzeCiJobFailureInput`](#analyzecijobfailureinput) | Input for analyze_ci_job_failure AI action. |
| <a id="mutationaiactionchat"></a>`chat` | [`AiChatInput`](#aichatinput) | Input for chat AI action. |
| <a id="mutationaiactionclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationaiactionclientsubscriptionid"></a>`clientSubscriptionId` | [`String`](#string) | Client generated ID that can be subscribed to, to receive a response for the mutation. |
| <a id="mutationaiactionexplaincode"></a>`explainCode` | [`AiExplainCodeInput`](#aiexplaincodeinput) | Input for explain_code AI action. |
| <a id="mutationaiactionexplainvulnerability"></a>`explainVulnerability` | [`AiExplainVulnerabilityInput`](#aiexplainvulnerabilityinput) | Input for explain_vulnerability AI action. |
| <a id="mutationaiactionfillinmergerequesttemplate"></a>`fillInMergeRequestTemplate` | [`AiFillInMergeRequestTemplateInput`](#aifillinmergerequesttemplateinput) | Input for fill_in_merge_request_template AI action. |
| <a id="mutationaiactiongeneratecommitmessage"></a>`generateCommitMessage` | [`AiGenerateCommitMessageInput`](#aigeneratecommitmessageinput) | Input for generate_commit_message AI action. |
| <a id="mutationaiactiongeneratedescription"></a>`generateDescription` | [`AiGenerateDescriptionInput`](#aigeneratedescriptioninput) | Input for generate_description AI action. |
| <a id="mutationaiactiongeneratetestfile"></a>`generateTestFile` | [`GenerateTestFileInput`](#generatetestfileinput) | Input for generate_test_file AI action. |
-| <a id="mutationaiactionmarkupformat"></a>`markupFormat` | [`MarkupFormat`](#markupformat) | Indicates the response format. |
| <a id="mutationaiactionsummarizecomments"></a>`summarizeComments` | [`AiSummarizeCommentsInput`](#aisummarizecommentsinput) | Input for summarize_comments AI action. |
| <a id="mutationaiactionsummarizereview"></a>`summarizeReview` | [`AiSummarizeReviewInput`](#aisummarizereviewinput) | Input for summarize_review AI action. |
| <a id="mutationaiactiontanukibot"></a>`tanukiBot` | [`AiTanukiBotInput`](#aitanukibotinput) | Input for tanuki_bot AI action. |
@@ -1701,7 +1782,7 @@ Input type: `CiAiGenerateConfigInput`
| ---- | ---- | ----------- |
| <a id="mutationciaigenerateconfigclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationciaigenerateconfigerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
-| <a id="mutationciaigenerateconfigusermessage"></a>`userMessage` | [`AiMessageType`](#aimessagetype) | User chat message. |
+| <a id="mutationciaigenerateconfigusermessage"></a>`userMessage` | [`AiMessage`](#aimessage) | User chat message. |
### `Mutation.ciJobTokenScopeAddProject`
@@ -2365,6 +2446,7 @@ Input type: `CreateTestCaseInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationcreatetestcaseclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationcreatetestcaseconfidential"></a>`confidential` | [`Boolean`](#boolean) | Sets the test case confidentiality. |
| <a id="mutationcreatetestcasedescription"></a>`description` | [`String`](#string) | Test case description. |
| <a id="mutationcreatetestcaselabelids"></a>`labelIds` | [`[ID!]`](#id) | IDs of labels to be added to the test case. |
| <a id="mutationcreatetestcaseprojectpath"></a>`projectPath` | [`ID!`](#id) | Project full path to create the test case in. |
@@ -2817,7 +2899,7 @@ Input type: `DeleteAnnotationInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationdeleteannotationclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
-| <a id="mutationdeleteannotationid"></a>`id` | [`MetricsDashboardAnnotationID!`](#metricsdashboardannotationid) | Global ID of the annotation to delete. |
+| <a id="mutationdeleteannotationid"></a>`id` | [`String!`](#string) | Global ID of the annotation to delete. |
#### Fields
@@ -3690,6 +3772,32 @@ Input type: `ExternalAuditEventDestinationUpdateInput`
| <a id="mutationexternalauditeventdestinationupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationexternalauditeventdestinationupdateexternalauditeventdestination"></a>`externalAuditEventDestination` | [`ExternalAuditEventDestination`](#externalauditeventdestination) | Updated destination. |
+### `Mutation.geoRegistriesBulkUpdate`
+
+Mutates multiple Geo registries for a given registry class. Does not mutate the registries if `geo_registries_update_mutation` feature flag is disabled.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Input type: `GeoRegistriesBulkUpdateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationgeoregistriesbulkupdateaction"></a>`action` | [`GeoRegistriesBulkAction!`](#georegistriesbulkaction) | Action to be executed on Geo registries. |
+| <a id="mutationgeoregistriesbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationgeoregistriesbulkupdateregistryclass"></a>`registryClass` | [`GeoRegistryClass!`](#georegistryclass) | Class of the Geo registries to be updated. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationgeoregistriesbulkupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationgeoregistriesbulkupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationgeoregistriesbulkupdateregistryclass"></a>`registryClass` | [`GeoRegistryClass`](#georegistryclass) | Updated Geo registry class. |
+
### `Mutation.geoRegistriesUpdate`
Mutates a Geo registry. Does not mutate the registry entry if `geo_registries_update_mutation` feature flag is disabled.
@@ -3706,7 +3814,7 @@ Input type: `GeoRegistriesUpdateInput`
| ---- | ---- | ----------- |
| <a id="mutationgeoregistriesupdateaction"></a>`action` | [`GeoRegistryAction!`](#georegistryaction) | Action to be executed on a Geo registry. |
| <a id="mutationgeoregistriesupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
-| <a id="mutationgeoregistriesupdateregistryclass"></a>`registryClass` | [`GeoRegistryClass!`](#georegistryclass) | Class of the Geo registry to be updated. |
+| <a id="mutationgeoregistriesupdateregistryclass"></a>`registryClass` | [`GeoRegistryClass`](#georegistryclass) | Class of the Geo registry to be updated. |
| <a id="mutationgeoregistriesupdateregistryid"></a>`registryId` | [`GeoBaseRegistryID!`](#geobaseregistryid) | ID of the Geo registry entry to be updated. |
#### Fields
@@ -3750,6 +3858,7 @@ Input type: `GoogleCloudLoggingConfigurationCreateInput`
| <a id="mutationgooglecloudloggingconfigurationcreategoogleprojectidname"></a>`googleProjectIdName` | [`String!`](#string) | Unique identifier of the Google Cloud project to which the logging configuration belongs. |
| <a id="mutationgooglecloudloggingconfigurationcreategrouppath"></a>`groupPath` | [`ID!`](#id) | Group path. |
| <a id="mutationgooglecloudloggingconfigurationcreatelogidname"></a>`logIdName` | [`String`](#string) | Unique identifier used to distinguish and manage different logs within the same Google Cloud project.(defaults to `audit_events`). |
+| <a id="mutationgooglecloudloggingconfigurationcreatename"></a>`name` | [`String`](#string) | Destination name. |
| <a id="mutationgooglecloudloggingconfigurationcreateprivatekey"></a>`privateKey` | [`String!`](#string) | Private Key associated with the service account. This key is used to authenticate the service account and authorize it to interact with the Google Cloud Logging service. |
#### Fields
@@ -3791,6 +3900,7 @@ Input type: `GoogleCloudLoggingConfigurationUpdateInput`
| <a id="mutationgooglecloudloggingconfigurationupdategoogleprojectidname"></a>`googleProjectIdName` | [`String`](#string) | Unique identifier of the Google Cloud project to which the logging configuration belongs. |
| <a id="mutationgooglecloudloggingconfigurationupdateid"></a>`id` | [`AuditEventsGoogleCloudLoggingConfigurationID!`](#auditeventsgooglecloudloggingconfigurationid) | ID of the google Cloud configuration to update. |
| <a id="mutationgooglecloudloggingconfigurationupdatelogidname"></a>`logIdName` | [`String`](#string) | Unique identifier used to distinguish and manage different logs within the same Google Cloud project. |
+| <a id="mutationgooglecloudloggingconfigurationupdatename"></a>`name` | [`String`](#string) | Destination name. |
| <a id="mutationgooglecloudloggingconfigurationupdateprivatekey"></a>`privateKey` | [`String`](#string) | Private Key associated with the service account. This key is used to authenticate the service account and authorize it to interact with the Google Cloud Logging service. |
#### Fields
@@ -3986,6 +4096,47 @@ Input type: `InstanceExternalAuditEventDestinationUpdateInput`
| <a id="mutationinstanceexternalauditeventdestinationupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationinstanceexternalauditeventdestinationupdateinstanceexternalauditeventdestination"></a>`instanceExternalAuditEventDestination` | [`InstanceExternalAuditEventDestination`](#instanceexternalauditeventdestination) | Updated destination. |
+### `Mutation.instanceGoogleCloudLoggingConfigurationCreate`
+
+Input type: `InstanceGoogleCloudLoggingConfigurationCreateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreateclientemail"></a>`clientEmail` | [`String!`](#string) | Email address associated with the service account that will be used to authenticate and interact with the Google Cloud Logging service. This is part of the IAM credentials. |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreategoogleprojectidname"></a>`googleProjectIdName` | [`String!`](#string) | Unique identifier of the Google Cloud project to which the logging configuration belongs. |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreatelogidname"></a>`logIdName` | [`String`](#string) | Unique identifier used to distinguish and manage different logs within the same Google Cloud project.(defaults to `audit_events`). |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreatename"></a>`name` | [`String`](#string) | Destination name. |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreateprivatekey"></a>`privateKey` | [`String!`](#string) | Private Key associated with the service account. This key is used to authenticate the service account and authorize it to interact with the Google Cloud Logging service. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationinstancegooglecloudloggingconfigurationcreateinstancegooglecloudloggingconfiguration"></a>`instanceGoogleCloudLoggingConfiguration` | [`InstanceGoogleCloudLoggingConfigurationType`](#instancegooglecloudloggingconfigurationtype) | configuration created. |
+
+### `Mutation.instanceGoogleCloudLoggingConfigurationDestroy`
+
+Input type: `InstanceGoogleCloudLoggingConfigurationDestroyInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationinstancegooglecloudloggingconfigurationdestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationinstancegooglecloudloggingconfigurationdestroyid"></a>`id` | [`AuditEventsInstanceGoogleCloudLoggingConfigurationID!`](#auditeventsinstancegooglecloudloggingconfigurationid) | ID of the Google Cloud logging configuration to destroy. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationinstancegooglecloudloggingconfigurationdestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationinstancegooglecloudloggingconfigurationdestroyerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.issuableResourceLinkCreate`
Input type: `IssuableResourceLinkCreateInput`
@@ -4393,7 +4544,7 @@ Input type: `IssuesBulkUpdateInput`
| <a id="mutationissuesbulkupdateids"></a>`ids` | [`[IssueID!]!`](#issueid) | Global ID array of the issues that will be updated. IDs that the user can't update will be ignored. A max of 100 can be provided. |
| <a id="mutationissuesbulkupdateiterationid"></a>`iterationId` | [`IterationID`](#iterationid) | Global ID of the iteration that will be assigned to the issues. |
| <a id="mutationissuesbulkupdatemilestoneid"></a>`milestoneId` | [`MilestoneID`](#milestoneid) | Global ID of the milestone that will be assigned to the issues. |
-| <a id="mutationissuesbulkupdateparentid"></a>`parentId` | [`IssueParentID!`](#issueparentid) | Global ID of the parent to which the bulk update will be scoped. The parent can be a project **(FREE)** or a group **(PREMIUM)**. Example `IssueParentID` are `"gid://gitlab/Project/1"` and `"gid://gitlab/Group/1"`. |
+| <a id="mutationissuesbulkupdateparentid"></a>`parentId` | [`IssueParentID!`](#issueparentid) | Global ID of the parent to which the bulk update will be scoped. The parent can be a project **(FREE ALL)** or a group **(PREMIUM ALL)**. Example `IssueParentID` are `"gid://gitlab/Project/1"` and `"gid://gitlab/Group/1"`. |
| <a id="mutationissuesbulkupdateremovelabelids"></a>`removeLabelIds` | [`[LabelID!]`](#labelid) | Global ID array of the labels that will be removed from the issues. |
| <a id="mutationissuesbulkupdatestateevent"></a>`stateEvent` | [`IssueStateEvent`](#issuestateevent) | Close or reopen an issue. |
| <a id="mutationissuesbulkupdatesubscriptionevent"></a>`subscriptionEvent` | [`IssuableSubscriptionEvent`](#issuablesubscriptionevent) | Subscribe to or unsubscribe from issue notifications. |
@@ -4946,7 +5097,7 @@ Input type: `MergeRequestUpdateInput`
| <a id="mutationmergerequestupdateprojectpath"></a>`projectPath` | [`ID!`](#id) | Project the merge request to mutate is in. |
| <a id="mutationmergerequestupdatestate"></a>`state` | [`MergeRequestNewState`](#mergerequestnewstate) | Action to perform to change the state. |
| <a id="mutationmergerequestupdatetargetbranch"></a>`targetBranch` | [`String`](#string) | Target branch of the merge request. |
-| <a id="mutationmergerequestupdatetimeestimate"></a>`timeEstimate` | [`String`](#string) | Estimated time to complete the merge request, or `0` to remove the current estimate. |
+| <a id="mutationmergerequestupdatetimeestimate"></a>`timeEstimate` | [`String`](#string) | Estimated time to complete the merge request. Use `null` or `0` to remove the current estimate. |
| <a id="mutationmergerequestupdatetitle"></a>`title` | [`String`](#string) | Title of the merge request. |
#### Fields
@@ -5443,6 +5594,7 @@ Input type: `ProjectCiCdSettingsUpdateInput`
| <a id="mutationprojectcicdsettingsupdatekeeplatestartifact"></a>`keepLatestArtifact` | [`Boolean`](#boolean) | Indicates if the latest artifact should be kept for the project. |
| <a id="mutationprojectcicdsettingsupdatemergepipelinesenabled"></a>`mergePipelinesEnabled` | [`Boolean`](#boolean) | Indicates if merge pipelines are enabled for the project. |
| <a id="mutationprojectcicdsettingsupdatemergetrainsenabled"></a>`mergeTrainsEnabled` | [`Boolean`](#boolean) | Indicates if merge trains are enabled for the project. |
+| <a id="mutationprojectcicdsettingsupdatemergetrainsskiptrainallowed"></a>`mergeTrainsSkipTrainAllowed` | [`Boolean`](#boolean) | Indicates whether an option is allowed to merge without refreshing the merge train. Ignored unless the `merge_trains_skip_train` feature flag is also enabled. |
#### Fields
@@ -5517,6 +5669,28 @@ Input type: `ProjectSetComplianceFrameworkInput`
| <a id="mutationprojectsetcomplianceframeworkerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationprojectsetcomplianceframeworkproject"></a>`project` | [`Project`](#project) | Project after mutation. |
+### `Mutation.projectSetContinuousVulnerabilityScanning`
+
+Enable/disable Continuous Vulnerability Scanning for the given project.
+
+Input type: `ProjectSetContinuousVulnerabilityScanningInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationprojectsetcontinuousvulnerabilityscanningclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationprojectsetcontinuousvulnerabilityscanningenable"></a>`enable` | [`Boolean!`](#boolean) | Desired status for Continuous Vulnerability Scanning feature. |
+| <a id="mutationprojectsetcontinuousvulnerabilityscanningprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationprojectsetcontinuousvulnerabilityscanningclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationprojectsetcontinuousvulnerabilityscanningcontinuousvulnerabilityscanningenabled"></a>`continuousVulnerabilityScanningEnabled` | [`Boolean!`](#boolean) | Whether feature is enabled. |
+| <a id="mutationprojectsetcontinuousvulnerabilityscanningerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+
### `Mutation.projectSetLocked`
Input type: `ProjectSetLockedInput`
@@ -6763,7 +6937,7 @@ Input type: `UpdateIssueInput`
| <a id="mutationupdateissueprojectpath"></a>`projectPath` | [`ID!`](#id) | Project the issue to mutate is in. |
| <a id="mutationupdateissueremovelabelids"></a>`removeLabelIds` | [`[ID!]`](#id) | IDs of labels to be removed from the issue. |
| <a id="mutationupdateissuestateevent"></a>`stateEvent` | [`IssueStateEvent`](#issuestateevent) | Close or reopen an issue. |
-| <a id="mutationupdateissuetimeestimate"></a>`timeEstimate` | [`String`](#string) | Estimated time to complete the issue, or `0` to remove the current estimate. |
+| <a id="mutationupdateissuetimeestimate"></a>`timeEstimate` | [`String`](#string) | Estimated time to complete the issue. Use `null` or `0` to remove the current estimate. |
| <a id="mutationupdateissuetitle"></a>`title` | [`String`](#string) | Title of the issue. |
| <a id="mutationupdateissuetype"></a>`type` | [`IssueType`](#issuetype) | Type of the issue. |
| <a id="mutationupdateissueweight"></a>`weight` | [`Int`](#int) | Weight of the issue. |
@@ -6988,7 +7162,7 @@ Input type: `UserAddOnAssignmentCreateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="mutationuseraddonassignmentcreateaddonpurchaseid"></a>`addOnPurchaseId` | [`GitlabSubscriptionsAddOnPurchaseID!`](#gitlabsubscriptionsaddonpurchaseid) | Global ID of AddOnPurchase to be assinged to. |
+| <a id="mutationuseraddonassignmentcreateaddonpurchaseid"></a>`addOnPurchaseId` | [`GitlabSubscriptionsAddOnPurchaseID!`](#gitlabsubscriptionsaddonpurchaseid) | Global ID of AddOnPurchase to be assigned to. |
| <a id="mutationuseraddonassignmentcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationuseraddonassignmentcreateuserid"></a>`userId` | [`UserID!`](#userid) | Global ID of user to be assigned. |
@@ -6999,6 +7173,7 @@ Input type: `UserAddOnAssignmentCreateInput`
| <a id="mutationuseraddonassignmentcreateaddonpurchase"></a>`addOnPurchase` | [`AddOnPurchase`](#addonpurchase) | AddOnPurchase state after mutation. |
| <a id="mutationuseraddonassignmentcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationuseraddonassignmentcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationuseraddonassignmentcreateuser"></a>`user` | [`AddOnUser`](#addonuser) | User who the add-on purchase was assigned to. |
### `Mutation.userAddOnAssignmentRemove`
@@ -7023,6 +7198,7 @@ Input type: `UserAddOnAssignmentRemoveInput`
| <a id="mutationuseraddonassignmentremoveaddonpurchase"></a>`addOnPurchase` | [`AddOnPurchase`](#addonpurchase) | AddOnPurchase state after mutation. |
| <a id="mutationuseraddonassignmentremoveclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationuseraddonassignmentremoveerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationuseraddonassignmentremoveuser"></a>`user` | [`AddOnUser`](#addonuser) | User that the add-on was removed from. |
### `Mutation.userCalloutCreate`
@@ -7094,7 +7270,7 @@ Input type: `VulnerabilitiesDismissInput`
| <a id="mutationvulnerabilitiesdismissclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationvulnerabilitiesdismisscomment"></a>`comment` | [`String`](#string) | Comment why vulnerability was dismissed (maximum 50,000 characters). |
| <a id="mutationvulnerabilitiesdismissdismissalreason"></a>`dismissalReason` | [`VulnerabilityDismissalReason`](#vulnerabilitydismissalreason) | Reason why vulnerability should be dismissed. |
-| <a id="mutationvulnerabilitiesdismissvulnerabilityids"></a>`vulnerabilityIds` | [`[VulnerabilityID!]!`](#vulnerabilityid) | IDs of the vulnerabilities to be dismissed. |
+| <a id="mutationvulnerabilitiesdismissvulnerabilityids"></a>`vulnerabilityIds` | [`[VulnerabilityID!]!`](#vulnerabilityid) | IDs of the vulnerabilities to be dismissed (maximum 100 entries). |
#### Fields
@@ -7472,6 +7648,33 @@ Input type: `WorkItemExportInput`
| <a id="mutationworkitemexporterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationworkitemexportmessage"></a>`message` | [`String`](#string) | Export request result message. |
+### `Mutation.workItemRemoveLinkedItems`
+
+Remove items linked to the work item.
+
+WARNING:
+**Introduced** in 16.3.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Input type: `WorkItemRemoveLinkedItemsInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationworkitemremovelinkeditemsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationworkitemremovelinkeditemsid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
+| <a id="mutationworkitemremovelinkeditemsworkitemsids"></a>`workItemsIds` | [`[WorkItemID!]!`](#workitemid) | Global IDs of the items to unlink. Maximum number of IDs you can provide: 3. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationworkitemremovelinkeditemsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationworkitemremovelinkeditemserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationworkitemremovelinkeditemsmessage"></a>`message` | [`String`](#string) | Linked items update result message. |
+| <a id="mutationworkitemremovelinkeditemsworkitem"></a>`workItem` | [`WorkItem`](#workitem) | Updated work item. |
+
### `Mutation.workItemSubscribe`
WARNING:
@@ -7704,51 +7907,51 @@ The edge type for [`AgentConfiguration`](#agentconfiguration).
| <a id="agentconfigurationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="agentconfigurationedgenode"></a>`node` | [`AgentConfiguration`](#agentconfiguration) | The item at the end of the edge. |
-#### `AiCachedMessageTypeConnection`
+#### `AiChatMessageConnection`
-The connection type for [`AiCachedMessageType`](#aicachedmessagetype).
+The connection type for [`AiChatMessage`](#aichatmessage).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="aicachedmessagetypeconnectionedges"></a>`edges` | [`[AiCachedMessageTypeEdge]`](#aicachedmessagetypeedge) | A list of edges. |
-| <a id="aicachedmessagetypeconnectionnodes"></a>`nodes` | [`[AiCachedMessageType]`](#aicachedmessagetype) | A list of nodes. |
-| <a id="aicachedmessagetypeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+| <a id="aichatmessageconnectionedges"></a>`edges` | [`[AiChatMessageEdge]`](#aichatmessageedge) | A list of edges. |
+| <a id="aichatmessageconnectionnodes"></a>`nodes` | [`[AiChatMessage]`](#aichatmessage) | A list of nodes. |
+| <a id="aichatmessageconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
-#### `AiCachedMessageTypeEdge`
+#### `AiChatMessageEdge`
-The edge type for [`AiCachedMessageType`](#aicachedmessagetype).
+The edge type for [`AiChatMessage`](#aichatmessage).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="aicachedmessagetypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
-| <a id="aicachedmessagetypeedgenode"></a>`node` | [`AiCachedMessageType`](#aicachedmessagetype) | The item at the end of the edge. |
+| <a id="aichatmessageedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="aichatmessageedgenode"></a>`node` | [`AiChatMessage`](#aichatmessage) | The item at the end of the edge. |
-#### `AiMessageTypeConnection`
+#### `AiMessageConnection`
-The connection type for [`AiMessageType`](#aimessagetype).
+The connection type for [`AiMessage`](#aimessage).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="aimessagetypeconnectionedges"></a>`edges` | [`[AiMessageTypeEdge]`](#aimessagetypeedge) | A list of edges. |
-| <a id="aimessagetypeconnectionnodes"></a>`nodes` | [`[AiMessageType]`](#aimessagetype) | A list of nodes. |
-| <a id="aimessagetypeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+| <a id="aimessageconnectionedges"></a>`edges` | [`[AiMessageEdge]`](#aimessageedge) | A list of edges. |
+| <a id="aimessageconnectionnodes"></a>`nodes` | [`[AiMessage]`](#aimessage) | A list of nodes. |
+| <a id="aimessageconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
-#### `AiMessageTypeEdge`
+#### `AiMessageEdge`
-The edge type for [`AiMessageType`](#aimessagetype).
+The edge type for [`AiMessage`](#aimessage).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="aimessagetypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
-| <a id="aimessagetypeedgenode"></a>`node` | [`AiMessageType`](#aimessagetype) | The item at the end of the edge. |
+| <a id="aimessageedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="aimessageedgenode"></a>`node` | [`AiMessage`](#aimessage) | The item at the end of the edge. |
#### `AlertManagementAlertConnection`
@@ -8997,6 +9200,98 @@ The edge type for [`CustomerRelationsOrganization`](#customerrelationsorganizati
| <a id="customerrelationsorganizationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="customerrelationsorganizationedgenode"></a>`node` | [`CustomerRelationsOrganization`](#customerrelationsorganization) | The item at the end of the edge. |
+#### `CustomizableDashboardConnection`
+
+The connection type for [`CustomizableDashboard`](#customizabledashboard).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardconnectionedges"></a>`edges` | [`[CustomizableDashboardEdge]`](#customizabledashboardedge) | A list of edges. |
+| <a id="customizabledashboardconnectionnodes"></a>`nodes` | [`[CustomizableDashboard]`](#customizabledashboard) | A list of nodes. |
+| <a id="customizabledashboardconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `CustomizableDashboardEdge`
+
+The edge type for [`CustomizableDashboard`](#customizabledashboard).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="customizabledashboardedgenode"></a>`node` | [`CustomizableDashboard`](#customizabledashboard) | The item at the end of the edge. |
+
+#### `CustomizableDashboardPanelConnection`
+
+The connection type for [`CustomizableDashboardPanel`](#customizabledashboardpanel).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardpanelconnectionedges"></a>`edges` | [`[CustomizableDashboardPanelEdge]`](#customizabledashboardpaneledge) | A list of edges. |
+| <a id="customizabledashboardpanelconnectionnodes"></a>`nodes` | [`[CustomizableDashboardPanel]`](#customizabledashboardpanel) | A list of nodes. |
+| <a id="customizabledashboardpanelconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `CustomizableDashboardPanelEdge`
+
+The edge type for [`CustomizableDashboardPanel`](#customizabledashboardpanel).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardpaneledgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="customizabledashboardpaneledgenode"></a>`node` | [`CustomizableDashboardPanel`](#customizabledashboardpanel) | The item at the end of the edge. |
+
+#### `CustomizableDashboardVisualizationConnection`
+
+The connection type for [`CustomizableDashboardVisualization`](#customizabledashboardvisualization).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardvisualizationconnectionedges"></a>`edges` | [`[CustomizableDashboardVisualizationEdge]`](#customizabledashboardvisualizationedge) | A list of edges. |
+| <a id="customizabledashboardvisualizationconnectionnodes"></a>`nodes` | [`[CustomizableDashboardVisualization]`](#customizabledashboardvisualization) | A list of nodes. |
+| <a id="customizabledashboardvisualizationconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `CustomizableDashboardVisualizationEdge`
+
+The edge type for [`CustomizableDashboardVisualization`](#customizabledashboardvisualization).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardvisualizationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="customizabledashboardvisualizationedgenode"></a>`node` | [`CustomizableDashboardVisualization`](#customizabledashboardvisualization) | The item at the end of the edge. |
+
+#### `CustomizablePermissionConnection`
+
+The connection type for [`CustomizablePermission`](#customizablepermission).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizablepermissionconnectionedges"></a>`edges` | [`[CustomizablePermissionEdge]`](#customizablepermissionedge) | A list of edges. |
+| <a id="customizablepermissionconnectionnodes"></a>`nodes` | [`[CustomizablePermission]`](#customizablepermission) | A list of nodes. |
+| <a id="customizablepermissionconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `CustomizablePermissionEdge`
+
+The edge type for [`CustomizablePermission`](#customizablepermission).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizablepermissionedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="customizablepermissionedgenode"></a>`node` | [`CustomizablePermission`](#customizablepermission) | The item at the end of the edge. |
+
#### `DastProfileConnection`
The connection type for [`DastProfile`](#dastprofile).
@@ -9898,6 +10193,29 @@ The edge type for [`InstanceExternalAuditEventDestination`](#instanceexternalaud
| <a id="instanceexternalauditeventdestinationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="instanceexternalauditeventdestinationedgenode"></a>`node` | [`InstanceExternalAuditEventDestination`](#instanceexternalauditeventdestination) | The item at the end of the edge. |
+#### `InstanceGoogleCloudLoggingConfigurationTypeConnection`
+
+The connection type for [`InstanceGoogleCloudLoggingConfigurationType`](#instancegooglecloudloggingconfigurationtype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="instancegooglecloudloggingconfigurationtypeconnectionedges"></a>`edges` | [`[InstanceGoogleCloudLoggingConfigurationTypeEdge]`](#instancegooglecloudloggingconfigurationtypeedge) | A list of edges. |
+| <a id="instancegooglecloudloggingconfigurationtypeconnectionnodes"></a>`nodes` | [`[InstanceGoogleCloudLoggingConfigurationType]`](#instancegooglecloudloggingconfigurationtype) | A list of nodes. |
+| <a id="instancegooglecloudloggingconfigurationtypeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `InstanceGoogleCloudLoggingConfigurationTypeEdge`
+
+The edge type for [`InstanceGoogleCloudLoggingConfigurationType`](#instancegooglecloudloggingconfigurationtype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="instancegooglecloudloggingconfigurationtypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="instancegooglecloudloggingconfigurationtypeedgenode"></a>`node` | [`InstanceGoogleCloudLoggingConfigurationType`](#instancegooglecloudloggingconfigurationtype) | The item at the end of the edge. |
+
#### `IssuableResourceLinkConnection`
The connection type for [`IssuableResourceLink`](#issuableresourcelink).
@@ -10570,6 +10888,29 @@ The edge type for [`OncallParticipantType`](#oncallparticipanttype).
| <a id="oncallparticipanttypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="oncallparticipanttypeedgenode"></a>`node` | [`OncallParticipantType`](#oncallparticipanttype) | The item at the end of the edge. |
+#### `OrganizationUserConnection`
+
+The connection type for [`OrganizationUser`](#organizationuser).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="organizationuserconnectionedges"></a>`edges` | [`[OrganizationUserEdge]`](#organizationuseredge) | A list of edges. |
+| <a id="organizationuserconnectionnodes"></a>`nodes` | [`[OrganizationUser]`](#organizationuser) | A list of nodes. |
+| <a id="organizationuserconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `OrganizationUserEdge`
+
+The edge type for [`OrganizationUser`](#organizationuser).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="organizationuseredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="organizationuseredgenode"></a>`node` | [`OrganizationUser`](#organizationuser) | The item at the end of the edge. |
+
#### `PackageBaseConnection`
The connection type for [`PackageBase`](#packagebase).
@@ -10897,75 +11238,6 @@ The edge type for [`PipelineTrigger`](#pipelinetrigger).
| <a id="pipelinetriggeredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="pipelinetriggeredgenode"></a>`node` | [`PipelineTrigger`](#pipelinetrigger) | The item at the end of the edge. |
-#### `ProductAnalyticsDashboardConnection`
-
-The connection type for [`ProductAnalyticsDashboard`](#productanalyticsdashboard).
-
-##### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboardconnectionedges"></a>`edges` | [`[ProductAnalyticsDashboardEdge]`](#productanalyticsdashboardedge) | A list of edges. |
-| <a id="productanalyticsdashboardconnectionnodes"></a>`nodes` | [`[ProductAnalyticsDashboard]`](#productanalyticsdashboard) | A list of nodes. |
-| <a id="productanalyticsdashboardconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
-
-#### `ProductAnalyticsDashboardEdge`
-
-The edge type for [`ProductAnalyticsDashboard`](#productanalyticsdashboard).
-
-##### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboardedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
-| <a id="productanalyticsdashboardedgenode"></a>`node` | [`ProductAnalyticsDashboard`](#productanalyticsdashboard) | The item at the end of the edge. |
-
-#### `ProductAnalyticsDashboardPanelConnection`
-
-The connection type for [`ProductAnalyticsDashboardPanel`](#productanalyticsdashboardpanel).
-
-##### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboardpanelconnectionedges"></a>`edges` | [`[ProductAnalyticsDashboardPanelEdge]`](#productanalyticsdashboardpaneledge) | A list of edges. |
-| <a id="productanalyticsdashboardpanelconnectionnodes"></a>`nodes` | [`[ProductAnalyticsDashboardPanel]`](#productanalyticsdashboardpanel) | A list of nodes. |
-| <a id="productanalyticsdashboardpanelconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
-
-#### `ProductAnalyticsDashboardPanelEdge`
-
-The edge type for [`ProductAnalyticsDashboardPanel`](#productanalyticsdashboardpanel).
-
-##### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboardpaneledgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
-| <a id="productanalyticsdashboardpaneledgenode"></a>`node` | [`ProductAnalyticsDashboardPanel`](#productanalyticsdashboardpanel) | The item at the end of the edge. |
-
-#### `ProductAnalyticsDashboardVisualizationConnection`
-
-The connection type for [`ProductAnalyticsDashboardVisualization`](#productanalyticsdashboardvisualization).
-
-##### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboardvisualizationconnectionedges"></a>`edges` | [`[ProductAnalyticsDashboardVisualizationEdge]`](#productanalyticsdashboardvisualizationedge) | A list of edges. |
-| <a id="productanalyticsdashboardvisualizationconnectionnodes"></a>`nodes` | [`[ProductAnalyticsDashboardVisualization]`](#productanalyticsdashboardvisualization) | A list of nodes. |
-| <a id="productanalyticsdashboardvisualizationconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
-
-#### `ProductAnalyticsDashboardVisualizationEdge`
-
-The edge type for [`ProductAnalyticsDashboardVisualization`](#productanalyticsdashboardvisualization).
-
-##### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboardvisualizationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
-| <a id="productanalyticsdashboardvisualizationedgenode"></a>`node` | [`ProductAnalyticsDashboardVisualization`](#productanalyticsdashboardvisualization) | The item at the end of the edge. |
-
#### `ProjectConnection`
The connection type for [`Project`](#project).
@@ -12080,6 +12352,29 @@ The edge type for [`UserAchievement`](#userachievement).
| <a id="userachievementedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="userachievementedgenode"></a>`node` | [`UserAchievement`](#userachievement) | The item at the end of the edge. |
+#### `UserAddOnAssignmentConnection`
+
+The connection type for [`UserAddOnAssignment`](#useraddonassignment).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="useraddonassignmentconnectionedges"></a>`edges` | [`[UserAddOnAssignmentEdge]`](#useraddonassignmentedge) | A list of edges. |
+| <a id="useraddonassignmentconnectionnodes"></a>`nodes` | [`[UserAddOnAssignment]`](#useraddonassignment) | A list of nodes. |
+| <a id="useraddonassignmentconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `UserAddOnAssignmentEdge`
+
+The edge type for [`UserAddOnAssignment`](#useraddonassignment).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="useraddonassignmentedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="useraddonassignmentedgenode"></a>`node` | [`UserAddOnAssignment`](#useraddonassignment) | The item at the end of the edge. |
+
#### `UserCalloutConnection`
The connection type for [`UserCallout`](#usercallout).
@@ -12461,6 +12756,305 @@ Represents AddOn purchase for Namespace.
| <a id="addonpurchasename"></a>`name` | [`String!`](#string) | Name of AddOn. |
| <a id="addonpurchasepurchasedquantity"></a>`purchasedQuantity` | [`Int!`](#int) | Number of seats purchased. |
+### `AddOnUser`
+
+A user with add-on data.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonuseravatarurl"></a>`avatarUrl` | [`String`](#string) | URL of the user's avatar. |
+| <a id="addonuserbio"></a>`bio` | [`String`](#string) | Bio of the user. |
+| <a id="addonuserbot"></a>`bot` | [`Boolean!`](#boolean) | Indicates if the user is a bot. |
+| <a id="addonusercallouts"></a>`callouts` | [`UserCalloutConnection`](#usercalloutconnection) | User callouts that belong to the user. (see [Connections](#connections)) |
+| <a id="addonusercommitemail"></a>`commitEmail` | [`String`](#string) | User's default commit email. |
+| <a id="addonusercreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
+| <a id="addonuserdiscord"></a>`discord` | [`String`](#string) | Discord ID of the user. |
+| <a id="addonuseremail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
+| <a id="addonuseremails"></a>`emails` | [`EmailConnection`](#emailconnection) | User's email addresses. (see [Connections](#connections)) |
+| <a id="addonusergitpodenabled"></a>`gitpodEnabled` | [`Boolean`](#boolean) | Whether Gitpod is enabled at the user level. |
+| <a id="addonusergroupcount"></a>`groupCount` | [`Int`](#int) | Group count for the user. |
+| <a id="addonusergroupmemberships"></a>`groupMemberships` | [`GroupMemberConnection`](#groupmemberconnection) | Group memberships of the user. (see [Connections](#connections)) |
+| <a id="addonuserid"></a>`id` | [`ID!`](#id) | ID of the user. |
+| <a id="addonuseride"></a>`ide` | [`Ide`](#ide) | IDE settings. |
+| <a id="addonuserjobtitle"></a>`jobTitle` | [`String`](#string) | Job title of the user. |
+| <a id="addonuserlinkedin"></a>`linkedin` | [`String`](#string) | LinkedIn profile name of the user. |
+| <a id="addonuserlocation"></a>`location` | [`String`](#string) | Location of the user. |
+| <a id="addonusername"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. |
+| <a id="addonusernamespace"></a>`namespace` | [`Namespace`](#namespace) | Personal namespace of the user. |
+| <a id="addonusernamespacecommitemails"></a>`namespaceCommitEmails` | [`NamespaceCommitEmailConnection`](#namespacecommitemailconnection) | User's custom namespace commit emails. (see [Connections](#connections)) |
+| <a id="addonuserorganization"></a>`organization` | [`String`](#string) | Who the user represents or works for. |
+| <a id="addonuserpreferencesgitpodpath"></a>`preferencesGitpodPath` | [`String`](#string) | Web path to the Gitpod section within user preferences. |
+| <a id="addonuserprofileenablegitpodpath"></a>`profileEnableGitpodPath` | [`String`](#string) | Web path to enable Gitpod for the user. |
+| <a id="addonuserprojectmemberships"></a>`projectMemberships` | [`ProjectMemberConnection`](#projectmemberconnection) | Project memberships of the user. (see [Connections](#connections)) |
+| <a id="addonuserpronouns"></a>`pronouns` | [`String`](#string) | Pronouns of the user. |
+| <a id="addonuserpublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
+| <a id="addonusersavedreplies"></a>`savedReplies` | [`SavedReplyConnection`](#savedreplyconnection) | Saved replies authored by the user. Will not return saved replies if `saved_replies` feature flag is disabled. (see [Connections](#connections)) |
+| <a id="addonuserstate"></a>`state` | [`UserState!`](#userstate) | State of the user. |
+| <a id="addonuserstatus"></a>`status` | [`UserStatus`](#userstatus) | User status. |
+| <a id="addonusertwitter"></a>`twitter` | [`String`](#string) | Twitter username of the user. |
+| <a id="addonuseruserachievements"></a>`userAchievements` **{warning-solid}** | [`UserAchievementConnection`](#userachievementconnection) | **Introduced** in 15.10. This feature is an Experiment. It can be changed or removed at any time. Achievements for the user. Only returns for namespaces where the `achievements` feature flag is enabled. |
+| <a id="addonuseruserpermissions"></a>`userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. |
+| <a id="addonuserusername"></a>`username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. |
+| <a id="addonuserwebpath"></a>`webPath` | [`String!`](#string) | Web path of the user. |
+| <a id="addonuserweburl"></a>`webUrl` | [`String!`](#string) | Web URL of the user. |
+
+#### Fields with arguments
+
+##### `AddOnUser.addOnAssignments`
+
+Add-on purchase assignments for the user.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`UserAddOnAssignmentConnection`](#useraddonassignmentconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonuseraddonassignmentsaddonpurchaseids"></a>`addOnPurchaseIds` | [`[GitlabSubscriptionsAddOnPurchaseID!]!`](#gitlabsubscriptionsaddonpurchaseid) | Global IDs of the add on purchases to find assignments for. |
+
+##### `AddOnUser.assignedMergeRequests`
+
+Merge requests assigned to the user.
+
+Returns [`MergeRequestConnection`](#mergerequestconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonuserassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
+| <a id="addonuserassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
+| <a id="addonuserassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
+| <a id="addonuserassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
+| <a id="addonuserassignedmergerequestsdraft"></a>`draft` | [`Boolean`](#boolean) | Limit result to draft merge requests. |
+| <a id="addonuserassignedmergerequestsgroupid"></a>`groupId` | [`GroupID`](#groupid) | The global ID of the group the authored merge requests should be in. Merge requests in subgroups are included. |
+| <a id="addonuserassignedmergerequestsiids"></a>`iids` | [`[String!]`](#string) | Array of IIDs of merge requests, for example `[1, 2]`. |
+| <a id="addonuserassignedmergerequestslabels"></a>`labels` | [`[String!]`](#string) | Array of label names. All resolved merge requests will have all of these labels. |
+| <a id="addonuserassignedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after this date. |
+| <a id="addonuserassignedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before this date. |
+| <a id="addonuserassignedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. |
+| <a id="addonuserassignedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
+| <a id="addonuserassignedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
+| <a id="addonuserassignedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
+| <a id="addonuserassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
+| <a id="addonuserassignedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
+| <a id="addonuserassignedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
+| <a id="addonuserassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
+| <a id="addonuserassignedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
+| <a id="addonuserassignedmergerequestsupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Merge requests updated after this timestamp. |
+| <a id="addonuserassignedmergerequestsupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Merge requests updated before this timestamp. |
+
+##### `AddOnUser.authoredMergeRequests`
+
+Merge requests authored by the user.
+
+Returns [`MergeRequestConnection`](#mergerequestconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonuserauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
+| <a id="addonuserauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
+| <a id="addonuserauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
+| <a id="addonuserauthoredmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
+| <a id="addonuserauthoredmergerequestsdraft"></a>`draft` | [`Boolean`](#boolean) | Limit result to draft merge requests. |
+| <a id="addonuserauthoredmergerequestsgroupid"></a>`groupId` | [`GroupID`](#groupid) | The global ID of the group the authored merge requests should be in. Merge requests in subgroups are included. |
+| <a id="addonuserauthoredmergerequestsiids"></a>`iids` | [`[String!]`](#string) | Array of IIDs of merge requests, for example `[1, 2]`. |
+| <a id="addonuserauthoredmergerequestslabels"></a>`labels` | [`[String!]`](#string) | Array of label names. All resolved merge requests will have all of these labels. |
+| <a id="addonuserauthoredmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after this date. |
+| <a id="addonuserauthoredmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before this date. |
+| <a id="addonuserauthoredmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. |
+| <a id="addonuserauthoredmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
+| <a id="addonuserauthoredmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
+| <a id="addonuserauthoredmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
+| <a id="addonuserauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
+| <a id="addonuserauthoredmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
+| <a id="addonuserauthoredmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
+| <a id="addonuserauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
+| <a id="addonuserauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
+| <a id="addonuserauthoredmergerequestsupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Merge requests updated after this timestamp. |
+| <a id="addonuserauthoredmergerequestsupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Merge requests updated before this timestamp. |
+
+##### `AddOnUser.groups`
+
+Groups where the user has access.
+
+Returns [`GroupConnection`](#groupconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonusergroupspermissionscope"></a>`permissionScope` | [`GroupPermission`](#grouppermission) | Filter by permissions the user has on groups. |
+| <a id="addonusergroupssearch"></a>`search` | [`String`](#string) | Search by group name or path. |
+
+##### `AddOnUser.reviewRequestedMergeRequests`
+
+Merge requests assigned to the user for review.
+
+Returns [`MergeRequestConnection`](#mergerequestconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonuserreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
+| <a id="addonuserreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
+| <a id="addonuserreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
+| <a id="addonuserreviewrequestedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
+| <a id="addonuserreviewrequestedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
+| <a id="addonuserreviewrequestedmergerequestsdraft"></a>`draft` | [`Boolean`](#boolean) | Limit result to draft merge requests. |
+| <a id="addonuserreviewrequestedmergerequestsgroupid"></a>`groupId` | [`GroupID`](#groupid) | The global ID of the group the authored merge requests should be in. Merge requests in subgroups are included. |
+| <a id="addonuserreviewrequestedmergerequestsiids"></a>`iids` | [`[String!]`](#string) | Array of IIDs of merge requests, for example `[1, 2]`. |
+| <a id="addonuserreviewrequestedmergerequestslabels"></a>`labels` | [`[String!]`](#string) | Array of label names. All resolved merge requests will have all of these labels. |
+| <a id="addonuserreviewrequestedmergerequestsmergedafter"></a>`mergedAfter` | [`Time`](#time) | Merge requests merged after this date. |
+| <a id="addonuserreviewrequestedmergerequestsmergedbefore"></a>`mergedBefore` | [`Time`](#time) | Merge requests merged before this date. |
+| <a id="addonuserreviewrequestedmergerequestsmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Title of the milestone. |
+| <a id="addonuserreviewrequestedmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
+| <a id="addonuserreviewrequestedmergerequestsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The global ID of the project the authored merge requests should be in. Incompatible with projectPath. |
+| <a id="addonuserreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
+| <a id="addonuserreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
+| <a id="addonuserreviewrequestedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
+| <a id="addonuserreviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
+| <a id="addonuserreviewrequestedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
+| <a id="addonuserreviewrequestedmergerequestsupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Merge requests updated after this timestamp. |
+| <a id="addonuserreviewrequestedmergerequestsupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Merge requests updated before this timestamp. |
+
+##### `AddOnUser.savedReply`
+
+Saved reply authored by the user. Will not return saved reply if `saved_replies` feature flag is disabled.
+
+Returns [`SavedReply`](#savedreply).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonusersavedreplyid"></a>`id` | [`UsersSavedReplyID!`](#userssavedreplyid) | ID of a saved reply. |
+
+##### `AddOnUser.snippets`
+
+Snippets authored by the user.
+
+Returns [`SnippetConnection`](#snippetconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonusersnippetsids"></a>`ids` | [`[SnippetID!]`](#snippetid) | Array of global snippet IDs. For example, `gid://gitlab/ProjectSnippet/1`. |
+| <a id="addonusersnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. |
+| <a id="addonusersnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. |
+
+##### `AddOnUser.starredProjects`
+
+Projects starred by the user.
+
+Returns [`ProjectConnection`](#projectconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonuserstarredprojectssearch"></a>`search` | [`String`](#string) | Search query. |
+
+##### `AddOnUser.timelogs`
+
+Time logged by the user.
+
+Returns [`TimelogConnection`](#timelogconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonusertimelogsenddate"></a>`endDate` | [`Time`](#time) | List timelogs within a date range where the logged date is equal to or before endDate. |
+| <a id="addonusertimelogsendtime"></a>`endTime` | [`Time`](#time) | List timelogs within a time range where the logged time is equal to or before endTime. |
+| <a id="addonusertimelogsgroupid"></a>`groupId` | [`GroupID`](#groupid) | List timelogs for a group. |
+| <a id="addonusertimelogsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | List timelogs for a project. |
+| <a id="addonusertimelogssort"></a>`sort` | [`TimelogSort`](#timelogsort) | List timelogs in a particular order. |
+| <a id="addonusertimelogsstartdate"></a>`startDate` | [`Time`](#time) | List timelogs within a date range where the logged date is equal to or after startDate. |
+| <a id="addonusertimelogsstarttime"></a>`startTime` | [`Time`](#time) | List timelogs within a time range where the logged time is equal to or after startTime. |
+| <a id="addonusertimelogsusername"></a>`username` | [`String`](#string) | List timelogs for a user. |
+
+##### `AddOnUser.todos`
+
+To-do items of the user.
+
+Returns [`TodoConnection`](#todoconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonusertodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | Action to be filtered. |
+| <a id="addonusertodosauthorid"></a>`authorId` | [`[ID!]`](#id) | ID of an author. |
+| <a id="addonusertodosgroupid"></a>`groupId` | [`[ID!]`](#id) | ID of a group. |
+| <a id="addonusertodosprojectid"></a>`projectId` | [`[ID!]`](#id) | ID of a project. |
+| <a id="addonusertodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | State of the todo. |
+| <a id="addonusertodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | Type of the todo. |
+
+##### `AddOnUser.workspaces`
+
+Workspaces owned by the current user.
+
+Returns [`WorkspaceConnection`](#workspaceconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="addonuserworkspacesids"></a>`ids` | [`[RemoteDevelopmentWorkspaceID!]`](#remotedevelopmentworkspaceid) | Array of global workspace IDs. For example, `["gid://gitlab/RemoteDevelopment::Workspace/1"]`. |
+| <a id="addonuserworkspacesincludeactualstates"></a>`includeActualStates` | [`[String!]`](#string) | Includes all workspaces that match any of the actual states. |
+| <a id="addonuserworkspacesprojectids"></a>`projectIds` | [`[ProjectID!]`](#projectid) | Filter workspaces by project id. |
+
### `AgentConfiguration`
Configuration details for an Agent.
@@ -12484,30 +13078,44 @@ Information about a connected Agent.
| <a id="agentmetadatapodnamespace"></a>`podNamespace` | [`String`](#string) | Namespace of the pod running the Agent. |
| <a id="agentmetadataversion"></a>`version` | [`String`](#string) | Agent version tag. |
-### `AiCachedMessageType`
+### `AiChatMessage`
+
+GitLab Duo Chat message.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="aicachedmessagetypecontent"></a>`content` | [`String`](#string) | Content of the message. Can be null for failed responses. |
-| <a id="aicachedmessagetypeerrors"></a>`errors` | [`[String!]!`](#string) | Errors that occurred while asynchronously fetching an AI (assistant) response. |
-| <a id="aicachedmessagetypeid"></a>`id` | [`ID`](#id) | UUID of the message. |
-| <a id="aicachedmessagetyperequestid"></a>`requestId` | [`ID`](#id) | UUID of the original request message. |
-| <a id="aicachedmessagetyperole"></a>`role` | [`AiCachedMessageRole!`](#aicachedmessagerole) | Message role. |
-| <a id="aicachedmessagetypetimestamp"></a>`timestamp` | [`Time!`](#time) | Message timestamp. |
+| <a id="aichatmessagecontent"></a>`content` | [`String`](#string) | Content of the message. Can be null for failed responses. |
+| <a id="aichatmessagecontenthtml"></a>`contentHtml` | [`String`](#string) | Content of the message in HTML format. Can be null for failed responses. |
+| <a id="aichatmessageerrors"></a>`errors` | [`[String!]!`](#string) | Errors that occurred while asynchronously fetching an AI (assistant) response. |
+| <a id="aichatmessageextras"></a>`extras` | [`AiMessageExtras`](#aimessageextras) | Extra message metadata. |
+| <a id="aichatmessageid"></a>`id` | [`ID`](#id) | UUID of the message. |
+| <a id="aichatmessagerequestid"></a>`requestId` | [`ID`](#id) | UUID of the original request message. Shared between chat prompt and response. |
+| <a id="aichatmessagerole"></a>`role` | [`AiChatMessageRole!`](#aichatmessagerole) | Message role. |
+| <a id="aichatmessagetimestamp"></a>`timestamp` | [`Time!`](#time) | Message timestamp. |
-### `AiMessageType`
+### `AiMessage`
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="aimessagetypecontent"></a>`content` | [`String`](#string) | Content of the message or null if loading. |
-| <a id="aimessagetypeerrors"></a>`errors` | [`[String!]!`](#string) | Errors that occurred while asynchronously fetching an AI(assistant) response. |
-| <a id="aimessagetypeid"></a>`id` | [`ID`](#id) | Global ID of the message. |
-| <a id="aimessagetypeisfetching"></a>`isFetching` | [`Boolean`](#boolean) | Whether the content is still being fetched, for a message with the assistant role. |
-| <a id="aimessagetyperole"></a>`role` | [`String!`](#string) | Role of the message (system, user, assistant). |
+| <a id="aimessagecontent"></a>`content` | [`String`](#string) | Content of the message or null if loading. |
+| <a id="aimessageerrors"></a>`errors` | [`[String!]!`](#string) | Errors that occurred while asynchronously fetching an AI(assistant) response. |
+| <a id="aimessageid"></a>`id` | [`ID`](#id) | Global ID of the message. |
+| <a id="aimessageisfetching"></a>`isFetching` | [`Boolean`](#boolean) | Whether the content is still being fetched, for a message with the assistant role. |
+| <a id="aimessagerole"></a>`role` | [`String!`](#string) | Role of the message (system, user, assistant). |
+
+### `AiMessageExtras`
+
+Extra metadata for AI message.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="aimessageextrassources"></a>`sources` | [`[JSON!]`](#json) | Sources used to form the message. |
### `AiResponse`
@@ -12515,11 +13123,18 @@ Information about a connected Agent.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="airesponsechunkid"></a>`chunkId` | [`Int`](#int) | Incremental ID for a chunk from a streamed response. Null when it is not a streamed response. |
+| <a id="airesponsecontent"></a>`content` | [`String`](#string) | Raw response content. |
+| <a id="airesponsecontenthtml"></a>`contentHtml` | [`String`](#string) | Response content as HTML. |
| <a id="airesponseerrors"></a>`errors` | [`[String!]`](#string) | Errors return by AI API as response. |
+| <a id="airesponseextras"></a>`extras` | [`AiMessageExtras`](#aimessageextras) | Extra message metadata. |
+| <a id="airesponseid"></a>`id` | [`ID`](#id) | UUID of the message. |
| <a id="airesponserequestid"></a>`requestId` | [`String`](#string) | ID of the original request. |
-| <a id="airesponseresponsebody"></a>`responseBody` | [`String`](#string) | Response body from AI API. |
-| <a id="airesponserole"></a>`role` | [`AiCachedMessageRole!`](#aicachedmessagerole) | Message role. |
+| <a id="airesponseresponsebody"></a>`responseBody` **{warning-solid}** | [`String`](#string) | **Deprecated** in 16.4. Moved to content attribute. |
+| <a id="airesponseresponsebodyhtml"></a>`responseBodyHtml` **{warning-solid}** | [`String`](#string) | **Deprecated** in 16.4. Moved to contentHtml attribute. |
+| <a id="airesponserole"></a>`role` | [`AiChatMessageRole!`](#aichatmessagerole) | Message role. |
| <a id="airesponsetimestamp"></a>`timestamp` | [`Time!`](#time) | Message timestamp. |
+| <a id="airesponsetype"></a>`type` | [`AiMessageType`](#aimessagetype) | Message type. |
### `AlertManagementAlert`
@@ -12754,6 +13369,7 @@ Represents a HTTP header key/value that belongs to an audit streaming destinatio
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="auditeventstreamingheaderactive"></a>`active` | [`Boolean!`](#boolean) | Header is active or not. |
| <a id="auditeventstreamingheaderid"></a>`id` | [`ID!`](#id) | ID of the header. |
| <a id="auditeventstreamingheaderkey"></a>`key` | [`String!`](#string) | Key of the header. |
| <a id="auditeventstreamingheadervalue"></a>`value` | [`String!`](#string) | Value of the header. |
@@ -12766,13 +13382,14 @@ Represents a HTTP header key/value that belongs to an instance level audit strea
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="auditeventsstreaminginstanceheaderactive"></a>`active` | [`Boolean!`](#boolean) | Header is active or not. |
| <a id="auditeventsstreaminginstanceheaderid"></a>`id` | [`ID!`](#id) | ID of the header. |
| <a id="auditeventsstreaminginstanceheaderkey"></a>`key` | [`String!`](#string) | Key of the header. |
| <a id="auditeventsstreaminginstanceheadervalue"></a>`value` | [`String!`](#string) | Value of the header. |
### `AutocompletedUser`
-Core represention of a GitLab user.
+Core representation of a GitLab user.
#### Fields
@@ -13086,6 +13703,15 @@ An emoji awarded by a user.
| <a id="baseserviceservicetype"></a>`serviceType` | [`ServiceType`](#servicetype) | Type of the service. |
| <a id="baseservicetype"></a>`type` | [`String`](#string) | Class name of the service. |
+### `Blame`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="blamefirstline"></a>`firstLine` | [`String`](#string) | First line of Git Blame for given range. |
+| <a id="blamegroups"></a>`groups` | [`[Groups!]`](#groups) | Git Blame grouped by contiguous lines for commit. |
+
### `Blob`
#### Fields
@@ -13710,7 +14336,8 @@ CI/CD variables for a GitLab instance.
| <a id="cijobpipeline"></a>`pipeline` | [`Pipeline`](#pipeline) | Pipeline the job belongs to. |
| <a id="cijobplaypath"></a>`playPath` | [`String`](#string) | Play path of the job. |
| <a id="cijobplayable"></a>`playable` | [`Boolean!`](#boolean) | Indicates the job can be played. |
-| <a id="cijobpreviousstagejobsorneeds"></a>`previousStageJobsOrNeeds` | [`JobNeedUnionConnection`](#jobneedunionconnection) | Jobs that must complete before the job runs. Returns `BuildNeed`, which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise. (see [Connections](#connections)) |
+| <a id="cijobpreviousstagejobs"></a>`previousStageJobs` | [`CiJobConnection`](#cijobconnection) | Jobs from the previous stage. (see [Connections](#connections)) |
+| <a id="cijobpreviousstagejobsorneeds"></a>`previousStageJobsOrNeeds` **{warning-solid}** | [`JobNeedUnionConnection`](#jobneedunionconnection) | **Deprecated** in 16.4. Replaced by previousStageJobs and needs fields. |
| <a id="cijobproject"></a>`project` | [`Project`](#project) | Project that the job belongs to. |
| <a id="cijobqueuedat"></a>`queuedAt` | [`Time`](#time) | When the job was enqueued and marked as pending. |
| <a id="cijobqueuedduration"></a>`queuedDuration` | [`Duration`](#duration) | How long the job was enqueued before starting. |
@@ -13759,11 +14386,23 @@ CI/CD variables for a GitLab instance.
### `CiJobTrace`
-#### Fields
+#### Fields with arguments
+
+##### `CiJobTrace.htmlSummary`
+
+HTML summary that contains the tail lines of the trace. Returns at most 16KB of raw bytes from the trace. The returned string might start with an unexpected invalid UTF-8 code point due to truncation.
+
+WARNING:
+**Introduced** in 15.11.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`String!`](#string).
+
+###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="cijobtracehtmlsummary"></a>`htmlSummary` **{warning-solid}** | [`String!`](#string) | **Introduced** in 15.11. This feature is an Experiment. It can be changed or removed at any time. HTML summary containing the last 10 lines of the trace. |
+| <a id="cijobtracehtmlsummarylastlines"></a>`lastLines` | [`Int`](#int) | Number of tail lines to return, up to a maximum of 100 lines. |
### `CiJobsDurationStatistics`
@@ -14141,6 +14780,58 @@ Code Quality report for a pipeline.
| <a id="codequalityreportsummaryminor"></a>`minor` | [`Int`](#int) | Total number of minor status. |
| <a id="codequalityreportsummaryunknown"></a>`unknown` | [`Int`](#int) | Total number of unknown status. |
+### `CodequalityReportsComparer`
+
+Represents reports comparison for code quality.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="codequalityreportscomparerreport"></a>`report` | [`CodequalityReportsComparerReport`](#codequalityreportscomparerreport) | Compared codequality report. |
+
+### `CodequalityReportsComparerReport`
+
+Represents compared code quality report.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="codequalityreportscomparerreportexistingerrors"></a>`existingErrors` | [`[CodequalityReportsComparerReportDegradation!]`](#codequalityreportscomparerreportdegradation) | All code quality degradations. |
+| <a id="codequalityreportscomparerreportnewerrors"></a>`newErrors` | [`[CodequalityReportsComparerReportDegradation!]!`](#codequalityreportscomparerreportdegradation) | New code quality degradations. |
+| <a id="codequalityreportscomparerreportresolvederrors"></a>`resolvedErrors` | [`[CodequalityReportsComparerReportDegradation!]`](#codequalityreportscomparerreportdegradation) | Resolved code quality degradations. |
+| <a id="codequalityreportscomparerreportstatus"></a>`status` | [`CodequalityReportsComparerReportStatus!`](#codequalityreportscomparerreportstatus) | Status of report. |
+| <a id="codequalityreportscomparerreportsummary"></a>`summary` | [`CodequalityReportsComparerReportSummary!`](#codequalityreportscomparerreportsummary) | Codequality report summary. |
+
+### `CodequalityReportsComparerReportDegradation`
+
+Represents a degradation on the compared codequality report.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="codequalityreportscomparerreportdegradationdescription"></a>`description` | [`String!`](#string) | Description of the code quality degradation. |
+| <a id="codequalityreportscomparerreportdegradationenginename"></a>`engineName` | [`String!`](#string) | Code quality plugin that reported the degradation. |
+| <a id="codequalityreportscomparerreportdegradationfilepath"></a>`filePath` | [`String!`](#string) | Relative path to the file containing the code quality degradation. |
+| <a id="codequalityreportscomparerreportdegradationfingerprint"></a>`fingerprint` | [`String!`](#string) | Unique fingerprint to identify the code quality degradation. For example, an MD5 hash. |
+| <a id="codequalityreportscomparerreportdegradationline"></a>`line` | [`Int!`](#int) | Line on which the code quality degradation occurred. |
+| <a id="codequalityreportscomparerreportdegradationseverity"></a>`severity` | [`CodeQualityDegradationSeverity!`](#codequalitydegradationseverity) | Severity of the code quality degradation (BLOCKER, CRITICAL, MAJOR, MINOR, INFO, UNKNOWN). |
+| <a id="codequalityreportscomparerreportdegradationweburl"></a>`webUrl` | [`String`](#string) | URL to the file along with line number. |
+
+### `CodequalityReportsComparerReportSummary`
+
+Represents a summary of the compared codequality report.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="codequalityreportscomparerreportsummaryerrored"></a>`errored` | [`Int`](#int) | Count of code quality errors. |
+| <a id="codequalityreportscomparerreportsummaryresolved"></a>`resolved` | [`Int`](#int) | Count of resolved code quality degradations. |
+| <a id="codequalityreportscomparerreportsummarytotal"></a>`total` | [`Int`](#int) | Total count of code quality degradations. |
+
### `Commit`
#### Fields
@@ -14196,6 +14887,19 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="commitpipelinesupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Pipelines updated before this date. |
| <a id="commitpipelinesusername"></a>`username` | [`String`](#string) | Filter pipelines by the user that triggered the pipeline. |
+### `CommitData`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="commitdataagemapclass"></a>`ageMapClass` | [`String!`](#string) | CSS class for age of commit. |
+| <a id="commitdataauthoravatar"></a>`authorAvatar` | [`String!`](#string) | Link to author avatar. |
+| <a id="commitdatacommitauthorlink"></a>`commitAuthorLink` | [`String!`](#string) | Link to the commit author. |
+| <a id="commitdatacommitlink"></a>`commitLink` | [`String!`](#string) | Link to the commit. |
+| <a id="commitdataprojectblamelink"></a>`projectBlameLink` | [`String`](#string) | Link to blame prior to the change. |
+| <a id="commitdatatimeagotooltip"></a>`timeAgoTooltip` | [`String!`](#string) | Time of commit. |
+
### `CommitParentNames`
#### Fields
@@ -14302,7 +15006,7 @@ Represents a ComplianceFramework associated with a Project.
| <a id="complianceframeworkdescription"></a>`description` | [`String!`](#string) | Description of the compliance framework. |
| <a id="complianceframeworkid"></a>`id` | [`ID!`](#id) | Compliance framework ID. |
| <a id="complianceframeworkname"></a>`name` | [`String!`](#string) | Name of the compliance framework. |
-| <a id="complianceframeworkpipelineconfigurationfullpath"></a>`pipelineConfigurationFullPath` | [`String`](#string) | Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hipaa` **(ULTIMATE)**. |
+| <a id="complianceframeworkpipelineconfigurationfullpath"></a>`pipelineConfigurationFullPath` | [`String`](#string) | Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hipaa` **(ULTIMATE ALL)**. |
### `ComplianceStandardsAdherence`
@@ -14636,6 +15340,61 @@ A custom emoji uploaded by user.
| <a id="customerrelationsorganizationname"></a>`name` | [`String!`](#string) | Name of the organization. |
| <a id="customerrelationsorganizationupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp the organization was last updated. |
+### `CustomizableDashboard`
+
+Represents a product analytics dashboard.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardcategory"></a>`category` | [`CustomizableDashboardCategory!`](#customizabledashboardcategory) | Category of dashboard. |
+| <a id="customizabledashboardconfigurationproject"></a>`configurationProject` | [`Project`](#project) | Project which contains the dashboard definition. |
+| <a id="customizabledashboarddescription"></a>`description` | [`String`](#string) | Description of the dashboard. |
+| <a id="customizabledashboardpanels"></a>`panels` | [`CustomizableDashboardPanelConnection!`](#customizabledashboardpanelconnection) | Panels shown on the dashboard. (see [Connections](#connections)) |
+| <a id="customizabledashboardslug"></a>`slug` | [`String!`](#string) | Slug of the dashboard. |
+| <a id="customizabledashboardtitle"></a>`title` | [`String!`](#string) | Title of the dashboard. |
+| <a id="customizabledashboarduserdefined"></a>`userDefined` | [`Boolean!`](#boolean) | Indicates whether the dashboard is user-defined or provided by GitLab. |
+
+### `CustomizableDashboardPanel`
+
+Represents a product analytics dashboard panel.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardpanelgridattributes"></a>`gridAttributes` | [`JSON`](#json) | Description of the position and size of the panel. |
+| <a id="customizabledashboardpanelqueryoverrides"></a>`queryOverrides` | [`JSON`](#json) | Overrides for the visualization query object. |
+| <a id="customizabledashboardpaneltitle"></a>`title` | [`String!`](#string) | Title of the panel. |
+| <a id="customizabledashboardpanelvisualization"></a>`visualization` | [`CustomizableDashboardVisualization!`](#customizabledashboardvisualization) | Visualization of the panel. |
+
+### `CustomizableDashboardVisualization`
+
+Represents a product analytics dashboard visualization.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizabledashboardvisualizationdata"></a>`data` | [`JSON!`](#json) | Data of the visualization. |
+| <a id="customizabledashboardvisualizationerrors"></a>`errors` | [`[String!]`](#string) | Validation errors in the visualization. |
+| <a id="customizabledashboardvisualizationoptions"></a>`options` | [`JSON!`](#json) | Options of the visualization. |
+| <a id="customizabledashboardvisualizationslug"></a>`slug` | [`String!`](#string) | Slug of the visualization. |
+| <a id="customizabledashboardvisualizationtype"></a>`type` | [`String!`](#string) | Type of the visualization. |
+
+### `CustomizablePermission`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="customizablepermissionavailablefor"></a>`availableFor` | [`[String!]!`](#string) | Objects the permission is available for. |
+| <a id="customizablepermissiondescription"></a>`description` | [`String`](#string) | Description of the permission. |
+| <a id="customizablepermissionname"></a>`name` | [`String!`](#string) | Localized name of the permission. |
+| <a id="customizablepermissionrequirement"></a>`requirement` | [`String`](#string) | Requirement of the permission. |
+| <a id="customizablepermissionvalue"></a>`value` | [`String!`](#string) | Value of the permission. |
+
### `DastPreScanVerification`
Represents a DAST Pre Scan Verification.
@@ -14763,7 +15522,7 @@ Represents a DAST Site Profile.
### `DastSiteProfileAuth`
-Input type for DastSiteProfile authentication.
+DastSiteProfile authentication.
#### Fields
@@ -14831,6 +15590,7 @@ A software dependency used by a project.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="dependencyid"></a>`id` | [`GlobalID!`](#globalid) | ID of the dependency. |
+| <a id="dependencylicenses"></a>`licenses` | [`[License!]`](#license) | Licenses associated to the dependency. |
| <a id="dependencylocation"></a>`location` | [`Location`](#location) | Information about where the dependency is located. |
| <a id="dependencyname"></a>`name` | [`String!`](#string) | Name of the dependency. |
| <a id="dependencypackager"></a>`packager` | [`PackageManager`](#packagemanager) | Description of the tool used to manage the dependency. |
@@ -15881,6 +16641,7 @@ Relationship between an epic and an issue.
| <a id="epicissueepicissueid"></a>`epicIssueId` | [`ID!`](#id) | ID of the epic-issue relation. |
| <a id="epicissueescalationpolicy"></a>`escalationPolicy` | [`EscalationPolicyType`](#escalationpolicytype) | Escalation policy associated with the issue. Available for issues which support escalation. |
| <a id="epicissueescalationstatus"></a>`escalationStatus` | [`IssueEscalationStatus`](#issueescalationstatus) | Escalation status of the issue. |
+| <a id="epicissueexternalauthor"></a>`externalAuthor` | [`String`](#string) | Email address of non-GitLab user reporting the issue. For guests, the email address is obfuscated. |
| <a id="epicissuehasepic"></a>`hasEpic` | [`Boolean!`](#boolean) | Indicates if the issue belongs to an epic. Can return true and not show an associated epic when the user has no access to the epic. |
| <a id="epicissuehealthstatus"></a>`healthStatus` | [`HealthStatus`](#healthstatus) | Current health status. |
| <a id="epicissuehidden"></a>`hidden` | [`Boolean`](#boolean) | Indicates the issue is hidden because the author has been banned. |
@@ -16321,7 +17082,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
##### `GeoNode.designManagementRepositoryRegistries`
-Find Design Repository registries on this Geo node. Ignored if `geo_design_management_repository_replication` feature flag is disabled.
+Find Design Management Repository registries on this Geo node.
WARNING:
**Introduced** in 16.1.
@@ -16583,7 +17344,7 @@ Stores Google Cloud Logging configurations associated with IAM service accounts,
| <a id="googlecloudloggingconfigurationtypegroup"></a>`group` | [`Group!`](#group) | Group the configuration belongs to. |
| <a id="googlecloudloggingconfigurationtypeid"></a>`id` | [`ID!`](#id) | ID of the configuration. |
| <a id="googlecloudloggingconfigurationtypelogidname"></a>`logIdName` | [`String!`](#string) | Log ID. |
-| <a id="googlecloudloggingconfigurationtypeprivatekey"></a>`privateKey` | [`String!`](#string) | Private key. |
+| <a id="googlecloudloggingconfigurationtypename"></a>`name` | [`String!`](#string) | Name of the external destination to send audit events to. |
### `GpgSignature`
@@ -16680,7 +17441,6 @@ GPG signature for a signed commit.
| <a id="groupvisibility"></a>`visibility` | [`String`](#string) | Visibility of the namespace. |
| <a id="groupvulnerabilityscanners"></a>`vulnerabilityScanners` | [`VulnerabilityScannerConnection`](#vulnerabilityscannerconnection) | Vulnerability scanners reported on the project vulnerabilities of the group and its subgroups. (see [Connections](#connections)) |
| <a id="groupweburl"></a>`webUrl` | [`String!`](#string) | Web URL of the group. |
-| <a id="groupworkitems"></a>`workItems` **{warning-solid}** | [`WorkItemConnection`](#workitemconnection) | **Introduced** in 16.3. This feature is an Experiment. It can be changed or removed at any time. Work items that belong to the namespace. |
#### Fields with arguments
@@ -16899,6 +17659,47 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupcontributionsfrom"></a>`from` | [`ISO8601Date!`](#iso8601date) | Start date of the reporting time range. |
| <a id="groupcontributionsto"></a>`to` | [`ISO8601Date!`](#iso8601date) | End date of the reporting time range. The end date must be within 93 days after the start date. |
+##### `Group.customizableDashboardVisualizations`
+
+Visualizations of the group or associated configuration project.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`CustomizableDashboardVisualizationConnection`](#customizabledashboardvisualizationconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupcustomizabledashboardvisualizationsslug"></a>`slug` | [`String`](#string) | Slug of the visualization to return. |
+
+##### `Group.customizableDashboards`
+
+Customizable dashboards for the group.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`CustomizableDashboardConnection`](#customizabledashboardconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupcustomizabledashboardscategory"></a>`category` | [`CustomizableDashboardCategory`](#customizabledashboardcategory) | Find by dashboard type. |
+| <a id="groupcustomizabledashboardsslug"></a>`slug` | [`String`](#string) | Find by dashboard slug. |
+
##### `Group.dataTransfer`
Data transfer data point for a specific period. This is mocked data under a development feature flag.
@@ -17461,6 +18262,23 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="grouptimelogsstarttime"></a>`startTime` | [`Time`](#time) | List timelogs within a time range where the logged time is equal to or after startTime. |
| <a id="grouptimelogsusername"></a>`username` | [`String`](#string) | List timelogs for a user. |
+##### `Group.valueStreamDashboardUsageOverview`
+
+Aggregated usage counts within the group.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`ValueStreamDashboardCount`](#valuestreamdashboardcount).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupvaluestreamdashboardusageoverviewidentifier"></a>`identifier` | [`ValueStreamDashboardMetric!`](#valuestreamdashboardmetric) | Type of counts to retrieve. |
+| <a id="groupvaluestreamdashboardusageoverviewtimeframe"></a>`timeframe` | [`Timeframe!`](#timeframe) | Counts recorded during this time frame, usually from beginning of the month until the end of the month (the system runs monthly aggregations). |
+
##### `Group.vulnerabilities`
Vulnerabilities reported on the projects in the group and its subgroups.
@@ -17479,6 +18297,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupvulnerabilitiesclusterid"></a>`clusterId` | [`[ClustersClusterID!]`](#clustersclusterid) | Filter vulnerabilities by `cluster_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. |
| <a id="groupvulnerabilitiesdismissalreason"></a>`dismissalReason` | [`[VulnerabilityDismissalReason!]`](#vulnerabilitydismissalreason) | Filter by dismissal reason. Only dismissed Vulnerabilities will be included with the filter. |
| <a id="groupvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
+| <a id="groupvulnerabilitieshasmergerequest"></a>`hasMergeRequest` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked merge requests. |
| <a id="groupvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
| <a id="groupvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| <a id="groupvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
@@ -17530,6 +18349,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="groupvulnerabilityseveritiescountclusteragentid"></a>`clusterAgentId` | [`[ClustersAgentID!]`](#clustersagentid) | Filter vulnerabilities by `cluster_agent_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. |
+| <a id="groupvulnerabilityseveritiescountdismissalreason"></a>`dismissalReason` | [`[VulnerabilityDismissalReason!]`](#vulnerabilitydismissalreason) | Filter by dismissal reason. |
| <a id="groupvulnerabilityseveritiescounthasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have issues. |
| <a id="groupvulnerabilityseveritiescounthasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have a resolution. |
| <a id="groupvulnerabilityseveritiescountimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
@@ -17540,6 +18360,22 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| <a id="groupvulnerabilityseveritiescountseverity"></a>`severity` | [`[VulnerabilitySeverity!]`](#vulnerabilityseverity) | Filter vulnerabilities by severity. |
| <a id="groupvulnerabilityseveritiescountstate"></a>`state` | [`[VulnerabilityState!]`](#vulnerabilitystate) | Filter vulnerabilities by state. |
+##### `Group.workItem`
+
+Find a work item by IID directly associated with the group. Returns `null` if the `namespace_level_work_items` feature flag is disabled.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`WorkItem`](#workitem).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupworkitemiid"></a>`iid` | [`String!`](#string) | IID of the work item. |
+
##### `Group.workItemTypes`
Work item types available to the group.
@@ -17556,6 +18392,35 @@ four standard [pagination arguments](#connection-pagination-arguments):
| ---- | ---- | ----------- |
| <a id="groupworkitemtypestaskable"></a>`taskable` | [`Boolean`](#boolean) | If `true`, only taskable work item types will be returned. Argument is experimental and can be removed in the future without notice. |
+##### `Group.workItems`
+
+Work items that belong to the namespace.
+
+WARNING:
+**Introduced** in 16.3.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`WorkItemConnection`](#workitemconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupworkitemsauthorusername"></a>`authorUsername` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is an Experiment. It can be changed or removed at any time. Filter work items by author username. |
+| <a id="groupworkitemsiid"></a>`iid` | [`String`](#string) | IID of the work item. For example, "1". |
+| <a id="groupworkitemsiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of work items. For example, `["1", "2"]`. |
+| <a id="groupworkitemsin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
+| <a id="groupworkitemsrequirementlegacywidget"></a>`requirementLegacyWidget` **{warning-solid}** | [`RequirementLegacyFilterInput`](#requirementlegacyfilterinput) | **Deprecated** in 15.9. Use work item IID filter instead. |
+| <a id="groupworkitemssearch"></a>`search` | [`String`](#string) | Search query for title or description. |
+| <a id="groupworkitemssort"></a>`sort` | [`WorkItemSort`](#workitemsort) | Sort work items by criteria. |
+| <a id="groupworkitemsstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of the work item. |
+| <a id="groupworkitemsstatuswidget"></a>`statusWidget` | [`StatusFilterInput`](#statusfilterinput) | Input for status widget filter. Ignored if `work_items_mvc_2` is disabled. |
+| <a id="groupworkitemstypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. |
+
### `GroupDataTransfer`
#### Fields
@@ -17755,6 +18620,18 @@ Represents the Geo sync and verification state of a group wiki repository.
| <a id="groupwikirepositoryregistryverificationstate"></a>`verificationState` | [`VerificationStateEnum`](#verificationstateenum) | Verification state of the GroupWikiRepositoryRegistry. |
| <a id="groupwikirepositoryregistryverifiedat"></a>`verifiedAt` | [`Time`](#time) | Timestamp of the most recent successful verification of the GroupWikiRepositoryRegistry. |
+### `Groups`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupscommit"></a>`commit` | [`Commit!`](#commit) | Commit responsible for specified group. |
+| <a id="groupscommitdata"></a>`commitData` | [`CommitData`](#commitdata) | HTML data derived from commit needed to present blame. |
+| <a id="groupslineno"></a>`lineno` | [`Int!`](#int) | Starting line number for the commit group. |
+| <a id="groupslines"></a>`lines` | [`[String!]!`](#string) | Array of lines added for the commit group. |
+| <a id="groupsspan"></a>`span` | [`Int!`](#int) | Number of contiguous lines which the blame spans for the commit group. |
+
### `HelmFileMetadata`
Helm file metadata.
@@ -17888,6 +18765,20 @@ Represents an external resource to send instance audit events to.
| <a id="instanceexternalauditeventdestinationname"></a>`name` | [`String!`](#string) | Name of the external destination to send audit events to. |
| <a id="instanceexternalauditeventdestinationverificationtoken"></a>`verificationToken` | [`String!`](#string) | Verification token to validate source of event. |
+### `InstanceGoogleCloudLoggingConfigurationType`
+
+Stores instance level Google Cloud Logging configurations associated with IAM service accounts,used for generating access tokens.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="instancegooglecloudloggingconfigurationtypeclientemail"></a>`clientEmail` | [`String!`](#string) | Client email. |
+| <a id="instancegooglecloudloggingconfigurationtypegoogleprojectidname"></a>`googleProjectIdName` | [`String!`](#string) | Google project ID. |
+| <a id="instancegooglecloudloggingconfigurationtypeid"></a>`id` | [`ID!`](#id) | ID of the configuration. |
+| <a id="instancegooglecloudloggingconfigurationtypelogidname"></a>`logIdName` | [`String!`](#string) | Log ID. |
+| <a id="instancegooglecloudloggingconfigurationtypename"></a>`name` | [`String!`](#string) | Name of the external destination to send audit events to. |
+
### `InstanceSecurityDashboard`
#### Fields
@@ -17954,6 +18845,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="instancesecuritydashboardvulnerabilityseveritiescountclusteragentid"></a>`clusterAgentId` | [`[ClustersAgentID!]`](#clustersagentid) | Filter vulnerabilities by `cluster_agent_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. |
+| <a id="instancesecuritydashboardvulnerabilityseveritiescountdismissalreason"></a>`dismissalReason` | [`[VulnerabilityDismissalReason!]`](#vulnerabilitydismissalreason) | Filter by dismissal reason. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescounthasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have issues. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescounthasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have a resolution. |
| <a id="instancesecuritydashboardvulnerabilityseveritiescountimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
@@ -18010,6 +18902,7 @@ Describes an issuable resource link for incident issues.
| <a id="issueepic"></a>`epic` | [`Epic`](#epic) | Epic to which this issue belongs. |
| <a id="issueescalationpolicy"></a>`escalationPolicy` | [`EscalationPolicyType`](#escalationpolicytype) | Escalation policy associated with the issue. Available for issues which support escalation. |
| <a id="issueescalationstatus"></a>`escalationStatus` | [`IssueEscalationStatus`](#issueescalationstatus) | Escalation status of the issue. |
+| <a id="issueexternalauthor"></a>`externalAuthor` | [`String`](#string) | Email address of non-GitLab user reporting the issue. For guests, the email address is obfuscated. |
| <a id="issuehasepic"></a>`hasEpic` | [`Boolean!`](#boolean) | Indicates if the issue belongs to an epic. Can return true and not show an associated epic when the user has no access to the epic. |
| <a id="issuehealthstatus"></a>`healthStatus` | [`HealthStatus`](#healthstatus) | Current health status. |
| <a id="issuehidden"></a>`hidden` | [`Boolean`](#boolean) | Indicates the issue is hidden because the author has been banned. |
@@ -18340,6 +19233,7 @@ Represents an SSH key.
| <a id="labeldescription"></a>`description` | [`String`](#string) | Description of the label (Markdown rendered as HTML for caching). |
| <a id="labeldescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. |
| <a id="labelid"></a>`id` | [`ID!`](#id) | Label ID. |
+| <a id="labellockonmerge"></a>`lockOnMerge` | [`Boolean!`](#boolean) | Indicates this label is locked for merge requests that have been merged. |
| <a id="labeltextcolor"></a>`textColor` | [`String!`](#string) | Text color of the label. |
| <a id="labeltitle"></a>`title` | [`String!`](#string) | Content of the label. |
| <a id="labelupdatedat"></a>`updatedAt` | [`Time!`](#time) | When this label was last updated. |
@@ -18368,6 +19262,15 @@ Represents the Geo sync and verification state of an LFS object.
| <a id="lfsobjectregistryverificationstate"></a>`verificationState` | [`VerificationStateEnum`](#verificationstateenum) | Verification state of the LfsObjectRegistry. |
| <a id="lfsobjectregistryverifiedat"></a>`verifiedAt` | [`Time`](#time) | Timestamp of the most recent successful verification of the LfsObjectRegistry. |
+### `License`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="licensename"></a>`name` | [`String!`](#string) | Name of the license. |
+| <a id="licenseurl"></a>`url` | [`String!`](#string) | License URL in relation to SPDX. |
+
### `LicenseHistoryEntry`
Represents an entry from the Cloud License history.
@@ -18457,6 +19360,7 @@ Defines which user roles, users, or groups can merge into a protected branch.
| <a id="mergerequestautomergestrategy"></a>`autoMergeStrategy` | [`String`](#string) | Selected auto merge strategy. |
| <a id="mergerequestavailableautomergestrategies"></a>`availableAutoMergeStrategies` | [`[String!]`](#string) | Array of available auto merge strategies. |
| <a id="mergerequestawardemoji"></a>`awardEmoji` | [`AwardEmojiConnection`](#awardemojiconnection) | List of emoji reactions associated with the merge request. (see [Connections](#connections)) |
+| <a id="mergerequestcodequalityreportscomparer"></a>`codequalityReportsComparer` **{warning-solid}** | [`CodequalityReportsComparer`](#codequalityreportscomparer) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Code quality reports comparison reported on the merge request. Returns `null` if `sast_reports_in_inline_diff` feature flag is disabled. |
| <a id="mergerequestcommenters"></a>`commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) |
| <a id="mergerequestcommitcount"></a>`commitCount` | [`Int`](#int) | Number of commits in the merge request. |
| <a id="mergerequestcommits"></a>`commits` | [`CommitConnection`](#commitconnection) | Merge request commits. (see [Connections](#connections)) |
@@ -18523,6 +19427,7 @@ Defines which user roles, users, or groups can merge into a protected branch.
| <a id="mergerequeststate"></a>`state` | [`MergeRequestState!`](#mergerequeststate) | State of the merge request. |
| <a id="mergerequestsubscribed"></a>`subscribed` | [`Boolean!`](#boolean) | Indicates if the currently logged in user is subscribed to this merge request. |
| <a id="mergerequestsuggestedreviewers"></a>`suggestedReviewers` **{warning-solid}** | [`SuggestedReviewersType`](#suggestedreviewerstype) | **Introduced** in 15.4. This feature is an Experiment. It can be changed or removed at any time. Suggested reviewers for merge request. Returns `null` if `suggested_reviewers` feature flag is disabled. This flag is disabled by default and only available on GitLab.com because the feature is experimental and is subject to change without notice. |
+| <a id="mergerequestsupportslockonmerge"></a>`supportsLockOnMerge` | [`Boolean!`](#boolean) | Indicates if the merge request supports locked labels. |
| <a id="mergerequesttargetbranch"></a>`targetBranch` | [`String!`](#string) | Target branch of the merge request. |
| <a id="mergerequesttargetbranchexists"></a>`targetBranchExists` | [`Boolean!`](#boolean) | Indicates if the target branch of the merge request exists. |
| <a id="mergerequesttargetproject"></a>`targetProject` | [`Project!`](#project) | Target project of the merge request. |
@@ -19554,6 +20459,7 @@ A review summary generated by AI.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestreviewllmsummarycontent"></a>`content` | [`String!`](#string) | Content of the review summary. |
+| <a id="mergerequestreviewllmsummarycontenthtml"></a>`contentHtml` | [`String!`](#string) | HTML content of the review summary, converted from Markdown. |
| <a id="mergerequestreviewllmsummarycreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of when the review summary was created. |
| <a id="mergerequestreviewllmsummarymergerequestdiffid"></a>`mergeRequestDiffId` | [`ID!`](#id) | ID of the Merge Request diff associated with the review summary. |
| <a id="mergerequestreviewllmsummaryprovider"></a>`provider` | [`String!`](#string) | AI provider that generated the summary. |
@@ -20222,6 +21128,40 @@ Active period time range for on-call rotation.
| <a id="oncallrotationactiveperiodtypeendtime"></a>`endTime` | [`String`](#string) | End of the rotation active period. |
| <a id="oncallrotationactiveperiodtypestarttime"></a>`startTime` | [`String`](#string) | Start of the rotation active period. |
+### `Organization`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="organizationid"></a>`id` **{warning-solid}** | [`ID!`](#id) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. ID of the organization. |
+| <a id="organizationname"></a>`name` **{warning-solid}** | [`String!`](#string) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Name of the organization. |
+| <a id="organizationorganizationusers"></a>`organizationUsers` **{warning-solid}** | [`OrganizationUserConnection!`](#organizationuserconnection) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Users with access to the organization. |
+| <a id="organizationpath"></a>`path` **{warning-solid}** | [`String!`](#string) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Path of the organization. |
+
+#### Fields with arguments
+
+##### `Organization.groups`
+
+Groups within this organization that the user has access to.
+
+WARNING:
+**Introduced** in 16.4.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`GroupConnection!`](#groupconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="organizationgroupssearch"></a>`search` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Search query for group name or full path. |
+| <a id="organizationgroupssort"></a>`sort` **{warning-solid}** | [`OrganizationGroupSort`](#organizationgroupsort) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Criteria to sort organization groups by. |
+
### `OrganizationStateCounts`
Represents the total number of organizations for the represented states.
@@ -20234,6 +21174,18 @@ Represents the total number of organizations for the represented states.
| <a id="organizationstatecountsall"></a>`all` | [`Int`](#int) | Number of organizations with state `ALL`. |
| <a id="organizationstatecountsinactive"></a>`inactive` | [`Int`](#int) | Number of organizations with state `INACTIVE`. |
+### `OrganizationUser`
+
+A user with access to the organization.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="organizationuserbadges"></a>`badges` **{warning-solid}** | [`[String!]`](#string) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Badges describing the user within the organization. |
+| <a id="organizationuserid"></a>`id` **{warning-solid}** | [`ID!`](#id) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. ID of the organization user. |
+| <a id="organizationuseruser"></a>`user` **{warning-solid}** | [`UserCore!`](#usercore) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. User that is associated with the organization. |
+
### `Package`
Represents a package with pipelines in the Package Registry.
@@ -20887,47 +21839,6 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="previewbillableuserchangeseatsinsubscription"></a>`seatsInSubscription` | [`Int`](#int) | Number of seats in subscription. |
| <a id="previewbillableuserchangewillincreaseoverage"></a>`willIncreaseOverage` | [`Boolean`](#boolean) | If the group will have an increased overage after change. |
-### `ProductAnalyticsDashboard`
-
-Represents a product analytics dashboard.
-
-#### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboarddescription"></a>`description` | [`String`](#string) | Description of the dashboard. |
-| <a id="productanalyticsdashboardpanels"></a>`panels` | [`ProductAnalyticsDashboardPanelConnection!`](#productanalyticsdashboardpanelconnection) | Panels shown on the dashboard. (see [Connections](#connections)) |
-| <a id="productanalyticsdashboardslug"></a>`slug` | [`String!`](#string) | Slug of the dashboard. |
-| <a id="productanalyticsdashboardtitle"></a>`title` | [`String!`](#string) | Title of the dashboard. |
-| <a id="productanalyticsdashboarduserdefined"></a>`userDefined` | [`Boolean!`](#boolean) | Indicates whether the dashboard is user-defined or provided by GitLab. |
-
-### `ProductAnalyticsDashboardPanel`
-
-Represents a product analytics dashboard panel.
-
-#### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboardpanelgridattributes"></a>`gridAttributes` | [`JSON`](#json) | Description of the position and size of the panel. |
-| <a id="productanalyticsdashboardpanelqueryoverrides"></a>`queryOverrides` | [`JSON`](#json) | Overrides for the visualization query object. |
-| <a id="productanalyticsdashboardpaneltitle"></a>`title` | [`String!`](#string) | Title of the panel. |
-| <a id="productanalyticsdashboardpanelvisualization"></a>`visualization` | [`ProductAnalyticsDashboardVisualization!`](#productanalyticsdashboardvisualization) | Visualization of the panel. |
-
-### `ProductAnalyticsDashboardVisualization`
-
-Represents a product analytics dashboard visualization.
-
-#### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="productanalyticsdashboardvisualizationdata"></a>`data` | [`JSON!`](#json) | Data of the visualization. |
-| <a id="productanalyticsdashboardvisualizationerrors"></a>`errors` | [`[String!]`](#string) | Validation errors in the visualization. |
-| <a id="productanalyticsdashboardvisualizationoptions"></a>`options` | [`JSON!`](#json) | Options of the visualization. |
-| <a id="productanalyticsdashboardvisualizationslug"></a>`slug` | [`String!`](#string) | Slug of the visualization. |
-| <a id="productanalyticsdashboardvisualizationtype"></a>`type` | [`String!`](#string) | Type of the visualization. |
-
### `Project`
#### Fields
@@ -21277,6 +22188,47 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectcontainerrepositoriesname"></a>`name` | [`String`](#string) | Filter the container repositories by their name. |
| <a id="projectcontainerrepositoriessort"></a>`sort` | [`ContainerRepositorySort`](#containerrepositorysort) | Sort container repositories by this criteria. |
+##### `Project.customizableDashboardVisualizations`
+
+Visualizations of the project or associated configuration project.
+
+WARNING:
+**Introduced** in 16.1.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`CustomizableDashboardVisualizationConnection`](#customizabledashboardvisualizationconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectcustomizabledashboardvisualizationsslug"></a>`slug` | [`String`](#string) | Slug of the visualization to return. |
+
+##### `Project.customizableDashboards`
+
+Customizable dashboards for the project.
+
+WARNING:
+**Introduced** in 15.6.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`CustomizableDashboardConnection`](#customizabledashboardconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectcustomizabledashboardscategory"></a>`category` | [`CustomizableDashboardCategory`](#customizabledashboardcategory) | Find by dashboard type. |
+| <a id="projectcustomizabledashboardsslug"></a>`slug` | [`String`](#string) | Find by dashboard slug. |
+
##### `Project.dastProfile`
DAST Profile associated with the project.
@@ -21905,7 +22857,7 @@ Network Policies of the project.
WARNING:
**Deprecated** in 14.8.
-Network policies are deprecated and will be removed in GitLab 16.0. Since GitLab 15.0 this field returns no data.
+Network policies are deprecated and will be removed in GitLab 17.0. This field returns no data in GitLab 15.0 and later.
Returns [`NetworkPolicyConnection`](#networkpolicyconnection).
@@ -22006,46 +22958,6 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectpipelinesupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Pipelines updated before this date. |
| <a id="projectpipelinesusername"></a>`username` | [`String`](#string) | Filter pipelines by the user that triggered the pipeline. |
-##### `Project.productAnalyticsDashboards`
-
-Product Analytics dashboards of the project.
-
-WARNING:
-**Introduced** in 15.6.
-This feature is an Experiment. It can be changed or removed at any time.
-
-Returns [`ProductAnalyticsDashboardConnection`](#productanalyticsdashboardconnection).
-
-This field returns a [connection](#connections). It accepts the
-four standard [pagination arguments](#connection-pagination-arguments):
-`before: String`, `after: String`, `first: Int`, `last: Int`.
-
-###### Arguments
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="projectproductanalyticsdashboardsslug"></a>`slug` | [`String`](#string) | Find by dashboard slug. |
-
-##### `Project.productAnalyticsVisualizations`
-
-Visualizations of the project or associated configuration project.
-
-WARNING:
-**Introduced** in 16.1.
-This feature is an Experiment. It can be changed or removed at any time.
-
-Returns [`ProductAnalyticsDashboardVisualizationConnection`](#productanalyticsdashboardvisualizationconnection).
-
-This field returns a [connection](#connections). It accepts the
-four standard [pagination arguments](#connection-pagination-arguments):
-`before: String`, `after: String`, `first: Int`, `last: Int`.
-
-###### Arguments
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="projectproductanalyticsvisualizationsslug"></a>`slug` | [`String`](#string) | Slug of the visualization to return. |
-
##### `Project.projectMembers`
Members of the project.
@@ -22340,6 +23252,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectvulnerabilitiesclusterid"></a>`clusterId` | [`[ClustersClusterID!]`](#clustersclusterid) | Filter vulnerabilities by `cluster_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. |
| <a id="projectvulnerabilitiesdismissalreason"></a>`dismissalReason` | [`[VulnerabilityDismissalReason!]`](#vulnerabilitydismissalreason) | Filter by dismissal reason. Only dismissed Vulnerabilities will be included with the filter. |
| <a id="projectvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. |
+| <a id="projectvulnerabilitieshasmergerequest"></a>`hasMergeRequest` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked merge requests. |
| <a id="projectvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. |
| <a id="projectvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
| <a id="projectvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. |
@@ -22378,6 +23291,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectvulnerabilityseveritiescountclusteragentid"></a>`clusterAgentId` | [`[ClustersAgentID!]`](#clustersagentid) | Filter vulnerabilities by `cluster_agent_id`. Vulnerabilities with a `reportType` of `cluster_image_scanning` are only included with this filter. |
+| <a id="projectvulnerabilityseveritiescountdismissalreason"></a>`dismissalReason` | [`[VulnerabilityDismissalReason!]`](#vulnerabilitydismissalreason) | Filter by dismissal reason. |
| <a id="projectvulnerabilityseveritiescounthasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have issues. |
| <a id="projectvulnerabilityseveritiescounthasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Filter vulnerabilities that do or do not have a resolution. |
| <a id="projectvulnerabilityseveritiescountimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. |
@@ -22444,6 +23358,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectcicdsettingkeeplatestartifact"></a>`keepLatestArtifact` | [`Boolean`](#boolean) | Whether to keep the latest builds artifacts. |
| <a id="projectcicdsettingmergepipelinesenabled"></a>`mergePipelinesEnabled` | [`Boolean`](#boolean) | Whether merge pipelines are enabled. |
| <a id="projectcicdsettingmergetrainsenabled"></a>`mergeTrainsEnabled` | [`Boolean`](#boolean) | Whether merge trains are enabled. |
+| <a id="projectcicdsettingmergetrainsskiptrainallowed"></a>`mergeTrainsSkipTrainAllowed` | [`Boolean!`](#boolean) | Whether merge immediately is allowed for merge trains. |
| <a id="projectcicdsettingproject"></a>`project` | [`Project`](#project) | Project the CI/CD settings belong to. |
### `ProjectConversations`
@@ -22452,7 +23367,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="projectconversationsciconfigmessages"></a>`ciConfigMessages` **{warning-solid}** | [`AiMessageTypeConnection`](#aimessagetypeconnection) | **Introduced** in 16.0. This feature is an Experiment. It can be changed or removed at any time. Messages generated by open ai and the user. |
+| <a id="projectconversationsciconfigmessages"></a>`ciConfigMessages` **{warning-solid}** | [`AiMessageConnection`](#aimessageconnection) | **Introduced** in 16.0. This feature is an Experiment. It can be changed or removed at any time. Messages generated by open ai and the user. |
### `ProjectDataTransfer`
@@ -22849,6 +23764,31 @@ Pypi metadata.
| <a id="querycomplexitylimit"></a>`limit` | [`Int`](#int) | GraphQL query complexity limit. See [GitLab documentation on this limit](https://docs.gitlab.com/ee/api/graphql/index.html#max-query-complexity). |
| <a id="querycomplexityscore"></a>`score` | [`Int`](#int) | GraphQL query complexity score. |
+### `QueueingDelayHistory`
+
+Aggregated statistics about queueing times for CI jobs.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="queueingdelayhistorytimeseries"></a>`timeSeries` | [`[QueueingHistoryTimeSeries!]`](#queueinghistorytimeseries) | Time series. |
+
+### `QueueingHistoryTimeSeries`
+
+The amount of time for a job to be picked up by a runner, in percentiles.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="queueinghistorytimeseriesp50"></a>`p50` **{warning-solid}** | [`Duration`](#duration) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. 50th percentile. 50% of the durations are lower than this value. |
+| <a id="queueinghistorytimeseriesp75"></a>`p75` **{warning-solid}** | [`Duration`](#duration) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. 75th percentile. 75% of the durations are lower than this value. |
+| <a id="queueinghistorytimeseriesp90"></a>`p90` **{warning-solid}** | [`Duration`](#duration) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. 90th percentile. 90% of the durations are lower than this value. |
+| <a id="queueinghistorytimeseriesp95"></a>`p95` **{warning-solid}** | [`Duration`](#duration) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. 95th percentile. 95% of the durations are lower than this value. |
+| <a id="queueinghistorytimeseriesp99"></a>`p99` **{warning-solid}** | [`Duration`](#duration) | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. 99th percentile. 99% of the durations are lower than this value. |
+| <a id="queueinghistorytimeseriestime"></a>`time` | [`Time!`](#time) | Start of the time interval. |
+
### `RecentFailures`
Recent failure history of a test case.
@@ -23101,6 +24041,25 @@ Returns [`RepositoryCodeownerValidation`](#repositorycodeownervalidation).
| <a id="repositoryblobstoredexternally"></a>`storedExternally` | [`Boolean`](#boolean) | Whether the blob's content is stored externally (for instance, in LFS). |
| <a id="repositoryblobwebpath"></a>`webPath` | [`String`](#string) | Web path of the blob. |
+#### Fields with arguments
+
+##### `RepositoryBlob.blame`
+
+Blob blame. Available only when feature flag `graphql_git_blame` is enabled.
+
+WARNING:
+**Introduced** in 16.3.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`Blame`](#blame).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="repositoryblobblamefromline"></a>`fromLine` | [`Int`](#int) | Range starting from the line. Cannot be less than 1 or greater than `to_line`. |
+| <a id="repositoryblobblametoline"></a>`toLine` | [`Int`](#int) | Range ending on the line. Cannot be less than 1 or less than `to_line`. |
+
### `RepositoryCodeownerError`
#### Fields
@@ -23342,6 +24301,7 @@ Represents the scan execution policy.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="scanexecutionpolicydescription"></a>`description` | [`String!`](#string) | Description of the policy. |
+| <a id="scanexecutionpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
| <a id="scanexecutionpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="scanexecutionpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
| <a id="scanexecutionpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
@@ -23358,6 +24318,7 @@ Represents the scan result policy.
| ---- | ---- | ----------- |
| <a id="scanresultpolicyallgroupapprovers"></a>`allGroupApprovers` | [`[PolicyApprovalGroup!]`](#policyapprovalgroup) | All potential approvers of the group type, including groups inaccessible to the user. |
| <a id="scanresultpolicydescription"></a>`description` | [`String!`](#string) | Description of the policy. |
+| <a id="scanresultpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
| <a id="scanresultpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` | [`[Group!]`](#group) | Approvers of the group type. |
| <a id="scanresultpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
@@ -24228,6 +25189,16 @@ Represents a recorded measurement (object count) for the Admins.
| <a id="userachievementupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp the achievement was last updated. |
| <a id="userachievementuser"></a>`user` | [`UserCore!`](#usercore) | Achievement recipient. |
+### `UserAddOnAssignment`
+
+An assignment of an AddOnPurchase to a User.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="useraddonassignmentaddonpurchase"></a>`addOnPurchase` | [`AddOnPurchase!`](#addonpurchase) | Add-on purchase the user is assigned to. |
+
### `UserCallout`
#### Fields
@@ -24239,7 +25210,7 @@ Represents a recorded measurement (object count) for the Admins.
### `UserCore`
-Core represention of a GitLab user.
+Core representation of a GitLab user.
#### Fields
@@ -24574,6 +25545,18 @@ fields relate to interactions between the two entities.
| <a id="valuestreamanalyticsmetricunit"></a>`unit` | [`String`](#string) | Unit of measurement. |
| <a id="valuestreamanalyticsmetricvalue"></a>`value` | [`Float`](#float) | Value for the metric. |
+### `ValueStreamDashboardCount`
+
+Represents a recorded measurement (object count) for the requested group.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="valuestreamdashboardcountcount"></a>`count` | [`Int`](#int) | Object count. |
+| <a id="valuestreamdashboardcountidentifier"></a>`identifier` | [`ValueStreamDashboardMetric!`](#valuestreamdashboardmetric) | Type of object being measured. |
+| <a id="valuestreamdashboardcountrecordedat"></a>`recordedAt` | [`Time`](#time) | Time the measurement was taken. |
+
### `ValueStreamMetricLinkType`
#### Fields
@@ -24618,7 +25601,7 @@ Represents a vulnerability.
| <a id="vulnerabilitydetails"></a>`details` | [`[VulnerabilityDetail!]!`](#vulnerabilitydetail) | Details of the vulnerability. |
| <a id="vulnerabilitydetectedat"></a>`detectedAt` | [`Time!`](#time) | Timestamp of when the vulnerability was first detected. |
| <a id="vulnerabilitydiscussions"></a>`discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) |
-| <a id="vulnerabilitydismissalreason"></a>`dismissalReason` | [`VulnerabilityDismissalReason`](#vulnerabilitydismissalreason) | Reason for dismissal. Returns `null` for states other than `dismissed`. Returns `null` if `expose_dismissal_reason` feature flag is disabled. |
+| <a id="vulnerabilitydismissalreason"></a>`dismissalReason` | [`VulnerabilityDismissalReason`](#vulnerabilitydismissalreason) | Reason for dismissal. Returns `null` for states other than `dismissed`. |
| <a id="vulnerabilitydismissedat"></a>`dismissedAt` | [`Time`](#time) | Timestamp of when the vulnerability state was changed to dismissed. |
| <a id="vulnerabilitydismissedby"></a>`dismissedBy` | [`UserCore`](#usercore) | User that dismissed the vulnerability. |
| <a id="vulnerabilityexternalissuelinks"></a>`externalIssueLinks` | [`VulnerabilityExternalIssueLinkConnection!`](#vulnerabilityexternalissuelinkconnection) | List of external issue links related to the vulnerability. (see [Connections](#connections)) |
@@ -24640,6 +25623,7 @@ Represents a vulnerability.
| <a id="vulnerabilityresolvedondefaultbranch"></a>`resolvedOnDefaultBranch` | [`Boolean!`](#boolean) | Indicates whether the vulnerability is fixed on the default branch or not. |
| <a id="vulnerabilityscanner"></a>`scanner` | [`VulnerabilityScanner`](#vulnerabilityscanner) | Scanner metadata for the vulnerability. |
| <a id="vulnerabilityseverity"></a>`severity` | [`VulnerabilitySeverity`](#vulnerabilityseverity) | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL). |
+| <a id="vulnerabilitysolution"></a>`solution` | [`String`](#string) | Recommended solution for the vulnerability. |
| <a id="vulnerabilitystate"></a>`state` | [`VulnerabilityState`](#vulnerabilitystate) | State of the vulnerability (DETECTED, CONFIRMED, RESOLVED, DISMISSED). |
| <a id="vulnerabilitystatecomment"></a>`stateComment` | [`String`](#string) | Comment given for the vulnerability state change. |
| <a id="vulnerabilitystatetransitions"></a>`stateTransitions` | [`VulnerabilityStateTransitionTypeConnection`](#vulnerabilitystatetransitiontypeconnection) | List of state transitions related to the vulnerability. (see [Connections](#connections)) |
@@ -24647,6 +25631,7 @@ Represents a vulnerability.
| <a id="vulnerabilityupdatedat"></a>`updatedAt` | [`Time`](#time) | Timestamp of when the vulnerability was last updated. |
| <a id="vulnerabilityusernotescount"></a>`userNotesCount` | [`Int!`](#int) | Number of user notes attached to the vulnerability. |
| <a id="vulnerabilityuserpermissions"></a>`userPermissions` | [`VulnerabilityPermissions!`](#vulnerabilitypermissions) | Permissions for the current user on the resource. |
+| <a id="vulnerabilityuuid"></a>`uuid` | [`String!`](#string) | UUID of the vulnerability finding. Can be used to look up the associated security report finding. |
| <a id="vulnerabilityvulnerabilitypath"></a>`vulnerabilityPath` | [`String`](#string) | Path to the vulnerability's details page. |
| <a id="vulnerabilityweburl"></a>`webUrl` | [`String`](#string) | URL to the vulnerability's details page. |
@@ -25296,6 +26281,7 @@ Check permissions for the current user on a work item.
| ---- | ---- | ----------- |
| <a id="workitempermissionsadminparentlink"></a>`adminParentLink` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_parent_link` on this resource. |
| <a id="workitempermissionsadminworkitem"></a>`adminWorkItem` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_work_item` on this resource. |
+| <a id="workitempermissionsadminworkitemlink"></a>`adminWorkItemLink` | [`Boolean!`](#boolean) | Indicates the user can perform `admin_work_item_link` on this resource. |
| <a id="workitempermissionscreatenote"></a>`createNote` | [`Boolean!`](#boolean) | Indicates the user can perform `create_note` on this resource. |
| <a id="workitempermissionsdeleteworkitem"></a>`deleteWorkItem` | [`Boolean!`](#boolean) | Indicates the user can perform `delete_work_item` on this resource. |
| <a id="workitempermissionsreadworkitem"></a>`readWorkItem` | [`Boolean!`](#boolean) | Indicates the user can perform `read_work_item` on this resource. |
@@ -25439,9 +26425,30 @@ Represents the linked items widget.
| <a id="workitemwidgetlinkeditemsblocked"></a>`blocked` | [`Boolean`](#boolean) | Indicates the work item is blocked. Returns `null`if `linked_work_items` feature flag is disabled. |
| <a id="workitemwidgetlinkeditemsblockedbycount"></a>`blockedByCount` | [`Int`](#int) | Count of items blocking the work item. Returns `null`if `linked_work_items` feature flag is disabled. |
| <a id="workitemwidgetlinkeditemsblockingcount"></a>`blockingCount` | [`Int`](#int) | Count of items the work item is blocking. Returns `null`if `linked_work_items` feature flag is disabled. |
-| <a id="workitemwidgetlinkeditemslinkeditems"></a>`linkedItems` **{warning-solid}** | [`LinkedWorkItemTypeConnection`](#linkedworkitemtypeconnection) | **Introduced** in 16.3. This feature is an Experiment. It can be changed or removed at any time. Linked items for the work item. Returns `null`if `linked_work_items` feature flag is disabled. |
| <a id="workitemwidgetlinkeditemstype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
+#### Fields with arguments
+
+##### `WorkItemWidgetLinkedItems.linkedItems`
+
+Linked items for the work item. Returns `null` if `linked_work_items` feature flag is disabled.
+
+WARNING:
+**Introduced** in 16.3.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Returns [`LinkedWorkItemTypeConnection`](#linkedworkitemtypeconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetlinkeditemslinkeditemsfilter"></a>`filter` | [`WorkItemRelatedLinkType`](#workitemrelatedlinktype) | Filter by link type. Supported values: RELATED, BLOCKED_BY, and BLOCKS. Returns all types if omitted. |
+
### `WorkItemWidgetMilestone`
Represents a milestone widget.
@@ -25672,14 +26679,23 @@ Agent token statuses.
| <a id="agenttokenstatusactive"></a>`ACTIVE` | Active agent token. |
| <a id="agenttokenstatusrevoked"></a>`REVOKED` | Revoked agent token. |
-### `AiCachedMessageRole`
+### `AiChatMessageRole`
Roles to filter in chat message.
| Value | Description |
| ----- | ----------- |
-| <a id="aicachedmessageroleassistant"></a>`ASSISTANT` | Filter only assistant messages. |
-| <a id="aicachedmessageroleuser"></a>`USER` | Filter only user messages. |
+| <a id="aichatmessageroleassistant"></a>`ASSISTANT` | Filter only assistant messages. |
+| <a id="aichatmessagerolesystem"></a>`SYSTEM` | Filter only system messages. |
+| <a id="aichatmessageroleuser"></a>`USER` | Filter only user messages. |
+
+### `AiMessageType`
+
+Types of messages returned from AI features.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="aimessagetypetool"></a>`TOOL` | Tool selection message. |
### `AlertManagementAlertSort`
@@ -25900,6 +26916,47 @@ Values for sorting inherited variables.
| <a id="cigroupvariablessortkey_asc"></a>`KEY_ASC` | Key by ascending order. |
| <a id="cigroupvariablessortkey_desc"></a>`KEY_DESC` | Key by descending order. |
+### `CiJobFailureReason`
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="cijobfailurereasonapi_failure"></a>`API_FAILURE` | A job that failed due to api failure. |
+| <a id="cijobfailurereasonarchived_failure"></a>`ARCHIVED_FAILURE` | A job that failed due to archived failure. |
+| <a id="cijobfailurereasonbridge_pipeline_is_child_pipeline"></a>`BRIDGE_PIPELINE_IS_CHILD_PIPELINE` | A job that failed due to bridge pipeline is child pipeline. |
+| <a id="cijobfailurereasonbuilds_disabled"></a>`BUILDS_DISABLED` | A job that failed due to builds disabled. |
+| <a id="cijobfailurereasonci_quota_exceeded"></a>`CI_QUOTA_EXCEEDED` | A job that failed due to ci quota exceeded. |
+| <a id="cijobfailurereasondata_integrity_failure"></a>`DATA_INTEGRITY_FAILURE` | A job that failed due to data integrity failure. |
+| <a id="cijobfailurereasondeployment_rejected"></a>`DEPLOYMENT_REJECTED` | A job that failed due to deployment rejected. |
+| <a id="cijobfailurereasondownstream_bridge_project_not_found"></a>`DOWNSTREAM_BRIDGE_PROJECT_NOT_FOUND` | A job that failed due to downstream bridge project not found. |
+| <a id="cijobfailurereasondownstream_pipeline_creation_failed"></a>`DOWNSTREAM_PIPELINE_CREATION_FAILED` | A job that failed due to downstream pipeline creation failed. |
+| <a id="cijobfailurereasonenvironment_creation_failure"></a>`ENVIRONMENT_CREATION_FAILURE` | A job that failed due to environment creation failure. |
+| <a id="cijobfailurereasonfailed_outdated_deployment_job"></a>`FAILED_OUTDATED_DEPLOYMENT_JOB` | A job that failed due to failed outdated deployment job. |
+| <a id="cijobfailurereasonforward_deployment_failure"></a>`FORWARD_DEPLOYMENT_FAILURE` | A job that failed due to forward deployment failure. |
+| <a id="cijobfailurereasoninsufficient_bridge_permissions"></a>`INSUFFICIENT_BRIDGE_PERMISSIONS` | A job that failed due to insufficient bridge permissions. |
+| <a id="cijobfailurereasoninsufficient_upstream_permissions"></a>`INSUFFICIENT_UPSTREAM_PERMISSIONS` | A job that failed due to insufficient upstream permissions. |
+| <a id="cijobfailurereasoninvalid_bridge_trigger"></a>`INVALID_BRIDGE_TRIGGER` | A job that failed due to invalid bridge trigger. |
+| <a id="cijobfailurereasonip_restriction_failure"></a>`IP_RESTRICTION_FAILURE` | A job that failed due to ip restriction failure. |
+| <a id="cijobfailurereasonjob_execution_timeout"></a>`JOB_EXECUTION_TIMEOUT` | A job that failed due to job execution timeout. |
+| <a id="cijobfailurereasonmissing_dependency_failure"></a>`MISSING_DEPENDENCY_FAILURE` | A job that failed due to missing dependency failure. |
+| <a id="cijobfailurereasonno_matching_runner"></a>`NO_MATCHING_RUNNER` | A job that failed due to no matching runner. |
+| <a id="cijobfailurereasonpipeline_loop_detected"></a>`PIPELINE_LOOP_DETECTED` | A job that failed due to pipeline loop detected. |
+| <a id="cijobfailurereasonproject_deleted"></a>`PROJECT_DELETED` | A job that failed due to project deleted. |
+| <a id="cijobfailurereasonprotected_environment_failure"></a>`PROTECTED_ENVIRONMENT_FAILURE` | A job that failed due to protected environment failure. |
+| <a id="cijobfailurereasonreached_max_descendant_pipelines_depth"></a>`REACHED_MAX_DESCENDANT_PIPELINES_DEPTH` | A job that failed due to reached max descendant pipelines depth. |
+| <a id="cijobfailurereasonreached_max_pipeline_hierarchy_size"></a>`REACHED_MAX_PIPELINE_HIERARCHY_SIZE` | A job that failed due to reached max pipeline hierarchy size. |
+| <a id="cijobfailurereasonrunner_system_failure"></a>`RUNNER_SYSTEM_FAILURE` | A job that failed due to runner system failure. |
+| <a id="cijobfailurereasonrunner_unsupported"></a>`RUNNER_UNSUPPORTED` | A job that failed due to runner unsupported. |
+| <a id="cijobfailurereasonscheduler_failure"></a>`SCHEDULER_FAILURE` | A job that failed due to scheduler failure. |
+| <a id="cijobfailurereasonscript_failure"></a>`SCRIPT_FAILURE` | A job that failed due to script failure. |
+| <a id="cijobfailurereasonsecrets_provider_not_found"></a>`SECRETS_PROVIDER_NOT_FOUND` | A job that failed due to secrets provider not found. |
+| <a id="cijobfailurereasonstale_schedule"></a>`STALE_SCHEDULE` | A job that failed due to stale schedule. |
+| <a id="cijobfailurereasonstuck_or_timeout_failure"></a>`STUCK_OR_TIMEOUT_FAILURE` | A job that failed due to stuck or timeout failure. |
+| <a id="cijobfailurereasontrace_size_exceeded"></a>`TRACE_SIZE_EXCEEDED` | A job that failed due to trace size exceeded. |
+| <a id="cijobfailurereasonunknown_failure"></a>`UNKNOWN_FAILURE` | A job that failed due to unknown failure. |
+| <a id="cijobfailurereasonunmet_prerequisites"></a>`UNMET_PREREQUISITES` | A job that failed due to unmet prerequisites. |
+| <a id="cijobfailurereasonupstream_bridge_project_not_found"></a>`UPSTREAM_BRIDGE_PROJECT_NOT_FOUND` | A job that failed due to upstream bridge project not found. |
+| <a id="cijobfailurereasonuser_blocked"></a>`USER_BLOCKED` | A job that failed due to user blocked. |
+
### `CiJobKind`
| Value | Description |
@@ -26025,6 +27082,16 @@ Values for sorting variables.
| <a id="codequalitydegradationseverityminor"></a>`MINOR` | Code Quality degradation has a status of minor. |
| <a id="codequalitydegradationseverityunknown"></a>`UNKNOWN` | Code Quality degradation has a status of unknown. |
+### `CodequalityReportsComparerReportStatus`
+
+Report comparison status.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="codequalityreportscomparerreportstatusfailed"></a>`FAILED` | Report failed to generate. |
+| <a id="codequalityreportscomparerreportstatusnot_found"></a>`NOT_FOUND` | Head report or base report not found. |
+| <a id="codequalityreportscomparerreportstatussuccess"></a>`SUCCESS` | Report successfully generated. |
+
### `CommitActionMode`
Mode of a commit action.
@@ -26261,6 +27328,14 @@ Values for sorting tags.
| <a id="customerrelationsorganizationstateall"></a>`all` | All available organizations. |
| <a id="customerrelationsorganizationstateinactive"></a>`inactive` | Inactive organizations. |
+### `CustomizableDashboardCategory`
+
+Categories for customizable dashboards.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="customizabledashboardcategoryanalytics"></a>`ANALYTICS` | Analytics category for customizable dashboards. |
+
### `DastPreScanVerificationCheckType`
Check type of the pre scan verification step.
@@ -26620,9 +27695,18 @@ List of statuses for forecasting model.
| <a id="forecaststatusready"></a>`READY` | Forecast is ready. |
| <a id="forecaststatusunavailable"></a>`UNAVAILABLE` | Forecast is unavailable. |
+### `GeoRegistriesBulkAction`
+
+Action to trigger on multiple Geo registries.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="georegistriesbulkactionresync_all"></a>`RESYNC_ALL` | Resync multiple registries. |
+| <a id="georegistriesbulkactionreverify_all"></a>`REVERIFY_ALL` | Reverify multiple registries. |
+
### `GeoRegistryAction`
-Action to trigger on one or more Geo registries.
+Action to trigger on an individual Geo registry.
| Value | Description |
| ----- | ----------- |
@@ -26951,16 +28035,6 @@ List limit metric setting.
| <a id="listlimitmetricissue_count"></a>`issue_count` | Limit list by number of issues. |
| <a id="listlimitmetricissue_weights"></a>`issue_weights` | Limit list by total weight of issues. |
-### `MarkupFormat`
-
-List markup formats.
-
-| Value | Description |
-| ----- | ----------- |
-| <a id="markupformathtml"></a>`HTML` | HTML format. |
-| <a id="markupformatmarkdown"></a>`MARKDOWN` | Markdown format. |
-| <a id="markupformatraw"></a>`RAW` | Raw format. |
-
### `MeasurementIdentifier`
Possible identifier types for a measurement.
@@ -27216,6 +28290,23 @@ Rotation length unit of an on-call rotation.
| <a id="oncallrotationunitenumhours"></a>`HOURS` | Hours. |
| <a id="oncallrotationunitenumweeks"></a>`WEEKS` | Weeks. |
+### `OrganizationGroupSort`
+
+Values for sorting organization groups.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="organizationgroupsortcreated_at_asc"></a>`CREATED_AT_ASC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Created at in ascending order. |
+| <a id="organizationgroupsortcreated_at_desc"></a>`CREATED_AT_DESC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Created at in descending order. |
+| <a id="organizationgroupsortid_asc"></a>`ID_ASC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. ID in ascending order. |
+| <a id="organizationgroupsortid_desc"></a>`ID_DESC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. ID in descending order. |
+| <a id="organizationgroupsortname_asc"></a>`NAME_ASC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Name in ascending order. |
+| <a id="organizationgroupsortname_desc"></a>`NAME_DESC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Name in descending order. |
+| <a id="organizationgroupsortpath_asc"></a>`PATH_ASC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Path in ascending order. |
+| <a id="organizationgroupsortpath_desc"></a>`PATH_DESC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Path in descending order. |
+| <a id="organizationgroupsortupdated_at_asc"></a>`UPDATED_AT_ASC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Updated at in ascending order. |
+| <a id="organizationgroupsortupdated_at_desc"></a>`UPDATED_AT_DESC` **{warning-solid}** | **Introduced** in 16.4. This feature is an Experiment. It can be changed or removed at any time. Updated at in descending order. |
+
### `OrganizationSort`
Values for sorting organizations.
@@ -27805,14 +28896,12 @@ Name of the feature that the callout is for.
| Value | Description |
| ----- | ----------- |
| <a id="usercalloutfeaturenameenumactive_user_count_threshold"></a>`ACTIVE_USER_COUNT_THRESHOLD` | Callout feature name for active_user_count_threshold. |
-| <a id="usercalloutfeaturenameenumartifacts_management_page_feedback_banner"></a>`ARTIFACTS_MANAGEMENT_PAGE_FEEDBACK_BANNER` | Callout feature name for artifacts_management_page_feedback_banner. |
| <a id="usercalloutfeaturenameenumbranch_rules_info_callout"></a>`BRANCH_RULES_INFO_CALLOUT` | Callout feature name for branch_rules_info_callout. |
| <a id="usercalloutfeaturenameenumbuy_pipeline_minutes_notification_dot"></a>`BUY_PIPELINE_MINUTES_NOTIFICATION_DOT` | Callout feature name for buy_pipeline_minutes_notification_dot. |
| <a id="usercalloutfeaturenameenumcanary_deployment"></a>`CANARY_DEPLOYMENT` | Callout feature name for canary_deployment. |
| <a id="usercalloutfeaturenameenumci_deprecation_warning_for_types_keyword"></a>`CI_DEPRECATION_WARNING_FOR_TYPES_KEYWORD` | Callout feature name for ci_deprecation_warning_for_types_keyword. |
| <a id="usercalloutfeaturenameenumcloud_licensing_subscription_activation_banner"></a>`CLOUD_LICENSING_SUBSCRIPTION_ACTIVATION_BANNER` | Callout feature name for cloud_licensing_subscription_activation_banner. |
| <a id="usercalloutfeaturenameenumcluster_security_warning"></a>`CLUSTER_SECURITY_WARNING` | Callout feature name for cluster_security_warning. |
-| <a id="usercalloutfeaturenameenumcode_suggestions_third_party_callout"></a>`CODE_SUGGESTIONS_THIRD_PARTY_CALLOUT` | Callout feature name for code_suggestions_third_party_callout. |
| <a id="usercalloutfeaturenameenumcreate_runner_workflow_banner"></a>`CREATE_RUNNER_WORKFLOW_BANNER` | Callout feature name for create_runner_workflow_banner. |
| <a id="usercalloutfeaturenameenumeoa_bronze_plan_banner"></a>`EOA_BRONZE_PLAN_BANNER` | Callout feature name for eoa_bronze_plan_banner. |
| <a id="usercalloutfeaturenameenumfeature_flags_new_version"></a>`FEATURE_FLAGS_NEW_VERSION` | Callout feature name for feature_flags_new_version. |
@@ -27846,6 +28935,7 @@ Name of the feature that the callout is for.
| <a id="usercalloutfeaturenameenumsecurity_configuration_devops_alert"></a>`SECURITY_CONFIGURATION_DEVOPS_ALERT` | Callout feature name for security_configuration_devops_alert. |
| <a id="usercalloutfeaturenameenumsecurity_configuration_upgrade_banner"></a>`SECURITY_CONFIGURATION_UPGRADE_BANNER` | Callout feature name for security_configuration_upgrade_banner. |
| <a id="usercalloutfeaturenameenumsecurity_newsletter_callout"></a>`SECURITY_NEWSLETTER_CALLOUT` | Callout feature name for security_newsletter_callout. |
+| <a id="usercalloutfeaturenameenumsecurity_policy_protected_branch_modification"></a>`SECURITY_POLICY_PROTECTED_BRANCH_MODIFICATION` | Callout feature name for security_policy_protected_branch_modification. |
| <a id="usercalloutfeaturenameenumsecurity_training_feature_promotion"></a>`SECURITY_TRAINING_FEATURE_PROMOTION` | Callout feature name for security_training_feature_promotion. |
| <a id="usercalloutfeaturenameenumsubmit_license_usage_data_banner"></a>`SUBMIT_LICENSE_USAGE_DATA_BANNER` | Callout feature name for submit_license_usage_data_banner. |
| <a id="usercalloutfeaturenameenumsuggest_pipeline"></a>`SUGGEST_PIPELINE` | Callout feature name for suggest_pipeline. |
@@ -27860,6 +28950,7 @@ Name of the feature that the callout is for.
| <a id="usercalloutfeaturenameenumunfinished_tag_cleanup_callout"></a>`UNFINISHED_TAG_CLEANUP_CALLOUT` | Callout feature name for unfinished_tag_cleanup_callout. |
| <a id="usercalloutfeaturenameenumuser_reached_limit_free_plan_alert"></a>`USER_REACHED_LIMIT_FREE_PLAN_ALERT` | Callout feature name for user_reached_limit_free_plan_alert. |
| <a id="usercalloutfeaturenameenumverification_reminder"></a>`VERIFICATION_REMINDER` | Callout feature name for verification_reminder. |
+| <a id="usercalloutfeaturenameenumvsd_feedback_banner"></a>`VSD_FEEDBACK_BANNER` | Callout feature name for vsd_feedback_banner. |
| <a id="usercalloutfeaturenameenumweb_ide_alert_dismissed"></a>`WEB_IDE_ALERT_DISMISSED` | Callout feature name for web_ide_alert_dismissed. |
| <a id="usercalloutfeaturenameenumweb_ide_ci_environments_guidance"></a>`WEB_IDE_CI_ENVIRONMENTS_GUIDANCE` | Callout feature name for web_ide_ci_environments_guidance. |
@@ -27873,6 +28964,18 @@ Possible states of a user.
| <a id="userstateblocked"></a>`blocked` | User has been blocked and is prevented from using the system. |
| <a id="userstatedeactivated"></a>`deactivated` | User is no longer active and is unable to use the system. |
+### `ValueStreamDashboardMetric`
+
+Possible identifier types for a measurement.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="valuestreamdashboardmetricgroups"></a>`GROUPS` | Group count. |
+| <a id="valuestreamdashboardmetricissues"></a>`ISSUES` | Issue count. |
+| <a id="valuestreamdashboardmetricmerge_requests"></a>`MERGE_REQUESTS` | Merge request count. |
+| <a id="valuestreamdashboardmetricpipelines"></a>`PIPELINES` | Pipeline count. |
+| <a id="valuestreamdashboardmetricprojects"></a>`PROJECTS` | Project count. |
+
### `VerificationStateEnum`
| Value | Description |
@@ -28055,6 +29158,7 @@ Values for work item award emoji update enum.
| ----- | ----------- |
| <a id="workitemawardemojiupdateactionadd"></a>`ADD` | Adds the emoji. |
| <a id="workitemawardemojiupdateactionremove"></a>`REMOVE` | Removes the emoji. |
+| <a id="workitemawardemojiupdateactiontoggle"></a>`TOGGLE` | Toggles the status of the emoji. |
### `WorkItemRelatedLinkType`
@@ -28212,6 +29316,12 @@ A `AuditEventsInstanceExternalAuditEventDestinationID` is a global ID. It is enc
An example `AuditEventsInstanceExternalAuditEventDestinationID` is: `"gid://gitlab/AuditEvents::InstanceExternalAuditEventDestination/1"`.
+### `AuditEventsInstanceGoogleCloudLoggingConfigurationID`
+
+A `AuditEventsInstanceGoogleCloudLoggingConfigurationID` is a global ID. It is encoded as a string.
+
+An example `AuditEventsInstanceGoogleCloudLoggingConfigurationID` is: `"gid://gitlab/AuditEvents::Instance::GoogleCloudLoggingConfiguration/1"`.
+
### `AuditEventsStreamingHeaderID`
A `AuditEventsStreamingHeaderID` is a global ID. It is encoded as a string.
@@ -28653,12 +29763,6 @@ A `MergeRequestID` is a global ID. It is encoded as a string.
An example `MergeRequestID` is: `"gid://gitlab/MergeRequest/1"`.
-### `MetricsDashboardAnnotationID`
-
-A `MetricsDashboardAnnotationID` is a global ID. It is encoded as a string.
-
-An example `MetricsDashboardAnnotationID` is: `"gid://gitlab/Metrics::Dashboard::Annotation/1"`.
-
### `MilestoneID`
A `MilestoneID` is a global ID. It is encoded as a string.
@@ -28689,6 +29793,12 @@ A `NoteableID` is a global ID. It is encoded as a string.
An example `NoteableID` is: `"gid://gitlab/Noteable/1"`.
+### `OrganizationsOrganizationID`
+
+A `OrganizationsOrganizationID` is a global ID. It is encoded as a string.
+
+An example `OrganizationsOrganizationID` is: `"gid://gitlab/Organizations::Organization/1"`.
+
### `PackagesConanFileMetadatumID`
A `PackagesConanFileMetadatumID` is a global ID. It is encoded as a string.
@@ -29063,6 +30173,7 @@ Implementations:
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="baseheaderinterfaceactive"></a>`active` | [`Boolean!`](#boolean) | Header is active or not. |
| <a id="baseheaderinterfaceid"></a>`id` | [`ID!`](#id) | ID of the header. |
| <a id="baseheaderinterfacekey"></a>`key` | [`String!`](#string) | Key of the header. |
| <a id="baseheaderinterfacevalue"></a>`value` | [`String!`](#string) | Value of the header. |
@@ -29206,6 +30317,23 @@ Implementations:
| <a id="externalauditeventdestinationinterfacename"></a>`name` | [`String!`](#string) | Name of the external destination to send audit events to. |
| <a id="externalauditeventdestinationinterfaceverificationtoken"></a>`verificationToken` | [`String!`](#string) | Verification token to validate source of event. |
+#### `GoogleCloudLoggingConfigurationInterface`
+
+Implementations:
+
+- [`GoogleCloudLoggingConfigurationType`](#googlecloudloggingconfigurationtype)
+- [`InstanceGoogleCloudLoggingConfigurationType`](#instancegooglecloudloggingconfigurationtype)
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="googlecloudloggingconfigurationinterfaceclientemail"></a>`clientEmail` | [`String!`](#string) | Client email. |
+| <a id="googlecloudloggingconfigurationinterfacegoogleprojectidname"></a>`googleProjectIdName` | [`String!`](#string) | Google project ID. |
+| <a id="googlecloudloggingconfigurationinterfaceid"></a>`id` | [`ID!`](#id) | ID of the configuration. |
+| <a id="googlecloudloggingconfigurationinterfacelogidname"></a>`logIdName` | [`String!`](#string) | Log ID. |
+| <a id="googlecloudloggingconfigurationinterfacename"></a>`name` | [`String!`](#string) | Name of the external destination to send audit events to. |
+
#### `MemberInterface`
Implementations:
@@ -29273,6 +30401,7 @@ Implementations:
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="orchestrationpolicydescription"></a>`description` | [`String!`](#string) | Description of the policy. |
+| <a id="orchestrationpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
| <a id="orchestrationpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="orchestrationpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
| <a id="orchestrationpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
@@ -29372,6 +30501,7 @@ Representation of a GitLab user.
Implementations:
+- [`AddOnUser`](#addonuser)
- [`AutocompletedUser`](#autocompleteduser)
- [`MergeRequestAssignee`](#mergerequestassignee)
- [`MergeRequestAuthor`](#mergerequestauthor)
@@ -29880,7 +31010,7 @@ Attributes for defining a CI/CD variable.
| <a id="complianceframeworkinputdefault"></a>`default` | [`Boolean`](#boolean) | Set this compliance framework as the default framework for the group. |
| <a id="complianceframeworkinputdescription"></a>`description` | [`String`](#string) | New description for the compliance framework. |
| <a id="complianceframeworkinputname"></a>`name` | [`String`](#string) | New name for the compliance framework. |
-| <a id="complianceframeworkinputpipelineconfigurationfullpath"></a>`pipelineConfigurationFullPath` | [`String`](#string) | Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hipaa` **(ULTIMATE)**. |
+| <a id="complianceframeworkinputpipelineconfigurationfullpath"></a>`pipelineConfigurationFullPath` | [`String`](#string) | Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hipaa` **(ULTIMATE ALL)**. |
### `ComplianceStandardsAdherenceInput`
diff --git a/doc/api/graphql/users_example.md b/doc/api/graphql/users_example.md
index 2234528c52a..0fd61689b8e 100644
--- a/doc/api/graphql/users_example.md
+++ b/doc/api/graphql/users_example.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/group_access_tokens.md b/doc/api/group_access_tokens.md
index d8b221a8f94..b99c91d2e5c 100644
--- a/doc/api/group_access_tokens.md
+++ b/doc/api/group_access_tokens.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -143,6 +143,24 @@ POST /groups/:id/access_tokens/:token_id/rotate
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/<group_id>/access_tokens/<token_id>/rotate"
```
+Example response:
+
+```json
+{
+ "id": 42,
+ "name": "Rotated Token",
+ "revoked": false,
+ "created_at": "2023-08-01T15:00:00.000Z",
+ "scopes": ["api"],
+ "user_id": 1337,
+ "last_used_at": null,
+ "active": true,
+ "expires_at": "2023-08-15",
+ "access_level": 30,
+ "token": "s3cr3t"
+}
+```
+
### Responses
- `200: OK` if existing token is successfully revoked and the new token is created.
diff --git a/doc/api/group_badges.md b/doc/api/group_badges.md
index fc7ec51af4d..61a2ef4a89b 100644
--- a/doc/api/group_badges.md
+++ b/doc/api/group_badges.md
@@ -52,7 +52,7 @@ Example response:
"id": 1,
"link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
"image_url": "https://shields.io/my/badge",
- "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=main",
"rendered_image_url": "https://shields.io/my/badge",
"kind": "group"
}
@@ -84,7 +84,7 @@ Example response:
"id": 1,
"link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
"image_url": "https://shields.io/my/badge",
- "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=main",
"rendered_image_url": "https://shields.io/my/badge",
"kind": "group"
}
@@ -201,7 +201,7 @@ Example response:
{
"link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
"image_url": "https://shields.io/my/badge",
- "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=main",
"rendered_image_url": "https://shields.io/my/badge"
}
```
diff --git a/doc/api/group_boards.md b/doc/api/group_boards.md
index 267b9feb750..5a7b67b562c 100644
--- a/doc/api/group_boards.md
+++ b/doc/api/group_boards.md
@@ -296,10 +296,10 @@ PUT /groups/:id/boards/:board_id
| `name` | string | no | The new name of the board |
| `hide_backlog_list` | boolean | no | Hide the Open list |
| `hide_closed_list` | boolean | no | Hide the Closed list |
-| `assignee_id` **(PREMIUM)** | integer | no | The assignee the board should be scoped to |
-| `milestone_id` **(PREMIUM)** | integer | no | The milestone the board should be scoped to |
-| `labels` **(PREMIUM)** | string | no | Comma-separated list of label names which the board should be scoped to |
-| `weight` **(PREMIUM)** | integer | no | The weight range from 0 to 9, to which the board should be scoped to |
+| `assignee_id` **(PREMIUM ALL)** | integer | no | The assignee the board should be scoped to |
+| `milestone_id` **(PREMIUM ALL)** | integer | no | The milestone the board should be scoped to |
+| `labels` **(PREMIUM ALL)** | string | no | Comma-separated list of label names which the board should be scoped to |
+| `weight` **(PREMIUM ALL)** | integer | no | The weight range from 0 to 9, to which the board should be scoped to |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/boards/1?name=new_name&milestone_id=44&assignee_id=1&labels=GroupLabel&weight=4"
diff --git a/doc/api/group_clusters.md b/doc/api/group_clusters.md
index 912d5e197c6..c32a14ee21e 100644
--- a/doc/api/group_clusters.md
+++ b/doc/api/group_clusters.md
@@ -179,7 +179,7 @@ Parameters:
| `platform_kubernetes_attributes[token]` | string | yes | The token to authenticate against Kubernetes |
| `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate. Required if API is using a self-signed TLS certificate. |
| `platform_kubernetes_attributes[authorization_type]` | string | no | The cluster authorization type: `rbac`, `abac` or `unknown_authorization`. Defaults to `rbac`. |
-| `environment_scope` | string | no | The associated environment to the cluster. Defaults to `*` **(PREMIUM)** |
+| `environment_scope` | string | no | The associated environment to the cluster. Defaults to `*` **(PREMIUM ALL)** |
Example request:
@@ -250,7 +250,7 @@ Parameters:
| `platform_kubernetes_attributes[api_url]` | string | no | The URL to access the Kubernetes API |
| `platform_kubernetes_attributes[token]` | string | no | The token to authenticate against Kubernetes |
| `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate. Required if API is using a self-signed TLS certificate. |
-| `environment_scope` | string | no | The associated environment to the cluster **(PREMIUM)** |
+| `environment_scope` | string | no | The associated environment to the cluster **(PREMIUM ALL)** |
NOTE:
`name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added
diff --git a/doc/api/group_import_export.md b/doc/api/group_import_export.md
index e95f4b307c8..e431d3c47d8 100644
--- a/doc/api/group_import_export.md
+++ b/doc/api/group_import_export.md
@@ -93,7 +93,7 @@ returns either:
The maximum import file size can be set by the Administrator on self-managed instances (default is `0` (unlimited)).
As an administrator, you can modify the maximum import file size either:
-- In the [Admin Area](../administration/settings/account_and_limit_settings.md).
+- In the [Admin Area](../administration/settings/import_and_export_settings.md).
- By using the `max_import_size` option in the [Application settings API](settings.md#change-application-settings).
For information on the maximum import file size on GitLab.com, see
diff --git a/doc/api/group_level_variables.md b/doc/api/group_level_variables.md
index 8aebbff1814..ef373e5b7fa 100644
--- a/doc/api/group_level_variables.md
+++ b/doc/api/group_level_variables.md
@@ -94,7 +94,7 @@ POST /groups/:id/variables
| `protected` | boolean | No | Whether the variable is protected |
| `masked` | boolean | No | Whether the variable is masked |
| `raw` | boolean | No | Whether the variable is treated as a raw string. Default: `false`. When `true`, variables in the value are not [expanded](../ci/variables/index.md#prevent-cicd-variable-expansion). |
-| `environment_scope` **(PREMIUM)** | string | No | The [environment scope](../ci/environments/index.md#limit-the-environment-scope-of-a-cicd-variable) of a variable |
+| `environment_scope` **(PREMIUM ALL)** | string | No | The [environment scope](../ci/environments/index.md#limit-the-environment-scope-of-a-cicd-variable) of a variable |
| `description` | string | No | The `description` of the variable. Default: `null` |
```shell
@@ -132,7 +132,7 @@ PUT /groups/:id/variables/:key
| `protected` | boolean | No | Whether the variable is protected |
| `masked` | boolean | No | Whether the variable is masked |
| `raw` | boolean | No | Whether the variable is treated as a raw string. Default: `false`. When `true`, variables in the value are not [expanded](../ci/variables/index.md#prevent-cicd-variable-expansion). |
-| `environment_scope` **(PREMIUM)** | string | No | The [environment scope](../ci/environments/index.md#limit-the-environment-scope-of-a-cicd-variable) of a variable |
+| `environment_scope` **(PREMIUM ALL)** | string | No | The [environment scope](../ci/environments/index.md#limit-the-environment-scope-of-a-cicd-variable) of a variable |
| `description` | string | No | The description of the variable. Default: `null`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/409641) in GitLab 16.2. |
```shell
diff --git a/doc/api/group_protected_branches.md b/doc/api/group_protected_branches.md
index c017d0741ce..10b7ff92e9c 100644
--- a/doc/api/group_protected_branches.md
+++ b/doc/api/group_protected_branches.md
@@ -49,7 +49,7 @@ Example response:
[
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 1,
@@ -114,7 +114,7 @@ GET /groups/:id/protected_branches/:name
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" \
- "https://gitlab.example.com/api/v4/groups/5/protected_branches/master"
+ "https://gitlab.example.com/api/v4/groups/5/protected_branches/main"
```
Example response:
@@ -122,7 +122,7 @@ Example response:
```json
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 1,
@@ -270,7 +270,7 @@ curl --request POST \
--header "PRIVATE-TOKEN: <your_access_token>" \
--header "Content-Type: application/json" \
--data '{
- "name": "master",
+ "name": "main",
"allowed_to_push": [{"access_level": 30}],
"allowed_to_merge": [{
"access_level": 30
@@ -286,7 +286,7 @@ Example response:
```json
{
"id": 5,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 1,
@@ -348,7 +348,7 @@ Example response:
```json
{
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 12,
@@ -406,14 +406,14 @@ To delete:
curl --header 'Content-Type: application/json' --request PATCH \
--data '{"allowed_to_push": [{access_level: 40}]}' \
--header "PRIVATE-TOKEN: <your_access_token>" \
- "https://gitlab.example.com/api/v4/groups/22034114/protected_branches/master"
+ "https://gitlab.example.com/api/v4/groups/22034114/protected_branches/main"
```
Example response:
```json
{
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 12,
@@ -431,14 +431,14 @@ Example response:
```shell
curl --header 'Content-Type: application/json' --request PATCH \
--data '{"allowed_to_push": [{"id": 12, "access_level": 0}]' \
- --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/22034114/protected_branches/master"
+ --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/22034114/protected_branches/main"
```
Example response:
```json
{
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 12,
@@ -456,14 +456,14 @@ Example response:
```shell
curl --header 'Content-Type: application/json' --request PATCH \
--data '{"allowed_to_push": [{"id": 12, "_destroy": true}]}' \
- --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/22034114/protected_branches/master"
+ --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/22034114/protected_branches/main"
```
Example response:
```json
{
- "name": "master",
+ "name": "main",
"push_access_levels": []
}
```
diff --git a/doc/api/group_ssh_certificates.md b/doc/api/group_ssh_certificates.md
new file mode 100644
index 00000000000..d6dc17a5c15
--- /dev/null
+++ b/doc/api/group_ssh_certificates.md
@@ -0,0 +1,115 @@
+---
+stage: Create
+group: Source Code
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Group SSH certificates API **(PREMIUM ALL)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/421915) in GitLab 16.4 [with a flag](../user/feature_flags.md) named `ssh_certificates_rest_endpoints`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../administration/feature_flags.md) named `ssh_certificates_rest_endpoints`.
+On GitLab.com, this feature is not available.
+
+Use this API to create, read and delete SSH certificates for a group.
+Only top-level groups can store SSH certificates.
+To use this API you must [authenticate yourself](rest/index.md#authentication) as an Administrator.
+
+## Get all SSH certificates for a particular group
+
+```plaintext
+GET groups/:id/ssh_certificates
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| ---------- | ------ | -------- |----------------------|
+| `id` | integer | Yes | The ID of the group. |
+
+By default, `GET` requests return 20 results at a time because the API results are paginated.
+Read more on [pagination](rest/index.md#pagination).
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://primary.example.com/api/v4/groups/90/ssh_certificates"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 12345,
+ "title": "SSH Title 1",
+ "key": "ssh-rsa AAAAB3NzaC1ea2dAAAADAQABAAAAgQDGbLkF44ScxRQi2FfA7VsHgGqptguSbmW26jkJhEiRZpGS4/+UzaaSqc8Psw2OhSsKc5QwfrB/ANpO4LhOjDzhf2FuD8ACkv3R7XtaJ+rN6PlyzoBfLAiSyzxhEoMFDBprTgaiZKgg2yQ9dRH55w3f6XMZ4hnaUae53nQgfQLxFw== example@gitlab.com",
+ "created_at": "2023-09-08T12:39:00.172Z"
+ },
+ {
+ "id":12346,
+ "title":"SSH Title 2",
+ "key": "ssh-rsa AAAAB3NzaC1ac2EAAAADAQABAAAAgQDTl/hHfu1F/KlR+QfgM2wUmyxcN5YeiaWluEGIrfXUeJuI+bK6xjpE3+2afHDYtE9VQkeL32KRjefX2d72Jeoa68ewt87Vn8CcGkUTOTpHNzeL8pHMKFs3m7ArSBxNg5vTdgAsq5dbDGNtat7b2WCHTNvtWoON1Jetne30uW2EwQ== example@gitlab.com",
+ "created_at": "2023-09-08T12:39:00.244Z"
+ }
+]
+```
+
+## Create SSH Certificate
+
+Create a new SSH certificate in the group.
+
+```plaintext
+POST /groups/:id/ssh_certificates
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+|-----------|------------| -------- |---------------------------------------|
+| `id` | integer | Yes | The ID of the group. |
+| `key` | string | Yes | The public key of the SSH certificate.|
+| `title` | string | Yes | The title of the SSH certificate. |
+
+Example request:
+
+```shell
+curl --request POST \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --url "https://gitlab.example.com/api/v4/groups/5/ssh_certificates?title=newtitle&key=ssh-rsa+REDACTED+example%40gitlab.com"
+```
+
+Example response:
+
+```json
+{
+ "id": 54321,
+ "title": "newtitle",
+ "key": "ssh-rsa ssh-rsa AAAAB3NzaC1ea2dAAAADAQABAAAAgQDGbLkF44ScxRQi2FfA7VsHgGqptguSbmW26jkJhEiRZpGS4/+UzaaSqc8Psw2OhSsKc5QwfrB/ANpO4LhOjDzhf2FuD8ACkv3R7XtaJ+rN6PlyzoBfLAiSyzxhEoMFDBprTgaiZKgg2yQ9dRH55w3f6XMZ4hnaUae53nQgfQLxFw== example@gitlab.com",
+ "created_at": "2023-09-08T12:39:00.172Z"
+}
+```
+
+## Delete group SSH certificate
+
+Delete a SSH certificate from a group.
+
+```plaintext
+DELETE /groups/:id/ssh_certificate/:id
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+|-----------|---------| -------- |-------------------------------|
+| `id` | integer | Yes | The ID of the group |
+| `id` | integer | Yes | The ID of the SSH certificate |
+
+Example request:
+
+```shell
+curl --request DELETE \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --url "https://gitlab.example.com/api/v4/groups/5/ssh_certificates/12345"
+```
diff --git a/doc/api/group_wikis.md b/doc/api/group_wikis.md
index 7396758ac40..2d758779f79 100644
--- a/doc/api/group_wikis.md
+++ b/doc/api/group_wikis.md
@@ -207,7 +207,7 @@ Example response:
{
"file_name" : "dk.png",
"file_path" : "uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png",
- "branch" : "master",
+ "branch" : "main",
"link" : {
"url" : "uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png",
"markdown" : "![dk](uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png)"
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 930a682c157..9ea37f4bb7c 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -38,7 +38,7 @@ Parameters:
| `owned` | boolean | no | Limit to groups explicitly owned by the current user |
| `min_access_level` | integer | no | Limit to groups where current user has at least this [role (`access_level`)](members.md#roles) |
| `top_level_only` | boolean | no | Limit to top level groups, excluding all subgroups |
-| `repository_storage` **(PREMIUM)** | string | no | Filter by repository storage used by the group _(administrators only)_. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419643) in GitLab 16.3 |
+| `repository_storage` **(PREMIUM ALL)** | string | no | Filter by repository storage used by the group _(administrators only)_. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419643) in GitLab 16.3 |
```plaintext
GET /groups
@@ -314,7 +314,7 @@ Parameters:
| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` |
| `min_access_level` | integer | no | Limit to projects where current user has at least this [role (`access_level`)](members.md#roles) |
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (administrators only) |
-| `with_security_reports` **(ULTIMATE)** | boolean | no | Return only projects that have security reports artifacts present in any of their builds. This means "projects with security reports enabled". Default is `false` |
+| `with_security_reports` **(ULTIMATE ALL)** | boolean | no | Return only projects that have security reports artifacts present in any of their builds. This means "projects with security reports enabled". Default is `false` |
1. Order by similarity: Orders the results by a similarity score calculated from the provided `search`
URL parameter. When using `order_by=similarity`, the `sort` parameter is ignored. When the `search`
@@ -327,7 +327,7 @@ Example response:
{
"id": 9,
"description": "foo",
- "default_branch": "master",
+ "default_branch": "main",
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"archived": false,
@@ -407,13 +407,13 @@ Example response:
"path":"html5-boilerplate",
"path_with_namespace":"h5bp/html5-boilerplate",
"created_at":"2020-04-27T06:13:22.642Z",
- "default_branch":"master",
+ "default_branch":"main",
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo":"ssh://git@gitlab.com/h5bp/html5-boilerplate.git",
"http_url_to_repo":"https://gitlab.com/h5bp/html5-boilerplate.git",
"web_url":"https://gitlab.com/h5bp/html5-boilerplate",
- "readme_url":"https://gitlab.com/h5bp/html5-boilerplate/-/blob/master/README.md",
+ "readme_url":"https://gitlab.com/h5bp/html5-boilerplate/-/blob/main/README.md",
"avatar_url":null,
"star_count":0,
"forks_count":4,
@@ -573,7 +573,7 @@ Example response:
{
"id": 7,
"description": "Voluptas veniam qui et beatae voluptas doloremque explicabo facilis.",
- "default_branch": "master",
+ "default_branch": "main",
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"archived": false,
@@ -612,7 +612,7 @@ Example response:
{
"id": 6,
"description": "Aspernatur omnis repudiandae qui voluptatibus eaque.",
- "default_branch": "master",
+ "default_branch": "main",
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"archived": false,
@@ -653,7 +653,7 @@ Example response:
{
"id": 8,
"description": "Velit eveniet provident fugiat saepe eligendi autem.",
- "default_branch": "master",
+ "default_branch": "main",
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"archived": false,
@@ -829,10 +829,10 @@ Parameters:
| `subgroup_creation_level` | string | no | Allowed to [create subgroups](../user/group/subgroups/index.md#create-a-subgroup). Can be `owner` (Owners), or `maintainer` (users with the Maintainer role). |
| `two_factor_grace_period` | integer | no | Time before Two-factor authentication is enforced (in hours). |
| `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. |
-| `membership_lock` **(PREMIUM)** | boolean | no | Users cannot be added to projects in this group. |
+| `membership_lock` **(PREMIUM ALL)** | boolean | no | Users cannot be added to projects in this group. |
| `extra_shared_runners_minutes_limit` **(PREMIUM SELF)** | integer | no | Can be set by administrators only. Additional compute minutes for this group. |
| `shared_runners_minutes_limit` **(PREMIUM SELF)** | integer | no | Can be set by administrators only. Maximum number of monthly compute minutes for this group. Can be `nil` (default; inherit system default), `0` (unlimited), or `> 0`. |
-| `wiki_access_level` **(PREMIUM)** | string | no | The wiki access level. Can be `disabled`, `private`, or `enabled`. |
+| `wiki_access_level` **(PREMIUM ALL)** | string | no | The wiki access level. Can be `disabled`, `private`, or `enabled`. |
### Options for `default_branch_protection`
@@ -893,8 +893,8 @@ GET /groups/:id/transfer_locations
| Attribute | Type | Required | Description |
|-------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the group to be transferred](rest/index.md#namespaced-path-encoding). |
-| `search` | string | **{dotted-circle}** No | The group names to search for. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the group to be transferred](rest/index.md#namespaced-path-encoding). |
+| `search` | string | No | The group names to search for. |
Example request:
@@ -988,17 +988,17 @@ PUT /groups/:id
| `two_factor_grace_period` | integer | no | Time before Two-factor authentication is enforced (in hours). |
| `visibility` | string | no | The visibility level of the group. Can be `private`, `internal`, or `public`. |
| `extra_shared_runners_minutes_limit` **(PREMIUM SELF)** | integer | no | Can be set by administrators only. Additional compute minutes for this group. |
-| `file_template_project_id` **(PREMIUM)** | integer | no | The ID of a project to load custom file templates from. |
-| `membership_lock` **(PREMIUM)** | boolean | no | Users cannot be added to projects in this group. |
-| `prevent_forking_outside_group` **(PREMIUM)** | boolean | no | When enabled, users can **not** fork projects from this group to external namespaces. |
+| `file_template_project_id` **(PREMIUM ALL)** | integer | no | The ID of a project to load custom file templates from. |
+| `membership_lock` **(PREMIUM ALL)** | boolean | no | Users cannot be added to projects in this group. |
+| `prevent_forking_outside_group` **(PREMIUM ALL)** | boolean | no | When enabled, users can **not** fork projects from this group to external namespaces. |
| `shared_runners_minutes_limit` **(PREMIUM SELF)** | integer | no | Can be set by administrators only. Maximum number of monthly compute minutes for this group. Can be `nil` (default; inherit system default), `0` (unlimited), or `> 0`. |
-| `unique_project_download_limit` **(ULTIMATE)** | integer | no | Maximum number of unique projects a user can download in the specified time period before they are banned. Available only on top-level groups. Default: 0, Maximum: 10,000. |
-| `unique_project_download_limit_interval_in_seconds` **(ULTIMATE)** | integer | no | Time period during which a user can download a maximum amount of projects before they are banned. Available only on top-level groups. Default: 0, Maximum: 864,000 seconds (10 days). |
-| `unique_project_download_limit_allowlist` **(ULTIMATE)** | array of strings | no | List of usernames excluded from the unique project download limit. Available only on top-level groups. Default: `[]`, Maximum: 100 usernames. |
-| `unique_project_download_limit_alertlist` **(ULTIMATE)** | array of integers | no | List of user IDs that are emailed when the unique project download limit is exceeded. Available only on top-level groups. Default: `[]`, Maximum: 100 user IDs. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110201) in GitLab 15.9. |
-| `auto_ban_user_on_excessive_projects_download` **(ULTIMATE)** | boolean | no | When enabled, users are automatically banned from the group when they download more than the maximum number of unique projects specified by `unique_project_download_limit` and `unique_project_download_limit_interval_in_seconds`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94159) in GitLab 15.4. |
-| `ip_restriction_ranges` **(PREMIUM)** | string | no | Comma-separated list of IP addresses or subnet masks to restrict group access. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/351493) in GitLab 15.4. |
-| `wiki_access_level` **(PREMIUM)** | string | no | The wiki access level. Can be `disabled`, `private`, or `enabled`. |
+| `unique_project_download_limit` **(ULTIMATE ALL)** | integer | no | Maximum number of unique projects a user can download in the specified time period before they are banned. Available only on top-level groups. Default: 0, Maximum: 10,000. |
+| `unique_project_download_limit_interval_in_seconds` **(ULTIMATE ALL)** | integer | no | Time period during which a user can download a maximum amount of projects before they are banned. Available only on top-level groups. Default: 0, Maximum: 864,000 seconds (10 days). |
+| `unique_project_download_limit_allowlist` **(ULTIMATE ALL)** | array of strings | no | List of usernames excluded from the unique project download limit. Available only on top-level groups. Default: `[]`, Maximum: 100 usernames. |
+| `unique_project_download_limit_alertlist` **(ULTIMATE ALL)** | array of integers | no | List of user IDs that are emailed when the unique project download limit is exceeded. Available only on top-level groups. Default: `[]`, Maximum: 100 user IDs. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110201) in GitLab 15.9. |
+| `auto_ban_user_on_excessive_projects_download` **(ULTIMATE ALL)** | boolean | no | When enabled, users are automatically banned from the group when they download more than the maximum number of unique projects specified by `unique_project_download_limit` and `unique_project_download_limit_interval_in_seconds`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94159) in GitLab 15.4. |
+| `ip_restriction_ranges` **(PREMIUM ALL)** | string | no | Comma-separated list of IP addresses or subnet masks to restrict group access. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/351493) in GitLab 15.4. |
+| `wiki_access_level` **(PREMIUM ALL)** | string | no | The wiki access level. Can be `disabled`, `private`, or `enabled`. |
NOTE:
The `projects` and `shared_projects` attributes in the response are deprecated and [scheduled for removal in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797).
@@ -1039,7 +1039,7 @@ Example response:
{
"id": 9,
"description": "foo",
- "default_branch": "master",
+ "default_branch": "main",
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"public": false,
@@ -1161,8 +1161,8 @@ Parameters:
| Attribute | Type | Required | Description |
|----------------------|------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) |
-| `permanently_remove` **(PREMIUM)** | boolean/string | no | Immediately deletes a subgroup if it is marked for deletion. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368276) in GitLab 15.4 |
-| `full_path` **(PREMIUM)** | string | no | Full path of subgroup to use with `permanently_remove`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368276) in GitLab 15.4. To find the subgroup path, see the [group details](groups.md#details-of-a-group) |
+| `permanently_remove` **(PREMIUM ALL)** | boolean/string | no | Immediately deletes a subgroup if it is marked for deletion. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368276) in GitLab 15.4 |
+| `full_path` **(PREMIUM ALL)** | string | no | Full path of subgroup to use with `permanently_remove`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368276) in GitLab 15.4. To find the subgroup path, see the [group details](groups.md#details-of-a-group) |
The response is `202 Accepted` if the user has authorization.
diff --git a/doc/api/index.md b/doc/api/index.md
index 7cb25c4ce17..8837c8a6016 100644
--- a/doc/api/index.md
+++ b/doc/api/index.md
@@ -6,13 +6,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Develop with GitLab **(FREE ALL)**
-Automate and interact with GitLab, and integrate with external applications.
+Automate with GitLab and integrate with external applications.
- [Integrations](../integration/index.md)
- [Webhooks](../user/project/integrations/webhooks.md)
- [REST API](rest/index.md)
- [GraphQL API](graphql/index.md)
- [OAuth 2.0 identity provider API](oauth2.md)
-- [GitLab CLI (glab)](../integration/glab/index.md)
-- [Visual Studio Code extension](../user/project/repository/vscode.md)
-- [Code Suggestions](../user/project/repository/code_suggestions.md)
+- [Editor and IDE extensions](../editor_extensions/index.md)
+- [Code Suggestions](../user/project/repository/code_suggestions/index.md)
diff --git a/doc/api/integrations.md b/doc/api/integrations.md
index 530506c9bed..f8bfa1279d4 100644
--- a/doc/api/integrations.md
+++ b/doc/api/integrations.md
@@ -17,9 +17,9 @@ This API requires an access token with the Maintainer or Owner role.
## List all active integrations
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21330) in GitLab 12.7.
+> `vulnerability_events` field [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131831) in GitLab 16.5.
-Get a list of all active project integrations.
+Get a list of all active project integrations. The `vulnerability_events` field is only available for GitLab Enterprise Edition.
```plaintext
GET /projects/:id/integrations
@@ -49,7 +49,8 @@ Example response:
"pipeline_events": true,
"wiki_page_events": true,
"job_events": true,
- "comment_on_event_enabled": true
+ "comment_on_event_enabled": true,
+ "vulnerability_events": true
},
{
"id": 76,
@@ -71,7 +72,8 @@ Example response:
"pipeline_events": true,
"wiki_page_events": true,
"job_events": true,
- "comment_on_event_enabled": true
+ "comment_on_event_enabled": true,
+ "vulnerability_events": true
}
]
```
@@ -434,6 +436,7 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `token` | string | true | The Telegram bot token. For example, `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`. |
| `room` | string | true | Unique identifier for the target chat or the username of the target channel (in the format `@channelusername`) |
+| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines |
| `push_events` | boolean | true | Enable notifications for push events |
| `issues_events` | boolean | true | Enable notifications for issue events |
| `confidential_issues_events` | boolean | true | Enable notifications for confidential issue events |
diff --git a/doc/api/issue_links.md b/doc/api/issue_links.md
index a7cacd64cbb..653f21e2f0b 100644
--- a/doc/api/issue_links.md
+++ b/doc/api/issue_links.md
@@ -77,9 +77,9 @@ Supported attributes:
| Attribute | Type | Required | Description |
|-----------------|----------------|------------------------|-----------------------------------------------------------------------------|
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `issue_iid` | integer | **{check-circle}** Yes | Internal ID of a project's issue. |
-| `issue_link_id` | integer/string | **{check-circle}** Yes | ID of an issue relationship. |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `issue_iid` | integer | Yes | Internal ID of a project's issue. |
+| `issue_link_id` | integer/string | Yes | ID of an issue relationship. |
Response body attributes:
diff --git a/doc/api/issues.md b/doc/api/issues.md
index f318515e0a6..07678f3ca42 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -64,13 +64,13 @@ GET /issues?state=opened
| `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `created_before` | datetime | no | Return issues created on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `any`, `today`, `tomorrow`, `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. |
-| `epic_id` **(PREMIUM)** | integer | no | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46887) in GitLab 13.6)_
-| `health_status` **(ULTIMATE)** | string | no | Return issues with the specified `health_status`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/370721) in GitLab 15.4)._ In [GitLab 15.5 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/370721), `None` returns issues with no health status assigned, and `Any` returns issues with a health status assigned.
+| `epic_id` **(PREMIUM ALL)** | integer | no | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46887) in GitLab 13.6)_
+| `health_status` **(ULTIMATE ALL)** | string | no | Return issues with the specified `health_status`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/370721) in GitLab 15.4)._ In [GitLab 15.5 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/370721), `None` returns issues with no health status assigned, and `Any` returns issues with a health status assigned.
| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description` |
| `issue_type` | string | no | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/260375) in GitLab 13.12)_ |
-| `iteration_id` **(PREMIUM)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
-| `iteration_title` **(PREMIUM)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
+| `iteration_id` **(PREMIUM ALL)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
+| `iteration_title` **(PREMIUM ALL)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. Using `None` or `Any` will be [deprecated in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/336044). Please use `milestone_id` attribute instead. `milestone` and `milestone_id` are mutually exclusive. |
| `milestone_id` | string | no | Returns issues assigned to milestones with a given timebox value (`None`, `Any`, `Upcoming`, and `Started`). `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. `Upcoming` lists all issues assigned to milestones due in the future. `Started` lists all issues assigned to open, started milestones. `milestone` and `milestone_id` are mutually exclusive. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335939) in GitLab 14.3)_ |
@@ -84,7 +84,7 @@ GET /issues?state=opened
| `state` | string | no | Return `all` issues or just those that are `opened` or `closed` |
| `updated_after` | datetime | no | Return issues updated on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `updated_before` | datetime | no | Return issues updated on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
-| `weight` **(PREMIUM)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
+| `weight` **(PREMIUM ALL)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
| `with_labels_details` | boolean | no | If `true`, the response returns more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. The `description_html` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) in GitLab 12.7|
```shell
@@ -294,12 +294,12 @@ GET /groups/:id/issues?state=opened
| `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `created_before` | datetime | no | Return issues created on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `any`, `today`, `tomorrow`, `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. |
-| `epic_id` **(PREMIUM)** | integer | no | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46887) in GitLab 13.6)_
+| `epic_id` **(PREMIUM ALL)** | integer | no | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46887) in GitLab 13.6)_
| `id` | integer/string | yes | The global ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `issue_type` | string | no | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/260375) in GitLab 13.12)_ |
-| `iteration_id` **(PREMIUM)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
-| `iteration_title` **(PREMIUM)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
+| `iteration_id` **(PREMIUM ALL)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
+| `iteration_title` **(PREMIUM ALL)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
@@ -312,7 +312,7 @@ GET /groups/:id/issues?state=opened
| `state` | string | no | Return all issues or just those that are `opened` or `closed` |
| `updated_after` | datetime | no | Return issues updated on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `updated_before` | datetime | no | Return issues updated on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
-| `weight` **(PREMIUM)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
+| `weight` **(PREMIUM ALL)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
| `with_labels_details` | boolean | no | If `true`, the response returns more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. The `description_html` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) in GitLab 12.7 |
```shell
@@ -498,12 +498,12 @@ GET /projects/:id/issues?state=opened
| `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `created_before` | datetime | no | Return issues created on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `due_date` | string | no | Return issues that have no due date, are overdue, or whose due date is this week, this month, or between two weeks ago and next month. Accepts: `0` (no due date), `any`, `today`, `tomorrow`, `overdue`, `week`, `month`, `next_month_and_previous_two_weeks`. |
-| `epic_id` **(PREMIUM)** | integer | no | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46887) in GitLab 13.6)_
+| `epic_id` **(PREMIUM ALL)** | integer | no | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46887) in GitLab 13.6)_
| `id` | integer/string | yes | The global ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `issue_type` | string | no | Filter to a given type of issue. One of `issue`, `incident`, or `test_case`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/260375) in GitLab 13.12)_ |
-| `iteration_id` **(PREMIUM)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
-| `iteration_title` **(PREMIUM)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
+| `iteration_id` **(PREMIUM ALL)** | integer | no | Return issues assigned to the given iteration ID. `None` returns issues that do not belong to an iteration. `Any` returns issues that belong to an iteration. Mutually exclusive with `iteration_title`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
+| `iteration_title` **(PREMIUM ALL)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
@@ -515,7 +515,7 @@ GET /projects/:id/issues?state=opened
| `state` | string | no | Return all issues or just those that are `opened` or `closed` |
| `updated_after` | datetime | no | Return issues updated on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `updated_before` | datetime | no | Return issues updated on or before the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
-| `weight` **(PREMIUM)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
+| `weight` **(PREMIUM ALL)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
| `with_labels_details` | boolean | no | If `true`, the response returns more details for each label in labels field: `:name`, `:color`, `:description`, `:description_html`, `:text_color`. Default is `false`. `description_html` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21413) in GitLab 12.7 |
```shell
@@ -1004,14 +1004,14 @@ POST /projects/:id/issues
| Attribute | Type | Required | Description |
|-------------------------------------------|----------------|----------|--------------|
| `assignee_id` | integer | no | The ID of the user to assign the issue to. Only appears on GitLab Free. |
-| `assignee_ids` **(PREMIUM)** | integer array | no | The IDs of the users to assign the issue to. |
+| `assignee_ids` **(PREMIUM ALL)** | integer array | no | The IDs of the users to assign the issue to. |
| `confidential` | boolean | no | Set an issue to be confidential. Default is `false`. |
| `created_at` | string | no | When the issue was created. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z`. Requires administrator or project/group owner rights. |
| `description` | string | no | The description of an issue. Limited to 1,048,576 characters. |
| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This fills out the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
| `due_date` | string | no | The due date. Date time string in the format `YYYY-MM-DD`, for example `2016-03-11` |
-| `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
-| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5) |
+| `epic_id` **(PREMIUM ALL)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
+| `epic_iid` **(PREMIUM ALL)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5) |
| `id` | integer/string | yes | The global ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `iid` | integer/string | no | The internal ID of the project's issue (requires administrator or project owner rights) |
| `issue_type` | string | no | The type of issue. One of `issue`, `incident`, or `test_case`. Default is `issue`. |
@@ -1019,7 +1019,7 @@ POST /projects/:id/issues
| `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This fills out the issue with a default description and mark all discussions as resolved. When passing a description or title, these values take precedence over the default values.|
| `milestone_id` | integer | no | The global ID of a milestone to assign issue. To find the `milestone_id` associated with a milestone, view an issue with the milestone assigned and [use the API](#single-project-issue) to retrieve the issue's details. |
| `title` | string | yes | The title of an issue |
-| `weight` **(PREMIUM)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. |
+| `weight` **(PREMIUM ALL)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues?title=Issues%20with%20auth&labels=bug"
@@ -1178,8 +1178,8 @@ PUT /projects/:id/issues/:issue_iid
| `description` | string | no | The description of an issue. Limited to 1,048,576 characters. |
| `discussion_locked` | boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. |
| `due_date` | string | no | The due date. Date time string in the format `YYYY-MM-DD`, for example `2016-03-11` |
-| `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
-| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5) |
+| `epic_id` **(PREMIUM ALL)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
+| `epic_iid` **(PREMIUM ALL)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5) |
| `id` | integer/string | yes | The global ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `issue_type` | string | no | Updates the type of issue. One of `issue`, `incident`, or `test_case`. |
@@ -1189,7 +1189,7 @@ PUT /projects/:id/issues/:issue_iid
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
| `title` | string | no | The title of an issue |
| `updated_at` | string | no | When the issue was updated. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` (requires administrator or project owner rights). Empty string or null values are not accepted.|
-| `weight` **(PREMIUM)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. 0 |
+| `weight` **(PREMIUM ALL)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. 0 |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues/85?state_event=close"
@@ -1515,10 +1515,10 @@ POST /projects/:id/issues/:issue_iid/clone
| Attribute | Type | Required | Description |
| --------------- | -------------- | ---------------------- | --------------------------------- |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `issue_iid` | integer | **{check-circle}** Yes | Internal ID of a project's issue. |
-| `to_project_id` | integer | **{check-circle}** Yes | ID of the new project. |
-| `with_notes` | boolean | **{dotted-circle}** No | Clone the issue with [notes](notes.md). Default is `false`. |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `issue_iid` | integer | Yes | Internal ID of a project's issue. |
+| `to_project_id` | integer | Yes | ID of the new project. |
+| `with_notes` | boolean | No | Clone the issue with [notes](notes.md). Default is `false`. |
```shell
curl --request POST \
@@ -2337,7 +2337,7 @@ Example response:
"state": "opened",
"created_at": "2017-04-06T18:33:34.168Z",
"updated_at": "2017-04-09T20:10:24.983Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "feature.custom-highlighting",
"upvotes": 0,
"downvotes": 0,
diff --git a/doc/api/issues_statistics.md b/doc/api/issues_statistics.md
index d2148b001cb..2c3383aa328 100644
--- a/doc/api/issues_statistics.md
+++ b/doc/api/issues_statistics.md
@@ -41,7 +41,7 @@ GET /issues_statistics?confidential=true
| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. |
| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE `assignee_username` array should only contain a single value or an invalid parameter error is returned otherwise. |
-| `epic_id` **(PREMIUM)** | integer | no | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46887) in GitLab 13.6)_
+| `epic_id` **(PREMIUM ALL)** | integer | no | Return issues associated with the given epic ID. `None` returns issues that are not associated with an epic. `Any` returns issues that are associated with an epic. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46887) in GitLab 13.6)_
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `search` | string | no | Search issues against their `title` and `description` |
diff --git a/doc/api/job_artifacts.md b/doc/api/job_artifacts.md
index 5a3861f888e..a65de457581 100644
--- a/doc/api/job_artifacts.md
+++ b/doc/api/job_artifacts.md
@@ -12,6 +12,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Get the job's artifacts zipped archive of a project.
+If you use cURL to download artifacts from GitLab.com, use the `--location` parameter
+as the request might redirect through a CND.
+
```plaintext
GET /projects/:id/jobs/:job_id/artifacts
```
@@ -20,16 +23,16 @@ GET /projects/:id/jobs/:job_id/artifacts
|---------------------------|----------------|----------|-------------|
| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
| `job_id` | integer | Yes | ID of a job. |
-| `job_token` **(PREMIUM)** | string | No | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
+| `job_token` **(PREMIUM ALL)** | string | No | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
Example request using the `PRIVATE-TOKEN` header:
```shell
-curl --location --output artifacts.zip --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/42/artifacts"
+curl --location --output artifacts.zip --location --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/42/artifacts"
```
To use this in a [`script` definition](../ci/yaml/index.md#script) inside
-`.gitlab-ci.yml` **(PREMIUM)**, you can use either:
+`.gitlab-ci.yml` **(PREMIUM ALL)**, you can use either:
- The `JOB-TOKEN` header with the GitLab-provided `CI_JOB_TOKEN` variable.
For example, the following job downloads the artifacts of the job with ID
@@ -69,6 +72,9 @@ the given reference name and job, provided the job finished successfully. This
is the same as [getting the job's artifacts](#get-job-artifacts), but by
defining the job's name instead of its ID.
+If you use cURL to download artifacts from GitLab.com, use the `--location` parameter
+as the request might redirect through a CND.
+
NOTE:
If a pipeline is [parent of other child pipelines](../ci/pipelines/downstream_pipelines.md#parent-child-pipelines), artifacts
are searched in hierarchical order from parent to child. For example, if both parent and
@@ -85,7 +91,7 @@ Parameters
| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
| `ref_name` | string | Yes | Branch or tag name in repository. HEAD or SHA references are not supported. |
| `job` | string | Yes | The name of the job. |
-| `job_token` **(PREMIUM)** | string | No | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
+| `job_token` **(PREMIUM ALL)** | string | No | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
Example request using the `PRIVATE-TOKEN` header:
@@ -94,7 +100,7 @@ curl --location --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.ex
```
To use this in a [`script` definition](../ci/yaml/index.md#script) inside
-`.gitlab-ci.yml` **(PREMIUM)**, you can use either:
+`.gitlab-ci.yml` **(PREMIUM ALL)**, you can use either:
- The `JOB-TOKEN` header with the GitLab-provided `CI_JOB_TOKEN` variable.
For example, the following job downloads the artifacts of the `test` job
@@ -132,6 +138,9 @@ Download a single artifact file from a job with a specified ID from inside
the job's artifacts zipped archive. The file is extracted from the archive and
streamed to the client.
+If you use cURL to download artifacts from GitLab.com, use the `--location` parameter
+as the request might redirect through a CND.
+
```plaintext
GET /projects/:id/jobs/:job_id/artifacts/*artifact_path
```
@@ -143,7 +152,7 @@ Parameters
| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
| `job_id` | integer | Yes | The unique job identifier. |
| `artifact_path` | string | Yes | Path to a file inside the artifacts archive. |
-| `job_token` **(PREMIUM)** | string | No | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
+| `job_token` **(PREMIUM ALL)** | string | No | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
Example request:
@@ -172,6 +181,9 @@ Artifacts for [parent and child pipelines](../ci/pipelines/downstream_pipelines.
are searched in hierarchical order from parent to child. For example, if both parent and child pipelines
have a job with the same name, the artifact from the parent pipeline is returned.
+If you use cURL to download artifacts from GitLab.com, use the `--location` parameter
+as the request might redirect through a CND.
+
```plaintext
GET /projects/:id/jobs/artifacts/:ref_name/raw/*artifact_path?job=name
```
@@ -184,7 +196,7 @@ Parameters:
| `ref_name` | string | Yes | Branch or tag name in repository. `HEAD` or `SHA` references are not supported. |
| `artifact_path` | string | Yes | Path to a file inside the artifacts archive. |
| `job` | string | Yes | The name of the job. |
-| `job_token` **(PREMIUM)** | string | No | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
+| `job_token` **(PREMIUM ALL)** | string | No | To be used with [triggers](../ci/jobs/ci_job_token.md#download-an-artifact-from-a-different-pipeline) for multi-project pipelines. It should be invoked only in a CI/CD job defined in the `.gitlab-ci.yml` file. The value is always `$CI_JOB_TOKEN`. The job associated with the `$CI_JOB_TOKEN` must be running when this token is used. |
Example request:
diff --git a/doc/api/license.md b/doc/api/license.md
index 39da6af30d4..d393229fcf2 100644
--- a/doc/api/license.md
+++ b/doc/api/license.md
@@ -265,3 +265,40 @@ Returns:
| Attribute | Type | Description |
|:-----------------------------|:--------------|:------------------------------------------|
| `success` | boolean | Whether the request succeeded or not. |
+
+## Retrieve usage information about the current license
+
+Gets usage information about the current license and exports it in CSV format.
+
+```plaintext
+GET /license/usage_export.csv
+```
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/license/usage_export.csv"
+```
+
+Example response:
+
+```csv
+License Key,"eyJkYXRhIjoib1EwRWZXU3RobDY2Yl=
+"
+Email,user@example.com
+License Start Date,2023-02-22
+License End Date,2024-02-22
+Company,Example Corp.
+Generated At,2023-09-05 06:56:23
+"",""
+Date,Billable User Count
+2023-07-11 12:00:05,21
+2023-07-13 12:00:06,21
+2023-08-16 12:00:02,21
+2023-09-04 12:00:12,21
+
+```
+
+Returns:
+
+- `202 Accepted` if the request to refresh billable users is successfully initiated.
+- `403 Forbidden` if the current user in not permitted to refresh billable users for the license.
+- `404 Not Found` if the license could not be found.
diff --git a/doc/api/linked_epics.md b/doc/api/linked_epics.md
index 1cb70fa38f0..4d0f1dbe6a0 100644
--- a/doc/api/linked_epics.md
+++ b/doc/api/linked_epics.md
@@ -17,14 +17,14 @@ Get a list of a given group's related epic links within group and sub-groups, fi
The user needs to have access to the `source_epic` and `target_epic` to access the related epic link.
```plaintext
-GET /groups/:id/epics/related_epic_links
+GET /groups/:id/related_epic_links
```
Supported attributes:
| Attribute | Type | Required | Description |
| ---------- | -------------- | ---------------------- | ------------------------------------------------------------------------- |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). |
| `created_after` | string | no | Return related epic links created on or after the given time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`) |
| `created_before` | string | no | Return related epic links created on or before the given time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`) |
| `updated_after` | string | no | Return related epic links updated on or after the given time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`) |
@@ -145,8 +145,8 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ---------- | -------------- | ---------------------- | ------------------------------------------------------------------------- |
-| `epic_iid` | integer | **{check-circle}** Yes | Internal ID of a group's epic |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). |
+| `epic_iid` | integer | Yes | Internal ID of a group's epic |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding). |
Example request:
@@ -224,11 +224,11 @@ Supported attributes:
| Attribute | Type | Required | Description |
|---------------------|----------------|-----------------------------|---------------------------------------|
-| `epic_iid` | integer | **{check-circle}** Yes | Internal ID of a group's epic. |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `target_epic_iid` | integer/string | **{check-circle}** Yes | Internal ID of a target group's epic. |
-| `target_group_id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the target group](rest/index.md#namespaced-path-encoding). |
-| `link_type` | string | **{dotted-circle}** No | Type of the relation (`relates_to`, `blocks`, `is_blocked_by`), defaults to `relates_to`. |
+| `epic_iid` | integer | Yes | Internal ID of a group's epic. |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `target_epic_iid` | integer/string | Yes | Internal ID of a target group's epic. |
+| `target_group_id` | integer/string | Yes | ID or [URL-encoded path of the target group](rest/index.md#namespaced-path-encoding). |
+| `link_type` | string | No | Type of the relation (`relates_to`, `blocks`, `is_blocked_by`), defaults to `relates_to`. |
Example request:
@@ -346,9 +346,9 @@ Supported attributes:
| Attribute | Type | Required | Description |
|--------------------------|----------------|-----------------------------|---------------------------------------|
-| `epic_iid` | integer | **{check-circle}** Yes | Internal ID of a group's epic. |
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `related_epic_link_id` | integer/string | **{check-circle}** Yes | Internal ID of a related epic link. |
+| `epic_iid` | integer | Yes | Internal ID of a group's epic. |
+| `id` | integer/string | Yes | ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `related_epic_link_id` | integer/string | Yes | Internal ID of a related epic link. |
Example request:
diff --git a/doc/api/managed_licenses.md b/doc/api/managed_licenses.md
deleted file mode 100644
index d9f74ddddb2..00000000000
--- a/doc/api/managed_licenses.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-stage: Fulfillment
-group: Utilization
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: 'index.md'
----
-
-# Managed Licenses API (removed) **(ULTIMATE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/390417) in GitLab 15.9
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/397067) in 16.0.
-
-<!-- This redirect file can be deleted after <2023-08-22>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/api/member_roles.md b/doc/api/member_roles.md
index 9d3e51efabd..76ae681bfb4 100644
--- a/doc/api/member_roles.md
+++ b/doc/api/member_roles.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -12,6 +12,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Admin vulnerability added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121534) in GitLab 16.1.
> - [Read dependency added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126247) in GitLab 16.3.
> - [Name and description fields added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/126423) in GitLab 16.3.
+> - [Admin merge request introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128302) in GitLab 16.4 [with a flag](../administration/feature_flags.md) named `admin_merge_request`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../administration/feature_flags.md) named `admin_merge_request`.
+On GitLab.com, this feature is not available.
## List all member roles of a group
@@ -34,6 +39,7 @@ If successful, returns [`200`](rest/index.md#status-codes) and the following res
| `[].description` | string | The description of the member role. |
| `[].group_id` | integer | The ID of the group that the member role belongs to. |
| `[].base_access_level` | integer | Base access level for member role. Valid values are 10 (Guest), 20 (Reporter), 30 (Developer), 40 (Maintainer), or 50 (Owner).|
+| `[].admin_merge_request` | boolean | Permission to admin project merge requests and enables the ability to `download_code`. |
| `[].admin_vulnerability` | boolean | Permission to admin project vulnerabilities. |
| `[].read_code` | boolean | Permission to read project code. |
| `[].read_dependency` | boolean | Permission to read project dependencies. |
@@ -42,7 +48,7 @@ If successful, returns [`200`](rest/index.md#status-codes) and the following res
Example request:
```shell
-curl --header "Authorization: Bearer <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/member_roles"
+curl --header "Authorization: Bearer <your_access_token>" "https://gitlab.example.com/api/v4/groups/84/member_roles"
```
Example response:
@@ -55,6 +61,7 @@ Example response:
"description: "Custom guest that can read code",
"group_id": 84,
"base_access_level": 10,
+ "admin_merge_request": false,
"admin_vulnerability": false,
"read_code": true,
"read_dependency": false,
@@ -66,6 +73,7 @@ Example response:
"description: "Custom guest that read and admin security entities",
"group_id": 84,
"base_access_level": 10,
+ "admin_merge_request": false,
"admin_vulnerability": true,
"read_code": false,
"read_dependency": true,
@@ -92,6 +100,7 @@ To add a member role to a group, the group must be at root-level (have no parent
| `name` | string | yes | The name of the member role. |
| `description` | string | no | The description of the member role. |
| `base_access_level` | integer | yes | Base access level for configured role. Valid values are 10 (Guest), 20 (Reporter), 30 (Developer), 40 (Maintainer), or 50 (Owner).|
+| `admin_merge_request` | boolean | no | Permission to admin project merge requests. |
| `admin_vulnerability` | boolean | no | Permission to admin project vulnerabilities. |
| `read_code` | boolean | no | Permission to read project code. |
| `read_dependency` | boolean | no | Permission to read project dependencies. |
@@ -106,6 +115,7 @@ If successful, returns [`201`](rest/index.md#status-codes) and the following att
| `description` | string | The description of the member role. |
| `group_id` | integer | The ID of the group that the member role belongs to. |
| `base_access_level` | integer | Base access level for member role. |
+| `admin_merge_request` | boolean | Permission to admin project merge requests. |
| `admin_vulnerability` | boolean | Permission to admin project vulnerabilities. |
| `read_code` | boolean | Permission to read project code. |
| `read_dependency` | boolean | Permission to read project dependencies. |
@@ -114,7 +124,7 @@ If successful, returns [`201`](rest/index.md#status-codes) and the following att
Example request:
```shell
- curl --request POST --header "Content-Type: application/json" --header "Authorization: Bearer $YOUR_ACCESS_TOKEN" --data '{"name" : "Custom guest", "base_access_level" : 10, "read_code" : true}' "https://example.gitlab.com/api/v4/groups/:id/member_roles"
+ curl --request POST --header "Content-Type: application/json" --header "Authorization: Bearer <your_access_token>" --data '{"name" : "Custom guest", "base_access_level" : 10, "read_code" : true}' "https://gitlab.example.com/api/v4/groups/84/member_roles"
```
Example response:
@@ -126,6 +136,7 @@ Example response:
"description": null,
"group_id": 84,
"base_access_level": 10,
+ "admin_merge_requests": false,
"admin_vulnerability": false,
"read_code": true,
"read_dependency": false,
@@ -157,5 +168,5 @@ If successful, returns [`204`](rest/index.md#status-codes) and an empty response
Example request:
```shell
-curl --request DELETE --header "Content-Type: application/json" --header "Authorization: Bearer $YOUR_ACCESS_TOKEN" "https://example.gitlab.com/api/v4/groups/:group_id/member_roles/:member_role_id"
+curl --request DELETE --header "Content-Type: application/json" --header "Authorization: Bearer <your_access_token>" "https://gitlab.example.com/api/v4/groups/84/member_roles/1"
```
diff --git a/doc/api/members.md b/doc/api/members.md
index f7e3d6898ec..7e085a101bb 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -135,7 +135,7 @@ GET /projects/:id/members/all
| `query` | string | no | A query string to search for members |
| `user_ids` | array of integers | no | Filter the results on the given user IDs |
| `show_seat_info` | boolean | no | Show seat information for users |
-| `state` | string | no | Filter results by member state, one of `awaiting` or `active` **(PREMIUM)** |
+| `state` | string | no | Filter results by member state, one of `awaiting` or `active` **(PREMIUM ALL)** |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/all"
@@ -519,7 +519,7 @@ POST /projects/:id/members
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `user_id` | integer/string | yes | The user ID of the new member or multiple IDs separated by commas |
-| `access_level` | integer | yes | A valid access level |
+| `access_level` | integer | yes | [A valid access level](access_requests.md#valid-access-levels) |
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY` |
| `invite_source` | string | no | The source of the invitation that starts the member creation process. GitLab team members can view more information in this confidential issue: `https://gitlab.com/gitlab-org/gitlab/-/issues/327120>`. |
| `tasks_to_be_done` | array of strings | no | Tasks the inviter wants the member to focus on. The tasks are added as issues to a specified project. The possible values are: `ci`, `code` and `issues`. If specified, requires `tasks_project_id`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69299) in GitLab 14.5 [with a flag](../administration/feature_flags.md) named `invite_members_for_task`. Disabled by default. |
@@ -571,9 +571,9 @@ PUT /projects/:id/members/:user_id
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `user_id` | integer | yes | The user ID of the member |
-| `access_level` | integer | yes | A valid access level |
+| `access_level` | integer | yes | A [valid access level](access_requests.md#valid-access-levels) |
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY` |
-| `member_role_id` | integer | no | The ID of a member role **(ULTIMATE)** |
+| `member_role_id` | integer | no | The ID of a member role **(ULTIMATE ALL)** |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/members/:user_id?access_level=40"
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index d64c71367a9..d00252da207 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -162,7 +162,7 @@ Supported attributes:
"protected_branches": [
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"access_level": 30,
@@ -264,7 +264,7 @@ Supported attributes:
"protected_branches": [
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"access_level": 30,
@@ -374,7 +374,7 @@ Supported attributes:
"protected_branches": [
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"access_level": 30,
@@ -508,7 +508,7 @@ Supported attributes:
"protected_branches": [
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"access_level": 30,
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 5f637dd28a3..53a605c56f0 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -51,8 +51,8 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ------------------------------- | -------------- | -------- | ----------- |
-| `approved_by_ids` **(PREMIUM)** | integer array | No | Returns merge requests which have been approved by all the users with the given `id`. Maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
-| `approver_ids` **(PREMIUM)** | integer array | No | Returns merge requests which have specified all the users with the given `id` as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
+| `approved_by_ids` **(PREMIUM ALL)** | integer array | No | Returns merge requests which have been approved by all the users with the given `id`. Maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
+| `approver_ids` **(PREMIUM ALL)** | integer array | No | Returns merge requests which have specified all the users with the given `id` as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved` | string | No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. Available only when the feature flag `mr_approved_filter` is enabled. |
| `assignee_id` | integer | No | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
| `author_id` | integer | No | Returns merge requests created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. |
@@ -114,7 +114,7 @@ Supported attributes:
"closed_at": null,
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -242,8 +242,8 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ------------------------------- | -------------- | -------- | ----------- |
| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `approved_by_ids` **(PREMIUM)** | integer array | No | Returns merge requests which have been approved by all the users with the given `id`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
-| `approver_ids` **(PREMIUM)** | integer array | No | Returns merge requests which have specified all the users with the given `id` as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
+| `approved_by_ids` **(PREMIUM ALL)** | integer array | No | Returns merge requests which have been approved by all the users with the given `id`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
+| `approver_ids` **(PREMIUM ALL)** | integer array | No | Returns merge requests which have specified all the users with the given `id` as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved` | string | No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. Available only when the feature flag `mr_approved_filter` is enabled. |
| `assignee_id` | integer | No | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
| `author_id` | integer | No | Returns merge requests created by the given user `id`. Mutually exclusive with `author_username`. |
@@ -303,7 +303,7 @@ Supported attributes:
"closed_at": null,
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -419,9 +419,9 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ------------------------------- | -------------- | -------- | ----------- |
| `id` | integer or string | Yes | The ID or [URL-encoded path of the group](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `approved_by_ids` **(PREMIUM)** | integer array | No | Returns merge requests which have been approved by all the users with the given `id`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
-| `approved_by_usernames` **(PREMIUM)** | string array | No | Returns merge requests which have been approved by all the users with the given `username`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
-| `approver_ids` **(PREMIUM)** | integer array | No | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
+| `approved_by_ids` **(PREMIUM ALL)** | integer array | No | Returns merge requests which have been approved by all the users with the given `id`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
+| `approved_by_usernames` **(PREMIUM ALL)** | string array | No | Returns merge requests which have been approved by all the users with the given `username`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
+| `approver_ids` **(PREMIUM ALL)** | integer array | No | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved` | string | No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. Available only when the feature flag `mr_approved_filter` is enabled. |
| `assignee_id` | integer | No | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
| `author_id` | integer | No | Returns merge requests created by the given user `id`. Mutually exclusive with `author_username`. |
@@ -479,7 +479,7 @@ Supported attributes:
"closed_at": null,
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -598,7 +598,7 @@ Supported attributes:
| Attribute | Type | Description |
|----------------------------------|------|-------------|
-| `approvals_before_merge`| integer | **(PREMIUM)** Number of approvals required before this merge request can merge. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. |
+| `approvals_before_merge`| integer | **(PREMIUM ALL)** Number of approvals required before this merge request can merge. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. |
| `assignee` | object | First assignee of the merge request. |
| `assignees` | array | Assignees of the merge request. |
| `author` | object | User who created this merge request. |
@@ -672,7 +672,7 @@ Supported attributes:
"prepared_at": "2018-09-04T11:16:17.520Z",
"closed_by": null,
"closed_at": null,
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "manual-job-rules",
"user_notes_count": 0,
"upvotes": 0,
@@ -1084,7 +1084,7 @@ Supported attributes:
"new_path": "VERSION",
"a_mode": "100644",
"b_mode": "100644",
- "diff": "--- a/VERSION\ +++ b/VERSION\ @@ -1 +1 @@\ -1.9.7\ +1.9.8",
+ "diff": "@@ -1 +1 @@\ -1.9.7\ +1.9.8",
"new_file": false,
"renamed_file": false,
"deleted_file": false
@@ -1140,7 +1140,7 @@ Example response:
"new_path": "README",
"a_mode": "100644",
"b_mode": "100644",
- "diff": "--- a/README\ +++ b/README\ @@ -1 +1 @@\ -Title\ +README",
+ "diff": "@@ -1 +1 @@\ -Title\ +README",
"new_file": false,
"renamed_file": false,
"deleted_file": false
@@ -1150,7 +1150,7 @@ Example response:
"new_path": "VERSION",
"a_mode": "100644",
"b_mode": "100644",
- "diff": "--- a/VERSION\ +++ b/VERSION\ @@ -1 +1 @@\ -1.9.7\ +1.9.8",
+ "diff": "@@\ -1.9.7\ +1.9.8",
"new_file": false,
"renamed_file": false,
"deleted_file": false
@@ -1179,7 +1179,7 @@ Supported attributes:
{
"id": 77,
"sha": "959e04d7c7a30600c894bd3c0cd0e1ce7f42c11d",
- "ref": "master",
+ "ref": "main",
"status": "success"
}
]
@@ -1262,7 +1262,7 @@ POST /projects/:id/merge_requests
| `target_branch` | string | Yes | The target branch. |
| `title` | string | Yes | Title of MR. |
| `allow_collaboration` | boolean | No | Allow commits from members who can merge to the target branch. |
-| `approvals_before_merge` **(PREMIUM)** | integer | No | Number of approvals required before this can be merged (see below). To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. |
+| `approvals_before_merge` **(PREMIUM ALL)** | integer | No | Number of approvals required before this can be merged (see below). To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. |
| `allow_maintainer_to_push` | boolean | No | Alias of `allow_collaboration`. |
| `assignee_id` | integer | No | Assignee user ID. |
| `assignee_ids` | integer array | No | The ID of the users to assign the merge request to. Set to `0` or provide an empty value to unassign all assignees. |
@@ -1284,7 +1284,7 @@ POST /projects/:id/merge_requests
"state": "merged",
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -1439,7 +1439,7 @@ Must include at least one non-required attribute from above.
"state": "merged",
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -1617,7 +1617,7 @@ Supported attributes:
"state": "merged",
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -1819,7 +1819,7 @@ Supported attributes:
"state": "merged",
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -2121,7 +2121,7 @@ Example response:
"state": "merged",
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -2281,7 +2281,7 @@ Example response:
"state": "merged",
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "test1",
"upvotes": 0,
"downvotes": 0,
@@ -2568,7 +2568,8 @@ Example response:
"created_at": "2016-07-26T14:44:48.926Z",
"merge_request_id": 105,
"state": "collected",
- "real_size": "1"
+ "real_size": "1",
+ "patch_id_sha": "d504412d5b6e6739647e752aff8e468dde093f2f"
}, {
"id": 108,
"head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24",
@@ -2577,7 +2578,8 @@ Example response:
"created_at": "2016-07-25T14:21:33.028Z",
"merge_request_id": 105,
"state": "collected",
- "real_size": "1"
+ "real_size": "1",
+ "patch_id_sha": "72c30d1f0115fc1d2bb0b29b24dc2982cbcdfd32"
}]
```
@@ -2620,6 +2622,7 @@ Example response:
"merge_request_id": 105,
"state": "collected",
"real_size": "1",
+ "patch_id_sha": "d504412d5b6e6739647e752aff8e468dde093f2f",
"commits": [{
"id": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30",
"short_id": "33e2ee85",
@@ -2650,7 +2653,7 @@ Example response:
"new_path": "LICENSE",
"a_mode": "0",
"b_mode": "100644",
- "diff": "--- /dev/null\n+++ b/LICENSE\n@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2018 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n",
+ "diff": "@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2018 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n",
"new_file": true,
"renamed_file": false,
"deleted_file": false
diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md
index 1ede530578b..569fcc3d644 100644
--- a/doc/api/namespaces.md
+++ b/doc/api/namespaces.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/notification_settings.md b/doc/api/notification_settings.md
index c4b2d90f2c7..e498c3c91fb 100644
--- a/doc/api/notification_settings.md
+++ b/doc/api/notification_settings.md
@@ -38,7 +38,7 @@ If the `custom` level is used, specific email events can be controlled. Availabl
- `success_pipeline`
- `moved_project`
- `merge_when_pipeline_succeeds`
-- `new_epic` **(ULTIMATE)**
+- `new_epic` **(ULTIMATE ALL)**
## Global notification settings
@@ -94,7 +94,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
| `success_pipeline` | boolean | no | Enable/disable this notification |
| `moved_project` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30371) in GitLab 13.3) |
| `merge_when_pipeline_succeeds` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/244840) in GitLab 13.9) |
-| `new_epic` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5863) in GitLab 11.3) **(ULTIMATE)** |
+| `new_epic` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5863) in GitLab 11.3) **(ULTIMATE ALL)** |
Example response:
@@ -166,7 +166,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
| `success_pipeline` | boolean | no | Enable/disable this notification |
| `moved_project` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30371) in GitLab 13.3) |
| `merge_when_pipeline_succeeds` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/244840) in GitLab 13.9) |
-| `new_epic` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5863) in GitLab 11.3) **(ULTIMATE)** |
+| `new_epic` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5863) in GitLab 11.3) **(ULTIMATE ALL)** |
Example responses:
diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md
index 75b50829ddd..00e8a4c86c6 100644
--- a/doc/api/oauth2.md
+++ b/doc/api/oauth2.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/packages.md b/doc/api/packages.md
index ac692956f22..a378be26a24 100644
--- a/doc/api/packages.md
+++ b/doc/api/packages.md
@@ -380,7 +380,7 @@ Example response:
"iid": 2,
"project_id": 9,
"sha": "e564015ac6cb3d8617647802c875b27d392f72a6",
- "ref": "master",
+ "ref": "main",
"status": "canceled",
"source": "push",
"created_at": "2023-02-01T12:23:23.694Z",
diff --git a/doc/api/packages/debian_group_distributions.md b/doc/api/packages/debian_group_distributions.md
index 0c7f4cdfeb8..68763a197aa 100644
--- a/doc/api/packages/debian_group_distributions.md
+++ b/doc/api/packages/debian_group_distributions.md
@@ -83,7 +83,7 @@ GET /groups/:id/-/debian_distributions/:codename
| Attribute | Type | Required | Description |
| ---------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](../rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `codename` | integer | yes | The `codename` of a distribution. |
+| `codename` | string | yes | The `codename` of a distribution. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/-/debian_distributions/unstable"
@@ -122,7 +122,7 @@ GET /groups/:id/-/debian_distributions/:codename/key.asc
| Attribute | Type | Required | Description |
| ---------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](../rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `codename` | integer | yes | The `codename` of a distribution. |
+| `codename` | string | yes | The `codename` of a distribution. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/-/debian_distributions/unstable/key.asc"
@@ -166,8 +166,8 @@ POST /groups/:id/-/debian_distributions
| `version` | string | no | The version of the new Debian distribution. |
| `description` | string | no | The description of the new Debian distribution. |
| `valid_time_duration_seconds` | integer | no | The valid time duration (in seconds) of the new Debian distribution. |
-| `components` | architectures | no | The new Debian distribution's list of components. |
-| `architectures` | architectures | no | The new Debian distribution's list of architectures. |
+| `components` | string array | no | The new Debian distribution's list of components. |
+| `architectures` | string array | no | The new Debian distribution's list of architectures. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/-/debian_distributions?codename=sid"
@@ -213,8 +213,8 @@ PUT /groups/:id/-/debian_distributions/:codename
| `version` | string | no | The Debian distribution's new version. |
| `description` | string | no | The Debian distribution's new description. |
| `valid_time_duration_seconds` | integer | no | The Debian distribution's new valid time duration (in seconds). |
-| `components` | architectures | no | The Debian distribution's new list of components. |
-| `architectures` | architectures | no | The Debian distribution's new list of architectures. |
+| `components` | string array | no | The Debian distribution's new list of components. |
+| `architectures` | string array | no | The Debian distribution's new list of architectures. |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/-/debian_distributions/unstable?suite=new-suite&valid_time_duration_seconds=604800"
@@ -253,7 +253,7 @@ DELETE /groups/:id/-/debian_distributions/:codename
| Attribute | Type | Required | Description |
| ---------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](../rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `codename` | integer | yes | The codename of the Debian distribution. |
+| `codename` | string | yes | The codename of the Debian distribution. |
```shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/-/debian_distributions/unstable"
diff --git a/doc/api/packages/debian_project_distributions.md b/doc/api/packages/debian_project_distributions.md
index 0a43546e2e1..952b75ceb0a 100644
--- a/doc/api/packages/debian_project_distributions.md
+++ b/doc/api/packages/debian_project_distributions.md
@@ -82,7 +82,7 @@ GET /projects/:id/debian_distributions/:codename
| Attribute | Type | Required | Description |
| ---------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `codename` | integer | yes | The `codename` of a distribution. |
+| `codename` | string | yes | The `codename` of a distribution. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/debian_distributions/unstable"
@@ -121,7 +121,7 @@ GET /projects/:id/debian_distributions/:codename/key.asc
| Attribute | Type | Required | Description |
| ---------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `codename` | integer | yes | The `codename` of a distribution. |
+| `codename` | string | yes | The `codename` of a distribution. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/debian_distributions/unstable/key.asc"
@@ -165,8 +165,8 @@ POST /projects/:id/debian_distributions
| `version` | string | no | The new Debian distribution's version. |
| `description` | string | no | The new Debian distribution's description. |
| `valid_time_duration_seconds` | integer | no | The new Debian distribution's valid time duration (in seconds). |
-| `components` | architectures | no | The new Debian distribution's list of components. |
-| `architectures` | architectures | no | The new Debian distribution's list of architectures. |
+| `components` | string array | no | The new Debian distribution's list of components. |
+| `architectures` | string array | no | The new Debian distribution's list of architectures. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/debian_distributions?codename=sid"
@@ -212,8 +212,8 @@ PUT /projects/:id/debian_distributions/:codename
| `version` | string | no | The Debian distribution's new version. |
| `description` | string | no | The Debian distribution's new description. |
| `valid_time_duration_seconds` | integer | no | The Debian distribution's new valid time duration (in seconds). |
-| `components` | architectures | no | The Debian distribution's new list of components. |
-| `architectures` | architectures | no | The Debian distribution's new list of architectures. |
+| `components` | string array | no | The Debian distribution's new list of components. |
+| `architectures` | string array | no | The Debian distribution's new list of architectures. |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/debian_distributions/unstable?suite=new-suite&valid_time_duration_seconds=604800"
@@ -252,7 +252,7 @@ DELETE /projects/:id/debian_distributions/:codename
| Attribute | Type | Required | Description |
| ---------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `codename` | integer | yes | The Debian distribution's codename. |
+| `codename` | string | yes | The Debian distribution's codename. |
```shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/debian_distributions/unstable"
diff --git a/doc/api/packages/nuget.md b/doc/api/packages/nuget.md
index a549d6af086..ee304ab28df 100644
--- a/doc/api/packages/nuget.md
+++ b/doc/api/packages/nuget.md
@@ -425,10 +425,12 @@ Example response:
}
```
-## V2 Feed Metadata Endpoint
+## V2 Feed Metadata Endpoints
> Introduced in GitLab 16.3.
+### $metadata endpoint
+
Authentication is not required. Returns metadata for a V2 feed available endpoints:
```plaintext
@@ -436,7 +438,7 @@ GET <route-prefix>/v2/$metadata
```
```shell
- curl "https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/$metadata"
+curl "https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/$metadata"
```
Example response:
@@ -475,3 +477,36 @@ Example response:
</edmx:DataServices>
</edmx:Edmx>
```
+
+### OData package entry endpoints
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127667) in GitLab 16.4.
+
+| Endpoint | Description |
+| -------- | ----------- |
+| `GET projects/:id/packages/nuget/v2/Packages()?$filter=(tolower(Id) eq '<package_name>')` | Returns an OData XML document containing information about the package with the given name. |
+| `GET projects/:id/packages/nuget/v2/FindPackagesById()?id='<package_name>'` | Returns an OData XML document containing information about the package with the given name. |
+| `GET projects/:id/packages/nuget/v2/Packages(Id='<package_name>',Version='<package_version>')` | Returns an OData XML document containing information about the package with the given name and version. |
+
+NOTE:
+GitLab doesn't receive an authentication token for the `Packages()` and `FindPackagesByID()` endpoints.
+To not reveal the package version to unauthenticated users, the actual latest package version is not returned. Instead, a placeholder version is returned.
+The latest version is obtained in the subsequent download request where the authentication token is sent.
+
+```shell
+curl "https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/Packages()?$filter=(tolower(Id) eq 'mynugetpkg')"
+```
+
+Example response:
+
+```xml
+<entry xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xml:base="https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2">
+ <id>https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/Packages(Id='mynugetpkg',Version='0.0.0-latest-version')</id>
+ <category term="V2FeedPackage" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
+ <title type="text">mynugetpkg</title>
+ <content type="application/zip" src="https://gitlab.example.com/api/v4/projects/1/packages/nuget/v2/download/mynugetpkg/latest"/>
+ <m:properties>
+ <d:Version>0.0.0-latest-version</d:Version>
+ </m:properties>
+ </entry>
+```
diff --git a/doc/api/personal_access_tokens.md b/doc/api/personal_access_tokens.md
index 901f99caee7..2131a29eb5b 100644
--- a/doc/api/personal_access_tokens.md
+++ b/doc/api/personal_access_tokens.md
@@ -45,14 +45,14 @@ Supported attributes:
| Attribute | Type | Required | Description |
|---------------------|----------------|----------|---------------------|
-| `created_after` | datetime (ISO 8601) | **{dotted-circle}** No | Limit results to PATs created after specified time. |
-| `created_before` | datetime (ISO 8601) | **{dotted-circle}** No | Limit results to PATs created before specified time. |
-| `last_used_after` | datetime (ISO 8601) | **{dotted-circle}** No | Limit results to PATs last used after specified time. |
-| `last_used_before` | datetime (ISO 8601) | **{dotted-circle}** No | Limit results to PATs last used before specified time. |
-| `revoked` | boolean | **{dotted-circle}** No | Limit results to PATs with specified revoked state. Valid values are `true` and `false`. |
-| `search` | string | **{dotted-circle}** No | Limit results to PATs with name containing search string. |
-| `state` | string | **{dotted-circle}** No | Limit results to PATs with specified state. Valid values are `active` and `inactive`. |
-| `user_id` | integer or string | **{dotted-circle}** No | Limit results to PATs owned by specified user. |
+| `created_after` | datetime (ISO 8601) | No | Limit results to PATs created after specified time. |
+| `created_before` | datetime (ISO 8601) | No | Limit results to PATs created before specified time. |
+| `last_used_after` | datetime (ISO 8601) | No | Limit results to PATs last used after specified time. |
+| `last_used_before` | datetime (ISO 8601) | No | Limit results to PATs last used before specified time. |
+| `revoked` | boolean | No | Limit results to PATs with specified revoked state. Valid values are `true` and `false`. |
+| `search` | string | No | Limit results to PATs with name containing search string. |
+| `state` | string | No | Limit results to PATs with specified state. Valid values are `active` and `inactive`. |
+| `user_id` | integer or string | No | Limit results to PATs owned by specified user. |
Example request:
@@ -226,6 +226,23 @@ Non-administrators can rotate their own tokens. Administrators can rotate tokens
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/personal_access_tokens/<personal_access_token_id>/rotate"
```
+Example response:
+
+```json
+{
+ "id": 42,
+ "name": "Rotated Token",
+ "revoked": false,
+ "created_at": "2023-08-01T15:00:00.000Z",
+ "scopes": ["api"],
+ "user_id": 1337,
+ "last_used_at": null,
+ "active": true,
+ "expires_at": "2023-08-15",
+ "token": "s3cr3t"
+}
+```
+
### Responses
- `200: OK` if the existing token is successfully revoked and the new token successfully created.
@@ -243,12 +260,13 @@ For each rotated token, the previous and now revoked token is referenced. This
chain of references defines a token family. In a token family, only the latest
token is active, and all other tokens in that family are revoked.
-When a revoked token from a token family is used in an authentication attempt,
-that attempt fails and the active token from the token family gets revoked.
+When a revoked token from a token family is used in an authentication attempt
+for the token rotation endpoint, that attempt fails and the active token from
+the token family gets revoked.
This mechanism helps to prevent compromise when a personal access token is
leaked.
-Automatic reuse detection is enabled for API requests.
+Automatic reuse detection is enabled for token rotation API requests.
## Revoke a personal access token
diff --git a/doc/api/plan_limits.md b/doc/api/plan_limits.md
index 53dedca3312..789acf46205 100644
--- a/doc/api/plan_limits.md
+++ b/doc/api/plan_limits.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/project_access_tokens.md b/doc/api/project_access_tokens.md
index 41bfcbd209b..793eb49c767 100644
--- a/doc/api/project_access_tokens.md
+++ b/doc/api/project_access_tokens.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -152,6 +152,24 @@ POST /projects/:id/access_tokens/:token_id/rotate
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/access_tokens/<token_id>/rotate"
```
+Example response:
+
+```json
+{
+ "id": 42,
+ "name": "Rotated Token",
+ "revoked": false,
+ "created_at": "2023-08-01T15:00:00.000Z",
+ "scopes": ["api"],
+ "user_id": 1337,
+ "last_used_at": null,
+ "active": true,
+ "expires_at": "2023-08-15",
+ "access_level": 30,
+ "token": "s3cr3t"
+}
+```
+
### Responses
- `200: OK` if the existing token is successfully revoked and the new token is successfully created.
diff --git a/doc/api/project_aliases.md b/doc/api/project_aliases.md
index 6bad94f48b3..b8ca5c2674c 100644
--- a/doc/api/project_aliases.md
+++ b/doc/api/project_aliases.md
@@ -48,7 +48,7 @@ GET /project_aliases/:name
| Attribute | Type | Required | Description |
|-----------|--------|----------|-----------------------|
-| `name` | string | **{check-circle}** Yes | The name of the alias. |
+| `name` | string | Yes | The name of the alias. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_aliases/gitlab"
@@ -75,8 +75,8 @@ POST /project_aliases
| Attribute | Type | Required | Description |
|--------------|----------------|----------|----------------------------------------|
-| `name` | string | **{check-circle}** Yes | The name of the alias. Must be unique. |
-| `project_id` | integer or string | **{check-circle}** Yes | The ID or path of the project. |
+| `name` | string | Yes | The name of the alias. Must be unique. |
+| `project_id` | integer or string | Yes | The ID or path of the project. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
@@ -111,7 +111,7 @@ DELETE /project_aliases/:name
| Attribute | Type | Required | Description |
|-----------|--------|----------|-----------------------|
-| `name` | string | **{check-circle}** Yes | The name of the alias. |
+| `name` | string | Yes | The name of the alias. |
```shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_aliases/gitlab"
diff --git a/doc/api/project_badges.md b/doc/api/project_badges.md
index 5c621bf6426..d615df112cf 100644
--- a/doc/api/project_badges.md
+++ b/doc/api/project_badges.md
@@ -47,7 +47,7 @@ Example response:
"id": 1,
"link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
"image_url": "https://shields.io/my/badge",
- "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=main",
"rendered_image_url": "https://shields.io/my/badge",
"kind": "project"
},
@@ -56,7 +56,7 @@ Example response:
"id": 2,
"link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
"image_url": "https://shields.io/my/badge",
- "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=main",
"rendered_image_url": "https://shields.io/my/badge",
"kind": "group"
}
@@ -88,7 +88,7 @@ Example response:
"id": 1,
"link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
"image_url": "https://shields.io/my/badge",
- "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=main",
"rendered_image_url": "https://shields.io/my/badge",
"kind": "project"
}
@@ -111,7 +111,7 @@ POST /projects/:id/badges
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
- --data "link_url=https://gitlab.com/gitlab-org/gitlab-foss/commits/master&image_url=https://shields.io/my/badge1&name=mybadge" \
+ --data "link_url=https://gitlab.com/gitlab-org/gitlab-foss/commits/main&image_url=https://shields.io/my/badge1&name=mybadge" \
"https://gitlab.example.com/api/v4/projects/:id/badges"
```
@@ -121,9 +121,9 @@ Example response:
{
"id": 1,
"name": "mybadge",
- "link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/master",
+ "link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/main",
"image_url": "https://shields.io/my/badge1",
- "rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/master",
+ "rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/main",
"rendered_image_url": "https://shields.io/my/badge1",
"kind": "project"
}
@@ -155,9 +155,9 @@ Example response:
{
"id": 1,
"name": "mybadge",
- "link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/master",
+ "link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/main",
"image_url": "https://shields.io/my/badge",
- "rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/master",
+ "rendered_link_url": "https://gitlab.com/gitlab-org/gitlab-foss/commits/main",
"rendered_image_url": "https://shields.io/my/badge",
"kind": "project"
}
@@ -204,7 +204,7 @@ Example response:
{
"link_url": "http://example.com/ci_status.svg?project=%{project_path}&ref=%{default_branch}",
"image_url": "https://shields.io/my/badge",
- "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=master",
+ "rendered_link_url": "http://example.com/ci_status.svg?project=example-org/example-project&ref=main",
"rendered_image_url": "https://shields.io/my/badge"
}
```
diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md
index 85aa28804b0..6e61c0d56b3 100644
--- a/doc/api/project_clusters.md
+++ b/doc/api/project_clusters.md
@@ -201,7 +201,7 @@ Parameters:
| `platform_kubernetes_attributes[ca_cert]` | string | no | TLS certificate. Required if API is using a self-signed TLS certificate. |
| `platform_kubernetes_attributes[namespace]` | string | no | The unique namespace related to the project |
| `platform_kubernetes_attributes[authorization_type]` | string | no | The cluster authorization type: `rbac`, `abac` or `unknown_authorization`. Defaults to `rbac`. |
-| `environment_scope` | string | no | The associated environment to the cluster. Defaults to `*` **(PREMIUM)** |
+| `environment_scope` | string | no | The associated environment to the cluster. Defaults to `*` **(PREMIUM ALL)** |
Example request:
diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md
index 113504aba8a..1a6b0ccc2c4 100644
--- a/doc/api/project_import_export.md
+++ b/doc/api/project_import_export.md
@@ -32,7 +32,7 @@ project to a web server or to any S3-compatible platform. For exports, GitLab:
time and is available throughout the export process.
- Administrators can modify the maximum export file size. By default, the maximum is unlimited (`0`). To change this,
edit `max_export_size` using either:
- - [GitLab UI](../administration/settings/account_and_limit_settings.md).
+ - [GitLab UI](../administration/settings/import_and_export_settings.md).
- [Application settings API](settings.md#change-application-settings)
- Has a fixed limit for the maximum import file size on GitLab.com. For more information, see
[Account and limit settings](../user/gitlab_com/index.md#account-and-limit-settings).
@@ -205,7 +205,7 @@ NOTE:
The maximum import file size can be set by the Administrator. It defaults to `0` (unlimited).
As an administrator, you can modify the maximum import file size. To do so, use the `max_import_size` option in the [Application settings API](settings.md#change-application-settings) or the [Admin Area](../administration/settings/account_and_limit_settings.md). Default [modified](https://gitlab.com/gitlab-org/gitlab/-/issues/251106) from 50 MB to 0 in GitLab 13.8.
-## Import a file from a remote object storage (Beta)
+## Import a file from a remote object storage **(BETA)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/282503) in GitLab 13.12 in [Beta](../policy/experiment-beta-support.md#beta) [with a flag](../administration/feature_flags.md) named `import_project_from_remote_file`. Enabled by default.
diff --git a/doc/api/project_relations_export.md b/doc/api/project_relations_export.md
index bce3c6271af..628bb467a02 100644
--- a/doc/api/project_relations_export.md
+++ b/doc/api/project_relations_export.md
@@ -63,10 +63,6 @@ curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" \
The status can be one of the following:
-- `0`: `started`
-- `1`: `finished`
-- `-1`: `failed`
-
- `0` - `started`
- `1` - `finished`
- `-1` - `failed`
diff --git a/doc/api/project_templates.md b/doc/api/project_templates.md
index dad09b0e479..f4fb17d8c57 100644
--- a/doc/api/project_templates.md
+++ b/doc/api/project_templates.md
@@ -20,7 +20,7 @@ It deprecates these endpoints, which are scheduled for removal in API version 5.
In addition to templates common to the entire instance, project-specific
templates are also available from this API endpoint.
-Support is also available for [group-level file templates](../user/group/manage.md#group-file-templates). **(PREMIUM)**
+Support is also available for [group-level file templates](../user/group/manage.md#group-file-templates). **(PREMIUM ALL)**
## Get all templates of a particular type
@@ -30,8 +30,8 @@ GET /projects/:id/templates/:type
| Attribute | Type | Required | Description |
| ---------- | ------ | -------- | ----------- |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `type` | string | **{check-circle}** Yes | The type of the template. Accepted values are: `dockerfiles`, `gitignores`, `gitlab_ci_ymls`, `licenses`, `issues`, or `merge_requests`. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `type` | string | Yes | The type of the template. Accepted values are: `dockerfiles`, `gitignores`, `gitlab_ci_ymls`, `licenses`, `issues`, or `merge_requests`. |
Example response (licenses):
@@ -96,12 +96,12 @@ GET /projects/:id/templates/:type/:name
| Attribute | Type | Required | Description |
| ---------- | ------ | -------- | ----------- |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `name` | string | **{check-circle}** Yes | The key of the template, as obtained from the collection endpoint. |
-| `type` | string | **{check-circle}** Yes | The type of the template. One of: `dockerfiles`, `gitignores`, `gitlab_ci_ymls`, `licenses`, `issues`, or `merge_requests`. |
-| `fullname` | string | **{dotted-circle}** No | The full name of the copyright holder to use when expanding placeholders in the template. Affects only licenses. |
-| `project` | string | **{dotted-circle}** No | The project name to use when expanding placeholders in the template. Affects only licenses. |
-| `source_template_project_id` | integer | **{dotted-circle}** No | The project ID where a given template is being stored. Helpful when multiple templates from different projects have the same name. If multiple templates have the same name, the match from `closest ancestor` is returned if `source_template_project_id` is not specified, |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `name` | string | Yes | The key of the template, as obtained from the collection endpoint. |
+| `type` | string | Yes | The type of the template. One of: `dockerfiles`, `gitignores`, `gitlab_ci_ymls`, `licenses`, `issues`, or `merge_requests`. |
+| `fullname` | string | No | The full name of the copyright holder to use when expanding placeholders in the template. Affects only licenses. |
+| `project` | string | No | The project name to use when expanding placeholders in the template. Affects only licenses. |
+| `source_template_project_id` | integer | No | The project ID where a given template is being stored. Helpful when multiple templates from different projects have the same name. If multiple templates have the same name, the match from `closest ancestor` is returned if `source_template_project_id` is not specified, |
Example response (Dockerfile):
diff --git a/doc/api/project_vulnerabilities.md b/doc/api/project_vulnerabilities.md
index c38ee31ddfc..2b4d3ec50df 100644
--- a/doc/api/project_vulnerabilities.md
+++ b/doc/api/project_vulnerabilities.md
@@ -90,7 +90,7 @@ Example response:
"path": "security-reports",
"path_with_namespace": "gitlab-org/security-reports"
},
- "project_default_branch": "master",
+ "project_default_branch": "main",
"report_type": "dependency_scanning",
"resolved_at": null,
"resolved_by_id": null,
@@ -178,7 +178,7 @@ Example response:
"path": "security-reports",
"path_with_namespace": "gitlab-org/security-reports"
},
- "project_default_branch": "master",
+ "project_default_branch": "main",
"report_type": "dependency_scanning",
"resolved_at": null,
"resolved_by_id": null,
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 5bd2ec07647..2c00e1cbdc8 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -53,34 +53,34 @@ GET /projects
| Attribute | Type | Required | Description |
|--------------------------------------------|----------|------------------------|-------------|
-| `archived` | boolean | **{dotted-circle}** No | Limit by archived status. |
-| `id_after` | integer | **{dotted-circle}** No | Limit results to projects with IDs greater than the specified ID. |
-| `id_before` | integer | **{dotted-circle}** No | Limit results to projects with IDs less than the specified ID. |
-| `imported` | boolean | **{dotted-circle}** No | Limit results to projects which were imported from external systems by current user. |
-| `last_activity_after` | datetime | **{dotted-circle}** No | Limit results to projects with last activity after specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`) |
-| `last_activity_before` | datetime | **{dotted-circle}** No | Limit results to projects with last activity before specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`) |
-| `membership` | boolean | **{dotted-circle}** No | Limit by projects that the current user is a member of. |
-| `min_access_level` | integer | **{dotted-circle}** No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
-| `order_by` | string | **{dotted-circle}** No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, `last_activity_at`, or `similarity` fields. `repository_size`, `storage_size`, `packages_size` or `wiki_size` fields are only allowed for administrators. `similarity` ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332890) in GitLab 14.1) is only available when searching and is limited to projects that the current user is a member of. Default is `created_at`. |
-| `owned` | boolean | **{dotted-circle}** No | Limit by projects explicitly owned by the current user. |
-| `repository_checksum_failed` **(PREMIUM)** | boolean | **{dotted-circle}** No | Limit projects where the repository checksum calculation has failed. |
-| `repository_storage` | string | **{dotted-circle}** No | Limit results to projects stored on `repository_storage`. _(administrators only)_ |
-| `search_namespaces` | boolean | **{dotted-circle}** No | Include ancestor namespaces when matching search criteria. Default is `false`. |
-| `search` | string | **{dotted-circle}** No | Return list of projects matching the search criteria. |
-| `simple` | boolean | **{dotted-circle}** No | Return only limited fields for each project. This operation is a no-op without authentication where only simple fields are returned. |
-| `sort` | string | **{dotted-circle}** No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
-| `starred` | boolean | **{dotted-circle}** No | Limit by projects starred by the current user. |
-| `statistics` | boolean | **{dotted-circle}** No | Include project statistics. Available only to users with at least the Reporter role. |
-| `topic` | string | **{dotted-circle}** No | Comma-separated topic names. Limit results to projects that match all of given topics. See `topics` attribute. |
-| `topic_id` | integer | **{dotted-circle}** No | Limit results to projects with the assigned topic given by the topic ID. |
-| `visibility` | string | **{dotted-circle}** No | Limit by visibility `public`, `internal`, or `private`. |
-| `wiki_checksum_failed` **(PREMIUM)** | boolean | **{dotted-circle}** No | Limit projects where the wiki checksum calculation has failed. |
-| `with_custom_attributes` | boolean | **{dotted-circle}** No | Include [custom attributes](custom_attributes.md) in response. _(administrator only)_ |
-| `with_issues_enabled` | boolean | **{dotted-circle}** No | Limit by enabled issues feature. |
-| `with_merge_requests_enabled` | boolean | **{dotted-circle}** No | Limit by enabled merge requests feature. |
-| `with_programming_language` | string | **{dotted-circle}** No | Limit by projects which use the given programming language. |
-| `updated_before` | datetime | **{dotted-circle}** No | Limit results to projects last updated before the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. For this filter to work, you must also provide `updated_at` as the `order_by` attribute. |
-| `updated_after` | datetime | **{dotted-circle}** No | Limit results to projects last updated after the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. For this filter to work, you must also provide `updated_at` as the `order_by` attribute. |
+| `archived` | boolean | No | Limit by archived status. |
+| `id_after` | integer | No | Limit results to projects with IDs greater than the specified ID. |
+| `id_before` | integer | No | Limit results to projects with IDs less than the specified ID. |
+| `imported` | boolean | No | Limit results to projects which were imported from external systems by current user. |
+| `last_activity_after` | datetime | No | Limit results to projects with last activity after specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`) |
+| `last_activity_before` | datetime | No | Limit results to projects with last activity before specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`) |
+| `membership` | boolean | No | Limit by projects that the current user is a member of. |
+| `min_access_level` | integer | No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
+| `order_by` | string | No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, `last_activity_at`, or `similarity` fields. `repository_size`, `storage_size`, `packages_size` or `wiki_size` fields are only allowed for administrators. `similarity` ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332890) in GitLab 14.1) is only available when searching and is limited to projects that the current user is a member of. Default is `created_at`. |
+| `owned` | boolean | No | Limit by projects explicitly owned by the current user. |
+| `repository_checksum_failed` **(PREMIUM ALL)** | boolean | No | Limit projects where the repository checksum calculation has failed. |
+| `repository_storage` | string | No | Limit results to projects stored on `repository_storage`. _(administrators only)_ |
+| `search_namespaces` | boolean | No | Include ancestor namespaces when matching search criteria. Default is `false`. |
+| `search` | string | No | Return list of projects matching the search criteria. |
+| `simple` | boolean | No | Return only limited fields for each project. This operation is a no-op without authentication where only simple fields are returned. |
+| `sort` | string | No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
+| `starred` | boolean | No | Limit by projects starred by the current user. |
+| `statistics` | boolean | No | Include project statistics. Available only to users with at least the Reporter role. |
+| `topic` | string | No | Comma-separated topic names. Limit results to projects that match all of given topics. See `topics` attribute. |
+| `topic_id` | integer | No | Limit results to projects with the assigned topic given by the topic ID. |
+| `visibility` | string | No | Limit by visibility `public`, `internal`, or `private`. |
+| `wiki_checksum_failed` **(PREMIUM ALL)** | boolean | No | Limit projects where the wiki checksum calculation has failed. |
+| `with_custom_attributes` | boolean | No | Include [custom attributes](custom_attributes.md) in response. _(administrator only)_ |
+| `with_issues_enabled` | boolean | No | Limit by enabled issues feature. |
+| `with_merge_requests_enabled` | boolean | No | Limit by enabled merge requests feature. |
+| `with_programming_language` | string | No | Limit by projects which use the given programming language. |
+| `updated_before` | datetime | No | Limit results to projects last updated before the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. For this filter to work, you must also provide `updated_at` as the `order_by` attribute. |
+| `updated_after` | datetime | No | Limit results to projects last updated after the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. For this filter to work, you must also provide `updated_at` as the `order_by` attribute. |
This endpoint supports [keyset pagination](rest/index.md#keyset-based-pagination)
for selected `order_by` options.
@@ -162,7 +162,7 @@ When the user is authenticated and `simple` is not set this returns something li
"ssh_url_to_repo": "git@gitlab.example.com:diaspora/diaspora-client.git",
"http_url_to_repo": "https://gitlab.example.com/diaspora/diaspora-client.git",
"web_url": "https://gitlab.example.com/diaspora/diaspora-client",
- "readme_url": "https://gitlab.example.com/diaspora/diaspora-client/blob/master/README.md",
+ "readme_url": "https://gitlab.example.com/diaspora/diaspora-client/blob/main/README.md",
"avatar_url": "https://gitlab.example.com/uploads/project/avatar/4/uploads/avatar.png",
"forks_count": 0,
"star_count": 0,
@@ -322,26 +322,26 @@ GET /users/:user_id/projects
| Attribute | Type | Required | Description |
|-------------------------------|---------|------------------------|-------------|
-| `user_id` | string | **{check-circle}** Yes | The ID or username of the user. |
-| `archived` | boolean | **{dotted-circle}** No | Limit by archived status. |
-| `id_after` | integer | **{dotted-circle}** No | Limit results to projects with IDs greater than the specified ID. |
-| `id_before` | integer | **{dotted-circle}** No | Limit results to projects with IDs less than the specified ID. |
-| `membership` | boolean | **{dotted-circle}** No | Limit by projects that the current user is a member of. |
-| `min_access_level` | integer | **{dotted-circle}** No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
-| `order_by` | string | **{dotted-circle}** No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at`. |
-| `owned` | boolean | **{dotted-circle}** No | Limit by projects explicitly owned by the current user. |
-| `search` | string | **{dotted-circle}** No | Return list of projects matching the search criteria. |
-| `simple` | boolean | **{dotted-circle}** No | Return only limited fields for each project. Without authentication, this operation is a no-op; only simple fields are returned. |
-| `sort` | string | **{dotted-circle}** No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
-| `starred` | boolean | **{dotted-circle}** No | Limit by projects starred by the current user. |
-| `statistics` | boolean | **{dotted-circle}** No | Include project statistics. Available only to users with at least the Reporter role. |
-| `visibility` | string | **{dotted-circle}** No | Limit by visibility `public`, `internal`, or `private`. |
-| `with_custom_attributes` | boolean | **{dotted-circle}** No | Include [custom attributes](custom_attributes.md) in response. _(administrator only)_ |
-| `with_issues_enabled` | boolean | **{dotted-circle}** No | Limit by enabled issues feature. |
-| `with_merge_requests_enabled` | boolean | **{dotted-circle}** No | Limit by enabled merge requests feature. |
-| `with_programming_language` | string | **{dotted-circle}** No | Limit by projects which use the given programming language. |
-| `updated_before` | datetime | **{dotted-circle}** No | Limit results to projects last updated before the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
-| `updated_after` | datetime | **{dotted-circle}** No | Limit results to projects last updated after the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
+| `user_id` | string | Yes | The ID or username of the user. |
+| `archived` | boolean | No | Limit by archived status. |
+| `id_after` | integer | No | Limit results to projects with IDs greater than the specified ID. |
+| `id_before` | integer | No | Limit results to projects with IDs less than the specified ID. |
+| `membership` | boolean | No | Limit by projects that the current user is a member of. |
+| `min_access_level` | integer | No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
+| `order_by` | string | No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at`. |
+| `owned` | boolean | No | Limit by projects explicitly owned by the current user. |
+| `search` | string | No | Return list of projects matching the search criteria. |
+| `simple` | boolean | No | Return only limited fields for each project. Without authentication, this operation is a no-op; only simple fields are returned. |
+| `sort` | string | No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
+| `starred` | boolean | No | Limit by projects starred by the current user. |
+| `statistics` | boolean | No | Include project statistics. Available only to users with at least the Reporter role. |
+| `visibility` | string | No | Limit by visibility `public`, `internal`, or `private`. |
+| `with_custom_attributes` | boolean | No | Include [custom attributes](custom_attributes.md) in response. _(administrator only)_ |
+| `with_issues_enabled` | boolean | No | Limit by enabled issues feature. |
+| `with_merge_requests_enabled` | boolean | No | Limit by enabled merge requests feature. |
+| `with_programming_language` | string | No | Limit by projects which use the given programming language. |
+| `updated_before` | datetime | No | Limit results to projects last updated before the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
+| `updated_after` | datetime | No | Limit results to projects last updated after the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
```json
[
@@ -349,12 +349,12 @@ GET /users/:user_id/projects
"id": 4,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
- "readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-client/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora client"
@@ -457,12 +457,12 @@ GET /users/:user_id/projects
"id": 6,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:brightbox/puppet.git",
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
"web_url": "http://example.com/brightbox/puppet",
- "readme_url": "http://example.com/brightbox/puppet/blob/master/README.md",
+ "readme_url": "http://example.com/brightbox/puppet/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"puppet"
@@ -596,10 +596,10 @@ GET /users/:user_id/contributed_projects
| Attribute | Type | Required | Description |
|-------------------------------|---------|------------------------|-------------|
-| `user_id` | string | **{check-circle}** Yes | The ID or username of the user. |
-| `order_by` | string | **{dotted-circle}** No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at`. |
-| `simple` | boolean | **{dotted-circle}** No | Return only limited fields for each project. Without authentication, this operation is a no-op; only simple fields are returned. |
-| `sort` | string | **{dotted-circle}** No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
+| `user_id` | string | Yes | The ID or username of the user. |
+| `order_by` | string | No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at`. |
+| `simple` | boolean | No | Return only limited fields for each project. Without authentication, this operation is a no-op; only simple fields are returned. |
+| `sort` | string | No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/users/5/contributed_projects"
@@ -613,12 +613,12 @@ Example response:
"id": 4,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
- "readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-client/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora client"
@@ -709,12 +709,12 @@ Example response:
"id": 6,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:brightbox/puppet.git",
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
"web_url": "http://example.com/brightbox/puppet",
- "readme_url": "http://example.com/brightbox/puppet/blob/master/README.md",
+ "readme_url": "http://example.com/brightbox/puppet/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"puppet"
@@ -841,23 +841,23 @@ GET /users/:user_id/starred_projects
| Attribute | Type | Required | Description |
|-------------------------------|---------|------------------------|-------------|
-| `user_id` | string | **{check-circle}** Yes | The ID or username of the user. |
-| `archived` | boolean | **{dotted-circle}** No | Limit by archived status. |
-| `membership` | boolean | **{dotted-circle}** No | Limit by projects that the current user is a member of. |
-| `min_access_level` | integer | **{dotted-circle}** No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
-| `order_by` | string | **{dotted-circle}** No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at`. |
-| `owned` | boolean | **{dotted-circle}** No | Limit by projects explicitly owned by the current user. |
-| `search` | string | **{dotted-circle}** No | Return list of projects matching the search criteria. |
-| `simple` | boolean | **{dotted-circle}** No | Return only limited fields for each project. Without authentication, this operation is a no-op; only simple fields are returned. |
-| `sort` | string | **{dotted-circle}** No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
-| `starred` | boolean | **{dotted-circle}** No | Limit by projects starred by the current user. |
-| `statistics` | boolean | **{dotted-circle}** No | Include project statistics. Available only to users with at least the Reporter role. |
-| `visibility` | string | **{dotted-circle}** No | Limit by visibility `public`, `internal`, or `private`. |
-| `with_custom_attributes` | boolean | **{dotted-circle}** No | Include [custom attributes](custom_attributes.md) in response. _(administrator only)_ |
-| `with_issues_enabled` | boolean | **{dotted-circle}** No | Limit by enabled issues feature. |
-| `with_merge_requests_enabled` | boolean | **{dotted-circle}** No | Limit by enabled merge requests feature. |
-| `updated_before` | datetime | **{dotted-circle}** No | Limit results to projects last updated before the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
-| `updated_after` | datetime | **{dotted-circle}** No | Limit results to projects last updated after the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
+| `user_id` | string | Yes | The ID or username of the user. |
+| `archived` | boolean | No | Limit by archived status. |
+| `membership` | boolean | No | Limit by projects that the current user is a member of. |
+| `min_access_level` | integer | No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
+| `order_by` | string | No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at`. |
+| `owned` | boolean | No | Limit by projects explicitly owned by the current user. |
+| `search` | string | No | Return list of projects matching the search criteria. |
+| `simple` | boolean | No | Return only limited fields for each project. Without authentication, this operation is a no-op; only simple fields are returned. |
+| `sort` | string | No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
+| `starred` | boolean | No | Limit by projects starred by the current user. |
+| `statistics` | boolean | No | Include project statistics. Available only to users with at least the Reporter role. |
+| `visibility` | string | No | Limit by visibility `public`, `internal`, or `private`. |
+| `with_custom_attributes` | boolean | No | Include [custom attributes](custom_attributes.md) in response. _(administrator only)_ |
+| `with_issues_enabled` | boolean | No | Limit by enabled issues feature. |
+| `with_merge_requests_enabled` | boolean | No | Limit by enabled merge requests feature. |
+| `updated_before` | datetime | No | Limit results to projects last updated before the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
+| `updated_after` | datetime | No | Limit results to projects last updated after the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/users/5/starred_projects"
@@ -871,12 +871,12 @@ Example response:
"id": 4,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
- "readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-client/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora client"
@@ -967,12 +967,12 @@ Example response:
"id": 6,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:brightbox/puppet.git",
"http_url_to_repo": "http://example.com/brightbox/puppet.git",
"web_url": "http://example.com/brightbox/puppet",
- "readme_url": "http://example.com/brightbox/puppet/blob/master/README.md",
+ "readme_url": "http://example.com/brightbox/puppet/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"puppet"
@@ -1099,22 +1099,22 @@ GET /projects/:id
| Attribute | Type | Required | Description |
|--------------------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `license` | boolean | **{dotted-circle}** No | Include project license data. |
-| `statistics` | boolean | **{dotted-circle}** No | Include project statistics. Available only to users with at least the Reporter role. |
-| `with_custom_attributes` | boolean | **{dotted-circle}** No | Include [custom attributes](custom_attributes.md) in response. _(administrators only)_ |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `license` | boolean | No | Include project license data. |
+| `statistics` | boolean | No | Include project statistics. Available only to users with at least the Reporter role. |
+| `with_custom_attributes` | boolean | No | Include [custom attributes](custom_attributes.md) in response. _(administrators only)_ |
```json
{
"id": 3,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
- "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
@@ -1182,7 +1182,7 @@ GET /projects/:id
},
"archived": false,
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
- "license_url": "http://example.com/diaspora/diaspora-client/blob/master/LICENSE",
+ "license_url": "http://example.com/diaspora/diaspora-client/blob/main/LICENSE",
"license": {
"key": "lgpl-3.0",
"name": "GNU Lesser General Public License v3.0",
@@ -1305,14 +1305,14 @@ target the upstream project by default.
"path":"gitlab-foss",
"path_with_namespace":"gitlab-org/gitlab-foss",
"created_at":"2013-09-26T06:02:36.000Z",
- "default_branch":"master",
+ "default_branch":"main",
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo":"git@gitlab.com:gitlab-org/gitlab-foss.git",
"http_url_to_repo":"https://gitlab.com/gitlab-org/gitlab-foss.git",
"web_url":"https://gitlab.com/gitlab-org/gitlab-foss",
"avatar_url":"https://gitlab.com/uploads/-/system/project/avatar/13083/logo-extra-whitespace.png",
- "license_url": "https://gitlab.com/gitlab-org/gitlab/-/blob/master/LICENSE",
+ "license_url": "https://gitlab.com/gitlab-org/gitlab/-/blob/main/LICENSE",
"license": {
"key": "mit",
"name": "MIT License",
@@ -1365,9 +1365,9 @@ GET /projects/:id/users
| Attribute | Type | Required | Description |
|--------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `search` | string | **{dotted-circle}** No | Search for specific users. |
-| `skip_users` | integer array | **{dotted-circle}** No | Filter out users with the specified IDs. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `search` | string | No | Search for specific users. |
+| `skip_users` | integer array | No | Filter out users with the specified IDs. |
```json
[
@@ -1400,12 +1400,12 @@ GET /projects/:id/groups
| Attribute | Type | Required | Description |
|-----------------------------|-------------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `search` | string | **{dotted-circle}** No | Search for specific groups. |
-| `shared_min_access_level` | integer | **{dotted-circle}** No | Limit to shared groups with at least this [role (`access_level`)](members.md#roles). |
-| `shared_visible_only` | boolean | **{dotted-circle}** No | Limit to shared groups user has access to. |
-| `skip_groups` | array of integers | **{dotted-circle}** No | Skip the group IDs passed. |
-| `with_shared` | boolean | **{dotted-circle}** No | Include projects shared with this group. Default is `false`. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `search` | string | No | Search for specific groups. |
+| `shared_min_access_level` | integer | No | Limit to shared groups with at least this [role (`access_level`)](members.md#roles). |
+| `shared_visible_only` | boolean | No | Limit to shared groups user has access to. |
+| `skip_groups` | array of integers | No | Skip the group IDs passed. |
+| `with_shared` | boolean | No | Include projects shared with this group. Default is `false`. |
```json
[
@@ -1438,8 +1438,8 @@ GET /projects/:id/share_locations
| Attribute | Type | Required | Description |
|-----------------------------|-------------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `search` | string | **{dotted-circle}** No | Search for specific groups. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `search` | string | No | Search for specific groups. |
```json
[
@@ -1492,77 +1492,77 @@ curl --request POST --header "PRIVATE-TOKEN: <your-token>" \
| Attribute | Type | Required | Description |
|-------------------------------------------------------------|---------|------------------------|-------------|
-| `name` | string | **{check-circle}** Yes (if `path` isn't provided) | The name of the new project. Equals path if not provided. |
-| `path` | string | **{check-circle}** Yes (if `name` isn't provided) | Repository name for new project. Generated based on name if not provided (generated as lowercase with dashes). Starting with GitLab 14.9, path must not start or end with a special character and must not contain consecutive special characters. |
-| `allow_merge_on_skipped_pipeline` | boolean | **{dotted-circle}** No | Set whether or not merge requests can be merged with skipped jobs. |
-| `only_allow_merge_if_all_status_checks_passed` **(ULTIMATE)** | boolean | **{dotted-circle}** No | Indicates that merges of merge requests should be blocked unless all status checks have passed. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369859) in GitLab 15.5 with feature flag `only_allow_merge_if_all_status_checks_passed` disabled by default. |
-| `analytics_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private` or `enabled` |
-| `approvals_before_merge` **(PREMIUM)** | integer | **{dotted-circle}** No | How many approvers should approve merge requests by default. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. |
-| `auto_cancel_pending_pipelines` | string | **{dotted-circle}** No | Auto-cancel pending pipelines. This action toggles between an enabled state and a disabled state; it is not a boolean. |
-| `auto_devops_deploy_strategy` | string | **{dotted-circle}** No | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`). |
-| `auto_devops_enabled` | boolean | **{dotted-circle}** No | Enable Auto DevOps for this project. |
-| `autoclose_referenced_issues` | boolean | **{dotted-circle}** No | Set whether auto-closing referenced issues on default branch. |
-| `avatar` | mixed | **{dotted-circle}** No | Image file for avatar of the project. |
-| `build_git_strategy` | string | **{dotted-circle}** No | The Git strategy. Defaults to `fetch`. |
-| `build_timeout` | integer | **{dotted-circle}** No | The maximum amount of time, in seconds, that a job can run. |
-| `builds_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `ci_config_path` | string | **{dotted-circle}** No | The path to CI configuration file. |
-| `container_expiration_policy_attributes` | hash | **{dotted-circle}** No | Update the image cleanup policy for this project. Accepts: `cadence` (string), `keep_n` (integer), `older_than` (string), `name_regex` (string), `name_regex_delete` (string), `name_regex_keep` (string), `enabled` (boolean). See the [Container Registry](../user/packages/container_registry/reduce_container_registry_storage.md#use-the-cleanup-policy-api) documentation for more information on `cadence`, `keep_n` and `older_than` values. |
-| `container_registry_access_level` | string | **{dotted-circle}** No | Set visibility of container registry, for this project, to one of `disabled`, `private` or `enabled`. |
-| `container_registry_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable container registry for this project. Use `container_registry_access_level` instead. |
-| `default_branch` | string | **{dotted-circle}** No | The [default branch](../user/project/repository/branches/default.md) name. Requires `initialize_with_readme` to be `true`. |
-| `description` | string | **{dotted-circle}** No | Short project description. |
-| `emails_disabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Disable email notifications. Use `emails_enabled` instead|
-| `emails_enabled` | boolean | **{dotted-circle}** No | Enable email notifications. |
-| `external_authorization_classification_label` **(PREMIUM)** | string | **{dotted-circle}** No | The classification label for the project. |
-| `forking_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `group_runners_enabled` | boolean | **{dotted-circle}** No | Enable group runners for this project. |
-| `group_with_project_templates_id` **(PREMIUM)** | integer | **{dotted-circle}** No | For group-level custom templates, specifies ID of group from which all the custom project templates are sourced. Leave empty for instance-level templates. Requires `use_custom_template` to be true. |
-| `import_url` | string | **{dotted-circle}** No | URL to import repository from. When the URL value isn't empty, you must not set `initialize_with_readme` to `true`. Doing so might result in the [following error](https://gitlab.com/gitlab-org/gitlab/-/issues/360266): `not a git repository`. |
-| `initialize_with_readme` | boolean | **{dotted-circle}** No | Whether to create a Git repository with just a `README.md` file. Default is `false`. When this boolean is true, you must not pass `import_url` or other attributes of this endpoint which specify alternative contents for the repository. Doing so might result in the [following error](https://gitlab.com/gitlab-org/gitlab/-/issues/360266): `not a git repository`. |
-| `issues_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `issues_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. |
-| `jobs_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. |
-| `lfs_enabled` | boolean | **{dotted-circle}** No | Enable LFS. |
-| `merge_method` | string | **{dotted-circle}** No | Set the [merge method](#project-merge-method) used. |
-| `merge_pipelines_enabled` | boolean | **{dotted-circle}** No | Enable or disable merge pipelines. |
-| `merge_requests_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `merge_requests_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable merge requests for this project. Use `merge_requests_access_level` instead. |
-| `merge_trains_enabled` | boolean | **{dotted-circle}** No | Enable or disable merge trains. |
-| `mirror_trigger_builds` **(PREMIUM)** | boolean | **{dotted-circle}** No | Pull mirroring triggers builds. |
-| `mirror` **(PREMIUM)** | boolean | **{dotted-circle}** No | Enables pull mirroring in a project. |
-| `namespace_id` | integer | **{dotted-circle}** No | Namespace for the new project (defaults to the current user's namespace). |
-| `only_allow_merge_if_all_discussions_are_resolved` | boolean | **{dotted-circle}** No | Set whether merge requests can only be merged when all the discussions are resolved. |
-| `only_allow_merge_if_pipeline_succeeds` | boolean | **{dotted-circle}** No | Set whether merge requests can only be merged with successful pipelines. This setting is named [**Pipelines must succeed**](../user/project/merge_requests/merge_when_pipeline_succeeds.md#require-a-successful-pipeline-for-merge) in the project settings. |
-| `packages_enabled` | boolean | **{dotted-circle}** No | Enable or disable packages repository feature. |
-| `pages_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, `enabled`, or `public`. |
-| `printing_merge_request_link_enabled` | boolean | **{dotted-circle}** No | Show link to create/view merge request when pushing from the command line. |
-| `public_builds` | boolean | **{dotted-circle}** No | If `true`, jobs can be viewed by non-project members. |
-| `releases_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `environments_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `feature_flags_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `infrastructure_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `monitor_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `remove_source_branch_after_merge` | boolean | **{dotted-circle}** No | Enable `Delete source branch` option by default for all new merge requests. |
-| `repository_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `repository_storage` | string | **{dotted-circle}** No | Which storage shard the repository is on. _(administrator only)_ |
-| `request_access_enabled` | boolean | **{dotted-circle}** No | Allow users to request member access. |
-| `requirements_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private` or `enabled` |
-| `resolve_outdated_diff_discussions` | boolean | **{dotted-circle}** No | Automatically resolve merge request diffs discussions on lines changed with a push. |
-| `security_and_compliance_access_level` | string | **{dotted-circle}** No | (GitLab 14.9 and later) Security and compliance access level. One of `disabled`, `private`, or `enabled`. |
-| `shared_runners_enabled` | boolean | **{dotted-circle}** No | Enable shared runners for this project. |
-| `show_default_award_emojis` | boolean | **{dotted-circle}** No | Show default award emojis. |
-| `snippets_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `snippets_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable snippets for this project. Use `snippets_access_level` instead. |
-| `squash_option` | string | **{dotted-circle}** No | One of `never`, `always`, `default_on`, or `default_off`. |
-| `tag_list` | array | **{dotted-circle}** No | _([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0)_ The list of tags for a project; put array of tags, that should be finally assigned to a project. Use `topics` instead. |
-| `template_name` | string | **{dotted-circle}** No | When used without `use_custom_template`, name of a [built-in project template](../user/project/index.md#create-a-project-from-a-built-in-template). When used with `use_custom_template`, name of a custom project template. |
-| `template_project_id` **(PREMIUM)** | integer | **{dotted-circle}** No | When used with `use_custom_template`, project ID of a custom project template. Using a project ID is preferable to using `template_name` since `template_name` may be ambiguous. |
-| `topics` | array | **{dotted-circle}** No | The list of topics for a project; put array of topics, that should be finally assigned to a project. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0.)_ |
-| `use_custom_template` **(PREMIUM)** | boolean | **{dotted-circle}** No | Use either custom [instance](../administration/custom_project_templates.md) or [group](../user/group/custom_project_templates.md) (with `group_with_project_templates_id`) project template. |
-| `visibility` | string | **{dotted-circle}** No | See [project visibility level](#project-visibility-level). |
-| `wiki_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `wiki_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable wiki for this project. Use `wiki_access_level` instead. |
+| `name` | string | Yes (if `path` isn't provided) | The name of the new project. Equals path if not provided. |
+| `path` | string | Yes (if `name` isn't provided) | Repository name for new project. Generated based on name if not provided (generated as lowercase with dashes). Starting with GitLab 14.9, path must not start or end with a special character and must not contain consecutive special characters. |
+| `allow_merge_on_skipped_pipeline` | boolean | No | Set whether or not merge requests can be merged with skipped jobs. |
+| `only_allow_merge_if_all_status_checks_passed` **(ULTIMATE ALL)** | boolean | No | Indicates that merges of merge requests should be blocked unless all status checks have passed. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369859) in GitLab 15.5 with feature flag `only_allow_merge_if_all_status_checks_passed` disabled by default. |
+| `analytics_access_level` | string | No | One of `disabled`, `private` or `enabled` |
+| `approvals_before_merge` **(PREMIUM ALL)** | integer | No | How many approvers should approve merge requests by default. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. |
+| `auto_cancel_pending_pipelines` | string | No | Auto-cancel pending pipelines. This action toggles between an enabled state and a disabled state; it is not a boolean. |
+| `auto_devops_deploy_strategy` | string | No | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`). |
+| `auto_devops_enabled` | boolean | No | Enable Auto DevOps for this project. |
+| `autoclose_referenced_issues` | boolean | No | Set whether auto-closing referenced issues on default branch. |
+| `avatar` | mixed | No | Image file for avatar of the project. |
+| `build_git_strategy` | string | No | The Git strategy. Defaults to `fetch`. |
+| `build_timeout` | integer | No | The maximum amount of time, in seconds, that a job can run. |
+| `builds_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `ci_config_path` | string | No | The path to CI configuration file. |
+| `container_expiration_policy_attributes` | hash | No | Update the image cleanup policy for this project. Accepts: `cadence` (string), `keep_n` (integer), `older_than` (string), `name_regex` (string), `name_regex_delete` (string), `name_regex_keep` (string), `enabled` (boolean). See the [Container Registry](../user/packages/container_registry/reduce_container_registry_storage.md#use-the-cleanup-policy-api) documentation for more information on `cadence`, `keep_n` and `older_than` values. |
+| `container_registry_access_level` | string | No | Set visibility of container registry, for this project, to one of `disabled`, `private` or `enabled`. |
+| `container_registry_enabled` | boolean | No | _(Deprecated)_ Enable container registry for this project. Use `container_registry_access_level` instead. |
+| `default_branch` | string | No | The [default branch](../user/project/repository/branches/default.md) name. Requires `initialize_with_readme` to be `true`. |
+| `description` | string | No | Short project description. |
+| `emails_disabled` | boolean | No | _(Deprecated)_ Disable email notifications. Use `emails_enabled` instead|
+| `emails_enabled` | boolean | No | Enable email notifications. |
+| `external_authorization_classification_label` **(PREMIUM ALL)** | string | No | The classification label for the project. |
+| `forking_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `group_runners_enabled` | boolean | No | Enable group runners for this project. |
+| `group_with_project_templates_id` **(PREMIUM ALL)** | integer | No | For group-level custom templates, specifies ID of group from which all the custom project templates are sourced. Leave empty for instance-level templates. Requires `use_custom_template` to be true. |
+| `import_url` | string | No | URL to import repository from. When the URL value isn't empty, you must not set `initialize_with_readme` to `true`. Doing so might result in the [following error](https://gitlab.com/gitlab-org/gitlab/-/issues/360266): `not a git repository`. |
+| `initialize_with_readme` | boolean | No | Whether to create a Git repository with just a `README.md` file. Default is `false`. When this boolean is true, you must not pass `import_url` or other attributes of this endpoint which specify alternative contents for the repository. Doing so might result in the [following error](https://gitlab.com/gitlab-org/gitlab/-/issues/360266): `not a git repository`. |
+| `issues_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `issues_enabled` | boolean | No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. |
+| `jobs_enabled` | boolean | No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. |
+| `lfs_enabled` | boolean | No | Enable LFS. |
+| `merge_method` | string | No | Set the [merge method](#project-merge-method) used. |
+| `merge_pipelines_enabled` | boolean | No | Enable or disable merge pipelines. |
+| `merge_requests_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `merge_requests_enabled` | boolean | No | _(Deprecated)_ Enable merge requests for this project. Use `merge_requests_access_level` instead. |
+| `merge_trains_enabled` | boolean | No | Enable or disable merge trains. |
+| `mirror_trigger_builds` **(PREMIUM ALL)** | boolean | No | Pull mirroring triggers builds. |
+| `mirror` **(PREMIUM ALL)** | boolean | No | Enables pull mirroring in a project. |
+| `namespace_id` | integer | No | Namespace for the new project (defaults to the current user's namespace). |
+| `only_allow_merge_if_all_discussions_are_resolved` | boolean | No | Set whether merge requests can only be merged when all the discussions are resolved. |
+| `only_allow_merge_if_pipeline_succeeds` | boolean | No | Set whether merge requests can only be merged with successful pipelines. This setting is named [**Pipelines must succeed**](../user/project/merge_requests/merge_when_pipeline_succeeds.md#require-a-successful-pipeline-for-merge) in the project settings. |
+| `packages_enabled` | boolean | No | Enable or disable packages repository feature. |
+| `pages_access_level` | string | No | One of `disabled`, `private`, `enabled`, or `public`. |
+| `printing_merge_request_link_enabled` | boolean | No | Show link to create/view merge request when pushing from the command line. |
+| `public_builds` | boolean | No | If `true`, jobs can be viewed by non-project members. |
+| `releases_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `environments_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `feature_flags_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `infrastructure_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `monitor_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `remove_source_branch_after_merge` | boolean | No | Enable `Delete source branch` option by default for all new merge requests. |
+| `repository_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `repository_storage` | string | No | Which storage shard the repository is on. _(administrator only)_ |
+| `request_access_enabled` | boolean | No | Allow users to request member access. |
+| `requirements_access_level` | string | No | One of `disabled`, `private` or `enabled` |
+| `resolve_outdated_diff_discussions` | boolean | No | Automatically resolve merge request diffs discussions on lines changed with a push. |
+| `security_and_compliance_access_level` | string | No | (GitLab 14.9 and later) Security and compliance access level. One of `disabled`, `private`, or `enabled`. |
+| `shared_runners_enabled` | boolean | No | Enable shared runners for this project. |
+| `show_default_award_emojis` | boolean | No | Show default award emojis. |
+| `snippets_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `snippets_enabled` | boolean | No | _(Deprecated)_ Enable snippets for this project. Use `snippets_access_level` instead. |
+| `squash_option` | string | No | One of `never`, `always`, `default_on`, or `default_off`. |
+| `tag_list` | array | No | _([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0)_ The list of tags for a project; put array of tags, that should be finally assigned to a project. Use `topics` instead. |
+| `template_name` | string | No | When used without `use_custom_template`, name of a [built-in project template](../user/project/index.md#create-a-project-from-a-built-in-template). When used with `use_custom_template`, name of a custom project template. |
+| `template_project_id` **(PREMIUM ALL)** | integer | No | When used with `use_custom_template`, project ID of a custom project template. Using a project ID is preferable to using `template_name` since `template_name` may be ambiguous. |
+| `topics` | array | No | The list of topics for a project; put array of topics, that should be finally assigned to a project. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0.)_ |
+| `use_custom_template` **(PREMIUM ALL)** | boolean | No | Use either custom [instance](../administration/custom_project_templates.md) or [group](../user/group/custom_project_templates.md) (with `group_with_project_templates_id`) project template. |
+| `visibility` | string | No | See [project visibility level](#project-visibility-level). |
+| `wiki_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `wiki_enabled` | boolean | No | _(Deprecated)_ Enable wiki for this project. Use `wiki_access_level` instead. |
## Create project for user
@@ -1580,79 +1580,79 @@ POST /projects/user/:user_id
| Attribute | Type | Required | Description |
|-------------------------------------------------------------|---------|------------------------|-------------|
-| `user_id` | integer | **{check-circle}** Yes | The user ID of the project owner. |
-| `name` | string | **{check-circle}** Yes | The name of the new project. |
-| `allow_merge_on_skipped_pipeline` | boolean | **{dotted-circle}** No | Set whether or not merge requests can be merged with skipped jobs. |
-| `only_allow_merge_if_all_status_checks_passed` **(ULTIMATE)** | boolean | **{dotted-circle}** No | Indicates that merges of merge requests should be blocked unless all status checks have passed. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369859) in GitLab 15.5 with feature flag `only_allow_merge_if_all_status_checks_passed` disabled by default. |
-| `analytics_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private` or `enabled` |
-| `approvals_before_merge` **(PREMIUM)** | integer | **{dotted-circle}** No | How many approvers should approve merge requests by default. [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). |
-| `auto_cancel_pending_pipelines` | string | **{dotted-circle}** No | Auto-cancel pending pipelines. This action toggles between an enabled state and a disabled state; it is not a boolean. |
-| `auto_devops_deploy_strategy` | string | **{dotted-circle}** No | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`). |
-| `auto_devops_enabled` | boolean | **{dotted-circle}** No | Enable Auto DevOps for this project. |
-| `autoclose_referenced_issues` | boolean | **{dotted-circle}** No | Set whether auto-closing referenced issues on default branch. |
-| `avatar` | mixed | **{dotted-circle}** No | Image file for avatar of the project. |
-| `build_git_strategy` | string | **{dotted-circle}** No | The Git strategy. Defaults to `fetch`. |
-| `build_timeout` | integer | **{dotted-circle}** No | The maximum amount of time, in seconds, that a job can run. |
-| `builds_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `ci_config_path` | string | **{dotted-circle}** No | The path to CI configuration file. |
-| `container_registry_access_level` | string | **{dotted-circle}** No | Set visibility of container registry, for this project, to one of `disabled`, `private` or `enabled`. |
-| `container_registry_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable container registry for this project. Use `container_registry_access_level` instead. |
-| `default_branch` | string | **{dotted-circle}** No | The [default branch](../user/project/repository/branches/default.md) name. Requires `initialize_with_readme` to be `true`. |
-| `description` | string | **{dotted-circle}** No | Short project description. |
-| `emails_disabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Disable email notifications. Use `emails_enabled` instead|
-| `emails_enabled` | boolean | **{dotted-circle}** No | Enable email notifications. |
-| `enforce_auth_checks_on_uploads` | boolean | **{dotted-circle}** No | Enforce [auth checks](../security/user_file_uploads.md#enable-authorization-checks-for-all-media-files) on uploads. |
-| `external_authorization_classification_label` **(PREMIUM)** | string | **{dotted-circle}** No | The classification label for the project. |
-| `forking_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `group_runners_enabled` | boolean | **{dotted-circle}** No | Enable group runners for this project. |
-| `group_with_project_templates_id` **(PREMIUM)** | integer | **{dotted-circle}** No | For group-level custom templates, specifies ID of group from which all the custom project templates are sourced. Leave empty for instance-level templates. Requires `use_custom_template` to be true. |
-| `import_url` | string | **{dotted-circle}** No | URL to import repository from. |
-| `initialize_with_readme` | boolean | **{dotted-circle}** No | `false` by default. |
-| `issues_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `issues_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. |
-| `jobs_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. |
-| `lfs_enabled` | boolean | **{dotted-circle}** No | Enable LFS. |
-| `merge_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md) used to create merge commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5.)_ |
-| `merge_method` | string | **{dotted-circle}** No | Set the [merge method](#project-merge-method) used. |
-| `merge_requests_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `merge_requests_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable merge requests for this project. Use `merge_requests_access_level` instead. |
-| `mirror_trigger_builds` **(PREMIUM)** | boolean | **{dotted-circle}** No | Pull mirroring triggers builds. |
-| `mirror` **(PREMIUM)** | boolean | **{dotted-circle}** No | Enables pull mirroring in a project. |
-| `namespace_id` | integer | **{dotted-circle}** No | Namespace for the new project (defaults to the current user's namespace). |
-| `only_allow_merge_if_all_discussions_are_resolved` | boolean | **{dotted-circle}** No | Set whether merge requests can only be merged when all the discussions are resolved. |
-| `only_allow_merge_if_pipeline_succeeds` | boolean | **{dotted-circle}** No | Set whether merge requests can only be merged with successful jobs. |
-| `packages_enabled` | boolean | **{dotted-circle}** No | Enable or disable packages repository feature. |
-| `pages_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, `enabled`, or `public`. |
-| `path` | string | **{dotted-circle}** No | Custom repository name for new project. By default generated based on name. |
-| `printing_merge_request_link_enabled` | boolean | **{dotted-circle}** No | Show link to create/view merge request when pushing from the command line. |
-| `public_builds` | boolean | **{dotted-circle}** No | If `true`, jobs can be viewed by non-project-members. |
-| `releases_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `environments_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `feature_flags_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `infrastructure_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `monitor_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `remove_source_branch_after_merge` | boolean | **{dotted-circle}** No | Enable `Delete source branch` option by default for all new merge requests. |
-| `repository_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `repository_storage` | string | **{dotted-circle}** No | Which storage shard the repository is on. _(administrators only)_ |
-| `request_access_enabled` | boolean | **{dotted-circle}** No | Allow users to request member access. |
-| `requirements_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, `enabled` or `public` |
-| `resolve_outdated_diff_discussions` | boolean | **{dotted-circle}** No | Automatically resolve merge request diffs discussions on lines changed with a push. |
-| `security_and_compliance_access_level` | string | **{dotted-circle}** No | (GitLab 14.9 and later) Security and compliance access level. One of `disabled`, `private`, or `enabled`. |
-| `shared_runners_enabled` | boolean | **{dotted-circle}** No | Enable shared runners for this project. |
-| `show_default_award_emojis` | boolean | **{dotted-circle}** No | Show default award emojis. |
-| `snippets_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `snippets_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable snippets for this project. Use `snippets_access_level` instead. |
-| `issue_branch_template` | string | **{dotted-circle}** No | Template used to suggest names for [branches created from issues](../user/project/merge_requests/creating_merge_requests.md#from-an-issue). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21243) in GitLab 15.6.)_ |
-| `squash_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md) used to create squash commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.)_ |
-| `squash_option` | string | **{dotted-circle}** No | One of `never`, `always`, `default_on`, or `default_off`. |
-| `suggestion_commit_message` | string | **{dotted-circle}** No | The commit message used to apply merge request [suggestions](../user/project/merge_requests/reviews/suggestions.md). |
-| `tag_list` | array | **{dotted-circle}** No | _([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0)_ The list of tags for a project; put array of tags, that should be finally assigned to a project. Use `topics` instead. |
-| `template_name` | string | **{dotted-circle}** No | When used without `use_custom_template`, name of a [built-in project template](../user/project/index.md#create-a-project-from-a-built-in-template). When used with `use_custom_template`, name of a custom project template. |
-| `topics` | array | **{dotted-circle}** No | The list of topics for the project. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0.)_ |
-| `use_custom_template` **(PREMIUM)** | boolean | **{dotted-circle}** No | Use either custom [instance](../administration/custom_project_templates.md) or [group](../user/group/custom_project_templates.md) (with `group_with_project_templates_id`) project template. |
-| `visibility` | string | **{dotted-circle}** No | See [project visibility level](#project-visibility-level). |
-| `wiki_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `wiki_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable wiki for this project. Use `wiki_access_level` instead. |
+| `user_id` | integer | Yes | The user ID of the project owner. |
+| `name` | string | Yes | The name of the new project. |
+| `allow_merge_on_skipped_pipeline` | boolean | No | Set whether or not merge requests can be merged with skipped jobs. |
+| `only_allow_merge_if_all_status_checks_passed` **(ULTIMATE ALL)** | boolean | No | Indicates that merges of merge requests should be blocked unless all status checks have passed. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369859) in GitLab 15.5 with feature flag `only_allow_merge_if_all_status_checks_passed` disabled by default. |
+| `analytics_access_level` | string | No | One of `disabled`, `private` or `enabled` |
+| `approvals_before_merge` **(PREMIUM ALL)** | integer | No | How many approvers should approve merge requests by default. [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). |
+| `auto_cancel_pending_pipelines` | string | No | Auto-cancel pending pipelines. This action toggles between an enabled state and a disabled state; it is not a boolean. |
+| `auto_devops_deploy_strategy` | string | No | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`). |
+| `auto_devops_enabled` | boolean | No | Enable Auto DevOps for this project. |
+| `autoclose_referenced_issues` | boolean | No | Set whether auto-closing referenced issues on default branch. |
+| `avatar` | mixed | No | Image file for avatar of the project. |
+| `build_git_strategy` | string | No | The Git strategy. Defaults to `fetch`. |
+| `build_timeout` | integer | No | The maximum amount of time, in seconds, that a job can run. |
+| `builds_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `ci_config_path` | string | No | The path to CI configuration file. |
+| `container_registry_access_level` | string | No | Set visibility of container registry, for this project, to one of `disabled`, `private` or `enabled`. |
+| `container_registry_enabled` | boolean | No | _(Deprecated)_ Enable container registry for this project. Use `container_registry_access_level` instead. |
+| `default_branch` | string | No | The [default branch](../user/project/repository/branches/default.md) name. Requires `initialize_with_readme` to be `true`. |
+| `description` | string | No | Short project description. |
+| `emails_disabled` | boolean | No | _(Deprecated)_ Disable email notifications. Use `emails_enabled` instead|
+| `emails_enabled` | boolean | No | Enable email notifications. |
+| `enforce_auth_checks_on_uploads` | boolean | No | Enforce [auth checks](../security/user_file_uploads.md#enable-authorization-checks-for-all-media-files) on uploads. |
+| `external_authorization_classification_label` **(PREMIUM ALL)** | string | No | The classification label for the project. |
+| `forking_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `group_runners_enabled` | boolean | No | Enable group runners for this project. |
+| `group_with_project_templates_id` **(PREMIUM ALL)** | integer | No | For group-level custom templates, specifies ID of group from which all the custom project templates are sourced. Leave empty for instance-level templates. Requires `use_custom_template` to be true. |
+| `import_url` | string | No | URL to import repository from. |
+| `initialize_with_readme` | boolean | No | `false` by default. |
+| `issues_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `issues_enabled` | boolean | No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. |
+| `jobs_enabled` | boolean | No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. |
+| `lfs_enabled` | boolean | No | Enable LFS. |
+| `merge_commit_template` | string | No | [Template](../user/project/merge_requests/commit_templates.md) used to create merge commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5.)_ |
+| `merge_method` | string | No | Set the [merge method](#project-merge-method) used. |
+| `merge_requests_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `merge_requests_enabled` | boolean | No | _(Deprecated)_ Enable merge requests for this project. Use `merge_requests_access_level` instead. |
+| `mirror_trigger_builds` **(PREMIUM ALL)** | boolean | No | Pull mirroring triggers builds. |
+| `mirror` **(PREMIUM ALL)** | boolean | No | Enables pull mirroring in a project. |
+| `namespace_id` | integer | No | Namespace for the new project (defaults to the current user's namespace). |
+| `only_allow_merge_if_all_discussions_are_resolved` | boolean | No | Set whether merge requests can only be merged when all the discussions are resolved. |
+| `only_allow_merge_if_pipeline_succeeds` | boolean | No | Set whether merge requests can only be merged with successful jobs. |
+| `packages_enabled` | boolean | No | Enable or disable packages repository feature. |
+| `pages_access_level` | string | No | One of `disabled`, `private`, `enabled`, or `public`. |
+| `path` | string | No | Custom repository name for new project. By default generated based on name. |
+| `printing_merge_request_link_enabled` | boolean | No | Show link to create/view merge request when pushing from the command line. |
+| `public_builds` | boolean | No | If `true`, jobs can be viewed by non-project-members. |
+| `releases_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `environments_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `feature_flags_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `infrastructure_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `monitor_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `remove_source_branch_after_merge` | boolean | No | Enable `Delete source branch` option by default for all new merge requests. |
+| `repository_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `repository_storage` | string | No | Which storage shard the repository is on. _(administrators only)_ |
+| `request_access_enabled` | boolean | No | Allow users to request member access. |
+| `requirements_access_level` | string | No | One of `disabled`, `private`, `enabled` or `public` |
+| `resolve_outdated_diff_discussions` | boolean | No | Automatically resolve merge request diffs discussions on lines changed with a push. |
+| `security_and_compliance_access_level` | string | No | (GitLab 14.9 and later) Security and compliance access level. One of `disabled`, `private`, or `enabled`. |
+| `shared_runners_enabled` | boolean | No | Enable shared runners for this project. |
+| `show_default_award_emojis` | boolean | No | Show default award emojis. |
+| `snippets_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `snippets_enabled` | boolean | No | _(Deprecated)_ Enable snippets for this project. Use `snippets_access_level` instead. |
+| `issue_branch_template` | string | No | Template used to suggest names for [branches created from issues](../user/project/merge_requests/creating_merge_requests.md#from-an-issue). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21243) in GitLab 15.6.)_ |
+| `squash_commit_template` | string | No | [Template](../user/project/merge_requests/commit_templates.md) used to create squash commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.)_ |
+| `squash_option` | string | No | One of `never`, `always`, `default_on`, or `default_off`. |
+| `suggestion_commit_message` | string | No | The commit message used to apply merge request [suggestions](../user/project/merge_requests/reviews/suggestions.md). |
+| `tag_list` | array | No | _([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0)_ The list of tags for a project; put array of tags, that should be finally assigned to a project. Use `topics` instead. |
+| `template_name` | string | No | When used without `use_custom_template`, name of a [built-in project template](../user/project/index.md#create-a-project-from-a-built-in-template). When used with `use_custom_template`, name of a custom project template. |
+| `topics` | array | No | The list of topics for the project. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0.)_ |
+| `use_custom_template` **(PREMIUM ALL)** | boolean | No | Use either custom [instance](../administration/custom_project_templates.md) or [group](../user/group/custom_project_templates.md) (with `group_with_project_templates_id`) project template. |
+| `visibility` | string | No | See [project visibility level](#project-visibility-level). |
+| `wiki_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `wiki_enabled` | boolean | No | _(Deprecated)_ Enable wiki for this project. Use `wiki_access_level` instead. |
## Edit project
@@ -1681,92 +1681,92 @@ Supported attributes:
| Attribute | Type | Required | Description |
|-------------------------------------------------------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `allow_merge_on_skipped_pipeline` | boolean | **{dotted-circle}** No | Set whether or not merge requests can be merged with skipped jobs. |
-| `allow_pipeline_trigger_approve_deployment` **(PREMIUM)** | boolean | **{dotted-circle}** No | Set whether or not a pipeline triggerer is allowed to approve deployments. |
-| `only_allow_merge_if_all_status_checks_passed` **(ULTIMATE)** | boolean | **{dotted-circle}** No | Indicates that merges of merge requests should be blocked unless all status checks have passed. Defaults to false.<br/><br/>[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369859) in GitLab 15.5 with feature flag `only_allow_merge_if_all_status_checks_passed` disabled by default. The feature flag was enabled by default in GitLab 15.9. |
-| `analytics_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private` or `enabled` |
-| `approvals_before_merge` **(PREMIUM)** | integer | **{dotted-circle}** No | How many approvers should approve merge requests by default. [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). |
-| `auto_cancel_pending_pipelines` | string | **{dotted-circle}** No | Auto-cancel pending pipelines. This action toggles between an enabled state and a disabled state; it is not a boolean. |
-| `auto_devops_deploy_strategy` | string | **{dotted-circle}** No | Auto Deploy strategy (`continuous`, `manual`, or `timed_incremental`). |
-| `auto_devops_enabled` | boolean | **{dotted-circle}** No | Enable Auto DevOps for this project. |
-| `autoclose_referenced_issues` | boolean | **{dotted-circle}** No | Set whether auto-closing referenced issues on default branch. |
-| `avatar` | mixed | **{dotted-circle}** No | Image file for avatar of the project. |
-| `build_git_strategy` | string | **{dotted-circle}** No | The Git strategy. Defaults to `fetch`. |
-| `build_timeout` | integer | **{dotted-circle}** No | The maximum amount of time, in seconds, that a job can run. |
-| `builds_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `ci_config_path` | string | **{dotted-circle}** No | The path to CI configuration file. |
-| `ci_default_git_depth` | integer | **{dotted-circle}** No | Default number of revisions for [shallow cloning](../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone). |
-| `ci_forward_deployment_enabled` | boolean | **{dotted-circle}** No | Enable or disable [prevent outdated deployment jobs](../ci/pipelines/settings.md#prevent-outdated-deployment-jobs). |
-| `ci_forward_deployment_rollback_allowed` | boolean | **{dotted-circle}** No | Enable or disable [allow job retries for rollback deployments](../ci/pipelines/settings.md#prevent-outdated-deployment-jobs). |
-| `ci_allow_fork_pipelines_to_run_in_parent_project` | boolean | **{dotted-circle}** No | Enable or disable [running pipelines in the parent project for merge requests from forks](../ci/pipelines/merge_request_pipelines.md#run-pipelines-in-the-parent-project). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325189) in GitLab 15.3.)_ |
-| `ci_separated_caches` | boolean | **{dotted-circle}** No | Set whether or not caches should be [separated](../ci/caching/index.md#cache-key-names) by branch protection status. |
-| `container_expiration_policy_attributes` | hash | **{dotted-circle}** No | Update the image cleanup policy for this project. Accepts: `cadence` (string), `keep_n` (integer), `older_than` (string), `name_regex` (string), `name_regex_delete` (string), `name_regex_keep` (string), `enabled` (boolean). |
-| `container_registry_access_level` | string | **{dotted-circle}** No | Set visibility of container registry, for this project, to one of `disabled`, `private` or `enabled`. |
-| `container_registry_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable container registry for this project. Use `container_registry_access_level` instead. |
-| `default_branch` | string | **{dotted-circle}** No | The [default branch](../user/project/repository/branches/default.md) name. |
-| `description` | string | **{dotted-circle}** No | Short project description. |
-| `emails_disabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Disable email notifications. Use `emails_enabled` instead|
-| `emails_enabled` | boolean | **{dotted-circle}** No | Enable email notifications. |
-| `enforce_auth_checks_on_uploads` | boolean | **{dotted-circle}** No | Enforce [auth checks](../security/user_file_uploads.md#enable-authorization-checks-for-all-media-files) on uploads. |
-| `external_authorization_classification_label` **(PREMIUM)** | string | **{dotted-circle}** No | The classification label for the project. |
-| `forking_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `group_runners_enabled` | boolean | **{dotted-circle}** No | Enable group runners for this project. |
-| `import_url` | string | **{dotted-circle}** No | URL the repository was imported from. |
-| `issues_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `issues_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. |
-| `issues_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for Issues. Description is parsed with GitLab Flavored Markdown. See [Templates for issues and merge requests](#templates-for-issues-and-merge-requests). |
-| `jobs_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. |
-| `keep_latest_artifact` | boolean | **{dotted-circle}** No | Disable or enable the ability to keep the latest artifact for this project. |
-| `lfs_enabled` | boolean | **{dotted-circle}** No | Enable LFS. |
-| `merge_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md) used to create merge commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5.)_ |
-| `merge_method` | string | **{dotted-circle}** No | Set the [merge method](#project-merge-method) used. |
-| `merge_pipelines_enabled` | boolean | **{dotted-circle}** No | Enable or disable merge pipelines. |
-| `merge_requests_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `merge_requests_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable merge requests for this project. Use `merge_requests_access_level` instead. |
-| `merge_requests_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for merge requests. Description is parsed with GitLab Flavored Markdown. See [Templates for issues and merge requests](#templates-for-issues-and-merge-requests). |
-| `merge_trains_enabled` | boolean | **{dotted-circle}** No | Enable or disable merge trains. |
-| `mirror_overwrites_diverged_branches` **(PREMIUM)** | boolean | **{dotted-circle}** No | Pull mirror overwrites diverged branches. |
-| `mirror_trigger_builds` **(PREMIUM)** | boolean | **{dotted-circle}** No | Pull mirroring triggers builds. |
-| `mirror_user_id` **(PREMIUM)** | integer | **{dotted-circle}** No | User responsible for all the activity surrounding a pull mirror event. _(administrators only)_ |
-| `mirror` **(PREMIUM)** | boolean | **{dotted-circle}** No | Enables pull mirroring in a project. |
-| `mr_default_target_self` | boolean | **{dotted-circle}** No | For forked projects, target merge requests to this project. If `false`, the target is the upstream project. |
-| `name` | string | **{dotted-circle}** No | The name of the project. |
-| `only_allow_merge_if_all_discussions_are_resolved` | boolean | **{dotted-circle}** No | Set whether merge requests can only be merged when all the discussions are resolved. |
-| `only_allow_merge_if_pipeline_succeeds` | boolean | **{dotted-circle}** No | Set whether merge requests can only be merged with successful jobs. |
-| `only_mirror_protected_branches` **(PREMIUM)** | boolean | **{dotted-circle}** No | Only mirror protected branches. |
-| `packages_enabled` | boolean | **{dotted-circle}** No | Enable or disable packages repository feature. |
-| `pages_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, `enabled`, or `public`. |
-| `path` | string | **{dotted-circle}** No | Custom repository name for the project. By default generated based on name. |
-| `printing_merge_request_link_enabled` | boolean | **{dotted-circle}** No | Show link to create/view merge request when pushing from the command line. |
-| `public_builds` | boolean | **{dotted-circle}** No | If `true`, jobs can be viewed by non-project members. |
-| `releases_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `environments_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `feature_flags_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `infrastructure_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `monitor_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `remove_source_branch_after_merge` | boolean | **{dotted-circle}** No | Enable `Delete source branch` option by default for all new merge requests. |
-| `repository_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `repository_storage` | string | **{dotted-circle}** No | Which storage shard the repository is on. _(administrators only)_ |
-| `request_access_enabled` | boolean | **{dotted-circle}** No | Allow users to request member access. |
-| `requirements_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, `enabled` or `public` |
-| `resolve_outdated_diff_discussions` | boolean | **{dotted-circle}** No | Automatically resolve merge request diffs discussions on lines changed with a push. |
-| `restrict_user_defined_variables` | boolean | **{dotted-circle}** No | Allow only users with the Maintainer role to pass user-defined variables when triggering a pipeline. For example when the pipeline is triggered in the UI, with the API, or by a trigger token. |
-| `security_and_compliance_access_level` | string | **{dotted-circle}** No | (GitLab 14.9 and later) Security and compliance access level. One of `disabled`, `private`, or `enabled`. |
-| `service_desk_enabled` | boolean | **{dotted-circle}** No | Enable or disable Service Desk feature. |
-| `shared_runners_enabled` | boolean | **{dotted-circle}** No | Enable shared runners for this project. |
-| `show_default_award_emojis` | boolean | **{dotted-circle}** No | Show default award emojis. |
-| `snippets_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `snippets_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable snippets for this project. Use `snippets_access_level` instead. |
-| `issue_branch_template` | string | **{dotted-circle}** No | Template used to suggest names for [branches created from issues](../user/project/merge_requests/creating_merge_requests.md#from-an-issue). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21243) in GitLab 15.6.)_ |
-| `squash_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md) used to create squash commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.)_ |
-| `squash_option` | string | **{dotted-circle}** No | One of `never`, `always`, `default_on`, or `default_off`. |
-| `suggestion_commit_message` | string | **{dotted-circle}** No | The commit message used to apply merge request suggestions. |
-| `tag_list` | array | **{dotted-circle}** No | _([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0)_ The list of tags for a project; put array of tags, that should be finally assigned to a project. Use `topics` instead. |
-| `topics` | array | **{dotted-circle}** No | The list of topics for the project. This replaces any existing topics that are already added to the project. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0.)_ |
-| `visibility` | string | **{dotted-circle}** No | See [project visibility level](#project-visibility-level). |
-| `wiki_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
-| `wiki_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable wiki for this project. Use `wiki_access_level` instead. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `allow_merge_on_skipped_pipeline` | boolean | No | Set whether or not merge requests can be merged with skipped jobs. |
+| `allow_pipeline_trigger_approve_deployment` **(PREMIUM ALL)** | boolean | No | Set whether or not a pipeline triggerer is allowed to approve deployments. |
+| `only_allow_merge_if_all_status_checks_passed` **(ULTIMATE ALL)** | boolean | No | Indicates that merges of merge requests should be blocked unless all status checks have passed. Defaults to false.<br/><br/>[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369859) in GitLab 15.5 with feature flag `only_allow_merge_if_all_status_checks_passed` disabled by default. The feature flag was enabled by default in GitLab 15.9. |
+| `analytics_access_level` | string | No | One of `disabled`, `private` or `enabled` |
+| `approvals_before_merge` **(PREMIUM ALL)** | integer | No | How many approvers should approve merge requests by default. [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/353097) in GitLab 16.0. To configure approval rules, see [Merge request approvals API](merge_request_approvals.md). |
+| `auto_cancel_pending_pipelines` | string | No | Auto-cancel pending pipelines. This action toggles between an enabled state and a disabled state; it is not a boolean. |
+| `auto_devops_deploy_strategy` | string | No | Auto Deploy strategy (`continuous`, `manual`, or `timed_incremental`). |
+| `auto_devops_enabled` | boolean | No | Enable Auto DevOps for this project. |
+| `autoclose_referenced_issues` | boolean | No | Set whether auto-closing referenced issues on default branch. |
+| `avatar` | mixed | No | Image file for avatar of the project. |
+| `build_git_strategy` | string | No | The Git strategy. Defaults to `fetch`. |
+| `build_timeout` | integer | No | The maximum amount of time, in seconds, that a job can run. |
+| `builds_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `ci_config_path` | string | No | The path to CI configuration file. |
+| `ci_default_git_depth` | integer | No | Default number of revisions for [shallow cloning](../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone). |
+| `ci_forward_deployment_enabled` | boolean | No | Enable or disable [prevent outdated deployment jobs](../ci/pipelines/settings.md#prevent-outdated-deployment-jobs). |
+| `ci_forward_deployment_rollback_allowed` | boolean | No | Enable or disable [allow job retries for rollback deployments](../ci/pipelines/settings.md#prevent-outdated-deployment-jobs). |
+| `ci_allow_fork_pipelines_to_run_in_parent_project` | boolean | No | Enable or disable [running pipelines in the parent project for merge requests from forks](../ci/pipelines/merge_request_pipelines.md#run-pipelines-in-the-parent-project). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325189) in GitLab 15.3.)_ |
+| `ci_separated_caches` | boolean | No | Set whether or not caches should be [separated](../ci/caching/index.md#cache-key-names) by branch protection status. |
+| `container_expiration_policy_attributes` | hash | No | Update the image cleanup policy for this project. Accepts: `cadence` (string), `keep_n` (integer), `older_than` (string), `name_regex` (string), `name_regex_delete` (string), `name_regex_keep` (string), `enabled` (boolean). |
+| `container_registry_access_level` | string | No | Set visibility of container registry, for this project, to one of `disabled`, `private` or `enabled`. |
+| `container_registry_enabled` | boolean | No | _(Deprecated)_ Enable container registry for this project. Use `container_registry_access_level` instead. |
+| `default_branch` | string | No | The [default branch](../user/project/repository/branches/default.md) name. |
+| `description` | string | No | Short project description. |
+| `emails_disabled` | boolean | No | _(Deprecated)_ Disable email notifications. Use `emails_enabled` instead|
+| `emails_enabled` | boolean | No | Enable email notifications. |
+| `enforce_auth_checks_on_uploads` | boolean | No | Enforce [auth checks](../security/user_file_uploads.md#enable-authorization-checks-for-all-media-files) on uploads. |
+| `external_authorization_classification_label` **(PREMIUM ALL)** | string | No | The classification label for the project. |
+| `forking_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `group_runners_enabled` | boolean | No | Enable group runners for this project. |
+| `import_url` | string | No | URL the repository was imported from. |
+| `issues_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `issues_enabled` | boolean | No | _(Deprecated)_ Enable issues for this project. Use `issues_access_level` instead. |
+| `issues_template` **(PREMIUM ALL)** | string | No | Default description for Issues. Description is parsed with GitLab Flavored Markdown. See [Templates for issues and merge requests](#templates-for-issues-and-merge-requests). |
+| `jobs_enabled` | boolean | No | _(Deprecated)_ Enable jobs for this project. Use `builds_access_level` instead. |
+| `keep_latest_artifact` | boolean | No | Disable or enable the ability to keep the latest artifact for this project. |
+| `lfs_enabled` | boolean | No | Enable LFS. |
+| `merge_commit_template` | string | No | [Template](../user/project/merge_requests/commit_templates.md) used to create merge commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5.)_ |
+| `merge_method` | string | No | Set the [merge method](#project-merge-method) used. |
+| `merge_pipelines_enabled` | boolean | No | Enable or disable merge pipelines. |
+| `merge_requests_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `merge_requests_enabled` | boolean | No | _(Deprecated)_ Enable merge requests for this project. Use `merge_requests_access_level` instead. |
+| `merge_requests_template` **(PREMIUM ALL)** | string | No | Default description for merge requests. Description is parsed with GitLab Flavored Markdown. See [Templates for issues and merge requests](#templates-for-issues-and-merge-requests). |
+| `merge_trains_enabled` | boolean | No | Enable or disable merge trains. |
+| `mirror_overwrites_diverged_branches` **(PREMIUM ALL)** | boolean | No | Pull mirror overwrites diverged branches. |
+| `mirror_trigger_builds` **(PREMIUM ALL)** | boolean | No | Pull mirroring triggers builds. |
+| `mirror_user_id` **(PREMIUM ALL)** | integer | No | User responsible for all the activity surrounding a pull mirror event. _(administrators only)_ |
+| `mirror` **(PREMIUM ALL)** | boolean | No | Enables pull mirroring in a project. |
+| `mr_default_target_self` | boolean | No | For forked projects, target merge requests to this project. If `false`, the target is the upstream project. |
+| `name` | string | No | The name of the project. |
+| `only_allow_merge_if_all_discussions_are_resolved` | boolean | No | Set whether merge requests can only be merged when all the discussions are resolved. |
+| `only_allow_merge_if_pipeline_succeeds` | boolean | No | Set whether merge requests can only be merged with successful jobs. |
+| `only_mirror_protected_branches` **(PREMIUM ALL)** | boolean | No | Only mirror protected branches. |
+| `packages_enabled` | boolean | No | Enable or disable packages repository feature. |
+| `pages_access_level` | string | No | One of `disabled`, `private`, `enabled`, or `public`. |
+| `path` | string | No | Custom repository name for the project. By default generated based on name. |
+| `printing_merge_request_link_enabled` | boolean | No | Show link to create/view merge request when pushing from the command line. |
+| `public_builds` | boolean | No | If `true`, jobs can be viewed by non-project members. |
+| `releases_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `environments_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `feature_flags_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `infrastructure_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `monitor_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `remove_source_branch_after_merge` | boolean | No | Enable `Delete source branch` option by default for all new merge requests. |
+| `repository_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `repository_storage` | string | No | Which storage shard the repository is on. _(administrators only)_ |
+| `request_access_enabled` | boolean | No | Allow users to request member access. |
+| `requirements_access_level` | string | No | One of `disabled`, `private`, `enabled` or `public` |
+| `resolve_outdated_diff_discussions` | boolean | No | Automatically resolve merge request diffs discussions on lines changed with a push. |
+| `restrict_user_defined_variables` | boolean | No | Allow only users with the Maintainer role to pass user-defined variables when triggering a pipeline. For example when the pipeline is triggered in the UI, with the API, or by a trigger token. |
+| `security_and_compliance_access_level` | string | No | (GitLab 14.9 and later) Security and compliance access level. One of `disabled`, `private`, or `enabled`. |
+| `service_desk_enabled` | boolean | No | Enable or disable Service Desk feature. |
+| `shared_runners_enabled` | boolean | No | Enable shared runners for this project. |
+| `show_default_award_emojis` | boolean | No | Show default award emojis. |
+| `snippets_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `snippets_enabled` | boolean | No | _(Deprecated)_ Enable snippets for this project. Use `snippets_access_level` instead. |
+| `issue_branch_template` | string | No | Template used to suggest names for [branches created from issues](../user/project/merge_requests/creating_merge_requests.md#from-an-issue). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21243) in GitLab 15.6.)_ |
+| `squash_commit_template` | string | No | [Template](../user/project/merge_requests/commit_templates.md) used to create squash commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.)_ |
+| `squash_option` | string | No | One of `never`, `always`, `default_on`, or `default_off`. |
+| `suggestion_commit_message` | string | No | The commit message used to apply merge request suggestions. |
+| `tag_list` | array | No | _([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0)_ The list of tags for a project; put array of tags, that should be finally assigned to a project. Use `topics` instead. |
+| `topics` | array | No | The list of topics for the project. This replaces any existing topics that are already added to the project. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328226) in GitLab 14.0.)_ |
+| `visibility` | string | No | See [project visibility level](#project-visibility-level). |
+| `wiki_access_level` | string | No | One of `disabled`, `private`, or `enabled`. |
+| `wiki_enabled` | boolean | No | _(Deprecated)_ Enable wiki for this project. Use `wiki_access_level` instead. |
## Fork project
@@ -1782,15 +1782,15 @@ POST /projects/:id/fork
| Attribute | Type | Required | Description |
|------------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `description` | string | **{dotted-circle}** No | The description assigned to the resultant project after forking. |
-| `mr_default_target_self` | boolean | **{dotted-circle}** No | For forked projects, target merge requests to this project. If `false`, the target is the upstream project. |
-| `name` | string | **{dotted-circle}** No | The name assigned to the resultant project after forking. |
-| `namespace_id` | integer | **{dotted-circle}** No | The ID of the namespace that the project is forked to. |
-| `namespace_path` | string | **{dotted-circle}** No | The path of the namespace that the project is forked to. |
-| `namespace` | integer or string | **{dotted-circle}** No | _(Deprecated)_ The ID or path of the namespace that the project is forked to. |
-| `path` | string | **{dotted-circle}** No | The path assigned to the resultant project after forking. |
-| `visibility` | string | **{dotted-circle}** No | The [visibility level](#project-visibility-level) assigned to the resultant project after forking. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `description` | string | No | The description assigned to the resultant project after forking. |
+| `mr_default_target_self` | boolean | No | For forked projects, target merge requests to this project. If `false`, the target is the upstream project. |
+| `name` | string | No | The name assigned to the resultant project after forking. |
+| `namespace_id` | integer | No | The ID of the namespace that the project is forked to. |
+| `namespace_path` | string | No | The path of the namespace that the project is forked to. |
+| `namespace` | integer or string | No | _(Deprecated)_ The ID or path of the namespace that the project is forked to. |
+| `path` | string | No | The path assigned to the resultant project after forking. |
+| `visibility` | string | No | The [visibility level](#project-visibility-level) assigned to the resultant project after forking. |
## List forks of a project
@@ -1805,23 +1805,23 @@ GET /projects/:id/forks
| Attribute | Type | Required | Description |
|-------------------------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `archived` | boolean | **{dotted-circle}** No | Limit by archived status. |
-| `membership` | boolean | **{dotted-circle}** No | Limit by projects that the current user is a member of. |
-| `min_access_level` | integer | **{dotted-circle}** No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
-| `order_by` | string | **{dotted-circle}** No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at`. |
-| `owned` | boolean | **{dotted-circle}** No | Limit by projects explicitly owned by the current user. |
-| `search` | string | **{dotted-circle}** No | Return list of projects matching the search criteria. |
-| `simple` | boolean | **{dotted-circle}** No | Return only limited fields for each project. Without authentication, this operation is a no-op; only simple fields are returned. |
-| `sort` | string | **{dotted-circle}** No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
-| `starred` | boolean | **{dotted-circle}** No | Limit by projects starred by the current user. |
-| `statistics` | boolean | **{dotted-circle}** No | Include project statistics. Available only to users with at least the Reporter role. |
-| `visibility` | string | **{dotted-circle}** No | Limit by visibility `public`, `internal`, or `private`. |
-| `with_custom_attributes` | boolean | **{dotted-circle}** No | Include [custom attributes](custom_attributes.md) in response. _(administrators only)_ |
-| `with_issues_enabled` | boolean | **{dotted-circle}** No | Limit by enabled issues feature. |
-| `with_merge_requests_enabled` | boolean | **{dotted-circle}** No | Limit by enabled merge requests feature. |
-| `updated_before` | datetime | **{dotted-circle}** No | Limit results to projects last updated before the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
-| `updated_after` | datetime | **{dotted-circle}** No | Limit results to projects last updated after the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `archived` | boolean | No | Limit by archived status. |
+| `membership` | boolean | No | Limit by projects that the current user is a member of. |
+| `min_access_level` | integer | No | Limit by current user minimal [role (`access_level`)](members.md#roles). |
+| `order_by` | string | No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at`. |
+| `owned` | boolean | No | Limit by projects explicitly owned by the current user. |
+| `search` | string | No | Return list of projects matching the search criteria. |
+| `simple` | boolean | No | Return only limited fields for each project. Without authentication, this operation is a no-op; only simple fields are returned. |
+| `sort` | string | No | Return projects sorted in `asc` or `desc` order. Default is `desc`. |
+| `starred` | boolean | No | Limit by projects starred by the current user. |
+| `statistics` | boolean | No | Include project statistics. Available only to users with at least the Reporter role. |
+| `visibility` | string | No | Limit by visibility `public`, `internal`, or `private`. |
+| `with_custom_attributes` | boolean | No | Include [custom attributes](custom_attributes.md) in response. _(administrators only)_ |
+| `with_issues_enabled` | boolean | No | Limit by enabled issues feature. |
+| `with_merge_requests_enabled` | boolean | No | Limit by enabled merge requests feature. |
+| `updated_before` | datetime | No | Limit results to projects last updated before the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
+| `updated_after` | datetime | No | Limit results to projects last updated after the specified time. Format: ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393979) in GitLab 15.10. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/forks"
@@ -1835,12 +1835,12 @@ Example responses:
"id": 3,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "internal",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
- "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
@@ -1924,7 +1924,7 @@ POST /projects/:id/star
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/star"
@@ -1937,12 +1937,12 @@ Example response:
"id": 3,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "internal",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
- "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
@@ -1980,7 +1980,7 @@ Example response:
"import_status": "none",
"archived": true,
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
- "license_url": "http://example.com/diaspora/diaspora-client/blob/master/LICENSE",
+ "license_url": "http://example.com/diaspora/diaspora-client/blob/main/LICENSE",
"license": {
"key": "lgpl-3.0",
"name": "GNU Lesser General Public License v3.0",
@@ -2032,7 +2032,7 @@ POST /projects/:id/unstar
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/unstar"
@@ -2045,12 +2045,12 @@ Example response:
"id": 3,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "internal",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
- "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
@@ -2088,7 +2088,7 @@ Example response:
"import_status": "none",
"archived": true,
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
- "license_url": "http://example.com/diaspora/diaspora-client/blob/master/LICENSE",
+ "license_url": "http://example.com/diaspora/diaspora-client/blob/main/LICENSE",
"license": {
"key": "lgpl-3.0",
"name": "GNU Lesser General Public License v3.0",
@@ -2138,8 +2138,8 @@ GET /projects/:id/starrers
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `search` | string | **{dotted-circle}** No | Search for specific users. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `search` | string | No | Search for specific users. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/starrers"
@@ -2184,7 +2184,7 @@ GET /projects/:id/languages
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/languages"
@@ -2215,7 +2215,7 @@ POST /projects/:id/archive
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/archive"
@@ -2228,12 +2228,12 @@ Example response:
"id": 3,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
- "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
@@ -2287,7 +2287,7 @@ Example response:
},
"archived": true,
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
- "license_url": "http://example.com/diaspora/diaspora-client/blob/master/LICENSE",
+ "license_url": "http://example.com/diaspora/diaspora-client/blob/main/LICENSE",
"license": {
"key": "lgpl-3.0",
"name": "GNU Lesser General Public License v3.0",
@@ -2347,7 +2347,7 @@ POST /projects/:id/unarchive
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/unarchive"
@@ -2360,12 +2360,12 @@ Example response:
"id": 3,
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"description_html": "<p data-sourcepos=\"1:1-1:56\" dir=\"auto\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>",
- "default_branch": "master",
+ "default_branch": "main",
"visibility": "private",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
- "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/master/README.md",
+ "readme_url": "http://example.com/diaspora/diaspora-project-site/blob/main/README.md",
"tag_list": [ //deprecated, use `topics` instead
"example",
"disapora project"
@@ -2419,7 +2419,7 @@ Example response:
},
"archived": false,
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
- "license_url": "http://example.com/diaspora/diaspora-client/blob/master/LICENSE",
+ "license_url": "http://example.com/diaspora/diaspora-client/blob/main/LICENSE",
"license": {
"key": "lgpl-3.0",
"name": "GNU Lesser General Public License v3.0",
@@ -2494,9 +2494,9 @@ DELETE /projects/:id
| Attribute | Type | Required | Description |
|------------------------------------|-------------------|------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `permanently_remove` **(PREMIUM)** | boolean/string | no | Immediately deletes a project if it is marked for deletion. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/396500) in GitLab 15.11 |
-| `full_path` **(PREMIUM)** | string | no | Full path of project to use with `permanently_remove`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/396500) in GitLab 15.11. To find the project path, use `path_with_namespace` from [get single project](projects.md#get-single-project) |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `permanently_remove` **(PREMIUM ALL)** | boolean/string | no | Immediately deletes a project if it is marked for deletion. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/396500) in GitLab 15.11 |
+| `full_path` **(PREMIUM ALL)** | string | no | Full path of project to use with `permanently_remove`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/396500) in GitLab 15.11. To find the project path, use `path_with_namespace` from [get single project](projects.md#get-single-project) |
## Restore project marked for deletion **(PREMIUM ALL)**
@@ -2510,7 +2510,7 @@ POST /projects/:id/restore
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
## Upload a file
@@ -2527,8 +2527,8 @@ POST /projects/:id/uploads
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `file` | string | **{check-circle}** Yes | The file to be uploaded. |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `file` | string | Yes | The file to be uploaded. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
To upload a file from your file system, use the `--form` argument. This causes
cURL to post data using the header `Content-Type: multipart/form-data`. The
@@ -2565,8 +2565,8 @@ PUT /projects/:id
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `avatar` | string | **{check-circle}** Yes | The file to be uploaded. |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `avatar` | string | Yes | The file to be uploaded. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
To upload an avatar from your file system, use the `--form` argument. This causes
cURL to post data using the header `Content-Type: multipart/form-data`. The
@@ -2611,10 +2611,10 @@ POST /projects/:id/share
| Attribute | Type | Required | Description |
|----------------|----------------|------------------------|-------------|
-| `group_access` | integer | **{check-circle}** Yes | The [role (`access_level`)](members.md#roles) to grant the group. |
-| `group_id` | integer | **{check-circle}** Yes | The ID of the group to share with. |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `expires_at` | string | **{dotted-circle}** No | Share expiration date in ISO 8601 format: 2016-09-26 |
+| `group_access` | integer | Yes | The [role (`access_level`)](members.md#roles) to grant the group. |
+| `group_id` | integer | Yes | The ID of the group to share with. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `expires_at` | string | No | Share expiration date in ISO 8601 format: 2016-09-26 |
## Delete a shared project link within a group
@@ -2626,8 +2626,8 @@ DELETE /projects/:id/share/:group_id
| Attribute | Type | Required | Description |
|------------|----------------|------------------------|-------------|
-| `group_id` | integer | **{check-circle}** Yes | The ID of the group. |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `group_id` | integer | Yes | The ID of the group. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/share/17"
@@ -2648,8 +2648,8 @@ POST /projects/:id/import_project_members/:project_id
| Attribute | Type | Required | Description |
|--------------|-------------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path](rest/index.md#namespaced-path-encoding) of the target project to receive the members. |
-| `project_id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path](rest/index.md#namespaced-path-encoding) of the source project to import the members from. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path](rest/index.md#namespaced-path-encoding) of the target project to receive the members. |
+| `project_id` | integer or string | Yes | The ID or [URL-encoded path](rest/index.md#namespaced-path-encoding) of the source project to import the members from. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/import_project_members/32"
@@ -2703,7 +2703,7 @@ GET /projects/:id/hooks
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
### Get project hook
@@ -2715,8 +2715,8 @@ GET /projects/:id/hooks/:hook_id
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|---------------------------|
-| `hook_id` | integer | **{check-circle}** Yes | The ID of a project hook. |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `hook_id` | integer | Yes | The ID of a project hook. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```json
{
@@ -2755,23 +2755,23 @@ POST /projects/:id/hooks
| Attribute | Type | Required | Description |
|------------------------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `url` | string | **{check-circle}** Yes | The hook URL. |
-| `confidential_issues_events` | boolean | **{dotted-circle}** No | Trigger hook on confidential issues events. |
-| `confidential_note_events` | boolean | **{dotted-circle}** No | Trigger hook on confidential note events. |
-| `deployment_events` | boolean | **{dotted-circle}** No | Trigger hook on deployment events. |
-| `enable_ssl_verification` | boolean | **{dotted-circle}** No | Do SSL verification when triggering the hook. |
-| `issues_events` | boolean | **{dotted-circle}** No | Trigger hook on issues events. |
-| `job_events` | boolean | **{dotted-circle}** No | Trigger hook on job events. |
-| `merge_requests_events` | boolean | **{dotted-circle}** No | Trigger hook on merge requests events. |
-| `note_events` | boolean | **{dotted-circle}** No | Trigger hook on note events. |
-| `pipeline_events` | boolean | **{dotted-circle}** No | Trigger hook on pipeline events. |
-| `push_events_branch_filter` | string | **{dotted-circle}** No | Trigger hook on push events for matching branches only. |
-| `push_events` | boolean | **{dotted-circle}** No | Trigger hook on push events. |
-| `releases_events` | boolean | **{dotted-circle}** No | Trigger hook on release events. |
-| `tag_push_events` | boolean | **{dotted-circle}** No | Trigger hook on tag push events. |
-| `token` | string | **{dotted-circle}** No | Secret token to validate received payloads; the token isn't returned in the response. |
-| `wiki_page_events` | boolean | **{dotted-circle}** No | Trigger hook on wiki events. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `url` | string | Yes | The hook URL. |
+| `confidential_issues_events` | boolean | No | Trigger hook on confidential issues events. |
+| `confidential_note_events` | boolean | No | Trigger hook on confidential note events. |
+| `deployment_events` | boolean | No | Trigger hook on deployment events. |
+| `enable_ssl_verification` | boolean | No | Do SSL verification when triggering the hook. |
+| `issues_events` | boolean | No | Trigger hook on issues events. |
+| `job_events` | boolean | No | Trigger hook on job events. |
+| `merge_requests_events` | boolean | No | Trigger hook on merge requests events. |
+| `note_events` | boolean | No | Trigger hook on note events. |
+| `pipeline_events` | boolean | No | Trigger hook on pipeline events. |
+| `push_events_branch_filter` | string | No | Trigger hook on push events for matching branches only. |
+| `push_events` | boolean | No | Trigger hook on push events. |
+| `releases_events` | boolean | No | Trigger hook on release events. |
+| `tag_push_events` | boolean | No | Trigger hook on tag push events. |
+| `token` | string | No | Secret token to validate received payloads; the token isn't returned in the response. |
+| `wiki_page_events` | boolean | No | Trigger hook on wiki events. |
### Edit project hook
@@ -2783,24 +2783,24 @@ PUT /projects/:id/hooks/:hook_id
| Attribute | Type | Required | Description |
|------------------------------|----------------|------------------------|-------------|
-| `hook_id` | integer | **{check-circle}** Yes | The ID of the project hook. |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `url` | string | **{check-circle}** Yes | The hook URL. |
-| `confidential_issues_events` | boolean | **{dotted-circle}** No | Trigger hook on confidential issues events. |
-| `confidential_note_events` | boolean | **{dotted-circle}** No | Trigger hook on confidential note events. |
-| `deployment_events` | boolean | **{dotted-circle}** No | Trigger hook on deployment events. |
-| `enable_ssl_verification` | boolean | **{dotted-circle}** No | Do SSL verification when triggering the hook. |
-| `issues_events` | boolean | **{dotted-circle}** No | Trigger hook on issues events. |
-| `job_events` | boolean | **{dotted-circle}** No | Trigger hook on job events. |
-| `merge_requests_events` | boolean | **{dotted-circle}** No | Trigger hook on merge requests events. |
-| `note_events` | boolean | **{dotted-circle}** No | Trigger hook on note events. |
-| `pipeline_events` | boolean | **{dotted-circle}** No | Trigger hook on pipeline events. |
-| `push_events_branch_filter` | string | **{dotted-circle}** No | Trigger hook on push events for matching branches only. |
-| `push_events` | boolean | **{dotted-circle}** No | Trigger hook on push events. |
-| `releases_events` | boolean | **{dotted-circle}** No | Trigger hook on release events. |
-| `tag_push_events` | boolean | **{dotted-circle}** No | Trigger hook on tag push events. |
-| `token` | string | **{dotted-circle}** No | Secret token to validate received payloads. Not returned in the response. When you change the webhook URL, the secret token is reset and not retained. |
-| `wiki_page_events` | boolean | **{dotted-circle}** No | Trigger hook on wiki page events. |
+| `hook_id` | integer | Yes | The ID of the project hook. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `url` | string | Yes | The hook URL. |
+| `confidential_issues_events` | boolean | No | Trigger hook on confidential issues events. |
+| `confidential_note_events` | boolean | No | Trigger hook on confidential note events. |
+| `deployment_events` | boolean | No | Trigger hook on deployment events. |
+| `enable_ssl_verification` | boolean | No | Do SSL verification when triggering the hook. |
+| `issues_events` | boolean | No | Trigger hook on issues events. |
+| `job_events` | boolean | No | Trigger hook on job events. |
+| `merge_requests_events` | boolean | No | Trigger hook on merge requests events. |
+| `note_events` | boolean | No | Trigger hook on note events. |
+| `pipeline_events` | boolean | No | Trigger hook on pipeline events. |
+| `push_events_branch_filter` | string | No | Trigger hook on push events for matching branches only. |
+| `push_events` | boolean | No | Trigger hook on push events. |
+| `releases_events` | boolean | No | Trigger hook on release events. |
+| `tag_push_events` | boolean | No | Trigger hook on tag push events. |
+| `token` | string | No | Secret token to validate received payloads. Not returned in the response. When you change the webhook URL, the secret token is reset and not retained. |
+| `wiki_page_events` | boolean | No | Trigger hook on wiki page events. |
### Delete project hook
@@ -2813,8 +2813,8 @@ DELETE /projects/:id/hooks/:hook_id
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `hook_id` | integer | **{check-circle}** Yes | The ID of the project hook. |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `hook_id` | integer | Yes | The ID of the project hook. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
Note the JSON response differs if the hook is available or not. If the project
hook is available before it's returned in the JSON response or an empty response
@@ -2833,8 +2833,8 @@ POST /projects/:id/fork/:forked_from_id
| Attribute | Type | Required | Description |
|------------------|----------------|------------------------|-------------|
-| `forked_from_id` | ID | **{check-circle}** Yes | The ID of the project that was forked from. |
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `forked_from_id` | ID | Yes | The ID of the project that was forked from. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
### Delete an existing forked from relationship
@@ -2844,7 +2844,7 @@ DELETE /projects/:id/fork
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
## Search for projects by name
@@ -2858,9 +2858,9 @@ GET /projects
| Attribute | Type | Required | Description |
|------------|--------|------------------------|-------------|
-| `search` | string | **{check-circle}** Yes | A string contained in the project name. |
-| `order_by` | string | **{dotted-circle}** No | Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields. |
-| `sort` | string | **{dotted-circle}** No | Return requests sorted in `asc` or `desc` order. |
+| `search` | string | Yes | A string contained in the project name. |
+| `order_by` | string | No | Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields. |
+| `sort` | string | No | Return requests sorted in `asc` or `desc` order. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects?search=test"
@@ -2874,8 +2874,8 @@ POST /projects/:id/housekeeping
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `task` | string | **{dotted-circle}** No | `prune` to trigger manual prune of unreachable objects or `eager` to trigger eager housekeeping. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `task` | string | No | `prune` to trigger manual prune of unreachable objects or `eager` to trigger eager housekeeping. |
## Push rules **(PREMIUM ALL)**
@@ -2890,7 +2890,7 @@ GET /projects/:id/push_rule
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) |
```json
{
@@ -2921,18 +2921,18 @@ POST /projects/:id/push_rule
| Attribute | Type | Required | Description |
|-----------------------------------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `author_email_regex` | string | **{dotted-circle}** No | All commit author emails must match this, for example `@my-company.com$`. |
-| `branch_name_regex` | string | **{dotted-circle}** No | All branch names must match this, for example `(feature|hotfix)\/*`. |
-| `commit_committer_check` | boolean | **{dotted-circle}** No | Users can only push commits to this repository if the committer email is one of their own verified emails. |
-| `commit_message_negative_regex` | string | **{dotted-circle}** No | No commit message is allowed to match this, for example `ssh\:\/\/`. |
-| `commit_message_regex` | string | **{dotted-circle}** No | All commit messages must match this, for example `Fixed \d+\..*`. |
-| `deny_delete_tag` | boolean | **{dotted-circle}** No | Deny deleting a tag. |
-| `file_name_regex` | string | **{dotted-circle}** No | All committed filenames must **not** match this, for example `(jar|exe)$`. |
-| `max_file_size` | integer | **{dotted-circle}** No | Maximum file size (MB). |
-| `member_check` | boolean | **{dotted-circle}** No | Restrict commits by author (email) to existing GitLab users. |
-| `prevent_secrets` | boolean | **{dotted-circle}** No | GitLab rejects any files that are likely to contain secrets. |
-| `reject_unsigned_commits` | boolean | **{dotted-circle}** No | Reject commit when it's not signed through GPG. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `author_email_regex` | string | No | All commit author emails must match this, for example `@my-company.com$`. |
+| `branch_name_regex` | string | No | All branch names must match this, for example `(feature|hotfix)\/*`. |
+| `commit_committer_check` | boolean | No | Users can only push commits to this repository if the committer email is one of their own verified emails. |
+| `commit_message_negative_regex` | string | No | No commit message is allowed to match this, for example `ssh\:\/\/`. |
+| `commit_message_regex` | string | No | All commit messages must match this, for example `Fixed \d+\..*`. |
+| `deny_delete_tag` | boolean | No | Deny deleting a tag. |
+| `file_name_regex` | string | No | All committed filenames must **not** match this, for example `(jar|exe)$`. |
+| `max_file_size` | integer | No | Maximum file size (MB). |
+| `member_check` | boolean | No | Restrict commits by author (email) to existing GitLab users. |
+| `prevent_secrets` | boolean | No | GitLab rejects any files that are likely to contain secrets. |
+| `reject_unsigned_commits` | boolean | No | Reject commit when it's not signed through GPG. |
### Edit project push rule
@@ -2944,18 +2944,18 @@ PUT /projects/:id/push_rule
| Attribute | Type | Required | Description |
|-----------------------------------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `author_email_regex` | string | **{dotted-circle}** No | All commit author emails must match this, for example `@my-company.com$`. |
-| `branch_name_regex` | string | **{dotted-circle}** No | All branch names must match this, for example `(feature|hotfix)\/*`. |
-| `commit_committer_check` | boolean | **{dotted-circle}** No | Users can only push commits to this repository if the committer email is one of their own verified emails. |
-| `commit_message_negative_regex` | string | **{dotted-circle}** No | No commit message is allowed to match this, for example `ssh\:\/\/`. |
-| `commit_message_regex` | string | **{dotted-circle}** No | All commit messages must match this, for example `Fixed \d+\..*`. |
-| `deny_delete_tag` | boolean | **{dotted-circle}** No | Deny deleting a tag. |
-| `file_name_regex` | string | **{dotted-circle}** No | All committed filenames must **not** match this, for example `(jar|exe)$`. |
-| `max_file_size` | integer | **{dotted-circle}** No | Maximum file size (MB). |
-| `member_check` | boolean | **{dotted-circle}** No | Restrict commits by author (email) to existing GitLab users. |
-| `prevent_secrets` | boolean | **{dotted-circle}** No | GitLab rejects any files that are likely to contain secrets. |
-| `reject_unsigned_commits` | boolean | **{dotted-circle}** No | Reject commits when they are not GPG signed. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `author_email_regex` | string | No | All commit author emails must match this, for example `@my-company.com$`. |
+| `branch_name_regex` | string | No | All branch names must match this, for example `(feature|hotfix)\/*`. |
+| `commit_committer_check` | boolean | No | Users can only push commits to this repository if the committer email is one of their own verified emails. |
+| `commit_message_negative_regex` | string | No | No commit message is allowed to match this, for example `ssh\:\/\/`. |
+| `commit_message_regex` | string | No | All commit messages must match this, for example `Fixed \d+\..*`. |
+| `deny_delete_tag` | boolean | No | Deny deleting a tag. |
+| `file_name_regex` | string | No | All committed filenames must **not** match this, for example `(jar|exe)$`. |
+| `max_file_size` | integer | No | Maximum file size (MB). |
+| `member_check` | boolean | No | Restrict commits by author (email) to existing GitLab users. |
+| `prevent_secrets` | boolean | No | GitLab rejects any files that are likely to contain secrets. |
+| `reject_unsigned_commits` | boolean | No | Reject commits when they are not GPG signed. |
### Delete project push rule
@@ -2970,7 +2970,7 @@ DELETE /projects/:id/push_rule
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
## Get groups to which a user can transfer a project
@@ -2984,8 +2984,8 @@ GET /projects/:id/transfer_locations
| Attribute | Type | Required | Description |
|-------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `search` | string | **{dotted-circle}** No | The group names to search for. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `search` | string | No | The group names to search for. |
Example request:
@@ -3029,8 +3029,8 @@ PUT /projects/:id/transfer
| Attribute | Type | Required | Description |
|-------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `namespace` | integer or string | **{check-circle}** Yes | The ID or path of the namespace to transfer to project to. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `namespace` | integer or string | Yes | The ID or path of the namespace to transfer to project to. |
Example request:
@@ -3051,13 +3051,13 @@ Example response:
"path_with_namespace": "cute-cats/hello-world",
"created_at": "2020-10-15T16:25:22.415Z",
"updated_at": "2020-10-15T16:25:22.415Z",
- "default_branch": "master",
+ "default_branch": "main",
"tag_list": [], //deprecated, use `topics` instead
"topics": [],
"ssh_url_to_repo": "git@gitlab.example.com:cute-cats/hello-world.git",
"http_url_to_repo": "https://gitlab.example.com/cute-cats/hello-world.git",
"web_url": "https://gitlab.example.com/cute-cats/hello-world",
- "readme_url": "https://gitlab.example.com/cute-cats/hello-world/-/blob/master/README.md",
+ "readme_url": "https://gitlab.example.com/cute-cats/hello-world/-/blob/main/README.md",
"avatar_url": null,
"forks_count": 0,
"star_count": 0,
@@ -3180,7 +3180,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
|:----------|:------|:------------|:------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
Example request:
@@ -3220,11 +3220,41 @@ with the API scope enabled.
| Attribute | Type | Required | Description |
|--------------|---------|------------------------|-------------|
-| `import_url` | string | **{check-circle}** Yes | URL of remote repository being mirrored (with `user:token` if needed). |
-| `mirror` | boolean | **{check-circle}** Yes | Enables pull mirroring on project when set to `true`. |
-| `mirror_trigger_builds`| boolean | **{dotted-circle}** No | Trigger pipelines for mirror updates when set to `true`. |
-| `only_mirror_protected_branches`| boolean | **{dotted-circle}** No | Limits mirroring to only protected branches when set to `true`. |
-| `mirror_branch_regex` | String | **{dotted-circle}** No | Contains a regular expression. Only branches with names matching the regex are mirrored. Requires `only_mirror_protected_branches` to be disabled. |
+| `import_url` | string | Yes | URL of remote repository being mirrored (with `user:token` if needed). |
+| `mirror` | boolean | Yes | Enables pull mirroring on project when set to `true`. |
+| `mirror_trigger_builds`| boolean | No | Trigger pipelines for mirror updates when set to `true`. |
+| `only_mirror_protected_branches`| boolean | No | Limits mirroring to only protected branches when set to `true`. |
+| `mirror_branch_regex` | String | No | Contains a regular expression. Only branches with names matching the regex are mirrored. Requires `only_mirror_protected_branches` to be disabled. |
+
+Example creating a project with pull mirroring:
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
+ --header "Content-Type: application/json" \
+ --data '{
+ "name": "new_project",
+ "namespace_id": "1",
+ "mirror": true,
+ "import_url": "https://username:token@gitlab.example.com/group/project.git"
+ }' \
+ --url "https://gitlab.example.com/api/v4/projects/"
+```
+
+Example adding pull mirroring:
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
+ --url "https://gitlab.example.com/api/v4/projects/:id" \
+ --data "mirror=true&import_url=https://username:token@gitlab.example.com/group/project.git"
+```
+
+Example removing pull mirroring:
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
+ --url "https://gitlab.example.com/api/v4/projects/:id" \
+ --data "mirror=false"
+```
## Start the pull mirroring process for a Project **(PREMIUM ALL)**
@@ -3236,7 +3266,7 @@ POST /projects/:id/mirror/pull
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/mirror/pull"
@@ -3263,8 +3293,8 @@ GET /projects/:id/snapshot
| Attribute | Type | Required | Description |
|-----------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
-| `wiki` | boolean | **{dotted-circle}** No | Whether to download the wiki, rather than project, repository. |
+| `id` | integer or string | Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `wiki` | boolean | No | Whether to download the wiki, rather than project, repository. |
## Get the path to repository storage
@@ -3281,7 +3311,7 @@ GET /projects/:id/storage
| Attribute | Type | Required | Description |
|--------------|----------------|------------------------|-------------|
-| `id` | integer or string | **{check-circle}** Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
+| `id` | integer or string | Yes | ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). |
```json
[
diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md
index 6bccc777e04..93a1280f7df 100644
--- a/doc/api/protected_branches.md
+++ b/doc/api/protected_branches.md
@@ -44,7 +44,7 @@ Example response:
[
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 1,
@@ -102,7 +102,7 @@ Example response:
[
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 1,
@@ -151,7 +151,7 @@ GET /projects/:id/protected_branches/:name
| `name` | string | yes | The name of the branch or wildcard |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_branches/master"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_branches/main"
```
Example response:
@@ -159,7 +159,7 @@ Example response:
```json
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 1,
@@ -187,7 +187,7 @@ Example response:
```json
{
"id": 1,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 1,
@@ -229,10 +229,10 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user.
| `name` | string | yes | The name of the branch or wildcard.
| `allow_force_push` | boolean | no | When enabled, members who can push to this branch can also force push. (default: `false`)
-| `allowed_to_merge` **(PREMIUM)** | array | no | Array of merge access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
-| `allowed_to_push` **(PREMIUM)** | array | no | Array of push access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
-| `allowed_to_unprotect` **(PREMIUM)** | array | no | Array of unprotect access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`. The access level `No access` is not available for this field. |
-| `code_owner_approval_required` **(PREMIUM)** | boolean | no | Prevent pushes to this branch if it matches an item in the [`CODEOWNERS` file](../user/project/codeowners/index.md). (defaults: false)
+| `allowed_to_merge` **(PREMIUM ALL)** | array | no | Array of merge access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
+| `allowed_to_push` **(PREMIUM ALL)** | array | no | Array of push access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
+| `allowed_to_unprotect` **(PREMIUM ALL)** | array | no | Array of unprotect access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`. The access level `No access` is not available for this field. |
+| `code_owner_approval_required` **(PREMIUM ALL)** | boolean | no | Prevent pushes to this branch if it matches an item in the [`CODEOWNERS` file](../user/project/codeowners/index.md). (defaults: false)
| `merge_access_level` | integer | no | Access levels allowed to merge. (defaults: `40`, Maintainer role)
| `push_access_level` | integer | no | Access levels allowed to push. (defaults: `40`, Maintainer role)
| `unprotect_access_level` | integer | no | Access levels allowed to unprotect. (defaults: `40`, Maintainer role)
@@ -368,7 +368,7 @@ curl --request POST \
--header "PRIVATE-TOKEN: <your_access_token>" \
--header "Content-Type: application/json" \
--data '{
- "name": "master",
+ "name": "main",
"allowed_to_push": [{"access_level": 30}],
"allowed_to_merge": [{
"access_level": 30
@@ -384,7 +384,7 @@ Example response:
```json
{
"id": 5,
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 1,
@@ -460,10 +460,10 @@ curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" "https://gitl
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user.
| `name` | string | yes | The name of the branch or wildcard.
| `allow_force_push` | boolean | no | When enabled, members who can push to this branch can also force push.
-| `allowed_to_merge` **(PREMIUM)** | array | no | Array of merge access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
-| `allowed_to_push` **(PREMIUM)** | array | no | Array of push access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
-| `allowed_to_unprotect` **(PREMIUM)** | array | no | Array of unprotect access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, `{access_level: integer}`, or `{id: integer, _destroy: true}` to destroy an existing access level. The access level `No access` is not available for this field. |
-| `code_owner_approval_required` **(PREMIUM)** | boolean | no | Prevent pushes to this branch if it matches an item in the [`CODEOWNERS` file](../user/project/codeowners/index.md). |
+| `allowed_to_merge` **(PREMIUM ALL)** | array | no | Array of merge access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
+| `allowed_to_push` **(PREMIUM ALL)** | array | no | Array of push access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, or `{access_level: integer}`.
+| `allowed_to_unprotect` **(PREMIUM ALL)** | array | no | Array of unprotect access levels, with each described by a hash of the form `{user_id: integer}`, `{group_id: integer}`, `{access_level: integer}`, or `{id: integer, _destroy: true}` to destroy an existing access level. The access level `No access` is not available for this field. |
+| `code_owner_approval_required` **(PREMIUM ALL)** | boolean | no | Prevent pushes to this branch if it matches an item in the [`CODEOWNERS` file](../user/project/codeowners/index.md). |
Elements in the `allowed_to_push`, `allowed_to_merge` and `allowed_to_unprotect` arrays should be one of `user_id`, `group_id` or
`access_level`, and take the form `{user_id: integer}`, `{group_id: integer}` or
@@ -486,14 +486,14 @@ To delete:
curl --header 'Content-Type: application/json' --request PATCH \
--data '{"allowed_to_push": [{"access_level": 40}]}' \
--header "PRIVATE-TOKEN: <your_access_token>" \
- "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/master"
+ "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/main"
```
Example response:
```json
{
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 12,
@@ -511,14 +511,14 @@ Example response:
```shell
curl --header 'Content-Type: application/json' --request PATCH \
--data '{"allowed_to_push": [{"id": 12, "access_level": 0}]}' \
- --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/master"
+ --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/main"
```
Example response:
```json
{
- "name": "master",
+ "name": "main",
"push_access_levels": [
{
"id": 12,
@@ -536,14 +536,14 @@ Example response:
```shell
curl --header 'Content-Type: application/json' --request PATCH \
--data '{"allowed_to_push": [{"id": 12, "_destroy": true}]}' \
- --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/master"
+ --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/main"
```
Example response:
```json
{
- "name": "master",
+ "name": "main",
"push_access_levels": []
}
```
diff --git a/doc/api/remote_mirrors.md b/doc/api/remote_mirrors.md
index 6b7bd3a485f..4808c317dc4 100644
--- a/doc/api/remote_mirrors.md
+++ b/doc/api/remote_mirrors.md
@@ -107,7 +107,7 @@ POST /projects/:id/remote_mirrors
| `enabled` | Boolean | no | Determines if the mirror is enabled. |
| `keep_divergent_refs` | Boolean | no | Determines if divergent refs are skipped. |
| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
-| `mirror_branch_regex` **(PREMIUM)** | String | no | Contains a regular expression. Only branches with names matching the regex are mirrored. Requires `only_protected_branches` to be disabled. |
+| `mirror_branch_regex` **(PREMIUM ALL)** | String | no | Contains a regular expression. Only branches with names matching the regex are mirrored. Requires `only_protected_branches` to be disabled. |
Example request:
@@ -148,7 +148,7 @@ PUT /projects/:id/remote_mirrors/:mirror_id
| `enabled` | Boolean | no | Determines if the mirror is enabled. |
| `keep_divergent_refs` | Boolean | no | Determines if divergent refs are skipped. |
| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
-| `mirror_branch_regex`**(PREMIUM)** | String | no | Determines if only the branch whose name matches the regex is mirrored. It does not work with `only_protected_branches` enabled. |
+| `mirror_branch_regex`**(PREMIUM ALL)** | String | no | Determines if only the branch whose name matches the regex is mirrored. It does not work with `only_protected_branches` enabled. |
Example request:
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 49415f42789..aae475a0356 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -189,7 +189,7 @@ Supported attributes:
| `straight` | boolean | no | Comparison method: `true` for direct comparison between `from` and `to` (`from`..`to`), `false` to compare using merge base (`from`...`to`)'. Default is `false`. |
```plaintext
-GET /projects/:id/repository/compare?from=master&to=feature
+GET /projects/:id/repository/compare?from=main&to=feature
```
Example response:
@@ -217,7 +217,7 @@ Example response:
"new_path": "files/js/application.js",
"a_mode": null,
"b_mode": "100644",
- "diff": "--- a/files/js/application.js\n+++ b/files/js/application.js\n@@ -24,8 +24,10 @@\n //= require g.raphael-min\n //= require g.bar-min\n //= require branch-graph\n-//= require highlightjs.min\n-//= require ace/ace\n //= require_tree .\n //= require d3\n //= require underscore\n+\n+function fix() { \n+ alert(\"Fixed\")\n+}",
+ "diff": "@@ -24,8 +24,10 @@\n //= require g.raphael-min\n //= require g.bar-min\n //= require branch-graph\n-//= require highlightjs.min\n-//= require ace/ace\n //= require_tree .\n //= require d3\n //= require underscore\n+\n+function fix() { \n+ alert(\"Fixed\")\n+}",
"new_file": false,
"renamed_file": false,
"deleted_file": false
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index 969470dcc54..cc0b4ea1972 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -35,7 +35,7 @@ GET /projects/:id/repository/files/:file_path
```
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=main"
```
| Attribute | Type | Required | Description |
@@ -54,7 +54,7 @@ Example response:
"encoding": "base64",
"content": "IyA9PSBTY2hlbWEgSW5mb3...",
"content_sha256": "4c294617b60715c1d218e61164a3abd4808a4284cbc30e6728a01ad9aada4481",
- "ref": "master",
+ "ref": "main",
"blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
"commit_id": "d5a3ff139356ce33e37e73add446f16869741b50",
"last_commit_id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
@@ -73,7 +73,7 @@ HEAD /projects/:id/repository/files/:file_path
```
```shell
-curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master"
+curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=main"
```
Example response:
@@ -88,7 +88,7 @@ X-Gitlab-Encoding: base64
X-Gitlab-File-Name: key.rb
X-Gitlab-File-Path: app/models/key.rb
X-Gitlab-Last-Commit-Id: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
-X-Gitlab-Ref: master
+X-Gitlab-Ref: main
X-Gitlab-Size: 1476
X-Gitlab-Execute-Filemode: false
...
@@ -112,7 +112,7 @@ GET /projects/:id/repository/files/:file_path/blame
| `range` | hash | no | Blame range. |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=master"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=main"
```
Example response:
@@ -147,7 +147,7 @@ NOTE:
`HEAD` method returns just file metadata, as in [Get file from repository](repository_files.md#get-file-from-repository).
```shell
-curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=master"
+curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=main"
```
Example response:
@@ -162,7 +162,7 @@ X-Gitlab-Encoding: base64
X-Gitlab-File-Name: file.rb
X-Gitlab-File-Path: path/to/file.rb
X-Gitlab-Last-Commit-Id: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
-X-Gitlab-Ref: master
+X-Gitlab-Ref: main
X-Gitlab-Size: 1476
X-Gitlab-Execute-Filemode: false
...
@@ -174,7 +174,7 @@ To request a blame range, specify `range[start]` and `range[end]` parameters wit
the starting and ending line numbers of the file.
```shell
-curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=master&range[start]=1&range[end]=2"
+curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=main&range[start]=1&range[end]=2"
```
Example response:
@@ -218,7 +218,7 @@ GET /projects/:id/repository/files/:file_path/raw
| `lfs` | boolean | no | Determines if the response should be Git LFS file contents, rather than the pointer. If the file is not tracked by Git LFS, ignored. Defaults to `false`. |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb/raw?ref=master"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb/raw?ref=main"
```
NOTE:
@@ -251,7 +251,7 @@ POST /projects/:id/repository/files/:file_path
```shell
curl --request POST --header 'PRIVATE-TOKEN: <your_access_token>' \
--header "Content-Type: application/json" \
- --data '{"branch": "master", "author_email": "author@example.com", "author_name": "Firstname Lastname",
+ --data '{"branch": "main", "author_email": "author@example.com", "author_name": "Firstname Lastname",
"content": "some content", "commit_message": "create a new file"}' \
"https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fproject%2Erb"
```
@@ -261,7 +261,7 @@ Example response:
```json
{
"file_path": "app/project.rb",
- "branch": "master"
+ "branch": "main"
}
```
@@ -293,7 +293,7 @@ PUT /projects/:id/repository/files/:file_path
```shell
curl --request PUT --header 'PRIVATE-TOKEN: <your_access_token>' \
--header "Content-Type: application/json" \
- --data '{"branch": "master", "author_email": "author@example.com", "author_name": "Firstname Lastname",
+ --data '{"branch": "main", "author_email": "author@example.com", "author_name": "Firstname Lastname",
"content": "some content", "commit_message": "update file"}' \
"https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fproject%2Erb"
```
@@ -303,7 +303,7 @@ Example response:
```json
{
"file_path": "app/project.rb",
- "branch": "master"
+ "branch": "main"
}
```
@@ -339,7 +339,7 @@ DELETE /projects/:id/repository/files/:file_path
```shell
curl --request DELETE --header 'PRIVATE-TOKEN: <your_access_token>' \
--header "Content-Type: application/json" \
- --data '{"branch": "master", "author_email": "author@example.com", "author_name": "Firstname Lastname",
+ --data '{"branch": "main", "author_email": "author@example.com", "author_name": "Firstname Lastname",
"commit_message": "delete file"}' \
"https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fproject%2Erb"
```
diff --git a/doc/api/repository_submodules.md b/doc/api/repository_submodules.md
index 650dc7783b8..7ed8e0bd33a 100644
--- a/doc/api/repository_submodules.md
+++ b/doc/api/repository_submodules.md
@@ -27,7 +27,7 @@ PUT /projects/:id/repository/submodules/:submodule
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/submodules/lib%2Fmodules%2Fexample" \
---data "branch=master&commit_sha=3ddec28ea23acc5caa5d8331a6ecb2a65fc03e88&commit_message=Update submodule reference"
+--data "branch=main&commit_sha=3ddec28ea23acc5caa5d8331a6ecb2a65fc03e88&commit_message=Update submodule reference"
```
Example response:
diff --git a/doc/api/rest/deprecations.md b/doc/api/rest/deprecations.md
index 80480e3f88f..154945977b2 100644
--- a/doc/api/rest/deprecations.md
+++ b/doc/api/rest/deprecations.md
@@ -61,10 +61,9 @@ The `changes from a single merge request` endpoint will be removed in v5 of the
Breaking change. [Related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/397067).
-The endpoint to get
-[all managed licenses for a given project](../managed_licenses.md)
-has been deprecated in favor the
+The endpoint to get all managed licenses for a given project has been deprecated in favor the
[License Approval policy](../../user/compliance/license_approval_policies.md) feature.
+
Users who wish to continue to enforce approvals based on detected licenses are encouraged to create a new [License Approval policy](../../user/compliance/license_approval_policies.md) instead.
The `managed licenses` endpoint will be removed in v5 of the GitLab REST API.
diff --git a/doc/api/rest/index.md b/doc/api/rest/index.md
index ba705a771c1..17da691b720 100644
--- a/doc/api/rest/index.md
+++ b/doc/api/rest/index.md
@@ -22,7 +22,7 @@ endpoint. New features can be added to the API in the same
version number.
New features and bug fixes are released in tandem with GitLab. Apart
-from incidental patch and security releases, GitLab is released on the 22nd of each
+from incidental patch and security releases, new minor versions of GitLab are released every
month. Major API version changes, and removal of entire API versions, are done in tandem
with major GitLab releases.
@@ -136,13 +136,10 @@ curl --header "Authorization: Bearer OAUTH-TOKEN" "https://gitlab.example.com/ap
Read more about [GitLab as an OAuth 2.0 provider](../oauth2.md).
NOTE:
-You should give OAuth access tokens an expiration. You can use the `refresh_token` parameter
-to refresh tokens. Integrations may need to be updated to use refresh tokens prior to
-expiration, which is based on the [`expires_in`](https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.14)
-property in the token endpoint response. See [OAuth 2.0 token](../oauth2.md) documentation
-for examples requesting a new access token using a refresh token.
-
-A default refresh setting of two hours is tracked in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/336598).
+All OAuth access tokens are valid for two hours after they are created. You can
+use the `refresh_token` parameter to refresh tokens. See
+[OAuth 2.0 token](../oauth2.md) documentation for how to request a new access
+token using a refresh token.
### Personal/project/group access tokens
@@ -167,6 +164,24 @@ You can also use personal, project, or group access tokens with OAuth-compliant
curl --header "Authorization: Bearer <your_access_token>" "https://gitlab.example.com/api/v4/projects"
```
+### Job tokens
+
+You can use job tokens to authenticate with [specific API endpoints](../../ci/jobs/ci_job_token.md)
+by passing the token in the `job_token` parameter or the `JOB-TOKEN` header.
+To pass the token in GitLab CI/CD jobs, use the `CI_JOB_TOKEN` variable.
+
+Example of using the job token in a parameter:
+
+```shell
+curl --location --output artifacts.zip "https://gitlab.example.com/api/v4/projects/1/jobs/42/artifacts?job_token=$CI_JOB_TOKEN"
+```
+
+Example of using the job token in a header:
+
+```shell
+curl --header "JOB-TOKEN:$CI_JOB_TOKEN" "https://gitlab.example.com/api/v4/projects/1/releases"
+```
+
### Session cookie
Signing in to the main GitLab application sets a `_gitlab_session` cookie. The
@@ -525,6 +540,7 @@ options:
| [Project jobs](../jobs.md#list-project-jobs) | `order_by=id`, `sort=desc` only | Authenticated users only. |
| [Project audit events](../audit_events.md#retrieve-all-project-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only. |
| [Projects](../projects.md) | `order_by=id` only | Authenticated and unauthenticated users. |
+| [Users](../users.md) | `order_by=id`, `order_by=name`, `order_by=username` | Authenticated and unauthenticated users. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419556) in GitLab 15.4 [with a flag](../../user/feature_flags.md)) named `api_keyset_pagination_multi_order`. Disabled by default. |
### Pagination response headers
diff --git a/doc/api/runners.md b/doc/api/runners.md
index 7c2bceb70eb..dba37edcb01 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -395,7 +395,7 @@ Example response:
"status": "running",
"stage": "test",
"name": "test",
- "ref": "master",
+ "ref": "main",
"tag": false,
"coverage": null,
"created_at": "2017-11-16T08:50:29.000Z",
@@ -439,7 +439,7 @@ Example response:
"pipeline": {
"id": 2,
"sha": "97de212e80737a608d939f648d959671fb0a0142",
- "ref": "master",
+ "ref": "main",
"status": "running"
},
"project": {
diff --git a/doc/api/saml.md b/doc/api/saml.md
index a44e1537f1e..60fd549f84f 100644
--- a/doc/api/saml.md
+++ b/doc/api/saml.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/scim.md b/doc/api/scim.md
index 94662250313..5fec030c110 100644
--- a/doc/api/scim.md
+++ b/doc/api/scim.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/search.md b/doc/api/search.md
index 06e62d28534..4a271d9ebdc 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -53,13 +53,13 @@ Example response:
"path": "flight",
"path_with_namespace": "twitter/flight",
"created_at": "2017-09-05T07:58:01.621Z",
- "default_branch": "master",
+ "default_branch": "main",
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo": "ssh://jarka@localhost:2222/twitter/flight.git",
"http_url_to_repo": "http://localhost:3000/twitter/flight.git",
"web_url": "http://localhost:3000/twitter/flight",
- "readme_url": "http://localhost:3000/twitter/flight/-/blob/master/README.md",
+ "readme_url": "http://localhost:3000/twitter/flight/-/blob/main/README.md",
"avatar_url": null,
"star_count": 0,
"forks_count": 0,
@@ -153,7 +153,7 @@ Example response:
"state": "opened",
"created_at": "2018-01-22T14:21:50.830Z",
"updated_at": "2018-02-06T12:40:33.295Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "jaja-test",
"upvotes": 0,
"downvotes": 0,
@@ -290,7 +290,7 @@ Example response:
"path": "home.md",
"filename": "home.md",
"id": null,
- "ref": "master",
+ "ref": "main",
"startline": 5,
"project_id": 6,
"group_id": null
@@ -367,7 +367,7 @@ Example response:
"path": "README.md",
"filename": "README.md",
"id": null,
- "ref": "master",
+ "ref": "main",
"startline": 46,
"project_id": 6
}
@@ -475,13 +475,13 @@ Example response:
"path": "flight",
"path_with_namespace": "twitter/flight",
"created_at": "2017-09-05T07:58:01.621Z",
- "default_branch": "master",
+ "default_branch": "main",
"tag_list":[], //deprecated, use `topics` instead
"topics":[],
"ssh_url_to_repo": "ssh://jarka@localhost:2222/twitter/flight.git",
"http_url_to_repo": "http://localhost:3000/twitter/flight.git",
"web_url": "http://localhost:3000/twitter/flight",
- "readme_url": "http://localhost:3000/twitter/flight/-/blob/master/README.md",
+ "readme_url": "http://localhost:3000/twitter/flight/-/blob/main/README.md",
"avatar_url": null,
"star_count": 0,
"forks_count": 0,
@@ -575,7 +575,7 @@ Example response:
"state": "opened",
"created_at": "2018-01-22T14:21:50.830Z",
"updated_at": "2018-02-06T12:40:33.295Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "jaja-test",
"upvotes": 0,
"downvotes": 0,
@@ -681,7 +681,7 @@ Example response:
"path": "home.md",
"filename": "home.md",
"id": null,
- "ref": "master",
+ "ref": "main",
"startline": 5,
"project_id": 6,
"group_id": 1
@@ -758,7 +758,7 @@ Example response:
"path": "README.md",
"filename": "README.md",
"id": null,
- "ref": "master",
+ "ref": "main",
"startline": 46,
"project_id": 6
}
@@ -934,7 +934,7 @@ Example response:
"state": "opened",
"created_at": "2018-01-22T14:21:50.830Z",
"updated_at": "2018-02-06T12:40:33.295Z",
- "target_branch": "master",
+ "target_branch": "main",
"source_branch": "jaja-test",
"upvotes": 0,
"downvotes": 0,
@@ -1094,7 +1094,7 @@ Example response:
"path": "home.md",
"filename": "home.md",
"id": null,
- "ref": "master",
+ "ref": "main",
"startline": 5,
"project_id": 6,
"group_id": 1
@@ -1177,7 +1177,7 @@ Example response:
"path": "README.md",
"filename": "README.md",
"id": null,
- "ref": "master",
+ "ref": "main",
"startline": 46,
"project_id": 6
}
diff --git a/doc/api/settings.md b/doc/api/settings.md
index aeb95f54431..d1921739d5c 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -17,6 +17,9 @@ For information on how to control the application settings cache for an instance
## Get current application settings
+> - `always_perform_delayed_deletion` feature flag [enabled](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332) in GitLab 15.11.
+> - `delayed_project_deletion` and `delayed_group_deletion` attributes removed in GitLab 16.0.
+
List the current [application settings](#list-of-settings-that-can-be-accessed-via-api-calls)
of the GitLab instance.
@@ -65,6 +68,7 @@ Example response:
"container_registry_expiration_policies_caching": true,
"container_registry_expiration_policies_worker_capacity": 4,
"container_registry_token_expire_delay": 5,
+ "decompress_archive_file_timeout": 210,
"repository_storages_weighted": {"default": 100},
"plantuml_enabled": false,
"plantuml_url": null,
@@ -126,8 +130,6 @@ these parameters:
- `file_template_project_id`
- `geo_node_allowed_ips`
- `geo_status_timeout`
-- `delayed_project_deletion`
-- `delayed_group_deletion`
- `default_project_deletion_protection`
- `deletion_adjourned_period`
- `disable_personal_access_tokens`
@@ -135,9 +137,6 @@ these parameters:
- `delete_unconfirmed_users`
- `unconfirmed_users_delete_after_days`
-From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled,
-the `delayed_project_deletion` and `delayed_group_deletion` attributes will not be exposed. These attributes will be removed in GitLab 16.0.
-
```json
{
"id": 1,
@@ -145,8 +144,6 @@ the `delayed_project_deletion` and `delayed_group_deletion` attributes will not
"group_owners_can_manage_default_branch_protection": true,
"file_template_project_id": 1,
"geo_node_allowed_ips": "0.0.0.0/0, ::/0",
- "delayed_project_deletion": false,
- "delayed_group_deletion": false,
"default_project_deletion_protection": false,
"deletion_adjourned_period": 7,
"disable_personal_access_tokens": false,
@@ -156,6 +153,9 @@ the `delayed_project_deletion` and `delayed_group_deletion` attributes will not
## Change application settings
+> - `always_perform_delayed_deletion` feature flag [enabled](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332) in GitLab 15.11.
+> - `delayed_project_deletion` and `delayed_group_deletion` attributes removed in GitLab 16.0.
+
Use an API call to modify GitLab instance
[application settings](#list-of-settings-that-can-be-accessed-via-api-calls).
@@ -208,6 +208,7 @@ Example response:
"container_registry_expiration_policies_caching": true,
"container_registry_expiration_policies_worker_capacity": 4,
"container_registry_token_expire_delay": 5,
+ "decompress_archive_file_timeout": 210,
"package_registry_cleanup_policies_worker_capacity": 2,
"repository_storages": ["default"],
"plantuml_enabled": false,
@@ -271,8 +272,6 @@ these parameters:
- `file_template_project_id`
- `geo_node_allowed_ips`
- `geo_status_timeout`
-- `delayed_project_deletion`
-- `delayed_group_deletion`
- `default_project_deletion_protection`
- `deletion_adjourned_period`
- `disable_personal_access_tokens`
@@ -280,9 +279,6 @@ these parameters:
- `delete_unconfirmed_users`
- `unconfirmed_users_delete_after_days`
-From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled,
-the `delayed_project_deletion` and `delayed_group_deletion` attributes will not be exposed. These attributes will be removed in GitLab 16.0.
-
Example responses: **(PREMIUM SELF)**
```json
@@ -312,8 +308,8 @@ listed in the descriptions of the relevant settings.
| `after_sign_up_text` | string | no | Text shown to the user after signing up. |
| `akismet_api_key` | string | required by: `akismet_enabled` | API key for Akismet spam protection. |
| `akismet_enabled` | boolean | no | (**If enabled, requires:** `akismet_api_key`) Enable or disable Akismet spam protection. |
-| `allow_account_deletion` **(PREMIUM)** | boolean | no | Set to `true` to allow users to delete their accounts. |
-| `allow_group_owners_to_manage_ldap` **(PREMIUM)** | boolean | no | Set to `true` to allow group owners to manage LDAP. |
+| `allow_account_deletion` **(PREMIUM ALL)** | boolean | no | Set to `true` to allow users to delete their accounts. |
+| `allow_group_owners_to_manage_ldap` **(PREMIUM ALL)** | boolean | no | Set to `true` to allow group owners to manage LDAP. |
| `allow_local_requests_from_hooks_and_services` | boolean | no | (Deprecated: Use `allow_local_requests_from_web_hooks_and_services` instead) Allow requests to the local network from webhooks and integrations. |
| `allow_local_requests_from_system_hooks` | boolean | no | Allow requests to the local network from system hooks. |
| `allow_local_requests_from_web_hooks_and_services` | boolean | no | Allow requests to the local network from webhooks and integrations. |
@@ -328,10 +324,10 @@ listed in the descriptions of the relevant settings.
| `auto_devops_domain` | string | no | Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages. |
| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for projects by default. It automatically builds, tests, and deploys applications based on a predefined CI/CD configuration. |
| `automatic_purchased_storage_allocation` | boolean | no | Enabling this permits automatic allocation of purchased storage in a namespace. Relevant only to EE distributions. |
-| `bulk_import_enabled` | boolean | no | Enable migrating GitLab groups by direct transfer. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383268) in GitLab 15.8. Setting also [available](../administration/settings/visibility_and_access_controls.md#enable-migration-of-groups-and-projects-by-direct-transfer) in the Admin Area. |
+| `bulk_import_enabled` | boolean | no | Enable migrating GitLab groups by direct transfer. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383268) in GitLab 15.8. Setting also [available](../administration/settings/import_and_export_settings.md#enable-migration-of-groups-and-projects-by-direct-transfer) in the Admin Area. |
| `bulk_import_max_download_file_size` | integer | no | Maximum download file size when importing from source GitLab instances by direct transfer. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384976) in GitLab 16.3. |
| `can_create_group` | boolean | no | Indicates whether users can create top-level groups. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367754) in GitLab 15.5. Defaults to `true`. |
-| `check_namespace_plan` **(PREMIUM)** | boolean | no | Enabling this makes only licensed EE features available to projects if the project namespace's plan includes the feature or if the project is public. |
+| `check_namespace_plan` **(PREMIUM ALL)** | boolean | no | Enabling this makes only licensed EE features available to projects if the project namespace's plan includes the feature or if the project is public. |
| `ci_max_total_yaml_size_bytes` | integer | no | The maximum amount of memory, in bytes, that can be allocated for the pipeline configuration, with all included YAML configuration files. |
| `ci_max_includes` | integer | no | The [maximum number of includes](../administration/settings/continuous_integration.md#maximum-includes) per pipeline. Default is `150`. |
| `commit_email_hostname` | string | no | Custom hostname (for private commit emails). |
@@ -346,22 +342,21 @@ listed in the descriptions of the relevant settings.
| `allow_account_deletion` | boolean | no | Enable [users to delete their accounts](../administration/settings/account_and_limit_settings.md#prevent-users-from-deleting-their-accounts). |
| `deactivate_dormant_users` | boolean | no | Enable [automatic deactivation of dormant users](../administration/moderate_users.md#automatically-deactivate-dormant-users). |
| `deactivate_dormant_users_period` | integer | no | Length of time (in days) after which a user is considered dormant. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336747) in GitLab 15.3. |
+| `decompress_archive_file_timeout` | integer | no | Default timeout for decompressing archived files, in seconds. Set to 0 to disable timeouts. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129161) in GitLab 16.4. |
| `default_artifacts_expire_in` | string | no | Set the default expiration time for each job's artifacts. |
| `default_branch_name` | string | no | [Instance-level custom initial branch name](../user/project/repository/branches/default.md#instance-level-custom-initial-branch-name). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225258) in GitLab 13.2. |
| `default_branch_protection` | integer | no | Determine if developers can push to the default branch. Can take: `0` _(not protected, both users with the Developer role or Maintainer role can push new commits and force push)_, `1` _(partially protected, users with the Developer role or Maintainer role can push new commits, but cannot force push)_ or `2` _(fully protected, users with the Developer or Maintainer role cannot push new commits, but users with the Developer or Maintainer role can; no one can force push)_ as a parameter. Default is `2`. |
| `default_ci_config_path` | string | no | Default CI/CD configuration file and path for new projects (`.gitlab-ci.yml` if not set). |
-| `default_group_visibility` | string | no | What visibility level new groups receive. Can take `private`, `internal` and `public` as a parameter. Default is `private`. |
+| `default_group_visibility` | string | no | What visibility level new groups receive. Can take `private`, `internal` and `public` as a parameter. Default is `private`. [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131203) in GitLab 16.4: cannot be set to any levels in `restricted_visibility_levels`.|
| `default_preferred_language` | string | no | Default preferred language for users who are not logged in. |
| `default_project_creation` | integer | no | Default project creation protection. Can take: `0` _(No one)_, `1` _(Maintainers)_ or `2` _(Developers + Maintainers)_|
-| `default_project_visibility` | string | no | What visibility level new projects receive. Can take `private`, `internal` and `public` as a parameter. Default is `private`. |
+| `default_project_visibility` | string | no | What visibility level new projects receive. Can take `private`, `internal` and `public` as a parameter. Default is `private`. [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131203) in GitLab 16.4: cannot be set to any levels in `restricted_visibility_levels`.|
| `default_projects_limit` | integer | no | Project limit per user. Default is `100000`. |
| `default_snippet_visibility` | string | no | What visibility level new snippets receive. Can take `private`, `internal` and `public` as a parameter. Default is `private`. |
-| `default_syntax_highlighting_theme` | integer | no | Default syntax highlighting theme for new users and users who are not signed in. See [IDs of available themes](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/themes.rb#L16).
-| `delayed_project_deletion` **(PREMIUM SELF)** | boolean | no | Enable delayed project deletion by default in new groups. Default is `false`. [From GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/352960), can only be enabled when `delayed_group_deletion` is true. From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled, this attribute has been removed. This attribute will be completely removed in GitLab 16.0. |
-| `delayed_group_deletion` **(PREMIUM SELF)** | boolean | no | Enable delayed group deletion. Default is `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352959) in GitLab 15.0. [From GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/352960), disables and locks the group-level setting for delayed protect deletion when set to `false`. From [GitLab 15.11](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113332), with the `always_perform_delayed_deletion` feature flag enabled, this attribute has been removed. This attribute will be completely removed in GitLab 16.0. |
+| `default_syntax_highlighting_theme` | integer | no | Default syntax highlighting theme for users who are new or not signed in. See [IDs of available themes](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/themes.rb#L16). |
| `default_project_deletion_protection` **(PREMIUM SELF)** | boolean | no | Enable default project deletion protection so only administrators can delete projects. Default is `false`. |
| `delete_unconfirmed_users` **(PREMIUM SELF)** | boolean | no | Specifies whether users who have not confirmed their email should be deleted. Default is `false`. When set to `true`, unconfirmed users are deleted after `unconfirmed_users_delete_after_days` days. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352514) in GitLab 16.1. |
-| `deletion_adjourned_period` **(PREMIUM SELF)** | integer | no | The number of days to wait before deleting a project or group that is marked for deletion. Value must be between `1` and `90`. Defaults to `7`. [From GitLab 15.1](https://gitlab.com/gitlab-org/gitlab/-/issues/352960), a hook on `deletion_adjourned_period` sets the period to `1` on every update, and sets both `delayed_project_deletion` and `delayed_group_deletion` to `false` if the period is `0`. |
+| `deletion_adjourned_period` **(PREMIUM SELF)** | integer | no | Number of days to wait before deleting a project or group that is marked for deletion. Value must be between `1` and `90`. Defaults to `7`. |
| `diagramsnet_enabled` | boolean | no | (If enabled, requires `diagramsnet_url`) Enable [Diagrams.net integration](../administration/integration/diagrams_net.md). Default is `true`. |
| `diagramsnet_url` | string | required by: `diagramsnet_enabled` | The Diagrams.net instance URL for integration. |
| `diff_max_patch_bytes` | integer | no | Maximum [diff patch size](../administration/diff_limits.md), in bytes. |
@@ -384,25 +379,25 @@ listed in the descriptions of the relevant settings.
| `eks_account_id` | string | no | Amazon account ID. |
| `eks_integration_enabled` | boolean | no | Enable integration with Amazon EKS. |
| `eks_secret_access_key` | string | no | AWS IAM secret access key. |
-| `elasticsearch_aws_access_key` **(PREMIUM)** | string | no | AWS IAM access key. |
-| `elasticsearch_aws_region` **(PREMIUM)** | string | no | The AWS region the Elasticsearch domain is configured. |
-| `elasticsearch_aws_secret_access_key` **(PREMIUM)** | string | no | AWS IAM secret access key. |
-| `elasticsearch_aws` **(PREMIUM)** | boolean | no | Enable the use of AWS hosted Elasticsearch. |
-| `elasticsearch_indexed_field_length_limit` **(PREMIUM)** | integer | no | Maximum size of text fields to index by Elasticsearch. 0 value means no limit. This does not apply to repository and wiki indexing. |
-| `elasticsearch_indexed_file_size_limit_kb` **(PREMIUM)** | integer | no | Maximum size of repository and wiki files that are indexed by Elasticsearch. |
-| `elasticsearch_indexing` **(PREMIUM)** | boolean | no | Enable Elasticsearch indexing. |
-| `elasticsearch_requeue_workers` **(PREMIUM)** | boolean | no | Enable automatic requeuing of indexing workers. This improves non-code indexing throughput by enqueuing Sidekiq jobs until all documents are processed. |
-| `elasticsearch_limit_indexing` **(PREMIUM)** | boolean | no | Limit Elasticsearch to index certain namespaces and projects. |
-| `elasticsearch_max_bulk_concurrency` **(PREMIUM)** | integer | no | Maximum concurrency of Elasticsearch bulk requests per indexing operation. This only applies to repository indexing operations. |
-| `elasticsearch_worker_number_of_shards` **(PREMIUM)** | integer | no | Number of indexing worker shards. This improves non-code indexing throughput by enqueuing more parallel Sidekiq jobs. Default is `2`. |
-| `elasticsearch_max_bulk_size_mb` **(PREMIUM)** | integer | no | Maximum size of Elasticsearch bulk indexing requests in MB. This only applies to repository indexing operations. |
-| `elasticsearch_namespace_ids` **(PREMIUM)** | array of integers | no | The namespaces to index via Elasticsearch if `elasticsearch_limit_indexing` is enabled. |
-| `elasticsearch_project_ids` **(PREMIUM)** | array of integers | no | The projects to index via Elasticsearch if `elasticsearch_limit_indexing` is enabled. |
-| `elasticsearch_search` **(PREMIUM)** | boolean | no | Enable Elasticsearch search. |
-| `elasticsearch_url` **(PREMIUM)** | string | no | The URL to use for connecting to Elasticsearch. Use a comma-separated list to support cluster (for example, `http://localhost:9200, http://localhost:9201"`). |
-| `elasticsearch_username` **(PREMIUM)** | string | no | The `username` of your Elasticsearch instance. |
-| `elasticsearch_password` **(PREMIUM)** | string | no | The password of your Elasticsearch instance. |
-| `email_additional_text` **(PREMIUM)** | string | no | Additional text added to the bottom of every email for legal/auditing/compliance reasons. |
+| `elasticsearch_aws_access_key` **(PREMIUM ALL)** | string | no | AWS IAM access key. |
+| `elasticsearch_aws_region` **(PREMIUM ALL)** | string | no | The AWS region the Elasticsearch domain is configured. |
+| `elasticsearch_aws_secret_access_key` **(PREMIUM ALL)** | string | no | AWS IAM secret access key. |
+| `elasticsearch_aws` **(PREMIUM ALL)** | boolean | no | Enable the use of AWS hosted Elasticsearch. |
+| `elasticsearch_indexed_field_length_limit` **(PREMIUM ALL)** | integer | no | Maximum size of text fields to index by Elasticsearch. 0 value means no limit. This does not apply to repository and wiki indexing. |
+| `elasticsearch_indexed_file_size_limit_kb` **(PREMIUM ALL)** | integer | no | Maximum size of repository and wiki files that are indexed by Elasticsearch. |
+| `elasticsearch_indexing` **(PREMIUM ALL)** | boolean | no | Enable Elasticsearch indexing. |
+| `elasticsearch_requeue_workers` **(PREMIUM ALL)** | boolean | no | Enable automatic requeuing of indexing workers. This improves non-code indexing throughput by enqueuing Sidekiq jobs until all documents are processed. |
+| `elasticsearch_limit_indexing` **(PREMIUM ALL)** | boolean | no | Limit Elasticsearch to index certain namespaces and projects. |
+| `elasticsearch_max_bulk_concurrency` **(PREMIUM ALL)** | integer | no | Maximum concurrency of Elasticsearch bulk requests per indexing operation. This only applies to repository indexing operations. |
+| `elasticsearch_worker_number_of_shards` **(PREMIUM ALL)** | integer | no | Number of indexing worker shards. This improves non-code indexing throughput by enqueuing more parallel Sidekiq jobs. Default is `2`. |
+| `elasticsearch_max_bulk_size_mb` **(PREMIUM ALL)** | integer | no | Maximum size of Elasticsearch bulk indexing requests in MB. This only applies to repository indexing operations. |
+| `elasticsearch_namespace_ids` **(PREMIUM ALL)** | array of integers | no | The namespaces to index via Elasticsearch if `elasticsearch_limit_indexing` is enabled. |
+| `elasticsearch_project_ids` **(PREMIUM ALL)** | array of integers | no | The projects to index via Elasticsearch if `elasticsearch_limit_indexing` is enabled. |
+| `elasticsearch_search` **(PREMIUM ALL)** | boolean | no | Enable Elasticsearch search. |
+| `elasticsearch_url` **(PREMIUM ALL)** | string | no | The URL to use for connecting to Elasticsearch. Use a comma-separated list to support cluster (for example, `http://localhost:9200, http://localhost:9201"`). |
+| `elasticsearch_username` **(PREMIUM ALL)** | string | no | The `username` of your Elasticsearch instance. |
+| `elasticsearch_password` **(PREMIUM ALL)** | string | no | The password of your Elasticsearch instance. |
+| `email_additional_text` **(PREMIUM ALL)** | string | no | Additional text added to the bottom of every email for legal/auditing/compliance reasons. |
| `email_author_in_body` | boolean | no | Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead. |
| `email_confirmation_setting` | string | no | Specifies whether users must confirm their email before sign in. Possible values are `off`, `soft`, and `hard`. |
| `custom_http_clone_url_root` | string | no | Set a custom Git clone URL for HTTP(S). |
@@ -421,12 +416,12 @@ listed in the descriptions of the relevant settings.
| `external_pipeline_validation_service_timeout` | integer | no | How long to wait for a response from the pipeline validation service. Assumes `OK` if it times out. |
| `static_objects_external_storage_url` | string | no | URL to an external storage for repository static objects. |
| `static_objects_external_storage_auth_token` | string | required by: `static_objects_external_storage_url` | Authentication token for the external storage linked in `static_objects_external_storage_url`. |
-| `file_template_project_id` **(PREMIUM)** | integer | no | The ID of a project to load custom file templates from. |
+| `file_template_project_id` **(PREMIUM ALL)** | integer | no | The ID of a project to load custom file templates from. |
| `first_day_of_week` | integer | no | Start day of the week for calendar views and date pickers. Valid values are `0` (default) for Sunday, `1` for Monday, and `6` for Saturday. |
| `globally_allowed_ips` | string | no | Comma-separated list of IP addresses and CIDRs always allowed for inbound traffic. For example, `1.1.1.1, 2.2.2.0/24`. |
-| `geo_node_allowed_ips` **(PREMIUM)** | string | yes | Comma-separated list of IPs and CIDRs of allowed secondary nodes. For example, `1.1.1.1, 2.2.2.0/24`. |
-| `geo_status_timeout` **(PREMIUM)** | integer | no | The amount of seconds after which a request to get a secondary node status times out. |
-| `git_two_factor_session_expiry` **(PREMIUM)** | integer | no | Maximum duration (in minutes) of a session for Git operations when 2FA is enabled. |
+| `geo_node_allowed_ips` **(PREMIUM ALL)** | string | yes | Comma-separated list of IPs and CIDRs of allowed secondary nodes. For example, `1.1.1.1, 2.2.2.0/24`. |
+| `geo_status_timeout` **(PREMIUM ALL)** | integer | no | The amount of seconds after which a request to get a secondary node status times out. |
+| `git_two_factor_session_expiry` **(PREMIUM ALL)** | integer | no | Maximum duration (in minutes) of a session for Git operations when 2FA is enabled. |
| `gitaly_timeout_default` | integer | no | Default Gitaly timeout, in seconds. This timeout is not enforced for Git fetch/push operations or Sidekiq jobs. Set to `0` to disable timeouts. |
| `gitaly_timeout_fast` | integer | no | Gitaly fast operation timeout, in seconds. Some Gitaly operations are expected to be fast. If they exceed this threshold, there may be a problem with a storage shard and 'failing fast' can help maintain the stability of the GitLab instance. Set to `0` to disable timeouts. |
| `gitaly_timeout_medium` | integer | no | Medium Gitaly timeout, in seconds. This should be a value between the Fast and the Default timeout. Set to `0` to disable timeouts. |
@@ -439,7 +434,7 @@ listed in the descriptions of the relevant settings.
| `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help. |
| `help_page_support_url` | string | no | Alternate support URL for help page and help dropdown list. |
| `help_page_text` | string | no | Custom text displayed on the help page. |
-| `help_text` **(PREMIUM)** | string | no | Deprecated: Use `description` parameter in the [Appearance API](../api/appearance.md). Custom text in sign-in page. |
+| `help_text` **(PREMIUM ALL)** | string | no | Deprecated: Use `description` parameter in the [Appearance API](../api/appearance.md). Custom text in sign-in page. |
| `hide_third_party_offers` | boolean | no | Do not display offers from third parties in GitLab. |
| `home_page_url` | string | no | Redirect to this URL when not logged in. |
| `housekeeping_bitmaps_enabled` | boolean | no | Deprecated. Git pack file bitmap creation is always enabled and cannot be changed via API and UI. Always returns `true`. |
@@ -457,8 +452,8 @@ listed in the descriptions of the relevant settings.
| `local_markdown_version` | integer | no | Increase this value when any cached Markdown should be invalidated. |
| `mailgun_signing_key` | string | no | The Mailgun HTTP webhook signing key for receiving events from webhook. |
| `mailgun_events_enabled` | boolean | no | Enable Mailgun event receiver. |
-| `maintenance_mode_message` **(PREMIUM)** | string | no | Message displayed when instance is in maintenance mode. |
-| `maintenance_mode` **(PREMIUM)** | boolean | no | When instance is in maintenance mode, non-administrative users can sign in with read-only access and make read-only API requests. |
+| `maintenance_mode_message` **(PREMIUM ALL)** | string | no | Message displayed when instance is in maintenance mode. |
+| `maintenance_mode` **(PREMIUM ALL)** | boolean | no | When instance is in maintenance mode, non-administrative users can sign in with read-only access and make read-only API requests. |
| `max_artifacts_size` | integer | no | Maximum artifacts size in MB. |
| `max_attachment_size` | integer | no | Limit attachment size in MB. |
| `max_decompressed_archive_size` | integer | no | Maximum decompressed file size for imported archives in MB. Set to `0` for unlimited. Default is `25600`. |
@@ -478,23 +473,23 @@ listed in the descriptions of the relevant settings.
| `git_rate_limit_users_alertlist` **(ULTIMATE SELF)** | array of integers | no | List of user IDs that are emailed when the Git abuse rate limit is exceeded. Default: `[]`, Maximum: 100 user IDs. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110201) in GitLab 15.9. |
| `auto_ban_user_on_excessive_projects_download` **(ULTIMATE SELF)** | boolean | no | When enabled, users will get automatically banned from the application when they download more than the maximum number of unique projects in the time period specified by `max_number_of_repository_downloads` and `max_number_of_repository_downloads_within_time_period` respectively. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94153) in GitLab 15.4 |
| `mirror_available` | boolean | no | Allow repository mirroring to configured by project Maintainers. If disabled, only Administrators can configure repository mirroring. |
-| `mirror_capacity_threshold` **(PREMIUM)** | integer | no | Minimum capacity to be available before scheduling more mirrors preemptively. |
-| `mirror_max_capacity` **(PREMIUM)** | integer | no | Maximum number of mirrors that can be synchronizing at the same time. |
-| `mirror_max_delay` **(PREMIUM)** | integer | no | Maximum time (in minutes) between updates that a mirror can have when scheduled to synchronize. |
-| `maven_package_requests_forwarding` **(PREMIUM)** | boolean | no | Use repo.maven.apache.org as a default remote repository when the package is not found in the GitLab Package Registry for Maven. |
-| `npm_package_requests_forwarding` **(PREMIUM)** | boolean | no | Use npmjs.org as a default remote repository when the package is not found in the GitLab Package Registry for npm. |
-| `pypi_package_requests_forwarding` **(PREMIUM)** | boolean | no | Use pypi.org as a default remote repository when the package is not found in the GitLab Package Registry for PyPI. |
+| `mirror_capacity_threshold` **(PREMIUM ALL)** | integer | no | Minimum capacity to be available before scheduling more mirrors preemptively. |
+| `mirror_max_capacity` **(PREMIUM ALL)** | integer | no | Maximum number of mirrors that can be synchronizing at the same time. |
+| `mirror_max_delay` **(PREMIUM ALL)** | integer | no | Maximum time (in minutes) between updates that a mirror can have when scheduled to synchronize. |
+| `maven_package_requests_forwarding` **(PREMIUM ALL)** | boolean | no | Use repo.maven.apache.org as a default remote repository when the package is not found in the GitLab Package Registry for Maven. |
+| `npm_package_requests_forwarding` **(PREMIUM ALL)** | boolean | no | Use npmjs.org as a default remote repository when the package is not found in the GitLab Package Registry for npm. |
+| `pypi_package_requests_forwarding` **(PREMIUM ALL)** | boolean | no | Use pypi.org as a default remote repository when the package is not found in the GitLab Package Registry for PyPI. |
| `outbound_local_requests_whitelist` | array of strings | no | Define a list of trusted domains or IP addresses to which local requests are allowed when local requests for webhooks and integrations are disabled.
| `package_registry_allow_anyone_to_pull_option` | boolean | no | Enable to [allow anyone to pull from Package Registry](../user/packages/package_registry/index.md#allow-anyone-to-pull-from-package-registry) visible and changeable.
| `package_metadata_purl_types` **(ULTIMATE SELF)** | array of integers | no | List of [package registry metadata to sync](../administration/settings/security_and_compliance.md#choose-package-registry-metadata-to-sync). See [the list](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/concerns/enums/package_metadata.rb#L5) of the available values.
| `pages_domain_verification_enabled` | boolean | no | Require users to prove ownership of custom domains. Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled. |
| `password_authentication_enabled_for_git` | boolean | no | Enable authentication for Git over HTTP(S) via a GitLab account password. Default is `true`. |
| `password_authentication_enabled_for_web` | boolean | no | Enable authentication for the web interface via a GitLab account password. Default is `true`. |
-| `minimum_password_length` **(PREMIUM)** | integer | no | Indicates whether passwords require a minimum length. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
-| `password_number_required` **(PREMIUM)** | boolean | no | Indicates whether passwords require at least one number. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
-| `password_symbol_required` **(PREMIUM)** | boolean | no | Indicates whether passwords require at least one symbol character. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
-| `password_uppercase_required` **(PREMIUM)** | boolean | no | Indicates whether passwords require at least one uppercase letter. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
-| `password_lowercase_required` **(PREMIUM)** | boolean | no | Indicates whether passwords require at least one lowercase letter. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
+| `minimum_password_length` **(PREMIUM ALL)** | integer | no | Indicates whether passwords require a minimum length. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
+| `password_number_required` **(PREMIUM ALL)** | boolean | no | Indicates whether passwords require at least one number. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
+| `password_symbol_required` **(PREMIUM ALL)** | boolean | no | Indicates whether passwords require at least one symbol character. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
+| `password_uppercase_required` **(PREMIUM ALL)** | boolean | no | Indicates whether passwords require at least one uppercase letter. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
+| `password_lowercase_required` **(PREMIUM ALL)** | boolean | no | Indicates whether passwords require at least one lowercase letter. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85763) in GitLab 15.1. |
| `performance_bar_allowed_group_id` | string | no | (Deprecated: Use `performance_bar_allowed_group_path` instead) Path of the group that is allowed to toggle the performance bar. |
| `performance_bar_allowed_group_path` | string | no | Path of the group that is allowed to toggle the performance bar. |
| `performance_bar_enabled` | boolean | no | (Deprecated: Pass `performance_bar_allowed_group_path: nil` instead) Allow enabling the performance bar. |
@@ -528,21 +523,21 @@ listed in the descriptions of the relevant settings.
| `recaptcha_site_key` | string | required by: `recaptcha_enabled` | Site key for reCAPTCHA. |
| `receive_max_input_size` | integer | no | Maximum push size (MB). |
| `repository_checks_enabled` | boolean | no | GitLab periodically runs `git fsck` in all project and wiki repositories to look for silent disk corruption issues. |
-| `repository_size_limit` **(PREMIUM)** | integer | no | Size limit per repository (MB) |
+| `repository_size_limit` **(PREMIUM ALL)** | integer | no | Size limit per repository (MB) |
| `repository_storages_weighted` | hash of strings to integers | no | (GitLab 13.1 and later) Hash of names of taken from `gitlab.yml` to [weights](../administration/repository_storage_paths.md#configure-where-new-repositories-are-stored). New projects are created in one of these stores, chosen by a weighted random selection. |
| `repository_storages` | array of strings | no | (GitLab 13.0 and earlier) List of names of enabled storage paths, taken from `gitlab.yml`. New projects are created in one of these stores, chosen at random. |
| `require_admin_approval_after_user_signup` | boolean | no | When enabled, any user that signs up for an account using the registration form is placed under a **Pending approval** state and has to be explicitly [approved](../administration/moderate_users.md) by an administrator. |
| `require_two_factor_authentication` | boolean | no | (**If enabled, requires:** `two_factor_grace_period`) Require all users to set up Two-factor authentication. |
-| `restricted_visibility_levels` | array of strings | no | Selected levels cannot be used by non-Administrator users for groups, projects or snippets. Can take `private`, `internal` and `public` as a parameter. Default is `null` which means there is no restriction. |
+| `restricted_visibility_levels` | array of strings | no | Selected levels cannot be used by non-Administrator users for groups, projects or snippets. Can take `private`, `internal` and `public` as a parameter. Default is `null` which means there is no restriction.[Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131203) in GitLab 16.4: cannot select levels that are set as `default_project_visibility` and `default_group_visibility`. |
| `rsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded RSA key. Default is `0` (no restriction). `-1` disables RSA keys. |
| `session_expire_delay` | integer | no | Session duration in minutes. GitLab restart is required to apply changes. |
| `security_policy_global_group_approvers_enabled` | boolean | no | Whether to look up scan result policy approval groups globally or within project hierarchies. |
| `shared_runners_enabled` | boolean | no | (**If enabled, requires:** `shared_runners_text` and `shared_runners_minutes`) Enable shared runners for new projects. |
-| `shared_runners_minutes` **(PREMIUM)** | integer | required by: `shared_runners_enabled` | Set the maximum number of compute minutes that a group can use on shared runners per month. |
+| `shared_runners_minutes` **(PREMIUM ALL)** | integer | required by: `shared_runners_enabled` | Set the maximum number of compute minutes that a group can use on shared runners per month. |
| `shared_runners_text` | string | required by: `shared_runners_enabled` | Shared runners text. |
-| `runner_token_expiration_interval` | integer | no | Set the expiration time (in seconds) of authentication tokens of newly registered instance runners. Minimum value is 7200 seconds. For more information, see [Automatically rotate authentication tokens](../ci/runners/configure_runners.md#automatically-rotate-authentication-tokens). |
-| `group_runner_token_expiration_interval` | integer | no | Set the expiration time (in seconds) of authentication tokens of newly registered group runners. Minimum value is 7200 seconds. For more information, see [Automatically rotate authentication tokens](../ci/runners/configure_runners.md#automatically-rotate-authentication-tokens). |
-| `project_runner_token_expiration_interval` | integer | no | Set the expiration time (in seconds) of authentication tokens of newly registered project runners. Minimum value is 7200 seconds. For more information, see [Automatically rotate authentication tokens](../ci/runners/configure_runners.md#automatically-rotate-authentication-tokens). |
+| `runner_token_expiration_interval` | integer | no | Set the expiration time (in seconds) of authentication tokens of newly registered instance runners. Minimum value is 7200 seconds. For more information, see [Automatically rotate authentication tokens](../ci/runners/configure_runners.md#automatically-rotate-runner-authentication-tokens). |
+| `group_runner_token_expiration_interval` | integer | no | Set the expiration time (in seconds) of authentication tokens of newly registered group runners. Minimum value is 7200 seconds. For more information, see [Automatically rotate authentication tokens](../ci/runners/configure_runners.md#automatically-rotate-runner-authentication-tokens). |
+| `project_runner_token_expiration_interval` | integer | no | Set the expiration time (in seconds) of authentication tokens of newly registered project runners. Minimum value is 7200 seconds. For more information, see [Automatically rotate authentication tokens](../ci/runners/configure_runners.md#automatically-rotate-runner-authentication-tokens). |
| `sidekiq_job_limiter_mode` | string | no | `track` or `compress`. Sets the behavior for [Sidekiq job size limits](../administration/settings/sidekiq_job_limits.md). Default: 'compress'. |
| `sidekiq_job_limiter_compression_threshold_bytes` | integer | no | The threshold in bytes at which Sidekiq jobs are compressed before being stored in Redis. Default: 100,000 bytes (100 KB). |
| `sidekiq_job_limiter_limit_bytes` | integer | no | The threshold in bytes at which Sidekiq jobs are rejected. Default: 0 bytes (doesn't reject any job). |
@@ -558,6 +553,7 @@ listed in the descriptions of the relevant settings.
| `snippet_size_limit` | integer | no | Max snippet content size in **bytes**. Default: 52428800 Bytes (50 MB).|
| `snowplow_app_id` | string | no | The Snowplow site name / application ID. (for example, `gitlab`) |
| `snowplow_collector_hostname` | string | required by: `snowplow_enabled` | The Snowplow collector hostname. (for example, `snowplow.trx.gitlab.net`) |
+| `snowplow_database_collector_hostname` | string | no | The Snowplow collector for database events hostname. (for example, `db-snowplow.trx.gitlab.net`) |
| `snowplow_cookie_domain` | string | no | The Snowplow cookie domain. (for example, `.gitlab.com`) |
| `snowplow_enabled` | boolean | no | Enable snowplow tracking. |
| `sourcegraph_enabled` | boolean | no | Enables Sourcegraph integration. Default is `false`. **If enabled, requires** `sourcegraph_url`. |
@@ -602,7 +598,7 @@ listed in the descriptions of the relevant settings.
| `user_default_external` | boolean | no | Newly registered users are external by default. |
| `user_default_internal_regex` | string | no | Specify an email address regex pattern to identify default internal users. |
| `user_defaults_to_private_profile` | boolean | no | Newly created users have private profile by default. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231301) in GitLab 15.8. Defaults to `false`. |
-| `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider. |
+| `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider. This setting does not affect group-level OAuth applications. |
| `user_show_add_ssh_key_message` | boolean | no | When set to `false` disable the `You won't be able to pull or push project code via SSH` warning shown to users with no uploaded SSH key. |
| `version_check_enabled` | boolean | no | Let GitLab inform you when an update is available. |
| `valid_runner_registrars` | array of strings | no | List of types which are allowed to register a GitLab Runner. Can be `[]`, `['group']`, `['project']` or `['group', 'project']`. |
diff --git a/doc/api/snippets.md b/doc/api/snippets.md
index 6fa6be3a43b..84b1baab6c4 100644
--- a/doc/api/snippets.md
+++ b/doc/api/snippets.md
@@ -184,7 +184,7 @@ Parameters:
Example request:
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/snippets/1/files/master/snippet%2Erb/raw"
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/snippets/1/files/main/snippet%2Erb/raw"
```
Example response:
@@ -270,7 +270,7 @@ Example response:
"files": [
{
"path": "text.txt",
- "raw_url": "https://gitlab.example.com/-/snippets/1/raw/master/renamed.md"
+ "raw_url": "https://gitlab.example.com/-/snippets/1/raw/main/renamed.md"
}
]
}
@@ -355,7 +355,7 @@ Example response:
"files": [
{
"path": "renamed.md",
- "raw_url": "https://gitlab.example.com/-/snippets/1/raw/master/renamed.md"
+ "raw_url": "https://gitlab.example.com/-/snippets/1/raw/main/renamed.md"
}
]
}
diff --git a/doc/api/statistics.md b/doc/api/statistics.md
index 691b03505a7..b60b012e339 100644
--- a/doc/api/statistics.md
+++ b/doc/api/statistics.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/status_checks.md b/doc/api/status_checks.md
index c988f8d63fc..3ed3755732f 100644
--- a/doc/api/status_checks.md
+++ b/doc/api/status_checks.md
@@ -35,7 +35,7 @@ GET /projects/:id/external_status_checks
{
"id": 14,
"project_id": 6,
- "name": "master",
+ "name": "main",
"created_at": "2020-10-12T14:04:50.787Z",
"updated_at": "2020-10-12T14:04:50.787Z",
"code_owner_approval_required": false
@@ -216,7 +216,7 @@ In case status check is already passed status code is 422
"namespace": "Flightjs",
"visibility_level": 20,
"path_with_namespace": "flightjs/Flight",
- "default_branch": "master",
+ "default_branch": "main",
"ci_config_path": null,
"homepage": "http://example.com/flightjs/Flight",
"url": "ssh://example.com/flightjs/Flight.git",
@@ -242,10 +242,10 @@ In case status check is already passed status code is 422
"merge_user_id": null,
"merge_when_pipeline_succeeds": false,
"milestone_id": null,
- "source_branch": "root-master-patch-30152",
+ "source_branch": "root-main-patch-30152",
"source_project_id": 6,
"state_id": 1,
- "target_branch": "master",
+ "target_branch": "main",
"target_project_id": 6,
"time_estimate": 0,
"title": "Update README.md",
@@ -263,7 +263,7 @@ In case status check is already passed status code is 422
"namespace": "Flightjs",
"visibility_level": 20,
"path_with_namespace": "flightjs/Flight",
- "default_branch": "master",
+ "default_branch": "main",
"ci_config_path": null,
"homepage": "http://example.com/flightjs/Flight",
"url": "ssh://example.com/flightjs/Flight.git",
@@ -281,7 +281,7 @@ In case status check is already passed status code is 422
"namespace": "Flightjs",
"visibility_level": 20,
"path_with_namespace": "flightjs/Flight",
- "default_branch": "master",
+ "default_branch": "main",
"ci_config_path": null,
"homepage": "http://example.com/flightjs/Flight",
"url": "ssh://example.com/flightjs/Flight.git",
diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md
index 14a078ff68d..446c91d7971 100644
--- a/doc/api/system_hooks.md
+++ b/doc/api/system_hooks.md
@@ -10,7 +10,7 @@ All methods require administrator authorization.
You can configure the URL endpoint of the system hooks from the GitLab user interface:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **System Hooks** (`/admin/hooks`).
diff --git a/doc/api/tags.md b/doc/api/tags.md
index 4b85c70f901..cc4ff7be577 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -10,8 +10,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> `version` value for the `order_by` attribute [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95150) in GitLab 15.4.
-Get a list of repository tags from a project, sorted by update date and time in descending order. This endpoint can be accessed without authentication if the
-repository is publicly accessible.
+Get a list of repository tags from a project, sorted by update date and time in
+descending order.
+
+NOTE:
+If the repository is publicly accessible, authentication
+(`--header "PRIVATE-TOKEN: <your_access_token>"`) is not required.
```plaintext
GET /projects/:id/repository/tags
@@ -19,12 +23,19 @@ GET /projects/:id/repository/tags
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer or string| yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `order_by` | string | no | Return tags ordered by `name`, `updated`, or `version`. Default is `updated`. |
-| `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc`. |
-| `search` | string | no | Return list of tags matching the search criteria. You can use `^term` and `term$` to find tags that begin and end with `term` respectively. No other regular expressions are supported. |
+| Attribute | Type | Required | Description |
+|------------|-------------------|----------|-------------|
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `order_by` | string | no | Return tags ordered by `name`, `updated`, or `version`. Default is `updated`. |
+| `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc`. |
+| `search` | string | no | Return a list of tags matching the search criteria. You can use `^term` and `term$` to find tags that begin and end with `term` respectively. No other regular expressions are supported. |
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ --url "https://gitlab.example.com/api/v4/projects/5/repository/tags"
+```
+
+Example Response:
```json
[
@@ -68,13 +79,14 @@ GET /projects/:id/repository/tags/:tag_name
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `tag_name` | string | yes | The name of the tag |
+| Attribute | Type | Required | Description |
+|------------|-------------------|----------|-------------|
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `tag_name` | string | yes | The name of a tag. |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/tags/v1.0.0"
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ --url "https://gitlab.example.com/api/v4/projects/5/repository/tags/v1.0.0"
```
Example Response:
@@ -115,15 +127,17 @@ POST /projects/:id/repository/tags
Parameters:
-| Attribute | Type | Required | Description |
-| --------------------- | -------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `tag_name` | string | yes | The name of a tag |
-| `ref` | string | yes | Create tag using commit SHA, another tag name, or branch name |
-| `message` | string | no | Creates annotated tag |
+| Attribute | Type | Required | Description |
+|------------|-------------------|----------|-------------|
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `tag_name` | string | yes | The name of a tag. |
+| `ref` | string | yes | Create a tag from a commit SHA, another tag name, or branch name. |
+| `message` | string | no | Create an annotated tag. |
```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/tags?tag_name=test&ref=master"
+curl --request POST \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --url "https://gitlab.example.com/api/v4/projects/5/repository/tags?tag_name=test&ref=main"
```
Example response:
@@ -154,13 +168,12 @@ Example response:
}
```
-The message is `null` when creating a lightweight tag. Otherwise, it contains the annotation.
+The type of tag created determines the contents of `target` and `message`:
-The target contains the tag objects ID when creating annotated tags,
-otherwise it contains the commit ID when creating lightweight tags.
+- For annotated tags, `message` contains the annotation, and `target` contains the tag object's ID.
+- For lightweight tags, `message` is null, and `target` contains the commit ID.
-In case of an error,
-status code `405` with an explaining error message is returned.
+Errors return status code `405` with an explanatory error message.
## Delete a tag
@@ -172,16 +185,16 @@ DELETE /projects/:id/repository/tags/:tag_name
Parameters:
-| Attribute | Type | Required | Description |
-| ---------- | -------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
-| `tag_name` | string | yes | The name of a tag |
+| Attribute | Type | Required | Description |
+|------------|-------------------|----------|-------------|
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `tag_name` | string | yes | The name of a tag. |
## Get X.509 signature of a tag
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106578) in GitLab 15.7.
-Get the [X.509 signature from a tag](../user/project/repository/x509_signed_commits/index.md),
+Get the [X.509 signature from a tag](../user/project/repository/signed_commits/x509.md),
if it is signed. Unsigned tags return a `404 Not Found` response.
```plaintext
@@ -190,13 +203,14 @@ GET /projects/:id/repository/tags/:tag_name/signature
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `tag_name` | string | yes | The name of a tag. |
+| Attribute | Type | Required | Description |
+|------------|-------------------|----------|-------------|
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `tag_name` | string | yes | The name of a tag. |
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/repository/tags/v1.1.1/signature"
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ --url "https://gitlab.example.com/api/v4/projects/1/repository/tags/v1.1.1/signature"
```
Example response if tag is X.509 signed:
diff --git a/doc/api/topics.md b/doc/api/topics.md
index 5d413eec7c0..0c729a95fe5 100644
--- a/doc/api/topics.md
+++ b/doc/api/topics.md
@@ -22,10 +22,10 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ------------------ | ------- | ---------------------- | ----------- |
-| `page` | integer | **{dotted-circle}** No | Page to retrieve. Defaults to `1`. |
-| `per_page` | integer | **{dotted-circle}** No | Number of records to return per page. Defaults to `20`. |
-| `search` | string | **{dotted-circle}** No | Search topics against their `name`. |
-| `without_projects` | boolean | **{dotted-circle}** No | Limit results to topics without assigned projects. |
+| `page` | integer | No | Page to retrieve. Defaults to `1`. |
+| `per_page` | integer | No | Number of records to return per page. Defaults to `20`. |
+| `search` | string | No | Search topics against their `name`. |
+| `without_projects` | boolean | No | Limit results to topics without assigned projects. |
Example request:
@@ -76,7 +76,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
| --------- | ------- | ---------------------- | ------------------- |
-| `id` | integer | **{check-circle}** Yes | ID of project topic |
+| `id` | integer | Yes | ID of project topic |
Example request:
@@ -117,10 +117,10 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ------------- | ------- | ---------------------- | ----------- |
-| `name` | string | **{check-circle}** Yes | Slug (name) |
-| `title` | string | **{check-circle}** Yes | Title |
-| `avatar` | file | **{dotted-circle}** No | Avatar |
-| `description` | string | **{dotted-circle}** No | Description |
+| `name` | string | Yes | Slug (name) |
+| `title` | string | Yes | Title |
+| `avatar` | file | No | Avatar |
+| `description` | string | No | Description |
Example request:
@@ -156,11 +156,11 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ------------- | ------- | ---------------------- | ------------------- |
-| `id` | integer | **{check-circle}** Yes | ID of project topic |
-| `avatar` | file | **{dotted-circle}** No | Avatar |
-| `description` | string | **{dotted-circle}** No | Description |
-| `name` | string | **{dotted-circle}** No | Slug (name) |
-| `title` | string | **{dotted-circle}** No | Title |
+| `id` | integer | Yes | ID of project topic |
+| `avatar` | file | No | Avatar |
+| `description` | string | No | Description |
+| `name` | string | No | Slug (name) |
+| `title` | string | No | Title |
Example request:
@@ -228,7 +228,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ------------- | ------- | ---------------------- | ------------------- |
-| `id` | integer | **{check-circle}** Yes | ID of project topic |
+| `id` | integer | Yes | ID of project topic |
Example request:
@@ -253,8 +253,8 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ----------------- | ------- | ---------------------- | -------------------------- |
-| `source_topic_id` | integer | **{check-circle}** Yes | ID of source project topic |
-| `target_topic_id` | integer | **{check-circle}** Yes | ID of target project topic |
+| `source_topic_id` | integer | Yes | ID of source project topic |
+| `target_topic_id` | integer | Yes | ID of target project topic |
Example request:
diff --git a/doc/api/usage_data.md b/doc/api/usage_data.md
index 1a2c3e95002..a8e6c6ac205 100644
--- a/doc/api/usage_data.md
+++ b/doc/api/usage_data.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference, api
diff --git a/doc/api/users.md b/doc/api/users.md
index 9b00dc5c7e0..0652742c557 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -58,6 +58,8 @@ GET /users
]
```
+This endpoint supports [keyset pagination](rest/index.md#keyset-based-pagination). Keyset pagination [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419556) in GitLab 16.5 [with a flag](../user/feature_flags.md) named `api_keyset_pagination_multi_order`. Disabled by default.
+
You can also use `?search=` to search for users by name, username, or public email. For example, `/users?search=John`. When you search for a:
- Public email, you must use the full email address to get an exact match. A search might return a partial match. For example, if you search for the email `on@example.com`, the search can return both `on@example.com` and `jon@example.com`.
@@ -97,7 +99,7 @@ GET /users?external=true
```
GitLab supports bot users such as the [alert bot](../operations/incident_management/integrations.md)
-or the [support bot](../user/project/service_desk/index.md#support-bot-user).
+or the [support bot](../user/project/service_desk/configure.md#support-bot-user).
You can exclude the following types of [internal users](../development/internal_users.md#internal-users)
from the users' list with the `exclude_internal=true` parameter
([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241144) in GitLab 13.4):
@@ -146,9 +148,9 @@ You can use all [parameters available for everyone](#for-non-administrator-users
| `two_factor` | string | no | Filter users by Two-factor authentication. Filter values are `enabled` or `disabled`. By default it returns all users |
| `without_projects` | boolean | no | Filter users without projects. Default is `false`, which means that all users are returned, with and without projects. |
| `admins` | boolean | no | Return only administrators. Default is `false` |
-| `auditors` **(PREMIUM)** | boolean | no | Return only auditor users. Default is `false`. If not included, it returns all users. |
-| `saml_provider_id` **(PREMIUM)** | number | no | Return only users created by the specified SAML provider ID. If not included, it returns all users. |
-| `skip_ldap` **(PREMIUM)** | boolean | no | Skip LDAP users. |
+| `auditors` **(PREMIUM ALL)** | boolean | no | Return only auditor users. Default is `false`. If not included, it returns all users. |
+| `saml_provider_id` **(PREMIUM ALL)** | number | no | Return only users created by the specified SAML provider ID. If not included, it returns all users. |
+| `skip_ldap` **(PREMIUM ALL)** | boolean | no | Skip LDAP users. |
```json
[
@@ -326,6 +328,10 @@ Get a single user.
### For user
+Prerequisites:
+
+- You must be signed in to use this endpoint.
+
```plaintext
GET /users/:id
```
@@ -532,7 +538,7 @@ Parameters:
| Attribute | Required | Description |
| :----------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `admin` | No | User is an administrator. Valid values are `true` or `false`. Defaults to false.
-| `auditor` **(PREMIUM)** | No | User is an auditor. Valid values are `true` or `false`. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3. |
+| `auditor` **(PREMIUM ALL)** | No | User is an auditor. Valid values are `true` or `false`. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3. |
| `avatar` | No | Image file for user's avatar |
| `bio` | No | User's biography |
| `can_create_group` | No | User can create top-level groups - true or false |
@@ -540,7 +546,7 @@ Parameters:
| `email` | Yes | Email |
| `extern_uid` | No | External UID |
| `external` | No | Flags the user as external - true or false (default) |
-| `extra_shared_runners_minutes_limit` **(PREMIUM)** | No | Can be set by administrators only. Additional compute minutes for this user. |
+| `extra_shared_runners_minutes_limit` **(PREMIUM ALL)** | No | Can be set by administrators only. Additional compute minutes for this user. |
| `force_random_password` | No | Set user password to a random value - true or false (default) |
| `group_id_for_saml` | No | ID of group where SAML has been configured |
| `linkedin` | No | LinkedIn |
@@ -553,7 +559,7 @@ Parameters:
| `projects_limit` | No | Number of projects user can create |
| `provider` | No | External provider name |
| `reset_password` | No | Send user password reset link - true or false(default) |
-| `shared_runners_minutes_limit` **(PREMIUM)** | No | Can be set by administrators only. Maximum number of monthly compute minutes for this user. Can be `nil` (default; inherit system default), `0` (unlimited), or `> 0`. |
+| `shared_runners_minutes_limit` **(PREMIUM ALL)** | No | Can be set by administrators only. Maximum number of monthly compute minutes for this user. Can be `nil` (default; inherit system default), `0` (unlimited), or `> 0`. |
| `skip_confirmation` | No | Skip confirmation - true or false (default) |
| `skype` | No | Skype ID |
| `theme_id` | No | GitLab theme for the user (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-color-theme) for more information) |
@@ -581,7 +587,7 @@ Parameters:
| Attribute | Required | Description |
| :----------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `admin` | No |User is an administrator. Valid values are `true` or `false`. Defaults to false.
-| `auditor` **(PREMIUM)** | No | User is an auditor. Valid values are `true` or `false`. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3.(default) |
+| `auditor` **(PREMIUM ALL)** | No | User is an auditor. Valid values are `true` or `false`. Defaults to false. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366404) in GitLab 15.3.(default) |
| `avatar` | No | Image file for user's avatar |
| `bio` | No | User's biography |
| `can_create_group` | No | User can create groups - true or false |
@@ -590,7 +596,7 @@ Parameters:
| `email` | No | Email |
| `extern_uid` | No | External UID |
| `external` | No | Flags the user as external - true or false (default) |
-| `extra_shared_runners_minutes_limit` **(PREMIUM)** | No | Can be set by administrators only. Additional compute minutes for this user. |
+| `extra_shared_runners_minutes_limit` **(PREMIUM ALL)** | No | Can be set by administrators only. Additional compute minutes for this user. |
| `group_id_for_saml` | No | ID of group where SAML has been configured |
| `id` | Yes | ID of the user |
| `linkedin` | No | LinkedIn |
@@ -604,7 +610,7 @@ Parameters:
| `pronouns` | No | Pronouns |
| `provider` | No | External provider name |
| `public_email` | No | Public email of the user (must be already verified) |
-| `shared_runners_minutes_limit` **(PREMIUM)** | No | Can be set by administrators only. Maximum number of monthly compute minutes for this user. Can be `nil` (default; inherit system default), `0` (unlimited) or `> 0`. |
+| `shared_runners_minutes_limit` **(PREMIUM ALL)** | No | Can be set by administrators only. Maximum number of monthly compute minutes for this user. Can be `nil` (default; inherit system default), `0` (unlimited) or `> 0`. |
| `skip_reconfirmation` | No | Skip reconfirmation - true or false (default) |
| `skype` | No | Skype ID |
| `theme_id` | No | GitLab theme for the user (for more information, see the [user preference documentation](../user/profile/preferences.md#change-the-color-theme) for more information) |
@@ -1265,7 +1271,7 @@ error occurs a `400 Bad Request` is returned with a message explaining the error
```
NOTE:
-This also adds an audit event, as described in [audit instance events](../administration/audit_events.md#instance-events). **(PREMIUM)**
+This also adds an audit event. **(PREMIUM ALL)**
## Delete SSH key for current user
@@ -1871,7 +1877,8 @@ Example response:
"id" : 2,
"created_at" : "2017-03-17T17:18:09.283Z",
"impersonation" : true,
- "expires_at" : "2017-04-04"
+ "expires_at" : "2017-04-04",
+ "last_used_at": "2017-03-24T09:44:21.722Z"
},
{
"active" : false,
@@ -1884,7 +1891,8 @@ Example response:
"created_at" : "2017-03-17T17:19:28.697Z",
"id" : 3,
"impersonation" : true,
- "expires_at" : "2017-04-14"
+ "expires_at" : "2017-04-14",
+ "last_used_at": "2017-03-24T09:44:21.722Z"
}
]
```
@@ -2026,7 +2034,7 @@ POST /users/:user_id/impersonation_tokens
| ------------ | ------- | -------- | --------------------------------------------------------------------------- |
| `user_id` | integer | yes | ID of the user |
| `name` | string | yes | Name of the impersonation token |
-| `expires_at` | date | no | Expiration date of the impersonation token in ISO format (`YYYY-MM-DD`) |
+| `expires_at` | date | yes | Expiration date of the impersonation token in ISO format (`YYYY-MM-DD`) |
| `scopes` | array | yes | Array of scopes of the impersonation token (`api`, `read_user`) |
```shell
diff --git a/doc/api/vulnerability_exports.md b/doc/api/vulnerability_exports.md
index ab25ca9e511..0886db257dd 100644
--- a/doc/api/vulnerability_exports.md
+++ b/doc/api/vulnerability_exports.md
@@ -187,11 +187,11 @@ The response is `404 Not Found` if the vulnerability export is not finished yet
Example response:
```csv
-Group Name,Project Name,Tool,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE,CWE,Other Identifiers,Detected At,Location,Activity,Comments,
-Gitlab.org,Defend,container_scanning,Trivy,resolved,CVE-2019-14697 in musl-utils-1.1.20-r4,"musl libc through 1.1.23 has an x87 floating-point stack adjustment imbalance, related to the math/i386/ directory. In some cases, use of this library could introduce out-of-bounds writes that are not present in an application's source code.",CVE-2019-14697 in musl-utils-1.1.20-r4,critical,CVE-2019-14697,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""musl-utils""}, ""version""=>""1.1.20-r4""}, ""operating_system""=>""alpine 3.9.2""}",true,"2022-10-07 13:41:08 UTC|root|resolved|changed vulnerability status to resolved",
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2019-19242 in sqlite-libs-3.26.0-r3,"SQLite 3.30.1 mishandles pExpr->y.pTab, as demonstrated by the TK_COLUMN case in sqlite3ExprCodeTarget in expr.c.",CVE-2019-19242 in sqlite-libs-3.26.0-r3,medium,CVE-2019-19242,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""sqlite-libs""}, ""version""=>""3.26.0-r3""}, ""operating_system""=>""alpine 3.9.2""}",true,"",
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2020-28928 in musl-1.1.20-r4,"In musl libc through 1.2.1, wcsnrtombs mishandles particular combinations of destination buffer size and source character limit, as demonstrated by an invalid write access (buffer overflow).",CVE-2020-28928 in musl-1.1.20-r4,medium,CVE-2020-28928,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""musl""}, ""version""=>""1.1.20-r4""}, ""operating_system""=>""alpine 3.9.2""}",true,"",
-Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') in rack,Carefully crafted requests can cause shell escape sequences to be written to the terminal via Rack's Lint middleware and CommonLogger middleware. These escape sequences can be leveraged to possibly execute commands in the victim's terminal.,Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') in rack,unknown,Gemfile.lock:rack:gemnasium:60b5a27f-4e4d-4ab4-8ae7-74b4b212e177,,Gemnasium-60b5a27f-4e4d-4ab4-8ae7-74b4b212e177; GHSA-wq4h-7r42-5hrr,2022-10-14 13:16:00 UTC,"{""file""=>""Gemfile.lock"", ""dependency""=>{""package""=>{""name""=>""rack""}, ""version""=>""2.2.3""}}",false,"",
-Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Denial of Service Vulnerability in Rack Multipart Parsing in rack,"Carefully crafted multipart POST requests can cause Rack's multipart parser to take much longer than expected, leading to a possible denial of service vulnerability. Impacted code will use Rack's multipart parser to parse multipart posts.",Denial of Service Vulnerability in Rack Multipart Parsing in rack,unknown,Gemfile.lock:rack:gemnasium:20daa17a-47b5-4f79-80c2-cd8f2db9805c,,Gemnasium-20daa17a-47b5-4f79-80c2-cd8f2db9805c; GHSA-hxqx-xwvh-44m2,2022-10-14 13:16:00 UTC,"{""file""=>""Gemfile.lock"", ""dependency""=>{""package""=>{""name""=>""rack""}, ""version""=>""2.2.3""}}",false,"",
-Gitlab.org,Defend,sast,Brakeman,detected,Possible SQL injection,,Possible SQL injection,medium,e52f23a259cd489168b4313317ac94a3f13bffde57b9635171c1a44a9f329e9a,,"""Brakeman Warning Code 0""",2022-10-13 15:16:36 UTC,"{""file""=>""main.rb"", ""class""=>""User"", ""method""=>""index"", ""start_line""=>3}",false,""
+Group Name,Project Name,Tool,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE,CWE,Other Identifiers,Detected At,Location,Activity,Comments,Full Path
+Gitlab.org,Defend,container_scanning,Trivy,resolved,CVE-2019-14697 in musl-utils-1.1.20-r4,"musl libc through 1.1.23 has an x87 floating-point stack adjustment imbalance, related to the math/i386/ directory. In some cases, use of this library could introduce out-of-bounds writes that are not present in an application's source code.",CVE-2019-14697 in musl-utils-1.1.20-r4,critical,CVE-2019-14697,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""musl-utils""}, ""version""=>""1.1.20-r4""}, ""operating_system""=>""alpine 3.9.2""}",true,"2022-10-07 13:41:08 UTC|root|resolved|changed vulnerability status to resolved",group/project/1
+Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2019-19242 in sqlite-libs-3.26.0-r3,"SQLite 3.30.1 mishandles pExpr->y.pTab, as demonstrated by the TK_COLUMN case in sqlite3ExprCodeTarget in expr.c.",CVE-2019-19242 in sqlite-libs-3.26.0-r3,medium,CVE-2019-19242,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""sqlite-libs""}, ""version""=>""3.26.0-r3""}, ""operating_system""=>""alpine 3.9.2""}",true,"",group/project/2
+Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2020-28928 in musl-1.1.20-r4,"In musl libc through 1.2.1, wcsnrtombs mishandles particular combinations of destination buffer size and source character limit, as demonstrated by an invalid write access (buffer overflow).",CVE-2020-28928 in musl-1.1.20-r4,medium,CVE-2020-28928,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""musl""}, ""version""=>""1.1.20-r4""}, ""operating_system""=>""alpine 3.9.2""}",true,"",group/project/3
+Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') in rack,Carefully crafted requests can cause shell escape sequences to be written to the terminal via Rack's Lint middleware and CommonLogger middleware. These escape sequences can be leveraged to possibly execute commands in the victim's terminal.,Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') in rack,unknown,Gemfile.lock:rack:gemnasium:60b5a27f-4e4d-4ab4-8ae7-74b4b212e177,,Gemnasium-60b5a27f-4e4d-4ab4-8ae7-74b4b212e177; GHSA-wq4h-7r42-5hrr,2022-10-14 13:16:00 UTC,"{""file""=>""Gemfile.lock"", ""dependency""=>{""package""=>{""name""=>""rack""}, ""version""=>""2.2.3""}}",false,"",group/project/4
+Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Denial of Service Vulnerability in Rack Multipart Parsing in rack,"Carefully crafted multipart POST requests can cause Rack's multipart parser to take much longer than expected, leading to a possible denial of service vulnerability. Impacted code will use Rack's multipart parser to parse multipart posts.",Denial of Service Vulnerability in Rack Multipart Parsing in rack,unknown,Gemfile.lock:rack:gemnasium:20daa17a-47b5-4f79-80c2-cd8f2db9805c,,Gemnasium-20daa17a-47b5-4f79-80c2-cd8f2db9805c; GHSA-hxqx-xwvh-44m2,2022-10-14 13:16:00 UTC,"{""file""=>""Gemfile.lock"", ""dependency""=>{""package""=>{""name""=>""rack""}, ""version""=>""2.2.3""}}",false,"",group/project/5
+Gitlab.org,Defend,sast,Brakeman,detected,Possible SQL injection,,Possible SQL injection,medium,e52f23a259cd489168b4313317ac94a3f13bffde57b9635171c1a44a9f329e9a,,"""Brakeman Warning Code 0""",2022-10-13 15:16:36 UTC,"{""file""=>""main.rb"", ""class""=>""User"", ""method""=>""index"", ""start_line""=>3}",false,"",group/project/6
```
diff --git a/doc/api/vulnerability_findings.md b/doc/api/vulnerability_findings.md
index a031e07fddf..05ae42d9100 100644
--- a/doc/api/vulnerability_findings.md
+++ b/doc/api/vulnerability_findings.md
@@ -142,63 +142,81 @@ To prepare for the [upcoming deprecation](https://gitlab.com/groups/gitlab-org/-
the Vulnerability Findings REST API endpoint, use the examples below to perform the equivalent operations
with the GraphQL API.
-### GraphQL - Project vulnerabilities
+### GraphQL - Project vulnerability findings
-Use [`Project.vulnerabilities`](graphql/reference/index.md#projectvulnerabilities).
+Use [`Pipeline.securityReportFindings`](graphql/reference/index.md#pipelinesecurityreportfindings).
```graphql
-{
- project(fullPath: "root/security-reports") {
- vulnerabilities {
- nodes{
- id
- reportType
- title
- severity
- scanner {
- externalId
- name
- vendor
- }
- identifiers {
- externalType
- externalId
- name
- url
- }
- falsePositive
- project {
- id
- name
- fullPath
- }
- description
- links {
- name
- url
- }
- location {
- ... on
- VulnerabilityLocationSast {
- file
- startLine
- endLine
- vulnerableClass
- vulnerableMethod
- blobPath
- }
- }
- details {
- ... on
- VulnerabilityDetailCode {
+query VulnerabilityFindings {
+ project(fullPath: "gitlab-examples/security/security-reports") {
+ pipelines(first:1) {
+ nodes {
+ securityReportFindings(first:1) {
+ nodes {
+ title
+ severity
+ state
+ scanner {
+ externalId
+ name
+ vendor
+ }
+ identifiers {
+ externalType
+ externalId
+ name
+ url
+ }
+ uuid
+ falsePositive
description
- fieldName
- lang
- name
- value
+ location {
+ ... on VulnerabilityLocationSast {
+ file
+ startLine
+ endLine
+ vulnerableClass
+ vulnerableMethod
+ blobPath
+ }
+
+ ... on VulnerabilityLocationContainerScanning {
+ dependency {
+ package {
+ name
+ }
+ version
+ }
+ image
+ operatingSystem
+ }
+
+ ... on VulnerabilityLocationDependencyScanning {
+ file
+ blobPath
+ dependency {
+ version
+ }
+ }
+ }
+ remediations {
+ diff
+ summary
+ }
+ solution
+ evidence {
+ request {
+ body
+ headers {
+ name
+ value
+ }
+ method
+ url
+ }
+ }
}
}
- state
}
}
}
@@ -211,50 +229,56 @@ Example response:
{
"data": {
"project": {
- "vulnerabilities": {
+ "pipelines": {
"nodes": [
{
- "id": "gid://gitlab/Vulnerability/236",
- "reportType": "SAST",
- "title": "Generic Object Injection Sink",
- "severity": "CRITICAL",
- "scanner": {
- "externalId": "eslint",
- "name": "ESLint",
- "vendor": "GitLab"
- },
- "identifiers": [
- {
- "externalType": "eslint_rule_id",
- "externalId": "security/detect-object-injection",
- "name": "ESLint rule ID security/detect-object-injection",
- "url": "https://github.com/nodesecurity/eslint-plugin-security#detect-object-injection"
- },
- {
- "externalType": "cwe",
- "externalId": "94",
- "name": "CWE-94",
- "url": "https://cwe.mitre.org/data/definitions/94.html"
- }
- ],
- "falsePositive": false,
- "project": {
- "id": "gid://gitlab/Project/20",
- "name": "Security Reports",
- "fullPath": "root/security-reports"
- },
- "description": "Bracket object notation with user input is present, this might allow an attacker to access all properties of the object and even it's prototype, leading to possible code execution.",
- "links": [],
- "location": {
- "file": "src/js/main.js",
- "startLine": "28",
- "endLine": "28",
- "vulnerableClass": null,
- "vulnerableMethod": null,
- "blobPath": "/root/security-reports/-/blob/91031428a5b5dbb81e8d889738b1875c1bfea787/src/js/main.js"
- },
- "details": [],
- "state": "DETECTED"
+ "securityReportFindings": {
+ "nodes": [
+ {
+ "title": "Deserialization of Untrusted Data",
+ "severity": "CRITICAL",
+ "state": "CONFIRMED",
+ "scanner": {
+ "externalId": "gemnasium",
+ "name": "Gemnasium",
+ "vendor": "GitLab"
+ },
+ "identifiers": [
+ {
+ "externalType": "gemnasium",
+ "externalId": "b60c2d6b-9083-4a97-a1b2-f7dc79bff74c",
+ "name": "Gemnasium-b60c2d6b-9083-4a97-a1b2-f7dc79bff74c",
+ "url": "https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/blob/master/gem/activerecord/CVE-2022-32224.yml"
+ },
+ {
+ "externalType": "cve",
+ "externalId": "CVE-2022-32224",
+ "name": "CVE-2022-32224",
+ "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-32224"
+ },
+ {
+ "externalType": "ghsa",
+ "externalId": "GHSA-3hhc-qp5v-9p2j",
+ "name": "GHSA-3hhc-qp5v-9p2j",
+ "url": "https://github.com/advisories/GHSA-3hhc-qp5v-9p2j"
+ }
+ ],
+ "uuid": "c9e40395-72cd-54f5-962f-e1d52c0dffab",
+ "falsePositive": false,
+ "description": "A possible escalation to RCE vulnerability exists when using YAML serialized columns in Active Record < 7.0.3.1, <6.1.6.1, <6.0.5.1 and <5.2.8.1 which could allow an attacker, that can manipulate data in the database (via means like SQL injection), the ability to escalate to an RCE.",
+ "location": {
+ "file": "dependency-scanning-files/Gemfile.lock",
+ "blobPath": null,
+ "dependency": {
+ "version": "5.0.0"
+ }
+ },
+ "remediations": [],
+ "solution": "Upgrade to versions 5.2.8.1, 6.0.5.1, 6.1.6.1, 7.0.3.1 or above.",
+ "evidence": null
+ }
+ ]
+ }
}
]
}
diff --git a/doc/api/wikis.md b/doc/api/wikis.md
index 3a5b8b075f5..c33d66a14e4 100644
--- a/doc/api/wikis.md
+++ b/doc/api/wikis.md
@@ -203,7 +203,7 @@ Example response:
{
"file_name" : "dk.png",
"file_path" : "uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png",
- "branch" : "master",
+ "branch" : "main",
"link" : {
"url" : "uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png",
"markdown" : "![dk](uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png)"
diff --git a/doc/architecture/blueprints/ai_gateway/index.md b/doc/architecture/blueprints/ai_gateway/index.md
index c9947723739..08cd8b691d4 100644
--- a/doc/architecture/blueprints/ai_gateway/index.md
+++ b/doc/architecture/blueprints/ai_gateway/index.md
@@ -46,7 +46,7 @@ connect to 3rd party providers.
## Language: Python
The AI-Gateway was originally started as the "model-gateway" that
-handled requests from IDEs to provide code suggestions. It was written
+handled requests from IDEs to provide Code Suggestions. It was written
in Python.
Python is an object oriented language that is familiar enough for
@@ -96,7 +96,7 @@ GitLab instances, they differ on these items:
| + Strict protocol definition that is easier to evolve versionless | - No strict schema, so the implementation needs to take good care of supporting multiple versions |
| + A new Ruby-gRPC server for vscode: likely faster because we can limit dependencies to load ([modular monolith](https://gitlab.com/gitlab-org/gitlab/-/issues/365293)) | - Existing Grape API for vscode: meaning slow boot time and unneeded resources loaded |
| + Bi-directional streaming | - Straight forward way to stream requests and responses (could still be added) |
-| - A new Python-gRPC server: we don't have experience running gRPC-Python servers | + Existing Python fastapi server, already running for code suggestions to extend |
+| - A new Python-gRPC server: we don't have experience running gRPC-Python servers | + Existing Python fastapi server, already running for Code Suggestions to extend |
| - Hard to pass on unknown messages from vscode through GitLab to ai-gateway | + Easier support for newer vscode + newer ai-gatway, through old GitLab instance |
| - Unknown support for gRPC in other clients (vscode, jetbrains, other editors) | + Support in all external clients |
| - Possible protocol mismatch (VSCode --REST--> Rails --gRPC--> AI gateway) | + Same protocol across the stack |
@@ -116,7 +116,7 @@ with a stable API over the [provider API we expose](#exposing-ai-providers)
as a direct proxy.
Some features will have specific endpoints, while others can share
-endpoints. For example, code suggestions or chat could have their own
+endpoints. For example, Code Suggestions or chat could have their own
endpoint, while several features that summarize issues or merge
requests could use the same endpoint but make the distinction on what
information is provided in the payload.
@@ -215,9 +215,9 @@ what is in the payload.
To document and validate the content of `payload` we can specify their
format using [JSON-schema](https://json-schema.org/).
-#### Example feature: code suggestions
+#### Example feature: Code Suggestions
-For example, a rough code suggestions service could look like this:
+For example, a rough Code Suggestions service could look like this:
```plaintext
POST /internal/code-suggestions/completions
@@ -281,7 +281,7 @@ The `metadata` field contains information that could be used in a
telemetry endpoint on the AI-gateway where we could count
suggestion-acceptance rates among other things.
-The way we will receive telemetry for code suggestions is being
+The way we will receive telemetry for Code Suggestions is being
discussed in [#415745](https://gitlab.com/gitlab-org/gitlab/-/issues/415745).
We will try to come up with an architecture for all AI-related features.
@@ -336,7 +336,7 @@ purpose API endpoint before we make the feature [generally available](../../../p
for self-managed installations. This makes it easier for us to support
features long-term even if the landscape of AI providers change.
-The [Experimental REST API](../../../development/ai_features.md#experimental-rest-api)
+The [Experimental REST API](../../../development/ai_features/index.md#experimental-rest-api)
available to GitLab team members should also use this proxy in the
short term. In the longer term, we should provide developers access to
a separate proxy that allows them to use GitLab owned authentication
diff --git a/doc/architecture/blueprints/cells/cells-feature-admin-area.md b/doc/architecture/blueprints/cells/cells-feature-admin-area.md
index a9cd170b2a7..3f23e56c3af 100644
--- a/doc/architecture/blueprints/cells/cells-feature-admin-area.md
+++ b/doc/architecture/blueprints/cells/cells-feature-admin-area.md
@@ -1,81 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Admin Area'
+redirect_to: 'impacted_features/admin-area.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Admin Area
-
-In our Cells architecture proposal we plan to share all admin related tables in GitLab.
-This allows for simpler management of all Cells in one interface and reduces the risk of settings diverging in different Cells.
-This introduces challenges with Admin Area pages that allow you to manage data that will be spread across all Cells.
-
-## 1. Definition
-
-There are consequences for Admin Area pages that contain data that span "the whole instance" as the Admin Area pages may be served by any Cell or possibly just one Cell.
-There are already many parts of the Admin Area that will have data that span many Cells.
-For example lists of all Groups, Projects, Topics, Jobs, Analytics, Applications and more.
-There are also administrative monitoring capabilities in the Admin Area that will span many Cells such as the "Background Jobs" and "Background Migrations" pages.
-
-## 2. Data flow
-
-## 3. Proposal
-
-We will need to decide how to handle these exceptions with a few possible
-options:
-
-1. Move all these pages out into a dedicated per-Cell admin section. Probably
- the URL will need to be routable to a single Cell like `/cells/<cell_id>/admin`,
- then we can display these data per Cell. These pages will be distinct from
- other Admin Area pages which control settings that are shared across all Cells. We
- will also need to consider how this impacts self-managed customers and
- whether, or not, this should be visible for single-Cell instances of GitLab.
-1. Build some aggregation interfaces for this data so that it can be fetched
- from all Cells and presented in a single UI. This may be beneficial to an
- administrator that needs to see and filter all data at a glance, especially
- when they don't know which Cell the data is on. The downside, however, is
- that building this kind of aggregation is very tricky when all Cells are
- designed to be totally independent, and it does also enforce stricter
- requirements on compatibility between Cells.
-
-The following overview describes at what level each feature contained in the current Admin Area will be managed:
-
-| Feature | Cluster | Cell | Organization |
-| --- | --- | --- | --- |
-| Abuse reports | | | |
-| Analytics | | | |
-| Applications | | | |
-| Deploy keys | | | |
-| Labels | | | |
-| Messages | ✓ | | |
-| Monitoring | | ✓ | |
-| Subscription | | | |
-| System hooks | | | |
-| Overview | | | |
-| Settings - General | ✓ | | |
-| Settings - Integrations | ✓ | | |
-| Settings - Repository | ✓ | | |
-| Settings - CI/CD (1) | ✓ | ✓ | |
-| Settings - Reporting | ✓ | | |
-| Settings - Metrics | ✓ | | |
-| Settings - Service usage data | | ✓ | |
-| Settings - Network | ✓ | | |
-| Settings - Appearance | ✓ | | |
-| Settings - Preferences | ✓ | | |
-
-(1) Depending on the specific setting, some will be managed at the cluster-level, and some at the Cell-level.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/admin-area.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md b/doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md
index 37347cf836d..050b3a922b1 100644
--- a/doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md
+++ b/doc/architecture/blueprints/cells/cells-feature-agent-for-kubernetes.md
@@ -1,30 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Agent for Kubernetes'
+redirect_to: 'impacted_features/agent-for-kubernetes.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Agent for Kubernetes
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/agent-for-kubernetes.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-backups.md b/doc/architecture/blueprints/cells/cells-feature-backups.md
index 3d20d6e2caa..a0c38171ce6 100644
--- a/doc/architecture/blueprints/cells/cells-feature-backups.md
+++ b/doc/architecture/blueprints/cells/cells-feature-backups.md
@@ -1,53 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Backups'
+redirect_to: 'impacted_features/backups.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Backups
-
-Each Cell will take its own backups, and consequently have its own isolated backup/restore procedure.
-
-## 1. Definition
-
-GitLab backup takes a backup of the PostgreSQL database used by the application, and also Git repository data.
-
-## 2. Data flow
-
-Each Cell has a number of application databases to back up (for example, `main`, and `ci`).
-Additionally, there may be cluster-wide metadata tables (for example, `users` table) which is directly accessible via PostgreSQL.
-
-## 3. Proposal
-
-### 3.1. Cluster-wide metadata
-
-It is currently unknown how cluster-wide metadata tables will be accessible.
-We may choose to have cluster-wide metadata tables backed up separately, or have each Cell back up its copy of cluster-wide metadata tables.
-
-### 3.2 Consistency
-
-#### 3.2.1 Take backups independently
-
-As each Cell will communicate with each other via API, and there will be no joins to the `users` table, it should be acceptable for each Cell to take a backup independently of each other.
-
-#### 3.2.2 Enforce snapshots
-
-We can require that each Cell take a snapshot for the PostgreSQL databases at around the same time to allow for a consistent enough backup.
-
-## 4. Evaluation
-
-As the number of Cells increases, it will likely not be feasible to take a snapshot at the same time for all Cells.
-Hence taking backups independently is the better option.
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/backups.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-ci-runners.md b/doc/architecture/blueprints/cells/cells-feature-ci-runners.md
index 4e7cea5bfd5..a14f2a47237 100644
--- a/doc/architecture/blueprints/cells/cells-feature-ci-runners.md
+++ b/doc/architecture/blueprints/cells/cells-feature-ci-runners.md
@@ -1,144 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: CI Runners'
+redirect_to: 'impacted_features/ci-runners.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: CI Runners
-
-GitLab executes CI jobs via [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/), very often managed by customers in their infrastructure.
-All CI jobs created as part of the CI pipeline are run in the context of a Project.
-This poses a challenge how to manage GitLab Runners.
-
-## 1. Definition
-
-There are 3 different types of runners:
-
-- Instance-wide: Runners that are registered globally with specific tags (selection criteria)
-- Group runners: Runners that execute jobs from a given top-level Group or Projects in that Group
-- Project runners: Runners that execute jobs from one Projects or many Projects: some runners might
- have Projects assigned from Projects in different top-level Groups.
-
-This, alongside with the existing data structure where `ci_runners` is a table describing all types of runners, poses a challenge as to how the `ci_runners` should be managed in a Cells environment.
-
-## 2. Data flow
-
-GitLab runners use a set of globally scoped endpoints to:
-
-- Register a new runner via registration token `https://gitlab.com/api/v4/runners`
- ([subject for removal](../runner_tokens/index.md)) (`registration token`)
-- Create a new runner in the context of a user `https://gitlab.com/api/v4/user/runners` (`runner token`)
-- Request jobs via an authenticated `https://gitlab.com/api/v4/jobs/request` endpoint (`runner token`)
-- Upload job status via `https://gitlab.com/api/v4/jobs/:job_id` (`build token`)
-- Upload trace via `https://gitlab.com/api/v4/jobs/:job_id/trace` (`build token`)
-- Download and upload artifacts via `https://gitlab.com/api/v4/jobs/:job_id/artifacts` (`build token`)
-
-Currently three types of authentication tokens are used:
-
-- Runner registration token ([subject for removal](../runner_tokens/index.md))
-- Runner token representing a registered runner in a system with specific configuration (`tags`, `locked`, etc.)
-- Build token representing an ephemeral token giving limited access to updating a specific job, uploading artifacts, downloading dependent artifacts, downloading and uploading container registry images
-
-Each of those endpoints receive an authentication token via header (`JOB-TOKEN` for `/trace`) or body parameter (`token` all other endpoints).
-
-Since the CI pipeline would be created in the context of a specific Cell, it would be required that pick of a build would have to be processed by that particular Cell.
-This requires that build picking depending on a solution would have to be either:
-
-- Routed to the correct Cell for the first time
-- Be two-phased: Request build from global pool, claim build on a specific Cell using a Cell specific URL
-
-## 3. Proposal
-
-### 3.1. Authentication tokens
-
-Even though the paths for CI runners are not routable, they can be made routable with these two possible solutions:
-
-- The `https://gitlab.com/api/v4/jobs/request` uses a long polling mechanism with
- a ticketing mechanism (based on `X-GitLab-Last-Update` header). When the runner first
- starts, it sends a request to GitLab to which GitLab responds with either a build to pick
- by runner. This value is completely controlled by GitLab. This allows GitLab
- to use JWT or any other means to encode a `cell` identifier that could be easily
- decodable by Router.
-- The majority of communication (in terms of volume) is using `build token`, making it
- the easiest target to change since GitLab is the sole owner of the token that the runner later
- uses for a specific job. There were prior discussions about not storing the `build token`
- but rather using a `JWT` token with defined scopes. Such a token could encode the `cell`
- to which the Router could route all requests.
-
-### 3.2. Request body
-
-- The most used endpoints pass the authentication token in the request body. It might be desired
- to use HTTP headers as an easier way to access this information by Router without
- a need to proxy requests.
-
-### 3.3. Instance-wide are Cell-local
-
-We can pick a design where all runners are always registered and local to a given Cell:
-
-- Each Cell has its own set of instance-wide runners that are updated at its own pace
-- The Project runners can only be linked to Projects from the same Organization, creating strong isolation.
-- In this model the `ci_runners` table is local to the Cell.
-- In this model we would require the above endpoints to be scoped to a Cell in some way, or be made routable. It might be via prefixing them, adding additional Cell parameters, or providing much more robust ways to decode runner tokens and match it to a Cell.
-- If a routable token is used, we could move away from cryptographic random stored in database to rather prefer to use JWT tokens.
-- The Admin Area showing registered runners would have to be scoped to a Cell.
-
-This model might be desired because it provides strong isolation guarantees.
-This model does significantly increase maintenance overhead because each Cell is managed separately.
-This model may require adjustments to the runner tags feature so that Projects have a consistent runner experience across Cells.
-
-### 3.4. Instance-wide are cluster-wide
-
-Contrary to the proposal where all runners are Cell-local, we can consider that runners
-are global, or just instance-wide runners are global.
-
-However, this requires significant overhaul of the system and we would have to change the following aspects:
-
-- The `ci_runners` table would likely have to be decomposed into `ci_instance_runners`, ...
-- All interfaces would have to be adopted to use the correct table.
-- Build queuing would have to be reworked to be two-phased where each Cell would know of all pending and running builds, but the actual claim of a build would happen against a Cell containing data.
-- It is likely that `ci_pending_builds` and `ci_running_builds` would have to be made `cluster-wide` tables, increasing the likelihood of creating hotspots in a system related to CI queueing.
-
-This model is complex to implement from an engineering perspective.
-Some data are shared between Cells.
-It creates hotspots/scalability issues in a system that might impact the experience of Organizations on other Cells, for instance during abuse.
-
-### 3.5. GitLab CI Daemon
-
-Another potential solution to explore is to have a dedicated service responsible for builds queueing, owning its database and working in a model of either sharded or Cell-ed service.
-There were prior discussions about [CI/CD Daemon](https://gitlab.com/gitlab-org/gitlab/-/issues/19435).
-
-If the service is sharded:
-
-- Depending on the model, if runners are cluster-wide or Cell-local, this service would have to fetch data from all Cells.
-- If the sharded service is used we could adapt a model of sharing a database containing `ci_pending_builds/ci_running_builds` with the service.
-- If the sharded service is used we could consider a push model where each Cell pushes to CI/CD Daemon builds that should be picked by runner.
-- The sharded service would be aware which Cell is responsible for processing the given build and could route processing requests to the designated Cell.
-
-If the service is Cell-ed:
-
-- All expectations of routable endpoints are still valid.
-
-In general usage of CI Daemon does not help significantly with the stated problem.
-However, this offers a few upsides related to more efficient processing and decoupling model: push model and it opens a way to offer stateful communication with GitLab runners (ex. gRPC or Websockets).
-
-## 4. Evaluation
-
-Considering all options it appears that the most promising solution is to:
-
-- Use [Instance-wide are Cell-local](#33-instance-wide-are-cell-local)
-- Refine endpoints to have routable identities (either via specific paths, or better tokens)
-
-Another potential upside is to get rid of `ci_builds.token` and rather use a `JWT token` that can much better and easier encode a wider set of scopes allowed by CI runner.
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/ci-runners.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-container-registry.md b/doc/architecture/blueprints/cells/cells-feature-container-registry.md
index 25af65a8700..d9ff6da7f62 100644
--- a/doc/architecture/blueprints/cells/cells-feature-container-registry.md
+++ b/doc/architecture/blueprints/cells/cells-feature-container-registry.md
@@ -1,114 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Container Registry'
+redirect_to: 'impacted_features/container-registry.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Container Registry
-
-GitLab [Container Registry](../../../user/packages/container_registry/index.md) is a feature allowing to store Docker container images in GitLab.
-
-## 1. Definition
-
-GitLab Container Registry is a complex service requiring usage of PostgreSQL, Redis and Object Storage dependencies.
-Right now there's undergoing work to introduce [Container Registry Metadata](../container_registry_metadata_database/index.md) to optimize data storage and image retention policies of Container Registry.
-
-GitLab Container Registry is serving as a container for stored data, but on its own does not authenticate `docker login`.
-The `docker login` is executed with user credentials (can be `personal access token`) or CI build credentials (ephemeral `ci_builds.token`).
-
-Container Registry uses data deduplication.
-It means that the same blob (image layer) that is shared between many Projects is stored only once.
-Each layer is hashed by `sha256`.
-
-The `docker login` does request a JWT time-limited authentication token that is signed by GitLab, but validated by Container Registry service.
-The JWT token does store all authorized scopes (`container repository images`) and operation types (`push` or `pull`).
-A single JWT authentication token can have many authorized scopes.
-This allows Container Registry and client to mount existing blobs from other scopes.
-GitLab responds only with authorized scopes.
-Then it is up to GitLab Container Registry to validate if the given operation can be performed.
-
-The GitLab.com pages are always scoped to a Project.
-Each Project can have many container registry images attached.
-
-Currently, on GitLab.com the actual registry service is served via `https://registry.gitlab.com`.
-
-The main identifiable problems are:
-
-- The authentication request (`https://gitlab.com/jwt/auth`) that is processed by GitLab.com.
-- The `https://registry.gitlab.com` that is run by an external service and uses its own data store.
-- Data deduplication. The Cells architecture with registry run in a Cell would reduce efficiency of data storage.
-
-## 2. Data flow
-
-### 2.1. Authorization request that is send by `docker login`
-
-```shell
-curl \
- --user "username:password" \
- "https://gitlab/jwt/auth?client_id=docker&offline_token=true&service=container_registry&scope=repository:gitlab-org/gitlab-build-images:push,pull"
-```
-
-Result is encoded and signed JWT token. Second base64 encoded string (split by `.`) contains JSON with authorized scopes.
-
-```json
-{"auth_type":"none","access":[{"type":"repository","name":"gitlab-org/gitlab-build-images","actions":["pull"]}],"jti":"61ca2459-091c-4496-a3cf-01bac51d4dc8","aud":"container_registry","iss":"omnibus-gitlab-issuer","iat":1669309469,"nbf":166}
-```
-
-### 2.2. Docker client fetching tags
-
-```shell
-curl \
- -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
- -H "Authorization: Bearer token" \
- https://registry.gitlab.com/v2/gitlab-org/gitlab-build-images/tags/list
-
-curl \
- -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
- -H "Authorization: Bearer token" \
- https://registry.gitlab.com/v2/gitlab-org/gitlab-build-images/manifests/danger-ruby-2.6.6
-```
-
-### 2.3. Docker client fetching blobs and manifests
-
-```shell
-curl \
- -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
- -H "Authorization: Bearer token" \
- https://registry.gitlab.com/v2/gitlab-org/gitlab-build-images/blobs/sha256:a3f2e1afa377d20897e08a85cae089393daa0ec019feab3851d592248674b416
-```
-
-## 3. Proposal
-
-### 3.1. Shard Container Registry separately to Cells architecture
-
-Due to its extensive and in general highly scalable horizontal architecture it should be evaluated if the GitLab Container Registry should be run not in Cell, but in a Cluster and be scaled independently.
-This might be easier, but would definitely not offer the same amount of data isolation.
-
-### 3.2. Run Container Registry within a Cell
-
-It appears that except `/jwt/auth` which would likely have to be processed by Router (to decode `scope`) the Container Registry could be run as a local service of a Cell.
-The actual data at least in case of GitLab.com is not forwarded via registry, but rather served directly from Object Storage / CDN.
-
-Its design encodes container repository image in a URL that is easily routable.
-It appears that we could re-use the same stateless Router service in front of Container Registry to serve manifests and blobs redirect.
-
-The only downside is increased complexity of managing standalone registry for each Cell, but this might be desired approach.
-
-## 4. Evaluation
-
-There do not seem to be any theoretical problems with running GitLab Container Registry in a Cell.
-It seems that the service can be easily made routable to work well.
-The practical complexities are around managing a complex service from an infrastructure side.
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/container-registry.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-contributions-forks.md b/doc/architecture/blueprints/cells/cells-feature-contributions-forks.md
index 8e144386908..a87e4ba3391 100644
--- a/doc/architecture/blueprints/cells/cells-feature-contributions-forks.md
+++ b/doc/architecture/blueprints/cells/cells-feature-contributions-forks.md
@@ -1,106 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Contributions: Forks'
+redirect_to: 'impacted_features/contributions-forks.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Contributions: Forks
-
-The [Forking workflow](../../../user/project/repository/forking_workflow.md) allows users to copy existing Project sources into their own namespace of choice (Personal or Group).
-
-## 1. Definition
-
-The [Forking workflow](../../../user/project/repository/forking_workflow.md) is a common workflow with various usage patterns:
-
-- It allows users to contribute back to upstream Project.
-- It persists repositories into their Personal Namespace.
-- Users can copy to make changes and release as modified Project.
-
-Forks allow users not having write access to a parent Project to make changes.
-The forking workflow is especially important for the open source community to contribute back to public Projects.
-However, it is equally important in some companies that prefer a strong split of responsibilities and tighter access control.
-The access to a Project is restricted to a designated list of developers.
-
-Forks enable:
-
-- Tighter control of who can modify the upstream Project.
-- Split of responsibilities: Parent Project might use CI configuration connecting to production systems.
-- To run CI pipelines in the context of a fork in a much more restrictive environment.
-- To consider all forks to be unvetted which reduces risks of leaking secrets, or any other information tied to the Project.
-
-The forking model is problematic in a Cells architecture for the following reasons:
-
-- Forks are clones of existing repositories. Forks could be created across different Organizations, Cells and Gitaly shards.
-- Users can create merge requests and contribute back to an upstream Project. This upstream Project might in a different Organization and Cell.
-- The merge request CI pipeline is executed in the context of the source Project, but presented in the context of the target Project.
-
-## 2. Data flow
-
-## 3. Proposals
-
-### 3.1. Intra-Cluster forks
-
-This proposal implements forks as intra-Cluster forks where communication is done via API between all trusted Cells of a cluster:
-
-- Forks are created always in the context of a user's choice of Group.
-- Forks are isolated from the Organization.
-- Organization or Group owner could disable forking across Organizations, or forking in general.
-- A merge request is created in the context of the target Project, referencing the external Project on another Cell.
-- To target Project the merge reference is transferred that is used for presenting information in context of the target Project.
-- CI pipeline is fetched in the context of the source Project as it is today, the result is fetched into the merge request of the target Project.
-- The Cell holding the target Project internally uses GraphQL to fetch the status of the source Project and includes in context of the information for merge request.
-
-Upsides:
-
-- All existing forks continue to work as they are, as they are treated as intra-Cluster forks.
-
-Downsides:
-
-- The purpose of Organizations is to provide strong isolation between Organizations. Allowing to fork across does break security boundaries.
-- However, this is no different to the ability of users today to clone a repository to a local computer and push it to any repository of choice.
-- Access control of source Project can be lower than those of target Project. Today, the system requires that in order to contribute back, the access level needs to be the same for fork and upstream.
-
-### 3.2. Forks are created in a Personal Namespace of the current Organization
-
-Instead of creating Projects across Organizations, forks are created in a user's Personal Namespace tied to the Organization. Example:
-
-- Each user that is part of an Organization receives their Personal Namespace. For example for `GitLab Inc.` it could be `gitlab.com/organization/gitlab-inc/@ayufan`.
-- The user has to fork into their own Personal Namespace of the Organization.
-- The user has as many Personal Namespaces as Organizations they belongs to.
-- The Personal Namespace behaves similar to the currently offered Personal Namespace.
-- The user can manage and create Projects within a Personal Namespace.
-- The Organization can prevent or disable usage of Personal Namespaces, disallowing forks.
-- All current forks are migrated into the Personal Namespace of user in an Organization.
-- All forks are part of the Organization.
-- Forks are not federated features.
-- The Personal Namespace and forked Project do not share configuration with the parent Project.
-
-### 3.3. Forks are created as internal Projects under current Projects
-
-Instead of creating Projects across Organizations, forks are attachments to existing Projects.
-Each user forking a Project receives their unique Project. Example:
-
-- For Project: `gitlab.com/gitlab-org/gitlab`, forks would be created in `gitlab.com/gitlab-org/gitlab/@kamil-gitlab`.
-- Forks are created in the context of the current Organization, they do not cross Organization boundaries and are managed by the Organization.
-- Tied to the user (or any other user-provided name of the fork).
-- Forks are not federated features.
-
-Downsides:
-
-- Does not answer how to handle and migrate all existing forks.
-- Might share current Group/Project settings, which could be breaking some security boundaries.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/contributions-forks.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-data-migration.md b/doc/architecture/blueprints/cells/cells-feature-data-migration.md
index 9ff661ddf68..5638bb29dc5 100644
--- a/doc/architecture/blueprints/cells/cells-feature-data-migration.md
+++ b/doc/architecture/blueprints/cells/cells-feature-data-migration.md
@@ -1,99 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Data migration'
+redirect_to: 'impacted_features/data-migration.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Data migration
-
-It is essential for a Cells architecture to provide a way to migrate data out of big Cells into smaller ones.
-This document describes various approaches to provide this type of split.
-
-We also need to handle cases where data is already violating the expected isolation constraints of Cells, for example references cannot span multiple Organizations.
-We know that existing features like linked issues allowed users to link issues across any Projects regardless of their hierarchy.
-There are many similar features.
-All of this data will need to be migrated in some way before it can be split across different Cells.
-This may mean some data needs to be deleted, or the feature needs to be changed and modelled slightly differently before we can properly split or migrate Organizations between Cells.
-
-Having schema deviations across different Cells, which is a necessary consequence of different databases, will also impact our ability to migrate data between Cells.
-Different schemas impact our ability to reliably replicate data across Cells and especially impact our ability to validate that the data is correctly replicated.
-It might force us to only be able to move data between Cells when the schemas are all in sync (slowing down deployments and the rebalancing process) or possibly only migrate from newer to older schemas which would be complex.
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-### 3.1. Split large Cells
-
-A single Cell can only be divided into many Cells.
-This is based on the principle that it is easier to create an exact clone of an existing Cell in many replicas out of which some will be made authoritative once migrated.
-Keeping those replicas up-to-date with Cell 0 is also much easier due to pre-existing replication solutions that can replicate the whole systems: Geo, PostgreSQL physical replication, etc.
-
-1. All data of an Organization needs to not be divided across many Cells.
-1. Split should be doable online.
-1. New Cells cannot contain pre-existing data.
-1. N Cells contain exact replica of Cell 0.
-1. The data of Cell 0 is live replicated to as many Cells it needs to be split.
-1. Once consensus is achieved between Cell 0 and N-Cells, the Organizations to be migrated away are marked as read-only cluster-wide.
-1. The `routes` is updated on for all Organizations to be split to indicate an authoritative Cell holding the most recent data, like `gitlab-org` on `cell-100`.
-1. The data for `gitlab-org` on Cell 0, and on other non-authoritative N-Cells are dormant and will be removed in the future.
-1. All accesses to `gitlab-org` on a given Cell are validated about `cell_id` of `routes` to ensure that given Cell is authoritative to handle the data.
-
-#### More challenges of this proposal
-
-1. There is no streaming replication capability for Elasticsearch, but you could
- snapshot the whole Elasticsearch index and recreate, but this takes hours.
- It could be handled by pausing Elasticsearch indexing on the initial Cell during
- the migration as indexing downtime is not a big issue, but this still needs
- to be coordinated with the migration process.
-1. Syncing Redis, Gitaly, CI Postgres, Main Postgres, registry Postgres, other
- new data stores snapshots in an online system would likely lead to gaps
- without a long downtime. You need to choose a sync point and at the sync
- point you need to stop writes to perform the migration. The more data stores
- there are to migrate at the same time the longer the write downtime for the
- failover. We would also need to find a reliable place in the application to
- actually block updates to all these systems with a high degree of
- confidence. In the past we've only been confident by shutting down all Rails
- services because any Rails process could write directly to any of these at
- any time due to async workloads or other surprising code paths.
-1. How to efficiently delete all the orphaned data. Locating all `ci_builds`
- associated with half the Organizations would be very expensive if we have to
- do joins. We haven't yet determined if we'd want to store an `organization_id`
- column on every table, but this is the kind of thing it would be helpful for.
-
-### 3.2. Migrate Organization from an existing Cell
-
-This is different to split, as we intend to perform logical and selective replication of data belonging to a single Organization.
-Today this type of selective replication is only implemented by Gitaly where we can migrate Git repository from a single Gitaly node to another with minimal downtime.
-
-In this model we would require identifying all resources belonging to a given Organization: database rows, object storage files, Git repositories, etc. and selectively copy them over to another (likely) existing Cell importing data into it.
-Ideally ensuring that we can perform logical replication live of all changed data, but change similarly to split which Cell is authoritative for this Organization.
-
-1. It is hard to identify all resources belonging to an Organization.
-1. It requires either downtime for the Organization or a robust system to identify live changes made.
-1. It likely will require a full database structure analysis (more robust than Project import/export) to perform selective PostgreSQL logical replication.
-
-#### More challenges of this proposal
-
-1. Logical replication is still not performant enough to keep up with our
- scale. Even if we could use logical replication we still don't have an
- efficient way to filter data related to a single Organization without
- joining all the way to the `organizations` table which will slow down
- logical replication dramatically.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/data-migration.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-database-sequences.md b/doc/architecture/blueprints/cells/cells-feature-database-sequences.md
index 2aeaaed7d64..9b426ed80a4 100644
--- a/doc/architecture/blueprints/cells/cells-feature-database-sequences.md
+++ b/doc/architecture/blueprints/cells/cells-feature-database-sequences.md
@@ -1,74 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Database Sequences'
+redirect_to: 'impacted_features/database-sequences.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Database Sequences
-
-GitLab today ensures that every database row create has a unique ID, allowing to access a merge request, CI Job or Project by a known global ID.
-Cells will use many distinct and not connected databases, each of them having a separate ID for most entities.
-At a minimum, any ID referenced between a Cell and the shared schema will need to be unique across the cluster to avoid ambiguous references.
-Further to required global IDs, it might also be desirable to retain globally unique IDs for all database rows to allow migrating resources between Cells in the future.
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-These are some preliminary ideas how we can retain unique IDs across the system.
-
-### 3.1. UUID
-
-Instead of using incremental sequences, use UUID (128 bit) that is stored in the database.
-
-- This might break existing IDs and requires adding a UUID column for all existing tables.
-- This makes all indexes larger as it requires storing 128 bit instead of 32/64 bit in index.
-
-### 3.2. Use Cell index encoded in ID
-
-Because a significant number of tables already use 64 bit ID numbers we could use MSB to encode the Cell ID:
-
-- This might limit the amount of Cells that can be enabled in a system, as we might decide to only allocate 1024 possible Cell numbers.
-- This would make it possible to migrate IDs between Cells, because even if an entity from Cell 1 is migrated to Cell 100 this ID would still be unique.
-- If resources are migrated the ID itself will not be enough to decode the Cell number and we would need a lookup table.
-- This requires updating all IDs to 32 bits.
-
-### 3.3. Allocate sequence ranges from central place
-
-Each Cell might receive its own range of sequences as they are consumed from a centrally managed place.
-Once a Cell consumes all IDs assigned for a given table it would be replenished and a next range would be allocated.
-Ranges would be tracked to provide a faster lookup table if a random access pattern is required.
-
-- This might make IDs migratable between Cells, because even if an entity from Cell 1 is migrated to Cell 100 this ID would still be unique.
-- If resources are migrated the ID itself will not be enough to decode the Cell number and we would need a much more robust lookup table as we could be breaking previously assigned sequence ranges.
-- This does not require updating all IDs to 64 bits.
-- This adds some performance penalty to all `INSERT` statements in Postgres or at least from Rails as we need to check for the sequence number and potentially wait for our range to be refreshed from the ID server.
-- The available range will need to be stored and incremented in a centralized place so that concurrent transactions cannot possibly get the same value.
-
-### 3.4. Define only some tables to require unique IDs
-
-Maybe it is acceptable only for some tables to have a globally unique IDs. It could be Projects, Groups and other top-level entities.
-All other tables like `merge_requests` would only offer a Cell-local ID, but when referenced outside it would rather use an IID (an ID that is monotonic in context of a given resource, like a Project).
-
-- This makes the ID 10000 for `merge_requests` be present on all Cells, which might be sometimes confusing regarding the uniqueness of the resource.
-- This might make random access by ID (if ever needed) impossible without using a composite key, like: `project_id+merge_request_id`.
-- This would require us to implement a transformation/generation of new ID if we need to migrate records to another Cell. This can lead to very difficult migration processes when these IDs are also used as foreign keys for other records being migrated.
-- If IDs need to change when moving between Cells this means that any links to records by ID would no longer work even if those links included the `project_id`.
-- If we plan to allow these IDs to not be unique and change the unique constraint to be based on a composite key then we'd need to update all foreign key references to be based on the composite key.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/database-sequences.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-explore.md b/doc/architecture/blueprints/cells/cells-feature-explore.md
index 4eab99d63e7..95924e3d1e8 100644
--- a/doc/architecture/blueprints/cells/cells-feature-explore.md
+++ b/doc/architecture/blueprints/cells/cells-feature-explore.md
@@ -1,71 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Explore'
+redirect_to: 'impacted_features/explore.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Explore
-
-Explore may not play a critical role in GitLab as it functions today, but GitLab today is not isolated. It is the isolation that makes Explore or some viable replacement necessary.
-
-The existing Group and Project Explore will initially be scoped to an Organization. However, there is a need for a global Explore that spans across Organizations to support the discoverability of public Groups and Projects, in particular in the context of discovering open source Projects. See user feedback [here](https://gitlab.com/gitlab-org/gitlab/-/issues/21582#note_1458298192) and [here](https://gitlab.com/gitlab-org/gitlab/-/issues/418228#note_1470045468).
-
-## 1. Definition
-
-The Explore functionality helps users in discovering Groups and Projects. Unauthenticated Users are only able to explore public Groups and Projects, authenticated Users can see all the Groups and Projects that they have access to, including private and internal Groups and Projects.
-
-## 2. Data flow
-
-## 3. Proposal
-
-The Explore feature problem falls under the broader umbrella of solving inter-Cell communication. [This topic warrants deeper research](index.md#can-different-cells-communicate-with-each-other).
-
-Below are possible directions for further investigation.
-
-### 3.1. Read only table mirror
-
-- Create a `shared_projects` table in the shared cluster-wide database.
-- The model for this table is read-only. No inserts/updates/deletes are allowed.
-- The table is filled with data (or a subset of data) from the Projects Cell-local table.
- - The write model Project (which is Cell-local) writes to the local database. We will primarily use this model for anything Cell-local.
- - This data is synchronized with `shared_projects` via a background job any time something changes.
- - The data in `shared_projects` is stored normalized, so that all the information necessary to display the Project Explore is there.
-- The Project Explore (as of today) is part of an instance-wide functionality, since it's not namespaced to any organizations/groups.
- - This section will read data using the read model for `shared_projects`.
-- Once the user clicks on a Project, they are redirected to the Cell containing the Organization.
-
-Downsides:
-
-- Need to have an explicit pattern to access instance-wide data. This however may be useful for admin functionalities too.
-- The Project Explore may not be as rich in features as it is today (various filtering options, role you have on that Project, etc.).
-- Extra complexity in managing CQRS.
-
-### 3.2 Explore scoped to an Organization
-
-The Project Explore and Group Explore are scoped to an Organization.
-
-Downsides:
-
-- No global discoverability of Groups and Projects.
-
-## 4. Evaluation
-
-The existing Group and Project Explore will initially be scoped to an Organization. Considering the [current usage of the Explore feature](https://gitlab.com/gitlab-data/product-analytics/-/issues/1302#note_1491215521), we deem this acceptable. Since all existing Users, Groups and Projects will initially be part of the default Organization, Groups and Projects will remain explorable and accessible as they are today. Only once existing Groups and Projects are moved out of the default Organization into different Organizations will this become a noticeable problem. Solutions to mitigate this are discussed in [issue #418228](https://gitlab.com/gitlab-org/gitlab/-/issues/418228). Ultimately, Explore could be replaced with a better search experience altogether.
-
-## 4.1. Pros
-
-- Initially the lack of discoverability will not be a problem.
-- Only around [1.5% of all exisiting Users are using the Explore functionality on a monthly basis](https://gitlab.com/gitlab-data/product-analytics/-/issues/1302#note_1491215521).
-
-## 4.2. Cons
-
-- The GitLab owned top-level Groups would be some of the first to be moved into their own Organization and thus be detached from the explorability of the default Organization.
+This document was moved to [another location](impacted_features/explore.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-git-access.md b/doc/architecture/blueprints/cells/cells-feature-git-access.md
index 611b4db5f43..18fc2b61b1f 100644
--- a/doc/architecture/blueprints/cells/cells-feature-git-access.md
+++ b/doc/architecture/blueprints/cells/cells-feature-git-access.md
@@ -1,156 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Git Access'
+redirect_to: 'impacted_features/git-access.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Git Access
-
-This document describes impact of Cells architecture on all Git access (over HTTPS and SSH) patterns providing explanation of how potentially those features should be changed to work well with Cells.
-
-## 1. Definition
-
-Git access is done throughout the application.
-It can be an operation performed by the system (read Git repository) or by a user (create a new file via Web IDE, `git clone` or `git push` via command line).
-The Cells architecture defines that all Git repositories will be local to the Cell, so no repository could be shared with another Cell.
-
-The Cells architecture will require that any Git operation can only be handled by a Cell holding the data.
-It means that any operation either via Web interface, API, or GraphQL needs to be routed to the correct Cell.
-It means that any `git clone` or `git push` operation can only be performed in the context of a Cell.
-
-## 2. Data flow
-
-The are various operations performed today by GitLab on a Git repository.
-This describes the data flow how they behave today to better represent the impact.
-
-It appears that Git access does require changes only to a few endpoints that are scoped to a Project.
-There appear to be different types of repositories:
-
-- Project: assigned to Group
-- Wiki: additional repository assigned to Project
-- Design: similar to Wiki, additional repository assigned to Project
-- Snippet: creates a virtual Project to hold repository, likely tied to the User
-
-### 2.1. Git clone over HTTPS
-
-Execution of: `git clone` over HTTPS
-
-```mermaid
-sequenceDiagram
- User ->> Workhorse: GET /gitlab-org/gitlab.git/info/refs?service=git-upload-pack
- Workhorse ->> Rails: GET /gitlab-org/gitlab.git/info/refs?service=git-upload-pack
- Rails ->> Workhorse: 200 OK
- Workhorse ->> Gitaly: RPC InfoRefsUploadPack
- Gitaly ->> User: Response
- User ->> Workhorse: POST /gitlab-org/gitlab.git/git-upload-pack
- Workhorse ->> Gitaly: RPC PostUploadPackWithSidechannel
- Gitaly ->> User: Response
-```
-
-### 2.2. Git clone over SSH
-
-Execution of: `git clone` over SSH
-
-```mermaid
-sequenceDiagram
- User ->> Git SSHD: ssh git@gitlab.com
- Git SSHD ->> Rails: GET /api/v4/internal/authorized_keys
- Rails ->> Git SSHD: 200 OK (list of accepted SSH keys)
- Git SSHD ->> User: Accept SSH
- User ->> Git SSHD: git clone over SSH
- Git SSHD ->> Rails: POST /api/v4/internal/allowed?project=/gitlab-org/gitlab.git&service=git-upload-pack
- Rails ->> Git SSHD: 200 OK
- Git SSHD ->> Gitaly: RPC SSHUploadPackWithSidechannel
- Gitaly ->> User: Response
-```
-
-### 2.3. Git push over HTTPS
-
-Execution of: `git push` over HTTPS
-
-```mermaid
-sequenceDiagram
- User ->> Workhorse: GET /gitlab-org/gitlab.git/info/refs?service=git-receive-pack
- Workhorse ->> Rails: GET /gitlab-org/gitlab.git/info/refs?service=git-receive-pack
- Rails ->> Workhorse: 200 OK
- Workhorse ->> Gitaly: RPC PostReceivePack
- Gitaly ->> Rails: POST /api/v4/internal/allowed?gl_repository=project-111&service=git-receive-pack
- Gitaly ->> Rails: POST /api/v4/internal/pre_receive?gl_repository=project-111
- Gitaly ->> Rails: POST /api/v4/internal/post_receive?gl_repository=project-111
- Gitaly ->> User: Response
-```
-
-### 2.4. Git push over SSHD
-
-Execution of: `git clone` over SSH
-
-```mermaid
-sequenceDiagram
- User ->> Git SSHD: ssh git@gitlab.com
- Git SSHD ->> Rails: GET /api/v4/internal/authorized_keys
- Rails ->> Git SSHD: 200 OK (list of accepted SSH keys)
- Git SSHD ->> User: Accept SSH
- User ->> Git SSHD: git clone over SSH
- Git SSHD ->> Rails: POST /api/v4/internal/allowed?project=/gitlab-org/gitlab.git&service=git-receive-pack
- Rails ->> Git SSHD: 200 OK
- Git SSHD ->> Gitaly: RPC ReceivePack
- Gitaly ->> Rails: POST /api/v4/internal/allowed?gl_repository=project-111
- Gitaly ->> Rails: POST /api/v4/internal/pre_receive?gl_repository=project-111
- Gitaly ->> Rails: POST /api/v4/internal/post_receive?gl_repository=project-111
- Gitaly ->> User: Response
-```
-
-### 2.5. Create commit via Web
-
-Execution of `Add CHANGELOG` to repository:
-
-```mermaid
-sequenceDiagram
- Web ->> Puma: POST /gitlab-org/gitlab/-/create/main
- Puma ->> Gitaly: RPC TreeEntry
- Gitaly ->> Rails: POST /api/v4/internal/allowed?gl_repository=project-111
- Gitaly ->> Rails: POST /api/v4/internal/pre_receive?gl_repository=project-111
- Gitaly ->> Rails: POST /api/v4/internal/post_receive?gl_repository=project-111
- Gitaly ->> Puma: Response
- Puma ->> Web: See CHANGELOG
-```
-
-## 3. Proposal
-
-The Cells stateless router proposal requires that any ambiguous path (that is not routable) will be made routable.
-It means that at least the following paths will have to be updated to introduce a routable entity (Project, Group, or Organization).
-
-Change:
-
-- `/api/v4/internal/allowed` => `/api/v4/internal/projects/<gl_repository>/allowed`
-- `/api/v4/internal/pre_receive` => `/api/v4/internal/projects/<gl_repository>/pre_receive`
-- `/api/v4/internal/post_receive` => `/api/v4/internal/projects/<gl_repository>/post_receive`
-- `/api/v4/internal/lfs_authenticate` => `/api/v4/internal/projects/<gl_repository>/lfs_authenticate`
-
-Where:
-
-- `gl_repository` can be `project-1111` (`Gitlab::GlRepository`)
-- `gl_repository` in some cases might be a full path to repository as executed by GitLab Shell (`/gitlab-org/gitlab.git`)
-
-## 4. Evaluation
-
-Supporting Git repositories if a Cell can access only its own repositories does not appear to be complex.
-The one major complication is supporting snippets, but this likely falls in the same category as for the approach to support a user's Personal Namespace.
-
-## 4.1. Pros
-
-1. The API used for supporting HTTPS/SSH and Hooks are well defined and can easily be made routable.
-
-## 4.2. Cons
-
-1. The sharing of repositories objects is limited to the given Cell and Gitaly node.
-1. Cross-Cells forks are likely impossible to be supported (discover: How this works today across different Gitaly node).
+This document was moved to [another location](impacted_features/git-access.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md b/doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md
index 7e4ab785095..964423334c1 100644
--- a/doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md
+++ b/doc/architecture/blueprints/cells/cells-feature-gitlab-pages.md
@@ -1,30 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: GitLab Pages'
+redirect_to: 'impacted_features/gitlab-pages.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: GitLab Pages
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/gitlab-pages.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-global-search.md b/doc/architecture/blueprints/cells/cells-feature-global-search.md
index 475db381ff5..0a2a89b2d45 100644
--- a/doc/architecture/blueprints/cells/cells-feature-global-search.md
+++ b/doc/architecture/blueprints/cells/cells-feature-global-search.md
@@ -1,35 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Global search'
+redirect_to: 'impacted_features/global-search.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Global search
-
-When we introduce multiple Cells we intend to isolate all services related to those Cells.
-This will include Elasticsearch which means our current global search functionality will not work.
-It may be possible to implement aggregated search across all Cells, but it is unlikely to be performant to do fan-out searches across all Cells especially once you start to do pagination which requires setting the correct offset and page number for each search.
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-Likely the first versions of Cells will not support global searches.
-Later, we may consider if building global searches to support popular use cases is worthwhile.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/global-search.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-graphql.md b/doc/architecture/blueprints/cells/cells-feature-graphql.md
index e8850dfbee3..69ce2128484 100644
--- a/doc/architecture/blueprints/cells/cells-feature-graphql.md
+++ b/doc/architecture/blueprints/cells/cells-feature-graphql.md
@@ -1,81 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: GraphQL'
+redirect_to: 'impacted_features/graphql.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: GraphQL
-
-GitLab extensively uses GraphQL to perform efficient data query operations.
-GraphQL due to it's nature is not directly routable.
-The way GitLab uses it calls the `/api/graphql` endpoint, and only the query or mutation of the body request might define where the data can be accessed.
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-There are at least two main ways to implement GraphQL in a Cells architecture.
-
-### 3.1. GraphQL routable by endpoint
-
-Change `/api/graphql` to `/api/organization/<organization>/graphql`.
-
-- This breaks all existing usages of `/api/graphql` endpoint because the API URI is changed.
-
-### 3.2. GraphQL routable by body
-
-As part of router parse GraphQL body to find a routable entity, like `project`.
-
-- This still makes the GraphQL query be executed only in context of a given Cell and not allowing the data to be merged.
-
-```json
-# Good example
-{
- project(fullPath:"gitlab-org/gitlab") {
- id
- description
- }
-}
-
-# Bad example, since Merge Request is not routable
-{
- mergeRequest(id: 1111) {
- iid
- description
- }
-}
-```
-
-### 3.3. Merging GraphQL Proxy
-
-Implement as part of router GraphQL Proxy which can parse body and merge results from many Cells.
-
-- This might make pagination hard to achieve, or we might assume that we execute many queries of which results are merged across all Cells.
-
-```json
-{
- project(fullPath:"gitlab-org/gitlab"){
- id, description
- }
- group(fullPath:"gitlab-com") {
- id, description
- }
-}
-```
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/graphql.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-organizations.md b/doc/architecture/blueprints/cells/cells-feature-organizations.md
index f1527b40ef4..6b589307404 100644
--- a/doc/architecture/blueprints/cells/cells-feature-organizations.md
+++ b/doc/architecture/blueprints/cells/cells-feature-organizations.md
@@ -1,36 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Organizations'
+redirect_to: 'impacted_features/organizations.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Organizations
-
-One of the major designs of a Cells architecture is strong isolation between Groups.
-Organizations as described by the [Organization blueprint](../organization/index.md) provides a way to have plausible UX for joining together many Groups that are isolated from the rest of the system.
-
-## 1. Definition
-
-Cells do require that all Groups and Projects of a single Organization can only be stored on a single Cell because a Cell can only access data that it holds locally and has very limited capabilities to read information from other Cells.
-
-Cells with Organizations do require strong isolation between Organizations.
-
-It will have significant implications on various user-facing features, like Todos, dropdowns allowing to select Projects, references to other issues or Projects, or any other social functions present at GitLab.
-Today those functions were able to reference anything in the whole system.
-With the introduction of Organizations this will be forbidden.
-
-This problem definition aims to answer effort and implications required to add strong isolation between Organizations to the system, including features affected and their data processing flow.
-The purpose is to ensure that our solution when implemented consistently avoids data leakage between Organizations residing on a single Cell.
-
-## 2. Proposal
-
-See the [Organization blueprint](../organization/index.md).
+This document was moved to [another location](impacted_features/organizations.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-personal-access-tokens.md b/doc/architecture/blueprints/cells/cells-feature-personal-access-tokens.md
index 3aca9f1e116..115af11e3a6 100644
--- a/doc/architecture/blueprints/cells/cells-feature-personal-access-tokens.md
+++ b/doc/architecture/blueprints/cells/cells-feature-personal-access-tokens.md
@@ -1,31 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Personal Access Tokens'
+redirect_to: 'impacted_features/personal-access-tokens.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Personal Access Tokens
-
-## 1. Definition
-
-Personal Access Tokens associated with a User are a way for Users to interact with the API of GitLab to perform operations.
-Personal Access Tokens today are scoped to the User, and can access all Groups that a User has access to.
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/personal-access-tokens.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md b/doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md
index e8f5c250a8e..6d5ec0c9dd6 100644
--- a/doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md
+++ b/doc/architecture/blueprints/cells/cells-feature-personal-namespaces.md
@@ -1,30 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Personal Namespaces'
+redirect_to: 'impacted_features/personal-namespaces.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Personal Namespaces
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/personal-namespaces.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md b/doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md
index d403d6ff963..0143ac6ffd9 100644
--- a/doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md
+++ b/doc/architecture/blueprints/cells/cells-feature-router-endpoints-classification.md
@@ -1,34 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Router Endpoints Classification'
+redirect_to: 'impacted_features/router-endpoints-classification.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Router Endpoints Classification
-
-Classification of all endpoints is essential to properly route requests hitting the load balancer of a GitLab installation to a Cell that can serve it.
-Each Cell should be able to decode each request and classify which Cell it belongs to.
-
-GitLab currently implements hundreds of endpoints.
-This document tries to describe various techniques that can be implemented to allow the Rails to provide this information efficiently.
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/router-endpoints-classification.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-schema-changes.md b/doc/architecture/blueprints/cells/cells-feature-schema-changes.md
index dd0f6c0705c..bf78a4eae41 100644
--- a/doc/architecture/blueprints/cells/cells-feature-schema-changes.md
+++ b/doc/architecture/blueprints/cells/cells-feature-schema-changes.md
@@ -1,38 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Schema changes'
+redirect_to: 'impacted_features/schema-changes.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Schema changes
-
-When we introduce multiple Cells that own their own databases this will complicate the process of making schema changes to Postgres and Elasticsearch.
-Today we already need to be careful to make changes comply with our zero downtime deployments.
-For example, [when removing a column we need to make changes over 3 separate deployments](../../../development/database/avoiding_downtime_in_migrations.md#dropping-columns).
-We have tooling like `post_migrate` that helps with these kinds of changes to reduce the number of merge requests needed, but these will be complicated when we are dealing with deploying multiple Rails applications that will be at different versions at any one time.
-This problem will be particularly tricky to solve for shared databases like our plan to share the `users` related tables among all Cells.
-
-A key benefit of Cells may be that it allows us to run different customers on different versions of GitLab.
-We may choose to update our own Cell before all our customers giving us even more flexibility than our current canary architecture.
-But doing this means that schema changes need to have even more versions of backward compatibility support which could slow down development as we need extra steps to make schema changes.
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/schema-changes.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-secrets.md b/doc/architecture/blueprints/cells/cells-feature-secrets.md
index 681c229711d..1c4c79d96fc 100644
--- a/doc/architecture/blueprints/cells/cells-feature-secrets.md
+++ b/doc/architecture/blueprints/cells/cells-feature-secrets.md
@@ -1,43 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Secrets'
+redirect_to: 'impacted_features/secrets.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Secrets
-
-Where possible, each Cell should have its own distinct set of secrets.
-However, there will be some secrets that will be required to be the same for all Cells in the cluster.
-
-## 1. Definition
-
-GitLab has a lot of [secrets](https://docs.gitlab.com/charts/installation/secrets.html) that need to be configured.
-Some secrets are for inter-component communication, for example, `GitLab Shell secret`, and used only within a Cell.
-Some secrets are used for features, for example, `ci_jwt_signing_key`.
-
-## 2. Data flow
-
-## 3. Proposal
-
-1. Secrets used for features will need to be consistent across all Cells, so that the UX is consistent.
- 1. This is especially true for the `db_key_base` secret which is used for
- encrypting data at rest in the database - so that Projects that are
- transferred to another Cell will continue to work. We do not want to have
- to re-encrypt such rows when we move Projects/Groups between Cells.
-1. Secrets which are used for intra-Cell communication only should be uniquely generated
- per Cell.
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/secrets.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-snippets.md b/doc/architecture/blueprints/cells/cells-feature-snippets.md
index bde0b098609..2963bbdec2c 100644
--- a/doc/architecture/blueprints/cells/cells-feature-snippets.md
+++ b/doc/architecture/blueprints/cells/cells-feature-snippets.md
@@ -1,56 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Snippets'
+redirect_to: 'impacted_features/snippets.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Snippets
-
-Snippets will be scoped to an Organization. Initially it will not be possible to aggregate snippet collections across Organizations. See also [issue #416954](https://gitlab.com/gitlab-org/gitlab/-/issues/416954).
-
-## 1. Definition
-
-Two different types of snippets exist:
-
-- [Project snippets](../../../api/project_snippets.md). These snippets have URLs
- like `/<group>/<project>/-/snippets/123`
-- [Personal snippets](../../../user/snippets.md). These snippets have URLs like
- `/-/snippets/123`
-
-Snippets are backed by a Git repository.
-
-## 2. Data flow
-
-## 3. Proposal
-
-### 3.1. Scoped to an organization
-
-Both project and personal snippets will be scoped to an Organization.
-
-- Project snippets URLs will remain unchanged, as the URLs are routable.
-- Personal snippets URLs will need to change to be `/-/organizations/<organization>/snippets/123`,
- so that the URL is routeable
-
-Creation of snippets will also be scoped to a User's current Organization. Because of that, we recommend renaming `personal snippets` to `organization snippets` once the Organization is rolled out. A User can create many independent snippet collections across multiple Organizations.
-
-## 4. Evaluation
-
-Snippets are scoped to an Organization because Gitaly is confined to a Cell.
-
-## 4.1. Pros
-
-- No need to have clusterwide Gitaly.
-
-## 4.2. Cons
-
-- We will break [snippet discovery](/ee/user/snippets.md#discover-snippets).
-- Snippet access may become subordinate to the visibility of the Organization.
+This document was moved to [another location](impacted_features/snippets.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-template.md b/doc/architecture/blueprints/cells/cells-feature-template.md
index 3cece3dc99e..c75cc88f46c 100644
--- a/doc/architecture/blueprints/cells/cells-feature-template.md
+++ b/doc/architecture/blueprints/cells/cells-feature-template.md
@@ -1,30 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Problem A'
+redirect_to: 'impacted_features/template.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: A
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/template.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-uploads.md b/doc/architecture/blueprints/cells/cells-feature-uploads.md
index fdac3a9977c..eab7a8a4fcd 100644
--- a/doc/architecture/blueprints/cells/cells-feature-uploads.md
+++ b/doc/architecture/blueprints/cells/cells-feature-uploads.md
@@ -1,30 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Uploads'
+redirect_to: 'impacted_features/uploads.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Uploads
-
-> TL;DR
-
-## 1. Definition
-
-## 2. Data flow
-
-## 3. Proposal
-
-## 4. Evaluation
-
-## 4.1. Pros
-
-## 4.2. Cons
+This document was moved to [another location](impacted_features/uploads.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-user-profile.md b/doc/architecture/blueprints/cells/cells-feature-user-profile.md
index fc02548f371..73f312f3762 100644
--- a/doc/architecture/blueprints/cells/cells-feature-user-profile.md
+++ b/doc/architecture/blueprints/cells/cells-feature-user-profile.md
@@ -1,52 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: User Profile'
+redirect_to: 'impacted_features/user-profile.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: User Profile
-
-The existing User Profiles will initially be scoped to an Organization. Long-term, we should consider aggregating parts of the User activity across Organizations to enable Users a global view of their contributions.
-
-## 1. Definition
-
-Each GitLab account has a [User Profile](../../../user/profile/index.md), which contains information about the User and their GitLab activity.
-
-## 2. Data flow
-
-## 3. Proposal
-
-User Profiles will be scoped to an Organization.
-
-- Users can set a Home Organization as their main Organization.
-- Users who do not exist in the database at all display a 404 not found error when trying to access their User Profile.
-- User who haven't contributed to an Organization display their User Profile with an empty state.
-- When displaying a User Profile empty state, if the profile has a Home Organization set to another Organization, we display a call-to-action allowing navigation to the main Organization.
-- User Profile URLs will not reference the Organization and remain as: `/<username>`. We follow the same pattern as is used for `Your Work`, meaning that profiles are always seen in the context of an Organization.
-- Breadcrumbs on the User Profile will present as `[Organization Name] / [Username]`.
-
-See [issue #411931](https://gitlab.com/gitlab-org/gitlab/-/issues/411931) for design proposals.
-
-## 4. Evaluation
-
-We expect the [majority of Users to perform most of their activity in one single Organization](../organization/index.md#data-exploration).
-This is why we deem it acceptable to scope the User Profile to an Organization at first.
-More discovery is necessary to understand which aspects of the current User Profile are relevant to showcase contributions in a global context.
-
-## 4.1. Pros
-
-- Viewing a User Profile scoped to an Organization allows you to focus on contributions that are most relevant to your Organization, filtering out the User's other activities.
-- Existing User Profile URLs do not break.
-
-## 4.2. Cons
-
-- Users will lose the ability to display their entire activity, which may lessen the effectiveness of using their User Profile as a resume of achievements when working across multiple Organizations.
+This document was moved to [another location](impacted_features/user-profile.md).
diff --git a/doc/architecture/blueprints/cells/cells-feature-your-work.md b/doc/architecture/blueprints/cells/cells-feature-your-work.md
index 08bb0bed709..344037f2a76 100644
--- a/doc/architecture/blueprints/cells/cells-feature-your-work.md
+++ b/doc/architecture/blueprints/cells/cells-feature-your-work.md
@@ -1,58 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Your Work'
+redirect_to: 'impacted_features/your-work.md'
+remove_date: '2023-11-17'
---
-<!-- vale gitlab.FutureTense = NO -->
-
-This document is a work-in-progress and represents a very early state of the
-Cells design. Significant aspects are not documented, though we expect to add
-them in the future. This is one possible architecture for Cells, and we intend to
-contrast this with alternatives before deciding which approach to implement.
-This documentation will be kept even if we decide not to implement this so that
-we can document the reasons for not choosing this approach.
-
-# Cells: Your Work
-
-Your Work will be scoped to an Organization.
-Counts presented in the individual dashboards will relate to the selected Organization.
-
-## 1. Definition
-
-When accessing `gitlab.com/dashboard/`, users can find a [focused view of items that they have access to](../../../tutorials/left_sidebar/index.md#use-a-more-focused-view).
-This overview contains dashboards relating to:
-
-- Projects
-- Groups
-- Issues
-- Merge requests
-- To-Do list
-- Milestones
-- Snippets
-- Activity
-- Workspaces
-- Environments
-- Operations
-- Security
-
-## 2. Data flow
-
-## 3. Proposal
-
-Your Work will be scoped to an Organization, giving the user an overview of all the items they can access in the Organization they are currently viewing.
-
-- Issue, Merge request and To-Do list counts will refer to the selected Organization.
-
-## 4. Evaluation
-
-Scoping Your Work to an Organization makes sense in the context of the [proposed Organization navigation](https://gitlab.com/gitlab-org/gitlab/-/issues/417778).
-Considering that [we expect most users to work in a single Organization](../organization/index.md#data-exploration), we deem this impact acceptable.
-
-## 4.1. Pros
-
-- Viewing Your Work scoped to an Organization allows Users to focus on content that is most relevant to their currently selected Organization.
-
-## 4.2. Cons
-
-- Users working across multiple Organizations will have to navigate to each Organization to access all of their work items.
+This document was moved to [another location](impacted_features/your-work.md).
diff --git a/doc/architecture/blueprints/cells/diagrams/cells-and-fulfillment.drawio.png b/doc/architecture/blueprints/cells/diagrams/cells-and-fulfillment.drawio.png
deleted file mode 100644
index c5fff9dbca5..00000000000
--- a/doc/architecture/blueprints/cells/diagrams/cells-and-fulfillment.drawio.png
+++ /dev/null
Binary files differ
diff --git a/doc/architecture/blueprints/cells/diagrams/index.md b/doc/architecture/blueprints/cells/diagrams/index.md
index 77d12612819..14db888382e 100644
--- a/doc/architecture/blueprints/cells/diagrams/index.md
+++ b/doc/architecture/blueprints/cells/diagrams/index.md
@@ -22,7 +22,7 @@ Load the `.drawio.png` or `.drawio.svg` file directly into **draw.io**, which yo
To create a diagram from a file:
1. Copy existing file and rename it. Ensure that the extension is `.drawio.png` or `.drawio.svg`.
-1. Edit the diagram.
+1. Edit the diagram.
1. Save the file.
To create a diagram from scratch using [draw.io desktop](https://github.com/jgraph/drawio-desktop/releases):
diff --git a/doc/architecture/blueprints/cells/diagrams/term-cell.drawio.png b/doc/architecture/blueprints/cells/diagrams/term-cell.drawio.png
index 84a6d6d1745..639026c801f 100644
--- a/doc/architecture/blueprints/cells/diagrams/term-cell.drawio.png
+++ b/doc/architecture/blueprints/cells/diagrams/term-cell.drawio.png
Binary files differ
diff --git a/doc/architecture/blueprints/cells/diagrams/term-cluster.drawio.png b/doc/architecture/blueprints/cells/diagrams/term-cluster.drawio.png
index a6fd790ba5e..c5e3a0f7c71 100644
--- a/doc/architecture/blueprints/cells/diagrams/term-cluster.drawio.png
+++ b/doc/architecture/blueprints/cells/diagrams/term-cluster.drawio.png
Binary files differ
diff --git a/doc/architecture/blueprints/cells/diagrams/term-organization.drawio.png b/doc/architecture/blueprints/cells/diagrams/term-organization.drawio.png
index f1cb7cd92fe..9bfdba43309 100644
--- a/doc/architecture/blueprints/cells/diagrams/term-organization.drawio.png
+++ b/doc/architecture/blueprints/cells/diagrams/term-organization.drawio.png
Binary files differ
diff --git a/doc/architecture/blueprints/cells/diagrams/term-top-level-group.drawio.png b/doc/architecture/blueprints/cells/diagrams/term-top-level-group.drawio.png
index f5535409945..c8f6393f9fc 100644
--- a/doc/architecture/blueprints/cells/diagrams/term-top-level-group.drawio.png
+++ b/doc/architecture/blueprints/cells/diagrams/term-top-level-group.drawio.png
Binary files differ
diff --git a/doc/architecture/blueprints/cells/glossary.md b/doc/architecture/blueprints/cells/glossary.md
index 11a1fc5acc9..69824663867 100644
--- a/doc/architecture/blueprints/cells/glossary.md
+++ b/doc/architecture/blueprints/cells/glossary.md
@@ -1,106 +1,6 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Glossary'
+redirect_to: 'goals.md#glossary'
+remove_date: '2023-11-24'
---
-# Cells: Glossary
-
-We use the following terms to describe components and properties of the Cells architecture.
-
-## Cell
-
-> Pod was renamed to Cell in <https://gitlab.com/gitlab-com/www-gitlab-com/-/merge_requests/121163>
-
-A Cell is a set of infrastructure components that contains multiple top-level groups that belong to different organizations. The components include both datastores (PostgreSQL, Redis etc.) and stateless services (web etc.). The infrastructure components provided within a Cell are shared among organizations and their top-level groups but not shared with other Cells. This isolation of infrastructure components means that Cells are independent from each other.
-
-<img src="diagrams/term-cell.drawio.png" height="200">
-
-### Cell properties
-
-- Each cell is independent from the others
-- Infrastructure components are shared by organizations and their top-level groups within a Cell
-- More Cells can be provisioned to provide horizontal scalability
-- A failing Cell does not lead to failure of other Cells
-- Noisy neighbor effects are limited to within a Cell
-- Cells are not visible to organizations; it is an implementation detail
-- Cells may be located in different geographical regions (for example, EU, US, JP, UK)
-
-Discouraged synonyms: GitLab instance, cluster, shard
-
-## Cluster
-
-A cluster is a collection of Cells.
-
-<img src="diagrams/term-cluster.drawio.png" height="300">
-
-### Cluster properties
-
-- A cluster holds cluster-wide metadata, for example Users, Routes, Settings.
-
-Discouraged synonyms: whale
-
-## Organizations
-
-GitLab references [Organizations in the initial set up](../../../topics/set_up_organization.md) and users can add a (free text) organization to their profile. There is no Organization entity established in the GitLab codebase.
-
-As part of delivering Cells, we propose the introduction of an `organization` entity. Organizations would represent billable entities or customers.
-
-Organizations are a known concept, present for example in [AWS](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/core-concepts.html) and [GCP](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy#organizations).
-
-Organizations work under the following assumptions:
-
-1. Users care about what happens within their organizations.
-1. Features need to work within an organization.
-1. Only few features need to work across organizations.
-1. Users understand that the majority of pages they view are only scoped to a single organization at a time.
-1. Organizations are located on a single cell.
-
-![Term Organization](diagrams/term-organization.drawio.png)
-
-### Organization properties
-
-- Top-level groups belong to organizations
-- Organizations are isolated from each other by default meaning that cross-group features will only work for group that exist within a single organization
-- User namespaces must not belong to an organization
-
-Discouraged synonyms: Billable entities, customers
-
-## Top-Level group
-
-Top-level group is the name given to the top most group of all other groups. Groups and projects are nested underneath the top-level group.
-
-Example:
-
-`https://gitlab.com/gitlab-org/gitlab/`:
-
-- `gitlab-org` is a `top-level group`; the root for all groups and projects of an organization
-- `gitlab` is a `project`; a project of the organization.
-
-The top-level group has served as the defacto Organization entity. With the creation of Organization, top-level groups will be [nested underneath Organizations](https://gitlab.com/gitlab-org/gitlab/-/issues/394796).
-
-Over time there won't be a distinction between a top-level group and a group. All features that make Top-level groups different from groups will move to Organization.
-
-Discouraged synonyms: Root-level namespace
-
-![Term Top-level Group](diagrams/term-top-level-group.drawio.png)
-
-### Top-level group properties
-
-- Top-level groups belonging to an organization are located on the same Cell
-- Top-level groups can interact with other top-level groups that belong to the same organization
-
-## Users
-
-Users are available globally and not restricted to a single Cell. Users belong to a single organization, but can participate in many organizations through group and project membership with varying permissions. Inside organizations, users can create multiple top-level groups. User activity is not limited to a single organization but their contributions (for example TODOs) are only aggregated within an organization. This avoids the need for aggregating across cells.
-
-### User properties
-
-- Users are shared globally across all Cells
-- Users can create multiple top-level groups
-- Users can be a member of multiple top-level groups
-- Users belong to one organization. See [!395736](https://gitlab.com/gitlab-org/gitlab/-/issues/395736)
-- Users can be members of groups and projects in different organizations
-- Users can administer organizations
-- User activity is aggregated in an organization
-- Every user has one personal namespace
+This document was moved to [another location](goals.md#glossary).
diff --git a/doc/architecture/blueprints/cells/goals.md b/doc/architecture/blueprints/cells/goals.md
index 3f3923aa255..f1a255aa879 100644
--- a/doc/architecture/blueprints/cells/goals.md
+++ b/doc/architecture/blueprints/cells/goals.md
@@ -6,7 +6,9 @@ description: 'Cells: Goals'
# Cells: Goals
-## Scalability
+## Goals
+
+### Scalability
The main goal of this new shared-infrastructure architecture is to provide additional scalability for our SaaS Platform.
GitLab.com is largely monolithic and we have estimated (internally) that the current architecture has scalability limitations,
@@ -16,34 +18,41 @@ even when database partitioning and decomposition are taken into account.
Cells provide a horizontally scalable solution because additional Cells can be created based on demand. Cells can be provisioned and tuned as needed for optimal scalability.
-## Increased availability
+### Increased availability
-A major challenge for shared-infrastructure architectures is a lack of isolation between top-level groups. This can lead to noisy neighbor effects. A organization's behavior inside a top-level group can impact all other organizations. This is highly undesirable. Cells provide isolation at the cell level. A group of organizations is fully isolated from other organizations located on a different Cell. This minimizes noisy neighbor effects while still benefiting from the cost-efficiency of shared infrastructure.
+A major challenge for shared-infrastructure architectures is a lack of isolation between top-level Groups.
+This can lead to noisy neighbor effects.
+An organization's behavior inside a top-level Group can impact all other organizations.
+This is highly undesirable.
+Cells provide isolation at the Cell level.
+A group of Organizations is fully isolated from other Organizations located on a different Cell.
+This minimizes noisy neighbor effects while still benefiting from the cost-efficiency of a shared infrastructure.
-Additionally, Cells provide a way to implement disaster recovery capabilities. Entire Cells may be replicated to read-only standbys with automatic failover capabilities.
+Additionally, Cells provide a way to implement disaster recovery capabilities.
+Entire Cells may be replicated to read-only standbys with automatic failover capabilities.
-## A consistent experience
+### A consistent experience
Organizations should have the same user experience on our SaaS platform as they do on a self-managed GitLab instance.
-## Regions
-
-GitLab.com is only hosted within the United States of America. Organizations located in other regions have voiced demand for local SaaS offerings. Cells provide a path towards [GitLab Regions](https://gitlab.com/groups/gitlab-org/-/epics/6037) because Cells may be deployed within different geographies. Depending on which of the organization's data is located outside a Cell, this may solve data residency and compliance problems.
+### Regions
-## Market segment
+GitLab.com is only hosted within the United States of America.
+Organizations located in other regions have voiced demand for local SaaS offerings.
+Cells provide a path towards [GitLab Regions](https://gitlab.com/groups/gitlab-org/-/epics/6037) because Cells may be deployed within different geographies.
+Depending on which of an organization's data is located outside a Cell, this may solve data residency and compliance problems.
-Cells would provide a solution for organizations in the small to medium business (up to 100 users) and the mid-market segment (up to 2000 users).
-(See [segmentation definitions](https://about.gitlab.com/handbook/sales/field-operations/gtm-resources/#segmentation).)
-Larger organizations may benefit substantially from [GitLab Dedicated](../../../subscriptions/gitlab_dedicated/index.md).
+### Market segment
-At this moment, GitLab.com has "social-network"-like capabilities that may not fit well into a more isolated organization model. Removing those features, however, possesses some challenges:
+At this moment, GitLab.com has "social network"-like capabilities that may not fit well into a more isolated Organization model.
+Removing those features, however, poses some challenges:
-1. How will existing `gitlab-org` contributors contribute to the namespace??
-1. How do we move existing top-level groups into the new model (effectively breaking their social features)?
+1. How will existing `gitlab-org` contributors contribute to the namespace?
+1. How do we move existing top-level Groups into the new model (effectively breaking their social features)?
-We should evaluate if the SMB and mid market segment is interested in these features, or if not having them is acceptable in most cases.
+We should evaluate if the small to medium business and mid-market segment is interested in these features, or if not having them is acceptable in most cases.
-## Self-managed
+### Self-managed
For reasons of consistency, it is expected that self-managed instances will
adopt the cells architecture as well. To expand, self-managed instances can
@@ -51,13 +60,341 @@ continue with just a single Cell while supporting the option of adding additiona
Cells. Organizations, and possible User decomposition will also be adopted for
self-managed instances.
-## High-level architecture problems to solve
+## Requirements
+
+| Type | Requirement | Severity |
+| ----------- | ------------------------------------------------- | -------- |
+| Product | Aggregation of cluster-wide data | Medium |
+| Product | All Cells are under a single GitLab.com domain | High |
+| Product | User can interact with many Cells | Medium |
+| Product | Minimal impact on contributor workflows | High |
+| Product | On-premise like experience | Medium |
+| Product | Minimize breaking changes | High |
+| Product | Enables support for Regions | Low |
+| Product | Limit impact on self-managed customers | Low |
+| Operational | Provides 10x headroom | High |
+| Operational | Provides 100x headroom | Medium |
+| Operational | Improve Service Availability | High |
+| Operational | Cost per user similar or lower to GitLab.com | Medium |
+| Operational | Unified way of deploying Cells | Medium |
+| Operational | Cells running in mixed deployments | High |
+| Operational | High resilience to a single Cell failure | High |
+| Operational | Small Cells | Medium |
+| Migration | Robust rollback and disaster recovery scenarios | High |
+| Migration | Scale existing GitLab.com database | High |
+| Migration | Re-balancing of Cells | Low |
+| Migration | Customer can migrate from GitLab.com to Dedicated | Low |
+| Development | Easy usage in development environment | Medium |
+
+### Aggregation of cluster-wide data
+
+The architecture should provide a way to present the cluster of Cells in a single view.
+This might mean to:
+
+- Aggregate user To-Dos from different Organizations
+- Perform cluster-wide searches of public Projects, or published source code
+
+### All Cells are under a single GitLab.com domain
+
+General users should be unaware of the presence of Cells.
+Cells would only be visible to instance administrators.
+Users using Organizations on another Cell or us migrating Organizations
+between Cells should be an operational detail that does not require
+any user intervention or is not visible to the user.
+
+### User can interact with many Cells
+
+Usage of many accounts to interact with different Organizations
+that might be on different Cells is strongly discouraged.
+The need to use many accounts will reduce adoption and put a barrier
+on users wanting to contribute to open-source Projects.
+
+In the future, users could have Organization specific settings,
+depending on the specific customer expectations.
+For instance, users might be shown with different display names in different Organizations.
+
+Users should not be required to use different SSH keys to access different
+Organizations due to the complexity of managing many SSH keys by the user.
+
+### Minimal impact on contributor workflows
+
+GitLab.com has a number of open-source and open-core projects (including [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab)).
+Cells should not make it harder to contribute to public Projects.
+Learning new ways to contribute is likely to hinder the adoption of Cells.
+The introduced architecture should focus on changing the existing workflows in the most minimal way.
+
+### On-premise like experience
+
+Currently on-premise has numerous advantages compared to our SaaS offering.
+On-premise allows to control all aspects of a GitLab installation, including but not limited to: managing users, access controls, or instance-wide settings.
+
+The difference between SaaS and on-premise is problematic for our customers,
+and us as it results in a different user experience.
+
+### Minimize breaking changes
+
+The introduction of Cells will imply changes in the supported GitLab.com workflows.
+Cells might affect how people use GitLab, as long as it provides a compelling user experience story.
+It is desired that each change introduced provides either operational value or user value, ideally both.
+
+Any Cells architecture should focus on not introducing breaking changes,
+or if introducing them provide a long window to support the change.
+The introduction of breaking changes will reduce the adoption rate
+and effectiveness of Cells and make rollout of the architecture more risky.
+
+It is important to distinguish between different severity of breaking changes:
+
+- Required: migration to a new architecture by design introduces a breaking change.
+ In such a case a customer has to use a new workflow, new API, or new endpoints right away
+ and is required to adapt to all changes at once. The customer has limited options to roll back.
+
+- Optional: migration to a new architecture does not enforce introducing breaking changes.
+ In such a case a customer can slowly adapt to introduced changes: a new workflow, new API,
+ or new endpoints, but retaining major aspects of the system to work as before.
+ The customer has a way to roll back to a previous known working state.
+
+### Enables support for Regions
+
+Support for Regions should enable us to run GitLab in different availability zones,
+or completely different data centers.
+
+This includes, but is not limited to allowing users to create Organizations in Europe, the US West or US East,
+and GitLab Inc. to use different cloud infrastructure providers (Google Cloud, AWS) to serve customers.
+
+Cells enable existing customers running Organizations to move their Organization between different deployment regions/data centers that are supported by GitLab on GitLab.com.
+
+### Limit impact on self-managed customers (Omnibus/CNG)
+
+The introduction of Cells should not impact small installations.
+Cells should not require running additional components by self-managed customers
+unless they are interested in Cells that will increase resource requirements.
+
+### Provides 10x headroom
+
+The Cells architecture must provide at least 10x headroom. As such our architecture must be suitable to run 10 Cells. We do not need to initially solve for the complexities that might come with running more than 10 Cells.
+
+### Provides 100x headroom
+
+The Cells architecture should be able to run more than 10 Cells.
+
+### Improve Service Availability
+
+The Cells architecture should allow us to provide better SLA for some customers
+by putting them on specific Cells of the cluster:
+
+- Cells have to reduce the impact of noisy neighbors, such as legitimate usage caused by a spiky workload.
+- Cells have to reduce the impact caused by abuse, for instance CI being used for cryptocurrency mining.
+
+### Cost per user similar or lower to GitLab.com
+
+The current GitLab.com architecture is rather cost-effective.
+The introduction of Cells will result in more infrastructure components
+due to data distribution:
+
+- The proposed Cells architecture should evaluate the cost of running additional Cells with respect
+ to the achieved infrastructure component isolation. In some cases it might be beneficial to reuse
+ infrastructure components to reduce the running cost of Cells.
+- The proposed Cells architecture should ensure a high degree of multi-tenancy on Cells.
+- The proposed Cells architecture could enable a way to balance the Cells load long term.
+
+### Unified way of deploying Cells
+
+The proposed Cells architecture anticipates a need to run 100 Cells and more in a cluster.
+This becomes operational overhead. It is strongly desired for the Cells architecture
+to reuse existing infrastructure tooling as much as possible for: deployment, monitoring,
+logging, disaster recovery, and customer support.
+
+### Cells running in mixed deployments
+
+It is strongly required for the Cells architecture to run different versions of applications across the cluster. The purpose is to provide staged deployments allowing to test changes on part of the cluster, and to update part of the cluster less frequently.
+
+This also indicates that Cells should be able to work with different versions of the underlying
+infrastructure components: PostgreSQL version, Redis version, Gitaly version, Elasticsearch version.
+
+Usage of different versions within a Cell has to have no effect on other Cells.
+
+### High resilience to a single Cell failure
+
+Unavailability of a single Cell should not result in other Cells being unable to function properly:
+
+- Intra-cluster communication between Cells should be resilient to single Cell failure.
+- Intra-cluster communication should limit its dependence on data stored in other Cells.
+- Cluster-shared data should provide an anti-corruption layer to prevent a single Cell from causing a cluster-wide outage.
+- Cells should be monitored and their availability status should be accessible to all other Cells.
+- Cluster-wide data aggregation should take the availability status of each Cell into account.
+- The loss of cell-local data (groups and projects) does only affect ability to access data located on this cell.
+
+### Small Cells
+
+The Cells architecture should provide a cost effective way to run small Cells.
+Running small Cells allows to achieve superior quality in terms of latency or performance
+due to processing a significantly smaller data set and allowing significant single-node vertical scaling.
+
+The ability to run small Cells could result in reduced complexity of individual Cell deployment:
+
+- Prefer single-node vertical scaling as a first technique for increasing capacity (increase CPU count, available memory).
+- Reduce amount of data stored within a Cell to reduce time-to-recovery in case of outages.
+- Less data results in faster database migrations, improved latency, and superior user-facing performance.
+
+### Robust rollback and disaster recovery scenarios
+
+Rollout of the Cells architecture is a fundamental change to how GitLab.com will operate.
+This will involve introducing a number of new components, and distributing data horizontally across
+different Cells.
+
+We anticipate that something will go wrong at some point. Each deployment phase of the Cells architecture needs to provide a way to roll back to a prior working state. This includes any user-facing changes, as well as any infrastructure deployed components.
+
+### Scale existing GitLab.com database
+
+The existing GitLab.com database will continue to grow while we deploy Cells.
+The Cells architecture should provide a way to increase Cell 1 (existing GitLab.com)
+capacity as soon as possible.
+
+### Re-balancing of Cells
+
+It is expected that data distribution on Cells will become uneven at some point.
+
+The problem of re-balancing Cells is rather complex, but at some scale it might
+provide a positive ROI compared to the running cost of imbalanced Cells.
+
+This might involve understanding how to selectively migrate customer data between
+Cells onto already existing Cells.
+
+### Customer can migrate from GitLab.com to Dedicated
+
+Cells will enforce an architecture with more isolation. However, it is expected
+that some customers would like to move from SaaS GitLab.com to GitLab Dedicated.
+
+This implies being able to selectively migrate data from the GitLab.com cluster to Dedicated.
+This could be achieved by:
+
+- Migrating a customer to a Dedicated Cell on the GitLab.com cluster.
+- Disconnecting a Cell from the GitLab.com cluster into its own standalone Dedicated Cell.
+
+### Easy usage in development environment
+
+The Cells architecture should be easy to run locally by developers as needed to be able to:
+
+- Implement cluster-wide features.
+- Model Cells not being available.
+
+## Non-Goals
+
+The following objectives are not part of this document. At some point they
+were considered, but dismissed as creating distraction from the goals and requirements documented above.
+
+### Federation between distinct GitLab instances
+
+The Cells architecture is meant to provide trusted intra-cluster communication
+with some set of data being shared. Federation is meant to solve the problem
+of data flow between two completely distinct and external instances.
+
+### Usage of cloud managed services
+
+Cells should not interfere with other efforts to move towards using more managed services in the cloud.
+
+### Cells should replace canary deployments
+
+When we have Cells we won't need to run canary deployments anymore as we can roll out changes to single Cells at a time.
+Our main benefit of canary deployments today is that we can roll out code changes to internal users first.
+With Cells, we will have internal users on a specific Cell, which can be deployed first.
+
+Additionally Cells may solve some issues with canaries today, for example not having a way to upgrade Sidekiq code for a subset of users.
+
+## Glossary
+
+| Term | Description | Discouraged Terms |
+| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
+| [Cell](#cell) | A Cell is a set of infrastructure components that contains multiple top-level Groups that belong to different Organizations. | GitLab instance, cluster, shard, Pod |
+| [Cluster](#cluster) | A cluster is a collection of Cells. | Whale, GitLab Dedicated instance, instance |
+| [Organizations](#organizations) | An Organization is the umbrella for one or multiple top-level Groups. | Billable entities, customers |
+| [Top-Level Group](#top-level-group) | Top-level Group is the name given to the top-most Group of all other Groups. Groups and Projects are nested underneath the top-level Group. | Root-level namespace |
+| [Users](#users) | An account containing its own personal namespace associated with an email. | Customer |
+
+### Cell
+
+> Pod was renamed to Cell in <https://gitlab.com/gitlab-com/www-gitlab-com/-/merge_requests/121163>
+
+A Cell is a set of infrastructure components that contains multiple top-level Groups that belong to different Organizations. The components include both data stores (PostgreSQL, Redis, etc.) and stateless services (web, etc.). The infrastructure components provided within a Cell are shared among Organizations and their top-level Groups, but are not shared with other Cells. This isolation of infrastructure components means that Cells are independent from each other.
+
+<img src="diagrams/term-cell.drawio.png" height="200">
+
+- Each Cell is independent from other Cells
+- Infrastructure components are shared by Organizations and their top-level Groups within a Cell
+- More Cells can be provisioned to provide horizontal scalability
+- A failing Cell does not lead to failure of other Cells
+- Noisy neighbor effects are limited to within a Cell
+- Cells are not visible to Organizations - they are an implementation detail
+- Cells may be located in different geographical regions (for example: EU, US, JP, UK)
+- A GitLab Dedicated instance can join the cluster, and become a Cell
+
+Discouraged synonyms: GitLab instance, cluster, shard, Pod
+
+### Cluster
+
+A cluster is a collection of Cells.
+
+<img src="diagrams/term-cluster.drawio.png" height="300">
+
+- A cluster holds cluster-wide metadata, for example: Users, Routes, Settings.
+
+Discouraged synonyms: Whale, GitLab Dedicated instance, instance
+
+### Organizations
+
+An Organization is the umbrella for one or multiple top-level Groups. Organizations are isolated from each other by default meaning that cross-namespace features will only work for namespaces that exist in a single Organization.
+
+![Term Organization](diagrams/term-organization.drawio.png)
+
+See the [Organization blueprint](../../blueprints/organization/index.md).
+
+Organizations are a known concept, present for example in [AWS](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/core-concepts.html) and [GCP](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy#organizations).
+
+Organizations work under the following assumptions:
+
+1. Users care about what happens within their Organization.
+1. Features need to work within an Organization.
+1. Only few features need to work across Organizations.
+1. Users understand that the majority of pages they view are only scoped to a single Organization at a time.
+1. Organizations are located on a single Cell.
+
+Properties:
+
+- Top-level Groups belong to Organizations.
+- Organizations are isolated from each other by default, meaning that cross-Group features will only work for Groups that exist within a single Organization.
+- Personal namespaces must not belong to an Organization.
+
+Discouraged synonyms: Billable entities, customers
+
+### Top-level Group
+
+Example:
+
+`https://gitlab.com/gitlab-org/gitlab/`:
+
+- `gitlab-org` is a `top-level group`; the root for all Groups and Projects of an Organization
+- `gitlab` is a `project`; a Project of the Organization.
+
+The top-level Group has served as the de facto Organization entity. With the creation of Organizations, top-level Groups will be [nested underneath Organizations](https://gitlab.com/gitlab-org/gitlab/-/issues/394796).
+
+Over time, there won't be a distinction between a top-level Group and a Group. All features that make top-level Groups different from Groups will move to the Organization.
+
+![Term Top-level Group](diagrams/term-top-level-group.drawio.png)
+
+- Top-level Groups belonging to the same Organization are located on the same Cell.
+- Top-level Groups can interact with other top-level Groups that belong to the same Organization.
+
+Discouraged synonyms: Root-level namespace
+
+### Users
-A number of technical issues need to be resolved to implement Cells (in no particular order). This section will be expanded.
+Users are available globally and not restricted to a single Cell. Users belong to a single Organization, but can participate in many Organizations through Group and Project membership with varying permissions. Inside Organizations, users can create multiple top-level Groups. User activity is not limited to a single Organization but their contributions (for example To-Dos) are only aggregated within an Organization. This avoids the need for aggregating across Cells.
-1. How are Cells provisioned? - [Design discussion](https://gitlab.com/gitlab-org/gitlab/-/issues/396641)
-1. What is a Cells topology? - [Design discussion](https://gitlab.com/gitlab-org/gitlab/-/issues/396641)
-1. How are users of an organization routed to the correct Cell? -
-1. How do users authenticate with Cells and Organizations? - [Design discussion](https://gitlab.com/gitlab-org/gitlab/-/issues/395736)
-1. How are Cells rebalanced?
-1. How can Cells implement disaster recovery capabilities?
+- Users are shared globally across all Cells.
+- Users can create multiple top-level Groups.
+- Users can be members of multiple top-level Groups.
+- Users belong to one Organization. See [!395736](https://gitlab.com/gitlab-org/gitlab/-/issues/395736).
+- Users can be members of Groups and Projects in different Organizations.
+- Users can administer Organizations.
+- User activity is aggregated in an Organization.
+- Every user has one personal namespace.
diff --git a/doc/architecture/blueprints/cells/impact.md b/doc/architecture/blueprints/cells/impact.md
index 30c70dca0cc..1f77b9056be 100644
--- a/doc/architecture/blueprints/cells/impact.md
+++ b/doc/architecture/blueprints/cells/impact.md
@@ -1,58 +1,7 @@
---
-stage: enablement
-group: Tenant Scale
-description: 'Cells: Cross-section impact'
+redirect_to: 'index.md'
+remove_date: '2023-11-22'
---
-# Cells: Cross-section impact
-
-Cells is a fundamental architecture change that impacts other sections and stages. This section summarizes and links to other groups that may be impacted and highlights potential conflicts that need to be resolved. The Tenant Scale group is not responsible for achieving the goals of other groups but we want to ensure that dependencies are resolved.
-
-## Summary
-
-Based on discussions with other groups the net impact of introducing Cells and a new entity called organizations is mostly neutral. It may slow down development in some areas. We did not discover major blockers for other teams.
-
-1. We need to resolve naming conflicts (proposal is TBD)
-1. Cells requires introducing Organizations. Organizations are a new entity **above** top-level groups. Because this is a new entity, it may impact the ability to consolidate settings for Group::Organization and influence their decision on [how to approach introducing a an organization](https://gitlab.com/gitlab-org/gitlab/-/issues/376285#approach-2-organization-is-built-on-top-of-top-level-groups)
-1. Organizations may make it slightly easier for Fulfillment to realize their billing plans.
-
-## Impact on Group::Organization
-
-We synced with the Organization PM and Designer ([recording](https://youtu.be/b5Opn9cFWFk)) and discussed the similarities and differences between the Cells and Organization proposal ([presentation](https://docs.google.com/presentation/d/1FsUi22Up15b_tu6p2m-yLML3hCZ3rgrZrmzJAxUsNmU/edit?usp=sharing)).
-
-### Goals of Group::Organization
-
-As defined in the [organization documentation](../../../user/organization/index.md):
-
-1. Create an entity to manage everything you do as a GitLab administrator, including:
- 1. Defining and applying settings to all of your groups, subgroups, and projects.
- 1. Aggregating data from all your groups, subgroups, and projects.
-1. Reach feature parity between SaaS and self-managed installations, with all Admin Area settings moving to groups (?). Hardware controls remain on the instance level.
-
-The [organization roadmap outlines](https://gitlab.com/gitlab-org/gitlab/-/issues/368237#high-level-goals) the current goals in detail.
-
-### Potential conflicts with Cells
-
-- Organization defines a new entity as the primary organizational object for groups and projects.
-- We will only introduce one entity
-- Group::Organization highlighted the need to further validate the key assumption that users only care about what happens within their organization.
-
-## Impact on Fulfillment
-
-We synced with Fulfillment ([recording](https://youtu.be/FkQF3uF7vTY)) to discuss how Cells would impact them. Fulfillment is supportive of an entity above top-level groups. Their perspective is outline in [!5639](https://gitlab.com/gitlab-org/customers-gitlab-com/-/merge_requests/5639/diffs).
-
-### Goals of Fulfillment
-
-- Fulfillment has a longstanding plan to move billing from the top-level group to a level above. This would mean that a license applies for an organization and all its top-level groups.
-- Fulfillment uses Zuora for billing and would like to have a 1-to-1 relationship between an organization and their Zuora entity called BillingAccount. They want to move away from tying a license to a single user.
-- If a customer needs multiple organizations, the corresponding BillingAccounts can be rolled up into a consolidated billing account (similar to [AWS consolidated billing](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/consolidated-billing.html))
-- Ideally, a self-managed instance has a single Organization by default, which should be enough for most customers.
-- Fulfillment prefers only one additional entity.
-
-A rough representation of this is:
-
-![Cells and Fulfillment](diagrams/cells-and-fulfillment.drawio.png)
-
-### Potential conflicts with Cells
-
-- There are no known conflicts between Fulfillment's plans and Cells
+This document was removed due to being outdated.
+Go to [index page](index.md) for the most recent content.
diff --git a/doc/architecture/blueprints/cells/impacted_features/admin-area.md b/doc/architecture/blueprints/cells/impacted_features/admin-area.md
new file mode 100644
index 00000000000..a9cd170b2a7
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/admin-area.md
@@ -0,0 +1,81 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Admin Area'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Admin Area
+
+In our Cells architecture proposal we plan to share all admin related tables in GitLab.
+This allows for simpler management of all Cells in one interface and reduces the risk of settings diverging in different Cells.
+This introduces challenges with Admin Area pages that allow you to manage data that will be spread across all Cells.
+
+## 1. Definition
+
+There are consequences for Admin Area pages that contain data that span "the whole instance" as the Admin Area pages may be served by any Cell or possibly just one Cell.
+There are already many parts of the Admin Area that will have data that span many Cells.
+For example lists of all Groups, Projects, Topics, Jobs, Analytics, Applications and more.
+There are also administrative monitoring capabilities in the Admin Area that will span many Cells such as the "Background Jobs" and "Background Migrations" pages.
+
+## 2. Data flow
+
+## 3. Proposal
+
+We will need to decide how to handle these exceptions with a few possible
+options:
+
+1. Move all these pages out into a dedicated per-Cell admin section. Probably
+ the URL will need to be routable to a single Cell like `/cells/<cell_id>/admin`,
+ then we can display these data per Cell. These pages will be distinct from
+ other Admin Area pages which control settings that are shared across all Cells. We
+ will also need to consider how this impacts self-managed customers and
+ whether, or not, this should be visible for single-Cell instances of GitLab.
+1. Build some aggregation interfaces for this data so that it can be fetched
+ from all Cells and presented in a single UI. This may be beneficial to an
+ administrator that needs to see and filter all data at a glance, especially
+ when they don't know which Cell the data is on. The downside, however, is
+ that building this kind of aggregation is very tricky when all Cells are
+ designed to be totally independent, and it does also enforce stricter
+ requirements on compatibility between Cells.
+
+The following overview describes at what level each feature contained in the current Admin Area will be managed:
+
+| Feature | Cluster | Cell | Organization |
+| --- | --- | --- | --- |
+| Abuse reports | | | |
+| Analytics | | | |
+| Applications | | | |
+| Deploy keys | | | |
+| Labels | | | |
+| Messages | ✓ | | |
+| Monitoring | | ✓ | |
+| Subscription | | | |
+| System hooks | | | |
+| Overview | | | |
+| Settings - General | ✓ | | |
+| Settings - Integrations | ✓ | | |
+| Settings - Repository | ✓ | | |
+| Settings - CI/CD (1) | ✓ | ✓ | |
+| Settings - Reporting | ✓ | | |
+| Settings - Metrics | ✓ | | |
+| Settings - Service usage data | | ✓ | |
+| Settings - Network | ✓ | | |
+| Settings - Appearance | ✓ | | |
+| Settings - Preferences | ✓ | | |
+
+(1) Depending on the specific setting, some will be managed at the cluster-level, and some at the Cell-level.
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/agent-for-kubernetes.md b/doc/architecture/blueprints/cells/impacted_features/agent-for-kubernetes.md
new file mode 100644
index 00000000000..37347cf836d
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/agent-for-kubernetes.md
@@ -0,0 +1,30 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Agent for Kubernetes'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Agent for Kubernetes
+
+> TL;DR
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/backups.md b/doc/architecture/blueprints/cells/impacted_features/backups.md
new file mode 100644
index 00000000000..3d20d6e2caa
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/backups.md
@@ -0,0 +1,53 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Backups'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Backups
+
+Each Cell will take its own backups, and consequently have its own isolated backup/restore procedure.
+
+## 1. Definition
+
+GitLab backup takes a backup of the PostgreSQL database used by the application, and also Git repository data.
+
+## 2. Data flow
+
+Each Cell has a number of application databases to back up (for example, `main`, and `ci`).
+Additionally, there may be cluster-wide metadata tables (for example, `users` table) which is directly accessible via PostgreSQL.
+
+## 3. Proposal
+
+### 3.1. Cluster-wide metadata
+
+It is currently unknown how cluster-wide metadata tables will be accessible.
+We may choose to have cluster-wide metadata tables backed up separately, or have each Cell back up its copy of cluster-wide metadata tables.
+
+### 3.2 Consistency
+
+#### 3.2.1 Take backups independently
+
+As each Cell will communicate with each other via API, and there will be no joins to the `users` table, it should be acceptable for each Cell to take a backup independently of each other.
+
+#### 3.2.2 Enforce snapshots
+
+We can require that each Cell take a snapshot for the PostgreSQL databases at around the same time to allow for a consistent enough backup.
+
+## 4. Evaluation
+
+As the number of Cells increases, it will likely not be feasible to take a snapshot at the same time for all Cells.
+Hence taking backups independently is the better option.
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/ci-cd-catalog.md b/doc/architecture/blueprints/cells/impacted_features/ci-cd-catalog.md
new file mode 100644
index 00000000000..3ca2ff042dc
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/ci-cd-catalog.md
@@ -0,0 +1,54 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: CI/CD Catalog'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the Cells design.
+Significant aspects are not documented, though we expect to add them in the future.
+This is one possible architecture for Cells, and we intend to contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that we can document the reasons for not choosing this approach.
+
+# Cells: CI/CD Catalog
+
+The [CI/CD pipeline components catalog](../../ci_pipeline_components/index.md) is a currently experimental feature that aims at helping users reuse pipeline configurations.
+Potentially, there are several aspects of the CI/CD catalog that might be affected by Cells:
+
+1. Namespace catalog, exists today as an experimental feature. With the introduction of Cells we would likely remove the namespace catalog and create a single Organization catalog, where all users would see all available published components in a single place (based on their permissions). This would replace today's offering, where users can have multiple catalogs which are bound to a namespace and completely isolated from each other.
+1. The community catalog is supposed to allow users to search across different Organizations.
+
+## 1. Definition
+
+The [CI/CD pipeline components catalog](../../ci_pipeline_components/index.md) makes reusing pipeline configurations easier and more efficient.
+It provides a way to discover and reuse pipeline constructs, allowing for a more streamlined experience.
+
+There are several flavors of the CI/CD catalog:
+
+1. [Namespace catalog (experimental)](../../../../ci/components/index.md): Bound to the top-level namespace (group or personal namespace). The namespace catalog aggregates all published components from Projects it contains. The number of top-level namespaces available in an Organization could potentially be the number of available catalogs.
+1. Instance-wide component catalog (planned): Surfacing all the components that are scattered across an instance. All published components in a public or internal Project will be available in the instance-wide catalog. Only a single instance-wide catalog is planned per instance.
+1. Community catalog (planned): Allow users to search all published components in different repositories across multiple namespaces. The original plan was to introduce a community catalog within self-managed customer that would act as an aggregator of all published components hosted in that instance.
+
+## 2. Data flow
+
+## 3. Proposal
+
+Moving to Organizations is a great opportunity to improve the user experience and to reach parity for both self-managed and GitLab.com users.
+
+- We introduce an Organization catalog which aggregates and surfaces all the published components that are hosted in a single Organization. The Organization catalog would make the namespace catalog obsolete.
+- Once Organizations exist, GitLab.com users would need a community catalog to surface components across multiple Organizations. We need additional research to understand if such a solution is needed for self-managed customers as well.
+
+## 4. Evaluation
+
+Moving to a single Organization will improve the experience for users of the CI/CD component catalog.
+Today we can have multiple catalogs based on the number of namespaces, making it difficult for users to surface information across an Organization.
+
+### 4.1. Pros
+
+- An Organization catalog will be one unified catalog serving as the single source of truth for an Organization.
+- An Organization catalog would serve both self-managed and GitLab.com users, whereas the current plan was to introduce two types of catalogs: an instance-wide component catalog for self-managed and a community catalog for GitLab.com.
+
+### 4.2. Cons
+
+- A separate catalog that surfaces components across Organizations would need to be implemented to serve the wider community (community catalog). This catalog will be required for GitLab.com only, later on we can evaluate if a similar catalog is needed for self-managed customers.
diff --git a/doc/architecture/blueprints/cells/impacted_features/ci-runners.md b/doc/architecture/blueprints/cells/impacted_features/ci-runners.md
new file mode 100644
index 00000000000..e9fe4905573
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/ci-runners.md
@@ -0,0 +1,144 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: CI Runners'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: CI Runners
+
+GitLab executes CI jobs via [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/), very often managed by customers in their infrastructure.
+All CI jobs created as part of the CI pipeline are run in the context of a Project.
+This poses a challenge how to manage GitLab Runners.
+
+## 1. Definition
+
+There are 3 different types of runners:
+
+- Instance-wide: Runners that are registered globally with specific tags (selection criteria)
+- Group runners: Runners that execute jobs from a given top-level Group or Projects in that Group
+- Project runners: Runners that execute jobs from one Projects or many Projects: some runners might
+ have Projects assigned from Projects in different top-level Groups.
+
+This, alongside with the existing data structure where `ci_runners` is a table describing all types of runners, poses a challenge as to how the `ci_runners` should be managed in a Cells environment.
+
+## 2. Data flow
+
+GitLab runners use a set of globally scoped endpoints to:
+
+- Register a new runner via registration token `https://gitlab.com/api/v4/runners`
+ ([subject for removal](../../runner_tokens/index.md)) (`registration token`)
+- Create a new runner in the context of a user `https://gitlab.com/api/v4/user/runners` (`runner token`)
+- Request jobs via an authenticated `https://gitlab.com/api/v4/jobs/request` endpoint (`runner token`)
+- Upload job status via `https://gitlab.com/api/v4/jobs/:job_id` (`build token`)
+- Upload trace via `https://gitlab.com/api/v4/jobs/:job_id/trace` (`build token`)
+- Download and upload artifacts via `https://gitlab.com/api/v4/jobs/:job_id/artifacts` (`build token`)
+
+Currently three types of authentication tokens are used:
+
+- Runner registration token ([subject for removal](../../runner_tokens/index.md))
+- Runner token representing a registered runner in a system with specific configuration (`tags`, `locked`, etc.)
+- Build token representing an ephemeral token giving limited access to updating a specific job, uploading artifacts, downloading dependent artifacts, downloading and uploading container registry images
+
+Each of those endpoints receive an authentication token via header (`JOB-TOKEN` for `/trace`) or body parameter (`token` all other endpoints).
+
+Since the CI pipeline would be created in the context of a specific Cell, it would be required that pick of a build would have to be processed by that particular Cell.
+This requires that build picking depending on a solution would have to be either:
+
+- Routed to the correct Cell for the first time
+- Be two-phased: Request build from global pool, claim build on a specific Cell using a Cell specific URL
+
+## 3. Proposal
+
+### 3.1. Authentication tokens
+
+Even though the paths for CI runners are not routable, they can be made routable with these two possible solutions:
+
+- The `https://gitlab.com/api/v4/jobs/request` uses a long polling mechanism with
+ a ticketing mechanism (based on `X-GitLab-Last-Update` header). When the runner first
+ starts, it sends a request to GitLab to which GitLab responds with either a build to pick
+ by runner. This value is completely controlled by GitLab. This allows GitLab
+ to use JWT or any other means to encode a `cell` identifier that could be easily
+ decodable by Router.
+- The majority of communication (in terms of volume) is using `build token`, making it
+ the easiest target to change since GitLab is the sole owner of the token that the runner later
+ uses for a specific job. There were prior discussions about not storing the `build token`
+ but rather using a `JWT` token with defined scopes. Such a token could encode the `cell`
+ to which the Router could route all requests.
+
+### 3.2. Request body
+
+- The most used endpoints pass the authentication token in the request body. It might be desired
+ to use HTTP headers as an easier way to access this information by Router without
+ a need to proxy requests.
+
+### 3.3. Instance-wide are Cell-local
+
+We can pick a design where all runners are always registered and local to a given Cell:
+
+- Each Cell has its own set of instance-wide runners that are updated at its own pace
+- The Project runners can only be linked to Projects from the same Organization, creating strong isolation.
+- In this model the `ci_runners` table is local to the Cell.
+- In this model we would require the above endpoints to be scoped to a Cell in some way, or be made routable. It might be via prefixing them, adding additional Cell parameters, or providing much more robust ways to decode runner tokens and match it to a Cell.
+- If a routable token is used, we could move away from cryptographic random stored in database to rather prefer to use JWT tokens.
+- The Admin Area showing registered runners would have to be scoped to a Cell.
+
+This model might be desired because it provides strong isolation guarantees.
+This model does significantly increase maintenance overhead because each Cell is managed separately.
+This model may require adjustments to the runner tags feature so that Projects have a consistent runner experience across Cells.
+
+### 3.4. Instance-wide are cluster-wide
+
+Contrary to the proposal where all runners are Cell-local, we can consider that runners
+are global, or just instance-wide runners are global.
+
+However, this requires significant overhaul of the system and we would have to change the following aspects:
+
+- The `ci_runners` table would likely have to be decomposed into `ci_instance_runners`, ...
+- All interfaces would have to be adopted to use the correct table.
+- Build queuing would have to be reworked to be two-phased where each Cell would know of all pending and running builds, but the actual claim of a build would happen against a Cell containing data.
+- It is likely that `ci_pending_builds` and `ci_running_builds` would have to be made `cluster-wide` tables, increasing the likelihood of creating hotspots in a system related to CI queueing.
+
+This model is complex to implement from an engineering perspective.
+Some data are shared between Cells.
+It creates hotspots/scalability issues in a system that might impact the experience of Organizations on other Cells, for instance during abuse.
+
+### 3.5. GitLab CI Daemon
+
+Another potential solution to explore is to have a dedicated service responsible for builds queueing, owning its database and working in a model of either sharded or Cell-ed service.
+There were prior discussions about [CI/CD Daemon](https://gitlab.com/gitlab-org/gitlab/-/issues/19435).
+
+If the service is sharded:
+
+- Depending on the model, if runners are cluster-wide or Cell-local, this service would have to fetch data from all Cells.
+- If the sharded service is used we could adapt a model of sharing a database containing `ci_pending_builds/ci_running_builds` with the service.
+- If the sharded service is used we could consider a push model where each Cell pushes to CI/CD Daemon builds that should be picked by runner.
+- The sharded service would be aware which Cell is responsible for processing the given build and could route processing requests to the designated Cell.
+
+If the service is Cell-ed:
+
+- All expectations of routable endpoints are still valid.
+
+In general usage of CI Daemon does not help significantly with the stated problem.
+However, this offers a few upsides related to more efficient processing and decoupling model: push model and it opens a way to offer stateful communication with GitLab runners (ex. gRPC or Websockets).
+
+## 4. Evaluation
+
+Considering all options it appears that the most promising solution is to:
+
+- Use [Instance-wide are Cell-local](#33-instance-wide-are-cell-local)
+- Refine endpoints to have routable identities (either via specific paths, or better tokens)
+
+Another potential upside is to get rid of `ci_builds.token` and rather use a `JWT token` that can much better and easier encode a wider set of scopes allowed by CI runner.
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/container-registry.md b/doc/architecture/blueprints/cells/impacted_features/container-registry.md
new file mode 100644
index 00000000000..ea15dd52d94
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/container-registry.md
@@ -0,0 +1,114 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Container Registry'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Container Registry
+
+GitLab [Container Registry](../../../../user/packages/container_registry/index.md) is a feature allowing to store Docker container images in GitLab.
+
+## 1. Definition
+
+GitLab Container Registry is a complex service requiring usage of PostgreSQL, Redis and Object Storage dependencies.
+Right now there's undergoing work to introduce [Container Registry Metadata](../../container_registry_metadata_database/index.md) to optimize data storage and image retention policies of Container Registry.
+
+GitLab Container Registry is serving as a container for stored data, but on its own does not authenticate `docker login`.
+The `docker login` is executed with user credentials (can be `personal access token`) or CI build credentials (ephemeral `ci_builds.token`).
+
+Container Registry uses data deduplication.
+It means that the same blob (image layer) that is shared between many Projects is stored only once.
+Each layer is hashed by `sha256`.
+
+The `docker login` does request a JWT time-limited authentication token that is signed by GitLab, but validated by Container Registry service.
+The JWT token does store all authorized scopes (`container repository images`) and operation types (`push` or `pull`).
+A single JWT authentication token can have many authorized scopes.
+This allows Container Registry and client to mount existing blobs from other scopes.
+GitLab responds only with authorized scopes.
+Then it is up to GitLab Container Registry to validate if the given operation can be performed.
+
+The GitLab.com pages are always scoped to a Project.
+Each Project can have many container registry images attached.
+
+Currently, on GitLab.com the actual registry service is served via `https://registry.gitlab.com`.
+
+The main identifiable problems are:
+
+- The authentication request (`https://gitlab.com/jwt/auth`) that is processed by GitLab.com.
+- The `https://registry.gitlab.com` that is run by an external service and uses its own data store.
+- Data deduplication. The Cells architecture with registry run in a Cell would reduce efficiency of data storage.
+
+## 2. Data flow
+
+### 2.1. Authorization request that is send by `docker login`
+
+```shell
+curl \
+ --user "username:password" \
+ "https://gitlab/jwt/auth?client_id=docker&offline_token=true&service=container_registry&scope=repository:gitlab-org/gitlab-build-images:push,pull"
+```
+
+Result is encoded and signed JWT token. Second base64 encoded string (split by `.`) contains JSON with authorized scopes.
+
+```json
+{"auth_type":"none","access":[{"type":"repository","name":"gitlab-org/gitlab-build-images","actions":["pull"]}],"jti":"61ca2459-091c-4496-a3cf-01bac51d4dc8","aud":"container_registry","iss":"omnibus-gitlab-issuer","iat":1669309469,"nbf":166}
+```
+
+### 2.2. Docker client fetching tags
+
+```shell
+curl \
+ -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
+ -H "Authorization: Bearer token" \
+ https://registry.gitlab.com/v2/gitlab-org/gitlab-build-images/tags/list
+
+curl \
+ -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
+ -H "Authorization: Bearer token" \
+ https://registry.gitlab.com/v2/gitlab-org/gitlab-build-images/manifests/danger-ruby-2.6.6
+```
+
+### 2.3. Docker client fetching blobs and manifests
+
+```shell
+curl \
+ -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
+ -H "Authorization: Bearer token" \
+ https://registry.gitlab.com/v2/gitlab-org/gitlab-build-images/blobs/sha256:a3f2e1afa377d20897e08a85cae089393daa0ec019feab3851d592248674b416
+```
+
+## 3. Proposal
+
+### 3.1. Shard Container Registry separately to Cells architecture
+
+Due to its extensive and in general highly scalable horizontal architecture it should be evaluated if the GitLab Container Registry should be run not in Cell, but in a Cluster and be scaled independently.
+This might be easier, but would definitely not offer the same amount of data isolation.
+
+### 3.2. Run Container Registry within a Cell
+
+It appears that except `/jwt/auth` which would likely have to be processed by Router (to decode `scope`) the Container Registry could be run as a local service of a Cell.
+The actual data at least in case of GitLab.com is not forwarded via registry, but rather served directly from Object Storage / CDN.
+
+Its design encodes container repository image in a URL that is easily routable.
+It appears that we could re-use the same stateless Router service in front of Container Registry to serve manifests and blobs redirect.
+
+The only downside is increased complexity of managing standalone registry for each Cell, but this might be desired approach.
+
+## 4. Evaluation
+
+There do not seem to be any theoretical problems with running GitLab Container Registry in a Cell.
+It seems that the service can be easily made routable to work well.
+The practical complexities are around managing a complex service from an infrastructure side.
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/contributions-forks.md b/doc/architecture/blueprints/cells/impacted_features/contributions-forks.md
new file mode 100644
index 00000000000..2053b87b125
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/contributions-forks.md
@@ -0,0 +1,163 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Contributions: Forks'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the Cells design.
+Significant aspects are not documented, though we expect to add them in the future.
+This is one possible architecture for Cells, and we intend to contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that we can document the reasons for not choosing this approach.
+
+# Cells: Contributions: Forks
+
+The [forking workflow](../../../../user/project/repository/forking_workflow.md) allows users to copy existing Project sources into their own namespace of choice (personal or Group).
+
+## 1. Definition
+
+The [forking workflow](../../../../user/project/repository/forking_workflow.md) is a common workflow with various usage patterns:
+
+- It allows users to contribute back to an upstream Project.
+- It persists repositories into their personal namespace.
+- Users can copy a Project to make changes and release it as a modified Project.
+
+Forks allow users not having write access to a parent Project to make changes.
+The forking workflow is especially important for the open-source community to contribute back to public Projects.
+However, it is equally important in some companies that prefer a strong split of responsibilities and tighter access control.
+The access to a Project is restricted to a designated list of developers.
+
+Forks enable:
+
+- Tighter control of who can modify the upstream Project.
+- Split of responsibilities: Parent Project might use CI configuration connecting to production systems.
+- To run CI pipelines in the context of a fork in a much more restrictive environment.
+- To consider all forks to be unvetted which reduces risks of leaking secrets, or any other information tied to the Project.
+
+The forking model is problematic in a Cells architecture for the following reasons:
+
+- Forks are clones of existing repositories. Forks could be created across different Organizations, Cells and Gitaly shards.
+- Users can create merge requests and contribute back to an upstream Project. This upstream Project might be in a different Organization and Cell.
+- The merge request CI pipeline is executed in the context of the source Project, but presented in the context of the target Project.
+
+## 2. Data exploration
+
+From a [data exploration](https://gitlab.com/gitlab-data/product-analytics/-/issues/1380), we retrieved the following information about existing forks:
+
+- Roughly 1.8m forks exist on GitLab.com at the moment.
+- The majority of forks are under a personal namespace (82%).
+- We were expecting a minimal use of forks within the same top-level Group and/or organization. Forking is only necessary for users who don't have permissions to access a Project. Inside companies we wouldn't expect teams to use forking workflows much unless they for some reason have different permissions across different team members. The data showed that only 9% of fork relationships have matching ultimate parent namespace identifiers (top-level Groups and personal namespaces). The other 91% of fork relationships are forked across different top-level namespaces. When trying to match top-level Groups to an identifiable company, we saw that:
+ - 3% of forked Projects are forked from an upstream Project in the same organization.
+ - 83% of forked Projects do not have an identifiable organization related to either up or downstream Project.
+ - The remaining 14% are forked from a source Project within a different company.
+- 9% of top-level Groups (95k) with activity in the last 12 months have a project with a fork relationship, compared to 5% of top-level Groups (91k) with no activity in the last 12 months. We expect these top-level Groups to be impacted by Cells.
+
+## 3. Proposal - Forks are created in a dedicated contribution space of the current Organization
+
+Instead of creating Projects across Organizations, forks are created in a contribution space tied to the Organization.
+A contribution space is similar to a personal namespace but rather than existing in the default Organization, it exists within the Organization someone is trying to contribute to.
+Example:
+
+- Any User that can view an Organization (all Users for public Organizations) can create a contribution space in the Organization. This is a dedicated namespace where they can create forks of Projects in that Organization. For example for `Produce Inc.` it could be `gitlab.com/organization/produce-inc/@ayufan`.
+- To create a contribution space we do not require membership of an Organization as this would prevent open source workflows where contributors are able to fork and create a merge request without ever being invited to a Group or Project. We strictly respect visibility, so Users would not be able to create a fork in a private Organization without first being invited.
+- When creating a fork for a Project Users will only be presented with the option to create forks in Groups that are part of the Organization. We will also give Users the option to create a contribution space and put the fork there. Today there is also a "Create a group" option when creating a fork. This functionality would also be limited to creating a new group in the organization to store the new fork.
+- In order to support Users that want to fork without contributing back we might consider an option to create [an unlinked fork](../../../../user/project/repository/forking_workflow.md#unlink-a-fork) in any namespace they have permission to write to.
+- The User has as many contribution spaces as Organizations they contribute to.
+- The User cannot create additional personal Projects within contribution spaces. Personal Projects can continue to be created in their personal namespace.
+- The Organization can prevent or disable usage of contribution spaces. This would disable forking by anyone that does not belong to a Group within the Organization.
+- All current forks are migrated into the contribution space of the User in an Organization. Because this may result in data loss when the fork also has links to data outside of the upstream Project we will also keep the personal Project around as archived and remove the fork relationship.
+- All forks are part of the Organization.
+- Forks are not federated features.
+- The contribution space and forked Project do not share configuration with the parent Project.
+- If the Organization is deleted, the Projects containing forks will be moved either to the default Organization or we'll create a new Organization to house them, which is essentially a ghost Organization of the former Organization.
+- Data in contribution spaces do not contribute to customer usage from a billing perspective.
+- Today we do not have organization-scoped runners but if we do implement that they will likely need special settings for how or if they can be used by contribution space projects.
+
+## 4. Alternative proposals considered
+
+### 4.1. Intra-cluster forks
+
+This proposal implements forks as intra-Cluster forks where communication is done via API between all trusted Cells of a cluster:
+
+- Forks are created always in the context of a user's choice of Group.
+- Forks are isolated from the Organization.
+- Organization or Group owner could disable forking across Organizations, or forking in general.
+- A merge request is created in the context of the target Project, referencing the external Project on another Cell.
+- To target Project the merge reference is transferred that is used for presenting information in context of the target Project.
+- CI pipeline is fetched in the context of the source Project as it is today, the result is fetched into the merge request of the target Project.
+- The Cell holding the target Project internally uses GraphQL to fetch the status of the source Project and includes in context of the information for merge request.
+
+Pros:
+
+- All existing forks continue to work as they are, as they are treated as intra-Cluster forks.
+
+Cons:
+
+- The purpose of Organizations is to provide strong isolation between Organizations. Allowing to fork across does break security boundaries.
+- However, this is no different to the ability of users today to clone a repository to a local computer and push it to any repository of choice.
+- Access control of the source Project can be lower than that of the target Project. Today, the system requires that in order to contribute back, the access level needs to be the same for fork and upstream Project.
+
+### 4.2. Forks are created as internal Projects under current Projects
+
+Instead of creating Projects across Organizations, forks are attachments to existing Projects.
+Each user forking a Project receives their unique Project.
+Example:
+
+- For Project: `gitlab.com/gitlab-org/gitlab`, forks would be created in `gitlab.com/gitlab-org/gitlab/@kamil-gitlab`.
+- Forks are created in the context of the current Organization, they do not cross Organization boundaries and are managed by the Organization.
+- Tied to the user (or any other user-provided name of the fork).
+- Forks are not federated features.
+
+Cons:
+
+- Does not answer how to handle and migrate all existing forks.
+- Might share current Group/Project settings, which could be breaking some security boundaries.
+
+## 5. Evaluation
+
+### 5.1. Pros
+
+### 5.2. Cons
+
+## 6. Example
+
+As an example, we will demonstrate the impact of this proposal for the case that we move `gitlab-org/gitlab` to a different Organization.
+`gitlab-org/gitlab` has [over 8K forks](https://gitlab.com/gitlab-org/gitlab/-/forks).
+
+### Does this direction impact the canonical URLs of those forks?
+
+Yes canonical URLs will change for forks.
+Existing users that have forks in personal namespaces and want to continue contributing merge requests, will be required to migrate their fork to a new fork in a contribution space.
+For example, a personal namespace fork at `https://gitlab.com/DylanGriffith/gitlab` will
+need to be migrated to `https://gitlab.com/-/contributions/gitlab-inc/@DylanGriffith/gitlab`.
+We may offer automated ways to move this, but manually the process would involve:
+
+1. Create the contribution space fork
+1. Push your local branch from your original fork to the new fork
+1. Recreate any merge request that was still open and you wanted to merge
+
+### Does it impact the Git URL of the repositories themselves?
+
+Yes.
+In the above the example the Git URL would change from
+`gitlab.com:DylanGriffith/gitlab.git` to `gitlab.com:/-/contributions/gitlab-inc/@DylanGriffith/gitlab.git`.
+
+### Would there be any user action required to accept their fork being moved within an Organization or towards a contribution space?
+
+If we offer an automated process we'd present this as an option for the user as they will become the new owner of the contribution space.
+
+### Can we make promises that we will not break the existing forks of public Projects hosted on GitLab.com?
+
+Existing fork projects will not be deleted but their fork relationship will be
+removed when the source project is moved to another Organization.
+The owner of the open source project will be made aware that they will disconnect their
+forks when they move the project which will require them to close all existing
+merge requests from those forks.
+There will need to be some process for keeping the history from these merge requests while effectively losing the ability to
+collaborate on them or merge them.
+
+In the case of `gitlab-org/gitlab` we will attempt to give as much notice of this process and make this process as transparent as possible.
+When we make the decision to move this project to an Organization we will seek additional
+feedback about what would be the minimum amount of automated migrations necessary to be acceptable here.
+But the workflow for contributors will change after the move so this will be a punctuated event regardless.
diff --git a/doc/architecture/blueprints/cells/impacted_features/data-migration.md b/doc/architecture/blueprints/cells/impacted_features/data-migration.md
new file mode 100644
index 00000000000..9ff661ddf68
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/data-migration.md
@@ -0,0 +1,99 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Data migration'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Data migration
+
+It is essential for a Cells architecture to provide a way to migrate data out of big Cells into smaller ones.
+This document describes various approaches to provide this type of split.
+
+We also need to handle cases where data is already violating the expected isolation constraints of Cells, for example references cannot span multiple Organizations.
+We know that existing features like linked issues allowed users to link issues across any Projects regardless of their hierarchy.
+There are many similar features.
+All of this data will need to be migrated in some way before it can be split across different Cells.
+This may mean some data needs to be deleted, or the feature needs to be changed and modelled slightly differently before we can properly split or migrate Organizations between Cells.
+
+Having schema deviations across different Cells, which is a necessary consequence of different databases, will also impact our ability to migrate data between Cells.
+Different schemas impact our ability to reliably replicate data across Cells and especially impact our ability to validate that the data is correctly replicated.
+It might force us to only be able to move data between Cells when the schemas are all in sync (slowing down deployments and the rebalancing process) or possibly only migrate from newer to older schemas which would be complex.
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+### 3.1. Split large Cells
+
+A single Cell can only be divided into many Cells.
+This is based on the principle that it is easier to create an exact clone of an existing Cell in many replicas out of which some will be made authoritative once migrated.
+Keeping those replicas up-to-date with Cell 0 is also much easier due to pre-existing replication solutions that can replicate the whole systems: Geo, PostgreSQL physical replication, etc.
+
+1. All data of an Organization needs to not be divided across many Cells.
+1. Split should be doable online.
+1. New Cells cannot contain pre-existing data.
+1. N Cells contain exact replica of Cell 0.
+1. The data of Cell 0 is live replicated to as many Cells it needs to be split.
+1. Once consensus is achieved between Cell 0 and N-Cells, the Organizations to be migrated away are marked as read-only cluster-wide.
+1. The `routes` is updated on for all Organizations to be split to indicate an authoritative Cell holding the most recent data, like `gitlab-org` on `cell-100`.
+1. The data for `gitlab-org` on Cell 0, and on other non-authoritative N-Cells are dormant and will be removed in the future.
+1. All accesses to `gitlab-org` on a given Cell are validated about `cell_id` of `routes` to ensure that given Cell is authoritative to handle the data.
+
+#### More challenges of this proposal
+
+1. There is no streaming replication capability for Elasticsearch, but you could
+ snapshot the whole Elasticsearch index and recreate, but this takes hours.
+ It could be handled by pausing Elasticsearch indexing on the initial Cell during
+ the migration as indexing downtime is not a big issue, but this still needs
+ to be coordinated with the migration process.
+1. Syncing Redis, Gitaly, CI Postgres, Main Postgres, registry Postgres, other
+ new data stores snapshots in an online system would likely lead to gaps
+ without a long downtime. You need to choose a sync point and at the sync
+ point you need to stop writes to perform the migration. The more data stores
+ there are to migrate at the same time the longer the write downtime for the
+ failover. We would also need to find a reliable place in the application to
+ actually block updates to all these systems with a high degree of
+ confidence. In the past we've only been confident by shutting down all Rails
+ services because any Rails process could write directly to any of these at
+ any time due to async workloads or other surprising code paths.
+1. How to efficiently delete all the orphaned data. Locating all `ci_builds`
+ associated with half the Organizations would be very expensive if we have to
+ do joins. We haven't yet determined if we'd want to store an `organization_id`
+ column on every table, but this is the kind of thing it would be helpful for.
+
+### 3.2. Migrate Organization from an existing Cell
+
+This is different to split, as we intend to perform logical and selective replication of data belonging to a single Organization.
+Today this type of selective replication is only implemented by Gitaly where we can migrate Git repository from a single Gitaly node to another with minimal downtime.
+
+In this model we would require identifying all resources belonging to a given Organization: database rows, object storage files, Git repositories, etc. and selectively copy them over to another (likely) existing Cell importing data into it.
+Ideally ensuring that we can perform logical replication live of all changed data, but change similarly to split which Cell is authoritative for this Organization.
+
+1. It is hard to identify all resources belonging to an Organization.
+1. It requires either downtime for the Organization or a robust system to identify live changes made.
+1. It likely will require a full database structure analysis (more robust than Project import/export) to perform selective PostgreSQL logical replication.
+
+#### More challenges of this proposal
+
+1. Logical replication is still not performant enough to keep up with our
+ scale. Even if we could use logical replication we still don't have an
+ efficient way to filter data related to a single Organization without
+ joining all the way to the `organizations` table which will slow down
+ logical replication dramatically.
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/data-pipeline-ingestion.md b/doc/architecture/blueprints/cells/impacted_features/data-pipeline-ingestion.md
new file mode 100644
index 00000000000..92de3df7c27
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/data-pipeline-ingestion.md
@@ -0,0 +1,39 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Data Pipeline Ingestion'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Data pipeline ingestion
+
+The Cells architecture will have a significant impact on the current [data pipeline](https://about.gitlab.com/handbook/business-technology/data-team/platform/pipelines/SAAS-Gitlab-com/) which exports data from Postgres to Snowflake for the use of data analytics. This data pipeline fulfils many use cases (i.e. SAAS Service ping, Gainsight metrics and Reporting and Analytics of the SAAS Platform).
+
+## 1. Definition
+
+## 2. Data flow
+
+The current data pipeline is limited by not having the possibility to get data via a CDC mechanism (which leads to data quality issues) and works by polling the Postgres database and looking for new and updated records or fully extracting data for certain tables which causes a lot of overhead.
+At the moment the data pipeline runs against two instances that get created from a snapshot of both the `main` and `ci` databases.
+This is done to avoid workload on the production databases.
+In the Cells architecture there will be more Postgres instances because of which the current pipeline couldn't scale to pull data from all the Postgres instances. Requirements around the data pipeline moving forward are as follows:
+
+- We need a process that allows capturing all the CDC (insert, update and delete) from all Cells, scaling automatically with N number of Cells.
+- We need to have (direct or indirect) access to database instances which allows it to do data catch up in case of major failure or root cause analysis for data anomalies.
+- We need monitoring in place to alert any incident that can delay the data ingestion.
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/database-sequences.md b/doc/architecture/blueprints/cells/impacted_features/database-sequences.md
new file mode 100644
index 00000000000..2aeaaed7d64
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/database-sequences.md
@@ -0,0 +1,74 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Database Sequences'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Database Sequences
+
+GitLab today ensures that every database row create has a unique ID, allowing to access a merge request, CI Job or Project by a known global ID.
+Cells will use many distinct and not connected databases, each of them having a separate ID for most entities.
+At a minimum, any ID referenced between a Cell and the shared schema will need to be unique across the cluster to avoid ambiguous references.
+Further to required global IDs, it might also be desirable to retain globally unique IDs for all database rows to allow migrating resources between Cells in the future.
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+These are some preliminary ideas how we can retain unique IDs across the system.
+
+### 3.1. UUID
+
+Instead of using incremental sequences, use UUID (128 bit) that is stored in the database.
+
+- This might break existing IDs and requires adding a UUID column for all existing tables.
+- This makes all indexes larger as it requires storing 128 bit instead of 32/64 bit in index.
+
+### 3.2. Use Cell index encoded in ID
+
+Because a significant number of tables already use 64 bit ID numbers we could use MSB to encode the Cell ID:
+
+- This might limit the amount of Cells that can be enabled in a system, as we might decide to only allocate 1024 possible Cell numbers.
+- This would make it possible to migrate IDs between Cells, because even if an entity from Cell 1 is migrated to Cell 100 this ID would still be unique.
+- If resources are migrated the ID itself will not be enough to decode the Cell number and we would need a lookup table.
+- This requires updating all IDs to 32 bits.
+
+### 3.3. Allocate sequence ranges from central place
+
+Each Cell might receive its own range of sequences as they are consumed from a centrally managed place.
+Once a Cell consumes all IDs assigned for a given table it would be replenished and a next range would be allocated.
+Ranges would be tracked to provide a faster lookup table if a random access pattern is required.
+
+- This might make IDs migratable between Cells, because even if an entity from Cell 1 is migrated to Cell 100 this ID would still be unique.
+- If resources are migrated the ID itself will not be enough to decode the Cell number and we would need a much more robust lookup table as we could be breaking previously assigned sequence ranges.
+- This does not require updating all IDs to 64 bits.
+- This adds some performance penalty to all `INSERT` statements in Postgres or at least from Rails as we need to check for the sequence number and potentially wait for our range to be refreshed from the ID server.
+- The available range will need to be stored and incremented in a centralized place so that concurrent transactions cannot possibly get the same value.
+
+### 3.4. Define only some tables to require unique IDs
+
+Maybe it is acceptable only for some tables to have a globally unique IDs. It could be Projects, Groups and other top-level entities.
+All other tables like `merge_requests` would only offer a Cell-local ID, but when referenced outside it would rather use an IID (an ID that is monotonic in context of a given resource, like a Project).
+
+- This makes the ID 10000 for `merge_requests` be present on all Cells, which might be sometimes confusing regarding the uniqueness of the resource.
+- This might make random access by ID (if ever needed) impossible without using a composite key, like: `project_id+merge_request_id`.
+- This would require us to implement a transformation/generation of new ID if we need to migrate records to another Cell. This can lead to very difficult migration processes when these IDs are also used as foreign keys for other records being migrated.
+- If IDs need to change when moving between Cells this means that any links to records by ID would no longer work even if those links included the `project_id`.
+- If we plan to allow these IDs to not be unique and change the unique constraint to be based on a composite key then we'd need to update all foreign key references to be based on the composite key.
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/explore.md b/doc/architecture/blueprints/cells/impacted_features/explore.md
new file mode 100644
index 00000000000..f839ce4be34
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/explore.md
@@ -0,0 +1,71 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Explore'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Explore
+
+Explore may not play a critical role in GitLab as it functions today, but GitLab today is not isolated. It is the isolation that makes Explore or some viable replacement necessary.
+
+The existing Group and Project Explore will initially be scoped to an Organization. However, there is a need for a global Explore that spans across Organizations to support the discoverability of public Groups and Projects, in particular in the context of discovering open source Projects. See user feedback [here](https://gitlab.com/gitlab-org/gitlab/-/issues/21582#note_1458298192) and [here](https://gitlab.com/gitlab-org/gitlab/-/issues/418228#note_1470045468).
+
+## 1. Definition
+
+The Explore functionality helps users in discovering Groups and Projects. Unauthenticated Users are only able to explore public Groups and Projects, authenticated Users can see all the Groups and Projects that they have access to, including private and internal Groups and Projects.
+
+## 2. Data flow
+
+## 3. Proposal
+
+The Explore feature problem falls under the broader umbrella of solving inter-Cell communication. [This topic warrants deeper research](../index.md#can-different-cells-communicate-with-each-other).
+
+Below are possible directions for further investigation.
+
+### 3.1. Read only table mirror
+
+- Create a `shared_projects` table in the shared cluster-wide database.
+- The model for this table is read-only. No inserts/updates/deletes are allowed.
+- The table is filled with data (or a subset of data) from the Projects Cell-local table.
+ - The write model Project (which is Cell-local) writes to the local database. We will primarily use this model for anything Cell-local.
+ - This data is synchronized with `shared_projects` via a background job any time something changes.
+ - The data in `shared_projects` is stored normalized, so that all the information necessary to display the Project Explore is there.
+- The Project Explore (as of today) is part of an instance-wide functionality, since it's not namespaced to any organizations/groups.
+ - This section will read data using the read model for `shared_projects`.
+- Once the user clicks on a Project, they are redirected to the Cell containing the Organization.
+
+Downsides:
+
+- Need to have an explicit pattern to access instance-wide data. This however may be useful for admin functionalities too.
+- The Project Explore may not be as rich in features as it is today (various filtering options, role you have on that Project, etc.).
+- Extra complexity in managing CQRS.
+
+### 3.2 Explore scoped to an Organization
+
+The Project Explore and Group Explore are scoped to an Organization.
+
+Downsides:
+
+- No global discoverability of Groups and Projects.
+
+## 4. Evaluation
+
+The existing Group and Project Explore will initially be scoped to an Organization. Considering the [current usage of the Explore feature](https://gitlab.com/gitlab-data/product-analytics/-/issues/1302#note_1491215521), we deem this acceptable. Since all existing Users, Groups and Projects will initially be part of the default Organization, Groups and Projects will remain explorable and accessible as they are today. Only once existing Groups and Projects are moved out of the default Organization into different Organizations will this become a noticeable problem. Solutions to mitigate this are discussed in [issue #418228](https://gitlab.com/gitlab-org/gitlab/-/issues/418228). Ultimately, Explore could be replaced with a better search experience altogether.
+
+## 4.1. Pros
+
+- Initially the lack of discoverability will not be a problem.
+- Only around [1.5% of all exisiting Users are using the Explore functionality on a monthly basis](https://gitlab.com/gitlab-data/product-analytics/-/issues/1302#note_1491215521).
+
+## 4.2. Cons
+
+- The GitLab owned top-level Groups would be some of the first to be moved into their own Organization and thus be detached from the explorability of the default Organization.
diff --git a/doc/architecture/blueprints/cells/impacted_features/git-access.md b/doc/architecture/blueprints/cells/impacted_features/git-access.md
new file mode 100644
index 00000000000..611b4db5f43
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/git-access.md
@@ -0,0 +1,156 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Git Access'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Git Access
+
+This document describes impact of Cells architecture on all Git access (over HTTPS and SSH) patterns providing explanation of how potentially those features should be changed to work well with Cells.
+
+## 1. Definition
+
+Git access is done throughout the application.
+It can be an operation performed by the system (read Git repository) or by a user (create a new file via Web IDE, `git clone` or `git push` via command line).
+The Cells architecture defines that all Git repositories will be local to the Cell, so no repository could be shared with another Cell.
+
+The Cells architecture will require that any Git operation can only be handled by a Cell holding the data.
+It means that any operation either via Web interface, API, or GraphQL needs to be routed to the correct Cell.
+It means that any `git clone` or `git push` operation can only be performed in the context of a Cell.
+
+## 2. Data flow
+
+The are various operations performed today by GitLab on a Git repository.
+This describes the data flow how they behave today to better represent the impact.
+
+It appears that Git access does require changes only to a few endpoints that are scoped to a Project.
+There appear to be different types of repositories:
+
+- Project: assigned to Group
+- Wiki: additional repository assigned to Project
+- Design: similar to Wiki, additional repository assigned to Project
+- Snippet: creates a virtual Project to hold repository, likely tied to the User
+
+### 2.1. Git clone over HTTPS
+
+Execution of: `git clone` over HTTPS
+
+```mermaid
+sequenceDiagram
+ User ->> Workhorse: GET /gitlab-org/gitlab.git/info/refs?service=git-upload-pack
+ Workhorse ->> Rails: GET /gitlab-org/gitlab.git/info/refs?service=git-upload-pack
+ Rails ->> Workhorse: 200 OK
+ Workhorse ->> Gitaly: RPC InfoRefsUploadPack
+ Gitaly ->> User: Response
+ User ->> Workhorse: POST /gitlab-org/gitlab.git/git-upload-pack
+ Workhorse ->> Gitaly: RPC PostUploadPackWithSidechannel
+ Gitaly ->> User: Response
+```
+
+### 2.2. Git clone over SSH
+
+Execution of: `git clone` over SSH
+
+```mermaid
+sequenceDiagram
+ User ->> Git SSHD: ssh git@gitlab.com
+ Git SSHD ->> Rails: GET /api/v4/internal/authorized_keys
+ Rails ->> Git SSHD: 200 OK (list of accepted SSH keys)
+ Git SSHD ->> User: Accept SSH
+ User ->> Git SSHD: git clone over SSH
+ Git SSHD ->> Rails: POST /api/v4/internal/allowed?project=/gitlab-org/gitlab.git&service=git-upload-pack
+ Rails ->> Git SSHD: 200 OK
+ Git SSHD ->> Gitaly: RPC SSHUploadPackWithSidechannel
+ Gitaly ->> User: Response
+```
+
+### 2.3. Git push over HTTPS
+
+Execution of: `git push` over HTTPS
+
+```mermaid
+sequenceDiagram
+ User ->> Workhorse: GET /gitlab-org/gitlab.git/info/refs?service=git-receive-pack
+ Workhorse ->> Rails: GET /gitlab-org/gitlab.git/info/refs?service=git-receive-pack
+ Rails ->> Workhorse: 200 OK
+ Workhorse ->> Gitaly: RPC PostReceivePack
+ Gitaly ->> Rails: POST /api/v4/internal/allowed?gl_repository=project-111&service=git-receive-pack
+ Gitaly ->> Rails: POST /api/v4/internal/pre_receive?gl_repository=project-111
+ Gitaly ->> Rails: POST /api/v4/internal/post_receive?gl_repository=project-111
+ Gitaly ->> User: Response
+```
+
+### 2.4. Git push over SSHD
+
+Execution of: `git clone` over SSH
+
+```mermaid
+sequenceDiagram
+ User ->> Git SSHD: ssh git@gitlab.com
+ Git SSHD ->> Rails: GET /api/v4/internal/authorized_keys
+ Rails ->> Git SSHD: 200 OK (list of accepted SSH keys)
+ Git SSHD ->> User: Accept SSH
+ User ->> Git SSHD: git clone over SSH
+ Git SSHD ->> Rails: POST /api/v4/internal/allowed?project=/gitlab-org/gitlab.git&service=git-receive-pack
+ Rails ->> Git SSHD: 200 OK
+ Git SSHD ->> Gitaly: RPC ReceivePack
+ Gitaly ->> Rails: POST /api/v4/internal/allowed?gl_repository=project-111
+ Gitaly ->> Rails: POST /api/v4/internal/pre_receive?gl_repository=project-111
+ Gitaly ->> Rails: POST /api/v4/internal/post_receive?gl_repository=project-111
+ Gitaly ->> User: Response
+```
+
+### 2.5. Create commit via Web
+
+Execution of `Add CHANGELOG` to repository:
+
+```mermaid
+sequenceDiagram
+ Web ->> Puma: POST /gitlab-org/gitlab/-/create/main
+ Puma ->> Gitaly: RPC TreeEntry
+ Gitaly ->> Rails: POST /api/v4/internal/allowed?gl_repository=project-111
+ Gitaly ->> Rails: POST /api/v4/internal/pre_receive?gl_repository=project-111
+ Gitaly ->> Rails: POST /api/v4/internal/post_receive?gl_repository=project-111
+ Gitaly ->> Puma: Response
+ Puma ->> Web: See CHANGELOG
+```
+
+## 3. Proposal
+
+The Cells stateless router proposal requires that any ambiguous path (that is not routable) will be made routable.
+It means that at least the following paths will have to be updated to introduce a routable entity (Project, Group, or Organization).
+
+Change:
+
+- `/api/v4/internal/allowed` => `/api/v4/internal/projects/<gl_repository>/allowed`
+- `/api/v4/internal/pre_receive` => `/api/v4/internal/projects/<gl_repository>/pre_receive`
+- `/api/v4/internal/post_receive` => `/api/v4/internal/projects/<gl_repository>/post_receive`
+- `/api/v4/internal/lfs_authenticate` => `/api/v4/internal/projects/<gl_repository>/lfs_authenticate`
+
+Where:
+
+- `gl_repository` can be `project-1111` (`Gitlab::GlRepository`)
+- `gl_repository` in some cases might be a full path to repository as executed by GitLab Shell (`/gitlab-org/gitlab.git`)
+
+## 4. Evaluation
+
+Supporting Git repositories if a Cell can access only its own repositories does not appear to be complex.
+The one major complication is supporting snippets, but this likely falls in the same category as for the approach to support a user's Personal Namespace.
+
+## 4.1. Pros
+
+1. The API used for supporting HTTPS/SSH and Hooks are well defined and can easily be made routable.
+
+## 4.2. Cons
+
+1. The sharing of repositories objects is limited to the given Cell and Gitaly node.
+1. Cross-Cells forks are likely impossible to be supported (discover: How this works today across different Gitaly node).
diff --git a/doc/architecture/blueprints/cells/impacted_features/gitlab-pages.md b/doc/architecture/blueprints/cells/impacted_features/gitlab-pages.md
new file mode 100644
index 00000000000..7e4ab785095
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/gitlab-pages.md
@@ -0,0 +1,30 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: GitLab Pages'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: GitLab Pages
+
+> TL;DR
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/global-search.md b/doc/architecture/blueprints/cells/impacted_features/global-search.md
new file mode 100644
index 00000000000..475db381ff5
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/global-search.md
@@ -0,0 +1,35 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Global search'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Global search
+
+When we introduce multiple Cells we intend to isolate all services related to those Cells.
+This will include Elasticsearch which means our current global search functionality will not work.
+It may be possible to implement aggregated search across all Cells, but it is unlikely to be performant to do fan-out searches across all Cells especially once you start to do pagination which requires setting the correct offset and page number for each search.
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+Likely the first versions of Cells will not support global searches.
+Later, we may consider if building global searches to support popular use cases is worthwhile.
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/graphql.md b/doc/architecture/blueprints/cells/impacted_features/graphql.md
new file mode 100644
index 00000000000..e8850dfbee3
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/graphql.md
@@ -0,0 +1,81 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: GraphQL'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: GraphQL
+
+GitLab extensively uses GraphQL to perform efficient data query operations.
+GraphQL due to it's nature is not directly routable.
+The way GitLab uses it calls the `/api/graphql` endpoint, and only the query or mutation of the body request might define where the data can be accessed.
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+There are at least two main ways to implement GraphQL in a Cells architecture.
+
+### 3.1. GraphQL routable by endpoint
+
+Change `/api/graphql` to `/api/organization/<organization>/graphql`.
+
+- This breaks all existing usages of `/api/graphql` endpoint because the API URI is changed.
+
+### 3.2. GraphQL routable by body
+
+As part of router parse GraphQL body to find a routable entity, like `project`.
+
+- This still makes the GraphQL query be executed only in context of a given Cell and not allowing the data to be merged.
+
+```json
+# Good example
+{
+ project(fullPath:"gitlab-org/gitlab") {
+ id
+ description
+ }
+}
+
+# Bad example, since Merge Request is not routable
+{
+ mergeRequest(id: 1111) {
+ iid
+ description
+ }
+}
+```
+
+### 3.3. Merging GraphQL Proxy
+
+Implement as part of router GraphQL Proxy which can parse body and merge results from many Cells.
+
+- This might make pagination hard to achieve, or we might assume that we execute many queries of which results are merged across all Cells.
+
+```json
+{
+ project(fullPath:"gitlab-org/gitlab"){
+ id, description
+ }
+ group(fullPath:"gitlab-com") {
+ id, description
+ }
+}
+```
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/organizations.md b/doc/architecture/blueprints/cells/impacted_features/organizations.md
new file mode 100644
index 00000000000..9fc8241e852
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/organizations.md
@@ -0,0 +1,36 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Organizations'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Organizations
+
+One of the major designs of a Cells architecture is strong isolation between Groups.
+Organizations as described by the [Organization blueprint](../../organization/index.md) provides a way to have plausible UX for joining together many Groups that are isolated from the rest of the system.
+
+## 1. Definition
+
+Cells do require that all Groups and Projects of a single Organization can only be stored on a single Cell because a Cell can only access data that it holds locally and has very limited capabilities to read information from other Cells.
+
+Cells with Organizations do require strong isolation between Organizations.
+
+It will have significant implications on various user-facing features, like Todos, dropdowns allowing to select Projects, references to other issues or Projects, or any other social functions present at GitLab.
+Today those functions were able to reference anything in the whole system.
+With the introduction of Organizations this will be forbidden.
+
+This problem definition aims to answer effort and implications required to add strong isolation between Organizations to the system, including features affected and their data processing flow.
+The purpose is to ensure that our solution when implemented consistently avoids data leakage between Organizations residing on a single Cell.
+
+## 2. Proposal
+
+See the [Organization blueprint](../../organization/index.md).
diff --git a/doc/architecture/blueprints/cells/impacted_features/personal-access-tokens.md b/doc/architecture/blueprints/cells/impacted_features/personal-access-tokens.md
new file mode 100644
index 00000000000..3aca9f1e116
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/personal-access-tokens.md
@@ -0,0 +1,31 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Personal Access Tokens'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Personal Access Tokens
+
+## 1. Definition
+
+Personal Access Tokens associated with a User are a way for Users to interact with the API of GitLab to perform operations.
+Personal Access Tokens today are scoped to the User, and can access all Groups that a User has access to.
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/personal-namespaces.md b/doc/architecture/blueprints/cells/impacted_features/personal-namespaces.md
new file mode 100644
index 00000000000..55d974bb351
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/personal-namespaces.md
@@ -0,0 +1,71 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Personal Namespaces'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the Cells design.
+Significant aspects are not documented, though we expect to add them in the future.
+This is one possible architecture for Cells, and we intend to contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that we can document the reasons for not choosing this approach.
+
+# Cells: Personal Namespaces
+
+Personal Namespaces do not easily fit with our overall architecture in Cells because the Cells architecture depends on all data belonging to a single Organization.
+When Users are allowed to work across multiple Organizations there is no natural fit for picking a single Organization to store personal Namespaces and their Projects.
+
+One important engineering constraint in Cells will be that data belonging to some Organization should not be linked to data belonging to another Organization.
+And specifically that functionality in GitLab can be scoped to a single Organization at a time.
+This presents a challenge for personal Namespaces as forking is one of the important workloads for personal Namespaces.
+Functionality related to forking and the UI that presents forked MRs to users will often require data from both the downstream and upstream Projects at the same time.
+Implementing such functionality would be very difficult if that data belonged in different Organizations stored on different
+Cells.
+This is especially the case with the merge request, as it is one of the most complicated and performance critical features in GitLab.
+
+Today personal Namespaces serve two purposes that are mostly non-overlapping:
+
+1. They provide a place for users to create personal Projects
+ that aren't expected to receive contributions from other people. This use case saves them from having to create a Group just for themselves.
+1. They provide a default place for a user to put any forks they
+ create when contributing to Projects where they don't have permission to push a branch. This again saves them from needing to create a Group just to store these forks. But the primary user need here is because they can't push branches to the upstream Project so they create a fork and contribute merge requests from the fork.
+
+## 1. Definition
+
+A [personal Namespace](../../../../user/namespace/index.md#types-of-namespaces) is based on a username and provided when a user creates an account.
+Users can create [personal Projects](../../../../user/project/working_with_projects.md#view-personal-projects) under their personal Namespace.
+
+## 2. Data flow
+
+## 3. Proposal
+
+As described above, personal Namespaces serve two purposes today:
+
+1. A place for users to store their Projects to save them from creating a Group.
+1. A place for users to store forks when they want to contribute to a Project where they don't have permission to push a branch.
+
+In this proposal we will only focus on (1) and assume that (2) will be replaced by suitable workflows described in [Cells: Contributions: Forks](../impacted_features/contributions-forks.md).
+
+Since we plan to move away from using personal Namespaces as a home for storing forks, we can assume that the main remaining use case does not need to support cross-Organization linking.
+In this case the easiest thing to do is to keep all personal Namespaces in the default Organization.
+Depending on the amount of workloads happening in personal Namespaces we may be required in the future to migrate them to different Cells.
+This may necessitate that they all get moved to some Organization created just for the user.
+If we go this route, there may be breakage similar to what will happen to when we move Groups or Projects into their own Organization, though the full impact may need further investigation.
+
+This decision, however, means that existing personal Namespaces that were used as forks to contribute to some upstream Project will become disconnected from the upstream as soon as the upstream moves into an Organization.
+On GitLab.com 10% of all projects in personal Namespaces are forks.
+This may be a slightly disruptive workflow but as long as the forks are mainly just storing branches used in merge requests then it may be reasonable to ask the affected users to recreate the fork in the context of the Organization.
+
+For existing Users, we suggest to keep their existing personal Namespaces in the default Organization.
+New Users joining an Organization other than the default Organization will also have their personal Namespace hosted on the default Organization. Having all personal Namespaces in the default Organization means we don't need to worry about deletion of the parent organization and the impact of that on personal Namespaces, which would be the case if they existed in other organizations.
+This implies that all Users will have an association to the default Organization via their personal Namespace, requiring them to switch to the default Organization to access their personal Namespace.
+
+We will further explore the idea of a `contribution space` to give Users a place to store forks when they want to contribute to a Project where they don't have permission to push a branch.
+That discussion will be handled as part of the larger discussion of the [Cells impact on forks](../impacted_features/contributions-forks.md).
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/router-endpoints-classification.md b/doc/architecture/blueprints/cells/impacted_features/router-endpoints-classification.md
new file mode 100644
index 00000000000..d403d6ff963
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/router-endpoints-classification.md
@@ -0,0 +1,34 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Router Endpoints Classification'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Router Endpoints Classification
+
+Classification of all endpoints is essential to properly route requests hitting the load balancer of a GitLab installation to a Cell that can serve it.
+Each Cell should be able to decode each request and classify which Cell it belongs to.
+
+GitLab currently implements hundreds of endpoints.
+This document tries to describe various techniques that can be implemented to allow the Rails to provide this information efficiently.
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/schema-changes.md b/doc/architecture/blueprints/cells/impacted_features/schema-changes.md
new file mode 100644
index 00000000000..0d6ca4717d3
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/schema-changes.md
@@ -0,0 +1,38 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Schema changes'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Schema changes
+
+When we introduce multiple Cells that own their own databases this will complicate the process of making schema changes to Postgres and Elasticsearch.
+Today we already need to be careful to make changes comply with our zero downtime deployments.
+For example, [when removing a column we need to make changes over 3 separate deployments](../../../../development/database/avoiding_downtime_in_migrations.md#dropping-columns).
+We have tooling like `post_migrate` that helps with these kinds of changes to reduce the number of merge requests needed, but these will be complicated when we are dealing with deploying multiple Rails applications that will be at different versions at any one time.
+This problem will be particularly tricky to solve for shared databases like our plan to share the `users` related tables among all Cells.
+
+A key benefit of Cells may be that it allows us to run different customers on different versions of GitLab.
+We may choose to update our own Cell before all our customers giving us even more flexibility than our current canary architecture.
+But doing this means that schema changes need to have even more versions of backward compatibility support which could slow down development as we need extra steps to make schema changes.
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/secrets.md b/doc/architecture/blueprints/cells/impacted_features/secrets.md
new file mode 100644
index 00000000000..681c229711d
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/secrets.md
@@ -0,0 +1,43 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Secrets'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Secrets
+
+Where possible, each Cell should have its own distinct set of secrets.
+However, there will be some secrets that will be required to be the same for all Cells in the cluster.
+
+## 1. Definition
+
+GitLab has a lot of [secrets](https://docs.gitlab.com/charts/installation/secrets.html) that need to be configured.
+Some secrets are for inter-component communication, for example, `GitLab Shell secret`, and used only within a Cell.
+Some secrets are used for features, for example, `ci_jwt_signing_key`.
+
+## 2. Data flow
+
+## 3. Proposal
+
+1. Secrets used for features will need to be consistent across all Cells, so that the UX is consistent.
+ 1. This is especially true for the `db_key_base` secret which is used for
+ encrypting data at rest in the database - so that Projects that are
+ transferred to another Cell will continue to work. We do not want to have
+ to re-encrypt such rows when we move Projects/Groups between Cells.
+1. Secrets which are used for intra-Cell communication only should be uniquely generated
+ per Cell.
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/snippets.md b/doc/architecture/blueprints/cells/impacted_features/snippets.md
new file mode 100644
index 00000000000..f77879907df
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/snippets.md
@@ -0,0 +1,56 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Snippets'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Snippets
+
+Snippets will be scoped to an Organization. Initially it will not be possible to aggregate snippet collections across Organizations. See also [issue #416954](https://gitlab.com/gitlab-org/gitlab/-/issues/416954).
+
+## 1. Definition
+
+Two different types of snippets exist:
+
+- [Project snippets](../../../../api/project_snippets.md). These snippets have URLs
+ like `/<group>/<project>/-/snippets/123`
+- [Personal snippets](../../../../user/snippets.md). These snippets have URLs like
+ `/-/snippets/123`
+
+Snippets are backed by a Git repository.
+
+## 2. Data flow
+
+## 3. Proposal
+
+### 3.1. Scoped to an organization
+
+Both project and personal snippets will be scoped to an Organization.
+
+- Project snippets URLs will remain unchanged, as the URLs are routable.
+- Personal snippets URLs will need to change to be `/-/organizations/<organization>/snippets/123`,
+ so that the URL is routeable
+
+Creation of snippets will also be scoped to a User's current Organization. Because of that, we recommend renaming `personal snippets` to `organization snippets` once the Organization is rolled out. A User can create many independent snippet collections across multiple Organizations.
+
+## 4. Evaluation
+
+Snippets are scoped to an Organization because Gitaly is confined to a Cell.
+
+## 4.1. Pros
+
+- No need to have clusterwide Gitaly.
+
+## 4.2. Cons
+
+- We will break [snippet discovery](/ee/user/snippets.md#discover-snippets).
+- Snippet access may become subordinate to the visibility of the Organization.
diff --git a/doc/architecture/blueprints/cells/impacted_features/template.md b/doc/architecture/blueprints/cells/impacted_features/template.md
new file mode 100644
index 00000000000..3cece3dc99e
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/template.md
@@ -0,0 +1,30 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Problem A'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: A
+
+> TL;DR
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/uploads.md b/doc/architecture/blueprints/cells/impacted_features/uploads.md
new file mode 100644
index 00000000000..fdac3a9977c
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/uploads.md
@@ -0,0 +1,30 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Uploads'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Uploads
+
+> TL;DR
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/cells/impacted_features/user-profile.md b/doc/architecture/blueprints/cells/impacted_features/user-profile.md
new file mode 100644
index 00000000000..fac8552e6d6
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/user-profile.md
@@ -0,0 +1,53 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: User Profile'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: User Profile
+
+The existing User Profiles will initially be scoped to an Organization. Long-term, we should consider aggregating parts of the User activity across Organizations to enable Users a global view of their contributions.
+
+## 1. Definition
+
+Each GitLab account has a [User Profile](../../../../user/profile/index.md), which contains information about the User and their GitLab activity.
+
+## 2. Data flow
+
+## 3. Proposal
+
+User Profiles will be scoped to an Organization. We follow the same pattern as is used for `Your Work`, meaning that profiles are always seen in the context of an Organization.
+
+- User Profile URLs will reference the Organization with the following URL structure `/-/organizations/<organization>/username`.
+- Users can set a Home Organization as their main Organization.
+- The default User Profile URL `/<username>` will refer to the user's Home Organization, or the default Organization if the user's Home Organization is not set.
+- Users who do not exist in the database at all display a 404 not found error when trying to access their User Profile.
+- User who haven't contributed to an Organization display their User Profile with an empty state.
+- When displaying a User Profile empty state, if the profile has a Home Organization set to another Organization, we display a call-to-action allowing navigation to the main Organization.
+- Breadcrumbs on the User Profile will present as `[Organization Name] / [Username]`.
+
+See [issue #411931](https://gitlab.com/gitlab-org/gitlab/-/issues/411931) for design proposals.
+
+## 4. Evaluation
+
+We expect the [majority of Users to perform most of their activity in one single Organization](../../organization/index.md#data-exploration).
+This is why we deem it acceptable to scope the User Profile to an Organization at first.
+More discovery is necessary to understand which aspects of the current User Profile are relevant to showcase contributions in a global context.
+
+## 4.1. Pros
+
+- Viewing a User Profile scoped to an Organization allows you to focus on contributions that are most relevant to your Organization, filtering out the User's other activities.
+- Existing User Profile URLs do not break.
+
+## 4.2. Cons
+
+- Users will lose the ability to display their entire activity, which may lessen the effectiveness of using their User Profile as a resume of achievements when working across multiple Organizations.
diff --git a/doc/architecture/blueprints/cells/impacted_features/your-work.md b/doc/architecture/blueprints/cells/impacted_features/your-work.md
new file mode 100644
index 00000000000..5a72d50fbea
--- /dev/null
+++ b/doc/architecture/blueprints/cells/impacted_features/your-work.md
@@ -0,0 +1,60 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Cells: Your Work'
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+
+This document is a work-in-progress and represents a very early state of the
+Cells design. Significant aspects are not documented, though we expect to add
+them in the future. This is one possible architecture for Cells, and we intend to
+contrast this with alternatives before deciding which approach to implement.
+This documentation will be kept even if we decide not to implement this so that
+we can document the reasons for not choosing this approach.
+
+# Cells: Your Work
+
+Your Work will be scoped to an Organization.
+Counts presented in the individual dashboards will relate to the selected Organization.
+
+## 1. Definition
+
+When accessing `gitlab.com/dashboard/`, users can find a [focused view of items that they have access to](../../../../tutorials/left_sidebar/index.md#use-a-more-focused-view).
+This overview contains dashboards relating to:
+
+- Projects
+- Groups
+- Issues
+- Merge requests
+- To-Do list
+- Milestones
+- Snippets
+- Activity
+- Workspaces
+- Environments
+- Operations
+- Security
+
+## 2. Data flow
+
+## 3. Proposal
+
+Your Work will be scoped to an Organization, giving the user an overview of all the items they can access in the Organization they are currently viewing.
+
+- Issue, Merge request and To-Do list counts will refer to the selected Organization.
+- The URL will reference the Organization with the following URL structure `/-/organizations/<organization>/dashboard`.
+- The default URL `/dashboard` will refer to the [Home Organization](../impacted_features/user-profile.md#3-proposal).
+
+## 4. Evaluation
+
+Scoping Your Work to an Organization makes sense in the context of the [proposed Organization navigation](https://gitlab.com/gitlab-org/gitlab/-/issues/417778).
+Considering that [we expect most users to work in a single Organization](../../organization/index.md#data-exploration), we deem this impact acceptable.
+
+## 4.1. Pros
+
+- Viewing Your Work scoped to an Organization allows Users to focus on content that is most relevant to their currently selected Organization.
+
+## 4.2. Cons
+
+- Users working across multiple Organizations will have to navigate to each Organization to access all of their work items.
diff --git a/doc/architecture/blueprints/cells/index.md b/doc/architecture/blueprints/cells/index.md
index 0e93b9d5d3b..28414f9b68c 100644
--- a/doc/architecture/blueprints/cells/index.md
+++ b/doc/architecture/blueprints/cells/index.md
@@ -1,5 +1,5 @@
---
-status: accepted
+status: ongoing
creation-date: "2022-09-07"
authors: [ "@ayufan", "@fzimmer", "@DylanGriffith", "@lohrc", "@tkuah" ]
coach: "@ayufan"
@@ -18,9 +18,7 @@ Cells is a new architecture for our software as a service platform. This archite
For more information about Cells, see also:
-- [Glossary](glossary.md)
-- [Goals](goals.md)
-- [Cross-section impact](impact.md)
+- [Goals, Glossary and Requirements](goals.md)
## Work streams
@@ -101,6 +99,10 @@ The first 2-3 quarters are required to define a general split of data and build
The purpose is to perform a targeted decomposition of `users` and `projects`, because `projects` will be stored locally in the Cell.
+1. **User can create Organization on Cell 2.**
+
+ The purpose is to create Organizations that are isolated from each other.
+
1. **User can change profile avatar that is shared in cluster.**
The purpose is to fix global uploads that are shared in cluster.
@@ -166,6 +168,11 @@ For example:
The routing service needs to be able to discover and monitor the health of all Cells.
+1. **User can use single domain to interact with many Cells.**
+
+ The routing service will intelligently route all requests to Cells based on the resource being
+ accessed versus the Cell containing the data.
+
1. **Router endpoints classification.**
The stateless routing service will fetch and cache information about endpoints from one of the Cells.
@@ -258,28 +265,30 @@ One iteration describes one quarter's worth of work.
- Data access layer: Initial Admin Area settings are shared across cluster.
- Essential workflows: Allow to share cluster-wide data with database-level data access layer
-1. [Iteration 2](https://gitlab.com/groups/gitlab-org/-/epics/9813) - FY24Q2 - In progress
+1. [Iteration 2](https://gitlab.com/groups/gitlab-org/-/epics/9813) - Expected delivery: 16.2 FY24Q2 | Actual delivery: 16.4 FY24Q3 - In progress
- Essential workflows: User accounts are shared across cluster.
- Essential workflows: User can create Group.
-1. [Iteration 3](https://gitlab.com/groups/gitlab-org/-/epics/10997) - FY24Q3 - Planned
+1. [Iteration 3](https://gitlab.com/groups/gitlab-org/-/epics/10997) - Expected delivery: 16.7 FY24Q4 - Planned
- Essential workflows: User can create Project.
- Routing: Technology.
- - Data access layer: Evaluate the efficiency of database-level access vs. API-oriented access layer
+ - Routing: Cell discovery.
+ - Data access layer: Evaluate the efficiency of database-level access vs. API-oriented access layer.
+ - Data access layer: Data access layer.
-1. [Iteration 4](https://gitlab.com/groups/gitlab-org/-/epics/10998) - FY24Q4
+1. [Iteration 4](https://gitlab.com/groups/gitlab-org/-/epics/10998) - Expected delivery: 16.10 FY25Q1 - Planned
- - Essential workflows: User can push to Git repository.
- - Essential workflows: User can create issue, merge request, and merge it after it is green.
+ - Essential workflows: User can create organization on Cell 2.
- Data access layer: Cluster-unique identifiers.
- - Routing: Cell discovery.
- - Routing: Router endpoints classification.
- - Cell deployment: Extend GitLab Dedicated to support GCP
+ - Routing: User can use single domain to interact with many Cells.
+ - Cell deployment: Extend GitLab Dedicated to support GCP.
-1. Iteration 5 - FY25Q1
+1. Iteration 5..N - starting FY25Q1
+ - Essential workflows: User can push to Git repository.
+ - Essential workflows: User can create issue, merge request, and merge it after it is green.
- Essential workflows: User can run CI pipeline.
- Essential workflows: Instance-wide settings are shared across cluster.
- Essential workflows: User can change profile avatar that is shared in cluster.
@@ -287,22 +296,13 @@ One iteration describes one quarter's worth of work.
- Essential workflows: User can manage Group and Project members.
- Essential workflows: User can manage instance-wide runners.
- Essential workflows: User is part of Organization and can only see information from the Organization.
+ - Routing: Router endpoints classification.
- Routing: GraphQL and other ambiguous endpoints.
- Data access layer: Allow to share cluster-wide data with database-level data access layer.
- Data access layer: Cluster-wide deletions.
- - Data access layer: Data access layer.
- Data access layer: Database migrations.
-1. Iteration 6 - FY25Q2
- - TBD
-
-1. Iteration 7 - FY25Q3
- - TBD
-
-1. Iteration 8 - FY25Q4
- - TBD
-
-## Technical Proposals
+## Technical proposals
The Cells architecture has long lasting implications to data processing, location, scalability and the GitLab architecture.
This section links all different technical proposals that are being evaluated.
@@ -315,34 +315,36 @@ This section links all different technical proposals that are being evaluated.
The Cells architecture will impact many features requiring some of them to be rewritten, or changed significantly.
Below is a list of known affected features with preliminary proposed solutions.
-- [Cells: Admin Area](cells-feature-admin-area.md)
-- [Cells: Backups](cells-feature-backups.md)
-- [Cells: CI Runners](cells-feature-ci-runners.md)
-- [Cells: Container Registry](cells-feature-container-registry.md)
-- [Cells: Contributions: Forks](cells-feature-contributions-forks.md)
-- [Cells: Database Sequences](cells-feature-database-sequences.md)
-- [Cells: Data Migration](cells-feature-data-migration.md)
-- [Cells: Explore](cells-feature-explore.md)
-- [Cells: Git Access](cells-feature-git-access.md)
-- [Cells: Global Search](cells-feature-global-search.md)
-- [Cells: GraphQL](cells-feature-graphql.md)
-- [Cells: Organizations](cells-feature-organizations.md)
-- [Cells: Secrets](cells-feature-secrets.md)
-- [Cells: Snippets](cells-feature-snippets.md)
-- [Cells: User Profile](cells-feature-user-profile.md)
-- [Cells: Your Work](cells-feature-your-work.md)
+- [Cells: Admin Area](impacted_features/admin-area.md)
+- [Cells: Backups](impacted_features/backups.md)
+- [Cells: CI Runners](impacted_features/ci-runners.md)
+- [Cells: Container Registry](impacted_features/container-registry.md)
+- [Cells: Contributions: Forks](impacted_features/contributions-forks.md)
+- [Cells: Database Sequences](impacted_features/database-sequences.md)
+- [Cells: Data Migration](impacted_features/data-migration.md)
+- [Cells: Explore](impacted_features/explore.md)
+- [Cells: Git Access](impacted_features/git-access.md)
+- [Cells: Global Search](impacted_features/global-search.md)
+- [Cells: GraphQL](impacted_features/graphql.md)
+- [Cells: Organizations](impacted_features/organizations.md)
+- [Cells: Personal Namespaces](impacted_features/personal-namespaces.md)
+- [Cells: Secrets](impacted_features/secrets.md)
+- [Cells: Snippets](impacted_features/snippets.md)
+- [Cells: User Profile](impacted_features/user-profile.md)
+- [Cells: Your Work](impacted_features/your-work.md)
### Impacted features: Placeholders
The following list of impacted features only represents placeholders that still require work to estimate the impact of Cells and develop solution proposals.
-- [Cells: Agent for Kubernetes](cells-feature-agent-for-kubernetes.md)
-- [Cells: GitLab Pages](cells-feature-gitlab-pages.md)
-- [Cells: Personal Access Tokens](cells-feature-personal-access-tokens.md)
-- [Cells: Personal Namespaces](cells-feature-personal-namespaces.md)
-- [Cells: Router Endpoints Classification](cells-feature-router-endpoints-classification.md)
-- [Cells: Schema changes (Postgres and Elasticsearch migrations)](cells-feature-schema-changes.md)
-- [Cells: Uploads](cells-feature-uploads.md)
+- [Cells: Agent for Kubernetes](impacted_features/agent-for-kubernetes.md)
+- [Cells: CI/CD Catalog](impacted_features/ci-cd-catalog.md)
+- [Cells: Data pipeline ingestion](impacted_features/data-pipeline-ingestion.md)
+- [Cells: GitLab Pages](impacted_features/gitlab-pages.md)
+- [Cells: Personal Access Tokens](impacted_features/personal-access-tokens.md)
+- [Cells: Router Endpoints Classification](impacted_features/router-endpoints-classification.md)
+- [Cells: Schema changes (Postgres and Elasticsearch migrations)](impacted_features/schema-changes.md)
+- [Cells: Uploads](impacted_features/uploads.md)
- ...
## Frequently Asked Questions
@@ -367,6 +369,59 @@ For example, users on GitLab Dedicated don't have to have a different and unique
Up until iteration 3, Cells communicate with each other only via a shared database that contains common data.
In iteration 4 we are going to evaluate the option of Cells calling each other via API to provide more isolation and reliability.
+### How are Cells provisioned?
+
+The GitLab.com cluster of Cells will use GitLab Dedicated instances.
+Once a GitLab Dedicated instance gets provisioned it could join the GitLab.com cluster and become a Cell.
+One requirement will be that the GitLab Dedicated instance does not contain any prior data.
+
+To reach shared resources, Cells will use [Private Service Connect](https://cloud.google.com/vpc/docs/private-service-connect).
+
+See also the [design discussion](https://gitlab.com/gitlab-org/gitlab/-/issues/396641).
+
+### What is a Cells topology?
+
+See the [design discussion](https://gitlab.com/gitlab-org/gitlab/-/issues/396641).
+
+### How are users of an Organization routed to the correct Cell?
+
+TBD
+
+### How do users authenticate with Cells and Organizations?
+
+See the [design discussion](https://gitlab.com/gitlab-org/gitlab/-/issues/395736).
+
+### How are Cells rebalanced?
+
+TBD
+
+### How can Cells implement disaster recovery capabilities?
+
+TBD
+
+### How do I decide whether to move my feature to the cluster, Cell or Organization level?
+
+By default, features are required to be scoped to the Organization level. Any deviation from that rule should be validated and approved by Tenant Scale.
+
+The design goals of the Cells architecture describe that [all Cells are under a single domain](goals.md#all-cells-are-under-a-single-gitlabcom-domain) and as such, Cells are invisible to the user:
+
+- Cell-local features should be limited to those related to managing the Cell, but never be a feature where the Cell semantic is exposed to the customer.
+- The Cells architecture wants to freely control the distribution of Organization and customer data across Cells without impacting users when data is migrated.
+
+Cluster-wide features are strongly discouraged because:
+
+- They might require storing a substantial amount of data cluster-wide which decreases [scalability headroom](goals.md#provides-100x-headroom).
+- They might require implementation of non-trivial [data aggregation](goals.md#aggregation-of-cluster-wide-data) that reduces resilience to [single node failure](goals.md#high-resilience-to-a-single-cell-failure).
+- They are harder to build due to the need of being able to run [mixed deployments](goals.md#cells-running-in-mixed-deployments). Cluster-wide features need to take this into account.
+- They might affect our ability to provide an [on-premise like experience on GitLab.com](goals.md#on-premise-like-experience).
+- Some features that are expected to be cluster-wide might in fact be better implemented using federation techniques that use trusted intra-cluster communication using the same user identity. User Profile is shared across the cluster.
+- The Cells architecture limits what services can be considered cluster-wide. Services that might initially be cluster-wide are still expected to be split in the future to achieve full service isolation. No feature should be built to depend on such a service (like Elasticsearch).
+
+### Will Cells use the [reference architecture for 50,000 users](../../../administration/reference_architectures/50k_users.md)?
+
+The infrastructure team will properly size Cells depending on the load.
+The Tenant Scale team sees an opportunity to use GitLab Dedicated as a base for Cells deployment.
+
## Decision log
- 2022-03-15: Google Cloud as the cloud service. For details, see [issue 396641](https://gitlab.com/gitlab-org/gitlab/-/issues/396641#note_1314932272).
@@ -378,3 +433,4 @@ In iteration 4 we are going to evaluate the option of Cells calling each other v
- [Database group investigation](https://about.gitlab.com/handbook/engineering/development/enablement/data_stores/database/doc/root-namespace-sharding.html)
- [Shopify Pods architecture](https://shopify.engineering/a-pods-architecture-to-allow-shopify-to-scale)
- [Opstrace architecture](https://gitlab.com/gitlab-org/opstrace/opstrace/-/blob/main/docs/architecture/overview.md)
+- [Adding Diagrams to this blueprint](diagrams/index.md)
diff --git a/doc/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md b/doc/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md
index c1ca0c60dcd..847532a36dc 100644
--- a/doc/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md
+++ b/doc/architecture/blueprints/cells/proposal-stateless-router-with-buffering-requests.md
@@ -27,10 +27,10 @@ monolith. This architecture also supports regions by allowing for low traffic
databases to be replicated across regions.
Users are not directly exposed to the concept of Cells but instead they see
-different data dependent on their chosen "organization".
-[Organizations](glossary.md#organizations) will be a new model introduced to enforce isolation in the
-application and allow us to decide which request route to which cell, since an
-organization can only be on a single cell.
+different data dependent on their chosen Organization.
+[Organizations](goals.md#organizations) will be a new entity introduced to enforce isolation in the
+application and allow us to decide which request routes to which Cell, since an
+Organization can only be on a single Cell.
## Differences
diff --git a/doc/architecture/blueprints/cells/proposal-stateless-router-with-routes-learning.md b/doc/architecture/blueprints/cells/proposal-stateless-router-with-routes-learning.md
index 3b3d481914f..962f71673df 100644
--- a/doc/architecture/blueprints/cells/proposal-stateless-router-with-routes-learning.md
+++ b/doc/architecture/blueprints/cells/proposal-stateless-router-with-routes-learning.md
@@ -27,10 +27,10 @@ monolith. This architecture also supports regions by allowing for low traffic
databases to be replicated across regions.
Users are not directly exposed to the concept of Cells but instead they see
-different data dependent on their chosen "organization".
-[Organizations](glossary.md#organizations) will be a new model introduced to enforce isolation in the
-application and allow us to decide which request route to which cell, since an
-organization can only be on a single cell.
+different data dependent on their chosen Organization.
+[Organizations](goals.md#organizations) will be a new entity introduced to enforce isolation in the
+application and allow us to decide which request routes to which Cell, since an
+Organization can only be on a single Cell.
## Differences
diff --git a/doc/architecture/blueprints/code_search_with_zoekt/diagrams/sharding_proposal_2023-08.drawio.png b/doc/architecture/blueprints/code_search_with_zoekt/diagrams/sharding_proposal_2023-08.drawio.png
new file mode 100644
index 00000000000..c45745c9dd2
--- /dev/null
+++ b/doc/architecture/blueprints/code_search_with_zoekt/diagrams/sharding_proposal_2023-08.drawio.png
Binary files differ
diff --git a/doc/architecture/blueprints/code_search_with_zoekt/index.md b/doc/architecture/blueprints/code_search_with_zoekt/index.md
index 273d8da482c..5b34d84b47e 100644
--- a/doc/architecture/blueprints/code_search_with_zoekt/index.md
+++ b/doc/architecture/blueprints/code_search_with_zoekt/index.md
@@ -273,6 +273,57 @@ progress and reassess if it turns out to add too much complexity to GitLab.
This is already implemented as the `::Zoekt::IndexedNamespace`
implements a many-to-many relationship between namespaces and shards.
+#### Sharding proposal with self-registering Zoekt nodes
+
+This proposal is mostly inspired by GitLab Runner's architecture with the main difference
+that the communication is bidirectional. We've arrived to this after discussions in [Zoekt Sharding and Replication](https://gitlab.com/gitlab-org/gitlab/-/issues/419900).
+
+##### Alternatives we've considered
+
+We've considered different options for where to manage the Zoekt cluster state including Raft and Zoekt's own database. We decided that there are many benefits to having the whole cluster state managed by GitLab instead of Zoekt so we're opting to keep Zoekt nodes as naive as possible.
+
+The main benefits are:
+
+1. The deployment cycle for GitLab is faster than Zoekt which requires many version bumps across many projects
+1. GitLab already has lots tooling that can be used for managing the state that we are already familiar with including Postgres, Redis, Sidekiq and others
+1. The engineers mainly working on this project have much more experience with Rails than Go and spend more time writing Rails code than Go code as the other search features are mostly in Rails
+
+Some of those benefits could also be seen as downsides and maybe not the right choice for different projects owned by different teams.
+
+##### High level proposal
+
+<img src="diagrams/sharding_proposal_2023-08.drawio.png" height="600">
+
+1. Zoekt nodes are started with 3 additional arguments: its own address, shard name, and GitLab URL.
+1. We'd like to keep shard name separate so that one will be able to migrate a shard to a different address.
+1. When Zoekt is running in k8s, we can pass `hostname --fqdn` (for example, `gitlab-zoekt-1.gitlab-zoekt.default.svc.cluster.local`) as an argument for the address. Customers running Zoekt on bare-metal will need to configure it separately.
+1. Zoekt most likely will use [Internal API](../../../development/internal_api/index.md) to connect to GitLab. We might also want to use a separate GitLab URL to keep the traffic internal and to avoid extra traffic cost.
+1. GitLab will maintain a lookup table with `last_seen_at` and shard's name (we could expand `::Zoekt::Shard`). We'll also need to introduce the concept of replicas and primaries.
+1. Zoekt nodes (indexers in this case) will send periodic requests to get new jobs with its address and name to the configured GitLab URL. GitLab will either register a new node or update the existing record in the lookup table.
+1. After the job is completed, `zoekt-indexer` will send a callback to GitLab to indicate that the job has been completed.
+1. If after a specified time GitLab doesn't receive a request, it can reassign namespaces to different shards and mark the missing shard as unavailable.
+1. When executing searches, we can round-robin requests to primaries and replicas. We might even want to implement retries. For example, if a request to primary fails, we send another request to replica right away or vice versa. Here is a related issue: [Consider circuit breaker for Zoekt code search](https://gitlab.com/gitlab-org/gitlab/-/issues/393445).
+1. Initially, we might want to skip replication until we implement efficiently moving and copying index files between shards (rsync for example).
+1. Rebalancing most likely will happen in a cron Sidekiq worker, which will consider if an indexed namespace has enough replicas as well as available storage.
+
+An example of command we might consider running in k8s:
+
+```shell
+./gitlab-zoekt-indexer -index_dir=/data/index -shard_name=`hostname` -address=`hostname --fqdn`
+```
+
+When we add more replicas to the stateful set, it should automatically handle addresses and shard names. For example:
+
+- `gitlab-zoekt-0` / `gitlab-zoekt-0.gitlab-zoekt.default.svc.cluster.local`
+- `gitlab-zoekt-1` / `gitlab-zoekt-1.gitlab-zoekt.default.svc.cluster.local`
+- ..
+
+Possible jobs indexer can receive:
+
+- `index_repositories(ids: [1,2,3,4])`
+- `delete_repositories(ids: [5,6])`
+- `copy_index(from: 'gitlab-zoekt-0', to: 'gitlab-zoekt-1', repo_id: 4)`
+
#### Replication and service discovery using Consul
If we plan to replicate at the Zoekt node level as described above we need to
diff --git a/doc/architecture/blueprints/container_registry_metadata_database_self_managed_rollout/index.md b/doc/architecture/blueprints/container_registry_metadata_database_self_managed_rollout/index.md
index 0987b317af8..84a95e3e7c3 100644
--- a/doc/architecture/blueprints/container_registry_metadata_database_self_managed_rollout/index.md
+++ b/doc/architecture/blueprints/container_registry_metadata_database_self_managed_rollout/index.md
@@ -66,29 +66,46 @@ the setup and maintenance of the registry database for new and existing deploys.
For the registry, we need to develop and validate import tooling which
coordinates with the core import functionality which was used to migrate all
-container images on GitLab.com. Additionally, we must validate that each supported
-storage driver works as expected with the import process and provide estimated
-import times for admins.
-
-We can structure our work to meet the standards outlined in support for
-Experiment, Beta, and Alpha features. Doing so will help to prioritize core
-functionality and to allow users who wish to be early adopters to begin using
-the database and providing us with invaluable feedback.
-
-These levels of support could be advertised to self-managed users via a simple
-chart, allowing them to tell at a glance the status of this project as it relates
-to their situation.
-
-| Installation | GCS | AWS | Filesystem | Azure | OSS | Swift|
-| ------ | ------ |------ | ------ | ------ |------ | ------ |
-| Omnibus | GA | GA | Beta | Experimental | Experimental | Experimental |
-| Charts | GA | GA |Beta | Experimental | Experimental | Experimental |
-
-### Justification of Structuring Support by Driver
-
-It's possible that we could simplify the proposed support matrix by structuring
-it only by deployment environment and not differentiate by storage driver. The
-following two sections briefly summarize several points for and against.
+container images on GitLab.com. Additionally, we should provide estimated import
+times for admins for each supported storage driver.
+
+During the beta phase, we can highlight key features of our work to provide a
+quick reference for what features we have now, are planning, their statuses, and
+an excutive summary of the overall state of the migration experience.
+This could be advertised to self-managed users via a simple chart, allowing them
+to tell at a glance the status of this project and determine if it is feature-
+complete enough for their needs and level of risk tolerance.
+
+This should be documented in the container registry administration documentation,
+rather than in this blueprint. Providing this information there will place it in
+a familiar place for self-managed admins, will allow for logical cross-linking
+from other sections of the same document, such as from the garbage collection
+section.
+
+For example:
+
+The metadata database is in early beta for self-managed users. The core migration
+process for existing registries has been implemented, and online garbage collection
+is fully implemented. Certain database enabled features are only enabled for GitLab.com
+and automatic database provisioning for the registry database is not available.
+Please see the table below for the status of features related to the container
+registry database.
+
+| Feature | Description | Status | Link |
+| --------------------------- | ------------------------------------------------------------------- | ------------------ | ---------------------------------------------------------------------------------------------- |
+| Import Tool | Allows existing deployments to migrate to the database. | Completed | [Import Tool](https://gitlab.com/gitlab-org/container-registry/-/issues/884) |
+| Automatic Import Validation | Tests that the import maintained data integrity of imported images. | Backlog | [Validate self-managed imports](https://gitlab.com/gitlab-org/container-registry/-/issues/938) |
+| Foo Bar | Lorem ipsum dolor sit amet. | Scheduled for 16.5 | <LINK> |
+
+### Structuring Support by Driver
+
+The import operation heavily relies on the object storage driver implementation
+to iterate over all registry metadata so that it can be stored in the database.
+It's possible that implementation differences in the driver will make a
+meaningful impact on the performance and reliability of the import process.
+
+The following two sections briefly summarize several points for and against
+structuring support by driver.
#### Arguments Opposed to Structuring Support by Driver
diff --git a/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.png b/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.png
index 0475a32e933..ce6bb1a8dfc 100644
--- a/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.png
+++ b/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.png
Binary files differ
diff --git a/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md b/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md
index 89606cdc8fa..2bd121a34bb 100644
--- a/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md
+++ b/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md
@@ -96,8 +96,10 @@ to function flawlessly. The suggested approach considers Gitaly's specific
constraints and distinguishing features, including cgroup utilization and
upload-pack RPC, among others.
-The proposed solution does not aim to replace the existing [Gitaly concurrency
-limit][Gitlay-backpressure], but automatically tweak its parameters. This means
+The proposed solution does not aim to replace the existing limits in Gitaly
+for [RPC concurrency](../../../administration/gitaly/configure_gitaly.md#limit-rpc-concurrency)
+and [pack object concurrency](../../../administration/gitaly/configure_gitaly.md#limit-pack-objects-concurrency),
+but automatically tweak the parameters. This means
that other aspects, such as queuing, in-queue timeout, queue length,
partitioning, and scoping, will remain unchanged. The proposed solution only
focuses on modifying the current **value** of the concurrency limit.
diff --git a/doc/architecture/blueprints/gitaly_handle_upload_pack_in_http2_server/index.md b/doc/architecture/blueprints/gitaly_handle_upload_pack_in_http2_server/index.md
new file mode 100644
index 00000000000..acee83b2649
--- /dev/null
+++ b/doc/architecture/blueprints/gitaly_handle_upload_pack_in_http2_server/index.md
@@ -0,0 +1,310 @@
+---
+status: proposed
+creation-date: "2023-06-15"
+authors: [ "@qmnguyen0711" ]
+approvers: [ ]
+owning-stage: "~devops::enablement"
+---
+
+<!-- vale gitlab.FutureTense = NO -->
+# Gitaly - Handle upload-pack traffic in a pure HTTP/2 server
+
+## Summary
+
+All Git data transferring operations that use HTTP/SSH are handled by upload-pack RPCs in Gitaly.
+
+These RPCs use a unique application-layer protocol called Sidechannel, which takes over the handshaking process during client dialing of the Gitaly gRPC server. This
+protocol allows for an out-of-band connection to transfer large data back to the client while serving the gRPC connection as normal.
+
+Although it provides a huge performance improvement over using pure gRPC streaming calls, this protocol is unconventional, confusing, sophisticated, and hard to extend
+or integrate into the next architecture of Gitaly. To address this, a new "boring" tech solution is proposed in this blueprint, which involves exposing a new HTTP/2 server
+to handle all upload-pack traffic.
+
+## Motivation
+
+This section will explore how Git data transfers work, giving special attention to the role of Sidechannel optimization, and discussing both its advantages and
+disadvantages. Our main goal is to make Git data transfers simpler while maintaining the performance improvements that Sidechannel optimization has
+provided. We are looking for a solution that won't require us to completely rewrite the system and won't affect other parts of the systems and other RPCs.
+
+### How Git data transfer works
+
+Please skip this part if you are familiar with how Git data transfer architecture at GitLab.
+
+Git data transfer is undeniably one of the crucial services that a Git server can offer. It is a fundamental feature of Git that was originally developed for Linux
+kernel development. As Git gained popularity, it continued to be recognized as a distributed system. However, the emergence of centralized Git services like GitHub or
+GitLab resulted in a shift in usage patterns. Consequently, handling Git data transfer in hosted Git servers has become challenging.
+
+Git supports transferring data in [packfiles](https://git-scm.com/book/en/v2/Git-Internals-Packfiles) over multiple protocols, notably HTTP and SSH. For more information, see
+[pack-protocol](https://git-scm.com/docs/pack-protocol) and [http-protocol](https://git-scm.com/docs/http-protocol).
+
+In short, the general flow involves the following steps:
+
+1. Reference Discovery: the server advertises its refs to the client.
+1. Packfile negotiation: the client negotiates the packfile necessary for the transport with the server by sending the list of refs it "haves", "wants", etc.
+1. Transfer Packfile data: the server composes the requested data and sends it back to the client using Pack protocol.
+
+Further details and optimizations can underlie these steps. Git servers have never had issues with reference discovery and Packfile negotiation. The most demanding aspect
+of the process is the transfer of Packfile data, which is where the actual data exchange takes place.
+
+For GitLab, Gitaly manages all Git operations. However, it is not accessible to external sources because Workhorse and GitLab Shell handle all external communications.
+Gitaly offers a gRPC server for them through specific RPCs such as [SmartHTTP](https://gitlab.com/gitlab-org/gitaly/-/blob/master/proto/smarthttp.proto) and
+[SSH](https://gitlab.com/gitlab-org/gitaly/-/blob/master/proto/ssh.proto). In addition, it provides numerous other RPCs for GitLab Rails and other services. The following
+diagram illustrates a clone using SSH:
+
+```mermaid
+sequenceDiagram
+ participant User as User
+ participant UserGit as git fetch
+ participant SSHClient as User's SSH Client
+ participant SSHD as GitLab SSHD
+ participant GitLabShell as gitlab-shell
+ participant GitalyServer as Gitaly
+ participant GitalyGit as git upload-pack
+
+ User ->> UserGit: Runs git fetch
+ UserGit ->> SSHClient: Spawns SSH client
+ Note over User,SSHClient: On user's local machine
+
+ SSHClient ->> SSHD: SSH session
+ Note over SSHClient,SSHD: Session over Internet
+
+ SSHD ->> GitLabShell: spawns gitlab-shell
+ GitLabShell ->> GitalyServer: gRPC SSHUploadPack
+ GitalyServer ->> GitalyGit: spawns git upload-pack
+
+ Note over GitalyServer,GitalyGit: On Gitaly server
+ Note over SSHD,GitalyGit: On GitLab server
+```
+
+Source: shameless copy from [this doc](https://gitlab.com/gitlab-org/gitaly/-/blob/master/cmd/gitaly-ssh/README.md?plain=0)
+
+### Git data transfer optimization with Sidechannel
+
+In the past, we faced many performance problems when transferring huge amounts of data with gRPC. [Epic 463](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/463) tracks
+the work of this optimization. More context surrounds it but, in summary, there are two main problems:
+
+- The way gRPC is designed is ideal for transmitting a large number of messages that are relatively small in size. However, when it comes to cloning a medium-sized
+ repository, it can result in transferring gigabytes of data. Protobuf struggles when dealing with large data, as confirmed by various sources
+ (examples: <https://protobuf.dev/programming-guides/techniques/#large-data> and <https://github.com/protocolbuffers/protobuf/issues/7968>). It adds significant overhead
+ and requires substantial CPU usage during encoding and decoding. Additionally, protobuf cannot read or write messages partially, which causes memory usage to skyrocket
+ when the server receives multiple requests simultaneously.
+- Secondly, `grpc-go` implementation also optimizes for a similar purpose. gRPC protocol is [built on HTTP/2](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md).
+ When the gRPC server writes into the wire, it wraps the data inside an HTTP/2 data frame. `grpc-go` implementation maintains an asynchronous control buffer. It allocates
+ new memory, copies the data over, and appends to the control buffer ([client](https://github.com/grpc/grpc-go/blob/master/internal/transport/http2_client.go),
+ [server](https://github.com/grpc/grpc-go/blob/master/internal/transport/http2_server.go)). So, even if we can overpass the protobuf problem with a
+ [custom codec](https://github.com/grpc/grpc-go/blob/master/Documentation/encoding.md), `grpc-go` is still an unsolved problem.
+ [Upstream discussion](https://github.com/grpc/grpc-go/issues/1455) (for read path only) about reusing memory is still pending.
+ [An attempt to add pooled memory]( https://github.com/grpc/grpc-go/commit/642675125e198ce612ea9caff4bf75d3a4a45667) was reverted because it conflicts with typical
+ usage patterns.
+
+We have developed a protocol called Sidechannel, which enables us to communicate raw binary data with clients through an out-of-band channel, bypassing the `grpc-go`
+implementation. For more information on Sidechannel, see [this document](https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/sidechannel.md). In summary, Sidechannel works
+as follows:
+
+- During the handshaking process of a gRPC server's acceptance of a client TCP connection, we use [Yamux](https://github.com/hashicorp/yamux) to multiplex the TCP
+ connection at the application layer. This allows the gRPC server to operate on a virtual multiplexed connection called Yamux stream.
+- When it becomes necessary for the server to transfer data, it establishes an additional Yamux stream. The data is transferred using that channel.
+
+```mermaid
+sequenceDiagram
+ participant Workhorse
+ participant Client handshaker
+ participant Server handshaker
+ participant Gitaly
+ Note over Workhorse,Client handshaker: Workhorse process
+ Note over Gitaly,Server handshaker: Gitaly process
+ Workhorse ->> Client handshaker: -
+ Client handshaker ->> Server handshaker: 1. Dial
+ Note over Server handshaker: Create Yamux session
+ Server handshaker ->> Client handshaker: -
+ Client handshaker ->> Workhorse: Yamux stream 1
+ Note over Workhorse: Persist Yamus session
+
+ par Yamux stream 1
+ Workhorse ->>+ Gitaly: 2. PostUploadWithSidechannel
+ Note over Gitaly: Validate request
+ Gitaly ->> Workhorse: 3. Open Sidechannel
+ end
+
+ Note over Workhorse: Create Yamux stream 2
+
+ par Yamux stream 2
+ Workhorse ->> Gitaly: 4. Packfile Negotiation and stuff
+ Workhorse ->> Gitaly: 5. Half-closed signal
+ Gitaly ->> Workhorse: 6. Packfile data
+ Note over Workhorse: Close Yamux stream 2
+ end
+
+ par Continue Yamux stream 1
+ Gitaly ->>- Workhorse: 7. PostUploadPackWithSidechannelResponse
+ end
+```
+
+Sidechannel solved the original problem for us so far. We observed a huge improvement in Git transfer utilization and a huge reduction in CPU and memory usage. Of course, it comes with some tradeoffs:
+
+- It's a clever trick, maybe too clever. `grpc-go` provides a handshaking hook solely for authentication purposes. It's not supposed to be used for connection modification.
+- Because Sidechannel works on the connection level, all RPCs using that connection must establish the multiplexing, even if they are not targeted upload-pack ones.
+- Yamux is an application-level multiplexer. It's heavily inspired by HTTP/2, especially the binary framing, flow control, etc. We can call it a slimmed-down version of HTTP/2.
+ We are stacking two framing protocols when running gRPC on top of Yamux.
+- The detailed implementation of Sidechannel is sophisticated. Apart from the aforementioned handshaking, when the server dials back, the client must start an invisible
+ gRPC server for handshaking before handing it back to the handler. It also implements an asymmetric framing protocol inspired by `pktline`. This protocol is tailored
+ for upload-pack RPC and overcomes the lack of the "half-closed" ability of Yamux.
+
+All of those complexity adds up to the point that it becomes a burden for the maintenance and future evolution of Gitaly. When looking forward to the future Gitaly
+Raft-based architecture, Sidechannel is usually a puzzle. Reasoning about the routing strategies and implementations must consider the compatibility with Sidechannel.
+Sidechannel is an application-layer protocol so most client-side routing libraries don't work well with it. Besides, we must ensure the performance
+gained by Sidechannel is reserved. Eventually, we can still find a way to fit Sidechannel in, but the choices are pretty limited, likely leading to another
+clever hack.
+
+Replacing Sidechannel with a simpler and widely adopted technology that maintains the same performance characteristics would be beneficial. One potential solution to address
+all the issues would be to transfer all upload-pack RPCs to a pure HTTP/2 server.
+
+### Goals
+
+- Find an alternative to Sidechannel for upload-pack RPCs that is easier to use, uncomplicated, and widely adopted.
+- The implementation must use supported API and use cases of popular libraries, frameworks, or Go's standard lib. No more hacking in the transportation layer.
+- The new solution must work well with Praefect and be friendly to future routing mechanisms, load-balancers, and proxies.
+- Have the same performance and low resource utilization as Sidechannel.
+- Allow gradual rollout and full backwards compatibility with clients.
+
+### Non-Goals
+
+- Re-implement everything we invested into gRPC, such as authentication, observability, concurrency limiting, metadata propagation, etc. We don't want to maintain or
+ replicate features between two systems simultaneously.
+- Modify other RPCs or change how they are used in clients.
+- Migrate all RPCs to a new HTTP/2 server.
+
+## Proposal
+
+A huge portion of this blueprint describes the historical contexts and why we should move on. The proposed solution is straightforward: Gitaly exposes a pure HTTP2 server
+to handle all upload-pack RPCs. Other RPCs stay intact and are handled by the existing gRPC server.
+
+```mermaid
+flowchart LR
+ Workhorse-- Other RPCs --> Port3000{{":3000"}}
+ Port3000 --o gRPCServer("gRPC Server")
+ Workhorse-- PostUploadPack --> Port3001{{":3001"}}
+ Port3001 --o HTTP2Server("HTTP/2 Server")
+ GitLabShell("GitLab Shell")-- SSHUploadPack --> Port3001
+ GitLabRails("GitLab Rails") -- Other RPCs --> Port3000
+ subgraph Gitaly
+ Port3000
+ gRPCServer
+ Port3001
+ HTTP2Server
+ end
+```
+
+As mentioned earlier, Sidechannel utilizes the Yamux multiplexing protocol, which can be seen as a streamlined version of HTTP/2. When HTTP/2 is used instead, the core
+functionality remains unchanged, namely multiplexing, binary framing protocol, and flow control. This means that clients like Workhorse can efficiently exchange
+large amounts of binary data over the same TCP connection without requiring a custom encoding and decoding layer like Protobuf. This was the intended use case for HTTP/2
+from the start and, in theory, it can deliver the same level of performance as Sidechannel. Moreover, this replacement can eliminate the overhead for other direct
+RPCs so the situation of gRPC over Yamux over TCP goes away.
+
+In addition, Gitaly provides access to advanced HTTP/2 functionality through its officially-supported APIs. HTTP/2 is a first-class citizen and is officially supported by
+Go's standard library. This protocol seamlessly integrates with off-the-shelf load balancers and proxies and is also supported by various libraries.
+
+At the end of the day, both UploadPack RPC and other normal RPCs can co-exist on the same port using the technique described in the following section. However, migrating all
+of them at one go is risky in terms of performance and functionality. There might be some unexpected consequeneces. Therefore, it would be wiser to perform the
+migration gradually on GitLab.com, starting with UploadPack RPC. Other RPCs can be migrated after careful consideration. Self-managed instances can use the existing
+single port without any modification, which means this change is transparent to users.
+
+The next section describes the detailed implementation and the pros and cons of that approach.
+
+## Design and implementation details
+
+### Design
+
+In summary, the proposal is for Gitaly to expose an HTTP2 server. At first glance, it looks like we'll need to implement a new handler and a series of interceptors. Fortunately,
+gRPC Server provides [ServeHTTP](https://github.com/grpc/grpc-go/blob/642dd63a85275a96d172f446911fd04111e2c74c/server.go#L1001-L1001), allowing us to handle HTTP/2 in the
+gRPC way. It implements the `http.Handler` interface to be plugged into a HTTP/2 server. Because gRPC protocol is built on top of HTTP/2, the HTTP/2 server receives and routes
+the request to the handlers accordingly. We can use the header for redirecting:
+
+```go
+if r.ProtoMajor == 2 && strings.HasPrefix(
+ r.Header.Get("Content-Type"), "application/grpc") {
+ grpcServer.ServeHTTP(w, r)
+} else {
+ yourMux.ServeHTTP(w, r)
+}
+```
+
+This approach brings the following benefits:
+
+- `ServeHTTP` uses Go's HTTP/2 server implementation, which is totally separate from `grpc-go`'s HTTP/2 server. Digging into the implementation of both gRPC and HTTP/2
+ implementation, the built-in implementation should solve the memory allocation issue mentioned in the above section.
+- `ServeHTTP` implements the Go standard library's `http.Handler` interface. It allows writing the handler as a gRPC handler, in which we can transfer raw binary data and
+ return status codes, including error details. Clients can receive a precise reason instead of a broken pipe error in Sidechannel when something goes wrong with the data
+ transferring process.
+- Most, if not all, interceptors could be re-used without modification. Other built-in tools, such as stats reporter, [channelz](https://grpc.io/blog/a-short-introduction-to-channelz/),
+ and client-side load-balancing, also work out of the box. Observability toolkits, such as logging, and metrics work well.
+- An upload-pack request becomes a pure streaming call on one connection. No need to open another out-of-band transportation anymore.
+- Clients (Workhorse and GitLab Shell) continue to use gRPC clients. A request using this approach is considered to be a normal gRPC call. Hence, it should work well
+ with Praefect, with minimal modifications.
+
+Of course, using `ServeHTTP` comes with a cost in which requests and responses are Protobuf structs. A custom codec can overcome these performance penalties. An ideal
+solution is to implement the handler as an HTTP handler so that we can have raw access to the connection. That solution entails re-implementing all gRPC-specific
+components though. As a result, the proposed solution makes a reasonable tradeoff to ease the evolution of this architecture.
+
+```mermaid
+sequenceDiagram
+ participant Workhorse
+ participant HTTP2 Server
+ participant UploadPack Handler
+ Note over HTTP2 Server, UploadPack Handler: Gitaly process
+
+ Workhorse ->> HTTP2 Server: 1. Dial
+ HTTP2 Server ->> Workhorse: Connection
+
+ par PostUploadPackV3
+ Workhorse ->> UploadPack Handler: 2. PostUploadPackV3Request
+ Note over UploadPack Handler: Validate request
+ UploadPack Handler ->> Workhorse: PostUploadPackV3Response (empty)
+ Workhorse ->> UploadPack Handler: 3. Send raw []byte
+ Workhorse ->> Workhorse: Close sending
+ UploadPack Handler ->> Workhorse: 4. Send raw []byte
+ UploadPack Handler ->> UploadPack Handler: Close connection
+ end
+```
+
+The proposed solution is to:
+
+- Implement a "raw codec" that passes-through input binary data.
+- Create a new `PostUploadPackV3` gRPC call and implement a corresponding server handler similar to other gRPC handlers.
+- Implement an HTTP/2 server that calls to gRPC's `ServeHTTP`. This server is treated as another gRPC server. In fact, Gitaly now starts up to 4 gRPC servers
+ (internally and externally) over different transportation channels. This HTTP2 server can blend into the fleet and use Gitaly's existing process management, and
+ graceful shutdowns and upgrades.
+
+I implemented two POC merge requests in Gitaly and Workhorse to demonstrate the solution:
+
+- Gitaly: [merge request 5885](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5885).
+- Workhorse: [merge request 123764](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123764).
+
+These POC MRs make the tests green for a non-Praefect setup. The early benchmarks on the local environment show that this approach:
+
+- Is slightly faster than the Sidechannel approach.
+- Reduces peak CPU consumption by **10-20%**.
+- Maintains the same memory utilization.
+
+The POC is not complete, but it shows the simplification using "boring" techniques. The performance improvement is totally unexpected though.
+
+The existing Sidechannel solution can co-exist with the new one. That makes gradual adoption feasible.
+
+Apart from external traffic, a Gitaly server also handles internal requests. They come from Git processes spawned by Gitaly. One typical example is
+`PackObjectsHookWithSidechannel` RPC, triggered by `git-upload-pack(1)` for generating Packfile. The proposed solution also benefits these internal RPCs.
+
+### Considerations
+
+A major issue with the proposed solution is that it opens up HTTP/2 through a separate port. While `ServeHTTP` enables us to integrate the gRPC handler into an existing
+HTTP/2 server, it doesn't support the other way around. A new port exposure leads to some extra setup, such as firewall, NAT, etc, in a restrictive environment. A typical
+setup doesn't need any infrastructure change. As mentioned above, the two-port situation occurs during the migration only. When it's done, we can unify them into one and
+release to self-managed instances. Users don't need to change anything.
+
+As previously mentioned, the newly-introduced HTTP/2 server is managed by the Gitaly process. It operates consistently with the existing gRPC servers for starting,
+restarting, shutting down, and upgrading. This also implies that load-balancing, service discovery, domain management, and other configurations will work seamlessly
+if they are set up for the current gRPC server. The new server can utilize most of the configurations of the current gRPC servers, including TLS and authentication. The
+only new configuration required is the address for the HTTP server to bind to. Therefore, exposing a new port should not be a hindrance.
+
+Another concern is that Workhorse and GitLab Shell must maintain a separate connection pool. At the moment, they maintain one connection to each Gitaly node. This number
+will be doubled to two connections to each Gitaly node. This shouldn't be a big issue. Eventually, the traffic splits between two connections in which most heavy operations
+are handled by the HTTP/2 server. GitLab Rails stay intact as it doesn't handle UploadPack.
diff --git a/doc/architecture/blueprints/gitlab_events_platform/index.md b/doc/architecture/blueprints/gitlab_events_platform/index.md
new file mode 100644
index 00000000000..7d6377aaf43
--- /dev/null
+++ b/doc/architecture/blueprints/gitlab_events_platform/index.md
@@ -0,0 +1,120 @@
+---
+status: proposed
+creation-date: "2023-03-06"
+authors: [ "@grzesiek", "@fabiopitino" ]
+coach: "@ayufan"
+approvers: [ "@jreporter", "@sgoldstein" ]
+owning-stage: "~devops::ops section"
+---
+
+# GitLab Events Platform
+
+## Summary
+
+GitLab codebase has grown a lot since the [first commit](https://gitlab.com/gitlab-org/gitlab/-/commit/93efff945215)
+made in 2011. We've been able to implement many features that got adopted by
+millions of users. There is a demand for more features, but there is also an
+opportunity of a paradigm change: instead of delivering features that cover
+specific use-cases, we can start building a platform that our users will be
+able to extend with automation as they see fit. We can build a flexible and
+generic DevSecOps solution that will integrate with external and internal
+workflows using a robust eventing system.
+
+In this design document we propose to add a few additional layers of
+abstraction to make it possible to:
+
+1. Design a notion of events hierarchy that encodes their origin and schema.
+1. Publish events from within the application code using Publishers.
+1. Intercept and transform events from external sources using Gateways.
+1. Subscribe to internal / external events using Subscribers.
+1. Hide queueing and processing implementation details behind an abstraction.
+
+This will allow us to transform GitLab into a generic automation tooling, but
+will also reduce the complexity of existing events-like features:
+
+1. [Webhooks](../../../user/project/integrations/webhook_events.md)
+1. [Audit Events](../../../administration/audit_events.md)
+1. [GitLab CI Events](https://about.gitlab.com/blog/2022/08/03/gitlab-ci-event-workflows/)
+1. [Package Events](https://gitlab.com/groups/gitlab-org/-/epics/9677)
+1. [GraphQL Events](https://gitlab.com/gitlab-org/gitlab/-/blob/dabf4783f5d758f69d947f5ff2391b4b1fb5f18a/app/graphql/graphql_triggers.rb)
+
+## Goals
+
+Build required abstractions and their implementation needed to better manage
+internally and externally published events.
+
+## Challenges
+
+1. There is no solution allowing users to build subscribers and publishers.
+1. There is no solution for managing subscriptions outside of the Ruby code.
+1. There are many events-like features inside GitLab not using common abstractions.
+1. Our current eventing solution `Gitlab::EventStore` is tightly coupled with Sidekiq.
+1. There is no unified and resilient way to subscribe to externally published events.
+1. Payloads associated with events differ a lot, similarly to how we define schemas.
+1. Not all events are strongly typed, there is no solution to manage their hierarchy.
+1. Events are not being versioned, it is easy to break schema contracts.
+1. We want to build more features based on events, but because of missing
+ abstractions the value we could get from the implementations is limited.
+
+## Proposal
+
+### Publishers
+
+Publishing events from within our Rails codebase is an important piece of the
+proposed architecture. Events should be strongly typed, ideally using Ruby classes.
+
+For example, we could emit events in the following way:
+
+```ruby
+include Gitlab::Events::Emittable
+
+emit Gitlab::Events::Package::Published.new(package)
+```
+
+- Publishing events should be a non-blocking, and near zero-cost operation.
+- Publishing events should take their origin and identity into the account.
+- Publishing events should build their payload based on their lineage.
+- `emit` can be a syntactic sugar over mechanism used in `GitLab::EventStore`.
+
+### Subscribers
+
+Subscribers will allow application developers to subscribe to arbitrary events,
+published internally or externally. Subscribers could also allow application
+developers to build subscription mechanisms that could be used by our users to,
+for example, subscribe to project events to trigger pipelines.
+
+Events that subscribers will subscribe to will becomes contracts, hence we
+should version them or use backwards-and-forward compatible solution (like
+Protobuf).
+
+### Gateways
+
+Gateways can be used to intercept internal and external events and change their
+type, augment lineage and transform their payloads.
+
+Gateways can be used, for example, to implement sink endpoints to intercept
+Cloud Events, wrap into an internally used Ruby classes and allow developers /
+users to subscribe to them.
+
+We also may be able to implement [cross-Cell](../cells) communication through a
+generic events bus implemented using Gateways.
+
+There are also ideas around cross-instance communication to improve how GitLab
+can coordinate complex deployments that involve multiple instances.
+
+### Processing
+
+Today in order to queue events, we either use PostgreSQL or Sidekiq. Both
+mechanisms are being used interchangeably and are tightly coupled with existing
+solution.
+
+The main purpose of building an abstraction for queuing and processing is to be
+able to switch to a different queuing backend when needed. For example, we
+could queue some of the events on Google Pub/Sub, and send those through a
+dedicated Gateway on their way back to the application.
+
+### Observability
+
+In order to understand interactions between events, publishers and subscribers
+we may need to deliver a proper instrumentation _via_ OpenTelemetry. This will
+allow us to visualize these interactions with Distributed Tracing Backends.
diff --git a/doc/architecture/blueprints/gitlab_steps/index.md b/doc/architecture/blueprints/gitlab_steps/index.md
new file mode 100644
index 00000000000..d7878445cd0
--- /dev/null
+++ b/doc/architecture/blueprints/gitlab_steps/index.md
@@ -0,0 +1,142 @@
+---
+status: proposed
+creation-date: "2023-08-23"
+authors: [ "@ayufan" ]
+coach: "@grzegorz"
+approvers: [ "@dhershkovitch", "@DarrenEastman", "@marknuzzo", "@nicolewilliams" ]
+owning-stage: "~devops::verify"
+participating-stages: [ ]
+---
+
+# Step Runner for executing GitLab Steps
+
+## Summary
+
+This document describes architecture of a new component called Step Runner, the GitLab Steps syntax it uses,
+and how the GitHub Actions support will be achieved.
+
+The competitive CI products [drone.io](https://drone.io),
+[GitHub Actions](https://docs.github.com/en/actions/creating-actions)
+have a composable CI jobs execution in form of steps, or actions.
+
+Their usage and our prior evaluation of [GitLab Runner Plugins](https://gitlab.com/gitlab-org/gitlab/-/issues/15067)
+shows a need for a better way to define CI job execution.
+
+## Glossary
+
+- GitLab Steps: a name of GitLab CI feature to define and use reusable components
+ within a single job execution context.
+- Step Runner: a RFC implementation for GitLab Steps that provides compatibility with the GitHub Actions.
+- GitHub Actions: similar to GitLab Steps, a reusable execution component used on GitHub.
+- CI Catalog: a public or private component catalog that could be used to discover and use shared components.
+- GitLab Rails: a main application responsible for pipeline execution, running on GitLab.com or on-premise installation.
+
+## Motivation
+
+Even though the current [`.gitlab-ci.yml`](../../../ci/yaml/gitlab_ci_yaml.md) is reasonably flexible, it easily becomes very
+complex when trying to support complex workflows. This complexity is represented
+with repetetitve patterns, a purpose-specific syntax, or a complex sequence of commands
+to execute.
+
+This is particularly challenging, because the [`.gitlab-ci.yml`](../../../ci/yaml/gitlab_ci_yaml.md)
+is inflexible on more complex workflows that require fine-tuning or special behavior
+for the CI job execution. Its prescriptive approach how to handle Git cloning,
+when artifacts are downloaded, or how the shell script is being executed quite often
+results in the need to work around the system for pipelines that are not "standard"
+or when new features are requested.
+
+This proves especially challenging when trying to add a new syntax to the
+[`.gitlab-ci.yml`](../../../ci/yaml/gitlab_ci_yaml.md)
+to support a specific feature, like [`secure files`](../../../ci/secure_files/index.md)
+or `release:` keyword. Adding these special features on a syntax level
+results in a more complex config, which is harder to maintain, and more complex
+to deal with technical debt when requirements change.
+
+An example of the `drone.io` and the `GitHub Actions` shows that a lot of workflows do not
+have to be part of CI syntax. Instead, they can be provided in the form of reusable components
+that are configured in a generic way in the CI config, and later downloaded and executed according
+to inputs and parameters.
+
+The GitLab Steps is meant to fill that product-gap by following similar model to competitors
+and to some extent staying compatible with them. The GitLab Steps is meant to replace all
+purpose-specific syntax to handle specific features. By providing and using reusable components,
+that are build outside of `.gitlab-ci.yml`, that are versioned, and requested when needed
+this allows the customer much more flexibility, and allows us to iterate on a catalog much faster.
+
+The reusable components that are part of a CI job execution could be used from a publicily hosted
+repository on GitLab.com, from on-premise repository of steps, or be fetched from local project.
+
+Each CI job would define a list of `steps:` to execute, that would reference GitLab Steps
+or GitHub Actions. Those steps would be executed by the step runner directly in the context of
+the target environment. GitLab Runner would be responsible to be connection between GitLab.com
+(or on-premise installation) and Step Runner.
+
+### Goals
+
+GitLab Steps:
+
+- GitLab Steps defines a syntax and structure for GitLab specific Steps implementation.
+- GitLab Steps are published in CI Catalog.
+- GitLab Steps can be used across instances (federation).
+- GitLab Steps do define `inputs` and `outputs`.
+- GitLab Steps needs to explicitly request sensitive informations with expected permissions.
+ For example: secrets, variables, tokens.
+
+GitLab Inc. managed repository of GitLab Steps:
+
+- GitLab Inc. provides a repository of GitLab Steps that are a drop-in replacement
+ for all current purpose-specific syntax: `artifacts:`, `cache:`, `release:`, etc.
+- GitLab Inc. will provide a generic step to execute `shell` steps supporting various
+ shells (`bash`, `powershell`).
+- The usage of purpose-specific syntax might be eventually deprecated in favor of steps.
+
+Step Runner:
+
+- Step Runner is hosted in a separate project in `https://gitlab.com/gitlab-org`.
+- Step Runner can be used to execute most of GitHub Actions.
+- Step Runner is run as a process in a target environment.
+- Step Runner can be used by user on their local machine to run steps of a specific CI job
+ from locally stored `.gitlab-ci.yml`.
+- Step Runner is external component to GitLab Runner, the GitLab Runner does provision
+ environment, construct payload and pass execution to Step Runner.
+- Step Runner is to replace all custom handling in GitLab Runner for `clone`, `artifacts`,
+ `caches`, `script` and `after_script`, and custom handling for all different shells (`bash`, `powershell`).
+- Step Runner is responsible for parsing and compiling GitLab Steps and GitHub Actions.
+- Step Runner is responsible for downloading, and managing repositories required by GitLab Steps and GitHub Actions.
+- Step Runner does control and monitor execution flow of individual steps of execution.
+- Step Runner is required to be executable from the command-line interface (CLI). It means that it can be configured either via config file,
+ or environment file, or be able to read `.gitlab-ci.yml`.
+- Step Runner can expose gRPC or other programmable interface to run config or get trace from.
+
+Steps Execution:
+
+- Each Step is defined by a single published or locally defined GitLab Step, or GitHub Action.
+- Each Step is executed depending on conditions that are defined by that step.
+- Each Step is executed with least amount of information exposed. Exposed informations to step
+ are requested explicitly by the step. For example: only environment variables explicitly
+ requested by the step will be passed to the step.
+- Each Step is considered untrusted. It means that even though some steps are trusted, the whole
+ CI job should be considered untrusted, since system cannot guarantee trust.
+- Each Step describes its execution in a form of preconditions, versions used, and output produced.
+ This is meant to allow to sign steps execution for the purpose of creating reproducible builds.
+
+Backward compatibility:
+
+- All currently executable syntax (for example: `before_script:`, `script:`, `artifacts:`, `cache:`, etc.)
+ should be convertible by GitLab (Rails)
+
+## Non-Goals
+
+TBD
+
+## Proposal
+
+TBD
+
+## Design and implementation details
+
+TBD
+
+## References
+
+- [GitLab Issue #215511](https://gitlab.com/gitlab-org/gitlab/-/issues/215511)
diff --git a/doc/architecture/blueprints/google_artifact_registry_integration/index.md b/doc/architecture/blueprints/google_artifact_registry_integration/index.md
new file mode 100644
index 00000000000..adde0f7f587
--- /dev/null
+++ b/doc/architecture/blueprints/google_artifact_registry_integration/index.md
@@ -0,0 +1,159 @@
+---
+status: proposed
+creation-date: "2023-08-31"
+authors: [ "@jdrpereira", "@10io" ]
+coach: "@grzesiek"
+approvers: [ "@trizzi", "@crystalpoole" ]
+owning-stage: "~devops::package"
+participating-stages: []
+---
+
+# Google Artifact Registry Integration
+
+## Summary
+
+GitLab and Google Cloud have recently [announced](https://about.gitlab.com/blog/2023/08/29/gitlab-google-partnership-s3c/) a partnership to combine the unique capabilities of their platforms.
+
+As highlighted in the announcement, one key goal is the ability to "_use Google's Artifact Registry with GitLab pipelines and packaging to create a security data plane_". The initial step toward this goal is to allow users to configure a new [Google Artifact Registry](https://cloud.google.com/artifact-registry) (abbreviated as GAR from now on) [project integration](../../../user/project/integrations/index.md) and display [container image artifacts](https://cloud.google.com/artifact-registry/docs/supported-formats) in the GitLab UI.
+
+## Motivation
+
+Please refer to the [announcement](https://about.gitlab.com/blog/2023/08/29/gitlab-google-partnership-s3c/) blog post for more details about the motivation and long-term goals of the GitLab and Google Cloud partnership.
+
+Regarding the scope of this design document, our primary focus is to fulfill the Product requirement of providing users with visibility over their container images in GAR. The motivation for this specific goal is rooted in foundational research on the use of external registries as a complement to the GitLab Container Registry ([internal](https://gitlab.com/gitlab-org/ux-research/-/issues/2602)).
+
+Since this marks the first step in the GAR integration, our aim is to achieve this goal in a way that establishes a foundation to facilitate reusability in the future. This groundwork could benefit potential future expansions, such as support for additional artifact formats (npm, Maven, etc.), and features beyond the Package stage (e.g., vulnerability scanning, deployments, etc.).
+
+### Goals
+
+- Allow GitLab users to configure a new [project integration](../../../user/project/integrations/index.md) for connecting to GAR.
+- Limited to a single top-level GAR [repository](https://cloud.google.com/artifact-registry/docs/repositories) per GitLab project.
+- Limited to GAR repositories in [Standard](https://cloud.google.com/artifact-registry/docs/repositories#mode) mode. Support for Remote and Virtual [repository modes](https://cloud.google.com/artifact-registry/docs/repositories#mode) (both in Preview) is a strech goal.
+- Limited to GAR repositories of format [Container images](https://cloud.google.com/artifact-registry/docs/supported-formats#container).
+- Use a Google Cloud [service account](https://cloud.google.com/iam/docs/service-account-overview) provided by the GitLab project owner/maintainer to interact with GAR.
+- Allow GitLab users to list container images under the connected GAR repository, including sub-repositories. The list should be paginable and sortable.
+- For each listed image, display its URI, list of tags, size, digest, upload time, media type, build time, and update time, as documented [here](https://cloud.google.com/artifact-registry/docs/reference/rest/v1/projects.locations.repositories.dockerImages#DockerImage).
+- Listing container images under the connected GAR repository is restricted to users with [Reporter+](../../../user/permissions.md#roles) roles.
+
+### Non-Goals
+
+While some of these may become goals for future iterations, they are currently out of scope:
+
+- Create, update and delete operations.
+- Connecting to multiple (top-level) GAR repositories under the same project.
+- Support for [repository formats](https://cloud.google.com/artifact-registry/docs/supported-formats) beyond container images.
+- Support for other [Identity and Access Management (IAM)](https://cloud.google.com/iam) permissions/credentials beyond [service accounts](https://cloud.google.com/iam/docs/service-account-overview).
+- GAR [cleanup policies](https://cloud.google.com/artifact-registry/docs/repositories/cleanup-policy).
+- Filtering the images list by their attributes (name or value). The current [GAR API](https://cloud.google.com/artifact-registry/docs/reference/rpc/google.devtools.artifactregistry.v1#listdockerimagesrequest) does not support filtering.
+- [Artifact analysis and vulnerability scanning](https://cloud.google.com/artifact-registry/docs/analysis).
+
+## Proposal
+
+### Design and Implementation Details
+
+#### Project Integration
+
+A new [project integration](../../../user/project/integrations/index.md) for GAR will be created. Once enabled, this will display a new "Google Artifact Registry" item in the "Operate" section of the sidebar. This is also where the [Harbor](../../../user/project/integrations/harbor.md) integration is displayed if enabled.
+
+The GAR integration can be enabled by project owner/maintainer(s), who must provide four configuration parameters during setup:
+
+- **GCP project ID**: The globally unique identifier for the GCP project where the target GAR repository lives.
+- **Repository location**: The [GCP location](https://cloud.google.com/about/locations) where the target GAR repository lives.
+- **Repository name**: The name of the target GAR repository.
+- **GCP service account key**: The _content_ (not the file) of the [service account key](https://cloud.google.com/iam/docs/keys-create-delete) in JSON format ([sample](https://cloud.google.com/iam/docs/keys-create-delete#creating)).
+
+#### Authentication
+
+The integration is simplified by using a single GCP service account for the integration. Users retain the ability to [audit usage](https://cloud.google.com/iam/docs/audit-logging/examples-service-accounts#access-with-key) of this service account on the GCP side and revoke permissions if/when necessary.
+
+The service account key provided during the integration setup must be granted at least with the [`Artifact Registry Reader`](https://cloud.google.com/artifact-registry/docs/access-control#permissions) role in the target GCP project.
+
+Saving the (encrypted) service account key JSON content in the backend allows us to easily grab and use it to initialize the GAR client (more about that later). Providing the content of the key file instead of uploading it is similar to what we do with users' public SSH keys.
+
+As previously highlighted, access to the GAR integration features is restricted to users with [Reporter+](../../../user/permissions.md#roles) roles.
+
+#### Resource Mapping
+
+For the [GitLab Container Registry](../../../user/packages/container_registry/index.md), repositories within a specific project must have a path that matches the project full path. This is essentially how we establish a resource mapping between GitLab Rails and the registry, which serves multiple purposes, including granular authorization, scoping storage usage to a given project/group/namespace, and more.
+
+Regarding the GAR integration, since there is no equivalent entities for GitLab project/group/namespace resources on the GAR side, we aim to simplify matters by allowing users to attach any [GAR repository](https://cloud.google.com/artifact-registry/docs/repositories) to any GitLab project, regardless of their respective paths. Similarly, we do not plan to restrict the attachment of a particular GAR repository to a single GitLab project. Ultimately, it is up to users to determine how to organize both datasets in the way that best suits their needs.
+
+#### GAR API
+
+GAR provides three APIs: Docker API, REST API, and RPC API.
+
+The [Docker API](https://cloud.google.com/artifact-registry/docs/reference/docker-api) is based on the [Docker Registry HTTP API V2](https://docs.docker.com/registry/spec/api), now superseded by the [OCI Distribution Specification API](https://github.com/opencontainers/distribution-spec/blob/main/spec.md) (from now on referred to as OCI API). This API is used for pushing/pulling images to/from GAR and also provides some discoverability operations. Please refer to [Alternative Solutions](#alternative-solutions) for the reasons why we don't intend to use it.
+
+Among the proprietary GAR APIs, the [REST API](https://cloud.google.com/artifact-registry/docs/reference/rest) provides basic functionality for managing repositories. This includes [`list`](https://cloud.google.com/artifact-registry/docs/reference/rest/v1/projects.locations.repositories.dockerImages/list) and [`get`](https://cloud.google.com/artifact-registry/docs/reference/rest/v1/projects.locations.repositories.dockerImages/get) operations for container image repositories, which could be used for this integration. Both operations return the same data structure, represented by the [`DockerImage`](https://cloud.google.com/artifact-registry/docs/reference/rest/v1/projects.locations.repositories.dockerImages#DockerImage) object, so both provide the same level of detail.
+
+Last but not least, there is also an [RPC API](https://cloud.google.com/artifact-registry/docs/reference/rpc/google.devtools.artifactregistry.v1), backed by gRPC and Protocol Buffers. This API provides the most functionality, covering all GAR features. From the available operations, we can make use of the [`ListDockerImagesRequest`](https://cloud.google.com/artifact-registry/docs/reference/rpc/google.devtools.artifactregistry.v1#listdockerimagesrequest) and [`GetDockerImageRequest`](https://cloud.google.com/artifact-registry/docs/reference/rpc/google.devtools.artifactregistry.v1#google.devtools.artifactregistry.v1.GetDockerImageRequest) operations. As with the REST API, both responses are composed of [`DockerImage`](https://cloud.google.com/artifact-registry/docs/reference/rpc/google.devtools.artifactregistry.v1#google.devtools.artifactregistry.v1.DockerImage) objects.
+
+Between the two proprietary API options, we chose the RPC one because it provides support not only for the operations we need today but also offers better coverage of all GAR features, which will be beneficial in future iterations. Finally, we do not intend to make direct use of this API but rather use it through the official Ruby client SDK. Please see [Client SDK](#client-sdk) below for more details.
+
+#### Backend Integration
+
+##### Client SDK
+
+To interact with GAR we will make use of the official GAR [Ruby client SDK](https://cloud.google.com/ruby/docs/reference/google-cloud-artifact_registry/latest).
+
+*TODO: Add more details about the client SDK integration and its limitations (no filtering for example).*
+
+##### Database Changes
+
+*TODO: Describe any necessary changes to the database to support this integration.*
+
+##### CI/CD variables
+
+Similar to the [Harbor](../../../user/project/integrations/harbor.md#configure-gitlab) integration, once users activates the GAR integration, additional CI/CD variables will be automatically available if the integration is enabled. These will be set according to the requirements described in the [documentation](https://cloud.google.com/artifact-registry/docs/docker/authentication#json-key):
+
+- `GCP_ARTIFACT_REGISTRY_URL`: This will be set to `https://LOCATION-docker.pkg.dev`, where `LOCATION` is the GCP project location configured for the integration.
+- `GCP_ARTIFACT_REGISTRY_PROJECT_URI`: This will be set to `LOCATION-docker.pkg.dev/PROJECT-ID`. `PROJECT-ID` is the GCP project ID of the GAR repository configured for the integration.
+- `GCP_ARTIFACT_REGISTRY_PASSWORD`: This will be set to the base64-encode version of the service account JSON key file configured for the integration.
+- `GCP_ARTIFACT_REGISTRY_USER`: This will be set to `_json_key_base64`.
+
+These can then be used to log in using `docker login`:
+
+```shell
+docker login -u $GCP_ARTIFACT_REGISTRY_USER -p $GCP_ARTIFACT_REGISTRY_PASSWORD $GCP_ARTIFACT_REGISTRY_URL
+```
+
+Similarly, these can be used to download images from the repository with `docker pull`:
+
+```shell
+docker pull $GCP_ARTIFACT_REGISTRY_PROJECT_URI/REPOSITORY/myapp:latest
+```
+
+Finally, provided that the configured service account has the `Artifact Registry Writer` role, one can also push images to GAR:
+
+```shell
+docker build -t $GCP_ARTIFACT_REGISTRY_REPOSITORY_URI/myapp:latest .
+docker push $GCP_ARTIFACT_REGISTRY_REPOSITORY_URI/myapp:latest
+```
+
+For forward compatibility reasons, the repository name (`REPOSITORY` in the command above) must be appended to `GCP_ARTIFACT_REGISTRY_PROJECT_URI` by the user. In the first iteration we will only support a single GAR repository, and therefore we could technically provide an e.g. `GCP_ARTIFACT_REGISTRY_REPOSITORY_URI` variable with the repository name already included. However, once we add support for multiple repositories, there is no way we can tell what repository a user will want to target for a specific instruction. So it must be the user to tell that.
+
+#### UI/UX
+
+This integration will include a dedicated page named "Google Artifact Registry," listed under the "Operate" section of the sidebar. This page will enable users to view the list of all container images in the configured GAR repository. See the [UI/UX](ui_ux.md) page for additional details.
+
+#### GraphQL APIs
+
+*TODO: Describe any GraphQL APIs or changes to existing APIs that will be needed for this integration.*
+
+## Alternative Solutions
+
+### Use Docker/OCI API
+
+One alternative solution considered was to use the Docker/OCI API provided by GAR, as it is a common standard for container registries. This approach would have allowed GitLab to reuse [existing logic](https://gitlab.com/gitlab-org/gitlab/-/blob/20df77103147c0c8ff1c22a888516eba4bab3c46/lib/container_registry/client.rb) for connecting to container registries, which could potentially speed up development. However, there were several drawbacks to this approach:
+
+- **Authentication Complexity**: The API requires authentication tokens, which need to be requested at the [login endpoint](https://docs.docker.com/registry/spec/auth/token). These tokens have limited validity, adding complexity to the authentication process. Handling expiring tokens would have been necessary.
+
+- **Limited Focus**: The API is solely focused on container registry objects, which does not align with the goal of creating a flexible integration framework for adopting additional GAR artifacts (e.g. package registry formats) down the road.
+
+- **Discoverability Limitations**: The API has severe limitations when it comes to discoverability, lacking features like filtering or sorting.
+
+- **Multiple Requests**: To retrieve all the required information about each image, multiple requests to different endpoints (listing tags, obtaining image manifests, and image configuration blobs) would have been necessary, leading to a `1+N` performance issue.
+
+GitLab had previously faced significant challenges with the last two limitations, prompting the development of a custom [GitLab Container Registry API](https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/api.md) to address them. Additionally, GitLab decided to [deprecate support](../../../update/deprecations.md#use-of-third-party-container-registries-is-deprecated) for connecting to third-party container registries using the Docker/OCI API due to these same limitations and the increased cost of maintaining two solutions in parallel. As a result, there is an ongoing effort to replace the use of the Docker/OCI API endpoints with custom API endpoints for all container registry functionalities in GitLab.
+
+Considering these factors, the decision was made to build the GAR integration from scratch using the proprietary GAR API. This approach provides more flexibility and control over the integration and can serve as a foundation for future expansions, such as support for other GAR artifact formats.
diff --git a/doc/architecture/blueprints/google_artifact_registry_integration/ui_ux.md b/doc/architecture/blueprints/google_artifact_registry_integration/ui_ux.md
new file mode 100644
index 00000000000..5cb862d50e7
--- /dev/null
+++ b/doc/architecture/blueprints/google_artifact_registry_integration/ui_ux.md
@@ -0,0 +1,17 @@
+---
+stage: package
+group: container registry
+description: 'UI/UX for Google Artifact Registry Integration'
+---
+
+# UI/UX for Google Artifact Registry Integration
+
+## Structure and Organization
+
+Unlike the GitLab Container Registry (and therefore the Docker Registry and OCI Distribution), GAR does not treat tags as the primary "artifacts" in a repository. Instead, the primary "artifacts" are the image manifests. For each manifest object (represented by [`DockerImage`](https://cloud.google.com/artifact-registry/docs/reference/rpc/google.devtools.artifactregistry.v1#google.devtools.artifactregistry.v1.DockerImage)), there is a list of assigned tags (if any). Consequently, when listing the contents of a repository through the GAR API, the response comprises a collection of manifest objects (along with their associated tags as properties), rather than a collection of tag objects. Additionally, due to this design choice, untagged manifests are also present in the response.
+
+To maximize flexibility, extensibility, and maintain familiarity for GAR users, we plan to fully embrace the GAR API data structures while surfacing data in the GitLab UI. We won't attempt to emulate a "list of tags" response to match the UI/UX that we already have for the GitLab Container Registry.
+
+Considering the above, there will be a view that provides a pageable and sortable list of all images in the configured GAR repository. Additionally, there will be a detail view to display more information about a single image. You can find a list of available image attributes documented [here](https://cloud.google.com/artifact-registry/docs/reference/rpc/google.devtools.artifactregistry.v1#google.devtools.artifactregistry.v1.DockerImage).
+
+## Designs
diff --git a/doc/architecture/blueprints/modular_monolith/bounded_contexts.md b/doc/architecture/blueprints/modular_monolith/bounded_contexts.md
index 0f71e24864e..8133106050d 100644
--- a/doc/architecture/blueprints/modular_monolith/bounded_contexts.md
+++ b/doc/architecture/blueprints/modular_monolith/bounded_contexts.md
@@ -41,11 +41,16 @@ The majority of the code is not properly namespaced and organized:
In June 2023 we've started extracing gems out of the main codebase, into
[`gems/` directory inside the monorepo](https://gitlab.com/gitlab-org/gitlab/-/blob/4c6e120069abe751d3128c05ade45ea749a033df/doc/development/gems.md).
-This is our first step towards modularization: externalize code that can be
-extracted to prevent coupling from being introduced into modules that have been
-designed as separate components.
+This is our first step towards modularization.
-These gems as still part of the monorepo.
+- We want to separate generic code from domain code (that powers the business logic).
+- We want to cleanup `lib/` directory from generic code.
+- We want to isolate code that could live in a separate project, to prevent it from depending on domain code.
+
+These gems as still part of the monorepo but could be extracted into dedicated repositories if needed.
+
+Extraction of gems is non blocking to modularization but the less generic code exists in `lib/` the
+easier will be identifying and separating bounded context.
### 1. What makes a bounded context?
@@ -103,17 +108,3 @@ With this static list we could:
- Understand where to place new classes and modules.
- Enforce if any top-level namespaces are used that are not in the list of bounded contexts.
- Autoload non-standard Rails directories based on the given list.
-
-## Glossary
-
-- `modules` are Ruby modules and can be used to nest code hierarchically.
-- `namespaces` are unique hierarchies of Ruby constants. For example, `Ci::` but also `Ci::JobArtifacts::` or `Ci::Pipeline::Chain::`.
-- `packages` are Packwerk packages to group together related functionalities. These packages can be big or small depending on the design and architecture. Inside a package all constants (classes and modules) have the same namespace. For example:
- - In a package `ci`, all the classes would be nested under `Ci::` namespace. There can be also nested namespaces like `Ci::PipelineProcessing::`.
- - In a package `ci-pipeline_creation` all classes are nested under `Ci::PipelineCreation`, like `Ci::PipelineCreation::Chain::Command`.
- - In a package `ci` a class named `MergeRequests::UpdateHeadPipelineService` would not be allowed because it would not match the package's namespace.
- - This can be enforced easily with [Packwerk's based Rubocop Cops](https://github.com/rubyatscale/rubocop-packs/blob/main/lib/rubocop/cop/packs/root_namespace_is_pack_name.rb).
-- `bounded context` is a top-level Packwerk package that represents a macro aspect of the domain. For example: `Ci::`, `MergeRequests::`, `Packages::`, etc.
- - A bounded context is represented by a single Ruby module/namespace. For example, `Ci::` and not `Ci::JobArtifacts::`.
- - A bounded context can be made of 1 or multiple Packwerk packages. Nested packages would be recommended if the domain is quite complex and we want to enforce privacy among all the implementation details. For example: `Ci::PipelineProcessing::` and `Ci::PipelineCreation::` could be separate packages of the same bounded context and expose their public API while keeping implementation details private.
- - A new bounded context like `RemoteDevelopment::` can be represented a single package while large and complex bounded contexts like `Ci::` would need to be organized into smaller/nested packages.
diff --git a/doc/architecture/blueprints/modular_monolith/hexagonal_monolith/index.md b/doc/architecture/blueprints/modular_monolith/hexagonal_monolith/index.md
index eb4b428cf52..f0f689d48ca 100644
--- a/doc/architecture/blueprints/modular_monolith/hexagonal_monolith/index.md
+++ b/doc/architecture/blueprints/modular_monolith/hexagonal_monolith/index.md
@@ -25,12 +25,22 @@ Use [Packwerk](https://github.com/Shopify/packwerk) to enforce privacy and depen
## Details
+```mermaid
+flowchart TD
+ u([User]) -- interacts directly with --> AA[Application Adapter: WebUI, REST, GraphQL, git, ...]
+ AA --uses abstractions from--> D[Application Domain]
+ AA -- depends on --> Platform
+ D -- depends on --> Platform[Platform: gems, configs, framework, ...]
+```
+
### Application domain
-The application core (functional domains) is divided into separate top-level bounded contexts called after the
-[feature category](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml) they represent.
+The application core (functional domains) is composed of all the code that describes the business logic, policies and data
+that is unique to GitLab product.
+It is divided into separate top-level [bounded contexts](../bounded_contexts.md).
A bounded-context is represented in the form of a Ruby module.
-This follows the existing [guideline on naming namespaces](../../../../development/software_design.md#use-namespaces-to-define-bounded-contexts) but puts more structure to it.
+This follows the existing [guideline on naming namespaces](../../../../development/software_design.md#use-namespaces-to-define-bounded-contexts)
+but puts more structure to it.
Modules should:
@@ -52,6 +62,12 @@ If a feature category is only relevant in the context of a parent feature catego
parent's bounded context. For example: Build artifacts existing in the context of Continuous Integration feature category
and they may be merged under a single bounded context.
+The application domain has no knowledge of outer layers like the application adapters and only depends on the
+platform code. This makes the domain code to be the SSoT of the business logic, be reusable and testable regardless
+whether the request came from the WebUI or REST API.
+
+If a dependency between an outer layer and an inner layer is required (domain code depending on the interface of an adapter), this can be solved using inversion of control techniques, especially dependency injection.
+
### Application adapters
>>>
@@ -67,9 +83,14 @@ Application adapters would be:
- Web UI (Rails controllers, view, JS and Vue client)
- REST API endpoints
- GraphQL Endpoints
-- Action Cable
-TODO: continue describing how adapters are organized and why they are separate from the domain code.
+They are responsible for the interaction with the user. Each adapter should interpret the request, parse parameters
+and invoke the right abstraction from the application domain, then present the result back to the user.
+
+Presentation logic, and possibly authentication, would be specific to the adapters layer.
+
+The application adapters layer depends on the platform code to run: the Rails framework, the gems that power the adapter,
+the configurations and utilities.
### Platform code
@@ -95,19 +116,76 @@ This means that aside from the Rails framework code, the rest of the platform co
Eventually all code inside `gems/` could potentially be extracted in a separate repository or open sourced.
Placing platform code inside `gems/` makes it clear that its purpose is to serve the application code.
-### Why Packwerk?
+### Enforcing boundaries
+
+Ruby does not have the concept of privacy of constants in a given module. Unlike other programming languages, even extracting
+well documented gems doesn't prevent other developers from coupling code to implementation details because all constants
+are public in Ruby.
+
+We can have a codebase perfectly organized in an hexagonal architecture but still having the application domain, the biggest
+part of the codebase, being a non modularized [big ball of mud](https://en.wikipedia.org/wiki/Big_ball_of_mud).
+
+Enforcing boundaries is also vital to maintaining the structure long term. We don't want that after a big modularization
+effort we slowly fall back into a big ball of mud gain by violating the boundaries.
+
+We explored the idea of [using Packwerk in a proof of concept](../proof_of_concepts.md#use-packwerk-to-enforce-module-boundaries)
+to enforce module boundaries.
-TODO:
+[Packwerk](https://github.com/Shopify/packwerk) is a static analyzer that allows to gradually introduce packages in the
+codebase and enforce privacy and explicit dependencies. Packwerk can detect if some Ruby code is using private implementation
+details of another package or if it's using a package that wasn't declared explicitly as a dependency.
-- boundaries not enforced at runtime. Ruby code will still work as being all loaded in the same memory space.
-- can be introduced incrementally. Not everything requires to be moved to packs for the Rails autoloader to work.
+Being a static analyzer it does not affect code execution, meaning that introducing Packwerk is safe and can be done
+gradually.
Companies like Gusto have been developing and maintaining a list of [development and engineering tools](https://github.com/rubyatscale)
for organizations that want to move to using a Rails modular monolith around Packwerk.
### EE and JH extensions
-TODO:
+One of the unique challenges of modularizing the GitLab codebase is the presence of EE extensions (managed by GitLab)
+and JH extensions (managed by JiHu).
+
+By moving related domain code (e.g. `Ci::`) under the same bounded context and Packwerk package, we would also need to
+move `ee/` extensions in it.
+
+To have top-level bounded contexts to also match Packwerk packages it means that all code related to a specific domain
+needs to be placed under the same package directory, including EE extensions, for example.
+
+The following is just an example of a possible directory structure:
+
+```shell
+domains
+├── ci
+│ ├── package.yml # package definition.
+│ ├── packwerk.yml # tool configurations for this package.
+│ ├── package_todo.yml # existing violations.
+│ ├── core # Core features available in Community Edition and always autoloaded.
+│ │ ├── app
+│ │ │ ├── models/...
+│ │ │ ├── services/...
+│ │ │ └── lib/... # domain-specific `lib` moved inside `app` together with other classes.
+│ │ └── spec
+│ │ └── models/...
+│ ├── ee # EE extensions specific to the bounded context, conditionally autoloaded.
+│ │ ├── models/...
+│ │ └── spec
+│ │ └── models/...
+│ └── public # Public constants are placed here so they can be referenced by other packages.
+│ ├── core
+│ │ ├── app
+│ │ │ └── models/...
+│ │ └── spec
+│ │ └── models/...
+│ └── ee
+│ ├── app
+│ │ └── models/...
+│ └── spec
+│ └── models/...
+├── merge_requests/
+├── repositories/
+└── ...
+```
## Challenges
diff --git a/doc/architecture/blueprints/modular_monolith/index.md b/doc/architecture/blueprints/modular_monolith/index.md
index ef50be643a6..f1e6c119552 100644
--- a/doc/architecture/blueprints/modular_monolith/index.md
+++ b/doc/architecture/blueprints/modular_monolith/index.md
@@ -93,12 +93,11 @@ There are many aspects and details required to make modularization of our
monolith successful. We will work on the aspects listed below, refine them, and
add more important details as we move forward towards the goal:
-1. [Deliver modularization proof-of-concepts that will deliver key insights](proof_of_concepts.md)
-1. [Align modularization plans to the organizational structure](bounded_contexts.md)
+1. [Deliver modularization proof-of-concepts that will deliver key insights](proof_of_concepts.md).
+1. Align modularization plans to the organizational structure by [defining bounded contexts](bounded_contexts.md).
+1. Separate domains into modules that will reflect organizational structure (TODO)
1. Start a training program for team members on how to work with decoupled domains (TODO)
1. Build tools that will make it easier to build decoupled domains through inversion of control (TODO)
-1. Separate domains into modules that will reflect organizational structure (TODO)
-1. Build necessary services to align frontend and backend modularization (TODO)
1. [Introduce hexagonal architecture within the monolith](hexagonal_monolith/index.md)
1. Introduce clean architecture with one-way-dependencies and host application (TODO)
1. Build abstractions that will make it possible to run and deploy domains separately (TODO)
@@ -107,6 +106,20 @@ add more important details as we move forward towards the goal:
In progress.
+## Glossary
+
+- `modules` are Ruby modules and can be used to nest code hierarchically.
+- `namespaces` are unique hierarchies of Ruby constants. For example, `Ci::` but also `Ci::JobArtifacts::` or `Ci::Pipeline::Chain::`.
+- `packages` are Packwerk packages to group together related functionalities. These packages can be big or small depending on the design and architecture. Inside a package all constants (classes and modules) have the same namespace. For example:
+ - In a package `ci`, all the classes would be nested under `Ci::` namespace. There can be also nested namespaces like `Ci::PipelineProcessing::`.
+ - In a package `ci-pipeline_creation` all classes are nested under `Ci::PipelineCreation`, like `Ci::PipelineCreation::Chain::Command`.
+ - In a package `ci` a class named `MergeRequests::UpdateHeadPipelineService` would not be allowed because it would not match the package's namespace.
+ - This can be enforced easily with [Packwerk's based Rubocop Cops](https://github.com/rubyatscale/rubocop-packs/blob/main/lib/rubocop/cop/packs/root_namespace_is_pack_name.rb).
+- `bounded context` is a top-level Packwerk package that represents a macro aspect of the domain. For example: `Ci::`, `MergeRequests::`, `Packages::`, etc.
+ - A bounded context is represented by a single Ruby module/namespace. For example, `Ci::` and not `Ci::JobArtifacts::`.
+ - A bounded context can be made of 1 or multiple Packwerk packages. Nested packages would be recommended if the domain is quite complex and we want to enforce privacy among all the implementation details. For example: `Ci::PipelineProcessing::` and `Ci::PipelineCreation::` could be separate packages of the same bounded context and expose their public API while keeping implementation details private.
+ - A new bounded context like `RemoteDevelopment::` can be represented a single package while large and complex bounded contexts like `Ci::` would need to be organized into smaller/nested packages.
+
## References
[List of references](references.md)
diff --git a/doc/architecture/blueprints/organization/index.md b/doc/architecture/blueprints/organization/index.md
index 09448d6d90c..0955d53313d 100644
--- a/doc/architecture/blueprints/organization/index.md
+++ b/doc/architecture/blueprints/organization/index.md
@@ -244,6 +244,7 @@ Organizations will have an Owner role. Compared to Users, they can perform the f
| View Groups overview | ✓ | ✓ (1) |
| View Projects overview | ✓ | ✓ (1) |
| View Users overview | ✓ | ✓ (2) |
+| View Organization activity page | ✓ | ✓ (1) |
| Transfer top-level Group into Organization if Owner of both | ✓ | |
(1) Users can only see what they have access to.
@@ -251,19 +252,53 @@ Organizations will have an Owner role. Compared to Users, they can perform the f
[Roles](../../../user/permissions.md) at the Group and Project level remain as they currently are.
+#### Relationship between Organization Owner and Instance Admin
+
+Users with the (Instance) Admin role can currently [administer a self-managed GitLab instance](../../../administration/index.md).
+As functionality is moved to the Organization level, Organization Owners will be able to access more features that are currently only accessible to Admins.
+On our SaaS platform, this helps us in empowering enterprises to manage their own Organization more efficiently without depending on the Instance Admin, which is currently a GitLab team member.
+On SaaS, we expect the Instance Admin and the Organization Owner to be different users.
+Self-managed instances are generally scoped to a single organization, so in this case it is possible that both roles are fulfilled by the same person.
+There are situations that might require intervention by an Instance Admin, for instance when Users are abusing the system.
+When that is the case, actions taken by the Instance Admin overrule actions of the Organization Owner.
+For instance, the Instance Admin can ban or delete a User on behalf of the Organization Owner.
+
### Routing
-Today only Users, Projects, Namespaces and container images are considered routable entities which require global uniqueness on `https://gitlab.com/<path>/-/`. Initially, Organization routes will be [unscoped](../../../development/routing.md). Organizations will follow the path `https://gitlab.com/-/organizations/org-name/` as one of the design goals is that the addition of Organizations should not change existing Group and Project paths.
+Today only Users, Projects, Namespaces and container images are considered routable entities which require global uniqueness on `https://gitlab.com/<path>/-/`.
+Initially, Organization routes will be [unscoped](../../../development/routing.md).
+Organizations will follow the path `https://gitlab.com/-/organizations/org-name/` as one of the design goals is that the addition of Organizations should not change existing Group and Project paths.
+
+## Impact of the Organization on Other Domains
+
+We want a minimal amount of infrequently written tables in the shared database.
+If we have high write volume or large amounts of data in the shared database then this can become a single bottleneck for scaling and we lose the horizontal scalability objective of Cells.
+With isolation being one of the main requirements to make Cells work, this means that existing features will mostly be scoped to an Organization rather than work across Organizations.
+One exception to this are Users, which are stored in the cluster-wide shared database.
+For a deeper exploration of the impact on select features, see the [list of features impacted by Cells](../cells/index.md#impacted-features).
+
+### Alignment between Organization and Fulfillment
-### Impact of the Organization on Other Features
+Fulfillment is supportive of an entity above top-level groups. Their perspective is outlined in issue [#1138](https://gitlab.com/gitlab-org/fulfillment-meta/-/issues/1138).
-We want a minimal amount of infrequently written tables in the shared database. If we have high write volume or large amounts of data in the shared database then this can become a single bottleneck for scaling and we lose the horizontal scalability objective of Cells. With isolation being one of the main requirements to make Cells work, this means that existing features will mostly be scoped to an Organization rather than work across Organizations. One exception to this are Users, which are stored in the cluster-wide shared database. For a deeper exploration of the impact on select features, see the [list of features impacted by Cells](../cells/index.md#impacted-features).
+#### Goals of Fulfillment
+
+- Fulfillment has a longstanding plan to move billing from the top-level Group to a level above. This would mean that a license applies to an Organization and all its top-level Groups.
+- Fulfillment uses Zuora for billing and would like to have a 1-to-1 relationship between an Organization and their Zuora entity called BillingAccount. They want to move away from tying a license to a single top-level Group.
+- If a customer needs multiple Organizations, they will need to have a separate BillingAccount per each.
+- Ideally, a self-managed instance has a single Organization by default, which should be enough for most customers.
+- Fulfillment prefers only one additional entity.
+
+### Open-source Contributions in Organizations
+
+Several aspects of the current open-source workflow will be impacted by the introduction of Organizations.
+We are conducting deeper research around this specific problem in [issue 420804](https://gitlab.com/gitlab-org/gitlab/-/issues/420804).
## Iteration Plan
The following iteration plan outlines how we intend to arrive at the Organization MVC. We are following the guidelines for [Experiment, Beta, and Generally Available features](../../../policy/experiment-beta-support.md).
-### Iteration 1: Organization Prototype (FY24Q3)
+### Iteration 1: Organization Prototype (FY24Q4)
In iteration 1, we introduce the concept of an Organization as a way to group top-level Groups together. Support for Organizations does not require any [Cells](../cells/index.md) work, but having them will make all subsequent iterations of Cells simpler. The goal of iteration 1 will be to generate a prototype that can be used by GitLab teams to test basic functionality within an Organization. The prototype contains the following functionality:
@@ -278,15 +313,16 @@ In iteration 1, we introduce the concept of an Organization as a way to group to
- Users can navigate between the different Organizations they are part of.
- Any User within or outside of an Organization can be invited to Groups and Projects contained by the Organization.
-### Iteration 2: Organization MVC Experiment (FY24Q4)
+### Iteration 2: Organization MVC Experiment (FY25Q1)
In iteration 2, an Organization MVC Experiment will be released. We will test the functionality with a select set of customers and improve the MVC based on these learnings. The MVC Experiment contains the following functionality:
- Users are listed in the User overview. Every Organization User can access the User overview and see Users that are part of the Groups and Projects they have access to.
- Organizations can be deleted.
+- Organization Owners can access the Activity page for the Organization.
- Forking across Organizations will be defined.
-### Iteration 3: Organization MVC Beta (FY24Q4)
+### Iteration 3: Organization MVC Beta (FY25Q1)
In iteration 3, the Organization MVC Beta will be released. Users will be able to transfer existing top-level Groups into an Organization.
@@ -297,7 +333,7 @@ In iteration 3, the Organization MVC Beta will be released. Users will be able t
- Top-level Groups can be transferred into an Organization.
- The Organization URL path can be changed.
-### Iteration 4: Organization MVC GA (FY25Q1)
+### Iteration 4: Organization MVC GA (FY25Q2)
In iteration 4, the Organization MVC will be rolled out.
@@ -343,6 +379,10 @@ A force-option will only be considered if the we do not achieve the load distrib
An alternative approach to building Organizations is to convert top-level Groups into Organizations. The main advantage of this approach is that features could be built on top of the Namespace framework and therewith leverage functionality that is already available at the Group level. We would avoid building the same feature multiple times. However, Organizations have been identified as a critical driver of Cells. Due to the urgency of delivering Cells, we decided to opt for the quickest and most straightforward solution to deliver an Organization, which is the lightweight design described above. More details on comparing the two Organization proposals can be found [here](https://gitlab.com/gitlab-org/tenant-scale-group/group-tasks/-/issues/56).
+## Frequently Asked Questions
+
+See [Organization: Frequently Asked Questions](organization-faq.md).
+
## Decision Log
- 2023-05-10: [Billing is not part of the Organization MVC](https://gitlab.com/gitlab-org/gitlab/-/issues/406614#note_1384055365)
diff --git a/doc/architecture/blueprints/organization/organization-faq.md b/doc/architecture/blueprints/organization/organization-faq.md
new file mode 100644
index 00000000000..97bd8f057cc
--- /dev/null
+++ b/doc/architecture/blueprints/organization/organization-faq.md
@@ -0,0 +1,44 @@
+---
+stage: enablement
+group: Tenant Scale
+description: 'Organization: FAQ'
+---
+
+# Organization: Frequently Asked Questions
+
+## Do we expect large SaaS customers to be licensed at the Organization level, for example to have the ability to include multiple top-level Groups under on license?
+
+Yes, this has been discussed with Fulfillment and is part of the post MVC roadmap for Organizations.
+See also [Alignment between Organization and Fulfillment](index.md#alignment-between-organization-and-fulfillment).
+
+## Do we expect to be able to configure alternate GitLab domain names for Organizations (such as `customer.gitlab.com`)?
+
+There is no plan at this point to allow configuration of alternate GitLab domain names.
+We have previously heard that sub-domains bring administrative challenges.
+GitLab Dedicated will be a much better fit for that at this moment.
+
+## Do we expect Organizations to have visibility settings (public/private) of their own? Will visibility remain a property of top-level Groups?
+
+Organizations are public for now but will have their own independent visibility settings.
+See also [When can Users see an Organization?](index.md#when-can-users-see-an-organization).
+
+## What would the migration of a feature from the top-level Group to the Organization look like?
+
+One of our requirements is that everything needs to be mapped to an Organization.
+Only that way will we achieve the isolation we are striving for.
+For SaaS, all existing Groups and Projects are already mapped to `Org_ID = 1` in the backend.
+`Org_ID = 1` corresponds to the `Default Organization`, meaning that upon Organization rollout, all existing Groups and Projects will be part of the default Organization and will be seen in that context.
+Because we want to achieve as much parity as possible between SaaS and self-managed, self-managed customers would also get everything mapped to the default Organization.
+The difference between SaaS and self-managed is that for SaaS we expect users to create many Organizations, and for self-managed we do not.
+We will control this via a `can_create_organization` application setting that will be enabled by default on SaaS and disabled by default for self-managed users.
+
+Consider whether your feature can support cascading, or in other words, whether the functionality is capable of existing on multiple nested levels without causing conflicts.
+If your feature can support cascading:
+
+- Today, you should add your feature to the top-level Group for both SaaS and self-managed, and to the instance for self-managed.
+- Once the Organization is ready, you would migrate your instance level feature over the Organization object at which point it would be available at both the Organization and top-level Group for all customers.
+
+If your feature cannot support cascading:
+
+- Today, you should add your feature to the top-level Group for SaaS only, and to the instance for self-managed. The top-level Group functionality would be hidden for self-managed users.
+- Once the Organization is ready, you would migrate instance functionality to the Organization for self-managed customers, but hide it at the Organization level for SaaS. On SaaS, users would continue to manage their functionality at the top-level Group, and not at the Organization level. At some point in the future when 99% of paying customers have moved to their own Organization, you could clean things up by introducing a breaking change and unhiding it from the Organization level for all customers (SaaS and self-managed) and removing the functionality from the top-level Group.
diff --git a/doc/architecture/blueprints/remote_development/index.md b/doc/architecture/blueprints/remote_development/index.md
index c7d1ec29add..d64fbfc8b55 100644
--- a/doc/architecture/blueprints/remote_development/index.md
+++ b/doc/architecture/blueprints/remote_development/index.md
@@ -485,7 +485,11 @@ RestartRequested -left-> Running : status=Running
## Injecting environment variables and files into a workspace
-Like CI, there is a need to inject environment variables and files into a workspace. These environment variables and files will be frozen in time during workspace creation to ensure the same values are injected into the workspace every time it starts/restarts. Thus, a new database table, on the lines of `ci_job_variables` will be required. This table will contain the following columns -
+Like CI, there is a need to inject environment variables and files into a workspace.
+These environment variables and files will be frozen in time during workspace creation to ensure the same values
+are injected into the workspace every time it starts/restarts.
+Thus, a new database table, on the lines of `ci_job_variables` will be required.
+This table will contain the following columns -
- `key` - To store the name of the environment variable or the file.
- `encrypted_value` - To store the encrypted value of the environment variable or the file.
@@ -493,29 +497,40 @@ Like CI, there is a need to inject environment variables and files into a worksp
- `workspace_id` - To reference the workspace the environment variable or the file is to be injected into.
- `variable_type` - To store whether this data is to be injected as an environment variable or a file.
-To perform the encryption, a secret key would be required. This would be uniquely generated for each workpsace upon creation.
-Having a unique secret key which is used for encrypting the corresponding workspace's environment variable and file data in the workspace, improves the security profile.
+To perform the encryption, the GitLab instance level secret key is used. The data about the environment variables
+and files will only be sent to the Agent when required i.e.
-Because of the nature of reconciliation loop between Agent and Rails, it is not scalable to decrypt these values at Rails side for each request.
-Instead, the `key`, `encrypted_value` and `encrypted_value_iv` of each environment variable of the workspace are sent to the Agent along with the workspace's `secret_key`
-for the Agent to decrypt them in place.
+- When new workspace creation request has been received from the user and an Agent initiates a Partial Reconciliation request
+- When an Agent initiates a Full Reconciliation request
-To optimize this further, the data about the environment variables and files along with the secret key will only be sent when required i.e.
+More details about the implementation details can be found in this [epic](https://gitlab.com/groups/gitlab-org/-/epics/10882).
-- When new workspace creation request has been received from the user and an Agent initiates a Partial Reonciliation request
-- When an Agent initiates a Full Reconciliation request
+We need to keep in mind potential performance concerns of decrypting workspace variables on the Rails side,
+and perform benchmarks of what scale we will reach unacceptably long request times for a reconcile request.
-When a workspace is created from a project, it will inherit all the variables from the group/subgroup/project hierarchy which are defined under
-[`Settings > CI/CD > Variables`](../../../ci/variables/index.md#define-a-cicd-variable-in-the-ui). This aspect will be generalized to allow for defining `Variables`
-which will be inherited in both CI/CD and Workspaces.
+e.g. a reconcile request for 100 workspaces with 20 encrypted values each == 2000 decryptions in a single request.
-A user will also be able to define, at a user level, environment variables and files to be injected into each workspace created by them.
+More details about the benchmarking can be found in this [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/421504).
-When a new workspace is created, a new personal access token associated to the user who created the workspace will be generated.
-This personal access token will be tied to the lifecycle of the workspace and will be injected into the workspace as an environment variable or a file
-to allow for cloning private projects and supporting transparent Git operations from within the workspace out-of-the-box among other things.
+When a workspace is created from a project, it will inherit all the variables from the group/subgroup/project hierarchy
+which are defined under [`Settings > CI/CD > Variables`](../../../ci/variables/index.md#define-a-cicd-variable-in-the-ui).
+This aspect will be generalized to allow for defining `Variables` which will be inherited in both CI/CD and Workspaces.
+A user will also be able to define, at a user level, environment variables and files to be injected into each
+workspace created by them. While creating a workspace, a user would be able to override any environment variable
+or file that is inherited from the group/subgroup/project/user hierarchy.
-More details about the implementation details can be found in this [epic](https://gitlab.com/groups/gitlab-org/-/epics/10882).
+## Git operations from within a workspace
+
+When a new workspace is created, a new personal access token associated to the user who created the workspace
+will be generated. This personal access token will be tied to the lifecycle of the workspace and will be injected
+into the workspace as a file to allow for cloning private projects and supporting transparent Git operations from
+within the workspace out-of-the-box among other things using a
+[custom Git credential helper](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage).
+
+[Investigation](https://gitlab.com/gitlab-org/gitlab/-/issues/421289#note_1511631931) into using
+ephemeral tokens(JWTs/OAuth/OIDC/etc.) instead of Personal Access Tokens revealed the need to have a common
+JWT Authentication/Authorization layer at GitLab which can be tracked in this [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/421983).
+Once such a feature is available, Personal Access Tokens for each workspace would be replaced with JWT tokens.
## Workspace user traffic authentication and authorization
diff --git a/doc/architecture/blueprints/runner_tokens/index.md b/doc/architecture/blueprints/runner_tokens/index.md
index 29d7c05c553..7e5ce57dcdc 100644
--- a/doc/architecture/blueprints/runner_tokens/index.md
+++ b/doc/architecture/blueprints/runner_tokens/index.md
@@ -78,7 +78,7 @@ graph TD
<!-- vale gitlab.Spelling = NO -->
In this proposal, runners created in the GitLab UI are assigned
-[authentication tokens](../../../security/token_overview.md#runner-authentication-tokens-also-called-runner-tokens)
+[authentication tokens](../../../security/token_overview.md#runner-authentication-tokens)
prefixed with `glrt-` (**G**it**L**ab **R**unner **T**oken).
<!-- vale gitlab.Spelling = YES -->
The prefix allows the existing `register` command to use the authentication token _in lieu_
@@ -97,8 +97,8 @@ token in the `--registration-token` argument:
| Token type | Behavior |
| ---------- | -------- |
-| [Registration token](../../../security/token_overview.md#runner-authentication-tokens-also-called-runner-tokens) | Leverages the `POST /api/v4/runners` REST endpoint to create a new runner, creating a new entry in `config.toml`. |
-| [Authentication token](../../../security/token_overview.md#runner-authentication-tokens-also-called-runner-tokens) | Leverages the `POST /api/v4/runners/verify` REST endpoint to ensure the validity of the authentication token. Creates an entry in `config.toml` file and a `system_id` value in a sidecar file if missing (`.runner_system_id`). |
+| [Registration token](../../../security/token_overview.md#runner-authentication-tokens) | Leverages the `POST /api/v4/runners` REST endpoint to create a new runner, creating a new entry in `config.toml`. |
+| [Runner authentication token](../../../security/token_overview.md#runner-authentication-tokens) | Leverages the `POST /api/v4/runners/verify` REST endpoint to ensure the validity of the authentication token. Creates an entry in `config.toml` file and a `system_id` value in a sidecar file if missing (`.runner_system_id`). |
### Transition period
@@ -423,21 +423,21 @@ scope.
| Component | Milestone | Changes |
|------------------|----------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| GitLab Rails app | `%16.6` | Disable registration tokens for all groups by running database migration (only on GitLab.com) | |
-| GitLab Rails app | `%16.6` | Disable registration tokens on the instance level by running database migration (except GitLab.com) | |
-| GitLab Rails app | `%16.8` | Disable registration tokens on the instance level for GitLab.com | |
+| GitLab Rails app | `%17.0` | Disable registration tokens for all groups by running database migration (only on GitLab.com) | |
+| GitLab Rails app | `%17.0` | Disable registration tokens on the instance level by running database migration (except GitLab.com) | |
+| GitLab Rails app | `%17.0` | Disable registration tokens on the instance level for GitLab.com | |
| GitLab Rails app | `%16.3` | Implement new `:create_runner` PPGAT scope so that we don't require a full `api` scope. |
-| GitLab Rails app | | Document gotchas when [automatically rotating runner tokens](../../../ci/runners/configure_runners.md#automatically-rotate-authentication-tokens) with multiple machines. |
+| GitLab Rails app | | Document gotchas when [automatically rotating runner tokens](../../../ci/runners/configure_runners.md#automatically-rotate-runner-authentication-tokens) with multiple machines. |
### Stage 7 - Removals
| Component | Milestone | Changes |
|------------------|----------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| GitLab Rails app | `17.0` | Remove UI enabling registration tokens on the group and instance levels. |
-| GitLab Rails app | `17.0` | Remove legacy UI showing registration with a registration token. |
-| GitLab Runner | `17.0` | Remove runner model arguments from `register` command (for example `--run-untagged`, `--tag-list`, etc.) |
-| GitLab Rails app | `17.0` | Create database migrations to drop `allow_runner_registration_token` setting columns from `application_settings` and `namespace_settings` tables. |
-| GitLab Rails app | `17.0` | Create database migrations to drop:<br/>- `runners_registration_token`/`runners_registration_token_encrypted` columns from `application_settings`;<br/>- `runners_token`/`runners_token_encrypted` from `namespaces` table;<br/>- `runners_token`/`runners_token_encrypted` from `projects` table. |
+| GitLab Rails app | `18.0` | Remove UI enabling registration tokens on the group and instance levels. |
+| GitLab Rails app | `18.0` | Remove legacy UI showing registration with a registration token. |
+| GitLab Runner | `18.0` | Remove runner model arguments from `register` command (for example `--run-untagged`, `--tag-list`, etc.) |
+| GitLab Rails app | `18.0` | Create database migrations to drop `allow_runner_registration_token` setting columns from `application_settings` and `namespace_settings` tables. |
+| GitLab Rails app | `18.0` | Create database migrations to drop:<br/>- `runners_registration_token`/`runners_registration_token_encrypted` columns from `application_settings`;<br/>- `runners_token`/`runners_token_encrypted` from `namespaces` table;<br/>- `runners_token`/`runners_token_encrypted` from `projects` table. |
## FAQ
diff --git a/doc/architecture/blueprints/runway/img/runway-architecture.png b/doc/architecture/blueprints/runway/img/runway-architecture.png
new file mode 100644
index 00000000000..e577eb7fd15
--- /dev/null
+++ b/doc/architecture/blueprints/runway/img/runway-architecture.png
Binary files differ
diff --git a/doc/architecture/blueprints/runway/img/runway_vault_4_.drawio b/doc/architecture/blueprints/runway/img/runway_vault_4_.drawio
new file mode 100644
index 00000000000..ed6366af0cc
--- /dev/null
+++ b/doc/architecture/blueprints/runway/img/runway_vault_4_.drawio
@@ -0,0 +1,189 @@
+<mxfile host="app.diagrams.net" modified="2023-08-04T01:11:28.014Z" agent="Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/116.0" etag="tMKdnwQyoIu5vVdj8cNn" version="21.6.6" type="device">
+ <diagram name="Page-1" id="zu7ysp4j318SMqtlebVL">
+ <mxGraphModel dx="1810" dy="1150" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
+ <root>
+ <mxCell id="0" />
+ <mxCell id="1" parent="0" />
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--46" value="GitLab Vault" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
+ <mxGeometry x="130" y="240" width="570" height="270" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--1" value="/runway" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
+ <mxGeometry x="170" y="280" width="490" height="210" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--2" value="/service1" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
+ <mxGeometry x="200" y="330" width="200" height="130" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--3" value="/production" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
+ <mxGeometry x="240" y="360" width="120" height="35" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--4" value="/staging" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
+ <mxGeometry x="240" y="410" width="120" height="35" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--5" value="/service2" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;" vertex="1" parent="1">
+ <mxGeometry x="425" y="330" width="200" height="130" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--6" value="/production" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
+ <mxGeometry x="465" y="360" width="120" height="35" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--7" value="/staging" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
+ <mxGeometry x="465" y="410" width="120" height="35" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--14" value="GCP Project: gitlab-runway-staging" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
+ <mxGeometry x="120" y="540" width="590" height="180" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--10" value="" style="strokeColor=#dddddd;shadow=1;strokeWidth=1;rounded=1;absoluteArcSize=1;arcSize=2;" vertex="1" parent="1">
+ <mxGeometry x="150" y="580" width="250" height="120" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--11" value="&lt;font color=&quot;#000000&quot;&gt;service1&lt;/font&gt;&lt;br&gt;Cloud Run" style="editableCssRules=.*;html=1;fontColor=#999999;shape=image;verticalLabelPosition=middle;labelBackgroundColor=#ffffff;verticalAlign=middle;labelPosition=right;align=left;spacingLeft=20;part=1;points=[];imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjM2NS40NjQ5OTY3NzA0MjQ5MyIgaGVpZ2h0PSIzNzkuMjIyOTk0NDYzNTc3OTUiIHZpZXdCb3g9IjAgMCA5Ni42OTU5OTkxNDU1MDc4MSAxMDAuMzM1OTk4NTM1MTU2MjUiPiYjeGE7PHN0eWxlIHR5cGU9InRleHQvY3NzIj4mI3hhOwkuc3Qwe2ZpbGw6IzQyODVmNDt9JiN4YTsJLnN0MXtmaWxsOiNhZWNiZmE7fSYjeGE7PC9zdHlsZT4mI3hhOwk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjkuNzk0IDEwMC4zMzZMNDYuOTIgNTAuMTY4aDQ5Ljc3NnpNMCA5OS42NzFsMTIuOTc2LTQ5LjUwMkgyOS4yMkwxNi44OTcgOTIuMDU0eiIvPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0yOS43OTQgMEw0Ni45MiA1MC4xNjhoNDkuNzc2ek0wIC42NjZsMTIuOTc2IDQ5LjUwMkgyOS4yMkwxNi44OTcgOC4yODN6Ii8+JiN4YTs8L3N2Zz4=;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--10">
+ <mxGeometry width="30" height="30" relative="1" as="geometry">
+ <mxPoint x="15" y="15" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--15" value="vault agent sidecar" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--10">
+ <mxGeometry x="55.55555555555556" y="43.996666666666655" width="166.66666666666666" height="32" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--31" value="crun-service1@gitlab-runway-staging.." style="editableCssRules=.*;html=1;shape=image;verticalLabelPosition=middle;labelBackgroundColor=#ffffff;verticalAlign=middle;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjE2LjQyMDAwMDA3NjI5Mzk0NSIgaGVpZ2h0PSIyMC4wNDk5OTkyMzcwNjA1NDciIGZpbGwtcnVsZT0iZXZlbm9kZCIgdmlld0JveD0iMCAwIDE2LjQyMDAwMDA3NjI5Mzk0NSAyMC4wNDk5OTkyMzcwNjA1NDciPiYjeGE7CTxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+JiN4YTsJLnN0MHtmaWxsOiM0Mjg1ZjQ7fSYjeGE7CS5zdDF7ZmlsbDojNjY5ZGY2O30mI3hhOwk8L3N0eWxlPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik04LjIxIDBMMCAzLjQydjUuNjNjMCA1LjA2IDMuNSA5LjggOC4yMSAxMSA0LjcxLTEuMTUgOC4yMS01Ljg5IDguMjEtMTAuOTVWMy40MnptMCAzLjc5YTIuNjMgMi42MyAwIDAgMSAxLjAwNSA1LjA2QTIuNjMgMi42MyAwIDAgMSA2LjM1IDQuNTZhMi42MyAyLjYzIDAgMCAxIDEuODYtLjc3em00LjExIDExLjE1YTguNjQgOC42NCAwIDAgMS00LjExIDIuOTMgOC42NCA4LjY0IDAgMCAxLTQuMTEtMi45M3YtMi4yNWMwLTEuNjcgMi43NC0yLjUyIDQuMTEtMi41MnM0LjExLjg1IDQuMTEgMi41MnoiLz4mI3hhOwk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNOC4yMSAwdjMuNzlhMi42MyAyLjYzIDAgMSAxIDAgNS4yNnYxLjEyYzEuMzcgMCA0LjExLjg1IDQuMTEgMi41MnYyLjI1YTguNjQgOC42NCAwIDAgMS00LjExIDIuOTNWMjBjNC43MS0xLjE1IDguMjEtNS44OSA4LjIxLTEwLjk1VjMuNDJ6Ii8+JiN4YTs8L3N2Zz4=;labelPosition=right;align=left;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--10">
+ <mxGeometry x="13.88888888888889" y="90" width="16" height="20" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--18" value="" style="strokeColor=#dddddd;shadow=1;strokeWidth=1;rounded=1;absoluteArcSize=1;arcSize=2;" vertex="1" parent="1">
+ <mxGeometry x="425" y="580" width="245" height="120" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--19" value="&lt;font color=&quot;#000000&quot;&gt;service2&lt;/font&gt;&lt;br&gt;Cloud Run" style="editableCssRules=.*;html=1;fontColor=#999999;shape=image;verticalLabelPosition=middle;labelBackgroundColor=#ffffff;verticalAlign=middle;labelPosition=right;align=left;spacingLeft=20;part=1;points=[];imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjM2NS40NjQ5OTY3NzA0MjQ5MyIgaGVpZ2h0PSIzNzkuMjIyOTk0NDYzNTc3OTUiIHZpZXdCb3g9IjAgMCA5Ni42OTU5OTkxNDU1MDc4MSAxMDAuMzM1OTk4NTM1MTU2MjUiPiYjeGE7PHN0eWxlIHR5cGU9InRleHQvY3NzIj4mI3hhOwkuc3Qwe2ZpbGw6IzQyODVmNDt9JiN4YTsJLnN0MXtmaWxsOiNhZWNiZmE7fSYjeGE7PC9zdHlsZT4mI3hhOwk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjkuNzk0IDEwMC4zMzZMNDYuOTIgNTAuMTY4aDQ5Ljc3NnpNMCA5OS42NzFsMTIuOTc2LTQ5LjUwMkgyOS4yMkwxNi44OTcgOTIuMDU0eiIvPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0yOS43OTQgMEw0Ni45MiA1MC4xNjhoNDkuNzc2ek0wIC42NjZsMTIuOTc2IDQ5LjUwMkgyOS4yMkwxNi44OTcgOC4yODN6Ii8+JiN4YTs8L3N2Zz4=;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--18">
+ <mxGeometry width="30" height="30" relative="1" as="geometry">
+ <mxPoint x="15" y="15" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--20" value="vault agent sidecar" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--18">
+ <mxGeometry x="54.44444444444444" y="43.996666666666655" width="163.33333333333334" height="32" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--34" value="crun-service2@gitlab-runway-staging.." style="editableCssRules=.*;html=1;shape=image;verticalLabelPosition=middle;labelBackgroundColor=#ffffff;verticalAlign=middle;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjE2LjQyMDAwMDA3NjI5Mzk0NSIgaGVpZ2h0PSIyMC4wNDk5OTkyMzcwNjA1NDciIGZpbGwtcnVsZT0iZXZlbm9kZCIgdmlld0JveD0iMCAwIDE2LjQyMDAwMDA3NjI5Mzk0NSAyMC4wNDk5OTkyMzcwNjA1NDciPiYjeGE7CTxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+JiN4YTsJLnN0MHtmaWxsOiM0Mjg1ZjQ7fSYjeGE7CS5zdDF7ZmlsbDojNjY5ZGY2O30mI3hhOwk8L3N0eWxlPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik04LjIxIDBMMCAzLjQydjUuNjNjMCA1LjA2IDMuNSA5LjggOC4yMSAxMSA0LjcxLTEuMTUgOC4yMS01Ljg5IDguMjEtMTAuOTVWMy40MnptMCAzLjc5YTIuNjMgMi42MyAwIDAgMSAxLjAwNSA1LjA2QTIuNjMgMi42MyAwIDAgMSA2LjM1IDQuNTZhMi42MyAyLjYzIDAgMCAxIDEuODYtLjc3em00LjExIDExLjE1YTguNjQgOC42NCAwIDAgMS00LjExIDIuOTMgOC42NCA4LjY0IDAgMCAxLTQuMTEtMi45M3YtMi4yNWMwLTEuNjcgMi43NC0yLjUyIDQuMTEtMi41MnM0LjExLjg1IDQuMTEgMi41MnoiLz4mI3hhOwk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNOC4yMSAwdjMuNzlhMi42MyAyLjYzIDAgMSAxIDAgNS4yNnYxLjEyYzEuMzcgMCA0LjExLjg1IDQuMTEgMi41MnYyLjI1YTguNjQgOC42NCAwIDAgMS00LjExIDIuOTNWMjBjNC43MS0xLjE1IDguMjEtNS44OSA4LjIxLTEwLjk1VjMuNDJ6Ii8+JiN4YTs8L3N2Zz4=;labelPosition=right;align=left;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--18">
+ <mxGeometry x="14.998888888888871" y="90" width="16" height="20" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="Vbz_GmQMVEEN3iYocOr--15" target="Vbz_GmQMVEEN3iYocOr--4">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="150" y="650" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="206" y="642" />
+ <mxPoint x="100" y="642" />
+ <mxPoint x="100" y="428" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--54" value="read" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Vbz_GmQMVEEN3iYocOr--29">
+ <mxGeometry x="-0.1058" y="3" relative="1" as="geometry">
+ <mxPoint as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--30" value="" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="Vbz_GmQMVEEN3iYocOr--20" target="Vbz_GmQMVEEN3iYocOr--7">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="400" y="610" as="sourcePoint" />
+ <mxPoint x="450" y="560" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="740" y="640" />
+ <mxPoint x="740" y="540" />
+ <mxPoint x="740" y="430" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--55" value="read" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Vbz_GmQMVEEN3iYocOr--30">
+ <mxGeometry x="-0.0904" y="1" relative="1" as="geometry">
+ <mxPoint as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--35" value="GCP Project: gitlab-runway-production" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
+ <mxGeometry x="120" y="760" width="590" height="180" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--36" value="" style="strokeColor=#dddddd;shadow=1;strokeWidth=1;rounded=1;absoluteArcSize=1;arcSize=2;" vertex="1" parent="1">
+ <mxGeometry x="150" y="800" width="250" height="120" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--37" value="&lt;font color=&quot;#000000&quot;&gt;service1&lt;/font&gt;&lt;br&gt;Cloud Run" style="editableCssRules=.*;html=1;fontColor=#999999;shape=image;verticalLabelPosition=middle;labelBackgroundColor=#ffffff;verticalAlign=middle;labelPosition=right;align=left;spacingLeft=20;part=1;points=[];imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjM2NS40NjQ5OTY3NzA0MjQ5MyIgaGVpZ2h0PSIzNzkuMjIyOTk0NDYzNTc3OTUiIHZpZXdCb3g9IjAgMCA5Ni42OTU5OTkxNDU1MDc4MSAxMDAuMzM1OTk4NTM1MTU2MjUiPiYjeGE7PHN0eWxlIHR5cGU9InRleHQvY3NzIj4mI3hhOwkuc3Qwe2ZpbGw6IzQyODVmNDt9JiN4YTsJLnN0MXtmaWxsOiNhZWNiZmE7fSYjeGE7PC9zdHlsZT4mI3hhOwk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjkuNzk0IDEwMC4zMzZMNDYuOTIgNTAuMTY4aDQ5Ljc3NnpNMCA5OS42NzFsMTIuOTc2LTQ5LjUwMkgyOS4yMkwxNi44OTcgOTIuMDU0eiIvPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0yOS43OTQgMEw0Ni45MiA1MC4xNjhoNDkuNzc2ek0wIC42NjZsMTIuOTc2IDQ5LjUwMkgyOS4yMkwxNi44OTcgOC4yODN6Ii8+JiN4YTs8L3N2Zz4=;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--36">
+ <mxGeometry width="30" height="30" relative="1" as="geometry">
+ <mxPoint x="15" y="15" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--38" value="vault agent sidecar" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--36">
+ <mxGeometry x="55.55555555555556" y="43.996666666666655" width="166.66666666666666" height="32" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--39" value="crun-service1@gitlab-runway-production.." style="editableCssRules=.*;html=1;shape=image;verticalLabelPosition=middle;labelBackgroundColor=#ffffff;verticalAlign=middle;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjE2LjQyMDAwMDA3NjI5Mzk0NSIgaGVpZ2h0PSIyMC4wNDk5OTkyMzcwNjA1NDciIGZpbGwtcnVsZT0iZXZlbm9kZCIgdmlld0JveD0iMCAwIDE2LjQyMDAwMDA3NjI5Mzk0NSAyMC4wNDk5OTkyMzcwNjA1NDciPiYjeGE7CTxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+JiN4YTsJLnN0MHtmaWxsOiM0Mjg1ZjQ7fSYjeGE7CS5zdDF7ZmlsbDojNjY5ZGY2O30mI3hhOwk8L3N0eWxlPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik04LjIxIDBMMCAzLjQydjUuNjNjMCA1LjA2IDMuNSA5LjggOC4yMSAxMSA0LjcxLTEuMTUgOC4yMS01Ljg5IDguMjEtMTAuOTVWMy40MnptMCAzLjc5YTIuNjMgMi42MyAwIDAgMSAxLjAwNSA1LjA2QTIuNjMgMi42MyAwIDAgMSA2LjM1IDQuNTZhMi42MyAyLjYzIDAgMCAxIDEuODYtLjc3em00LjExIDExLjE1YTguNjQgOC42NCAwIDAgMS00LjExIDIuOTMgOC42NCA4LjY0IDAgMCAxLTQuMTEtMi45M3YtMi4yNWMwLTEuNjcgMi43NC0yLjUyIDQuMTEtMi41MnM0LjExLjg1IDQuMTEgMi41MnoiLz4mI3hhOwk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNOC4yMSAwdjMuNzlhMi42MyAyLjYzIDAgMSAxIDAgNS4yNnYxLjEyYzEuMzcgMCA0LjExLjg1IDQuMTEgMi41MnYyLjI1YTguNjQgOC42NCAwIDAgMS00LjExIDIuOTNWMjBjNC43MS0xLjE1IDguMjEtNS44OSA4LjIxLTEwLjk1VjMuNDJ6Ii8+JiN4YTs8L3N2Zz4=;labelPosition=right;align=left;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--36">
+ <mxGeometry x="13.88888888888889" y="90" width="16" height="20" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--40" value="" style="strokeColor=#dddddd;shadow=1;strokeWidth=1;rounded=1;absoluteArcSize=1;arcSize=2;" vertex="1" parent="1">
+ <mxGeometry x="425" y="800" width="245" height="120" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--41" value="&lt;font color=&quot;#000000&quot;&gt;service2&lt;/font&gt;&lt;br&gt;Cloud Run" style="editableCssRules=.*;html=1;fontColor=#999999;shape=image;verticalLabelPosition=middle;labelBackgroundColor=#ffffff;verticalAlign=middle;labelPosition=right;align=left;spacingLeft=20;part=1;points=[];imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjM2NS40NjQ5OTY3NzA0MjQ5MyIgaGVpZ2h0PSIzNzkuMjIyOTk0NDYzNTc3OTUiIHZpZXdCb3g9IjAgMCA5Ni42OTU5OTkxNDU1MDc4MSAxMDAuMzM1OTk4NTM1MTU2MjUiPiYjeGE7PHN0eWxlIHR5cGU9InRleHQvY3NzIj4mI3hhOwkuc3Qwe2ZpbGw6IzQyODVmNDt9JiN4YTsJLnN0MXtmaWxsOiNhZWNiZmE7fSYjeGE7PC9zdHlsZT4mI3hhOwk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjkuNzk0IDEwMC4zMzZMNDYuOTIgNTAuMTY4aDQ5Ljc3NnpNMCA5OS42NzFsMTIuOTc2LTQ5LjUwMkgyOS4yMkwxNi44OTcgOTIuMDU0eiIvPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0yOS43OTQgMEw0Ni45MiA1MC4xNjhoNDkuNzc2ek0wIC42NjZsMTIuOTc2IDQ5LjUwMkgyOS4yMkwxNi44OTcgOC4yODN6Ii8+JiN4YTs8L3N2Zz4=;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--40">
+ <mxGeometry width="30" height="30" relative="1" as="geometry">
+ <mxPoint x="15" y="15" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--42" value="vault agent sidecar" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--40">
+ <mxGeometry x="54.44444444444444" y="43.996666666666655" width="163.33333333333334" height="32" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--43" value="crun-service2@gitlab-runway-production.." style="editableCssRules=.*;html=1;shape=image;verticalLabelPosition=middle;labelBackgroundColor=#ffffff;verticalAlign=middle;aspect=fixed;imageAspect=0;image=data:image/svg+xml,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyIgd2lkdGg9IjE2LjQyMDAwMDA3NjI5Mzk0NSIgaGVpZ2h0PSIyMC4wNDk5OTkyMzcwNjA1NDciIGZpbGwtcnVsZT0iZXZlbm9kZCIgdmlld0JveD0iMCAwIDE2LjQyMDAwMDA3NjI5Mzk0NSAyMC4wNDk5OTkyMzcwNjA1NDciPiYjeGE7CTxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+JiN4YTsJLnN0MHtmaWxsOiM0Mjg1ZjQ7fSYjeGE7CS5zdDF7ZmlsbDojNjY5ZGY2O30mI3hhOwk8L3N0eWxlPiYjeGE7CTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik04LjIxIDBMMCAzLjQydjUuNjNjMCA1LjA2IDMuNSA5LjggOC4yMSAxMSA0LjcxLTEuMTUgOC4yMS01Ljg5IDguMjEtMTAuOTVWMy40MnptMCAzLjc5YTIuNjMgMi42MyAwIDAgMSAxLjAwNSA1LjA2QTIuNjMgMi42MyAwIDAgMSA2LjM1IDQuNTZhMi42MyAyLjYzIDAgMCAxIDEuODYtLjc3em00LjExIDExLjE1YTguNjQgOC42NCAwIDAgMS00LjExIDIuOTMgOC42NCA4LjY0IDAgMCAxLTQuMTEtMi45M3YtMi4yNWMwLTEuNjcgMi43NC0yLjUyIDQuMTEtMi41MnM0LjExLjg1IDQuMTEgMi41MnoiLz4mI3hhOwk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNOC4yMSAwdjMuNzlhMi42MyAyLjYzIDAgMSAxIDAgNS4yNnYxLjEyYzEuMzcgMCA0LjExLjg1IDQuMTEgMi41MnYyLjI1YTguNjQgOC42NCAwIDAgMS00LjExIDIuOTNWMjBjNC43MS0xLjE1IDguMjEtNS44OSA4LjIxLTEwLjk1VjMuNDJ6Ii8+JiN4YTs8L3N2Zz4=;labelPosition=right;align=left;" vertex="1" parent="Vbz_GmQMVEEN3iYocOr--40">
+ <mxGeometry x="14.998888888888871" y="90" width="16" height="20" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--44" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="Vbz_GmQMVEEN3iYocOr--38" target="Vbz_GmQMVEEN3iYocOr--3">
+ <mxGeometry relative="1" as="geometry">
+ <Array as="points">
+ <mxPoint x="60" y="860" />
+ <mxPoint x="60" y="378" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--53" value="read" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Vbz_GmQMVEEN3iYocOr--44">
+ <mxGeometry x="0.1399" relative="1" as="geometry">
+ <mxPoint as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--45" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="Vbz_GmQMVEEN3iYocOr--42" target="Vbz_GmQMVEEN3iYocOr--6">
+ <mxGeometry relative="1" as="geometry">
+ <Array as="points">
+ <mxPoint x="770" y="860" />
+ <mxPoint x="770" y="378" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--56" value="read" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Vbz_GmQMVEEN3iYocOr--45">
+ <mxGeometry x="0.1104" y="-2" relative="1" as="geometry">
+ <mxPoint as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.882;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="Vbz_GmQMVEEN3iYocOr--47" target="Vbz_GmQMVEEN3iYocOr--1">
+ <mxGeometry relative="1" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--49" value="create/manage" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Vbz_GmQMVEEN3iYocOr--48">
+ <mxGeometry x="0.0275" y="-1" relative="1" as="geometry">
+ <mxPoint as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--47" value="reliability tooling" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
+ <mxGeometry x="610" y="80" width="120" height="60" as="geometry" />
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--51" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="Vbz_GmQMVEEN3iYocOr--50" target="Vbz_GmQMVEEN3iYocOr--2">
+ <mxGeometry relative="1" as="geometry">
+ <mxPoint x="230" y="160" as="sourcePoint" />
+ <Array as="points">
+ <mxPoint x="224" y="210" />
+ <mxPoint x="300" y="210" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--52" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="Vbz_GmQMVEEN3iYocOr--50" target="Vbz_GmQMVEEN3iYocOr--5">
+ <mxGeometry relative="1" as="geometry">
+ <Array as="points">
+ <mxPoint x="224" y="210" />
+ <mxPoint x="525" y="210" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--57" value="create/manage" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Vbz_GmQMVEEN3iYocOr--52">
+ <mxGeometry x="0.0102" relative="1" as="geometry">
+ <mxPoint as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="Vbz_GmQMVEEN3iYocOr--50" value="runway provisioner" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
+ <mxGeometry x="164" y="80" width="120" height="60" as="geometry" />
+ </mxCell>
+ </root>
+ </mxGraphModel>
+ </diagram>
+</mxfile>
diff --git a/doc/architecture/blueprints/runway/img/runway_vault_4_.drawio.png b/doc/architecture/blueprints/runway/img/runway_vault_4_.drawio.png
new file mode 100644
index 00000000000..b56e326c8c4
--- /dev/null
+++ b/doc/architecture/blueprints/runway/img/runway_vault_4_.drawio.png
Binary files differ
diff --git a/doc/architecture/blueprints/runway/index.md b/doc/architecture/blueprints/runway/index.md
new file mode 100644
index 00000000000..becb7914feb
--- /dev/null
+++ b/doc/architecture/blueprints/runway/index.md
@@ -0,0 +1,251 @@
+---
+status: ongoing
+creation-date: "2023-07-31"
+authors: [ "@igorwwwwwwwwwwwwwwwwwwww", "@ggillies" ]
+coach: "@andrewn"
+approvers: [ "@marin", "@fzimmer" ]
+---
+
+<!-- Blueprints often contain forward-looking statements -->
+<!-- vale gitlab.FutureTense = NO -->
+
+# Runway: A PaaS for GitLab
+
+## Summary
+
+Runway is an internal Platform as a Service for GitLab, which aims to enable teams to deploy and run their services quickly and safely.
+
+## Motivation
+
+<!--
+This section is for explicitly listing the motivation, goals and non-goals of
+this blueprint. Describe why the change is important, all the opportunities,
+and the benefits to users.
+
+The motivation section can optionally provide links to issues that demonstrate
+interest in a blueprint within the wider GitLab community. Links to
+documentation for competing products and services is also encouraged in cases
+where they demonstrate clear gaps in the functionality GitLab provides.
+
+For concrete proposals we recommend laying out goals and non-goals explicitly,
+but this section may be framed in terms of problem statements, challenges, or
+opportunities. The latter may be a more suitable framework in cases where the
+problem is not well-defined or design details not yet established.
+-->
+
+The underlying motivation for this initiative is covered in [the Service Integration blueprint](../gitlab_ml_experiments/index.md). This blueprint can be considered the implementation of the strategic requirements put forward in that proposal.
+
+### Goals
+
+<!--
+List the specific goals / opportunities of the blueprint.
+
+- What is it trying to achieve?
+- How will we know that this has succeeded?
+- What are other less tangible opportunities here?
+-->
+
+- Development teams aiming to deploy their service without having to worry too much about managing the infrastructure, scaling, monitoring.
+- We are focusing on satellite services that are stateless and thus can be autoscaled to meet demand.
+- We aim to integrate with existing GitLab features and tooling to provide a streamlined experience.
+
+### Non-Goals
+
+<!--
+Listing non-goals helps to focus discussion and make progress. This section is
+optional.
+
+- What is out of scope for this blueprint?
+-->
+
+- Hosting the GitLab monolith: The monolith is a complex application with very specialized requirements, and as such is out of scope. Deployment of the monolith is owned by the Delivery team, and there are other tools and initiatives that target this space, e.g. [Cells](../cells/index.md).
+- Arbitrary GCP resources: While we may support a commonly used subset of GCP resources, we will be selective with what we support. If you need more flexibility, you may want to request a [GitLab Sandbox](https://about.gitlab.com/handbook/infrastructure-standards/realms/sandbox/) project instead.
+- Arbitrary Kubernetes resources: As a managed platform, we aim not to expose too much of the underlying deployment mechanisms. This allows us to have a well-supported subset and gives us the flexibility to change providers. If you have specialized requirements, getting your own Kubernetes cluster may be a better option.
+
+## Proposal
+
+<!--
+This is where we get down to the specifics of what the proposal actually is,
+but keep it simple! This should have enough detail that reviewers can
+understand exactly what you're proposing, but should not include things like
+API designs or implementation. The "Design Details" section below is for the
+real nitty-gritty.
+
+You might want to consider including the pros and cons of the proposed solution so that they can be
+compared with the pros and cons of alternatives.
+-->
+
+Runway is a means for deploying a service, packaged up as a Docker image to a production environment. It leverages GitLab CI/CD as well as other GitLab product features to do this.
+
+## Design and implementation details
+
+<!--
+This section should contain enough information that the specifics of your
+change are understandable. This may include API specs (though not always
+required) or even code snippets. If there's any ambiguity about HOW your
+proposal will be implemented, this is the place to discuss them.
+
+If you are not sure how many implementation details you should include in the
+blueprint, the rule of thumb here is to provide enough context for people to
+understand the proposal. As you move forward with the implementation, you may
+need to add more implementation details to the blueprint, as those may become
+an important context for important technical decisions made along the way. A
+blueprint is also a register of such technical decisions. If a technical
+decision requires additional context before it can be made, you probably should
+document this context in a blueprint. If it is a small technical decision that
+can be made in a merge request by an author and a maintainer, you probably do
+not need to document it here. The impact a technical decision will have is
+another helpful information - if a technical decision is very impactful,
+documenting it, along with associated implementation details, is advisable.
+
+If it's helpful to include workflow diagrams or any other related images.
+Diagrams authored in GitLab flavored markdown are preferred. In cases where
+that is not feasible, images should be placed under `images/` in the same
+directory as the `index.md` for the proposal.
+-->
+
+The design of Runway aims to decouple individual components in a way that allows them to be changed and replaced over time.
+
+### Architecture
+
+![Runway Architecture](img/runway-architecture.png)
+
+[Diagram Source](https://gitlab.com/gitlab-com/gl-infra/platform/runway/team/uploads/a6b6646efaa084937ef1f961ad902b59/runway-arch.key)
+
+[Initial Architecture Discussion](https://gitlab.com/gitlab-com/gl-infra/platform/runway/team/-/issues/7)
+
+### Provisioner
+
+Provisioner is the privileged code that creates service accounts and minimal resources needed by the rest of the system.
+
+This process is responsible for taking a request "create an experimentation space for me", and stamping out the minimum required infrastructure for that space. It also covers decommissioning when a space is no longer needed.
+
+- It is currently based on Terraform.
+- Terraform runs via CI on the provisioner project.
+- We store terraform state in the GitLab Terraform state backend.
+
+### Reconciler
+
+The Reconciler is the heart of the system. It is responsible for creating a desired view of the world (based on service definition and current version), finding the differences from the actual state, and then applying that diff.
+
+Deploying a new version of a service is a matter of invoking the Reconciler.
+
+This process is responsible for taking an artifact (e.g. a Docker image) from a service developer and bringing that into a runtime. This includes rollout strategies, rollbacks, canarying, multi-environment promotion, as well as diagnostic tools for failed deploys. Some of these capabilities may also be delegated to the runtime. There should also be a standard way for connecting an existing code base to a deployment.
+
+- It is currently based on Terraform.
+- Terraform runs via CI on the deployment project, triggered as a downstream pipeline from the service project.
+- We store terraform state in the GitLab Terraform state backend on the deployment project.
+
+The user-facing integration with the Reconciler is mediated via [`ci-tasks/service-project/runway.yml`](https://gitlab.com/gitlab-com/gl-infra/platform/runway/ci-tasks/-/blob/main/service-project/runway.yml), which is a version-locked CI task that service projects include into their CI config.
+
+### Runtime
+
+The runtime is responsible for actually scheduling and running the service workloads. Reconciler targets a runtime. Runtime will provide autoscaled compute resources with a degree of tenant isolation. It will also optionally expose an endpoint at which the workload can be reached. This endpoint will have a DNS name and be TLS encrypted.
+
+- It is currently based on Cloud Run.
+- If we need more flexibility, [Knative](https://knative.dev/docs/) is a likely migration target.
+
+A service should expose an HTTP port, and it should be stateless (allowing instances to be auto-scaled). Other execution models (e.g. scheduled jobs) may be supported in the future.
+
+#### Images used by Runtime
+
+The images deployed by Runway are built by the teams responsible for the service. They are able to build the image in any fashion they wish and keep it inside the GitLab container registry of the service project. As part of the Runway deployment process, this image is mirrored to [GCP Artifact Registry](https://cloud.google.com/artifact-registry) before being consumed by Cloud Run. This is for two reasons:
+
+1. Cloud run is only able to consume images from GCP Artifact Registry.
+1. This means that if for whatever reason the image tag is changed in the future (by error), the image running inside Runway is not affected.
+
+#### GCP Project Layout
+
+Runway currently uses shared GCP projects based off three environments (dev, staging, production). These GCP projects are
+
+- Dev: `runway-dev-527768b3` (managed by IT [HackyStack](https://handbook.gitlab.com/handbook/infrastructure-standards/realms/sandbox/))
+- Staging: `gitlab-runway-staging` (managed by [reliability](https://gitlab.com/gitlab-com/gl-infra/config-mgmt/-/tree/master/environments/runway-staging?ref_type=heads)
+- Production: `gitlab-runway-production` (managed by [reliability](https://gitlab.com/gitlab-com/gl-infra/config-mgmt/-/tree/master/environments/runway-production?ref_type=heads)
+
+### Documents and Schemas used by Runway
+
+In order for runway to function, there are two JSON/YAML documents in use. They are:
+
+1. The Runway Inventory Model. This covers what service projects are currently onboarded into Runway. It's located [here](https://gitlab.com/gitlab-com/gl-infra/platform/runway/provisioner/-/blob/main/inventory.json?ref_type=heads). The schema used to validate the docuemnt is located [here](https://gitlab.com/gitlab-com/gl-infra/platform/runway/runwayctl/-/blob/main/schemas/service-inventory/v1.0.0-beta/inventory.schema.json?ref_type=heads). There is no backwards compatibility guarenteed to changes to this document schema. This is because it's only used internally by the Runway team, and there is only a single document actually being used by Runway to provision/deprovision Runway services.
+
+1. The runway Service Model. This is used by Runway users to pass through configuration needed to Runway in order to deploy their service. It's located inside their Service project, at `.runway/runway.yml`. [An example is here](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/main/.runway/runway.yml?ref_type=heads). The schema used to validate the document is located [here](https://gitlab.com/gitlab-com/gl-infra/platform/runway/runwayctl/-/blob/main/schemas/service-manifest/v1.0.0-beta/manifest.schema.json?ref_type=heads). We aim to continue to make improvements and changes to the model, but all changes to the model within the same `kind/apiVersion` must be backwards compatible. In order to
+make breaking changes, a new `apiVersion` of the schema will be released. The overall goal is to copy the [Kubernetes model for making API changes](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md).
+
+There are also [GitLab CI templates](https://gitlab.com/gitlab-com/gl-infra/platform/runway/ci-tasks) used by Runway users in order to automate deployments via Runway through GitLab CI. Users will be encouraged to use tools such as [Renovate bot](https://gitlab.com/gitlab-com/gl-infra/common-ci-tasks/-/blob/main/renovate-bot.md) in order to make sure the CI templates and
+version of Runway they are using is up to date. The Runway team will support all released versions of Runway, with the exception of when a security issue is identified. When this happens, Runway users will be expected to update to a version of Runway that contains a fix for the issue as soon as possible (once notification is received).
+
+### Secrets management
+
+For secrets management we aim to integrate with our existing HashiCorp Vault setup. We will sync secrets from Vault to whatever secrets store the Runtime integrates best with. For Cloud Run, we will use Google Secret Manager. For Kubernetes, we would use external-secrets to sync to Kubernetes Secret objects.
+
+The following high level diagram shows the proposed setup of secrets within Vault, for consumption via runway. The general idea is a top level namespace (`/runway`) will be made in Vault, with roles and policies such that:
+
+- Runway team members have full privileges over the namespace.
+- The runway provisioner running in CI has the ability to create/modify/delete new service namespaces at `runway/env/$environment/service`. The environments currently needed are dev, staging, and production.
+- The runway reconciler service accounts and GitLab team members will need read only access to `runway/env/$environment/service/$runway_service_id` in order to read secrets for deployment.
+- The runway reconciler will mirror secrets in Vault into Google Secrets Manager for consumption in Cloud Run via its native secrets integration.
+
+![Runway Vault Architecture](img/runway_vault_4_.drawio.png)
+
+[Diagram Source](img/runway_vault_4_.drawio)
+
+### Identity Management, Authentication, Authorization across Runway Components
+
+The goal of Runway is to not rely on long lived secrets or tokens inside the runway components themselves. In order to achieve this, all pieces of runway authenticate to each other in the following ways.
+
+#### Service projects to runway deployment projects
+
+This is handled by GitLab downstream pipeline triggers. Because of this, all permissions are handled within GitLab itself (and API calls to GitLab use short lived `CI_JOB_TOKEN`). We leverage [CI_JOB_TOKEN allowlists](../../../ci/jobs/ci_job_token.md#add-a-project-to-the-job-token-scope-allowlist) to allow deployment projects and service projects to interact in API calls (e.g. updating environments in the service project).
+
+#### Deployment project to GCP Cloud
+
+GitLab CI pipelines in the deployment project are responsible for talking to GCP to provision and change the cloud resources for a Runway Service. This is done via [OpenID Connnect](../../../ci/cloud_services/google_cloud/index.md) leveraging setup done in the Runway provisioner, in order to make deployment projects authenticate as a GCP service account
+with restricted permissions.
+
+#### Reconciler to GCP Cloud
+
+The reconciler (`runwayctl` wrapping around `terraform`), runs inside GitLab CI in the deployment project. This uses a specific service account setup for each Runway service, with only the permissions it needs to manipulate the GCP apis for its work. The authentication for this is handled by GitLab CI as described above.
+
+### Observability
+
+Observability will be covered [in a separate blueprint](https://gitlab.com/gitlab-com/gl-infra/platform/runway/team/-/issues/76).
+
+## Alternative Solutions
+
+<!--
+It might be a good idea to include a list of alternative solutions or paths considered, although it is not required. Include pros and cons for
+each alternative solution/path.
+
+"Do nothing" and its pros and cons could be included in the list too.
+-->
+
+### Unmanaged GCP project
+
+Instead of building a managed platform, we could give teams a GCP project and let them have at it. In fact, this is what we have done for a few services. It brings excellent isolation and flexibility. There are however several issues with this approach:
+
+- **Missing Infrastructure-as-Code:** Without any existing structure, teams may be inclined to create cloud resources via UI without using Terraform or similar IaC tools. This makes it very difficult to audit changes and re-provision the infrastructure across several environments.
+- **Sprawling:** Without sane and safe defaults, every service will need to develop their own approach for deploying services. This also makes it very difficult for anyone else to contribute to these services.
+- **Non-scalable design:** By being able to create arbitrary VMs, it can be tempting to co-locate services on a single machine without thinking about horizontal scalability.
+
+### Unmanaged Kubernetes cluster or namespace
+
+Instead of building a custom platform, we could decide that Kubernetes is the platform, and let teams have either their own cluster or their own namespace in a shared cluster.
+
+Some challenges with this approach:
+
+- **Baseline cost for GKE:** The management fee is $70 per month. If we aim to have many services across multiple environments, some of them receiving low traffic volume, then a separate cluster per service is not cost effective. This suggests we would want to go with a shared cluster.
+- **Developer friendliness:** Kubernetes is growing in popularity but it's not the most developer friendly interface. There are a lot of concepts and abstractions to grapple with. A narrower interface a la "deploy this container and give me a port", while less flexible, has a much lower barrier to entry.
+
+It is plausible that Runway will evolve more in this direction.
+
+### GCP project per service
+
+GCP projects provide a very solid foundation for resource isolation and cost attribution. Ideally we would leverage such a model. However, the lack of shared resources comes at a significant baseline cost per service.
+
+If we want to make use of GKE, the per-cluster management fee of $70 per month would likely result in the minimum cost for a service being $140 per month. For small services, this is not cost effective.
+
+An alternative to consider would be running Kubernetes without GKE. This then means we need to manage that Kubernetes deployment ourselves, and stay on top of the differences to GKE.
+
+Another alternative to consider is to use Cloud Run for small services and GKE for larger ones. This however requires maintaining compatibility with Cloud Run, and potentially be limited to the lowest common denominator in terms of features.
+
+Some hybrid is possible (e.g. give a Runway service its own project), but as long as we have shared resources, we need to implement permission control on a per-resource level.
diff --git a/doc/architecture/blueprints/transfer_data/index.md b/doc/architecture/blueprints/transfer_data/index.md
new file mode 100644
index 00000000000..9eea86d91e7
--- /dev/null
+++ b/doc/architecture/blueprints/transfer_data/index.md
@@ -0,0 +1,141 @@
+---
+status: proposed
+creation-date: "2023-09-07"
+authors: [ "@vyaklushin" ]
+approvers: [ "@ofernandez2", "@sean_carroll" ]
+coach: ["@andrewn", "@grzesiek"]
+owning-stage: "~group::source_code"
+participating-stages: []
+---
+
+# Transfer data
+
+## Summary
+
+GitLab already provides users transparency on their Usage Quotas.
+
+We currently display data about:
+
+- used license seats
+- used storage
+- CI/CD minutes usage
+
+But we don't collect and present transfer data (egress traffic caused by
+various parts of the application).
+
+Collecting data about number of transferred bytes between clients, customers
+and services will allow us to discover new efficiencies and reduce the
+operational risk. We want to better understand the data transfer
+patterns across the whole application stack.
+
+The goal of this blueprint to describe steps we need to do to achieve the result.
+
+### Goals
+
+Explore various solutions to store, process and present transfer data across the
+whole application stack.
+
+## Proposal
+
+There are different types of transferred data.
+
+| Type | Description |
+| --------------- | ----------------------------------------------------------- |
+| `Repository` | Egress data related to Git `fetch` operations (pull, clone) |
+| `Artifacts` | Artifacts transfer caused by direct and proxied egress |
+| `Pages` | Pages egress (depends on Artifacts API) |
+| `Packages` | Package registry egress |
+| `Registry` | Container registry egress |
+| `Uploads` | Object store egress |
+
+Each type has different implementations and can be measured separately but
+collection of metadata / data transfer telemetry and consuming / visualizing it,
+should be built on top of the same abstraction.
+
+## Overview
+
+```mermaid
+flowchart TB
+
+ A[Applications] -->|send logs| Pub(Google Pub/Sub)
+ Pub -->JSONParser
+
+
+ subgraph DataflowPipeline
+ direction TB
+
+ JSONParser -->|selects only JSON lines| LogProcessor
+ LogProcessor -->|insert only data transfer logs|ClickHouse
+ end
+
+ClickHouse -->|query transfer logs| Rails
+```
+
+### Applications
+
+Every application produces logs in structured format. Logs related
+to transfer data requests have metadata fields that include the
+number of bytes transferred, namespace, project, and timestamp
+of the egress event.
+
+### Google Pub/Sub
+
+Application logs are collected and sent to Google Pub/Sub.
+Pub/Sub allows to subscribe to topics and read incoming logs.
+
+### Dataflow pipeline
+
+[Dataflow](https://cloud.google.com/dataflow/docs/overview) is a Google
+Cloud unified stream and batch data processing that's serverless, fast
+, and cost-effective. It's built on the open-source
+[Apache Beam](https://beam.apache.org/) project.
+
+Dataflow pipeline provides a data processing abstraction that can be written
+in Java, Python or Go.
+
+The Dataflow pipeline is a core of the processing logic. It relies on the streaming
+implementation of Dataflow. The pipeline subscribes to Pub/Sub topics,
+reads, processes logs, and inserts them into ClickHouse database.
+
+### ClickHouse
+
+ClickHouse is designed to provide a fast access to work with massive
+data sets. It will allow customers to query aggregated data for
+dynamic timeframes.
+
+ClickHouse is an abstract store for logs. The Dataflow pipeline will
+transform different input sources into consistent structure to be
+stored in ClickHouse. That allows to support various inputs and formats
+without affecting ClickHouse-stored timeseries.
+
+ClickHouse table schema
+
+```sql
+CREATE TABLE transfer_data
+(
+ created_at DateTime,
+ bytes UInt64,
+ project String,
+ namespace String,
+ type String
+)
+ENGINE = MergeTree
+PRIMARY KEY (project, namespace)
+```
+
+`created_at` - a timestamp of the event
+`bytes` - a number of transferred bytes
+`project` - a full project path
+`namespace` - a root namespace of the project
+`type` - a type of egress (`git`, `container_registry`, ...)
+
+### Rails
+
+Rails application uses [a gem to connect and query ClickHouse](../../../development/database/clickhouse/clickhouse_within_gitlab.md).
+Customers will be able see their transfer data details in their dashboard.
+They can request a transfer data report for their whole namespace or
+for particular projects.
+
+## Implementation proposals
+
+- [Repository egress](repository.md)
diff --git a/doc/architecture/blueprints/transfer_data/repository.md b/doc/architecture/blueprints/transfer_data/repository.md
new file mode 100644
index 00000000000..7d3b6be8150
--- /dev/null
+++ b/doc/architecture/blueprints/transfer_data/repository.md
@@ -0,0 +1,67 @@
+---
+status: proposed
+creation-date: "2023-09-07"
+authors: [ "@vyaklushin" ]
+approvers: [ "@ofernandez2", "@sean_carroll" ]
+coach: ["@andrewn", "@grzesiek"]
+owning-stage: "~group::source_code"
+participating-stages: []
+---
+
+# Repository egress
+
+Users generate Repository egress events for every fetch operation in Git. It
+includes commands like `git clone`, `git fetch` and `git pull`, because all of
+them request data from Gitaly that needs to be delivered to the end user.
+
+Two main clients of Gitaly traffic are
+[GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell)(for SSH traffic)
+and
+[Workhorse](https://gitlab.com/gitlab-org/gitlab/-/tree/master/workhorse)
+(for HTTP traffic).
+
+Both clients send `git-upload-pack` command to Gitaly and stream back the
+Git response that contains requested changes.
+
+## Current metrics
+
+| Service | Number of `git-upload-pack` events (per day) |
+|--------------|----------------------------------------------|
+| Workhorse | ~80 million |
+| GitLab Shell | ~85 million |
+| Gitaly | ~165 million (combined traffic) |
+
+Kibana links to see current metrics for each service:
+
+- [Workhorse](https://log.gprd.gitlab.net/goto/cf799060-e2b2-11ed-8afc-c9851e4645c0)
+- [GitLab Shell](https://log.gprd.gitlab.net/goto/bd93f5c0-e2b2-11ed-a017-0d32180b1390)
+- [Gitaly](https://log.gprd.gitlab.net/goto/9221c230-e2b4-11ed-8afc-c9851e4645c0)
+
+Total number of events:
+
+- 165 million per day
+- 7.5 million per hour
+- 120 thousand per minute
+
+## Logs structure
+
+### HTTP traffic
+
+Captured in Workhorse logs.
+
+| Fields | Description |
+|---------------|-----------------------------|
+| written_bytes | number of bytes transferred |
+| uri | namespace and project name |
+| timestamp | timestamp of Egress event |
+
+### SSH traffic
+
+Captured in GitLab Shell logs.
+
+| Fields | Description |
+|---------------|-----------------------------|
+| written_bytes | number of bytes transferred |
+| project | full project name |
+| root_namspace | root namespace |
+| timestamp | timestamp of Egress event |
diff --git a/doc/architecture/blueprints/work_items/index.md b/doc/architecture/blueprints/work_items/index.md
index 9924b0db9f4..6f5b48fffcb 100644
--- a/doc/architecture/blueprints/work_items/index.md
+++ b/doc/architecture/blueprints/work_items/index.md
@@ -46,6 +46,9 @@ Work is underway to convert existing objects to Work Item Types or add new ones:
Every Work Item type has the following common properties:
+**NOTE:**
+You can also refer to fields of [Work Item](../../../api/graphql/reference/index.md#workitem) to learn more.
+
- `id` - a unique Work Item global identifier;
- `iid` - internal ID of the Work Item, relative to the parent workspace (currently workspace can only be a project)
- Work Item type;
@@ -63,20 +66,25 @@ All Work Item types share the same pool of predefined widgets and are customized
### Work Item widget types (updating)
-| widget type | feature flag |
-|---|---|
-| assignees | |
-| description | |
-| hierarchy | |
-| [iteration](https://gitlab.com/gitlab-org/gitlab/-/issues/367456) | |
-| [milestone](https://gitlab.com/gitlab-org/gitlab/-/issues/367463) | |
-| labels | |
-| start and due date | |
-| status\* | |
-| weight | |
-| [notes](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) | |
-
-\* status is not currently a widget, but a part of the root work item, similar to title
+| Widget | Description | feature flag |
+|---|---|---|
+| [WorkItemWidgetAssignees](../../../api/graphql/reference/index.md#workitemwidgetassignees) | List of work item assignees | |
+| [WorkItemWidgetAwardEmoji](../../../api/graphql/reference/index.md#workitemwidgetawardemoji) | Emoji reactions added to work item, including support for upvote/downvote counts | |
+| [WorkItemWidgetCurrentUserTodos](../../../api/graphql/reference/index.md#workitemwidgetcurrentusertodos) | User todo state of work item | |
+| [WorkItemWidgetDescription](../../../api/graphql/reference/index.md#workitemwidgetdescription) | Description of work item, including support for edited state, timestamp, and author | |
+| [WorkItemWidgetHealthStatus](../../../api/graphql/reference/index.md#workitemwidgethealthstatus) | Health status assignment support for work item | |
+| [WorkItemWidgetHierarchy](../../../api/graphql/reference/index.md#workitemwidgethierarchy) | Hierarchy of work items, including support for boolean representing presence of children. **Note:** Hierarchy is currently available only for OKRs. | `okrs_mvc` |
+| [WorkItemWidgetIteration](../../../api/graphql/reference/index.md#workitemwidgetiteration) | Iteration assignment support for work item | |
+| [WorkItemWidgetLabels](../../../api/graphql/reference/index.md#workitemwidgetlabels) | List of labels added to work items, including support for checking whether scoped labels are supported |
+| [WorkItemWidgetLinkedItems](../../../api/graphql/reference/index.md#workitemwidgetlinkeditems) | List of work items added as related to a given work item, with possible relationship types being `relates_to`, `blocks`, and `blocked_by`. Includes support for individual counts of blocked status, blocked by, blocking, and related to. | `linked_work_items` |
+| [WorkItemWidgetMilestone](../../../api/graphql/reference/index.md#workitemwidgetmilestone) | Milestone assignment support for work item | |
+| [WorkItemWidgetNotes](../../../api/graphql/reference/index.md#workitemwidgetnotes) | List of discussions within a work item | |
+| [WorkItemWidgetNotifications](../../../api/graphql/reference/index.md#workitemwidgetnotifications) | Notifications subscription status of a work item for current user | |
+| [WorkItemWidgetProgress](../../../api/graphql/reference/index.md#workitemwidgetprogress) | Progress value of a work item. **Note:** Progress is currently available only for OKRs. | `okrs_mvc` |
+| [WorkItemWidgetStartAndDueDate](../../../api/graphql/reference/index.md#workitemwidgetstartandduedate) | Set start and due dates for a work item | |
+| [WorkItemWidgetStatus](../../../api/graphql/reference/index.md#workitemwidgetstatus) | Status of a work item when type is Requirement, with possible status types being `unverified`, `satisfied`, or `failed` | |
+| [WorkItemWidgetTestReports](../../../api/graphql/reference/index.md#workitemwidgettestreports) | Test reports associated with a work item | |
+| [WorkItemWidgetWeight](../../../api/graphql/reference/index.md#workitemwidgetweight) | Set weight of a work item | |
### Work item relationships
diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md
index be5112251a4..7aeafce9352 100644
--- a/doc/ci/caching/index.md
+++ b/doc/ci/caching/index.md
@@ -535,7 +535,7 @@ and should only be disabled in an environment where all users with Developer rol
To use the same cache for all branches:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. Clear the **Use separate caches for protected branches** checkbox.
@@ -630,7 +630,7 @@ The next time the pipeline runs, the cache is stored in a different location.
You can clear the cache in the GitLab UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Build > Pipelines**.
1. In the upper-right corner, select **Clear runner caches**.
diff --git a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
index 7164fae10a1..1820cf77841 100644
--- a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
@@ -15,8 +15,8 @@ GitLab CI/CD can be used with Bitbucket Cloud by:
To use GitLab CI/CD with a Bitbucket Cloud repository:
1. In GitLab, create a project:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
- 1. Select **View all your projects**.
+ 1. On the left sidebar, select **Search or go to**.
+ 1. Select **View all my projects**.
1. On the right of the page, select **New project**.
1. Select **Run CI/CD for external repository**.
1. Select **Repository by URL**.
@@ -40,7 +40,7 @@ To use GitLab CI/CD with a Bitbucket Cloud repository:
using the Personal Access Token we just generated for authentication.
```plaintext
- https://gitlab.com/api/v4/projects/<PROJECT_ID>/mirror/pull?private_token=<PERSONAL_ACCESS_TOKEN>
+ https://gitlab.example.com/api/v4/projects/:project_id/mirror/pull?private_token=<your_personal_access_token>
```
The web hook Trigger should be set to 'Repository Push'.
diff --git a/doc/ci/ci_cd_for_external_repos/github_integration.md b/doc/ci/ci_cd_for_external_repos/github_integration.md
index 1fad7ad5a53..bc61990fcd8 100644
--- a/doc/ci/ci_cd_for_external_repos/github_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/github_integration.md
@@ -34,8 +34,8 @@ repositories:
`repo` and `admin:repo_hook` so that GitLab can access your project,
update commit statuses, and create a web hook to notify GitLab of new commits.
1. In GitLab, create a project:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
- 1. Select **View all your projects**.
+ 1. On the left sidebar, select **Search or go to**.
+ 1. Select **View all my projects**.
1. On the right of the page, select **New project**.
1. Select **Run CI/CD for external repository**.
1. Select **GitHub**.
@@ -63,8 +63,8 @@ To manually enable GitLab CI/CD for your repository:
1. Enter a **Token description** and update the scope to allow
`repo` so that GitLab can access your project and update commit statuses.
1. In GitLab, create a project:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
- 1. Select **View all your projects**.
+ 1. On the left sidebar, select **Search or go to**.
+ 1. Select **View all my projects**.
1. Select **New project**.
1. Select **Run CI/CD for external repository** and **Repository by URL**.
1. In the **Git repository URL** field, enter the HTTPS URL for your GitHub repository.
diff --git a/doc/ci/ci_cd_for_external_repos/index.md b/doc/ci/ci_cd_for_external_repos/index.md
index a9093632a8c..76996294a96 100644
--- a/doc/ci/ci_cd_for_external_repos/index.md
+++ b/doc/ci/ci_cd_for_external_repos/index.md
@@ -18,14 +18,14 @@ external repository to get the benefits of GitLab CI/CD.
Connecting an external repository sets up [repository mirroring](../../user/project/repository/mirror/index.md)
and creates a lightweight project with issues, merge requests, wiki, and
snippets disabled. These features
-[can be re-enabled later](../../user/project/settings/index.md#configure-project-visibility-features-and-permissions).
+[can be re-enabled later](../../user/project/settings/index.md#configure-project-features-and-permissions).
## Connect to an external repository
To connect to an external repository:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your projects**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my projects**.
1. Select **New project**.
1. Select **Run CI/CD for external repository**.
1. Select **GitHub** or **Repository by URL**.
@@ -33,7 +33,7 @@ To connect to an external repository:
If the **Run CI/CD for external repository** option is not available, the GitLab instance
might not have any import sources configured. Ask an administrator for your instance to check
-the [import sources configuration](../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources).
+the [import sources configuration](../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources).
## Pipelines for external pull requests
diff --git a/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md b/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md
index f50b7be855a..2a73184eb7f 100644
--- a/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md
+++ b/doc/ci/cloud_deployment/ecs/deploy_to_aws_ecs.md
@@ -17,7 +17,7 @@ Ensure your own [runners are configured](../../runners/index.md).
## Prerequisites
-- An [AWS account](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/).
+- An [AWS account](https://repost.aws/knowledge-center/create-and-activate-aws-account).
Sign in with an existing AWS account or create a new one.
- In this guide, you create an infrastructure in [`us-east-2` region](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html).
You can use any region, but do not change it after you begin.
diff --git a/doc/ci/cloud_services/aws/index.md b/doc/ci/cloud_services/aws/index.md
index f0183fc7ba2..dd36da86cca 100644
--- a/doc/ci/cloud_services/aws/index.md
+++ b/doc/ci/cloud_services/aws/index.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
WARNING:
`CI_JOB_JWT_V2` was [deprecated in GitLab 15.9](../../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated)
-and is scheduled to be removed in GitLab 16.5. Use [ID tokens](../../yaml/index.md#id_tokens) instead.
+and is scheduled to be removed in GitLab 17.0. Use [ID tokens](../../yaml/index.md#id_tokens) instead.
In this tutorial, we'll show you how to use a GitLab CI/CD job with a JSON web token (JWT) to retrieve temporary credentials from AWS without needing to store secrets.
To do this, you must configure OpenID Connect (OIDC) for ID federation between GitLab and AWS. For background and requirements for integrating GitLab using OIDC, see [Connect to cloud services](../index.md).
@@ -85,9 +85,12 @@ assume role:
- `ROLE_ARN`: The role ARN defined in this [step](#configure-a-role-and-trust).
- `GITLAB_OIDC_TOKEN`: An OIDC [ID token](../../yaml/index.md#id_tokens).
-## Working example
+## Working examples
-See this [reference project](https://gitlab.com/guided-explorations/aws/configure-openid-connect-in-aws) for provisioning OIDC in AWS using Terraform and a sample script to retrieve temporary credentials.
+- See this [reference project](https://gitlab.com/guided-explorations/aws/configure-openid-connect-in-aws) for provisioning OIDC in AWS using Terraform and a sample script to retrieve temporary credentials.
+- [OIDC and Multi-Account Deployment with GitLab and ECS](https://gitlab.com/guided-explorations/aws/oidc-and-multi-account-deployment-with-ecs).
+- AWS Partner (APN) Blog: [Setting up OpenID Connect with GitLab CI/CD](https://aws.amazon.com/blogs/apn/setting-up-openid-connect-with-gitlab-ci-cd-to-provide-secure-access-to-environments-in-aws-accounts/).
+- [GitLab at AWS re:Inforce 2023: Secure GitLab CD pipelines to AWS w/ OpenID and JWT](https://www.youtube.com/watch?v=xWQGADDVn8g).
## Troubleshooting
diff --git a/doc/ci/cloud_services/azure/index.md b/doc/ci/cloud_services/azure/index.md
index fa8ff506dd0..3a882cf6820 100644
--- a/doc/ci/cloud_services/azure/index.md
+++ b/doc/ci/cloud_services/azure/index.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
WARNING:
`CI_JOB_JWT_V2` was [deprecated in GitLab 15.9](../../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated)
-and is scheduled to be removed in GitLab 16.5. Use [ID tokens](../../yaml/index.md#id_tokens) instead.
+and is scheduled to be removed in GitLab 17.0. Use [ID tokens](../../yaml/index.md#id_tokens) instead.
This tutorial demonstrates how to use a JSON web token (JWT) in a GitLab CI/CD job
to retrieve temporary credentials from Azure without needing to store secrets.
@@ -135,7 +135,7 @@ The CI/CD variables are:
- `AZURE_CLIENT_ID`: The [application client ID you saved earlier](#create-azure-ad-application-and-service-principal).
- `AZURE_TENANT_ID`: Your Azure Active Directory. You can
- [find it by using the Azure CLI or Azure Portal](https://learn.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-how-to-find-tenant).
+ [find it by using the Azure CLI or Azure Portal](https://learn.microsoft.com/en-us/azure/active-directory/fundamentals/how-to-find-tenant).
- `GITLAB_OIDC_TOKEN`: An OIDC [ID token](../../yaml/index.md#id_tokens).
## Troubleshooting
diff --git a/doc/ci/cloud_services/google_cloud/index.md b/doc/ci/cloud_services/google_cloud/index.md
index f2318b818d8..a733f3d59cb 100644
--- a/doc/ci/cloud_services/google_cloud/index.md
+++ b/doc/ci/cloud_services/google_cloud/index.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
WARNING:
`CI_JOB_JWT_V2` was [deprecated in GitLab 15.9](../../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated)
-and is scheduled to be removed in GitLab 16.5. Use [ID tokens](../../yaml/index.md#id_tokens) instead.
+and is scheduled to be removed in GitLab 17.0. Use [ID tokens](../../yaml/index.md#id_tokens) instead.
This tutorial demonstrates authenticating to Google Cloud from a GitLab CI/CD job
using a JSON Web Token (JWT) token and Workload Identity Federation. This configuration
diff --git a/doc/ci/cloud_services/index.md b/doc/ci/cloud_services/index.md
index 6896fffcce7..87984c424c4 100644
--- a/doc/ci/cloud_services/index.md
+++ b/doc/ci/cloud_services/index.md
@@ -12,9 +12,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
WARNING:
`CI_JOB_JWT` and `CI_JOB_JWT_V2` were [deprecated in GitLab 15.9](../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated)
-and are scheduled to be removed in GitLab 16.5. Use [ID tokens](../yaml/index.md#id_tokens) instead.
+and are scheduled to be removed in GitLab 17.0. Use [ID tokens](../yaml/index.md#id_tokens) instead.
-GitLab CI/CD supports [OpenID Connect (OIDC)](https://openid.net/connect/faq/) to
+GitLab CI/CD supports [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/) to
give your build and deployment jobs access to cloud credentials and services.
Historically, teams stored secrets in projects or applied permissions on the GitLab Runner
instance to build and deploy. OIDC capable [ID tokens](../yaml/index.md#id_tokens) are configurable
diff --git a/doc/ci/components/catalog.md b/doc/ci/components/catalog.md
new file mode 100644
index 00000000000..2194e72d56c
--- /dev/null
+++ b/doc/ci/components/catalog.md
@@ -0,0 +1,33 @@
+---
+stage: Verify
+group: Pipeline Authoring
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# CI/CD catalog **(PREMIUM ALL EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/407249) in GitLab 16.1.
+
+The CI/CD catalog is a list of [components repositories](index.md#components-repository),
+each containing resources that you can add to your CI/CD pipelines.
+
+## Mark a components repository as a catalog resource
+
+After components are added to a components repository, they can immediately be [used](index.md#use-a-component-in-a-cicd-configuration)
+to build pipelines in other projects.
+
+However, this repository is not discoverable. You must mark this project as a catalog resource
+to allow it to be visible in the CI/CD Catalog so other users can discover it.
+
+To mark a project as a catalog resource:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Visibility, project features, permissions**.
+1. Scroll down to **CI/CD Catalog resource** and select the toggle to mark the project as a catalog resource.
+
+Ensure the project has a clear [description](../../user/project/settings/index.md#edit-project-name-and-description),
+as the project description is displayed in the component list in the catalog.
+
+NOTE:
+This action is not reversible.
diff --git a/doc/ci/components/index.md b/doc/ci/components/index.md
index 4a739bdfcf6..e73436522dc 100644
--- a/doc/ci/components/index.md
+++ b/doc/ci/components/index.md
@@ -2,29 +2,32 @@
stage: Verify
group: Pipeline Authoring
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-type: reference
---
-# CI/CD Components (Experimental)
+# CI/CD components **(FREE ALL EXPERIMENT)**
> - Introduced as an [experimental feature](../../policy/experiment-beta-support.md) in GitLab 16.0, [with a flag](../../administration/feature_flags.md) named `ci_namespace_catalog_experimental`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/groups/gitlab-org/-/epics/9897) in GitLab 16.2.
-> - [Feature flag `ci_namespace_catalog_experimental` removed.](https://gitlab.com/gitlab-org/gitlab/-/issues/394772) in GitLab 16.3.
+> - [Feature flag `ci_namespace_catalog_experimental` removed](https://gitlab.com/gitlab-org/gitlab/-/issues/394772) in GitLab 16.3.
This feature is an experimental feature and [an epic exists](https://gitlab.com/groups/gitlab-org/-/epics/9897)
to track future work. Tell us about your use case by leaving comments in the epic.
-## Components Repository
+## Components repository
-A components repository is a GitLab project with a repository that hosts one or more pipeline components. A pipeline component is a reusable single pipeline configuration unit. You can use them to compose an entire pipeline configuration or a small part of a larger pipeline. It can optionally take [input parameters](../yaml/includes.md#define-input-parameters-with-specinputs).
+A components repository is a GitLab project with a repository that hosts one or more pipeline components.
+A pipeline component is a reusable single pipeline configuration unit. Use them to compose
+an entire pipeline configuration or a small part of a larger pipeline.
-### Create a components repository
+A component can optionally take [input parameters](../yaml/inputs.md).
+
+## Create a components repository
To create a components repository, you must:
1. [Create a new project](../../user/project/index.md#create-a-blank-project) with a `README.md` file.
-
-1. Create a `template.yml` file inside the project's root directory that contains the configuration you want to provide as a component. For example:
+1. Create a `template.yml` file inside the project's root directory that contains the configuration you want to provide as a component.
+ For example:
```yaml
spec:
@@ -39,14 +42,71 @@ To create a components repository, you must:
### Directory structure
-A components repository can host one or more components.
+A components repository can host one or more components, and must follow a mandatory file structure.
+
+Component configurations can be saved through the following directory structure, containing:
+
+- A `templates` directory at the top level of your components repository. All component configuration files
+ should be saved under this directory.
+- Files ending in `.yml` containing the component configurations, one file per component.
+- A Markdown `README.md` file explaining the details of all the components in the repository.
+
+For example, if the project contains a single component and a pipeline to test the component,
+the file structure should be similar to:
+
+```plaintext
+├── templates/
+│ └── only_template.yml
+├── README.md
+└── .gitlab-ci.yml
+```
+
+This example component could be referenced with a path similar to `gitlab.com/my-username/my-component/only_template@<version>`,
+if the project is:
+
+- On GitLab.com
+- Named `my-component`
+- In a personal namespace named `my-username`
+
+The templates directory and the suffix of the configuration file should be excluded from the referenced path.
+
+If the project contains multiple components, then the file structure should be similar to:
+
+```plaintext
+├── README.md
+├── .gitlab-ci.yml
+└── templates/
+ └── all-scans.yml
+ └── secret-detection.yml
+```
+
+These components would be referenced with these paths:
-Components repositories must follow a mandatory file structure, containing:
+- `gitlab.com/my-username/my-component/all-scans`
+- `gitlab.com/my-username/my-component/secret-detection`
+
+You can omit the filename in the path if the configuration file is named `template.yml`.
+For example, the following component could be referenced with `gitlab.com/my-username/my-component/dast`:
+
+```plaintext
+├── README.md
+├── .gitlab-ci.yml
+├── templates/
+│ └── dast
+│ └── template.yml
+```
+
+#### Component configurations saved in any directory (deprecated)
+
+NOTE:
+Saving component configurations through this directory structure is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/415855).
+
+Components configurations can be saved through the following directory structure, containing:
- `template.yml`: The component configuration, one file per component. If there is
only one component, this file can be in the root of the project. If there are multiple
components, each file must be in a separate subdirectory.
-- `README.md`: A documentation file explaining the details of the all the components in the repository.
+- `README.md`: A documentation file explaining the details of all the components in the repository.
For example, if the project is on GitLab.com, named `my-component`, and in a personal
namespace named `my-username`:
@@ -60,6 +120,9 @@ namespace named `my-username`:
└── .gitlab-ci.yml
```
+ The `.gitlab-ci.yml` file is not required for a CI/CD component to work, but
+ [testing the component](#test-the-component) in a pipeline in the project is recommended.
+
This component is referenced with the path `gitlab.com/my-username/my-component@<version>`.
- Containing one default component and multiple sub-components, then the file structure
@@ -95,279 +158,281 @@ Nesting of components is not possible. For example:
│ └── nested_template.yml
```
-### Test a component
+## Release a component
+
+To create a release for a CI/CD component, use either:
+
+- The [`release`](../yaml/index.md#release) keyword in a CI/CD pipeline. Like in the
+ [component testing example](#test-the-component), you can set a component to automatically
+ be released after all tests pass in pipelines for new tags.
+- The [UI for creating a release](../../user/project/releases/index.md#create-a-release).
+
+All released versions of the components are displayed in the CI/CD Catalog
+page for the given resource, providing users with information about official releases.
-Testing components as part of the development workflow to ensure that quality maintains high standards is strongly recommended.
+Components [can be used](#use-a-component-in-a-cicd-configuration) without being released,
+but only with a commit SHA or a branch name. To enable the use of tags or the `~latest` version keyword,
+you must create a release.
-Testing changes in a CI/CD pipeline can be done, like any other project, by creating a `.gitlab-ci.yml` in the root directory.
+## Use a component in a CI/CD configuration
+You can add a component to a CI/CD configuration with the `include: component` keyword.
For example:
```yaml
include:
- # include the component located in the current project from the current SHA
- - component: gitlab.com/$CI_PROJECT_PATH@$CI_COMMIT_SHA
+ - component: gitlab.example.com/my-namespace/my-component@1.0
inputs:
stage: build
-
-stages: [build, test, release]
-
-# Expect `component-job` is added.
-# This is an example of testing that the included component works as expected.
-# You can leverage GitLab API endpoints or 3rd party tools to inspect data generated by the component.
-ensure-job-added:
- stage: test
- image: badouralix/curl-jq
- script:
- - |
- route="https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/pipelines/$CI_PIPELINE_ID/jobs"
- count=`curl --silent --header "PRIVATE-TOKEN: $API_TOKEN" $route | jq 'map(select(.name | contains("component-job"))) | length'`
- if [ "$count" != "1" ]; then
- exit 1
- fi
-
-# If we are tagging a release with a specific convention ("v" + number) and all
-# previous checks succeeded, we proceed with creating a release automatically.
-create-release:
- stage: release
- image: registry.gitlab.com/gitlab-org/release-cli:latest
- rules:
- - if: $CI_COMMIT_TAG =~ /^v\d+/
- script: echo "Creating release $CI_COMMIT_TAG"
- release:
- tag_name: $CI_COMMIT_TAG
- description: "Release $CI_COMMIT_TAG of components repository $CI_PROJECT_PATH"
```
-After committing and pushing changes, the pipeline tests the component then releases it if the test passes.
+The component is identified by a unique address in the form `<fully-qualified-domain-name>/<component-path>@<specific-version>`,
+where:
-### Release a component
+- `<fully-qualified-domain-name>` matches the GitLab host. You can only reference components
+ in the same GitLab instance as your project.
+- `<component-path>` is the component project's full path and directory where the
+ component YAML file is located.
+- `<specific-version>` is the version of the component. In order of highest priority first,
+ the version can be:
+ - A branch name, for example `main`.
+ - A commit SHA, for example `e3262fdd0914fa823210cdb79a8c421e2cef79d8`.
+ - A tag, for example: `1.0`. If a tag and branch exist with the same name, the tag
+ takes precedence over the branch. If a tag and commit SHA exist with the same name,
+ the commit SHA takes precedence over the tag.
+ - `~latest`, which is a special version that always points to the most recent released tag.
+ Available only if the component has been [released](#release-a-component).
-Component repositories are released using the [`release`](../yaml/index.md#release) keyword within a CI pipeline.
+For example, for a component repository located at `gitlab-org/dast` on `gitlab.com`,
+the path:
-Like in the [example above](#test-a-component), after all tests pass in a pipeline running for a tag ref, we can release a new version of the components repository.
+- `gitlab.com/gitlab-org/dast@main` targets the `template.yml` in the root directory
+ on the `main` branch.
+- `gitlab.com/gitlab-org/dast@e3262fdd0914fa823210cdb79a8c421e2cef79d8` targets the same file
+ for the specified commit SHA.
+- `gitlab.com/gitlab-org/dast@1.0` targets the same file for the `1.0` tag.
+- `gitlab.com/gitlab-org/dast@~latest` targets the same file for the latest release.
+- `gitlab.com/gitlab-org/dast/api-scan@main` targets a different file, the `template.yml`
+ in the `/api-scan` directory in the component repository, for the `main` branch.
-All released versions of the components repository are displayed in the Components Catalog page for the given resource, providing users with information about official releases.
+## Best practices
-### Use a component in a CI/CD configuration
+### Avoid using global keywords
-A pipeline component is identified by a unique address in the form `<fully-qualified-doman-name>/<component-path>@<version>`
-containing:
+Avoid using [global keywords](../yaml/index.md#global-keywords) in a component.
+Using these keywords in a component affects all jobs in a pipeline, including jobs
+directly defined in the main `.gitlab-ci.yml` or in other included components.
-- **A fully qualified domain name (FQDN)**: The FQDN must match the GitLab host.
-- **A specific version**: The version of the component can be (in order of highest priority first):
- - A commit SHA, for example `gitlab.com/gitlab-org/dast@e3262fdd0914fa823210cdb79a8c421e2cef79d8`.
- - A tag. for example: `gitlab.com/gitlab-org/dast@1.0`.
- - `~latest`, which is a special version that always points to the most recent released tag,
- for example `gitlab.com/gitlab-org/dast@~latest`.
- - A branch name, for example `gitlab.com/gitlab-org/dast@main`.
-- **A component path**: Contains the project's full path and the directory where the component YAML file `template.yml` is located.
+As an alternative to global keywords, instead:
-For example, for a component repository located at `gitlab-org/dast` on `gitlab.com`:
+- Add the configuration directly to each job, even if it creates some duplication
+ in the component configuration.
+- Use the [`extends`](../yaml/index.md#extends) keyword in the component.
-- The path `gitlab.com/gitlab-org/dast` tries to load the `template.yml` from the root directory.
-- The path `gitlab.com/gitlab-org/dast/api-scan` tries to load the `template.yml` from the `/api-scan` directory.
+For example, using the `default` keyword is not recommended:
-**Additional notes:**
+```yaml
+# Not recommended
+default:
+ image: ruby:3.0
-- You can only reference components in the same GitLab instance as your project.
-- If a tag and branch exist with the same name, the tag takes precedence over the branch.
-- If a tag is named the same as a commit SHA that exists, like `e3262fdd0914fa823210cdb79a8c421e2cef79d8`,
- the commit SHA takes precedence over the tag.
+rspec-1:
+ script: bundle exec rspec dir1/
-### Best practices
+rspec-2:
+ script: bundle exec rspec dir2/
+```
-#### Avoid using global keywords
+Instead, you can:
-When using [global keywords](../yaml/index.md#global-keywords) all jobs in the
-pipeline are affected. Using these keywords in a component affects all jobs in a
-pipeline, whether they are directly defined in the main `.gitlab-ci.yml` or
-in any included components.
+- Add the configuration to each job:
-To make the composition of pipelines more deterministic, either:
+ ```yaml
+ rspec-1:
+ image: ruby:3.0
+ script: bundle exec rspec dir1/
-- Duplicate the default configuration for each job.
-- Use [`extends`](../yaml/index.md#extends) feature within the component.
+ rspec-2:
+ image: ruby:3.0
+ script: bundle exec rspec dir2/
+ ```
-```yaml
-##
-# BAD
-default:
- image: ruby:3.0
+- Use `extends` to reuse configuration:
-rspec:
- script: bundle exec rspec
-```
+ ```yaml
+ .rspec-image:
+ image: ruby:3.0
-```yaml
-##
-# GOOD
-rspec:
- image: ruby:3.0
- script: bundle exec rspec
-```
+ rspec-1:
+ extends:
+ - .rspec-image
+ script: bundle exec rspec dir1/
-#### Replace hard-coded values with inputs
+ rspec-2:
+ extends:
+ - .rspec-image
+ script: bundle exec rspec dir2/
+ ```
-A typical hard-coded value found in CI templates is `stage:` value. Such hard coded values may force the user
-of the component to know and adapt the pipeline to such implementation details.
+### Replace hard-coded values with inputs
-For example, if `stage: test` is hard-coded for a job in a component, the pipeline using the component must
-define the `test` stage. Additionally, if the user of the component want to customize the stage value it has
-to override the configuration:
+Avoid hard-coding values in CI/CD components. Hard-coded values might force
+component users to need to review the component's internal details and adapt their pipeline
+to work with the component.
-```yaml
-##
-# BAD: In order to use different stage name you need to override all the jobs
-# included by the component.
-include:
- - component: gitlab.com/gitlab-org/ruby-test@1.0
+A common keyword with problematic hard-coded values is `stage`. If a component job's
+stage is set to a specific value, the pipeline using the component **must** define
+the exact same stage. Additionally, if the component user wants to use a different stage,
+they must [override](../yaml/includes.md#override-included-configuration-values) the configuration.
-stages: [verify, deploy]
+The preferred method is to use the [`input` keyword](../yaml/inputs.md).
+The component user can specify the exact value they need.
-unit-test:
- stage: verify
+For example:
-integration-test:
- stage: verify
-```
+- In the component configuration:
-```yaml
-##
-# BAD: In order to use the component correctly you need to define the stage
-# that is hard-coded in it.
-include:
- - component: gitlab.com/gitlab-org/ruby-test@1.0
+ ```yaml
+ spec:
+ inputs:
+ stage:
+ default: test
+ ---
+ unit-test:
+ stage: $[[ inputs.stage ]]
+ script: echo unit tests
+
+ integration-test:
+ stage: $[[ inputs.stage ]]
+ script: echo integration tests
+ ```
-stages: [test, deploy]
-```
+- In the project using the component:
-To improve this we can use [input parameters](../yaml/includes.md#define-input-parameters-with-specinputs)
-allowing the user of a component to inject values that can be customized:
+ ```yaml
+ include:
+ - component: gitlab.com/gitlab-org/ruby-test@1.0
+ inputs:
+ stage: verify
-```yaml
-##
-# GOOD: We don't need to know the implementation details of a component and instead we can
-# rely on the inputs.
-include:
- - component: gitlab.com/gitlab-org/ruby-test@1.0
- inputs:
- stage: verify
+ stages: [verify, deploy]
+ ```
-stages: [verify, deploy]
+### Replace custom CI/CD variables with inputs
-##
-# inside the component YAML:
-spec:
- inputs:
- stage:
- default: test
----
-unit-test:
- stage: $[[ inputs.stage ]]
- script: echo unit tests
+When using CI/CD variables in a component, evaluate if the `inputs` keyword
+should be used instead. Avoid requiring a user to define custom variables to change a component's
+behavior. You should try to use `inputs` for any component customization.
-integration-test:
- stage: $[[ inputs.stage ]]
- script: echo integration tests
-```
+Inputs are explicitly defined in the component's specs, and are better validated than variables.
+For example, if a required input is not passed to the component, GitLab returns a pipeline error.
+By contrast, if a variable is not defined, its value is empty, and there is no error.
-#### Prefer inputs over variables
+For example, use `inputs` instead of variables to let users change a scanner's output format:
-If variables are only used for YAML evaluation (for example `rules`) and not by the Runner
-execution, it's advised to use inputs instead.
-Inputs are explicitly defined in the component's contract and they are better validated
-than variables.
+- In the component configuration:
-For example, if a required input is not passed an error is returned as soon as the component
-is being used. By contrast, if a variable is not defined, it's value is empty.
+ ```yaml
+ spec:
+ inputs:
+ scanner-output:
+ default: json
+ ---
+ my-scanner:
+ script: my-scan --output $[[ inputs.scanner-output ]]
+ ```
-```yaml
-##
-# BAD: you need to configure an environment variable for a custom value that doesn't need
-# to be used on the Runner
-unit-test:
- image: $MY_COMPONENT_X_IMAGE
- script: echo unit tests
-
-integration-test:
- image: $MY_COMPONENT_X_IMAGE
- script: echo integration tests
-
-##
-# Usage:
-include:
- - component: gitlab.com/gitlab-org/ruby-test@1.0
+- In the project using the component:
-variables:
- MY_COMPONENT_X_IMAGE: ruby:3.2
-```
+ ```yaml
+ include:
+ - component: gitlab.example.com/my-scanner@1.0
+ inputs:
+ scanner-output: yaml
+ ```
-```yaml
-##
-# GOOD: we define a customizable value and accept it as input
-spec:
- inputs:
- image:
- default: ruby:3.0
----
-unit-test:
- image: $[[ inputs.image ]]
- script: echo unit tests
+In other cases, CI/CD variables are still preferred, including:
-integration-test:
- image: $[[ inputs.image ]]
- script: echo integration tests
+- Using [predefined variables](../variables/predefined_variables.md) to automatically configure
+ a component to match a user's project.
+- Requiring tokens or other sensitive values to be stored as [masked or protected variables in project settings](../variables/index.md#define-a-cicd-variable-in-the-ui).
-##
-# Usage:
-include:
- - component: gitlab.com/gitlab-org/ruby-test@1.0
- inputs:
- image: ruby:3.2
-```
+### Use semantic versioning
-#### Use semantic versioning
+When tagging and releasing new versions of components, you should use [semantic versioning](https://semver.org).
+Semantic versioning is the standard for communicating that a change is a major, minor, patch,
+or other kind of change.
-When tagging and releasing new versions of components we recommend using [semantic versioning](https://semver.org)
-which is the standard for communicating bugfixes, minor and major or breaking changes.
+You should use at least the `major.minor` format, as this is widely understood. For example,
+`2.0` or `2.1`.
-We recommend adopting at least the `MAJOR.MINOR` format.
+Other examples of semantic versioning:
-For example: `2.1`, `1.0.0`, `1.0.0-alpha`, `2.1.3`, `3.0.0-rc.1`.
+- `1.0.0`
+- `2.1.3`
+- `1.0.0-alpha`
+- `3.0.0-rc1`
-## CI/CD Catalog **(PREMIUM ALL)**
+### Test the component
-The CI/CD Catalog is a list of [components repositories](#components-repository),
-each containing resources that you can add to your CI/CD pipelines.
+Testing CI/CD components as part of the development workflow is strongly recommended
+and helps ensure consistent behavior.
-### Mark the project as a catalog resource
+Test changes in a CI/CD pipeline (like any other project) by creating a `.gitlab-ci.yml`
+in the root directory.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/407249) in GitLab 16.1.
+For example:
-After components are added to a components repository, they can immediately be [used](#use-a-component-in-a-cicd-configuration) to build pipelines in other projects.
+```yaml
+include:
+ # include the component located in the current project from the current SHA
+ - component: gitlab.com/$CI_PROJECT_PATH@$CI_COMMIT_SHA
+ inputs:
+ stage: build
-However, this repository is not discoverable. You must mark this project as a catalog resource to allow it to be visible in the CI Catalog
-so other users can discover it.
+stages: [build, test, release]
-To mark a project as a catalog resource:
+# Expect `component-job` is added.
+# This example tests that the included component works as expected.
+# You can inspect data generated by the component, use GitLab API endpoints or third-party tools.
+ensure-job-added:
+ stage: test
+ image: badouralix/curl-jq
+ script:
+ - |
+ route="https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/pipelines/$CI_PIPELINE_ID/jobs"
+ count=`curl --silent --header "PRIVATE-TOKEN: $API_TOKEN" $route | jq 'map(select(.name | contains("component-job"))) | length'`
+ if [ "$count" != "1" ]; then
+ exit 1
+ fi
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. On the left sidebar, select **Settings > General**.
-1. Expand **Visibility, project features, permissions**.
-1. Scroll down to **CI/CD Catalog resource** and select the toggle to mark the project as a catalog resource.
+# If we are tagging a release with a specific convention ("v" + number) and all
+# previous checks succeeded, we proceed with creating a release automatically.
+create-release:
+ stage: release
+ image: registry.gitlab.com/gitlab-org/release-cli:latest
+ rules:
+ - if: $CI_COMMIT_TAG =~ /^v\d+/
+ script: echo "Creating release $CI_COMMIT_TAG"
+ release:
+ tag_name: $CI_COMMIT_TAG
+ description: "Release $CI_COMMIT_TAG of components repository $CI_PROJECT_PATH"
+```
-NOTE:
-This action is not reversible.
+After committing and pushing changes, the pipeline tests the component, then releases it if the test passes.
-## Convert a CI template to component
+## Convert a CI/CD template to a component
-Any existing CI template, that you share with other projects via `include:` syntax, can be converted to a CI component.
+Any existing CI/CD template that you use in projects by using the `include:` syntax
+can be converted to a CI/CD component:
-1. Decide whether you want the component to be part of an existing [components repository](#components-repository),
- if you want to logically group components together. Create and setup a [components repository](#components-repository) otherwise.
-1. Create a YAML file in the components repository according to the expected [directory structure](#directory-structure).
-1. Copy the content of the template YAML file into the new component YAML file.
-1. Refactor the component YAML to follow the [best practices](#best-practices) for components.
-1. Leverage the `.gitlab-ci.yml` in the components repository to [test changes to the component](#test-a-component).
-1. Tag and [release the component](#release-a-component).
+1. Decide if you want the component to be part of an existing [components repository](index.md#components-repository)
+ to be grouped with other components, or create and set up a new components repository.
+1. Create a YAML file in the components repository according to the expected [directory structure](index.md#directory-structure).
+1. Copy the content of the original template YAML file into the new component YAML file.
+1. Refactor the new component's configuration to:
+ - Follow the [best practices](index.md#best-practices) for components.
+ - Improve the configuration, for example by enabling [merge request pipelines](../pipelines/merge_request_pipelines.md)
+ or making it [more efficient](../pipelines/pipeline_efficiency.md).
+1. Leverage the `.gitlab-ci.yml` in the components repository to [test changes to the component](index.md#test-the-component).
+1. Tag and [release the component](index.md#release-a-component).
diff --git a/doc/ci/docker/authenticate_registry.md b/doc/ci/docker/authenticate_registry.md
index 52cc3071fda..28edb5140dd 100644
--- a/doc/ci/docker/authenticate_registry.md
+++ b/doc/ci/docker/authenticate_registry.md
@@ -18,9 +18,9 @@ login`:
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
services:
- - docker:20.10.16-dind
+ - docker:24.0.5-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
@@ -42,7 +42,7 @@ empty or remove it.
If you are an administrator for GitLab Runner, you can mount a file
with the authentication configuration to `~/.docker/config.json`.
Then every job that the runner picks up is already authenticated. If you
-are using the official `docker:20.10.16` image, the home directory is
+are using the official `docker:24.0.5` image, the home directory is
under `/root`.
If you mount the configuration file, any `docker` command
@@ -126,9 +126,9 @@ The same commands apply for any solution you implement.
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
services:
- - docker:20.10.16-dind
+ - docker:24.0.5-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
diff --git a/doc/ci/docker/buildah_rootless_tutorial.md b/doc/ci/docker/buildah_rootless_tutorial.md
new file mode 100644
index 00000000000..fdb33fd4a8b
--- /dev/null
+++ b/doc/ci/docker/buildah_rootless_tutorial.md
@@ -0,0 +1,149 @@
+---
+stage: Verify
+group: Pipeline Execution
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: howto
+---
+
+# Tutorial: Use Buildah in a rootless container with GitLab Runner Operator on OpenShift **(FREE)**
+
+This tutorial teaches you how to successfully build images using the `buildah` tool,
+with GitLab Runner deployed using [GitLab Runner Operator](https://gitlab.com/gitlab-org/gl-openshift/gitlab-runner-operator)
+on an OpenShift cluster.
+
+This guide is an adaptation of [using Buildah to build images in a rootless OpenShift container](https://github.com/containers/buildah/blob/main/docs/tutorials/05-openshift-rootless-build.md)
+documentation for GitLab Runner Operator.
+
+To complete this tutorial, you will:
+
+1. [Configure the Buildah image](#configure-the-buildah-image)
+1. [Configure the service account](#configure-the-service-account)
+1. [Configure the job](#configure-the-job)
+
+## Prerequisites
+
+- A runner already deployed to a `gitlab-runner` namespace.
+
+## Configure the Buildah image
+
+We start by preparing a custom image based on the `quay.io/buildah/stable:v1.23.1` image.
+
+1. Create the `Containerfile-buildah` file:
+
+ ```shell
+ cat > Containerfile-buildah <<EOF
+ FROM quay.io/buildah/stable:v1.23.1
+
+ RUN touch /etc/subgid /etc/subuid \
+ && chmod g=u /etc/subgid /etc/subuid /etc/passwd \
+ && echo build:10000:65536 > /etc/subuid \
+ && echo build:10000:65536 > /etc/subgid
+
+ # Use chroot since the default runc does not work when running rootless
+ RUN echo "export BUILDAH_ISOLATION=chroot" >> /home/build/.bashrc
+
+ # Use VFS since fuse does not work
+ RUN mkdir -p /home/build/.config/containers \
+ && (echo '[storage]';echo 'driver = "vfs"') > /home/build/.config/containers/storage.conf
+
+ # The buildah container will run as `build` user
+ USER build
+ WORKDIR /home/build
+ EOF
+ ```
+
+1. Build and push the Buildah image to a Container Registry. Let's push to the
+ [GitLab Container Registry](../../user/packages/container_registry/index.md):
+
+ ```shell
+ docker build -f Containerfile-buildah -t registry.example.com/group/project/buildah:1.23.1 .
+ docker push registry.example.com/group/project/buildah:1.23.1
+ ```
+
+## Configure the service account
+
+For these steps, you need to run the commands in a terminal connected to the OpenShift cluster.
+
+1. Run this command to create a service account named `buildah-sa`:
+
+ ```shell
+ oc create -f - <<EOF
+ apiVersion: v1
+ kind: ServiceAccount
+ metadata:
+ name: buildah-sa
+ namespace: gitlab-runner
+ EOF
+ ```
+
+1. Give the created service account the ability to run with `anyuid` [SCC](https://docs.openshift.com/container-platform/4.3/authentication/managing-security-context-constraints.html):
+
+ ```shell
+ oc adm policy add-scc-to-user anyuid -z buildah-sa -n gitlab-runner
+ ```
+
+1. Use a [runner configuration template](https://docs.gitlab.com/runner/configuration/configuring_runner_operator.html#customize-configtoml-with-a-configuration-template)
+ to configure Operator to use the service account we just created. Create a `custom-config.toml` file that contains:
+
+ ```toml
+ [[runners]]
+ [runners.kubernetes]
+ service_account_overwrite_allowed = "buildah-*"
+ ```
+
+1. Create a `ConfigMap` named `custom-config-toml` from the `custom-config.toml` file:
+
+ ```shell
+ oc create configmap custom-config-toml --from-file config.toml=custom-config.toml -n gitlab-runner
+ ```
+
+1. Set the `config` property of the `Runner` by updating its [Custom Resource Definition (CRD) file](https://docs.gitlab.com/runner/install/operator.html#install-gitlab-runner):
+
+ ```yaml
+ apiVersion: apps.gitlab.com/v1beta2
+ kind: Runner
+ metadata:
+ name: builah-runner
+ spec:
+ gitlabUrl: https://gitlab.example.com
+ token: gitlab-runner-secret
+ config: custom-config-toml
+ ```
+
+## Configure the job
+
+The final step is to set up a GitLab CI/CD configuration file in you project to use
+the image we built and the configured service account:
+
+```yaml
+build:
+ stage: build
+ image: registry.example.com/group/project/buildah:1.23.1
+ variables:
+ STORAGE_DRIVER: vfs
+ BUILDAH_FORMAT: docker
+ BUILDAH_ISOLATION: chroot
+ FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/test"
+ KUBERNETES_SERVICE_ACCOUNT_OVERWRITE: "buildah-sa"
+ before_script:
+ # Log in to the GitLab container registry
+ - buildah login -u "$CI_REGISTRY_USER" --password $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ script:
+ - buildah images
+ - buildah build -t $FQ_IMAGE_NAME
+ - buildah images
+ - buildah push $FQ_IMAGE_NAME
+```
+
+The job should use the image that we built as the value of `image` keyword.
+
+The `KUBERNETES_SERVICE_ACCOUNT_OVERWRITE` variable should have the value of the
+service account name that we created.
+
+Congratulations, you've successfully built an image with Buildah in a rootless container!
+
+## Troubleshooting
+
+There is a [known issue](https://github.com/containers/buildah/issues/4049) with running as non-root.
+You might need to use a [workaround](https://docs.gitlab.com/runner/configuration/configuring_runner_operator.html#configure-setfcap)
+if you are using an OpenShift runner.
diff --git a/doc/ci/docker/docker_layer_caching.md b/doc/ci/docker/docker_layer_caching.md
index 861bea70cb7..b34b58ce964 100644
--- a/doc/ci/docker/docker_layer_caching.md
+++ b/doc/ci/docker/docker_layer_caching.md
@@ -29,9 +29,9 @@ This example `.gitlab-ci.yml` file shows how to use Docker caching:
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
services:
- - docker:20.10.16-dind
+ - docker:24.0.5-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index fb38de0f7de..269ce2c3212 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -80,7 +80,8 @@ For more information, see [security of the `docker` group](https://blog.zopyx.co
"Docker-in-Docker" (`dind`) means:
-- Your registered runner uses the [Docker executor](https://docs.gitlab.com/runner/executors/docker.html) or the [Kubernetes executor](https://docs.gitlab.com/runner/executors/kubernetes.html).
+- Your registered runner uses the [Docker executor](https://docs.gitlab.com/runner/executors/docker.html) or
+ the [Kubernetes executor](https://docs.gitlab.com/runner/executors/kubernetes.html).
- The executor uses a [container image of Docker](https://hub.docker.com/_/docker/), provided
by Docker, to run your CI/CD jobs.
@@ -90,7 +91,7 @@ the job script in context of the image in privileged mode.
You should use Docker-in-Docker with TLS enabled,
which is supported by [GitLab.com shared runners](../runners/index.md).
-You should always pin a specific version of the image, like `docker:20.10.16`.
+You should always pin a specific version of the image, like `docker:24.0.5`.
If you use a tag like `docker:latest`, you have no control over which version is used.
This can cause incompatibility problems when new versions are released.
@@ -121,12 +122,12 @@ To use Docker-in-Docker with TLS enabled:
--registration-token REGISTRATION_TOKEN \
--executor docker \
--description "My Docker Runner" \
- --docker-image "docker:20.10.16" \
+ --docker-image "docker:24.0.5" \
--docker-privileged \
--docker-volumes "/certs/client"
```
- - This command registers a new runner to use the `docker:20.10.16` image.
+ - This command registers a new runner to use the `docker:24.0.5` image (if none is specified at the job level).
To start the build and service containers, it uses the `privileged` mode.
If you want to use Docker-in-Docker,
you must always use `privileged = true` in your Docker containers.
@@ -143,7 +144,7 @@ To use Docker-in-Docker with TLS enabled:
executor = "docker"
[runners.docker]
tls_verify = false
- image = "docker:20.10.16"
+ image = "docker:24.0.5"
privileged = true
disable_cache = false
volumes = ["/certs/client", "/cache"]
@@ -153,13 +154,13 @@ To use Docker-in-Docker with TLS enabled:
```
1. You can now use `docker` in the job script. You should include the
- `docker:20.10.16-dind` service:
+ `docker:24.0.5-dind` service:
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
services:
- - docker:20.10.16-dind
+ - docker:24.0.5-dind
before_script:
- docker info
@@ -202,7 +203,7 @@ Assuming that the runner's `config.toml` is similar to:
executor = "docker"
[runners.docker]
tls_verify = false
- image = "docker:20.10.16"
+ image = "docker:24.0.5"
privileged = true
disable_cache = false
volumes = ["/cache"]
@@ -212,13 +213,13 @@ Assuming that the runner's `config.toml` is similar to:
```
You can now use `docker` in the job script. You should include the
-`docker:20.10.16-dind` service:
+`docker:24.0.5-dind` service:
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
services:
- - docker:20.10.16-dind
+ - docker:24.0.5-dind
before_script:
- docker info
@@ -276,13 +277,13 @@ To use Docker-in-Docker with TLS enabled in Kubernetes:
```
1. You can now use `docker` in the job script. You should include the
- `docker:20.10.16-dind` service:
+ `docker:24.0.5-dind` service:
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
services:
- - docker:20.10.16-dind
+ - docker:24.0.5-dind
before_script:
- docker info
@@ -330,7 +331,7 @@ Docker-in-Docker is the recommended configuration, but you should be aware of th
- **Storage drivers**: By default, earlier versions of Docker use the `vfs` storage driver,
which copies the file system for each job. Docker 17.09 and later use `--storage-driver overlay2`, which is
the recommended storage driver. See [Using the OverlayFS driver](#use-the-overlayfs-driver) for details.
-- **Root file system**: Because the `docker:20.10.16-dind` container and the runner container do not share their
+- **Root file system**: Because the `docker:24.0.5-dind` container and the runner container do not share their
root file system, you can use the job's working directory as a mount point for
child containers. For example, if you have files you want to share with a
child container, you could create a subdirectory under `/builds/$CI_PROJECT_PATH`
@@ -352,7 +353,7 @@ container. Docker is then available in the context of the image.
If you bind the Docker socket and you are
[using GitLab Runner 11.11 or later](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/1261),
-you can no longer use `docker:20.10.16-dind` as a service. Volume bindings also affect services,
+you can no longer use `docker:24.0.5-dind` as a service. Volume bindings also affect services,
making them incompatible.
To make Docker available in the context of the image, you need to mount
@@ -369,7 +370,7 @@ Your configuration should look similar to this example:
executor = "docker"
[runners.docker]
tls_verify = false
- image = "docker:20.10.16"
+ image = "docker:24.0.5"
privileged = false
disable_cache = false
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
@@ -385,7 +386,7 @@ sudo gitlab-runner register -n \
--registration-token REGISTRATION_TOKEN \
--executor docker \
--description "My Docker Runner" \
- --docker-image "docker:20.10.16" \
+ --docker-image "docker:24.0.5" \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
```
@@ -408,7 +409,7 @@ mirror:
```yaml
services:
- - name: docker:20.10.16-dind
+ - name: docker:24.0.5-dind
command: ["--registry-mirror", "https://registry-mirror.example.com"] # Specify the registry mirror to use
```
@@ -431,7 +432,7 @@ Docker:
...
privileged = true
[[runners.docker.services]]
- name = "docker:20.10.16-dind"
+ name = "docker:24.0.5-dind"
command = ["--registry-mirror", "https://registry-mirror.example.com"]
```
@@ -445,7 +446,7 @@ Kubernetes:
...
privileged = true
[[runners.kubernetes.services]]
- name = "docker:20.10.16-dind"
+ name = "docker:24.0.5-dind"
command = ["--registry-mirror", "https://registry-mirror.example.com"]
```
@@ -552,12 +553,12 @@ the implications of this method are:
docker run --rm -t -i -v $(pwd)/src:/home/app/src test-image:latest run_app_tests
```
-You do not need to include the `docker:20.10.16-dind` service, like you do when
+You do not need to include the `docker:24.0.5-dind` service, like you do when
you use the Docker-in-Docker executor:
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
before_script:
- docker info
@@ -638,30 +639,43 @@ To build Docker images without enabling privileged mode on the runner, you can
use one of these alternatives:
- [`kaniko`](using_kaniko.md).
-- [`buildah`](https://github.com/containers/buildah). There is a [known issue](https://github.com/containers/buildah/issues/4049) with running as non-root, you might need this [workaround](https://docs.gitlab.com/runner/configuration/configuring_runner_operator.html#configure-setfcap) if you are using OpenShift Runner.
+- [`buildah`](#buildah-example).
-For example, with `buildah`:
+### Buildah example
-```yaml
-# Some details from https://major.io/2019/05/24/build-containers-in-gitlab-ci-with-buildah/
+To use Buildah with GitLab CI/CD, you need [a runner](https://docs.gitlab.com/runner/) with one
+of the following executors:
+
+- [Kubernetes](https://docs.gitlab.com/runner/executors/kubernetes.html).
+- [Docker](https://docs.gitlab.com/runner/executors/docker.html).
+- [Docker Machine](https://docs.gitlab.com/runner/executors/docker_machine.html).
+
+In this example, you use Buildah to:
+
+1. Build a Docker image.
+1. Push it to [GitLab Container Registry](../../user/packages/container_registry/index.md).
+In the last step, Buildah uses the `Dockerfile` under the
+root directory of the project to build the Docker image. Finally, it pushes the image to the
+project's Container Registry:
+
+```yaml
build:
stage: build
image: quay.io/buildah/stable
variables:
- # Use vfs with buildah. Docker offers overlayfs as a default, but buildah
+ # Use vfs with buildah. Docker offers overlayfs as a default, but Buildah
# cannot stack overlayfs on top of another overlayfs filesystem.
STORAGE_DRIVER: vfs
# Write all image metadata in the docker format, not the standard OCI format.
# Newer versions of docker can handle the OCI format, but older versions, like
# the one shipped with Fedora 30, cannot handle the format.
BUILDAH_FORMAT: docker
- # You may need this workaround for some errors: https://stackoverflow.com/a/70438141/1233435
- BUILDAH_ISOLATION: chroot
FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/test"
before_script:
- # Log in to the GitLab container registry
- - export REGISTRY_AUTH_FILE=$HOME/auth.json
+ # GitLab Container Registry credentials taken from the
+ # [predefined CI/CD variables](../variables/index.md#predefined-cicd-variables)
+ # to authenticate to the registry.
- echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
script:
- buildah images
@@ -670,6 +684,9 @@ build:
- buildah push $FQ_IMAGE_NAME
```
+If you are using GitLab Runner Operator deployed to an OpenShift cluster, try the
+[tutorial for using Buildah to build images in rootless container](buildah_rootless_tutorial.md).
+
## Use the GitLab Container Registry
After you've built a Docker image, you can push it to the
@@ -702,9 +719,9 @@ This issue can occur when the service's image name
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
services:
- - registry.hub.docker.com/library/docker:20.10.16-dind
+ - registry.hub.docker.com/library/docker:24.0.5-dind
```
A service's hostname is [derived from the full image name](../../ci/services/index.md#accessing-the-services).
@@ -713,15 +730,94 @@ To allow service resolution and access, add an explicit alias for the service na
```yaml
default:
- image: docker:20.10.16
+ image: docker:24.0.5
services:
- - name: registry.hub.docker.com/library/docker:20.10.16-dind
+ - name: registry.hub.docker.com/library/docker:24.0.5-dind
alias: docker
```
+### `Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?`
+
+You might get the following error when trying to run a `docker` command
+to access a `dind` service:
+
+```shell
+$ docker ps
+Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
+```
+
+Make sure your job has defined these environment variables:
+
+- `DOCKER_HOST`
+- `DOCKER_TLS_CERTDIR` (optional)
+- `DOCKER_TLS_VERIFY` (optional)
+
+You may also want to update the image that provides the Docker
+client. For example, the [`docker/compose` images are obsolete](https://hub.docker.com/r/docker/compose) and should be
+replaced with [`docker`](https://hub.docker.com/_/docker).
+
+As described in [runner issue 30944](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/30944#note_1514250909),
+this error can happen if your job previously relied on environment variables derived from the deprecated
+[Docker `--link` parameter](https://docs.docker.com/network/links/#environment-variables),
+such as `DOCKER_PORT_2375_TCP`. Your job fails with this error if:
+
+- Your CI/CD image relies on a legacy variable, such as `DOCKER_PORT_2375_TCP`.
+- The [runner feature flag `FF_NETWORK_PER_BUILD`](https://docs.gitlab.com/runner/configuration/feature-flags.html) is set to `true`.
+- `DOCKER_HOST` is not explicitly set.
+
### Error: `Error response from daemon: Get "https://registry-1.docker.io/v2/": unauthorized: incorrect username or password`
This error appears when you use the deprecated variable, `CI_BUILD_TOKEN`. To prevent users from receiving this error, you should:
- Use [CI_JOB_TOKEN](../jobs/ci_job_token.md) instead.
- Change from `gitlab-ci-token/CI_BUILD_TOKEN` to `$CI_REGISTRY_USER/$CI_REGISTRY_PASSWORD`.
+
+### Error: `error during connect: Post "https://docker:2376/v1.24/auth": dial tcp: lookup docker on 127.0.0.11:53: no such host`
+
+This error appears when the `dind` service has failed to start. Check
+the job log to see if `mount: permission denied (are you root?)`
+appears. For example:
+
+```plaintext
+Service container logs:
+2023-08-01T16:04:09.541703572Z Certificate request self-signature ok
+2023-08-01T16:04:09.541770852Z subject=CN = docker:dind server
+2023-08-01T16:04:09.556183222Z /certs/server/cert.pem: OK
+2023-08-01T16:04:10.641128729Z Certificate request self-signature ok
+2023-08-01T16:04:10.641173149Z subject=CN = docker:dind client
+2023-08-01T16:04:10.656089908Z /certs/client/cert.pem: OK
+2023-08-01T16:04:10.659571093Z ip: can't find device 'ip_tables'
+2023-08-01T16:04:10.660872131Z modprobe: can't change directory to '/lib/modules': No such file or directory
+2023-08-01T16:04:10.664620455Z mount: permission denied (are you root?)
+2023-08-01T16:04:10.664692175Z Could not mount /sys/kernel/security.
+2023-08-01T16:04:10.664703615Z AppArmor detection and --privileged mode might break.
+2023-08-01T16:04:10.665952353Z mount: permission denied (are you root?)
+```
+
+This indicates the GitLab Runner does not have permission to start the
+`dind` service:
+
+1. Check that `privileged = true` is set in the `config.toml`.
+1. Make sure the CI job has the right Runner tags to use these
+privileged runners.
+
+### Error: `cgroups: cgroup mountpoint does not exist: unknown`
+
+There is a known incompatibility introduced by Docker Engine 20.10.
+
+When the host uses Docker Engine 20.10 or newer, then the `docker:dind` service in a version older than 20.10 does
+not work as expected.
+
+While the service itself will start without problems, trying to build the container image results in the error:
+
+```plaintext
+cgroups: cgroup mountpoint does not exist: unknown
+```
+
+To resolve this issue, update the `docker:dind` container to version at least 20.10.x,
+for example `docker:24.0.5-dind`.
+
+The opposite configuration (`docker:24.0.5-dind` service and Docker Engine on the host in version
+19.06.x or older) works without problems. For the best strategy, you should to frequently test and update
+job environment versions to the newest. This brings new features, improved security and - for this specific
+case - makes the upgrade on the underlying Docker Engine on the runner's host transparent for the job.
diff --git a/doc/ci/docker/using_kaniko.md b/doc/ci/docker/using_kaniko.md
index 568f4977c2f..8ab13c7154d 100644
--- a/doc/ci/docker/using_kaniko.md
+++ b/doc/ci/docker/using_kaniko.md
@@ -58,7 +58,7 @@ project's Container Registry while tagging it with the Git tag:
build:
stage: build
image:
- name: gcr.io/kaniko-project/executor:v1.9.0-debug
+ name: gcr.io/kaniko-project/executor:v1.14.0-debug
entrypoint: [""]
script:
- /kaniko/executor
@@ -96,7 +96,7 @@ build:
https_proxy: <your-proxy>
no_proxy: <your-no-proxy>
image:
- name: gcr.io/kaniko-project/executor:v1.9.0-debug
+ name: gcr.io/kaniko-project/executor:v1.14.0-debug
entrypoint: [""]
script:
- /kaniko/executor
@@ -158,3 +158,25 @@ on what other GitLab CI patterns are demonstrated are available at the project p
If you receive this error, it might be due to an outside proxy. Setting the `http_proxy`
and `https_proxy` [environment variables](../../administration/packages/container_registry.md#running-the-docker-daemon-with-a-proxy)
can fix the problem.
+
+### Error: `kaniko should only be run inside of a container, run with the --force flag if you are sure you want to continue`
+
+There is a known incompatibility introduced by Docker Engine 20.10.
+
+When the host uses Docker Engine 20.10 or newer, then the `gcr.io/kaniko-project/executor:debug` image in a version
+older than v1.9.0 does not work as expected.
+
+When you try to build the image, Kaniko fails with:
+
+```plaintext
+kaniko should only be run inside of a container, run with the --force flag if you are sure you want to continue
+```
+
+To resolve this issue, update the `gcr.io/kaniko-project/executor:debug` container to version at least v1.9.0,
+for example `gcr.io/kaniko-project/executor:v1.14.0-debug`.
+
+The opposite configuration (`gcr.io/kaniko-project/executor:v1.14.0-debug` image and Docker Engine
+on the host in version 19.06.x or older) works without problems. For the best strategy, you should
+frequently test and update job environment versions to the newest. This brings new features, improved
+security and - for this specific case - makes the upgrade on underlying Docker Engine on the runner's
+host transparent for the job.
diff --git a/doc/ci/enable_or_disable_ci.md b/doc/ci/enable_or_disable_ci.md
index 395a07f48c8..3081b8d1b39 100644
--- a/doc/ci/enable_or_disable_ci.md
+++ b/doc/ci/enable_or_disable_ci.md
@@ -30,7 +30,7 @@ When you disable GitLab CI/CD:
To disable GitLab CI/CD in your project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. In the **Repository** section, turn off **CI/CD**.
@@ -40,7 +40,7 @@ To disable GitLab CI/CD in your project:
To enable GitLab CI/CD in your project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. In the **Repository** section, turn on **CI/CD**.
diff --git a/doc/ci/environments/deployment_approvals.md b/doc/ci/environments/deployment_approvals.md
index 2933b25e09b..754dcafb9f7 100644
--- a/doc/ci/environments/deployment_approvals.md
+++ b/doc/ci/environments/deployment_approvals.md
@@ -8,32 +8,24 @@ description: Require approvals prior to deploying to a Protected Environment
# Deployment approvals **(PREMIUM ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/343864) in GitLab 14.7 with a flag named `deployment_approvals`. Disabled by default.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/347342) in GitLab 14.8.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/347342) in GitLab 14.8. Feature flag `deployment_approvals` removed.
-It may be useful to require additional approvals before deploying to certain protected environments (for example, production). This pre-deployment approval requirement is useful to accommodate testing, security, or compliance processes that must happen before each deployment.
+You can require additional approvals for deployments to protected
+environments. Deployments are blocked until all required approvals are
+given.
-When a protected environment requires one or more approvals, all deployments to that environment become blocked and wait for the required approvals from the `Allowed to Deploy` list before running.
+Use deployment approvals to accommodate testing,
+security, or compliance processes. For example, you might want to
+require approvals for deployments to production environments.
-NOTE:
-See the [epic](https://gitlab.com/groups/gitlab-org/-/epics/6832) for planned features.
-
-## Prerequisites
-
-- Basic knowledge of [GitLab Environments and Deployments](index.md).
-- Basic knowledge of [Protected Environments](protected_environments.md).
+## Configure deployment approvals
-## Configure deployment approvals for a project
+You can require approvals for deployments to protected environments in
+a project.
To configure deployment approvals for a project:
-1. [Create a deployment job](#create-a-deployment-job).
-1. [Require approvals for a protected environment](#require-approvals-for-a-protected-environment).
-
-### Create a deployment job
-
-Create a deployment job in the `.gitlab-ci.yml` file of the desired project. The job does **not** need to be manual (`when: manual`).
-
-Example:
+1. Create a deployment job in the `.gitlab-ci.yml` file of your project:
```yaml
stages:
@@ -47,22 +39,15 @@ Example:
name: ${CI_JOB_NAME}
```
-### Require approvals for a protected environment
+ The job does not need to be manual (`when: manual`).
-There are two ways to configure the approval requirements:
+1. Add the required [approval rules](#multiple-approval-rules).
-- [Unified approval setting](#unified-approval-setting-deprecated) ... You can define who can execute **and** approve deployments.
- This is useful when there is no separation of duties between executors and approvers in your organization.
-- [Multiple approval rules](#multiple-approval-rules) ... You can define who can execute **or** approve deployments.
- This is useful when there is a separation of duties between executors and approvers in your organization.
-
-NOTE:
-Multiple approval rules is a more flexible option than the unified approval setting, thus both configurations shouldn't
-co-exist and multiple approval rules takes the precedence over the unified approval setting if it happens.
+The environments in your project require approval before deployment.
<!--- start_remove The following content will be removed on remove_date: '2024-05-22' -->
-#### Unified approval setting (deprecated)
+### Unified approval setting (deprecated)
> - UI configuration [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/378447) in GitLab
> 15.11.
@@ -94,7 +79,7 @@ Maintainer role.
<!--- end_remove -->
-#### Multiple approval rules
+### Multiple approval rules
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345678) in GitLab 14.10 with a flag named `deployment_approval_rules`. Disabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/345678) in GitLab 15.0. [Feature flag `deployment_approval_rules`](https://gitlab.com/gitlab-org/gitlab/-/issues/345678) removed.
@@ -107,7 +92,7 @@ Maintainer role.
- **Allowed to deploy** sets which entities can execute the deployment job.
- **Approvers** sets which entities can approve the deployment job.
-After this is configured, all jobs deploying to this environment automatically go into a blocked state and wait for approvals before running. Ensure that the number of required approvals is less than the number of users allowed to deploy.
+After this is configured, all jobs deploying to this environment automatically go into a blocked state and wait for approvals before running. Ensure that the number of required approvals is less than the number of users allowed to deploy. Once a deployment job is approved, it must be [run manually](../jobs/job_control.md#run-a-manual-job).
A configuration that uses the REST API might look like:
@@ -128,7 +113,7 @@ NOTE:
To protect, update, or unprotect an environment, you must have at least the
Maintainer role.
-#### Migrate to multiple approval rules
+### Migrate to multiple approval rules
You can migrate a protected environment from unified approval rules to multiple
approval rules. Unified approval rules allow all entities that can deploy to an
@@ -137,7 +122,7 @@ create a new approval rule for each entity allowed to deploy to the environment.
To migrate with the UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Protected environments**.
1. From the **Environment** list, select your environment.
@@ -171,7 +156,7 @@ require `Administrator` to approve every deployment job in `Production`.
By default, the user who triggers a deployment pipeline can't also approve the deployment job.
To allow self-approval of a deployment job:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Protected environments**.
1. From the **Approval options**, select the **Allow pipeline triggerer to approve deployment** checkbox.
@@ -196,7 +181,7 @@ Prerequisites:
To approve or reject a deployment to a protected environment using the UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select the environment's name.
1. In the deployment's row, select **Approval options** (**{thumb-up}**).
@@ -233,7 +218,7 @@ granted.
To view the approval details of a deployment:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select the environment's name.
1. In the deployment's row, select **Approval options** (**{thumb-up}**).
@@ -249,7 +234,7 @@ The approval status details are shown:
### Using the UI
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select the environment being deployed to.
1. Look for the `blocked` label.
@@ -265,9 +250,9 @@ Use the [Deployments API](../../api/deployments.md#get-a-specific-deployment) to
- When the [multiple approval rules](#multiple-approval-rules) is configured:
- The `approval_summary` field contains the current approval status per rule.
-## Related features
+## Related topics
-For details about other GitLab features aimed at protecting deployments, see [safe deployments](deployment_safety.md).
+- [Deployment approvals feature epic](https://gitlab.com/groups/gitlab-org/-/epics/6832)
<!-- ## Troubleshooting
diff --git a/doc/ci/environments/environments_dashboard.md b/doc/ci/environments/environments_dashboard.md
index e98205f45b9..0beaf2b8888 100644
--- a/doc/ci/environments/environments_dashboard.md
+++ b/doc/ci/environments/environments_dashboard.md
@@ -20,7 +20,7 @@ see which pipelines are green and which are red allowing you to
diagnose if there is a block at a particular point, or if there's
a more systemic problem you need to investigate.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. Select **Environments**.
diff --git a/doc/ci/environments/incremental_rollouts.md b/doc/ci/environments/incremental_rollouts.md
index a498e525b54..309e311e252 100644
--- a/doc/ci/environments/incremental_rollouts.md
+++ b/doc/ci/environments/incremental_rollouts.md
@@ -22,9 +22,9 @@ Manual and Timed rollouts are included automatically in projects controlled by
[Auto DevOps](../../topics/autodevops/index.md), but they are also configurable through
GitLab CI/CD in the `.gitlab-ci.yml` configuration file.
-Manually triggered rollouts can be implemented with your [Continuous Delivery](../introduction/index.md#continuous-delivery)
-methodology, while timed rollouts do not require intervention and can be part of your
-[Continuous Deployment](../introduction/index.md#continuous-deployment) strategy.
+Manually triggered rollouts can be implemented with Continuous Delivery,
+while timed rollouts do not require intervention and can be part of your
+Continuous Deployment strategy.
You can also combine both of them in a way that the app is deployed automatically
unless you eventually intervene manually if necessary.
diff --git a/doc/ci/environments/index.md b/doc/ci/environments/index.md
index c91018980f0..713d58de326 100644
--- a/doc/ci/environments/index.md
+++ b/doc/ci/environments/index.md
@@ -51,7 +51,7 @@ Deployments show up in this list only after a deployment job has created them.
To search environments by name:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. In the search bar, enter your search term.
- The length of your **search term should be 3 or more characters**.
@@ -93,7 +93,7 @@ Prerequisites:
To create a static environment in the UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select **Create an environment**.
1. Complete the fields.
@@ -339,13 +339,19 @@ It points to the commit you're rolling back to.
For the rollback to succeed, the deployment process must be defined in
the job's `script`.
+Only the [deployment jobs](../jobs/index.md#deployment-jobs) are run.
+In cases where a previous job generates artifacts that must be regenerated
+on deploy, you must manually run the necessary jobs from the pipelines page.
+For example, if you use Terraform and your `plan` and `apply` commands are separated
+into multiple jobs, you must manually run the jobs to deploy or roll back.
+
#### Retry or roll back a deployment
If there is a problem with a deployment, you can retry it or roll it back.
To retry or roll back a deployment:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select the environment.
1. To the right of the deployment name:
@@ -359,7 +365,7 @@ In this case, see [job retries for rollback deployments](deployment_safety.md#jo
### Environment URL
-> - [Fixed](https://gitlab.com/gitlab-org/gitlab/-/issues/337417) to persist arbitrary URLs in GitLab 15.2 [with a flag](../../administration/feature_flags.md) named `soft_validation_on_external_url`. Disabled by default.
+> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/337417) to persist arbitrary URLs in GitLab 15.2 [with a flag](../../administration/feature_flags.md) named `soft_validation_on_external_url`. Disabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/337417) in GitLab 15.3. [Feature flag `soft_validation_on_external_url`](https://gitlab.com/gitlab-org/gitlab/-/issues/367206) removed.
The [environment URL](../yaml/index.md#environmenturl) is displayed in a few
@@ -560,7 +566,7 @@ you can view its expiration date and time.
To view an environment's expiration date and time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select the name of the environment.
@@ -573,7 +579,7 @@ you can override its expiration.
To override an environment's expiration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select the deployment name.
1. in the upper-right corner, select the thumbtack (**{thumbtack}**).
@@ -600,7 +606,7 @@ Environments view, the stop and deploy jobs must be in the same
To stop an environment in the GitLab UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Next to the environment you want to stop, select **Stop**.
1. On the confirmation dialog, select **Stop environment**.
@@ -664,7 +670,7 @@ Prerequisites:
To delete an environment:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select the **Stopped** tab.
1. Next to the environment you want to delete, select **Delete environment**.
@@ -767,7 +773,7 @@ Limitations of GitLab Auto Rollback:
GitLab Auto Rollback is turned off by default. To turn it on:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Automatic deployment rollbacks**.
1. Select the checkbox for **Enable automatic rollbacks**.
@@ -910,6 +916,7 @@ the `review/feature-1` spec takes precedence over `review/*` and `*` specs.
## Related topics
- [Dashboard for Kubernetes](kubernetes_dashboard.md)
+- [Downstream pipelines for deployments](../pipelines/downstream_pipelines.md#downstream-pipelines-for-deployments)
- [Deploy to multiple environments with GitLab CI/CD (blog post)](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/)
- [Review Apps](../review_apps/index.md)
- [Protected environments](protected_environments.md)
diff --git a/doc/ci/environments/kubernetes_dashboard.md b/doc/ci/environments/kubernetes_dashboard.md
index 98b6731e469..0f9e1d808ec 100644
--- a/doc/ci/environments/kubernetes_dashboard.md
+++ b/doc/ci/environments/kubernetes_dashboard.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference
---
-# Dashboard for Kubernetes (Beta) **(FREE ALL)**
+# Dashboard for Kubernetes **(FREE ALL BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390769) in GitLab 16.1, with [flags](../../administration/feature_flags.md) named `environment_settings_to_graphql`, `kas_user_access`, `kas_user_access_project`, and `expose_authorized_cluster_agents`. This feature is in [Beta](../../policy/experiment-beta-support.md#beta).
> - Feature flag `environment_settings_to_graphql` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124177) in GitLab 16.2.
@@ -15,17 +15,12 @@ Use the Dashboard for Kubernetes to understand the status of your clusters with
The dashboard works with every connected Kubernetes cluster, whether you deployed them
with CI/CD or GitOps.
-For Flux users, the synchronization status of a given environment is not displayed in the dashboard.
-[Issue 391581](https://gitlab.com/gitlab-org/gitlab/-/issues/391581) proposes to add this functionality.
-
## Configure a dashboard
> - Filtering resources by namespace [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/403618) in GitLab 16.2 [with a flag](../../administration/feature_flags.md) named `kubernetes_namespace_for_environment`. Disabled by default.
> - Filtering resources by namespace [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127043) in GitLab 16.3. Feature flag `kubernetes_namespace_for_environment` removed.
-> - Selecting the related Flux resource [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128857) in GitLab 16.3 [with a flag](../../administration/feature_flags.md) named `flux_resource_for_environment`. Disabled by default.
-
-FLAG:
-On self-managed GitLab, by default selecting a Flux resource is not available. To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `flux_resource_for_environment`. On GitLab.com, this feature is not available.
+> - Selecting the related Flux resource [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128857) in GitLab 16.3 [with a flag](../../administration/feature_flags.md) named `flux_resource_for_environment`.
+> - Selecting the related Flux resource [generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130648) in GitLab 16.4. Feature flag `flux_resource_for_environment` removed.
Configure a dashboard to use it for a given environment.
You can configure dashboard for an environment that already exists, or
@@ -38,9 +33,9 @@ Prerequisites:
### The environment already exists
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
-1. Select the environment to be associated with the Kubernetes.
+1. Select the environment to be associated with the agent for Kubernetes.
1. Select **Edit**.
1. Select a GitLab agent for Kubernetes.
1. Optional. From the **Kubernetes namespace** dropdown list, select a namespace.
@@ -49,7 +44,7 @@ Prerequisites:
### The environment doesn't exist
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select **New environment**.
1. Complete the **Name** field.
@@ -62,17 +57,25 @@ Prerequisites:
To view a configured dashboard:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
-1. Expand the environment associated with GitLab agent for Kubernetes.
+1. Expand the environment associated with the agent for Kubernetes.
1. Expand **Kubernetes overview**.
### Flux sync status
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/391581) in GitLab 16.3.
-> - Customizing the name of the Flux resource [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128857) in GitLab 16.3 [with a flag](../../administration/feature_flags.md) named `flux_resource_for_environment`. Disabled by default.
+> - Customizing the name of the Flux resource [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128857) in GitLab 16.3 [with a flag](../../administration/feature_flags.md) named `flux_resource_for_environment`.
+> - Customizing the name of the Flux resource [generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130648) in GitLab 16.4. Feature flag `flux_resource_for_environment` removed.
-A dashboard displays the sync status of your Flux deployments.
+You can review the sync status of your Flux deployments from a dashboard.
+To display the deployment status, your dashboard must be able to retrieve the `Kustomization` and `HelmRelease` resources,
+which requires a namespace to be configured for the environment.
+
+By default, GitLab searches the `Kustomization` and `HelmRelease` resources for the name of the project slug.
+You can specify the resource names with the **Flux resource** dropdown list in the environment settings.
+
+A dashboard displays one of the following status badges:
| Status | Description |
|---------|-------------|
@@ -83,11 +86,6 @@ A dashboard displays the sync status of your Flux deployments.
| **Unknown** | The sync status of the deployment couldn't be retrieved. |
| **Unavailable** | The `Kustomization` or `HelmRelease` resource couldn't be retrieved. |
-Deployments rely on Flux `Kustomization` and `HelmRelease` resources to gather
-the status of a given environment, which requires a namespace to be configured for the environment.
-By default, GitLab searches the `Kustomization` and `HelmRelease` resources for the name of the project slug.
-You can customize the name GitLab looks for in the environment settings.
-
## Troubleshooting
When working with the Dashboard for Kubernetes, you might encounter the following issues.
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
index fd789ea798d..21b58ac5ab4 100644
--- a/doc/ci/environments/protected_environments.md
+++ b/doc/ci/environments/protected_environments.md
@@ -30,7 +30,7 @@ Prerequisites:
To protect an environment:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Protected environments**.
1. Select **Protect an environment**.
@@ -256,7 +256,7 @@ To protect a group-level environment, make sure your environments have the corre
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325249) in GitLab 15.1.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > CI/CD**.
1. Expand **Protected environments**.
1. From the **Environment** list, select the [deployment tier of environments](index.md#deployment-tier-of-environments) you want to protect.
diff --git a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
index 737c95cf747..647669385d8 100644
--- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
+++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
@@ -9,7 +9,7 @@ type: tutorial
WARNING:
Authenticating with `CI_JOB_JWT` was [deprecated in GitLab 15.9](../../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated)
-and the token is scheduled to be removed in GitLab 16.5. Use
+and the token is scheduled to be removed in GitLab 17.0. Use
[ID tokens to authenticate with HashiCorp Vault](../../secrets/id_token_authentication.md#automatic-id-token-authentication-with-hashicorp-vault)
instead, as demonstrated on this page.
diff --git a/doc/ci/examples/deployment/index.md b/doc/ci/examples/deployment/index.md
index f9360faedac..2be800efcbb 100644
--- a/doc/ci/examples/deployment/index.md
+++ b/doc/ci/examples/deployment/index.md
@@ -121,7 +121,7 @@ We also use two secure variables:
To store API keys as secure variables:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Variables**.
diff --git a/doc/ci/examples/semantic-release.md b/doc/ci/examples/semantic-release.md
index b284e2b2dc1..356a3d1d63e 100644
--- a/doc/ci/examples/semantic-release.md
+++ b/doc/ci/examples/semantic-release.md
@@ -96,7 +96,7 @@ As part of publishing a package, semantic-release increases the version number i
1. Under **select scopes**, select the **api** checkbox.
1. Select **Create project access token**.
1. Copy the value.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Variables**.
1. Select **Add variable**.
diff --git a/doc/ci/index.md b/doc/ci/index.md
index 21fe122f503..8d9108e4fc5 100644
--- a/doc/ci/index.md
+++ b/doc/ci/index.md
@@ -6,174 +6,86 @@ description: "Learn how to use GitLab CI/CD, the GitLab built-in Continuous Inte
type: index
---
-# GitLab CI/CD **(FREE ALL)**
-
-GitLab CI/CD is a tool for software development using the continuous methodologies:
-
-- [Continuous Integration (CI)](introduction/index.md#continuous-integration)
-- [Continuous Delivery (CD)](introduction/index.md#continuous-delivery)
-- [Continuous Deployment (CD)](introduction/index.md#continuous-deployment)
-
-NOTE:
-Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.
-Watch our ["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
-webcast to learn about continuous methods and how GitLab CI/CD can help you simplify and scale software development.
-
-Use GitLab CI/CD to catch bugs and errors early in
-the development cycle. Ensure that all the code deployed to
-production complies with the code standards you established for
-your app.
-
-GitLab CI/CD can automatically build, test, deploy, and
-monitor your applications by using [Auto DevOps](../topics/autodevops/index.md).
-
-For a complete overview of these methodologies and GitLab CI/CD,
-read the [Introduction to CI/CD with GitLab](introduction/index.md).
-
-<div class="video-fallback">
- Video demonstration of continuous integration with GitLab CI/CD: <a href="https://www.youtube.com/watch?v=ljth1Q5oJoo">Continuous Integration with GitLab (overview demo)</a>.
-</div>
-<figure class="video-container">
- <iframe src="https://www.youtube-nocookie.com/embed/ljth1Q5oJoo" frameborder="0" allowfullscreen> </iframe>
-</figure>
-
-## Concepts
-
-GitLab CI/CD uses a number of concepts to describe and run your build and deploy.
-
-| Concept | Description |
-|:--------------------------------------------------------|:--------------------------------------------------------------------------------------|
-| [Pipelines](pipelines/index.md) | Structure your CI/CD process through pipelines. |
-| [CI/CD variables](variables/index.md) | Reuse values based on a variable/value key pair. |
-| [Environments](environments/index.md) | Deploy your application to different environments (for example, staging, production). |
-| [Job artifacts](jobs/job_artifacts.md) | Output, use, and reuse job artifacts. |
-| [Cache dependencies](caching/index.md) | Cache your dependencies for a faster execution. |
-| [GitLab Runner](https://docs.gitlab.com/runner/) | Configure your own runners to execute your scripts. |
-| [Pipeline efficiency](pipelines/pipeline_efficiency.md) | Configure your pipelines to run quickly and efficiently. |
-| [Test cases](test_cases/index.md) | Create testing scenarios. |
-
-## Configuration
-
-GitLab CI/CD supports numerous configuration options:
-
-| Configuration | Description |
-|:---------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------|
-| [Schedule pipelines](pipelines/schedules.md) | Schedule pipelines to run as often as you need. |
-| [Custom path for `.gitlab-ci.yml`](pipelines/settings.md#specify-a-custom-cicd-configuration-file) | Define a custom path for the CI/CD configuration file. |
-| [Git submodules for CI/CD](git_submodules.md) | Configure jobs for using Git submodules. |
-| [SSH keys for CI/CD](ssh_keys/index.md) | Using SSH keys in your CI pipelines. |
-| [Pipeline triggers](triggers/index.md) | Trigger pipelines through the API. |
-| [Merge request pipelines](pipelines/merge_request_pipelines.md) | Design a pipeline structure for running a pipeline in merge requests. |
-| [Integrate with Kubernetes clusters](../user/infrastructure/clusters/index.md) | Connect your project to Google Kubernetes Engine (GKE) or an existing Kubernetes cluster. |
-| [Optimize GitLab and GitLab Runner for large repositories](large_repositories/index.md) | Recommended strategies for handling large repositories. |
-| [`.gitlab-ci.yml` full reference](yaml/index.md) | All the attributes you can use with GitLab CI/CD. |
-
-Certain operations can only be performed according to the
-[user](../user/permissions.md#gitlab-cicd-permissions) and [job](../user/permissions.md#job-permissions) permissions.
-
-## Features
-
-GitLab CI/CD features, grouped by DevOps stage, include:
-
-| Feature | Description |
-|:---------------------------------------------------------------------------------------------|:------------|
-| **Configure** | |
-| [Auto DevOps](../topics/autodevops/index.md) | Set up your app's entire lifecycle. |
-| [ChatOps](chatops/index.md) | Trigger CI jobs from chat, with results sent back to the channel. |
-| [Connect to cloud services](cloud_services/index.md) | Connect to cloud providers using OpenID Connect (OIDC) to retrieve temporary credentials to access services or secrets. |
-| **Verify** | |
-| [CI services](services/index.md) | Link Docker containers with your base image. |
-| [GitLab CI/CD for external repositories](ci_cd_for_external_repos/index.md) | Get the benefits of GitLab CI/CD combined with repositories in GitHub and Bitbucket Cloud. |
-| [Interactive Web Terminals](interactive_web_terminal/index.md) | Open an interactive web terminal to debug the running jobs. |
-| [Review Apps](review_apps/index.md) | Configure GitLab CI/CD to preview code changes. |
-| [Unit test reports](testing/unit_test_reports.md) | Identify test failures directly on merge requests. |
-| [Using Docker images](docker/using_docker_images.md) | Use GitLab and GitLab Runner with Docker to build and test applications. |
-| **Release** | |
-| [Auto Deploy](../topics/autodevops/stages.md#auto-deploy) | Deploy your application to a production environment in a Kubernetes cluster. |
-| [Building Docker images](docker/using_docker_build.md) | Maintain Docker-based projects using GitLab CI/CD. |
-| [Canary Deployments](../user/project/canary_deployments.md) | Ship features to only a portion of your pods and let a percentage of your user base to visit the temporarily deployed feature. |
-| [Deploy boards](../user/project/deploy_boards.md) | Check the current health and status of each CI/CD environment running on Kubernetes. |
-| [Feature flags](../operations/feature_flags.md) | Deploy your features behind Feature flags. |
-| [GitLab Pages](../user/project/pages/index.md) | Deploy static websites. |
-| [GitLab Releases](../user/project/releases/index.md) | Add release notes to Git tags. |
-| [Cloud deployment](cloud_deployment/index.md) | Deploy your application to a main cloud provider. |
-| **Secure** | |
-| [Code Quality](testing/code_quality.md) | Analyze your source code quality. |
-| [Container Scanning](../user/application_security/container_scanning/index.md) | Scan your container images for known vulnerabilities. |
-| [Coverage-guided fuzz testing](../user/application_security/coverage_fuzzing/index.md) | Test your application's behavior by providing randomized input. |
-| [Dynamic Application Security Testing](../user/application_security/dast/index.md) | Test your application's runtime behavior for vulnerabilities. |
-| [Dependency Scanning](../user/application_security/dependency_scanning/index.md) | Analyze your dependencies for known vulnerabilities. |
-| [Infrastructure as Code scanning](../user/application_security/iac_scanning/index.md) | Scan your IaC configuration files for known vulnerabilities. |
-| [License Scanning](../user/compliance/license_scanning_of_cyclonedx_files/index.md) | Search your project dependencies for their licenses. | Search your project dependencies for their licenses. |
-| [Secret Detection](../user/application_security/secret_detection/index.md) | Search your application's source code for secrets. |
-| [Static Application Security Testing](../user/application_security/sast/index.md) | Test your application's source code for known vulnerabilities. |
-| [Web API fuzz testing](../user/application_security/api_fuzzing/index.md) | Test your application's API behavior by providing randomized input. |
-| **Govern** | |
-| [Compliance frameworks](../user/group/compliance_frameworks.md) | Enforce a GitLab CI/CD configuration on all projects in a group. |
-| [Scan execution policies](../user/application_security/policies/scan-execution-policies.md) | Enforce security scans run on a specified schedule or with the project pipeline. |
-| [Scan results policies](../user/application_security/policies/scan-result-policies.md) | Enforce action based on results of a pipeline security scan. |
-
-## Examples
-
-See the [CI/CD examples](examples/index.md) page for example project code and tutorials for
-using GitLab CI/CD with various:
-
-- App frameworks
-- Languages
-- Platforms
-
-## Administration
-
-You can change the default behavior of GitLab CI/CD for:
-
-- An entire GitLab instance in the [CI/CD administration settings](../administration/cicd.md).
-- Specific projects in the [pipelines settings](pipelines/settings.md).
-
-See also:
-
-- [Enable or disable GitLab CI/CD in a project](enable_or_disable_ci.md).
+# Get started with GitLab CI/CD **(FREE ALL)**
+
+CI/CD is a continuous method of software development, where you continuously build,
+test, deploy, and monitor iterative code changes.
+
+This iterative process helps reduce the chance that you develop new code based on
+buggy or failed previous versions. GitLab CI/CD can catch bugs early in the development cycle,
+and help ensure that all the code deployed to production complies with your established code standards.
+
+## Common terms
+
+If you're new to GitLab CI/CD, start by reviewing some of the commonly used terms.
+
+### The `.gitlab-ci.yml` file
+
+To use GitLab CI/CD, you start with a `.gitlab-ci.yml` file at the root of your project.
+In this file, you specify the list of things you want to do, like test and deploy your application.
+This file follows the YAML format and has its own special syntax.
+
+You can name this file anything you want, but `.gitlab-ci.yml` is the most common name.
+Use the pipeline editor to edit the `.gitlab-ci.yml` file and test the syntax before you commit changes.
+
+**Get started:**
+
+- [Create your first `.gitlab-ci.yml` file](quick_start/index.md).
+- [View all the possible keywords that you can use in the `.gitlab-ci.yml` file](yaml/index.md).
+
+### Runners
+
+Runners are the agents that run your jobs. These agents can run on physical machines or virtual instances.
+In your `.gitlab-ci.yml` file, you can specify a container image you want to use when running the job.
+The runner loads the image and runs the job either locally or in the container.
+
+If you use GitLab.com, free shared runners are already available for you. And you can register your own
+runners on GitLab.com if you'd like.
+
+If you don't use GitLab.com, you can:
+
+- Register runners or use runners already registered for your self-managed instance.
+- Create a runner on your local machine.
+
+**Get started:**
+
+- [Create a runner on your local machine](../tutorials/create_register_first_runner/index.md).
+- [Learn more about runners](https://docs.gitlab.com/runner/).
+
+### Pipelines
+
+Pipelines are made up of jobs and stages:
+
+- **Jobs** define what you want to do. For example, test code changes, or deploy
+ to a staging environment.
+- Jobs are grouped into **stages**. Each stage contains at least one job.
+ Typical stages might be `build`, `test`, and `deploy`.
+
+**Get started:**
+
+- [Learn more about pipelines](pipelines/index.md).
+
+### CI/CD variables
+
+CI/CD variables help you customize jobs by making values defined elsewhere accessible to jobs.
+They can be hard-coded in your `.gitlab-ci.yml` file, project settings, or dynamically generated
+[predefined variables](variables/predefined_variables.md).
+
+**Get started:**
+
+- [Learn more about CI/CD variables](variables/index.md).
+
+## Videos
+
+- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [GitLab CI/CD demo](https://www.youtube-nocookie.com/embed/ljth1Q5oJoo).
+- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [GitLab CI/CD and the Web IDE](https://youtu.be/l5705U8s_nQ?t=369).
+- Webcast: [Mastering continuous software development](https://about.gitlab.com/webcast/mastering-ci-cd/).
## Related topics
-- [Why you might choose GitLab CI/CD](https://about.gitlab.com/blog/2016/10/17/gitlab-ci-oohlala/)
-- [Reasons you might migrate from another platform](https://about.gitlab.com/blog/2016/07/22/building-our-web-app-on-gitlab-ci/)
-- [Five teams that made the switch to GitLab CI/CD](https://about.gitlab.com/blog/2019/04/25/5-teams-that-made-the-switch-to-gitlab-ci-cd/)
-- If you use VS Code to edit your GitLab CI/CD configuration, the
- [GitLab Workflow VS Code extension](../user/project/repository/vscode.md) helps you
+- [Five teams that made the switch to GitLab CI/CD](https://about.gitlab.com/blog/2019/04/25/5-teams-that-made-the-switch-to-gitlab-ci-cd/).
+- [Make the case for CI/CD in your organization](https://about.gitlab.com/devops-tools/github-vs-gitlab/).
+- Learn how [Verizon reduced rebuilds](https://about.gitlab.com/blog/2019/02/14/verizon-customer-story/) from 30 days to under 8 hours with GitLab.
+- Use the [GitLab Workflow VS Code extension](../user/project/repository/vscode.md) to
[validate your configuration](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#validate-gitlab-ci-configuration)
- and [view your pipeline status](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#information-about-your-branch-pipelines-mr-closing-issue)
-
-See also the [Why CI/CD?](https://docs.google.com/presentation/d/1OGgk2Tcxbpl7DJaIOzCX4Vqg3dlwfELC3u2jEeCBbDk) presentation.
-
-### Major version changes (breaking)
-
-As GitLab CI/CD has evolved, certain breaking changes have
-been necessary.
-
-For GitLab 15.0 and later, all breaking changes are documented on the following pages:
-
-- [Deprecations](../update/deprecations.md)
-- [Removals](../update/removals.md)
-
-The breaking changes for [GitLab Runner](https://docs.gitlab.com/runner/) in earlier
-major version releases are:
-
-- 14.0: No breaking changes.
-- 13.0:
- - [Remove Backported `os.Expand`](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4915).
- - [Remove Fedora 29 package support](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/16158).
- - [Remove macOS 32-bit support](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/25466).
- - [Removed `debug/jobs/list?v=1` endpoint](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6361).
- - [Remove support for array of strings when defining services for Docker executor](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4922).
- - [Remove `--docker-services` flag on register command](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6404).
- - [Remove legacy build directory caching](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4180).
- - [Remove `FF_USE_LEGACY_VOLUMES_MOUNTING_ORDER` feature flag](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6581).
- - [Remove support for Windows Server 1803](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6553).
-- 12.0:
- - [Use `refspec` to clone/fetch Git repository](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4069).
- - [Old cache configuration](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4070).
- - [Old metrics server configuration](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4072).
- - [Remove `FF_K8S_USE_ENTRYPOINT_OVER_COMMAND`](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4073).
- - [Remove Linux distributions that reach EOL](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/1130).
- - [Update command line API for helper images](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4013).
- - [Remove old `git clean` flow](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4175).
+ and [view your pipeline status](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#information-about-your-branch-pipelines-mr-closing-issue).
diff --git a/doc/ci/introduction/img/gitlab_workflow_example_11_9.png b/doc/ci/introduction/img/gitlab_workflow_example_11_9.png
deleted file mode 100644
index 1f11db55f81..00000000000
--- a/doc/ci/introduction/img/gitlab_workflow_example_11_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/introduction/img/gitlab_workflow_example_extended_v12_3.png b/doc/ci/introduction/img/gitlab_workflow_example_extended_v12_3.png
deleted file mode 100644
index 6e1066d4868..00000000000
--- a/doc/ci/introduction/img/gitlab_workflow_example_extended_v12_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/introduction/index.md b/doc/ci/introduction/index.md
index 35692ed7b7e..536dd224ac5 100644
--- a/doc/ci/introduction/index.md
+++ b/doc/ci/introduction/index.md
@@ -1,116 +1,11 @@
---
-stage: Verify
-group: Pipeline Authoring
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-description: "An overview of Continuous Integration, Continuous Delivery, and Continuous Deployment, as well as an introduction to GitLab CI/CD."
-type: concepts
+redirect_to: 'index.md'
+remove_date: '2023-11-24'
---
-# CI/CD concepts **(FREE ALL)**
+This document was moved to [another location](../index.md).
-With the continuous method of software development, you continuously build,
-test, and deploy iterative code changes. This iterative process helps reduce
-the chance that you develop new code based on buggy or failed previous versions.
-With this method, you strive to have less human intervention or even no intervention at all,
-from the development of new code until its deployment.
-
-The three primary approaches for the continuous method are:
-
-- [Continuous Integration](#continuous-integration)
-- [Continuous Delivery](#continuous-delivery)
-- [Continuous Deployment](#continuous-deployment)
-
-Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.
-Watch our ["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
-webcast to learn about continuous methods and how built-in GitLab CI/CD can help you simplify and scale software development.
-
-- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>Learn how to: [configure CI/CD](https://www.youtube.com/watch?v=opdLqwz6tcE).
-- [Make the case for CI/CD in your organization](https://about.gitlab.com/devops-tools/github-vs-gitlab/).
-- Learn how [Verizon reduced rebuilds](https://about.gitlab.com/blog/2019/02/14/verizon-customer-story/) from 30 days to under 8 hours with GitLab.
-
-## Continuous Integration
-
-Consider an application that has its code stored in a Git
-repository in GitLab. Developers push code changes every day,
-multiple times a day. For every push to the repository, you
-can create a set of scripts to build and test your application
-automatically. These scripts help decrease the chances that you introduce errors in your application.
-
-This practice is known as [Continuous Integration](https://en.wikipedia.org/wiki/Continuous_integration).
-Each change submitted to an application, even to development branches,
-is built and tested automatically and continuously. These tests ensure the
-changes pass all tests, guidelines, and code compliance
-standards you established for your application.
-
-[GitLab itself](https://gitlab.com/gitlab-org/gitlab) is an
-example of a project that uses Continuous Integration as a software
-development method. For every push to the project, a set
-of checks run against the code.
-
-## Continuous Delivery
-
-[Continuous Delivery](https://continuousdelivery.com/) is a step
-beyond Continuous Integration. Not only is your application
-built and tested each time a code change is pushed to the codebase,
-the application is also deployed continuously. However, with continuous
-delivery, you trigger the deployments manually.
-
-Continuous Delivery checks the code automatically, but it requires
-human intervention to manually and strategically trigger the deployment
-of the changes.
-
-## Continuous Deployment
-
-Continuous Deployment is another step beyond Continuous Integration, similar to
-Continuous Delivery. The difference is that instead of deploying your
-application manually, you set it to be deployed automatically.
-Human intervention is not required.
-
-## GitLab CI/CD
-
-[GitLab CI/CD](../quick_start/index.md) is the part of GitLab that you use
-for all of the continuous methods (Continuous Integration,
-Delivery, and Deployment). With GitLab CI/CD, you can test, build,
-and publish your software with no third-party application or integration needed.
-
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For an overview, see [Introduction to GitLab CI/CD](https://www.youtube.com/watch?v=l5705U8s_nQ&t=397) from an April 2020 GitLab meetup.
-
-### GitLab CI/CD workflow
-
-GitLab CI/CD fits in a common development workflow.
-
-You can start by discussing a code implementation in an issue
-and working locally on your proposed changes. Then you can push your
-commits to a feature branch in a remote repository that's hosted in GitLab.
-The push triggers the CI/CD pipeline for your project. Then, GitLab CI/CD:
-
-- Runs automated scripts (sequentially or in parallel) to:
- - Build and test your application.
- - Preview the changes in a Review App, the same as you
- would see on your `localhost`.
-
-After the implementation works as expected:
-
-- Get your code reviewed and approved.
-- Merge the feature branch into the default branch.
- - GitLab CI/CD deploys your changes automatically to a production environment.
-
-If something goes wrong, you can roll back your changes.
-
-![GitLab workflow example](img/gitlab_workflow_example_11_9.png)
-
-This workflow shows the major steps in the GitLab process.
-You don't need any external tools to deliver your software and
-you can visualize all the steps in the GitLab UI.
-
-### A deeper look into the CI/CD workflow
-
-If you look deeper into the workflow, you can see
-the features available in GitLab at each stage of the DevOps
-lifecycle.
-
-![Deeper look into the basic CI/CD workflow](img/gitlab_workflow_example_extended_v12_3.png)
-
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-[Get a deeper look at GitLab CI/CD](https://youtu.be/l5705U8s_nQ?t=369).
+<!-- This redirect file can be deleted after <2023-11-24>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/ci/jobs/ci_job_token.md b/doc/ci/jobs/ci_job_token.md
index dee078c21e0..f1aa834a038 100644
--- a/doc/ci/jobs/ci_job_token.md
+++ b/doc/ci/jobs/ci_job_token.md
@@ -121,7 +121,7 @@ Prerequisite:
To disable the job token scope allowlist:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Token Access**.
1. Toggle **Limit access _to_ this project** to disabled.
@@ -144,7 +144,7 @@ Prerequisite:
To add a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Token Access**.
1. Verify **Limit access _to_ this project** is enabled.
@@ -188,7 +188,7 @@ Prerequisite:
To configure the job token scope:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Token Access**.
1. Toggle **Limit access _from_ this project** to enabled.
@@ -255,7 +255,7 @@ While troubleshooting CI/CD job token authentication issues, be aware that:
- A [GraphQL example mutation](../../api/graphql/getting_started.md#update-project-settings)
is available to toggle the scope settings per project.
- [This comment](https://gitlab.com/gitlab-org/gitlab/-/issues/351740#note_1335673157)
- demonstrates how to use graphQL with Bash and cURL to:
+ demonstrates how to use GraphQL with Bash and cURL to:
- Enable the inbound token access scope.
- Give access to project B from project A, or add B to A's allowlist.
- To remove project access.
diff --git a/doc/ci/jobs/index.md b/doc/ci/jobs/index.md
index 762fb717505..90a64ea7569 100644
--- a/doc/ci/jobs/index.md
+++ b/doc/ci/jobs/index.md
@@ -48,7 +48,7 @@ Selecting an individual job shows you its job log, and allows you to:
To view the full list of jobs that ran in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Jobs**.
You can filter the list by [job status](#the-order-of-jobs-in-a-pipeline).
diff --git a/doc/ci/jobs/job_artifacts.md b/doc/ci/jobs/job_artifacts.md
index b080a4fd1e9..b6269918ed9 100644
--- a/doc/ci/jobs/job_artifacts.md
+++ b/doc/ci/jobs/job_artifacts.md
@@ -299,7 +299,7 @@ You can also delete individual artifacts from the [**Artifacts** page](#bulk-del
You can delete multiple artifacts at the same time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Artifacts**.
1. Select the checkboxes next to the artifacts you want to delete. You can select up to 50 artifacts.
1. Select **Delete selected**.
@@ -341,7 +341,7 @@ Keeping the latest artifacts can use a large amount of storage space in projects
with a lot of jobs or large artifacts. If the latest artifacts are not needed in
a project, you can disable this behavior to save space:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Artifacts**.
1. Clear the **Keep artifacts from most recent successful jobs** checkbox.
diff --git a/doc/ci/jobs/job_control.md b/doc/ci/jobs/job_control.md
index 770e1d38297..1065ee93389 100644
--- a/doc/ci/jobs/job_control.md
+++ b/doc/ci/jobs/job_control.md
@@ -867,7 +867,7 @@ linux:rspec:
parallel:
matrix:
- PROVIDER: aws
- - STACK: app1
+ STACK: app1
script: echo "Running rspec on linux..."
mac:rspec:
@@ -877,7 +877,7 @@ mac:rspec:
parallel:
matrix:
- PROVIDER: [gcp, vultr]
- - STACK: [data]
+ STACK: [data]
script: echo "Running rspec on mac..."
production:
diff --git a/doc/ci/large_repositories/index.md b/doc/ci/large_repositories/index.md
index da5ebe21341..cef0554bf6c 100644
--- a/doc/ci/large_repositories/index.md
+++ b/doc/ci/large_repositories/index.md
@@ -1,254 +1,11 @@
---
-stage: Verify
-group: Runner
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-type: reference
+redirect_to: '../../user/project/repository/managing_large_repositories.md'
+remove_date: '2023-11-30'
---
-# Optimize GitLab for large repositories **(FREE ALL)**
+This document was moved to [another location](../../user/project/repository/managing_large_repositories.md).
-Large repositories consisting of more than 50k files in a worktree
-may require more optimizations beyond
-[pipeline efficiency](../pipelines/pipeline_efficiency.md)
-because of the time required to clone and check out.
-
-GitLab and GitLab Runner handle this scenario well
-but require optimized configuration to efficiently perform its
-set of operations.
-
-The general guidelines for handling big repositories are simple.
-Each guideline is described in more detail in the sections below:
-
-- Always fetch incrementally. Do not clone in a way that results in recreating all of the worktree.
-- Always use shallow clone to reduce data transfer. Be aware that this puts more burden
- on GitLab instance due to higher CPU impact.
-- Control the clone directory if you heavily use a fork-based workflow.
-- Optimize `git clean` flags to ensure that you remove or keep data that might affect or speed-up your build.
-
-## Shallow cloning
-
-> Introduced in GitLab Runner 8.9.
-
-GitLab and GitLab Runner perform a [shallow clone](../pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone)
-by default.
-
-Ideally, you should always use `GIT_DEPTH` with a small number
-like 10. This instructs GitLab Runner to perform shallow clones.
-Shallow clones make Git request only the latest set of changes for a given branch,
-up to desired number of commits as defined by the `GIT_DEPTH` variable.
-
-This significantly speeds up fetching of changes from Git repositories,
-especially if the repository has a very long backlog consisting of number
-of big files as we effectively reduce amount of data transfer.
-
-The following example makes the runner shallow clone to fetch only a given branch;
-it does not fetch any other branches nor tags.
-
-```yaml
-variables:
- GIT_DEPTH: 10
-
-test:
- script:
- - ls -al
-```
-
-## Git strategy
-
-> Introduced in GitLab Runner 8.9.
-
-By default, GitLab is configured to use the [`fetch` Git strategy](../runners/configure_runners.md#git-strategy),
-which is recommended for large repositories.
-This strategy reduces the amount of data to transfer and
-does not really impact the operations that you might do on a repository from CI.
-
-## Git clone path
-
-> Introduced in GitLab Runner 11.10.
-
-[`GIT_CLONE_PATH`](../runners/configure_runners.md#custom-build-directories) allows you to
-control where you clone your sources. This can have implications if you
-heavily use big repositories with fork workflow.
-
-Fork workflow from GitLab Runner's perspective is stored as a separate repository
-with separate worktree. That means that GitLab Runner cannot optimize the usage
-of worktrees and you might have to instruct GitLab Runner to use that.
-
-In such cases, ideally you want to make the GitLab Runner executor be used only
-for the given project and not shared across different projects to make this
-process more efficient.
-
-The [`GIT_CLONE_PATH`](../runners/configure_runners.md#custom-build-directories) has to be
-within the `$CI_BUILDS_DIR`. Currently, it is impossible to pick any path
-from disk.
-
-## Git clean flags
-
-> Introduced in GitLab Runner 11.10.
-
-[`GIT_CLEAN_FLAGS`](../runners/configure_runners.md#git-clean-flags) allows you to control
-whether or not you require the `git clean` command to be executed for each CI
-job. By default, GitLab ensures that you have your worktree on the given SHA,
-and that your repository is clean.
-
-[`GIT_CLEAN_FLAGS`](../runners/configure_runners.md#git-clean-flags) is disabled when set
-to `none`. On very big repositories, this might be desired because `git
-clean` is disk I/O intensive. Controlling that with `GIT_CLEAN_FLAGS: -ffdx
--e .build/` (for example) allows you to control and disable removal of some
-directories within the worktree between subsequent runs, which can speed-up
-the incremental builds. This has the biggest effect if you re-use existing
-machines and have an existing worktree that you can re-use for builds.
-
-For exact parameters accepted by
-[`GIT_CLEAN_FLAGS`](../runners/configure_runners.md#git-clean-flags), see the documentation
-for [`git clean`](https://git-scm.com/docs/git-clean). The available parameters
-are dependent on Git version.
-
-## Git fetch extra flags
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4142) in GitLab Runner 13.1.
-
-[`GIT_FETCH_EXTRA_FLAGS`](../runners/configure_runners.md#git-fetch-extra-flags) allows you
-to modify `git fetch` behavior by passing extra flags.
-
-For example, if your project contains a large number of tags that your CI jobs don't rely on,
-you could add [`--no-tags`](https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---no-tags)
-to the extra flags to make your fetches faster and more compact.
-
-Also in the case where you repository does _not_ contain a lot of
-tags, `--no-tags` can [make a big difference in some cases](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/746).
-If your CI builds do not depend on Git tags it is worth trying.
-
-See the [`GIT_FETCH_EXTRA_FLAGS` documentation](../runners/configure_runners.md#git-fetch-extra-flags)
-for more information.
-
-## Fork-based workflow
-
-> Introduced in GitLab Runner 11.10.
-
-Following the guidelines above, let's imagine that we want to:
-
-- Optimize for a big project (more than 50k files in directory).
-- Use forks-based workflow for contributing.
-- Reuse existing worktrees. Have preconfigured runners that are pre-cloned with repositories.
-- Runner assigned only to project and all forks.
-
-Let's consider the following two examples, one using `shell` executor and
-other using `docker` executor.
-
-### `shell` executor example
-
-Let's assume that you have the following [`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html).
-
-```toml
-concurrent = 4
-
-[[runners]]
- url = "GITLAB_URL"
- token = "TOKEN"
- executor = "shell"
- builds_dir = "/builds"
- cache_dir = "/cache"
-
- [runners.custom_build_dir]
- enabled = true
-```
-
-This `config.toml`:
-
-- Uses the `shell` executor,
-- Specifies a custom `/builds` directory where all clones are stored.
-- Enables the ability to specify `GIT_CLONE_PATH`,
-- Runs at most 4 jobs at once.
-
-### `docker` executor example
-
-Let's assume that you have the following [`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html).
-
-```toml
-concurrent = 4
-
-[[runners]]
- url = "GITLAB_URL"
- token = "TOKEN"
- executor = "docker"
- builds_dir = "/builds"
- cache_dir = "/cache"
-
- [runners.docker]
- volumes = ["/builds:/builds", "/cache:/cache"]
-```
-
-This `config.toml`:
-
-- Uses the `docker` executor,
-- Specifies a custom `/builds` directory on disk where all clones are stored.
- We host mount the `/builds` directory to make it reusable between subsequent runs
- and be allowed to override the cloning strategy.
-- Doesn't enable the ability to specify `GIT_CLONE_PATH` as it is enabled by default.
-- Runs at most 4 jobs at once.
-
-### Our `.gitlab-ci.yml`
-
-Once we have the executor configured, we need to fine tune our `.gitlab-ci.yml`.
-
-Our pipeline is most performant if we use the following `.gitlab-ci.yml`:
-
-```yaml
-variables:
- GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME
-
-build:
- script: ls -al
-```
-
-This YAML setting configures a custom clone path. This path makes it possible to re-use worktrees
-between the parent project and forks because we use the same clone path for all forks.
-
-Why use `$CI_CONCURRENT_ID`? The main reason is to ensure that worktrees used are not conflicting
-between projects. The `$CI_CONCURRENT_ID` represents a unique identifier within the given executor.
-When we use it to construct the path, this directory does not conflict
-with other concurrent jobs running.
-
-### Store custom clone options in `config.toml`
-
-Ideally, all job-related configuration should be stored in `.gitlab-ci.yml`.
-However, sometimes it is desirable to make these schemes part of the runner's configuration.
-
-In the above example of Forks, making this configuration discoverable for users may be preferred,
-but this brings administrative overhead as the `.gitlab-ci.yml` needs to be updated for each branch.
-In such cases, it might be desirable to keep the `.gitlab-ci.yml` clone path agnostic, but make it
-a configuration of the runner.
-
-We can extend our [`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html)
-with the following specification that is used by the runner if `.gitlab-ci.yml` does not override it:
-
-```toml
-concurrent = 4
-
-[[runners]]
- url = "GITLAB_URL"
- token = "TOKEN"
- executor = "docker"
- builds_dir = "/builds"
- cache_dir = "/cache"
-
- environment = [
- "GIT_CLONE_PATH=$CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME"
- ]
-
- [runners.docker]
- volumes = ["/builds:/builds", "/cache:/cache"]
-```
-
-This makes the cloning configuration to be part of the given runner
-and does not require us to update each `.gitlab-ci.yml`.
-
-## Git fetch caching step
-
-For very active repositories with a large number of references and files, consider using the
-[Gitaly pack-objects cache](../../administration/gitaly/configure_gitaly.md#pack-objects-cache).
-The pack-objects cache:
-
-- Benefits all repositories on your GitLab server.
-- Automatically works for forks.
+<!-- This redirect file can be deleted after <2023-11-30>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/ci/lint.md b/doc/ci/lint.md
index 0ca0469f5e9..2b54c645807 100644
--- a/doc/ci/lint.md
+++ b/doc/ci/lint.md
@@ -24,7 +24,7 @@ configuration added with the [`includes` keyword](yaml/index.md#include).
To check CI/CD configuration with the CI lint tool:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipelines**.
1. In the upper-right corner, select **CI lint**.
1. Paste a copy of the CI/CD configuration you want to check into the text box.
@@ -45,7 +45,7 @@ Prerequisites:
To simulate a pipeline:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipelines**.
1. In the upper-right corner, select **CI lint**.
1. Paste a copy of the CI/CD configuration you want to check into the text box.
diff --git a/doc/ci/migration/examples/img/maven-freestyle-plugin.png b/doc/ci/migration/examples/img/maven-freestyle-plugin.png
new file mode 100644
index 00000000000..bb3308a1595
--- /dev/null
+++ b/doc/ci/migration/examples/img/maven-freestyle-plugin.png
Binary files differ
diff --git a/doc/ci/migration/examples/img/maven-freestyle-shell.png b/doc/ci/migration/examples/img/maven-freestyle-shell.png
new file mode 100644
index 00000000000..73ecbb9401d
--- /dev/null
+++ b/doc/ci/migration/examples/img/maven-freestyle-shell.png
Binary files differ
diff --git a/doc/ci/migration/examples/jenkins-maven.md b/doc/ci/migration/examples/jenkins-maven.md
new file mode 100644
index 00000000000..0ed08357eef
--- /dev/null
+++ b/doc/ci/migration/examples/jenkins-maven.md
@@ -0,0 +1,232 @@
+---
+stage: Verify
+group: Pipeline Authoring
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: index, howto
+---
+
+# Migrate a Maven build from Jenkins to GitLab CI/CD
+
+If you have a Maven build in Jenkins, you can use a [Java Spring](https://gitlab.com/gitlab-org/project-templates/spring)
+project template to migrate to GitLab. The template uses Maven for its underlying dependency management.
+
+## Sample Jenkins configurations
+
+The following three Jenkins examples each use different methods to test, build, and install a
+Maven project into a shell agent:
+
+- Freestyle with shell execution
+- Freestyle with the Maven task plugin
+- A declarative pipeline using a Jenkinsfile
+
+All three examples run the same three commands in order, in three different stages:
+
+- `mvn test`: Run any tests found in the codebase
+- `mvn package -DskipTests`: Compile the code into an executable type defined in the POM
+ and skip running any tests because that was done in the first stage.
+- `mvn install -DskipTests`: Install the compiled executable into the agent's local Maven
+ `.m2` repository and again skip running the tests.
+
+These examples use a single, persistent Jenkins agent, which requires Maven to be
+pre-installed on the agent. This method of execution is similar to a GitLab Runner
+using the [shell executor](https://docs.gitlab.com/runner/executors/shell.html).
+
+### Freestyle with shell execution
+
+If using Jenkins' built-in shell execution option to directly call `mvn` commands
+from the shell on the agent, the configuration might look like:
+
+![freestyle shell](img/maven-freestyle-shell.png)
+
+### Freestyle with Maven task plugin
+
+If using the Maven plugin in Jenkins to declare and execute any specific goals
+in the [Maven build lifecycle](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html),
+the configuration might look like:
+
+![freestyle plugin](img/maven-freestyle-plugin.png)
+
+This plugin requires Maven to be installed on the Jenkins agent, and uses a script wrapper
+for calling Maven commands.
+
+### Using a declarative pipeline
+
+If using a declarative pipeline, the configuration might look like:
+
+```groovy
+pipeline {
+ agent any
+ tools {
+ maven 'maven-3.6.3'
+ jdk 'jdk11'
+ }
+ stages {
+ stage('Build') {
+ steps {
+ sh "mvn package -DskipTests"
+ }
+ }
+ stage('Test') {
+ steps {
+ sh "mvn test"
+ }
+ }
+ stage('Install') {
+ steps {
+ sh "mvn install -DskipTests"
+ }
+ }
+ }
+}
+```
+
+This example uses shell execution commands instead of plugins.
+
+By default, a declarative pipeline configuration is stored either in the Jenkins
+pipeline configuration or directly in the Git repository in a `Jenksinfile`.
+
+## Convert Jenkins configuration to GitLab CI/CD
+
+While the examples above are all slightly different, they can all be migrated to GitLab CI/CD
+with the same pipeline configuration.
+
+Prerequisites:
+
+- A GitLab Runner with a Shell executor
+- Maven 3.6.3 and Java 11 JDK installed on the shell runner
+
+This example mimics the behavior and syntax of building, testing, and installing on Jenkins.
+
+In a GitLab CI/CD pipeline, the commands run in "jobs", which are grouped into stages.
+The migrated configuration in the `.gitlab-ci.yml` configuration file consists of
+two global keywords (`stages` and `variables`) followed by 3 jobs:
+
+```yaml
+stages:
+ - build
+ - test
+ - install
+
+variables:
+ MAVEN_OPTS: >-
+ -Dhttps.protocols=TLSv1.2
+ -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository
+ MAVEN_CLI_OPTS: >-
+ -DskipTests
+
+build-JAR:
+ stage: build
+ script:
+ - mvn $MAVEN_CLI_OPTS package
+
+test-code:
+ stage: test
+ script:
+ - mvn test
+
+install-JAR:
+ stage: install
+ script:
+ - mvn $MAVEN_CLI_OPTS install
+```
+
+In this example:
+
+- `stages` defines three stages that run in order. Like the Jenkins examples above,
+ the test job runs first, followed by the build job, and finally the install job.
+- `variables` defines [CI/CD variables](../../variables/index.md) that can be used by all jobs:
+ - `MAVEN_OPTS` are Maven environment variables needed whenever Maven is executed:
+ - `-Dhttps.protocols=TLSv1.2` sets the TLS protocol to version 1.2 for any HTTP requests in the pipeline.
+ - `-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository` sets the location of the
+ local Maven repository to the GitLab project directory on the runner, so the job
+ can access and modify the repository.
+ - `MAVEN_CLI_OPTS` are specific arguments to be added to `mvn` commands:
+ - `-DskipTests` skips the `test` stage in the Maven build lifecycle.
+- `test-code`, `build-JAR`, and `install-JAR` are the user-defined names for the jobs
+ to run in the pipeline:
+ - `stage` defines which stage the job runs in. A pipeline contains one or more stages
+ and a stage contains one or more jobs. This example has three stages, each with a single job.
+ - `script` defines the commands to run in that job, similar to `steps` in a `Jenkinsfile`.
+ Jobs can run multiple commands in sequence, which run in the image container,
+ but in this example the jobs run only one command each.
+
+### Run jobs in Docker containers
+
+Instead of using a persistent machine for handling this build process like the Jenkins samples,
+this example uses an ephemeral Docker container to handle execution. Using a container
+removes the need for maintaining a virtual machine and the Maven version installed on it.
+It also increases flexibility for expanding and extending the functionality of the pipeline.
+
+Prerequisites:
+
+- A GitLab Runner with the Docker executor that can be used by the project.
+ If you are using GitLab.com, you can use the public shared runners.
+
+This migrated pipeline configuration consists of three global keywords (`stages`, `default`, and `variables`)
+followed by 3 jobs. This configuration makes use of additional GitLab CI/CD features
+for an improved pipeline compared to the [example above](#convert-jenkins-configuration-to-gitlab-cicd):
+
+```yaml
+stages:
+ - build
+ - test
+ - install
+
+default:
+ image: maven:3.6.3-openjdk-11
+ cache:
+ key: $CI_COMMIT_REF_SLUG
+ paths:
+ - .m2/
+
+variables:
+ MAVEN_OPTS: >-
+ -Dhttps.protocols=TLSv1.2
+ -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository
+ MAVEN_CLI_OPTS: >-
+ -DskipTests
+
+build-JAR:
+ stage: build
+ script:
+ - mvn $MAVEN_CLI_OPTS package
+
+test-code:
+ stage: test
+ script:
+ - mvn test
+
+install-JAR:
+ stage: install
+ script:
+ - mvn $MAVEN_CLI_OPTS install
+```
+
+In this example:
+
+- `stages` defines three stages that run in order. Like the Jenkins examples above,
+ the test job runs first, followed by the build job, and finally the install job.
+- `default` defines standard configuration to reuse in all jobs by default:
+ - `image` defines the Docker image container to use and execute commands in. In this example,
+ it's an official Maven Docker image with everything needed already installed.
+ - `cache` is used to cache and reuse dependencies:
+ - `key` is the unique identifier for the specific cache archive. In this example,
+ it's a shortened version of the Git commit ref, autogenerated as a [predefined CI/CD variable](../../variables/predefined_variables.md).
+ Any job that runs for the same commit ref reuses the same cache.
+ - `paths` are the directories or files to include in the cache. In this example,
+ we cache the `.m2/` directory to avoid re-installing dependencies between job runs.
+- `variables` defines [CI/CD variables](../../variables/index.md) that can be used by all jobs:
+ - `MAVEN_OPTS` are Maven environment variables needed whenever Maven is executed:
+ - `-Dhttps.protocols=TLSv1.2` sets the TLS protocol to version 1.2 for any HTTP requests in the pipeline.
+ - `-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository` sets the location of the
+ local Maven repository to the GitLab project directory on the runner, so the job
+ can access and modify the repository.
+ - `MAVEN_CLI_OPTS` are specific arguments to be added to `mvn` commands:
+ - `-DskipTests` skips the `test` stage in the Maven build lifecycle.
+- `test-code`, `build-JAR`, and `install-JAR` are the user-defined names for the jobs
+ to run in the pipeline:
+ - `stage` defines which stage the job runs in. A pipeline contains one or more stages
+ and a stage contains one or more jobs. This example has three stages, each with a single job.
+ - `script` defines the commands to run in that job, similar to `steps` in a `Jenkinsfile`.
+ Jobs can run multiple commands in sequence, which run in the image container,
+ but in this example the jobs run only one command each.
diff --git a/doc/ci/migration/jenkins.md b/doc/ci/migration/jenkins.md
index 54ea3812029..d02c2f9c54e 100644
--- a/doc/ci/migration/jenkins.md
+++ b/doc/ci/migration/jenkins.md
@@ -7,215 +7,175 @@ type: index, howto
# Migrating from Jenkins **(FREE ALL)**
-A lot of GitLab users have successfully migrated to GitLab CI/CD from Jenkins.
-We've collected several resources here that you might find informative if you're just getting started.
-Think of this page as a "GitLab CI/CD for Jenkins Users" guide.
+If you're migrating from Jenkins to GitLab CI/CD, you should be able
+to create CI/CD pipelines that do everything you need.
+
+You can start by watching the [Migrating from Jenkins to GitLab](https://www.youtube.com/watch?v=RlEVGOpYF5Y)
+video for examples of:
+
+- Converting a Jenkins pipeline into a GitLab CI/CD pipeline.
+- Using Auto DevOps to test your code automatically.
+
+## Get started
The following list of recommended steps was created after observing organizations
-that were able to quickly complete this migration:
-
-1. Start by reading the GitLab CI/CD [Quick Start Guide](../quick_start/index.md) and [important product differences](#important-product-differences).
-1. Learn the importance of [managing the organizational transition](#manage-organizational-transition).
-1. [Add runners](../runners/index.md) to your GitLab instance.
-1. Educate and enable your developers to independently perform the following steps in their projects:
- 1. Review the [Quick Start Guide](../quick_start/index.md) and [Pipeline Configuration Reference](../yaml/index.md).
- 1. Use the [Jenkins Wrapper](#jenkinsfile-wrapper) to temporarily maintain fragile Jenkins jobs.
- 1. Migrate the build and CI jobs and configure them to show results directly in your merge requests. They can use [Auto DevOps](../../topics/autodevops/index.md) as a starting point, and [customize](../../topics/autodevops/customize.md) or [decompose](../../topics/autodevops/customize.md#use-individual-components-of-auto-devops) the configuration as needed.
- 1. Add [Review Apps](../review_apps/index.md).
- 1. Migrate the deployment jobs using [cloud deployment templates](../cloud_deployment/index.md), adding [environments](../environments/index.md), and [deploy boards](../../user/project/deploy_boards.md).
- 1. Work to unwrap any jobs still running with the use of the Jenkins wrapper.
-1. Take stock of any common CI/CD job definitions then create and share [templates](#templates) for them.
-1. Check the [pipeline efficiency documentation](../pipelines/pipeline_efficiency.md)
- to learn how to make your GitLab CI/CD pipelines faster and more efficient.
-
-Watch the [Migrating from Jenkins to GitLab](https://www.youtube.com/watch?v=RlEVGOpYF5Y) video for examples of how to:
-
-- Convert a Jenkins pipeline into a GitLab CI/CD pipeline.
-- Use Auto DevOps to test your code automatically.
-
-Otherwise, read on for important information that helps you get the ball rolling. Welcome
-to GitLab!
+that were able to quickly complete this migration.
+
+Before doing any migration work, you should [start with a migration plan](plan_a_migration.md).
+
+Engineers that need to migrate projects to GitLab CI/CD should:
+
+- Read about some [key GitLab CI/CD features](#key-gitlab-cicd-features).
+- Follow tutorials to create:
+ - [Your first GitLab pipeline](../quick_start/index.md).
+ - [A more complex pipeline](../quick_start/tutorial.md) that builds, tests,
+ and deploys a static site.
+- Review the [`.gitlab-ci.yml` keyword reference](../yaml/index.md).
+- Ensure [runners](../runners/index.md) are available, either by using shared GitLab.com runners
+ or installing new runners.
+- Migrate build and CI jobs and configure them to show results directly in merge requests.
+ You can use [Auto DevOps](../../topics/autodevops/index.md) as a starting point,
+ and [customize](../../topics/autodevops/customize.md) or [decompose](../../topics/autodevops/customize.md#use-individual-components-of-auto-devops)
+ the configuration as needed.
+- Migrate deployment jobs by using [cloud deployment templates](../cloud_deployment/index.md),
+ [environments](../environments/index.md), and the [GitLab agent for Kubernetes](../../user/clusters/agent/index.md).
+- Check if any CI/CD configuration can be reused across different projects, then create
+ and share [templates](#templates).
+- Check the [pipeline efficiency documentation](../pipelines/pipeline_efficiency.md)
+ to learn how to make your GitLab CI/CD pipelines faster and more efficient.
If you have questions that are not answered here, the [GitLab community forum](https://forum.gitlab.com/)
can be a great resource.
-## Manage organizational transition
-
-An important part of transitioning from Jenkins to GitLab is the cultural and organizational
-changes that come with the move, and successfully managing them. A few
-things we have found that help this are:
-
-- Setting and communicating a clear vision of what your migration goals are helps
- your users understand why the effort is worth it. The value is clear when
- the work is done, but people need to be aware while it's in progress too.
-- Sponsorship and alignment from the relevant leadership team helps with the point above.
-- Spending time educating your users on what's different and sharing this document
- with them helps ensure you are successful.
-- Finding ways to sequence or delay parts of the migration can help a lot, but you
- don't want to leave things in a non-migrated (or partially-migrated) state for too
- long. To gain all the benefits of GitLab, moving your existing Jenkins setup over
- as-is, including any current problems, isn't enough. You need to take advantage
- of the improvements that GitLab offers, and this requires (eventually) updating
- your implementation as part of the transition.
-
-## JenkinsFile Wrapper
-
-We are building a [JenkinsFile Wrapper](https://gitlab.com/gitlab-org/jfr-container-builder/) which
-you can use to run a complete Jenkins instance inside of a GitLab job, including plugins. This can help ease the process
-of transition, by letting you delay the migration of less urgent pipelines for a period of time.
-
-If you are interested in helping GitLab test the wrapper, join our [public testing issue](https://gitlab.com/gitlab-org/gitlab/-/issues/215675) for instructions and to provide your feedback.
-
-NOTE:
-If you have a paid GitLab subscription, the JenkinsFile Wrapper is not packaged with GitLab and falls outside of the scope of support. For more information, see the [Statement of Support](https://about.gitlab.com/support/statement-of-support/).
-
-## Important product differences
-
-Some high level differences between the products worth mentioning are:
-
-- With GitLab you don't need a root `pipeline` keyword to wrap everything.
-- The way pipelines are triggered and [trigger other pipelines](../yaml/index.md#trigger)
- is different than Jenkins. GitLab pipelines can be triggered:
-
- - on push
- - on [schedule](../pipelines/schedules.md)
- - from the [GitLab UI](../pipelines/index.md#run-a-pipeline-manually)
- - by [API call](../triggers/index.md)
- - by [webhook](../triggers/index.md#use-a-webhook)
- - by [ChatOps](../chatops/index.md)
-
-- You can control which jobs run in which cases, depending on how they are triggered,
- with the [`rules` syntax](../yaml/index.md#rules).
-- GitLab [pipeline scheduling concepts](../pipelines/schedules.md) are also different from Jenkins.
-- You can reuse pipeline configurations using the [`include` keyword](../yaml/index.md#include)
- and [templates](#templates). Your templates can be kept in a central repository (with different
- permissions), and then any project can use them. This central project could also
- contain scripts or other reusable code.
-- You can also use the [`extends` keyword](../yaml/index.md#extends) to reuse configuration
- in a single pipeline configuration.
-- All jobs in a single stage always run in parallel, and all stages run in sequence.
- Certain jobs might break this sequencing as needed with our [directed acyclic graph](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/47063)
- feature.
+### Key GitLab CI/CD features
+
+GitLab CI/CD key features might be different or not exist in Jenkins. For example,
+in GitLab:
+
+- Pipelines can be triggered with:
+ - A Git push
+ - A [Schedule](../pipelines/schedules.md)
+ - The [GitLab UI](../pipelines/index.md#run-a-pipeline-manually)
+ - An [API call](../triggers/index.md)
+ - A [webhook](../triggers/index.md#use-a-webhook)
+- You can control which jobs run in which cases with the [`rules` syntax](../yaml/index.md#rules).
+- You can reuse pipeline configurations:
+ - Use the [`extends` keyword](../yaml/index.md#extends) to reuse configuration
+ in a single pipeline configuration.
+ - Use the [`include` keyword](../yaml/index.md#include) to reuse configuration across
+ multiple pipelines and projects.
+- Jobs are grouped into stages, and jobs in the same stage can run at the same time.
+ Stages run in sequence. Jobs can be configured to run outside of the stage ordering with the
+ [`needs` keyword](../yaml/index.md#needs).
- The [`parallel`](../yaml/index.md#parallel) keyword can automatically parallelize tasks,
- like tests that support parallelization.
-- Usually all jobs in a single stage run in parallel, and all stages run in sequence.
- Different [pipeline architectures](../pipelines/pipeline_architectures.md) allow you to change this behavior.
-- The new [`rules` syntax](../yaml/index.md#rules) is the recommended method of
- controlling when different jobs run. It is more powerful than the `only/except` syntax.
-- One important difference is that jobs run independently of each other and have a
- fresh environment in each job. Passing artifacts between jobs is controlled using the
- [`artifacts`](../yaml/index.md#artifacts) and [`dependencies`](../yaml/index.md#dependencies)
- keywords. When finished, use the planned [Workspaces](https://gitlab.com/gitlab-org/gitlab/-/issues/29265)
- feature to persist a common workspace between serial jobs.
-- The `.gitlab-ci.yml` file is checked in to the root of your repository, much like a Jenkinsfile, but
- is in the YAML format (see [complete reference](../yaml/index.md)) instead of a Groovy DSL. It's most
- analogous to the declarative Jenkinsfile format.
-- Manual approvals or gates can be set up as [`when:manual` jobs](../jobs/job_control.md#create-a-job-that-must-be-run-manually). These can
- also leverage [`protected environments`](../jobs/job_control.md#run-a-job-after-a-delay)
- to control who is able to approve them.
-- GitLab comes with a [container registry](../../user/packages/container_registry/index.md), so you can use
- container images to set up your build environment. For example, set up one pipeline that builds your build environment
- itself and publish that to the container registry. Then, have your pipelines use this instead of each building their
- own environment, which is slower and may be less consistent. We have extensive documentation on [how to use the Container Registry](../../user/packages/container_registry/index.md).
-- A central utilities repository can be a great place to put assorted scheduled jobs
- or other manual jobs that function like utilities. Jenkins installations tend to
- have a few of these.
-
-## Agents vs. runners
-
-Both Jenkins agents and GitLab runners are the hosts that run jobs. To convert the
-Jenkins agent, uninstall it and then [install and register the runner](../runners/index.md).
-Runners do not require much overhead, so you can size them similarly to the Jenkins
-agents you were using.
-
-Some important differences in the way runners work in comparison to agents are:
-
-- Runners can be set up as [shared across an instance, be added at the group level, or set up at the project level](../runners/runners_scope.md).
- They self-select jobs from the scopes you've defined automatically.
-- You can also [use tags](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) for finer control, and
- associate runners with specific jobs. For example, you can use a tag for jobs that
+ especially tests that support parallelization.
+- Jobs run independently of each other and have a fresh environment for each job.
+ Passing artifacts between jobs is controlled using the [`artifacts`](../yaml/index.md#artifacts)
+ and [`dependencies`](../yaml/index.md#dependencies) keywords.
+- The `.gitlab-ci.yml` configuration file exists in your Git repository, like a `Jenkinsfile`,
+ but is [a YAML file](#yaml-configuration-file), not Groovy.
+- GitLab comes with a [container registry](../../user/packages/container_registry/index.md).
+ You can build and store custom container images to run your jobs in.
+
+## Runners
+
+Like Jenkins agents, GitLab runners are the hosts that run jobs. If you are using GitLab.com,
+you can use the [shared runner fleet](../runners/index.md) to run jobs without provisioning
+your own runners.
+
+To convert a Jenkins agent for use with GitLab CI/CD, uninstall the agent and then
+[install and register a runner](../runners/index.md). Runners do not require much overhead,
+so you might be able to use similar provisioning as the Jenkins agents you were using.
+
+Some key details about runners:
+
+- Runners can be [configured](../runners/runners_scope.md) to be shared across an instance,
+ a group, or dedicated to a single project.
+- You can use the [`tags` keyword](../runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run)
+ for finer control, and associate runners with specific jobs. For example, you can use a tag for jobs that
require dedicated, more powerful, or specific hardware.
- GitLab has [autoscaling for runners](https://docs.gitlab.com/runner/configuration/autoscale.html).
Use autoscaling to provision runners only when needed and scale down when not needed,
similar to ephemeral agents in Jenkins.
-If you are using `gitlab.com`, you can take advantage of our [shared runner fleet](../runners/index.md)
-to run jobs without provisioning your own runners. We are investigating making them
-[available for self-managed instances](https://gitlab.com/groups/gitlab-org/-/epics/835)
-as well.
+## YAML configuration file
-## Groovy vs. YAML
+GitLab pipeline configuration files use the [YAML](https://yaml.org/) format instead of
+the [Groovy](https://groovy-lang.org/) format that Jenkins uses.
-Jenkins Pipelines are based on [Groovy](https://groovy-lang.org/), so the pipeline specification is written as code.
-GitLab works a bit differently, using the more highly structured [YAML](https://yaml.org/) format.
-The scripting elements are in `script` blocks separate from the pipeline specification itself.
-
-Using YAML is a strength of GitLab, in that it helps keep the learning curve much simpler to get up and running.
-It also avoids some of the problem of unconstrained complexity which can make your Jenkinsfile hard to understand
-and manage.
-
-We do of course still value DRY (don't repeat yourself) principles. We want to ensure that
-behaviors of your jobs can be codified once and applied as needed. You can use the `extends` syntax to
-[reuse configuration in your jobs](../yaml/index.md#extends), and `include` can
-be used to [reuse pipeline configurations](../yaml/index.md#include) in pipelines
-in different projects:
+Using YAML is a strength of GitLab CI/CD, as it is a simple format to understand
+and start using. For example, a small configuration file with two jobs and some
+shared configuration in a hidden job:
```yaml
-.in-docker:
+.test-config:
tags:
- - docker
- image: alpine
+ - docker-runners
+ stage: test
-rspec:
+test-job:
extends:
- - .in-docker
+ - .docker-config
script:
- - rake rspec
+ - bundle exec rake rspec
+
+lint-job:
+ extends:
+ - .docker-config
+ script:
+ - yarn run prettier
```
-## Artifact publishing
+In this example:
+
+- The commands to run in jobs are added with the [`script` keyword](../yaml/index.md#script).
+- The [`extends` keyword](../yaml/index.md#extends) reduces duplication in the configuration
+ by adding the same `tags` and `stage` configuration defined in `.test-config` to both jobs.
+
+### Artifacts
+
+In GitLab, any job can use the [`artifacts` keyword](../yaml/index.md#artifacts)
+to define a set of [artifacts](../jobs/job_artifacts.md) to be stored when a job completes.
+Artifacts are files that can be used in later jobs, for example for testing or deployment.
-Artifacts may work a bit differently than you've used them with Jenkins. In GitLab, any job can define
-a set of artifacts to be saved by using the `artifacts` keyword. This can be configured to point to a file
-or set of files that can then be persisted from job to job. Read more on our detailed
-[artifacts documentation](../jobs/job_artifacts.md):
+For example:
```yaml
pdf:
script: xelatex mycv.tex
artifacts:
paths:
- - ./mycv.pdf
- - ./output/
+ - mycv.pdf
+ - output/
expire_in: 1 week
```
-Additionally, we have package management features like built-in container and package registries that you
-can leverage. You can see the complete list of packaging features in the
-[Packages and registries](../../user/packages/index.md) documentation.
+In this example:
-## Integrated features
+- The `mycv.pdf` file and all the files in `output/` are stored and could be used
+ in later jobs.
+- To save resources, the artifacts expire and are deleted after one week.
-You may have used plugins to get things like code quality, unit tests, and security scanning working in Jenkins.
-GitLab takes advantage of our connected ecosystem to automatically pull these kinds of results into
-your merge requests, pipeline details pages, and other locations. You may find that you actually don't
-need to configure anything to have these appear.
+### Scanning features
-Our [CI/CD feature index](../index.md#features) has the full list of bundled features and links to the documentation for each.
-Refer to this index if these features aren't working as expected, or if you'd like to see what's available.
+You might have used plugins for things like code quality, security, or static application scanning
+in Jenkins. Tools like these are already available in GitLab and can be used in your
+pipeline.
+
+GitLab features including [code quality](../testing/code_quality.md), [security scanning](../../user/application_security/index.md),
+[SAST](../../user/application_security/sast/index.md), and many others generate reports
+when they complete. These reports can be displayed in merge requests and pipeline details pages.
### Templates
-For advanced CI/CD teams, project templates can enable the reuse of pipeline configurations,
-as well as encourage inner sourcing.
+For organizations with many CI/CD pipelines, you can use project templates to configure
+custom CI/CD configuration templates and reuse them across projects.
+
+Group maintainers can configure a group to use as the source for [custom project templates](../../administration/custom_project_templates.md).
+These templates can be used by all projects in the group.
-In self-managed GitLab instances, you can build an [Instance Template Repository](../../administration/settings/instance_template_repository.md).
-Development teams across the whole organization can select templates from a dropdown list.
-A group maintainer or a group owner is able to set a group to use as the source for the
-[custom project templates](../../administration/custom_project_templates.md). This can
-be used by all projects in the group. An instance administrator can set a group as
-the source for [instance project templates](../../user/group/custom_project_templates.md),
-which can be used by projects in that instance.
+An instance administrator can set a group as the source for [instance project templates](../../user/group/custom_project_templates.md),
+which can be used by all projects in that instance.
## Convert a declarative Jenkinsfile
@@ -361,7 +321,48 @@ my_job:
- if: $CI_COMMIT_BRANCH
```
+## Secrets Management
+
+Privileged information, often referred to as "secrets", is sensitive information
+or credentials you need in your CI/CD workflow. You might use secrets to unlock protected resources
+or sensitive information in tools, applications, containers, and cloud-native environments.
+
+Secrets management in Jenkins is usually handled with the `Secret` type field or the
+Credentials Plugin. Credentials stored in the Jenkins settings can be exposed to
+jobs as environment variables by using the Credentials Binding plugin.
+
+For secrets management in GitLab, you can use one of the supported integrations
+for an external service. These services securely store secrets outside of your GitLab project,
+though you must have a subscription for the service:
+
+- [HashiCorp Vault](../secrets/id_token_authentication.md#automatic-id-token-authentication-with-hashicorp-vault)
+- [Azure Key Vault](../secrets/azure_key_vault.md).
+
+GitLab also supports [OIDC authentication](../secrets/id_token_authentication.md)
+for other third party services that support OIDC.
+
+Additionally, you can make credentials available to jobs by storing them in CI/CD variables, though secrets
+stored in plain text are susceptible to accidental exposure, [the same as in Jenkins](https://www.jenkins.io/doc/developer/security/secrets/#storing-secrets).
+You should always store sensitive information in [masked](../variables/index.md#mask-a-cicd-variable)
+and [protected](../variables/index.md#protect-a-cicd-variable) variables, which mitigates
+some of the risk.
+
+Also, never store secrets as variables in your `.gitlab-ci.yml` file, which is public to all
+users with access to the project. Storing sensitive information in variables should
+only be done in [the project, group, or instance settings](../variables/index.md#define-a-cicd-variable-in-the-ui).
+
+Review the [security guidelines](../variables/index.md#cicd-variable-security) to improve
+the safety of your CI/CD variables.
+
## Additional resources
-For help making your pipelines faster and more efficient, see the
-[pipeline efficiency documentation](../pipelines/pipeline_efficiency.md).
+- You can use the [JenkinsFile Wrapper](https://gitlab.com/gitlab-org/jfr-container-builder/)
+ to run a complete Jenkins instance inside of a GitLab CI/CD job, including plugins. Use this tool to
+ help ease the transition to GitLab CI/CD, by delaying the migration of less urgent pipelines.
+
+ NOTE:
+ The JenkinsFile Wrapper is not packaged with GitLab and falls outside of the scope of support.
+ For more information, see the [Statement of Support](https://about.gitlab.com/support/statement-of-support/).
+- If your tooling outputs packages that you want to make accessible, you can store them
+ in a [package registry](../../user/packages/index.md).
+- Use [review Apps](../review_apps/index.md) to preview changes before merging them.
diff --git a/doc/ci/migration/plan_a_migration.md b/doc/ci/migration/plan_a_migration.md
new file mode 100644
index 00000000000..488b2abf3a2
--- /dev/null
+++ b/doc/ci/migration/plan_a_migration.md
@@ -0,0 +1,71 @@
+---
+stage: Verify
+group: Pipeline Authoring
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: index, howto
+---
+
+# Plan a migration from another tool to GitLab CI/CD
+
+Before starting a migration from another tool to GitLab CI/CD, you should begin by
+developing a migration plan.
+
+Review the advice on [managing organizational changes](#manage-organizational-changes)
+first for advice on initial steps for larger migrations.
+
+Users involved in the migration itself should review the [questions to ask before starting a migration](#technical-questions-to-ask-before-starting-a-migration),
+as an important technical step for setting expectations. CI/CD tools differ in approach,
+structure, and technical specifics. While some concepts map one-to-one, others require
+interactive conversion.
+
+It's important to focus on your desired end state instead of strictly translating
+the behavior of your old tool.
+
+## Manage organizational changes
+
+An important part of transitioning to GitLab CI/CD is the cultural and organizational
+changes that come with the move, and successfully managing them.
+
+A few things that organizations have reported as helping:
+
+- Set and communicate a clear vision of what your migration goals are, which helps
+ your users understand why the effort is worth it. The value is clear when
+ the work is done, but people need to be aware while it's in progress too.
+- Sponsorship and alignment from the relevant leadership teams helps with the point above.
+- Spend time educating your users on what's different, and share this guide
+ with them.
+- Finding ways to sequence or delay parts of the migration can help a lot. Importantly though,
+ try not to leave things in a non-migrated (or partially-migrated) state for too
+ long.
+- To gain all the benefits of GitLab, moving your existing configuration over as-is,
+ including any current problems, isn't enough. Take advantage of the improvements
+ that GitLab CI/CD offers, and update your implementation as part of the transition.
+
+## Technical questions to ask before starting a migration
+
+Asking some initial technical questions about your CI/CD needs helps quickly define
+the migration requirements:
+
+- How many projects use this pipeline?
+- What branching strategy is used? Feature branches? Mainline? Release branches?
+- What tools do you use to build your code? For example, Maven, Gradle, or NPM?
+- What tools do you use to test your code? For example JUnit, Pytest, or Jest?
+- Do you use any security scanners?
+- Where do you store any built packages?
+- How do you deploy your code?
+- Where do you deploy your code?
+
+### Jenkins
+
+If you are [migrating from Jenkins](jenkins.md), these additional questions can help with planning
+the migration:
+
+- What plugins are used by jobs in Jenkins today?
+ - Do you know what these plugins do exactly?
+ - Do any plugin wrap a common build tool? For example, Maven, Gradle, or NPM?
+- What is installed on the Jenkins agents?
+- Are there any shared libraries in use?
+- How are you authenticating from Jenkins? Are you using SSH keys, API tokens, or other secrets?
+- Are there other projects that you need to access from your pipeline?
+- Are there credentials in Jenkins to access outside services? For example Ansible Tower,
+ Artifactory, or other Cloud Providers or deployment targets?
diff --git a/doc/ci/mobile_devops.md b/doc/ci/mobile_devops.md
index 6969b3d4ef4..4e1a0f4683c 100644
--- a/doc/ci/mobile_devops.md
+++ b/doc/ci/mobile_devops.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference
---
-# Mobile DevOps (Experiment)
+# Mobile DevOps **(EXPERIMENT)**
Use GitLab Mobile DevOps to quickly build, sign, and release native and cross-platform mobile apps
for Android and iOS using GitLab CI/CD. Mobile DevOps is an experimental feature developed by
@@ -189,8 +189,7 @@ fastlane init
```
This command creates a `fastlane` folder in the project with an `Appfile` and a stubbed-out `fastfile`.
-This process asks you for login credentials to App Store Connect
-to generate an app identifier and App Store app if they don't already exist.
+During this process, you are prompted for App Store Connect login credentials to generate an app identifier and an App Store app if they don't already exist.
The next step sets up fastlane match to manage code signing files for the project.
Run the following command to generate a `Matchfile` with the configuration:
@@ -295,7 +294,7 @@ Use the [Google Play integration](../user/project/integrations/google_play.md),
to configure your CI/CD pipelines to connect to the [Google Play Console](https://play.google.com/console)
to build and release Android apps. To enable the integration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Google Play**.
1. Under **Enable integration**, select the **Active** checkbox.
@@ -352,7 +351,7 @@ Use the [Apple App Store integration](../user/project/integrations/apple_app_sto
to configure your CI/CD pipelines to connect to [App Store Connect](https://appstoreconnect.apple.com/)
to build and release apps for iOS, iPadOS, macOS, tvOS, and watchOS. To enable the integration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Apple App Store**.
1. Under **Enable integration**, select the **Active** checkbox.
diff --git a/doc/ci/pipeline_editor/index.md b/doc/ci/pipeline_editor/index.md
index 5291a8abb49..1dc6bc05e71 100644
--- a/doc/ci/pipeline_editor/index.md
+++ b/doc/ci/pipeline_editor/index.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference
---
-# Pipeline Editor **(FREE ALL)**
+# Pipeline editor **(FREE ALL)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4540) in GitLab 13.8.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/270059) in GitLab 13.10.
diff --git a/doc/ci/pipelines/cicd_minutes.md b/doc/ci/pipelines/cicd_minutes.md
index 4e822cf3edd..fa4a5e691a7 100644
--- a/doc/ci/pipelines/cicd_minutes.md
+++ b/doc/ci/pipelines/cicd_minutes.md
@@ -54,7 +54,7 @@ Prerequisite:
To change the default quota that applies to all namespaces:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**.
@@ -76,7 +76,7 @@ Prerequisite:
To set a compute quota for a namespace:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Groups**.
1. For the group you want to update, select **Edit**.
@@ -107,7 +107,7 @@ Prerequisite:
To view compute usage for your group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to
+1. On the left sidebar, select **Search or go to** and
find your group. The group must not be a subgroup.
1. Select **Settings > Usage Quotas**.
1. Select the **Pipelines** tab.
@@ -167,7 +167,7 @@ You can purchase additional compute minutes for your group.
You cannot transfer purchased compute minutes from one group to another,
so be sure to select the correct group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Usage Quotas**.
1. Select **Pipelines**.
1. Select **Buy additional compute minutes**.
diff --git a/doc/ci/pipelines/downstream_pipelines.md b/doc/ci/pipelines/downstream_pipelines.md
index fca6e8407ef..6dc58882f37 100644
--- a/doc/ci/pipelines/downstream_pipelines.md
+++ b/doc/ci/pipelines/downstream_pipelines.md
@@ -439,6 +439,7 @@ upstream pipeline:
Use [`needs:project`](../yaml/index.md#needsproject) to fetch artifacts from an
upstream pipeline:
+1. In GitLab 15.9 and later, [add the downstream project to the job token scope allowlist](../jobs/ci_job_token.md#add-a-project-to-the-job-token-scope-allowlist) of the upstream project.
1. In the upstream pipeline, save the artifacts in a job with the [`artifacts`](../yaml/index.md#artifacts)
keyword, then trigger the downstream pipeline with a trigger job:
@@ -491,6 +492,7 @@ because the downstream pipeline attempts to fetch artifacts from the latest bran
To fetch the artifacts from the upstream `merge request` pipeline instead of the `branch` pipeline,
pass `CI_MERGE_REQUEST_REF_PATH` to the downstream pipeline using [variable inheritance](#pass-yaml-defined-cicd-variables):
+1. In GitLab 15.9 and later, [add the downstream project to the job token scope allowlist](../jobs/ci_job_token.md#add-a-project-to-the-job-token-scope-allowlist) of the upstream project.
1. In a job in the upstream pipeline, save the artifacts using the [`artifacts`](../yaml/index.md#artifacts) keyword.
1. In the job that triggers the downstream pipeline, pass the `$CI_MERGE_REQUEST_REF_PATH` variable:
@@ -718,6 +720,80 @@ Use the [`trigger:forward` keyword](../yaml/index.md#triggerforward) to specify
what type of variables to forward to the downstream pipeline. Forwarded variables
are considered trigger variables, which have the [highest precedence](../variables/index.md#cicd-variable-precedence).
+## Downstream pipelines for deployments
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369061) in GitLab 16.4.
+
+You can use the [`environment`](../yaml/index.md#environment) keyword with [`trigger`](../yaml/index.md#trigger).
+You might want to use `environment` from a trigger job if your deployment and application projects are separately managed.
+
+```yaml
+deploy:
+ trigger:
+ project: project-group/my-downstream-project
+ environment: production
+```
+
+A downstream pipeline can provision infrastructure, deploy to a designated environment, and return the deployment status
+to the upstream project.
+
+You can [view the environment and deployment](../environments/index.md#view-environments-and-deployments)
+from the upstream project.
+
+### Advanced example
+
+This example configuration has the following behaviors:
+
+- The upstream project dynamically composes an environment name based on a branch name.
+- The upstream project passes the context of the deployment to the downstream project with `UPSTREAM_*` variables.
+
+The `.gitlab-ci.yml` in an upstream project:
+
+```yaml
+stages:
+ - deploy
+ - cleanup
+
+.downstream-deployment-pipeline:
+ variables:
+ UPSTREAM_PROJECT_ID: $CI_PROJECT_ID
+ UPSTREAM_ENVIRONMENT_NAME: $CI_ENVIRONMENT_NAME
+ UPSTREAM_ENVIRONMENT_ACTION: $CI_ENVIRONMENT_ACTION
+ trigger:
+ project: project-group/deployment-project
+ branch: main
+ strategy: depend
+
+deploy-review:
+ stage: deploy
+ extends: .downstream-deployment-pipeline
+ environment:
+ name: review/$CI_COMMIT_REF_SLUG
+ on_stop: stop-review
+
+stop-review:
+ stage: cleanup
+ extends: .downstream-deployment-pipeline
+ environment:
+ name: review/$CI_COMMIT_REF_SLUG
+ action: stop
+ when: manual
+```
+
+The `.gitlab-ci.yml` in a downstream project:
+
+```yaml
+deploy:
+ script: echo "Deploy to ${UPSTREAM_ENVIRONMENT_NAME} for ${UPSTREAM_PROJECT_ID}"
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "pipeline" && $UPSTREAM_ENVIRONMENT_ACTION == "start"
+
+stop:
+ script: echo "Stop ${UPSTREAM_ENVIRONMENT_NAME} for ${UPSTREAM_PROJECT_ID}"
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "pipeline" && $UPSTREAM_ENVIRONMENT_ACTION == "stop"
+```
+
## Troubleshooting
### Trigger job fails and does not create multi-project pipeline
@@ -747,3 +823,9 @@ You cannot trigger a multi-project pipeline with a tag when a branch exists with
name. The downstream pipeline fails to create with the error: `downstream pipeline can not be created, Ref is ambiguous`.
Only trigger multi-project pipelines with tag names that do not match branch names.
+
+### `403 Forbidden` error when downloading a job artifact from an upstream pipeline
+
+In GitLab 15.9 and later, CI/CD job tokens are scoped to the project that the pipeline executes under. Therefore, the job token in a downstream pipeline cannot be used to access an upstream project by default.
+
+To resolve this, [add the downstream project to the job token scope allowlist](../jobs/ci_job_token.md#add-a-project-to-the-job-token-scope-allowlist).
diff --git a/doc/ci/pipelines/index.md b/doc/ci/pipelines/index.md
index 7cde8b50524..f0f0f6d29d2 100644
--- a/doc/ci/pipelines/index.md
+++ b/doc/ci/pipelines/index.md
@@ -139,7 +139,7 @@ operation of the pipeline.
To execute a pipeline manually:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipelines**.
1. Select **Run pipeline**.
1. In the **Run for branch name or tag** field, select the branch or tag to run the pipeline for.
@@ -310,9 +310,9 @@ related objects, such as builds, logs, artifacts, and triggers.
A strict security model is enforced when pipelines are executed on
[protected branches](../../user/project/protected_branches.md).
-The following actions are allowed on protected branches only if the user is
+The following actions are allowed on protected branches if the user is
[allowed to merge or push](../../user/project/protected_branches.md)
-on that specific branch:
+to that specific branch:
- Run manual pipelines (using the [Web UI](#run-a-pipeline-manually) or [pipelines API](#pipelines-api)).
- Run scheduled pipelines.
@@ -321,15 +321,13 @@ on that specific branch:
- Trigger manual actions on existing pipelines.
- Retry or cancel existing jobs (using the Web UI or pipelines API).
-**Variables** marked as **protected** are accessible only to jobs that
-run on protected branches, preventing untrusted users getting unintended access to
-sensitive information like deployment credentials and tokens.
+**Variables** marked as **protected** are accessible to jobs that run in pipelines for protected branches. Only assign users the right to merge to protected branches if they have permission to access sensitive information like deployment credentials and tokens.
**Runners** marked as **protected** can run jobs only on protected
branches, preventing untrusted code from executing on the protected runner and
preserving deployment keys and other credentials from being unintentionally
accessed. To ensure that jobs intended to be executed on protected
-runners do not use regular runners, they must be tagged accordingly.
+runners do not use regular runners, they must be [tagged](../yaml/index.md#tags) accordingly.
Review the [deployment safety](../environments/deployment_safety.md)
page for additional security recommendations for securing your pipelines.
@@ -349,7 +347,7 @@ Prerequisites:
To trigger the pipeline when the upstream project is rebuilt:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Pipeline subscriptions**.
1. Select **Add project**.
diff --git a/doc/ci/pipelines/merge_request_pipelines.md b/doc/ci/pipelines/merge_request_pipelines.md
index 356b97aacc0..7b8a2a16734 100644
--- a/doc/ci/pipelines/merge_request_pipelines.md
+++ b/doc/ci/pipelines/merge_request_pipelines.md
@@ -169,8 +169,13 @@ To use the UI to run a pipeline in the parent project for a merge request from a
1. Select **Run pipeline**. You must read and accept the warning, or the pipeline does not run.
You can disable this feature by using [the projects API](../../api/projects.md#edit-project)
-to disable the `ci_allow_fork_pipelines_to_run_in_parent_project` setting.
-The setting is `enabled` by default.
+to disable the `ci_allow_fork_pipelines_to_run_in_parent_project` setting (enabled by default).
+When you disable this setting, new pipelines from forks in the parent project are prevented.
+
+WARNING:
+Older pipelines created before the setting was disabled are not affected and continue to run.
+If you rerun a job in an older pipeline, the job uses the same context as when the
+pipeline was originally created.
## Available predefined variables
diff --git a/doc/ci/pipelines/merge_trains.md b/doc/ci/pipelines/merge_trains.md
index c2bf9743e4f..d7f03490c68 100644
--- a/doc/ci/pipelines/merge_trains.md
+++ b/doc/ci/pipelines/merge_trains.md
@@ -101,7 +101,7 @@ Prerequisites:
To enable merge trains:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. In the **Merge method** section, verify that **Merge commit** is selected.
1. In the **Merge options** section:
diff --git a/doc/ci/pipelines/merged_results_pipelines.md b/doc/ci/pipelines/merged_results_pipelines.md
index 51678e64b10..1a21a2a9a00 100644
--- a/doc/ci/pipelines/merged_results_pipelines.md
+++ b/doc/ci/pipelines/merged_results_pipelines.md
@@ -41,7 +41,7 @@ To use merged results pipelines:
To enable merged results pipelines in a project, you must have at least the
Maintainer role:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. In the **Merge options** section, select **Enable merged results pipelines**.
1. Select **Save changes**.
diff --git a/doc/ci/pipelines/pipeline_architectures.md b/doc/ci/pipelines/pipeline_architectures.md
index d0324f16ffb..305e48ca9f5 100644
--- a/doc/ci/pipelines/pipeline_architectures.md
+++ b/doc/ci/pipelines/pipeline_architectures.md
@@ -306,5 +306,4 @@ deploy_b:
environment: production
```
-It's also possible to set jobs to run before or after triggering child pipelines,
-for example if you have common setup steps or a unified deployment at the end.
+Jobs can be set to run before or after triggering child pipelines in GitLab, allowing common setup steps or unified deployment.
diff --git a/doc/ci/pipelines/pipeline_artifacts.md b/doc/ci/pipelines/pipeline_artifacts.md
deleted file mode 100644
index 79435c0276d..00000000000
--- a/doc/ci/pipelines/pipeline_artifacts.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-stage: Verify
-group: Pipeline Security
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-redirect_to: '../testing/test_coverage_visualization.md'
-remove_date: '2023-08-31'
----
-
-This document was moved to [another location](../testing/test_coverage_visualization.md).
-
-<!-- This redirect file can be deleted after <2023-08-31>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/ci/pipelines/pipeline_efficiency.md b/doc/ci/pipelines/pipeline_efficiency.md
index 1d7d6c3289a..3d24be0f8e1 100644
--- a/doc/ci/pipelines/pipeline_efficiency.md
+++ b/doc/ci/pipelines/pipeline_efficiency.md
@@ -28,7 +28,7 @@ The easiest indicators to check for inefficient pipelines are the runtimes of th
stages, and the total runtime of the pipeline itself. The total pipeline duration is
heavily influenced by the:
-- [Size of the repository](../large_repositories/index.md)
+- [Size of the repository](../../user/project/repository/managing_large_repositories.md)
- Total number of stages and jobs.
- Dependencies between jobs.
- The ["critical path"](#directed-acyclic-graphs-dag-visualization), which represents
@@ -227,7 +227,7 @@ Methods to reduce Docker image size:
- Use a small base image, for example `debian-slim`.
- Do not install convenience tools such as vim or curl if they aren't strictly needed.
- Create a dedicated development image.
-- Disable man pages and docs installed by packages to save space.
+- Disable man pages and documentation installed by packages to save space.
- Reduce the `RUN` layers and combine software installation steps.
- Use [multi-stage builds](https://blog.alexellis.io/mutli-stage-docker-builds/)
to merge multiple Dockerfiles that use the builder pattern into one Dockerfile, which can reduce image size.
diff --git a/doc/ci/pipelines/schedules.md b/doc/ci/pipelines/schedules.md
index 75a7d373203..1003c03bebf 100644
--- a/doc/ci/pipelines/schedules.md
+++ b/doc/ci/pipelines/schedules.md
@@ -26,7 +26,7 @@ Otherwise, the pipeline is not created. No error message is displayed.
To add a pipeline schedule:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipeline schedules**.
1. Select **New schedule** and fill in the form.
- **Interval Pattern**: Select one of the preconfigured intervals, or enter a custom
@@ -47,7 +47,7 @@ you must delete unused schedules before you can add another.
The owner of a pipeline schedule can edit it:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipeline schedules**.
1. Next to the schedule, select **Edit** (**{pencil}**) and fill in the form.
@@ -60,7 +60,7 @@ of the schedule.
To trigger a pipeline schedule manually, so that it runs immediately instead of
the next scheduled time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Build > Pipeline schedules**.
1. On the right of the list, for
the pipeline you want to run, select **Play** (**{play}**).
@@ -79,7 +79,7 @@ including [protected environments](../environments/protected_environments.md) an
To take ownership of a pipeline created by a different user:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Build > Pipeline schedules**.
1. On the right of the list, for
the pipeline you want to become owner of, select **Take ownership**.
diff --git a/doc/ci/pipelines/settings.md b/doc/ci/pipelines/settings.md
index b9c95c63098..02559da75a0 100644
--- a/doc/ci/pipelines/settings.md
+++ b/doc/ci/pipelines/settings.md
@@ -24,7 +24,7 @@ For public and internal projects, you can change who can see your:
To change the visibility of your pipelines and related features:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. Select or clear the **Public pipelines** checkbox.
@@ -56,7 +56,7 @@ This setting has no effect when:
To change the pipeline visibility for non-project members:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. For **CI/CD**, choose:
@@ -72,7 +72,7 @@ is selected.
You can set pending or running pipelines to cancel automatically when a pipeline for new changes runs on the same branch. You can enable this in the project settings:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General Pipelines**.
1. Select the **Auto-cancel redundant pipelines** checkbox.
@@ -94,7 +94,7 @@ newer one, which may not be what you want.
To avoid this scenario:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. Select the **Prevent outdated deployment jobs** checkbox.
@@ -112,7 +112,7 @@ directory. However, you can specify an alternate filename path, including locati
To customize the path:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. In the **CI/CD configuration file** field, enter the filename. If the file:
@@ -161,7 +161,7 @@ able to edit it.
You can choose how your repository is fetched from GitLab when a job runs.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. Under **Git strategy**, select an option:
@@ -169,7 +169,7 @@ You can choose how your repository is fetched from GitLab when a job runs.
for every job. However, the local working copy is always pristine.
- `git fetch` is faster because it re-uses the local working copy (and falls
back to clone if it doesn't exist). This is recommended, especially for
- [large repositories](../large_repositories/index.md#git-strategy).
+ [large repositories](../../user/project/repository/managing_large_repositories.md#git-strategy).
The configured Git strategy can be overridden by the [`GIT_STRATEGY` variable](../runners/configure_runners.md#git-strategy)
in the `.gitlab-ci.yml` file.
@@ -182,7 +182,7 @@ in the `.gitlab-ci.yml` file.
You can limit the number of changes that GitLab CI/CD fetches when it clones
a repository.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. Under **Git strategy**, under **Git shallow clone**, enter a value.
@@ -192,14 +192,14 @@ a repository.
In GitLab versions 14.7 and later, newly created projects have a default `git depth`
value of `20`. GitLab versions 14.6 and earlier have a default `git depth` value of `50`.
-This value can be overridden by the [`GIT_DEPTH` variable](../large_repositories/index.md#shallow-cloning)
+This value can be overridden by the [`GIT_DEPTH` variable](../../user/project/repository/managing_large_repositories.md#shallow-cloning)
in the `.gitlab-ci.yml` file.
## Set a limit for how long jobs can run
You can define how long a job can run before it times out.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. In the **Timeout** field, enter the number of minutes, or a human-readable value like `2 hours`.
diff --git a/doc/ci/quick_start/tutorial.md b/doc/ci/quick_start/tutorial.md
index acc47a07a02..41239615590 100644
--- a/doc/ci/quick_start/tutorial.md
+++ b/doc/ci/quick_start/tutorial.md
@@ -8,10 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
This tutorial walks you through configuring a progressively more complex CI/CD pipeline
through small, iterative steps. The pipeline is always fully functional,
-but it gains more functionality with each step.
+but it gains more functionality with each step. The goal is to build, test, and deploy
+a documentation site.
-When you finish this tutorial, you will have a new project on GitLab.com and a working documentation site on
-[Docusaurus](https://docusaurus.io/).
+When you finish this tutorial, you will have a new project on GitLab.com and a working documentation site
+using [Docusaurus](https://docusaurus.io/).
To complete this tutorial, you will:
@@ -36,8 +37,8 @@ Before adding the pipeline configuration, you must first set up a Docusaurus pro
on GitLab.com:
1. Create a new project under your username (not a group):
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
- 1. Select **View all your projects**.
+ 1. On the left sidebar, select **Search or go to**.
+ 1. Select **View all my projects**.
1. On the right of the page, select **New project**.
1. Select **Create blank project**.
1. Enter the project details:
diff --git a/doc/ci/resource_groups/index.md b/doc/ci/resource_groups/index.md
index cf29ab62240..a0f6a8008d0 100644
--- a/doc/ci/resource_groups/index.md
+++ b/doc/ci/resource_groups/index.md
@@ -9,7 +9,7 @@ description: Control the job concurrency in GitLab CI/CD
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15536) in GitLab 12.7.
-By default, pipelines in GitLab CI/CD run in parallel. The parallelization is an important factor to improve
+By default, pipelines in GitLab CI/CD run concurrently. Concurrency is an important factor to improve
the feedback loop in merge requests, however, there are some situations that
you may want to limit the concurrency on deployment
jobs to run them one by one.
@@ -130,13 +130,13 @@ pipelines run almost at the same time:
Depending on the process mode of the resource group:
- If the process mode is set to `unordered`:
- - `deploy-1`, `deploy-2`, and `deploy-3` do not run in parallel.
+ - `deploy-1`, `deploy-2`, and `deploy-3` do not run concurrently.
- There is no guarantee on the job execution order, for example, `deploy-1` could run before or after `deploy-3` runs.
- If the process mode is `oldest_first`:
- - `deploy-1`, `deploy-2`, and `deploy-3` do not run in parallel.
+ - `deploy-1`, `deploy-2`, and `deploy-3` do not run concurrently.
- `deploy-1` runs first, `deploy-2` runs second, and `deploy-3` runs last.
- If the process mode is `newest_first`:
- - `deploy-1`, `deploy-2`, and `deploy-3` do not run in parallel.
+ - `deploy-1`, `deploy-2`, and `deploy-3` do not run concurrently.
- `deploy-3` runs first, `deploy-2` runs second and `deploy-1` runs last.
## Pipeline-level concurrency control with cross-project/parent-child pipelines
diff --git a/doc/ci/review_apps/img/enable_review_app_v16.png b/doc/ci/review_apps/img/enable_review_app_v16.png
new file mode 100644
index 00000000000..00e305d6a6b
--- /dev/null
+++ b/doc/ci/review_apps/img/enable_review_app_v16.png
Binary files differ
diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md
index d05861818e2..f831c53c024 100644
--- a/doc/ci/review_apps/index.md
+++ b/doc/ci/review_apps/index.md
@@ -76,14 +76,14 @@ Prerequisite:
To use the review apps template:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to
+1. On the left sidebar, select **Search or go to** and
find the project you want to create a review app job for.
-1. Select **Build > Environments**.
+1. Select **Operate > Environments**.
1. Select **Enable review apps**.
1. Copy the provided code snippet and paste it into your
`.gitlab-ci.yml` file:
- ![enable review apps modal](img/enable_review_app_v12_8.png)
+ ![enable review apps modal](img/enable_review_app_v16.png)
You can edit this template as needed.
diff --git a/doc/ci/runners/configure_runners.md b/doc/ci/runners/configure_runners.md
index 3e26c120f74..fd1716cc58a 100644
--- a/doc/ci/runners/configure_runners.md
+++ b/doc/ci/runners/configure_runners.md
@@ -64,9 +64,9 @@ of shared runners on large GitLab instances. This ensures that you
control access to your GitLab instances and secure [runner executors](https://docs.gitlab.com/runner/executors/).
If certain executors run a job, the file system, the code the runner executes,
-and the runner token may be exposed. This means that anyone that runs jobs
+and the runner authentication token may be exposed. This means that anyone that runs jobs
on a _shared runner_ can access another user's code that runs on the runner.
-Users with access to the runner token can use it to create a clone of
+Users with access to the runner authentication token can use it to create a clone of
a runner and submit false jobs in a vector attack. For more information, see [Security Considerations](https://docs.gitlab.com/runner/security/).
### Prevent runners from revealing sensitive information
@@ -76,7 +76,7 @@ on [protected branches](../../user/project/protected_branches.md), or jobs that
To prevent runners from revealing sensitive information:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. Find the runner you want to protect or unprotect. Make sure the runner is enabled.
@@ -111,7 +111,7 @@ That new runner may then be used to obtain the values of secret variables or to
To reset the registration token:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. To the right of **New project runner**, select the vertical ellipsis (**{ellipsis_v}**).
@@ -124,19 +124,19 @@ you use to provision and register new values.
### Reset the runner authentication token
-If an authentication token is revealed, an attacker could use the token to [clone a runner](https://docs.gitlab.com/runner/security/#cloning-a-runner).
+If a runner authentication token is revealed, an attacker could use the token to [clone a runner](https://docs.gitlab.com/runner/security/#cloning-a-runner).
-To reset the authentication token:
+To reset the runner authentication token:
1. Delete the runner:
- [Delete a shared runner](runners_scope.md#delete-shared-runners).
- [Delete a group runner](runners_scope.md#delete-a-group-runner).
- [Delete a project runner](runners_scope.md#delete-a-project-runner).
-1. Create a new runner so that it is assigned a new authentication token:
- - [Create a shared runner](runners_scope.md#create-a-shared-runner-with-an-authentication-token).
- - [Create a group runner](runners_scope.md#create-a-group-runner-with-an-authentication-token).
- - [Create a project runner](runners_scope.md#create-a-project-runner-with-an-authentication-token).
-1. Optional. To verify that the previous authentication token has been revoked, use the [Runners API](../../api/runners.md#verify-authentication-for-a-registered-runner).
+1. Create a new runner so that it is assigned a new runner authentication token:
+ - [Create a shared runner](runners_scope.md#create-a-shared-runner-with-a-runner-authentication-token).
+ - [Create a group runner](runners_scope.md#create-a-group-runner-with-a-runner-authentication-token).
+ - [Create a project runner](runners_scope.md#create-a-project-runner-with-a-runner-authentication-token).
+1. Optional. To verify that the previous runner authentication token has been revoked, use the [Runners API](../../api/runners.md#verify-authentication-for-a-registered-runner).
## Use tags to control which jobs a runner can run
@@ -874,7 +874,7 @@ defaults to the number of CPUs available.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 15.3 [with a flag](../../administration/feature_flags.md) named `enforce_runner_token_expires_at`. Disabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/377902) in GitLab 15.5. Feature flag `enforce_runner_token_expires_at` removed.
-Each runner has an [authentication token](../../api/runners.md#registration-and-authentication-tokens)
+Each runner has an [runner authentication token](../../api/runners.md#registration-and-authentication-tokens)
to connect with the GitLab instance.
To help prevent the token from being compromised, you can have the
@@ -883,12 +883,12 @@ they are updated for each runner, regardless of the runner's status (`online` or
No manual intervention should be required, and no running jobs should be affected.
-If you need to manually update the authentication token, you can run a
+If you need to manually update the runner authentication token, you can run a
command to [reset the token](https://docs.gitlab.com/runner/commands/#gitlab-runner-reset-token).
-### Automatically rotate authentication tokens
+### Automatically rotate runner authentication tokens
-You can specify an interval for authentication tokens to rotate.
+You can specify an interval for runner authentication tokens to rotate.
This rotation helps ensure the security of the tokens assigned to your runners.
Prerequisites:
@@ -897,11 +897,11 @@ Prerequisites:
To automatically rotate runner authentication tokens:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**..
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **Continuous Integration and Deployment**
1. Set a **Runners expiration** time for runners, leave empty for no expiration.
1. Select **Save**.
-Before the interval expires, runners automatically request a new authentication token.
+Before the interval expires, runners automatically request a new runner authentication token.
diff --git a/doc/ci/runners/index.md b/doc/ci/runners/index.md
index 5427911e1ce..7e597264e1e 100644
--- a/doc/ci/runners/index.md
+++ b/doc/ci/runners/index.md
@@ -17,10 +17,15 @@ Your jobs can run on:
- [Windows runners](saas/windows_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta))
- [macOS runners](saas/macos_saas_runner.md) ([Beta](../../policy/experiment-beta-support.md#beta))
-Refer to the compute minutes [cost factor](../../ci/pipelines/cicd_minutes.md#cost-factor) for the cost factor applied to the machine type based on size.
-The number of minutes you can use on these runners depends on the [maximum number of compute minutes](../pipelines/cicd_minutes.md)
+For more information about the cost factor applied to the machine type based on size, see [cost factor](../../ci/pipelines/cicd_minutes.md#cost-factor).
+The number of minutes you can use on these runners depends on the [maximum number of units of compute](../pipelines/cicd_minutes.md)
in your [subscription plan](https://about.gitlab.com/pricing/).
+[Untagged](../../ci/runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) jobs automatically run in containers
+on the `small` Linux runners.
+
+The objective is to make 90% of CI/CD jobs start executing in 120 seconds or less. The error rate should be less than 0.5%.
+
## How SaaS runners work
When you use SaaS runners:
@@ -30,9 +35,6 @@ When you use SaaS runners:
- The virtual machine where your job runs has `sudo` access with no password.
- The storage is shared by the operating system, the image with pre-installed software, and a copy of your cloned repository.
This means that the available free disk space for your jobs to use is reduced.
-- [Untagged](../../ci/runners/configure_runners.md#use-tags-to-control-which-jobs-a-runner-can-run) jobs automatically run in containers
-on the `small` Linux runners.
-- The objective is to make 90% of CI jobs start executing in 120 seconds or less. The error rate target will be less than 0.5%.
NOTE:
Jobs handled by SaaS runners on GitLab.com **time out after 3 hours**, regardless of the timeout configured in a project.
@@ -67,3 +69,65 @@ takes over the task of securely deleting the virtual machine and associated data
- Inbound communication from the public internet to the temporary VM is not allowed.
- Firewall rules do not permit communication between VMs.
- The only internal communication allowed to the temporary VMs is from the runner manager.
+
+## Supported image lifecycle
+
+For runners on macOS and Windows, you can only run jobs on supported images. You cannot bring your own image. Supported images have the following lifecycle:
+
+- Beta
+- Generally Available
+- Deprecated
+
+### Beta
+
+To gather feedback on an image prior to making the image Generally Available (GA) and to address
+any issues, new images are released as Beta. Any jobs running on Beta images are not
+covered by the service-level agreement. If you use Beta images, you can provide feedback
+by creating an issue.
+
+### Generally Available
+
+A Generally Available (GA) image is released after the image completes a Beta phase
+and is considered suitable for general use. To become GA, the
+image must fulfill the following requirements:
+
+- Successful completion of a Beta phase by resolving all reported significant bugs
+- Compatibility of installed software with the underlying OS
+
+Jobs running on GA images are covered by the defined service-level agreement. Over time, these images are deprecated.
+
+### Deprecated
+
+A maximum of two Generally Available (GA) images are supported at a time. After a new GA image is released,
+the oldest GA image becomes deprecated. A deprecated image is no longer
+updated and is deleted after 3 months in accordance with the [deprecation guidelines](../../development/deprecation_guidelines/index.md).
+
+## Major version changes (breaking)
+
+As GitLab CI/CD and Runner have evolved, certain breaking changes have been necessary.
+
+For GitLab 15.0 and later, all breaking changes are documented on the following page:
+
+- [Deprecations and removals](../../update/deprecations.md)
+
+The breaking changes for GitLab Runner in earlier major version releases are:
+
+- 14.0: No breaking changes.
+- 13.0:
+ - [Remove Backported `os.Expand`](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4915).
+ - [Remove Fedora 29 package support](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/16158).
+ - [Remove macOS 32-bit support](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/25466).
+ - [Removed `debug/jobs/list?v=1` endpoint](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6361).
+ - [Remove support for array of strings when defining services for Docker executor](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4922).
+ - [Remove `--docker-services` flag on register command](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6404).
+ - [Remove legacy build directory caching](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4180).
+ - [Remove `FF_USE_LEGACY_VOLUMES_MOUNTING_ORDER` feature flag](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6581).
+ - [Remove support for Windows Server 1803](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/6553).
+- 12.0:
+ - [Use `refspec` to clone/fetch Git repository](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4069).
+ - [Old cache configuration](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4070).
+ - [Old metrics server configuration](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4072).
+ - [Remove `FF_K8S_USE_ENTRYPOINT_OVER_COMMAND`](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4073).
+ - [Remove Linux distributions that reach EOL](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/1130).
+ - [Update command line API for helper images](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4013).
+ - [Remove old `git clean` flow](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4175).
diff --git a/doc/ci/runners/new_creation_workflow.md b/doc/ci/runners/new_creation_workflow.md
index 55ff5165ff7..c4c2fbebb12 100644
--- a/doc/ci/runners/new_creation_workflow.md
+++ b/doc/ci/runners/new_creation_workflow.md
@@ -14,15 +14,13 @@ As with all projects, the items mentioned on this page are subject to change or
The development, release, and timing of any products, features, or functionality remain at the
sole discretion of GitLab Inc.
-In GitLab 16.0, we introduced a new runner creation workflow that uses authentication tokens to register
-runners. The legacy workflow that uses registration tokens is deprecated and will be removed in GitLab 17.0.
+In GitLab 16.0, we introduced a new runner creation workflow that uses runner authentication tokens to register
+runners. The legacy workflow that uses registration tokens is deprecated and will be removed in GitLab 18.0.
For information about the current development status of the new workflow, see [epic 7663](https://gitlab.com/groups/gitlab-org/-/epics/7663).
For information about the technical design and reasons for the new architecture, see [Next GitLab Runner Token Architecture](../../architecture/blueprints/runner_tokens/index.md).
-## Feedback
-
If you experience problems or have concerns about the new runner registration workflow,
or if the following information is not sufficient,
you can let us know in the [feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/387993).
@@ -32,8 +30,8 @@ you can let us know in the [feedback issue](https://gitlab.com/gitlab-org/gitlab
For the new runner registration workflow, you:
1. [Create a runner](register_runner.md) directly in the GitLab UI.
-1. Receive an authentication token.
-1. Use the authentication token instead of the registration token when you register
+1. Receive a runner authentication token.
+1. Use the runner authentication token instead of the registration token when you register
a runner with this configuration. Runner managers registered in multiple hosts appear
under the same runner in the GitLab UI, but with an identifying system ID.
@@ -46,54 +44,63 @@ multiple runners. For more information, see [Reusing a GitLab Runner configurati
## Estimated time frame for planned changes
- In GitLab 15.10 and later, you can use the new runner registration workflow.
-- In GitLab 16.6, we plan to disable registration tokens.
-- In GitLab 17.0, we plan to completely remove support for runner registration tokens.
+- In GitLab 17.0, we plan to disable runner registration tokens.
+- In GitLab 18.0, we plan to completely remove support for runner registration tokens.
## Prevent your runner registration workflow from breaking
-Until GitLab 16.6, you can still use the legacy runner registration workflow.
+Until GitLab 17.0, you can still use the legacy runner registration workflow.
-In GitLab 16.6, the legacy runner registration workflow will be disabled automatically. You will be able to manually re-enable the legacy runner registration workflow for a limited time. For more information, see
-[Using registration tokens after GitLab 16.6](#using-registration-tokens-after-gitlab-166).
+In GitLab 17.0, the legacy runner registration workflow will be disabled automatically. You will be able to manually re-enable the legacy runner registration workflow for a limited time. For more information, see
+[Using registration tokens after GitLab 17.0](#using-registration-tokens-after-gitlab-170).
-If no action is taken before your GitLab instance is upgraded to GitLab 16.6, then your runner registration
+If no action is taken before your GitLab instance is upgraded to GitLab 17.0, then your runner registration
workflow will break.
To avoid a broken workflow, you must:
-1. [Create a shared runner](runners_scope.md#create-a-shared-runner-with-an-authentication-token) and obtain the authentication token.
+1. [Create a shared runner](runners_scope.md#create-a-shared-runner-with-a-runner-authentication-token) and obtain the authentication token.
1. Replace the registration token in your runner registration workflow with the
authentication token.
-## Using registration tokens after GitLab 16.6
+## Using registration tokens after GitLab 17.0
-To continue using registration tokens after GitLab 16.6:
+To continue using registration tokens after GitLab 17.0:
-- On GitLab.com, you can manually re-enable the legacy runner registration process in the top-level group settings until GitLab 16.8.
-- On GitLab self-managed, you can manually re-enable the legacy runner registration process in the Admin Area settings until GitLab 17.0.
+- On GitLab.com, you can manually re-enable the legacy runner registration process in the top-level group settings until GitLab 18.0.
+- On GitLab self-managed, you can manually re-enable the legacy runner registration process in the Admin Area settings until GitLab 18.0.
Plans to implement a UI setting to re-enable registration tokens are proposed in [issue 411923](https://gitlab.com/gitlab-org/gitlab/-/issues/411923)
+## Runners registered with a registration token will continue to work after 18.0
+
+Existing runners will not be affected by these changes, they will still work even after the legacy registration method is removed.
+
## Changes to the `gitlab-runner register` command syntax
-The `gitlab-runner register` command will stop accepting registration tokens and instead accept new
+The `gitlab-runner register` command will stop accepting registration tokens and instead accept new runner
authentication tokens generated in the GitLab runners administration page.
-These authentication tokens are recognizable by their `glrt-` prefix.
+The runner authentication tokens are recognizable by their `glrt-` prefix.
When you create a runner in the GitLab UI, you specify configuration values that were previously command-line options
prompted by the `gitlab-runner register` command.
These command-line options have been [deprecated](../../update/deprecations.md#registration-tokens-and-server-side-runner-arguments-in-post-apiv4runners-endpoint).
-If you specify an authentication token with:
+If you specify a runner authentication token with:
- the `--token` command-line option, the `gitlab-runner register` command does not accept the configuration values.
- the `--registration-token` command-line option, the `gitlab-runner register` command ignores the configuration values.
+| Token | Registration command |
+|----------------------------------------|-----------------------------------------------------------------------------------------------------------|
+| Runner authentication token | `gitlab-runner register --token $RUNNER_AUTHENTICATION_TOKEN` |
+| Runner registration token (deprecated) | `gitlab-runner register --registration-token $RUNNER_REGISTRATION_TOKEN <runner configuration arguments>` |
+
Authentication tokens have the prefix, `glrt-`.
To ensure minimal disruption to your automation workflow,
[legacy-compatible registration processing](https://docs.gitlab.com/runner/register/#legacy-compatible-registration-processing)
-triggers if an authentication token is specified in the legacy parameter `--registration-token`.
+triggers if a runner authentication token is specified in the legacy parameter `--registration-token`.
Example command for GitLab 15.9:
@@ -126,7 +133,7 @@ gitlab-runner register \
## Impact on autoscaling
In autoscaling scenarios such as GitLab Runner Operator or GitLab Runner Helm Chart, the
-registration token is replaced with the authentication token generated from the UI.
+registration token is replaced with the runner authentication token generated from the UI.
This means that the same runner configuration is reused across jobs, instead of creating a runner
for each job.
The specific runner can be identified by the unique system ID that is generated when the runner
@@ -138,33 +145,13 @@ Existing runners will continue to work as usual. This change only affects regist
## Creating runners programmatically
-A new [POST /user/runners REST API](../../api/users.md#create-a-runner) was introduced in
-GitLab 15.11, which allows a runner to be created in the context of an authenticated user. This should only be used in
-scenarios where the runner configuration is dynamic, or not reusable. If the runner configuration is static, it is
-preferable to reuse the authentication token of an existing runner.
+In GitLab 15.11 and later, you can use the [POST /user/runners REST API](../../api/users.md#create-a-runner)
+to create a runner as an authenticated user. This should only be used if the runner configuration is dynamic
+or not reusable. If the runner configuration is static, you should reuse the runner authentication token of
+an existing runner.
-The following snippet shows how a group runner could be created and registered with a
-[Group Access Token](../../user/group/settings/group_access_tokens.md) using the new creation flow.
-The process is very similar when using [Project Access Tokens](../../user/project/settings/project_access_tokens.md)
-or [Personal Access Tokens](../../user/profile/personal_access_tokens.md):
-
-```shell
-# `GROUP_ID` contains the numerical ID of the group where the runner will be created
-# `GITLAB_TOKEN` can be a Personal Access Token for a group owner, or a Group Access Token on the respective group
-# created with `owner` access and `api` scope.
-#
-# The output will be parsed by `jq` to extract the token of the newly created runner
-RUNNER_TOKEN=$(curl --silent --request POST "https://gitlab.com/api/v4/user/runners" \
- --header "private-token: $GITLAB_TOKEN" \
- --data runner_type=group_type --data group_id=$GROUP_ID --data 'description=My runner' --data 'tag_list=java,linux' \
- | jq -r '.token')
-
-gitlab-runner register \
- --non-interactive \
- --executor "shell" \
- --url "https://gitlab.com/" \
- --token "$RUNNER_TOKEN"
-```
+For instructions about how to automate runner creation and registration, see the tutorial,
+[Automate runner creation and registration](../../tutorials/automate_runner_creation/index.md).
## Installing GitLab Runner with Helm chart
@@ -185,7 +172,7 @@ runUntagged: true
protected: true
```
-If you store the runner token in `secrets`, you must also modify them.
+If you store the runner authentication token in `secrets`, you must also modify them.
In the legacy runner registration workflow, fields were specified with:
@@ -212,3 +199,7 @@ data:
runner-registration-token: "" # need to leave as an empty string for compatibility reasons
runner-token: "REDACTED"
```
+
+NOTE:
+If your secret management solution doesn't allow you to set an empty string for `runner-registration-token`,
+you can set it to any string - it will be ignored when `runner-token` is present.
diff --git a/doc/ci/runners/runners_scope.md b/doc/ci/runners/runners_scope.md
index fff695eb606..c6387a60495 100644
--- a/doc/ci/runners/runners_scope.md
+++ b/doc/ci/runners/runners_scope.md
@@ -34,7 +34,7 @@ If you are using GitLab.com:
- The shared runners consume the [compute minutes](../pipelines/cicd_minutes.md)
included with your account.
-### Create a shared runner with an authentication token
+### Create a shared runner with a runner authentication token
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383139) in GitLab 15.10. Deployed behind the `create_runner_workflow_for_admin` [flag](../../administration/feature_flags.md)
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/389269) in GitLab 16.0.
@@ -44,23 +44,32 @@ Prerequisite:
- You must be an administrator.
-When you create a runner, it is assigned an authentication token that you use to register it. The runner uses the token to authenticate with GitLab when picking up jobs from the job queue.
+When you create a runner, it is assigned a runner authentication token that you use to register it. The runner uses the token to authenticate with GitLab when picking up jobs from the job queue.
To create a shared runner:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **CI/CD > Runners**.
1. Select **New instance runner**.
-1. Select a platform.
-1. Optional. Enter configurations for the runner.
-1. Select **Submit**.
-1. Follow the on-screen instructions to register the runner from the command line.
-
-You can also [create a runner](../../api/users.md#create-a-runner) with the API to generate an authentication token.
+1. Select the operating system where GitLab Runner is installed.
+1. In the **Tags** section, in the **Tags** field, enter the job tags to specify jobs the runner can run.
+ If there are no job tags for this runner, select **Run untagged**.
+1. Optional. In the **Runner description** field, to add a runner description
+ that displays in GitLab, enter a runner description.
+1. Optional. In the **Configuration** section, add additional configurations.
+1. Select **Create runner**.
+1. Follow the on-screen instructions to register the runner from the command line. When prompted by the command line:
+ - For the `GitLab instance URL`, use the URL for your GitLab instance. For example, if your project
+ is hosted on `gitlab.example.com/yourname/yourproject`, your GitLab instance URL is `https://gitlab.example.com`.
+ - For the `executor`, enter the type of [executor](https://docs.gitlab.com/runner/executors/). The executor is the
+ environment where the runner executes the job.
+
+You can also [use the API](../../api/users.md#create-a-runner) to create a runner.
NOTE:
-The authentication token displays in the UI for only a short period of time during registration.
+The runner authentication token displays in the UI for a limited period of time during registration. After you register the runner,
+the authentication token is stored in the `config.toml`.
### Create a shared runner with a registration token (deprecated)
@@ -75,7 +84,7 @@ Prerequisite:
To create a shared runner:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **CI/CD > Runners**.
1. Select **Register an instance runner**.
@@ -90,7 +99,7 @@ Prerequisite:
You can pause a runner so that it does not accept jobs from groups and projects in the GitLab instance.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **CI/CD > Runners**.
1. In the search box, enter the runner description or filter the runner list.
@@ -110,7 +119,7 @@ jobs, you can [pause](#pause-or-resume-a-shared-runner) the runner instead.
To delete a single or multiple shared runners:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **CI/CD > Runners**.
1. In the search box, enter the runner description or filter the list of runners.
@@ -134,7 +143,7 @@ For existing projects, an administrator must
To enable shared runners for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. Turn on the **Enable shared runners for this project** toggle.
@@ -143,7 +152,7 @@ To enable shared runners for a project:
To enable shared runners for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. Turn on the **Enable shared runners for this group** toggle.
@@ -156,7 +165,7 @@ or group.
To disable shared runners for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. In the **Shared runners** area, turn off the **Enable shared runners for this project** toggle.
@@ -170,7 +179,7 @@ Shared runners are automatically disabled for a project:
To disable shared runners for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. Turn off the **Enable shared runners for this group** toggle.
@@ -222,7 +231,7 @@ to have access to a set of runners.
Group runners process jobs by using a first in, first out queue.
-### Create a group runner with an authentication token
+### Create a group runner with a runner authentication token
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383143) in GitLab 15.10. Deployed behind the `create_runner_workflow_for_namespace` [flag](../../administration/feature_flags.md). Disabled by default.
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/393919) in GitLab 16.0.
@@ -233,22 +242,31 @@ Prerequisites:
- You must have the Owner role for the group.
You can create a group runner for your self-managed GitLab instance or for GitLab.com.
-When you create a runner, it is assigned an authentication token that you use to register it. The runner uses the token to authenticate with GitLab when picking up jobs from the job queue.
+When you create a runner, it is assigned a runner authentication token that you use to register it.
+The runner uses the token to authenticate with GitLab when it picks up jobs from the job queue.
To create a group runner:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
1. Select **New group runner**.
-1. Select a platform.
-1. Optional. Enter configurations for the runner.
-1. Select **Submit**.
-1. Follow the on-screen instructions to register the runner from the command line.
-
-You can also [create a runner](../../api/users.md#create-a-runner) with the API to generate an authentication token.
+1. Select the operating system where GitLab Runner is installed.
+1. In the **Tags** section, in the **Tags** field, enter the job tags to specify jobs the runner can run.
+ If there are no job tags for this runner, select **Run untagged**.
+1. Optional. In the **Runner description** field, add a runner description
+ that displays in GitLab.
+1. Optional. In the **Configuration** section, add additional configurations.
+1. Select **Create runner**.
+1. Follow the on-screen instructions to register the runner from the command line. When prompted by the command line:
+ - For the `GitLab instance URL`, use the URL for your GitLab instance. For example, if your project
+ is hosted on `gitlab.example.com/yourname/yourproject`, your GitLab instance URL is `https://gitlab.example.com`.
+ - For the `executor`, enter the type of [executor](https://docs.gitlab.com/runner/executors/). The executor is the
+ environment where the runner executes the job.
+
+You can also [use the API](../../api/users.md#create-a-runner) to create a runner.
NOTE:
-The authentication token displays in the UI for only a short period of time during registration.
+The runner authentication token displays in the UI for only a short period of time during registration.
### Create a group runner with a registration token (deprecated)
@@ -256,7 +274,7 @@ The authentication token displays in the UI for only a short period of time duri
WARNING:
The ability to pass a runner registration token, and support for certain configuration arguments was
-[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in GitLab 15.6 and will be removed in GitLab 17.0. Authentication tokens
+[deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in GitLab 15.6 and will be removed in GitLab 18.0. Authentication tokens
should be used instead. For more information, see [Migrating to the new runner registration workflow](new_creation_workflow.md).
You must have the Owner role for the group.
@@ -264,7 +282,7 @@ You must have the Owner role for the group.
To create a group runner:
1. [Install GitLab Runner](https://docs.gitlab.com/runner/install/).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
1. In the upper-right corner, select **Register a group runner**.
1. Select **Show runner installation and registration instructions**.
@@ -273,17 +291,20 @@ To create a group runner:
Alternately, you can copy the registration token and follow the documentation for
how to [register a runner](https://docs.gitlab.com/runner/register/).
-### View and manage group runners
+### View group runners
+
+> Ability for users with the Maintainer role to view group runners [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384179) in GitLab 16.4.
+
+Prerequisite:
+
+- You must have the Maintainer or Owner role for the group.
-You can view and manage all runners for a group, its subgroups, and projects.
+You can view all runners for a group and its subgroups and projects.
You can do this for your self-managed GitLab instance or for GitLab.com.
-You must have the Owner role for the group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
-From this page, you can edit, pause, and remove runners from the group, its subgroups, and projects.
-
#### Filter group runners to show only inherited
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337838/) in GitLab 15.5.
@@ -297,7 +318,7 @@ By default, only those that are inherited are shown.
To show all runners available in the instance, including shared runners and
those in other groups:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
1. Above the list, turn off the **Show only inherited** toggle.
@@ -310,7 +331,7 @@ Prerequisite:
You can pause a runner so that it does not accept jobs from subgroups and projects in the GitLab
instance. If you pause a group runner that is used by multiple projects, the runner pauses for all projects.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
1. In the search box, enter the runner description or filter the runner list.
1. In the runner list, to the right of the runner:
@@ -331,7 +352,7 @@ jobs, you can [pause](#pause-or-resume-a-group-runner) the runner instead.
To delete a single or multiple group runners:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
1. In the search box, enter the runner description or filter the list of runners.
1. Delete the group runner:
@@ -344,11 +365,15 @@ To delete a single or multiple group runners:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363012) in GitLab 15.1.
+Prerequisite:
+
+- You must have the Owner role for the group.
+
You can clean up group runners that have been inactive for more than three months.
Group runners are those that were created at the group level.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
1. Turn on the **Enable stale runner cleanup** toggle.
@@ -399,7 +424,7 @@ NOTE:
Project runners do not get shared with forked projects automatically.
A fork *does* copy the CI/CD settings of the cloned repository.
-### Create a project runner with an authentication token
+### Create a project runner with a runner authentication token
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383143) in GitLab 15.10. Deployed behind the `create_runner_workflow_for_namespace` [flag](../../administration/feature_flags.md). Disabled by default.
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/393919) in GitLab 16.0.
@@ -409,23 +434,33 @@ Prerequisites:
- You must have the Maintainer role for the project.
-You can create a project runner for your self-managed GitLab instance or for GitLab.com. When you create a runner, it is assigned an authentication token that you use to register to the runner. The runner uses the token to authenticate with GitLab when picking up jobs from the job queue.
+You can create a project runner for your self-managed GitLab instance or for GitLab.com. When you create a runner,
+it is assigned a runner authentication token that you use to register to the runner. The runner uses the token to
+authenticate with GitLab when it picks up jobs from the job queue.
To create a project runner:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand the **Runners** section.
1. Select **New project runner**.
-1. Select a platform.
-1. Optional. Enter configurations for the runner.
-1. Select **Submit**.
-1. Follow the on-screen instructions to register the runner from the command line.
-
-You can also [create a runner](../../api/users.md#create-a-runner) with the API to generate an authentication token.
+1. Select the operating system where GitLab Runner is installed.
+1. In the **Tags** section, in the **Tags** field, enter the job tags to specify jobs the runner can run.
+ If there are no job tags for this runner, select **Run untagged**.
+1. Optional. In the **Runner description** field, add a description for the runner
+ that displays in GitLab.
+1. Optional. In the **Configuration** section, add additional configurations.
+1. Select **Create runner**.
+1. Follow the on-screen instructions to register the runner from the command line. When prompted by the command line:
+ - For the `GitLab instance URL`, use the URL for your GitLab instance. For example, if your project
+ is hosted on `gitlab.example.com/yourname/yourproject`, your GitLab instance URL is `https://gitlab.example.com`.
+ - For the `executor`, enter the type of [executor](https://docs.gitlab.com/runner/executors/). The executor is the
+ environment where the runner executes the job.
+
+You can also [use the API](../../api/users.md#create-a-runner) to create a runner.
NOTE:
-The authentication token displays in the UI for only a short period of time during registration.
+The runner authentication token displays in the UI for only a short period of time during registration.
### Create a project runner with a registration token (deprecated)
@@ -441,7 +476,7 @@ Prerequisite:
To create a project runner:
1. [Install GitLab Runner](https://docs.gitlab.com/runner/install/).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to
+1. On the left sidebar, select **Search or go to** and
find the project where you want to use the runner.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
@@ -459,7 +494,7 @@ Prerequisite:
You can pause a project runner so that it does not accept jobs from projects it's assigned to
in the GitLab instance.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to
+1. On the left sidebar, select **Search or go to** and
find the project where you want to enable the runner.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
@@ -479,7 +514,7 @@ When you delete a project runner, it is permanently deleted from the GitLab inst
no longer be used by projects. If you want to temporarily stop the runner from accepting
jobs, you can [pause](#pause-or-resume-a-project-runner) the runner instead.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to
+1. On the left sidebar, select **Search or go to** and
find the project where you want to enable the runner.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
@@ -500,7 +535,7 @@ You must have at least the Maintainer role for:
To enable a project runner for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to
+1. On the left sidebar, select **Search or go to** and
find the project where you want to enable the runner.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
@@ -520,7 +555,7 @@ but can also be changed later.
To lock or unlock a project runner:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to
+1. On the left sidebar, select **Search or go to** and
find the project where you want to enable the runner.
1. Select **Settings > CI/CD**.
1. Expand **Runners**.
@@ -553,7 +588,7 @@ runners are considered.
queued for longer than the median value, and half of the jobs queued for less than the
median value.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **CI/CD > Runners**.
1. Select **View metrics**.
@@ -569,10 +604,10 @@ To determine which runners need to be upgraded:
1. View the list of runners:
- For a group:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+ 1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Build > Runners**.
- For the instance:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **CI/CD > Runners**.
@@ -602,7 +637,7 @@ Prerequisite:
To determine the IP address of a shared runner:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **CI/CD > Runners**.
1. Find the runner in the table and view the **IP Address** column.
diff --git a/doc/ci/runners/saas/linux_saas_runner.md b/doc/ci/runners/saas/linux_saas_runner.md
index dd5381f3cd6..c026ccf3d22 100644
--- a/doc/ci/runners/saas/linux_saas_runner.md
+++ b/doc/ci/runners/saas/linux_saas_runner.md
@@ -29,7 +29,7 @@ The `small` machine type is set as default. If no [tag](../../yaml/index.md#tags
the jobs will run on this default runner.
All SaaS runners on Linux currently run on
-[`n2d-standard`](https://cloud.google.com/compute/docs/general-purpose-machines#n2d_machines) gerneral-purpose compute from GCP.
+[`n2d-standard`](https://cloud.google.com/compute/docs/general-purpose-machines#n2d_machines) general-purpose compute from GCP.
The machine type and underlying processor type can change. Jobs optimized for a specific processor design could behave inconsistently.
## Container images
diff --git a/doc/ci/runners/saas/macos/codesigning.md b/doc/ci/runners/saas/macos/codesigning.md
deleted file mode 100644
index 7e70e984c7c..00000000000
--- a/doc/ci/runners/saas/macos/codesigning.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../macos_saas_runner.md'
-remove_date: '2023-09-05'
----
-
-This document was moved to [another location](../macos_saas_runner.md).
-
-<!-- This redirect file can be deleted after <2023-09-05>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> \ No newline at end of file
diff --git a/doc/ci/runners/saas/macos/environment.md b/doc/ci/runners/saas/macos/environment.md
deleted file mode 100644
index 7e70e984c7c..00000000000
--- a/doc/ci/runners/saas/macos/environment.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../macos_saas_runner.md'
-remove_date: '2023-09-05'
----
-
-This document was moved to [another location](../macos_saas_runner.md).
-
-<!-- This redirect file can be deleted after <2023-09-05>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> \ No newline at end of file
diff --git a/doc/ci/runners/saas/macos_saas_runner.md b/doc/ci/runners/saas/macos_saas_runner.md
index 44f99ed6ccc..1445ae58bd4 100644
--- a/doc/ci/runners/saas/macos_saas_runner.md
+++ b/doc/ci/runners/saas/macos_saas_runner.md
@@ -4,7 +4,7 @@ group: Runner
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# SaaS runners on macOS (Beta) **(PREMIUM SAAS)**
+# SaaS runners on macOS **(PREMIUM SAAS BETA)**
SaaS runners on macOS are in [Beta](../../../policy/experiment-beta-support.md#beta) for open source programs and customers in Premium and Ultimate plans.
@@ -38,28 +38,30 @@ in your `.gitlab-ci.yml` file.
Each image runs a specific version of macOS and Xcode.
-| VM image | Status |
-|---------------------------|---------------|
-| `macos-12-xcode-13` | `maintenance` |
-| `macos-12-xcode-14` | `maintenance` |
-| (none, awaiting macOS 13) | `beta` |
+| VM image | Status |
+|----------------------------|--------|
+| `macos-12-xcode-13` | `GA` |
+| `macos-12-xcode-14` | `GA` |
+| `macos-13-xcode-14` | `Beta` |
-NOTE:
-If your job requires tooling or dependencies not available in our available images, those can only be installed in the job execution.
+## Image update policy for macOS
-## Image update policy
+macOS and Xcode follow a yearly release cadence, during which GitLab increments its versions synchronously. GitLab typically supports multiple versions of preinstalled tools. For more information, see
+a [full list of preinstalled software](https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/job-images/-/tree/main/toolchain).
-GitLab expects to release new images based on this cadence:
+GitLab provides `stable` and `latest` macOS images that follow different update patterns:
-macOS updates:
+- **Stable image:** The `stable` images and installed components are updated every release. Images without the `:latest` prefix are considered stable images.
+- **Latest image:** The `latest` images are typically updated on a weekly cadence and use a `:latest` prefix in the image name. Using the `latest` image results in more regularly updated components and shorter update times for Homebrew or asdf. The `latest` images are used to test software components before releasing the components to the `stable` images.
+By definition, the `latest` images are always Beta.
+A `latest` image is not available.
-- **For new OS versions:** When Apple releases a new macOS version to developers (like macOS `12`), GitLab will plan to release an image based on the OS within the next 30 business days. The image is considered `beta` and the contents of the image (including tool versions) are subject to change until the first patch release (`12.1`). The long-term name will not include `beta` (for example, `macos-12-xcode-13`), so customers are moved automatically out of beta over time. GitLab will try to minimize breaking changes between the first two minor versions but makes no guarantees. Tooling often gets critical bug fixes after the first public release of an OS version.
+### Image release process
-- **After the first patch release (`12.1`):**
- - The image moves to `maintenance` mode. The tools GitLab builds into the image with Homebrew and asdf are frozen. GitLab continues making Xcode updates, security updates, and any non-breaking changes deemed necessary.
- - The image for the previous OS version (`11`) moves to `frozen` mode. GitLab then does only unavoidable changes: security updates, runner version upgrades, and setting the production password.
+When Apple releases a new macOS version, GitLab releases both `stable` and `latest` images based on the OS in the next release. Both images are Beta.
-Both macOS and Xcode follow a yearly release cadence. As time goes on, GitLab increments their versions synchronously (meaning we build macOS 11 with Xcode 12, macOS 12 with Xcode 13, and so on).
+With the release of the first patch to macOS, the `stable` image becomes Generally Available (GA).
+As only two GA images are supported at a time, the prior OS version becomes deprecated and is deleted after three months in accordance with the [supported image lifecycle](../index.md#supported-image-lifecycle).
## Example `.gitlab-ci.yml` file
diff --git a/doc/ci/runners/saas/windows_saas_runner.md b/doc/ci/runners/saas/windows_saas_runner.md
index 8ec44b8c275..108388f22c8 100644
--- a/doc/ci/runners/saas/windows_saas_runner.md
+++ b/doc/ci/runners/saas/windows_saas_runner.md
@@ -4,7 +4,7 @@ group: Runner
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# SaaS runners on Windows (Beta) **(FREE SAAS)**
+# SaaS runners on Windows **(FREE SAAS BETA)**
SaaS runner on Windows autoscale by launching virtual machines on
the Google Cloud Platform. This solution uses an
@@ -35,7 +35,7 @@ You can execute your job in one of the following Windows versions:
| Version tag | Status |
|----------------|---------------|
-| `windows-1809` | `maintenance` |
+| `windows-1809` | `Beta` |
You can find a full list of available pre-installed software in
the [pre-installed software documentation](https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/gcp/windows-containers/blob/main/cookbooks/preinstalled-software/README.md).
@@ -81,16 +81,15 @@ test:
- echo "running scripts in the test job"
```
-## Limitations and known issues
+## Known issues
-- All the limitations mentioned in our [Beta definition](../../../policy/experiment-beta-support.md#beta).
-- The average provisioning time for a new Windows VM is 5 minutes.
- This means that you may notice slower build start times
- on the Windows runner fleet during the beta. In a future
- release we intend to update the autoscaler to enable
- the pre-provisioning of virtual machines. This is intended to significantly reduce
- the time it takes to provision a VM on the Windows fleet. You can
- follow along in the [related issue](https://gitlab.com/gitlab-org/ci-cd/custom-executor-drivers/autoscaler/-/issues/32).
+- For more information about support for Beta features, see [Beta](../../../policy/experiment-beta-support.md#beta).
+- The average provisioning time for a new Windows virtual machine (VM) is five minutes, so
+ you might notice slower start times for builds on the Windows runner
+ fleet during the Beta. Updating the autoscaler to enable the pre-provisioning
+ of virtual machines is proposed in a future release. This update is intended to
+ significantly reduce the time it takes to provision a VM on the Windows fleet.
+ For more information, see [issue 32](https://gitlab.com/gitlab-org/ci-cd/custom-executor-drivers/autoscaler/-/issues/32).
- The Windows runner fleet may be unavailable occasionally
for maintenance or updates.
- The job may stay in a pending state for longer than the
diff --git a/doc/ci/secrets/id_token_authentication.md b/doc/ci/secrets/id_token_authentication.md
index 22a260e4bb6..697346474f8 100644
--- a/doc/ci/secrets/id_token_authentication.md
+++ b/doc/ci/secrets/id_token_authentication.md
@@ -193,7 +193,7 @@ ID token authentication is now always available, and JSON Web Token access is al
To enable automatic ID token authentication:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Token Access**.
1. Turn on the **Limit JSON Web Token (JWT) access** toggle.
diff --git a/doc/ci/secure_files/index.md b/doc/ci/secure_files/index.md
index 37c453a5b9d..a666e0aca7b 100644
--- a/doc/ci/secure_files/index.md
+++ b/doc/ci/secure_files/index.md
@@ -29,7 +29,7 @@ tool.
To add a secure file to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand the **Secure Files** section.
1. Select **Upload File**.
diff --git a/doc/ci/services/index.md b/doc/ci/services/index.md
index f92c50fcf3f..a2ffd095de3 100644
--- a/doc/ci/services/index.md
+++ b/doc/ci/services/index.md
@@ -493,5 +493,10 @@ Docker privileged mode applies to services. This means that the service image co
## Shared /builds directory
-Services can access files from the build because all services have the job
-directory mounted as a volume under `/builds`.
+The build directory is mounted as a volume under `/builds` and is shared
+between the job and services. The job checks the project out into
+`/builds/$CI_PROJECT_PATH` after the services are running. As a result, if your
+service needs files from the project or, for example, wants to put files there
+to serve as artifacts, it may need to wait for that directory to exist and
+have `$CI_COMMIT_SHA` checked out. Any changes made before the job finishes its
+checkout process are removed by the checkout process.
diff --git a/doc/ci/test_cases/index.md b/doc/ci/test_cases/index.md
index 0bc9ae7776e..d9dcbca0825 100644
--- a/doc/ci/test_cases/index.md
+++ b/doc/ci/test_cases/index.md
@@ -27,7 +27,7 @@ Prerequisite:
To create a test case in a GitLab project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Test cases**.
1. Select **New test case**. You are taken to the new test case form. Here you can enter
the new case's title, [description](../../user/markdown.md), attach a file, and assign [labels](../../user/project/labels.md).
@@ -45,7 +45,7 @@ Prerequisites:
To view a test case:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Test cases**.
1. Select the title of the test case you want to view. You are taken to the test case page.
@@ -80,7 +80,7 @@ To archive a test case, on the test case's page, select **Archive test case**.
To view archived test cases:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Test cases**.
1. Select **Archived**.
diff --git a/doc/ci/testing/code_coverage.md b/doc/ci/testing/code_coverage.md
index 90a07314083..fb846f52a72 100644
--- a/doc/ci/testing/code_coverage.md
+++ b/doc/ci/testing/code_coverage.md
@@ -72,7 +72,7 @@ Use this regex for commonly used test tools.
To see the evolution of your project code coverage over time,
you can view a graph or download a CSV file with this data.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Analyze > Repository analytics**.
The historic data for each job is listed in the dropdown list above the graph.
diff --git a/doc/ci/testing/load_performance_testing.md b/doc/ci/testing/load_performance_testing.md
index 549aa10287e..6b16f15a9d9 100644
--- a/doc/ci/testing/load_performance_testing.md
+++ b/doc/ci/testing/load_performance_testing.md
@@ -59,7 +59,7 @@ Configuring your Load Performance Testing job can be broken down into several di
### Determine the test parameters
-The first thing you need to do is determine the [type of load test](https://k6.io/docs/test-types/introduction)
+The first thing you need to do is determine the [type of load test](https://k6.io/docs/test-types/load-test-types/)
you want to run, and how you want it to run (for example, the number of users, throughput, and so on).
Refer to the [k6 docs](https://k6.io/docs/), especially the [k6 testing guides](https://k6.io/docs/testing-guides),
@@ -79,7 +79,7 @@ We strongly recommend [not running these tests against a production environment]
### Write the load performance test
After the environment is prepared, you can write the k6 test itself. k6 is a flexible
-tool and can be used to run [many kinds of performance tests](https://k6.io/docs/test-types/introduction).
+tool and can be used to run [many kinds of performance tests](https://k6.io/docs/test-types/load-test-types/).
Refer to the [k6 documentation](https://k6.io/docs/) for detailed information on how to write tests.
### Configure the test in GitLab CI/CD
@@ -151,7 +151,7 @@ The CI/CD YAML configuration example above works for testing against static envi
but it can be extended to work with [review apps](../review_apps/index.md) or
[dynamic environments](../environments/index.md) with a few extra steps.
-The best approach is to capture the dynamic URL in a [`.env` file](https://docs.docker.com/compose/env-file/)
+The best approach is to capture the dynamic URL in a [`.env` file](https://docs.docker.com/compose/environment-variables/env-file/)
as a job artifact to be shared, then use a custom CI/CD variable we've provided named `K6_DOCKER_OPTIONS`
to configure the k6 Docker container to use the file. With this, k6 can then use any
environment variables from the `.env` file in scripts using standard JavaScript,
diff --git a/doc/ci/triggers/index.md b/doc/ci/triggers/index.md
index 506f6fb2106..698118f457f 100644
--- a/doc/ci/triggers/index.md
+++ b/doc/ci/triggers/index.md
@@ -26,7 +26,7 @@ Prerequisite:
To create a trigger token:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Pipeline trigger tokens**.
1. Select **Add new token**
@@ -154,7 +154,7 @@ users with the Owner and Maintainer role can view the values.
To revoke a pipeline trigger token:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Pipeline triggers**.
1. To the left of the trigger token you want to revoke, select **Revoke** (**{remove}**).
diff --git a/doc/ci/troubleshooting.md b/doc/ci/troubleshooting.md
index 3d5bcc64889..e0b8c6213de 100644
--- a/doc/ci/troubleshooting.md
+++ b/doc/ci/troubleshooting.md
@@ -210,6 +210,42 @@ To illustrate its life cycle:
1. The runner fetches the persistent pipeline ref and gets source code from the checkout-SHA.
1. When the pipeline finishes, its persistent ref is cleaned up in a background process.
+### `get_sources` job section fails because of an HTTP/2 problem
+
+Sometimes, jobs fail with the following cURL error:
+
+```plaintext
+++ git -c 'http.userAgent=gitlab-runner <version>' fetch origin +refs/pipelines/<id>:refs/pipelines/<id> ...
+error: RPC failed; curl 16 HTTP/2 send again with decreased length
+fatal: ...
+```
+
+You can work around this problem by configuring Git and `libcurl` to
+[use HTTP/1.1](https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpversion).
+The configuration can be added to:
+
+- A job's [`pre_get_sources_script`](yaml/index.md#hookspre_get_sources_script):
+
+ ```yaml
+ job_name:
+ hooks:
+ pre_get_sources_script:
+ - git config --local http.version "HTTP/1.1"
+ ```
+
+- The [runner's `config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html)
+ with [Git configuration environment variables](https://git-scm.com/docs/git-config#ENVIRONMENT):
+
+ ```toml
+ [[runners]]
+ ...
+ environment = [
+ "GIT_CONFIG_COUNT=1",
+ "GIT_CONFIG_KEY_1=http.version",
+ "GIT_CONFIG_VALUE_1=HTTP/1.1"
+ ]
+ ```
+
### Merge request pipeline messages
The merge request pipeline widget shows information about the pipeline status in
@@ -440,9 +476,9 @@ This flag reduces system resource usage on the `jobs/request` endpoint.
When enabled, jobs created in the last hour can run in projects which are out of quota.
Earlier jobs are already canceled by a periodic background worker (`StuckCiJobsWorker`).
-## CI/CD troubleshooting rails console commands
+## CI/CD troubleshooting Rails console commands
-The following commands are run in the [rails console](../administration/operations/rails_console.md#starting-a-rails-console-session).
+The following commands are run in the [Rails console](../administration/operations/rails_console.md#starting-a-rails-console-session).
WARNING:
Any command that changes data directly could be damaging if not run correctly, or under the right conditions.
diff --git a/doc/ci/variables/index.md b/doc/ci/variables/index.md
index 6280c9080ab..975157ff917 100644
--- a/doc/ci/variables/index.md
+++ b/doc/ci/variables/index.md
@@ -170,7 +170,7 @@ To add a group variable:
- **Key**: Must be one line, with no spaces, using only letters, numbers, or `_`.
- **Value**: No limitations.
- **Type**: `Variable` (default) or [`File`](#use-file-type-cicd-variables).
- - **Environment scope** Optional. `All`, or specific [environments](../environments/index.md#limit-the-environment-scope-of-a-cicd-variable). **(PREMIUM)**
+ - **Environment scope** Optional. `All`, or specific [environments](../environments/index.md#limit-the-environment-scope-of-a-cicd-variable). **(PREMIUM ALL)**
- **Protect variable** Optional. If selected, the variable is only available
in pipelines that run on protected branches or tags.
- **Mask variable** Optional. If selected, the variable's **Value** is masked
@@ -194,7 +194,7 @@ Prerequisite:
To add an instance variable:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD** and expand the **Variables** section.
1. Select **Add variable** and fill in the details:
@@ -371,7 +371,7 @@ For example:
```yaml
variables:
- SITE_URL: "https://example.gitlab.com"
+ SITE_URL: "https://gitlab.example.com"
job:
script:
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 6acb254e76f..b1a0fca9069 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -68,9 +68,9 @@ as it can cause the pipeline to behave unexpectedly.
| `CI_HAS_OPEN_REQUIREMENTS` | 13.1 | all | Only available if the pipeline's project has an open [requirement](../../user/project/requirements/index.md). `true` when available. |
| `CI_JOB_ID` | 9.0 | all | The internal ID of the job, unique across all jobs in the GitLab instance. |
| `CI_JOB_IMAGE` | 12.9 | 12.9 | The name of the Docker image running the job. |
-| `CI_JOB_JWT` (Deprecated) | 12.10 | all | A RS256 JSON web token to authenticate with third party systems that support JWT authentication, for example [HashiCorp's Vault](../secrets/index.md). [Deprecated in GitLab 15.9](../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated) and scheduled to be removed in GitLab 16.5. Use [ID tokens](../yaml/index.md#id_tokens) instead. |
-| `CI_JOB_JWT_V1` (Deprecated) | 14.6 | all | The same value as `CI_JOB_JWT`. [Deprecated in GitLab 15.9](../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated) and scheduled to be removed in GitLab 16.5. Use [ID tokens](../yaml/index.md#id_tokens) instead. |
-| `CI_JOB_JWT_V2` (Deprecated) | 14.6 | all | A newly formatted RS256 JSON web token to increase compatibility. Similar to `CI_JOB_JWT`, except the issuer (`iss`) claim is changed from `gitlab.com` to `https://gitlab.com`, `sub` has changed from `job_id` to a string that contains the project path, and an `aud` claim is added. The `aud` field is a constant value. Trusting JWTs in multiple relying parties can lead to [one RP sending a JWT to another one and acting maliciously as a job](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72555#note_769112331). [Deprecated in GitLab 15.9](../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated) and scheduled to be removed in GitLab 16.5. Use [ID tokens](../yaml/index.md#id_tokens) instead. |
+| `CI_JOB_JWT` (Deprecated) | 12.10 | all | A RS256 JSON web token to authenticate with third party systems that support JWT authentication, for example [HashiCorp's Vault](../secrets/index.md). [Deprecated in GitLab 15.9](../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated) and scheduled to be removed in GitLab 17.0. Use [ID tokens](../yaml/index.md#id_tokens) instead. |
+| `CI_JOB_JWT_V1` (Deprecated) | 14.6 | all | The same value as `CI_JOB_JWT`. [Deprecated in GitLab 15.9](../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated) and scheduled to be removed in GitLab 17.0. Use [ID tokens](../yaml/index.md#id_tokens) instead. |
+| `CI_JOB_JWT_V2` (Deprecated) | 14.6 | all | A newly formatted RS256 JSON web token to increase compatibility. Similar to `CI_JOB_JWT`, except the issuer (`iss`) claim is changed from `gitlab.com` to `https://gitlab.com`, `sub` has changed from `job_id` to a string that contains the project path, and an `aud` claim is added. The `aud` field is a constant value. Trusting JWTs in multiple relying parties can lead to [one RP sending a JWT to another one and acting maliciously as a job](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72555#note_769112331). [Deprecated in GitLab 15.9](../../update/deprecations.md#old-versions-of-json-web-tokens-are-deprecated) and scheduled to be removed in GitLab 17.0. Use [ID tokens](../yaml/index.md#id_tokens) instead. |
| `CI_JOB_MANUAL` | 8.12 | all | Only available if the job was started manually. `true` when available. |
| `CI_JOB_NAME` | 9.0 | 0.5 | The name of the job. |
| `CI_JOB_NAME_SLUG` | 15.4 | all | `CI_JOB_NAME_SLUG` in lowercase, shortened to 63 bytes, and with everything except `0-9` and `a-z` replaced with `-`. No leading / trailing `-`. Use in paths. |
@@ -165,13 +165,15 @@ These variables are available when:
| `CI_MERGE_REQUEST_PROJECT_PATH` | 11.6 | all | The path of the project of the merge request. For example `namespace/awesome-project`. |
| `CI_MERGE_REQUEST_PROJECT_URL` | 11.6 | all | The URL of the project of the merge request. For example, `http://192.168.10.15:3000/namespace/awesome-project`. |
| `CI_MERGE_REQUEST_REF_PATH` | 11.6 | all | The ref path of the merge request. For example, `refs/merge-requests/1/head`. |
+| `CI_MERGE_REQUEST_SQUASH_ON_MERGE` | 16.4 | all | `true` when the [squash on merge](../../user/project/merge_requests/squash_and_merge.md) option is set. |
| `CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` | 11.6 | all | The source branch name of the merge request. |
+| `CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED` | 16.4 | all | `true` when the source branch of the merge request is [protected](../../user/project/protected_branches.md). |
| `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the source branch of the merge request. The variable is empty in merge request pipelines. The SHA is present only in [merged results pipelines](../pipelines/merged_results_pipelines.md). |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_ID` | 11.6 | all | The ID of the source project of the merge request. |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` | 11.6 | all | The path of the source project of the merge request. |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_URL` | 11.6 | all | The URL of the source project of the merge request. |
| `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` | 11.6 | all | The target branch name of the merge request. |
-| `CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED` | 15.2 | all | The protection status for the target branch of the merge request. |
+| `CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED` | 15.2 | all | `true` when the target branch of the merge request is [protected](../../user/project/protected_branches.md). |
| `CI_MERGE_REQUEST_TARGET_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the target branch of the merge request. The variable is empty in merge request pipelines. The SHA is present only in [merged results pipelines](../pipelines/merged_results_pipelines.md). |
| `CI_MERGE_REQUEST_TITLE` | 11.9 | all | The title of the merge request. |
| `CI_MERGE_REQUEST_EVENT_TYPE` | 12.3 | all | The event type of the merge request. Can be `detached`, `merged_result` or `merge_train`. |
diff --git a/doc/ci/variables/where_variables_can_be_used.md b/doc/ci/variables/where_variables_can_be_used.md
index 52edeb67f0e..d25f9801f5b 100644
--- a/doc/ci/variables/where_variables_can_be_used.md
+++ b/doc/ci/variables/where_variables_can_be_used.md
@@ -22,6 +22,8 @@ There are two places defined variables can be used. On the:
### `.gitlab-ci.yml` file
+> Support for `CI_ENVIRONMENT_*` variables except `CI_ENVIRONMENT_SLUG` [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128694) in GitLab 16.4.
+
| Definition | Can be expanded? | Expansion place | Description |
|:----------------------------------------------------------------------|:-----------------|:-----------------------|:------------|
| [`after_script`](../yaml/index.md#after_script) | yes | Script execution shell | The variable expansion is made by the [execution shell environment](#execution-shell-environment). |
@@ -32,15 +34,15 @@ There are two places defined variables can be used. On the:
| [`environment:name`](../yaml/index.md#environmentname) | yes | GitLab | Similar to `environment:url`, but the variables expansion doesn't support the following:<br/><br/>- `CI_ENVIRONMENT_*` variables.<br/>- [Persisted variables](#persisted-variables). |
| [`environment:url`](../yaml/index.md#environmenturl) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab.<br/><br/>Supported are all variables defined for a job (project/group variables, variables from `.gitlab-ci.yml`, variables from triggers, variables from pipeline schedules).<br/><br/>Not supported are variables defined in the GitLab Runner `config.toml` and variables created in the job's `script`. |
| [`environment:auto_stop_in`](../yaml/index.md#environmentauto_stop_in)| yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab.<br/><br/> The value of the variable being substituted should be a period of time in a human readable natural language form. See [possible inputs](../yaml/index.md#environmentauto_stop_in) for more information.|
-| [`except:variables`](../yaml/index.md#onlyvariables--exceptvariables) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- `CI_ENVIRONMENT_*` variables, except `CI_ENVIRONMENT_NAME` which is supported.<br/>- [Persisted variables](#persisted-variables). |
+| [`except:variables`](../yaml/index.md#onlyvariables--exceptvariables) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- `CI_ENVIRONMENT_SLUG` variable.<br/>- [Persisted variables](#persisted-variables). |
| [`id_tokens:aud`](../yaml/index.md#id_tokens) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. Variable expansion [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/414293) in GitLab 16.1. |
| [`image`](../yaml/index.md#image) | yes | Runner | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
| [`include`](../yaml/index.md#include) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. <br/><br/>See [Use variables with include](../yaml/includes.md#use-variables-with-include) for more information on supported variables. |
-| [`only:variables`](../yaml/index.md#onlyvariables--exceptvariables) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- `CI_ENVIRONMENT_*` variables, except `CI_ENVIRONMENT_NAME` which is supported.<br/>- [Persisted variables](#persisted-variables). |
+| [`only:variables`](../yaml/index.md#onlyvariables--exceptvariables) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- `CI_ENVIRONMENT_SLUG` variable.<br/>- [Persisted variables](#persisted-variables). |
| [`resource_group`](../yaml/index.md#resource_group) | yes | GitLab | Similar to `environment:url`, but the variables expansion doesn't support the following:<br/>- `CI_ENVIRONMENT_URL`<br/>- [Persisted variables](#persisted-variables). |
| [`rules:changes`](../yaml/index.md#ruleschanges) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. |
| [`rules:exists`](../yaml/index.md#rulesexists) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. |
-| [`rules:if`](../yaml/index.md#rulesif) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- `CI_ENVIRONMENT_*` variables, except `CI_ENVIRONMENT_NAME` which is supported.<br/>- [Persisted variables](#persisted-variables). |
+| [`rules:if`](../yaml/index.md#rulesif) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- `CI_ENVIRONMENT_SLUG` variable.<br/>- [Persisted variables](#persisted-variables). |
| [`script`](../yaml/index.md#script) | yes | Script execution shell | The variable expansion is made by the [execution shell environment](#execution-shell-environment). |
| [`services:name`](../yaml/index.md#services) | yes | Runner | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
| [`services`](../yaml/index.md#services) | yes | Runner | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
diff --git a/doc/ci/yaml/artifacts_reports.md b/doc/ci/yaml/artifacts_reports.md
index fa7e941ffe5..e931a8b3b4e 100644
--- a/doc/ci/yaml/artifacts_reports.md
+++ b/doc/ci/yaml/artifacts_reports.md
@@ -40,6 +40,55 @@ GitLab can display the results of one or more reports in the merge request
For more information, see [Accessibility testing](../testing/accessibility_testing.md).
+## `artifacts:reports:annotations`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38337) in GitLab 16.3.
+
+The `annotations` report is used to attach auxiliary data to a job.
+
+An annotations report is a JSON file with annotation sections. Each annotation
+section can have any desired name and can have any number of annotations of the
+same or differing types.
+
+Each annotation is a single key (the annotation type), containing the subkeys with
+the data for that annotation.
+
+### Annotation types
+
+#### `external_link`
+
+An `external_link` annotation can be attached to a job to add a link to the job
+output page. The value of an `external_link` annotation is an object with the
+following keys:
+
+| Key | Description |
+|---------|----------------------------------------------------|
+| `label` | The human-readable label associated with the link. |
+| `url` | The URL pointed to by the link. |
+
+### Example report
+
+The following is an example of what a job annotations report might look like:
+
+```json
+{
+ "my_annotation_section_1": [
+ {
+ "external_link": {
+ "label": "URL 1",
+ "url": "https://url1.example.com/"
+ }
+ },
+ {
+ "external_link": {
+ "label": "URL 2",
+ "url": "https://url2.example.com/"
+ }
+ }
+ ]
+}
+```
+
## `artifacts:reports:api_fuzzing` **(ULTIMATE ALL)**
> - Introduced in GitLab 13.4.
@@ -95,7 +144,7 @@ GitLab can display the results of coverage report in the merge request
## `artifacts:reports:codequality`
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212499) to GitLab Free in 13.2.
-> - [Added support for multiple reports in diff annotations and full pipeline report](https://gitlab.com/gitlab-org/gitlab/-/issues/9014) in 15.7.
+> - Support for multiple reports in diff annotations and full pipeline report [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9014) in 15.7.
The `codequality` report collects [code quality issues](../testing/code_quality.md). The
collected code quality report uploads to GitLab as an artifact.
@@ -313,7 +362,7 @@ The collected Secret Detection report is uploaded to GitLab.
GitLab can display the results of one or more reports in:
- The merge request [secret scanning widget](../../user/application_security/secret_detection/index.md).
-- The [pipeline **Security** tab](../../user/application_security/index.md#view-security-scan-information-in-the-pipeline-security-tab).
+- The [pipeline security tab](../../user/application_security/index.md#pipeline-security-tab).
- The [security dashboard](../../user/application_security/security_dashboard/index.md).
## `artifacts:reports:terraform`
@@ -325,6 +374,6 @@ The `terraform` report obtains a Terraform `tfplan.json` file. [JQ processing re
The collected Terraform plan report uploads to GitLab as an artifact.
GitLab can display the results of one or more reports in the merge request
-[terraform widget](../../user/infrastructure/iac/mr_integration.md#output-terraform-plan-information-into-a-merge-request).
+[Terraform widget](../../user/infrastructure/iac/mr_integration.md#output-terraform-plan-information-into-a-merge-request).
For more information, see [Output `terraform plan` information into a merge request](../../user/infrastructure/iac/mr_integration.md).
diff --git a/doc/ci/yaml/includes.md b/doc/ci/yaml/includes.md
index 79eb42fd781..f0e5a475838 100644
--- a/doc/ci/yaml/includes.md
+++ b/doc/ci/yaml/includes.md
@@ -501,6 +501,44 @@ In this example, GitLab checks for the existence of `test-file.yml` in `my-group
not the current project. Follow [issue 386040](https://gitlab.com/gitlab-org/gitlab/-/issues/386040)
for information about work to improve this behavior.
+### `include` with `rules:changes`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342209) in GitLab 16.4.
+
+Use [`rules:changes`](index.md#ruleschanges) to conditionally include other configuration files
+based on changed files. For example:
+
+```yaml
+include:
+ - local: builds1.yml
+ rules:
+ - changes:
+ - Dockerfile
+ - local: builds2.yml
+ rules:
+ - changes:
+ paths:
+ - Dockerfile
+ compare_to: 'refs/heads/branch1'
+ when: always
+ - local: builds3.yml
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+ changes:
+ paths:
+ - Dockerfile
+
+test:
+ stage: test
+ script: exit 0
+```
+
+In this example:
+
+- `builds1.yml` is included when `Dockerfile` has changed.
+- `builds2.yml` is included when `Dockerfile` has changed relative to `refs/heads/branch1`.
+- `builds3.yml` is included when `Dockerfile` has changed and the pipeline source is a merge request event.
+
## Use `include:local` with wildcard file paths
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25921) in GitLab 13.11.
@@ -528,144 +566,6 @@ When the pipeline runs, GitLab:
include: 'configs/**/*.yml'
```
-## Define inputs for configuration added with `include` (Beta)
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/391331) in GitLab 15.11 as a Beta feature.
-
-FLAG:
-`spec` and `with` are experimental [Open Beta features](../../policy/experiment-beta-support.md#beta)
-and subject to change without notice.
-
-### Define input parameters with `spec:inputs`
-
-Use `spec:inputs` to define input parameters for CI/CD configuration intended to be added
-to a pipeline with `include`. Use [`include:inputs`](#set-input-parameter-values-with-includeinputs)
-to define the values to use when the pipeline runs.
-
-The specs must be declared at the top of the configuration file, in a header section.
-Separate the header from the rest of the configuration with `---`.
-
-Use the interpolation format `$[[ input.input-id ]]` to reference the values outside of the header section.
-The inputs are evaluated and interpolated once, when the configuration is fetched
-during pipeline creation, but before the configuration is merged with the contents of the `.gitlab-ci.yml`.
-
-```yaml
-spec:
- inputs:
- environment:
- job-stage:
----
-
-scan-website:
- stage: $[[ inputs.job-stage ]]
- script: ./scan-website $[[ inputs.environment ]]
-```
-
-When using `spec:inputs`:
-
-- Defined inputs are mandatory by default.
-- Inputs can be made optional by specifying a `default`. Use `default: null` to have no default value.
-- A string containing an interpolation block must not exceed 1 MB.
-- The string inside an interpolation block must not exceed 1 KB.
-
-For example, a `custom_configuration.yml`:
-
-```yaml
-spec:
- inputs:
- website:
- user:
- default: 'test-user'
- flags:
- default: null
----
-
-# The pipeline configuration would follow...
-```
-
-In this example:
-
-- `website` is mandatory and must be defined.
-- `user` is optional. If not defined, the value is `test-user`.
-- `flags` is optional. If not defined, it has no value.
-
-### Specify functions to manipulate input values
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/409462) in GitLab 16.3.
-
-You can specify predefined functions in the interpolation block to manipulate the input value.
-The format supported is the following:
-
-```yaml
-$[[ input.input-id | <function1> | <function2> | ... <functionN> ]]
-```
-
-Details:
-
-- Only [predefined interpolation functions](#predefined-interpolation-functions) are permitted.
-- A maximum of 3 functions may be specified in a single interpolation block.
-- The functions are executed in the sequence they are specified.
-
-```yaml
-spec:
- inputs:
- test:
- default: '0123456789'
----
-
-test-job:
- script: echo $[[ inputs.test | truncate(1,3) ]]
-```
-
-In this example:
-
-- The function [`truncate`](#truncate) applies to the value of `inputs.test`.
-- Assuming the value of `inputs.test` is `0123456789`, then the output of `script` would be `echo 123`.
-
-### Predefined interpolation functions
-
-#### Truncate
-
-Use `truncate` to shorten the interpolated value. For example:
-
-- `truncate(<offset>,<length>)`
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| `offset` | Integer | Number of characters to offset by. |
-| `length` | Integer | Number of characters to return after the offset. |
-
-Example:
-
-```yaml
-$[[ inputs.test | truncate(3,5) ]]
-```
-
-Assuming the value of `inputs.test` is `0123456789`, then the output would be `34567`.
-
-### Set input parameter values with `include:inputs`
-
-> `include:with` [renamed to `include:inputs`](https://gitlab.com/gitlab-org/gitlab/-/issues/406780) in GitLab 16.0.
-
-Use `include:inputs` to set the values for the parameters when the included configuration
-is added to the pipeline.
-
-For example, to include a `custom_configuration.yml` that has the same specs
-as the [example above](#define-input-parameters-with-specinputs):
-
-```yaml
-include:
- - local: 'custom_configuration.yml'
- inputs:
- website: "My website"
-```
-
-In this example:
-
-- `website` has a value of `My website` for the included configuration.
-- `user` has a value of `test-user`, because that is the default when not specified.
-- `flags` has no value, because it is optional and has no default when not specified.
-
## Troubleshooting
### `Maximum of 150 nested includes are allowed!` error
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index c4f7e6d6e01..6275d4293ea 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -9,9 +9,11 @@ type: reference
This document lists the configuration options for your GitLab `.gitlab-ci.yml` file.
-- For a quick introduction to GitLab CI/CD, follow the [quick start guide](../quick_start/index.md).
-- For a collection of examples, see [GitLab CI/CD Examples](../examples/index.md).
-- To view a large `.gitlab-ci.yml` file used in an enterprise, see the [`.gitlab-ci.yml` file for `gitlab`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml).
+- For a collection of examples, see [GitLab CI/CD examples](../examples/index.md).
+- To view a large `.gitlab-ci.yml` file used in an enterprise, see the
+ [`.gitlab-ci.yml` file for `gitlab`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml).
+- To create your own `.gitlab-ci.yml` file, try a tutorial that demonstrates a
+ [simple](../quick_start/index.md) or [complex](../quick_start/tutorial.md) pipeline.
When you are editing your `.gitlab-ci.yml` file, you can validate it with the
[CI Lint](../lint.md) tool.
@@ -75,8 +77,11 @@ or import additional pipeline configuration.
### `default`
-You can set global defaults for some keywords. Jobs that do not define one or more
-of the listed keywords use the value defined in the `default` section.
+> Support for `id_tokens` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419750) in GitLab 16.4.
+
+You can set global defaults for some keywords. Each default keyword is copied to every job
+that doesn't already have it defined. If the job already has a keyword defined, that default
+is not used.
**Keyword type**: Global keyword.
@@ -87,6 +92,7 @@ of the listed keywords use the value defined in the `default` section.
- [`before_script`](#before_script)
- [`cache`](#cache)
- [`hooks`](#hooks)
+- [`id_tokens`](#id_tokens)
- [`image`](#image)
- [`interruptible`](#interruptible)
- [`retry`](#retry)
@@ -99,6 +105,7 @@ of the listed keywords use the value defined in the `default` section.
```yaml
default:
image: ruby:3.0
+ retry: 2
rspec:
script: bundle exec rspec
@@ -108,16 +115,17 @@ rspec 2.7:
script: bundle exec rspec
```
-In this example, `ruby:3.0` is the default `image` value for all jobs in the pipeline.
-The `rspec 2.7` job does not use the default, because it overrides the default with
-a job-specific `image` section:
+In this example:
+
+- `image: ruby:3.0` and `retry: 2` are the default keywords for all jobs in the pipeline.
+- The `rspec` job does not have `image` or `retry` defined, so it uses the defaults of
+ `image: ruby:3.0` and `retry: 2`.
+- The `rspec 2.7` job does not have `retry` defined, but it does have `image` explictly defined.
+ It uses the default `retry: 2`, but ignores the default `image` and uses the `image: ruby:2.7`
+ defined in the job.
**Additional details**:
-- When the pipeline is created, each default is copied to all jobs that don't have
- that keyword defined.
-- If a job already has one of the keywords configured, the configuration in the job
- takes precedence and is not replaced by the default.
- Control inheritance of default keywords in jobs with [`inherit:default`](#inheritdefault).
### `include`
@@ -267,6 +275,11 @@ include:
- When you include a YAML file from another private project, the user running the pipeline
must be a member of both projects and have the appropriate permissions to run pipelines.
A `not found or access denied` error may be displayed if the user does not have access to any of the included files.
+- Be careful when including another project's CI/CD configuration file. No pipelines or notifications trigger when CI/CD configuration files change.
+ From a security perspective, this is similar to pulling a third-party dependency. For the `ref`, consider:
+ - Using a specific SHA hash, which should be the most stable option.
+ - Applying both [protected branch](../../user/project/protected_branches.md) and [protected tag](../../user/project/protected_tags.md#prevent-tag-creation-with-the-same-name-as-branches) rules to
+ the `ref` in the other project. Protected tags and branches are more likely to pass through change management before changing.
#### `include:remote`
@@ -293,9 +306,11 @@ include:
- All [nested includes](includes.md#use-nested-includes) are executed without context as a public user,
so you can only include public projects or templates. No variables are available in the `include` section of nested includes.
-- Be careful when including a remote CI/CD configuration file. No pipelines or notifications
- trigger when external CI/CD configuration files change. From a security perspective,
- this is similar to pulling a third-party dependency.
+- Be careful when including another project's CI/CD configuration file. No pipelines or notifications trigger
+ when the other project's files change. From a security perspective, this is similar to
+ pulling a third-party dependency. If you link to another GitLab project you own, consider the use of both
+ [protected branches](../../user/project/protected_branches.md) and [protected tags](../../user/project/protected_tags.md#prevent-tag-creation-with-the-same-name-as-branches)
+ to enforce change management rules.
#### `include:template`
@@ -1518,27 +1533,28 @@ is extracted from the job output. The coverage is shown in the UI if at least on
line in the job output matches the regular expression.
To extract the code coverage value from the match, GitLab uses
-this smaller regular expression: `\d+(\.\d+)?`.
+this smaller regular expression: `\d+(?:\.\d+)?`.
**Possible inputs**:
-- A regular expression. Must start and end with `/`. Must match the coverage number.
+- An RE2 regular expression. Must start and end with `/`. Must match the coverage number.
May match surrounding text as well, so you don't need to use a regular expression character group
to capture the exact number.
+ Because it uses RE2 syntax, all groups must be non-capturing.
**Example of `coverage`**:
```yaml
job1:
script: rspec
- coverage: '/Code coverage: \d+\.\d+/'
+ coverage: '/Code coverage: \d+(?:\.\d+)?/'
```
In this example:
1. GitLab checks the job log for a match with the regular expression. A line
like `Code coverage: 67.89% of lines covered` would match.
-1. GitLab then checks the matched fragment to find a match to `\d+(\.\d+)?`.
+1. GitLab then checks the matched fragment to find a match to `\d+(?:\.\d+)?`.
The sample matching line above gives a code coverage of `67.89`.
**Additional details**:
@@ -1997,12 +2013,19 @@ at certain stages of job execution, like before retrieving the Git repository.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/381840) in GitLab 15.10. Feature flag `ci_hooks_pre_get_sources_script` removed.
Use `hooks:pre_get_sources_script` to specify a list of commands to execute on the runner
-before retrieving the Git repository and any submodules. You can use it
-to adjust the Git client configuration first, for example.
+before cloning the Git repository and any submodules.
+You can use it for example to:
-**Related topics**:
+- Adjust the [Git configuration](../troubleshooting.md#get_sources-job-section-fails-because-of-an-http2-problem).
+- Export [tracing variables](../../topics/git/useful_git_commands.md).
-- [GitLab Runner configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)
+**Possible inputs**: An array including:
+
+- Single line commands.
+- Long commands [split over multiple lines](script.md#split-long-commands).
+- [YAML anchors](yaml_optimization.md#yaml-anchors-for-scripts).
+
+CI/CD variables [are supported](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
**Example of `hooks:pre_get_sources_script`**:
@@ -2014,6 +2037,10 @@ job1:
script: echo 'hello job1 script'
```
+**Related topics**:
+
+- [GitLab Runner configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)
+
### `id_tokens`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356986) in GitLab 15.7.
@@ -2717,7 +2744,7 @@ linux:rspec:
parallel:
matrix:
- PROVIDER: aws
- - STACK: app1
+ STACK: app1
script: echo "Running rspec on linux..."
```
@@ -3379,6 +3406,8 @@ only one of the jobs starts. The other jobs wait until the `resource_group` is f
Resource groups behave similar to semaphores in other programming languages.
+You can choose a [process mode](../resource_groups/index.md#process-modes) to strategically control the job concurrency for your deployment preferences. The default process mode is `unordered`. To change the process mode of a resource group, use the [API](../../api/resource_groups.md#edit-an-existing-resource-group) to send a request to edit an existing resource group.
+
You can define multiple resource groups per environment. For example,
when deploying to physical devices, you might have multiple physical devices. Each device
can be deployed to, but only one deployment can occur per device at any given time.
@@ -3598,10 +3627,10 @@ to specific files.
WARNING:
You should use `rules: changes` only with **branch pipelines** or **merge request pipelines**.
You can use `rules: changes` with other pipeline types, but `rules: changes` always
-evaluates to true when there is no Git `push` event. Tag pipelines, scheduled pipelines, manual pipelines,
-and so on do **not** have a Git `push` event associated with them. A `rules: changes` job
-is **always** added to those pipelines if there is no `if` that limits the job to
-branch or merge request pipelines.
+evaluates to true for new branch pipelines or when there is no Git `push` event. Pipelines like tag pipelines,
+scheduled pipelines, and manual pipelines, all do **not**
+have a Git `push` event associated with them. In these cases, use [`rules: changes: compare_to`](#ruleschangescompare_to)
+to specify the branch to compare against.
**Keyword type**: Job keyword. You can use it only as part of a job.
@@ -4368,6 +4397,9 @@ test:
### `trigger`
+> - Support for `resource_group` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/39057) support for `resource_group` in GitLab 13.9.
+> - Support for `environment` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369061) in GitLab 16.4.
+
Use `trigger` to declare that a job is a "trigger job" which starts a
[downstream pipeline](../pipelines/downstream_pipelines.md) that is either:
@@ -4386,6 +4418,8 @@ The keywords available for use in trigger jobs are:
- [`trigger`](#trigger).
- [`variables`](#variables).
- [`when`](#when) (only with a value of `on_success`, `on_failure`, or `always`).
+- [`resource_group`](#resource_group).
+- [`environment`](#environment).
**Keyword type**: Job keyword. You can use it only as part of a job.
@@ -4417,6 +4451,7 @@ trigger-multi-project-pipeline:
to forward these variables to downstream pipelines.
- [Job-level persisted variables](../variables/where_variables_can_be_used.md#persisted-variables)
are not available in trigger jobs.
+- Environment variables [defined in the runner's `config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) are not available to trigger jobs and are not passed to downstream pipelines.
**Related topics**:
diff --git a/doc/ci/yaml/inputs.md b/doc/ci/yaml/inputs.md
new file mode 100644
index 00000000000..1af53d666ce
--- /dev/null
+++ b/doc/ci/yaml/inputs.md
@@ -0,0 +1,174 @@
+---
+stage: Verify
+group: Pipeline Authoring
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Define inputs for configuration added with `include` **(FREE ALL BETA)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/391331) in GitLab 15.11 as a Beta feature.
+
+FLAG:
+`spec` and `inputs` are experimental [Open Beta features](../../policy/experiment-beta-support.md#beta)
+and subject to change without notice.
+
+## Define input parameters with `spec:inputs`
+
+Use `spec:inputs` to define input parameters for CI/CD configuration intended to be added
+to a pipeline with `include`. Use [`include:inputs`](#set-input-parameter-values-with-includeinputs)
+to define the values to use when the pipeline runs.
+
+The specs must be declared at the top of the configuration file, in a header section.
+Separate the header from the rest of the configuration with `---`.
+
+Use the interpolation format `$[[ input.input-id ]]` to reference the values outside of the header section.
+The inputs are evaluated and interpolated once, when the configuration is fetched
+during pipeline creation, but before the configuration is merged with the contents of the `.gitlab-ci.yml`.
+
+```yaml
+spec:
+ inputs:
+ environment:
+ job-stage:
+---
+
+scan-website:
+ stage: $[[ inputs.job-stage ]]
+ script: ./scan-website $[[ inputs.environment ]]
+```
+
+When using `spec:inputs`:
+
+- Defined inputs are mandatory by default.
+- Inputs can be made optional by specifying a `default`. Use `default: null` to have no default value.
+- A string containing an interpolation block must not exceed 1 MB.
+- The string inside an interpolation block must not exceed 1 KB.
+
+For example, a `custom_configuration.yml`:
+
+```yaml
+spec:
+ inputs:
+ website:
+ user:
+ default: 'test-user'
+ flags:
+ default: null
+---
+
+# The pipeline configuration would follow...
+```
+
+In this example:
+
+- `website` is mandatory and must be defined.
+- `user` is optional. If not defined, the value is `test-user`.
+- `flags` is optional. If not defined, it has no value.
+
+## Set input parameter values with `include:inputs`
+
+> `include:with` [renamed to `include:inputs`](https://gitlab.com/gitlab-org/gitlab/-/issues/406780) in GitLab 16.0.
+
+Use `include:inputs` to set the values for the parameters when the included configuration
+is added to the pipeline.
+
+For example, to include a `custom_configuration.yml` that has the same specs
+as the [example above](#define-input-parameters-with-specinputs):
+
+```yaml
+include:
+ - local: 'custom_configuration.yml'
+ inputs:
+ website: "My website"
+```
+
+In this example:
+
+- `website` has a value of `My website` for the included configuration.
+- `user` has a value of `test-user`, because that is the default when not specified.
+- `flags` has no value, because it is optional and has no default when not specified.
+
+### Use `include:inputs` with multiple files
+
+`inputs` must be specified separately for each included file. For example:
+
+```yaml
+include:
+ - component: gitlab.com/org/my-component@1.0
+ inputs:
+ stage: my-stage
+ - local: path/to/file.yml
+ inputs:
+ stage: my-stage
+```
+
+You can also include the same file multiple times, with different inputs.
+For example:
+
+```yaml
+include:
+ - local: path/to/my-super-linter.yml
+ inputs:
+ type: docs
+ job-name: lint-docs
+ lint-path: "doc/"
+ - local: path/to/my-super-linter.yml
+ inputs:
+ type: yaml
+ job-name: lint-yaml
+ lint-path: "data/yaml/"
+```
+
+## Specify functions to manipulate input values
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/409462) in GitLab 16.3.
+
+You can specify predefined functions in the interpolation block to manipulate the input value.
+The format supported is the following:
+
+```yaml
+$[[ input.input-id | <function1> | <function2> | ... <functionN> ]]
+```
+
+Details:
+
+- Only [predefined interpolation functions](#predefined-interpolation-functions) are permitted.
+- A maximum of 3 functions may be specified in a single interpolation block.
+- The functions are executed in the sequence they are specified.
+
+```yaml
+spec:
+ inputs:
+ test:
+ default: '0123456789'
+---
+
+test-job:
+ script: echo $[[ inputs.test | truncate(1,3) ]]
+```
+
+In this example:
+
+- The function [`truncate`](#truncate) applies to the value of `inputs.test`.
+- Assuming the value of `inputs.test` is `0123456789`, then the output of `script` would be `echo 123`.
+
+### Predefined interpolation functions
+
+#### `truncate`
+
+Use `truncate` to shorten the interpolated value. For example:
+
+- `truncate(<offset>,<length>)`
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `offset` | Integer | Number of characters to offset by. |
+| `length` | Integer | Number of characters to return after the offset. |
+
+Example:
+
+```yaml
+$[[ inputs.test | truncate(3,5) ]]
+```
+
+Assuming the value of `inputs.test` is `0123456789`, then the output would be `34567`.
diff --git a/doc/ci/yaml/signing_examples.md b/doc/ci/yaml/signing_examples.md
index 72e007a749f..e97ade891c4 100644
--- a/doc/ci/yaml/signing_examples.md
+++ b/doc/ci/yaml/signing_examples.md
@@ -7,12 +7,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Use Sigstore for keyless signing and verification **(FREE SAAS)**
The [Sigstore](https://www.sigstore.dev/) project provides a CLI called
-[Cosign](https://docs.sigstore.dev/cosign/overview/) which can be used for keyless signing of container images built
+[Cosign](https://docs.sigstore.dev/signing/quickstart/) which can be used for keyless signing of container images built
with GitLab CI/CD. Keyless signing has many advantages, including eliminating the need to manage, safeguard, and rotate a private
key. Cosign requests a short-lived key pair to use for signing, records it on a certificate transparency log, and
then discards it. The key is generated through a token obtained from the GitLab server using the OIDC identity of the user who
ran the pipeline. This token includes unique claims that certify the token was generated by a CI/CD pipeline. To learn more,
-see Cosign [documentation](https://docs.sigstore.dev/cosign/overview/#example-working-with-containers) on keyless signatures.
+see Cosign [documentation](https://docs.sigstore.dev/signing/quickstart/#example-working-with-containers) on keyless signatures.
For details on the mapping between GitLab OIDC claims and Fulcio certificate extensions, see the GitLab column of
[Mapping OIDC token claims to Fulcio OIDs](https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md#mapping-oidc-token-claims-to-fulcio-oids).
@@ -30,17 +30,21 @@ You can use Cosign to sign and verify container images and build artifacts.
- You must use a version of Cosign that is `>= 2.0.1`.
+**Limitations**
+
+- The `id_tokens` portion of the CI/CD config file must be located in the project that is being built and signed. AutoDevOps, CI files included from another repository, and child pipelines are not supported. Work to remove this limitation is being tracked in [issue 411317](https://gitlab.com/gitlab-org/gitlab/-/issues/411317).
+
**Best practices**:
- Build and sign an image/artifact in the same job to prevent it from being tampered with before it is signed.
- When signing container images, sign the digest (which is immutable) instead of the tag.
GitLab [ID tokens](../secrets/id_token_authentication.md#id-tokens) can be used by Cosign for
-[keyless signing](https://docs.sigstore.dev/cosign/overview/). The token must have
+[keyless signing](https://docs.sigstore.dev/signing/quickstart/). The token must have
`sigstore` set as the [`aud`](../secrets/id_token_authentication.md#token-payload) claim. The token can be used by Cosign automatically when it is set in the
`SIGSTORE_ID_TOKEN` environment variable.
-To learn more about how to install Cosign, see [Cosign Installation documentation](https://docs.sigstore.dev/cosign/installation/).
+To learn more about how to install Cosign, see [Cosign Installation documentation](https://docs.sigstore.dev/system_config/installation/).
### Signing
@@ -49,7 +53,7 @@ To learn more about how to install Cosign, see [Cosign Installation documentatio
The example below demonstrates how to sign a container image in GitLab CI. The signature is automatically stored in the
same container repository as the image.
-To learn more about signing containers, see [Cosign Signing Containers documentation](https://docs.sigstore.dev/cosign/signing_with_containers/).
+To learn more about signing containers, see [Cosign Signing Containers documentation](https://docs.sigstore.dev/signing/signing_with_containers/).
```yaml
build_and_sign_image:
@@ -77,7 +81,7 @@ build_and_sign_image:
The example below demonstrates how to sign a build artifact in GitLab CI. You should save the `cosign.bundle` file
produced by `cosign sign-blob`, which is used for signature verification.
-To learn more about signing artifacts, see [Cosign Signing Blobs documentation](https://docs.sigstore.dev/cosign/signing_with_blobs/#keyless-signing-of-blobs-and-files).
+To learn more about signing artifacts, see [Cosign Signing Blobs documentation](https://docs.sigstore.dev/signing/signing_with_blobs/).
```yaml
build_and_sign_artifact:
@@ -109,7 +113,7 @@ build_and_sign_artifact:
| `--certificate-oidc-issuer` | The GitLab instance URL where the image/artifact was signed. For example, `https://gitlab.com`. |
| `--bundle` | The `bundle` file produced by `cosign sign-blob`. Only used for verifying build artifacts. |
-To learn more about verifying signed images/artifacts, see [Cosign Verifying documentation](https://docs.sigstore.dev/cosign/verify/#keyless-verification-using-openid-connect).
+To learn more about verifying signed images/artifacts, see [Cosign Verifying documentation](https://docs.sigstore.dev/verifying/verify/).
#### Container images
@@ -149,7 +153,7 @@ You can use Sigstore and npm, together with GitLab CI/CD, to digitally sign buil
### About npm provenance
-[npm CLI](https://docs.npmjs.com/cli) allows package maintainers to provide users with provenance attestations. Using npm
+[npm CLI](https://docs.npmjs.com/cli/) allows package maintainers to provide users with provenance attestations. Using npm
CLI provenance generation allows users to trust and verify that the package they are downloading and using is from you and the
build system that built it.
diff --git a/doc/cloud_seed/index.md b/doc/cloud_seed/index.md
index a5067215ebb..70166b2d09f 100644
--- a/doc/cloud_seed/index.md
+++ b/doc/cloud_seed/index.md
@@ -21,8 +21,8 @@ services on a hyper-cloud based on a foundation of Terraform and infrastructure-
We believe that it should be **trivial** to deploy web applications (and other workloads) from GitLab to major cloud
providers.
-To support this effort, Cloud Seed makes it simple and intuitive to consume appropriate Google Cloud services
-within GitLab.
+To support this effort, Cloud Seed makes it straightforward and intuitive to consume appropriate Google Cloud services
+in GitLab.
## Why Google Cloud
@@ -114,11 +114,11 @@ the underlying Google Cloud service that is used to provision the database insta
The following databases and versions are supported:
-- PostgreSQL: 14, 13, 12, 11, 10 and 9.6
+- PostgreSQL: 14, 13, 12, 11, 10, and 9.6
- MySQL: 8.0, 5.7 and 5.6
- SQL Server
- - 2019: Standard, Enterprise, Express and Web
- - 2017: Standard, Enterprise, Express and Web
+ - 2019: Standard, Enterprise, Express, and Web
+ - 2017: Standard, Enterprise, Express, and Web
Google Cloud pricing applies. Please refer to the [Cloud SQL pricing page](https://cloud.google.com/sql/pricing).
@@ -129,7 +129,7 @@ Google Cloud pricing applies. Please refer to the [Cloud SQL pricing page](https
### Create a database instance
-From the `Project :: Infrastructure :: Google Cloud` page, select the **Database** tab. Here you will find three
+From the `Project :: Infrastructure :: Google Cloud` page, select the **Database** tab. Here you find three
buttons to create Postgres, MySQL, and SQL Server database instances.
The database instance creation form has fields for GCP project, Git ref (branch or tag), database version and
@@ -145,7 +145,7 @@ Successful creation of the database instance triggers a background worker to per
### Connect to the database
-Once the database instance setup is complete, the database connection details are available as project variables. These
+After the database instance setup is complete, the database connection details are available as project variables. These
can be managed through the `Project :: Settings :: CI` page and are made available to pipeline executing in the
appropriate environment.
@@ -158,11 +158,9 @@ Console. Select an instance to view the details and manage the instance.
There are several ways you can contribute to Cloud Seed:
-- [Become a Cloud Seed user](https://docs.google.com/forms/d/e/1FAIpQLSeJPtFE8Vpqs_YTAKkFK42p5mO9zIYA2jr_PiP2h32cs8R39Q/viewform)
- in GitLab
- and [share feedback](https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/feedback/-/issues/new?template=general_feedback).
+- Use Cloud Seed and [share feedback](https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/feedback/-/issues/new?template=general_feedback).
- If you are familiar with Ruby on Rails or Vue.js,
consider [contributing to GitLab](../development/contributing/index.md) as a developer.
- - Much of Cloud Seed is an internal module within the GitLab codebase.
+ - Much of Cloud Seed is an internal module in the GitLab codebase.
- If you are familiar with GitLab pipelines, consider contributing to
the [Cloud Seed Library](https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library) project.
diff --git a/doc/development/activitypub/actor.md b/doc/development/activitypub/actor.md
new file mode 100644
index 00000000000..1d10e421df7
--- /dev/null
+++ b/doc/development/activitypub/actor.md
@@ -0,0 +1,11 @@
+---
+redirect_to: 'actors/index.md'
+remove_date: '2023-12-08'
+---
+
+This document was moved to [another location](actors/index.md).
+
+<!-- This redirect file can be deleted after <2023-12-08>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/development/activitypub/actors/group.md b/doc/development/activitypub/actors/group.md
new file mode 100644
index 00000000000..dad02298170
--- /dev/null
+++ b/doc/development/activitypub/actors/group.md
@@ -0,0 +1,205 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+---
+
+# Activities for group actor **(EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023) in GitLab 16.5 [with two flags](../../../administration/feature_flags.md) named `activity_pub` and `activity_pub_project`. Disabled by default. This feature is an [Experiment](../../../policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flags](../../../administration/feature_flags.md)
+named `activity_pub` and `activity_pub_project`.
+On GitLab.com, this feature is not available.
+The feature is not ready for production use.
+
+This feature requires two feature flags:
+
+- `activity_pub`: Enables or disables all ActivityPub-related features.
+- `activity_pub_project`: Enables and disable ActivityPub features specific to
+ projects. Requires the `activity_pub` flag to also be enabled.
+
+## Profile
+
+```javascript
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "id": GROUP_URL,
+ "type": "Group",
+ "name": GROUP_NAME,
+ "summary": GROUP_DESCRIPTION,
+ "url": GROUP_URL,
+ "outbox": GROUP_OUTBOX_URL,
+ "inbox": null,
+}
+```
+
+## Outbox
+
+The various activities for a group are:
+
+- [The group was created](#the-group-was-created).
+- All project activities for projects in that group, and its subgroups.
+- [A user joined the group](#a-user-joined-the-group).
+- [A user left the group](#a-user-left-the-group).
+- [The group was deleted](#the-group-was-deleted).
+- [A subgroup was created](#a-subgroup-was-created).
+- [A subgroup was deleted](#a-subgroup-was-deleted).
+
+### The group was created
+
+```javascript
+{
+ "id": GROUP_OUTBOX_URL#event_id,
+ "type": "Create",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": GROUP_URL,
+ "type": "Group",
+ "name": GROUP_NAME,
+ "url": GROUP_URL,
+ }
+}
+```
+
+### A user joined the group
+
+```javascript
+{
+ "id": GROUP_OUTBOX_URL#event_id,
+ "type": "Join",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": GROUP_URL,
+ "type": "Group",
+ "name": GROUP_NAME,
+ "url": GROUP_URL,
+ },
+}
+```
+
+### A user left the group
+
+```javascript
+{
+ "id": GROUP_OUTBOX_URL#event_id,
+ "type": "Leave",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": GROUP_URL,
+ "type": "Group",
+ "name": GROUP_NAME,
+ "url": GROUP_URL,
+ },
+}
+```
+
+### The group was deleted
+
+```javascript
+{
+ "id": GROUP_OUTBOX_URL#event_id,
+ "type": "Delete",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": GROUP_URL,
+ "type": "Group",
+ "name": GROUP_NAME,
+ "url": GROUP_URL,
+ }
+}
+```
+
+### A subgroup was created
+
+```javascript
+{
+ "id": GROUP_OUTBOX_URL#event_id,
+ "type": "Create",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": GROUP_URL,
+ "type": "Group",
+ "name": GROUP_NAME,
+ "url": GROUP_URL,
+ "context": {
+ "id": PARENT_GROUP_URL,
+ "type": "Group",
+ "name": PARENT_GROUP_NAME,
+ "url": PARENT_GROUP_URL,
+ }
+ }
+}
+```
+
+### A subgroup was deleted
+
+```javascript
+{
+ "id": GROUP_OUTBOX_URL#event_id,
+ "type": "Delete",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": GROUP_URL,
+ "type": "Group",
+ "name": GROUP_NAME,
+ "url": GROUP_URL,
+ "context": {
+ "id": PARENT_GROUP_URL,
+ "type": "Group",
+ "name": PARENT_GROUP_NAME,
+ "url": PARENT_GROUP_URL,
+ }
+ }
+}
+```
diff --git a/doc/development/activitypub/actors/index.md b/doc/development/activitypub/actors/index.md
new file mode 100644
index 00000000000..032cb26587a
--- /dev/null
+++ b/doc/development/activitypub/actors/index.md
@@ -0,0 +1,148 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+---
+
+# Implement an ActivityPub actor **(EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023) in GitLab 16.5 [with two flags](../../../administration/feature_flags.md) named `activity_pub` and `activity_pub_project`. Disabled by default. This feature is an [Experiment](../../../policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flags](../../../administration/feature_flags.md)
+named `activity_pub` and `activity_pub_project`.
+On GitLab.com, this feature is not available.
+The feature is not ready for production use.
+
+This feature requires two feature flags:
+
+- `activity_pub`: Enables or disables all ActivityPub-related features.
+- `activity_pub_project`: Enables and disable ActivityPub features specific to
+ projects. Requires the `activity_pub` flag to also be enabled.
+
+ActivityPub is based on three standard documents:
+
+- [ActivityPub](https://www.w3.org/TR/activitypub/) defines the HTTP
+ requests happening to implement federation.
+- [ActivityStreams](https://www.w3.org/TR/activitystreams-core/) defines the
+ format of the JSON messages exchanged by the users of the protocol.
+- [Activity Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/)
+ defines the various messages recognized by default.
+
+The first one is typically handled by controllers, while the two others are
+related to what happen in serializers.
+
+To implement an ActivityPub actor, you must:
+
+- Implement the profile page of the resource.
+- Implement the outbox page.
+- Handle incoming requests on the inbox.
+
+All requests are made using
+`application/ld+json; profile="https://www.w3.org/ns/activitystreams"` as `Accept` HTTP header.
+
+The actors we're implementing for the social features:
+
+- [Releases](releases.md)
+- [Topics](topic.md)
+- [Projects](project.md)
+- [Groups](group.md)
+- [Users](user.md)
+
+## Profile page
+
+Querying the profile page is used to retrieve:
+
+- General information about it, like name and description.
+- URLs for the inbox and the outbox.
+
+To implement a profile page, create an ActivityStreams
+serializer in `app/serializers/activity_pub/`, making your serializer
+inherit from `ActivityStreamsSerializer`. See below in the serializers
+section about the mandatory fields.
+
+To call your serializer in your controller:
+
+```ruby
+opts = {
+ inbox: nil,
+ outbox: outbox_project_releases_url(project)
+}
+
+render json: ActivityPub::ReleasesActorSerializer.new.represent(project, opts)
+```
+
+- `outbox` is the endpoint where to find the activities feed for this
+actor.
+- `inbox` is where to POST to subscribe to the feed. Not yet implemented, so pass `nil`.
+
+## Outbox page
+
+The outbox is the list of activities for the resource. It's a feed for the
+resource, and it allows ActivityPub clients to show public activities for
+this actor without having yet subscribed to it.
+
+To implement an outbox page, create an ActivityStreams
+serializer in `app/serializers/activity_pub/`, making your serializer
+inherit from `ActivityStreamsSerializer`. See below in the serializers
+section about the mandatory fields.
+
+You call your serializer in your controller like this:
+
+```ruby
+serializer = ActivityPub::ReleasesOutboxSerializer.new.with_pagination(request, response)
+render json: serializer.represent(releases)
+```
+
+This converts the response to an `OrderedCollection`
+ActivityPub type, with all the correct fields.
+
+## Inbox
+
+Not yet implemented.
+
+The inbox is where the ActivityPub compatible third-parties makes their
+requests, to subscribe to the actor or send it messages.
+
+## ActivityStreams serializers
+
+The serializers implement half the core of ActivityPub support: they're all
+about [ActivityStreams](https://www.w3.org/TR/activitystreams-core/), the
+message format used by ActivityPub.
+
+To leverage the features doing most of the formatting for you, your
+serializer should inherit from `ActivityPub::ActivityStreamsSerializer`.
+
+To use it, call the `#represent` method. It requires you to provide
+`inbox` and `outbox` options (as mentioned above) if it
+is an actor profile page. You don't need those if your serializer
+represents an object that is just meant to be embedded as part of actors,
+like the object representing the contact information for a user.
+
+Each resource serialized (included other objects embedded in your
+actor) must provide an `id` and a `type` field.
+
+`id` is a URL. It's meant to be a unique identifier for the resource, and
+it must point to an existing page: ideally, an actor. Otherwise, you can
+just reference the closest actor and use an anchor, like this:
+
+```plaintext
+https://gitlab.com/user/project/-/releases#release-1
+```
+
+`type` should be taken from ActivityStreams core vocabulary:
+
+- [Activity types](https://www.w3.org/TR/activitystreams-vocabulary/#activity-types)
+- [Actor types](https://www.w3.org/TR/activitystreams-vocabulary/#actor-types)
+- [Object types](https://www.w3.org/TR/activitystreams-vocabulary/#object-types)
+
+The properties you can use are all documented in
+[the ActivityStreams vocabulary document](https://www.w3.org/TR/activitystreams-vocabulary).
+Given the type you have chosen for your resource, find the
+`properties` list, telling you all available properties, direct or
+inherited.
+
+It's worth noting that Mastodon adds one more property, `preferredName`.
+Mastodon expects it to be set on any actor, or that actor is not recognized by
+Mastodon.
diff --git a/doc/development/activitypub/actors/project.md b/doc/development/activitypub/actors/project.md
new file mode 100644
index 00000000000..4f876b9e3fa
--- /dev/null
+++ b/doc/development/activitypub/actors/project.md
@@ -0,0 +1,640 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+---
+
+# Activities for project actor **(EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023) in GitLab 16.5 [with two flags](../../../administration/feature_flags.md) named `activity_pub` and `activity_pub_project`. Disabled by default. This feature is an [Experiment](../../../policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flags](../../../administration/feature_flags.md)
+named `activity_pub` and `activity_pub_project`.
+On GitLab.com, this feature is not available.
+The feature is not ready for production use.
+
+This feature requires two feature flags:
+
+- `activity_pub`: Enables or disables all ActivityPub-related features.
+- `activity_pub_project`: Enables and disable ActivityPub features specific to
+ projects. Requires the `activity_pub` flag to also be enabled.
+
+## Profile
+
+```javascript
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ "outbox": PROJECT_OUTBOX_URL,
+ "inbox": null,
+}
+```
+
+## Outbox
+
+For a project, we can map the events happening on the project activity
+timeline on GitLab, when a user:
+
+- [Creates the repository](#user-creates-the-repository).
+- [Pushes commits](#user-pushes-commits).
+- [Pushes a tag](#user-pushes-a-tag).
+- [Opens a merge request](#user-opens-a-merge-request).
+- [Accepts a merge request](#user-accepts-a-merge-request).
+- [Closes a merge request](#user-closes-a-merge-request).
+- [Opens an issue](#user-opens-an-issue).
+- [Closes an issue](#user-closes-an-issue).
+- [Reopens an issue](#user-reopens-an-issue).
+- [Comments on a merge request](#user-comments-on-a-merge-request).
+- [Comments on an issue](#user-comments-on-an-issue).
+- [Creates a wiki page](#user-creates-a-wiki-page).
+- [Updates a wiki page](#user-updates-a-wiki-page).
+- [Destroys a wiki page](#user-destroys-a-wiki-page).
+- [Joins the project](#user-joins-the-project).
+- [Leaves the project](#user-leaves-the-project).
+- [Deletes the repository](#user-deletes-the-repository).
+
+There's also a Design tab in the project activities, but it's just empty in
+all projects I follow and I don't see anything related to it in my projects
+sidebar. Maybe it's a premium feature? If so, it's of no concern to us for
+public following through ActivityPub.
+
+### User creates the repository
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Create",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ }
+}
+```
+
+### User pushes commits
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Update",
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ "result": COMMITS_DIFF_URL,
+}
+```
+
+### User pushes a tag
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Update",
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ "name": TAG_NAME,
+ "result": COMMIT_URL,
+}
+```
+
+### User opens a merge request
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Add",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": MERGE_REQUEST_URL,
+ "type": "Application",
+ "name": MERGE_REQUEST_TITLE,
+ "url": MERGE_REQUEST_URL,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ },
+ "target": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+}
+```
+
+### User accepts a merge request
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Accept",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": MERGE_REQUEST_URL,
+ "type": "Application",
+ "name": MERGE_REQUEST_TITLE,
+ "url": MERGE_REQUEST_URL,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ },
+ "target": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+}
+```
+
+### User closes a merge request
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Remove",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": MERGE_REQUEST_URL,
+ "type": "Application",
+ "name": MERGE_REQUEST_TITLE,
+ "url": MERGE_REQUEST_URL,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ },
+ "origin": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+}
+```
+
+### User opens an issue
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Add",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": ISSUE_URL,
+ "type": "Page",
+ "name": ISSUE_TITLE,
+ "url": ISSUE_URL,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ }
+ },
+ "target": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ }
+}
+```
+
+Why to add the project both as `object.context` and `target`? For multiple
+consistency reasons:
+
+- The **Add** activity is more commonly used with a `target`.
+- The **Remove** activity used to close the issue is more
+ commonly used with an `origin`.
+- The **Update** activity used to reopen an issue specifies that
+ `target` and `origin` have no specific meaning, making `context` better
+ suited for that.
+- We could use `context` only with **Update**, but merge requests
+ must be taken into consideration.
+
+Merge requests are very similar to issues, so we want their activities to
+be similar. While the best type for issues is `page`, the type chosen for
+merge request is `application`, both to distinguish it from issues and because
+they contain code.
+
+To distinguish merge requests from projects (which are also `application`),
+merge requests are an `application` with another `application` (the project)
+as context. Given the merge request will have a `context` even with the **Add**
+and **Remove** activities, the same is done with issues for consistency.
+
+An alternative that was considered, but dismissed: instead of **Add** for issues,
+use **Create**. That would have allowed us to always use `context`, but
+it creates more problems that it solves. **Accept** and **Reject** could work quite
+well for closing merge requests, but what would we use to close issues?
+**Delete** is incorrect, as the issue is not deleted, just closed.
+Reopening the issue later would require an **Update** after a
+**Delete**.
+
+Using **Create** for opening issues and **Remove** for closing
+issues would be asymmetrical:
+
+- **Create** is mirrored by **Delete**.
+- **Add** is mirrored by **Remove**.
+
+To minimize pain for those who will build on top of those resources, it's best
+to duplicate the project information as `context` and `target` / `origin`.
+
+### User closes an issue
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Remove",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": ISSUE_URL,
+ "type": "Page",
+ "name": ISSUE_TITLE,
+ "url": ISSUE_URL,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ },
+ "origin": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+}
+```
+
+### User reopens an issue
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Update",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": ISSUE_URL,
+ "type": "Page",
+ "name": ISSUE_TITLE,
+ "url": ISSUE_URL,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ },
+}
+```
+
+### User comments on a merge request
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Add",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": NOTE_URL,
+ "type": "Note",
+ "content": NOTE_NOTE,
+ },
+ "target": {
+ "id": MERGE_REQUEST_URL,
+ "type": "Application",
+ "name": MERGE_REQUEST_TITLE,
+ "url": MERGE_REQUEST_URL,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ },
+}
+```
+
+### User comments on an issue
+
+```javascript
+{
+ "id": PROJECT_URL#event_id,
+ "type": "Add",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": NOTE_URL,
+ "type": "Note",
+ "content": NOTE_NOTE,
+ },
+ "target": {
+ "id": ISSUE_URL,
+ "type": "Page",
+ "name": ISSUE_TITLE,
+ "url": ISSUE_URL,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ },
+}
+```
+
+### User creates a wiki page
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Create",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": WIKI_PAGE_URL,
+ "type": "Page",
+ "name": WIKI_PAGE_HUMAN_TITLE,
+ "url": WIKI_PAGE_URL,
+ }
+}
+```
+
+### User updates a wiki page
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Update",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": WIKI_PAGE_URL,
+ "type": "Page",
+ "name": WIKI_PAGE_HUMAN_TITLE,
+ "url": WIKI_PAGE_URL,
+ }
+}
+```
+
+### User destroys a wiki page
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Delete",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": WIKI_PAGE_URL,
+ "type": "Page",
+ "name": WIKI_PAGE_HUMAN_TITLE,
+ "url": WIKI_PAGE_URL,
+ }
+}
+```
+
+### User joins the project
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Add",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "target": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+}
+```
+
+The GitLab project timeline does not mention who added a member to the
+project, so this does the same. However, the **Add** activity requires an Actor.
+For that reason, we use the same person as actor and object.
+
+In the **Members** page of a project contains a `source` attribute.
+While there is sometimes mention of who added the user, this is used mainly
+to distinguish if the user is a member attached to the project directly, or
+through a group. It would not be a good "actor" (that would rather be an
+`origin` for the membership).
+
+### User leaves the project
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Remove",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "target": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+}
+```
+
+See [User joined the project](#user-joins-the-project).
+
+### User deletes the repository
+
+```javascript
+{
+ "id": PROJECT_OUTBOX_URL#event_id,
+ "type": "Delete",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ }
+}
+```
diff --git a/doc/development/activitypub/actors/releases.md b/doc/development/activitypub/actors/releases.md
new file mode 100644
index 00000000000..009b98b6adf
--- /dev/null
+++ b/doc/development/activitypub/actors/releases.md
@@ -0,0 +1,85 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+---
+
+# Activities for following releases actor **(EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023) in GitLab 16.5 [with two flags](../../../administration/feature_flags.md) named `activity_pub` and `activity_pub_project`. Disabled by default. This feature is an [Experiment](../../../policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flags](../../../administration/feature_flags.md)
+named `activity_pub` and `activity_pub_project`.
+On GitLab.com, this feature is not available.
+The feature is not ready for production use.
+
+This feature requires two feature flags:
+
+- `activity_pub`: Enables or disables all ActivityPub-related features.
+- `activity_pub_project`: Enables and disable ActivityPub features specific to
+ projects. Requires the `activity_pub` flag to also be enabled.
+
+## Profile
+
+The profile is this actor is a bit different from other actors. We don't want to
+show activities for a given release, but instead the releases for a given project.
+
+The profile endpoint is handled by `Projects::ReleasesController#index`
+on the list of releases, and should reply with something like this:
+
+```javascript
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "id": PROJECT_RELEASES_URL,
+ "type": "Application",
+ "name": PROJECT_NAME + " releases",
+ "url": PROJECT_RELEASES_URL,
+ "content": PROJECT_DESCRIPTION,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ "outbox": PROJECT_RELEASES_OUTBOX_URL,
+ "inbox": null,
+}
+```
+
+## Outbox
+
+The release actor is relatively simple: the only activity happening is the
+**Create release** event.
+
+```javascript
+{
+ "id": PROJECT_RELEASES_OUTBOX_URL#release_id,
+ "type": "Create",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ },
+ "object": {
+ "id": RELEASE_URL,
+ "type": "Application",
+ "name": RELEASE_TITLE,
+ "url": RELEASE_URL,
+ "content": RELEASE_DESCRIPTION,
+ "context": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "summary": PROJECT_DESCRIPTION,
+ "url": PROJECT_URL,
+ },
+ },
+}
+```
diff --git a/doc/development/activitypub/actors/topic.md b/doc/development/activitypub/actors/topic.md
new file mode 100644
index 00000000000..f99a6e0569a
--- /dev/null
+++ b/doc/development/activitypub/actors/topic.md
@@ -0,0 +1,91 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+---
+
+# Activities for topic actor **(EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023) in GitLab 16.5 [with two flags](../../../administration/feature_flags.md) named `activity_pub` and `activity_pub_project`. Disabled by default. This feature is an [Experiment](../../../policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flags](../../../administration/feature_flags.md)
+named `activity_pub` and `activity_pub_project`.
+On GitLab.com, this feature is not available.
+The feature is not ready for production use.
+
+This feature requires two feature flags:
+
+- `activity_pub`: Enables or disables all ActivityPub-related features.
+- `activity_pub_project`: Enables and disable ActivityPub features specific to
+ projects. Requires the `activity_pub` flag to also be enabled.
+
+## Profile
+
+```javascript
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "id": TOPIC_URL,
+ "type": "Group",
+ "name": TOPIC_NAME,
+ "url": TOPIC_URL,
+ "summary": TOPIC_DESCRIPTION,
+ "outbox": TOPIC_OUTBOX_URL,
+ "inbox": null,
+}
+```
+
+## Outbox
+
+Like the release actor, the topic specification is not complex. It generates an
+activity only when a new project has been added to the given topic.
+
+```javascript
+{
+ "id": TOPIC_OUTBOX_URL#event_id,
+ "type": "Add",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "actor": {
+ "id": PROJECT_URL,
+ "type": "Application",
+ "name": PROJECT_NAME,
+ "url": PROJECT_URL,
+ },
+ "object": {
+ "id": TOPIC_URL,
+ "type": "Group",
+ "name": TOPIC_NAME,
+ "url": TOPIC_URL,
+ },
+ },
+}
+```
+
+## Possible difficulties
+
+There is hidden complexity here.
+
+The simpler way to build this endpoint is to take the projects associated
+to a topic, and sort them by descending creation date. However,
+if we do that, discrepancies will occur when implementing the
+activity push part of the standard.
+
+Adding the project to a topic is not made at project creation time. It's
+made when a project's topics are _edited_. That action can happen a very long time
+after the project creation date. In that case, a push activity is
+created and sent to federated instances when adding the topic to the
+project. However, the list in the outbox endpoint that sorts projects by descending
+creation date doesn't show the project, because it was created long ago.
+
+No special logic happens when a topic is added to a project, except:
+
+- Cleaning up the topic list.
+- Creating the topic in database, if it doesn't exist yet.
+
+No event is generated. We should add such an event so the activity
+push create an event, ideally in `Projects::UpdateService`. Then, the outbox endpoint
+can list those events to be sure to match what was sent. When doing that, we should
+verify that it doesn't affect other pages or endpoints dealing with events.
diff --git a/doc/development/activitypub/actors/user.md b/doc/development/activitypub/actors/user.md
new file mode 100644
index 00000000000..9fe4f8ec88e
--- /dev/null
+++ b/doc/development/activitypub/actors/user.md
@@ -0,0 +1,47 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+---
+
+# Activities for following user actor **(EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023) in GitLab 16.5 [with two flags](../../../administration/feature_flags.md) named `activity_pub` and `activity_pub_project`. Disabled by default. This feature is an [Experiment](../../../policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flags](../../../administration/feature_flags.md)
+named `activity_pub` and `activity_pub_project`.
+On GitLab.com, this feature is not available.
+The feature is not ready for production use.
+
+This feature requires two feature flags:
+
+- `activity_pub`: Enables or disables all ActivityPub-related features.
+- `activity_pub_project`: Enables and disable ActivityPub features specific to
+ projects. Requires the `activity_pub` flag to also be enabled.
+
+## Profile
+
+This activity is the first resource ActivityPub has in mind:
+
+```javascript
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "id": USER_PROFILE_URL,
+ "type": "Person",
+ "name": USER_NAME,
+ "url": USER_PROFILE_URL,
+ "outbox": USER_OUTBOX_URL,
+ "inbox": null,
+}
+```
+
+## Outbox
+
+The user actor is special because it can be linked to all events happening on the platform.
+It's a join of events on other resources:
+
+- All release activities.
+- All project activities.
+- All group activities.
diff --git a/doc/development/activitypub/index.md b/doc/development/activitypub/index.md
new file mode 100644
index 00000000000..d89f18080f0
--- /dev/null
+++ b/doc/development/activitypub/index.md
@@ -0,0 +1,216 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
+---
+
+# ActivityPub **(EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127023) in GitLab 16.5 [with two flags](../../administration/feature_flags.md) named `activity_pub` and `activity_pub_project`. Disabled by default. This feature is an [Experiment](../../policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flags](../../administration/feature_flags.md)
+named `activity_pub` and `activity_pub_project`.
+On GitLab.com, this feature is not available.
+The feature is not ready for production use.
+
+Usage of ActivityPub in GitLab is governed by the
+[GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
+
+The goal of those documents is to provide an implementation path for adding
+Fediverse capabilities to GitLab.
+
+This page describes the conceptual and high level point of view, while
+sub-pages discuss implementation in more technical depth (as in, how to
+implement this in the actual rails codebase of GitLab).
+
+This feature requires two feature flags:
+
+- `activity_pub`: Enables or disables all ActivityPub-related features.
+- `activity_pub_project`: Enables and disable ActivityPub features specific to
+ projects. Requires the `activity_pub` flag to also be enabled.
+
+## What
+
+Feel free to jump to [the Why section](#why) if you already know what
+ActivityPub and the Fediverse are.
+
+Among the push for [decentralization of the web](https://en.wikipedia.org/wiki/Decentralized_web),
+several projects tried different protocols with different ideals behind their reasoning.
+Some examples:
+
+- [Secure Scuttlebutt](https://en.wikipedia.org/wiki/Secure_Scuttlebutt) (or SSB for short)
+- [Dat](https://en.wikipedia.org/wiki/Dat_%28software%29)
+- [IPFS](https://en.wikipedia.org/wiki/InterPlanetary_File_System),
+- [Solid](https://en.wikipedia.org/wiki/Solid_%28web_decentralization_project%29)
+
+One gained traction recently: [ActivityPub](https://en.wikipedia.org/wiki/ActivityPub),
+better known for the colloquial [Fediverse](https://en.wikipedia.org/wiki/Fediverse) built
+on top of it, through applications like
+[Mastodon](https://en.wikipedia.org/wiki/Mastodon_%28social_network%29)
+(which could be described as some sort of decentralized Facebook) or
+[Lemmy](https://en.wikipedia.org/wiki/Lemmy_%28software%29) (which could be
+described as some sort of decentralized Reddit).
+
+ActivityPub has several advantages that makes it attractive
+to implementers and could explain its current success:
+
+- **It's built on top of HTTP**. You don't need to install new software or
+ to tinker with TCP/UDP to implement ActivityPub, if you have a webserver
+ or an application that provides an HTTP API (like a rails application),
+ you already have everything you need.
+- **It's built on top of JSON**. All communications are basically JSON
+ objects, which web developers are already used to, which simplifies adoption.
+- **It's a W3C standard and already has multiple implementations**. Being
+ piloted by the W3C is a guarantee of stability and quality work. They
+ have profusely demonstrated in the past through their work on HTML, CSS
+ or other web standards that we can build on top of their work without
+ the fear of it becoming deprecated or irrelevant after a few years.
+
+### The Fediverse
+
+The core idea behind Mastodon and Lemmy is called the Fediverse. Rather
+than full decentralization, those applications rely on federation, in the
+sense that there still are servers and clients. It's not P2P like SSB,
+Dat and IPFS, but instead a galaxy of servers chatting with each other
+instead of having central servers controlled by a single entity.
+
+The user signs up to one of those servers (called **instances**), and they
+can then interact with users either on this instance, or on other ones.
+From the perspective of the user, they access a global network, and not
+only their instance. They see the articles posted on other instances, they
+can comment on them, upvote them, etc.
+
+What happens behind the scenes:
+their instance knows where the user they reply to is hosted. It
+contacts that other instance to let them know there is a message for them -
+somewhat similar to SMTP. Similarly, when a user subscribes
+to a feed, their instance informs the instance where the feed is
+hosted of this subscription. That target instance then posts back
+messages when new activities are created. This allows for a push model, rather
+than a constant poll model like RSS. Of course, what was just described is
+the happy path; there is moderation, validation and fault tolerance
+happening all the way.
+
+### ActivityPub
+
+Behind the Fediverse is the ActivityPub protocol. It's a HTTP API
+attempting to be as general a social network implementation as possible,
+while giving options to be extendable.
+
+The basic idea is that an `actor` sends and receives `activities`. Activities
+are structured JSON messages with well-defined properties, but are extensible
+to cover any need. An actor is defined by four endpoints, which are
+contacted with the
+`application/ld+json; profile="https://www.w3.org/ns/activitystreams"` HTTP Accept header:
+
+- `GET /inbox`: used by the actor to find new activities intended for them.
+- `POST /inbox`: used by instances to push new activities intended for the actor.
+- `GET /outbox`: used by anyone to read the activities created by the actor.
+- `POST /outbox`: used by the actor to publish new activities.
+
+Among those, Mastodon and Lemmy only use `POST /inbox` and `GET /outbox`, which
+are the minimum needed to implement federation:
+
+- Instances push new activities for the actor on the inbox.
+- Reading the outbox allows reading the feed of an actor.
+
+Additionally, Mastodon and Lemmy implement a `GET /` endpoint (with the
+mentioned Accept header). This endpoint responds with general information about the
+actor, like name and URL of the inbox and outbox. While not required by the
+standard, it makes discovery easier.
+
+While a person is the main use case for an actor, an actor does not
+necessarily map to a person. Anything can be an actor: a topic, a
+subreddit, a group, an event. For GitLab, anything with activities (in the sense
+of what GitLab means by "activity") can be an ActivityPub actor. This includes
+items like projects, groups, and releases. In those more abstract examples,
+an actor can be thought of as an actionable feed.
+
+ActivityPub by itself does not cover everything that is needed to implement
+the Fediverse. Most notably, these are left for the implementers to figure out:
+
+- Finding a way to deal with spam. Spam is handled by authorizing or
+ blocking ("defederating") other instances.
+- Discovering new instances.
+- Performing network-wide searches.
+
+## Why
+
+Why would a social media protocol be useful for GitLab? People want a single,
+global GitLab network to interact between various projects, without having to
+register on each of their hosts.
+
+Several very popular discussions around this have already happened:
+
+- [Share events externally via ActivityPub](https://gitlab.com/gitlab-org/gitlab/-/issues/21582)
+- [Implement cross-server (federated) merge requests](https://gitlab.com/gitlab-org/gitlab/-/issues/14116)
+- [Distributed merge requests](https://gitlab.com/groups/gitlab-org/-/epics/260).
+
+The ideal workflow would be:
+
+1. Alice registers to her favorite GitLab instance, like `gitlab.example.org`.
+1. She looks for a project on a given topic, and sees Bob's project, even though
+ Bob is on `gitlab.com`.
+1. Alice selects **Fork**, and the `gitlab.com/Bob/project.git` is
+ forked to `gitlab.example.org/Alice/project.git`.
+1. She makes her edits, and opens a merge request, which appears in Bob's
+ project on `gitlab.com`.
+1. Alice and Bob discuss the merge request, each one from their own GitLab
+ instance.
+1. Bob can send additional commits, which are picked up by Alice's instance.
+1. When Bob accepts the merge request, his instance picks up the code from
+ Alice's instance.
+
+In this process, ActivityPub would help in:
+
+- Letting Bob know a fork happened.
+- Sending the merge request to Bob.
+- Enabling Alice and Bob to discuss the merge request.
+- Letting Alice know the code was merged.
+
+It does _not_ help in these cases, which need specific implementations:
+
+- Implementing a network-wide search.
+- Implementing cross-instance forks. (Not needed, thanks to Git.)
+
+Why use ActivityPub here rather than implementing cross-instance merge requests
+in a custom way? Two reasons:
+
+1. **Building on top of a standard helps reach beyond GitLab**.
+ While the workflow presented above only mentions GitLab, building on top
+ of a W3C standard means other forges can follow GitLab
+ there, and build a massive Fediverse of code sharing.
+1. **An opportunity to make GitLab more social**. To prepare the
+ architecture for the workflow above, smaller steps can be taken, allowing
+ people to subscribe to activity feeds from their Fediverse social
+ network. Anything that has a RSS feed could become an ActivityPub feed.
+ People on Mastodon could follow their favorite developer, project, or topic
+ from GitLab and see the news in their feed on Mastodon, hopefully raising
+ engagement with GitLab.
+
+## How
+
+The idea of this implementation path is not to take the fastest route to
+the feature with the most value added (cross-instance merge requests), but
+to go on with the smallest useful step at each iteration, making sure each step
+brings something immediately.
+
+1. **Implement ActivityPub for social following**.
+ After this, the Fediverse can follow activities on GitLab instances.
+ 1. ActivityPub to subscribe to project releases.
+ 1. ActivityPub to subscribe to project creation in topics.
+ 1. ActivityPub to subscribe to project activities.
+ 1. ActivityPub to subscribe to group activities.
+ 1. ActivityPub to subscribe to user activities.
+1. **Implement cross-instance search** to enable discovering projects on other instances.
+1. **Implement cross-instance forks** to enable forking a project from an other instance.
+1. **Implement ActivityPub for cross-instance discussions** to enable discussing
+ issues and merge requests from another instance:
+ 1. In issues.
+ 1. In merge requests.
+1. **Implement ActivityPub to submit cross-instance merge requests** to enable
+ submitting merge requests to other instances.
+
+For now, see [how to implement an ActivityPub actor](actors/index.md).
diff --git a/doc/development/adding_service_component.md b/doc/development/adding_service_component.md
index 6e47d2991dc..3ce303d429a 100644
--- a/doc/development/adding_service_component.md
+++ b/doc/development/adding_service_component.md
@@ -23,7 +23,7 @@ The following outline re-uses the [maturity metric](https://about.gitlab.com/dir
- [Release management](#release-management)
- [Enabled on GitLab.com](feature_flags/controls.md#enabling-a-feature-for-gitlabcom)
- Complete
- - [Configurable by the GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit)
+ - [Validated by the Reference Architecture group and scaled out recommendations made](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/self-managed-excellence/#reference-architectures)
- Lovable
- Enabled by default for the majority of users
diff --git a/doc/development/ai_architecture.md b/doc/development/ai_architecture.md
index 84a2635b13c..28483b943d1 100644
--- a/doc/development/ai_architecture.md
+++ b/doc/development/ai_architecture.md
@@ -11,7 +11,7 @@ GitLab has created a common set of tools to support our product groups and their
1. Increase the velocity of feature teams by providing a set of high quality, ready to use tools
1. Ability to switch underlying technologies quickly and easily
-AI is moving very quickly, and we need to be able to keep pace with changes in the area. We have built an [abstraction layer](../../ee/development/ai_features.md) to do this, allowing us to take a more "pluggable" approach to the underlying models, data stores, and other technologies.
+AI is moving very quickly, and we need to be able to keep pace with changes in the area. We have built an [abstraction layer](../../ee/development/ai_features/index.md) to do this, allowing us to take a more "pluggable" approach to the underlying models, data stores, and other technologies.
The following diagram from the [architecture blueprint](../architecture/blueprints/ai_gateway/index.md) shows a simplified view of how the different components in GitLab interact. The abstraction layer helps avoid code duplication within the REST APIs within the `AI API` block.
@@ -27,6 +27,25 @@ There are two primary reasons for this: the best AI models are cloud-based as th
The AI Gateway (formerly the [model gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist)) is a standalone-service that will give access to AI features to all users of GitLab, no matter which instance they are using: self-managed, dedicated or GitLab.com. The SaaS-based AI abstraction layer will transition to connecting to this gateway, rather than accessing cloud-based providers directly.
+Calls to the AI-gateway from GitLab-rails can be made using the
+[Abstraction Layer](ai_features/index.md#abstraction-layer).
+By default, these actions are performed asynchronously via a Sidekiq
+job to prevent long-running requests in Puma. It should be used for
+non-latency sensitive actions due to the added latency by Sidekiq.
+
+At the time of writing, the Abstraction Layer still directly calls the AI providers. This will be
+changed [in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/424614).
+
+When a certain action is latency sensitive, we can decide to call the
+AI-gateway directly. This avoids the latency added by Sidekiq.
+[We already do this for `code_suggestions`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/api/code_suggestions.rb)
+which get handled by API endpoints nested in
+`/api/v4/code_suggestions`. For any new endpoints added, we should
+nest them within the `/api/v4/ai_assisted` namespace. Doing this will
+automatically route the requests on GitLab.com to the `ai-assisted`
+fleet for GitLab.com, isolating the workload from the regular API and
+making it easier to scale if needed.
+
## Supported technologies
As part of the AI working group, we have been investigating various technologies and vetting them. Below is a list of the tools which have been reviewed and already approved for use within the GitLab application.
@@ -98,7 +117,7 @@ The following table documents functionality that Code Suggestions offers today,
#### Code Suggestions Latency
-Code Suggestions acceptance rates are _highly_ sensitive to latency. While writing code with an AI assistant, a user will pause only for a short duration before continuing on with manually typing out a block of code. As soon as the user has pressed a subsequent keypress, the existing suggestion will be invalidated and a new request will need to be issued to the code suggestions endpoint. In turn, this request will also be highly sensitive to latency.
+Code Suggestions acceptance rates are _highly_ sensitive to latency. While writing code with an AI assistant, a user will pause only for a short duration before continuing on with manually typing out a block of code. As soon as the user has pressed a subsequent keypress, the existing suggestion will be invalidated and a new request will need to be issued to the Code Suggestions endpoint. In turn, this request will also be highly sensitive to latency.
In a worst case with sufficient latency, the IDE could be issuing a string of requests, each of which is then ignored as the user proceeds without waiting for the response. This adds no value for the user, while still putting load on our services.
diff --git a/doc/development/ai_features.md b/doc/development/ai_features.md
index ffe151f3876..a952d8f2804 100644
--- a/doc/development/ai_features.md
+++ b/doc/development/ai_features.md
@@ -1,659 +1,11 @@
---
-stage: AI-powered
-group: AI Framework
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+redirect_to: 'ai_features/index.md'
+remove_date: '2023-12-01'
---
-# AI features based on 3rd-party integrations
+This document was moved to [another location](ai_features/index.md).
-[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117296) in GitLab 15.11.
-
-## Features
-
-- Async execution of the long running API requests
- - GraphQL Action starts the request
- - Background workers execute
- - GraphQL subscriptions deliver results back in real time
-- Abstraction for
- - OpenAI
- - Google Vertex AI
- - Anthropic
-- Rate Limiting
-- Circuit Breaker
-- Multi-Level feature flags
-- License checks on group level
-- Snowplow execution tracking
-- Tracking of Token Spent on Prometheus
-- Configuration for Moderation check of inputs
-- Automatic Markdown Rendering of responses
-- Centralised Group Level settings for experiment and 3rd party
-- Experimental API endpoints for exploration of AI APIs by GitLab team members without the need for credentials
- - OpenAI
- - Google Vertex AI
- - Anthropic
-
-## Feature flags
-
-Apply the following two feature flags to any AI feature work:
-
-- A general that applies to all AI features.
-- A flag specific to that feature. The feature flag name [must be different](feature_flags/index.md#feature-flags-for-licensed-features) than the licensed feature name.
-
-See the [feature flag tracker](https://gitlab.com/gitlab-org/gitlab/-/issues/405161) for the list of all feature flags and how to use them.
-
-## Implement a new AI action
-
-To implement a new AI action, connect to the preferred AI provider. You can connect to this API using either the:
-
-- Experimental REST API.
-- Abstraction layer.
-
-All AI features are experimental.
-
-## Test AI features locally
-
-NOTE:
-Use [this snippet](https://gitlab.com/gitlab-org/gitlab/-/snippets/2554994) for help automating the following section.
-
-1. Enable the required general feature flags:
-
- ```ruby
- Feature.enable(:ai_related_settings)
- Feature.enable(:openai_experimentation)
- Feature.enable(:tofa_experimentation_main_flag)
- Feature.enable(:anthropic_experimentation)
- ```
-
-1. Simulate the GDK to [simulate SaaS](ee_features.md#simulate-a-saas-instance) and ensure the group you want to test has an Ultimate license
-1. Enable `Experimental features` and `Third-party AI services`
- 1. Go to the group with the Ultimate license
- 1. **Group Settings** > **General** -> **Permissions and group features**
- 1. Enable **Experiment features**
- 1. Enable **Third-party AI services**
-1. Enable the specific feature flag for the feature you want to test
-1. Set the required access token. To receive an access token:
- 1. For Vertex, follow the [instructions below](#configure-gcp-vertex-access).
- 1. For all other providers, like Anthropic or OpenAI, create an access request where `@m_gill`, `@wayne`, and `@timzallmann` are the tech stack owners.
-
-### Set up the embedding database
-
-NOTE:
-Use [this snippet](https://gitlab.com/gitlab-org/gitlab/-/snippets/2554994) for help automating the following section.
-
-For features that use the embedding database, additional setup is needed.
-
-1. Enable [pgvector](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/pgvector.md#enable-pgvector-in-the-gdk) in GDK
-1. Enable the embedding database in GDK
-
- ```shell
- gdk config set gitlab.rails.databases.embedding.enabled true
- ```
-
-1. Run `gdk reconfigure`
-1. Run database migrations to create the embedding database
-
-### Set up GitLab Duo Chat
-
-NOTE:
-Use [this snippet](https://gitlab.com/gitlab-org/gitlab/-/snippets/2554994) for help automating the following section.
-
-1. [Enable Anthropic API features](#configure-anthropic-access).
-1. [Enable OpenAI support](#configure-openai-access).
-1. [Ensure the embedding database is configured](#set-up-the-embedding-database).
-1. Enable feature specific feature flag.
-
- ```ruby
- Feature.enable(:gitlab_duo)
- Feature.enable(:tanuki_bot)
- Feature.enable(:ai_redis_cache)
- ```
-
-1. Ensure that your current branch is up-to-date with `master`.
-1. To access the GitLab Duo Chat interface, in the lower-left corner of any page, select **Help** and **Ask GitLab Duo Chat**.
-
-#### Tips for local development
-
-1. When responses are taking too long to appear in the user interface, consider restarting Sidekiq by running `gdk restart rails-background-jobs`. If that doesn't work, try `gdk kill` and then `gdk start`.
-1. Alternatively, bypass Sidekiq entirely and run the chat service synchronously. This can help with debugging errors as GraphQL errors are now available in the network inspector instead of the Sidekiq logs.
-
-```diff
-diff --git a/ee/app/services/llm/chat_service.rb b/ee/app/services/llm/chat_service.rb
-index 5fa7ae8a2bc1..5fe996ba0345 100644
---- a/ee/app/services/llm/chat_service.rb
-+++ b/ee/app/services/llm/chat_service.rb
-@@ -5,7 +5,7 @@ class ChatService < BaseService
- private
-
- def perform
-- worker_perform(user, resource, :chat, options)
-+ worker_perform(user, resource, :chat, options.merge(sync: true))
- end
-
- def valid?
-```
-
-### Working with GitLab Duo Chat
-
-Prompts are the most vital part of GitLab Duo Chat system. Prompts are the instructions sent to the Large Language Model to perform certain tasks.
-
-The state of the prompts is the result of weeks of iteration. If you want to change any prompt in the current tool, you must put it behind a feature flag.
-
-If you have any new or updated prompts, ask members of AI Framework team to review, because they have significant experience with them.
-
-### Setup for GitLab documentation chat (legacy chat)
-
-To populate the embedding database for GitLab chat:
-
-1. Open a rails console
-1. Run [this script](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/10588#note_1373586079) to populate the embedding database
-
-### Contributing to GitLab Duo Chat
-
-The Chat feature uses a [zero-shot agent](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/gitlab/llm/chain/agents/zero_shot/executor.rb) that includes a system prompt explaining how the large language model should interpret the question and provide an
-answer. The system prompt defines available tools that can be used to gather
-information to answer the user's question.
-
-The zero-shot agent receives the user's question and decides which tools to use to gather information to answer it.
-It then makes a request to the large language model, which decides if it can answer directly or if it needs to use one
-of the defined tools.
-
-The tools each have their own prompt that provides instructions to the large language model on how to use that tool to
-gather information. The tools are designed to be self-sufficient and avoid multiple requests back and forth to
-the large language model.
-
-After the tools have gathered the required information, it is returned to the zero-shot agent, which asks the large language
-model if enough information has been gathered to provide the final answer to the user's question.
-
-#### Adding a new tool
-
-To add a new tool:
-
-1. Create files for the tool in the `ee/lib/gitlab/llm/chain/tools/` folder. Use existing tools like `issue_identifier` or
-`resource_reader` as a template.
-
-1. Write a class for the tool that includes:
-
- - Name and description of what the tool does
- - Example questions that would use this tool
- - Instructions for the large language model on how to use the tool to gather information - so the main prompts that
- this tool is using.
-
-1. Test and iterate on the prompt using RSpec tests that make real requests to the large language model.
- - Prompts require trial and error, the non-deterministic nature of working with LLM can be surprising.
- - Anthropic provides good [guide](https://docs.anthropic.com/claude/docs/introduction-to-prompt-design) on working on prompts.
-
-1. Implement code in the tool to parse the response from the large language model and return it to the zero-shot agent.
-
-1. Add the new tool name to the `tools` array in `ee/lib/gitlab/llm/completions/chat.rb` so the zero-shot agent knows about it.
-
-1. Add tests by adding questions to the test-suite for which the new tool should respond to. Iterate on the prompts as needed.
-
-The key things to keep in mind are properly instructing the large language model through prompts and tool descriptions,
-keeping tools self-sufficient, and returning responses to the zero-shot agent. With some trial and error on prompts,
-adding new tools can expand the capabilities of the chat feature.
-
-There are available short [videos](https://www.youtube.com/playlist?list=PL05JrBw4t0KoOK-bm_bwfHaOv-1cveh8i) covering this topic.
-
-### Debugging
-
-To gather more insights about the full request, use the `Gitlab::Llm::Logger` file to debug logs.
-The default logging level on production is `INFO` and **must not** be used to log any data that could contain personal identifying information.
-
-To follow the debugging messages related to the AI requests on the abstraction layer, you can use:
-
-```shell
-export LLM_DEBUG=1
-gdk start
-tail -f log/llm.log
-```
-
-### Configure GCP Vertex access
-
-In order to obtain a GCP service key for local development, please follow the steps below:
-
-- Create a sandbox GCP environment by visiting [this page](https://about.gitlab.com/handbook/infrastructure-standards/#individual-environment) and following the instructions, or by requesting access to our existing group environment by using [this template](https://gitlab.com/gitlab-com/it/infra/issue-tracker/-/issues/new?issuable_template=gcp_group_account_iam_update_request).
-- In the GCP console, go to `IAM & Admin` > `Service Accounts` and click on the "Create new service account" button
-- Name the service account something specific to what you're using it for. Select Create and Continue. Under `Grant this service account access to project`, select the role `Vertex AI User`. Select `Continue` then `Done`
-- Select your new service account and `Manage keys` > `Add Key` > `Create new key`. This will download the **private** JSON credentials for your service account.
-- Open the Rails console. Update the settings to:
-
-```ruby
-Gitlab::CurrentSettings.update(vertex_ai_credentials: File.read('/YOUR_FILE.json'))
-
-# Note: These credential examples will not work locally for all models
-Gitlab::CurrentSettings.update(vertex_ai_host: "<root-domain>") # Example: us-central1-aiplatform.googleapis.com
-Gitlab::CurrentSettings.update(vertex_ai_project: "<project-id>") # Example: cloud-large-language-models
-```
-
-Internal team members can [use this snippet](https://gitlab.com/gitlab-com/gl-infra/production/-/snippets/2541742) for help configuring these endpoints.
-
-### Configure OpenAI access
-
-```ruby
-Gitlab::CurrentSettings.update(openai_api_key: "<open-ai-key>")
-```
-
-### Configure Anthropic access
-
-```ruby
-Feature.enable(:anthropic_experimentation)
-Gitlab::CurrentSettings.update!(anthropic_api_key: <insert API key>)
-```
-
-### Testing GitLab Duo Chat with predefined questions
-
-Because success of answers to user questions in GitLab Duo Chat heavily depends on toolchain and prompts of each tool, it's common that even a minor change in a prompt or a tool impacts processing of some questions. To make sure that a change in the toolchain doesn't break existing functionality, you can use the following rspecs to validate answers to some predefined questions:
-
-```ruby
-export OPENAI_API_KEY='<key>'
-export ANTHROPIC_API_KEY='<key>'
-REAL_AI_REQUEST=1 rspec ee/spec/lib/gitlab/llm/chain/agents/zero_shot/executor_spec.rb
-```
-
-When you need to update the test questions that require documentation embeddings,
-make sure a new fixture is generated and committed together with the change.
-
-#### Populating embeddings and using embeddings fixture
-
-To seed your development database with the embeddings for GitLab Documentation,
-you may use the pre-generated embeddings and a Rake test.
-
-```shell
-RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:seed_pre_generated
-```
-
-The DBCleaner gem we use clear the database tables before each test runs.
-Instead of fully populating the table `tanuki_bot_mvc` where we store embeddings for the documentations,
-we can add a few selected embeddings to the table from a pre-generated fixture.
-
-For instance, to test that the question "How can I reset my password" is correctly
-retrieving the relevant embeddings and answered, we can extract the top N closet embeddings
-to the question into a fixture and only restore a small number of embeddings quickly.
-To faciliate an extraction process, a Rake task been written.
-You can add or remove the questions needed to be tested in the Rake task and run the task to generate a new fixture.
-
-```shell
-RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:extract_embeddings
-```
-
-In the specs where you need to use the embeddings,
-use the RSpec config hook `:ai_embedding_fixtures` on a context.
-
-```ruby
-context 'when asking about how to use GitLab', :ai_embedding_fixtures do
- # ...examples
-end
-```
-
-## Experimental REST API
-
-Use the [experimental REST API endpoints](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/api/ai/experimentation) to quickly experiment and prototype AI features.
-
-The endpoints are:
-
-- `https://gitlab.example.com/api/v4/ai/experimentation/openai/completions`
-- `https://gitlab.example.com/api/v4/ai/experimentation/openai/embeddings`
-- `https://gitlab.example.com/api/v4/ai/experimentation/openai/chat/completions`
-- `https://gitlab.example.com/api/v4/ai/experimentation/anthropic/complete`
-- `https://gitlab.example.com/api/v4/ai/experimentation/tofa/chat`
-
-These endpoints are only for prototyping, not for rolling features out to customers.
-The experimental endpoint is only available to GitLab team members on production. Use the
-[GitLab API token](../user/profile/personal_access_tokens.md) to authenticate.
-
-## Abstraction layer
-
-### GraphQL API
-
-To connect to the AI provider API using the Abstraction Layer, use an extendable GraphQL API called
-[`aiAction`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/graphql/mutations/ai/action.rb).
-The `input` accepts key/value pairs, where the `key` is the action that needs to be performed.
-We only allow one AI action per mutation request.
-
-Example of a mutation:
-
-```graphql
-mutation {
- aiAction(input: {summarizeComments: {resourceId: "gid://gitlab/Issue/52"}}) {
- clientMutationId
- }
-}
-```
-
-As an example, assume we want to build an "explain code" action. To do this, we extend the `input` with a new key,
-`explainCode`. The mutation would look like this:
-
-```graphql
-mutation {
- aiAction(input: {explainCode: {resourceId: "gid://gitlab/MergeRequest/52", code: "foo() { console.log()" }}) {
- clientMutationId
- }
-}
-```
-
-The GraphQL API then uses the [OpenAI Client](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/gitlab/llm/open_ai/client.rb)
-to send the response.
-
-Remember that other clients are available and you should not use OpenAI.
-
-#### How to receive a response
-
-As the OpenAI API requests are handled in a background job, we do not keep the request alive and
-the response is sent through the `aiCompletionResponse` subscription:
-
-```mutation
-subscription aiCompletionResponse($userId: UserID, $resourceId: AiModelID!) {
- aiCompletionResponse(userId: $userId, resourceId: $resourceId) {
- responseBody
- errors
- }
-}
-```
-
-WARNING:
-You should only subscribe to the subscription once the mutation is sent. If multiple subscriptions are active on the same page, they currently all receive updates as our identifier is the user and the resource. To mitigate this, you should only subscribe when the mutation is sent. You can use [`skip()`](You can use [`skip()`](https://apollo.vuejs.org/guide/apollo/subscriptions.html#skipping-the-subscription)) for this case. To prevent this problem in the future, we implement a [request identifier](https://gitlab.com/gitlab-org/gitlab/-/issues/408196).
-
-#### Current abstraction layer flow
-
-The following graph uses OpenAI as an example. You can use different providers.
-
-```mermaid
-flowchart TD
-A[GitLab frontend] -->B[AiAction GraphQL mutation]
-B --> C[Llm::ExecuteMethodService]
-C --> D[One of services, for example: Llm::GenerateSummaryService]
-D -->|scheduled| E[AI worker:Llm::CompletionWorker]
-E -->F[::Gitlab::Llm::Completions::Factory]
-F -->G[`::Gitlab::Llm::OpenAi::Completions::...` class using `::Gitlab::Llm::OpenAi::Templates::...` class]
-G -->|calling| H[Gitlab::Llm::OpenAi::Client]
-H --> |response| I[::Gitlab::Llm::OpenAi::ResponseService]
-I --> J[GraphqlTriggers.ai_completion_response]
-J --> K[::GitlabSchema.subscriptions.trigger]
-```
-
-## CircuitBreaker
-
-The CircuitBreaker concern is a reusable module that you can include in any class that needs to run code with circuit breaker protection. The concern provides a `run_with_circuit` method that wraps a code block with circuit breaker functionality, which helps prevent cascading failures and improves system resilience. For more information about the circuit breaker pattern, see:
-
-- [What is Circuit breaker](https://martinfowler.com/bliki/CircuitBreaker.html).
-- [The Hystrix documentation on CircuitBreaker](https://github.com/Netflix/Hystrix/wiki/How-it-Works#circuit-breaker).
-
-### Use CircuitBreaker
-
-To use the CircuitBreaker concern, you need to include it in a class. For example:
-
-```ruby
-class MyService
- include Gitlab::Llm::Concerns::CircuitBreaker
-
- def call_external_service
- run_with_circuit do
- # Code that interacts with external service goes here
-
- raise InternalServerError
- end
- end
-end
-```
-
-The `call_external_service` method is an example method that interacts with an external service.
-By wrapping the code that interacts with the external service with `run_with_circuit`, the method is executed within the circuit breaker.
-The circuit breaker is created and configured by the `circuit` method, which is called automatically when the `CircuitBreaker` module is included.
-The method should raise `InternalServerError` error which will be counted towards the error threshold if raised during the execution of the code block.
-
-The circuit breaker tracks the number of errors and the rate of requests,
-and opens the circuit if it reaches the configured error threshold or volume threshold.
-If the circuit is open, subsequent requests fail fast without executing the code block, and the circuit breaker periodically allows a small number of requests through to test the service's availability before closing the circuit again.
-
-### Configuration
-
-The circuit breaker is configured with two constants which control the number of errors and requests at which the circuit will open:
-
-- `ERROR_THRESHOLD`
-- `VOLUME_THRESHOLD`
-
-You can adjust these values as needed for the specific service and usage pattern.
-The `InternalServerError` is the exception class counted towards the error threshold if raised during the execution of the code block.
-This is the exception class that triggers the circuit breaker when raised by the code that interacts with the external service.
-
-NOTE:
-The `CircuitBreaker` module depends on the `Circuitbox` gem to provide the circuit breaker implementation. By default, the service name is inferred from the class name where the concern module is included. Override the `service_name` method if the name needs to be different.
-
-### Testing
-
-To test code that uses the `CircuitBreaker` concern, you can use `RSpec` shared examples and pass the `service` and `subject` variables:
-
-```ruby
-it_behaves_like 'has circuit breaker' do
- let(:service) { dummy_class.new }
- let(:subject) { service.dummy_method }
-end
-```
-
-## How to implement a new action
-
-### Register a new method
-
-Go to the `Llm::ExecuteMethodService` and add a new method with the new service class you will create.
-
-```ruby
-class ExecuteMethodService < BaseService
- METHODS = {
- # ...
- amazing_new_ai_feature: Llm::AmazingNewAiFeatureService
- }.freeze
-```
-
-### Create a Service
-
-1. Create a new service under `ee/app/services/llm/` and inherit it from the `BaseService`.
-1. The `resource` is the object we want to act on. It can be any object that includes the `Ai::Model` concern. For example it could be a `Project`, `MergeRequest`, or `Issue`.
-
-```ruby
-# ee/app/services/llm/amazing_new_ai_feature_service.rb
-
-module Llm
- class AmazingNewAiFeatureService < BaseService
- private
-
- def perform
- ::Llm::CompletionWorker.perform_async(user.id, resource.id, resource.class.name, :amazing_new_ai_feature)
- success
- end
-
- def valid?
- super && Ability.allowed?(user, :amazing_new_ai_feature, resource)
- end
- end
-end
-```
-
-### Authorization
-
-We recommend to use [policies](policies.md) to deal with authorization for a feature. Currently we need to make sure to cover the following checks:
-
-1. General AI feature flag is enabled
-1. Feature specific feature flag is enabled
-1. The namespace has the required license for the feature
-1. User is a member of the group/project
-1. `experiment_features_enabled` and `third_party_ai_features_enabled` flags are set on the `Namespace`
-
-For our example, we need to implement the `allowed?(:amazing_new_ai_feature)` call. As an example, you can look at the [Issue Policy for the summarize comments feature](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/policies/ee/issue_policy.rb). In our example case, we want to implement the feature for Issues as well:
-
-```ruby
-# ee/app/policies/ee/issue_policy.rb
-
-module EE
- module IssuePolicy
- extend ActiveSupport::Concern
- prepended do
- with_scope :subject
- condition(:ai_available) do
- ::Feature.enabled?(:openai_experimentation)
- end
-
- with_scope :subject
- condition(:amazing_new_ai_feature_enabled) do
- ::Feature.enabled?(:amazing_new_ai_feature, subject_container) &&
- subject_container.licensed_feature_available?(:amazing_new_ai_feature)
- end
-
- rule do
- ai_available & amazing_new_ai_feature_enabled & is_project_member
- end.enable :amazing_new_ai_feature
- end
- end
-end
-```
-
-### Pairing requests with responses
-
-Because multiple users' requests can be processed in parallel, when receiving responses,
-it can be difficult to pair a response with its original request. The `requestId`
-field can be used for this purpose, because both the request and response are assured
-to have the same `requestId` UUID.
-
-### Caching
-
-AI requests and responses can be cached. Cached conversation is being used to
-display user interaction with AI features. In the current implementation, this cache
-is not used to skip consecutive calls to the AI service when a user repeats
-their requests.
-
-```graphql
-query {
- aiMessages {
- nodes {
- id
- requestId
- content
- role
- errors
- timestamp
- }
- }
-}
-```
-
-This cache is especially useful for chat functionality. For other services,
-caching is disabled. (It can be enabled for a service by using `cache_response: true`
-option.)
-
-Caching has following limitations:
-
-- Messages are stored in Redis stream.
-- There is a single stream of messages per user. This means that all services
- currently share the same cache. If needed, this could be extended to multiple
- streams per user (after checking with the infrastructure team that Redis can handle
- the estimated amount of messages).
-- Only the last 50 messages (requests + responses) are kept.
-- Expiration time of the stream is 3 days since adding last message.
-- User can access only their own messages. There is no authorization on the caching
- level, and any authorization (if accessed by not current user) is expected on
- the service layer.
-
-### Check if feature is allowed for this resource based on namespace settings
-
-There are two settings allowed on root namespace level that restrict the use of AI features:
-
-- `experiment_features_enabled`
-- `third_party_ai_features_enabled`.
-
-To check if that feature is allowed for a given namespace, call:
-
-```ruby
-Gitlab::Llm::StageCheck.available?(namespace, :name_of_the_feature)
-```
-
-Add the name of the feature to the `Gitlab::Llm::StageCheck` class. There are arrays there that differentiate
-between experimental and beta features.
-
-This way we are ready for the following different cases:
-
-- If the feature is not in any array, the check will return `true`. For example, the feature was moved to GA and does not use a third-party setting.
-- If feature is in GA, but uses a third-party setting, the class will return a proper answer based on the namespace third-party setting.
-
-To move the feature from the experimental phase to the beta phase, move the name of the feature from the `EXPERIMENTAL_FEATURES` array to the `BETA_FEATURES` array.
-
-### Implement calls to AI APIs and the prompts
-
-The `CompletionWorker` will call the `Completions::Factory` which will initialize the Service and execute the actual call to the API.
-In our example, we will use OpenAI and implement two new classes:
-
-```ruby
-# /ee/lib/gitlab/llm/open_ai/completions/amazing_new_ai_feature.rb
-
-module Gitlab
- module Llm
- module OpenAi
- module Completions
- class AmazingNewAiFeature
- def initialize(ai_prompt_class)
- @ai_prompt_class = ai_prompt_class
- end
-
- def execute(user, issue, options)
- options = ai_prompt_class.get_options(options[:messages])
-
- ai_response = Gitlab::Llm::OpenAi::Client.new(user).chat(content: nil, **options)
-
- ::Gitlab::Llm::OpenAi::ResponseService.new(user, issue, ai_response, options: {}).execute(
- Gitlab::Llm::OpenAi::ResponseModifiers::Chat.new
- )
- end
-
- private
-
- attr_reader :ai_prompt_class
- end
- end
- end
- end
-end
-```
-
-```ruby
-# /ee/lib/gitlab/llm/open_ai/templates/amazing_new_ai_feature.rb
-
-module Gitlab
- module Llm
- module OpenAi
- module Templates
- class AmazingNewAiFeature
- TEMPERATURE = 0.3
-
- def self.get_options(messages)
- system_content = <<-TEMPLATE
- You are an assistant that writes code for the following input:
- """
- TEMPLATE
-
- {
- messages: [
- { role: "system", content: system_content },
- { role: "user", content: messages },
- ],
- temperature: TEMPERATURE
- }
- end
- end
- end
- end
- end
-end
-```
-
-Because we support multiple AI providers, you may also use those providers for the same example:
-
-```ruby
-Gitlab::Llm::VertexAi::Client.new(user)
-Gitlab::Llm::Anthropic::Client.new(user)
-```
-
-### Add Ai Action to GraphQL
-
-TODO
-
-## Security
-
-Refer to the [secure coding guidelines for Artificial Intelligence (AI) features](secure_coding_guidelines.md#artificial-intelligence-ai-features).
+<!-- This redirect file can be deleted after <2023-12-01>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/development/ai_features/duo_chat.md b/doc/development/ai_features/duo_chat.md
new file mode 100644
index 00000000000..5c7359eca9f
--- /dev/null
+++ b/doc/development/ai_features/duo_chat.md
@@ -0,0 +1,139 @@
+---
+stage: AI-powered
+group: Duo Chat
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# GitLab Duo Chat
+
+## Set up GitLab Duo Chat
+
+NOTE:
+Use [this snippet](https://gitlab.com/gitlab-org/gitlab/-/snippets/2554994) for help automating the following section.
+
+1. [Enable Anthropic API features](index.md#configure-anthropic-access).
+1. [Enable OpenAI support](index.md#configure-openai-access).
+1. [Ensure the embedding database is configured](index.md#set-up-the-embedding-database).
+1. Enable feature specific feature flag.
+
+ ```ruby
+ Feature.enable(:gitlab_duo)
+ Feature.enable(:tanuki_bot)
+ Feature.enable(:ai_redis_cache)
+ ```
+
+1. Ensure that your current branch is up-to-date with `master`.
+1. To access the GitLab Duo Chat interface, in the lower-left corner of any page, select **Help** and **Ask GitLab Duo Chat**.
+
+### Tips for local development
+
+1. When responses are taking too long to appear in the user interface, consider restarting Sidekiq by running `gdk restart rails-background-jobs`. If that doesn't work, try `gdk kill` and then `gdk start`.
+1. Alternatively, bypass Sidekiq entirely and run the chat service synchronously. This can help with debugging errors as GraphQL errors are now available in the network inspector instead of the Sidekiq logs.
+
+```diff
+diff --git a/ee/app/services/llm/chat_service.rb b/ee/app/services/llm/chat_service.rb
+index 5fa7ae8a2bc1..5fe996ba0345 100644
+--- a/ee/app/services/llm/chat_service.rb
++++ b/ee/app/services/llm/chat_service.rb
+@@ -5,7 +5,7 @@ class ChatService < BaseService
+ private
+
+ def perform
+- worker_perform(user, resource, :chat, options)
++ worker_perform(user, resource, :chat, options.merge(sync: true))
+ end
+
+ def valid?
+```
+
+## Working with GitLab Duo Chat
+
+Prompts are the most vital part of GitLab Duo Chat system. Prompts are the instructions sent to the Large Language Model to perform certain tasks.
+
+The state of the prompts is the result of weeks of iteration. If you want to change any prompt in the current tool, you must put it behind a feature flag.
+
+If you have any new or updated prompts, ask members of AI Framework team to review, because they have significant experience with them.
+
+## Contributing to GitLab Duo Chat
+
+The Chat feature uses a [zero-shot agent](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/gitlab/llm/chain/agents/zero_shot/executor.rb) that includes a system prompt explaining how the large language model should interpret the question and provide an
+answer. The system prompt defines available tools that can be used to gather
+information to answer the user's question.
+
+The zero-shot agent receives the user's question and decides which tools to use to gather information to answer it.
+It then makes a request to the large language model, which decides if it can answer directly or if it needs to use one
+of the defined tools.
+
+The tools each have their own prompt that provides instructions to the large language model on how to use that tool to
+gather information. The tools are designed to be self-sufficient and avoid multiple requests back and forth to
+the large language model.
+
+After the tools have gathered the required information, it is returned to the zero-shot agent, which asks the large language
+model if enough information has been gathered to provide the final answer to the user's question.
+
+### Adding a new tool
+
+To add a new tool:
+
+1. Create files for the tool in the `ee/lib/gitlab/llm/chain/tools/` folder. Use existing tools like `issue_identifier` or
+ `resource_reader` as a template.
+
+1. Write a class for the tool that includes:
+
+ - Name and description of what the tool does
+ - Example questions that would use this tool
+ - Instructions for the large language model on how to use the tool to gather information - so the main prompts that
+ this tool is using.
+
+1. Test and iterate on the prompt using RSpec tests that make real requests to the large language model.
+ - Prompts require trial and error, the non-deterministic nature of working with LLM can be surprising.
+ - Anthropic provides good [guide](https://docs.anthropic.com/claude/docs/introduction-to-prompt-design) on working on prompts.
+ - GitLab [guide](prompts.md) on working with prompts.
+
+1. Implement code in the tool to parse the response from the large language model and return it to the zero-shot agent.
+
+1. Add the new tool name to the `tools` array in `ee/lib/gitlab/llm/completions/chat.rb` so the zero-shot agent knows about it.
+
+1. Add tests by adding questions to the test-suite for which the new tool should respond to. Iterate on the prompts as needed.
+
+The key things to keep in mind are properly instructing the large language model through prompts and tool descriptions,
+keeping tools self-sufficient, and returning responses to the zero-shot agent. With some trial and error on prompts,
+adding new tools can expand the capabilities of the Chat feature.
+
+There are available short [videos](https://www.youtube.com/playlist?list=PL05JrBw4t0KoOK-bm_bwfHaOv-1cveh8i) covering this topic.
+
+## Debugging
+
+To gather more insights about the full request, use the `Gitlab::Llm::Logger` file to debug logs.
+The default logging level on production is `INFO` and **must not** be used to log any data that could contain personal identifying information.
+
+To follow the debugging messages related to the AI requests on the abstraction layer, you can use:
+
+```shell
+export LLM_DEBUG=1
+gdk start
+tail -f log/llm.log
+```
+
+## Testing GitLab Duo Chat with predefined questions
+
+Because success of answers to user questions in GitLab Duo Chat heavily depends on toolchain and prompts of each tool, it's common that even a minor change in a prompt or a tool impacts processing of some questions. To make sure that a change in the toolchain doesn't break existing functionality, you can use the following rspecs to validate answers to some predefined questions:
+
+```ruby
+export OPENAI_API_KEY='<key>'
+export ANTHROPIC_API_KEY='<key>'
+REAL_AI_REQUEST=1 rspec ee/spec/lib/gitlab/llm/chain/agents/zero_shot/executor_spec.rb
+```
+
+When you need to update the test questions that require documentation embeddings,
+make sure a new fixture is generated and committed together with the change.
+
+## GraphQL Subscription
+
+The GraphQL Subscription for Chat behaves slightly different because it's user-centric. A user could have Chat open on multiple browser tabs, or also on their IDE.
+We therefore need to broadcast messages to multiple clients to keep them in sync. The `aiAction` mutation with the `chat` action behaves the following:
+
+1. All complete Chat messages (including messages from the user) are broadcasted with the `userId` and the `resourceId` from the mutation as identifier, ignoring the `clientSubscriptionId`.
+1. Chunks from streamed Chat messages are broadcasted with the `userId`, `resourceId`, and `clientSubscriptionId` as identifier.
+
+To truly sync messages between all clients of a user, we need to remove the `resourceId` as well, which will be fixed by [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/420296).
diff --git a/doc/development/ai_features/index.md b/doc/development/ai_features/index.md
new file mode 100644
index 00000000000..e1d3ae36570
--- /dev/null
+++ b/doc/development/ai_features/index.md
@@ -0,0 +1,577 @@
+---
+stage: AI-powered
+group: AI Framework
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# AI features based on 3rd-party integrations
+
+[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117296) in GitLab 15.11.
+
+## Features
+
+- Async execution of the long running API requests
+ - GraphQL Action starts the request
+ - Background workers execute
+ - GraphQL subscriptions deliver results back in real time
+- Abstraction for
+ - OpenAI
+ - Google Vertex AI
+ - Anthropic
+- Rate Limiting
+- Circuit Breaker
+- Multi-Level feature flags
+- License checks on group level
+- Snowplow execution tracking
+- Tracking of Token Spent on Prometheus
+- Configuration for Moderation check of inputs
+- Automatic Markdown Rendering of responses
+- Centralised Group Level settings for experiment and 3rd party
+- Experimental API endpoints for exploration of AI APIs by GitLab team members without the need for credentials
+ - OpenAI
+ - Google Vertex AI
+ - Anthropic
+
+## Feature flags
+
+Apply the following two feature flags to any AI feature work:
+
+- A general that applies to all AI features.
+- A flag specific to that feature. The feature flag name [must be different](../feature_flags/index.md#feature-flags-for-licensed-features) than the licensed feature name.
+
+See the [feature flag tracker](https://gitlab.com/gitlab-org/gitlab/-/issues/405161) for the list of all feature flags and how to use them.
+
+## Implement a new AI action
+
+To implement a new AI action, connect to the preferred AI provider. You can connect to this API using either the:
+
+- Experimental REST API.
+- Abstraction layer.
+
+All AI features are experimental.
+
+## Test AI features locally
+
+NOTE:
+Use [this snippet](https://gitlab.com/gitlab-org/gitlab/-/snippets/2554994) for help automating the following section.
+
+1. Enable the required general feature flags:
+
+ ```ruby
+ Feature.enable(:ai_related_settings)
+ Feature.enable(:openai_experimentation)
+ ```
+
+1. Simulate the GDK to [simulate SaaS](../ee_features.md#simulate-a-saas-instance) and ensure the group you want to test has an Ultimate license
+1. Enable `Experimental features` and `Third-party AI services`
+ 1. Go to the group with the Ultimate license
+ 1. **Group Settings** > **General** -> **Permissions and group features**
+ 1. Enable **Experiment features**
+ 1. Enable **Third-party AI services**
+1. Enable the specific feature flag for the feature you want to test
+1. Set the required access token. To receive an access token:
+ 1. For Vertex, follow the [instructions below](#configure-gcp-vertex-access).
+ 1. For all other providers, like Anthropic or OpenAI, create an access request where `@m_gill`, `@wayne`, and `@timzallmann` are the tech stack owners.
+
+### Set up the embedding database
+
+NOTE:
+Use [this snippet](https://gitlab.com/gitlab-org/gitlab/-/snippets/2554994) for help automating the following section.
+
+For features that use the embedding database, additional setup is needed.
+
+1. Enable [pgvector](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/pgvector.md#enable-pgvector-in-the-gdk) in GDK
+1. Enable the embedding database in GDK
+
+ ```shell
+ gdk config set gitlab.rails.databases.embedding.enabled true
+ ```
+
+1. Run `gdk reconfigure`
+1. Run database migrations to create the embedding database
+
+### Setup for GitLab documentation chat (legacy chat)
+
+To populate the embedding database for GitLab chat:
+
+1. Open a rails console
+1. Run [this script](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/10588#note_1373586079) to populate the embedding database
+
+### Configure GCP Vertex access
+
+In order to obtain a GCP service key for local development, please follow the steps below:
+
+- Create a sandbox GCP environment by visiting [this page](https://about.gitlab.com/handbook/infrastructure-standards/#individual-environment) and following the instructions, or by requesting access to our existing group environment by using [this template](https://gitlab.com/gitlab-com/it/infra/issue-tracker/-/issues/new?issuable_template=gcp_group_account_iam_update_request).
+- In the GCP console, go to `IAM & Admin` > `Service Accounts` and click on the "Create new service account" button
+- Name the service account something specific to what you're using it for. Select Create and Continue. Under `Grant this service account access to project`, select the role `Vertex AI User`. Select `Continue` then `Done`
+- Select your new service account and `Manage keys` > `Add Key` > `Create new key`. This will download the **private** JSON credentials for your service account.
+- If you are using your own project, you may also need to enable the Vertex AI API:
+ 1. Go to **APIs & Services > Enabled APIs & services**.
+ 1. Select **+ Enable APIs and Services**.
+ 1. Search for `Vertex AI API`.
+ 1. Select **Vertex AI API**, then select **Enable**.
+- Open the Rails console. Update the settings to:
+
+```ruby
+Gitlab::CurrentSettings.update(vertex_ai_credentials: File.read('/YOUR_FILE.json'))
+
+# Note: These credential examples will not work locally for all models
+Gitlab::CurrentSettings.update(vertex_ai_host: "<root-domain>") # Example: us-central1-aiplatform.googleapis.com
+Gitlab::CurrentSettings.update(vertex_ai_project: "<project-id>") # Example: cloud-large-language-models
+```
+
+Internal team members can [use this snippet](https://gitlab.com/gitlab-com/gl-infra/production/-/snippets/2541742) for help configuring these endpoints.
+
+### Configure OpenAI access
+
+```ruby
+Gitlab::CurrentSettings.update(openai_api_key: "<open-ai-key>")
+```
+
+### Configure Anthropic access
+
+```ruby
+Gitlab::CurrentSettings.update!(anthropic_api_key: <insert API key>)
+```
+
+#### Populating embeddings and using embeddings fixture
+
+To seed your development database with the embeddings for GitLab Documentation,
+you may use the pre-generated embeddings and a Rake test.
+
+```shell
+RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:seed_pre_generated
+```
+
+The DBCleaner gem we use clear the database tables before each test runs.
+Instead of fully populating the table `tanuki_bot_mvc` where we store embeddings for the documentations,
+we can add a few selected embeddings to the table from a pre-generated fixture.
+
+For instance, to test that the question "How can I reset my password" is correctly
+retrieving the relevant embeddings and answered, we can extract the top N closet embeddings
+to the question into a fixture and only restore a small number of embeddings quickly.
+To faciliate an extraction process, a Rake task been written.
+You can add or remove the questions needed to be tested in the Rake task and run the task to generate a new fixture.
+
+```shell
+RAILS_ENV=development bundle exec rake gitlab:llm:embeddings:extract_embeddings
+```
+
+In the specs where you need to use the embeddings,
+use the RSpec config hook `:ai_embedding_fixtures` on a context.
+
+```ruby
+context 'when asking about how to use GitLab', :ai_embedding_fixtures do
+ # ...examples
+end
+```
+
+### Working with GitLab Duo Chat
+
+View [guidelines](duo_chat.md) for working with GitLab Duo Chat.
+
+## Experimental REST API
+
+Use the [experimental REST API endpoints](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/api/ai/experimentation) to quickly experiment and prototype AI features.
+
+The endpoints are:
+
+- `https://gitlab.example.com/api/v4/ai/experimentation/openai/completions`
+- `https://gitlab.example.com/api/v4/ai/experimentation/openai/embeddings`
+- `https://gitlab.example.com/api/v4/ai/experimentation/openai/chat/completions`
+- `https://gitlab.example.com/api/v4/ai/experimentation/anthropic/complete`
+- `https://gitlab.example.com/api/v4/ai/experimentation/vertex/chat`
+
+These endpoints are only for prototyping, not for rolling features out to customers.
+
+In your local dev environment, you can experiment with these endpoints locally with the feature flag enabled:
+
+```ruby
+Feature.enable(:ai_experimentation_api)
+```
+
+On production, the experimental endpoints are only available to GitLab team members. Use a
+[GitLab API token](../../user/profile/personal_access_tokens.md) to authenticate.
+
+## Abstraction layer
+
+### GraphQL API
+
+To connect to the AI provider API using the Abstraction Layer, use an extendable GraphQL API called
+[`aiAction`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/graphql/mutations/ai/action.rb).
+The `input` accepts key/value pairs, where the `key` is the action that needs to be performed.
+We only allow one AI action per mutation request.
+
+Example of a mutation:
+
+```graphql
+mutation {
+ aiAction(input: {summarizeComments: {resourceId: "gid://gitlab/Issue/52"}}) {
+ clientMutationId
+ }
+}
+```
+
+As an example, assume we want to build an "explain code" action. To do this, we extend the `input` with a new key,
+`explainCode`. The mutation would look like this:
+
+```graphql
+mutation {
+ aiAction(input: {explainCode: {resourceId: "gid://gitlab/MergeRequest/52", code: "foo() { console.log()" }}) {
+ clientMutationId
+ }
+}
+```
+
+The GraphQL API then uses the [OpenAI Client](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/gitlab/llm/open_ai/client.rb)
+to send the response.
+
+Remember that other clients are available and you should not use OpenAI.
+
+#### How to receive a response
+
+The API requests to AI providers are handled in a background job. We therefore do not keep the request alive and the Frontend needs to match the request to the response from the subscription.
+
+WARNING:
+Determining the right response to a request can cause problems when only `userId` and `resourceId` are used. For example, when two AI features use the same `userId` and `resourceId` both subscriptions will receive the response from each other. To prevent this intereference, we introduced the `clientSubscriptionId`.
+
+To match a response on the `aiCompletionResponse` subscription, you can provide a `clientSubscriptionId` to the `aiAction` mutation.
+
+- The `clientSubscriptionId` should be unique per feature and within a page to not interfere with other AI features. We recommend to use a `UUID`.
+- Only when the `clientSubscriptionId` is provided as part of the `aiAction` mutation, it will be used for broadcasting the `aiCompletionResponse`.
+- If the `clientSubscriptionId` is not provided, only `userId` and `resourceId` are used for the `aiCompletionResponse`.
+
+As an example mutation for summarizing comments, we provide a `randomId` as part of the mutation:
+
+```graphql
+mutation {
+ aiAction(input: {summarizeComments: {resourceId: "gid://gitlab/Issue/52"}, clientSubscriptionId: "randomId"}) {
+ clientMutationId
+ }
+}
+```
+
+In our component, we then listen on the `aiCompletionResponse` using the `userId`, `resourceId` and `clientSubscriptionId` (`"randomId"`):
+
+```graphql
+subscription aiCompletionResponse($userId: UserID, $resourceId: AiModelID, $clientSubscriptionId: String) {
+ aiCompletionResponse(userId: $userId, resourceId: $resourceId, clientSubscriptionId: $clientSubscriptionId) {
+ content
+ errors
+ }
+}
+```
+
+Note that the [subscription for chat](duo_chat.md#graphql-subscription) behaves differently.
+
+To not have many concurrent subscriptions, you should also only subscribe to the subscription once the mutation is sent by using [`skip()`](https://apollo.vuejs.org/guide/apollo/subscriptions.html#skipping-the-subscription).
+
+#### Current abstraction layer flow
+
+The following graph uses OpenAI as an example. You can use different providers.
+
+```mermaid
+flowchart TD
+A[GitLab frontend] -->B[AiAction GraphQL mutation]
+B --> C[Llm::ExecuteMethodService]
+C --> D[One of services, for example: Llm::GenerateSummaryService]
+D -->|scheduled| E[AI worker:Llm::CompletionWorker]
+E -->F[::Gitlab::Llm::Completions::Factory]
+F -->G[`::Gitlab::Llm::OpenAi::Completions::...` class using `::Gitlab::Llm::OpenAi::Templates::...` class]
+G -->|calling| H[Gitlab::Llm::OpenAi::Client]
+H --> |response| I[::Gitlab::Llm::OpenAi::ResponseService]
+I --> J[GraphqlTriggers.ai_completion_response]
+J --> K[::GitlabSchema.subscriptions.trigger]
+```
+
+## CircuitBreaker
+
+The CircuitBreaker concern is a reusable module that you can include in any class that needs to run code with circuit breaker protection. The concern provides a `run_with_circuit` method that wraps a code block with circuit breaker functionality, which helps prevent cascading failures and improves system resilience. For more information about the circuit breaker pattern, see:
+
+- [What is Circuit breaker](https://martinfowler.com/bliki/CircuitBreaker.html).
+- [The Hystrix documentation on CircuitBreaker](https://github.com/Netflix/Hystrix/wiki/How-it-Works#circuit-breaker).
+
+### Use CircuitBreaker
+
+To use the CircuitBreaker concern, you need to include it in a class. For example:
+
+```ruby
+class MyService
+ include Gitlab::Llm::Concerns::CircuitBreaker
+
+ def call_external_service
+ run_with_circuit do
+ # Code that interacts with external service goes here
+
+ raise InternalServerError
+ end
+ end
+end
+```
+
+The `call_external_service` method is an example method that interacts with an external service.
+By wrapping the code that interacts with the external service with `run_with_circuit`, the method is executed within the circuit breaker.
+The circuit breaker is created and configured by the `circuit` method, which is called automatically when the `CircuitBreaker` module is included.
+The method should raise `InternalServerError` error which will be counted towards the error threshold if raised during the execution of the code block.
+
+The circuit breaker tracks the number of errors and the rate of requests,
+and opens the circuit if it reaches the configured error threshold or volume threshold.
+If the circuit is open, subsequent requests fail fast without executing the code block, and the circuit breaker periodically allows a small number of requests through to test the service's availability before closing the circuit again.
+
+### Configuration
+
+The circuit breaker is configured with two constants which control the number of errors and requests at which the circuit will open:
+
+- `ERROR_THRESHOLD`
+- `VOLUME_THRESHOLD`
+
+You can adjust these values as needed for the specific service and usage pattern.
+The `InternalServerError` is the exception class counted towards the error threshold if raised during the execution of the code block.
+This is the exception class that triggers the circuit breaker when raised by the code that interacts with the external service.
+
+NOTE:
+The `CircuitBreaker` module depends on the `Circuitbox` gem to provide the circuit breaker implementation. By default, the service name is inferred from the class name where the concern module is included. Override the `service_name` method if the name needs to be different.
+
+### Testing
+
+To test code that uses the `CircuitBreaker` concern, you can use `RSpec` shared examples and pass the `service` and `subject` variables:
+
+```ruby
+it_behaves_like 'has circuit breaker' do
+ let(:service) { dummy_class.new }
+ let(:subject) { service.dummy_method }
+end
+```
+
+## How to implement a new action
+
+### Register a new method
+
+Go to the `Llm::ExecuteMethodService` and add a new method with the new service class you will create.
+
+```ruby
+class ExecuteMethodService < BaseService
+ METHODS = {
+ # ...
+ amazing_new_ai_feature: Llm::AmazingNewAiFeatureService
+ }.freeze
+```
+
+### Create a Service
+
+1. Create a new service under `ee/app/services/llm/` and inherit it from the `BaseService`.
+1. The `resource` is the object we want to act on. It can be any object that includes the `Ai::Model` concern. For example it could be a `Project`, `MergeRequest`, or `Issue`.
+
+```ruby
+# ee/app/services/llm/amazing_new_ai_feature_service.rb
+
+module Llm
+ class AmazingNewAiFeatureService < BaseService
+ private
+
+ def perform
+ ::Llm::CompletionWorker.perform_async(user.id, resource.id, resource.class.name, :amazing_new_ai_feature)
+ success
+ end
+
+ def valid?
+ super && Ability.allowed?(user, :amazing_new_ai_feature, resource)
+ end
+ end
+end
+```
+
+### Authorization
+
+We recommend to use [policies](../policies.md) to deal with authorization for a feature. Currently we need to make sure to cover the following checks:
+
+1. General AI feature flag is enabled
+1. Feature specific feature flag is enabled
+1. The namespace has the required license for the feature
+1. User is a member of the group/project
+1. `experiment_features_enabled` and `third_party_ai_features_enabled` flags are set on the `Namespace`
+
+For our example, we need to implement the `allowed?(:amazing_new_ai_feature)` call. As an example, you can look at the [Issue Policy for the summarize comments feature](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/policies/ee/issue_policy.rb). In our example case, we want to implement the feature for Issues as well:
+
+```ruby
+# ee/app/policies/ee/issue_policy.rb
+
+module EE
+ module IssuePolicy
+ extend ActiveSupport::Concern
+ prepended do
+ with_scope :subject
+ condition(:ai_available) do
+ ::Feature.enabled?(:openai_experimentation)
+ end
+
+ with_scope :subject
+ condition(:amazing_new_ai_feature_enabled) do
+ ::Feature.enabled?(:amazing_new_ai_feature, subject_container) &&
+ subject_container.licensed_feature_available?(:amazing_new_ai_feature)
+ end
+
+ rule do
+ ai_available & amazing_new_ai_feature_enabled & is_project_member
+ end.enable :amazing_new_ai_feature
+ end
+ end
+end
+```
+
+### Pairing requests with responses
+
+Because multiple users' requests can be processed in parallel, when receiving responses,
+it can be difficult to pair a response with its original request. The `requestId`
+field can be used for this purpose, because both the request and response are assured
+to have the same `requestId` UUID.
+
+### Caching
+
+AI requests and responses can be cached. Cached conversation is being used to
+display user interaction with AI features. In the current implementation, this cache
+is not used to skip consecutive calls to the AI service when a user repeats
+their requests.
+
+```graphql
+query {
+ aiMessages {
+ nodes {
+ id
+ requestId
+ content
+ role
+ errors
+ timestamp
+ }
+ }
+}
+```
+
+This cache is especially useful for chat functionality. For other services,
+caching is disabled. (It can be enabled for a service by using `cache_response: true`
+option.)
+
+Caching has following limitations:
+
+- Messages are stored in Redis stream.
+- There is a single stream of messages per user. This means that all services
+ currently share the same cache. If needed, this could be extended to multiple
+ streams per user (after checking with the infrastructure team that Redis can handle
+ the estimated amount of messages).
+- Only the last 50 messages (requests + responses) are kept.
+- Expiration time of the stream is 3 days since adding last message.
+- User can access only their own messages. There is no authorization on the caching
+ level, and any authorization (if accessed by not current user) is expected on
+ the service layer.
+
+### Check if feature is allowed for this resource based on namespace settings
+
+There are two settings allowed on root namespace level that restrict the use of AI features:
+
+- `experiment_features_enabled`
+- `third_party_ai_features_enabled`.
+
+To check if that feature is allowed for a given namespace, call:
+
+```ruby
+Gitlab::Llm::StageCheck.available?(namespace, :name_of_the_feature)
+```
+
+Add the name of the feature to the `Gitlab::Llm::StageCheck` class. There are arrays there that differentiate
+between experimental and beta features.
+
+This way we are ready for the following different cases:
+
+- If the feature is not in any array, the check will return `true`. For example, the feature was moved to GA and does not use a third-party setting.
+- If feature is in GA, but uses a third-party setting, the class will return a proper answer based on the namespace third-party setting.
+
+To move the feature from the experimental phase to the beta phase, move the name of the feature from the `EXPERIMENTAL_FEATURES` array to the `BETA_FEATURES` array.
+
+### Implement calls to AI APIs and the prompts
+
+The `CompletionWorker` will call the `Completions::Factory` which will initialize the Service and execute the actual call to the API.
+In our example, we will use OpenAI and implement two new classes:
+
+```ruby
+# /ee/lib/gitlab/llm/open_ai/completions/amazing_new_ai_feature.rb
+
+module Gitlab
+ module Llm
+ module OpenAi
+ module Completions
+ class AmazingNewAiFeature
+ def initialize(ai_prompt_class)
+ @ai_prompt_class = ai_prompt_class
+ end
+
+ def execute(user, issue, options)
+ options = ai_prompt_class.get_options(options[:messages])
+
+ ai_response = Gitlab::Llm::OpenAi::Client.new(user).chat(content: nil, **options)
+
+ ::Gitlab::Llm::OpenAi::ResponseService.new(user, issue, ai_response, options: {}).execute(
+ Gitlab::Llm::OpenAi::ResponseModifiers::Chat.new
+ )
+ end
+
+ private
+
+ attr_reader :ai_prompt_class
+ end
+ end
+ end
+ end
+end
+```
+
+```ruby
+# /ee/lib/gitlab/llm/open_ai/templates/amazing_new_ai_feature.rb
+
+module Gitlab
+ module Llm
+ module OpenAi
+ module Templates
+ class AmazingNewAiFeature
+ TEMPERATURE = 0.3
+
+ def self.get_options(messages)
+ system_content = <<-TEMPLATE
+ You are an assistant that writes code for the following input:
+ """
+ TEMPLATE
+
+ {
+ messages: [
+ { role: "system", content: system_content },
+ { role: "user", content: messages },
+ ],
+ temperature: TEMPERATURE
+ }
+ end
+ end
+ end
+ end
+ end
+end
+```
+
+Because we support multiple AI providers, you may also use those providers for the same example:
+
+```ruby
+Gitlab::Llm::VertexAi::Client.new(user)
+Gitlab::Llm::Anthropic::Client.new(user)
+```
+
+### Monitoring Ai Actions
+
+- Error ratio and response latency apdex for each Ai action can be found on [Sidekiq Service dashboard](https://dashboards.gitlab.net/d/sidekiq-main/sidekiq-overview?orgId=1) under "SLI Detail: llm_completion".
+- Spent tokens, usage of each Ai feature and other statistics can be found on [periscope dashboard](https://app.periscopedata.com/app/gitlab/1137231/Ai-Features).
+
+### Add Ai Action to GraphQL
+
+TODO
+
+## Security
+
+Refer to the [secure coding guidelines for Artificial Intelligence (AI) features](../secure_coding_guidelines.md#artificial-intelligence-ai-features).
diff --git a/doc/development/ai_features/prompts.md b/doc/development/ai_features/prompts.md
new file mode 100644
index 00000000000..f4738055f6b
--- /dev/null
+++ b/doc/development/ai_features/prompts.md
@@ -0,0 +1,28 @@
+---
+stage: AI-powered
+group: AI Framework
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Working with AI prompts
+
+This documentation provides some tips and guidelines for working with AI prompts, particularly aimed at GitLab engineers. The tips are:
+
+1. Set the tone - Describe how the AI assistant should respond, e.g. "You're a helpful assistant specialized in DevSecOps". Giving context helps the AI provide better answers. This establishes expectations for how the AI should communicate.
+1. Be specific - When describing a task, provide lots of details and context to help the AI understand. Give as much specific information as possible. For example, don't just say "summarize this text", provide context like "You are an AI assistant named GitLab Duo. Please read the following text and summarize it in 3 concise sentences focusing on the key points." The more details you provide, the better the AI will perform.
+1. Give examples - Provide examples of potential questions and desired answers. This helps the AI give better responses. For instance, you can provide a sample question like "What is the main idea of this text?" and then give the ideal concise summary as an example response. Always give the instructions first, and then provide illustrative examples.
+1. Guide the input - Use delimiters to clearly indicate where the user's input starts and ends. The AI needs to know what is input. Make it obvious to the model what text is the user input.
+1. Step-by-step reasoning - Ask the AI to explain its reasoning step-by-step. This produces more accurate results. You can get better responses by explicitly asking the model to think through its reasoning step-by-step and show the full explanation. Say something like "Please explain your reasoning step-by-step for how you arrived at your summary:"
+1. Allow uncertainty - Tell the AI to say "I don't know" if it is unsure, to avoid hallucinating answers. Give the model an explicit way out if it does not know the answer to avoid false responses. Say "If you do not know the answer, please respond with 'I don't know'".
+1. Use positive phrasing - Say what the AI should do, not what it shouldn't do, even when prohibiting actions. Although tricky, use positive language as much as possible, even when restricting behavior. For example, say "Please provide helpful, honest responses" rather than "Do not provide harmful or dishonest responses".
+1. Correct language - Use proper English grammar and syntax to help the AI understand. Having technically accurate language and grammar will enable the model to better comprehend the prompt. This is why working with technical writers is very helpful for crafting prompts.
+1. Test different models - Prompts are provider specific. Test new models before fully switching. It's important to recognize prompts do not work equally across different AI providers. Make sure to test performance carefully when changing to a new model, don't assume it will work the same.
+1. Build quality control - Automate testing prompts with RSpec or Rake task to catch differences. Develop automated checks to regularly test prompts and catch regressions. Use frameworks like RSpec or Rake tasks to build test cases with sample inputs and desired outputs.
+1. Iterate - Refine prompts gradually, testing changes to see their impact. Treat prompt engineering as an iterative process. Make small changes, then test results before continuing. Build up prompts incrementally while continually evaluating effects.
+
+## Further Resources
+
+For more comprehensive prompt engineering guides, see:
+
+- [Prompt Engineering Guide 1](https://www.promptingguide.ai/)
+- [Prompt Engineering Guide 2](https://www.deeplearning.ai/short-courses/chatgpt-prompt-engineering-for-developers/)
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 440068d55c2..3662b21eb9e 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -1058,6 +1058,17 @@ A taxonomic genus. See: [Wikipedia page on genera](https://wikipedia.org/wiki/Ge
Multiple documentation references can be provided. The syntax for this property
is a `HashMap` where the keys are textual descriptions, and the values are URLs.
+### Subscription tier badges
+
+If a field or argument is available to higher subscription tiers than the other fields,
+add the [tier badge](documentation/styleguide/index.md#product-tier-badges) inline.
+
+For example:
+
+```ruby
+description: '**(ULTIMATE ALL)** Full path of a custom template.'
+```
+
## Authorization
See: [GraphQL Authorization](graphql_guide/authorization.md)
diff --git a/doc/development/audit_event_guide/index.md b/doc/development/audit_event_guide/index.md
index b8af1341919..aeab188fa76 100644
--- a/doc/development/audit_event_guide/index.md
+++ b/doc/development/audit_event_guide/index.md
@@ -55,7 +55,7 @@ With `Gitlab::Audit::Auditor` service, we can instrument audit events in two way
### Using block to record multiple events
-This method is useful when events are emitted deep in the call stack.
+You can use this method when events are emitted deep in the call stack.
For example, we can record multiple audit events when the user updates a merge
request approval rule. As part of this user flow, we would like to audit changes
@@ -118,7 +118,7 @@ end
### Data volume considerations
Because every audit event is persisted to the database, consider the amount of data we expect to generate, and the rate of generation, for new
-audit events. For new audit events that will produce a lot of data in the database, consider adding a
+audit events. For new audit events that produce a lot of data in the database, consider adding a
[streaming-only audit event](#event-streaming) instead. If you have questions about this, feel free to ping
`@gitlab-org/govern/compliance/backend` in an issue or merge request.
@@ -225,6 +225,22 @@ To add a new audit event type:
| `saved_to_database` | yes | Indicate whether to persist events to database and JSON logs |
| `streamed` | yes | Indicate that events should be streamed to external services (if configured) |
+### Generate documentation
+
+Audit event types documentation is automatically generated and [published](../../administration/audit_event_streaming/audit_event_types.md)
+to the GitLab documentation site.
+
+If you add a new audit event type, run the
+[`gitlab:audit_event_types:compile_docs` Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/tasks/gitlab/audit_event_types/audit_event_types.rake)
+to update the documentation:
+
+```shell
+bundle exec rake gitlab:audit_event_types:compile_docs
+```
+
+Run the [`gitlab:audit_event_types:check_docs` Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/tasks/gitlab/audit_event_types/audit_event_types.rake)
+to check if the documentation is up-to-date.
+
## Event streaming
All events where the entity is a `Group` or `Project` are recorded in the audit log, and also streamed to one or more
@@ -233,7 +249,7 @@ All events where the entity is a `Group` or `Project` are recorded in the audit
- `Group`, events are streamed to the group's root ancestor's event streaming destinations.
- `Project`, events are streamed to the project's root ancestor's event streaming destinations.
-You can add streaming-only events that are not stored in the GitLab database. This is primarily intended to be used for actions that generate
+You can add streaming-only events that are not stored in the GitLab database. Streaming-only events are primarily intended to be used for actions that generate
a large amount of data. See [this merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76719/diffs#d56e47632f0384722d411ed3ab5b15e947bd2265_26_36)
for an example.
This feature is under heavy development. Follow the [parent epic](https://gitlab.com/groups/gitlab-org/-/epics/5925) for updates on feature
@@ -243,5 +259,5 @@ development.
We intentionally do not translate audit event messages because translated messages would be saved in the database and served to users, regardless of their locale settings.
-This could mean, for example, that we use the locale for the currently authenticated user to record an audit event message and stream the message to an external streaming
+For example, this could mean that we use the locale for the authenticated user to record an audit event message and stream the message to an external streaming
destination in the wrong language for that destination. Users could find that confusing.
diff --git a/doc/development/avoiding_required_stops.md b/doc/development/avoiding_required_stops.md
index 0308e0c30c0..5c2197048b0 100644
--- a/doc/development/avoiding_required_stops.md
+++ b/doc/development/avoiding_required_stops.md
@@ -10,7 +10,7 @@ Required stops are any changes to GitLab [components](architecture.md) or
dependencies that result in the need to upgrade to and stop at a specific
`major.minor` version when [upgrading GitLab](../update/index.md).
-While Development maintains a [maintainenance policy](../policy/maintenance.md)
+While Development maintains a [maintenance policy](../policy/maintenance.md)
that results in a three-release (3 month) backport window - GitLab maintains a
much longer window of [version support](https://about.gitlab.com/support/statement-of-support/#version-support)
that includes the current major version, as well as the two previous major
@@ -31,8 +31,16 @@ across greater than 1-3 minor releases.
Wherever possible, a required stop should be avoided. If it can't be avoided,
the required stop should be aligned to a _scheduled_ required stop.
+In cases where we are considering retroactively declaring an unplanned required stop,
+please contact the [Distribution team product manager](https://about.gitlab.com/handbook/product/categories/#distributionbuild-group) to advise on next steps. If there
+is uncertainty about whether we should declare a required stop, the Distribution product
+manager may escalate to GitLab product leadership (VP or Chief Product Officer) to make
+a final determination. This may happen, for example, if a change might require a stop for
+a small subset of very large self-managed installations and there are well-defined workarounds
+if customers run into issues.
+
Scheduled required stops are often implemented for the previous `major`.`minor`
-release just prior to a `major` version release in order to accomodate multiple
+release just prior to a `major` version release in order to accommodate multiple
[planned deprecations](../update/terminology.md#deprecation) and known
[breaking changes](../update/terminology.md#breaking-change).
diff --git a/doc/development/build_test_package.md b/doc/development/build_test_package.md
index 70aa328bf8a..c4ae0ac5b71 100644
--- a/doc/development/build_test_package.md
+++ b/doc/development/build_test_package.md
@@ -19,12 +19,23 @@ that will create:
commit which triggered the pipeline).
When you push a commit to either the GitLab CE or GitLab EE project, the
-pipeline for that commit will have a `build-package` manual action you can
-trigger.
+pipeline for that commit will have a `trigger-omnibus` job in the `qa` stage you
+can trigger manually (if it didn't trigger already).
-![Manual actions](img/build_package_v12_6.png)
+![Trigger omnibus QA job](img/trigger_omnibus_v16_3.png)
-![Build package manual action](img/trigger_build_package_v12_6.png)
+After the child pipeline started, you can select `trigger-omnibus` to go to
+the child pipeline named `TRIGGERED_EE_PIPELINE`.
+
+![Triggered child pipeline](img/triggered_ee_pipeline_v16_3.png)
+
+Next, select the `Trigger:package` job in the `trigger-package` stage.
+
+The `Trigger:package` job when finished will upload its artifacts to GitLab, and
+then you can `Browse` them and download the `.deb` file or you can use the
+GitLab API to download the file straight to your VM. Keep in mind the expiry of
+these artifacts is short, so they will be deleted automatically within a day or
+so.
## Specifying versions of components
diff --git a/doc/development/cascading_settings.md b/doc/development/cascading_settings.md
index 42f4b5dd6f3..16ad7b3eab6 100644
--- a/doc/development/cascading_settings.md
+++ b/doc/development/cascading_settings.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/cloud_connector/code_suggestions_for_sm.md b/doc/development/cloud_connector/code_suggestions_for_sm.md
new file mode 100644
index 00000000000..bd8a39bc0d6
--- /dev/null
+++ b/doc/development/cloud_connector/code_suggestions_for_sm.md
@@ -0,0 +1,259 @@
+---
+stage: Data Stores
+group: Cloud Connector
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Cloud Connector MVC: Code Suggestions for Self-Managed/GitLab Dedicated
+
+This document presents the systems and their interactions involved in delivering
+the [Code Suggestions AI feature](../../user/project/repository/code_suggestions/index.md)
+to self-managed and GitLab Dedicated customers. It was considered the MVC
+or initial iteration toward a more extensive vision called [GitLab Cloud Connector](https://gitlab.com/groups/gitlab-org/-/epics/308)
+(formerly "GitLab Plus"), which will allow self-managed customers to benefit from
+features operated by us.
+
+In the context of this document, and any architectural discussions around Cloud Connector features,
+it is important to understand that **Cloud Connector is not a system**. It is an umbrella term
+for all the projects we engage in that make existing SaaS-only features available to
+self-managed and GitLab Dedicated customers. Some of these may be sufficiently similar to share
+solutions, including new systems that deliver these features, but this may not extend to all
+features covered by the Cloud Connector umbrella project.
+
+For the remainder of this document we do not distinguish between self-managed and GitLab Dedicated
+use cases, as at the time of this writing, they are identical. We are exploring any necessary
+deviations needed specifically for GitLab Dedicated in [issue 410394](https://gitlab.com/gitlab-org/gitlab/-/issues/410394).
+
+## Problem statement
+
+Code Suggestions for self-managed users work almost identically to GitLab SaaS:
+
+1. The user:
+ 1. Connects their IDE to a GitLab instance.
+ 1. Requests a code suggestion through their IDE.
+1. The GitLab instance:
+ 1. Authenticates the user and performs instance-local permission and configuration checks.
+ 1. Produces a [JSON Web Token](https://jwt.io/) to use with the [AI gateway](../../architecture/blueprints/ai_gateway/index.md).
+ 1. Forwards the request to the AI gateway with this access token.
+ 1. Returns the response back to the user's IDE.
+
+The unique challenge we had to solve in the context of self-managed instances is step 2b:
+For GitLab SaaS, we can make an instance-local decision about whether a user is allowed to use Code Suggestions
+(or any other feature for that matter) and contact the AI gateway, but for self-managed users we cannot.
+This is because we cannot trust a self-managed instance to produce such a token as we have no control over them.
+In the context of Cloud Connector, this means providing a system for permission delegation that takes into account
+self-managed instance billing and license data, so that once we establish that an instance is eligible
+for this feature based on its payment history, we can issue an access token to this instance.
+
+The architecture and data flow for this solution are outlined in the following section.
+
+## Architecture
+
+NOTE:
+This section covers the architectural details relevant to Code Suggestions in the context of Cloud Connector.
+A more high-level overview can be found in [AI Architecture](../ai_architecture.md).
+
+The Code Suggestions architecture for Cloud Connector serves as a blueprint to implement
+similar features in the future. As mentioned above, the primary problem to solve is verifying that a request
+coming from a self-managed instance is eligible to obtain Code Suggestions from the AI gateway. This can
+be broken down further into two smaller problems:
+
+1. **Instance eligibility.** Code suggestions are a paid feature. The source of truth for subscription state is the
+ customers portal (CustomersDot). A self-managed GitLab instance must therefore involve
+ CustomersDot in the decision for whether an instance is allowed to request code suggestions
+ on behalf of a user before it forwards this request to the AI gateway.
+1. **AI gateway authentication.** Because the AI gateway has no concept of self-managed instance or user identity,
+ the AI gateway must verify that the instance from which a request originates is legitimate.
+ This is handled almost identically to GitLab SaaS. The relevant differences are covered in later sections.
+
+Three systems are involved in the entire flow, with the following responsibilities:
+
+1. **GitLab Rails application:**
+ - Authenticates the current user requesting a code suggestion, as it would any other API request.
+ - Manages and checks instance-level configuration related to Code Suggestions for self-managed installations.
+ - [Runs a background cron job](#gitlabcustomersdot-token-synchronization) that regularly fetches an JWT access token for use with the AI gateway from CustomersDot.
+ - Calls the AI gateway with the given JWT access token, potentially enriching the call
+ with instance-local context.
+1. **CustomersDot:**
+ - Provides a user interface for customers to purchase Code Suggestions.
+ - When a GitLab instance syncs with CustomersDot, checks whether it
+ has an active Code Suggestions purchase, and issues a cryptographically signed JWT access token scoped
+ to the Code Suggestions feature. This mechanism is extensible to other Cloud Connector features.
+ - Acts as an [OIDC Provider](https://openid.net/developers/how-connect-works/) by offering discovery and configuration endpoints
+ that serve the public keys required to validate a Code Suggestions JWT. The AI gateway
+ calls these endpoints (see below.)
+1. **AI gateway:**
+ - Services Code Suggestions requests coming from the GitLab application.
+ - Synchronizes with CustomersDot OIDC endpoints to obtain token validation keys.
+ - Validates the JWT access token sent by a GitLab instance using these keys.
+ This establishes the necessary trust relationship between any GitLab instance
+ and the AI gateway, which is hosted by us.
+
+It is important to highlight that from the perspective of the AI gateway, all requests are equal.
+As long as the access token can be verified to be authentic, the request will succeed, be that
+from a GitLab SaaS or self-managed user.
+
+The following diagram shows how these systems interact at a high level:
+
+<!--
+ Component architecture sources for PlantUML diagram source code:
+ https://gitlab.com/gitlab-org/gitlab/-/snippets/3597299
+
+ The comments do not render correctly in various tested browser, so it is included as a binary image instead.
+-->
+![Code Suggestions architecture and components](img/code_suggestions_components.png)
+
+## Implementation details and data flow
+
+This section breaks down the three primary mechanisms used to deliver Code Suggestions
+to self-managed instances:
+
+1. GitLab/CustomersDot token synchronization.
+1. Proxying AI gateway requests.
+1. AI gateway access token validation.
+
+The sequence diagram below shows how a typical flow might look like.
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant U as User
+ participant VS as IDE
+ participant SM as GitLab
+ participant CD as CustomersDot
+ participant AI as AI gateway<br/>(aka Model Gateway)
+
+ Note over SM,CD: AI gateway token synchronization
+ loop Sidekiq cron job
+ SM->>CD: sync subscription seat data
+ CD->>CD: verify eligibility
+ Note over CD,SM: Token validity tied to subscription
+ CD-->>SM: seat data + AI gateway access token (JWT)
+ SM->>SM: store seat data + JWT
+ end
+ Note over U,AI: Developer persona
+ U->>SM: create PAT
+ SM-->>U: PAT
+ U->>VS: configure with PAT
+ loop Use code suggestions
+ Note over VS,AI: All requests via AI abstraction layer
+ VS->>SM: get code suggestions with PAT
+ SM->>SM: auth user with PAT
+ SM->>AI: fetch code suggestions with JWT
+ alt Validation key missing
+ AI->>CD: fetch JWKS
+ AI->>AI: cache key set in Redis
+ else
+ AI->>AI: load key set
+ end
+ AI->>AI: validate JWT with<br/>cached JWKS keys
+ AI-->>SM: code suggestions
+ SM-->>VS: code suggestions
+ end
+```
+
+### GitLab/CustomersDot token synchronization
+
+The first problem we had to solve was to determine whether any given self-managed GitLab is
+allowed to use Code Suggestions. The mechanism described below was built for Code
+Suggestions but could serve any other Cloud Connector feature tied to a Cloud License
+subscription.
+
+The source of truth for this from the perspective of the GitLab Rails application is CustomersDot,
+which itself converses with Zuora (a third party subscription service) to determine which
+subscriptions or add-ons are active for a given customer.
+
+Unlike with GitLab SaaS, CustomersDot does not call back into self-managed GitLab instances when
+subscriptions or add-ons are purchased. Instead, a daily synchronization job is scheduled in
+Sidekiq that compares purchases against actual seat usage using the `/api/v1/seat_links`
+REST endpoint on CustomersDot. An instance authenticates itself by posting
+its license key as part of the request, which CustomersDot uses to look up subscription data
+connected to this license, therefore using the license key as a form of authentication token.
+
+If CustomersDot deems the instance eligible, it embeds a Code Suggestions token in the response
+payload:
+
+```json
+"service_tokens": {
+ "code_suggestions": {
+ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiI0M2FlOWI4...qmvMVhRS01YRc6a5LaBbhU_m5tw",
+ "expires_at": 1695121894
+ }
+}
+```
+
+- `token` is an [encoded JSON Web Token](https://jwt.io/) signed with RSA256, an asymmetric
+ secure signing algorithm. This allows other services who hold the corresponding public key
+ to validate the authenticity of this token. The token carries [claims](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-token-claims#registered-claims) that receivers
+ can verify, most importantly the `aud` (audience) claim. We use the audience claim to scope
+ access to particular features, such as Code Suggestions. Each paid feature requires a separate
+ token to be issued with a corresponding claim.
+- `expires_at`: UNIX epoch timestamp of the token's expiration time. Tokens currently have
+ an expiration time of 3 days. This TTL was chosen to strike a balance between regularly
+ rolling over access tokens and some leeway in case the token sync fails.
+
+NOTE:
+To sign tokens, CustomersDot maintains a private key.
+For security reasons, we rotate this key on a regular basis. For more information, refer
+to [the key rotation process for CustomersDot](https://gitlab.com/gitlab-org/customers-gitlab-com/-/blob/main/doc/architecture/add_ons/code_suggestions/authorization_for_self_managed.md#jwk-signing-key-rotation).
+
+Upon receiving a response, GitLab Rails stores this token in Postgres and removes any
+other tokens it may have previously stored. When users request a code suggestion, GitLab
+can then load this token and attach it to AI gateway requests, which is described next.
+
+### Proxying AI gateway requests
+
+Given the JWT access token described above, a GitLab instance is ready to serve Code Suggestions
+requests to users. Upon receiving a request to `/api/v4/code_suggestions/completions`, GitLab:
+
+1. Authenticates this request with a user's Personal Access Token (PAT), as it would any REST API call.
+ Users configure this token in their IDE settings.
+1. Verifies that the administrator has the Code Suggestions feature enabled and the instance
+ license tier includes this feature.
+1. Loads the JWT access token from the database.
+1. Forwards the request to the AI gateway with the token attached.
+
+As with GitLab SaaS requests, the downstream call uses Workhorse's `senddata` feature. This
+mechanism yields control to Workhorse by responding with a `send-url` header field. Workhorse
+then intercepts this response and calls into the AI gateway given the request URL, headers
+and payload provided through `send-url`. This relieves the Puma process from stalling on downstream I/O,
+removing a scalability bottleneck.
+
+This process is mostly identical to GitLab SaaS. The biggest difference is
+how GitLab Rails resolves user permissions and loads the access token. GitLab SaaS can self-issue the access token
+because billing is not handled by CustomersDot.
+
+### AI gateway access token validation
+
+The next problem we had to solve was authenticating the Code Suggestions requests that a self-managed GitLab sends
+to the AI gateway on behalf of a user. The AI gateway does not and should not have any knowledge
+of a customer's instance. Instead, the gateway verifies the request's authenticity by decoding the JWT
+access token enclosed in the request using a public key it fetches from CustomersDot, which is
+the original issuer of the token.
+
+The AI gateway accomplishes this by first requesting a [JSON Web Key Set](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets)
+from CustomersDot. The keyset obtained from the JWKS endpoint is then cached for 24 hours and used to decode any
+JWTs attached to Code Suggestions requests. Note that token expiration is implicitly enforced
+in that expired tokens fail to decode, in which case the AI gateway rejects this request.
+
+The steps to obtain the JWKS and verify tokens are detailed in [the AI service verification sequence diagram](https://gitlab.com/gitlab-org/customers-gitlab-com/-/blob/main/doc/architecture/add_ons/code_suggestions/authorization_for_self_managed.md#gitlab-hosted-ai-service-flow-to-verify-jwt-token) for CustomersDot.
+
+This process is mostly identical to GitLab SaaS. The only difference is that the AI gateway obtains validation keys
+from CustomersDot instead of GitLab SaaS, which self-issues its own tokens.
+
+## Gaps and outlook
+
+Code Suggestions was the first Cloud Connector feature we looked at, but we expect many more
+to be designed and built, some of which may require different technical approaches from what is
+documented here.
+
+Some areas that are not currently well-defined or understood include:
+
+- Support for GitLab Dedicated and regional deployments. This is currently being investigated in
+ [issue 410394](https://gitlab.com/gitlab-org/gitlab/-/issues/410394).
+- The impact on end-user experience when a GitLab instance is deployed to a geographic region that
+ has high latency overhead when connecting to a GitLab service in US-east.
+- There are some known usability issues with relying solely on a daily Sidekiq job to fetch access
+ tokens. We are exploring ways to improve this in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/11289).
+- Rate-limiting requests at the GitLab instance level was out of scope for the MVC. We are exploring
+ this idea in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/420123).
diff --git a/doc/development/cloud_connector/img/code_suggestions_components.png b/doc/development/cloud_connector/img/code_suggestions_components.png
new file mode 100644
index 00000000000..3f41d1d1a6b
--- /dev/null
+++ b/doc/development/cloud_connector/img/code_suggestions_components.png
Binary files differ
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index a8c527ad30e..17c16e79232 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -161,12 +161,6 @@ The [Roulette dashboard](https://gitlab-org.gitlab.io/gitlab-roulette/) contains
For more information, review [the roulette README](https://gitlab.com/gitlab-org/gitlab-roulette).
-As an experiment, we want to introduce a `local` reviewer status for database reviews. Local reviewers are reviewers
-focusing on work from a team/stage, but not outside of it. This helps to focus and build great domain
-knowledge. We are not introducing changes to the reviewer roulette till we evaluate the impact and feedback from this
-experiment. We ask to respect reviewers who decline reviews based on their focus on `local` reviews. For tracking purposes,
-please use in your personal YAML file entry: `- reviewer database local` instead of `- reviewer database`.
-
### Approval guidelines
As described in the section on the responsibility of the maintainer below, you
diff --git a/doc/development/code_suggestions/index.md b/doc/development/code_suggestions/index.md
new file mode 100644
index 00000000000..38fd6200ace
--- /dev/null
+++ b/doc/development/code_suggestions/index.md
@@ -0,0 +1,56 @@
+---
+stage: Create
+group: Code Creation
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Code Suggestions development guidelines
+
+## Code Suggestions development setup
+
+The recommended setup for locally developing and debugging Code Suggestions is to have all 3 different components running:
+
+- IDE Extension (e.g. VSCode Extension)
+- Main application configured correctly
+- [Model gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist)
+
+This should enable everyone to see locally any change in an IDE being sent to the main application transformed to a prompt which is then sent to the respective model.
+
+### Setup instructions
+
+1. Install and run locally the [VSCode Extension](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/CONTRIBUTING.md#configuring-development-environment)
+ 1. Add the ```"gitlab.debug": true,``` info to the Code Suggestions development config
+ 1. In VSCode navigate to the Extensions page and find "GitLab Workflow" in the list
+ 1. Open the extension settings by clicking a small cog icon and select "Extension Settings" option
+ 1. Check a "GitLab: Debug" checkbox.
+1. Main Application
+ 1. Enable Feature Flags ```code_suggestions_completion_api``` and ```code_suggestions_tokens_api```
+ 1. In your terminal, navigate to a `gitlab` inside your `gitlab-development-kit` directory
+ 1. Run `bundle exec rails c` to start a Rails console
+ 1. Call `Feature.enable(:code_suggestions_completion_api)` and `Feature.enable(:code_suggestions_tokens_api)` from the console
+ 1. Run the GDK with ```export CODE_SUGGESTIONS_BASE_URL=http://localhost:5052```
+1. [Setup Model Gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist#how-to-run-the-server-locally)
+ 1. Build tree sitter libraries ```poetry run scripts/build-tree-sitter-lib.py```
+ 1. Extra .env Changes for all debugging insights
+ 1. LOG_LEVEL=DEBUG
+ 1. LOG_FORMAT_JSON=false
+ 1. LOG_TO_FILE=true
+ 1. Watch the new log file ```modelgateway_debug.log``` , e.g. ```tail -f modelgateway_debug.log | fblog -a prefix -a suffix -a current_file_name -a suggestion -a language -a input -a parameters -a score -a exception```
+
+### Setup instructions to use staging Model Gateway
+
+When testing interactions with the Model Gateway, you might want to integrate your local GDK
+with the deployed staging Model Gateway. To do this:
+
+1. You need a [cloud staging license](../../user/project/repository/code_suggestions/self_managed.md#update-gitlab) that has the Code Suggestions add-on, because add-ons are enabled on staging. Drop a note in the `#s_fulfillment` internal Slack channel to request an add-on to your license. See this [handbook page](https://about.gitlab.com/handbook/developer-onboarding/#working-on-gitlab-ee-developer-licenses) for how to request a license for local development.
+1. Set env variables to point customers-dot to staging, and the Model Gateway to staging:
+
+ ```shell
+ export GITLAB_LICENSE_MODE=test
+ export CUSTOMER_PORTAL_URL=https://customers.staging.gitlab.com
+ export CODE_SUGGESTIONS_BASE_URL=https://codesuggestions.staging.gitlab.com
+ ```
+
+1. Restart the GDK.
+1. Ensure you followed the necessary [steps to enable the Code Suggestions feature](../../user/project/repository/code_suggestions/self_managed.md#gitlab-163-and-later).
+1. Test out the Code Suggestions feature by opening the Web IDE for a project.
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index d2063a6836d..4f941b798c1 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -61,7 +61,7 @@ To write and test your code, you will use the GitLab Development Kit.
- To run a pre-configured GDK instance in the cloud, use [GDK with Gitpod](../../integration/gitpod.md).
From a project repository:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. In the upper right, select **Edit > Gitpod**.
1. If you want to contribute to the [website](https://about.gitlab.com/) or the [handbook](https://about.gitlab.com/handbook/),
go to the footer of any page and select **Edit in Web IDE** to open the [Web IDE](../../user/project/web_ide/index.md).
diff --git a/doc/development/database/avoiding_downtime_in_migrations.md b/doc/development/database/avoiding_downtime_in_migrations.md
index 371df5b45ff..5a2343e883c 100644
--- a/doc/development/database/avoiding_downtime_in_migrations.md
+++ b/doc/development/database/avoiding_downtime_in_migrations.md
@@ -14,8 +14,7 @@ requiring downtime.
## Dropping columns
-Removing columns is tricky because running GitLab processes may still be using
-the columns. To work around this safely, you need three steps in three releases:
+Removing columns is tricky because running GitLab processes expect these columns to exist, as ActiveRecord caches the tables schema, even if the columns are not referenced. This happens if the columns are not explicitly marked as ignored. To work around this safely, you need three steps in three releases:
1. [Ignoring the column](#ignoring-the-column-release-m) (release M)
1. [Dropping the column](#dropping-the-column-release-m1) (release M+1)
diff --git a/doc/development/database/batched_background_migrations.md b/doc/development/database/batched_background_migrations.md
index 10490df7b5e..a6d827df820 100644
--- a/doc/development/database/batched_background_migrations.md
+++ b/doc/development/database/batched_background_migrations.md
@@ -193,9 +193,10 @@ Because batched migrations are update heavy and there were few incidents in the
These database indicators are checked to throttle a migration. On getting a
stop signal, the migration is paused for a set time (10 minutes):
-- WAL queue pending archival crossing a threshold.
+- WAL queue pending archival crossing the threshold.
- Active autovacuum on the tables on which the migration works on.
- Patroni apdex SLI dropping below the SLO.
+- WAL rate crossing the threshold.
It's an ongoing effort to add more indicators to further enhance the
database health check framework. For more details, see
diff --git a/doc/development/database/clickhouse/clickhouse_within_gitlab.md b/doc/development/database/clickhouse/clickhouse_within_gitlab.md
new file mode 100644
index 00000000000..297776429d7
--- /dev/null
+++ b/doc/development/database/clickhouse/clickhouse_within_gitlab.md
@@ -0,0 +1,237 @@
+---
+stage: Data Stores
+group: Database
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# ClickHouse within GitLab
+
+This document gives a high-level overview of how to develop features using ClickHouse in the GitLab Rails application.
+
+NOTE:
+Most of the tooling and APIs are considered unstable.
+
+## GDK setup
+
+For instructions on how to set up a ClickHouse server locally, see the [ClickHouse installation documentation](https://clickhouse.com/docs/en/install).
+
+### Configure your Rails application
+
+1. Copy the example file and configure the credentials:
+
+ ```shell
+ cp config/click_house.yml.example
+ config/click_house.yml
+ ```
+
+1. Create the database using the `clickhouse-client` CLI tool:
+
+ ```shell
+ clickhouse-client --password
+ ```
+
+ ```sql
+ create database gitlab_clickhouse_development;
+ ```
+
+### Validate your setup
+
+Run the Rails console and invoke a simple query:
+
+```ruby
+ClickHouse::Client.select('SELECT 1', :main)
+# => [{"1"=>1}]
+```
+
+## Database schema and migrations
+
+For the ClickHouse database there are no established schema migration procedures yet. We have very basic tooling to build up the database schema in the test environment from scratch using timestamp-prefixed SQL files.
+
+You can create a table by placing a new SQL file in the `db/click_house/main` folder:
+
+```sql
+// 20230811124511_create_issues.sql
+CREATE TABLE issues
+(
+ id UInt64 DEFAULT 0,
+ title String DEFAULT ''
+)
+ENGINE = MergeTree
+PRIMARY KEY (id)
+```
+
+When you're working locally in your development environment, you can create or re-create your table schema by executing the respective `CREATE TABLE` statement. Alternatively, you can use the following snippet in the Rails console:
+
+```ruby
+require_relative 'spec/support/database/click_house/hooks.rb'
+
+# Drops and re-creates all tables
+ClickHouseTestRunner.new.ensure_schema
+```
+
+## Writing database queries
+
+For the ClickHouse database we don't use ORM (Object Relational Mapping). The main reason is that the GitLab application has many customizations for the `ActiveRecord` PostgresSQL adapter and the application generally assumes that all databases are using `PostgreSQL`. Since ClickHouse-related features are still in a very early stage of development, we decided to implement a simple HTTP client to avoid hard to discover bugs and long debugging time when dealing with multiple `ActiveRecord` adapters.
+
+Additionally, ClickHouse might not be used the same way as other adapters for `ActiveRecord`. The access patterns differ from traditional transactional databases, in that ClickHouse:
+
+- Uses nested aggregation `SELECT` queries with `GROUP BY` clauses.
+- Doesn't use single `INSERT` statements. Data is inserted in batches via background jobs.
+- Has different consistency characteristics, no transactions.
+- Has very little database-level validations.
+
+Database queries are written and executed with the help of the `ClickHouse::Client` gem.
+
+A simple query from the `events` table:
+
+```ruby
+rows = ClickHouse::Client.select('SELECT * FROM events', :main)
+```
+
+When working with queries with placeholders you can use the `ClickHouse::Query` object where you need to specify the placeholder name and its data type. The actual variable replacement, quoting and escaping will be done by the ClickHouse server.
+
+```ruby
+raw_query = 'SELECT * FROM events WHERE id > {min_id:UInt64}'
+placeholders = { min_id: Integer(100) }
+query = ClickHouse::Client::Query.new(raw_query: raw_query, placeholders: placeholders)
+
+rows = ClickHouse::Client.select(query, :main)
+```
+
+When using placeholders the client can provide the query with redacted placeholder values which can be ingested by our logging system. You can see the redacted version of your query by calling the `to_redacted_sql` method:
+
+```ruby
+puts query.to_redacted_sql
+```
+
+ClickHouse allows only one statement per request. This means that the common SQL injection vulnerability where the statement is closed with a `;` character and then another query is "injected" cannot be exploited:
+
+```ruby
+ClickHouse::Client.select('SELECT 1; SELECT 2', :main)
+
+# ClickHouse::Client::DatabaseError: Code: 62. DB::Exception: Syntax error (Multi-statements are not allowed): failed at position 9 (end of query): ; SELECT 2. . (SYNTAX_ERROR) (version 23.4.2.11 (official build))
+```
+
+### Subqueries
+
+You can compose complex queries with the `ClickHouse::Client::Query` class by specifying the query placeholder with the special `Subquery` type. The library will make sure to correctly merge the queries and the placeholders:
+
+```ruby
+subquery = ClickHouse::Client::Query.new(raw_query: 'SELECT id FROM events WHERE id = {id:UInt64}', placeholders: { id: Integer(10) })
+
+raw_query = 'SELECT * FROM events WHERE id > {id:UInt64} AND id IN ({q:Subquery})'
+placeholders = { id: Integer(10), q: subquery }
+
+query = ClickHouse::Client::Query.new(raw_query: raw_query, placeholders: placeholders)
+rows = ClickHouse::Client.select(query, :main)
+
+# ClickHouse will replace the placeholders
+puts query.to_sql # SELECT * FROM events WHERE id > {id:UInt64} AND id IN (SELECT id FROM events WHERE id = {id:UInt64})
+
+puts query.to_redacted_sql # SELECT * FROM events WHERE id > $1 AND id IN (SELECT id FROM events WHERE id = $2)
+
+puts query.placeholders # { id: 10 }
+```
+
+In case there are placeholders with the same name but different values the query will raise an error.
+
+### Writing query conditions
+
+When working with complex forms where multiple filter conditions are present, building queries by concatenating query fragments as string can get out of hands very quickly. For queries with several conditions you may use the `ClickHouse::QueryBuilder` class. The class uses the `Arel` gem to generate queries and provides a similar query interface like `ActiveRecord`.
+
+```ruby
+builder = ClickHouse::QueryBuilder.new('events')
+
+query = builder
+ .where(builder.table[:created_at].lteq(Date.today))
+ .where(id: [1,2,3])
+
+rows = ClickHouse::Client.select(query, :main)
+```
+
+## Inserting data
+
+The ClickHouse client supports inserting data through the standard query interface:
+
+```ruby
+raw_query = 'INSERT INTO events (id, target_type) VALUES ({id:UInt64}, {target_type:String})'
+placeholders = { id: 1, target_type: 'Issue' }
+
+query = ClickHouse::Client::Query.new(raw_query: raw_query, placeholders: placeholders)
+rows = ClickHouse::Client.execute(query, :main)
+```
+
+Inserting data this way is acceptable if:
+
+- The table contains settings or configuration data where we need to add one row.
+- For testing, test data has to be prepared in the database.
+
+When inserting data, we should always try to use batch processing where multiple rows are inserted at once. Building large `INSERT` queries in memory is discouraged because of the increased memory usage. Additionally, values specified within such queries cannot be redacted automatically by the client.
+
+To compress data and reduce memory usage, insert CSV data. You can do this with the internal [`CsvBuilder`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/gems/csv_builder) gem:
+
+```ruby
+iterator = Event.find_each
+
+# insert from events table using only the id and the target_type columns
+column_mapping = {
+ id: :id,
+ target_type: :target_type
+}
+
+CsvBuilder::Gzip.new(iterator, column_mapping).render do |tempfile|
+ query = 'INSERT INTO events (id, target_type) FORMAT CSV'
+ ClickHouse::Client.insert_csv(query, File.open(tempfile.path), :main)
+end
+```
+
+NOTE:
+It's important to test and verify efficient batching of database records from PostgreSQL. Consider using the techniques described in the [Iterating tables in batches](../iterating_tables_in_batches.md).
+
+## Testing
+
+ClickHouse is enabled on CI/CD but to avoid significantly affecting the pipeline runtime we've decided to run the ClickHouse server for test cases tagged with `:click_house` only.
+
+The `:click_house` tag ensures that the database schema is properly set up before every test case.
+
+```ruby
+RSpec.describe MyClickHouseFeature, :click_house do
+ it 'returns rows' do
+ rows = ClickHouse::Client.select('SELECT 1', :main)
+ expect(rows.size).to eq(1)
+ end
+end
+```
+
+## Multiple databases
+
+By design, the `ClickHouse::Client` library supports configuring multiple databases. Because we're still at a very early stage of development, we only have one database called `main`.
+
+Multi database configuration example:
+
+```yaml
+development:
+ main:
+ database: gitlab_clickhouse_main_development
+ url: 'http://localhost:8123'
+ username: clickhouse
+ password: clickhouse
+
+ user_analytics: # made up database
+ database: gitlab_clickhouse_user_analytics_development
+ url: 'http://localhost:8123'
+ username: clickhouse
+ password: clickhouse
+```
+
+## Observability
+
+All queries executed via the `ClickHouse::Client` library expose the query with performance metrics (timings, read bytes) via `ActiveSupport::Notifications`.
+
+```ruby
+ActiveSupport::Notifications.subscribe('sql.click_house') do |_, _, _, _, data|
+ puts data.inspect
+end
+```
+
+Additionally, to view the executed ClickHouse queries in web interactions, on the performance bar, next to the `ch` label select the count.
diff --git a/doc/development/database/foreign_keys.md b/doc/development/database/foreign_keys.md
index 5dda3dd55a3..84ab32d0c0b 100644
--- a/doc/development/database/foreign_keys.md
+++ b/doc/development/database/foreign_keys.md
@@ -195,5 +195,5 @@ end
```
Using a foreign key as primary key saves space but can make
-[batch counting](../internal_analytics/service_ping/implement.md#batch-counters) in [Service Ping](../service_ping/index.md) less efficient.
+[batch counting](../internal_analytics/service_ping/implement.md#batch-counters) in [Service Ping](../internal_analytics/service_ping/index.md) less efficient.
Consider using a regular `id` column if the table is relevant for Service Ping.
diff --git a/doc/development/database/index.md b/doc/development/database/index.md
index 1ee6aeaa213..70681994229 100644
--- a/doc/development/database/index.md
+++ b/doc/development/database/index.md
@@ -109,6 +109,7 @@ including the major methods:
## ClickHouse
- [Introduction](clickhouse/index.md)
+- [ClickHouse within GitLab](clickhouse/clickhouse_within_gitlab.md)
- [Optimizing query execution](clickhouse/optimization.md)
- [Rebuild GitLab features using ClickHouse 1: Activity data](clickhouse/gitlab_activity_data.md)
- [Rebuild GitLab features using ClickHouse 2: Merge Request analytics](clickhouse/merge_request_analytics.md)
@@ -118,3 +119,4 @@ including the major methods:
- [Maintenance operations](maintenance_operations.md)
- [Update multiple database objects](setting_multiple_values.md)
+- [Batch iteration in a tree hierarchy proof of concept](poc_tree_iterator.md)
diff --git a/doc/development/database/multiple_databases.md b/doc/development/database/multiple_databases.md
index 7037ab22983..4387e19b6df 100644
--- a/doc/development/database/multiple_databases.md
+++ b/doc/development/database/multiple_databases.md
@@ -11,6 +11,9 @@ To allow GitLab to scale further we
The two databases are `main` and `ci`. GitLab supports being run with either one database or two databases.
On GitLab.com we are using two separate databases.
+For the purpose of building the [Cells](../../architecture/blueprints/cells/index.md) architecture, we are decomposing
+the databases further, to introduce another database `gitlab_main_clusterwide`.
+
## GitLab Schema
For properly discovering allowed patterns between different databases
@@ -23,17 +26,22 @@ that we cannot use PostgreSQL schema due to complex migration procedures. Instea
the concept of application-level classification.
Each table of GitLab needs to have a `gitlab_schema` assigned:
-- `gitlab_main`: describes all tables that are being stored in the `main:` database (for example, like `projects`, `users`).
-- `gitlab_ci`: describes all CI tables that are being stored in the `ci:` database (for example, `ci_pipelines`, `ci_builds`).
-- `gitlab_geo`: describes all Geo tables that are being stored in the `geo:` database (for example, like `project_registry`, `secondary_usage_data`).
-- `gitlab_shared`: describes all application tables that contain data across all decomposed databases (for example, `loose_foreign_keys_deleted_records`) for models that inherit from `Gitlab::Database::SharedModel`.
-- `gitlab_internal`: describes all internal tables of Rails and PostgreSQL (for example, `ar_internal_metadata`, `schema_migrations`, `pg_*`).
-- `gitlab_pm`: describes all tables that store `package_metadata` (it is an alias for `gitlab_main`).
-- `...`: more schemas to be introduced with additional decomposed databases
+| Database | Description | Notes |
+| -------- | ----------- | ------- |
+| `gitlab_main`| All tables that are being stored in the `main:` database. | Currently, this is being replaced with `gitlab_main_cell`, for the purpose of building the [Cells](../../architecture/blueprints/cells/index.md) architecture. `gitlab_main_cell` schema describes all tables that are local to a cell in a GitLab installation. For example, `projects` and `groups` |
+| `gitlab_main_clusterwide` | All tables that are being stored cluster-wide in a GitLab installation, in the [Cells](../../architecture/blueprints/cells/index.md) architecture. For example, `users` and `application_settings` | |
+| `gitlab_ci` | All CI tables that are being stored in the `ci:` database (for example, `ci_pipelines`, `ci_builds`) | |
+| `gitlab_geo` | All Geo tables that are being stored in the `geo:` database (for example, like `project_registry`, `secondary_usage_data`) | |
+| `gitlab_shared` | All application tables that contain data across all decomposed databases (for example, `loose_foreign_keys_deleted_records`) for models that inherit from `Gitlab::Database::SharedModel`. | |
+| `gitlab_internal` | All internal tables of Rails and PostgreSQL (for example, `ar_internal_metadata`, `schema_migrations`, `pg_*`) | |
+| `gitlab_pm` | All tables that store `package_metadata`| It is an alias for `gitlab_main`|
+
+More schemas to be introduced with additional decomposed databases
The usage of schema enforces the base class to be used:
-- `ApplicationRecord` for `gitlab_main`
+- `ApplicationRecord` for `gitlab_main`/`gitlab_main_cell.`
+- `MainClusterwide::ApplicationRecord` for `gitlab_main_clusterwide`.
- `Ci::ApplicationRecord` for `gitlab_ci`
- `Geo::TrackingBase` for `gitlab_geo`
- `Gitlab::Database::SharedModel` for `gitlab_shared`
@@ -465,6 +473,20 @@ You can see a real example of using this method for fixing a cross-join in
#### Allowlist for existing cross-joins
+The easiest way of identifying a cross-join is via failing pipelines.
+
+As an example, in [!130038](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130038/diffs) we moved the `notification_settings` table to the `gitlab_main_cell` schema, by marking it as such in the `db/docs/notification_settings.yml` file.
+
+The pipeline failed with the following [error](https://gitlab.com/gitlab-org/gitlab/-/jobs/4929130983):
+
+```ruby
+Database::PreventCrossJoins::CrossJoinAcrossUnsupportedTablesError:
+
+Unsupported cross-join across 'users, notification_settings' querying 'gitlab_main_clusterwide, gitlab_main_cell' discovered when executing query 'SELECT "users".* FROM "users" WHERE "users"."id" IN (SELECT "notification_settings"."user_id" FROM ((SELECT "notification_settings"."user_id" FROM "notification_settings" WHERE "notification_settings"."source_id" = 119 AND "notification_settings"."source_type" = 'Project' AND (("notification_settings"."level" = 3 AND EXISTS (SELECT true FROM "notification_settings" "notification_settings_2" WHERE "notification_settings_2"."user_id" = "notification_settings"."user_id" AND "notification_settings_2"."source_id" IS NULL AND "notification_settings_2"."source_type" IS NULL AND "notification_settings_2"."level" = 2)) OR "notification_settings"."level" = 2))) notification_settings)'
+```
+
+To make the pipeline green, this cross-join query must be allow-listed.
+
A cross-join across databases can be explicitly allowed by wrapping the code in the
`::Gitlab::Database.allow_cross_joins_across_databases` helper method. Alternative
way is to mark a given relation as `relation.allow_cross_joins_across_databases`.
@@ -494,6 +516,30 @@ def find_actual_head_pipeline
end
```
+In model associations or scopes, this can be used as in the following example:
+
+```ruby
+class Group < Namespace
+ has_many :users, -> {
+ allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/422405")
+ }, through: :group_members
+end
+```
+
+WARNING:
+Overriding an association can have unintended consequences and may even lead to data loss, as we noticed in [issue 424307](https://gitlab.com/gitlab-org/gitlab/-/issues/424307). Do not override existing ActiveRecord associations to mark a cross-join as allowed, as in the example below.
+
+```ruby
+class Group < Namespace
+ has_many :users, through: :group_members
+
+ # DO NOT override an association like this.
+ def users
+ super.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/422405")
+ end
+end
+```
+
The `url` parameter should point to an issue with a milestone for when we intend
to fix the cross-join. If the cross-join is being used in a migration, we do not
need to fix the code. See <https://gitlab.com/gitlab-org/gitlab/-/issues/340017>
@@ -530,7 +576,42 @@ more information, look at the
[transaction guidelines](transaction_guidelines.md#dangerous-example-third-party-api-calls)
page.
-#### Fixing cross-database errors
+#### Fixing cross-database transactions
+
+A transaction across databases can be explicitly allowed by wrapping the code in the
+`Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction` helper method.
+
+For cross-database transactions in Rails callbacks, the `cross_database_ignore_tables` method can be used.
+
+These methods should only be used for existing code.
+
+The `temporary_ignore_tables_in_transaction` helper method can be used as follows:
+
+```ruby
+class GroupMember < Member
+ def update_two_factor_requirement
+ return unless user
+
+ # To mark and ignore cross-database transactions involving members and users/user_details/user_preferences
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[users user_details user_preferences], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424288'
+ ) do
+ user.update_two_factor_requirement
+ end
+ end
+end
+```
+
+The `cross_database_ignore_tables` method can be used as follows:
+
+```ruby
+class Namespace < ApplicationRecord
+ include CrossDatabaseIgnoredTables
+
+ # To mark and ignore cross-database transactions involving namespaces and routes/redirect_routes happening within Rails callbacks.
+ cross_database_ignore_tables %w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424277'
+end
+```
##### Removing the transaction block
@@ -616,6 +697,23 @@ or records that point to nowhere, which might lead to bugs. As such we created
["loose foreign keys"](loose_foreign_keys.md) which is an asynchronous
process of cleaning up orphaned records.
+### Allowlist for existing cross-database foreign keys
+
+The easiest way of identifying a cross-database foreign key is via failing pipelines.
+
+As an example, in [!130038](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130038/diffs) we moved the `notification_settings` table to the `gitlab_main_cell` schema, by marking it in the `db/docs/notification_settings.yml` file.
+
+`notification_settings.user_id` is a column that points to `users`, but the `users` table belongs to a different database, thus this is now treated as a cross-database foreign key.
+
+We have a spec to capture such cases of cross-database foreign keys in [`no_cross_db_foreign_keys_spec.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/01d3a1e41513200368a22bbab5d4312174762ee0/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb), which would fail if such a cross-database foreign key is encountered.
+
+To make the pipeline green, this cross-database foreign key must be allow-listed.
+
+To do this, explicitly allow the existing cross-database foreign key to exist by adding it as an exception in the same spec (as in [this example](https://gitlab.com/gitlab-org/gitlab/-/blob/7d99387f399c548af24d93d564b35f2f9510662d/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb#L26)).
+This way, the spec will not fail.
+
+Later, this foreign key can be converted to a loose foreign key, like we did in [!130080](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130080/diffs).
+
## Testing for multiple databases
In our testing CI pipelines, we test GitLab by default with multiple databases set up, using
diff --git a/doc/development/database/not_null_constraints.md b/doc/development/database/not_null_constraints.md
index e1b6868c68e..05b1081fc4d 100644
--- a/doc/development/database/not_null_constraints.md
+++ b/doc/development/database/not_null_constraints.md
@@ -72,8 +72,6 @@ The steps required are:
Depending on the size of the table, a background migration for cleanup could be required in the next release.
See the [`NOT NULL` constraints on large tables](not_null_constraints.md#not-null-constraints-on-large-tables) section for more information.
- - Create an issue for the next milestone to validate the `NOT NULL` constraint.
-
1. Release `N.M+1` (next release)
1. Make sure all existing records on GitLab.com have attribute set. If not, go back to step 1 from Release `N.M`.
diff --git a/doc/development/database/poc_tree_iterator.md b/doc/development/database/poc_tree_iterator.md
new file mode 100644
index 00000000000..453f77f0cde
--- /dev/null
+++ b/doc/development/database/poc_tree_iterator.md
@@ -0,0 +1,475 @@
+---
+stage: Data Stores
+group: Database
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Batch iteration in a tree hierarchy (proof of concept)
+
+The group hierarchy in GitLab is represented with a tree, where the root element
+is the top-level namespace, and the child elements are the subgroups or the
+recently introduced `Namespaces::ProjectNamespace` records.
+
+The tree is implemented in the `namespaces` table ,via the `parent_id` column.
+The column points to the parent namespace record. The top level namespace has no
+`parent_id`.
+
+Partial hierarchy of `gitlab-org`:
+
+```mermaid
+flowchart TD
+ A("gitlab-org (9979)") --- B("quality (2750817)")
+ B --- C("engineering-productivity (16947798)")
+ B --- D("performance-testing (9453799)")
+ A --- F("charts (5032027)")
+ A --- E("ruby (14018648)")
+```
+
+Efficiently iterating over the group hierarchy has several potential use cases.
+This is true especially in background jobs, which need to perform queries on the group hierarchy,
+where stable and safe execution is more important than fast runtime. Batch iteration
+requires more network round-trips, but each batch provides similar performance
+characteristics.
+
+A few examples:
+
+- For each subgroup, do something.
+- For each project in the hierarchy, do something.
+- For each issue in the hierarchy, do something.
+
+## Problem statement
+
+A group hierarchy could grow so big that a single query would not be able to load
+it in time. The query would fail with statement timeout error.
+
+Addressing scalability issues related to very large groups requires us to store
+the same data in different formats (de-normalization). However, if we're unable
+to load the group hierarchy, then de-normalization could not be implemented.
+
+One de-normalization technique would be to store all descendant group IDs for a
+given group. This would speed up queries where we need to load the group and its
+subgroups. Example:
+
+```mermaid
+flowchart TD
+ A(1) --- B(2)
+ A --- C(3)
+ C --- D(4)
+```
+
+| GROUP_ID | DESCENDANT_GROUP_IDS |
+|----------|------------------------|
+| 1 | `[2,3,4]` |
+| 2 | `[]` |
+| 3 | `[4]` |
+| 4 | `[]` |
+
+With this structure, determining all the subgroups would require us to read only
+one row from the database, instead of 4 rows. For a hierarchy as big as 1000 groups,
+this could make a huge difference.
+
+The reading of the hierarchy problem is solved with this de-normalization. However,
+we still need to find a way to persist this data in a table. Because a group and
+its hierarchy could grow very large, we cannot expect a single query to work here.
+
+```sql
+SELECT id FROM namespaces WHERE traversal_ids && ARRAY[9970]
+```
+
+The query above could time out for large groups, so we need to process the data in batches.
+
+Implementing batching logic in a tree is not something we've looked at before,
+and it's fairly complex to implement. An `EachBatch` or `find_in_batches` based
+solution would not work because:
+
+- The data (group IDs) are not sorted in the hierarchy.
+- Groups in sub groups don't know about the top-level group ID.
+
+## Algorithm
+
+The batching query is implemented as a recursive CTE SQL query, where one batch
+would read a maximum of N rows. Due to the tree structure, reading N rows might
+not necessarily mean that we're reading N group IDs. If the tree is structured in
+a non-optimal way, a batch could return less (but never more) group IDs.
+
+The query implements a [depth-first](https://en.wikipedia.org/wiki/Depth-first_search)
+tree walking logic, where the DB scans the first branch of the tree until the leaf
+element. We're implementing depth-first algorithm because, when a batch is finished,
+the query must return enough information for the next batch (cursor). In GitLab,
+we limit the depth of the tree to 20, which means that in the worst case, the
+query would return a cursor containing 19 elements.
+
+Implementing a [breadth-first](https://en.wikipedia.org/wiki/Breadth-first_search)
+tree walking algorithm would be impractical, because a group can have unbounded
+number of descendants, thus we might end up with a huge cursor.
+
+1. Create an initializer row that contains:
+ 1. The currently processed group ID (top-level group ID)
+ 1. Two arrays (tree depth and the collected IDs)
+ 1. A counter for tracking the number of row reads in the query.
+1. Recursively process the row and do one of the following (whenever the condition matches):
+ - Load the first child namespace and update the currently processed namespace
+ ID if we're not at the leaf node. (Walking down a branch)
+ - Load the next namespace record on the current depth if there are any rows left.
+ - Walk up one node and process rows at one level higher.
+1. Continue the processing until the number of reads reaches our `LIMIT` (batch size).
+1. Find the last processed row which contains the data for the cursor, and all the collected record IDs.
+
+```sql
+WITH RECURSIVE result AS (
+ (
+ SELECT
+ 9970 AS current_id, /* current namespace id we're processing */
+ ARRAY[9970]::int[] AS depth, /* cursor */
+ ARRAY[9970]::int[] AS ids, /* collected ids */
+ 1::bigint AS reads,
+ 'initialize' AS action
+ ) UNION ALL
+ (
+ WITH cte AS ( /* trick for referencing the result cte multiple times */
+ select * FROM result
+ )
+ SELECT * FROM (
+ (
+ SELECT /* walk down the branch */
+ namespaces.id,
+ cte.depth || namespaces.id,
+ cte.ids || namespaces.id,
+ cte.reads + 1,
+ 'walkdown'
+ FROM namespaces, cte
+ WHERE
+ namespaces.parent_id = cte.current_id
+ ORDER BY namespaces.id ASC
+ LIMIT 1
+ ) UNION ALL
+ (
+ SELECT /* find next element on the same level */
+ namespaces.id,
+ cte.depth[:array_length(cte.depth, 1) - 1] || namespaces.id,
+ cte.ids || namespaces.id,
+ cte.reads + 1,
+ 'next'
+ FROM namespaces, cte
+ WHERE
+ namespaces.parent_id = cte.depth[array_length(cte.depth, 1) - 1] AND
+ namespaces.id > cte.depth[array_length(cte.depth, 1)]
+ ORDER BY namespaces.id ASC
+ LIMIT 1
+ ) UNION ALL
+ (
+ SELECT /* jump up one node when finished with the current level */
+ cte.current_id,
+ cte.depth[:array_length(cte.depth, 1) - 1],
+ cte.ids,
+ cte.reads + 1,
+ 'jump'
+ FROM cte
+ WHERE cte.depth <> ARRAY[]::int[]
+ LIMIT 1
+ )
+ ) next_row LIMIT 1
+ )
+)
+SELECT current_id, depth, ids, action
+FROM result
+```
+
+```plaintext
+ current_id | depth | ids | action
+------------+--------------+------------------------+------------
+ 24 | {24} | {24} | initialize
+ 25 | {24,25} | {24,25} | walkdown
+ 26 | {24,26} | {24,25,26} | next
+ 112 | {24,112} | {24,25,26,112} | next
+ 113 | {24,113} | {24,25,26,112,113} | next
+ 114 | {24,113,114} | {24,25,26,112,113,114} | walkdown
+ 114 | {24,113} | {24,25,26,112,113,114} | jump
+ 114 | {24} | {24,25,26,112,113,114} | jump
+ 114 | {} | {24,25,26,112,113,114} | jump
+```
+
+NOTE:
+Using this query to find all the namespace IDs in a group hierarchy is likely slower
+than other querying methods, such as the current `self_and_descendants` implementation
+based on the `traversal_ids` column. The query above should be only used when
+implementing batch iteration over the group hierarchy.
+
+Rudimentary batching implementation in Ruby:
+
+```ruby
+class NamespaceEachBatch
+ def initialize(namespace_id:, cursor: nil)
+ @namespace_id = namespace_id
+ @cursor = cursor || { current_id: namespace_id, depth: [namespace_id] }
+ end
+
+ def each_batch(of: 500)
+ current_cursor = cursor.dup
+
+ first_iteration = true
+ loop do
+ new_cursor, ids = load_batch(cursor: current_cursor, of: of, first_iteration: first_iteration)
+ first_iteration = false
+ current_cursor = new_cursor
+
+ yield ids
+
+ break if new_cursor[:depth].empty?
+ end
+ end
+
+ private
+
+ # yields array of namespace ids
+ def load_batch(cursor:, of:, first_iteration: false)
+ recursive_cte = Gitlab::SQL::RecursiveCTE.new(:result,
+ union_args: { remove_order: false, remove_duplicates: false })
+
+ ids = first_iteration ? namespace_id.to_s : ""
+
+ recursive_cte << Namespace.select(
+ Arel.sql(Integer(cursor.fetch(:current_id)).to_s).as('current_id'),
+ Arel.sql("ARRAY[#{cursor.fetch(:depth).join(',')}]::int[]").as('depth'),
+ Arel.sql("ARRAY[#{ids}]::int[]").as('ids'),
+ Arel.sql("1::bigint AS count")
+ ).from('(VALUES (1)) AS does_not_matter').limit(1)
+
+ cte = Gitlab::SQL::CTE.new(:cte, Namespace.select('*').from('result'))
+
+ union_query = Namespace.with(cte.to_arel).from_union(
+ walk_down,
+ next_elements,
+ up_one_level,
+ remove_duplicates: false,
+ remove_order: false
+ ).select('current_id', 'depth', 'ids', 'count').limit(1)
+
+ recursive_cte << union_query
+
+ scope = Namespace.with
+ .recursive(recursive_cte.to_arel)
+ .from(recursive_cte.alias_to(Namespace.arel_table))
+ .limit(of)
+ row = Namespace.from(scope.arel.as('namespaces')).order(count: :desc).limit(1).first
+
+ [
+ { current_id: row[:current_id], depth: row[:depth] },
+ row[:ids]
+ ]
+ end
+
+ attr_reader :namespace_id, :cursor
+
+ def walk_down
+ Namespace.select(
+ Arel.sql('namespaces.id').as('current_id'),
+ Arel.sql('cte.depth || namespaces.id').as('depth'),
+ Arel.sql('cte.ids || namespaces.id').as('ids'),
+ Arel.sql('cte.count + 1').as('count')
+ ).from('cte, LATERAL (SELECT id FROM namespaces WHERE parent_id = cte.current_id ORDER BY id LIMIT 1) namespaces')
+ end
+
+ def next_elements
+ Namespace.select(
+ Arel.sql('namespaces.id').as('current_id'),
+ Arel.sql('cte.depth[:array_length(cte.depth, 1) - 1] || namespaces.id').as('depth'),
+ Arel.sql('cte.ids || namespaces.id').as('ids'),
+ Arel.sql('cte.count + 1').as('count')
+ ).from('cte, LATERAL (SELECT id FROM namespaces WHERE namespaces.parent_id = cte.depth[array_length(cte.depth, 1) - 1] AND namespaces.id > cte.depth[array_length(cte.depth, 1)] ORDER BY id LIMIT 1) namespaces')
+ end
+
+ def up_one_level
+ Namespace.select(
+ Arel.sql('cte.current_id').as('current_id'),
+ Arel.sql('cte.depth[:array_length(cte.depth, 1) - 1]').as('depth'),
+ Arel.sql('cte.ids').as('ids'),
+ Arel.sql('cte.count + 1').as('count')
+ ).from('cte')
+ .where('cte.depth <> ARRAY[]::int[]')
+ .limit(1)
+ end
+end
+
+iterator = NamespaceEachBatch.new(namespace_id: 9970)
+all_ids = []
+iterator.each_batch do |ids|
+ all_ids.concat(ids)
+end
+
+# Test
+puts all_ids.count
+puts all_ids.sort == Namespace.where('traversal_ids && ARRAY[9970]').pluck(:id).sort
+```
+
+Example batch query:
+
+```sql
+SELECT
+ "namespaces".*
+FROM ( WITH RECURSIVE "result" AS ((
+ SELECT
+ 15847356 AS current_id,
+ ARRAY[9970,
+ 12061481,
+ 12128714,
+ 12445111,
+ 15847356]::int[] AS depth,
+ ARRAY[]::int[] AS ids,
+ 1::bigint AS count
+ FROM (
+ VALUES (1)) AS does_not_matter
+ LIMIT 1)
+ UNION ALL ( WITH "cte" AS MATERIALIZED (
+ SELECT
+ *
+ FROM
+ result
+)
+ SELECT
+ current_id,
+ depth,
+ ids,
+ count
+ FROM ((
+ SELECT
+ namespaces.id AS current_id,
+ cte.depth || namespaces.id AS depth,
+ cte.ids || namespaces.id AS ids,
+ cte.count + 1 AS count
+ FROM
+ cte,
+ LATERAL (
+ SELECT
+ id
+ FROM
+ namespaces
+ WHERE
+ parent_id = cte.current_id
+ ORDER BY
+ id
+ LIMIT 1
+) namespaces
+)
+ UNION ALL (
+ SELECT
+ namespaces.id AS current_id,
+ cte.depth[:array_length(
+ cte.depth, 1
+) - 1] || namespaces.id AS depth,
+ cte.ids || namespaces.id AS ids,
+ cte.count + 1 AS count
+ FROM
+ cte,
+ LATERAL (
+ SELECT
+ id
+ FROM
+ namespaces
+ WHERE
+ namespaces.parent_id = cte.depth[array_length(
+ cte.depth, 1
+) - 1]
+ AND namespaces.id > cte.depth[array_length(
+ cte.depth, 1
+)]
+ ORDER BY
+ id
+ LIMIT 1
+) namespaces
+)
+ UNION ALL (
+ SELECT
+ cte.current_id AS current_id,
+ cte.depth[:array_length(
+ cte.depth, 1
+) - 1] AS depth,
+ cte.ids AS ids,
+ cte.count + 1 AS count
+ FROM
+ cte
+ WHERE (
+ cte.depth <> ARRAY[]::int[]
+)
+ LIMIT 1
+)
+) namespaces
+ LIMIT 1
+))
+SELECT
+ "namespaces".*
+FROM
+ "result" AS "namespaces"
+LIMIT 500) namespaces
+ORDER BY
+ "count" DESC
+LIMIT 1
+```
+
+Execution plan:
+
+```plaintext
+ Limit (cost=16.36..16.36 rows=1 width=76) (actual time=436.963..436.970 rows=1 loops=1)
+ Buffers: shared hit=3721 read=423 dirtied=8
+ I/O Timings: read=412.590 write=0.000
+ -> Sort (cost=16.36..16.39 rows=11 width=76) (actual time=436.961..436.968 rows=1 loops=1)
+ Sort Key: namespaces.count DESC
+ Sort Method: top-N heapsort Memory: 27kB
+ Buffers: shared hit=3721 read=423 dirtied=8
+ I/O Timings: read=412.590 write=0.000
+ -> Limit (cost=15.98..16.20 rows=11 width=76) (actual time=0.005..436.394 rows=500 loops=1)
+ Buffers: shared hit=3718 read=423 dirtied=8
+ I/O Timings: read=412.590 write=0.000
+ CTE result
+ -> Recursive Union (cost=0.00..15.98 rows=11 width=76) (actual time=0.003..432.924 rows=500 loops=1)
+ Buffers: shared hit=3718 read=423 dirtied=8
+ I/O Timings: read=412.590 write=0.000
+ -> Limit (cost=0.00..0.01 rows=1 width=76) (actual time=0.002..0.003 rows=1 loops=1)
+ I/O Timings: read=0.000 write=0.000
+ -> Result (cost=0.00..0.01 rows=1 width=76) (actual time=0.001..0.002 rows=1 loops=1)
+ I/O Timings: read=0.000 write=0.000
+ -> Limit (cost=0.76..1.57 rows=1 width=76) (actual time=0.862..0.862 rows=1 loops=499)
+ Buffers: shared hit=3718 read=423 dirtied=8
+ I/O Timings: read=412.590 write=0.000
+ CTE cte
+ -> WorkTable Scan on result (cost=0.00..0.20 rows=10 width=76) (actual time=0.000..0.000 rows=1 loops=499)
+ I/O Timings: read=0.000 write=0.000
+ -> Append (cost=0.56..17.57 rows=21 width=76) (actual time=0.862..0.862 rows=1 loops=499)
+ Buffers: shared hit=3718 read=423 dirtied=8
+ I/O Timings: read=412.590 write=0.000
+ -> Nested Loop (cost=0.56..7.77 rows=10 width=76) (actual time=0.675..0.675 rows=0 loops=499)
+ Buffers: shared hit=1693 read=357 dirtied=1
+ I/O Timings: read=327.812 write=0.000
+ -> CTE Scan on cte (cost=0.00..0.20 rows=10 width=76) (actual time=0.001..0.001 rows=1 loops=499)
+ I/O Timings: read=0.000 write=0.000
+ -> Limit (cost=0.56..0.73 rows=1 width=4) (actual time=0.672..0.672 rows=0 loops=499)
+ Buffers: shared hit=1693 read=357 dirtied=1
+ I/O Timings: read=327.812 write=0.000
+ -> Index Only Scan using index_namespaces_on_parent_id_and_id on public.namespaces namespaces_1 (cost=0.56..5.33 rows=29 width=4) (actual time=0.671..0.671 rows=0 loops=499)
+ Index Cond: (namespaces_1.parent_id = cte.current_id)
+ Heap Fetches: 7
+ Buffers: shared hit=1693 read=357 dirtied=1
+ I/O Timings: read=327.812 write=0.000
+ -> Nested Loop (cost=0.57..9.45 rows=10 width=76) (actual time=0.208..0.208 rows=1 loops=442)
+ Buffers: shared hit=2025 read=66 dirtied=7
+ I/O Timings: read=84.778 write=0.000
+ -> CTE Scan on cte cte_1 (cost=0.00..0.20 rows=10 width=72) (actual time=0.000..0.000 rows=1 loops=442)
+ I/O Timings: read=0.000 write=0.000
+ -> Limit (cost=0.57..0.89 rows=1 width=4) (actual time=0.203..0.203 rows=1 loops=442)
+ Buffers: shared hit=2025 read=66 dirtied=7
+ I/O Timings: read=84.778 write=0.000
+ -> Index Only Scan using index_namespaces_on_parent_id_and_id on public.namespaces namespaces_2 (cost=0.57..3.77 rows=10 width=4) (actual time=0.201..0.201 rows=1 loops=442)
+ Index Cond: ((namespaces_2.parent_id = (cte_1.depth)[(array_length(cte_1.depth, 1) - 1)]) AND (namespaces_2.id > (cte_1.depth)[array_length(cte_1.depth, 1)]))
+ Heap Fetches: 35
+ Buffers: shared hit=2025 read=66 dirtied=6
+ I/O Timings: read=84.778 write=0.000
+ -> Limit (cost=0.00..0.03 rows=1 width=76) (actual time=0.003..0.003 rows=1 loops=59)
+ I/O Timings: read=0.000 write=0.000
+ -> CTE Scan on cte cte_2 (cost=0.00..0.29 rows=9 width=76) (actual time=0.002..0.002 rows=1 loops=59)
+ Filter: (cte_2.depth <> '{}'::integer[])
+ Rows Removed by Filter: 0
+ I/O Timings: read=0.000 write=0.000
+ -> CTE Scan on result namespaces (cost=0.00..0.22 rows=11 width=76) (actual time=0.005..436.240 rows=500 loops=1)
+ Buffers: shared hit=3718 read=423 dirtied=8
+ I/O Timings: read=412.590 write=0.000
+```
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index bb0bfbc759b..ba0423a1a0d 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -173,10 +173,11 @@ Include in the MR description:
##### Query Plans
- The query plan for each raw SQL query included in the merge request along with the link to the query plan following each raw SQL snippet.
-- Provide a link to the plan generated using the `explain` command in the [postgres.ai](database/database_lab.md) chatbot.
- - If it's not possible to get an accurate picture in Database Lab, you may need to seed a development environment, and instead provide links
- from [explain.depesz.com](https://explain.depesz.com) or [explain.dalibo.com](https://explain.dalibo.com). Be sure to paste both the plan
- and the query used in the form.
+- Provide a link to the plan generated using the `explain` command in the [postgres.ai](database/database_lab.md) chatbot. The `explain` command runs
+ `EXPLAIN ANALYZE`.
+ - If it's not possible to get an accurate picture in Database Lab, you may need to
+ seed a development environment, and instead provide output
+ from `EXPLAIN ANALYZE`. Create links to the plan using [explain.depesz.com](https://explain.depesz.com) or [explain.dalibo.com](https://explain.dalibo.com). Be sure to paste both the plan and the query used in the form.
- When providing query plans, make sure it hits enough data:
- To produce a query plan with enough data, you can use the IDs of:
- The `gitlab-org` namespace (`namespace_id = 9970`), for queries involving a group.
@@ -192,6 +193,13 @@ Include in the MR description:
plan _before_ and _after_ the change. This helps spot differences quickly.
- Include data that shows the performance improvement, preferably in
the form of a benchmark.
+- When evaluating a query plan, we need the final query to be
+ executed against the database. We don't need to analyze the intermediate
+ queries returned as `ActiveRecord::Relation` from finders and scopes.
+ PostgreSQL query plans are dependent on all the final parameters,
+ including limits and other things that may be added before final execution.
+ One way to be sure of the actual query executed is to check
+ `log/development.log`.
#### Preparation when adding foreign keys to existing tables
diff --git a/doc/development/development_seed_files.md b/doc/development/development_seed_files.md
new file mode 100644
index 00000000000..2bf3688fd48
--- /dev/null
+++ b/doc/development/development_seed_files.md
@@ -0,0 +1,26 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Development seed files
+
+Development seed files are listed under `gitlab/db/fixtures/development/` and `gitlab/ee/db/fixtures/development/`
+folders. These files are used to populate the database with records to help verifying if feature functionalities, like charts, are working as expected on local host.
+
+The task `rake db:seed_fu` can be used to run all development seeds with the exception of the ones under a flag which is usually passed as an environment variable.
+
+The following table summarizes the seeds and tasks that can be used to generate
+data for features.
+
+| Feature | Command | Seed |
+|-------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
+| DevOps Adoption | `FILTER=devops_adoption bundle exec rake db:seed_fu` | [31_devops_adoption.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/db/fixtures/development/31_devops_adoption.rb) |
+| Value Streams Dashboard | `FILTER=cycle_analytics SEED_VSA=1 bundle exec rake db:seed_fu` | [17_cycle_analytics.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/db/fixtures/development/17_cycle_analytics.rb) |
+| Value Stream Analytics | `FILTER=customizable_cycle_analytics SEED_CUSTOMIZABLE_CYCLE_ANALYTICS=1 bundle exec rake db:seed_fu` | [30_customizable_cycle_analytics](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/db/fixtures/development/30_customizable_cycle_analytics.rb) |
+| CI/CD analytics | `FILTER=ci_cd_analytics SEED_CI_CD_ANALYTICS=1 bundle exec rake db:seed_fu` | [38_ci_cd_analytics](https://gitlab.com/gitlab-org/gitlab/-/blob/master/db/fixtures/development/38_ci_cd_analytics.rb?ref_type=heads) |
+| Contributions Analytics<br><br>Productivity Analytics<br><br>Code review Analytics<br><br>Merge Request Analytics | `FILTER=productivity_analytics SEED_PRODUCTIVITY_ANALYTICS=1 bundle exec rake db:seed_fu` | [90_productivity_analytics](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/db/fixtures/development/90_productivity_analytics.rb) |
+| Repository Analytics | `FILTER=14_pipelines NEW_PROJECT=1 bundle exec rake db:seed_fu` | [14_pipelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/db/fixtures/development/14_pipelines.rb?ref_type=heads) |
+| Issue Analytics<br><br>Insights | `NEW_PROJECT=1 bin/rake gitlab:seed:insights:issues` | [insights Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/seed/insights.rake) |
+| DORA metrics | `SEED_DORA=1 FILTER=dora_metrics bundle exec rake db:seed_fu` | [92_dora_metrics](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/db/fixtures/development/92_dora_metrics.rb) |
diff --git a/doc/development/documentation/alpha_beta.md b/doc/development/documentation/alpha_beta.md
index 61f07e79e12..4579c57b448 100644
--- a/doc/development/documentation/alpha_beta.md
+++ b/doc/development/documentation/alpha_beta.md
@@ -1,49 +1,11 @@
---
-info: For assistance with this Style Guide page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects
-stage: none
-group: unassigned
+redirect_to: 'experiment_beta.md'
+remove_date: '2023-11-29'
---
-# Documenting Experiment and Beta features
+This document was moved to [another location](experiment_beta.md).
-Some features are not generally available and are instead considered
-[Experiment or Beta](../../policy/experiment-beta-support.md).
-
-When you document a feature in one of these three statuses:
-
-- Add `(Experiment)` or `(Beta)` in parentheses after the page or topic title.
-- Do not include `(Experiment)` or `(Beta)` in the left nav.
-- Ensure the version history lists the feature's status.
-
-These features are usually behind a feature flag, which follow [these documentation guidelines](feature_flags.md).
-
-If you add details of how users should enroll, or how to contact the team with issues,
-the `FLAG:` note should be above these details.
-
-For example:
-
-```markdown
-## Great new feature (Experiment)
-
-> [Introduced](link) in GitLab 15.10. This feature is an [Experiment](<link_to>/policy/experiment-beta-support.md).
-
-FLAG:
-On self-managed GitLab, by default this feature is not available.
-To make it available, an administrator can enable the feature flag named `example_flag`.
-On GitLab.com, this feature is not available. This feature is not ready for production use.
-
-Use this great new feature when you need to do this new thing.
-
-This feature is an [Experiment](<link_to>/policy/experiment-beta-support.md). To join
-the list of users testing this feature, do this thing. If you find a bug,
-[open an issue](link).
-```
-
-When the feature is ready for production, remove:
-
-- The text in parentheses.
-- Any language about the feature not being ready for production in the body
- description.
-- The feature flag information if available.
-
-Ensure the version history is up-to-date by adding a note about the production release.
+<!-- This redirect file can be deleted after <2023-11-29>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/development/documentation/experiment_beta.md b/doc/development/documentation/experiment_beta.md
new file mode 100644
index 00000000000..fab78082cb5
--- /dev/null
+++ b/doc/development/documentation/experiment_beta.md
@@ -0,0 +1,49 @@
+---
+info: For assistance with this Style Guide page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects
+stage: none
+group: unassigned
+---
+
+# Documenting Experiment and Beta features
+
+Some features are not generally available and are instead considered
+[Experiment or Beta](../../policy/experiment-beta-support.md).
+
+When you document a feature in one of these three statuses:
+
+- Add the tier badge after the page or topic title.
+- Do not include `(Experiment)` or `(Beta)` in the left nav.
+- Ensure the version history lists the feature's status.
+
+These features are usually behind a feature flag, which follow [these documentation guidelines](feature_flags.md).
+
+If you add details of how users should enroll, or how to contact the team with issues,
+the `FLAG:` note should be above these details.
+
+For example:
+
+```markdown
+## Great new feature **(EXPERIMENT)**
+
+> [Introduced](link) in GitLab 15.10. This feature is an [Experiment](<link_to>/policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available.
+To make it available, an administrator can enable the feature flag named `example_flag`.
+On GitLab.com, this feature is not available. This feature is not ready for production use.
+
+Use this great new feature when you need to do this new thing.
+
+This feature is an [Experiment](<link_to>/policy/experiment-beta-support.md). To join
+the list of users testing this feature, do this thing. If you find a bug,
+[open an issue](link).
+```
+
+When the feature is ready for production, remove:
+
+- The text in parentheses.
+- Any language about the feature not being ready for production in the body
+ description.
+- The feature flag information if available.
+
+Ensure the version history is up-to-date by adding a note about the production release.
diff --git a/doc/development/documentation/help.md b/doc/development/documentation/help.md
index fb730aca6f0..a921429bf49 100644
--- a/doc/development/documentation/help.md
+++ b/doc/development/documentation/help.md
@@ -28,9 +28,6 @@ For example:
1. The change shows up in the 14.5 self-managed release, due to missing the release cutoff
for 14.4.
-The exact cutoff date for each release is flexible, and can be sooner or later
-than expected due to holidays, weekends or other events. In general, MRs merged
-by the 17th should be present in the release on the 22nd, though it is not guaranteed.
If it is important that a documentation update is present in that month's release,
merge it as early as possible.
diff --git a/doc/development/documentation/restful_api_styleguide.md b/doc/development/documentation/restful_api_styleguide.md
index a5d565ffa79..a53330a7e63 100644
--- a/doc/development/documentation/restful_api_styleguide.md
+++ b/doc/development/documentation/restful_api_styleguide.md
@@ -146,7 +146,7 @@ Sort the table by required attributes first, then alphabetically.
| Attribute | Type | Required | Description |
|------------------------------|---------------|----------|-----------------------------------------------------|
| `title` | string | Yes | Title of the issue. |
-| `assignee_ids` **(PREMIUM)** | integer array | No | IDs of the users to assign the issue to. |
+| `assignee_ids` **(PREMIUM ALL)** | integer array | No | IDs of the users to assign the issue to. |
| `confidential` | boolean | No | Sets the issue to confidential. Default is `false`. |
```
@@ -155,7 +155,7 @@ Rendered example:
| Attribute | Type | Required | Description |
|------------------------------|---------------|----------|-----------------------------------------------------|
| `title` | string | Yes | Title of the issue. |
-| `assignee_ids` **(PREMIUM)** | integer array | No | IDs of the users to assign the issue to. |
+| `assignee_ids` **(PREMIUM ALL)** | integer array | No | IDs of the users to assign the issue to. |
| `confidential` | boolean | No | Sets the issue to confidential. Default is `false`. |
For information about writing attribute descriptions, see the [GraphQL API description style guide](../api_graphql_styleguide.md#description-style-guide).
@@ -181,7 +181,7 @@ Sort the table alphabetically.
```markdown
| Attribute | Type | Description |
|------------------------------|---------------|-------------------------------------------|
-| `assignee_ids` **(PREMIUM)** | integer array | IDs of the users to assign the issue to. |
+| `assignee_ids` **(PREMIUM ALL)** | integer array | IDs of the users to assign the issue to. |
| `confidential` | boolean | Whether the issue is confidential or not. |
| `title` | string | Title of the issue. |
```
@@ -190,7 +190,7 @@ Rendered example:
| Attribute | Type | Description |
|------------------------------|---------------|-------------------------------------------|
-| `assignee_ids` **(PREMIUM)** | integer array | IDs of the users to assign the issue to. |
+| `assignee_ids` **(PREMIUM ALL)** | integer array | IDs of the users to assign the issue to. |
| `confidential` | boolean | Whether the issue is confidential or not. |
| `title` | string | Title of the issue. |
diff --git a/doc/development/documentation/review_apps.md b/doc/development/documentation/review_apps.md
index adc9d727844..483145d1f44 100644
--- a/doc/development/documentation/review_apps.md
+++ b/doc/development/documentation/review_apps.md
@@ -16,6 +16,7 @@ Review apps are enabled for the following projects:
- [Omnibus GitLab](https://gitlab.com/gitlab-org/omnibus-gitlab)
- [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner)
- [GitLab Charts](https://gitlab.com/gitlab-org/charts/gitlab)
+- [GitLab Operator](https://gitlab.com/gitlab-org/cloud-native/gitlab-operator)
Alternatively, check the [`gitlab-docs` development guide](https://gitlab.com/gitlab-org/gitlab-docs/blob/main/README.md#development-when-contributing-to-gitlab-documentation)
or [the GDK documentation](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/howto/gitlab_docs.md)
diff --git a/doc/development/documentation/site_architecture/automation.md b/doc/development/documentation/site_architecture/automation.md
new file mode 100644
index 00000000000..5b2b02ad97e
--- /dev/null
+++ b/doc/development/documentation/site_architecture/automation.md
@@ -0,0 +1,77 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Automated pages
+
+Most pages in the GitLab documentation are written manually in Markdown.
+However, some pages are created by automated processes.
+
+Two primary categories of automation exist in the GitLab documentation:
+
+- Content that is generated by using a standard process and structured data (for example, YAML or JSON files).
+- Content that is generated by any other means.
+
+Automation helps with consistency and speed. But content that is automated in a
+non-standard way causes difficulty with:
+
+- Frontend changes.
+- Site troubleshooting and maintenance.
+- The contributor experience.
+
+Ideally, any automation should be done in a standard way, which helps alleviate some of the downsides.
+
+## Pages generated from structured data
+
+Some functionality on the docs site uses structured data:
+
+- Hierarchical global navigation (YAML)
+- Survey banner (YAML)
+- Badges (YAML)
+- Homepage content lists (YAML)
+- Redirects (YAML)
+- Versions menu (JSON)
+
+## Pages generated otherwise
+
+Other pages are generated by using non-standard processes. These pages often use solutions
+that are coded across multiple repositories.
+
+| Page | Details | Owner |
+|---|---|---|
+| [All feature flags in GitLab](../../../user/feature_flags.md) | [Generated during docs build](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/doc/raketasks.md#generate-the-feature-flag-tables) | [Technical Writing](https://about.gitlab.com/handbook/product/ux/technical-writing/) |
+| [GitLab Runner feature flags](https://docs.gitlab.com/runner/configuration/feature-flags.html) | [Page source](https://gitlab.com/gitlab-org/gitlab-runner/-/blob/ec6e1797d2173a95c8ac7f726bd62f6f110b7211/docs/configuration/feature-flags.md?plain=1#L39) | [Runner](https://about.gitlab.com/handbook/engineering/development/ops/verify/runner/) |
+| [Deprecations and removals by version](../../../update/deprecations.md) | [Deprecating GitLab features](../../deprecation_guidelines/index.md) | |
+| [GraphQL API resources](../../../api/graphql/reference/index.md) | [GraphQL API style guide](../../api_graphql_styleguide.md#documentation-and-schema) | [Import and Integrate](https://about.gitlab.com/handbook/engineering/development/dev/manage/import-and-integrate/) |
+| [Audit event types](../../../administration/audit_event_streaming/audit_event_types.md) | [Audit event development guidelines](../../audit_event_guide/index.md) | [Compliance](https://about.gitlab.com/handbook/engineering/development/sec/govern/compliance/) |
+| DAST vulnerability check documentation ([Example](../../../user/application_security/dast/checks/798.19.md)) | [How to generate the Markdown](https://gitlab.com/gitlab-org/security-products/dast-cwe-checks/-/blob/main/doc/how-to-generate-the-markdown-documentation.md) | [Dynamic Analysis](https://about.gitlab.com/handbook/product/categories/#dynamic-analysis-group) |
+| Blueprints ([Example](../../../architecture/blueprints/ci_data_decay/pipeline_partitioning.md)) | | |
+| [The docs homepage](../../../index.md) | | [Technical Writing](https://about.gitlab.com/handbook/product/ux/technical-writing/) |
+
+## Make an automation request
+
+If you want to automate a page on the docs site:
+
+1. Review [issue 823](https://gitlab.com/gitlab-org/gitlab-docs/-/issues/823)
+ and consider adding feedback there.
+1. If that issue does not describe what you need, contact
+ [the DRI for the docs site backend](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects).
+
+Because automation adds extra complexity and a support burden, we
+review it on a case-by-case basis.
+
+## Document the automation
+
+If you do add automation, you must document:
+
+- The list of files that are included.
+- The `.gitlab-ci.yml` updates and any pipeline requirements.
+- The steps needed to troubleshoot.
+
+Other GitLab team members should be able to easily find information about how to maintain the automation.
+You should announce the change widely, including, at a minimum:
+
+- In Slack, in `#whats-happening-at-gitlab`.
+- In the Technical Writer team meeting agenda.
diff --git a/doc/development/documentation/site_architecture/deployment_process.md b/doc/development/documentation/site_architecture/deployment_process.md
index 2ba69ca0987..767fdf907d6 100644
--- a/doc/development/documentation/site_architecture/deployment_process.md
+++ b/doc/development/documentation/site_architecture/deployment_process.md
@@ -66,12 +66,12 @@ graph TD
C["14.2 MR merged"]
D["13.12 MR merged"]
E["12.10 MR merged"]
- F{{"Container registry on `gitlab-docs` project"}}
- A--"`image:docs-single`<br>job runs and pushes<br>`gitlab-docs:14.4` image"-->F
- B--"`image:docs-single`<br>job runs and pushes<br>`gitlab-docs:14.3` image"-->F
- C--"`image:docs-single`<br>job runs and pushes<br>`gitlab-docs:14.2` image"-->F
- D--"`image:docs-single`<br>job runs and pushes<br>`gitlab-docs:13.12` image"-->F
- E--"`image:docs-single`<br>job runs and pushes<br>`gitlab-docs:12.10` image"-->F
+ F{{"Container registry on gitlab-docs project"}}
+ A--"image:docs-single<br>job runs and pushes<br>gitlab-docs:14.4 image"-->F
+ B--"image:docs-single<br>job runs and pushes<br>gitlab-docs:14.3 image"-->F
+ C--"image:docs-single<br>job runs and pushes<br>gitlab-docs:14.2 image"-->F
+ D--"image:docs-single<br>job runs and pushes<br>gitlab-docs:13.12 image"-->F
+ E--"image:docs-single<br>job runs and pushes<br>gitlab-docs:12.10 image"-->F
```
### Rebuild stable documentation images
@@ -104,23 +104,23 @@ For example, [a pipeline](https://gitlab.com/gitlab-org/gitlab-docs/-/pipelines/
```mermaid
graph TD
- A["Latest `gitlab`, `gitlab-runner`<br>`omnibus-gitlab`, and `charts`"]
- subgraph "Container registry on `gitlab-docs` project"
- B["14.4 versioned docs<br>`gitlab-docs:14.4`"]
- C["14.3 versioned docs<br>`gitlab-docs:14.3`"]
- D["14.2 versioned docs<br>`gitlab-docs:14.2`"]
- E["13.12 versioned docs<br>`gitlab-docs:13.12`"]
- F["12.10 versioned docs<br>`gitlab-docs:12.10`"]
+ A["Latest gitlab, gitlab-runner<br>omnibus-gitlab, and charts"]
+ subgraph "Container registry on gitlab-docs project"
+ B["14.4 versioned docs<br>gitlab-docs:14.4"]
+ C["14.3 versioned docs<br>gitlab-docs:14.3"]
+ D["14.2 versioned docs<br>gitlab-docs:14.2"]
+ E["13.12 versioned docs<br>gitlab-docs:13.12"]
+ F["12.10 versioned docs<br>gitlab-docs:12.10"]
end
- G[["Scheduled pipeline<br>`image:docs-latest` job<br>combines all these"]]
+ G[["Scheduled pipeline<br>image:docs-latest job<br>combines all these"]]
A--"Default branches<br>pulled down"-->G
- B--"`gitlab-docs:14.4` image<br>pulled down"-->G
- C--"`gitlab-docs:14.3` image<br>pulled down"-->G
- D--"`gitlab-docs:14.2` image<br>pulled down"-->G
- E--"`gitlab-docs:13.12` image<br>pulled down"-->G
- F--"`gitlab-docs:12.10` image<br>pulled down"-->G
+ B--"gitlab-docs:14.4 image<br>pulled down"-->G
+ C--"gitlab-docs:14.3 image<br>pulled down"-->G
+ D--"gitlab-docs:14.2 image<br>pulled down"-->G
+ E--"gitlab-docs:13.12 image<br>pulled down"-->G
+ F--"gitlab-docs:12.10 image<br>pulled down"-->G
H{{"Container registry on gitlab-docs project"}}
- G--"Latest `gitlab-docs:latest` image<br>pushed up"-->H
+ G--"Latest gitlab-docs:latest image<br>pushed up"-->H
```
## Pages deploy job
@@ -144,7 +144,7 @@ graph LR
A{{"Container registry on gitlab-docs project"}}
B[["Scheduled pipeline<br>`pages` and<br>`pages:deploy` job"]]
C([docs.gitlab.com])
- A--"`gitlab-docs:latest`<br>pulled"-->B
+ A--"gitlab-docs:latest<br>pulled"-->B
B--"Unpacked documentation uploaded"-->C
```
diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md
index 94bc6bba240..0fa5819acae 100644
--- a/doc/development/documentation/styleguide/index.md
+++ b/doc/development/documentation/styleguide/index.md
@@ -62,20 +62,45 @@ the documentation helps others efficiently accomplish tasks and solve problems.
## Writing for localization
-The GitLab documentation is not localized, but we follow guidelines that
-help benefit translation. For example, we:
+The GitLab documentation is not localized, but we follow guidelines that help us write for a global audience.
-- Write in [active voice](word_list.md#active-voice).
-- Write in [present tense](word_list.md#future-tense).
-- Avoid words that can be translated incorrectly, like:
- - [since and because](word_list.md#since)
- - [once and after](word_list.md#once)
- - [it](word_list.md#it)
-- Avoid [-ing](word_list.md#-ing-words) words.
+[The GitLab voice](#the-gitlab-voice) dictates that we write clearly and directly with translation in mind.
+Our style guide, [word list](word_list.md), and [Vale rules](../testing.md) ensure consistency in the documentation.
-[The GitLab voice](#the-gitlab-voice) dictates that we write clearly and directly,
-and with translation in mind. [The word list](word_list.md) and our Vale rules
-also aid in consistency, which is important for localization.
+When documentation is translated into other languages, the meaning of each word must be clear.
+The increasing use of machine translation, GitLab Duo Chat, and other AI tools
+means that consistency is even more important.
+
+The following rules can help documentation be translated more efficiently.
+
+Avoid:
+
+- Phrases that hide the subject like [**there is** and **there are**](word_list.md#there-is-there-are).
+- Ambiguous pronouns like [**it**](word_list.md#it).
+- Words that end in [**-ing**](word_list.md#-ing-words).
+- Words that can be confused with one another like [**since**](word_list.md#since) and **because**.
+- Latin abbreviations like [**e.g.**](word_list.md#eg) and [**i.e.**](word_list.md#ie).
+- Culture-specific references like **kill two birds with one stone**.
+
+Use:
+
+- Standard [text for links](#text-for-links).
+- [Lists](#lists) and [tables](#tables) instead of complex sentences and paragraphs.
+- Common abbreviations like [**AI**](word_list.md#ai-artificial-intelligence) and
+ [**CI/CD**](word_list.md#cicd) and abbreviations you've previously spelled out.
+
+Also, keep the following guidance in mind:
+
+- Be consistent with [feature names](#feature-names) and how to interact with them.
+- Break up noun strings. For example, instead of **project integration custom settings**,
+ use **custom settings for project integrations**.
+- Format [dates and times](https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/date-time-terms)
+ consistently and for an international audience.
+- Use [images](#images), including screenshots, sparingly.
+- For [UI text](#ui-text), allow for up to 30% expansion and contraction in translation.
+ To see how much a string expands or contracts in another language, paste the string
+ into [Google Translate](https://translate.google.com/) and review the results.
+ You can ask a colleague who speaks the language to verify if the translation is clear.
## Markdown
@@ -240,12 +265,13 @@ create an issue or an MR to propose a change to the user interface text.
#### Feature names
-- Feature names are typically lowercase.
-- Some features require title case, typically nouns that name GitLab-specific capabilities or tools. Features requiring
- title case should be:
- - Added as a proper name to markdownlint [configuration](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.markdownlint.yml),
- so that it can be consistently applied across all documentation.
- - Added to the [word list](word_list.md).
+Feature names should be lowercase.
+
+However, in a few rare cases, features can be title case. These exceptions are:
+
+- Added as a proper name to [markdownlint](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.markdownlint.yml),
+ so they can be consistently applied across all documentation.
+- Added to the [word list](word_list.md).
If the term is not in the word list, ask a GitLab Technical Writer for advice.
@@ -449,7 +475,7 @@ For example:
cp <your_source_directory> <your_destination_directory>
```
-If the placeholder is not in a code block, use [`<` and `>`] and wrap the placeholder
+If the placeholder is not in a code block, use `<` and `>` and wrap the placeholder
in a single backtick. For example:
```plaintext
@@ -738,7 +764,7 @@ For example:
```html
<html>
-<small>Footnotes
+<small>Footnotes:
<ol>
<li>This is the footnote.</li>
<li>This is the other footnote.</li>
@@ -755,7 +781,7 @@ This text renders as this output:
| App B | Description text. <sup>2</sup> |
<html>
-<small>Footnotes
+<small>Footnotes:
<ol>
<li>This is the footnote.</li>
<li>This is the other footnote.</li>
@@ -984,7 +1010,7 @@ To be consistent, use these templates when you write navigation steps in a task
To open project settings:
```markdown
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
```
@@ -992,7 +1018,7 @@ To open project settings:
To open group settings:
```markdown
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
```
@@ -1000,7 +1026,7 @@ To open group settings:
To open either project or group settings:
```markdown
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
```
@@ -1020,14 +1046,14 @@ To create a group:
To open the Admin Area:
```markdown
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
```
To open the **Your work** menu item:
```markdown
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
```
@@ -1049,15 +1075,15 @@ To save the selection in some dropdown lists:
To view all your projects:
```markdown
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your projects**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my projects**.
```
To view all your groups:
```markdown
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your groups**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my groups**.
```
### Optional steps
@@ -1089,7 +1115,7 @@ Use the phrase **Complete the fields**.
For example:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Push rules**.
1. Complete the fields.
@@ -1641,7 +1667,7 @@ The H1 tier badge should be the badge that applies to the lowest tier for the fe
#### Available product tier badges
-Tier badges must include two components, in this order: a subscription tier and an offering.
+Tier badges should include two components, in this order: a subscription tier and an offering.
These components are surrounded by bold and parentheses, for example `**(ULTIMATE SAAS)**`.
Subscription tiers:
@@ -1661,10 +1687,14 @@ You can also add a third component for the feature's status:
- `EXPERIMENT`
- `BETA`
+For example, `**(FREE ALL EXPERIMENT)**`.
+
+A tier or status can stand alone. An offering should always have a tier.
+
#### Add a tier badge
To add a tier badge to a topic title, add the two relevant components
-after the title text. You must include the subscription tier first, and then the offering.
+after the title text. You should include the subscription tier first, and then the offering.
For example:
```markdown
@@ -1677,6 +1707,12 @@ Optionally, you can add the feature status as the last part of the badge:
# Topic title **(FREE ALL EXPERIMENT)**
```
+Or add the status by itself:
+
+```markdown
+# Topic title **(EXPERIMENT)**
+```
+
##### Inline tier badges
Do not add tier badges inline with other text, except for [API attributes](../restful_api_styleguide.md).
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index d65df0b56c8..509cabbe631 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -22,7 +22,9 @@ For guidance not on this page, we defer to these style guides:
- [Google Developer Documentation Style Guide](https://developers.google.com/style)
<!-- vale off -->
-<!-- markdownlint-disable -->
+
+<!-- Disable trailing punctuation in heading rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md026---trailing-punctuation-in-heading -->
+<!-- markdownlint-disable MD026 -->
## `&`
@@ -85,7 +87,7 @@ is passive. `Zombies select the button` is active.
## Admin Area
-Use title case for **Admin Area** to refer to the area of the UI that you access when you select **Main menu > Admin**.
+Use title case for **Admin Area**.
This area of the UI says **Admin Area** at the top of the page and on the menu.
## administrator
@@ -233,7 +235,6 @@ Use **text box** to refer to the UI field. Do not use **field** or **box**. For
- In the **Variable name** text box, enter a value.
-
## bullet
Don't refer to individual items in an ordered or unordered list as **bullets**. Use **list item** instead. If you need to be less ambiguous, you can use:
@@ -263,6 +264,9 @@ See also [contractions](index.md#contractions).
Use **Chat** with a capital `c` for **Chat** or **GitLab Duo Chat**.
+On first use on a page, use **GitLab Duo Chat**.
+Thereafter, use **Chat** by itself.
+
## checkbox
Use one word for **checkbox**. Do not use **check box**.
@@ -306,9 +310,30 @@ This version is different than the larger, more monolithic **Linux package** tha
You can also use **cloud-native GitLab** for short. It should be hyphenated and lowercase.
+## Code explanation
+
+Use sentence case for **Code explanation**.
+
+On first mention on a page, use **GitLab Duo Code explanation**.
+Thereafter, use **Code explanation** by itself.
+
+## Code review summary
+
+Use sentence case for **Code review summary**.
+
+On first mention on a page, use **GitLab Duo Code review summary**.
+Thereafter, use **Code review summary** by itself.
+
## Code Suggestions
-Use title case for **Code Suggestions**.
+Use title case for **Code Suggestions**. On first mention on a page, use **GitLab Duo Code Suggestions**.
+
+**Code Suggestions** should always be plural, and is capitalized even if it's generic.
+
+Examples:
+
+- Use Code Suggestions to display suggestions as you type. (This phrase describes the feature.)
+- As you type, Code Suggestions are displayed. (This phrase is generic but still uses capital letters.)
## collapse
@@ -438,6 +463,13 @@ Use **inactive** or **off** instead. ([Vale](../testing.md#vale) rule: [`Inclusi
Use **prevent** instead of **disallow**. ([Vale](../testing.md#vale) rule: [`Substitutions.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Substitutions.yml))
+## Discussion summary
+
+Use sentence case for **Discussion summary**.
+
+On first mention on a page, use **GitLab Duo Discussion summary**.
+Thereafter, use **Discussion summary** by itself.
+
## Docker-in-Docker, `dind`
Use **Docker-in-Docker** when you are describing running a Docker container by using the Docker executor.
@@ -580,7 +612,7 @@ Instead of:
However, you can make an exception when you are writing a task and you need to refer to all
of the fields at once. For example:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. Complete the fields.
@@ -621,6 +653,13 @@ For **GB** and **MB**, follow the [Microsoft guidance](https://learn.microsoft.c
Use title case for **Geo**.
+## Git suggestions
+
+Use sentence case for **Git suggestions**.
+
+On first mention on a page, use **GitLab Duo Git suggestions**.
+Thereafter, use **Git suggestions** by itself.
+
## GitLab
Do not make **GitLab** possessive (GitLab's). This guidance follows [GitLab Trademark Guidelines](https://about.gitlab.com/handbook/marketing/brand-and-product-marketing/brand/brand-activation/trademark-guidelines/).
@@ -633,6 +672,24 @@ Do not use **Dedicated** by itself. Always use **GitLab Dedicated**.
Do not use **Duo** by itself. Always use **GitLab Duo**.
+On first use on a page, use **GitLab Duo `<featurename>`**. For example:
+
+- GitLab Duo Chat
+- GitLab Duo Code Suggestions
+- GitLab Duo Suggested Reviewers
+- GitLab Duo Value stream forecasting
+- GitLab Duo Discussion summary
+- GitLab Duo Merge request summary
+- GitLab Duo Code review summary
+- GitLab Duo Code explanation
+- GitLab Duo Vulnerability summary
+- GitLab Duo Test generation
+- GitLab Duo Git suggestions
+- GitLab Duo Root cause analysis
+- GitLab Duo Issue description generation
+
+After the first use, use the feature name without **GitLab Duo**.
+
## GitLab Flavored Markdown
When possible, spell out [**GitLab Flavored Markdown**](../../../user/markdown.md).
@@ -757,7 +814,7 @@ Do not use **in order to**. Use **to** instead. ([Vale](../testing.md#vale) rule
For the plural of **index**, use **indexes**.
-However, for ElasticSearch, use [**indices**](https://www.elastic.co/blog/what-is-an-elasticsearch-index).
+However, for Elasticsearch, use [**indices**](https://www.elastic.co/blog/what-is-an-elasticsearch-index).
## Installation from source
@@ -792,6 +849,13 @@ Use lowercase for **issue**.
Use lowercase for **issue board**.
+## Issue description generation
+
+Use sentence case for **Issue description generation**.
+
+On first mention on a page, use **GitLab Duo Issue description generation**.
+Thereafter, use **Issue description generation** by itself.
+
## issue weights
Use lowercase for **issue weights**.
@@ -860,13 +924,13 @@ When writing about licenses:
Use:
- - Add a license to your instance.
- - Purchase a subscription.
+- Add a license to your instance.
+- Purchase a subscription.
Instead of:
- - Buy a license.
- - Purchase a license.
+- Buy a license.
+- Purchase a license.
## limitations
@@ -956,6 +1020,13 @@ the user account becomes a **member**.
Use lowercase for **merge requests**. If you use **MR** as the acronym, spell it out on first use.
+## Merge request summary
+
+Use sentence case for **Merge request summary**.
+
+On first mention on a page, use **GitLab Duo Merge request summary**.
+Thereafter, use **Merge request summary** by itself.
+
## milestones
Use lowercase for **milestones**.
@@ -1277,6 +1348,13 @@ Do not use **roles** and [**permissions**](#permissions) interchangeably. Each u
Roles are not the same as [**access levels**](#access-level).
+## Root cause analysis
+
+Use sentence case for **Root cause analysis**.
+
+On first mention on a page, use **GitLab Duo Root cause analysis**.
+Thereafter, use **Root cause analysis** by itself.
+
## roll back
Use **roll back** for changing a GitLab version to an earlier one.
@@ -1454,6 +1532,17 @@ To describe tiers:
| In the Premium tier or higher | In the Premium and Ultimate tier |
| In the Premium tier or lower | In the Free and Premium tier |
+## Suggested Reviewers
+
+Use title case for **Suggested Reviewers**. On first mention on a page, use **GitLab Duo Suggested Reviewers**.
+
+**Suggested Reviewers** should always be plural, and is capitalized even if it's generic.
+
+Examples:
+
+- Suggested Reviewers can recommend a person to review your merge request. (This phrase describes the feature.)
+- As you type, Suggested Reviewers are displayed. (This phrase is generic but still uses capital letters.)
+
## that
Do not use **that** when describing a noun. For example:
@@ -1482,6 +1571,13 @@ talking about non-specific modules. For example:
- You can publish a Terraform module to your project's Terraform Module Registry.
+## Test generation
+
+Use sentence case for **Test generation**.
+
+On first mention on a page, use **GitLab Duo Test generation**.
+Thereafter, use **Test generation** by itself.
+
## text box
Use **text box** instead of **field** or **box** when referring to the UI element.
@@ -1620,10 +1716,23 @@ When you add a **user account** to a group or project, the user account becomes
Do not use **utilize**. Use **use** instead. It's more succinct and easier for non-native English speakers to understand.
([Vale](../testing.md#vale) rule: [`SubstitutionSuggestions.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SubstitutionSuggestions.yml))
+## Value stream forecasting
+
+Use sentence case for **Value stream forecasting**. On first mention on a page, use **GitLab Duo Value stream forecasting**.
+
+Thereafter, use **Value stream forecasting** by itself.
+
## via
Do not use Latin abbreviations. Use **with**, **through**, or **by using** instead. ([Vale](../testing.md#vale) rule: [`LatinTerms.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/LatinTerms.yml))
+## Vulnerability summary
+
+Use sentence case for **Vulnerability summary**.
+
+On first mention on a page, use **GitLab Duo Vulnerability summary**.
+Thereafter, use **Vulnerability summary** by itself.
+
## we
Try to avoid **we** and focus instead on how the user can accomplish something in GitLab.
diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md
index 0c65e008436..c0f1d0028f9 100644
--- a/doc/development/documentation/testing.md
+++ b/doc/development/documentation/testing.md
@@ -507,7 +507,21 @@ To configure markdownlint in your editor, install one of the following as approp
To configure Vale in your editor, install one of the following as appropriate:
-- Sublime Text [`SublimeLinter-vale` package](https://packagecontrol.io/packages/SublimeLinter-vale).
+- Sublime Text [`SublimeLinter-vale` package](https://packagecontrol.io/packages/SublimeLinter-vale). To have Vale
+ suggestions appears as blue instead of red (which is how errors appear), add `vale` configuration to your
+ [SublimeLinter](http://sublimelinter.readthedocs.org) configuration:
+
+ ```json
+ "vale": {
+ "styles": [{
+ "mark_style": "outline",
+ "scope": "region.bluish",
+ "types": ["suggestion"]
+ }]
+ }
+ ```
+
+- [LSP for Sublime Text](https://lsp.sublimetext.io) package [`LSP-vale-ls`](https://packagecontrol.io/packages/LSP-vale-ls).
- Visual Studio Code [`ChrisChinchilla.vale-vscode` extension](https://marketplace.visualstudio.com/items?itemName=ChrisChinchilla.vale-vscode).
You can configure the plugin to [display only a subset of alerts](#show-subset-of-vale-alerts).
- Vim [ALE plugin](https://github.com/dense-analysis/ale).
diff --git a/doc/development/documentation/topic_types/task.md b/doc/development/documentation/topic_types/task.md
index 87ce4d770f5..7fb4201ac40 100644
--- a/doc/development/documentation/topic_types/task.md
+++ b/doc/development/documentation/topic_types/task.md
@@ -43,7 +43,7 @@ Prerequisites:
To create an issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**.
1. In the upper-right corner, select **New issue**.
1. Complete the fields. (If you have reference content that lists each field, link to it here.)
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 9219fcd6710..2bf8ad81ba4 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -49,7 +49,7 @@ version of the product:
1. Enable **Allow use of licensed EE features** to make licensed EE features available to projects
only if the project namespace's plan includes the feature.
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Account and limit**.
@@ -57,7 +57,7 @@ version of the product:
1. Select **Save changes**.
1. Ensure the group you want to test the EE feature for is actually using an EE plan:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Groups**.
1. Identify the group you want to modify, and select **Edit**.
@@ -463,7 +463,7 @@ end
When it's not possible/logical to modify the implementation of a method, then
wrap it in a self-descriptive method and use that method.
-For example, in GitLab-FOSS, the only user created by the system is `User.ghost`
+For example, in GitLab-FOSS, the only user created by the system is `Users::Internal.ghost`
but in EE there are several types of bot-users that aren't really users. It would
be incorrect to override the implementation of `User#ghost?`, so instead we add
a method `#internal?` to `app/models/user.rb`. The implementation:
diff --git a/doc/development/event_store.md b/doc/development/event_store.md
index c54e6ae2d07..918da8fb738 100644
--- a/doc/development/event_store.md
+++ b/doc/development/event_store.md
@@ -300,6 +300,21 @@ executed synchronously every time the given event is published.
For complex conditions it's best to subscribe to all the events and then handle the logic
in the `handle_event` method of the subscriber worker.
+### Delayed dispatching of events
+
+A subscription can specify a delay when to receive an event:
+
+```ruby
+store.subscribe ::MergeRequests::UpdateHeadPipelineWorker,
+ to: ::Ci::PipelineCreatedEvent,
+ delay: 1.minute
+```
+
+The `delay` parameter switches the dispatching of the event to use `perform_in` method
+on the subscriber Sidekiq worker, instead of `perform_async`.
+
+This technique is useful when publishing many events and leverage the Sidekiq deduplication.
+
## Testing
### Testing the publisher
diff --git a/doc/development/experiment_guide/implementing_experiments.md b/doc/development/experiment_guide/implementing_experiments.md
index 6fe58a1da54..61a46397390 100644
--- a/doc/development/experiment_guide/implementing_experiments.md
+++ b/doc/development/experiment_guide/implementing_experiments.md
@@ -281,7 +281,7 @@ about contexts now.
We can assume we run the experiment in one or a few places, but
track events potentially in many places. The tracking call remains the same, with
the arguments you would usually use when
-[tracking events using snowplow](../snowplow/index.md). The easiest example
+[tracking events using snowplow](../internal_analytics/snowplow/index.md). The easiest example
of tracking an event in Ruby would be:
```ruby
diff --git a/doc/development/fe_guide/accessibility.md b/doc/development/fe_guide/accessibility.md
index 65b50bedb0c..a9f82e85493 100644
--- a/doc/development/fe_guide/accessibility.md
+++ b/doc/development/fe_guide/accessibility.md
@@ -531,10 +531,43 @@ We aim to have full coverage for all the views.
One of the advantages of testing in feature tests is that we can check different states, not only
single components in isolation.
-Make sure to add assertions, when the view you are working on:
+You can find some examples on how to approach accessibility checks below.
-- Has an empty state,
-- Has significant changes in page structure, for example an alert is shown, or a new section is rendered.
+#### Empty state
+
+Some views have an empty state that result in a page structure that's different from the default view.
+They may also offer some actions, for example to create a first issue or to enable a feature.
+In this case, add assertions for both an empty state and a default view.
+
+#### Ensure compliance before user interactions
+
+Often we test against a number of steps we expect our users to perform.
+In this case, make sure to include the check early on, before any of them has been simulated.
+This way we ensure there are no barriers to what we expect of users.
+
+#### Ensure compliance after changed page structure
+
+User interactions may result in significant changes in page structure. For example, a modal is shown, or a new section is rendered.
+In that case, add an assertion after any such change.
+We want to make sure that users are able to interact with all available components.
+
+#### Separate file for extensive test suites
+
+For some views, feature tests span multiple files.
+Take a look at our [feature tests for a merge request](https://gitlab.com/gitlab-org/gitlab/-/tree/master/spec/features/merge_request).
+The number of user interactions that needs to be covered is too big to fit into one test file.
+As a result, multiple feature tests cover one view, with different user privileges, or data sets.
+If we were to include accessibility checks in all of them, there is a chance we would cover the same states of a view multiple times and significantly increase the run time.
+It would also make it harder to determine the coverage for accessibility, if assertions would be scattered across many files.
+
+In that case, consider creating one test file dedicated to accessibility.
+Place it in the same directory and name it `accessibility_spec.rb`, for example `spec/features/merge_request/accessibility_spec.rb`.
+
+#### Shared examples
+
+Often feature tests include shared examples for a number of scenarios.
+If they differ only by provided data, but are based on the same user interaction, you can check for accessibility compliance outside the shared examples.
+This way we only run the check once and save resources.
### How to add accessibility tests
diff --git a/doc/development/fe_guide/architecture.md b/doc/development/fe_guide/architecture.md
index 0c85a21fdf4..810d9af2de7 100644
--- a/doc/development/fe_guide/architecture.md
+++ b/doc/development/fe_guide/architecture.md
@@ -6,16 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Architecture
-When developing a feature that requires architectural design, or changing the fundamental design of an existing feature, discuss it with a Frontend Architecture Expert.
+When building new features, consider reaching out to relevant stakeholders as early as possible in the process.
-A Frontend Architect is an expert who makes high-level Frontend design decisions
-and decides on technical standards, including coding standards and frameworks.
-
-Architectural decisions should be accessible to everyone, so document
-them in the relevant Merge Request discussion or by updating our documentation
-when appropriate.
-
-You can find the Frontend Architecture experts on the [team page](https://about.gitlab.com/company/team/).
+Architectural decisions should be accessible to everyone. Document
+them in the relevant Merge Request discussions or by updating our documentation
+when appropriate by adding an entry to this section.
## Widget Architecture
@@ -23,8 +18,3 @@ The [Plan stage](https://about.gitlab.com/handbook/engineering/development/dev/p
is refactoring the right sidebar to consist of **widgets**. They have a specific architecture to be
reusable and to expose an interface that can be used by external Vue applications on the page.
Learn more about the [widget architecture](widgets.md).
-
-## Examples
-
-You can find [documentation about the desired architecture](vue.md) for a new
-feature built with Vue.js.
diff --git a/doc/development/fe_guide/axios.md b/doc/development/fe_guide/axios.md
index f90a2b37a1c..876855b807c 100644
--- a/doc/development/fe_guide/axios.md
+++ b/doc/development/fe_guide/axios.md
@@ -6,9 +6,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Axios
-We use [Axios](https://github.com/axios/axios) to communicate with the server in Vue applications and most new code.
+In older parts of our codebase using the REST API, we used [Axios](https://github.com/axios/axios) to communicate with the server, but you should not use Axios in new applications. Instead rely on `apollo-client` to query the GraphQL API. For more details, see [our GraphQL documentation](graphql.md).
-In order to guarantee all defaults are set you *should not use Axios directly*, you should import Axios from `axios_utils`.
+To guarantee all defaults are set you should import Axios from `axios_utils`. Do not use Axios directly.
## CSRF token
diff --git a/doc/development/fe_guide/customizable_dashboards.md b/doc/development/fe_guide/customizable_dashboards.md
index ac8b0b8a1ab..476a8acabd0 100644
--- a/doc/development/fe_guide/customizable_dashboards.md
+++ b/doc/development/fe_guide/customizable_dashboards.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Product Analytics
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -74,15 +74,15 @@ export const pageViewsOverTime = {
dimensions: [],
filters: [
{
- member: 'SnowplowTrackedEvents.event',
+ member: 'TrackedEvents.event',
operator: 'equals',
values: ['page_view']
}
],
- measures: ['SnowplowTrackedEvents.pageViewsCount'],
+ measures: ['TrackedEvents.pageViewsCount'],
timeDimensions: [
{
- dimension: 'SnowplowTrackedEvents.derivedTstamp',
+ dimension: 'TrackedEvents.derivedTstamp',
granularity: 'day',
},
],
@@ -123,6 +123,7 @@ import { pageViewsOverTime } from './visualizations';
export const dashboard = {
slug: 'my_dashboard', // Used to set the URL path for the dashboard.
title: 'My dashboard title', // The title to display.
+ description: 'This is a description of the dashboard', // A description of the dashboard
// Each dashboard consists of an array of panels to display.
panels: [
{
@@ -143,7 +144,7 @@ export const dashboard = {
// Here we override the Cube.js query to get page views per week instead of days.
queryOverrides: {
timeDimensions: {
- dimension: 'SnowplowTrackedEvents.derivedTstamp',
+ dimension: 'TrackedEvents.derivedTstamp',
granularity: 'week',
},
},
diff --git a/doc/development/fe_guide/dark_mode.md b/doc/development/fe_guide/dark_mode.md
index 5e8f844172a..144418f72cd 100644
--- a/doc/development/fe_guide/dark_mode.md
+++ b/doc/development/fe_guide/dark_mode.md
@@ -5,7 +5,7 @@ group: Development
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-This page is about developing dark mode for GitLab. For more information on how to enable dark mode, see [Change the syntax highlighting theme]](../../user/profile/preferences.md#change-the-syntax-highlighting-theme).
+This page is about developing dark mode for GitLab. For more information on how to enable dark mode, see [Change the syntax highlighting theme](../../user/profile/preferences.md#change-the-syntax-highlighting-theme).
# How dark mode works
diff --git a/doc/development/fe_guide/design_anti_patterns.md b/doc/development/fe_guide/design_anti_patterns.md
index f087fbd8235..e0d3a80d9c8 100644
--- a/doc/development/fe_guide/design_anti_patterns.md
+++ b/doc/development/fe_guide/design_anti_patterns.md
@@ -1,218 +1,10 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+redirect_to: 'design_patterns.md'
+remove_date: '2023-12-07'
---
-# Design Anti-patterns
+This document was moved to [another location](design_patterns.md).
-Anti-patterns may seem like good approaches at first, but it has been shown that they bring more ills than benefits. These should
-generally be avoided.
-
-Throughout the GitLab codebase, there may be historic uses of these anti-patterns. [Use discretion](https://about.gitlab.com/handbook/engineering/development/principles/#balance-refactoring-and-velocity)
-when figuring out whether or not to refactor, when touching code that uses one of these legacy patterns.
-
-NOTE:
-For new features, anti-patterns are not necessarily prohibited, but it is **strongly suggested** to find another approach.
-
-## Shared Global Object (Anti-pattern)
-
-A shared global object is an instance of something that can be accessed from anywhere and therefore has no clear owner.
-
-Here's an example of this pattern applied to a Vuex Store:
-
-```javascript
-const createStore = () => new Vuex.Store({
- actions,
- state,
- mutations
-});
-
-// Notice that we are forcing all references to this module to use the same single instance of the store.
-// We are also creating the store at import-time and there is nothing which can automatically dispose of it.
-//
-// As an alternative, we should export the `createStore` and let the client manage the
-// lifecycle and instance of the store.
-export default createStore();
-```
-
-### What problems do Shared Global Objects cause?
-
-Shared Global Objects are convenient because they can be accessed from anywhere. However,
-the convenience does not always outweigh their heavy cost:
-
-- **No ownership.** There is no clear owner to these objects and therefore they assume a non-deterministic
- and permanent lifecycle. This can be especially problematic for tests.
-- **No access control.** When Shared Global Objects manage some state, this can create some very buggy and difficult
- coupling situations because there is no access control to this object.
-- **Possible circular references.** Shared Global Objects can also create some circular referencing situations since submodules
- of the Shared Global Object can reference modules that reference itself (see
- [this MR for an example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33366)).
-
-Here are some historic examples where this pattern was identified to be problematic:
-
-- [Reference to global Vuex store in IDE](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36401)
-- [Docs update to discourage singleton Vuex store](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36952)
-
-### When could the Shared Global Object pattern be actually appropriate?
-
-Shared Global Object's solve the problem of making something globally accessible. This pattern
-could be appropriate:
-
-- When a responsibility is truly global and should be referenced across the application
- (for example, an application-wide Event Bus).
-
-Even in these scenarios, consider avoiding the Shared Global Object pattern because the
-side-effects can be notoriously difficult to reason with.
-
-### References
-
-For more information, see [Global Variables Are Bad on the C2 wiki](https://wiki.c2.com/?GlobalVariablesAreBad).
-
-## Singleton (Anti-pattern)
-
-The classic [Singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern) is an approach to ensure that only one
-instance of a thing exists.
-
-Here's an example of this pattern:
-
-```javascript
-class MyThing {
- constructor() {
- // ...
- }
-
- // ...
-}
-
-MyThing.instance = null;
-
-export const getThingInstance = () => {
- if (MyThing.instance) {
- return MyThing.instance;
- }
-
- const instance = new MyThing();
- MyThing.instance = instance;
- return instance;
-};
-```
-
-### What problems do Singletons cause?
-
-It is a big assumption that only one instance of a thing should exist. More often than not,
-a Singleton is misused and causes very tight coupling amongst itself and the modules that reference it.
-
-Here are some historic examples where this pattern was identified to be problematic:
-
-- [Test issues caused by singleton class in IDE](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30398#note_331174190)
-- [Implicit Singleton created by module's shared variables](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/97#note_417515776)
-- [Complexity caused by Singletons](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29461#note_324585814)
-
-Here are some ills that Singletons often produce:
-
-1. **Non-deterministic tests.** Singletons encourage non-deterministic tests because the single instance is shared across
- individual tests, often causing the state of one test to bleed into another.
-1. **High coupling.** Under the hood, clients of a singleton class all share a single specific
- instance of an object, which means this pattern inherits all the [problems of Shared Global Object](#what-problems-do-shared-global-objects-cause)
- such as no clear ownership and no access control. These leads to high coupling situations that can
- be buggy and difficult to untangle.
-1. **Infectious.** Singletons are infectious, especially when they manage state. Consider the component
- [RepoEditor](https://gitlab.com/gitlab-org/gitlab/-/blob/27ad6cb7b76430fbcbaf850df68c338d6719ed2b/app%2Fassets%2Fjavascripts%2Fide%2Fcomponents%2Frepo_editor.vue#L0-1)
- used in the Web IDE. This component interfaces with a Singleton [Editor](https://gitlab.com/gitlab-org/gitlab/-/blob/862ad57c44ec758ef3942ac2e7a2bd40a37a9c59/app%2Fassets%2Fjavascripts%2Fide%2Flib%2Feditor.js#L21)
- which manages some state for working with Monaco. Because of the Singleton nature of the Editor class,
- the component `RepoEditor` is now forced to be a Singleton as well. Multiple instances of this component
- would cause production issues because no one truly owns the instance of `Editor`.
-
-### Why is the Singleton pattern popular in other languages like Java?
-
-This is because of the limitations of languages like Java where everything has to be wrapped
-in a class. In JavaScript we have things like object and function literals where we can solve
-many problems with a module that exports utility functions.
-
-### When could the Singleton pattern be actually appropriate?**
-
-Singletons solve the problem of enforcing there to be only 1 instance of a thing. It's possible
-that a Singleton could be appropriate in the following rare cases:
-
-- We need to manage some resource that **MUST** have just 1 instance (that is, some hardware restriction).
-- There is a real [cross-cutting concern](https://en.wikipedia.org/wiki/Cross-cutting_concern) (for example, logging) and a Singleton provides the simplest API.
-
-Even in these scenarios, consider avoiding the Singleton pattern.
-
-### What alternatives are there to the Singleton pattern?
-
-#### Utility Functions
-
-When no state needs to be managed, we can export utility functions from a module without
-messing with any class instantiation.
-
-```javascript
-// bad - Singleton
-export class ThingUtils {
- static create() {
- if(this.instance) {
- return this.instance;
- }
-
- this.instance = new ThingUtils();
- return this.instance;
- }
-
- bar() { /* ... */ }
-
- fuzzify(id) { /* ... */ }
-}
-
-// good - Utility functions
-export const bar = () => { /* ... */ };
-
-export const fuzzify = (id) => { /* ... */ };
-```
-
-#### Dependency Injection
-
-[Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) is an approach which breaks
-coupling by declaring a module's dependencies to be injected from outside the module (for example, through constructor parameters, a bona-fide Dependency Injection framework, and even in Vue `provide/inject`).
-
-```javascript
-// bad - Vue component coupled to Singleton
-export default {
- created() {
- this.mediator = MyFooMediator.getInstance();
- },
-};
-
-// good - Vue component declares dependency
-export default {
- inject: ['mediator']
-};
-```
-
-```javascript
-// bad - We're not sure where the singleton is in it's lifecycle so we init it here.
-export class Foo {
- constructor() {
- Bar.getInstance().init();
- }
-
- stuff() {
- return Bar.getInstance().doStuff();
- }
-}
-
-// good - Lets receive this dependency as a constructor argument.
-// It's also not our responsibility to manage the lifecycle.
-export class Foo {
- constructor(bar) {
- this.bar = bar;
- }
-
- stuff() {
- return this.bar.doStuff();
- }
-}
-```
-
-In this example, the lifecycle and implementation details of `mediator` are all managed
-**outside** the component (most likely the page entrypoint).
+<!-- This redirect file can be deleted after <2023-12-07>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/development/fe_guide/design_patterns.md b/doc/development/fe_guide/design_patterns.md
index 3c273ab18e9..44238ff5dc5 100644
--- a/doc/development/fe_guide/design_patterns.md
+++ b/doc/development/fe_guide/design_patterns.md
@@ -6,12 +6,226 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Design Patterns
+This page covers suggested design patterns and also anti-patterns.
+
+NOTE:
+When adding a design pattern to this document, be sure to clearly state the **problem it solves**.
+When adding a design anti-pattern, clearly state **the problem it prevents**.
+
+## Patterns
+
The following design patterns are suggested approaches for solving common problems. Use discretion when evaluating
if a certain pattern makes sense in your situation. Just because it is a pattern, doesn't mean it is a good one for your problem.
+## Anti-patterns
+
+Anti-patterns may seem like good approaches at first, but it has been shown that they bring more ills than benefits. These should
+generally be avoided.
+
+Throughout the GitLab codebase, there may be historic uses of these anti-patterns. [Use discretion](https://about.gitlab.com/handbook/engineering/development/principles/#balance-refactoring-and-velocity)
+when figuring out whether or not to refactor, when touching code that uses one of these legacy patterns.
+
NOTE:
-When adding a design pattern to this document, be sure to clearly state the **problem it solves**.
+For new features, anti-patterns are not necessarily prohibited, but it is **strongly suggested** to find another approach.
+
+### Shared Global Object
+
+A shared global object is an instance of something that can be accessed from anywhere and therefore has no clear owner.
+
+Here's an example of this pattern applied to a Vuex Store:
+
+```javascript
+const createStore = () => new Vuex.Store({
+ actions,
+ state,
+ mutations
+});
+
+// Notice that we are forcing all references to this module to use the same single instance of the store.
+// We are also creating the store at import-time and there is nothing which can automatically dispose of it.
+//
+// As an alternative, we should export the `createStore` and let the client manage the
+// lifecycle and instance of the store.
+export default createStore();
+```
+
+#### What problems do Shared Global Objects cause?
+
+Shared Global Objects are convenient because they can be accessed from anywhere. However,
+the convenience does not always outweigh their heavy cost:
+
+- **No ownership.** There is no clear owner to these objects and therefore they assume a non-deterministic
+ and permanent lifecycle. This can be especially problematic for tests.
+- **No access control.** When Shared Global Objects manage some state, this can create some very buggy and difficult
+ coupling situations because there is no access control to this object.
+- **Possible circular references.** Shared Global Objects can also create some circular referencing situations since submodules
+ of the Shared Global Object can reference modules that reference itself (see
+ [this MR for an example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33366)).
+
+Here are some historic examples where this pattern was identified to be problematic:
+
+- [Reference to global Vuex store in IDE](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36401)
+- [Docs update to discourage singleton Vuex store](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36952)
+
+#### When could the Shared Global Object pattern be actually appropriate?
+
+Shared Global Object's solve the problem of making something globally accessible. This pattern
+could be appropriate:
+
+- When a responsibility is truly global and should be referenced across the application
+ (for example, an application-wide Event Bus).
+
+Even in these scenarios, consider avoiding the Shared Global Object pattern because the
+side-effects can be notoriously difficult to reason with.
+
+#### References
+
+For more information, see [Global Variables Are Bad on the C2 wiki](https://wiki.c2.com/?GlobalVariablesAreBad).
+
+### Singleton
+
+The classic [Singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern) is an approach to ensure that only one
+instance of a thing exists.
+
+Here's an example of this pattern:
+
+```javascript
+class MyThing {
+ constructor() {
+ // ...
+ }
+
+ // ...
+}
+
+MyThing.instance = null;
+
+export const getThingInstance = () => {
+ if (MyThing.instance) {
+ return MyThing.instance;
+ }
+
+ const instance = new MyThing();
+ MyThing.instance = instance;
+ return instance;
+};
+```
+
+#### What problems do Singletons cause?
+
+It is a big assumption that only one instance of a thing should exist. More often than not,
+a Singleton is misused and causes very tight coupling amongst itself and the modules that reference it.
+
+Here are some historic examples where this pattern was identified to be problematic:
+
+- [Test issues caused by singleton class in IDE](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30398#note_331174190)
+- [Implicit Singleton created by module's shared variables](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/97#note_417515776)
+- [Complexity caused by Singletons](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29461#note_324585814)
+
+Here are some ills that Singletons often produce:
+
+1. **Non-deterministic tests.** Singletons encourage non-deterministic tests because the single instance is shared across
+ individual tests, often causing the state of one test to bleed into another.
+1. **High coupling.** Under the hood, clients of a singleton class all share a single specific
+ instance of an object, which means this pattern inherits all the [problems of Shared Global Object](#what-problems-do-shared-global-objects-cause)
+ such as no clear ownership and no access control. These leads to high coupling situations that can
+ be buggy and difficult to untangle.
+1. **Infectious.** Singletons are infectious, especially when they manage state. Consider the component
+ [RepoEditor](https://gitlab.com/gitlab-org/gitlab/-/blob/27ad6cb7b76430fbcbaf850df68c338d6719ed2b/app%2Fassets%2Fjavascripts%2Fide%2Fcomponents%2Frepo_editor.vue#L0-1)
+ used in the Web IDE. This component interfaces with a Singleton [Editor](https://gitlab.com/gitlab-org/gitlab/-/blob/862ad57c44ec758ef3942ac2e7a2bd40a37a9c59/app%2Fassets%2Fjavascripts%2Fide%2Flib%2Feditor.js#L21)
+ which manages some state for working with Monaco. Because of the Singleton nature of the Editor class,
+ the component `RepoEditor` is now forced to be a Singleton as well. Multiple instances of this component
+ would cause production issues because no one truly owns the instance of `Editor`.
+
+#### Why is the Singleton pattern popular in other languages like Java?
+
+This is because of the limitations of languages like Java where everything has to be wrapped
+in a class. In JavaScript we have things like object and function literals where we can solve
+many problems with a module that exports utility functions.
+
+#### When could the Singleton pattern be actually appropriate?**
+
+Singletons solve the problem of enforcing there to be only 1 instance of a thing. It's possible
+that a Singleton could be appropriate in the following rare cases:
+
+- We need to manage some resource that **MUST** have just 1 instance (that is, some hardware restriction).
+- There is a real [cross-cutting concern](https://en.wikipedia.org/wiki/Cross-cutting_concern) (for example, logging) and a Singleton provides the simplest API.
+
+Even in these scenarios, consider avoiding the Singleton pattern.
+
+#### What alternatives are there to the Singleton pattern?
+
+##### Utility Functions
+
+When no state needs to be managed, we can export utility functions from a module without
+messing with any class instantiation.
+
+```javascript
+// bad - Singleton
+export class ThingUtils {
+ static create() {
+ if(this.instance) {
+ return this.instance;
+ }
+
+ this.instance = new ThingUtils();
+ return this.instance;
+ }
+
+ bar() { /* ... */ }
+
+ fuzzify(id) { /* ... */ }
+}
+
+// good - Utility functions
+export const bar = () => { /* ... */ };
+
+export const fuzzify = (id) => { /* ... */ };
+```
+
+##### Dependency Injection
+
+[Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) is an approach which breaks
+coupling by declaring a module's dependencies to be injected from outside the module (for example, through constructor parameters, a bona-fide Dependency Injection framework, and even in Vue `provide/inject`).
+
+```javascript
+// bad - Vue component coupled to Singleton
+export default {
+ created() {
+ this.mediator = MyFooMediator.getInstance();
+ },
+};
+
+// good - Vue component declares dependency
+export default {
+ inject: ['mediator']
+};
+```
+
+```javascript
+// bad - We're not sure where the singleton is in it's lifecycle so we init it here.
+export class Foo {
+ constructor() {
+ Bar.getInstance().init();
+ }
+
+ stuff() {
+ return Bar.getInstance().doStuff();
+ }
+}
+
+// good - Lets receive this dependency as a constructor argument.
+// It's also not our responsibility to manage the lifecycle.
+export class Foo {
+ constructor(bar) {
+ this.bar = bar;
+ }
-## TBD
+ stuff() {
+ return this.bar.doStuff();
+ }
+}
+```
-Stay tuned!
+In this example, the lifecycle and implementation details of `mediator` are all managed
+**outside** the component (most likely the page entrypoint).
diff --git a/doc/development/fe_guide/development_process.md b/doc/development/fe_guide/development_process.md
deleted file mode 100644
index 232689080ea..00000000000
--- a/doc/development/fe_guide/development_process.md
+++ /dev/null
@@ -1,125 +0,0 @@
----
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
----
-
-# Frontend Development Process
-
-You can find more about the organization of the frontend team in the [handbook](https://about.gitlab.com/handbook/engineering/frontend/).
-
-## Development Checklist
-
-The idea is to remind us about specific topics during the time we build a new feature or start something. This is a common practice in other industries (like pilots) that also use standardized checklists to reduce problems early on.
-
-Copy the content over to your issue or merge request and if something doesn't apply, remove it from your current list.
-
-This checklist is intended to help us during development of bigger features/refactorings. It is not a "use it always and every point always matches" list.
-
-Use your best judgment when to use it and contribute new points through merge requests if something comes to your mind.
-
-```markdown
-### Frontend development
-
-#### Planning development
-
-- [ ] Check the current set weight of the issue, does it fit your estimate?
-- [ ] Are all [departments](https://about.gitlab.com/handbook/engineering/#engineering-teams) that are needed from your perspective already involved in the issue? (For example is UX missing?)
-- [ ] Is the specification complete? Are you missing decisions? How about error handling/defaults/edge cases? Take your time to understand the needed implementation and go through its flow.
-- [ ] Are all necessary UX specifications available that you will need to implement? Are there new UX components/patterns in the designs? Then contact the UI component team early on. How should error messages or validation be handled?
-- [ ] **Library usage** Use Vuex as soon as you have even a medium state to manage, use Vue router if you need to have different views internally and want to link from the outside. Check what libraries we already have for which occasions.
-- [ ] **Plan your implementation:**
- - [ ] **Architecture plan:** Create a plan aligned with GitLab's architecture, how you are going to do the implementation, for example Vue application setup and its components (through [onion skinning](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/35873#note_39994091)), Store structure and data flow, which existing Vue components can you reuse. It's a good idea to go through your plan with another engineer to refine it.
- - [ ] **Backend:** The best way is to kickoff the implementation in a call and discuss with the assigned Backend engineer what you will need from the backend and also when. Can you reuse existing API's? How is the performance with the planned architecture? Maybe create together a JSON mock object to already start with development.
- - [ ] **Communication:** It also makes sense to have for bigger features an own slack channel (normally called #f_{feature_name}) and even weekly demo calls with all people involved.
- - [ ] **Dependency Plan:** Are there big dependencies in the plan between you and others, then maybe create an execution diagram to show what is blocking which part and the order of the different parts.
- - [ ] **Task list:** Create a simple checklist of the subtasks that are needed for the implementation, also consider creating even sub issues. (for example show a comment, delete a comment, update a comment, etc.). This helps you and also everyone else following the implementation
-- [ ] **Keep it small** To make it easier for you and also all reviewers try to keep merge requests small and merge into a feature branch if needed. To accomplish that you need to plan that from the start. Different methods are:
- - [ ] **Skeleton based plan** Start with an MR that has the skeleton of the components with placeholder content. In following MRs you can fill the components with interactivity. This also makes it easier to spread out development on multiple people.
- - [ ] **Cookie Mode** Think about hiding the feature behind a cookie flag if the implementation is on top of existing features
- - [ ] **New route** Are you refactoring something big then you might consider adding a new route where you implement the new feature and when finished delete the current route and rename the new one. (for example 'merge_request' and 'new_merge_request')
-- [ ] **Setup** Is there any specific setup needed for your implementation (for example a kubernetes cluster)? Then let everyone know if it is not already mentioned where they can find documentation (if it doesn't exist - create it)
-- [ ] **Security** Are there any new security relevant implementations? Then contact the security team for an app security review. If you are not sure ask our [domain expert](https://about.gitlab.com/handbook/engineering/frontend/#frontend-domain-experts)
-
-#### During development
-
-- [ ] Check off tasks on your created task list to keep everyone updated on the progress
-- [ ] [Share your work early with reviewers/maintainers](#share-your-work-early)
-- [ ] Share your work with UXer and Product Manager with Screenshots and/or [GIF images](https://about.gitlab.com/handbook/product/making-gifs/). They are easy to create for you and keep them up to date.
-- [ ] If you are blocked on something let everyone on the issue know through a comment.
-- [ ] Are you unable to work on this issue for a longer period of time, also let everyone know.
-- [ ] **Documentation** Update/add docs for the new feature, see `docs/`. Ping one of the documentation experts/reviewers
-
-#### Finishing development + Review
-
-- [ ] **Keep it in the scope** Try to focus on the actual scope and avoid a scope creep during review and keep new things to new issues.
-- [ ] **Performance** Have you checked performance? For example do the same thing with 500 comments instead of 1. Document the tests and possible findings in the MR so a reviewer can directly see it.
-- [ ] Have you tested with a variety of our [supported browsers](../../install/requirements.md#supported-web-browsers)? You can use [browserstack](https://www.browserstack.com/) to be able to access a wide variety of browsers and operating systems.
-- [ ] Did you check the mobile view?
-- [ ] Check the built webpack bundle (For the report run `WEBPACK_REPORT=true gdk start`, then open `webpack-report/index.html`) if we have unnecessary bloat due to wrong references, including libraries multiple times, etc.. If you need help contact the webpack [domain expert](https://about.gitlab.com/handbook/engineering/frontend/#frontend-domain-experts)
-- [ ] **Tests** Not only greenfield tests - Test also all bad cases that come to your mind.
-- [ ] If you have multiple MRs then also smoke test against the final merge.
-- [ ] Are there any big changes on how and especially how frequently we use the API then let production know about it
-- [ ] Smoke test of the RC on dev., staging., canary deployments and .com
-- [ ] Follow up on issues that came out of the review. Create issues for discovered edge cases that should be covered in future iterations.
-```
-
-### Code deletion checklist
-
-When your merge request deletes code, it's important to also delete all
-related code that is no longer used.
-When deleting Haml and Vue code, check whether it contains the following types of
-code that is unused:
-
-- CSS.
-
- For example, we've deleted a Vue component that contained the `.mr-card` class, which is now unused.
- The `.mr-card` CSS rule set should then be deleted from `merge_requests.scss`.
-
-- Ruby variables.
-
- Deleting unused Ruby variables is important so we don't continue instantiating them with
- potentially expensive code.
-
- For example, we've deleted a Haml template that used the `@total_count` Ruby variable.
- The `@total_count` variable was no longer used in the remaining templates for the page.
- The instantiation of `@total_count` in `issues_controller.rb` should then be deleted so that we
- don't make unnecessary database calls to calculate the count of issues.
-
-- Ruby methods.
-
-### Merge Request Review
-
-With the purpose of being [respectful of others' time](https://about.gitlab.com/handbook/values/#be-respectful-of-others-time), follow these guidelines when asking for a review:
-
-- Make sure your Merge Request:
- - milestone is set
- - at least the labels suggested by danger-bot are set
- - has a clear description
- - includes before/after screenshots if there is a UI change
- - pipeline is green
- - includes tests
- - includes a changelog entry (when necessary)
-- Before assigning to a maintainer, assign to a reviewer.
-- If you assigned a merge request or pinged someone directly, be patient because we work in different timezones and asynchronously. Unless the merge request is urgent (like fixing a broken default branch), don't DM or reassign the merge request before waiting for a 24-hour window.
-- If you have a question regarding your merge request/issue, make it on the merge request/issue. When we DM each other, we no longer have a SSOT and [no one else is able to contribute](https://about.gitlab.com/handbook/values/#public-by-default).
-- When you have a big **Draft** merge request with many changes, you're advised to get the review started before adding/removing significant code. Make sure it is assigned well before the release cut-off, as the reviewers/maintainers would always prioritize reviewing finished MRs before the **Draft** ones.
-- Make sure to remove the `Draft:` title before the last round of review.
-
-### Share your work early
-
-1. Before writing code, ensure your vision of the architecture is aligned with
- GitLab architecture.
-1. Add a diagram to the issue and ask a frontend maintainer in the Slack channel `#frontend_maintainers` about it.
-
- ![Diagram of issue boards architecture](img/boards_diagram.png)
-
-1. Don't take more than one week between starting work on a feature and
- sharing a Merge Request with a reviewer or a maintainer.
-
-### Vue features
-
-1. Follow the steps in [Vue.js Best Practices](vue.md)
-1. Follow the style guide.
-1. Only a handful of people are allowed to merge Vue related features.
- Reach out to one of Vue experts early in this process.
diff --git a/doc/development/fe_guide/getting_started.md b/doc/development/fe_guide/getting_started.md
new file mode 100644
index 00000000000..bb59bf7b8ee
--- /dev/null
+++ b/doc/development/fe_guide/getting_started.md
@@ -0,0 +1,54 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Getting started
+
+This page will guide you through the Frontend development process and show you what a normal Merge Request cycle looks like. You can find more about the organization of the frontend team in the [handbook](https://about.gitlab.com/handbook/engineering/frontend/).
+
+There are a lot of things to consider for a first merge request and it can feel overwhelming. The [Frontend onboarding course](onboarding_course/index.md) provides a 6-week structured curriculum to learn how to contribute to the GitLab frontend.
+
+## Development life cycle
+
+### Step 1: Preparing the issue
+
+Before tackling any work, read through the issue that has been assigned to you and make sure that all [required departments](https://about.gitlab.com/handbook/engineering/#engineering-teams) have been involved as they should. Read through the comments as needed and if unclear, post a comment in the issue summarizing **what you think the work is** and ping your Engineering or Product Manager to confirm. Then once everything is clarified, apply the correct worfklow labels to the issue and create a merge request branch. If created directly from the issue, the issue and the merge request will be linked by default.
+
+### Step 2: Plan your implementation
+
+Before writing code, make sure to ask yourself the following questions and have clear answers before you start developing:
+
+- What API data is required? Is it already available in our API or should I ask a Backend counterpart?
+ - If this is GraphQL, write a query proposal and ask your BE counterpart to confirm they are in agreement.
+- Can I use [GitLab UI components](https://gitlab-org.gitlab.io/gitlab-ui/?path=/docs/base-accordion--docs)? Which components are appropriate and do they have all of the functionality that I need?
+- Are there existing components or utils in the GitLab project that I could use?
+- [Should this change live behind a Feature Flag](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/#when-to-use-feature-flags)?
+- In which directory should this code live?
+- Should I build part of this feature as reusable? If so, where should it live in the codebase and how do I make it discoverable?
+ - Note: For now this is still being considered, but the `vue_shared` folder is still the preferred directory for GitLab-wide components.
+- What kinds of tests will it require? Consider unit tests **and** [Feature Tests](../testing_guide/frontend_testing.md#get-started-with-feature-tests)? Should I reach out to a [SET](https://handbook.gitlab.com/job-families/engineering/software-engineer-in-test/) for guidance or am I comfortable implementing the tests?
+- How big will this change be? Try to keep diffs to **500+- at the most**.
+
+If all of these questions have an answer, then you can safely move on to writing code.
+
+### Step 3: Writing code
+
+Make sure to communicate with your team as you progress or if you are unable to work on a planned issue for a long period of time.
+
+If you require assistance, make sure to push your branch and share your Merge Request either directly to a teammate or in the Slack channel `#frontend` to get advice on how to move forward. You can [mark your Merge Request as a draft](../../user/project/merge_requests/drafts.md), which will clearly communicate that it is not ready for a full on review. Always remember to have a [low level of shame](https://handbook.gitlab.com/handbook/values/#low-level-of-shame) and **ask for help when you need it**.
+
+As you write code, make sure to test your change thoroughly. It is the author's responsibility to test their code, ensure that it works as expected, and ensure that it did not break existing behaviours. Reviewers may help in that regard, but **do not expect it**. Make sure to check different browsers, mobile viewports and unexpected user flows.
+
+### Step 4: Review
+
+When it's time to send your code to review, it can be quite stressful. It is recommended to read through [the code review guidelines](../code_review.md) to get a better sense of what to expect. One of the most valuable pieces of advice that is **essential** is simply:
+
+> ... to avoid unnecessary back-and-forth with reviewers, ... perform a self-review of your own merge request, and follow the Code Review guidelines.
+
+This is key to having a great merge request experience because you will catch small mistakes and leave comments in areas where your reviewer might be uncertain and have questions. This speeds up the process tremendously.
+
+### Step 5: Verifying
+
+After your code has merged (congratulations!), make sure to verify that it works on the production environment and does not cause any errors.
diff --git a/doc/development/fe_guide/guides.md b/doc/development/fe_guide/guides.md
new file mode 100644
index 00000000000..dc2fffcf10a
--- /dev/null
+++ b/doc/development/fe_guide/guides.md
@@ -0,0 +1,13 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Guides
+
+This section contains guides to help our developers.
+For example, you can find information about how to accomplish a specific task,
+or how get proficient with a tool.
+
+Guidelines related to one specific technology, like Vue, should not be added to this section. Instead, add them to the `Tech Stack` section.
diff --git a/doc/development/fe_guide/img/boards_diagram.png b/doc/development/fe_guide/img/boards_diagram.png
deleted file mode 100644
index 856c9b05bbf..00000000000
--- a/doc/development/fe_guide/img/boards_diagram.png
+++ /dev/null
Binary files differ
diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md
index 405e830406e..70f7aad207b 100644
--- a/doc/development/fe_guide/index.md
+++ b/doc/development/fe_guide/index.md
@@ -86,135 +86,48 @@ Now that our values have been defined, we can base our goals on these values and
We have detailed description on how we see GitLab frontend in the future in [Frontend Goals](frontend_goals.md) section
-### Frontend onboarding course
+### First time contributors
-The [Frontend onboarding course](onboarding_course/index.md) provides a 6-week structured curriculum to learn how to contribute to the GitLab frontend.
+If you're a first-time contributor, see [Contribute to GitLab development](../contributing/index.md).
-### Browser Support
+When you're ready to create your first merge request, or need to review the GitLab frontend workflow, see [Getting started](getting_started.md).
-For supported browsers, see our [requirements](../../install/requirements.md#supported-web-browsers).
+For a guided introduction to frontend development at GitLab, you can watch the [Frontend onboarding course](onboarding_course/index.md) which provides a six-week structured curriculum.
-Use [BrowserStack](https://www.browserstack.com/) to test with our supported browsers.
-Sign in to BrowserStack with the credentials saved in the **Engineering** vault of the GitLab
-[shared 1Password account](https://about.gitlab.com/handbook/security/#1password-guide).
+### Helpful links
-## Initiatives
+#### Initiatives
You can find current frontend initiatives with a cross-functional impact on epics
with the label [frontend-initiative](https://gitlab.com/groups/gitlab-org/-/epics?state=opened&page=1&sort=UPDATED_AT_DESC&label_name[]=frontend-initiative).
-## Principles
-
-[High-level guidelines](principles.md) for contributing to GitLab.
-
-## Development Process
-
-How we [plan and execute](development_process.md) the work on the frontend.
-
-## Architecture
-
-How we go about [making fundamental design decisions](architecture.md) in the GitLab frontend team
-or make changes to our frontend development guidelines.
-
-## Testing
+#### Testing
How we write [frontend tests](../testing_guide/frontend_testing.md), run the GitLab test suite, and debug test related
issues.
-## Pajamas Design System
+#### Pajamas Design System
Reusable components with technical and usage guidelines can be found in our
[Pajamas Design System](https://design.gitlab.com/).
-## Design Patterns
-
-JavaScript [design patterns](design_patterns.md) in the GitLab codebase.
-
-## Design Anti-patterns
-
-JavaScript [design anti-patterns](design_anti_patterns.md) we try to avoid.
-
-## Vue.js Best Practices
-
-Vue specific [design patterns and practices](vue.md).
-
-## Vuex
-
-[Vuex](vuex.md) specific design patterns and practices.
-
-## Axios
-
-[Axios](axios.md) specific practices and gotchas.
-
-## GraphQL
-
-How to use [GraphQL](graphql.md).
-
-## HAML
-
-How to use [HAML](haml.md).
-
-## ViewComponent
-
-How we use [ViewComponent](view_component.md).
-
-## Icons and Illustrations
-
-How we use SVG for our [Icons and Illustrations](icons.md).
-
-## Dependencies
-
-General information about frontend [dependencies](dependencies.md) and how we manage them.
-
-## Keyboard Shortcuts
-
-How we implement [keyboard shortcuts](keyboard_shortcuts.md) that can be customized and disabled.
-
-## Editors
-
-GitLab text editing experiences are provided by the [source editor](source_editor.md) and
-the [rich text editor](content_editor.md).
-
-## Frontend FAQ
+#### Frontend FAQ
Read the [frontend's FAQ](frontend_faq.md) for common small pieces of helpful information.
-## Style Guides
-
-See the relevant style guides for our guidelines and for information on linting:
-
-- [JavaScript](style/javascript.md). Our guide is based on
-the excellent [Airbnb](https://github.com/airbnb/javascript) style guide with a few small
-changes.
-- [SCSS](style/scss.md): [our SCSS conventions](https://gitlab.com/gitlab-org/frontend/gitlab-stylelint-config) which are enforced through [`stylelint`](https://stylelint.io).
-- [HTML](style/html.md). Guidelines for writing HTML code consistent with the rest of the codebase.
-- [Vue](style/vue.md). Guidelines and conventions for Vue code may be found here.
-
-## [Tooling](tooling.md)
-
-Our code is automatically formatted with [Prettier](https://prettier.io) to follow our guidelines. Read our [Tooling guide](tooling.md) for more detail.
-
-## [Performance](performance.md)
-
-Best practices for monitoring and maximizing frontend performance.
-
-## [Security](security.md)
-
-Frontend security practices.
-
-## Accessibility
-
-Our [accessibility standards and resources](accessibility.md).
-
-## Logging
-
-Best practices for [client-side logging](logging.md) for GitLab frontend development.
-
-## [Internationalization (i18n) and Translations](../i18n/externalization.md)
+#### [Internationalization (i18n) and Translations](../i18n/externalization.md)
Frontend internationalization support is described in [this document](../i18n/index.md).
The [externalization part of the guide](../i18n/externalization.md) explains the helpers/methods available.
-## [Troubleshooting](troubleshooting.md)
+#### [Troubleshooting](troubleshooting.md)
Running into a Frontend development problem? Check out [this guide](troubleshooting.md) to help resolve your issue.
+
+#### Browser support
+
+For supported browsers, see our [requirements](../../install/requirements.md#supported-web-browsers).
+
+Use [BrowserStack](https://www.browserstack.com/) to test with our supported browsers.
+Sign in to BrowserStack with the credentials saved in the **Engineering** vault of the GitLab
+[shared 1Password account](https://about.gitlab.com/handbook/security/#1password-guide).
diff --git a/doc/development/fe_guide/principles.md b/doc/development/fe_guide/principles.md
deleted file mode 100644
index 6d1a3238b73..00000000000
--- a/doc/development/fe_guide/principles.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
----
-
-# Principles
-
-These principles ensure that your frontend contribution starts off in the right direction.
-
-## Discuss architecture before implementation
-
-Discuss your architecture design in an issue before writing code. This helps decrease the review time and also provides good practice for writing and thinking about system design.
-
-## Be consistent
-
-There are multiple ways of writing code to accomplish the same results. We should be as consistent as possible in how we write code across our codebases. This makes it easier for us to maintain our code across GitLab.
-
-## Improve code [iteratively](https://about.gitlab.com/handbook/values/#iteration)
-
-Whenever you see existing code that does not follow our current style guide, update it proactively. You don't need to fix everything, but each merge request should iteratively improve our codebase, and reduce technical debt where possible.
diff --git a/doc/development/fe_guide/sentry.md b/doc/development/fe_guide/sentry.md
new file mode 100644
index 00000000000..af4a006c7ea
--- /dev/null
+++ b/doc/development/fe_guide/sentry.md
@@ -0,0 +1,34 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Sentry
+
+As part of the [Frontend Observability Working Group](https://google.com) we're looking to provide documentation on how to use Sentry effectively.
+If left unchecked, Sentry can get noisy and become unreliable.
+This page aims to help guide us toward more sensible Sentry usage.
+
+## Which errors we should report to Sentry explicitly and which should be only shown to users (e.g. as alerts)
+
+If we send all errors to Sentry, it gets very noisy, very quickly.
+We want to filter out the errors that we either don't care about, or have no control over.
+For example, if a user fills out a form incorrectly, this is not something we want to send to Sentry.
+If that form fails because it's hitting a dead endpoint, this is an error we want Sentry to know about.
+
+## How to catch errors correctly so Sentry can display them reliably
+
+TBD
+
+## How to catch special cases you want to track (like we did with the pipeline graph)
+
+TBD
+
+## How to navigate Sentry and find errors
+
+TBD
+
+## How to debug Sentry errors effectively
+
+TBD
diff --git a/doc/development/fe_guide/tech_stack.md b/doc/development/fe_guide/tech_stack.md
new file mode 100644
index 00000000000..9c0d50ea7bd
--- /dev/null
+++ b/doc/development/fe_guide/tech_stack.md
@@ -0,0 +1,11 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Tech Stack
+
+For an exhaustive list of all the technology that we use, simply check our [latest `package.json` file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/package.json?ref_type=heads).
+
+Each navigation item in this section is a guide for that specific technology.
diff --git a/doc/development/fe_guide/tips_and_tricks.md b/doc/development/fe_guide/tips_and_tricks.md
new file mode 100644
index 00000000000..dcacdb8387b
--- /dev/null
+++ b/doc/development/fe_guide/tips_and_tricks.md
@@ -0,0 +1,31 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Tips and tricks
+
+## Code deletion checklist
+
+When your merge request deletes code, it's important to also delete all
+related code that is no longer used.
+When deleting Haml and Vue code, check whether it contains the following types of
+code that is unused:
+
+- CSS.
+
+ For example, we've deleted a Vue component that contained the `.mr-card` class, which is now unused.
+ The `.mr-card` CSS rule set should then be deleted from `merge_requests.scss`.
+
+- Ruby variables.
+
+ Deleting unused Ruby variables is important so we don't continue instantiating them with
+ potentially expensive code.
+
+ For example, we've deleted a Haml template that used the `@total_count` Ruby variable.
+ The `@total_count` variable was no longer used in the remaining templates for the page.
+ The instantiation of `@total_count` in `issues_controller.rb` should then be deleted so that we
+ don't make unnecessary database calls to calculate the count of issues.
+
+- Ruby methods.
diff --git a/doc/development/feature_development.md b/doc/development/feature_development.md
index c4a5c996ab1..2f013f698dc 100644
--- a/doc/development/feature_development.md
+++ b/doc/development/feature_development.md
@@ -95,7 +95,7 @@ Consult these topics for information on contributing to specific GitLab features
- [Shell commands](shell_commands.md) in the GitLab codebase
- [Value Stream Analytics development guide](value_stream_analytics.md)
- [Application limits](application_limits.md)
-- [AI features](ai_features.md)
+- [AI features](ai_features/index.md)
### Import and Export
@@ -163,8 +163,8 @@ The following integration guides are internal. Some integrations require access
## Analytics Instrumentation guides
- [Analytics Instrumentation guide](https://about.gitlab.com/handbook/product/analytics-instrumentation-guide/)
-- [Service Ping guide](service_ping/index.md)
-- [Snowplow guide](snowplow/index.md)
+- [Service Ping guide](internal_analytics/service_ping/index.md)
+- [Snowplow guide](internal_analytics/snowplow/index.md)
## Experiment guide
diff --git a/doc/development/feature_flags/index.md b/doc/development/feature_flags/index.md
index 8c0f7faab28..af40fd8b945 100644
--- a/doc/development/feature_flags/index.md
+++ b/doc/development/feature_flags/index.md
@@ -420,9 +420,18 @@ The actor is a second parameter of the `Feature.enabled?` call. The
same actor type must be used consistently for all invocations of `Feature.enabled?`.
```ruby
+# Bad
Feature.enabled?(:feature_flag, project)
Feature.enabled?(:feature_flag, group)
Feature.enabled?(:feature_flag, user)
+
+# Good
+Feature.enabled?(:feature_flag, group_a)
+Feature.enabled?(:feature_flag, group_b)
+
+# Also good - using separate flags for each actor type
+Feature.enabled?(:feature_flag_group, group)
+Feature.enabled?(:feature_flag_user, user)
```
See [Feature flags in the development of GitLab](controls.md#process) for details on how to use ChatOps
diff --git a/doc/development/features_inside_dot_gitlab.md b/doc/development/features_inside_dot_gitlab.md
index a1f5111d6f4..f8de93a2243 100644
--- a/doc/development/features_inside_dot_gitlab.md
+++ b/doc/development/features_inside_dot_gitlab.md
@@ -16,6 +16,6 @@ When implementing new features, please refer to these existing features to avoid
- [Route Maps](../ci/review_apps/index.md#route-maps): `.gitlab/route-map.yml`.
- [Customize Auto DevOps Helm Values](../topics/autodevops/customize.md#customize-helm-chart-values): `.gitlab/auto-deploy-values.yaml`.
- [Insights](../user/project/insights/index.md#configure-project-insights): `.gitlab/insights.yml`.
-- [Service Desk Templates](../user/project/service_desk/index.md#customize-emails-sent-to-the-requester): `.gitlab/service_desk_templates/`.
+- [Service Desk Templates](../user/project/service_desk/configure.md#customize-emails-sent-to-the-requester): `.gitlab/service_desk_templates/`.
- [Secret Detection Custom Rulesets](../user/application_security/secret_detection/index.md#disable-predefined-analyzer-rules): `.gitlab/secret-detection-ruleset.toml`
- [Static Analysis Custom Rulesets](../user/application_security/sast/customize_rulesets.md#create-the-configuration-file): `.gitlab/sast-ruleset.toml`
diff --git a/doc/development/file_storage.md b/doc/development/file_storage.md
index c346d55f639..39833a441ee 100644
--- a/doc/development/file_storage.md
+++ b/doc/development/file_storage.md
@@ -56,7 +56,7 @@ they are still not 100% standardized. You can see them below:
CI Artifacts and LFS Objects behave differently in CE and EE. In CE they inherit the `GitlabUploader`
while in EE they inherit the `ObjectStorage` and store files in and S3 API compatible object store.
-In the case of Issues/MR/Notes Markdown attachments, there is a different approach using the [Hashed Storage](../administration/repository_storage_types.md) layout,
+In the case of Issues/MR/Notes Markdown attachments, there is a different approach using the [Hashed Storage](../administration/repository_storage_paths.md) layout,
instead of basing the path into a mutable variable `:project_path_with_namespace`, it's possible to use the
hash of the project ID instead, if project migrates to the new approach (introduced in 10.2).
diff --git a/doc/development/fips_compliance.md b/doc/development/fips_compliance.md
index 4f6a9feb191..60677abf292 100644
--- a/doc/development/fips_compliance.md
+++ b/doc/development/fips_compliance.md
@@ -59,7 +59,7 @@ listed here that also do not work properly in FIPS mode:
- [Container Scanning](../user/application_security/container_scanning/index.md) support for scanning images in repositories that require authentication.
- [Code Quality](../ci/testing/code_quality.md) does not support operating in FIPS-compliant mode.
- [Dependency scanning](../user/application_security/dependency_scanning/index.md) support for Gradle.
-- [Dynamic Application Security Testing (DAST)](../user/application_security/dast/proxy-based.md) supports a reduced set of analyzers. The proxy-based analyzer is not available in FIPS mode today, however browser-based DAST, DAST API, and DAST API Fuzzing images are available.
+- [Dynamic Application Security Testing (DAST)](../user/application_security/dast/proxy-based.md) supports a reduced set of analyzers. The proxy-based analyzer and on-demand scanning is not available in FIPS mode today, however browser-based DAST, DAST API, and DAST API Fuzzing images are available.
- [Solutions for vulnerabilities](../user/application_security/vulnerabilities/index.md#resolve-a-vulnerability)
for yarn projects.
- [Static Application Security Testing (SAST)](../user/application_security/sast/index.md)
diff --git a/doc/development/gems.md b/doc/development/gems.md
index c061b33b5e4..132bf931da8 100644
--- a/doc/development/gems.md
+++ b/doc/development/gems.md
@@ -238,11 +238,10 @@ The project for a new Gem should always be created in [`gitlab-org/ruby/gems` na
the gem name with `gitlab-`. For example, `gitlab-sidekiq-fetcher`.
1. Locally create the gem or fork as necessary.
1. [Publish an empty `0.0.1` version of the gem to rubygems.org](https://guides.rubygems.org/publishing/#publishing-to-rubygemsorg) to ensure the gem name is reserved.
-1. Add the [`gitlab_rubygems`](https://rubygems.org/profiles/gitlab_rubygems) and [`gitlab-qa`](https://rubygems.org/profiles/gitlab-qa) users as owners of the new gem by running:
+1. Add the [`gitlab_rubygems`](https://rubygems.org/profiles/gitlab_rubygems) user as owner of the new gem by running:
```shell
gem owner <gem-name> --add gitlab_rubygems
- gem owner <gem-name> --add gitlab-qa
```
1. Optional. Add some or all of the following users as co-owners:
@@ -251,8 +250,8 @@ The project for a new Gem should always be created in [`gitlab-org/ruby/gems` na
- [Stan Hu](https://rubygems.org/profiles/stanhu)
1. Optional. Add any other relevant developers as co-owners.
1. Visit `https://rubygems.org/gems/<gem-name>` and verify that the gem was published
- successfully and `gitlab_rubygems` & `gitlab-qa` are also owners.
-1. Create a project in the [`gitlab-org/ruby/gems` group](https://gitlab.com/gitlab-org/ruby/gems/). To create this project:
+ successfully and `gitlab_rubygems` is also an owner.
+1. Create a project in the [`gitlab-org/ruby/gems` group](https://gitlab.com/gitlab-org/ruby/gems/) (or in a subgroup of it):
1. Follow the [instructions for new projects](https://about.gitlab.com/handbook/engineering/gitlab-repositories/#creating-a-new-project).
1. Follow the instructions for setting up a [CI/CD configuration](https://about.gitlab.com/handbook/engineering/gitlab-repositories/#cicd-configuration).
1. Use the [shared CI/CD config](https://gitlab.com/gitlab-org/quality/pipeline-common/-/blob/master/ci/gem-release.yml)
@@ -264,7 +263,7 @@ The project for a new Gem should always be created in [`gitlab-org/ruby/gems` na
file: '/ci/gem-release.yml'
```
- This job will handle building and publishing the gem (it uses a `gilab-qa` Rubygems.org
+ This job will handle building and publishing the gem (it uses a `gitlab_rubygems` Rubygems.org
API token inherited from the `gitlab-org/ruby/gems` group, in order to publish the gem
package), as well as creating the tag, release and populating its release notes by
using the
diff --git a/doc/development/git_object_deduplication.md b/doc/development/git_object_deduplication.md
index 961bfca0d9b..65d2338cd65 100644
--- a/doc/development/git_object_deduplication.md
+++ b/doc/development/git_object_deduplication.md
@@ -46,7 +46,7 @@ reliable decide if an object is no longer needed.
### Git alternates in GitLab: pool repositories
-GitLab organizes this object borrowing by [creating special **pool repositories**](../administration/repository_storage_types.md)
+GitLab organizes this object borrowing by [creating special **pool repositories**](../administration/repository_storage_paths.md)
which are hidden from the user. We then use Git
alternates to let a collection of project repositories borrow from a
single pool repository. We call such a collection of project
@@ -101,7 +101,7 @@ are as follows:
### Assumptions
-- All repositories in a pool must use [hashed storage](../administration/repository_storage_types.md).
+- All repositories in a pool must use [hashed storage](../administration/repository_storage_paths.md).
This is so that we don't have to ever worry about updating paths in
`object/info/alternates` files.
- All repositories in a pool must be on the same Gitaly storage shard.
diff --git a/doc/development/github_importer.md b/doc/development/github_importer.md
index d38be071f39..45554ae465d 100644
--- a/doc/development/github_importer.md
+++ b/doc/development/github_importer.md
@@ -243,11 +243,13 @@ To avoid mismatching users, the search by GitHub user ID is not done when import
Enterprise.
Because this process is quite expensive we cache the result of these lookups in
-Redis. For every user looked up we store three keys:
+Redis. For every user looked up we store five keys:
- A Redis key mapping GitHub usernames to their Email addresses.
- A Redis key mapping a GitHub Email addresses to a GitLab user ID.
- A Redis key mapping a GitHub user ID to GitLab user ID.
+- A Redis key mapping a GitHub username to an ETAG header.
+- A Redis key indicating whether an email lookup has been done for a project.
We cache two types of lookups:
@@ -260,9 +262,12 @@ The expiration time of these keys is 24 hours. When retrieving the cache of a
positive lookup, we refresh the TTL automatically. The TTL of false lookups is
never refreshed.
+If a lookup for email returns an empty or negative lookup, a [Conditional Request](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#conditional-requests) is made with a cached ETAG in the header once for every project.
+Conditional Requests do not count towards the GitHub API rate limit.
+
Because of this caching layer, it's possible newly registered GitLab accounts
aren't linked to their corresponding GitHub accounts. This, however, is resolved
-after the cached keys expire.
+after the cached keys expire or if a new project is imported.
The user cache lookup is shared across projects. This means that the greater the number of
projects that are imported, fewer GitHub API calls are needed.
@@ -287,7 +292,7 @@ The code for this resides in:
- `lib/gitlab/github_import/label_finder.rb`
- `lib/gitlab/github_import/milestone_finder.rb`
-- `lib/gitlab/github_import/caching.rb`
+- `lib/gitlab/cache/import/caching.rb`
## Logs
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 7648e84f5e8..c6d7b231b72 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -9,8 +9,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
This document describes various guidelines and best practices for GitLab
projects using the [Go language](https://go.dev/).
-## Overview
-
GitLab is built on top of [Ruby on Rails](https://rubyonrails.org/), but we're
also using Go for projects where it makes sense. Go is a very powerful
language, with many advantages, and is best suited for projects with a lot of
@@ -73,7 +71,7 @@ of possible security breaches in our code:
Remember to run
[SAST](../../user/application_security/sast/index.md) and [Dependency Scanning](../../user/application_security/dependency_scanning/index.md)
-**(ULTIMATE)** on your project (or at least the
+**(ULTIMATE ALL)** on your project (or at least the
[`gosec` analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/gosec)),
and to follow our [Security requirements](../code_review.md#security).
@@ -142,6 +140,12 @@ become available, you can share job templates like this
Go GitLab linter plugins are maintained in the [`gitlab-org/language-tools/go/linters`](https://gitlab.com/gitlab-org/language-tools/go/linters/) namespace.
+### Help text style guide
+
+If your Go project produces help text for users, consider following the advice given in the
+[Help text style guide](https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/help_text_style_guide.md) in the
+`gitaly` project.
+
## Dependencies
Dependencies should be kept to the minimum. The introduction of a new
@@ -340,21 +344,34 @@ which documents and centralizes at the same time all the possible command line
interactions with the program. Don't use `os.GetEnv`, it hides variables deep
in the code.
-## Daemons
+## Libraries
+
+### LabKit
-### Logging
+[LabKit](https://gitlab.com/gitlab-org/labkit) is a place to keep common
+libraries for Go services. For examples using of using LabKit, see [`workhorse`](https://gitlab.com/gitlab-org/gitlab/tree/master/workhorse)
+and [`gitaly`](https://gitlab.com/gitlab-org/gitaly). LabKit exports three related pieces of functionality:
-The usage of a logging library is strongly recommended for daemons. Even
-though there is a `log` package in the standard library, we generally use
-[Logrus](https://github.com/sirupsen/logrus). Its plugin ("hooks") system
-makes it a powerful logging library, with the ability to add notifiers and
-formatters at the logger level directly.
+- [`gitlab.com/gitlab-org/labkit/correlation`](https://gitlab.com/gitlab-org/labkit/tree/master/correlation):
+ for propagating and extracting correlation ids between services.
+- [`gitlab.com/gitlab-org/labkit/tracing`](https://gitlab.com/gitlab-org/labkit/tree/master/tracing):
+ for instrumenting Go libraries for distributed tracing.
+- [`gitlab.com/gitlab-org/labkit/log`](https://gitlab.com/gitlab-org/labkit/tree/master/log):
+ for structured logging using Logrus.
+
+This gives us a thin abstraction over underlying implementations that is
+consistent across Workhorse, Gitaly, and possibly other Go servers. For
+example, in the case of `gitlab.com/gitlab-org/labkit/tracing` we can switch
+from using `Opentracing` directly to using `Zipkin` or the Go kit's own tracing wrapper
+without changes to the application code, while still keeping the same
+consistent configuration mechanism (that is, the `GITLAB_TRACING` environment
+variable).
#### Structured (JSON) logging
Every binary ideally must have structured (JSON) logging in place as it helps
-with searching and filtering the logs. At GitLab we use structured logging in
-JSON format, as all our infrastructure assumes that. When using
+with searching and filtering the logs. LabKit provides an abstraction over [Logrus](https://github.com/sirupsen/logrus).
+We use structured logging in JSON format, because all our infrastructure assumes that. When using
[Logrus](https://github.com/sirupsen/logrus) you can turn on structured
logging by using the build in [JSON formatter](https://github.com/sirupsen/logrus#formatters). This follows the
same logging type we use in our [Ruby applications](../logging.md#use-structured-json-logging).
@@ -375,26 +392,6 @@ There are a few guidelines one should follow when using the
have to log multiple keys, always use `WithFields` instead of calling
`WithField` more than once.
-### Tracing and Correlation
-
-[LabKit](https://gitlab.com/gitlab-org/labkit) is a place to keep common
-libraries for Go services. Currently it's vendored into two projects:
-Workhorse and Gitaly, and it exports two main (but related) pieces of
-functionality:
-
-- [`gitlab.com/gitlab-org/labkit/correlation`](https://gitlab.com/gitlab-org/labkit/tree/master/correlation):
- for propagating and extracting correlation ids between services.
-- [`gitlab.com/gitlab-org/labkit/tracing`](https://gitlab.com/gitlab-org/labkit/tree/master/tracing):
- for instrumenting Go libraries for distributed tracing.
-
-This gives us a thin abstraction over underlying implementations that is
-consistent across Workhorse, Gitaly, and, in future, other Go servers. For
-example, in the case of `gitlab.com/gitlab-org/labkit/tracing` we can switch
-from using `Opentracing` directly to using `Zipkin` or the Go kit's own tracing wrapper
-without changes to the application code, while still keeping the same
-consistent configuration mechanism (that is, the `GITLAB_TRACING` environment
-variable).
-
### Context
Since daemons are long-running applications, they should have mechanisms to
diff --git a/doc/development/gotchas.md b/doc/development/gotchas.md
index 25651639170..59362dc33c0 100644
--- a/doc/development/gotchas.md
+++ b/doc/development/gotchas.md
@@ -221,7 +221,7 @@ Assets that need to be served to the user are stored under the `app/assets` dire
However, you cannot access the content of any file from within `app/assets` from the application code, as we do not include that folder in production installations as a [space saving measure](https://gitlab.com/gitlab-org/omnibus-gitlab/-/commit/ca049f990b223f5e1e412830510a7516222810be).
```ruby
-support_bot = User.support_bot
+support_bot = Users::Internal.support_bot
# accessing a file from the `app/assets` folder
support_bot.avatar = Rails.root.join('app', 'assets', 'images', 'bot_avatars', 'support_bot.png').open
@@ -244,3 +244,59 @@ Use `app/assets` for storing any asset that needs to be precompiled and served t
Use `lib/assets` for storing any asset that does not need to be served to the end user directly, but is still required to be accessed by the application code.
MR for reference: [!37671](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37671)
+
+## Do not override `has_many through:` or `has_one through:` associations
+
+Associations with the `:through` option should not be overridden as we could accidentally
+destroy the wrong object.
+
+This is because the `destroy()` method behaves differently when acting on
+`has_many through:` and `has_one through:` associations.
+
+```ruby
+group.users.destroy(id)
+```
+
+The code example above reads as if we are destroying a `User` record, but behind the scenes, it is destroying a `Member` record. This is because the `users` association is defined on `Group` as a `has_many through:` association:
+
+```ruby
+class Group < Namespace
+ has_many :group_members, -> { where(requested_at: nil).where.not(members: { access_level: Gitlab::Access::MINIMAL_ACCESS }) }, dependent: :destroy, as: :source
+
+ has_many :users, through: :group_members
+end
+```
+
+And Rails has the following [behavior](https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many) on using `destroy()` on such associations:
+
+> If the :through option is used, then the join records are destroyed instead, not the objects themselves.
+
+This is why a `Member` record, which is the join record connecting a `User` and `Group`, is being destroyed.
+
+Now, if we override the `users` association, so like:
+
+```ruby
+class Group < Namespace
+ has_many :group_members, -> { where(requested_at: nil).where.not(members: { access_level: Gitlab::Access::MINIMAL_ACCESS }) }, dependent: :destroy, as: :source
+
+ has_many :users, through: :group_members
+
+ def users
+ super.where(admin: false)
+ end
+end
+```
+
+The overridden method now changes the above behavior of `destroy()`, such that if we execute
+
+```ruby
+group.users.destroy(id)
+```
+
+a `User` record will be deleted, which can lead to data loss.
+
+In short, overriding a `has_many through:` or `has_one through:` association can prove dangerous.
+To prevent this from happening, we are introducing an
+automated check in [!131455](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131455).
+
+For more information, see [issue 424536](https://gitlab.com/gitlab-org/gitlab/-/issues/424536).
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index f4ace7491eb..68c2778eabe 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -204,9 +204,9 @@ Example:
```javascript
// Bad. Not necessary in Frontend environment.
-expect(findText()).toBe(__('Lorem ipsum dolar sit'));
+expect(findText()).toBe(__('Lorem ipsum dolor sit'));
// Good.
-expect(findText()).toBe('Lorem ipsum dolar sit');
+expect(findText()).toBe('Lorem ipsum dolor sit');
```
#### Recommendations
diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md
index cf50e417278..65cde363e98 100644
--- a/doc/development/i18n/proofreader.md
+++ b/doc/development/i18n/proofreader.md
@@ -31,7 +31,7 @@ are very appreciative of the work done by translators and proofreaders!
- Huang Tao - [GitLab](https://gitlab.com/htve), [Crowdin](https://crowdin.com/profile/htve)
- Victor Wu - [GitLab](https://gitlab.com/_victorwu_), [Crowdin](https://crowdin.com/profile/victorwu)
- Xiaogang Wen - [GitLab](https://gitlab.com/xiaogang_cn), [Crowdin](https://crowdin.com/profile/xiaogang_gitlab)
- - Shuang Zhang - [GitLab](https://gitlab.com/tonygodspeed92), [Crowdin](https://crowdin.com/profile/tonygodspeed92)
+ - Qi Zhao - [GitLab](https://gitlab.com/zhaoqi01), [Crowdin](https://crowdin.com/profile/zhaoqi01)
- Chinese Traditional ç¹é«”中文
- Weizhe Ding - [GitLab](https://gitlab.com/d.weizhe), [Crowdin](https://crowdin.com/profile/d.weizhe)
- Yi-Jyun Pan - [GitLab](https://gitlab.com/pan93412), [Crowdin](https://crowdin.com/profile/pan93412)
diff --git a/doc/development/img/build_package_v12_6.png b/doc/development/img/build_package_v12_6.png
deleted file mode 100644
index 32a3ebedba4..00000000000
--- a/doc/development/img/build_package_v12_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/development/img/trigger_build_package_v12_6.png b/doc/development/img/trigger_build_package_v12_6.png
deleted file mode 100644
index ca6797ebf65..00000000000
--- a/doc/development/img/trigger_build_package_v12_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/development/img/trigger_omnibus_v16_3.png b/doc/development/img/trigger_omnibus_v16_3.png
new file mode 100644
index 00000000000..d5348333faa
--- /dev/null
+++ b/doc/development/img/trigger_omnibus_v16_3.png
Binary files differ
diff --git a/doc/development/img/triggered_ee_pipeline_v16_3.png b/doc/development/img/triggered_ee_pipeline_v16_3.png
new file mode 100644
index 00000000000..be91f35b9ab
--- /dev/null
+++ b/doc/development/img/triggered_ee_pipeline_v16_3.png
Binary files differ
diff --git a/doc/development/integrations/index.md b/doc/development/integrations/index.md
index dd73256ce11..f84375b3b77 100644
--- a/doc/development/integrations/index.md
+++ b/doc/development/integrations/index.md
@@ -12,7 +12,7 @@ which are part of our [main Rails project](https://gitlab.com/gitlab-org/gitlab)
Also see our [direction page](https://about.gitlab.com/direction/manage/import_and_integrate/integrations/) for an overview of our strategy around integrations.
-This guide is a work in progress. You're welcome to ping `@gitlab-org/manage/integrations`
+This guide is a work in progress. You're welcome to ping `@gitlab-org/manage/import-and-integrate`
if you need clarification or spot any outdated information.
## Add a new integration
@@ -39,9 +39,9 @@ if you need clarification or spot any outdated information.
has_one :foo_bar_integration, class_name: 'Integrations::FooBar'
```
-### Define properties
+### Define fields
-Integrations can define arbitrary properties to store their configuration with the class method `Integration.prop_accessor`.
+Integrations can define arbitrary fields to store their configuration with the class method `Integration.field`.
The values are stored as an encrypted JSON hash in the `integrations.encrypted_properties` column.
For example:
@@ -49,25 +49,26 @@ For example:
```ruby
module Integrations
class FooBar < Integration
- prop_accessor :url
- prop_accessor :tags
+ field :url
+ field :tags
end
end
```
-`Integration.prop_accessor` installs accessor methods on the class. Here we would have `#url`, `#url=` and `#url_changed?`, to manage the `url` field. Fields stored in `Integration#properties` should be accessed by these accessors directly on the model, just like other ActiveRecord attributes.
+`Integration.field` installs accessor methods on the class.
+Here we would have `#url`, `#url=`, and `#url_changed?` to manage the `url` field.
+These accessors should access the fields stored in `Integration#properties` directly on the model, just like other `ActiveRecord` attributes.
-You should always access the properties through their `getters`, and not interact with the `properties` hash directly.
+You should always access the fields through their `getters` and not interact with the `properties` hash directly.
You **must not** write to the `properties` hash, you **must** use the generated setter method instead. Direct writes to this
hash are not persisted.
You should also define validations for all your properties.
+To see how these fields are exposed in the frontend form for the integration,
+see [Customize the frontend form](#customize-the-frontend-form).
-Also refer to the section [Customize the frontend form](#customize-the-frontend-form) below to see how these properties
-are exposed in the frontend form for the integration.
-
-There is an alternative approach using `Integration.data_field`, which you may see in other integrations.
-With data fields the values are stored in a separate table per integration. At the moment we don't recommend using this for new integrations.
+Other approaches include using `Integration.prop_accessor` or `Integration.data_field`, which you might see in earlier versions of integrations.
+You should not use these approaches for new integrations.
### Define trigger events
@@ -94,7 +95,7 @@ The following events are supported for integrations:
| [Pipeline event](../../user/project/integrations/webhook_events.md#pipeline-events) | | `pipeline` | A pipeline status changes.
| [Push event](../../user/project/integrations/webhook_events.md#push-events) | ✓ | `push` | A push is made to the repository.
| [Tag push event](../../user/project/integrations/webhook_events.md#tag-events) | ✓ | `tag_push` | New tags are pushed to the repository.
-| Vulnerability event **(ULTIMATE)** | | `vulnerability` | A new, unique vulnerability is recorded.
+| Vulnerability event **(ULTIMATE ALL)** | | `vulnerability` | A new, unique vulnerability is recorded.
| [Wiki page event](../../user/project/integrations/webhook_events.md#wiki-page-events) | ✓ | `wiki_page` | A wiki page is created or updated.
#### Event examples
@@ -191,8 +192,8 @@ This method should return an array of hashes for each field, where the keys can
| Key | Type | Required | Default | Description
|:---------------|:--------|:---------|:-----------------------------|:--
-| `type:` | string | true | | The type of the form field. Can be `text`, `textarea`, `password`, `checkbox`, or `select`.
-| `name:` | string | true | | The property name for the form field. This must match a `prop_accessor` [defined on the class](#define-properties).
+| `type:` | symbol | true | `:text` | The type of the form field. Can be `:text`, `:textarea`, `:password`, `:checkbox`, or `:select`.
+| `name:` | string | true | | The property name for the form field.
| `required:` | boolean | false | `false` | Specify if the form field is required or optional.
| `title:` | string | false | Capitalized value of `name:` | The label for the form field.
| `placeholder:` | string | false | | A placeholder for the form field.
@@ -200,19 +201,19 @@ This method should return an array of hashes for each field, where the keys can
| `api_only:` | boolean | false | `false` | Specify if the field should only be available through the API, and excluded from the frontend form.
| `if:` | boolean or lambda | false | `true` | Specify if the field should be available. The value can be a boolean or a lambda.
-### Additional keys for `type: 'checkbox'`
+### Additional keys for `type: :checkbox`
| Key | Type | Required | Default | Description
|:------------------|:-------|:---------|:------------------|:--
| `checkbox_label:` | string | false | Value of `title:` | A custom label that displays next to the checkbox.
-### Additional keys for `type: 'select'`
+### Additional keys for `type: :select`
| Key | Type | Required | Default | Description
|:-----------|:------|:---------|:--------|:--
| `choices:` | array | true | | A nested array of `[label, value]` tuples.
-### Additional keys for `type: 'password'`
+### Additional keys for `type: :password`
| Key | Type | Required | Default | Description
|:----------------------------|:-------|:---------|:------------------|:--
@@ -226,30 +227,20 @@ This example defines a required `url` field, and optional `username` and `passwo
```ruby
module Integrations
class FooBar < Integration
- prop_accessor :url, :username, :password
-
- def fields
- [
- {
- type: 'text',
- name: 'url',
- title: s_('FooBarIntegration|Server URL'),
- placeholder: 'https://example.com/',
- required: true
- },
- {
- type: 'text',
- name: 'username',
- title: s_('FooBarIntegration|Username'),
- },
- {
- type: 'password',
- name: 'password',
- title: s_('FoobarIntegration|Password'
- non_empty_password_title: s_('FooBarIntegration|Enter new password')
- }
- ]
- end
+ field :url,
+ type: :text,
+ title: s_('FooBarIntegration|Server URL'),
+ placeholder: 'https://example.com/',
+ required: true
+
+ field :username,
+ type: :text,
+ title: s_('FooBarIntegration|Username')
+
+ field :password,
+ type: 'password',
+ title: s_('FoobarIntegration|Password'
+ non_empty_password_title: s_('FooBarIntegration|Enter new password')
end
end
```
diff --git a/doc/development/integrations/jenkins.md b/doc/development/integrations/jenkins.md
index 65194a04a62..f52098394dc 100644
--- a/doc/development/integrations/jenkins.md
+++ b/doc/development/integrations/jenkins.md
@@ -24,7 +24,7 @@ brew services start jenkins
GitLab does not allow requests to localhost or the local network by default. When running Jenkins on your local machine, you need to enable local access.
1. Log into your GitLab instance as an administrator.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**, and select the following checkboxes:
@@ -55,8 +55,8 @@ To set up the Jenkins project you intend to run your build on, read
You can configure your integration between Jenkins and GitLab:
-- With the [recommended approach for Jenkins integration](../../integration/jenkins.md#configure-a-jenkins-integration-recommended).
-- [Using a webhook](../../integration/jenkins.md#configure-a-webhook).
+- With the [recommended approach for Jenkins integration](../../integration/jenkins.md#with-a-jenkins-server-url).
+- [Using a webhook](../../integration/jenkins.md#with-a-webhook).
## Test your setup
diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md
index 8fda6042fcf..8c6e3145000 100644
--- a/doc/development/integrations/secure.md
+++ b/doc/development/integrations/secure.md
@@ -181,7 +181,7 @@ See also [Docker Tagging: Best practices for tagging and versioning Docker image
## Command line
-A scanner is a command line tool that takes environment variables as inputs,
+A scanner is a command-line tool that takes environment variables as inputs,
and generates a file that is uploaded as a report (based on the job definition).
It also generates text output on the standard output and standard error streams, and exits with a status code.
diff --git a/doc/development/internal_analytics/index.md b/doc/development/internal_analytics/index.md
index c7cf907ca92..d24ecf5a99c 100644
--- a/doc/development/internal_analytics/index.md
+++ b/doc/development/internal_analytics/index.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/internal_event_tracking/architecture.md b/doc/development/internal_analytics/internal_event_tracking/architecture.md
index de5672a4895..0265e39745a 100644
--- a/doc/development/internal_analytics/internal_event_tracking/architecture.md
+++ b/doc/development/internal_analytics/internal_event_tracking/architecture.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/internal_event_tracking/event_definition_guide.md b/doc/development/internal_analytics/internal_event_tracking/event_definition_guide.md
index 7e4222ead2e..591c6672810 100644
--- a/doc/development/internal_analytics/internal_event_tracking/event_definition_guide.md
+++ b/doc/development/internal_analytics/internal_event_tracking/event_definition_guide.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/internal_event_tracking/index.md b/doc/development/internal_analytics/internal_event_tracking/index.md
index 73e9e2d1a4c..e35d5f6f084 100644
--- a/doc/development/internal_analytics/internal_event_tracking/index.md
+++ b/doc/development/internal_analytics/internal_event_tracking/index.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/internal_event_tracking/introduction.md b/doc/development/internal_analytics/internal_event_tracking/introduction.md
index ebb3caa198a..e776691fdf0 100644
--- a/doc/development/internal_analytics/internal_event_tracking/introduction.md
+++ b/doc/development/internal_analytics/internal_event_tracking/introduction.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/internal_event_tracking/migration.md b/doc/development/internal_analytics/internal_event_tracking/migration.md
new file mode 100644
index 00000000000..4b8a726768f
--- /dev/null
+++ b/doc/development/internal_analytics/internal_event_tracking/migration.md
@@ -0,0 +1,155 @@
+---
+stage: Analyze
+group: Analytics Instrumentation
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Migrating existing tracking to internal event tracking
+
+GitLab Internal Events Tracking exposes a unified API on top of the existing tracking options. Currently RedisHLL and Snowplow are supported.
+
+This page describes how you can switch from tracking using a single method to using Internal Events Tracking.
+
+## Migrating from tracking with Snowplow
+
+If you are already tracking events in Snowplow, you can start collecting metrics also from self-managed instances by switching to Internal Events Tracking.
+
+Notice that the Snowplow event you trigger after switching to Internal Events Tracking looks slightly different from your current event.
+
+Please make sure that you are okay with this change before you migrate.
+
+### Backend
+
+If you are already tracking Snowplow events using `Gitlab::Tracking.event` and you want to migrate to Internal Events Tracking you might start with something like this:
+
+```ruby
+Gitlab::Tracking.event(name, 'ci_templates_unique', namespace: namespace,
+ project: project, context: [context], user: user, label: label)
+```
+
+The code above can be replaced by something like this:
+
+```ruby
+Gitlab::InternalEvents.track_event('ci_templates_unique', namespace: namespace, project: project, user: user)
+```
+
+In addition, you have to create definitions for the metrics that you would like to track.
+
+To generate metric definitions, you can use the generator like this:
+
+```shell
+bin/rails g gitlab:analytics:internal_events \
+ --time_frames=7d 28d\
+ --group=project_management \
+ --stage=plan \
+ --section=dev \
+ --event=ci_templates_unique \
+ --unique=user.id \
+ --mr=https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121544
+```
+
+### Frontend
+
+If you are using the `Tracking` mixin in the Vue component, you can replace it with the `InternalEvents` mixin.
+
+For example, if your current Vue component look like this:
+
+```vue
+import Tracking from '~/tracking';
+...
+mixins: [Tracking.mixin()]
+...
+...
+this.track('some_label', options)
+```
+
+After converting it to Internal Events Tracking, it should look like this:
+
+```vue
+import { InternalEvents } from '~/tracking';
+...
+mixins: [InternalEvents.mixin()]
+...
+...
+this.track_event('action')
+```
+
+You can use [this MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123901/diffs) as an example. It migrates the `devops_adoption_app` component to use Internal Events Tracking.
+
+If you are using `data-track-action` in the component, you have to change it to `data-event-tracking` to migrate to Internal Events Tracking.
+
+For example, if a button is defined like this:
+
+```vue
+ <gl-button
+ :href="diffFile.external_url"
+ :title="externalUrlLabel"
+ :aria-label="externalUrlLabel"
+ target="_blank"
+ data-track-action="click_toggle_external_button"
+ data-track-label="diff_toggle_external_button"
+ data-track-property="diff_toggle_external"
+ icon="external-link"
+/>
+```
+
+This can be converted to Internal Events Tracking like this:
+
+```vue
+ <gl-button
+ :href="diffFile.external_url"
+ :title="externalUrlLabel"
+ :aria-label="externalUrlLabel"
+ target="_blank"
+ data-event-tracking="click_toggle_external_button"
+ icon="external-link"
+/>
+```
+
+Notice that we just need action to pass in the `data-event-tracking` attribute which will be passed to both Snowplow and RedisHLL.
+
+## Migrating from tracking with RedisHLL
+
+### Backend
+
+If you are currently tracking a metric in `RedisHLL` like this:
+
+```ruby
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:git_write_action, values: current_user.id)
+```
+
+To start using Internal Events Tracking, follow these steps:
+
+1. Create an event definition that describes `git_write_action` ([guide](../snowplow/event_dictionary_guide.md#create-a-new-event-definition)).
+1. Find metric definitions that list `git_write_action` in the events section (`20210216182041_action_monthly_active_users_git_write.yml` and `20210216184045_git_write_action_weekly.yml`).
+1. Change the `data_source` from `redis_hll` to `internal_events` in the metric definition files.
+1. Add an `events` section to both metric definition files.
+
+ ```yaml
+ events:
+ - name: git_write_action
+ unique: user.id
+ ```
+
+ Use `project.id` or `namespace.id` instead of `user.id` if your metric is counting something other than unique users.
+1. Call `InternalEvents.tract_event` instead of `HLLRedisCounter.track_event`:
+
+ ```diff
+ - Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:git_write_action, values: current_user.id)
+ + Gitlab::InternalEvents.track_event('project_created', user: current_user)
+ ```
+
+1. Optional. Add additional values to the event. You typically want to add `project` and `namespace` as it is useful information to have in the data warehouse.
+
+ ```diff
+ - Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:git_write_action, values: current_user.id)
+ + Gitlab::InternalEvents.track_event('project_created', user: current_user, project: project, namespace: namespace)
+ ```
+
+1. Update your test to use the `internal event tracking` shared example.
+
+### Frontend
+
+If you are calling `trackRedisHllUserEvent` in the frontend to track the frontend event, you can convert this to Internal events by using mixin, raw JavaScript or data tracking attribute,
+
+[Quick start guide](quick_start.md#frontend-tracking) has example for each methods.
diff --git a/doc/development/internal_analytics/internal_event_tracking/quick_start.md b/doc/development/internal_analytics/internal_event_tracking/quick_start.md
index 84926657a3b..19c76ecc045 100644
--- a/doc/development/internal_analytics/internal_event_tracking/quick_start.md
+++ b/doc/development/internal_analytics/internal_event_tracking/quick_start.md
@@ -1,15 +1,39 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Quick start for internal event tracking
+# Quick start for Internal Event Tracking
In an effort to provide a more efficient, scalable, and unified tracking API, GitLab is deprecating existing RedisHLL and Snowplow tracking. Instead, we're implementing a new `track_event` method.
-With this approach, we can both update RedisHLL counters and send Snowplow events simultaneously, streamlining the tracking process.
+With this approach, we can update both RedisHLL counters and send Snowplow events without worrying about the underlying implementation.
-## Create and trigger events
+In order to instrument your code with Internal Events Tracking need three things:
+
+1. Define an event
+1. Define one or more metrics
+1. Trigger the event
+
+## Defining event and metrics
+
+To create event and metric definitions you can use the `internal_events` generator.
+
+This example will create an event definition for an event called `project_created` and two metric definitions which will be aggregated every 7 and 28 days.
+
+```shell
+bin/rails g gitlab:analytics:internal_events \
+--time_frames=7d 28d \
+--group=project_management \
+--stage=plan --section=dev \
+--event=project_created \
+--unique=user.id \
+--mr=https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121544
+```
+
+## Trigger events
+
+Triggering an event and thereby updating a metric is slightly different on backend and frontend. Please refer to the relevant section below.
### Backend tracking
@@ -18,9 +42,9 @@ To trigger an event, call the `Gitlab::InternalEvents.track_event` method with t
```ruby
Gitlab::InternalEvents.track_event(
"i_code_review_user_apply_suggestion",
- user_id: user_id,
- namespace_id: namespace_id,
- project_id: project_id
+ user: user,
+ namespace: namespace,
+ project: project
)
```
@@ -46,7 +70,7 @@ To implement Vue component tracking:
```javascript
export default {
mixins: [trackingMixin],
-
+
data() {
return {
expanded: false,
@@ -97,7 +121,7 @@ This attribute ensures that if we want to track GitLab internal events for a but
</gl-button>
```
-For Haml
+#### Haml
```haml
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle', data: { event_tracking: 'action' }}) do
@@ -111,3 +135,7 @@ Sometimes we want to send internal events when the component is rendered or load
= render Pajamas::ButtonComponent.new(button_options: { data: { event_tracking_load: 'true', event_tracking: 'i_devops' } }) do
= _("New project")
```
+
+### Limitations
+
+The only values we allow for `unique` are `user.id`, `project.id`, and `namespace.id`, as they are logged as part of the standard context. We currently don't have anywhere to put a value like `merge_request.id`. That will change with self-describing events.
diff --git a/doc/development/internal_analytics/service_ping/implement.md b/doc/development/internal_analytics/service_ping/implement.md
index 9dbfa02854d..c6da26f86c2 100644
--- a/doc/development/internal_analytics/service_ping/implement.md
+++ b/doc/development/internal_analytics/service_ping/implement.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/service_ping/index.md b/doc/development/internal_analytics/service_ping/index.md
index 22e66a247c9..f532bb1ac31 100644
--- a/doc/development/internal_analytics/service_ping/index.md
+++ b/doc/development/internal_analytics/service_ping/index.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/service_ping/metrics_dictionary.md b/doc/development/internal_analytics/service_ping/metrics_dictionary.md
index 8103db5113f..e677118fff6 100644
--- a/doc/development/internal_analytics/service_ping/metrics_dictionary.md
+++ b/doc/development/internal_analytics/service_ping/metrics_dictionary.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -46,9 +46,9 @@ Each metric is defined in a separate YAML file consisting of a number of fields:
| `performance_indicator_type` | no | `array`; may be set to one of [`gmau`, `smau`, `paid_gmau`, `umau` or `customer_health_score`](https://about.gitlab.com/handbook/business-technology/data-team/data-catalog/xmau-analysis/). |
| `tier` | yes | `array`; may contain one or a combination of `free`, `premium` or `ultimate`. The [tier](https://about.gitlab.com/handbook/marketing/brand-and-product-marketing/product-and-solution-marketing/tiers/#definitions) where the tracked feature is available. This should be verbose and contain all tiers where a metric is available. |
| `milestone` | yes | The milestone when the metric is introduced and when it's available to self-managed instances with the official GitLab release. |
-| `milestone_removed` | no | The milestone when the metric is removed. |
+| `milestone_removed` | no | The milestone when the metric is removed. Required for removed metrics. |
| `introduced_by_url` | no | The URL to the merge request that introduced the metric to be available for self-managed instances. |
-| `removed_by_url` | no | The URL to the merge request that removed the metric. |
+| `removed_by_url` | no | The URL to the merge request that removed the metric. Required for removed metrics. |
| `repair_issue_url` | no | The URL of the issue that was created to repair a metric with a `broken` status. |
| `options` | no | `object`: options information needed to calculate the metric value. |
| `skip_validation` | no | This should **not** be set. [Used for imported metrics until we review, update and make them valid](https://gitlab.com/groups/gitlab-org/-/epics/5425). |
diff --git a/doc/development/internal_analytics/service_ping/metrics_instrumentation.md b/doc/development/internal_analytics/service_ping/metrics_instrumentation.md
index dc225a40d1b..ada7cc566a1 100644
--- a/doc/development/internal_analytics/service_ping/metrics_instrumentation.md
+++ b/doc/development/internal_analytics/service_ping/metrics_instrumentation.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/service_ping/metrics_lifecycle.md b/doc/development/internal_analytics/service_ping/metrics_lifecycle.md
index bb3d6797011..4980a8cf63d 100644
--- a/doc/development/internal_analytics/service_ping/metrics_lifecycle.md
+++ b/doc/development/internal_analytics/service_ping/metrics_lifecycle.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/service_ping/performance_indicator_metrics.md b/doc/development/internal_analytics/service_ping/performance_indicator_metrics.md
index d7811c52bb1..63177f093e2 100644
--- a/doc/development/internal_analytics/service_ping/performance_indicator_metrics.md
+++ b/doc/development/internal_analytics/service_ping/performance_indicator_metrics.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/service_ping/review_guidelines.md b/doc/development/internal_analytics/service_ping/review_guidelines.md
index 8a46de7086e..c816c905097 100644
--- a/doc/development/internal_analytics/service_ping/review_guidelines.md
+++ b/doc/development/internal_analytics/service_ping/review_guidelines.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/service_ping/troubleshooting.md b/doc/development/internal_analytics/service_ping/troubleshooting.md
index 8f5e94506cd..e685635c5f7 100644
--- a/doc/development/internal_analytics/service_ping/troubleshooting.md
+++ b/doc/development/internal_analytics/service_ping/troubleshooting.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -58,7 +58,7 @@ checking the configuration file of your GitLab instance:
- Using the Admin Area:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Metrics and profiling**.
1. Expand **Usage statistics**.
@@ -116,7 +116,7 @@ To work around this bug, you have two options:
sudo gitlab-ctl reconfigure
```
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Metrics and profiling**.
1. Expand **Usage statistics**.
diff --git a/doc/development/internal_analytics/service_ping/usage_data.md b/doc/development/internal_analytics/service_ping/usage_data.md
index b6ec3e00670..8742bc03fbb 100644
--- a/doc/development/internal_analytics/service_ping/usage_data.md
+++ b/doc/development/internal_analytics/service_ping/usage_data.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/snowplow/event_dictionary_guide.md b/doc/development/internal_analytics/snowplow/event_dictionary_guide.md
index 6e8947e0210..c0d5e3efdfa 100644
--- a/doc/development/internal_analytics/snowplow/event_dictionary_guide.md
+++ b/doc/development/internal_analytics/snowplow/event_dictionary_guide.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/snowplow/implementation.md b/doc/development/internal_analytics/snowplow/implementation.md
index 5ad97cf528c..5d328f22ca5 100644
--- a/doc/development/internal_analytics/snowplow/implementation.md
+++ b/doc/development/internal_analytics/snowplow/implementation.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/snowplow/index.md b/doc/development/internal_analytics/snowplow/index.md
index 8265bceaf06..17d3f3f2cfc 100644
--- a/doc/development/internal_analytics/snowplow/index.md
+++ b/doc/development/internal_analytics/snowplow/index.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -32,7 +32,7 @@ instances do not have a collector configured and do not collect data via Snowplo
You can configure your self-managed GitLab instance to use a custom Snowplow collector.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Snowplow**.
diff --git a/doc/development/internal_analytics/snowplow/infrastructure.md b/doc/development/internal_analytics/snowplow/infrastructure.md
index 462dee2c39b..b856ccec78e 100644
--- a/doc/development/internal_analytics/snowplow/infrastructure.md
+++ b/doc/development/internal_analytics/snowplow/infrastructure.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/snowplow/review_guidelines.md b/doc/development/internal_analytics/snowplow/review_guidelines.md
index 03d1812cbfc..a0bdad8fafb 100644
--- a/doc/development/internal_analytics/snowplow/review_guidelines.md
+++ b/doc/development/internal_analytics/snowplow/review_guidelines.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/snowplow/schemas.md b/doc/development/internal_analytics/snowplow/schemas.md
index 21142f68d39..2cc09500c36 100644
--- a/doc/development/internal_analytics/snowplow/schemas.md
+++ b/doc/development/internal_analytics/snowplow/schemas.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_analytics/snowplow/troubleshooting.md b/doc/development/internal_analytics/snowplow/troubleshooting.md
index b531c6dcd56..5eabba04792 100644
--- a/doc/development/internal_analytics/snowplow/troubleshooting.md
+++ b/doc/development/internal_analytics/snowplow/troubleshooting.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Analytics Instrumentation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/internal_api/index.md b/doc/development/internal_api/index.md
index 538b66124ba..81fd78d1d27 100644
--- a/doc/development/internal_api/index.md
+++ b/doc/development/internal_api/index.md
@@ -178,6 +178,40 @@ Example response:
- GitLab Shell
+## Authorized Certs
+
+This endpoint is called by the GitLab Shell to get the namespace that has a particular CA SSH certificate
+configured. It also accepts `user_identifier` to return a GitLab user for specified identifier.
+
+| Attribute | Type | Required | Description |
+|:----------------------|:-------|:---------|:------------|
+| `key` | string | yes | The fingerprint of the SSH certificate. |
+| `user_identifier` | string | yes | The identifier of the user to whom the SSH certificate has been issued (username or primary email). |
+
+```plaintext
+GET /internal/authorized_certs
+```
+
+Example request:
+
+```shell
+curl --request GET --header "Gitlab-Shell-Api-Request: <JWT token>" "http://localhost:3001/api/v4/internal/authorized_certs?key=<key>&user_identifier=<user_identifier>"
+```
+
+Example response:
+
+```json
+{
+ "success": true,
+ "namespace": "gitlab-org",
+ "username": "root"
+}
+```
+
+### Known consumers
+
+- GitLab Shell
+
## Get user for user ID or key
This endpoint is used when a user performs `ssh git@gitlab.com`. It
@@ -492,21 +526,24 @@ curl --request GET --header "Gitlab-Kas-Api-Request: <JWT token>" \
Called from GitLab agent server (`kas`) to increase the usage
metric counters.
-| Attribute | Type | Required | Description |
-|:--------------------------------------------------------------------------|:--------------|:---------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `counters` | hash | no | Hash of counters |
-| `counters["k8s_api_proxy_request"]` | integer | no | The number to increase the `k8s_api_proxy_request` counter by |
-| `counters["gitops_sync"]` | integer | no | The number to increase the `gitops_sync` counter by |
-| `counters["flux_git_push_notifications_total"]` | integer | no | The number to increase the `flux_git_push_notifications_total` counter by |
-| `counters["k8s_api_proxy_requests_via_ci_access"]` | integer | no | The number to increase the `k8s_api_proxy_requests_via_ci_access` counter by |
-| `counters["k8s_api_proxy_requests_via_user_access"]` | integer | no | The number to increase the `k8s_api_proxy_requests_via_user_access` counter by |
-| `unique_counters` | hash | no | Array of unique numbers |
-| `unique_counters["agent_users_using_ci_tunnel"]` | integer array | no | The set of unique user ids that have interacted a CI Tunnel to track the `agent_users_using_ci_tunnel` metric event |
-| `unique_counters["k8s_api_proxy_requests_unique_users_via_ci_access"]` | integer array | no | The set of unique user ids that have interacted a CI Tunnel via `ci_access` to track the `k8s_api_proxy_requests_unique_users_via_ci_access` metric event |
-| `unique_counters["k8s_api_proxy_requests_unique_agents_via_ci_access"]` | integer array | no | The set of unique user ids that have interacted a CI Tunnel via `ci_access` to track the `k8s_api_proxy_requests_unique_agents_via_ci_access` metric event |
-| `unique_counters["k8s_api_proxy_requests_unique_users_via_user_access"]` | integer array | no | The set of unique user ids that have interacted a CI Tunnel via `user_access` to track the `k8s_api_proxy_requests_unique_users_via_user_access` metric event |
-| `unique_counters["k8s_api_proxy_requests_unique_agents_via_user_access"]` | integer array | no | The set of unique user ids that have interacted a CI Tunnel via `user_access` to track the `k8s_api_proxy_requests_unique_agents_via_user_access` metric event |
-| `unique_counters["flux_git_push_notified_unique_projects"]` | integer array | no | The set of unique projects ids that have been notified to reconcile their Flux workloads to track the `flux_git_push_notified_unique_projects` metric event |
+| Attribute | Type | Required | Description |
+|:--------------------------------------------------------------------------|:--------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `counters` | hash | no | Hash of counters |
+| `counters["k8s_api_proxy_request"]` | integer | no | The number to increase the `k8s_api_proxy_request` counter by |
+| `counters["gitops_sync"]` | integer | no | The number to increase the `gitops_sync` counter by |
+| `counters["flux_git_push_notifications_total"]` | integer | no | The number to increase the `flux_git_push_notifications_total` counter by |
+| `counters["k8s_api_proxy_requests_via_ci_access"]` | integer | no | The number to increase the `k8s_api_proxy_requests_via_ci_access` counter by |
+| `counters["k8s_api_proxy_requests_via_user_access"]` | integer | no | The number to increase the `k8s_api_proxy_requests_via_user_access` counter by |
+| `counters["k8s_api_proxy_requests_via_pat_access"]` | integer | no | The number to increase the `k8s_api_proxy_requests_via_pat_access` counter by |
+| `unique_counters` | hash | no | Array of unique numbers |
+| `unique_counters["agent_users_using_ci_tunnel"]` | integer array | no | The set of unique user ids that have interacted a CI Tunnel to track the `agent_users_using_ci_tunnel` metric event |
+| `unique_counters["k8s_api_proxy_requests_unique_users_via_ci_access"]` | integer array | no | The set of unique user ids that have interacted a CI Tunnel via `ci_access` to track the `k8s_api_proxy_requests_unique_users_via_ci_access` metric event |
+| `unique_counters["k8s_api_proxy_requests_unique_agents_via_ci_access"]` | integer array | no | The set of unique agent ids that have interacted a CI Tunnel via `ci_access` to track the `k8s_api_proxy_requests_unique_agents_via_ci_access` metric event |
+| `unique_counters["k8s_api_proxy_requests_unique_users_via_user_access"]` | integer array | no | The set of unique user ids that have interacted a CI Tunnel via `user_access` to track the `k8s_api_proxy_requests_unique_users_via_user_access` metric event |
+| `unique_counters["k8s_api_proxy_requests_unique_agents_via_user_access"]` | integer array | no | The set of unique agent ids that have interacted a CI Tunnel via `user_access` to track the `k8s_api_proxy_requests_unique_agents_via_user_access` metric event |
+| `unique_counters["k8s_api_proxy_requests_unique_users_via_pat_access"]` | integer array | no | The set of unique user ids that have used the KAS Kubernetes API proxy via PAT to track the `k8s_api_proxy_requests_unique_users_via_pat_access` metric event |
+| `unique_counters["k8s_api_proxy_requests_unique_agents_via_pat_access"]` | integer array | no | The set of unique agent ids that have used the KAS Kubernetes API proxy via PAT to track the `k8s_api_proxy_requests_unique_agents_via_pat_access` metric event |
+| `unique_counters["flux_git_push_notified_unique_projects"]` | integer array | no | The set of unique projects ids that have been notified to reconcile their Flux workloads to track the `flux_git_push_notified_unique_projects` metric event |
```plaintext
POST /internal/kubernetes/usage_metrics
@@ -819,7 +856,7 @@ Example response:
## Subscription add-on purchases (excluding storage and compute packs)
-The subscription add-on purchase endpoint is used by [CustomersDot](https://gitlab.com/gitlab-org/customers-gitlab-com) (`customers.gitlab.com`) to apply subscription add-on purchases like code suggestions for personal namespaces, or top-level groups within GitLab.com. It is not used to apply storage and compute pack purchases.
+The subscription add-on purchase endpoint is used by [CustomersDot](https://gitlab.com/gitlab-org/customers-gitlab-com) (`customers.gitlab.com`) to apply subscription add-on purchases like Code Suggestions for personal namespaces, or top-level groups within GitLab.com. It is not used to apply storage and compute pack purchases.
### Create a subscription add-on purchase
@@ -831,9 +868,9 @@ POST /namespaces/:id/subscription_add_on_purchase/:add_on_name
| Attribute | Type | Required | Description |
|:------------|:--------|:---------|:------------|
-| `quantity` | integer | yes | Amount of units in the subscription add-on purchase (Example: Number of seats for a code suggestions add-on) |
+| `quantity` | integer | yes | Amount of units in the subscription add-on purchase (Example: Number of seats for a Code Suggestions add-on) |
| `expires_on` | date | yes | Expiration date of the subscription add-on purchase |
-| `purchase_xid` | string | yes | Identifier for the subscription add-on purchase (Example: Subscription name for a code suggestions add-on) |
+| `purchase_xid` | string | yes | Identifier for the subscription add-on purchase (Example: Subscription name for a Code Suggestions add-on) |
Example request:
@@ -864,9 +901,9 @@ PUT /namespaces/:id/subscription_add_on_purchase/:add_on_name
| Attribute | Type | Required | Description |
|:------------|:--------|:---------|:------------|
-| `quantity` | integer | no | Amount of units in the subscription add-on purchase (Example: Number of seats for a code suggestions add-on) |
+| `quantity` | integer | no | Amount of units in the subscription add-on purchase (Example: Number of seats for a Code Suggestions add-on) |
| `expires_on` | date | yes | Expiration date of the subscription add-on purchase |
-| `purchase_xid` | string | no | Identifier for the subscription add-on purchase (Example: Subscription name for a code suggestions add-on) |
+| `purchase_xid` | string | no | Identifier for the subscription add-on purchase (Example: Subscription name for a Code Suggestions add-on) |
Example request:
@@ -1365,7 +1402,7 @@ Example request:
```shell
curl --verbose --request PATCH "https://gitlab.example.com/api/scim/v2/groups/test_group/Users/f0b1d561c-21ff-4092-beab-8154b17f82f2" \
- --data '{ "Operations": [{"op":"Update","path":"name.formatted","value":"New Name"}] }' \
+ --data '{ "Operations": [{"op":"replace","path":"id","value":"1234abcd"}] }' \
--header "Authorization: Bearer <your_scim_token>" --header "Content-Type: application/scim+json"
```
diff --git a/doc/development/internal_users.md b/doc/development/internal_users.md
index 1c12e541149..cf45cf941d0 100644
--- a/doc/development/internal_users.md
+++ b/doc/development/internal_users.md
@@ -43,7 +43,7 @@ Other examples of internal users:
- [GitLab Admin Bot](https://gitlab.com/gitlab-org/gitlab/-/blob/278bc9018dd1515a10cbf15b6c6cd55cb5431407/app/models/user.rb#L950-960)
- [Alert Bot](../operations/incident_management/alerts.md#trigger-actions-from-alerts)
- [Ghost User](../user/profile/account/delete_account.md#associated-records)
-- [Support Bot](../user/project/service_desk/index.md#support-bot-user)
+- [Support Bot](../user/project/service_desk/configure.md#support-bot-user)
- Visual Review Bot
- Resource access tokens, including:
- [Project access tokens](../user/project/settings/project_access_tokens.md).
diff --git a/doc/development/merge_request_concepts/performance.md b/doc/development/merge_request_concepts/performance.md
index 665b84b2c40..7e26bf982b2 100644
--- a/doc/development/merge_request_concepts/performance.md
+++ b/doc/development/merge_request_concepts/performance.md
@@ -195,20 +195,18 @@ costly, time-consuming query to the replicas.
Read about [complex queries on the relation object](../database/iterating_tables_in_batches.md#complex-queries-on-the-relation-object)
for considerations on how to use CTEs. We have found in some situations that CTEs can become
-problematic in use (similar to the n+1 problem above). In particular, hierarchical recursive
+problematic in use (similar to the N+1 problem above). In particular, hierarchical recursive
CTE queries such as the CTE in [AuthorizedProjectsWorker](https://gitlab.com/gitlab-org/gitlab/-/issues/325688)
are very difficult to optimize and don't scale. We should avoid them when implementing new features
that require any kind of hierarchical structure.
CTEs have been effectively used as an optimization fence in many simpler cases,
such as this [example](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/43242#note_61416277).
-Beginning in PostgreSQL 12, CTEs are inlined then [optimized by default](https://paquier.xyz/postgresql-2/postgres-12-with-materialize/).
-Keeping the old behavior requires marking CTEs with the keyword `MATERIALIZED`.
+With the currently supported PostgreSQL versions, the optimization fence behavior must be enabled
+with the `MATERIALIZED` keyword. By default CTEs are inlined then [optimized by default](https://paquier.xyz/postgresql-2/postgres-12-with-materialize/).
When building CTE statements, use the `Gitlab::SQL::CTE` class [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56976) in GitLab 13.11.
-By default, this `Gitlab::SQL::CTE` class forces materialization through adding the `MATERIALIZED` keyword for PostgreSQL 12 and higher.
-`Gitlab::SQL::CTE` automatically omits materialization when PostgreSQL 11 is running
-(this behavior is implemented using a custom Arel node `Gitlab::Database::AsWithMaterialized` under the surface).
+By default, this `Gitlab::SQL::CTE` class forces materialization through adding the `MATERIALIZED` keyword.
WARNING:
Upgrading to GitLab 14.0 requires PostgreSQL 12 or later.
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 65dc4de30d1..9be322812e3 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -1290,6 +1290,48 @@ class BuildMetadata
end
```
+Additionally, you can expose the keys in a `JSONB` column as
+ActiveRecord attributes. Do this when you need complex validations,
+or ActiveRecord change tracking. This feature is provided by the
+[`jsonb_accessor`](https://github.com/madeintandem/jsonb_accessor) gem,
+and does not replace `JsonSchemaValidator`.
+
+```ruby
+module Organizations
+ class OrganizationSetting < ApplicationRecord
+ belongs_to :organization
+
+ validates :settings, json_schema: { filename: "organization_settings" }
+
+ jsonb_accessor :settings,
+ restricted_visibility_levels: [:integer, { array: true }]
+
+ validates_each :restricted_visibility_levels do |record, attr, value|
+ value&.each do |level|
+ unless Gitlab::VisibilityLevel.options.value?(level)
+ record.errors.add(attr, format(_("'%{level}' is not a valid visibility level"), level: level))
+ end
+ end
+ end
+ end
+end
+```
+
+You can now use `restricted_visibility_levels` as an ActiveRecord attribute:
+
+```ruby
+> s = Organizations::OrganizationSetting.find(1)
+=> #<Organizations::OrganizationSetting:0x0000000148d67628>
+> s.settings
+=> {"restricted_visibility_levels"=>[20]}
+> s.restricted_visibility_levels
+=> [20]
+> s.restricted_visibility_levels = [0]
+=> [0]
+> s.changes
+=> {"settings"=>[{"restricted_visibility_levels"=>[20]}, {"restricted_visibility_levels"=>[0]}], "restricted_visibility_levels"=>[[20], [0]]}
+```
+
## Encrypted attributes
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227779) in GitLab 14.0.
diff --git a/doc/development/packages/debian_repository.md b/doc/development/packages/debian_repository.md
index b3e9bedfdd4..2d8ba98f9ad 100644
--- a/doc/development/packages/debian_repository.md
+++ b/doc/development/packages/debian_repository.md
@@ -17,11 +17,13 @@ This guide explains:
There are two types of [Debian packages](https://www.debian.org/doc/manuals/debian-faq/pkg-basics.en.html): binary and source.
- **Binary** - These are usually `.deb` files and contain executables, config files, and other data. A binary package must match your OS or architecture since it is already compiled. These are usually installed using `dpkg`. Dependencies must already exist on the system when installing a binary package.
-- **Source** - These are usual made up of `.dsc` files and `.gz` files. A source package is compiled on your system. These are fetched and installed with [`apt`](https://manpages.debian.org/bullseye/apt/apt.8.en.html), which then uses `dpkg` after the package is compiled. When you use `apt`, it will fetch and install the necessary dependencies.
+- **Source** - These are usually made up of `.dsc` files and compressed `.tar` files. A source package may be compiled on your system.
-The `.deb` file follows the naming convention `<PackageName>_<VersionNumber>-<DebianRevisionNumber>_<DebianArchitecture>.deb`
+Packages are fetched with [`apt`](https://manpages.debian.org/bullseye/apt/apt.8.en.html) and installed with `dpkg`. When you use `apt`, it also fetches and installs any dependencies.
-It includes a `control file` that contains metadata about the package. You can view the control file by using `dpkg --info <deb_file>`
+The `.deb` file follows the naming convention `<PackageName>_<VersionNumber>-<DebianRevisionNumber>_<DebianArchitecture>.deb`.
+
+It includes a `control file` that contains metadata about the package. You can view the control file by using `dpkg --info <deb_file>`.
The [`.changes` file](https://www.debian.org/doc/debian-policy/ch-controlfields.html#debian-changes-files-changes) is used to tell the Debian repository how to process updates to packages. It contains a variety of metadata for the package, including architecture, distribution, and version. In addition to the metadata, they contain three lists of checksums: `sha1`, `sha256`, and `md5` in the `Files` section. Refer to [sample_1.2.3~alpha2_amd64.changes](https://gitlab.com/gitlab-org/gitlab/-/blob/dd1e70d3676891025534dc4a1e89ca9383178fe7/spec/fixtures/packages/debian/sample_1.2.3~alpha2_amd64.changes) for an example of how these files are structured.
@@ -40,8 +42,8 @@ When it comes to Debian, packages don't exist on their own. They belong to a _di
## What does a Debian Repository look like?
- A [Debian repository](https://wiki.debian.org/DebianRepository) is made up of many releases.
-- Each release is given a **codename**. For the public Debian repository, these are things like "bullseye" and "jesse".
- - There is also the concept of **suites** which are essentially aliases of codenames synonymous with release channels like "stable" and "edge".
+- Each release is given a stable **codename**. For the public Debian repository, these are names like "bullseye" and "jessie".
+ - There is also the concept of **suites** which are essentially aliases of codenames synonymous with release channels like "stable" and "edge". Over time they change and point to different _codenames_.
- Each release has many **components**. In the public repository, these are "main", "contrib", and "non-free".
- Each release has many **architectures** such as "amd64", "arm64", or "i386".
- Each release has a signed **Release** file (see below about [GPG signing](#what-are-gpg-keys-and-what-are-signed-releases))
diff --git a/doc/development/performance.md b/doc/development/performance.md
index fd7e9a85fba..428d5637aa9 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -250,7 +250,7 @@ the timeout.
Once profiling stops, the profile is written out to disk at
`$STACKPROF_FILE_PREFIX/stackprof.$PID.$RAND.profile`. It can then be inspected
-further through the `stackprof` command line tool, as described in the
+further through the `stackprof` command-line tool, as described in the
[Reading a Stackprof profile section](#reading-a-stackprof-profile).
Currently supported profiling targets are:
diff --git a/doc/development/permissions.md b/doc/development/permissions.md
index aa58447b818..35fd0f1c440 100644
--- a/doc/development/permissions.md
+++ b/doc/development/permissions.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/permissions/authorizations.md b/doc/development/permissions/authorizations.md
index 8d8944562a8..7580b7c473b 100644
--- a/doc/development/permissions/authorizations.md
+++ b/doc/development/permissions/authorizations.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/permissions/custom_roles.md b/doc/development/permissions/custom_roles.md
index 337c8f6d96b..d317d943cd3 100644
--- a/doc/development/permissions/custom_roles.md
+++ b/doc/development/permissions/custom_roles.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/permissions/predefined_roles.md b/doc/development/permissions/predefined_roles.md
index 9afc5966e93..50e8fbfd5b3 100644
--- a/doc/development/permissions/predefined_roles.md
+++ b/doc/development/permissions/predefined_roles.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -96,6 +96,20 @@ NOTE:
In [GitLab 14.9](https://gitlab.com/gitlab-org/gitlab/-/issues/351211) and later, projects in personal namespaces have a maximum role of Owner.
Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/219299) in GitLab 14.8 and earlier, projects in personal namespaces have a maximum role of Maintainer.
+#### Guest role
+
+A user with the Guest role in GitLab can view project plans, blockers and other
+progress indicators. While unable to modify data they have not created, Guests
+can contribute to a project by creating and linking project work items. Guests
+can also view high-level project information such as:
+
+- Analytics.
+- Incident information.
+- Issues and epics.
+- Licenses.
+
+For more information, see [project member permissions](../../user/permissions.md#project-members-permissions).
+
### Confidential issues
[Confidential issues](../../user/project/issues/confidential_issues.md) can be accessed
diff --git a/doc/development/pipelines/index.md b/doc/development/pipelines/index.md
index 316ae3c83cd..a5b654e96e2 100644
--- a/doc/development/pipelines/index.md
+++ b/doc/development/pipelines/index.md
@@ -278,8 +278,8 @@ See `.review:rules:start-review-app-pipeline` in
[`rules.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rules.gitlab-ci.yml) for
the specific list of rules.
-If you want to force a Review App to be deployed regardless of your changes, you can add the
-`pipeline:run-review-app` label to the merge request.
+If you want to deploy a Review App in a merge request, you can either trigger the `start-review-app-pipeline` manual job in the CI/CD pipeline, or add the
+`pipeline:run-review-app` label to the merge request and run a new CI/CD pipeline.
Consult the [Review Apps](../testing_guide/review_apps.md) dedicated page for more information.
diff --git a/doc/development/pipelines/internals.md b/doc/development/pipelines/internals.md
index 1a4e4e738a8..0e2c1c991fd 100644
--- a/doc/development/pipelines/internals.md
+++ b/doc/development/pipelines/internals.md
@@ -152,7 +152,7 @@ that are scoped to a single [configuration keyword](../../ci/yaml/index.md#job-k
| `.setup-test-env-cache` | Allows a job to use a default `cache` definition suitable for setting up test environment for subsequent Ruby/Rails tasks. |
| `.ruby-cache` | Allows a job to use a default `cache` definition suitable for Ruby tasks. |
| `.static-analysis-cache` | Allows a job to use a default `cache` definition suitable for static analysis tasks. |
-| `.coverage-cache` | Allows a job to use a default `cache` definition suitable for coverage tasks. |
+| `.ruby-gems-coverage-cache` | Allows a job to use a default `cache` definition suitable for coverage tasks. |
| `.qa-cache` | Allows a job to use a default `cache` definition suitable for QA tasks. |
| `.yarn-cache` | Allows a job to use a default `cache` definition suitable for frontend jobs that do a `yarn install`. |
| `.assets-compile-cache` | Allows a job to use a default `cache` definition suitable for frontend jobs that compile assets. |
@@ -164,7 +164,7 @@ that are scoped to a single [configuration keyword](../../ci/yaml/index.md#job-k
| `.use-pg15-ee` | Same as `.use-pg15` but also use an `elasticsearch` service (see [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml) for the specific version of the service). |
| `.use-kaniko` | Allows a job to use the `kaniko` tool to build Docker images. |
| `.as-if-foss` | Simulate the FOSS project by setting the `FOSS_ONLY='1'` CI/CD variable. |
-| `.use-docker-in-docker` | Allows a job to use Docker in Docker. |
+| `.use-docker-in-docker` | Allows a job to use Docker in Docker. For more details, see the [handbook about CI/CD configuration](https://about.gitlab.com/handbook/engineering/gitlab-repositories/#cicd-configuration). |
## `rules`, `if:` conditions and `changes:` patterns
@@ -198,7 +198,7 @@ and included in `rules` definitions via [YAML anchors](../../ci/yaml/yaml_optimi
| `if-merge-request` | Matches if the pipeline is for a merge request. | |
| `if-merge-request-title-as-if-foss` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:run-as-if-foss" | |
| `if-merge-request-title-update-caches` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:update-cache". | |
-| `if-merge-request-title-run-all-rspec` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:run-all-rspec". | |
+| `if-merge-request-labels-run-all-rspec` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:run-all-rspec". | |
| `if-security-merge-request` | Matches if the pipeline is for a security merge request. | |
| `if-security-schedule` | Matches if the pipeline is for a security scheduled pipeline. | |
| `if-nightly-master-schedule` | Matches if the pipeline is for a `master` scheduled pipeline with `$NIGHTLY` set. | |
@@ -396,7 +396,6 @@ For this scenario, you have to:
- `GITALY_SERVER_VERSION`
- `GITLAB_ELASTICSEARCH_INDEXER_VERSION`
- `GITLAB_KAS_VERSION`
- - `GITLAB_METRICS_EXPORTER_VERSION`
- `GITLAB_PAGES_VERSION`
- `GITLAB_SHELL_VERSION`
- `scripts/trigger-build.rb`
@@ -417,3 +416,25 @@ For this scenario, you have to:
- `spec/simplecov_env.rb`
Additionally, `scripts/utils.sh` is always downloaded from the API when this pattern is used (this file contains the code for `.fast-no-clone-job`).
+
+#### Runner tags
+
+On GitLab.com, both unprivileged and privileged runners are
+available. For projects in the `gitlab-org` group and forks of those
+projects, only one of the following tags should be added to a job:
+
+- `gitlab-org`: Jobs randomly use privileged and unprivileged runners.
+- `gitlab-org-docker`: Jobs must use a privileged runner. If you need [Docker-in-Docker support](../../ci/docker/using_docker_build.md#use-docker-in-docker),
+use `gitlab-org-docker` instead of `gitlab-org`.
+
+The `gitlab-org-docker` tag is added by the `.use-docker-in-docker` job
+definition above.
+
+To ensure compatibility with forks, avoid using both `gitlab-org` and
+`gitlab-org-docker` simultaneously. No instance runners
+have both `gitlab-org` and `gitlab-org-docker` tags. For forks of
+`gitlab-org` projects, jobs will get stuck if both tags are supplied because
+no matching runners are available.
+
+See [the GitLab Repositories handbook page](https://about.gitlab.com/handbook/engineering/gitlab-repositories/#cicd-configuration)
+for more information.
diff --git a/doc/development/pipelines/performance.md b/doc/development/pipelines/performance.md
index 2dbed640fbb..7db498adc02 100644
--- a/doc/development/pipelines/performance.md
+++ b/doc/development/pipelines/performance.md
@@ -40,7 +40,7 @@ This works well for the following reasons:
- `.ruby-cache`
- `.static-analysis-cache`
- `.rubocop-cache`
- - `.coverage-cache`
+ - `.ruby-gems-coverage-cache`
- `.ruby-node-cache`
- `.qa-cache`
- `.yarn-cache`
diff --git a/doc/development/policies.md b/doc/development/policies.md
index 38f1fc54bf4..faf5b32985f 100644
--- a/doc/development/policies.md
+++ b/doc/development/policies.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/development/rails_update.md b/doc/development/rails_update.md
index 32295cc0e43..772206c2d73 100644
--- a/doc/development/rails_update.md
+++ b/doc/development/rails_update.md
@@ -4,11 +4,11 @@ group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Rails update guidelines
+# Rails upgrade guidelines
We strive to run GitLab using the latest Rails releases to benefit from performance, security updates, and new features.
-## Rails update approach
+## Rails upgrade approach
1. [Prepare an MR for GitLab](#prepare-an-mr-for-gitlab).
1. [Prepare an MR for Gitaly](#prepare-an-mr-for-gitaly).
@@ -40,7 +40,7 @@ We strive to run GitLab using the latest Rails releases to benefit from performa
### Create patch releases and backports for security patches
-If the Rails update was over a patch release and it contains important security fixes,
+If the Rails upgrade was over a patch release and it contains important security fixes,
make sure to release it in a
GitLab patch release to self-managed customers. Consult with our [release managers](https://about.gitlab.com/community/release-managers/)
for how to proceed.
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index b15c4eca5ae..d879668649d 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -30,7 +30,9 @@ See also [Mass inserting Rails models](mass_insert.md).
**LARGE_PROJECTS**: Create large projects (through import) from a predefined set of URLs.
-### Seeding issues for all or a given project
+### Seeding Data
+
+#### Seeding issues for all projects or a single project
You can seed issues for all or a given project with the `gitlab:seed:issues`
task:
@@ -197,6 +199,14 @@ bundle exec rake "gitlab:seed:ci_variables_instance"
bundle exec rake "gitlab:seed:ci_variables_instance[25, CI_VAR_]"
```
+#### Seed a project for merge train development
+
+Seeds a project with merge trains configured and 20 merge requests(each with 3 commits). The command:
+
+```shell
+rake gitlab:seed:merge_trains:project
+```
+
### Automation
If you're very sure that you want to **wipe the current database** and refill
@@ -520,6 +530,11 @@ The following command combines the intent of [Update GraphQL documentation and s
bundle exec rake gitlab:graphql:update_all
```
+## Update audit event types documentation
+
+For information on updating audit event types documentation, see
+[Generate documentation](audit_event_guide/index.md#generate-documentation).
+
## Update OpenAPI client for Error Tracking feature
NOTE:
diff --git a/doc/development/redis.md b/doc/development/redis.md
index ebc7c0271a1..19a6b8e75d4 100644
--- a/doc/development/redis.md
+++ b/doc/development/redis.md
@@ -56,7 +56,7 @@ the entry, instead of relying on the key changing.
### Multi-key commands
-GitLab supports Redis Cluster only for the Redis [rate-limiting](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/redis/rate_limiting.rb) type, introduced in [epic 823](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/823).
+GitLab supports Redis Cluster for [cache-related workloads](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/redis/cache.rb) type, introduced in [epic 878](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/878).
This imposes an additional constraint on naming: where GitLab is performing
operations that require several keys to be held on the same Redis server - for
@@ -81,6 +81,12 @@ Developers are highly encouraged to use [hash-tags](https://redis.io/docs/refere
where appropriate to facilitate future adoption of Redis Cluster in more Redis types. For example, the Namespace model uses hash-tags
for its [config cache keys](https://gitlab.com/gitlab-org/gitlab/-/blob/1a12337058f260d38405886d82da5e8bb5d8da0b/app/models/namespace.rb#L786).
+To perform multi-key commands, developers may use the [`Gitlab::Redis::CrossSlot::Pipeline`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/redis/cross_slot.rb) wrapper.
+However, this does not work for [transactions](https://redis.io/docs/interact/transactions/) as Redis Cluster does not support cross-slot transactions.
+
+For `Rails.cache`, we handle the `MGET` command found in `read_multi_get` by [patching it](https://gitlab.com/gitlab-org/gitlab/-/blob/c2bad2aac25e2f2778897bd4759506a72b118b15/lib/gitlab/patch/redis_cache_store.rb#L10) to use the `Gitlab::Redis::CrossSlot::Pipeline` wrapper.
+The minimum size of the pipeline is set to 1000 commands and it can be adjusted by using the `GITLAB_REDIS_CLUSTER_PIPELINE_BATCH_LIMIT` environment variable.
+
## Redis in structured logging
For GitLab Team Members: There are <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
diff --git a/doc/development/rubocop_development_guide.md b/doc/development/rubocop_development_guide.md
index 1fdc0fbe78c..f6c11a0c7e3 100644
--- a/doc/development/rubocop_development_guide.md
+++ b/doc/development/rubocop_development_guide.md
@@ -28,6 +28,12 @@ discussions, nitpicking, or back-and-forth in reviews. The
[GitLab Ruby style guide](backend/ruby_style_guide.md) includes a non-exhaustive
list of styles that commonly come up in reviews and are not enforced.
+By default, we should not
+[disable a RuboCop rule inline](https://docs.rubocop.org/rubocop/configuration.html#disabling-cops-within-source-code), because it negates agreed-upon code standards that the rule is attempting to apply to the codebase.
+
+If you must use inline disable, provide the reason on the MR and ensure the reviewers agree
+before merging.
+
Additionally, we have dedicated
[test-specific style guides and best practices](testing_guide/index.md).
@@ -53,7 +59,7 @@ A cop is in a _grace period_ if it is enabled and has `Details: grace period` de
On the default branch, offenses from cops in the [grace period](rake_tasks.md#run-rubocop-in-graceful-mode) do not fail the RuboCop CI job. Instead, the job notifies the `#f_rubocop` Slack channel. However, on other branches, the RuboCop job fails.
-A grace period can safely be lifted as soon as there are no warnings for 2 weeks in the `#f_rubocop` channel on Slack.
+A grace period can safely be lifted as soon as there are no warnings for 1 week in the `#f_rubocop` channel on Slack.
## Enabling a new cop
@@ -61,7 +67,7 @@ A grace period can safely be lifted as soon as there are no warnings for 2 weeks
1. [Generate TODOs for the new cop](rake_tasks.md#generate-initial-rubocop-todo-list).
1. [Set the new cop to `grace period`](#cop-grace-period).
1. Create an issue to fix TODOs and encourage community contributions (via ~"quick win" and/or ~"Seeking community contributions"). [See some examples](https://gitlab.com/gitlab-org/gitlab/-/issues/?sort=created_date&state=opened&label_name%5B%5D=quick%20wins&label_name%5B%5D=static%20code%20analysis&first_page_size=20).
-1. Create an issue to remove `grace period` after 2 weeks of silence in the `#f_rubocop` Slack channel. [See an example](https://gitlab.com/gitlab-org/gitlab/-/issues/374903).
+1. Create an issue to remove `grace period` after 1 week of silence in the `#f_rubocop` Slack channel. [See an example](https://gitlab.com/gitlab-org/gitlab/-/issues/374903).
## Silenced offenses
diff --git a/doc/development/ruby_upgrade.md b/doc/development/ruby_upgrade.md
index 21c19c31b0a..d3629bc8dba 100644
--- a/doc/development/ruby_upgrade.md
+++ b/doc/development/ruby_upgrade.md
@@ -272,5 +272,5 @@ These experimental branches are not intended to be merged; they can be closed on
and merged back independently.
- **Give yourself enough time to fix problems ahead of a milestone release.** GitLab moves fast.
As a Ruby upgrade requires many MRs to be sent and reviewed, make sure all changes are merged at least a week
-before the 22nd. This gives us extra time to act if something breaks. If in doubt, it is better to
+before release day. This gives us extra time to act if something breaks. If in doubt, it is better to
postpone the upgrade to the following month, as we [prioritize availability over velocity](https://about.gitlab.com/handbook/engineering/development/principles/#prioritizing-technical-decisions).
diff --git a/doc/development/sec/token_revocation_api.md b/doc/development/sec/token_revocation_api.md
index e2006ba519c..860faf30cf6 100644
--- a/doc/development/sec/token_revocation_api.md
+++ b/doc/development/sec/token_revocation_api.md
@@ -108,8 +108,8 @@ For example, to configure these values in the
```ruby
::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_token: 'MYSECRETTOKEN')
-::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_url: 'https://example.gitlab.com/revocation_service/v1/revoke_tokens')
-::Gitlab::CurrentSettings.update!(secret_detection_revocation_token_types_url: 'https://example.gitlab.com/revocation_service/v1/revocable_token_types')
+::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_url: 'https://gitlab.example.com/revocation_service/v1/revoke_tokens')
+::Gitlab::CurrentSettings.update!(secret_detection_revocation_token_types_url: 'https://gitlab.example.com/revocation_service/v1/revocable_token_types')
::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_enabled: true)
```
diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md
index 186239cc547..806fbd8d1f6 100644
--- a/doc/development/secure_coding_guidelines.md
+++ b/doc/development/secure_coding_guidelines.md
@@ -1279,7 +1279,7 @@ Credentials can be:
- Login details like username and password.
- Private keys.
-- Tokens (PAT, runner tokens, JWT token, CSRF tokens, project access tokens, etc).
+- Tokens (PAT, runner authentication tokens, JWT token, CSRF tokens, project access tokens, etc).
- Session cookies.
- Any other piece of information that can be used for authentication or authorization purposes.
diff --git a/doc/development/service_ping/implement.md b/doc/development/service_ping/implement.md
deleted file mode 100644
index c1077793fb9..00000000000
--- a/doc/development/service_ping/implement.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/implement.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/implement.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md
deleted file mode 100644
index d0806ed375b..00000000000
--- a/doc/development/service_ping/index.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/index.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/index.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/service_ping/metrics_dictionary.md b/doc/development/service_ping/metrics_dictionary.md
deleted file mode 100644
index fecab4916f5..00000000000
--- a/doc/development/service_ping/metrics_dictionary.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/metrics_dictionary.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/metrics_dictionary.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/service_ping/metrics_instrumentation.md b/doc/development/service_ping/metrics_instrumentation.md
deleted file mode 100644
index 5a4dfc325e2..00000000000
--- a/doc/development/service_ping/metrics_instrumentation.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/metrics_instrumentation.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/metrics_instrumentation.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/service_ping/metrics_lifecycle.md b/doc/development/service_ping/metrics_lifecycle.md
deleted file mode 100644
index 520b18139ff..00000000000
--- a/doc/development/service_ping/metrics_lifecycle.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/metrics_lifecycle.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/metrics_lifecycle.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/service_ping/performance_indicator_metrics.md b/doc/development/service_ping/performance_indicator_metrics.md
deleted file mode 100644
index eda7224732d..00000000000
--- a/doc/development/service_ping/performance_indicator_metrics.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/performance_indicator_metrics.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/performance_indicator_metrics.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/service_ping/review_guidelines.md b/doc/development/service_ping/review_guidelines.md
deleted file mode 100644
index d5805f615e2..00000000000
--- a/doc/development/service_ping/review_guidelines.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/review_guidelines.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/review_guidelines.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/service_ping/troubleshooting.md b/doc/development/service_ping/troubleshooting.md
deleted file mode 100644
index 31b04c1a6bc..00000000000
--- a/doc/development/service_ping/troubleshooting.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/troubleshooting.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/troubleshooting.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/service_ping/usage_data.md b/doc/development/service_ping/usage_data.md
deleted file mode 100644
index 94ae90273d0..00000000000
--- a/doc/development/service_ping/usage_data.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/service_ping/usage_data.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/service_ping/usage_data.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/shell_commands.md b/doc/development/shell_commands.md
index 25f62fbcc98..321bd7aeadd 100644
--- a/doc/development/shell_commands.md
+++ b/doc/development/shell_commands.md
@@ -88,7 +88,7 @@ cat: illegal option -- l
usage: cat [-benstuv] [file ...]
```
-In the example above, the argument parser of `cat` assumes that `-l` is an option. The solution in the example above is to make it clear to `cat` that `-l` is really an argument, not an option. Many Unix command line tools follow the convention of separating options from arguments with `--`.
+In the example above, the argument parser of `cat` assumes that `-l` is an option. The solution in the example above is to make it clear to `cat` that `-l` is really an argument, not an option. Many Unix command-line tools follow the convention of separating options from arguments with `--`.
```shell
# Example (continued)
diff --git a/doc/development/snowplow/event_dictionary_guide.md b/doc/development/snowplow/event_dictionary_guide.md
deleted file mode 100644
index 2bea681bf59..00000000000
--- a/doc/development/snowplow/event_dictionary_guide.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/snowplow/event_dictionary_guide.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/snowplow/event_dictionary_guide.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/snowplow/implementation.md b/doc/development/snowplow/implementation.md
deleted file mode 100644
index a9e4e252a53..00000000000
--- a/doc/development/snowplow/implementation.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/snowplow/implementation.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/snowplow/implementation.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/snowplow/index.md b/doc/development/snowplow/index.md
deleted file mode 100644
index c0e53fe3b1b..00000000000
--- a/doc/development/snowplow/index.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/snowplow/index.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/snowplow/index.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/snowplow/infrastructure.md b/doc/development/snowplow/infrastructure.md
deleted file mode 100644
index 6374af40ffe..00000000000
--- a/doc/development/snowplow/infrastructure.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/snowplow/infrastructure.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/snowplow/infrastructure.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/snowplow/review_guidelines.md b/doc/development/snowplow/review_guidelines.md
deleted file mode 100644
index f4752e08dde..00000000000
--- a/doc/development/snowplow/review_guidelines.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/snowplow/review_guidelines.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/snowplow/review_guidelines.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/snowplow/schemas.md b/doc/development/snowplow/schemas.md
deleted file mode 100644
index 7e00ddd976d..00000000000
--- a/doc/development/snowplow/schemas.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/snowplow/schemas.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/snowplow/schemas.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/snowplow/troubleshooting.md b/doc/development/snowplow/troubleshooting.md
deleted file mode 100644
index ed1f5033239..00000000000
--- a/doc/development/snowplow/troubleshooting.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../internal_analytics/snowplow/troubleshooting.md'
-remove_date: '2023-08-20'
----
-
-This document was moved to [another location](../internal_analytics/snowplow/troubleshooting.md).
-
-<!-- This redirect file can be deleted after <2023-08-20>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 65787f7a355..49739d7c8e9 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -911,7 +911,8 @@ so we need to set some guidelines for their use going forward:
### Common test setup
NOTE:
-`before_all` does not work with the `:delete` strategy. For more information, see [issue 420379](https://gitlab.com/gitlab-org/gitlab/-/issues/420379).
+`let_it_be` and `before_all` do not work with DatabaseCleaner's deletion strategy. This includes migration specs, Rake task specs, and specs that have the `:delete` RSpec metadata tag.
+For more information, see [issue 420379](https://gitlab.com/gitlab-org/gitlab/-/issues/420379).
In some cases, there is no need to recreate the same object for tests
again for each example. For example, a project and a guest of that project
@@ -1060,7 +1061,7 @@ Failing with an error along the lines of:
```shell
expected {
"assignee_id" => nil, "...1 +0000 } to include {"customer_relations_contacts" => [{:created_at => "2023-08-04T13:30:20Z", :first_name => "Sidney Jones3" }]}
-
+
Diff:
@@ -1,35 +1,69 @@
-"customer_relations_contacts" => [{:created_at=>"2023-08-04T13:30:20Z", :first_name=>"Sidney Jones3" }],
@@ -1225,7 +1226,7 @@ specs, so created repositories accumulate in this directory over the
lifetime of the process. Deleting them is expensive, but this could lead to
pollution unless carefully managed.
-To avoid this, [hashed storage](../../administration/repository_storage_types.md)
+To avoid this, [hashed storage](../../administration/repository_storage_paths.md)
is enabled in the test suite. This means that repositories are given a unique
path that depends on their project's ID. Because the project IDs are not reset
between specs, each spec gets its own repository on disk,
diff --git a/doc/development/testing_guide/end_to_end/beginners_guide.md b/doc/development/testing_guide/end_to_end/beginners_guide.md
index 4627d5d29cb..12f90e0d88c 100644
--- a/doc/development/testing_guide/end_to_end/beginners_guide.md
+++ b/doc/development/testing_guide/end_to_end/beginners_guide.md
@@ -266,7 +266,7 @@ ensuring we now sign in at the beginning of each test.
Next, let's test something other than Login. Let's test Issues, which are owned by the Plan
stage and the Project Management Group, so [create a file](#identify-the-devops-stage) in
-`qa/specs/features/browser_ui/3_create/issues` called `issues_spec.rb`.
+`qa/specs/features/browser_ui/2_plan/issue` called `issues_spec.rb`.
```ruby
# frozen_string_literal: true
@@ -274,12 +274,7 @@ stage and the Project Management Group, so [create a file](#identify-the-devops-
module QA
RSpec.describe 'Plan' do
describe 'Issues', product_group: :project_management do
- let(:issue) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.title = 'My issue'
- issue.description = 'This is an issue specific to this test'
- end
- end
+ let(:issue) { create(:issue) }
before do
Flow::Login.sign_in
diff --git a/doc/development/testing_guide/end_to_end/best_practices.md b/doc/development/testing_guide/end_to_end/best_practices.md
index 96bd02d235b..ab4dd9acb63 100644
--- a/doc/development/testing_guide/end_to_end/best_practices.md
+++ b/doc/development/testing_guide/end_to_end/best_practices.md
@@ -169,18 +169,14 @@ Page::Main::Menu.perform do |menu|
end
#=> Good
-issue = Resource::Issue.fabricate_via_api! do |issue|
- issue.name = 'issue-name'
-end
+issue = create(:issue, name: 'issue-name')
Project::Issues::Index.perform do |index|
expect(index).to have_issue(issue)
end
#=> Bad
-issue = Resource::Issue.fabricate_via_api! do |issue|
- issue.name = 'issue-name'
-end
+issue = create(:issue, name: 'issue-name')
Project::Issues::Index.perform do |index|
expect(index).to have_issue(issue)
@@ -371,7 +367,7 @@ If the _only_ action in the test that requires administrator access is to toggle
In line with [using the API](#prefer-api-over-ui), use a `Commit` resource whenever possible.
-`ProjectPush` uses raw shell commands via the Git Command Line Interface (CLI) whereas the `Commit` resource makes an HTTP request.
+`ProjectPush` uses raw shell commands from the Git command-line interface (CLI), and the `Commit` resource makes an HTTP request.
```ruby
# Using a commit resource
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index 4e7ef6f29a2..30fb1abd7df 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -55,17 +55,17 @@ graph TB
A2 -.->|1. Triggers an `omnibus-gitlab-mirror` pipeline<br>and wait for it to be done| B1
B2[`Trigger-qa` stage<br>`Trigger:qa-test` job] -.->|2. Triggers a `gitlab-qa-mirror` pipeline<br>and wait for it to be done| C1
-subgraph "`gitlab-org/gitlab` pipeline"
+subgraph " `gitlab-org/gitlab` pipeline"
A1[`build-images` stage<br>`build-qa-image` and `build-assets-image` jobs]
A2[`qa` stage<br>`e2e:package-and-test` job]
end
-subgraph "`gitlab-org/build/omnibus-gitlab-mirror` pipeline"
+subgraph " `gitlab-org/build/omnibus-gitlab-mirror` pipeline"
B1[`Trigger-docker` stage<br>`Trigger:gitlab-docker` job] -->|once done| B2
end
-subgraph "`gitlab-org/gitlab-qa-mirror` pipeline"
- C1>End-to-end jobs run]
+subgraph " `gitlab-org/gitlab-qa-mirror` pipeline"
+ C1[End-to-end jobs run]
end
```
diff --git a/doc/development/testing_guide/end_to_end/resources.md b/doc/development/testing_guide/end_to_end/resources.md
index becdc375c63..bf3f1c25f5e 100644
--- a/doc/development/testing_guide/end_to_end/resources.md
+++ b/doc/development/testing_guide/end_to_end/resources.md
@@ -392,7 +392,7 @@ In this case, the result is similar to calling `Resource::Shirt.fabricate!`.
### Factories
-You may also use FactoryBot invocations to create resources within your tests.
+You may also use [FactoryBot](https://github.com/thoughtbot/factory_bot/) invocations to create, build, and fetch resources within your tests.
```ruby
# create a project via the API to use in the test
@@ -403,9 +403,81 @@ let(:issue) { create(:issue, project: project) }
# create a private project via the API with a specific name
let(:project) { create(:project, :private, name: 'my-project-name', add_name_uuid: false) }
+
+###
+
+# instantiate an Issue but don't create it via API yet
+let(:issue) { build(:issue) }
+
+# instantiate a Project and perform some actions before creating
+let(:project) do
+ build(:project) do |p|
+ p.name = 'Test'
+ p.add_name_uuid = false
+ end
+end
+
+# fetch an existing issue via the API with attributes
+let(:existing_issue) { build(:issue, project: project, iid: issue.iid).reload! }
+```
+
+All factories are defined in [`qa/qa/factories`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/factories/) and are representative of
+their respective `QA::Resource::Base` class.
+
+For example, a factory `:issue` can be found in `qa/resource/issue.rb`. A factory `:project` can be found in `qa/resource/project.rb`.
+
+#### Create a new Factory
+
+Given a resource:
+
+```ruby
+# qa/resource/shirt.rb
+module QA
+ module Resource
+ class Shirt < Base
+ attr_accessor :name
+ attr_reader :read_only
+
+ attribute :brand
+
+ def api_post_body
+ { name: name, brand: brand }
+ end
+ end
+ end
+end
```
-All factories are defined in [`qa/qa/factories`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/factories/).
+Define a factory with defaults and overrides:
+
+```ruby
+# qa/factories/shirts.rb
+module QA
+ FactoryBot.define do
+ factory :shirt, class: 'QA::Resource::Shirt' do
+ brand { 'BrandName' }
+
+ trait :with_name do
+ name { 'Shirt Name' }
+ end
+ end
+ end
+end
+```
+
+In the test, create the resource via the API:
+
+```ruby
+let(:my_shirt) { create(:shirt, brand: 'AnotherBrand') } #<Resource::Shirt @brand="AnotherBrand" @name=nil>
+let(:named_shirt) { create(:shirt, :with_name) } #<Resource::Shirt @brand="Brand Name" @name="Shirt Name">
+let(:invalid_shirt) { create(:shirt, read_only: true) } # NoMethodError
+
+it 'creates a shirt' do
+ expect(my_shirt.brand).to eq('AnotherBrand')
+ expect(named_shirt.name).to eq('Shirt Name')
+ expect(invalid_shirt).to raise_error(NoMethodError) # tries to call Resource::Shirt#read_only=
+end
+```
### Resources cleanup
diff --git a/doc/development/testing_guide/flaky_tests.md b/doc/development/testing_guide/flaky_tests.md
index 2d36377967e..cd5e32bc0ad 100644
--- a/doc/development/testing_guide/flaky_tests.md
+++ b/doc/development/testing_guide/flaky_tests.md
@@ -38,6 +38,18 @@ it's reset to a pristine test after each test.
- [Example 4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103434#note_1172316521): A test for a database query passes in a fresh database, but in a
CI/CD pipeline where the database is used to process previous test sequences, the test fails. This likely
means that the query itself needs to be updated to work in a non-clean database.
+- [Example 5](https://gitlab.com/gitlab-org/gitlab/-/issues/416663#note_1457867234): Unrelated database connections
+ in asynchronous requests checked back in, causing the tests to accidentally
+ use these unrelated database connections. The failure was resolved in this
+ [merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125742).
+- [Example 6](https://gitlab.com/gitlab-org/gitlab/-/issues/418757#note_1502138269): The maximum time to live
+ for a database connection causes these connections to be disconnected, which
+ in turn causes tests that rely on the transactions on these connections to
+ in turn causes tests that rely on the transactions on these connections to
+ fail. The issue was fixed in this [merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128567).
+- [Example 7](https://gitlab.com/gitlab-org/quality/engineering-productivity/master-broken-incidents/-/issues/3389#note_1534827164):
+ A TCP socket used in a test was not closed before the next test, which also used
+ the same port with another TCP socket.
### Dataset-specific
@@ -172,10 +184,12 @@ it 'succeeds', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/12345'
end
```
-This means it is skipped unless run with `--tag quarantine`:
+This means it is skipped in CI. By default, the quarantined tests will run locally.
+
+We can skip them in local development as well by running with `--tag ~quarantine`:
```shell
-bin/rspec --tag quarantine
+bin/rspec --tag ~quarantine
```
After the long-term quarantining MR has reached production, you should revert the fast-quarantine MR you created earlier.
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 8da4350074d..3800e22b2f9 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -51,7 +51,7 @@ The default timeout for Jest is set in
If your test exceeds that time, it fails.
If you cannot improve the performance of the tests, you can increase the timeout
-for the whole suite using [`jest.setTimeout`](https://jestjs.io/docs/28.x/jest-object#jestsettimeouttimeout)
+for the whole suite using [`jest.setTimeout`](https://jestjs.io/docs/next/jest-object#jestsettimeouttimeout)
```javascript
jest.setTimeout(500);
@@ -63,7 +63,7 @@ describe('Component', () => {
});
```
-or for a specific test by providing a third argument to [`it`](https://jestjs.io/docs/28.x/api#testname-fn-timeout)
+or for a specific test by providing a third argument to [`it`](https://jestjs.io/docs/next/api#testname-fn-timeout)
```javascript
describe('Component', () => {
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index b4ae23336d5..ba13ca0c05a 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -6,21 +6,17 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Using review apps in the development of GitLab
-Review apps are deployed using the `start-review-app-pipeline` job which triggers a child pipeline containing a series of jobs to perform the various tasks needed to deploy a review app.
+Review apps are deployed using the `start-review-app-pipeline` manual job which triggers a child pipeline containing a series of jobs to perform the various tasks needed to deploy a review app.
![start-review-app-pipeline job](img/review-app-parent-pipeline.png)
For any of the following scenarios, the `start-review-app-pipeline` job would be automatically started:
-- for merge requests with CI configuration changes
-- for merge requests with frontend changes
-- for merge requests with changes to `{,ee/,jh/}{app/controllers}/**/*`
-- for merge requests with changes to `{,ee/,jh/}{app/models}/**/*`
-- for merge requests with changes to `{,ee/,jh/}lib/{,ee/,jh/}gitlab/**/*`
-- for merge requests with QA changes
- for scheduled pipelines
- the MR has the `pipeline:run-review-app` label set
+For all other scenarios, the `start-review-app-pipeline` job can be triggered manually.
+
## E2E test runs on review apps
On every pipeline in the `qa` stage (which comes after the `review` stage), the `review-qa-smoke` and `review-qa-blocking` jobs are automatically started.
@@ -278,7 +274,7 @@ find a way to limit it to only us.**
- [Review apps integration for CE/EE (presentation)](https://docs.google.com/presentation/d/1QPLr6FO4LduROU8pQIPkX1yfGvD13GEJIBOenqoKxR8/edit?usp=sharing)
- [Stability issues](https://gitlab.com/gitlab-org/quality/quality-engineering/team-tasks/-/issues/212)
-### Helpful command line tools
+### Helpful command-line tools
- [K9s](https://github.com/derailed/k9s) - enables CLI dashboard across pods and enabling filtering by labels
- [Stern](https://github.com/wercker/stern) - enables cross pod log tailing based on label/field selectors
diff --git a/doc/development/value_stream_analytics.md b/doc/development/value_stream_analytics.md
index 955fc88c713..5aa6aecd9db 100644
--- a/doc/development/value_stream_analytics.md
+++ b/doc/development/value_stream_analytics.md
@@ -354,36 +354,4 @@ Analytics::CycleAnalytics::ReaggregationWorker.new.perform
#### Value stream analytics
-Seed issues and merge requests for value stream analytics:
-
- ```shell
- // Seed 10 issues for the project specified by <project-id>
- $ VSA_SEED_PROJECT_ID=<project-id> VSA_ISSUE_COUNT=10 SEED_VSA=true FILTER=cycle_analytics rake db:seed_fu
- ```
-
-#### DORA metrics
-
-Seed DORA daily metrics for value stream, insights and CI/CD analytics:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. On the project's homepage, in the upper-left corner, copy the **Project ID**. You need it in a later step.
-1. [Create an environment for your selected project from the UI](../ci/environments/index.md#create-a-static-environment) named `production`.
-1. Open the rails console:
-
- ```shell
- rails c
- ```
-
-1. In the rails console, find the created environment by searching for the project ID:
-
- ```shell
- e = Environment.find_by(project_id: <project-id>, name: "production")
- ```
-
-1. To seed data for the past 100 days for the environment, run the following command:
-
- ```shell
- 100.times { |i| Dora::DailyMetrics.create(environment_id: e.id, date: (i + 1).days.ago, deployment_frequency: rand(50), incidents_count: rand(5), lead_time_for_changes_in_seconds: rand(50000), time_to_restore_service_in_seconds: rand(100000)) }
- ```
-
-DORA metric data should now be available for your selected project and any group or subgroup it belongs to.
+For instructions on how to seed data for value stream analytics, see [development seed files](../development/development_seed_files.md).
diff --git a/doc/development/work_items.md b/doc/development/work_items.md
index 90e454bec85..2b28b2cd4f2 100644
--- a/doc/development/work_items.md
+++ b/doc/development/work_items.md
@@ -45,14 +45,15 @@ Here are some problems with current issues usage and why we are looking into wor
## Work item terminology
-To avoid confusion and ensure communication is efficient, we will use the following terms exclusively when discussing work items.
+To avoid confusion and ensure [communication is efficient](https://handbook.gitlab.com/handbook/communication/#mecefu-terms), we will use the following terms exclusively when discussing work items. This list is the [single source of truth (SSoT)](https://handbook.gitlab.com/handbook/values/#single-source-of-truth) for Work Item terminology.
| Term | Description | Example of misuse | Should be |
| --- | --- | --- | --- |
| work item type | Classes of work item; for example: issue, requirement, test case, incident, or task | _Epics will eventually become issues_ | _Epics will eventually become a **work item type**_ |
| work item | An instance of a work item type | | |
-| work item view | The new frontend view that renders work items of any type | | |
-| legacy issue view | The existing view used to render issues and incidents | | |
+| work item view | The new frontend view that renders work items of any type | _This should be rendered in the new view_ | _This should be rendered in the work item view_ |
+| legacy object | An object that has been or will be converted to a Work Item Type | _Epics will be migrated from a standalone/old/former object to a work item type_ | _Epics will be converted from a legacy object to a work item type_ |
+| legacy issue view | The existing view used to render issues and incidents | _Issues continue to be rendered in the old view_ | _Issues continue to be rendered in the legacy issue view_ |
| issue | The existing issue model | | |
| issuable | Any model currently using the issuable module (issues, epics and MRs) | _Incidents are an **issuable**_ | _Incidents are a **work item type**_ |
| widget | A UI element to present or allow interaction with specific work item data | | |
@@ -84,9 +85,10 @@ end
We already use the concept of WITs within `issues` table through `issue_type`
column. There are `issue`, `incident`, and `test_case` issue types. To extend this
-so that in future we can allow users to define custom WITs, we will move the
-`issue_type` to a separate table: `work_item_types`. The migration process of `issue_type`
-to `work_item_types` will involve creating the set of WITs for all root-level groups.
+so that in future we can allow users to define custom WITs, we will
+move the `issue_type` to a separate table: `work_item_types`. The migration process of `issue_type`
+to `work_item_types` will involve creating the set of WITs for all root-level groups as described in
+[this epic](https://gitlab.com/groups/gitlab-org/-/epics/6536).
NOTE:
At first, defining a WIT will only be possible at the root-level group, which would then be inherited by subgroups.
@@ -99,7 +101,7 @@ assume the following base types: `issue: 0`, `incident: 1`, `test_case: 2`.
The respective `work_item_types` records:
-| `group_id` | `base_type` | `title` |
+| `namespace_id` | `base_type` | `title` |
| -------------- | ----------- | --------- |
| 11 | 0 | Issue |
| 11 | 1 | Incident |
@@ -191,6 +193,164 @@ Until the architecture of WIT widgets is finalized, we are holding off on the cr
types. If a new work item type is absolutely necessary, please reach out to a
member of the [Project Management Engineering Team](https://gitlab.com/gitlab-org/gitlab/-/issues/370599).
+### Creating a new work item type in the database
+
+We have completed the removal of the `issue_type` column from the issues table, in favor of using the new
+`work_item_types` table as described in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/6536)).
+
+After the introduction of the `work_item_types` table, we added more `work_item_types`, and we want to make it
+easier for other teams to do so. To introduce a new `work_item_type`, you must:
+
+1. Write a database migration to create a new record in the `work_item_types` table.
+1. Update `Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter`.
+
+The following MRs demonstrate how to introduce new `work_item_types`:
+
+- [MR example 1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127482)
+- [MR example 2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127917)
+
+#### Write a database migration
+
+First, write a database migration that creates the new record in the `work_item_types` table.
+
+Keep the following in mind when you write your migration:
+
+- **Important:** Exclude new type from existing APIs.
+ - We probably want to exclude newly created work items of this type from showing
+ up in existing features (like issue lists) until we fully release a feature. For this reason,
+ we have to add a new type to
+ [this exclude list](https://gitlab.com/gitlab-org/gitlab/-/blob/a0a52dd05b5d3c6ca820b672f9c0626840d2429b/app/models/work_items/type.rb#L84),
+ unless it is expected that users can create new issues and work items with the new type as soon as the migration
+ is executed.
+- Use a regular migration, not a post-deploy.
+ - We believe it would be beneficial to use
+ [regular migrations](migration_style_guide.md#choose-an-appropriate-migration-type)
+ to add new work item types instead of a
+ [post deploy migration](database/post_deployment_migrations.md).
+ This way, follow-up MRs that depend on the type being created can assume it exists right away,
+ instead of having to wait for the next release.
+- Migrations should avoid failures.
+ - We expect data related to `work_item_types` to be in a certain state when running the migration that will create a new
+ type. At the moment, we write migrations that check the data and don't fail in the event we find
+ it in an inconsistent state. There's a discussion about how much we can rely on the state of data based on seeds and
+ migrations in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/423483). We can only
+ have a successful pipeline if we write the migration so it doesn't fail if data exists in an inconsistent
+ state. We probably need to update some of the database jobs in order to change this.
+- Add widget definitions for the new type.
+ - The migration adds the new work item type as well as the widget definitions that are required for each work item.
+ The widgets you choose depend on the feature the new work item supports, but there are some that probably
+ all new work items need, like `Description`.
+- Optional. Create hierarchy restrictions.
+ - In one of the example MRs we also insert records in the `work_item_hierarchy_restrictions` table. This is only
+ necessary if the new work item type is going to use the `Hierarchy` widget. In this table, you must add what
+ work item type can have children and of what type. Also, you should specify the hierarchy depth for work items of the same
+ type.
+
+##### Example of adding a ticket work item
+
+The `Ticket` work item type already exists in the database, but we'll use it as an example migration.
+Note that for a new type you need to use a new name and ENUM value.
+
+```ruby
+class AddTicketWorkItemType < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ ISSUE_ENUM_VALUE = 0
+ # Enum value comes from the model where the enum is defined in
+ # https://gitlab.com/gitlab-org/gitlab/-/blob/1253f12abddb69cd1418c9e13e289d828b489f36/app/models/work_items/type.rb#L30.
+ # A new work item type should simply pick the next integer value.
+ TICKET_ENUM_VALUE = 8
+ TICKET_NAME = 'Ticket'
+ # Widget definitions also have an enum defined in
+ # https://gitlab.com/gitlab-org/gitlab/-/blob/1253f12abddb69cd1418c9e13e289d828b489f36/app/models/work_items/widget_definition.rb#L17.
+ # We need to provide both the enum and name as we plan to support custom widget names in the future.
+ TICKET_WIDGETS = {
+ 'Assignees' => 0,
+ 'Description' => 1,
+ 'Hierarchy' => 2,
+ 'Labels' => 3,
+ 'Milestone' => 4,
+ 'Notes' => 5,
+ 'Start and due date' => 6,
+ 'Health status' => 7,
+ 'Weight' => 8,
+ 'Iteration' => 9,
+ 'Notifications' => 14,
+ 'Current user todos' => 15,
+ 'Award emoji' => 16
+ }.freeze
+
+ class MigrationWorkItemType < MigrationRecord
+ self.table_name = 'work_item_types'
+ end
+
+ class MigrationWidgetDefinition < MigrationRecord
+ self.table_name = 'work_item_widget_definitions'
+ end
+
+ class MigrationHierarchyRestriction < MigrationRecord
+ self.table_name = 'work_item_hierarchy_restrictions'
+ end
+
+ def up
+ existing_ticket_work_item_type = MigrationWorkItemType.find_by(base_type: TICKET_ENUM_VALUE, namespace_id: nil)
+
+ return say('Ticket work item type record exists, skipping creation') if existing_ticket_work_item_type
+
+ new_ticket_work_item_type = MigrationWorkItemType.create(
+ name: TICKET_NAME,
+ namespace_id: nil,
+ base_type: TICKET_ENUM_VALUE,
+ icon_name: 'issue-type-issue'
+ )
+
+ return say('Ticket work item type create record failed, skipping creation') if new_ticket_work_item_type.new_record?
+
+ widgets = TICKET_WIDGETS.map do |widget_name, widget_enum_value|
+ {
+ work_item_type_id: new_ticket_work_item_type.id,
+ name: widget_name,
+ widget_type: widget_enum_value
+ }
+ end
+
+ MigrationWidgetDefinition.upsert_all(
+ widgets,
+ unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
+ )
+
+ issue_type = MigrationWorkItemType.find_by(base_type: ISSUE_ENUM_VALUE, namespace_id: nil)
+ return say('Issue work item type not found, skipping hierarchy restrictions creation') unless issue_type
+
+ # This part of the migration is only necessary if the new type uses the `Hierarchy` widget.
+ restrictions = [
+ { parent_type_id: new_ticket_work_item_type.id, child_type_id: new_ticket_work_item_type.id, maximum_depth: 1 },
+ { parent_type_id: new_ticket_work_item_type.id, child_type_id: issue_type.id, maximum_depth: 1 }
+ ]
+
+ MigrationHierarchyRestriction.upsert_all(
+ restrictions,
+ unique_by: :index_work_item_hierarchy_restrictions_on_parent_and_child
+ )
+ end
+
+ def down
+ # There's the remote possibility that issues could already be
+ # using this issue type, with a tight foreign constraint.
+ # Therefore we will not attempt to remove any data.
+ end
+end
+```
+
+<!-- markdownlint-disable-next-line MD044 -->
+#### Update Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter
+
+The [BaseTypeImporter](https://gitlab.com/gitlab-org/gitlab/-/blob/f816a369d7d6bbd1d8d53d6c0bca4ca3389fdba7/lib/gitlab/database_importers/work_items/base_type_importer.rb)
+is where we can clearly visualize the structure of the types we have and what widgets are associated with each of them.
+`BaseTypeImporter` is the single source of truth for fresh GitLab installs and also our test suite. This should always
+reflect what we change with migrations.
+
### Custom work item types
With the WIT widget metadata and the workflow around mapping WIT to specific
diff --git a/doc/editor_extensions/index.md b/doc/editor_extensions/index.md
index 11220bc716c..f9742d30803 100644
--- a/doc/editor_extensions/index.md
+++ b/doc/editor_extensions/index.md
@@ -4,7 +4,7 @@ group: Code Review
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Editor and IDE Extensions
+# Editor and IDE extensions
GitLab has plugins and extensions to extend GitLab functionality to the following editors:
@@ -13,7 +13,7 @@ GitLab has plugins and extensions to extend GitLab functionality to the followin
- [Visual Studio](visual_studio/index.md)
- [Neovim](neovim/index.md)
-GitLab also supports developers in their command line interface with [`glab`](gitlab_cli/index.md) the GitLab CLI.
+GitLab also supports developers in their command-line interface with [`glab`](gitlab_cli/index.md) the GitLab CLI.
## Features
diff --git a/doc/editor_extensions/jetbrains_ide/index.md b/doc/editor_extensions/jetbrains_ide/index.md
index dcf13570b11..7809ad69866 100644
--- a/doc/editor_extensions/jetbrains_ide/index.md
+++ b/doc/editor_extensions/jetbrains_ide/index.md
@@ -30,7 +30,7 @@ integrates GitLab with JetBrains IDEs. The following JetBrains IDEs are supporte
## Supported features
-GitLab for JetBrains supports [GitLab Duo Code Suggestions](../../user/project/repository/code_suggestions.md).
+GitLab for JetBrains supports [GitLab Duo Code Suggestions](../../user/project/repository/code_suggestions/index.md).
## Download the extension
diff --git a/doc/editor_extensions/neovim/index.md b/doc/editor_extensions/neovim/index.md
index e2e410ae82c..220cae8f334 100644
--- a/doc/editor_extensions/neovim/index.md
+++ b/doc/editor_extensions/neovim/index.md
@@ -13,7 +13,7 @@ integrates GitLab with Neovim. The following Neovim versions are supported:
## Supported features
-GitLab for Neovim supports [GitLab Duo Code Suggestions](../../user/project/repository/code_suggestions.md).
+GitLab for Neovim supports [GitLab Duo Code Suggestions](../../user/project/repository/code_suggestions/index.md).
## Install and configure the extension
diff --git a/doc/editor_extensions/visual_studio/index.md b/doc/editor_extensions/visual_studio/index.md
index 744f7759bf5..76a1abe058a 100644
--- a/doc/editor_extensions/visual_studio/index.md
+++ b/doc/editor_extensions/visual_studio/index.md
@@ -14,7 +14,7 @@ integrates GitLab with Visual Studio. The following Visual Studio versions are s
## Supported features
-GitLab for Visual Studio supports [GitLab Duo Code Suggestions](../../user/project/repository/code_suggestions.md).
+GitLab for Visual Studio supports [GitLab Duo Code Suggestions](../../user/project/repository/code_suggestions/index.md).
## Download the extension
diff --git a/doc/editor_extensions/visual_studio_code/index.md b/doc/editor_extensions/visual_studio_code/index.md
index 7c49879be13..2aa745c17a8 100644
--- a/doc/editor_extensions/visual_studio_code/index.md
+++ b/doc/editor_extensions/visual_studio_code/index.md
@@ -22,7 +22,8 @@ do more day-to-day tasks in Visual Studio Code, such as:
and paste snippets to, and from, your editor.
- [Browse repositories](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#browse-a-repository-without-cloning)
without cloning them.
-- [Receive Code Suggestions](../../user/project/repository/code_suggestions.md).
+- [Receive Code Suggestions](../../user/project/repository/code_suggestions/index.md).
+- [View Security findings](https://marketplace.visualstudio.com/items?itemName=gitlab.gitlab-workflow#security-findings).
## Download the extension
@@ -35,7 +36,7 @@ you can [configure](https://marketplace.visualstudio.com/items?itemName=GitLab.g
- [Features to display or hide](https://gitlab.com/gitlab-org/gitlab-vscode-extension#extension-settings).
- [Self-signed certificate](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#self-signed-certificates) information.
-- [Code Suggestions](../../user/project/repository/code_suggestions.md).
+- [Code Suggestions](../../user/project/repository/code_suggestions/index.md).
## Report issues with the extension
diff --git a/doc/gitlab-basics/add-file.md b/doc/gitlab-basics/add-file.md
index 255d78ab915..55300d52b71 100644
--- a/doc/gitlab-basics/add-file.md
+++ b/doc/gitlab-basics/add-file.md
@@ -25,7 +25,7 @@ If you are unfamiliar with the command line, use the
<!-- Original source for this list: doc/user/project/repository/web_editor.md#upload-a-file -->
<!-- For why we duplicated the info, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111072#note_1267429478 -->
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. From the project dashboard or repository, next to the branch name, select the plus icon (**{plus}**).
1. From the dropdown list, select **Upload file**.
1. Complete the fields. To create a merge request with the uploaded file, ensure the **Start a new merge request with these changes** toggle is turned on.
diff --git a/doc/install/aws/gitlab_hybrid_on_aws.md b/doc/install/aws/gitlab_hybrid_on_aws.md
index 42488becbd6..b39f39f293e 100644
--- a/doc/install/aws/gitlab_hybrid_on_aws.md
+++ b/doc/install/aws/gitlab_hybrid_on_aws.md
@@ -32,38 +32,12 @@ Amazon provides a managed Kubernetes service offering known as [Amazon Elastic K
## Available Infrastructure as Code for GitLab Cloud Native Hybrid
-The [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md) is an effort made by GitLab to create a multi-cloud, multi-GitLab (Linux package installation + Cloud Native Hybrid) toolkit to provision GitLab. GET is developed by GitLab developers and is open to community contributions. GET is where GitLab is investing its resources as the primary option for Infrastructure as Code, and is being actively used in production as a part of [GitLab Dedicated](../../subscriptions/gitlab_dedicated/index.md).
+The [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md) is a set of opinionated Terraform
+and Ansible scripts. These scripts help with the deployment of Linux package or Cloud Native Hybrid environments on selected cloud providers and are used
+by GitLab developers for [GitLab Dedicated](../../subscriptions/gitlab_dedicated/index.md) (for example).
-For more information about the project, see [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md).
-
-The [AWS Quick Start for GitLab Cloud Native Hybrid on EKS](https://aws-quickstart.github.io/quickstart-eks-gitlab/) is developed by AWS, GitLab, and the community that contributes to AWS Quick Starts, whether directly to the GitLab Quick Start or to the underlying Quick Start dependencies GitLab inherits (for example, EKS Quick Start).
-
-GET is recommended for most deployments. The AWS Quick Start can be used if the IaC language of choice is CloudFormation, integration with AWS services like Control Tower is desired, or preference for a UI-driven configuration experience or when any aspect in the below table is an overriding concern.
-
-NOTE:
-This automation is in **[Open Beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#open-beta)**. GitLab is working with AWS on resolving [the outstanding issues](https://github.com/aws-quickstart/quickstart-eks-gitlab/issues?q=is%3Aissue+is%3Aopen+%5BHL%5D) before it is fully released. You can subscribe to this issue to be notified of progress and release announcements: [AWS Quick Start for GitLab Cloud Native Hybrid on EKS Status: Beta](https://gitlab.com/gitlab-com/alliances/aws/public-tracker/-/issues/11).<br><br>
-The Beta version deploys Aurora PostgreSQL, but the release version will deploy Amazon RDS PostgreSQL due to [known issues](https://gitlab.com/gitlab-com/alliances/aws/public-tracker/-/issues?label_name%5B%5D=AWS+Known+Issue) with Aurora. All performance testing results will also be redone after this change has been made.
-
-| | [AWS Quick Start for GitLab Cloud Native Hybrid on EKS](https://aws-quickstart.github.io/quickstart-eks-gitlab/) | [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) |
-| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
-| Overview and Vision | [AWS Quick Start](https://aws.amazon.com/solutions/implementations/amazon-eks/) | [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md) |
-| Licensing | [Open Source (Apache 2.0)](https://github.com/aws-quickstart/quickstart-eks-gitlab/blob/main/LICENSE.txt) | [GitLab Enterprise Edition license](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/LICENSE) ([GitLab Premium tier](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md)) |
-| GitLab Support | [GitLab Beta Support](../../policy/experiment-beta-support.md#beta) | [GitLab GA Support](../../policy/experiment-beta-support.md#generally-available-ga) |
-| GitLab Reference Architecture Compliant | Yes | Yes |
-| GitLab Performance Tool (GPT) Tested | Yes | Yes |
-| Amazon Well Architected Compliant | Yes<br />(via Quick Start program) | Critical portions <br />reviewed by AWS |
-| Target Cloud Platforms | AWS | AWS, Google, Azure |
-| IaC Languages | CloudFormation (Quick Starts) | Terraform, Ansible |
-| Community Contributions and Participation (EcoSystem) | <u>GitLab QSG</u>: Getting Started<br /><u>For QSG Dependencies (for example, EKS)</u>: Substantial | Getting Started |
-| Compatible with AWS Meta-Automation Services (via CloudFormation) | - [AWS Service Catalog](https://aws.amazon.com/servicecatalog/) (Direct Import)<br>- [ServiceNow via an AWS Service Catalog Connector](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/integrations-servicenow.html#integrations-servicenow)<br>- [Jira Service Manager via an AWS Service Catalog Connector](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/integrations-jiraservicedesk.html#integrations-jiraservicedesk)<br>- [AWS Control Tower](https://docs.aws.amazon.com/controltower/) ([Integration](https://aws.amazon.com/blogs/infrastructure-and-automation/deploy-aws-quick-start-to-multiple-accounts-using-aws-control-tower/))<br>- Quick Starts<br>- [AWS SaaS Factory](https://aws.amazon.com/partners/programs/saas-factory/) | No |
-| Results in a Ready-to-Use instance | Yes | Manual Actions or <br />Supplemental IaC Required |
-| **<u>Configuration Features</u>** | | |
-| Can deploy Linux package (non-Kubernetes) | No | Yes |
-| Can deploy a single instance by using the Linux package (non-Kubernetes) | No | Yes |
-| Complete Internal Encryption | 85%, Targeting 100% | Manual |
-| AWS GovCloud Support | Yes | TBD |
-| No Code Form-Based Deployment User Experience Available | Yes | No |
-| Full IaC User Experience Available | Yes | Yes |
+You can use the GitLab Environment Toolkit to deploy a Cloud Native Hybrid environment on AWS. However, it's not required and may not support every valid
+permutation. That said, the scripts are presented as-is and you can adapt them accordingly.
### Two and Three Zone High Availability
diff --git a/doc/install/azure/index.md b/doc/install/azure/index.md
index 8a3cd720079..60591991ea7 100644
--- a/doc/install/azure/index.md
+++ b/doc/install/azure/index.md
@@ -248,7 +248,7 @@ in this section whenever you need to update GitLab.
To determine the version of GitLab you're currently running:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Dashboard**.
1. Find the version under the **Components** table.
diff --git a/doc/install/cloud_native/index.md b/doc/install/cloud_native/index.md
deleted file mode 100644
index d971cd419e9..00000000000
--- a/doc/install/cloud_native/index.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'https://docs.gitlab.com/charts/'
-remove_date: '2023-09-09'
----
-
-This document was moved to [another location](https://docs.gitlab.com/charts/).
-
-<!-- This redirect file can be deleted after <2023-09-09>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> \ No newline at end of file
diff --git a/doc/install/install_methods.md b/doc/install/install_methods.md
index fb48107e81b..5945e418274 100644
--- a/doc/install/install_methods.md
+++ b/doc/install/install_methods.md
@@ -17,7 +17,7 @@ or use one of the following methods.
| [Helm chart](https://docs.gitlab.com/charts/) | A chart for installing a cloud-native version of GitLab and its components on Kubernetes. | Use if your infrastructure is on Kubernetes and you're familiar with how it works. Management, observability, and some concepts are different than traditional deployments.<br/>- Administration and troubleshooting requires Kubernetes knowledge.<br/>- It can be more expensive for smaller installations. The default installation requires more resources than a single node Linux package deployment, because most services are deployed in a redundant fashion.<br/><br/> |
| [Docker](docker.md) | The GitLab packages in a Docker container. | Use if you're familiar with Docker. |
| [Source](installation.md) | GitLab and its components from scratch. | Use if none of the previous methods are available for your platform. Can use for unsupported systems like \*BSD.|
-| [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit#documentation) | A set of automation tools. | Use to deploy a [reference architecture](../administration/reference_architectures/index.md) on most major cloud providers. Has some [limitations](https://gitlab.com/gitlab-org/gitlab-environment-toolkit#missing-features-to-be-aware-of) and manual setup for production environments. |
+| [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit#documentation) | A set of opinionated Terraform and Ansible scripts. | Use to deploy a [reference architecture](../administration/reference_architectures/index.md) on selected major cloud providers. Has some [limitations](https://gitlab.com/gitlab-org/gitlab-environment-toolkit#missing-features-to-be-aware-of) and manual setup for production environments. |
| [GitLab Operator](https://docs.gitlab.com/operator/) | An installation and management method that follows the [Kubernetes Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/). | Use to run GitLab in an [OpenShift](openshift_and_gitlab/index.md) environment. |
## Unsupported Linux distributions and Unix-like operating systems
diff --git a/doc/install/next_steps.md b/doc/install/next_steps.md
index ecc456cd3ec..4ad6a011cd6 100644
--- a/doc/install/next_steps.md
+++ b/doc/install/next_steps.md
@@ -42,7 +42,7 @@ installation.
- [Back up and restore GitLab](../administration/backup_restore/index.md): Learn the different
ways you can back up or restore GitLab.
-- [Upgrade GitLab](../update/index.md): Every 22nd of the month, a new feature-rich GitLab version
+- [Upgrade GitLab](../update/index.md): Every month, a new feature-rich GitLab version
is released. Learn how to upgrade to it, or to an interim release that contains a security fix.
- [Release and maintenance policy](../policy/maintenance.md): Learn about GitLab
policies governing version naming, as well as release pace for major, minor, patch,
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index b095f265808..81244594a59 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -50,11 +50,13 @@ The following is the recommended minimum Memory hardware guidance for a handful
- 8 GB RAM supports up to 1000 users
- More users? Consult the [reference architectures page](../administration/reference_architectures/index.md)
-In addition to the above, we generally recommend having at least 2 GB of swap on your server,
-even if you currently have enough available RAM. Having swap helps to reduce the chance of errors occurring
-if your available memory changes. We also recommend configuring the kernel's swappiness setting
-to a low value like `10` to make the most of your RAM while still having the swap
-available when needed.
+For smaller installations, you should:
+
+- Have at least 2 GB of swap on your server, even if you have enough available RAM. Having swap helps to reduce the chance of
+ errors occurring if your available memory changes.
+- Configure the kernel's swappiness setting to a low value like `10` to make the most of your RAM while still having the swap available when needed.
+
+For larger installations that follow our reference architectures, you [shouldn't configure swap](../administration/reference_architectures/index.md#no-swap).
NOTE:
Although excessive swapping is undesired and degrades performance, it is an
@@ -98,7 +100,7 @@ The following managed PostgreSQL services are known to be incompatible and shoul
| GitLab version | Managed service |
|----------------|-------------------------------------------------------|
-| 14.4+ | Amazon Aurora (see [14.4.0](../update/index.md#1440)) |
+| 14.4+ | Amazon Aurora (see [14.4.0](../update/versions/gitlab_14_changes.md#1440)) |
NOTE:
Support for [PostgreSQL 9.6 and 10 was removed in GitLab 13.0](https://about.gitlab.com/releases/2020/05/22/gitlab-13-0-released/#postgresql-11-is-now-the-minimum-required-version-to-install-gitlab) so that GitLab can benefit from PostgreSQL 11 improvements, such as partitioning.
diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md
index f23bfa47eba..066c04081a5 100644
--- a/doc/integration/advanced_search/elasticsearch.md
+++ b/doc/integration/advanced_search/elasticsearch.md
@@ -5,7 +5,7 @@ group: Global Search
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Elasticsearch **(PREMIUM SELF)**
+# Elasticsearch **(PREMIUM ALL)**
This page describes how to enable advanced search. When enabled,
advanced search provides faster search response times and [improved search features](../../user/search/advanced_search.md).
@@ -14,16 +14,14 @@ advanced search provides faster search response times and [improved search featu
### Elasticsearch version requirements
-> Support for Elasticsearch 6.8 was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/350275) in GitLab 15.0.
+> Support for Elasticsearch 6.8 [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/350275) in GitLab 15.0.
Advanced search works with the following versions of Elasticsearch.
-| GitLab version | Elasticsearch version |
-|-----------------------|--------------------------|
-| GitLab 15.0 or later | Elasticsearch 7.x - 8.x |
-| GitLab 13.9 - 14.10 | Elasticsearch 6.8 - 7.x |
-| GitLab 13.3 - 13.8 | Elasticsearch 6.4 - 7.x |
-| GitLab 12.7 - 13.2 | Elasticsearch 6.x - 7.x |
+| GitLab version | Elasticsearch version |
+|-----------------------|-----------------------------|
+| GitLab 15.0 and later | Elasticsearch 7.x and later |
+| GitLab 14.0 to 14.10 | Elasticsearch 6.8 to 7.x |
Advanced search follows the [Elasticsearch end-of-life policy](https://www.elastic.co/support/eol).
When we change Elasticsearch supported versions in GitLab, we announce them in [deprecation notes](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations) in monthly release posts
@@ -31,10 +29,10 @@ before we remove them.
### OpenSearch version requirements
-| GitLab version | OpenSearch version |
-|-------------------------|---------------------------|
-| GitLab 15.0 to 15.5.2 | OpenSearch 1.x |
-| GitLab 15.5.3 and later | OpenSearch 1.x and later |
+| GitLab version | OpenSearch version |
+|-------------------------|--------------------------|
+| GitLab 15.5.3 and later | OpenSearch 1.x and later |
+| GitLab 15.0 to 15.5.2 | OpenSearch 1.x |
If your version of Elasticsearch or OpenSearch is incompatible, to prevent data loss, indexing pauses and
a message is logged in the
@@ -47,7 +45,7 @@ If you are using a compatible version and after connecting to OpenSearch, you ge
Elasticsearch requires additional resources to those documented in the
[GitLab system requirements](../../install/requirements.md).
-Memory, CPU, and storage resource amounts vary depending on the amount of data you index into the Elasticsearch cluster. Heavily used Elasticsearch clusters may require more resources. The [`estimate_cluster_size`](#gitlab-advanced-search-rake-tasks) Rake task ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/221177) in GitLab 13.10) uses the total repository size to estimate the advanced search storage requirements.
+Memory, CPU, and storage resource amounts vary depending on the amount of data you index into the Elasticsearch cluster. Heavily used Elasticsearch clusters may require more resources. The [`estimate_cluster_size`](#gitlab-advanced-search-rake-tasks) Rake task uses the total repository size to estimate the advanced search storage requirements.
## Install Elasticsearch
@@ -68,10 +66,14 @@ The search index updates after you:
## Upgrade to a new Elasticsearch major version
-> - Elasticsearch 6.8 support is removed with GitLab 15.0.
-> - Upgrading from GitLab 14.10 to 15.0 requires that you are using any version of Elasticsearch 7.x.
+> Support for Elasticsearch 6.8 [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/350275) in GitLab 15.0.
-You are not required to change the GitLab configuration when you upgrade Elasticsearch.
+You don't have to change the GitLab configuration when you upgrade Elasticsearch.
+
+You should pause indexing during an Elasticsearch upgrade so changes can still be tracked.
+When the Elasticsearch cluster is fully upgraded and active, [resume indexing](#unpause-indexing).
+
+When you upgrade to GitLab 15.0 and later, you must use Elasticsearch 7.x and later.
## Elasticsearch repository indexer
@@ -82,7 +84,7 @@ Depending on your GitLab version, there are different installation procedures fo
- For Linux package installations, the Go indexer is included.
- For self-compiled installations, see [Install the indexer from source](#install-the-indexer-from-source).
- If you're using the GitLab Development Kit, see [Elasticsearch in the GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/elasticsearch.md).
-- If you're running a Helm deployment of GitLab 11.10 and later, [the indexer is already included](https://gitlab.com/gitlab-org/build/CNG/-/merge_requests/213).
+- If you're using the GitLab Helm chart, [the indexer is already included](https://gitlab.com/gitlab-org/build/CNG/-/merge_requests/213).
### Install the indexer from source
@@ -166,7 +168,7 @@ Prerequisite:
To enable advanced search:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Advanced Search**.
@@ -210,7 +212,7 @@ You can only use the **Index all projects** setting to perform
initial indexing, not to re-create an index from scratch.
To enable advanced search with **Index all projects**:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Advanced Search**.
1. Select the **Elasticsearch indexing** checkbox, then select **Save changes**.
@@ -402,7 +404,7 @@ You can improve the language support for Chinese and Japanese languages by utili
To enable languages support:
1. Install the desired plugins, refer to [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/plugins/7.9/installation.html) for plugins installation instructions. The plugins must be installed on every node in the cluster, and each node must be restarted after installation. For a list of plugins, see the table later in this section.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Advanced Search**.
1. Locate **Custom analyzers: language support**.
@@ -424,7 +426,7 @@ For guidance on what to install, see the following Elasticsearch language plugin
To disable the Elasticsearch integration:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Advanced Search**.
1. Clear the **Elasticsearch indexing** and **Search with Elasticsearch enabled** checkboxes.
@@ -441,7 +443,7 @@ To disable the Elasticsearch integration:
## Unpause Indexing
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Advanced Search**.
1. Expand **Advanced Search**.
@@ -462,14 +464,10 @@ You can use zero-downtime reindexing to configure index settings or mappings tha
### Trigger the reindex via the advanced search administration
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34069) in GitLab 13.2.
-> - A scheduled index deletion and the ability to cancel it was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38914) in GitLab 13.3.
-> - Support for retries during reindexing was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55681) in GitLab 13.12.
-
To trigger the reindexing process:
1. Sign in to your GitLab instance as an administrator.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Advanced Search**.
1. Expand **Elasticsearch zero-downtime reindexing**.
@@ -485,9 +483,7 @@ While the reindexing is running, you can follow its progress under that same sec
#### Elasticsearch zero-downtime reindexing
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55681) in GitLab 13.12.
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Advanced Search**.
1. Expand **Elasticsearch zero-downtime reindexing**, and you'll
@@ -536,7 +532,7 @@ Sometimes, you might want to abandon the unfinished reindex job and resume the i
bundle exec rake gitlab:elastic:mark_reindex_failed RAILS_ENV=production
```
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Advanced Search**.
1. Expand **Advanced Search**.
@@ -545,12 +541,7 @@ Sometimes, you might want to abandon the unfinished reindex job and resume the i
## Index integrity
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112369) in GitLab 15.10 [with a flag](../../administration/feature_flags.md) named `search_index_integrity`. Disabled by default.
-> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/392981) in GitLab 16.0.
-> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/392981) in GitLab 16.3.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To hide the feature, an administrator can [disable the feature flag](../../administration/feature_flags.md) named `search_index_integrity`.
-On GitLab.com, this feature is available.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/392981) in GitLab 16.4. Feature flag `search_index_integrity` removed.
Index integrity detects and fixes missing repository data.
This feature is automatically used when code searches
@@ -558,8 +549,6 @@ scoped to a group or project return no results.
## Advanced search migrations
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/234046) in GitLab 13.6.
-
With reindex migrations running in the background, there's no need for a manual
intervention. This usually happens in situations where new features are added to
advanced search, which means adding or changing the way content is indexed.
@@ -685,7 +674,7 @@ The following are some available Rake tasks:
| [`sudo gitlab-rake gitlab:elastic:index_snippets`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Performs an Elasticsearch import that indexes the snippets data. |
| [`sudo gitlab-rake gitlab:elastic:index_users`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Imports all users into Elasticsearch. |
| [`sudo gitlab-rake gitlab:elastic:projects_not_indexed`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Displays which projects are not indexed. |
-| [`sudo gitlab-rake gitlab:elastic:reindex_cluster`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Schedules a zero-downtime cluster reindexing task. This feature should be used with an index that was created after GitLab 13.0. |
+| [`sudo gitlab-rake gitlab:elastic:reindex_cluster`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Schedules a zero-downtime cluster reindexing task. |
| [`sudo gitlab-rake gitlab:elastic:mark_reindex_failed`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Mark the most recent re-index job as failed. |
| [`sudo gitlab-rake gitlab:elastic:list_pending_migrations`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | List pending migrations. Pending migrations include those that have not yet started, have started but not finished, and those that are halted. |
| [`sudo gitlab-rake gitlab:elastic:estimate_cluster_size`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Get an estimate of cluster size based on the total repository size. |
@@ -751,7 +740,7 @@ For basic guidance on choosing a cluster configuration you may refer to [Elastic
- A good guideline is to ensure you keep the number of shards per node below 20 per GB heap it has configured. A node with a 30 GB heap should therefore have a maximum of 600 shards, but the further below this limit you can keep it the better. This generally helps the cluster stay in good health.
- Number of Elasticsearch shards:
- Small shards result in small segments, which increases overhead. Aim to keep the average shard size between at least a few GB and a few tens of GB.
- - Another consideration is the number of documents. To determine the number of shards to use, sum the numbers in the **Main menu > Admin > Dashboard > Statistics** pane (the number of documents to be indexed), divide by 5 million, and add 5. For example:
+ - Another consideration is the number of documents. To determine the number of shards to use, sum the numbers in the Admin Area under **Dashboard > Statistics** (the number of documents to be indexed), divide by 5 million, and add 5. For example:
- If you have fewer than about 2,000,000 documents, use the default of 5 shards
- 10,000,000 documents: `10000000/5000000 + 5` = 7 shards
- 100,000,000 documents: `100000000/5000000 + 5` = 25 shards
@@ -828,7 +817,7 @@ Make sure to prepare for this task by having a
```
This enqueues a Sidekiq job for each project that needs to be indexed.
- You can view the jobs in **Main menu > Admin > Monitoring > Background Jobs > Queues Tab**
+ You can view the jobs in the Admin Area under **Monitoring > Background Jobs > Queues Tab**
and select `elastic_commit_indexer`, or you can query indexing status using a Rake task:
```shell
@@ -893,7 +882,7 @@ Make sure to prepare for this task by having a
A force merge should be called after enabling the refreshing above.
- For Elasticsearch 6.x, the index should be in read-only mode before proceeding with the force merge:
+ For Elasticsearch 6.x and later, ensure the index is in read-only mode before proceeding with the force merge:
```shell
curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' \
@@ -909,7 +898,7 @@ Make sure to prepare for this task by having a
curl --request POST 'localhost:9200/gitlab-production/_forcemerge?max_num_segments=5'
```
- After this, if your index is in read-only mode, switch back to read-write:
+ Then, change the index back to read-write mode:
```shell
curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' \
diff --git a/doc/integration/advanced_search/elasticsearch_troubleshooting.md b/doc/integration/advanced_search/elasticsearch_troubleshooting.md
index d13d47a1633..df1e1f49083 100644
--- a/doc/integration/advanced_search/elasticsearch_troubleshooting.md
+++ b/doc/integration/advanced_search/elasticsearch_troubleshooting.md
@@ -513,3 +513,9 @@ $ jq '.class' sidekiq/current | sort | uniq -c | sort -nr
In this case, `free -m` on the overloaded GitLab node would also show
unexpectedly high `buff/cache` usage.
+
+## `Couldn't load task status` error when reindexing
+
+When you reindex, you might get a `Couldn't load task status` error. A `sliceId must be greater than 0 but was [-1]` error might also appear on the Elasticsearch host. As a workaround, consider [reindexing from scratch](../../integration/advanced_search/elasticsearch_troubleshooting.md#last-resort-to-recreate-an-index) or upgrading to GitLab 16.3.
+
+For more information, see [issue 422938](https://gitlab.com/gitlab-org/gitlab/-/issues/422938).
diff --git a/doc/integration/akismet.md b/doc/integration/akismet.md
index 19c86743eba..94c25a0547b 100644
--- a/doc/integration/akismet.md
+++ b/doc/integration/akismet.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -30,7 +30,7 @@ To use Akismet:
1. Sign in or create a new account.
1. Select **Show** to reveal the API key, and copy the API key's value.
1. Sign in to GitLab as an administrator.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Reporting**.
1. Expand **Spam and Anti-bot Protection**.
diff --git a/doc/integration/alicloud.md b/doc/integration/alicloud.md
index 9054341960f..3984deb303a 100644
--- a/doc/integration/alicloud.md
+++ b/doc/integration/alicloud.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/arkose.md b/doc/integration/arkose.md
index cd0b80e5a66..575cf8c4271 100644
--- a/doc/integration/arkose.md
+++ b/doc/integration/arkose.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/auth0.md b/doc/integration/auth0.md
index e6a6853cdef..a6577a3eb89 100644
--- a/doc/integration/auth0.md
+++ b/doc/integration/auth0.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/azure.md b/doc/integration/azure.md
index 08ca19a950b..71f6c2cf3a0 100644
--- a/doc/integration/azure.md
+++ b/doc/integration/azure.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/bitbucket.md b/doc/integration/bitbucket.md
index 7fad67116f3..0e880c79b7a 100644
--- a/doc/integration/bitbucket.md
+++ b/doc/integration/bitbucket.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/cas.md b/doc/integration/cas.md
deleted file mode 100644
index d2a29161a53..00000000000
--- a/doc/integration/cas.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-stage: Manage
-group: Authentication and Authorization
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-15'
-redirect_to: '../administration/auth/index.md'
----
-
-# CAS OmniAuth provider (removed) **(FREE SELF)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/369127)
-in GitLab 15.3 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/369128)
-in 16.0.
diff --git a/doc/integration/datadog.md b/doc/integration/datadog.md
index 5e89cfbe6a0..4d26235e65f 100644
--- a/doc/integration/datadog.md
+++ b/doc/integration/datadog.md
@@ -27,7 +27,7 @@ project, group, or instance level:
1. *For project-level or group-level integrations:* In GitLab, go to your project or group.
1. *For instance-level integrations:*
1. Sign in to GitLab as a user with administrator access.
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Integrations**.
1. Scroll to **Add an integration**, and select **Datadog**.
diff --git a/doc/integration/ding_talk.md b/doc/integration/ding_talk.md
index 005bf0a3244..91727ba5398 100644
--- a/doc/integration/ding_talk.md
+++ b/doc/integration/ding_talk.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md
index 2d0f0892f30..a4c7f75ea19 100644
--- a/doc/integration/external-issue-tracker.md
+++ b/doc/integration/external-issue-tracker.md
@@ -25,7 +25,7 @@ References are displayed as issue links.
To disable the GitLab issue tracker for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Under **Issues**, turn off the toggle.
diff --git a/doc/integration/facebook.md b/doc/integration/facebook.md
index 0ff640306c3..299b1e53ff2 100644
--- a/doc/integration/facebook.md
+++ b/doc/integration/facebook.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/github.md b/doc/integration/github.md
index df9a0db961b..0de7e463944 100644
--- a/doc/integration/github.md
+++ b/doc/integration/github.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md
index 92709d974aa..8162d011395 100644
--- a/doc/integration/gitlab.md
+++ b/doc/integration/gitlab.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/gitpod.md b/doc/integration/gitpod.md
index 9b431846f2b..288c2615d66 100644
--- a/doc/integration/gitpod.md
+++ b/doc/integration/gitpod.md
@@ -45,7 +45,7 @@ With the Gitpod integration enabled for your GitLab instance, to enable it for y
For self-managed GitLab instances, a GitLab administrator must:
1. Enable the Gitpod integration in GitLab:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Gitpod** configuration section.
@@ -61,7 +61,7 @@ GitLab users can then [enable the Gitpod integration for themselves](#enable-git
You can launch Gitpod directly from GitLab in one of these ways:
- **From a project repository:**
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. In the upper right, select **Edit > Gitpod**.
- **From a merge request:**
diff --git a/doc/integration/google.md b/doc/integration/google.md
index 5bba50c940a..5ef47c79e2d 100644
--- a/doc/integration/google.md
+++ b/doc/integration/google.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md
index 736f5bc080c..4f76301adeb 100644
--- a/doc/integration/jenkins.md
+++ b/doc/integration/jenkins.md
@@ -8,33 +8,34 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/246756) to GitLab Free in 13.7.
-You can trigger a build in Jenkins when you push code to your repository or
-create a merge request in GitLab. The Jenkins pipeline status displays on merge
-requests widgets and on the GitLab project's home page.
+[Jenkins](https://www.jenkins.io/) is an open source automation server that supports
+building, deploying and automating projects.
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For an overview of the Jenkins integration for GitLab, see
-[GitLab workflow with Jira issues and Jenkins pipelines](https://youtu.be/Jn-_fyra7xQ).
-
-Use the Jenkins integration when:
+You should use a Jenkins integration with GitLab when:
- You plan to migrate your CI from Jenkins to [GitLab CI/CD](../ci/index.md)
in the future, but need an interim solution.
- You're invested in [Jenkins plugins](https://plugins.jenkins.io/) and choose
to keep using Jenkins to build your apps.
-NOTE:
-This documentation focuses only on how to configure a Jenkins *integration* with
-GitLab. Learn how to set up Jenkins [on your local machine](../development/integrations/jenkins.md)
-in the developer documentation, and how to migrate from Jenkins to GitLab CI/CD in the
-[Migrating from Jenkins](../ci/migration/jenkins.md) documentation.
+After you have configured a Jenkins integration, you trigger a build in Jenkins
+when you push code to your repository or create a merge request in GitLab. The
+Jenkins pipeline status displays on merge request widgets and the GitLab
+project's home page.
+
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview of the Jenkins integration for GitLab, see
+[GitLab workflow with Jira issues and Jenkins pipelines](https://youtu.be/Jn-_fyra7xQ).
+
+To configure a Jenkins integration with GitLab:
-The Jenkins integration requires configuration in both GitLab and Jenkins.
+- Grant Jenkins access to the GitLab project.
+- Configure the Jenkins server.
+- Configure the Jenkins project.
+- Configure the GitLab project.
## Grant Jenkins access to the GitLab project
-To grant Jenkins access to the GitLab project:
-
1. Create a personal, project, or group access token.
- [Create a personal access token](../user/profile/personal_access_tokens.md#create-a-personal-access-token)
@@ -46,20 +47,22 @@ To grant Jenkins access to the GitLab project:
to use the token for all Jenkins integrations in all projects of that group.
1. Set the access token scope to **API**.
-1. Copy the access token value to [configure the Jenkins server](#configure-the-jenkins-server).
+1. Copy the access token value to configure the Jenkins server.
## Configure the Jenkins server
-Install and configure the Jenkins plugin. The plugin must be installed and configured to
-authorize the connection to GitLab.
+Install and configure the Jenkins plugin to authorize the connection to GitLab.
1. On the Jenkins server, select **Manage Jenkins > Manage Plugins**.
-1. Install the [Jenkins GitLab Plugin](https://wiki.jenkins.io/display/JENKINS/GitLab+Plugin).
+1. Select the **Available** tab. Search for `gitlab-plugin` and select it to install.
+ See the [Jenkins GitLab documentation](https://wiki.jenkins.io/display/JENKINS/GitLab+Plugin)
+ for other ways to install the plugin.
1. Select **Manage Jenkins > Configure System**.
1. In the **GitLab** section, select **Enable authentication for '/project' end-point**.
1. Select **Add**, then choose **Jenkins Credential Provider**.
1. Select **GitLab API token** as the token type.
-1. In **API Token**, [paste the value you copied from GitLab](#grant-jenkins-access-to-the-gitlab-project) and select **Add**.
+1. In **API Token**, [paste the access token value you copied from GitLab](#grant-jenkins-access-to-the-gitlab-project)
+ and select **Add**.
1. Enter the GitLab server's URL in **GitLab host URL**.
1. To test the connection, select **Test Connection**.
@@ -72,21 +75,21 @@ For more information, see
Set up the Jenkins project you intend to run your build on.
-1. On your Jenkins instance, go to **New Item**.
+1. On your Jenkins instance, select **New Item**.
1. Enter the project's name.
1. Select **Freestyle** or **Pipeline** and select **OK**.
- We recommend a Freestyle project, because the Jenkins plugin updates the build status on
- GitLab. In a Pipeline project, you must configure a script to update the status on GitLab.
+ You should select a freestyle project, because the Jenkins plugin updates the build status on
+ GitLab. In a pipeline project, you must configure a script to update the status on GitLab.
1. Choose your GitLab connection from the dropdown list.
1. Select **Build when a change is pushed to GitLab**.
1. Select the following checkboxes:
- **Accepted Merge Request Events**
- **Closed Merge Request Events**
1. Specify how the build status is reported to GitLab:
- - If you created a **Freestyle** project, in the **Post-build Actions** section, choose
- **Publish build status to GitLab**.
- - If you created a **Pipeline** project, you must use a Jenkins Pipeline script to update the status on
- GitLab.
+ - If you created a freestyle project, in the **Post-build Actions** section,
+ choose **Publish build status to GitLab**.
+ - If you created a pipeline project, you must use a Jenkins Pipeline script to
+ update the status on GitLab.
Example Jenkins Pipeline script:
@@ -106,18 +109,19 @@ Set up the Jenkins project you intend to run your build on.
}
```
- For more Jenkins Pipeline script examples, go to the [Jenkins GitLab plugin repository on GitHub](https://github.com/jenkinsci/gitlab-plugin#scripted-pipeline-jobs).
+ For more Jenkins Pipeline script examples, see the
+ [Jenkins GitLab plugin repository on GitHub](https://github.com/jenkinsci/gitlab-plugin#scripted-pipeline-jobs).
## Configure the GitLab project
Configure the GitLab integration with Jenkins in one of the following ways.
-### Configure a Jenkins integration (recommended)
+### With a Jenkins server URL
-GitLab recommends this approach for Jenkins integrations because it is easier to configure
-than the [webhook integration](#configure-a-webhook).
+You should use this approach for Jenkins integrations if you can provide GitLab
+with your Jenkins server URL and authentication information.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Jenkins**.
1. Select the **Active** checkbox.
@@ -128,61 +132,62 @@ than the [webhook integration](#configure-a-webhook).
1. Enter the **Jenkins server URL**.
1. Optional. Clear the **Enable SSL verification** checkbox to disable [SSL verification](../user/project/integrations/index.md#manage-ssl-verification).
1. Enter the **Project name**.
-
The project name should be URL-friendly, where spaces are replaced with underscores. To ensure
the project name is valid, copy it from your browser's address bar while viewing the Jenkins
project.
-1. If your Jenkins server requires
- authentication, enter the **Username** and **Password**.
+1. If your Jenkins server requires authentication, enter the **Username** and **Password**.
1. Optional. Select **Test settings**.
1. Select **Save changes**.
-### Configure a webhook
+### With a webhook
-If you are unable to provide GitLab with your Jenkins server login, you can use this option
-to integrate GitLab and Jenkins.
+If you cannot [provide GitLab with your Jenkins server URL and authentication information](#with-a-jenkins-server-url), you can configure a webhook to integrate GitLab and Jenkins.
1. In the configuration of your Jenkins job, in the GitLab configuration section, select **Advanced**.
1. Under **Secret Token**, select **Generate**.
1. Copy the token, and save the job configuration.
-1. In GitLab, create a webhook for your project, enter the trigger URL
- (such as `https://JENKINS_URL/project/YOUR_JOB`) and paste the token in **Secret Token**.
+1. In GitLab:
+ - [Create a webhook for your project](../user/project/integrations/webhooks.md#configure-a-webhook-in-gitlab).
+ - Enter the trigger URL (such as `https://JENKINS_URL/project/YOUR_JOB`).
+ - Paste the token in **Secret Token**.
1. To test the webhook, select **Test**.
## Related topics
-- For a real use case, read the blog post
- [Continuous integration: From Jenkins to GitLab using Docker](https://about.gitlab.com/blog/2017/07/27/docker-my-precious/).
-- See the ['GitLab vs. Jenkins' comparison page](https://about.gitlab.com/devops-tools/jenkins-vs-gitlab/)
- for information on how moving to a single application for the entire software development
- lifecycle can decrease hours spent on maintaining toolchains by 10% or more.
+- [GitLab Jenkins Integration](https://about.gitlab.com/solutions/jenkins/)
+- [How to set up Jenkins on your local machine](../development/integrations/jenkins.md)
+- [How to migrate from Jenkins to GitLab CI/CD](../ci/migration/jenkins.md)
## Troubleshooting
### Error during GitLab configuration - "Connection failed. Please check your settings"
-If you get this error message while configuring GitLab, the following are possible causes:
+While configuring GitLab, you might get an error that states "Connection failed. Please check your settings".
+
+This issue has multiple possible causes and solutions:
-- GitLab is unable to reach your Jenkins instance at the address. If your GitLab instance is self-managed, try pinging the
- Jenkins instance at the domain provided on the GitLab instance.
-- The Jenkins instance is at a local address and is not included in the
- [GitLab installation's allowlist](../security/webhooks.md#allow-outbound-requests-to-certain-ip-addresses-and-domains).
-- The credentials for the Jenkins instance do not have sufficient access or are invalid.
-- The **Enable authentication for `/project` end-point** checkbox is not selected in your [Jenkins plugin configuration](#configure-the-jenkins-server).
+| Cause | Workaround |
+|------------------------------------------------------------------|-------------|
+| GitLab is unable to reach your Jenkins instance at the address. | If your GitLab instance is self-managed, ping the Jenkins instance at the domain provided on the GitLab instance. |
+| The Jenkins instance is at a local address and is not included in the [GitLab installation's allowlist](../security/webhooks.md#allow-outbound-requests-to-certain-ip-addresses-and-domains).| Add the instance to the GitLab installation's allowlist. |
+| The credentials for the Jenkins instance do not have sufficient access or are invalid.| Grant the credentials sufficient access or create valid credentials. |
+|The **Enable authentication for `/project` end-point** checkbox is not selected in your [Jenkins plugin configuration](#configure-the-jenkins-server)| Select the checkbox. |
### Error in merge requests - "Could not connect to the CI server"
-You might get the `Could not connect to the CI server` error if GitLab did not
-receive a build status update from Jenkins via the [Commit Status API](../api/commits.md#commit-status).
+You might get an error that states `Could not connect to the CI server` in a merge
+request if GitLab did not receive a build status update from Jenkins through the
+[Commit Status API](../api/commits.md#commit-status).
-This issue occurs when Jenkins is not properly
-configured or there is an error reporting the status via the API.
+This issue occurs when Jenkins is not properly configured or there is an error
+reporting the status through the API.
-To fix this issue, ensure you:
+To fix this issue:
1. [Configure the Jenkins server](#configure-the-jenkins-server) for GitLab API access.
-1. [Configure the Jenkins project](#configure-the-jenkins-project), including the
- 'Publish build status to GitLab' post-build action.
+1. [Configure the Jenkins project](#configure-the-jenkins-project), and make sure
+ that, if you create a freestyle project, you choose the "Publish build status to GitLab"
+ post-build action.
### Merge request event does not trigger a Jenkins pipeline
diff --git a/doc/integration/jira/configure.md b/doc/integration/jira/configure.md
index 8ef7b7bc442..dd43c6417e8 100644
--- a/doc/integration/jira/configure.md
+++ b/doc/integration/jira/configure.md
@@ -26,7 +26,7 @@ You can configure these settings at the [group level](../../administration/setti
To configure your project settings in GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Jira**.
1. Under **Enable integration**, select the **Active** checkbox.
@@ -89,7 +89,7 @@ To copy the API token, select **Copy**.
To migrate from Jira Server to Jira Cloud in GitLab and maintain your Jira integration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Jira**.
1. In **Web URL**, enter the new Jira site URL (for example, `https://myjirasite.atlassian.net`).
diff --git a/doc/integration/jira/connect-app.md b/doc/integration/jira/connect-app.md
index 985f67fdf98..3fa2a58b787 100644
--- a/doc/integration/jira/connect-app.md
+++ b/doc/integration/jira/connect-app.md
@@ -100,7 +100,7 @@ You must enable OAuth authentication to:
To create an OAuth application:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Applications**.
1. Select **New application**.
@@ -139,10 +139,11 @@ To create branches from Jira Cloud, [install the app manually](#install-the-gitl
- The instance must be on GitLab version 15.7 or later.
- You must set up [OAuth authentication](#set-up-oauth-authentication-for-self-managed-instances).
- Your network must allow inbound and outbound connections between GitLab and Jira. For self-managed instances that are behind a
- firewall and cannot be directly accessed from the internet, you can:
+ firewall and cannot be directly accessed from the internet:
- Open your firewall and only allow inbound traffic from [Atlassian IP addresses](https://support.atlassian.com/organization-administration/docs/ip-addresses-and-domains-for-atlassian-cloud-products/#Outgoing-Connections).
- Set up an internet-facing reverse proxy in front of your self-managed instance. To secure this proxy further, only allow inbound
traffic from [Atlassian IP addresses](https://support.atlassian.com/organization-administration/docs/ip-addresses-and-domains-for-atlassian-cloud-products/#Outgoing-Connections).
+ - Add [GitLab IP addresses](../../user/gitlab_com/index.md#ip-range) to the allowlist of your firewall.
### Set up your instance
@@ -150,7 +151,7 @@ To create branches from Jira Cloud, [install the app manually](#install-the-gitl
To set up your self-managed instance for the GitLab for Jira Cloud app in GitLab 15.7 and later:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **GitLab for Jira App**.
@@ -245,7 +246,7 @@ You might want to use a proxy if you're managing multiple GitLab instances but o
To configure your GitLab instance to serve as a proxy:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **GitLab for Jira App**.
@@ -315,7 +316,7 @@ To resolve this issue, disable the **Jira Connect Proxy URL** setting.
- In GitLab 15.8 and later:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **GitLab for Jira App**.
diff --git a/doc/integration/jira/dvcs/troubleshooting.md b/doc/integration/jira/dvcs/troubleshooting.md
index 801bdab4139..570237779b4 100644
--- a/doc/integration/jira/dvcs/troubleshooting.md
+++ b/doc/integration/jira/dvcs/troubleshooting.md
@@ -132,12 +132,12 @@ Failed to execute request [https://gitlab.com/api/v4/projects/:id/merge_requests
{"message":"403 Forbidden"}
```
-If you find a `{"message":"403 Forbidden"}` error, it is possible that this specific project has some [GitLab features disabled](../../../user/project/settings/index.md#configure-project-visibility-features-and-permissions).
+If you find a `{"message":"403 Forbidden"}` error, it is possible that this specific project has some [GitLab features disabled](../../../user/project/settings/index.md#configure-project-features-and-permissions).
In the example above, the merge requests feature is disabled.
To resolve the issue, enable the relevant feature:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Use the toggles to enable the features as needed.
@@ -146,7 +146,7 @@ To resolve the issue, enable the relevant feature:
To find webhook logs in a DVCS-linked project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Settings > Webhooks**.
1. Scroll down to **Project Hooks**.
1. Next to the log that points to your Jira instance, select **Edit**.
diff --git a/doc/integration/jira/index.md b/doc/integration/jira/index.md
index c7a60ec2ff8..a723ae2a249 100644
--- a/doc/integration/jira/index.md
+++ b/doc/integration/jira/index.md
@@ -58,7 +58,6 @@ The [Jira issue integration](configure.md) posts GitLab data in the form of comm
The GitLab for Jira Cloud app and Jira DVCS connector share this data through the [Jira development panel](development_panel.md).
This method provides more fine-grained access control because access can be restricted to certain user groups or roles.
-## Third-party Jira integrations
+## Related topics
-Developers have built several third-party Jira integrations for GitLab that are
-listed on the [Atlassian Marketplace](https://marketplace.atlassian.com/search?product=jira&query=gitlab).
+- [Third-party Jira integrations](https://marketplace.atlassian.com/search?product=jira&query=gitlab)
diff --git a/doc/integration/jira/issues.md b/doc/integration/jira/issues.md
index 06d64d19db5..ae4b726327c 100644
--- a/doc/integration/jira/issues.md
+++ b/doc/integration/jira/issues.md
@@ -52,7 +52,7 @@ You can [disable comments](#disable-comments-on-jira-issues) on issues.
With this integration, you can prevent merge requests from being merged if they do not refer to a Jira issue.
To enable this feature:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. In the **Merge checks** section, select **Require an associated issue from Jira**.
1. Select **Save**.
@@ -76,7 +76,7 @@ When you don't configure custom rules, the [default behavior](https://gitlab.com
To define a regex pattern for Jira issue keys:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Jira**.
1. Go to the **Jira issue matching** section.
@@ -92,7 +92,7 @@ and you've set a `JIRA#` prefix, GitLab matches `JIRA#ALPHA-1` rather than `ALPH
To define a prefix for Jira issue keys:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Jira**.
1. Go to the **Jira issue matching** section.
@@ -136,7 +136,7 @@ provided your GitLab administrator [has configured the integration](configure.md
To view Jira issues:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Plan > Jira issues**.
The issues are sorted by **Created date** by default, with the most recently created issues listed at the top.
diff --git a/doc/integration/jira/troubleshooting.md b/doc/integration/jira/troubleshooting.md
index 70c6a306299..c2b79f116eb 100644
--- a/doc/integration/jira/troubleshooting.md
+++ b/doc/integration/jira/troubleshooting.md
@@ -55,7 +55,7 @@ To change all Jira projects to use instance-level integration settings:
```ruby
jira_integration_instance_id = Integrations::Jira.find_by(instance: true).id
- Integrations::Jira.where(active: true, instance: false, template: false, inherit_from_id: nil).find_each do |integration|
+ Integrations::Jira.where(active: true, instance: false, inherit_from_id: nil).find_each do |integration|
integration.update_attribute(:inherit_from_id, jira_integration_instance_id)
end
```
diff --git a/doc/integration/kerberos.md b/doc/integration/kerberos.md
index c7dbc5caf35..9139c374780 100644
--- a/doc/integration/kerberos.md
+++ b/doc/integration/kerberos.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
---
@@ -106,7 +106,7 @@ set up GitLab to create a new account when a Kerberos user tries to sign in.
If you're an administrator, you can link a Kerberos account to an
existing GitLab account. To do so:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. Select a user, then select the **Identities** tab.
@@ -148,7 +148,7 @@ With that information at hand:
```
1. As an administrator, you can confirm the new, blocked account:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users** and review the **Blocked** tab.
1. You can enable the user.
diff --git a/doc/integration/mattermost/index.md b/doc/integration/mattermost/index.md
index fea25a398ba..389568ccf6d 100644
--- a/doc/integration/mattermost/index.md
+++ b/doc/integration/mattermost/index.md
@@ -224,7 +224,7 @@ sudo chown mattermost:mattermost /var/opt/gitlab/mattermost/config.json
sudo gitlab-ctl start mattermost
```
-## Mattermost Command Line Tools (CLI)
+## Mattermost command-line tool (CLI)
[`mmctl`](https://docs.mattermost.com/manage/mmctl-command-line-tool.html) is a CLI tool for the Mattermost server which is installed locally and uses the Mattermost API, but may also be used remotely. You must configure Mattermost either for local connections or authenticate as an administrator with local login credentials (not through GitLab SSO). The executable is located at `/opt/gitlab/embedded/bin/mmctl`.
@@ -308,42 +308,6 @@ This setting can also be configured in `/var/opt/gitlab/mattermost/config.json`.
## Upgrading GitLab Mattermost
-Below is a list of Mattermost versions for GitLab 14.0 and later:
-
-| GitLab version | Mattermost version |
-|:---------------|:-------------------|
-| 16.2 | 7.10 |
-| 16.1 | 7.10 |
-| 16.0 | 7.10 |
-| 15.11 | 7.9 |
-| 15.10 | 7.8 |
-| 15.9 | 7.7 |
-| 15.8 | 7.5 |
-| 15.7 | 7.5 |
-| 15.6 | 7.4 |
-| 15.5 | 7.3 |
-| 15.4 | 7.2 |
-| 15.3 | 7.1 |
-| 15.2 | 7.0 |
-| 15.1 | 6.7 |
-| 15.0 | 6.6 |
-| 14.10 | 6.5 |
-| 14.9 | 6.4 |
-| 14.8 | 6.3 |
-| 14.7 | 6.2 |
-| 14.6 | 6.1 |
-| 14.5 | 5.39 |
-| 14.4 | 5.39 |
-| 14.3 | 5.38 |
-| 14.2 | 5.37 |
-| 14.1 | 5.36 |
-| 14.0 | 5.35 |
-
-- GitLab 14.5 remained on Mattermost 5.39.
-- GitLab 14.6 updates to Mattermost 6.1 instead of 6.0.
-- GitLab 15.8 remained on Mattermost 7.5.
-- GitLab 16.1 and 16.2 remained on Mattermost 7.10.
-
NOTE:
When upgrading the Mattermost version, it is essential to check the
[Important Upgrade Notes](https://docs.mattermost.com/administration/important-upgrade-notes.html)
@@ -368,7 +332,38 @@ If this is not the case, there are two options:
For a complete list of upgrade notices and special considerations for older versions, see the [Mattermost documentation](https://docs.mattermost.com/administration/important-upgrade-notes.html).
-## Upgrading GitLab Mattermost to 14.6
+### GitLab Mattermost versions shipped with the Linux package
+
+Below is a list of Mattermost version changes for GitLab 14.0 and later:
+
+| GitLab version | Mattermost version | Notes |
+| :------------- | :----------------- | ---------------------------------------------------------------------------------------- |
+| 16.4 | 8.1 | |
+| 16.3 | 8.0 | |
+| 16.0 | 7.10 | |
+| 15.11 | 7.9 | |
+| 15.10 | 7.8 | |
+| 15.9 | 7.7 | |
+| 15.7 | 7.5 | |
+| 15.6 | 7.4 | |
+| 15.5 | 7.3 | |
+| 15.4 | 7.2 | |
+| 15.3 | 7.1 | |
+| 15.2 | 7.0 | |
+| 15.1 | 6.7 | |
+| 15.0 | 6.6 | |
+| 14.10 | 6.5 | |
+| 14.9 | 6.4 | |
+| 14.8 | 6.3 | |
+| 14.7 | 6.2 | |
+| 14.6 | 6.1 | Updates to 6.1 instead of 6.0. [See upgrade notes](#upgrading-gitlab-mattermost-to-146). |
+| 14.4 | 5.39 | |
+| 14.3 | 5.38 | |
+| 14.2 | 5.37 | |
+| 14.1 | 5.36 | |
+| 14.0 | 5.35 | |
+
+### Upgrading GitLab Mattermost to 14.6
GitLab 14.6 ships with Mattermost 6.1 including potentially long running database migrations for Mattermost 6.0. For information about upgrading and for ways to reduce the downtime caused by those migrations, read the [Important Upgrade Notes](https://docs.mattermost.com/administration/important-upgrade-notes.html) for both versions. If you need to perform any manual migrations, [connect to the bundled PostgreSQL database](#connecting-to-the-bundled-postgresql-database).
@@ -409,4 +404,3 @@ For help and support around your GitLab Mattermost deployment, see:
- [Troubleshooting Mattermost issues](https://docs.mattermost.com/install/troubleshooting.html).
- [Mattermost GitLab Issues Support Handbook](https://docs.mattermost.com/process/support.html?highlight=omnibus#gitlab-issues).
-- [GitLab Mattermost issue tracker](https://gitlab.com/gitlab-org/gitlab-mattermost/-/issues) for verified bugs with repro steps.
diff --git a/doc/integration/oauth2_generic.md b/doc/integration/oauth2_generic.md
index 00a50489793..5595a45fe3e 100644
--- a/doc/integration/oauth2_generic.md
+++ b/doc/integration/oauth2_generic.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md
index fc849adc2b3..af525cc8770 100644
--- a/doc/integration/oauth_provider.md
+++ b/doc/integration/oauth_provider.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -75,7 +75,7 @@ To create a new application for a group:
To create an application for your GitLab instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Applications**.
1. Select **New application**.
@@ -85,6 +85,8 @@ The user authorization step is automatically skipped for this application.
## View all authorized applications
+> `k8s_proxy` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/422408) in GitLab 16.4 [with a flag](../administration/feature_flags.md) named `k8s_proxy_pat`. Enabled by default.
+
To see all the application you've authorized with your GitLab credentials:
1. On the left sidebar, select your avatar.
@@ -95,7 +97,7 @@ The GitLab OAuth 2 applications support scopes, which allow application to perfo
different actions. See the following table for all available scopes.
| Scope | Description |
-| ------------------ | ----------- |
+|--------------------| ----------- |
| `api` | Grants complete read/write access to the API, including all groups and projects, the container registry, and the package registry. |
| `read_user` | Grants read-only access to the authenticated user's profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users. |
| `read_api` | Grants read access to the API, including all groups and projects, the container registry, and the package registry. |
@@ -108,6 +110,7 @@ different actions. See the following table for all available scopes.
| `profile` | Grants read-only access to the user's profile data using [OpenID Connect](openid_connect_provider.md). |
| `email` | Grants read-only access to the user's primary email address using [OpenID Connect](openid_connect_provider.md). |
| `create_runner` | Grants permission to create runners. |
+| `k8s_proxy` | Grants permission to perform Kubernetes API calls using the agent for Kubernetes. |
At any time you can revoke any access by selecting **Revoke**.
@@ -115,16 +118,27 @@ At any time you can revoke any access by selecting **Revoke**.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21745) in GitLab 14.3, with the ability to opt out.
> - Ability to opt-out of expiring access token [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/340848) in GitLab 15.0.
+> - Database validation on `expires_in` [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112765) in GitLab 15.10. If your GitLab instance has any remaining OAuth Access Tokens without `expires_in` set when you are upgrading to 15.10 or later, the database migration will raise an error. For workaround instructions, see the [GitLab 15.10.0 upgrade documentation](../update/versions/gitlab_15_changes.md#15100).
WARNING:
The ability to opt out of expiring access tokens was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/340848)
in GitLab 14.3 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/340848) in 15.0. All
existing integrations must be updated to support access token refresh.
-Access tokens expire after two hours. Integrations that use access tokens must generate new ones at least every
-two hours.
+Access tokens expire after two hours. Integrations that use access tokens must
+generate new ones using the `refresh_token` attribute. Refresh tokens may be
+used even after the `access_token` itself expires.
+See [OAuth 2.0 token documentation](../api/oauth2.md) for more detailed
+information on how to refresh expired access tokens.
+
+This expiration setting is set in the GitLab codebase using the
+`access_token_expires_in` configuration from
+[Doorkeeper](https://github.com/doorkeeper-gem/doorkeeper), the library that
+provides GitLab as an OAuth provider functionality. The expiration setting is
+not configurable.
-When applications are deleted, all grants and tokens associated with the application are also deleted.
+When applications are deleted, all grants and tokens associated with the
+application are also deleted.
## Hashed OAuth application secrets
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 30aa913ab8c..6add3534593 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -257,7 +257,7 @@ By default, sign-in is enabled for all the OAuth providers configured in `config
To enable or disable an OmniAuth provider:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Sign-in restrictions**.
diff --git a/doc/integration/openid_connect_provider.md b/doc/integration/openid_connect_provider.md
index ec3c2d53495..c9c208bf1c1 100644
--- a/doc/integration/openid_connect_provider.md
+++ b/doc/integration/openid_connect_provider.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -48,22 +48,22 @@ Similar URLs can be used for other GitLab instances.
The following user information is shared with clients:
-| Claim | Type | Description |
-|:---------------------|:----------|:------------|
-| `sub` | `string` | The ID of the user |
-| `auth_time` | `integer` | The timestamp for the user's last authentication |
-| `name` | `string` | The user's full name |
-| `nickname` | `string` | The user's GitLab username |
-| `preferred_username` | `string` | The user's GitLab username |
-| `email` | `string` | The user's email address<br>This is the user's *primary* email address if the application has access to the `email` claim and the user's *public* email address otherwise |
-| `email_verified` | `boolean` | Whether the user's email address was verified |
-| `website` | `string` | URL for the user's website |
-| `profile` | `string` | URL for the user's GitLab profile |
-| `picture` | `string` | URL for the user's GitLab avatar |
-| `groups` | `array` | Paths for the groups the user is a member of, either directly or through an ancestor group. |
-| `groups_direct` | `array` | Paths for the groups the user is a direct member of. |
-| `https://gitlab.org/claims/groups/owner` | `array` | Names of the groups the user is a direct member of with Owner role |
-| `https://gitlab.org/claims/groups/maintainer` | `array` | Names of the groups the user is a direct member of with Maintainer role |
-| `https://gitlab.org/claims/groups/developer` | `array` | Names of the groups the user is a direct member of with Developer role |
-
-The claims `sub`, `sub_legacy`, `email`, `email_verified` and `groups_direct` are included in the ID token. All other claims are available from the `/oauth/userinfo` endpoint used by OIDC clients.
+| Claim | Type | Description | Included in ID Token | Included in `userinfo` endpoint |
+|:---------------------|:----------|:------------|:---------------------|:------------------------------|
+| `sub` | `string` | The ID of the user | **{check-circle}** Yes | **{check-circle}** Yes |
+| `auth_time` | `integer` | The timestamp for the user's last authentication | **{check-circle}** Yes | **{dotted-circle}** No |
+| `name` | `string` | The user's full name | **{check-circle}** Yes | **{check-circle}** Yes |
+| `nickname` | `string` | The user's GitLab username | **{check-circle}** Yes| **{check-circle}** Yes |
+| `preferred_username` | `string` | The user's GitLab username | **{check-circle}** Yes | **{check-circle}** Yes |
+| `email` | `string` | The user's email address<br>This is the user's *primary* email address | **{check-circle}** Yes | **{check-circle}** Yes |
+| `email_verified` | `boolean` | Whether the user's email address was verified | **{check-circle}** Yes | **{check-circle}** Yes |
+| `website` | `string` | URL for the user's website | **{check-circle}** Yes | **{check-circle}** Yes |
+| `profile` | `string` | URL for the user's GitLab profile | **{check-circle}** Yes | **{check-circle}** Yes|
+| `picture` | `string` | URL for the user's GitLab avatar | **{check-circle}** Yes| **{check-circle}** Yes |
+| `groups` | `array` | Paths for the groups the user is a member of, either directly or through an ancestor group. | **{dotted-circle}** No | **{check-circle}** Yes |
+| `groups_direct` | `array` | Paths for the groups the user is a direct member of. | **{check-circle}** Yes | **{dotted-circle}** No |
+| `https://gitlab.org/claims/groups/owner` | `array` | Names of the groups the user is a direct member of with Owner role | **{dotted-circle}** No | **{check-circle}** Yes |
+| `https://gitlab.org/claims/groups/maintainer` | `array` | Names of the groups the user is a direct member of with Maintainer role | **{dotted-circle}** No | **{check-circle}** Yes |
+| `https://gitlab.org/claims/groups/developer` | `array` | Names of the groups the user is a direct member of with Developer role | **{dotted-circle}** No | **{check-circle}** Yes |
+
+The claims `email` and `email_verified` are only added if the application has access to the `email` claim and the user's **public** email address, otherwise they are not included. All other claims are available from the `/oauth/userinfo` endpoint used by OIDC clients.
diff --git a/doc/integration/recaptcha.md b/doc/integration/recaptcha.md
index 9e44efc3e60..cd94cdfa43c 100644
--- a/doc/integration/recaptcha.md
+++ b/doc/integration/recaptcha.md
@@ -17,7 +17,7 @@ To use reCAPTCHA, first create a site and private key.
1. Go to the [Google reCAPTCHA page](https://www.google.com/recaptcha/admin).
1. To get reCAPTCHA v2 keys, fill in the form and select **Submit**.
1. Sign in to your GitLab server as an administrator.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Reporting**.
1. Expand **Spam and Anti-bot Protection**.
diff --git a/doc/integration/salesforce.md b/doc/integration/salesforce.md
index 3a90a4570e6..a1df213d9dc 100644
--- a/doc/integration/salesforce.md
+++ b/doc/integration/salesforce.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/integration/saml.md b/doc/integration/saml.md
index e4ad8c33aa1..7af1dbeeff8 100644
--- a/doc/integration/saml.md
+++ b/doc/integration/saml.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
@@ -116,7 +116,7 @@ For more information on:
omniauth:
enabled: true
allowSingleSignOn: ['saml']
- blockAutoCreatedUsers: true
+ blockAutoCreatedUsers: false
```
1. Optional. You can automatically link SAML users with existing GitLab users if their
diff --git a/doc/integration/shibboleth.md b/doc/integration/shibboleth.md
index 859b5682879..c392864e346 100644
--- a/doc/integration/shibboleth.md
+++ b/doc/integration/shibboleth.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
diff --git a/doc/integration/sourcegraph.md b/doc/integration/sourcegraph.md
index 076b7f3937e..729dbade1d1 100644
--- a/doc/integration/sourcegraph.md
+++ b/doc/integration/sourcegraph.md
@@ -49,7 +49,7 @@ You can skip this step if you already have your GitLab repositories searchable i
### Configure your GitLab instance with Sourcegraph
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Sourcegraph** configuration section.
diff --git a/doc/integration/twitter.md b/doc/integration/twitter.md
index ed83db0d4eb..6491df1ec56 100644
--- a/doc/integration/twitter.md
+++ b/doc/integration/twitter.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/operations/error_tracking.md b/doc/operations/error_tracking.md
index 36c5ed03197..82982a03016 100644
--- a/doc/operations/error_tracking.md
+++ b/doc/operations/error_tracking.md
@@ -1,5 +1,5 @@
---
-stage: Analytics
+stage: Analyze
group: Observability
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -8,6 +8,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Error Tracking allows developers to discover and view errors generated by their application. Because error information is surfaced where the code is developed, this increases efficiency and awareness. Users can choose between [GitLab Integrated error tracking](#integrated-error-tracking) and [Sentry based](#sentry-error-tracking) backends.
+To leave feedback about Error Tracking bugs or functionality, please comment in the [feedback issue](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2362) or open a [new issue](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/new).
+
## How error tracking works
For error tracking to work, you need:
@@ -172,7 +174,7 @@ To enable the Sentry integration:
`event:read`, and
`event:write` (for resolving events).
1. In GitLab, enable and configure Error Tracking:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor > Error Tracking**.
1. Under **Enable error tracking**, select the **Active** checkbox.
1. Under **Error tracking backend**, select **Sentry**.
@@ -206,3 +208,15 @@ To rectify the following error, specify the deprecated DSN in **Sentry.io > Proj
```plaintext
ERROR: Sentry failure builds=0 error=raven: dsn missing private key
```
+
+## Troubleshooting
+
+When working with Error Tracking, you might encounter the following issues.
+
+### Error `Connection failed. Check auth token and try again`
+
+If the Monitor feature is disabled in the [project settings](../user/project/settings/index.md#configure-project-features-and-permissions),
+you might see an error when you try to [enable Sentry integration for a project](#enable-sentry-integration-for-a-project).
+The resulting request to `/project/path/-/error_tracking/projects.json?api_host=https:%2F%2Fsentry.example.com%2F&token=<token>` returns a 404 status.
+
+To fix this issue, enable the Monitor feature for the project.
diff --git a/doc/operations/feature_flags.md b/doc/operations/feature_flags.md
index 21470f66750..5fd497a79e1 100644
--- a/doc/operations/feature_flags.md
+++ b/doc/operations/feature_flags.md
@@ -39,7 +39,7 @@ with GitLab, so it's up to developers to use a compatible client library and
To create and enable a feature flag:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Feature flags**.
1. Select **New feature flag**.
1. Enter a name that starts with a letter and contains only lowercase letters, digits, underscores (`_`),
@@ -181,7 +181,7 @@ For example:
To create a user list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Feature flags**.
1. Select **View user lists**
1. Select **New user list**.
@@ -197,7 +197,7 @@ When viewing a list, you can rename it by selecting **Edit** (**{pencil}**).
To add users to a user list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Feature flags**.
1. Select **Edit** (**{pencil}**) next to the list you want to add users to.
1. Select **Add Users**.
@@ -211,7 +211,7 @@ To add users to a user list:
To remove users from a user list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Feature flags**.
1. Select **Edit** (**{pencil}**) next to the list you want to change.
1. Select **Remove** (**{remove}**) next to the ID you want to remove.
@@ -224,7 +224,7 @@ To remove the feature flag from the code during cleanup, find any project refere
To search for code references of a feature flag:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Feature flags**.
1. Edit the feature flag you want to remove.
1. Select **More actions** (**{ellipsis_v}**).
@@ -235,7 +235,7 @@ To search for code references of a feature flag:
In [GitLab 13.0 and earlier](https://gitlab.com/gitlab-org/gitlab/-/issues/8621),
to disable a feature flag for a specific environment:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Feature flags**.
1. For the feature flag you want to disable, select **Edit** (**{pencil}**).
1. To disable the flag:
@@ -250,7 +250,7 @@ to disable a feature flag for a specific environment:
To disable a feature flag for all environments:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Feature flags**.
1. For the feature flag you want to disable, slide the Status toggle to **Disabled**.
@@ -265,7 +265,7 @@ Then prepare your application with a client library.
To get the access credentials that your application needs to communicate with GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Feature flags**.
1. Select **Configure** to view the following:
- **API URL**: URL where the client (application) connects to get a list of feature flags.
diff --git a/doc/operations/img/tracing_list_v16_3.png b/doc/operations/img/tracing_list_v16_3.png
new file mode 100644
index 00000000000..93c336d4bd7
--- /dev/null
+++ b/doc/operations/img/tracing_list_v16_3.png
Binary files differ
diff --git a/doc/operations/incident_management/alerts.md b/doc/operations/incident_management/alerts.md
index e558462cad7..f92739580bd 100644
--- a/doc/operations/incident_management/alerts.md
+++ b/doc/operations/incident_management/alerts.md
@@ -179,7 +179,7 @@ To assign an alert:
1. Display the list of current alerts:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Alerts**.
1. Select your desired alert to display its details.
@@ -219,7 +219,7 @@ Prerequisites:
To configure the actions:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor**.
1. Expand the **Alerts** section, then select the **Alert settings** tab.
1. Select the **Create an incident** checkbox.
diff --git a/doc/operations/incident_management/escalation_policies.md b/doc/operations/incident_management/escalation_policies.md
index 0cbbf42372e..604e223cf55 100644
--- a/doc/operations/incident_management/escalation_policies.md
+++ b/doc/operations/incident_management/escalation_policies.md
@@ -22,7 +22,7 @@ Prerequisite:
To create an escalation policy:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Escalation Policies**.
1. Select **Add an escalation policy**.
1. Enter the policy's name and description, and
@@ -46,7 +46,7 @@ the paged users is created on the alert.
To update an escalation policy:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Escalation Policies**.
1. Select **Edit escalation policy** (**{pencil}**).
1. Edit the information.
@@ -56,7 +56,7 @@ To update an escalation policy:
To delete an escalation policy:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Escalation Policies**.
1. Select **Delete escalation policy** (**{remove}**).
1. On the confirmation dialog, select **Delete escalation policy**.
diff --git a/doc/operations/incident_management/incident_timeline_events.md b/doc/operations/incident_management/incident_timeline_events.md
index 0c47ff46bc9..f5322e0a7cc 100644
--- a/doc/operations/incident_management/incident_timeline_events.md
+++ b/doc/operations/incident_management/incident_timeline_events.md
@@ -23,7 +23,7 @@ They are grouped with dates and are listed in ascending order of the time when t
To view the event timeline of an incident:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
1. Select an incident.
1. Select the **Timeline** tab.
@@ -42,7 +42,7 @@ Prerequisites:
To create a timeline event:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
1. Select an incident.
1. Select the **Timeline** tab.
@@ -66,7 +66,7 @@ Prerequisites:
To create a timeline event from a comment on the incident:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
1. Select an incident.
1. Create a comment or choose an existing comment.
@@ -83,7 +83,7 @@ of an incident.
![Incident timeline event for severity change](img/timeline_event_for_severity_change_v15_6.png)
-### When labels change (Experiment)
+### When labels change **(EXPERIMENT)**
> [Introduced]([issue-link](https://gitlab.com/gitlab-org/gitlab/-/issues/365489)) in GitLab 15.3 [with a flag](../../administration/feature_flags.md) named `incident_timeline_events_from_labels`. Disabled by default.
@@ -106,7 +106,7 @@ Prerequisites:
To delete a timeline event:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
1. Select an incident.
1. Select the **Timeline** tab.
diff --git a/doc/operations/incident_management/incidents.md b/doc/operations/incident_management/incidents.md
index 4aae8809620..43df69a3b39 100644
--- a/doc/operations/incident_management/incidents.md
+++ b/doc/operations/incident_management/incidents.md
@@ -154,7 +154,7 @@ Prerequisites:
To configure the timer:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor**.
1. Expand the **Incidents** section, then select the **Incident settings** tab.
1. Select **Activate "time to SLA" countdown timer**.
diff --git a/doc/operations/incident_management/integrations.md b/doc/operations/incident_management/integrations.md
index 5eed1921168..8691d78c4c9 100644
--- a/doc/operations/incident_management/integrations.md
+++ b/doc/operations/incident_management/integrations.md
@@ -101,7 +101,7 @@ parameters. All fields are optional. If the incoming alert does not contain a va
| `monitoring_tool` | String | The name of the associated monitoring tool. |
| `hosts` | String or Array | One or more hosts, as to where this incident occurred. |
| `severity` | String | The severity of the alert. Case-insensitive. Can be one of: `critical`, `high`, `medium`, `low`, `info`, `unknown`. Defaults to `critical` if missing or value is not in this list. |
-| `fingerprint` | String or Array | The unique identifier of the alert. This can be used to group occurrences of the same alert. |
+| `fingerprint` | String or Array | The unique identifier of the alert. This can be used to group occurrences of the same alert. When the `generic_alert_fingerprinting` feature is enabled, the fingerprint is generated automatically based on the payload (excluding the `start_time`, `end_time`, and `hosts` parameters). |
| `gitlab_environment_name` | String | 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). |
You can also add custom fields to the alert's payload. The values of extra
@@ -144,7 +144,7 @@ Prerequisites:
- You must have at least the Maintainer role for the project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor**.
1. Expand the **Alerts** section, and select **Add new integration**.
1. From the **Select integration type** dropdown list, select **Prometheus**.
@@ -418,6 +418,11 @@ receives a payload with the end time of the alert set. For HTTP Endpoints
without [custom mappings](#map-fields-in-custom-alerts), the expected
field is `end_time`. With custom mappings, you can select the expected field.
+GitLab determines which alert to resolve based on the `fingerprint` value that can be provided as
+part of the payload.
+For more information on alert properties and mappings, see
+[Customize the alert payload outside of GitLab](#customize-the-alert-payload-outside-of-gitlab).
+
You can also configure the associated [incident to be closed automatically](../incident_management/manage_incidents.md#automatically-close-incidents-via-recovery-alerts) when the alert resolves.
## Link to your Opsgenie Alerts **(PREMIUM ALL)**
diff --git a/doc/operations/incident_management/linked_resources.md b/doc/operations/incident_management/linked_resources.md
index 15317f61057..57fcb31e3ba 100644
--- a/doc/operations/incident_management/linked_resources.md
+++ b/doc/operations/incident_management/linked_resources.md
@@ -27,7 +27,7 @@ Linked resources for an incident are listed under the **Summary** tab.
To view the linked resources of an incident:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
1. Select an incident.
@@ -41,7 +41,7 @@ Prerequisites:
To add a linked resource:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
1. Select an incident.
1. In the **Linked resources** section, select the plus icon (**{plus-square}**).
@@ -92,7 +92,7 @@ Prerequisites:
To remove a linked resource:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
1. Select an incident.
1. In the **Linked resources** section, select **Remove** (**{close}**).
diff --git a/doc/operations/incident_management/manage_incidents.md b/doc/operations/incident_management/manage_incidents.md
index f88d9b51891..28c4adec250 100644
--- a/doc/operations/incident_management/manage_incidents.md
+++ b/doc/operations/incident_management/manage_incidents.md
@@ -24,7 +24,7 @@ Prerequisites:
To create an incident from the incidents list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
1. Select **Create incident**.
@@ -38,7 +38,7 @@ Prerequisites:
To create an incident from the issues list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, and select **New issue**.
1. From the **Type** dropdown list, select **Incident**. Only fields relevant to
incidents are available on the page.
@@ -57,7 +57,7 @@ Prerequisites:
To create an incident from an alert:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Alerts**.
1. Select your desired alert.
1. Select **Create incident**.
@@ -88,7 +88,7 @@ Prerequisites:
To set up a webhook with PagerDuty:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor**
1. Expand **Incidents**.
1. Select the **PagerDuty integration** tab.
@@ -104,7 +104,7 @@ check if a GitLab incident is created from the incident.
To view the [incidents list](incidents.md#incidents-list):
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > Incidents**.
To view an incident's [details page](incidents.md#incident-details), select it from the list.
@@ -239,7 +239,7 @@ Prerequisites:
To configure the setting:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor**.
1. Expand the **Incidents** section.
1. Select the **Automatically close associated incident** checkbox.
diff --git a/doc/operations/incident_management/oncall_schedules.md b/doc/operations/incident_management/oncall_schedules.md
index 808dc30581d..255cc79b3ce 100644
--- a/doc/operations/incident_management/oncall_schedules.md
+++ b/doc/operations/incident_management/oncall_schedules.md
@@ -28,7 +28,7 @@ Prerequisite:
To create an on-call schedule:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > On-call Schedules**.
1. Select **Add a schedule**.
1. Enter the schedule's name and description and select a time zone.
@@ -43,7 +43,7 @@ create [rotations](#rotations) for your schedule.
To update a schedule:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > On-call Schedules**.
1. Select **Edit schedule** (**{pencil}**).
1. Edit the information.
@@ -56,7 +56,7 @@ interval (if one is set) to the corresponding times in the new time zone.
To delete a schedule:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > On-call Schedules**.
1. Select **Delete escalation policy** (**{remove}**).
1. On the confirmation dialog, select **Delete schedule**.
@@ -67,7 +67,7 @@ Add rotations to an existing schedule to put your team members on-call.
To create a rotation:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > On-call Schedules**.
1. Select the **Add a rotation** link.
1. Enter the following information:
@@ -85,7 +85,7 @@ To create a rotation:
To edit a rotation:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > On-call Schedules**.
1. In the **Rotations** section, select **Edit rotation** (**{pencil}**).
1. Edit the information.
@@ -95,7 +95,7 @@ To edit a rotation:
To delete a rotation:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Monitor > On-call Schedules**.
1. In the **Rotations** section, select **Delete rotation** (**{remove}**).
1. On the confirmation dialog, select **Delete rotation**.
diff --git a/doc/operations/incident_management/paging.md b/doc/operations/incident_management/paging.md
index 05cc8c8e221..845c17d974a 100644
--- a/doc/operations/incident_management/paging.md
+++ b/doc/operations/incident_management/paging.md
@@ -26,7 +26,7 @@ Email notifications are available in projects for triggered alerts. Project
members with the **Owner** or **Maintainer** roles have the option to receive
a single email notification for new alerts.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor**.
1. Expand **Alerts**.
1. On the **Alert settings** tab, select the
diff --git a/doc/operations/incident_management/slack.md b/doc/operations/incident_management/slack.md
index 82d5d8b3150..100aaa0d9bc 100644
--- a/doc/operations/incident_management/slack.md
+++ b/doc/operations/incident_management/slack.md
@@ -4,7 +4,7 @@ group: Respond
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Incident management for Slack (Beta) **(FREE SAAS)**
+# Incident management for Slack **(FREE SAAS BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344856) in GitLab 15.7 [with a flag](../../administration/feature_flags.md) named `incident_declare_slash_command`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/378072) in GitLab 15.10 in [Beta](../../policy/experiment-beta-support.md#beta).
diff --git a/doc/operations/incident_management/status_page.md b/doc/operations/incident_management/status_page.md
index 374571d225e..682b2ffd705 100644
--- a/doc/operations/incident_management/status_page.md
+++ b/doc/operations/incident_management/status_page.md
@@ -45,7 +45,7 @@ Prerequisite:
To provide GitLab with the AWS account information needed to push content to your Status Page:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor**.
1. Expand **Status page**.
1. Select the **Active** checkbox.
@@ -96,7 +96,7 @@ the issue can potentially [publish comments to your GitLab Status Page](#publish
After creating the CI/CD variables, configure the Project you want to use for
Incident issues:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Monitor**.
1. Expand **Status page**.
1. Fill in your cloud provider's credentials and make sure to select the **Active** checkbox.
diff --git a/doc/operations/metrics/alerts.md b/doc/operations/metrics/alerts.md
deleted file mode 100644
index a5f580ac503..00000000000
--- a/doc/operations/metrics/alerts.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../index.md'
----
-
-# Set up alerts for Prometheus metrics (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/default.md b/doc/operations/metrics/dashboards/default.md
deleted file mode 100644
index 3eec1272307..00000000000
--- a/doc/operations/metrics/dashboards/default.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# GitLab-defined metrics dashboards (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/develop.md b/doc/operations/metrics/dashboards/develop.md
deleted file mode 100644
index c6d4721863a..00000000000
--- a/doc/operations/metrics/dashboards/develop.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# Developing templates for custom dashboards (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/index.md b/doc/operations/metrics/dashboards/index.md
deleted file mode 100644
index df94f979f5f..00000000000
--- a/doc/operations/metrics/dashboards/index.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# Custom dashboards (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/panel_types.md b/doc/operations/metrics/dashboards/panel_types.md
deleted file mode 100644
index 8dcf4e6ad28..00000000000
--- a/doc/operations/metrics/dashboards/panel_types.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# Panel types for dashboards (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/settings.md b/doc/operations/metrics/dashboards/settings.md
deleted file mode 100644
index 7abcbf88d59..00000000000
--- a/doc/operations/metrics/dashboards/settings.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# Dashboard settings (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/templating_variables.md b/doc/operations/metrics/dashboards/templating_variables.md
deleted file mode 100644
index ceeeb229a81..00000000000
--- a/doc/operations/metrics/dashboards/templating_variables.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# Templating variables for metrics dashboards (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/variables.md b/doc/operations/metrics/dashboards/variables.md
deleted file mode 100644
index b4ea05a0cea..00000000000
--- a/doc/operations/metrics/dashboards/variables.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# Using variables (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/yaml.md b/doc/operations/metrics/dashboards/yaml.md
deleted file mode 100644
index 95c02319b19..00000000000
--- a/doc/operations/metrics/dashboards/yaml.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# Dashboard YAML properties (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/dashboards/yaml_number_format.md b/doc/operations/metrics/dashboards/yaml_number_format.md
deleted file mode 100644
index e75beadfab9..00000000000
--- a/doc/operations/metrics/dashboards/yaml_number_format.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../index.md'
----
-
-# Unit formats reference (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/embed.md b/doc/operations/metrics/embed.md
deleted file mode 100644
index 68f115b66db..00000000000
--- a/doc/operations/metrics/embed.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../index.md'
----
-
-# Embedding metric charts within GitLab Flavored Markdown (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/metrics/embed_grafana.md b/doc/operations/metrics/embed_grafana.md
deleted file mode 100644
index 82967aa663f..00000000000
--- a/doc/operations/metrics/embed_grafana.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../index.md'
----
-# Embed Grafana panels in Markdown (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
-Use [embed charts](https://gitlab.com/groups/gitlab-org/opstrace/-/epics/33) instead.
diff --git a/doc/operations/metrics/index.md b/doc/operations/metrics/index.md
deleted file mode 100644
index 65f84c9c825..00000000000
--- a/doc/operations/metrics/index.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../index.md'
----
-
-# Monitor your environment's metrics (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/operations/tracing.md b/doc/operations/tracing.md
new file mode 100644
index 00000000000..608a9c998f8
--- /dev/null
+++ b/doc/operations/tracing.md
@@ -0,0 +1,75 @@
+---
+stage: Analyze
+group: Observability
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Distributed tracing **(ULTIMATE SAAS EXPERIMENT)**
+
+> Introduced in GitLab 16.3 [with flags](../administration/feature_flags.md) named `observability_group_tab` and `observability_tracing`. Disabled by default.
+
+FLAG:
+On GitLab.com, by default this feature is not available. To make it available,
+an administrator can [enable the feature flags](../administration/feature_flags.md) named `observability_group_tab` and `observability_tracing`.
+The feature is not ready for production use.
+
+With distributed tracing, you can troubleshoot application performance issues by inspecting how a request moves through different services and systems, the timing of each operation, and any errors or logs as they occur. Tracing is particularly useful in the context of microservice applications, which group multiple independent services collaborating to fulfill user requests.
+
+This feature is an [Experiment](../policy/experiment-beta-support.md). For more information, see the [group direction page](https://about.gitlab.com/direction/analytics/observability/). To leave feedback about tracing bugs or functionality, please comment in the [feedback issue](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2363) or open a [new issue](https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/new).
+
+## Configure distributed tracing for a project
+
+To configure distributed tracing:
+
+1. [Create an access token and enable tracing.](#create-an-access-token-and-enable-tracing)
+1. [Configure your application to use the OpenTelemetry exporter.](#configure-your-application-to-use-the-opentelemetry-exporter)
+
+### Create an access token and enable tracing
+
+Prerequisites:
+
+- You must have at least the Maintainer role for the project.
+
+To enable tracing in a project:
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **Settings > Access Tokens**.
+1. Create an access token with the following scopes: `read_api`, `read_observability`, `write_observability`.
+1. Copy the value of the access token.
+1. Navigate to your project.
+1. Select **Monitor > Tracing**.
+1. Select **Enable**.
+
+## Configure your application to use the OpenTelemetry exporter
+
+Next, configure your application to send traces to GitLab.
+
+To do this, set the following environment variables:
+
+```shell
+OTEL_EXPORTER = "otlphttp"
+OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "https://observe.gitlab.com/v3/<namespace-id>/<gitlab-project-id>/ingest/traces"
+OTEL_EXPORTER_OTLP_TRACES_HEADERS = "PRIVATE-TOKEN=<gitlab-access-token>"
+```
+
+Use the following values:
+
+- `namespace-id`: The top-level namespace ID where your project is located.
+- `gitlab-project-id`: The project ID.
+- `gitlab-access-token`: The access token you [created previously](#create-an-access-token-and-enable-tracing).
+
+When your application is configured, run it, and the OpenTelemetry exporter attempts to send
+traces to GitLab.
+
+## View your traces
+
+If your traces are exported successfully, you can see them in the project.
+
+To view the list of traces:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Monitor > Traces**.
+
+To see the details of a trace, select it from the list.
+
+![list of traces](img/tracing_list_v16_3.png)
diff --git a/doc/policy/alpha-beta-support.md b/doc/policy/alpha-beta-support.md
deleted file mode 100644
index bfea5b3a2d6..00000000000
--- a/doc/policy/alpha-beta-support.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'experiment-beta-support.md'
-remove_date: '2023-09-07'
----
-
-This document was moved to [another location](experiment-beta-support.md).
-
-<!-- This redirect file can be deleted after <2023-09-07>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/policy/experiment-beta-support.md b/doc/policy/experiment-beta-support.md
index 68cc96f118b..a87a72d7910 100644
--- a/doc/policy/experiment-beta-support.md
+++ b/doc/policy/experiment-beta-support.md
@@ -13,6 +13,9 @@ All other features are considered to be Generally Available (GA).
## Experiment
Support is not provided for features listed as "Experimental" or "Alpha" or any similar designation. Issues regarding such features should be opened in the GitLab issue tracker. Teams should release features as GA from the start unless there are strong reasons to release them as Experiment or Beta versions first.
+All Experimental features must [initiate Production Readiness Review](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#process) and complete the [experiment section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#experiment).
+
+Experimental features are:
- Not ready for production use.
- No support available.
@@ -20,7 +23,7 @@ Support is not provided for features listed as "Experimental" or "Alpha" or any
- Can be removed at any time.
- Data loss may occur.
- Documentation may not exist or just be in a blog format.
-- Offer an easy way to choose to opt-in to experimental features with minimal friction. For example, needing to flip a feature flag is too much friction, but a group or project-level setting that is in the UI is not.
+- Offer a way to opt-in with minimal friction. For example, needing to flip a feature flag is too much friction, but a group or project-level setting in the UI is not.
- Link out to the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/) in the opt-in.
- Documentation reflects that the feature is subject to the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
- [UI reflects experiment status](https://design.gitlab.com/usability/feature-management#highlighting-feature-versions).
@@ -33,6 +36,9 @@ Support is not provided for features listed as "Experimental" or "Alpha" or any
## Beta
Commercially-reasonable efforts are made to provide limited support for features designated as "Beta," with the expectation that issues require extra time and assistance from development to troubleshoot.
+All Beta features must complete all sections up to and including the [beta section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#beta) by following the [Production Readiness Review process](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness/#process).
+
+Beta features are:
- May not be ready for production use.
- Support on a commercially-reasonable effort basis.
@@ -50,7 +56,9 @@ Commercially-reasonable efforts are made to provide limited support for features
## Generally Available (GA)
-Generally Available features means that they passed the [Production Readiness Review](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md) for GitLab.com, and are:
+Generally Available features must complete the [Production Readiness Review](https://about.gitlab.com/handbook/engineering/infrastructure/production/readiness) and complete all sections up to and including the [GA section in the readiness template](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/.gitlab/issue_templates/production_readiness.md#general-availability).
+
+GA features are:
- Ready for production use at any scale.
- Fully documented and supported.
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index a6de6f594fb..bb27fcb27e0 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -36,8 +36,8 @@ The following table describes the version types and their release cadence:
| Version type | Description | Cadence |
|:-------------|:------------|:--------|
-| Major | For significant changes, or when any backward-incompatible changes are introduced to the public API. | Yearly. The next major release is GitLab 16.0 on May 22, 2023. GitLab schedules major releases on May 22 each year, by default. |
-| Minor | For when new backward-compatible functionality is introduced to the public API, a minor feature is introduced, or when a set of smaller features is rolled out. | Monthly on the 22nd. |
+| Major | For significant changes, or when any backward-incompatible changes are introduced to the public API. | Yearly. The next major release is GitLab 17.0, scheduled for May 16th, 2024. GitLab [schedules major releases](https://about.gitlab.com/releases/) for May each year, by default. |
+| Minor | For when new backward-compatible functionality is introduced to the public API, a minor feature is introduced, or when a set of smaller features is rolled out. | Monthly. |
| Patch | For backward-compatible bug fixes that fix incorrect behavior. See [Patch releases](#patch-releases). | As needed. |
## Upgrade recommendations
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 11a6e06fcf5..5ffed097a51 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -156,7 +156,7 @@ These commands don't work for artifacts stored on
[object storage](../administration/object_storage.md).
WARNING:
-Prior to GitLab 14.9, this task incorrectly deletes [pipeline artifacts](../ci/pipelines/pipeline_artifacts.md).
+Prior to GitLab 14.9, this task incorrectly deletes [test coverage-related artifacts](../ci/testing/test_coverage_visualization.md).
[The bug fix](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81022) was
also back-ported to 14.6.6, 14.7.5, and 14.8.3. Upgrade to a release with the bug
fix to avoid data loss.
diff --git a/doc/raketasks/generate_sample_prometheus_data.md b/doc/raketasks/generate_sample_prometheus_data.md
deleted file mode 100644
index 77c7d2c2c1a..00000000000
--- a/doc/raketasks/generate_sample_prometheus_data.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: 'index.md'
----
-
-# Sample Prometheus data Rake task (removed) **(FREE SELF)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
deleted file mode 100644
index d3b734eba12..00000000000
--- a/doc/raketasks/import.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-stage: Systems
-group: Distribution
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
----
-
-# Import bare repositories (removed) **(FREE SELF)**
-
-The Rake task for importing bare repositories was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108507)
-in GitLab 15.8 and [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118676) in GitLab 16.0.
diff --git a/doc/raketasks/list_repos.md b/doc/raketasks/list_repos.md
index 258d41aa190..b404e4dec60 100644
--- a/doc/raketasks/list_repos.md
+++ b/doc/raketasks/list_repos.md
@@ -4,7 +4,14 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# List repository directories Rake task **(FREE SELF)**
+<!--- start_remove The following content will be removed on remove_date: '2024-05-16' -->
+
+# List repository directories Rake task (deprecated) **(FREE SELF)**
+
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/384361) in GitLab 16.4 and is planned for removal in 17.0.
+[If migrating GitLab, use backup and restore](../administration/operations/moving_repositories.md#recommended-approach-in-all-cases)
+instead.
You can print a list of all Git repositories on disk managed by GitLab.
@@ -34,3 +41,5 @@ sudo gitlab-rake gitlab:list_repos SINCE='Sep 1 2015'
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:list_repos RAILS_ENV=production SINCE='Sep 1 2015'
```
+
+<!--- end_remove --> \ No newline at end of file
diff --git a/doc/raketasks/x509_signatures.md b/doc/raketasks/x509_signatures.md
index ab35f432fc2..ec85c400d49 100644
--- a/doc/raketasks/x509_signatures.md
+++ b/doc/raketasks/x509_signatures.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# X.509 signatures Rake task **(FREE SELF)**
-When [signing commits with X.509](../user/project/repository/x509_signed_commits/index.md),
+When [signing commits with X.509](../user/project/repository/signed_commits/x509.md),
the trust anchor might change and the signatures stored within the database must be updated.
## Update all X.509 signatures
diff --git a/doc/security/asset_proxy.md b/doc/security/asset_proxy.md
index cde377cbb73..16051d22bd6 100644
--- a/doc/security/asset_proxy.md
+++ b/doc/security/asset_proxy.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/security/crime_vulnerability.md b/doc/security/crime_vulnerability.md
index fdf3e5055b0..2c9969ab707 100644
--- a/doc/security/crime_vulnerability.md
+++ b/doc/security/crime_vulnerability.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
diff --git a/doc/security/email_verification.md b/doc/security/email_verification.md
index da844e3a2eb..7ebdfc32d2e 100644
--- a/doc/security/email_verification.md
+++ b/doc/security/email_verification.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/security/hardening.md b/doc/security/hardening.md
index 21b8594fc6e..9c222e5c758 100644
--- a/doc/security/hardening.md
+++ b/doc/security/hardening.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/security/hardening_application_recommendations.md b/doc/security/hardening_application_recommendations.md
index e9c09abdea1..5a11c53ffee 100644
--- a/doc/security/hardening_application_recommendations.md
+++ b/doc/security/hardening_application_recommendations.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -14,7 +14,7 @@ web interface.
## System hooks
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **System Hooks**.
@@ -33,7 +33,7 @@ encouraged for communications through system hooks.
## Push rules
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Push Rules**.
@@ -48,7 +48,7 @@ The adjustments help limit pushes to established and authorized users.
## Deploy keys
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Deploy Keys**.
@@ -61,7 +61,7 @@ the documentation on [deploy keys](../user/project/deploy_keys/index.md) and
## General
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
@@ -180,7 +180,7 @@ For more detailed information, see
## Integrations
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Integrations**.
@@ -192,7 +192,7 @@ process or authenticated user.
## Metrics and profiling
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Metrics and profiling**.
@@ -206,11 +206,11 @@ security patches come out frequently, this helps you stay up to date.
restrict data gathering and statistics reporting to a software vendor, you may have
to disable the **Enable service ping** feature. For more information on what data is collected to
help you make an informed decision, see
-[service ping](../development/service_ping/index.md).
+[service ping](../development/internal_analytics/service_ping/index.md).
## Network
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
diff --git a/doc/security/hardening_cicd_recommendations.md b/doc/security/hardening_cicd_recommendations.md
index 16b649cbdd7..72a3699868b 100644
--- a/doc/security/hardening_cicd_recommendations.md
+++ b/doc/security/hardening_cicd_recommendations.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/security/hardening_configuration_recommendations.md b/doc/security/hardening_configuration_recommendations.md
index 1cc3294f68b..e8cae41c535 100644
--- a/doc/security/hardening_configuration_recommendations.md
+++ b/doc/security/hardening_configuration_recommendations.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/security/hardening_general_concepts.md b/doc/security/hardening_general_concepts.md
index a227f0134d0..3c50196f9bc 100644
--- a/doc/security/hardening_general_concepts.md
+++ b/doc/security/hardening_general_concepts.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/security/hardening_operating_system_recommendations.md b/doc/security/hardening_operating_system_recommendations.md
index 33f88d43d22..80eea9b5085 100644
--- a/doc/security/hardening_operating_system_recommendations.md
+++ b/doc/security/hardening_operating_system_recommendations.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/security/identity_verification.md b/doc/security/identity_verification.md
index a4f7baad0e2..b6932d88820 100644
--- a/doc/security/identity_verification.md
+++ b/doc/security/identity_verification.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/security/index.md b/doc/security/index.md
index 5365228537f..d3bff521fcb 100644
--- a/doc/security/index.md
+++ b/doc/security/index.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: index
@@ -24,7 +24,7 @@ type: index
- [Proxying images](asset_proxy.md)
- [CI/CD variables](../ci/variables/index.md#cicd-variable-security)
- [Token overview](token_overview.md)
-- [Maximum decompressed file size for imported archives](../administration/settings/account_and_limit_settings.md#maximum-decompressed-file-size-for-imported-archives)
+- [Maximum decompressed file size for imported archives](../administration/settings/import_and_export_settings.md#maximum-decompressed-file-size-for-imported-archives)
- [Responding to security incidents](responding_to_security_incidents.md)
To harden your GitLab instance and minimize the risk of unwanted user account creation, consider access control features like [Sign up restrictions](../administration/settings/sign_up_restrictions.md) and [Authentication options](../topics/authentication/index.md). For more detailed information, refer to [Hardening](hardening.md).
diff --git a/doc/security/information_exclusivity.md b/doc/security/information_exclusivity.md
index 21e4ad8b108..a0d7b425a23 100644
--- a/doc/security/information_exclusivity.md
+++ b/doc/security/information_exclusivity.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: concepts
diff --git a/doc/security/password_length_limits.md b/doc/security/password_length_limits.md
index d8e9728f455..c7ebd713240 100644
--- a/doc/security/password_length_limits.md
+++ b/doc/security/password_length_limits.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference, howto
@@ -24,7 +24,7 @@ The user password length is set to a minimum of 8 characters by default.
To change the minimum password length using GitLab UI:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Sign-up restrictions**.
diff --git a/doc/security/password_storage.md b/doc/security/password_storage.md
index e814f4e5069..71e7510513e 100644
--- a/doc/security/password_storage.md
+++ b/doc/security/password_storage.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
diff --git a/doc/security/passwords_for_integrated_authentication_methods.md b/doc/security/passwords_for_integrated_authentication_methods.md
index a141241f97c..c7d94120887 100644
--- a/doc/security/passwords_for_integrated_authentication_methods.md
+++ b/doc/security/passwords_for_integrated_authentication_methods.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
diff --git a/doc/security/project_import_decompressed_archive_size_limits.md b/doc/security/project_import_decompressed_archive_size_limits.md
index 48767740625..a4749d0e5f9 100644
--- a/doc/security/project_import_decompressed_archive_size_limits.md
+++ b/doc/security/project_import_decompressed_archive_size_limits.md
@@ -1,9 +1,9 @@
---
-redirect_to: '../administration/settings/account_and_limit_settings.md#maximum-decompressed-file-size-for-imported-archives'
+redirect_to: '../administration/settings/import_and_export_settings.md#maximum-decompressed-file-size-for-imported-archives'
remove_date: '2023-11-02'
---
-This document was moved to [another location](../administration/settings/account_and_limit_settings.md#maximum-decompressed-file-size-for-imported-archives).
+This document was moved to [another location](../administration/settings/import_and_export_settings.md#maximum-decompressed-file-size-for-imported-archives).
<!-- This redirect file can be deleted after <2023-11-02>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
diff --git a/doc/security/rate_limits.md b/doc/security/rate_limits.md
index ee10d66a8ad..936e2931ff5 100644
--- a/doc/security/rate_limits.md
+++ b/doc/security/rate_limits.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference, howto
@@ -121,6 +121,9 @@ The **rate limit** is 20 calls per minute per IP address.
### Project Jobs API endpoint
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/382985) in GitLab 15.7 [with a flag](../administration/feature_flags.md) named `ci_enforce_rate_limits_jobs_api`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/384186) in GitLab 16.0. Feature flag `ci_enforce_rate_limits_jobs_api` removed.
+
There is a rate limit for the endpoint `project/:id/jobs`, which is enforced to reduce timeouts when retrieving jobs.
The **rate limit** is 600 calls per minute per authenticated user.
@@ -186,7 +189,7 @@ To remove a blocked IP:
keys *rack::attack*
```
-By default, the [`keys` command is disabled](https://docs.gitlab.com/omnibus/settings/redis.html#renamed-commands).
+ By default, the [`keys` command is disabled](https://docs.gitlab.com/omnibus/settings/redis.html#renamed-commands).
1. Optionally, add [the IP to the allowlist](https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-rack-attack)
to prevent it being denylisted again.
diff --git a/doc/security/reset_user_password.md b/doc/security/reset_user_password.md
index fa15efe7cb7..4a59d2f9a21 100644
--- a/doc/security/reset_user_password.md
+++ b/doc/security/reset_user_password.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: howto
@@ -20,7 +20,7 @@ The user's new password must meet all [password requirements](../user/profile/us
To reset a user's password in the UI:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. For the user whose password you want to update, select **Edit**.
diff --git a/doc/security/responding_to_security_incidents.md b/doc/security/responding_to_security_incidents.md
index 0cd7170d35b..b5e38ce55ca 100644
--- a/doc/security/responding_to_security_incidents.md
+++ b/doc/security/responding_to_security_incidents.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference, howto
diff --git a/doc/security/ssh_keys_restrictions.md b/doc/security/ssh_keys_restrictions.md
index 87cbf12471f..90affd089f3 100644
--- a/doc/security/ssh_keys_restrictions.md
+++ b/doc/security/ssh_keys_restrictions.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -20,7 +20,7 @@ limit the allowed SSH key algorithms.
GitLab allows you to restrict the allowed SSH key technology as well as specify
the minimum key length for each technology:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General** .
1. Expand the **Visibility and access controls** section:
diff --git a/doc/security/token_overview.md b/doc/security/token_overview.md
index cb01c7d5160..f605e95dfbf 100644
--- a/doc/security/token_overview.md
+++ b/doc/security/token_overview.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
@@ -20,9 +20,10 @@ You can create [Personal access tokens](../user/profile/personal_access_tokens.m
You can limit the scope and expiration date of your personal access tokens. By default,
they inherit permissions from the user who created them.
-You can use the [personal access tokens API](../api/personal_access_tokens.md) to
-programmatically take action, such as
-[rotating a personal access token](../api/personal_access_tokens.md#rotate-a-personal-access-token).
+You can use the personal access tokens API to programmatically take action,
+such as [rotating a personal access token](../api/personal_access_tokens.md#rotate-a-personal-access-token).
+
+You will receive an email when personal access tokens are 7 days or less from expiration.
## OAuth2 tokens
@@ -55,6 +56,8 @@ You can use the [project access tokens API](../api/project_access_tokens.md) to
programmatically take action, such as
[rotating a project access token](../api/project_access_tokens.md#rotate-a-project-access-token).
+All project maintainers receive an email when project access tokens are 7 days or less from expiration.
+
## Group access tokens
[Group access tokens](../user/group/settings/group_access_tokens.md#group-access-tokens)
@@ -72,6 +75,8 @@ You can use the [group access tokens API](../api/group_access_tokens.md) to
programmatically take action, such as
[rotating a group access token](../api/group_access_tokens.md#rotate-a-group-access-token).
+All group owners receive an email when group access tokens are 7 days or less from expiration.
+
## Deploy tokens
[Deploy tokens](../user/project/deploy_tokens/index.md) allow you to download (`git clone`) or push and pull packages and container registry images of a project without having a user and a password. Deploy tokens cannot be used with the GitLab API.
@@ -86,39 +91,50 @@ This is useful, for example, for cloning repositories to your Continuous Integra
Project maintainers and owners can add or enable a deploy key for a project repository
-## Runner registration tokens (deprecated)
+## Runner authentication tokens
-WARNING:
-The ability to pass a runner registration token has been [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) and is
-planned for removal in 17.0, along with support for certain configuration arguments. This change is a breaking change. GitLab plans to introduce a new
-[GitLab Runner token architecture](../architecture/blueprints/runner_tokens/index.md), which introduces
-a new method for registering runners and eliminates the
-runner registration token.
+In GitLab 16.0 and later, you can use a runner authentication token to register
+runners instead of a runner registration token. Runner registration tokens have
+been [deprecated](../update/deprecations.md#registration-tokens-and-server-side-runner-arguments-in-gitlab-runner-register-command).
-Runner registration tokens are used to [register](https://docs.gitlab.com/runner/register/) a [runner](https://docs.gitlab.com/runner/) with GitLab. Group or project owners or instance administrators can obtain them through the GitLab user interface. The registration token is limited to runner registration and has no further scope.
+After you create a runner and its configuration, you receive a runner authentication token
+that you use to register the runner. The runner authentication token is stored locally in the
+[`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html) file, which
+you use to configure the runner.
-You can use the runner registration token to add runners that execute jobs in a project or group. The runner has access to the project's code, so be careful when assigning project and group-level permissions.
+The runner uses the runner authentication token to authenticate with GitLab when
+it picks up jobs from the job queue. After the runner authenticates with GitLab,
+the runner receives a [job token](../ci/jobs/ci_job_token.md), which it uses to
+execute the job.
-## Runner authentication tokens (also called runner tokens)
+The runner authentication token stays on the runner machine. The execution environments
+for the following executors only have access to the job token and not the runner authentication token:
-Once created, the runner receives an authentication token, which it uses to authenticate with GitLab when picking up jobs from the job queue. The authentication token is stored locally in the runner's [`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html) file.
+- Docker Machine
+- Kubernetes
+- VirtualBox
+- Parallels
+- SSH
-After authentication with GitLab, the runner receives a [job token](../ci/jobs/ci_job_token.md), which it uses to execute the job.
+Malicious access to a runner's file system may expose the `config.toml` file and the
+runner authentication token. The attacker could use the runner authentication
+to [clone the runner](https://docs.gitlab.com/runner/security/#cloning-a-runner).
-In case of Docker Machine/Kubernetes/VirtualBox/Parallels/SSH executors, the execution environment has no access to the runner authentication token, because it stays on the runner machine. They have access to the job token only, which is needed to execute the job.
+You can use the `runners` API to
+programmatically [rotate or revoke a runner authentication token](../api/runners.md#reset-runners-authentication-token-by-using-the-current-token).
-Malicious access to a runner's file system may expose the `config.toml` file and thus the authentication token, allowing an attacker to [clone the runner](https://docs.gitlab.com/runner/security/#cloning-a-runner).
+## Runner registration tokens (deprecated)
-In GitLab 16.0 and later, you can use an authentication token to register runners instead of a
-registration token. Runner registration tokens have been [deprecated](../update/deprecations.md#registration-tokens-and-server-side-runner-arguments-in-gitlab-runner-register-command).
+WARNING:
+The ability to pass a runner registration token has been [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) and is
+planned for removal in GitLab 18.0, along with support for certain configuration arguments. This change is a breaking change. GitLab has implemented a new
+[GitLab Runner token architecture](../ci/runners/new_creation_workflow.md), which introduces
+a new method for registering runners and eliminates the
+runner registration token.
-To generate an authentication token, you create a runner in the GitLab UI and use the authentication token
-instead of the registration token.
+Runner registration tokens are used to [register](https://docs.gitlab.com/runner/register/) a [runner](https://docs.gitlab.com/runner/) with GitLab. Group or project owners or instance administrators can obtain them through the GitLab user interface. The registration token is limited to runner registration and has no further scope.
-| Process | Registration command |
-| ------------------ | --------------------- |
-| Registration token (deprecated) | `gitlab-runner register --registration-token $RUNNER_REGISTRATION_TOKEN <runner configuration arguments>` |
-| Authentication token | `gitlab-runner register --token $RUNNER_AUTHENTICATION_TOKEN` |
+You can use the runner registration token to add runners that execute jobs in a project or group. The runner has access to the project's code, so be careful when assigning project and group-level permissions.
## CI/CD job tokens
diff --git a/doc/security/two_factor_authentication.md b/doc/security/two_factor_authentication.md
index 906bf4cd062..0c569e9843d 100644
--- a/doc/security/two_factor_authentication.md
+++ b/doc/security/two_factor_authentication.md
@@ -1,50 +1,55 @@
---
type: howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Enforce two-factor authentication **(FREE ALL)**
-Two-factor authentication (2FA) provides an additional level of security to your
-users' GitLab account. When enabled, users are prompted for a code generated by an application in
-addition to supplying their username and password to sign in.
+[Two-factor authentication (2FA)](../user/profile/account/two_factor_authentication.md)
+is an authentication method that requires the user to provide two different factors
+to prove their identity:
+
+- Username and password.
+- A second authentication method, such as a code generated by an application.
+
+2FA makes it harder for an unauthorized person to access an account because
+they would need both factors.
NOTE:
If you are [using and enforcing SSO](../user/group/saml_sso/index.md#sso-enforcement), you might already be enforcing 2FA on the identity provider (IDP) side. Enforcing 2FA on GitLab as well might be unnecessary.
-Read more about [two-factor authentication (2FA)](../user/profile/account/two_factor_authentication.md).
-
## Enforce 2FA for all users **(FREE SELF)**
-Users on GitLab can enable it without any administrator's intervention. If you
-want to enforce everyone to set up 2FA, you can choose from two different ways:
+Administrators can enforce 2FA for all users in two different ways:
+
+- Enforce on next sign in.
+- Suggest on next sign in, but allow a grace period before enforcing.
-- Enforce on next login.
-- Suggest on next login, but allow a grace period before enforcing.
+ After the configured grace period has elapsed, users can sign in but
+ cannot leave the 2FA configuration area at `/-/profile/two_factor_auth`.
-After the configured grace period has elapsed, users can sign in but
-cannot leave the 2FA configuration area at `/-/profile/two_factor_auth`.
+You can use the UI or the API to enforce 2FA for all users.
-To enable 2FA for all users:
+### Use the UI
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
-1. Expand the **Sign-in restrictions** section, where you can configure both.
+1. Expand the **Sign-in restrictions** section:
+ - Select **Enforce two-factor authentication** to enable this feature.
+ - In **Two-factor grace period**, enter a number of hours. If you want to
+ enforce 2FA on next sign-in attempt, enter `0`.
-If you want 2FA enforcement to take effect during the next sign-in attempt,
-change the grace period to `0`.
+### Use the API
-### Disable 2FA enforcement through Rails console
+Use the [application settings API](../api/settings.md) to modify the following settings:
-Using the [Rails console](../administration/operations/rails_console.md), enforcing 2FA for
-all user can be disabled. Connect to the Rails console and run:
+- `require_two_factor_authentication`.
+- `two_factor_grace_period`.
-```ruby
-Gitlab::CurrentSettings.update!('require_two_factor_authentication': false)
-```
+For more information, see the [list of settings that can be accessed through API calls](../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
## Enforce 2FA for all users in a group **(FREE ALL)**
@@ -56,59 +61,67 @@ Prerequisites:
To enforce 2FA only for certain groups:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Select **All users in this group must set up two-factor authentication**.
+1. Optional. In **Delay 2FA enforcement (hours)**, enter the number of hours you
+ want the grace period to last for.
+ If there are multiple different grace periods in a top level group and its subgroups
+ and projects, the shortest grace period is used.
1. Select **Save changes**.
-You can also specify a grace period in the **Delay 2FA enforcement** option.
-
-If you want to enforce 2FA only for certain groups, you can enable it in the
-group settings and specify a grace period as above.
-
-The following are important notes about 2FA:
-
-- Projects belonging to a 2FA-enabled group that
- [is shared](../user/project/members/share_project_with_groups.md)
- with a 2FA-disabled group will *not* require members of the 2FA-disabled group to use
- 2FA for the project. For example, if project *P* belongs to 2FA-enabled group *A* and
- is shared with 2FA-disabled group *B*, members of group *B* can access project *P*
- without 2FA. To ensure this scenario doesn't occur,
- [prevent sharing of projects](../user/group/access_and_permissions.md#prevent-a-project-from-being-shared-with-groups)
- for the 2FA-enabled group.
-- If you add additional members to a project within a group or subgroup that has
- 2FA enabled, 2FA is **not** required for those individually added members.
-- If there are multiple 2FA requirements (for example, group + all users, or multiple
- groups) the shortest grace period is used.
-- It is possible to prevent subgroups from setting up their own 2FA requirements:
- 1. Go to the top-level group's **Settings > General**.
- 1. Expand the **Permissions and group features** section.
- 1. Uncheck the **Allow subgroups to set up their own two-factor authentication rule** field.
-
- This action causes all subgroups with 2FA requirements to stop requiring that from their members.
-- Access tokens are not required to provide a second factor for authentication because they are API-based.
- Tokens generated before 2FA is enforced remain valid.
+Access tokens are not required to provide a second factor for authentication because
+they are API-based. Tokens generated before 2FA is enforced remain valid.
+
+### 2FA in subgroups
+
+You can enable and enforce 2FA for individual subgroups in the same way as a top
+level group.
+
+You can prevent subgroups from setting up their own 2FA requirements:
+
+1. Go to the top level group's **Settings > General**.
+1. Expand the **Permissions and group features** section.
+1. Clear the **Allow subgroups to set up their own two-factor authentication rule** checkbox.
+
+This action causes all subgroups with 2FA requirements to stop requiring 2FA from
+their members.
+
+### 2FA in projects
+
+If a project belonging to a group that enables or enforces 2FA is [shared](../user/project/members/share_project_with_groups.md)
+with a group that does not enable or enforce 2FA, members of the non-2FA group can access that project
+without using 2FA. For example:
+
+- Group *A* has 2FA enabled and enforced. Group *B* does not have 2FA enabled.
+- If a project, *P*, that belongs to group *A* is shared with group *B*, members
+ of group *B* can access project *P* without 2FA.
+
+To ensure this does not occur, [prevent sharing of projects](../user/group/access_and_permissions.md#prevent-a-project-from-being-shared-with-groups)
+for the 2FA group.
+
+If you add members to a project in a group or subgroup that has 2FA
+enabled, 2FA is **not** required for those individually added members.
## Disable 2FA **(FREE SELF)**
+You can disable 2FA for a single user or all users.
+
+This is a permanent and irreversible action. Users must reactivate 2FA to use it again.
+
WARNING:
Disabling 2FA for users does not disable the [enforce 2FA for all users](#enforce-2fa-for-all-users)
or [enforce 2FA for all users in a group](#enforce-2fa-for-all-users-in-a-group)
settings. You must also disable any enforced 2FA settings so users aren't asked to set up 2FA again
when they next sign in to GitLab.
-WARNING:
-This is a permanent and irreversible action. Users must reactivate 2FA to use it again.
-
### For a single user
-To disable 2FA for non-administrator users, you should use the [API endpoint](../api/users.md#disable-two-factor-authentication)
-instead of the Rails console.
-Using the [Rails console](../administration/operations/rails_console.md), 2FA for a single user can be disabled.
-Connect to the Rails console and run:
+#### Administrators
-**In GitLab 13.5 and later:**
+In GitLab 13.5 and later, use the [Rails console](../administration/operations/rails_console.md)
+to disable 2FA for a single administrator:
```ruby
admin = User.find_by_username('<USERNAME>')
@@ -117,20 +130,33 @@ user_to_disable = User.find_by_username('<USERNAME>')
TwoFactor::DestroyService.new(admin, user: user_to_disable).execute
```
-The target user is notified that 2FA has been disabled.
+The administrator is notified that 2FA has been disabled.
+
+#### Non-administrators
+
+In GitLab 15.2 and later, you can use either the Rails console or the
+[API endpoint](../api/users.md#disable-two-factor-authentication) to disable 2FA
+for a non-administrator.
+
+You can disable 2FA for your own account.
+
+You cannot use the API endpoint to disable 2FA for administrators.
### For all users
-There may be some special situations where you want to disable 2FA for everyone
-even when forced 2FA is disabled. There is a Rake task for that:
+To disable 2FA for all users even when forced 2FA is disabled, use the following Rake task.
-```shell
-# Omnibus installations
-sudo gitlab-rake gitlab:two_factor:disable_for_all_users
+- For installations that use the Linux package:
-# Installations from source
-sudo -u git -H bundle exec rake gitlab:two_factor:disable_for_all_users RAILS_ENV=production
-```
+ ```shell
+ sudo gitlab-rake gitlab:two_factor:disable_for_all_users
+ ```
+
+- For self-compiled installations:
+
+ ```shell
+ sudo -u git -H bundle exec rake gitlab:two_factor:disable_for_all_users RAILS_ENV=production
+ ```
## 2FA for Git over SSH operations **(PREMIUM ALL)**
diff --git a/doc/security/unlock_user.md b/doc/security/unlock_user.md
index 5e21cad8f3e..b2c8624b057 100644
--- a/doc/security/unlock_user.md
+++ b/doc/security/unlock_user.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: howto
@@ -25,7 +25,7 @@ If 2FA is enabled, users are locked after five failed sign-in attempts within 10
## Unlock a user from the Admin Area
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. Use the search bar to find the locked user.
@@ -46,13 +46,13 @@ To unlock a locked user:
sudo -u git -H bundle exec rails console -e production
```
-1. Find the user to unlock. You can search by email or ID.
+1. Find the user to unlock. You can search by email:
```ruby
user = User.find_by(email: 'admin@local.host')
```
- or
+ Or you can search by ID:
```ruby
user = User.where(id: 1).first
@@ -64,7 +64,7 @@ To unlock a locked user:
user.unlock_access!
```
-1. Exit the console with <kbd>Control</kbd>+<kbd>d</kbd>
+1. Exit the console with <kbd>Control</kbd>+<kbd>d</kbd>.
The user should now be able to sign in.
diff --git a/doc/security/user_email_confirmation.md b/doc/security/user_email_confirmation.md
index 899fed0b584..56445903d6c 100644
--- a/doc/security/user_email_confirmation.md
+++ b/doc/security/user_email_confirmation.md
@@ -1,6 +1,6 @@
---
type: howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -11,7 +11,7 @@ GitLab can be configured to require confirmation of a user's email address when
the user signs up. When this setting is enabled, the user is unable to sign in until
they confirm their email address.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Sign-up restrictions** and look for the **Email confirmation settings** options.
diff --git a/doc/security/user_file_uploads.md b/doc/security/user_file_uploads.md
index e0f1342b9c9..6ddda281a03 100644
--- a/doc/security/user_file_uploads.md
+++ b/doc/security/user_file_uploads.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -47,7 +47,7 @@ Prerequisite:
To configure authentication settings for all media files:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Scroll to **Project visibility** and select **Require authentication to view media files**.
diff --git a/doc/security/webhooks.md b/doc/security/webhooks.md
index 78c32341bf6..f8bd50bc4b3 100644
--- a/doc/security/webhooks.md
+++ b/doc/security/webhooks.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: concepts, reference, howto
@@ -50,7 +50,7 @@ To prevent exploitation of insecure internal web services, all webhook and integ
To allow access to these addresses:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
@@ -64,7 +64,7 @@ Prerequisite:
[System hooks](../administration/system_hooks.md) can make requests to the local network by default. To prevent system hook requests to the local network:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
@@ -80,7 +80,7 @@ Prerequisite:
To filter requests by blocking many requests:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
@@ -106,7 +106,7 @@ Prerequisite:
To allow outbound requests to certain IP addresses and domains:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Network**.
1. Expand **Outbound requests**.
diff --git a/doc/subscriptions/bronze_starter.md b/doc/subscriptions/bronze_starter.md
index 93a68fa0338..3b2ef601136 100644
--- a/doc/subscriptions/bronze_starter.md
+++ b/doc/subscriptions/bronze_starter.md
@@ -76,9 +76,7 @@ the tiers are no longer mentioned in GitLab documentation:
- [Contribution Analytics](../user/group/contribution_analytics/index.md)
- [Merge Request Analytics](../user/analytics/merge_request_analytics.md)
- [Code Review Analytics](../user/analytics/code_review_analytics.md)
- - [Audit Events](../administration/audit_events.md), including
- [Group events](../administration/audit_events.md#group-events) and
- [Project events](../administration/audit_events.md#project-events)
+ - [Audit Events](../administration/audit_events.md)
- Rake tasks:
- [Displaying GitLab license information](../administration/raketasks/maintenance.md#show-gitlab-license-information)
- Reference Architecture information:
diff --git a/doc/subscriptions/community_programs.md b/doc/subscriptions/community_programs.md
index 26d221cf62d..a1d50dcb239 100644
--- a/doc/subscriptions/community_programs.md
+++ b/doc/subscriptions/community_programs.md
@@ -22,7 +22,7 @@ To meet GitLab for Open Source Program requirements, first add an OSI-approved o
To add a license to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the overview page, select **Add LICENSE**. If the license you want is not available as a license template, manually copy the entire, unaltered [text of your chosen license](https://opensource.org/licenses/) into the `LICENSE` file. GitLab defaults to **All rights reserved** if users do not perform this action.
![Add license](img/add-license.png)
@@ -45,7 +45,7 @@ Benefits of the GitLab Open Source Program apply to all projects in a GitLab nam
#### Screenshot 1: License overview
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select your project avatar. If you haven't specified an avatar for your project, the avatar displays as a single letter.
1. Take a screenshot of the project overview that clearly displays the license you've chosen for your project.
@@ -53,7 +53,7 @@ Benefits of the GitLab Open Source Program apply to all projects in a GitLab nam
#### Screenshot 2: License contents
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1.Select **Code > Repository** and locate the project's `LICENSE` file.
1. Take a screenshot of the contents of the file. Make sure the screenshot includes the title of the license.
@@ -63,7 +63,7 @@ Benefits of the GitLab Open Source Program apply to all projects in a GitLab nam
To be eligible for the GitLab Open Source Program, projects must be publicly visible. To check your project's public visibility settings:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. From the **Project visibility** dropdown list, select **Public**.
diff --git a/doc/subscriptions/gitlab_com/index.md b/doc/subscriptions/gitlab_com/index.md
index cb2a324bc9b..ff85c658c50 100644
--- a/doc/subscriptions/gitlab_com/index.md
+++ b/doc/subscriptions/gitlab_com/index.md
@@ -48,7 +48,7 @@ Prerequisite:
To see the status of your GitLab SaaS subscription:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Billing**.
The following information is displayed:
@@ -80,10 +80,13 @@ Every user is included in seat usage, with the following exceptions:
- Users who are pending approval.
- Members with the [Guest role on an Ultimate subscription](#free-guest-users).
+- Members with the [minimal access role](../../user/permissions.md#users-with-minimal-access).
+- [Banned members](../../user/group/moderate_users.md#ban-a-user).
+- [Blocked users](../../administration/moderate_users.md#block-a-user).
- GitLab-created service accounts:
- [Ghost User](../../user/profile/account/delete_account.md#associated-records).
- Bots such as:
- - [Support Bot](../../user/project/service_desk/index.md#support-bot-user).
+ - [Support Bot](../../user/project/service_desk/configure.md#support-bot-user).
- [Bot users for projects](../../user/project/settings/project_access_tokens.md#bot-users-for-projects).
- [Bot users for groups](../../user/group/settings/group_access_tokens.md#bot-users-for-groups).
@@ -99,7 +102,7 @@ In this case, they would see only the features available to that subscription.
To view a list of seats being used:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Usage Quotas**.
1. On the **Seats** tab, view usage information.
@@ -113,7 +116,7 @@ The counts for **Max seats used** and **Seats owed** are updated once per day.
To view your subscription information and a summary of seat counts:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Billing**.
The usage statistics are updated once per day, which may cause
@@ -141,7 +144,7 @@ For example:
To export seat usage data as a CSV file:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Billing**.
1. Under **Seats currently in use**, select **See usage**.
1. Select **Export list**.
@@ -185,13 +188,13 @@ GitLab [bills you for the overage](../quarterly_reconciliation.md).
To add seats to a subscription:
1. Log in to the [Customers Portal](https://customers.gitlab.com/).
-1. Navigate to the **Manage Purchases** page.
+1. Go to the **Manage Purchases** page.
1. Select **Add more seats** on the relevant subscription card.
1. Enter the number of additional users.
-1. Select **Proceed to checkout**.
-1. Review the **Subscription Upgrade Detail**. The system lists the total price for all users on the
+1. Review the **Purchase summary** section. The system lists the total price for all users on the
system and a credit for what you've already paid. You are only be charged for the net change.
-1. Select **Confirm Upgrade**.
+1. Enter your payment information.
+1. Select **Purchase seats**.
The following is emailed to you:
@@ -202,7 +205,7 @@ The following is emailed to you:
To remove a billable user from your subscription:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Billing**.
1. In the **Seats currently in use** section, select **See usage**.
1. In the row for the user you want to remove, on the right side, select the ellipsis and **Remove user**.
@@ -241,10 +244,11 @@ amounts at which the alert displays.
To change the namespace linked to a subscription:
-1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) with a
+1. Sign in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) with a
[linked](../customers_portal.md#link-a-gitlabcom-account) GitLab.com account.
-1. Go to the **Manage Purchases** page.
-1. Select **Change linked namespace**.
+1. Do one of the following:
+ - If the subscription is not linked to a namespace, select **Link subscription to a group**.
+ - If the subscription is already linked to a namespace, select **Subscription actions** (**{ellipsis_v}**) > **Change linked group**.
1. Select the desired group from the **New Namespace** dropdown list. For a group to appear here, you must have the Owner role for that group.
1. If the [total number of users](#view-seat-usage) in your group exceeds the number of seats in your subscription,
you are prompted to pay for the additional users. Subscription charges are calculated based on
@@ -258,18 +262,17 @@ To change the namespace linked to a subscription:
1. Select **Confirm changes**.
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For a demo, see [Linking GitLab Subscription to the Namespace](https://youtu.be/qAq8pyFP-a0).
-
Only one namespace can be linked to a subscription.
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For a demo, see [Linking GitLab Subscription to the Namespace](https://youtu.be/8iOsN8ajBUw).
+
## Upgrade your GitLab SaaS subscription tier
To upgrade your [GitLab tier](https://about.gitlab.com/pricing/):
-1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
-1. Select **Upgrade** on the relevant subscription card on the
- [Manage purchases](https://customers.gitlab.com/subscriptions) page.
+1. Sign in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
+1. Select **Upgrade** on the relevant subscription card.
1. Select the desired upgrade.
1. Confirm the active form of payment, or add a new form of payment.
1. Check the **I accept the Privacy Policy and Terms of Service** checkbox.
@@ -305,12 +308,12 @@ Before you renew your subscription:
Starting 30 days before a subscription expires, GitLab notifies group owners
of the date of expiry with a banner in the GitLab user interface.
-
+You can only renew your subscription 15 days before it is due to expire.
To renew your subscription:
-1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) and beneath your existing subscription, select **Renew**.
-The **Renew** button remains disabled (grayed-out) until 15 days before a subscription expires.
-You can hover your mouse on the **Renew** button to see the date when it becomes active.
+1. Sign in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) and beneath your existing subscription, select **Renew**.
+The **Renew** button displays only 15 days before a subscription expires. If there are more than 15 days before
+the subscription expires, select **Subscription actions** (**{ellipsis_v}**), then select **Renew subscription** to view the date when you can renew.
1. Review your renewal details and complete the payment process.
1. Select **Confirm purchase**.
@@ -340,10 +343,8 @@ expiration date without a gap in available service. Subscriptions purchased thro
To view or change automatic subscription renewal (at the same tier as the
previous period), sign in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in), and:
-- If a **Turn on auto-renew** button is displayed, your subscription was canceled
- previously. Select it to resume automatic renewal.
-- If a **Cancel subscription** button is displayed, your subscription is set to automatically
- renew at the end of the subscription period. Select it to cancel automatic renewal.
+- If the subscription card displays `Expires on DATE`, your subscription is not set to automatically renew. To enable automatic renewal, in **Subscription actions** (**{ellipsis_v}**), select **Turn on auto-renew**.
+- If the subscription card displays `Autorenews on DATE`, your subscription is set to automatically renew at the end of the subscription period. To cancel automatic renewal, in **Subscription actions** (**{ellipsis_v}**), select **Cancel subscription**.
If you have difficulty during the renewal process, contact the
[Support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293) for assistance.
@@ -430,7 +431,7 @@ main quota. You can find pricing for additional storage on the
To purchase additional storage for your group on GitLab SaaS:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Usage Quotas**.
1. Select **Storage** tab.
1. Select **Purchase more storage**.
diff --git a/doc/subscriptions/gitlab_dedicated/index.md b/doc/subscriptions/gitlab_dedicated/index.md
index a2e04812876..fd20e353056 100644
--- a/doc/subscriptions/gitlab_dedicated/index.md
+++ b/doc/subscriptions/gitlab_dedicated/index.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
GitLab Dedicated is a fully isolated, single-tenant SaaS service that is:
- Hosted and managed by GitLab, Inc.
-- Deployed on AWS in a cloud region of your choice (see the [regions that are not supported](#aws-regions-not-supported)).
+- Deployed on AWS in a cloud region of your choice. See [unavailable AWS regions](#unavailable-aws-regions).
GitLab Dedicated removes the overhead of platform management to increase your operational efficiency, reduce risk, and enhance the speed and agility of your organization. Each GitLab Dedicated instance is highly available with disaster recovery and deployed into the cloud region of your choice. GitLab teams fully manage the maintenance and operations of each isolated instance, so customers can access our latest product improvements while meeting the most complex compliance standards.
@@ -19,7 +19,7 @@ It's the offering of choice for enterprises and organizations in highly regulate
### Data residency
-GitLab Dedicated allows you to select the cloud region where your data will be stored. Upon [onboarding](../../administration/dedicated/index.md#onboarding), choose the cloud region where you want to deploy your Dedicated instance. Some AWS regions have limited features and as a result, we are not able to deploy production instances to those regions. See below for the [full list of regions](#aws-regions-not-supported) not supported.
+GitLab Dedicated allows you to select the cloud region where your data will be stored. Upon [onboarding](../../administration/dedicated/index.md#onboarding), choose the cloud region where you want to deploy your Dedicated instance. Some AWS regions have limited features and as a result, we are not able to deploy production instances to those regions. See below for the [list of unavailable AWS regions](#unavailable-aws-regions).
### Availability and scalability
@@ -29,7 +29,7 @@ GitLab Dedicated leverages the GitLab [Cloud Native Hybrid reference architectur
When [onboarding](../../administration/dedicated/index.md#onboarding) to GitLab Dedicated, you can provide a Secondary AWS region in which your data is stored. This region is used to recover your GitLab Dedicated instance in case of a disaster. Regular backups of all GitLab Dedicated datastores (including Database and Git repositories) are taken and tested regularly and stored in your desired secondary region. GitLab Dedicated also provides the ability to store copies of these backups in a separate cloud region of choice for greater redundancy.
-For more information, read about the [recovery plan for GitLab Dedicated](https://about.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/slas/#disaster-recovery-plan) as well as RPO and RTO targets.
+For more information, read about the [recovery plan for GitLab Dedicated](https://about.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/slas/#disaster-recovery-plan) as well as RPO and RTO targets. These targets are available only when both the primary and secondary regions are supported by GitLab Dedicated. See below for a [list of unavailable AWS regions](#unavailable-aws-regions) for GitLab Dedicated.
### Security
@@ -129,7 +129,8 @@ The following GitLab application features are not available:
The following features will not be supported:
- Mattermost
-- Server-side Git hooks. Use [push rules](../../user/project/repository/push_rules.md) instead.
+- [Server-side Git hooks](../../administration/server_hooks.md).
+ GitLab Dedicated is a SaaS service, and access to the underlying infrastructure is only available to GitLab Inc. team members. Due to the nature of server side configuration, there is a possible security concern of running arbitrary code on Dedicated services, as well as the possible impact that can have on the service SLA. Use the alternative [push rules](../../user/project/repository/push_rules.md) or [webhooks](../../user/project/integrations/webhooks.md) instead.
### GitLab Dedicated service features
@@ -143,9 +144,12 @@ The following operational features are not available:
- Observability Dashboard using Switchboard
- Pre-Production Instance
-### AWS regions not supported
+### Unavailable AWS regions
-The following AWS regions are not available:
+The following is an incomplete list of unavailable AWS regions. Regions must support `io2` volumes and meet other requirements. GitLab team members can view our evaluation of additional
+regions in this confidential issue: `https://gitlab.com/gitlab-com/gl-infra/gitlab-dedicated/team/-/issues/1405`.
+
+Contact [GitLab Support](https://about.gitlab.com/support/) if you have any questions.
- Jakarta (`ap-southeast-3`)
- Bahrain (`me-south-1`)
@@ -156,6 +160,15 @@ The following AWS regions are not available:
- Zurich (`eu-central-2`)
- GovCloud (US-East) (`us-gov-east-1`)
- GovCloud (US-West) (`us-gov-west-1`)
+- Melbourne (`ap-southeast-4`)
+- Hyderabad (`ap-south-2`)
+- Osaka (`ap-northeast-3`)
+- Beijing (`cn-north-1`)
+- Ningxia (`cn-northwest-1`)
+- Spain (`eu-south-2`)
+- Tel Aviv (`il-central-1`)
+- UAE (`me-central-1`)
+- São Paulo (`sa-east-1`)
## Planned features
diff --git a/doc/subscriptions/quarterly_reconciliation.md b/doc/subscriptions/quarterly_reconciliation.md
index 7e7cc93e284..1962ce02647 100644
--- a/doc/subscriptions/quarterly_reconciliation.md
+++ b/doc/subscriptions/quarterly_reconciliation.md
@@ -79,6 +79,15 @@ seats, and an invoice is generated for a prorated amount. If a credit card
is on file, a payment is automatically applied. Otherwise, an invoice is
sent and subject to your payment terms.
+### Troubleshooting failed payment
+
+If your credit card is declined during the reconciliation process, an email will be sent with the subject `Your GitLab subscription failed to reconcile`. Please follow these instructions to update your payment information, and the reconciliation will be automatically retried:
+
+1. Log in to your account at `https://customers.gitlab.com`.
+1. Go to **Payment Methods**.
+1. Select **Add New Payment Method**.
+1. Make sure that the payment method is set as **Default**.
+
## Quarterly reconciliation eligibility
### You are automatically enrolled in quarterly reconciliation if
diff --git a/doc/subscriptions/self_managed/index.md b/doc/subscriptions/self_managed/index.md
index fca6ea57a95..ea6b87134ac 100644
--- a/doc/subscriptions/self_managed/index.md
+++ b/doc/subscriptions/self_managed/index.md
@@ -36,7 +36,7 @@ Prorated charges are not possible without a quarterly usage report.
You can view users for your license and determine if you've gone over your subscription.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Users**.
@@ -57,7 +57,7 @@ billable user, with the following exceptions:
- GitLab-created service accounts:
- [Ghost User](../../user/profile/account/delete_account.md#associated-records).
- Bots such as:
- - [Support Bot](../../user/project/service_desk/index.md#support-bot-user).
+ - [Support Bot](../../user/project/service_desk/configure.md#support-bot-user).
- [Bot users for projects](../../user/project/settings/project_access_tokens.md#bot-users-for-projects).
- [Bot users for groups](../../user/group/settings/group_access_tokens.md#bot-users-for-groups).
- Other [internal users](../../development/internal_users.md#internal-users).
@@ -217,7 +217,7 @@ Example of a license sync request:
You can manually synchronize your subscription details at any time.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Subscription**.
1. In the **Subscription details** section, select **Sync subscription details**.
@@ -228,7 +228,7 @@ A job is queued. When the job finishes, the subscription details are updated.
If you are an administrator, you can view the status of your subscription:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Subscription**.
@@ -253,7 +253,7 @@ It also displays the following information:
If you are an administrator, you can export your license usage into a CSV:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Subscription**.
1. In the upper-right corner, select **Export license usage file**.
diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md
index 6137ade4559..8efa5afcb80 100644
--- a/doc/topics/authentication/index.md
+++ b/doc/topics/authentication/index.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -30,7 +30,6 @@ This page gathers all the resources for the topic **Authentication** in GitLab.
- **Integrations:**
- [OmniAuth](../../integration/omniauth.md)
- [Atlassian Crowd OmniAuth Provider](../../administration/auth/crowd.md)
- - [CAS OmniAuth Provider](../../integration/cas.md)
- [SAML OmniAuth Provider](../../integration/saml.md)
- [SAML for GitLab.com Groups](../../user/group/saml_sso/index.md)
- [SCIM user provisioning for GitLab.com Groups](../../user/group/saml_sso/scim_setup.md)
diff --git a/doc/topics/autodevops/cicd_variables.md b/doc/topics/autodevops/cicd_variables.md
index a5897e0b233..21d9dd0b3d3 100644
--- a/doc/topics/autodevops/cicd_variables.md
+++ b/doc/topics/autodevops/cicd_variables.md
@@ -136,7 +136,7 @@ Prerequisite:
To configure secret variables:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Variables**.
1. Create a CI/CD variable with the prefix `K8S_SECRET_`. For example, you
diff --git a/doc/topics/autodevops/cloud_deployments/auto_devops_with_ecs.md b/doc/topics/autodevops/cloud_deployments/auto_devops_with_ecs.md
index af396e159da..6ac8f87940e 100644
--- a/doc/topics/autodevops/cloud_deployments/auto_devops_with_ecs.md
+++ b/doc/topics/autodevops/cloud_deployments/auto_devops_with_ecs.md
@@ -13,7 +13,7 @@ You can choose to target AWS ECS as a deployment platform instead of using Kuber
To get started on Auto DevOps to AWS ECS, you must add a specific CI/CD variable.
To do so, follow these steps:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Auto DevOps**.
1. Specify which AWS platform to target during the Auto DevOps deployment
diff --git a/doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md b/doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md
index 53b20f880a9..d0a7814348c 100644
--- a/doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md
+++ b/doc/topics/autodevops/cloud_deployments/auto_devops_with_eks.md
@@ -132,7 +132,7 @@ While Auto DevOps is enabled by default, Auto DevOps can be disabled at both
the instance level (for self-managed instances) and the group level. Complete
these steps to enable Auto DevOps if it's disabled:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the application project.
+1. On the left sidebar, select **Search or go to** and find the application project.
1. Select **Settings > CI/CD**.
1. Expand **Auto DevOps**.
1. Select **Default to Auto DevOps pipeline** to display more options.
diff --git a/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md b/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md
index a939fe108a1..d50bdcfa056 100644
--- a/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md
+++ b/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md
@@ -136,7 +136,7 @@ While Auto DevOps is enabled by default, Auto DevOps can be disabled at both
the instance level (for self-managed instances) and the group level. Complete
these steps to enable Auto DevOps if it's disabled:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the application project.
+1. On the left sidebar, select **Search or go to** and find the application project.
1. Select **Settings > CI/CD**.
1. Expand **Auto DevOps**.
1. Select **Default to Auto DevOps pipeline** to display more options.
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 0668ea0df14..4191ba257ca 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -101,7 +101,7 @@ Prerequisites:
To enable Auto DevOps for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Auto DevOps**.
1. Select the **Default to Auto DevOps pipeline** checkbox.
@@ -132,7 +132,7 @@ Prerequisites:
To enable Auto DevOps for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > CI/CD**.
1. Expand **Auto DevOps**.
1. Select the **Default to Auto DevOps pipeline** checkbox.
@@ -144,7 +144,7 @@ clear the **Default to Auto DevOps pipeline** checkbox.
After enabling Auto DevOps at the group level, you can trigger the
Auto DevOps pipeline for any project that belongs to that group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Make sure the project doesn't contain a `.gitlab-ci.yml` file.
1. Select **Build > Pipelines**.
1. To trigger the Auto DevOps pipeline, select **Run pipeline**.
@@ -164,7 +164,7 @@ Prerequisites:
To enable Auto DevOps for your instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > CI/CD**.
1. Expand **Auto DevOps**.
diff --git a/doc/topics/autodevops/prepare_deployment.md b/doc/topics/autodevops/prepare_deployment.md
index c5a758e5d70..1dced373461 100644
--- a/doc/topics/autodevops/prepare_deployment.md
+++ b/doc/topics/autodevops/prepare_deployment.md
@@ -43,7 +43,7 @@ To define the base domain, either:
- In the project, group, or instance level: go to your cluster settings and add it there.
- In the project or group level: add it as an environment variable: `KUBE_INGRESS_BASE_DOMAIN`.
-- In the instance level: go to **Main menu > Admin > Settings > CI/CD > Continuous Integration and Delivery** and add it there.
+- In the instance level: go to the Admin Area, then **Settings > CI/CD > Continuous Integration and Delivery** and add it there.
The base domain variable `KUBE_INGRESS_BASE_DOMAIN` follows the same order of precedence
as other environment [variables](../../ci/variables/index.md#cicd-variable-precedence).
diff --git a/doc/topics/autodevops/requirements.md b/doc/topics/autodevops/requirements.md
index 47d79fcfc6b..a0aaba99a59 100644
--- a/doc/topics/autodevops/requirements.md
+++ b/doc/topics/autodevops/requirements.md
@@ -41,7 +41,7 @@ that works best for your needs:
You can choose the deployment method when enabling Auto DevOps or later:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **Auto DevOps**.
1. Choose the deployment strategy.
@@ -60,7 +60,7 @@ To define the base domain, either:
- In the project, group, or instance level: go to your cluster settings and add it there.
- In the project or group level: add it as an environment variable: `KUBE_INGRESS_BASE_DOMAIN`.
-- In the instance level: go to **Main menu > Admin > Settings > CI/CD > Continuous Integration and Delivery** and add it there.
+- In the instance level: go to the Admin Area, then **Settings > CI/CD > Continuous Integration and Delivery** and add it there.
The base domain variable `KUBE_INGRESS_BASE_DOMAIN` follows the same order of
[precedence as other environment variables](../../ci/variables/index.md#cicd-variable-precedence).
diff --git a/doc/topics/git/how_to_install_git/index.md b/doc/topics/git/how_to_install_git/index.md
index 40c5147e20b..52e8e2e1259 100644
--- a/doc/topics/git/how_to_install_git/index.md
+++ b/doc/topics/git/how_to_install_git/index.md
@@ -34,16 +34,16 @@ Prerequisites:
To install Git on macOS:
-1. Open a terminal and install the XCode Command Line Tools:
+1. Open a terminal and install Xcode Command Line Tools:
```shell
xcode-select --install
```
- Alternatively, you can install the entire [XCode](https://developer.apple.com/xcode/)
+ Alternatively, you can install the entire [Xcode](https://developer.apple.com/xcode/)
package through the macOS App Store.
-1. Select **Install** to download and install XCode Command Line Tools.
+1. Select **Install** to download and install Xcode Command Line Tools.
1. Install Homebrew according to the [official Homebrew installation instructions](https://brew.sh/index.html).
1. Install Git by running `brew install git` from your terminal.
1. In a terminal, verify that Git works on your computer:
diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md
index 05b14b21f20..e349cf0bb92 100644
--- a/doc/topics/git/index.md
+++ b/doc/topics/git/index.md
@@ -8,104 +8,116 @@ type: index
# Git **(FREE ALL)**
Git is a [free and open source](https://git-scm.com/about/free-and-open-source)
-distributed version control system designed to handle everything from small to
-large projects with speed and efficiency.
+distributed version control system. It handles projects of all sizes quickly and
+efficiently, while providing support for rolling back changes when needed.
-[GitLab](https://about.gitlab.com) is a Git-based fully integrated platform for
-software development. Besides Git functionalities, GitLab has a lot of
-powerful [features](https://about.gitlab.com/features/) to enhance your
-[workflow](https://about.gitlab.com/topics/version-control/what-is-gitlab-flow/).
+GitLab is built on top of (and with) Git, and provides you a Git-based, fully-integrated
+platform for software development. GitLab adds many powerful
+[features](https://about.gitlab.com/features/) on top of Git to enhance your workflow.
-We've gathered some resources to help you to get the best from Git with GitLab.
+These resources can help you to get the best from using Git with GitLab.
-More information is also available on the [Git website](https://git-scm.com).
+## Learn about Git
-## Getting started
+New to Git? These resources can help you understand basic Git concepts before
+you dive in:
-The following resources can help you get started with Git:
-
-- [Git-ing started with Git](https://www.youtube.com/watch?v=Ce5nz5n41z4),
- a video introduction to Git.
-- [Make your first Git commit](../../tutorials/make_first_git_commit/index.md)
-- [Git Basics](https://git-scm.com/book/en/v2/Getting-Started-Git-Basics)
-- [Git on the Server - GitLab](https://git-scm.com/book/en/v2/Git-on-the-Server-GitLab)
-- [How to install Git](how_to_install_git/index.md)
- [Git concepts](terminology.md)
-- [Start using Git on the command line](../../gitlab-basics/start-using-git.md)
-- [GitLab Git Cheat Sheet (download)](https://about.gitlab.com/images/press/git-cheat-sheet.pdf)
-- Commits:
- - [Revert a commit](../../user/project/merge_requests/revert_changes.md#revert-a-commit)
- - [Cherry-picking a commit](../../user/project/merge_requests/cherry_pick_changes.md)
- - [Squash-and-merge](../../user/project/merge_requests/squash_and_merge.md)
- - [Signing commits](../../user/project/repository/gpg_signed_commits/index.md)
-- [Git stash](stash.md)
-- [Git file blame](../../user/project/repository/git_blame.md)
-- [Git file history](../../user/project/repository/git_history.md)
-- [Git tags](../../user/project/repository/tags/index.md)
-
-### Concepts
-
-The following are resources on version control concepts:
-
-- [Why Git is Worth the Learning Curve](https://about.gitlab.com/blog/2017/05/17/learning-curve-is-the-biggest-challenge-developers-face-with-git/)
-- [The future of SaaS hosted Git repository pricing](https://about.gitlab.com/blog/2016/05/11/git-repository-pricing/)
-- [Git website on version control](https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control)
-- [GitLab University presentation about Version Control](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit?usp=sharing)
-
-### Work with Git on the command line
-
-You can do many Git tasks from the command line:
-
-- [Cherry-pick](cherry_picking.md).
-- [Getting started with Git](../../tutorials/make_first_git_commit/index.md).
-- [Git add](git_add.md).
-- [Git stash](stash.md).
-- [Rollback commits](rollback_commits.md).
-- [Unstage](unstage.md).
-
-## Git tips
-
-The following resources may help you become more efficient at using Git:
+- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+ Video tutorial: [Git-ing started with Git](https://www.youtube.com/watch?v=Ce5nz5n41z4)
+- PDF download: [GitLab Git Cheat Sheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf)
-- [Useful Git commands](useful_git_commands.md) collected by the GitLab support team.
-- [Git Tips & Tricks](https://about.gitlab.com/blog/2016/12/08/git-tips-and-tricks/)
-- [Eight Tips to help you work better with Git](https://about.gitlab.com/blog/2015/02/19/8-tips-to-help-you-work-better-with-git/)
+The official Git documentation also offers information on
+[Git basics](https://git-scm.com/book/en/v2/Getting-Started-Git-Basics).
-## Troubleshooting Git
+## Begin using Git
-If you have problems with Git, the following may help:
+After you learn how Git works, you're ready to try it out. These resources are
+appropriate for when you're ready to start learning Git by doing:
-- [Numerous _undo_ possibilities in Git](numerous_undo_possibilities_in_git/index.md)
-- Learn a few [Git troubleshooting](troubleshooting_git.md) techniques
-
-## Branching strategies
+- [How to install Git](how_to_install_git/index.md)
+- [Start using Git on the command line](../../gitlab-basics/start-using-git.md)
+- Tutorial: [Make your first Git commit](../../tutorials/make_first_git_commit/index.md)
+- Tutorial: [How to update Git commit messages](../../tutorials/update_commit_messages/index.md)
+- The [GitLab CLI](https://gitlab.com/gitlab-org/cli/)
+
+A typical Git user encounters these concepts soon after starting to use Git:
+
+- [`git add`](git_add.md) to start tracking files with Git.
+- [Tags](../../user/project/repository/tags/index.md) and
+ [branches](../../user/project/repository/branches/index.md).
+- [How to undo mistakes](numerous_undo_possibilities_in_git/index.md),
+ including [`git reset`](rollback_commits.md).
+- View a chronological list of changes to a file with
+ [Git history](../../user/project/repository/git_history.md).
+- View a line-by-line editing history of a file with
+ [`git blame`](../../user/project/repository/git_blame.md).
+- [Sign commits](../../user/project/repository/signed_commits/gpg.md)
+ for increased accountability and trust.
+
+## Learn more complex commands
+
+When you're comfortable with basic Git commands, you're ready to dive into the
+more complex features of Git. These commands aren't required when creating
+straightforward changes. When you begin managing multiple branches or need more complex
+change management, you're ready for these features:
+
+- To stop tracking changes to a file, because you don't want to commit them,
+ [unstage the changes](unstage.md).
+- [Stash your changes](stash.md) when your current work isn't ready to create a commit locally,
+ but you need to switch branches to work on something else.
+- If you create many small commits locally, you can use
+ [squash and merge](../../user/project/merge_requests/squash_and_merge.md)
+ to combine them into fewer commits before pushing them.
+- [Cherry-pick](../../user/project/merge_requests/cherry_pick_changes.md) the contents
+ of a commit from one branch to another.
+- [Revert an existing commit](../../user/project/merge_requests/revert_changes.md#revert-a-commit)
+ if it contains changes you no longer want.
+
+## Learn branching and workflow strategies
+
+When you're comfortable with the creation and handling of individual branches,
+you're ready to learn about Git workflows and branching strategies:
- [Feature branch workflow](../../gitlab-basics/feature_branch_workflow.md)
-- [Git Branching - Branches in a Nutshell](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell)
-- [Git Branching - Branching Workflows](https://git-scm.com/book/en/v2/Git-Branching-Branching-Workflows)
-
-## Advanced use
-
-The following are advanced topics for those who want to get the most out of Git:
-
- [Introduction to Git rebase, force-push, and merge conflicts](git_rebase.md)
-- [Server Hooks](../../administration/server_hooks.md)
-- [Git Attributes](../../user/project/git_attributes.md)
-- Git Submodules: [Using Git submodules with GitLab CI](../../ci/git_submodules.md)
-- [Partial Clone](partial_clone.md)
-
-## API
-
-[Gitignore templates](../../api/templates/gitignores.md) API allow for
-Git-related queries from GitLab.
-
-## Git Large File Storage (LFS)
-
-The following relate to Git Large File Storage:
-
-- [Getting Started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
-- [Migrate an existing Git repository with Git LFS](lfs/migrate_to_git_lfs.md)
-- [Removing objects from LFS](lfs/index.md#removing-objects-from-lfs)
-- [GitLab Git LFS user documentation](lfs/index.md)
-- [GitLab Git LFS administrator documentation](../../administration/lfs/index.md)
-- [Towards a production quality open source Git LFS server](https://about.gitlab.com/blog/2015/08/13/towards-a-production-quality-open-source-git-lfs-server/)
+- From the official Git documentation:
+ - [Git Branching - Branches in a Nutshell](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell)
+ - [Git Branching - Branching Workflows](https://git-scm.com/book/en/v2/Git-Branching-Branching-Workflows)
+
+## Learn advanced topics in Git management
+
+Git and GitLab, combined together, provide advanced features for repository management:
+
+- Enforce commit policies and run tasks with [Git server hooks](../../administration/server_hooks.md).
+- Define which file types to treat as binary, and set the languages to use for
+ syntax highlighting with [the `.gitattributes` file](../../user/project/git_attributes.md).
+- To keep a Git repository as a subdirectory in another repository,
+ [use Git submodules with GitLab CI](../../ci/git_submodules.md).
+- When working with extremely large repositories, you can use a [partial clone](partial_clone.md)
+ of a repository instead of a complete clone.
+- GitLab APIs for [`.gitignore` files](../../api/templates/gitignores.md),
+ [commits](../../api/commits.md), [tags](../../api/tags.md),
+ and [repositories](../../api/repositories.md).
+
+### Git Large File Storage (LFS)
+
+Many Git projects must manage large binary assets, such as videos and images.
+Implementing Git Large File Storage can help manage these assets while keeping
+your repository small:
+
+- [User documentation](lfs/index.md) for Git LFS at GitLab
+- [Administrator documentation](../../administration/lfs/index.md) for Git LFS at GitLab
+- Blog post: [Getting Started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
+- [Migrate an existing Git repository](lfs/migrate_to_git_lfs.md) with Git LFS
+- [Remove objects](lfs/index.md#removing-objects-from-lfs) from Git LFS
+- Blog post: [Towards a production-quality open source Git LFS server](https://about.gitlab.com/blog/2015/08/13/towards-a-production-quality-open-source-git-lfs-server/)
+
+## Related topics
+
+- Official [Git documentation](https://git-scm.com), including
+ [Git on the Server - GitLab](https://git-scm.com/book/en/v2/Git-on-the-Server-GitLab)
+- [Git troubleshooting](troubleshooting_git.md) techniques
+- [Git commands](useful_git_commands.md) collected by the GitLab support team
+- Blog post: [Git Tips & Tricks](https://about.gitlab.com/blog/2016/12/08/git-tips-and-tricks/)
+- Blog post: [Eight Tips to help you work better with Git](https://about.gitlab.com/blog/2015/02/19/8-tips-to-help-you-work-better-with-git/)
diff --git a/doc/topics/git/lfs/index.md b/doc/topics/git/lfs/index.md
index d9c906ccd81..23d972e9aa7 100644
--- a/doc/topics/git/lfs/index.md
+++ b/doc/topics/git/lfs/index.md
@@ -32,7 +32,7 @@ Prerequisites:
To do this:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand the **Visibility, project features, permissions** section.
1. Turn on the **Git Large File Storage (LFS)** toggle.
@@ -299,3 +299,23 @@ You might choose to do this if you are using an appliance like a Nexus Repositor
GitLab can't verify LFS objects. Pushes then fail if you have GitLab LFS support enabled.
To stop push failure, LFS support can be disabled in the [Project settings](../../../user/project/settings/index.md), which also disables GitLab LFS value-adds (Verifying LFS objects, UI integration for LFS).
+
+### I/O timeout when pushing LFS objects
+
+You might get an error that states:
+
+```shell
+LFS: Put "http://your-instance.com/root/project.git/gitlab-lfs/objects/cc29e205d04a4062d0fb131700e8bfc8e54c44d0176a8dca22f40b24ef26d325/15": read tcp your-instance-ip:54544->your-instance-ip:443: i/o timeout
+error: failed to push some refs to 'ssh://your-instance.com:2222/root/project.git'
+```
+
+When network conditions are unstable, the Git LFS client might time out when trying to upload files
+if network conditions are unstable.
+
+The workaround is to set the client activity timeout a higher value.
+
+For example, to set the timeout to 60 seconds:
+
+```shell
+git config lfs.activitytimeout 60
+```
diff --git a/doc/topics/git/troubleshooting_git.md b/doc/topics/git/troubleshooting_git.md
index 43d5d746539..0cc7259a104 100644
--- a/doc/topics/git/troubleshooting_git.md
+++ b/doc/topics/git/troubleshooting_git.md
@@ -197,7 +197,7 @@ The root causes vary, so multiple potential solutions exist, and you may need to
apply more than one:
- If this error occurs when cloning a large repository, you can
- [decrease the cloning depth](../../ci/large_repositories/index.md#shallow-cloning)
+ [decrease the cloning depth](../../user/project/repository/managing_large_repositories.md#shallow-cloning)
to a value of `1`. For example:
```shell
diff --git a/doc/topics/offline/quick_start_guide.md b/doc/topics/offline/quick_start_guide.md
index 82a88b53dcf..301f73a268d 100644
--- a/doc/topics/offline/quick_start_guide.md
+++ b/doc/topics/offline/quick_start_guide.md
@@ -217,7 +217,9 @@ always fails because it uses `pool.ntp.org`. This error can be ignored but you c
## Enabling the Package Metadata Database
-Enabling the Package Metadata Database is required to enable [license scanning of CycloneDX files](../../user/compliance/license_scanning_of_cyclonedx_files).
+Enabling the Package Metadata Database is required to enable
+[Continuous Vulnerability Scanning](../../user/application_security/continuous_vulnerability_scanning/index.md)
+and [license scanning of CycloneDX files](../../user/compliance/license_scanning_of_cyclonedx_files/index.md).
This process requires the use of License and/or Advisory Data under what is collectively called the Package Metadata Database, which is licensed under the [EE License](https://storage.googleapis.com/prod-export-license-bucket-1a6c642fc4de57d4/LICENSE).
Note the following in relation to use of the Package Metadata Database:
@@ -225,8 +227,6 @@ Note the following in relation to use of the Package Metadata Database:
- The Package Metadata Database may contain links to third-party websites or resources. We provide these links only as a convenience and are not responsible for any third-party data, content, products, or services from those websites or resources or links displayed on such websites.
- The Package Metadata Database is based in part on information made available by third parties, and GitLab is not responsible for the accuracy or completeness of content made available.
-Enabling the Package Metadata Database is also required to enable Continuous Vulnerability Scans for Dependency Scanning (see [epic 9534](https://gitlab.com/groups/gitlab-org/-/epics/9534) tracking this work for more info).
-
Package metadata is stored in the following Google Cloud Provider (GCP) buckets:
- License Scanning - prod-export-license-bucket-1a6c642fc4de57d4
@@ -351,3 +351,29 @@ The directory for package metadata changed with the release of 16.2 from `vendor
```shell
sed -i '.bckup' -e 's#vendor/package_metadata_db#vendor/package_metadata/licenses#g' [FILE ...]
```
+
+### Troubleshooting
+
+#### Missing database data
+
+If license or advisory data is missing from the dependency list or MR pages, one possible cause of this is that the database has not been synchronized with the export data.
+
+`package_metadata` synchronization is triggered by using cron jobs ([advisory sync](https://gitlab.com/gitlab-org/gitlab/-/blob/16-3-stable-ee/config/initializers/1_settings.rb#L864-866) and [license sync](https://gitlab.com/gitlab-org/gitlab/-/blob/16-3-stable-ee/config/initializers/1_settings.rb#L855-857)) and imports only the package registry types enabled in [admin settings](../../administration/settings/security_and_compliance.md#choose-package-registry-metadata-to-sync).
+
+The file structure in `vendor/package_metadata` must coincide with the package registry type enabled above. For example, to sync `maven` license or advisory data, the package metadata directory under the Rails directory must have the following structure:
+
+- For licenses:`$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/licenses/v2/maven/**/*.ndjson`.
+- For advisories:`$GITLAB_RAILS_ROOT_DIR/vendor/package_metadata/advisories/v2/maven/**/*.ndjson`.
+
+After a successful run, data under the `pm_` tables in the database should be populated (check using [Rails console](../../administration/operations/rails_console.md)):
+
+- For licenses: `sudo gitlab-rails runner "puts \"Package model has #{PackageMetadata::Package.where(purl_type: 'maven').size} packages\""`
+- For advisories: `sudo gitlab-rails runner "puts \"Advisory model has #{PackageMetadata::AffectedPackage.where(purl_type: 'maven').size} packages\""`
+
+Additionally, checkpoint data should exist for the particular package registry being synchronized. For Maven, for example, there should be a checkpoint created after a successful sync run:
+
+- For licenses: `sudo gitlab-rails runner "puts \"maven data has been synced up to #{PackageMetadata::Checkpoint.where(data_type: 'licenses', purl_type: 'maven')}\""`
+- For advisories: `sudo gitlab-rails runner "puts \"maven data has been synced up to #{PackageMetadata::Checkpoint.where(data_type: 'advisories', purl_type: 'maven')}\""`
+
+Finally, you can check the [`application_json.log`](../../administration/logs/index.md#application_jsonlog) logs to verify that the
+sync job has run and is without error by searching for `DEBUG` messages where the class is `PackageMetadata::SyncService`. Example: `{"severity":"DEBUG","time":"2023-06-22T16:41:00.825Z","correlation_id":"a6e80150836b4bb317313a3fe6d0bbd6","class":"PackageMetadata::SyncService","message":"Evaluating data for licenses:gcp/prod-export-license-bucket-1a6c642fc4de57d4/v2/pypi/1694703741/0.ndjson"}`.
diff --git a/doc/tutorials/automate_runner_creation/index.md b/doc/tutorials/automate_runner_creation/index.md
new file mode 100644
index 00000000000..fa1373f1e3a
--- /dev/null
+++ b/doc/tutorials/automate_runner_creation/index.md
@@ -0,0 +1,220 @@
+---
+stage: none
+group: Tutorials
+info: For assistance with this tutorial, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
+---
+
+# Tutorial: Automate runner creation and registration **(FREE ALL)**
+
+This tutorial describes how to automate runner creation and registration.
+
+To automate runner creation and registration:
+
+1. [Create a personal access token](#create-a-personal-access-token).
+1. [Create a runner configuration](#create-a-runner-configuration).
+1. [Automate GitLab Runner installation and registration](#automate-runner-installation-and-registration).
+1. [View runners with the same configuration](#view-runners-with-the-same-configuration).
+
+NOTE:
+The instructions in this tutorial describe runner creation and registration
+with runner authentication tokens, which have replaced the deprecated registration
+method that uses registration tokens. For more information, see
+[The new runner registration workflow](../../ci/runners/new_creation_workflow.md#the-new-runner-registration-workflow).
+
+## Prerequisites
+
+- GitLab Runner must be installed on your GitLab instance.
+- To create shared runners, you must be an administrator.
+- To create group runners, you must be an administrator or have the Owner role for the group.
+- To create project runners, you must be an administrator or have the Maintainer role for the project.
+
+## Create an access token
+
+Create an access token so that you can use the REST API to create runners.
+
+You can create:
+
+- A personal access token to use with shared, group, and project runners.
+- A group or project access token to use with group and project runners.
+
+The access token is only visible once in the GitLab UI. After you leave the page,
+you no longer have access to the token. You should use a secrets management solution
+to store the token, like HashiCorp Vault or the Keeper Secrets Manager Terraform plugin.
+
+### Create a personal access token
+
+1. On the left sidebar, select your avatar.
+1. Select **Edit profile**.
+1. On the left sidebar, select **Access Tokens**.
+1. Select **Add new token**.
+1. Enter a name and expiry date for the token.
+ - The token expires on that date at midnight UTC.
+ - If you do not enter an expiry date, the expiry date is automatically set to 365 days later than the current date.
+ - By default, this date can be a maximum of 365 days later than the current date.
+1. In the **Select scopes** section, select the **create_runner** checkbox.
+1. Select **Create personal access token**.
+
+### Create a project or group access token
+
+WARNING:
+Project access tokens are treated as [internal users](../../development/internal_users.md).
+If an internal user creates a project access token, that token is able to access
+all projects that have visibility level set to [Internal](../../user/public_access.md).
+
+To create a project access token:
+
+1. On the left sidebar, select **Search or go to** and find your project or group.
+1. Select **Settings > Access Tokens**.
+1. Select **Add new token**
+1. Enter a name. The token name is visible to any user with permissions to view
+ the group or project.
+1. Enter an expiry date for the token.
+ - The token expires on that date at midnight UTC.
+ - If you do not enter an expiry date, the expiry date is automatically set
+ to 365 days later than the current date.
+ - By default, this date can be a maximum of 365 days later than the current date.
+ - An instance-wide [maximum lifetime](../../administration/settings/account_and_limit_settings.md#limit-the-lifetime-of-access-tokens)
+ setting can limit the maximum allowable lifetime on self-managed instances.
+1. From the **Select a role** dropdown list:
+ - For the project access token, select **Maintainer**.
+ - For the group access token, select **Owner**.
+1. In the **Select scopes** section, select the **create_runner** checkbox.
+1. Select **Create project access token**.
+
+## Create a runner configuration
+
+A runner configuration is where you configure runners to your requirements.
+
+After you create a runner configuration, you receive a runner authentication
+to register the runner. One or many runners can be linked to the
+same configuration when these runners are registered with the same runner authentication
+token. The runner configuration is stored in the `config.toml` file.
+
+To create a runner configuration, you can use:
+
+- The GitLab REST API.
+- The `gitlab_user_runner` Terraform resource.
+
+### With the GitLab REST API
+
+Prerequisites:
+
+- The URL for your GitLab instance. For example, if your project is hosted on
+ `gitlab.example.com/yourname/yourproject`, your GitLab instance URL is
+ `https://gitlab.example.com`.
+- For group or project runners, the ID number of the group or project. The ID number
+ is displayed in the project or group overview page, under the project or group
+ name.
+
+Use the access token in the [`POST /user/runners`](../../api/users.md#create-a-runner)
+REST endpoint to create a runner:
+
+1. Use `curl` to invoke the endpoint to create a runner:
+
+ ::Tabs
+
+ :::TabTitle Project
+
+ ```shell
+ curl --silent --request POST --url "https://gitlab.example.com/api/v4/user/runners"
+ --data "runner_type=project_type"
+ --data "project_id=<project_id>"
+ --data "description=<your_runner_description>"
+ --data "tag_list=<your_comma_separated_job_tags>"
+ --header "PRIVATE-TOKEN: <project_access_token>"
+ ```
+
+ :::TabTitle Group
+
+ ```shell
+ curl --silent --request POST --url "https://gitlab.example.com/api/v4/user/runners"
+ --data "runner_type=group_type"
+ --data "group_id=<group_id>"
+ --data "description=<your_runner_description>"
+ --data "tag_list=<your_comma_separated_job_tags>"
+ --header "PRIVATE-TOKEN: <group_access_token>"
+ ```
+
+ :::TabTitle Shared
+
+ ```shell
+ curl --silent --request POST --url "https://gitlab.example.com/api/v4/user/runners"
+ --data "runner_type=instance_type"
+ --data "description=<your_runner_description>"
+ --data "tag_list=<your_comma_separated_job_tags>"
+ --header "PRIVATE-TOKEN: <personal_access_token>"
+ ```
+
+ ::EndTabs
+
+1. Save the returned `token` value in a secure location or your secrets management
+ solution. The `token` value is returned only once in the API response.
+
+## With the `gitlab_user_runner` Terraform resource
+
+To create the runner configuration with Terraform, use the
+[`gitlab_user_runner` Terraform resource](https://gitlab.com/gitlab-org/terraform-provider-gitlab/-/blob/main/docs/resources/user_runner.md?ref_type=heads)
+from the [GitLab Terraform provider](https://gitlab.com/gitlab-org/terraform-provider-gitlab).
+
+Here's an example configuration block:
+
+```terraform
+resource "gitlab_user_runner" "example_runner" {
+ runner_type = "instance_type"
+ description = "my-runner"
+ tag_list = ["shell", "docker"]
+}
+```
+
+## Automate runner installation and registration
+
+If you host the runner on a virtual machine instance in a public cloud, you can automate
+runner installation and registration.
+
+After you create a runner and its configuration, you can use the same runner
+authentication token to register multiple runners with the same configuration.
+For example, you can deploy multiple shared runners with the same executor type
+and job tags to the target compute host. Each runner registered with the same runner
+authentication token has a unique `system_id`, which GitLab Runner
+generates randomly and stores in your local file system.
+
+Here's an example of an automation workflow you can use to register and deploy your
+runners to Google Compute Engine:
+
+1. Use [Terraform infrastructure as code](../../user/infrastructure/iac/index.md)
+ to install the runner application to a virtual machine hosted on Google Cloud
+ Platform (GCP).
+1. In the [GCP Terraform provider](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance),
+ use the `metadata` key to add the runner authentication token to the runner
+ configuration file on the GCP virtual machine.
+1. To register the runner with the target GitLab instance, use a `cloud-init` script
+ populated from the GCP Terraform provider. Here's an example:
+
+ ```shell
+ #!/bin/bash
+ apt update
+ curl --location "https://packages.gitlab.com/install/repositories/runner/
+ gitlab-runner/script.deb.sh" | bash
+ GL_NAME=$(curl 169.254.169.254/computeMetadata/v1/instance/name
+ --header "Metadata-Flavor:Google")
+ GL_EXECUTOR=$(curl 169.254.169.254/computeMetadata/v1/instance/attributes/
+ gl_executor --header "Metadata-Flavor:Google")
+ apt update
+ apt install -y gitlab-runner
+ gitlab-runner register --non-interactive --name="$GL_NAME" --url="https://gitlab.com"
+ --token="$RUNNER_TOKEN" --request-concurrency="12" --executor="$GL_EXECUTOR"
+ --docker-image="alpine:latest"
+ systemctl restart gitlab-runner
+ ```
+
+## View runners with the same configuration
+
+Now that you've automated your runner creation and automation, you can view
+the runners that use the same configuration in the GitLab UI.
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. On the left sidebar, select **CI/CD > Runners**.
+1. In the search box, enter the runner description or search the list of runners.
+1. To view the runners that use the same configuration, in the **Details** tab,
+ next to **Runners**, select **Show details**.
diff --git a/doc/tutorials/boards_for_teams/index.md b/doc/tutorials/boards_for_teams/index.md
index c316e42d218..fd61a4c03c5 100644
--- a/doc/tutorials/boards_for_teams/index.md
+++ b/doc/tutorials/boards_for_teams/index.md
@@ -99,7 +99,7 @@ projects you create later.
To create each label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your **Paperclip Software Factory** group.
+1. On the left sidebar, select **Search or go to** and find your **Paperclip Software Factory** group.
1. Select **Manage > Labels**.
1. Select **New label**.
1. In the **Title** field, enter the name of the label. Start with `Frontend`.
@@ -124,7 +124,7 @@ to manage issues from all the projects that you might create later in this group
To create a new group issue board:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your **Paperclip Software Factory** group.
+1. On the left sidebar, select **Search or go to** and find your **Paperclip Software Factory** group.
1. Select **Plan > Issue boards**.
1. Create the UX workflow and Frontend workflow boards.
diff --git a/doc/tutorials/build_application.md b/doc/tutorials/build_application.md
index c22cba7e0e8..2b1f63874b1 100644
--- a/doc/tutorials/build_application.md
+++ b/doc/tutorials/build_application.md
@@ -21,6 +21,7 @@ Use CI/CD pipelines to automatically build, test, and deploy your code.
| [Find CI/CD examples and templates](../ci/examples/index.md#cicd-examples) | Use these examples and templates to set up CI/CD for your use case. | |
| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Understand CI/CD rules](https://www.youtube.com/watch?v=QjQc-zeL16Q) (8m 56s) | Learn more about how to use CI/CD rules. | |
| [Use Auto DevOps to deploy an application](../topics/autodevops/cloud_deployments/auto_devops_with_gke.md) | Deploy an application to Google Kubernetes Engine (GKE). | |
+| [Using Buildah in a rootless container with GitLab Runner Operator on OpenShift](../ci/docker/buildah_rootless_tutorial.md) | Learn how to setup GitLab Runner Operator on OpenShift to build Docker images with Buildah in a rootless container | |
## Configure GitLab Runner
@@ -30,6 +31,7 @@ Set up runners to run jobs in a pipeline.
|-------|-------------|--------------------|
| [Create, register, and run your own project runner](create_register_first_runner/index.md) | Learn the basics of how to create and register a project runner that runs jobs for your project. | **{star}** |
| [Configure GitLab Runner to use the Google Kubernetes Engine](configure_gitlab_runner_to_use_gke/index.md) | Learn how to configure GitLab Runner to use the GKE to run jobs. | |
+| [Automate the creation of runners](https://about.gitlab.com/blog/2023/07/06/how-to-automate-creation-of-runners/) | Learn how to automate runner creation as an authenticated user to optimize your runner fleet. | |
## Publish a static website
diff --git a/doc/tutorials/compliance_pipeline/index.md b/doc/tutorials/compliance_pipeline/index.md
index 5396248d05a..710a2eb59ab 100644
--- a/doc/tutorials/compliance_pipeline/index.md
+++ b/doc/tutorials/compliance_pipeline/index.md
@@ -46,7 +46,7 @@ projects with the compliance framework applied.
To create the compliance pipeline project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial group` group.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial group` group.
1. Select **New project**.
1. Select **Create blank project**.
1. In the **Project name** field, enter `Tutorial compliance project`.
@@ -54,7 +54,7 @@ To create the compliance pipeline project:
To add compliance pipeline configuration to `Tutorial compliance project`:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial compliance project` project.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial compliance project` project.
1. Select **Build > Pipeline editor**.
1. Select **Configure pipeline**.
1. In the pipeline editor, replace the default configuration with:
@@ -74,7 +74,7 @@ The compliance framework is configured in the [new group](#create-a-new-group).
To configure the compliance framework:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial group` group.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial group` group.
1. Select **Settings > General**.
1. Expand **Compliance frameworks**.
1. Select **Add framework**.
@@ -87,7 +87,7 @@ To configure the compliance framework:
For convenience, make the new compliance framework the default for all new projects in the group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial group` group.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial group` group.
1. Select **Settings > General**.
1. Expand **Compliance frameworks**.
1. In the row for `Tutorial compliance framework`, select **Options** (**{ellipsis_v}**).
@@ -100,7 +100,7 @@ compliance pipeline configuration in their pipelines.
To create a new project for running the compliance pipeline configuration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial group` group.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial group` group.
1. Select **Create new** (**{plus}**) and **New project/repository**.
1. Select **Create blank project**.
1. In the **Project name** field, enter `Tutorial project`.
@@ -114,7 +114,7 @@ pipeline configuration in `Tutorial compliance project`.
To run the compliance pipeline configuration in `Tutorial project`:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial project` project.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial project` project.
1. Select **Build > Pipelines**.
1. Select **Run pipeline**.
1. On the **Run pipeline** page, select **Run pipeline**.
@@ -132,7 +132,7 @@ compliance pipeline configuration to refer to it.
To create the regular pipeline configuration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial project` project.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial project` project.
1. Select **Build > Pipeline editor**.
1. Select **Configure pipeline**.
1. In the pipeline editor, replace the default configuration with:
@@ -148,7 +148,7 @@ To create the regular pipeline configuration:
To combine the new project pipeline configuration with the compliance pipeline configuration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial compliance project` project.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial compliance project` project.
1. Select **Build > Pipeline editor**.
1. In the existing configuration, add:
@@ -162,7 +162,7 @@ To combine the new project pipeline configuration with the compliance pipeline c
To confirm the regular pipeline configuration is combined with the compliance pipeline configuration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `Tutorial project` project.
+1. On the left sidebar, select **Search or go to** and find the `Tutorial project` project.
1. Select **Build > Pipelines**.
1. Select **Run pipeline**.
1. On the **Run pipeline** page, select **Run pipeline**.
diff --git a/doc/tutorials/configure_gitlab_runner_to_use_gke/index.md b/doc/tutorials/configure_gitlab_runner_to_use_gke/index.md
index d9a6dbbb3f0..8fa2dbe3479 100644
--- a/doc/tutorials/configure_gitlab_runner_to_use_gke/index.md
+++ b/doc/tutorials/configure_gitlab_runner_to_use_gke/index.md
@@ -80,15 +80,11 @@ Now that you have a cluster, you're ready to install and configure the Kubernete
1. Install the Operator Lifecycle Manager (OLM), a tool that manages the Kubernetes Operators that
run on the cluster:
- <!-- markdownlint-disable -->
-
```shell
curl --silent --location "https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.24.0/install.sh" \
| bash -s v0.24.0
```
- <!-- markdownlint-enable -->
-
1. Install the Kubernetes Operator Catalog:
```shell
@@ -196,7 +192,6 @@ To check if runners are running in the GKE cluster, you can either:
```
- Check the job log in GitLab:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**)
- to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Jobs** and find the job.
1. To view the job log, select the job status.
diff --git a/doc/tutorials/convert_personal_namespace_to_group/index.md b/doc/tutorials/convert_personal_namespace_to_group/index.md
index 093dd04882a..39bfebb7f4e 100644
--- a/doc/tutorials/convert_personal_namespace_to_group/index.md
+++ b/doc/tutorials/convert_personal_namespace_to_group/index.md
@@ -56,7 +56,7 @@ Before you start the transfer process, make sure you:
To transfer a project to a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. Under **Transfer project**, choose the group to transfer the project to.
@@ -84,7 +84,7 @@ Finally, rename the new group's URL to the username of the original personal nam
To [change your group path](../../user/group/manage.md#change-a-groups-path) (group URL):
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Advanced** section.
1. Under **Change group URL**, enter the user's original username.
diff --git a/doc/tutorials/create_register_first_runner/index.md b/doc/tutorials/create_register_first_runner/index.md
index 05bf5cd8288..a16899509e7 100644
--- a/doc/tutorials/create_register_first_runner/index.md
+++ b/doc/tutorials/create_register_first_runner/index.md
@@ -53,7 +53,7 @@ In this file, you define:
- The structure and order of jobs that the runner should execute.
- The decisions the runner should make when specific conditions are encountered.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Project overview**.
1. Select the plus icon (**{plus}**), then select **New file**.
1. In the **Filename** field, enter `.gitlab-ci.yml`.
@@ -85,7 +85,7 @@ to GitLab so that it can pick up jobs from the project pipeline.
To create a project runner:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand the **Runners** section.
1. Select **New project runner**.
@@ -107,7 +107,7 @@ To create a project runner:
### Check the runner configuration file
-After you register the runner, the configuration and authentication token is saved to your `config.toml`. The runner uses the
+After you register the runner, the configuration and runner authentication token is saved to your `config.toml`. The runner uses the
token to authenticate with GitLab when picking up jobs from the job queue.
You can use the `config.toml` to
@@ -130,7 +130,7 @@ Here's what your `config.toml` should look like after you register and start the
Next, trigger a pipeline in your project so you can view your runner execute a job.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipelines**.
1. Select **Run pipeline**.
1. Select a job to view the job log. The output should look similar to this example, which shows
diff --git a/doc/tutorials/dependency_scanning.md b/doc/tutorials/dependency_scanning.md
index 90bc2ec96a2..6eb2592c2f4 100644
--- a/doc/tutorials/dependency_scanning.md
+++ b/doc/tutorials/dependency_scanning.md
@@ -138,7 +138,7 @@ need to upgrade the `fastify` package.
To fix the vulnerability:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. In the upper right, select **Edit > GitPod** and open
GitPod in a new tab.
1. If you are prompted to, select **Continue with GitLab**, then select **Authorize**.
diff --git a/doc/tutorials/export_sbom.md b/doc/tutorials/export_sbom.md
new file mode 100644
index 00000000000..f0bbf6febf6
--- /dev/null
+++ b/doc/tutorials/export_sbom.md
@@ -0,0 +1,95 @@
+---
+stage: Secure
+group: Composition Analysis
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Tutorial: Export dependency list in SBOM format **(ULTIMATE ALL)**
+
+Dependency Scanning output can be exported to the CycloneDX JSON format.
+
+This tutorial shows you how to generate a CycloneDX JSON SBOM for a pipeline, and then to upload it as a CI job artifact.
+
+## Prerequisites
+
+Set up Dependency Scanning. For detailed instructions, follow [the Dependency Scanning tutorial](dependency_scanning.md).
+
+## Create configuration files
+
+1. Create a [snippet](../api/snippets.md) with the following code.
+
+ Filename: `export.sh`
+
+ ```shell
+ #! /bin/sh
+
+ function create_export {
+ curl --silent \
+ --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" \
+ -X 'POST' --data "export_type=sbom" \
+ "http://gitlab.example.com/api/v4/pipelines/$CI_PIPELINE_ID/dependency_list_exports" \
+ | jq '.id'
+ }
+
+ function check_status {
+ curl --silent \
+ --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" \
+ --write-out "%{http_code}" --output /dev/null \
+ http://gitlab.example.com/api/v4/dependency_list_exports/$1
+ }
+
+ function download {
+ curl --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" \
+ --output "gl-sbom-merged-$CI_PIPELINE_ID.cdx.json" \
+ "http://gitlab.example.com/api/v4/dependency_list_exports/$1/download"
+ }
+
+ function export_sbom {
+ local ID=$(create_export)
+
+ for run in $(seq 0 3); do
+ local STATUS=$(check_status $ID)
+ # Status is 200 when JSON is generated.
+ # Status is 202 when generate JSON job is running.
+ if [ $STATUS -eq "200" ]; then
+ download $ID
+
+ exit 0
+ elif [ $STATUS -ne "202" ]; then
+ exit 1
+ fi
+
+ echo "Waiting for JSON to be generated"
+ sleep 5
+ done
+
+ exit 1
+ }
+
+ export_sbom
+ ```
+
+ The above script works in the following steps:
+
+ 1. Create a CycloneDX SBOM export for the current pipeline.
+ 1. Check the status of that export, and stop when it's ready.
+ 1. Download the CycloneDX SBOM file.
+
+1. Update `.gitlab-ci.yml` with the following code.
+
+ ```yaml
+ export-merged-sbom:
+ before_script:
+ - apk add --update jq curl
+ stage: .post
+ script:
+ - curl --output export.sh --url "https://gitlab.example.com/api/v4/snippets/<SNIPPET_ID>/raw"
+ - /bin/sh export.sh
+ artifacts:
+ paths:
+ - "gl-sbom-merged-*.cdx.json"
+ ```
+
+1. Go to **Build > Pipelines** and confirm that the latest pipeline completed successfully.
+
+In the job artifacts, `gl-sbom-merged-<pipeline_id>.cdx.json` file should be present.
diff --git a/doc/tutorials/fuzz_testing/index.md b/doc/tutorials/fuzz_testing/index.md
index e4c494e9b85..252a3501a32 100644
--- a/doc/tutorials/fuzz_testing/index.md
+++ b/doc/tutorials/fuzz_testing/index.md
@@ -59,7 +59,7 @@ a random buffer as a parameter.
To create the two fuzz target files:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `fuzz-testing-demo` project.
+1. On the left sidebar, select **Search or go to** and find the `fuzz-testing-demo` project.
1. Create a file in the root directory of the project.
1. Name the file `fuzz-sayhello.js` and add the following code:
diff --git a/doc/tutorials/hugo/index.md b/doc/tutorials/hugo/index.md
index 97c79e77392..5f466234a36 100644
--- a/doc/tutorials/hugo/index.md
+++ b/doc/tutorials/hugo/index.md
@@ -139,7 +139,7 @@ You'll see that GitLab has run your `test` and `pages` jobs.
To view your site, on the left-hand navigation, select **Settings > Pages**
-The `pages` job in your pipeline has deployed the contents of your `public` directory to GitLab Pages. Under **Access pages**, you should see the link in the format: `https://<your-namespace>.gitlab.io/<project-name>`.
+The `pages` job in your pipeline has deployed the contents of your `public` directory to GitLab Pages. Under **Access pages**, you should see the link in the format: `https://<your-namespace>.gitlab.io/<project-path>`.
You won't see this link if you haven't yet run your pipeline.
diff --git a/doc/tutorials/issue_triage/index.md b/doc/tutorials/issue_triage/index.md
index 38e4285c2ce..2634837edc8 100644
--- a/doc/tutorials/issue_triage/index.md
+++ b/doc/tutorials/issue_triage/index.md
@@ -102,7 +102,7 @@ However, they aren't mutually exclusive.
To create each label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Labels**.
1. Select **New label**.
1. In the **Title** field, enter the name of the label. Start with `type::bug`.
@@ -152,7 +152,7 @@ To set up your issue board:
1. Decide on the scope of the board. For example, create one that you'll use to assign
severity to issues.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your
+1. On the left sidebar, select **Search or go to** and find your
**Issue triage tutorial** project.
1. Select **Plan > Issue boards**.
1. In the upper-left corner of the issue board page, select the dropdown list with the current board name.
diff --git a/doc/tutorials/left_sidebar/img/admin_area_v16_4.png b/doc/tutorials/left_sidebar/img/admin_area_v16_4.png
new file mode 100644
index 00000000000..ca6a229f69c
--- /dev/null
+++ b/doc/tutorials/left_sidebar/img/admin_area_v16_4.png
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/project_selected_v16_0.png b/doc/tutorials/left_sidebar/img/project_selected_v16_0.png
deleted file mode 100644
index 534b06ac5de..00000000000
--- a/doc/tutorials/left_sidebar/img/project_selected_v16_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/project_selected_v16_4.png b/doc/tutorials/left_sidebar/img/project_selected_v16_4.png
new file mode 100644
index 00000000000..a15068a14d9
--- /dev/null
+++ b/doc/tutorials/left_sidebar/img/project_selected_v16_4.png
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/search_projects_v16_0.png b/doc/tutorials/left_sidebar/img/search_projects_v16_0.png
deleted file mode 100644
index 12182f24009..00000000000
--- a/doc/tutorials/left_sidebar/img/search_projects_v16_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/search_projects_v16_4.png b/doc/tutorials/left_sidebar/img/search_projects_v16_4.png
new file mode 100644
index 00000000000..966836f8d31
--- /dev/null
+++ b/doc/tutorials/left_sidebar/img/search_projects_v16_4.png
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/sidebar_middle_v16_1.png b/doc/tutorials/left_sidebar/img/sidebar_middle_v16_1.png
deleted file mode 100644
index 67e89c2c0a4..00000000000
--- a/doc/tutorials/left_sidebar/img/sidebar_middle_v16_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/sidebar_middle_v16_4.png b/doc/tutorials/left_sidebar/img/sidebar_middle_v16_4.png
new file mode 100644
index 00000000000..2556a4985d9
--- /dev/null
+++ b/doc/tutorials/left_sidebar/img/sidebar_middle_v16_4.png
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/sidebar_top_v16_1.png b/doc/tutorials/left_sidebar/img/sidebar_top_v16_1.png
deleted file mode 100644
index fcb56370fc7..00000000000
--- a/doc/tutorials/left_sidebar/img/sidebar_top_v16_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/sidebar_top_v16_4.png b/doc/tutorials/left_sidebar/img/sidebar_top_v16_4.png
new file mode 100644
index 00000000000..3bfe781f2b2
--- /dev/null
+++ b/doc/tutorials/left_sidebar/img/sidebar_top_v16_4.png
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/your_work_v16_0.png b/doc/tutorials/left_sidebar/img/your_work_v16_0.png
deleted file mode 100644
index f7b5ed4217d..00000000000
--- a/doc/tutorials/left_sidebar/img/your_work_v16_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorials/left_sidebar/img/your_work_v16_4.png b/doc/tutorials/left_sidebar/img/your_work_v16_4.png
new file mode 100644
index 00000000000..65e91b0077b
--- /dev/null
+++ b/doc/tutorials/left_sidebar/img/your_work_v16_4.png
Binary files differ
diff --git a/doc/tutorials/left_sidebar/index.md b/doc/tutorials/left_sidebar/index.md
index fee10fbe783..d30ade980dc 100644
--- a/doc/tutorials/left_sidebar/index.md
+++ b/doc/tutorials/left_sidebar/index.md
@@ -28,20 +28,19 @@ At the top of the left sidebar are several shortcuts. Use these shortcuts to
show and hide the left sidebar, create new items, search, and view your profile. You can also view your list of issues,
merge requests, and to-do items.
-![Top of sidebar](img/sidebar_top_v16_1.png)
+![Top of sidebar](img/sidebar_top_v16_4.png)
+NOTE:
If you have hidden the left sidebar, you can display it temporarily by hovering your cursor over the left edge of the GitLab window.
The next area of the left sidebar changes based on the information you're viewing. For example,
you might be viewing a project, exploring projects or groups, or viewing your profile.
-Use this area to switch to other areas of the left sidebar.
+To switch to other areas of the left sidebar, use **Search or go to**.
-![Context switching](img/sidebar_middle_v16_1.png)
+![Context switching](img/sidebar_middle_v16_4.png)
The rest of the left sidebar is populated based on the option you choose. For example,
-if you're in a project, the sidebar is project-specific:
-
-![Project-specific options](img/sidebar_bottom_v16_1.png)
+if you're in a project, the sidebar is project-specific.
## Find your project
@@ -49,19 +48,15 @@ Now let's go over a few common tasks you'll use the left sidebar for.
To start, we will find the project we want to work on.
-1. To explore all available projects, on the left sidebar, select **Explore**:
-
- ![Explore](img/explore_v16_0.png)
-
-1. On the right, above the list of projects, type search criteria.
- The search finds projects with a matching description.
+1. To explore all available projects, on the left sidebar, select **Search or go to**.
+1. Choose from the list of frequently visited projects, or
+ type a colon `:` followed by the project name:
- ![Search projects](img/search_projects_v16_0.png)
+ ![Search projects](img/search_projects_v16_4.png)
-1. When you find the project you want, select the project name.
- The left sidebar now shows project-specific options.
+The left sidebar now shows project-specific options.
- ![Project-specific options](img/project_selected_v16_0.png)
+![Project-specific options](img/project_selected_v16_4.png)
## Pin frequently used items
@@ -82,12 +77,12 @@ The items you pin while you're viewing a project are different than the items yo
## Use a more focused view
On the left sidebar, you can also choose a more focused view into the areas you have access to.
-Change the view to **Your work**:
+Select **Search or go to** and then select **Your work**:
-![Your work](img/your_work_v16_0.png)
+![Your work](img/your_work_v16_4.png)
## Go to the Admin Area
-The Admin Area is also available on the left sidebar:
+The Admin Area is also available on the left sidebar when you select **Search or go to**:
-![Admin Area](img/admin_area_v16_0.png)
+![Admin Area](img/admin_area_v16_4.png)
diff --git a/doc/tutorials/manage_user/index.md b/doc/tutorials/manage_user/index.md
index 91309d7cb42..df343fe5f08 100644
--- a/doc/tutorials/manage_user/index.md
+++ b/doc/tutorials/manage_user/index.md
@@ -79,8 +79,8 @@ You will now create subgroups to reflect this organization structure.
> Subgroups and projects must have visibility settings that are at least as restrictive as the visibility setting of their parent group. For example, you cannot have a private parent group and a public subgroup.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your groups**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my groups**.
1. Select **Development**. You should see an **Owner** label next to the group
name as you have the Owner role.
1. On the parent group's overview page, in the upper-right corner, select **New subgroup**.
@@ -106,7 +106,7 @@ for the organization.
You will now manually create the users for your organization. These are test
users. To create the first test user, Alex Smith:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Users**.
1. Select **New user**.
@@ -149,7 +149,7 @@ You can give users access to all projects in a group by adding them to that grou
First, you will add all the users to the parent group, Development.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the **Development** group.
+1. On the left sidebar, select **Search or go to** and find the **Development** group.
1. Select **Manage > Members**.
1. Select **Invite members**.
1. Complete the fields for the product manager, Alex Smith.
@@ -189,7 +189,7 @@ subgroups with the same role.
You can filter a subgroup to show which users are direct members of that subgroup,
and which members have inherited membership of that subgroup from the parent group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the **Development** group.
+1. On the left sidebar, select **Search or go to** and find the **Development** group.
1. Select the **User Experience** subgroup.
1. On the left sidebar, select **Subgroup information > Members**.
1. On the **Members** page, select the **Filter members** field.
@@ -209,7 +209,7 @@ them from the parent group.
Go back to the parent group and remove everyone except Alex Smith:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the parent group.
+1. On the left sidebar, select **Search or go to** and find the parent group.
1. Select **Manage > Members**.
1. On the member row you want to remove, select the vertical ellipsis (**{ellipsis_v}**)
and then select **Remove member**.
@@ -228,7 +228,7 @@ You will now add users directly to the different subgroups.
### Add users to the Product Management subgroup
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the **Development** group.
+1. On the left sidebar, select **Search or go to** and find the **Development** group.
1. Select the **Product Management** subgroup.
1. On the left sidebar, select **Subgroup information > Members**.
@@ -267,7 +267,7 @@ add users to the Engineering subgroup.
You are now going to invite some users to the Engineering subgroup.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the **Development** group.
+1. On the left sidebar, select **Search or go to** and find the **Development** group.
1. Select the **Engineering** subgroup.
1. On the left sidebar, select **Subgroup information > Members**. The only
members are you and Alex, both with the Owner role. These are inherited roles.
@@ -312,7 +312,7 @@ included in both nested subgroups due to inherited permissions.
Therefore, you will add these users to the appropriate nested subgroup directly
rather than to the User Experience subgroup.
-1. 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the **Development** group.
+1. 1. On the left sidebar, select **Search or go to** and find the **Development** group.
1. Select the **User Experience** subgroup, and then the **UX Design** subgroup.
1. On the left sidebar, select **Subgroup information > Members**. You and Alex
Smith are currently the only members. These are inherited roles.
@@ -371,7 +371,7 @@ need to work on, and that piece of work is for the whole organization. To organi
that work, you are going to create a project in the Development parent group, and
add different users to that project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the **Development** group.
+1. On the left sidebar, select **Search or go to** and find the **Development** group.
1. Select **Create new** (**{plus}**) and **New project/repository**.
1. Select **Create blank project**.
1. Enter the project details:
@@ -400,7 +400,7 @@ directly to the project.
## Add users to the project and parent group
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the **Release 2.0** project.
+1. On the left sidebar, select **Search or go to** and find the **Release 2.0** project.
1. On the left sidebar, select **Manage > Members**.
1. Select **Invite members**. Invite the following users:
@@ -433,7 +433,7 @@ projects by assigning roles.
You can also change the visibility of individual features in a project. You cannot
do this for groups.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the **Release 2.0** project.
+1. On the left sidebar, select **Search or go to** and find the **Release 2.0** project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. In **Project visibility**, you can who can see the project in the public access
diff --git a/doc/tutorials/move_personal_project_to_group/index.md b/doc/tutorials/move_personal_project_to_group/index.md
index 29849752f5f..73d22de6983 100644
--- a/doc/tutorials/move_personal_project_to_group/index.md
+++ b/doc/tutorials/move_personal_project_to_group/index.md
@@ -57,7 +57,7 @@ Before you move your project to a group:
Now you're ready to move your project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. Under **Transfer project**, choose the group to transfer the project to.
@@ -78,7 +78,7 @@ your related resources and tools, such as websites and package managers.
You can now view your project in your group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Look for your project under **Subgroups and projects**.
Start enjoying the benefits of a group! For example, as the group Owner, you can
diff --git a/doc/tutorials/plan_and_track.md b/doc/tutorials/plan_and_track.md
index 7dcafbd26ce..c5c2919cac7 100644
--- a/doc/tutorials/plan_and_track.md
+++ b/doc/tutorials/plan_and_track.md
@@ -12,8 +12,6 @@ issues, epics, and more.
| Topic | Description | Good for beginners |
|-------|-------------|--------------------|
| [GitLab Agile Project Management](https://levelup.gitlab.com/courses/gitlab-agile-project-management) | Learn how to use planning features to manage your projects in this self-paced course. | **{star}** |
-| [Create a project from a template](https://gitlab.com/projects/new#create_from_template) | Choose a project template and create a project with files to get you started. | |
-| [Migrate to GitLab](../user/project/import/index.md) | If you are coming to GitLab from another platform, you can import or convert your projects. | |
| [Build a protected workflow for your project](protected_workflow/index.md) | Set up a workflow for your teams, and enforce protections with approval rules. | |
| [Run an agile iteration](agile_sprint/index.md) | Use group, projects, and iterations to run an agile development iteration. |
| [Set up a single project for issue triage](issue_triage/index.md) | Use labels to set up a project for issue triage. | **{star}** |
diff --git a/doc/tutorials/protected_workflow/index.md b/doc/tutorials/protected_workflow/index.md
index b055faddc75..5ff798fce6b 100644
--- a/doc/tutorials/protected_workflow/index.md
+++ b/doc/tutorials/protected_workflow/index.md
@@ -62,7 +62,7 @@ Then you'll add these new groups as members of the `engineering` group.
First, create the new subgroup:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**)
+1. On the left sidebar, select **Search or go to**
and search for `engineering`. Select the group named `Engineering`:
![The engineering group in search results](img/search_engineering_v16_2.png)
@@ -75,7 +75,7 @@ First, create the new subgroup:
Next, add the subgroup as a member of the `engineering` group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**)
+1. On the left sidebar, select **Search or go to**
and search for `engineering`. Select the group named `Engineering`.
1. On the left sidebar, select **Manage > Members**.
1. On the top right, select **Invite a group**.
@@ -105,7 +105,7 @@ for projects owned by `engineering`. As a result:
To add a user to the `frontend` subgroup:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**)
+1. On the left sidebar, select **Search or go to**
and search for `frontend`. Select the `Frontend` group.
1. Select **Manage > Members**.
1. Select **Invite members**.
@@ -127,7 +127,7 @@ smaller subgroups you just created.
To create the new `excelsior` project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) and
+1. On the left sidebar, select **Search or go to** and
search for `engineering`. Select the group named `Engineering`.
1. On the overview page for the `engineering` group, on the left sidebar, at the top,
select **Create new...** (**{plus}**) and **In this group > New project/repository**.
@@ -162,7 +162,7 @@ GitLab Premium or Ultimate.
To add a CODEOWNERS file to your `excelsior` project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) and
+1. On the left sidebar, select **Search or go to** and
search for `Excelsior`. Select the project named `Excelsior`.
1. Next to the branch name, select the plus icon (**{plus}**), then **New file**:
![Create a new file in the project](img/new_file_v16_2.png)
diff --git a/doc/tutorials/scan_execution_policy/index.md b/doc/tutorials/scan_execution_policy/index.md
new file mode 100644
index 00000000000..d0122908e19
--- /dev/null
+++ b/doc/tutorials/scan_execution_policy/index.md
@@ -0,0 +1,197 @@
+---
+stage: Govern
+group: Security Policies
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Tutorial: Set up a scan execution policy **(ULTIMATE ALL)**
+
+This tutorial shows you how to create and apply a
+[scan execution policy](../../user/application_security/policies/scan-execution-policies.md).
+These policies enforce application security tools as part of the CI/CD pipeline. In this tutorial,
+you create a policy to enforce secret detection in the CI/CD pipeline of two projects.
+
+In this tutorial, you:
+
+- [Create project A](#create-project-a).
+- [Create the scan execution policy](#create-the-scan-execution-policy).
+- [Test the scan execution policy with project A](#test-the-scan-execution-policy-with-project-a).
+- [Create project B](#create-project-b).
+- [Link project B to the security policy project](#link-project-b-to-the-security-policy-project).
+- [Test the scan execution policy with project B](#test-the-scan-execution-policy-with-project-b).
+
+Prerequisite:
+
+- Permission to create new projects in an existing group.
+
+## Create project A
+
+In a standard workflow, you might already have an existing project. In this
+tutorial, you're starting with nothing, so the first step is to create a project.
+
+To create project A:
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **New project**.
+1. Select **Create blank project**.
+1. Complete the fields. For **Project name**, enter `go-example-a`.
+1. Select **Create project**.
+1. Select **Add (`+`) > New file**.
+1. Enter `helloworld.go` in the filename.
+1. Copy and paste the following example Go code into the file.
+
+ ```go
+ package main
+ import "fmt"
+ func main() {
+ fmt.Println("Hello world")
+ }
+ ```
+
+1. Select **Commit changes**.
+
+The next step is to create a scan execution policy. When the first security policy is created, a
+policy project is created. The policy project stores the security policies created in any projects
+that are linked to it. Keeping policies separate from the projects they protect makes your security
+configuration reusable and easier to maintain.
+
+## Create the scan execution policy
+
+To create the scan execution policy:
+
+1. On the left sidebar, select **Search or go to** and search for the `go-example-a` project.
+1. Go to **Secure > Policies**.
+1. Select **New policy**.
+1. In the **Scan execution policy** section, select **Select policy**.
+1. Complete the fields.
+ - **Name**: Enforce secret detection.
+ - **Policy status**: Enabled.
+ - **Actions**: Run a Secret Detection scan.
+ - **Conditions**: Triggers every time a pipeline runs for all branches.
+1. Select **Configure with a merge request**.
+
+ The policy project `go-example-a - Security project` is created, and a merge request is created.
+
+1. Optional. Review the generated policy YAML in the merge request's **Changes** tab.
+1. Go to the **Overview** tab and select **Merge**.
+1. On the left sidebar, select **Search or go to** and search for the `go-example-a` project.
+1. Go to **Secure > Policies**.
+
+You now have a scan execution policy that runs a secret detection scan on every MR, for any branch.
+Test the policy by creating a merge request in project A.
+
+## Test the scan execution policy with project A
+
+To test the scan execution policy:
+
+1. On the left sidebar, select **Search or go to** and find the project named `go-example-a`.
+1. Go to **Code > Repository**.
+1. Select the `helloworld.go` file.
+1. Select **Edit > Edit single file**.
+1. Add the following line immediately after the `fmt.Println("hello world")` line:
+
+ ```plaintext
+ var GitLabFeedToken = "feed_token=eFLISqaBym4EjAefkl58"
+ ```
+
+1. In the **Target Branch** field, enter `feature-a`.
+1. Select **Commit changes**.
+1. When the merge request page opens, select **Create merge request**.
+
+ Let's check if the scan execution policy worked. Remember that we specified that secret detection
+ is to run every time a pipeline runs, for any branch.
+
+1. In the merge request just created, go the **Pipelines** tab and select the created pipeline.
+
+ Here you can see that a secret detection job ran. Let's check if it detected the test secret.
+
+1. Select the secret detection job.
+
+ Near the bottom of the job's log, the following output confirms that the example secret was detected.
+
+ ```plaintext
+ [INFO] [secrets] [2023-09-04T03:46:36Z] â–¶ 3:46AM INF 1 commits scanned.
+ [INFO] [secrets] [2023-09-04T03:46:36Z] â–¶ 3:46AM INF scan completed in 60ms
+ [INFO] [secrets] [2023-09-04T03:46:36Z] â–¶ 3:46AM WRN leaks found: 1
+ ```
+
+You've seen the policy work for one project. Create another project and apply the same policy.
+
+## Create project B
+
+To create project B:
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **New project**.
+1. Select **Create blank project**.
+1. Complete the fields. For **Project name**, enter `go-example-b`.
+1. Select **Create project**.
+1. Select **Add (`+`) > New file**.
+1. Enter `helloworld.go` in the filename.
+1. Copy and paste the following example Go code into the file.
+
+ ```go
+ package main
+ import "fmt"
+ func main() {
+ fmt.Println("Hello world")
+ }
+ ```
+
+1. Select **Commit changes**.
+
+Now that you have another project, you link it to the same policy project.
+
+## Link project B to the security policy project
+
+To link project B to the security policy project:
+
+1. On the left sidebar, select **Search or go to** and find the `go-example-b` project.
+1. Go to **Secure > Policies**.
+1. Select **Edit policy project**.
+1. Select the dropdown list, then search for the security policy project created at the start of
+ this tutorial.
+1. Select **Save**.
+
+Linking project B to the same policy project resulted in the same policy being applied. A scan
+execution policy runs a secret detection scan on every MR, for any branch. Let's test the
+policy by creating an MR in project B.
+
+## Test the scan execution policy with project B
+
+To test the scan execution policy:
+
+1. On the left sidebar, select **Search or go to** and find the `go-example-b` project.
+1. Go to **Code > Repository**.
+1. Select the `helloworld.go` file.
+1. Select **Edit > Edit single file**.
+1. Add the following line immediately after the `fmt.Println("hello world")` line:
+
+ ```plaintext
+ var AdobeClient = "4ab4b080d9ce4072a6be2629c399d653"
+ ```
+
+1. In the **Target Branch** field, enter `feature-b`.
+1. Select **Commit changes**.
+1. When the merge request page opens, select **Create merge request**.
+
+ Let's check if the scan execution policy worked. Remember that we specified that secret detection
+ is to run every time a pipeline runs, for any branch.
+
+1. In the merge request just created, go the **Pipelines** tab and select the created pipeline.
+
+1. In the merge request just created, select the pipeline's ID.
+
+ Here you can see that a secret detection job ran. Let's check if it detected the test secret.
+
+1. Select the secret detection job.
+
+ Near the bottom of the job's log, the following output confirms that the example secret was detected.
+
+ ```plaintext
+ [INFO] [secrets] [2023-09-04T04:22:28Z] â–¶ 4:22AM INF 1 commits scanned.
+ [INFO] [secrets] [2023-09-04T04:22:28Z] â–¶ 4:22AM INF scan completed in 58.2ms
+ [INFO] [secrets] [2023-09-04T04:22:28Z] â–¶ 4:22AM WRN leaks found: 1
+ ```
+
+Congratulations. You've learned how to create a scan execution policy and enforce it on projects.
diff --git a/doc/tutorials/scan_result_policy/index.md b/doc/tutorials/scan_result_policy/index.md
index 1c23d6a36eb..dabc311135a 100644
--- a/doc/tutorials/scan_result_policy/index.md
+++ b/doc/tutorials/scan_result_policy/index.md
@@ -35,7 +35,7 @@ To set up a scan result policy:
Next, you'll add a scan result policy to your test project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `sast-scan-result-policy` project.
+1. On the left sidebar, select **Search or go to** and find the `sast-scan-result-policy` project.
1. Select **Secure > Policies**.
1. Select **New policy**.
1. In **Scan result policy**, select **Select policy**.
@@ -60,7 +60,7 @@ Next, you'll add a scan result policy to your test project:
The application creates a new project to store the policies linked to it, and creates a merge request to define the policy.
1. Select **Merge**.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `sast-scan-result-policy` project.
+1. On the left sidebar, select **Search or go to** and find the `sast-scan-result-policy` project.
1. Select **Secure > Policies**.
You can see the list of policies added in the previous steps.
@@ -69,7 +69,7 @@ Next, you'll add a scan result policy to your test project:
Nice work, you've created a scan result policy. To test it, create some vulnerabilities and check the result:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the `sast-scan-result-policy` project.
+1. On the left sidebar, select **Search or go to** and find the `sast-scan-result-policy` project.
1. Select **Code > Repository**.
1. From the **Add** (**{plus}**) dropdown list, select **New file**.
1. In the **Filename** field enter `main.ts`.
diff --git a/doc/tutorials/secure_application.md b/doc/tutorials/secure_application.md
index 54235d0a6dc..606ca4d2909 100644
--- a/doc/tutorials/secure_application.md
+++ b/doc/tutorials/secure_application.md
@@ -11,8 +11,10 @@ GitLab can check your application for security vulnerabilities and that it meets
| Topic | Description | Good for beginners |
|-------|-------------|--------------------|
| [Set up dependency scanning](dependency_scanning.md) | Learn how to detect vulnerabilities in an application's dependencies. | **{star}** |
+| [Export Dependency List in SBOM format](export_sbom.md) | Learn how to export an application's dependencies to the CycloneDX SBOM format. | **{star}** |
| [Create a compliance pipeline](compliance_pipeline/index.md) | Learn how to create compliance pipelines for your groups. | **{star}** |
| [Set up a scan result policy](scan_result_policy/index.md) | Learn how to configure a scan result policy that takes action based on scan results. | **{star}** |
+| [Set up a scan execution policy](scan_execution_policy/index.md) | Learn how to create a scan execution policy to enforce security scanning of your project. | **{star}** |
| [Scan a Docker container for vulnerabilities](container_scanning/index.md) | Learn how to use container scanning templates to add container scanning to your projects. | **{star}** |
| [Get started with GitLab application security](../user/application_security/get-started-security.md) | Follow recommended steps to set up security tools. | |
| [GitLab Security Essentials](https://levelup.gitlab.com/courses/security-essentials) | Learn about the essential security capabilities of GitLab in this self-paced course. | |
diff --git a/doc/tutorials/update_commit_messages/index.md b/doc/tutorials/update_commit_messages/index.md
index f6d92b5c13f..90626d95c32 100644
--- a/doc/tutorials/update_commit_messages/index.md
+++ b/doc/tutorials/update_commit_messages/index.md
@@ -12,7 +12,7 @@ that your commit message didn't completely align with a project's
[commit message guidelines](../../development/contributing/merge_request_workflow.md#commit-messages-guidelines).
Updating the message can be tricky if you don't have much practice with using Git
-from the command line interface (CLI). But don't worry, even if you have only ever worked in
+from the command-line interface (CLI). But don't worry, even if you have only ever worked in
the GitLab UI, we'll walk you through the steps to use the CLI.
This tutorial explains how to rewrite commit messages in both cases:
@@ -33,7 +33,7 @@ You must have:
- A GitLab project with a Git branch containing commits that you want to update.
- Git [installed on your local machine](../../topics/git/how_to_install_git/index.md).
-- The ability to get to your local machine's command line interface (CLI). In macOS,
+- The ability to get to your local machine's command-line interface (CLI). In macOS,
you can use Terminal. In Windows, you can use PowerShell. Linux users are probably
already familiar with their system's CLI.
- Familiarity with your system's default editor. This tutorial assumes your editor is Vim,
diff --git a/doc/tutorials/website_project_with_analytics/index.md b/doc/tutorials/website_project_with_analytics/index.md
index a0a78b68585..c75ec27fd24 100644
--- a/doc/tutorials/website_project_with_analytics/index.md
+++ b/doc/tutorials/website_project_with_analytics/index.md
@@ -131,20 +131,20 @@ To create an Insights report, in the `My website` project:
```yaml
bugsCharts:
- title: "Charts for bugs"
- charts:
- - title: "Monthly bugs created"
- description: "Open bugs created per month"
- type: bar
- query:
- data_source: issuables
- params:
- issuable_type: issue
- issuable_state: opened
- filter_labels:
- - bug
- group_by: month
- period_limit: 12
+ title: "Charts for bugs"
+ charts:
+ - title: "Monthly bugs created"
+ description: "Open bugs created per month"
+ type: bar
+ query:
+ data_source: issuables
+ params:
+ issuable_type: issue
+ issuable_state: opened
+ filter_labels:
+ - bug
+ group_by: month
+ period_limit: 12
```
1. Select **Commit changes**.
diff --git a/doc/update/background_migrations.md b/doc/update/background_migrations.md
index cbdcfef3bae..5a4b19016f8 100644
--- a/doc/update/background_migrations.md
+++ b/doc/update/background_migrations.md
@@ -30,7 +30,7 @@ are created by GitLab developers and run automatically on upgrade. However, such
limited in scope to help with migrating some `integer` database columns to `bigint`. This is needed to
prevent integer overflow for some tables.
-Some installations [may need to run GitLab 14.0 for at least a day](index.md#1400)
+Some installations [may need to run GitLab 14.0 for at least a day](versions/gitlab_14_changes.md#1400)
to complete the database changes introduced by that upgrade.
Batched background migrations are handled by Sidekiq and
@@ -67,7 +67,7 @@ Prerequisites:
To check the status of batched background migrations:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Monitoring > Background Migrations**.
1. Select **Queued** or **Finalizing** to see incomplete migrations,
@@ -190,26 +190,34 @@ the number of batched background migrations executed in parallel:
ApplicationSetting.update_all(database_max_running_batched_background_migrations: 4)
```
-### Fix and retry failed batched background migrations
+### Resolve failed batched background migrations
+
+If a batched background migration fails, [fix and retry](#fix-and-retry-the-migration) it.
+If the migration continues to fail with an error, either:
+
+- [Finish the failed migration manually](#finish-a-failed-migration-manually)
+- [Mark the failed migration finished](#mark-a-failed-migration-finished)
+
+#### Fix and retry the migration
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67504) in GitLab 14.3.
-If you [check the status](#check-the-status-of-batched-background-migrations) of batched background migrations,
-some migrations might display in the **Failed** tab with a **failed** status:
+All failed batched background migrations must be resolved to upgrade to a newer
+version of GitLab. If you [check the status](#check-the-status-of-batched-background-migrations)
+of batched background migrations, some migrations might display in the **Failed** tab
+with a **failed** status:
![failed batched background migrations table](img/batched_background_migrations_failed_v14_3.png)
-You must resolve all failed batched background migrations to upgrade to a newer
-version of GitLab.
-
To determine why the batched background migration failed,
-[view the failure error logs](../development/database/batched_background_migrations.md#viewing-failure-error-logs) or:
+[view the failure error logs](../development/database/batched_background_migrations.md#viewing-failure-error-logs)
+or view error information in the UI.
Prerequisites:
- You must have administrator access to the instance.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Monitoring > Background Migrations**.
1. Select the **Failed** tab. This displays a list of failed batched background migrations.
@@ -219,13 +227,13 @@ Prerequisites:
If you are a GitLab customer, consider opening a [Support Request](https://support.gitlab.com/hc/en-us/requests/new)
to debug why the batched background migrations failed.
-To correct the problem, you can retry the failed batched background migrations:
+To correct the problem, you can retry the failed migration.
Prerequisites:
- You must have administrator access to the instance.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Monitoring > Background Migrations**.
1. Select the **Failed** tab. This displays a list of failed batched background migrations.
@@ -235,6 +243,111 @@ To monitor the retried batched background migrations, you can
[check the status of batched background migrations](#check-the-status-of-batched-background-migrations)
on a regular interval.
+#### Finish a failed migration manually
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62634) in GitLab 14.1.
+
+To manually finish a batched background migration that failed with an error,
+use the information in the failure error logs or the database:
+
+::Tabs
+
+:::TabTitle From the failure error logs
+
+1. [View the failure error logs](../development/database/batched_background_migrations.md#viewing-failure-error-logs)
+ and look for an `An error has occurred, all later migrations canceled` error message, like this:
+
+ ```plaintext
+ StandardError: An error has occurred, all later migrations canceled:
+
+ Expected batched background migration for the given configuration to be marked as
+ 'finished', but it is 'active':
+ {:job_class_name=>"CopyColumnUsingBackgroundMigrationJob",
+ :table_name=>"push_event_payloads",
+ :column_name=>"event_id",
+ :job_arguments=>[["event_id"],
+ ["event_id_convert_to_bigint"]]
+ }
+ ```
+
+1. Run the following command, replacing the values in angle brackets with the correct arguments:
+
+ ```shell
+ sudo gitlab-rake gitlab:background_migrations:finalize[<job_class_name>,<table_name>,<column_name>,'<job_arguments>']
+ ```
+
+ When dealing with multiple arguments, such as `[["id"],["id_convert_to_bigint"]]`, escape the
+ comma between each argument with a backslash <code>&#92;</code> to prevent an invalid character error.
+ For example, to finish the migration from the previous step:
+
+ ```shell
+ sudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,push_event_payloads,event_id,'[["event_id"]\, ["event_id_convert_to_bigint"]]']
+ ```
+
+:::TabTitle From the database
+
+ 1. [Check the status](#check-the-status-of-batched-background-migrations) of the
+ migration in the database.
+ 1. Use the query results to construct a migration command, replacing the values
+ in angle brackets with the correct arguments:
+
+ ```shell
+ sudo gitlab-rake gitlab:background_migrations:finalize[<job_class_name>,<table_name>,<column_name>,'<job_arguments>']
+ ```
+
+ For example, if the query returns this data:
+
+ - `job_class_name`: `CopyColumnUsingBackgroundMigrationJob`
+ - `table_name`: `events`
+ - `column_name`: `id`
+ - `job_arguments`: `[["id"], ["id_convert_to_bigint"]]`
+
+ When dealing with multiple arguments, such as `[["id"],["id_convert_to_bigint"]]`, escape the
+ comma between each argument with a backslash <code>&#92;</code> to prevent an invalid character error.
+ The command should be:
+
+ ```shell
+ sudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,events,id,'[["id"]\, ["id_convert_to_bigint"]]']
+ ```
+
+::EndTabs
+
+#### Mark a failed migration finished
+
+WARNING:
+[Contact GitLab Support](https://about.gitlab.com/support/#contact-support) before using
+these instructions. This action can cause data loss, and make your instance fail
+in ways that are difficult to recover from.
+
+There can be cases where the background migration fails: when jumping too many version upgrades,
+or backward-incompatible database schema changes. (For an example, see [issue 393216](https://gitlab.com/gitlab-org/gitlab/-/issues/393216)).
+Failed background migrations prevent further application upgrades.
+
+When the background migration is determined to be "safe" to skip, the migration can be manually marked finished:
+
+WARNING:
+Make sure you create a backup before proceeding.
+
+```ruby
+# Start the rails console
+
+connection = ApplicationRecord.connection # or Ci::ApplicationRecord.connection, depending on which DB was the migration scheduled
+
+Gitlab::Database::SharedModel.using_connection(connection) do
+ migration = Gitlab::Database::BackgroundMigration::BatchedMigration.find_for_configuration(
+ Gitlab::Database.gitlab_schemas_for_connection(connection),
+ 'BackfillUserDetailsFields',
+ :users,
+ :id,
+ []
+ )
+
+ # mark all jobs completed
+ migration.batched_jobs.update_all(status: Gitlab::Database::BackgroundMigration::BatchedJob.state_machine.states['succeeded'].value)
+ migration.update_attribute(:status, Gitlab::Database::BackgroundMigration::BatchedMigration.state_machine.states[:finished].value)
+end
+```
+
## Background migrations
In GitLab 13, background migrations were not batched. In GitLab 14 and later, this
@@ -303,6 +416,8 @@ sudo -u git -H bundle exec rails runner -e production 'puts Gitlab::Database::Ba
## Troubleshooting
+<!-- Linked from lib/gitlab/database/migrations/batched_background_migration_helpers.rb -->
+
### Database migrations failing because of batched background migration not finished
When updating to GitLab version 14.2 or later, database migrations might fail with a message like:
@@ -319,8 +434,8 @@ Expected batched background migration for the given configuration to be marked a
}
```
-First, check if you have followed the [version-specific upgrade instructions for 14.2](../update/index.md#1420).
-If you have, you can [manually finish the batched background migration](#manually-finishing-a-batched-background-migration).
+First, check if you have followed the [version-specific upgrade instructions for 14.2](../update/versions/gitlab_14_changes.md#1420).
+If you have, you can [manually finish the batched background migration](#finish-a-failed-migration-manually)).
If you haven't, choose one of the following methods:
1. [Rollback and upgrade](#roll-back-and-follow-the-required-upgrade-path) through one of the required
@@ -334,7 +449,7 @@ version and manually ensuring that the batched migrations complete successfully.
1. Update to either 14.0.5 or 14.1 **before** updating to 14.2+
1. [Check the status](#check-the-status-of-batched-background-migrations) of the batched background migrations and
make sure they are all marked as finished before attempting to upgrade again. If any remain marked as active,
-you can [manually finish them](#manually-finishing-a-batched-background-migration).
+you can [manually finish them](#finish-a-failed-migration-manually).
#### Roll forward and finish the migrations on the upgraded version
@@ -344,7 +459,7 @@ To run all the batched background migrations, it can take a significant amount o
depending on the size of your GitLab installation.
1. [Check the status](#check-the-status-of-batched-background-migrations) of the batched background migrations in the
-database, and [manually run them](#manually-finishing-a-batched-background-migration) with the appropriate
+database, and [manually run them](#finish-a-failed-migration-manually) with the appropriate
arguments until the status query returns no rows.
1. When the status of all of all them is marked as complete, re-run migrations for your installation.
1. [Complete the database migrations](../administration/raketasks/maintenance.md#run-incomplete-database-migrations) from your GitLab upgrade:
@@ -368,89 +483,9 @@ version and wait for the batched background migrations to finish.
1. [Check the status](#check-the-status-of-batched-background-migrations) of the batched background migration from
the error message, and make sure it is listed as finished. If it is still active, either wait until it is done,
-or [manually finish it](#manually-finishing-a-batched-background-migration).
+or [manually finish it](#finish-a-failed-migration-manually).
1. Re-run migrations for your installation, so the remaining post-deployment migrations finish.
-### Manually finishing a batched background migration
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62634) in GitLab 14.1
-
-If you need to manually finish a batched background migration due to an
-error, you can run:
-
-```shell
-sudo gitlab-rake gitlab:background_migrations:finalize[<job_class_name>,<table_name>,<column_name>,'<job_arguments>']
-```
-
-Replace the values in angle brackets with the correct
-arguments. For example, if you receive an error similar to this:
-
-```plaintext
-StandardError: An error has occurred, all later migrations canceled:
-
-Expected batched background migration for the given configuration to be marked as
-'finished', but it is 'active':
- {:job_class_name=>"CopyColumnUsingBackgroundMigrationJob",
- :table_name=>"push_event_payloads",
- :column_name=>"event_id",
- :job_arguments=>[["event_id"],
- ["event_id_convert_to_bigint"]]
- }
-```
-
-Plug the arguments from the error message into the command:
-
-```shell
-sudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,push_event_payloads,event_id,'[["event_id"]\, ["event_id_convert_to_bigint"]]']
-```
-
-If you need to manually run a batched background migration to continue an upgrade, you can
-[check the status](#check-the-status-of-batched-background-migrations) in the database and get the
-arguments from the query results. For example, if the query returns this:
-
-```plaintext
- job_class_name | table_name | column_name | job_arguments
----------------------------------------+------------+-------------+------------------------------------
- CopyColumnUsingBackgroundMigrationJob | events | id | [["id"], ["id_convert_to_bigint"]]
- ```
-
-The results from the query can be plugged into the command:
-
-```shell
-sudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,events,id,'[["id"]\, ["id_convert_to_bigint"]]']
-```
-
-#### Mark a batched migration finished
-
-There can be cases where the background migration fails: when jumping too many version upgrades,
-or backward-incompatible database schema changes. (For an example, see [issue 393216](https://gitlab.com/gitlab-org/gitlab/-/issues/393216)).
-Failed background migrations prevent further application upgrades.
-
-When the background migration is determined to be "safe" to skip, the migration can be manually marked finished:
-
-WARNING:
-Make sure you create a backup before proceeding.
-
-```ruby
-# Start the rails console
-
-connection = ApplicationRecord.connection # or Ci::ApplicationRecord.connection, depending on which DB was the migration scheduled
-
-Gitlab::Database::SharedModel.using_connection(connection) do
- migration = Gitlab::Database::BackgroundMigration::BatchedMigration.find_for_configuration(
- Gitlab::Database.gitlab_schemas_for_connection(connection),
- 'BackfillUserDetailsFields',
- :users,
- :id,
- []
- )
-
- # mark all jobs completed
- migration.batched_jobs.update_all(status: Gitlab::Database::BackgroundMigration::BatchedJob.state_machine.states['succeeded'].value)
- migration.update_attribute(:status, Gitlab::Database::BackgroundMigration::BatchedMigration.state_machine.states[:finished].value)
-end
-```
-
### The `BackfillNamespaceIdForNamespaceRoute` batched migration job fails
In GitLab 14.8, the `BackfillNamespaceIdForNamespaceRoute` batched background migration job
@@ -516,26 +551,26 @@ of Sidekiq jobs that perform various database or file updates.
`BackfillDraftStatusOnMergeRequests` can be permanently stuck in a
**pending** state across upgrades when the instance lacks records that match
the migration's target. To clean up this stuck migration, see the
- [14.2.0 version-specific instructions](index.md#1420).
+ [14.2.0 version-specific instructions](versions/gitlab_14_changes.md#1420).
- GitLab 14.4 introduced an issue where a background migration named
`PopulateTopicsTotalProjectsCountCache` can be permanently stuck in a
**pending** state across upgrades when the instance lacks records that match
the migration's target. To clean up this stuck migration, see the
- [14.4.0 version-specific instructions](index.md#1440).
+ [14.4.0 version-specific instructions](versions/gitlab_14_changes.md#1440).
- GitLab 14.5 introduced an issue where a background migration named
`UpdateVulnerabilityOccurrencesLocation` can be permanently stuck in a
**pending** state across upgrades when the instance lacks records that match
the migration's target. To clean up this stuck migration, see the
- [14.5.0 version-specific instructions](index.md#1450).
+ [14.5.0 version-specific instructions](versions/gitlab_14_changes.md#1450).
- GitLab 14.8 introduced an issue where a background migration named
`PopulateTopicsNonPrivateProjectsCount` can be permanently stuck in a
**pending** state across upgrades. To clean up this stuck migration, see the
- [14.8.0 version-specific instructions](index.md#1480).
+ [14.8.0 version-specific instructions](versions/gitlab_14_changes.md#1480).
- GitLab 14.9 introduced an issue where a background migration named
`ResetDuplicateCiRunnersTokenValuesOnProjects` can be permanently stuck in a
**pending** state across upgrades when the instance lacks records that match
the migration's target. To clean up this stuck migration, see the
- [14.9.0 version-specific instructions](index.md#1490).
+ [14.9.0 version-specific instructions](versions/gitlab_14_changes.md#1490).
For other background migrations stuck in pending, run the following check. If
it returns non-zero and the count does not decrease over time, follow the rest
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 08a5a3a7549..153119da1cc 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -46,6 +46,108 @@ For deprecation reviewers (Technical Writers only):
{::options parse_block_html="true" /}
<div class="js-deprecation-filters"></div>
+<div class="milestone-wrapper" data-milestone="18.0">
+
+## GitLab 18.0
+
+<div class="deprecation breaking-change" data-milestone="18.0">
+
+### GitLab Runner registration token in Runner Operator
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">15.6</span>
+- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/382077).
+</div>
+
+The [`runner-registration-token`](https://docs.gitlab.com/runner/install/operator.html#install-the-kubernetes-operator) parameter that uses the OpenShift and Kubernetes Vanilla Operator to install a runner on Kubernetes is deprecated. Authentication tokens will be used to register runners instead. Registration tokens, and support for certain configuration arguments,
+will be removed in GitLab 18.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
+The configuration arguments disabled for authentication tokens are:
+
+- `--locked`
+- `--access-level`
+- `--run-untagged`
+- `--tag-list`
+
+This change is a breaking change. You should use an [authentication token](../ci/runners/register_runner.md) in the `gitlab-runner register` command instead.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="18.0">
+
+### Registration tokens and server-side runner arguments in `gitlab-runner register` command
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">15.6</span>
+- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/380872).
+</div>
+
+Registration tokens and certain configuration arguments in the command `gitlab-runner register` that [registers](https://docs.gitlab.com/runner/register/) a runner, are deprecated.
+Authentication tokens will be used to register runners instead. Registration tokens, and support for certain configuration arguments,
+will be removed in GitLab 18.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
+The configuration arguments disabled for authentication tokens are:
+
+- `--locked`
+- `--access-level`
+- `--run-untagged`
+- `--maximum-timeout`
+- `--paused`
+- `--tag-list`
+- `--maintenance-note`
+
+This change is a breaking change. You should [create a runner in the UI](../ci/runners/register_runner.md) to add configurations, and use the authentication token in the `gitlab-runner register` command instead.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="18.0">
+
+### Support for REST API endpoints that reset runner registration tokens
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">15.7</span>
+- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/383341).
+</div>
+
+The support for runner registration tokens is deprecated. As a consequence, the REST API endpoints to reset a registration token are also deprecated and will
+return the HTTP `410 Gone` status code in GitLab 18.0.
+The deprecated endpoints are:
+
+- `POST /runners/reset_registration_token`
+- `POST /projects/:id/runners/reset_registration_token`
+- `POST /groups/:id/runners/reset_registration_token`
+
+We plan to implement a new method to bind runners to a GitLab instance
+as part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/ci/runners/new_creation_workflow.html).
+The work is planned in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/7633).
+This new architecture introduces a new method for registering runners and will eliminate the legacy
+[runner registration token](https://docs.gitlab.com/ee/security/token_overview.html#runner-registration-tokens).
+From GitLab 18.0 and later, the runner registration methods implemented by the new GitLab Runner token architecture will be the only supported methods.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="18.0">
+
+### `runnerRegistrationToken` parameter for GitLab Runner Helm Chart
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">15.6</span>
+- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/381111).
+</div>
+
+The [`runnerRegistrationToken`](https://docs.gitlab.com/runner/install/kubernetes.html#required-configuration) parameter to use the GitLab Helm Chart to install a runner on Kubernetes is deprecated.
+
+We plan to implement a new method to bind runners to a GitLab instance leveraging `runnerToken`
+as part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/ci/runners/new_creation_workflow.html).
+The work is planned in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/7633).
+
+From GitLab 18.0 and later, the methods to register runners introduced by the new GitLab Runner token architecture will be the only supported methods.
+
+</div>
+</div>
+
<div class="milestone-wrapper" data-milestone="17.0">
## GitLab 17.0
@@ -131,6 +233,30 @@ These three variables will be removed in GitLab 17.0.
<div class="deprecation breaking-change" data-milestone="17.0">
+### Default CI/CD job token (`CI_JOB_TOKEN`) scope changed
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">15.9</span>
+- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/383084).
+</div>
+
+In GitLab 14.4 we introduced the ability to [limit your project's CI/CD job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#limit-your-projects-job-token-access) (`CI_JOB_TOKEN`) access to make it more secure. You can prevent job tokens **from your project's** pipelines from being used to **access other projects**. When enabled with no other configuration, your pipelines cannot access other projects. To use the job token to access other projects from your pipeline, you must list those projects explicitly in the **Limit CI_JOB_TOKEN access** setting's allowlist, and you must be a maintainer in all the projects.
+
+The job token functionality was updated in 15.9 with a better security setting to [allow access to your project with a job token](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#allow-access-to-your-project-with-a-job-token). When enabled with no other configuration, job tokens **from other projects** cannot **access your project**. Similar to the older setting, you can optionally allow other projects to access your project with a job token if you list those projects explicitly in the **Allow access to this project with a CI_JOB_TOKEN** setting's allowlist. With this new setting, you must be a maintainer in your own project, but only need to have the Guest role in the other projects.
+
+The **Limit** setting was deprecated in 16.0 in preference of the better **Allow access** setting and **Limit** setting was disabled by default for all new projects. From this point forward, if the **Limit** setting is disabled in any project, it will not be possible to re-enable this setting in 16.0 or later.
+
+In 17.0, we will remove the **Limit** setting completely, and set the **Allow access** setting to enabled for all projects. This change ensures a higher level of security between projects. If you currently use the **Limit** setting, you should update your projects to use the **Allow access** setting instead. If other projects access your project with a job token, you must add them to the **Allow access** allowlist.
+
+To prepare for this change, users on GitLab.com or self-managed GitLab 15.9 or later can enable the **Allow access** setting now and add the other projects. It will not be possible to disable the setting in 17.0 or later.
+
+In 16.3, the names of these settings were changed to clarify their meanings: the deprecated **Limit CI_JOB_TOKEN access** setting is now called **Limit access _from_ this project**, and the newer **Allow access to this project with a CI_JOB_TOKEN** setting is now called **Limit access _to_ this project**.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
### Deprecate Windows CMD in GitLab Runner
<div class="deprecation-notes">
@@ -189,6 +315,20 @@ The GitLab Runner Kubernetes executor setting, `terminationGracePeriodSeconds`,
<div class="deprecation breaking-change" data-milestone="17.0">
+### Deprecate change vulnerability status from the Developer role
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">16.4</span>
+- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/424133).
+</div>
+
+The ability for Developers to change the status of vulnerabilities is now deprecated. We plan to make a breaking change in the upcoming GitLab 17.0 release to remove this ability from the Developer role. Users who wish to continue to grant this permission to developers can [create a custom role](https://docs.gitlab.com/ee/user/permissions.html#custom-roles) for their developers and add in the `admin_vulnerability` permission to give them this access.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
### Deprecate field `hasSolutions` from GraphQL VulnerabilityType
<div class="deprecation-notes">
@@ -273,6 +413,25 @@ To avoid any disruptions, you should replace `filepath` with `direct_asset_path`
<div class="deprecation breaking-change" data-milestone="17.0">
+### Geo: Legacy replication details routes for designs and projects deprecated
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">16.4</span>
+- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/424002).
+</div>
+
+As part of the migration of legacy data types to the [Geo self-service framework](https://docs.gitlab.com/ee/development/geo/framework.html), the following replication details routes are deprecated:
+
+- Designs `/admin/geo/replication/designs` replaced by `/admin/geo/sites/<Geo Node/Site ID>/replication/design_management_repositories`
+- Projects `/admin/geo/replication/projects` replaced by `/admin/geo/sites/<Geo Node/Site ID>/replication/projects`
+
+From GitLab 16.4 to 17.0, lookups for the legacy routes will automatically be redirected to the new routes. We will remove the redirections in 17.0. Please update any bookmarks or scripts that may use the legacy routes.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
### GitLab Helm chart values `gitlab.kas.privateApi.*` are deprecated
<div class="deprecation-notes">
@@ -310,29 +469,6 @@ are deprecated and will be removed from the GraphQL API. For installation instru
<div class="deprecation breaking-change" data-milestone="17.0">
-### GitLab Runner registration token in Runner Operator
-
-<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.6</span>
-- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/382077).
-</div>
-
-The [`runner-registration-token`](https://docs.gitlab.com/runner/install/operator.html#install-the-kubernetes-operator) parameter that uses the OpenShift and Kubernetes Vanilla Operator to install a runner on Kubernetes is deprecated. Authentication tokens will be used to register runners instead. Registration tokens, and support for certain configuration arguments,
-will be removed in GitLab 17.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
-The configuration arguments disabled for authentication tokens are:
-
-- `--locked`
-- `--access-level`
-- `--run-untagged`
-- `--tag-list`
-
-This change is a breaking change. You should use an [authentication token](../ci/runners/register_runner.md) in the `gitlab-runner register` command instead.
-
-</div>
-
-<div class="deprecation breaking-change" data-milestone="17.0">
-
### GraphQL deprecation of `dependencyProxyTotalSizeInBytes` field
<div class="deprecation-notes">
@@ -381,6 +517,20 @@ Use `totalIssueWeight` instead, introduced in GitLab 16.2.
<div class="deprecation breaking-change" data-milestone="17.0">
+### GraphQL networkPolicies resource deprecated
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">14.8</span>
+- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/421440).
+</div>
+
+The `networkPolicies` [GraphQL resource](https://docs.gitlab.com/ee/api/graphql/reference/#projectnetworkpolicies) has been deprecated and will be removed in GitLab 17.0. Since GitLab 15.0 this field has returned no data.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
### GraphQL type, `RunnerMembershipFilter` renamed to `CiRunnerMembershipFilter`
<div class="deprecation-notes">
@@ -410,6 +560,61 @@ In GitLab 17.0, the `DISABLED_WITH_OVERRIDE` value of the `SharedRunnersSetting`
<div class="deprecation breaking-change" data-milestone="17.0">
+### HashiCorp Vault integration will no longer use CI_JOB_JWT by default
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">15.9</span>
+- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/366798).
+</div>
+
+As part of our effort to improve the security of your CI workflows using JWT and OIDC, the native HashiCorp integration is also being updated in GitLab 16.0. Any projects that use the [`secrets:vault`](https://docs.gitlab.com/ee/ci/yaml/#secretsvault) keyword to retrieve secrets from Vault will need to be [configured to use the ID tokens](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#configure-automatic-id-token-authentication). ID tokens were introduced in 15.7.
+
+To prepare for this change, use the new [`id_tokens`](https://docs.gitlab.com/ee/ci/yaml/#id_tokens)
+keyword and configure the `aud` claim. Ensure the bound audience is prefixed with `https://`.
+
+In GitLab 15.9 to 15.11, you can [enable the **Limit JSON Web Token (JWT) access**](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#enable-automatic-id-token-authentication)
+setting, which prevents the old tokens from being exposed to any jobs and enables
+[ID token authentication for the `secrets:vault` keyword](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#configure-automatic-id-token-authentication).
+
+In GitLab 16.0 and later:
+
+- This setting will be removed.
+- CI/CD jobs that use the `id_tokens` keyword can use ID tokens with `secrets:vault`,
+ and will not have any `CI_JOB_JWT*` tokens available.
+- Jobs that do not use the `id_tokens` keyword will continue to have the `CI_JOB_JWT*`
+ tokens available until GitLab 17.0.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
+### Internal Container Registry API tag deletion endpoint
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">16.4</span>
+- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/container-registry/-/issues/1094).
+</div>
+
+The [Docker Registry HTTP API V2 Spec](https://docs.docker.com/registry/spec/api/), later replaced by the [OCI Distribution Spec](https://github.com/opencontainers/distribution-spec/blob/main/spec.md) did not include a tag delete operation, and an unsafe and slow workaround (involving deleting manifests, not tags) had to be used to achieve the same end.
+
+Tag deletion is an important function, so we added a tag deletion operation to the GitLab Container Registry, extending the V2 API beyond the scope of the Docker and OCI distribution spec.
+
+Since then, the OCI Distribution Spec has had some updates and it now has a tag delete operation, using the [`DELETE /v2/<name>/manifests/<tag>` endpoint](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#deleting-tags).
+
+This leaves the container registry with two endpoints that provide the exact same functionality. `DELETE /v2/<name>/tags/reference/<tag>` is the custom GitLab tag delete endpoint and `DELETE /v2/<name>/manifests/<tag>`, the OCI compliant tag delete endpoint introduced in GitLab 16.4.
+
+Support for the custom GitLab tag delete endpoint is deprecated in GitLab 16.4, and it will be removed in GitLab 17.0.
+
+This endpoint is used by the **internal** Container Registry application API, not the public [GitLab Container Registry API](https://docs.gitlab.com/ee/api/container_registry.html). No action should be required by the majority of container registry users. All the GitLab UI and API functionality related to tag deletions will remain intact as we transition to the new OCI-compliant endpoint.
+
+If you do access the internal container registry API and use the original tag deletion endpoint, you must update to the new endpoint.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
### Maintainer role providing the ability to change Package settings using GraphQL API
<div class="deprecation-notes">
@@ -432,6 +637,48 @@ settings for the group using either the GitLab UI or GraphQL API.
<div class="deprecation breaking-change" data-milestone="17.0">
+### Old versions of JSON web tokens are deprecated
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">15.9</span>
+- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/366798).
+</div>
+
+[ID tokens](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html) with OIDC support
+were introduced in GitLab 15.7. These tokens are more configurable than the old JSON web tokens (JWTs), are OIDC compliant,
+and only available in CI/CD jobs that explictly have ID tokens configured.
+ID tokens are more secure than the old `CI_JOB_JWT*` JSON web tokens which are exposed in every job,
+and as a result these old JSON web tokens are deprecated:
+
+- `CI_JOB_JWT`
+- `CI_JOB_JWT_V1`
+- `CI_JOB_JWT_V2`
+
+To prepare for this change, configure your pipelines to use [ID tokens](https://docs.gitlab.com/ee/ci/yaml/index.html#id_tokens)
+instead of the deprecated tokens. For OIDC compliance, the `iss` claim now uses
+the fully qualified domain name, for example `https://example.com`, previously
+introduced with the `CI_JOB_JWT_V2` token.
+
+In GitLab 15.9 to 15.11, you can [enable the **Limit JSON Web Token (JWT) access**](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#enable-automatic-id-token-authentication)
+setting, which prevents the old tokens from being exposed to any jobs and enables
+[ID token authentication for the `secrets:vault` keyword](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#configure-automatic-id-token-authentication).
+
+In GitLab 16.0 and later:
+
+- This setting will be removed.
+- CI/CD jobs that use the `id_tokens` keyword can use ID tokens with `secrets:vault`,
+ and will not have any `CI_JOB_JWT*` tokens available.
+- Jobs that do not use the `id_tokens` keyword will continue to have the `CI_JOB_JWT*`
+ tokens available until GitLab 17.0.
+
+In GitLab 17.0, the deprecated tokens will be completely removed and will no longer
+be available in CI/CD jobs.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="17.0">
+
### OmniAuth Facebook is deprecated
<div class="deprecation-notes">
@@ -544,33 +791,6 @@ This change is a breaking change. You should [create a runner in the UI](../ci/r
<div class="deprecation breaking-change" data-milestone="17.0">
-### Registration tokens and server-side runner arguments in `gitlab-runner register` command
-
-<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.6</span>
-- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/380872).
-</div>
-
-Registration tokens and certain configuration arguments in the command `gitlab-runner register` that [registers](https://docs.gitlab.com/runner/register/) a runner, are deprecated.
-Authentication tokens will be used to register runners instead. Registration tokens, and support for certain configuration arguments,
-will be removed in GitLab 17.0. For more information, see [Migrating to the new runner registration workflow](../ci/runners/new_creation_workflow.md).
-The configuration arguments disabled for authentication tokens are:
-
-- `--locked`
-- `--access-level`
-- `--run-untagged`
-- `--maximum-timeout`
-- `--paused`
-- `--tag-list`
-- `--maintenance-note`
-
-This change is a breaking change. You should [create a runner in the UI](../ci/runners/register_runner.md) to add configurations, and use the authentication token in the `gitlab-runner register` command instead.
-
-</div>
-
-<div class="deprecation breaking-change" data-milestone="17.0">
-
### Required Pipeline Configuration is deprecated
<div class="deprecation-notes">
@@ -678,56 +898,43 @@ we'll be introducing support in [this epic](https://gitlab.com/groups/gitlab-org
<div class="deprecation breaking-change" data-milestone="17.0">
-### Support for REST API endpoints that reset runner registration tokens
+### The GitLab legacy requirement IID is deprecated in favor of work item IID
<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.7</span>
+- Announced in GitLab <span class="milestone">15.9</span>
- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/383341).
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390263).
</div>
-The support for runner registration tokens is deprecated. As a consequence, the REST API endpoints to reset a registration token are also deprecated and will
-return the HTTP `410 Gone` status code in GitLab 17.0.
-The deprecated endpoints are:
-
-- `POST /runners/reset_registration_token`
-- `POST /projects/:id/runners/reset_registration_token`
-- `POST /groups/:id/runners/reset_registration_token`
-
-We plan to implement a new method to bind runners to a GitLab instance
-as part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/).
-The work is planned in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/7633).
-This new architecture introduces a new method for registering runners and will eliminate the legacy
-[runner registration token](https://docs.gitlab.com/ee/security/token_overview.html#runner-registration-tokens).
-From GitLab 17.0 and later, the runner registration methods implemented by the new GitLab Runner token architecture will be the only supported methods.
+We will be transitioning to a new IID as a result of moving requirements to a [work item type](https://docs.gitlab.com/ee/development/work_items.html#work-items-and-work-item-types). Users should begin using the new IID as support for the legacy IID and existing formatting will end in GitLab 17.0. The legacy requirement IID remains available until its removal in GitLab 17.0.
</div>
<div class="deprecation breaking-change" data-milestone="17.0">
-### The GitLab legacy requirement IID is deprecated in favor of work item IID
+### The Visual Reviews tool is deprecated
<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.9</span>
+- Announced in GitLab <span class="milestone">15.8</span>
- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390263).
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/387751).
</div>
-We will be transitioning to a new IID as a result of moving requirements to a [work item type](https://docs.gitlab.com/ee/development/work_items.html#work-items-and-work-item-types). Users should begin using the new IID as support for the legacy IID and existing formatting will end in GitLab 17.0. The legacy requirement IID remains available until its removal in GitLab 17.0.
+Due to limited customer usage and capabilities, the Visual Reviews feature for Review Apps is deprecated and will be removed. There is no planned replacement and users should stop using Visual Reviews before GitLab 17.0.
</div>
<div class="deprecation breaking-change" data-milestone="17.0">
-### The Visual Reviews tool is deprecated
+### The `ci_job_token_scope_enabled` projects API attribute is deprecated
<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.8</span>
+- Announced in GitLab <span class="milestone">16.4</span>
- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/387751).
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/423091).
</div>
-Due to limited customer usage and capabilities, the Visual Reviews feature for Review Apps is deprecated and will be removed. There is no planned replacement and users should stop using Visual Reviews before GitLab 17.0.
+GitLab 16.1 introduced [API endpoints for the job token scope](https://gitlab.com/gitlab-org/gitlab/-/issues/351740). In the [projects API](https://docs.gitlab.com/ee/api/projects.html), the `ci_job_token_scope_enabled` attribute is deprecated, and will be removed in 17.0. You should use the [job token scope APIs](https://docs.gitlab.com/ee/api/project_job_token_scopes.html) instead.
</div>
@@ -830,26 +1037,6 @@ removed in 17.0.
<div class="deprecation breaking-change" data-milestone="17.0">
-### `runnerRegistrationToken` parameter for GitLab Runner Helm Chart
-
-<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.6</span>
-- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/381111).
-</div>
-
-The [`runnerRegistrationToken`](https://docs.gitlab.com/runner/install/kubernetes.html#required-configuration) parameter to use the GitLab Helm Chart to install a runner on Kubernetes is deprecated.
-
-We plan to implement a new method to bind runners to a GitLab instance leveraging `runnerToken`
-as part of the new [GitLab Runner token architecture](https://docs.gitlab.com/ee/architecture/blueprints/runner_tokens/).
-The work is planned in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/7633).
-
-From GitLab 17.0 and later, the methods to register runners introduced by the new GitLab Runner token architecture will be the only supported methods.
-
-</div>
-
-<div class="deprecation breaking-change" data-milestone="17.0">
-
### `sidekiq` delivery method for `incoming_email` and `service_desk_email` is deprecated
<div class="deprecation-notes">
@@ -909,92 +1096,42 @@ Previous work helped [align the vulnerabilities calls for pipeline security tabs
</div>
</div>
-<div class="milestone-wrapper" data-milestone="16.5">
+<div class="milestone-wrapper" data-milestone="16.6">
-## GitLab 16.5
+## GitLab 16.6
-<div class="deprecation " data-milestone="16.5">
+<div class="deprecation breaking-change" data-milestone="16.6">
-### Adding non-LDAP synced members to a locked LDAP group is deprecated
+### Job token allowlist covers public and internal projects
<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">16.0</span>
-- Removal in GitLab <span class="milestone">16.5</span>
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/213311).
-</div>
-
-Enabling the `ldap_settings_unlock_groups_by_owners` feature flag allowed non-LDAP synced users to be added to a locked LDAP group. This [feature](https://gitlab.com/gitlab-org/gitlab/-/issues/1793) has always been disabled by default and behind a feature flag. We are removing this feature to keep continuity with our SAML integration, and because allowing non-synced group members defeats the "single source of truth" principle of using a directory service. Once this feature is removed, any LDAP group members that are not synced with LDAP will lose access to that group.
-
+- Announced in GitLab <span class="milestone">16.3</span>
+- Removal in GitLab <span class="milestone">16.6</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/420678).
</div>
-<div class="deprecation breaking-change" data-milestone="16.5">
+Starting in 16.6, projects that are **public** or **internal** will no longer authorize job token requests from projects that are **not** on the project's allowlist when [**Limit access to this project**](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html#allow-access-to-your-project-with-a-job-token) is enabled.
-### HashiCorp Vault integration will no longer use CI_JOB_JWT by default
+If you have [public or internal](https://docs.gitlab.com/ee/user/public_access.html#change-project-visibility) projects with the **Limit access to this project** setting enabled, you must add any projects which make job token requests to your project's allowlist for continued authorization.
-<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.9</span>
-- Removal in GitLab <span class="milestone">16.5</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/366798).
+</div>
</div>
-As part of our effort to improve the security of your CI workflows using JWT and OIDC, the native HashiCorp integration is also being updated in GitLab 16.0. Any projects that use the [`secrets:vault`](https://docs.gitlab.com/ee/ci/yaml/#secretsvault) keyword to retrieve secrets from Vault will need to be [configured to use the ID tokens](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#configure-automatic-id-token-authentication). ID tokens were introduced in 15.7.
-
-To prepare for this change, use the new [`id_tokens`](https://docs.gitlab.com/ee/ci/yaml/#id_tokens)
-keyword and configure the `aud` claim. Ensure the bound audience is prefixed with `https://`.
-
-In GitLab 15.9 to 15.11, you can [enable the **Limit JSON Web Token (JWT) access**](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#enable-automatic-id-token-authentication)
-setting, which prevents the old tokens from being exposed to any jobs and enables
-[ID token authentication for the `secrets:vault` keyword](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#configure-automatic-id-token-authentication).
-
-In GitLab 16.0 and later:
-
-- This setting will be removed.
-- CI/CD jobs that use the `id_tokens` keyword can use ID tokens with `secrets:vault`,
- and will not have any `CI_JOB_JWT*` tokens available.
-- Jobs that do not use the `id_tokens` keyword will continue to have the `CI_JOB_JWT*`
- tokens available until GitLab 16.5.
+<div class="milestone-wrapper" data-milestone="16.5">
-</div>
+## GitLab 16.5
-<div class="deprecation breaking-change" data-milestone="16.5">
+<div class="deprecation " data-milestone="16.5">
-### Old versions of JSON web tokens are deprecated
+### Adding non-LDAP synced members to a locked LDAP group is deprecated
<div class="deprecation-notes">
-- Announced in GitLab <span class="milestone">15.9</span>
-- Removal in GitLab <span class="milestone">16.5</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
-- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/366798).
+- Announced in GitLab <span class="milestone">16.0</span>
+- Removal in GitLab <span class="milestone">16.5</span>
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/213311).
</div>
-[ID tokens](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html) with OIDC support
-were introduced in GitLab 15.7. These tokens are more configurable than the old JSON web tokens (JWTs), are OIDC compliant,
-and only available in CI/CD jobs that explictly have ID tokens configured.
-ID tokens are more secure than the old `CI_JOB_JWT*` JSON web tokens which are exposed in every job,
-and as a result these old JSON web tokens are deprecated:
-
-- `CI_JOB_JWT`
-- `CI_JOB_JWT_V1`
-- `CI_JOB_JWT_V2`
-
-To prepare for this change, configure your pipelines to use [ID tokens](https://docs.gitlab.com/ee/ci/yaml/index.html#id_tokens)
-instead of the deprecated tokens. For OIDC compliance, the `iss` claim now uses
-the fully qualified domain name, for example `https://example.com`, previously
-introduced with the `CI_JOB_JWT_V2` token.
-
-In GitLab 15.9 to 15.11, you can [enable the **Limit JSON Web Token (JWT) access**](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#enable-automatic-id-token-authentication)
-setting, which prevents the old tokens from being exposed to any jobs and enables
-[ID token authentication for the `secrets:vault` keyword](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#configure-automatic-id-token-authentication).
-
-In GitLab 16.0 and later:
-
-- This setting will be removed.
-- CI/CD jobs that use the `id_tokens` keyword can use ID tokens with `secrets:vault`,
- and will not have any `CI_JOB_JWT*` tokens available.
-- Jobs that do not use the `id_tokens` keyword will continue to have the `CI_JOB_JWT*`
- tokens available until GitLab 16.5.
-
-In GitLab 16.5, the deprecated tokens will be completely removed and will no longer
-be available in CI/CD jobs.
+Enabling the `ldap_settings_unlock_groups_by_owners` feature flag allowed non-LDAP synced users to be added to a locked LDAP group. This [feature](https://gitlab.com/gitlab-org/gitlab/-/issues/1793) has always been disabled by default and behind a feature flag. We are removing this feature to keep continuity with our SAML integration, and because allowing non-synced group members defeats the "single source of truth" principle of using a directory service. Once this feature is removed, any LDAP group members that are not synced with LDAP will lose access to that group.
</div>
</div>
@@ -1038,9 +1175,19 @@ However, enabling the bundled Grafana will no longer work from GitLab 16.3.
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/387561).
</div>
-**Update:** We previously announced we would remove the existing License Compliance CI template in GitLab 16.0. However, due to performance issues with the [license scanning of CycloneDX files](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/) we will do this change in 16.3 instead.
+**Update:** We previously announced we would remove the existing License Compliance CI template in GitLab 16.0. However, due to performance issues with the [license scanning of CycloneDX files](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/) we will do this in 16.3 instead.
+
+The GitLab [**License Compliance**](https://docs.gitlab.com/ee/user/compliance/license_compliance/) CI/CD template is now deprecated and is scheduled for removal in the GitLab 16.3 release.
+
+To continue using GitLab for license compliance, remove the **License Compliance** template from your CI/CD pipeline and add the **Dependency Scanning** template. The **Dependency Scanning** template is now capable of gathering the required license information, so it is no longer necessary to run a separate license compliance job.
+
+Before you remove the **License Compliance** CI/CD template, verify that the instance has been upgraded to a version that supports the new method of license scanning.
+
+To begin using the Dependency Scanner quickly at scale, you may set up a scan execution policy at the group level to enforce the SBOM-based license scan for all projects in the group. Then, you may remove the inclusion of the `Jobs/License-Scanning.gitlab-ci.yml` template from your CI/CD configuration.
+
+If you wish to continue using the legacy license compliance feature, you can do so by setting the `LICENSE_MANAGEMENT_VERSION CI` variable to `4`. This variable can be set at the project, group, or instance level. This configuration change will allow you to continue using an existing version of license compliance without having to adopt the new approach.
-The GitLab [License Compliance](https://docs.gitlab.com/ee/user/compliance/license_compliance/) CI template is now deprecated and is scheduled for removal in the GitLab 16.1 release. Users who wish to continue using GitLab for License Compliance should remove the License Compliance template from their CI pipeline and add the [Dependency Scanning template](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuration). The Dependency Scanning template is now capable of gathering the required license information so it is no longer necessary to run a separate License Compliance job. The License Compliance CI template should not be removed prior to verifying that the `license_scanning_sbom_scanner` and `package_metadata_synchronization` flags are enabled for the instance and that the instance has been upgraded to a version that supports [the new method of license scanning](https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/).
+Bugs and vulnerabilities in this legacy analyzer will no longer be fixed.
| CI Pipeline Includes | GitLab <= 15.8 | 15.9 <= GitLab < 16.3 | GitLab >= 16.3 |
| ------------- | ------------- | ------------- | ------------- |
@@ -1052,6 +1199,22 @@ The GitLab [License Compliance](https://docs.gitlab.com/ee/user/compliance/licen
<div class="deprecation breaking-change" data-milestone="16.3">
+### RSA key size limits
+
+<div class="deprecation-notes">
+- Announced in GitLab <span class="milestone">16.3</span>
+- Removal in GitLab <span class="milestone">16.3</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
+- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/groups/gitlab-org/-/epics/11186).
+</div>
+
+Go versions 1.20.7 and later add a `maxRSAKeySize` constant that limits RSA keys to a maximum of 8192 bits. As a result, RSA keys larger than 8192 bits will no longer work with GitLab. Any RSA keys larger than 8192 bits must be regenerated at a smaller size.
+
+You might notice this issue because your logs include an error like `tls: server sent certificate containing RSA key larger than 8192 bits`. To test the length of your key, use this command: `openssl rsa -in <your-key-file> -text -noout | grep "Key:"`.
+
+</div>
+
+<div class="deprecation breaking-change" data-milestone="16.3">
+
### Twitter OmniAuth login option is removed from GitLab.com
<div class="deprecation-notes">
@@ -3376,7 +3539,7 @@ By default, all new applications expire access tokens after 2 hours. In GitLab 1
had no expiration. In GitLab 15.0, an expiry will be automatically generated for any existing token that does not
already have one.
-You should [opt in](https://docs.gitlab.com/ee/integration/oauth_provider.html#expiring-access-tokens) to expiring
+You should [opt in](https://docs.gitlab.com/ee/integration/oauth_provider.html#access-token-expiration) to expiring
tokens before GitLab 15.0 is released:
1. Edit the application.
diff --git a/doc/update/index.md b/doc/update/index.md
index 5a0fd0bdf31..b821be3deea 100644
--- a/doc/update/index.md
+++ b/doc/update/index.md
@@ -25,12 +25,9 @@ has additional information about upgrading, including:
Depending on the installation method and your GitLab version, there are multiple
official ways to upgrade GitLab:
-- [Linux packages (Omnibus)](#linux-packages-omnibus)
-- [Self-compiled installations](#self-compiled-installation)
-- [Docker installations](#installation-using-docker)
-- [Kubernetes (Helm) installations](#installation-using-helm)
+::Tabs
-### Linux packages (Omnibus)
+:::TabTitle Linux packages (Omnibus)
The [package upgrade guide](package/index.md)
contains the steps needed to upgrade a package installed by official GitLab
@@ -39,12 +36,27 @@ repositories.
There are also instructions when you want to
[upgrade to a specific version](package/index.md#upgrade-to-a-specific-version-using-the-official-repositories).
-### Self-compiled installation
+:::TabTitle Helm chart (Kubernetes)
+
+GitLab can be deployed into a Kubernetes cluster using Helm.
+Instructions on how to upgrade a cloud-native deployment are in
+[a separate document](https://docs.gitlab.com/charts/installation/upgrade.html).
+
+Use the [version mapping](https://docs.gitlab.com/charts/installation/version_mappings.html)
+from the chart version to GitLab version to determine the [upgrade path](#upgrade-paths).
+
+:::TabTitle Docker
+
+GitLab provides official Docker images for both Community and Enterprise
+editions, and they are based on the Omnibus package. See how to
+[install GitLab using Docker](../install/docker.md).
+
+:::TabTitle Self-compiled (source)
- [Upgrading Community Edition and Enterprise Edition from source](upgrading_from_source.md) -
The guidelines for upgrading Community Edition and Enterprise Edition from source.
- [Patch versions](patch_versions.md) guide includes the steps needed for a
- patch version, such as 13.2.0 to 13.2.1, and apply to both Community and Enterprise
+ patch version, such as 15.2.0 to 15.2.1, and apply to both Community and Enterprise
Editions.
In the past we used separate documents for the upgrading instructions, but we
@@ -54,20 +66,7 @@ can still be found in the Git repository:
- [Old upgrading guidelines for Community Edition](https://gitlab.com/gitlab-org/gitlab-foss/tree/11-8-stable/doc/update)
- [Old upgrading guidelines for Enterprise Edition](https://gitlab.com/gitlab-org/gitlab/-/tree/11-8-stable-ee/doc/update)
-### Installation using Docker
-
-GitLab provides official Docker images for both Community and Enterprise
-editions, and they are based on the Omnibus package. See how to
-[install GitLab using Docker](../install/docker.md).
-
-### Installation using Helm
-
-GitLab can be deployed into a Kubernetes cluster using Helm.
-Instructions on how to upgrade a cloud-native deployment are in
-[a separate document](https://docs.gitlab.com/charts/installation/upgrade.html).
-
-Use the [version mapping](https://docs.gitlab.com/charts/installation/version_mappings.html)
-from the chart version to GitLab version to determine the [upgrade path](#upgrade-paths).
+::EndTabs
## Plan your upgrade
@@ -188,9 +187,13 @@ When upgrading:
1. Find where your version sits in the upgrade path:
- - GitLab 14: [`14.0.12`](#1400) > [`14.3.6`](#1430) > [`14.9.5`](#1490) > [`14.10.5`](#14100).
- - GitLab 15: [`15.0.5`](#1500) > [`15.1.6`](#1510) (for GitLab instances with multiple web nodes) > [`15.4.6`](#1540) > [`15.11.13`](#15110).
- - GitLab 16: [`16.0.x`](versions/gitlab_16_changes.md#1600) (only [instances with lots of users](versions/gitlab_16_changes.md#long-running-user-type-data-change)) > [latest `16.Y.Z`](https://gitlab.com/gitlab-org/gitlab/-/releases).
+ - GitLab 14: [`14.0.12`](versions/gitlab_14_changes.md#1400) > [`14.3.6`](versions/gitlab_14_changes.md#1430) >
+ [`14.9.5`](versions/gitlab_14_changes.md#1490) > [`14.10.5`](versions/gitlab_14_changes.md#14100).
+ - GitLab 15: [`15.0.5`](versions/gitlab_15_changes.md#1500) > [`15.1.6`](versions/gitlab_15_changes.md#1510) (for
+ GitLab instances with multiple web nodes) > [`15.4.6`](versions/gitlab_15_changes.md#1540) >
+ [`15.11.13`](versions/gitlab_15_changes.md#15110).
+ - GitLab 16: [`16.0.x`](versions/gitlab_16_changes.md#1600) (only
+ [instances with lots of users](versions/gitlab_16_changes.md#long-running-user-type-data-change)) > [`16.3`](versions/gitlab_16_changes.md#1630) > [latest `16.Y.Z`](https://gitlab.com/gitlab-org/gitlab/-/releases).
1. Check for [required upgrade stops](#required-upgrade-stops).
1. Consult the [version-specific upgrade instructions](#version-specific-upgrading-instructions).
@@ -209,11 +212,9 @@ crucial database schema and migration patches may be included in the latest patc
Required upgrade stops are versions of GitLab that you must upgrade to before upgrading to later versions. Required
upgrade stops allow required background migrations to finish.
-During GitLab 16.x, we are scheduling two or three required upgrade stops. We will give at least two milestones of
-notice when we schedule a required upgrade stop.
+During GitLab 16.x, we are scheduling required upgrade stops beforehand so users can better plan out appropriate upgrade stops and downtime when necessary.
-The first planned required upgrade stop is scheduled for GitLab 16.3. If nothing is introduced requiring an upgrade stop,
-GitLab 16.3 will be treated as a regular upgrade.
+The first scheduled required upgrade stop has been announced for 16.3. When planning upgrades, please take this into account.
### Earlier GitLab versions
@@ -287,1499 +288,15 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
### GitLab 16
-Before upgrading, see [GitLab 16 changes](versions/gitlab_16_changes.md).
-
-### 15.11.1
-
-- Many [project importers](../user/project/import/index.md) and [group importers](../user/group/import/index.md) now
- require the Maintainer role instead of only requiring the Developer role. For more information, see the documentation
- for any importers you use.
-- Geo: Some project imports do not initialize wiki repositories on project creation. Since the migration of project wikis to SSF, [missing wiki repositories are being incorrectly flagged as failing verification](https://gitlab.com/gitlab-org/gitlab/-/issues/409704). This is not a result of an actual replication/verification failure but an invalid internal state for these missing repositories inside Geo and results in errors in the logs and the verification progress reporting a failed state for these wiki repositories. If you have not imported projects you are not impacted by this issue.
- - Impacted versions: GitLab versions 15.11.x, 16.0.x, and 16.1.0 - 16.1.2.
- - Versions containing fix: GitLab 16.1.3 and later.
-- Geo: A [bug](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7841) in the built-in `pg-upgrade` tool prevents upgrading the bundled PostgreSQL database to version 13. This leaves the secondary site in a broken state, and prevents upgrading the Geo installation to GitLab 16.x ([PostgreSQL 12 support has removed in 16.0](deprecations.md#postgresql-12-deprecated) and later releases). This occurs on secondary sites using the bundled PostgreSQL software, running both the secondary main Rails database and tracking database on the same node. There is a manual [workaround](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7841#workaround) for those impacted until a fix is backported to 15.11.
- - Impacted versions: GitLab versions 15.2 - 15.11
- - Versions containing fix: 15.11.12 and later.
- - Version 16.0 and later are not impacted. Note, 15.11 is a mandatory upgrade stop on the way to 16.0.
-
-### 15.11.0
-
-- **Upgrade to patch release 15.11.3 or later**. This avoids [issue 408304](https://gitlab.com/gitlab-org/gitlab/-/issues/408304) when upgrading from 15.5.0 and earlier.
-- Geo: Some project imports do not initialize wiki repositories on project creation. Since the migration of project wikis to SSF, [missing wiki repositories are being incorrectly flagged as failing verification](https://gitlab.com/gitlab-org/gitlab/-/issues/409704). This is not a result of an actual replication/verification failure but an invalid internal state for these missing repositories inside Geo and results in errors in the logs and the verification progress reporting a failed state for these wiki repositories. If you have not imported projects you are not impacted by this issue.
- - Impacted versions: GitLab versions 15.11.x, 16.0.x, and 16.1.0 - 16.1.2.
- - Versions containing fix: GitLab 16.1.3 and later.
-- Geo: A [bug](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7841) in the built-in `pg-upgrade` tool prevents upgrading the bundled PostgreSQL database to version 13. This leaves the secondary site in a broken state, and prevents upgrading the Geo installation to GitLab 16.x ([PostgreSQL 12 support has removed in 16.0](deprecations.md#postgresql-12-deprecated) and later releases). This occurs on secondary sites using the bundled PostgreSQL software, running both the secondary main Rails database and tracking database on the same node. There is a manual [workaround](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7841#workaround) for those impacted until a fix is backported to 15.11.
- - Impacted versions: GitLab versions 15.2 - 15.11.11.
- - Versions containing fix: 15.11.12 and later.
- - Version 16.0 and later are not impacted. Note, 15.11 is a mandatory upgrade stop on the way to 16.0.
-
-### 15.11.x
-
-- A [bug](https://gitlab.com/gitlab-org/gitlab/-/issues/411604) can cause new LDAP users signing in for the first time to be assigned a username based on their email address instead of their LDAP username attribute. A manual workaround is to set `gitlab_rails['omniauth_auto_link_ldap_user'] = true`, or upgrade to GitLab 16.1 or later where the bug has been fixed.
-
-### 15.10.5
-
-- A [bug with Elastic Indexer Cron Workers](https://gitlab.com/gitlab-org/gitlab/-/issues/408214) can cause saturation in Sidekiq.
- - When this issue occurs, merge request merges, pipelines, Slack notifications, and other events are not created or take a long time to occur.
- - This issue may not manifest immediately as it can take up to a week before the Sidekiq is saturated enough.
- - Elasticsearch does not need to be enabled for this to occur.
- - To resolve this issue, upgrade to 15.11 or use the workaround in the issue.
-- Many [project importers](../user/project/import/index.md) and [group importers](../user/group/import/index.md) now
- require the Maintainer role instead of only requiring the Developer role. For more information, see the documentation
- for any importers you use.
-
-### 15.10.0
-
-- A [bug with Elastic Indexer Cron Workers](https://gitlab.com/gitlab-org/gitlab/-/issues/408214) can cause saturation in Sidekiq.
- - When this issue occurs, merge request merges, pipelines, Slack notifications, and other events are not created or take a long time to occur.
- - This issue may not manifest immediately as it can take up to a week before the Sidekiq is saturated enough.
- - Elasticsearch does not need to be enabled for this to occur.
- - To resolve this issue, upgrade to 15.11 or use the workaround in the issue.
-- Gitaly configuration changes significantly in Omnibus GitLab 16.0. You can begin migrating to the new structure in Omnibus GitLab 15.10 while backwards compatibility is
- maintained in the lead up to Omnibus GitLab 16.0. [Read more about this change](#gitaly-omnibus-gitlab-configuration-structure-change).
-- You might encounter the following error while upgrading to GitLab 15.10 or later:
-
- ```shell
- STDOUT: rake aborted!
- StandardError: An error has occurred, all later migrations canceled:
- PG::CheckViolation: ERROR: check constraint "check_70f294ef54" is violated by some row
- ```
-
- This error is caused by a [batched background migration introduced in GitLab 15.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107701)
- not being finalized before GitLab 15.10. To resolve this error:
-
- 1. Execute the following SQL statement using the database console (`sudo gitlab-psql` for Linux package installs):
-
- ```sql
- UPDATE oauth_access_tokens SET expires_in = '7200' WHERE expires_in IS NULL;
- ```
-
- 1. [Re-run database migrations](../administration/raketasks/maintenance.md#run-incomplete-database-migrations).
-
-- You might also encounter the following error while upgrading to GitLab 15.10 or later:
-
- ```shell
- "exception.class": "ActiveRecord::StatementInvalid",
- "exception.message": "PG::SyntaxError: ERROR: zero-length delimited identifier at or near \"\"\"\"\nLINE 1: ...COALESCE(\"lock_version\", 0) + 1 WHERE \"ci_builds\".\"\" IN (SEL...\n
- ```
-
- This error is caused by a [batched background migration introduced in GitLab 14.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81410)
- not being finalized before upgrading to GitLab 15.10 or later. To resolve this error, it is safe to [mark the migration as complete](background_migrations.md#mark-a-batched-migration-finished):
-
- ```ruby
- # Start the rails console
-
- connection = Ci::ApplicationRecord.connection
-
- Gitlab::Database::SharedModel.using_connection(connection) do
- migration = Gitlab::Database::BackgroundMigration::BatchedMigration.find_for_configuration(
- Gitlab::Database.gitlab_schemas_for_connection(connection), 'NullifyOrphanRunnerIdOnCiBuilds', :ci_builds, :id, [])
-
- # mark all jobs completed
- migration.batched_jobs.update_all(status: Gitlab::Database::BackgroundMigration::BatchedJob.state_machine.states[:succeeded].value)
- migration.update_attribute(:status, Gitlab::Database::BackgroundMigration::BatchedMigration.state_machine.states[:finished].value)
- end
- ```
-
-For more information, see [issue 415724](https://gitlab.com/gitlab-org/gitlab/-/issues/415724).
-
-### 15.9.0
-
-- A [bug with Elastic Indexer Cron Workers](https://gitlab.com/gitlab-org/gitlab/-/issues/408214) can cause saturation in Sidekiq.
- - When this issue occurs, merge request merges, pipelines, Slack notifications, and other events are not created or take a long time to occur.
- - This issue may not manifest immediately as it can take up to a week before the Sidekiq is saturated enough.
- - Elasticsearch does not need to be enabled for this to occur.
- - To resolve this issue, upgrade to 15.11 or use the workaround in the issue.
-- **Upgrade to patch release 15.9.3 or later**. This provides fixes for two database migration bugs:
- - Patch releases 15.9.0, 15.9.1, 15.9.2 have [a bug that can cause data loss](#user-profile-data-loss-bug-in-159x) from the user profile fields.
- - The second [bug fix](https://gitlab.com/gitlab-org/gitlab/-/issues/394760) ensures it is possible to upgrade directly from 15.4.x.
-- As part of the [CI Partitioning effort](../architecture/blueprints/ci_data_decay/pipeline_partitioning.md), a [new Foreign Key](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107547) was added to `ci_builds_needs`. On GitLab instances with large CI tables, adding this constraint can take longer than usual.
-- Praefect's metadata verifier's [invalid metadata deletion behavior](../administration/gitaly/praefect.md#enable-deletions) is now enabled by default.
-
- The metadata verifier processes replica records in the Praefect database and verifies the replicas actually exist on the Gitaly nodes. If the replica doesn't exist, its
- metadata record is deleted. This enables Praefect to fix situations where a replica has a metadata record indicating it's fine but, in reality, it doesn't exist on disk.
- After the metadata record is deleted, Praefect's reconciler schedules a replication job to recreate the replica.
-
- Because of past issues with the state management logic, there may be invalid metadata records in the database. These could exist, for example, because of incomplete
- deletions of repositories or partially completed renames. The verifier deletes these stale replica records of affected repositories. These repositories may show up as
- unavailable repositories in the metrics and `praefect dataloss` sub-command because of the replica records being removed. If you encounter such repositories, remove
- the repository using `praefect remove-repository` to remove the repository's remaining records.
-
- You can find repositories with invalid metadata records prior in GitLab 15.0 and later by searching for the log records outputted by the verifier. [Read more about repository verification, and to see an example log entry](../administration/gitaly/praefect.md#repository-verification).
-- Praefect configuration changes significantly in Omnibus GitLab 16.0. You can begin migrating to the new structure in Omnibus GitLab 15.9 while backwards compatibility is
- maintained in the lead up to Omnibus GitLab 16.0. [Read more about this change](#praefect-omnibus-gitlab-configuration-structure-change).
-- For **self-compiled (source) installations**, with the addition of `gitlab-sshd` the Kerberos headers are needed to build GitLab Shell.
-
- ```shell
- sudo apt install libkrb5-dev
- ```
-
-### 15.8.2
-
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-
-### 15.8.1
-
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.8.0
-
-- Git 2.38.0 and later is required by Gitaly. For self-compiled installations, you should use the [Git version provided by Gitaly](../install/installation.md#git).
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-
-### 15.7.6
-
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.7.5
-
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.7.4
-
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.7.3
-
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.7.2
-
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the upgrades. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.7.1
-
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.7.0
-
-- This version validates a `NOT NULL DB` constraint on the `issues.work_item_type_id` column.
- To upgrade to this version, no records with a `NULL` `work_item_type_id` should exist on the `issues` table.
- There are multiple `BackfillWorkItemTypeIdForIssues` background migrations that will be finalized with
- the `EnsureWorkItemTypeBackfillMigrationFinished` post-deploy migration.
-- GitLab 15.4.0 introduced a [batched background migration](background_migrations.md#batched-background-migrations) to
- [backfill `namespace_id` values on issues table](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91921). This
- migration might take multiple hours or days to complete on larger GitLab instances. Make sure the migration
- has completed successfully before upgrading to 15.7.0.
-- A database constraint is added, specifying that the `namespace_id` column on the issues
- table has no `NULL` values.
-
- - If the `namespace_id` batched background migration from 15.4 failed (see above) then the 15.7 upgrade
- fails with a database migration error.
-
- - On GitLab instances with large issues tables, validating this constraint causes the upgrade to take
- longer than usual. All database changes need to complete within a one-hour limit:
-
- ```plaintext
- FATAL: Mixlib::ShellOut::CommandTimeout: rails_migration[gitlab-rails]
- [..]
- Mixlib::ShellOut::CommandTimeout: Command timed out after 3600s:
- ```
-
- A workaround exists to [complete the data change and the upgrade manually](package/index.md#mixlibshelloutcommandtimeout-rails_migrationgitlab-rails--command-timed-out-after-3600s).
-- The default Sidekiq `max_concurrency` has been changed to 20. This is now
- consistent in our documentation and product defaults.
-
- For example, previously:
-
- - Linux package installation default (`sidekiq['max_concurrency']`): 50
- - Self-compiled installation default: 50
- - Helm chart default (`gitlab.sidekiq.concurrency`): 25
-
- Reference architectures still use a default of 10 as this is set specifically
- for those configurations.
-
- Sites that have configured `max_concurrency` will not be affected by this change.
- [Read more about the Sidekiq concurrency setting](../administration/sidekiq/extra_sidekiq_processes.md#concurrency).
-- GitLab Runner 15.7.0 introduced a breaking change that affects CI/CD jobs: [Correctly handle expansion of job file variables](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/3613).
- Previously, job-defined variables that referred to
- [file type variables](../ci/variables/index.md#use-file-type-cicd-variables)
- were expanded to the value of the file variable (its content). This behavior did not
- respect the typical rules of shell variable expansion. There was also the potential
- that secrets or sensitive information could leak if the file variable and its
- contents printed. For example, if they were printed in an echo output. For more information,
- see [Understanding the file type variable expansion change in GitLab 15.7](https://about.gitlab.com/blog/2023/02/13/impact-of-the-file-type-variable-change-15-7/).
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-
-### 15.6.7
-
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.6.6
-
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.6.5
-
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.6.4
-
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6, and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.6.3
-
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.6.2
-
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.6.1
-
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.6.0
-
-- You should use one of the [officially supported PostgreSQL versions](../administration/package_information/postgresql_versions.md). Some database migrations can cause stability and performance issues with older PostgreSQL versions.
-- Git 2.37.0 and later is required by Gitaly. For self-compiled installations, you should use the [Git version provided by Gitaly](../install/installation.md#git).
-- A database change to modify the behavior of four indexes fails on instances
- where these indexes do not exist:
-
- ```plaintext
- Caused by:
- PG::UndefinedTable: ERROR: relation "index_issues_on_title_trigram" does not exist
- ```
-
- The other three indexes are: `index_merge_requests_on_title_trigram`, `index_merge_requests_on_description_trigram`,
- and `index_issues_on_description_trigram`.
-
- This issue was [fixed in GitLab 15.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105375) and backported
- to GitLab 15.6.2. The issue can also be worked around:
- [read about how to create these indexes](https://gitlab.com/gitlab-org/gitlab/-/issues/378343#note_1199863087).
-- Geo: [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
-- Geo: We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
- - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
- - Versions containing fix: GitLab 15.8.3 and later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.5.5
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.5.4
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.5.3
-
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
- - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
- - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- sidekiq['routing_rules'] = [['*', 'default']]
- ```
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.5.2
-
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
- - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
- - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- sidekiq['routing_rules'] = [['*', 'default']]
- ```
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.5.1
-
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
- - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
- - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- sidekiq['routing_rules'] = [['*', 'default']]
- ```
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.5.0
-
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
- - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
- - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- sidekiq['routing_rules'] = [['*', 'default']]
- ```
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.4.6
-
-- Due to a [bug introduced in curl in GitLab 15.4.6](https://github.com/curl/curl/issues/10122), the [`no_proxy` environment variable may not work properly](../administration/geo/replication/troubleshooting.md#secondary-site-returns-received-http-code-403-from-proxy-after-connect). Either downgrade to GitLab 15.4.5, or upgrade to GitLab 15.5.7 or a later version.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.4.5
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.4.4
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.4.3
-
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.4.2
-
-- A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
- - Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
- - Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
- - 15.2.5 --> 15.3.5
- - 15.3.0 - 15.3.4 --> 15.3.5
- - 15.4.1 --> 15.4.3
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.4.1
-
-- A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
- - Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
- - Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
- - 15.2.5 --> 15.3.5
- - 15.3.0 - 15.3.4 --> 15.3.5
- - 15.4.1 --> 15.4.3
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-
-### 15.4.0
-
-- GitLab 15.4.0 includes a [batched background migration](background_migrations.md#batched-background-migrations) to [remove incorrect values from `expire_at` in `ci_job_artifacts` table](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89318).
- This migration might take hours or days to complete on larger GitLab instances.
-- By default, Gitaly and Praefect nodes use the time server at `pool.ntp.org`. If your instance can not connect to `pool.ntp.org`, [configure the `NTP_HOST` variable](../administration/gitaly/praefect.md#customize-time-server-setting).
-- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
- - The default routing rule has been reverted in 15.4.5, so upgrading to that version or later will return to the previous behavior.
- - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- sidekiq['routing_rules'] = [['*', 'default']]
- ```
-
-- New Git repositories created in Gitaly cluster [no longer use the `@hashed` storage path](#change-to-praefect-generated-replica-paths-in-gitlab-153). Server
- hooks for new repositories must be copied into a different location.
-- The structure of `/etc/gitlab/gitlab-secrets.json` was modified in [GitLab 15.4](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/6310),
- and new configuration was added to `gitlab_pages`, `grafana`, and `mattermost` sections.
- In a highly available or GitLab Geo environment, secrets need to be the same on all nodes.
- If you're manually syncing the secrets file across nodes, or manually specifying secrets in
- `/etc/gitlab/gitlab.rb`, make sure `/etc/gitlab/gitlab-secrets.json` is the same on all nodes.
-- GitLab 15.4.0 introduced a [batched background migration](background_migrations.md#batched-background-migrations) to
- [backfill `namespace_id` values on issues table](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91921). This
- migration might take multiple hours or days to complete on larger GitLab instances. Make sure the migration
- has completed successfully before upgrading to 15.7.0 or later.
-- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
-- A redesigned sign-in page is enabled by default in GitLab 15.4 and later, with improvements shipping in later releases. For more information, see [epic 8557](https://gitlab.com/groups/gitlab-org/-/epics/8557).
- It can be disabled with a feature flag. Start [a Rails console](../administration/operations/rails_console.md) and run:
-
- ```ruby
- Feature.disable(:restyle_login_page)
- ```
-
-### 15.3.4
-
-A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
-
-- Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
-- Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
- - 15.2.5 --> 15.3.5
- - 15.3.0 - 15.3.4 --> 15.3.5
- - 15.4.1 --> 15.4.3
-
-### 15.3.3
-
-- In GitLab 15.3.3, [SAML Group Links](../api/groups.md#saml-group-links) API `access_level` attribute type changed to `integer`. See
-[the API documentation](../api/members.md).
-- A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
-
- - Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
- - Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
- - 15.2.5 --> 15.3.5
- - 15.3.0 - 15.3.4 --> 15.3.5
- - 15.4.1 --> 15.4.3
-
-### 15.3.2
-
-A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
-
-- Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
-- Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
- - 15.2.5 --> 15.3.5
- - 15.3.0 - 15.3.4 --> 15.3.5
- - 15.4.1 --> 15.4.3
-
-### 15.3.1
-
-A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
-
-- Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
-- Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
- - 15.2.5 --> 15.3.5
- - 15.3.0 - 15.3.4 --> 15.3.5
- - 15.4.1 --> 15.4.3
-
-### 15.3.0
-
-- [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
-- LFS transfers can [redirect to the primary from secondary site mid-session](https://gitlab.com/gitlab-org/gitlab/-/issues/371571) causing failed pull and clone requests when [Geo proxying](../administration/geo/secondary_proxy/index.md) is enabled. Geo proxying is enabled by default in GitLab 15.1 and later. See [Geo: LFS transfer redirect to primary from secondary site mid-session issue in GitLab 15.1.0 to 15.3.2](#geo-lfs-transfers-redirect-to-primary-from-secondary-site-mid-session-in-gitlab-1510-to-1532) for more details.
-- New Git repositories created in Gitaly cluster [no longer use the `@hashed` storage path](#change-to-praefect-generated-replica-paths-in-gitlab-153). Server
- hooks for new repositories must be copied into a different location.
-- A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
-
- - Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
- - Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
- - 15.2.5 --> 15.3.5
- - 15.3.0 - 15.3.4 --> 15.3.5
- - 15.4.1 --> 15.4.3
-
-### 15.2.5
-
-A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
-
-- Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
-- Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
- - 15.2.5 --> 15.3.5
- - 15.3.0 - 15.3.4 --> 15.3.5
- - 15.4.1 --> 15.4.3
-
-### 15.2.0
-
-- GitLab installations that have multiple web nodes should be
- [upgraded to 15.1](#1510) before upgrading to 15.2 (and later) due to a
- configuration change in Rails that can result in inconsistent ETag key
- generation.
-- Some Sidekiq workers were renamed in this release. To avoid any disruption, [run the Rake tasks to migrate any pending jobs](../administration/sidekiq/sidekiq_job_migration.md#migrate-queued-and-future-jobs) before starting the upgrade to GitLab 15.2.0.
-- Gitaly now executes its binaries in a [runtime location](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4670). By default on Omnibus GitLab,
- this path is `/var/opt/gitlab/gitaly/run/`. If this location is mounted with `noexec`, merge requests generate the following error:
-
- ```plaintext
- fork/exec /var/opt/gitlab/gitaly/run/gitaly-<nnnn>/gitaly-git2go-v15: permission denied
- ```
-
- To resolve this, remove the `noexec` option from the file system mount. An alternative is to change the Gitaly runtime directory:
-
- 1. Add `gitaly['runtime_dir'] = '<PATH_WITH_EXEC_PERM>'` to `/etc/gitlab/gitlab.rb` and specify a location without `noexec` set.
- 1. Run `sudo gitlab-ctl reconfigure`.
-- [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
-- LFS transfers can [redirect to the primary from secondary site mid-session](https://gitlab.com/gitlab-org/gitlab/-/issues/371571) causing failed pull and clone requests when [Geo proxying](../administration/geo/secondary_proxy/index.md) is enabled. Geo proxying is enabled by default in GitLab 15.1 and later. See [Geo: LFS transfer redirect to primary from secondary site mid-session issue in GitLab 15.1.0 to 15.3.2](#geo-lfs-transfers-redirect-to-primary-from-secondary-site-mid-session-in-gitlab-1510-to-1532) for more details.
-
-### 15.1.0
-
-- If you run external PostgreSQL, particularly AWS RDS,
- [check you have a PostgreSQL bug fix](#postgresql-segmentation-fault-issue)
- to avoid the database crashing.
-- In GitLab 15.1.0, we are switching Rails `ActiveSupport::Digest` to use SHA256 instead of MD5.
- This affects ETag key generation for resources such as raw Snippet file
- downloads. To ensure consistent ETag key generation across multiple
- web nodes when upgrading, all servers must first be upgraded to 15.1.Z before
- upgrading to 15.2.0 or later:
-
- 1. Ensure all GitLab web nodes are running GitLab 15.1.Z.
- 1. [Enable the `active_support_hash_digest_sha256` feature flag](../administration/feature_flags.md#how-to-enable-and-disable-features-behind-flags) to switch `ActiveSupport::Digest` to use SHA256:
-
- 1. [Start the rails console](../administration/operations/rails_console.md)
- 1. Enable the feature flag:
-
- ```ruby
- Feature.enable(:active_support_hash_digest_sha256)
- ```
-
- 1. Only then, continue to upgrade to later versions of GitLab.
-- Unauthenticated requests to the [`ciConfig` GraphQL field](../api/graphql/reference/index.md#queryciconfig) are no longer supported.
- Before you upgrade to GitLab 15.1, add an [access token](../api/rest/index.md#authentication) to your requests.
- The user creating the token must have [permission](../user/permissions.md) to create pipelines in the project.
-- [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
-- LFS transfers can [redirect to the primary from secondary site mid-session](https://gitlab.com/gitlab-org/gitlab/-/issues/371571) causing failed pull and clone requests when [Geo proxying](../administration/geo/secondary_proxy/index.md) is enabled. Geo proxying is enabled by default in GitLab 15.1 and later. See [Geo: LFS transfer redirect to primary from secondary site mid-session issue in GitLab 15.1.0 to 15.3.2](#geo-lfs-transfers-redirect-to-primary-from-secondary-site-mid-session-in-gitlab-1510-to-1532) for more details.
-
-### 15.0.0
-
-- Elasticsearch 6.8 [is no longer supported](../integration/advanced_search/elasticsearch.md#version-requirements). Before you upgrade to GitLab 15.0, [update Elasticsearch to any 7.x version](../integration/advanced_search/elasticsearch.md#upgrade-to-a-new-elasticsearch-major-version).
-- If you run external PostgreSQL, particularly AWS RDS,
- [check you have a PostgreSQL bug fix](#postgresql-segmentation-fault-issue)
- to avoid the database crashing.
-- The use of encrypted S3 buckets with storage-specific configuration is no longer supported after [removing support for using `background_upload`](deprecations.md#background-upload-for-object-storage).
-- The [certificate-based Kubernetes integration (DEPRECATED)](../user/infrastructure/clusters/index.md#certificate-based-kubernetes-integration-deprecated) is disabled by default, but you can be re-enable it through the [`certificate_based_clusters` feature flag](../administration/feature_flags.md#how-to-enable-and-disable-features-behind-flags) until GitLab 16.0.
-- When you use the GitLab Helm Chart project with a custom `serviceAccount`, ensure it has `get` and `list` permissions for the `serviceAccount` and `secret` resources.
-- The [`custom_hooks_dir`](../administration/server_hooks.md#create-global-server-hooks-for-all-repositories) setting for configuring global server hooks is now configured in
- Gitaly. The previous implementation in GitLab Shell was removed in GitLab 15.0. With this change, global server hooks are stored only inside a subdirectory named after the
- hook type. Global server hooks can no longer be a single hook file in the root of the custom hooks directory. For example, you must use `<custom_hooks_dir>/<hook_name>.d/*` rather
- than `<custom_hooks_dir>/<hook_name>`.
- - Use `gitaly['custom_hooks_dir']` in `gitlab.rb` ([introduced in 14.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/4208))
- for Omnibus GitLab. This replaces `gitlab_shell['custom_hooks_dir']`.
-- [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
-- The `FF_GITLAB_REGISTRY_HELPER_IMAGE` [feature flag](../administration/feature_flags.md#enable-or-disable-the-feature) is removed and helper images are always pulled from GitLab Registry.
-- The `AES256-GCM-SHA384` SSL cipher is no longer allowed by NGINX.
- See how you can [add the cipher back](https://docs.gitlab.com/omnibus/update/gitlab_15_changes.html#aes256-gcm-sha384-ssl-cipher-no-longer-allowed-by-default-by-nginx) to the allow list.
-- Support for more than one database has been added to GitLab. For **self-compiled (source) installations**,
- `config/database.yml` must include a database name in the database configuration.
- The `main: database` must be first. If an invalid or deprecated syntax is used, an error is generated
- during application start:
-
- ```plaintext
- ERROR: This installation of GitLab uses unsupported 'config/database.yml'.
- The main: database needs to be defined as a first configuration item instead of primary. (RuntimeError)
- ```
-
- Previously, the `config/database.yml` file looked like the following:
-
- ```yaml
- production:
- adapter: postgresql
- encoding: unicode
- database: gitlabhq_production
- ...
- ```
-
- Starting with GitLab 15.0, it must define a `main` database first:
-
- ```yaml
- production:
- main:
- adapter: postgresql
- encoding: unicode
- database: gitlabhq_production
- ...
- ```
-
-### 14.10.0
-
-- Before upgrading to GitLab 14.10, you must already have the latest 14.9.Z installed on your instance.
- The upgrade to GitLab 14.10 executes a [concurrent index drop](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84308) of unneeded
- entries from the `ci_job_artifacts` database table. This could potentially run for multiple minutes, especially if the table has a lot of
- traffic and the migration is unable to acquire a lock. It is advised to let this process finish as restarting may result in data loss.
-
-- If you run external PostgreSQL, particularly AWS RDS,
- [check you have a PostgreSQL bug fix](#postgresql-segmentation-fault-issue)
- to avoid the database crashing.
-
-- Upgrading to patch level 14.10.3 or later might encounter a one-hour timeout due to a long running database data change,
- if it was not completed while running GitLab 14.9.
-
- ```plaintext
- FATAL: Mixlib::ShellOut::CommandTimeout: rails_migration[gitlab-rails]
- (gitlab::database_migrations line 51) had an error:
- [..]
- Mixlib::ShellOut::CommandTimeout: Command timed out after 3600s:
- ```
-
- A workaround exists to [complete the data change and the upgrade manually](package/index.md#mixlibshelloutcommandtimeout-rails_migrationgitlab-rails--command-timed-out-after-3600s).
-
-### 14.9.0
-
-- Database changes made by the upgrade to GitLab 14.9 can take hours or days to complete on larger GitLab instances.
- These [batched background migrations](background_migrations.md#batched-background-migrations) update whole database tables to ensure corresponding
- records in `namespaces` table for each record in `projects` table.
-
- After you upgrade to 14.9.0 or a later 14.9 patch version,
- [batched background migrations must finish](background_migrations.md#batched-background-migrations)
- before you upgrade to a later version.
-
- If the migrations are not finished and you try to upgrade to a later version,
- you see errors like:
-
- ```plaintext
- Expected batched background migration for the given configuration to be marked as 'finished', but it is 'active':
- ```
-
- Or
-
- ```plaintext
- Error executing action `run` on resource 'bash[migrate gitlab-rails database]'
- ================================================================================
-
- Mixlib::ShellOut::ShellCommandFailed
- ------------------------------------
- Command execution failed. STDOUT/STDERR suppressed for sensitive resource
- ```
-
-- GitLab 14.9.0 includes a
- [background migration `ResetDuplicateCiRunnersTokenValuesOnProjects`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79140)
- that may remain stuck permanently in a **pending** state.
-
- To clean up this stuck job, run the following in the [GitLab Rails Console](../administration/operations/rails_console.md):
-
- ```ruby
- Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "ResetDuplicateCiRunnersTokenValuesOnProjects").find_each do |job|
- puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("ResetDuplicateCiRunnersTokenValuesOnProjects", job.arguments)
- end
- ```
-
-- If you run external PostgreSQL, particularly AWS RDS,
- [check you have a PostgreSQL bug fix](#postgresql-segmentation-fault-issue)
- to avoid the database crashing.
-
-### 14.8.0
-
-- If upgrading from a version earlier than 14.6.5, 14.7.4, or 14.8.2, review the [Critical Security Release: 14.8.2, 14.7.4, and 14.6.5](https://about.gitlab.com/releases/2022/02/25/critical-security-release-gitlab-14-8-2-released/) blog post.
- Updating to 14.8.2 or later resets runner registration tokens for your groups and projects.
-- The agent server for Kubernetes [is enabled by default](https://about.gitlab.com/releases/2022/02/22/gitlab-14-8-released/#the-agent-server-for-kubernetes-is-enabled-by-default)
- on Omnibus installations. If you run GitLab at scale,
- such as [the reference architectures](../administration/reference_architectures/index.md),
- you must disable the agent on the following server types, **if the agent is not required**.
-
- - Praefect
- - Gitaly
- - Sidekiq
- - Redis (if configured using `redis['enable'] = true` and not via `roles`)
- - Container registry
- - Any other server types based on `roles(['application_role'])`, such as the GitLab Rails nodes
-
- [The reference architectures](../administration/reference_architectures/index.md) have been updated
- with this configuration change and a specific role for standalone Redis servers.
-
- Steps to disable the agent:
-
- 1. Add `gitlab_kas['enable'] = false` to `gitlab.rb`.
- 1. If the server is already upgraded to 14.8, run `gitlab-ctl reconfigure`.
-- GitLab 14.8.0 includes a
-[background migration `PopulateTopicsNonPrivateProjectsCount`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79140)
-that may remain stuck permanently in a **pending** state.
-
- To clean up this stuck job, run the following in the [GitLab Rails Console](../administration/operations/rails_console.md):
-
- ```ruby
- Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "PopulateTopicsNonPrivateProjectsCount").find_each do |job|
- puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("PopulateTopicsNonPrivateProjectsCount", job.arguments)
- end
- ```
-
-- If upgrading from a version earlier than 14.3.0, to avoid
- [an issue with job retries](https://gitlab.com/gitlab-org/gitlab/-/issues/357822), first upgrade
- to GitLab 14.7.x and make sure all batched migrations have finished.
-- If upgrading from version 14.3.0 or later, you might notice a failed
- [batched migration](background_migrations.md#batched-background-migrations) named
- `BackfillNamespaceIdForNamespaceRoute`. You can [ignore](https://gitlab.com/gitlab-org/gitlab/-/issues/357822)
- this. Retry it after you upgrade to version 14.9.x.
-- If you run external PostgreSQL, particularly AWS RDS,
- [check you have a PostgreSQL bug fix](#postgresql-segmentation-fault-issue)
- to avoid the database crashing.
-
-### 14.7.0
-
-- See [LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2](#lfs-objects-import-and-mirror-issue-in-gitlab-1460-to-1472).
-- If upgrading from a version earlier than 14.6.5, 14.7.4, or 14.8.2, review the [Critical Security Release: 14.8.2, 14.7.4, and 14.6.5](https://about.gitlab.com/releases/2022/02/25/critical-security-release-gitlab-14-8-2-released/) blog post.
- Updating to 14.7.4 or later resets runner registration tokens for your groups and projects.
-- GitLab 14.7 introduced a change where Gitaly expects persistent files in the `/tmp` directory.
- When using the `noatime` mount option on `/tmp` in a node running Gitaly, most Linux distributions
- run into [an issue with Git server hooks getting deleted](https://gitlab.com/gitlab-org/gitaly/-/issues/4113).
- These conditions are present in the default Amazon Linux configuration.
-
- If your Linux distribution manages files in `/tmp` with the `tmpfiles.d` service, you
- can override the behavior of `tmpfiles.d` for the Gitaly files and avoid this issue:
-
- ```shell
- sudo printf "x /tmp/gitaly-%s-*\n" hooks git-exec-path >/etc/tmpfiles.d/gitaly-workaround.conf
- ```
-
- This issue is fixed in GitLab 14.10 and later when using the [Gitaly runtime directory](https://docs.gitlab.com/omnibus/update/gitlab_14_changes.html#gitaly-runtime-directory)
- to specify a location to store persistent files.
-
-### 14.6.0
-
-- See [LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2](#lfs-objects-import-and-mirror-issue-in-gitlab-1460-to-1472).
-- If upgrading from a version earlier than 14.6.5, 14.7.4, or 14.8.2, review the [Critical Security Release: 14.8.2, 14.7.4, and 14.6.5](https://about.gitlab.com/releases/2022/02/25/critical-security-release-gitlab-14-8-2-released/) blog post.
- Updating to 14.6.5 or later resets runner registration tokens for your groups and projects.
-
-### 14.5.0
-
-- When `make` is run, Gitaly builds are now created in `_build/bin` and no longer in the root directory of the source directory. If you
-are using a self-compiled installation, update paths to these binaries in your [systemd unit files](upgrading_from_source.md#configure-systemd-units)
-or [init scripts](upgrading_from_source.md#configure-sysv-init-script) by [following the documentation](upgrading_from_source.md).
-
-- Connections between Workhorse and Gitaly use the Gitaly `backchannel` protocol by default. If you deployed a gRPC proxy between Workhorse and Gitaly,
- Workhorse can no longer connect. As a workaround, [disable the temporary `workhorse_use_sidechannel`](../administration/feature_flags.md#enable-or-disable-the-feature)
- feature flag. If you need a proxy between Workhorse and Gitaly, use a TCP proxy. If you have feedback about this change, go to [this issue](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1301).
-
-- In 14.1 we introduced a background migration that changes how we store merge request diff commits,
- to significantly reduce the amount of storage needed.
- In 14.5 we introduce a set of migrations that wrap up this process by making sure
- that all remaining jobs over the `merge_request_diff_commits` table are completed.
- These jobs have already been processed in most cases so that no extra time is necessary during an upgrade to 14.5.
- However, if there are remaining jobs or you haven't already upgraded to 14.1,
- the deployment may take multiple hours to complete.
-
- All merge request diff commits automatically incorporate these changes, and there are no
- additional requirements to perform the upgrade.
- Existing data in the `merge_request_diff_commits` table remains unpacked until you run `VACUUM FULL merge_request_diff_commits`.
- However, the `VACUUM FULL` operation locks and rewrites the entire `merge_request_diff_commits` table,
- so the operation takes some time to complete and it blocks access to this table until the end of the process.
- We advise you to only run this command while GitLab is not actively used or it is taken offline for the duration of the process.
- The time it takes to complete depends on the size of the table, which can be obtained by using `select pg_size_pretty(pg_total_relation_size('merge_request_diff_commits'));`.
-
- For more information, refer to [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/331823).
-
-- GitLab 14.5.0 includes a
- [background migration `UpdateVulnerabilityOccurrencesLocation`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72788)
- that may remain stuck permanently in a **pending** state when the instance lacks records that match the migration's target.
-
- To clean up this stuck job, run the following in the [GitLab Rails Console](../administration/operations/rails_console.md):
-
- ```ruby
- Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "UpdateVulnerabilityOccurrencesLocation").find_each do |job|
- puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("UpdateVulnerabilityOccurrencesLocation", job.arguments)
- end
- ```
-
-- Upgrading to 14.5 (or later) [might encounter a one hour timeout](https://gitlab.com/gitlab-org/gitlab/-/issues/354211)
- owing to a long running database data change.
-
- ```plaintext
- FATAL: Mixlib::ShellOut::CommandTimeout: rails_migration[gitlab-rails]
- (gitlab::database_migrations line 51) had an error:
- [..]
- Mixlib::ShellOut::CommandTimeout: Command timed out after 3600s:
- ```
-
- [There is a workaround to complete the data change and the upgrade manually](package/index.md#mixlibshelloutcommandtimeout-rails_migrationgitlab-rails--command-timed-out-after-3600s)
-
-- As part of [enabling real-time issue assignees](https://gitlab.com/gitlab-org/gitlab/-/issues/330117), Action Cable is now enabled by default.
- For **self-compiled (source) installations**, `config/cable.yml` is required to be present.
-
- Configure this by running:
-
- ```shell
- cd /home/git/gitlab
- sudo -u git -H cp config/cable.yml.example config/cable.yml
-
- # Change the Redis socket path if you are not using the default Debian / Ubuntu configuration
- sudo -u git -H editor config/cable.yml
- ```
-
-### 14.4.4
-
-- For [zero-downtime upgrades](zero_downtime.md) on a GitLab cluster with separate Web and API nodes, you must enable the `paginated_tree_graphql_query` [feature flag](../administration/feature_flags.md#enable-or-disable-the-feature) _before_ upgrading GitLab Web nodes to 14.4.
- This is because we [enabled `paginated_tree_graphql_query` by default in 14.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70913/diffs), so if GitLab UI is on 14.4 and its API is on 14.3, the frontend has this feature enabled but the backend has it disabled. This results in the following error:
-
- ```shell
- bundle.esm.js:63 Uncaught (in promise) Error: GraphQL error: Field 'paginatedTree' doesn't exist on type 'Repository'
- ```
-
-### 14.4.0
-
-- Git 2.33.x and later is required. We recommend you use the
- [Git version provided by Gitaly](../install/installation.md#git).
-- See [Maintenance mode issue in GitLab 13.9 to 14.4](#maintenance-mode-issue-in-gitlab-139-to-144).
-- After enabling database load balancing by default in 14.4.0, we found an issue where
- [cron jobs would not work if the connection to PostgreSQL was severed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73716),
- as Sidekiq would continue using a bad connection. Geo and other features that rely on
- cron jobs running regularly do not work until Sidekiq is restarted. We recommend
- upgrading to GitLab 14.4.3 and later if this issue affects you.
-- After enabling database load balancing by default in 14.4.0, we found an issue where
- [Database load balancing does not work with an AWS Aurora cluster](https://gitlab.com/gitlab-org/gitlab/-/issues/220617).
- We recommend moving your databases from Aurora to RDS for PostgreSQL before
- upgrading. Refer to [Moving GitLab databases to a different PostgreSQL instance](../administration/postgresql/moving.md).
-- GitLab 14.4.0 includes a
-[background migration `PopulateTopicsTotalProjectsCountCache`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71033)
-that may remain stuck permanently in a **pending** state when the instance lacks records that match the migration's target.
-
- To clean up this stuck job, run the following in the [GitLab Rails Console](../administration/operations/rails_console.md):
-
- ```ruby
- Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "PopulateTopicsTotalProjectsCountCache").find_each do |job|
- puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("PopulateTopicsTotalProjectsCountCache", job.arguments)
- end
- ```
-
-### 14.3.0
-
-- [Instances running 14.0.0 - 14.0.4 should not upgrade directly to GitLab 14.2 or later](#upgrading-to-later-14y-releases).
-- Ensure [batched background migrations finish](background_migrations.md#batched-background-migrations) before upgrading
- to 14.3.Z from earlier GitLab 14 releases.
-- Ruby 2.7.4 is required. Refer to [the Ruby installation instructions](../install/installation.md#2-ruby)
-for how to proceed.
-- GitLab 14.3.0 contains post-deployment migrations to [address Primary Key overflow risk for tables with an integer PK](https://gitlab.com/groups/gitlab-org/-/epics/4785) for the tables listed below:
-
- - [`ci_builds.id`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70245)
- - [`ci_builds.stage_id`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66688)
- - [`ci_builds_metadata`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65692)
- - [`taggings`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66625)
- - [`events`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64779)
-
- If the migrations are executed as part of a no-downtime deployment, there's a risk of failure due to lock conflicts with the application logic, resulting in lock timeout or deadlocks. In each case, these migrations are safe to re-run until successful:
-
- ```shell
- # For Omnibus GitLab
- sudo gitlab-rake db:migrate
-
- # For source installations
- sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
- ```
-
-- After upgrading to 14.3, ensure that all the `MigrateMergeRequestDiffCommitUsers` background
- migration jobs have completed before continuing with upgrading to GitLab 14.5 or later.
- This is especially important if your GitLab instance has a large
- `merge_request_diff_commits` table. Any pending
- `MigrateMergeRequestDiffCommitUsers` background migration jobs are
- foregrounded in GitLab 14.5, and may take a long time to complete.
- You can check the count of pending jobs for
- `MigrateMergeRequestDiffCommitUsers` by using the PostgreSQL console (or `sudo
- gitlab-psql`):
-
- ```sql
- select status, count(*) from background_migration_jobs
- where class_name = 'MigrateMergeRequestDiffCommitUsers' group by status;
- ```
-
- As jobs are completed, the database records change from `0` (pending) to `1`. If the number of
- pending jobs doesn't decrease after a while, it's possible that the
- `MigrateMergeRequestDiffCommitUsers` background migration jobs have failed. You
- can check for errors in the Sidekiq logs:
-
- ```shell
- sudo grep MigrateMergeRequestDiffCommitUsers /var/log/gitlab/sidekiq/current | grep -i error
- ```
-
- If needed, you can attempt to run the `MigrateMergeRequestDiffCommitUsers` background
- migration jobs manually in the [GitLab Rails Console](../administration/operations/rails_console.md).
- This can be done using Sidekiq asynchronously, or by using a Rails process directly:
-
- - Using Sidekiq to schedule jobs asynchronously:
-
- ```ruby
- # For the first run, only attempt to execute 1 migration. If successful, increase
- # the limit for subsequent runs
- limit = 1
-
- jobs = Gitlab::Database::BackgroundMigrationJob.for_migration_class('MigrateMergeRequestDiffCommitUsers').pending.to_a
-
- pp "#{jobs.length} jobs remaining"
-
- jobs.first(limit).each do |job|
- BackgroundMigrationWorker.perform_in(5.minutes, 'MigrateMergeRequestDiffCommitUsers', job.arguments)
- end
- ```
-
- NOTE:
- The queued jobs can be monitored using the Sidekiq admin panel, which can be accessed at the `/admin/sidekiq` endpoint URI.
-
- - Using a Rails process to run jobs synchronously:
-
- ```ruby
- def process(concurrency: 1)
- queue = Queue.new
-
- Gitlab::Database::BackgroundMigrationJob
- .where(class_name: 'MigrateMergeRequestDiffCommitUsers', status: 0)
- .each { |job| queue << job }
-
- concurrency
- .times
- .map do
- Thread.new do
- Thread.abort_on_exception = true
-
- loop do
- job = queue.pop(true)
- time = Benchmark.measure do
- Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers
- .new
- .perform(*job.arguments)
- end
-
- puts "#{job.id} finished in #{time.real.round(2)} seconds"
- rescue ThreadError
- break
- end
- end
- end
- .each(&:join)
- end
-
- ActiveRecord::Base.logger.level = Logger::ERROR
- process
- ```
-
- NOTE:
- When using Rails to execute these background migrations synchronously, make sure that the machine running the process has sufficient resources to handle the task. If the process gets terminated, it's likely due to insufficient memory available. If your SSH session times out after a while, it might be necessary to run the previous code by using a terminal multiplexer like `screen` or `tmux`.
-
-- See [Maintenance mode issue in GitLab 13.9 to 14.4](#maintenance-mode-issue-in-gitlab-139-to-144).
-
-- You may see the following error when setting up two factor authentication (2FA) for accounts
- that authenticate using an LDAP password:
-
- ```plaintext
- You must provide a valid current password
- ```
-
- - The error occurs because verification is incorrectly performed against accounts'
- randomly generated internal GitLab passwords, not the LDAP passwords.
- - This is [fixed in GitLab 14.5.0 and backported to 14.4.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73538).
- - Workarounds:
- - Instead of upgrading to GitLab 14.3.x to comply with the supported upgrade path:
- 1. Upgrade to 14.4.5.
- 1. Make sure the [`MigrateMergeRequestDiffCommitUsers` background migration](#1430) has finished.
- 1. Upgrade to GitLab 14.5 or later.
- - Reset the random password for affected accounts, using [the Rake task](../security/reset_user_password.md#use-a-rake-task):
-
- ```plaintext
- sudo gitlab-rake "gitlab:password:reset[user_handle]"
- ```
-
-- If you encounter the error, `I18n::InvalidLocale: :en is not a valid locale`, when starting the application, follow the [patching](https://about.gitlab.com/handbook/support/workflows/patching_an_instance.html) process. Use [122978](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122978) as the `mr_iid`.
-
-### 14.2.0
-
-- [Instances running 14.0.0 - 14.0.4 should not upgrade directly to GitLab 14.2 or later](#upgrading-to-later-14y-releases).
-- Ensure [batched background migrations finish](background_migrations.md#batched-background-migrations) before upgrading
- to 14.2.Z from earlier GitLab 14 releases.
-- GitLab 14.2.0 contains background migrations to [address Primary Key overflow risk for tables with an integer PK](https://gitlab.com/groups/gitlab-org/-/epics/4785) for the tables listed below:
- - [`ci_build_needs`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65216)
- - [`ci_build_trace_chunks`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66123)
- - [`ci_builds_runner_session`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66433)
- - [`deployments`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67341)
- - [`geo_job_artifact_deleted_events`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66763)
- - [`push_event_payloads`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67299)
- - `ci_job_artifacts`:
- - [Finalize `job_id` conversion to `bigint` for `ci_job_artifacts`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67774)
- - [Finalize `ci_job_artifacts` conversion to `bigint`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65601)
-
- If the migrations are executed as part of a no-downtime deployment, there's a risk of failure due to lock conflicts with the application logic, resulting in lock timeout or deadlocks. In each case, these migrations are safe to re-run until successful:
-
- ```shell
- # For Omnibus GitLab
- sudo gitlab-rake db:migrate
-
- # For source installations
- sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
- ```
-
-- See [Maintenance mode issue in GitLab 13.9 to 14.4](#maintenance-mode-issue-in-gitlab-139-to-144).
-- GitLab 14.2.0 includes a
- [background migration `BackfillDraftStatusOnMergeRequests`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67687)
- that may remain stuck permanently in a **pending** state when the instance lacks records that match the migration's target.
-
- To clean up this stuck job, run the following in the [GitLab Rails Console](../administration/operations/rails_console.md):
-
- ```ruby
- Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "BackfillDraftStatusOnMergeRequests").find_each do |job|
- puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("BackfillDraftStatusOnMergeRequests", job.arguments)
- end
- ```
-
-- If you encounter the error, `I18n::InvalidLocale: :en is not a valid locale`, when starting the application, follow the [patching](https://about.gitlab.com/handbook/support/workflows/patching_an_instance.html) process. Use [123476](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123476) as the `mr_iid`.
-
-### 14.1.0
-
-- [Instances running 14.0.0 - 14.0.4 should not upgrade directly to GitLab 14.2 or later](#upgrading-to-later-14y-releases)
- but can upgrade to 14.1.Z.
-
- It is not required for instances already running 14.0.5 (or later) to stop at 14.1.Z.
- 14.1 is included on the upgrade path for the broadest compatibility
- with self-managed installations, and ensure 14.0.0-14.0.4 installations do not
- encounter issues with [batched background migrations](background_migrations.md#batched-background-migrations).
-
-- Upgrading to GitLab [14.5](#1450) (or later) may take a lot longer if you do not upgrade to at least 14.1
- first. The 14.1 merge request diff commits database migration can take hours to run, but runs in the
- background while GitLab is in use. GitLab instances upgraded directly from 14.0 to 14.5 or later must
- run the migration in the foreground and therefore take a lot longer to complete.
-
-- See [Maintenance mode issue in GitLab 13.9 to 14.4](#maintenance-mode-issue-in-gitlab-139-to-144).
-
-- If you encounter the error, `I18n::InvalidLocale: :en is not a valid locale`, when starting the application, follow the [patching](https://about.gitlab.com/handbook/support/workflows/patching_an_instance.html) process. Use [123475](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123475) as the `mr_iid`.
-
-### 14.0.0
-
-Prerequisites:
-
-- The [GitLab 14.0 release post contains several important notes](https://about.gitlab.com/releases/2021/06/22/gitlab-14-0-released/#upgrade)
- about pre-requisites including [using Patroni instead of repmgr](../administration/postgresql/replication_and_failover.md#switching-from-repmgr-to-patroni),
- migrating [to hashed storage](../administration/raketasks/storage.md#migrate-to-hashed-storage),
- and [to Puma](../administration/operations/puma.md).
-- The support of PostgreSQL 11 [has been dropped](../install/requirements.md#database). Make sure to [update your database](https://docs.gitlab.com/omnibus/settings/database.html#upgrade-packaged-postgresql-server) to version 12 before updating to GitLab 14.0.
-
-Long running batched background database migrations:
-
-- Database changes made by the upgrade to GitLab 14.0 can take hours or days to complete on larger GitLab instances.
- These [batched background migrations](background_migrations.md#batched-background-migrations) update whole database tables to mitigate primary key overflow and must be finished before upgrading to GitLab 14.2 or later.
-- Due to an issue where `BatchedBackgroundMigrationWorkers` were
- [not working](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/2785#note_614738345)
- for self-managed instances, a [fix was created](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65106)
- that requires an update to at least 14.0.5. The fix was also released in [14.1.0](#1410).
-
- After you update to 14.0.5 or a later 14.0 patch version,
- [batched background migrations must finish](background_migrations.md#batched-background-migrations)
- before you upgrade to a later version.
-
- If the migrations are not finished and you try to upgrade to a later version,
- you see an error like:
-
- ```plaintext
- Expected batched background migration for the given configuration to be marked as 'finished', but it is 'active':
- ```
-
- See how to [resolve this error](background_migrations.md#database-migrations-failing-because-of-batched-background-migration-not-finished).
-
-Other issues:
-
-- In GitLab 13.3 some [pipeline processing methods were deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/218536)
- and this code was completely removed in GitLab 14.0. If you plan to upgrade from
- **GitLab 13.2 or older** directly to 14.0, this is [unsupported](#upgrading-to-a-new-major-version).
- You should instead follow a [supported upgrade path](#upgrade-paths).
-- See [Maintenance mode issue in GitLab 13.9 to 14.4](#maintenance-mode-issue-in-gitlab-139-to-144).
-
-#### Upgrading to later 14.Y releases
-
-- Instances running 14.0.0 - 14.0.4 should not upgrade directly to GitLab 14.2 or later,
- because of [batched background migrations](background_migrations.md#batched-background-migrations).
- 1. Upgrade first to either:
- - 14.0.5 or a later 14.0.Z patch release.
- - 14.1.0 or a later 14.1.Z patch release.
- 1. [Batched background migrations must finish](background_migrations.md#batched-background-migrations)
- before you upgrade to a later version [and may take longer than usual](#1400).
-
-### User profile data loss bug in 15.9.x
-
-There is a database migration bug in 15.9.0, 15.9.1, and 15.9.2 that can cause data loss from the user profile fields `linkedin`, `twitter`, `skype`, `website_url`, `location`, and `organization`.
-
-This bug is fixed in patch releases 15.9.3 and later.
-
-The following upgrade path also works around the bug:
-
-1. Upgrade to GitLab 15.6.x, 15.7.x, or 15.8.x.
-1. [Ensure batched background migrations](background_migrations.md#batched-background-migrations) are complete.
-1. Upgrade to an earlier GitLab 15.9 patch release that doesn't have the bug fix.
-
-It is not then required to upgrade to 15.9.3 or later for this issue.
-
-[Read the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/393216) for more information.
-
-### Gitaly: Omnibus GitLab configuration structure change
-
-Gitaly configuration structure in Omnibus GitLab [changes](https://gitlab.com/gitlab-org/gitaly/-/issues/4467) in GitLab 16.0 to be consistent with the Gitaly configuration
-structure used in self-compiled installations.
-
-As a result of this change, a single hash under `gitaly['configuration']` holds most Gitaly
-configuration. Some `gitaly['..']` configuration options will continue to be used by Omnibus GitLab 16.0 and later:
-
-- `enable`
-- `dir`
-- `bin_path`
-- `env_directory`
-- `env`
-- `open_files_ulimit`
-- `consul_service_name`
-- `consul_service_meta`
-
-Migrate by moving your existing configuration under the new structure. The new structure is supported from Omnibus GitLab 15.10.
-
-The new structure is documented below with the old keys described in a comment above the new keys. When applying the new structure to your configuration:
-
-1. Replace the `...` with the value from the old key.
-1. Skip any keys you haven't configured a value for previously.
-1. Remove the old keys from the configuration once migrated.
-1. Optional but recommended. Include a trailing comma for all hash keys so the hash remains valid when keys are re-ordered or additional keys are added.
-1. When configuring `storage` to replace `git_data_dirs`, you must append `repositories` to the path as documented below. If you omit this step, your Git repositories are
- inaccessible until the configuration is fixed.
-
- ```ruby
-gitaly['configuration'] = {
- # gitaly['socket_path']
- socket_path: ...,
- # gitaly['runtime_dir']
- runtime_dir: ...,
- # gitaly['listen_addr']
- listen_addr: ...,
- # gitaly['prometheus_listen_addr']
- prometheus_listen_addr: ...,
- # gitaly['tls_listen_addr']
- tls_listen_addr: ...,
- tls: {
- # gitaly['certificate_path']
- certificate_path: ...,
- # gitaly['key_path']
- key_path: ...,
- },
- # gitaly['graceful_restart_timeout']
- graceful_restart_timeout: ...,
- logging: {
- # gitaly['logging_level']
- level: ...,
- # gitaly['logging_format']
- format: ...,
- # gitaly['logging_sentry_dsn']
- sentry_dsn: ...,
- # gitaly['logging_ruby_sentry_dsn']
- ruby_sentry_dsn: ...,
- # gitaly['logging_sentry_environment']
- sentry_environment: ...,
- # gitaly['log_directory']
- dir: ...,
- },
- prometheus: {
- # gitaly['prometheus_grpc_latency_buckets']. The old value was configured as a string
- # such as '[0, 1, 2]'. The new value must be an array like [0, 1, 2].
- grpc_latency_buckets: ...,
- },
- auth: {
- # gitaly['auth_token']
- token: ...,
- # gitaly['auth_transitioning']
- transitioning: ...,
- },
- git: {
- # gitaly['git_catfile_cache_size']
- catfile_cache_size: ...,
- # gitaly['git_bin_path']
- bin_path: ...,
- # gitaly['use_bundled_git']
- use_bundled_binaries: ...,
- # gitaly['gpg_signing_key_path']
- signing_key: ...,
- # gitaly['gitconfig']. This is still an array but the type of the elements have changed.
- config: [
- {
- # Previously the elements contained 'section', and 'subsection' in addition to 'key'. Now
- # these all should be concatenated into just 'key', separated by dots. For example,
- # {section: 'first', subsection: 'middle', key: 'last', value: 'value'}, should become
- # {key: 'first.middle.last', value: 'value'}.
- key: ...,
- value: ...,
- },
- ],
- },
- # Storage could previously be configured through either gitaly['storage'] or 'git_data_dirs'. Migrate
- # the relevant configuration according to the instructions below.
- # For 'git_data_dirs', migrate only the 'path' to the gitaly['configuration'] and leave the rest of it untouched.
- storage: [
- {
- # gitaly['storage'][<index>]['name']
- #
- # git_data_dirs[<name>]. The storage name was configured as a key in the map.
- name: ...,
- # gitaly['storage'][<index>]['path']
- #
- # git_data_dirs[<name>]['path']. Use the value from git_data_dirs[<name>]['path'] and append '/repositories' to it.
- #
- # For example, if the path in 'git_data_dirs' was '/var/opt/gitlab/git-data', use
- # '/var/opt/gitlab/git-data/repositories'. The '/repositories' extension was automatically
- # appended to the path configured in `git_data_dirs`.
- path: ...,
- },
- ],
- hooks: {
- # gitaly['custom_hooks_dir']
- custom_hooks_dir: ...,
- },
- daily_maintenance: {
- # gitaly['daily_maintenance_disabled']
- disabled: ...,
- # gitaly['daily_maintenance_start_hour']
- start_hour: ...,
- # gitaly['daily_maintenance_start_minute']
- start_minute: ...,
- # gitaly['daily_maintenance_duration']
- duration: ...,
- # gitaly['daily_maintenance_storages']
- storages: ...,
- },
- cgroups: {
- # gitaly['cgroups_mountpoint']
- mountpoint: ...,
- # gitaly['cgroups_hierarchy_root']
- hierarchy_root: ...,
- # gitaly['cgroups_memory_bytes']
- memory_bytes: ...,
- # gitaly['cgroups_cpu_shares']
- cpu_shares: ...,
- repositories: {
- # gitaly['cgroups_repositories_count']
- count: ...,
- # gitaly['cgroups_repositories_memory_bytes']
- memory_bytes: ...,
- # gitaly['cgroups_repositories_cpu_shares']
- cpu_shares: ...,
- }
- },
- # gitaly['concurrency']. While the structure is the same, the string keys in the array elements
- # should be replaced by symbols as elsewhere. {'key' => 'value'}, should become {key: 'value'}.
- concurrency: ...,
- # gitaly['rate_limiting']. While the structure is the same, the string keys in the array elements
- # should be replaced by symbols as elsewhere. {'key' => 'value'}, should become {key: 'value'}.
- rate_limiting: ...,
- pack_objects_cache: {
- # gitaly['pack_objects_cache_enabled']
- enabled: ...,
- # gitaly['pack_objects_cache_dir']
- dir: ...,
- # gitaly['pack_objects_cache_max_age']
- max_age: ...,
- }
-}
-```
-
-### Praefect: Omnibus GitLab configuration structure change
-
-Praefect configuration structure in Omnibus GitLab [changes](https://gitlab.com/gitlab-org/gitaly/-/issues/4467) in GitLab 16.0 to be consistent with the Praefect configuration
-structure used in self-compiled installations.
-
-As a result of this change, a single hash under `praefect['configuration']` holds most Praefect
-configuration. Some `praefect['..']` configuration options will continue to be used by Omnibus GitLab 16.0 and later:
-
-- `enable`
-- `dir`
-- `log_directory`
-- `env_directory`
-- `env`
-- `wrapper_path`
-- `auto_migrate`
-- `consul_service_name`
-
-Migrate by moving your existing configuration under the new structure. The new structure is supported from Omnibus GitLab 15.9.
-
-The new structure is documented below with the old keys described in a comment above the new keys. When applying the new structure to your configuration:
-
-1. Replace the `...` with the value from the old key.
-1. Skip any keys you haven't configured a value for previously.
-1. Remove the old keys from the configuration once migrated.
-1. Optional but recommended. Include a trailing comma for all hash keys so the hash remains valid when keys are re-ordered or additional keys are added.
-
-```ruby
-praefect['configuration'] = {
- # praefect['listen_addr']
- listen_addr: ...,
- # praefect['socket_path']
- socket_path: ...,
- # praefect['prometheus_listen_addr']
- prometheus_listen_addr: ...,
- # praefect['tls_listen_addr']
- tls_listen_addr: ...,
- # praefect['separate_database_metrics']
- prometheus_exclude_database_from_default_metrics: ...,
- auth: {
- # praefect['auth_token']
- token: ...,
- # praefect['auth_transitioning']
- transitioning: ...,
- },
- logging: {
- # praefect['logging_format']
- format: ...,
- # praefect['logging_level']
- level: ...,
- },
- failover: {
- # praefect['failover_enabled']
- enabled: ...,
- },
- background_verification: {
- # praefect['background_verification_delete_invalid_records']
- delete_invalid_records: ...,
- # praefect['background_verification_verification_interval']
- verification_interval: ...,
- },
- reconciliation: {
- # praefect['reconciliation_scheduling_interval']
- scheduling_interval: ...,
- # praefect['reconciliation_histogram_buckets']. The old value was configured as a string
- # such as '[0, 1, 2]'. The new value must be an array like [0, 1, 2].
- histogram_buckets: ...,
- },
- tls: {
- # praefect['certificate_path']
- certificate_path: ...,
- # praefect['key_path']
- key_path: ...,
- },
- database: {
- # praefect['database_host']
- host: ...,
- # praefect['database_port']
- port: ...,
- # praefect['database_user']
- user: ...,
- # praefect['database_password']
- password: ...,
- # praefect['database_dbname']
- dbname: ...,
- # praefect['database_sslmode']
- sslmode: ...,
- # praefect['database_sslcert']
- sslcert: ...,
- # praefect['database_sslkey']
- sslkey: ...,
- # praefect['database_sslrootcert']
- sslrootcert: ...,
- session_pooled: {
- # praefect['database_direct_host']
- host: ...,
- # praefect['database_direct_port']
- port: ...,
- # praefect['database_direct_user']
- user: ...,
- # praefect['database_direct_password']
- password: ...,
- # praefect['database_direct_dbname']
- dbname: ...,
- # praefect['database_direct_sslmode']
- sslmode: ...,
- # praefect['database_direct_sslcert']
- sslcert: ...,
- # praefect['database_direct_sslkey']
- sslkey: ...,
- # praefect['database_direct_sslrootcert']
- sslrootcert: ...,
- }
- },
- sentry: {
- # praefect['sentry_dsn']
- sentry_dsn: ...,
- # praefect['sentry_environment']
- sentry_environment: ...,
- },
- prometheus: {
- # praefect['prometheus_grpc_latency_buckets']. The old value was configured as a string
- # such as '[0, 1, 2]'. The new value must be an array like [0, 1, 2].
- grpc_latency_buckets: ...,
- },
- # praefect['graceful_stop_timeout']
- graceful_stop_timeout: ...,
-
- # praefect['virtual_storages']. The old value was a hash map but the new value is an array.
- virtual_storage: [
- {
- # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]. The name was previously the key in
- # the 'virtual_storages' hash.
- name: ...,
- # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]['nodes'][NODE_NAME]. The old value was a hash map
- # but the new value is an array.
- node: [
- {
- # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]['nodes'][NODE_NAME]. Use NODE_NAME key as the
- # storage.
- storage: ...,
- # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]['nodes'][NODE_NAME]['address'].
- address: ...,
- # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]['nodes'][NODE_NAME]['token'].
- token: ...,
- },
- ],
- }
- ]
-}
-```
-
-### Change to Praefect-generated replica paths in GitLab 15.3
-
-New Git repositories created in Gitaly cluster no longer use the `@hashed` storage path.
-
-Praefect now generates replica paths for use by Gitaly cluster.
-This change is a pre-requisite for Gitaly cluster atomically creating, deleting, and
-renaming Git repositories.
-
-To identify the replica path, [query the Praefect repository metadata](../administration/gitaly/troubleshooting.md#view-repository-metadata)
-and pass the `@hashed` storage path to `-relative-path`.
-
-With this information, you can correctly install [server hooks](../administration/server_hooks.md).
-
-### Geo: LFS transfers redirect to primary from secondary site mid-session in GitLab 15.1.0 to 15.3.2
-
-LFS transfers can [redirect to the primary from secondary site mid-session](https://gitlab.com/gitlab-org/gitlab/-/issues/371571) causing failed pull and clone requests in GitLab 15.1.0 to 15.3.2 when [Geo proxying](../administration/geo/secondary_proxy/index.md) is enabled. Geo proxying is enabled by default in GitLab 15.1 and later.
-
-This issue is resolved in GitLab 15.3.3, so customers with the following configuration should upgrade to 15.3.3 or later:
-
-- LFS is enabled.
-- LFS objects are being replicated across Geo sites.
-- Repositories are being pulled by using a Geo secondary site.
-
-### Geo: Incorrect object storage LFS file deletion on secondary sites in GitLab 15.0.0 to 15.3.2
-
-[Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397)
-can occur in GitLab 15.0.0 to 15.3.2 in the following situations:
-
-- GitLab-managed object storage replication is disabled, and LFS objects are created while importing a project with object storage enabled.
-- GitLab-managed replication to sync object storage is enabled and subsequently disabled.
-
-This issue is resolved in 15.3.3. Customers who have both LFS enabled and LFS objects being replicated across Geo sites
-should upgrade directly to 15.3.3 to reduce the risk of data loss on secondary sites.
-
-### PostgreSQL segmentation fault issue
-
-If you run GitLab with external PostgreSQL, particularly AWS RDS, ensure you upgrade PostgreSQL
-to patch levels to a minimum of 12.7 or 13.3 before upgrading to GitLab 14.8 or later.
-
-[In 14.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75511)
-for GitLab Enterprise Edition and [in 15.1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87983)
-for GitLab Community Edition a GitLab feature called Loose Foreign Keys was enabled.
-
-After it was enabled, we have had reports of unplanned PostgreSQL restarts caused
-by a database engine bug that causes a segmentation fault.
-
-Read more [in the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/364763).
-
-### LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2
-
-When Geo is enabled, LFS objects fail to be saved for imported or mirrored projects.
-
-[This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/352368) was fixed in GitLab 14.8.0 and backported into 14.7.3.
+Before upgrading to GitLab 16, see [GitLab 16 changes](versions/gitlab_16_changes.md).
-### Maintenance mode issue in GitLab 13.9 to 14.4
+### GitLab 15
-When [Maintenance mode](../administration/maintenance_mode/index.md) is enabled, users cannot sign in with SSO, SAML, or LDAP.
+Before upgrading to GitLab 15, see [GitLab 15 changes](versions/gitlab_15_changes.md).
-Users who were signed in before Maintenance mode was enabled, continue to be signed in. If the administrator who enabled Maintenance mode loses their session, then they can't disable Maintenance mode via the UI. In that case, you can [disable Maintenance mode via the API or Rails console](../administration/maintenance_mode/index.md#disable-maintenance-mode).
+### GitLab 14
-[This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/329261) was fixed in GitLab 14.5.0 and backported into 14.4.3 and 14.3.5.
+Before upgrading to GitLab 14, see [GitLab 14 changes](versions/gitlab_14_changes.md).
## Miscellaneous
diff --git a/doc/update/package/index.md b/doc/update/package/index.md
index 148791dbc75..19d308bce6b 100644
--- a/doc/update/package/index.md
+++ b/doc/update/package/index.md
@@ -43,6 +43,14 @@ check the version your are upgrading to:
- [GitLab 15](https://docs.gitlab.com/omnibus/update/gitlab_15_changes.html)
- [GitLab 14](https://docs.gitlab.com/omnibus/update/gitlab_14_changes.html)
+### Earlier GitLab versions
+
+For version-specific information for earlier GitLab versions, see the [documentation archives](https://archives.docs.gitlab.com).
+The versions of the documentation in the archives contain version-specific information for even earlier versions of GitLab.
+
+For example, the [documentation for GitLab 15.11](https://archives.docs.gitlab.com/15.11/ee/update/package/#version-specific-changes)
+contains information on versions back to GitLab 11.
+
## Back up before upgrading
The GitLab database is backed up before installing a newer GitLab version. You
diff --git a/doc/update/plan_your_upgrade.md b/doc/update/plan_your_upgrade.md
index 0bb760ec47e..25578dbef59 100644
--- a/doc/update/plan_your_upgrade.md
+++ b/doc/update/plan_your_upgrade.md
@@ -103,11 +103,7 @@ For the upgrade plan, start by creating an outline of a plan that best applies
to your instance and then upgrade it for any relevant features you're using.
- Generate an upgrade plan by reading and understanding the relevant documentation:
- - upgrade based on the installation method:
- - [Linux package (Omnibus)](index.md#linux-packages-omnibus)
- - [Self-compiled](index.md#self-compiled-installation)
- - [Docker](index.md#installation-using-docker)
- - [Helm Charts](index.md#installation-using-helm)
+ - Upgrade based on the [installation method](index.md#upgrade-based-on-installation-method).
- [Zero-downtime upgrades](zero_downtime.md) (if possible and desired)
- [Convert from GitLab Community Edition to Enterprise Edition](package/convert_to_ee.md)
- What version should you upgrade to:
@@ -122,7 +118,7 @@ to your instance and then upgrade it for any relevant features you're using.
[turning on maintenance mode](../administration/maintenance_mode/index.md) during the
upgrade.
- About PostgreSQL:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Look for the version of PostgreSQL you are using.
If [a PostgreSQL upgrade is needed](../administration/package_information/postgresql_versions.md),
diff --git a/doc/update/versions/gitlab_14_changes.md b/doc/update/versions/gitlab_14_changes.md
new file mode 100644
index 00000000000..700baf4ef09
--- /dev/null
+++ b/doc/update/versions/gitlab_14_changes.md
@@ -0,0 +1,909 @@
+---
+stage: Systems
+group: Distribution
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# GitLab 14 changes **(FREE SELF)**
+
+This page contains upgrade information for minor and patch versions of GitLab 14.
+Ensure you review these instructions for:
+
+- Your installation type.
+- All versions between your current version and your target version.
+
+For more information about upgrading GitLab Helm Chart, see [the release notes for 5.0](https://docs.gitlab.com/charts/releases/5_0.html).
+
+## 14.10.0
+
+- Before upgrading to GitLab 14.10, you must already have the latest 14.9.Z installed on your instance.
+ The upgrade to GitLab 14.10 executes a [concurrent index drop](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84308) of unneeded
+ entries from the `ci_job_artifacts` database table. This could potentially run for multiple minutes, especially if the table has a lot of
+ traffic and the migration is unable to acquire a lock. It is advised to let this process finish as restarting may result in data loss.
+
+- If you run GitLab with external PostgreSQL, particularly AWS RDS, ensure you
+ upgrade PostgreSQL to patch levels to a minimum of 12.7 or 13.3 before
+ upgrading to GitLab 14.8 or later.
+
+ [In 14.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75511)
+ for GitLab Enterprise Edition and [in 15.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87983)
+ for GitLab Community Edition a GitLab feature called Loose Foreign Keys was enabled.
+
+ After it was enabled, we have had reports of unplanned PostgreSQL restarts caused
+ by a database engine bug that causes a segmentation fault.
+
+ For more information, see [issue 364763](https://gitlab.com/gitlab-org/gitlab/-/issues/364763).
+
+- Upgrading to patch level 14.10.3 or later might encounter a one-hour timeout due to a long running database data change,
+ if it was not completed while running GitLab 14.9.
+
+ ```plaintext
+ FATAL: Mixlib::ShellOut::CommandTimeout: rails_migration[gitlab-rails]
+ (gitlab::database_migrations line 51) had an error:
+ [..]
+ Mixlib::ShellOut::CommandTimeout: Command timed out after 3600s:
+ ```
+
+ A workaround exists to [complete the data change and the upgrade manually](../package/index.md#mixlibshelloutcommandtimeout-rails_migrationgitlab-rails--command-timed-out-after-3600s).
+
+### Linux package installations
+
+- In GitLab 14.10, Gitaly has introduced a new runtime directory. This directory is intended to hold all files and
+ directories Gitaly needs to create at runtime to operate correctly. This includes, for example, internal sockets, the
+ Git execution environment, or the temporary hooks directory.
+
+ This new configuration can be set via `gitaly['runtime_dir']`. It replaces the old `gitaly['internal_socket_dir']`
+ configuration. If the internal socket directory is not explicitly configured, sockets will be created in the runtime directory.
+
+ Support for `gitaly['internal_socket_dir']` will be removed in 15.0.
+
+## 14.9.0
+
+- Database changes made by the upgrade to GitLab 14.9 can take hours or days to complete on larger GitLab instances.
+ These [batched background migrations](../background_migrations.md#batched-background-migrations) update whole database tables to ensure corresponding
+ records in `namespaces` table for each record in `projects` table.
+
+ After you upgrade to 14.9.0 or a later 14.9 patch version,
+ [batched background migrations must finish](../background_migrations.md#batched-background-migrations)
+ before you upgrade to a later version.
+
+ If the migrations are not finished and you try to upgrade to a later version,
+ you see errors like:
+
+ ```plaintext
+ Expected batched background migration for the given configuration to be marked as 'finished', but it is 'active':
+ ```
+
+ Or
+
+ ```plaintext
+ Error executing action `run` on resource 'bash[migrate gitlab-rails database]'
+ ================================================================================
+
+ Mixlib::ShellOut::ShellCommandFailed
+ ------------------------------------
+ Command execution failed. STDOUT/STDERR suppressed for sensitive resource
+ ```
+
+- GitLab 14.9.0 includes a
+ [background migration `ResetDuplicateCiRunnersTokenValuesOnProjects`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79140)
+ that may remain stuck permanently in a **pending** state.
+
+ To clean up this stuck job, run the following in the [GitLab Rails Console](../../administration/operations/rails_console.md):
+
+ ```ruby
+ Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "ResetDuplicateCiRunnersTokenValuesOnProjects").find_each do |job|
+ puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("ResetDuplicateCiRunnersTokenValuesOnProjects", job.arguments)
+ end
+ ```
+
+- If you run GitLab with external PostgreSQL, particularly AWS RDS, ensure you
+ upgrade PostgreSQL to patch levels to a minimum of 12.7 or 13.3 before
+ upgrading to GitLab 14.8 or later.
+
+ [In 14.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75511)
+ for GitLab Enterprise Edition and [in 15.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87983)
+ for GitLab Community Edition a GitLab feature called Loose Foreign Keys was enabled.
+
+ After it was enabled, we have had reports of unplanned PostgreSQL restarts caused
+ by a database engine bug that causes a segmentation fault.
+
+ For more information, see [issue 364763](https://gitlab.com/gitlab-org/gitlab/-/issues/364763).
+
+### Geo installations **(PREMIUM SELF)**
+
+- **Do not** upgrade to GitLab 14.9.0. Instead, use 14.9.1 or later.
+
+ We've discovered an issue with Geo's CI verification feature that may
+ [cause job traces to be lost](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/6664). This issue was fixed
+ in [the GitLab 14.9.1 patch release](https://about.gitlab.com/releases/2022/03/23/gitlab-14-9-1-released/).
+
+ If you have already upgraded to GitLab 14.9.0, you can disable the feature causing the issue by
+ [disabling the `geo_job_artifact_replication` feature flag](../../administration/feature_flags.md#how-to-enable-and-disable-features-behind-flags).
+
+## 14.8.0
+
+- If upgrading from a version earlier than 14.6.5, 14.7.4, or 14.8.2, review the [Critical Security Release: 14.8.2, 14.7.4, and 14.6.5](https://about.gitlab.com/releases/2022/02/25/critical-security-release-gitlab-14-8-2-released/) blog post.
+ Updating to 14.8.2 or later resets runner registration tokens for your groups and projects.
+- The agent server for Kubernetes [is enabled by default](https://about.gitlab.com/releases/2022/02/22/gitlab-14-8-released/#the-agent-server-for-kubernetes-is-enabled-by-default)
+ on Omnibus installations. If you run GitLab at scale,
+ such as [the reference architectures](../../administration/reference_architectures/index.md),
+ you must disable the agent on the following server types, **if the agent is not required**.
+
+ - Praefect
+ - Gitaly
+ - Sidekiq
+ - Redis (if configured using `redis['enable'] = true` and not via `roles`)
+ - Container registry
+ - Any other server types based on `roles(['application_role'])`, such as the GitLab Rails nodes
+
+ [The reference architectures](../../administration/reference_architectures/index.md) have been updated
+ with this configuration change and a specific role for standalone Redis servers.
+
+ Steps to disable the agent:
+
+ 1. Add `gitlab_kas['enable'] = false` to `gitlab.rb`.
+ 1. If the server is already upgraded to 14.8, run `gitlab-ctl reconfigure`.
+- GitLab 14.8.0 includes a
+[background migration `PopulateTopicsNonPrivateProjectsCount`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79140)
+that may remain stuck permanently in a **pending** state.
+
+ To clean up this stuck job, run the following in the [GitLab Rails Console](../../administration/operations/rails_console.md):
+
+ ```ruby
+ Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "PopulateTopicsNonPrivateProjectsCount").find_each do |job|
+ puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("PopulateTopicsNonPrivateProjectsCount", job.arguments)
+ end
+ ```
+
+- If upgrading from a version earlier than 14.3.0, to avoid
+ [an issue with job retries](https://gitlab.com/gitlab-org/gitlab/-/issues/357822), first upgrade
+ to GitLab 14.7.x and make sure all batched migrations have finished.
+- If upgrading from version 14.3.0 or later, you might notice a failed
+ [batched migration](../background_migrations.md#batched-background-migrations) named
+ `BackfillNamespaceIdForNamespaceRoute`. You can [ignore](https://gitlab.com/gitlab-org/gitlab/-/issues/357822)
+ this. Retry it after you upgrade to version 14.9.x.
+- If you run GitLab with external PostgreSQL, particularly AWS RDS, ensure you
+ upgrade PostgreSQL to patch levels to a minimum of 12.7 or 13.3 before
+ upgrading to GitLab 14.8 or later.
+
+ [In 14.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75511)
+ for GitLab Enterprise Edition and [in 15.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87983)
+ for GitLab Community Edition a GitLab feature called Loose Foreign Keys was enabled.
+
+ After it was enabled, we have had reports of unplanned PostgreSQL restarts caused
+ by a database engine bug that causes a segmentation fault.
+
+ For more information, see [issue 364763](https://gitlab.com/gitlab-org/gitlab/-/issues/364763).
+
+## 14.7.0
+
+- If upgrading from a version earlier than 14.6.5, 14.7.4, or 14.8.2, review the [Critical Security Release: 14.8.2, 14.7.4, and 14.6.5](https://about.gitlab.com/releases/2022/02/25/critical-security-release-gitlab-14-8-2-released/) blog post.
+ Updating to 14.7.4 or later resets runner registration tokens for your groups and projects.
+- GitLab 14.7 introduced a change where Gitaly expects persistent files in the `/tmp` directory.
+ When using the `noatime` mount option on `/tmp` in a node running Gitaly, most Linux distributions
+ run into [an issue with Git server hooks getting deleted](https://gitlab.com/gitlab-org/gitaly/-/issues/4113).
+ These conditions are present in the default Amazon Linux configuration.
+
+ If your Linux distribution manages files in `/tmp` with the `tmpfiles.d` service, you
+ can override the behavior of `tmpfiles.d` for the Gitaly files and avoid this issue:
+
+ ```shell
+ sudo printf "x /tmp/gitaly-%s-*\n" hooks git-exec-path >/etc/tmpfiles.d/gitaly-workaround.conf
+ ```
+
+ This issue is fixed in GitLab 14.10 and later when using the [Gitaly runtime directory](https://docs.gitlab.com/omnibus/update/gitlab_14_changes.html#gitaly-runtime-directory)
+ to specify a location to store persistent files.
+
+### Linux package installations
+
+- In GitLab 14.8, we are upgrading Redis from 6.0.16 to 6.2.6. This upgrade is expected to be fully backwards compatible.
+
+ If your instance has Redis HA with Sentinel, follow the upgrade steps documented in
+ [Redis HA (using Sentinel)](../zero_downtime.md#redis-ha-using-sentinel).
+
+### Geo installations **(PREMIUM SELF)**
+
+- LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2.
+ When Geo is enabled, LFS objects fail to be saved for imported or mirrored projects.
+ [This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/352368) was fixed in GitLab 14.8.0 and backported into 14.7.3.
+- There is [an issue in GitLab 14.2 through 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/299819#note_822629467)
+ that affects Geo when the GitLab-managed object storage replication is used, causing blob object types to fail synchronization.
+
+ Since GitLab 14.2, verification failures result in synchronization failures and cause a resynchronization of these objects.
+
+ As verification is not yet implemented for files stored in object storage (see
+ [issue 13845](https://gitlab.com/gitlab-org/gitlab/-/issues/13845) for more details), this
+ results in a loop that consistently fails for all objects stored in object storage.
+
+ For information on how to fix this, see
+ [Troubleshooting - Failed syncs with GitLab-managed object storage replication](../../administration/geo/replication/troubleshooting.md#failed-syncs-with-gitlab-managed-object-storage-replication).
+
+## 14.6.0
+
+- If upgrading from a version earlier than 14.6.5, 14.7.4, or 14.8.2, review the [Critical Security Release: 14.8.2, 14.7.4, and 14.6.5](https://about.gitlab.com/releases/2022/02/25/critical-security-release-gitlab-14-8-2-released/) blog post.
+ Updating to 14.6.5 or later resets runner registration tokens for your groups and projects.
+
+### Geo installations **(PREMIUM SELF)**
+
+- LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2.
+ When Geo is enabled, LFS objects fail to be saved for imported or mirrored projects.
+ [This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/352368) was fixed in GitLab 14.8.0 and backported into 14.7.3.
+- There is [an issue in GitLab 14.2 through 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/299819#note_822629467)
+ that affects Geo when the GitLab-managed object storage replication is used, causing blob object types to fail synchronization.
+
+ Since GitLab 14.2, verification failures result in synchronization failures and cause a resynchronization of these objects.
+
+ As verification is not yet implemented for files stored in object storage (see
+ [issue 13845](https://gitlab.com/gitlab-org/gitlab/-/issues/13845) for more details), this
+ results in a loop that consistently fails for all objects stored in object storage.
+
+ For information on how to fix this, see
+ [Troubleshooting - Failed syncs with GitLab-managed object storage replication](../../administration/geo/replication/troubleshooting.md#failed-syncs-with-gitlab-managed-object-storage-replication).
+
+## 14.5.0
+
+- Connections between Workhorse and Gitaly use the Gitaly `backchannel` protocol by default. If you deployed a gRPC proxy between Workhorse and Gitaly,
+ Workhorse can no longer connect. As a workaround, [disable the temporary `workhorse_use_sidechannel`](../../administration/feature_flags.md#enable-or-disable-the-feature)
+ feature flag. If you need a proxy between Workhorse and Gitaly, use a TCP proxy. If you have feedback about this change, go to [this issue](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1301).
+
+- In 14.1 we introduced a background migration that changes how we store merge request diff commits,
+ to significantly reduce the amount of storage needed.
+ In 14.5 we introduce a set of migrations that wrap up this process by making sure
+ that all remaining jobs over the `merge_request_diff_commits` table are completed.
+ These jobs have already been processed in most cases so that no extra time is necessary during an upgrade to 14.5.
+ However, if there are remaining jobs or you haven't already upgraded to 14.1,
+ the deployment may take multiple hours to complete.
+
+ All merge request diff commits automatically incorporate these changes, and there are no
+ additional requirements to perform the upgrade.
+ Existing data in the `merge_request_diff_commits` table remains unpacked until you run `VACUUM FULL merge_request_diff_commits`.
+ However, the `VACUUM FULL` operation locks and rewrites the entire `merge_request_diff_commits` table,
+ so the operation takes some time to complete and it blocks access to this table until the end of the process.
+ We advise you to only run this command while GitLab is not actively used or it is taken offline for the duration of the process.
+ The time it takes to complete depends on the size of the table, which can be obtained by using `select pg_size_pretty(pg_total_relation_size('merge_request_diff_commits'));`.
+
+ For more information, refer to [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/331823).
+
+- GitLab 14.5.0 includes a
+ [background migration `UpdateVulnerabilityOccurrencesLocation`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72788)
+ that may remain stuck permanently in a **pending** state when the instance lacks records that match the migration's target.
+
+ To clean up this stuck job, run the following in the [GitLab Rails Console](../../administration/operations/rails_console.md):
+
+ ```ruby
+ Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "UpdateVulnerabilityOccurrencesLocation").find_each do |job|
+ puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("UpdateVulnerabilityOccurrencesLocation", job.arguments)
+ end
+ ```
+
+- Upgrading to 14.5 (or later) [might encounter a one hour timeout](https://gitlab.com/gitlab-org/gitlab/-/issues/354211)
+ owing to a long running database data change.
+
+ ```plaintext
+ FATAL: Mixlib::ShellOut::CommandTimeout: rails_migration[gitlab-rails]
+ (gitlab::database_migrations line 51) had an error:
+ [..]
+ Mixlib::ShellOut::CommandTimeout: Command timed out after 3600s:
+ ```
+
+ [There is a workaround to complete the data change and the upgrade manually](../package/index.md#mixlibshelloutcommandtimeout-rails_migrationgitlab-rails--command-timed-out-after-3600s)
+
+- As part of [enabling real-time issue assignees](https://gitlab.com/gitlab-org/gitlab/-/issues/330117), Action Cable is now enabled by default.
+ For **self-compiled (source) installations**, `config/cable.yml` is required to be present.
+
+ Configure this by running:
+
+ ```shell
+ cd /home/git/gitlab
+ sudo -u git -H cp config/cable.yml.example config/cable.yml
+
+ # Change the Redis socket path if you are not using the default Debian / Ubuntu configuration
+ sudo -u git -H editor config/cable.yml
+ ```
+
+### Self-compiled installations
+
+- When `make` is run, Gitaly builds are now created in `_build/bin` and no longer in the root directory of the source directory. If you
+are using a self-compiled installation, update paths to these binaries in your [systemd unit files](../upgrading_from_source.md#configure-systemd-units)
+or [init scripts](../upgrading_from_source.md#configure-sysv-init-script) by [following the documentation](../upgrading_from_source.md).
+
+### Geo installations **(PREMIUM SELF)**
+
+- There is [an issue in GitLab 14.2 through 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/299819#note_822629467)
+ that affects Geo when the GitLab-managed object storage replication is used, causing blob object types to fail synchronization.
+
+ Since GitLab 14.2, verification failures result in synchronization failures and cause a resynchronization of these objects.
+
+ As verification is not yet implemented for files stored in object storage (see
+ [issue 13845](https://gitlab.com/gitlab-org/gitlab/-/issues/13845) for more details), this
+ results in a loop that consistently fails for all objects stored in object storage.
+
+ For information on how to fix this, see
+ [Troubleshooting - Failed syncs with GitLab-managed object storage replication](../../administration/geo/replication/troubleshooting.md#failed-syncs-with-gitlab-managed-object-storage-replication).
+
+## 14.4.4
+
+- For [zero-downtime upgrades](../zero_downtime.md) on a GitLab cluster with separate Web and API nodes, you must enable the `paginated_tree_graphql_query` [feature flag](../../administration/feature_flags.md#enable-or-disable-the-feature) _before_ upgrading GitLab Web nodes to 14.4.
+ This is because we [enabled `paginated_tree_graphql_query` by default in 14.4](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70913/diffs), so if GitLab UI is on 14.4 and its API is on 14.3, the frontend has this feature enabled but the backend has it disabled. This results in the following error:
+
+ ```shell
+ bundle.esm.js:63 Uncaught (in promise) Error: GraphQL error: Field 'paginatedTree' doesn't exist on type 'Repository'
+ ```
+
+## 14.4.1 and 14.4.2
+
+### Geo installations **(PREMIUM SELF)**
+
+- There is [an issue in GitLab 14.4.0 through 14.4.2](#1440) that can affect
+ Geo and other features that rely on cronjobs. We recommend upgrading to GitLab 14.4.3 or later.
+
+## 14.4.0
+
+- Git 2.33.x and later is required. We recommend you use the
+ [Git version provided by Gitaly](../../install/installation.md#git).
+- When [Maintenance mode](../../administration/maintenance_mode/index.md) is
+ enabled, users cannot sign in with SSO, SAML, or LDAP.
+
+ Users who were signed in before Maintenance mode was enabled, continue to be
+ signed in. If the administrator who enabled Maintenance mode loses their
+ session, then they can't disable Maintenance mode via the UI. In that case,
+ you can
+ [disable Maintenance mode via the API or Rails console](../../administration/maintenance_mode/index.md#disable-maintenance-mode).
+
+ [This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/329261) was fixed in
+ GitLab 14.5.0 and backported into 14.4.3 and 14.3.5.
+- After enabling database load balancing by default in 14.4.0, we found an issue where
+ [cron jobs would not work if the connection to PostgreSQL was severed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73716),
+ as Sidekiq would continue using a bad connection. Geo and other features that rely on
+ cron jobs running regularly do not work until Sidekiq is restarted. We recommend
+ upgrading to GitLab 14.4.3 and later if this issue affects you.
+- After enabling database load balancing by default in 14.4.0, we found an issue where
+ [Database load balancing does not work with an AWS Aurora cluster](https://gitlab.com/gitlab-org/gitlab/-/issues/220617).
+ We recommend moving your databases from Aurora to RDS for PostgreSQL before
+ upgrading. Refer to [Moving GitLab databases to a different PostgreSQL instance](../../administration/postgresql/moving.md).
+- GitLab 14.4.0 includes a
+[background migration `PopulateTopicsTotalProjectsCountCache`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71033)
+that may remain stuck permanently in a **pending** state when the instance lacks records that match the migration's target.
+
+ To clean up this stuck job, run the following in the [GitLab Rails Console](../../administration/operations/rails_console.md):
+
+ ```ruby
+ Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "PopulateTopicsTotalProjectsCountCache").find_each do |job|
+ puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("PopulateTopicsTotalProjectsCountCache", job.arguments)
+ end
+ ```
+
+### Linux package installations
+
+- In GitLab 14.4, the provided Grafana version is 7.5, this is a downgrade from the Grafana 8.1 version introduced in
+ GitLab 14.3. This was reverted to an Apache-licensed Grafana release to allow time to consider the implications of the
+ newer AGPL-licensed releases.
+
+ Users that have customized their Grafana install with plugins or library panels may experience errors in Grafana after
+ the downgrade. If the errors persist after a Grafana restart you may need to reset the Grafana db and re-add the
+ customizations. The Grafana database can be reset with `sudo gitlab-ctl reset-grafana`.
+
+### Geo installations **(PREMIUM SELF)**
+
+- There is [an issue in GitLab 14.2 through 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/299819#note_822629467)
+ that affects Geo when the GitLab-managed object storage replication is used, causing blob object types to fail synchronization.
+
+ Since GitLab 14.2, verification failures result in synchronization failures and cause a resynchronization of these objects.
+
+ As verification is not yet implemented for files stored in object storage (see
+ [issue 13845](https://gitlab.com/gitlab-org/gitlab/-/issues/13845) for more details), this
+ results in a loop that consistently fails for all objects stored in object storage.
+
+ For information on how to fix this, see
+ [Troubleshooting - Failed syncs with GitLab-managed object storage replication](../../administration/geo/replication/troubleshooting.md#failed-syncs-with-gitlab-managed-object-storage-replication).
+
+- There is [an issue in GitLab 14.4.0 through 14.4.2](#1440) that can affect
+ Geo and other features that rely on cronjobs. We recommend upgrading to GitLab 14.4.3 or later.
+
+## 14.3.0
+
+- [Instances running 14.0.0 - 14.0.4 should not upgrade directly to GitLab 14.2 or later](#upgrading-to-later-14y-releases).
+- Ensure [batched background migrations finish](../background_migrations.md#batched-background-migrations) before upgrading
+ to 14.3.Z from earlier GitLab 14 releases.
+- GitLab 14.3.0 contains post-deployment migrations to [address Primary Key overflow risk for tables with an integer PK](https://gitlab.com/groups/gitlab-org/-/epics/4785) for the tables listed below:
+
+ - [`ci_builds.id`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70245)
+ - [`ci_builds.stage_id`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66688)
+ - [`ci_builds_metadata`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65692)
+ - [`taggings`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66625)
+ - [`events`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64779)
+
+ If the migrations are executed as part of a no-downtime deployment, there's a risk of failure due to lock conflicts with the application logic, resulting in lock timeout or deadlocks. In each case, these migrations are safe to re-run until successful:
+
+ ```shell
+ # For Omnibus GitLab
+ sudo gitlab-rake db:migrate
+
+ # For source installations
+ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+ ```
+
+- After upgrading to 14.3, ensure that all the `MigrateMergeRequestDiffCommitUsers` background
+ migration jobs have completed before continuing with upgrading to GitLab 14.5 or later.
+ This is especially important if your GitLab instance has a large
+ `merge_request_diff_commits` table. Any pending
+ `MigrateMergeRequestDiffCommitUsers` background migration jobs are
+ foregrounded in GitLab 14.5, and may take a long time to complete.
+ You can check the count of pending jobs for
+ `MigrateMergeRequestDiffCommitUsers` by using the PostgreSQL console (or `sudo
+ gitlab-psql`):
+
+ ```sql
+ select status, count(*) from background_migration_jobs
+ where class_name = 'MigrateMergeRequestDiffCommitUsers' group by status;
+ ```
+
+ As jobs are completed, the database records change from `0` (pending) to `1`. If the number of
+ pending jobs doesn't decrease after a while, it's possible that the
+ `MigrateMergeRequestDiffCommitUsers` background migration jobs have failed. You
+ can check for errors in the Sidekiq logs:
+
+ ```shell
+ sudo grep MigrateMergeRequestDiffCommitUsers /var/log/gitlab/sidekiq/current | grep -i error
+ ```
+
+ If needed, you can attempt to run the `MigrateMergeRequestDiffCommitUsers` background
+ migration jobs manually in the [GitLab Rails Console](../../administration/operations/rails_console.md).
+ This can be done using Sidekiq asynchronously, or by using a Rails process directly:
+
+ - Using Sidekiq to schedule jobs asynchronously:
+
+ ```ruby
+ # For the first run, only attempt to execute 1 migration. If successful, increase
+ # the limit for subsequent runs
+ limit = 1
+
+ jobs = Gitlab::Database::BackgroundMigrationJob.for_migration_class('MigrateMergeRequestDiffCommitUsers').pending.to_a
+
+ pp "#{jobs.length} jobs remaining"
+
+ jobs.first(limit).each do |job|
+ BackgroundMigrationWorker.perform_in(5.minutes, 'MigrateMergeRequestDiffCommitUsers', job.arguments)
+ end
+ ```
+
+ NOTE:
+ The queued jobs can be monitored using the Sidekiq admin panel, which can be accessed at the `/admin/sidekiq` endpoint URI.
+
+ - Using a Rails process to run jobs synchronously:
+
+ ```ruby
+ def process(concurrency: 1)
+ queue = Queue.new
+
+ Gitlab::Database::BackgroundMigrationJob
+ .where(class_name: 'MigrateMergeRequestDiffCommitUsers', status: 0)
+ .each { |job| queue << job }
+
+ concurrency
+ .times
+ .map do
+ Thread.new do
+ Thread.abort_on_exception = true
+
+ loop do
+ job = queue.pop(true)
+ time = Benchmark.measure do
+ Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers
+ .new
+ .perform(*job.arguments)
+ end
+
+ puts "#{job.id} finished in #{time.real.round(2)} seconds"
+ rescue ThreadError
+ break
+ end
+ end
+ end
+ .each(&:join)
+ end
+
+ ActiveRecord::Base.logger.level = Logger::ERROR
+ process
+ ```
+
+ NOTE:
+ When using Rails to execute these background migrations synchronously, make sure that the machine running the process has sufficient resources to handle the task. If the process gets terminated, it's likely due to insufficient memory available. If your SSH session times out after a while, it might be necessary to run the previous code by using a terminal multiplexer like `screen` or `tmux`.
+
+- When [Maintenance mode](../../administration/maintenance_mode/index.md) is
+ enabled, users cannot sign in with SSO, SAML, or LDAP.
+
+ Users who were signed in before Maintenance mode was enabled, continue to be
+ signed in. If the administrator who enabled Maintenance mode loses their
+ session, then they can't disable Maintenance mode via the UI. In that case,
+ you can
+ [disable Maintenance mode via the API or Rails console](../../administration/maintenance_mode/index.md#disable-maintenance-mode).
+
+ [This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/329261) was fixed in
+ GitLab 14.5.0 and backported into 14.4.3 and 14.3.5.
+
+- You may see the following error when setting up two factor authentication (2FA) for accounts
+ that authenticate using an LDAP password:
+
+ ```plaintext
+ You must provide a valid current password
+ ```
+
+ - The error occurs because verification is incorrectly performed against accounts'
+ randomly generated internal GitLab passwords, not the LDAP passwords.
+ - This is [fixed in GitLab 14.5.0 and backported to 14.4.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73538).
+ - Workarounds:
+ - Instead of upgrading to GitLab 14.3.x to comply with the supported upgrade path:
+ 1. Upgrade to 14.4.5.
+ 1. Make sure the [`MigrateMergeRequestDiffCommitUsers` background migration](#1430) has finished.
+ 1. Upgrade to GitLab 14.5 or later.
+ - Reset the random password for affected accounts, using [the Rake task](../../security/reset_user_password.md#use-a-rake-task):
+
+ ```plaintext
+ sudo gitlab-rake "gitlab:password:reset[user_handle]"
+ ```
+
+- If you encounter the error, `I18n::InvalidLocale: :en is not a valid locale`, when starting the application, follow the [patching](https://about.gitlab.com/handbook/support/workflows/patching_an_instance.html) process. Use [122978](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122978) as the `mr_iid`.
+
+### Self-compiled installations
+
+- Ruby 2.7.4 is required. Refer to [the Ruby installation instructions](../../install/installation.md#2-ruby)
+ for how to proceed.
+
+### Geo installations **(PREMIUM SELF)**
+
+- There is [an issue in GitLab 14.2 through 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/299819#note_822629467)
+ that affects Geo when the GitLab-managed object storage replication is used, causing blob object types to fail synchronization.
+
+ Since GitLab 14.2, verification failures result in synchronization failures and cause a resynchronization of these objects.
+
+ As verification is not yet implemented for files stored in object storage (see
+ [issue 13845](https://gitlab.com/gitlab-org/gitlab/-/issues/13845) for more details), this
+ results in a loop that consistently fails for all objects stored in object storage.
+
+ For information on how to fix this, see
+ [Troubleshooting - Failed syncs with GitLab-managed object storage replication](../../administration/geo/replication/troubleshooting.md#failed-syncs-with-gitlab-managed-object-storage-replication).
+
+- We found an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/336013) where the Container Registry replication
+ wasn't fully working if you used multi-arch images. In case of a multi-arch image, only the primary architecture
+ (for example `amd64`) would be replicated to the secondary site. This has been [fixed in GitLab 14.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67624) and was backported to 14.2 and 14.1, but manual steps are required to force a re-sync.
+
+ You can check if you are affected by running:
+
+ ```shell
+ docker manifest inspect <SECONDARY_IMAGE_LOCATION> | jq '.mediaType'
+ ```
+
+ Where `<SECONDARY_IMAGE_LOCATION>` is a container image on your secondary site.
+ If the output matches `application/vnd.docker.distribution.manifest.list.v2+json`
+ (there can be a `mediaType` entry at several levels, we only care about the top level entry),
+ then you don't need to do anything.
+
+ Otherwise, for each **secondary** site, on a Rails application node, open a [Rails console](../../administration/operations/rails_console.md), and run the following:
+
+ ```ruby
+ list_type = 'application/vnd.docker.distribution.manifest.list.v2+json'
+
+ Geo::ContainerRepositoryRegistry.synced.each do |gcr|
+ cr = gcr.container_repository
+ primary = Geo::ContainerRepositorySync.new(cr)
+ cr.tags.each do |tag|
+ primary_manifest = JSON.parse(primary.send(:client).repository_raw_manifest(cr.path, tag.name))
+ next unless primary_manifest['mediaType'].eql?(list_type)
+
+ cr.delete_tag_by_name(tag.name)
+ end
+ primary.execute
+ end
+ ```
+
+ If you are running a version prior to 14.1 and are using Geo and multi-arch containers in your Container Registry,
+ we recommend [upgrading](../../administration/geo/replication/upgrading_the_geo_sites.md) to at least GitLab 14.1.
+
+## 14.2.0
+
+- [Instances running 14.0.0 - 14.0.4 should not upgrade directly to GitLab 14.2 or later](#upgrading-to-later-14y-releases).
+- Ensure [batched background migrations finish](../background_migrations.md#batched-background-migrations) before upgrading
+ to 14.2.Z from earlier GitLab 14 releases.
+- GitLab 14.2.0 contains background migrations to [address Primary Key overflow risk for tables with an integer PK](https://gitlab.com/groups/gitlab-org/-/epics/4785) for the tables listed below:
+ - [`ci_build_needs`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65216)
+ - [`ci_build_trace_chunks`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66123)
+ - [`ci_builds_runner_session`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66433)
+ - [`deployments`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67341)
+ - [`geo_job_artifact_deleted_events`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66763)
+ - [`push_event_payloads`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67299)
+ - `ci_job_artifacts`:
+ - [Finalize `job_id` conversion to `bigint` for `ci_job_artifacts`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67774)
+ - [Finalize `ci_job_artifacts` conversion to `bigint`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65601)
+
+ If the migrations are executed as part of a no-downtime deployment, there's a risk of failure due to lock conflicts with the application logic, resulting in lock timeout or deadlocks. In each case, these migrations are safe to re-run until successful:
+
+ ```shell
+ # For Omnibus GitLab
+ sudo gitlab-rake db:migrate
+
+ # For source installations
+ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+ ```
+
+- When [Maintenance mode](../../administration/maintenance_mode/index.md) is
+ enabled, users cannot sign in with SSO, SAML, or LDAP.
+
+ Users who were signed in before Maintenance mode was enabled, continue to be
+ signed in. If the administrator who enabled Maintenance mode loses their
+ session, then they can't disable Maintenance mode via the UI. In that case,
+ you can
+ [disable Maintenance mode via the API or Rails console](../../administration/maintenance_mode/index.md#disable-maintenance-mode).
+
+ [This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/329261) was fixed in
+ GitLab 14.5.0 and backported into 14.4.3 and 14.3.5.
+- GitLab 14.2.0 includes a
+ [background migration `BackfillDraftStatusOnMergeRequests`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67687)
+ that may remain stuck permanently in a **pending** state when the instance lacks records that match the migration's target.
+
+ To clean up this stuck job, run the following in the [GitLab Rails Console](../../administration/operations/rails_console.md):
+
+ ```ruby
+ Gitlab::Database::BackgroundMigrationJob.pending.where(class_name: "BackfillDraftStatusOnMergeRequests").find_each do |job|
+ puts Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded("BackfillDraftStatusOnMergeRequests", job.arguments)
+ end
+ ```
+
+- If you encounter the error, `I18n::InvalidLocale: :en is not a valid locale`, when starting the application, follow the [patching](https://about.gitlab.com/handbook/support/workflows/patching_an_instance.html) process. Use [123476](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123476) as the `mr_iid`.
+
+### Geo installations **(PREMIUM SELF)**
+
+- There is [an issue in GitLab 14.2 through 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/299819#note_822629467)
+ that affects Geo when the GitLab-managed object storage replication is used, causing blob object types to fail synchronization.
+
+ Since GitLab 14.2, verification failures result in synchronization failures and cause a resynchronization of these objects.
+
+ As verification is not yet implemented for files stored in object storage (see
+ [issue 13845](https://gitlab.com/gitlab-org/gitlab/-/issues/13845) for more details), this
+ results in a loop that consistently fails for all objects stored in object storage.
+
+ For information on how to fix this, see
+ [Troubleshooting - Failed syncs with GitLab-managed object storage replication](../../administration/geo/replication/troubleshooting.md#failed-syncs-with-gitlab-managed-object-storage-replication).
+
+- We found an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/336013) where the Container Registry replication
+ wasn't fully working if you used multi-arch images. In case of a multi-arch image, only the primary architecture
+ (for example `amd64`) would be replicated to the secondary site. This has been [fixed in GitLab 14.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67624) and was backported to 14.2 and 14.1, but manual steps are required to force a re-sync.
+
+ You can check if you are affected by running:
+
+ ```shell
+ docker manifest inspect <SECONDARY_IMAGE_LOCATION> | jq '.mediaType'
+ ```
+
+ Where `<SECONDARY_IMAGE_LOCATION>` is a container image on your secondary site.
+ If the output matches `application/vnd.docker.distribution.manifest.list.v2+json`
+ (there can be a `mediaType` entry at several levels, we only care about the top level entry),
+ then you don't need to do anything.
+
+ Otherwise, for each **secondary** site, on a Rails application node, open a [Rails console](../../administration/operations/rails_console.md), and run the following:
+
+ ```ruby
+ list_type = 'application/vnd.docker.distribution.manifest.list.v2+json'
+
+ Geo::ContainerRepositoryRegistry.synced.each do |gcr|
+ cr = gcr.container_repository
+ primary = Geo::ContainerRepositorySync.new(cr)
+ cr.tags.each do |tag|
+ primary_manifest = JSON.parse(primary.send(:client).repository_raw_manifest(cr.path, tag.name))
+ next unless primary_manifest['mediaType'].eql?(list_type)
+
+ cr.delete_tag_by_name(tag.name)
+ end
+ primary.execute
+ end
+ ```
+
+ If you are running a version prior to 14.1 and are using Geo and multi-arch containers in your Container Registry,
+ we recommend [upgrading](../../administration/geo/replication/upgrading_the_geo_sites.md) to at least GitLab 14.1.
+
+## 14.1.0
+
+- [Instances running 14.0.0 - 14.0.4 should not upgrade directly to GitLab 14.2 or later](#upgrading-to-later-14y-releases)
+ but can upgrade to 14.1.Z.
+
+ It is not required for instances already running 14.0.5 (or later) to stop at 14.1.Z.
+ 14.1 is included on the upgrade path for the broadest compatibility
+ with self-managed installations, and ensure 14.0.0-14.0.4 installations do not
+ encounter issues with [batched background migrations](../background_migrations.md#batched-background-migrations).
+
+- Upgrading to GitLab [14.5](#1450) (or later) may take a lot longer if you do not upgrade to at least 14.1
+ first. The 14.1 merge request diff commits database migration can take hours to run, but runs in the
+ background while GitLab is in use. GitLab instances upgraded directly from 14.0 to 14.5 or later must
+ run the migration in the foreground and therefore take a lot longer to complete.
+
+- When [Maintenance mode](../../administration/maintenance_mode/index.md) is
+ enabled, users cannot sign in with SSO, SAML, or LDAP.
+
+ Users who were signed in before Maintenance mode was enabled, continue to be
+ signed in. If the administrator who enabled Maintenance mode loses their
+ session, then they can't disable Maintenance mode via the UI. In that case,
+ you can
+ [disable Maintenance mode via the API or Rails console](../../administration/maintenance_mode/index.md#disable-maintenance-mode).
+
+ [This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/329261) was fixed in
+ GitLab 14.5.0 and backported into 14.4.3 and 14.3.5.
+
+- If you encounter the error, `I18n::InvalidLocale: :en is not a valid locale`, when starting the application, follow the [patching](https://about.gitlab.com/handbook/support/workflows/patching_an_instance.html) process. Use [123475](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123475) as the `mr_iid`.
+
+### Geo installations **(PREMIUM SELF)**
+
+- We found an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/336013) where the Container Registry replication
+ wasn't fully working if you used multi-arch images. In case of a multi-arch image, only the primary architecture
+ (for example `amd64`) would be replicated to the secondary site. This has been [fixed in GitLab 14.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67624) and was backported to 14.2 and 14.1, but manual steps are required to force a re-sync.
+
+ You can check if you are affected by running:
+
+ ```shell
+ docker manifest inspect <SECONDARY_IMAGE_LOCATION> | jq '.mediaType'
+ ```
+
+ Where `<SECONDARY_IMAGE_LOCATION>` is a container image on your secondary site.
+ If the output matches `application/vnd.docker.distribution.manifest.list.v2+json`
+ (there can be a `mediaType` entry at several levels, we only care about the top level entry),
+ then you don't need to do anything.
+
+ Otherwise, for each **secondary** site, on a Rails application node, open a [Rails console](../../administration/operations/rails_console.md), and run the following:
+
+ ```ruby
+ list_type = 'application/vnd.docker.distribution.manifest.list.v2+json'
+
+ Geo::ContainerRepositoryRegistry.synced.each do |gcr|
+ cr = gcr.container_repository
+ primary = Geo::ContainerRepositorySync.new(cr)
+ cr.tags.each do |tag|
+ primary_manifest = JSON.parse(primary.send(:client).repository_raw_manifest(cr.path, tag.name))
+ next unless primary_manifest['mediaType'].eql?(list_type)
+
+ cr.delete_tag_by_name(tag.name)
+ end
+ primary.execute
+ end
+ ```
+
+ If you are running a version prior to 14.1 and are using Geo and multi-arch containers in your Container Registry,
+ we recommend [upgrading](../../administration/geo/replication/upgrading_the_geo_sites.md) to at least GitLab 14.1.
+- We found an issue where [Primary sites cannot be removed from the UI](https://gitlab.com/gitlab-org/gitlab/-/issues/338231).
+
+ This bug only exists in the UI and does not block the removal of Primary sites using any other method.
+
+ If you are running an affected version and need to remove your Primary site, you can manually remove the Primary site
+ by using the [Geo Sites API](../../api/geo_nodes.md#delete-a-geo-node).
+
+## 14.0.0
+
+Prerequisites:
+
+- The [GitLab 14.0 release post contains several important notes](https://about.gitlab.com/releases/2021/06/22/gitlab-14-0-released/#upgrade)
+ about pre-requisites including [using Patroni instead of repmgr](../../administration/postgresql/replication_and_failover.md#switching-from-repmgr-to-patroni),
+ migrating [to hashed storage](../../administration/raketasks/storage.md#migrate-to-hashed-storage),
+ and [to Puma](../../administration/operations/puma.md).
+- The support of PostgreSQL 11 [has been dropped](../../install/requirements.md#database). Make sure to [update your database](https://docs.gitlab.com/omnibus/settings/database.html#upgrade-packaged-postgresql-server) to version 12 before updating to GitLab 14.0.
+
+Long running batched background database migrations:
+
+- Database changes made by the upgrade to GitLab 14.0 can take hours or days to complete on larger GitLab instances.
+ These [batched background migrations](../background_migrations.md#batched-background-migrations) update whole database tables to mitigate primary key overflow and must be finished before upgrading to GitLab 14.2 or later.
+- Due to an issue where `BatchedBackgroundMigrationWorkers` were
+ [not working](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/2785#note_614738345)
+ for self-managed instances, a [fix was created](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65106)
+ that requires an update to at least 14.0.5. The fix was also released in [14.1.0](#1410).
+
+ After you update to 14.0.5 or a later 14.0 patch version,
+ [batched background migrations must finish](../background_migrations.md#batched-background-migrations)
+ before you upgrade to a later version.
+
+ If the migrations are not finished and you try to upgrade to a later version,
+ you see an error like:
+
+ ```plaintext
+ Expected batched background migration for the given configuration to be marked as 'finished', but it is 'active':
+ ```
+
+ See how to [resolve this error](../background_migrations.md#database-migrations-failing-because-of-batched-background-migration-not-finished).
+
+Other issues:
+
+- In GitLab 13.3 some [pipeline processing methods were deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/218536)
+ and this code was completely removed in GitLab 14.0. If you plan to upgrade from
+ **GitLab 13.2 or older** directly to 14.0, this is [unsupported](../index.md#upgrading-to-a-new-major-version).
+ You should instead follow a [supported upgrade path](../index.md#upgrade-paths).
+- When [Maintenance mode](../../administration/maintenance_mode/index.md) is
+ enabled, users cannot sign in with SSO, SAML, or LDAP.
+
+ Users who were signed in before Maintenance mode was enabled, continue to be
+ signed in. If the administrator who enabled Maintenance mode loses their
+ session, then they can't disable Maintenance mode via the UI. In that case,
+ you can
+ [disable Maintenance mode via the API or Rails console](../../administration/maintenance_mode/index.md#disable-maintenance-mode).
+
+ [This bug](https://gitlab.com/gitlab-org/gitlab/-/issues/329261) was fixed in
+ GitLab 14.5.0 and backported into 14.4.3 and 14.3.5.
+- **In GitLab 13.12.2 and later**, users with expired passwords can no longer authenticate with API and Git using tokens because of
+ the [Insufficient Expired Password Validation](https://about.gitlab.com/releases/2021/06/01/security-release-gitlab-13-12-2-released/#insufficient-expired-password-validation)
+ security fix. If your users get authentication issues following the upgrade, check that their password is not expired:
+
+ 1. [Connect to the PostgreSQL database](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-postgresql-database) and execute the
+ following query:
+
+ ```sql
+ select id,username,password_expires_at from users where password_expires_at < now();
+ ```
+
+ 1. If the user is in the returned list, reset the `password_expires_at` for that user:
+
+ ```sql
+ update users set password_expires_at = null where username='<USERNAME>';
+ ```
+
+### Linux package installations
+
+- In GitLab 13.0, `sidekiq-cluster` was enabled by default and the `sidekiq` service ran `sidekiq-cluster` under the hood.
+ However, users could control this behavior using `sidekiq['cluster']` setting to run Sidekiq directly instead. Users
+ could also run `sidekiq-cluster` separately using the various `sidekiq_cluster[*]` settings available in `gitlab.rb`.
+ However these features were deprecated and are now being removed.
+
+ Starting with GitLab 14.0, `sidekiq-cluster` becomes the only way to run Sidekiq in Linux package installations. As
+ part of this process, support for the following settings in `gitlab.rb` is being removed:
+
+ - `sidekiq['cluster']` setting. Sidekiq can only be run using `sidekiq-cluster` now.
+ - `sidekiq_cluster[*]` settings. They should be set via respective `sidekiq[*]` counterparts.
+ - `sidekiq['concurrency']` setting. The limits should be controlled using the two settings `sidekiq['min_concurrency']`
+ and `sidekiq['max_concurrency']`.
+
+- In GitLab 13.0, Puma became the default web server for GitLab, but users were still able to continue using Unicorn if
+ needed. Starting with GitLab 14.0, Unicorn is no longer supported as a webserver for GitLab and is no longer shipped
+ with the Linux package.
+
+ Users must migrate to Puma following [the documentation](../../administration/operations/puma.md) to upgrade to GitLab
+ 14.0.
+- The Consul version has been updated from 1.6.10 to 1.9.6 for Geo and multi-node PostgreSQL installs. Its important
+ that Consul nodes be upgraded and restarted one at a time.
+
+ For more information, see [Upgrade the Consul nodes](../../administration/consul.md#upgrade-the-consul-nodes).
+- Starting with GitLab 14.0, GitLab automatically generates a password for initial administrator user (`root`) and stores
+ this value to `/etc/gitlab/initial_root_password`.
+
+ For more information, see
+ [Set up the initial password](https://docs.gitlab.com/omnibus/installation/index.html#set-up-the-initial-password).
+- The binaries for PostgreSQL 11 and repmgr have been removed. Prior to upgrading, administrators of Linux package
+ installations must:
+ 1. Ensure the installation is using [PostgreSQL 12](https://docs.gitlab.com/omnibus/settings/database.html#upgrade-packaged-postgresql-server).
+ 1. If using repmgr, [convert to using patroni](../../administration/postgresql/replication_and_failover.md#switching-from-repmgr-to-patroni).
+- Two configuration options for Redis were deprecated in GitLab 13 and removed in GitLab 14:
+
+ - `redis_slave_role` is replaced with `redis_replica_role`.
+ - `redis['client_output_buffer_limit_slave']` is replaced with `redis['client_output_buffer_limit_replica']`.
+
+ Redis Cache nodes being upgraded from GitLab 13.12 to 14.0 that still refer to `redis_slave_role` in `gitlab.rb` will
+ encounter an error in the output of `gitlab-ctl reconfigure`:
+
+ ```plaintext
+ There was an error running gitlab-ctl reconfigure:
+
+ The following invalid roles have been set in 'roles': redis_slave_role
+ ```
+
+### Geo installations **(PREMIUM SELF)**
+
+- We found an issue where [Primary sites cannot be removed from the UI](https://gitlab.com/gitlab-org/gitlab/-/issues/338231).
+
+ This bug only exists in the UI and does not block the removal of Primary sites using any other method.
+
+ If you are running an affected version and need to remove your Primary site, you can manually remove the Primary site
+ by using the [Geo Sites API](../../api/geo_nodes.md#delete-a-geo-node).
+
+### Upgrading to later 14.Y releases
+
+- Instances running 14.0.0 - 14.0.4 should not upgrade directly to GitLab 14.2 or later,
+ because of [batched background migrations](../background_migrations.md#batched-background-migrations).
+ 1. Upgrade first to either:
+ - 14.0.5 or a later 14.0.Z patch release.
+ - 14.1.0 or a later 14.1.Z patch release.
+ 1. [Batched background migrations must finish](../background_migrations.md#batched-background-migrations)
+ before you upgrade to a later version [and may take longer than usual](#1400).
diff --git a/doc/update/versions/gitlab_15_changes.md b/doc/update/versions/gitlab_15_changes.md
new file mode 100644
index 00000000000..12cbf5c5ec1
--- /dev/null
+++ b/doc/update/versions/gitlab_15_changes.md
@@ -0,0 +1,921 @@
+---
+stage: Systems
+group: Distribution
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# GitLab 15 changes **(FREE SELF)**
+
+This page contains upgrade information for minor and patch versions of GitLab 15.
+Ensure you review these instructions for:
+
+- Your installation type.
+- All versions between your current version and your target version.
+
+For more information about upgrading GitLab Helm Chart, see [the release notes for 6.0](https://docs.gitlab.com/charts/releases/6_0.html).
+
+## 15.11.1
+
+- Many [project importers](../../user/project/import/index.md) and [group importers](../../user/group/import/index.md) now
+ require the Maintainer role instead of only requiring the Developer role. For more information, see the documentation
+ for any importers you use.
+
+## 15.11.0
+
+- **Upgrade to patch release 15.11.3 or later**. This avoids [issue 408304](https://gitlab.com/gitlab-org/gitlab/-/issues/408304) when upgrading from 15.5.0 and earlier.
+
+### Linux package installations
+
+In GitLab 15.11, PostgreSQL will automatically be upgraded to 13.x except for the following cases:
+
+- You are running the database in high availability using Patroni.
+- Your database nodes are part of a GitLab Geo configuration.
+- You have specifically [opted out](https://docs.gitlab.com/omnibus/settings/database.html#opt-out-of-automatic-postgresql-upgrades) from automatically upgrading PostgreSQL.
+- You have `postgresql['version'] = 12` in your `/etc/gitlab/gitlab.rb`.
+
+Fault-tolerant and Geo installations support manual upgrades to PostgreSQL 13,
+see [Packaged PostgreSQL deployed in an HA/Geo Cluster](https://docs.gitlab.com/omnibus/settings/database.html#packaged-postgresql-deployed-in-an-hageo-cluster).
+
+### Geo installations **(PREMIUM SELF)**
+
+- Some project imports do not initialize wiki repositories on project creation. See
+ [the details and workaround](gitlab_16_changes.md#wiki-repositories-not-initialized-on-project-creation).
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+
+#### `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13
+
+| Affected minor releases | Affected patch releases | Fixed in |
+|-------------------------|-------------------------|----------|
+| 15.2 - 15.10 | All | None |
+| 15.11 | 15.11.0 - 15.11.11 | 15.11.12 and later |
+
+A [bug](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7841) in the
+built-in `pg-upgrade` tool prevents upgrading the bundled PostgreSQL database
+to version 13. This leaves the secondary site in a broken state, and prevents
+upgrading the Geo installation to GitLab 16.x
+([PostgreSQL 12 support has removed in 16.0](../deprecations.md#postgresql-12-deprecated) and later
+releases). This occurs on secondary sites using the bundled PostgreSQL
+software, running both the secondary main Rails database and tracking database
+on the same node. There is a manual
+[workaround](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7841#workaround)
+if you can't upgrade to 15.11.12 and later.
+
+## 15.11.x
+
+- A [bug](https://gitlab.com/gitlab-org/gitlab/-/issues/411604) can cause new LDAP users signing in for the first time to be assigned a username based on their email address instead of their LDAP username attribute. A manual workaround is to set `gitlab_rails['omniauth_auto_link_ldap_user'] = true`, or upgrade to GitLab 16.1 or later where the bug has been fixed.
+
+## 15.10.5
+
+- A [bug with Elastic Indexer Cron Workers](https://gitlab.com/gitlab-org/gitlab/-/issues/408214) can cause saturation in Sidekiq.
+ - When this issue occurs, merge request merges, pipelines, Slack notifications, and other events are not created or take a long time to occur.
+ - This issue may not manifest immediately as it can take up to a week before the Sidekiq is saturated enough.
+ - Elasticsearch does not need to be enabled for this to occur.
+ - To resolve this issue, upgrade to 15.11 or use the workaround in the issue.
+- Many [project importers](../../user/project/import/index.md) and [group importers](../../user/group/import/index.md) now
+ require the Maintainer role instead of only requiring the Developer role. For more information, see the documentation
+ for any importers you use.
+
+## 15.10.0
+
+- A [bug with Elastic Indexer Cron Workers](https://gitlab.com/gitlab-org/gitlab/-/issues/408214) can cause saturation in Sidekiq.
+ - When this issue occurs, merge request merges, pipelines, Slack notifications, and other events are not created or take a long time to occur.
+ - This issue may not manifest immediately as it can take up to a week before the Sidekiq is saturated enough.
+ - Elasticsearch does not need to be enabled for this to occur.
+ - To resolve this issue, upgrade to 15.11 or use the workaround in the issue.
+- A [bug with zero-downtime reindexing](https://gitlab.com/gitlab-org/gitlab/-/issues/422938) can cause a `Couldn't load task status` error when you reindex. You might also get a `sliceId must be greater than 0 but was [-1]` error on the Elasticsearch host. As a workaround, consider [reindexing from scratch](../../integration/advanced_search/elasticsearch_troubleshooting.md#last-resort-to-recreate-an-index) or upgrading to GitLab 16.3.
+- Gitaly configuration changes significantly in Omnibus GitLab 16.0. You can begin migrating to the new structure in Omnibus GitLab 15.10 while backwards compatibility is
+ maintained in the lead up to Omnibus GitLab 16.0. [Read more about this change](gitlab_16_changes.md#gitaly-configuration-structure-change).
+- You might encounter the following error while upgrading to GitLab 15.10 or later:
+
+ ```shell
+ STDOUT: rake aborted!
+ StandardError: An error has occurred, all later migrations canceled:
+ PG::CheckViolation: ERROR: check constraint "check_70f294ef54" is violated by some row
+ ```
+
+ This error is caused by a [batched background migration introduced in GitLab 15.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107701)
+ not being finalized before GitLab 15.10. To resolve this error:
+
+ 1. Execute the following SQL statement using the database console (`sudo gitlab-psql` for Linux package installs):
+
+ ```sql
+ UPDATE oauth_access_tokens SET expires_in = '7200' WHERE expires_in IS NULL;
+ ```
+
+ 1. [Re-run database migrations](../../administration/raketasks/maintenance.md#run-incomplete-database-migrations).
+
+- You might also encounter the following error while upgrading to GitLab 15.10 or later:
+
+ ```shell
+ "exception.class": "ActiveRecord::StatementInvalid",
+ "exception.message": "PG::SyntaxError: ERROR: zero-length delimited identifier at or near \"\"\"\"\nLINE 1: ...COALESCE(\"lock_version\", 0) + 1 WHERE \"ci_builds\".\"\" IN (SEL...\n
+ ```
+
+ This error is caused by a [batched background migration introduced in GitLab 14.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81410)
+ not being finalized before upgrading to GitLab 15.10 or later. To resolve this error, it is safe to [mark the migration as complete](../background_migrations.md#mark-a-failed-migration-finished):
+
+ ```ruby
+ # Start the rails console
+
+ connection = Ci::ApplicationRecord.connection
+
+ Gitlab::Database::SharedModel.using_connection(connection) do
+ migration = Gitlab::Database::BackgroundMigration::BatchedMigration.find_for_configuration(
+ Gitlab::Database.gitlab_schemas_for_connection(connection), 'NullifyOrphanRunnerIdOnCiBuilds', :ci_builds, :id, [])
+
+ # mark all jobs completed
+ migration.batched_jobs.update_all(status: Gitlab::Database::BackgroundMigration::BatchedJob.state_machine.states[:succeeded].value)
+ migration.update_attribute(:status, Gitlab::Database::BackgroundMigration::BatchedMigration.state_machine.states[:finished].value)
+ end
+ ```
+
+ For more information, see [issue 415724](https://gitlab.com/gitlab-org/gitlab/-/issues/415724).
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+
+## 15.9.0
+
+- A [bug with Elastic Indexer Cron Workers](https://gitlab.com/gitlab-org/gitlab/-/issues/408214) can cause saturation in Sidekiq.
+ - When this issue occurs, merge request merges, pipelines, Slack notifications, and other events are not created or take a long time to occur.
+ - This issue may not manifest immediately as it can take up to a week before the Sidekiq is saturated enough.
+ - Elasticsearch does not need to be enabled for this to occur.
+ - To resolve this issue, upgrade to 15.11 or use the workaround in the issue.
+- **Upgrade to patch release 15.9.3 or later**. This provides fixes for two database migration bugs:
+ - Patch releases 15.9.0, 15.9.1, 15.9.2 have a bug that can cause data loss
+ from the user profile fields `linkedin`, `twitter`, `skype`, `website_url`,
+ `location`, and `organization`. For more information, see
+ [issue 393216](https://gitlab.com/gitlab-org/gitlab/-/issues/393216).
+ - The second [bug fix](https://gitlab.com/gitlab-org/gitlab/-/issues/394760) ensures it is possible to upgrade directly from 15.4.x.
+- As part of the [CI Partitioning effort](../../architecture/blueprints/ci_data_decay/pipeline_partitioning.md), a [new Foreign Key](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107547) was added to `ci_builds_needs`. On GitLab instances with large CI tables, adding this constraint can take longer than usual.
+- Praefect's metadata verifier's [invalid metadata deletion behavior](../../administration/gitaly/praefect.md#enable-deletions) is now enabled by default.
+
+ The metadata verifier processes replica records in the Praefect database and verifies the replicas actually exist on the Gitaly nodes. If the replica doesn't exist, its
+ metadata record is deleted. This enables Praefect to fix situations where a replica has a metadata record indicating it's fine but, in reality, it doesn't exist on disk.
+ After the metadata record is deleted, Praefect's reconciler schedules a replication job to recreate the replica.
+
+ Because of past issues with the state management logic, there may be invalid metadata records in the database. These could exist, for example, because of incomplete
+ deletions of repositories or partially completed renames. The verifier deletes these stale replica records of affected repositories. These repositories may show up as
+ unavailable repositories in the metrics and `praefect dataloss` sub-command because of the replica records being removed. If you encounter such repositories, remove
+ the repository using `praefect remove-repository` to remove the repository's remaining records.
+
+ You can find repositories with invalid metadata records prior in GitLab 15.0 and later by searching for the log records outputted by the verifier. [Read more about repository verification, and to see an example log entry](../../administration/gitaly/praefect.md#repository-verification).
+- Praefect configuration changes significantly in Omnibus GitLab 16.0. You can begin migrating to the new structure in Omnibus GitLab 15.9 while backwards compatibility is
+ maintained in the lead up to Omnibus GitLab 16.0. [Read more about this change](gitlab_16_changes.md#praefect-configuration-structure-change).
+
+### Self-compiled installations
+
+- For **self-compiled (source) installations**, with the addition of `gitlab-sshd` the Kerberos headers are needed to build GitLab Shell.
+
+ ```shell
+ sudo apt install libkrb5-dev
+ ```
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+
+## 15.8.2
+
+### Geo installations **(PREMIUM SELF)**
+
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.8.1
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.8.0
+
+- Git 2.38.0 and later is required by Gitaly. For self-compiled installations, you should use the [Git version provided by Gitaly](../../install/installation.md#git).
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.7.6
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.7.5
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.7.4
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.7.3
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.7.2
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the upgrades. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.7.1
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.7.0
+
+- This version validates a `NOT NULL DB` constraint on the `issues.work_item_type_id` column.
+ To upgrade to this version, no records with a `NULL` `work_item_type_id` should exist on the `issues` table.
+ There are multiple `BackfillWorkItemTypeIdForIssues` background migrations that will be finalized with
+ the `EnsureWorkItemTypeBackfillMigrationFinished` post-deploy migration.
+- GitLab 15.4.0 introduced a [batched background migration](../background_migrations.md#batched-background-migrations) to
+ [backfill `namespace_id` values on issues table](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91921). This
+ migration might take multiple hours or days to complete on larger GitLab instances. Make sure the migration
+ has completed successfully before upgrading to 15.7.0.
+- A database constraint is added, specifying that the `namespace_id` column on the issues
+ table has no `NULL` values.
+
+ - If the `namespace_id` batched background migration from 15.4 failed (see above) then the 15.7 upgrade
+ fails with a database migration error.
+
+ - On GitLab instances with large issues tables, validating this constraint causes the upgrade to take
+ longer than usual. All database changes need to complete within a one-hour limit:
+
+ ```plaintext
+ FATAL: Mixlib::ShellOut::CommandTimeout: rails_migration[gitlab-rails]
+ [..]
+ Mixlib::ShellOut::CommandTimeout: Command timed out after 3600s:
+ ```
+
+ A workaround exists to [complete the data change and the upgrade manually](../package/index.md#mixlibshelloutcommandtimeout-rails_migrationgitlab-rails--command-timed-out-after-3600s).
+- The default Sidekiq `max_concurrency` has been changed to 20. This is now
+ consistent in our documentation and product defaults.
+
+ For example, previously:
+
+ - Linux package installation default (`sidekiq['max_concurrency']`): 50
+ - Self-compiled installation default: 50
+ - Helm chart default (`gitlab.sidekiq.concurrency`): 25
+
+ Reference architectures still use a default of 10 as this is set specifically
+ for those configurations.
+
+ Sites that have configured `max_concurrency` will not be affected by this change.
+ [Read more about the Sidekiq concurrency setting](../../administration/sidekiq/extra_sidekiq_processes.md#concurrency).
+- GitLab Runner 15.7.0 introduced a breaking change that affects CI/CD jobs: [Correctly handle expansion of job file variables](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/3613).
+ Previously, job-defined variables that referred to
+ [file type variables](../../ci/variables/index.md#use-file-type-cicd-variables)
+ were expanded to the value of the file variable (its content). This behavior did not
+ respect the typical rules of shell variable expansion. There was also the potential
+ that secrets or sensitive information could leak if the file variable and its
+ contents printed. For example, if they were printed in an echo output. For more information,
+ see [Understanding the file type variable expansion change in GitLab 15.7](https://about.gitlab.com/blog/2023/02/13/impact-of-the-file-type-variable-change-15-7/).
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.6.7
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.6.6
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+
+## 15.6.5
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.6.4
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6, and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.6.3
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.6.2
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.6.1
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.6.0
+
+- You should use one of the [officially supported PostgreSQL versions](../../administration/package_information/postgresql_versions.md). Some database migrations can cause stability and performance issues with older PostgreSQL versions.
+- Git 2.37.0 and later is required by Gitaly. For self-compiled installations, you should use the [Git version provided by Gitaly](../../install/installation.md#git).
+- A database change to modify the behavior of four indexes fails on instances
+ where these indexes do not exist:
+
+ ```plaintext
+ Caused by:
+ PG::UndefinedTable: ERROR: relation "index_issues_on_title_trigram" does not exist
+ ```
+
+ The other three indexes are: `index_merge_requests_on_title_trigram`, `index_merge_requests_on_description_trigram`,
+ and `index_issues_on_description_trigram`.
+
+ This issue was [fixed in GitLab 15.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/105375) and backported
+ to GitLab 15.6.2. The issue can also be worked around:
+ [read about how to create these indexes](https://gitlab.com/gitlab-org/gitlab/-/issues/378343#note_1199863087).
+
+### Linux package installations
+
+In GitLab 15.6, the [PostgreSQL versions shipped with `omnibus-gitlab` packages](../../administration/package_information/postgresql_versions.md)
+have been upgraded to 12.12 and 13.8. Unless
+[explicitly opted out](https://docs.gitlab.com/omnibus/settings/database.html#automatic-restart-when-the-postgresql-version-changes),
+this can cause an automatic restart of the PostgreSQL service, and can
+potentially cause downtime.
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+- [Container registry push events are rejected](https://gitlab.com/gitlab-org/gitlab/-/issues/386389) by the `/api/v4/container_registry_event/events` endpoint resulting in Geo secondary sites not being aware of updates to container registry images and subsequently not replicating the updates. Secondary sites may contain out of date container images after a failover as a consequence. This affects versions 15.6.0 - 15.6.6 and 15.7.0 - 15.7.2. If you're using Geo with container repositories, you are advised to upgrade to GitLab 15.6.7, 15.7.3, or 15.8.0 which contain a fix for this issue and avoid potential data loss after a failover.
+- We discovered an issue where [replication and verification of projects and wikis was not keeping up](https://gitlab.com/gitlab-org/gitlab/-/issues/387980) on small number of Geo installations. Your installation may be affected if you see some projects and/or wikis persistently in the "Queued" state for verification. This can lead to data loss after a failover.
+ - Affected versions: GitLab versions 15.6.x, 15.7.x, and 15.8.0 - 15.8.2.
+ - Versions containing fix: GitLab 15.8.3 and later.
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.5.5
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.5.4
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.5.3
+
+- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+ - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
+ - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ sidekiq['routing_rules'] = [['*', 'default']]
+ ```
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.5.2
+
+- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+ - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
+ - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ sidekiq['routing_rules'] = [['*', 'default']]
+ ```
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.5.1
+
+- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+ - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
+ - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ sidekiq['routing_rules'] = [['*', 'default']]
+ ```
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.5.0
+
+- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+ - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
+ - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ sidekiq['routing_rules'] = [['*', 'default']]
+ ```
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+
+## 15.4.6
+
+- Due to a [bug introduced in curl in GitLab 15.4.6](https://github.com/curl/curl/issues/10122), the [`no_proxy` environment variable may not work properly](../../administration/geo/replication/troubleshooting.md#secondary-site-returns-received-http-code-403-from-proxy-after-connect). Either downgrade to GitLab 15.4.5, or upgrade to GitLab 15.5.7 or a later version.
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.4.5
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.4.4
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.4.3
+
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.4.2
+
+- A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
+ - Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
+ - Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
+ - 15.2.5 --> 15.3.5
+ - 15.3.0 - 15.3.4 --> 15.3.5
+ - 15.4.1 --> 15.4.3
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.4.1
+
+- A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
+ - Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
+ - Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
+ - 15.2.5 --> 15.3.5
+ - 15.3.0 - 15.3.4 --> 15.3.5
+ - 15.4.1 --> 15.4.3
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+
+## 15.4.0
+
+- GitLab 15.4.0 includes a [batched background migration](../background_migrations.md#batched-background-migrations) to [remove incorrect values from `expire_at` in `ci_job_artifacts` table](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89318).
+ This migration might take hours or days to complete on larger GitLab instances.
+- By default, Gitaly and Praefect nodes use the time server at `pool.ntp.org`. If your instance can not connect to `pool.ntp.org`, [configure the `NTP_HOST` variable](../../administration/gitaly/praefect.md#customize-time-server-setting).
+- GitLab 15.4.0 introduced a default [Sidekiq routing rule](../../administration/sidekiq/processing_specific_job_classes.md#routing-rules) that routes all jobs to the `default` queue. For instances using [queue selectors](../../administration/sidekiq/processing_specific_job_classes.md#queue-selectors-deprecated), this causes [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+ - The default routing rule has been reverted in 15.4.5, so upgrading to that version or later will return to the previous behavior.
+ - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ sidekiq['routing_rules'] = [['*', 'default']]
+ ```
+
+- The structure of `/etc/gitlab/gitlab-secrets.json` was modified in [GitLab 15.4](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/6310),
+ and new configuration was added to `gitlab_pages`, `grafana`, and `mattermost` sections.
+ In a highly available or GitLab Geo environment, secrets need to be the same on all nodes.
+ If you're manually syncing the secrets file across nodes, or manually specifying secrets in
+ `/etc/gitlab/gitlab.rb`, make sure `/etc/gitlab/gitlab-secrets.json` is the same on all nodes.
+- GitLab 15.4.0 introduced a [batched background migration](../background_migrations.md#batched-background-migrations) to
+ [backfill `namespace_id` values on issues table](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91921). This
+ migration might take multiple hours or days to complete on larger GitLab instances. Make sure the migration
+ has completed successfully before upgrading to 15.7.0 or later.
+- Due to [a bug introduced in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/390155), if one or more Git repositories in Gitaly Cluster is [unavailable](../../administration/gitaly/recovery.md#unavailable-repositories), then [Repository checks](../../administration/repository_checks.md#repository-checks) and [Geo replication and verification](../../administration/geo/index.md) stop running for all project or project wiki repositories in the affected Gitaly Cluster. The bug was fixed by [reverting the change in GitLab 15.9.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110823). Before upgrading to this version, check if you have any "unavailable" repositories. See [the bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/390155) for more information.
+- A redesigned sign-in page is enabled by default in GitLab 15.4 and later, with improvements shipping in later releases. For more information, see [epic 8557](https://gitlab.com/groups/gitlab-org/-/epics/8557).
+ It can be disabled with a feature flag. Start [a Rails console](../../administration/operations/rails_console.md) and run:
+
+ ```ruby
+ Feature.disable(:restyle_login_page)
+ ```
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+
+## 15.3.4
+
+A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
+
+- Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
+- Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
+ - 15.2.5 --> 15.3.5
+ - 15.3.0 - 15.3.4 --> 15.3.5
+ - 15.4.1 --> 15.4.3
+
+## 15.3.3
+
+- In GitLab 15.3.3, [SAML Group Links](../../api/groups.md#saml-group-links) API `access_level` attribute type changed to `integer`. See
+[the API documentation](../../api/members.md).
+- A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
+
+ - Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
+ - Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
+ - 15.2.5 --> 15.3.5
+ - 15.3.0 - 15.3.4 --> 15.3.5
+ - 15.4.1 --> 15.4.3
+
+## 15.3.2
+
+A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
+
+- Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
+- Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
+ - 15.2.5 --> 15.3.5
+ - 15.3.0 - 15.3.4 --> 15.3.5
+ - 15.4.1 --> 15.4.3
+
+## 15.3.1
+
+A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
+
+- Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
+- Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
+ - 15.2.5 --> 15.3.5
+ - 15.3.0 - 15.3.4 --> 15.3.5
+ - 15.4.1 --> 15.4.3
+
+## 15.3.0
+
+- New Git repositories created in Gitaly cluster no longer use the `@hashed`
+ storage path. Server hooks for new repositories must be copied into a
+ different location. Praefect now generates replica paths for use by Gitaly
+ cluster. This change is a pre-requisite for Gitaly cluster atomically
+ creating, deleting, and renaming Git repositories.
+
+ To identify the replica path,
+ [query the Praefect repository metadata](../../administration/gitaly/troubleshooting.md#view-repository-metadata)
+ and pass the `@hashed` storage path to `-relative-path`.
+
+ With this information, you can correctly install
+ [server hooks](../../administration/server_hooks.md).
+
+- A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
+
+ - Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
+ - Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
+ - 15.2.5 --> 15.3.5
+ - 15.3.0 - 15.3.4 --> 15.3.5
+ - 15.4.1 --> 15.4.3
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+- LFS transfers can redirect to the primary from secondary site mid-session. See
+ [the details and workaround](#lfs-transfers-redirect-to-primary-from-secondary-site-mid-session).
+- Incorrect object storage LFS files deletion on Geo secondary sites. See
+ [the details and workaround](#incorrect-object-storage-lfs-file-deletion-on-secondary-sites).
+
+#### LFS transfers redirect to primary from secondary site mid-session
+
+| Affected minor releases | Affected patch releases | Fixed in |
+|-------------------------|-------------------------|----------|
+| 15.1 | All | None |
+| 15.2 | All | None |
+| 15.3 | 15.3.0 - 15.3.2 | 15.3.3 and later |
+
+LFS transfers can [redirect to the primary from secondary site mid-session](https://gitlab.com/gitlab-org/gitlab/-/issues/371571) causing failed pull and clone requests in GitLab 15.1.0 to 15.3.2 when [Geo proxying](../../administration/geo/secondary_proxy/index.md) is enabled. Geo proxying is enabled by default in GitLab 15.1 and later.
+
+This issue is resolved in GitLab 15.3.3, so customers with the following configuration should upgrade to 15.3.3 or later:
+
+- LFS is enabled.
+- LFS objects are being replicated across Geo sites.
+- Repositories are being pulled by using a Geo secondary site.
+
+#### Incorrect object storage LFS file deletion on secondary sites
+
+| Affected minor releases | Affected patch releases | Fixed in |
+|-------------------------|-------------------------|----------|
+| 15.0 | All | None |
+| 15.1 | All | None |
+| 15.2 | All | None |
+| 15.3 | 15.3.0 - 15.3.2 | 15.3.3 and later |
+
+[Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397)
+can occur in GitLab 15.0.0 to 15.3.2 in the following situations:
+
+- GitLab-managed object storage replication is disabled, and LFS objects are created while importing a project with object storage enabled.
+- GitLab-managed replication to sync object storage is enabled and subsequently disabled.
+
+This issue is resolved in 15.3.3. Customers who have both LFS enabled and LFS objects being replicated across Geo sites
+should upgrade directly to 15.3.3 to reduce the risk of data loss on secondary sites.
+
+## 15.2.5
+
+A [license caching issue](https://gitlab.com/gitlab-org/gitlab/-/issues/376706) prevents some premium features of GitLab from working correctly if you add a new license. Workarounds for this issue:
+
+- Restart all Rails, Sidekiq and Gitaly nodes after applying a new license. This clears the relevant license caches and allows all premium features to operate correctly.
+- Upgrade to a version that is not affected by this issue. The following upgrade paths are available for affected versions:
+ - 15.2.5 --> 15.3.5
+ - 15.3.0 - 15.3.4 --> 15.3.5
+ - 15.4.1 --> 15.4.3
+
+## 15.2.0
+
+- GitLab installations that have multiple web nodes should be
+ [upgraded to 15.1](#1510) before upgrading to 15.2 (and later) due to a
+ configuration change in Rails that can result in inconsistent ETag key
+ generation.
+- Some Sidekiq workers were renamed in this release. To avoid any disruption, [run the Rake tasks to migrate any pending jobs](../../administration/sidekiq/sidekiq_job_migration.md#migrate-queued-and-future-jobs) before starting the upgrade to GitLab 15.2.0.
+- Gitaly now executes its binaries in a [runtime location](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4670). By default on Omnibus GitLab,
+ this path is `/var/opt/gitlab/gitaly/run/`. If this location is mounted with `noexec`, merge requests generate the following error:
+
+ ```plaintext
+ fork/exec /var/opt/gitlab/gitaly/run/gitaly-<nnnn>/gitaly-git2go-v15: permission denied
+ ```
+
+ To resolve this, remove the `noexec` option from the file system mount. An alternative is to change the Gitaly runtime directory:
+
+ 1. Add `gitaly['runtime_dir'] = '<PATH_WITH_EXEC_PERM>'` to `/etc/gitlab/gitlab.rb` and specify a location without `noexec` set.
+ 1. Run `sudo gitlab-ctl reconfigure`.
+
+### Geo installations **(PREMIUM SELF)**
+
+- `pg_upgrade` fails to upgrade the bundled PostregSQL database to version 13. See
+ [the details and workaround](#pg_upgrade-fails-to-upgrade-the-bundled-postregsql-database-to-version-13).
+- LFS transfers can redirect to the primary from secondary site mid-session. See
+ [the details and workaround](#lfs-transfers-redirect-to-primary-from-secondary-site-mid-session).
+- Incorrect object storage LFS files deletion on Geo secondary sites. See
+ [the details and workaround](#incorrect-object-storage-lfs-file-deletion-on-secondary-sites).
+
+## 15.1.0
+
+- In GitLab 15.1.0, we are switching Rails `ActiveSupport::Digest` to use SHA256 instead of MD5.
+ This affects ETag key generation for resources such as raw Snippet file
+ downloads. To ensure consistent ETag key generation across multiple
+ web nodes when upgrading, all servers must first be upgraded to 15.1.6 before
+ upgrading to 15.2.0 or later:
+
+ 1. Ensure all GitLab web nodes are running GitLab 15.1.6.
+ 1. If you run [GitLab on Kubernetes](https://docs.gitlab.com/charts/installation/) by using the cloud native GitLab Helm chart, make sure that all
+ webservice pods are running GitLab 15.1.Z:
+
+ ```shell
+ kubectl get pods -l app=webservice -o custom-columns=webservice-image:{.spec.containers[0].image},workhorse-image:{.spec.containers[1].image}
+ ```
+
+ 1. [Enable the `active_support_hash_digest_sha256` feature flag](../../administration/feature_flags.md#how-to-enable-and-disable-features-behind-flags) to switch `ActiveSupport::Digest` to use SHA256:
+
+ 1. [Start the rails console](../../administration/operations/rails_console.md)
+ 1. Enable the feature flag:
+
+ ```ruby
+ Feature.enable(:active_support_hash_digest_sha256)
+ ```
+
+ 1. Only then, continue to upgrade to later versions of GitLab.
+- Unauthenticated requests to the [`ciConfig` GraphQL field](../../api/graphql/reference/index.md#queryciconfig) are no longer supported.
+ Before you upgrade to GitLab 15.1, add an [access token](../../api/rest/index.md#authentication) to your requests.
+ The user creating the token must have [permission](../../user/permissions.md) to create pipelines in the project.
+
+### Geo installations **(PREMIUM SELF)**
+
+- [Geo proxying](../../administration/geo/secondary_proxy/index.md) was [enabled by default for different URLs](https://gitlab.com/gitlab-org/gitlab/-/issues/346112) in 15.1. This may be a breaking change. If needed, you may [disable Geo proxying](../../administration/geo/secondary_proxy/index.md#disable-geo-proxying). If you are using SAML with different URLs, you must modify your SAML configuration and your Identity Provider configuration. For more information, see the [Geo with Single Sign-On (SSO) documentation](../../administration/geo/replication/single_sign_on.md).
+- LFS transfers can redirect to the primary from secondary site mid-session. See
+ [the details and workaround](#lfs-transfers-redirect-to-primary-from-secondary-site-mid-session).
+- Incorrect object storage LFS files deletion on Geo secondary sites. See
+ [the details and workaround](#incorrect-object-storage-lfs-file-deletion-on-secondary-sites).
+
+## 15.0.0
+
+- Elasticsearch 6.8 [is no longer supported](../../integration/advanced_search/elasticsearch.md#version-requirements). Before you upgrade to GitLab 15.0, [update Elasticsearch to any 7.x version](../../integration/advanced_search/elasticsearch.md#upgrade-to-a-new-elasticsearch-major-version).
+- If you run GitLab with external PostgreSQL, particularly AWS RDS, ensure you
+ upgrade PostgreSQL to patch levels to a minimum of 12.7 or 13.3 before
+ upgrading to GitLab 14.8 or later.
+
+ [In 14.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75511)
+ for GitLab Enterprise Edition and [in 15.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87983)
+ for GitLab Community Edition a GitLab feature called Loose Foreign Keys was enabled.
+
+ After it was enabled, we have had reports of unplanned PostgreSQL restarts caused
+ by a database engine bug that causes a segmentation fault.
+
+ For more information, see [issue 364763](https://gitlab.com/gitlab-org/gitlab/-/issues/364763).
+
+- The use of encrypted S3 buckets with storage-specific configuration is no longer supported after [removing support for using `background_upload`](../deprecations.md#background-upload-for-object-storage).
+- The [certificate-based Kubernetes integration (DEPRECATED)](../../user/infrastructure/clusters/index.md#certificate-based-kubernetes-integration-deprecated) is disabled by default, but you can be re-enable it through the [`certificate_based_clusters` feature flag](../../administration/feature_flags.md#how-to-enable-and-disable-features-behind-flags) until GitLab 16.0.
+- When you use the GitLab Helm Chart project with a custom `serviceAccount`, ensure it has `get` and `list` permissions for the `serviceAccount` and `secret` resources.
+- The `FF_GITLAB_REGISTRY_HELPER_IMAGE` [feature flag](../../administration/feature_flags.md#enable-or-disable-the-feature) is removed and helper images are always pulled from GitLab Registry.
+
+### Linux package installations
+
+- The [`custom_hooks_dir`](../../administration/server_hooks.md#create-global-server-hooks-for-all-repositories) setting for configuring global server hooks is now configured in
+ Gitaly. The previous implementation in GitLab Shell was removed in GitLab 15.0. With this change, global server hooks are stored only inside a subdirectory named after the
+ hook type. Global server hooks can no longer be a single hook file in the root of the custom hooks directory. For example, you must use `<custom_hooks_dir>/<hook_name>.d/*` rather
+ than `<custom_hooks_dir>/<hook_name>`.
+ - Use `gitaly['custom_hooks_dir']` in `gitlab.rb` ([introduced in 14.3](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/4208))
+ for Omnibus GitLab. This replaces `gitlab_shell['custom_hooks_dir']`.
+- PostgreSQL 13.6 is being shipped as the default version for fresh installs and
+ 12.10 for upgrades. You can manually upgrade to PostgreSQL 13.6 following the
+ [upgrade docs](https://docs.gitlab.com/omnibus/settings/database.html#gitlab-150-and-later).
+ Because of underlying structural changes, the running PostgreSQL process
+ **_must_** be restarted when it is upgraded before running database
+ migrations. If automatic restart is skipped, you must run the following
+ command before migrations are run:
+
+ ```shell
+ # If using PostgreSQL
+ sudo gitlab-ctl restart postgresql
+
+ # If using Patroni for Database replication
+ sudo gitlab-ctl restart patroni
+ ```
+
+ If PostgreSQL is not restarted, you might face
+ [errors related to loading libraries](https://docs.gitlab.com/omnibus/settings/database.html#could-not-load-library-plpgsqlso).
+
+- Starting with GitLab 15.0, `postgresql` and `geo-postgresql` services are
+ automatically restarted when the PostgreSQL version changes. Restarting
+ PostgreSQL services causes downtime due to the temporary unavailability of the
+ database for operations. While this restart is mandatory for proper functioning
+ of the Database services, you might want more control over when the PostgreSQL
+ is restarted. For that purpose, you can choose to skip the automatic restarts as
+ part of `gitlab-ctl reconfigure` and manually restart the services.
+
+ To skip automatic restarts as part of GitLab 15.0 upgrade, perform the following
+ steps before the upgrade:
+
+ 1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
+
+ ```ruby
+ # For PostgreSQL/Patroni
+ postgresql['auto_restart_on_version_change'] = false
+
+ # For Geo PostgreSQL
+ geo_postgresql['auto_restart_on_version_change'] = false
+ ```
+
+ 1. Reconfigure GitLab:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+ NOTE:
+ It is mandatory to restart PostgreSQL when underlying version changes, to avoid
+ errors like the [one related to loading necessary libraries](https://docs.gitlab.com/omnibus/settings/database.html#could-not-load-library-plpgsqlso)
+ that can cause downtime. So, if you skip the automatic restarts using the above
+ method, ensure that you restart the services manually before upgrading to GitLab
+ 15.0.
+
+- Starting with GitLab 15.0, the `AES256-GCM-SHA384` SSL cipher will not be allowed by
+ NGINX by default. If you require this cipher (for example, if you use
+ [AWS's Classic Load Balancer](https://docs.aws.amazon.com/en_en/elasticloadbalancing/latest/classic/elb-ssl-security-policy.html#ssl-ciphers)),
+ you can add the cipher back to the allow list by following the steps below:
+
+ 1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
+
+ ```ruby
+ nginx['ssl_ciphers'] = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384"
+ ```
+
+ 1. Reconfigure GitLab:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+- Support for Gitaly's internal socket path is removed.
+ In GitLab 14.10, Gitaly introduced a new directory that holds all runtime
+ data Gitaly requires to operate correctly. This new directory replaces the
+ old internal socket directory, and consequentially the usage of
+ `gitaly['internal_socket_dir']` was deprecated in favor of
+ `gitaly['runtime_dir']`.
+
+ The old `gitaly['internal_socket_dir']` configuration was removed in this release.
+
+- Background uploads settings for object storage are removed.
+ Object storage now preferentially uses direct uploads.
+
+ The following keys are no longer supported in `/etc/gitlab/gitlab.rb`:
+
+ - `gitlab_rails['artifacts_object_store_direct_upload']`
+ - `gitlab_rails['artifacts_object_store_background_upload']`
+ - `gitlab_rails['external_diffs_object_store_direct_upload']`
+ - `gitlab_rails['external_diffs_object_store_background_upload']`
+ - `gitlab_rails['lfs_object_store_direct_upload']`
+ - `gitlab_rails['lfs_object_store_background_upload']`
+ - `gitlab_rails['uploads_object_store_direct_upload']`
+ - `gitlab_rails['uploads_object_store_background_upload']`
+ - `gitlab_rails['packages_object_store_direct_upload']`
+ - `gitlab_rails['packages_object_store_background_upload']`
+ - `gitlab_rails['dependency_proxy_object_store_direct_upload']`
+ - `gitlab_rails['dependency_proxy_object_store_background_upload']`
+
+### Self-compiled installations
+
+- Support for more than one database has been added to GitLab. For **self-compiled (source) installations**,
+ `config/database.yml` must include a database name in the database configuration.
+ The `main: database` must be first. If an invalid or deprecated syntax is used, an error is generated
+ during application start:
+
+ ```plaintext
+ ERROR: This installation of GitLab uses unsupported 'config/database.yml'.
+ The main: database needs to be defined as a first configuration item instead of primary. (RuntimeError)
+ ```
+
+ Previously, the `config/database.yml` file looked like the following:
+
+ ```yaml
+ production:
+ adapter: postgresql
+ encoding: unicode
+ database: gitlabhq_production
+ ...
+ ```
+
+ Starting with GitLab 15.0, it must define a `main` database first:
+
+ ```yaml
+ production:
+ main:
+ adapter: postgresql
+ encoding: unicode
+ database: gitlabhq_production
+ ...
+ ```
+
+### Geo installations **(PREMIUM SELF)**
+
+- Incorrect object storage LFS files deletion on Geo secondary sites. See
+ [the details and workaround](#incorrect-object-storage-lfs-file-deletion-on-secondary-sites).
diff --git a/doc/update/versions/gitlab_16_changes.md b/doc/update/versions/gitlab_16_changes.md
index cd51ca2a518..04581a88a93 100644
--- a/doc/update/versions/gitlab_16_changes.md
+++ b/doc/update/versions/gitlab_16_changes.md
@@ -4,7 +4,7 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# GitLab 16 changes
+# GitLab 16 changes **(FREE SELF)**
This page contains upgrade information for minor and patch versions of GitLab 16.
Ensure you review these instructions for:
@@ -12,11 +12,76 @@ Ensure you review these instructions for:
- Your installation type.
- All versions between your current version and your target version.
-Some GitLab installations must upgrade to GitLab 16.0 before upgrading to any other version. For more information, see
-[Long-running user type data change](#long-running-user-type-data-change).
-
For more information about upgrading GitLab Helm Chart, see [the release notes for 7.0](https://docs.gitlab.com/charts/releases/7_0.html).
+## Issues to be aware of when upgrading from 15.11
+
+- Some GitLab installations must upgrade to GitLab 16.0 before upgrading to any other version. For more information, see
+ [Long-running user type data change](#long-running-user-type-data-change).
+- Other installations can skip 16.0, 16.1, and 16.2 as the first required stop on the upgrade path is 16.3. Review the notes for those intermediate
+ versions.
+- If your GitLab instance upgraded first to 15.11.0, 15.11.1, or 15.11.2 the database schema is incorrect.
+ Recommended: perform the workaround before upgrading to 16.x.
+ See [the details and workaround](#undefined-column-error-upgrading-to-162-or-later).
+- Linux package installations must change Gitaly and Praefect configuration structure before upgrading to GitLab 16.
+ **To avoid data loss** reconfigure Praefect first, and as part of the new configuration, disable metadata verification.
+ Read more:
+
+ - [Praefect configuration structure change](#praefect-configuration-structure-change).
+ - [Gitaly configuration structure change](#gitaly-configuration-structure-change).
+
+## 16.4.0
+
+- Updating a group path [received a bug fix](https://gitlab.com/gitlab-org/gitlab/-/issues/419289) that uses a database index introduced in 16.3.
+
+ If you upgrade to 16.4 from a version lower than 16.3, you must execute `ANALYZE packages_packages;` in the database before you use it.
+
+- You might encounter the following error while upgrading to GitLab 16.4 or later:
+
+ ```plaintext
+ main: == 20230830084959 ValidatePushRulesConstraints: migrating =====================
+ main: -- execute("SET statement_timeout TO 0")
+ main: -> 0.0002s
+ main: -- execute("ALTER TABLE push_rules VALIDATE CONSTRAINT force_push_regex_size_constraint;")
+ main: -> 0.0004s
+ main: -- execute("RESET statement_timeout")
+ main: -> 0.0003s
+ main: -- execute("ALTER TABLE push_rules VALIDATE CONSTRAINT delete_branch_regex_size_constraint;")
+ rails aborted!
+ StandardError: An error has occurred, all later migrations canceled:
+
+ PG::CheckViolation: ERROR: check constraint "delete_branch_regex_size_constraint" of relation "push_rules" is violated by some row
+ ```
+
+ These constraints might return an error:
+
+ - `author_email_regex_size_constraint`
+ - `branch_name_regex_size_constraint`
+ - `commit_message_negative_regex_size_constraint`
+ - `commit_message_regex_size_constraint`
+ - `delete_branch_regex_size_constraint`
+ - `file_name_regex_size_constraint`
+ - `force_push_regex_size_constraint`
+
+ To fix the error, find the records in the `push_rules` table that exceed the 511
+ character limit.
+
+ ```sql
+ ;; replace `delete_branch_regex` with a name of the field used in constraint
+ SELECT id FROM push_rules WHERE LENGTH(delete_branch_regex) > 511;
+ ```
+
+ Reduce the value length of the regex field for affected push rules records, then
+ retry the migration.
+
+### Self-compiled installations
+
+- A new method of configuring paths for the GitLab secret and custom hooks is preferred in GitLab 16.4 and later:
+ 1. Update your configuration `[gitlab] secret_file` to [configure the path](../../administration/gitaly/reference.md#gitlab) to the GitLab secret token.
+ 1. If you have custom hooks, update your configuration `[hooks] custom_hooks_dir` to [configure the path](../../administration/gitaly/reference.md#custom-hooks) to
+ server-side custom hooks.
+ 1. Remove the `[gitlab-shell] dir` configuration.
+
## 16.3.0
- For Go applications, [`crypto/tls`: verifying certificate chains containing large RSA keys is slow (CVE-2023-29409)](https://github.com/golang/go/issues/61460)
@@ -54,6 +119,17 @@ Specific information applies to Linux package installations:
- [An informal explanation](https://gitlab.com/gitlab-org/gitlab/-/issues/416714#note_1482388504).
- `omnibus-gitlab` [merge request 7035](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/7035), which introduces the environment variable.
+### Geo installations
+
+Specific information applies to installations using Geo:
+
+- Git pulls against a secondary Geo site are being proxied to the primary Geo site even when that secondary site is up to date. You are impacted if you are using Geo to accelerate remote users who make Git pull requests against a secondary Geo site.
+
+ - Impacted versions: 16.3.0 - 16.3.2
+ - Versions containing fix: 16.4.0
+
+ For more information, see [issue 425224](https://gitlab.com/gitlab-org/gitlab/-/issues/425224).
+
## 16.2.0
- Legacy LDAP configuration settings may cause
@@ -62,11 +138,15 @@ Specific information applies to Linux package installations:
in the `tls_options` hash, or use the legacy `gitlab_rails['ldap_host']` option.
See the [configuration workarounds](https://gitlab.com/gitlab-org/gitlab/-/issues/419485#workarounds)
for more details.
-- New job artifacts are not replicated if job artifacts are configured to be stored in object storage and `direct_upload` is enabled. This bug is fixed in GitLab versions 16.1.4,
- 16.2.3, 16.3.0, and later.
- - Impacted versions: GitLab versions 16.1.0 - 16.1.3 and 16.2.0 - 16.2.2.
- - If you deployed an affected version, after upgrading to a fixed GitLab version, follow [these instructions](https://gitlab.com/gitlab-org/gitlab/-/issues/419742#to-fix-data)
- to resync the affected job artifacts.
+- If your GitLab database was created by or upgraded via versions 15.11.0 - 15.11.2 inclusive, upgrading to GitLab 16.2 fails with:
+
+ ```plaintext
+ PG::UndefinedColumn: ERROR: column "id_convert_to_bigint" of relation "ci_build_needs" does not exist
+ LINE 1: ...db_config_name:main*/ UPDATE "ci_build_needs" SET "id_conver...
+ ```
+
+ See [the details and workaround](#undefined-column-error-upgrading-to-162-or-later).
+
- You might encounter the following error while upgrading to GitLab 16.2 or later:
```plaintext
@@ -98,6 +178,17 @@ Specific information applies to Linux package installations:
- Git 2.41.0 and later is required by Gitaly. You should use the [Git version provided by Gitaly](../../install/installation.md#git).
+### Geo installations
+
+Specific information applies to installations using Geo:
+
+- New job artifacts are not replicated by Geo if job artifacts are configured to be stored in object storage and `direct_upload` is enabled. This bug is fixed in GitLab versions 16.1.4,
+ 16.2.3, 16.3.0, and later.
+ - Impacted versions: GitLab versions 16.1.0 - 16.1.3 and 16.2.0 - 16.2.2.
+ - While running an affected version, artifacts which appeared to become synced may actually be missing on the secondary site.
+ Affected artifacts are automatically resynced upon upgrade to 16.1.5, 16.2.5, 16.3.1, 16.4.0, or later.
+ You can [manually resync affected job artifacts](https://gitlab.com/gitlab-org/gitlab/-/issues/419742#to-fix-data) if needed.
+
## 16.1.0
- A `BackfillPreparedAtMergeRequests` background migration is finalized with
@@ -106,11 +197,6 @@ Specific information applies to Linux package installations:
[backfill `prepared_at` values on the `merge_requests` table](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111865). This
migration may take multiple days to complete on larger GitLab instances. Make sure the migration
has completed successfully before upgrading to 16.1.0.
-- New job artifacts are not replicated if job artifacts are configured to be stored in object storage and `direct_upload` is enabled. This bug is fixed in GitLab versions 16.1.4,
- 16.2.3, 16.3.0, and later.
- - Impacted versions: GitLab versions 16.1.0 - 16.1.3 and 16.2.0 - 16.2.2.
- - If you deployed an affected version, after upgrading to a fixed GitLab version, follow [these instructions](https://gitlab.com/gitlab-org/gitlab/-/issues/419742#to-fix-data)
- to resync the affected job artifacts.
### Self-compiled installations
@@ -118,23 +204,41 @@ Specific information applies to Linux package installations:
[removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118645). For more information, see the
[`puma.rb.example`](https://gitlab.com/gitlab-org/gitlab/-/blob/16-0-stable-ee/config/puma.rb.example) file.
-### Geo installations
+### Geo installations **(PREMIUM SELF)**
Specific information applies to installations using Geo:
-- Some project imports do not initialize wiki repositories on project creation. Because of the migration of project wikis to
- SSF, [missing wiki repositories are being incorrectly flagged as failing verification](https://gitlab.com/gitlab-org/gitlab/-/issues/409704).
- This issue is not a result of an actual replication/verification failure but an invalid internal state for these missing
- repositories inside Geo and results in errors in the logs and the verification progress reporting a failed state for
- these wiki repositories. If you have not imported projects you are not impacted by this issue.
- - Impacted versions: GitLab versions 15.11.x, 16.0.x, and 16.1.0 - 16.1.2.
- - Versions containing fix: GitLab 16.1.3 and later.
+- Some project imports do not initialize wiki repositories on project creation. See
+ [the details and workaround](#wiki-repositories-not-initialized-on-project-creation).
- Because of the migration of project designs to SSF, [missing design repositories are being incorrectly flagged as failing verification](https://gitlab.com/gitlab-org/gitlab/-/issues/414279).
This issue is not a result of an actual replication/verification failure but an invalid internal state for these missing
repositories inside Geo and results in errors in the logs and the verification progress reporting a failed state for
these design repositories. You could be impacted by this issue even if you have not imported projects.
- - Impacted versions: GitLab versions 16.1.x.
- - Versions containing fix: GitLab 16.2.0 and later.
+ - Impacted versions: GitLab versions 16.1.0 - 16.1.2
+ - Versions containing fix: GitLab 16.1.3 and later.
+- New job artifacts are not replicated by Geo if job artifacts are configured to be stored in object storage and `direct_upload` is enabled. This bug is fixed in GitLab versions 16.1.4,
+ 16.2.3, 16.3.0, and later.
+ - Impacted versions: GitLab versions 16.1.0 - 16.1.3 and 16.2.0 - 16.2.2.
+ - While running an affected version, artifacts which appeared to become synced may actually be missing on the secondary site.
+ Affected artifacts are automatically resynced upon upgrade to 16.1.5, 16.2.5, 16.3.1, 16.4.0, or later.
+ You can [manually resync affected job artifacts](https://gitlab.com/gitlab-org/gitlab/-/issues/419742#to-fix-data) if needed.
+
+#### Wiki repositories not initialized on project creation
+
+| Affected minor releases | Affected patch releases | Fixed in |
+|-------------------------|-------------------------|----------|
+| 15.11 | All | None |
+| 16.0 | All | None |
+| 16.1 | 16.1.0 - 16.1.2 | 16.1.3 and later |
+
+Some project imports do not initialize wiki repositories on project creation.
+Since the migration of project wikis to SSF,
+[missing wiki repositories are being incorrectly flagged as failing verification](https://gitlab.com/gitlab-org/gitlab/-/issues/409704).
+This is not a result of an actual replication/verification failure but an
+invalid internal state for these missing repositories inside Geo and results in
+errors in the logs and the verification progress reporting a failed state for
+these wiki repositories. If you have not imported projects you are not impacted
+by this issue.
## 16.0.0
@@ -168,18 +272,371 @@ Specific information applies to Linux package installations:
Workaround is to make use of a different key type, or upgrade the client OpenSSH to a version >= 8.7.
-### Geo installations
+- [Migrate your Praefect configuration to the new structure](#praefect-configuration-structure-change)
+ to ensure all your `praefect['..']` settings continue to work in GitLab 16.0 and later.
+
+- [Migrate your Gitaly configuration to the new structure](#gitaly-configuration-structure-change)
+ to ensure all your `gitaly['..']` settings continue to work in GitLab 16.0 and later.
+
+### Geo installations **(PREMIUM SELF)**
Specific information applies to installations using Geo:
-- Some project imports do not initialize wiki repositories on project creation. Because of the migration of project wikis to
- SSF, [missing wiki repositories are being incorrectly flagged as failing verification](https://gitlab.com/gitlab-org/gitlab/-/issues/409704).
- This issue is not a result of an actual replication/verification failure but an invalid internal state for these missing
- repositories inside Geo and results in errors in the logs and the verification progress reporting a failed state for
- these wiki repositories. If you have not imported projects you are not impacted by this issue.
+- Some project imports do not initialize wiki repositories on project creation. See
+ [the details and workaround](#wiki-repositories-not-initialized-on-project-creation).
+
+### Gitaly configuration structure change
+
+The Gitaly configuration structure in the Linux package
+[changes](https://gitlab.com/gitlab-org/gitaly/-/issues/4467) in GitLab 16.0
+to be consistent with the Gitaly configuration structure used in
+self-compiled installations.
+
+As a result of this change, a single hash under `gitaly['configuration']` holds most Gitaly
+configuration. Some `gitaly['..']` configuration options continue to be used by GitLab 16.0 and later:
+
+- `enable`
+- `dir`
+- `bin_path`
+- `env_directory`
+- `env`
+- `open_files_ulimit`
+- `consul_service_name`
+- `consul_service_meta`
+
+Migrate by moving your existing configuration under the new structure. The new structure is supported from GitLab 15.10.
+
+**Migrate to the new structure**
+
+WARNING:
+If you are running Gitaly cluster, [migrate Praefect to the new configuration structure **first**](#praefect-configuration-structure-change).
+Once this change is tested, proceed with your Gitaly nodes.
+If Gitaly is misconfigured as part of the configuration structure change, [repository verification](../../administration/gitaly/praefect.md#repository-verification)
+will [delete metadata required for Gitaly cluster to work](https://gitlab.com/gitlab-org/gitaly/-/issues/5529).
+To protect against configuration mistakes, temporarily disable repository verification in Praefect.
+
+1. If you're running Gitaly Cluster, ensure repository verification is disabled on all Praefect nodes.
+ Configure `verification_interval: 0`, and apply with `gitlab-ctl reconfigure`.
+1. When applying the new structure to your configuration
+ - Replace the `...` with the value from the old key.
+ - When configuring `storage` to replace `git_data_dirs`, **you must append `repositories` to the path** as documented below.
+ If you miss this out your Git repositories are inaccessible until the configuration is fixed.
+ This misconfiguration can cause metadata deletion, and is the reason for disabling repository verification.
+ - Skip any keys you haven't configured a value for previously.
+ - Recommended. Include a trailing comma for all hash keys so the hash remains valid when keys are re-ordered or additional keys are added.
+1. Apply the change with `gitlab-ctl reconfigure`.
+1. Test Git repository functionality in GitLab.
+1. Remove the old keys from the configuration once migrated, and then re-run `gitlab-ctl reconfigure`.
+1. Recommended, if you're running Gitaly Cluster. Reinstate Praefect [repository verification](../../administration/gitaly/praefect.md#repository-verification)
+ by removing `verification_interval: 0`.
+
+The new structure is documented below with the old keys described in a comment above the new keys.
+
+```ruby
+gitaly['configuration'] = {
+ # gitaly['socket_path']
+ socket_path: ...,
+ # gitaly['runtime_dir']
+ runtime_dir: ...,
+ # gitaly['listen_addr']
+ listen_addr: ...,
+ # gitaly['prometheus_listen_addr']
+ prometheus_listen_addr: ...,
+ # gitaly['tls_listen_addr']
+ tls_listen_addr: ...,
+ tls: {
+ # gitaly['certificate_path']
+ certificate_path: ...,
+ # gitaly['key_path']
+ key_path: ...,
+ },
+ # gitaly['graceful_restart_timeout']
+ graceful_restart_timeout: ...,
+ logging: {
+ # gitaly['logging_level']
+ level: ...,
+ # gitaly['logging_format']
+ format: ...,
+ # gitaly['logging_sentry_dsn']
+ sentry_dsn: ...,
+ # gitaly['logging_ruby_sentry_dsn']
+ ruby_sentry_dsn: ...,
+ # gitaly['logging_sentry_environment']
+ sentry_environment: ...,
+ # gitaly['log_directory']
+ dir: ...,
+ },
+ prometheus: {
+ # gitaly['prometheus_grpc_latency_buckets']. The old value was configured as a string
+ # such as '[0, 1, 2]'. The new value must be an array like [0, 1, 2].
+ grpc_latency_buckets: ...,
+ },
+ auth: {
+ # gitaly['auth_token']
+ token: ...,
+ # gitaly['auth_transitioning']
+ transitioning: ...,
+ },
+ git: {
+ # gitaly['git_catfile_cache_size']
+ catfile_cache_size: ...,
+ # gitaly['git_bin_path']
+ bin_path: ...,
+ # gitaly['use_bundled_git']
+ use_bundled_binaries: ...,
+ # gitaly['gpg_signing_key_path']
+ signing_key: ...,
+ # gitaly['gitconfig']. This is still an array but the type of the elements have changed.
+ config: [
+ {
+ # Previously the elements contained 'section', and 'subsection' in addition to 'key'. Now
+ # these all should be concatenated into just 'key', separated by dots. For example,
+ # {section: 'first', subsection: 'middle', key: 'last', value: 'value'}, should become
+ # {key: 'first.middle.last', value: 'value'}.
+ key: ...,
+ value: ...,
+ },
+ ],
+ },
+ # Storage could previously be configured through either gitaly['storage'] or 'git_data_dirs'. Migrate
+ # the relevant configuration according to the instructions below.
+ # For 'git_data_dirs', migrate only the 'path' to the gitaly['configuration'] and leave the rest of it untouched.
+ storage: [
+ {
+ # gitaly['storage'][<index>]['name']
+ #
+ # git_data_dirs[<name>]. The storage name was configured as a key in the map.
+ name: ...,
+ # gitaly['storage'][<index>]['path']
+ #
+ # git_data_dirs[<name>]['path']. Use the value from git_data_dirs[<name>]['path'] and append '/repositories' to it.
+ #
+ # For example, if the path in 'git_data_dirs' was '/var/opt/gitlab/git-data', use
+ # '/var/opt/gitlab/git-data/repositories'. The '/repositories' extension was automatically
+ # appended to the path configured in `git_data_dirs`.
+ path: ...,
+ },
+ ],
+ hooks: {
+ # gitaly['custom_hooks_dir']
+ custom_hooks_dir: ...,
+ },
+ daily_maintenance: {
+ # gitaly['daily_maintenance_disabled']
+ disabled: ...,
+ # gitaly['daily_maintenance_start_hour']
+ start_hour: ...,
+ # gitaly['daily_maintenance_start_minute']
+ start_minute: ...,
+ # gitaly['daily_maintenance_duration']
+ duration: ...,
+ # gitaly['daily_maintenance_storages']
+ storages: ...,
+ },
+ cgroups: {
+ # gitaly['cgroups_mountpoint']
+ mountpoint: ...,
+ # gitaly['cgroups_hierarchy_root']
+ hierarchy_root: ...,
+ # gitaly['cgroups_memory_bytes']
+ memory_bytes: ...,
+ # gitaly['cgroups_cpu_shares']
+ cpu_shares: ...,
+ repositories: {
+ # gitaly['cgroups_repositories_count']
+ count: ...,
+ # gitaly['cgroups_repositories_memory_bytes']
+ memory_bytes: ...,
+ # gitaly['cgroups_repositories_cpu_shares']
+ cpu_shares: ...,
+ }
+ },
+ # gitaly['concurrency']. While the structure is the same, the string keys in the array elements
+ # should be replaced by symbols as elsewhere. {'key' => 'value'}, should become {key: 'value'}.
+ concurrency: ...,
+ # gitaly['rate_limiting']. While the structure is the same, the string keys in the array elements
+ # should be replaced by symbols as elsewhere. {'key' => 'value'}, should become {key: 'value'}.
+ rate_limiting: ...,
+ pack_objects_cache: {
+ # gitaly['pack_objects_cache_enabled']
+ enabled: ...,
+ # gitaly['pack_objects_cache_dir']
+ dir: ...,
+ # gitaly['pack_objects_cache_max_age']
+ max_age: ...,
+ }
+}
+```
- - Impacted versions: GitLab versions 15.11.x, 16.0.x, and 16.1.0 - 16.1.2.
- - Versions containing fix: GitLab 16.1.3 and later.
+### Praefect configuration structure change
+
+The Praefect configuration structure in the Linux package
+[changes](https://gitlab.com/gitlab-org/gitaly/-/issues/4467) in GitLab 16.0
+to be consistent with the Praefect configuration structure used in
+self-compiled installations.
+
+As a result of this change, a single hash under `praefect['configuration']` holds most Praefect
+configuration. Some `praefect['..']` configuration options continue to be used by GitLab 16.0 and later:
+
+- `enable`
+- `dir`
+- `log_directory`
+- `env_directory`
+- `env`
+- `wrapper_path`
+- `auto_migrate`
+- `consul_service_name`
+
+Migrate by moving your existing configuration under the new structure. The new structure is supported from GitLab 15.9.
+
+**Migrate to the new structure**
+
+WARNING:
+Migrate Praefect to the new configuration structure **first**.
+Once this change is tested, [proceed with your Gitaly nodes](#gitaly-configuration-structure-change).
+If Gitaly is misconfigured as part of the configuration structure change, [repository verification](../../administration/gitaly/praefect.md#repository-verification)
+will [delete metadata required for Gitaly cluster to work](https://gitlab.com/gitlab-org/gitaly/-/issues/5529).
+To protect against configuration mistakes, temporarily disable repository verification in Praefect.
+
+1. When applying the new structure to your configuration:
+ - Replace the `...` with the value from the old key.
+ - Disable repository verification using `verification_interval: 0`, as shown below.
+ - Skip any keys you haven't configured a value for previously.
+ - Recommended. Include a trailing comma for all hash keys so the hash remains valid when keys are re-ordered or additional keys are added.
+1. Apply the change with `gitlab-ctl reconfigure`.
+1. Test Git repository functionality in GitLab.
+1. Remove the old keys from the configuration once migrated, and then re-run `gitlab-ctl reconfigure`.
+
+The new structure is documented below with the old keys described in a comment above the new keys.
+
+```ruby
+praefect['configuration'] = {
+ # praefect['listen_addr']
+ listen_addr: ...,
+ # praefect['socket_path']
+ socket_path: ...,
+ # praefect['prometheus_listen_addr']
+ prometheus_listen_addr: ...,
+ # praefect['tls_listen_addr']
+ tls_listen_addr: ...,
+ # praefect['separate_database_metrics']
+ prometheus_exclude_database_from_default_metrics: ...,
+ auth: {
+ # praefect['auth_token']
+ token: ...,
+ # praefect['auth_transitioning']
+ transitioning: ...,
+ },
+ logging: {
+ # praefect['logging_format']
+ format: ...,
+ # praefect['logging_level']
+ level: ...,
+ },
+ failover: {
+ # praefect['failover_enabled']
+ enabled: ...,
+ },
+ background_verification: {
+ # praefect['background_verification_delete_invalid_records']
+ delete_invalid_records: ...,
+ # praefect['background_verification_verification_interval']
+ #
+ # IMPORTANT:
+ # As part of reconfiguring Praefect, disable this feature.
+ # Read about this above.
+ #
+ verification_interval: 0,
+ },
+ reconciliation: {
+ # praefect['reconciliation_scheduling_interval']
+ scheduling_interval: ...,
+ # praefect['reconciliation_histogram_buckets']. The old value was configured as a string
+ # such as '[0, 1, 2]'. The new value must be an array like [0, 1, 2].
+ histogram_buckets: ...,
+ },
+ tls: {
+ # praefect['certificate_path']
+ certificate_path: ...,
+ # praefect['key_path']
+ key_path: ...,
+ },
+ database: {
+ # praefect['database_host']
+ host: ...,
+ # praefect['database_port']
+ port: ...,
+ # praefect['database_user']
+ user: ...,
+ # praefect['database_password']
+ password: ...,
+ # praefect['database_dbname']
+ dbname: ...,
+ # praefect['database_sslmode']
+ sslmode: ...,
+ # praefect['database_sslcert']
+ sslcert: ...,
+ # praefect['database_sslkey']
+ sslkey: ...,
+ # praefect['database_sslrootcert']
+ sslrootcert: ...,
+ session_pooled: {
+ # praefect['database_direct_host']
+ host: ...,
+ # praefect['database_direct_port']
+ port: ...,
+ # praefect['database_direct_user']
+ user: ...,
+ # praefect['database_direct_password']
+ password: ...,
+ # praefect['database_direct_dbname']
+ dbname: ...,
+ # praefect['database_direct_sslmode']
+ sslmode: ...,
+ # praefect['database_direct_sslcert']
+ sslcert: ...,
+ # praefect['database_direct_sslkey']
+ sslkey: ...,
+ # praefect['database_direct_sslrootcert']
+ sslrootcert: ...,
+ }
+ },
+ sentry: {
+ # praefect['sentry_dsn']
+ sentry_dsn: ...,
+ # praefect['sentry_environment']
+ sentry_environment: ...,
+ },
+ prometheus: {
+ # praefect['prometheus_grpc_latency_buckets']. The old value was configured as a string
+ # such as '[0, 1, 2]'. The new value must be an array like [0, 1, 2].
+ grpc_latency_buckets: ...,
+ },
+ # praefect['graceful_stop_timeout']
+ graceful_stop_timeout: ...,
+ # praefect['virtual_storages']. The old value was a hash map but the new value is an array.
+ virtual_storage: [
+ {
+ # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]. The name was previously the key in
+ # the 'virtual_storages' hash.
+ name: ...,
+ # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]['nodes'][NODE_NAME]. The old value was a hash map
+ # but the new value is an array.
+ node: [
+ {
+ # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]['nodes'][NODE_NAME]. Use NODE_NAME key as the
+ # storage.
+ storage: ...,
+ # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]['nodes'][NODE_NAME]['address'].
+ address: ...,
+ # praefect['virtual_storages'][VIRTUAL_STORAGE_NAME]['nodes'][NODE_NAME]['token'].
+ token: ...,
+ },
+ ],
+ }
+ ]
+}
+```
## Long-running user type data change
@@ -196,7 +653,7 @@ migration might take multiple days to complete on larger GitLab instances. Make
has completed successfully before upgrading to 16.1.0 or later.
GitLab 16.1 introduces the `FinalizeUserTypeMigration` migration which ensures the
-16.0 `MigrateHumanUserType` background migration is completed, making the 16.0 changes synchronously
+16.0 `MigrateHumanUserType` background migration is completed, executing the 16.0 change synchronously
during the upgrade if it's not completed.
GitLab 16.2 [implements a `NOT NULL` database constraint](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122454)
@@ -219,3 +676,127 @@ an unusable state, generating `500` errors. The errors are caused by Sidekiq and
application code that is incompatible with the database schema.
At the end of the workaround process, Sidekiq and Puma are restarted to resolve that issue.
+
+## Undefined column error upgrading to 16.2 or later
+
+A bug in GitLab 15.11 incorrectly disabled a database change on self-managed instances.
+For more information, see [issue 408835](https://gitlab.com/gitlab-org/gitlab/-/issues/408835).
+
+If your GitLab instance upgraded first to 15.11.0, 15.11.1, or 15.11.2 the database schema is
+incorrect and upgrading to GitLab 16.2 or later fails with an error. A database change
+requires the earlier modification to be in place:
+
+```plaintext
+PG::UndefinedColumn: ERROR: column "id_convert_to_bigint" of relation "ci_build_needs" does not exist
+LINE 1: ...db_config_name:main*/ UPDATE "ci_build_needs" SET "id_conver...
+```
+
+GitLab 15.11.3 shipped a fix for this bug, but it doesn't correct the problem on
+instances already running the earlier 15.11 releases.
+
+If you're not sure if an instance is affected, check for the column on the
+[database console](../../administration/troubleshooting/postgresql.md#start-a-database-console):
+
+```sql
+select pg_typeof (id_convert_to_bigint) from public.ci_build_needs limit 1;
+```
+
+If you need the workaround, this query fails:
+
+```plaintext
+ERROR: column "id_convert_to_bigintd" does not exist
+LINE 1: select pg_typeof (id_convert_to_bigintd) from public.ci_buil...
+```
+
+Unaffected instances return:
+
+```plaintext
+ pg_typeof
+-----------
+ bigint
+```
+
+The workaround for this issue differs if your GitLab instance's database schema
+was recently created:
+
+| Installation version | Workaround |
+| -------------------- | ---------- |
+| 15.9 or earlier | [15.9](#workaround-instance-created-with-159-or-earlier) |
+| 15.10 | [15.10](#workaround-instance-created-with-1510) |
+| 15.11 | [15.11](#workaround-instance-created-with-1511) |
+
+Most instances should use the 15.9 procedure. Only very new instances require the
+the 15.10 or 15.11 procedures. If you've migrated GitLab using backup and restore,
+the database schema comes from the original instance. Select the workaround based
+on the source instance.
+
+The commands in the following sections are for Linux package installations, and
+differ for other installation types:
+
+::Tabs
+
+:::TabTitle Docker
+
+- Omit `sudo`
+- Shell into the GitLab container and run the same commands:
+
+ ```shell
+ docker exec -it <container-id> bash
+ ```
+
+:::TabTitle Self-compiled (source)
+
+- Use `sudo -u git -H bundle exec rake` instead of `sudo gitlab-rake`
+- Run the SQL on [your PostgreSQL database console](../../administration/troubleshooting/postgresql.md#start-a-database-console)
+
+:::TabTitle Helm chart (Kubernetes)
+
+- Omit `sudo`.
+- Shell into the `toolbox` pod to run the Rake commands: `gitlab-rake` is in `/usr/local/bin` if not in the `PATH`.
+ - Refer to our [Kubernetes cheat sheet](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html#gitlab-specific-kubernetes-information) for details.
+- Run the SQL on [your PostgreSQL database console](../../administration/troubleshooting/postgresql.md#start-a-database-console)
+
+::EndTabs
+
+### Workaround: instance created with 15.9 or earlier
+
+```shell
+# Restore schema
+sudo gitlab-psql -c "DELETE FROM schema_migrations WHERE version IN ('20230130175512', '20230130104819');"
+sudo gitlab-rake db:migrate:up VERSION=20230130175512
+sudo gitlab-rake db:migrate:up VERSION=20230130104819
+
+# Re-schedule background migrations
+sudo gitlab-rake db:migrate:down VERSION=20230130202201
+sudo gitlab-rake db:migrate:down VERSION=20230130110855
+sudo gitlab-rake db:migrate:up VERSION=20230130202201
+sudo gitlab-rake db:migrate:up VERSION=20230130110855
+```
+
+### Workaround: instance created with 15.10
+
+```shell
+# Restore schema for sent_notifications
+sudo gitlab-psql -c "DELETE FROM schema_migrations WHERE version = '20230130175512';"
+sudo gitlab-rake db:migrate:up VERSION=20230130175512
+
+# Re-schedule background migration for sent_notifications
+sudo gitlab-rake db:migrate:down VERSION=20230130202201
+sudo gitlab-rake db:migrate:up VERSION=20230130202201
+
+# Restore schema for ci_build_needs
+sudo gitlab-rake db:migrate:down VERSION=20230321163547
+sudo gitlab-psql -c "INSERT INTO schema_migrations (version) VALUES ('20230321163547');"
+```
+
+### Workaround: instance created with 15.11
+
+```shell
+# Restore schema for sent_notifications
+sudo gitlab-rake db:migrate:down VERSION=20230411153310
+sudo gitlab-psql -c "INSERT INTO schema_migrations (version) VALUES ('20230411153310');"
+
+# Restore schema for ci_build_needs
+sudo gitlab-rake db:migrate:down VERSION=20230321163547
+sudo gitlab-psql -c "INSERT INTO schema_migrations (version) VALUES ('20230321163547');"
+```
diff --git a/doc/user/ai_features.md b/doc/user/ai_features.md
index 9558e40d56f..feea06666dc 100644
--- a/doc/user/ai_features.md
+++ b/doc/user/ai_features.md
@@ -5,62 +5,49 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: index, reference
---
-# AI/ML powered features
+# GitLab Duo
GitLab is creating AI-assisted features across our DevSecOps platform. These features aim to help increase velocity and solve key pain points across the software development lifecycle.
-## Enable AI/ML features
-
-> Introduced in GitLab 16.0 and [actively being rolled out](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118222).
-
-Prerequisites:
-
-- You must have the Owner role for the group.
-
-To enable AI/ML features for a top-level group:
-
-- Enable [Experiment features](group/manage.md#enable-experiment-features).
-- Enable [third-party AI features](group/manage.md#enable-third-party-ai-features) (enabled by default).
- To disable AI features powered by third-party APIs, clear this setting.
+| Feature | Purpose | Large Language Model | Current availability | Maturity |
+|-|-|-|-|-|
+| [Suggested Reviewers](project/merge_requests/reviews/index.md#gitlab-duo-suggested-reviewers) | Assists in creating faster and higher-quality reviews by automatically suggesting reviewers for your merge request. | GitLab creates a machine learning model for each project, which is used to generate reviewers <br><br> [View the issue](https://gitlab.com/gitlab-org/modelops/applied-ml/applied-ml-updates/-/issues/10) | SaaS only | [Generally Available (GA)](../policy/experiment-beta-support.md#generally-available-ga) |
+| [Code Suggestions](project/repository/code_suggestions/index.md) | Helps you write code more efficiently by viewing code suggestions as you type. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS <br> Self-managed | [Beta](../policy/experiment-beta-support.md#beta) |
+| [Vulnerability summary](application_security/vulnerabilities/index.md#explaining-a-vulnerability) | Helps you remediate vulnerabilities more efficiently, uplevel your skills, and write more secure code. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) <br><br> Anthropic's claude model if degraded performance | SaaS only <br><br> Ultimate tier | [Beta](../policy/experiment-beta-support.md#beta) |
+| [Code explanation](#explain-code-in-the-web-ui-with-code-explanation) | Helps you understand code by explaining it in English language. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS only <br><br> Ultimate tier | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Chat](#answer-questions-with-chat) | Process and generate text and code in a conversational manner. Helps you quickly identify useful information in large volumes of text in issues, epics, code, and GitLab documentation. | Anthropic's claude model <br><br> OpenAI Embeddings | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Value stream forecasting](#forecast-deployment-frequency-with-value-stream-forecasting) | Assists you with predicting productivity metrics and identifying anomalies across your software development lifecycle. | Statistical forecasting | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Discussion summary](#summarize-issue-discussions-with-discussion-summary) | Assists with quickly getting everyone up to speed on lengthy conversations to help ensure you are all on the same page. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Merge request summary](project/merge_requests/ai_in_merge_requests.md#summarize-merge-request-changes) | Efficiently communicate the impact of your merge request changes. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Code review summary](project/merge_requests/ai_in_merge_requests.md#summarize-my-merge-request-review) | Helps ease merge request handoff between authors and reviewers and help reviewers efficiently understand suggestions. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Merge request template population](project/merge_requests/ai_in_merge_requests.md#fill-in-merge-request-templates) | Generate a description for the merge request based on the contents of the template. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Test generation](project/merge_requests/ai_in_merge_requests.md#generate-suggested-tests-in-merge-requests) | Automates repetitive tasks and helps catch bugs early. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Git suggestions](https://gitlab.com/gitlab-org/gitlab/-/issues/409636) | Helps you discover or recall Git commands when and where you need them. | OpenAI | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| **Root cause analysis** | Assists you in determining the root cause for a pipeline failure and failed CI/CD build. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
+| [Issue description generation](#summarize-an-issue-with-issue-description-generation) | Generate issue descriptions. | [Google Vertex Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview) | SaaS only | [Experiment](../policy/experiment-beta-support.md#experiment) |
-These settings work together so you can have a mix of both experimental and third-party AI features.
-
-## Generally Available AI features
-
-When a feature is [Generally Available](../policy/experiment-beta-support.md#generally-available-ga),
-it does not require [Experiment features to be enabled](group/manage.md#enable-experiment-features).
-Some of these features might require [third-party AI features to be enabled](group/manage.md#enable-third-party-ai-features).
-
-The following feature is Generally Available:
-
-- [Suggested Reviewers](project/merge_requests/reviews/index.md#suggested-reviewers)
+## Enable AI/ML features
-## Beta AI features
+The [Generally Available](../policy/experiment-beta-support.md#generally-available-ga) features listed in the previous table do not need to be enabled.
-[Beta features](../policy/experiment-beta-support.md#beta) do not require
-[Experiment features to be enabled](group/manage.md#enable-experiment-features).
+[Experiment features](../policy/experiment-beta-support.md#experiment) and [Beta features](../policy/experiment-beta-support.md#beta) (besides Code Suggestions) on SaaS must be enabled by a user who has the Owner role in the group. Their usage is subject to the [Testing Terms of Use](https://about.gitlab.com/handbook/legal/testing-agreement/).
-The following features are in Beta:
+In addition, all features built on large language models (LLM) from Google, Anthropic or OpenAI require that [third-party AI features are enabled](group/manage.md#enable-third-party-ai-features) (which they are by default). The table above shows which features are built on which LLM. To disable AI features powered by third-party APIs, clear this setting.
-- [Code Suggestions](project/repository/code_suggestions.md)
-- [Explain this vulnerability](application_security/vulnerabilities/index.md#explaining-a-vulnerability-beta)
+Code Suggestions currently has its own settings:
-## Experiment AI features
+- View [how to enable for self-managed](project/repository/code_suggestions/saas.md#enable-code-suggestions).
+- View [how to enable for SaaS](project/repository/code_suggestions/self_managed.md#enable-code-suggestions-on-self-managed-gitlab).
-[Experiment](../policy/experiment-beta-support.md#experiment) AI features require
-[Experiment features to be enabled](group/manage.md#enable-experiment-features) as well as [third-party AI services to be enabled](group/manage.md#enable-third-party-ai-features).
+The use of Code Suggestions is also subject to the [Testing Terms of Use](https://about.gitlab.com/handbook/legal/testing-agreement/).
-The following features are in Experiment:
+![Settings to enable AI/ML features](img/enable_AI_ML_features.png)
-- [Fill in merge request templates](project/merge_requests/ai_in_merge_requests.md#fill-in-merge-request-templates)
-- [Summarize merge request changes](project/merge_requests/ai_in_merge_requests.md#summarize-merge-request-changes)
-- [Summarize my merge request review](project/merge_requests/ai_in_merge_requests.md#summarize-my-merge-request-review)
-- [Suggested merge or squash commit message](project/merge_requests/ai_in_merge_requests.md#suggested-merge-or-squash-commit-message)
-- [Generate suggested tests in merge requests](project/merge_requests/ai_in_merge_requests.md#generate-suggested-tests-in-merge-requests)
+## Experimental AI features and how to use them
-The rest of the features described on this page are also in the Experiment phase.
+The following subsections describe the experimental AI features in more detail.
-### Explain Selected Code in the Web UI **(ULTIMATE SAAS)**
+### Explain code in the Web UI with Code explanation **(ULTIMATE SAAS EXPERIMENT)**
> Introduced in GitLab 15.11 as an [Experiment](../policy/experiment-beta-support.md#experiment) on GitLab.com.
@@ -75,7 +62,7 @@ By using a large language model, GitLab can explain the code in natural language
Prerequisites:
-Additional prerequisites [beyond the two above](#experiment-ai-features).
+Additional prerequisites in addition to [the settings listed previously](#enable-aiml-features).
- The project must be on GitLab.com.
- You must have the GitLab Ultimate subscription tier.
@@ -83,7 +70,7 @@ Additional prerequisites [beyond the two above](#experiment-ai-features).
To explain your code:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select any file in your project that contains code.
1. On the file, select the lines that you want to have explained.
1. On the left side, select the question mark (**{question}**). You might have to scroll to the first line of your selection to view it. This sends the selected code, together with a prompt, to provide an explanation to the large language model.
@@ -93,7 +80,7 @@ To explain your code:
You can also have code explained in the context of a merge request. To explain
code in a merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Code > Merge requests**, then select your merge request.
1. On the secondary menu, select **Changes**.
1. On the file you would like explained, select the three dots (**{ellipsis_v}**) and select **View File @ $SHA**.
@@ -109,7 +96,7 @@ code in a merge request:
We cannot guarantee that the large language model produces results that are correct. Use the explanation with caution.
-### GitLab Duo Chat **(ULTIMATE SAAS)**
+### Answer questions with Chat **(ULTIMATE SAAS EXPERIMENT)**
> Introduced in GitLab 16.0 as an [Experiment](../policy/experiment-beta-support.md#experiment).
@@ -154,7 +141,7 @@ Or, you can add a comment in the [feedback issue](https://gitlab.com/gitlab-org/
NOTE:
Only the last 50 messages are retained in the chat history. The chat history expires 3 days after last use.
-### Summarize issue discussions **(ULTIMATE SAAS)**
+### Summarize issue discussions with Discussion summary **(ULTIMATE SAAS EXPERIMENT)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10344) in GitLab 16.0 as an [Experiment](../policy/experiment-beta-support.md#experiment).
@@ -174,7 +161,7 @@ Provide feedback on this experimental feature in [issue 407779](https://gitlab.c
**Data usage**: When you use this feature, the text of public comments on the issue are sent to the large
language model referenced above.
-### Show deployment frequency forecast **(ULTIMATE SAAS)**
+### Forecast deployment frequency with Value stream forecasting **(ULTIMATE ALL EXPERIMENT)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10228) in GitLab 16.2 as an [Experiment](../policy/experiment-beta-support.md#experiment).
@@ -182,7 +169,7 @@ This feature is an [Experiment](../policy/experiment-beta-support.md) on GitLab.
In CI/CD Analytics, you can view a forecast of deployment frequency:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > CI/CD analytics**.
1. Select the **Deployment frequency** tab.
1. Turn on the **Show forecast** toggle.
@@ -191,9 +178,11 @@ In CI/CD Analytics, you can view a forecast of deployment frequency:
The forecast is displayed as a dotted line on the chart. Data is forecasted for a duration that is half of the selected date range.
For example, if you select a 30-day range, a forecast for the following 15 days is displayed.
+![Forecast deployment frequency](img/forecast_deployment_frequency.png)
+
Provide feedback on this experimental feature in [issue 416833](https://gitlab.com/gitlab-org/gitlab/-/issues/416833).
-### Generate issue descriptions **(ULTIMATE SAAS)**
+### Summarize an issue with Issue description generation **(ULTIMATE SAAS EXPERIMENT)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10762) in GitLab 16.3 as an [Experiment](../policy/experiment-beta-support.md#experiment).
diff --git a/doc/user/analytics/analytics_dashboards.md b/doc/user/analytics/analytics_dashboards.md
index 49870e8c66c..68b9fef5cc7 100644
--- a/doc/user/analytics/analytics_dashboards.md
+++ b/doc/user/analytics/analytics_dashboards.md
@@ -4,7 +4,7 @@ group: Product Analytics
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Analytics dashboards (Experiment) **(ULTIMATE ALL)**
+# Analytics dashboards **(ULTIMATE ALL EXPERIMENT)**
> Introduced in GitLab 15.9 as an [Experiment](../../policy/experiment-beta-support.md#experiment) feature [with a flag](../../administration/feature_flags.md) named `combined_analytics_dashboards`. Disabled by default.
@@ -29,15 +29,16 @@ The following data sources are configured for analytics dashboards:
## Built-in dashboards
To help you get started with analytics, GitLab provides built-in dashboards with predefined visualizations.
+These dashboards are labeled **By GitLab**, and you cannot edit them.
+Instead, you can create a custom dashboard with a similar style.
### Product analytics
+When [product analytics](../product_analytics/index.md) is enabled and onboarded, two built-in dashboard are added:
+
- **Audience** displays metrics related to traffic, such as the number of users and sessions.
- **Behavior** displays metrics related to user activity, such as the number of page views and events.
-These dashboards are labeled **By GitLab**, and you cannot edit them.
-Instead, you can create a custom dashboard with a similar style.
-
### Value Stream Management
- **Value Streams Dashboard** displays metrics related to [DevOps performance, security exposure, and workstream optimization](../analytics/value_streams_dashboard.md#devsecops-metrics-comparison-panel).
@@ -64,9 +65,6 @@ On self-managed GitLab, by default this feature is not available. To make it ava
On GitLab.com, this feature is not available.
This feature is not ready for production use.
-NOTE:
-This feature does not work in conjunction with the `product_analytics_snowplow_support` feature flag.
-
You can use the dashboard designer to:
- Create custom dashboards.
@@ -82,7 +80,7 @@ Prerequisite:
To view a list of dashboards (both built-in and custom) for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Analytics dashboards**.
1. From the list of available dashboards, select the dashboard you want to view.
@@ -97,9 +95,9 @@ This feature will be connected to group-level dashboards as part of [issue #4115
To change the location of a group's dashboards:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the project you want to store your dashboard files in.
+1. On the left sidebar, select **Search or go to** and find the project you want to store your dashboard files in.
The project must belong to the group for which you create the dashboards.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Analytics**.
1. In the **Analytics Dashboards** section, select your dashboard files project.
@@ -116,10 +114,10 @@ You can share dashboards only between projects that are located in the same grou
To change the location of project dashboards:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project,
+1. On the left sidebar, select **Search or go to** and find your project,
or select **Create new...** (**{plus}**) and **New project/repository**
to create the project to store your dashboard files.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) and find the analytics project.
+1. On the left sidebar, select **Search or go to** and find the analytics project.
1. Select **Settings > General**.
1. Expand **Analytics**.
1. In the **Analytics Dashboards** section, select your dashboard files project.
@@ -180,7 +178,7 @@ create a `line_chart.yaml` file with the following required fields:
To create a custom dashboard:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Analytics dashboards**.
1. Select **New dashboard**.
1. In the **New dashboard** input, enter the name of the dashboard.
@@ -194,7 +192,7 @@ You can edit your custom dashboard's title and add or resize visualizations in t
To edit an existing custom dashboard:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Analytics dashboards**.
1. From the list of available dashboards, select a custom dashboard (one without the `By GitLab` label) you want to edit.
1. Select **Edit**.
@@ -209,9 +207,13 @@ To edit an existing custom dashboard:
If the dashboard displays a global error message that data could not be loaded, first try reloading the page. If the error persists:
-- Check that your configurations match the [JSON schema](#define-a-dashboard) defined in `ee/app/validators/json_schemas/analytics_dashboard.json`.
+- Check that your configurations match the [dashboard JSON schema](#define-a-dashboard) defined in `ee/app/validators/json_schemas/analytics_dashboard.json`.
- For product analytics, check your [admin and project settings](../product_analytics/index.md#project-level-settings), and make sure they are set up correctly.
+### `Invalid visualization configuration`
+
+If a dashboard panel displays a message that the visualization configuration is invalid, check that your visualization configurations match the [visualization JSON schema](#define-a-chart-visualization) defined in `ee/app/validators/json_schemas/analytics_visualization.json`.
+
### Dashboard panel error
If a dashboard panel displays an error message:
diff --git a/doc/user/analytics/ci_cd_analytics.md b/doc/user/analytics/ci_cd_analytics.md
index 8dc69b2f664..61bc77e4469 100644
--- a/doc/user/analytics/ci_cd_analytics.md
+++ b/doc/user/analytics/ci_cd_analytics.md
@@ -32,7 +32,7 @@ View pipeline duration history:
To view CI/CD analytics:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > CI/CD analytics**.
## View DORA deployment frequency chart **(ULTIMATE ALL)**
@@ -50,7 +50,7 @@ The deployment frequency chart is available for groups and projects.
To view the deployment frequency chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > CI/CD analytics**.
1. Select the **Deployment frequency** tab.
@@ -72,7 +72,7 @@ merge requests to be deployed to a production environment. This chart is availab
To view the lead time for changes chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > CI/CD analytics**.
1. Select the **Lead time** tab.
@@ -88,7 +88,7 @@ Time to restore service is one of the four DORA metrics that DevOps teams use fo
To view the time to restore service chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > CI/CD analytics**.
1. Select the **Time to restore service** tab.
@@ -104,6 +104,6 @@ Change failure rate is one of the four DORA metrics that DevOps teams use for me
To view the change failure rate chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > CI/CD analytics**.
1. Select the **Change failure rate** tab.
diff --git a/doc/user/analytics/code_review_analytics.md b/doc/user/analytics/code_review_analytics.md
index 27d3e45803e..e5b475d0e45 100644
--- a/doc/user/analytics/code_review_analytics.md
+++ b/doc/user/analytics/code_review_analytics.md
@@ -34,7 +34,7 @@ Prerequisite:
To view code review analytics:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Code review analytics**.
1. Optional. Filter results:
1. Select the filter bar.
diff --git a/doc/user/analytics/contributor_statistics.md b/doc/user/analytics/contributor_statistics.md
index 514f1ca42ab..ee10522e80b 100644
--- a/doc/user/analytics/contributor_statistics.md
+++ b/doc/user/analytics/contributor_statistics.md
@@ -15,7 +15,7 @@ and line charts with the number of commits by each project member.
To view contributor statistics for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Contributor statistics**.
1. From the **Branches** (**main**) dropdown list, select the branch you want to view commits for.
1. To view the number of commits made on a specific day, hover over the line chart.
@@ -28,7 +28,7 @@ To view contributor statistics for a project:
To view a list of commits made by project members per day:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Contributor statistics**.
1. Select **History**.
1. From the **Branches** (**main**) dropdown list, select the branch you want to view commits for.
@@ -42,7 +42,7 @@ To view a list of commits made by project members per day:
To view the list of commits to the project as an RSS feed in Atom format:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Contributor statistics**.
1. Select **History**.
1. In the upper-right corner, select the feed symbol (**{rss}**).
diff --git a/doc/user/analytics/dora_metrics.md b/doc/user/analytics/dora_metrics.md
index 0efe4a53427..391a1c7965f 100644
--- a/doc/user/analytics/dora_metrics.md
+++ b/doc/user/analytics/dora_metrics.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# DevOps Research and Assessment (DORA) metrics **(ULTIMATE ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/275991) in GitLab 13.7.
-> - [Added support](https://gitlab.com/gitlab-org/gitlab/-/issues/291746) for lead time for changes in GitLab 13.10.
+> - Lead time for changes [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/291746) in GitLab 13.10.
The [DevOps Research and Assessment (DORA)](https://cloud.google.com/blog/products/devops-sre/using-the-four-keys-to-measure-your-devops-performance)
team has identified four metrics that measure DevOps performance.
@@ -33,7 +33,7 @@ This enables teams and managers to understand all aspects of productivity, quali
## Deployment frequency
-> [Fixed](https://gitlab.com/gitlab-org/gitlab/-/issues/394712) the frequency calculation formula for the `all` and `monthly` intervals in GitLab 16.0.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/394712) fix for the frequency calculation formula for `all` and `monthly` intervals in GitLab 16.0.
Deployment frequency is the frequency of successful deployments to production over the given date range (hourly, daily, weekly, monthly, or yearly).
@@ -144,6 +144,24 @@ The table below provides an overview of the DORA metrics' data aggregation in di
| Time to restore service | Number of seconds an incident was open for | daily median per month | daily median | `day` (default) or `month` |
| Change failure rate | percentage of deployments that cause an incident in production | daily median per month | percentage of failed deployments | `day` (default) or `month` |
+## Configure DORA metrics calculation **(ULTIMATE ALL BETA)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96561) in GitLab 15.4 [with a flag](../../administration/feature_flags.md) named `dora_configuration`. Disabled by default. This feature is in [Beta](../../policy/experiment-beta-support.md).
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `dora_configuration`.
+On GitLab.com, this feature is not available.
+This feature is not ready for production use.
+
+You can configure the behavior of DORA metrics calculations.
+To do this, in the Rails console run the following command:
+
+```ruby
+Dora::Configuration.create!(project: my_project, ltfc_target_branches: \['master', 'main'\])
+```
+
+This feature is in [Beta](../../policy/experiment-beta-support.md).
+
## Retrieve DORA metrics data
To retrieve DORA data, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
diff --git a/doc/user/analytics/img/dora_performers_score_panel_v16_3.png b/doc/user/analytics/img/dora_performers_score_panel_v16_3.png
deleted file mode 100644
index 9f59667f9e9..00000000000
--- a/doc/user/analytics/img/dora_performers_score_panel_v16_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/analytics/img/issues_closed_analytics_v16_4.png b/doc/user/analytics/img/issues_closed_analytics_v16_4.png
new file mode 100644
index 00000000000..5e1fe4eaa8c
--- /dev/null
+++ b/doc/user/analytics/img/issues_closed_analytics_v16_4.png
Binary files differ
diff --git a/doc/user/analytics/index.md b/doc/user/analytics/index.md
index abeda983dad..f096d1e2882 100644
--- a/doc/user/analytics/index.md
+++ b/doc/user/analytics/index.md
@@ -6,84 +6,63 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Analyze GitLab usage **(FREE ALL)**
-## Instance-level analytics
+GitLab provides different types of analytics insights at the instance, group, and project level.
+These insights appear on the left sidebar, under [**Analyze**](../project/settings/index.md#disable-project-analytics).
-Instance-level analytics make it possible to aggregate analytics across
-GitLab, so that users can view information across multiple projects and groups
-in one place.
+## Instance-level analytics
-For more information, see [instance-level analytics](../admin_area/analytics/index.md).
+Use [instance-level analytics](../../administration/analytics/index.md) to aggregate analytics across GitLab,
+so that you can view information across multiple projects and groups in one place.
## Group-level analytics
> Moved to GitLab Premium in 13.9.
-GitLab provides several analytics features at the group level. Some of these features require you to use a higher tier than GitLab Free.
+Use group-level analytics to get insights into your groups':
-- [Application Security](../application_security/security_dashboard/index.md)
-- [Contribution](../group/contribution_analytics/index.md)
-- [DevOps Adoption](../group/devops_adoption/index.md)
+- [Security Dashboards](../application_security/security_dashboard/index.md)
+- [Contribution analytics](../group/contribution_analytics/index.md)
+- [DevOps adoption](../group/devops_adoption/index.md)
- [Insights](../group/insights/index.md)
-- [Issue](../group/issues_analytics/index.md)
-- [Productivity](productivity_analytics.md)
-- [Repositories](../group/repositories_analytics/index.md)
-- [Value Stream Management Analytics](../group/value_stream_analytics/index.md), and [Value Stream Management Dashboard](value_streams_dashboard.md)
+- [Issue analytics](../group/issues_analytics/index.md)
+- [Productivity analytics](productivity_analytics.md)
+- [Repositories analytics](../group/repositories_analytics/index.md)
+- [Value Stream Management Analytics](../group/value_stream_analytics/index.md) and [Value Stream Management Dashboard](value_streams_dashboard.md)
## Project-level analytics
-You can use GitLab to review analytics at the project level. Some of these features require you to use a higher tier than GitLab Free.
+Use project-level analytics to get insights into your projects':
- [Analytics dashboards](analytics_dashboards.md), enabled with the `combined_analytics_dashboards_editor`
[feature flag](../../development/feature_flags/index.md#enabling-a-feature-flag-locally-in-development)
-- [Application Security](../application_security/security_dashboard/index.md)
-- [CI/CD & DORA](ci_cd_analytics.md)
-- [Code Review](code_review_analytics.md)
+- [Security Dashboards](../application_security/security_dashboard/index.md)
+- [CI/CD analytics and DORA metrics](ci_cd_analytics.md)
+- [Code review analytics](code_review_analytics.md)
- [Contributor statistics](../../user/analytics/contributor_statistics.md)
- [Insights](../project/insights/index.md)
-- [Issue](../../user/analytics/issue_analytics.md)
-- [Merge Request](merge_request_analytics.md), enabled with the `project_merge_request_analytics`
+- [Issue analytics](../../user/analytics/issue_analytics.md)
+- [Merge request analytics](merge_request_analytics.md), enabled with the `project_merge_request_analytics`
[feature flag](../../development/feature_flags/index.md#enabling-a-feature-flag-locally-in-development)
-- [Repository](repository_analytics.md)
-- [Value Stream Management Analytics](../group/value_stream_analytics/index.md), and [Value Stream Management Dashboard](value_streams_dashboard.md)
-
-### Remove project analytics from the left sidebar
-
-By default, analytics for a project are displayed under the **Analyze** item in the left sidebar. To remove this item:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Visibility, project features, permissions**.
-1. Turn off the **Analytics** toggle.
-1. Select **Save changes**.
+- [Repository analytics](repository_analytics.md)
+- [Value Stream Management Analytics](../group/value_stream_analytics/index.md) and [Value Stream Management Dashboard](value_streams_dashboard.md)
## User-configurable analytics
-The following analytics features are available for users to create personalized views:
-
-- [Application Security](../application_security/security_dashboard/index.md#security-center)
-
-Be sure to review the documentation page for this feature for GitLab tier requirements.
+View vulnerabilities of your selected projects in the [Security Center](../application_security/security_dashboard/index.md#security-center).
## Value streams management
-You can use the following analytics features to analyze and visualize the performance of your projects and groups:
+Analyze and visualize the performance of your projects and groups with:
- [Value stream analytics for projects and groups](../group/value_stream_analytics/index.md)
- [Value streams dashboard](value_streams_dashboard.md)
## Glossary
-We use the following terms to describe GitLab analytics:
-
-- **Mean Time to Change (MTTC):** The average duration between idea and delivery. GitLab measures
-MTTC from issue creation to the issue's latest related merge request's deployment to production.
-- **Mean Time to Detect (MTTD):** The average duration that a bug goes undetected in production.
-GitLab measures MTTD from deployment of bug to issue creation.
-- **Mean Time To Merge (MTTM):** The average lifespan of a merge request. GitLab measures MTTM from
-merge request creation to merge request merge (and closed/un-merged merge requests are excluded).
-For more information, see [Merge Request Analytics](merge_request_analytics.md).
-- **Mean Time to Recover/Repair/Resolution/Resolve/Restore (MTTR):** The average duration that a bug
-is not fixed in production. GitLab measures MTTR from deployment of bug to deployment of fix.
-- **Velocity:** The total issue burden completed in some period of time. The burden is usually measured
-in points or weight, often per sprint. For example, your velocity may be "30 points per sprint". GitLab
-measures velocity as the total points or weight of issues closed in a given period of time.
+| Metric | Definition | Measurement in GitLab |
+| ------ | ---------- | --------------------- |
+| Mean Time to Change (MTTC) | The average duration between idea and delivery. | From issue creation to the issue's latest related merge request's deployment to production. |
+| Mean Time to Detect (MTTD) | The average duration that a bug goes undetected in production. | From deployment of bug to issue creation. |
+| Mean Time To Merge (MTTM) | The average lifespan of a merge request. | From merge request creation to merge request merge (excluding closed and unmerged merge requests). For more information, see [Merge Request Analytics](merge_request_analytics.md). |
+| Mean Time to Recover/Repair/Resolution/Resolve/Restore (MTTR) | The average duration that a bug is not fixed in production. | From deployment of bug to deployment of fix. |
+| Velocity | The total issue burden completed in some period of time. The burden is usually measured in points or weight, often per sprint. | Total points or weight of issues closed in a given period of time. Expressed as, for example, "30 points per sprint". |
diff --git a/doc/user/analytics/issue_analytics.md b/doc/user/analytics/issue_analytics.md
index 7caee947318..8f29c008d75 100644
--- a/doc/user/analytics/issue_analytics.md
+++ b/doc/user/analytics/issue_analytics.md
@@ -15,9 +15,11 @@ prior.
To access the chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Issue analytics**.
+You can also access the chart from the [Value Streams Dashboard](value_streams_dashboard.md#dashboard-metrics-and-drill-down-reports) through the **New issues** drill-down report.
+
Hover over each bar to see the total number of issues.
To narrow the scope of issues included in the graph, enter your criteria in the
@@ -36,6 +38,20 @@ shows a total of 15 months for the chart in the GitLab.org group.
![Issues created per month](img/issues_created_per_month_v14_8.png)
+## Enhanced issue analytics **(ULTIMATE ALL)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233905/) in GitLab 16.4 [with a flag](../../administration/feature_flags.md) named `issues_completed_analytics_feature_flag`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, an administrator can
+[enable the feature flag](../../administration/feature_flags.md) named `issues_completed_analytics_feature_flag`. On GitLab.com, this feature is not
+available. This feature is not ready for production use.
+
+Enhanced issue analytics display the additional metric "Issues closed", which represents the total number of resolved issues in your project over a selected period.
+You can use this metric to improve the overall turn-around time and value delivered to your customers.
+
+![Issues opened and closed per month](img/issues_closed_analytics_v16_4.png)
+
## Drill into the information
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196547) in GitLab 13.1.
diff --git a/doc/user/analytics/merge_request_analytics.md b/doc/user/analytics/merge_request_analytics.md
index 998f56ac40a..0f8eb9ac211 100644
--- a/doc/user/analytics/merge_request_analytics.md
+++ b/doc/user/analytics/merge_request_analytics.md
@@ -29,7 +29,7 @@ Prerequisite:
To view merge request analytics:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Merge request analytics**.
## View the number of merge requests in a date range
@@ -39,7 +39,7 @@ To view merge request analytics:
To view the number of merge requests merged during a specific date range:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Merge request analytics**.
1. Optional. Filter results:
1. Select the filter bar.
@@ -73,6 +73,6 @@ created and when it's merged. Closed and not yet merged merge requests are not i
To view **Mean time to merge**:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Merge request analytics**. The **Mean time to merge** number
is displayed on the dashboard.
diff --git a/doc/user/analytics/productivity_analytics.md b/doc/user/analytics/productivity_analytics.md
index ea896f07204..a17eb08c53c 100644
--- a/doc/user/analytics/productivity_analytics.md
+++ b/doc/user/analytics/productivity_analytics.md
@@ -26,7 +26,7 @@ Prerequisite:
- You must have at least the Reporter role for the group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Productivity analytics**.
1. Optional. Filter results:
1. Select a project from the dropdown list.
@@ -44,7 +44,7 @@ Use the following charts in productivity analytics to view the velocity of your
merge requests to merge after they were created.
- **Trendline**: number of merge requests that were merged in a specific time period.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Productivity analytics**.
To filter time metrics:
@@ -56,7 +56,7 @@ To filter time metrics:
To view commit statistics for your group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Productivity analytics**.
1. Under the **Trendline** scatterplot, view the commit statistics:
- The left histogram shows the number of hours between commits, comments, and merges.
diff --git a/doc/user/analytics/repository_analytics.md b/doc/user/analytics/repository_analytics.md
index 46fa36658c4..26bce8a20c2 100644
--- a/doc/user/analytics/repository_analytics.md
+++ b/doc/user/analytics/repository_analytics.md
@@ -20,7 +20,7 @@ Repository analytics is part of [GitLab Community Edition](https://gitlab.com/gi
Repository analytics requires:
- An initialized Git repository.
-- At least one commit in the default branch (`master` by default).
+- At least one commit in the default branch (`main` by default).
NOTE:
Without a Git commit in the default branch, the menu item isn't visible.
@@ -30,7 +30,7 @@ Commits in a project's [wiki](../project/wiki/index.md#track-wiki-events) are no
To review repository analytics for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Repository analytics**.
## How repository analytics chart data is updated
diff --git a/doc/user/analytics/value_streams_dashboard.md b/doc/user/analytics/value_streams_dashboard.md
index 2c6626ad315..ed637dd886f 100644
--- a/doc/user/analytics/value_streams_dashboard.md
+++ b/doc/user/analytics/value_streams_dashboard.md
@@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Released in GitLab 15.11 as an Open [Beta](../../policy/experiment-beta-support.md#beta) feature [with a flag](../../administration/feature_flags.md) named `group_analytics_dashboards_page`. Enabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/392734) in GitLab 16.0. Feature flag `group_analytics_dashboards_page` removed.
-You can leave feedback on dashboard bugs or functionality in [issue 419488](https://gitlab.com/gitlab-org/gitlab/-/issues/419488).
+To help us improve the Value Streams Dashboard, please share feedback about your experience in this [survey](https://gitlab.fra1.qualtrics.com/jfe/form/SV_50guMGNU2HhLeT4).
For more information, see also the [Value Stream Management category direction page](https://about.gitlab.com/direction/plan/value_stream_management/).
The Value Streams Dashboard is a customizable dashboard you can use to identify trends, patterns, and opportunities for digital transformation improvements.
@@ -71,22 +71,46 @@ For example, if a project has a high score for Deployment Frequency (Velocity),
These scoring are based on Google's classifications in the [DORA 2022 Accelerate State of DevOps Report](https://cloud.google.com/blog/products/devops-sre/dora-2022-accelerate-state-of-devops-report-now-out).
+## Enable or disable overview background aggregation **(ULTIMATE SELF)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120610) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `modify_value_stream_dashboard_settings`. Disabled by default.
+> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130704) in GitLab 16.4.
+
+FLAG:
+On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, an administrator can [disable the feature flag](../../administration/feature_flags.md) named `modify_value_stream_dashboard_settings`.
+On GitLab.com, this feature is not available.
+This feature is not ready for production use.
+
+Prerequisite:
+
+- You must have administrator access to the instance.
+
+To enable or disable the overview count aggregation for the Value Streams Dashboard:
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **Settings > General**.
+1. Expand **Analytics**.
+1. In **Value Streams Dashboard**, select or clear the **Enable overview background aggregation for Value Streams Dashboard** checkbox.
+
+To retrieve aggregated usage counts in the group, use the [GraphQL API](../../api/graphql/reference/index.md#groupvaluestreamdashboardusageoverview).
+
## View the value streams dashboard
Prerequisite:
- You must have at least the Reporter role for the group.
+- Overview background aggregation for Value Streams Dashboards must be enabled.
To view the value streams dashboard:
- From Analytics Dashboards:
- 1. On the group left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+ 1. On the group left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Analytics Dashboards**.
- From Value Stream Analytics:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+ 1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value stream analytics**.
1. Below the **Filter results** text box, in the **Lifecycle metrics** row, select **Value Streams Dashboard / DORA**.
1. Optional. To open the new page, append this path `/analytics/dashboards/value_streams_dashboard` to the group URL (for example, `https://gitlab.com/groups/gitlab-org/-/analytics/dashboards/value_streams_dashboard`).
@@ -118,7 +142,7 @@ Prerequisite:
- You must have at least the Maintainer role for the group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Analytics**.
1. Select the project where you would like to store your YAML configuration file.
@@ -126,7 +150,7 @@ Prerequisite:
After you have set up the project, set up the configuration file:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. In the default branch, create the configuration file: `.gitlab/analytics/dashboards/value_streams/value_streams.yaml`.
1. In the `value_streams.yaml` configuration file, fill in the configuration options:
diff --git a/doc/user/application_security/api_fuzzing/index.md b/doc/user/application_security/api_fuzzing/index.md
index c365c7f6bab..1bac636ac3f 100644
--- a/doc/user/application_security/api_fuzzing/index.md
+++ b/doc/user/application_security/api_fuzzing/index.md
@@ -101,7 +101,7 @@ a YAML snippet that you can paste in your GitLab CI/CD configuration.
To generate an API Fuzzing configuration snippet:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **API Fuzzing** row, select **Enable API Fuzzing**.
1. Complete the fields. For details see [Available CI/CD variables](#available-cicd-variables).
diff --git a/doc/user/application_security/configuration/index.md b/doc/user/application_security/configuration/index.md
index 10e16a173d8..1e9163a4c26 100644
--- a/doc/user/application_security/configuration/index.md
+++ b/doc/user/application_security/configuration/index.md
@@ -1,5 +1,4 @@
---
-type: reference, howto
stage: Secure
group: Static Analysis
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
@@ -7,11 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Security configuration **(FREE ALL)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20711) in GitLab 12.6.
-> - SAST configuration was [enabled](https://gitlab.com/groups/gitlab-org/-/epics/3659) in 13.3 and [improved](https://gitlab.com/gitlab-org/gitlab/-/issues/232862) in 13.4.
-> - DAST Profiles feature was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40474) in 13.4.
-> - A simplified version was made [available in all tiers](https://gitlab.com/gitlab-org/gitlab/-/issues/294076) in GitLab 13.10.
-> - [Redesigned](https://gitlab.com/gitlab-org/gitlab/-/issues/326926) in 14.2.
+> Security configuration page was [redesigned](https://gitlab.com/gitlab-org/gitlab/-/issues/326926) in GitLab 14.2.
The **Security configuration** page lists the following for the security testing and compliance tools:
@@ -40,7 +35,7 @@ all security features are configured by default.
To view a project's security configuration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
Select **Configuration history** to see the `.gitlab-ci.yml` file's history.
diff --git a/doc/user/application_security/continuous_vulnerability_scanning/index.md b/doc/user/application_security/continuous_vulnerability_scanning/index.md
new file mode 100644
index 00000000000..4094a0add28
--- /dev/null
+++ b/doc/user/application_security/continuous_vulnerability_scanning/index.md
@@ -0,0 +1,59 @@
+---
+stage: Secure
+group: Composition Analysis
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Continuous Vulnerability Scanning **(ULTIMATE EXPERIMENT)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371063) in GitLab 16.4 as an [Experiment](../../../policy/experiment-beta-support.md#experiment) with two [features flags](../../../administration/feature_flags.md) named `dependency_scanning_on_advisory_ingestion` and `package_metadata_advisory_sync`. Enabled by default.
+
+NOTE:
+This feature is an [Experiment](../../../policy/experiment-beta-support.md#experiment) and subject to change without notice.
+If you have any feedback, you can let us know in the [feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/425072).
+
+FLAG:
+On self-managed GitLab, by default this feature is available. To hide the feature, an administrator can [disable the feature flags](../../feature_flags.md) named `dependency_scanning_on_advisory_ingestion` and `package_metadata_advisory_sync`.
+On GitLab.com, this feature is available.
+
+Continuous Vulnerability Scanning detects new vulnerabilities outside a pipeline.
+Your projects are automatically scanned whenever advisories are added to the [`GitLab Advisory Database`](https://advisories.gitlab.com/).
+Projects that depend on the affected components have new vulnerabilities automatically created.
+
+Continuous Vulnerability Scanning detects vulnerabilities in the latest CycloneDX SBOM reports for the default branch.
+[Dependency Scanning](../dependency_scanning/index.md) is used to generate these reports.
+
+## Configuration
+
+To enable Continuous Vulnerability Scanning:
+
+- Enable the Continuous Vulnerability Scanning setting in the project's [security configuration](../configuration/index.md).
+- Enable [Dependency Scanning](../dependency_scanning/index.md#configuration) and ensure that its prerequisites are met.
+
+On GitLab self-managed only, you can [choose package registry metadata to sync](../../../administration/settings/security_and_compliance.md#choose-package-registry-metadata-to-sync) in the Admin Area for the GitLab instance.
+
+### Requirements for offline environments
+
+For self-managed GitLab instances in an environment with limited, restricted, or intermittent access to external resources through the internet,
+some adjustments are required to successfully scan CycloneDX reports for vulnerabilities.
+For more information, see the offline [quick start guide](../../../topics/offline/quick_start_guide.md#enabling-the-package-metadata-database).
+
+## Supported languages and package managers
+
+The supported files and versions are the ones supported by
+[Dependency Scanning](../dependency_scanning/index.md#supported-languages-and-package-managers).
+
+Go pseudo versions are not supported. A project dependency that references a Go pseudo version is never considered as affected. This might result in false negatives.
+
+## Checking new vulnerabilities
+
+New vulnerabilities detected by Continuous Vulnerability Scanning are visible on the [Vulnerability Report](../vulnerability_report/index.md).
+However, they are not listed on the [Dependency List](../dependency_list/index.md) or in the pipeline where the affected SBOM component was detected.
+
+After an advisory is added to the [`GitLab Advisory Database`](https://advisories.gitlab.com/),
+it might take a few hours before the corresponding vulnerabilities are added to your projects.
+
+## Contributing to the vulnerability database
+
+To find a vulnerability, you can search the [`GitLab Advisory Database`](https://advisories.gitlab.com/).
+You can also [submit new vulnerabilities](https://gitlab.com/gitlab-org/security-products/gemnasium-db/blob/master/CONTRIBUTING.md).
diff --git a/doc/user/application_security/coverage_fuzzing/index.md b/doc/user/application_security/coverage_fuzzing/index.md
index 59bd2b1ffb3..599203dedcc 100644
--- a/doc/user/application_security/coverage_fuzzing/index.md
+++ b/doc/user/application_security/coverage_fuzzing/index.md
@@ -58,7 +58,7 @@ You can use the following fuzzing engines to test the specified languages.
To confirm the status of coverage-guided fuzz testing:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Coverage Fuzzing** section the status is:
- **Not configured**
@@ -172,7 +172,7 @@ artifacts files you can download from the CI/CD pipeline. Also, a project member
To view details of the corpus registry:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Coverage Fuzzing** section, select **Manage corpus**.
@@ -200,7 +200,7 @@ provided by the `COVFUZZ_CORPUS_NAME` variable. The corpus is updated on every p
To upload an existing corpus file:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Coverage Fuzzing** section, select **Manage corpus**.
1. Select **New corpus**.
diff --git a/doc/user/application_security/dast/authentication.md b/doc/user/application_security/dast/authentication.md
index b13b41e4a37..aed4066bc52 100644
--- a/doc/user/application_security/dast/authentication.md
+++ b/doc/user/application_security/dast/authentication.md
@@ -412,9 +412,12 @@ Authentication failed because a home page should be displayed after login. Inste
### Configure the authentication report
+WARNING:
+The authentication report can contain sensitive information such as the credentials used to perform the login.
+
An authentication report can be saved as a CI/CD job artifact to assist with understanding the cause of an authentication failure.
-The report contains steps during the login process, HTTP requests and responses, the Document Object Model (DOM) and screenshots.
+The report contains steps performed during the login process, HTTP requests and responses, the Document Object Model (DOM) and screenshots.
![dast-auth-report](img/dast_auth_report.jpg)
diff --git a/doc/user/application_security/dast/checks/113.1.md b/doc/user/application_security/dast/checks/113.1.md
new file mode 100644
index 00000000000..44c3be330f2
--- /dev/null
+++ b/doc/user/application_security/dast/checks/113.1.md
@@ -0,0 +1,27 @@
+---
+stage: Secure
+group: Dynamic Analysis
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Improper Neutralization of CRLF Sequences in HTTP Headers
+
+## Description
+
+By inserting Carriage Return / Line Feed (CRLF) characters, malicious users could potentially inject arbitrary data into HTTP responses. By modifying HTTP responses, attackers could conduct cross-site scripting or cache poisoning attacks against other users of the system.
+
+## Remediation
+
+User input should never be used in constructing HTTP header responses without some form
+of validation against newlines. This includes URLs supplied by the user for HTTP redirects.
+
+## Details
+
+| ID | Aggregated | CWE | Type | Risk |
+|:---|:--------|:--------|:--------|:--------|
+| 113.1 | false | 113 | Active | high |
+
+## Links
+
+- [OWASP](https://owasp.org/www-community/attacks/HTTP_Response_Splitting)
+- [CWE](https://cwe.mitre.org/data/definitions/113.html)
diff --git a/doc/user/application_security/dast/checks/16.7.md b/doc/user/application_security/dast/checks/16.7.md
index edaace407ae..d407234d2c2 100644
--- a/doc/user/application_security/dast/checks/16.7.md
+++ b/doc/user/application_security/dast/checks/16.7.md
@@ -22,8 +22,8 @@ Only three directives are applicable for the `Strict-Transport-Security` header.
1. `includeSubDomains`: This optional, valueless directive signals that the policy applies to this host as well as any subdomains found under this host's domain.
1. `preload`: While not part of the specification, setting this optional value allows major browser organizations to add this site into the browser's preloaded set of HTTPS sites. This requires further action on behalf of the website operator to submit their domain to the browser's HSTS preload list. See [hstspreload.org](https://hstspreload.org/) for more information.
-Invalid directives, or the `Strict-Transport-Security` header appearing more than once (if the
-values are different) is considered invalid.
+Note that invalid directives, or the `Strict-Transport-Security` header appearing more than once (if the values are
+different) is considered invalid.
Prior to adding to this security configuration to your website, it is recommended you review the hstspreload.org [Deployment Recommendations](https://hstspreload.org/#deployment-recommendations).
diff --git a/doc/user/application_security/dast/checks/16.9.md b/doc/user/application_security/dast/checks/16.9.md
index c63a620794e..b0ba502b578 100644
--- a/doc/user/application_security/dast/checks/16.9.md
+++ b/doc/user/application_security/dast/checks/16.9.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## Description
A `Content-Security-Policy-Report-Only` (CSPRO) was identified on the target site. CSP-Report-Only headers
-aid in determining how to implement a `Content-Security-Policy` that does not disrupt use of the target
+aid in determining how to implement a `Content-Security-Policy` that does not disrupt normal use of the target
site.
## Remediation
diff --git a/doc/user/application_security/dast/checks/index.md b/doc/user/application_security/dast/checks/index.md
index 1b3ce45dc43..035f4a4b486 100644
--- a/doc/user/application_security/dast/checks/index.md
+++ b/doc/user/application_security/dast/checks/index.md
@@ -4,7 +4,7 @@ group: Dynamic Analysis
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# DAST browser-based crawler vulnerability checks **(ULTIMATE ALL)**
+# DAST browser-based crawler vulnerability checks **(ULTIMATE)**
The [DAST browser-based crawler](../browser_based.md) provides a number of vulnerability checks that are used to scan for vulnerabilities in the site under test.
@@ -167,4 +167,5 @@ The [DAST browser-based crawler](../browser_based.md) provides a number of vulne
| ID | Check | Severity | Type |
|:---|:------|:---------|:-----|
+| [113.1](113.1.md) | Improper Neutralization of CRLF Sequences in HTTP Headers | High | Active |
| [22.1](22.1.md) | Improper limitation of a pathname to a restricted directory (Path traversal) | High | Active |
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 24aadd14dd1..4ec693593fb 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -81,8 +81,8 @@ analyzer-specific configuration instructions.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in GitLab 13.1.
-Detected vulnerabilities are shown in [Merge requests](../index.md#view-security-scan-information-in-merge-requests), the [Pipeline security tab](../index.md#view-security-scan-information-in-the-pipeline-security-tab),
-and the [Vulnerability report](../index.md#view-security-scan-information-in-the-vulnerability-report).
+Detected vulnerabilities appear in [merge requests](../index.md#merge-request), the [pipeline security tab](../index.md#pipeline-security-tab),
+and the [vulnerability report](../index.md#vulnerability-report).
1. To see all vulnerabilities detected, either:
- From your project, select **Security & Compliance**, then **Vulnerability report**.
diff --git a/doc/user/application_security/dast/proxy-based.md b/doc/user/application_security/dast/proxy-based.md
index 7538bd38d9f..86af7d4c5da 100644
--- a/doc/user/application_security/dast/proxy-based.md
+++ b/doc/user/application_security/dast/proxy-based.md
@@ -89,7 +89,7 @@ In this method you manually edit the existing `.gitlab-ci.yml` file. Use this me
To include the DAST template:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipeline editor**.
1. Copy and paste the following to the bottom of the `.gitlab-ci.yml` file.
@@ -156,7 +156,7 @@ snippet is created that you paste into the `.gitlab-ci.yml` file.
To configure DAST using the UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Enable DAST** or
**Configure DAST**.
@@ -467,6 +467,9 @@ The DAST job does not require the project's repository to be present when runnin
> - Runner tags selection [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345430) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `on_demand_scans_runner_tags. Disabled by default.
> - Runner tags selection [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111499) in GitLab 16.3.
+WARNING:
+On-demand scans are not available when GitLab is running in FIPS mode.
+
An on-demand DAST scan runs outside the DevOps life cycle. Changes in your repository don't trigger
the scan. You must either start it manually, or schedule it to run. For on-demand DAST scans,
a [site profile](#site-profile) defines **what** is to be scanned, and a
@@ -483,7 +486,7 @@ An on-demand scan can be run in active or passive mode:
To view on-demand scans:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Secure > On-demand scans**.
On-demand scans are grouped by their status. The scan library contains all available on-demand
@@ -499,7 +502,7 @@ Prerequisites:
To run an existing on-demand scan:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > On-demand scans**.
1. Select the **Scan library** tab.
1. In the scan's row, select **Run scan**.
@@ -522,7 +525,7 @@ Create an on-demand scan to:
To create an on-demand DAST scan:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Secure > On-demand scans**.
1. Select **New scan**.
1. Complete the **Scan name** and **Description** fields.
@@ -550,7 +553,7 @@ The on-demand DAST scan runs as specified and the project's dashboard shows the
To view details of an on-demand scan:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > On-demand scans**.
1. Select the **Scan library** tab.
1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Edit**.
@@ -559,7 +562,7 @@ To view details of an on-demand scan:
To edit an on-demand scan:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > On-demand scans**.
1. Select the **Scan library** tab.
1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Edit**.
@@ -570,7 +573,7 @@ To edit an on-demand scan:
To delete an on-demand scan:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > On-demand scans**.
1. Select the **Scan library** tab.
1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Delete**.
@@ -632,7 +635,7 @@ equivalent in functionality, so use whichever is most suitable:
To create a site profile:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Select **New > Site profile**.
@@ -654,7 +657,7 @@ When a validated site profile's file, header, or meta tag is edited, the site's
To edit a site profile:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Select the **Site Profiles** tab.
@@ -669,7 +672,7 @@ See [Scan execution policies](../policies/scan-execution-policies.md) for more i
To delete a site profile:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Select the **Site Profiles** tab.
@@ -687,7 +690,7 @@ Prerequisites:
To validate a site profile:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Select the **Site Profiles** tab.
@@ -724,7 +727,7 @@ page.
To retry a site profile's failed validation:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Select the **Site Profiles** tab.
@@ -738,7 +741,7 @@ have their validation status revoked.
To revoke a site profile's validation status:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Beside the validated profile, select **Revoke validation**.
@@ -809,7 +812,7 @@ A scanner profile contains:
To create a scanner profile:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Select **New > Scanner profile**.
@@ -824,7 +827,7 @@ For more information, see [Scan execution policies](../policies/scan-execution-p
To edit a scanner profile:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Select the **Scanner profiles** tab.
@@ -840,7 +843,7 @@ page. For more information, see [Scan execution policies](../policies/scan-execu
To delete a scanner profile:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
1. Select the **Scanner profiles** tab.
diff --git a/doc/user/application_security/dependency_list/img/dependency_list_v13_11.png b/doc/user/application_security/dependency_list/img/dependency_list_v13_11.png
deleted file mode 100644
index 5b2bd985ce4..00000000000
--- a/doc/user/application_security/dependency_list/img/dependency_list_v13_11.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/dependency_list/img/dependency_list_v16_3.png b/doc/user/application_security/dependency_list/img/dependency_list_v16_3.png
index f3a8f3d8d5d..7e4e80f9c00 100644
--- a/doc/user/application_security/dependency_list/img/dependency_list_v16_3.png
+++ b/doc/user/application_security/dependency_list/img/dependency_list_v16_3.png
Binary files differ
diff --git a/doc/user/application_security/dependency_list/index.md b/doc/user/application_security/dependency_list/index.md
index a55f26f529d..d8726cbd456 100644
--- a/doc/user/application_security/dependency_list/index.md
+++ b/doc/user/application_security/dependency_list/index.md
@@ -9,17 +9,16 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - System dependencies [introduced](https://gitlab.com/groups/gitlab-org/-/epics/6698) in GitLab 14.6.
> - Group-level dependency list [introduced](https://gitlab.com/groups/gitlab-org/-/epics/8090) in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `group_level_dependencies`. Disabled by default.
+> - Group-level dependency list [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/411257) in GitLab 16.4.
-Use the dependency list to review your project or group's dependencies and key
-details about those dependencies, including their known vulnerabilities. It is a collection of dependencies in your project, including existing and new findings.
+Use the dependency list to review your project or group's dependencies and key details about those
+dependencies, including their known vulnerabilities. This list is a collection of dependencies in your
+project, including existing and new findings. This information is sometimes referred to as a
+Software Bill of Materials, SBOM, or BOM.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Project Dependency](https://www.youtube.com/watch?v=ckqkn9Tnbw4).
-To see the dependency list, go to your project or group and select **Secure > Dependency list**.
-
-This information is sometimes referred to as a Software Bill of Materials, SBOM, or BOM.
-
## Prerequisites
To view your project's dependencies, ensure you meet the following requirements:
@@ -34,21 +33,33 @@ To view your project's dependencies, ensure you meet the following requirements:
You should not change the default behavior of allowing the
[application security jobs](../../application_security/index.md#application-coverage) to fail.
-## View a project's dependencies
+## View project dependencies
+
+To view the dependencies of a project or all projects in a group:
-![Dependency list](img/dependency_list_v13_11.png)
+1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. Select **Secure > Dependency list**.
-GitLab displays dependencies with the following information:
+Details of each dependency are listed, sorted by decreasing severity of vulnerabilities (if any). You can sort the list instead by component name or packager.
| Field | Description |
-|-----------|-------------|
+|:----------|:-----------|
| Component | The dependency's name and version. |
| Packager | The packager used to install the dependency. |
| Location | For system dependencies, this lists the image that was scanned. For application dependencies, this shows a link to the packager-specific lock file in your project that declared the dependency. It also shows the [dependency path](#dependency-paths) to a top-level dependency, if any, and if supported. |
-| License | Links to dependency's software licenses. |
+| License<sup>1</sup> | Links to dependency's software licenses. A warning badge that includes the number of vulnerabilities detected in the dependency. |
+| Projects<sup>2</sup> | Links to the project with the dependency. If multiple projects have the same dependency, the total number of these projects is shown. To go to a project with this dependency, select the **Projects** number, then search for and select its name. The project search feature is supported only on groups that have up to 600 occurrences in their group hierarchy. |
+
+<html>
+<small>Footnotes:
+ <ol>
+ <li>Project-level only.</li>
+ <li>Group-level only.</li>
+ </ol>
+</small>
+</html>
-Displayed dependencies are initially sorted by the severity of their known vulnerabilities, if any. They
-can also be sorted by name or by the packager that installed them.
+![Dependency list](img/dependency_list_v16_3.png)
### Vulnerabilities
@@ -60,7 +71,7 @@ select the vulnerability's description. The [vulnerability's details](../vulnera
### Dependency paths
The dependency list shows the path between a dependency and a top-level dependency it's connected
-to, if any. There are many possible paths connecting a transient dependency to top-level
+to, if any. Multiple paths may connect a transient dependency to top-level
dependencies, but the user interface shows only one of the shortest paths.
NOTE:
@@ -73,42 +84,20 @@ Dependency paths are supported for the following package managers:
- [NuGet](https://www.nuget.org/)
- [Yarn 1.x](https://classic.yarnpkg.com/lang/en/)
- [sbt](https://www.scala-sbt.org)
+- [Conan](https://conan.io)
### Licenses
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10536) in GitLab 12.3.
-
If the [Dependency Scanning](../../application_security/dependency_scanning/index.md) CI job is configured,
-[discovered licenses](../../compliance/license_scanning_of_cyclonedx_files/index.md#enable-license-scanning) are displayed on this page.
-
-## View a group's dependencies
-
-FLAG:
-On self-managed GitLab, and GitLab.com the feature is disabled by default. To show the feature, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `group_level_dependencies`.
-
-![Dependency list](img/dependency_list_v16_3.png)
-
-GitLab displays dependencies with the following information:
-
-| Field | Description |
-|-----------|-------------|
-| Component | The dependency's name and version. |
-| Packager | The packager used to install the dependency. |
-| Location | For operating system dependencies, this lists the image that was scanned. For application dependencies, this shows a link to the packager-specific lock file in your project that declared the dependency. It also shows the [dependency path](#dependency-paths) to a top-level dependency, if any, and if supported. If there are multiple locations, the total number of locations is displayed. |
-| Projects | Links to the project related to the dependency. If there are multiple projects, the total number of projects is displayed. |
-
-Displayed dependencies are initially sorted by packager. They
-can also be sorted by name.
-
-## Downloading the dependency list
-
-You can download the full list of dependencies and their details in
-`JSON` format.
+[discovered licenses](../../compliance/license_scanning_of_cyclonedx_files/index.md) are displayed on this page.
-### In the UI
+## Download the dependency list
-You can download your group's or project's list of dependencies and their details in JSON format by selecting the **Export** button. The dependency list only shows the results of the last successful pipeline to run on the default branch.
+You can download the full list of dependencies and their details in JSON format. The dependency
+list shows only the results of the last successful pipeline that ran on the default branch.
-### Using the API
+To download the dependency list:
-You can download your project's list of dependencies [using the API](../../../api/dependencies.md#list-project-dependencies). Note this only provides the dependencies identified by the [Gemnasium family of analyzers](../dependency_scanning/index.md#dependency-analyzers) and not any other of the GitLab dependency analyzers.
+1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. Select **Secure > Dependency list**.
+1. Select **Export**.
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 5a2394113cb..f8bd5b99cb6 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -18,6 +18,8 @@ Dependency Scanning can run in the development phase of your application's life
pipeline runs, vulnerabilities are identified and compared between the source and target branches.
Vulnerabilities and their severity are listed in the merge request, enabling you to proactively
address the risk to your application, before the code change is committed.
+Vulnerabilities can also be identified outside a pipeline by
+[Continuous Vulnerability Scanning](../continuous_vulnerability_scanning/index.md).
GitLab offers both Dependency Scanning and [Container Scanning](../container_scanning/index.md) to
ensure coverage for all of these dependency types. To cover as much of your risk area as possible,
@@ -327,7 +329,7 @@ GitLab analyzers obtain dependency information using one of the following two me
The following package managers use lockfiles that GitLab analyzers are capable of parsing directly:
-| Package Manager | Supported File Format Versions | Tested Versions |
+| Package Manager | Supported File Format Versions | Tested Package Manager Versions |
| ------ | ------ | ------ |
| Bundler | Not applicable | [1.17.3](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/ruby-bundler/default/Gemfile.lock#L118), [2.1.4](https://gitlab.com/gitlab-org/security-products/tests/ruby-bundler/-/blob/bundler2-FREEZE/Gemfile.lock#L118) |
| Composer | Not applicable | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/php-composer/default/composer.lock) |
@@ -335,7 +337,7 @@ The following package managers use lockfiles that GitLab analyzers are capable o
| Go | Not applicable | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/go-modules/gosum/default/go.sum) <sup><strong><a href="#notes-regarding-parsing-lockfiles-1">1</a></strong></sup> |
| NuGet | v1, v2<sup><b><a href="#notes-regarding-parsing-lockfiles-2">2</a></b></sup> | [4.9](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/csharp-nuget-dotnetcore/default/src/web.api/packages.lock.json#L2) |
| npm | v1, v2, v3<sup><b><a href="#notes-regarding-parsing-lockfiles-3">3</a></b></sup> | [6.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-npm/default/package-lock.json#L4), [7.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-npm/lockfileVersion2/package-lock.json#L4), [9.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/scanner/parser/npm/fixtures/lockfile-v3/simple/package-lock.json#L4) |
-| pnpm | v5.3, v5.4, v6 | [7.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-pnpm/default/pnpm-lock.yaml#L1), [8.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/scanner/parser/pnpm/fixtures/v6/simple/pnpm-lock.yaml#L1) |
+| pnpm | v5, v6 | [7.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-pnpm/default/pnpm-lock.yaml#L1), [8.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/scanner/parser/pnpm/fixtures/v6/simple/pnpm-lock.yaml#L1) |
| yarn | v1, v2<sup><b><a href="#notes-regarding-parsing-lockfiles-4">4</a></b></sup>, v3<sup><b><a href="#notes-regarding-parsing-lockfiles-4">4</a></b></sup> | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/classic/default/yarn.lock#L2), [2.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/berry/v2/default/yarn.lock), [3.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/berry/v3/default/yarn.lock) |
| Poetry | v1 | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/python-poetry/default/poetry.lock) |
@@ -559,7 +561,7 @@ always take the latest dependency scanning artifact available.
To enable Dependency Scanning in a project, you can create a merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Dependency Scanning** row, select **Configure with a merge request**.
1. Review and merge the merge request to enable Dependency Scanning.
@@ -1019,62 +1021,7 @@ variables:
See explanations of the variables above in the [configuration section](#configuration).
-### Specific settings for languages and package managers
-
-See the following sections for configuring specific languages and package managers.
-
-#### Python (pip)
-
-If you need to install Python packages before the analyzer runs, you should use `pip install --user` in the `before_script` of the scanning job. The `--user` flag causes project dependencies to be installed in the user directory. If you do not pass the `--user` option, packages are installed globally, and they are not scanned and don't show up when listing project dependencies.
-
-#### Python (setuptools)
-
-If you need to install Python packages before the analyzer runs, you should use `python setup.py install --user` in the `before_script` of the scanning job. The `--user` flag causes project dependencies to be installed in the user directory. If you do not pass the `--user` option, packages are installed globally, and they are not scanned and don't show up when listing project dependencies.
-
-When using self-signed certificates for your private PyPi repository, no extra job configuration (aside
-from the template `.gitlab-ci.yml` above) is needed. However, you must update your `setup.py` to
-ensure that it can reach your private repository. Here is an example configuration:
-
-1. Update `setup.py` to create a `dependency_links` attribute pointing at your private repository for each
- dependency in the `install_requires` list:
-
- ```python
- install_requires=['pyparsing>=2.0.3'],
- dependency_links=['https://pypi.example.com/simple/pyparsing'],
- ```
-
-1. Fetch the certificate from your repository URL and add it to the project:
-
- ```shell
- printf "\n" | openssl s_client -connect pypi.example.com:443 -servername pypi.example.com | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > internal.crt
- ```
-
-1. Point `setup.py` at the newly downloaded certificate:
-
- ```python
- import setuptools.ssl_support
- setuptools.ssl_support.cert_paths = ['internal.crt']
- ```
-
-#### Python (Pipenv)
-
-If running in a limited network connectivity environment, you must configure the `PIPENV_PYPI_MIRROR`
-variable to use a private PyPi mirror. This mirror must contain both default and development dependencies.
-
-```yaml
-variables:
- PIPENV_PYPI_MIRROR: https://pypi.example.com/simple
-```
-
-<!-- markdownlint-disable MD044 -->
-Alternatively, if it's not possible to use a private registry, you can load the required packages
-into the Pipenv virtual environment cache. For this option, the project must check in the
-`Pipfile.lock` into the repository, and load both default and development packages into the cache.
-See the example [python-pipenv](https://gitlab.com/gitlab-org/security-products/tests/python-pipenv/-/blob/41cc017bd1ed302f6edebcfa3bc2922f428e07b6/.gitlab-ci.yml#L20-42)
-project for an example of how this can be done.
-<!-- markdownlint-enable MD044 -->
-
-## Hosting a copy of the `gemnasium_db` advisory database
+### Hosting a copy of the `gemnasium_db` advisory database
The [`gemnasium_db`](https://gitlab.com/gitlab-org/security-products/gemnasium-db) Git repository is
used by `gemnasium`, `gemnasium-maven`, and `gemnasium-python` as the source of vulnerability data.
@@ -1085,7 +1032,7 @@ one of the following:
- [Host a copy of the advisory database](#host-a-copy-of-the-advisory-database)
- [Use a local clone](#use-a-local-clone)
-### Host a copy of the advisory database
+#### Host a copy of the advisory database
If [gemnasium-db](https://gitlab.com/gitlab-org/security-products/gemnasium-db) is not reachable
from within the environment, the user can host their own Git copy. Then the analyzer can be
@@ -1098,7 +1045,7 @@ variables:
...
```
-### Use a local clone
+#### Use a local clone
If a hosted copy is not possible, then the user can clone [gemnasium-db](https://gitlab.com/gitlab-org/security-products/gemnasium-db)
or create an archive before the scan and point the analyzer to the directory (using:
@@ -1129,6 +1076,61 @@ variables:
GRADLE_CLI_OPTS: "-Dhttps.proxyHost=squid-proxy -Dhttps.proxyPort=3128 -Dhttp.proxyHost=squid-proxy -Dhttp.proxyPort=3128 -Dhttp.nonProxyHosts=localhost"
```
+## Specific settings for languages and package managers
+
+See the following sections for configuring specific languages and package managers.
+
+### Python (pip)
+
+If you need to install Python packages before the analyzer runs, you should use `pip install --user` in the `before_script` of the scanning job. The `--user` flag causes project dependencies to be installed in the user directory. If you do not pass the `--user` option, packages are installed globally, and they are not scanned and don't show up when listing project dependencies.
+
+### Python (setuptools)
+
+If you need to install Python packages before the analyzer runs, you should use `python setup.py install --user` in the `before_script` of the scanning job. The `--user` flag causes project dependencies to be installed in the user directory. If you do not pass the `--user` option, packages are installed globally, and they are not scanned and don't show up when listing project dependencies.
+
+When using self-signed certificates for your private PyPi repository, no extra job configuration (aside
+from the template `.gitlab-ci.yml` above) is needed. However, you must update your `setup.py` to
+ensure that it can reach your private repository. Here is an example configuration:
+
+1. Update `setup.py` to create a `dependency_links` attribute pointing at your private repository for each
+ dependency in the `install_requires` list:
+
+ ```python
+ install_requires=['pyparsing>=2.0.3'],
+ dependency_links=['https://pypi.example.com/simple/pyparsing'],
+ ```
+
+1. Fetch the certificate from your repository URL and add it to the project:
+
+ ```shell
+ printf "\n" | openssl s_client -connect pypi.example.com:443 -servername pypi.example.com | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > internal.crt
+ ```
+
+1. Point `setup.py` at the newly downloaded certificate:
+
+ ```python
+ import setuptools.ssl_support
+ setuptools.ssl_support.cert_paths = ['internal.crt']
+ ```
+
+### Python (Pipenv)
+
+If running in a limited network connectivity environment, you must configure the `PIPENV_PYPI_MIRROR`
+variable to use a private PyPi mirror. This mirror must contain both default and development dependencies.
+
+```yaml
+variables:
+ PIPENV_PYPI_MIRROR: https://pypi.example.com/simple
+```
+
+<!-- markdownlint-disable MD044 -->
+Alternatively, if it's not possible to use a private registry, you can load the required packages
+into the Pipenv virtual environment cache. For this option, the project must check in the
+`Pipfile.lock` into the repository, and load both default and development packages into the cache.
+See the example [python-pipenv](https://gitlab.com/gitlab-org/security-products/tests/python-pipenv/-/blob/41cc017bd1ed302f6edebcfa3bc2922f428e07b6/.gitlab-ci.yml#L20-42)
+project for an example of how this can be done.
+<!-- markdownlint-enable MD044 -->
+
## Warnings
We recommend that you use the most recent version of all containers, and the most recent supported version of all package managers and languages. Using previous versions carries an increased security risk because unsupported versions may no longer benefit from active security reporting and backporting of security fixes.
diff --git a/doc/user/application_security/gitlab_advisory_database/index.md b/doc/user/application_security/gitlab_advisory_database/index.md
new file mode 100644
index 00000000000..e59eaccf8f8
--- /dev/null
+++ b/doc/user/application_security/gitlab_advisory_database/index.md
@@ -0,0 +1,95 @@
+---
+stage: Secure
+group: Vulnerability Research
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# GitLab Advisory Database
+
+The [GitLab Advisory Database](https://gitlab.com/gitlab-org/security-products/gemnasium-db) serves as a repository for security advisories related to software dependencies.
+
+The database is an essential component of both [Dependency Scanning](../dependency_scanning/index.md) and [Container Scanning](../container_scanning/index.md).
+
+A free and open-source version of the GitLab Advisory Database is also available as [GitLab Advisory Database (Open Source Edition)](https://gitlab.com/gitlab-org/advisories-community). However, there is a 30-day delay in updates.
+
+## Standardization
+
+In our advisories, we adopt standardized practices to effectively communicate vulnerabilities and their impact.
+
+- [CVE](../terminology/index.md#cve)
+- [CVSS](../terminology/index.md#cvss)
+- [CWE](../terminology/index.md#cwe)
+
+## Explore the database
+
+To view the database content, go to the [GitLab Advisory Database](https://advisories.gitlab.com) home page. On the home page you can:
+
+- Search the database, by identifier, package name, and description.
+- View advisories that were added recently.
+- View statistical information, including coverage and update frequency.
+
+### Search
+
+Each advisory has a page with the following details:
+
+- **Identifiers**: Public identifiers. For example, CVE ID, GHSA ID, or the GitLab internal ID (`GMS-<year>-<nr>`).
+- **Package Slug**: Package type and package name separated by a slash.
+- **Vulnerability**: A short description of the security flaw.
+- **Description**: A detailed description of the security flaw and potential risks.
+- **Affected Versions**: The affected versions.
+- **Solution**: How to remediate the vulnerability.
+- **Last Modified**: The date when the advisory was last modified.
+
+### Statistics
+
+The home page also offers a [statistic section](https://advisories.gitlab.com/stats/index.html) that provides valuable insights into advisory distribution, the origins of vulnerabilities, dependency scanning coverage, and timelines for vulnerability resolution.
+
+## Open Source Edition
+
+GitLab provides a free and open-source version of the database, the [GitLab Advisory Database (Open Source Edition)](https://gitlab.com/gitlab-org/advisories-community).
+
+The open-source version is a time-delayed clone of the GitLab Advisory Database, MIT-licensed and contains all advisories from the GitLab Advisory Database that are older than 30 days or with the `community-sync` flag.
+
+## Integrations
+
+- [Dependency Scanning](../dependency_scanning/index.md)
+- [Container Scanning](../container_scanning/index.md)
+- Third-party tools
+
+NOTE:
+GitLab Advisory Database Terms prohibit the use of data contained in the GitLab Advisory Database by third-party tools. Third-party integrators can use the MIT-licensed, time-delayed [repository clone](https://gitlab.com/gitlab-org/advisories-community) instead.
+
+### How the database can be used
+
+As an example, we highlight the use of the database as a source for an Advisory Ingestion process as part of Continuous Vulnerability Scans.
+
+```mermaid
+flowchart TB
+ subgraph Dependency Scanning
+ A[GitLab Advisory Database]
+ end
+ subgraph Container Scanning
+ C[GitLab Advisory Database \n Open Source Edition \n integrated into Trivy]
+ end
+ A --> B{Ingest}
+ C --> B
+ B --> |store| D{{"Cloud Storage \n (NDJSON format)"}}
+ F[\GitLab Instance/] --> |pulls data| D
+ F --> |stores| G[(Relational Database)]
+```
+
+## Maintenance
+
+The [Vulnerability Research](https://about.gitlab.com/handbook/engineering/development/sec/secure/vulnerability-research/) team is responsible for the maintenance and regular updates of the GitLab Advisory Database and the GitLab Advisory Database (Open Source Edition).
+
+Community contributions are accessible in [advisories-community](https://gitlab.com/gitlab-org/advisories-community) via the `community-sync` flag.
+
+## Contributing to the vulnerability database
+
+If you know about a vulnerability that is not listed, you can contribute to the GitLab Advisory Database by either opening an issue or submit the vulnerability.
+
+For more information, see [Contribution Guidelines](https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/blob/master/CONTRIBUTING.md).
+
+## License
+
+The GitLab Advisory Database is freely accessible in accordance with the [GitLab Advisory Database Terms](https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/blob/master/LICENSE.md#gitlab-advisory-database-term).
diff --git a/doc/user/application_security/iac_scanning/index.md b/doc/user/application_security/iac_scanning/index.md
index 334e8c28378..8cdeeb92e09 100644
--- a/doc/user/application_security/iac_scanning/index.md
+++ b/doc/user/application_security/iac_scanning/index.md
@@ -121,7 +121,7 @@ The **Configure with a merge request** button been temporarily disabled due to a
To enable IaC Scanning in a project, you can create a merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Infrastructure as Code (IaC) Scanning** row, select **Configure with a merge request**.
1. Review and merge the merge request to enable IaC Scanning.
@@ -130,7 +130,7 @@ Pipelines now include an IaC Scanning job.
## Customize rulesets **(ULTIMATE ALL)**
-> [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) support for overriding rules in GitLab 14.8.
+> Support for overriding rules [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) in GitLab 14.8.
You can customize the default IaC Scanning rules provided with GitLab.
diff --git a/doc/user/application_security/img/security_widget_v13_7.png b/doc/user/application_security/img/security_widget_v13_7.png
deleted file mode 100644
index fb1eaf9a2be..00000000000
--- a/doc/user/application_security/img/security_widget_v13_7.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/img/security_widget_v16_4.png b/doc/user/application_security/img/security_widget_v16_4.png
new file mode 100644
index 00000000000..dfed372ba31
--- /dev/null
+++ b/doc/user/application_security/img/security_widget_v16_4.png
Binary files differ
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index 615ff7e3fda..62155e07fbc 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -103,7 +103,7 @@ The following vulnerability scanners and their databases are regularly updated:
|:----------------------------------------------------------------|:---------------------------------|
| [Container Scanning](container_scanning/index.md) | A job runs on a daily basis to build new images with the latest vulnerability database updates from the upstream scanner. GitLab monitors this job through an internal alert that tells the engineering team when the database becomes more than 48 hours old. For more information, see the [Vulnerabilities database update](container_scanning/index.md#vulnerabilities-database). |
| [Dependency Scanning](dependency_scanning/index.md) | Relies on the [GitLab Advisory Database](https://gitlab.com/gitlab-org/security-products/gemnasium-db). It is updated on a daily basis using [data from NVD, the `ruby-advisory-db` and the GitHub Advisory Database as data sources](https://gitlab.com/gitlab-org/security-products/gemnasium-db/-/blob/master/SOURCES.md). See our [current measurement of time from CVE being issued to our product being updated](https://about.gitlab.com/handbook/engineering/development/performance-indicators/#cve-issue-to-update). |
-| [Dynamic Application Security Testing (DAST)](dast/index.md) | The scanning engine is updated on a periodic basis. See the [version of the underlying tool `zaproxy`](https://gitlab.com/gitlab-org/security-products/dast/blob/main/Dockerfile#L1). The scanning rules are downloaded at scan runtime. |
+| [Dynamic Application Security Testing (DAST)](dast/index.md) | [DAST proxy-based](dast/proxy-based.md) and [browser-based](dast/browser_based.md) engines are updated on a periodic basis. [DAST proxy-based](dast/proxy-based.md) analyzer downloads the scanning rules at scan runtime. See the [version of the underlying tool `zaproxy`](https://gitlab.com/gitlab-org/security-products/dast/blob/main/Dockerfile#L27). [DAST browser-based](dast/browser_based.md) rules run [different vulnerability checks](dast/checks/index.md). |
| [Secret Detection](secret_detection/index.md#detected-secrets) | GitLab maintains the [detection rules](secret_detection/index.md#detected-secrets) and [accepts community contributions](secret_detection/index.md#adding-new-patterns). The scanning engine is updated at least once per month if a relevant update is available. |
| [Static Application Security Testing (SAST)](sast/index.md) | The source of scan rules depends on which [analyzer](sast/analyzers.md) is used for each [supported programming language](sast/index.md#supported-languages-and-frameworks). GitLab maintains a ruleset for the Semgrep-based analyzer and updates it regularly based on internal research and user feedback. For other analyzers, the ruleset is sourced from the upstream open-source scanner. Each analyzer is updated at least once per month if a relevant update is available. |
@@ -223,20 +223,30 @@ We do not recommend changing the job [`allow_failure` setting](../../ci/yaml/ind
The artifact generated by the secure analyzer contains all findings it discovers on the target branch, regardless of whether they were previously found, dismissed, or completely new (it puts in everything that it finds).
-## View security scan information in merge requests **(FREE ALL)**
+## View security scan information
+
+Security scan information appears in multiple locations and formats:
+
+- Merge request
+- Pipeline security tab
+- Security dashboard
+- Vulnerability report
+- GitLab Workflow extension for VS Code
+
+### Merge request **(FREE ALL)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4393) in GitLab Free 13.5.
> - Made [available in all tiers](https://gitlab.com/gitlab-org/gitlab/-/issues/273205) in 13.6.
> - Report download dropdown list [added](https://gitlab.com/gitlab-org/gitlab/-/issues/273418) in 13.7.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/249550) in GitLab 13.9.
-### All tiers
+#### All tiers
Merge requests which have run security scans let you know that the generated
reports are available to download. To download a report, select
**Download results**, and select the desired report.
-![Security widget](img/security_widget_v13_7.png)
+![Security widget](img/security_widget_v16_4.png)
Security scans produce at least one of these [CI `artifacts:reports` types](../../ci/yaml/artifacts_reports.md):
@@ -248,7 +258,9 @@ Security scans produce at least one of these [CI `artifacts:reports` types](../.
- `artifacts:reports:sast`
- `artifacts:reports:secret_detection`
-### Ultimate
+In the Free tier, the reports above aren't parsed by GitLab. As a result, the widget does not change based on the results of the security scans.
+
+#### Ultimate
A merge request contains a security widget which displays a summary of the _new_ results. New results are determined by comparing the findings of the merge request against the findings of the most recent completed pipeline (`success`, `failed`, `canceled` or `skipped`) for the commit when the feature branch was created from the target branch.
@@ -263,26 +275,32 @@ findings, select **View full report** to go directly to the **Security** tab in
![Security scanning results in a merge request](img/mr_security_scanning_results_v14_3.png)
-## View security scan information in the pipeline Security tab
+### Pipeline security tab
A pipeline's security tab lists all findings in the current branch. It includes new findings introduced by this branch
and existing vulnerabilities already present when you created the branch. These results likely do not match the findings
displayed in the Merge Request security widget, as those do not include the existing vulnerabilities. Refer to [View vulnerabilities in a pipeline](vulnerability_report/pipeline.md) for more information.
-## View security scan information in the Security Dashboard
+### Security dashboard
-The Security Dashboard show vulnerabilities present in a project's default branch. Data is updated every 24 hours. Vulnerability count updates resulting from any feature branches introducing new vulnerabilities that are merged to default are included after the daily data refresh.
+The security dashboard shows the vulnerabilities on a project's default branch. Data is updated every 24 hours. Vulnerability count updates resulting from any feature branches introducing new vulnerabilities that are merged to default are included after the daily data refresh.
For more details, see [Security Dashboard](security_dashboard/index.md).
-## View security scan information in the Vulnerability Report
+### Vulnerability report
-The vulnerability report shows the results of the last completed pipeline on the default branch. It is updated on every pipeline completion. All detected vulnerabilities are shown as well as any previous ones that are no longer detected in the latest scan. Vulnerabilities that are no longer detected may have been remediated or otherwise removed and can be marked as `Resolved` after proper verification. Vulnerabilities that are no longer detected are denoted with an icon for filtering and review.
+The vulnerability report shows the results of the last completed pipeline on the default branch. It is updated on every pipeline completion. All detected vulnerabilities are shown and any previous ones that are no longer detected in the latest scan. Vulnerabilities that are no longer detected may have been remediated or otherwise removed and can be marked as `Resolved` after proper verification. Vulnerabilities that are no longer detected are denoted with an icon for filtering and review.
By default, the vulnerability report does not show vulnerabilities of `dismissed` or `resolved` status so you can focus on open vulnerabilities. You can change the Status filter to see these.
[Read more about the Vulnerability report](vulnerability_report/index.md).
+### GitLab Workflow extension for VS Code
+
+You can now see security findings directly in Visual Studio Code (VS Code) using [GitLab Workflow VS Code extension](../../editor_extensions/visual_studio_code/index.md), just as you would in a merge request.
+
+For more details, see [extension page](https://marketplace.visualstudio.com/items?itemName=gitlab.gitlab-workflow#security-findings).
+
## Security approvals in merge requests
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9928) in GitLab 12.2.
@@ -453,7 +471,7 @@ You can always find supported and deprecated schema versions in the [source code
You can interact with the results of the security scanning tools in several locations:
-- [Scan information in merge requests](#view-security-scan-information-in-merge-requests)
+- [Scan information in merge requests](#merge-request)
- [Project Security Dashboard](security_dashboard/index.md#view-vulnerabilities-over-time-for-a-project)
- [Security pipeline tab](security_dashboard/index.md)
- [Group Security Dashboard](security_dashboard/index.md#view-vulnerabilities-over-time-for-a-group)
@@ -526,7 +544,7 @@ Additional details about the differences between the two solutions are outlined
| **Flexibility** | Supports anything that can be done in a CI file. | Limited to only the items for which GitLab has explicitly added support. DAST, SAST, SAST IaC, Secret Detection, Dependency Scanning, and Container Scanning scans are supported. |
| **Usability** | Requires knowledge of CI YAML. | Follows a `rules` and `actions`-based YAML structure. |
| **Inclusion in CI pipeline** | The compliance pipeline is executed instead of the project's `.gitlab-ci.yml` file. To include the project's `.gitlab-ci.yml` file, use an `include` statement. Defined variables aren't allowed to be overwritten by the included project's YAML file. | Forced inclusion of a new job into the CI pipeline. DAST jobs that must be customized on a per-project basis can have project-level Site Profiles and Scan Profiles defined. To ensure separation of duties, these profiles are immutable when referenced in a scan execution policy. All jobs can be customized as part of the security policy itself with the same variables that are usually available to the CI job. |
-| **Schedulable** | Can be scheduled through a scheduled pipeline on the group. | Can be scheduled natively through the policy configuration itself. |
+| **Schedulable** | Has to be scheduled through a scheduled pipeline on each project. | Can be scheduled natively through the policy configuration itself. |
| **Separation of Duties** | Only group owners can create compliance framework labels. Only project owners can apply compliance framework labels to projects. The ability to make or approve changes to the compliance pipeline definition is limited to individuals who are explicitly given access to the project that contains the compliance pipeline. | Only project owners can define a linked security policy project. The ability to make or approve changes to security policies is limited to individuals who are explicitly given access to the security policy project. |
| **Ability to apply one standard to multiple projects** | The same compliance framework label can be applied to multiple projects inside a group. | The same security policy project can be used for multiple projects across GitLab with no requirement of being located in the same group. |
@@ -721,8 +739,8 @@ Instructions are available in the [legacy template project](https://gitlab.com/g
In these circumstances, that the job succeeds is the default behavior. The job's status indicates
success or failure of the analyzer itself. Analyzer results are displayed in the
[job logs](../../ci/jobs/index.md#expand-and-collapse-job-log-sections),
-[Merge Request widget](#view-security-scan-information-in-merge-requests) or
-[Security Dashboard](security_dashboard/index.md).
+[merge request widget](#merge-request), or
+[security dashboard](security_dashboard/index.md).
### Error: job `is used for configuration only, and its script should not be executed`
diff --git a/doc/user/application_security/policies/index.md b/doc/user/application_security/policies/index.md
index 25e2f523f08..84c28d4008c 100644
--- a/doc/user/application_security/policies/index.md
+++ b/doc/user/application_security/policies/index.md
@@ -58,7 +58,7 @@ to select, edit, and unlink a security policy project.
As a project owner, take the following steps to create or edit an association between your current
project and a project that you would like to designate as the security policy project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Policies**.
1. Select **Edit Policy Project**, and search for and select the
project you would like to link from the dropdown list.
@@ -82,7 +82,7 @@ policies for all available environments. You can check a
policy's information (for example, description or enforcement
status), and create and edit deployed policies:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Policies**.
![Policies List Page](img/policies_list_v15_1.png)
@@ -93,7 +93,7 @@ status), and create and edit deployed policies:
You can use the policy editor to create, edit, and delete policies:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Policies**.
- To create a new policy, select **New policy** which is located in the **Policies** page's header.
You can then select which type of policy to create.
@@ -142,12 +142,13 @@ The workaround is to amend your group or instance push rules to allow branches f
### Troubleshooting common issues configuring security policies
- Confirm that scanners are properly configured and producing results for the latest branch. Security Policies are designed to require approval when there are no results (no security report), as this ensures that no vulnerabilities are introduced. We cannot know if there are any vulnerabilities unless the scans enforced by the policy complete successfully and are evaluated.
+- For scan result policies, we require artifacts for each scanner defined in the policy for both the source and target branch. To ensure scan result policies capture the necessary results, confirm your scan execution is properly implemented and enforced. If using scan execution policies, enforcing on `all branches` often address this need.
- When running scan execution policies based on a SAST action, ensure target repositories contain proper code files. SAST runs different analyzers [based on the types of files in the repo](../sast/index.md#supported-languages-and-frameworks), and if no supported files are found it will not run any jobs. See the [SAST CI template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml) for more details.
-- Check for any branch configuration conflicts. If your policy is configured to enforce rules on `main` but some projects within the scope are using `master` as their default branch, the policy is not applied for the latter. Support for specifying the `default` branch in your policies is proposed in [epic 9468](https://gitlab.com/groups/gitlab-org/-/epics/9468).
+- Check for any branch configuration conflicts. If your policy is configured to enforce rules on `main` but some projects within the scope are using `master` as their default branch, the policy is not applied for the latter. You can define policies to enforce rules generically on `default` branches regardless of the name used in the project or on `all protected branches` to address this issue.
- Scan result policies created at the group or sub-group level can take some time to apply to all the merge requests in the group.
- Scheduled scan execution policies run with a minimum 15 minute cadence. Learn more [about the schedule rule type](../policies/scan-execution-policies.md#schedule-rule-type).
- When scheduling pipelines, keep in mind that CRON scheduling is based on UTC on GitLab SaaS and is based on your server time for self managed instances. When testing new policies, it may appear pipelines are not running properly when in fact they are scheduled in your server's timezone.
-- When enforcing scan execution policies, security policies creates a bot in the target project that will trigger scheduled pipelines to ensure enforcement. If the bot is
+- When enforcing scan execution policies, security policies creates a bot in the target project that will trigger scheduled pipelines to ensure enforcement. If the bot is
deleted or missing, the target project's pipeline will not be executed. To recreate a security policy bot user unlink and link the security policy project again.
- You should not link a security policy project to a development project and to the group or sub-group the development project belongs to at the same time. Linking this way will result in approval rules from the Scan Result Policy not being applied to merge requests in the development project.
- When creating a Scan Result Policy, neither the array `severity_levels` nor the array `vulnerability_states` in the [scan_finding rule](../policies/scan-result-policies.md#scan_finding-rule-type) can be left empty; for a working rule, at least one entry must exist.
diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md
index 834a50f39ef..ac15dfc0a47 100644
--- a/doc/user/application_security/policies/scan-execution-policies.md
+++ b/doc/user/application_security/policies/scan-execution-policies.md
@@ -97,7 +97,12 @@ the following sections and tables provide an alternative.
## `pipeline` rule type
> - The `branch_type` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404774) in GitLab 16.1 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_type`. Disabled by default.
-> - The `branch_type` field was [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/413062) in GitLab 16.2.
+> - Generally available in GitLab 16.2. Feature flag `security_policies_branch_type` removed.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Enabled by default.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is available.
This rule enforces the defined actions whenever the pipeline runs for a selected branch.
@@ -106,33 +111,35 @@ This rule enforces the defined actions whenever the pipeline runs for a selected
| `type` | `string` | true | `pipeline` | The rule's type. |
| `branches` <sup>1</sup> | `array` of `string` | true if `branch_type` field does not exist | `*` or the branch's name | The branch the given policy applies to (supports wildcard). |
| `branch_type` <sup>1</sup> | `string` | true if `branches` field does not exist | `default`, `protected` or `all` | The types of branches the given policy applies to. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
1. You must specify only one of `branches` or `branch_type`.
## `schedule` rule type
> - The `branch_type` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404774) in GitLab 16.1 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_type`. Disabled by default.
-> - The `branch_type` field was [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/413062) in GitLab 16.2.
-> - The security policy bot users were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/394958) in GitLab 16.3 [with flags](../../../administration/feature_flags.md) named `scan_execution_group_bot_users` and `scan_execution_bot_users`. Enabled by default.
+> - Generally available in GitLab 16.2. Feature flag `security_policies_branch_type` removed.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Enabled by default.
FLAG:
-On self-managed GitLab, security policy bot users are available. To hide the feature, an administrator can [disable the feature flags](../../../administration/feature_flags.md) named `scan_execution_group_bot_users` and `scan_execution_bot_users`.
+On self-managed GitLab, by default the `branch_exceptions` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
On GitLab.com, this feature is available.
-This rule enforces the defined actions and schedules a scan on the provided date/time.
+This rule schedules a scan pipeline, enforcing the defined actions on the schedule defined in the `cadence` field. A scheduled pipeline does not run other jobs defined in the project's `.gitlab-ci.yml` file. When a project is linked to a security policy project, a security policy bot is created in the project and will become the author of any scheduled pipelines.
| Field | Type | Required | Possible values | Description |
|------------|------|----------|-----------------|-------------|
| `type` | `string` | true | `schedule` | The rule's type. |
| `branches` <sup>1</sup> | `array` of `string` | true if either `branch_type` or `agents` fields does not exist | `*` or the branch's name | The branch the given policy applies to (supports wildcard). |
| `branch_type` <sup>1</sup> | `string` | true if either `branches` or `agents` fields does not exist | `default`, `protected` or `all` | The types of branches the given policy applies to. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `cadence` | `string` | true | CRON expression (for example, `0 0 * * *`) | A whitespace-separated string containing five fields that represents the scheduled time. Minimum of 15 minute intervals when used together with the `branches` field. |
| `timezone` | `string` | false | Time zone identifier (for example, `America/New_York`) | Time zone to apply to the cadence. Value must be an IANA Time Zone Database identifier. |
| `agents` <sup>1</sup> | `object` | true if either `branch_type` or `branches` fields do not exists | | The name of the [GitLab agents](../../clusters/agent/index.md) where [Operational Container Scanning](../../clusters/agent/vulnerabilities.md) runs. The object key is the name of the Kubernetes agent configured for your project in GitLab. |
1. You must specify only one of `branches`, `branch_type`, or `agents`.
-Scheduled scan pipelines are triggered by a security policy bot user that is a guest member of the project. Security policy bot users are automatically created when the security policy project is linked, and removed when the security policy project is unlinked.
+Scheduled scan pipelines are triggered by a security policy bot user that is a guest member of the project with elevated permissions for users of type `security_policy_bot` so it may carry out this task. Security policy bot users are automatically created when the security policy project is linked, and removed when the security policy project is unlinked.
If the project does not have a security policy bot user, the scheduled scan pipeline will not be triggered. To recreate a security policy bot user unlink and link the security policy project again.
@@ -214,11 +221,12 @@ Note the following:
is not scheduled successfully.
- For a secret detection scan, only rules with the default ruleset are supported. [Custom rulesets](../secret_detection/index.md#custom-rulesets)
are not supported.
-- A secret detection scan runs in `normal` mode when executed as part of a pipeline, and in
+- A secret detection scan runs in `default` mode when executed as part of a pipeline, and in
[`historic`](../secret_detection/index.md#full-history-secret-detection)
mode when executed as part of a scheduled scan.
- A container scanning scan that is configured for the `pipeline` rule type ignores the agent defined in the `agents` object. The `agents` object is only considered for `schedule` rule types.
An agent with a name provided in the `agents` object must be created and configured for the project.
+- Variables defined in a Scan Execution Policy follow the standard [CI/CD variable precedence](../../../ci/variables/index.md#cicd-variable-precedence).
## Example security policies project
diff --git a/doc/user/application_security/policies/scan-result-policies.md b/doc/user/application_security/policies/scan-result-policies.md
index c5cfd63641b..a42b3f02c26 100644
--- a/doc/user/application_security/policies/scan-result-policies.md
+++ b/doc/user/application_security/policies/scan-result-policies.md
@@ -84,23 +84,36 @@ the following sections and tables provide an alternative.
## Scan result policy schema
+> The `approval_settings` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418752) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `scan_result_policy_settings`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `scan_result_policy_settings`.
+On GitLab.com, this feature is not available.
+
| Field | Type | Required |Possible values | Description |
|-------|------|----------|----------------|-------------|
| `name` | `string` | true | | Name of the policy. Maximum of 255 characters.|
| `description` (optional) | `string` | true | | Description of the policy. |
| `enabled` | `boolean` | true | `true`, `false` | Flag to enable (`true`) or disable (`false`) the policy. |
| `rules` | `array` of rules | true | | List of rules that the policy applies. |
-| `actions` | `array` of actions | true | | List of actions that the policy enforces. |
+| `actions` | `array` of actions | false| | List of actions that the policy enforces. |
+| `approval_settings` | `object` | false | `{prevent_approval_by_author: boolean, prevent_approval_by_commit_author: boolean, remove_approvals_with_new_commit: boolean, require_password_to_approve: boolean}` | Project settings that the policy overrides. |
## `scan_finding` rule type
> - The scan result policy field `vulnerability_attributes` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123052) in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `enforce_vulnerability_attributes_rules`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/418784) in GitLab 16.3.
> - The scan result policy field `vulnerability_age` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123956) in GitLab 16.2.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Enabled by default.
FLAG:
On self-managed GitLab, by default the `vulnerability_attributes` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `enforce_vulnerability_attributes_rules`.
On GitLab.com, this feature is available.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is available.
+
This rule enforces the defined actions based on security scan findings.
| Field | Type | Required | Possible values | Description |
@@ -108,6 +121,7 @@ This rule enforces the defined actions based on security scan findings.
| `type` | `string` | true | `scan_finding` | The rule's type. |
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of branches the given policy applies to. Cannot be used with the `branches` field. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `scanners` | `array` of `string` | true | `sast`, `secret_detection`, `dependency_scanning`, `container_scanning`, `dast`, `coverage_fuzzing`, `api_fuzzing` | The security scanners for this rule to consider. `sast` includes results from both SAST and SAST IaC scanners. |
| `vulnerabilities_allowed` | `integer` | true | Greater than or equal to zero | Number of vulnerabilities allowed before this rule is considered. |
| `severity_levels` | `array` of `string` | true | `info`, `unknown`, `low`, `medium`, `high`, `critical` | The severity levels for this rule to consider. |
@@ -119,6 +133,11 @@ This rule enforces the defined actions based on security scan findings.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `license_scanning_policies`.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/397644) in GitLab 15.11. Feature flag `license_scanning_policies` removed.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Enabled by default.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is available.
This rule enforces the defined actions based on license findings.
@@ -127,10 +146,30 @@ This rule enforces the defined actions based on license findings.
| `type` | `string` | true | `license_finding` | The rule's type. |
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of branches the given policy applies to. Cannot be used with the `branches` field. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `match_on_inclusion` | `boolean` | true | `true`, `false` | Whether the rule matches inclusion or exclusion of licenses listed in `license_types`. |
| `license_types` | `array` of `string` | true | license types | [SPDX license names](https://spdx.org/licenses) to match on, for example `Affero General Public License v1.0` or `MIT License`. |
| `license_states` | `array` of `string` | true | `newly_detected`, `detected` | Whether to match newly detected and/or previously detected licenses. The `newly_detected` state triggers approval when either a new package is introduced or when a new license for an existing package is detected. |
+## `any_merge_request` rule type
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418752) in GitLab 16.4.
+> - The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Enabled by default.
+
+FLAG:
+On self-managed GitLab, by default the `branch_exceptions` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`.
+On GitLab.com, this feature is available.
+
+This rule enforces the defined actions for any merge request based on the commits signature.
+
+| Field | Type | Required | Possible values | Description |
+|---------------|---------------------|--------------------------------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `type` | `string` | true | `any_merge_request` | The rule's type. |
+| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
+| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of branches the given policy applies to. Cannot be used with the `branches` field. |
+| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
+| `commits` | `string` | true | `any`, `unsigned` | Whether the rule matches for any commits, or only if unsigned commits are detected in the merge request. |
+
## `require_approval` action type
This action sets an approval rule to be required when conditions are met for at least one rule in
diff --git a/doc/user/application_security/sast/analyzers.md b/doc/user/application_security/sast/analyzers.md
index 832ad100701..f896616d537 100644
--- a/doc/user/application_security/sast/analyzers.md
+++ b/doc/user/application_security/sast/analyzers.md
@@ -64,7 +64,7 @@ content directly. Instead, it enhances the results with additional properties, i
- CWEs.
- Location tracking fields.
-- A means of identifying false positives or insignificant findings. **(ULTIMATE)**
+- A means of identifying false positives or insignificant findings. **(ULTIMATE ALL)**
## Transition to Semgrep-based scanning
diff --git a/doc/user/application_security/sast/customize_rulesets.md b/doc/user/application_security/sast/customize_rulesets.md
index 4ae8f1c4f8b..90731114303 100644
--- a/doc/user/application_security/sast/customize_rulesets.md
+++ b/doc/user/application_security/sast/customize_rulesets.md
@@ -7,10 +7,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Customize rulesets **(ULTIMATE ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235382) in GitLab 13.5.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/339614) support for
+> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/339614) support for
> passthrough chains. Expanded to include additional passthrough types of `file`, `git`, and `url` in GitLab 14.6.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) support for overriding rules in GitLab 14.8.
-> - [Added](https://gitlab.com/gitlab-org/security-products/analyzers/ruleset/-/merge_requests/18) support for specifying ambiguous passthrough refs in GitLab 16.2.
+> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) support for overriding rules in GitLab 14.8.
+> - [Enabled](https://gitlab.com/gitlab-org/security-products/analyzers/ruleset/-/merge_requests/18) support for specifying ambiguous passthrough refs in GitLab 16.2.
You can customize the behavior of our SAST analyzers by [defining a ruleset configuration file](#create-the-configuration-file) in the
repository being scanned. There are two kinds of customization:
@@ -29,8 +29,8 @@ You can disable predefined rules for any SAST analyzer.
When you disable a rule:
- Most analyzers still scan for the vulnerability. The results are removed as a processing step after the scan completes, and they don't appear in the [`gl-sast-report.json` artifact](index.md#reports-json-format).
-- Findings for the disabled rule no longer appear in the [Pipeline Security tab](../index.md#view-security-scan-information-in-the-pipeline-security-tab).
-- Existing findings for the disabled rule on the default branch are marked ["No longer detected"](../vulnerability_report/index.md#activity-filter) in the [Vulnerability Report](../index.md#view-security-scan-information-in-the-vulnerability-report).
+- Findings for the disabled rule no longer appear in the [pipeline security tab](../index.md#pipeline-security-tab).
+- Existing findings for the disabled rule on the default branch are marked as [`No longer detected`](../vulnerability_report/index.md#activity-filter) in the [vulnerability report](../index.md#vulnerability-report).
The Semgrep-based analyzer handles disabled rules differently:
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 717608274e5..acc7e9d9e84 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -55,21 +55,16 @@ For more information about our plans for language support in SAST, see the [cate
| Language / framework | [Analyzer](analyzers.md) used for scanning | Minimum supported GitLab version |
|------------------------------|--------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
-| .NET Core<sup>3</sup> | [Security Code Scan](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) | 11.0 |
-| .NET Framework<sup>3</sup> | [Security Code Scan](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) | 13.0 |
| .NET (all versions, C# only) | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 15.4 |
| Apex (Salesforce) | [PMD](https://gitlab.com/gitlab-org/security-products/analyzers/pmd-apex) | 12.1 |
| C | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 14.2 |
| C/C++ | [Flawfinder](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder) | 10.7 |
| Elixir (Phoenix) | [Sobelow](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow) | 11.1 |
-| Go<sup>2</sup> | [Gosec](https://gitlab.com/gitlab-org/security-products/analyzers/gosec) | 10.7 |
| Go | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 14.4 |
| Groovy<sup>1</sup> | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 11.3 (Gradle) & 11.9 (Maven, SBT) |
| Helm Charts | [Kubesec](https://gitlab.com/gitlab-org/security-products/analyzers/kubesec) | 13.1 |
| Java (any build system) | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 14.10 |
-| Java<sup>1, 2</sup> | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 10.6 (Maven), 10.8 (Gradle) & 11.9 (SBT) |
| Java (Android) | [MobSF (beta)](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) | 13.5 |
-| JavaScript<sup>2</sup> | [ESLint security plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 11.8 |
| JavaScript | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 13.10 |
| Kotlin (Android) | [MobSF (beta)](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) | 13.5 |
| Kotlin (General)<sup>1</sup> | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 13.11 |
@@ -77,24 +72,34 @@ For more information about our plans for language support in SAST, see the [cate
| Node.js | [NodeJsScan](https://gitlab.com/gitlab-org/security-products/analyzers/nodejs-scan) | 11.1 |
| Objective-C (iOS) | [MobSF (beta)](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) | 13.5 |
| PHP | [phpcs-security-audit](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit) | 10.8 |
-| Python<sup>2</sup> | [bandit](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) | 10.3 |
| Python | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 13.9 |
-| React<sup>2</sup> | [ESLint react plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 12.5 |
| React | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 13.10 |
| Ruby | [brakeman](https://gitlab.com/gitlab-org/security-products/analyzers/brakeman) | 13.9 |
| Ruby on Rails | [brakeman](https://gitlab.com/gitlab-org/security-products/analyzers/brakeman) | 10.3 |
| Scala (any build system) | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 16.0 |
| Scala<sup>1</sup> | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 11.0 (SBT) & 11.9 (Gradle, Maven) |
| Swift (iOS) | [MobSF (beta)](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) | 13.5 |
-| TypeScript<sup>2</sup> | [ESLint security plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 11.9, [merged](https://gitlab.com/gitlab-org/gitlab/-/issues/36059) with ESLint in 13.2 |
| TypeScript | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with [GitLab-managed rules](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/RULES.md) | 13.10 |
1. The SpotBugs-based analyzer supports [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/), and [SBT](https://www.scala-sbt.org/). It can also be used with variants like the
[Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html),
[Grails](https://grails.org/),
and the [Maven wrapper](https://github.com/takari/maven-wrapper). However, SpotBugs has [limitations](https://gitlab.com/gitlab-org/gitlab/-/issues/350801) when used against [Ant](https://ant.apache.org/)-based projects. We recommend using the Semgrep-based analyzer for Ant-based Java or Scala projects.
-1. These analyzers reached [End of Support](https://about.gitlab.com/handbook/product/gitlab-the-product/#end-of-support) status [in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/352554).
-1. Security Code Scan reached [End of Support](https://about.gitlab.com/handbook/product/gitlab-the-product/#end-of-support) status [in GitLab 16.0](https://gitlab.com/gitlab-org/gitlab/-/issues/390416).
+
+## End of supported analyzers
+
+GitLab has reached [End of Support](https://about.gitlab.com/handbook/product/gitlab-the-product/#end-of-support) for the below analyzers. These analyzers have been replaced by the Semgrep-based analyzer.
+
+| Language / framework | [Analyzer](analyzers.md) used for scanning | Minimum supported GitLab version | End Of Support GitLab version |
+|------------------------------|--------------------------------------------------------------------------------------------------------------| --------------------------------- | ------------------------------------------------------------- |
+| .NET Core | [Security Code Scan](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) | 11.0 | [16.0](https://gitlab.com/gitlab-org/gitlab/-/issues/390416) |
+| .NET Framework | [Security Code Scan](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) | 13.0 | [16.0](https://gitlab.com/gitlab-org/gitlab/-/issues/390416) |
+| Go | [Gosec](https://gitlab.com/gitlab-org/security-products/analyzers/gosec) | 10.7 | [15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/352554) |
+| Java | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 10.6 (Maven), 10.8 (Gradle) & 11.9 (SBT) | [15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/352554) |
+| Python | [bandit](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) | 10.3 | [15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/352554) |
+| React | [ESLint react plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 12.5 | [15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/352554) |
+| JavaScript | [ESLint security plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 11.8 | [15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/352554) |
+| TypeScript | [ESLint security plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 11.9, with ESLint in 13.2 | [15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/352554) |
## Multi-project support
@@ -151,8 +156,9 @@ Advanced vulnerability tracking is available in a subset of the [supported langu
- C++, in the Flawfinder analyzer only
- C#, in the Semgrep-based analyzer only
- Go, in the Semgrep-based analyzer only
-- Java, in the Semgrep-based and mobsf analyzers
+- Java, in the mobsf, Semgrep-based and SpotBugs analyzers
- JavaScript, in the Semgrep-based and NodeJS-Scan analyzers
+- PHP, in the phpcs-security-audit analyzer
- Python, in the Semgrep-based analyzer only
- Ruby, in the Brakeman-based analyzer
@@ -278,7 +284,7 @@ successfully, and an error may occur.
To enable and configure SAST with customizations:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. If the project does not have a `.gitlab-ci.yml` file, select **Enable SAST** in the Static
Application Security Testing (SAST) row, otherwise select **Configure SAST**.
@@ -300,7 +306,7 @@ successfully, and an error may occur.
To enable and configure SAST with default settings:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the SAST section, select **Configure with a merge request**.
1. Review and merge the merge request to enable SAST.
@@ -619,7 +625,7 @@ For information, see [Download job artifacts](../../../ci/jobs/job_artifacts.md#
For details of the report file's schema, see
[SAST report file schema](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/sast-report-format.json).
-For an example SAST report file, see [`gl-secret-detection-report.json`](https://gitlab.com/gitlab-org/security-products/analyzers/secrets/-/blob/master/qa/expect/secrets/gl-secret-detection-report.json) example.
+For an example SAST report file, see [`gl-sast-report.json`](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep/-/blob/main/qa/expect/js/default/gl-sast-report.json) example.
## Running SAST in an offline environment
diff --git a/doc/user/application_security/sast/rules.md b/doc/user/application_security/sast/rules.md
new file mode 100644
index 00000000000..4e7a6387f9b
--- /dev/null
+++ b/doc/user/application_security/sast/rules.md
@@ -0,0 +1,101 @@
+---
+stage: Secure
+group: Static Analysis
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# SAST rules **(FREE)**
+
+GitLab SAST uses a set of [analyzers](analyzers.md) to scan code for potential vulnerabilities.
+Each analyzer processes the code then uses rules to find possible weaknesses in source code.
+The rules determine what types of weaknesses the analyzer reports.
+
+## Source of rules
+
+### Semgrep-based analyzer
+
+GitLab creates, maintains, and supports the rules that are used in the Semgrep-based GitLab SAST analyzer.
+This analyzer scans [many languages](index.md#supported-languages-and-frameworks) in a single CI/CD pipeline job.
+It combines:
+
+- the Semgrep open-source engine.
+- GitLab-managed detection rules.
+- GitLab proprietary technology for [vulnerability tracking](index.md#advanced-vulnerability-tracking) and [false positive detection](index.md#false-positive-detection).
+
+### Other analyzers
+
+GitLab SAST uses other analyzers to scan the remaining [supported languages](index.md#supported-languages-and-frameworks).
+The rules for these scans are defined in the upstream projects for each scanner.
+
+## How rule updates are released
+
+GitLab updates rules regularly based on customer feedback and internal research.
+Rules are released as part of the container image for each analyzer.
+You automatically receive updated analyzers and rules unless you [manually pin analyzers to a specific version](index.md#pinning-to-minor-image-version).
+
+Analyzers and their rules are updated [at least monthly](../index.md#vulnerability-scanner-maintenance) if relevant updates are available.
+
+The GitLab ruleset for the Semgrep-based analyzer is managed in [the GitLab-managed open-source `sast-rules` project](https://gitlab.com/gitlab-org/security-products/sast-rules).
+When rules are updated, they're released as part of the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep)'s container image.
+
+## Configure rules in your projects
+
+You should use the default SAST rules unless you have a specific reason to make a change.
+The default ruleset is designed to be relevant to most projects.
+
+However, you can [customize which rules are used](#apply-local-rule-preferences) or [control how rule changes are rolled out](#coordinate-rule-rollouts) if needed.
+
+### Apply local rule preferences
+
+You may want to customize the rules used in SAST scans because:
+
+- Your organization has assigned priorities to specific vulnerability classes, such as choosing to address Cross-Site Scripting (XSS) or SQL Injection before other classes of vulnerabilities.
+- You believe that a specific rule is a false positive result or isn't relevant in the context of your codebase.
+
+To change which rules are used to scan your projects, adjust their severity, or apply other preferences, see [Customize rulesets](customize_rulesets.md).
+If your customization would benefit other users, consider [reporting a problem to GitLab](#report-a-problem-with-a-gitlab-sast-rule).
+
+### Coordinate rule rollouts
+
+To control the rollout of rule changes, you can [pin SAST analyzers to a specific version](index.md#pinning-to-minor-image-version).
+
+If you want to make these changes at the same time across multiple projects, consider setting the variables in:
+
+- [Group-level CI/CD variables](../../../ci/variables/index.md#for-a-group).
+- Custom CI/CD variables in a [Scan Execution Policy](../policies/scan-execution-policies.md).
+
+## Report a problem with a GitLab SAST rule
+<!-- This title is intended to match common search queries users might make. -->
+
+GitLab welcomes contributions to the rulesets used in SAST.
+Contributions might address:
+
+- False positive results, where the potential vulnerability is incorrect.
+- False negative results, where SAST did not report a potential vulnerability that truly exists.
+- The name, severity rating, description, guidance, or other explanatory content for a rule.
+
+If you believe a detection rule could be improved for all users, consider:
+
+- Submitting a merge request to [the `sast-rules` repository](https://gitlab.com/gitlab-org/security-products/sast-rules). See the [contribution instructions](https://gitlab.com/gitlab-org/security-products/sast-rules#contributing) for details.
+- Filing an issue in [the `gitlab-org/gitlab` issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues/).
+ - Post a comment that says `@gitlab-bot label ~"group::static analysis" ~"Category:SAST"` so your issue lands in the correct triage workflow.
+
+## Important rule changes
+
+GitLab updates SAST rules [regularly](#how-rule-updates-are-released).
+This section highlights the most important changes.
+More details are available in release announcements and in the CHANGELOG links provided.
+
+### Rule changes in the Semgrep-based analyzer
+
+Key changes to the GitLab-managed ruleset for Semgrep-based scanning include:
+
+- Beginning in GitLab 16.3, the GitLab Static Analysis and Vulnerability Research teams are working to remove rules that tend to produce too many false positive results or not enough actionable true positive results. Existing findings from these removed rules are [automatically resolved](index.md#automatic-vulnerability-resolution); they no longer appear in the [Security Dashboard](../security_dashboard/index.md#view-vulnerabilities-over-time-for-a-project) or in the default view of the [Vulnerability Report](../vulnerability_report/index.md). This work is tracked in [epic 10907](https://gitlab.com/groups/gitlab-org/-/epics/10907).
+- In GitLab 16.0 through 16.2, the GitLab Vulnerability Research team updated the guidance that's included in each result.
+- In GitLab 15.10, the `detect-object-injection` rule was [removed by default](https://gitlab.com/gitlab-org/gitlab/-/issues/373920) and its findings were [automatically resolved](index.md#automatic-vulnerability-resolution).
+
+For more details, see the [CHANGELOG for `sast-rules`](https://gitlab.com/gitlab-org/security-products/sast-rules/-/blob/main/CHANGELOG.md).
+
+### Rule changes in other analyzers
+
+See the CHANGELOG file for each [analyzer](analyzers.md) for details of the changes, including new or updated rules, included in each version.
diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md
index 10e8356de16..a10c029bec6 100644
--- a/doc/user/application_security/secret_detection/index.md
+++ b/doc/user/application_security/secret_detection/index.md
@@ -27,7 +27,7 @@ You can run scans and view [Secret Detection JSON report artifacts](../../../ci/
With GitLab Ultimate, Secret Detection results are also processed so you can:
-- See them in the [merge request widget](../index.md#view-security-scan-information-in-merge-requests), [pipeline security report](../vulnerability_report/pipeline.md), and [Vulnerability Report](../vulnerability_report/index.md).
+- See them in the [merge request widget](../index.md#merge-request), [pipeline security report](../vulnerability_report/pipeline.md), and [vulnerability report](../vulnerability_report/index.md) UIs.
- Use them in approval workflows.
- Review them in the security dashboard.
- [Automatically respond](automatic_response.md) to leaks in public repositories.
@@ -155,7 +155,7 @@ To enable Secret Detection, either:
This method requires you to manually edit the existing `.gitlab-ci.yml` file. Use this method if
your GitLab CI/CD configuration file is complex.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipeline editor**.
1. Copy and paste the following to the bottom of the `.gitlab-ci.yml` file:
@@ -188,7 +188,7 @@ error may occur. In that case, use the [manual](#edit-the-gitlab-ciyml-file-manu
To enable Secret Detection:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. In the **Secret Detection** row, select **Configure with a merge request**.
1. Optional. Complete the fields.
@@ -338,12 +338,14 @@ To enable full history Secret Detection, set the variable `SECRET_DETECTION_HIST
## Custom rulesets **(ULTIMATE ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211387) in GitLab 13.5.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/339614) support for passthrough chains.
+> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/339614) support for passthrough chains.
> Expanded to include additional passthrough types of `file`, `git`, and `url` in GitLab 14.6.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) support for overriding rules in
+> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) support for overriding rules in
> GitLab 14.8.
-You can customize the default Secret Detection rules provided with GitLab.
+You can customize which [secrets are reported in the GitLab UI](#secret-detection).
+However, the `secret_detection` job logs always include the number
+of secrets detected by the default Secret Detection rules.
The following customization options can be used separately, or in combination:
@@ -510,7 +512,7 @@ optional authentication, and optional Git SHA. The variable uses the following f
```
NOTE:
-Loading local project configuration takes precedence over `SECRET_DETECTION_RULESET_GIT_REFERENCE` values.
+A local `.gitlab/secret-detection-ruleset.toml` file in the project takes precedence over `SECRET_DETECTION_RULESET_GIT_REFERENCE`.
The following example includes the Secret Detection template in a project to be scanned and specifies
the `SECRET_DETECTION_RULESET_GIT_REFERENCE` variable for referencing a separate project configuration.
diff --git a/doc/user/application_security/secure_your_application.md b/doc/user/application_security/secure_your_application.md
index 0b028f6936d..f4fb8c49277 100644
--- a/doc/user/application_security/secure_your_application.md
+++ b/doc/user/application_security/secure_your_application.md
@@ -27,3 +27,4 @@ GitLab can check your applications for security vulnerabilities.
- [Policies](policies/index.md)
- [Security scanner integration](../../development/integrations/secure.md)
- [Secure and Govern Terminology](terminology/index.md)
+- [GitLab Advisory Database](gitlab_advisory_database/index.md)
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index b6d95e53227..53a6dfe6d0a 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -66,7 +66,7 @@ Project Security Dashboards show statistics for all vulnerabilities with a curre
To view total number of vulnerabilities over time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security dashboard**.
1. Filter and search for what you need.
- To filter the chart by severity, select the legend name.
@@ -79,7 +79,7 @@ To view total number of vulnerabilities over time:
To download an SVG image of the vulnerabilities chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security dashboard**.
1. Select **Save chart as an image** (**{download}**).
@@ -90,7 +90,7 @@ branches of projects in a group and its subgroups.
To view vulnerabilities over time for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Security > Security dashboard**.
1. Hover over the chart to get more details about vulnerabilities.
- You can display the vulnerability trends over a 30, 60, or 90-day time frame (the default is 90 days).
@@ -104,7 +104,7 @@ Use the group Security Dashboard to view the security status of projects.
To view project security status for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Secure > Security dashboard**.
Each project is assigned a letter [grade](#project-vulnerability-grades) according to the highest-severity open vulnerability.
@@ -142,7 +142,7 @@ The Security Center includes:
To view the Security Center:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. Select **Security > Security dashboard**.
@@ -150,7 +150,7 @@ To view the Security Center:
To add projects to the Security Center:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. Expand **Security**.
1. Select **Settings**.
diff --git a/doc/user/application_security/vulnerabilities/index.md b/doc/user/application_security/vulnerabilities/index.md
index fa0027754ad..34c57292767 100644
--- a/doc/user/application_security/vulnerabilities/index.md
+++ b/doc/user/application_security/vulnerabilities/index.md
@@ -24,10 +24,10 @@ change its status to **Resolved**. This ensures that if it is accidentally reint
merge, it is reported again as a new record. To change the status of multiple vulnerabilities, use
the Vulnerability Report's [Activity filter](../vulnerability_report/index.md#activity-filter).
-## Explaining a vulnerability (Beta) **(ULTIMATE SAAS)**
+## Explaining a vulnerability **(ULTIMATE SAAS BETA)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10368) in GitLab 16.0 as an [Experiment](../../../policy/experiment-beta-support.md#experiment) on GitLab.com.
-> - Promoted to [Beta](../../../policy/experiment-beta-support.md#beta) status in 16.2.
+> - Promoted to [Beta](../../../policy/experiment-beta-support.md#beta) status in GitLab 16.2.
GitLab can help you with a vulnerability by using a large language model to:
@@ -37,8 +37,8 @@ GitLab can help you with a vulnerability by using a large language model to:
### Explain a vulnerability
-Use the explain this vulnerability feature to better understand a vulnerability and its possible
-mitigation.
+Explain a vulnerability with GitLab Duo Vulnerability summary. Use the explanation to better
+understand a vulnerability and its possible mitigation.
Prerequisites:
@@ -46,11 +46,11 @@ Prerequisites:
- You must be a member of the project.
- The vulnerability must be a SAST finding.
-Learn more about [how to enable all AI features](../../ai_features.md#enable-aiml-features).
+Learn more about [how to enable all GitLab Duo features](../../ai_features.md#enable-aiml-features).
To explain the vulnerability:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Security and Compliance > Vulnerability report**.
1. In the **Tool** dropdown list, select **SAST**.
1. Select the SAST vulnerability you want explained.
@@ -108,7 +108,7 @@ When dismissing a vulnerability, one of the following reasons must be chosen to
To change a vulnerability's status from its Vulnerability Page:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
1. Select the vulnerability's description.
1. From the **Status** dropdown list select a status, then select **Change status**.
@@ -130,15 +130,11 @@ You can create either:
- [A GitLab issue](#create-a-gitlab-issue-for-a-vulnerability) (default).
- [A Jira issue](#create-a-jira-issue-for-a-vulnerability).
-Creating a Jira issue requires that
-[Jira integration](../../../integration/jira/index.md) is enabled on the project. Note
-that when Jira integration is enabled, the GitLab issue feature is not available.
-
### Create a GitLab issue for a vulnerability
To create a GitLab issue for a vulnerability:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
1. Select the vulnerability's description.
1. Select **Create issue**.
@@ -157,7 +153,7 @@ Prerequisites:
To create a Jira issue for a vulnerability:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
1. Select the vulnerability's description.
1. Select **Create Jira issue**.
@@ -169,28 +165,21 @@ fields are pre-populated from the vulnerability's details.
Unlike GitLab issues, the status of whether a Jira issue is open or closed does not display in the
GitLab user interface.
-## Linking a vulnerability to issues
-
-NOTE:
-If Jira issue support is enabled, GitLab issues are disabled so this feature is not available.
+## Linking a vulnerability to GitLab and Jira issues
-You can link a vulnerability to one or more existing GitLab issues. Adding a link helps track
-the issue that resolves or mitigates a vulnerability.
+You can link a vulnerability to one or more existing [GitLab](#create-a-gitlab-issue-for-a-vulnerability)
+or [Jira](#create-a-jira-issue-for-a-vulnerability) issues. Only one linking feature is available at the same time.
+Adding a link helps track the issue that resolves or mitigates a vulnerability.
-Issues linked to a vulnerability are shown in the Vulnerability Report and the vulnerability's page.
+### Link a vulnerability to existing GitLab issues
-Be aware of the following conditions between a vulnerability and a linked issue:
+Prerequisite:
-- The vulnerability page shows related issues, but the issue page doesn't show the vulnerability
- it's related to.
-- An issue can only be related to one vulnerability at a time.
-- Issues can be linked across groups and projects.
+- [Jira issue integration](../../../integration/jira/configure.md) must not be enabled.
-## Link a vulnerability to existing issues
+To link a vulnerability to existing GitLab issues:
-To link a vulnerability to existing issues:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
1. Select the vulnerability's description.
1. In the **Linked issues** section, select the plus icon (**{plus}**).
@@ -199,9 +188,43 @@ To link a vulnerability to existing issues:
- Enter the issue's ID (prefixed with a hash `#`).
1. Select **Add**.
-The selected issues are added to the **Linked issues** section, and the linked issues counter is
+The selected GitLab issues are added to the **Linked items** section, and the linked issues counter is
+updated.
+
+GitLab issues linked to a vulnerability are shown in the Vulnerability Report and the vulnerability's page.
+
+Be aware of the following conditions between a vulnerability and a linked GitLab issue:
+
+- The vulnerability page shows related issues, but the issue page doesn't show the vulnerability
+ it's related to.
+- An issue can only be related to one vulnerability at a time.
+- Issues can be linked across groups and projects.
+
+### Link a vulnerability to existing Jira issues
+
+Prerequisite:
+
+- [Jira issue integration](../../../integration/jira/configure.md) must be enabled, with option **Enable Jira issue creation from vulnerabilities** also enabled.
+
+To link a vulnerability to existing Jira issues, add the following line to the Jira issue's description:
+
+```plaintext
+/-/security/vulnerabilities/<id>
+```
+
+`<id>` is any [vulnerability ID](../../../api/vulnerabilities.md#single-vulnerability).
+You can add several lines with different IDs to one description.
+
+Jira issues with appropriate description are added to the **Related Jira issues** section, and the linked issues counter is
updated.
+Jira issues linked to a vulnerability are shown only on the vulnerability page.
+
+Be aware of the following conditions between a vulnerability and a linked Jira issue:
+
+- The vulnerability page and the issue page show the vulnerability they are related to.
+- An issue can be related to one or more vulnerabilities at the same time.
+
## Resolve a vulnerability
For some vulnerabilities a solution is already known. In those instances, a vulnerability's page
@@ -225,7 +248,7 @@ To resolve a vulnerability, you can either:
To resolve the vulnerability with a merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
1. Select the vulnerability's description.
1. From the **Resolve with merge request** dropdown list, select **Resolve with merge request**.
@@ -237,7 +260,7 @@ Process the merge request according to your standard workflow.
To manually apply the patch that GitLab generated for a vulnerability:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
1. Select the vulnerability's description.
1. From the **Resolve with merge request** dropdown list, select **Download patch to resolve**.
@@ -260,7 +283,7 @@ Security training helps your developers learn how to fix vulnerabilities. Develo
To enable security training for vulnerabilities in your project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Security configuration**.
1. On the tab bar, select **Vulnerability Management**.
1. To enable a security training provider, turn on the toggle.
@@ -280,7 +303,7 @@ Vulnerabilities with a CWE are most likely to return a training result.
To view the security training for a vulnerability:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
1. Select the vulnerability for which you want to view security training.
1. Select **View training**.
diff --git a/doc/user/application_security/vulnerability_report/index.md b/doc/user/application_security/vulnerability_report/index.md
index 46ce3173ee7..3ec1151b1d6 100644
--- a/doc/user/application_security/vulnerability_report/index.md
+++ b/doc/user/application_security/vulnerability_report/index.md
@@ -40,8 +40,6 @@ status of a Jira issue is not shown in the GitLab UI.
## Project-level Vulnerability Report
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/6165) in GitLab 11.1.
-
At the project level, the Vulnerability Report also contains:
- A time stamp showing when it was updated, including a link to the latest pipeline.
@@ -55,7 +53,7 @@ this page displays the vulnerabilities that originate from the selected project.
To view the project-level vulnerability report:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
## Vulnerability Report actions
@@ -129,8 +127,6 @@ The content of the Project filter depends on the current level:
### Activity filter
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/259255) in GitLab 13.9
-
The Activity filter behaves differently from the other filters. The selected values form mutually
exclusive sets to allow for precisely locating the desired vulnerability records. Additionally, not
all options can be selected in combination.
@@ -150,8 +146,6 @@ To view more details of a vulnerability, select the vulnerability's **Descriptio
## View vulnerable source location
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267509) in GitLab 13.10.
-
Some security scanners output the filename and line number of a potential vulnerability. When
that information is available, the vulnerability's details include a link to the relevant file,
in the default branch.
@@ -160,8 +154,7 @@ To view the relevant file, select the filename in the vulnerability's details.
## Change status of vulnerabilities
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292636) in GitLab 13.10, all statuses became selectable.
-> - Providing a comment and dismissal reason [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/408366) in GitLab 16.0.
+> Providing a comment and dismissal reason [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/408366) in GitLab 16.0.
From the Vulnerability Report you can change the status of one or more vulnerabilities.
@@ -184,9 +177,6 @@ To sort vulnerabilities by the date each vulnerability was detected, select the
## Export vulnerability details
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213014) in the Security Center (previously known as the Instance Security Dashboard) and project-level Vulnerability Report (previously known as the Project Security Dashboard) in GitLab 13.0.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/213013) to the group-level Vulnerability Report in GitLab 13.1.
-
You can export details of the vulnerabilities listed in the Vulnerability Report. The export format
is CSV (comma separated values). All vulnerabilities are included because filters do not
apply to the export.
@@ -229,8 +219,6 @@ thousands of vulnerabilities. Do not close the page until the download finishes.
## Dismiss a vulnerability
-> The option of adding a dismissal reason was introduced in GitLab 12.0.
-
When you evaluate a vulnerability and decide it requires no more action,
you can mark it as **Dismissed**.
Dismissed vulnerabilities do not appear in the merge request security widget
@@ -260,7 +248,7 @@ To undo this action, select a different status from the same menu.
To add a new vulnerability finding from your project level Vulnerability Report page:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Vulnerability report**.
1. Select **Submit vulnerability**.
1. Complete the fields and submit the form.
diff --git a/doc/user/application_security/vulnerability_report/pipeline.md b/doc/user/application_security/vulnerability_report/pipeline.md
index 7a414e9a4ae..ef66925b9c9 100644
--- a/doc/user/application_security/vulnerability_report/pipeline.md
+++ b/doc/user/application_security/vulnerability_report/pipeline.md
@@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
To view vulnerabilities in a pipeline:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipelines**.
1. From the list, select the pipeline you want to check for vulnerabilities.
1. Select the **Security** tab.
@@ -25,9 +25,11 @@ For example, if a pipeline contains DAST and SAST jobs, but the DAST job fails b
[exit code](../../../development/integrations/secure.md#exit-code), the report doesn't show DAST results.
The pipeline vulnerability report only shows results contained in the security report artifacts. This report differs from
-the [Vulnerability Report](index.md), which contains cumulative results of all successful jobs, and from the merge request
-[security widget](../index.md#view-security-scan-information-in-merge-requests), which combines the branch results with
-cumulative results.
+the [vulnerability report](index.md), which contains cumulative results of all successful jobs, and from the merge request
+[security widget](../index.md#merge-request), which contains new vulnerability findings that don't already exist on the default branch.
+
+NOTE:
+If a new advisory is added to our advisory database and the last pipeline for the default branch is stale, the resulting vulnerability may appear in the MR widget as "New" when it is already in the default branch. This will be resolved by [Continuous Vulnerability Scans](https://gitlab.com/groups/gitlab-org/-/epics/7886).
The pipeline vulnerability report only displays after the pipeline is complete. If the pipeline has a [blocking manual job](../../../ci/jobs/job_control.md#types-of-manual-jobs), the pipeline waits for the manual job and the vulnerabilities cannot be displayed if the blocking manual job did not run.
diff --git a/doc/user/award_emojis.md b/doc/user/award_emojis.md
index a7c58b4d2a8..26cccd7584e 100644
--- a/doc/user/award_emojis.md
+++ b/doc/user/award_emojis.md
@@ -47,7 +47,7 @@ To remove an emoji reaction, select the emoji again.
> - [Introduced for GraphQL API](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911) in GitLab 13.6 [with a flag](../administration/feature_flags.md) named `custom_emoji`. Disabled by default.
> - Enabled on GitLab.com in GitLab 14.0.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/333095) UI to add emoji in GitLab 16.2.
+> - UI to add emoji [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333095) in GitLab 16.2.
Custom emoji show in the emoji picker everywhere you can react with emoji.
To add an emoji reaction to a comment or description:
diff --git a/doc/user/clusters/agent/ci_cd_workflow.md b/doc/user/clusters/agent/ci_cd_workflow.md
index 260263632c5..a1281d3d75c 100644
--- a/doc/user/clusters/agent/ci_cd_workflow.md
+++ b/doc/user/clusters/agent/ci_cd_workflow.md
@@ -15,9 +15,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - The ability to switch between certificate-based clusters and agents was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335089) in GitLab 14.9. The certificate-based cluster context is always called `gitlab-deploy`.
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/80508) from _CI/CD tunnel_ to _CI/CD workflow_ in GitLab 14.9.
-You can use a GitLab CI/CD workflow to safely deploy to and update your Kubernetes clusters.
+You can use GitLab CI/CD to safely connect, deploy, and update your Kubernetes clusters.
-To do so, you must first [install an agent in your cluster](install/index.md). When done, you have a Kubernetes context and can
+To do so, [install an agent in your cluster](install/index.md). When done, you have a Kubernetes context and can
run Kubernetes API commands in your GitLab CI/CD pipeline.
To ensure access to your cluster is safe:
@@ -25,11 +25,11 @@ To ensure access to your cluster is safe:
- Each agent has a separate context (`kubecontext`).
- Only the project where the agent is configured, and any additional projects you authorize, can access the agent in your cluster.
-The CI/CD workflow requires runners to be registered with GitLab, but these runners do not have to be in the cluster where the agent is.
+To use GitLab CI/CD to interact with your cluster, runners must be registered with GitLab. However, these runners do not have to be in the cluster where the agent is.
-## GitLab CI/CD workflow steps
+## Use GitLab CI/CD with your cluster
-To update a Kubernetes cluster by using GitLab CI/CD, complete the following steps.
+To update a Kubernetes cluster with GitLab CI/CD:
1. Ensure you have a working Kubernetes cluster and the manifests are in a GitLab project.
1. In the same GitLab project, [register and install the GitLab agent](install/index.md).
@@ -64,7 +64,7 @@ Authorization configuration can take one or two minutes to propagate.
To authorize the agent to access the GitLab project where you keep Kubernetes manifests:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the project that contains the [agent configuration file](install/index.md#create-an-agent-configuration-file) (`config.yaml`).
+1. On the left sidebar, select **Search or go to** and find the project that contains the [agent configuration file](install/index.md#create-an-agent-configuration-file) (`config.yaml`).
1. Edit the `config.yaml` file. Under the `ci_access` keyword, add the `projects` attribute.
1. For the `id`, add the path to the project. Do not wrap the path in quotation marks.
@@ -89,7 +89,7 @@ Choose the context to run `kubectl` commands from your CI/CD scripts.
To authorize the agent to access all of the GitLab projects in a group or subgroup:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the project that contains the [agent configuration file](install/index.md#create-an-agent-configuration-file) (`config.yaml`).
+1. On the left sidebar, select **Search or go to** and find the project that contains the [agent configuration file](install/index.md#create-an-agent-configuration-file) (`config.yaml`).
1. Edit the `config.yaml` file. Under the `ci_access` keyword, add the `groups` attribute.
1. For the `id`, add the path:
diff --git a/doc/user/clusters/agent/gitops/flux_tutorial.md b/doc/user/clusters/agent/gitops/flux_tutorial.md
index f2d65b900f0..27724a95291 100644
--- a/doc/user/clusters/agent/gitops/flux_tutorial.md
+++ b/doc/user/clusters/agent/gitops/flux_tutorial.md
@@ -83,7 +83,7 @@ You must register `agentk` before you install it in your cluster.
To register `agentk`:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
If you have an [agent configuration file](../install/index.md#create-an-agent-configuration-file),
it must be in this project. Your cluster manifest files should also be in this project.
1. Select **Operate > Kubernetes clusters**.
@@ -123,9 +123,7 @@ To install `agentk`:
name: gitlab-agent-token
type: Opaque
stringData:
- values.yaml: |-
- config:
- token: "<your-token-here>"
+ token: "<your-token-here>"
```
1. Apply `secret.yaml` to your cluster:
@@ -173,12 +171,11 @@ To install `agentk`:
values:
config:
kasAddress: "wss://kas.gitlab.com"
- valuesFrom:
- - kind: Secret
- name: gitlab-agent-token
- valuesKey: values.yaml
+ secretName: gitlab-agent-token
```
+ The Helm release uses the secret from the previous step.
+
1. To verify that `agentk` is installed and running in the cluster, run the following command:
```shell
diff --git a/doc/user/clusters/agent/install/index.md b/doc/user/clusters/agent/install/index.md
index 75571d1a4f5..d620a9f658c 100644
--- a/doc/user/clusters/agent/install/index.md
+++ b/doc/user/clusters/agent/install/index.md
@@ -43,7 +43,7 @@ To install the agent in your cluster:
For configuration settings, the agent uses a YAML file in the GitLab project. You must create this file if:
- You use [a GitOps workflow](../gitops/agent.md#gitops-workflow-steps).
-- You use [a GitLab CI/CD workflow](../ci_cd_workflow.md#gitlab-cicd-workflow-steps) and want to authorize a different project to use the agent.
+- You use [a GitLab CI/CD workflow](../ci_cd_workflow.md#use-gitlab-cicd-with-your-cluster) and want to authorize a different project to use the agent.
- You [allow specific project or group members to access Kubernetes](../user_access.md).
To create an agent configuration file:
@@ -76,11 +76,11 @@ In GitLab 14.10, a [flag](../../../../administration/feature_flags.md) named `ce
Prerequisites:
- For a [GitLab CI/CD workflow](../ci_cd_workflow.md), ensure that
- [GitLab CI/CD is enabled](../../../../ci/enable_or_disable_ci.md#enable-cicd-in-a-project).
+ [GitLab CI/CD is not disabled](../../../../ci/enable_or_disable_ci.md#disable-cicd-in-a-project).
You must register an agent before you can install the agent in your cluster. To register an agent:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
If you have an [agent configuration file](#create-an-agent-configuration-file),
it must be in this project. Your cluster manifest files should also be in this project.
1. Select **Operate > Kubernetes clusters**.
@@ -114,22 +114,26 @@ To connect to multiple clusters, you must configure, register, and install an ag
#### Install the agent with Helm
+WARNING:
+For simplicity, the default Helm chart configuration sets up a service account for the agent with `cluster-admin` rights. You should not use this on production systems. To deploy to a production system, follow the instructions in [Customize the Helm installation](#customize-the-helm-installation) to create a service account with the minimum permissions required for your deployment and specify that during installation.
+
To install the agent on your cluster using Helm:
1. [Install Helm](https://helm.sh/docs/intro/install/).
1. In your computer, open a terminal and [connect to your cluster](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/).
1. Run the command you copied when you [registered your agent with GitLab](#register-the-agent-with-gitlab).
-
-Optionally, you can [customize the Helm installation](#customize-the-helm-installation). If you install the agent on a production system, you should customize the Helm installation to skip creating the service account.
+1. Optional. [Customize the Helm installation](#customize-the-helm-installation).
+ If you install the agent on a production system, you should customize the Helm installation to restrict the permissions of the service account. See [How to deploy the GitLab Agent for Kubernetes with limited permissions](https://about.gitlab.com/blog/2021/09/10/setting-up-the-k-agent/).
##### Customize the Helm installation
By default, the Helm installation command generated by GitLab:
- Creates a namespace `gitlab-agent` for the deployment (`--namespace gitlab-agent`). You can skip creating the namespace by omitting the `--create-namespace` flag.
-- Sets up a service account for the agent with `cluster-admin` rights. You can:
+- Sets up a service account for the agent and assigns it the `cluster-admin` role. You can:
- Skip creating the service account by adding `--set serviceAccount.create=false` to the `helm install` command. In this case, you must set `serviceAccount.name` to a pre-existing service account.
- - Skip creating the RBAC permissions by adding `--set rbac.create=false` to the `helm install` command. In this case, you must bring your own RBAC permissions for the agent. Otherwise, it has no permissions at all.
+ - Customise the role assigned to the service account by adding `--set rbac.useExistingRole <your role name>` to the `helm install` command. In this case, you should have a pre-created role with restricted permissions that can be used by the service account.
+ - Skip role assignment altogether by adding `--set rbac.create=false` to your `helm install` command. In this case, you must create `ClusterRoleBinding` manually.
- Creates a `Secret` resource for the agent's access token. To instead bring your own secret with a token, omit the token (`--set token=...`) and instead use `--set config.secretName=<your secret name>`.
- Creates a `Deployment` resource for the `agentk` pod.
diff --git a/doc/user/clusters/agent/user_access.md b/doc/user/clusters/agent/user_access.md
index a5989d823f6..21dc249b1d1 100644
--- a/doc/user/clusters/agent/user_access.md
+++ b/doc/user/clusters/agent/user_access.md
@@ -4,7 +4,7 @@ group: Environments
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Grant users Kubernetes access (Beta) **(FREE ALL)**
+# Grant users Kubernetes access **(FREE ALL BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390769) in GitLab 16.1, with [flags](../../../administration/feature_flags.md) named `environment_settings_to_graphql`, `kas_user_access`, `kas_user_access_project`, and `expose_authorized_cluster_agents`. This feature is in [Beta](../../../policy/experiment-beta-support.md#beta).
> - Feature flag `environment_settings_to_graphql` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124177) in GitLab 16.2.
@@ -141,6 +141,60 @@ subjects:
kind: Group
```
+## Access a cluster with the Kubernetes API
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131144) in GitLab 16.4.
+
+You can configure an agent to allow GitLab users to access a cluster with the Kubernetes API.
+
+Prerequisite:
+
+- You have an agent configured with the `user_access` entry.
+
+To grant Kubernetes API access:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Operate > Kubernetes clusters** and retrieve the numerical ID of the agent you want to access. You need the ID to construct the full API token.
+1. Create a [personal access token](../../profile/personal_access_tokens.md) with the `k8s_proxy` scope. You need the access token to construct the full API token.
+1. Construct `kube config` entries to access the cluster:
+ 1. Make sure that the proper `kube config` is selected.
+ For example, you can set the `KUBECONFIG` environment variable.
+ 1. Add the GitLab KAS proxy cluster to the `kube config`:
+
+ ```shell
+ kubectl config set-cluster <cluster_name> --server "https://kas.gitlab.com/k8s-proxy"
+ ```
+
+ The `server` argument points to the KAS address of your GitLab instance.
+ On GitLab.com, this is `https://kas.gitlab.com/k8s-proxy`.
+ You can get the KAS address of your instance when you register an agent.
+
+ 1. Use your numerical agent ID and personal access token to construct an API token:
+
+ ```shell
+ kubectl config set-credentials <gitlab_user> --token "pat:<agent-id>:<token>"
+ ```
+
+ 1. Add the context to combine the cluster and the user:
+
+ ```shell
+ kubectl config set-context <gitlab_agent> --cluster <cluster_name> --user <gitlab_user>
+ ```
+
+ 1. Activate the new context:
+
+ ```shell
+ kubectl config use-context <gitlab_agent>
+ ```
+
+1. Check that the configuration works:
+
+ ```shell
+ kubectl get nodes
+ ```
+
+The configured user can access your cluster with the Kubernetes API.
+
## Related topics
- [Architectural blueprint](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_user_access.md)
diff --git a/doc/user/clusters/agent/vulnerabilities.md b/doc/user/clusters/agent/vulnerabilities.md
index a967ec9ea24..a2dc50e43d7 100644
--- a/doc/user/clusters/agent/vulnerabilities.md
+++ b/doc/user/clusters/agent/vulnerabilities.md
@@ -9,9 +9,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6346) in GitLab 14.8.
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/368828) the starboard directive in GitLab 15.4. The starboard directive is scheduled for removal in GitLab 16.0.
-To view cluster vulnerabilities, you can view the [vulnerability report](../../application_security/vulnerabilities/index.md).
-You can also configure your agent so the vulnerabilities are displayed with other agent information in GitLab.
-
## Enable operational container scanning
You can use operational container scanning to scan container images in your cluster for security vulnerabilities. You
@@ -24,7 +21,7 @@ If both `agent config` and `scan execution policies` are configured, the configu
### Enable via agent configuration
To enable scanning of all images within your Kubernetes cluster via the agent configuration, add a `container_scanning` configuration block to your agent
-configuration with a `cadence` field containing a [CRON expression](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm) for when the scans are run.
+configuration with a `cadence` field containing a [CRON expression](https://en.wikipedia.org/wiki/Cron) for when the scans are run.
```yaml
container_scanning:
@@ -129,7 +126,7 @@ Resource requirements can only be set up using the agent configuration. If you e
To view vulnerability information in GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the project that contains the agent configuration file.
+1. On the left sidebar, select **Search or go to** and find the project that contains the agent configuration file.
1. Select **Operate > Kubernetes clusters**.
1. Select the **Agent** tab.
1. Select an agent to view the cluster vulnerabilities.
@@ -140,3 +137,9 @@ This information can also be found under [operational vulnerabilities](../../../
NOTE:
You must have at least the Developer role.
+
+## Scanning private images
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/415451) in GitLab 16.4.
+
+To scan private images, the scanner relies on the image pull secrets (direct references and from the service account) to pull the image.
diff --git a/doc/user/clusters/agent/work_with_agent.md b/doc/user/clusters/agent/work_with_agent.md
index 08e1021f886..70abbebaaad 100644
--- a/doc/user/clusters/agent/work_with_agent.md
+++ b/doc/user/clusters/agent/work_with_agent.md
@@ -4,9 +4,9 @@ group: Environments
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Working with the agent for Kubernetes **(FREE ALL)**
+# Managing the agent for Kubernetes instances **(FREE ALL)**
-Use the following tasks when working with the agent for Kubernetes.
+Use the following tasks when you work with the agent for Kubernetes.
## View your agents
@@ -18,7 +18,7 @@ Prerequisite:
To view the list of agents:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the project that contains your agent configuration file.
+1. On the left sidebar, select **Search or go to** and find the project that contains your agent configuration file.
You cannot view registered agents from a project that does not contain the agent configuration file.
1. Select **Operate > Kubernetes clusters**.
1. Select **Agent** tab to view clusters connected to GitLab through the agent.
@@ -40,7 +40,7 @@ is shared with a project, it automatically appears in the project agent tab.
To view the list of shared agents:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Kubernetes clusters**.
1. Select the **Agent** tab.
@@ -54,7 +54,7 @@ The activity logs help you to identify problems and get the information
you need for troubleshooting. You can see events from a week before the
current date. To view an agent's activity:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the project that contains your agent configuration file.
+1. On the left sidebar, select **Search or go to** and find the project that contains your agent configuration file.
1. Select **Operate > Kubernetes clusters**.
1. Select the agent you want to see activity for.
@@ -115,7 +115,7 @@ An agent can have only two active tokens at one time.
To reset the agent token without downtime:
1. Create a new token:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Kubernetes clusters**.
1. Select the agent you want to create a token for.
1. On the **Access tokens** tab, select **Create token**.
@@ -137,7 +137,7 @@ clean up those resources manually.
To remove an agent from the UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the project that contains the agent configuration file.
+1. On the left sidebar, select **Search or go to** and find the project that contains the agent configuration file.
1. Select **Operate > Kubernetes clusters**.
1. In the table, in the row for your agent, in the **Options** column, select the vertical ellipsis (**{ellipsis_v}**).
1. Select **Delete agent**.
diff --git a/doc/user/clusters/cost_management.md b/doc/user/clusters/cost_management.md
deleted file mode 100644
index a155dcf4a3c..00000000000
--- a/doc/user/clusters/cost_management.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Deploy
-group: Environments
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../index.md'
----
-
-# Cluster cost management (removed) **(ULTIMATE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/clusters/integrations.md b/doc/user/clusters/integrations.md
deleted file mode 100644
index 0f389b94a33..00000000000
--- a/doc/user/clusters/integrations.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Deploy
-group: Environments
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../index.md'
----
-
-# Cluster integrations (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/clusters/management_project.md b/doc/user/clusters/management_project.md
index 3341074f54d..3c5c90abdae 100644
--- a/doc/user/clusters/management_project.md
+++ b/doc/user/clusters/management_project.md
@@ -62,7 +62,7 @@ To associate a cluster management project with your cluster:
- [Group-level cluster](../group/clusters/index.md), go to your group's **Kubernetes**
page.
- [Instance-level cluster](../instance/clusters/index.md):
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Kubernetes**.
1. Expand **Advanced settings**.
diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md
index f4f42f4dc27..a40fc5a262e 100644
--- a/doc/user/clusters/management_project_template.md
+++ b/doc/user/clusters/management_project_template.md
@@ -86,9 +86,7 @@ cluster applications with [Helm v3](https://helm.sh/).
This file has a list of paths to other Helm files for each app. They're all commented out by default, so you must uncomment
the paths for the apps that you would like to use in your cluster.
-By default, each `helmfile.yaml` in these sub-paths has the attribute `installed: true`. This means that every time
-the pipeline runs, Helmfile tries to either install or update your apps according to the current state of your
-cluster and Helm releases. If you change this attribute to `installed: false`, Helmfile tries try to uninstall this app
+By default, each `helmfile.yaml` in these sub-paths has the attribute `installed: true`. This means that, depending on the state of your cluster and Helm releases, Helmfile attempts to install or update apps every time the pipeline runs. If you change this attribute to `installed: false`, Helmfile tries to uninstall this app
from your cluster. [Read more](https://helmfile.readthedocs.io/en/latest/) about how Helmfile works.
### Built-in applications
@@ -101,7 +99,6 @@ The [built-in supported applications](https://gitlab.com/gitlab-org/project-temp
- [Cert-manager](../infrastructure/clusters/manage/management_project_applications/certmanager.md)
- [GitLab Runner](../infrastructure/clusters/manage/management_project_applications/runner.md)
- [Ingress](../infrastructure/clusters/manage/management_project_applications/ingress.md)
-- [Prometheus](../../operations/metrics/index.md)
- [Vault](../infrastructure/clusters/manage/management_project_applications/vault.md)
Each application has an `applications/{app}/values.yaml` file.
diff --git a/doc/user/compliance/compliance_center/index.md b/doc/user/compliance/compliance_center/index.md
index bd3409abe01..2510b5e73a7 100644
--- a/doc/user/compliance/compliance_center/index.md
+++ b/doc/user/compliance/compliance_center/index.md
@@ -32,7 +32,7 @@ Prerequisites:
To view the standards adherence dashboard for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
### GitLab standard
@@ -75,13 +75,13 @@ information, see [Merge request approval rules](../../project/merge_requests/app
> - GraphQL API [introduced](https://gitlab.com/groups/gitlab-org/-/epics/7222) in GitLab 14.9.
> - [Generally available](https://gitlab.com/groups/gitlab-org/-/epics/5237) in GitLab 14.10. [Feature flag `compliance_violations_report`](https://gitlab.com/gitlab-org/gitlab/-/issues/346266) removed.
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112111) to compliance violations report in GitLab 15.9.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/394950) ability to create/edit compliance frameworks in GitLab 16.0.
+> - Ability to create and edit compliance frameworks [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/394950) in GitLab 16.0.
With compliance violations report, you can see a high-level view of merge request activity for all projects in the group.
When you select a row in the compliance report, a drawer appears that provides:
-- The project name and [compliance framework label](../../project/settings/index.md#add-a-compliance-framework-to-a-project),
+- The project name and [compliance framework label](../../project/working_with_projects.md#add-a-compliance-framework-to-a-project),
if the project has one assigned.
- A link to the merge request that introduced the violation.
- The merge request's branch path in the format `[source] into [target]`.
@@ -100,7 +100,7 @@ Prerequisites:
To view the compliance violations report:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
You can sort the compliance report on:
@@ -207,7 +207,7 @@ If the commit has a related merge commit, then the following are also included:
To generate the Chain of Custody report:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. Select **List of all merge commits**.
@@ -223,7 +223,7 @@ details for the provided commit SHA.
To generate a commit-specific Chain of Custody report:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. At the top of the compliance report, to the right of **List of all commits**, select the down arrow
(**{chevron-lg-down}**).
@@ -254,7 +254,7 @@ Prerequisites:
To view the compliance frameworks report:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. On the page, select the **Frameworks** tab.
@@ -271,7 +271,7 @@ Prerequisites:
To apply a compliance framework to one project in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. On the page, select the **Frameworks** tab.
1. Next to the project you want to add the compliance framework to, select **{plus}** **Add framework**.
@@ -279,7 +279,7 @@ To apply a compliance framework to one project in a group:
To apply a compliance framework to multiple projects in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. On the page, select the **Frameworks** tab.
1. Select multiple projects.
@@ -300,20 +300,46 @@ Prerequisites:
To remove a compliance framework from one project in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. On the page, select the **Frameworks** tab.
1. Next to the compliance framework to remove from the project, select **{close}** on the framework label.
To remove a compliance framework from multiple projects in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. On the page, select the **Frameworks** tab.
1. Select multiple projects.
1. From the **Choose one bulk action** dropdown list, select **Remove framework from selected projects**.
1. Select **Remove**.
+### Export a report of merge request compliance violations on projects in a group
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356791) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `compliance_violation_csv_export`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named
+`compliance_violation_csv_export`. On GitLab.com, this feature is not available. The feature is not ready for production use.
+
+Export a report of merge request compliance violations on merge requests belonging to projects in a group. Reports:
+
+- Do not use filters on the violations report.
+- Are truncated at 15 MB so the email attachment is not too large.
+
+Prerequisites:
+
+- You must be an administrator or have the Owner role for the group.
+
+To export a report of merge request compliance violations for projects in a group:
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. On the left sidebar, select **Secure > Compliance center**.
+1. On the page, select the **Violations** tab.
+1. On the Violations tab, select the **Export full report as CSV** action in the top right corner
+
+A report is compiled and delivered to your email inbox as an attachment.
+
### Export a report of compliance frameworks on projects in a group
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387912) in GitLab 16.0.
@@ -329,7 +355,7 @@ Prerequisites:
To export a report of compliance frameworks on projects in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. On the page, select the **Frameworks** tab.
1. On the Frameworks tab, select the **Export as CSV** action in the top right corner
@@ -342,7 +368,7 @@ A report is compiled and delivered to your email inbox as an attachment.
To filter the list of compliance frameworks:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Secure > Compliance center**.
1. On the page, select the **Frameworks** tab.
1. In the search field:
diff --git a/doc/user/compliance/license_approval_policies.md b/doc/user/compliance/license_approval_policies.md
index e3350b1ae10..cf5f340c0f6 100644
--- a/doc/user/compliance/license_approval_policies.md
+++ b/doc/user/compliance/license_approval_policies.md
@@ -41,7 +41,7 @@ Create a license approval policy to enforce license compliance.
To create a license approval policy:
1. [Link a security policy project](../application_security/policies/index.md#managing-the-linked-security-policy-project) to your development group, subgroup, or project (the Owner role is required).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Secure > Policies**.
1. Create a new [Scan Result Policy](../application_security/policies/scan-result-policies.md).
1. In your policy rule, select **License scanning**.
diff --git a/doc/user/compliance/license_compliance/index.md b/doc/user/compliance/license_compliance/index.md
deleted file mode 100644
index 00578219016..00000000000
--- a/doc/user/compliance/license_compliance/index.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-type: reference, howto
-stage: Secure
-group: Composition Analysis
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../license_approval_policies.md'
----
-
-# License Compliance (removed) **(ULTIMATE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387561) in GitLab 15.9
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/421363) in GitLab 16.3.
-Use [License Approval Policies](https://gitlab.com/groups/gitlab-org/-/epics/8092) instead.
diff --git a/doc/user/compliance/license_list.md b/doc/user/compliance/license_list.md
index 96ea43e5ce2..f315f319b71 100644
--- a/doc/user/compliance/license_list.md
+++ b/doc/user/compliance/license_list.md
@@ -20,7 +20,7 @@ requirements must be met:
Alternatively, licenses will also appear under the license list when using our deprecated [`License-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml) as long as the following requirements are met:
-1. The Dependency Scanning CI/CD job must be [enabled](license_scanning_of_cyclonedx_files/index.md#enable-license-scanning) for your project.
+1. The Dependency Scanning CI/CD job must be [enabled](license_scanning_of_cyclonedx_files/index.md#configuration) for your project.
1. Your project must use at least one of the
[supported languages and package managers](license_scanning_of_cyclonedx_files/index.md#supported-languages-and-package-managers).
diff --git a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md
index 97f9f277776..98404ecd2ed 100644
--- a/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md
+++ b/doc/user/compliance/license_scanning_of_cyclonedx_files/index.md
@@ -7,13 +7,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# License scanning of CycloneDX files **(ULTIMATE ALL)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384932) in GitLab 15.9 for GitLab SaaS [with two flags](../../../administration/feature_flags.md) named `license_scanning_sbom_scanner` and `package_metadata_synchronization`. Both flags are disabled by default and both flags must be enabled for this feature to work.
-> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/385173) in GitLab 15.10 for GitLab SaaS.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/385173) in GitLab 15.10 for self-managed GitLab [with two flags](../../../administration/feature_flags.md) named `license_scanning_sbom_scanner` and `package_metadata_synchronization`, both of which must be enabled for this feature to work. The flags are disabled by default due to the initial performance load when the license database is first imported. Work to improve performance is being tracked in [issue 397670](https://gitlab.com/gitlab-org/gitlab/-/issues/397670).
-> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/385173) in GitLab 15.11 for self-managed GitLab.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/384932) in GitLab 15.9 for GitLab SaaS [with two flags](../../../administration/feature_flags.md) named `license_scanning_sbom_scanner` and `package_metadata_synchronization`. Both flags disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/385176) in GitLab 16.4. Feature flags `license_scanning_sbom_scanner` and `package_metadata_synchronization` removed.
-FLAG:
-The legacy License Compliance analyzer was deprecated in GitLab 15.9 and removed in GitLab 16.3. To continue using GitLab for License Compliance, remove the License Compliance template from your CI/CD pipeline and add the [Dependency Scanning template](../../application_security/dependency_scanning/index.md#configuration). The Dependency Scanning template is now capable of gathering the required license information so it is no longer necessary to run a separate License Compliance job. The License Compliance CI/CD template should not be removed prior to verifying that the `license_scanning_sbom_scanner` and `package_metadata_synchronization` flags are enabled for the instance and that the instance has been upgraded to a version that supports the new method of license scanning. To begin using the Dependency Scanner quickly at scale, you may set up a [scan execution policy](../../application_security/policies/scan-execution-policies.md) at the group level to enforce the SBOM-based license scan for all projects in the group. Then, you may remove the inclusion of the `Jobs/License-Scanning.gitlab-ci.yml` template from your CI/CD configuration. If you wish to continue using the legacy License Compliance feature, you can do so by setting the `LICENSE_MANAGEMENT_VERSION CI` variable to `4`. This variable can be set at the [project](../../../ci/variables/index.md#for-a-project), [group](../../../ci/variables/index.md#for-a-group) or [instance](../../../ci/variables/index.md#for-an-instance) level. This configuration change will allow you to continue using an existing version of the License Compliance without having to adopt the new approach. **Bugs and vulnerabilities in this legacy analyzer will no longer be fixed.**
+NOTE:
+The legacy License Compliance analyzer was deprecated in GitLab 15.9 and removed in GitLab 16.3. To continue using GitLab for License Compliance, remove the License Compliance template from your CI/CD pipeline and add the [Dependency Scanning template](../../application_security/dependency_scanning/index.md#configuration). The Dependency Scanning template is now capable of gathering the required license information so it is no longer necessary to run a separate License Compliance job. The License Compliance CI/CD template should not be removed prior to verifying that the instance has been upgraded to a version that supports the new method of license scanning. To begin using the Dependency Scanner quickly at scale, you may set up a [scan execution policy](../../application_security/policies/scan-execution-policies.md) at the group level to enforce the SBOM-based license scan for all projects in the group. Then, you may remove the inclusion of the `Jobs/License-Scanning.gitlab-ci.yml` template from your CI/CD configuration. If you wish to continue using the legacy License Compliance feature, you can do so by setting the `LICENSE_MANAGEMENT_VERSION CI` variable to `4`. This variable can be set at the [project](../../../ci/variables/index.md#for-a-project), [group](../../../ci/variables/index.md#for-a-group) or [instance](../../../ci/variables/index.md#for-an-instance) level. This configuration change will allow you to continue using the existing version of License Compliance to generate [license scanning report](../../../ci/yaml/artifacts_reports.md#artifactsreportslicense_scanning) artifacts in your pipelines. However, since legacy license scanning support is being removed from our codebase, switching back to this legacy analyzer prevents other License Compliance features from working as expected, so this approach is not recommended. In addition to this, **bugs and vulnerabilities in this legacy analyzer will no longer be fixed.**
To detect the licenses in use, License Compliance relies on running the
[Dependency Scanning CI Jobs](../../application_security/dependency_scanning/index.md),
@@ -22,17 +20,16 @@ Other 3rd party scanners may also be used as long as they produce a CycloneDX fi
This method of scanning is also capable of parsing and identifying over 500 different types of licenses, as defined in [the SPDX list](https://spdx.org/licenses/).
Licenses not in the SPDX list are reported as "Unknown". License information can also be extracted from packages that are dual-licensed, or have multiple different licenses that apply.
-## Enable license scanning
+## Configuration
-Prerequisites:
-
-- On GitLab self-managed only, enable [Synchronization with the GitLab License Database](../../../administration/settings/security_and_compliance.md#choose-package-registry-metadata-to-sync) in Admin Area for the GitLab instance. On GitLab SaaS this step has already been completed.
-- Enable [Dependency Scanning](../../application_security/dependency_scanning/index.md#configuration)
- and ensure that its prerequisites are met.
+Enable [Dependency Scanning](../../application_security/dependency_scanning/index.md#configuration)
+and ensure that its prerequisites are met.
From the `.gitlab-ci.yml` file, remove the deprecated line `Jobs/License-Scanning.gitlab-ci.yml`, if
it's present.
+On GitLab self-managed only, you can [choose package registry metadata to sync](../../../administration/settings/security_and_compliance.md#choose-package-registry-metadata-to-sync) in the Admin Area for the GitLab instance.
+
## Supported languages and package managers
License scanning is supported for the following languages and package managers:
@@ -164,3 +161,29 @@ gemnasium-dependency_scanning:
- apk update && apk add jq
- jq '.components |= unique' gl-sbom-gem-bundler.cdx.json > tmp.json && mv tmp.json gl-sbom-gem-bundler.cdx.json
```
+
+### Remove unused license data
+
+License scanning changes (released in GitLab 15.9) required a significant amount of additional disk space to be available on the instances. This issue was resolved in GitLab 16.3 by the [Reduce package metadata table on-disk footprint](https://gitlab.com/groups/gitlab-org/-/epics/10415) epic. But if your instance was running license scanning between GitLab 15.9 and 16.3, you may want to remove the unneeded data.
+
+To remove the unneeded data:
+
+1. Check if the [package_metadata_synchronization](https://about.gitlab.com/releases/2023/02/22/gitlab-15-9-released/#new-license-compliance-scanner) feature flag is currently, or was previously enabled, and if so, disable it. Use [Rails console](../../../administration/operations/rails_console.md) to execute the following commands.
+
+ ```ruby
+ Feature.enabled?(:package_metadata_synchronization) && Feature.disable(:package_metadata_synchronization)
+ ```
+
+1. Check if there is deprecated data in the database:
+
+ ```ruby
+ PackageMetadata::PackageVersionLicense.count
+ PackageMetadata::PackageVersion.count
+ ```
+
+1. If there is deprecated data in the database, remove it by running the following commands in order:
+
+ ```ruby
+ PackageMetadata::PackageVersionLicense.delete_all
+ PackageMetadata::PackageVersion.delete_all
+ ```
diff --git a/doc/user/crm/index.md b/doc/user/crm/index.md
index 53add75ee19..46e395af5bc 100644
--- a/doc/user/crm/index.md
+++ b/doc/user/crm/index.md
@@ -36,7 +36,7 @@ you must enable CRM features for the subgroup.
To enable customer relations management in a group or subgroup:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group or subgroup.
+1. On the left sidebar, select **Search or go to** and find your group or subgroup.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Select **Customer relations is enabled**.
@@ -52,7 +52,7 @@ Prerequisites:
To view a group's contacts:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer contacts**.
![Contacts list](crm_contacts_v14_10.png)
@@ -65,7 +65,7 @@ Prerequisites:
To create a contact:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer contacts**.
1. Select **New contact**.
1. Complete all required fields.
@@ -82,7 +82,7 @@ Prerequisites:
To edit an existing contact:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer contacts**.
1. Next to the contact you wish to edit, select **Edit** (**{pencil}**).
1. Edit the required fields.
@@ -100,7 +100,7 @@ Each contact can be in one of two states:
To change the state of a contact:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer contacts**.
1. Next to the contact you wish to edit, select **Edit** (**{pencil}**).
1. Select or clear the **Active** checkbox.
@@ -116,7 +116,7 @@ Prerequisites:
To view a group's organizations:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer organizations**.
![Organizations list](crm_organizations_v14_10.png)
@@ -129,7 +129,7 @@ Prerequisites:
To create an organization:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer organizations**.
1. Select **New organization**.
1. Complete all required fields.
@@ -146,7 +146,7 @@ Prerequisites:
To edit an existing organization:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer organizations**.
1. Next to the organization you wish to edit, select **Edit** (**{pencil}**).
1. Edit the required fields.
@@ -168,7 +168,7 @@ Prerequisites:
To view a contact's issues, select a contact from the issue sidebar, or:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer contacts**.
1. Next to the contact whose issues you wish to view, select **View issues** (**{issues}**).
@@ -180,7 +180,7 @@ Prerequisites:
To view an organization's issues:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Customer organizations**.
1. Next to the organization whose issues you wish to view, select **View issues** (**{issues}**).
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 0bdbfe79775..9d4a151cc53 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -13,7 +13,7 @@ type: reference, howto
> - Paginated merge request discussions [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/370075) in GitLab 15.8. Feature flag `paginated_mr_discussions` removed.
GitLab encourages communication through comments, threads, and
-[code suggestions](../project/merge_requests/reviews/suggestions.md).
+[Code Suggestions](../project/merge_requests/reviews/suggestions.md).
Two types of comments are available:
@@ -275,3 +275,29 @@ To create a thread:
A threaded comment is created.
![Thread comment](img/discussion_comment.png)
+
+## Resolve a thread
+
+> - Resolvable threads for issues [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31114) in GitLab 16.3 [with a flag](../../administration/feature_flags.md) named `resolvable_issue_threads`. Disabled by default.
+> - Resolvable threads for issues [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/31114) in GitLab 16.4.
+
+FLAG:
+On self-managed GitLab, resolvable threads _for issues_ are available by default.
+To hide the feature, an administrator can
+[disable the feature flag](../../administration/feature_flags.md) named `resolvable_issue_threads`.
+On GitLab.com, this feature is available.
+
+You can resolve a thread when you want to finish a conversation.
+
+Prerequisites:
+
+- You must be in an issue or merge request.
+- You must have at least the Developer role or be the author of the issue or merge request.
+
+To resolve a thread:
+
+1. Go to the thread.
+1. Do one of the following:
+ - In the upper-right corner of the original comment, select **Resolve thread** (**{check-circle}**).
+ - Below the last reply, in the **Reply** field, select **Resolve thread**.
+ - Below the last reply, in the **Reply** field, enter text, select the **Resolve thread** checkbox, and select **Add comment now**.
diff --git a/doc/user/enterprise_user/index.md b/doc/user/enterprise_user/index.md
index e7be5bfb140..04683620ba9 100644
--- a/doc/user/enterprise_user/index.md
+++ b/doc/user/enterprise_user/index.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
@@ -79,7 +79,7 @@ For more information on group-level domain verification, see [epic 5299](https:/
The custom domain must match the email domain exactly. For example, if your email is `username@example.com`, verify the `example.com` domain.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your top-level group.
+1. On the left sidebar, select **Search or go to** and find your top-level group.
1. Select **Settings > Domain Verification**.
1. In the upper-right corner, select **Add Domain**.
1. In **Domain**, enter the domain name.
@@ -105,7 +105,7 @@ and paste them in your domain's control panel as a `TXT` record.
After you have added all the DNS records:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Domain Verification**.
1. On the domain table row, Select **Retry verification** (**{retry}**).
@@ -125,7 +125,7 @@ For GitLab instances with domain verification enabled, if the domain cannot be v
To view all configured domains in your group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your top-level group.
+1. On the left sidebar, select **Search or go to** and find your top-level group.
1. Select **Settings > Domain Verification**.
You then see:
@@ -138,7 +138,7 @@ You then see:
To edit or remove a domain:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your top-level group.
+1. On the left sidebar, select **Search or go to** and find your top-level group.
1. Select **Settings > Domain Verification**.
1. When viewing **Domain Verification**, select the project listed next to the relevant domain.
1. Edit or remove a domain following the relevant [GitLab Pages custom domains](../project/pages/custom_domains_ssl_tls_certification/index.md) instructions.
@@ -159,7 +159,7 @@ Top-level group Owners can disable two-factor authentication (2FA) for enterpris
To disable 2FA:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Find a user with the **Enterprise** and **2FA** badges.
1. Select **More actions** (**{ellipsis_v}**) and select **Disable two-factor authentication**.
diff --git a/doc/user/free_user_limit.md b/doc/user/free_user_limit.md
index 0af5c76ade8..c978105c13b 100644
--- a/doc/user/free_user_limit.md
+++ b/doc/user/free_user_limit.md
@@ -25,7 +25,7 @@ Prerequisite:
- You must have the Owner role for the group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Settings > Usage Quotas**.
1. To view all members, select the **Seats** tab.
1. To remove a member, select **Remove user**.
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index 47f6e0ac1d9..09e05538fd7 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -18,7 +18,7 @@ GitLab.com has the:
- [`email_confirmation_setting`](../../administration/settings/sign_up_restrictions.md#confirm-user-email)
setting set to **Hard**.
- [`unconfirmed_users_delete_after_days`](../../administration/moderate_users.md#automatically-delete-unconfirmed-users)
- setting set to one day.
+ setting set to three days.
## Password requirements
@@ -82,7 +82,7 @@ The IP addresses for `mg.gitlab.com` are subject to change at any time.
On GitLab.com, there's a mailbox configured for Service Desk with the email address:
`contact-project+%{key}@incoming.gitlab.com`. To use this mailbox, configure the
-[custom suffix](../project/service_desk/index.md#configure-a-suffix-for-service-desk-alias-email) in project
+[custom suffix](../project/service_desk/configure.md#configure-a-suffix-for-service-desk-alias-email) in project
settings.
## Backups
@@ -217,7 +217,7 @@ the default value [is the same as for self-managed instances](../../administrati
| Maximum remote file size for imports from external object storages | 10 GB |
| Maximum download file size when importing from source GitLab instances by direct transfer | 5 GB |
| Maximum attachment size | 100 MB |
-| [Maximum decompressed file size for imported archives](../../administration/settings/account_and_limit_settings.md#maximum-decompressed-file-size-for-imported-archives) | 25 GB |
+| [Maximum decompressed file size for imported archives](../../administration/settings/import_and_export_settings.md#maximum-decompressed-file-size-for-imported-archives) | 25 GB |
If you are near or over the repository size limit, you can either
[reduce your repository size with Git](../project/repository/reducing_the_repo_size_using_git.md)
@@ -225,7 +225,7 @@ or [purchase additional storage](https://about.gitlab.com/pricing/licensing-faq/
NOTE:
`git push` and GitLab project imports are limited to 5 GB per request through
-Cloudflare. Git LFS and imports other than a file upload are not affected by
+Cloudflare. Imports other than a file upload are not affected by
this limit. Repository limits apply to both public and private projects.
## Default import sources
@@ -236,7 +236,7 @@ The import sources that are available by default depend on which GitLab you use:
- GitLab.com: all available import sources are enabled by default.
- GitLab self-managed: no import sources are enabled by default and must be
- [enabled](../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources).
+ [enabled](../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources).
| Import source | GitLab.com default | GitLab self-managed default |
|:----------------------------------------------------------------------------------------------------|:-----------------------|:----------------------------|
diff --git a/doc/user/group/access_and_permissions.md b/doc/user/group/access_and_permissions.md
index 0ccd4512039..428c87143f6 100644
--- a/doc/user/group/access_and_permissions.md
+++ b/doc/user/group/access_and_permissions.md
@@ -46,7 +46,7 @@ configured by an administrator.
To change the permitted Git access protocols for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Choose the permitted protocols from **Enabled Git access protocols**.
@@ -71,7 +71,7 @@ Administrators can combine restricted access by IP address with
To restrict group access by IP address:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. In the **Restrict access by IP address** text box, enter a list of IPv4 or IPv6
@@ -102,6 +102,15 @@ Keep in mind that restricting group access by IP address has the following impli
IP access restrictions applied to self-managed instances are possible with [`gitlab-sshd`](../../administration/operations/gitlab_sshd.md)
with [PROXY protocol](../../administration/operations/gitlab_sshd.md#proxy-protocol-support) enabled.
- IP restriction is not applicable to shared resources belonging to a group. Any shared resource is accessible to a user even if that user is not able to access the group.
+- While IP restrictions apply to public projects, they aren't a complete firewall and cached files for a project may still be accessible to users not in the IP block
+
+### GitLab.com access restrictions
+
+On GitLab.com shared runners are added to the [global allowlist](../../administration/settings/visibility_and_access_controls.md#configure-globally-allowed-ip-address-ranges), so that they are available regardless of IP restrictions.
+
+Artifact and Registry downloading from runners is sourced from any Google or, in the case of MacOS runners, Amazon IP address in that region.
+The download is therefore not added to the global allowlist.
+To allow runner downloading, add the [outbound runner CIDR ranges](../gitlab_com/index.md#ip-range) to your group allowlist.
## Restrict group access by domain **(PREMIUM ALL)**
@@ -113,7 +122,7 @@ You can prevent users with email addresses in specific domains from being added
To restrict group access by domain:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. In the **Restrict membership by email** field, enter the domain names.
@@ -157,7 +166,7 @@ If you prevent group sharing outside the hierarchy for the **Animals** group:
To prevent sharing outside of the group's hierarchy:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Select **Members cannot invite groups outside of `<group_name>` and its subgroups**.
@@ -173,7 +182,7 @@ which can be confusing and difficult to control.
To restrict the permission to invite project members to a single source,
prevent a project from being shared with other groups:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Select **Projects in `<group_name>` cannot be shared with other groups**.
@@ -187,7 +196,7 @@ added to a project lose access when the setting is enabled.
As a group Owner, you can prevent non-members from requesting access to
your group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Clear the **Allow users to request access** checkbox.
@@ -207,7 +216,7 @@ If even one is set to `true`, then the group does not allow outside forks.
To prevent projects from being forked outside the group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Check **Prevent project forking outside current group**.
@@ -232,7 +241,7 @@ The setting does not cascade. Projects in subgroups observe the subgroup configu
To prevent members from being added to projects in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Under **Membership**, select **Users cannot be added to projects in this group**.
@@ -254,7 +263,7 @@ For more information on the administration of LDAP and group sync, refer to the
NOTE:
When you add LDAP synchronization, if an LDAP user is a group member and they are not part of the LDAP group, they are removed from the group.
-You can use a workaround to [manage project access through LDAP groups](../project/settings/index.md#manage-project-access-through-ldap-groups).
+You can use a workaround to [manage project access through LDAP groups](../project/working_with_projects.md#manage-project-access-through-ldap-groups).
### Create group links via CN **(PREMIUM SELF)**
@@ -284,7 +293,7 @@ To create group links via filter:
LDAP user permissions can be manually overridden by an administrator. To override a user's permissions:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Manage > Members**. If LDAP synchronization
has granted a user a role with:
- More permissions than the parent group membership, that user is displayed as having
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index e41991f365c..5c0844dff92 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -21,7 +21,7 @@ your group, enabling you to use the same cluster across multiple projects.
To view your group-level Kubernetes clusters:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Operate > Kubernetes**.
## Cluster management project
@@ -89,7 +89,7 @@ your cluster, which can cause deployment jobs to fail.
To clear the cache:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Operate > Kubernetes**.
1. Select your cluster.
1. Expand **Advanced settings**.
diff --git a/doc/user/group/compliance_frameworks.md b/doc/user/group/compliance_frameworks.md
index 35e8ad27bc3..7258791a983 100644
--- a/doc/user/group/compliance_frameworks.md
+++ b/doc/user/group/compliance_frameworks.md
@@ -15,7 +15,7 @@ requirements or needs additional oversight. The label can optionally enforce
Compliance frameworks are created on top-level groups. Group owners can create, edit, and delete compliance frameworks:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. Create, edit, or delete compliance frameworks.
@@ -31,7 +31,7 @@ Prerequisite:
To assign a compliance framework to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings** > **General**.
1. Expand **Compliance frameworks**.
1. Select a compliance framework.
@@ -66,7 +66,7 @@ A compliance framework that is set to default has a **default** label.
Group owners can set a compliance framework as default (or remove the setting):
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Compliance frameworks** section and locate the compliance framework to set (or remove) as default.
1. Select the vertical ellipsis (**{ellipsis_v}**) for the compliance frame and then select **Set default** (or
@@ -155,7 +155,7 @@ Therefore, communicate with project users about compliance pipeline configuratio
To configure a compliance pipeline:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. In **Compliance pipeline configuration (optional)**, add the path to the compliance framework configuration. Use the
@@ -165,7 +165,7 @@ To configure a compliance pipeline:
- `.compliance-ci.yaml@gitlab-org/gitlab`.
This configuration is inherited by projects where the compliance framework label is
-[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance
+[applied](../project/working_with_projects.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance
framework label, the compliance pipeline configuration is run instead of the labeled project's own pipeline configuration.
The user running the pipeline in the labeled project must at least have the Reporter role on the compliance project.
diff --git a/doc/user/group/contribution_analytics/index.md b/doc/user/group/contribution_analytics/index.md
index 9716143f5e2..96cc9ce974c 100644
--- a/doc/user/group/contribution_analytics/index.md
+++ b/doc/user/group/contribution_analytics/index.md
@@ -20,7 +20,7 @@ Use contribution analytics data visualizations to:
To view contribution analytics:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Contribution analytics**.
Three bar charts and a table illustrate the number of contributions made by each group member:
diff --git a/doc/user/group/custom_project_templates.md b/doc/user/group/custom_project_templates.md
index 1a481641111..87c1c548abd 100644
--- a/doc/user/group/custom_project_templates.md
+++ b/doc/user/group/custom_project_templates.md
@@ -40,7 +40,7 @@ Projects in nested subgroups are not included in the template list.
## Which projects are available as templates
- Public and internal projects can be selected by any authenticated user as a template for a new project,
- if all [project features](../project/settings/index.md#configure-project-visibility-features-and-permissions)
+ if all [project features](../project/settings/index.md#configure-project-features-and-permissions)
except for **GitLab Pages** and **Security and Compliance** are set to **Everyone With Access**.
- Private projects can be selected only by users who are members of the projects.
@@ -69,6 +69,35 @@ gitlab.com/myorganization/
...
```
+## What is copied from the templates
+
+The entire custom instance-level project templates repository is copied, including:
+
+- Branches
+- Commits
+- Tags
+
+If the user:
+
+- Has the Owner role on the custom instance-level project templates project or is a GitLab administrator,
+ all project settings are copied over to the new project.
+- Doesn't have the Owner role or is not a GitLab administrator,
+ project deploy keys and project webhooks aren't copied over because they contain sensitive data.
+
+To learn more about what is migrated, see
+[Items that are exported](../project/settings/import_export.md#items-that-are-exported).
+
+## User assignments in templates
+
+When you use a template created by another user, any items that were assigned
+to a user in the template are reassigned to you. It's important to understand
+this reassignment when you configure security features like protected branches
+and tags. For example, if the template contains a protected branch:
+
+- In the template, the branch allows the _template owner_ to merge into the default branch.
+- In the project created from the template, the branch allows _you_ to merge into
+ the default branch.
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/group/devops_adoption/index.md b/doc/user/group/devops_adoption/index.md
index 852d26f3816..5359d7b52a0 100644
--- a/doc/user/group/devops_adoption/index.md
+++ b/doc/user/group/devops_adoption/index.md
@@ -36,7 +36,7 @@ Prerequisite:
To view DevOps Adoption:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > DevOps adoption**
## DevOps Adoption categories
@@ -80,7 +80,7 @@ twelve months. The chart only shows data from when you enabled DevOps Adoption f
To view feature adoption over time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > DevOps adoption**.
1. Select the **Overview** tab.
diff --git a/doc/user/group/epics/epic_boards.md b/doc/user/group/epics/epic_boards.md
index 41231db5964..69b64861bd5 100644
--- a/doc/user/group/epics/epic_boards.md
+++ b/doc/user/group/epics/epic_boards.md
@@ -25,7 +25,7 @@ On the top of each list, you can see the number of epics in the list (**{epic}**
To view an epic board:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Epic boards**.
![GitLab epic board - Premium](img/epic_board_v15_10.png)
@@ -38,7 +38,7 @@ Prerequisites:
To create a new epic board:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Epic boards**.
1. In the upper-left corner, select the dropdown list with the current board name.
1. Select **Create new board**.
@@ -87,7 +87,7 @@ Prerequisites:
To create a new list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Epic boards**.
1. In the upper-right corner, select **Create list**.
1. In the **New list** column expand the **Select a label** dropdown list and select the label to use as
diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md
index e6116151012..b79177e1571 100644
--- a/doc/user/group/epics/manage_epics.md
+++ b/doc/user/group/epics/manage_epics.md
@@ -209,7 +209,7 @@ Prerequisites:
To view epics in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Epics**.
### Who can view an epic
@@ -254,7 +254,7 @@ You can filter the list of epics by:
To filter:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Epics**.
1. Select the field **Search or filter results**.
1. From the dropdown list, select the scope or enter plain text to search by epic title or description.
diff --git a/doc/user/group/import/index.md b/doc/user/group/import/index.md
index b645ea04038..a049b4afcc1 100644
--- a/doc/user/group/import/index.md
+++ b/doc/user/group/import/index.md
@@ -30,7 +30,7 @@ If you migrate from GitLab.com to self-managed GitLab, an administrator can crea
> - `bulk_import_projects` feature flag [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/339941) in GitLab 15.10.
On self-managed GitLab, by default [migrating group items](#migrated-group-items) is not available. To show the
-feature, an administrator can [enable it in application settings](../../../administration/settings/visibility_and_access_controls.md#enable-migration-of-groups-and-projects-by-direct-transfer).
+feature, an administrator can [enable it in application settings](../../../administration/settings/import_and_export_settings.md#enable-migration-of-groups-and-projects-by-direct-transfer).
Migrating groups by direct transfer copies the groups from one place to another. You can:
@@ -47,7 +47,7 @@ Migrating groups by direct transfer copies the groups from one place to another.
Not all group and project resources are copied. See list of copied resources below:
- [Migrated group items](#migrated-group-items).
-- [Migrated project items](#migrated-project-items-beta).
+- [Migrated project items](#migrated-project-items).
WARNING:
Importing groups with projects is in [Beta](../../../policy/experiment-beta-support.md#beta). This feature is not
@@ -157,16 +157,20 @@ To migrate groups by direct transfer:
- The network connection between instances or GitLab.com must support HTTPS.
- Any firewalls must not block the connection between the source and destination GitLab instances.
- Both GitLab instances must have group migration by direct transfer
- [enabled in application settings](../../../administration/settings/visibility_and_access_controls.md#enable-migration-of-groups-and-projects-by-direct-transfer)
+ [enabled in application settings](../../../administration/settings/import_and_export_settings.md#enable-migration-of-groups-and-projects-by-direct-transfer)
by an instance administrator.
- The source GitLab instance must be running GitLab 14.0 or later.
-- You must have a [personal access token](../../../user/profile/personal_access_tokens.md) for the source GitLab
- instance:
- - For GitLab 15.1 and later source instances, the personal access token must have the `api` scope.
- - For GitLab 15.0 and earlier source instances, the personal access token must have both the `api` and
- `read_repository` scopes.
+- You must have a
+ [personal access token](../../../user/profile/personal_access_tokens.md) for
+ the source GitLab instance:
+ - For GitLab 15.1 and later source instances, the personal access token must
+ have the `api` scope.
+ - For GitLab 15.0 and earlier source instances, the personal access token must
+ have both the `api` and `read_repository` scopes.
- You must have the Owner role on the source group to migrate from.
-- You must have at least the Maintainer role on the destination group to migrate to.
+- Your must have a role on the destination namespace the enables you to
+ [create a subgroup](../../group/subgroups/index.md#create-a-subgroup) in that
+ namespace.
### Prepare user accounts
@@ -287,7 +291,7 @@ Some group items are excluded from migration because they either:
- May contain sensitive information: CI/CD variables, webhooks, and deploy tokens.
- Are not supported: push rules.
-### Migrated project items (Beta)
+### Migrated project items **(BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/267945) in GitLab 14.4 [with a flag](../../feature_flags.md) named `bulk_import_projects`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/339941) in GitLab 15.6.
@@ -460,7 +464,7 @@ To solve this, you must change the source group path to include a non-numerical
- The GitLab UI:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+ 1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. Under **Change group URL**, change the group URL to include non-numeric characters.
@@ -593,7 +597,7 @@ Prerequisite:
To enable import and export for a group:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand **Visibility and access controls**.
@@ -607,7 +611,7 @@ Prerequisites:
To export the contents of a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. In the **Advanced** section, select **Export group**.
1. After the export is generated, you should receive an email with a link to the [exported contents](#exported-contents)
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 13fba43f8ef..484fd8c533b 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -49,14 +49,14 @@ the immediate parent group.
To explore all public groups:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your groups**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my groups**.
1. At the top right, select **Explore groups**.
To view groups where you have a direct or indirect membership:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your groups**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my groups**.
This page shows groups that you are a member of:
@@ -67,7 +67,7 @@ This page shows groups that you are a member of:
To view the activity of a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Activity**.
1. Optional. To filter activity by contribution type, select a tab:
@@ -106,7 +106,7 @@ For details about groups, watch [GitLab Namespaces (users, groups and subgroups)
To remove a group and its contents:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Advanced** section.
1. In the **Remove group** section, select **Remove group**.
@@ -115,8 +115,8 @@ To remove a group and its contents:
A group can also be removed from the groups dashboard:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your groups**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my groups**.
1. Select (**{ellipsis_v}**) for the group you want to delete.
1. Select **Delete**.
1. In the Remove group section, select **Remove group**.
@@ -143,7 +143,7 @@ Prerequisites:
To immediately remove a group marked for deletion:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. In the "Permanently remove group" section, select **Remove group**.
@@ -158,7 +158,7 @@ are deleted.
To restore a group that is marked for deletion:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Advanced** section.
1. In the Restore group section, select **Restore group**.
@@ -167,10 +167,12 @@ To restore a group that is marked for deletion:
As a user, you can request to be a member of a group, if an administrator allows it.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your groups**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my groups**.
1. At the top right side, select **Explore groups**.
-1. Under the group name, select **Request Access**.
+1. Search for the group by name.
+1. In the search results, select the name of the group.
+1. On the group page, under the group name, select **Request Access**.
As many as ten of the most-recently-active group owners receive an email with your request.
Any group owner can approve or decline the request.
@@ -182,7 +184,7 @@ If you change your mind before your request is approved, select
To view a group's members:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
A table displays the member's:
@@ -219,7 +221,7 @@ In lists of group members, entries can display the following badges:
- **SAML**, to indicate the member has a [SAML account](saml_sso/index.md) connected to them.
- **Enterprise**, to indicate that the member is an [enterprise user](../enterprise_user/index.md).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Above the list of members, in the **Filter members** box, enter filter criteria.
- To view members in the group only, select **Membership = Direct**.
@@ -231,7 +233,7 @@ In lists of group members, entries can display the following badges:
You can search for members by name, username, or [public email](../profile/index.md#set-your-public-email).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Above the list of members, in the **Filter members** box, enter search criteria.
1. To the right of the **Filter members** box, select the magnifying glass (**{search}**).
@@ -240,7 +242,7 @@ You can search for members by name, username, or [public email](../profile/index
You can sort members by **Account**, **Access granted**, **Max role**, or **Last sign-in**.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Above the list of members, in the upper-right corner, from the **Account** list, select
the criteria to filter by.
@@ -257,7 +259,7 @@ Prerequisite:
- You must have the Owner role.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Select **Invite members**.
1. Fill in the fields.
@@ -287,7 +289,7 @@ Prerequisites:
To remove a member from a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Next to the member you want to remove, select the vertical ellipsis (**{ellipsis_v}**).
1. Select **Remove member**.
@@ -325,7 +327,7 @@ By default, users with:
To change the role that can create projects under a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Select the desired option in the **Roles allowed to create projects** dropdown list.
diff --git a/doc/user/group/insights/index.md b/doc/user/group/insights/index.md
index 5cb982a85e4..2ded1b08de2 100644
--- a/doc/user/group/insights/index.md
+++ b/doc/user/group/insights/index.md
@@ -23,7 +23,7 @@ Prerequisites:
To access your group's insights:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Insights**.
## Interact with insights charts
@@ -65,7 +65,7 @@ To configure group insights:
1. Create a new file [`.gitlab/insights.yml`](../../project/insights/index.md#configure-project-insights)
in a project that belongs to your group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Analytics** and find the **Insights** section.
1. Select the project that contains your `.gitlab/insights.yml` configuration file.
diff --git a/doc/user/group/issues_analytics/img/issues_closed_analytics_v16_4.png b/doc/user/group/issues_analytics/img/issues_closed_analytics_v16_4.png
new file mode 100644
index 00000000000..5e1fe4eaa8c
--- /dev/null
+++ b/doc/user/group/issues_analytics/img/issues_closed_analytics_v16_4.png
Binary files differ
diff --git a/doc/user/group/issues_analytics/index.md b/doc/user/group/issues_analytics/index.md
index 46ba1747b06..4f1c7b4be7a 100644
--- a/doc/user/group/issues_analytics/index.md
+++ b/doc/user/group/issues_analytics/index.md
@@ -1,7 +1,7 @@
---
type: reference
stage: Plan
-group: Project Management
+group: Optimize
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -15,9 +15,11 @@ prior.
To access the chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Analyze > Issue analytics**.
+You can also access the chart from the [Value Streams Dashboard](../../analytics/value_streams_dashboard.md) through the **New issues** drill-down report.
+
Hover over each bar to see the total number of issues.
To narrow the scope of issues included in the graph, enter your criteria in the
@@ -36,6 +38,20 @@ shows a total of 15 months for the chart in the GitLab.org group.
![Issues created per month](img/issues_created_per_month_v12_8_a.png)
+## Enhanced issue analytics **(ULTIMATE ALL)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233905/) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `issues_completed_analytics_feature_flag`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, an administrator can
+[enable the feature flag](../../../administration/feature_flags.md) named `issues_completed_analytics_feature_flag`. On GitLab.com, this feature is not
+available. This feature is not ready for production use.
+
+Enhanced issue analytics display the additional metric "Issues closed", which represents the total number of resolved issues in your group over a selected period.
+You can use this metric to improve the overall turn-around time and value delivered to your customers.
+
+![Issues opened and closed per month](img/issues_closed_analytics_v16_4.png)
+
## Drill into the information
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196547) in GitLab 13.1.
diff --git a/doc/user/group/iterations/index.md b/doc/user/group/iterations/index.md
index 91e69f3a02d..8c0838cf33c 100644
--- a/doc/user/group/iterations/index.md
+++ b/doc/user/group/iterations/index.md
@@ -50,7 +50,7 @@ Prerequisites:
To create an iteration cadence:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Iterations**.
1. Select **New iteration cadence**.
1. Enter the title and description of the iteration cadence.
@@ -70,7 +70,7 @@ If you want to manually manage the created cadence, read [Manual Iteration Manag
### View the iterations list
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Iterations**.
To view all the iterations in a cadence, ordered by descending date, select that iteration cadence.
@@ -78,7 +78,7 @@ From there you can create a new iteration or select an iteration to get a more d
NOTE:
If a project has issue tracking
-[turned off](../../project/settings/index.md#configure-project-visibility-features-and-permissions),
+[turned off](../../project/settings/index.md#configure-project-features-and-permissions),
to view the iterations list, enter its URL. To do so, add: `/-/cadences` to your project or group URL.
For example `https://gitlab.com/gitlab-org/sample-data-templates/sample-gitlab-project/-/cadences`.
This is tracked in [issue 339009](https://gitlab.com/gitlab-org/gitlab/-/issues/339009).
@@ -91,7 +91,7 @@ Prerequisites:
To edit an iteration cadence:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Iterations**.
1. Select **Edit iteration cadence**.
@@ -105,7 +105,7 @@ doesn't delete the eight existing upcoming iterations.
#### Turn on and off automatic scheduling for an iteration cadence
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Iterations**.
1. Next to the cadence for which you want to turn on or off automatic scheduling, select the
three-dot menu (**{ellipsis_v}**) **> Edit cadence**.
@@ -157,7 +157,7 @@ Deleting an iteration cadence also deletes all iterations within that cadence.
To delete an iteration cadence:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Iterations**.
1. Select the three-dot menu (**{ellipsis_v}**) > **Delete cadence** for the cadence you want to delete.
1. Select **Delete cadence**.
@@ -178,7 +178,7 @@ Prerequisites:
To create an iteration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Plan > Iterations** and select an iteration cadence.
1. Select **New iteration**.
1. Enter the title, a description (optional), a start date, and a due date.
@@ -277,7 +277,7 @@ and get a more accurate understanding of scope attributable to each label.
To group issues by label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Iterations**.
1. In the **Group by** dropdown list, select **Label**.
1. Select the **Filter by label** dropdown list.
diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md
index 743aabd8f4b..65190847b05 100644
--- a/doc/user/group/manage.md
+++ b/doc/user/group/manage.md
@@ -29,7 +29,7 @@ Prerequisite:
To add a group README:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. In the **Group README** section, select **Add README**. This action creates a new project `gitlab-profile` that contains the `README.md` file.
1. On the prompt for creating a README, select **Create and add README**. You're redirected to the Web IDE, where a README file is created.
@@ -41,12 +41,12 @@ You can change the owner of a group. Each group must always have at least one
member with the Owner role.
- As an administrator:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+ 1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Give a different member the **Owner** role.
1. Refresh the page. You can now remove the **Owner** role from the original owner.
- As the current group's owner:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+ 1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Give a different member the **Owner** role.
1. Have the new owner sign in and remove the **Owner** role from you.
@@ -72,7 +72,7 @@ create a new group and transfer projects to it instead.
To change your group path (group URL):
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Advanced** section.
1. Under **Change group URL**, enter a new name.
@@ -130,14 +130,15 @@ After sharing the `Frontend` group with the `Engineering` group:
- The **Groups** tab lists the `Engineering` group.
- The **Groups** tab lists a group regardless of whether it is a public or private group.
-- All direct members of the `Engineering` group have access to the `Frontend` group. Direct members of `Engineering` that gain access to the `Frontend` group keep their same access level as in `Engineering`, but up to the maximum access level selected when sharing the group. Inherited members of the `Engineering` group do not gain access to the `Frontend` group.
+- All direct members of the `Engineering` group have access to the `Frontend` group. Direct members of `Engineering` that gain access to the `Frontend` group keep their same access level as in `Engineering`, but up to the maximum access level selected when sharing the group.
+- Inherited members of the `Engineering` group do not gain access to the `Frontend` group.
- Direct members of the `Engineering` group who have the **Group Invite** badge next to their profile on the group's usage quota page count towards the billable members of the `Frontend` group.
## Remove a shared group
To unshare a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
1. Select the **Groups** tab.
1. To the right of the account you want to remove, select **Remove group** (**{remove}**).
@@ -174,7 +175,7 @@ When transferring groups, note:
To transfer a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Advanced** section.
1. In the **Remove group** section, select **Transfer group**.
@@ -189,7 +190,7 @@ You can disable all email notifications related to the group, which includes its
To disable email notifications:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Select **Email notifications are disabled**.
@@ -209,7 +210,7 @@ This is particularly helpful for groups with a large number of users.
To disable group mentions:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Permissions and group features** section.
1. Select **Group mentions are disabled**.
@@ -222,7 +223,7 @@ To disable group mentions:
You can export a list of members in a group or subgroup as a CSV.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group or subgroup.
+1. On the left sidebar, select **Search or go to** and find your group or subgroup.
1. On the left sidebar, **Manage > Members**.
1. Select **Export as CSV**.
1. After the CSV file has been generated, it is emailed as an attachment to the user that requested it.
@@ -252,7 +253,7 @@ Prerequisite:
To specify a user cap:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
You can set a cap on the top-level group only.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
@@ -274,7 +275,7 @@ Prerequisite:
To remove the user cap:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. In the **User cap** box, delete the value.
@@ -295,7 +296,7 @@ Prerequisite:
To approve members that are pending because they've exceeded the user cap:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Settings > Usage Quotas**.
1. On the **Seats** tab, under the alert, select **View pending approvals**.
1. For each member you want to approve, select **Approve**.
@@ -336,7 +337,7 @@ For more information, see [group-level project templates](custom_project_templat
To enable group file templates:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Templates** section.
1. Choose a project to act as the template repository.
@@ -369,7 +370,7 @@ Prerequisites:
To enable this setting:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Merge requests**.
1. Under **Merge checks**, select **Pipelines must succeed**.
@@ -388,7 +389,7 @@ Prerequisite:
To change this behavior:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Merge requests**.
1. Under **Merge checks**:
@@ -407,7 +408,7 @@ Prerequisite:
To enable this setting:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Merge requests**.
1. Under **Merge checks**, select **All threads must be resolved**.
@@ -425,7 +426,7 @@ that belong to the group.
To view the merge request approval settings for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand the **Merge request approvals** section.
1. Select the settings you want.
@@ -443,19 +444,19 @@ for the ability to set merge request approval rules for groups is tracked in
WARNING:
This feature is in [Beta](../../policy/experiment-beta-support.md#beta).
-Beta users should read about the [known limitations](../project/repository/code_suggestions.md#known-limitations).
-We look forward to hearing your [feedback](../project/repository/code_suggestions.md#feedback).
+Beta users should read about the [known limitations](../project/repository/code_suggestions/index.md#known-limitations).
+We look forward to hearing your [feedback](../project/repository/code_suggestions/index.md#feedback).
-You can give all users in a group and its subgroups access to [Code Suggestions](../project/repository/code_suggestions.md).
+You can give all users in a group and its subgroups access to [Code Suggestions](../project/repository/code_suggestions/index.md).
- This setting
[cascades to all projects](../project/merge_requests/approvals/settings.md#settings-cascading) in the group.
- Each user can
- [enable or disable Code Suggestions for themselves](../project/repository/code_suggestions.md#enable-code-suggestions-for-an-individual-user).
+ [Enable Code Suggestions](../../user/profile/preferences.md#enable-code-suggestions).
To enable Code Suggestions for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Under **Code Suggestions**, select the **Projects in this group can use Code Suggestions** checkbox.
@@ -476,7 +477,7 @@ that belong to the group.
To enable Experiment features for a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Under **Experiment features**, select the **Use Experiment features** checkbox.
@@ -496,7 +497,7 @@ that belong to the group.
To disable third-party AI features for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Under **Third-party AI services**, uncheck the **Use third-party AI services** checkbox.
@@ -521,7 +522,7 @@ Changes to [group wikis](../project/wiki/group.md) do not appear in group activi
You can view the most recent actions taken in a group, either in your browser or in an RSS feed:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Manage > Activity**.
To view the activity feed in Atom format, select the
diff --git a/doc/user/group/moderate_users.md b/doc/user/group/moderate_users.md
index 7e67bb6ddb5..6859125b323 100644
--- a/doc/user/group/moderate_users.md
+++ b/doc/user/group/moderate_users.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/group/reporting/git_abuse_rate_limit.md b/doc/user/group/reporting/git_abuse_rate_limit.md
index abb967ad8b1..1b14edb04d9 100644
--- a/doc/user/group/reporting/git_abuse_rate_limit.md
+++ b/doc/user/group/reporting/git_abuse_rate_limit.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/group/repositories_analytics/index.md b/doc/user/group/repositories_analytics/index.md
index 3e7bacbb817..6f02b27a214 100644
--- a/doc/user/group/repositories_analytics/index.md
+++ b/doc/user/group/repositories_analytics/index.md
@@ -37,7 +37,7 @@ The **Analyze > Repository analytics** group page displays the average test cove
To see the latest code coverage for each project in your group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Repository analytics**.
1. In the **Latest test coverage results** section, from the **Select projects** dropdown list, choose the projects you want to check.
@@ -52,7 +52,7 @@ You can get a CSV of the code coverage data for all of the projects in your grou
To get the report:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Repository analytics**.
1. Select **Download historic test coverage data (.csv)**.
1. Select the projects and date range you want to include in the report.
diff --git a/doc/user/group/saml_sso/example_saml_config.md b/doc/user/group/saml_sso/example_saml_config.md
index c5f84510c57..70e01e1d9a9 100644
--- a/doc/user/group/saml_sso/example_saml_config.md
+++ b/doc/user/group/saml_sso/example_saml_config.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: reference
diff --git a/doc/user/group/saml_sso/group_sync.md b/doc/user/group/saml_sso/group_sync.md
index c3edc01fe74..335c989c85f 100644
--- a/doc/user/group/saml_sso/group_sync.md
+++ b/doc/user/group/saml_sso/group_sync.md
@@ -1,6 +1,6 @@
---
type: reference, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -155,10 +155,11 @@ To integrate Microsoft Azure AD, you:
To configure for a GitLab.com group:
-1. Configure [SAML SSO for the group](../../../user/group/saml_sso/index.md).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your top-level group.
+1. On the left sidebar, select **Search or go to** and find your top-level group.
1. Select **Settings > SAML SSO**.
+1. Configure [SAML SSO for the group](../../../user/group/saml_sso/index.md).
1. In the **Microsoft Azure integration** section, select the **Enable Microsoft Azure integration for this group** checkbox.
+ This section will only be visible if SAML SSO is configured and enabled for the group.
1. Enter the **Tenant ID**, **Client ID**, and **Client secret** obtained earlier when configuring Azure Active Directory in the Azure Portal.
1. Optional. If using Azure AD for US Government or Azure AD China, enter the appropriate **Login API endpoint** and **Graph API endpoint**. The default values work for most organizations.
1. Select **Save changes**.
@@ -166,7 +167,7 @@ To configure for a GitLab.com group:
To configure for self-managed:
1. Configure [SAML SSO for the instance](../../../integration/saml.md).
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. In the **Microsoft Azure integration** section, select the **Enable Microsoft Azure integration for this group** checkbox.
@@ -197,7 +198,7 @@ When global group memberships lock is enabled:
To enable global group memberships lock:
1. [Configure SAML](../../../integration/saml.md) for your self-managed GitLab instance.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 41c2090f4bc..734679cf331 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -38,7 +38,7 @@ If you are having issues setting up your identity provider, see the
To set up SSO with Azure as your identity provider:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > SAML SSO**.
1. Note the information on this page.
1. Go to Azure and [follow the instructions for configuring SSO for an application](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/add-application-portal-setup-sso). The following GitLab settings correspond to the Azure fields.
@@ -71,7 +71,7 @@ For more information, see an [example configuration page](example_saml_config.md
To set up Google Workspace as your identity provider:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > SAML SSO**.
1. Note the information on this page.
1. Follow the instructions for [setting up SSO with Google as your identity provider](https://support.google.com/a/answer/6087519?hl=en). The following GitLab settings correspond to the Google Workspace fields.
@@ -115,7 +115,7 @@ View a demo of [how to configure SAML with Google Workspaces and set up Group Sy
To set up SSO with Okta as your identity provider:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > SAML SSO**.
1. Note the information on this page.
1. Follow the instructions for [setting up a SAML application in Okta](https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/).
@@ -152,7 +152,7 @@ OneLogin supports its own [GitLab (SaaS) application](https://onelogin.service-n
To set up OneLogin as your identity provider:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > SAML SSO**.
1. Note the information on this page.
1. If you use the OneLogin generic
@@ -179,7 +179,7 @@ To set up OneLogin as your identity provider:
To configure some identity providers, you need a GitLab metadata URL.
To find this URL:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > SAML SSO**.
1. Copy the provided **GitLab metadata URL**.
1. Follow your identity provider's documentation and paste the metadata URL when it's requested.
@@ -217,7 +217,7 @@ If the **NameID** is configured with the email address, [change the **NameID** f
After you set up your identity provider to work with GitLab, you must configure GitLab to use it for authentication:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > SAML SSO**.
1. Complete the fields:
- In the **Identity provider single sign-on URL** field, enter the SSO URL from your identity provider.
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 9096824cc2c..a9b9bf26444 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -10,12 +10,14 @@ You can use the open standard System for Cross-domain Identity Management (SCIM)
- Create users.
- Remove users (deactivate SCIM identity).
+- Re-add users (reactivate SCIM identity).
GitLab SAML SSO SCIM doesn't support updating users.
When SCIM is enabled for a GitLab group, membership of that group is synchronized between GitLab and an identity provider.
The [internal GitLab group SCIM API](../../../development/internal_api/index.md#group-scim-api) implements part of [the RFC7644 protocol](https://www.rfc-editor.org/rfc/rfc7644).
+Identity providers can use the [internal GitLab group SCIM API](../../../development/internal_api/index.md#group-scim-api) to develop a SCIM app.
## Configure GitLab
@@ -25,7 +27,7 @@ Prerequisites:
To configure GitLab SAML SSO SCIM:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > SAML SSO**.
1. Select **Generate a SCIM token**.
1. For configuration of your identity provider, save the:
@@ -40,7 +42,7 @@ You can configure one of the following as an identity provider:
- [Okta](#configure-okta).
NOTE:
-Other providers can work with GitLab but they have not been tested and are not supported.
+Other providers can work with GitLab but they have not been tested and are not supported. You should contact the provider for support. GitLab support can assist by reviewing related log entries.
### Configure Azure Active Directory
@@ -165,7 +167,8 @@ To configure Okta for SCIM:
During the synchronization process, all new users:
- Receive GitLab accounts.
-- Are welcomed to their groups with an invitation email. You may want to warn your employees to expect this email.
+- Are welcomed to their groups with an invitation email.
+ You can [bypass email confirmation with a verified domain](index.md#bypass-user-email-confirmation-with-verified-domains).
The following diagram describes what happens when you add users to your SCIM app:
@@ -216,10 +219,11 @@ Remove or deactivate a user on the identity provider to remove their access to:
- The top-level group.
- All subgroups and projects.
-After the identity provider performs a sync based on its configured schedule, the user's membership is revoked and they
-lose access.
+After the identity provider performs a sync based on its configured schedule,
+the user's membership is revoked and they lose access.
-When you enable SCIM, this does not automatically remove existing users who do not have a SAML identity.
+When you enable SCIM, this does not automatically remove existing users who do
+not have a SAML identity.
NOTE:
Deprovisioning does not delete the GitLab user account.
@@ -230,3 +234,14 @@ graph TD
B -->|No| C[Nothing to do]
B -->|Yes| D[GitLab removes user from GitLab group]
```
+
+### Reactivate access
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/379149) in GitLab 16.0 [with a flag](../../feature_flags.md) named `skip_saml_identity_destroy_during_scim_deprovision`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121226) in GitLab 16.4. Feature flag `skip_saml_identity_destroy_during_scim_deprovision` removed.
+
+After a user is removed or deactivated through SCIM, you can reactivate that user by
+adding them to the SCIM identity provider.
+
+After the identity provider performs a sync based on its configured schedule,
+the user's SCIM identity is reactivated and their group memberships are restored.
diff --git a/doc/user/group/saml_sso/troubleshooting.md b/doc/user/group/saml_sso/troubleshooting.md
index 82703893834..cf9b9f5d4eb 100644
--- a/doc/user/group/saml_sso/troubleshooting.md
+++ b/doc/user/group/saml_sso/troubleshooting.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -217,6 +217,18 @@ to [reset their password](https://gitlab.com/users/password/new) if both:
- The account was provisioned by SCIM.
- They are signing in with username and password for the first time.
+### Message: "SAML Name ID and email address do not match your user account" **(PREMIUM SAAS)**
+
+Users might get an error that states "SAML Name ID and email address do not match your user account. Contact an administrator."
+This means:
+
+- The NameID value sent by SAML does not match the existing SAML identity `extern_uid` value.
+- Either the SAML response did not include an email address or the email address did not match the user's GitLab email address.
+
+The workaround is that a GitLab group Owner uses the [SAML API](../../../api/saml.md) to update the user's SAML `extern_uid`.
+The `extern_uid` value must match the Name ID value sent by the SAML identity provider (IdP). Depending on the IdP configuration
+this may be a generated unique ID, an email address, or other value.
+
## Other user sign in issues
### Verify `NameID`
@@ -254,12 +266,24 @@ If all users are receiving a `404` after signing in to the identity provider (Id
- In the GitLab configuration by [matching it to the HTTPS endpoint of GitLab](../../../integration/saml.md#configure-saml-support-in-gitlab).
- As the `Assertion Consumer Service URL` or equivalent when setting up the SAML app on your IdP.
-- Verify if the `404` is related to [the user having too many groups assigned to them in their Azure IdP](group_sync.md#user-that-belongs-to-many-saml-groups-automatically-removed-from-gitlab-group) by checking:
+- Verify if the `404` is related to [the user having too many groups assigned to them in their Azure IdP](group_sync.md#user-that-belongs-to-many-saml-groups-automatically-removed-from-gitlab-group).
+
+If a subset of users are receiving a `404` after signing in to the IdP, first verify audit events if the user gets added to the group and then immediately removed. Alternatively, if the user can successfully sign in, but they do not show as [a member of the top-level group](../index.md#search-a-group):
- - If the user has group links configured.
- - Audit events if the user gets added to the group and then immediately removed.
+- Ensure the user has been [added to the SAML identity provider](index.md#user-access-and-management), and [SCIM](scim_setup.md) if configured.
+- Ensure the user's SCIM identity's `active` attribute is `true` using the [SCIM API](../../../api/scim.md).
+ If the `active` attribute is `false`, you can do one of the following to possibly resolve the issue:
-For configuration examples for some of the common providers, see the [example group SAML and SCIM configurations](example_saml_config.md).
+ - Trigger a sync for the user in the SCIM identity provider. For example, Azure has a "Provision on demand" option.
+ - Remove and re-add the user in the SCIM identity provider.
+ - Have the user [unlink their account](index.md#unlink-accounts) if possible, then [link their account](index.md#link-saml-to-your-existing-gitlabcom-account).
+ - Use the [internal SCIM API](../../../development/internal_api/index.md#update-a-single-scim-provisioned-user) to update the user's SCIM identity using your group's SCIM token.
+ If you do not know your group's SCIM token, reset the token and update the SCIM identity provider app with the new token.
+ Example request:
+
+ ```plaintext
+ curl --request PATCH "https://gitlab.example.com/api/scim/v2/groups/test_group/Users/f0b1d561c-21ff-4092-beab-8154b17f82f2" --header "Authorization: Bearer <SCIM_TOKEN>" --data '{ "Operations": [{"op":"Replace","path":"active","value":"true"}] }'
+ ```
### 500 error after login **(FREE SELF)**
@@ -283,6 +307,21 @@ Make sure the ACS URL points to `https://gitlab.example.com/users/auth/saml/call
If the ACS URL is correct, and you still have errors, review the other
Troubleshooting sections.
+#### 422 error with non-allowed email
+
+You might get an 422 error that states "Email is not allowed for sign-up. Please use your regular email address."
+
+This message might indicate that you must add or remove a domain from your domain allowlist or denylist settings.
+
+To implement this workaround:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings** > **General**.
+1. Expand **Sign-up restrictions**.
+1. Add or remove a domain as appropriate to **Allowed domains for sign-ups** and **Denied domains for sign-ups**.
+1. Select **Save changes**.
+
### User is blocked when signing in through SAML **(FREE SELF)**
The following are the most likely reasons that a user is blocked when signing in through SAML:
@@ -298,18 +337,6 @@ Pay particular attention to the following 403 errors:
- `app_not_configured`
- `app_not_configured_for_user`
-## SAML Name ID and email address do not match your user account **(PREMIUM SAAS)**
-
-If users encounter the error `SAML Name ID and email address do not match your user account. Contact an administrator.`
-this means:
-
-- The NameID value sent by SAML does not match the existing SAML identity `extern_uid` value.
-- Either the SAML response did not include an email address or the email address did not match the user's GitLab email address.
-
-A GitLab group Owner can use the [SAML API](../../../api/saml.md) to update the user's SAML `extern_uid`.
-The `extern_uid` value must match the Name ID value sent by the SAML identity provider (IdP). Depending on the IdP configuration
-this may be a generated unique ID, an email address, or other value.
-
## Message: "The member's email address is not linked to a SAML account" **(PREMIUM SAAS)**
This error appears when you try to invite a user to a GitLab.com group (or subgroup or project within a group) that has [SAML SSO enforcement](index.md#sso-enforcement) enabled.
@@ -318,3 +345,6 @@ If you see this message after trying to invite a user to a group:
1. Ensure the user has been [added to the SAML identity provider](index.md#user-access-and-management).
1. Ask the user to [link SAML to their existing GitLab.com account](index.md#link-saml-to-your-existing-gitlabcom-account), if they have one. Otherwise, ask the user to create a GitLab.com account by [accessing GitLab.com through the identity provider's dashboard](index.md#user-access-and-management), or by [signing up manually](https://gitlab.com/users/sign_up) and linking SAML to their new account.
+1. Ensure the user is a [member of the top-level group](../index.md#search-a-group).
+
+Additionally, see [troubleshooting users receiving a 404 after sign in](#users-receive-a-404).
diff --git a/doc/user/group/saml_sso/troubleshooting_scim.md b/doc/user/group/saml_sso/troubleshooting_scim.md
index 7d2aa8faa99..63d10f3e932 100644
--- a/doc/user/group/saml_sso/troubleshooting_scim.md
+++ b/doc/user/group/saml_sso/troubleshooting_scim.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -13,7 +13,18 @@ This section contains possible solutions for problems you might encounter.
When you remove a user, they are removed from the group but their account is not deleted
(see [remove access](scim_setup.md#remove-access)).
-When the user is added back to the SCIM app, GitLab cannot create a new user because the user already exists.
+When the user is added back to the SCIM app, GitLab does not create a new user because the user already exists.
+
+From August 11, 2023, the `skip_saml_identity_destroy_during_scim_deprovision` feature flag is enabled.
+
+For a user de-provisioned by SCIM from that date, their SAML identity is not removed.
+
+When that user is added back to the SCIM app:
+
+- Their SCIM identity `active` attribute is set to `true`.
+- They can sign in using SSO.
+
+For users de-provisioned by SCIM before that date, their SAML identity is destroyed.
To solve this problem:
diff --git a/doc/user/group/settings/group_access_tokens.md b/doc/user/group/settings/group_access_tokens.md
index 76aa77d026b..795967e9f91 100644
--- a/doc/user/group/settings/group_access_tokens.md
+++ b/doc/user/group/settings/group_access_tokens.md
@@ -1,11 +1,11 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
type: reference, howto
---
-# Group access tokens
+# Group access tokens **(FREE)**
With group access tokens, you can use a single token to:
@@ -57,7 +57,7 @@ all projects that have visibility level set to [Internal](../../public_access.md
To create a group access token:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Access Tokens**.
1. Enter a name. The token name is visible to any user with permissions to view the group.
1. Enter an expiry date for the token:
@@ -119,7 +119,7 @@ or API. However, administrators can use a workaround:
To revoke a group access token:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Access Tokens**.
1. Next to the group access token to revoke, select **Revoke**.
@@ -138,6 +138,8 @@ token.revoke!
## Scopes for a group access token
+> `k8s_proxy` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/422408) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `k8s_proxy_pat`. Enabled by default.
+
The scope determines the actions you can perform when you authenticate with a group access token.
| Scope | Description |
@@ -149,12 +151,14 @@ The scope determines the actions you can perform when you authenticate with a gr
| `read_repository` | Grants read access (pull) to all repositories within a group. |
| `write_repository` | Grants read and write access (pull and push) to all repositories within a group. |
| `create_runner` | Grants permission to create runners in a group. |
+| `ai_features` | Grants permission to perform API actions for GitLab Duo. |
+| `k8s_proxy` | Grants permission to perform Kubernetes API calls using the agent for Kubernetes in a group. |
## Enable or disable group access token creation
To enable or disable group access token creation for all subgroups in a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Under **Permissions**, turn on or off **Users can create project access tokens and group access tokens in this group**.
diff --git a/doc/user/group/subgroups/index.md b/doc/user/group/subgroups/index.md
index 4fb8b293334..e9064ff72a6 100644
--- a/doc/user/group/subgroups/index.md
+++ b/doc/user/group/subgroups/index.md
@@ -56,7 +56,7 @@ the private subgroup.
To view the subgroups of a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select the **Subgroups and projects** tab.
1. To view a nested subgroup, expand a subgroup in the hierarchy list.
@@ -77,14 +77,14 @@ Prerequisites:
- At least the Maintainer role for a group to create subgroups for it.
- The [role determined by a setting](#change-who-can-create-subgroups). These users can create
subgroups even if group creation is
- [disabled by an Administrator](../../../administration/admin_area.md#prevent-a-user-from-creating-groups) in the user's settings.
+ [disabled by an Administrator](../../../administration/admin_area.md#prevent-a-user-from-creating-top-level-groups) in the user's settings.
NOTE:
You cannot host a GitLab Pages subgroup website with a top-level domain name. For example, `subgroupname.example.io`.
To create a subgroup:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find a parent group for the subgroup.
+1. On the left sidebar, select **Search or go to** and find a parent group for the subgroup.
1. On the parent group's overview page, in the upper-right corner, select **New subgroup**.
1. Select **Create group**.
1. Fill in the fields. View a list of [reserved names](../../reserved_names.md) that cannot be used as group names.
@@ -99,13 +99,13 @@ Prerequisite:
To change who can create subgroups on a group:
- As a user with the Owner role on the group:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+ 1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Select a role from **Roles allowed to create subgroups**.
1. Select **Save changes**.
- As an administrator:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Overview > Groups**.
1. In the group's row select **Edit**.
@@ -161,7 +161,7 @@ Group permissions for a member can be changed only by:
To see if a member has inherited the permissions from a parent group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Members**.
Members list for an example subgroup _Four_:
diff --git a/doc/user/group/value_stream_analytics/index.md b/doc/user/group/value_stream_analytics/index.md
index 1e042ab1924..0d91416dfa5 100644
--- a/doc/user/group/value_stream_analytics/index.md
+++ b/doc/user/group/value_stream_analytics/index.md
@@ -212,7 +212,7 @@ Prerequisites:
To view value stream analytics for your group or project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value stream analytics**.
1. To view metrics for a particular stage, select a stage below the **Filter results** text box.
1. Optional. Filter the results:
@@ -302,7 +302,7 @@ Prerequisite:
To view lifecycle metrics:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value stream analytics**.
Lifecycle metrics display below the **Filter results** text box.
1. Optional. Filter the results:
@@ -316,7 +316,7 @@ To view lifecycle metrics:
To view the [Value Streams Dashboard](../../analytics/value_streams_dashboard.md) and [DORA metrics](../../analytics/dora_metrics.md):
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value stream analytics**.
1. Below the **Filter results** text box, in the **Lifecycle metrics** row, select **Value Streams Dashboard / DORA**.
1. Optional. To open the new page, append this path `/analytics/dashboards/value_streams_dashboard` to the group URL
@@ -331,7 +331,7 @@ Value stream analytics shows the median time spent by issues or merge requests i
To view the median time spent in each stage by a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value stream analytics**.
1. Optional. Filter the results:
1. Select the **Filter results** text box.
@@ -355,7 +355,7 @@ group and time frame.
To view tasks by type:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Analyze > Value stream analytics**.
1. Below the **Filter results** text box, select **Overview**. The **Tasks by type** chart displays below the **Total time** chart.
1. To switch between the task type, select the **Settings** (**{settings}**) dropdown list
@@ -372,7 +372,7 @@ To view tasks by type:
When you create a value stream, you can use GitLab default stages and hide or re-order them. You can also
create custom stages in addition to those provided in the default template.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value Stream analytics**.
1. Select **Create new Value Stream**.
1. Enter a name for the value stream.
@@ -396,7 +396,7 @@ If you have recently upgraded to GitLab Premium, it can take up to 30 minutes fo
When you create a value stream, you can create and add custom stages that align with your own development workflows.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value Stream analytics**.
1. Select **Create value stream**.
1. For each stage:
@@ -430,7 +430,7 @@ The first value stream uses standard timestamp-based events for defining the sta
After you create a value stream, you can customize it to suit your purposes. To edit a value stream:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value Stream analytics**.
1. In the upper-right corner, select the dropdown list, then select a value stream.
1. Next to the value stream dropdown list, select **Edit**.
@@ -449,7 +449,7 @@ After you create a value stream, you can customize it to suit your purposes. To
To delete a custom value stream:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. In the upper-right corner, select the dropdown list, then select the value stream you would like to delete.
1. Select **Delete (name of value stream)**.
1. To confirm, select **Delete**.
@@ -464,7 +464,7 @@ To delete a custom value stream:
The **Total time chart** shows the average number of days it takes for development cycles to complete.
The chart shows data for the last 500 workflow items.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Analyze > Value stream analytics**.
1. Above the **Filter results** box, select a stage:
- To view a summary of the cycle time for all stages, select **Overview**.
diff --git a/doc/user/img/enable_AI_ML_features.png b/doc/user/img/enable_AI_ML_features.png
new file mode 100644
index 00000000000..577fb367e4d
--- /dev/null
+++ b/doc/user/img/enable_AI_ML_features.png
Binary files differ
diff --git a/doc/user/img/forecast_deployment_frequency.png b/doc/user/img/forecast_deployment_frequency.png
new file mode 100644
index 00000000000..4c8c6f47a08
--- /dev/null
+++ b/doc/user/img/forecast_deployment_frequency.png
Binary files differ
diff --git a/doc/user/infrastructure/clusters/connect/index.md b/doc/user/infrastructure/clusters/connect/index.md
index 5010c2e92a3..961914aac9c 100644
--- a/doc/user/infrastructure/clusters/connect/index.md
+++ b/doc/user/infrastructure/clusters/connect/index.md
@@ -34,17 +34,17 @@ your cluster's level.
**Project-level clusters:**
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Kubernetes clusters**.
**Group-level clusters:**
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Operate > Kubernetes clusters**.
**Instance-level clusters:**
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Kubernetes**.
diff --git a/doc/user/infrastructure/clusters/connect/new_civo_cluster.md b/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
index 91429e203f3..de35b21c8b6 100644
--- a/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
@@ -35,8 +35,8 @@ Start by [importing the example project by URL](../../../project/import/repo_by_
To import the project:
-1. In GitLab, on the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your projects**..
+1. In GitLab, on the left sidebar, select **Search or go to**.
+1. Select **View all my projects**..
1. On the right of the page, select **New project**.
1. Select **Import project**.
1. Select **Repository by URL**.
diff --git a/doc/user/infrastructure/clusters/connect/new_eks_cluster.md b/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
index ef51db097d9..4ec28a7c3c6 100644
--- a/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
@@ -34,8 +34,8 @@ Start by [importing the example project by URL](../../../project/import/repo_by_
To import the project:
-1. In GitLab, on the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your projects**.
+1. In GitLab, on the left sidebar, select **Search or go to**.
+1. Select **View all my projects**.
1. On the right of the page, select **New project**.
1. Select **Import project**.
1. Select **Repository by URL**.
diff --git a/doc/user/infrastructure/clusters/connect/new_gke_cluster.md b/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
index 3d717e0f473..96819860a2f 100644
--- a/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
@@ -41,8 +41,8 @@ Start by [importing the example project by URL](../../../project/import/repo_by_
To import the project:
-1. In GitLab, on the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your projects**.
+1. In GitLab, on the left sidebar, select **Search or go to**.
+1. Select **View all my projects**.
1. On the right of the page, select **New project**.
1. Select **Import project**.
1. Select **Repository by URL**.
diff --git a/doc/user/infrastructure/clusters/index.md b/doc/user/infrastructure/clusters/index.md
index ad587154021..cace9c66fcf 100644
--- a/doc/user/infrastructure/clusters/index.md
+++ b/doc/user/infrastructure/clusters/index.md
@@ -13,9 +13,9 @@ To connect clusters to GitLab, use the [GitLab agent](../../clusters/agent/index
WARNING:
In GitLab 14.5, the certificate-based method to connect Kubernetes clusters
to GitLab was [deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8),
-as well as its related [features](#deprecated-features). In self-managed GitLab 15.0 and later,
+as well as its related [features](#deprecated-features). In self-managed GitLab 17.0 and later,
this feature is disabled by default. For GitLab SaaS users, this feature is available until
-GitLab 15.6 for users who have at least one certificate-based cluster enabled in their namespace hierarchy.
+GitLab 15.9 for users who have at least one certificate-based cluster enabled in their namespace hierarchy.
For GitLab SaaS users that never used this feature previously, it is no longer available.
The certificate-based Kubernetes integration with GitLab is deprecated.
@@ -54,12 +54,9 @@ This feature flag re-enables the certificate-based Kubernetes integration.
- [GitLab-managed clusters](../../project/clusters/gitlab_managed_clusters.md)
- [Deploy applications through certificate-based connection](../../project/clusters/deploy_to_cluster.md)
- [Cluster Management Project](../../clusters/management_project.md)
-- [Cluster integrations](../../clusters/integrations.md)
-- [Cluster cost management](../../clusters/cost_management.md)
- [Cluster environments](../../clusters/environments.md)
- [Show Canary Ingress deployments on deploy boards](../../project/canary_deployments.md#show-canary-ingress-deployments-on-deploy-boards-deprecated)
- [Deploy Boards](../../project/deploy_boards.md)
-- [Clusters health](manage/clusters_health.md)
- [Web terminals](../../../administration/integration/terminal.md)
### Cluster levels
diff --git a/doc/user/infrastructure/clusters/manage/clusters_health.md b/doc/user/infrastructure/clusters/manage/clusters_health.md
deleted file mode 100644
index cf1b5585a0c..00000000000
--- a/doc/user/infrastructure/clusters/manage/clusters_health.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Deploy
-group: Environments
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../index.md'
----
-
-# Clusters health (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/infrastructure/clusters/manage/management_project_applications/vault.md b/doc/user/infrastructure/clusters/manage/management_project_applications/vault.md
index 193e3b70fba..ac61c0c11b4 100644
--- a/doc/user/infrastructure/clusters/manage/management_project_applications/vault.md
+++ b/doc/user/infrastructure/clusters/manage/management_project_applications/vault.md
@@ -90,7 +90,7 @@ After you have successfully installed Vault, you must
and obtain the initial root token. You need access to your Kubernetes cluster that
Vault has been deployed into to do this. To initialize the Vault, get a
shell to one of the Vault pods running inside Kubernetes (typically this is done
-by using the `kubectl` command line tool). After you have a shell into the pod,
+by using the `kubectl` command-line tool). After you have a shell into the pod,
run the `vault operator init` command:
```shell
diff --git a/doc/user/infrastructure/iac/index.md b/doc/user/infrastructure/iac/index.md
index 26b4b66ac63..25605cdac62 100644
--- a/doc/user/infrastructure/iac/index.md
+++ b/doc/user/infrastructure/iac/index.md
@@ -64,7 +64,7 @@ In each GitLab major release (for example, 15.0), the latest templates replace t
To use a Terraform template:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project you want to integrate with Terraform.
+1. On the left sidebar, select **Search or go to** and find your project you want to integrate with Terraform.
1. Select **Code > Repository**.
1. Edit your `.gitlab-ci.yml` file, use the `include` attribute to fetch the Terraform template:
diff --git a/doc/user/infrastructure/iac/terraform_state.md b/doc/user/infrastructure/iac/terraform_state.md
index 4a8f2f11e58..081e20b158e 100644
--- a/doc/user/infrastructure/iac/terraform_state.md
+++ b/doc/user/infrastructure/iac/terraform_state.md
@@ -116,7 +116,7 @@ inconsistent. Instead, use a remote storage resource.
[initialized for CI/CD](#initialize-a-terraform-state-as-a-backend-by-using-gitlab-cicd).
1. Copy a pre-populated Terraform `init` command:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Terraform states**.
1. Next to the environment you want to use, select **Actions**
(**{ellipsis_v}**) and select **Copy Terraform init command**.
@@ -294,7 +294,7 @@ To read the Terraform state in the target project, you need at least the Develop
To view Terraform state files:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Terraform states**.
[An epic exists](https://gitlab.com/groups/gitlab-org/-/epics/4563) to track improvements to this UI.
diff --git a/doc/user/instance/clusters/index.md b/doc/user/instance/clusters/index.md
index 15a3703adbf..5787051a2c2 100644
--- a/doc/user/instance/clusters/index.md
+++ b/doc/user/instance/clusters/index.md
@@ -21,7 +21,7 @@ projects.
To view the instance level Kubernetes clusters:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Kubernetes**.
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index c724ae465b8..c996b29c9a2 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -691,11 +691,6 @@ To update the rendered references if the assignee, milestone, or health status c
edit the comment or description and save it.
For more information, see issue [420807](https://gitlab.com/gitlab-org/gitlab/-/issues/420807).
-### Embedding metrics
-
-Metric charts can be embedded in GitLab Flavored Markdown. Read
-[Embedding Metrics in GitLab flavored Markdown](../operations/metrics/embed.md) for more details.
-
### Embedding Observability dashboards
You can embed GitLab Observability UI dashboards descriptions and comments, for example in epics, issues, and MRs.
diff --git a/doc/user/okrs.md b/doc/user/okrs.md
index f9c242e7c2a..bb58dcf516b 100644
--- a/doc/user/okrs.md
+++ b/doc/user/okrs.md
@@ -60,7 +60,7 @@ Prerequisites:
To create an objective:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Plan > Issues**.
1. In the upper-right corner, next to **New issue**, select the down arrow **{chevron-lg-down}** and then select **New objective**.
1. Select **New objective** again.
@@ -77,7 +77,7 @@ Prerequisites:
To view an objective:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Plan > Issues**.
1. [Filter the list of issues](project/issues/managing_issues.md#filter-the-list-of-issues)
for `Type = objective`.
@@ -91,7 +91,7 @@ Prerequisites:
To view a key result:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Plan > Issues**.
1. [Filter the list of issues](project/issues/managing_issues.md#filter-the-list-of-issues)
for `Type = key_result`.
@@ -246,7 +246,7 @@ To refer to an objective or key result elsewhere in GitLab, you can use its full
To copy the objective or key result reference to your clipboard:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your objective or key result to view it.
1. In the top right corner, select the vertical ellipsis (**{ellipsis_v}**), then select **Copy Reference**.
@@ -266,7 +266,7 @@ For more information about creating comments by sending an email and the necessa
To copy the objective's or key result's email address:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. In the top right corner, select the vertical ellipsis (**{ellipsis_v}**), then select **Copy objective email address** or **Copy key result email address**.
diff --git a/doc/user/operations_dashboard/index.md b/doc/user/operations_dashboard/index.md
index 3f86e945492..3364d927a9b 100644
--- a/doc/user/operations_dashboard/index.md
+++ b/doc/user/operations_dashboard/index.md
@@ -11,7 +11,7 @@ including pipeline and alert status.
To access the dashboard:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. Select **Operations**.
diff --git a/doc/user/packages/composer_repository/index.md b/doc/user/packages/composer_repository/index.md
index 0fcc44e8780..3c80e739465 100644
--- a/doc/user/packages/composer_repository/index.md
+++ b/doc/user/packages/composer_repository/index.md
@@ -4,7 +4,7 @@ group: Package Registry
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Composer packages in the Package Registry **(FREE ALL)**
+# Composer packages in the Package Registry **(FREE ALL BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15886) in GitLab 13.2.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) from GitLab Premium to GitLab Free in 13.3.
@@ -280,21 +280,53 @@ To install a package:
composer req <package-name>:<package-version>
```
- If successful, you should see output indicating that the package installed successfully.
-
- You can also install from source (by pulling the Git repository directly) using the
- `--prefer-source` option:
-
- ```shell
- composer update --prefer-source
- ```
-
WARNING:
Never commit the `auth.json` file to your repository. To install packages from a CI/CD job,
consider using the [`composer config`](https://getcomposer.org/doc/articles/handling-private-packages.md#satis) tool with your access token
stored in a [GitLab CI/CD variable](../../../ci/variables/index.md) or in
[HashiCorp Vault](../../../ci/secrets/index.md).
+### Install from source
+
+You can install from source by pulling the Git repository directly. To do so, either:
+
+- Use the `--prefer-source` option:
+
+ ```shell
+ composer update --prefer-source
+ ```
+
+- In the `composer.json`, use the [`preferred-install` field under the `config` key](https://getcomposer.org/doc/06-config.md#preferred-install):
+
+ ```json
+ {
+ ...
+ "config": {
+ "preferred-install": {
+ "<package name>": "source"
+ }
+ }
+ ...
+ }
+ ```
+
+#### SSH access
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119739) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `composer_use_ssh_source_urls`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, an administrator can
+[enable the feature flag](../../../administration/feature_flags.md) named `composer_use_ssh_source_urls`.
+
+When you install from source, the `composer` configures an
+access to the project's Git repository.
+Depending on the project visibility, the access type is different:
+
+- On public projects, the `https` Git URL is used. Make sure you can [clone the repository with HTTPS](../../../gitlab-basics/start-using-git.md#clone-with-https).
+- On internal or private projects, the `ssh` Git URL is used. Make sure you can [clone the repository with SSH](../../../gitlab-basics/start-using-git.md#clone-with-ssh).
+
+You can access the `ssh` Git URL from a CI/CD job using [SSH keys with GitLab CI/CD](../../../ci/ssh_keys/index.md).
+
### Working with Deploy Tokens
Although Composer packages are accessed at the group level, a group or project deploy token can be
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index 72c5a1980b5..74152515198 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -4,7 +4,7 @@ group: Package Registry
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Conan packages in the Package Registry **(FREE ALL)**
+# Conan packages in the Package Registry **(FREE ALL EXPERIMENT)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8248) in GitLab 12.6.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) from GitLab Premium to GitLab Free in 13.3.
diff --git a/doc/user/packages/container_registry/delete_container_registry_images.md b/doc/user/packages/container_registry/delete_container_registry_images.md
index 88a318d0770..0b91a9453a7 100644
--- a/doc/user/packages/container_registry/delete_container_registry_images.md
+++ b/doc/user/packages/container_registry/delete_container_registry_images.md
@@ -32,7 +32,7 @@ The online garbage collector is an instance-wide feature, and applies to all nam
To delete container images using the GitLab UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. For:
- A group, select **Operate > Container Registry**.
- A project, select **Deploy > Container Registry**.
diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md
index 3ec5ddb235e..1f95d2f9403 100644
--- a/doc/user/packages/container_registry/index.md
+++ b/doc/user/packages/container_registry/index.md
@@ -21,7 +21,7 @@ rate limits and speed up your pipelines. For more information about the Docker R
You can view the Container Registry for a project or group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. For:
- A group, select **Operate > Container Registry**.
- A project, select **Deploy > Container Registry**.
@@ -38,7 +38,7 @@ If a project is public, the Container Registry is also public.
You can use the Container Registry **Tag Details** page to view a list of tags associated with a given container image:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. For:
- A group, select **Operate > Container Registry**.
- A project, select **Deploy > Container Registry**.
@@ -54,7 +54,7 @@ tags on this page. You can share a filtered view by copying the URL from your br
To download and run a container image hosted in the Container Registry:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. For:
- A group, select **Operate > Container Registry**.
- A project, select **Deploy > Container Registry**.
@@ -115,7 +115,7 @@ The Container Registry is enabled by default.
You can, however, remove the Container Registry for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand the **Visibility, project features, permissions** section
and disable **Container Registry**.
@@ -133,7 +133,7 @@ You can, however, change the visibility of the Container Registry for a project.
For more information about the permissions that this setting grants to users,
see [Container Registry visibility permissions](#container-registry-visibility-permissions).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand the section **Visibility, project features, permissions**.
1. Under **Container Registry**, select an option from the dropdown list:
diff --git a/doc/user/packages/container_registry/reduce_container_registry_storage.md b/doc/user/packages/container_registry/reduce_container_registry_storage.md
index fd781847855..2af16dcc85a 100644
--- a/doc/user/packages/container_registry/reduce_container_registry_storage.md
+++ b/doc/user/packages/container_registry/reduce_container_registry_storage.md
@@ -229,7 +229,7 @@ For self-managed instances, those settings can be updated in the [Rails console]
They are also available in the [administrator area](../../admin_area/index.md):
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > CI/CD**
1. Expand **Container Registry**.
diff --git a/doc/user/packages/container_registry/troubleshoot_container_registry.md b/doc/user/packages/container_registry/troubleshoot_container_registry.md
index 34c86a90d49..13e14dfdeb4 100644
--- a/doc/user/packages/container_registry/troubleshoot_container_registry.md
+++ b/doc/user/packages/container_registry/troubleshoot_container_registry.md
@@ -91,7 +91,7 @@ The following procedure uses these sample project names:
There may be a delay while the images are queued and deleted.
1. Change the path or transfer the project:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand the **Advanced** section.
1. In the **Change path** text box, edit the path.
@@ -127,3 +127,12 @@ time is set to 15 minutes.
If you are using self-managed GitLab, an administrator can
[increase the token duration](../../../administration/packages/container_registry.md#increase-token-duration).
+
+## Slow uploads when using `kaniko` to push large images
+
+When you push large images with `kaniko`, you might experience uncharacteristically long delays.
+
+This is typically a result of [a performance issue with `kaniko` and HTTP/2](https://github.com/GoogleContainerTools/kaniko/issues/2751).
+The current workaround is to use HTTP/1.1 when pushing with `kaniko`.
+
+To use HTTP/1.1, set the `GODEBUG` environment variable to `"http2client=0"`.
diff --git a/doc/user/packages/debian_repository/index.md b/doc/user/packages/debian_repository/index.md
index b7fbeb96202..8e555204f80 100644
--- a/doc/user/packages/debian_repository/index.md
+++ b/doc/user/packages/debian_repository/index.md
@@ -4,7 +4,7 @@ group: Package Registry
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Debian packages in the Package Registry **(FREE ALL)**
+# Debian packages in the Package Registry **(FREE ALL EXPERIMENT)**
> - Debian API [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42670) in GitLab 13.5.
> - Debian group API [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66188) in GitLab 14.2.
@@ -12,7 +12,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
WARNING:
The Debian package registry for GitLab is under development and isn't ready for production use. This [epic](https://gitlab.com/groups/gitlab-org/-/epics/6057) details the remaining
-work and timelines to make it production ready.
+work and timelines to make it production ready. Support for [Debian packages is an experiment](../package_registry/supported_package_managers.md), and has known security vulnerabilities.
Publish Debian packages in your project's Package Registry. Then install the
packages whenever you need to use them as a dependency.
@@ -27,8 +27,11 @@ Prerequisites:
- The `dpkg-deb` binary must be installed on the GitLab instance.
This binary is usually provided by the [`dpkg` package](https://wiki.debian.org/Teams/Dpkg/Downstream),
installed by default on Debian and derivatives.
+- Support for compression algorithm ZStandard requires version `dpkg >=
+ 1.21.18` from Debian 12 Bookworm or `dpkg >= 1.19.0.5ubuntu2` from Ubuntu
+ 18.04 Bionic Beaver.
-## Enable the Debian API **(FREE SELF)**
+## Enable the Debian API
Debian repository support is still a work in progress. It's gated behind a feature flag that's
**disabled by default**.
@@ -50,7 +53,7 @@ To disable it:
Feature.disable(:debian_packages)
```
-## Enable the Debian group API **(FREE SELF)**
+## Enable the Debian group API
The Debian group repository is also behind a second feature flag that is disabled by default.
diff --git a/doc/user/packages/dependency_proxy/index.md b/doc/user/packages/dependency_proxy/index.md
index 11b67e5cda3..02810bcb922 100644
--- a/doc/user/packages/dependency_proxy/index.md
+++ b/doc/user/packages/dependency_proxy/index.md
@@ -39,7 +39,7 @@ For a list of planned additions, view the
To enable or turn off the Dependency Proxy for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Packages and registries**.
1. Expand the **Dependency Proxy** section.
1. To enable the proxy, turn on **Enable Proxy**. To turn it off, turn the toggle off.
@@ -52,7 +52,7 @@ for the entire GitLab instance.
To view the Dependency Proxy:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Operate > Dependency Proxy**.
The Dependency Proxy is not available for projects.
@@ -179,7 +179,7 @@ You can also use [custom CI/CD variables](../../../ci/variables/index.md#for-a-p
To store a Docker image in Dependency Proxy storage:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Operate > Dependency Proxy**.
1. Copy the **Dependency Proxy image prefix**.
1. Use one of these commands. In these examples, the image is `alpine:latest`.
@@ -367,7 +367,12 @@ see [issue 354826](https://gitlab.com/gitlab-org/gitlab/-/issues/354826).
### `exec format error` when running images from the dependency proxy
-This error occurs if you try to use the dependency proxy on an ARM-based Docker install.
+NOTE:
+This issue was [resolved](https://gitlab.com/gitlab-org/gitlab/-/issues/325669) in GitLab 16.3.
+For self managed instances that are 16.2 or earlier, you can update your instance to 16.3
+or use the workaround documented below.
+
+This error occurs if you try to use the dependency proxy on an ARM-based Docker install in GitLab 16.2 or earlier.
The dependency proxy only supports the x86_64 architecture when pulling an image with a specific tag.
As a workaround, you can specify the SHA256 of the image to force the dependency proxy
@@ -378,5 +383,3 @@ docker pull ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/library/docker:20.10.3@sha
```
In this example, `bc9dcf5c8e5908845acc6d34ab8824bca496d6d47d1b08af3baf4b3adb1bd8fe` is the SHA256 of the ARM based image.
-
-For more information about the work to add support for other architectures, see [issue 325669](https://gitlab.com/gitlab-org/gitlab/-/issues/325669).
diff --git a/doc/user/packages/generic_packages/index.md b/doc/user/packages/generic_packages/index.md
index e309ab002c4..938093f2a27 100644
--- a/doc/user/packages/generic_packages/index.md
+++ b/doc/user/packages/generic_packages/index.md
@@ -127,7 +127,7 @@ or the UI.
In the UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Packages and registries**.
1. In the **Generic** row of the **Duplicate packages** table, turn off the **Allow duplicates** toggle.
1. Optional. In the **Exceptions** text box, enter a regular expression that matches the names and versions of packages to allow.
diff --git a/doc/user/packages/go_proxy/index.md b/doc/user/packages/go_proxy/index.md
index 52f98ecf4dc..6dffd7371b6 100644
--- a/doc/user/packages/go_proxy/index.md
+++ b/doc/user/packages/go_proxy/index.md
@@ -4,7 +4,7 @@ group: Package Registry
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Go proxy for GitLab **(FREE ALL)**
+# Go proxy for GitLab **(FREE ALL EXPERIMENT)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27376) in GitLab 13.1.
> - It's deployed behind a feature flag, disabled by default.
diff --git a/doc/user/packages/harbor_container_registry/index.md b/doc/user/packages/harbor_container_registry/index.md
index 0cdaaf8ece0..d45b6ea7026 100644
--- a/doc/user/packages/harbor_container_registry/index.md
+++ b/doc/user/packages/harbor_container_registry/index.md
@@ -12,7 +12,7 @@ You can integrate the [Harbor container registry](../../../user/project/integrat
You can view the Harbor Registry for a project or group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Operate > Harbor Registry**.
You can search, sort, and filter images on this page. You can share a filtered view by copying the URL from your browser.
@@ -29,7 +29,7 @@ Default settings for the Harbor integration at the project level are inherited f
To download and run a Harbor image hosted in the GitLab Harbor Registry:
1. Copy the link to your container image:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+ 1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Operate > Harbor Registry** and find the image you want.
1. Select the **Copy** icon next to the image name.
@@ -39,7 +39,7 @@ To download and run a Harbor image hosted in the GitLab Harbor Registry:
To view the list of tags associated with a specific artifact:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Go to **Operate > Harbor Registry**.
1. Select the image name to view its artifacts.
1. Select the artifact you want.
@@ -57,7 +57,7 @@ To build and push to the Harbor Registry:
To view these commands:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Operate > Harbor Registry**.
1. Select **CLI Commands**.
@@ -65,7 +65,7 @@ To view these commands:
To remove the Harbor Registry for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > Integrations**.
1. Select **Harbor** under **Active integrations**.
1. Under **Enable integration**, clear the **Active** checkbox.
diff --git a/doc/user/packages/helm_repository/index.md b/doc/user/packages/helm_repository/index.md
index 57aee4fb4ca..b7888fe2d18 100644
--- a/doc/user/packages/helm_repository/index.md
+++ b/doc/user/packages/helm_repository/index.md
@@ -4,7 +4,7 @@ group: Package Registry
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Helm charts in the Package Registry **(FREE ALL)**
+# Helm charts in the Package Registry **(FREE ALL BETA)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18997) in GitLab 14.1.
diff --git a/doc/user/packages/maven_repository/index.md b/doc/user/packages/maven_repository/index.md
index 51755eda7bb..13d84fa3d99 100644
--- a/doc/user/packages/maven_repository/index.md
+++ b/doc/user/packages/maven_repository/index.md
@@ -480,7 +480,7 @@ To prevent users from publishing duplicate Maven packages, you can use the [Grap
In the UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Packages and registries**.
1. In the **Maven** row of the **Duplicate packages** table, turn off the **Allow duplicates** toggle.
1. Optional. In the **Exceptions** text box, enter a regular expression that matches the names and versions of packages to allow.
diff --git a/doc/user/packages/nuget_repository/index.md b/doc/user/packages/nuget_repository/index.md
index 74daf9fd891..340df4a3c5f 100644
--- a/doc/user/packages/nuget_repository/index.md
+++ b/doc/user/packages/nuget_repository/index.md
@@ -432,6 +432,21 @@ choco push MyPackage.1.0.0.nupkg --source "https://gitlab.example.com/api/v4/pro
When you publish a package with the same name or version as an existing package,
the existing package is overwritten.
+### Do not allow duplicate NuGet packages
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/293748) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `nuget_duplicates_option`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `nuget_duplicates_option`.
+The feature is not ready for production use.
+
+To prevent users from publishing duplicate NuGet packages, you can use the [GraphQl API](../../../api/graphql/reference/index.md#packagesettings).
+
+WARNING:
+If the .nuspec file isn't located in the root of the package, the package might
+not be recognized as a duplicate.
+
## Install packages
If multiple packages have the same name and version, when you install
diff --git a/doc/user/packages/package_registry/index.md b/doc/user/packages/package_registry/index.md
index 4d9ad03afde..59184b811d4 100644
--- a/doc/user/packages/package_registry/index.md
+++ b/doc/user/packages/package_registry/index.md
@@ -45,7 +45,7 @@ For information on how to create and upload a package, view the GitLab documenta
<!--- start_remove The following content will be removed on remove_date: '2023-11-22' -->
WARNING:
-[External authorization](../../admin_area/settings/external_authorization.md) will be enabled by default in GitLab 16.0. External authorization prevents personal access tokens and deploy tokens from accessing container and package registries and affects all users who use these tokens to access the registries. You can disable external authorization if you want to use personal access tokens and deploy tokens with the container or package registries.
+In GitLab 16.0 and later, [external authorization](../../admin_area/settings/external_authorization.md) prevents personal access tokens and deploy tokens from accessing container and package registries and affects all users who use these tokens to access the registries. You can disable external authorization if you want to use personal access tokens and deploy tokens with the container or package registries.
<!--- end_remove -->
Authentication depends on the package manager being used. For more information, see the docs on the
@@ -104,14 +104,9 @@ You can view which pipeline published the package, and the commit and user who t
### To import packages
If you already have packages built in a different registry, you can import them
-into your GitLab package registry with the [Packages Importer](https://gitlab.com/gitlab-org/ci-cd/package-stage/pkgs_importer).
+into your GitLab package registry with the [package importer](https://gitlab.com/gitlab-org/ci-cd/package-stage/pkgs_importer).
-The Packages Importer runs a CI/CD pipeline that [can import these package types](https://gitlab.com/gitlab-org/ci-cd/package-stage/pkgs_importer#formats-supported):
-
-- Maven
-- NPM
-- NuGet
-- PyPI
+For a list of supported packages, see [Importing packages from other repositories](supported_functionality.md#importing-packages-from-other-repositories).
## Reduce storage usage
@@ -163,7 +158,7 @@ Registry disables all Package Registry operations.
To allow anyone to pull from the Package Registry, regardless of project visibility:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your private or internal project.
+1. On the left sidebar, select **Search or go to** and find your private or internal project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Turn on the **Allow anyone to pull from Package Registry** toggle.
diff --git a/doc/user/packages/package_registry/supported_functionality.md b/doc/user/packages/package_registry/supported_functionality.md
index d3aa522f780..3e8852da808 100644
--- a/doc/user/packages/package_registry/supported_functionality.md
+++ b/doc/user/packages/package_registry/supported_functionality.md
@@ -39,7 +39,7 @@ Packages can be pulled from your project, group, or instance.
| [Maven (with `mvn`)](../maven_repository/index.md) | Y | Y | Y |
| [Maven (with `gradle`)](../maven_repository/index.md) | Y | Y | Y |
| [Maven (with `sbt`)](../maven_repository/index.md) | Y | Y | Y |
-| [npm](../npm_registry/index.md) | Y | N | Y |
+| [npm](../npm_registry/index.md) | Y | Y | Y |
| [NuGet](../nuget_repository/index.md) | Y | Y | N |
| [PyPI](../pypi_repository/index.md) | Y | Y | N |
| [Generic packages](../generic_packages/index.md) | Y | N | N |
@@ -72,7 +72,7 @@ Requests for packages not found in your GitLab project are forwarded to the publ
| [Go](../go_proxy/index.md) | N |
| [Ruby gems](../rubygems_registry/index.md) | N |
-### Deleting packages
+## Deleting packages
When package requests are forwarded to a public registry, deleting packages can
be a [dependency confusion vulnerability](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610).
@@ -89,6 +89,27 @@ To reduce the associated security risks, before deleting a package you can:
- Instance administrators can disable forwarding in the [**Continuous Integration** section](../../../administration/settings/continuous_integration.md#package-registry-configuration) of the Admin Area.
- Group owners can disable forwarding in the **Packages and Registries** section of the group settings.
+## Importing packages from other repositories
+
+You can use GitLab pipelines to import packages from other repositories, such as Maven Central or Artifactory with the [package importer tool](https://gitlab.com/gitlab-org/ci-cd/package-stage/pkgs_importer).
+
+| Package type | Importer available? |
+|-------------------------------------------------------|---------------------|
+| [Maven (with `mvn`)](../maven_repository/index.md) | Y |
+| [Maven (with `gradle`)](../maven_repository/index.md) | Y |
+| [Maven (with `sbt`)](../maven_repository/index.md) | Y |
+| [npm](../npm_registry/index.md) | Y |
+| [NuGet](../nuget_repository/index.md) | Y |
+| [PyPI](../pypi_repository/index.md) | Y |
+| [Generic packages](../generic_packages/index.md) | N |
+| [Terraform](../terraform_module_registry/index.md) | N |
+| [Composer](../composer_repository/index.md) | N |
+| [Conan](../conan_repository/index.md) | N |
+| [Helm](../helm_repository/index.md) | N |
+| [Debian](../debian_repository/index.md) | N |
+| [Go](../go_proxy/index.md) | N |
+| [Ruby gems](../rubygems_registry/index.md) | N |
+
## Allow or prevent duplicates **(FREE ALL)**
By default, the GitLab package registry either allows or prevents duplicates based on the default of that specific package manager format.
diff --git a/doc/user/packages/rubygems_registry/index.md b/doc/user/packages/rubygems_registry/index.md
index 1c898ee6d92..361114e6f9e 100644
--- a/doc/user/packages/rubygems_registry/index.md
+++ b/doc/user/packages/rubygems_registry/index.md
@@ -4,7 +4,7 @@ group: Package Registry
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Ruby gems in the Package Registry **(FREE ALL)**
+# Ruby gems in the Package Registry **(FREE ALL EXPERIMENT)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/803) in GitLab 13.10.
diff --git a/doc/user/packages/yarn_repository/index.md b/doc/user/packages/yarn_repository/index.md
index 262e15fe240..52accfc4fae 100644
--- a/doc/user/packages/yarn_repository/index.md
+++ b/doc/user/packages/yarn_repository/index.md
@@ -82,7 +82,7 @@ authentication token or use a private runner.
To create an authentication token for your project or group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. On the left sidebar, select **Settings > Repository > Deploy Tokens**.
1. Create a deployment token with `read_package_registry` and `write_package_registry` scopes and copy the generated token.
1. On the left sidebar, select **Settings > CI/CD > Variables**.
@@ -301,7 +301,7 @@ Then you can use `yarn add` to install your packages.
## Related topics
- [npm documentation](../npm_registry/index.md#helpful-hints)
-- [Yarn Migration Guide](https://yarnpkg.com/getting-started/migration)
+- [Yarn Migration Guide](https://yarnpkg.com/migration/guide/)
## Troubleshooting
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index d19f98b98ed..dadfb75ed4e 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -66,10 +66,10 @@ The following table lists project permissions available for each role:
| [Analytics](analytics/index.md):<br>View [repository analytics](analytics/repository_analytics.md) | | ✓ | ✓ | ✓ | ✓ |
| [Application security](application_security/index.md):<br>View licenses in [dependency list](application_security/dependency_list/index.md) | | | ✓ | ✓ | ✓ |
| [Application security](application_security/index.md):<br>Create and run [on-demand DAST scans](application_security/dast/proxy-based.md#on-demand-scans) | | | ✓ | ✓ | ✓ |
-| [Application security](application_security/index.md):<br>Manage [security policy](application_security/policies/index.md) | | | ✓ | ✓ | ✓ |
| [Application security](application_security/index.md):<br>View [dependency list](application_security/dependency_list/index.md) | | | ✓ | ✓ | ✓ |
| [Application security](application_security/index.md):<br>Create a [CVE ID Request](application_security/cve_id_request.md) | | | | ✓ | ✓ |
| [Application security](application_security/index.md):<br>Create or assign [security policy project](application_security/policies/index.md) | | | | | ✓ |
+| [Application security](application_security/index.md):<br>Create, edit, delete [individual security policies](application_security/policies/index.md) | | | ✓ | ✓ | ✓ |
| [GitLab Agent for Kubernetes](clusters/agent/index.md):<br>View agents | | | ✓ | ✓ | ✓ |
| [GitLab Agent for Kubernetes](clusters/agent/index.md):<br>Manage agents | | | | ✓ | ✓ |
| [Container Registry](packages/container_registry/index.md):<br>Create, edit, delete [cleanup policies](packages/container_registry/delete_container_registry_images.md#use-a-cleanup-policy) | | | | ✓ | ✓ |
@@ -132,9 +132,6 @@ The following table lists project permissions available for each role:
| [Merge requests](project/merge_requests/index.md):<br>[Resolve a thread](project/merge_requests/index.md#resolve-a-thread) | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Manage [merge approval rules](project/merge_requests/approvals/settings.md) (project settings) | | | | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Delete | | | | | ✓ |
-| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>Manage user-starred metrics dashboards (6) | ✓ | ✓ | ✓ | ✓ | ✓ |
-| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>View metrics dashboard annotations | | ✓ | ✓ | ✓ | ✓ |
-| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ |
| [Package registry](packages/index.md):<br>Pull a package | ✓ (1) | ✓ | ✓ | ✓ | ✓ |
| [Package registry](packages/index.md):<br>Publish a package | | | ✓ | ✓ | ✓ |
| [Package registry](packages/index.md):<br>Delete a package | | | | ✓ | ✓ |
@@ -173,7 +170,7 @@ The following table lists project permissions available for each role:
| [Projects](project/index.md):<br>Rename project | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Share (invite) projects with groups | | | | ✓ (7) | ✓ (7) |
| [Projects](project/index.md):<br>View 2FA status of members | | | | ✓ | ✓ |
-| [Projects](project/index.md):<br>Assign project to a [compliance framework](project/settings/index.md#add-a-compliance-framework-to-a-project) | | | | | ✓ |
+| [Projects](project/index.md):<br>Assign project to a [compliance framework](project/working_with_projects.md#add-a-compliance-framework-to-a-project) | | | | | ✓ |
| [Projects](project/index.md):<br>Archive project | | | | | ✓ |
| [Projects](project/index.md):<br>Change project visibility level | | | | | ✓ |
| [Projects](project/index.md):<br>Delete project | | | | | ✓ |
@@ -384,7 +381,7 @@ The following table lists group permissions available for each role:
| Delete [group wiki](project/wiki/group.md) pages | | | ✓ | ✓ | ✓ |
| Edit [epic](group/epics/index.md) comments (posted by any user) | | | | ✓ | ✓ |
| List group deploy tokens | | | | ✓ | ✓ |
-| Manage [group push rules](group/access_and_permissions.md#group-push-rules) | | | | ✓ | ✓ |
+| Manage [group push rules](group/access_and_permissions.md#group-push-rules) | | | | ✓ | ✓ |
| View/manage group-level Kubernetes cluster | | | | ✓ | ✓ |
| Create and manage compliance frameworks | | | | | ✓ |
| Create/Delete group deploy tokens | | | | | ✓ |
@@ -401,6 +398,7 @@ The following table lists group permissions available for each role:
| View 2FA status of members | | | | | ✓ |
| View [Billing](../subscriptions/gitlab_com/index.md#view-your-gitlab-saas-subscription) | | | | | ✓ (3) |
| View group [Usage Quotas](usage_quotas.md) page | | | | | ✓ (3) |
+| View group runners | | | | ✓ | ✓ |
| Manage group runners | | | | | ✓ |
| [Migrate groups](group/import/index.md) | | | | | ✓ |
| Manage [subscriptions, and purchase storage and compute minutes](../subscriptions/gitlab_com/index.md) | | | | | ✓ |
@@ -473,10 +471,10 @@ To work around the issue, give these users the Guest role or higher to any proje
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106256) in GitLab 15.7 [with a flag](../administration/feature_flags.md) named `customizable_roles`.
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/110810) in GitLab 15.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114524) in GitLab 15.10.
-> - The ability for a custom role to view a vulnerability report [introduced](https://gitlab.com/groups/gitlab-org/-/epics/10160) in GitLab 16.1.
-
-FLAG:
-On self-managed GitLab, by default the ability for a custom role to view a vulnerability report is not available. To make it available, an administrator can [enable the feature flag](../administration/feature_flags.md) named `elevated_guests`. On GitLab.com, this feature is available.
+> - The ability for a custom role to view a vulnerability report [introduced](https://gitlab.com/groups/gitlab-org/-/epics/10160) in GitLab 16.1 [with a flag](../administration/feature_flags.md) named `custom_roles_vulnerability`.
+> - Ability to view a vulnerability report [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123835) in GitLab 16.1.
+> - [Feature flag `custom_roles_vulnerability` removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124049) in GitLab 16.2.
+> - Ability to create and remove a custom role with the UI [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/393235) in GitLab 16.4.
Custom roles allow group members who are assigned the Owner role to create roles
specific to the needs of their organization.
@@ -488,24 +486,65 @@ The following custom roles are available:
- The Guest+1 role, which allows users with the Guest role to view code.
- In GitLab 16.1 and later, you can create a custom role that can view vulnerability reports and change the status of the vulnerabilities.
+- In GitLab 16.3 and later, you can create a custom role that can view the dependency list.
+- In GitLab 16.4 and later, you can create a custom role that can approve merge requests.
You can discuss individual custom role and permission requests in [issue 391760](https://gitlab.com/gitlab-org/gitlab/-/issues/391760).
-When you enable the view vulnerability custom role for a user with the Guest role, that user has access to elevated permissions, and therefore:
+When you enable a custom role for a user with the Guest role, that user has
+access to elevated permissions, and therefore:
- Is considered a [billable user](../subscriptions/self_managed/index.md#billable-users) on self-managed GitLab.
- [Uses a seat](../subscriptions/gitlab_com/index.md#how-seat-usage-is-determined) on GitLab.com.
-This does not apply to the Guest+1 custom role because the `view_code` ability is excluded from this behavior.
+This does not apply to Guest+1, a Guest custom role that only enables the `read_code`
+permission. Users with that specific custom role are not considered billable users
+and do not use a seat.
### Create a custom role
-To enable custom roles for your group, a group member with the Owner role:
+Prerequisites:
+
+- You must be an administrator for the self-managed instance, or have the Owner
+ role in the group you are creating the custom role in.
+- The group must be in the Ultimate tier.
+- You must have:
+ - At least one private project so that you can see the effect of giving a
+ user with the Guest role a custom role. The project can be in the group itself
+ or one of that group's subgroups.
+ - A [personal access token with the API scope](profile/personal_access_tokens.md#create-a-personal-access-token).
+
+#### GitLab SaaS
+
+Prerequisite:
+
+- You must have the Owner role in the group you are creating the custom role in.
+
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **Settings > Roles and Permissions**.
+1. Select **Add new role**.
+1. In **Base role to use as template**, select **Guest**.
+1. In **Role name**, enter the custom role's title.
+1. Select the **Permissions** for the new custom role.
+1. Select **Create new role**.
+
+#### Self Managed GitLab Instances
+
+Prerequisite:
+
+- You must be an administrator for the self-managed instance you are creating the custom role in.
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. Select **Settings > Roles and Permissions**.
+1. From the top dropdown list, select the group you want to create a custom role in.
+1. Select **Add new role**.
+1. In **Base role to use as template**, select **Guest**.
+1. In **Role name**, enter the custom role's title.
+1. Select the **Permissions** for the new custom role.
+1. Select **Create new role**.
-1. Makes sure that there is at least one private project in this group or one of
- its subgroups, so that you can see the effect of giving a Guest a custom role.
-1. Creates a personal access token with the API scope.
-1. Uses [the API](../api/member_roles.md#add-a-member-role-to-a-group) to create a custom role for the root group.
+To create a custom role, you can also [use the API](../api/member_roles.md#add-a-member-role-to-a-group).
#### Custom role requirements
@@ -518,7 +557,9 @@ You can see the required minimal access levels and abilities requirements in the
| Ability | Minimal access level | Required ability |
| -- | -- | -- |
| `read_code` | Guest | - |
+| `read_dependency` | Guest | - |
| `read_vulnerability` | Guest | - |
+| `admin_merge_request` | Guest | - |
| `admin_vulnerability` | Guest | `read_vulnerability` |
### Associate a custom role with an existing group member
@@ -529,53 +570,77 @@ the Owner role:
1. Invites a user as a direct member to the root group or any subgroup or project in the root
group's hierarchy as a Guest. At this point, this Guest user cannot see any
code on the projects in the group or subgroup.
-1. Optional. If the Owner does not know the `ID` of the Guest user receiving a custom
- role, finds that `ID` by making an [API request](../api/member_roles.md#list-all-member-roles-of-a-group).
+1. Optional. If the Owner does not know the `id` of the Guest user receiving a custom
+ role, finds that `id` by making an [API request](../api/member_roles.md#list-all-member-roles-of-a-group).
1. Associates the member with the Guest+1 role using the [Group and Project Members API endpoint](../api/members.md#edit-a-member-of-a-group-or-project)
```shell
# to update a project membership
- curl --request PUT --header "Content-Type: application/json" --header "Authorization: Bearer $YOUR_ACCESS_TOKEN" --data '{"member_role_id": '$MEMBER_ROLE_ID', "access_level": 10}' "https://example.gitlab.com/api/v4/projects/$ID/members/$GUEST_USER_ID"
+ curl --request PUT --header "Content-Type: application/json" --header "Authorization: Bearer <your_access_token>" --data '{"member_role_id": '<member_role_id>', "access_level": 10}' "https://gitlab.example.com/api/v4/projects/<project_id>/members/<user_id>"
# to update a group membership
- curl --request PUT --header "Content-Type: application/json" --header "Authorization: Bearer $YOUR_ACCESS_TOKEN" --data '{"member_role_id": '$MEMBER_ROLE_ID', "access_level": 10}' "https://example.gitlab.com/api/v4/groups/$ID/members/$GUEST_USER_ID"
+ curl --request PUT --header "Content-Type: application/json" --header "Authorization: Bearer <your_access_token>" --data '{"member_role_id": '<member_role_id>', "access_level": 10}' "https://gitlab.example.com/api/v4/groups/<group_id>/members/<user_id>"
```
Where:
- - `$ID`: The `ID` or [URL-encoded path of the project or group](../api/rest/index.md#namespaced-path-encoding) associated with the membership receiving the custom role.
- - `$MEMBER_ROLE_ID`: The `ID` of the member role created in the previous section.
- - `$GUEST_USER_ID`: The `ID` of the Guest user receiving a custom role.
+ - `<project_id` and `<group_id>`: The `id` or [URL-encoded path of the project or group](../api/rest/index.md#namespaced-path-encoding) associated with the membership receiving the custom role.
+ - `<member_role_id>`: The `id` of the member role created in the previous section.
+ - `<user_id>`: The `id` of the user receiving a custom role.
Now the Guest+1 user can view code on all projects associated with this membership.
-### Remove a custom role from a group member
+### Remove a custom role
+
+Prerequisite:
+
+- You must be an administrator or have the Owner role in the group you are removing the custom role from.
+
+You can remove a custom role from a group only if no group members have that role.
+
+To do this, you can either remove the custom role from all group members with that custom role, or remove those members from the group.
+
+#### Remove a custom role from a group member
To remove a custom role from a group member, use the [Group and Project Members API endpoint](../api/members.md#edit-a-member-of-a-group-or-project)
and pass an empty `member_role_id` value.
```shell
-curl --request PUT --header "Content-Type: application/json" --header "Authorization: Bearer $YOUR_ACCESS_TOKEN" --data '{"member_role_id": "", "access_level": 10}' "https://example.gitlab.com/api/v4/groups/$GROUP_PATH/members/$GUEST_USER_ID"
+# to update a project membership
+curl --request PUT --header "Content-Type: application/json" --header "Authorization: Bearer <your_access_token>" --data '{"member_role_id": "", "access_level": 10}' "https://gitlab.example.com/api/v4/projects/<project_id>/members/<user_id>"
+
+# to update a group membership
+curl --request PUT --header "Content-Type: application/json" --header "Authorization: Bearer <your_access_token>" --data '{"member_role_id": "", "access_level": 10}' "https://gitlab.example.com/api/v4/groups/<group_id>/members/<user_id>"
```
-Now the user is a regular Guest.
+#### Remove a group member with a custom role from the group
-### Remove a custom role
+1. On the left sidebar, select **Search or go to** and find your group.
+1. Select **Manage > Members**.
+1. On the member row you want to remove, select the vertical ellipsis
+ (**{ellipsis_v}**) and select **Remove member**.
+1. In the **Remove member** confirmation dialog, do not select any checkboxes.
+1. Select **Remove member**.
-Removing a custom role also removes all members with that custom role from
-the group. If you decide to delete a custom role, you must re-add any users with that custom
-role to the group.
+#### Delete the custom role
-To remove a custom role from a group, a group member with
-the Owner role:
+After you have made sure no group members have that custom role, delete the
+custom role.
+
+1. On the left sidebar, select **Search or go to**.
+1. GitLab.com only. Select **Admin Area**.
+1. Select **Settings > Roles and Permissions**.
+1. Select **Custom Roles**.
+1. In the **Actions** column, select **Delete role** (**{remove}**) and confirm.
-1. Optional. If the Owner does not know the `ID` of a custom
- role, finds that `ID` by making an [API request](../api/member_roles.md#list-all-member-roles-of-a-group).
-1. Uses [the API](../api/member_roles.md#remove-member-role-of-a-group) to delete the custom role.
+To delete a custom role, you can also [use the API](../api/member_roles.md#remove-member-role-of-a-group).
+To use the API, you must know the `id` of the custom role. If you do not know this
+`id`, find it by making an [API request](../api/member_roles.md#list-all-member-roles-of-a-group).
### Known issues
-- Additional permissions can only be applied to users with the Guest role.
-- If a user with a custom role is shared with a group or project, their custom role is not transferred over with them. The user has the regular Guest role in the new group or project.
+- If a user with a custom role is shared with a group or project, their custom
+ role is not transferred over with them. The user has the regular Guest role in
+ the new group or project.
- You cannot use an [Auditor user](../administration/auditor_users.md) as a template for a custom role.
diff --git a/doc/user/product_analytics/index.md b/doc/user/product_analytics/index.md
index 06a90af55c7..d90b2d5c882 100644
--- a/doc/user/product_analytics/index.md
+++ b/doc/user/product_analytics/index.md
@@ -4,26 +4,23 @@ group: Product Analytics
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Product analytics (Experiment) **(ULTIMATE ALL)**
+# Product analytics **(ULTIMATE ALL EXPERIMENT)**
> - Introduced in GitLab 15.4 as an [Experiment](../../policy/experiment-beta-support.md#experiment) feature [with a flag](../../administration/feature_flags.md) named `cube_api_proxy`. Disabled by default.
> - `cube_api_proxy` revised to only reference the [Product Analytics API](../../api/product_analytics.md) in GitLab 15.6.
> - `cube_api_proxy` removed and replaced with `product_analytics_internal_preview` in GitLab 15.10.
> - `product_analytics_internal_preview` replaced with `product_analytics_dashboards` in GitLab 15.11.
-> - Snowplow integration introduced in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `product_analytics_snowplow_support`. Disabled by default.
+> - Snowplow integration [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/398253) in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `product_analytics_snowplow_support`. Disabled by default.
+> - Snowplow integration feature flag `product_analytics_snowplow_support` [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130228) in GitLab 16.4.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `product_analytics_dashboards`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
-FLAG:
-On self-managed GitLab, by default the Snowplow integration is not available. To make it available per project or for your entire instance, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `product_analytics_snowplow_support`.
-On GitLab.com, this feature is not available.
-This feature is not ready for production use.
-
This page is a work in progress, and we're updating the information as we add more features.
For more information, see the [group direction page](https://about.gitlab.com/direction/analytics/product-analytics/).
+To leave feedback about Product Analytics bugs or functionality, please comment in [issue 391970](https://gitlab.com/gitlab-org/gitlab/-/issues/391970) or open a new issue with the label `group::product analytics`.
## How product analytics works
@@ -66,7 +63,7 @@ flowchart TB
> - `product_analytics_internal_preview` replaced with `product_analytics_dashboards` in GitLab 15.11.
FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, an administrator can [enable the feature flags](../../administration/feature_flags.md) named `product_analytics_dashboards` and `product_analytics_admin_settings`.
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, an administrator can [enable the feature flags](../../administration/feature_flags.md) named `product_analytics_dashboards`, `product_analytics_admin_settings`, and `combined_analytics_dashboards`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
@@ -77,7 +74,7 @@ Prerequisite:
- You must be an administrator of a self-managed GitLab instance.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand the **Analytics** tab and find the **Product analytics** section.
@@ -93,8 +90,9 @@ Prerequisites:
- Product analytics must be enabled at the instance-level.
- You must have at least the Maintainer role for the project or group the project belongs to.
+- The project must be in a group namespace.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Analytics**.
1. Expand **Configure** and enter the configuration values.
1. Select **Save changes**.
@@ -105,6 +103,9 @@ To instrument code to collect data, use one or more of the existing SDKs:
- [Browser SDK](https://gitlab.com/gitlab-org/analytics-section/product-analytics/gl-application-sdk-browser)
- [Ruby SDK](https://gitlab.com/gitlab-org/analytics-section/product-analytics/gl-application-sdk-rb)
+- [Python SDK](https://gitlab.com/gitlab-org/analytics-section/product-analytics/gl-application-sdk-python)
+- [Node SDK](https://gitlab.com/gitlab-org/analytics-section/product-analytics/gl-application-sdk-node)
+- [.NET SDK](https://gitlab.com/gitlab-org/analytics-section/product-analytics/gl-application-sdk-dotnet)
## Product analytics dashboards
diff --git a/doc/user/profile/account/create_accounts.md b/doc/user/profile/account/create_accounts.md
index f2f1921f0bb..c3612b787ac 100644
--- a/doc/user/profile/account/create_accounts.md
+++ b/doc/user/profile/account/create_accounts.md
@@ -1,6 +1,6 @@
---
type: reference
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -33,7 +33,7 @@ Prerequisite:
To create a user manually:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select **New user**.
diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md
index 2694ed5f213..cf6ee61660f 100644
--- a/doc/user/profile/account/delete_account.md
+++ b/doc/user/profile/account/delete_account.md
@@ -1,6 +1,6 @@
---
type: howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -36,7 +36,7 @@ On GitLab.com, there is a seven day delay between a user deleting their own acco
As an administrator, to delete a user account:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Overview > Users**.
1. Select a user.
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index 83bdf883510..c7633b2c664 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -62,6 +62,8 @@ In GitLab 14.3 and later, your account email must be confirmed to enable 2FA.
To enable 2FA with a one-time password:
+<!-- vale gitlab.Substitutions = NO -->
+
1. **In GitLab:**
1. Access your [**User settings**](../index.md#access-your-user-settings).
1. Select **Account**.
@@ -70,7 +72,7 @@ To enable 2FA with a one-time password:
1. Install a compatible application. For example:
- Cloud-based (recommended because you can restore access if you lose the hardware device):
- [Authy](https://authy.com/).
- - [Duo](https://duo.com/).
+ - [Cisco Duo](https://duo.com/).
- Other (proprietary):
- [Google Authenticator](https://support.google.com/accounts/answer/1066447?hl=en).
- [Microsoft Authenticator](https://www.microsoft.com/en-us/security/mobile-authenticator-app).
@@ -85,6 +87,8 @@ To enable 2FA with a one-time password:
1. Enter your current password.
1. Select **Submit**.
+<!-- vale gitlab.Substitutions = YES -->
+
If you entered the correct pin, GitLab displays a list of [recovery codes](#recovery-codes). Download them and keep them
in a safe place.
@@ -152,27 +156,33 @@ Configure FortiAuthenticator in GitLab. On your GitLab server:
(Linux package installations) or [restart](../../../administration/restart_gitlab.md#self-compiled-installations)
(self-compiled installations).
-### Enable one-time password using Duo
+<!-- vale gitlab.Substitutions = NO -->
+
+### Enable one-time password using Cisco Duo
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15760) in GitLab 15.10.
FLAG:
On self-managed GitLab, by default this feature is available. On GitLab.com this feature is not available.
-You can use Duo as an OTP provider in GitLab.
+You can use Cisco Duo as an OTP provider in GitLab.
+
+DUO® is a registered trademark of Cisco Systems, Inc., and/or its affiliates in the United States and certain other countries.
#### Prerequisites
-To use Duo as an OTP provider:
+To use Cisco Duo as an OTP provider:
+
+- Your account must exist in both Cisco Duo and GitLab, with the same username in both applications.
+- You must have [configured Cisco Duo](https://admin.duosecurity.com/) and have an integration key, secret key, and API hostname.
-- Your account must exist in both Duo and GitLab, with the same username in both applications.
-- You must have [configured Duo](https://admin.duosecurity.com/) and have an integration key, secret key, and API hostname.
+For more information, see the [Cisco Duo API documentation](https://duo.com/docs/authapi).
-For more information, see the [Duo API documentation](https://duo.com/docs/authapi).
+GitLab 15.10 has been tested with Cisco Duo version D261.14
-GitLab 15.10 has been tested with Duo version D261.14
+#### Configure Cisco Duo in GitLab
-#### Configure Duo in GitLab
+<!-- vale gitlab.Substitutions = YES -->
On your GitLab server:
diff --git a/doc/user/profile/achievements.md b/doc/user/profile/achievements.md
index 080ab41083b..1b875e984a1 100644
--- a/doc/user/profile/achievements.md
+++ b/doc/user/profile/achievements.md
@@ -4,7 +4,7 @@ group: Tenant Scale
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Achievements (Experiment) **(FREE ALL)**
+# Achievements **(FREE ALL EXPERIMENT)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113156) in GitLab 15.10 [with a flag](../../administration/feature_flags.md) named `achievements`. Disabled by default.
diff --git a/doc/user/profile/img/profile-preferences-syntax-themes_v15_11.png b/doc/user/profile/img/profile-preferences-syntax-themes_v15_11.png
deleted file mode 100644
index 39cd35f3b5b..00000000000
--- a/doc/user/profile/img/profile-preferences-syntax-themes_v15_11.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index a25260c3db9..cff18654292 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -1,6 +1,6 @@
---
type: index, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -353,7 +353,7 @@ A list of **Most Recent Activity** contributions is displayed.
To view your activity:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. Select **Activity**.
1. Optional. To filter your activity by contribution type, in the **Your Activity** tab, select a tab:
@@ -397,15 +397,15 @@ When you sign in, three cookies are set:
- A session cookie called `_gitlab_session`.
This cookie has no set expiration date. However, it expires based on its `session_expire_delay`.
-- A session cookie called `about_gitlab_active_user`.
- This cookie is used by the [marketing site](https://about.gitlab.com/) to determine if a user has an active GitLab session. No user information is passed to the cookie and it expires with the session.
+- A session cookie called `gitlab_user`.
+ This cookie is used by the [marketing site](https://about.gitlab.com/) to determine if a user has an active GitLab session. No user information is passed to the cookie and it expires two weeks from login.
- A persistent cookie called `remember_user_token`, which is set only if you selected **Remember me** on the sign-in page.
-When you close your browser, the `_gitlab_session` and `about_gitlab_active_user` cookies are usually cleared client-side.
+When you close your browser, the `_gitlab_session` and `gitlab_user` cookies are usually cleared client-side.
When it expires or isn't available, GitLab:
- Uses the `remember_user_token`cookie to get you a new `_gitlab_session` cookie and keep you signed in, even if you close your browser.
-- Sets the `about_gitlab_active_user` to `true`.
+- Sets the `gitlab_user` to `true`.
When both the `remember_user_token` and `_gitlab_session` cookies are gone or expired, you must sign in again.
diff --git a/doc/user/profile/notifications.md b/doc/user/profile/notifications.md
index f1310bbb323..706065d4693 100644
--- a/doc/user/profile/notifications.md
+++ b/doc/user/profile/notifications.md
@@ -107,7 +107,7 @@ To select a notification level for a group, use either of these methods:
Or:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select the notification dropdown list, next to the bell icon (**{notifications}**).
1. Select the desired [notification level](#notification-levels).
@@ -138,7 +138,7 @@ To select a notification level for a project, use either of these methods:
Or:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select the notification dropdown list, next to the bell icon (**{notifications}**).
1. Select the desired [notification level](#notification-levels).
@@ -275,6 +275,7 @@ epics:
| Merge Request | New note | Participants, Watchers, Subscribers, and Custom notification level with this event selected. Also anyone mentioned by username in the comment, with notification level "Mention" or higher. |
| Merge Request | Pushed | Participants and Custom notification level with this event selected. |
| Merge Request | Reassigned | Participants, Watchers, Subscribers, Custom notification level with this event selected, and the old assignee. |
+| Merge Request | Review requested | Participants, Watchers, Subscribers, Custom notification level with this event selected, and the old reviewer. |
| Merge Request | Reopened | Subscribers and participants. |
| Merge Request | Title or description changed | Any new mentions by username. |
| Pipeline | Failed | The author of the pipeline. |
@@ -367,20 +368,21 @@ a merge request or an issue.
The following table lists all GitLab-specific email headers:
-| Header | Description |
-| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
-| `List-Id` | The path of the project in an RFC 2919 mailing list identifier. You can use it for email organization with filters. |
-| `X-GitLab-(Resource)-ID` | The ID of the resource the notification is for. The resource, for example, can be `Issue`, `MergeRequest`, `Commit`, or another such resource. |
-| `X-GitLab-ConfidentialIssue` | The boolean value indicating issue confidentiality for notifications. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222908) in GitLab 16.0. |
-| `X-GitLab-Discussion-ID` | The ID of the thread the comment belongs to, in notification emails for comments. |
-| `X-GitLab-Group-Id` | The group's ID. Only present on notification emails for [epics](../group/epics/index.md). |
-| `X-GitLab-Group-Path` | The group's path. Only present on notification emails for [epics](../group/epics/index.md) |
-| `X-GitLab-NotificationReason` | The reason for the notification. [See possible values.](#x-gitlab-notificationreason). |
-| `X-GitLab-Pipeline-Id` | The ID of the pipeline the notification is for, in notification emails for pipelines. |
-| `X-GitLab-Project-Id` | The project's ID. |
-| `X-GitLab-Project-Path` | The project's path. |
-| `X-GitLab-Project` | The name of the project the notification belongs to. |
-| `X-GitLab-Reply-Key` | A unique token to support reply by email. |
+| Header | Description |
+| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `List-Id` | The path of the project in an RFC 2919 mailing list identifier. You can use it for email organization with filters. |
+| `X-GitLab-(Resource)-ID` | The ID of the resource the notification is for. The resource, for example, can be `Issue`, `MergeRequest`, `Commit`, or another such resource. |
+| `X-GitLab-(Resource)-State` | The state of the resource the notification is for. The resource can be, for example, `Issue` or `MergeRequest`. The value can be `opened`, `closed`, `merged`, or `locked`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130967) in GitLab 16.4. |
+| `X-GitLab-ConfidentialIssue` | The boolean value indicating issue confidentiality for notifications. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222908) in GitLab 16.0. |
+| `X-GitLab-Discussion-ID` | The ID of the thread the comment belongs to, in notification emails for comments. |
+| `X-GitLab-Group-Id` | The group's ID. Only present on notification emails for [epics](../group/epics/index.md). |
+| `X-GitLab-Group-Path` | The group's path. Only present on notification emails for [epics](../group/epics/index.md) |
+| `X-GitLab-NotificationReason` | The reason for the notification. [See possible values.](#x-gitlab-notificationreason). |
+| `X-GitLab-Pipeline-Id` | The ID of the pipeline the notification is for, in notification emails for pipelines. |
+| `X-GitLab-Project-Id` | The project's ID. |
+| `X-GitLab-Project-Path` | The project's path. |
+| `X-GitLab-Project` | The name of the project the notification belongs to. |
+| `X-GitLab-Reply-Key` | A unique token to support reply by email. |
### X-GitLab-NotificationReason
diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index 9161f5d4cf6..c3361040a00 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -1,6 +1,6 @@
---
type: concepts, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -104,7 +104,8 @@ To view the last time a token was used:
## Personal access token scopes
-> Personal access tokens no longer being able to access container or package registries [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387721) in GitLab 16.0.
+> - Personal access tokens no longer being able to access container or package registries [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387721) in GitLab 16.0.
+> - `k8s_proxy` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/422408) in GitLab 16.4 [with a flag](../../administration/feature_flags.md) named `k8s_proxy_pat`. Enabled by default.
A personal access token can perform actions based on the assigned scopes.
@@ -120,13 +121,15 @@ A personal access token can perform actions based on the assigned scopes.
| `sudo` | Grants permission to perform API actions as any user in the system, when authenticated as an administrator. |
| `admin_mode` | Grants permission to perform API actions as an administrator, when Admin Mode is enabled. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107875) in GitLab 15.8.) |
| `create_runner` | Grants permission to create runners. |
+| `ai_features` | Grants permission to perform API actions for GitLab Duo. |
+| `k8s_proxy` | Grants permission to perform Kubernetes API calls using the agent for Kubernetes. |
WARNING:
If you enabled [external authorization](../admin_area/settings/external_authorization.md), personal access tokens cannot access container or package registries. If you use personal access tokens to access these registries, this measure breaks this use of these tokens. Disable external authorization to use personal access tokens with container or package registries.
## When personal access tokens expire
-Personal access tokens expire on the date you define, at midnight UTC.
+Personal access tokens expire on the date you define, at midnight, 00:00 AM UTC.
- GitLab runs a check at 01:00 AM UTC every day to identify personal access tokens that expire in the next seven days. The owners of these tokens are notified by email.
- GitLab runs a check at 02:00 AM UTC every day to identify personal access tokens that expire on the current date. The owners of these tokens are notified by email.
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index 2df2674d539..f057e62694b 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -13,7 +13,7 @@ You can update your preferences to change the look and feel of GitLab.
You can change the color theme of the GitLab UI. These colors are displayed on the left sidebar.
Using individual color themes might help you differentiate between your different
-GitLab instances.
+GitLab instances.
To change the color theme:
@@ -25,7 +25,7 @@ To change the color theme:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28252) in GitLab 13.1 as an [Experiment](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28252).
-Dark mode makes elements on the GitLab UI stand out on a dark background.
+Dark mode makes elements on the GitLab UI stand out on a dark background.
- To turn on Dark mode, Select **Preferences > Color theme > Dark Mode**.
@@ -44,139 +44,304 @@ To change the syntax highlighting theme:
1. In the **Syntax highlighting theme** section, select a theme.
1. Select **Save changes**.
-To view the updated syntax highlighting theme, refresh your project's page.
+To view the updated syntax highlighting theme, refresh your project's page.
To customize the syntax highlighting theme, you can also [use the Application settings API](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls). Use `default_syntax_highlighting_theme` to change the syntax highlighting colors on a more granular level.
-If these steps do not work, your programming language might not be supported by the syntax highlighters.
+If these steps do not work, your programming language might not be supported by the syntax highlighters.
For more information, view [Rouge Ruby Library](https://github.com/rouge-ruby/rouge) for guidance on code files and Snippets. View [Moncaco Editor](https://microsoft.github.io/monaco-editor/) and [Monarch](https://microsoft.github.io/monaco-editor/monarch.html) for guidance on the Web IDE.
## Change the diff colors
-Diffs use two different background colors to show changes between versions of code. By default, the original file in red and the changes made in green.
+Diffs use two different background colors to show changes between versions of code. By default, the original file is in red, and the changes are in green.
To change the diff colors:
1. On the left sidebar, select your avatar.
1. Select **Preferences**.
-1. Go to the **Diff colors** section.
-1. Complete the fields.
+1. Go to the **Diff colors** section.
+1. Select a color or enter a color code.
1. Select **Save changes**.
-1. Optional. Type a color code in the fields.
+
+To change back to the default colors, clear the **Color for removed lines** and **Color for added lines** text boxes and select **Save changes**.
## Behavior
-The following settings allow you to customize the behavior of the GitLab layout
-and default views of your dashboard and the projects' landing pages.
+Use the **Behavior** section to customize the behavior and layout of your GitLab self-managed instance. You can change your layout width and choose the default content for your homepage, group and project overview pages. You have options to customize appearance and function, like whitespace rendering, file display, and text automation.
-### Layout width
+### Change the layout width on the UI
-GitLab can be set up to use different widths depending on your liking. Choose
-between the fixed (max. `1280px`) and the fluid (`100%`) application layout.
+You can stretch content on the GitLab UI to fill the entire page. By default, page content is fixed at 1280 pixels wide.
-NOTE:
-While `1280px` is the standard max width when using fixed layout, some pages still use 100% width, depending on the content.
+To change the layout width of your UI:
-### Homepage
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. Under **Layout width**, choose **Fixed** or **Fluid**.
+1. Select **Save changes**.
-This setting changes the behavior of the tanuki icon in the upper-left corner of GitLab.
+### Choose your homepage
-### Group overview content
+Control what page you view when you select the GitLab logo (**{tanuki}**). You can set your homepage to be Projects (default), Your Groups, Your Activity, and other content.
-The **Group overview content** dropdown list allows you to choose what information is
-displayed on a group's home page.
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. For **Homepage**, select a default.
+1. Select **Save changes**.
-You can choose between 2 options:
+### Customize default content on your group overview page
-- Details (default)
-- [Security dashboard](../application_security/security_dashboard/index.md)
+You can change the main content on your group overview page. Your group overview page is the page that shows when you select **Groups** on the left sidebar. You can customize the default content for your group overview page to the:
-### Project overview content
+- Details Dashboard (default), which includes an overview of group activities and projects.
+- Security Dashboard, which might include group security policies and other security topics.
-The **Project overview content** setting allows you to choose what content you want to
-see on a project's home page.
+For more information, view [Groups](../../user/group/index.md).
-If **Files and Readme** is selected, you can show or hide the shortcut buttons above the file list on the project overview with the **Show shortcut buttons above files on project overview** setting.
+To change the default content on your group overview page:
-### Tab width
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. For **Group overivew content**, select an option.
+1. Select **Save changes**.
-You can set the displayed width of tab characters across various parts of
-GitLab, for example, blobs, diffs, and snippets.
+### Customize default content on your project overview page
-NOTE:
-Some parts of GitLab do not respect this setting, including the WebIDE, file
-editor and Markdown editor.
+Your project overview page is the page you view when you select **Project overview** on the left sidebar. You can set your main project overview page to the Activity page, the Readme file, and other content.
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. For **Project overivew content**, select an option.
+1. Select **Save changes**.
+
+### Hide shortcut buttons
+
+Shortcut buttons precede the list of files on a project's overview page. These buttons provide links to parts of a project, such as the README file or license agreements.
+
+To hide shortcut buttons on the project overview page:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. Clear the **Show shortcut buttons above files on project overview** checkbox.
+1. Select **Save changes**.
+
+### Show whitespace characters in the Web IDE
+
+Whitespace characters are any blank characters in a text, such as spaces and indentations. You might use whitespace to structure content in code. If your programming language is sensitive to whitespaces, the Web IDE can detect changes to them.
+
+To render whitespace in the Web IDE:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. Select the **Render whitespace characters in the Web IDE** checkbox.
+1. Select **Save changes**.
+
+You can view changes to whitespace in diffs.
+
+To view diffs on the Web IDE, follow these steps:
+
+1. On the left sidebar, select **Source Control** (**{branch}**).
+1. Under the **Changes** tab, select your file.
+
+### Show whitespace changes in diffs
+
+View changes to whitespace in diff files. For more information on whitespaces, view the previous task.
+
+To view changes to whitespace in diffs:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. Select the **Show whitespace changes in diffs** checkbox.
+1. Select **Save changes**.
+
+For more information on diffs, view [Change the diff colors](#change-the-diff-colors).
+
+### Show one file per page in a merge request
+
+The **Changes** tab lets you view all file changes in a merge request on one page.
+Instead, you can choose to view one file at a time.
+
+To show one file per page on the **Changes** tab:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. Select the **Show one file at a time on merge request's Changes tab** checkbox.
+1. Select **Save changes**.
+
+Then, to move between files on the **Changes** tab, below each file, select the **Previous** and **Next** buttons.
+
+### Auto-enclose characters
+
+Automatically add the corresponding closing character to text when you type the opening character. For example, you can automatically insert a closing bracket when you type an opening bracket. This setting works only in description and comment boxes and for the following characters: `**"`, `'`, ```, `(`, `[`, `{`, `<`, `*`, `_**`.
+
+To auto-enclose characters in description and comment boxes:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. Select the **Surround text selection when typing quotes or brackets** checkbox.
+1. Select **Save changes**.
+
+In a description or comment box, you can now type a word, highlight it, then type an
+opening character. Instead of replacing the text, the closing character is added to the end.
+
+### Automate new list items
+
+Create a new list item when you press <kbd>Enter</kbd> in a list in description and comment boxes.
+
+To add a new list item when you press the <kbd>Enter</kbd> key:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. Select the **Automatically add new list items** checkbox.
+1. Select **Save changes**.
+
+### Change the tab width
+
+Change the default size of tabs in diffs, blobs, and snippets. The WebIDE, file editor, and Markdown editor do not support this feature.
+
+To adjust the default tab width:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Behavior** section.
+1. For **Tab width**, enter a value.
+1. Select **Save changes**.
## Localization
-### Language
+Change localization settings such as your language, calendar start day, and time preferences.
-Select your preferred language from a list of supported languages.
+### Change your display language on the GitLab UI
-*This feature is experimental and translations are not complete yet.*
+GitLab supports multiple languages on the UI. To help improve translations or request support for an unlisted language, view [Translating GitLab](../../development/i18n/translation.md).
-### First day of the week
+To choose a language for the GitLab UI:
-The first day of the week can be customized for calendar views and date pickers.
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Localization** section.
+1. Under **Language**, select an option.
+1. Select **Save changes**.
+
+You might need to refresh your page to view the updated language.
-You can choose one of the following options as the first day of the week:
+### Customize your contribution calendar start day
-- Saturday
-- Sunday
-- Monday
+Choose which day of the week the contribution calendar starts with. The contribution calendar shows project contributions over the past year. You can view this calendar on each user profile. To access your user profile:
-If you select **System Default**, the first day of the week is set to the
-[instance default](../../administration/settings/index.md#change-the-default-first-day-of-the-week).
+- On the left sidebar, select your avatar > select your name or username.
+
+To change your contribution calendar start day:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Localization** section.
+1. Under **First day of the week**, select an option.
+1. Select **Save changes**.
-## Time preferences
+After you change your calendar start day, refresh your user profile page.
-### Use relative times
+### Show exact times instead of relative times
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65570) in GitLab 14.1.
-You can select your preferred time format for the GitLab user interface:
+Customize the format used to display times of activities on your group and project overview pages and user profiles. You can display times in a:
+
+- Relative format, for example `30 minutes ago`.
+- Absolute format, for example `September 3, 2022, 3:57 PM`.
+
+To use relative times on the GitLab UI:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Go to the **Time preferences** section.
+1. Clear the **Use relative times** checkbox.
+1. Select **Save changes**.
+
+## User identities in CI job JSON web tokens
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387537) in GitLab 16.0.
+
+CI/CD jobs generate JSON web tokens, which can include a list of your external identities.
+Instead of making separate API calls to get individual accounts, you can find your user identities in a single authentication token.
+
+External identities are not included by default.
+To enable including external identities, see [Token payload](../../ci/secrets/id_token_authentication.md#token-payload).
+
+## Control follower engagement
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325558) in GitLab 16.0.
+
+Turn off the ability to follow or be followed by other GitLab users. By default, your user profile, including your name and profile photo, is public in the **Following** tabs of other users. When you deactivate this setting:
+
+- GitLab deletes all of your followers and followed connections.
+- GitLab automatically removes your user profile from the pages of each connection.
+
+To remove the ability to be followed by and follow other users:
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Clear the **Enable follow users** checkbox.
+1. Select **Save changes**.
+
+To access your **Followers** and **Following** tabs:
-- Relative times, for example, `30 minutes ago`.
-- Absolute times, for example, `May 18, 2021, 3:57 PM`.
+- On the left sidebar, select your avatar > select your name or username.
+- Select **Followers** or **Following**.
-The times are formatted depending on your chosen language and browser locale.
+## Enable Code Suggestions
-To set your time preference:
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121079) in GitLab 16.1 as [Beta](../../policy/experiment-beta-support.md#beta).
-1. On the **Preferences** page, go to **Time preferences**.
-1. Select the **Use relative times** checkbox to use relative times,
- or clear the checkbox to use absolute times.
+To enable [Code Suggestions](../../user/project/repository/code_suggestions/index.md):
+
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Select the **Enable Code Suggestions** checkbox.
1. Select **Save changes**.
NOTE:
-This feature is experimental, and choosing absolute times might break certain layouts.
-Open an issue if you notice that using absolute times breaks a layout.
+If Code Suggestions are turned off [for the group](../../user/group/manage.md#enable-code-suggestions), then you cannot enable them for yourself. (Your setting has no effect.)
-## User identities in CI job JSON web tokens
+## Integrate your GitLab instance with third-party services
+
+Give third-party services access to your GitLab account.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/387537) in GitLab 16.0. False by default.
+### Integrate your GitLab instance with Gitpod
-You can select to include the list of your external identities in the JSON Web Token information that is generated for a CI job.
-For more information and examples, see [Token Payload](../../ci/secrets/id_token_authentication.md#token-payload).
+Configure your GitLab instance with Gitpod when you want to launch and manage code directly from your GitLab browser. Gitpod automatically prepares and builds development environments for your projects.
-## Integrations
+To integrate with Gitpod:
-Configure your preferences with third-party services which provide enhancements to your GitLab experience.
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Find the **Integrations** section.
+1. Select the **Enable Gitpod integration** checkbox.
+1. Select **Save changes**.
-### Sourcegraph
+### Integrate your GitLab instance with Sourcegraph
-NOTE:
-This setting is only visible if Sourcegraph has been enabled by a GitLab administrator.
+GitLab supports Sourcegraph integration for all public projects on GitLab.
-Manage the availability of integrated code intelligence features powered by
-Sourcegraph. View [the Sourcegraph feature documentation](../../integration/sourcegraph.md#enable-sourcegraph-in-user-preferences)
-for more information.
+To integrate with Sourcegraph:
-### Gitpod
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. Find the **Integrations** section.
+1. Select the **Enable integrated code intelligence on code views** checkbox.
+1. Select **Save changes**.
-Enable and disable the [GitLab-Gitpod integration](../../integration/gitpod.md). This is only
-visible after the integration is configured by a GitLab administrator. View
-[the Gitpod feature documentation](../../integration/gitpod.md) for more information.
+You must be the administrator of the GitLab instance to configure GitLab with Sourcegraph.
<!-- ## Troubleshooting
diff --git a/doc/user/profile/service_accounts.md b/doc/user/profile/service_accounts.md
index e593378ce4a..8845ee55e14 100644
--- a/doc/user/profile/service_accounts.md
+++ b/doc/user/profile/service_accounts.md
@@ -1,6 +1,6 @@
---
type: index, howto
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -22,6 +22,11 @@ A service account:
You should use service accounts in pipelines or integrations where credentials must be
set up and maintained without being impacted by changes in human user membership.
+You can authenticate as a service account with a [personal access token](personal_access_tokens.md).
+Service account users with a personal access token have the same abilities as a standard user.
+This includes interacting with [registries](../packages/index.md) and using the personal access
+token for [Git operations](personal_access_tokens.md#clone-repository-using-personal-access-token).
+
## Create a service account
The number of service accounts you can create is restricted by the number of service
@@ -50,7 +55,8 @@ Prerequisite:
The response includes the personal access token value.
-1. Use the returned personal access token value to authenticate with the GitLab API as the service account user.
+1. Make this service account a group or project member by [manually adding the service account user to the group or project](#add-a-service-account-to-subgroup-or-project).
+1. Use the returned personal access token value to authenticate as the service account user.
### Self-managed GitLab
@@ -63,14 +69,16 @@ Prerequisite:
This service account is associated with the entire instance, not a specific group
or project in the instance.
-1. [Create a personal access token](../../api/users.md#create-service-account-user)
+1. [Create a personal access token](../../api/users.md#create-a-personal-access-token)
for the service account user.
You define the scopes for the service account by [setting the scopes for the personal access token](personal_access_tokens.md#personal-access-token-scopes).
The response includes the personal access token value.
-1. Use the returned personal access token value to authenticate with the GitLab API as the service account user.
+1. Make this service account a group or project member by
+ [manually adding the service account user to the group or project](#add-a-service-account-to-subgroup-or-project).
+1. Use the returned personal access token value to authenticate as the service account user.
## Add a service account to subgroup or project
@@ -88,27 +96,13 @@ A service account:
- Can have different roles across multiple subgroups and projects of the same top level group.
- On GitLab.com, only belongs to one top-level group.
-### Add to a subgroup
-
-You can add the service account to a subgroup [through the UI](../group/index.md#add-users-to-a-group)
-or API.
-
-To add the service account through the API, call the following endpoint:
-
-```shell
-curl --request POST --header "PRIVATE-TOKEN: <ACCESS TOKEN>" --data "user_id=<service_account_user_id>&access_level=30" "https://gitlab.example.com/api/v4/groups/<subgroup_id>/members"
-```
-
-### Add to a project
-
-You can add the service account to a project [through the UI](../project/members/index.md#add-users-to-a-project)
-or API.
+### Add to a subgroup or project
-To add the service account through the API, call the following endpoint:
+You can add the service account to a subgroup or project through the:
-```shell
-curl --request POST --header "PRIVATE-TOKEN: <PRIVATE-TOKEN>" --data "user_id=<service_account_user_id>&access_level=30" "https://gitlab.example.com/api/v4/projects/<project_id>/members"
-```
+- [API](../../api/members.md#add-a-member-to-a-group-or-project).
+- [Group members UI](../group/index.md#add-users-to-a-group).
+- [Project members UI](../project/members/index.md#add-users-to-a-project).
### Change a service account role in a subgroup or project
diff --git a/doc/user/profile/user_passwords.md b/doc/user/profile/user_passwords.md
index d8604bc712e..7882502a588 100644
--- a/doc/user/profile/user_passwords.md
+++ b/doc/user/profile/user_passwords.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/user/project/badges.md b/doc/user/project/badges.md
index c275d2b39db..39c1d228d63 100644
--- a/doc/user/project/badges.md
+++ b/doc/user/project/badges.md
@@ -130,7 +130,7 @@ If you find that you have to add the same badges to several projects, you may wa
To add a new badge to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Badges**.
1. Select **Add badge**.
@@ -152,7 +152,7 @@ A common project badge presents the GitLab CI pipeline status.
To add this badge to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Badges**.
1. Under **Name**, enter _Pipeline Status_.
@@ -181,7 +181,7 @@ If you need individual badges for each project, either:
To add a new badge to a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Badges**.
1. Under "Link", enter the URL that the badges should point to and under
@@ -203,7 +203,7 @@ Badges associated with a group can be edited or deleted only at the [group level
You can view the exact link for your badges.
Then you can use the link to embed the badge in your HTML or Markdown pages.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > CI/CD**.
1. Expand **General pipelines**.
1. In the **Pipeline status**, **Coverage report**, or **Latest release** sections, view the URLs for the images.
@@ -270,7 +270,7 @@ https://gitlab.example.com/<project_path>/-/raw/<default_branch>/my-image.svg
To add a new badge with a custom image to a group or project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or
+1. On the left sidebar, select **Search or go to** and find your project or
group.
1. Select **Settings > General**.
1. Expand **Badges**.
diff --git a/doc/user/project/clusters/add_eks_clusters.md b/doc/user/project/clusters/add_eks_clusters.md
index 45d3834542b..d8b1b6fd413 100644
--- a/doc/user/project/clusters/add_eks_clusters.md
+++ b/doc/user/project/clusters/add_eks_clusters.md
@@ -56,7 +56,7 @@ cluster certificates:
1. Go to your:
- Project's **Operate > Kubernetes clusters** page, for a project-level cluster.
- Group's **Kubernetes** page, for a group-level cluster.
- - **Main menu > Admin > Kubernetes**, for an instance-level cluster.
+ - The Admin Area's **Kubernetes** page, for an instance-level cluster.
1. Select **Integrate with a cluster certificate**.
1. Under the **Create new cluster** tab, select **Amazon EKS** to display an
`Account ID` and `External ID` needed for later steps.
@@ -248,7 +248,7 @@ For example, the following policy document allows assuming a role whose name sta
To configure Amazon authentication in GitLab, generate an access key for the
IAM user in the Amazon AWS console, and follow these steps:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Amazon EKS**.
diff --git a/doc/user/project/clusters/add_existing_cluster.md b/doc/user/project/clusters/add_existing_cluster.md
index 5127248baed..7e2c429c6bb 100644
--- a/doc/user/project/clusters/add_existing_cluster.md
+++ b/doc/user/project/clusters/add_existing_cluster.md
@@ -68,7 +68,7 @@ To add a Kubernetes cluster to your project, group, or instance:
1. Navigate to your:
1. Project's **{cloud-gear}** **Operate > Kubernetes clusters** page, for a project-level cluster.
1. Group's **{cloud-gear}** **Kubernetes** page, for a group-level cluster.
- 1. **Main menu > Admin > Kubernetes** page, for an instance-level cluster.
+ 1. The Admin Area's **Kubernetes** page, for an instance-level cluster.
1. On the **Kubernetes clusters** page, select the **Connect with a certificate** option from the **Actions** dropdown list.
1. On the **Connect a cluster** page, fill in the details:
1. **Kubernetes cluster name** (required) - The name you wish to give the cluster.
diff --git a/doc/user/project/clusters/add_gke_clusters.md b/doc/user/project/clusters/add_gke_clusters.md
index a3a7cb35346..a087460d89e 100644
--- a/doc/user/project/clusters/add_gke_clusters.md
+++ b/doc/user/project/clusters/add_gke_clusters.md
@@ -63,7 +63,7 @@ cluster certificates:
- Project's **{cloud-gear}** **Operate > Kubernetes clusters** page, for a project-level
cluster.
- Group's **{cloud-gear}** **Kubernetes** page, for a group-level cluster.
- - **Main menu > Admin > Kubernetes** page, for an instance-level cluster.
+ - The Admin Area's **Kubernetes** page, for an instance-level cluster.
1. Select **Integrate with a cluster certificate**.
1. Under the **Create new cluster** tab, select **Google GKE**.
1. Connect your Google account if you haven't done already by selecting the
diff --git a/doc/user/project/clusters/add_remove_clusters.md b/doc/user/project/clusters/add_remove_clusters.md
index 16ad95bb95c..a3263109bb1 100644
--- a/doc/user/project/clusters/add_remove_clusters.md
+++ b/doc/user/project/clusters/add_remove_clusters.md
@@ -19,7 +19,7 @@ When you successfully connect an existing cluster using cluster certificates, th
1. Go to your:
- Project's **{cloud-gear}** **Operate > Kubernetes clusters** page, for a project-level cluster.
- Group's **{cloud-gear}** **Kubernetes** page, for a group-level cluster.
- - **Main menu > Admin > Kubernetes** page, for an instance-level cluster.
+ - The Admin Area's **Kubernetes** page, for an instance-level cluster.
1. Select the name of the cluster you want to disable.
1. Toggle **GitLab Integration** off (in gray).
1. Select **Save changes**.
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 58553fbb1c3..1a69b45b651 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -24,5 +24,5 @@ to a single project.
To view project-level Kubernetes clusters:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Kubernetes clusters**.
diff --git a/doc/user/project/codeowners/index.md b/doc/user/project/codeowners/index.md
index 74974958910..d783471f0da 100644
--- a/doc/user/project/codeowners/index.md
+++ b/doc/user/project/codeowners/index.md
@@ -6,17 +6,16 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Code Owners **(PREMIUM ALL)**
-> Moved to GitLab Premium in 13.9.
-
Use the Code Owners feature to define who has expertise for specific parts of your project's codebase.
Define the owners of files and directories in a repository to:
- **Require owners to approve changes.** Combine protected branches with Code Owners to require
experts to approve merge requests before they merge into a protected branch.
- **Identify owners.** Code Owner names are displayed on the files and directories they own:
+
![Code Owners displayed in UI](../img/codeowners_in_UI_v15_10.png)
-Use Code Owners in combination with merge request
+Combine Code Owners with merge request
[approval rules](../merge_requests/approvals/rules.md) (either optional or required)
to build a flexible approval workflow:
@@ -42,13 +41,11 @@ For example:
<iframe src="https://www.youtube-nocookie.com/embed/RoyBySTUSB0" frameborder="0" allowfullscreen> </iframe>
</figure>
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-
## View Code Owners of a file or directory
To view the Code Owners of a file or directory:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Repository**.
1. Go to the file or directory you want to see the Code Owners for.
1. Optional. Select a branch or tag.
@@ -57,14 +54,14 @@ GitLab shows the Code Owners at the top of the page.
## Set up Code Owners
-1. Create a `CODEOWNERS` file in your [preferred location](#code-owners-file).
+1. Create a `CODEOWNERS` file in your [preferred location](#codeowners-file).
1. Define some rules in the file following the [Code Owners syntax reference](reference.md).
Some suggestions:
- Configure [All eligible approvers](../merge_requests/approvals/rules.md#code-owners-as-eligible-approvers) approval rule.
- [Require Code Owner approval](../protected_branches.md#require-code-owner-approval-on-a-protected-branch) on a protected branch.
1. Commit your changes, and push them up to GitLab.
-### Code Owners file
+### `CODEOWNERS` file
A `CODEOWNERS` file (with no extension) specifies the users or
[shared groups](../members/share_project_with_groups.md) responsible for
@@ -78,9 +75,17 @@ all others are ignored:
1. In the `docs` directory: `./docs/CODEOWNERS`.
1. In the `.gitlab` directory: `./.gitlab/CODEOWNERS`.
-### Add a group as a Code Owner
+For more information, see [Code Owners syntax and error handling](reference.md).
+
+#### When user or group change names
+
+When a user or group change their names, the `CODEOWNERS` isn't automatically updated with the new names.
+To enter the new names, you must edit the file.
-> Group and subgroup hierarchy support was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32432) in GitLab 13.0.
+Organizations using SAML SSO can [set usernames](../../../integration/saml.md#set-a-username) to
+prevent users from being able to change their usernames.
+
+### Add a group as a Code Owner
To set the members of a group or subgroup as a Code Owner:
@@ -99,8 +104,6 @@ file.md @group-x @group-x/subgroup-y
#### Group inheritance and eligibility
-> Group and subgroup hierarchy support was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32432) in GitLab 13.0.
-
```mermaid
graph TD
A[Parent group X] -->|owns| B[Project A]
@@ -188,9 +191,6 @@ Only one CODEOWNERS pattern per section is matched to a file path.
### Organize Code Owners by putting them into sections
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12137) in GitLab 13.2 [with a flag](../../../administration/feature_flags.md) named `sectional_codeowners`. Disabled by default.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42389) in GitLab 13.4. Feature flag `sectional_codeowners` removed.
-
You can organize Code Owners by putting them into named sections.
You can use sections for shared directories, so that multiple
@@ -215,9 +215,10 @@ The following image shows a **Groups** and **Documentation** section:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371711) in GitLab 15.11 [with a flag](../../../administration/feature_flags.md) named `codeowners_default_owners`. Disabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115888) in GitLab 15.11. Feature flag `codeowners_default_owners` removed.
-If multiple file paths inside a section share the same ownership, define a default
-Code Owner for the section. All paths in that section inherit this default, unless
-you override the section default on a specific line.
+If multiple file paths inside a section share the same ownership, define default
+Code Owners for the section.
+All paths in that section inherit this default, unless you override the section
+default on a specific line.
Default owners are applied when specific owners are not specified for file paths.
Specific owners defined beside the file path override default owners:
@@ -227,7 +228,7 @@ Specific owners defined beside the file path override default owners:
docs/
README.md
-[Database] @database-team
+[Database] @database-team @agarcia
model/db/
config/db/database-setup.md @docs-team
```
@@ -235,9 +236,14 @@ config/db/database-setup.md @docs-team
In this example:
- `@docs-team` owns all items in the `Documentation` section.
-- `@database-team` owns all items in the `Database` section except
+- `@database-team` and `@agarcia` own all items in the `Database` section except
`config/db/database-setup.md`, which has an override assigning it to `@docs-team`.
+Compare this behavior to when you use [regular entries and sections together](#use-regular-entries-and-sections-together),
+when entries in sections don't override entries without sections.
+
+#### Use default owners and optional sections together
+
To combine the syntax for default owners with [optional sections](#make-a-code-owners-section-optional)
and required approvals, place default owners at the end:
@@ -251,6 +257,38 @@ model/db/
config/db/database-setup.md @docs-team
```
+#### Use regular entries and sections together
+
+If you set a default Code Owner for a path outside a section, their approval is always required, and
+the entry isn't overridden.
+Entries without sections are treated as if they were another, unnamed section:
+
+```plaintext
+# Required for all files
+* @general-approvers
+
+[Documentation] @docs-team
+docs/
+README.md
+*.txt
+
+[Database] @database-team
+model/db/
+config/db/database-setup.md @docs-team
+```
+
+In this example:
+
+- `@general-approvers` owns all items everywhere, without overrides.
+- `@docs-team` owns all items in the `Documentation` section.
+- `@database-team` owns all items in the `Database` section except
+ `config/db/database-setup.md`, which has an override assigning it to `@docs-team`.
+- A merge request that modifies `model/db/CHANGELOG.txt` would require three approvals: one from each
+ of the `@general-approvers`,`@docs-team`, and `@database-team` groups.
+
+Compare this behavior to when you use only [default owners for sections](#set-default-owner-for-a-section),
+when specific entries within a section override the section default.
+
#### Sections with duplicate names
If multiple sections have the same name, they are combined.
@@ -275,8 +313,6 @@ entries under **Database**. The entries defined under the sections **Documentati
#### Make a Code Owners section optional
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/232995) in GitLab 13.8.
-
You can designate optional sections in your Code Owners file. Prepend the
section name with the caret `^` character to treat the entire section as optional.
Optional sections enable you to designate responsible parties for various parts
@@ -314,14 +350,14 @@ section is marked as optional.
You can require multiple approvals for the Code Owners sections under the Approval Rules area in merge requests.
Append the section name with a number `n` in brackets. This requires `n` approvals from the Code Owners in this section.
-Please note valid entries for `n` are integers `≥ 1`. `[1]` is optional as it is the default. Invalid values for `n` are treated as `1`.
+Valid entries for `n` are integers `≥ 1`. `[1]` is optional because it is the default. Invalid values for `n` are treated as `1`.
WARNING:
[Issue #384881](https://gitlab.com/gitlab-org/gitlab/-/issues/385881) proposes changes
to the behavior of this setting. Do not intentionally set invalid values. They may
become valid in the future, and cause unexpected behavior.
-Please confirm you enabled `Require approval from code owners` in `Settings > Repository > Protected branches`, otherwise the Code Owner approvals will be optional.
+Make sure you enabled `Require approval from code owners` in `Settings > Repository > Protected branches`, otherwise the Code Owner approvals are optional.
In this example, the `[Documentation]` section requires 2 approvals:
@@ -337,7 +373,7 @@ The `Documentation` Code Owners section under the **Approval Rules** area displa
![MR widget - Multiple Approval Code Owners sections](../img/multi_approvals_code_owners_sections_v15_9.png)
-### Allowed to Push
+### Allowed to push
Users who are **Allowed to push** can choose to create a merge request
for their changes, or push the changes directly to a branch. If the user
@@ -350,12 +386,15 @@ and release tooling.
All changes from users _without_ the **Allowed to push** permission must be routed through a merge request.
-## Technical Resources
+## Related topics
-[Code Owners development guidelines](../../../development/code_owners/index.md)
+- [Syntax reference](reference.md)
+- [Development guidelines](../../../development/code_owners/index.md)
## Troubleshooting
+When working with Code Owners, you might encounter the following issues.
+
For more information about how the Code Owners feature handles errors, see the
[Code Owners reference](reference.md).
@@ -363,7 +402,8 @@ For more information about how the Code Owners feature handles errors, see the
A Code Owner approval rule is optional if any of these conditions are true:
-- The user or group are not a member of the project. Code Owners [cannot inherit from parent groups](https://gitlab.com/gitlab-org/gitlab/-/issues/288851/).
+- The user or group is not a member of the project.
+ Code Owners [cannot inherit members from parent groups](https://gitlab.com/gitlab-org/gitlab/-/issues/288851/).
- [Code Owner approval on a protected branch](../protected_branches.md#require-code-owner-approval-on-a-protected-branch) has not been set up.
- The section is [marked as optional](#make-a-code-owners-section-optional).
@@ -383,7 +423,15 @@ if any of these conditions are true:
member of the Code Owner group.
- Current user is an external user who does not have permission to the internal Code Owner group.
-### Approval rule is invalid. GitLab has approved this rule automatically to unblock the merge request
+### Approval rule is invalid
+
+You might get an error that states:
+
+```plaintext
+Approval rule is invalid.
+GitLab has approved this rule automatically to unblock the merge request.
+```
+
+This issue occurs when an approval rule uses a Code Owner that is not a direct member of the project.
-This message may appear if an approval rule uses a Code Owner that is not a direct member of the project.
-Check that the group or user has been invited to the project.
+The workaround is to check that the group or user has been invited to the project.
diff --git a/doc/user/project/deploy_boards.md b/doc/user/project/deploy_boards.md
index 395873d3107..91a3d71642d 100644
--- a/doc/user/project/deploy_boards.md
+++ b/doc/user/project/deploy_boards.md
@@ -21,7 +21,7 @@ type: howto, reference
WARNING:
This feature was [deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
[An epic exists](https://gitlab.com/groups/gitlab-org/-/epics/2493)
-to add this functionality to the [agent](../index.md).
+to add this functionality to the [agent](../clusters/agent/index.md).
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `certificate_based_clusters`.
diff --git a/doc/user/project/deploy_keys/index.md b/doc/user/project/deploy_keys/index.md
index f0d84616c24..c0a50dade31 100644
--- a/doc/user/project/deploy_keys/index.md
+++ b/doc/user/project/deploy_keys/index.md
@@ -64,7 +64,7 @@ Deploy keys work even if the user who created them is removed from the group or
To view the deploy keys available to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Deploy keys**.
@@ -82,7 +82,7 @@ Prerequisites:
- [Generate an SSH key pair](../../ssh.md#generate-an-ssh-key-pair). Put the private SSH
key on the host that requires access to the repository.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Deploy keys**.
1. Select **Add new key**.
@@ -104,7 +104,7 @@ Prerequisites:
To create a public deploy key:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Deploy Keys**.
1. Select **New deploy key**.
@@ -122,7 +122,7 @@ Prerequisites:
To grant a public deploy key access to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Deploy keys**.
1. Select **Publicly accessible deploy keys**.
@@ -139,7 +139,7 @@ Prerequisites:
To edit the project access permissions of a deploy key:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Deploy keys**.
1. In the key's row, select **Edit** (**{pencil}**).
@@ -156,7 +156,7 @@ Prerequisites:
To disable a deploy key:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Deploy keys**.
1. Select **Disable** (**{cancel}**).
@@ -192,7 +192,7 @@ If you need to find the keys that belong to a non-member or blocked user,
you can use [the Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session) to identify unusable deploy keys using a script similar to the following:
```ruby
-ghost_user_id = User.ghost.id
+ghost_user_id = Users::Internal.ghost.id
DeployKeysProject.with_write_access.find_each do |deploy_key_mapping|
project = deploy_key_mapping.project
diff --git a/doc/user/project/deploy_tokens/index.md b/doc/user/project/deploy_tokens/index.md
index 41fb0018be9..8b7e185508b 100644
--- a/doc/user/project/deploy_tokens/index.md
+++ b/doc/user/project/deploy_tokens/index.md
@@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Deploy tokens **(FREE ALL)**
-> [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/213566) package registry scopes in GitLab 13.0.
-
You can use a deploy token to enable authentication of deployment tasks, independent of a user
account. In most cases you use a deploy token from an external host, like a build server or CI/CD
server.
@@ -92,7 +90,7 @@ Prerequisites:
- You must have at least the Maintainer role for the project or group.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > Repository**.
1. Expand **Deploy tokens**.
1. Select **Add token**.
@@ -112,7 +110,7 @@ Prerequisites:
To revoke a deploy token:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > Repository**.
1. Expand **Deploy tokens**.
1. In the **Active Deploy Tokens** section, by the token you want to revoke, select **Revoke**.
diff --git a/doc/user/project/description_templates.md b/doc/user/project/description_templates.md
index 4da49c4fb12..97b350c8692 100644
--- a/doc/user/project/description_templates.md
+++ b/doc/user/project/description_templates.md
@@ -16,7 +16,7 @@ You might want to use these templates:
- For different stages of your workflow, for example, feature proposal, feature improvement, or a bug report.
- For every issue or merge request for a specific project, so the layout is consistent.
-- For a [Service Desk email template](service_desk/index.md#use-a-custom-template-for-service-desk-tickets).
+- For a [Service Desk email template](service_desk/configure.md#use-a-custom-template-for-service-desk-tickets).
For description templates to work, they must be:
@@ -32,7 +32,7 @@ directory in your repository.
To create an issue description template:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Repository**.
1. Next to the default branch, select **{plus}**.
1. Select **New file**.
@@ -52,7 +52,7 @@ that depend on the contents of commit messages and branch names.
To create a merge request description template for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Repository**.
1. Next to the default branch, select **{plus}**.
1. Select **New file**.
@@ -110,7 +110,7 @@ You can set a description template at the **instance level** for issues
and merge requests by using an [instance template repository](../admin_area/settings/instance_template_repository.md).
You can also use the instance template repository for file templates.
-You might also be interested [project templates](../admin_area/custom_project_templates.md)
+You might also be interested in [project templates](../admin_area/custom_project_templates.md)
that you can use when creating a new project in the instance.
### Set group-level description templates **(PREMIUM ALL)**
@@ -118,13 +118,18 @@ that you can use when creating a new project in the instance.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52360) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/321247) in GitLab 14.0.
-With **group-level** description templates, you can select a repository within the group to store
-your templates. Then, you can access these templates from other projects in the group.
+With **group-level** description templates, you can select a project within the group to store
+your templates. Then, you can access these templates in other projects in the group.
As a result, you can use the same templates in issues and merge requests in all the group's projects.
+Prerequisites:
+
+- You must have the Owner role for the group.
+- The project must be a direct child of the group.
+
To re-use templates [you've created](../project/description_templates.md#create-an-issue-template):
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Templates**.
1. From the dropdown list, select your template project as the template repository at group level.
@@ -155,7 +160,7 @@ To set a default description template for merge requests, either:
This [doesn't overwrite](#priority-of-default-description-templates) the default template if one has been set in the project settings.
- Users on GitLab Premium and Ultimate: set the default template in project settings:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. In the **Default description template for merge requests** section, fill in the text area.
1. Select **Save changes**.
@@ -167,7 +172,7 @@ To set a default description template for issues, either:
This [doesn't overwrite](#priority-of-default-description-templates) the default template if one has been set in the project settings.
- Users on GitLab Premium and Ultimate: set the default template in project settings:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Default description template for issues**.
1. Fill in the text area.
diff --git a/doc/user/project/file_lock.md b/doc/user/project/file_lock.md
index 88aa9446787..783f5f3ee7c 100644
--- a/doc/user/project/file_lock.md
+++ b/doc/user/project/file_lock.md
@@ -151,7 +151,7 @@ You can push files to GitLab whether they're locked or unlocked.
NOTE:
Although multi-branch file locks can be created and managed through the Git LFS
-command line interface, file locks can be created for any file.
+command-line interface, file locks can be created for any file.
### View exclusively-locked files
@@ -221,7 +221,7 @@ similar functionality for locked files is discussed in
To view and remove file locks:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Locked files**.
This list shows all the files locked either through LFS or GitLab UI.
diff --git a/doc/user/project/import/bitbucket.md b/doc/user/project/import/bitbucket.md
index 0f612d5b222..bafcbbb9cbd 100644
--- a/doc/user/project/import/bitbucket.md
+++ b/doc/user/project/import/bitbucket.md
@@ -36,7 +36,7 @@ When importing:
- [Bitbucket Cloud integration](../../../integration/bitbucket.md) must be enabled. If that integration is not enabled, ask your GitLab administrator
to enable it. The Bitbucket Cloud integration is enabled by default on GitLab.com.
-- [Bitbucket Cloud import source](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources) must be enabled. If not enabled, ask your
+- [Bitbucket Cloud import source](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources) must be enabled. If not enabled, ask your
GitLab administrator to enable it. The Bitbucket Cloud import source is enabled by default on GitLab.com.
- At least the Maintainer role on the destination group to import to.
@@ -117,5 +117,5 @@ current Bitbucket public name, and reconnect if there's a mismatch:
1. Following reconnection, the user should use the API again to verify that their `extern_uid` in
the GitLab database now matches their current Bitbucket public name.
-The importer must then [delete the imported project](../../project/working_with_projects.md#delete-a-project)
+The importer must then [delete the imported project](../../project/settings/index.md#delete-a-project)
and import again.
diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md
index a80ce95c163..4afe23a29fa 100644
--- a/doc/user/project/import/bitbucket_server.md
+++ b/doc/user/project/import/bitbucket_server.md
@@ -32,7 +32,7 @@ You can import Bitbucket repositories to GitLab.
> Requirement for Maintainer role instead of Developer role introduced in GitLab 16.0 and backported to GitLab 15.11.1 and GitLab 15.10.5.
-- [Bitbucket Server import source](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources)
+- [Bitbucket Server import source](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources)
must be enabled. If not enabled, ask your GitLab administrator to enable it. The Bitbucket Server import source is enabled
by default on GitLab.com.
- At least the Maintainer role on the destination group to import to.
@@ -87,6 +87,9 @@ original creator.
The importer creates any new namespaces (groups) if they don't exist. If the namespace is taken, the
repository imports under the namespace of the user who started the import process.
+The importer attempts to find reviewers by their email address in the GitLab user database. If they don't exist in GitLab, they cannot be added as reviewers to a
+merge request.
+
### User assignment by username
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218609) in GitLab 13.4 [with a flag](../../../administration/feature_flags.md) named `bitbucket_server_user_mapping_by_username`. Disabled by default.
diff --git a/doc/user/project/import/cvs.md b/doc/user/project/import/cvs.md
index f5f924ef603..90ed6cfdb2c 100644
--- a/doc/user/project/import/cvs.md
+++ b/doc/user/project/import/cvs.md
@@ -39,10 +39,10 @@ The following list illustrates the main differences between CVS and Git:
your state in version control, then you merge the other developer's changes.
You can also ask the other developer to do the merge and resolve any conflicts
themselves.
-- **Signed commits.** Git supports signing your commits with GPG for additional
+- **Signed commits.** Git supports
+ [signing your commits](../repository/signed_commits/index.md) for additional
security and verification that the commit indeed came from its original author.
- GitLab can [integrate with GPG](../repository/gpg_signed_commits/index.md)
- and show whether a signed commit is correctly verified.
+ GitLab shows whether a signed commit is correctly verified.
_Some of the items above were taken from this great
[Stack Overflow post](https://stackoverflow.com/a/824241/974710). For a more
diff --git a/doc/user/project/import/fogbugz.md b/doc/user/project/import/fogbugz.md
index 85c24886687..2bce6708556 100644
--- a/doc/user/project/import/fogbugz.md
+++ b/doc/user/project/import/fogbugz.md
@@ -19,7 +19,7 @@ users.
> Requirement for Maintainer role instead of Developer role introduced in GitLab 16.0 and backported to GitLab 15.11.1 and GitLab 15.10.5.
-- [FogBugz import source](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources)
+- [FogBugz import source](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources)
must be enabled. If not enabled, ask your GitLab administrator to enable it. The FogBugz import source is enabled
by default on GitLab.com.
- At least the Maintainer role on the destination group to import to.
diff --git a/doc/user/project/import/gitea.md b/doc/user/project/import/gitea.md
index 98457b96dde..9629ec03443 100644
--- a/doc/user/project/import/gitea.md
+++ b/doc/user/project/import/gitea.md
@@ -32,7 +32,7 @@ on the issue about the original Gitea author.
> Requirement for Maintainer role instead of Developer role introduced in GitLab 16.0 and backported to GitLab 15.11.1 and GitLab 15.10.5.
- Gitea version 1.0.0 or later.
-- [Gitea import source](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources)
+- [Gitea import source](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources)
must be enabled. If not enabled, ask your GitLab administrator to enable it. The Gitea import source is enabled
by default on GitLab.com.
- At least the Maintainer role on the destination group to import to.
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 2079c61da31..75d25e29bd9 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -28,6 +28,9 @@ When importing projects:
- If a user referenced in the project is not found in the GitLab database, the project creator is set as the author and
assignee. The project creator is usually the user that initiated the import process. A note on the issue mentioning the
original GitHub author is added.
+- Reviewers assigned to GitHub pull requests that do not exist in GitLab are not imported. In this case, the import
+ creates comments describing that non-existent users were added as reviewers and approvers. However, the actual
+ reviewer status and approval are not applied to the merge request in GitLab.
- You can change the target namespace and target repository name before you import.
- The importer also imports branches on forks of projects related to open pull requests. These branches are
imported with a naming scheme similar to `GH-SHA-username/pull-request-number/fork-name/branch`. This may lead to
@@ -43,7 +46,7 @@ For an overview of the import process, see [How to migrate from GitHub to GitLab
To import projects from GitHub:
-- [GitHub import source](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources)
+- [GitHub import source](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources)
must be enabled. If not enabled, ask your GitLab administrator to enable it. The GitHub import source is enabled
by default on GitLab.com.
- You must have at least the Maintainer role on the destination group to import to.
@@ -55,12 +58,8 @@ To import projects from GitHub:
When issues and pull requests are being imported, the importer attempts to find their GitHub authors and assignees in
the database of the GitLab instance. Pull requests are called _merge requests_ in GitLab. For the importer to succeed,
matching email addresses are required.
-- GitHub accounts must have a GitHub public-facing email address is populated. This means all comments and contributions
- are properly mapped to the same user in GitLab. GitHub Enterprise does not require this field to be populated so you
- may have to add it on existing accounts.
-
-Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/383047), if you are using GitHub as an OmniAuth provider, ensure that the URL
-perimeter is specified in the [OmniAuth configuration](../../../integration/github.md#enable-github-oauth-in-gitlab).
+- GitHub accounts must have a GitHub public-facing email address so that all comments and contributions can be properly mapped to
+ the same user in GitLab. GitHub Enterprise does not require this field to be populated so you might have to add it on existing accounts.
### Importing from GitHub Enterprise to self-managed GitLab
@@ -68,7 +67,7 @@ If you are importing from GitHub Enterprise to a self-managed GitLab instance:
- You must first enable the [GitHub integration](../../../integration/github.md).
- GitHub must be enabled as an import source in the
- [Admin Area](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources).
+ [Admin Area](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources).
- For GitLab 15.10 and earlier, you must add `github.com` and `api.github.com` entries in the
[allowlist for local requests](../../../security/webhooks.md#allow-outbound-requests-to-certain-ip-addresses-and-domains).
@@ -78,7 +77,17 @@ If you are importing from GitHub.com to a self-managed GitLab instance:
- You don't need to enable the [GitHub integration](../../../integration/github.md).
- GitHub must be enabled as an import source in the
- [Admin Area](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources).
+ [Admin Area](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources).
+
+### Known issues
+
+- GitHub pull request comments (known as diff notes in GitLab) created before 2017 are imported in separate threads.
+ This occurs because of a limitation of the GitHub API that doesn't include `in_reply_to_id` for comments before 2017.
+- Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/383047), if you are using GitHub as an
+ OmniAuth provider, ensure that the URL perimeter is specified in the
+ [OmniAuth configuration](../../../integration/github.md#enable-github-oauth-in-gitlab).
+- Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/424400), Markdown attachments from
+ repositories on GitHub Enterprise Server instances aren't imported.
## Import your GitHub repository into GitLab
@@ -288,10 +297,10 @@ When they are imported, supported GitHub branch protection rules are mapped to e
| :---------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------ |
| **Require conversation resolution before merging** for the project's default branch | **All threads must be resolved** [project setting](../merge_requests/index.md#prevent-merge-unless-all-threads-are-resolved) | [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/371110) |
| **Require a pull request before merging** | **No one** option in the **Allowed to push and merge** list of [branch protection settings](../protected_branches.md#add-protection-to-existing-branches) | [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/370951) |
-| **Require signed commits** for the project's default branch | **Reject unsigned commits** GitLab [push rule](../repository/push_rules.md#prevent-unintended-consequences) **(PREMIUM)** | [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/370949) |
+| **Require signed commits** for the project's default branch | **Reject unsigned commits** GitLab [push rule](../repository/push_rules.md#prevent-unintended-consequences) **(PREMIUM ALL)** | [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/370949) |
| **Allow force pushes - Everyone** | **Allowed to force push** [branch protection setting](../protected_branches.md#allow-force-push-on-a-protected-branch) | [GitLab 15.6](https://gitlab.com/gitlab-org/gitlab/-/issues/370943) |
-| **Require a pull request before merging - Require review from Code Owners** | **Require approval from code owners** [branch protection setting](../protected_branches.md#require-code-owner-approval-on-a-protected-branch) **(PREMIUM)** | [GitLab 15.6](https://gitlab.com/gitlab-org/gitlab/-/issues/376683) |
-| **Require a pull request before merging - Allow specified actors to bypass required pull requests** | List of users in the **Allowed to push and merge** list of [branch protection settings](../protected_branches.md#add-protection-to-existing-branches) **(PREMIUM)**. Without a **Premium** subscription, the list of users that are allowed to push and merge is limited to roles. | [GitLab 15.8](https://gitlab.com/gitlab-org/gitlab/-/issues/384939) |
+| **Require a pull request before merging - Require review from Code Owners** | **Require approval from code owners** [branch protection setting](../protected_branches.md#require-code-owner-approval-on-a-protected-branch) **(PREMIUM ALL)** | [GitLab 15.6](https://gitlab.com/gitlab-org/gitlab/-/issues/376683) |
+| **Require a pull request before merging - Allow specified actors to bypass required pull requests** | List of users in the **Allowed to push and merge** list of [branch protection settings](../protected_branches.md#add-protection-to-existing-branches) **(PREMIUM ALL)**. Without a **Premium** subscription, the list of users that are allowed to push and merge is limited to roles. | [GitLab 15.8](https://gitlab.com/gitlab-org/gitlab/-/issues/384939) |
Mapping GitHub rule **Require status checks to pass before merging** to
[external status checks](../merge_requests/status_checks.md) was considered in issue
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index c1d6f5dbcbe..df831c2f3eb 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -41,7 +41,7 @@ with a malicious `.gitlab-ci.yml` file could allow an attacker to exfiltrate gro
GitLab self-managed administrators can reduce their attack surface by disabling import sources they don't need:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Visibility and access controls**.
diff --git a/doc/user/project/import/manifest.md b/doc/user/project/import/manifest.md
index 433496ba6c9..aaf19439c24 100644
--- a/doc/user/project/import/manifest.md
+++ b/doc/user/project/import/manifest.md
@@ -19,7 +19,7 @@ repositories like the Android Open Source Project (AOSP).
> Requirement for Maintainer role instead of Developer role introduced in GitLab 16.0 and backported to GitLab 15.11.1 and GitLab 15.10.5.
-- [Manifest import source](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources)
+- [Manifest import source](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources)
must be enabled. If not enabled, ask your GitLab administrator to enable it. The Manifest import source is enabled
by default on GitLab.com.
- GitLab must use PostgreSQL for its database, because [subgroups](../../group/subgroups/index.md) are needed for the manifest import
diff --git a/doc/user/project/import/phabricator.md b/doc/user/project/import/phabricator.md
deleted file mode 100644
index 7b9615b883c..00000000000
--- a/doc/user/project/import/phabricator.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-stage: Manage
-group: Import and Integrate
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
----
-
-# Import Phabricator tasks into a GitLab project (removed) **(FREE SELF)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106369) in GitLab 15.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117649) in 16.0.
diff --git a/doc/user/project/import/repo_by_url.md b/doc/user/project/import/repo_by_url.md
index 5d23ee885bb..375cb718538 100644
--- a/doc/user/project/import/repo_by_url.md
+++ b/doc/user/project/import/repo_by_url.md
@@ -12,15 +12,15 @@ You can import your existing repositories by providing the Git URL.
> Requirement for Maintainer role instead of Developer role introduced in GitLab 16.0 and backported to GitLab 15.11.1 and GitLab 15.10.5.
-- [Repository by URL import source](../../../administration/settings/visibility_and_access_controls.md#configure-allowed-import-sources)
+- [Repository by URL import source](../../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources)
must be enabled. If not enabled, ask your GitLab administrator to enable it. The Repository by URL import source is enabled
by default on GitLab.com.
- At least the Maintainer role on the destination group to import to.
## Import project by URL
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your projects**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my projects**.
1. On the right of the page, select **New project**.
1. Select the **Import project** tab.
1. Select **Repository by URL**.
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 478e9c6bf1b..b60d87adbd3 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -134,7 +134,7 @@ Prerequisites:
[added to your GitLab account](../ssh.md#add-an-ssh-key-to-your-gitlab-account).
- You must have permission to add new projects to a namespace. To check if you have permission:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+ 1. On the left sidebar, select **Search or go to** and find your group.
1. In the upper-right corner, confirm that **New project** is visible.
Contact your GitLab administrator if you require permission.
diff --git a/doc/user/project/insights/index.md b/doc/user/project/insights/index.md
index 60b23540ac3..d8ad7f9a29c 100644
--- a/doc/user/project/insights/index.md
+++ b/doc/user/project/insights/index.md
@@ -24,7 +24,7 @@ Prerequisites:
To view project insights:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Insights**.
1. To view a report, select the **Select report** dropdown list.
@@ -52,7 +52,7 @@ To configure project insights, either:
- Create a `.gitlab/insights.yml` file locally in the root directory of your project, and push your changes.
- Create a `.gitlab/insights.yml` file in the UI:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Above the file list, select the branch you want to commit to, select the plus icon, then select **New file**.
1. In the **File name** text box, enter `.gitlab/insights.yml`.
1. In the large text box, update the file contents.
diff --git a/doc/user/project/integrations/apple_app_store.md b/doc/user/project/integrations/apple_app_store.md
index 6005bc48d56..763f478eb99 100644
--- a/doc/user/project/integrations/apple_app_store.md
+++ b/doc/user/project/integrations/apple_app_store.md
@@ -29,7 +29,7 @@ An Apple ID enrolled in the [Apple Developer Program](https://developer.apple.co
GitLab supports enabling the Apple App Store integration at the project level. Complete these steps in GitLab:
1. In the Apple App Store Connect portal, generate a new private key for your project by following [these instructions](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Apple App Store Connect**.
1. Under **Enable integration**, select the **Active** checkbox.
diff --git a/doc/user/project/integrations/asana.md b/doc/user/project/integrations/asana.md
index c73563ba162..442b8695136 100644
--- a/doc/user/project/integrations/asana.md
+++ b/doc/user/project/integrations/asana.md
@@ -32,7 +32,7 @@ In Asana, create a Personal Access Token.
Complete these steps in GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Asana**.
1. Ensure that the **Active** toggle is enabled.
diff --git a/doc/user/project/integrations/bamboo.md b/doc/user/project/integrations/bamboo.md
index 9abbe75cc4c..242d5e6974c 100644
--- a/doc/user/project/integrations/bamboo.md
+++ b/doc/user/project/integrations/bamboo.md
@@ -36,7 +36,7 @@ integration in GitLab.
## Configure GitLab
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Atlassian Bamboo**.
1. Ensure the **Active** checkbox is selected.
diff --git a/doc/user/project/integrations/bugzilla.md b/doc/user/project/integrations/bugzilla.md
index 048673cd4a2..febbee66c33 100644
--- a/doc/user/project/integrations/bugzilla.md
+++ b/doc/user/project/integrations/bugzilla.md
@@ -14,7 +14,7 @@ You can configure Bugzilla as an
To enable the Bugzilla integration in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Bugzilla**.
1. Under **Enable integration**, select the **Active** checkbox.
@@ -39,7 +39,7 @@ project pages. This link takes you to the appropriate Bugzilla project.
You can also disable [GitLab internal issue tracking](../issues/index.md) in this project.
For more information about the steps and consequences of disabling GitLab issues, see
-[Configure project visibility, features, and permissions](../settings/index.md#configure-project-visibility-features-and-permissions).
+Configure project [visibility](../../../user/public_access.md#change-project-visibility), [features, and permissions](../settings/index.md#configure-project-features-and-permissions).
## Reference Bugzilla issues in GitLab
diff --git a/doc/user/project/integrations/clickup.md b/doc/user/project/integrations/clickup.md
index 7075aca28c2..dc93ff8ed06 100644
--- a/doc/user/project/integrations/clickup.md
+++ b/doc/user/project/integrations/clickup.md
@@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
You can use [ClickUp](https://clickup.com/) as an external issue tracker.
To enable the ClickUp integration in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **ClickUp**.
1. Under **Enable integration**, select the **Active** checkbox.
@@ -34,7 +34,7 @@ For example, this is a configuration for a project named `gitlab-ci`:
You can also disable [GitLab internal issue tracking](../issues/index.md) in this project.
For more information about the steps and consequences of disabling GitLab issues, see
-[Configure project visibility, features, and permissions](../settings/index.md#configure-project-visibility-features-and-permissions).
+Configure project [visibility](../../../user/public_access.md#change-project-visibility), [features, and permissions](../settings/index.md#configure-project-features-and-permissions).
## Reference ClickUp issues in GitLab
diff --git a/doc/user/project/integrations/custom_issue_tracker.md b/doc/user/project/integrations/custom_issue_tracker.md
index 54d092d2fa9..0a31e66fe96 100644
--- a/doc/user/project/integrations/custom_issue_tracker.md
+++ b/doc/user/project/integrations/custom_issue_tracker.md
@@ -20,7 +20,7 @@ on the left sidebar in your project.
To enable a custom issue tracker in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Custom issue tracker**.
1. Under **Enable integration**, select the **Active** checkbox.
diff --git a/doc/user/project/integrations/discord_notifications.md b/doc/user/project/integrations/discord_notifications.md
index 67f76d48744..29d92b16e32 100644
--- a/doc/user/project/integrations/discord_notifications.md
+++ b/doc/user/project/integrations/discord_notifications.md
@@ -28,7 +28,7 @@ and configure it in GitLab.
With the webhook URL created in the Discord channel, you can set up the Discord Notifications integration in GitLab.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Discord Notifications**.
1. Ensure that the **Active** toggle is enabled.
diff --git a/doc/user/project/integrations/emails_on_push.md b/doc/user/project/integrations/emails_on_push.md
index 105061efba7..5c1130c7893 100644
--- a/doc/user/project/integrations/emails_on_push.md
+++ b/doc/user/project/integrations/emails_on_push.md
@@ -11,7 +11,7 @@ that is pushed to your project.
To enable emails on push:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Emails on push**.
1. In the **Recipients** section, provide a list of emails separated by spaces or newlines.
diff --git a/doc/user/project/integrations/ewm.md b/doc/user/project/integrations/ewm.md
index 7ee0306e7c0..831078e4e4b 100644
--- a/doc/user/project/integrations/ewm.md
+++ b/doc/user/project/integrations/ewm.md
@@ -14,7 +14,7 @@ This IBM product was [formerly named Rational Team Concert (RTC)](https://jazz.n
To enable the EWM integration, in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **EWM**.
1. Under **Enable integration**, select the **Active** checkbox.
diff --git a/doc/user/project/integrations/github.md b/doc/user/project/integrations/github.md
index 3f4b110468b..c368a9da2f6 100644
--- a/doc/user/project/integrations/github.md
+++ b/doc/user/project/integrations/github.md
@@ -29,7 +29,7 @@ Complete these steps on GitHub:
Complete these steps in GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **GitHub**.
1. Ensure the **Active** checkbox is selected.
diff --git a/doc/user/project/integrations/gitlab_slack_application.md b/doc/user/project/integrations/gitlab_slack_application.md
index a082d9aa5be..d762c71242d 100644
--- a/doc/user/project/integrations/gitlab_slack_application.md
+++ b/doc/user/project/integrations/gitlab_slack_application.md
@@ -30,7 +30,7 @@ Although functionality has not changed, you should [reinstall the app](#update-t
To install the GitLab for Slack app from project integration settings:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **GitLab for Slack app**.
1. Select **Install GitLab for Slack app**.
@@ -55,7 +55,7 @@ When GitLab releases new features for the GitLab for Slack app, you might have t
To update your GitLab for Slack app:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find a project for
+1. On the left sidebar, select **Search or go to** and find a project for
which the GitLab for Slack app is configured.
1. Select **Settings > Integrations**.
1. Select **GitLab for Slack app**.
@@ -105,7 +105,7 @@ The command returns an error if no matching action is found.
By default, slash commands expect a project full path. To create a shorter project alias in the GitLab for Slack app:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **GitLab for Slack app**.
1. The current **Project Alias**, if any, is displayed. To edit this value,
@@ -122,7 +122,7 @@ With Slack notifications, GitLab can send messages to Slack workspace channels f
To configure Slack notifications:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find a project for
+1. On the left sidebar, select **Search or go to** and find a project for
which the GitLab for Slack app is [installed](#install-the-gitlab-for-slack-app).
1. Select **Settings > Integrations**.
1. Select **GitLab for Slack app**.
@@ -168,10 +168,19 @@ The following events are available for Slack notifications:
| **Wiki page** | A wiki page is created or updated. |
| **Deployment** | A deployment starts or finishes. |
| **Alert** | A new, unique alert is recorded. |
-| **Group mention in public** | A group is mentioned in a public context. |
-| **Group mention in private** | A group is mentioned in a confidential context. |
+| **[Group mention](#trigger-notifications-for-group-mentions) in public** | A group is mentioned in a public context. |
+| **[Group mention](#trigger-notifications-for-group-mentions) in private** | A group is mentioned in a confidential context. |
| [**Vulnerability**](../../application_security/vulnerabilities/index.md) | A new, unique vulnerability is recorded. |
+### Trigger notifications for group mentions
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/417751) in GitLab 16.4.
+
+To trigger a [notification event](#notification-events) for a group mention, use `@<group_name>` in:
+
+- Issue and merge request descriptions
+- Comments on issues, merge requests, and commits
+
## Troubleshooting
### GitLab for Slack app does not appear in the list of integrations
diff --git a/doc/user/project/integrations/google_play.md b/doc/user/project/integrations/google_play.md
index 696bb6acf99..1affa7abfb4 100644
--- a/doc/user/project/integrations/google_play.md
+++ b/doc/user/project/integrations/google_play.md
@@ -29,7 +29,7 @@ Prerequisites:
To enable the Google Play integration in GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Google Play**.
1. In **Enable integration**, select the **Active** checkbox.
diff --git a/doc/user/project/integrations/harbor.md b/doc/user/project/integrations/harbor.md
index 803984f82bf..9d6be5da810 100644
--- a/doc/user/project/integrations/harbor.md
+++ b/doc/user/project/integrations/harbor.md
@@ -25,7 +25,7 @@ In the Harbor instance, ensure that:
GitLab supports integrating Harbor projects at the group or project level. Complete these steps in GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Harbor**.
1. Under **Enable integration**, select the **Active** checkbox.
diff --git a/doc/user/project/integrations/index.md b/doc/user/project/integrations/index.md
index 00ae1a0478c..59b5043b8f7 100644
--- a/doc/user/project/integrations/index.md
+++ b/doc/user/project/integrations/index.md
@@ -18,7 +18,7 @@ Prerequisites:
To view the available integrations for your project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
You can also view and manage integration settings across [all projects in an instance or group](../../admin_area/settings/project_integration_management.md).
diff --git a/doc/user/project/integrations/irker.md b/doc/user/project/integrations/irker.md
index f5084392841..146123f97cd 100644
--- a/doc/user/project/integrations/irker.md
+++ b/doc/user/project/integrations/irker.md
@@ -39,7 +39,7 @@ network. For more details, read
## Complete these steps in GitLab
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **irker (IRC gateway)**.
1. Ensure that the **Active** toggle is enabled.
diff --git a/doc/user/project/integrations/mattermost.md b/doc/user/project/integrations/mattermost.md
index 9e1de5e3aab..9588fbff922 100644
--- a/doc/user/project/integrations/mattermost.md
+++ b/doc/user/project/integrations/mattermost.md
@@ -41,7 +41,7 @@ Display name override is not enabled by default, you need to ask your administra
After the Mattermost instance has an incoming webhook set up, you can set up GitLab
to send the notifications:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Mattermost notifications**.
1. Select the GitLab events to generate notifications for. For each event you select, input the Mattermost channel
diff --git a/doc/user/project/integrations/mattermost_slash_commands.md b/doc/user/project/integrations/mattermost_slash_commands.md
index 4898d5bd337..715e744988c 100644
--- a/doc/user/project/integrations/mattermost_slash_commands.md
+++ b/doc/user/project/integrations/mattermost_slash_commands.md
@@ -31,7 +31,7 @@ you must have Mattermost [3.4 or later](https://mattermost.com/blog/category/pla
If Mattermost is installed on the same server as GitLab,
you can automatically configure Mattermost slash commands:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Mattermost slash commands**.
1. Under **Enable integration**, ensure the **Active** checkbox is selected.
@@ -67,7 +67,7 @@ To get configuration values from GitLab:
1. In a different browser tab, sign in to
GitLab as a user with administrator access.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Integrations**.
1. Select **Mattermost slash commands**. GitLab displays potential values for Mattermost settings.
diff --git a/doc/user/project/integrations/microsoft_teams.md b/doc/user/project/integrations/microsoft_teams.md
index b359696c72b..dea34709dff 100644
--- a/doc/user/project/integrations/microsoft_teams.md
+++ b/doc/user/project/integrations/microsoft_teams.md
@@ -35,7 +35,7 @@ After you configure Microsoft Teams to receive notifications, you must configure
GitLab to send the notifications:
1. Sign in to GitLab as an administrator.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Microsoft Teams notifications**.
1. To enable the integration, select **Active**.
diff --git a/doc/user/project/integrations/pivotal_tracker.md b/doc/user/project/integrations/pivotal_tracker.md
index 3697e660deb..cd0a1819afd 100644
--- a/doc/user/project/integrations/pivotal_tracker.md
+++ b/doc/user/project/integrations/pivotal_tracker.md
@@ -37,7 +37,7 @@ In Pivotal Tracker, [create an API token](https://www.pivotaltracker.com/help/ar
Complete these steps in GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Pivotal Tracker**.
1. Ensure that the **Active** toggle is enabled.
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
deleted file mode 100644
index c0b2591d824..00000000000
--- a/doc/user/project/integrations/prometheus.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: 'index.md'
----
-
-# Prometheus (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/project/integrations/prometheus_library/cloudwatch.md b/doc/user/project/integrations/prometheus_library/cloudwatch.md
deleted file mode 100644
index e31f3b26e66..00000000000
--- a/doc/user/project/integrations/prometheus_library/cloudwatch.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../../../operations/index.md'
----
-
-# Monitoring AWS resources (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/project/integrations/prometheus_library/haproxy.md b/doc/user/project/integrations/prometheus_library/haproxy.md
deleted file mode 100644
index 4a0d324932b..00000000000
--- a/doc/user/project/integrations/prometheus_library/haproxy.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../../../operations/index.md'
----
-
-# Monitoring HAProxy (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/project/integrations/prometheus_library/index.md b/doc/user/project/integrations/prometheus_library/index.md
deleted file mode 100644
index 49345f41514..00000000000
--- a/doc/user/project/integrations/prometheus_library/index.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../../../operations/index.md'
----
-
-# Prometheus Metrics library (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md
deleted file mode 100644
index f5bbaffa58e..00000000000
--- a/doc/user/project/integrations/prometheus_library/kubernetes.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../../../operations/index.md'
----
-
-# Monitoring Kubernetes (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/project/integrations/prometheus_library/nginx.md b/doc/user/project/integrations/prometheus_library/nginx.md
deleted file mode 100644
index e38f26710fc..00000000000
--- a/doc/user/project/integrations/prometheus_library/nginx.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../../../operations/index.md'
----
-
-# Monitoring NGINX (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress.md b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
deleted file mode 100644
index 189cf59a514..00000000000
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../../../operations/index.md'
----
-
-# Monitoring NGINX Ingress Controller (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
deleted file mode 100644
index e4edd63314f..00000000000
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2023-08-22'
-redirect_to: '../../../../operations/index.md'
----
-
-# Monitoring NGINX Ingress Controller with VTS metrics (removed) **(FREE ALL)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/399231) in 16.0.
diff --git a/doc/user/project/integrations/pumble.md b/doc/user/project/integrations/pumble.md
index 218a036f0a2..3f1907d04cb 100644
--- a/doc/user/project/integrations/pumble.md
+++ b/doc/user/project/integrations/pumble.md
@@ -26,7 +26,7 @@ notifications:
1. To enable the integration for your group or project:
1. In your group or project, on the left sidebar, select **Settings > Integrations**.
1. To enable the integration for your instance:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. On the left sidebar, select **Settings > Integrations**.
1. Select the **Pumble** integration.
diff --git a/doc/user/project/integrations/redmine.md b/doc/user/project/integrations/redmine.md
index af2c7265f5d..a66aa9cd00a 100644
--- a/doc/user/project/integrations/redmine.md
+++ b/doc/user/project/integrations/redmine.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
You can use [Redmine](https://www.redmine.org/) as an external issue tracker.
To enable the Redmine integration in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Redmine**.
1. Under **Enable integration**, select the **Active** checkbox.
@@ -38,7 +38,7 @@ For example, this is a configuration for a project named `gitlab-ci`:
You can also disable [GitLab internal issue tracking](../issues/index.md) in this project.
For more information about the steps and consequences of disabling GitLab issues, see
-[Configure project visibility, features, and permissions](../settings/index.md#configure-project-visibility-features-and-permissions).
+Configure project [visibility](../../../user/public_access.md#change-project-visibility), [features, and permissions](../settings/index.md#configure-project-features-and-permissions).
## Reference Redmine issues in GitLab
diff --git a/doc/user/project/integrations/shimo.md b/doc/user/project/integrations/shimo.md
index b2c85c8cb4c..aeddee29109 100644
--- a/doc/user/project/integrations/shimo.md
+++ b/doc/user/project/integrations/shimo.md
@@ -23,7 +23,7 @@ This change is a breaking change.
To enable the Shimo integration for your project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Shimo**.
1. Under **Enable integration**, ensure the **Active** checkbox is selected.
@@ -36,7 +36,7 @@ On the left sidebar, **Shimo** now appears instead of **Wiki**.
To view the Shimo Workspace from your group or project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Shimo**.
1. On the **Shimo Workspace** page, select **Go to Shimo Workspace**.
diff --git a/doc/user/project/integrations/slack.md b/doc/user/project/integrations/slack.md
index 87d7476e42e..d48fd929d54 100644
--- a/doc/user/project/integrations/slack.md
+++ b/doc/user/project/integrations/slack.md
@@ -32,7 +32,7 @@ to control GitLab from Slack. Slash commands are configured separately.
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106760) in GitLab 15.9 to limit Slack channels to 10 per event.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Slack notifications**.
1. Under **Enable integration**, select the **Active** checkbox.
@@ -79,10 +79,19 @@ The following triggers are available for Slack notifications:
| **Wiki page** | A wiki page is created or updated. |
| **Deployment** | A deployment starts or finishes. |
| **Alert** | A new, unique alert is recorded. |
-| **Group mention in public** | A group is mentioned in a public context. |
-| **Group mention in private** | A group is mentioned in a confidential context. |
+| **[Group mention](#trigger-notifications-for-group-mentions) in public** | A group is mentioned in a public context. |
+| **[Group mention](#trigger-notifications-for-group-mentions) in private** | A group is mentioned in a confidential context. |
| [**Vulnerability**](../../application_security/vulnerabilities/index.md) | A new, unique vulnerability is recorded. |
+## Trigger notifications for group mentions
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/417751) in GitLab 16.4.
+
+To trigger a [notification event](#triggers-for-slack-notifications) for a group mention, use `@<group_name>` in:
+
+- Issue and merge request descriptions
+- Comments on issues, merge requests, and commits
+
## Troubleshooting
If your Slack integration is not working, start troubleshooting by
@@ -147,7 +156,7 @@ Commands that change data can cause damage if not run correctly or under the rig
```ruby
# Grab all projects that have the Slack notifications enabled
-p = Project.find_by_sql("SELECT p.id FROM projects p LEFT JOIN integrations s ON p.id = s.project_id WHERE s.type_new = 'Slack' AND s.active = true")
+p = Project.find_by_sql("SELECT p.id FROM projects p LEFT JOIN integrations s ON p.id = s.project_id WHERE s.type_new = 'Integrations::Slack' AND s.active = true")
# Disable the integration on each of the projects that were found.
p.each do |project|
diff --git a/doc/user/project/integrations/slack_slash_commands.md b/doc/user/project/integrations/slack_slash_commands.md
index 78c8180cb4c..67894e158c8 100644
--- a/doc/user/project/integrations/slack_slash_commands.md
+++ b/doc/user/project/integrations/slack_slash_commands.md
@@ -23,7 +23,7 @@ For a list of available slash commands, see [Slash commands](gitlab_slack_applic
Slack slash commands are scoped to a project. To configure Slack slash commands:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Slack slash commands** and leave this browser tab open.
1. In a new browser tab, sign in to Slack and [add a new slash command](https://my.slack.com/services/new/slash-commands).
diff --git a/doc/user/project/integrations/squash_tm.md b/doc/user/project/integrations/squash_tm.md
index ff633783e83..75849d61551 100644
--- a/doc/user/project/integrations/squash_tm.md
+++ b/doc/user/project/integrations/squash_tm.md
@@ -26,7 +26,7 @@ are synchronized as requirements in Squash TM and test progress is reported in G
## Configure GitLab
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Squash TM**.
1. Ensure that the **Active** toggle is enabled.
diff --git a/doc/user/project/integrations/telegram.md b/doc/user/project/integrations/telegram.md
index d68222d2f94..4e94ef76f58 100644
--- a/doc/user/project/integrations/telegram.md
+++ b/doc/user/project/integrations/telegram.md
@@ -40,10 +40,10 @@ After you invite the bot to a Telegram channel, you can configure GitLab to send
1. To enable the integration:
- **For your group or project:**
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+ 1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > Integrations**.
- **For your instance:**
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Integrations**.
1. Select **Telegram**.
diff --git a/doc/user/project/integrations/unify_circuit.md b/doc/user/project/integrations/unify_circuit.md
index d59bfde5944..34f8cf262cd 100644
--- a/doc/user/project/integrations/unify_circuit.md
+++ b/doc/user/project/integrations/unify_circuit.md
@@ -15,7 +15,7 @@ copy its URL.
In GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **Unify Circuit**.
1. Turn on the **Active** toggle.
diff --git a/doc/user/project/integrations/webex_teams.md b/doc/user/project/integrations/webex_teams.md
index 370584303f8..b675ffa7a36 100644
--- a/doc/user/project/integrations/webex_teams.md
+++ b/doc/user/project/integrations/webex_teams.md
@@ -26,10 +26,10 @@ notifications:
1. To enable integration:
- At the project or group level:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+ 1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > Integrations**.
- At the instance level:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Integrations**.
1. Select the **Webex Teams** integration.
diff --git a/doc/user/project/integrations/webhook_events.md b/doc/user/project/integrations/webhook_events.md
index c4dd8dcf812..269fdf304a8 100644
--- a/doc/user/project/integrations/webhook_events.md
+++ b/doc/user/project/integrations/webhook_events.md
@@ -988,7 +988,7 @@ Payload example:
"draft": {
"previous": true,
"current": false
- }
+ },
"updated_at": {
"previous": "2017-09-15 16:50:55 UTC",
"current":"2017-09-15 16:52:00 UTC"
@@ -1026,7 +1026,7 @@ Payload example:
"last_edited_by_id": {
"previous": null,
"current": 3278533
- },
+ }
},
"assignees": [
{
@@ -1521,7 +1521,8 @@ Deployment events are triggered when a deployment:
- Fails
- Is cancelled
-The `deployable_id` in the payload is the ID of the CI/CD job.
+The `deployable_id` and `deployable_url` in the payload represent a CI/CD job that executed the deployment.
+When the deployment event occurs by [API](../../../ci/environments/external_deployment_tools.md) or [`trigger` jobs](../../../ci/pipelines/downstream_pipelines.md), `deployable_url` is `null`.
Request header:
@@ -1879,12 +1880,13 @@ Payload example:
## Emoji events
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123952) in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `emoji_webhooks`. Disabled by default.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123952) in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `emoji_webhooks`. Disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/417288) in GitLab 16.3.
+> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/417288) in GitLab 16.4.
FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `emoji_webhooks`.
-On GitLab.com, this feature is not available.
-This feature is not ready for production use.
+On self-managed GitLab, by default this feature is available. To hide the feature, an administrator can
+[disable the feature flag](../../../administration/feature_flags.md) named `emoji_webhooks`. On GitLab.com, this feature is available.
NOTE:
To have the `emoji_webhooks` flag enabled on GitLab.com, see [issue 417288](https://gitlab.com/gitlab-org/gitlab/-/issues/417288).
diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md
index fe3d5e015a6..8e7f8bcd67d 100644
--- a/doc/user/project/integrations/webhooks.md
+++ b/doc/user/project/integrations/webhooks.md
@@ -40,7 +40,7 @@ including:
## Group webhooks **(PREMIUM ALL)**
You can configure a group webhook, which is triggered by events
-that occur across all projects in the group. If you configure identical webhooks
+that occur across all projects in the group and its subgroups. If you configure identical webhooks
in a group and a project, they are both triggered by an event in the
project.
diff --git a/doc/user/project/integrations/youtrack.md b/doc/user/project/integrations/youtrack.md
index 651c1a15b7a..c05083a1d83 100644
--- a/doc/user/project/integrations/youtrack.md
+++ b/doc/user/project/integrations/youtrack.md
@@ -14,7 +14,7 @@ You can configure YouTrack as an
To enable the YouTrack integration in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **YouTrack**.
1. Under **Enable integration**, select the **Active** checkbox.
@@ -30,7 +30,7 @@ project pages. This link takes you to the appropriate YouTrack project.
You can also disable [GitLab internal issue tracking](../issues/index.md) in this project.
For more information about the steps and consequences of disabling GitLab issues, see
-[Configure project visibility, features, and permissions](../settings/index.md#configure-project-visibility-features-and-permissions).
+Configure project [visibility](../../../user/public_access.md#change-project-visibility), [features, and permissions](../settings/index.md#configure-project-features-and-permissions).
## Reference YouTrack issues in GitLab
diff --git a/doc/user/project/issues/confidential_issues.md b/doc/user/project/issues/confidential_issues.md
index 0b8f6cc33fc..60b50251555 100644
--- a/doc/user/project/issues/confidential_issues.md
+++ b/doc/user/project/issues/confidential_issues.md
@@ -32,7 +32,7 @@ When you create a confidential issue in a project, the project becomes listed in
To create a confidential issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, at the top, select **Create new** (**{plus}**).
1. From the dropdown list, select **New issue**.
1. Complete the [fields](create_issues.md#fields-in-the-new-issue-form).
@@ -43,7 +43,7 @@ To create a confidential issue:
To change the confidentiality of an existing issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**.
1. Select the title of your issue to view it.
1. On the right sidebar, next to **Confidentiality**, select **Edit**.
diff --git a/doc/user/project/issues/create_issues.md b/doc/user/project/issues/create_issues.md
index 3014b088fd6..cd4ef43d333 100644
--- a/doc/user/project/issues/create_issues.md
+++ b/doc/user/project/issues/create_issues.md
@@ -28,7 +28,7 @@ Prerequisites:
To create an issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Either:
- On the left sidebar, select **Plan > Issues**, and then, in the upper-right corner, select **New issue**.
@@ -51,7 +51,7 @@ Prerequisites:
To create an issue from a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Issues**.
1. In the upper-right corner, select **Select project to create issue**.
1. Select the project you'd like to create an issue for. The button now reflects the selected
@@ -98,7 +98,7 @@ Prerequisites:
To create an issue from a project issue board:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issue boards**.
1. At the top of a board list, select **Create new issue** (**{plus-square}**).
1. Enter the issue's title.
@@ -106,7 +106,7 @@ To create an issue from a project issue board:
To create an issue from a group issue board:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Issue boards**.
1. At the top of a board list, select **Create new issue** (**{plus-square}**).
1. Enter the issue's title.
@@ -130,7 +130,7 @@ Prerequisites:
To email an issue to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**.
1. At the bottom of the page, select **Email a new issue to this project**.
1. To copy the email address, select **Copy** (**{copy-to-clipboard}**).
diff --git a/doc/user/project/issues/crosslinking_issues.md b/doc/user/project/issues/crosslinking_issues.md
index b3fe7da4280..882e4d97938 100644
--- a/doc/user/project/issues/crosslinking_issues.md
+++ b/doc/user/project/issues/crosslinking_issues.md
@@ -76,3 +76,10 @@ you can also [set an issue to close automatically](managing_issues.md#closing-is
as soon as the merge request is merged.
![issue mentioned in MR](img/mention_in_merge_request.png)
+
+## From branch names
+
+When you create a branch in the same project as an issue and start the branch name with the issue
+number, followed by a hyphen, the issue and MR you create are linked.
+For more information, see
+[Prefix branch names with issue numbers](../repository/branches/index.md#prefix-branch-names-with-issue-numbers).
diff --git a/doc/user/project/issues/csv_export.md b/doc/user/project/issues/csv_export.md
index 86370cab963..34a9b69038b 100644
--- a/doc/user/project/issues/csv_export.md
+++ b/doc/user/project/issues/csv_export.md
@@ -1,97 +1,102 @@
---
-stage: none
-group: unassigned
+stage: Plan
+group: Project Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Export issues to CSV **(FREE ALL)**
-> Moved to GitLab Free in 12.10.
-
-You can export issues as CSV files from GitLab, which are sent to your default
-notification email address as an attachment.
-
-**Export Issues to CSV** enables you and your team to export all the data
-collected from issues into a **[comma-separated values](https://en.wikipedia.org/wiki/Comma-separated_values)** (CSV)
-file, which stores tabular data in plain text.
+You can export issues from GitLab to a plain-text CSV
+([comma-separated values](https://en.wikipedia.org/wiki/Comma-separated_values))
+file. The CSV file is attached to an email, and sent to your default
+notification email address.
<!-- vale gitlab.Spelling = NO -->
-CSV files can be used with any plotter or spreadsheet-based program, such as
-Microsoft Excel, Open Office Calc, or Google Sheets.
+CSV files can be used with any plotter or spreadsheet-based program, like
+Microsoft Excel, OpenOffice Calc, or Google Sheets. Use a CSV list of issues to:
<!-- vale gitlab.Spelling = YES -->
-Here are some of the uses of exporting issues as CSV files:
-
-- Make a snapshot of issues for offline analysis or to communicate with other
- teams who may not be in GitLab.
+- Create a snapshot of issues for offline analysis, or to share with other
+ teams who might not be in GitLab.
- Create diagrams, graphs, and charts from the CSV data.
-- Present the data in any other format for auditing or sharing reasons.
-- Import the issues elsewhere to a system outside of GitLab.
-- Long-term issues' data analysis with multiple snapshots created along the
- time.
+- Convert the data to other formats for auditing or sharing.
+- Import the issues to a system outside of GitLab.
+- Analyze long-term trends with multiple snapshots created over time.
- Use the long-term data to gather relevant feedback given in the issues, and
improve your product based on real metrics.
-## Choosing which issues to include
-
-After selecting a project, from the issues page you can narrow down which
-issues to export using the search bar, along with the All/Open/Closed tabs. All
-issues returned are exported, including those not shown on the first page.
+## Select issues to export
-![CSV export button](img/csv_export_button_v12_9.png)
+You can export issues from individual projects, but not groups.
-GitLab asks you to confirm the number of issues and email address for the
-export, after which the email is prepared.
+Prerequisites:
-![CSV export modal dialog](img/csv_export_modal.png)
+- You must have at least the Reporter role.
-## Sorting
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Plan > Issues**.
+1. Above the list of issues, select **Search or filter results...**.
+1. In the dropdown list that appears, select the attributes to filter by.
+ For more information about filter options, see
+ [Filter the list of issues](managing_issues.md#filter-the-list-of-issues).
+1. In the upper right, select **Actions** (**{ellipsis_v}**) **> Export as CSV**.
+1. In the dialog, verify that the email address is correct, then select **Export issues**.
-Exported issues are always sorted by `Title`.
+All matching issues are exported, including those not shown on the first page.
+The exported CSV does not contain attachments from issues.
## Format
-Data is encoded with a comma as the column delimiter, with `"` used to quote
-fields if needed, and newlines to separate rows. The first row contains the
-headers, which are listed in the following table along with a description of
-the values:
-
-| Column | Description |
-|------------------------------------------|-----------------------------------------------------------|
-| Title | Issue `title` |
-| Description | Issue `description` |
-| Issue ID | Issue `iid` |
-| URL | A link to the issue on GitLab |
-| State | `Open` or `Closed` |
-| Author | Full name of the issue author |
-| Author Username | Username of the author, with the `@` symbol omitted |
-| Assignee | Full name of the issue assignee |
-| Assignee Username | Username of the author, with the `@` symbol omitted |
-| Confidential | `Yes` or `No` |
-| Locked | `Yes` or `No` |
-| Due Date | Formatted as `YYYY-MM-DD` |
-| Created At (UTC) | Formatted as `YYYY-MM-DD HH:MM:SS` |
-| Updated At (UTC) | Formatted as `YYYY-MM-DD HH:MM:SS` |
-| Milestone | Title of the issue milestone |
-| Weight | Issue weight |
-| Labels | Title of any labels joined with a `,` |
-| Time Estimate | [Time estimate](../time_tracking.md#estimates) in seconds |
-| Time Spent | [Time spent](../time_tracking.md#time-spent) in seconds |
-| [Epic](../../group/epics/index.md) ID | ID of the parent epic, introduced in 12.7 |
-| [Epic](../../group/epics/index.md) Title | Title of the parent epic, introduced in 12.7 |
-
-In GitLab 14.7 and earlier, the first two columns were `Issue ID` and `URL`,
-which [caused an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/34769)
-when importing back into GitLab.
-
-## Limitations
-
-- Export Issues to CSV is not available at the Group's Issues List.
-- Issues are sent as an email attachment, with a 15 MB export limit to ensure
- successful delivery across a range of email providers. If you reach the limit,
- we suggest narrowing the search before export, perhaps by exporting open and
- closed issues separately.
-- CSV files are plain text files. This means that the exported CSV file doesn't
- contain any issue attachments.
+The CSV file has this format:
+
+- Sort is by title.
+- Columns are delimited with commas.
+- Fields are quoted with double quotes (`"`) if needed.
+- Newline characters separate rows.
+
+## Columns
+
+The following columns are included in the CSV file.
+
+| Column | Description |
+|-------------------|-------------|
+| Title | Issue `title` |
+| Description | Issue `description` |
+| Issue ID | Issue `iid` |
+| URL | A link to the issue on GitLab |
+| State | `Open` or `Closed` |
+| Author | Full name of the issue author |
+| Author Username | Username of the author, with the `@` symbol omitted |
+| Assignee | Full name of the issue assignee |
+| Assignee Username | Username of the author, with the `@` symbol omitted |
+| Confidential | `Yes` or `No` |
+| Locked | `Yes` or `No` |
+| Due Date | Formatted as `YYYY-MM-DD` |
+| Created At (UTC) | Formatted as `YYYY-MM-DD HH:MM:SS` |
+| Updated At (UTC) | Formatted as `YYYY-MM-DD HH:MM:SS` |
+| Milestone | Title of the issue milestone |
+| Weight | Issue weight |
+| Labels | Labels, separated by commas |
+| Time Estimate | [Time estimate](../time_tracking.md#estimates) in seconds |
+| Time Spent | [Time spent](../time_tracking.md#time-spent) in seconds |
+| Epic ID | ID of the parent epic |
+| Epic Title | Title of the parent epic |
+
+## Troubleshooting
+
+When working with exported issues, you might encounter the following issues.
+
+### Column order
+
+In GitLab 14.7 and earlier, the first two columns in exported files were `Issue ID` and `URL`,
+which caused problems importing data back into GitLab. For more information, see
+[issue 34769](https://gitlab.com/gitlab-org/gitlab/-/issues/34769).
+
+### Size of export
+
+Issues are sent as an email attachment, with a 15 MB export limit to ensure
+successful delivery across a range of email providers. If you reach the limit,
+narrow your search before export. For example, consider exporting open and
+closed issues separately.
diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md
index 4068083cd1e..0ea49ff387f 100644
--- a/doc/user/project/issues/design_management.md
+++ b/doc/user/project/issues/design_management.md
@@ -6,12 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Design management **(FREE ALL)**
-> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/660) in GitLab 12.2.
-> - Support for SVGs [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12771) in GitLab 12.4.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212566) from GitLab Premium to GitLab Free in 13.0.
-> - Design Management section in issues [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223193) in GitLab 13.2, with a feature flag named `design_management_moved`. In earlier versions, designs were displayed in a separate tab.
-> - Design Management section in issues [feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/223197) for new displays in GitLab 13.4.
-
With Design Management you can upload design assets (including wireframes and mockups)
to GitLab issues and keep them stored in a single place. Product designers, product managers, and
engineers can collaborate on designs with a single source of truth.
@@ -29,7 +23,7 @@ For a video overview, see [Design Management (GitLab 12.2)](https://www.youtube.
- On self-managed instances, a GitLab administrator must
[enable LFS globally](../../../administration/lfs/index.md).
- On both GitLab.com and self-managed instances, LFS must be
- [enabled for the project itself](../settings/index.md#configure-project-visibility-features-and-permissions).
+ [enabled for the project itself](../settings/index.md#configure-project-features-and-permissions).
If enabled globally, LFS is enabled by default for all projects. If you have
disabled it for your project, you must enable it again.
@@ -58,7 +52,6 @@ You can upload files of the following types as designs:
- JPEG
- JPG
- PNG
-- SVG
- TIFF
- WEBP
@@ -69,7 +62,7 @@ Support for PDF files is tracked in [issue 32811](https://gitlab.com/gitlab-org/
- Design Management data isn't deleted when:
- [A project is destroyed](https://gitlab.com/gitlab-org/gitlab/-/issues/13429).
- [An issue is deleted](https://gitlab.com/gitlab-org/gitlab/-/issues/13427).
-- In GitLab 12.7 and later, Design Management data [can be replicated](../../../administration/geo/replication/datatypes.md#limitations-on-replicationverification)
+- Design Management data [can be replicated](../../../administration/geo/replication/datatypes.md#limitations-on-replicationverification)
and in GitLab 16.1 and later it can be [verified by Geo as well](https://gitlab.com/gitlab-org/gitlab/-/issues/355660).
## View a design
@@ -106,9 +99,6 @@ a blue icon (**{file-modified-solid}**) is displayed.
### Zoom in on a design
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13217) in GitLab 12.7.
-> - Ability to drag a zoomed image to move it [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/197324) in GitLab 12.10.
-
You can explore a design in more detail by zooming in and out of the image:
- To control the amount of zoom, select plus (`+`) and minus (`-`)
@@ -124,7 +114,7 @@ To move around the image while zoomed in, drag the image.
Prerequisites:
- You must have at least the Developer role for the project.
-- In GitLab 13.1 and later, the names of the uploaded files must be no longer than 255 characters.
+- The names of the uploaded files must be no longer than 255 characters.
To add a design to an issue:
@@ -163,6 +153,7 @@ Prerequisites:
To do so, [add a design](#add-a-design-to-an-issue) with the same filename.
To browse all the design versions, use the dropdown list at the top of the **Designs** section.
+It's shown as either **Showing latest version** or **Showing version #N**.
### Skipped designs
@@ -172,14 +163,19 @@ When designs are skipped, a warning message is displayed.
## Archive a design
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11089) in GitLab 12.4.
-> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/220964) the button from "Delete" to "Archive" in GitLab 13.3.
-
You can archive individual designs or select a few of them to archive at once.
+Archived designs are not permanently lost.
+You can browse [previous versions](#add-a-new-version-of-a-design).
+
+When you archive a design, its URL changes.
+If the design isn't available in the latest version, you can link to it only with the version in the
+URL.
+
Prerequisites:
- You must have at least the Developer role for the project.
+- You can archive only the latest version of a design.
To archive a single design:
@@ -192,15 +188,10 @@ To archive multiple designs at once:
1. Select the checkboxes on the designs you want to archive.
1. Select **Archive selected**.
-NOTE:
-Only the latest version of the designs can be archived.
-Archived designs are not permanently lost. You can browse
-[previous versions](#add-a-new-version-of-a-design).
+## Markdown and rich text editors for descriptions
<!-- When content_editor_on_issues flag is removed, move version notes
- to "Add a design to an issue", update that topic, and delete the one below. -->
-
-## Markdown and rich text editors for descriptions
+ to "Add a design to an issue", update that topic, and delete this one. -->
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388449) in GitLab 16.1 [with a flag](../../../administration/feature_flags.md) named `content_editor_on_issues`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/375172) in GitLab 16.2.
@@ -214,30 +205,28 @@ It's the same editor you use for comments across GitLab.
## Reorder designs
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34382) in GitLab 13.3.
-
You can change the order of designs by dragging them to a new position.
## Add a comment to a design
-> Adjusting a pin's position [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34353) in GitLab 12.8.
-
You can start [discussions](../../discussions/index.md) on uploaded designs. To do so:
-<!-- vale gitlab.SubstitutionWarning = NO -->
1. Go to an issue.
1. Select the design.
+<!-- vale gitlab.SubstitutionWarning = NO -->
+<!-- Disable Vale so it doesn't catch "click" -->
1. Click or tap the image. A pin is created in that spot, identifying the discussion's location.
+<!-- vale gitlab.SubstitutionWarning = YES -->
1. Enter your message.
1. Select **Comment**.
-<!-- vale gitlab.SubstitutionWarning = YES -->
-You can adjust a pin's position by dragging it around the image. You can use this when your design's
-layout has changed, or when you want to move a pin to add a new one in its place.
+You can adjust a pin's position by dragging it around the image.
+Use this when your design's layout has changed, or to move a pin so you can add a new one in
+its place.
New discussion threads get different pin numbers, which you can use to refer to them.
-In GitLab 12.5 and later, new discussions are output to the issue activity,
+New discussions are output to the issue activity,
so that everyone involved can participate in the discussion.
## Delete a comment from a design
@@ -255,8 +244,6 @@ To delete a comment from a design:
## Resolve a discussion thread on a design
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13049) in GitLab 13.1.
-
When you're done discussing part of a design, you can resolve the discussion thread.
To mark a thread as resolved or unresolved, either:
@@ -272,16 +259,10 @@ To revisit a resolved discussion, expand **Resolved Comments** below the visible
## Add a to-do item for a design
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/198439) in GitLab 13.4.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/245074) in GitLab 13.5.
-
To add a [to-do item](../../todos.md) for a design, select **Add a to do** on the design sidebar.
## Refer to a design in Markdown
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217160) in GitLab 13.1.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/258662) in GitLab 13.5.
-
To refer to a design in a [Markdown](../../markdown.md) text box in GitLab, for example, in
a comment or description, paste its URL. It's then displayed as a short reference.
@@ -297,9 +278,6 @@ It's rendered as:
## Design activity records
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33051) in GitLab 13.1.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/225205) in GitLab 13.2.
-
User activity events on designs (creation, deletion, and updates) are tracked by GitLab and
displayed on the [user profile](../../profile/index.md#access-your-user-profile),
[group](../../group/manage.md#view-group-activity),
@@ -307,8 +285,6 @@ and [project](../working_with_projects.md#view-project-activity) activity pages.
## GitLab-Figma plugin
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-figma-plugin/-/issues/2) in GitLab 13.2.
-
You can use the GitLab-Figma plugin to upload your designs from Figma directly to your issues
in GitLab.
@@ -316,3 +292,26 @@ To use the plugin in Figma, install it from the [Figma Directory](https://www.fi
and connect to GitLab through a personal access token.
For more information, see the [plugin documentation](https://gitlab.com/gitlab-org/gitlab-figma-plugin/-/wikis/home).
+
+## Troubleshooting
+
+When working with Design Management, you might encounter the following issues.
+
+### Could not find design
+
+You might get an error that states `Could not find design`.
+
+This issue occurs when a design has been [archived](#archive-a-design),
+so it's not available in the latest version, and the link you've followed doesn't specify a version.
+
+When you archive a design, its URL changes.
+If the design isn't available in the latest version, it can be linked to only with the version in the URL.
+
+For example, `https://gitlab.example.com/mygroup/myproject/-/issues/123456/designs/menu.png?version=503554`.
+You can no longer access `menu.png` with `https://gitlab.example.com/mygroup/myproject/-/issues/123456/designs/menu.png`.
+
+The workaround is to select one of the previous versions from the dropdown list at the top of the
+**Designs** section.
+It's shown as either **Showing latest version** or **Showing version #N**.
+
+Issue [392540](https://gitlab.com/gitlab-org/gitlab/-/issues/392540) tracks improving this behavior.
diff --git a/doc/user/project/issues/img/csv_export_button_v12_9.png b/doc/user/project/issues/img/csv_export_button_v12_9.png
deleted file mode 100644
index 702b6439d7c..00000000000
--- a/doc/user/project/issues/img/csv_export_button_v12_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/issues/img/csv_export_modal.png b/doc/user/project/issues/img/csv_export_modal.png
deleted file mode 100644
index f988deec966..00000000000
--- a/doc/user/project/issues/img/csv_export_modal.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
index 02cefaa47ef..cb3cbf5fc36 100644
--- a/doc/user/project/issues/managing_issues.md
+++ b/doc/user/project/issues/managing_issues.md
@@ -18,7 +18,7 @@ Prerequisites:
To edit an issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select the title of your issue to view it.
1. To the right of the title, select **Edit title and description** (**{pencil}**).
1. Edit the available fields.
@@ -54,7 +54,7 @@ Prerequisites:
To edit multiple issues at the same time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**.
1. Select **Bulk edit**. A sidebar on the right of your screen appears.
1. Select the checkboxes next to each issue you want to edit.
@@ -88,7 +88,7 @@ Prerequisites:
To edit multiple issues at the same time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Issues**.
1. Select **Bulk edit**. A sidebar on the right of your screen appears.
1. Select the checkboxes next to each issue you want to edit.
@@ -117,7 +117,7 @@ Prerequisites:
To move an issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. On the right sidebar, select **Move issue**.
1. Search for a project to move the issue to.
@@ -138,7 +138,7 @@ Prerequisite:
To move multiple issues at the same time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**.
1. Select **Bulk edit**. A sidebar on the right of your screen appears.
1. Select the checkboxes next to each issue you want to move.
@@ -212,7 +212,7 @@ To close an issue, you can either:
- In an [issue board](../issue_board.md), drag an issue card from its list into the **Closed** list.
- From any other page in the GitLab UI:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. At the top of the issue, select **Close issue**.
@@ -309,7 +309,7 @@ Prerequisites:
To disable automatic issue closing:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Branch defaults**.
1. Clear the **Auto-close referenced issues on default branch** checkbox.
@@ -357,7 +357,7 @@ Prerequisites:
To change issue type:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. To the right of the title, select **Edit title and description** (**{pencil}**).
1. Edit the issue and select an issue type from the **Issue type** dropdown list:
@@ -377,14 +377,14 @@ Prerequisites:
To delete an issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. On the top right corner, select **Issue actions** (**{ellipsis_v}**).
1. Select **Delete issue**.
Alternatively:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select the title of your issue to view it.
1. Select **Edit title and description** (**{pencil}**).
1. Select **Delete issue**.
@@ -399,7 +399,7 @@ You can promote an issue to an [epic](../../group/epics/index.md) in the immedia
To promote an issue to an epic:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. On the top right corner, select **Issue actions** (**{ellipsis_v}**).
1. Select **Promote to epic**.
@@ -422,7 +422,7 @@ You can use the `/promote_to_incident` [quick action](../quick_actions.md) to pr
To add an issue to an [iteration](../../group/iterations/index.md):
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. On the right sidebar, in the **Iteration** section, select **Edit**.
1. From the dropdown list, select the iteration to associate this issue with.
@@ -434,7 +434,7 @@ Alternatively, you can use the `/iteration` [quick action](../quick_actions.md#i
To view all issues assigned to you:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**).
+1. On the left sidebar, select **Search or go to**.
1. From the dropdown list, select **Issues assigned to me**.
Or:
@@ -453,7 +453,7 @@ Or:
To filter the list of issues:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**.
1. Above the list of issues, select **Search or filter results...**.
1. In the dropdown list that appears, select the attribute you want to filter by.
@@ -491,7 +491,7 @@ when you [filter the list of issues](#filter-the-list-of-issues) by:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39908) in GitLab 12.1.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**.
1. In the **Search** box, type the issue ID. For example, enter filter `#10` to return only issue 10.
@@ -504,7 +504,7 @@ To refer to an issue elsewhere in GitLab, you can use its full URL or a short re
To copy the issue reference to your clipboard:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. On the right sidebar, next to **Reference**, select **Copy Reference** (**{copy-to-clipboard}**).
@@ -528,7 +528,7 @@ For more information about creating comments by sending an email and the necessa
To copy the issue's email address:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. On the right sidebar, next to **Issue email**, select **Copy Reference** (**{copy-to-clipboard}**).
@@ -545,7 +545,7 @@ themselves or another project member assigns them.
To change the assignee on an issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. On the right sidebar, in the **Assignee** section, select **Edit**.
1. From the dropdown list, select the user to add as an assignee.
@@ -586,7 +586,7 @@ Prerequisites:
To edit health status of an issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. On the right sidebar, in the **Health status** section, select **Edit**.
1. From the dropdown list, select the status to add to this issue:
diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md
index 4daaaf72683..86d21d07950 100644
--- a/doc/user/project/labels.md
+++ b/doc/user/project/labels.md
@@ -69,7 +69,7 @@ You can also assign and unassign labels with [quick actions](quick_actions.md):
To view the **project's labels**:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Labels**.
Or:
@@ -86,7 +86,7 @@ project or group path where it was created.
To view the **group's labels**:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Labels**.
Or:
@@ -108,7 +108,7 @@ Prerequisites:
To create a project label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Labels**.
1. Select **New label**.
1. In the **Title** field, enter a short, descriptive name for the label. You
@@ -142,7 +142,7 @@ To do so:
To create a group label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Labels**.
1. Select **New label**.
1. In the **Title** field, enter a short, descriptive name for the label. You
@@ -182,7 +182,7 @@ Prerequisites:
To edit a **project** label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Labels**.
1. Next to the label you want to edit, select **Edit** (**{pencil}**).
@@ -190,7 +190,7 @@ To edit a **project** label:
To edit a **group** label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Labels**.
1. Next to the label you want to edit, select **Edit** (**{pencil}**).
@@ -208,7 +208,7 @@ Prerequisites:
To delete a **project** label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Labels**.
1. Either:
@@ -221,7 +221,7 @@ To delete a **project** label:
To delete a **group** label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Manage > Labels**.
1. Either:
@@ -251,7 +251,7 @@ Prerequisites:
To promote a project label to a group label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Labels**.
1. Next to the **Subscribe** button, select the three dots (**{ellipsis_v}**) and
select **Promote to group label**.
@@ -302,7 +302,7 @@ Prerequisites:
To add the default labels to the project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Labels**.
1. Select **Generate a default set of labels**.
@@ -441,7 +441,7 @@ Prerequisites:
To prioritize a label:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Labels**.
1. Next to a label you want to prioritize, select the star (**{star-o}**).
diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md
index 1e9bd307333..901a8fe9850 100644
--- a/doc/user/project/members/index.md
+++ b/doc/user/project/members/index.md
@@ -119,7 +119,7 @@ Prerequisite:
To add a user to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. Select **Invite members**.
1. If the user:
@@ -180,7 +180,7 @@ Prerequisites:
To add a group to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. Select **Invite a group**.
1. Select a group.
@@ -211,7 +211,7 @@ If the importing member's role in the target project is:
To import users:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. Select **Import from a project**.
1. Select the project. You can view only the projects for which you're a maintainer.
@@ -236,7 +236,7 @@ Prerequisites:
To remove a member from a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. Next to the project member you want to remove, select **Remove member**.
1. Optional. On the confirmation dialog, select the
@@ -273,7 +273,7 @@ You can filter and sort members in a project.
### Display inherited members
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. In the **Filter members** box, select `Membership` `=` `Inherited`.
1. Press <kbd>Enter</kbd>.
@@ -282,7 +282,7 @@ You can filter and sort members in a project.
### Display direct members
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. In the **Filter members** box, select `Membership` `=` `Direct`.
1. Press <kbd>Enter</kbd>.
@@ -305,7 +305,7 @@ You can sort members by **Account**, **Access granted**, **Max role**, or **Last
GitLab users can request to become a member of a project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find the project you want to be a member of.
+1. On the left sidebar, select **Search or go to** and find the project you want to be a member of.
1. By the project's name, select **Request Access**.
![Request access button](img/request_access_button.png)
@@ -329,7 +329,7 @@ Prerequisite:
- You must be the project owner.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Under **Project visibility**, select **Users can request access**.
diff --git a/doc/user/project/members/share_project_with_groups.md b/doc/user/project/members/share_project_with_groups.md
index 3780018bf11..deefe9040fa 100644
--- a/doc/user/project/members/share_project_with_groups.md
+++ b/doc/user/project/members/share_project_with_groups.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
When you want a group to have access to your project,
you can invite [a group](../../group/index.md) to the project.
-The group's members get access to the project, which becomes a *shared project*.
+The group's direct and inherited members get access to the project, which becomes a *shared project*.
## Example
@@ -53,11 +53,12 @@ must be at least as restrictive as that of the project. For example, you can inv
> - [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.
-You can share a project with a group by inviting that group to the project.
+Similar to how you [share a group with another group](../../group/manage.md#share-a-group-with-another-group),
+you can share a project with a group by inviting that group to the project.
To invite a group to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. Select **Invite a group**.
1. **Select a group** you want to add to the project.
@@ -99,7 +100,7 @@ For example, if a group member has the role of Developer, and the group is invit
To view the maximum role assigned to a member:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Members**.
1. In the **Max role** column, view the user's maximum assigned role.
@@ -109,7 +110,7 @@ In a group, a shared project is a project to which the group members gained acce
To view a group's shared projects:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the group page, select the **Shared projects** tab.
A list of shared projects is displayed.
diff --git a/doc/user/project/merge_requests/ai_in_merge_requests.md b/doc/user/project/merge_requests/ai_in_merge_requests.md
index c1aa729d8c5..304717cf9fc 100644
--- a/doc/user/project/merge_requests/ai_in_merge_requests.md
+++ b/doc/user/project/merge_requests/ai_in_merge_requests.md
@@ -34,8 +34,7 @@ Provide feedback on this experimental feature in [issue 416537](https://gitlab.c
- Title of the merge request
- Contents of the description
-- Source branch name
-- Target branch name
+- Diff of changes between the source branch's head and the target branch
## Summarize merge request changes **(ULTIMATE SAAS)**
diff --git a/doc/user/project/merge_requests/approvals/rules.md b/doc/user/project/merge_requests/approvals/rules.md
index cbbeac17355..87ff6376ebd 100644
--- a/doc/user/project/merge_requests/approvals/rules.md
+++ b/doc/user/project/merge_requests/approvals/rules.md
@@ -89,17 +89,15 @@ To edit a merge request approval rule:
## Add multiple approval rules
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1979) in GitLab 11.10.
-
In GitLab Premium and Ultimate tiers, you can enforce multiple approval rules on a
merge request, and multiple default approval rules for a project. If your tier
supports multiple default rules:
- When [adding](#add-an-approval-rule) or [editing](#edit-an-approval-rule) an approval rule
- for a project, GitLab displays the **Add approval rule** button even after a rule is defined.
+ for a project, GitLab displays **Add approval rule**, even after a rule is defined.
- When editing or overriding multiple approval rules
[on a merge request](#edit-or-override-merge-request-approval-rules), GitLab
- displays the **Add approval rule** button even after a rule is defined.
+ displays **Add approval rule**, even after a rule is defined.
When an [eligible approver](#eligible-approvers) approves a merge request, it
reduces the number of approvals left (the **Approvals** column) for all rules that the approver belongs to:
@@ -111,8 +109,6 @@ For an overview, see [Multiple Approvers](https://www.youtube.com/watch?v=8JQJ58
## Eligible approvers
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10294) in GitLab 13.3, when an eligible approver comments on a merge request, it appears in the **Commented by** column of the Approvals widget.
-
To be eligible as an approver for a project, a user must be a member of one or
more of these:
@@ -140,15 +136,20 @@ users were not explicitly listed in the approval rules.
### Group approvers
-You can add a group of users as approvers, but those users count as approvers only if
-they have **direct membership** to the group. Inherited members do not count. Group approvers are
-restricted to only groups [with share access to the project](../../members/share_project_with_groups.md).
+You can add a group of users as approvers. All **direct members** of this group
+can approve the rule. **Inherited members** cannot approve the rule.
+
+Typically the group is a subgroup in your top-level namespace, unless you are
+collaborating with an external group. If you are collaborating with another group,
+you must [share access to the project](../../members/share_project_with_groups.md)
+before assigning the group as a group approver.
A user's membership in an approvers group affects their individual ability to
approve in these ways:
-- A user already part of a group approver who is later added as an individual approver
- counts as one approver, and not two.
+- Inherited members are not considered approvers. Only direct members can approve merge requests.
+- A user from a group approver group who is later _also_ added as an individual approver
+ counts as one approver, not two.
- Merge request authors do not count as eligible approvers on their own merge requests by default.
To change this behavior, disable the
[**Prevent author approval**](settings.md#prevent-approval-by-author)
@@ -157,6 +158,12 @@ approve in these ways:
[**Prevent committers approval**](settings.md#prevent-approvals-by-users-who-add-commits)
project setting.
+NOTE:
+Creating multiple top-level groups to manage groups of users is not necessary, and is
+discouraged because GitLab Free [is limited to 5 group members](https://about.gitlab.com/pricing/faq-efficient-free-tier/).
+Managing groups of users using subgroups in your top-level namespace enables you
+to use a single license.
+
### Code owners as eligible approvers
> Moved to GitLab Premium in 13.9.
@@ -261,12 +268,9 @@ For more information, see [Coverage check approval rule](../../../../ci/testing/
## Security Approvals **(ULTIMATE ALL)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357021) in GitLab 15.0.
+> - Security approvals moved to merge request approvals settings [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357021) in GitLab 15.0.
> - Bot comment for approvals [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/411656) in GitLab 16.2 [with a flag](../../../../administration/feature_flags.md) named `security_policy_approval_notification`. Enabled by default.
-
-FLAG:
-On self-managed GitLab, by default the bot comment for approvals is available. To hide the feature, an administrator can [disable the feature flag](../../../../administration/feature_flags.md) named `security_policy_approval_notification`.
-On GitLab.com, the bot comment for approvals is available.
+> - Bot comment for approvals [generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130827) in GitLab 16.3. Feature flag `security_policy_approval_notification` removed.
You can use [scan result policies](../../../application_security/policies/scan-result-policies.md#scan-result-policy-editor) to define security approvals based on the status of vulnerabilities in the merge request and the default branch.
Details for each security policy is shown in the Security Approvals section of your Merge Request configuration.
diff --git a/doc/user/project/merge_requests/approvals/settings.md b/doc/user/project/merge_requests/approvals/settings.md
index b520ee41493..ae16eb2a790 100644
--- a/doc/user/project/merge_requests/approvals/settings.md
+++ b/doc/user/project/merge_requests/approvals/settings.md
@@ -65,6 +65,7 @@ this setting, unless you configure one of these options:
> - Moved to GitLab Premium in 13.9.
> - [Feature flag `keep_merge_commits_for_approvals`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127744) added in GitLab 16.3 to also include merge commits in this check.
+> - [Feature flag `keep_merge_commits_for_approvals`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131778) removed in GitLab 16.5. This check now includes merge commits.
By default, users who commit to a merge request can still approve it. At both
the project level or [instance level](../../../admin_area/merge_requests_approvals.md),
diff --git a/doc/user/project/merge_requests/changes.md b/doc/user/project/merge_requests/changes.md
index ab882af7eda..18f19197f4c 100644
--- a/doc/user/project/merge_requests/changes.md
+++ b/doc/user/project/merge_requests/changes.md
@@ -158,7 +158,7 @@ rebases and file changes.
To add a comment to a merge request file:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. Select **Changes**.
1. In the header for the file you want to comment on, select **Comment** (**{comment}**).
diff --git a/doc/user/project/merge_requests/cherry_pick_changes.md b/doc/user/project/merge_requests/cherry_pick_changes.md
index d9b2ecf0806..ef1554f3b86 100644
--- a/doc/user/project/merge_requests/cherry_pick_changes.md
+++ b/doc/user/project/merge_requests/cherry_pick_changes.md
@@ -52,7 +52,7 @@ Commit `G` is added after the cherry-pick.
After a merge request is merged, you can cherry-pick all changes introduced
by the merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**, and find your merge request.
1. Scroll to the merge request reports section, and find the **Merged by** report.
1. In the upper-right corner, select **Cherry-pick**:
@@ -70,7 +70,7 @@ You can cherry-pick a single commit from multiple locations in your GitLab proje
To cherry-pick a commit from the list of all commits for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Commits**.
1. Select the [title](https://git-scm.com/docs/git-commit#_discussion) of the commit you want to cherry-pick.
1. In the upper-right corner, select **Options > Cherry-pick** to show the cherry-pick modal.
@@ -84,7 +84,7 @@ You can cherry-pick commits from any merge request in your project, regardless o
whether the merge request is open or closed. To cherry-pick a commit from the
list of commits included in a merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**, and find your merge request.
1. In the merge request's secondary menu, select **Commits** to display the commit details page.
1. Select the [title](https://git-scm.com/docs/git-commit#_discussion) of the commit you want to cherry-pick.
@@ -98,7 +98,7 @@ list of commits included in a merge request:
You can cherry-pick from the list of previous commits affecting an individual file
when you view that file in your project's Git repository:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Repository** and go to the file
changed by the commit.
1. Select **History**, then select the [title](https://git-scm.com/docs/git-commit#_discussion)
diff --git a/doc/user/project/merge_requests/commit_templates.md b/doc/user/project/merge_requests/commit_templates.md
index 1fc7188ffea..5ca097da29f 100644
--- a/doc/user/project/merge_requests/commit_templates.md
+++ b/doc/user/project/merge_requests/commit_templates.md
@@ -8,7 +8,7 @@ type: reference, howto
# Commit message templates **(FREE ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) squash commit templates in GitLab 14.6.
+> - Squash commit templates [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.
GitLab uses commit templates to create default messages for specific types of
commits. These templates encourage commit messages to follow a particular format,
@@ -29,7 +29,7 @@ Prerequisite:
To do this:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Depending on the type of template you want to create, scroll to either
[**Merge commit message template**](#default-template-for-merge-commits) or
@@ -66,13 +66,13 @@ GitLab creates a squash commit message with this template:
## Supported variables in commit templates
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/346805) `first_commit` and `first_multiline_commit` variables in GitLab 14.6.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75639) `url`, `approved_by`, and `merged_by` variables in GitLab 14.7.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/20421) `co_authored_by` variable in GitLab 14.7.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/26303) `all_commits` variable in GitLab 14.9.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/378352) `reviewed_by` variable in GitLab 15.7.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/199823) `local_reference` variable in GitLab 16.1.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128553) `source_project_id` variables in GitLab 16.3.
+> - `first_commit` and `first_multiline_commit` variables [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346805) in GitLab 14.6.
+> - `url`, `approved_by`, and `merged_by` variables [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75639) in GitLab 14.7.
+> - `co_authored_by` variable [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20421) in GitLab 14.7.
+> - `all_commits` variable [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/26303) in GitLab 14.9.
+> - `reviewed_by` variable [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378352) in GitLab 15.7.
+> - `local_reference` variable [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199823) in GitLab 16.1.
+> - `source_project_id` variables [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/128553) in GitLab 16.3.
Commit message templates support these variables:
diff --git a/doc/user/project/merge_requests/commits.md b/doc/user/project/merge_requests/commits.md
index ddd2a0ddcb5..502dfd7acab 100644
--- a/doc/user/project/merge_requests/commits.md
+++ b/doc/user/project/merge_requests/commits.md
@@ -18,7 +18,7 @@ From this tab, you can review commit messages and copy a commit's SHA when you n
To see the commits included in a merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**, then select your merge request.
1. To show a list of the commits in the merge request, newest first, select **Commits** .
To read more about the commit, select **Toggle commit description** (**{ellipsis_h}**)
@@ -48,7 +48,7 @@ if another merge request:
To add previously merged commits to a merge request for more context:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**, then select your merge request.
1. Select **Commits**.
1. Scroll to the end of the list of commits, and select **Add previously merged commits**.
@@ -63,7 +63,7 @@ force push.
To add discussion to a specific commit:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Commits**.
1. Below the commits, in the **Comment** field, enter a comment.
1. Save your comment as either a standalone comment, or a thread:
@@ -74,7 +74,7 @@ To add discussion to a specific commit:
To view the changes between previously merged commits:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**, then select your merge request.
1. Select **Changes**.
1. By **Compare** (**{file-tree}**), select the commits to compare:
diff --git a/doc/user/project/merge_requests/conflicts.md b/doc/user/project/merge_requests/conflicts.md
index fefc6aabddf..e132ddfb729 100644
--- a/doc/user/project/merge_requests/conflicts.md
+++ b/doc/user/project/merge_requests/conflicts.md
@@ -59,7 +59,7 @@ in the user interface, and you can also resolve conflicts locally through the co
To resolve less-complex conflicts from the GitLab user interface:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find the merge request.
1. Select **Overview**, and scroll to the merge request reports section.
1. Find the merge conflicts message, and select **Resolve conflicts**.
@@ -84,7 +84,7 @@ Some merge conflicts are more complex, requiring you to manually modify lines to
resolve their conflicts. Use the merge conflict resolution editor to resolve complex
conflicts in the GitLab interface:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find the merge request.
1. Select **Overview**, and scroll to the merge request reports section.
1. Find the merge conflicts message, and select **Resolve conflicts**.
diff --git a/doc/user/project/merge_requests/creating_merge_requests.md b/doc/user/project/merge_requests/creating_merge_requests.md
index e31460c1997..ec269bec84d 100644
--- a/doc/user/project/merge_requests/creating_merge_requests.md
+++ b/doc/user/project/merge_requests/creating_merge_requests.md
@@ -19,7 +19,7 @@ to streamline merge request creation.
You can create a merge request from the list of merge requests.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. In the upper-right corner, select **New merge request**.
1. Select a source and target branch and then **Compare branches and continue**.
@@ -95,7 +95,7 @@ You can create a merge request when you add, edit, or upload a file to a reposit
You can create a merge request when you create a branch.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
1. Type a branch name and select **New branch**.
1. Above the file list, on the right side, select **Create merge request**.
@@ -142,7 +142,7 @@ to reduce the need for editing merge requests manually through the UI.
You can create a merge request from your fork to contribute back to the main project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select your fork of the repository.
1. On the left sidebar, select **Code > Merge requests**, and select **New merge request**.
1. In the **Source branch** dropdown list box, select the branch in your forked repository as the source branch.
@@ -171,7 +171,7 @@ Prerequisites:
To create a merge request by sending an email:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. In the upper-right corner, select **Email a new merge request to this project**.
An email address is displayed. Copy this address.
@@ -216,7 +216,7 @@ scenarios when you create a new merge request:
To have merge requests from a fork by default target your own fork
(instead of the upstream project), you can change the default.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. In the **Target project** section, select the option you want to use for
your default target project.
diff --git a/doc/user/project/merge_requests/csv_export.md b/doc/user/project/merge_requests/csv_export.md
index 15b2e53d7d9..cc7fa050766 100644
--- a/doc/user/project/merge_requests/csv_export.md
+++ b/doc/user/project/merge_requests/csv_export.md
@@ -12,7 +12,7 @@ Export all the data collected from a project's merge requests into a comma-separ
To export merge requests to a CSV file:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. Add any searches or filters. This can help you keep the size of the CSV file under the 15 MB limit. The limit ensures
the file can be emailed to a variety of email providers.
diff --git a/doc/user/project/merge_requests/dependencies.md b/doc/user/project/merge_requests/dependencies.md
index b80698f99c3..e208785fd63 100644
--- a/doc/user/project/merge_requests/dependencies.md
+++ b/doc/user/project/merge_requests/dependencies.md
@@ -57,7 +57,7 @@ information about the dependency:
To view dependency information on a merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and identify your merge request.
1. Scroll to the merge request reports area. Dependent merge requests display information
about the total number of dependencies set, such as
@@ -105,7 +105,7 @@ Prerequisite:
To do this:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and identify your merge request.
1. Select **Edit**.
1. In **Merge request dependencies**, paste either the reference or the full URL
@@ -120,7 +120,7 @@ Prerequisite:
- You must have a role in the project that allows you to edit merge requests.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and identify your merge request.
1. Select **Edit**.
1. Scroll to **Merge request dependencies** and select **Remove** next to the reference
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index 3ad07d0377e..ed762979ff1 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -46,7 +46,7 @@ You can view merge requests for your project, group, or yourself.
To view all merge requests for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
Or, to use a [keyboard shortcut](../../shortcuts.md), press <kbd>g</kbd> + <kbd>m</kbd>.
@@ -55,7 +55,7 @@ Or, to use a [keyboard shortcut](../../shortcuts.md), press <kbd>g</kbd> + <kbd>
To view merge requests for all projects in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Code > Merge requests**.
If your group contains subgroups, this view also displays merge requests from the subgroup projects.
@@ -64,7 +64,7 @@ If your group contains subgroups, this view also displays merge requests from th
To view all merge requests assigned to you:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**).
+1. On the left sidebar, select **Search or go to**.
1. From the dropdown list, select **Merge requests assigned to me**.
or:
@@ -85,16 +85,16 @@ or:
To filter the list of merge requests:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. Above the list of merge requests, select **Search or filter results...**.
1. From the dropdown list, select the attribute you wish to filter by. Some examples:
- [**By environment or deployment date**](#by-environment-or-deployment-date).
- **ID**: Enter filter `#30` to return only merge request 30.
- User filters: Type (or select from the dropdown list) any of these filters to display a list of users:
- - **Approved-By**, for merge requests already approved by a user. **(PREMIUM)**.
+ - **Approved-By**, for merge requests already approved by a user. **(PREMIUM ALL)**.
- **Approver**, for merge requests that this user is eligible to approve.
- (For more information, read about [Code owners](../codeowners/index.md)). **(PREMIUM)**
+ (For more information, read about [Code owners](../codeowners/index.md)). **(PREMIUM ALL)**
- **Reviewer**, for merge requests reviewed by this user.
1. Select or type the operator to use for filtering the attribute. The following operators are
available:
@@ -156,7 +156,7 @@ To assign the merge request to a user, use the `/assign @user`
[quick action](../quick_actions.md#issues-merge-requests-and-epics) in a text area in
a merge request, or:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. On the right sidebar, expand the right sidebar and locate the **Assignees** section.
1. Select **Edit**.
@@ -176,7 +176,7 @@ accountable for it:
To assign multiple assignees to a merge request, use the `/assign @user`
[quick action](../quick_actions.md#issues-merge-requests-and-epics) in a text area, or:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. On the right sidebar, expand the right sidebar and locate the **Assignees** section.
1. Select **Edit** and, from the dropdown list, select all users you want
@@ -312,7 +312,7 @@ On GitLab.com, this feature is enabled for GitLab team members only.
To understand the history of a merge request, filter its activity feed to show you
only the items that are relevant to you.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. Select a merge request.
1. Scroll to **Activity**.
@@ -341,22 +341,7 @@ sort order by clicking the sort button on the right.
> Resolving comments individually was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/28750) in GitLab 13.6.
-In a merge request, you can resolve a thread when you want to finish a conversation.
-
-Prerequisites:
-
-- You must have at least the Developer role
- or be the author of the change being reviewed.
-- Resolvable threads can be added only to merge requests. It doesn't work
- for comments in issues, commits, or snippets.
-
-To resolve a thread:
-
-1. Go to the thread.
-1. Do one of the following:
- - In the upper-right corner of the original comment, select **Resolve thread** (**{check-circle}**).
- - Below the last reply, in the **Reply** field, select **Resolve thread**.
- - Below the last reply, in the **Reply** field, enter text, select the **Resolve thread** checkbox, and select **Add comment now**.
+In a merge request, you can [resolve a thread](../../discussions/index.md#resolve-a-thread) when you want to finish a conversation.
At the top of the page, the number of unresolved threads is updated:
@@ -390,7 +375,7 @@ You can prevent merge requests from being merged until all threads are
resolved. When this setting is enabled, the **Unresolved threads** counter in a merge request
is shown in orange when at least one thread remains unresolved.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. In the **Merge checks** section, select the **All threads must be resolved** checkbox.
1. Select **Save changes**.
@@ -400,7 +385,7 @@ is shown in orange when at least one thread remains unresolved.
You can set merge requests to automatically resolve threads when lines are modified
with a new push.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. In the **Merge options** section, select
**Automatically resolve merge request diff threads when they become outdated**.
diff --git a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
index 16482d92d7e..77dcb269071 100644
--- a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
+++ b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
@@ -39,7 +39,7 @@ To do this when pushing from the command line, use the `merge_request.merge_when
To do this from the GitLab user interface:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. Select the merge request to edit.
1. Scroll to the merge request reports section.
@@ -63,7 +63,7 @@ Prerequisites:
To do this:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. Select the merge request to edit.
1. Scroll to the merge request reports section.
@@ -79,7 +79,7 @@ merge. This configuration works for both:
- GitLab CI/CD pipelines.
- Pipelines run from an [external CI integration](../integrations/index.md#available-integrations).
-As a result, [disabling GitLab CI/CD pipelines](../../../ci/enable_or_disable_ci.md)
+As a result, [disabling GitLab CI/CD pipelines](../../../ci/enable_or_disable_ci.md#disable-cicd-in-a-project)
does not disable this feature, but you can use pipelines from external
CI providers with it.
@@ -90,7 +90,7 @@ Prerequisites:
To enable this setting:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Scroll to **Merge checks**, and select **Pipelines must succeed**.
This setting also prevents merge requests from being merged if there is no pipeline,
@@ -111,7 +111,7 @@ Prerequisite:
To change this behavior:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Under **Merge checks**:
- Select **Pipelines must succeed**.
diff --git a/doc/user/project/merge_requests/methods/index.md b/doc/user/project/merge_requests/methods/index.md
index 7eac0e8839a..959ada4928e 100644
--- a/doc/user/project/merge_requests/methods/index.md
+++ b/doc/user/project/merge_requests/methods/index.md
@@ -26,7 +26,7 @@ gitGraph
## Configure a project's merge method
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Select your desired **Merge method** from these options:
- Merge commit
diff --git a/doc/user/project/merge_requests/revert_changes.md b/doc/user/project/merge_requests/revert_changes.md
index 14e2ff84eae..7e6bf606f10 100644
--- a/doc/user/project/merge_requests/revert_changes.md
+++ b/doc/user/project/merge_requests/revert_changes.md
@@ -30,7 +30,7 @@ Prerequisites:
To do this:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and identify your merge request.
1. Scroll to the merge request reports area, and find the report showing when the
merge request was merged.
@@ -55,7 +55,7 @@ Prerequisites:
To do this:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. If you know the merge request that contains the commit:
1. Select **Code > Merge requests**, then identify and select your merge request.
1. Select **Commits**, then select the title of the commit you want to revert. This displays the commit in the **Changes** tab of your merge request.
diff --git a/doc/user/project/merge_requests/reviews/img/suggested_reviewers_v15_9.png b/doc/user/project/merge_requests/reviews/img/suggested_reviewers_v15_9.png
deleted file mode 100644
index 70db0d79eaf..00000000000
--- a/doc/user/project/merge_requests/reviews/img/suggested_reviewers_v15_9.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/reviews/img/suggested_reviewers_v16_3.png b/doc/user/project/merge_requests/reviews/img/suggested_reviewers_v16_3.png
new file mode 100644
index 00000000000..9c3ecebd395
--- /dev/null
+++ b/doc/user/project/merge_requests/reviews/img/suggested_reviewers_v16_3.png
Binary files differ
diff --git a/doc/user/project/merge_requests/reviews/index.md b/doc/user/project/merge_requests/reviews/index.md
index e4882134654..c09071e856c 100644
--- a/doc/user/project/merge_requests/reviews/index.md
+++ b/doc/user/project/merge_requests/reviews/index.md
@@ -10,7 +10,7 @@ type: index, reference
[Merge requests](../index.md) are the primary method of making changes to files in a
GitLab project. [Create and submit a merge request](../creating_merge_requests.md)
to propose changes. Your team leaves [comments](../../../discussions/index.md) on
-your merge request, and makes [code suggestions](suggestions.md) you can accept
+your merge request, and makes [Code Suggestions](suggestions.md) you can accept
from the user interface. When your work is reviewed, your team members can choose
to accept or reject it.
@@ -21,17 +21,24 @@ review merge requests in Visual Studio Code.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Merge request review](https://www.youtube.com/watch?v=2MayfXKpU08&list=PLFGfElNsQthYDx0A_FaNNfUm9NHsK6zED&index=183).
-## Suggested reviewers **(ULTIMATE SAAS)**
+## GitLab Duo Suggested Reviewers **(ULTIMATE SAAS)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/modelops/applied-ml/review-recommender/-/epics/3) in GitLab 15.4 as a [Beta](../../../../policy/experiment-beta-support.md#beta) feature [with a flag](../../../../administration/feature_flags.md) named `suggested_reviewers_control`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/368356) in GitLab 15.6.
> - Beta designation [removed from the UI](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113058) in GitLab 15.10.
-GitLab can suggest reviewers. Using the changes in a merge request and a project's contribution graph, machine learning suggestions appear in the reviewer section of the right sidebar.
+GitLab uses machine learning to suggest reviewers for your merge request.
-![Suggested Reviewers](img/suggested_reviewers_v15_9.png)
+To suggest reviewers, GitLab uses:
-For more information, see [Data usage in Suggested Reviewers](data_usage.md).
+- The changes in the merge request
+- The project's contribution graph
+
+GitLab Duo Suggested Reviewers also integrates with Code Owners, profile status, and merge request rules, helping you make a more informed decision when choosing reviewers that can meet your review criteria.
+
+![GitLab Duo Suggested Reviewers](img/suggested_reviewers_v16_3.png)
+
+For more information, see [Data usage in GitLab Duo Suggested Reviewers](data_usage.md).
### Enable suggested reviewers
@@ -73,11 +80,40 @@ If you [approve a merge request](../approvals/index.md#approve-a-merge-request)
are shown in the reviewer list, a green check mark **{check-circle-filled}**
displays next to your name.
+### Request a review
+
+To assign a reviewer to a merge request, in a text area in
+the merge request, use the `/assign_reviewer @user`
+[quick action](../../quick_actions.md#issues-merge-requests-and-epics). Alternatively:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Code > Merge requests** and find your merge request.
+1. On the right sidebar, in the **Reviewers** section, select **Edit**.
+1. Search for the user you want to assign, and select the user.
+
+The merge request is added to the user's review requests.
+
+#### From multiple users **(PREMIUM ALL)**
+
+> Moved to GitLab Premium in 13.9.
+
+To assign multiple reviewers to a merge request, in a text area in
+the merge request, use the `/assign_reviewer @user`
+[quick action](../../quick_actions.md#issues-merge-requests-and-epics). Alternatively:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Code > Merge requests** and find your merge request.
+1. On the right sidebar, in the **Reviewers** section, select **Edit**.
+1. From the dropdown list, select all the users you want
+ to assign to the merge request.
+
+To remove a reviewer, clear the user from the same dropdown list.
+
### Download merge request changes as a diff
To download the changes included in a merge request as a diff:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. Select your merge request.
1. In the upper-right corner, select **Code > Plain diff**.
@@ -100,7 +136,7 @@ curl "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/000000.diff" | git a
To download the changes included in a merge request as a patch file:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests**.
1. Select your merge request.
1. In the upper-right corner, select **Code > Patches**.
diff --git a/doc/user/project/merge_requests/reviews/suggestions.md b/doc/user/project/merge_requests/reviews/suggestions.md
index 4857d58933a..2b046399c4e 100644
--- a/doc/user/project/merge_requests/reviews/suggestions.md
+++ b/doc/user/project/merge_requests/reviews/suggestions.md
@@ -14,7 +14,7 @@ merge request, authored by the user who suggested the changes.
## Create suggestions
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. On the secondary menu, select **Changes**.
1. Find the lines of code you want to change.
@@ -92,7 +92,7 @@ Prerequisites:
To apply suggested changes directly from the merge request:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. Find the comment containing the suggestion you want to apply.
- To apply suggestions individually, select **Apply suggestion**.
@@ -140,7 +140,7 @@ Merge requests created from forks use the template defined in the target project
To meet your project's needs, you can customize these messages and include other
placeholder variables:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Scroll to **Merge suggestions**, and alter the text to meet your needs.
See [Supported variables](#supported-variables) for a list of placeholders
@@ -172,7 +172,7 @@ For example, to customize the commit message to output
To reduce the number of commits added to your branch, you can apply multiple
suggestions in a single commit.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. For each suggestion you want to apply, and select **Add suggestion to batch**.
1. Optional. To remove a suggestion, select **Remove from batch**.
diff --git a/doc/user/project/merge_requests/squash_and_merge.md b/doc/user/project/merge_requests/squash_and_merge.md
index ea999fe039a..a6d55ee44e2 100644
--- a/doc/user/project/merge_requests/squash_and_merge.md
+++ b/doc/user/project/merge_requests/squash_and_merge.md
@@ -71,7 +71,7 @@ Prerequisites:
To configure the default squashing behavior for all merge requests in your project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. In the **Squash commits when merging** section, select your desired behavior:
- **Do not allow**: Squashing is never performed, and the option is not displayed.
diff --git a/doc/user/project/merge_requests/status_checks.md b/doc/user/project/merge_requests/status_checks.md
index e0e65c99433..f87d379b974 100644
--- a/doc/user/project/merge_requests/status_checks.md
+++ b/doc/user/project/merge_requests/status_checks.md
@@ -36,7 +36,7 @@ see [epic 3869](https://gitlab.com/groups/gitlab-org/-/epics/3869).
By default, merge requests in projects can be merged even if external status checks fail. To block the merging of merge requests when external checks fail:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Select the **Status checks must succeed** checkbox.
1. Select **Save changes**.
diff --git a/doc/user/project/milestones/burndown_and_burnup_charts.md b/doc/user/project/milestones/burndown_and_burnup_charts.md
index 7c9a5a37292..65cc9477c49 100644
--- a/doc/user/project/milestones/burndown_and_burnup_charts.md
+++ b/doc/user/project/milestones/burndown_and_burnup_charts.md
@@ -13,7 +13,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## Burndown charts
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6495) to GitLab 11.2 for group milestones.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/6903) [fixed burndown charts](#fixed-burndown-charts) in GitLab 13.6.
> - Moved to GitLab Premium in 13.9.
@@ -32,13 +31,13 @@ For an overview, check the video demonstration on [Mapping work versus time with
To view a project's burndown chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Milestones**.
1. Select a milestone from the list.
To view a group's burndown chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Milestones**.
1. Select a milestone from the list.
@@ -112,13 +111,13 @@ Burnup charts show the assigned and completed work for a milestone.
To view a project's burnup chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Milestones**.
1. Select a milestone from the list.
To view a group's burnup chart:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Plan > Milestones**.
1. Select a milestone from the list.
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index 4bb751aedc5..328e56e2bd8 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -37,7 +37,7 @@ For information about project and group milestones API, see:
To view the milestone list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Milestones**.
In a project, GitLab displays milestones that belong to the project.
@@ -46,7 +46,7 @@ In a group, GitLab displays milestones that belong to the group and all projects
### View milestones in a project with issues turned off
If a project has issue tracking
-[turned off](../settings/index.md#configure-project-visibility-features-and-permissions),
+[turned off](../settings/index.md#configure-project-features-and-permissions),
to get to the milestones page, enter its URL.
To do so:
@@ -66,7 +66,7 @@ You might not see some milestones because they're in projects or groups you're n
To do so:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. On the left sidebar, select **Milestones**.
@@ -121,7 +121,7 @@ Prerequisites:
To create a milestone:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Milestones**.
1. Select **New milestone**.
1. Enter the title.
@@ -140,7 +140,7 @@ Prerequisites:
To edit a milestone:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Milestones**.
1. Select a milestone's title.
1. In the top right corner, select **Milestone actions** (**{ellipsis_v}**) and then select **Edit**.
@@ -157,7 +157,7 @@ Prerequisites:
To edit a milestone:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Milestones**.
1. Select a milestone's title.
1. In the top right corner, select **Milestone actions** (**{ellipsis_v}**) and then select **Delete**.
@@ -183,7 +183,7 @@ Prerequisites:
To promote a project milestone:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Milestones**.
1. Either:
- Select **Promote to Group Milestone** (**{level-up}**) next to the milestone you want to promote.
diff --git a/doc/user/project/ml/experiment_tracking/index.md b/doc/user/project/ml/experiment_tracking/index.md
index d4516746afc..0aad9a69743 100644
--- a/doc/user/project/ml/experiment_tracking/index.md
+++ b/doc/user/project/ml/experiment_tracking/index.md
@@ -70,7 +70,7 @@ on how to use GitLab as a backend for the MLflow Client.
To list the current active experiments, either go to `https/-/ml/experiments` or:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Analyze > Model experiments**.
1. To display all candidates that have been logged, along with their metrics, parameters, and metadata, select an experiment.
1. To display details for a candidate, select **Details**.
diff --git a/doc/user/project/ml/experiment_tracking/mlflow_client.md b/doc/user/project/ml/experiment_tracking/mlflow_client.md
index 3e78cc5b7f2..9cedb5780ed 100644
--- a/doc/user/project/ml/experiment_tracking/mlflow_client.md
+++ b/doc/user/project/ml/experiment_tracking/mlflow_client.md
@@ -24,7 +24,7 @@ Prerequisites:
- A [personal](../../../../user/profile/personal_access_tokens.md), [project](../../../../user/project/settings/project_access_tokens.md), or [group](../../../../user/group/settings/group_access_tokens.md) access token with at least the Developer role and the `api` permission.
- The project ID. To find the project ID:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
To use MLflow client compatibility from a local environment:
@@ -83,6 +83,7 @@ tested. More information can be found in the [MLflow Documentation](https://www.
| `set_experiment` | Yes | 15.11 | |
| `get_run` | Yes | 15.11 | |
| `start_run` | Yes | 15.11 | (16.3) If a name is not provided, the candidate receives a random nickname. |
+| `search_runs` | Yes | 15.11 | (16.4) `experiment_ids` supports only a single experiment ID with order by column or metric. |
| `log_artifact` | Yes with caveat | 15.11 | (15.11) `artifact_path` must be empty. Does not support directories. |
| `log_artifacts` | Yes with caveat | 15.11 | (15.11) `artifact_path` must be empty. Does not support directories. |
| `log_batch` | Yes | 15.11 | |
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
index 8bf4875ba1e..d8e4fce41ef 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
@@ -43,7 +43,7 @@ this document for an [overview on DNS records](dns_concepts.md).
To add your custom domain to GitLab Pages:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. In the upper-right corner, select **New Domain**.
1. In **Domain**, enter the domain name.
@@ -113,7 +113,7 @@ Subdomains (`subdomain.example.com`) require:
Whether it's a user or a project website, the DNS record
should point to your Pages domain (`namespace.gitlab.io`),
-without any `/project-name`.
+without any path.
![DNS `CNAME` record pointing to GitLab.com project](img/dns_cname_record_example.png)
@@ -154,7 +154,7 @@ If you're using Cloudflare, check
After you have added all the DNS records:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. Next to the domain name, select **Edit**.
1. In **Verification status**, select **Retry verification** (**{retry}**).
@@ -246,7 +246,7 @@ meet these requirements.
- To add the certificate at the time you add a new domain:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. In the upper-right corner, select **New Domain**.
1. In **Domain**, enter the domain name.
@@ -255,7 +255,7 @@ meet these requirements.
- To add the certificate to a domain previously added:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. Next to the domain name, select **Edit**.
1. In **Certificate**, turn off the **Automatic certificate management using Let's Encrypt** toggle to add an [SSL/TLS certificate](#adding-an-ssltls-certificate-to-pages).
@@ -283,7 +283,7 @@ domain (as long as you've set a valid certificate for it).
To enable this setting:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. Select the **Force HTTPS (requires valid certificates)** checkbox.
1. Select **Save changes**.
@@ -303,7 +303,7 @@ You can edit a custom domain to:
To edit a custom domain:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Pages**.
1. Next to the domain name, select **Edit**.
@@ -313,7 +313,7 @@ After a custom domain is deleted, the domain is no longer verified in GitLab and
To delete and remove a custom domain:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Deploy > Pages**.
1. Next to the domain name, select **Remove**.
1. When prompted, select **Remove domain**.
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
index 5c1fc41d947..3d9fe4b04e9 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
@@ -42,7 +42,7 @@ For **self-managed** GitLab instances, make sure your administrator has
Once you've met the requirements, enable Let's Encrypt integration:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. Next to the domain name, select **Edit**.
1. Turn on the **Automatic certificate management using Let's Encrypt** toggle.
@@ -69,7 +69,7 @@ associated Pages domain. GitLab also renews it automatically.
If you get an error **Something went wrong while obtaining the Let's Encrypt certificate**, first, make sure that your pages site is set to "Everyone" in your project's **Settings > General > Visibility**. This allows the Let's Encrypt Servers reach your pages site. Once this is confirmed, you can try obtaining the certificate again by following these steps:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. Next to the domain name, select **Edit**.
1. In **Verification status**, select **Retry verification** (**{retry}**).
@@ -84,7 +84,7 @@ If you get an error **Something went wrong while obtaining the Let's Encrypt cer
If you've enabled Let's Encrypt integration, but a certificate is absent after an hour and you see the message, "GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later.", try to remove and add the domain for GitLab Pages again by following these steps:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. Next to the domain name, select **Remove**.
1. [Add the domain again, and verify it](index.md#1-add-a-custom-domain).
diff --git a/doc/user/project/pages/getting_started/pages_ci_cd_template.md b/doc/user/project/pages/getting_started/pages_ci_cd_template.md
index f8ee3f10d1e..90fc1a72eb3 100644
--- a/doc/user/project/pages/getting_started/pages_ci_cd_template.md
+++ b/doc/user/project/pages/getting_started/pages_ci_cd_template.md
@@ -16,7 +16,7 @@ Use a `.gitlab-ci.yml` template when you have an existing project that you want
Your GitLab repository should contain files specific to an SSG, or plain HTML. After you complete
these steps, you may have to do additional configuration for the Pages site to generate properly.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. From the **Add** (**{plus}**) dropdown list, select **New file**.
1. From the **Select a template type** dropdown list, select `.gitlab-ci.yml`.
1. From the **Apply a template** dropdown list, in the **Pages** section, select the name of your SSG.
diff --git a/doc/user/project/pages/getting_started/pages_ui.md b/doc/user/project/pages/getting_started/pages_ui.md
index ab3c12427b3..8fa927bd61c 100644
--- a/doc/user/project/pages/getting_started/pages_ui.md
+++ b/doc/user/project/pages/getting_started/pages_ui.md
@@ -33,7 +33,7 @@ a pipeline deploys your Pages website.
To complete the setup and generate a GitLab Pages deployment:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
A **Get Started with Pages** form appears. If this form is not available,
diff --git a/doc/user/project/pages/getting_started_part_one.md b/doc/user/project/pages/getting_started_part_one.md
index e44a7bf347f..ec511ee0a5f 100644
--- a/doc/user/project/pages/getting_started_part_one.md
+++ b/doc/user/project/pages/getting_started_part_one.md
@@ -25,13 +25,13 @@ For GitLab self-managed instances, replace `example.io`
with your instance's Pages domain. For GitLab.com,
Pages domains are `*.gitlab.io`.
-| Type of GitLab Pages | The name of the project created in GitLab | Website URL |
+| Type of GitLab Pages | Example path of a project in GitLab | Website URL |
| -------------------- | ------------ | ----------- |
-| User pages | `username.example.io` | `http(s)://username.example.io` |
-| Group pages | `groupname.example.io` | `http(s)://groupname.example.io` |
-| Project pages owned by a user | `projectname` | `http(s)://username.example.io/projectname` |
-| Project pages owned by a group | `projectname` | `http(s)://groupname.example.io/projectname`|
-| Project pages owned by a subgroup | `subgroup/projectname` | `http(s)://groupname.example.io/subgroup/projectname`|
+| User pages | `username/username.example.io` | `http(s)://username.example.io` |
+| Group pages | `acmecorp/acmecorp.example.io` | `http(s)://acmecorp.example.io` |
+| Project pages owned by a user | `username/my-website` | `http(s)://username.example.io/my-website` |
+| Project pages owned by a group | `acmecorp/webshop` | `http(s)://acmecorp.example.io/webshop`|
+| Project pages owned by a subgroup | `acmecorp/documentation/product-manual` | `http(s)://acmecorp.example.io/documentation/product-manual`|
WARNING:
There are some known [limitations](introduction.md#subdomains-of-subdomains)
@@ -72,7 +72,7 @@ To understand Pages domains clearly, read the examples below.
**General example:**
- On GitLab.com, a project site is always available under
- `https://namespace.gitlab.io/project-name`
+ `https://namespace.gitlab.io/project-slug`
- On GitLab.com, a user or group website is available under
`https://namespace.gitlab.io/`
- On your GitLab instance, replace `gitlab.io` above with your
@@ -86,7 +86,7 @@ The `baseurl` option might be named differently in some static site generators.
Every Static Site Generator (SSG) default configuration expects
to find your website under a (sub)domain (`example.com`), not
in a subdirectory of that domain (`example.com/subdir`). Therefore,
-whenever you publish a project website (`namespace.gitlab.io/project-name`),
+whenever you publish a project website (for example, `namespace.gitlab.io/project-slug`),
you must look for this configuration (base URL) on your static site generator's
documentation and set it up to reflect this pattern.
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index 4585ee2cecd..664c80e0351 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -47,9 +47,9 @@ depending on your static generator configuration.
If the case of `404.html`, there are different scenarios. For example:
-- If you use project Pages (served under `/projectname/`) and try to access
- `/projectname/non/existing_file`, GitLab Pages tries to serve first
- `/projectname/404.html`, and then `/404.html`.
+- If you use project Pages (served under `/project-slug/`) and try to access
+ `/project-slug/non/existing_file`, GitLab Pages tries to serve first
+ `/project-slug/404.html`, and then `/404.html`.
- If you use user or group Pages (served under `/`) and try to access
`/non/existing_file` GitLab Pages tries to serve `/404.html`.
- If you use a custom domain and try to access `/non/existing_file`, GitLab
@@ -64,7 +64,7 @@ You can configure redirects for your site using a `_redirects` file. For more in
To remove your pages:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. Select **Remove pages**.
@@ -87,7 +87,7 @@ For [group websites](../../project/pages/getting_started_part_one.md#user-and-gr
the group must be at the top level and not a subgroup.
For [project websites](../../project/pages/getting_started_part_one.md#project-website-examples),
-you can create your project first and access it under `http(s)://namespace.example.io/projectname`.
+you can create your project first and access it under `http(s)://namespace.example.io/project-path`.
## Enable unique domains
@@ -99,7 +99,7 @@ By default, every project in a group shares the same domain, for example, `group
To ensure your project uses a unique Pages domain, enable the unique domains feature for the project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Pages**.
1. Select the **Use unique domain** checkbox.
1. Select **Save changes**.
@@ -308,7 +308,7 @@ For a list of known issues, see the GitLab [public issue tracker](https://gitlab
This problem most likely results from a missing `index.html` file in the public directory. If after deploying a Pages site
a 404 is encountered, confirm that the public directory contains an `index.html` file. If the file contains a different name
-such as `test.html`, the Pages site can still be accessed, but the full path would be needed. For example: `https//group-name.pages.example.com/project-name/test.html`.
+such as `test.html`, the Pages site can still be accessed, but the full path would be needed. For example: `https//group-name.pages.example.com/project-slug/test.html`.
The contents of the public directory can be confirmed by [browsing the artifacts](../../../ci/jobs/job_artifacts.md#download-job-artifacts) from the latest pipeline.
diff --git a/doc/user/project/pages/redirects.md b/doc/user/project/pages/redirects.md
index 5f1f5bc59ae..ff1f138e5b7 100644
--- a/doc/user/project/pages/redirects.md
+++ b/doc/user/project/pages/redirects.md
@@ -47,14 +47,14 @@ To create redirects, create a configuration file named `_redirects` in the
configured at the instance level. Only the first matching rules within the configured maximum are processed.
The default file size limit is 64 KB, and the default maximum number of rules is 1,000.
- If your GitLab Pages site uses the default domain name (such as
- `namespace.gitlab.io/projectname`) you must prefix every rule with the project name:
+ `namespace.gitlab.io/project-slug`) you must prefix every rule with the path:
```plaintext
- /projectname/wardrobe.html /projectname/narnia.html 302
+ /project-slug/wardrobe.html /project-slug/narnia.html 302
```
- If your GitLab Pages site uses [custom domains](custom_domains_ssl_tls_certification/index.md),
- no project name prefix is needed. For example, if your custom domain is `example.com`,
+ no project path prefix is needed. For example, if your custom domain is `example.com`,
your `_redirects` file would look like:
```plaintext
@@ -69,7 +69,7 @@ the file instead of your redirect. For example, if the files `hello.html` and
is ignored because `hello.html` exists:
```plaintext
-/projectname/hello.html /projectname/world.html 302
+/project-slug/hello.html /project-slug/world.html 302
```
GitLab does not support Netlify
@@ -210,8 +210,7 @@ would **not** match a request URL like `/old/file`:
## Debug redirect rules
If a redirect isn't working as expected, or you want to check your redirect syntax, visit
-`https://[namespace.gitlab.io]/projectname/_redirects`, replacing `[namespace.gitlab.io]` with
-your domain name. The `_redirects` file isn't served directly, but your browser
+`[your pages url]/_redirects`. The `_redirects` file isn't served directly, but your browser
displays a numbered list of your redirect rules, and whether the rule is valid or invalid:
```plaintext
diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md
index 505f1a530cd..fac07a1313a 100644
--- a/doc/user/project/protected_branches.md
+++ b/doc/user/project/protected_branches.md
@@ -95,7 +95,7 @@ Prerequisites:
To protect a branch:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -133,7 +133,7 @@ Prerequisite:
To protect a branch for all the projects in a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -157,7 +157,7 @@ Prerequisite:
To protect multiple branches at the same time:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -193,7 +193,7 @@ from the command line or from a Git client application.
To create a new branch through the user interface:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
1. Select **New branch**.
1. Fill in the branch name and select an existing branch, tag, or commit to
@@ -205,7 +205,7 @@ To create a new branch through the user interface:
You can force everyone to submit a merge request, rather than allowing them to
check in directly to a protected branch:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -218,7 +218,7 @@ check in directly to a protected branch:
You can allow everyone with write access to push to the protected branch.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -247,7 +247,7 @@ Prerequisites:
To allow a deploy key to push to a protected branch:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -267,7 +267,7 @@ protected branches.
To protect a new branch and enable force push:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -280,7 +280,7 @@ To protect a new branch and enable force push:
To enable force pushes on branches that are already protected:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -322,7 +322,7 @@ the applicable rules have **Required approval from code owners** enabled.
To protect a new branch and enable Code Owner's approval:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -333,7 +333,7 @@ To protect a new branch and enable Code Owner's approval:
To enable Code Owner's approval on branches that are already protected:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected branches**.
1. Select **Add protected branch**.
@@ -366,7 +366,7 @@ for details about the pipelines security model.
Users with at least the Maintainer role can manually delete protected
branches by using the GitLab web interface:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
1. Next to the branch you want to delete, select **Delete** (**{remove}**).
1. On the confirmation dialog, enter the branch name and select **Yes, delete protected branch**.
diff --git a/doc/user/project/protected_tags.md b/doc/user/project/protected_tags.md
index 8686d02271c..b312acd49f4 100644
--- a/doc/user/project/protected_tags.md
+++ b/doc/user/project/protected_tags.md
@@ -31,7 +31,7 @@ Prerequisites:
- You must have at least the Maintainer role for the project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected tags**.
1. Select **Add new**.
@@ -77,7 +77,9 @@ all matching tags:
A tag and a branch with identical names can contain different commits. If your
tags and branches use the same names, users running `git checkout`
commands might check out the _tag_ `qa` when they instead meant to check out
-the _branch_ `qa`.
+the _branch_ `qa`. As an added security measure, avoid creating tags with the
+same name as branches. Confusing the two could lead to potential
+security or operational issues.
To prevent this problem:
@@ -111,7 +113,7 @@ Prerequisites:
To allow a deploy key to create a protected tag:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Protected tags**.
1. From the **Tag** dropdown list, select the tag you want to protect.
@@ -129,7 +131,7 @@ Prerequisite:
To do this:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Tags**.
1. Next to the tag you want to delete, select **Delete** (**{remove}**).
1. On the confirmation dialog, enter the tag name and select **Yes, delete protected tag**.
diff --git a/doc/user/project/push_options.md b/doc/user/project/push_options.md
index d0a938e054d..e8451e3049d 100644
--- a/doc/user/project/push_options.md
+++ b/doc/user/project/push_options.md
@@ -6,119 +6,97 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Push options **(FREE ALL)**
-GitLab supports using client-side [Git push options](https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt)
-to perform various actions at the same time as pushing changes. Additionally, [Push Rules](repository/push_rules.md) offer server-side control and enforcement options.
+When you push changes to a branch, you can use client-side
+[Git push options](https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt).
+In Git 2.10 and later, use Git push options to:
-Currently, there are push options available for:
+- [Skip CI jobs](#push-options-for-gitlab-cicd)
+- [Push to merge requests](#push-options-for-merge-requests)
-- [Skipping CI jobs](#push-options-for-gitlab-cicd)
-- [Merge requests](#push-options-for-merge-requests)
-
-NOTE:
-Git push options are only available with Git 2.10 or newer.
-
-For Git versions 2.10 to 2.17 use `--push-option`:
+In Git 2.18 and later, you can use either the long format (`--push-option`) or the shorter `-o`:
```shell
-git push --push-option=<push_option>
+git push -o <push_option>
```
-For version 2.18 and later, you can use the above format, or the shorter `-o`:
+In Git 2.10 to 2.17, you must use the long format:
```shell
-git push -o <push_option>
+git push --push-option=<push_option>
```
+For server-side controls and enforcement of best practices, see
+[push rules](repository/push_rules.md) and [server hooks](../../administration/server_hooks.md).
+
## Push options for GitLab CI/CD
You can use push options to skip a CI/CD pipeline, or pass CI/CD variables.
-| Push option | Description | Introduced in version |
-| ------------------------------ | ------------------------------------------------------------------------------------------- |---------------------- |
-| `ci.skip` | Do not create a CI pipeline for the latest push. Only skips branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). This does not skip pipelines for CI integrations, such as Jenkins. | [11.7](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/15643) |
-| `ci.variable="<name>=<value>"` | Provide [CI/CD variables](../../ci/variables/index.md) to be used in a CI pipeline, if one is created due to the push. Only passes variables to branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). | [12.6](https://gitlab.com/gitlab-org/gitlab/-/issues/27983) |
-| `integrations.skip_ci` | Skip push events for CI integrations, such as Atlassian Bamboo, Buildkite, Drone, Jenkins, and JetBrains TeamCity. | [16.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123837) |
+| Push option | Description | Example |
+|--------------------------------|-------------|---------|
+| `ci.skip` | Do not create a CI/CD pipeline for the latest push. Skips only branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). This does not skip pipelines for CI/CD integrations, such as Jenkins. | `git push -o ci.skip` |
+| `ci.variable="<name>=<value>"` | Provide [CI/CD variables](../../ci/variables/index.md) to the CI/CD pipeline, if one is created due to the push. Passes variables only to branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). | `git push -o ci.variable="MAX_RETRIES=10" -o ci.variable="MAX_TIME=600"` |
+| `integrations.skip_ci` | Skip push events for CI/CD integrations, such as Atlassian Bamboo, Buildkite, Drone, Jenkins, and JetBrains TeamCity. Introduced in [GitLab 16.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123837). | `git push -o integrations.skip_ci` |
-An example of using `ci.skip`:
-
-```shell
-git push -o ci.skip
-```
-
-An example of passing some CI/CD variables for a pipeline:
-
-```shell
-git push -o ci.variable="MAX_RETRIES=10" -o ci.variable="MAX_TIME=600"
-```
+## Push options for merge requests
-An example of using `integrations.skip_ci`:
+Git push options can perform actions for merge requests while pushing changes:
-```shell
-git push -o integrations.skip_ci
-```
+| Push option | Description |
+|----------------------------------------------|-------------|
+| `merge_request.create` | Create a new merge request for the pushed branch. |
+| `merge_request.target=<branch_name>` | Set the target of the merge request to a particular branch or upstream project, such as: `git push -o merge_request.target=project_path/branch`. |
+| `merge_request.merge_when_pipeline_succeeds` | Set the merge request to [merge when its pipeline succeeds](merge_requests/merge_when_pipeline_succeeds.md). |
+| `merge_request.remove_source_branch` | Set the merge request to remove the source branch when it's merged. |
+| `merge_request.title="<title>"` | Set the title of the merge request. For example: `git push -o merge_request.title="The title I want"`. |
+| `merge_request.description="<description>"` | Set the description of the merge request. For example: `git push -o merge_request.description="The description I want"`. |
+| `merge_request.draft` | Mark the merge request as a draft. For example: `git push -o merge_request.draft`. Introduced in [GitLab 15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/296673). |
+| `merge_request.milestone="<milestone>"` | Set the milestone of the merge request. For example: `git push -o merge_request.milestone="3.0"`. Introduced in [GitLab 14.1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63960). |
+| `merge_request.label="<label>"` | Add labels to the merge request. If the label does not exist, it is created. For example, for two labels: `git push -o merge_request.label="label1" -o merge_request.label="label2"`. |
+| `merge_request.unlabel="<label>"` | Remove labels from the merge request. For example, for two labels: `git push -o merge_request.unlabel="label1" -o merge_request.unlabel="label2"`. |
+| `merge_request.assign="<user>"` | Assign users to the merge request. Accepts username or user ID. For example, for two users: `git push -o merge_request.assign="user1" -o merge_request.assign="user2"`. Support for usernames added in [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/344276). |
+| `merge_request.unassign="<user>"` | Remove assigned users from the merge request. Accepts username or user ID. For example, for two users: `git push -o merge_request.unassign="user1" -o merge_request.unassign="user2"`. Support for usernames added in [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/344276). |
-## Push options for merge requests
+## Formats for push options
-You can use Git push options to perform certain actions for merge requests at the same
-time as pushing changes:
-
-| Push option | Description | Introduced in version |
-| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------- |
-| `merge_request.create` | Create a new merge request for the pushed branch. | [11.10](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26752) |
-| `merge_request.target=<branch_name>` | Set the target of the merge request to a particular branch or upstream project, such as: `git push -o merge_request.target=project_path/branch` | [11.10](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26752) |
-| `merge_request.merge_when_pipeline_succeeds` | Set the merge request to [merge when its pipeline succeeds](merge_requests/merge_when_pipeline_succeeds.md). | [11.10](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26752) |
-| `merge_request.remove_source_branch` | Set the merge request to remove the source branch when it's merged. | [12.2](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/64320) |
-| `merge_request.title="<title>"` | Set the title of the merge request. For example: `git push -o merge_request.title="The title I want"`. | [12.2](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/64320) |
-| `merge_request.description="<description>"` | Set the description of the merge request. For example: `git push -o merge_request.description="The description I want"`. | [12.2](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/64320) |
-| `merge_request.draft` | Mark the merge request as a draft. For example: `git push -o merge_request.draft`. | [15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/296673) |
-| `merge_request.milestone="<milestone>"` | Set the milestone of the merge request. For example: `git push -o merge_request.milestone="3.0"`. | [14.1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63960) |
-| `merge_request.label="<label>"` | Add labels to the merge request. If the label does not exist, it is created. For example, for two labels: `git push -o merge_request.label="label1" -o merge_request.label="label2"`. | [12.3](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31831) |
-| `merge_request.unlabel="<label>"` | Remove labels from the merge request. For example, for two labels: `git push -o merge_request.unlabel="label1" -o merge_request.unlabel="label2"`. | [12.3](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31831) |
-| `merge_request.assign="<user>"` | Assign users to the merge request. Accepts username or user ID. For example, for two users: `git push -o merge_request.assign="user1" -o merge_request.assign="user2"`. | [13.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25904), support for usernames added in [15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/344276) |
-| `merge_request.unassign="<user>"` | Remove assigned users from the merge request. Accepts username or user ID.For example, for two users: `git push -o merge_request.unassign="user1" -o merge_request.unassign="user2"`. | [13.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25904), support for usernames added in [15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/344276) |
-
-If you use a push option that requires text with spaces in it, you need to enclose it
-in quotes (`"`). You can omit the quotes if there are no spaces. Some examples:
+If your push option requires text containing spaces, enclose the text in
+double quotes (`"`). You can omit the quotes if there are no spaces. Some examples:
```shell
git push -o merge_request.label="Label with spaces"
git push -o merge_request.label=Label-with-no-spaces
```
-You can combine push options to accomplish multiple tasks at once, by using
-multiple `-o` (or `--push-option`) flags. For example, if you want to create a new
-merge request, and target a branch named `my-target-branch`:
+To combine push options to accomplish multiple tasks at once, use
+multiple `-o` (or `--push-option`) flags. This command creates a
+new merge request, targets a branch (`my-target-branch`), and sets auto-merge:
```shell
-git push -o merge_request.create -o merge_request.target=my-target-branch
+git push -o merge_request.create -o merge_request.target=my-target-branch -o merge_request.merge_when_pipeline_succeeds
```
-Additionally if you want the merge request to merge as soon as the pipeline succeeds you can do:
+## Create Git aliases for common commands
-```shell
-git push -o merge_request.create -o merge_request.target=my-target-branch -o merge_request.merge_when_pipeline_succeeds
-```
+Adding push options to Git commands can create very long commands. If
+you use the same push options frequently, create Git aliases for them.
+Git aliases are command-line shortcuts for longer Git commands.
-## Useful Git aliases
+To create and use a Git alias for the
+[merge when pipeline succeeds Git push option](#push-options-for-merge-requests):
-As shown above, Git push options can cause Git commands to grow very long. If
-you use the same push options frequently, it's useful to create
-[Git aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases). Git aliases
-are command line shortcuts for Git which can significantly simplify the use of
-long Git commands.
+1. In your terminal window, run this command:
-### Merge when pipeline succeeds alias
+ ```shell
+ git config --global alias.mwps "push -o merge_request.create -o merge_request.target=main -o merge_request.merge_when_pipeline_succeeds"
+ ```
-To set up a Git alias for the
-[merge when pipeline succeeds Git push option](#push-options-for-merge-requests):
+1. To use the alias to push a local branch that targets the default branch (`main`)
+ and auto-merges, run this command:
-```shell
-git config --global alias.mwps "push -o merge_request.create -o merge_request.target=master -o merge_request.merge_when_pipeline_succeeds"
-```
+ ```shell
+ git mwps origin <local-branch-name>
+ ```
-Then to quickly push a local branch that targets the default branch and merges when the
-pipeline succeeds:
+## Related topics
-```shell
-git mwps origin <local-branch-name>
-```
+- [Git aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases) in the Git documentation
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index aee052631fc..097c726d163 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -146,10 +146,13 @@ To auto-format this table, use the VS Code Markdown Table formatter: `https://do
|:--------------------------------------------------------------|:-----------------------|:-----------------------|:-----------------------|:-------|
| `/assign @user1 @user2` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Assign one or more users. |
| `/assign me` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Assign yourself. |
+| `/award :emoji:` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Toggle an emoji reaction. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/412275) in GitLab 16.5 |
| `/cc @user` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mention a user. In GitLab 15.0 and later, this command performs no action. You can instead type `CC @user` or only `@user`. [In GitLab 14.9 and earlier](https://gitlab.com/gitlab-org/gitlab/-/issues/31200), mentioning a user at the start of a line creates a specific type of to-do item notification. |
+| `/checkin_reminder` | **{dotted-circle}** No| **{check-circle}** Yes | **{dotted-circle}** No | Set checkin reminder cadence. Options are `weekly`, `twice-monthly`, `monthly`, `never`. This action is behind a feature flag. |
| `/clear_health_status` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Clear [health status](issues/managing_issues.md#health-status). |
| `/clear_weight` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Clear weight. |
| `/close` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Close. |
+| `/confidential` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mark work item as confidential. [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/412276) in GitLab 16.4. |
| `/done` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mark to-do item as done. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/412277) in GitLab 16.2. |
| `/due <date>` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes | Set due date. Examples of valid `<date>` include `in 2 days`, `this Friday` and `December 31st`. |
| `/health_status <value>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Set [health status](issues/managing_issues.md#health-status). Valid options for `<value>` are `on_track`, `needs_attention`, or `at_risk`. |
@@ -160,6 +163,7 @@ To auto-format this table, use the VS Code Markdown Table formatter: `https://do
| `/remove_due_date` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes | Remove due date. |
| `/reopen` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Reopen. |
| `/shrug <comment>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Append the comment with `¯\_(ツ)_/¯`. |
+| `/subscribe` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Subscribe to notifications. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/420796) in GitLab 16.4 |
| `/tableflip <comment>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Append the comment with `(╯°□°)╯︵ â”»â”â”»`. |
| `/title <new title>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Change title. |
| `/todo` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Add a to-do item. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/412277) in GitLab 16.2. |
@@ -168,6 +172,7 @@ To auto-format this table, use the VS Code Markdown Table formatter: `https://do
| `/unassign` | **{dotted-circle}** No | **{check-circle}** Yes | **{check-circle}** Yes | Remove all assignees. |
| `/unlabel ~label1 ~label2` or `/remove_label ~label1 ~label2` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Remove specified labels. |
| `/unlabel` or `/remove_label` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Remove all labels. |
+| `/unsubscribe` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Unsubscribe to notifications. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/420796) in GitLab 16.4 |
| `/weight <value>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set weight. Valid options for `<value>` include `0`, `1`, and `2`. |
## Commit messages
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
index 8e65514cd1d..17ea0e3f694 100644
--- a/doc/user/project/releases/index.md
+++ b/doc/user/project/releases/index.md
@@ -74,7 +74,7 @@ Prerequisites:
To create a release in the Releases page:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Releases** and select **New release**.
1. From the [**Tag name**](release_fields.md#tag-name) dropdown list, either:
- Select an existing Git tag. Selecting an existing tag that is already associated with a release
@@ -215,7 +215,7 @@ To delete a release, use either the
In the UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Deploy > Releases**.
1. In the upper-right corner of the release you want to delete, select **Edit this release**
(**{pencil}**).
@@ -287,22 +287,40 @@ are defined as [crontab](https://crontab.guru/) entries.
If the job that's executing is in a freeze period, GitLab CI/CD creates an environment
variable named `$CI_DEPLOY_FREEZE`.
-To prevent the deployment job from executing, create a `rules` entry in your
-`.gitlab-ci.yml`, for example:
+To prevent the deployment job from executing in multiple projects in a group,
+define the `.freezedeployment` job in a file shared across the group.
+Use the [`includes`](../../../ci/yaml/includes.md) keyword to incorporate the
+template in your project's `.gitlab-ci.yml` file:
```yaml
-deploy_to_production:
+.freezedeployment:
stage: deploy
- script: deploy_to_prod.sh
+ before_script:
+ - '[[ ! -z "$CI_DEPLOY_FREEZE" ]] && echo "INFRASTRUCTURE OUTAGE WINDOW" && exit 1; '
rules:
- - if: $CI_DEPLOY_FREEZE == null
+ - if: '$CI_DEPLOY_FREEZE'
+ when: manual
+ allow_failure: true
+ - when: on_success
+```
+
+To prevent the deployment job from executing, use the [`extends`](../../../ci/yaml/index.md#extends) keyword in the `deploy_to_production` job of your `.gitlab-ci.yml` file to inherit the configuration from the `.freezedeployment` template job:
+
+```yaml
+deploy_to_production:
+ extends: .freezedeployment
+ script: deploy_to_prod.sh
environment: production
```
+This configuration blocks deployment jobs conditionally and maintains pipeline continuity. When a freeze period is defined, the job fails and the pipeline can proceed without deployment. Manual deployment is possible after the freeze period.
+
+This approach offers deployment control during critical maintenance, and ensures the uninterrupted flow of the CI/CD pipeline.
+
To set a deploy freeze window in the UI, complete these steps:
1. Sign in to GitLab as a user with the Maintainer role.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Settings > CI/CD**.
1. Scroll to **Deploy freezes**.
1. Select **Expand** to see the deploy freeze table.
@@ -342,7 +360,7 @@ Releases can be made accessible to non-project members while keeping repository-
projects that use releases as a way to give access to new versions of software but do not want the source code to
be public.
-To make releases available publicly, set the following [project settings](../settings/index.md#project-feature-settings):
+To make releases available publicly, set the following [project settings](../settings/index.md#configure-project-features-and-permissions):
- Repository is enabled and set to **Only Project Members**
- Releases is enabled and set to **Everyone With Access**
diff --git a/doc/user/project/releases/release_cli.md b/doc/user/project/releases/release_cli.md
index e1de9cbdc1c..9daa6705ad8 100644
--- a/doc/user/project/releases/release_cli.md
+++ b/doc/user/project/releases/release_cli.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab Release CLI tool
-The [GitLab Release CLI (`release-cli`)](https://gitlab.com/gitlab-org/release-cli) tool
+The [GitLab Release CLI (`release-cli`)](https://gitlab.com/gitlab-org/release-cli)
is a command-line tool for managing releases from the command line or from a CI/CD pipeline.
You can use the release CLI to create, update, modify, and delete releases.
diff --git a/doc/user/project/remote_development/connect_machine.md b/doc/user/project/remote_development/connect_machine.md
index ec3d63462f3..6bbc0b8123a 100644
--- a/doc/user/project/remote_development/connect_machine.md
+++ b/doc/user/project/remote_development/connect_machine.md
@@ -4,7 +4,7 @@ group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Tutorial: Connect a remote machine to the Web IDE (Beta) **(FREE ALL)**
+# Tutorial: Connect a remote machine to the Web IDE **(FREE ALL BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95169) in GitLab 15.4 [with a flag](../../../administration/feature_flags.md) named `vscode_web_ide`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/371084) in GitLab 15.7.
diff --git a/doc/user/project/remote_development/index.md b/doc/user/project/remote_development/index.md
index 16110af984a..8ca505be500 100644
--- a/doc/user/project/remote_development/index.md
+++ b/doc/user/project/remote_development/index.md
@@ -4,7 +4,7 @@ group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Remote development (Beta) **(FREE ALL)**
+# Remote development **(FREE ALL BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95169) in GitLab 15.4 [with a flag](../../../administration/feature_flags.md) named `vscode_web_ide`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/371084) in GitLab 15.7.
diff --git a/doc/user/project/repository/branches/default.md b/doc/user/project/repository/branches/default.md
index e123debb724..fdc822ca49f 100644
--- a/doc/user/project/repository/branches/default.md
+++ b/doc/user/project/repository/branches/default.md
@@ -42,7 +42,7 @@ Prerequisites:
To update the default branch for an individual [project](../../index.md):
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Branch defaults**. For **Default branch**, select a new default branch.
1. Optional. Select the **Auto-close referenced issues on default branch** checkbox to close
@@ -68,7 +68,7 @@ GitLab [administrators](../../../permissions.md) of self-managed instances can
customize the initial branch for projects hosted on that instance. Individual
groups and subgroups can override this instance-wide setting for their projects.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Repository**.
1. Expand **Default branch**.
@@ -85,7 +85,7 @@ overrides it.
Users with the Owner role of groups and subgroups can configure the default branch name for a group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Repository**.
1. Expand **Default branch**.
1. For **Initial default branch name**, select a new default branch.
@@ -128,7 +128,7 @@ you must either:
Administrators of self-managed instances can customize the initial default branch protection for projects hosted on that instance. Individual
groups and subgroups can override this instance-wide setting for their projects.
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Repository**.
1. Expand **Default branch**.
@@ -146,7 +146,7 @@ can be overridden on a per-group basis by the group's owner. In
[GitLab Premium or Ultimate](https://about.gitlab.com/pricing/), GitLab administrators can
disable this privilege for group owners, enforcing the instance-level protection rule:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > Repository**.
1. Expand the **Default branch** section.
@@ -167,7 +167,7 @@ can be overridden on a per-group basis by the group's owner. In
[enforce protection of initial default branches](#prevent-overrides-of-default-branch-protection)
which locks this setting for group owners.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > Repository**.
1. Expand **Default branch**.
1. Select [**Initial default branch protection**](#protect-initial-default-branches).
diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md
index f7445ffe950..f33d443cd7f 100644
--- a/doc/user/project/repository/branches/index.md
+++ b/doc/user/project/repository/branches/index.md
@@ -11,7 +11,7 @@ Branches are versions of a project's working tree. When you create a new
cannot be deleted) for your repository. Default branch settings can be configured
at the project, subgroup, group, or instance level.
-As your project grows, your team [creates](../web_editor.md#create-a-branch) more
+As your project grows, your team creates more
branches, preferably by following [branch naming patterns](#prefix-branch-names-with-issue-numbers).
Each branch represents a set of changes, which allows development work to be done
in parallel. Development work in one branch does not affect another branch.
@@ -27,9 +27,13 @@ Branches are the foundation of development in a project:
## Create branch
+Prerequisites:
+
+- You must have at least the Developer role for the project.
+
To create a new branch from the GitLab UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
1. On the top right, select **New branch**.
1. Enter a **Branch name**.
@@ -44,15 +48,15 @@ you can add one.
Prerequisites:
-- You must have at least the Developer role in the project.
-- Unless you have the Maintainer or Owner roles, the
+- You must have at least the Developer role for the project.
+- If you don't have the Maintainer or Owner role, the
[default branch protection](../../../group/manage.md#change-the-default-branch-protection-of-a-group)
must be set to `Partially protected` or `Not protected` for you to push a commit
to the default branch.
To add a [default branch](default.md) to an empty project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Scroll to **The repository for this project is empty** and select the type of
file you want to add.
1. In the Web IDE, make any desired changes to this file, then select **Create commit**.
@@ -64,7 +68,7 @@ GitLab creates a default branch and adds your file to it.
Prerequisites:
-- You must have at least the Developer role in the project.
+- You must have at least the Developer role for the project.
When viewing an issue, you can create an associated branch directly from that page.
Branches created this way use the
@@ -73,11 +77,11 @@ including variables.
Prerequisites:
-- You must have at least the Developer role in the project.
+- You must have at least the Developer role for the project.
To create a branch from an issue:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues** and find your issue.
1. Below the issue description, find the **Create merge request** dropdown list, and select
**{chevron-down}** to display the dropdown list.
@@ -89,7 +93,7 @@ To create a branch from an issue:
## Manage and protect branches
-GitLab provides you multiple methods to protect individual branches. These methods
+GitLab provides multiple methods to protect individual branches. These methods
ensure your branches receive oversight and quality checks from their creation to their deletion:
- The [default branch](default.md) in your project receives extra protection.
@@ -104,19 +108,19 @@ ensure your branches receive oversight and quality checks from their creation to
You can manage your branches:
- With the GitLab user interface.
-- With the [command line](../../../../gitlab-basics/start-using-git.md#create-a-branch).
+- With Git on the [command line](../../../../gitlab-basics/start-using-git.md#create-a-branch).
- With the [Branches API](../../../../api/branches.md).
### View all branches
To view and manage your branches in the GitLab user interface:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
On this page, you can:
-- See all branches, active branches, or stale branches.
+- See all branches, or filter to see only active or stale branches.
- Create new branches.
- [Compare branches](#compare-branches).
- Delete merged branches.
@@ -145,19 +149,19 @@ and their protection methods:
Prerequisites:
-- You must have at least the Maintainer role in the project.
+- You must have at least the Maintainer role for the project.
To view the **Branch rules overview** list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
-1. Expand **Branch Rules** to view all branches with protections.
+1. Expand **Branch rules** to view all branches with protections.
- To add protections to a new branch:
1. Select **Add branch rule**.
1. Select **Create protected branch**.
- To view more information about protections on an existing branch:
1. Identify the branch you want more information about.
- 1. Select **Details** to see information about its:
+ 1. Select **View details** to see information about its:
- [Branch protections](../../protected_branches.md).
- [Approval rules](../../merge_requests/approvals/rules.md).
- [Status checks](../../merge_requests/status_checks.md).
@@ -173,12 +177,17 @@ GitLab enforces these additional rules on all branches:
- No spaces are allowed in branch names.
- Branch names with 40 hexadecimal characters are prohibited, because they are similar to Git commit hashes.
-Common software packages, like Docker, may enforce
+Common software packages, like Docker, can enforce
[additional branch naming restrictions](../../../../administration/packages/container_registry.md#docker-connection-error).
-For best compatibility with other software packages, use only numbers, hyphens (`-`),
-underscores (`_`), and lower-case letters from the ASCII standard table. You
-can use forward slashes (`/`) and emoji in branch names, but compatibility with other
+For the best compatibility with other software packages, use only:
+
+- Numbers
+- Hyphens (`-`)
+- Underscores (`_`)
+- Lowercase letters from the ASCII standard table
+
+You can use forward slashes (`/`) and emoji in branch names, but compatibility with other
software packages cannot be guaranteed.
Branch names with specific formatting offer extra benefits:
@@ -200,7 +209,7 @@ Prerequisites:
To change the default pattern for branches created from issues:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Branch defaults**.
1. Scroll to **Branch name template** and enter a value. The field supports these variables:
@@ -210,8 +219,13 @@ To change the default pattern for branches created from issues:
### Prefix branch names with issue numbers
-To streamline the creation of merge requests, start your branch name with an
-issue number. GitLab uses the issue number to import data into the merge request:
+To streamline the creation of merge requests, start your Git branch name with the
+issue number, followed by a hyphen.
+For example, to link a branch to issue `#123`, start the branch name with `123-`.
+
+The issue and the branch must be in the same project.
+
+GitLab uses the issue number to import data into the merge request:
- The issue is marked as related to the merge request. The issue and merge request
display links to each other.
@@ -224,21 +238,9 @@ issue number. GitLab uses the issue number to import data into the merge request
## Compare branches
-> - Repository filter search box [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52967) in GitLab 13.10.
-> - Revision swapping [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60491) in GitLab 13.12.
-
-The default compare mode uses the `git diff from...to` method, instead of the
-`git diff from to` method, to compare branches. The `git diff from...to` method
-provides a more human-readable diff, because it does not include unrelated changes
-made to the target branch after the source branch was created.
-
-NOTE:
-The `git diff from...to` method shows all changes from a cherry-picked commit as
-new changes. It uses the merge base, not the actual commit content, to compare branches.
-
To compare branches in a repository:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Compare revisions**.
1. Select the **Source** branch to search for your desired branch. Exact matches are
shown first. You can refine your search with operators:
@@ -247,8 +249,23 @@ To compare branches in a repository:
- `*` matches using a wildcard: `branch*cache*` matches `fix/branch-search-cache-expiration`.
- You can combine operators: `^chore/*migration$` matches `chore/user-data-migration`.
1. Select the **Target** repository and branch. Exact matches are shown first.
-1. Select **Compare** to show the list of commits, and changed files. To reverse
- the **Source** and **Target**, select **Swap revisions**.
+1. Below **Show changes**, select the method to compare branches:
+ <!-- vale gitlab.SubstitutionWarning = NO -->
+ <!-- Disable Vale so it doesn't flag "since" -->
+ - **Only incoming changes from source** (default) shows differences from the source branch since
+ the latest common commit on both branches.
+ It doesn't include unrelated changes made to the target branch after the source branch was created.
+ This method uses the `git diff <from>...<to>`
+ [Git command](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt-emgitdiffemltoptionsgtltcommitgtltcommitgt--ltpathgt82308203-1).
+ To compare branches, this method uses the merge base instead of the actual commit, so
+ changes from cherry-picked commits are shown as new changes.
+ - **Include changes to target since source was created** shows all the differences between the two
+ branches.
+ This method uses the `git diff <from> <to>`
+ [Git command](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt-emgitdiffemltoptionsgt--merge-baseltcommitgtltcommitgt--ltpathgt82308203).
+ <!-- vale gitlab.SubstitutionWarning = YES -->
+1. Select **Compare** to show the list of commits, and changed files.
+1. Optional. To reverse the **Source** and **Target**, select **Swap revisions** (**{substitute}**).
## Delete merged branches
@@ -259,15 +276,15 @@ Merged branches can be deleted in bulk if they meet all of these criteria:
Prerequisites:
-- You must have at least the Developer role in the project.
+- You must have at least the Developer role for the project.
To do this:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
1. On the upper right corner of the page, select **More** **{ellipsis_v}**.
1. Select **Delete merged branches**.
-1. In the modal window, enter the word `delete` to confirm, then select **Delete merged branches**.
+1. In the dialog, enter the word `delete` to confirm, then select **Delete merged branches**.
## Related topics
@@ -323,7 +340,7 @@ Error: Could not set the default branch. Do you have a branch named 'HEAD' in yo
To fix this problem:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Branches**.
1. Search for a branch named `HEAD`.
1. Make sure the branch has no uncommitted changes.
diff --git a/doc/user/project/repository/code_suggestions.md b/doc/user/project/repository/code_suggestions.md
deleted file mode 100644
index 6f18aabaa46..00000000000
--- a/doc/user/project/repository/code_suggestions.md
+++ /dev/null
@@ -1,375 +0,0 @@
----
-stage: AI-powered
-group: AI Model Validation
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-type: index, reference
----
-
-# Code Suggestions (Beta) **(FREE ALL)**
-
-> - [Introduced](https://about.gitlab.com/releases/2023/02/22/gitlab-15-9-released/#code-suggestions-available-in-closed-beta) in GitLab 15.9 as [Beta](../../../policy/experiment-beta-support.md#beta) for early access Ultimate customers on GitLab.com.
-> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/408104) as opt-in with GitLab 15.11 as [Beta](../../../policy/experiment-beta-support.md#beta).
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/408158) from GitLab Ultimate to GitLab Premium in 16.0.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/410801) from GitLab Premium to GitLab Free in 16.0.
-> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121079) in GitLab 16.1.
-> - [Introduced support for Google Vertex AI Codey APIs](https://gitlab.com/groups/gitlab-org/-/epics/10562) in GitLab 16.1.
-> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10653) in GitLab 16.1 as [Beta](../../../policy/experiment-beta-support.md#beta) on self-managed GitLab.
-> - Code suggestions in the GitLab WebIDE enabled for all GitLab-hosted customers.
-> - [Removed support for GitLab native model](https://gitlab.com/groups/gitlab-org/-/epics/10752) in GitLab 16.2.
-
-WARNING:
-This feature is in [Beta](../../../policy/experiment-beta-support.md#beta).
-Beta users should read about the [known limitations](#known-limitations). We look forward to hearing your [feedback](#feedback).
-
-Write code more efficiently by using generative AI to suggest code while you're developing.
-
-Code Suggestions are available:
-
-- To users of GitLab SaaS (by default) and self-managed GitLab Enterprise Edition (when requested). Code Suggestions are not available for GitLab Community Edition.
-- In VS Code, Microsoft Visual Studio, JetBrains IDEs, and Neovim. You must have the corresponding GitLab extension installed.
-- In the GitLab WebIDE.
-
-<div class="video-fallback">
- <a href="https://www.youtube.com/watch?v=WnxBYxN2-p4">View an end-to-end demo of Code Suggestions in VS Code</a>.
-</div>
-<figure class="video-container">
- <iframe src="https://www.youtube-nocookie.com/embed/WnxBYxN2-p4" frameborder="0" allowfullscreen> </iframe>
-</figure>
-
-Usage of Code Suggestions is governed by the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
-Learn about [data usage when using Code Suggestions](#code-suggestions-data-usage).
-
-## Supported languages
-
-The best results from Code Suggestions are expected [for languages the Google Vertex AI Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview#supported_coding_languages) directly support:
-
-- C++
-- C#
-- Go
-- Google SQL
-- Java
-- JavaScript
-- Kotlin
-- PHP
-- Python
-- Ruby
-- Rust
-- Scala
-- Swift
-- TypeScript
-
-### Supported code infrastructure interfaces
-
-Code Suggestions includes [Google Vertex AI Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview#supported_code_infrastructure_interfaces) support for the following infrastructure as code interfaces:
-
-- Google Cloud CLI
-- Kubernetes Resource Model (KRM)
-- Terraform
-
-Suggestion quality for other languages and using natural language code comments to request completions may not yet result in high-quality suggestions.
-
-### Supported languages in IDEs
-
-Editor support for languages is documented in the following table.
-
-| Language | VS Code | JetBrains IDEs | Visual Studio | Neovim |
-|---------------------------------|--------------------------------------------------------------|------------------------------|---------------|--------|
-| C++ | ✓ | | ✓ | |
-| C# | ✓ | ✓ | ✓ | |
-| Go | ✓ | ✓ (IDEA Ultimate / GoLand) | | |
-| Google SQL | | | | |
-| Java | ✓ | ✓ | | |
-| JavaScript | ✓ | ✓ | | |
-| Kotlin | ✓ | ✓ | | |
-| PHP | ✓ | ✓ (IDEA Ultimate) | | |
-| Python | ✓ | ✓ | | ✓ |
-| Ruby | ✓ | ✓ (IDEA Ultimate / RubyMine) | | ✓ |
-| Rust | ✓ | ✓ | | |
-| Scala | ✓ | ✓ | | |
-| Swift | ✓ | ✓ | | |
-| TypeScript | ✓ | ✓ | | |
-| Google Cloud CLI | | | | |
-| Kubernetes Resource Model (KRM) | | | | |
-| Terraform | ✓ (Requires 3rd party extension providing Terraform support) | | | |
-
-## Supported editor extensions
-
-Code Suggestions supports a variety of popular editors including:
-
-- VS Code, using [the VS Code GitLab Workflow extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).
-- [GitLab WebIDE (VS Code in the Cloud)](../../project/web_ide/index.md), with no additional configuration.
-- Microsoft Visual Studio, using the [Visual Studio GitLab extension](https://marketplace.visualstudio.com/items?itemName=GitLab.GitLabExtensionForVisualStudio).
-- JetBrains IDEs, using the [GitLab plugin](https://plugins.jetbrains.com/plugin/22325-gitlab).
-- Neovim, using the [`gitlab.vim` plugin](https://gitlab.com/gitlab-org/editor-extensions/gitlab.vim).
-
-A [GitLab Language Server for Code Suggestions](https://gitlab.com/gitlab-org/editor-extensions/gitlab-language-server-for-code-suggestions)
-is also in process.
-This improvement should result in:
-
-- Faster iteration and standardization of the IDE extensions.
-- The ability to use Code Suggestions even when an official editor extension isn't available.
-
-## Enable Code Suggestions on GitLab SaaS **(FREE SAAS)**
-
-Code Suggestions can be enabled [for all members of a group](../../group/manage.md#enable-code-suggestions).
-
-Each individual user must also choose to enable Code Suggestions.
-
-### Enable Code Suggestions for an individual user
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121079) in GitLab 16.1 as [Beta](../../../policy/experiment-beta-support.md#beta).
-
-Each user can enable Code Suggestions for themselves:
-
-1. On the left sidebar, select your avatar.
-1. Select **Preferences**.
-1. In the **Code Suggestions** section, select the **Enable Code Suggestions** checkbox.
-1. Select **Save changes**.
-
-If Code Suggestions is enabled for the group, the group setting overrides the user setting.
-
-NOTE:
-This setting controls Code Suggestions for all IDEs. Support for [more granular control per IDE](https://gitlab.com/groups/gitlab-org/-/epics/10624) is proposed.
-
-## Enable Code Suggestions on self-managed GitLab **(FREE SELF)**
-
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10653) in GitLab 16.1 as [Beta](../../../policy/experiment-beta-support.md#beta).
-
-To enable Code Suggestions on a self-managed GitLab EE instance, you must:
-
-- Be an administrator.
-- Have a [GitLab SaaS account](https://gitlab.com/users/sign_up).
-You do not need to have a GitLab SaaS subscription.
-
-Then, you will:
-
-1. Enable Code Suggestions for your SaaS account.
-1. Enable Code Suggestions for the instance.
-1. [Request early access](#request-access-to-code-suggestions) to the Code Suggestions Beta.
-
-### Enable Code Suggestions for your SaaS account
-
-To enable Code Suggestions for your GitLab SaaS account:
-
-1. Create a [personal access token](../../profile/personal_access_tokens.md#create-a-personal-access-token)
- with the `api` scope.
-1. On the left sidebar, select your avatar.
-1. Select **Preferences**.
-1. In the **Code Suggestions** section, select **Enable Code Suggestions**.
-1. Select **Save changes**.
-
-### Enable Code Suggestions for the instance
-
-You must enable Code Suggestions for the instance. When you do this, you:
-
-- Agree to the [GitLab testing agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
-- Acknowledge that GitLab:
- - Sends data from the instance, including personal data, to GitLab.com infrastructure.
-
-To enable Code Suggestions for your self-managed GitLab instance:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. On the left sidebar, select **Settings > General**.
-1. Expand **Code Suggestions** and:
- - Select **Turn on Code Suggestions for this instance**.
- - In **Personal access token**, enter your GitLab SaaS personal access token.
-1. Select **Save changes**.
-
-This setting is visible only in self-managed GitLab instances.
-
-WARNING:
-If you clear the **Turn on code suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
-
-### Request access to Code Suggestions
-
-GitLab provisions access on a customer-by-customer basis for Code Suggestions
-on self-managed instances. To request access:
-
-1. Sign into your GitLab SaaS account.
-1. Comment on [issue 415393](https://gitlab.com/gitlab-org/gitlab/-/issues/415393)
- and tag your customer success manager.
-
-After GitLab has provisioned access to Code Suggestions for your instance,
-the users in your instance can now enable Code Suggestions.
-
-## Use Code Suggestions
-
-Prerequisites:
-
-- For self-managed GitLab, Code Suggestions must be enabled [for the instance](#enable-code-suggestions-on-self-managed-gitlab).
-- For GitLab SaaS, Code Suggestions must be enabled [for the top-level group](../../group/manage.md#enable-code-suggestions) and [for your user account](#enable-code-suggestions-for-an-individual-user).
-- Install and configure a [supported IDE editor extension](#supported-editor-extensions).
-To use Code Suggestions:
-
-1. Author your code. As you type, suggestions are displayed. Depending on the cursor position, the extension either:
-
- - Provides entire code snippets, like generating functions.
- - Completes the current line.
-
-1. To accept a suggestion, press <kbd>Tab</kbd>.
-
-Suggestions are best when writing new code. Editing existing functions or 'fill in the middle' of a function may not perform as expected.
-
-GitLab is making improvements to the Code Suggestions to improve the quality. AI is non-deterministic, so you may not get the same suggestion every time with the same input.
-
-This feature is currently in [Beta](../../../policy/experiment-beta-support.md#beta).
-Code Suggestions depends on both Google Vertex AI Codey APIs and the GitLab Code Suggestions service. We have built this feature to gracefully degrade and have controls in place to allow us to
-mitigate abuse or misuse. GitLab may disable this feature for any or all customers at any time at our discretion.
-
-## Code Suggestions data usage
-
-Code Suggestions is a generative artificial intelligence (AI) model.
-
-Your personal access token enables a secure API connection to GitLab.com.
-This API connection securely transmits a context window from your IDE/editor to the Code Suggestions GitLab hosted service which calls Google Vertex AI Codey APIs,
-and the generated suggestion is transmitted back to your IDE/editor.
-
-GitLab currently leverages [Google Cloud's Vertex AI Codey API models](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview).
-
-### Data privacy
-
-No new additional data is collected to enable this feature. Private non-public GitLab customer data is
-not used as training data.
-
-Learn more about Google Vertex AI Codey APIs [Data Governance](https://cloud.google.com/vertex-ai/docs/generative-ai/data-governance)
-
-### Inference window context
-
-Code Suggestions currently inferences against the currently opened file and has a context window of 2,048 tokens and 8,192 character limits. This limit includes content before and after the cursor, the file name, and the extension type.
-Learn more about Google Vertex AI [code-gecko](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models).
-
-The maximum number of tokens that is generated in the response is default 64. A token is approximately four characters. 100 tokens correspond to roughly 60-80 words.
-Learn more about Google Vertex AI [`code-gecko`](https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/code-completion).
-
-### Self-managed instance data privacy
-
-A self-managed GitLab instance does not generate the code suggestion. After successful
-authentication to the self-managed instance, a token is generated.
-
-The IDE/editor then uses this token to securely transmit data directly to
-GitLab.com's Code Suggestions service for processing.
-
-The Code Suggestion service then securely returns an AI-generated code suggestion.
-
-Neither GitLab nor Google Vertex AI Codey APIs have any visibility into a self-managed customer's code other than
-what is sent to generate the code suggestion.
-
-### Training data
-
-Code suggestions are routed through Google Vertex AI Codey APIs. Learn more about Google Vertex AI Codey APIs [Data Governance](https://cloud.google.com/vertex-ai/docs/generative-ai/data-governance) and [Responsible AI](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/responsible-ai).
-
-Google Vertex AI Codey APIs are not trained on private non-public GitLab customer or user data.
-
-Google has [shared the following](https://ai.google/discover/foundation-models/) about the data Codey models are trained on:
-
-> Codey is our family of foundational coding models built on PaLM 2. Codey was fine-tuned on a large dataset of high quality, permissively licensed code from external sources
-
-## Progressive enhancement
-
-This feature is designed as a progressive enhancement to developer's IDEs.
-Code Suggestions offer a completion if the machine learning engine can generate a recommendation.
-In the event of a connection issue or model inference failure, the feature gracefully degrades.
-Code Suggestions do not prevent you from writing code in your IDE.
-
-### Internet connectivity
-
-Code Suggestions does not work with offline environments.
-
-To use Code Suggestions:
-
-- On GitLab.com, you must have an internet connection and be able to access GitLab.
-- In GitLab 16.1 and later, on self-managed GitLab, you must have an internet connection.
-
-### Model accuracy and quality
-
-Code Suggestions can generate low-quality, incomplete, and possibly insecure code.
-We strongly encourage all beta users to leverage GitLab native
-[Code Quality Scanning](../../../ci/testing/code_quality.md) and
-[Security Scanning](../../application_security/index.md) capabilities.
-
-GitLab currently does not retrain Google Vertex AI Codey APIs. GitLab makes no claims
-to the accuracy or quality of code suggestions generated by Google Vertex AI Codey API.
-Read more about [Google Vertex AI foundation model capabilities](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models).
-
-## Known limitations
-
-While in Beta, we are working on improving the accuracy of overall generated content.
-However, Code Suggestions may generate suggestions that are:
-
-- Low-quality
-- Incomplete
-- Produce failed pipelines
-- Insecure code
-- Offensive or insensitive
-
-We are also aware of specific situations that can produce unexpected or incoherent results including:
-
-- Suggestions written in the middle of existing functions, or "fill in the middle."
-- Suggestions based on natural language code comments.
-- Suggestions that mixed programming languages in unexpected ways.
-
-## Feedback
-
-Report issues in the [feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/405152).
-
-## Troubleshooting
-
-### Code Suggestions aren't displayed
-
-If Code Suggestions are not displayed, try the following troubleshooting steps.
-
-In GitLab, ensure Code Suggestions is enabled:
-
-- [For your user account](#enable-code-suggestions-for-an-individual-user).
-- [For *all* top-level groups your account belongs to](../../group/manage.md#enable-code-suggestions). If you don't have a role that lets you view the top-level group's settings, contact a group owner.
-
-To confirm that your account is enabled, go to [https://gitlab.com/api/v4/ml/ai-assist](https://gitlab.com/api/v4/ml/ai-assist). A response of `user_is_allowed` should return `true`.
-
-#### Code Suggestions not displayed in VS Code or GitLab WebIDE
-
-Check all the steps in [Code Suggestions aren't displayed](#code-suggestions-arent-displayed) first.
-
-If you are a self-managed user, ensure that Code Suggestions for the [GitLab WebIDE](../../project/web_ide/index.md) are enabled. The same settings apply to VS Code as local IDE.
-
-1. On the left sidebar, select **Extensions > GitLab Workflow**.
-1. Select **Settings** (**{settings}**), and then select **Extension Settings**.
-1. In **GitLab > AI Assisted Code Suggestions**, select the **Enable code completion (Beta)**
- checkbox.
-
-If the settings are enabled, but Code Suggestions are still not displayed, try the following steps:
-
-1. Enable the `Debug` checkbox in the GitLab Workflow **Extension Settings**.
-1. Open the extension log in **View > Output** and change the dropdown list to **GitLab Workflow** as the log filter. The command palette command is `GitLab: Show Extension Logs`.
-1. Disable and re-enable the **Enable code completion (Beta)** checkbox.
-1. Verify that the debug log contains similar output:
-
-```shell
-2023-07-14T17:29:00:763 [debug]: Disabling code completion
-2023-07-14T17:29:01:802 [debug]: Enabling code completion
-2023-07-14T17:29:01:802 [debug]: AI Assist: Using server: https://codesuggestions.gitlab.com/v2/completions
-```
-
-#### Code Suggestions not displayed in Microsoft Visual Studio
-
-Check all the steps in [Code Suggestions aren't displayed](#code-suggestions-arent-displayed) first.
-
-1. Ensure you have properly [set up the extension](https://gitlab.com/gitlab-org/editor-extensions/gitlab-visual-studio-extension#setup).
-1. From the **Tools > Options** menu, find the **GitLab** option. Ensure **Log Level** is set to **Debug**.
-1. Open the extension log in **View > Output** and change the dropdown list to **GitLab Extension** as the log filter.
-1. Verify that the debug log contains similar output:
-
-```shell
-14:48:21:344 GitlabProposalSource.GetCodeSuggestionAsync
-14:48:21:344 LsClient.SendTextDocumentCompletionAsync("GitLab.Extension.Test\TestData.cs", 34, 0)
-14:48:21:346 LS(55096): time="2023-07-17T14:48:21-05:00" level=info msg="update context"
-```
-
-### Authentication troubleshooting
-
-If the above steps do not solve your issue, the problem may be related to the recent changes in authentication,
-specifically the token system. To resolve the issue:
-
-1. Remove the existing personal access token from your GitLab account settings.
-1. Reauthorize your GitLab account in VS Code using OAuth.
-1. Test the code suggestions feature with different file extensions to verify if the issue is resolved.
diff --git a/doc/user/project/repository/code_suggestions/index.md b/doc/user/project/repository/code_suggestions/index.md
new file mode 100644
index 00000000000..4f0c0b2c9a6
--- /dev/null
+++ b/doc/user/project/repository/code_suggestions/index.md
@@ -0,0 +1,192 @@
+---
+stage: Create
+group: Code Creation
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: index, reference
+---
+
+# Code Suggestions **(FREE ALL BETA)**
+
+> - [Introduced support for Google Vertex AI Codey APIs](https://gitlab.com/groups/gitlab-org/-/epics/10562) in GitLab 16.1.
+> - [Removed support for GitLab native model](https://gitlab.com/groups/gitlab-org/-/epics/10752) in GitLab 16.2.
+
+WARNING:
+This feature is in [Beta](../../../../policy/experiment-beta-support.md#beta).
+Beta users should read about the [known limitations](#known-limitations). We look forward to hearing your [feedback](#feedback).
+
+Write code more efficiently by using generative AI to suggest code while you're developing.
+
+GitLab Duo Code Suggestions are available:
+
+- On [self-managed](self_managed.md) and [SaaS](saas.md).
+- In VS Code, Microsoft Visual Studio, JetBrains IDEs, and Neovim. You must have the corresponding GitLab extension installed.
+- In the GitLab WebIDE.
+
+<div class="video-fallback">
+ <a href="https://www.youtube.com/watch?v=WnxBYxN2-p4">View an end-to-end demo of Code Suggestions in VS Code</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube-nocookie.com/embed/WnxBYxN2-p4" frameborder="0" allowfullscreen> </iframe>
+</figure>
+
+Usage of Code Suggestions is governed by the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
+Learn about [data usage when using Code Suggestions](#code-suggestions-data-usage).
+
+## Supported languages
+
+The best results from Code Suggestions are expected [for languages the Google Vertex AI Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview#supported_coding_languages) directly support:
+
+- C++
+- C#
+- Go
+- Google SQL
+- Java
+- JavaScript
+- Kotlin
+- PHP
+- Python
+- Ruby
+- Rust
+- Scala
+- Swift
+- TypeScript
+
+### Supported code infrastructure interfaces
+
+Code Suggestions includes [Google Vertex AI Codey APIs](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview#supported_code_infrastructure_interfaces) support for the following infrastructure as code interfaces:
+
+- Google Cloud CLI
+- Kubernetes Resource Model (KRM)
+- Terraform
+
+Suggestion quality for other languages and using natural language code comments to request completions may not yet result in high-quality suggestions.
+
+### Supported languages in IDEs
+
+Editor support for languages is documented in the following table.
+
+| Language | VS Code | JetBrains IDEs | Visual Studio | Neovim |
+|------------------|------------------------|------------------------|------------------------|--------|
+| C++ | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes | **{check-circle}** Yes |
+| C# | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| Go | **{check-circle}** Yes | **{check-circle}** Yes (IDEA Ultimate / GoLand) | **{check-circle}** Yes | **{check-circle}** Yes |
+| Google SQL | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | **{check-circle}** Yes |
+| Java | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| JavaScript | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| Kotlin | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| PHP | **{check-circle}** Yes | **{check-circle}** Yes (IDEA Ultimate) | **{check-circle}** Yes | **{check-circle}** Yes |
+| Python | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| Ruby | **{check-circle}** Yes | **{check-circle}** Yes (IDEA Ultimate / RubyMine) | **{check-circle}** Yes | **{check-circle}** Yes |
+| Rust | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| Scala | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| Swift | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| TypeScript | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes |
+| Google Cloud | **{dotted-circle}** No | **{dotted-circle}** No | **{dotted-circle}** No | **{dotted-circle}** No |
+| Kubernetes Resource Model (KRM) | **{dotted-circle}** No | **{dotted-circle}** No | **{dotted-circle}** No | **{dotted-circle}** No |
+| Terraform | **{check-circle}** Yes (Requires third-party extension providing Terraform support) | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes (Requires third-party extension providing the `terraform` file type) |
+
+## Supported editor extensions
+
+Code Suggestions supports a variety of popular editors including:
+
+- VS Code, using [the VS Code GitLab Workflow extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).
+- [GitLab WebIDE (VS Code in the Cloud)](../../../project/web_ide/index.md), with no additional configuration.
+- Microsoft Visual Studio, using the [Visual Studio GitLab extension](https://marketplace.visualstudio.com/items?itemName=GitLab.GitLabExtensionForVisualStudio).
+- JetBrains IDEs, using the [GitLab plugin](https://plugins.jetbrains.com/plugin/22325-gitlab).
+- Neovim, using the [`gitlab.vim` plugin](https://gitlab.com/gitlab-org/editor-extensions/gitlab.vim).
+
+A [GitLab Language Server for Code Suggestions](https://gitlab.com/gitlab-org/editor-extensions/gitlab-language-server-for-code-suggestions)
+is also in process.
+This improvement should result in:
+
+- Faster iteration and standardization of the IDE extensions.
+- The ability to use Code Suggestions even when an official editor extension isn't available.
+
+## Code Suggestions data usage
+
+Code Suggestions is a generative artificial intelligence (AI) model.
+
+Your personal access token enables a secure API connection to GitLab.com.
+This API connection securely transmits a context window from your IDE/editor to the Code Suggestions GitLab hosted service which calls Google Vertex AI Codey APIs,
+and the generated suggestion is transmitted back to your IDE/editor.
+
+GitLab currently leverages [Google Cloud's Vertex AI Codey API models](https://cloud.google.com/vertex-ai/docs/generative-ai/code/code-models-overview). Learn more about Google Vertex AI Codey APIs [Data Governance](https://cloud.google.com/vertex-ai/docs/generative-ai/data-governance).
+
+### Telemetry
+
+For self-managed instances that have enabled Code Suggestions and SaaS accounts, we collect aggregated or de-identified first-party usage data through our [Snowplow collector](https://about.gitlab.com/handbook/business-technology/data-team/platform/snowplow/). This usage data includes the following metrics:
+
+- Language the code suggestion was in (for example, Python)
+- Editor being used (for example, VS Code)
+- Number of suggestions shown, accepted, rejected, or that had errors
+- Duration of time that a suggestion was shown
+- Prompt and suffix lengths
+- Model used
+- Number of unique users
+- Number of unique instances
+
+### Inference window context
+
+Code Suggestions currently inferences against the currently opened file and has a context window of 2,048 tokens and 8,192 character limits. This limit includes content before and after the cursor, the file name, and the extension type.
+Learn more about Google Vertex AI [code-gecko](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models).
+
+The maximum number of tokens that is generated in the response is default 64. A token is approximately four characters. 100 tokens correspond to roughly 60-80 words.
+Learn more about Google Vertex AI [`code-gecko`](https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/code-completion).
+
+### Training data
+
+Code Suggestions are routed through Google Vertex AI Codey APIs. Learn more about Google Vertex AI Codey APIs [Data Governance](https://cloud.google.com/vertex-ai/docs/generative-ai/data-governance) and [Responsible AI](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/responsible-ai).
+
+Google Vertex AI Codey APIs are not trained on private non-public GitLab customer or user data.
+
+Google has [shared the following](https://ai.google/discover/foundation-models/) about the data Codey models are trained on:
+
+> Codey is our family of foundational coding models built on PaLM 2. Codey was fine-tuned on a large dataset of high quality, permissively licensed code from external sources
+
+## Progressive enhancement
+
+This feature is designed as a progressive enhancement to developer's IDEs.
+Code Suggestions offer a completion if the machine learning engine can generate a recommendation.
+In the event of a connection issue or model inference failure, the feature gracefully degrades.
+Code Suggestions do not prevent you from writing code in your IDE.
+
+### Internet connectivity
+
+Code Suggestions does not work with offline environments.
+
+To use Code Suggestions:
+
+- On GitLab.com, you must have an internet connection and be able to access GitLab.
+- In GitLab 16.1 and later, on self-managed GitLab, you must have an internet connection.
+
+### Model accuracy and quality
+
+Code Suggestions can generate low-quality, incomplete, and possibly insecure code.
+We strongly encourage all beta users to leverage GitLab native
+[Code Quality Scanning](../../../../ci/testing/code_quality.md) and
+[Security Scanning](../../../application_security/index.md) capabilities.
+
+GitLab currently does not retrain Google Vertex AI Codey APIs. GitLab makes no claims
+to the accuracy or quality of Code Suggestions generated by Google Vertex AI Codey API.
+Read more about [Google Vertex AI foundation model capabilities](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models).
+
+## Known limitations
+
+While in Beta, we are working on improving the accuracy of overall generated content.
+However, Code Suggestions may generate suggestions that are:
+
+- Low-quality
+- Incomplete
+- Produce failed pipelines
+- Insecure code
+- Offensive or insensitive
+
+We are also aware of specific situations that can produce unexpected or incoherent results including:
+
+- Suggestions written in the middle of existing functions, or "fill in the middle."
+- Suggestions based on natural language code comments.
+- Suggestions that mixed programming languages in unexpected ways.
+
+## Feedback
+
+Report issues in the [feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/405152).
diff --git a/doc/user/project/repository/code_suggestions/saas.md b/doc/user/project/repository/code_suggestions/saas.md
new file mode 100644
index 00000000000..174c227b6fe
--- /dev/null
+++ b/doc/user/project/repository/code_suggestions/saas.md
@@ -0,0 +1,54 @@
+---
+stage: Create
+group: Code Creation
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: index, reference
+---
+
+# Code Suggestions on GitLab SaaS **(FREE SAAS BETA)**
+
+> - [Introduced](https://about.gitlab.com/releases/2023/02/22/gitlab-15-9-released/#code-suggestions-available-in-closed-beta) in GitLab 15.9 as [Beta](../../../../policy/experiment-beta-support.md#beta) for early access Ultimate customers on GitLab.com.
+> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/408104) as opt-in with GitLab 15.11 as [Beta](../../../../policy/experiment-beta-support.md#beta).
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/408158) from GitLab Ultimate to GitLab Premium in 16.0.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/410801) from GitLab Premium to GitLab Free in 16.0.
+> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121079) in GitLab 16.1.
+
+Write code more efficiently by using generative AI to suggest code while you're developing.
+
+Usage of GitLab Duo Code Suggestions is governed by the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
+Learn about [data usage when using Code Suggestions](index.md#code-suggestions-data-usage).
+
+## Enable Code Suggestions
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121079) in GitLab 16.1 as [Beta](../../../../policy/experiment-beta-support.md#beta).
+
+You can enable Code Suggestions for an individual or group:
+
+- [Enable Code Suggestions for all group members](../../../group/manage.md#enable-code-suggestions). (You must be a group owner).
+- [Enable Code Suggestions for your own account](../../../profile/preferences.md#enable-code-suggestions).
+
+The group setting takes precedence over the user setting.
+
+## Use Code Suggestions
+
+Prerequisites:
+
+- Ensure Code Suggestions is enabled for your user and group.
+- You must have installed and configured a [supported IDE editor extension](index.md#supported-editor-extensions).
+
+To use Code Suggestions:
+
+1. Author your code. As you type, suggestions are displayed. Depending on the cursor position, the extension either:
+
+ - Provides entire code snippets, like generating functions.
+ - Completes the current line.
+
+1. To accept a suggestion, press <kbd>Tab</kbd>.
+
+Suggestions are best when writing new code. Editing existing functions or 'fill in the middle' of a function may not perform as expected.
+
+GitLab is making improvements to the Code Suggestions to improve the quality. AI is non-deterministic, so you may not get the same suggestion every time with the same input.
+
+This feature is currently in [Beta](../../../../policy/experiment-beta-support.md#beta).
+Code Suggestions depends on both Google Vertex AI Codey APIs and the GitLab Code Suggestions service. We have built this feature to gracefully degrade and have controls in place to allow us to
+mitigate abuse or misuse. GitLab may disable this feature for any or all customers at any time at our discretion.
diff --git a/doc/user/project/repository/code_suggestions/self_managed.md b/doc/user/project/repository/code_suggestions/self_managed.md
new file mode 100644
index 00000000000..3c149604086
--- /dev/null
+++ b/doc/user/project/repository/code_suggestions/self_managed.md
@@ -0,0 +1,187 @@
+---
+stage: Create
+group: Code Creation
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: index, reference
+---
+
+# Code Suggestions on self-managed GitLab **(PREMIUM SELF BETA)**
+
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10653) in GitLab 16.1 as [Beta](../../../../policy/experiment-beta-support.md#beta) on self-managed GitLab.
+> - [Introduced support for Google Vertex AI Codey APIs](https://gitlab.com/groups/gitlab-org/-/epics/10562) in GitLab 16.1.
+> - [Removed support for GitLab native model](https://gitlab.com/groups/gitlab-org/-/epics/10752) in GitLab 16.2.
+> - Code Suggestions in the GitLab WebIDE enabled for all GitLab-hosted customers.
+
+Write code more efficiently by using generative AI to suggest code while you're developing.
+
+GitLab Duo Code Suggestions are available on GitLab Enterprise Edition.
+Cloud licensing is required for Premium and Ultimate subscription tiers.
+
+Code Suggestions are not available for GitLab Community Edition.
+
+WARNING:
+In GitLab 16.3 and later, only Premium and Ultimate customers can participate in the free trial of Code Suggestions on self-managed GitLab.
+
+Usage of Code Suggestions is governed by the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
+Learn about [data usage when using Code Suggestions](index.md#code-suggestions-data-usage).
+
+## Enable Code Suggestions on self-managed GitLab **(FREE SELF)**
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10653) in GitLab 16.1 as [Beta](../../../../policy/experiment-beta-support.md#beta).
+
+When you enable Code Suggestions for your self-managed instance, you:
+
+- Agree to the [GitLab testing agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
+- Acknowledge that GitLab sends data from the instance, including personal data, to GitLab.com infrastructure.
+
+How you enable Code Suggestions differs depending on your version of GitLab.
+
+### GitLab 16.3 and later
+
+Prerequisites:
+
+- You are a new Code Suggestions customer as of GitLab 16.3.
+- All of the users in your instance have the latest version of their IDE extension.
+- You are an administrator.
+
+To enable Code Suggestions for your self-managed GitLab instance:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Code Suggestions** and select **Turn on Code Suggestions for this instance**.
+ In GitLab 16.3, you do not need to enter anything into the **Personal access token** field.
+ In GitLab 16.4 and later, there is no **Personal access token** field.
+1. Select **Save changes**.
+
+This setting is visible only in self-managed GitLab instances.
+
+WARNING:
+In GitLab 16.2 and earlier, if you clear the **Turn on Code Suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
+
+To make sure Code Suggestions works immediately, you must [manually synchronize your subscription](#manually-synchronize-your-subscription).
+
+The users in your instance can now use Code Suggestions.
+
+### GitLab 16.2 and earlier
+
+Prerequisites:
+
+- You are an administrator.
+- You have a [customer success manager](https://about.gitlab.com/handbook/customer-success/csm/]).
+- You have a [GitLab SaaS account](https://gitlab.com/users/sign_up). You do not need to have a GitLab SaaS subscription.
+
+NOTE:
+If you do not have a customer success manager, you cannot participate in the free trial of Code Suggestions on self-managed GitLab. Upgrade to GitLab 16.3 to [perform self-service onboarding](#gitlab-163-and-later).
+
+Then, you will:
+
+1. Enable Code Suggestions for your SaaS account.
+1. Enable Code Suggestions for the instance.
+1. [Request early access](#request-access-to-code-suggestions) to the Code Suggestions Beta.
+
+#### Enable Code Suggestions for your SaaS account
+
+To enable Code Suggestions for your GitLab SaaS account:
+
+1. Create a [personal access token](../../../profile/personal_access_tokens.md#create-a-personal-access-token)
+ with the `api` scope.
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. In the **Code Suggestions** section, select **Enable Code Suggestions**.
+1. Select **Save changes**.
+
+#### Enable Code Suggestions for the instance
+
+To enable Code Suggestions for your self-managed GitLab instance:
+
+1. On the left sidebar, select **Search or go to**.
+1. Select **Admin Area**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Code Suggestions** and:
+ - Select **Turn on Code Suggestions for this instance**.
+ - In **Personal access token**, enter your GitLab SaaS personal access token.
+1. Select **Save changes**.
+
+This setting is visible only in self-managed GitLab instances.
+
+WARNING:
+If you clear the **Turn on Code Suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
+
+#### Request access to Code Suggestions
+
+GitLab provisions access on a customer-by-customer basis for Code Suggestions
+on self-managed instances. To request access, contact your customer success manager.
+
+Your customer success manager then provisions access by commenting on [issue 415393](https://gitlab.com/gitlab-org/gitlab/-/issues/415393) (internal access only).
+
+After GitLab has provisioned access to Code Suggestions for your instance,
+the users in your instance can now enable Code Suggestions.
+
+### Configure network and proxy settings
+
+Configure any firewalls to allow outbound connections to `https://codesuggestions.gitlab.com/`.
+
+If your GitLab instance uses an HTTP proxy server to access the internet, ensure
+the server is configured to allow outbound connections, including the
+[`gitlab_workhorse` environment variable](https://docs.gitlab.com/omnibus/settings/environment-variables.html).
+
+### Update GitLab
+
+In GitLab 16.3 and later, GitLab is enforcing the cloud licensing requirement for Code Suggestions:
+
+- The Premium and Ultimate subscription tiers support cloud Licensing.
+- GitLab Free does not have cloud licensing support.
+
+If you have a GitLab Free subscription and update to GitLab 16.3 or later,
+to continue having early access to Code Suggestions, you must:
+
+1. Have a [subscription that supports cloud licensing](https://about.gitlab.com/pricing/).
+1. Make sure you have the latest version of your [IDE extension](index.md#supported-editor-extensions).
+1. [Manually synchronize your subscription](#manually-synchronize-your-subscription).
+
+#### Manually synchronize your subscription
+
+You must [manually synchronize your subscription](../../../../subscriptions/self_managed/index.md#manually-synchronize-your-subscription-details) if either:
+
+- You have already updated to GitLab 16.3 and have just bought a Premium or Ultimate tier subscription.
+- You already have a Premium or Ultimate tier subscription and have just updated to GitLab 16.3.
+
+Without the manual synchronization, it might take up to 24 hours to active Code Suggestions on your instance.
+
+## Use Code Suggestions
+
+Prerequisites:
+
+- Code Suggestions must be enabled [for the instance](#enable-code-suggestions-on-self-managed-gitlab).
+- You must have installed and configured a [supported IDE editor extension](index.md#supported-editor-extensions).
+
+To use Code Suggestions:
+
+1. Author your code. As you type, suggestions are displayed. Depending on the cursor position, the extension either:
+
+ - Provides entire code snippets, like generating functions.
+ - Completes the current line.
+
+1. To accept a suggestion, press <kbd>Tab</kbd>.
+
+Suggestions are best when writing new code. Editing existing functions or 'fill in the middle' of a function may not perform as expected.
+
+GitLab is making improvements to the Code Suggestions to improve the quality. AI is non-deterministic, so you may not get the same suggestion every time with the same input.
+
+This feature is currently in [Beta](../../../../policy/experiment-beta-support.md#beta).
+Code Suggestions depends on both Google Vertex AI Codey APIs and the GitLab Code Suggestions service. We have built this feature to gracefully degrade and have controls in place to allow us to
+mitigate abuse or misuse. GitLab may disable this feature for any or all customers at any time at our discretion.
+
+### Data privacy
+
+A self-managed GitLab instance does not generate the code suggestion. After successful
+authentication to the self-managed instance, a token is generated.
+
+The IDE/editor then uses this token to securely transmit data directly to
+GitLab.com's Code Suggestions service for processing.
+
+The Code Suggestions service then securely returns an AI-generated code suggestion.
+
+Neither GitLab nor Google Vertex AI Codey APIs have any visibility into a self-managed customer's code other than
+what is sent to generate the code suggestion.
diff --git a/doc/user/project/repository/code_suggestions/troubleshooting.md b/doc/user/project/repository/code_suggestions/troubleshooting.md
new file mode 100644
index 00000000000..c0cdb3cc32d
--- /dev/null
+++ b/doc/user/project/repository/code_suggestions/troubleshooting.md
@@ -0,0 +1,69 @@
+---
+stage: Create
+group: Code Creation
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: index, reference
+---
+
+# Troubleshooting Code Suggestions **(FREE ALL BETA)**
+
+When working with GitLab Duo Code Suggestions, you might encounter the following issues.
+
+## Code Suggestions aren't displayed
+
+If Code Suggestions are not displayed, try the following troubleshooting steps.
+
+In GitLab, ensure Code Suggestions is enabled:
+
+- [For your user account](../../../profile/preferences.md#enable-code-suggestions).
+- [For *all* top-level groups your account belongs to](../../../group/manage.md#enable-code-suggestions). If you don't have a role that lets you view the top-level group's settings, contact a group owner.
+
+To confirm that your account is enabled, go to [https://gitlab.com/api/v4/ml/ai-assist](https://gitlab.com/api/v4/ml/ai-assist). A response of `user_is_allowed` should return `true`.
+
+### Code Suggestions not displayed in VS Code or GitLab WebIDE
+
+Check all the steps in [Code Suggestions aren't displayed](#code-suggestions-arent-displayed) first.
+
+If you are a self-managed user, ensure that Code Suggestions for the [GitLab WebIDE](../../../project/web_ide/index.md) are enabled. The same settings apply to VS Code as local IDE.
+
+1. On the left sidebar, select **Extensions > GitLab Workflow**.
+1. Select **Settings** (**{settings}**), and then select **Extension Settings**.
+1. In **GitLab > AI Assisted Code Suggestions**, select the **Enable code completion (Beta)**
+ checkbox.
+
+If the settings are enabled, but Code Suggestions are still not displayed, try the following steps:
+
+1. Enable the `Debug` checkbox in the GitLab Workflow **Extension Settings**.
+1. Open the extension log in **View > Output** and change the dropdown list to **GitLab Workflow** as the log filter. The command palette command is `GitLab: Show Extension Logs`.
+1. Disable and re-enable the **Enable code completion (Beta)** checkbox.
+1. Verify that the debug log contains similar output:
+
+```shell
+2023-07-14T17:29:00:763 [debug]: Disabling code completion
+2023-07-14T17:29:01:802 [debug]: Enabling code completion
+2023-07-14T17:29:01:802 [debug]: AI Assist: Using server: https://codesuggestions.gitlab.com/v2/completions
+```
+
+### Code Suggestions not displayed in Microsoft Visual Studio
+
+Check all the steps in [Code Suggestions aren't displayed](#code-suggestions-arent-displayed) first.
+
+1. Ensure you have properly [set up the extension](https://gitlab.com/gitlab-org/editor-extensions/gitlab-visual-studio-extension#setup).
+1. From the **Tools > Options** menu, find the **GitLab** option. Ensure **Log Level** is set to **Debug**.
+1. Open the extension log in **View > Output** and change the dropdown list to **GitLab Extension** as the log filter.
+1. Verify that the debug log contains similar output:
+
+```shell
+14:48:21:344 GitlabProposalSource.GetCodeSuggestionAsync
+14:48:21:344 LsClient.SendTextDocumentCompletionAsync("GitLab.Extension.Test\TestData.cs", 34, 0)
+14:48:21:346 LS(55096): time="2023-07-17T14:48:21-05:00" level=info msg="update context"
+```
+
+## Authentication troubleshooting
+
+If the above steps do not solve your issue, the problem may be related to the recent changes in authentication,
+specifically the token system. To resolve the issue:
+
+1. Remove the existing personal access token from your GitLab account settings.
+1. Reauthorize your GitLab account in VS Code using OAuth.
+1. Test the Code Suggestions feature with different file extensions to verify if the issue is resolved.
diff --git a/doc/user/project/repository/file_finder.md b/doc/user/project/repository/file_finder.md
index ee2be6dee7c..5dd8ad39889 100644
--- a/doc/user/project/repository/file_finder.md
+++ b/doc/user/project/repository/file_finder.md
@@ -14,7 +14,7 @@ File finder is powered by the [`fuzzaldrin-plus`](https://github.com/jeancroy/fu
To search for a file:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Repository**.
1. In the upper right, select **Find file**.
1. In the search box, start typing the filename.
diff --git a/doc/user/project/repository/forking_workflow.md b/doc/user/project/repository/forking_workflow.md
index 4c37b92b388..a304a8d108d 100644
--- a/doc/user/project/repository/forking_workflow.md
+++ b/doc/user/project/repository/forking_workflow.md
@@ -59,8 +59,8 @@ or the command line. GitLab Premium and Ultimate tiers can also automate updates
To update your fork from the GitLab UI:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your projects**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my projects**.
1. Select the fork you want to update.
1. Below the dropdown list for branch name, find the **Forked from** (**{fork}**)
information box to determine if your fork is ahead, behind, or both. In this example,
@@ -181,13 +181,13 @@ To restore the fork relationship, [use the API](../../../api/projects.md#create-
To remove a fork relationship:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. In the **Remove fork relationship** section, select **Remove fork relationship**.
1. To confirm, enter the project path and select **Confirm**.
-When you unlink a fork that uses a [hashed storage pool](../../../administration/repository_storage_types.md#hashed-object-pools)
+When you unlink a fork that uses a [hashed storage pool](../../../administration/repository_storage_paths.md#hashed-object-pools)
to share objects with another repository:
- All objects are copied from the pool into your fork.
diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md
index 8bb6d868270..592041ef4e2 100644
--- a/doc/user/project/repository/gpg_signed_commits/index.md
+++ b/doc/user/project/repository/gpg_signed_commits/index.md
@@ -1,330 +1,11 @@
---
-stage: Create
-group: Source Code
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+redirect_to: '../signed_commits/gpg.md'
+remove_date: '2023-12-01'
---
-# Sign commits with GPG **(FREE ALL)**
+This document was moved to [another location](../signed_commits/gpg.md).
-You can sign the commits you make in a GitLab repository with a
-GPG ([GNU Privacy Guard](https://gnupg.org/)) key. When you add a cryptographic
-signature to your commit, you provide extra assurance that a commit
-originated from you, rather than an impersonator. If GitLab can verify a commit
-author's identity with a public GPG key, the commit is marked **Verified** in the
-GitLab UI. You can then configure [push rules](../push_rules.md)
-for your project to reject individual commits not signed with GPG, or reject all
-commits from unverified users.
-
-NOTE:
-GitLab uses the term GPG for all OpenPGP, PGP, and GPG-related material and
-implementations.
-
-For GitLab to consider a commit verified:
-
-- The committer must have a GPG public/private key pair.
-- The committer's public key must be uploaded to their GitLab account.
-- One of the email addresses in the GPG public key must match a **verified** email address
- used by the committer in GitLab. To keep this address private, use the automatically generated
- [private commit email address](../../../profile/index.md#use-an-automatically-generated-private-commit-email)
- GitLab provides in your profile.
-- The committer's email address must match the verified email address from the
- GPG key.
-
-GitLab uses its own keyring to verify the GPG signature. It does not access any
-public key server.
-
-GPG verified tags are not supported.
-
-For more details about GPG, refer to the [related topics list](#related-topics).
-
-## View a user's public GPG key
-
-To view a user's public GPG key, you can either:
-
-- Go to `https://gitlab.example.com/<USERNAME>.gpg`. GitLab displays the GPG key,
- if the user has configured one, or a blank page for users without a configured GPG key.
-- Go to the user's profile (such as `https://gitlab.example.com/<USERNAME>`). In the upper-right corner
- of the user's profile, select **View public GPG keys** (**{key}**).
-
-## Configure commit signing
-
-To sign commits, you must configure both your local machine and your GitLab account:
-
-1. [Create a GPG key](#create-a-gpg-key).
-1. [Add a GPG key to your account](#add-a-gpg-key-to-your-account).
-1. [Associate your GPG key with Git](#associate-your-gpg-key-with-git).
-1. [Sign your Git commits](#sign-your-git-commits).
-
-### Create a GPG key
-
-If you don't already have a GPG key, create one:
-
-1. [Install GPG](https://www.gnupg.org/download/) for your operating system.
- If your operating system has `gpg2` installed, replace `gpg` with `gpg2` in
- the commands on this page.
-1. To generate your key pair, run the command appropriate for your version of `gpg`:
-
- ```shell
- # Use this command for the default version of GPG, including
- # Gpg4win on Windows, and most macOS versions:
- gpg --gen-key
-
- # Use this command for versions of GPG later than 2.1.17:
- gpg --full-gen-key
- ```
-
-1. Select the algorithm your key should use, or press <kbd>Enter</kbd> to select
- the default option, `RSA and RSA`.
-1. Select the key length, in bits. GitLab recommends 4096-bit keys.
-1. Specify the validity period of your key. This value is subjective, and the
- default value is no expiration.
-1. To confirm your answers, enter `y`.
-1. Enter your name.
-1. Enter your email address. It must match a
- [verified email address](../../../profile/index.md#change-the-email-displayed-on-your-commits)
- in your GitLab account.
-1. Optional. Enter a comment to display in parentheses after your name.
-1. GPG displays the information you've entered so far. Edit the information or press
- <kbd>O</kbd> (for `Okay`) to continue.
-1. Enter a strong password, then enter it again to confirm it.
-1. To list your private GPG key, run this command, replacing
- `<EMAIL>` with the email address you used when you generated the key:
-
- ```shell
- gpg --list-secret-keys --keyid-format LONG <EMAIL>
- ```
-
-1. In the output, identify the `sec` line, and copy the GPG key ID. It begins after
- the `/` character. In this example, the key ID is `30F2B65B9246B6CA`:
-
- ```plaintext
- sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
- D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA
- uid [ultimate] Mr. Robot <your_email>
- ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
- ```
-
-1. To show the associated public key, run this command, replacing `<ID>` with the
- GPG key ID from the previous step:
-
- ```shell
- gpg --armor --export <ID>
- ```
-
-1. Copy the public key, including the `BEGIN PGP PUBLIC KEY BLOCK` and
- `END PGP PUBLIC KEY BLOCK` lines. You need this key in the next step.
-
-### Add a GPG key to your account
-
-To add a GPG key to your user settings:
-
-1. Sign in to GitLab.
-1. On the left sidebar, select your avatar.
-1. Select **Edit profile**.
-1. Select **GPG Keys** (**{key}**).
-1. Select **Add new key**.
-1. In **Key**, paste your _public_ key.
-1. To add the key to your account, select **Add key**. GitLab shows the key's
- fingerprint, email address, and creation date:
-
- ![GPG key single page](img/profile_settings_gpg_keys_single_key.png)
-
-After you add a key, you cannot edit it. Instead, remove the offending key and re-add it.
-
-### Associate your GPG key with Git
-
-After you [create your GPG key](#create-a-gpg-key) and
-[add it to your account](#add-a-gpg-key-to-your-account), you must configure Git
-to use this key:
-
-1. Run this command to list the private GPG key you just created,
- replacing `<EMAIL>` with the email address for your key:
-
- ```shell
- gpg --list-secret-keys --keyid-format LONG <EMAIL>
- ```
-
-1. Copy the GPG private key ID that starts with `sec`. In this example, the private key ID is
- `30F2B65B9246B6CA`:
-
- ```plaintext
- sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
- D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA
- uid [ultimate] Mr. Robot <your_email>
- ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
- ```
-
-1. Run this command to configure Git to sign your commits with your key,
- replacing `<KEY ID>` with your GPG key ID:
-
- ```shell
- git config --global user.signingkey <KEY ID>
- ```
-
-### Sign your Git commits
-
-After you [add your public key to your account](#add-a-gpg-key-to-your-account),
-you can sign individual commits manually, or configure Git to default to signed commits:
-
-- Sign individual Git commits manually:
- 1. Add `-S` flag to any commit you want to sign:
-
- ```shell
- git commit -S -m "My commit message"
- ```
-
- 1. Enter the passphrase of your GPG key when asked.
- 1. Push to GitLab and check that your commits [are verified](#verify-commits).
-- Sign all Git commits by default by running this command:
-
- ```shell
- git config --global commit.gpgsign true
- ```
-
-#### Set signing key conditionally
-
-If you maintain signing keys for separate purposes, such as work and personal
-use, use an `IncludeIf` statement in your `.gitconfig` file to set which key
-you sign commits with.
-
-Prerequisites:
-
-- Requires Git version 2.13 or later.
-
-1. In the same directory as your main `~/.gitconfig` file, create a second file,
- such as `.gitconfig-gitlab`.
-1. In your main `~/.gitconfig` file, add your Git settings for work in non-GitLab projects.
-1. Append this information to the end of your main `~/.gitconfig` file:
-
- ```ini
- # The contents of this file are included only for GitLab.com URLs
- [includeIf "hasconfig:remote.*.url:https://gitlab.com/**"]
-
- # Edit this line to point to your alternate configuration file
- path = ~/.gitconfig-gitlab
- ```
-
-1. In your alternate `.gitconfig-gitlab` file, add the configuration overrides to
- use when you're committing to a GitLab repository. All settings from your
- main `~/.gitconfig` file are retained unless you explicitly override them.
- In this example,
-
- ```ini
- # Alternate ~/.gitconfig-gitlab file
- # These values are used for repositories matching the string 'gitlab.com',
- # and override their corresponding values in ~/.gitconfig
-
- [user]
- email = you@example.com
- signingkey = <KEY ID>
-
- [commit]
- gpgsign = true
- ```
-
-## Verify commits
-
-You can review commits for a merge request, or for an entire project:
-
-1. To review commits for a project:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
- 1. Select **Code > Commits**.
-1. To review commits for a merge request:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
- 1. Select **Code > Merge requests**, then select your merge request.
- 1. Select **Commits**.
-1. Identify the commit you want to review. Signed commits show either a **Verified**
- or **Unverified** badge, depending on the verification status of the GPG
- signature. Unsigned commits do not display a badge:
-
- ![Signed and unsigned commits](img/project_signed_and_unsigned_commits.png)
-
-1. To display the signature details for a commit, select the GPG badge:
-
- ![Signed commit with verified signature](img/project_signed_commit_verified_signature.png)
-
- ![Signed commit with unverified signature](img/project_signed_commit_unverified_signature.png)
-
-## Revoke a GPG key
-
-If a GPG key becomes compromised, revoke it. Revoking a key changes both future and past commits:
-
-- Past commits signed by this key are marked as unverified.
-- Future commits signed by this key are marked as unverified.
-
-To revoke a GPG key:
-
-1. On the left sidebar, select your avatar.
-1. Select **Edit profile**.
-1. Select **GPG Keys** (**{key}**).
-1. Select **Revoke** next to the GPG key you want to delete.
-
-## Remove a GPG key
-
-When you remove a GPG key from your GitLab account:
-
-- Previous commits signed with this key remain verified.
-- Future commits (including any commits created but not yet pushed) that attempt
- to use this key are unverified.
-
-To remove a GPG key from your account:
-
-1. On the left sidebar, select your avatar.
-1. Select **Edit profile**.
-1. Select **GPG Keys** (**{key}**).
-1. Select **Remove** (**{remove}**) next to the GPG key you want to delete.
-
-If you must unverify both future and past commits,
-[revoke the associated GPG key](#revoke-a-gpg-key) instead.
-
-## Related topics
-
-- [Sign commits and tags with X.509 certificates](../x509_signed_commits/index.md)
-- [Sign commits with SSH keys](../ssh_signed_commits/index.md)
-- [Commits API](../../../../api/commits.md)
-- GPG resources:
- - [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work)
- - [Managing OpenPGP Keys](https://riseup.net/en/security/message-security/openpgp/gpg-keys)
- - [OpenPGP Best Practices](https://riseup.net/en/security/message-security/openpgp/best-practices)
- - [Creating a new GPG key with subkeys](https://www.void.gr/kargig/blog/2013/12/02/creating-a-new-gpg-key-with-subkeys/) (advanced)
- - [Review existing GPG keys in your instance](../../../../administration/credentials_inventory.md#review-existing-gpg-keys)
-
-## Troubleshooting
-
-### Fix verification problems with signed commits
-
-Commits can be signed with [X.509 certificates](../x509_signed_commits/index.md)
-or a GPG key. The verification process for both methods can fail for multiple reasons:
-
-| Value | Description | Possible Fixes |
-|-----------------------------|-------------|----------------|
-| `UNVERIFIED` | The commit signature is not valid. | Sign the commit with a valid signature. |
-| `SAME_USER_DIFFERENT_EMAIL` | The GPG key used to sign the commit does not contain the committer email, but does contain a different valid email for the committer. | Amend the commit to use an email address that matches the GPG key, or update the GPG key [to include the email address](https://security.stackexchange.com/a/261468). |
-| `OTHER_USER` | The signature and GPG key are valid, but the key belongs to a different user than the committer. | Amend the commit to use the correct email address, or amend the commit to use a GPG key associated with your user. |
-| `UNVERIFIED_KEY` | The key associated with the GPG signature has no verified email address associated with the committer. | Add and verify the email to your GitLab profile, [update the GPG key to include the email address](https://security.stackexchange.com/a/261468), or amend the commit to use a different committer email address. |
-| `UNKNOWN_KEY` | The GPG key associated with the GPG signature for this commit is unknown to GitLab. | [Add the GPG key](#add-a-gpg-key-to-your-account) to your GitLab profile. |
-| `MULTIPLE_SIGNATURES` | Multiple GPG or X.509 signatures have been found for the commit. | Amend the commit to use only one GPG or X.509 signature. |
-
-### Secret key not available
-
-If you receive the errors `secret key not available`
-or `gpg: signing failed: secret key not available`, try using `gpg2` instead of `gpg`:
-
-```shell
-git config --global gpg.program gpg2
-```
-
-If your GPG key is password protected and the password entry prompt does not appear,
-add `export GPG_TTY=$(tty)` to your shell's `rc` file (commonly `~/.bashrc` or `~/.zshrc`)
-
-### GPG failed to sign the data
-
-If your GPG key is password protected and you receive the error:
-
-```shell
-error: gpg failed to sign the data
-fatal: failed to write commit object
-```
-
-If the password entry prompt does not appear, add `export GPG_TTY=$(tty)` to your shell's `rc` file
-(commonly `~/.bashrc` or `~/.zshrc`) and restart your terminal.
+<!-- This redirect file can be deleted after <2023-12-01>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index 3d00ceafc05..e97892458b4 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -55,7 +55,7 @@ to a branch in the repository. When you use the command line, you can commit mul
[Revert a commit](../merge_requests/revert_changes.md#revert-a-commit)
from the UI to a selected branch.
- **Sign a commit:**
- Use GPG to [sign your commits](gpg_signed_commits/index.md).
+ Add extra security by [signing your commits](signed_commits/index.md).
## Clone a repository
@@ -73,7 +73,7 @@ into Xcode on macOS.
1. Select **Xcode**.
The project is cloned onto your computer and you are
-prompted to open XCode.
+prompted to open Xcode.
### Clone and open in Visual Studio Code
@@ -216,6 +216,11 @@ To render an OpenAPI file:
1. Go to the OpenAPI file in your repository.
1. Between the **Display source** and **Edit** buttons, select **Display OpenAPI**. When an OpenAPI file is found, it replaces the
**Display rendered file** button.
+1. To display the `operationId` in the operations list, add `displayOperationId=true` to the query string.
+
+NOTE:
+When `displayOperationId` is present in the query string and has _any_ value, it
+evaluates to `true`. This behavior matches the default behavior of Swagger.
## Repository size
diff --git a/doc/user/project/repository/jupyter_notebooks/index.md b/doc/user/project/repository/jupyter_notebooks/index.md
index 70ee841a991..2a1fc0cddf8 100644
--- a/doc/user/project/repository/jupyter_notebooks/index.md
+++ b/doc/user/project/repository/jupyter_notebooks/index.md
@@ -37,7 +37,7 @@ When commits include changes to Jupyter Notebook files, GitLab:
- Enables switching between raw and rendered diffs on the Commit and Compare pages. (Not available on merge request pages.)
- Renders images on the diffs.
-Code suggestions are not available on diffs and merge requests for `.ipynb` files.
+Code Suggestions are not available on diffs and merge requests for `.ipynb` files.
Cleaner notebook diffs are not generated when the notebook is too large.
diff --git a/doc/user/project/repository/managing_large_repositories.md b/doc/user/project/repository/managing_large_repositories.md
index e5c1e4a6614..1d5127b5e08 100644
--- a/doc/user/project/repository/managing_large_repositories.md
+++ b/doc/user/project/repository/managing_large_repositories.md
@@ -1,53 +1,411 @@
---
stage: Systems
-group: Distribution
+group: Gitaly
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-description: "Documentation on large repositories."
---
-# Managing large repositories **(FREE SELF)**
+# Managing monorepos
-GitLab, like any Git based system, is subject to similar performance restraints when it comes to large
-repositories that size into the gigabytes.
+Monorepos have become a regular part of development team workflows. While they have many advantages, monorepos can present performance challenges
+when using them in GitLab. Therefore, you should know:
-In the following sections, we detail several best practices for improving performance with these large repositories on GitLab.
+- What repository characteristics can impact performance.
+- Some tools and steps to optimize monorepos.
-## Large File System (LFS)
+## Impact on performance
-It's *strongly* recommended in any Git system that binary or blob files (for example, packages, audio, video, or graphics) are stored as Large File Storage (LFS) objects. With LFS, the objects are stored externally, such as in Object Storage, which reduces the number and size of objects in the repository. Storing objects in external Object Storage can improve performance.
+Because GitLab is a Git-based system, it is subject to similar performance
+constraints as Git when it comes to large repositories that are gigabytes in
+size.
-To analyze if a repository has large objects, you can use a tool like [`git-sizer`](https://github.com/github/git-sizer) for detailed analysis. This tool shows details about what makes up the repository, and highlights any areas of concern. If any large objects are found, you can then remove them with a tool such as [`git filter-repo`](reducing_the_repo_size_using_git.md).
+Monorepos can be large for [many reasons](https://about.gitlab.com/blog/2022/09/06/speed-up-your-monorepo-workflow-in-git/#characteristics-of-monorepos).
+
+Large repositories pose a performance risk performance when used in GitLab, especially if a large monorepo receives many clones or pushes a day, which is common for them.
+
+Git itself has performance limitations when it comes to handling
+monorepos.
+
+[Gitaly](https://gitlab.com/gitlab-org/gitaly) is our Git storage service built
+on top of [Git](https://git-scm.com/). This means that any limitations of
+Git are experienced in Gitaly, and in turn by end users of GitLab.
+
+## Profiling repositories
+
+Large repositories generally experience performance issues in Git. Knowing why
+your repository is large can help you develop mitigation strategies to avoid
+performance problems.
+
+You can use [`git-sizer`](https://github.com/github/git-sizer) to get a snapshot
+of repository characteristics and discover problem aspects of your monorepo.
+
+For example:
+
+```shell
+Processing blobs: 1652370
+Processing trees: 3396199
+Processing commits: 722647
+Matching commits to trees: 722647
+Processing annotated tags: 534
+Processing references: 539
+| Name | Value | Level of concern |
+| ---------------------------- | --------- | ------------------------------ |
+| Overall repository size | | |
+| * Commits | | |
+| * Count | 723 k | * |
+| * Total size | 525 MiB | ** |
+| * Trees | | |
+| * Count | 3.40 M | ** |
+| * Total size | 9.00 GiB | **** |
+| * Total tree entries | 264 M | ***** |
+| * Blobs | | |
+| * Count | 1.65 M | * |
+| * Total size | 55.8 GiB | ***** |
+| * Annotated tags | | |
+| * Count | 534 | |
+| * References | | |
+| * Count | 539 | |
+| | | |
+| Biggest objects | | |
+| * Commits | | |
+| * Maximum size [1] | 72.7 KiB | * |
+| * Maximum parents [2] | 66 | ****** |
+| * Trees | | |
+| * Maximum entries [3] | 1.68 k | * |
+| * Blobs | | |
+| * Maximum size [4] | 13.5 MiB | * |
+| | | |
+| History structure | | |
+| * Maximum history depth | 136 k | |
+| * Maximum tag depth [5] | 1 | |
+| | | |
+| Biggest checkouts | | |
+| * Number of directories [6] | 4.38 k | ** |
+| * Maximum path depth [7] | 13 | * |
+| * Maximum path length [8] | 134 B | * |
+| * Number of files [9] | 62.3 k | * |
+| * Total size of files [9] | 747 MiB | |
+| * Number of symlinks [10] | 40 | |
+| * Number of submodules | 0 | |
+```
+
+In this example, a few items are raised with a high level of concern. See the
+following sections for information on solving:
+
+- A high number of references.
+- Large blobs.
+
+### Large number of references
+
+A reference in Git (a branch or tag) is used to refer to a commit. Each
+reference is stored as an individual file. If you are curious, you can go
+to any `.git` directory and look under the `refs` directory.
+
+A large number of references can cause performance problems because, with more references,
+object walks that Git does are larger for various operations such as clones, pushes, and
+housekeeping tasks.
+
+#### Mitigation strategies
+
+To mitigate the effects of a large number of references in a monorepo:
+
+- Create an automated process for cleaning up old branches.
+- If certain references don't need to be visible to the client, hide them using the
+ [`transfer.hideRefs`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-transferhideRefs)
+ configuration setting. Because Gitaly ignores any on-server Git configuration, you must change the Gitaly configuration
+ itself in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitaly['configuration'] = {
+ # ...
+ git: {
+ # ...
+ config: [
+ # ...
+ { key: "transfer.hideRefs", value: "refs/namespace_to_hide" },
+ ],
+ },
+ }
+ ```
+
+In Git 2.42.0 and later, different Git operations can skip over hidden references
+when doing an object graph walk.
+
+### Using LFS for large blobs
+
+Because Git is built to handle text data, it doesn't handle large
+binary files efficiently.
+
+Therefore, you should store binary or blob files (for example, packages, audio, video, or graphics)
+as Large File Storage (LFS) objects. With LFS, the objects are stored externally, such as in Object
+Storage, which reduces the number and size of objects in the repository. Storing
+objects in external Object Storage can improve performance.
+
+To analyze if a repository has large objects, you can use a tool like
+[`git-sizer`](https://github.com/github/git-sizer) for detailed analysis. This
+tool shows details about what makes up the repository, and highlights any areas
+of concern. If any large objects are found, you can then remove them with a tool
+such as [`git filter-repo`](reducing_the_repo_size_using_git.md).
For more information, refer to the [Git LFS documentation](../../../topics/git/lfs/index.md).
-## Gitaly Pack Objects Cache
+## Optimizing large repositories for GitLab
+
+Other than modifying your workflow and the actual repository, you can take other
+steps to maximize performance of monorepos with GitLab.
+
+### Gitaly pack-objects cache
+
+For very active repositories with a large number of references and files, consider using the
+[Gitaly pack-objects cache](../../../administration/gitaly/configure_gitaly.md#pack-objects-cache).
+The pack-objects cache:
+
+- Benefits all repositories on your GitLab server.
+- Automatically works for forks.
+
+You should always:
+
+- Fetch incrementally. Do not clone in a way that recreates all of the worktree.
+- Use shallow clones to reduce data transfer. Be aware that this puts more burden on GitLab instance because of higher CPU impact.
+
+Control the clone directory if you heavily use a fork-based workflow. Optimize
+`git clean` flags to ensure that you remove or keep data that might affect or
+speed-up your build.
+
+For more information, see [Pack-objects cache](../../../administration/gitaly/configure_gitaly.md#pack-objects-cache).
+
+### Reduce concurrent clones in CI/CD
+
+Large repositories tend to be monorepos. This usually means that these
+repositories get a lot of traffic not only from users, but from CI/CD.
+
+CI/CD loads tend to be concurrent because pipelines are scheduled during set times.
+As a result, the Git requests against the repositories can spike notably during
+these times and lead to reduced performance for both CI/CD and users alike.
+
+You should reduce CI/CD pipeline concurrency by staggering them to run at different times. For example, a set running at one time and another set running several
+minutes later.
+
+#### Shallow cloning
+
+GitLab and GitLab Runner perform a [shallow clone](../../../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone)
+by default.
+
+Ideally, you should always use `GIT_DEPTH` with a small number
+like 10. This instructs GitLab Runner to perform shallow clones.
+Shallow clones make Git request only the latest set of changes for a given branch,
+up to desired number of commits as defined by the `GIT_DEPTH` variable.
+
+This significantly speeds up fetching of changes from Git repositories,
+especially if the repository has a very long backlog consisting of a number
+of big files because we effectively reduce amount of data transfer.
+The following pipeline configuration example makes the runner shallow clone to fetch only a given branch.
+The runner does not fetch any other branches nor tags.
+
+```yaml
+variables:
+ GIT_DEPTH: 10
+
+test:
+ script:
+ - ls -al
+```
+
+#### Git strategy
+
+By default, GitLab is configured to use the [`fetch` Git strategy](../../../ci/runners/configure_runners.md#git-strategy),
+which is recommended for large repositories.
+This strategy reduces the amount of data to transfer and
+does not really impact the operations that you might do on a repository from CI/CD.
+
+#### Git clone path
+
+[`GIT_CLONE_PATH`](../../../ci/runners/configure_runners.md#custom-build-directories) allows you to
+control where you clone your repositories. This can have implications if you
+heavily use big repositories with a fork-based workflow.
+
+A fork, from the perspective of GitLab Runner, is stored as a separate repository
+with a separate worktree. That means that GitLab Runner cannot optimize the usage
+of worktrees and you might have to instruct GitLab Runner to use that.
+
+In such cases, ideally you want to make the GitLab Runner executor be used only
+for the given project and not shared across different projects to make this
+process more efficient.
+
+The [`GIT_CLONE_PATH`](../../../ci/runners/configure_runners.md#custom-build-directories) must be
+in the directory set in `$CI_BUILDS_DIR`. You can't pick any path from disk.
+
+#### Git clean flags
+
+[`GIT_CLEAN_FLAGS`](../../../ci/runners/configure_runners.md#git-clean-flags) allows you to control
+whether or not you require the `git clean` command to be executed for each CI/CD
+job. By default, GitLab ensures that:
+
+- You have your worktree on the given SHA.
+- Your repository is clean.
+
+[`GIT_CLEAN_FLAGS`](../../../ci/runners/configure_runners.md#git-clean-flags) is disabled when set
+to `none`. On very big repositories, this might be desired because `git
+clean` is disk I/O intensive. Controlling that with `GIT_CLEAN_FLAGS: -ffdx
+-e .build/` (for example) allows you to control and disable removal of some
+directories in the worktree between subsequent runs, which can speed-up
+the incremental builds. This has the biggest effect if you re-use existing
+machines and have an existing worktree that you can re-use for builds.
+
+For exact parameters accepted by
+[`GIT_CLEAN_FLAGS`](../../../ci/runners/configure_runners.md#git-clean-flags), see the documentation
+for [`git clean`](https://git-scm.com/docs/git-clean). The available parameters
+are dependent on the Git version.
+
+#### Git fetch extra flags
+
+[`GIT_FETCH_EXTRA_FLAGS`](../../../ci/runners/configure_runners.md#git-fetch-extra-flags) allows you
+to modify `git fetch` behavior by passing extra flags.
+
+For example, if your project contains a large number of tags that your CI/CD jobs don't rely on,
+you could add [`--no-tags`](https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---no-tags)
+to the extra flags to make your fetches faster and more compact.
+
+Also in the case where you repository does _not_ contain a lot of
+tags, `--no-tags` can [make a big difference in some cases](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/746).
+If your CI/CD builds do not depend on Git tags, setting `--no-tags` is worth trying.
+
+For more information, see the [`GIT_FETCH_EXTRA_FLAGS` documentation](../../../ci/runners/configure_runners.md#git-fetch-extra-flags).
+
+#### Fork-based workflow
+
+Following the guidelines above, let's imagine that we want to:
+
+- Optimize for a big project (more than 50k files in directory).
+- Use forks-based workflow for contributing.
+- Reuse existing worktrees. Have preconfigured runners that are pre-cloned with repositories.
+- Runner assigned only to project and all forks.
+
+Let's consider the following two examples, one using `shell` executor and
+other using `docker` executor.
+
+##### `shell` executor example
+
+Let's assume that you have the following [`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html).
+
+```toml
+concurrent = 4
+
+[[runners]]
+ url = "GITLAB_URL"
+ token = "TOKEN"
+ executor = "shell"
+ builds_dir = "/builds"
+ cache_dir = "/cache"
+
+ [runners.custom_build_dir]
+ enabled = true
+```
+
+This `config.toml`:
+
+- Uses the `shell` executor,
+- Specifies a custom `/builds` directory where all clones are stored.
+- Enables the ability to specify `GIT_CLONE_PATH`,
+- Runs at most 4 jobs at once.
+
+##### `docker` executor example
+
+Let's assume that you have the following [`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html).
+
+```toml
+concurrent = 4
+
+[[runners]]
+ url = "GITLAB_URL"
+ token = "TOKEN"
+ executor = "docker"
+ builds_dir = "/builds"
+ cache_dir = "/cache"
+
+ [runners.docker]
+ volumes = ["/builds:/builds", "/cache:/cache"]
+```
+
+This `config.toml`:
+
+- Uses the `docker` executor,
+- Specifies a custom `/builds` directory on disk where all clones are stored.
+ We host mount the `/builds` directory to make it reusable between subsequent runs
+ and be allowed to override the cloning strategy.
+- Doesn't enable the ability to specify `GIT_CLONE_PATH` as it is enabled by default.
+- Runs at most 4 jobs at once.
+
+##### Our `.gitlab-ci.yml`
+
+Once we have the executor configured, we need to fine tune our `.gitlab-ci.yml`.
+
+Our pipeline is most performant if we use the following `.gitlab-ci.yml`:
+
+```yaml
+variables:
+ GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME
+
+build:
+ script: ls -al
+```
+
+This YAML setting configures a custom clone path. This path makes it possible to re-use worktrees
+between the parent project and forks because we use the same clone path for all forks.
+
+Why use `$CI_CONCURRENT_ID`? The main reason is to ensure that worktrees used are not conflicting
+between projects. The `$CI_CONCURRENT_ID` represents a unique identifier within the given executor.
+When we use it to construct the path, this directory does not conflict
+with other concurrent jobs running.
+
+### Store custom clone options in `config.toml`
+
+Ideally, all job-related configuration should be stored in `.gitlab-ci.yml`.
+However, sometimes it is desirable to make these schemes part of the runner's configuration.
-Gitaly, the service that provides storage for Git repositories, can be configured to cache a short rolling window of Git fetch responses. This is recommended for large repositories as it can notably reduce server load when your server receives lots of fetch traffic.
+In the above example of forks, making this configuration discoverable for users may be preferred,
+but this brings administrative overhead as the `.gitlab-ci.yml` needs to be updated for each branch.
+In such cases, it might be desirable to keep the `.gitlab-ci.yml` clone path agnostic, but make it
+a configuration of the runner.
-Refer to the [Gitaly Pack Objects Cache for more information](../../../administration/gitaly/configure_gitaly.md#pack-objects-cache).
+We can extend our [`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html)
+with the following specification that is used by the runner if `.gitlab-ci.yml` does not override it:
-## Reference Architectures
+```toml
+concurrent = 4
-Large repositories tend to be found in larger organisations with many users. The GitLab Quality and Support teams provide several [Reference Architectures](../../../administration/reference_architectures/index.md) that are the recommended way to deploy GitLab at scale.
+[[runners]]
+ url = "GITLAB_URL"
+ token = "TOKEN"
+ executor = "docker"
+ builds_dir = "/builds"
+ cache_dir = "/cache"
-In these types of setups it's recommended that the GitLab environment used matches a Reference Architecture to improve performance.
+ environment = [
+ "GIT_CLONE_PATH=$CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME"
+ ]
-## Gitaly Cluster
+ [runners.docker]
+ volumes = ["/builds:/builds", "/cache:/cache"]
+```
-Gitaly Cluster can notably improve large repository performance as it holds multiple replicas of the repository across several nodes. As a result, Gitaly Cluster can load balance read requests against those repositories and is also fault-tolerant.
+This makes the cloning configuration to be part of the given runner
+and does not require us to update each `.gitlab-ci.yml`.
-It's recommended for large repositories, however, Gitaly Cluster is a large solution with additional complexity of setup, and management. Refer to the [Gitaly Cluster documentation for more information](../../../administration/gitaly/index.md), specifically the [Before deploying Gitaly Cluster](../../../administration/gitaly/index.md#before-deploying-gitaly-cluster) section.
+### Reference architectures
-## Keep GitLab up to date
+Large repositories tend to be found in larger organisations with many users. The GitLab Quality and Support teams provide several [reference architectures](../../../administration/reference_architectures/index.md) that are the recommended way to deploy GitLab at scale.
-Performance improvements and fixes are added continuously in GitLab. As such, it's recommended you keep GitLab updated to the latest version where possible to benefit from these.
+In these types of setups, the GitLab environment used should match a reference architecture to improve performance.
-## Reduce concurrent clones in CI/CD
+### Gitaly Cluster
-Large repositories tend to be monorepos. This in turn typically means that these repositories get a lot of traffic not only from users, but from CI/CD.
+Gitaly Cluster can notably improve large repository performance because it holds multiple replicas of the repository across several nodes.
+As a result, Gitaly Cluster can load balance read requests against those replicas and is fault-tolerant.
-CI/CD loads tend to be concurrent as pipelines are scheduled during set times. As a result, the Git requests against the repositories can spike notably during these times and lead to reduced performance for both CI and users alike.
+Though Gitaly Cluster is recommended for large repositories, it is a large solution with additional complexity of setup and management. Refer to the
+[Gitaly Cluster documentation for more information](../../../administration/gitaly/index.md), specifically the
+[Before deploying Gitaly Cluster](../../../administration/gitaly/index.md#before-deploying-gitaly-cluster) section.
-When designing CI/CD pipelines, it's advisable to reduce their concurrency by staggering them to run at different times, for example, a set running at one time, and another set running several minutes later.
+### Keep GitLab up to date
-There's several other actions that can be explored to improve CI/CD performance with large repositories. Refer to the [Runner documentation for more information](../../../ci/large_repositories/index.md).
+You should keep GitLab updated to the latest version where possible to benefit from performance improvements and fixes are added continuously to GitLab.
diff --git a/doc/user/project/repository/mirror/bidirectional.md b/doc/user/project/repository/mirror/bidirectional.md
index fade9e1b63c..9d97f53cb43 100644
--- a/doc/user/project/repository/mirror/bidirectional.md
+++ b/doc/user/project/repository/mirror/bidirectional.md
@@ -44,7 +44,7 @@ and [pull](pull.md#pull-from-a-remote-repository) mirrors in the upstream GitLab
To create the webhook in the downstream instance:
1. Create a [personal access token](../../../profile/personal_access_tokens.md) with `API` scope.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Settings > Webhooks**.
1. Add the webhook **URL**, which (in this case) uses the
[Pull Mirror API](../../../../api/projects.md#start-the-pull-mirroring-process-for-a-project)
diff --git a/doc/user/project/repository/mirror/index.md b/doc/user/project/repository/mirror/index.md
index 7ade27e556d..b16197e45b2 100644
--- a/doc/user/project/repository/mirror/index.md
+++ b/doc/user/project/repository/mirror/index.md
@@ -40,7 +40,7 @@ Prerequisites:
- If your mirror connects with `ssh://`, the host key must be detectable on the server,
or you must have a local copy of the key.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Mirroring repositories**.
1. Select **Add new**.
@@ -111,7 +111,7 @@ Prerequisite:
- You must have at least the Maintainer role for the project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Mirroring repositories**.
1. Scroll to **Mirrored repositories** and identify the mirror to update.
@@ -124,9 +124,8 @@ When you create a mirror, you must configure the authentication method for it.
GitLab supports these authentication methods:
- [SSH authentication](#ssh-authentication).
-- Password.
+- Username and password.
-When using password authentication, ensure you specify the username.
For a [project access token](../../settings/project_access_tokens.md) or
[group access token](../../../group/settings/group_access_tokens.md),
use the username (not token name) and the token as the password.
@@ -154,7 +153,7 @@ When you mirror a repository and select the **SSH public key** as your
authentication method, GitLab generates a public key for you. The non-GitLab server
needs this key to establish trust with your GitLab repository. To copy your SSH public key:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Mirroring repositories**.
1. Scroll to **Mirrored repositories**.
diff --git a/doc/user/project/repository/mirror/pull.md b/doc/user/project/repository/mirror/pull.md
index ba54c18f8ee..5b3c76d982a 100644
--- a/doc/user/project/repository/mirror/pull.md
+++ b/doc/user/project/repository/mirror/pull.md
@@ -64,14 +64,13 @@ Prerequisites:
token serves as your GitHub password.
- [GitLab Silent Mode](../../../../administration/silent_mode/index.md) is not enabled.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Mirroring repositories**.
-1. Enter the **Git repository URL**. Include the username
- in the URL, if required: `https://MYUSERNAME@gitlab.com/GROUPNAME/PROJECTNAME.git`
+1. Enter the **Git repository URL**.
NOTE:
- To mirror the `gitlab` repository, use `git@gitlab.com:gitlab-org/gitlab.git`
+ To mirror the `gitlab` repository, use `gitlab.com:gitlab-org/gitlab.git`
or `https://gitlab.com/gitlab-org/gitlab.git`.
1. In **Mirror direction**, select **Pull**.
diff --git a/doc/user/project/repository/mirror/push.md b/doc/user/project/repository/mirror/push.md
index cd4fe68b01b..e18e3631d7f 100644
--- a/doc/user/project/repository/mirror/push.md
+++ b/doc/user/project/repository/mirror/push.md
@@ -37,7 +37,7 @@ and pulling from, remote mirrors.
To set up push mirroring for an existing project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Mirroring repositories**.
1. Enter a repository URL.
@@ -89,12 +89,12 @@ To configure a mirror from GitLab to GitHub:
1. Enter a **Git repository URL** with this format, changing the variables as needed:
```plaintext
- https://USERNAME@github.com/GROUP/PROJECT.git
+ https://github.com/GROUP/PROJECT.git
```
- - `USERNAME`: The username of the owner of the personal access token.
- `GROUP`: The group on GitHub.
- `PROJECT`: The project on GitHub.
+1. For **Username**, enter the username of the owner of the personal access token.
1. For **Password**, enter your GitHub personal access token.
1. Select **Mirror repository**.
@@ -164,19 +164,17 @@ To set up a mirror from GitLab to AWS CodeCommit:
1. Open your new repository, and then select **Clone URL > Clone HTTPS** (not **Clone HTTPS (GRC)**).
1. In GitLab, open the repository to be push-mirrored.
1. Select **Settings > Repository**, and then expand **Mirroring repositories**.
-1. Fill in the **Git repository URL** field using this format:
+1. Fill in the **Git repository URL** field using this format, replacing
+ `<aws-region>` with your AWS region, and
+ `<your_codecommit_repo>` with the name of your repository in CodeCommit:
```plaintext
- https://<your_aws_git_userid>@git-codecommit.<aws-region>.amazonaws.com/v1/repos/<your_codecommit_repo>
+ https://git-codecommit.<aws-region>.amazonaws.com/v1/repos/<your_codecommit_repo>
```
- Replace `<your_aws_git_userid>` with the AWS **special HTTPS Git user ID**
- from the IAM Git credentials created earlier. Replace `<your_codecommit_repo>`
- with the name of your repository in CodeCommit.
-
-1. For **Mirror direction**, select **Push**.
-1. For **Authentication method**, select **Password**. Fill in the **Password** box
- with the special IAM Git clone user ID **password** created earlier in AWS.
+1. For **Authentication method**, select **Username and Password**.
+1. For **Username**, enter the AWS **special HTTPS Git user ID**.
+1. For **Password**, enter the special IAM Git clone user ID password created earlier in AWS.
1. Leave the option **Only mirror protected branches** for CodeCommit. It pushes more
frequently (from every five minutes to every minute).
@@ -202,7 +200,8 @@ If it isn't working correctly, a red `error` tag appears, and shows the error me
[personal access token](../../../profile/personal_access_tokens.md) with `write_repository` scope.
1. On the source GitLab instance:
1. Enter the **Git repository URL** using this format:
- `https://oauth2@<destination host>/<your_gitlab_group_or_name>/<your_gitlab_project>.git`.
+ `https://<destination host>/<your_gitlab_group_or_name>/<your_gitlab_project>.git`.
+ 1. Enter the **Username** `oauth2`.
1. Enter the **Password**. Use the GitLab personal access token created on the
destination GitLab instance.
1. Select **Mirror repository**.
diff --git a/doc/user/project/repository/mirror/troubleshooting.md b/doc/user/project/repository/mirror/troubleshooting.md
index 5817aab5fc7..a83231ceb63 100644
--- a/doc/user/project/repository/mirror/troubleshooting.md
+++ b/doc/user/project/repository/mirror/troubleshooting.md
@@ -67,7 +67,7 @@ If you receive this error after creating a new project using
Check if the repository owner is specified in the URL of your mirrored repository:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Mirroring repositories**.
1. If no repository owner is specified, delete and add the URL again in this format,
@@ -168,7 +168,7 @@ Prerequisites:
To resolve the issue:
1. [Verify the host key](index.md#verify-a-host-key).
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Mirroring repositories**.
1. To refresh the keys, either:
diff --git a/doc/user/project/repository/push_rules.md b/doc/user/project/repository/push_rules.md
index 2756149b5bd..d61d09301a5 100644
--- a/doc/user/project/repository/push_rules.md
+++ b/doc/user/project/repository/push_rules.md
@@ -39,7 +39,7 @@ Prerequisite:
To create global push rules:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Push Rules**.
1. Expand **Push rules**.
@@ -52,7 +52,7 @@ The push rule of an individual project overrides the global push rule.
To override global push rules for a specific project, or to update the rules
for an existing project to match new global push rules:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Repository**.
1. Expand **Push rules**.
1. Set the rule you want.
@@ -126,7 +126,7 @@ Some validation examples:
Use these rules to prevent unintended consequences.
-- **Reject unsigned commits**: Commit must be signed through [GPG](gpg_signed_commits/index.md). This rule
+- **Reject unsigned commits**: Commit must be signed through [GPG](signed_commits/gpg.md). This rule
can block some legitimate commits [created in the Web IDE](#reject-unsigned-commits-push-rule-disables-web-ide),
and allow [unsigned commits created in the GitLab UI](#unsigned-commits-created-in-the-gitlab-ui).
- **Do not allow users to remove Git tags with `git push`**: Users cannot use `git push` to remove Git tags.
@@ -274,7 +274,7 @@ to use them as standard characters in a match condition.
## Related topics
- [Git server hooks](../../../administration/server_hooks.md) (previously called server hooks), to create complex custom push rules
-- [Signing commits with GPG](gpg_signed_commits/index.md)
+- [Signing commits with GPG](signed_commits/gpg.md)
- [Protected branches](../protected_branches.md)
## Troubleshooting
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 590323bfadd..bfe8964a876 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
@@ -26,7 +26,7 @@ you begin. The best way to back up a repository is to
The size of a repository is determined by computing the accumulated size of all files in the repository.
It is similar to executing `du --summarize --bytes` on your repository's
-[hashed storage path](../../../administration/repository_storage_types.md).
+[hashed storage path](../../../administration/repository_storage_paths.md).
## Purge files from repository history
@@ -53,7 +53,7 @@ visible even after they have been removed from the repository.
To purge files from a GitLab repository:
-1. Install either [`git filter-repo`](https://github.com/newren/git-filter-repo/blob/main/INSTALL.md) or
+1. Install [`git filter-repo`](https://github.com/newren/git-filter-repo/blob/main/INSTALL.md) and optionally
[`git-sizer`](https://github.com/github/git-sizer#getting-started)
using a supported package manager or from source.
diff --git a/doc/user/project/repository/signed_commits/gpg.md b/doc/user/project/repository/signed_commits/gpg.md
new file mode 100644
index 00000000000..88f6917d4b6
--- /dev/null
+++ b/doc/user/project/repository/signed_commits/gpg.md
@@ -0,0 +1,284 @@
+---
+stage: Create
+group: Source Code
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Sign commits with GPG **(FREE ALL)**
+
+You can sign the commits you make in a GitLab repository with a
+GPG ([GNU Privacy Guard](https://gnupg.org/)) key.
+
+NOTE:
+GitLab uses the term GPG for all OpenPGP, PGP, and GPG-related material and
+implementations.
+
+For GitLab to consider a commit verified:
+
+- The committer must have a GPG public/private key pair.
+- The committer's public key must be uploaded to their GitLab account.
+- One of the email addresses in the GPG public key must match a **verified** email address
+ used by the committer in GitLab. To keep this address private, use the automatically generated
+ [private commit email address](../../../profile/index.md#use-an-automatically-generated-private-commit-email)
+ GitLab provides in your profile.
+- The committer's email address must match the verified email address from the
+ GPG key.
+
+GitLab uses its own keyring to verify the GPG signature. It does not access any
+public key server.
+
+GPG verified tags are not supported.
+
+For more details about GPG, refer to the [related topics list](#related-topics).
+
+## View a user's public GPG key
+
+To view a user's public GPG key, you can either:
+
+- Go to `https://gitlab.example.com/<USERNAME>.gpg`. GitLab displays the GPG key,
+ if the user has configured one, or a blank page for users without a configured GPG key.
+- Go to the user's profile (such as `https://gitlab.example.com/<USERNAME>`). In the upper-right corner
+ of the user's profile, select **View public GPG keys** (**{key}**).
+
+## Configure commit signing
+
+To sign commits, you must configure both your local machine and your GitLab account:
+
+1. [Create a GPG key](#create-a-gpg-key).
+1. [Add a GPG key to your account](#add-a-gpg-key-to-your-account).
+1. [Associate your GPG key with Git](#associate-your-gpg-key-with-git).
+1. [Sign your Git commits](#sign-your-git-commits).
+
+### Create a GPG key
+
+If you don't already have a GPG key, create one:
+
+1. [Install GPG](https://www.gnupg.org/download/) for your operating system.
+ If your operating system has `gpg2` installed, replace `gpg` with `gpg2` in
+ the commands on this page.
+1. To generate your key pair, run the command appropriate for your version of `gpg`:
+
+ ```shell
+ # Use this command for the default version of GPG, including
+ # Gpg4win on Windows, and most macOS versions:
+ gpg --gen-key
+
+ # Use this command for versions of GPG later than 2.1.17:
+ gpg --full-gen-key
+ ```
+
+1. Select the algorithm your key should use, or press <kbd>Enter</kbd> to select
+ the default option, `RSA and RSA`.
+1. Select the key length, in bits. GitLab recommends 4096-bit keys.
+1. Specify the validity period of your key. This value is subjective, and the
+ default value is no expiration.
+1. To confirm your answers, enter `y`.
+1. Enter your name.
+1. Enter your email address. It must match a
+ [verified email address](../../../profile/index.md#change-the-email-displayed-on-your-commits)
+ in your GitLab account.
+1. Optional. Enter a comment to display in parentheses after your name.
+1. GPG displays the information you've entered so far. Edit the information or press
+ <kbd>O</kbd> (for `Okay`) to continue.
+1. Enter a strong password, then enter it again to confirm it.
+1. To list your private GPG key, run this command, replacing
+ `<EMAIL>` with the email address you used when you generated the key:
+
+ ```shell
+ gpg --list-secret-keys --keyid-format LONG <EMAIL>
+ ```
+
+1. In the output, identify the `sec` line, and copy the GPG key ID. It begins after
+ the `/` character. In this example, the key ID is `30F2B65B9246B6CA`:
+
+ ```plaintext
+ sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
+ D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA
+ uid [ultimate] Mr. Robot <your_email>
+ ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
+ ```
+
+1. To show the associated public key, run this command, replacing `<ID>` with the
+ GPG key ID from the previous step:
+
+ ```shell
+ gpg --armor --export <ID>
+ ```
+
+1. Copy the public key, including the `BEGIN PGP PUBLIC KEY BLOCK` and
+ `END PGP PUBLIC KEY BLOCK` lines. You need this key in the next step.
+
+### Add a GPG key to your account
+
+To add a GPG key to your user settings:
+
+1. Sign in to GitLab.
+1. On the left sidebar, select your avatar.
+1. Select **Edit profile**.
+1. Select **GPG Keys** (**{key}**).
+1. Select **Add new key**.
+1. In **Key**, paste your _public_ key.
+1. To add the key to your account, select **Add key**. GitLab shows the key's
+ fingerprint, email address, and creation date:
+
+ ![GPG key single page](img/profile_settings_gpg_keys_single_key.png)
+
+After you add a key, you cannot edit it. Instead, remove the offending key and re-add it.
+
+### Associate your GPG key with Git
+
+After you [create your GPG key](#create-a-gpg-key) and
+[add it to your account](#add-a-gpg-key-to-your-account), you must configure Git
+to use this key:
+
+1. Run this command to list the private GPG key you just created,
+ replacing `<EMAIL>` with the email address for your key:
+
+ ```shell
+ gpg --list-secret-keys --keyid-format LONG <EMAIL>
+ ```
+
+1. Copy the GPG private key ID that starts with `sec`. In this example, the private key ID is
+ `30F2B65B9246B6CA`:
+
+ ```plaintext
+ sec rsa4096/30F2B65B9246B6CA 2017-08-18 [SC]
+ D5E4F29F3275DC0CDA8FFC8730F2B65B9246B6CA
+ uid [ultimate] Mr. Robot <your_email>
+ ssb rsa4096/B7ABC0813E4028C0 2017-08-18 [E]
+ ```
+
+1. Run this command to configure Git to sign your commits with your key,
+ replacing `<KEY ID>` with your GPG key ID:
+
+ ```shell
+ git config --global user.signingkey <KEY ID>
+ ```
+
+### Sign your Git commits
+
+After you [add your public key to your account](#add-a-gpg-key-to-your-account),
+you can sign individual commits manually, or configure Git to default to signed commits:
+
+- Sign individual Git commits manually:
+ 1. Add `-S` flag to any commit you want to sign:
+
+ ```shell
+ git commit -S -m "My commit message"
+ ```
+
+ 1. Enter the passphrase of your GPG key when asked.
+ 1. Push to GitLab and check that your commits [are verified](../signed_commits/index.md#verify-commits).
+- Sign all Git commits by default by running this command:
+
+ ```shell
+ git config --global commit.gpgsign true
+ ```
+
+#### Set signing key conditionally
+
+If you maintain signing keys for separate purposes, such as work and personal
+use, use an `IncludeIf` statement in your `.gitconfig` file to set which key
+you sign commits with.
+
+Prerequisites:
+
+- Requires Git version 2.13 or later.
+
+1. In the same directory as your main `~/.gitconfig` file, create a second file,
+ such as `.gitconfig-gitlab`.
+1. In your main `~/.gitconfig` file, add your Git settings for work in non-GitLab projects.
+1. Append this information to the end of your main `~/.gitconfig` file:
+
+ ```ini
+ # The contents of this file are included only for GitLab.com URLs
+ [includeIf "hasconfig:remote.*.url:https://gitlab.com/**"]
+
+ # Edit this line to point to your alternate configuration file
+ path = ~/.gitconfig-gitlab
+ ```
+
+1. In your alternate `.gitconfig-gitlab` file, add the configuration overrides to
+ use when you're committing to a GitLab repository. All settings from your
+ main `~/.gitconfig` file are retained unless you explicitly override them.
+ In this example,
+
+ ```ini
+ # Alternate ~/.gitconfig-gitlab file
+ # These values are used for repositories matching the string 'gitlab.com',
+ # and override their corresponding values in ~/.gitconfig
+
+ [user]
+ email = you@example.com
+ signingkey = <KEY ID>
+
+ [commit]
+ gpgsign = true
+ ```
+
+## Revoke a GPG key
+
+If a GPG key becomes compromised, revoke it. Revoking a key changes both future and past commits:
+
+- Past commits signed by this key are marked as unverified.
+- Future commits signed by this key are marked as unverified.
+
+To revoke a GPG key:
+
+1. On the left sidebar, select your avatar.
+1. Select **Edit profile**.
+1. Select **GPG Keys** (**{key}**).
+1. Select **Revoke** next to the GPG key you want to delete.
+
+## Remove a GPG key
+
+When you remove a GPG key from your GitLab account:
+
+- Previous commits signed with this key remain verified.
+- Future commits (including any commits created but not yet pushed) that attempt
+ to use this key are unverified.
+
+To remove a GPG key from your account:
+
+1. On the left sidebar, select your avatar.
+1. Select **Edit profile**.
+1. Select **GPG Keys** (**{key}**).
+1. Select **Remove** (**{remove}**) next to the GPG key you want to delete.
+
+If you must unverify both future and past commits,
+[revoke the associated GPG key](#revoke-a-gpg-key) instead.
+
+## Related topics
+
+- GPG resources:
+ - [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work)
+ - [Managing OpenPGP Keys](https://riseup.net/en/security/message-security/openpgp/gpg-keys)
+ - [OpenPGP Best Practices](https://riseup.net/en/security/message-security/openpgp/best-practices)
+ - [Creating a new GPG key with subkeys](https://www.void.gr/kargig/blog/2013/12/02/creating-a-new-gpg-key-with-subkeys/) (advanced)
+ - [Review existing GPG keys in your instance](../../../../administration/credentials_inventory.md#review-existing-gpg-keys)
+
+## Troubleshooting
+
+### Secret key not available
+
+If you receive the errors `secret key not available`
+or `gpg: signing failed: secret key not available`, try using `gpg2` instead of `gpg`:
+
+```shell
+git config --global gpg.program gpg2
+```
+
+If your GPG key is password protected and the password entry prompt does not appear,
+add `export GPG_TTY=$(tty)` to your shell's `rc` file (commonly `~/.bashrc` or `~/.zshrc`)
+
+### GPG failed to sign the data
+
+If your GPG key is password protected and you receive the error:
+
+```shell
+error: gpg failed to sign the data
+fatal: failed to write commit object
+```
+
+If the password entry prompt does not appear, add `export GPG_TTY=$(tty)` to your shell's `rc` file
+(commonly `~/.bashrc` or `~/.zshrc`) and restart your terminal.
diff --git a/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png b/doc/user/project/repository/signed_commits/img/profile_settings_gpg_keys_single_key.png
index ae0a8696c6c..ae0a8696c6c 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png
+++ b/doc/user/project/repository/signed_commits/img/profile_settings_gpg_keys_single_key.png
Binary files differ
diff --git a/doc/user/project/repository/gpg_signed_commits/img/project_signed_and_unsigned_commits.png b/doc/user/project/repository/signed_commits/img/project_signed_and_unsigned_commits.png
index e1d44f15f3f..e1d44f15f3f 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/project_signed_and_unsigned_commits.png
+++ b/doc/user/project/repository/signed_commits/img/project_signed_and_unsigned_commits.png
Binary files differ
diff --git a/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_unverified_signature.png b/doc/user/project/repository/signed_commits/img/project_signed_commit_unverified_signature.png
index 763a677f94a..763a677f94a 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_unverified_signature.png
+++ b/doc/user/project/repository/signed_commits/img/project_signed_commit_unverified_signature.png
Binary files differ
diff --git a/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_verified_signature.png b/doc/user/project/repository/signed_commits/img/project_signed_commit_verified_signature.png
index 1b6fa3fc2e2..1b6fa3fc2e2 100644
--- a/doc/user/project/repository/gpg_signed_commits/img/project_signed_commit_verified_signature.png
+++ b/doc/user/project/repository/signed_commits/img/project_signed_commit_verified_signature.png
Binary files differ
diff --git a/doc/user/project/repository/signed_commits/index.md b/doc/user/project/repository/signed_commits/index.md
new file mode 100644
index 00000000000..e6632ecb81a
--- /dev/null
+++ b/doc/user/project/repository/signed_commits/index.md
@@ -0,0 +1,64 @@
+---
+stage: Create
+group: Source Code
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Signed commits **(FREE ALL)**
+
+When you add a cryptographic signature to your commit, you provide extra assurance that a commit
+originated from you, rather than an impersonator. If GitLab can verify a commit
+author's identity with a public GPG key, the commit is marked **Verified** in the
+GitLab UI. You can then configure [push rules](../push_rules.md)
+for your project to reject individual commits not signed with GPG, or reject all
+commits from unverified users.
+
+Sign commits with your:
+
+- [SSH key](ssh.md).
+- [GPG key](gpg.md).
+- [Personal x.509 certificate](x509.md).
+
+## Verify commits
+
+You can review commits for a merge request, or for an entire project, to confirm
+they are signed:
+
+1. To review commits for a project:
+ 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. Select **Code > Commits**.
+1. To review commits for a merge request:
+ 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Merge requests**, then select your merge request.
+ 1. Select **Commits**.
+1. Identify the commit you want to review. Signed commits show either a **Verified**
+ or **Unverified** badge, depending on the verification status of the signature.
+ Unsigned commits do not display a badge:
+
+ ![Signed and unsigned commits](img/project_signed_and_unsigned_commits.png)
+
+1. To display the signature details for a commit, select **Verified** to see
+ the fingerprint or key ID:
+
+ ![Signed commit with verified signature](img/project_signed_commit_verified_signature.png)
+
+ ![Signed commit with unverified signature](img/project_signed_commit_unverified_signature.png)
+
+You can also [use the Commits API](../../../../api/commits.md#get-gpg-signature-of-a-commit)
+to check a commit's signature.
+
+## Troubleshooting
+
+### Fix verification problems with signed commits
+
+The verification process for commits signed with GPG keys or X.509 certificates
+can fail for multiple reasons:
+
+| Value | Description | Possible Fixes |
+|-----------------------------|-------------|----------------|
+| `UNVERIFIED` | The commit signature is not valid. | Sign the commit with a valid signature. |
+| `SAME_USER_DIFFERENT_EMAIL` | The GPG key used to sign the commit does not contain the committer email, but does contain a different valid email for the committer. | Amend the commit to use an email address that matches the GPG key, or update the GPG key [to include the email address](https://security.stackexchange.com/a/261468). |
+| `OTHER_USER` | The signature and GPG key are valid, but the key belongs to a different user than the committer. | Amend the commit to use the correct email address, or amend the commit to use a GPG key associated with your user. |
+| `UNVERIFIED_KEY` | The key associated with the GPG signature has no verified email address associated with the committer. | Add and verify the email to your GitLab profile, [update the GPG key to include the email address](https://security.stackexchange.com/a/261468), or amend the commit to use a different committer email address. |
+| `UNKNOWN_KEY` | The GPG key associated with the GPG signature for this commit is unknown to GitLab. | [Add the GPG key](gpg.md#add-a-gpg-key-to-your-account) to your GitLab profile. |
+| `MULTIPLE_SIGNATURES` | Multiple GPG or X.509 signatures have been found for the commit. | Amend the commit to use only one GPG or X.509 signature. |
diff --git a/doc/user/project/repository/signed_commits/ssh.md b/doc/user/project/repository/signed_commits/ssh.md
new file mode 100644
index 00000000000..3572e56da84
--- /dev/null
+++ b/doc/user/project/repository/signed_commits/ssh.md
@@ -0,0 +1,167 @@
+---
+stage: Create
+group: Source Code
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# Sign commits with SSH keys **(FREE ALL)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/343879) in GitLab 15.7 [with a flag](../../../../administration/feature_flags.md) named `ssh_commit_signatures`. Enabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/384202) in GitLab 15.8. Feature flag `ssh_commit_signatures` removed.
+
+When you sign commits with SSH keys, GitLab uses the SSH public keys associated
+with your GitLab account to cryptographically verify the commit signature.
+If successful, GitLab displays a **Verified** label on the commit.
+
+You may use the same SSH keys for `git+ssh` authentication to GitLab
+and signing commit signatures as long as their usage type is **Authentication & Signing**.
+It can be verified on the page for [adding an SSH key to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account).
+
+For more information about managing the SSH keys associated with your GitLab account, see
+[Use SSH keys to communicate with GitLab](../../../ssh.md).
+
+## Configure Git to sign commits with your SSH key
+
+After you [create an SSH key](../../../ssh.md#generate-an-ssh-key-pair) and
+[add it to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account)
+or [generate it using a password manager](../../../ssh.md#generate-an-ssh-key-pair-with-a-password-manager),
+configure Git to begin using the key.
+
+Prerequisites:
+
+- Git 2.34.0 or newer.
+- OpenSSH 8.0 or newer.
+
+ NOTE:
+ OpenSSH 8.7 has broken signing functionality. If you are on OpenSSH 8.7, upgrade to OpenSSH 8.8.
+
+- A SSH key with the usage type of either **Authentication & Signing** or **Signing**.
+ The SSH key must be one of these types:
+ - [ED25519](../../../ssh.md#ed25519-ssh-keys) (recommended)
+ - [RSA](../../../ssh.md#rsa-ssh-keys)
+
+To configure Git to use your key:
+
+1. Configure Git to use SSH for commit signing:
+
+ ```shell
+ git config --global gpg.format ssh
+ ```
+
+1. Specify which SSH key should be used as the signing key, changing the filename
+ (here, `~/.ssh/examplekey`) to the location of your key. The filename may
+ differ, depending on how you generated your key:
+
+ ```shell
+ git config --global user.signingkey ~/.ssh/examplekey
+ ```
+
+## Sign commits with your SSH key
+
+Prerequisites:
+
+- You've [created an SSH key](../../../ssh.md#generate-an-ssh-key-pair).
+- You've [added the key](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account) to your GitLab account.
+- You've [configured Git to sign commits](#configure-git-to-sign-commits-with-your-ssh-key) with your SSH key.
+
+To sign a commit:
+
+1. Use the `-S` flag when signing your commits:
+
+ ```shell
+ git commit -S -m "My commit msg"
+ ```
+
+1. Optional. If you don't want to type the `-S` flag every time you commit, tell
+ Git to sign your commits automatically:
+
+ ```shell
+ git config --global commit.gpgsign true
+ ```
+
+1. If your SSH key is protected, Git prompts you to enter your passphrase.
+1. Push to GitLab.
+1. Check that your commits [are verified](#verify-commits).
+ Signature verification uses the `allowed_signers` file to associate emails and SSH keys.
+ For help configuring this file, read [Verify commits locally](#verify-commits-locally).
+
+## Verify commits
+
+You can verify all types of signed commits
+[in the GitLab UI](../signed_commits/index.md#verify-commits). Commits signed
+with an SSH key can also be verified locally.
+
+### Verify commits locally
+
+To verify commits locally, create an
+[allowed signers file](https://man7.org/linux/man-pages/man1/ssh-keygen.1.html#ALLOWED_SIGNERS)
+for Git to associate SSH public keys with users:
+
+1. Create an allowed signers file:
+
+ ```shell
+ touch allowed_signers
+ ```
+
+1. Configure the `allowed_signers` file in Git:
+
+ ```shell
+ git config gpg.ssh.allowedSignersFile "$(pwd)/allowed_signers"
+ ```
+
+1. Add your entry to the allowed signers file. Use this command to add your
+ email address and public SSH key to the `allowed_signers` file. Replace `<MY_KEY>`
+ with the name of your key, and `~/.ssh/allowed_signers`
+ with the location of your project's `allowed_signers` file:
+
+ ```shell
+ # Modify this line to meet your needs.
+ # Declaring the `git` namespace helps prevent cross-protocol attacks.
+ echo "$(git config --get user.email) namespaces=\"git\" $(cat ~/.ssh/<MY_KEY>.pub)" >> ~/.ssh/allowed_signers
+ ```
+
+ The resulting entry in the `allowed_signers` file contains your email address, key type,
+ and key contents, like this:
+
+ ```plaintext
+ example@gitlab.com namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmaTS47vRmsKyLyK1jlIFJn/i8wdGQ3J49LYyIYJ2hv
+ ```
+
+1. Repeat the previous step for each user who you want to verify signatures for.
+ Consider checking this file in to your Git repository if you want to locally
+ verify signatures for many different contributors.
+
+1. Use `git log --show-signature` to view the signature status for the commits:
+
+ ```shell
+ $ git log --show-signature
+
+ commit e2406b6cd8ebe146835ceab67ff4a5a116e09154 (HEAD -> main, origin/main, origin/HEAD)
+ Good "git" signature for johndoe@example.com with ED25519 key SHA256:Ar44iySGgxic+U6Dph4Z9Rp+KDaix5SFGFawovZLAcc
+ Author: John Doe <johndoe@example.com>
+ Date: Tue Nov 29 06:54:15 2022 -0600
+
+ SSH signed commit
+ ```
+
+## Revoke an SSH key for signing commits
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108344) in GitLab 15.9.
+
+If an SSH key becomes compromised, revoke it. Revoking a key changes both future and past commits:
+
+- Past commits signed by this key are marked as unverified.
+- Future commits signed by this key are marked as unverified.
+
+To revoke an SSH key:
+
+1. On the left sidebar, select your avatar.
+1. Select **Edit profile**.
+1. On the left sidebar, select (**{key}**) **SSH Keys**.
+1. Select **Revoke** next to the SSH key you want to delete.
+
+## Related topics
+
+- [Sign commits and tags with X.509 certificates](../signed_commits/x509.md)
+- [Sign commits with GPG](gpg.md)
+- [Commits API](../../../../api/commits.md)
diff --git a/doc/user/project/repository/signed_commits/x509.md b/doc/user/project/repository/signed_commits/x509.md
new file mode 100644
index 00000000000..17767cbd8f4
--- /dev/null
+++ b/doc/user/project/repository/signed_commits/x509.md
@@ -0,0 +1,362 @@
+---
+stage: Create
+group: Source Code
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Sign commits and tags with X.509 certificates **(FREE ALL)**
+
+[X.509](https://en.wikipedia.org/wiki/X.509) is a standard format for public key
+certificates issued by a public or private Public Key Infrastructure (PKI).
+Personal X.509 certificates are used for authentication or signing purposes
+such as S/MIME (Secure/Multipurpose Internet Mail Extensions).
+However, Git also supports signing of commits and tags with X.509 certificates in a
+similar way as with [GPG (GnuPG, or GNU Privacy Guard)](gpg.md).
+The main difference is the way GitLab determines whether or not the developer's signature is trusted:
+
+- For X.509, a root certificate authority is added to the GitLab trust store.
+ (A trust store is a repository of trusted security certificates.) Combined with
+ any required intermediate certificates in the signature, the developer's certificate
+ can be chained back to a trusted root certificate.
+- For GPG, developers [add their GPG key](gpg.md#add-a-gpg-key-to-your-account)
+ to their account.
+
+GitLab uses its own certificate store and therefore defines the
+[trust chain](https://www.ssl.com/faqs/what-is-a-certificate-authority/).
+For a commit or tag to be *verified* by GitLab:
+
+- The signing certificate email must match a verified email address in GitLab.
+- The GitLab instance must be able to establish a full trust chain
+ from the certificate in the signature to a trusted certificate in the GitLab certificate store.
+ This chain may include intermediate certificates supplied in the signature. You may
+ need to add certificates, such as Certificate Authority root certificates,
+ [to the GitLab certificate store](https://docs.gitlab.com/omnibus/settings/ssl/index.html#install-custom-public-certificates).
+- The signing time must be in the time range of the
+ [certificate validity](https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.5),
+ which is usually up to three years.
+- The signing time is equal to, or later than, the commit time.
+
+If a commit's status has already been determined and stored in the database,
+use the Rake task [to re-check the status](../../../../raketasks/x509_signatures.md).
+Refer to the [Troubleshooting section](#troubleshooting).
+GitLab checks certificate revocation lists on a daily basis with a background worker.
+
+## Limitations
+
+- Certificates without `authorityKeyIdentifier`,
+ `subjectKeyIdentifier`, and `crlDistributionPoints` display as **Unverified**. We
+ recommend using certificates from a PKI that are in line with
+ [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280).
+- If you have more than one email in the Subject Alternative Name list in
+ your signing certificate,
+ [only the first one is used to verify commits](https://gitlab.com/gitlab-org/gitlab/-/issues/336677).
+- The `X509v3 Subject Key Identifier` (SKI) in the issuer certificate and the
+ signing certificate
+ [must be 40 characters long](https://gitlab.com/gitlab-org/gitlab/-/issues/332503).
+ If your SKI is shorter, commits don't show as verified in GitLab, and
+ short subject key identifiers may also
+ [cause errors when accessing the project](https://gitlab.com/gitlab-org/gitlab/-/issues/332464),
+ such as 'An error occurred while loading commit signatures' and
+ `HTTP 422 Unprocessable Entity` errors.
+
+## Configure for signed commits
+
+To sign your commits, tags, or both, you must:
+
+1. [Obtain an X.509 key pair](#obtain-an-x509-key-pair).
+1. [Associate your X.509 certificate with Git](#associate-your-x509-certificate-with-git).
+1. [Sign and verify commits](#sign-and-verify-commits).
+1. [Sign and verify tags](#sign-and-verify-tags).
+
+### Obtain an X.509 key pair
+
+If your organization has Public Key Infrastructure (PKI), that PKI provides
+an S/MIME key. If you do not have an S/MIME key pair from a PKI, you can either
+create your own self-signed pair, or purchase a pair.
+
+### Associate your X.509 certificate with Git
+
+To take advantage of X.509 signing, you need Git 2.19.0 or later. You can
+check your Git version with the command `git --version`.
+
+If you have the correct version, you can proceed to configure Git.
+
+### Linux
+
+Configure Git to use your key for signing:
+
+```shell
+signingkey=$( gpgsm --list-secret-keys | egrep '(key usage|ID)' | grep -B 1 digitalSignature | awk '/ID/ {print $2}' )
+git config --global user.signingkey $signingkey
+git config --global gpg.format x509
+```
+
+#### Windows and macOS
+
+To configure Windows or macOS:
+
+1. Install [S/MIME Sign](https://github.com/github/smimesign) by either:
+ - Downloading the installer.
+ - Running `brew install smimesign` on macOS.
+1. Get the ID of your certificate by running `smimesign --list-keys`.
+1. Set your signing key by running `git config --global user.signingkey <ID>`, replacing `<ID>` with the certificate ID.
+1. Configure X.509 with this command:
+
+ ```shell
+ git config --global gpg.x509.program smimesign
+ git config --global gpg.format x509
+ ```
+
+### Sign and verify commits
+
+After you have [associated your X.509 certificate with Git](#associate-your-x509-certificate-with-git) you
+can sign your commits:
+
+1. When you create a Git commit, add the `-S` flag:
+
+ ```shell
+ git commit -S -m "feat: x509 signed commits"
+ ```
+
+1. Push to GitLab, and check that your commits are verified with the `--show-signature` flag:
+
+ ```shell
+ git log --show-signature
+ ```
+
+1. *If you don't want to type the `-S` flag every time you commit,* run this command
+ for Git to sign your commits every time:
+
+ ```shell
+ git config --global commit.gpgsign true
+ ```
+
+### Sign and verify tags
+
+After you have [associated your X.509 certificate with Git](#associate-your-x509-certificate-with-git) you
+can start signing your tags:
+
+1. When you create a Git tag, add the `-s` flag:
+
+ ```shell
+ git tag -s v1.1.1 -m "My signed tag"
+ ```
+
+1. Push to GitLab and verify your tags are signed with this command:
+
+ ```shell
+ git tag --verify v1.1.1
+ ```
+
+1. *If you don't want to type the `-s` flag every time you tag,* run this command
+ for Git to sign your tags each time:
+
+ ```shell
+ git config --global tag.gpgsign true
+ ```
+
+## Related topics
+
+- [Rake task for X.509 signatures](../../../../raketasks/x509_signatures.md)
+
+## Troubleshooting
+
+For committers without administrator access, review the list of
+[verification problems with signed commits](../signed_commits/index.md#fix-verification-problems-with-signed-commits)
+for possible fixes. The other troubleshooting suggestions on this page require
+administrator access.
+
+### Re-verify commits
+
+GitLab stores the status of any checked commits in the database. You can use a
+Rake task to [check the status of any previously checked commits](../../../../raketasks/x509_signatures.md).
+
+After you make any changes, run this command:
+
+```shell
+sudo gitlab-rake gitlab:x509:update_signatures
+```
+
+### Main verification checks
+
+The code performs
+[these key checks](https://gitlab.com/gitlab-org/gitlab/-/blob/v14.1.0-ee/lib/gitlab/x509/signature.rb#L33),
+which all must return `verified`:
+
+- `x509_certificate.nil?` should be false.
+- `x509_certificate.revoked?` should be false.
+- `verified_signature` should be true.
+- `user.nil?` should be false.
+- `user.verified_emails.include?(@email)` should be true.
+- `certificate_email == @email` should be true.
+
+To investigate why a commit shows as `Unverified`:
+
+1. [Start a Rails console](../../../../administration/operations/rails_console.md#starting-a-rails-console-session):
+
+ ```shell
+ sudo gitlab-rails console
+ ```
+
+1. Identify the project (either by path or ID) and full commit SHA that you're investigating.
+ Use this information to create `signature` to run other checks against:
+
+ ```ruby
+ project = Project.find_by_full_path('group/subgroup/project')
+ project = Project.find_by_id('121')
+ commit = project.repository.commit_by(oid: '87fdbd0f9382781442053b0b76da729344e37653')
+ signedcommit=Gitlab::X509::Commit.new(commit)
+ signature=Gitlab::X509::Signature.new(signedcommit.signature_text, signedcommit.signed_text, commit.committer_email, commit.created_at)
+ ```
+
+ If you make changes to address issues identified running through the checks, restart the
+ Rails console and run though the checks again from the start.
+
+1. Check the certificate on the commit:
+
+ ```ruby
+ signature.x509_certificate.nil?
+ signature.x509_certificate.revoked?
+ ```
+
+ Both checks should return `false`:
+
+ ```ruby
+ > signature.x509_certificate.nil?
+ => false
+ > signature.x509_certificate.revoked?
+ => false
+ ```
+
+ A [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/332503) causes
+ these checks to fail with `Validation failed: Subject key identifier is invalid`.
+
+1. Run a cryptographic check on the signature. The code must return `true`:
+
+ ```ruby
+ signature.verified_signature
+ ```
+
+ If it returns `false` then [investigate this check further](#cryptographic-verification-checks).
+
+1. Confirm the email addresses match on the commit and the signature:
+
+ - The Rails console displays the email addresses being compared.
+ - The final command must return `true`:
+
+ ```ruby
+ sigemail=signature.__send__:certificate_email
+ commitemail=commit.committer_email
+ sigemail == commitemail
+ ```
+
+ A [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/336677) exists:
+ only the first email in the `Subject Alternative Name` list is compared. To
+ display the `Subject Alternative Name` list, run:
+
+ ```ruby
+ signature.__send__ :get_certificate_extension,'subjectAltName'
+ ```
+
+ If the developer's email address is not the first one in the list, this check
+ fails, and the commit is marked `unverified`.
+
+1. The email address on the commit must be associated with an account in GitLab.
+ This check should return `false`:
+
+ ```ruby
+ signature.user.nil?
+ ```
+
+1. Check the email address is associated with a user in GitLab. This check should
+ return a user, such as `#<User id:1234 @user_handle>`:
+
+ ```ruby
+ User.find_by_any_email(commit.committer_email)
+ ```
+
+ If it returns `nil`, the email address is not associated with a user, and the check fails.
+
+1. Confirm the developer's email address is verified. This check must return true:
+
+ ```ruby
+ signature.user.verified_emails.include?(commit.committer_email)
+ ```
+
+ If the previous check returned `nil`, this command displays an error:
+
+ ```plaintext
+ NoMethodError (undefined method `verified_emails' for nil:NilClass)
+ ```
+
+1. The verification status is stored in the database. To display the database record:
+
+ ```ruby
+ pp CommitSignatures::X509CommitSignature.by_commit_sha(commit.sha);nil
+ ```
+
+ If all the previous checks returned the correct values:
+
+ - `verification_status: "unverified"` indicates the database record needs
+ updating. [Use the Rake task](#re-verify-commits).
+
+ - `[]` indicates the database doesn't have a record yet. Locate the commit
+ in GitLab to check the signature and store the result.
+
+#### Cryptographic verification checks
+
+If GitLab determines that `verified_signature` is `false`, investigate the reason
+in the Rails console. These checks require `signature` to exist. Refer to the `signature`
+step of the previous [main verification checks](#main-verification-checks).
+
+1. Check the signature, without checking the issuer, returns `true`:
+
+ ```ruby
+ signature.__send__ :valid_signature?
+ ```
+
+1. Check the signing time and date. This check must return `true`:
+
+ ```ruby
+ signature.__send__ :valid_signing_time?
+ ```
+
+ - The code allows for code signing certificates to expire.
+ - A commit must be signed during the validity period of the certificate,
+ and at or after the commit's datestamp. Display the commit time and
+ certificate details including `not_before`, `not_after` with:
+
+ ```ruby
+ commit.created_at
+ pp signature.__send__ :cert; nil
+ ```
+
+1. Check the signature, including that TLS trust can be established. This check must return `true`:
+
+ ```ruby
+ signature.__send__(:p7).verify([], signature.__send__(:cert_store), signature.__send__(:signed_text))
+ ```
+
+ 1. If this fails, add the missing certificates required to establish trust
+ [to the GitLab certificate store](https://docs.gitlab.com/omnibus/settings/ssl/index.html#install-custom-public-certificates).
+
+ 1. After adding more certificates, (if these troubleshooting steps then pass)
+ run the Rake task to [re-verify commits](#re-verify-commits).
+
+ 1. Display the certificates, including in the signature:
+
+ ```ruby
+ pp signature.__send__(:p7).certificates ; nil
+ ```
+
+Ensure any additional intermediate certificates and the root certificate are added
+to the certificate store. For consistency with how certificate chains are built on
+web servers:
+
+- Git clients that are signing commits should include the certificate
+ and all intermediate certificates in the signature.
+- The GitLab certificate store should only contain the root.
+
+If you remove a root certificate from the GitLab
+trust store, such as when it expires, commit signatures which chain back to that
+root display as `unverified`.
diff --git a/doc/user/project/repository/ssh_signed_commits/index.md b/doc/user/project/repository/ssh_signed_commits/index.md
index d8d798ac651..89e3d811dba 100644
--- a/doc/user/project/repository/ssh_signed_commits/index.md
+++ b/doc/user/project/repository/ssh_signed_commits/index.md
@@ -1,181 +1,11 @@
---
-stage: Create
-group: Source Code
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+redirect_to: '../signed_commits/ssh.md'
+remove_date: '2023-12-01'
---
-# Sign commits with SSH keys **(FREE ALL)**
+This document was moved to [another location](../signed_commits/ssh.md).
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/343879) in GitLab 15.7 [with a flag](../../../../administration/feature_flags.md) named `ssh_commit_signatures`. Enabled by default.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/384202) in GitLab 15.8. Feature flag `ssh_commit_signatures` removed.
-
-Use SSH keys to sign Git commits in the same manner as
-[GPG signed commits](../gpg_signed_commits/index.md). When you sign commits
-with SSH keys, GitLab uses the SSH public keys associated with your
-GitLab account to cryptographically verify the commit signature.
-If successful, GitLab displays a **Verified** label on the commit.
-
-You may use the same SSH keys for `git+ssh` authentication to GitLab
-and signing commit signatures as long as their usage type is **Authentication & Signing**.
-It can be verified on the page for [adding an SSH key to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account).
-
-For more information about managing the SSH keys associated with your GitLab account, see
-[Use SSH keys to communicate with GitLab](../../../ssh.md).
-
-## Configure Git to sign commits with your SSH key
-
-After you [create an SSH key](../../../ssh.md#generate-an-ssh-key-pair) and
-[add it to your GitLab account](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account)
-or [generate it using a password manager](../../../ssh.md#generate-an-ssh-key-pair-with-a-password-manager),
-configure Git to begin using the key.
-
-Prerequisites:
-
-- Git 2.34.0 or newer.
-- OpenSSH 8.0 or newer.
-
- NOTE:
- OpenSSH 8.7 has broken signing functionality. If you are on OpenSSH 8.7, upgrade to OpenSSH 8.8.
-
-- A SSH key with the usage type of either **Authentication & Signing** or **Signing**.
- The SSH key must be one of these types:
- - [ED25519](../../../ssh.md#ed25519-ssh-keys) (recommended)
- - [RSA](../../../ssh.md#rsa-ssh-keys)
-
-To configure Git to use your key:
-
-1. Configure Git to use SSH for commit signing:
-
- ```shell
- git config --global gpg.format ssh
- ```
-
-1. Specify which SSH key should be used as the signing key, changing the filename
- (here, `~/.ssh/examplekey`) to the location of your key. The filename may
- differ, depending on how you generated your key:
-
- ```shell
- git config --global user.signingkey ~/.ssh/examplekey
- ```
-
-## Sign commits with your SSH key
-
-Prerequisites:
-
-- You've [created an SSH key](../../../ssh.md#generate-an-ssh-key-pair).
-- You've [added the key](../../../ssh.md#add-an-ssh-key-to-your-gitlab-account) to your GitLab account.
-- You've [configured Git to sign commits](#configure-git-to-sign-commits-with-your-ssh-key) with your SSH key.
-
-To sign a commit:
-
-1. Use the `-S` flag when signing your commits:
-
- ```shell
- git commit -S -m "My commit msg"
- ```
-
-1. Optional. If you don't want to type the `-S` flag every time you commit, tell
- Git to sign your commits automatically:
-
- ```shell
- git config --global commit.gpgsign true
- ```
-
-1. If your SSH key is protected, Git prompts you to enter your passphrase.
-1. Push to GitLab.
-1. Check that your commits [are verified](#verify-commits).
- Signature verification uses the `allowed_signers` file to associate emails and SSH keys.
- For help configuring this file, read [Verify commits locally](#verify-commits-locally).
-
-## Verify commits
-
-You can review commits for a merge request, or for an entire project, to confirm
-they are signed:
-
-1. To review commits for a project:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
- 1. Select **Code > Commits**.
-1. To review commits for a merge request:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
- 1. On the left sidebar, select **Merge requests**, then select your merge request.
- 1. Select **Commits**.
-1. Identify the commit you want to review. Signed commits show either a **Verified**
- or **Unverified** badge, depending on the verification status of the signature.
- Unsigned commits do not display a badge.
-1. To display the signature details for a commit, select **Verified**. GitLab shows
- the SSH key's fingerprint.
-
-## Verify commits locally
-
-To verify commits locally, create an
-[allowed signers file](https://man7.org/linux/man-pages/man1/ssh-keygen.1.html#ALLOWED_SIGNERS)
-for Git to associate SSH public keys with users:
-
-1. Create an allowed signers file:
-
- ```shell
- touch allowed_signers
- ```
-
-1. Configure the `allowed_signers` file in Git:
-
- ```shell
- git config gpg.ssh.allowedSignersFile "$(pwd)/allowed_signers"
- ```
-
-1. Add your entry to the allowed signers file. Use this command to add your
- email address and public SSH key to the `allowed_signers` file. Replace `<MY_KEY>`
- with the name of your key, and `~/.ssh/allowed_signers`
- with the location of your project's `allowed_signers` file:
-
- ```shell
- # Modify this line to meet your needs.
- # Declaring the `git` namespace helps prevent cross-protocol attacks.
- echo "$(git config --get user.email) namespaces=\"git\" $(cat ~/.ssh/<MY_KEY>.pub)" >> ~/.ssh/allowed_signers
- ```
-
- The resulting entry in the `allowed_signers` file contains your email address, key type,
- and key contents, like this:
-
- ```plaintext
- example@gitlab.com namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmaTS47vRmsKyLyK1jlIFJn/i8wdGQ3J49LYyIYJ2hv
- ```
-
-1. Repeat the previous step for each user who you want to verify signatures for.
- Consider checking this file in to your Git repository if you want to locally
- verify signatures for many different contributors.
-
-1. Use `git log --show-signature` to view the signature status for the commits:
-
- ```shell
- $ git log --show-signature
-
- commit e2406b6cd8ebe146835ceab67ff4a5a116e09154 (HEAD -> main, origin/main, origin/HEAD)
- Good "git" signature for johndoe@example.com with ED25519 key SHA256:Ar44iySGgxic+U6Dph4Z9Rp+KDaix5SFGFawovZLAcc
- Author: John Doe <johndoe@example.com>
- Date: Tue Nov 29 06:54:15 2022 -0600
-
- SSH signed commit
- ```
-
-## Revoke an SSH key for signing commits
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108344) in GitLab 15.9.
-
-If an SSH key becomes compromised, revoke it. Revoking a key changes both future and past commits:
-
-- Past commits signed by this key are marked as unverified.
-- Future commits signed by this key are marked as unverified.
-
-To revoke an SSH key:
-
-1. On the left sidebar, select your avatar.
-1. Select **Edit profile**.
-1. On the left sidebar, select (**{key}**) **SSH Keys**.
-1. Select **Revoke** next to the SSH key you want to delete.
-
-## Related topics
-
-- [Sign commits and tags with X.509 certificates](../x509_signed_commits/index.md)
-- [Sign commits with GPG](../gpg_signed_commits/index.md)
-- [Commits API](../../../../api/commits.md)
+<!-- This redirect file can be deleted after <2023-12-01>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/project/repository/tags/index.md b/doc/user/project/repository/tags/index.md
index 5a01d6f2085..765f5539244 100644
--- a/doc/user/project/repository/tags/index.md
+++ b/doc/user/project/repository/tags/index.md
@@ -44,14 +44,14 @@ In the GitLab UI, each tag displays:
To view all existing tags for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Tags**.
## View tagged commits in the commits list
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18795) in GitLab 15.10.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Commits**.
1. Commits with a tag are labeled with a tag icon (**{tag}**) and the name of the tag.
This example shows a commit tagged `v1.26.0`:
@@ -88,7 +88,7 @@ To create either a lightweight or annotated tag from the command line, and push
To create a tag from the GitLab UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Tags**.
1. Select **New tag**.
1. Provide a **Tag name**.
diff --git a/doc/user/project/repository/web_editor.md b/doc/user/project/repository/web_editor.md
index 121a7b41f54..3acc62186a3 100644
--- a/doc/user/project/repository/web_editor.md
+++ b/doc/user/project/repository/web_editor.md
@@ -25,7 +25,7 @@ for any change you commit through the Web Editor.
To create a text file in the Web Editor:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. From the project dashboard or repository, next to the branch name,
select the plus icon (**{plus}**).
1. From the dropdown list, select **New file**.
@@ -35,7 +35,7 @@ To create a text file in the Web Editor:
### Create a file from a template
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Repository**.
1. Next to the project name, select the plus icon (**{plus}**) to display a
dropdown list, then select **New file** from the list.
@@ -56,7 +56,7 @@ To create a text file in the Web Editor:
To edit a text file in the Web Editor:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Go to your file.
1. In the upper right, select **Edit > Edit single file**.
@@ -105,7 +105,7 @@ To upload a binary file in the Web Editor:
<!-- This list is duplicated at doc/gitlab-basics/add-file.md#from-the-ui -->
<!-- For why we duplicated the info, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111072#note_1267429478 -->
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. From the project dashboard or repository, next to the branch name, select the plus icon (**{plus}**).
1. From the dropdown list, select **Upload file**.
1. Complete the fields. To create a merge request with the uploaded file, ensure the **Start a new merge request with these changes** toggle is turned on.
@@ -115,7 +115,7 @@ To upload a binary file in the Web Editor:
To create a directory in the Web Editor:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. From the project dashboard or repository, next to the branch name, select the plus icon (**{plus}**).
1. From the dropdown list, select **New directory**.
1. Complete the fields. To create a merge request with the new directory, ensure the **Start a new merge request with these changes** toggle is turned on.
@@ -125,7 +125,7 @@ To create a directory in the Web Editor:
To create a [branch](branches/index.md) in the Web Editor:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. From the project dashboard or repository, next to the branch name, select the plus icon (**{plus}**).
1. From the dropdown list, select **New branch**.
1. Complete the fields.
@@ -136,7 +136,7 @@ To create a [branch](branches/index.md) in the Web Editor:
You can create [tags](tags/index.md) to mark milestones such as
production releases and release candidates. To create a tag in the Web Editor:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. From the project dashboard or repository, next to the branch name, select the plus icon (**{plus}**).
1. From the dropdown list, select **New tag**.
1. Complete the fields.
diff --git a/doc/user/project/repository/x509_signed_commits/index.md b/doc/user/project/repository/x509_signed_commits/index.md
index 20860718b43..ae418581820 100644
--- a/doc/user/project/repository/x509_signed_commits/index.md
+++ b/doc/user/project/repository/x509_signed_commits/index.md
@@ -1,366 +1,11 @@
---
-stage: Create
-group: Source Code
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+redirect_to: '../signed_commits/x509.md'
+remove_date: '2023-12-01'
---
-# Sign commits and tags with X.509 certificates **(FREE ALL)**
+This document was moved to [another location](../signed_commits/x509.md).
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17773) in GitLab 12.8.
-
-[X.509](https://en.wikipedia.org/wiki/X.509) is a standard format for public key
-certificates issued by a public or private Public Key Infrastructure (PKI).
-Personal X.509 certificates are used for authentication or signing purposes
-such as S/MIME (Secure/Multipurpose Internet Mail Extensions).
-However, Git also supports signing of commits and tags with X.509 certificates in a
-similar way as with [GPG (GnuPG, or GNU Privacy Guard)](../gpg_signed_commits/index.md).
-The main difference is the way GitLab determines whether or not the developer's signature is trusted:
-
-- For X.509, a root certificate authority is added to the GitLab trust store.
- (A trust store is a repository of trusted security certificates.) Combined with
- any required intermediate certificates in the signature, the developer's certificate
- can be chained back to a trusted root certificate.
-- For GPG, developers [add their GPG key](../gpg_signed_commits/index.md#add-a-gpg-key-to-your-account)
- to their account.
-
-GitLab uses its own certificate store and therefore defines the
-[trust chain](https://www.ssl.com/faqs/what-is-a-certificate-authority/).
-For a commit or tag to be *verified* by GitLab:
-
-- The signing certificate email must match a verified email address in GitLab.
-- The GitLab instance must be able to establish a full trust chain
- from the certificate in the signature to a trusted certificate in the GitLab certificate store.
- This chain may include intermediate certificates supplied in the signature. You may
- need to add certificates, such as Certificate Authority root certificates,
- [to the GitLab certificate store](https://docs.gitlab.com/omnibus/settings/ssl/index.html#install-custom-public-certificates).
-- The signing time must be in the time range of the
- [certificate validity](https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.5),
- which is usually up to three years.
-- The signing time is equal to, or later than, the commit time.
-
-If a commit's status has already been determined and stored in the database,
-use the Rake task [to re-check the status](../../../../raketasks/x509_signatures.md).
-Refer to the [Troubleshooting section](#troubleshooting).
-GitLab checks certificate revocation lists on a daily basis with a background worker.
-
-## Limitations
-
-- Self-signed certificates without `authorityKeyIdentifier`,
- `subjectKeyIdentifier`, and `crlDistributionPoints` are not supported. We
- recommend using certificates from a PKI that are in line with
- [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280).
-- If you have more than one email in the Subject Alternative Name list in
- your signing certificate,
- [only the first one is used to verify commits](https://gitlab.com/gitlab-org/gitlab/-/issues/336677).
-- The `X509v3 Subject Key Identifier` (SKI) in the issuer certificate and the
- signing certificate
- [must be 40 characters long](https://gitlab.com/gitlab-org/gitlab/-/issues/332503).
- If your SKI is shorter, commits don't show as verified in GitLab, and
- short subject key identifiers may also
- [cause errors when accessing the project](https://gitlab.com/gitlab-org/gitlab/-/issues/332464),
- such as 'An error occurred while loading commit signatures' and
- `HTTP 422 Unprocessable Entity` errors.
-
-## Configure for signed commits
-
-To sign your commits, tags, or both, you must:
-
-1. [Obtain an X.509 key pair](#obtain-an-x509-key-pair).
-1. [Associate your X.509 certificate with Git](#associate-your-x509-certificate-with-git).
-1. [Sign and verify commits](#sign-and-verify-commits).
-1. [Sign and verify tags](#sign-and-verify-tags).
-
-### Obtain an X.509 key pair
-
-If your organization has Public Key Infrastructure (PKI), that PKI provides
-an S/MIME key. If you do not have an S/MIME key pair from a PKI, you can either
-create your own self-signed pair, or purchase a pair.
-
-### Associate your X.509 certificate with Git
-
-To take advantage of X.509 signing, you need Git 2.19.0 or later. You can
-check your Git version with the command `git --version`.
-
-If you have the correct version, you can proceed to configure Git.
-
-### Linux
-
-Configure Git to use your key for signing:
-
-```shell
-signingkey=$( gpgsm --list-secret-keys | egrep '(key usage|ID)' | grep -B 1 digitalSignature | awk '/ID/ {print $2}' )
-git config --global user.signingkey $signingkey
-git config --global gpg.format x509
-```
-
-#### Windows and macOS
-
-To configure Windows or macOS:
-
-1. Install [S/MIME Sign](https://github.com/github/smimesign) by either:
- - Downloading the installer.
- - Running `brew install smimesign` on macOS.
-1. Get the ID of your certificate by running `smimesign --list-keys`.
-1. Set your signing key by running `git config --global user.signingkey <ID>`, replacing `<ID>` with the certificate ID.
-1. Configure X.509 with this command:
-
- ```shell
- git config --global gpg.x509.program smimesign
- git config --global gpg.format x509
- ```
-
-### Sign and verify commits
-
-After you have [associated your X.509 certificate with Git](#associate-your-x509-certificate-with-git) you
-can sign your commits:
-
-1. When you create a Git commit, add the `-S` flag:
-
- ```shell
- git commit -S -m "feat: x509 signed commits"
- ```
-
-1. Push to GitLab, and check that your commits are verified with the `--show-signature` flag:
-
- ```shell
- git log --show-signature
- ```
-
-1. *If you don't want to type the `-S` flag every time you commit,* run this command
- for Git to sign your commits every time:
-
- ```shell
- git config --global commit.gpgsign true
- ```
-
-### Sign and verify tags
-
-After you have [associated your X.509 certificate with Git](#associate-your-x509-certificate-with-git) you
-can start signing your tags:
-
-1. When you create a Git tag, add the `-s` flag:
-
- ```shell
- git tag -s v1.1.1 -m "My signed tag"
- ```
-
-1. Push to GitLab and verify your tags are signed with this command:
-
- ```shell
- git tag --verify v1.1.1
- ```
-
-1. *If you don't want to type the `-s` flag every time you tag,* run this command
- for Git to sign your tags each time:
-
- ```shell
- git config --global tag.gpgsign true
- ```
-
-## Related topics
-
-- [Rake task for X.509 signatures](../../../../raketasks/x509_signatures.md)
-- [Sign commits with GPG](../gpg_signed_commits/index.md)
-- [Sign commits with SSH keys](../ssh_signed_commits/index.md)
-
-## Troubleshooting
-
-For committers without administrator access, review the list of
-[verification problems with signed commits](../gpg_signed_commits/index.md#fix-verification-problems-with-signed-commits)
-for possible fixes. The other troubleshooting suggestions on this page require
-administrator access.
-
-### Re-verify commits
-
-GitLab stores the status of any checked commits in the database. You can use a
-Rake task to [check the status of any previously checked commits](../../../../raketasks/x509_signatures.md).
-
-After you make any changes, run this command:
-
-```shell
-sudo gitlab-rake gitlab:x509:update_signatures
-```
-
-### Main verification checks
-
-The code performs
-[these key checks](https://gitlab.com/gitlab-org/gitlab/-/blob/v14.1.0-ee/lib/gitlab/x509/signature.rb#L33),
-which all must return `verified`:
-
-- `x509_certificate.nil?` should be false.
-- `x509_certificate.revoked?` should be false.
-- `verified_signature` should be true.
-- `user.nil?` should be false.
-- `user.verified_emails.include?(@email)` should be true.
-- `certificate_email == @email` should be true.
-
-To investigate why a commit shows as `Unverified`:
-
-1. [Start a Rails console](../../../../administration/operations/rails_console.md#starting-a-rails-console-session):
-
- ```shell
- sudo gitlab-rails console
- ```
-
-1. Identify the project (either by path or ID) and full commit SHA that you're investigating.
- Use this information to create `signature` to run other checks against:
-
- ```ruby
- project = Project.find_by_full_path('group/subgroup/project')
- project = Project.find_by_id('121')
- commit = project.repository.commit_by(oid: '87fdbd0f9382781442053b0b76da729344e37653')
- signedcommit=Gitlab::X509::Commit.new(commit)
- signature=Gitlab::X509::Signature.new(signedcommit.signature_text, signedcommit.signed_text, commit.committer_email, commit.created_at)
- ```
-
- If you make changes to address issues identified running through the checks, restart the
- Rails console and run though the checks again from the start.
-
-1. Check the certificate on the commit:
-
- ```ruby
- signature.x509_certificate.nil?
- signature.x509_certificate.revoked?
- ```
-
- Both checks should return `false`:
-
- ```ruby
- > signature.x509_certificate.nil?
- => false
- > signature.x509_certificate.revoked?
- => false
- ```
-
- A [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/332503) causes
- these checks to fail with `Validation failed: Subject key identifier is invalid`.
-
-1. Run a cryptographic check on the signature. The code must return `true`:
-
- ```ruby
- signature.verified_signature
- ```
-
- If it returns `false` then [investigate this check further](#cryptographic-verification-checks).
-
-1. Confirm the email addresses match on the commit and the signature:
-
- - The Rails console displays the email addresses being compared.
- - The final command must return `true`:
-
- ```ruby
- sigemail=signature.__send__:certificate_email
- commitemail=commit.committer_email
- sigemail == commitemail
- ```
-
- A [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/336677) exists:
- only the first email in the `Subject Alternative Name` list is compared. To
- display the `Subject Alternative Name` list, run:
-
- ```ruby
- signature.__send__ :get_certificate_extension,'subjectAltName'
- ```
-
- If the developer's email address is not the first one in the list, this check
- fails, and the commit is marked `unverified`.
-
-1. The email address on the commit must be associated with an account in GitLab.
- This check should return `false`:
-
- ```ruby
- signature.user.nil?
- ```
-
-1. Check the email address is associated with a user in GitLab. This check should
- return a user, such as `#<User id:1234 @user_handle>`:
-
- ```ruby
- User.find_by_any_email(commit.committer_email)
- ```
-
- If it returns `nil`, the email address is not associated with a user, and the check fails.
-
-1. Confirm the developer's email address is verified. This check must return true:
-
- ```ruby
- signature.user.verified_emails.include?(commit.committer_email)
- ```
-
- If the previous check returned `nil`, this command displays an error:
-
- ```plaintext
- NoMethodError (undefined method `verified_emails' for nil:NilClass)
- ```
-
-1. The verification status is stored in the database. To display the database record:
-
- ```ruby
- pp CommitSignatures::X509CommitSignature.by_commit_sha(commit.sha);nil
- ```
-
- If all the previous checks returned the correct values:
-
- - `verification_status: "unverified"` indicates the database record needs
- updating. [Use the Rake task](#re-verify-commits).
-
- - `[]` indicates the database doesn't have a record yet. Locate the commit
- in GitLab to check the signature and store the result.
-
-#### Cryptographic verification checks
-
-If GitLab determines that `verified_signature` is `false`, investigate the reason
-in the Rails console. These checks require `signature` to exist. Refer to the `signature`
-step of the previous [main verification checks](#main-verification-checks).
-
-1. Check the signature, without checking the issuer, returns `true`:
-
- ```ruby
- signature.__send__ :valid_signature?
- ```
-
-1. Check the signing time and date. This check must return `true`:
-
- ```ruby
- signature.__send__ :valid_signing_time?
- ```
-
- - The code allows for code signing certificates to expire.
- - A commit must be signed during the validity period of the certificate,
- and at or after the commit's datestamp. Display the commit time and
- certificate details including `not_before`, `not_after` with:
-
- ```ruby
- commit.created_at
- pp signature.__send__ :cert; nil
- ```
-
-1. Check the signature, including that TLS trust can be established. This check must return `true`:
-
- ```ruby
- signature.__send__(:p7).verify([], signature.__send__(:cert_store), signature.__send__(:signed_text))
- ```
-
- 1. If this fails, add the missing certificates required to establish trust
- [to the GitLab certificate store](https://docs.gitlab.com/omnibus/settings/ssl/index.html#install-custom-public-certificates).
-
- 1. After adding more certificates, (if these troubleshooting steps then pass)
- run the Rake task to [re-verify commits](#re-verify-commits).
-
- 1. Display the certificates, including in the signature:
-
- ```ruby
- pp signature.__send__(:p7).certificates ; nil
- ```
-
-Ensure any additional intermediate certificates and the root certificate are added
-to the certificate store. For consistency with how certificate chains are built on
-web servers:
-
-- Git clients that are signing commits should include the certificate
- and all intermediate certificates in the signature.
-- The GitLab certificate store should only contain the root.
-
-If you remove a root certificate from the GitLab
-trust store, such as when it expires, commit signatures which chain back to that
-root display as `unverified`.
+<!-- This redirect file can be deleted after <2023-12-01>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/project/requirements/index.md b/doc/user/project/requirements/index.md
index 1f79982bb1f..d99729e3c1b 100644
--- a/doc/user/project/requirements/index.md
+++ b/doc/user/project/requirements/index.md
@@ -137,7 +137,7 @@ You can also sort the requirements list by:
## Allow requirements to be satisfied from a CI job
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2859) in GitLab 13.1.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/215514) ability to specify individual requirements and their statuses in GitLab 13.2.
+> - Ability to specify individual requirements and their statuses [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215514) in GitLab 13.2.
GitLab supports [requirements test reports](../../../ci/yaml/artifacts_reports.md#artifactsreportsrequirements) now.
You can add a job to your CI pipeline that, when triggered, marks all existing
diff --git a/doc/user/project/service_desk/configure.md b/doc/user/project/service_desk/configure.md
new file mode 100644
index 00000000000..f8f4ab44e5a
--- /dev/null
+++ b/doc/user/project/service_desk/configure.md
@@ -0,0 +1,873 @@
+---
+stage: Monitor
+group: Respond
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Configure Service Desk **(FREE ALL)**
+
+By default, Service Desk is active in new projects.
+If it's not active, you can do it in the project's settings.
+
+Prerequisites:
+
+- You must have at least the Maintainer role for the project.
+- On GitLab self-managed, you must [set up incoming email](../../../administration/incoming_email.md#set-it-up)
+ for the GitLab instance. You should use
+ [email sub-addressing](../../../administration/incoming_email.md#email-sub-addressing),
+ but you can also use [catch-all mailboxes](../../../administration/incoming_email.md#catch-all-mailbox).
+ To do this, you must have administrator access.
+- You must have enabled [issue](../settings/index.md#configure-project-features-and-permissions)
+ tracker for the project.
+
+To enable Service Desk in your project:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Service Desk**.
+1. Turn on the **Activate Service Desk** toggle.
+1. Optional. Complete the fields.
+ - [Add a suffix](#configure-a-suffix-for-service-desk-alias-email) to your Service Desk email address.
+ - If the list below **Template to append to all Service Desk issues** is empty, create a
+ [description template](../description_templates.md) in your repository.
+1. Select **Save changes**.
+
+Service Desk is now enabled for this project.
+If anyone sends an email to the address available below **Email address to use for Service Desk**,
+GitLab creates a confidential issue with the email's content.
+
+## Improve your project's security
+
+To improve your Service Desk project's security, you should:
+
+- Put the Service Desk email address behind an alias on your email system so you can change it later.
+- [Enable Akismet](../../../integration/akismet.md) on your GitLab instance to add spam checking to this service.
+ Unblocked email spam can result in many spam issues being created.
+
+## Customize emails sent to the requester
+
+> - Moved from GitLab Premium to GitLab Free in 13.2.
+> - `UNSUBSCRIBE_URL`, `SYSTEM_HEADER`, `SYSTEM_FOOTER`, and `ADDITIONAL_TEXT` placeholders [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/285512) in GitLab 15.9.
+> - `%{ISSUE_DESCRIPTION}` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223751) in GitLab 16.0.
+> - `%{ISSUE_URL}` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/408793) in GitLab 16.1.
+
+An email is sent to the requester when:
+
+- A requester submits a new ticket by emailing Service Desk.
+- A new public comment is added on a Service Desk ticket.
+ - Editing a comment does not trigger a new email to be sent.
+
+You can customize the body of these email messages with Service Desk email templates. The templates
+can include [GitLab Flavored Markdown](../../markdown.md) and [some HTML tags](../../markdown.md#inline-html).
+For example, you can format the emails to include a header and footer in accordance with your
+organization's brand guidelines. You can also include the following placeholders to display dynamic
+content specific to the Service Desk ticket or your GitLab instance.
+
+| Placeholder | `thank_you.md` | `new_note.md` | Description
+| ---------------------- | ---------------------- | ---------------------- | -----------
+| `%{ISSUE_ID}` | **{check-circle}** Yes | **{check-circle}** Yes | Ticket IID.
+| `%{ISSUE_PATH}` | **{check-circle}** Yes | **{check-circle}** Yes | Project path appended with the ticket IID.
+| `%{ISSUE_URL}` | **{check-circle}** Yes | **{check-circle}** Yes | URL of the ticket. External participants can only view the ticket if the project is public and ticket is not confidential (Service Desk tickets are confidential by default).
+| `%{ISSUE_DESCRIPTION}` | **{check-circle}** Yes | **{check-circle}** Yes | Ticket description. If a user has edited the description, it may contain sensitive information that is not intended to be delivered to external participants. Use this placeholder with care and ideally only if you never modify descriptions or your team is aware of the template design.
+| `%{UNSUBSCRIBE_URL}` | **{check-circle}** Yes | **{check-circle}** Yes | Unsubscribe URL.
+| `%{NOTE_TEXT}` | **{dotted-circle}** No | **{check-circle}** Yes | The new comment added to the ticket by a user. Take care to include this placeholder in `new_note.md`. Otherwise, the requesters may never see the updates on their Service Desk ticket.
+
+### Thank you email
+
+When a requester submits an issue through Service Desk, GitLab sends a **thank you email**.
+Without additional configuration, GitLab sends the default thank you email.
+
+To create a custom thank you email template:
+
+1. In the `.gitlab/service_desk_templates/` directory of your repository, create a file named `thank_you.md`.
+1. Populate the Markdown file with text, [GitLab Flavored Markdown](../../markdown.md),
+ [some selected HTML tags](../../markdown.md#inline-html), and placeholders to customize the reply
+ to Service Desk requesters.
+
+### New note email
+
+When a Service Desk ticket has a new public comment, GitLab sends a **new note email**.
+Without additional configuration, GitLab sends the content of the comment.
+
+To keep your emails on brand, you can create a custom new note email template. To do so:
+
+1. In the `.gitlab/service_desk_templates/` directory in your repository, create a file named `new_note.md`.
+1. Populate the Markdown file with text, [GitLab Flavored Markdown](../../markdown.md),
+ [some selected HTML tags](../../markdown.md#inline-html), and placeholders to customize the new note
+ email. Be sure to include the `%{NOTE_TEXT}` in the template to make sure the email recipient can
+ read the contents of the comment.
+
+### Instance-level email header, footer, and additional text **(FREE SELF)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344819) in GitLab 15.9.
+
+Instance administrators can add a header, footer or additional text to the GitLab instance and apply
+them to all emails sent from GitLab. If you're using a custom `thank_you.md` or `new_note.md`, to include
+this content, add `%{SYSTEM_HEADER}`, `%{SYSTEM_FOOTER}`, or `%{ADDITIONAL_TEXT}` to your templates.
+
+For more information, see [System header and footer messages](../../../administration/appearance.md#system-header-and-footer-messages) and [custom additional text](../../../administration/settings/email.md#custom-additional-text).
+
+## Use a custom template for Service Desk tickets
+
+You can select one [description template](../description_templates.md#create-an-issue-template)
+**per project** to be appended to every new Service Desk ticket's description.
+
+You can set description templates at various levels:
+
+- The entire [instance](../description_templates.md#set-instance-level-description-templates).
+- A specific [group or subgroup](../description_templates.md#set-group-level-description-templates).
+- A specific [project](../description_templates.md#set-a-default-template-for-merge-requests-and-issues).
+
+The templates are inherited. For example, in a project, you can also access templates set for the instance, or the project's parent groups.
+
+Prerequisite:
+
+- You must have [created a description template](../description_templates.md#create-an-issue-template).
+
+To use a custom description template with Service Desk:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Service Desk**.
+1. From the dropdown list **Template to append to all Service Desk issues**, search or select your template.
+
+## Support Bot user
+
+Behind the scenes, Service Desk works by the special Support Bot user creating issues.
+This user isn't a [billable user](../../../subscriptions/self_managed/index.md#billable-users),
+so it does not count toward the license limit count.
+
+In GitLab 16.0 and earlier, comments generated from Service Desk emails show `GitLab Support Bot`
+as the author. In [GitLab 16.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/226995),
+these comments show the email of the user who sent the email.
+This feature only applies to comments made in GitLab 16.1 and later.
+
+### Change the Support Bot's display name
+
+You can change the display name of the Support Bot user. Emails sent from Service Desk have
+this name in the `From` header. The default display name is `GitLab Support Bot`.
+
+To edit the custom email display name:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Service Desk**.
+1. Below **Email display name**, enter a new name.
+1. Select **Save changes**.
+
+## Custom email address **(BETA)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/329990) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `service_desk_custom_email`. Disabled by default.
+> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/387003) in GitLab 16.4.
+
+FLAG:
+On self-managed GitLab, by default this feature is available. To hide the feature per project or for
+your entire instance, an administrator can [disable the feature flag](../../../administration/feature_flags.md)
+named `service_desk_custom_email`. On GitLab.com, this feature is available.
+
+Configure a custom email address to show as the sender of your support communication.
+Maintain brand identity and instill confidence among support requesters with a domain they recognize.
+
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, see [a short showcase video](https://youtu.be/_moD5U3xcQs).
+
+This feature is in [Beta](../../../policy/experiment-beta-support.md#beta).
+A Beta feature is not production-ready, but is unlikely to change drastically
+before it's released. We encourage users to try Beta features and provide feedback
+in [the feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/416637).
+
+### Prerequisites
+
+You can use one custom email address for Service Desk per project and it must be unique across the instance.
+
+The custom email address you want to use must meet all of the following requirements:
+
+- You can set up email forwarding.
+- Forwarded emails preserve the original `From` header.
+- Your service provider must support sub-addressing. An email address consists of a local part (everything before `@`) and a
+ domain part.
+
+ With email sub-addressing you can create unique variations of an email address by adding a `+` symbol followed
+ by any text to the local part. Given the email address `support@example.com`, check whether sub-addressing is supported by
+ sending an email to `support+1@example.com`. This email should appear in your mailbox.
+- You have SMTP credentials (ideally, you should use an app password).
+- You must have at least the Maintainer role for the project.
+- Service Desk must be configured for the project.
+
+### Configure a custom email address
+
+Configure and verify a custom email address when you want to send Service Desk emails using your own email address.
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Service Desk** and find the **Custom email** settings.
+1. Note the presented Service Desk address of this project, and with your email provider
+ (for example, Gmail), set up email forwarding from the custom email address to the
+ Service Desk address.
+1. Back in GitLab, complete the fields. **SMTP host** must be resolvable from the network of your GitLab instance (on GitLab self-managed)
+ or the public internet (on GitLab SaaS).
+1. Select **Save & test settings**.
+
+The configuration has been saved and the verification of the custom email address is triggered.
+
+#### Verification
+
+1. After completing the configuration, all project owners and the administrator that saved the custom email configuration receive a notification email.
+1. A verification email is sent using the provided SMTP credentials to the custom email address (with a sub-addressing part).
+ The email contains a verification token. When email forwarding is set up correctly and all prerequisites are met,
+ the email is forwarded to your Service Desk address and ingested by GitLab. GitLab checks the following conditions:
+ 1. GitLab can send an email using the SMTP credentials.
+ 1. Sub-addressing is supported (with the `+verify` sub-addressing part).
+ 1. `From` header is preserved after forwarding.
+ 1. Verification token is correct.
+ 1. Email is received in 30 minutes.
+
+Typically the process takes only a few minutes.
+
+To cancel verification at any time or if it fails, select **Reset custom email**.
+The settings page updates accordingly and reflects the current state of the verification.
+The SMTP credentials are deleted and you can start the configuration again.
+
+On failure and success all project owners and the user who triggered the verification process receive a
+notification email with the verification result.
+If the verification failed, the email also contains details of the reason.
+
+If the verification was successful, the custom email address is ready to be used.
+You can now enable sending Service Desk emails via the custom email address.
+
+### Enable or disable the custom email address
+
+After the custom email address has been verified, administrators can enable or disable sending Service Desk emails via the custom email address.
+
+To **enable** the custom email address:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Service Desk**.
+1. Turn on the **Enable custom email** toggle.
+ Service Desk emails to external participants are sent using the SMTP credentials.
+
+To **disable** the custom email address:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Service Desk**.
+1. Turn off the **Enable custom email** toggle.
+ Because you set up email forwarding, emails to your custom email address continue to be processed and
+ appear as Service Desk Tickets in your project.
+
+ Service Desk emails to external participants are now sent using the GitLab instance's default outgoing
+ email configuration.
+
+### Change or remove custom email configuration
+
+To change the custom email configuration you must reset and remove it and configure custom email again.
+
+To reset the configuration at any step in the process, select **Reset custom email**.
+The credentials are then removed from the database.
+
+### Custom email reply address
+
+External participants can [reply by email](../../../administration/reply_by_email.md) to Service Desk tickets.
+GitLab uses an email reply address with a 32-character reply key that corresponds to the ticket.
+When a custom email is configured, GitLab generates the reply address from that email.
+
+### Known issues
+
+- Some service providers don't allow SMTP connections any more.
+ Often you can enable them on a per user basis and create an app password.
+- Microsoft Exchange doesn't preserve the `From` header, so you cannot use a custom email from the same tenant.
+ As a workaround:
+ - On GitLab SaaS, use a transport rule to forward emails from the custom email address to the Service Desk email
+ from GitLab SaaS. Forwarding to an email address outside the current tenant preserves the original `From` header.
+ - On GitLab self-managed, use a subdomain or a different domain from another service provider for the
+ custom email address or the GitLab instance `incoming_email` or `service_desk_email`.
+
+## Use an additional Service Desk alias email **(FREE SELF)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2201) in GitLab 13.0.
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/284656) in GitLab 13.8.
+
+You can use an additional alias email address for Service Desk on an instance level.
+
+To do this, you must configure
+a [`service_desk_email`](#configure-service-desk-alias-email) in the instance configuration. You can also configure a
+[custom suffix](#configure-a-suffix-for-service-desk-alias-email) that replaces the default `-issue-` portion on the sub-addressing part.
+
+### Configure Service Desk alias email
+
+NOTE:
+On GitLab.com a custom mailbox is already configured with `contact-project+%{key}@incoming.gitlab.com` as the email address. You can still configure the
+[custom suffix](#configure-a-suffix-for-service-desk-alias-email) in project settings.
+
+Service Desk uses the [incoming email](../../../administration/incoming_email.md)
+configuration by default. However, to have a separate email address for Service Desk,
+configure `service_desk_email` with a [custom suffix](#configure-a-suffix-for-service-desk-alias-email)
+in project settings.
+
+Prerequisites:
+
+- The `address` must include the `+%{key}` placeholder in the `user` portion of the address,
+ before the `@`. The placeholder is used to identify the project where the issue should be created.
+- The `service_desk_email` and `incoming_email` configurations must always use separate mailboxes
+ to make sure Service Desk emails are processed correctly.
+
+To configure a custom mailbox for Service Desk with IMAP, add the following snippets to your configuration file in full:
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+NOTE:
+In GitLab 15.3 and later, Service Desk uses `webhook` (internal API call) by default instead of enqueuing a Sidekiq job.
+To use `webhook` on a Linux package installation running GitLab 15.3, you must generate a secret file.
+For more information, see [merge request 5927](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5927).
+In GitLab 15.4, reconfiguring a Linux package installation generates this secret file automatically, so no
+secret file configuration setting is needed.
+For more information, see [issue 1462](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1462).
+
+```ruby
+gitlab_rails['service_desk_email_enabled'] = true
+gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@gmail.com"
+gitlab_rails['service_desk_email_email'] = "project_contact@gmail.com"
+gitlab_rails['service_desk_email_password'] = "[REDACTED]"
+gitlab_rails['service_desk_email_mailbox_name'] = "inbox"
+gitlab_rails['service_desk_email_idle_timeout'] = 60
+gitlab_rails['service_desk_email_log_file'] = "/var/log/gitlab/mailroom/mail_room_json.log"
+gitlab_rails['service_desk_email_host'] = "imap.gmail.com"
+gitlab_rails['service_desk_email_port'] = 993
+gitlab_rails['service_desk_email_ssl'] = true
+gitlab_rails['service_desk_email_start_tls'] = false
+```
+
+:::TabTitle Self-compiled (source)
+
+```yaml
+service_desk_email:
+ enabled: true
+ address: "project_contact+%{key}@example.com"
+ user: "project_contact@example.com"
+ password: "[REDACTED]"
+ host: "imap.gmail.com"
+ delivery_method: webhook
+ secret_file: .gitlab-mailroom-secret
+ port: 993
+ ssl: true
+ start_tls: false
+ log_path: "log/mailroom.log"
+ mailbox: "inbox"
+ idle_timeout: 60
+ expunge_deleted: true
+```
+
+::EndTabs
+
+The configuration options are the same as for configuring
+[incoming email](../../../administration/incoming_email.md#set-it-up).
+
+#### Use encrypted credentials
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108279) in GitLab 15.9.
+
+Instead of having the Service Desk email credentials stored in plaintext in the configuration files, you can optionally
+use an encrypted file for the incoming email credentials.
+
+Prerequisites:
+
+- To use encrypted credentials, you must first enable the
+ [encrypted configuration](../../../administration/encrypted_configuration.md).
+
+The supported configuration items for the encrypted file are:
+
+- `user`
+- `password`
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+1. If initially your Service Desk configuration in `/etc/gitlab/gitlab.rb` looked like:
+
+ ```ruby
+ gitlab_rails['service_desk_email_email'] = "service-desk-email@mail.example.com"
+ gitlab_rails['service_desk_email_password'] = "examplepassword"
+ ```
+
+1. Edit the encrypted secret:
+
+ ```shell
+ sudo gitlab-rake gitlab:service_desk_email:secret:edit EDITOR=vim
+ ```
+
+1. Enter the unencrypted contents of the Service Desk email secret:
+
+ ```yaml
+ user: 'service-desk-email@mail.example.com'
+ password: 'examplepassword'
+ ```
+
+1. Edit `/etc/gitlab/gitlab.rb` and remove the `service_desk` settings for `email` and `password`.
+1. Save the file and reconfigure GitLab:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+:::TabTitle Helm chart (Kubernetes)
+
+Use a Kubernetes secret to store the Service Desk email password. For more information,
+read about [Helm IMAP secrets](https://docs.gitlab.com/charts/installation/secrets.html#imap-password-for-service-desk-emails).
+
+:::TabTitle Docker
+
+1. If initially your Service Desk configuration in `docker-compose.yml` looked like:
+
+ ```yaml
+ version: "3.6"
+ services:
+ gitlab:
+ image: 'gitlab/gitlab-ee:latest'
+ restart: always
+ hostname: 'gitlab.example.com'
+ environment:
+ GITLAB_OMNIBUS_CONFIG: |
+ gitlab_rails['service_desk_email_email'] = "service-desk-email@mail.example.com"
+ gitlab_rails['service_desk_email_password'] = "examplepassword"
+ ```
+
+1. Get inside the container, and edit the encrypted secret:
+
+ ```shell
+ sudo docker exec -t <container_name> bash
+ gitlab-rake gitlab:service_desk_email:secret:edit EDITOR=editor
+ ```
+
+1. Enter the unencrypted contents of the Service Desk secret:
+
+ ```yaml
+ user: 'service-desk-email@mail.example.com'
+ password: 'examplepassword'
+ ```
+
+1. Edit `docker-compose.yml` and remove the `service_desk` settings for `email` and `password`.
+1. Save the file and restart GitLab:
+
+ ```shell
+ docker compose up -d
+ ```
+
+:::TabTitle Self-compiled (source)
+
+1. If initially your Service Desk configuration in `/home/git/gitlab/config/gitlab.yml` looked like:
+
+ ```yaml
+ production:
+ service_desk_email:
+ user: 'service-desk-email@mail.example.com'
+ password: 'examplepassword'
+ ```
+
+1. Edit the encrypted secret:
+
+ ```shell
+ bundle exec rake gitlab:service_desk_email:secret:edit EDITOR=vim RAILS_ENVIRONMENT=production
+ ```
+
+1. Enter the unencrypted contents of the Service Desk secret:
+
+ ```yaml
+ user: 'service-desk-email@mail.example.com'
+ password: 'examplepassword'
+ ```
+
+1. Edit `/home/git/gitlab/config/gitlab.yml` and remove the `service_desk_email:` settings for `user` and `password`.
+1. Save the file and restart GitLab and Mailroom
+
+ ```shell
+ # For systems running systemd
+ sudo systemctl restart gitlab.target
+
+ # For systems running SysV init
+ sudo service gitlab restart
+ ```
+
+::EndTabs
+
+#### Microsoft Graph
+
+> - Alternative Azure deployments [introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5978) in GitLab 14.9.
+> - [Introduced for self-compiled (source) installs](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116494) in GitLab 15.11.
+
+`service_desk_email` can be configured to read Microsoft Exchange Online mailboxes with the Microsoft
+Graph API instead of IMAP. Set up an OAuth 2.0 application for Microsoft Graph
+[the same way as for incoming email](../../../administration/incoming_email.md#microsoft-graph).
+
+::Tabs
+
+:::TabTitle Linux package (Omnibus)
+
+1. Edit `/etc/gitlab/gitlab.rb` and add the following lines, substituting
+ the values you want:
+
+ ```ruby
+ gitlab_rails['service_desk_email_enabled'] = true
+ gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@example.onmicrosoft.com"
+ gitlab_rails['service_desk_email_email'] = "project_contact@example.onmicrosoft.com"
+ gitlab_rails['service_desk_email_mailbox_name'] = "inbox"
+ gitlab_rails['service_desk_email_log_file'] = "/var/log/gitlab/mailroom/mail_room_json.log"
+ gitlab_rails['service_desk_email_inbox_method'] = 'microsoft_graph'
+ gitlab_rails['service_desk_email_inbox_options'] = {
+ 'tenant_id': '<YOUR-TENANT-ID>',
+ 'client_id': '<YOUR-CLIENT-ID>',
+ 'client_secret': '<YOUR-CLIENT-SECRET>',
+ 'poll_interval': 60 # Optional
+ }
+ ```
+
+ For Microsoft Cloud for US Government or [other Azure deployments](https://learn.microsoft.com/en-us/graph/deployments),
+ configure the `azure_ad_endpoint` and `graph_endpoint` settings. For example:
+
+ ```ruby
+ gitlab_rails['service_desk_email_inbox_options'] = {
+ 'azure_ad_endpoint': 'https://login.microsoftonline.us',
+ 'graph_endpoint': 'https://graph.microsoft.us',
+ 'tenant_id': '<YOUR-TENANT-ID>',
+ 'client_id': '<YOUR-CLIENT-ID>',
+ 'client_secret': '<YOUR-CLIENT-SECRET>',
+ 'poll_interval': 60 # Optional
+ }
+ ```
+
+:::TabTitle Helm chart (Kubernetes)
+
+1. Create the [Kubernetes Secret containing the OAuth 2.0 application client secret](https://docs.gitlab.com/charts/installation/secrets.html#microsoft-graph-client-secret-for-service-desk-emails):
+
+ ```shell
+ kubectl create secret generic service-desk-email-client-secret --from-literal=secret=<YOUR-CLIENT_SECRET>
+ ```
+
+1. Create the [Kubernetes Secret for the GitLab Service Desk email auth token](https://docs.gitlab.com/charts/installation/secrets.html#gitlab-service-desk-email-auth-token).
+ Replace `<name>` with the name of the [Helm release name](https://helm.sh/docs/intro/using_helm/) for the GitLab installation:
+
+ ```shell
+ kubectl create secret generic <name>-service-desk-email-auth-token --from-literal=authToken=$(head -c 512 /dev/urandom | LC_CTYPE=C tr -cd 'a-zA-Z0-9' | head -c 32 | base64)
+ ```
+
+1. Export the Helm values:
+
+ ```shell
+ helm get values gitlab > gitlab_values.yaml
+ ```
+
+1. Edit `gitlab_values.yaml`:
+
+ ```yaml
+ global:
+ appConfig:
+ serviceDeskEmail:
+ enabled: true
+ address: "project_contact+%{key}@example.onmicrosoft.com"
+ user: "project_contact@example.onmicrosoft.com"
+ mailbox: inbox
+ inboxMethod: microsoft_graph
+ azureAdEndpoint: https://login.microsoftonline.com
+ graphEndpoint: https://graph.microsoft.com
+ tenantId: "YOUR-TENANT-ID"
+ clientId: "YOUR-CLIENT-ID"
+ clientSecret:
+ secret: service-desk-email-client-secret
+ key: secret
+ deliveryMethod: webhook
+ authToken:
+ secret: <name>-service-desk-email-auth-token
+ key: authToken
+ ```
+
+ For Microsoft Cloud for US Government or [other Azure deployments](https://learn.microsoft.com/en-us/graph/deployments),
+configure the `azureAdEndpoint` and `graphEndpoint` settings. These fields are case-sensitive:
+
+ ```yaml
+ global:
+ appConfig:
+ serviceDeskEmail:
+ [..]
+ azureAdEndpoint: https://login.microsoftonline.us
+ graphEndpoint: https://graph.microsoft.us
+ [..]
+ ```
+
+1. Save the file and apply the new values:
+
+ ```shell
+ helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
+ ```
+
+:::TabTitle Docker
+
+1. Edit `docker-compose.yml`:
+
+ ```yaml
+ version: "3.6"
+ services:
+ gitlab:
+ environment:
+ GITLAB_OMNIBUS_CONFIG: |
+ gitlab_rails['service_desk_email_enabled'] = true
+ gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@example.onmicrosoft.com"
+ gitlab_rails['service_desk_email_email'] = "project_contact@example.onmicrosoft.com"
+ gitlab_rails['service_desk_email_mailbox_name'] = "inbox"
+ gitlab_rails['service_desk_email_log_file'] = "/var/log/gitlab/mailroom/mail_room_json.log"
+ gitlab_rails['service_desk_email_inbox_method'] = 'microsoft_graph'
+ gitlab_rails['service_desk_email_inbox_options'] = {
+ 'tenant_id': '<YOUR-TENANT-ID>',
+ 'client_id': '<YOUR-CLIENT-ID>',
+ 'client_secret': '<YOUR-CLIENT-SECRET>',
+ 'poll_interval': 60 # Optional
+ }
+ ```
+
+1. Save the file and restart GitLab:
+
+ ```shell
+ docker compose up -d
+ ```
+
+For Microsoft Cloud for US Government or [other Azure deployments](https://learn.microsoft.com/en-us/graph/deployments),
+configure the `azure_ad_endpoint` and `graph_endpoint` settings:
+
+1. Edit `docker-compose.yml`:
+
+ ```yaml
+ version: "3.6"
+ services:
+ gitlab:
+ environment:
+ GITLAB_OMNIBUS_CONFIG: |
+ gitlab_rails['service_desk_email_enabled'] = true
+ gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@example.onmicrosoft.com"
+ gitlab_rails['service_desk_email_email'] = "project_contact@example.onmicrosoft.com"
+ gitlab_rails['service_desk_email_mailbox_name'] = "inbox"
+ gitlab_rails['service_desk_email_log_file'] = "/var/log/gitlab/mailroom/mail_room_json.log"
+ gitlab_rails['service_desk_email_inbox_method'] = 'microsoft_graph'
+ gitlab_rails['service_desk_email_inbox_options'] = {
+ 'azure_ad_endpoint': 'https://login.microsoftonline.us',
+ 'graph_endpoint': 'https://graph.microsoft.us',
+ 'tenant_id': '<YOUR-TENANT-ID>',
+ 'client_id': '<YOUR-CLIENT-ID>',
+ 'client_secret': '<YOUR-CLIENT-SECRET>',
+ 'poll_interval': 60 # Optional
+ }
+ ```
+
+1. Save the file and restart GitLab:
+
+ ```shell
+ docker compose up -d
+ ```
+
+:::TabTitle Self-compiled (source)
+
+1. Edit `/home/git/gitlab/config/gitlab.yml`:
+
+ ```yaml
+ service_desk_email:
+ enabled: true
+ address: "project_contact+%{key}@example.onmicrosoft.com"
+ user: "project_contact@example.onmicrosoft.com"
+ mailbox: "inbox"
+ delivery_method: webhook
+ log_path: "log/mailroom.log"
+ secret_file: .gitlab-mailroom-secret
+ inbox_method: "microsoft_graph"
+ inbox_options:
+ tenant_id: "<YOUR-TENANT-ID>"
+ client_id: "<YOUR-CLIENT-ID>"
+ client_secret: "<YOUR-CLIENT-SECRET>"
+ poll_interval: 60 # Optional
+ ```
+
+ For Microsoft Cloud for US Government or [other Azure deployments](https://learn.microsoft.com/en-us/graph/deployments),
+ configure the `azure_ad_endpoint` and `graph_endpoint` settings. For example:
+
+ ```yaml
+ service_desk_email:
+ enabled: true
+ address: "project_contact+%{key}@example.onmicrosoft.com"
+ user: "project_contact@example.onmicrosoft.com"
+ mailbox: "inbox"
+ delivery_method: webhook
+ log_path: "log/mailroom.log"
+ secret_file: .gitlab-mailroom-secret
+ inbox_method: "microsoft_graph"
+ inbox_options:
+ azure_ad_endpoint: "https://login.microsoftonline.us"
+ graph_endpoint: "https://graph.microsoft.us"
+ tenant_id: "<YOUR-TENANT-ID>"
+ client_id: "<YOUR-CLIENT-ID>"
+ client_secret: "<YOUR-CLIENT-SECRET>"
+ poll_interval: 60 # Optional
+ ```
+
+::EndTabs
+
+### Configure a suffix for Service Desk alias email
+
+You can set a custom suffix in your project's Service Desk settings.
+
+A suffix can contain only lowercase letters (`a-z`), numbers (`0-9`), or underscores (`_`).
+
+When configured, the custom suffix creates a new Service Desk email address, consisting of the
+`service_desk_email_address` setting and a key of the format: `<project_full_path>-<custom_suffix>`
+
+Prerequisites:
+
+- You must have configured a [Service Desk alias email](#configure-service-desk-alias-email).
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Service Desk**.
+1. Below **Email address suffix**, enter the suffix to use.
+1. Select **Save changes**.
+
+For example, suppose the `mygroup/myproject` project Service Desk settings has the following configured:
+
+- Email address suffix is set to `support`.
+- Service Desk email address is configured to `contact+%{key}@example.com`.
+
+The Service Desk email address for this project is: `contact+mygroup-myproject-support@example.com`.
+The [incoming email](../../../administration/incoming_email.md) address still works.
+
+If you don't configure a custom suffix, the default project identification is used for identifying
+the project.
+
+## Configure email ingestion in multi-node environments
+
+A multi-node environment is a setup where GitLab is run across multiple servers
+for scalability, fault tolerance, and performance reasons.
+
+GitLab uses a separate process called `mail_room` to ingest new unread emails
+from the `incoming_email` and `service_desk_email` mailboxes.
+
+### Helm chart (Kubernetes)
+
+The [GitLab Helm chart](https://docs.gitlab.com/charts/) is made up of multiple subcharts, and one of them is
+the [Mailroom subchart](https://docs.gitlab.com/charts/charts/gitlab/mailroom/index.html). Configure the
+[common settings for `incoming_email`](https://docs.gitlab.com/charts/installation/command-line-options.html#incoming-email-configuration)
+and the [common settings for `service_desk_email`](https://docs.gitlab.com/charts/installation/command-line-options.html#service-desk-email-configuration).
+
+### Linux package (Omnibus)
+
+In multi-node Linux package installation environments, run `mail_room` only on one node. Run it either on a single
+`rails` node (for example, `application_role`)
+or completely separately.
+
+#### Set up all nodes
+
+1. Add basic configuration for `incoming_email` and `service_desk_email` on every node
+ to render email addresses in the web UI and in generated emails.
+
+ Find the `incoming_email` or `service_desk_email` section in `/etc/gitlab/gitlab.rb`:
+
+ ::Tabs
+
+ :::TabTitle `incoming_email`
+
+ ```ruby
+ gitlab_rails['incoming_email_enabled'] = true
+ gitlab_rails['incoming_email_address'] = "incoming+%{key}@example.com"
+ ```
+
+ :::TabTitle `service_desk_email`
+
+ ```ruby
+ gitlab_rails['service_desk_email_enabled'] = true
+ gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@example.com"
+ ```
+
+ ::EndTabs
+
+1. GitLab offers two methods to transport emails from `mail_room` to the GitLab
+application. You can configure the `delivery_method` for each email setting individually:
+ 1. Recommended: `webhook` (default in GitLab 15.3 and later) sends the email payload via an API POST request to your GitLab
+ application. It uses a shared token to authenticate. If you choose this method,
+ make sure the `mail_room` process can access the API endpoint and distribute the shared
+ token across all application nodes.
+
+ ::Tabs
+
+ :::TabTitle `incoming_email`
+
+ ```ruby
+ gitlab_rails['incoming_email_delivery_method'] = "webhook"
+
+ # The URL that mail_room can contact. You can also use an internal URL or IP,
+ # just make sure mail_room can access the GitLab API via that address.
+ # Do not end with "/".
+ gitlab_rails['incoming_email_gitlab_url'] = "https://gitlab.example.com"
+
+ # The shared secret file that should contain a random token. Make sure it's the same on every node.
+ gitlab_rails['incoming_email_secret_file'] = ".gitlab_mailroom_secret"
+ ```
+
+ :::TabTitle `service_desk_email`
+
+ ```ruby
+ gitlab_rails['service_desk_email_delivery_method'] = "webhook"
+
+ # The URL that mail_room can contact. You can also use an internal URL or IP,
+ # just make sure mail_room can access the GitLab API via that address.
+ # Do not end with "/".
+
+ gitlab_rails['service_desk_email_gitlab_url'] = "https://gitlab.example.com"
+
+ # The shared secret file that should contain a random token. Make sure it's the same on every node.
+ gitlab_rails['service_desk_email_secret_file'] = ".gitlab_mailroom_secret"
+ ```
+
+ ::EndTabs
+
+ 1. [Deprecated in GitLab 16.0 and planned for removal in 17.0)](../../../update/deprecations.md#sidekiq-delivery-method-for-incoming_email-and-service_desk_email-is-deprecated):
+ If you experience issues with the `webhook` setup, use `sidekiq` to deliver the email payload directly to GitLab Sidekiq using Redis.
+
+ ::Tabs
+
+ :::TabTitle `incoming_email`
+
+ ```ruby
+ # It uses the Redis configuration to directly add Sidekiq jobs
+ gitlab_rails['incoming_email_delivery_method'] = "sidekiq"
+ ```
+
+ :::TabTitle `service_desk_email`
+
+ ```ruby
+ # It uses the Redis configuration to directly add Sidekiq jobs
+ gitlab_rails['service_desk_email_delivery_method'] = "sidekiq"
+ ```
+
+ ::EndTabs
+
+1. Disable `mail_room` on all nodes that should not run email ingestion. For example, in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ mailroom['enabled'] = false
+ ```
+
+1. [Reconfigure GitLab](../../../administration/restart_gitlab.md) for the changes to take effect.
+
+#### Set up a single email ingestion node
+
+After setting up all nodes and disabling the `mail_room` process, enable `mail_room` on a single node.
+This node polls the mailboxes for `incoming_email` and `service_desk_email` on a regular basis and
+move new unread emails to GitLab.
+
+1. Choose an existing node that additionally handles email ingestion.
+1. Add [full configuration and credentials](../../../administration/incoming_email.md#configuration-examples)
+ for `incoming_email` and `service_desk_email`.
+1. Enable `mail_room` on this node. For example, in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ mailroom['enabled'] = true
+ ```
+
+1. [Reconfigure GitLab](../../../administration/restart_gitlab.md) on this node for the changes to take effect.
diff --git a/doc/user/project/service_desk/index.md b/doc/user/project/service_desk/index.md
index 208e798bd21..ab807553436 100644
--- a/doc/user/project/service_desk/index.md
+++ b/doc/user/project/service_desk/index.md
@@ -39,870 +39,21 @@ Meanwhile:
- Your team saves time by not having to leave GitLab (or set up integrations) to follow up with
your customer.
-## Configure Service Desk
-
-By default, Service Desk is active in new projects.
-If it's not active, you can do it in the project's settings.
-
-Prerequisites:
-
-- You must have at least the Maintainer role for the project.
-- On GitLab self-managed, you must [set up incoming email](../../../administration/incoming_email.md#set-it-up)
- for the GitLab instance. You should use
- [email sub-addressing](../../../administration/incoming_email.md#email-sub-addressing),
- but you can also use [catch-all mailboxes](../../../administration/incoming_email.md#catch-all-mailbox).
- To do this, you must have administrator access.
-- You must have enabled [issue](../settings/index.md#configure-project-visibility-features-and-permissions)
- tracker for the project.
-
-To enable Service Desk in your project:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Service Desk**.
-1. Turn on the **Activate Service Desk** toggle.
-1. Optional. Complete the fields.
- - [Add a suffix](#configure-a-suffix-for-service-desk-alias-email) to your Service Desk email address.
- - If the list below **Template to append to all Service Desk issues** is empty, create a
- [description template](../description_templates.md) in your repository.
-1. Select **Save changes**.
-
-Service Desk is now enabled for this project.
-If anyone sends an email to the address available below **Email address to use for Service Desk**,
-GitLab creates a confidential issue with the email's content.
-
-### Improve your project's security
-
-To improve your Service Desk project's security, you should:
-
-- Put the Service Desk email address behind an alias on your email system so you can change it later.
-- [Enable Akismet](../../../integration/akismet.md) on your GitLab instance to add spam checking to this service.
- Unblocked email spam can result in many spam issues being created.
-
-### Customize emails sent to the requester
-
-> - Moved from GitLab Premium to GitLab Free in 13.2.
-> - `UNSUBSCRIBE_URL`, `SYSTEM_HEADER`, `SYSTEM_FOOTER`, and `ADDITIONAL_TEXT` placeholders [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/285512) in GitLab 15.9.
-> - `%{ISSUE_DESCRIPTION}` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223751) in GitLab 16.0.
-> - `%{ISSUE_URL}` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/408793) in GitLab 16.1.
-
-An email is sent to the requester when:
-
-- A requester submits a new ticket by emailing Service Desk.
-- A new public comment is added on a Service Desk ticket.
- - Editing a comment does not trigger a new email to be sent.
-
-You can customize the body of these email messages with Service Desk email templates. The templates
-can include [GitLab Flavored Markdown](../../markdown.md) and [some HTML tags](../../markdown.md#inline-html).
-For example, you can format the emails to include a header and footer in accordance with your
-organization's brand guidelines. You can also include the following placeholders to display dynamic
-content specific to the Service Desk ticket or your GitLab instance.
-
-| Placeholder | `thank_you.md` | `new_note.md` | Description
-| ---------------------- | ---------------------- | ---------------------- | -----------
-| `%{ISSUE_ID}` | **{check-circle}** Yes | **{check-circle}** Yes | Ticket IID.
-| `%{ISSUE_PATH}` | **{check-circle}** Yes | **{check-circle}** Yes | Project path appended with the ticket IID.
-| `%{ISSUE_URL}` | **{check-circle}** Yes | **{check-circle}** Yes | URL of the ticket. External participants can only view the ticket if the project is public and ticket is not confidential (Service Desk tickets are confidential by default).
-| `%{ISSUE_DESCRIPTION}` | **{check-circle}** Yes | **{check-circle}** Yes | Ticket description. If a user has edited the description, it may contain sensitive information that is not intended to be delivered to external participants. Use this placeholder with care and ideally only if you never modify descriptions or your team is aware of the template design.
-| `%{UNSUBSCRIBE_URL}` | **{check-circle}** Yes | **{check-circle}** Yes | Unsubscribe URL.
-| `%{NOTE_TEXT}` | **{dotted-circle}** No | **{check-circle}** Yes | The new comment added to the ticket by a user. Take care to include this placeholder in `new_note.md`. Otherwise, the requesters may never see the updates on their Service Desk ticket.
-
-#### Thank you email
-
-When a requester submits an issue through Service Desk, GitLab sends a **thank you email**.
-Without additional configuration, GitLab sends the default thank you email.
-
-To create a custom thank you email template:
-
-1. In the `.gitlab/service_desk_templates/` directory of your repository, create a file named `thank_you.md`.
-1. Populate the Markdown file with text, [GitLab Flavored Markdown](../../markdown.md),
- [some selected HTML tags](../../markdown.md#inline-html), and placeholders to customize the reply
- to Service Desk requesters.
-
-#### New note email
-
-When a Service Desk ticket has a new public comment, GitLab sends a **new note email**.
-Without additional configuration, GitLab sends the content of the comment.
-
-To keep your emails on brand, you can create a custom new note email template. To do so:
-
-1. In the `.gitlab/service_desk_templates/` directory in your repository, create a file named `new_note.md`.
-1. Populate the Markdown file with text, [GitLab Flavored Markdown](../../markdown.md),
- [some selected HTML tags](../../markdown.md#inline-html), and placeholders to customize the new note
- email. Be sure to include the `%{NOTE_TEXT}` in the template to make sure the email recipient can
- read the contents of the comment.
-
-#### Instance-level email header, footer, and additional text **(FREE SELF)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344819) in GitLab 15.9.
-
-Instance administrators can add a header, footer or additional text to the GitLab instance and apply
-them to all emails sent from GitLab. If you're using a custom `thank_you.md` or `new_note.md`, to include
-this content, add `%{SYSTEM_HEADER}`, `%{SYSTEM_FOOTER}`, or `%{ADDITIONAL_TEXT}` to your templates.
-
-For more information, see [System header and footer messages](../../../administration/appearance.md#system-header-and-footer-messages) and [custom additional text](../../../administration/settings/email.md#custom-additional-text).
-
-### Use a custom template for Service Desk tickets
-
-You can select one [description template](../description_templates.md#create-an-issue-template)
-**per project** to be appended to every new Service Desk ticket's description.
-
-You can set description templates at various levels:
-
-- The entire [instance](../description_templates.md#set-instance-level-description-templates).
-- A specific [group or subgroup](../description_templates.md#set-group-level-description-templates).
-- A specific [project](../description_templates.md#set-a-default-template-for-merge-requests-and-issues).
-
-The templates are inherited. For example, in a project, you can also access templates set for the instance, or the project's parent groups.
-
-Prerequisite:
-
-- You must have [created a description template](../description_templates.md#create-an-issue-template).
-
-To use a custom description template with Service Desk:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Service Desk**.
-1. From the dropdown list **Template to append to all Service Desk issues**, search or select your template.
-
-### Support Bot user
-
-Behind the scenes, Service Desk works by the special Support Bot user creating issues.
-This user isn't a [billable user](../../../subscriptions/self_managed/index.md#billable-users),
-so it does not count toward the license limit count.
-
-In GitLab 16.0 and earlier, comments generated from Service Desk emails show `GitLab Support Bot`
-as the author. In [GitLab 16.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/226995),
-these comments show the email of the user who sent the email.
-This feature only applies to comments made in GitLab 16.1 and later.
-
-#### Change the Support Bot's display name
-
-You can change the display name of the Support Bot user. Emails sent from Service Desk have
-this name in the `From` header. The default display name is `GitLab Support Bot`.
-
-To edit the custom email display name:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Service Desk**.
-1. Below **Email display name**, enter a new name.
-1. Select **Save changes**.
-
-### Use an additional Service Desk alias email **(FREE SELF)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2201) in GitLab 13.0.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/284656) in GitLab 13.8.
-
-You can use an additional alias email address for Service Desk on an instance level.
-
-To do this, you must configure
-a [`service_desk_email`](#configure-service-desk-alias-email) in the instance configuration. You can also configure a
-[custom suffix](#configure-a-suffix-for-service-desk-alias-email) that replaces the default `-issue-` portion on the sub-addressing part.
-
-#### Configure Service Desk alias email
-
-NOTE:
-On GitLab.com a custom mailbox is already configured with `contact-project+%{key}@incoming.gitlab.com` as the email address. You can still configure the
-[custom suffix](#configure-a-suffix-for-service-desk-alias-email) in project settings.
-
-Service Desk uses the [incoming email](../../../administration/incoming_email.md)
-configuration by default. However, to have a separate email address for Service Desk,
-configure `service_desk_email` with a [custom suffix](#configure-a-suffix-for-service-desk-alias-email)
-in project settings.
-
-Prerequisites:
-
-- The `address` must include the `+%{key}` placeholder in the `user` portion of the address,
- before the `@`. The placeholder is used to identify the project where the issue should be created.
-- The `service_desk_email` and `incoming_email` configurations must always use separate mailboxes
- to make sure Service Desk emails are processed correctly.
-
-To configure a custom mailbox for Service Desk with IMAP, add the following snippets to your configuration file in full:
-
-::Tabs
-
-:::TabTitle Linux package (Omnibus)
-
-NOTE:
-In GitLab 15.3 and later, Service Desk uses `webhook` (internal API call) by default instead of enqueuing a Sidekiq job.
-To use `webhook` on a Linux package installation running GitLab 15.3, you must generate a secret file.
-For more information, see [merge request 5927](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5927).
-In GitLab 15.4, reconfiguring a Linux package installation generates this secret file automatically, so no
-secret file configuration setting is needed.
-For more information, see [issue 1462](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1462).
-
-```ruby
-gitlab_rails['service_desk_email_enabled'] = true
-gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@gmail.com"
-gitlab_rails['service_desk_email_email'] = "project_contact@gmail.com"
-gitlab_rails['service_desk_email_password'] = "[REDACTED]"
-gitlab_rails['service_desk_email_mailbox_name'] = "inbox"
-gitlab_rails['service_desk_email_idle_timeout'] = 60
-gitlab_rails['service_desk_email_log_file'] = "/var/log/gitlab/mailroom/mail_room_json.log"
-gitlab_rails['service_desk_email_host'] = "imap.gmail.com"
-gitlab_rails['service_desk_email_port'] = 993
-gitlab_rails['service_desk_email_ssl'] = true
-gitlab_rails['service_desk_email_start_tls'] = false
-```
-
-:::TabTitle Self-compiled (source)
-
-```yaml
-service_desk_email:
- enabled: true
- address: "project_contact+%{key}@example.com"
- user: "project_contact@example.com"
- password: "[REDACTED]"
- host: "imap.gmail.com"
- delivery_method: webhook
- secret_file: .gitlab-mailroom-secret
- port: 993
- ssl: true
- start_tls: false
- log_path: "log/mailroom.log"
- mailbox: "inbox"
- idle_timeout: 60
- expunge_deleted: true
-```
-
-::EndTabs
-
-The configuration options are the same as for configuring
-[incoming email](../../../administration/incoming_email.md#set-it-up).
-
-##### Use encrypted credentials
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108279) in GitLab 15.9.
-
-Instead of having the Service Desk email credentials stored in plaintext in the configuration files, you can optionally
-use an encrypted file for the incoming email credentials.
-
-Prerequisites:
-
-- To use encrypted credentials, you must first enable the
- [encrypted configuration](../../../administration/encrypted_configuration.md).
-
-The supported configuration items for the encrypted file are:
-
-- `user`
-- `password`
-
-::Tabs
-
-:::TabTitle Linux package (Omnibus)
-
-1. If initially your Service Desk configuration in `/etc/gitlab/gitlab.rb` looked like:
-
- ```ruby
- gitlab_rails['service_desk_email_email'] = "service-desk-email@mail.example.com"
- gitlab_rails['service_desk_email_password'] = "examplepassword"
- ```
-
-1. Edit the encrypted secret:
-
- ```shell
- sudo gitlab-rake gitlab:service_desk_email:secret:edit EDITOR=vim
- ```
-
-1. Enter the unencrypted contents of the Service Desk email secret:
-
- ```yaml
- user: 'service-desk-email@mail.example.com'
- password: 'examplepassword'
- ```
-
-1. Edit `/etc/gitlab/gitlab.rb` and remove the `service_desk` settings for `email` and `password`.
-1. Save the file and reconfigure GitLab:
-
- ```shell
- sudo gitlab-ctl reconfigure
- ```
-
-:::TabTitle Helm chart (Kubernetes)
-
-Use a Kubernetes secret to store the Service Desk email password. For more information,
-read about [Helm IMAP secrets](https://docs.gitlab.com/charts/installation/secrets.html#imap-password-for-service-desk-emails).
-
-:::TabTitle Docker
-
-1. If initially your Service Desk configuration in `docker-compose.yml` looked like:
-
- ```yaml
- version: "3.6"
- services:
- gitlab:
- image: 'gitlab/gitlab-ee:latest'
- restart: always
- hostname: 'gitlab.example.com'
- environment:
- GITLAB_OMNIBUS_CONFIG: |
- gitlab_rails['service_desk_email_email'] = "service-desk-email@mail.example.com"
- gitlab_rails['service_desk_email_password'] = "examplepassword"
- ```
-
-1. Get inside the container, and edit the encrypted secret:
-
- ```shell
- sudo docker exec -t <container_name> bash
- gitlab-rake gitlab:service_desk_email:secret:edit EDITOR=editor
- ```
-
-1. Enter the unencrypted contents of the Service Desk secret:
-
- ```yaml
- user: 'service-desk-email@mail.example.com'
- password: 'examplepassword'
- ```
-
-1. Edit `docker-compose.yml` and remove the `service_desk` settings for `email` and `password`.
-1. Save the file and restart GitLab:
-
- ```shell
- docker compose up -d
- ```
-
-:::TabTitle Self-compiled (source)
-
-1. If initially your Service Desk configuration in `/home/git/gitlab/config/gitlab.yml` looked like:
-
- ```yaml
- production:
- service_desk_email:
- user: 'service-desk-email@mail.example.com'
- password: 'examplepassword'
- ```
-
-1. Edit the encrypted secret:
-
- ```shell
- bundle exec rake gitlab:service_desk_email:secret:edit EDITOR=vim RAILS_ENVIRONMENT=production
- ```
-
-1. Enter the unencrypted contents of the Service Desk secret:
-
- ```yaml
- user: 'service-desk-email@mail.example.com'
- password: 'examplepassword'
- ```
-
-1. Edit `/home/git/gitlab/config/gitlab.yml` and remove the `service_desk_email:` settings for `user` and `password`.
-1. Save the file and restart GitLab and Mailroom
-
- ```shell
- # For systems running systemd
- sudo systemctl restart gitlab.target
-
- # For systems running SysV init
- sudo service gitlab restart
- ```
-
-::EndTabs
-
-##### Microsoft Graph
-
-> - Alternative Azure deployments [introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5978) in GitLab 14.9.
-> - [Introduced for self-compiled (source) installs](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116494) in GitLab 15.11.
-
-`service_desk_email` can be configured to read Microsoft Exchange Online mailboxes with the Microsoft
-Graph API instead of IMAP. Set up an OAuth 2.0 application for Microsoft Graph
-[the same way as for incoming email](../../../administration/incoming_email.md#microsoft-graph).
-
-::Tabs
-
-:::TabTitle Linux package (Omnibus)
-
-1. Edit `/etc/gitlab/gitlab.rb` and add the following lines, substituting
- the values you want:
-
- ```ruby
- gitlab_rails['service_desk_email_enabled'] = true
- gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@example.onmicrosoft.com"
- gitlab_rails['service_desk_email_email'] = "project_contact@example.onmicrosoft.com"
- gitlab_rails['service_desk_email_mailbox_name'] = "inbox"
- gitlab_rails['service_desk_email_log_file'] = "/var/log/gitlab/mailroom/mail_room_json.log"
- gitlab_rails['service_desk_email_inbox_method'] = 'microsoft_graph'
- gitlab_rails['service_desk_email_inbox_options'] = {
- 'tenant_id': '<YOUR-TENANT-ID>',
- 'client_id': '<YOUR-CLIENT-ID>',
- 'client_secret': '<YOUR-CLIENT-SECRET>',
- 'poll_interval': 60 # Optional
- }
- ```
-
- For Microsoft Cloud for US Government or [other Azure deployments](https://learn.microsoft.com/en-us/graph/deployments),
- configure the `azure_ad_endpoint` and `graph_endpoint` settings. For example:
-
- ```ruby
- gitlab_rails['service_desk_email_inbox_options'] = {
- 'azure_ad_endpoint': 'https://login.microsoftonline.us',
- 'graph_endpoint': 'https://graph.microsoft.us',
- 'tenant_id': '<YOUR-TENANT-ID>',
- 'client_id': '<YOUR-CLIENT-ID>',
- 'client_secret': '<YOUR-CLIENT-SECRET>',
- 'poll_interval': 60 # Optional
- }
- ```
-
-:::TabTitle Helm chart (Kubernetes)
-
-1. Create the [Kubernetes Secret containing the OAuth 2.0 application client secret](https://docs.gitlab.com/charts/installation/secrets.html#microsoft-graph-client-secret-for-service-desk-emails):
-
- ```shell
- kubectl create secret generic service-desk-email-client-secret --from-literal=secret=<YOUR-CLIENT_SECRET>
- ```
-
-1. Create the [Kubernetes Secret for the GitLab Service Desk email auth token](https://docs.gitlab.com/charts/installation/secrets.html#gitlab-service-desk-email-auth-token).
- Replace `<name>` with the name of the [Helm release name](https://helm.sh/docs/intro/using_helm/) for the GitLab installation:
-
- ```shell
- kubectl create secret generic <name>-service-desk-email-auth-token --from-literal=authToken=$(head -c 512 /dev/urandom | LC_CTYPE=C tr -cd 'a-zA-Z0-9' | head -c 32 | base64)
- ```
-
-1. Export the Helm values:
-
- ```shell
- helm get values gitlab > gitlab_values.yaml
- ```
-
-1. Edit `gitlab_values.yaml`:
-
- ```yaml
- global:
- appConfig:
- serviceDeskEmail:
- enabled: true
- address: "project_contact+%{key}@example.onmicrosoft.com"
- user: "project_contact@example.onmicrosoft.com"
- mailbox: inbox
- inboxMethod: microsoft_graph
- azureAdEndpoint: https://login.microsoftonline.com
- graphEndpoint: https://graph.microsoft.com
- tenantId: "YOUR-TENANT-ID"
- clientId: "YOUR-CLIENT-ID"
- clientSecret:
- secret: service-desk-email-client-secret
- key: secret
- deliveryMethod: webhook
- authToken:
- secret: <name>-service-desk-email-auth-token
- key: authToken
- ```
-
- For Microsoft Cloud for US Government or [other Azure deployments](https://learn.microsoft.com/en-us/graph/deployments),
-configure the `azureAdEndpoint` and `graphEndpoint` settings. These fields are case-sensitive:
-
- ```yaml
- global:
- appConfig:
- serviceDeskEmail:
- [..]
- azureAdEndpoint: https://login.microsoftonline.us
- graphEndpoint: https://graph.microsoft.us
- [..]
- ```
-
-1. Save the file and apply the new values:
-
- ```shell
- helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
- ```
-
-:::TabTitle Docker
-
-1. Edit `docker-compose.yml`:
-
- ```yaml
- version: "3.6"
- services:
- gitlab:
- environment:
- GITLAB_OMNIBUS_CONFIG: |
- gitlab_rails['service_desk_email_enabled'] = true
- gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@example.onmicrosoft.com"
- gitlab_rails['service_desk_email_email'] = "project_contact@example.onmicrosoft.com"
- gitlab_rails['service_desk_email_mailbox_name'] = "inbox"
- gitlab_rails['service_desk_email_log_file'] = "/var/log/gitlab/mailroom/mail_room_json.log"
- gitlab_rails['service_desk_email_inbox_method'] = 'microsoft_graph'
- gitlab_rails['service_desk_email_inbox_options'] = {
- 'tenant_id': '<YOUR-TENANT-ID>',
- 'client_id': '<YOUR-CLIENT-ID>',
- 'client_secret': '<YOUR-CLIENT-SECRET>',
- 'poll_interval': 60 # Optional
- }
- ```
-
-1. Save the file and restart GitLab:
-
- ```shell
- docker compose up -d
- ```
-
-For Microsoft Cloud for US Government or [other Azure deployments](https://learn.microsoft.com/en-us/graph/deployments),
-configure the `azure_ad_endpoint` and `graph_endpoint` settings:
-
-1. Edit `docker-compose.yml`:
-
- ```yaml
- version: "3.6"
- services:
- gitlab:
- environment:
- GITLAB_OMNIBUS_CONFIG: |
- gitlab_rails['service_desk_email_enabled'] = true
- gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@example.onmicrosoft.com"
- gitlab_rails['service_desk_email_email'] = "project_contact@example.onmicrosoft.com"
- gitlab_rails['service_desk_email_mailbox_name'] = "inbox"
- gitlab_rails['service_desk_email_log_file'] = "/var/log/gitlab/mailroom/mail_room_json.log"
- gitlab_rails['service_desk_email_inbox_method'] = 'microsoft_graph'
- gitlab_rails['service_desk_email_inbox_options'] = {
- 'azure_ad_endpoint': 'https://login.microsoftonline.us',
- 'graph_endpoint': 'https://graph.microsoft.us',
- 'tenant_id': '<YOUR-TENANT-ID>',
- 'client_id': '<YOUR-CLIENT-ID>',
- 'client_secret': '<YOUR-CLIENT-SECRET>',
- 'poll_interval': 60 # Optional
- }
- ```
-
-1. Save the file and restart GitLab:
-
- ```shell
- docker compose up -d
- ```
-
-:::TabTitle Self-compiled (source)
-
-1. Edit `/home/git/gitlab/config/gitlab.yml`:
-
- ```yaml
- service_desk_email:
- enabled: true
- address: "project_contact+%{key}@example.onmicrosoft.com"
- user: "project_contact@example.onmicrosoft.com"
- mailbox: "inbox"
- delivery_method: webhook
- log_path: "log/mailroom.log"
- secret_file: .gitlab-mailroom-secret
- inbox_method: "microsoft_graph"
- inbox_options:
- tenant_id: "<YOUR-TENANT-ID>"
- client_id: "<YOUR-CLIENT-ID>"
- client_secret: "<YOUR-CLIENT-SECRET>"
- poll_interval: 60 # Optional
- ```
-
- For Microsoft Cloud for US Government or [other Azure deployments](https://learn.microsoft.com/en-us/graph/deployments),
- configure the `azure_ad_endpoint` and `graph_endpoint` settings. For example:
-
- ```yaml
- service_desk_email:
- enabled: true
- address: "project_contact+%{key}@example.onmicrosoft.com"
- user: "project_contact@example.onmicrosoft.com"
- mailbox: "inbox"
- delivery_method: webhook
- log_path: "log/mailroom.log"
- secret_file: .gitlab-mailroom-secret
- inbox_method: "microsoft_graph"
- inbox_options:
- azure_ad_endpoint: "https://login.microsoftonline.us"
- graph_endpoint: "https://graph.microsoft.us"
- tenant_id: "<YOUR-TENANT-ID>"
- client_id: "<YOUR-CLIENT-ID>"
- client_secret: "<YOUR-CLIENT-SECRET>"
- poll_interval: 60 # Optional
- ```
-
-::EndTabs
-
-#### Configure a suffix for Service Desk alias email
-
-You can set a custom suffix in your project's Service Desk settings.
-
-A suffix can contain only lowercase letters (`a-z`), numbers (`0-9`), or underscores (`_`).
-
-When configured, the custom suffix creates a new Service Desk email address, consisting of the
-`service_desk_email_address` setting and a key of the format: `<project_full_path>-<custom_suffix>`
-
-Prerequisites:
-
-- You must have configured a [Service Desk alias email](#configure-service-desk-alias-email).
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Service Desk**.
-1. Below **Email address suffix**, enter the suffix to use.
-1. Select **Save changes**.
-
-For example, suppose the `mygroup/myproject` project Service Desk settings has the following configured:
-
-- Email address suffix is set to `support`.
-- Service Desk email address is configured to `contact+%{key}@example.com`.
-
-The Service Desk email address for this project is: `contact+mygroup-myproject-support@example.com`.
-The [incoming email](../../../administration/incoming_email.md) address still works.
-
-If you don't configure a custom suffix, the default project identification is used for identifying
-the project.
-
-### Configure email ingestion in multi-node environments
-
-A multi-node environment is a setup where GitLab is run across multiple servers
-for scalability, fault tolerance, and performance reasons.
-
-GitLab uses a separate process called `mail_room` to ingest new unread emails
-from the `incoming_email` and `service_desk_email` mailboxes.
-
-#### Helm chart (Kubernetes)
-
-The [GitLab Helm chart](https://docs.gitlab.com/charts/) is made up of multiple subcharts, and one of them is
-the [Mailroom subchart](https://docs.gitlab.com/charts/charts/gitlab/mailroom/index.html). Configure the
-[common settings for `incoming_email`](https://docs.gitlab.com/charts/installation/command-line-options.html#incoming-email-configuration)
-and the [common settings for `service_desk_email`](https://docs.gitlab.com/charts/installation/command-line-options.html#service-desk-email-configuration).
-
-#### Linux package (Omnibus)
-
-In multi-node Linux package installation environments, run `mail_room` only on one node. Run it either on a single
-`rails` node (for example, `application_role`)
-or completely separately.
-
-##### Set up all nodes
-
-1. Add basic configuration for `incoming_email` and `service_desk_email` on every node
- to render email addresses in the web UI and in generated emails.
-
- Find the `incoming_email` or `service_desk_email` section in `/etc/gitlab/gitlab.rb`:
-
- ::Tabs
-
- :::TabTitle `incoming_email`
-
- ```ruby
- gitlab_rails['incoming_email_enabled'] = true
- gitlab_rails['incoming_email_address'] = "incoming+%{key}@example.com"
- ```
-
- :::TabTitle `service_desk_email`
-
- ```ruby
- gitlab_rails['service_desk_email_enabled'] = true
- gitlab_rails['service_desk_email_address'] = "project_contact+%{key}@example.com"
- ```
-
- ::EndTabs
-
-1. GitLab offers two methods to transport emails from `mail_room` to the GitLab
-application. You can configure the `delivery_method` for each email setting individually:
- 1. Recommended: `webhook` (default in GitLab 15.3 and later) sends the email payload via an API POST request to your GitLab
- application. It uses a shared token to authenticate. If you choose this method,
- make sure the `mail_room` process can access the API endpoint and distribute the shared
- token across all application nodes.
-
- ::Tabs
-
- :::TabTitle `incoming_email`
-
- ```ruby
- gitlab_rails['incoming_email_delivery_method'] = "webhook"
-
- # The URL that mail_room can contact. You can also use an internal URL or IP,
- # just make sure mail_room can access the GitLab API via that address.
- # Do not end with "/".
- gitlab_rails['incoming_email_gitlab_url'] = "https://gitlab.example.com"
-
- # The shared secret file that should contain a random token. Make sure it's the same on every node.
- gitlab_rails['incoming_email_secret_file'] = ".gitlab_mailroom_secret"
- ```
-
- :::TabTitle `service_desk_email`
-
- ```ruby
- gitlab_rails['service_desk_email_delivery_method'] = "webhook"
-
- # The URL that mail_room can contact. You can also use an internal URL or IP,
- # just make sure mail_room can access the GitLab API via that address.
- # Do not end with "/".
-
- gitlab_rails['service_desk_email_gitlab_url'] = "https://gitlab.example.com"
-
- # The shared secret file that should contain a random token. Make sure it's the same on every node.
- gitlab_rails['service_desk_email_secret_file'] = ".gitlab_mailroom_secret"
- ```
-
- ::EndTabs
-
- 1. [Deprecated in GitLab 16.0 and planned for removal in 17.0)](../../../update/deprecations.md#sidekiq-delivery-method-for-incoming_email-and-service_desk_email-is-deprecated):
- If you experience issues with the `webhook` setup, use `sidekiq` to deliver the email payload directly to GitLab Sidekiq using Redis.
-
- ::Tabs
-
- :::TabTitle `incoming_email`
-
- ```ruby
- # It uses the Redis configuration to directly add Sidekiq jobs
- gitlab_rails['incoming_email_delivery_method'] = "sidekiq"
- ```
-
- :::TabTitle `service_desk_email`
-
- ```ruby
- # It uses the Redis configuration to directly add Sidekiq jobs
- gitlab_rails['service_desk_email_delivery_method'] = "sidekiq"
- ```
-
- ::EndTabs
-
-1. Disable `mail_room` on all nodes that should not run email ingestion. For example, in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- mailroom['enabled'] = false
- ```
-
-1. [Reconfigure GitLab](../../../administration/restart_gitlab.md) for the changes to take effect.
-
-##### Set up a single email ingestion node
-
-After setting up all nodes and disabling the `mail_room` process, enable `mail_room` on a single node.
-This node polls the mailboxes for `incoming_email` and `service_desk_email` on a regular basis and
-move new unread emails to GitLab.
-
-1. Choose an existing node that additionally handles email ingestion.
-1. Add [full configuration and credentials](../../../administration/incoming_email.md#configuration-examples)
- for `incoming_email` and `service_desk_email`.
-1. Enable `mail_room` on this node. For example, in `/etc/gitlab/gitlab.rb`:
-
- ```ruby
- mailroom['enabled'] = true
- ```
-
-1. [Reconfigure GitLab](../../../administration/restart_gitlab.md) on this node for the changes to take effect.
-
-## Use Service Desk
-
-You can use Service Desk to [create an issue](#as-an-end-user-issue-creator) or [respond to one](#as-a-responder-to-the-issue).
-In these issues, you can also see our friendly neighborhood [Support Bot](#support-bot-user).
-
-### View Service Desk email address
-
-To check what the Service Desk email address is for your project:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Monitor > Service Desk**.
-
-The email address is available at the top of the issue list.
-
-### As an end user (issue creator)
-
-> Support for additional email headers [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346600) in GitLab 14.6. In earlier versions, the Service Desk email address had to be in the "To" field.
-
-To create a Service Desk issue, an end user does not need to know anything about
-the GitLab instance. They just send an email to the address they are given, and
-receive an email back confirming receipt:
-
-![Service Desk enabled](img/service_desk_confirmation_email.png)
-
-This also gives the end user an option to unsubscribe.
-
-If they don't choose to unsubscribe, then any new comments added to the issue
-are sent as emails:
-
-![Service Desk reply email](img/service_desk_reply.png)
-
-Any responses they send via email are displayed in the issue itself.
-
-For information about headers used for treating email, see
-[the incoming email documentation](../../../administration/incoming_email.md#accepted-headers).
-
-### As a responder to the issue
-
-For responders to the issue, everything works just like other GitLab issues.
-GitLab displays a familiar-looking issue tracker where responders can see
-issues created through customer support requests, and filter or interact with them.
-
-![Service Desk Issue tracker](img/service_desk_issue_tracker.png)
-
-Messages from the end user are shown as coming from the special
-[Support Bot user](../../../subscriptions/self_managed/index.md#billable-users).
-You can read and write comments as you usually do in GitLab:
-
-![Service Desk issue thread](img/service_desk_thread.png)
-
-- The project's visibility (private, internal, public) does not affect Service Desk.
-- The path to the project, including its group or namespace, is shown in emails.
-
-#### View Service Desk issues
-
-Prerequisites:
-
-- You must have at least the Reporter role for the project.
-
-To view Service Desk issues:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Monitor > Service Desk**.
-
-### Email contents and formatting
-
-#### Special HTML formatting in HTML emails
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109811) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `service_desk_html_to_text_email_handler`. Disabled by default.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116809) in GitLab 15.11. Feature flag `service_desk_html_to_text_email_handler` removed.
-
-HTML emails show HTML formatting, such as:
-
-- Tables
-- Blockquotes
-- Images
-- Collapsible sections
-
-#### Files attached to comments
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11733) in GitLab 15.8 [with a flag](../../../administration/feature_flags.md) named `service_desk_new_note_email_native_attachments`. Disabled by default.
-> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/386860) in GitLab 15.10.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `service_desk_new_note_email_native_attachments`.
-On GitLab.com, this feature is available.
-
-If a comment contains any attachments and their total size is less than or equal to 10 MB, these
-attachments are sent as part of the email. In other cases, the email contains links to the attachments.
-
-In GitLab 15.9 and earlier, uploads to a comment are sent as links in the email.
-
-## 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](../issues/confidential_issues.md), so they are
-only visible to project members. The project owner can
-[make an issue public](../issues/confidential_issues.md#in-an-existing-issue).
-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.
-
-Anyone in your project can use the Service Desk email address to create an issue in this project, **regardless
-of their role** in the project.
-
-The unique internal email address is visible to project members at least
-the Reporter role in your GitLab instance.
-An external user (issue creator) cannot see the internal email address
-displayed in the information note.
-
-### Moving a Service Desk issue
-
-> [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/372246) in GitLab 15.7: customers continue receiving notifications when a Service Desk issue is moved.
-
-You can move a Service Desk issue the same way you
-[move a regular issue](../issues/managing_issues.md#move-an-issue) in GitLab.
-
-If a Service Desk issue is moved to a different project with Service Desk enabled,
-the customer who created the issue continues to receive email notifications.
-Because a moved issue is first closed, then copied, the customer is considered to be a participant
-in both issues. They continue to receive any notifications in the old issue and the new one.
+## Related topics
+
+- [Configure Service Desk](configure.md)
+ - [Improve your project's security](configure.md#improve-your-projects-security)
+ - [Customize emails sent to the requester](configure.md#customize-emails-sent-to-the-requester)
+ - [Use a custom template for Service Desk tickets](configure.md#use-a-custom-template-for-service-desk-tickets)
+ - [Support Bot user](configure.md#support-bot-user)
+ - [Custom email address (Beta)](configure.md#custom-email-address)
+ - [Use an additional Service Desk alias email](configure.md#use-an-additional-service-desk-alias-email)
+ - [Configure email ingestion in multi-node environments](configure.md#configure-email-ingestion-in-multi-node-environments)
+- [Use Service Desk](using_service_desk.md#use-service-desk)
+ - [As an end user (issue creator)](using_service_desk.md#as-an-end-user-issue-creator)
+ - [As a responder to the issue](using_service_desk.md#as-a-responder-to-the-issue)
+ - [Email contents and formatting](using_service_desk.md#email-contents-and-formatting)
+ - [Privacy considerations](using_service_desk.md#privacy-considerations)
## Troubleshooting Service Desk
diff --git a/doc/user/project/service_desk/using_service_desk.md b/doc/user/project/service_desk/using_service_desk.md
new file mode 100644
index 00000000000..73d85d418d9
--- /dev/null
+++ b/doc/user/project/service_desk/using_service_desk.md
@@ -0,0 +1,182 @@
+---
+stage: Monitor
+group: Respond
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Use Service Desk **(FREE ALL)**
+
+You can use Service Desk to [create an issue](#as-an-end-user-issue-creator) or [respond to one](#as-a-responder-to-the-issue).
+In these issues, you can also see our friendly neighborhood [Support Bot](configure.md#support-bot-user).
+
+## View Service Desk email address
+
+To check what the Service Desk email address is for your project:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Monitor > Service Desk**.
+
+The email address is available at the top of the issue list.
+
+## As an end user (issue creator)
+
+> Support for additional email headers [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346600) in GitLab 14.6. In earlier versions, the Service Desk email address had to be in the "To" field.
+
+To create a Service Desk issue, an end user does not need to know anything about
+the GitLab instance. They just send an email to the address they are given, and
+receive an email back confirming receipt:
+
+![Service Desk enabled](img/service_desk_confirmation_email.png)
+
+This also gives the end user an option to unsubscribe.
+
+If they don't choose to unsubscribe, then any new comments added to the issue
+are sent as emails:
+
+![Service Desk reply email](img/service_desk_reply.png)
+
+Any responses they send via email are displayed in the issue itself.
+
+For information about headers used for treating email, see
+[the incoming email documentation](../../../administration/incoming_email.md#accepted-headers).
+
+## As a responder to the issue
+
+For responders to the issue, everything works just like other GitLab issues.
+GitLab displays a familiar-looking issue tracker where responders can see
+issues created through customer support requests, and filter or interact with them.
+
+![Service Desk Issue tracker](img/service_desk_issue_tracker.png)
+
+Messages from the end user are shown as coming from the special
+[Support Bot user](../../../subscriptions/self_managed/index.md#billable-users).
+You can read and write comments as you usually do in GitLab:
+
+![Service Desk issue thread](img/service_desk_thread.png)
+
+- The project's visibility (private, internal, public) does not affect Service Desk.
+- The path to the project, including its group or namespace, is shown in emails.
+
+### View Service Desk issues
+
+Prerequisites:
+
+- You must have at least the Reporter role for the project.
+
+To view Service Desk issues:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Monitor > Service Desk**.
+
+#### Redesigned issue list
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/413092) in GitLab 16.1 [with a flag](../../../administration/feature_flags.md) named `service_desk_vue_list`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `service_desk_vue_list`.
+On GitLab.com, this feature is not available.
+The feature is not ready for production use.
+
+When this feature is enabled, the Service Desk issue list more closely matches the regular issue list.
+Available features include:
+
+- The same sorting and ordering options [as on the issue list](../issues/sorting_issue_lists.md).
+- The same filters, including [the OR operator](#filter-with-the-or-operator) and [filtering by issue ID](#filter-issues-by-id).
+
+There is no longer an option to create a new issue from the Service Desk issue list.
+This decision better reflects the nature of Service Desk, where new issues are created by emailing
+a dedicated email address.
+
+##### Filter the list of issues
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Monitor > Service Desk**.
+1. Above the list of issues, select **Search or filter results...**.
+1. In the dropdown list that appears, select the attribute you want to filter by.
+1. Select or type the operator to use for filtering the attribute. The following operators are
+ available:
+ - `=`: Is
+ - `!=`: Is not one of
+1. Enter the text to filter the attribute by.
+ You can filter some attributes by **None** or **Any**.
+1. Repeat this process to filter by multiple attributes. Multiple attributes are joined by a logical
+ `AND`.
+
+##### Filter with the OR operator
+
+When [filtering with the OR operator](../issues/managing_issues.md#filter-with-the-or-operator) is enabled,
+you can use **is one of: `||`**
+when you [filter the list of issues](#filter-the-list-of-issues) by:
+
+- Assignees
+- Labels
+
+`is one of` represents an inclusive OR. For example, if you filter by `Assignee is one of Sidney Jones` and
+`Assignee is one of Zhang Wei`, GitLab shows issues where either `Sidney`, `Zhang`, or both of them are assignees.
+
+##### Filter issues by ID
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Monitor > Service Desk**.
+1. In the **Search** box, type the issue ID. For example, enter filter `#10` to return only issue 10.
+
+## Email contents and formatting
+
+### Special HTML formatting in HTML emails
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109811) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `service_desk_html_to_text_email_handler`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116809) in GitLab 15.11. Feature flag `service_desk_html_to_text_email_handler` removed.
+
+HTML emails show HTML formatting, such as:
+
+- Tables
+- Blockquotes
+- Images
+- Collapsible sections
+
+### Files attached to comments
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11733) in GitLab 15.8 [with a flag](../../../administration/feature_flags.md) named `service_desk_new_note_email_native_attachments`. Disabled by default.
+> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/386860) in GitLab 15.10.
+
+FLAG:
+On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `service_desk_new_note_email_native_attachments`.
+On GitLab.com, this feature is available.
+
+If a comment contains any attachments and their total size is less than or equal to 10 MB, these
+attachments are sent as part of the email. In other cases, the email contains links to the attachments.
+
+In GitLab 15.9 and earlier, uploads to a comment are sent as links in the email.
+
+## 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](../issues/confidential_issues.md), so they are
+only visible to project members. The project owner can
+[make an issue public](../issues/confidential_issues.md#in-an-existing-issue).
+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.
+
+Anyone in your project can use the Service Desk email address to create an issue in this project, **regardless
+of their role** in the project.
+
+The unique internal email address is visible to project members at least
+the Reporter role in your GitLab instance.
+An external user (issue creator) cannot see the internal email address
+displayed in the information note.
+
+### Moving a Service Desk issue
+
+> [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/372246) in GitLab 15.7: customers continue receiving notifications when a Service Desk issue is moved.
+
+You can move a Service Desk issue the same way you
+[move a regular issue](../issues/managing_issues.md#move-an-issue) in GitLab.
+
+If a Service Desk issue is moved to a different project with Service Desk enabled,
+the customer who created the issue continues to receive email notifications.
+Because a moved issue is first closed, then copied, the customer is considered to be a participant
+in both issues. They continue to receive any notifications in the old issue and the new one.
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 087330431ad..22eb7c54d12 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -79,14 +79,14 @@ For example:
Before you can migrate projects on a self-managed GitLab instance using file exports, GitLab administrators must:
-1. [Enable file exports](../../../administration/settings/visibility_and_access_controls.md#enable-project-export) on the source
+1. [Enable file exports](../../../administration/settings/import_and_export_settings.md#enable-project-export) on the source
instance.
1. Enable file exports as an import source for the destination instance. On GitLab.com, file exports are already enabled
as an import source.
To enable file exports as an import source for the destination instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Admin Area**.
1. Select **Settings > General**.
1. Expand **Visibility and access controls**.
@@ -113,7 +113,7 @@ Prerequisites:
To export a project and its data, follow these steps:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. Select **Export project**.
@@ -245,7 +245,7 @@ If you have a larger project, consider [using a Rake task](../../../administrati
Administrators can set the maximum import file size one of two ways:
- With the `max_import_size` option in the [Application settings API](../../../api/settings.md#change-application-settings).
-- In the [Admin Area UI](../../../administration/settings/account_and_limit_settings.md#max-import-size).
+- In the [Admin Area UI](../../../administration/settings/import_and_export_settings.md#max-import-size).
The default is `0` (unlimited).
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 6c2140595d9..d9c114c0a59 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -11,9 +11,11 @@ Use the **Settings** page to manage the configuration options in your [project](
## View project settings
-You must have at least the Maintainer role to view project settings.
+Prerequisite:
+
+- You must have at least the Maintainer role for the project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. To display all settings in a section, select **Expand**.
1. Optional. Use the search box to find a setting.
@@ -22,8 +24,11 @@ You must have at least the Maintainer role to view project settings.
Use the project general settings to edit your project details.
-1. Sign in to GitLab with at least the Maintainer role.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+Prerequisite:
+
+- You must have at least the Maintainer role for the project.
+
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. In the **Project name** text box, enter your project name.
1. In the **Project description** text box, enter your project description.
@@ -31,11 +36,11 @@ Use the project general settings to edit your project details.
## Assign topics to a project
-Use topics to categorize projects and find similar new projects.
+Use [topics](../working_with_projects.md#organizing-projects-with-topics) to categorize projects and find similar new projects.
To assign topics to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings** > **General**.
1. In the **Topics** text box, enter the project topics. Popular topics are suggested as you type.
1. Select **Save changes**.
@@ -46,50 +51,38 @@ If you're an instance administrator, you can administer all project topics from
NOTE:
The assigned topics are visible only to users with access to the project, but everyone can see which topics exist on the GitLab instance. Do not include sensitive information in the name of a topic.
-## Add a compliance framework to a project **(PREMIUM ALL)**
+## Rename a repository
+
+A project's repository name defines its URL and its place on the file disk
+where GitLab is installed.
+
+Prerequisite:
-You can
-[add compliance frameworks to projects](../../group/compliance_frameworks.md#add-a-compliance-framework-to-a-project)
-in a group that has a compliance framework.
+- You must be an administrator or have the Maintainer or Owner role for the project.
+
+NOTE:
+When you change the repository path, users may experience issues if they push to, or pull from, the old URL. For more information, see
+[redirects when renaming repositories](../repository/index.md#what-happens-when-a-repository-path-changes).
+
+To rename a repository:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Advanced**.
+1. In the **Change path** text box, edit the path.
+1. Select **Change path**.
-## Configure project visibility, features, and permissions
+## Configure project features and permissions
-To configure visibility, features, and permissions for a project:
+To configure features and permissions for a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
-1. To change the project visibility, select the dropdown list. If you select to **Public**, you limit access to some features to **Only Project Members**.
1. To allow users to request access to the project, select the **Users can request access** checkbox.
-1. Use the [toggles](#project-feature-settings) to enable or disable features in the project.
+1. To enable or disable features in the project, use the feature toggles.
1. Select **Save changes**.
-### Project feature settings
-
-Use the toggles to enable or disable features in the project.
-
-| Option | More access limit options | Description
-| :------------------------------- | :------------------------ | :---------- |
-| **Issues** | **{check-circle}** Yes | Activates the GitLab issues tracker.
-| **Repository** | **{check-circle}** Yes | Enables [repository](../repository/index.md) functionality.
-| **Merge requests** | **{check-circle}** Yes | Enables [merge request](../merge_requests/index.md) functionality; also see [Merge request settings](#configure-merge-request-settings-for-a-project).
-| **Forks** | **{check-circle}** Yes | Enables [forking](../repository/forking_workflow.md) functionality.
-| **Git Large File Storage (LFS)** | **{dotted-circle}** No | Enables the use of [large files](../../../topics/git/lfs/index.md).
-| **Packages** | **{dotted-circle}** No | Supports configuration of a [package registry](../../../administration/packages/index.md#gitlab-package-registry-administration) functionality.
-| **CI/CD** | **{check-circle}** Yes | Enables [CI/CD](../../../ci/index.md) functionality.
-| **Container Registry** | **{dotted-circle}** No | Activates a [registry](../../packages/container_registry/index.md) for your Docker images.
-| **Analytics** | **{check-circle}** Yes | Enables [analytics](../../analytics/index.md).
-| **Requirements** | **{check-circle}** Yes | Control access to [Requirements Management](../requirements/index.md).
-| **Security and Compliance** | **{check-circle}** Yes | Control access to [security features](../../application_security/index.md).
-| **Wiki** | **{check-circle}** Yes | Enables a separate system for [documentation](../wiki/index.md).
-| **Snippets** | **{check-circle}** Yes | Enables [sharing of code and text](../../snippets.md).
-| **Pages** | **{check-circle}** Yes | Allows you to [publish static websites](../pages/index.md).
-| **Releases** | **{check-circle}** Yes | Control access to [Releases](../releases/index.md).
-| **Environments** | **{check-circle}** Yes | Control access to [Environments and Deployments](../../../ci/environments/index.md).
-| **Feature flags** | **{check-circle}** Yes | Control access to [Feature flags](../../../operations/feature_flags.md).
-| **Monitor** | **{check-circle}** Yes | Control access to [Monitor](../../../operations/index.md) features.
-| **Infrastructure** | **{check-circle}** Yes | Control access to [Infrastructure](../../infrastructure/index.md) features.
-
When you disable a feature, the following additional features are also disabled:
- If you disable the **Issues** feature, project users cannot use:
@@ -111,164 +104,66 @@ When you disable a feature, the following additional features are also disabled:
- **Git Large File Storage**
- **Packages**
-- Metrics dashboard access requires reading project environments and deployments.
+- The metrics dashboard requires read access to project environments and deployments.
Users with access to the metrics dashboard can also access environments and deployments.
-### Manage project access through LDAP groups
-
-You can [use LDAP to manage group membership](../../group/access_and_permissions.md#manage-group-memberships-via-ldap).
-
-You cannot use LDAP groups to manage project access, but you can use the following
-workaround.
-
-Prerequisites:
-
-- You must [integrate LDAP with GitLab](../../../administration/auth/ldap/index.md).
-- You must be an administrator.
-
-1. [Create a group](../../group/index.md#create-a-group) to track membership of your project.
-1. [Set up LDAP synchronization](../../../administration/auth/ldap/ldap_synchronization.md) for that group.
-1. To use LDAP groups to manage access to a project, [add the LDAP-synchronized group as a member](../members/index.md#add-groups-to-a-project)
- to the project.
-
-## Disable CVE identifier request in issues **(FREE SAAS)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41203) in GitLab 13.4, only for public projects on GitLab.com.
-
-In some environments, users can submit a [CVE identifier request](../../application_security/cve_id_request.md) in an issue.
-
-To disable the CVE identifier request option in issues in your project:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Visibility, project features, permissions**.
-1. Under **Issues**, turn off the **CVE ID requests in the issue sidebar** toggle.
-1. Select **Save changes**.
-
-## Disable project email notifications
-
-Prerequisites:
-
-- You must be an Owner of the project to disable email notifications related to the project.
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Visibility, project features, permissions**.
-1. Clear the **Disable email notifications** checkbox.
-
## Configure merge request settings for a project
Configure your project's merge request settings:
- Set up the [merge request method](../merge_requests/methods/index.md) (merge commit, fast-forward merge).
- Add merge request [description templates](../description_templates.md).
-- Enable [merge request approvals](../merge_requests/approvals/index.md).
-- Enable [status checks](../merge_requests/status_checks.md).
-- Enable [merge only if pipeline succeeds](../merge_requests/merge_when_pipeline_succeeds.md).
-- Enable [merge only when all threads are resolved](../merge_requests/index.md#prevent-merge-unless-all-threads-are-resolved).
-- Enable [require an associated issue from Jira](../../../integration/jira/issues.md#require-associated-jira-issue-for-merge-requests-to-be-merged).
-- Enable [**Delete source branch when merge request is accepted** option by default](#delete-the-source-branch-on-merge-by-default).
-- Configure [suggested changes commit messages](../merge_requests/reviews/suggestions.md#configure-the-commit-message-for-applied-suggestions).
-- Configure [merge and squash commit message templates](../merge_requests/commit_templates.md).
-- Configure [the default target project](../merge_requests/creating_merge_requests.md#set-the-default-target-project) for merge requests coming from forks.
-- Enable [Suggested Reviewers](../merge_requests/reviews/index.md#suggested-reviewers).
-
-## Service Desk
-
-Enable [Service Desk](../service_desk/index.md) for your project to offer customer support.
-
-## Export project
-
-Learn how to [export a project](import_export.md#import-a-project-and-its-data) in GitLab.
-
-## Advanced project settings
-
-Use the advanced settings to archive, rename, transfer,
-[remove a fork relationship](../repository/forking_workflow.md#unlink-a-fork), or delete a project.
-
-### Archive a project
-
-When you archive a project, the repository, packages, issues, merge requests, and all
-other features are read-only. Archived projects are also hidden from project listings.
-
-To archive a project:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Advanced**.
-1. In the **Archive project** section, select **Archive project**.
-1. To confirm, select **OK**.
-
-### Unarchive a project
-
-When you unarchive a project, you remove the read-only restriction and make it
-available in project lists.
-
-Prerequisites:
-
-- To unarchive a project, you must be an administrator or a project Owner.
-
-1. Find the archived project.
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
- 1. Select **View all your projects**.
- 1. Select **Explore projects**.
- 1. In the **Sort projects** dropdown list, select **Show archived projects**.
- 1. In the **Filter by name** field, enter the project name.
- 1. Select the project link.
-1. On the left sidebar, select **Settings > General**.
-1. Under **Advanced**, select **Expand**.
-1. In the **Unarchive project** section, select **Unarchive project**.
-1. To confirm, select **OK**.
-
-### Rename a repository
-
-A project's repository name defines its URL and its place on the file disk
-where GitLab is installed.
-
-Prerequisites:
-
-You must be a project maintainer, owner, or administrator to rename a repository.
-
-NOTE:
-When you change the repository path, users may experience issues if they push to, or pull from, the old URL. For more information, see
-[redirects when renaming repositories](../repository/index.md#what-happens-when-a-repository-path-changes).
-
-To rename a repository:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand **Advanced**.
-1. In the **Change path** text box, edit the path.
-1. Select **Change path**.
-
-## Delete the source branch on merge by default
+- Enable:
+ - [Merge request approvals](../merge_requests/approvals/index.md).
+ - [Status checks](../merge_requests/status_checks.md).
+ - [Merge only if pipeline succeeds](../merge_requests/merge_when_pipeline_succeeds.md).
+ - [Merge only when all threads are resolved](../merge_requests/index.md#prevent-merge-unless-all-threads-are-resolved).
+ - [Required associated issue from Jira](../../../integration/jira/issues.md#require-associated-jira-issue-for-merge-requests-to-be-merged).
+ - [GitLab Duo Suggested Reviewers](../merge_requests/reviews/index.md#gitlab-duo-suggested-reviewers)
+ - [**Delete source branch when merge request is accepted** option by default](#delete-the-source-branch-on-merge-by-default).
+- Configure:
+ - [Suggested changes commit messages](../merge_requests/reviews/suggestions.md#configure-the-commit-message-for-applied-suggestions).
+ - [Merge and squash commit message templates](../merge_requests/commit_templates.md).
+ - [Default target project](../merge_requests/creating_merge_requests.md#set-the-default-target-project) for merge requests coming from forks.
+
+### Delete the source branch on merge by default
In merge requests, you can change the default behavior so that the
**Delete the source branch** checkbox is always selected.
To set this default:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Select **Enable "Delete source branch" option by default**.
1. Select **Save changes**.
+## Export project
+
+You can [export a project and its data](import_export.md#export-a-project-and-its-data).
+
## Transfer a project to another namespace
When you transfer a project to another namespace, you move the project to a different group.
Prerequisites:
-- You must have at least the Maintainer role for the [group](../../group/index.md#create-a-group) to which you are transferring.
+- You must have at least the Maintainer role for the [group](../../group/index.md#create-a-group) you are transferring to.
- You must be the Owner of the project you transfer.
- The group must allow creation of new projects.
- The project must not contain any [container images](../../packages/container_registry/index.md#move-or-rename-container-registry-repositories).
-- Remove any npm packages. If you transfer a project to a different root namespace, the project must not contain any npm packages. When you update the path of a user or group, or transfer a subgroup or project, you must remove any npm packages first. You cannot update the root namespace of a project with npm packages. Make sure you update your .npmrc files to follow the naming convention and run npm publish if necessary.
-- If a security policy is assigned to the project, it is automatically unassigned during the transfer.
+- The project must not have a security policy.
+ If a security policy is assigned to the project, it is automatically unassigned during the transfer.
+- If the root namespace changes, you must remove npm packages that follow the [naming convention](../../../user/packages/npm_registry/index.md#naming-convention) from the project.
+ After you transfer the project you can either:
+
+ - Update the package scope with the new root namespace path, and publish it again to the project.
+ - Republish the package to the project without updating the root namespace path, which causes the package to no longer follow the naming convention.
+ If you republish the package without updating the root namespace path, it will not be available at the [instance level endpoint](../../../user/packages/npm_registry/index.md#install-from-the-instance-level).
To transfer a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. Under **Transfer project**, choose the namespace to transfer the project to.
@@ -283,12 +178,46 @@ to move any project to any namespace.
### Transferring a GitLab SaaS project to a different subscription tier
-When you transfer a project from a namespace licensed for GitLab SaaS Premium or Ultimate to GitLab Free, the following paid feature data is deleted:
+When you transfer a project from a namespace licensed for GitLab SaaS Premium or Ultimate to GitLab Free:
-- [Project access tokens](../../../user/project/settings/project_access_tokens.md) are revoked
+- [Project access tokens](../../../user/project/settings/project_access_tokens.md) are revoked.
- [Pipeline subscriptions](../../../ci/pipelines/index.md#trigger-a-pipeline-when-an-upstream-project-is-rebuilt)
and [test cases](../../../ci/test_cases/index.md) are deleted.
+## Archive a project
+
+When you archive a project, the repository, packages, issues, merge requests, and all
+other features become read-only. Archived projects are also hidden from project lists.
+
+To archive a project:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Advanced**.
+1. In the **Archive project** section, select **Archive project**.
+1. To confirm, select **OK**.
+
+## Unarchive a project
+
+When you unarchive a project, the read-only restriction is removed,
+and the project becomes available in project lists.
+
+Prerequisite:
+
+- You must be an administrator or have the Owner role for the project.
+
+1. Find the archived project.
+ 1. On the left sidebar, select **Search or go to**.
+ 1. Select **View all my projects**.
+ 1. Select **Explore projects**.
+ 1. In the **Sort projects** dropdown list, select **Show archived projects**.
+ 1. In the **Filter by name** field, enter the project name.
+ 1. Select the project link.
+1. On the left sidebar, select **Settings > General**.
+1. Under **Advanced**, select **Expand**.
+1. In the **Unarchive project** section, select **Unarchive project**.
+1. To confirm, select **OK**.
+
## Delete a project
> - Default deletion behavior for projects changed to [delayed project deletion](https://gitlab.com/gitlab-org/gitlab/-/issues/32935) in GitLab 12.6.
@@ -297,6 +226,10 @@ When you transfer a project from a namespace licensed for GitLab SaaS Premium or
> - Default deletion behavior changed to delayed deletion on the Premium and Ultimate tier [on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/393622) and [on self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119606) in GitLab 16.0.
You can mark a project to be deleted.
+After you delete a project:
+
+- Projects in personal namespaces are deleted immediately.
+- Projects in groups are deleted after a retention period.
Prerequisite:
@@ -304,7 +237,7 @@ Prerequisite:
To delete a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. In the **Delete this project** section, select **Delete project**.
@@ -312,6 +245,8 @@ To delete a project:
This action deletes the project and all associated resources (such as issues and merge requests).
+You can also [delete projects using the Rails console](../working_with_projects.md#delete-a-project-using-console).
+
### Delayed project deletion **(PREMIUM ALL)**
> - [Enabled for projects in personal namespaces](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89466) in GitLab 15.1.
@@ -323,6 +258,10 @@ Projects in a group (not a personal namespace) can be deleted after a delay peri
On self-managed instances, group administrators can define a deletion delay period of between 1 and 90 days.
On SaaS, there is a non-adjustable default retention period of seven days.
+You can [view projects that are pending deletion](../working_with_projects.md#view-projects-pending-deletion),
+and use the Rails console to
+[find projects that are pending deletion](../working_with_projects.md#find-projects-that-are-pending-deletion).
+
### Delete a project immediately
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/191367) in GitLab 14.1.
@@ -340,7 +279,7 @@ Prerequisites:
To immediately delete a project marked for deletion:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. In the **Delete this project** section, select **Delete project**.
@@ -352,39 +291,55 @@ To immediately delete a project marked for deletion:
To restore a project marked for deletion:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Advanced**.
1. In the Restore project section, select **Restore project**.
-## Monitor settings
+## Disable project analytics
-### Alerts
+By default, [analytics for a project](../../analytics/index.md#project-level-analytics) are displayed under the **Analyze** item in the left sidebar.
+To disable this feature and remove the **Analyze** item from the left sidebar:
-Configure [alert integrations](../../../operations/incident_management/integrations.md#configuration) to triage and manage critical problems in your application as [alerts](../../../operations/incident_management/alerts.md).
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Visibility, project features, permissions**.
+1. Turn off the **Analytics** toggle.
+1. Select **Save changes**.
-### Incidents
+## Disable CVE identifier request in issues **(FREE SAAS)**
-#### Alert integration
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41203) in GitLab 13.4, only for public projects on GitLab.com.
-Automatically [create](../../../operations/incident_management/alerts.md#trigger-actions-from-alerts), [notify on](../../../operations/incident_management/paging.md#email-notifications-for-alerts), and [resolve](../../../operations/incident_management/manage_incidents.md#automatically-close-incidents-via-recovery-alerts) incidents based on GitLab alerts.
+In some environments, users can submit a [CVE identifier request](../../application_security/cve_id_request.md) in an issue.
-#### PagerDuty integration
+To disable the CVE identifier request option in issues in your project:
-[Create incidents in GitLab for each PagerDuty incident](../../../operations/incident_management/manage_incidents.md#using-the-pagerduty-webhook).
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Visibility, project features, permissions**.
+1. Under **Issues**, turn off the **CVE ID requests in the issue sidebar** toggle.
+1. Select **Save changes**.
-#### Incident settings
+## Disable project email notifications
-[Manage Service Level Agreements for incidents](../../../operations/incident_management/incidents.md#service-level-agreement-countdown-timer) with an SLA countdown timer.
+Prerequisite:
-### Error Tracking
+- You must have the Owner role for the project.
-Configure Error Tracking to discover and view [Sentry errors within GitLab](../../../operations/error_tracking.md).
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Settings > General**.
+1. Expand **Visibility, project features, permissions**.
+1. Clear the **Disable email notifications** checkbox.
-### Status Page **(ULTIMATE ALL)**
+## Related topics
-[Add Storage credentials](../../../operations/incident_management/status_page.md#sync-incidents-to-the-status-page)
-to enable the syncing of public Issues to a [deployed status page](../../../operations/incident_management/status_page.md#create-a-status-page-project).
+- [Alert integrations](../../../operations/incident_management/integrations.md#configuration)
+- [PagerDuty incident management](../../../operations/incident_management/manage_incidents.md#using-the-pagerduty-webhook)
+- [SLA countdown timer](../../../operations/incident_management/incidents.md#service-level-agreement-countdown-timer)
+- [Error tracking](../../../operations/error_tracking.md)
+- [Incidents sync](../../../operations/incident_management/status_page.md#sync-incidents-to-the-status-page)
+- [Service Desk](../service_desk/index.md)
## Troubleshooting
diff --git a/doc/user/project/settings/project_access_tokens.md b/doc/user/project/settings/project_access_tokens.md
index 78620eb2ab3..29d57328532 100644
--- a/doc/user/project/settings/project_access_tokens.md
+++ b/doc/user/project/settings/project_access_tokens.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments"
type: reference, howto
@@ -55,7 +55,7 @@ all projects that have visibility level set to [Internal](../../public_access.md
To create a project access token:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Access Tokens**.
1. Enter a name. The token name is visible to any user with permissions to view the project.
1. Enter an expiry date for the token.
@@ -73,12 +73,14 @@ A project access token is displayed. Save the project access token somewhere saf
To revoke a project access token:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Access Tokens**.
1. Next to the project access token to revoke, select **Revoke**.
## Scopes for a project access token
+> `k8s_proxy` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/422408) in GitLab 16.4 [with a flag](../../../administration/feature_flags.md) named `k8s_proxy_pat`. Enabled by default.
+
The scope determines the actions you can perform when you authenticate with a project access token.
NOTE:
@@ -93,6 +95,8 @@ See the warning in [create a project access token](#create-a-project-access-toke
| `read_repository` | Grants read access (pull) to the repository. |
| `write_repository` | Grants read and write access (pull and push) to the repository. |
| `create_runner` | Grants permission to create runners in the project. |
+| `ai_features` | Grants permission to perform API actions for GitLab Duo. |
+| `k8s_proxy` | Grants permission to perform Kubernetes API calls using the agent for Kubernetes in the project. |
## Enable or disable project access token creation
@@ -100,7 +104,7 @@ See the warning in [create a project access token](#create-a-project-access-toke
To enable or disable project access token creation for all projects in a top-level group:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Under **Permissions**, turn on or off **Allow project and group access token creation**.
diff --git a/doc/user/project/system_notes.md b/doc/user/project/system_notes.md
index 84ff9efbd14..661f10290c6 100644
--- a/doc/user/project/system_notes.md
+++ b/doc/user/project/system_notes.md
@@ -31,7 +31,7 @@ The filtering options are:
### On an epic
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Epics**.
1. Identify your desired epic, and select its title.
1. Go to the **Activity** section.
@@ -39,14 +39,14 @@ The filtering options are:
### On an issue
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues** and find your issue.
1. Go to **Activity**.
1. For **Sort or filter**, select **Show all activity**.
### On a merge request
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. Go to **Activity**.
1. For **Sort or filter**, select **Show all activity**.
diff --git a/doc/user/project/time_tracking.md b/doc/user/project/time_tracking.md
index ec8d886c68e..f9a11a51c98 100644
--- a/doc/user/project/time_tracking.md
+++ b/doc/user/project/time_tracking.md
@@ -185,7 +185,7 @@ The following time units are available:
In GitLab self-managed instances, you can limit the display of time units to hours.
To do so:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Settings > Preferences**.
1. Expand **Localization**.
1. Under **Time tracking**, select the **Limit display of time tracking units to hours** checkbox.
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index 994ed244832..fb2bd707c56 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -23,7 +23,7 @@ To pair the Web IDE with a remote development environment, see [remote developme
To open the Web IDE from the GitLab UI:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Use the <kbd>.</kbd> keyboard shortcut.
You can also open the Web IDE from:
@@ -81,6 +81,20 @@ To view a list of files you changed in the Web IDE:
Your `CHANGES`, `STAGED CHANGES`, and `MERGE CHANGES` are displayed.
For more information, see the [VS Code documentation](https://code.visualstudio.com/docs/sourcecontrol/overview#_commit).
+## Restore uncommitted changes
+
+You don't have to manually save any file you modify in the Web IDE.
+Modified files are automatically staged and can be [committed](#commit-changes).
+Uncommitted changes are saved in your browser's local storage and persist
+even if you close the browser tab or refresh the Web IDE.
+
+If your uncommitted changes are not available, you can restore the changes from local history.
+To restore uncommitted changes in the Web IDE:
+
+1. Press <kbd>Shift</kbd>+<kbd>Command</kbd>+<kbd>P</kbd>.
+1. In the search box, enter `Local History: Find Entry to Restore`.
+1. Select the file that contains the uncommitted changes.
+
## Upload a new file
To upload a new file in the Web IDE:
@@ -203,7 +217,7 @@ To protect your privacy and data:
- Carefully review the permissions requested by an extension before you install the extension.
- Keep your extensions up to date to ensure that any security or privacy vulnerabilities are addressed promptly. -->
-## Interactive web terminals for the Web IDE (Beta)
+## Interactive web terminals for the Web IDE **(BETA)**
WARNING:
This feature is in [Beta](../../../policy/experiment-beta-support.md#beta) and subject to change without notice.
diff --git a/doc/user/project/web_ide_beta/index.md b/doc/user/project/web_ide_beta/index.md
deleted file mode 100644
index a4c733be376..00000000000
--- a/doc/user/project/web_ide_beta/index.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../web_ide/index.md'
-remove_date: '2023-08-22'
----
-
-This document was moved to [another location](../web_ide/index.md).
-
-<!-- This redirect file can be deleted after <2023-08-22>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/project/wiki/group.md b/doc/user/project/wiki/group.md
index 916c8abf066..ae182f1f183 100644
--- a/doc/user/project/wiki/group.md
+++ b/doc/user/project/wiki/group.md
@@ -26,7 +26,7 @@ can edit group wikis. Group wiki repositories can be moved using the
To access a group wiki:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. To display the wiki, either:
- On the left sidebar, select **Plan > Wiki**.
- On any page in the group, use the <kbd>g</kbd> + <kbd>w</kbd>
@@ -66,7 +66,7 @@ can enable or disable a group wiki through the group settings.
To open group settings:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. Select **Settings > General**.
1. Expand **Permissions and group features**.
1. Scroll to **Wiki** and select one of these options:
diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md
index 71fc4dd20a3..4f3aa0d0d49 100644
--- a/doc/user/project/wiki/index.md
+++ b/doc/user/project/wiki/index.md
@@ -31,7 +31,7 @@ with sibling pages listed in alphabetical order. To view a list of all pages, se
To access a project wiki:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. To display the wiki, either:
- On the left sidebar, select **Plan > Wiki**.
- On any page in the project, use the <kbd>g</kbd> + <kbd>w</kbd>
@@ -61,7 +61,7 @@ When a wiki is created, it is empty. On your first visit, you can create the
home page users see when viewing the wiki. This page requires a specific title
to be used as your wiki's home page. To create it:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
1. Select **Create your first page**.
1. GitLab requires this first page be titled `home`. The page with this
@@ -77,7 +77,7 @@ to be used as your wiki's home page. To create it:
Users with at least the Developer role can create new wiki pages:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
1. Select **New page** on this page, or any other wiki page.
1. Select a content format.
@@ -138,7 +138,7 @@ may not be able to check out the wiki locally afterward.
You need at least the Developer role to edit a wiki page:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
1. Go to the page you want to edit, and either:
- Use the <kbd>e</kbd> wiki [keyboard shortcut](../../shortcuts.md#wiki-pages).
@@ -157,7 +157,7 @@ For an example, read [Table of contents](../../markdown.md#table-of-contents).
You need at least the Developer role to delete a wiki page:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
1. Go to the page you want to delete.
1. Select the edit icon (**{pencil}**).
@@ -168,7 +168,7 @@ You need at least the Developer role to delete a wiki page:
You need at least the Developer role to move a wiki page:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
1. Go to the page you want to move.
1. Select the edit icon (**{pencil}**).
@@ -192,7 +192,7 @@ The history page shows:
To view the changes for a wiki page:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
1. Go to the page you want to view history for.
1. Select **Page history**.
@@ -203,7 +203,7 @@ To view the changes for a wiki page:
You can see the changes made in a version of a wiki page, similar to versioned diff file views:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
1. Go to the wiki page you're interested in.
1. Select **Page history** to see all page versions.
@@ -234,7 +234,7 @@ You need at least the Developer role to customize the wiki
navigation sidebar. This process creates a wiki page named `_sidebar` which fully
replaces the default sidebar navigation:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Plan > Wiki**.
1. In the upper-right corner of the page, select **Edit sidebar**.
1. When complete, select **Save changes**.
@@ -257,7 +257,7 @@ A `_sidebar` example, formatted with Markdown:
Wikis are enabled by default in GitLab. Project [administrators](../../permissions.md)
can enable or disable a project wiki by following the instructions in
-[Sharing and permissions](../settings/index.md#configure-project-visibility-features-and-permissions).
+[Sharing and permissions](../settings/index.md#configure-project-features-and-permissions).
Administrators for self-managed GitLab installs can
[configure additional wiki settings](../../../administration/wikis/index.md).
@@ -268,7 +268,7 @@ You can disable group wikis from the [group settings](group.md#configure-group-w
To add a link to an external wiki from a project's left sidebar:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **External wiki**.
1. Add the URL to your external wiki.
@@ -284,7 +284,7 @@ To hide the internal wiki from the sidebar, [disable the project's wiki](#disabl
To hide the link to an external wiki:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Integrations**.
1. Select **External wiki**.
1. Under **Enable integration**, clear the **Active** checkbox.
@@ -294,7 +294,7 @@ To hide the link to an external wiki:
To disable a project's internal wiki:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Scroll down to find **Wiki** and toggle it off (in gray).
diff --git a/doc/user/project/working_with_projects.md b/doc/user/project/working_with_projects.md
index 8c050caed17..2a4f0b99246 100644
--- a/doc/user/project/working_with_projects.md
+++ b/doc/user/project/working_with_projects.md
@@ -13,7 +13,7 @@ code are saved in projects, and most features are in the scope of projects.
To view all projects for the GitLab instance:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Explore**.
On the left sidebar, **Projects** is selected. On the right, the list shows
@@ -25,7 +25,7 @@ If you are not authenticated, then the list shows public projects only.
To view projects you are a member of:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
On the left sidebar, **Projects** is selected. On the list, on the **Yours** tab,
@@ -68,7 +68,7 @@ Do not include sensitive information in the name of a topic.
To explore project topics:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Explore**.
1. On the left sidebar, select **Topics**.
1. To view projects associated with a topic, select a topic.
@@ -110,7 +110,7 @@ To subscribe to a topic:
- From a project:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. In the **Project overview** page, from the **Topics** list select the topic you want to subscribe to.
1. In the upper-right corner, select **Subscribe to the new projects feed** (**{rss}**).
@@ -132,25 +132,9 @@ You can add a star to projects you use frequently to make them easier to find.
To add a star to a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. In the upper-right corner of the page, select **Star**.
-## Delete a project
-
-After you delete a project:
-
-- Projects in personal namespaces are deleted immediately.
-- Projects in groups are [deleted after a retention period](../project/settings/index.md#delayed-project-deletion).
-
-To delete a project:
-
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Settings > General**.
-1. Expand the **Advanced** section.
-1. Scroll down to the **Delete project** section.
-1. Select **Delete project**.
-1. Confirm this action by completing the field.
-
## View projects pending deletion **(PREMIUM ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37014) in GitLab 13.3 for Administrators.
@@ -160,8 +144,8 @@ To delete a project:
To view a list of all projects that are pending deletion:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **View all your projects**.
+1. On the left sidebar, select **Search or go to**.
+1. Select **View all my projects**.
1. Based on your GitLab version:
- GitLab 14.6 and later: select the **Pending deletion** tab.
- GitLab 14.5 and earlier: select the **Deleted projects** tab.
@@ -176,7 +160,7 @@ Each project in the list shows:
To view the activity of a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Manage > Activity**.
1. Optional. To filter activity by contribution type, select a tab:
@@ -190,8 +174,8 @@ To view the activity of a project:
## Search in projects
-To search through your projects, on the left sidebar, at the top, select **Search GitLab**
-(**{search}**). GitLab filters as you type.
+To search through your projects, on the left sidebar, select **Search or go to**.
+GitLab filters as you type.
You can also look for the projects you [starred](#star-a-project) (**Starred projects**).
@@ -214,7 +198,7 @@ You can also choose to hide or show archived projects.
You can filter projects by the programming language they use. To do this:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select either:
- **View all your projects**, to filter your projects.
- **Explore**, to filter all projects you can access.
@@ -230,7 +214,7 @@ Prerequisite:
- You must have the Owner role for the project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Use the toggle by each feature you want to turn on or off, or change access for.
@@ -274,7 +258,7 @@ When you leave a project:
To leave a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Leave project**. The **Leave project** option only displays
on the project dashboard when a project is part of a group under a
[group namespace](../namespace/index.md).
@@ -408,18 +392,44 @@ To access the Geo secondary server with HTTP:
The `go get` request generates HTTP traffic to the primary Geo server. When the module
download starts, the `insteadOf` configuration sends the traffic to the secondary Geo server.
+## Add a compliance framework to a project **(PREMIUM)**
+
+You can add compliance frameworks to projects in a group that has a [compliance framework](../group/compliance_frameworks.md).
+
+## Manage project access through LDAP groups
+
+You can [use LDAP to manage group membership](../group/access_and_permissions.md#manage-group-memberships-via-ldap).
+
+You cannot use LDAP groups to manage project access, but you can use the following workaround.
+
+Prerequisites:
+
+- You must [integrate LDAP with GitLab](../../administration/auth/ldap/index.md).
+- You must be an administrator.
+
+1. [Create a group](../group/index.md#create-a-group) to track membership of your project.
+1. [Set up LDAP synchronization](../../administration/auth/ldap/ldap_synchronization.md) for that group.
+1. To use LDAP groups to manage access to a project,
+[add the LDAP-synchronized group as a member](../group/manage.md) to the project.
+
## Related topics
- [Import a project](../../user/project/import/index.md).
- [Connect an external repository to GitLab CI/CD](../../ci/ci_cd_for_external_repos/index.md).
- [Fork a project](repository/forking_workflow.md#create-a-fork).
-- [Adjust project visibility and access levels](settings/index.md#configure-project-visibility-features-and-permissions).
+- Adjust [project visibility](../../user/public_access.md#change-project-visibility) and [permissions](settings/index.md#configure-project-features-and-permissions).
- [Limitations on project and group names](../../user/reserved_names.md#limitations-on-project-and-group-names)
## Troubleshooting
When working with projects, you might encounter the following issues, or require alternate methods to complete specific tasks.
+### `An error occurred while fetching commit data`
+
+When you visit a project, the message `An error occurred while fetching commit data` might be displayed
+if you use an ad blocker in your browser. The solution is to disable your ad blocker
+for the GitLab instance you are trying to access.
+
### Find projects using an SQL query
While in [a Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session), you can find and store an array of projects based on a SQL query:
diff --git a/doc/user/public_access.md b/doc/user/public_access.md
index 5f43f177e36..37b79c8f1a8 100644
--- a/doc/user/public_access.md
+++ b/doc/user/public_access.md
@@ -67,7 +67,7 @@ Prerequisite:
- You must have the Owner role for a project.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Settings > General**.
1. Expand **Visibility, project features, permissions**.
1. Change **Project visibility** to either **Private**, **Internal**, or **Public**.
@@ -86,7 +86,7 @@ Prerequisites:
restrictive as the new setting of the parent group. For example, you cannot set a group
to private if a subgroup or project in that group is public.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your group.
+1. On the left sidebar, select **Search or go to** and find your group.
1. On the left sidebar, select **Settings > General**.
1. Expand **Naming, visibility**.
1. Under **Visibility level** select either **Private**, **Internal**, or **Public**.
diff --git a/doc/user/report_abuse.md b/doc/user/report_abuse.md
index bad62825ba5..45113562e87 100644
--- a/doc/user/report_abuse.md
+++ b/doc/user/report_abuse.md
@@ -1,5 +1,5 @@
---
-stage: Anti-Abuse
+stage: Govern
group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -24,10 +24,19 @@ You can report a user through their:
## Report abuse from the user's profile page
+> - Report abuse from overflow menu [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/414773) in GitLab 16.4 [with a flag](../administration/feature_flags.md) named `user_profile_overflow_menu_vue`. Disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/414773) in GitLab 16.4.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../administration/feature_flags.md) named `user_profile_overflow_menu_vue`.
+On GitLab.com, this feature is available.
+
To report abuse from a user's profile page:
1. Anywhere in GitLab, select the name of the user.
-1. In the upper-right corner of the user's profile, select **Report abuse to administrator** (**{information-o}**).
+1. In the upper-right corner of the user's profile, if the `user_profile_overflow_menu_vue` feature flag is:
+ - Enabled, select the vertical ellipsis (**{ellipsis_v}**), then **Report abuse to administrator**.
+ - Disabled, select **Report abuse to administrator** (**{information-o}**).
1. Select a reason for reporting the user.
1. Complete an abuse report.
1. Select **Send report**.
diff --git a/doc/user/search/advanced_search.md b/doc/user/search/advanced_search.md
index c12d7889fb8..c1da3e9e2ba 100644
--- a/doc/user/search/advanced_search.md
+++ b/doc/user/search/advanced_search.md
@@ -39,8 +39,6 @@ You can use advanced search in:
Advanced search uses [Elasticsearch syntax](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html#simple-query-string-syntax). The syntax supports both exact and fuzzy search queries.
-<!-- markdownlint-disable -->
-
| Syntax | Description | Example |
|--------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `"` | Exact search | [`"gem sidekiq"`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=%22gem+sidekiq%22) |
@@ -53,11 +51,12 @@ Advanced search uses [Elasticsearch syntax](https://www.elastic.co/guide/en/elas
| `#` | Issue ID | [`#23456`](https://gitlab.com/search?snippets=&scope=issues&repository_ref=&search=%2323456&group_id=9970&project_id=278964) |
| `!` | Merge request ID | [`!23456`](https://gitlab.com/search?snippets=&scope=merge_requests&repository_ref=&search=%2123456&group_id=9970&project_id=278964) |
-### Refining user search
+### User search
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388409) in GitLab 15.10.
+> Ability to refine user search [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/388409) in GitLab 15.10.
-In user search, a [fuzzy query](https://www.elastic.co/guide/en/elasticsearch/reference/7.2/query-dsl-fuzzy-query.html) is used by default. You can refine your search with [Elasticsearch syntax](#syntax).
+When you search for a user, a [fuzzy query](https://www.elastic.co/guide/en/elasticsearch/reference/7.2/query-dsl-fuzzy-query.html) is used by default.
+You can refine user search with [Elasticsearch syntax](#syntax).
### Code search
@@ -68,11 +67,13 @@ In user search, a [fuzzy query](https://www.elastic.co/guide/en/elasticsearch/re
| `extension:` | File extension without `.` <sup>2</sup> | [`extension:js`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=extension%3Ajs&snippets=) |
| `blob:` | Git object ID <sup>2</sup> | [`blob:998707*`](https://gitlab.com/search?snippets=false&scope=blobs&repository_ref=&search=blob%3A998707*&group_id=9970) |
-1. `path:` returns matches for full paths or subpaths.
+1. `path:` returns matches for full or partial paths.
1. `extension:` and `blob:` return exact matches only.
### Examples
+<!-- markdownlint-disable MD044 -->
+
| Query | Description |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
| [`rails -filename:gemfile.lock`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=rails+-filename%3Agemfile.lock&snippets=) | Returns `rails` in all files except the `gemfile.lock` file. |
@@ -81,7 +82,6 @@ In user search, a [fuzzy query](https://www.elastic.co/guide/en/elasticsearch/re
| [<code>helper -extension:yml -extension:js</code>](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=helper+-extension%3Ayml+-extension%3Ajs&snippets=) | Returns `helper` in all files except files with a `.yml` or `.js` extension. |
| [<code>helper path:lib/git</code>](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=helper+path%3Alib%2Fgit) | Returns `helper` in all files with a `lib/git*` path (for example, `spec/lib/gitlab`). |
-
<!-- markdownlint-enable -->
## Known issues
@@ -89,8 +89,8 @@ In user search, a [fuzzy query](https://www.elastic.co/guide/en/elasticsearch/re
- You can only search files smaller than 1 MB.
For more information, see [issue 195764](https://gitlab.com/gitlab-org/gitlab/-/issues/195764).
For self-managed GitLab instances, an administrator can
- [change this limit](../../integration/advanced_search/elasticsearch.md#advanced-search-configuration).
-- You can only use advanced search on the default branch of a project.
+ [configure this setting](../../integration/advanced_search/elasticsearch.md#advanced-search-configuration).
+- You can use advanced search on the default branch of a project only.
For more information, see [issue 229966](https://gitlab.com/gitlab-org/gitlab/-/issues/229966).
- The search query must not contain any of the following characters:
diff --git a/doc/user/search/command_palette.md b/doc/user/search/command_palette.md
index 671afe13ace..0f42e727eda 100644
--- a/doc/user/search/command_palette.md
+++ b/doc/user/search/command_palette.md
@@ -7,21 +7,17 @@ type: reference
# Command palette **(FREE ALL)**
-> Introduced in GitLab 16.2 [with a flag](../../administration/feature_flags.md) named `command_palette`. Enabled by default.
+> - Introduced in GitLab 16.2 [with a flag](../../administration/feature_flags.md) named `command_palette`. Enabled by default.
+> - Feature flag `command_palette` removed in GitLab 16.4.
You can use command palette to narrow down the scope of your search or to
find an object more quickly.
-FLAG:
-On self-managed GitLab, by default this feature is available.
-To hide the feature, an administrator can [disable the feature flag](../../administration/feature_flags.md) named `command_palette`.
-On GitLab.com, this feature is available.
-
## Open the command palette
To open the command palette:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) or use the <kbd>/</kbd> key to enable.
+1. On the left sidebar, at the top, select **Search or go to** or use the <kbd>/</kbd> key to enable.
1. Type one of the special characters:
- <kbd>></kbd> - Create a new object or find a menu item.
diff --git a/doc/user/search/exact_code_search.md b/doc/user/search/exact_code_search.md
index 8a64dc9e70f..48445ccfc3c 100644
--- a/doc/user/search/exact_code_search.md
+++ b/doc/user/search/exact_code_search.md
@@ -28,5 +28,19 @@ searches.
## Syntax
-To understand the possible filtering options, see the
-[Zoekt query syntax](https://github.com/sourcegraph/zoekt/blob/main/doc/query_syntax.md).
+This table shows some example queries for exact code search.
+
+| Query | Description |
+| -------------------- |-------------------------------------------------------------------------------------- |
+| `foo` | Returns files that contain `foo` |
+| `"class foo"` | Returns files that contain the exact string `class foo` |
+| `class foo` | Returns files that contain both `class` and `foo` |
+| `foo or bar` | Returns files that contain either `foo` or `bar` |
+| `class Foo` | Returns files that contain `class` (case insensitive) and `Foo` (case sensitive) |
+| `class Foo case:yes` | Returns files that contain `class` and `Foo` (both case sensitive) |
+| `foo -bar` | Returns files that contain `foo` but not `bar` |
+| `foo file:js` | Searches for `foo` in files with names that contain `js` |
+| `foo -file:test` | Searches for `foo` in files with names that do not contain `test` |
+| `foo lang:ruby` | Searches for `foo` in Ruby source code |
+| `foo f:\.js$` | Searches for `foo` in files with names that end with `.js` |
+| `foo.*bar` | Searches for strings that match the regular expression `foo.*bar` |
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index 5600f18c61c..8c7db5ca29e 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -17,23 +17,26 @@ Both types of search are the same, except when you are searching through code.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68640) in GitLab 14.3.
-To improve the performance of your instance's global search, a GitLab administrator
-can limit the search scope by disabling the following [`ops` feature flags](../../development/feature_flags/index.md#ops-type).
-
-| Scope | Feature flag | Description |
-|--|--|--|
-| Code | `global_search_code_tab` | When enabled, global search includes code. |
-| Commits | `global_search_commits_tab` | When enabled, global search includes commits. |
-| Issues | `global_search_issues_tab` | When enabled, global search includes issues. |
-| Merge requests | `global_search_merge_requests_tab` | When enabled, global search includes merge requests. |
-| Users | `global_search_users_tab` | When enabled, global search includes users. |
-| Wiki | `global_search_wiki_tab` | When enabled, global search includes project and [group wikis](../project/wiki/group.md). |
+To improve the performance of your instance's global search, an administrator can limit the search scope
+by disabling one or more [`ops` feature flags](../../development/feature_flags/index.md#ops-type).
+
+| Scope | Feature flag | Description |
+|----------------|------------------------------------|-------------------------------------------------------------------------------------------|
+| Code | `global_search_code_tab` | When enabled, global search includes code. |
+| Commits | `global_search_commits_tab` | When enabled, global search includes commits. |
+| Issues | `global_search_issues_tab` | When enabled, global search includes issues. |
+| Merge requests | `global_search_merge_requests_tab` | When enabled, global search includes merge requests. |
+| Users | `global_search_users_tab` | When enabled, global search includes users. |
+| Wiki | `global_search_wiki_tab` | When enabled, global search includes project and [group wikis](../project/wiki/group.md). |
All global search scopes are enabled by default on self-managed instances.
## Global search validation
-Global search ignores and logs as abusive any search with:
+> - Support for partial matches in issue search [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71913) in GitLab 14.9 [with a flag](../../administration/feature_flags.md) named `issues_full_text_search`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124703) in GitLab 16.2. Feature flag `issues_full_text_search` removed.
+
+Global search ignores and logs as abusive any search that includes:
- Fewer than two characters
- A term longer than 100 characters (URL search terms must not exceed 200 characters)
@@ -47,11 +50,28 @@ Global search only flags with an error any search that includes more than:
- 4096 characters
- 64 terms
+Partial matches are not supported in issue search.
+For example, when you search issues for `play`, the query does not return issues that contain `display`.
+However, the query matches all possible variations of the string (for example, `plays`).
+
+## Autocomplete suggestions
+
+As you type in the search box, autocomplete suggestions are displayed for:
+
+- [Projects](#search-for-a-project-by-full-path) and groups
+- Users
+- Help pages
+- Project features (for example, milestones)
+- Settings (for example, user settings)
+- Recently viewed merge requests
+- Recently viewed issues and epics
+- [GitLab Flavored Markdown references](../markdown.md#gitlab-specific-references) for issues in a project
+
## Search in all GitLab
To search in all GitLab:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**).
+1. On the left sidebar, at the top, select **Search or go to**.
1. Type your search query. You must type at least two characters.
1. Press <kbd>Enter</kbd> to search, or select from the list.
@@ -61,18 +81,56 @@ The results are displayed. To filter the results, on the left sidebar, select a
To search in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Search GitLab** (**{search}**) again and type the string you want to search for.
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Search or go to** again and type the string you want to search for.
1. Press <kbd>Enter</kbd> to search, or select from the list.
The results are displayed. To filter the results, on the left sidebar, select a filter.
+## Search for a project by full path
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108906) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `full_path_project_search`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114932) in GitLab 15.11. Feature flag `full_path_project_search` removed.
+
+You can search for a project by entering its full path (including the namespace it belongs to) in the search box.
+As you type the project path, [autocomplete suggestions](#autocomplete-suggestions) are displayed.
+
+For example:
+
+- `gitlab-org/gitlab` searches for the `gitlab` project in the `gitlab-org` namespace.
+- `gitlab-org/` displays autocomplete suggestions for projects that belong to the `gitlab-org` namespace.
+
+## Include archived projects in search results
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121981) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `search_projects_hide_archived`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/413821) in GitLab 16.3. Feature flag `search_projects_hide_archived` removed.
+
+By default, archived projects are excluded from search results.
+To include archived projects:
+
+1. On the project search page, on the left sidebar, select the **Include archived** checkbox.
+1. On the left sidebar, select **Apply**.
+
+## Exclude issues in archived projects from search results
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124846) in GitLab 16.2 [with a flag](../../administration/feature_flags.md) named `search_issues_hide_archived_projects`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available,
+an administrator can [enable the feature flag](../../administration/feature_flags.md) named `search_issues_hide_archived_projects`. On GitLab.com, this feature is not available.
+
+By default, issues in archived projects are included in search results.
+To exclude issues in archived projects, ensure the `search_issues_hide_archived_projects` flag is enabled.
+
+To include issues in archived projects with `search_issues_hide_archived_projects` enabled,
+you must add the parameter `include_archived=true` to the URL.
+
## Search for code
To search for code in a project:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Search GitLab** (**{search}**) again and type the code you want to search for.
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Search or go to** again and type the code you want to search for.
1. Press <kbd>Enter</kbd> to search, or select from the list.
Code search shows only the first result in the file.
@@ -97,110 +155,26 @@ To filter code search results by one or more languages:
1. On the code search page, on the left sidebar, select one or more languages.
1. On the left sidebar, select **Apply**.
-## Exclude search results
-
-### From archived projects
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121981) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `search_projects_hide_archived`. Disabled by default.
-
-FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available,
-an administrator can [enable the feature flag](../../administration/feature_flags.md) named `search_projects_hide_archived`. On GitLab.com, this feature is not available.
-
-Archived projects are included in search results by default. To exclude archived projects, ensure the `search_projects_hide_archived` flag is enabled.
-
-To include archived projects with `search_projects_hide_archived` enabled, you must add the parameter `include_archived=true` to the URL.
-
-### From issues in archived projects
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124846) in GitLab 16.2 [with a flag](../../administration/feature_flags.md) named `search_issues_hide_archived_projects`. Disabled by default.
-
-FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available,
-an administrator can [enable the feature flag](../../administration/feature_flags.md) named `search_issues_hide_archived_projects`. On GitLab.com, this feature is not available.
-
-Issues in archived projects are included in search results by default. To exclude issues in archived projects, ensure the `search_issues_hide_archived_projects` flag is enabled.
-
-To include issues in archived projects with `search_issues_hide_archived_projects` enabled, you must add the parameter `include_archived=true` to the URL.
-
-## Search for a project by full path
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108906) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `full_path_project_search`. Disabled by default.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114932) in GitLab 15.11. Feature flag `full_path_project_search` removed.
-
-You can search for a project by entering its full path (including the namespace it belongs to) in the search box.
-As you type the project path, [autocomplete suggestions](#autocomplete-suggestions) are displayed.
-
-For example:
-
-- `gitlab-org/gitlab` searches for the `gitlab` project in the `gitlab-org` namespace.
-- `gitlab-org/` displays autocomplete suggestions for projects that belong to the `gitlab-org` namespace.
-
## Search for a commit SHA
To search for a commit SHA:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
-1. Select **Search GitLab** (**{search}**) again and type the commit SHA you want to search for.
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Search or go to** again and type the commit SHA you want to search for.
1. Press <kbd>Enter</kbd> to search, or select from the list.
If a single result is returned, GitLab redirects to the commit result
and gives you the option to return to the search results page.
-## Search for specific terms
-
-> - [Support for partial matches in issue search](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71913) removed in GitLab 14.9 [with a flag](../../administration/feature_flags.md) named `issues_full_text_search`. Disabled by default.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124703) in GitLab 16.2. Feature flag `issues_full_text_search` removed.
-
-You can filter issues and merge requests by specific terms included in titles or descriptions.
-
-- Syntax
- - Searches look for all the words in a query, in any order. For example: searching
- issues for `display bug` returns all issues matching both those words, in any order.
- - To find the exact term, use double quotes: `"display bug"`.
-- Limitation
- - For performance reasons, terms shorter than three characters are ignored. For example: searching
- issues for `included in titles` is same as `included titles`
- - Search is limited to 4096 characters and 64 terms per query.
- - When searching issues, partial matches are not allowed. For example: searching for `play` will
- not return issues that have the word `display`. But variations of words match, so searching
- for `displays` also returns issues that have the word `display`.
-
## Run a search from history
You can run a search from history for issues and merge requests. Search history is stored locally
in your browser. To run a search from history:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. To view recent searches:
- For issues, on the left sidebar, select **Plan > Issues**. Above the list, to the left of the search box, select (**{history}**).
- For merge requests, on the left sidebar, select **Code > Merge requests**. Above the list, to the left of the search box, select **Recent searches**.
1. From the dropdown list, select a search.
-
-## Remove search filters
-
-Individual filters can be removed by selecting the filter's (x) button or backspacing. The entire search filter can be cleared by selecting the search box's (x) button or via <kbd>⌘</kbd> (Mac) + <kbd>⌫</kbd>.
-
-To delete filter tokens one at a time, the <kbd>⌥</kbd> (Mac) / <kbd>Control</kbd> + <kbd>⌫</kbd> keyboard combination can be used.
-
-## Autocomplete suggestions
-
-In the search box, you can view autocomplete suggestions for:
-
-- [Projects](#search-for-a-project-by-full-path) and groups
-- Users
-- Various help pages (try and type **API help**)
-- Project feature pages (try and type **milestones**)
-- Various settings pages (try and type **user settings**)
-- Recently viewed issues (try and type some word from the title of a recently viewed issue)
-- Recently viewed merge requests (try and type some word from the title of a recently viewed merge request)
-- Recently viewed epics (try and type some word from the title of a recently viewed epic)
-- [GitLab Flavored Markdown](../markdown.md#gitlab-specific-references) (GLFM) for issues in a project (try and type a GLFM reference for an issue)
-
-## Search settings
-
-You can search inside a Project, Group, Administrator, or User's settings by entering
-a search term in the search box located at the top of the page. The search results
-appear highlighted in the sections that match the search term.
diff --git a/doc/user/shortcuts.md b/doc/user/shortcuts.md
index d8b4d147d24..b0ef1fcc99a 100644
--- a/doc/user/shortcuts.md
+++ b/doc/user/shortcuts.md
@@ -109,18 +109,19 @@ These shortcuts are available when viewing issues:
These shortcuts are available when viewing [merge requests](project/merge_requests/index.md):
-| macOS shortcut | Windows shortcut | Description |
-|-----------------------------------|---------------------|-------------|
-| <kbd>]</kbd> or <kbd>j</kbd> | | Move to next file. |
-| <kbd>&#91;</kbd> or <kbd>k</kbd> | | Move to previous file. |
+| macOS shortcut | Windows shortcut | Description |
+|-----------------------------------|-----------------------------------|-------------|
+| <kbd>]</kbd> or <kbd>j</kbd> | | Move to next file. |
+| <kbd>&#91;</kbd> or <kbd>k</kbd> | | Move to previous file. |
| <kbd>Command</kbd> + <kbd>p</kbd> | <kbd>Control</kbd> + <kbd>p</kbd> | Search for, and then jump to a file for review. |
-| <kbd>n</kbd> | | Move to next unresolved discussion. |
-| <kbd>p</kbd> | | Move to previous unresolved discussion. |
-| <kbd>b</kbd> | | Copy source branch name. |
-| <kbd>c</kbd> + <kbd>r</kbd> | | Copy merge request reference. |
-| <kbd>r</kbd> | | Start writing a comment. Pre-selected text is quoted in the comment. Can't be used to reply in a thread. |
-| <kbd>c</kbd> | | Move to next commit. |
-| <kbd>x</kbd> | | Move to previous commit. |
+| <kbd>n</kbd> | | Move to next unresolved discussion. |
+| <kbd>p</kbd> | | Move to previous unresolved discussion. |
+| <kbd>b</kbd> | | Copy source branch name. |
+| <kbd>c</kbd> + <kbd>r</kbd> | | Copy merge request reference. |
+| <kbd>r</kbd> | | Start writing a comment. Pre-selected text is quoted in the comment. Can't be used to reply in a thread. |
+| <kbd>c</kbd> | | Move to next commit. |
+| <kbd>x</kbd> | | Move to previous commit. |
+| <kbd>f</kbd> | | Toggle file browser. |
### Project files
@@ -324,20 +325,25 @@ These shortcuts are available when viewing [epics](group/epics/index.md):
## Disable keyboard shortcuts
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22113) in GitLab 12.8.
+> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/202494) from the shortcuts page to user preferences in GitLab 16.4.
To disable keyboard shortcuts:
-1. While viewing a page that supports keyboard shortcuts, and outside a text box,
-press <kbd>?</kbd> to display the list of shortcuts.
-1. Select **Toggle shortcuts**.
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. In the **Behavior** section, clear the **Enable keyboard shortcuts** checkbox.
+1. Select **Save changes**.
## Enable keyboard shortcuts
+> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/202494) from the shortcuts page to user preferences in GitLab 16.4.
+
To enable keyboard shortcuts:
-1. On the left sidebar, at the bottom, select **Help** (**{question}**), then **Keyboard shortcuts**.
-1. Select **Toggle shortcuts**.
+1. On the left sidebar, select your avatar.
+1. Select **Preferences**.
+1. In the **Behavior** section, select the **Enable keyboard shortcuts** checkbox.
+1. Select **Save changes**.
## Troubleshooting
diff --git a/doc/user/snippets.md b/doc/user/snippets.md
index a5a547727d3..dbcc90c26df 100644
--- a/doc/user/snippets.md
+++ b/doc/user/snippets.md
@@ -63,17 +63,17 @@ In GitLab versions 13.0 and later, snippets are [versioned by default](#versione
To discover all snippets visible to you in GitLab, you can:
- **View a project's snippets**:
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Snippets**.
- **View all the snippets you created**:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. Select **Snippets**.
On GitLab.com, you can also visit your [snippets directly](https://gitlab.com/dashboard/snippets).
- **Explore all public snippets**:
- 1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+ 1. On the left sidebar, select **Search or go to**.
1. Select **Explore**.
1. Select **Snippets**.
@@ -110,11 +110,11 @@ content was saved as the initial commit to the snippets' repository.
## Filenames
Snippets support syntax highlighting based on the filename and
-extension provided for them. While you can submit a snippet
-without a filename and extension, it needs a valid name so the
-content can be created as a file in the snippet's repository.
+extension provided for them. You can submit a snippet
+without a filename and extension, but a valid name is required for
+creating content as a file in the repository.
-If you don't give a snippet a filename and extension,
+If no filename and extension are provided for the snippet,
GitLab adds a filename in the format `snippetfile<x>.txt`
where `<x>` represents a number added to the file, starting with 1. This
number increments if you add more unnamed snippets.
@@ -138,7 +138,7 @@ A single snippet can support up to 10 files, which helps keep related files toge
- A `gulpfile.js` file and a `package.json` file, which together can be
used to bootstrap a project and manage its dependencies.
-If you need more than 10 files for your snippet, we recommend you create a
+If you need more than 10 files for your snippet, you should create a
[wiki](project/wiki/index.md) instead. Wikis are available for projects at all
subscription levels, and [groups](project/wiki/group.md) for
[GitLab Premium](https://about.gitlab.com/pricing/).
@@ -167,9 +167,9 @@ To delete a file from your snippet through the GitLab UI:
## Clone snippets
-Instead of copying a snippet to a local file, you may want to clone a snippet to
-preserve its relationship with the repository, so you can receive or make updates
-as needed. Select **Clone** on a snippet to display the URLs to clone with SSH or HTTPS:
+To ensure you receive updates, clone the snippet instead of copying it locally. Cloning
+maintains the snippet's connection with the repository. Select **Clone** on a snippet
+to display the URLs to clone with SSH or HTTPS:
![Clone snippet](img/snippet_clone_button_v13_0.png)
@@ -229,7 +229,7 @@ Prerequisites:
To do this task:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. On the left sidebar, select **Code > Snippets**.
1. Select the snippet you want to report as spam.
1. Select **Submit as spam**.
diff --git a/doc/user/ssh.md b/doc/user/ssh.md
index f418cc5f6b7..0e10fea18ad 100644
--- a/doc/user/ssh.md
+++ b/doc/user/ssh.md
@@ -1,5 +1,5 @@
---
-stage: Manage
+stage: Govern
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
@@ -22,7 +22,7 @@ SSH uses two keys, a public key and a private key.
It is not possible to reveal confidential data by uploading your public key. When you need to copy or upload your SSH public key, make sure you do not accidentally copy or upload your private key instead.
-You can use your private key to [sign commits](project/repository/ssh_signed_commits/index.md),
+You can use your private key to [sign commits](project/repository/signed_commits/ssh.md),
which makes your use of GitLab and your data even more secure.
This signature then can be verified by anyone using your public key.
@@ -74,11 +74,16 @@ must have [OpenSSH 8.2](https://www.openssh.com/releasenotes.html#8.2) or later
### RSA SSH keys
+> Maximum RSA key length [changed](https://gitlab.com/groups/gitlab-org/-/epics/11186) in GitLab 16.3.
+
Available documentation suggests ED25519 is more secure than RSA.
If you use an RSA key, the US National Institute of Standards and Technology in
[Publication 800-57 Part 3 (PDF)](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57Pt3r1.pdf)
-recommends a key size of at least 2048 bits. The default key size depends on your version of `ssh-keygen`.
+recommends a key size of at least 2048 bits. Due to limitations in Go,
+RSA keys [cannot exceed 8192 bits](#tls-server-sent-certificate-containing-rsa-key-larger-than-8192-bits).
+
+The default key size depends on your version of `ssh-keygen`.
Review the `man` page for your installed `ssh-keygen` command for details.
## See if you have an existing SSH key pair
@@ -523,6 +528,17 @@ are **explicitly not supported** and may stop working at any time.
## Troubleshooting
+### TLS: server sent certificate containing RSA key larger than 8192 bits
+
+In GitLab 16.3 and later, Go limits RSA keys to a maximum of 8192 bits.
+To check the length of a key:
+
+```shell
+openssl rsa -in <your-key-file> -text -noout | grep "Key:"
+```
+
+Replace any key longer than 8192 bits with a shorter key.
+
### Password prompt with `git clone`
When you run `git clone`, you may be prompted for a password, like `git@gitlab.example.com's password:`.
diff --git a/doc/user/storage_management_automation.md b/doc/user/storage_management_automation.md
index 210aca4ee35..9a505d23597 100644
--- a/doc/user/storage_management_automation.md
+++ b/doc/user/storage_management_automation.md
@@ -28,7 +28,7 @@ You must use the following scopes to [authenticate](../api/rest/index.md#authent
- Full API access with the `api` scope.
- At least the Maintainer role on all projects.
-You can use command line tools or a programming language to interact with the REST API.
+You can use command-line tools or a programming language to interact with the REST API.
### Command line
@@ -71,7 +71,7 @@ see [Efficient DevSecOps workflows: Hands-on `python-gitlab` API automation](htt
For more information about other API client libraries, see [Third-party clients](../api/rest/index.md#third-party-clients).
NOTE:
-Use [GitLab Duo Code Suggestions](project/repository/code_suggestions.md) to write code more efficiently.
+Use [GitLab Duo Code Suggestions](project/repository/code_suggestions/index.md) to write code more efficiently.
## Strategies for storage analysis
diff --git a/doc/user/tasks.md b/doc/user/tasks.md
index c340bb736ef..f4fec01d42b 100644
--- a/doc/user/tasks.md
+++ b/doc/user/tasks.md
@@ -12,7 +12,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Known limitation:
-- [Tasks currently cannot be accessed via REST API.](https://gitlab.com/gitlab-org/gitlab/-/issues/368055)
+- [Tasks cannot be accessed via REST API.](https://gitlab.com/gitlab-org/gitlab/-/issues/368055)
For the latest updates, check the [Tasks Roadmap](https://gitlab.com/groups/gitlab-org/-/epics/7103).
@@ -41,7 +41,7 @@ View tasks in issues, in the **Tasks** section.
You can also [filter the list of issues](project/issues/managing_issues.md#filter-the-list-of-issues)
for `Type = task`.
-If you select a task from an issue, it opens in a modal window.
+If you select a task from an issue, it opens in a dialog window.
If you select a task to open in a new browser tab, or select it from the issue list,
the task opens in a full-page view.
@@ -107,7 +107,7 @@ To edit a task:
### Using the rich text editor
-> - Rich text editing in the modal view [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363007) in GitLab 15.6 [with a flag](../administration/feature_flags.md) named `work_items_mvc`. Disabled by default.
+> - Rich text editing in the dialog view [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363007) in GitLab 15.6 [with a flag](../administration/feature_flags.md) named `work_items_mvc`. Disabled by default.
> - Rich text editing in the full page view [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/104533) in GitLab 15.7.
FLAG:
@@ -336,7 +336,7 @@ To refer to a task elsewhere in GitLab, you can use its full URL or a short refe
To copy the task reference to your clipboard:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your task to view it.
1. In the top right corner, select the vertical ellipsis (**{ellipsis_v}**), then select **Copy Reference**.
@@ -356,7 +356,7 @@ For more information about creating comments by sending an email and the necessa
To copy the task's email address:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Plan > Issues**, then select your issue to view it.
1. In the top right corner, select the vertical ellipsis (**{ellipsis_v}**), then select **Copy task email address**.
diff --git a/doc/user/usage_quotas.md b/doc/user/usage_quotas.md
index ade99a5fef8..8c6840fae92 100644
--- a/doc/user/usage_quotas.md
+++ b/doc/user/usage_quotas.md
@@ -23,7 +23,7 @@ Prerequisites:
- To view storage usage for a project, you must have at least the Maintainer role for the project or Owner role for the namespace.
- To view storage usage for a namespace, you must have the Owner role for the namespace.
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. On the left sidebar, select **Settings > Usage Quotas**.
1. Select the **Storage** tab.
@@ -179,7 +179,11 @@ available decreases. All projects no longer have the read-only status because 40
## Namespace storage limit
Namespaces on GitLab SaaS have a storage limit. For more information, see our [pricing page](https://about.gitlab.com/pricing/).
-This limit is not visible on the **Usage quotas** page, but is prior to the limit being [applied](#namespace-storage-limit-application-schedule). Self-managed deployments are not affected.
+
+After namespace storage limits are enforced, view them in the **Usage quotas** page.
+For more information about the namespace storage limit enforcement, see the FAQ pages for the [Free](https://about.gitlab.com/pricing/faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier) and [Paid](https://about.gitlab.com/pricing/faq-paid-storage-transfer/) tiers.
+
+Namespace storage limits do not apply to self-managed deployments, but administrators can [manage the repository size](../administration/settings/account_and_limit_settings.md#repository-size-limit).
Storage types that add to the total namespace storage are:
@@ -196,17 +200,20 @@ If your total namespace storage exceeds the available namespace storage quota, a
To notify you that you have nearly exceeded your namespace storage quota:
-- In the command line interface, a notification displays after each `git push` action when you've reached 95% and 100% of your namespace storage quota.
+- In the command-line interface, a notification displays after each `git push` action when you've reached 95% and 100% of your namespace storage quota.
- In the GitLab UI, a notification displays when you've reached 75%, 95%, and 100% of your namespace storage quota.
- GitLab sends an email to members with the Owner role to notify them when namespace storage usage is at 70%, 85%, 95%, and 100%.
-To prevent exceeding the namespace storage quota, you can:
+To prevent exceeding the namespace storage limit, you can:
-- Reduce storage consumption by following the suggestions in the [Manage Your Storage Usage](#manage-your-storage-usage) section of this page.
-- Apply for [GitLab for Education](https://about.gitlab.com/solutions/education/join/), [GitLab for Open Source](https://about.gitlab.com/solutions/open-source/join/), or [GitLab for Startups](https://about.gitlab.com/solutions/startups/) if you meet the eligibility requirements.
-- Consider using a [self-managed instance](../subscriptions/self_managed/index.md) of GitLab which does not have these limits on the free tier.
+- [Manage your storage usage](#manage-your-storage-usage).
+- If you meet the eligibility requirements, you can apply for:
+ - [GitLab for Education](https://about.gitlab.com/solutions/education/join/)
+ - [GitLab for Open Source](https://about.gitlab.com/solutions/open-source/join/)
+ - [GitLab for Startups](https://about.gitlab.com/solutions/startups/)
+- Consider using a [self-managed instance](../subscriptions/self_managed/index.md) of GitLab, which does not have these limits on the Free tier.
- [Purchase additional storage](../subscriptions/gitlab_com/index.md#purchase-more-storage-and-transfer) units at $60/year for 10 GB of storage.
-- [Start a trial](https://about.gitlab.com/free-trial/) or [upgrade to GitLab Premium or Ultimate](https://about.gitlab.com/pricing/) which include higher limits and features that enable growing teams to ship faster without sacrificing on quality.
+- [Start a trial](https://about.gitlab.com/free-trial/) or [upgrade to GitLab Premium or Ultimate](https://about.gitlab.com/pricing/), which include higher limits and features to enable growing teams to ship faster without sacrificing on quality.
- [Talk to an expert](https://page.gitlab.com/usage_limits_help.html) for more information about your options.
### View project fork storage usage
@@ -215,14 +222,10 @@ A cost factor is applied to the storage consumed by project forks so that forks
To view the amount of namespace storage the fork has used:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project or group.
+1. On the left sidebar, select **Search or go to** and find your project or group.
1. On the left sidebar, select **Settings > Usage Quotas**.
1. Select the **Storage** tab. The **Total** column displays the amount of namespace storage used by the fork as a portion of the actual size of the fork on disk.
The cost factor applies to the project repository, LFS objects, job artifacts, packages, snippets, and the wiki.
The cost factor does not apply to private forks in namespaces on the Free plan.
-
-### Namespace storage limit application schedule
-
-Information on when namespace-level storage limits are applied is available on these FAQ pages for the [Free](https://about.gitlab.com/pricing/faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier) and [Paid](https://about.gitlab.com/pricing/faq-paid-storage-transfer/) tier.
diff --git a/doc/user/workspace/configuration.md b/doc/user/workspace/configuration.md
index 3900c95e41a..3684845c2c7 100644
--- a/doc/user/workspace/configuration.md
+++ b/doc/user/workspace/configuration.md
@@ -4,7 +4,7 @@ group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Workspace configuration (Beta) **(PREMIUM ALL)**
+# Workspace configuration **(PREMIUM ALL BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112397) in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `remote_development_feature_flag`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/391543) in GitLab 16.0.
@@ -25,6 +25,8 @@ which you can customize to meet the specific needs of each project.
## Set up a workspace
+> Support for private projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124273) in GitLab 16.4.
+
### Prerequisites
- Set up a Kubernetes cluster that the GitLab agent for Kubernetes supports.
@@ -48,8 +50,8 @@ which you can customize to meet the specific needs of each project.
You can use any agent defined under the root group of your project,
provided that remote development is properly configured for that agent.
- You must have at least the Developer role in the root group.
-- In each public project you want to use this feature for, create a [devfile](index.md#devfile):
- 1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+- In each project you want to use this feature for, create a [devfile](index.md#devfile):
+ 1. On the left sidebar, select **Search or go to** and find your project.
1. In the root directory of your project, create a file named `.devfile.yaml`.
You can use one of the [example configurations](index.md#example-configurations).
- Ensure the container images used in the devfile support [arbitrary user IDs](index.md#arbitrary-user-ids).
@@ -58,12 +60,11 @@ which you can customize to meet the specific needs of each project.
To create a workspace:
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. On the left sidebar, select **Search or go to**.
1. Select **Your work**.
1. Select **Workspaces**.
1. Select **New workspace**.
1. From the **Select project** dropdown list, [select a project with a `.devfile.yaml` file](#prerequisites).
- You can only create workspaces for public projects.
1. From the **Select cluster agent** dropdown list, select a cluster agent owned by the group the project belongs to.
1. In **Time before automatic termination**, enter the number of hours until the workspace automatically terminates.
This timeout is a safety measure to prevent a workspace from consuming excessive resources or running indefinitely.
@@ -75,6 +76,8 @@ You also have access to the terminal and can install any necessary dependencies.
## Connect to a workspace with SSH
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/10478) in GitLab 16.3.
+
Prerequisites:
- SSH must be enabled for the workspace.
diff --git a/doc/user/workspace/create_image.md b/doc/user/workspace/create_image.md
index 43140a622e0..df70ff31194 100644
--- a/doc/user/workspace/create_image.md
+++ b/doc/user/workspace/create_image.md
@@ -4,7 +4,7 @@ group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Tutorial: Create a custom workspace image that supports arbitrary user IDs (Beta) **(PREMIUM ALL)**
+# Tutorial: Create a custom workspace image that supports arbitrary user IDs **(PREMIUM ALL BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112397) in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `remote_development_feature_flag`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/391543) in GitLab 16.0.
diff --git a/doc/user/workspace/index.md b/doc/user/workspace/index.md
index 51e3e905a92..1284067a391 100644
--- a/doc/user/workspace/index.md
+++ b/doc/user/workspace/index.md
@@ -4,7 +4,7 @@ group: IDE
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Workspaces (Beta) **(PREMIUM ALL)**
+# Workspaces **(PREMIUM ALL BETA)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112397) in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `remote_development_feature_flag`. Disabled by default.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/391543) in GitLab 16.0.
@@ -35,7 +35,8 @@ When you [create a workspace](configuration.md#set-up-a-workspace), you must:
- Assign the workspace to a specific project.
- Select a project with a [`.devfile.yaml`](#devfile) file.
-The workspace can then interact with the GitLab API based on the permissions granted to the current user.
+The workspace can interact with the GitLab API, with the access level defined by current user permissions.
+A running workspace remains accessible even if user permissions are later revoked.
### Open and manage workspaces from a project
@@ -43,7 +44,7 @@ The workspace can then interact with the GitLab API based on the permissions gra
To open a workspace from a file or the repository file list:
-1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
+1. On the left sidebar, select **Search or go to** and find your project.
1. In the upper right, select **Edit**.
1. From the dropdown list, under **Your workspaces**, select the workspace.
@@ -128,13 +129,15 @@ The Web IDE is the only code editor available for workspaces.
The Web IDE is powered by the [GitLab VS Code fork](https://gitlab.com/gitlab-org/gitlab-web-ide-vscode-fork).
For more information, see [Web IDE](../project/web_ide/index.md).
-## Private repositories
+## Personal access token
-You cannot [create a workspace](configuration.md#set-up-a-workspace) for a private repository
-because GitLab does not inject any credentials into the workspace.
-You can only create a workspace for public repositories that have a devfile.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129715) in GitLab 16.4.
-From a workspace, you can clone any repository manually.
+When you [create a workspace](configuration.md#set-up-a-workspace), you get a personal access token with `write_repository` permission.
+This token is used to initially clone the project while starting the workspace.
+
+Any Git operation you perform in the workspace uses this token for authentication and authorization.
+When you terminate the workspace, the token is revoked.
## Pod interaction in a cluster
diff --git a/gems/activerecord-gitlab/lib/active_record/gitlab_patches/rescue_from.rb b/gems/activerecord-gitlab/lib/active_record/gitlab_patches/rescue_from.rb
index eaa42d1523d..faabddd2686 100644
--- a/gems/activerecord-gitlab/lib/active_record/gitlab_patches/rescue_from.rb
+++ b/gems/activerecord-gitlab/lib/active_record/gitlab_patches/rescue_from.rb
@@ -3,8 +3,10 @@
module ActiveRecord
module GitlabPatches
# This adds `rescue_from` to ActiveRecord::Base.
- # Currently, only errors called from `ActiveRecord::Relation#exec_queries`
- # will be handled by `rescue_from`.
+ # Currently only the following places will be handled by `rescue_from`:
+ #
+ # - `ActiveRecord::Relation#load`, and other methods that call
+ # `ActiveRecord::Relation#exec_queries`.
#
# class ApplicationRecord < ActiveRecord::Base
# rescue_from MyException, with: :my_handler
diff --git a/gems/activerecord-gitlab/spec/active_record/gitlab_patches/rescue_from_spec.rb b/gems/activerecord-gitlab/spec/active_record/gitlab_patches/rescue_from_spec.rb
index c1537c3bd90..22729edb014 100644
--- a/gems/activerecord-gitlab/spec/active_record/gitlab_patches/rescue_from_spec.rb
+++ b/gems/activerecord-gitlab/spec/active_record/gitlab_patches/rescue_from_spec.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-RSpec.describe ActiveRecord::GitlabPatches::RescueFrom, :without_sqlite3 do
+RSpec.describe ActiveRecord::GitlabPatches::RescueFrom do
let(:model_with_rescue_from) do
- Class.new(ActiveRecord::Base) do
- rescue_from ActiveRecord::ConnectionNotEstablished, with: :handle_exception
+ Class.new(Project) do
+ rescue_from ActiveRecord::StatementInvalid, with: :handle_exception
class << self
def handle_exception(exception); end
@@ -12,20 +12,18 @@ RSpec.describe ActiveRecord::GitlabPatches::RescueFrom, :without_sqlite3 do
end
let(:model_without_rescue_from) do
- Class.new(ActiveRecord::Base)
+ Class.new(Project)
end
- it 'triggers rescue_from' do
- stub_const('ModelWithRescueFrom', model_with_rescue_from)
+ context 'for errors from ActiveRelation.load' do
+ it 'triggers rescue_from' do
+ expect(model_with_rescue_from).to receive(:handle_exception)
- expect(model_with_rescue_from).to receive(:handle_exception)
-
- expect { model_with_rescue_from.all.load }.not_to raise_error
- end
-
- it 'does not trigger rescue_from' do
- stub_const('ModelWithoutRescueFrom', model_without_rescue_from)
+ expect { model_with_rescue_from.where('BADQUERY').load }.not_to raise_error
+ end
- expect { model_without_rescue_from.all.load }.to raise_error(ActiveRecord::ConnectionNotEstablished)
+ it 'does not trigger rescue_from' do
+ expect { model_without_rescue_from.where('BADQUERY').load }.to raise_error(ActiveRecord::StatementInvalid)
+ end
end
end
diff --git a/gems/click_house-client/lib/click_house/client.rb b/gems/click_house-client/lib/click_house/client.rb
index abc54f2bce0..1ca3653c45f 100644
--- a/gems/click_house-client/lib/click_house/client.rb
+++ b/gems/click_house-client/lib/click_house/client.rb
@@ -6,6 +6,9 @@ require 'active_support/time'
require 'active_support/notifications'
require_relative "client/database"
require_relative "client/configuration"
+require_relative "client/bind_index_manager"
+require_relative "client/query_like"
+require_relative "client/query"
require_relative "client/formatter"
require_relative "client/response"
@@ -25,6 +28,7 @@ module ClickHouse
Error = Class.new(StandardError)
ConfigurationError = Class.new(Error)
DatabaseError = Class.new(Error)
+ QueryError = Class.new(Error)
# Executes a SELECT database query
def self.select(query, database, configuration = self.configuration)
@@ -40,15 +44,52 @@ module ClickHouse
# Executes any kinds of database query without returning any data (INSERT, DELETE)
def self.execute(query, database, configuration = self.configuration)
instrumented_execute(query, database, configuration) do |response, instrument|
- if response.headers['x-clickhouse-summary']
- instrument[:statistics] =
- Gitlab::Json.parse(response.headers['x-clickhouse-summary']).symbolize_keys
- end
+ expose_summary(response.headers, instrument)
end
true
end
+ # Inserts a gzip-compressed CSV to ClickHouse
+ #
+ # Usage:
+ #
+ # Create a compressed CSV file:
+ # > File.binwrite("my_csv.csv", ActiveSupport::Gzip.compress("id\n10\n20"))
+ #
+ # Invoke the INSERT query:
+ # > ClickHouse::Client.insert_csv('INSERT INTO events (id) FORMAT CSV', File.open("my_csv.csv"), :main)
+ def self.insert_csv(query, io, database, configuration = self.configuration)
+ db = lookup_database(configuration, database)
+
+ headers = db.headers.merge(
+ 'Transfer-Encoding' => 'chunked',
+ 'Content-Length' => File.size(io).to_s,
+ 'Content-Encoding' => 'gzip'
+ )
+
+ query = ClickHouse::Client::Query.build(query)
+ ActiveSupport::Notifications.instrument('sql.click_house', { query: query, database: database }) do |instrument|
+ response = configuration.http_post_proc.call(
+ db.build_custom_uri(extra_variables: { query: query.to_sql }).to_s,
+ headers,
+ io
+ )
+ raise DatabaseError, response.body unless response.success?
+
+ expose_summary(response.headers, instrument)
+ end
+
+ true
+ end
+
+ private_class_method def self.expose_summary(headers, instrument)
+ return unless headers['x-clickhouse-summary']
+
+ instrument[:statistics] =
+ Gitlab::Json.parse(headers['x-clickhouse-summary']).symbolize_keys
+ end
+
private_class_method def self.lookup_database(configuration, database)
configuration.databases[database].tap do |db|
raise ConfigurationError, "The database '#{database}' is not configured" unless db
@@ -58,11 +99,21 @@ module ClickHouse
private_class_method def self.instrumented_execute(query, database, configuration)
db = lookup_database(configuration, database)
+ query = ClickHouse::Client::Query.build(query)
+
+ log_contents = configuration.log_proc.call(query)
+ configuration.logger.info(log_contents)
+
ActiveSupport::Notifications.instrument('sql.click_house', { query: query, database: database }) do |instrument|
+ # Use a multipart POST request where the placeholders are sent with the param_ prefix
+ # See: https://github.com/ClickHouse/ClickHouse/issues/8842
+ query_with_params = query.placeholders.transform_keys { |key| "param_#{key}" }
+ query_with_params['query'] = query.to_sql
+
response = configuration.http_post_proc.call(
db.uri.to_s,
db.headers,
- query
+ query_with_params
)
raise DatabaseError, response.body unless response.success?
diff --git a/gems/click_house-client/lib/click_house/client/bind_index_manager.rb b/gems/click_house-client/lib/click_house/client/bind_index_manager.rb
new file mode 100644
index 00000000000..618b13f2fd7
--- /dev/null
+++ b/gems/click_house-client/lib/click_house/client/bind_index_manager.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module ClickHouse
+ module Client
+ class BindIndexManager
+ def initialize(start_index = 1)
+ @current_index = start_index
+ end
+
+ def next_bind_str
+ bind_str = "$#{@current_index}"
+ @current_index += 1
+ bind_str
+ end
+ end
+ end
+end
diff --git a/gems/click_house-client/lib/click_house/client/configuration.rb b/gems/click_house-client/lib/click_house/client/configuration.rb
index 882b37993dc..4a71934466f 100644
--- a/gems/click_house-client/lib/click_house/client/configuration.rb
+++ b/gems/click_house-client/lib/click_house/client/configuration.rb
@@ -18,6 +18,9 @@ module ClickHouse
#
# *json_parser*: object for parsing JSON strings, it should respond to the "parse" method
#
+ # *logger*: object for receiving logger commands. Default `$stdout`
+ # *log_proc*: any output (e.g. structure) to wrap around the query for every statement
+ #
# Example:
#
# Gitlab::ClickHouse::Client.configure do |c|
@@ -31,6 +34,11 @@ module ClickHouse
# }
# )
#
+ # c.logger = MyLogger.new
+ # c.log_proc = ->(query) do
+ # { query_body: query.to_redacted_sql }
+ # end
+ #
# c.http_post_proc = lambda do |url, headers, body|
# options = {
# headers: headers,
@@ -44,13 +52,15 @@ module ClickHouse
#
# c.json_parser = JSON
# end
- attr_accessor :http_post_proc, :json_parser
+ attr_accessor :http_post_proc, :json_parser, :logger, :log_proc
attr_reader :databases
def initialize
@databases = {}
@http_post_proc = nil
@json_parser = JSON
+ @logger = ::Logger.new($stdout)
+ @log_proc = ->(query) { query.to_sql }
end
def register_database(name, **args)
diff --git a/gems/click_house-client/lib/click_house/client/database.rb b/gems/click_house-client/lib/click_house/client/database.rb
index faf5a953a12..9fac0df8d87 100644
--- a/gems/click_house-client/lib/click_house/client/database.rb
+++ b/gems/click_house-client/lib/click_house/client/database.rb
@@ -17,19 +17,20 @@ module ClickHouse
end
def uri
- @uri ||= begin
- parsed = Addressable::URI.parse(@url)
- parsed.query_values = @variables
- parsed
- end
+ @uri ||= build_custom_uri
+ end
+
+ def build_custom_uri(extra_variables: {})
+ parsed = Addressable::URI.parse(@url)
+ parsed.query_values = @variables.merge(extra_variables)
+ parsed
end
def headers
@headers ||= {
'X-ClickHouse-User' => @username,
'X-ClickHouse-Key' => @password,
- 'X-ClickHouse-Format' => 'JSON', # always return JSON data
- 'Content-Encoding' => 'gzip' # tell the server that we send compressed data
+ 'X-ClickHouse-Format' => 'JSON' # always return JSON data
}.freeze
end
end
diff --git a/gems/click_house-client/lib/click_house/client/formatter.rb b/gems/click_house-client/lib/click_house/client/formatter.rb
index bb60d8db7f7..de7ae72bdf8 100644
--- a/gems/click_house-client/lib/click_house/client/formatter.rb
+++ b/gems/click_house-client/lib/click_house/client/formatter.rb
@@ -7,7 +7,8 @@ module ClickHouse
TYPE_CASTERS = {
'UInt64' => ->(value) { Integer(value) },
- "DateTime64(6, 'UTC')" => ->(value) { ActiveSupport::TimeZone["UTC"].parse(value) }
+ "DateTime64(6, 'UTC')" => ->(value) { ActiveSupport::TimeZone['UTC'].parse(value) },
+ "IntervalSecond" => ->(value) { ActiveSupport::Duration.build(value.to_i) }
}.freeze
def self.format(result)
diff --git a/gems/click_house-client/lib/click_house/client/query.rb b/gems/click_house-client/lib/click_house/client/query.rb
new file mode 100644
index 00000000000..41435d239cf
--- /dev/null
+++ b/gems/click_house-client/lib/click_house/client/query.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+module ClickHouse
+ module Client
+ class Query < QueryLike
+ SUBQUERY_PLACEHOLDER_REGEX = /{\w+:Subquery}/ # exmaple: {var:Subquery}, special "internal" type for subqueries
+ PLACEHOLDER_REGEX = /{\w+:\w+}/ # exmaple: {var:UInt8}
+ PLACEHOLDER_NAME_REGEX = /{(\w+):/ # exmaple: {var:UInt8} => var
+
+ def initialize(raw_query:, placeholders: {})
+ raise QueryError, 'Empty query string given' if raw_query.blank?
+
+ @raw_query = raw_query
+ @placeholders = placeholders || {}
+ end
+
+ # List of placeholders to be sent to ClickHouse for replacement.
+ # If there are subqueries, merge their placeholders as well.
+ def placeholders
+ all_placeholders = @placeholders.select { |_, v| !v.is_a?(QueryLike) }
+ @placeholders.each do |_name, value|
+ next unless value.is_a?(QueryLike)
+
+ all_placeholders.merge!(value.placeholders) do |key, a, b|
+ raise QueryError, "mismatching values for the '#{key}' placeholder: #{a} vs #{b}"
+ end
+ end
+
+ all_placeholders
+ end
+
+ # Placeholder replacement is handled by ClickHouse, only subquery placeholders
+ # will be replaced.
+ def to_sql
+ raw_query.gsub(SUBQUERY_PLACEHOLDER_REGEX) do |placeholder_in_query|
+ value = placeholder_value(placeholder_in_query)
+
+ if value.is_a?(QueryLike)
+ value.to_sql
+ else
+ placeholder_in_query
+ end
+ end
+ end
+
+ def to_redacted_sql(bind_index_manager = BindIndexManager.new)
+ raw_query.gsub(PLACEHOLDER_REGEX) do |placeholder_in_query|
+ value = placeholder_value(placeholder_in_query)
+
+ if value.is_a?(QueryLike)
+ value.to_redacted_sql(bind_index_manager)
+ else
+ bind_index_manager.next_bind_str
+ end
+ end
+ end
+
+ def self.build(query)
+ return query if query.is_a?(ClickHouse::Client::QueryLike)
+
+ new(raw_query: query)
+ end
+
+ private
+
+ attr_reader :raw_query
+
+ def placeholder_value(placeholder_in_query)
+ placeholder = placeholder_in_query[PLACEHOLDER_NAME_REGEX, 1]
+ @placeholders.fetch(placeholder.to_sym)
+ end
+ end
+ end
+end
diff --git a/gems/click_house-client/lib/click_house/client/query_like.rb b/gems/click_house-client/lib/click_house/client/query_like.rb
new file mode 100644
index 00000000000..9e9ee46a338
--- /dev/null
+++ b/gems/click_house-client/lib/click_house/client/query_like.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module ClickHouse
+ module Client
+ class QueryLike
+ # Build a SQL string that can be executed on a ClickHouse database.
+ def to_sql
+ raise NotImplementedError
+ end
+
+ # Redacted version of the SQL query generated by the to_sql method where the
+ # placeholders are stripped. These queries are meant to be exported to external
+ # log aggregation systems.
+ def to_redacted_sql(bind_index_manager = BindIndexManager.new)
+ raise NotImplementedError
+ end
+ end
+ end
+end
diff --git a/gems/click_house-client/spec/click_house/client/bind_index_manager_spec.rb b/gems/click_house-client/spec/click_house/client/bind_index_manager_spec.rb
new file mode 100644
index 00000000000..38e0865676a
--- /dev/null
+++ b/gems/click_house-client/spec/click_house/client/bind_index_manager_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ClickHouse::Client::BindIndexManager do
+ describe '#next_bind_str' do
+ context 'when initialized without a start index' do
+ let(:bind_manager) { described_class.new }
+
+ it 'starts from index 1 by default' do
+ expect(bind_manager.next_bind_str).to eq('$1')
+ end
+
+ it 'increments the bind string on subsequent calls' do
+ bind_manager.next_bind_str
+ expect(bind_manager.next_bind_str).to eq('$2')
+ end
+ end
+
+ context 'when initialized with a start index' do
+ let(:bind_manager) { described_class.new(2) }
+
+ it 'starts from the given index' do
+ expect(bind_manager.next_bind_str).to eq('$2')
+ end
+
+ it 'increments the bind string on subsequent calls' do
+ bind_manager.next_bind_str
+ expect(bind_manager.next_bind_str).to eq('$3')
+ end
+ end
+ end
+end
diff --git a/gems/click_house-client/spec/click_house/client/database_spec.rb b/gems/click_house-client/spec/click_house/client/database_spec.rb
index a74d4a119a4..fdb4c72c0cb 100644
--- a/gems/click_house-client/spec/click_house/client/database_spec.rb
+++ b/gems/click_house-client/spec/click_house/client/database_spec.rb
@@ -24,7 +24,6 @@ RSpec.describe ClickHouse::Client::Database do
describe '#headers' do
it 'returns the correct headers' do
expect(database.headers).to eq({
- "Content-Encoding" => "gzip",
"X-ClickHouse-Format" => "JSON",
'X-ClickHouse-User' => 'user',
'X-ClickHouse-Key' => 'pass'
diff --git a/gems/click_house-client/spec/click_house/client/formatter_spec.rb b/gems/click_house-client/spec/click_house/client/formatter_spec.rb
new file mode 100644
index 00000000000..0af3aa0bdbc
--- /dev/null
+++ b/gems/click_house-client/spec/click_house/client/formatter_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ClickHouse::Client::Formatter do
+ it 'formats values according to types in metadata' do
+ # this query here is just for documentation purposes, it generates the response below
+ _query = <<~SQL.squish
+ SELECT toUInt64(1) as uint64,
+ toDateTime64('2016-06-15 23:00:00', 6, 'UTC') as datetime64_6,
+ INTERVAL 1 second as interval_second
+ SQL
+
+ response_json = <<~JSON
+{
+ "meta":
+ [
+ {
+ "name": "uint64",
+ "type": "UInt64"
+ },
+ {
+ "name": "datetime64_6",
+ "type": "DateTime64(6, 'UTC')"
+ },
+ {
+ "name": "interval_second",
+ "type": "IntervalSecond"
+ }
+ ],
+
+ "data":
+ [
+ {
+ "uint64": "1",
+ "datetime64_6": "2016-06-15 23:00:00.000000",
+ "interval_second": "1"
+ }
+ ],
+
+ "rows": 1,
+
+ "statistics":
+ {
+ "elapsed": 0.002101,
+ "rows_read": 1,
+ "bytes_read": 1
+ }
+}
+ JSON
+
+ parsed_response = JSON.parse(response_json)
+ formatted_response = described_class.format(parsed_response)
+
+ expect(formatted_response).to(
+ eq(
+ [{ "uint64" => 1,
+ "datetime64_6" => ActiveSupport::TimeZone["UTC"].parse("2016-06-15 23:00:00"),
+ "interval_second" => 1.second }]
+ )
+ )
+ end
+end
diff --git a/gems/click_house-client/spec/click_house/client/query_like_spec.rb b/gems/click_house-client/spec/click_house/client/query_like_spec.rb
new file mode 100644
index 00000000000..8b8426bd5fd
--- /dev/null
+++ b/gems/click_house-client/spec/click_house/client/query_like_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ClickHouse::Client::QueryLike do
+ subject(:query) { described_class.new }
+
+ describe '#to_sql' do
+ it { expect { query.to_sql }.to raise_error(NotImplementedError) }
+ end
+
+ describe '#to_redacted_sql' do
+ it { expect { query.to_redacted_sql }.to raise_error(NotImplementedError) }
+ end
+end
diff --git a/gems/click_house-client/spec/click_house/client/query_spec.rb b/gems/click_house-client/spec/click_house/client/query_spec.rb
new file mode 100644
index 00000000000..82733e523b1
--- /dev/null
+++ b/gems/click_house-client/spec/click_house/client/query_spec.rb
@@ -0,0 +1,125 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ClickHouse::Client::Query do
+ subject(:query) { described_class.new(raw_query: raw_query, placeholders: placeholders) }
+
+ let(:sql) { query.to_sql }
+ let(:redacted_sql) { query.to_redacted_sql }
+
+ context 'when using no placeholders' do
+ let(:raw_query) { 'SELECT * FROM events' }
+ let(:placeholders) { nil }
+
+ it { expect(sql).to eq(raw_query) }
+ it { expect(redacted_sql).to eq(raw_query) }
+
+ context 'when placeholders is an empty hash' do
+ let(:placeholders) { {} }
+
+ it { expect(sql).to eq(raw_query) }
+ it { expect(redacted_sql).to eq(raw_query) }
+ end
+ end
+
+ context 'when placeholders are given' do
+ let(:raw_query) { 'SELECT * FROM events WHERE id = {id:UInt64}' }
+ let(:placeholders) { { id: 1 } }
+
+ it { expect(sql).to eq(raw_query) }
+ it { expect(redacted_sql).to eq('SELECT * FROM events WHERE id = $1') }
+ end
+
+ context 'when multiple placeholders are given' do
+ let(:raw_query) do
+ <<~SQL.squish
+ SELECT *
+ FROM events
+ WHERE
+ id = {id:UInt64} AND
+ title = {some_title:String} AND
+ another_id = {id:UInt64}
+ SQL
+ end
+
+ let(:placeholders) { { id: 1, some_title: "'title'" } }
+
+ it do
+ expect(sql).to eq(raw_query)
+ end
+
+ it do
+ expect(redacted_sql).to eq(
+ <<~SQL.squish
+ SELECT *
+ FROM events
+ WHERE
+ id = $1 AND
+ title = $2 AND
+ another_id = $3
+ SQL
+ )
+ end
+ end
+
+ context 'when dealing with subqueries' do
+ let(:raw_query) { 'SELECT * FROM events WHERE id < {min_id:UInt64} AND id IN ({q:Subquery})' }
+
+ let(:subquery) do
+ described_class.new(raw_query: 'SELECT id FROM events WHERE id > {max_id:UInt64}', placeholders: { max_id: 11 })
+ end
+
+ let(:placeholders) { { min_id: 100, q: subquery } }
+
+ it 'replaces the subquery but preserves the other placeholders' do
+ q = 'SELECT * FROM events WHERE id < {min_id:UInt64} AND id IN (SELECT id FROM events WHERE id > {max_id:UInt64})'
+ expect(sql).to eq(q)
+ end
+
+ it 'replaces the subquery and replaces the placeholders with indexed values' do
+ expect(redacted_sql).to eq('SELECT * FROM events WHERE id < $1 AND id IN (SELECT id FROM events WHERE id > $2)')
+ end
+
+ it 'merges the placeholders' do
+ expect(query.placeholders).to eq({ min_id: 100, max_id: 11 })
+ end
+ end
+
+ describe 'validation' do
+ context 'when SQL string is empty' do
+ let(:raw_query) { '' }
+ let(:placeholders) { {} }
+
+ it 'raises error' do
+ expect { query }.to raise_error(ClickHouse::Client::QueryError, /Empty query string given/)
+ end
+ end
+
+ context 'when SQL string is nil' do
+ let(:raw_query) { nil }
+ let(:placeholders) { {} }
+
+ it 'raises error' do
+ expect { query }.to raise_error(ClickHouse::Client::QueryError, /Empty query string given/)
+ end
+ end
+
+ context 'when same placeholder value does not match' do
+ let(:raw_query) { 'SELECT id FROM events WHERE id = {id:UInt64} AND id IN ({q:Subquery})' }
+
+ let(:subquery) do
+ subquery_string = 'SELECT id FROM events WHERE id = {id:UInt64}'
+ described_class.new(raw_query: subquery_string, placeholders: { id: 10 })
+ end
+
+ let(:placeholders) { { id: 5, q: subquery } }
+
+ it 'raises error' do
+ expect do
+ query.placeholders
+ end.to raise_error(ClickHouse::Client::QueryError, /mismatching values for the 'id' placeholder/)
+ end
+ end
+ end
+end
diff --git a/gems/click_house-client/spec/click_house/client_spec.rb b/gems/click_house-client/spec/click_house/client_spec.rb
index 883199198ba..ab2407a83d7 100644
--- a/gems/click_house-client/spec/click_house/client_spec.rb
+++ b/gems/click_house-client/spec/click_house/client_spec.rb
@@ -30,6 +30,9 @@ RSpec.describe ClickHouse::Client do
let(:configuration) do
ClickHouse::Client::Configuration.new.tap do |config|
+ config.log_proc = ->(query) do
+ { query_string: query.to_sql }
+ end
config.register_database(:test_db, **database_config)
config.http_post_proc = ->(_url, _headers, _query) {
body = File.read(query_result_fixture)
@@ -71,7 +74,7 @@ RSpec.describe ClickHouse::Client do
end
context 'when the DB is not configured' do
- it 'raises erro' do
+ it 'raises error' do
expect do
described_class.select('SELECT * FROM issues', :different_db, configuration)
end.to raise_error(ClickHouse::Client::ConfigurationError, /not configured/)
@@ -94,5 +97,34 @@ RSpec.describe ClickHouse::Client do
end.to raise_error(ClickHouse::Client::DatabaseError, 'some error')
end
end
+
+ describe 'default logging' do
+ let(:fake_logger) { instance_double("Logger", info: 'logged!') }
+ let(:query_string) { 'SELECT * FROM issues' }
+
+ before do
+ configuration.logger = fake_logger
+ end
+
+ shared_examples 'proper logging' do
+ it 'calls the custom logger and log_proc' do
+ expect(fake_logger).to receive(:info).at_least(:once).with({ query_string: query_string })
+
+ described_class.select(query_object, :test_db, configuration)
+ end
+ end
+
+ context 'when query is a string' do # rubocop:disable RSpec/MultipleMemoizedHelpers
+ let(:query_object) { query_string }
+
+ it_behaves_like 'proper logging'
+ end
+
+ context 'when query is a Query object' do # rubocop:disable RSpec/MultipleMemoizedHelpers
+ let(:query_object) { ClickHouse::Client::Query.new(raw_query: query_string) }
+
+ it_behaves_like 'proper logging'
+ end
+ end
end
end
diff --git a/gems/config/rubocop.yml b/gems/config/rubocop.yml
index 58746de53b0..72b37aa60b5 100644
--- a/gems/config/rubocop.yml
+++ b/gems/config/rubocop.yml
@@ -2,7 +2,7 @@
# (AllCops/Exclude: 'gems/**/*') if RuboCop cop is run within `gems/...`.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/417281
<%
- relative_path = ENV['PWD'].delete_prefix(File.expand_path('../..'))
+ relative_path = ENV['PWD'].delete_prefix(File.expand_path('../..'))
RuboCop::ConfigLoader.ignore_parent_exclusion = relative_path.start_with?('/gems/')
%>
---
@@ -61,6 +61,9 @@ Gitlab/RSpec/AvoidSetup:
Graphql/AuthorizeTypes:
Enabled: false
+Gitlab/Json:
+ Enabled: false
+
# This cop doesn't make sense in the context of gems
Graphql/Descriptions:
Enabled: false
diff --git a/gems/csv_builder/lib/csv_builder/gzip.rb b/gems/csv_builder/lib/csv_builder/gzip.rb
index 60875006a35..f97c066705a 100644
--- a/gems/csv_builder/lib/csv_builder/gzip.rb
+++ b/gems/csv_builder/lib/csv_builder/gzip.rb
@@ -2,12 +2,14 @@
module CsvBuilder
class Gzip < CsvBuilder::Builder
- # Writes the CSV file compressed and yields the written tempfile.
+ # Writes the CSV file compressed and yields the written tempfile and rows written.
+ #
#
# Example:
- # > CsvBuilder::Gzip.new(Issue, { title: -> (row) { row.title.upcase }, id: :id }).render do |tempfile|
+ # > CsvBuilder::Gzip.new(Issue, { title: -> (row) { row.title.upcase }, id: :id }).render do |tempfile, rows|
# > puts tempfile.path
# > puts `zcat #{tempfile.path}`
+ # > puts rows
# > end
def render
Tempfile.open(['csv_builder_gzip', '.csv.gz']) do |tempfile|
@@ -16,7 +18,7 @@ module CsvBuilder
write_csv csv, until_condition: -> {} # truncation must be handled outside of the CsvBuilder
csv.close
- yield tempfile
+ yield tempfile, @rows_written
end
end
end
diff --git a/gems/csv_builder/spec/csv_builder/gzip_spec.rb b/gems/csv_builder/spec/csv_builder/gzip_spec.rb
index 9d24d351247..22462d8dd0a 100644
--- a/gems/csv_builder/spec/csv_builder/gzip_spec.rb
+++ b/gems/csv_builder/spec/csv_builder/gzip_spec.rb
@@ -26,6 +26,13 @@ RSpec.describe CsvBuilder::Gzip do
])
end
+ it 'yields the number of written rows as the second argument' do
+ row_count = 0
+ builder.render { |_, rows| row_count = rows }
+
+ expect(row_count).to eq(2)
+ end
+
it 'requires a block' do
expect { builder.render }.to raise_error(LocalJumpError)
end
diff --git a/gems/gem.gitlab-ci.yml b/gems/gem.gitlab-ci.yml
index 4e91f0cbe44..a379a887bdd 100644
--- a/gems/gem.gitlab-ci.yml
+++ b/gems/gem.gitlab-ci.yml
@@ -55,7 +55,7 @@ rubocop:
rspec:
extends: .ruby_matrix
script:
- - bundle exec rspec
+ - RAILS_ENV=test bundle exec rspec
coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
artifacts:
expire_in: 31d
diff --git a/gems/gitlab-http/.gitignore b/gems/gitlab-http/.gitignore
new file mode 100644
index 00000000000..b04a8c840df
--- /dev/null
+++ b/gems/gitlab-http/.gitignore
@@ -0,0 +1,11 @@
+/.bundle/
+/.yardoc
+/_yardoc/
+/coverage/
+/doc/
+/pkg/
+/spec/reports/
+/tmp/
+
+# rspec failure tracking
+.rspec_status
diff --git a/gems/gitlab-http/.gitlab-ci.yml b/gems/gitlab-http/.gitlab-ci.yml
new file mode 100644
index 00000000000..cf85b7fcc2e
--- /dev/null
+++ b/gems/gitlab-http/.gitlab-ci.yml
@@ -0,0 +1,4 @@
+include:
+ - local: gems/gem.gitlab-ci.yml
+ inputs:
+ gem_name: "gitlab-http"
diff --git a/gems/gitlab-http/.rspec b/gems/gitlab-http/.rspec
new file mode 100644
index 00000000000..34c5164d9b5
--- /dev/null
+++ b/gems/gitlab-http/.rspec
@@ -0,0 +1,3 @@
+--format documentation
+--color
+--require spec_helper
diff --git a/gems/gitlab-http/.rubocop.yml b/gems/gitlab-http/.rubocop.yml
new file mode 100644
index 00000000000..73ea5f610b3
--- /dev/null
+++ b/gems/gitlab-http/.rubocop.yml
@@ -0,0 +1,22 @@
+inherit_from:
+ - ../config/rubocop.yml
+
+Naming/ClassAndModuleCamelCase:
+ AllowedNames:
+ - HTTP_V2
+
+Performance/RegexpMatch:
+ Enabled: false
+
+Style/SpecialGlobalVars:
+ Enabled: false
+
+Lint/DuplicateBranch:
+ Enabled: false
+
+RSpec/MultipleMemoizedHelpers:
+ Enabled: false
+
+RSpec/FilePath:
+ CustomTransform:
+ HTTP_V2: http_v2
diff --git a/gems/gitlab-http/Gemfile b/gems/gitlab-http/Gemfile
new file mode 100644
index 00000000000..a6a5c2a4bc1
--- /dev/null
+++ b/gems/gitlab-http/Gemfile
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+source "https://rubygems.org"
+
+# Specify your gem's dependencies in gitlab-http.gemspec
+gemspec
+
+group :development, :test do
+ gem 'gitlab-rspec', path: '../gitlab-rspec'
+end
+
+gem 'gitlab-utils', path: '../gitlab-utils'
diff --git a/gems/gitlab-http/Gemfile.lock b/gems/gitlab-http/Gemfile.lock
new file mode 100644
index 00000000000..4afa39ef750
--- /dev/null
+++ b/gems/gitlab-http/Gemfile.lock
@@ -0,0 +1,185 @@
+PATH
+ remote: ../gitlab-rspec
+ specs:
+ gitlab-rspec (0.1.0)
+ activesupport (>= 6.1, < 7.1)
+ rspec (~> 3.0)
+
+PATH
+ remote: ../gitlab-utils
+ specs:
+ gitlab-utils (0.1.0)
+ actionview (>= 6.1.7.2)
+ activesupport (>= 6.1.7.2)
+ addressable (~> 2.8)
+ nokogiri (~> 1.15.2)
+ rake (~> 13.0)
+
+PATH
+ remote: .
+ specs:
+ gitlab-http (0.1.0)
+ activesupport (~> 7.0.6)
+ httparty (~> 0.21.0)
+ ipaddress (~> 0.8.3)
+ nokogiri (~> 1.15.4)
+ railties (~> 7.0.6)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actionpack (7.0.7)
+ actionview (= 7.0.7)
+ activesupport (= 7.0.7)
+ rack (~> 2.0, >= 2.2.4)
+ rack-test (>= 0.6.3)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
+ actionview (7.0.7)
+ activesupport (= 7.0.7)
+ builder (~> 3.1)
+ erubi (~> 1.4)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
+ activesupport (7.0.7)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ tzinfo (~> 2.0)
+ addressable (2.8.4)
+ public_suffix (>= 2.0.2, < 6.0)
+ ast (2.4.2)
+ builder (3.2.4)
+ concurrent-ruby (1.2.2)
+ crack (0.4.5)
+ rexml
+ crass (1.0.6)
+ diff-lcs (1.5.0)
+ erubi (1.12.0)
+ gitlab-styles (10.1.0)
+ rubocop (~> 1.50.2)
+ rubocop-graphql (~> 0.18)
+ rubocop-performance (~> 1.15)
+ rubocop-rails (~> 2.17)
+ rubocop-rspec (~> 2.22)
+ hashdiff (1.0.1)
+ httparty (0.21.0)
+ mini_mime (>= 1.0.0)
+ multi_xml (>= 0.5.2)
+ i18n (1.14.1)
+ concurrent-ruby (~> 1.0)
+ ipaddress (0.8.3)
+ json (2.6.3)
+ loofah (2.21.3)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.12.0)
+ method_source (1.0.0)
+ mini_mime (1.1.2)
+ mini_portile2 (2.8.4)
+ minitest (5.18.1)
+ multi_xml (0.6.0)
+ nokogiri (1.15.4)
+ mini_portile2 (~> 2.8.2)
+ racc (~> 1.4)
+ parallel (1.23.0)
+ parser (3.2.2.3)
+ ast (~> 2.4.1)
+ racc
+ public_suffix (5.0.1)
+ racc (1.7.1)
+ rack (2.2.7)
+ rack-test (2.1.0)
+ rack (>= 1.3)
+ rails-dom-testing (2.0.3)
+ activesupport (>= 4.2.0)
+ nokogiri (>= 1.6)
+ rails-html-sanitizer (1.6.0)
+ loofah (~> 2.21)
+ nokogiri (~> 1.14)
+ railties (7.0.7)
+ actionpack (= 7.0.7)
+ activesupport (= 7.0.7)
+ method_source
+ rake (>= 12.2)
+ thor (~> 1.0)
+ zeitwerk (~> 2.5)
+ rainbow (3.1.1)
+ rake (13.0.6)
+ regexp_parser (2.8.1)
+ rexml (3.2.5)
+ rspec (3.12.0)
+ rspec-core (~> 3.12.0)
+ rspec-expectations (~> 3.12.0)
+ rspec-mocks (~> 3.12.0)
+ rspec-core (3.12.2)
+ rspec-support (~> 3.12.0)
+ rspec-expectations (3.12.3)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.12.0)
+ rspec-mocks (3.12.5)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.12.0)
+ rspec-rails (6.0.3)
+ actionpack (>= 6.1)
+ activesupport (>= 6.1)
+ railties (>= 6.1)
+ rspec-core (~> 3.12)
+ rspec-expectations (~> 3.12)
+ rspec-mocks (~> 3.12)
+ rspec-support (~> 3.12)
+ rspec-support (3.12.1)
+ rubocop (1.50.2)
+ json (~> 2.3)
+ parallel (~> 1.10)
+ parser (>= 3.2.0.0)
+ rainbow (>= 2.2.2, < 4.0)
+ regexp_parser (>= 1.8, < 3.0)
+ rexml (>= 3.2.5, < 4.0)
+ rubocop-ast (>= 1.28.0, < 2.0)
+ ruby-progressbar (~> 1.7)
+ unicode-display_width (>= 2.4.0, < 3.0)
+ rubocop-ast (1.29.0)
+ parser (>= 3.2.1.0)
+ rubocop-capybara (2.18.0)
+ rubocop (~> 1.41)
+ rubocop-factory_bot (2.23.1)
+ rubocop (~> 1.33)
+ rubocop-graphql (0.19.0)
+ rubocop (>= 0.87, < 2)
+ rubocop-performance (1.18.0)
+ rubocop (>= 1.7.0, < 2.0)
+ rubocop-ast (>= 0.4.0)
+ rubocop-rails (2.20.2)
+ activesupport (>= 4.2.0)
+ rack (>= 1.1)
+ rubocop (>= 1.33.0, < 2.0)
+ rubocop-rspec (2.23.0)
+ rubocop (~> 1.33)
+ rubocop-capybara (~> 2.17)
+ rubocop-factory_bot (~> 2.22)
+ ruby-progressbar (1.13.0)
+ thor (1.2.2)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ unicode-display_width (2.4.2)
+ webmock (3.18.1)
+ addressable (>= 2.8.0)
+ crack (>= 0.3.2)
+ hashdiff (>= 0.4.0, < 2.0.0)
+ zeitwerk (2.6.8)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ gitlab-http!
+ gitlab-rspec!
+ gitlab-styles (~> 10.1.0)
+ gitlab-utils!
+ rspec-rails (~> 6.0.3)
+ rubocop (~> 1.50.2)
+ rubocop-rspec (~> 2.22)
+ webmock (~> 3.18.1)
+
+BUNDLED WITH
+ 2.4.14
diff --git a/gems/gitlab-http/README.md b/gems/gitlab-http/README.md
new file mode 100644
index 00000000000..13ff330bb19
--- /dev/null
+++ b/gems/gitlab-http/README.md
@@ -0,0 +1,42 @@
+# Gitlab::HTTP_V2
+
+This gem is used as a proxy for all outbounding http connection
+coming from callbacks, services and hooks. The direct use of the HTTParty
+is discouraged because it can lead to several security problems, like SSRF
+calling internal IP or services.
+
+## Usage
+
+### Configuration
+
+```ruby
+Gitlab::HTTP_V2.configure do |config|
+ config.allowed_internal_uris = []
+
+ config.log_exception_proc = ->(exception, extra_info) do
+ # operation
+ end
+ config.silent_mode_log_info_proc = ->(message, http_method) do
+ # operation
+ end
+end
+```
+
+### Actions
+
+Basic examples;
+
+```ruby
+Gitlab::HTTP_V2.post(uri, body: body)
+
+Gitlab::HTTP_V2.try_get(uri, params)
+
+response = Gitlab::HTTP_V2.head(project_url, verify: true)
+
+Gitlab::HTTP_V2.post(path, base_uri: base_uri, **params)
+```
+
+## Development
+
+After checking out the repo, run `bundle` to install dependencies.
+Then, run `RACK_ENV=test bundle exec rspec spec` to run the tests.
diff --git a/gems/gitlab-http/gitlab-http.gemspec b/gems/gitlab-http/gitlab-http.gemspec
new file mode 100644
index 00000000000..2653d4d4fb7
--- /dev/null
+++ b/gems/gitlab-http/gitlab-http.gemspec
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require_relative "lib/gitlab/http_v2/version"
+
+Gem::Specification.new do |spec|
+ spec.name = "gitlab-http"
+ spec.version = Gitlab::HTTP_V2::Version::VERSION
+ spec.authors = ["GitLab Engineers"]
+ spec.email = ["engineering@gitlab.com"]
+
+ spec.summary = "GitLab HTTP client"
+ spec.description = "GitLab HTTP client"
+ spec.homepage = "https://gitlab.com/gitlab-org/gitlab/-/tree/master/gems/gitlab-http"
+ spec.license = 'MIT'
+ spec.required_ruby_version = ">= 3.0"
+ spec.metadata["rubygems_mfa_required"] = "true"
+
+ spec.files = Dir['lib/**/*.rb']
+ spec.test_files = Dir['spec/**/*']
+ spec.require_paths = ["lib"]
+
+ spec.add_runtime_dependency 'activesupport', '~> 7.0.6'
+ spec.add_runtime_dependency 'httparty', '~> 0.21.0'
+ spec.add_runtime_dependency 'ipaddress', '~> 0.8.3'
+ spec.add_runtime_dependency 'nokogiri', '~> 1.15.4'
+ spec.add_runtime_dependency "railties", "~> 7.0.6"
+
+ spec.add_development_dependency 'gitlab-styles', '~> 10.1.0'
+ spec.add_development_dependency 'rspec-rails', '~> 6.0.3'
+ spec.add_development_dependency "rubocop", "~> 1.50.2"
+ spec.add_development_dependency "rubocop-rspec", "~> 2.22"
+ spec.add_development_dependency 'webmock', '~> 3.18.1'
+end
diff --git a/gems/gitlab-http/lib/gitlab-http.rb b/gems/gitlab-http/lib/gitlab-http.rb
new file mode 100644
index 00000000000..1fc0e16ec9f
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab-http.rb
@@ -0,0 +1,11 @@
+# rubocop:disable Naming/FileName
+
+# frozen_string_literal: true
+
+# When we say gem 'gitlab-http' in Gemfile, bundler will also run require gitlab-http for us and it'd
+# resolve the conflict when we call `Gitlab::HTTP_V2.configure` first time.
+# See more: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125024#note_1502698924
+
+require_relative 'gitlab/http_v2'
+
+# rubocop:enable Naming/FileName
diff --git a/gems/gitlab-http/lib/gitlab/http_v2.rb b/gems/gitlab-http/lib/gitlab/http_v2.rb
new file mode 100644
index 00000000000..8f3ede95530
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require_relative "http_v2/configuration"
+require_relative "http_v2/patches"
+require_relative "http_v2/client"
+
+module Gitlab
+ module HTTP_V2
+ SUPPORTED_HTTP_METHODS = [:get, :try_get, :post, :patch, :put, :delete, :head, :options].freeze
+
+ class << self
+ delegate(*SUPPORTED_HTTP_METHODS, to: ::Gitlab::HTTP_V2::Client)
+
+ def configuration
+ @configuration ||= Configuration.new
+ end
+
+ def configure
+ yield(configuration)
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/buffered_io.rb b/gems/gitlab-http/lib/gitlab/http_v2/buffered_io.rb
new file mode 100644
index 00000000000..478b9102dec
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/buffered_io.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require 'net/http'
+require 'webmock' if Rails.env.test?
+
+# The Ruby 3.2 does change Net protocol. Please see;
+# https://github.com/ruby/ruby/blob/ruby_3_2/lib/net/protocol.rb#L194-L206
+# vs https://github.com/ruby/ruby/blob/ruby_3_1/lib/net/protocol.rb#L190-L200
+NET_PROTOCOL_VERSION_0_2_0 = Gem::Version.new(Net::Protocol::VERSION) >= Gem::Version.new('0.2.0')
+
+module Gitlab
+ module HTTP_V2
+ # Net::BufferedIO is overwritten by webmock but in order to test this class,
+ # it needs to inherit from the original BufferedIO.
+ # https://github.com/bblimke/webmock/blob/867f4b290fd133658aa9530cba4ba8b8c52c0d35/lib/webmock/http_lib_adapters/net_http.rb#L266
+ parent_class = if const_defined?('WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetBufferedIO') &&
+ Rails.env.test?
+ WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetBufferedIO
+ else
+ Net::BufferedIO
+ end
+
+ class BufferedIo < parent_class
+ HEADER_READ_TIMEOUT = 20
+
+ # rubocop: disable Style/RedundantReturn
+ # rubocop: disable Cop/LineBreakAfterGuardClauses
+ # rubocop: disable Layout/EmptyLineAfterGuardClause
+
+ # Original method:
+ # https://github.com/ruby/ruby/blob/cdb7d699d0641e8f081d590d06d07887ac09961f/lib/net/protocol.rb#L190-L200
+ def readuntil(terminator, ignore_eof = false, start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC))
+ if NET_PROTOCOL_VERSION_0_2_0
+ offset = @rbuf_offset
+ begin
+ until idx = @rbuf.index(terminator, offset) # rubocop:disable Lint/AssignmentInCondition
+ if (elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) > HEADER_READ_TIMEOUT
+ raise Gitlab::HTTP_V2::HeaderReadTimeout,
+ "Request timed out after reading headers for #{elapsed} seconds"
+ end
+
+ offset = @rbuf.bytesize
+ rbuf_fill
+ end
+
+ return rbuf_consume(idx + terminator.bytesize - @rbuf_offset)
+ rescue EOFError
+ raise unless ignore_eof
+ return rbuf_consume(@rbuf.size)
+ end
+ else
+ begin
+ until idx = @rbuf.index(terminator) # rubocop:disable Lint/AssignmentInCondition
+ if (elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) > HEADER_READ_TIMEOUT
+ raise Gitlab::HTTP_V2::HeaderReadTimeout,
+ "Request timed out after reading headers for #{elapsed} seconds"
+ end
+
+ rbuf_fill
+ end
+
+ return rbuf_consume(idx + terminator.size)
+ rescue EOFError
+ raise unless ignore_eof
+ return rbuf_consume(@rbuf.size)
+ end
+ end
+ end
+ # rubocop: enable Style/RedundantReturn
+ # rubocop: enable Cop/LineBreakAfterGuardClauses
+ # rubocop: enable Layout/EmptyLineAfterGuardClause
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/client.rb b/gems/gitlab-http/lib/gitlab/http_v2/client.rb
new file mode 100644
index 00000000000..8daf19d7351
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/client.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+require 'httparty'
+require 'net/http'
+require 'active_support/all'
+require_relative 'new_connection_adapter'
+require_relative "exceptions"
+
+module Gitlab
+ module HTTP_V2
+ class Client
+ DEFAULT_TIMEOUT_OPTIONS = {
+ open_timeout: 10,
+ read_timeout: 20,
+ write_timeout: 30
+ }.freeze
+ DEFAULT_READ_TOTAL_TIMEOUT = 30.seconds
+
+ SILENT_MODE_ALLOWED_METHODS = [
+ Net::HTTP::Get,
+ Net::HTTP::Head,
+ Net::HTTP::Options,
+ Net::HTTP::Trace
+ ].freeze
+
+ include HTTParty # rubocop:disable Gitlab/HTTParty
+
+ class << self
+ alias_method :httparty_perform_request, :perform_request
+ end
+
+ connection_adapter NewConnectionAdapter
+
+ def self.perform_request(http_method, path, options, &block)
+ raise_if_blocked_by_silent_mode(http_method) if options.delete(:silent_mode_enabled)
+
+ log_info = options.delete(:extra_log_info)
+ options_with_timeouts =
+ if !options.has_key?(:timeout)
+ options.with_defaults(DEFAULT_TIMEOUT_OPTIONS)
+ else
+ options
+ end
+
+ if options[:stream_body]
+ httparty_perform_request(http_method, path, options_with_timeouts, &block)
+ else
+ begin
+ start_time = nil
+ read_total_timeout = options.fetch(:timeout, DEFAULT_READ_TOTAL_TIMEOUT)
+
+ httparty_perform_request(http_method, path, options_with_timeouts) do |fragment|
+ start_time ||= system_monotonic_time
+ elapsed = system_monotonic_time - start_time
+
+ raise ReadTotalTimeout, "Request timed out after #{elapsed} seconds" if elapsed > read_total_timeout
+
+ yield fragment if block
+ end
+ rescue HTTParty::RedirectionTooDeep
+ raise RedirectionTooDeep
+ rescue *HTTP_ERRORS => e
+ extra_info = log_info || {}
+ extra_info = log_info.call(e, path, options) if log_info.respond_to?(:call)
+ configuration.log_exception(e, extra_info)
+
+ raise e
+ end
+ end
+ end
+
+ def self.try_get(path, options = {}, &block)
+ self.get(path, options, &block) # rubocop:disable Style/RedundantSelf
+ rescue *HTTP_ERRORS
+ nil
+ end
+
+ def self.raise_if_blocked_by_silent_mode(http_method)
+ return if SILENT_MODE_ALLOWED_METHODS.include?(http_method)
+
+ configuration.silent_mode_log_info('Outbound HTTP request blocked', http_method.to_s)
+
+ raise SilentModeBlockedError, 'only get, head, options, and trace methods are allowed in silent mode'
+ end
+
+ def self.system_monotonic_time
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
+ end
+
+ def self.configuration
+ Gitlab::HTTP_V2.configuration
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/configuration.rb b/gems/gitlab-http/lib/gitlab/http_v2/configuration.rb
new file mode 100644
index 00000000000..98b07d0cf27
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/configuration.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module HTTP_V2
+ class Configuration
+ attr_accessor :allowed_internal_uris, :log_exception_proc, :silent_mode_log_info_proc
+
+ def log_exception(...)
+ log_exception_proc&.call(...)
+ end
+
+ def silent_mode_log_info(...)
+ silent_mode_log_info_proc&.call(...)
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/domain_allowlist_entry.rb b/gems/gitlab-http/lib/gitlab/http_v2/domain_allowlist_entry.rb
new file mode 100644
index 00000000000..5a08c891184
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/domain_allowlist_entry.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module HTTP_V2
+ class DomainAllowlistEntry
+ attr_reader :domain, :port
+
+ def initialize(domain, port: nil)
+ @domain = domain
+ @port = port
+ end
+
+ def match?(requested_domain, requested_port = nil)
+ return false unless domain == requested_domain
+ return true if port.nil?
+
+ port == requested_port
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/exceptions.rb b/gems/gitlab-http/lib/gitlab/http_v2/exceptions.rb
new file mode 100644
index 00000000000..5a34d0b9939
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/exceptions.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'net/http'
+
+module Gitlab
+ module HTTP_V2
+ BlockedUrlError = Class.new(StandardError)
+ RedirectionTooDeep = Class.new(StandardError)
+ ReadTotalTimeout = Class.new(Net::ReadTimeout)
+ HeaderReadTimeout = Class.new(Net::ReadTimeout)
+ SilentModeBlockedError = Class.new(StandardError)
+
+ HTTP_TIMEOUT_ERRORS = [
+ Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout, Gitlab::HTTP_V2::ReadTotalTimeout
+ ].freeze
+
+ HTTP_ERRORS = HTTP_TIMEOUT_ERRORS + [
+ EOFError, SocketError, OpenSSL::SSL::SSLError, OpenSSL::OpenSSLError,
+ Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH,
+ Gitlab::HTTP_V2::BlockedUrlError, Gitlab::HTTP_V2::RedirectionTooDeep,
+ Net::HTTPBadResponse
+ ].freeze
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/ip_allowlist_entry.rb b/gems/gitlab-http/lib/gitlab/http_v2/ip_allowlist_entry.rb
new file mode 100644
index 00000000000..ed5a2dba284
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/ip_allowlist_entry.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module HTTP_V2
+ class IpAllowlistEntry
+ attr_reader :ip, :port
+
+ # Argument ip should be an IPAddr object
+ def initialize(ip, port: nil)
+ @ip = ip
+ @port = port
+ end
+
+ def match?(requested_ip, requested_port = nil)
+ requested_ip = IPAddr.new(requested_ip) if requested_ip.is_a?(String)
+
+ return false unless ip_include?(requested_ip)
+ return true if port.nil?
+
+ port == requested_port
+ end
+
+ private
+
+ # Prior to ipaddr v1.2.3, if the allow list were the IPv4 to IPv6
+ # mapped address ::ffff:169.254.168.100 and the requested IP were
+ # 169.254.168.100 or ::ffff:169.254.168.100, the IP would be
+ # considered in the allow list. However, with
+ # https://github.com/ruby/ipaddr/pull/31, IPAddr#include? will
+ # only match if the IP versions are the same. This method
+ # preserves backwards compatibility if the versions differ by
+ # checking inclusion by coercing an IPv4 address to its IPv6
+ # mapped address.
+ def ip_include?(requested_ip)
+ return true if ip.include?(requested_ip)
+ return ip.include?(requested_ip.ipv4_mapped) if requested_ip.ipv4? && ip.ipv6?
+ return ip.ipv4_mapped.include?(requested_ip) if requested_ip.ipv6? && ip.ipv4?
+
+ false
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/net_http_adapter.rb b/gems/gitlab-http/lib/gitlab/http_v2/net_http_adapter.rb
new file mode 100644
index 00000000000..c6af2ed6aff
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/net_http_adapter.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'net/http'
+require 'webmock' if Rails.env.test?
+require_relative 'buffered_io'
+
+module Gitlab
+ module HTTP_V2
+ # Webmock overwrites the Net::HTTP#request method with
+ # https://github.com/bblimke/webmock/blob/867f4b290fd133658aa9530cba4ba8b8c52c0d35/lib/webmock/http_lib_adapters/net_http.rb#L74
+ # Net::HTTP#request usually calls Net::HTTP#connect but the Webmock overwrite doesn't.
+ # This makes sure that, in a test environment, the superclass is the Webmock overwrite.
+ parent_class = if defined?(WebMock) && Rails.env.test?
+ WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP)
+ else
+ Net::HTTP
+ end
+
+ class NetHttpAdapter < parent_class
+ private
+
+ def connect
+ result = super
+
+ @socket = BufferedIo.new(@socket.io,
+ read_timeout: @socket.read_timeout,
+ write_timeout: @socket.write_timeout,
+ continue_timeout: @socket.continue_timeout,
+ debug_output: @socket.debug_output)
+
+ result
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb b/gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb
new file mode 100644
index 00000000000..ee4be97dc6d
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+# This class is part of the Gitlab::HTTP wrapper. It handles local requests and header timeouts
+#
+# 1. Local requests
+# Depending on the value of the global setting allow_local_requests_from_web_hooks_and_services,
+# this adapter will allow/block connection to internal IPs and/or urls.
+#
+# This functionality can be overridden by providing the setting the option
+# allow_local_requests = true in the request. For example:
+# Gitlab::HTTP.get('http://www.gitlab.com', allow_local_requests: true)
+#
+# This option will take precedence over the global setting.
+#
+# 2. Header timeouts
+# When the use_read_total_timeout option is used, that means the receiver
+# of the HTTP request cannot be trusted. Gitlab::BufferedIo will be used,
+# to read header data. It is a modified version of Net::BufferedIO that
+# raises a timeout error if reading header data takes too much time.
+
+require 'httparty'
+require_relative 'net_http_adapter'
+require_relative 'url_blocker'
+
+module Gitlab
+ module HTTP_V2
+ class NewConnectionAdapter < HTTParty::ConnectionAdapter
+ def initialize(...)
+ super
+
+ @allow_local_requests = options.delete(:allow_local_requests)
+ @extra_allowed_uris = options.delete(:extra_allowed_uris)
+ @deny_all_requests_except_allowed = options.delete(:deny_all_requests_except_allowed)
+ @outbound_local_requests_allowlist = options.delete(:outbound_local_requests_allowlist)
+ @dns_rebinding_protection_enabled = options.delete(:dns_rebinding_protection_enabled)
+ end
+
+ def connection
+ result = validate_url_with_proxy!(uri)
+ @uri = result.uri
+ hostname = result.hostname
+
+ http = super
+ http.hostname_override = hostname if hostname
+
+ unless result.use_proxy
+ http.proxy_from_env = false
+ http.proxy_address = nil
+ end
+
+ net_adapter = NetHttpAdapter.new(http.address, http.port)
+
+ http.instance_variables.each do |variable|
+ net_adapter.instance_variable_set(variable, http.instance_variable_get(variable))
+ end
+
+ net_adapter
+ end
+
+ private
+
+ def validate_url_with_proxy!(url)
+ UrlBlocker.validate_url_with_proxy!(url, **url_blocker_options)
+ rescue UrlBlocker::BlockedUrlError => e
+ raise HTTP_V2::BlockedUrlError, "URL is blocked: #{e.message}"
+ end
+
+ def url_blocker_options
+ {
+ allow_local_network: @allow_local_requests,
+ allow_localhost: @allow_local_requests,
+ extra_allowed_uris: @extra_allowed_uris,
+ schemes: %w[http https],
+ deny_all_requests_except_allowed: @deny_all_requests_except_allowed,
+ outbound_local_requests_allowlist: @outbound_local_requests_allowlist,
+ dns_rebind_protection: @dns_rebinding_protection_enabled
+ }.compact
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/patches.rb b/gems/gitlab-http/lib/gitlab/http_v2/patches.rb
new file mode 100644
index 00000000000..3d26fbc6447
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/patches.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+require_relative "../../hostname_override_patch"
+require_relative "../../net_http/protocol_patch"
+require_relative "../../net_http/response_patch"
+require_relative "../../httparty/response_patch"
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/url_allowlist.rb b/gems/gitlab-http/lib/gitlab/http_v2/url_allowlist.rb
new file mode 100644
index 00000000000..6e17315c87d
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/url_allowlist.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'gitlab/utils/all'
+require_relative 'ip_allowlist_entry'
+require_relative 'domain_allowlist_entry'
+
+module Gitlab
+ module HTTP_V2
+ class UrlAllowlist
+ class << self
+ def ip_allowed?(ip_string, allowlist, port: nil)
+ return false if ip_string.blank?
+
+ ip_allowlist, _ = outbound_local_requests_allowlist_arrays(allowlist)
+ ip_obj = ::Gitlab::Utils.string_to_ip_object(ip_string)
+
+ ip_allowlist.any? do |ip_allowlist_entry|
+ ip_allowlist_entry.match?(ip_obj, port)
+ end
+ end
+
+ def domain_allowed?(domain_string, allowlist, port: nil)
+ return false if domain_string.blank?
+
+ _, domain_allowlist = outbound_local_requests_allowlist_arrays(allowlist)
+
+ domain_allowlist.any? do |domain_allowlist_entry|
+ domain_allowlist_entry.match?(domain_string, port)
+ end
+ end
+
+ private
+
+ def outbound_local_requests_allowlist_arrays(allowlist)
+ return [[], []] if allowlist.blank?
+
+ allowlist.reduce([[], []]) do |(ip_allowlist, domain_allowlist), string|
+ address, port = parse_addr_and_port(string)
+
+ ip_obj = ::Gitlab::Utils.string_to_ip_object(address)
+
+ if ip_obj
+ ip_allowlist << IpAllowlistEntry.new(ip_obj, port: port)
+ else
+ domain_allowlist << DomainAllowlistEntry.new(address, port: port)
+ end
+
+ [ip_allowlist, domain_allowlist]
+ end
+ end
+
+ def parse_addr_and_port(str)
+ case str
+ when /\A\[(?<address> .* )\]:(?<port> \d+ )\z/x # string like "[::1]:80"
+ address = $~[:address]
+ port = $~[:port]
+ when /\A(?<address> [^:]+ ):(?<port> \d+ )\z/x # string like "127.0.0.1:80"
+ address = $~[:address]
+ port = $~[:port]
+ else # string with no port number
+ address = str
+ port = nil
+ end
+
+ [address, port&.to_i]
+ end
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/url_blocker.rb b/gems/gitlab-http/lib/gitlab/http_v2/url_blocker.rb
new file mode 100644
index 00000000000..a794ab2f443
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/url_blocker.rb
@@ -0,0 +1,409 @@
+# frozen_string_literal: true
+
+require 'resolv'
+require 'ipaddress'
+require_relative 'url_allowlist'
+
+module Gitlab
+ module HTTP_V2
+ class UrlBlocker
+ BlockedUrlError = Class.new(StandardError)
+ HTTP_PROXY_ENV_VARS = %w[http_proxy https_proxy HTTP_PROXY HTTPS_PROXY].freeze
+
+ # Result stores the validation result:
+ # uri - The original URI requested
+ # hostname - The hostname that should be used to connect. For DNS
+ # rebinding protection, this will be the resolved IP address of
+ # the hostname.
+ # use_proxy -
+ # If true, this means that the proxy server specified in the
+ # http_proxy/https_proxy environment variables should be used.
+ #
+ # If false, this either means that no proxy server was specified
+ # or that the hostname in the URL is exempt via the no_proxy
+ # environment variable. This allows the caller to disable usage
+ # of a proxy since the IP address may be used to
+ # connect. Otherwise, Net::HTTP may erroneously compare the IP
+ # address against the no_proxy list.
+ Result = Struct.new(:uri, :hostname, :use_proxy)
+
+ class << self
+ # Validates the given url according to the constraints specified by arguments.
+ #
+ # ports - Raises error if the given URL port is not between given ports.
+ # allow_localhost - Raises error if URL resolves to a localhost IP address and argument is false.
+ # allow_local_network - Raises error if URL resolves to a link-local address and argument is false.
+ # extra_allowed_uris - Array of URI objects that are allowed in addition to hostname and IP constraints.
+ # This parameter is passed in this class when making the HTTP request.
+ # ascii_only - Raises error if URL has unicode characters and argument is true.
+ # enforce_user - Raises error if URL user doesn't start with alphanumeric characters and argument is true.
+ # enforce_sanitization - Raises error if URL includes any HTML/CSS/JS tags and argument is true.
+ # deny_all_requests_except_allowed - Raises error if URL is not in the allow list and argument is true.
+ # Can be Boolean or Proc. Defaults to instance app setting.
+ # dns_rebind_protection - Enforce DNS-rebinding attack protection.
+ # outbound_local_requests_allowlist - A list of trusted domains or IP addresses to which local requests are
+ # allowed when local requests for webhooks and integrations are disabled. This parameter is static and
+ # comes from the `outbound_local_requests_whitelist` application setting. # rubocop:disable Naming/InclusiveLanguage
+ #
+ # Returns a Result object.
+ # rubocop:disable Metrics/ParameterLists
+ def validate_url_with_proxy!(
+ url,
+ schemes:,
+ ports: [],
+ allow_localhost: false,
+ allow_local_network: true,
+ extra_allowed_uris: [],
+ ascii_only: false,
+ enforce_user: false,
+ enforce_sanitization: false,
+ deny_all_requests_except_allowed: false,
+ dns_rebind_protection: true,
+ outbound_local_requests_allowlist: []
+ )
+ # rubocop:enable Metrics/ParameterLists
+
+ return Result.new(nil, nil, true) if url.nil?
+
+ raise ArgumentError, 'The schemes is a required argument' if schemes.blank?
+
+ # Param url can be a string, URI or Addressable::URI
+ uri = parse_url(url)
+
+ validate_uri(
+ uri: uri,
+ schemes: schemes,
+ ports: ports,
+ enforce_sanitization: enforce_sanitization,
+ enforce_user: enforce_user,
+ ascii_only: ascii_only
+ )
+
+ begin
+ address_info = get_address_info(uri)
+ rescue SocketError
+ proxy_in_use = uri_under_proxy_setting?(uri, nil)
+
+ unless enforce_address_info_retrievable?(uri,
+ dns_rebind_protection,
+ deny_all_requests_except_allowed,
+ outbound_local_requests_allowlist)
+ return Result.new(uri, nil, proxy_in_use)
+ end
+
+ raise BlockedUrlError, 'Host cannot be resolved or invalid'
+ end
+
+ ip_address = ip_address(address_info)
+ proxy_in_use = uri_under_proxy_setting?(uri, ip_address)
+
+ # Ignore DNS rebind protection when a proxy is being used, as DNS
+ # rebinding is expected behavior.
+ dns_rebind_protection &&= !proxy_in_use
+ return Result.new(uri, nil, proxy_in_use) if domain_in_allow_list?(uri, outbound_local_requests_allowlist)
+
+ protected_uri_with_hostname = enforce_uri_hostname(ip_address, uri, dns_rebind_protection, proxy_in_use)
+
+ if ip_in_allow_list?(ip_address, outbound_local_requests_allowlist, port: get_port(uri))
+ return protected_uri_with_hostname
+ end
+
+ return protected_uri_with_hostname if allowed_uri?(uri, extra_allowed_uris)
+
+ validate_deny_all_requests_except_allowed!(deny_all_requests_except_allowed)
+
+ validate_local_request(
+ address_info: address_info,
+ allow_localhost: allow_localhost,
+ allow_local_network: allow_local_network
+ )
+
+ protected_uri_with_hostname
+ end
+
+ def blocked_url?(url, **kwargs)
+ validate!(url, **kwargs)
+
+ false
+ rescue BlockedUrlError
+ true
+ end
+
+ # For backwards compatibility, Returns an array with [<uri>, <original-hostname>].
+ # Issue for refactoring: https://gitlab.com/gitlab-org/gitlab/-/issues/410890
+ def validate!(...)
+ result = validate_url_with_proxy!(...)
+ [result.uri, result.hostname]
+ end
+
+ private
+
+ # Returns the given URI with IP address as hostname and the original hostname respectively
+ # in an Array.
+ #
+ # It checks whether the resolved IP address matches with the hostname. If not, it changes
+ # the hostname to the resolved IP address.
+ #
+ # The original hostname is used to validate the SSL, given in that scenario
+ # we'll be making the request to the IP address, instead of using the hostname.
+ def enforce_uri_hostname(ip_address, uri, dns_rebind_protection, proxy_in_use)
+ unless dns_rebind_protection && ip_address && ip_address != uri.hostname
+ return Result.new(uri, nil, proxy_in_use)
+ end
+
+ new_uri = uri.dup
+ new_uri.hostname = ip_address
+ Result.new(new_uri, uri.hostname, proxy_in_use)
+ end
+
+ def ip_address(address_info)
+ address_info.first&.ip_address
+ end
+
+ def validate_uri(uri:, schemes:, ports:, enforce_sanitization:, enforce_user:, ascii_only:)
+ validate_html_tags(uri) if enforce_sanitization
+
+ return if internal?(uri)
+
+ validate_scheme(uri.scheme, schemes)
+ validate_port(get_port(uri), ports) if ports.any?
+ validate_user(uri.user) if enforce_user
+ validate_hostname(uri.hostname)
+ validate_unicode_restriction(uri) if ascii_only
+ end
+
+ def uri_under_proxy_setting?(uri, ip_address)
+ return false unless http_proxy_env?
+ # `no_proxy|NO_PROXY` specifies addresses for which the proxy is not
+ # used. If it's empty, there are no exceptions and this URI
+ # will be under proxy settings.
+ return true if no_proxy_env.blank?
+
+ # `no_proxy|NO_PROXY` is being used. We must check whether it
+ # applies to this specific URI.
+ ::URI::Generic.use_proxy?(uri.hostname, ip_address, get_port(uri), no_proxy_env)
+ end
+
+ # Returns addrinfo object for the URI.
+ #
+ # @param uri [Addressable::URI]
+ #
+ # @raise [Gitlab::UrlBlocker::BlockedUrlError, ArgumentError] - BlockedUrlError raised if host is too long.
+ #
+ # @return [Array<Addrinfo>]
+ def get_address_info(uri)
+ Addrinfo.getaddrinfo(uri.hostname, get_port(uri), nil, :STREAM).map do |addr|
+ addr.ipv6_v4mapped? ? addr.ipv6_to_ipv4 : addr
+ end
+ rescue ArgumentError => e
+ # Addrinfo.getaddrinfo errors if the domain exceeds 1024 characters.
+ raise unless e.message.include?('hostname too long')
+
+ raise BlockedUrlError, "Host is too long (maximum is 1024 characters)"
+ end
+
+ def enforce_address_info_retrievable?(
+ uri, dns_rebind_protection, deny_all_requests_except_allowed,
+ outbound_local_requests_allowlist)
+ # Do not enforce if URI is in the allow list
+ return false if domain_in_allow_list?(uri, outbound_local_requests_allowlist)
+
+ # Enforce if the instance should block requests
+ return true if deny_all_requests_except_allowed?(deny_all_requests_except_allowed)
+
+ # Do not enforce if DNS rebinding protection is disabled
+ return false unless dns_rebind_protection
+
+ # Do not enforce if proxy is used
+ return false if http_proxy_env?
+
+ # In the test suite we use a lot of mocked urls that are either invalid or
+ # don't exist. In order to avoid modifying a ton of tests and factories
+ # we allow invalid urls unless the environment variable RSPEC_ALLOW_INVALID_URLS
+ # is not true
+ return false if Rails.env.test? && ENV['RSPEC_ALLOW_INVALID_URLS'] == 'true'
+
+ true
+ end
+
+ def validate_local_request(
+ address_info:,
+ allow_localhost:,
+ allow_local_network:)
+ return if allow_local_network && allow_localhost
+
+ unless allow_localhost
+ validate_localhost(address_info)
+ validate_loopback(address_info)
+ end
+
+ return if allow_local_network
+
+ validate_local_network(address_info)
+ validate_link_local(address_info)
+ validate_shared_address(address_info)
+ validate_limited_broadcast_address(address_info)
+ end
+
+ def validate_shared_address(addrs_info)
+ netmask = IPAddr.new('100.64.0.0/10')
+ return unless addrs_info.any? { |addr| netmask.include?(addr.ip_address) }
+
+ raise BlockedUrlError, "Requests to the shared address space are not allowed"
+ end
+
+ def validate_html_tags(uri)
+ uri_str = uri.to_s
+ sanitized_uri = ActionController::Base.helpers.sanitize(uri_str, tags: [])
+ return if sanitized_uri == uri_str
+
+ raise BlockedUrlError, 'HTML/CSS/JS tags are not allowed'
+ end
+
+ def parse_url(url)
+ Addressable::URI.parse(url).tap do |parsed_url|
+ raise Addressable::URI::InvalidURIError if multiline_blocked?(parsed_url)
+ end
+ rescue Addressable::URI::InvalidURIError, URI::InvalidURIError
+ raise BlockedUrlError, 'URI is invalid'
+ end
+
+ def multiline_blocked?(parsed_url)
+ url = parsed_url.to_s
+
+ return true if url =~ /\n|\r/
+ # Google Cloud Storage uses a multi-line, encoded Signature query string
+ return false if %w[http https].include?(parsed_url.scheme&.downcase)
+
+ CGI.unescape(url) =~ /\n|\r/
+ end
+
+ def validate_port(port, ports)
+ return if port.blank?
+ # Only ports under 1024 are restricted
+ return if port >= 1024
+ return if ports.include?(port)
+
+ raise BlockedUrlError, "Only allowed ports are #{ports.join(', ')}, and any over 1024"
+ end
+
+ def validate_scheme(scheme, schemes)
+ return unless scheme.blank? || (schemes.any? && schemes.exclude?(scheme))
+
+ raise BlockedUrlError, "Only allowed schemes are #{schemes.join(', ')}"
+ end
+
+ def validate_user(value)
+ return if value.blank?
+ return if value =~ /\A\p{Alnum}/
+
+ raise BlockedUrlError, "Username needs to start with an alphanumeric character"
+ end
+
+ def validate_hostname(value)
+ return if value.blank?
+ return if IPAddress.valid?(value)
+ return if value =~ /\A\p{Alnum}/
+
+ raise BlockedUrlError, "Hostname or IP address invalid"
+ end
+
+ def validate_unicode_restriction(uri)
+ return if uri.to_s.ascii_only?
+
+ raise BlockedUrlError, "URI must be ascii only #{uri.to_s.dump}"
+ end
+
+ def validate_localhost(addrs_info)
+ local_ips = ["::", "0.0.0.0"]
+ local_ips.concat(Socket.ip_address_list.map(&:ip_address))
+
+ return if (local_ips & addrs_info.map(&:ip_address)).empty?
+
+ raise BlockedUrlError, "Requests to localhost are not allowed"
+ end
+
+ def validate_loopback(addrs_info)
+ return unless addrs_info.any? { |addr| addr.ipv4_loopback? || addr.ipv6_loopback? }
+
+ raise BlockedUrlError, "Requests to loopback addresses are not allowed"
+ end
+
+ def validate_local_network(addrs_info)
+ return unless addrs_info.any? { |addr| addr.ipv4_private? || addr.ipv6_sitelocal? || addr.ipv6_unique_local? }
+
+ raise BlockedUrlError, "Requests to the local network are not allowed"
+ end
+
+ def validate_link_local(addrs_info)
+ netmask = IPAddr.new('169.254.0.0/16')
+ return unless addrs_info.any? { |addr| addr.ipv6_linklocal? || netmask.include?(addr.ip_address) }
+
+ raise BlockedUrlError, "Requests to the link local network are not allowed"
+ end
+
+ # Raises a BlockedUrlError if the instance is configured to deny all requests.
+ #
+ # This should only be called after allow list checks have been made.
+ def validate_deny_all_requests_except_allowed!(should_deny)
+ return unless deny_all_requests_except_allowed?(should_deny)
+
+ raise BlockedUrlError, "Requests to hosts and IP addresses not on the Allow List are denied"
+ end
+
+ # Raises a BlockedUrlError if any IP in `addrs_info` is the limited
+ # broadcast address.
+ # https://datatracker.ietf.org/doc/html/rfc919#section-7
+ def validate_limited_broadcast_address(addrs_info)
+ blocked_ips = ["255.255.255.255"]
+
+ return if (blocked_ips & addrs_info.map(&:ip_address)).empty?
+
+ raise BlockedUrlError, "Requests to the limited broadcast address are not allowed"
+ end
+
+ def allowed_uri?(uri, extra_allowed_uris)
+ internal?(uri) || check_uri(uri, extra_allowed_uris)
+ end
+
+ # Allow url from the GitLab instance itself but only for the configured hostname and ports
+ def internal?(uri)
+ check_uri(uri, Gitlab::HTTP_V2.configuration.allowed_internal_uris)
+ end
+
+ def check_uri(uri, allowlist)
+ allowlist.any? do |allowed_uri|
+ allowed_uri.scheme == uri.scheme &&
+ allowed_uri.hostname == uri.hostname &&
+ get_port(allowed_uri) == get_port(uri)
+ end
+ end
+
+ def deny_all_requests_except_allowed?(should_deny)
+ should_deny.is_a?(Proc) ? should_deny.call : should_deny
+ end
+
+ def domain_in_allow_list?(uri, outbound_local_requests_allowlist)
+ Gitlab::HTTP_V2::UrlAllowlist.domain_allowed?(
+ uri.normalized_host, outbound_local_requests_allowlist, port: get_port(uri))
+ end
+
+ def ip_in_allow_list?(ip_address, outbound_local_requests_allowlist, port: nil)
+ Gitlab::HTTP_V2::UrlAllowlist.ip_allowed?(ip_address, outbound_local_requests_allowlist, port: port)
+ end
+
+ def no_proxy_env
+ ENV['no_proxy'] || ENV['NO_PROXY']
+ end
+
+ def http_proxy_env?
+ HTTP_PROXY_ENV_VARS.any? { |name| ENV[name].present? }
+ end
+
+ def get_port(uri)
+ uri.port || uri.default_port
+ end
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/version.rb b/gems/gitlab-http/lib/gitlab/http_v2/version.rb
new file mode 100644
index 00000000000..8a9a17de112
--- /dev/null
+++ b/gems/gitlab-http/lib/gitlab/http_v2/version.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module HTTP_V2
+ module Version
+ VERSION = "0.1.0"
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/hostname_override_patch.rb b/gems/gitlab-http/lib/hostname_override_patch.rb
new file mode 100644
index 00000000000..c5799bf0682
--- /dev/null
+++ b/gems/gitlab-http/lib/hostname_override_patch.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+# This override allows passing `@hostname_override` to the SNI protocol,
+# which is used to lookup the correct SSL certificate in the
+# request handshake process.
+#
+# Given we've forced the HTTP request to be sent to the resolved
+# IP address in a few scenarios (e.g.: `Gitlab::HTTP_V2` through
+# `UrlBlocker.validate!`), we need to provide the _original_
+# hostname via SNI in order to have a clean connection setup.
+#
+# This is ultimately needed in order to avoid DNS rebinding attacks
+# through HTTP requests.
+
+require 'net/http'
+
+class OpenSSL::SSL::SSLContext
+ attr_accessor :hostname_override
+end
+
+class OpenSSL::SSL::SSLSocket
+ module HostnameOverride
+ # rubocop: disable Gitlab/ModuleWithInstanceVariables
+ def hostname=(hostname)
+ super(@context.hostname_override || hostname)
+ end
+
+ def post_connection_check(hostname)
+ super(@context.hostname_override || hostname)
+ end
+ # rubocop: enable Gitlab/ModuleWithInstanceVariables
+ end
+
+ prepend HostnameOverride
+end
+
+class Net::HTTP
+ attr_accessor :hostname_override
+
+ SSL_IVNAMES << :@hostname_override
+ SSL_ATTRIBUTES << :hostname_override
+
+ module HostnameOverride
+ def addr_port
+ return super unless hostname_override
+
+ addr = hostname_override
+ default_port = use_ssl? ? Net::HTTP.https_default_port : Net::HTTP.http_default_port
+ default_port == port ? addr : "#{addr}:#{port}"
+ end
+ end
+
+ prepend HostnameOverride
+end
diff --git a/gems/gitlab-http/lib/httparty/response_patch.rb b/gems/gitlab-http/lib/httparty/response_patch.rb
new file mode 100644
index 00000000000..3488ff034b4
--- /dev/null
+++ b/gems/gitlab-http/lib/httparty/response_patch.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'httparty'
+
+HTTParty::Response.class_eval do
+ # Original method: https://github.com/jnunemaker/httparty/blob/v0.20.0/lib/httparty/response.rb#L83-L86
+ # Related issue: https://github.com/jnunemaker/httparty/issues/568
+ #
+ # We need to override this method because `Concurrent::Promise` calls `nil?` on the response when
+ # calling the `value` method. And the `value` calls `nil?`.
+ # https://github.com/ruby-concurrency/concurrent-ruby/blob/v1.2.2/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb#L64
+ def nil?
+ response.nil? || response.body.blank?
+ end
+end
diff --git a/gems/gitlab-http/lib/net_http/protocol_patch.rb b/gems/gitlab-http/lib/net_http/protocol_patch.rb
new file mode 100644
index 00000000000..8231423e1a5
--- /dev/null
+++ b/gems/gitlab-http/lib/net_http/protocol_patch.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+# Monkey patch Net::HTTP to fix missing URL decoding for username and password in proxy settings
+#
+# See proposed upstream fix https://github.com/ruby/net-http/pull/5
+# See Ruby-lang issue https://bugs.ruby-lang.org/issues/17542
+# See issue on GitLab https://gitlab.com/gitlab-org/gitlab/-/issues/289836
+
+require 'net/http'
+
+# This file can be removed once Ruby 3.0 is no longer supported:
+# https://gitlab.com/gitlab-org/gitlab/-/issues/396223
+return if Gem::Version.new(Net::HTTP::VERSION) >= Gem::Version.new('0.2.0')
+
+module Net
+ class HTTP < Protocol
+ def proxy_user
+ if environment_variable_is_multiuser_safe? && @proxy_from_env
+ user = proxy_uri&.user
+ CGI.unescape(user) unless user.nil?
+ else
+ @proxy_user
+ end
+ end
+
+ def proxy_pass
+ if environment_variable_is_multiuser_safe? && @proxy_from_env
+ pass = proxy_uri&.password
+ CGI.unescape(pass) unless pass.nil?
+ else
+ @proxy_pass
+ end
+ end
+
+ def environment_variable_is_multiuser_safe?
+ ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE
+ end
+ end
+end
diff --git a/gems/gitlab-http/lib/net_http/response_patch.rb b/gems/gitlab-http/lib/net_http/response_patch.rb
new file mode 100644
index 00000000000..e5477a31318
--- /dev/null
+++ b/gems/gitlab-http/lib/net_http/response_patch.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Net
+ class HTTPResponse
+ # rubocop: disable Cop/LineBreakAfterGuardClauses
+ # rubocop: disable Cop/LineBreakAroundConditionalBlock
+ # rubocop: disable Layout/EmptyLineAfterGuardClause
+ # rubocop: disable Style/AndOr
+ # rubocop: disable Style/CharacterLiteral
+ # rubocop: disable Style/InfiniteLoop
+
+ # Original method:
+ # https://github.com/ruby/ruby/blob/v2_7_5/lib/net/http/response.rb#L54-L69
+ #
+ # Our changes:
+ # - Pass along the `start_time` to `Gitlab::HTTP_V2::BufferedIo`, so we can raise a timeout
+ # if reading the headers takes too long.
+ # - Limit the regexes to avoid ReDoS attacks.
+ def self.each_response_header(sock)
+ start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ key = value = nil
+ while true
+ line = if sock.is_a?(Gitlab::HTTP_V2::BufferedIo)
+ sock.readuntil("\n", true, start_time)
+ else
+ sock.readuntil("\n", true)
+ end
+ line = line.sub(/\s{0,10}\z/, '')
+ break if line.empty?
+ if line[0] == ?\s or line[0] == ?\t and value
+ # rubocop:disable Gitlab/NoCodeCoverageComment
+ # :nocov:
+ value << ' ' unless value.empty?
+ value << line.strip
+ # :nocov:
+ # rubocop:enable Gitlab/NoCodeCoverageComment
+ else
+ yield key, value if key
+ key, value = line.strip.split(/\s{0,10}:\s{0,10}/, 2)
+ raise Net::HTTPBadResponse, 'wrong header line format' if value.nil?
+ end
+ end
+ yield key, value if key
+ end
+ # rubocop: enable Cop/LineBreakAfterGuardClauses
+ # rubocop: enable Cop/LineBreakAroundConditionalBlock
+ # rubocop: enable Layout/EmptyLineAfterGuardClause
+ # rubocop: enable Style/AndOr
+ # rubocop: enable Style/CharacterLiteral
+ # rubocop: enable Style/InfiniteLoop
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/buffered_io_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/buffered_io_spec.rb
new file mode 100644
index 00000000000..74fe8b18199
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/buffered_io_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::HTTP_V2::BufferedIo do
+ describe '#readuntil' do
+ let(:mock_io) { StringIO.new('a') }
+ let(:start_time) { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
+
+ before do
+ stub_const('Gitlab::HTTP_V2::BufferedIo::HEADER_READ_TIMEOUT', 0.1)
+ end
+
+ subject(:readuntil) do
+ described_class.new(mock_io).readuntil('a', false, start_time)
+ end
+
+ it 'does not raise a timeout error' do
+ expect { readuntil }.not_to raise_error
+ end
+
+ context 'when the response contains infinitely long headers' do
+ before do
+ read_counter = 0
+
+ allow(mock_io).to receive(:read_nonblock) do |buffer_size, *_|
+ read_counter += 1
+ raise 'Test did not raise HeaderReadTimeout' if read_counter > 10
+
+ sleep 0.01
+ 'H' * buffer_size
+ end
+ end
+
+ it 'raises a timeout error' do
+ expect do
+ readuntil
+ end.to raise_error(Gitlab::HTTP_V2::HeaderReadTimeout,
+ /Request timed out after reading headers for 0\.[0-9]+ seconds/)
+ end
+
+ context 'when not passing start_time' do
+ subject(:readuntil) do
+ described_class.new(mock_io).readuntil('a', false)
+ end
+
+ it 'raises a timeout error' do
+ expect do
+ readuntil
+ end.to raise_error(Gitlab::HTTP_V2::HeaderReadTimeout,
+ /Request timed out after reading headers for 0\.[0-9]+ seconds/)
+ end
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/domain_allowlist_entry_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/domain_allowlist_entry_spec.rb
new file mode 100644
index 00000000000..0f9d5bc550d
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/domain_allowlist_entry_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::HTTP_V2::DomainAllowlistEntry do
+ let(:domain) { 'www.example.com' }
+
+ describe '#initialize' do
+ it 'initializes without port' do
+ domain_allowlist_entry = described_class.new(domain)
+
+ expect(domain_allowlist_entry.domain).to eq(domain)
+ expect(domain_allowlist_entry.port).to be(nil)
+ end
+
+ it 'initializes with port' do
+ port = 8080
+ domain_allowlist_entry = described_class.new(domain, port: port)
+
+ expect(domain_allowlist_entry.domain).to eq(domain)
+ expect(domain_allowlist_entry.port).to eq(port)
+ end
+ end
+
+ describe '#match?' do
+ it 'matches when domain and port are equal' do
+ port = 8080
+ domain_allowlist_entry = described_class.new(domain, port: port)
+
+ expect(domain_allowlist_entry).to be_match(domain, port)
+ end
+
+ it 'matches any port when port is nil' do
+ domain_allowlist_entry = described_class.new(domain)
+
+ expect(domain_allowlist_entry).to be_match(domain, 8080)
+ expect(domain_allowlist_entry).to be_match(domain, 9090)
+ end
+
+ it 'does not match when port is present but requested_port is nil' do
+ domain_allowlist_entry = described_class.new(domain, port: 8080)
+
+ expect(domain_allowlist_entry).not_to be_match(domain, nil)
+ end
+
+ it 'matches when port and requested_port are nil' do
+ domain_allowlist_entry = described_class.new(domain)
+
+ expect(domain_allowlist_entry).to be_match(domain)
+ end
+
+ it 'does not match if domain is not equal' do
+ domain_allowlist_entry = described_class.new(domain)
+
+ expect(domain_allowlist_entry).not_to be_match('www.gitlab.com', 8080)
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/ip_allowlist_entry_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/ip_allowlist_entry_spec.rb
new file mode 100644
index 00000000000..ad7d993ec62
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/ip_allowlist_entry_spec.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::HTTP_V2::IpAllowlistEntry, feature_category: :shared do
+ let(:ipv4) { IPAddr.new('192.168.1.1') }
+
+ describe '#initialize' do
+ it 'initializes without port' do
+ ip_allowlist_entry = described_class.new(ipv4)
+
+ expect(ip_allowlist_entry.ip).to eq(ipv4)
+ expect(ip_allowlist_entry.port).to be(nil)
+ end
+
+ it 'initializes with port' do
+ port = 8080
+ ip_allowlist_entry = described_class.new(ipv4, port: port)
+
+ expect(ip_allowlist_entry.ip).to eq(ipv4)
+ expect(ip_allowlist_entry.port).to eq(port)
+ end
+ end
+
+ describe '#match?' do
+ it 'matches with equivalent IP and port' do
+ port = 8080
+ ip_allowlist_entry = described_class.new(ipv4, port: port)
+
+ expect(ip_allowlist_entry).to be_match(ipv4.to_s, port)
+ end
+
+ it 'matches any port when port is nil' do
+ ip_allowlist_entry = described_class.new(ipv4)
+
+ expect(ip_allowlist_entry).to be_match(ipv4.to_s, 8080)
+ expect(ip_allowlist_entry).to be_match(ipv4.to_s, 9090)
+ end
+
+ it 'does not match when port is present but requested_port is nil' do
+ ip_allowlist_entry = described_class.new(ipv4, port: 8080)
+
+ expect(ip_allowlist_entry).not_to be_match(ipv4.to_s, nil)
+ end
+
+ it 'matches when port and requested_port are nil' do
+ ip_allowlist_entry = described_class.new(ipv4)
+
+ expect(ip_allowlist_entry).to be_match(ipv4.to_s)
+ end
+
+ it 'works with ipv6' do
+ ipv6 = IPAddr.new('fe80::c800:eff:fe74:8')
+ ip_allowlist_entry = described_class.new(ipv6)
+
+ expect(ip_allowlist_entry).to be_match(ipv6.to_s, 8080)
+ end
+
+ it 'matches ipv4 within IPv4 range' do
+ ipv4_range = IPAddr.new('127.0.0.0/28')
+ ip_allowlist_entry = described_class.new(ipv4_range)
+
+ expect(ip_allowlist_entry).to be_match(ipv4_range.to_range.last.to_s, 8080)
+ expect(ip_allowlist_entry).not_to be_match('127.0.1.1', 8080)
+ end
+
+ it 'matches IPv6 within IPv6 range' do
+ ipv6_range = IPAddr.new('::ffff:192.168.1.0/8')
+ ip_allowlist_entry = described_class.new(ipv6_range)
+
+ expect(ip_allowlist_entry).to be_match(ipv6_range.to_range.last.to_s, 8080)
+ expect(ip_allowlist_entry).not_to be_match('fd84:6d02:f6d8:f::f', 8080)
+ end
+
+ it 'matches IPv4 to IPv6 mapped addresses in allow list' do
+ ipv6_range = IPAddr.new('::ffff:192.168.1.1')
+ ip_allowlist_entry = described_class.new(ipv6_range)
+
+ expect(ip_allowlist_entry).to be_match(ipv4, 8080)
+ expect(ip_allowlist_entry).to be_match(ipv6_range.to_range.last.to_s, 8080)
+ expect(ip_allowlist_entry).not_to be_match('::ffff:192.168.1.0', 8080)
+ expect(ip_allowlist_entry).not_to be_match('::ffff:169.254.168.101', 8080)
+ end
+
+ it 'matches IPv4 to IPv6 mapped addresses in requested IP' do
+ ipv4_range = IPAddr.new('192.168.1.1/24')
+ ip_allowlist_entry = described_class.new(ipv4_range)
+
+ expect(ip_allowlist_entry).to be_match(ipv4, 8080)
+ expect(ip_allowlist_entry).to be_match('::ffff:192.168.1.0', 8080)
+ expect(ip_allowlist_entry).to be_match('::ffff:192.168.1.1', 8080)
+ expect(ip_allowlist_entry).not_to be_match('::ffff:169.254.170.100/8', 8080)
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/net_http_adapter_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/net_http_adapter_spec.rb
new file mode 100644
index 00000000000..22998803cc8
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/net_http_adapter_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'net/http'
+
+RSpec.describe Gitlab::HTTP_V2::NetHttpAdapter, feature_category: :api do
+ describe '#connect' do
+ let(:url) { 'https://example.org' }
+ let(:net_http_adapter) { described_class.new(url) }
+
+ subject(:connect) { net_http_adapter.send(:connect) }
+
+ before do
+ allow(TCPSocket).to receive(:open).and_return(Socket.new(:INET, :STREAM))
+ end
+
+ it 'uses a Gitlab::HTTP_V2::BufferedIo instance as @socket' do
+ connect
+
+ expect(net_http_adapter.instance_variable_get(:@socket)).to be_a(Gitlab::HTTP_V2::BufferedIo)
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb
new file mode 100644
index 00000000000..b82646fb365
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/net_http_patch_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'net/http'
+
+RSpec.describe 'Net::HTTP patch proxy user and password encoding' do
+ let(:net_http) { Net::HTTP.new('hostname.example') }
+
+ before do
+ # This file can be removed once Ruby 3.0 is no longer supported:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/396223
+ skip if Gem::Version.new(Net::HTTP::VERSION) >= Gem::Version.new('0.2.0')
+ end
+
+ describe '#proxy_user' do
+ subject { net_http.proxy_user }
+
+ it { is_expected.to eq(nil) }
+
+ context 'with http_proxy env' do
+ let(:http_proxy) { 'http://proxy.example:8000' }
+
+ before do
+ stub_env('http_proxy', http_proxy)
+ end
+
+ it { is_expected.to eq(nil) }
+
+ context 'and user:password authentication' do
+ let(:http_proxy) { 'http://Y%5CX:R%25S%5D%20%3FX@proxy.example:8000' }
+
+ context 'when on multiuser safe platform' do
+ # linux, freebsd, darwin are considered multi user safe platforms
+ # See https://github.com/ruby/net-http/blob/v0.1.1/lib/net/http.rb#L1174-L1178
+
+ before do
+ allow(net_http).to receive(:environment_variable_is_multiuser_safe?).and_return(true)
+ end
+
+ it { is_expected.to eq 'Y\\X' }
+ end
+
+ context 'when not on multiuser safe platform' do
+ before do
+ allow(net_http).to receive(:environment_variable_is_multiuser_safe?).and_return(false)
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+ end
+
+ describe '#proxy_pass' do
+ subject { net_http.proxy_pass }
+
+ it { is_expected.to eq(nil) }
+
+ context 'with http_proxy env' do
+ let(:http_proxy) { 'http://proxy.example:8000' }
+
+ before do
+ stub_env('http_proxy', http_proxy)
+ end
+
+ it { is_expected.to eq(nil) }
+
+ context 'and user:password authentication' do
+ let(:http_proxy) { 'http://Y%5CX:R%25S%5D%20%3FX@proxy.example:8000' }
+
+ context 'when on multiuser safe platform' do
+ # linux, freebsd, darwin are considered multi user safe platforms
+ # See https://github.com/ruby/net-http/blob/v0.1.1/lib/net/http.rb#L1174-L1178
+
+ before do
+ allow(net_http).to receive(:environment_variable_is_multiuser_safe?).and_return(true)
+ end
+
+ it { is_expected.to eq 'R%S] ?X' }
+ end
+
+ context 'when not on multiuser safe platform' do
+ before do
+ allow(net_http).to receive(:environment_variable_is_multiuser_safe?).and_return(false)
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/net_http_response_patch_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/net_http_response_patch_spec.rb
new file mode 100644
index 00000000000..f8d0f0a57fc
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/net_http_response_patch_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Net::HTTPResponse patch header read timeout', feature_category: :shared do
+ describe '.each_response_header' do
+ let(:server_response) do
+ <<~HTTP
+ Content-Type: text/html
+ Header-Two: foo
+
+ Hello World
+ HTTP
+ end
+
+ before do
+ stub_const('Gitlab::HTTP_V2::BufferedIo::HEADER_READ_TIMEOUT', 0.1)
+ end
+
+ subject(:each_response_header) { Net::HTTPResponse.each_response_header(socket) { |k, v| } } # rubocop:disable Lint/EmptyBlock
+
+ context 'with Net::BufferedIO' do
+ let(:socket) { Net::BufferedIO.new(StringIO.new(server_response)) }
+
+ it 'does not forward start time to the socket' do
+ allow(socket).to receive(:readuntil).and_call_original
+ expect(socket).to receive(:readuntil).with("\n", true)
+
+ each_response_header
+ end
+
+ context 'when the response contains many consecutive spaces' do
+ it 'has no regex backtracking issues' do
+ expect(socket).to receive(:readuntil).and_return(
+ "a: #{' ' * 100_000} b",
+ ''
+ )
+
+ Timeout.timeout(1) do
+ each_response_header
+ end
+ end
+ end
+ end
+
+ context 'with Gitlab:HTTP_V2:::BufferedIo' do
+ let(:mock_io) { StringIO.new(server_response) }
+ let(:socket) { Gitlab::HTTP_V2::BufferedIo.new(mock_io) }
+
+ it 'forwards start time to the socket' do
+ allow(socket).to receive(:readuntil).and_call_original
+ expect(socket).to receive(:readuntil).with("\n", true, kind_of(Numeric))
+
+ each_response_header
+ end
+
+ context 'when the response contains an infinite number of headers' do
+ before do
+ read_counter = 0
+
+ allow(mock_io).to receive(:read_nonblock) do
+ read_counter += 1
+ raise 'Test did not raise HeaderReadTimeout' if read_counter > 10
+
+ sleep 0.01
+ +"Yet-Another-Header: foo\n"
+ end
+ end
+
+ it 'raises a timeout error' do
+ expect { each_response_header }.to raise_error(Gitlab::HTTP_V2::HeaderReadTimeout,
+ /Request timed out after reading headers for 0\.[0-9]+ seconds/)
+ end
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/new_connection_adapter_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/new_connection_adapter_spec.rb
new file mode 100644
index 00000000000..852bafc5557
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/new_connection_adapter_spec.rb
@@ -0,0 +1,157 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::HTTP_V2::NewConnectionAdapter, feature_category: :shared do
+ let(:uri) { URI('https://example.org') }
+ let(:options) { {} }
+
+ subject(:connection) { described_class.new(uri, options).connection }
+
+ describe '#connection' do
+ before do
+ stub_all_dns('https://example.org', ip_address: '93.184.216.34')
+ end
+
+ context 'when local requests are allowed' do
+ let(:options) { { allow_local_requests: true } }
+
+ it 'sets up the connection' do
+ expect(connection).to be_a(Gitlab::HTTP_V2::NetHttpAdapter)
+ expect(connection.address).to eq('93.184.216.34')
+ expect(connection.hostname_override).to eq('example.org')
+ expect(connection.addr_port).to eq('example.org')
+ expect(connection.port).to eq(443)
+ end
+ end
+
+ context 'when local requests are not allowed' do
+ let(:options) { { allow_local_requests: false } }
+
+ it 'sets up the connection' do
+ expect(connection).to be_a(Gitlab::HTTP_V2::NetHttpAdapter)
+ expect(connection.address).to eq('93.184.216.34')
+ expect(connection.hostname_override).to eq('example.org')
+ expect(connection.addr_port).to eq('example.org')
+ expect(connection.port).to eq(443)
+ end
+
+ context 'when it is a request to local network' do
+ let(:uri) { URI('http://172.16.0.0/12') }
+
+ it 'raises error' do
+ expect { subject }.to raise_error(
+ Gitlab::HTTP_V2::BlockedUrlError,
+ "URL is blocked: Requests to the local network are not allowed"
+ )
+ end
+
+ context 'when local request allowed' do
+ let(:options) { { allow_local_requests: true } }
+
+ it 'sets up the connection' do
+ expect(connection).to be_a(Gitlab::HTTP_V2::NetHttpAdapter)
+ expect(connection.address).to eq('172.16.0.0')
+ expect(connection.hostname_override).to be(nil)
+ expect(connection.addr_port).to eq('172.16.0.0')
+ expect(connection.port).to eq(80)
+ end
+ end
+ end
+
+ context 'when it is a request to local address' do
+ let(:uri) { URI('http://127.0.0.1') }
+
+ it 'raises error' do
+ expect { subject }.to raise_error(
+ Gitlab::HTTP_V2::BlockedUrlError,
+ "URL is blocked: Requests to localhost are not allowed"
+ )
+ end
+
+ context 'when local request allowed' do
+ let(:options) { { allow_local_requests: true } }
+
+ it 'sets up the connection' do
+ expect(connection).to be_a(Gitlab::HTTP_V2::NetHttpAdapter)
+ expect(connection.address).to eq('127.0.0.1')
+ expect(connection.hostname_override).to be(nil)
+ expect(connection.addr_port).to eq('127.0.0.1')
+ expect(connection.port).to eq(80)
+ end
+ end
+ end
+
+ context 'when port different from URL scheme is used' do
+ let(:uri) { URI('https://example.org:8080') }
+
+ it 'sets up the addr_port accordingly' do
+ expect(connection).to be_a(Gitlab::HTTP_V2::NetHttpAdapter)
+ expect(connection.address).to eq('93.184.216.34')
+ expect(connection.hostname_override).to eq('example.org')
+ expect(connection.addr_port).to eq('example.org:8080')
+ expect(connection.port).to eq(8080)
+ end
+ end
+ end
+
+ context 'when DNS rebinding protection is disabled' do
+ let(:options) { { dns_rebinding_protection_enabled: false } }
+
+ it 'sets up the connection' do
+ expect(connection).to be_a(Gitlab::HTTP_V2::NetHttpAdapter)
+ expect(connection.address).to eq('example.org')
+ expect(connection.hostname_override).to eq(nil)
+ expect(connection.addr_port).to eq('example.org')
+ expect(connection.port).to eq(443)
+ end
+ end
+
+ context 'when proxy is enabled' do
+ before do
+ stub_env('http_proxy', 'http://proxy.example.com')
+ end
+
+ it 'proxy stays configured' do
+ expect(connection.proxy?).to be true
+ expect(connection.proxy_from_env?).to be true
+ expect(connection.proxy_address).to eq('proxy.example.com')
+ end
+
+ context 'when no_proxy matches the request' do
+ before do
+ stub_env('no_proxy', 'example.org')
+ end
+
+ it 'proxy is disabled' do
+ expect(connection.proxy?).to be false
+ expect(connection.proxy_from_env?).to be false
+ expect(connection.proxy_address).to be nil
+ end
+ end
+
+ context 'when no_proxy does not match the request' do
+ before do
+ stub_env('no_proxy', 'example.com')
+ end
+
+ it 'proxy stays configured' do
+ expect(connection.proxy?).to be true
+ expect(connection.proxy_from_env?).to be true
+ expect(connection.proxy_address).to eq('proxy.example.com')
+ end
+ end
+ end
+
+ context 'when URL scheme is not HTTP/HTTPS' do
+ let(:uri) { URI('ssh://example.org') }
+
+ it 'raises error' do
+ expect { subject }.to raise_error(
+ Gitlab::HTTP_V2::BlockedUrlError,
+ "URL is blocked: Only allowed schemes are http, https"
+ )
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/url_allowlist_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/url_allowlist_spec.rb
new file mode 100644
index 00000000000..bac69a2c38c
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/url_allowlist_spec.rb
@@ -0,0 +1,153 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::HTTP_V2::UrlAllowlist do
+ let(:allowlist) { [] }
+
+ describe '#domain_allowed?' do
+ let(:allowlist) { %w[www.example.com example.com] }
+
+ it 'returns true if domains present in allowlist' do
+ not_allowed = %w[subdomain.example.com example.org]
+
+ aggregate_failures do
+ allowlist.each do |domain|
+ expect(described_class).to be_domain_allowed(domain, allowlist)
+ end
+
+ not_allowed.each do |domain|
+ expect(described_class).not_to be_domain_allowed(domain, allowlist)
+ end
+ end
+ end
+
+ it 'returns false when domain is blank' do
+ expect(described_class).not_to be_domain_allowed(nil, allowlist)
+ end
+
+ context 'with ports' do
+ let(:allowlist) { ['example.io:3000'] }
+
+ it 'returns true if domain and ports present in allowlist' do
+ parsed_allowlist = [['example.io', 3000]]
+ not_allowed = [
+ 'example.io',
+ ['example.io', 3001]
+ ]
+
+ aggregate_failures do
+ parsed_allowlist.each do |domain, port|
+ expect(described_class).to be_domain_allowed(domain, allowlist, port: port)
+ end
+
+ not_allowed.each do |domain, port|
+ expect(described_class).not_to be_domain_allowed(domain, allowlist, port: port)
+ end
+ end
+ end
+ end
+ end
+
+ describe '#ip_allowed?' do
+ let(:allowlist) do
+ [
+ '0.0.0.0',
+ '127.0.0.1',
+ '192.168.1.1',
+ '0:0:0:0:0:ffff:192.168.1.2',
+ '::ffff:c0a8:102',
+ 'fc00:bf8b:e62c:abcd:abcd:aaaa:aaaa:aaaa',
+ '0:0:0:0:0:ffff:169.254.169.254',
+ '::ffff:a9fe:a9fe',
+ '::ffff:a9fe:a864',
+ 'fe80::c800:eff:fe74:8'
+ ]
+ end
+
+ it 'returns true if ips present in allowlist' do
+ aggregate_failures do
+ allowlist.each do |ip_address|
+ expect(described_class).to be_ip_allowed(ip_address, allowlist)
+ end
+
+ %w[172.16.2.2 127.0.0.2 fe80::c800:eff:fe74:9].each do |ip_address|
+ expect(described_class).not_to be_ip_allowed(ip_address, allowlist)
+ end
+ end
+ end
+
+ it 'returns false when ip is blank' do
+ expect(described_class).not_to be_ip_allowed(nil, allowlist)
+ end
+
+ context 'with ip ranges in allowlist' do
+ let(:ipv4_range) { '127.0.0.0/28' }
+ let(:ipv6_range) { 'fd84:6d02:f6d8:c89e::/124' }
+
+ let(:allowlist) do
+ [
+ ipv4_range,
+ ipv6_range
+ ]
+ end
+
+ it 'does not allowlist ipv4 range when not in allowlist' do
+ IPAddr.new(ipv4_range).to_range.to_a.each do |ip|
+ expect(described_class).not_to be_ip_allowed(ip.to_s, [])
+ end
+ end
+
+ it 'allowlists all ipv4s in the range when in allowlist' do
+ IPAddr.new(ipv4_range).to_range.to_a.each do |ip|
+ expect(described_class).to be_ip_allowed(ip.to_s, allowlist)
+ end
+ end
+
+ it 'does not allowlist ipv6 range when not in allowlist' do
+ IPAddr.new(ipv6_range).to_range.to_a.each do |ip|
+ expect(described_class).not_to be_ip_allowed(ip.to_s, [])
+ end
+ end
+
+ it 'allowlists all ipv6s in the range when in allowlist' do
+ IPAddr.new(ipv6_range).to_range.to_a.each do |ip|
+ expect(described_class).to be_ip_allowed(ip.to_s, allowlist)
+ end
+ end
+
+ it 'does not allowlist IPs outside the range' do
+ expect(described_class).not_to be_ip_allowed("fd84:6d02:f6d8:c89e:0:0:1:f", allowlist)
+
+ expect(described_class).not_to be_ip_allowed("127.0.1.15", allowlist)
+ end
+ end
+
+ context 'with ports' do
+ let(:allowlist) { %w[127.0.0.9:3000 [2001:db8:85a3:8d3:1319:8a2e:370:7348]:443] }
+
+ it 'returns true if ip and ports present in allowlist' do
+ parsed_allowlist = [
+ ['127.0.0.9', 3000],
+ ['[2001:db8:85a3:8d3:1319:8a2e:370:7348]', 443]
+ ]
+ not_allowed = [
+ '127.0.0.9',
+ ['127.0.0.9', 3001],
+ '[2001:db8:85a3:8d3:1319:8a2e:370:7348]',
+ ['[2001:db8:85a3:8d3:1319:8a2e:370:7348]', 3001]
+ ]
+
+ aggregate_failures do
+ parsed_allowlist.each do |ip, port|
+ expect(described_class).to be_ip_allowed(ip, allowlist, port: port)
+ end
+
+ not_allowed.each do |ip, port|
+ expect(described_class).not_to be_ip_allowed(ip, allowlist, port: port)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2/url_blocker_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2/url_blocker_spec.rb
new file mode 100644
index 00000000000..e47098e6f74
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2/url_blocker_spec.rb
@@ -0,0 +1,988 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::HTTP_V2::UrlBlocker, :stub_invalid_dns_only, feature_category: :shared do
+ let(:schemes) { %w[http https] }
+
+ # This test ensures backward compatibliity for the validate! method.
+ # We shoud refactor all callers of validate! to handle a Result object:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/410890
+ describe '#validate!' do
+ let(:options) { { schemes: schemes } }
+
+ subject { described_class.validate!(import_url, **options) }
+
+ shared_examples 'validates URI and hostname' do
+ it 'runs the url validations' do
+ uri, hostname = subject
+
+ expect(uri).to eq(Addressable::URI.parse(expected_uri))
+ expect(hostname).to eq(expected_hostname)
+ end
+ end
+
+ context 'when the URL hostname is a domain' do
+ context 'when domain can be resolved' do
+ let(:import_url) { 'https://example.org' }
+
+ before do
+ stub_dns(import_url, ip_address: '93.184.216.34')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'https://93.184.216.34' }
+ let(:expected_hostname) { 'example.org' }
+ let(:expected_use_proxy) { false }
+ end
+ end
+ end
+ end
+
+ describe '#validate_url_with_proxy!' do
+ let(:options) { { schemes: schemes } }
+
+ subject { described_class.validate_url_with_proxy!(import_url, **options) }
+
+ shared_examples 'validates URI and hostname' do
+ it 'runs the url validations' do
+ expect(subject.uri).to eq(Addressable::URI.parse(expected_uri))
+ expect(subject.hostname).to eq(expected_hostname)
+ expect(subject.use_proxy).to eq(expected_use_proxy)
+ end
+ end
+
+ shared_context 'when instance configured to deny all requests' do
+ let(:options) { super().merge(deny_all_requests_except_allowed: true) }
+ end
+
+ shared_examples 'a URI denied by `deny_all_requests_except_allowed`' do
+ context 'when instance setting is enabled' do
+ include_context 'when instance configured to deny all requests'
+
+ it 'blocks the request' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+
+ context 'when instance setting is not enabled' do
+ it 'does not block the request' do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context 'when passed as an argument' do
+ let(:options) { super().merge(deny_all_requests_except_allowed: arg_value) }
+
+ context 'when argument is a proc that evaluates to true' do
+ let(:arg_value) { proc { true } }
+
+ it 'blocks the request' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+
+ context 'when argument is a proc that evaluates to false' do
+ let(:arg_value) { proc { false } }
+
+ it 'does not block the request' do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context 'when argument is true' do
+ let(:arg_value) { true }
+
+ it 'blocks the request' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+
+ context 'when argument is false' do
+ let(:arg_value) { false }
+
+ it 'does not block the request' do
+ expect { subject }.not_to raise_error
+ end
+ end
+ end
+ end
+
+ shared_examples 'a URI exempt from `deny_all_requests_except_allowed`' do
+ include_context 'when instance configured to deny all requests'
+
+ it 'does not block the request' do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context 'when URI is nil' do
+ let(:import_url) { nil }
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { nil }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { true }
+ end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
+ end
+
+ context 'when URI is internal' do
+ let(:import_url) { 'http://localhost' }
+
+ before do
+ stub_dns(import_url, ip_address: '127.0.0.1')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://127.0.0.1' }
+ let(:expected_hostname) { 'localhost' }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
+ end
+
+ context 'when URI is for a local object storage' do
+ let(:import_url) { "#{host}/external-diffs/merge_request_diffs/mr-1/diff-1" }
+
+ context 'when extra_allowed_uris is passed' do
+ let(:options) { super().merge(extra_allowed_uris: [URI(host)]) }
+
+ context 'with a local domain name' do
+ let(:host) { 'http://review-minio-svc.svc:9000' }
+
+ before do
+ stub_dns(host, ip_address: '127.0.0.1')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://127.0.0.1:9000/external-diffs/merge_request_diffs/mr-1/diff-1' }
+ let(:expected_hostname) { 'review-minio-svc.svc' }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
+ end
+
+ context 'with an IP address' do
+ let(:host) { 'http://127.0.0.1:9000' }
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://127.0.0.1:9000/external-diffs/merge_request_diffs/mr-1/diff-1' }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
+ end
+
+ context 'with an LFS object storage' do
+ let(:host) { 'http://127.0.0.1:9000' }
+
+ context 'when extra_allowed_uris is not passed' do
+ let(:options) { super().merge(extra_allowed_uris: []) }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+ end
+ end
+
+ context 'when extra_allowed_uris is not passed' do
+ context 'with a local domain name' do
+ let(:host) { 'http://review-minio-svc.svc:9000' }
+
+ before do
+ stub_dns(host, ip_address: '127.0.0.1')
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+
+ context 'with an IP address' do
+ let(:host) { 'http://127.0.0.1:9000' }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+ end
+ end
+
+ context 'when the URL hostname is a domain' do
+ context 'when domain can be resolved' do
+ let(:import_url) { 'https://example.org' }
+
+ before do
+ stub_dns(import_url, ip_address: '93.184.216.34')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'https://93.184.216.34' }
+ let(:expected_hostname) { 'example.org' }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
+ end
+
+ context 'when domain cannot be resolved' do
+ let(:import_url) { 'http://foobar.x' }
+
+ before do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+
+ context 'with HTTP_PROXY' do
+ let(:import_url) { 'http://foobar.x' }
+
+ before do
+ stub_env('http_proxy', 'http://proxy.example.com')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { true }
+ end
+
+ context 'with no_proxy' do
+ before do
+ stub_env('no_proxy', 'foobar.x')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { false }
+ end
+ end
+ end
+ end
+
+ context 'when domain is too long' do
+ let(:import_url) { "https://example#{'a' * 1024}.com" }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+ end
+
+ context 'when the URL hostname is an IP address' do
+ let(:import_url) { 'https://93.184.216.34' }
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
+
+ context 'when the address is invalid' do
+ let(:import_url) { 'http://1.1.1.1.1' }
+
+ it 'raises an error' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect { subject }.to raise_error(described_class::BlockedUrlError)
+ end
+ end
+ end
+
+ context 'when DNS rebinding protection with IP allowed' do
+ let(:import_url) { 'http://a.192.168.0.120.3times.127.0.0.1.1time.repeat.rebind.network:9121/scrape?target=unix:///var/opt/gitlab/redis/redis.socket&amp;check-keys=*' }
+
+ before do
+ stub_dns(import_url, ip_address: '192.168.0.120')
+
+ allow(Gitlab::HTTP_V2::UrlAllowlist).to receive(:ip_allowed?).and_return(true)
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://192.168.0.120:9121/scrape?target=unix:///var/opt/gitlab/redis/redis.socket&amp;check-keys=*' }
+ let(:expected_hostname) { 'a.192.168.0.120.3times.127.0.0.1.1time.repeat.rebind.network' }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
+
+ context 'with HTTP_PROXY' do
+ before do
+ stub_env('http_proxy', 'http://proxy.example.com')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { true }
+ end
+
+ context 'when domain is in no_proxy env' do
+ before do
+ stub_env('no_proxy', 'a.192.168.0.120.3times.127.0.0.1.1time.repeat.rebind.network')
+ end
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { 'http://192.168.0.120:9121/scrape?target=unix:///var/opt/gitlab/redis/redis.socket&amp;check-keys=*' }
+ let(:expected_hostname) { 'a.192.168.0.120.3times.127.0.0.1.1time.repeat.rebind.network' }
+ let(:expected_use_proxy) { false }
+ end
+ end
+ end
+ end
+
+ context 'with disabled DNS rebinding protection' do
+ let(:options) { { dns_rebind_protection: false, schemes: schemes } }
+
+ context 'when URI is internal' do
+ let(:import_url) { 'http://localhost' }
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI exempt from `deny_all_requests_except_allowed`'
+ end
+
+ context 'when the URL hostname is a domain' do
+ let(:import_url) { 'https://example.org' }
+
+ before do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+ end
+
+ context 'when domain can be resolved' do
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
+ end
+
+ context 'when domain cannot be resolved' do
+ let(:import_url) { 'http://foobar.x' }
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
+ end
+ end
+
+ context 'when the URL hostname is an IP address' do
+ let(:import_url) { 'https://93.184.216.34' }
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
+
+ context 'when it is invalid' do
+ let(:import_url) { 'http://1.1.1.1.1' }
+
+ it_behaves_like 'validates URI and hostname' do
+ let(:expected_uri) { import_url }
+ let(:expected_hostname) { nil }
+ let(:expected_use_proxy) { false }
+ end
+
+ it_behaves_like 'a URI denied by `deny_all_requests_except_allowed`'
+ end
+ end
+ end
+ end
+
+ describe '#blocked_url?' do
+ let(:ports) { [80, 443] }
+
+ it 'allows imports from configured web host and port' do
+ import_url = "http://localhost:80/t.git"
+ expect(described_class.blocked_url?(import_url, schemes: schemes)).to be false
+ end
+
+ it 'allows mirroring from configured SSH host and port' do
+ import_url = "ssh://localhost:22/t.git"
+ expect(described_class.blocked_url?(import_url, schemes: schemes)).to be false
+ end
+
+ it 'returns true for bad localhost hostname' do
+ expect(described_class.blocked_url?('https://localhost:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for bad port' do
+ expect(described_class.blocked_url?('https://gitlab.com:25/foo/foo.git', ports: ports, schemes: schemes))
+ .to be true
+ end
+
+ it 'returns true for bad scheme' do
+ expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git', schemes: ['https'])).to be false
+ expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git', schemes: ['http'])).to be true
+ end
+
+ it 'returns true for bad protocol on configured web/SSH host and ports' do
+ web_url = "javascript://localhost:80/t.git%0aalert(1)"
+ expect(described_class.blocked_url?(web_url, schemes: schemes)).to be true
+
+ ssh_url = "javascript://localhost:22/t.git%0aalert(1)"
+ expect(described_class.blocked_url?(ssh_url, schemes: schemes)).to be true
+ end
+
+ it 'returns true for localhost IPs' do
+ expect(described_class.blocked_url?('https://[0:0:0:0:0:0:0:0]/foo/foo.git', schemes: schemes)).to be true
+ expect(described_class.blocked_url?('https://0.0.0.0/foo/foo.git', schemes: schemes)).to be true
+ expect(described_class.blocked_url?('https://[::]/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for loopback IP' do
+ expect(described_class.blocked_url?('https://127.0.0.2/foo/foo.git', schemes: schemes)).to be true
+ expect(described_class.blocked_url?('https://127.0.0.1/foo/foo.git', schemes: schemes)).to be true
+ expect(described_class.blocked_url?('https://[::1]/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for alternative version of 127.0.0.1 (0177.1)' do
+ expect(described_class.blocked_url?('https://0177.1:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for alternative version of 127.0.0.1 (017700000001)' do
+ expect(described_class.blocked_url?('https://017700000001:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for alternative version of 127.0.0.1 (0x7f.1)' do
+ expect(described_class.blocked_url?('https://0x7f.1:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for alternative version of 127.0.0.1 (0x7f.0.0.1)' do
+ expect(described_class.blocked_url?('https://0x7f.0.0.1:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for alternative version of 127.0.0.1 (0x7f000001)' do
+ expect(described_class.blocked_url?('https://0x7f000001:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for alternative version of 127.0.0.1 (2130706433)' do
+ expect(described_class.blocked_url?('https://2130706433:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for alternative version of 127.0.0.1 (127.000.000.001)' do
+ expect(described_class.blocked_url?('https://127.000.000.001:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for alternative version of 127.0.0.1 (127.0.1)' do
+ expect(described_class.blocked_url?('https://127.0.1:65535/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ context 'with ipv6 mapped address' do
+ it 'returns true for localhost IPs' do
+ expect(described_class.blocked_url?('https://[0:0:0:0:0:ffff:0.0.0.0]/foo/foo.git', schemes: schemes))
+ .to be true
+ expect(described_class.blocked_url?('https://[::ffff:0.0.0.0]/foo/foo.git', schemes: schemes)).to be true
+ expect(described_class.blocked_url?('https://[::ffff:0:0]/foo/foo.git', schemes: schemes)).to be true
+ end
+
+ it 'returns true for loopback IPs' do
+ expect(described_class.blocked_url?('https://[0:0:0:0:0:ffff:127.0.0.1]/foo/foo.git', schemes: schemes))
+ .to be true
+ expect(described_class.blocked_url?('https://[::ffff:127.0.0.1]/foo/foo.git', schemes: schemes)).to be true
+ expect(described_class.blocked_url?('https://[::ffff:7f00:1]/foo/foo.git', schemes: schemes)).to be true
+ expect(described_class.blocked_url?('https://[0:0:0:0:0:ffff:127.0.0.2]/foo/foo.git', schemes: schemes))
+ .to be true
+ expect(described_class.blocked_url?('https://[::ffff:127.0.0.2]/foo/foo.git', schemes: schemes)).to be true
+ expect(described_class.blocked_url?('https://[::ffff:7f00:2]/foo/foo.git', schemes: schemes)).to be true
+ end
+ end
+
+ it 'returns true for a non-alphanumeric hostname' do
+ aggregate_failures do
+ expect(described_class).to be_blocked_url('ssh://-oProxyCommand=whoami/a', schemes: ['ssh'])
+
+ # The leading character here is a Unicode "soft hyphen"
+ expect(described_class).to be_blocked_url('ssh://­oProxyCommand=whoami/a', schemes: ['ssh'])
+
+ # Unicode alphanumerics are allowed
+ expect(described_class).not_to be_blocked_url('ssh://ÄŸitlab.com/a', schemes: ['ssh'])
+ end
+ end
+
+ it 'returns true for invalid URL' do
+ expect(described_class.blocked_url?('http://:8080', schemes: schemes)).to be true
+ end
+
+ it 'returns false for legitimate URL' do
+ expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git', schemes: schemes)).to be false
+ end
+
+ describe 'allow_local_network' do
+ let(:shared_address_space_ips) { ['100.64.0.0', '100.64.127.127', '100.64.255.255'] }
+
+ let(:local_ips) do
+ [
+ '192.168.1.2',
+ '[0:0:0:0:0:ffff:192.168.1.2]',
+ '[::ffff:c0a8:102]',
+ '10.0.0.2',
+ '[0:0:0:0:0:ffff:10.0.0.2]',
+ '[::ffff:a00:2]',
+ '172.16.0.2',
+ '[0:0:0:0:0:ffff:172.16.0.2]',
+ '[::ffff:ac10:20]',
+ '[feef::1]',
+ '[fee2::]',
+ '[fc00:bf8b:e62c:abcd:abcd:aaaa:aaaa:aaaa]',
+ *shared_address_space_ips
+ ]
+ end
+
+ let(:limited_broadcast_address_variants) do
+ [
+ '255.255.255.255', # "normal" dotted decimal
+ '0377.0377.0377.0377', # Octal
+ '0377.00000000377.00377.0000377', # Still octal
+ '0xff.0xff.0xff.0xff', # hex
+ '0xffffffff', # still hex
+ '0xBaaaaaaaaaaaaaaaaffffffff', # padded hex
+ '255.255.255.255:65535', # with a port
+ '4294967295', # as an integer / dword
+ '[::ffff:ffff:ffff]', # short IPv6
+ '[0000:0000:0000:0000:0000:ffff:ffff:ffff]' # long IPv6
+ ]
+ end
+
+ let(:fake_domain) { 'www.fakedomain.fake' }
+
+ shared_examples 'allows local requests' do
+ it 'does not block urls from private networks' do
+ local_ips.each do |ip|
+ stub_domain_resolv(fake_domain, ip) do
+ expect(described_class).not_to be_blocked_url("http://#{fake_domain}", **url_blocker_attributes)
+ end
+
+ expect(described_class).not_to be_blocked_url("http://#{ip}", **url_blocker_attributes)
+ end
+ end
+
+ it 'allows localhost endpoints' do
+ expect(described_class).not_to be_blocked_url('http://0.0.0.0', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url('http://localhost', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url('http://127.0.0.1', **url_blocker_attributes)
+ end
+
+ it 'allows loopback endpoints' do
+ expect(described_class).not_to be_blocked_url('http://127.0.0.2', **url_blocker_attributes)
+ end
+
+ it 'allows IPv4 link-local endpoints' do
+ expect(described_class).not_to be_blocked_url('http://169.254.169.254', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url('http://169.254.168.100', **url_blocker_attributes)
+ end
+
+ it 'allows IPv6 link-local endpoints' do
+ expect(described_class).not_to be_blocked_url(
+ 'http://[0:0:0:0:0:ffff:169.254.169.254]', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.169.254]', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a9fe]', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url(
+ 'http://[0:0:0:0:0:ffff:169.254.168.100]', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url('http://[::ffff:169.254.168.100]', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url('http://[::ffff:a9fe:a864]', **url_blocker_attributes)
+ expect(described_class).not_to be_blocked_url('http://[fe80::c800:eff:fe74:8]', **url_blocker_attributes)
+ end
+
+ it 'allows limited broadcast address 255.255.255.255 and variants' do
+ limited_broadcast_address_variants.each do |variant|
+ expect(described_class).not_to be_blocked_url("https://#{variant}", **url_blocker_attributes),
+ "Expected #{variant} to be allowed"
+ end
+ end
+ end
+
+ context 'when true (default)' do
+ let(:url_blocker_attributes) do
+ options.merge(
+ allow_localhost: true,
+ allow_local_network: true
+ )
+ end
+
+ let(:options) { { schemes: schemes } }
+
+ it_behaves_like 'allows local requests',
+ { allow_localhost: true, allow_local_network: true, schemes: %w[http https] }
+ end
+
+ context 'when false' do
+ it 'blocks urls from private networks' do
+ local_ips.each do |ip|
+ stub_domain_resolv(fake_domain, ip) do
+ expect(described_class).to be_blocked_url(
+ "http://#{fake_domain}", allow_local_network: false, schemes: schemes)
+ end
+
+ expect(described_class).to be_blocked_url("http://#{ip}", allow_local_network: false, schemes: schemes)
+ end
+ end
+
+ it 'blocks IPv4 link-local endpoints' do
+ expect(described_class).to be_blocked_url(
+ 'http://169.254.169.254', allow_local_network: false, schemes: schemes)
+ expect(described_class).to be_blocked_url(
+ 'http://169.254.168.100', allow_local_network: false, schemes: schemes)
+ end
+
+ it 'blocks IPv6 link-local endpoints' do
+ expect(described_class).to be_blocked_url(
+ 'http://[0:0:0:0:0:ffff:169.254.169.254]', allow_local_network: false, schemes: schemes)
+ expect(described_class).to be_blocked_url(
+ 'http://[::ffff:169.254.169.254]', allow_local_network: false, schemes: schemes)
+ expect(described_class).to be_blocked_url(
+ 'http://[::ffff:a9fe:a9fe]', allow_local_network: false, schemes: schemes)
+ expect(described_class).to be_blocked_url(
+ 'http://[0:0:0:0:0:ffff:169.254.168.100]', allow_local_network: false, schemes: schemes)
+ expect(described_class).to be_blocked_url(
+ 'http://[::ffff:169.254.168.100]', allow_local_network: false, schemes: schemes)
+ expect(described_class).to be_blocked_url(
+ 'http://[::ffff:a9fe:a864]', allow_local_network: false, schemes: schemes)
+ expect(described_class).to be_blocked_url(
+ 'http://[fe80::c800:eff:fe74:8]', allow_local_network: false, schemes: schemes)
+ end
+
+ it 'blocks limited broadcast address 255.255.255.255 and variants' do
+ # Raise BlockedUrlError for invalid URLs.
+ # The padded hex version, for example, is a valid URL on Mac but
+ # not on Ubuntu.
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ limited_broadcast_address_variants.each do |variant|
+ expect(described_class).to be_blocked_url(
+ "https://#{variant}", allow_local_network: false, schemes: schemes),
+ "Expected #{variant} to be blocked"
+ end
+ end
+
+ context 'when local domain/IP is allowed' do
+ let(:url_blocker_attributes) do
+ options.merge(
+ allow_localhost: false,
+ allow_local_network: false
+ )
+ end
+
+ let(:options) { { schemes: schemes, outbound_local_requests_allowlist: allowlist } }
+
+ context 'with IPs in allowlist' do
+ let(:allowlist) do
+ [
+ '0.0.0.0',
+ '127.0.0.1',
+ '127.0.0.2',
+ '192.168.1.1',
+ *local_ips,
+ '0:0:0:0:0:ffff:169.254.169.254',
+ '::ffff:a9fe:a9fe',
+ '::ffff:169.254.168.100',
+ '::ffff:a9fe:a864',
+ 'fe80::c800:eff:fe74:8',
+ '255.255.255.255',
+
+ # garbage IPs
+ '45645632345',
+ 'garbage456:more345gar:bage'
+ ]
+ end
+
+ it_behaves_like 'allows local requests',
+ { allow_localhost: false, allow_local_network: false, schemes: %w[http https] }
+
+ it 'allows IP when dns_rebind_protection is disabled' do
+ url = "http://example.com"
+ attrs = url_blocker_attributes.merge(dns_rebind_protection: false)
+
+ stub_domain_resolv('example.com', '192.168.1.2') do
+ expect(described_class).not_to be_blocked_url(url, **attrs)
+ end
+
+ stub_domain_resolv('example.com', '192.168.1.3') do
+ expect(described_class).to be_blocked_url(url, **attrs)
+ end
+ end
+
+ it 'allows the limited broadcast address 255.255.255.255' do
+ expect(described_class).not_to be_blocked_url('http://255.255.255.255', **url_blocker_attributes)
+ end
+ end
+
+ context 'with domains in allowlist' do
+ let(:allowlist) do
+ [
+ 'www.example.com',
+ 'example.com',
+ 'xn--itlab-j1a.com',
+ 'garbage$^$%#$^&$'
+ ]
+ end
+
+ it 'allows domains present in allowlist' do
+ domain = 'example.com'
+ subdomain1 = 'www.example.com'
+ subdomain2 = 'subdomain.example.com'
+
+ stub_domain_resolv(domain, '192.168.1.1') do
+ expect(described_class).not_to be_blocked_url("http://#{domain}",
+ **url_blocker_attributes)
+ end
+
+ stub_domain_resolv(subdomain1, '192.168.1.1') do
+ expect(described_class).not_to be_blocked_url("http://#{subdomain1}",
+ **url_blocker_attributes)
+ end
+
+ # subdomain2 is not part of the allowlist so it should be blocked
+ stub_domain_resolv(subdomain2, '192.168.1.1') do
+ expect(described_class).to be_blocked_url("http://#{subdomain2}",
+ **url_blocker_attributes)
+ end
+ end
+
+ it 'works with unicode and idna encoded domains' do
+ unicode_domain = 'ÄŸitlab.com'
+ idna_encoded_domain = 'xn--itlab-j1a.com'
+
+ stub_domain_resolv(unicode_domain, '192.168.1.1') do
+ expect(described_class).not_to be_blocked_url("http://#{unicode_domain}",
+ **url_blocker_attributes)
+ end
+
+ stub_domain_resolv(idna_encoded_domain, '192.168.1.1') do
+ expect(described_class).not_to be_blocked_url("http://#{idna_encoded_domain}",
+ **url_blocker_attributes)
+ end
+ end
+
+ shared_examples 'dns rebinding checks' do
+ shared_examples 'allowlists the domain' do
+ let(:allowlist) { [domain] }
+ let(:url) { "http://#{domain}" }
+
+ before do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+ end
+
+ it do
+ expect(described_class).not_to be_blocked_url(url, **options, dns_rebind_protection: dns_rebind_value)
+ end
+ end
+
+ describe 'dns_rebinding_setting' do
+ context 'when enabled' do
+ let(:dns_rebind_value) { true }
+
+ it_behaves_like 'allowlists the domain'
+ end
+
+ context 'when disabled' do
+ let(:dns_rebind_value) { false }
+
+ it_behaves_like 'allowlists the domain'
+ end
+ end
+ end
+
+ context 'when the domain cannot be resolved' do
+ let(:domain) { 'foobar.x' }
+
+ it_behaves_like 'dns rebinding checks'
+ end
+
+ context 'when the domain can be resolved' do
+ let(:domain) { 'example.com' }
+
+ before do
+ stub_dns(url, ip_address: '93.184.216.34')
+ end
+
+ it_behaves_like 'dns rebinding checks'
+ end
+ end
+
+ context 'with ports' do
+ let(:allowlist) do
+ ["127.0.0.1:2000"]
+ end
+
+ it 'allows domain with port when resolved ip has port allowed' do
+ stub_domain_resolv("www.resolve-domain.com", '127.0.0.1', 2000) do
+ expect(described_class).not_to be_blocked_url(
+ "http://www.resolve-domain.com:2000", **url_blocker_attributes)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe 'enforce_user' do
+ context 'when false (default)' do
+ it 'does not block urls with a non-alphanumeric username' do
+ expect(described_class).not_to be_blocked_url('ssh://-oProxyCommand=whoami@example.com/a', schemes: ['ssh'])
+
+ # The leading character here is a Unicode "soft hyphen"
+ expect(described_class).not_to be_blocked_url('ssh://­oProxyCommand=whoami@example.com/a', schemes: ['ssh'])
+
+ # Unicode alphanumerics are allowed
+ expect(described_class).not_to be_blocked_url('ssh://ÄŸitlab@example.com/a', schemes: ['ssh'])
+ end
+ end
+
+ context 'when true' do
+ it 'blocks urls with a non-alphanumeric username' do
+ aggregate_failures do
+ expect(described_class).to be_blocked_url(
+ 'ssh://-oProxyCommand=whoami@example.com/a', enforce_user: true, schemes: ['ssh'])
+
+ # The leading character here is a Unicode "soft hyphen"
+ expect(described_class).to be_blocked_url(
+ 'ssh://­oProxyCommand=whoami@example.com/a', enforce_user: true, schemes: ['ssh'])
+
+ # Unicode alphanumerics are allowed
+ expect(described_class).not_to be_blocked_url(
+ 'ssh://ÄŸitlab@example.com/a', enforce_user: true, schemes: ['ssh'])
+ end
+ end
+ end
+ end
+
+ context 'when ascii_only is true' do
+ it 'returns true for unicode domain' do
+ expect(described_class.blocked_url?(
+ 'https://ð•˜itⅼαƄ.com/foo/foo.bar', ascii_only: true, schemes: schemes)).to be true
+ end
+
+ it 'returns true for unicode tld' do
+ expect(described_class.blocked_url?(
+ 'https://gitlab.ᴄοï½/foo/foo.bar', ascii_only: true, schemes: schemes)).to be true
+ end
+
+ it 'returns true for unicode path' do
+ expect(described_class.blocked_url?(
+ 'https://gitlab.com/ð’‡Î¿Î¿/ð’‡Î¿Î¿.Ƅαê®', ascii_only: true, schemes: schemes)).to be true
+ end
+
+ it 'returns true for IDNA deviations' do
+ expect(described_class.blocked_url?(
+ 'https://mißile.com/foo/foo.bar', ascii_only: true, schemes: schemes)).to be true
+ expect(described_class.blocked_url?(
+ 'https://miςςile.com/foo/foo.bar', ascii_only: true, schemes: schemes)).to be true
+ expect(described_class.blocked_url?(
+ 'https://gitâ€lab.com/foo/foo.bar', ascii_only: true, schemes: schemes)).to be true
+ expect(described_class.blocked_url?(
+ 'https://git‌lab.com/foo/foo.bar', ascii_only: true, schemes: schemes)).to be true
+ end
+ end
+
+ it 'blocks urls with invalid ip address' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect(described_class).to be_blocked_url('http://8.8.8.8.8', schemes: schemes)
+ end
+
+ it 'blocks urls whose hostname cannot be resolved' do
+ stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
+
+ expect(described_class).to be_blocked_url('http://foobar.x', schemes: schemes)
+ end
+
+ context 'when gitlab is running on a non-default port' do
+ let(:gitlab_port) { 3000 }
+
+ before do
+ Gitlab::HTTP_V2.configuration.allowed_internal_uris = [
+ URI::HTTP.build(
+ scheme: 'http',
+ host: 'gitlab.local',
+ port: gitlab_port
+ )
+ ]
+ end
+
+ it 'returns true for url targeting the wrong port' do
+ stub_domain_resolv('gitlab.local', '127.0.0.1') do
+ expect(described_class).to be_blocked_url("http://gitlab.local/foo", schemes: schemes)
+ end
+ end
+
+ it 'does not block url on gitlab port' do
+ stub_domain_resolv('gitlab.local', '127.0.0.1', gitlab_port) do
+ expect(described_class).not_to be_blocked_url("http://gitlab.local:#{gitlab_port}/foo", schemes: schemes)
+ end
+ end
+ end
+
+ def stub_domain_resolv(domain, ip, port = 80)
+ address = instance_double(Addrinfo,
+ ip_address: ip,
+ ipv4_private?: true,
+ ipv6_linklocal?: false,
+ ipv4_loopback?: false,
+ ipv6_loopback?: false,
+ ipv4?: false,
+ ip_port: port
+ )
+ allow(Addrinfo).to receive(:getaddrinfo).with(domain, port, any_args).and_return([address])
+ allow(address).to receive(:ipv6_v4mapped?).and_return(false)
+
+ yield
+
+ allow(Addrinfo).to receive(:getaddrinfo).and_call_original
+ end
+ end
+
+ describe '#validate_hostname' do
+ let(:ip_addresses) do
+ [
+ '2001:db8:1f70::999:de8:7648:6e8',
+ 'FE80::C800:EFF:FE74:8',
+ '::ffff:127.0.0.1',
+ '::ffff:169.254.168.100',
+ '::ffff:7f00:1',
+ '0:0:0:0:0:ffff:0.0.0.0',
+ 'localhost',
+ '127.0.0.1',
+ '127.000.000.001',
+ '0x7f000001',
+ '0x7f.0.0.1',
+ '0x7f.0.0.1',
+ '017700000001',
+ '0177.1',
+ '2130706433',
+ '::',
+ '::1'
+ ]
+ end
+
+ it 'does not raise error for valid Ip addresses' do
+ ip_addresses.each do |ip|
+ expect { described_class.send(:validate_hostname, ip) }.not_to raise_error
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/http_v2_spec.rb b/gems/gitlab-http/spec/gitlab/http_v2_spec.rb
new file mode 100644
index 00000000000..bfa1dcd2633
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/http_v2_spec.rb
@@ -0,0 +1,453 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::HTTP_V2, feature_category: :shared do
+ context 'when allow_local_requests' do
+ it 'sends the request to the correct URI' do
+ stub_full_request('https://example.org:8080', ip_address: '8.8.8.8').to_return(status: 200)
+
+ described_class.get('https://example.org:8080', allow_local_requests: false)
+
+ expect(WebMock).to have_requested(:get, 'https://8.8.8.8:8080').once
+ end
+ end
+
+ context 'when not allow_local_requests' do
+ it 'sends the request to the correct URI' do
+ stub_full_request('https://example.org:8080')
+
+ described_class.get('https://example.org:8080', allow_local_requests: true)
+
+ expect(WebMock).to have_requested(:get, 'https://8.8.8.9:8080').once
+ end
+ end
+
+ context 'when reading the response is too slow' do
+ before(:all) do
+ # Override Net::HTTP to add a delay between sending each response chunk
+ mocked_http = Class.new(Net::HTTP) do
+ def request(*)
+ super do |response|
+ response.instance_eval do
+ def read_body(*)
+ mock_stream = @body.split(' ')
+ mock_stream.each do |fragment|
+ sleep 0.002.seconds
+
+ yield fragment if block_given?
+ end
+
+ @body
+ end
+ end
+
+ yield response if block_given?
+
+ response
+ end
+ end
+ end
+
+ @original_net_http = Net.send(:remove_const, :HTTP)
+ @webmock_net_http = WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP)
+
+ Net.send(:const_set, :HTTP, mocked_http)
+ WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_set(:@webMockNetHTTP, mocked_http)
+
+ # Reload Gitlab::NetHttpAdapter
+ described_class.send(:remove_const, :NetHttpAdapter)
+ load "gitlab/http_v2/net_http_adapter.rb"
+ end
+
+ before do
+ stub_const("#{described_class}::Client::DEFAULT_READ_TOTAL_TIMEOUT", 0.001.seconds)
+
+ WebMock.stub_request(:post, /.*/).to_return do
+ { body: "chunk-1 chunk-2", status: 200 }
+ end
+ end
+
+ after(:all) do
+ Net.send(:remove_const, :HTTP)
+ Net.send(:const_set, :HTTP, @original_net_http) # rubocop:disable RSpec/InstanceVariable
+ WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_set(:@webMockNetHTTP, @webmock_net_http) # rubocop:disable RSpec/InstanceVariable
+
+ # Reload Gitlab::NetHttpAdapter
+ described_class.send(:remove_const, :NetHttpAdapter)
+ load "gitlab/http_v2/net_http_adapter.rb"
+ end
+
+ let(:options) { {} }
+
+ subject(:request_slow_responder) { described_class.post('http://example.org', **options) }
+
+ it 'raises an error' do
+ expect do
+ request_slow_responder
+ end.to raise_error(Gitlab::HTTP_V2::ReadTotalTimeout,
+ /Request timed out after ?([0-9]*[.])?[0-9]+ seconds/)
+ end
+
+ context 'and timeout option is greater than DEFAULT_READ_TOTAL_TIMEOUT' do
+ let(:options) { { timeout: 10.seconds } }
+
+ it 'does not raise an error' do
+ expect { request_slow_responder }.not_to raise_error
+ end
+ end
+
+ context 'and stream_body option is truthy' do
+ let(:options) { { stream_body: true } }
+
+ it 'does not raise an error' do
+ expect { request_slow_responder }.not_to raise_error
+ end
+ end
+ end
+
+ it 'calls a block' do
+ WebMock.stub_request(:post, /.*/)
+
+ expect { |b| described_class.post('http://example.org', &b) }.to yield_with_args
+ end
+
+ describe 'allow_local_requests' do
+ before do
+ WebMock.stub_request(:get, /.*/).to_return(status: 200, body: 'Success')
+ end
+
+ context 'when it is disabled' do
+ it 'deny requests to localhost' do
+ expect do
+ described_class.get('http://localhost:3003', allow_local_requests: false)
+ end.to raise_error(Gitlab::HTTP_V2::BlockedUrlError)
+ end
+
+ it 'deny requests to private network' do
+ expect do
+ described_class.get('http://192.168.1.2:3003', allow_local_requests: false)
+ end.to raise_error(Gitlab::HTTP_V2::BlockedUrlError)
+ end
+
+ context 'if allow_local_requests set to true' do
+ it 'override the global value and allow requests to localhost or private network' do
+ stub_full_request('http://localhost:3003')
+
+ expect { described_class.get('http://localhost:3003', allow_local_requests: true) }.not_to raise_error
+ end
+ end
+ end
+
+ context 'when it is enabled' do
+ it 'allow requests to localhost' do
+ stub_full_request('http://localhost:3003')
+
+ expect { described_class.get('http://localhost:3003', allow_local_requests: true) }.not_to raise_error
+ end
+
+ it 'allow requests to private network' do
+ expect { described_class.get('http://192.168.1.2:3003', allow_local_requests: true) }.not_to raise_error
+ end
+
+ context 'if allow_local_requests set to false' do
+ it 'override the global value and ban requests to localhost or private network' do
+ expect do
+ described_class.get('http://localhost:3003',
+ allow_local_requests: false)
+ end.to raise_error(Gitlab::HTTP_V2::BlockedUrlError)
+ end
+ end
+ end
+ end
+
+ describe 'handle redirect loops' do
+ before do
+ stub_full_request("http://example.org", method: :any)
+ .to_raise(HTTParty::RedirectionTooDeep.new("Redirection Too Deep"))
+ end
+
+ it 'handles GET requests' do
+ expect { described_class.get('http://example.org') }.to raise_error(Gitlab::HTTP_V2::RedirectionTooDeep)
+ end
+
+ it 'handles POST requests' do
+ expect { described_class.post('http://example.org') }.to raise_error(Gitlab::HTTP_V2::RedirectionTooDeep)
+ end
+
+ it 'handles PUT requests' do
+ expect { described_class.put('http://example.org') }.to raise_error(Gitlab::HTTP_V2::RedirectionTooDeep)
+ end
+
+ it 'handles DELETE requests' do
+ expect { described_class.delete('http://example.org') }.to raise_error(Gitlab::HTTP_V2::RedirectionTooDeep)
+ end
+
+ it 'handles HEAD requests' do
+ expect { described_class.head('http://example.org') }.to raise_error(Gitlab::HTTP_V2::RedirectionTooDeep)
+ end
+ end
+
+ describe 'setting default timeouts' do
+ let(:default_timeout_options) { described_class::Client::DEFAULT_TIMEOUT_OPTIONS }
+
+ before do
+ stub_full_request('http://example.org', method: :any)
+ end
+
+ context 'when no timeouts are set' do
+ it 'sets default open and read and write timeouts' do
+ expect(described_class::Client).to receive(:httparty_perform_request).with(
+ Net::HTTP::Get, 'http://example.org', default_timeout_options
+ ).and_call_original
+
+ described_class.get('http://example.org')
+ end
+ end
+
+ context 'when :timeout is set' do
+ it 'does not set any default timeouts' do
+ expect(described_class::Client).to receive(:httparty_perform_request).with(
+ Net::HTTP::Get, 'http://example.org', { timeout: 1 }
+ ).and_call_original
+
+ described_class.get('http://example.org', timeout: 1)
+ end
+ end
+
+ context 'when :open_timeout is set' do
+ it 'only sets default read and write timeout' do
+ expect(described_class::Client).to receive(:httparty_perform_request).with(
+ Net::HTTP::Get, 'http://example.org', default_timeout_options.merge(open_timeout: 1)
+ ).and_call_original
+
+ described_class.get('http://example.org', open_timeout: 1)
+ end
+ end
+
+ context 'when :read_timeout is set' do
+ it 'only sets default open and write timeout' do
+ expect(described_class::Client).to receive(:httparty_perform_request).with(
+ Net::HTTP::Get, 'http://example.org', default_timeout_options.merge(read_timeout: 1)
+ ).and_call_original
+
+ described_class.get('http://example.org', read_timeout: 1)
+ end
+ end
+
+ context 'when :write_timeout is set' do
+ it 'only sets default open and read timeout' do
+ expect(described_class::Client).to receive(:httparty_perform_request).with(
+ Net::HTTP::Put, 'http://example.org', default_timeout_options.merge(write_timeout: 1)
+ ).and_call_original
+
+ described_class.put('http://example.org', write_timeout: 1)
+ end
+ end
+ end
+
+ describe '.try_get' do
+ let(:path) { 'http://example.org' }
+ let(:default_timeout_options) { described_class::Client::DEFAULT_TIMEOUT_OPTIONS }
+
+ let(:extra_log_info_proc) do
+ proc do |error, url, options|
+ { klass: error.class, url: url, options: options }
+ end
+ end
+
+ let(:request_options) do
+ {
+ **default_timeout_options,
+ verify: false,
+ basic_auth: { username: 'user', password: 'pass' }
+ }
+ end
+
+ described_class::HTTP_ERRORS.each do |exception_class|
+ context "with #{exception_class}" do
+ let(:klass) { exception_class }
+
+ context 'with path' do
+ before do
+ expect(described_class::Client).to receive(:httparty_perform_request) # rubocop:disable RSpec/ExpectInHook
+ .with(Net::HTTP::Get, path, default_timeout_options)
+ .and_raise(klass)
+ end
+
+ it 'handles requests without extra_log_info' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), {})
+
+ expect(described_class.try_get(path)).to be_nil
+ end
+
+ it 'handles requests with extra_log_info as hash' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), { a: :b })
+
+ expect(described_class.try_get(path, extra_log_info: { a: :b })).to be_nil
+ end
+
+ it 'handles requests with extra_log_info as proc' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), { url: path, klass: klass, options: {} })
+
+ expect(described_class.try_get(path, extra_log_info: extra_log_info_proc)).to be_nil
+ end
+ end
+
+ context 'with path and options' do
+ before do
+ expect(described_class::Client).to receive(:httparty_perform_request) # rubocop:disable RSpec/ExpectInHook
+ .with(Net::HTTP::Get, path, request_options)
+ .and_raise(klass)
+ end
+
+ it 'handles requests without extra_log_info' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), {})
+
+ expect(described_class.try_get(path, request_options)).to be_nil
+ end
+
+ it 'handles requests with extra_log_info as hash' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), { a: :b })
+
+ expect(described_class.try_get(path, **request_options, extra_log_info: { a: :b })).to be_nil
+ end
+
+ it 'handles requests with extra_log_info as proc' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), { klass: klass, url: path, options: request_options })
+
+ expect(described_class.try_get(path, **request_options, extra_log_info: extra_log_info_proc)).to be_nil
+ end
+ end
+
+ context 'with path, options, and block' do
+ let(:block) do
+ proc {}
+ end
+
+ before do
+ expect(described_class::Client).to receive(:httparty_perform_request) # rubocop:disable RSpec/ExpectInHook
+ .with(Net::HTTP::Get, path, request_options, &block)
+ .and_raise(klass)
+ end
+
+ it 'handles requests without extra_log_info' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), {})
+
+ expect(described_class.try_get(path, request_options, &block)).to be_nil
+ end
+
+ it 'handles requests with extra_log_info as hash' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), { a: :b })
+
+ expect(described_class.try_get(path, **request_options, extra_log_info: { a: :b }, &block)).to be_nil
+ end
+
+ it 'handles requests with extra_log_info as proc' do
+ expect(described_class.configuration)
+ .to receive(:log_exception)
+ .with(instance_of(klass), { klass: klass, url: path, options: request_options })
+
+ expect(
+ described_class.try_get(path, **request_options, extra_log_info: extra_log_info_proc, &block)
+ ).to be_nil
+ end
+ end
+ end
+ end
+ end
+
+ describe 'silent mode', feature_category: :geo_replication do
+ before do
+ stub_full_request("http://example.org", method: :any)
+ end
+
+ context 'when silent mode is enabled' do
+ let(:silent_mode) { true }
+
+ it 'allows GET requests' do
+ expect { described_class.get('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+
+ it 'allows HEAD requests' do
+ expect { described_class.head('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+
+ it 'allows OPTIONS requests' do
+ expect { described_class.options('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+
+ it 'blocks POST requests' do
+ expect do
+ described_class.post('http://example.org', silent_mode_enabled: silent_mode)
+ end.to raise_error(Gitlab::HTTP_V2::SilentModeBlockedError)
+ end
+
+ it 'blocks PUT requests' do
+ expect do
+ described_class.put('http://example.org', silent_mode_enabled: silent_mode)
+ end.to raise_error(Gitlab::HTTP_V2::SilentModeBlockedError)
+ end
+
+ it 'blocks DELETE requests' do
+ expect do
+ described_class.delete('http://example.org', silent_mode_enabled: silent_mode)
+ end.to raise_error(Gitlab::HTTP_V2::SilentModeBlockedError)
+ end
+
+ it 'logs blocked requests' do
+ expect(described_class.configuration).to receive(:silent_mode_log_info).with(
+ "Outbound HTTP request blocked", 'Net::HTTP::Post'
+ )
+
+ expect do
+ described_class.post('http://example.org', silent_mode_enabled: silent_mode)
+ end.to raise_error(Gitlab::HTTP_V2::SilentModeBlockedError)
+ end
+ end
+
+ context 'when silent mode is disabled' do
+ let(:silent_mode) { false }
+
+ it 'allows GET requests' do
+ expect { described_class.get('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+
+ it 'allows HEAD requests' do
+ expect { described_class.head('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+
+ it 'allows OPTIONS requests' do
+ expect { described_class.options('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+
+ it 'blocks POST requests' do
+ expect { described_class.post('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+
+ it 'blocks PUT requests' do
+ expect { described_class.put('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+
+ it 'blocks DELETE requests' do
+ expect { described_class.delete('http://example.org', silent_mode_enabled: silent_mode) }.not_to raise_error
+ end
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/gitlab/stub_requests.rb b/gems/gitlab-http/spec/gitlab/stub_requests.rb
new file mode 100644
index 00000000000..ea4a6865251
--- /dev/null
+++ b/gems/gitlab-http/spec/gitlab/stub_requests.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StubRequests
+ IP_ADDRESS_STUB = '8.8.8.9'
+
+ # Fully stubs a request using WebMock class. This class also
+ # stubs the IP address the URL is translated to (DNS lookup).
+ #
+ # It expects the final request to go to the `ip_address` instead the given url.
+ # That's primarily a DNS rebind attack prevention of Gitlab::HTTP
+ # (see: Gitlab::HTTP_V2::UrlBlocker).
+ #
+ def stub_full_request(url, ip_address: IP_ADDRESS_STUB, port: 80, method: :get)
+ stub_dns(url, ip_address: ip_address, port: port)
+
+ url = stubbed_hostname(url, hostname: ip_address)
+ WebMock.stub_request(method, url)
+ end
+
+ def stub_dns(url, ip_address:, port: 80)
+ url = parse_url(url)
+ socket = Socket.sockaddr_in(port, ip_address)
+ addr = Addrinfo.new(socket)
+
+ # See Gitlab::UrlBlocker
+ allow(Addrinfo).to receive(:getaddrinfo)
+ .with(url.hostname, url.port, nil, :STREAM)
+ .and_return([addr])
+ end
+
+ def stub_all_dns(url, ip_address:)
+ url = URI(url)
+ port = 80 # arbitarily chosen, does not matter as we are not going to connect
+ socket = Socket.sockaddr_in(port, ip_address)
+ addr = Addrinfo.new(socket)
+
+ # See Gitlab::UrlBlocker
+ allow(Addrinfo).to receive(:getaddrinfo).and_call_original
+ allow(Addrinfo).to receive(:getaddrinfo)
+ .with(url.hostname, anything, nil, :STREAM)
+ .and_return([addr])
+ end
+
+ def stubbed_hostname(url, hostname: IP_ADDRESS_STUB)
+ url = parse_url(url)
+ url.hostname = hostname
+ url.to_s
+ end
+
+ private
+
+ def parse_url(url)
+ url.is_a?(URI) ? url : URI(url)
+ end
+ end
+end
diff --git a/gems/gitlab-http/spec/spec_helper.rb b/gems/gitlab-http/spec/spec_helper.rb
new file mode 100644
index 00000000000..a9bfc471aef
--- /dev/null
+++ b/gems/gitlab-http/spec/spec_helper.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'rails'
+require 'rspec/mocks'
+
+require 'gitlab/rspec/all'
+require 'gitlab/http_v2'
+require 'gitlab/http_v2/configuration'
+require 'gitlab/stub_requests'
+require 'webmock/rspec'
+
+ENV["RSPEC_ALLOW_INVALID_URLS"] = 'true' # rubocop: disable RSpec/EnvAssignment
+
+RSpec.configure do |config|
+ config.include StubENV
+ config.include Gitlab::StubRequests
+
+ # Enable flags like --only-failures and --next-failure
+ config.example_status_persistence_file_path = ".rspec_status"
+
+ # Disable RSpec exposing methods globally on `Module` and `main`
+ config.disable_monkey_patching!
+
+ config.expect_with :rspec do |c|
+ c.syntax = :expect
+ end
+end
+
+Gitlab::HTTP_V2.configure do |config|
+ config.allowed_internal_uris = [
+ URI::HTTP.build(
+ scheme: 'http',
+ host: 'localhost',
+ port: '80'
+ ),
+ URI::Generic.build(
+ scheme: 'ssh',
+ host: 'localhost',
+ port: '22'
+ )
+ ]
+
+ config.log_exception_proc = ->(exception, extra_info) do
+ # no-op
+ end
+
+ config.silent_mode_log_info_proc = ->(message, http_method) do
+ # no-op
+ end
+end
diff --git a/gems/gitlab-schema-validation/lib/gitlab/schema/validation/inconsistency.rb b/gems/gitlab-schema-validation/lib/gitlab/schema/validation/inconsistency.rb
index 13799b8b9ff..503e05f12e9 100644
--- a/gems/gitlab-schema-validation/lib/gitlab/schema/validation/inconsistency.rb
+++ b/gems/gitlab-schema-validation/lib/gitlab/schema/validation/inconsistency.rb
@@ -36,6 +36,17 @@ module Gitlab
Diffy::Diff.new(structure_sql_statement, database_statement)
end
+ def to_h
+ {
+ type: type,
+ object_type: object_type,
+ table_name: table_name,
+ object_name: object_name,
+ structure_sql_statement: structure_sql_statement,
+ database_statement: database_statement
+ }
+ end
+
def display
<<~MSG
#{'-' * 54}
diff --git a/gems/gitlab-schema-validation/spec/lib/gitlab/schema/validation/inconsistency_spec.rb b/gems/gitlab-schema-validation/spec/lib/gitlab/schema/validation/inconsistency_spec.rb
index 268bb4556e3..300383d5909 100644
--- a/gems/gitlab-schema-validation/spec/lib/gitlab/schema/validation/inconsistency_spec.rb
+++ b/gems/gitlab-schema-validation/spec/lib/gitlab/schema/validation/inconsistency_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Schema::Validation::Inconsistency do
+RSpec.describe Gitlab::Schema::Validation::Inconsistency, feature_category: :database do
let(:validator) { Gitlab::Schema::Validation::Validators::DifferentDefinitionIndexes }
let(:database_statement) { 'CREATE INDEX index_name ON public.achievements USING btree (namespace_id)' }
@@ -44,6 +44,23 @@ RSpec.describe Gitlab::Schema::Validation::Inconsistency do
end
end
+ describe '#to_h' do
+ let(:result) do
+ {
+ database_statement: inconsistency.database_statement,
+ object_name: inconsistency.object_name,
+ object_type: inconsistency.object_type,
+ structure_sql_statement: inconsistency.structure_sql_statement,
+ table_name: inconsistency.table_name,
+ type: inconsistency.type
+ }
+ end
+
+ it 'returns the to_h of the validator' do
+ expect(inconsistency.to_h).to eq(result)
+ end
+ end
+
describe '#table_name' do
it 'returns the table name' do
expect(inconsistency.table_name).to eq('achievements')
diff --git a/jest.config.base.js b/jest.config.base.js
index 5253286bfa9..39c86f9a792 100644
--- a/jest.config.base.js
+++ b/jest.config.base.js
@@ -37,7 +37,7 @@ module.exports = (path, options = {}) => {
}
if (USE_VUE_3) {
- setupFilesAfterEnv.unshift(`<rootDir>/${path}/vue_compat_test_setup.js`);
+ setupFilesAfterEnv.unshift('<rootDir>/spec/frontend/vue_compat_test_setup.js');
Object.assign(vueModuleNameMappers, {
'^vue$': '@vue/compat',
'^@vue/test-utils$': '@vue/test-utils-vue3',
@@ -262,5 +262,9 @@ module.exports = (path, options = {}) => {
url: TEST_HOST,
},
testRunner: 'jest-jasmine2',
+ snapshotSerializers: [
+ '<rootDir>/spec/frontend/__helpers__/html_string_serializer.js',
+ '<rootDir>/spec/frontend/__helpers__/clean_html_element_serializer.js',
+ ],
};
};
diff --git a/lefthook.yml b/lefthook.yml
index 27a237a8fb3..e57a6cce518 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -101,7 +101,7 @@ pre-push:
audit_event_types_docs:
tags: documentation
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
- glob: '{config/audit_events/types/*.yml,ee/config/audit_events/types/*yml}'
+ glob: '{config/audit_events/types/*.yml,ee/config/audit_events/types/*yml,doc/administration/audit_event_streaming/audit_event_types.md}'
run: bundle exec rake gitlab:audit_event_types:check_docs
rubocop:
tags: backend style
@@ -135,26 +135,26 @@ auto-fix:
commands:
frontend:
tags: frontend style
- files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD) --cached
glob: '*.{js,vue}'
run: 'yarn run lint:eslint:fix {files} && yarn run prettier --write --list-different {files}'
jsonlint:
tags: style
- files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD) --cached
glob: '*.{json}'
run: scripts/lint-json --format --verbose {files}
prettier-graphql:
tags: frontend style
- files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD) --cached
glob: '*.{graphql}'
run: yarn run prettier --write --list-different {files}
rubocop:
tags: backend style
- files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD) --cached
glob: '*.{rb,rake}'
run: REVEAL_RUBOCOP_TODO=0 bundle exec rubocop --parallel --autocorrect --force-exclusion {files}
gettext:
tags: backend frontend view haml
- files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD | while read file;do git diff --unified=1 $(git merge-base origin/master HEAD)..HEAD $file | grep -Fqe '_(' && echo $file;done; true
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD --cached | while read file;do git diff --unified=1 $(git merge-base origin/master HEAD)..HEAD $file | grep -Fqe '_(' && echo $file;done; true
glob: '*.{haml,rb,js,vue}'
run: tooling/bin/gettext_extractor locale/gitlab.pot
diff --git a/lib/api/ci/helpers/runner.rb b/lib/api/ci/helpers/runner.rb
index 94c1942a244..542b2390df2 100644
--- a/lib/api/ci/helpers/runner.rb
+++ b/lib/api/ci/helpers/runner.rb
@@ -26,7 +26,7 @@ module API
def get_runner_details_from_request
return get_runner_ip unless params['info'].present?
- attributes_for_keys(%w(name version revision platform architecture executor), params['info'])
+ attributes_for_keys(%w[name version revision platform architecture executor], params['info'])
.merge(get_system_id_from_request)
.merge(get_runner_config_from_request)
.merge(get_runner_ip)
@@ -45,9 +45,7 @@ module API
def current_runner
token = params[:token]
- if token
- ::Ci::Runner.sticking.stick_or_unstick_request(env, :runner, token)
- end
+ load_balancer_stick_request(::Ci::Runner, :runner, token) if token
strong_memoize(:current_runner) do
::Ci::Runner.find_by_token(token.to_s)
@@ -111,11 +109,7 @@ module API
def current_job
id = params[:id]
- if id
- ::Ci::Build
- .sticking
- .stick_or_unstick_request(env, :build, id)
- end
+ load_balancer_stick_request(::Ci::Build, :build, id) if id
strong_memoize(:current_job) do
::Ci::Build.find_by_id(id)
@@ -155,7 +149,7 @@ module API
private
def get_runner_config_from_request
- { config: attributes_for_keys(%w(gpus), params.dig('info', 'config')) }
+ { config: attributes_for_keys(%w[gpus], params.dig('info', 'config')) }
end
def metrics
diff --git a/lib/api/ci/jobs.rb b/lib/api/ci/jobs.rb
index 5d60c004a03..6f0a2ff7f62 100644
--- a/lib/api/ci/jobs.rb
+++ b/lib/api/ci/jobs.rb
@@ -250,7 +250,7 @@ module API
]
end
route_setting :authentication, job_token_allowed: true
- get '/allowed_agents', urgency: :low, feature_category: :deployment_management do
+ get '/allowed_agents', urgency: :default, feature_category: :deployment_management do
validate_current_authenticated_job
status 200
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 531235dc9b2..acb64cd0d3a 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -61,7 +61,7 @@ module API
requires :sha, type: String, desc: 'The commit hash',
documentation: { example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
requires :state, type: String, desc: 'The state of the status',
- values: %w(pending running success failed canceled),
+ values: %w[pending running success failed canceled],
documentation: { example: 'pending' }
optional :ref, type: String, desc: 'The ref',
documentation: { example: 'develop' }
@@ -80,75 +80,16 @@ module API
post ':id/statuses/:sha' do
authorize! :create_commit_status, user_project
- not_found! 'Commit' unless commit
+ response =
+ ::Ci::CreateCommitStatusService
+ .new(user_project, current_user, params)
+ .execute(optional_commit_status_params: optional_commit_status_params)
- # Since the CommitStatus is attached to ::Ci::Pipeline (in the future Pipeline)
- # We need to always have the pipeline object
- # To have a valid pipeline object that can be attached to specific MR
- # Other CI service needs to send `ref`
- # If we don't receive it, we will attach the CommitStatus to
- # the first found branch on that commit
-
- pipeline = all_matching_pipelines.first
-
- ref = params[:ref]
- ref ||= pipeline&.ref
- ref ||= user_project.repository.branch_names_contains(commit.sha).first
- not_found! 'References for commit' unless ref
-
- name = params[:name] || params[:context] || 'default'
-
- pipeline ||= user_project.ci_pipelines.build(
- source: :external,
- sha: commit.sha,
- ref: ref,
- user: current_user,
- protected: user_project.protected_for?(ref))
-
- pipeline.ensure_project_iid!
- pipeline.save!
-
- authorize! :update_pipeline, pipeline
-
- # rubocop: disable Performance/ActiveRecordSubtransactionMethods
- stage = pipeline.stages.safe_find_or_create_by!(name: 'external') do |stage|
- stage.position = GenericCommitStatus::EXTERNAL_STAGE_IDX
- stage.project = pipeline.project
- end
- # rubocop: enable Performance/ActiveRecordSubtransactionMethods
-
- status = GenericCommitStatus.running_or_pending.find_or_initialize_by(
- project: user_project,
- pipeline: pipeline,
- name: name,
- ref: ref,
- user: current_user,
- protected: user_project.protected_for?(ref),
- ci_stage: stage,
- stage_idx: stage.position,
- stage: 'external'
- )
-
- updatable_optional_attributes = %w[target_url description coverage]
- status.assign_attributes(attributes_for_keys(updatable_optional_attributes))
-
- render_validation_error!(status) unless status.valid?
-
- response = ::Ci::Pipelines::AddJobService.new(pipeline).execute!(status) do |job|
- apply_job_state!(job)
- rescue ::StateMachines::InvalidTransition => e
- render_api_error!(e.message, 400)
+ if response.error?
+ render_api_error!(response.message, response.http_status)
+ else
+ present response.payload[:job], with: Entities::CommitStatus
end
-
- render_validation_error!(response.payload[:job]) unless response.success?
-
- if pipeline.latest?
- MergeRequest
- .where(source_project: user_project, source_branch: ref)
- .update_all(head_pipeline_id: pipeline.id)
- end
-
- present response.payload[:job], with: Entities::CommitStatus
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -183,6 +124,11 @@ module API
render_api_error!('invalid state', 400)
end
end
+
+ def optional_commit_status_params
+ updatable_optional_attributes = %w[target_url description coverage]
+ attributes_for_keys(updatable_optional_attributes)
+ end
end
end
end
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index a4e1e8308c3..069d117db17 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -41,7 +41,7 @@ module API
namespace: namespace,
user: current_user,
label: 'counts.web_ide_commits',
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: 'counts.web_ide_commits').to_context]
+ context: [Gitlab::Usage::MetricDefinition.context_for('counts.web_ide_commits').to_context]
)
end
end
diff --git a/lib/api/concerns/packages/npm_endpoints.rb b/lib/api/concerns/packages/npm_endpoints.rb
index a045a3d4828..4278510e999 100644
--- a/lib/api/concerns/packages/npm_endpoints.rb
+++ b/lib/api/concerns/packages/npm_endpoints.rb
@@ -197,7 +197,7 @@ module API
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
get '*package_name', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do
package_name = params[:package_name]
- packages =
+ available_packages =
if Feature.enabled?(:npm_allow_packages_in_multiple_projects)
finder_for_endpoint_scope(package_name).execute
else
@@ -205,7 +205,8 @@ module API
.execute
end
- redirect_request = project_or_nil.blank? || packages.empty?
+ # In order to redirect a request, packages should not exist (without taking the user into account).
+ redirect_request = project_or_nil.blank? || available_packages.empty?
redirect_registry_request(
forward_to_registry: redirect_request,
@@ -213,9 +214,25 @@ module API
target: project_or_nil,
package_name: package_name
) do
- authorize_read_package!(project)
+ if endpoint_scope == :project || Feature.disabled?(:npm_allow_packages_in_multiple_projects)
+ authorize_read_package!(project)
+ elsif Feature.enabled?(:npm_allow_packages_in_multiple_projects)
+ available_packages_to_user = ::Packages::Npm::PackagesForUserFinder.new(
+ current_user,
+ group_or_namespace,
+ package_name: params[:package_name]
+ ).execute
+
+ if available_packages.any? && available_packages_to_user.empty?
+ forbidden! if current_user
+
+ not_found!('Packages')
+ end
+
+ available_packages = available_packages_to_user
+ end
- not_found!('Packages') if packages.empty?
+ not_found!('Packages') if available_packages.empty?
if endpoint_scope == :project && Feature.enabled?(:npm_metadata_cache, project)
if metadata_cache&.file&.exists?
@@ -228,7 +245,7 @@ module API
enqueue_sync_metadata_cache_worker(project, package_name)
end
- metadata = generate_metadata_service(packages).execute.payload
+ metadata = generate_metadata_service(available_packages).execute.payload
present metadata, with: ::API::Entities::NpmPackage
end
end
diff --git a/lib/api/discussions.rb b/lib/api/discussions.rb
index 45466a1894c..7c608f6f78e 100644
--- a/lib/api/discussions.rb
+++ b/lib/api/discussions.rb
@@ -76,7 +76,7 @@ module API
requires :base_sha, type: String, desc: 'Base commit SHA in the source branch'
requires :start_sha, type: String, desc: 'SHA referencing commit in target branch'
requires :head_sha, type: String, desc: 'SHA referencing HEAD of this merge request'
- requires :position_type, type: String, desc: 'Type of the position reference', values: %w(text image)
+ requires :position_type, type: String, desc: 'Type of the position reference', values: %w[text image file]
optional :new_path, type: String, desc: 'File path after change'
optional :new_line, type: Integer, desc: 'Line number after change'
optional :old_path, type: String, desc: 'File path before change'
diff --git a/lib/api/entities/ci/job_request/job_info.rb b/lib/api/entities/ci/job_request/job_info.rb
index 5c3f4b08af2..e228e490946 100644
--- a/lib/api/entities/ci/job_request/job_info.rb
+++ b/lib/api/entities/ci/job_request/job_info.rb
@@ -7,6 +7,8 @@ module API
class JobInfo < Grape::Entity
expose :id, :name, :stage
expose :project_id, :project_name
+ expose :time_in_queue_seconds
+ expose :project_jobs_running_on_instance_runners_count
end
end
end
diff --git a/lib/api/entities/diff.rb b/lib/api/entities/diff.rb
index e9650f07f00..b9538893d32 100644
--- a/lib/api/entities/diff.rb
+++ b/lib/api/entities/diff.rb
@@ -5,7 +5,7 @@ module API
class Diff < Grape::Entity
expose :json_safe_diff, as: :diff, documentation: {
type: 'string',
- example: '--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n...'
+ example: '@@ -71,6 +71,8 @@\n...'
}
expose :new_path, documentation: { type: 'string', example: 'doc/update/5.4-to-6.0.md' }
expose :old_path, documentation: { type: 'string', example: 'doc/update/5.4-to-6.0.md' }
diff --git a/lib/api/entities/feature.rb b/lib/api/entities/feature.rb
index 48dd5a22a7e..f341472e8c2 100644
--- a/lib/api/entities/feature.rb
+++ b/lib/api/entities/feature.rb
@@ -7,8 +7,10 @@ module API
expose :state, documentation: { type: 'string', example: 'off' }
expose :gates, using: Entities::FeatureGate do |model|
model.gates.map do |gate|
- value = model.gate_values[gate.key]
-
+ # in Flipper 0.26.1, they removed two GateValues#[] method calls for performance reasons
+ # https://github.com/flippercloud/flipper/pull/706/commits/ed914b6adc329455a634be843c38db479299efc7
+ # https://github.com/flippercloud/flipper/commit/eee20f3ae278d168c8bf70a7a5fcc03bedf432b5
+ value = model.gate_values.send(gate.key) # rubocop:disable GitlabSecurity/PublicSend
# By default all gate values are populated. Only show relevant ones.
if (value.is_a?(Integer) && value == 0) || (value.is_a?(Set) && value.empty?)
next
diff --git a/lib/api/entities/feature_flag/basic_user_list.rb b/lib/api/entities/feature_flag/basic_user_list.rb
new file mode 100644
index 00000000000..df577e9f1a4
--- /dev/null
+++ b/lib/api/entities/feature_flag/basic_user_list.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class FeatureFlag < Grape::Entity
+ class BasicUserList < Grape::Entity
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :iid, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'user_list' }
+ expose :user_xids, documentation: { type: 'string', example: 'user1,user2' }
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/feature_flag/strategy.rb b/lib/api/entities/feature_flag/strategy.rb
index 62178420370..aea38f0e24a 100644
--- a/lib/api/entities/feature_flag/strategy.rb
+++ b/lib/api/entities/feature_flag/strategy.rb
@@ -8,6 +8,7 @@ module API
expose :name, documentation: { type: 'string', example: 'userWithId' }
expose :parameters, documentation: { type: 'string', example: '{"userIds": "user1"}' }
expose :scopes, using: FeatureFlag::Scope
+ expose :user_list, using: FeatureFlag::BasicUserList
end
end
end
diff --git a/lib/api/entities/feature_flag/user_list.rb b/lib/api/entities/feature_flag/user_list.rb
index efb3261658a..47f89cea4d2 100644
--- a/lib/api/entities/feature_flag/user_list.rb
+++ b/lib/api/entities/feature_flag/user_list.rb
@@ -3,16 +3,12 @@
module API
module Entities
class FeatureFlag < Grape::Entity
- class UserList < Grape::Entity
+ class UserList < BasicUserList
include RequestAwareEntity
- expose :id, documentation: { type: 'integer', example: 1 }
- expose :iid, documentation: { type: 'integer', example: 1 }
expose :project_id, documentation: { type: 'integer', example: 2 }
expose :created_at, documentation: { type: 'dateTime', example: '2020-02-04T08:13:10.507Z' }
expose :updated_at, documentation: { type: 'dateTime', example: '2020-02-04T08:13:10.507Z' }
- expose :name, documentation: { type: 'string', example: 'user_list' }
- expose :user_xids, documentation: { type: 'string', example: 'user1,user2' }
expose :path do |list|
project_feature_flags_user_list_path(list.project, list)
diff --git a/lib/api/entities/merge_request_diff.rb b/lib/api/entities/merge_request_diff.rb
index 3eda1400855..23a2631a485 100644
--- a/lib/api/entities/merge_request_diff.rb
+++ b/lib/api/entities/merge_request_diff.rb
@@ -4,7 +4,7 @@ module API
module Entities
class MergeRequestDiff < Grape::Entity
expose :id, :head_commit_sha, :base_commit_sha, :start_commit_sha,
- :created_at, :merge_request_id, :state, :real_size
+ :created_at, :merge_request_id, :state, :real_size, :patch_id_sha
end
end
end
diff --git a/lib/api/entities/ml/mlflow/get_run.rb b/lib/api/entities/ml/mlflow/get_run.rb
new file mode 100644
index 00000000000..4bf10f987cc
--- /dev/null
+++ b/lib/api/entities/ml/mlflow/get_run.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module Ml
+ module Mlflow
+ class GetRun < Grape::Entity
+ expose :itself, using: Run, as: :run
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/ml/mlflow/run.rb b/lib/api/entities/ml/mlflow/run.rb
index 01d85e8862b..10e2434521d 100644
--- a/lib/api/entities/ml/mlflow/run.rb
+++ b/lib/api/entities/ml/mlflow/run.rb
@@ -5,13 +5,11 @@ module API
module Ml
module Mlflow
class Run < Grape::Entity
- expose :run do
- expose :itself, using: RunInfo, as: :info
- expose :data do
- expose :metrics, using: Metric
- expose :params, using: KeyValue
- expose :metadata, as: :tags, using: KeyValue
- end
+ expose :itself, using: RunInfo, as: :info
+ expose :data do
+ expose :metrics, using: Metric
+ expose :params, using: KeyValue
+ expose :metadata, as: :tags, using: KeyValue
end
end
end
diff --git a/lib/api/entities/ml/mlflow/search_runs.rb b/lib/api/entities/ml/mlflow/search_runs.rb
new file mode 100644
index 00000000000..21c2d58452e
--- /dev/null
+++ b/lib/api/entities/ml/mlflow/search_runs.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module Ml
+ module Mlflow
+ class SearchRuns < Grape::Entity # rubocop:disable Search/NamespacedClass
+ expose :candidates, with: Run, as: :runs
+ expose :next_page_token
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/note.rb b/lib/api/entities/note.rb
index 6ed5ca43fbb..c693edc611b 100644
--- a/lib/api/entities/note.rb
+++ b/lib/api/entities/note.rb
@@ -4,7 +4,7 @@ module API
module Entities
class Note < Grape::Entity
# Only Issue and MergeRequest have iid
- NOTEABLE_TYPES_WITH_IID = %w(Issue MergeRequest).freeze
+ NOTEABLE_TYPES_WITH_IID = %w[Issue MergeRequest].freeze
expose :id
expose :type
diff --git a/lib/api/entities/personal_access_token.rb b/lib/api/entities/personal_access_token.rb
index 3ec91ca5fc9..b9f831021a1 100644
--- a/lib/api/entities/personal_access_token.rb
+++ b/lib/api/entities/personal_access_token.rb
@@ -13,7 +13,7 @@ module API
expose :active?, as: :active, documentation: { type: 'boolean' }
expose :expires_at, documentation:
{ type: 'dateTime', example: '2020-08-31T15:53:00.073Z' } do |personal_access_token|
- personal_access_token.expires_at ? personal_access_token.expires_at.strftime("%Y-%m-%d") : nil
+ personal_access_token.expires_at ? personal_access_token.expires_at.iso8601 : nil
end
end
end
diff --git a/lib/api/entities/project_integration_basic.rb b/lib/api/entities/project_integration_basic.rb
index d7e111b990e..ad6128e3498 100644
--- a/lib/api/entities/project_integration_basic.rb
+++ b/lib/api/entities/project_integration_basic.rb
@@ -29,3 +29,5 @@ module API
end
end
end
+
+API::Entities::ProjectIntegrationBasic.prepend_mod
diff --git a/lib/api/feature_flags.rb b/lib/api/feature_flags.rb
index 1846ddf6833..4ed288ee997 100644
--- a/lib/api/feature_flags.rb
+++ b/lib/api/feature_flags.rb
@@ -63,7 +63,8 @@ module API
optional :version, type: String, desc: 'The version of the feature flag. Must be `new_version_flag`. Omit to create a Legacy feature flag.'
optional :strategies, type: Array do
requires :name, type: String, desc: 'The strategy name. Can be `default`, `gradualRolloutUserId`, `userWithId`, or `gitlabUserList`. In GitLab 13.5 and later, can be `flexibleRollout`'
- requires :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
+ optional :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
+ optional :user_list_id, type: Integer, desc: "The ID of the feature flag user list. If strategy is `gitlabUserList`."
optional :scopes, type: Array do
requires :environment_scope, type: String, desc: 'The environment scope of the scope'
end
@@ -131,6 +132,7 @@ module API
optional :id, type: Integer, desc: 'The feature flag strategy ID'
optional :name, type: String, desc: 'The strategy name'
optional :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
+ optional :user_list_id, type: Integer, desc: "The ID of the feature flag user list"
optional :_destroy, type: Boolean, desc: 'Delete the strategy when true'
optional :scopes, type: Array do
optional :id, type: Integer, desc: 'The scope id'
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index b7f21bd6c22..e967b88e500 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -8,6 +8,7 @@ module API
include Helpers::PaginationStrategies
include Gitlab::Ci::Artifacts::Logger
include Gitlab::Utils::StrongMemoize
+ include Gitlab::RackLoadBalancingHelpers
SUDO_HEADER = "HTTP_SUDO"
GITLAB_SHARED_SECRET_HEADER = "Gitlab-Shared-Secret"
@@ -91,9 +92,7 @@ module API
save_current_token_in_env
if @current_user
- ::ApplicationRecord
- .sticking
- .stick_or_unstick_request(env, :user, @current_user.id)
+ load_balancer_stick_request(::ApplicationRecord, :user, @current_user.id)
end
@current_user
@@ -185,6 +184,30 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
+ def find_pipeline(id)
+ return unless id
+
+ if id.to_s =~ INTEGER_ID_REGEX
+ ::Ci::Pipeline.find_by(id: id)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def find_pipeline!(id)
+ pipeline = find_pipeline(id)
+ check_pipeline_access(pipeline)
+ end
+
+ def check_pipeline_access(pipeline)
+ return forbidden! unless authorized_project_scope?(pipeline&.project)
+
+ return pipeline if can?(current_user, :read_pipeline, pipeline)
+ return unauthorized! if authenticate_non_public?
+
+ not_found!('Pipeline')
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
def find_group(id)
if id.to_s =~ INTEGER_ID_REGEX
Group.find_by(id: id)
@@ -686,8 +709,8 @@ module API
namespace_id: namespace_id,
project_id: project_id
)
- rescue StandardError => error
- Gitlab::AppLogger.warn("Internal Event tracking event failed for event: #{event_name}, message: #{error.message}")
+ rescue StandardError => e
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e, event_name: event_name)
end
def order_by_similarity?(allow_unauthorized: true)
diff --git a/lib/api/helpers/common_helpers.rb b/lib/api/helpers/common_helpers.rb
index 855648f2ef0..265e9ffcdbd 100644
--- a/lib/api/helpers/common_helpers.rb
+++ b/lib/api/helpers/common_helpers.rb
@@ -27,7 +27,7 @@ module API
options[:route_options][:params].map do |key, val|
param_type = val[:type]
# Search for parameters with Array types (e.g. "[String]", "[Integer]", etc.)
- if param_type =~ %r(\[\w*\])
+ if param_type =~ %r{\[\w*\]}
key
end
end.compact.to_set
diff --git a/lib/api/helpers/integrations_helpers.rb b/lib/api/helpers/integrations_helpers.rb
index 53117af8648..8f846fe7348 100644
--- a/lib/api/helpers/integrations_helpers.rb
+++ b/lib/api/helpers/integrations_helpers.rb
@@ -124,95 +124,6 @@ module API
].freeze
end
- def self.chat_notification_events
- [
- {
- required: false,
- name: :commit_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for commit_events'
- },
- {
- required: false,
- name: :push_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for push_events'
- },
- {
- required: false,
- name: :issues_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for issues_events'
- },
- {
- required: false,
- name: :incident_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for incident_events'
- },
- {
- required: false,
- name: :alert_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for alert_events'
- },
- {
- required: false,
- name: :confidential_issues_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for confidential_issues_events'
- },
- {
- required: false,
- name: :merge_requests_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for merge_requests_events'
- },
- {
- required: false,
- name: :note_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for note_events'
- },
- {
- required: false,
- name: :confidential_note_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for confidential_note_events'
- },
- {
- required: false,
- name: :tag_push_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for tag_push_events'
- },
- {
- required: false,
- name: :deployment_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for deployment_events'
- },
- {
- required: false,
- name: :job_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for job_events'
- },
- {
- required: false,
- name: :pipeline_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for pipeline_events'
- },
- {
- required: false,
- name: :wiki_page_events,
- type: ::Grape::API::Boolean,
- desc: 'Enable notifications for wiki_page_events'
- }
- ].freeze
- end
-
def self.integrations
{
'apple-app-store' => [
@@ -453,7 +364,6 @@ module API
desc: 'Branches for which notifications are to be sent'
},
chat_notification_flags,
- chat_notification_events,
chat_notification_channels
].flatten,
'drone-ci' => [
@@ -548,8 +458,7 @@ module API
name: :branches_to_be_notified,
type: String,
desc: 'Branches for which notifications are to be sent'
- },
- chat_notification_events
+ }
].flatten,
'harbor' => [
{
@@ -813,8 +722,7 @@ module API
name: :webhook,
type: String,
desc: 'The Pumble chat webhook. For example, https://api.pumble.com/workspaces/x/...'
- },
- chat_notification_events
+ }
].flatten,
'pushover' => [
{
@@ -919,8 +827,7 @@ module API
'slack' => [
chat_notification_settings,
chat_notification_flags,
- chat_notification_channels,
- chat_notification_events
+ chat_notification_channels
].flatten,
'microsoft-teams' => [
{
@@ -940,8 +847,7 @@ module API
'mattermost' => [
chat_notification_settings,
chat_notification_flags,
- chat_notification_channels,
- chat_notification_events
+ chat_notification_channels
].flatten,
'teamcity' => [
{
@@ -988,7 +894,7 @@ module API
type: String,
desc: 'Unique identifier for the target chat or username of the target channel (in the format @channelusername)'
},
- chat_notification_events
+ chat_notification_flags
].flatten,
'unify-circuit' => [
{
@@ -996,8 +902,7 @@ module API
name: :webhook,
type: String,
desc: 'The Unify Circuit webhook. e.g. https://circuit.com/rest/v2/webhooks/incoming/…'
- },
- chat_notification_events
+ }
].flatten,
'webex-teams' => [
{
@@ -1005,8 +910,7 @@ module API
name: :webhook,
type: String,
desc: 'The Webex Teams webhook. For example, https://api.ciscospark.com/v1/webhooks/incoming/...'
- },
- chat_notification_events
+ }
].flatten,
'zentao' => [
{
@@ -1082,12 +986,17 @@ module API
::Integrations::PipelinesEmail,
::Integrations::Pivotaltracker,
::Integrations::Prometheus,
+ ::Integrations::Pumble,
::Integrations::Pushover,
::Integrations::Redmine,
+ ::Integrations::Shimo,
::Integrations::Slack,
::Integrations::SlackSlashCommands,
::Integrations::SquashTm,
::Integrations::Teamcity,
+ ::Integrations::Telegram,
+ ::Integrations::UnifyCircuit,
+ ::Integrations::WebexTeams,
::Integrations::Youtrack,
::Integrations::Zentao
]
diff --git a/lib/api/helpers/kubernetes/agent_helpers.rb b/lib/api/helpers/kubernetes/agent_helpers.rb
new file mode 100644
index 00000000000..50a8c2a5aed
--- /dev/null
+++ b/lib/api/helpers/kubernetes/agent_helpers.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+module API
+ module Helpers
+ module Kubernetes
+ module AgentHelpers
+ include Gitlab::Utils::StrongMemoize
+
+ def authenticate_gitlab_kas_request!
+ render_api_error!('KAS JWT authentication invalid', 401) unless Gitlab::Kas.verify_api_request(headers)
+ end
+
+ def agent_token
+ cluster_agent_token_from_authorization_token
+ end
+ strong_memoize_attr :agent_token
+
+ def agent
+ agent_token.agent
+ end
+ strong_memoize_attr :agent
+
+ def gitaly_info(project)
+ gitaly_features = Feature::Gitaly.server_feature_flags
+
+ Gitlab::GitalyClient.connection_data(project.repository_storage).merge(features: gitaly_features)
+ end
+
+ def gitaly_repository(project)
+ project.repository.gitaly_repository.to_h
+ end
+
+ def check_feature_enabled
+ not_found!('Internal API not found') unless Feature.enabled?(:kubernetes_agent_internal_api, type: :ops)
+ end
+
+ def check_agent_token
+ unauthorized! unless agent_token
+
+ ::Clusters::AgentTokens::TrackUsageService.new(agent_token).execute
+ end
+
+ def agent_has_access_to_project?(project)
+ Guest.can?(:download_code, project) || agent.has_access_to?(project)
+ end
+
+ def increment_unique_events
+ events = params[:unique_counters]&.slice(
+ :agent_users_using_ci_tunnel,
+ :k8s_api_proxy_requests_unique_users_via_ci_access, :k8s_api_proxy_requests_unique_agents_via_ci_access,
+ :k8s_api_proxy_requests_unique_users_via_user_access, :k8s_api_proxy_requests_unique_agents_via_user_access,
+ :k8s_api_proxy_requests_unique_users_via_pat_access, :k8s_api_proxy_requests_unique_agents_via_pat_access,
+ :flux_git_push_notified_unique_projects
+ )
+
+ events&.each do |event, entity_ids|
+ increment_unique_values(event, entity_ids)
+ end
+ end
+
+ def increment_count_events
+ events = params[:counters]&.slice(
+ :gitops_sync, :k8s_api_proxy_request, :flux_git_push_notifications_total,
+ :k8s_api_proxy_requests_via_ci_access, :k8s_api_proxy_requests_via_user_access,
+ :k8s_api_proxy_requests_via_pat_access
+ )
+
+ Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(events)
+ end
+
+ def update_configuration(agent:, config:)
+ ::Clusters::Agents::Authorizations::CiAccess::RefreshService.new(agent, config: config).execute
+ ::Clusters::Agents::Authorizations::UserAccess::RefreshService.new(agent, config: config).execute
+ end
+
+ def retrieve_user_from_session_cookie
+ # Load session
+ public_session_id_string =
+ begin
+ Gitlab::Kas::UserAccess.decrypt_public_session_id(params[:access_key])
+ rescue StandardError
+ bad_request!('Invalid access_key')
+ end
+
+ session_id = Rack::Session::SessionId.new(public_session_id_string)
+ session = ActiveSession.sessions_from_ids([session_id.private_id]).first
+ unauthorized!('Invalid session') unless session
+
+ # CSRF check
+ unless ::Gitlab::Kas::UserAccess.valid_authenticity_token?(session.symbolize_keys, params[:csrf_token])
+ unauthorized!('CSRF token does not match')
+ end
+
+ # Load user
+ user = Warden::SessionSerializer.new('rack.session' => session).fetch(:user)
+ unauthorized!('Invalid user in session') unless user
+ user
+ end
+
+ def retrieve_user_from_personal_access_token
+ return unless access_token.present?
+
+ validate_access_token!(scopes: [Gitlab::Auth::K8S_PROXY_SCOPE])
+
+ ::PersonalAccessTokens::LastUsedService.new(access_token).execute
+
+ access_token.user || raise(UnauthorizedError)
+ end
+
+ def access_token
+ return unless params[:access_key].present?
+
+ PersonalAccessToken.find_by_token(params[:access_key])
+ end
+ strong_memoize_attr :access_token
+ end
+ end
+ end
+end
diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb
index 4b5335840f6..5219c244968 100644
--- a/lib/api/helpers/notes_helpers.rb
+++ b/lib/api/helpers/notes_helpers.rb
@@ -102,7 +102,7 @@ module API
def finder_params_by_noteable_type_and_id(type, id)
target_type = type.name.underscore
{ target_type: target_type }.tap do |h|
- if %w(issue merge_request).include?(target_type)
+ if %w[issue merge_request].include?(target_type)
h[:target_iid] = id
else
h[:target_id] = id
diff --git a/lib/api/helpers/packages/maven.rb b/lib/api/helpers/packages/maven.rb
index 694a1ec6436..71d1ba486ed 100644
--- a/lib/api/helpers/packages/maven.rb
+++ b/lib/api/helpers/packages/maven.rb
@@ -16,6 +16,66 @@ module API
desc: 'Package file name',
documentation: { example: 'mypkg-1.0-SNAPSHOT.jar' }
end
+
+ def extract_format(file_name)
+ name, _, format = file_name.rpartition('.')
+
+ if %w[md5 sha1].include?(format)
+ unprocessable_entity! if Gitlab::FIPS.enabled? && format == 'md5'
+
+ [name, format]
+ else
+ [file_name, format]
+ end
+ end
+
+ def fetch_package(file_name:, project: nil, group: nil)
+ order_by_package_file = file_name.include?(::Packages::Maven::Metadata.filename) &&
+ params[:path].exclude?(::Packages::Maven::FindOrCreatePackageService::SNAPSHOT_TERM)
+
+ ::Packages::Maven::PackageFinder.new(
+ current_user,
+ project || group,
+ path: params[:path],
+ order_by_package_file: order_by_package_file
+ ).execute
+ end
+
+ def project
+ nil
+ end
+
+ def group
+ nil
+ end
+
+ def present_carrierwave_file_with_head_support!(package_file, supports_direct_download: true)
+ package_file.package.touch_last_downloaded_at
+ file = package_file.file
+
+ if head_request_on_aws_file?(file, supports_direct_download) && !file.file_storage?
+ return redirect(signed_head_url(file))
+ end
+
+ present_carrierwave_file!(file, supports_direct_download: supports_direct_download)
+ end
+
+ def signed_head_url(file)
+ fog_storage = ::Fog::Storage.new(file.fog_credentials)
+ fog_dir = fog_storage.directories.new(key: file.fog_directory)
+ fog_file = fog_dir.files.new(key: file.path)
+ expire_at = ::Fog::Time.now + file.fog_authenticated_url_expiration
+
+ fog_file.collection.head_url(fog_file.key, expire_at)
+ end
+
+ def head_request_on_aws_file?(file, supports_direct_download)
+ Gitlab.config.packages.object_store.enabled &&
+ supports_direct_download &&
+ file.class.direct_download_enabled? &&
+ request.head? &&
+ file.fog_credentials[:provider] == 'AWS'
+ end
end
end
end
diff --git a/lib/api/helpers/packages_helpers.rb b/lib/api/helpers/packages_helpers.rb
index f3b3a299204..6529bb43993 100644
--- a/lib/api/helpers/packages_helpers.rb
+++ b/lib/api/helpers/packages_helpers.rb
@@ -118,10 +118,7 @@ module API
def track_snowplow_event(action_name, category, args)
event_name = "i_package_#{action_name}"
key_path = "counts.package_events_i_package_#{action_name}"
- service_ping_context = Gitlab::Tracking::ServicePingContext.new(
- data_source: :redis,
- key_path: key_path
- ).to_context
+ service_ping_context = Gitlab::Usage::MetricDefinition.context_for(key_path).to_context
Gitlab::Tracking.event(
category,
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index 699d3f360d9..8a0ec1c1abf 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -10,9 +10,9 @@ module API
params :optional_project_params_ce do
optional :description, type: String, desc: 'The description of the project'
- optional :build_git_strategy, type: String, values: %w(fetch clone), desc: 'The Git strategy. Defaults to `fetch`'
+ optional :build_git_strategy, type: String, values: %w[fetch clone], desc: 'The Git strategy. Defaults to `fetch`'
optional :build_timeout, type: Integer, desc: 'Build timeout'
- optional :auto_cancel_pending_pipelines, type: String, values: %w(disabled enabled), desc: 'Auto-cancel pending pipelines'
+ optional :auto_cancel_pending_pipelines, type: String, values: %w[disabled enabled], desc: 'Auto-cancel pending pipelines'
optional :ci_config_path, type: String, desc: 'The path to CI config file. Defaults to `.gitlab-ci.yml`'
optional :service_desk_enabled, type: Boolean, desc: 'Disable or enable the service desk'
@@ -23,22 +23,22 @@ module API
optional :jobs_enabled, type: Boolean, desc: 'Flag indication if jobs are enabled'
optional :snippets_enabled, type: Boolean, desc: 'Flag indication if snippets are enabled'
- optional :issues_access_level, type: String, values: %w(disabled private enabled), desc: 'Issues access level. One of `disabled`, `private` or `enabled`'
- optional :repository_access_level, type: String, values: %w(disabled private enabled), desc: 'Repository access level. One of `disabled`, `private` or `enabled`'
- optional :merge_requests_access_level, type: String, values: %w(disabled private enabled), desc: 'Merge requests access level. One of `disabled`, `private` or `enabled`'
- optional :forking_access_level, type: String, values: %w(disabled private enabled), desc: 'Forks access level. One of `disabled`, `private` or `enabled`'
- optional :wiki_access_level, type: String, values: %w(disabled private enabled), desc: 'Wiki access level. One of `disabled`, `private` or `enabled`'
- optional :builds_access_level, type: String, values: %w(disabled private enabled), desc: 'Builds access level. One of `disabled`, `private` or `enabled`'
- optional :snippets_access_level, type: String, values: %w(disabled private enabled), desc: 'Snippets access level. One of `disabled`, `private` or `enabled`'
- optional :pages_access_level, type: String, values: %w(disabled private enabled public), desc: 'Pages access level. One of `disabled`, `private`, `enabled` or `public`'
- optional :analytics_access_level, type: String, values: %w(disabled private enabled), desc: 'Analytics access level. One of `disabled`, `private` or `enabled`'
- optional :container_registry_access_level, type: String, values: %w(disabled private enabled), desc: 'Controls visibility of the container registry. One of `disabled`, `private` or `enabled`. `private` will make the container registry accessible only to project members (reporter role and above). `enabled` will make the container registry accessible to everyone who has access to the project. `disabled` will disable the container registry'
- optional :security_and_compliance_access_level, type: String, values: %w(disabled private enabled), desc: 'Security and compliance access level. One of `disabled`, `private` or `enabled`'
- optional :releases_access_level, type: String, values: %w(disabled private enabled), desc: 'Releases access level. One of `disabled`, `private` or `enabled`'
- optional :environments_access_level, type: String, values: %w(disabled private enabled), desc: 'Environments access level. One of `disabled`, `private` or `enabled`'
- optional :feature_flags_access_level, type: String, values: %w(disabled private enabled), desc: 'Feature flags access level. One of `disabled`, `private` or `enabled`'
- optional :infrastructure_access_level, type: String, values: %w(disabled private enabled), desc: 'Infrastructure access level. One of `disabled`, `private` or `enabled`'
- optional :monitor_access_level, type: String, values: %w(disabled private enabled), desc: 'Monitor access level. One of `disabled`, `private` or `enabled`'
+ optional :issues_access_level, type: String, values: %w[disabled private enabled], desc: 'Issues access level. One of `disabled`, `private` or `enabled`'
+ optional :repository_access_level, type: String, values: %w[disabled private enabled], desc: 'Repository access level. One of `disabled`, `private` or `enabled`'
+ optional :merge_requests_access_level, type: String, values: %w[disabled private enabled], desc: 'Merge requests access level. One of `disabled`, `private` or `enabled`'
+ optional :forking_access_level, type: String, values: %w[disabled private enabled], desc: 'Forks access level. One of `disabled`, `private` or `enabled`'
+ optional :wiki_access_level, type: String, values: %w[disabled private enabled], desc: 'Wiki access level. One of `disabled`, `private` or `enabled`'
+ optional :builds_access_level, type: String, values: %w[disabled private enabled], desc: 'Builds access level. One of `disabled`, `private` or `enabled`'
+ optional :snippets_access_level, type: String, values: %w[disabled private enabled], desc: 'Snippets access level. One of `disabled`, `private` or `enabled`'
+ optional :pages_access_level, type: String, values: %w[disabled private enabled public], desc: 'Pages access level. One of `disabled`, `private`, `enabled` or `public`'
+ optional :analytics_access_level, type: String, values: %w[disabled private enabled], desc: 'Analytics access level. One of `disabled`, `private` or `enabled`'
+ optional :container_registry_access_level, type: String, values: %w[disabled private enabled], desc: 'Controls visibility of the container registry. One of `disabled`, `private` or `enabled`. `private` will make the container registry accessible only to project members (reporter role and above). `enabled` will make the container registry accessible to everyone who has access to the project. `disabled` will disable the container registry'
+ optional :security_and_compliance_access_level, type: String, values: %w[disabled private enabled], desc: 'Security and compliance access level. One of `disabled`, `private` or `enabled`'
+ optional :releases_access_level, type: String, values: %w[disabled private enabled], desc: 'Releases access level. One of `disabled`, `private` or `enabled`'
+ optional :environments_access_level, type: String, values: %w[disabled private enabled], desc: 'Environments access level. One of `disabled`, `private` or `enabled`'
+ optional :feature_flags_access_level, type: String, values: %w[disabled private enabled], desc: 'Feature flags access level. One of `disabled`, `private` or `enabled`'
+ optional :infrastructure_access_level, type: String, values: %w[disabled private enabled], desc: 'Infrastructure access level. One of `disabled`, `private` or `enabled`'
+ optional :monitor_access_level, type: String, values: %w[disabled private enabled], desc: 'Monitor access level. One of `disabled`, `private` or `enabled`'
optional :emails_disabled, type: Boolean, desc: 'Deprecated: Use emails_enabled instead.'
optional :emails_enabled, type: Boolean, desc: 'Enable email notifications'
@@ -65,18 +65,18 @@ module API
optional :topics, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of topics for a project'
optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for project', documentation: { type: 'file' }
optional :printing_merge_request_link_enabled, type: Boolean, desc: 'Show link to create/view merge request when pushing from the command line'
- optional :merge_method, type: String, values: %w(ff rebase_merge merge), desc: 'The merge method used when merging merge requests'
+ optional :merge_method, type: String, values: %w[ff rebase_merge merge], desc: 'The merge method used when merging merge requests'
optional :suggestion_commit_message, type: String, desc: 'The commit message used to apply merge request suggestions'
optional :merge_commit_template, type: String, desc: 'Template used to create merge commit message'
optional :squash_commit_template, type: String, desc: 'Template used to create squash commit message'
optional :issue_branch_template, type: String, desc: 'Template used to create a branch from an issue'
optional :initialize_with_readme, type: Boolean, desc: "Initialize a project with a README.md"
optional :auto_devops_enabled, type: Boolean, desc: 'Flag indication if Auto DevOps is enabled'
- optional :auto_devops_deploy_strategy, type: String, values: %w(continuous manual timed_incremental), desc: 'Auto Deploy strategy'
+ optional :auto_devops_deploy_strategy, type: String, values: %w[continuous manual timed_incremental], desc: 'Auto Deploy strategy'
optional :autoclose_referenced_issues, type: Boolean, desc: 'Flag indication if referenced issues auto-closing is enabled'
optional :repository_storage, type: String, desc: 'Which storage shard the repository is on. Available only to admins'
optional :packages_enabled, type: Boolean, desc: 'Enable project packages feature'
- optional :squash_option, type: String, values: %w(never always default_on default_off), desc: 'Squash default for project. One of `never`, `always`, `default_on`, or `default_off`.'
+ optional :squash_option, type: String, values: %w[never always default_on default_off], desc: 'Squash default for project. One of `never`, `always`, `default_on`, or `default_off`.'
optional :mr_default_target_self, type: Boolean, desc: 'Merge requests of this forked project targets itself by default'
end
diff --git a/lib/api/helpers/search_helpers.rb b/lib/api/helpers/search_helpers.rb
index 66321306496..3c1d4dfac49 100644
--- a/lib/api/helpers/search_helpers.rb
+++ b/lib/api/helpers/search_helpers.rb
@@ -5,21 +5,21 @@ module API
module SearchHelpers
def self.global_search_scopes
# This is a separate method so that EE can redefine it.
- %w(projects issues merge_requests milestones snippet_titles users)
+ %w[projects issues merge_requests milestones snippet_titles users]
end
def self.group_search_scopes
# This is a separate method so that EE can redefine it.
- %w(projects issues merge_requests milestones users)
+ %w[projects issues merge_requests milestones users]
end
def self.project_search_scopes
# This is a separate method so that EE can redefine it.
- %w(issues merge_requests milestones notes wiki_blobs commits blobs users)
+ %w[issues merge_requests milestones notes wiki_blobs commits blobs users]
end
def self.search_states
- %w(all opened closed merged)
+ %w[all opened closed merged]
end
end
end
diff --git a/lib/api/integrations.rb b/lib/api/integrations.rb
index 3ec0a723808..a73e34f54a3 100644
--- a/lib/api/integrations.rb
+++ b/lib/api/integrations.rb
@@ -31,7 +31,7 @@ module API
INTEGRATIONS[integration.to_param.tr("_", "-")] << {
required: false,
name: event_name.to_sym,
- type: String,
+ type: ::Grape::API::Boolean,
desc: IntegrationsHelper.integration_event_description(integration, event_name)
}
end
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index 8783a8dd57c..a88c8b69b81 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -4,81 +4,12 @@ module API
# Kubernetes Internal API
module Internal
class Kubernetes < ::API::Base
- include Gitlab::Utils::StrongMemoize
-
before do
check_feature_enabled
authenticate_gitlab_kas_request!
end
- helpers do
- def authenticate_gitlab_kas_request!
- render_api_error!('KAS JWT authentication invalid', 401) unless Gitlab::Kas.verify_api_request(headers)
- end
-
- def agent_token
- @agent_token ||= cluster_agent_token_from_authorization_token
- end
-
- def agent
- @agent ||= agent_token.agent
- end
-
- def repo_type
- Gitlab::GlRepository::PROJECT
- end
-
- def gitaly_info(project)
- gitaly_features = Feature::Gitaly.server_feature_flags
-
- Gitlab::GitalyClient.connection_data(project.repository_storage).merge(features: gitaly_features)
- end
-
- def gitaly_repository(project)
- project.repository.gitaly_repository.to_h
- end
-
- def check_feature_enabled
- not_found!('Internal API not found') unless Feature.enabled?(:kubernetes_agent_internal_api, type: :ops)
- end
-
- def check_agent_token
- unauthorized! unless agent_token
-
- ::Clusters::AgentTokens::TrackUsageService.new(agent_token).execute
- end
-
- def agent_has_access_to_project?(project)
- Guest.can?(:download_code, project) || agent.has_access_to?(project)
- end
-
- def increment_unique_events
- events = params[:unique_counters]&.slice(
- :agent_users_using_ci_tunnel,
- :k8s_api_proxy_requests_unique_users_via_ci_access, :k8s_api_proxy_requests_unique_agents_via_ci_access,
- :k8s_api_proxy_requests_unique_users_via_user_access, :k8s_api_proxy_requests_unique_agents_via_user_access,
- :flux_git_push_notified_unique_projects
- )
-
- events&.each do |event, entity_ids|
- increment_unique_values(event, entity_ids)
- end
- end
-
- def increment_count_events
- events = params[:counters]&.slice(
- :gitops_sync, :k8s_api_proxy_request, :flux_git_push_notifications_total,
- :k8s_api_proxy_requests_via_ci_access, :k8s_api_proxy_requests_via_user_access
- )
-
- Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(events)
- end
-
- def update_configuration(agent:, config:)
- ::Clusters::Agents::Authorizations::CiAccess::RefreshService.new(agent, config: config).execute
- ::Clusters::Agents::Authorizations::UserAccess::RefreshService.new(agent, config: config).execute
- end
- end
+ helpers ::API::Helpers::Kubernetes::AgentHelpers
namespace 'internal' do
namespace 'kubernetes' do
@@ -155,33 +86,23 @@ module API
desc 'Authorize a proxy user request'
params do
requires :agent_id, type: Integer, desc: 'ID of the agent accessed'
- requires :access_type, type: String, values: ['session_cookie'], desc: 'The type of the access key being verified.'
+ requires :access_type, type: String, values: %w[session_cookie personal_access_token], desc: 'The type of access key being verified.'
requires :access_key, type: String, desc: 'The authentication secret for the given access type.'
given access_type: ->(val) { val == 'session_cookie' } do
requires :csrf_token, type: String, allow_blank: false, desc: 'CSRF token that must be checked when access_type is "session_cookie", to ensure the request originates from a GitLab browsing session.'
end
end
post '/', feature_category: :deployment_management do
- # Load session
- public_session_id_string =
- begin
- Gitlab::Kas::UserAccess.decrypt_public_session_id(params[:access_key])
- rescue StandardError
- bad_request!('Invalid access_key')
- end
-
- session_id = Rack::Session::SessionId.new(public_session_id_string)
- session = ActiveSession.sessions_from_ids([session_id.private_id]).first
- unauthorized!('Invalid session') unless session
-
- # CSRF check
- unless ::Gitlab::Kas::UserAccess.valid_authenticity_token?(session.symbolize_keys, params[:csrf_token])
- unauthorized!('CSRF token does not match')
- end
-
# Load user
- user = Warden::SessionSerializer.new('rack.session' => session).fetch(:user)
- unauthorized!('Invalid user in session') unless user
+ user = if params[:access_type] == 'session_cookie'
+ retrieve_user_from_session_cookie
+ elsif params[:access_type] == 'personal_access_token'
+ u = retrieve_user_from_personal_access_token
+ bad_request!('PAT authentication is not enabled') unless Feature.enabled?(:k8s_proxy_pat, u)
+ u
+ end
+
+ bad_request!('Unable to get user from request data') if user.nil?
# Load agent
agent = ::Clusters::Agent.find(params[:agent_id])
@@ -205,6 +126,7 @@ module API
optional :flux_git_push_notifications_total, type: Integer, desc: 'The count to increment the flux_git_push_notifications_total metrics by'
optional :k8s_api_proxy_requests_via_ci_access, type: Integer, desc: 'The count to increment the k8s_api_proxy_requests_via_ci_access metric by'
optional :k8s_api_proxy_requests_via_user_access, type: Integer, desc: 'The count to increment the k8s_api_proxy_requests_via_user_access metric by'
+ optional :k8s_api_proxy_requests_via_pat_access, type: Integer, desc: 'The count to increment the k8s_api_proxy_requests_via_pat_access metric by'
end
optional :unique_counters, type: Hash do
@@ -213,6 +135,8 @@ module API
optional :k8s_api_proxy_requests_unique_agents_via_ci_access, type: Array[Integer], desc: 'An array of agents that have interacted with the CI tunnel via `ci_access`'
optional :k8s_api_proxy_requests_unique_users_via_user_access, type: Array[Integer], desc: 'An array of users that have interacted with the CI tunnel via `user_access`'
optional :k8s_api_proxy_requests_unique_agents_via_user_access, type: Array[Integer], desc: 'An array of agents that have interacted with the CI tunnel via `user_access`'
+ optional :k8s_api_proxy_requests_unique_users_via_pat_access, type: Array[Integer], desc: 'An array of users that have interacted with the CI tunnel via Personal Access Token'
+ optional :k8s_api_proxy_requests_unique_agents_via_pat_access, type: Array[Integer], desc: 'An array of agents that have interacted with the CI tunnel via Personal Access Token'
optional :flux_git_push_notified_unique_projects, type: Array[Integer], desc: 'An array of projects that have been notified to reconcile their Flux workloads'
end
end
diff --git a/lib/api/internal/pages.rb b/lib/api/internal/pages.rb
index 5664a3df589..971b76279a1 100644
--- a/lib/api/internal/pages.rb
+++ b/lib/api/internal/pages.rb
@@ -36,16 +36,7 @@ module API
virtual_domain = ::Gitlab::Pages::VirtualHostFinder.new(params[:host]).execute
no_content! unless virtual_domain
- if virtual_domain.cache_key.present?
- # Cache context is not added to make it easier to expire the cache with
- # Gitlab::Pages::CacheControl
- present_cached virtual_domain,
- cache_context: nil,
- with: Entities::Internal::Pages::VirtualDomain,
- expires_in: ::Gitlab::Pages::CacheControl::EXPIRE
- else
- present virtual_domain, with: Entities::Internal::Pages::VirtualDomain
- end
+ present virtual_domain, with: Entities::Internal::Pages::VirtualDomain
end
end
end
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index eccc55ed158..517de98a148 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -34,18 +34,6 @@ module API
.exists?
end
- def extract_format(file_name)
- name, _, format = file_name.rpartition('.')
-
- if %w(md5 sha1).include?(format)
- unprocessable_entity! if Gitlab::FIPS.enabled? && format == 'md5'
-
- [name, format]
- else
- [file_name, format]
- end
- end
-
# The sha verification done by the maven api is between:
# - the sha256 set by workhorse helpers
# - the sha256 of the sha1 of the uploaded package file
@@ -69,46 +57,6 @@ module API
format == 'jar'
end
- def present_carrierwave_file_with_head_support!(package_file, supports_direct_download: true)
- package_file.package.touch_last_downloaded_at
- file = package_file.file
-
- if head_request_on_aws_file?(file, supports_direct_download) && !file.file_storage?
- return redirect(signed_head_url(file))
- end
-
- present_carrierwave_file!(file, supports_direct_download: supports_direct_download)
- end
-
- def signed_head_url(file)
- fog_storage = ::Fog::Storage.new(file.fog_credentials)
- fog_dir = fog_storage.directories.new(key: file.fog_directory)
- fog_file = fog_dir.files.new(key: file.path)
- expire_at = ::Fog::Time.now + file.fog_authenticated_url_expiration
-
- fog_file.collection.head_url(fog_file.key, expire_at)
- end
-
- def head_request_on_aws_file?(file, supports_direct_download)
- Gitlab.config.packages.object_store.enabled &&
- supports_direct_download &&
- file.class.direct_download_enabled? &&
- request.head? &&
- file.fog_credentials[:provider] == 'AWS'
- end
-
- def fetch_package(file_name:, project: nil, group: nil)
- order_by_package_file = file_name.include?(::Packages::Maven::Metadata.filename) &&
- !params[:path].include?(::Packages::Maven::FindOrCreatePackageService::SNAPSHOT_TERM)
-
- ::Packages::Maven::PackageFinder.new(
- current_user,
- project || group,
- path: params[:path],
- order_by_package_file: order_by_package_file
- ).execute
- end
-
def find_and_present_package_file(package, file_name, format, params)
project = package&.project
package_file = nil
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 03b9ee03b46..1c0b9c56aa7 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -182,7 +182,7 @@ module API
merge_requests = find_merge_requests(group_id: user_group.id, include_subgroups: true)
options = serializer_options_for(merge_requests).merge(group: user_group)
- if !options[:skip_merge_status_recheck] && ::Feature.enabled?(:batched_api_mergeability_checks, user_group)
+ unless options[:skip_merge_status_recheck]
batch_process_mergeability_checks(merge_requests)
# NOTE: skipping individual mergeability checks in the presenter
diff --git a/lib/api/metadata.rb b/lib/api/metadata.rb
index 788d9843c63..e35d22f656a 100644
--- a/lib/api/metadata.rb
+++ b/lib/api/metadata.rb
@@ -5,7 +5,7 @@ module API
helpers ::API::Helpers::GraphqlHelpers
include APIGuard
- allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
+ allow_access_with_scope [:read_user, :ai_features], if: -> (request) { request.get? || request.head? }
before { authenticate! }
diff --git a/lib/api/ml/mlflow/api_helpers.rb b/lib/api/ml/mlflow/api_helpers.rb
index 66689d8e0ca..19ac0dbba1b 100644
--- a/lib/api/ml/mlflow/api_helpers.rb
+++ b/lib/api/ml/mlflow/api_helpers.rb
@@ -4,6 +4,14 @@ module API
module Ml
module Mlflow
module ApiHelpers
+ def check_api_read!
+ not_found! unless can?(current_user, :read_model_experiments, user_project)
+ end
+
+ def check_api_write!
+ unauthorized! unless can?(current_user, :write_model_experiments, user_project)
+ end
+
def resource_not_found!
render_structured_api_error!({ error_code: 'RESOURCE_DOES_NOT_EXIST' }, 404)
end
@@ -32,6 +40,37 @@ module API
@candidate ||= find_candidate!(params[:run_id])
end
+ def candidates_order_params(params)
+ find_params = {
+ order_by: nil,
+ order_by_type: nil,
+ sort: nil
+ }
+
+ return find_params if params[:order_by].blank?
+
+ order_by_split = params[:order_by].split(' ')
+ order_by_column_split = order_by_split[0].split('.')
+ if order_by_column_split.size == 1
+ order_by_column = order_by_column_split[0]
+ order_by_column_type = 'column'
+ elsif order_by_column_split[0] == 'metrics'
+ order_by_column = order_by_column_split[1]
+ order_by_column_type = 'metric'
+ else
+ order_by_column = nil
+ order_by_column_type = nil
+ end
+
+ order_by_sort = order_by_split[1]
+
+ {
+ order_by: order_by_column,
+ order_by_type: order_by_column_type,
+ sort: order_by_sort
+ }
+ end
+
def find_experiment!(iid, name)
experiment_repository.by_iid_or_name(iid: iid, name: name) || resource_not_found!
end
diff --git a/lib/api/ml/mlflow/entrypoint.rb b/lib/api/ml/mlflow/entrypoint.rb
index 7948949dac6..3e0cb723580 100644
--- a/lib/api/ml/mlflow/entrypoint.rb
+++ b/lib/api/ml/mlflow/entrypoint.rb
@@ -27,7 +27,8 @@ module API
authenticate!
- not_found! unless can?(current_user, :read_model_experiments, user_project)
+ check_api_read!
+ check_api_write! unless request.get? || request.head?
end
rescue_from ActiveRecord::ActiveRecordError do |e|
diff --git a/lib/api/ml/mlflow/runs.rb b/lib/api/ml/mlflow/runs.rb
index f737c6bd497..5b6afffaae1 100644
--- a/lib/api/ml/mlflow/runs.rb
+++ b/lib/api/ml/mlflow/runs.rb
@@ -26,7 +26,7 @@ module API
end
post 'create', urgency: :low do
present candidate_repository.create!(experiment, params[:start_time], params[:tags], params[:run_name]),
- with: Entities::Ml::Mlflow::Run, packages_url: packages_url
+ with: Entities::Ml::Mlflow::GetRun, packages_url: packages_url
end
desc 'Gets an MLFlow Run, which maps to GitLab Candidates' do
@@ -38,7 +38,47 @@ module API
optional :run_uuid, type: String, desc: 'This parameter is ignored'
end
get 'get', urgency: :low do
- present candidate, with: Entities::Ml::Mlflow::Run, packages_url: packages_url
+ present candidate, with: Entities::Ml::Mlflow::GetRun, packages_url: packages_url
+ end
+
+ desc 'Searches runs/candidates within a project' do
+ success Entities::Ml::Mlflow::Run
+ detail 'https://www.mlflow.org/docs/1.28.0/rest-api.html#search-runs' \
+ 'experiment_ids supports only a single experiment ID.' \
+ 'Introduced in GitLab 16.4'
+ end
+ params do
+ requires :experiment_ids,
+ type: Array,
+ desc: 'IDs of the experiments to get searches from, relative to the project'
+ optional :max_results,
+ type: Integer,
+ desc: 'Maximum number of runs/candidates to fetch in a page. Default is 200, maximum in 1000',
+ default: 200
+ optional :order_by,
+ type: String,
+ desc: 'Order criteria. Can be by a column of the run/candidate (created_at, name) or by a metric if' \
+ 'prefixed by `metrics`. Valid examples: `created_at`, `created_at DESC`, `metrics.my_metric DESC`' \
+ 'Sorting by candidate parameter or metadata is not supported.',
+ default: 'created_at DESC'
+ optional :page_token,
+ type: String,
+ desc: 'Token for pagination'
+ end
+ get 'search', urgency: :low do
+ params[:experiment_id] = params[:experiment_ids][0]
+
+ max_results = [params[:max_results], 1000].min
+ finder_params = candidates_order_params(params)
+ finder = ::Projects::Ml::CandidateFinder.new(experiment, finder_params)
+ paginator = finder.execute.keyset_paginate(cursor: params[:page_token], per_page: max_results)
+
+ result = {
+ candidates: paginator.records,
+ next_page_token: paginator.cursor_for_next_page
+ }
+
+ present result, with: Entities::Ml::Mlflow::SearchRuns, packages_url: packages_url
end
desc 'Updates a Run.' do
diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb
index 8cd72d2ab15..e3d292eb2b0 100644
--- a/lib/api/notification_settings.rb
+++ b/lib/api/notification_settings.rb
@@ -39,8 +39,12 @@ module API
notification_setting.transaction do
new_notification_email = params.delete(:notification_email)
- if new_notification_email
- ::Users::UpdateService.new(current_user, user: current_user, notification_email: new_notification_email).execute
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ %w[users user_details], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424289'
+ ) do
+ if new_notification_email
+ ::Users::UpdateService.new(current_user, user: current_user, notification_email: new_notification_email).execute
+ end
end
notification_setting.update(declared_params(include_missing: false))
diff --git a/lib/api/npm_group_packages.rb b/lib/api/npm_group_packages.rb
index 1aa3135b186..f2b8e1840a1 100644
--- a/lib/api/npm_group_packages.rb
+++ b/lib/api/npm_group_packages.rb
@@ -11,6 +11,10 @@ module API
def endpoint_scope
:group
end
+
+ def group_or_namespace
+ group
+ end
end
params do
diff --git a/lib/api/npm_instance_packages.rb b/lib/api/npm_instance_packages.rb
index ea92818e76c..1805edceb2c 100644
--- a/lib/api/npm_instance_packages.rb
+++ b/lib/api/npm_instance_packages.rb
@@ -10,6 +10,10 @@ module API
def endpoint_scope
:instance
end
+
+ def group_or_namespace
+ top_namespace_from(params[:package_name])
+ end
end
namespace 'packages/npm' do
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index bff645700f5..dbc789c68b6 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -84,6 +84,8 @@ module API
file_name: file_name(symbol_package)
)
+ check_duplicate(file_params, symbol_package)
+
package = ::Packages::CreateTemporaryPackageService.new(
project, current_user, declared_params.merge(build: current_authenticated_job)
).execute(:nuget, name: temp_file_name(symbol_package))
@@ -98,6 +100,14 @@ module API
created!
end
+ def check_duplicate(file_params, symbol_package)
+ return if symbol_package || Feature.disabled?(:nuget_duplicates_option, project_or_group.namespace)
+
+ service_params = file_params.merge(remote_url: params['package.remote_url'])
+ response = ::Packages::Nuget::CheckDuplicatesService.new(project_or_group, current_user, service_params).execute
+ render_api_error!(response.message, response.reason) if response.error?
+ end
+
def publish_package(symbol_package: false)
upload_nuget_package_file(symbol_package: symbol_package) do |package|
track_package_event(
@@ -119,9 +129,25 @@ module API
end
def format_filename(package)
- return "#{params[:package_filename]}.#{params[:format]}" if Feature.disabled?(:nuget_normalized_version, project_or_group) || package.version == params[:package_version]
+ return "#{params[:package_filename]}.#{params[:format]}" if package.version == params[:package_version]
return "#{params[:package_filename].sub(params[:package_version], package.version)}.#{params[:format]}" if package.normalized_nuget_version == params[:package_version]
end
+
+ def present_odata_entry
+ project = find_project(params[:project_id])
+
+ not_found! unless project
+
+ env['api.format'] = :binary
+ content_type 'application/xml; charset=utf-8'
+
+ odata_entry = ::Packages::Nuget::OdataPackageEntryService
+ .new(project, declared_params)
+ .execute
+ .payload
+
+ present odata_entry
+ end
end
params do
@@ -317,5 +343,74 @@ module API
end
end
end
+
+ params do
+ requires :project_id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project',
+ regexp: ::API::Concerns::Packages::Nuget::PrivateEndpoints::POSITIVE_INTEGER_REGEX
+ end
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ namespace ':project_id/packages/nuget/v2' do
+ # https://joelverhagen.github.io/NuGetUndocs/?http#endpoint-find-packages-by-id
+ desc 'The NuGet V2 Feed Find Packages by ID endpoint' do
+ detail 'This feature was introduced in GitLab 16.4'
+ success code: 200
+ failure [
+ { code: 404, message: 'Not Found' },
+ { code: 400, message: 'Bad Request' }
+ ]
+ tags %w[nuget_packages]
+ end
+
+ params do
+ requires :id, as: :package_name, type: String, allow_blank: false, coerce_with: ->(val) { val.delete("'") },
+ desc: 'The NuGet package name', regexp: Gitlab::Regex.nuget_package_name_regex,
+ documentation: { example: 'mynugetpkg' }
+ end
+ get 'FindPackagesById\(\)', urgency: :low do
+ present_odata_entry
+ end
+
+ # https://joelverhagen.github.io/NuGetUndocs/?http#endpoint-enumerate-packages
+ desc 'The NuGet V2 Feed Enumerate Packages endpoint' do
+ detail 'This feature was introduced in GitLab 16.4'
+ success code: 200
+ failure [
+ { code: 404, message: 'Not Found' },
+ { code: 400, message: 'Bad Request' }
+ ]
+ tags %w[nuget_packages]
+ end
+
+ params do
+ requires :$filter, as: :package_name, type: String, allow_blank: false,
+ coerce_with: ->(val) { val.match(/tolower\(Id\) eq '(.+?)'/)&.captures&.first },
+ desc: 'The NuGet package name', regexp: Gitlab::Regex.nuget_package_name_regex,
+ documentation: { example: 'mynugetpkg' }
+ end
+ get 'Packages\(\)', urgency: :low do
+ present_odata_entry
+ end
+
+ # https://joelverhagen.github.io/NuGetUndocs/?http#endpoint-get-a-single-package
+ desc 'The NuGet V2 Feed Single Package Metadata endpoint' do
+ detail 'This feature was introduced in GitLab 16.4'
+ success code: 200
+ failure [
+ { code: 404, message: 'Not Found' },
+ { code: 400, message: 'Bad Request' }
+ ]
+ tags %w[nuget_packages]
+ end
+ params do
+ requires :package_name, type: String, allow_blank: false, desc: 'The NuGet package name',
+ regexp: Gitlab::Regex.nuget_package_name_regex, documentation: { example: 'mynugetpkg' }
+ requires :package_version, type: String, allow_blank: false, desc: 'The NuGet package version',
+ regexp: Gitlab::Regex.nuget_version_regex, documentation: { example: '1.3.0.17' }
+ end
+ get 'Packages\(Id=\'*package_name\',Version=\'*package_version\'\)', urgency: :low do
+ present_odata_entry
+ end
+ end
+ end
end
end
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
index 8a72ec051dc..7467b8e564e 100644
--- a/lib/api/project_export.rb
+++ b/lib/api/project_export.rb
@@ -154,7 +154,7 @@ module API
{ code: 503, message: 'Service unavailable' }
]
tags ['project_export']
- produces %w[application/octet-stream application/json]
+ produces %w[application/octet-stream application/gzip application/json]
end
params do
requires :relation, type: String, project_portable: true, desc: 'Project relation name'
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
index c28d0ae2def..60dfc925269 100644
--- a/lib/api/project_import.rb
+++ b/lib/api/project_import.rb
@@ -10,7 +10,7 @@ module API
feature_category :importers
urgency :low
- before { authenticate! unless route.settings[:skip_authentication] }
+ before { authenticate! }
helpers do
def import_params
@@ -132,7 +132,6 @@ module API
]
tags ['project_import']
end
- route_setting :skip_authentication, true
get ':id/import' do
present user_project, with: Entities::ProjectImportStatus, current_user: current_user
end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 4131f41743f..98316bf1d4b 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -112,7 +112,7 @@ module API
optional :recursive, type: Boolean, default: false, desc: 'Used to get a recursive tree'
use :pagination
- optional :pagination, type: String, values: %w(legacy keyset none), default: 'legacy', desc: 'Specify the pagination method ("none" is only valid if "recursive" is true)'
+ optional :pagination, type: String, values: %w[legacy keyset none], default: 'legacy', desc: 'Specify the pagination method ("none" is only valid if "recursive" is true)'
given pagination: ->(value) { value == 'keyset' } do
optional :page_token, type: String,
diff --git a/lib/api/search.rb b/lib/api/search.rb
index b14fce13f5e..5f78979ec8a 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -7,7 +7,8 @@ module API
before do
authenticate!
- check_rate_limit!(:search_rate_limit, scope: [current_user])
+ check_rate_limit!(:search_rate_limit, scope: [current_user],
+ users_allowlist: Gitlab::CurrentSettings.current_application_settings.search_rate_limit_allowlist)
end
feature_category :global_search
@@ -102,7 +103,7 @@ module API
end
def snippets?
- %w(snippet_titles).include?(params[:scope]).to_s
+ %w[snippet_titles].include?(params[:scope]).to_s
end
def entity
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index e2dc78fe84a..9616efbfe37 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -45,6 +45,7 @@ module API
optional :asset_proxy_whitelist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Deprecated: Use :asset_proxy_allowlist instead. Assets that match these domain(s) will NOT be proxied. Wildcards allowed. Your GitLab installation URL is automatically whitelisted.'
optional :asset_proxy_allowlist, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Assets that match these domain(s) will NOT be proxied. Wildcards allowed. Your GitLab installation URL is automatically allowed.'
optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)'
+ optional :decompress_archive_file_timeout, type: Integer, desc: 'Default timeout for decompressing archived files, in seconds. Set to 0 to disable timeouts.'
optional :default_artifacts_expire_in, type: String, desc: "Set the default expiration time for each job's artifacts"
optional :default_ci_config_path, type: String, desc: 'The instance default CI/CD configuration file and path for new projects'
optional :default_project_creation, type: Integer, values: ::Gitlab::Access.project_creation_values, desc: 'Determine if developers can create projects in the group'
@@ -109,7 +110,6 @@ module API
optional :import_sources, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce,
values: %w[github bitbucket bitbucket_server fogbugz git gitlab_project gitea manifest],
desc: 'Enabled sources for code import during project creation. OmniAuth must be configured for GitHub, Bitbucket, and GitLab.com'
- optional :in_product_marketing_emails_enabled, type: Boolean, desc: 'By default, in-product marketing emails are enabled. To disable these emails, disable this option.'
optional :invisible_captcha_enabled, type: Boolean, desc: 'Enable Invisible Captcha spam detection during signup.'
optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts"
optional :max_attachment_size, type: Integer, desc: 'Maximum attachment size in MB'
diff --git a/lib/api/users.rb b/lib/api/users.rb
index fff0e9fee06..a01ace3a9c3 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -141,7 +141,11 @@ module API
users = users.preload(:user_detail)
- present paginate(users), options
+ if Feature.enabled?(:api_keyset_pagination_multi_order)
+ present paginate_with_strategies(users), options
+ else
+ present paginate(users), options
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -1021,7 +1025,7 @@ module API
# Enabling /user endpoint for the v3 version to allow oauth
# authentication through this endpoint.
- version %w(v3 v4), using: :path do
+ version %w[v3 v4], using: :path do
desc 'Get the currently authenticated user' do
success Entities::UserPublic
end
diff --git a/lib/api/validations/validators/bulk_imports.rb b/lib/api/validations/validators/bulk_imports.rb
index 67dc084cc12..77d76c98e00 100644
--- a/lib/api/validations/validators/bulk_imports.rb
+++ b/lib/api/validations/validators/bulk_imports.rb
@@ -36,7 +36,8 @@ module API
raise Grape::Exceptions::Validation.new(
params: [@scope.full_name(attr_name)],
- message: Gitlab::Regex.bulk_import_destination_namespace_path_regex_message
+ message: "must be a relative path and not include protocol, sub-domain, or domain information. " \
+ "For example, 'destination/full/path' not 'https://example.com/destination/full/path'"
)
end
end
@@ -51,7 +52,7 @@ module API
raise Grape::Exceptions::Validation.new(
params: [@scope.full_name(attr_name)],
message: "must be a relative path and not include protocol, sub-domain, or domain information. " \
- "For example, 'source/full/path' not 'https://example.com/source/full/path'" \
+ "For example, 'source/full/path' not 'https://example.com/source/full/path'"
)
end
end
diff --git a/lib/backup/database.rb b/lib/backup/database.rb
index 12656cb3702..f70a7e41862 100644
--- a/lib/backup/database.rb
+++ b/lib/backup/database.rb
@@ -27,18 +27,20 @@ module Backup
def dump(destination_dir, backup_id)
FileUtils.mkdir_p(destination_dir)
- each_database_snapshot_id do |database_name, snapshot_id|
- base_model = base_models_for_backup[database_name]
+ each_database(destination_dir) do |database_name, current_db|
+ model = current_db[:model]
+ snapshot_id = current_db[:snapshot_id]
- config = base_model.connection_db_config.configuration_hash
+ pg_env = model.config[:pg_env]
+ connection = model.connection
+ active_record_config = model.config[:activerecord]
+ pg_database = active_record_config[:database]
db_file_name = file_name(destination_dir, database_name)
FileUtils.rm_f(db_file_name)
- pg_database = config[:database]
-
progress.print "Dumping PostgreSQL database #{pg_database} ... "
- pg_env(config)
+
pgsql_args = ["--clean"] # Pass '--clean' to include 'DROP TABLE' statements in the DB dump.
pgsql_args << '--if-exists'
pgsql_args << "--snapshot=#{snapshot_id}" if snapshot_id
@@ -53,11 +55,13 @@ module Backup
end
end
- success = Backup::Dump::Postgres.new.dump(pg_database, db_file_name, pgsql_args)
+ success = with_transient_pg_env(pg_env) do
+ Backup::Dump::Postgres.new.dump(pg_database, db_file_name, pgsql_args)
+ end
- base_model.connection.rollback_transaction if snapshot_id
+ connection.rollback_transaction if snapshot_id
- raise DatabaseBackupError.new(config, db_file_name) unless success
+ raise DatabaseBackupError.new(active_record_config, db_file_name) unless success
report_success(success)
progress.flush
@@ -72,8 +76,10 @@ module Backup
override :restore
def restore(destination_dir)
- base_models_for_backup.each do |database_name, base_model|
- config = base_model.connection_db_config.configuration_hash
+ base_models_for_backup.each do |database_name, _base_model|
+ backup_model = Backup::DatabaseModel.new(database_name)
+
+ config = backup_model.config[:activerecord]
db_file_name = file_name(destination_dir, database_name)
database = config[:database]
@@ -94,21 +100,23 @@ module Backup
# hanging out from a failed upgrade
drop_tables(database_name)
- decompress_rd, decompress_wr = IO.pipe
- decompress_pid = spawn(*%w(gzip -cd), out: decompress_wr, in: db_file_name)
- decompress_wr.close
-
- status, @errors =
- case config[:adapter]
- when "postgresql" then
- progress.print "Restoring PostgreSQL database #{database} ... "
- pg_env(config)
- execute_and_track_errors(pg_restore_cmd(database), decompress_rd)
- end
- decompress_rd.close
-
- Process.waitpid(decompress_pid)
- success = $?.success? && status.success?
+ pg_env = backup_model.config[:pg_env]
+ success = with_transient_pg_env(pg_env) do
+ decompress_rd, decompress_wr = IO.pipe
+ decompress_pid = spawn(*%w[gzip -cd], out: decompress_wr, in: db_file_name)
+ decompress_wr.close
+
+ status, @errors =
+ case config[:adapter]
+ when "postgresql" then
+ progress.print "Restoring PostgreSQL database #{database} ... "
+ execute_and_track_errors(pg_restore_cmd(database), decompress_rd)
+ end
+ decompress_rd.close
+
+ Process.waitpid(decompress_pid)
+ $?.success? && status.success?
+ end
if @errors.present?
progress.print "------ BEGIN ERRORS -----\n".color(:yellow)
@@ -204,30 +212,6 @@ module Backup
end
end
- def pg_env(config)
- args = {
- username: 'PGUSER',
- host: 'PGHOST',
- port: 'PGPORT',
- password: 'PGPASSWORD',
- # SSL
- sslmode: 'PGSSLMODE',
- sslkey: 'PGSSLKEY',
- sslcert: 'PGSSLCERT',
- sslrootcert: 'PGSSLROOTCERT',
- sslcrl: 'PGSSLCRL',
- sslcompression: 'PGSSLCOMPRESSION'
- }
- args.each do |opt, arg|
- # This enables the use of different PostgreSQL settings in
- # case PgBouncer is used. PgBouncer clears the search path,
- # which wreaks havoc on Rails if connections are reused.
- override = "GITLAB_BACKUP_#{arg}"
- val = ENV[override].presence || config[opt].to_s.presence
- ENV[arg] = val if val
- end
- end
-
def report_success(success)
if success
progress.puts '[DONE]'.color(:green)
@@ -251,30 +235,45 @@ module Backup
puts_time 'done'.color(:green)
end
+ def with_transient_pg_env(extended_env)
+ ENV.merge!(extended_env)
+ result = yield
+ ENV.reject! { |k, _| extended_env.key?(k) }
+
+ result
+ end
+
def pg_restore_cmd(database)
['psql', database]
end
- def each_database_snapshot_id(&block)
- @database_to_snapshot_id = {}
+ def each_database(destination_dir, &block)
+ databases = {}
+ ::Gitlab::Database::EachDatabase.each_connection(
+ only: base_models_for_backup.keys, include_shared: false
+ ) do |_connection, name|
+ next if databases[name]
+
+ backup_model = Backup::DatabaseModel.new(name)
- if @database_to_snapshot_id.empty?
- ::Gitlab::Database::EachDatabase.each_connection(
- only: base_models_for_backup.keys, include_shared: false
- ) do |connection, database_name|
- @database_to_snapshot_id[database_name] = nil
+ databases[name] = {
+ model: backup_model
+ }
- next unless Gitlab::Database.database_mode == Gitlab::Database::MODE_MULTIPLE_DATABASES
+ next unless Gitlab::Database.database_mode == Gitlab::Database::MODE_MULTIPLE_DATABASES
- Gitlab::Database::TransactionTimeoutSettings.new(connection).disable_timeouts
+ connection = backup_model.connection
+ begin
+ Gitlab::Database::TransactionTimeoutSettings.new(connection).disable_timeouts
connection.begin_transaction(isolation: :repeatable_read)
-
- @database_to_snapshot_id[database_name] = connection.select_value("SELECT pg_export_snapshot()")
+ databases[name][:snapshot_id] = connection.select_value("SELECT pg_export_snapshot()")
+ rescue ActiveRecord::ConnectionNotEstablished
+ raise Backup::DatabaseBackupError.new(backup_model.config[:activerecord], file_name(destination_dir, name))
end
end
- @database_to_snapshot_id.each(&block)
+ databases.each(&block)
end
end
end
diff --git a/lib/backup/database_model.rb b/lib/backup/database_model.rb
new file mode 100644
index 00000000000..6129a3ce891
--- /dev/null
+++ b/lib/backup/database_model.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module Backup
+ class DatabaseModel
+ SUPPORTED_OVERRIDES = {
+ username: 'PGUSER',
+ host: 'PGHOST',
+ port: 'PGPORT',
+ password: 'PGPASSWORD',
+ # SSL
+ sslmode: 'PGSSLMODE',
+ sslkey: 'PGSSLKEY',
+ sslcert: 'PGSSLCERT',
+ sslrootcert: 'PGSSLROOTCERT',
+ sslcrl: 'PGSSLCRL',
+ sslcompression: 'PGSSLCOMPRESSION'
+ }.freeze
+
+ attr_reader :config
+
+ def initialize(name)
+ configure_model(name)
+ end
+
+ def connection
+ @model.connection
+ end
+
+ private
+
+ def configure_model(name)
+ source_model = Gitlab::Database.database_base_models_with_gitlab_shared[name]
+
+ @model = backup_model_for(name)
+
+ original_config = source_model.connection_db_config.configuration_hash.dup
+
+ @config = config_for_backup(original_config)
+
+ @model.establish_connection(
+ ActiveRecord::DatabaseConfigurations::HashConfig.new(
+ source_model.connection_db_config.env_name,
+ name.to_s,
+ original_config.merge(@config[:activerecord])
+ )
+ )
+
+ Gitlab::Database::LoadBalancing::Setup.new(@model).setup
+ end
+
+ def backup_model_for(name)
+ klass_name = name.camelize
+
+ return "#{self.class.name}::#{klass_name}".constantize if self.class.const_defined?(klass_name.to_sym, false)
+
+ self.class.const_set(klass_name, Class.new(ApplicationRecord))
+ end
+
+ def config_for_backup(config)
+ db_config = {
+ activerecord: config,
+ pg_env: {}
+ }
+ SUPPORTED_OVERRIDES.each do |opt, arg|
+ # This enables the use of different PostgreSQL settings in
+ # case PgBouncer is used. PgBouncer clears the search path,
+ # which wreaks havoc on Rails if connections are reused.
+ override = "GITLAB_BACKUP_#{arg}"
+ val = ENV[override].presence || config[opt].to_s.presence
+
+ next unless val
+
+ db_config[:pg_env][arg] = val
+ db_config[:activerecord][opt] = val
+ end
+
+ db_config
+ end
+ end
+end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index 60239781926..2cded4a55bb 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -484,7 +484,7 @@ module Backup
puts_time 'Unpacking backup ... '.color(:blue)
- if Kernel.system(*%W(tar -xf #{tar_file}))
+ if Kernel.system(*%W[tar -xf #{tar_file}])
puts_time 'Unpacking backup ... '.color(:blue) + 'done'.color(:green)
else
puts_time 'Unpacking backup failed'.color(:red)
@@ -494,7 +494,7 @@ module Backup
end
def tar_version
- tar_version, _ = Gitlab::Popen.popen(%w(tar --version))
+ tar_version, _ = Gitlab::Popen.popen(%w[tar --version])
tar_version.dup.force_encoding('locale').split("\n").first
end
diff --git a/lib/backup/repositories.rb b/lib/backup/repositories.rb
index 199da8821d9..3b1547148d8 100644
--- a/lib/backup/repositories.rb
+++ b/lib/backup/repositories.rb
@@ -73,7 +73,10 @@ module Backup
def enqueue_project(project)
strategy.enqueue(project, Gitlab::GlRepository::PROJECT)
strategy.enqueue(project, Gitlab::GlRepository::WIKI)
- strategy.enqueue(project, Gitlab::GlRepository::DESIGN)
+
+ return unless project.design_management_repository
+
+ strategy.enqueue(project.design_management_repository, Gitlab::GlRepository::DESIGN)
end
def enqueue_snippet(snippet)
diff --git a/lib/banzai/filter/ascii_doc_sanitization_filter.rb b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
index 67f5baf4635..4158aa8a5ec 100644
--- a/lib/banzai/filter/ascii_doc_sanitization_filter.rb
+++ b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
@@ -8,7 +8,7 @@ module Banzai
class AsciiDocSanitizationFilter < Banzai::Filter::BaseSanitizationFilter
# Anchor link prefixed by "user-content-" pattern
PREFIXED_ID_PATTERN = /\A#{Gitlab::Asciidoc::DEFAULT_ADOC_ATTRS['idprefix']}(:?[[:alnum:]]|-|_)+\z/.freeze
- SECTION_HEADINGS = %w(h2 h3 h4 h5 h6).freeze
+ SECTION_HEADINGS = %w[h2 h3 h4 h5 h6].freeze
# Footnote link patterns
FOOTNOTE_LINK_ID_PATTERNS = {
@@ -17,18 +17,18 @@ module Banzai
}.freeze
# Classes used by Asciidoctor to style components
- ADMONITION_CLASSES = %w(fa icon-note icon-tip icon-warning icon-caution icon-important).freeze
- ALIGNMENT_BUILTINS_CLASSES = %w(text-center text-left text-right text-justify).freeze
+ ADMONITION_CLASSES = %w[fa icon-note icon-tip icon-warning icon-caution icon-important].freeze
+ ALIGNMENT_BUILTINS_CLASSES = %w[text-center text-left text-right text-justify].freeze
CALLOUT_CLASSES = ['conum'].freeze
- CHECKLIST_CLASSES = %w(fa fa-check-square-o fa-square-o).freeze
- LIST_CLASSES = %w(checklist none no-bullet unnumbered unstyled).freeze
+ CHECKLIST_CLASSES = %w[fa fa-check-square-o fa-square-o].freeze
+ LIST_CLASSES = %w[checklist none no-bullet unnumbered unstyled].freeze
- TABLE_FRAME_CLASSES = %w(frame-all frame-topbot frame-sides frame-ends frame-none).freeze
- TABLE_GRID_CLASSES = %w(grid-all grid-rows grid-cols grid-none).freeze
- TABLE_STRIPES_CLASSES = %w(stripes-all stripes-odd stripes-even stripes-hover stripes-none).freeze
+ TABLE_FRAME_CLASSES = %w[frame-all frame-topbot frame-sides frame-ends frame-none].freeze
+ TABLE_GRID_CLASSES = %w[grid-all grid-rows grid-cols grid-none].freeze
+ TABLE_STRIPES_CLASSES = %w[stripes-all stripes-odd stripes-even stripes-hover stripes-none].freeze
ELEMENT_CLASSES_ALLOWLIST = {
- span: %w(big small underline overline line-through).freeze,
+ span: %w[big small underline overline line-through].freeze,
div: ALIGNMENT_BUILTINS_CLASSES + ['admonitionblock'].freeze,
td: ['icon'].freeze,
i: ADMONITION_CLASSES + CALLOUT_CLASSES + CHECKLIST_CLASSES,
@@ -44,14 +44,14 @@ module Banzai
# Allow any classes in `span`, `i`, `div`, `td`, `ul`, `ol` and `a` elements
# but then remove any unknown classes
- allowlist[:attributes]['span'] = %w(class)
+ allowlist[:attributes]['span'] = %w[class]
allowlist[:attributes]['div'].push('class')
- allowlist[:attributes]['td'] = %w(class)
- allowlist[:attributes]['i'] = %w(class)
- allowlist[:attributes]['ul'] = %w(class)
- allowlist[:attributes]['ol'] = %w(class)
+ allowlist[:attributes]['td'] = %w[class]
+ allowlist[:attributes]['i'] = %w[class]
+ allowlist[:attributes]['ul'] = %w[class]
+ allowlist[:attributes]['ol'] = %w[class]
allowlist[:attributes]['a'].push('class')
- allowlist[:attributes]['table'] = %w(class)
+ allowlist[:attributes]['table'] = %w[class]
allowlist[:transformers].push(self.class.remove_element_classes)
# Allow `id` in anchor and footnote elements
@@ -60,7 +60,7 @@ module Banzai
# Allow `id` in heading elements for section anchors
SECTION_HEADINGS.each do |header|
- allowlist[:attributes][header] = %w(id)
+ allowlist[:attributes][header] = %w[id]
end
# Remove ids that are not explicitly allowed
diff --git a/lib/banzai/filter/autolink_filter.rb b/lib/banzai/filter/autolink_filter.rb
index bbddaa37380..e877e5f316c 100644
--- a/lib/banzai/filter/autolink_filter.rb
+++ b/lib/banzai/filter/autolink_filter.rb
@@ -42,7 +42,7 @@ module Banzai
ENTITY_UNTRUSTED_REGEX = Gitlab::UntrustedRegexp.new(ENTITY_UNTRUSTED, multiline: false)
# Text matching LINK_PATTERN inside these elements will not be linked
- IGNORE_PARENTS = %w(a code kbd pre script style).to_set
+ IGNORE_PARENTS = %w[a code kbd pre script style].to_set
# The XPath query to use for finding text nodes to parse.
TEXT_QUERY = %(descendant-or-self::text()[
diff --git a/lib/banzai/filter/base_sanitization_filter.rb b/lib/banzai/filter/base_sanitization_filter.rb
index 0735fbb8d4c..938e1486195 100644
--- a/lib/banzai/filter/base_sanitization_filter.rb
+++ b/lib/banzai/filter/base_sanitization_filter.rb
@@ -14,7 +14,7 @@ module Banzai
include Gitlab::Utils::StrongMemoize
extend Gitlab::Utils::SanitizeNodeLink
- UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze
+ UNSAFE_PROTOCOLS = %w[data javascript vbscript].freeze
def allowlist
strong_memoize(:allowlist) do
@@ -24,9 +24,9 @@ module Banzai
allowlist[:elements].push('span')
# Allow data-math-style attribute in order to support LaTeX formatting
- allowlist[:attributes]['code'] = %w(data-math-style)
- allowlist[:attributes]['pre'] = %w(data-canonical-lang data-lang-params
- data-math-style data-mermaid-style data-kroki-style)
+ allowlist[:attributes]['code'] = %w[data-math-style]
+ allowlist[:attributes]['pre'] = %w[data-canonical-lang data-lang-params
+ data-math-style data-mermaid-style data-kroki-style]
# Allow html5 details/summary elements
allowlist[:elements].push('details')
@@ -34,7 +34,7 @@ module Banzai
# Allow abbr elements with title attribute
allowlist[:elements].push('abbr')
- allowlist[:attributes]['abbr'] = %w(title)
+ allowlist[:attributes]['abbr'] = %w[title]
# Disallow `name` attribute globally, allow on `a`
allowlist[:attributes][:all].delete('name')
diff --git a/lib/banzai/filter/broadcast_message_sanitization_filter.rb b/lib/banzai/filter/broadcast_message_sanitization_filter.rb
index 183908d02a9..e55e1901b4f 100644
--- a/lib/banzai/filter/broadcast_message_sanitization_filter.rb
+++ b/lib/banzai/filter/broadcast_message_sanitization_filter.rb
@@ -11,7 +11,7 @@ module Banzai
allowlist[:attributes]['a'].push('class', 'style')
- allowlist[:css] = { properties: %w(color border background padding margin text-decoration) }
+ allowlist[:css] = { properties: %w[color border background padding margin text-decoration] }
allowlist
end
diff --git a/lib/banzai/filter/code_language_filter.rb b/lib/banzai/filter/code_language_filter.rb
index 60e5a4063df..a5ae3817d83 100644
--- a/lib/banzai/filter/code_language_filter.rb
+++ b/lib/banzai/filter/code_language_filter.rb
@@ -32,12 +32,17 @@ module Banzai
lang, lang_params = parse_lang_params(code_node)
pre_node = code_node.parent
- pre_node.remove_attribute('lang') if lang.present?
+ if lang.present?
+ code_node.remove_attribute('lang')
+ pre_node.remove_attribute('lang')
+ end
+
pre_node.set_attribute(LANG_ATTR, escape_once(lang)) if lang.present?
pre_node.set_attribute(LANG_PARAMS_ATTR, escape_once(lang_params)) if lang_params.present?
# cmark-gfm added this, it's now in data-lang-params
pre_node.remove_attribute('data-meta')
+ code_node.remove_attribute('data-meta')
end
private
@@ -55,14 +60,14 @@ module Banzai
# "```suggestion:+1-10 more```" -> '<pre data-canonical-lang="suggestion" data-lang-params="+1-10 more">'.
def parse_lang_params(code_node)
pre_node = code_node.parent
- language = pre_node.attr('lang')
+ language = pre_node.attr('lang') || code_node.attr('lang')
return unless language
language, language_params = language.split(LANG_PARAMS_DELIMITER, 2)
# cmark-gfm places extra lang parameters into data-meta
- language_params = [pre_node.attr('data-meta'), language_params].compact.join(' ')
+ language_params = [pre_node.attr('data-meta'), code_node.attr('data-meta'), language_params].compact.join(' ')
[language, language_params]
end
diff --git a/lib/banzai/filter/custom_emoji_filter.rb b/lib/banzai/filter/custom_emoji_filter.rb
index b589d264526..dddaaebc9de 100644
--- a/lib/banzai/filter/custom_emoji_filter.rb
+++ b/lib/banzai/filter/custom_emoji_filter.rb
@@ -5,7 +5,7 @@ module Banzai
class CustomEmojiFilter < HTML::Pipeline::Filter
include Gitlab::Utils::StrongMemoize
- IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set
+ IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set
def call
return doc unless resource_parent
diff --git a/lib/banzai/filter/emoji_filter.rb b/lib/banzai/filter/emoji_filter.rb
index d8c9fd0a7f0..33c93b169f4 100644
--- a/lib/banzai/filter/emoji_filter.rb
+++ b/lib/banzai/filter/emoji_filter.rb
@@ -7,7 +7,7 @@ module Banzai
#
# Based on HTML::Pipeline::EmojiFilter
class EmojiFilter < HTML::Pipeline::Filter
- IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set
+ IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set
def call
doc.xpath('descendant-or-self::text()').each do |node|
diff --git a/lib/banzai/filter/gollum_tags_filter.rb b/lib/banzai/filter/gollum_tags_filter.rb
index 0548d5a9997..ade4f82e54b 100644
--- a/lib/banzai/filter/gollum_tags_filter.rb
+++ b/lib/banzai/filter/gollum_tags_filter.rb
@@ -57,7 +57,7 @@ module Banzai
ALLOWED_IMAGE_EXTENSIONS = /.+(jpg|png|gif|svg|bmp)\z/i.freeze
# Do not perform linking inside these tags.
- IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set
+ IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set
def call
doc.xpath('descendant-or-self::text()').each do |node|
@@ -115,7 +115,7 @@ module Banzai
end
def url?(path)
- path.start_with?(*%w(http https))
+ path.start_with?(*%w[http https])
end
# Attempt to process the tag as a page link tag.
diff --git a/lib/banzai/filter/inline_diff_filter.rb b/lib/banzai/filter/inline_diff_filter.rb
index fc77984f135..b886c68716b 100644
--- a/lib/banzai/filter/inline_diff_filter.rb
+++ b/lib/banzai/filter/inline_diff_filter.rb
@@ -4,7 +4,7 @@
module Banzai
module Filter
class InlineDiffFilter < HTML::Pipeline::Filter
- IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set
+ IGNORED_ANCESTOR_TAGS = %w[pre code tt].to_set
INLINE_DIFF_DELETION_UNTRUSTED = '(?:\[\-(.*?)\-\]|\{\-(.*?)\-\})'
INLINE_DIFF_DELETION_UNTRUSTED_REGEX =
diff --git a/lib/banzai/filter/issuable_reference_expansion_filter.rb b/lib/banzai/filter/issuable_reference_expansion_filter.rb
index 1c3e25b3b27..22fbaa11066 100644
--- a/lib/banzai/filter/issuable_reference_expansion_filter.rb
+++ b/lib/banzai/filter/issuable_reference_expansion_filter.rb
@@ -11,7 +11,7 @@ module Banzai
include Gitlab::Utils::StrongMemoize
NUMBER_OF_SUMMARY_ASSIGNEES = 2
- VISIBLE_STATES = %w(closed merged).freeze
+ VISIBLE_STATES = %w[closed merged].freeze
EXTENDED_FORMAT_XPATH = Gitlab::Utils::Nokogiri.css_to_xpath('a[data-reference-format="+s"]')
def call
diff --git a/lib/banzai/filter/references/reference_filter.rb b/lib/banzai/filter/references/reference_filter.rb
index 5353d3f4e49..caec808ef04 100644
--- a/lib/banzai/filter/references/reference_filter.rb
+++ b/lib/banzai/filter/references/reference_filter.rb
@@ -151,7 +151,7 @@ module Banzai
def ignore_ancestor_query
@ignore_ancestor_query ||= begin
- parents = %w(pre code a style)
+ parents = %w[pre code a style]
parents << 'blockquote' if context[:ignore_blockquotes]
parents.map { |n| "ancestor::#{n}" }.join(' or ')
diff --git a/lib/banzai/filter/repository_link_filter.rb b/lib/banzai/filter/repository_link_filter.rb
index e06126bdf0f..028a081075d 100644
--- a/lib/banzai/filter/repository_link_filter.rb
+++ b/lib/banzai/filter/repository_link_filter.rb
@@ -114,7 +114,7 @@ module Banzai
# Repository routes are under /-/ scope now.
# Since we craft a path without using route helpers we must
# ensure - is added here.
- prefix = '-' if %w(tree blob raw commits).include?(resource_type.to_s)
+ prefix = '-' if %w[tree blob raw commits].include?(resource_type.to_s)
uri.path = [
relative_url_root,
diff --git a/lib/banzai/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb
index c2cad237d6f..15013c8595e 100644
--- a/lib/banzai/filter/sanitization_filter.rb
+++ b/lib/banzai/filter/sanitization_filter.rb
@@ -33,7 +33,7 @@ module Banzai
# Allow section elements with data-footnotes attribute
allowlist[:elements].push('section')
- allowlist[:attributes]['section'] = %w(data-footnotes)
+ allowlist[:attributes]['section'] = %w[data-footnotes]
allowlist[:attributes]['a'].push('data-footnote-ref', 'data-footnote-backref', 'data-footnote-backref-idx')
allowlist
diff --git a/lib/banzai/filter/spaced_link_filter.rb b/lib/banzai/filter/spaced_link_filter.rb
index d370a585271..9331e72cd36 100644
--- a/lib/banzai/filter/spaced_link_filter.rb
+++ b/lib/banzai/filter/spaced_link_filter.rb
@@ -39,7 +39,7 @@ module Banzai
)
# Text matching LINK_OR_IMAGE_PATTERN inside these elements will not be linked
- IGNORE_PARENTS = %w(a code kbd pre script style).to_set
+ IGNORE_PARENTS = %w[a code kbd pre script style].to_set
# The XPath query to use for finding text nodes to parse.
TEXT_QUERY = %(descendant-or-self::text()[
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index e02d668a1ca..6888e0d19e5 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -93,7 +93,7 @@ module Banzai
end
def use_rouge?(language)
- (%w(math suggestion) + ::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES).exclude?(language)
+ (%w[math suggestion] + ::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES).exclude?(language)
end
end
end
diff --git a/lib/banzai/filter/table_of_contents_filter.rb b/lib/banzai/filter/table_of_contents_filter.rb
index de3e978b320..abd1003fde0 100644
--- a/lib/banzai/filter/table_of_contents_filter.rb
+++ b/lib/banzai/filter/table_of_contents_filter.rb
@@ -55,7 +55,7 @@ module Banzai
def anchor_tag(href)
escaped_href = CGI.escape(href) # account for non-ASCII characters
- %{<a id="user-content-#{href}" class="anchor" href="##{escaped_href}" aria-hidden="true"></a>}
+ %(<a id="user-content-#{href}" class="anchor" href="##{escaped_href}" aria-hidden="true"></a>)
end
def push_toc(children, root: false)
@@ -69,7 +69,7 @@ module Banzai
end
def push_anchor(header_node)
- result[:toc] << %{<li><a href="##{header_node.href}">#{header_node.text}</a>}
+ result[:toc] << %(<li><a href="##{header_node.href}">#{header_node.text}</a>)
push_toc(header_node.children)
result[:toc] << '</li>'
end
diff --git a/lib/banzai/pipeline/base_pipeline.rb b/lib/banzai/pipeline/base_pipeline.rb
index 87d1cf9912f..249b332be78 100644
--- a/lib/banzai/pipeline/base_pipeline.rb
+++ b/lib/banzai/pipeline/base_pipeline.rb
@@ -16,7 +16,7 @@ module Banzai
end
class << self
- %i(call to_document to_html).each do |meth|
+ %i[call to_document to_html].each do |meth|
define_method(meth) do |text, context|
context = transform_context(context)
diff --git a/lib/banzai/pipeline/description_pipeline.rb b/lib/banzai/pipeline/description_pipeline.rb
index 8f8ce1cbd41..8236c7092d2 100644
--- a/lib/banzai/pipeline/description_pipeline.rb
+++ b/lib/banzai/pipeline/description_pipeline.rb
@@ -4,7 +4,7 @@ module Banzai
module Pipeline
class DescriptionPipeline < FullPipeline
ALLOWLIST = Banzai::Filter::SanitizationFilter::LIMITED.deep_dup.merge(
- elements: Banzai::Filter::SanitizationFilter::LIMITED[:elements] - %w(pre code img ol ul li)
+ elements: Banzai::Filter::SanitizationFilter::LIMITED[:elements] - %w[pre code img ol ul li]
)
def self.transform_context(context)
diff --git a/lib/banzai/pipeline/incident_management/timeline_event_pipeline.rb b/lib/banzai/pipeline/incident_management/timeline_event_pipeline.rb
index eef2b2674dd..b00b4dd85b5 100644
--- a/lib/banzai/pipeline/incident_management/timeline_event_pipeline.rb
+++ b/lib/banzai/pipeline/incident_management/timeline_event_pipeline.rb
@@ -5,7 +5,7 @@ module Banzai
module IncidentManagement
class TimelineEventPipeline < PlainMarkdownPipeline
ALLOWLIST = Banzai::Filter::SanitizationFilter::LIMITED.deep_dup.merge(
- elements: %w(p b i strong em pre code a img)
+ elements: %w[p b i strong em pre code a img]
).freeze
def self.filters
diff --git a/lib/bitbucket/page.rb b/lib/bitbucket/page.rb
index 38c689628dd..7a51e2f3297 100644
--- a/lib/bitbucket/page.rb
+++ b/lib/bitbucket/page.rb
@@ -20,7 +20,7 @@ module Bitbucket
private
def parse_attrs(raw)
- raw.slice(*%w(size page pagelen next previous)).symbolize_keys
+ raw.slice(*%w[size page pagelen next previous]).symbolize_keys
end
def parse_values(raw, bitbucket_rep_class)
diff --git a/lib/bitbucket/representation/issue.rb b/lib/bitbucket/representation/issue.rb
index 3f6db9cb75b..7a50bdf58d6 100644
--- a/lib/bitbucket/representation/issue.rb
+++ b/lib/bitbucket/representation/issue.rb
@@ -3,7 +3,7 @@
module Bitbucket
module Representation
class Issue < Representation::Base
- CLOSED_STATUS = %w(resolved invalid duplicate wontfix closed).freeze
+ CLOSED_STATUS = %w[resolved invalid duplicate wontfix closed].freeze
def iid
raw['id']
diff --git a/lib/bitbucket/representation/pull_request.rb b/lib/bitbucket/representation/pull_request.rb
index 75183b1df95..6451b8f5d1f 100644
--- a/lib/bitbucket/representation/pull_request.rb
+++ b/lib/bitbucket/representation/pull_request.rb
@@ -39,19 +39,45 @@ module Bitbucket
end
def source_branch_name
- source_branch.dig('branch', 'name')
+ source_branch&.dig('branch', 'name')
end
def source_branch_sha
- source_branch.dig('commit', 'hash')
+ source_branch&.dig('commit', 'hash')
end
def target_branch_name
- target_branch.dig('branch', 'name')
+ target_branch&.dig('branch', 'name')
end
def target_branch_sha
- target_branch.dig('commit', 'hash')
+ target_branch&.dig('commit', 'hash')
+ end
+
+ def reviewers
+ raw['reviewers']&.pluck('username')
+ end
+
+ def to_hash
+ {
+ iid: iid,
+ author: author,
+ description: description,
+ created_at: created_at,
+ updated_at: updated_at,
+ state: state,
+ title: title,
+ source_branch_name: source_branch_name,
+ source_branch_sha: source_branch_sha,
+ merge_commit_sha: merge_commit_sha,
+ target_branch_name: target_branch_name,
+ target_branch_sha: target_branch_sha,
+ reviewers: reviewers
+ }
+ end
+
+ def merge_commit_sha
+ raw['merge_commit']&.dig('hash')
end
private
diff --git a/lib/bulk_imports/common/graphql/get_members_query.rb b/lib/bulk_imports/common/graphql/get_members_query.rb
index 8fa8d7f4c0b..4f7533ee25f 100644
--- a/lib/bulk_imports/common/graphql/get_members_query.rb
+++ b/lib/bulk_imports/common/graphql/get_members_query.rb
@@ -14,7 +14,7 @@ module BulkImports
<<-GRAPHQL
query($full_path: ID!, $cursor: String, $per_page: Int) {
portable: #{context.entity.entity_type}(fullPath: $full_path) {
- members: #{members_type}(relations: #{relations}, first: $per_page, after: $cursor) {
+ members: #{members_type}(relations: [#{relations}], first: $per_page, after: $cursor) {
page_info: pageInfo {
next_page: endCursor
has_next_page: hasNextPage
@@ -29,6 +29,7 @@ module BulkImports
user {
user_gid: id
public_email: publicEmail
+ username: username
}
}
}
@@ -69,11 +70,27 @@ module BulkImports
def relations
if context.entity.group?
- "[DIRECT INHERITED SHARED_FROM_GROUPS]"
+ group_relations
else
- "[DIRECT INHERITED INVITED_GROUPS SHARED_INTO_ANCESTORS]"
+ project_relations
end
end
+
+ def source_version
+ Gitlab::VersionInfo.parse(context.bulk_import.source_version)
+ end
+
+ def group_relations
+ base_relation = "DIRECT INHERITED"
+ base_relation += " SHARED_FROM_GROUPS" if source_version >= Gitlab::VersionInfo.parse("14.7.0")
+ base_relation
+ end
+
+ def project_relations
+ base_relation = "DIRECT INHERITED INVITED_GROUPS"
+ base_relation += " SHARED_INTO_ANCESTORS" if source_version >= Gitlab::VersionInfo.parse("16.0.0")
+ base_relation
+ end
end
end
end
diff --git a/lib/bulk_imports/common/pipelines/entity_finisher.rb b/lib/bulk_imports/common/pipelines/entity_finisher.rb
index a52504d04bc..fa09f36fdd6 100644
--- a/lib/bulk_imports/common/pipelines/entity_finisher.rb
+++ b/lib/bulk_imports/common/pipelines/entity_finisher.rb
@@ -34,7 +34,7 @@ module BulkImports
importer: 'gitlab_migration'
)
- context.portable.try(:after_import)
+ ::BulkImports::FinishProjectImportWorker.perform_async(entity.project_id) if entity.project?
end
private
diff --git a/lib/bulk_imports/common/transformers/member_attributes_transformer.rb b/lib/bulk_imports/common/transformers/member_attributes_transformer.rb
index 382e6a51a73..4cd87ec2b59 100644
--- a/lib/bulk_imports/common/transformers/member_attributes_transformer.rb
+++ b/lib/bulk_imports/common/transformers/member_attributes_transformer.rb
@@ -12,7 +12,7 @@ module BulkImports
return unless user
return unless valid_access_level?(access_level)
- cache_source_user_id(data, user, context)
+ cache_source_user_data(data, user, context)
{
user_id: user.id,
@@ -36,14 +36,21 @@ module BulkImports
Gitlab::Access.options_with_owner.value?(access_level)
end
- def cache_source_user_id(data, user, context)
+ def cache_source_user_data(data, user, context)
gid = data&.dig('user', 'user_gid')
return unless gid
source_user_id = GlobalID.parse(gid).model_id
+ source_username = data&.dig('user', 'username')
- ::BulkImports::UsersMapper.new(context: context).cache_source_user_id(source_user_id, user.id)
+ mapper = ::BulkImports::UsersMapper.new(context: context)
+
+ mapper.cache_source_user_id(source_user_id, user.id)
+ return unless source_username
+ return if source_username == user.username
+
+ mapper.cache_source_username(source_username, user.username)
end
end
end
diff --git a/lib/bulk_imports/groups/loaders/group_loader.rb b/lib/bulk_imports/groups/loaders/group_loader.rb
index 5f5307123a5..85d85f0f703 100644
--- a/lib/bulk_imports/groups/loaders/group_loader.rb
+++ b/lib/bulk_imports/groups/loaders/group_loader.rb
@@ -4,6 +4,8 @@ module BulkImports
module Groups
module Loaders
class GroupLoader
+ TWO_FACTOR_KEY = 'require_two_factor_authentication'
+
GroupCreationError = Class.new(StandardError)
def load(context, data)
@@ -16,6 +18,10 @@ module BulkImports
raise(GroupCreationError, 'User not allowed to create group') unless user_can_create_group?(current_user, data)
raise(GroupCreationError, 'Group exists') if group_exists?(destination_namespace, path)
+ unless two_factor_requirements_met?(current_user, data)
+ raise(GroupCreationError, 'User requires Two-Factor Authentication')
+ end
+
group = ::Groups::CreateService.new(current_user, data).execute
raise(GroupCreationError, group.errors.full_messages.to_sentence) if group.errors.any?
@@ -37,6 +43,12 @@ module BulkImports
end
end
+ def two_factor_requirements_met?(current_user, data)
+ return true unless data.has_key?(TWO_FACTOR_KEY) && data[TWO_FACTOR_KEY]
+
+ current_user.two_factor_enabled?
+ end
+
def group_exists?(destination_namespace, path)
full_path = destination_namespace.present? ? File.join(destination_namespace, path) : path
diff --git a/lib/bulk_imports/network_error.rb b/lib/bulk_imports/network_error.rb
index fda4bb74a30..b21889adcb3 100644
--- a/lib/bulk_imports/network_error.rb
+++ b/lib/bulk_imports/network_error.rb
@@ -5,10 +5,19 @@ module BulkImports
TRACKER_COUNTER_KEY = 'bulk_imports/%{entity_id}/%{stage}/%{tracker_id}/network_error/%{error}'
ENTITY_COUNTER_KEY = 'bulk_imports/%{entity_id}/network_error/%{error}'
- RETRIABLE_EXCEPTIONS = Gitlab::HTTP::HTTP_TIMEOUT_ERRORS + [
+ NO_SPACE_LEFT_EXCEPTION = Errno::ENOSPC
+ DECOMPRESSION_FAILURE_EXCEPTION = Zlib::Error
+
+ EXCEPTIONS_RETRY_DELAY = {
+ NO_SPACE_LEFT_EXCEPTION => 120,
+ DECOMPRESSION_FAILURE_EXCEPTION => 60
+ }.freeze
+
+ RETRIABLE_EXCEPTIONS = Gitlab::HTTP::HTTP_TIMEOUT_ERRORS + EXCEPTIONS_RETRY_DELAY.keys + [
EOFError, SocketError, OpenSSL::SSL::SSLError, OpenSSL::OpenSSLError,
Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH
].freeze
+
RETRIABLE_HTTP_CODES = [429].freeze
DEFAULT_RETRY_DELAY_SECONDS = 30
@@ -37,7 +46,7 @@ module BulkImports
if response&.code == 429
response.headers.fetch('Retry-After', DEFAULT_RETRY_DELAY_SECONDS).to_i
else
- DEFAULT_RETRY_DELAY_SECONDS
+ EXCEPTIONS_RETRY_DELAY[cause&.class] || DEFAULT_RETRY_DELAY_SECONDS
end.seconds
end
diff --git a/lib/bulk_imports/pipeline/runner.rb b/lib/bulk_imports/pipeline/runner.rb
index 81f8dee30d9..1e2d9152047 100644
--- a/lib/bulk_imports/pipeline/runner.rb
+++ b/lib/bulk_imports/pipeline/runner.rb
@@ -58,11 +58,9 @@ module BulkImports
importer: 'gitlab_migration'
)
rescue BulkImports::NetworkError => e
- if e.retriable?(context.tracker)
- raise BulkImports::RetryPipelineError.new(e.message, e.retry_delay)
- else
- log_and_fail(e, step)
- end
+ raise BulkImports::RetryPipelineError.new(e.message, e.retry_delay) if e.retriable?(context.tracker)
+
+ log_and_fail(e, step)
rescue BulkImports::RetryPipelineError
raise
rescue StandardError => e
diff --git a/lib/bulk_imports/projects/pipelines/references_pipeline.rb b/lib/bulk_imports/projects/pipelines/references_pipeline.rb
index f00a62edf51..e2032569ab5 100644
--- a/lib/bulk_imports/projects/pipelines/references_pipeline.rb
+++ b/lib/bulk_imports/projects/pipelines/references_pipeline.rb
@@ -22,8 +22,10 @@ module BulkImports
def transform(_context, object)
body = object_body(object).dup
+ body.gsub!(username_regex(mapped_usernames), mapped_usernames)
+
matching_urls(object).each do |old_url, new_url|
- body.gsub!(old_url, new_url)
+ body.gsub!(old_url, new_url) if body.include?(old_url)
end
object.assign_attributes(body_field(object) => body)
@@ -37,10 +39,21 @@ module BulkImports
private
+ def mapped_usernames
+ @mapped_usernames ||= ::BulkImports::UsersMapper.new(context: context)
+ .map_usernames.transform_keys { |key| "@#{key}" }
+ .transform_values { |value| "@#{value}" }
+ end
+
+ def username_regex(mapped_usernames)
+ @username_regex ||= Regexp.new(mapped_usernames.keys.sort_by(&:length)
+ .reverse.map { |x| Regexp.escape(x) }.join('|'))
+ end
+
def add_matching_objects(collection, enum)
collection.each_batch(of: BATCH_SIZE, column: :iid) do |batch|
batch.each do |object|
- enum << object if object_has_reference?(object)
+ enum << object if object_has_reference?(object) || object_has_username?(object)
end
end
end
@@ -51,7 +64,7 @@ module BulkImports
object.notes.each_batch(of: BATCH_SIZE) do |notes_batch|
notes_batch.each do |note|
note.refresh_markdown_cache!
- enum << note if object_has_reference?(note)
+ enum << note if object_has_reference?(note) || object_has_username?(note)
end
end
end
@@ -62,6 +75,12 @@ module BulkImports
object_body(object)&.include?(source_full_path)
end
+ def object_has_username?(object)
+ return false unless object_body(object)
+
+ mapped_usernames.keys.any? { |old_username| object_body(object).include?(old_username) }
+ end
+
def object_body(object)
call_object_method(object)
end
diff --git a/lib/bulk_imports/users_mapper.rb b/lib/bulk_imports/users_mapper.rb
index 74412bc3831..af002c67367 100644
--- a/lib/bulk_imports/users_mapper.rb
+++ b/lib/bulk_imports/users_mapper.rb
@@ -6,17 +6,17 @@ module BulkImports
SOURCE_USER_IDS_CACHE_KEY = 'bulk_imports/%{bulk_import}/%{entity}/source_user_ids'
+ SOURCE_USERNAMES_CACHE_KEY = 'bulk_imports/%{bulk_import}/%{entity}/source_usernames'
+
def initialize(context:)
@context = context
- @cache_key = SOURCE_USER_IDS_CACHE_KEY % {
- bulk_import: @context.bulk_import.id,
- entity: @context.entity.id
- }
+ @user_ids_cache_key = generate_cache_key(SOURCE_USER_IDS_CACHE_KEY)
+ @usernames_cache_key = generate_cache_key(SOURCE_USERNAMES_CACHE_KEY)
end
def map
strong_memoize(:map) do
- map = hash_with_default
+ map = Hash.new { default_user_id }
cached_source_user_ids.each_pair do |source_id, destination_id|
map[source_id.to_i] = destination_id.to_i
@@ -26,6 +26,18 @@ module BulkImports
end
end
+ def map_usernames
+ strong_memoize(:map_usernames) do
+ map = {}
+
+ cached_source_usernames.each_pair do |source_username, destination_username|
+ map[source_username] = destination_username
+ end
+
+ map
+ end
+ end
+
def include?(source_user_id)
map.has_key?(source_user_id)
end
@@ -35,17 +47,28 @@ module BulkImports
end
def cache_source_user_id(source_id, destination_id)
- ::Gitlab::Cache::Import::Caching.hash_add(@cache_key, source_id, destination_id)
+ ::Gitlab::Cache::Import::Caching.hash_add(@user_ids_cache_key, source_id, destination_id)
+ end
+
+ def cache_source_username(source_username, destination_username)
+ ::Gitlab::Cache::Import::Caching.hash_add(@usernames_cache_key, source_username, destination_username)
end
private
- def hash_with_default
- Hash.new { default_user_id }
+ def generate_cache_key(pattern)
+ pattern % {
+ bulk_import: @context.bulk_import.id,
+ entity: @context.entity.id
+ }
end
def cached_source_user_ids
- ::Gitlab::Cache::Import::Caching.values_from_hash(@cache_key)
+ ::Gitlab::Cache::Import::Caching.values_from_hash(@user_ids_cache_key)
+ end
+
+ def cached_source_usernames
+ ::Gitlab::Cache::Import::Caching.values_from_hash(@usernames_cache_key)
end
end
end
diff --git a/lib/click_house/bind_index_manager.rb b/lib/click_house/bind_index_manager.rb
deleted file mode 100644
index 96b0940ce71..00000000000
--- a/lib/click_house/bind_index_manager.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-module ClickHouse
- class BindIndexManager
- def initialize(start_index = 1)
- @current_index = start_index
- end
-
- def next_bind_str
- bind_str = "$#{@current_index}"
- @current_index += 1
- bind_str
- end
- end
-end
diff --git a/lib/click_house/logger.rb b/lib/click_house/logger.rb
new file mode 100644
index 00000000000..90af644799b
--- /dev/null
+++ b/lib/click_house/logger.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module ClickHouse
+ class Logger < ::Gitlab::JsonLogger
+ exclude_context!
+
+ def self.file_name_noext
+ 'clickhouse'
+ end
+ end
+end
diff --git a/lib/click_house/query_builder.rb b/lib/click_house/query_builder.rb
index a2136420b2f..dc139663e7c 100644
--- a/lib/click_house/query_builder.rb
+++ b/lib/click_house/query_builder.rb
@@ -2,7 +2,7 @@
# rubocop:disable CodeReuse/ActiveRecord
module ClickHouse
- class QueryBuilder
+ class QueryBuilder < ClickHouse::Client::QueryLike
attr_reader :table
attr_accessor :conditions, :manager
@@ -93,8 +93,8 @@ module ClickHouse
manager.to_sql
end
- def to_redacted_sql
- ::ClickHouse::Redactor.redact(self)
+ def to_redacted_sql(bind_index_manager = ClickHouse::Client::BindIndexManager.new)
+ ::ClickHouse::Redactor.redact(self, bind_index_manager)
end
private
diff --git a/lib/click_house/record_sync_context.rb b/lib/click_house/record_sync_context.rb
new file mode 100644
index 00000000000..5d2d77d3283
--- /dev/null
+++ b/lib/click_house/record_sync_context.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module ClickHouse
+ class RecordSyncContext
+ attr_reader :last_record_id, :last_processed_id, :total_record_count, :record_count_in_current_batch
+
+ def initialize(
+ last_record_id:, max_records_per_batch:,
+ runtime_limiter: Analytics::CycleAnalytics::RuntimeLimiter.new)
+ @last_record_id = last_record_id
+ @runtime_limiter = runtime_limiter
+ @max_records_per_batch = max_records_per_batch
+ @last_processed_id = nil
+ @record_count_in_current_batch = 0
+ @total_record_count = 0
+ end
+
+ delegate :over_time?, to: :@runtime_limiter
+
+ def new_batch!
+ @record_count_in_current_batch = 0
+ end
+
+ def no_more_records!
+ @no_more_records = true
+ end
+
+ def no_more_records?
+ !!@no_more_records
+ end
+
+ def last_processed_id=(value)
+ @record_count_in_current_batch += 1
+ @total_record_count += 1
+ @last_processed_id = value
+ @last_record_id = value
+ end
+
+ def record_limit_reached?
+ @record_count_in_current_batch == @max_records_per_batch
+ end
+ end
+end
diff --git a/lib/click_house/redactor.rb b/lib/click_house/redactor.rb
index 9b8e2bc90d9..6ca7c46e747 100644
--- a/lib/click_house/redactor.rb
+++ b/lib/click_house/redactor.rb
@@ -14,9 +14,8 @@ module ClickHouse
# redacted_query = ClickHouse::Redactor.redact(query_builder)
# # The redacted_query will contain the SQL query with values replaced by placeholders.
# output: "SELECT * FROM \"users\" WHERE \"users\".\"name\" = $1"
- def self.redact(query_builder)
+ def self.redact(query_builder, bind_manager = ClickHouse::Client::BindIndexManager.new)
cloned_query_builder = query_builder.clone
- bind_manager = ::ClickHouse::BindIndexManager.new
cloned_query_builder.conditions = cloned_query_builder.conditions.map do |condition|
redact_condition(condition, bind_manager)
diff --git a/lib/click_house/sync_cursor.rb b/lib/click_house/sync_cursor.rb
new file mode 100644
index 00000000000..9426f727072
--- /dev/null
+++ b/lib/click_house/sync_cursor.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module ClickHouse
+ class SyncCursor
+ QUERY = <<~SQL
+ SELECT argMax(primary_key_value, recorded_at) AS primary_key_value
+ FROM sync_cursors
+ WHERE table_name = {table_name:String}
+ LIMIT 1
+ SQL
+
+ INSERT_CURSOR_QUERY = <<~SQL
+ INSERT INTO sync_cursors
+ (primary_key_value, table_name, recorded_at)
+ VALUES ({primary_key_value:UInt64}, {table_name:String}, {recorded_at:DateTime64})
+ SQL
+
+ def self.cursor_for(identifier)
+ query = ClickHouse::Client::Query.new(
+ raw_query: QUERY,
+ placeholders: { table_name: identifier.to_s }
+ )
+
+ # The query returns the default value (0) when no records are present.
+ ClickHouse::Client.select(query, :main).first['primary_key_value']
+ end
+
+ def self.update_cursor_for(identifier, value)
+ query = ClickHouse::Client::Query.new(
+ raw_query: INSERT_CURSOR_QUERY,
+ placeholders: {
+ primary_key_value: value,
+ table_name: identifier.to_s,
+ recorded_at: Time.current.to_f
+ }
+ )
+
+ ClickHouse::Client.execute(query, :main)
+ end
+ end
+end
diff --git a/lib/constraints/activity_pub_constrainer.rb b/lib/constraints/activity_pub_constrainer.rb
new file mode 100644
index 00000000000..6a38e67b54b
--- /dev/null
+++ b/lib/constraints/activity_pub_constrainer.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Constraints
+ class ActivityPubConstrainer
+ def matches?(request)
+ accept = header(request)
+ mime_types.any? { |m| accept.include?(m) }
+ end
+
+ private
+
+ def mime_types
+ ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"']
+ end
+
+ def header(request)
+ request.headers['Accept'] || request.headers['Content-Type'] || ''
+ end
+ end
+end
diff --git a/lib/container_registry/path.rb b/lib/container_registry/path.rb
index 9b2a61cdedc..9e5d8347b53 100644
--- a/lib/container_registry/path.rb
+++ b/lib/container_registry/path.rb
@@ -66,7 +66,7 @@ module ContainerRegistry
def repository_name
return unless has_project?
- @path.remove(%r(^#{Regexp.escape(project_path)}/?))
+ @path.remove(%r{^#{Regexp.escape(project_path)}/?})
end
def project_path
diff --git a/lib/feature.rb b/lib/feature.rb
index 3847f880be0..cee6f633e78 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -348,7 +348,7 @@ module Feature
end
def gate_specified?
- %i(user project group feature_group namespace repository).any? { |key| params.key?(key) }
+ %i[user project group feature_group namespace repository].any? { |key| params.key?(key) }
end
def targets
diff --git a/lib/generators/batched_background_migration/templates/batched_background_migration_job_spec.template b/lib/generators/batched_background_migration/templates/batched_background_migration_job_spec.template
index c41b8107c95..b05695ffa3b 100644
--- a/lib/generators/batched_background_migration/templates/batched_background_migration_job_spec.template
+++ b/lib/generators/batched_background_migration/templates/batched_background_migration_job_spec.template
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe Gitlab::BackgroundMigration::<%= class_name %>, schema: <%= migration_number %>, feature_category: :<%= feature_category %> do # rubocop:disable Layout/LineLength
+RSpec.describe Gitlab::BackgroundMigration::<%= class_name %>, feature_category: :<%= feature_category %> do # rubocop:disable Layout/LineLength
# Tests go here
end
diff --git a/lib/generators/gitlab/analytics/internal_events_generator.rb b/lib/generators/gitlab/analytics/internal_events_generator.rb
index ae738c5dcb0..083d5c31c9b 100644
--- a/lib/generators/gitlab/analytics/internal_events_generator.rb
+++ b/lib/generators/gitlab/analytics/internal_events_generator.rb
@@ -87,9 +87,11 @@ module Gitlab
def create_metric_file
validate!
- template "event_definition.yml",
- event_file_path(event),
- ask_description(event, "event", "what the event is supposed to track, where, and when")
+ unless event_exists?
+ template "event_definition.yml",
+ event_file_path(event),
+ ask_description(event, "event", "what the event is supposed to track, where, and when")
+ end
time_frames.each do |time_frame|
template "metric_definition.yml",
@@ -106,12 +108,6 @@ module Gitlab
private
- def known_event_entry
- <<~YML
- - name: #{event}
- YML
- end
-
def event_identifiers
return unless include_default_event_properties?
@@ -190,8 +186,6 @@ module Gitlab
end
def validate!
- raise "An event '#{event}' already exists" if event_exists?
-
validate_tiers!
%i[unique event mr section stage group].each do |option|
diff --git a/lib/generators/gitlab/usage_metric_definition_generator.rb b/lib/generators/gitlab/usage_metric_definition_generator.rb
index cdbfda2495b..5fe0ab1364d 100644
--- a/lib/generators/gitlab/usage_metric_definition_generator.rb
+++ b/lib/generators/gitlab/usage_metric_definition_generator.rb
@@ -26,7 +26,7 @@ module Gitlab
TOP_LEVEL_DIR = 'config'
TOP_LEVEL_DIR_EE = 'ee'
- VALID_INPUT_DIRS = (TIME_FRAME_DIRS.flat_map { |d| [d.name, d.time_frame] } - %w(none)).freeze
+ VALID_INPUT_DIRS = (TIME_FRAME_DIRS.flat_map { |d| [d.name, d.time_frame] } - %w[none]).freeze
source_root File.expand_path('../../../generator_templates/usage_metric_definition', __dir__)
diff --git a/lib/generators/gitlab/usage_metric_generator.rb b/lib/generators/gitlab/usage_metric_generator.rb
index 3624a6eb5a7..bc9f33573af 100644
--- a/lib/generators/gitlab/usage_metric_generator.rb
+++ b/lib/generators/gitlab/usage_metric_generator.rb
@@ -16,8 +16,8 @@ module Gitlab
numbers: 'Numbers'
}.freeze
- ALLOWED_DATABASE_OPERATIONS = %w(count distinct_count estimate_batch_distinct_count sum average).freeze
- ALLOWED_NUMBERS_OPERATIONS = %w(add).freeze
+ ALLOWED_DATABASE_OPERATIONS = %w[count distinct_count estimate_batch_distinct_count sum average].freeze
+ ALLOWED_NUMBERS_OPERATIONS = %w[add].freeze
ALLOWED_OPERATIONS = ALLOWED_DATABASE_OPERATIONS | ALLOWED_NUMBERS_OPERATIONS
source_root File.expand_path('usage_metric/templates', __dir__)
diff --git a/lib/gitlab.rb b/lib/gitlab.rb
index 0361adc7fc7..d4cd62a9c21 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -47,7 +47,7 @@ module Gitlab
APP_DIRS_PATTERN = %r{^/?(app|config|ee|lib|spec|\(\w*\))}.freeze
VERSION = File.read(root.join("VERSION")).strip.freeze
INSTALLATION_TYPE = File.read(root.join("INSTALLATION_TYPE")).strip.freeze
- HTTP_PROXY_ENV_VARS = %w(http_proxy https_proxy HTTP_PROXY HTTPS_PROXY).freeze
+ HTTP_PROXY_ENV_VARS = %w[http_proxy https_proxy HTTP_PROXY HTTPS_PROXY].freeze
def self.simulate_com?
return false unless Rails.env.development?
diff --git a/lib/gitlab/alert_management/payload/prometheus.rb b/lib/gitlab/alert_management/payload/prometheus.rb
index 15fa91646c8..e64fb52c0cf 100644
--- a/lib/gitlab/alert_management/payload/prometheus.rb
+++ b/lib/gitlab/alert_management/payload/prometheus.rb
@@ -7,32 +7,32 @@ module Gitlab
class Prometheus < Base
extend Gitlab::Utils::Override
- attribute :alert_markdown, paths: %w(annotations gitlab_incident_markdown)
+ attribute :alert_markdown, paths: %w[annotations gitlab_incident_markdown]
attribute :annotations, paths: 'annotations'
- attribute :description, paths: %w(annotations description)
+ attribute :description, paths: %w[annotations description]
attribute :ends_at, paths: 'endsAt', type: :time
- attribute :environment_name, paths: %w(labels gitlab_environment_name)
- attribute :generator_url, paths: %w(generatorURL)
+ attribute :environment_name, paths: %w[labels gitlab_environment_name]
+ attribute :generator_url, paths: %w[generatorURL]
attribute :gitlab_y_label,
- paths: [%w(annotations gitlab_y_label),
- %w(annotations title),
- %w(annotations summary),
- %w(labels alertname)]
- attribute :runbook, paths: %w(annotations runbook)
+ paths: [%w[annotations gitlab_y_label],
+ %w[annotations title],
+ %w[annotations summary],
+ %w[labels alertname]]
+ attribute :runbook, paths: %w[annotations runbook]
attribute :starts_at,
paths: 'startsAt',
type: :time,
fallback: -> { Time.current.utc }
attribute :status, paths: 'status'
attribute :title,
- paths: [%w(annotations title),
- %w(annotations summary),
- %w(labels alertname)]
+ paths: [%w[annotations title],
+ %w[annotations summary],
+ %w[labels alertname]]
attribute :starts_at_raw,
- paths: [%w(startsAt)]
+ paths: [%w[startsAt]]
private :starts_at_raw
- attribute :severity_raw, paths: %w(labels severity)
+ attribute :severity_raw, paths: %w[labels severity]
private :severity_raw
METRIC_TIME_WINDOW = 30.minutes
diff --git a/lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb b/lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb
index b2e1c9e2379..08439ac5f1e 100644
--- a/lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb
+++ b/lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb
@@ -7,7 +7,7 @@ module Gitlab
register_for 'gitlab-html-pipeline'
def format(node, lang, opts)
- %(<pre #{lang ? %[lang="#{lang}"] : ''}><code>#{node.content}</code></pre>)
+ %(<pre #{lang ? %(lang="#{lang}") : ''}><code>#{node.content}</code></pre>)
end
end
end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index cafa75d5f59..9ddfc995535 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -5,12 +5,19 @@ module Gitlab
MissingPersonalAccessTokenError = Class.new(StandardError)
IpBlocked = Class.new(StandardError)
+ # Scopes used for GitLab internal API (Kubernetes cluster access)
+ K8S_PROXY_SCOPE = :k8s_proxy
+
# Scopes used for GitLab API access
API_SCOPE = :api
READ_API_SCOPE = :read_api
READ_USER_SCOPE = :read_user
CREATE_RUNNER_SCOPE = :create_runner
- API_SCOPES = [API_SCOPE, READ_API_SCOPE, READ_USER_SCOPE, CREATE_RUNNER_SCOPE].freeze
+ API_SCOPES = [API_SCOPE, READ_API_SCOPE, READ_USER_SCOPE, CREATE_RUNNER_SCOPE, K8S_PROXY_SCOPE].freeze
+
+ # Scopes for Duo
+ AI_FEATURES = :ai_features
+ AI_FEATURES_SCOPES = [AI_FEATURES].freeze
PROFILE_SCOPE = :profile
EMAIL_SCOPE = :email
@@ -429,7 +436,7 @@ module Gitlab
end
def non_admin_available_scopes
- API_SCOPES + REPOSITORY_SCOPES + registry_scopes + OBSERVABILITY_SCOPES
+ API_SCOPES + REPOSITORY_SCOPES + registry_scopes + OBSERVABILITY_SCOPES + AI_FEATURES_SCOPES
end
def find_build_by_token(token)
diff --git a/lib/gitlab/auth/devise/strategies/combined_two_factor_authenticatable.rb b/lib/gitlab/auth/devise/strategies/combined_two_factor_authenticatable.rb
new file mode 100644
index 00000000000..ef326fd2a99
--- /dev/null
+++ b/lib/gitlab/auth/devise/strategies/combined_two_factor_authenticatable.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Devise
+ module Strategies
+ # This strategy combines the following strategies from
+ # devise_two_factor gem:
+ # - TwoFactorAuthenticatable: https://github.com/devise-two-factor/devise-two-factor/blob/v4.0.2/lib/devise_two_factor/strategies/two_factor_authenticatable.rb
+ # - TwoFactorBackupable: https://github.com/devise-two-factor/devise-two-factor/blob/v4.0.2/lib/devise_two_factor/strategies/two_factor_backupable.rb
+ # to avoid double incrementing failed login attempts counter by each
+ # strategy in case an incorrect password is provided.
+ class CombinedTwoFactorAuthenticatable < ::Devise::Strategies::DatabaseAuthenticatable
+ def authenticate!
+ resource = mapping.to.find_for_database_authentication(authentication_hash)
+
+ # We check the OTP / backup code, then defer to DatabaseAuthenticatable
+ is_valid = validate(resource) do
+ validate_otp(resource) || resource.invalidate_otp_backup_code!(params[scope]['otp_attempt'])
+ end
+
+ if is_valid
+ # Devise fails to authenticate invalidated resources, but if we've
+ # gotten here, the object changed (Since we deleted a recovery code)
+ resource.save!
+
+ super
+ end
+
+ fail(::Devise.paranoid ? :invalid : :not_found_in_database) unless resource # rubocop: disable Style/SignalException
+
+ # We want to cascade to the next strategy if this one fails,
+ # but database authenticatable automatically halts on a bad password
+ @halted = false if @result == :failure
+ end
+
+ def validate_otp(resource)
+ return true unless resource.otp_required_for_login
+
+ return if params[scope]['otp_attempt'].nil?
+
+ resource.validate_and_consume_otp!(params[scope]['otp_attempt'])
+ end
+ end
+ end
+ end
+ end
+end
+
+Warden::Strategies.add(
+ :combined_two_factor_authenticatable,
+ Gitlab::Auth::Devise::Strategies::CombinedTwoFactorAuthenticatable)
diff --git a/lib/gitlab/auth/ldap/adapter.rb b/lib/gitlab/auth/ldap/adapter.rb
index 0201f1f8725..a91d99d1b76 100644
--- a/lib/gitlab/auth/ldap/adapter.rb
+++ b/lib/gitlab/auth/ldap/adapter.rb
@@ -41,7 +41,7 @@ module Gitlab
ldap_search(base: dn,
filter: filter,
scope: Net::LDAP::SearchScope_BaseObject,
- attributes: %w{dn}).any?
+ attributes: %w[dn]).any?
end
def ldap_search(*args)
diff --git a/lib/gitlab/auth/ldap/config.rb b/lib/gitlab/auth/ldap/config.rb
index 13ca4f01154..ed7caf84558 100644
--- a/lib/gitlab/auth/ldap/config.rb
+++ b/lib/gitlab/auth/ldap/config.rb
@@ -198,8 +198,8 @@ module Gitlab
def default_attributes
{
- 'username' => %W(#{uid} uid sAMAccountName userid).uniq,
- 'email' => %w(mail email userPrincipalName),
+ 'username' => %W[#{uid} uid sAMAccountName userid].uniq,
+ 'email' => %w[mail email userPrincipalName],
'name' => 'cn',
'first_name' => 'givenName',
'last_name' => 'sn'
diff --git a/lib/gitlab/auth/o_auth/provider.rb b/lib/gitlab/auth/o_auth/provider.rb
index 2ce8677c8b7..1f07baefa67 100644
--- a/lib/gitlab/auth/o_auth/provider.rb
+++ b/lib/gitlab/auth/o_auth/provider.rb
@@ -33,7 +33,7 @@ module Gitlab
end
def self.providers
- Devise.omniauth_providers
+ ::Devise.omniauth_providers
end
def self.enabled?(name)
@@ -69,7 +69,7 @@ module Gitlab
end
else
provider = Gitlab.config.omniauth.providers.find do |provider|
- provider.name == name || (provider.name == 'openid_connect' && provider.args.name == name)
+ provider.name == name || (provider.name == 'openid_connect' && provider.dig(:args, :name) == name)
end
merge_provider_args_with_defaults!(provider)
diff --git a/lib/gitlab/background_migration/backfill_has_merge_request_of_vulnerability_reads.rb b/lib/gitlab/background_migration/backfill_has_merge_request_of_vulnerability_reads.rb
new file mode 100644
index 00000000000..7f0ee54012b
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_has_merge_request_of_vulnerability_reads.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Sets the `has_merge_request` of the existing `vulnerability_reads` records
+ class BackfillHasMergeRequestOfVulnerabilityReads < BatchedMigrationJob
+ operation_name :set_has_merge_request
+ feature_category :database
+
+ UPDATE_SQL = <<~SQL
+ UPDATE
+ vulnerability_reads
+ SET
+ has_merge_request = true
+ FROM
+ (%<subquery>s) as sub_query
+ WHERE
+ vulnerability_reads.vulnerability_id = sub_query.vulnerability_id
+ SQL
+
+ def perform
+ each_sub_batch do |sub_batch|
+ update_query = update_query_for(sub_batch)
+
+ connection.execute(update_query)
+ end
+ end
+
+ private
+
+ def update_query_for(sub_batch)
+ subquery = sub_batch.joins("
+ INNER JOIN vulnerability_merge_request_links ON
+ vulnerability_reads.vulnerability_id =
+ vulnerability_merge_request_links.vulnerability_id")
+
+ format(UPDATE_SQL, subquery: subquery.to_sql)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb b/lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb
index b0b7882d54d..228269adc04 100644
--- a/lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb
+++ b/lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb
@@ -14,7 +14,7 @@ module Gitlab
batch_metrics.time_operation(:update_all) do
ApplicationRecord.connection.execute <<~SQL
- WITH route_and_ns(route_id, project_namespace_id) AS #{::Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH route_and_ns(route_id, project_namespace_id) AS MATERIALIZED (
#{sub_batch.to_sql}
)
UPDATE routes
diff --git a/lib/gitlab/background_migration/backfill_note_discussion_id.rb b/lib/gitlab/background_migration/backfill_note_discussion_id.rb
index ce2698b3cb8..d5f12e73ff8 100644
--- a/lib/gitlab/background_migration/backfill_note_discussion_id.rb
+++ b/lib/gitlab/background_migration/backfill_note_discussion_id.rb
@@ -37,7 +37,7 @@ module Gitlab
{ discussion_id: note.generate_discussion_id }
end
- Gitlab::Database::BulkUpdate.execute(%i(discussion_id), mapping)
+ Gitlab::Database::BulkUpdate.execute(%i[discussion_id], mapping)
end
end
end
diff --git a/lib/gitlab/background_migration/backfill_nuget_normalized_version.rb b/lib/gitlab/background_migration/backfill_nuget_normalized_version.rb
new file mode 100644
index 00000000000..26ca5f299b4
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_nuget_normalized_version.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Backfill the normalized_version column in the packages_nuget_metadata table
+ class BackfillNugetNormalizedVersion < BatchedMigrationJob
+ operation_name :update_all
+ feature_category :package_registry
+
+ scope_to ->(relation) { relation.where(normalized_version: nil) }
+
+ # rubocop: disable Style/Documentation
+ class Package < ApplicationRecord
+ self.table_name = 'packages_packages'
+ end
+
+ class PackagesNugetMetadatum < ApplicationRecord
+ self.table_name = 'packages_nuget_metadata'
+
+ LEADING_ZEROES_REGEX = /^(?!0$)0+(?=\d)/
+
+ belongs_to :package
+ delegate :version, to: :package, prefix: true
+
+ def set_normalized_version
+ return unless package
+
+ self.normalized_version = normalize
+ end
+
+ private
+
+ def normalize
+ version = remove_leading_zeroes
+ version = remove_build_metadata(version)
+ version = omit_zero_in_fourth_part(version)
+ append_suffix(version)
+ end
+
+ def remove_leading_zeroes
+ package_version.split('.').map { |part| part.sub(LEADING_ZEROES_REGEX, '') }.join('.')
+ end
+
+ def remove_build_metadata(version)
+ version.split('+').first.downcase
+ end
+
+ def omit_zero_in_fourth_part(version)
+ parts = version.split('.')
+ parts[3] = nil if parts.fourth == '0' && parts.third.exclude?('-')
+ parts.compact.join('.')
+ end
+
+ def append_suffix(version)
+ version << '.0.0' if version.count('.') == 0
+ version << '.0' if version.count('.') == 1
+ version
+ end
+ end
+ # rubocop: enable Style/Documentation
+
+ def perform
+ each_sub_batch do |sub_batch|
+ sub_batch.select(:package_id).then do |relation|
+ connection.execute(update_query(relation))
+ end
+ end
+ end
+
+ private
+
+ def update_query(relation)
+ <<-SQL.squish
+ UPDATE packages_nuget_metadata
+ SET normalized_version = v.normalized_version
+ FROM ( VALUES #{package_id_and_normalized_version(relation)} ) AS v(package_id, normalized_version)
+ WHERE packages_nuget_metadata.package_id = v.package_id;
+ SQL
+ end
+
+ def package_id_and_normalized_version(relation)
+ packages = Package
+ .where(id: relation.map(&:package_id))
+ .select(:id, :version)
+ .index_by(&:id)
+
+ # We need a new PackagesNugetMetadatum instance to be able to trigger
+ # #set_normalized_version method that sets the normalized_version.
+ relation.map do |record|
+ new_record = PackagesNugetMetadatum.new(record.attributes)
+ new_record.package = packages[record.package_id]
+ new_record.set_normalized_version
+ "(#{record.package_id}, '#{new_record.normalized_version}')"
+ end.join(', ')
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_project_statistics_storage_size_with_recent_size.rb b/lib/gitlab/background_migration/backfill_project_statistics_storage_size_with_recent_size.rb
new file mode 100644
index 00000000000..40daedffa64
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_project_statistics_storage_size_with_recent_size.rb
@@ -0,0 +1,165 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # rubocop:disable Style/Documentation
+ class BackfillProjectStatisticsStorageSizeWithRecentSize < BatchedMigrationJob
+ RECENT_OBJECTS_SIZE_ENABLED_AT = Date.new(2023, 8, 8).freeze
+
+ class Route < ::ApplicationRecord
+ belongs_to :source, inverse_of: :route, polymorphic: true
+ end
+
+ class Namespace < ::ApplicationRecord
+ self.table_name = 'namespaces'
+ self.inheritance_column = nil # rubocop:disable Database/AvoidInheritanceColumn
+
+ include Routable
+
+ belongs_to :parent, class_name: 'Namespace', inverse_of: 'namespaces'
+
+ has_one :route, -> { where(source_type: 'Namespace') }, inverse_of: :source, foreign_key: :source_id
+
+ has_many :projects, inverse_of: :parent
+ has_many :namespaces, inverse_of: :parent
+ end
+
+ class Project < ::ApplicationRecord
+ self.table_name = 'projects'
+
+ include Routable
+
+ has_one :statistics, class_name: '::Gitlab::BackgroundMigration::BackfillProjectStatisticsStorageSizeWithRecentSize::ProjectStatistics' # rubocop:disable Layout/LineLength
+ has_one :route, -> { where(source_type: 'Project') }, inverse_of: :source, foreign_key: :source_id
+ belongs_to :parent, class_name: 'Namespace', foreign_key: :namespace_id, inverse_of: 'projects'
+
+ delegate :disk_path, to: :storage
+
+ def repository
+ Gitlab::GlRepository::PROJECT.repository_for(self)
+ end
+
+ def storage
+ Storage::Hashed.new(self)
+ end
+ end
+
+ module Storage
+ class Hashed
+ attr_accessor :project
+
+ ROOT_PATH_PREFIX = '@hashed'
+
+ def initialize(project)
+ @project = project
+ end
+
+ def disk_path
+ "#{ROOT_PATH_PREFIX}/#{disk_hash[0..1]}/#{disk_hash[2..3]}/#{disk_hash}"
+ end
+
+ def disk_hash
+ @disk_hash ||= Digest::SHA2.hexdigest(project.id.to_s)
+ end
+ end
+ end
+
+ class ProjectStatistics < ::ApplicationRecord
+ include ::EachBatch
+
+ self.table_name = 'project_statistics'
+
+ belongs_to :project, class_name: '::Gitlab::BackgroundMigration::BackfillProjectStatisticsStorageSizeWithRecentSize::Project' # rubocop:disable Layout/LineLength
+
+ def update_repository_size
+ self.repository_size = project.repository.recent_objects_size.megabytes
+ end
+
+ def update_storage_size(storage_size_components)
+ return unless repository_size > 0
+
+ update_repository_size
+
+ new_storage_size = storage_size_components.sum { |component| method(component).call }
+
+ # Only update storage_size if storage_size needs updating
+ return unless storage_size != new_storage_size
+
+ self.storage_size = new_storage_size
+ save!
+
+ ::Namespaces::ScheduleAggregationWorker.perform_async(project.namespace_id)
+ log_with_data('Scheduled Namespaces::ScheduleAggregationWorker')
+ end
+
+ private
+
+ def log_with_data(log_line)
+ log_info(
+ log_line,
+ project_id: project.id,
+ pipeline_artifacts_size: pipeline_artifacts_size,
+ storage_size: storage_size,
+ namespace_id: project.namespace_id
+ )
+ end
+
+ def log_info(message, **extra)
+ ::Gitlab::BackgroundMigration::Logger.info(
+ migrator: 'BackfillProjectStatisticsStorageSizeWithRecentSize',
+ message: message,
+ **extra
+ )
+ end
+
+ def wiki_size
+ super.to_i
+ end
+
+ def snippets_size
+ super.to_i
+ end
+ end
+
+ scope_to ->(relation) do
+ scope = relation.where('repository_size > 0')
+
+ if Gitlab.dev_or_test_env? || Gitlab.org_or_com?
+ scope = scope.where('updated_at < ?', RECENT_OBJECTS_SIZE_ENABLED_AT)
+ end
+
+ scope
+ end
+
+ operation_name :update_storage_size
+
+ feature_category :consumables_cost_management
+
+ def perform
+ each_sub_batch do |sub_batch|
+ ProjectStatistics.merge(sub_batch).each do |statistics|
+ statistics.update_storage_size(storage_size_components)
+ end
+ end
+ end
+
+ private
+
+ # Overridden in EE
+ def storage_size_components
+ [
+ :repository_size,
+ :wiki_size,
+ :lfs_objects_size,
+ :build_artifacts_size,
+ :packages_size,
+ :snippets_size,
+ :uploads_size
+ ]
+ end
+ end
+ end
+ # rubocop:enable Style/Documentation
+end
+
+Gitlab::BackgroundMigration::BackfillProjectStatisticsStorageSizeWithRecentSize.prepend_mod
diff --git a/lib/gitlab/background_migration/backfill_snippet_repositories.rb b/lib/gitlab/background_migration/backfill_snippet_repositories.rb
index b58f0a3a3e0..15ea4ab26e9 100644
--- a/lib/gitlab/background_migration/backfill_snippet_repositories.rb
+++ b/lib/gitlab/background_migration/backfill_snippet_repositories.rb
@@ -129,7 +129,7 @@ module Gitlab
end
def migration_bot_user
- @migration_bot_user ||= User.migration_bot
+ @migration_bot_user ||= Users::Internal.migration_bot
end
# We sometimes receive invalid path errors from Gitaly if the Snippet filename
diff --git a/lib/gitlab/background_migration/backfill_user_preferences_with_defaults.rb b/lib/gitlab/background_migration/backfill_user_preferences_with_defaults.rb
new file mode 100644
index 00000000000..2fba6e66d48
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_user_preferences_with_defaults.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Backfills the user_preferences table columns with their default values
+ class BackfillUserPreferencesWithDefaults < BatchedMigrationJob
+ operation_name :backfill_user_preferences_with_defaults
+ feature_category :user_profile
+
+ def perform
+ each_sub_batch do |sub_batch|
+ connection.transaction do
+ sub_batch.where(tab_width: nil).update_all(tab_width: 8)
+ sub_batch.where(time_display_relative: nil).update_all(time_display_relative: true)
+ sub_batch.where(render_whitespace_in_code: nil).update_all(render_whitespace_in_code: false)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_users_with_defaults.rb b/lib/gitlab/background_migration/backfill_users_with_defaults.rb
new file mode 100644
index 00000000000..10b4963163d
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_users_with_defaults.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Backfills the users table columns with their default values
+ class BackfillUsersWithDefaults < BatchedMigrationJob
+ operation_name :backfill_users_with_defaults
+ feature_category :user_profile
+
+ def perform
+ each_sub_batch do |sub_batch|
+ connection.transaction do
+ sub_batch.where(project_view: nil).update_all(project_view: 2)
+ sub_batch.where(hide_no_ssh_key: nil).update_all(hide_no_ssh_key: false)
+ sub_batch.where(hide_no_password: nil).update_all(hide_no_password: false)
+ sub_batch.where(notified_of_own_activity: nil).update_all(notified_of_own_activity: false)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_workspace_personal_access_token.rb b/lib/gitlab/background_migration/backfill_workspace_personal_access_token.rb
new file mode 100644
index 00000000000..f71759dc8dd
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_workspace_personal_access_token.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # No op on ce
+ class BackfillWorkspacePersonalAccessToken < BatchedMigrationJob
+ feature_category :remote_development
+ def perform; end
+ end
+ end
+end
+
+Gitlab::BackgroundMigration::BackfillWorkspacePersonalAccessToken.prepend_mod_with('Gitlab::BackgroundMigration::BackfillWorkspacePersonalAccessToken') # rubocop:disable Layout/LineLength
diff --git a/lib/gitlab/background_migration/cleanup_orphaned_routes.rb b/lib/gitlab/background_migration/cleanup_orphaned_routes.rb
index c221f8ea411..d6695eddf02 100644
--- a/lib/gitlab/background_migration/cleanup_orphaned_routes.rb
+++ b/lib/gitlab/background_migration/cleanup_orphaned_routes.rb
@@ -40,7 +40,7 @@ module Gitlab
non_orphaned_namespace_routes.each_batch(column: batch_column, of: sub_batch_size) do |sub_batch|
batch_metrics.time_operation(:fix_missing_namespace_id) do
ApplicationRecord.connection.execute <<~SQL
- WITH route_and_ns(route_id, namespace_id) AS #{::Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH route_and_ns(route_id, namespace_id) AS MATERIALIZED (
#{sub_batch.to_sql}
)
UPDATE routes
diff --git a/lib/gitlab/background_migration/convert_credit_card_validation_data_to_hashes.rb b/lib/gitlab/background_migration/convert_credit_card_validation_data_to_hashes.rb
new file mode 100644
index 00000000000..7bb3b661caa
--- /dev/null
+++ b/lib/gitlab/background_migration/convert_credit_card_validation_data_to_hashes.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Converts a credit card's expiration_date, last_digits, network & holder_name
+ # to hash and store values in new columns
+ class ConvertCreditCardValidationDataToHashes < BatchedMigrationJob
+ operation_name :convert_credit_card_data
+ feature_category :user_profile
+
+ class CreditCardValidation < ApplicationRecord # rubocop:disable Style/Documentation
+ self.table_name = 'user_credit_card_validations'
+ end
+
+ def perform
+ each_sub_batch do |sub_batch|
+ credit_cards = CreditCardValidation.where(user_id: sub_batch)
+
+ credit_card_hashes = credit_cards.map do |c|
+ {
+ user_id: c.user_id,
+ credit_card_validated_at: c.credit_card_validated_at,
+ last_digits_hash: hashed_value(c.last_digits),
+ holder_name_hash: hashed_value(c.holder_name&.downcase),
+ network_hash: hashed_value(c.network&.downcase),
+ expiration_date_hash: hashed_value(c.expiration_date&.to_s)
+ }
+ end
+
+ CreditCardValidation.upsert_all(credit_card_hashes)
+ end
+ end
+
+ def hashed_value(value)
+ Gitlab::CryptoHelper.sha256(value) if value.present?
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/create_compliance_standards_adherence.rb b/lib/gitlab/background_migration/create_compliance_standards_adherence.rb
new file mode 100644
index 00000000000..a79dc107cc7
--- /dev/null
+++ b/lib/gitlab/background_migration/create_compliance_standards_adherence.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # rubocop: disable Style/Documentation
+ class CreateComplianceStandardsAdherence < BatchedMigrationJob
+ feature_category :compliance_management
+
+ def perform
+ # no-op. The logic is defined in EE module.
+ end
+ end
+ # rubocop: enable Style/Documentation
+ end
+end
+
+::Gitlab::BackgroundMigration::CreateComplianceStandardsAdherence.prepend_mod
diff --git a/lib/gitlab/background_migration/fix_first_mentioned_in_commit_at.rb b/lib/gitlab/background_migration/fix_first_mentioned_in_commit_at.rb
index 6de2187b8e3..5225fb6aced 100644
--- a/lib/gitlab/background_migration/fix_first_mentioned_in_commit_at.rb
+++ b/lib/gitlab/background_migration/fix_first_mentioned_in_commit_at.rb
@@ -41,7 +41,7 @@ module Gitlab
.where('issue_metrics.first_mentioned_in_commit_at > first_authored_date.authored_date')
TmpIssueMetrics.connection.execute <<~UPDATE_METRICS
- WITH cte AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH cte AS MATERIALIZED (
#{inner_query.to_sql}
)
UPDATE issue_metrics
diff --git a/lib/gitlab/background_migration/fix_namespace_ids_of_vulnerability_reads.rb b/lib/gitlab/background_migration/fix_namespace_ids_of_vulnerability_reads.rb
new file mode 100644
index 00000000000..ffa1d0f4157
--- /dev/null
+++ b/lib/gitlab/background_migration/fix_namespace_ids_of_vulnerability_reads.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # rubocop: disable Style/Documentation
+ class FixNamespaceIdsOfVulnerabilityReads < BatchedMigrationJob
+ feature_category :vulnerability_management
+
+ def perform
+ # no-op for the FOSS version.
+ end
+ end
+ # rubocop: enable Style/Documentation
+ end
+end
+
+::Gitlab::BackgroundMigration::FixNamespaceIdsOfVulnerabilityReads.prepend_mod
diff --git a/lib/gitlab/background_migration/fix_projects_without_project_feature.rb b/lib/gitlab/background_migration/fix_projects_without_project_feature.rb
index c21f9c1d50f..45a93f158d8 100644
--- a/lib/gitlab/background_migration/fix_projects_without_project_feature.rb
+++ b/lib/gitlab/background_migration/fix_projects_without_project_feature.rb
@@ -22,7 +22,7 @@ module Gitlab
def sql(from_id, to_id)
<<~SQL
- WITH created_records AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH created_records AS MATERIALIZED (
INSERT INTO project_features (
project_id,
merge_requests_access_level,
diff --git a/lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb b/lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb
index 452167d4d61..41326060a05 100644
--- a/lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb
+++ b/lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb
@@ -136,7 +136,7 @@ module Gitlab
# there is no uniq constraint on project_id and type pair, which prevents us from using ON CONFLICT
def create_sql(from_id, to_id)
<<~SQL
- WITH created_records AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH created_records AS MATERIALIZED (
INSERT INTO services (project_id, #{DEFAULTS.keys.map { |key| %("#{key}") }.join(',')}, created_at, updated_at)
#{select_insert_values_sql(from_id, to_id)}
RETURNING *
@@ -149,7 +149,7 @@ module Gitlab
# there is no uniq constraint on project_id and type pair, which prevents us from using ON CONFLICT
def update_sql(from_id, to_id)
<<~SQL
- WITH updated_records AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH updated_records AS MATERIALIZED (
UPDATE services SET active = TRUE
WHERE services.project_id BETWEEN #{Integer(from_id)} AND #{Integer(to_id)} AND services.properties = '{}' AND services.type = '#{Migratable::PrometheusService.type}'
AND #{group_cluster_condition(from_id, to_id)} AND services.active = FALSE
diff --git a/lib/gitlab/background_migration/populate_denormalized_columns_for_sbom_occurrences.rb b/lib/gitlab/background_migration/populate_denormalized_columns_for_sbom_occurrences.rb
new file mode 100644
index 00000000000..0996db01f8a
--- /dev/null
+++ b/lib/gitlab/background_migration/populate_denormalized_columns_for_sbom_occurrences.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # rubocop:disable Style/Documentation
+ class PopulateDenormalizedColumnsForSbomOccurrences < BatchedMigrationJob
+ feature_category :dependency_management
+
+ def perform
+ # no-op for the FOSS version
+ end
+ end
+ # rubocop:enable Style/Documentation
+ end
+end
+
+::Gitlab::BackgroundMigration::PopulateDenormalizedColumnsForSbomOccurrences.prepend_mod
diff --git a/lib/gitlab/background_migration/populate_projects_star_count.rb b/lib/gitlab/background_migration/populate_projects_star_count.rb
index 0790bd98018..97e2d9b81ac 100644
--- a/lib/gitlab/background_migration/populate_projects_star_count.rb
+++ b/lib/gitlab/background_migration/populate_projects_star_count.rb
@@ -42,7 +42,7 @@ module Gitlab
::Gitlab::Database.allow_cross_joins_across_databases(url:
'https://gitlab.com/gitlab-org/gitlab/-/issues/421843') do
ApplicationRecord.connection.execute <<~SQL
- WITH batched_relation AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (#{sub_batch.select(:id).to_sql})
+ WITH batched_relation AS MATERIALIZED (#{sub_batch.select(:id).to_sql})
UPDATE projects
SET star_count = (
SELECT COUNT(*)
diff --git a/lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces.rb b/lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces.rb
index 845a3c16bbe..e21d7951f59 100644
--- a/lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces.rb
+++ b/lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces.rb
@@ -90,7 +90,7 @@ module Gitlab
.select("namespaces.id, namespaces.tmp_project_id")
ApplicationRecord.connection.execute <<~SQL
- WITH cte(project_namespace_id, project_id) AS #{::Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
+ WITH cte(project_namespace_id, project_id) AS MATERIALIZED (
#{projects.to_sql}
)
UPDATE projects
diff --git a/lib/gitlab/background_migration/rebalance_partition_id.rb b/lib/gitlab/background_migration/rebalance_partition_id.rb
deleted file mode 100644
index 7000ae5a856..00000000000
--- a/lib/gitlab/background_migration/rebalance_partition_id.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This rebalances partition_id to fix invalid records in production
- class RebalancePartitionId < BatchedMigrationJob
- INVALID_PARTITION_ID = 101
- VALID_PARTITION_ID = 100
-
- scope_to ->(relation) { relation.where(partition_id: INVALID_PARTITION_ID) }
- operation_name :update_all
- feature_category :continuous_integration
-
- def perform
- each_sub_batch do |sub_batch|
- sub_batch.update_all(partition_id: VALID_PARTITION_ID)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/sync_scan_result_policies.rb b/lib/gitlab/background_migration/sync_scan_result_policies.rb
new file mode 100644
index 00000000000..0b68e4312f3
--- /dev/null
+++ b/lib/gitlab/background_migration/sync_scan_result_policies.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Background migration to sync scan result policies from YAML to DB table by kicking off sync Sidekiq jobs
+ class SyncScanResultPolicies < BatchedMigrationJob
+ feature_category :security_policy_management
+
+ def perform; end
+ end
+ end
+end
+
+Gitlab::BackgroundMigration::SyncScanResultPolicies.prepend_mod
diff --git a/lib/gitlab/background_migration/update_users_set_external_if_service_account.rb b/lib/gitlab/background_migration/update_users_set_external_if_service_account.rb
new file mode 100644
index 00000000000..c8f1847aca3
--- /dev/null
+++ b/lib/gitlab/background_migration/update_users_set_external_if_service_account.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # This class is responsible for updating users external field if service account.
+ class UpdateUsersSetExternalIfServiceAccount < BatchedMigrationJob
+ operation_name :update # This is used as the key on collecting metrics
+ scope_to ->(relation) { relation.where(user_type: HasUserType::USER_TYPES[:service_account]) }
+ feature_category :system_access
+
+ def perform
+ each_sub_batch do |sub_batch|
+ sub_batch.update_all(external: true)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index e785ce558db..7f228c19b6b 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -210,7 +210,11 @@ module Gitlab
source_branch_sha = pull_request.source_branch_sha
target_branch_sha = pull_request.target_branch_sha
- source_branch_sha = project.repository.commit(source_branch_sha)&.sha || source_branch_sha
+
+ source_sha_from_commit_sha = project.repository.commit(source_branch_sha)&.sha
+ source_sha_from_merge_sha = project.repository.commit(pull_request.merge_commit_sha)&.sha
+
+ source_branch_sha = source_sha_from_commit_sha || source_sha_from_merge_sha || source_branch_sha
target_branch_sha = project.repository.commit(target_branch_sha)&.sha || target_branch_sha
merge_request = project.merge_requests.create!(
diff --git a/lib/gitlab/bitbucket_import/importers/pull_request_importer.rb b/lib/gitlab/bitbucket_import/importers/pull_request_importer.rb
new file mode 100644
index 00000000000..d76e08e1039
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/importers/pull_request_importer.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module Importers
+ class PullRequestImporter
+ include Loggable
+
+ def initialize(project, hash)
+ @project = project
+ @formatter = Gitlab::ImportFormatter.new
+ @user_finder = UserFinder.new(project)
+ @object = hash.with_indifferent_access
+ end
+
+ def execute
+ log_info(import_stage: 'import_pull_request', message: 'starting', iid: object[:iid])
+
+ description = ''
+ description += author_line
+ description += object[:description] if object[:description]
+
+ attributes = {
+ iid: object[:iid],
+ title: object[:title],
+ description: description,
+ source_project_id: project.id,
+ source_branch: Gitlab::Git.ref_name(object[:source_branch_name]),
+ source_branch_sha: source_branch_sha,
+ target_project_id: project.id,
+ target_branch: Gitlab::Git.ref_name(object[:target_branch_name]),
+ target_branch_sha: object[:target_branch_sha],
+ state_id: MergeRequest.available_states[object[:state]],
+ author_id: author_id,
+ created_at: object[:created_at],
+ updated_at: object[:updated_at]
+ }
+
+ creator = Gitlab::Import::MergeRequestCreator.new(project)
+
+ merge_request = creator.execute(attributes)
+
+ if merge_request
+ merge_request.assignee_ids = [author_id]
+ merge_request.reviewer_ids = reviewers
+ merge_request.save!
+ end
+
+ log_info(import_stage: 'import_pull_request', message: 'finished', iid: object[:iid])
+ rescue StandardError => e
+ Gitlab::Import::ImportFailureService.track(project_id: project.id, exception: e)
+ end
+
+ private
+
+ attr_reader :object, :project, :formatter, :user_finder
+
+ def author_line
+ return '' if find_user_id
+
+ formatter.author_line(object[:author])
+ end
+
+ def find_user_id
+ user_finder.find_user_id(object[:author])
+ end
+
+ def author_id
+ user_finder.gitlab_user_id(project, object[:author])
+ end
+
+ def reviewers
+ return [] unless object[:reviewers].present?
+
+ object[:reviewers].filter_map do |reviewer|
+ user_finder.find_user_id(reviewer)
+ end
+ end
+
+ def source_branch_sha
+ project.repository.commit(object[:source_branch_sha])&.sha ||
+ project.repository.commit(object[:merge_commit_sha])&.sha ||
+ object[:source_branch_sha]
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/importers/pull_requests_importer.rb b/lib/gitlab/bitbucket_import/importers/pull_requests_importer.rb
new file mode 100644
index 00000000000..1c7ce7f2f3a
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/importers/pull_requests_importer.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module Importers
+ class PullRequestsImporter
+ include ParallelScheduling
+
+ def execute
+ log_info(import_stage: 'import_pull_requests', message: 'importing pull requests')
+
+ pull_requests = client.pull_requests(project.import_source)
+
+ pull_requests.each do |pull_request|
+ job_waiter.jobs_remaining += 1
+
+ next if already_enqueued?(pull_request)
+
+ job_delay = calculate_job_delay(job_waiter.jobs_remaining)
+
+ sidekiq_worker_class.perform_in(job_delay, project.id, pull_request.to_hash, job_waiter.key)
+
+ mark_as_enqueued(pull_request)
+ end
+
+ job_waiter
+ rescue StandardError => e
+ track_import_failure!(project, exception: e)
+ end
+
+ private
+
+ def sidekiq_worker_class
+ ImportPullRequestWorker
+ end
+
+ def collection_method
+ :pull_requests
+ end
+
+ def id_for_already_enqueued_cache(object)
+ object.iid
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/importers/repository_importer.rb b/lib/gitlab/bitbucket_import/importers/repository_importer.rb
new file mode 100644
index 00000000000..7b0362b6ec6
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/importers/repository_importer.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module Importers
+ class RepositoryImporter
+ include Loggable
+
+ def initialize(project)
+ @project = project
+ end
+
+ def execute
+ log_info(import_stage: 'import_repository', message: 'starting import')
+
+ if project.empty_repo?
+ project.repository.import_repository(project.import_url)
+ project.repository.fetch_as_mirror(project.import_url, refmap: refmap)
+
+ validate_repository_size!
+
+ update_clone_time
+ end
+
+ import_wiki
+
+ log_info(import_stage: 'import_repository', message: 'finished import')
+
+ true
+ rescue ::Gitlab::Git::CommandError => e
+ Gitlab::ErrorTracking.log_exception(
+ e, import_stage: 'import_repository', message: 'failed import', error: e.message
+ )
+
+ # Expire cache to prevent scenarios such as:
+ # 1. First import failed, but the repo was imported successfully, so +exists?+ returns true
+ # 2. Retried import, repo is broken or not imported but +exists?+ still returns true
+ project.repository.expire_content_cache if project.repository_exists?
+
+ raise
+ end
+
+ private
+
+ attr_reader :project
+
+ def refmap
+ # We omit :heads and :tags since these are fetched in the import_repository
+ ['+refs/pull-requests/*/to:refs/merge-requests/*/head']
+ end
+
+ def import_wiki
+ return if project.wiki.repository_exists?
+
+ project.wiki.repository.import_repository(wiki.import_url)
+ rescue StandardError => e
+ Gitlab::ErrorTracking.log_exception(
+ e, import_stage: 'import_repository', message: 'failed to import wiki', error: e.message
+ )
+ end
+
+ def wiki
+ WikiFormatter.new(project)
+ end
+
+ def update_clone_time
+ project.touch(:last_repository_updated_at)
+ end
+
+ def validate_repository_size!
+ # Defined in EE
+ end
+ end
+ end
+ end
+end
+
+Gitlab::BitbucketImport::Importers::RepositoryImporter.prepend_mod
diff --git a/lib/gitlab/bitbucket_import/loggable.rb b/lib/gitlab/bitbucket_import/loggable.rb
new file mode 100644
index 00000000000..eda3cc96d4d
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/loggable.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module Loggable
+ def log_debug(messages)
+ logger.debug(log_data(messages))
+ end
+
+ def log_info(messages)
+ logger.info(log_data(messages))
+ end
+
+ def log_warn(messages)
+ logger.warn(log_data(messages))
+ end
+
+ def log_error(messages)
+ logger.error(log_data(messages))
+ end
+
+ private
+
+ def logger
+ Gitlab::BitbucketImport::Logger
+ end
+
+ def log_data(messages)
+ messages.merge(log_base_data)
+ end
+
+ def log_base_data
+ {
+ class: self.class.name,
+ project_id: project.id,
+ project_path: project.full_path
+ }
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/logger.rb b/lib/gitlab/bitbucket_import/logger.rb
new file mode 100644
index 00000000000..1f4d175f8a3
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/logger.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ class Logger < ::Gitlab::Import::Logger
+ def default_attributes
+ super.merge(import_type: :bitbucket)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/parallel_importer.rb b/lib/gitlab/bitbucket_import/parallel_importer.rb
new file mode 100644
index 00000000000..1563261fa4a
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/parallel_importer.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ class ParallelImporter
+ def self.async?
+ true
+ end
+
+ def self.imports_repository?
+ true
+ end
+
+ def self.track_start_import(project)
+ Gitlab::Import::Metrics.new(:bitbucket_importer, project).track_start_import
+ end
+
+ def initialize(project)
+ @project = project
+ end
+
+ def execute
+ Gitlab::Import::SetAsyncJid.set_jid(project.import_state)
+
+ Stage::ImportRepositoryWorker
+ .with_status
+ .perform_async(project.id)
+
+ true
+ end
+
+ private
+
+ attr_reader :project
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/parallel_scheduling.rb b/lib/gitlab/bitbucket_import/parallel_scheduling.rb
new file mode 100644
index 00000000000..f4df9a35526
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/parallel_scheduling.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ module ParallelScheduling
+ include Loggable
+
+ attr_reader :project, :already_enqueued_cache_key, :job_waiter_cache_key
+
+ # The base cache key to use for tracking already enqueued objects.
+ ALREADY_ENQUEUED_CACHE_KEY =
+ 'bitbucket-importer/already-enqueued/%{project}/%{collection}'
+
+ # The base cache key to use for storing job waiter key
+ JOB_WAITER_CACHE_KEY =
+ 'bitbucket-importer/job-waiter/%{project}/%{collection}'
+
+ BATCH_SIZE = 100
+
+ # project - An instance of `Project`.
+ def initialize(project)
+ @project = project
+
+ @already_enqueued_cache_key =
+ format(ALREADY_ENQUEUED_CACHE_KEY, project: project.id, collection: collection_method)
+ @job_waiter_cache_key =
+ format(JOB_WAITER_CACHE_KEY, project: project.id, collection: collection_method)
+ end
+
+ private
+
+ def client
+ @client ||= Bitbucket::Client.new(project.import_data.credentials)
+ end
+
+ # Returns the ID to use for the cache used for checking if an object has
+ # already been enqueued or not.
+ #
+ # object - The object we may want to import.
+ def id_for_already_enqueued_cache(object)
+ raise NotImplementedError
+ end
+
+ # The Sidekiq worker class used for scheduling the importing of objects in
+ # parallel.
+ def sidekiq_worker_class
+ raise NotImplementedError
+ end
+
+ # The name of the method to call to retrieve the data to import.
+ def collection_method
+ raise NotImplementedError
+ end
+
+ def job_waiter
+ @job_waiter ||= begin
+ key = Gitlab::Cache::Import::Caching.read(job_waiter_cache_key)
+ key ||= Gitlab::Cache::Import::Caching.write(job_waiter_cache_key, JobWaiter.generate_key)
+
+ JobWaiter.new(0, key)
+ end
+ end
+
+ def already_enqueued?(object)
+ id = id_for_already_enqueued_cache(object)
+
+ Gitlab::Cache::Import::Caching.set_includes?(already_enqueued_cache_key, id)
+ end
+
+ # Marks the given object as "already enqueued".
+ def mark_as_enqueued(object)
+ id = id_for_already_enqueued_cache(object)
+
+ Gitlab::Cache::Import::Caching.set_add(already_enqueued_cache_key, id)
+ end
+
+ def calculate_job_delay(job_index)
+ multiplier = (job_index / BATCH_SIZE)
+
+ (multiplier * 1.minute) + 1.second
+ end
+
+ def track_import_failure!(project, exception:, **args)
+ Gitlab::Import::ImportFailureService.track(
+ project_id: project.id,
+ error_source: self.class.name,
+ exception: exception,
+ **args
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/user_finder.rb b/lib/gitlab/bitbucket_import/user_finder.rb
new file mode 100644
index 00000000000..70ed94351d5
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/user_finder.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BitbucketImport
+ class UserFinder
+ USER_ID_FOR_AUTHOR_CACHE_KEY = 'bitbucket-importer/user-finder/%{project_id}/%{author}'
+ CACHE_USER_ID_NOT_FOUND = -1
+
+ attr_reader :project
+
+ def initialize(project)
+ @project = project
+ end
+
+ def find_user_id(author)
+ return unless author
+
+ cache_key = build_cache_key(author)
+ cached_id = cache.read_integer(cache_key)
+
+ return if cached_id == CACHE_USER_ID_NOT_FOUND
+ return cached_id if cached_id
+
+ id = User.by_provider_and_extern_uid(:bitbucket, author).select(:id).first&.id
+
+ cache.write(cache_key, id || CACHE_USER_ID_NOT_FOUND)
+
+ id
+ end
+
+ def gitlab_user_id(project, username)
+ find_user_id(username) || project.creator_id
+ end
+
+ private
+
+ def cache
+ Cache::Import::Caching
+ end
+
+ def build_cache_key(author)
+ format(USER_ID_FOR_AUTHOR_CACHE_KEY, project_id: project.id, author: author)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_server_import/importer.rb b/lib/gitlab/bitbucket_server_import/importer.rb
deleted file mode 100644
index 1871dd3a89d..00000000000
--- a/lib/gitlab/bitbucket_server_import/importer.rb
+++ /dev/null
@@ -1,468 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BitbucketServerImport
- class Importer
- include Loggable
-
- attr_reader :recover_missing_commits
- attr_reader :project, :project_key, :repository_slug, :client, :errors, :users, :already_imported_cache_key
-
- BATCH_SIZE = 100
- # The base cache key to use for tracking already imported objects.
- ALREADY_IMPORTED_CACHE_KEY =
- 'bitbucket_server-importer/already-imported/%{project}/%{collection}'
-
- TempBranch = Struct.new(:name, :sha)
-
- def self.imports_repository?
- true
- end
-
- def self.refmap
- # We omit :heads and :tags since these are fetched in the import_repository
- ['+refs/pull-requests/*/to:refs/merge-requests/*/head']
- end
-
- # Unlike GitHub, you can't grab the commit SHAs for pull requests that
- # have been closed but not merged even though Bitbucket has these
- # commits internally. We can recover these pull requests by creating a
- # branch with the Bitbucket REST API, but by default we turn this
- # behavior off.
- def initialize(project, recover_missing_commits: false)
- @project = project
- @recover_missing_commits = recover_missing_commits
- @project_key = project.import_data.data['project_key']
- @repository_slug = project.import_data.data['repo_slug']
- @client = BitbucketServer::Client.new(project.import_data.credentials)
- @formatter = Gitlab::ImportFormatter.new
- @errors = []
- @users = {}
- @temp_branches = []
- @already_imported_cache_key = ALREADY_IMPORTED_CACHE_KEY %
- { project: project.id, collection: collection_method }
- end
-
- def collection_method
- :pull_requests
- end
-
- def execute
- import_repository
- import_pull_requests
- download_lfs_objects
- delete_temp_branches
- handle_errors
- metrics.track_finished_import
-
- log_info(import_stage: "complete")
-
- Gitlab::Cache::Import::Caching.expire(already_imported_cache_key, Gitlab::Cache::Import::Caching::SHORTER_TIMEOUT)
- true
- end
-
- private
-
- def handle_errors
- return unless errors.any?
-
- project.import_state.update_column(:last_error, {
- message: 'The remote data could not be fully imported.',
- errors: errors
- }.to_json)
- end
-
- def find_user_id(by:, value:)
- return unless value
-
- return users[value] if users.key?(value)
-
- user = if by == :email
- User.find_by_any_email(value, confirmed: true)
- else
- User.find_by_username(value)
- end
-
- users[value] = user&.id
-
- user&.id
- end
-
- def repo
- @repo ||= client.repo(project_key, repository_slug)
- end
-
- def sha_exists?(sha)
- project.repository.commit(sha)
- end
-
- def temp_branch_name(pull_request, suffix)
- "gitlab/import/pull-request/#{pull_request.iid}/#{suffix}"
- end
-
- # This method restores required SHAs that GitLab needs to create diffs
- # into branch names as the following:
- #
- # gitlab/import/pull-request/N/{to,from}
- def restore_branches(pull_requests)
- shas_to_restore = []
-
- pull_requests.each do |pull_request|
- shas_to_restore << TempBranch.new(temp_branch_name(pull_request, :from),
- pull_request.source_branch_sha)
- shas_to_restore << TempBranch.new(temp_branch_name(pull_request, :to),
- pull_request.target_branch_sha)
- end
-
- # Create the branches on the Bitbucket Server first
- created_branches = restore_branch_shas(shas_to_restore)
-
- @temp_branches += created_branches
- # Now sync the repository so we get the new branches
- import_repository unless created_branches.empty?
- end
-
- def restore_branch_shas(shas_to_restore)
- shas_to_restore.each_with_object([]) do |temp_branch, branches_created|
- branch_name = temp_branch.name
- sha = temp_branch.sha
-
- next if sha_exists?(sha)
-
- begin
- client.create_branch(project_key, repository_slug, branch_name, sha)
- branches_created << temp_branch
- rescue BitbucketServer::Connection::ConnectionError => e
- log_warn(message: "Unable to recreate branch", sha: sha, error: e.message)
- end
- end
- end
-
- def import_repository
- log_info(import_stage: 'import_repository', message: 'starting import')
-
- project.repository.import_repository(project.import_url)
- project.repository.fetch_as_mirror(project.import_url, refmap: self.class.refmap)
-
- log_info(import_stage: 'import_repository', message: 'finished import')
- rescue ::Gitlab::Git::CommandError => e
- Gitlab::ErrorTracking.log_exception(
- e,
- import_stage: 'import_repository', message: 'failed import', error: e.message
- )
-
- # Expire cache to prevent scenarios such as:
- # 1. First import failed, but the repo was imported successfully, so +exists?+ returns true
- # 2. Retried import, repo is broken or not imported but +exists?+ still returns true
- project.repository.expire_content_cache if project.repository_exists?
-
- raise
- end
-
- def download_lfs_objects
- result = Projects::LfsPointers::LfsImportService.new(project).execute
-
- if result[:status] == :error
- errors << { type: :lfs_objects, errors: "The Lfs import process failed. #{result[:message]}" }
- end
- end
-
- # Bitbucket Server keeps tracks of references for open pull requests in
- # refs/heads/pull-requests, but closed and merged requests get moved
- # into hidden internal refs under stash-refs/pull-requests. Unless the
- # SHAs involved are at the tip of a branch or tag, there is no way to
- # retrieve the server for those commits.
- #
- # To avoid losing history, we use the Bitbucket API to re-create the branch
- # on the remote server. Then we have to issue a `git fetch` to download these
- # branches.
- def import_pull_requests
- page = 0
-
- log_info(import_stage: 'import_pull_requests', message: "starting")
-
- loop do
- log_debug(import_stage: 'import_pull_requests', message: "importing page #{page} and batch-size #{BATCH_SIZE} from #{page * BATCH_SIZE} to #{(page + 1) * BATCH_SIZE}")
-
- pull_requests = client.pull_requests(project_key, repository_slug, page_offset: page, limit: BATCH_SIZE).to_a
-
- break if pull_requests.empty?
-
- # Creating branches on the server and fetching the newly-created branches
- # may take a number of network round-trips. This used to be done in batches to
- # avoid doing a git fetch for every new branch, as the whole process is now
- # batched, we do not need to separately do this in batches.
- restore_branches(pull_requests) if recover_missing_commits
-
- pull_requests.each do |pull_request|
- if already_imported?(pull_request)
- log_info(import_stage: 'import_pull_requests', message: 'already imported', iid: pull_request.iid)
- else
- import_bitbucket_pull_request(pull_request)
- end
- rescue StandardError => e
- Gitlab::ErrorTracking.log_exception(
- e,
- import_stage: 'import_pull_requests', iid: pull_request.iid, error: e.message
- )
-
- backtrace = Gitlab::BacktraceCleaner.clean_backtrace(e.backtrace)
- errors << { type: :pull_request, iid: pull_request.iid, errors: e.message, backtrace: backtrace.join("\n"), raw_response: pull_request.raw }
- end
-
- log_debug(import_stage: 'import_pull_requests', message: "finished page #{page} and batch-size #{BATCH_SIZE}")
- page += 1
- end
- end
-
- # Returns true if the given object has already been imported, false
- # otherwise.
- #
- # object - The object to check.
- def already_imported?(pull_request)
- Gitlab::Cache::Import::Caching.set_includes?(already_imported_cache_key, pull_request.iid)
- end
-
- # Marks the given object as "already imported".
- def mark_as_imported(pull_request)
- Gitlab::Cache::Import::Caching.set_add(already_imported_cache_key, pull_request.iid)
- end
-
- def delete_temp_branches
- @temp_branches.each do |branch|
- client.delete_branch(project_key, repository_slug, branch.name, branch.sha)
- project.repository.delete_branch(branch.name)
- rescue BitbucketServer::Connection::ConnectionError => e
- Gitlab::ErrorTracking.log_exception(
- e,
- import_stage: 'delete_temp_branches', branch: branch.name, error: e.message
- )
-
- @errors << { type: :delete_temp_branches, branch_name: branch.name, errors: e.message }
- end
- end
-
- def import_bitbucket_pull_request(pull_request)
- log_info(import_stage: 'import_bitbucket_pull_requests', message: 'starting', iid: pull_request.iid)
-
- description = ''
- description += author_line(pull_request)
- description += pull_request.description if pull_request.description
-
- attributes = {
- iid: pull_request.iid,
- title: pull_request.title,
- description: description,
- reviewer_ids: reviewers(pull_request.reviewers),
- source_project_id: project.id,
- source_branch: Gitlab::Git.ref_name(pull_request.source_branch_name),
- source_branch_sha: pull_request.source_branch_sha,
- target_project_id: project.id,
- target_branch: Gitlab::Git.ref_name(pull_request.target_branch_name),
- target_branch_sha: pull_request.target_branch_sha,
- state_id: MergeRequest.available_states[pull_request.state],
- author_id: author_id(pull_request),
- created_at: pull_request.created_at,
- updated_at: pull_request.updated_at
- }
-
- creator = Gitlab::Import::MergeRequestCreator.new(project)
- merge_request = creator.execute(attributes)
-
- if merge_request.persisted?
- import_pull_request_comments(pull_request, merge_request)
-
- metrics.merge_requests_counter.increment
- end
-
- log_info(import_stage: 'import_bitbucket_pull_requests', message: 'finished', iid: pull_request.iid)
- mark_as_imported(pull_request)
- end
-
- def import_pull_request_comments(pull_request, merge_request)
- log_info(import_stage: 'import_pull_request_comments', message: 'starting', iid: merge_request.iid)
-
- comments, other_activities = client.activities(project_key, repository_slug, pull_request.iid).partition(&:comment?)
-
- merge_event = other_activities.find(&:merge_event?)
- import_merge_event(merge_request, merge_event) if merge_event
-
- inline_comments, pr_comments = comments.partition(&:inline_comment?)
-
- import_inline_comments(inline_comments.map(&:comment), merge_request)
- import_standalone_pr_comments(pr_comments.map(&:comment), merge_request)
-
- log_info(import_stage: 'import_pull_request_comments', message: 'finished', iid: merge_request.iid,
- merge_event_found: merge_event.present?,
- inline_comments_count: inline_comments.count,
- standalone_pr_comments: pr_comments.count)
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def import_merge_event(merge_request, merge_event)
- log_info(import_stage: 'import_merge_event', message: 'starting', iid: merge_request.iid)
-
- committer = merge_event.committer_email
-
- user_id = find_user_id(by: :email, value: committer) || project.creator_id
- timestamp = merge_event.merge_timestamp
- merge_request.update({ merge_commit_sha: merge_event.merge_commit })
- metric = MergeRequest::Metrics.find_or_initialize_by(merge_request: merge_request)
- metric.update(merged_by_id: user_id, merged_at: timestamp)
-
- log_info(import_stage: 'import_merge_event', message: 'finished', iid: merge_request.iid)
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def import_inline_comments(inline_comments, merge_request)
- log_info(import_stage: 'import_inline_comments', message: 'starting', iid: merge_request.iid)
-
- inline_comments.each do |comment|
- position = build_position(merge_request, comment)
- parent = create_diff_note(merge_request, comment, position)
-
- next unless parent&.persisted?
-
- discussion_id = parent.discussion_id
-
- comment.comments.each do |reply|
- create_diff_note(merge_request, reply, position, discussion_id)
- end
- end
-
- log_info(import_stage: 'import_inline_comments', message: 'finished', iid: merge_request.iid)
- end
-
- def create_diff_note(merge_request, comment, position, discussion_id = nil)
- attributes = pull_request_comment_attributes(comment)
- attributes.merge!(position: position, type: 'DiffNote')
- attributes[:discussion_id] = discussion_id if discussion_id
-
- note = merge_request.notes.build(attributes)
-
- if note.valid?
- note.save
- return note
- end
-
- log_info(import_stage: 'create_diff_note', message: 'creating fallback DiffNote', iid: merge_request.iid)
-
- # Bitbucket Server supports the ability to comment on any line, not just the
- # line in the diff. If we can't add the note as a DiffNote, fallback to creating
- # a regular note.
- create_fallback_diff_note(merge_request, comment, position)
- rescue StandardError => e
- Gitlab::ErrorTracking.log_exception(
- e,
- import_stage: 'create_diff_note', comment_id: comment.id, error: e.message
- )
-
- errors << { type: :pull_request, id: comment.id, errors: e.message }
- nil
- end
-
- def create_fallback_diff_note(merge_request, comment, position)
- attributes = pull_request_comment_attributes(comment)
- note = "*Comment on"
-
- note += " #{position.old_path}:#{position.old_line} -->" if position.old_line
- note += " #{position.new_path}:#{position.new_line}" if position.new_line
- note += "*\n\n#{comment.note}"
-
- attributes[:note] = note
- merge_request.notes.create!(attributes)
- end
-
- def build_position(merge_request, pr_comment)
- params = {
- diff_refs: merge_request.diff_refs,
- old_path: pr_comment.file_path,
- new_path: pr_comment.file_path,
- old_line: pr_comment.old_pos,
- new_line: pr_comment.new_pos
- }
-
- Gitlab::Diff::Position.new(params)
- end
-
- def import_standalone_pr_comments(pr_comments, merge_request)
- pr_comments.each do |comment|
- merge_request.notes.create!(pull_request_comment_attributes(comment))
-
- comment.comments.each do |replies|
- merge_request.notes.create!(pull_request_comment_attributes(replies))
- end
- rescue StandardError => e
- Gitlab::ErrorTracking.log_exception(
- e,
- import_stage: 'import_standalone_pr_comments', merge_request_id: merge_request.id, comment_id: comment.id, error: e.message
- )
-
- errors << { type: :pull_request, comment_id: comment.id, errors: e.message }
- end
- end
-
- def pull_request_comment_attributes(comment)
- author = uid(comment)
- note = ''
-
- unless author
- author = project.creator_id
- note = "*By #{comment.author_username} (#{comment.author_email})*\n\n"
- end
-
- note +=
- # Provide some context for replying
- if comment.parent_comment
- "> #{comment.parent_comment.note.truncate(80)}\n\n#{comment.note}"
- else
- comment.note
- end
-
- {
- project: project,
- note: note,
- author_id: author,
- created_at: comment.created_at,
- updated_at: comment.updated_at
- }
- end
-
- def metrics
- @metrics ||= Gitlab::Import::Metrics.new(:bitbucket_server_importer, @project)
- end
-
- def author_line(rep_object)
- return '' if uid(rep_object)
-
- @formatter.author_line(rep_object.author)
- end
-
- def author_id(rep_object)
- uid(rep_object) || project.creator_id
- end
-
- def uid(rep_object)
- # We want this to only match either username or email depending on the flag state.
- # There should be no fall-through.
- if Feature.enabled?(:bitbucket_server_user_mapping_by_username, type: :ops)
- find_user_id(by: :username, value: rep_object.author_username)
- else
- find_user_id(by: :email, value: rep_object.author_email)
- end
- end
-
- def reviewers(reviewers)
- return [] unless reviewers.present?
-
- reviewers.filter_map do |reviewer|
- if Feature.enabled?(:bitbucket_server_user_mapping_by_username, type: :ops)
- find_user_id(by: :username, value: reviewer.dig('user', 'slug'))
- else
- find_user_id(by: :email, value: reviewer.dig('user', 'emailAddress'))
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/checks/matching_merge_request.rb b/lib/gitlab/checks/matching_merge_request.rb
index 15178597a99..d0644856105 100644
--- a/lib/gitlab/checks/matching_merge_request.rb
+++ b/lib/gitlab/checks/matching_merge_request.rb
@@ -26,8 +26,10 @@ module Gitlab
# sessions, replication lag could erroneously cause step 5 to
# report no matching merge requests. To avoid this, we check
# the write location to ensure the replica can make this query.
+ # Adding use_primary_on_empty_location: true for extra precaution in case there happens to be
+ # no LSN saved for the project then we will use the primary.
track_session_metrics do
- ::ApplicationRecord.sticking.select_valid_host(:project, @project.id)
+ ::ApplicationRecord.sticking.find_caught_up_replica(:project, @project.id, use_primary_on_empty_location: true)
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/lib/gitlab/ci/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb
index 42a8b561d34..d581fbfda42 100644
--- a/lib/gitlab/ci/ansi2html.rb
+++ b/lib/gitlab/ci/ansi2html.rb
@@ -299,7 +299,7 @@ module Gitlab
end
def handle_new_line
- write_in_tag %{<br/>}
+ write_in_tag %(<br/>)
close_open_tags if @sections.any? && @lineno_in_section == 0
@lineno_in_section += 1
@@ -324,7 +324,7 @@ module Gitlab
return if @sections.include?(section)
@sections << section
- write_raw %{<div class="section-start" data-timestamp="#{timestamp}" data-section="#{data_section_names}" role="button"></div>}
+ write_raw %(<div class="section-start" data-timestamp="#{timestamp}" data-section="#{data_section_names}" role="button"></div>)
@lineno_in_section = 0
end
@@ -333,7 +333,7 @@ module Gitlab
# close all sections up to section
until @sections.empty?
- write_raw %{<div class="section-end" data-section="#{data_section_names}"></div>}
+ write_raw %(<div class="section-end" data-section="#{data_section_names}"></div>)
last_section = @sections.pop
break if section == last_section
@@ -423,9 +423,9 @@ module Gitlab
close_open_tags
@out << if css_classes.any?
- %{<span class="#{css_classes.join(' ')}">}
+ %(<span class="#{css_classes.join(' ')}">)
else
- %{<span>}
+ %(<span>)
end
@n_open_tags += 1
@@ -433,7 +433,7 @@ module Gitlab
def close_open_tags
while @n_open_tags > 0
- @out << %{</span>}
+ @out << %(</span>)
@n_open_tags -= 1
end
end
diff --git a/lib/gitlab/ci/build/artifacts/metadata.rb b/lib/gitlab/ci/build/artifacts/metadata.rb
index d0ab4916c90..5748b8e34cf 100644
--- a/lib/gitlab/ci/build/artifacts/metadata.rb
+++ b/lib/gitlab/ci/build/artifacts/metadata.rb
@@ -18,7 +18,11 @@ module Gitlab
def initialize(stream, path, **opts)
@stream = stream
- @path = path
+
+ # Ensure to remove any ./ prefix from the path
+ # so that the pattern matching will work as expected
+ @path = path.gsub(%r{^\./}, '')
+
@opts = opts
@full_version = read_version
end
@@ -59,7 +63,7 @@ module Gitlab
entries = {}
child_pattern = '[^/]*/?$' unless @opts[:recursive]
- match_pattern = /^#{Regexp.escape(@path)}#{child_pattern}/
+ match_pattern = /^#{Regexp.escape(path)}#{child_pattern}/
until gz.eof?
begin
diff --git a/lib/gitlab/ci/build/duration_parser.rb b/lib/gitlab/ci/build/duration_parser.rb
index 9385dccd5f3..97049a4f876 100644
--- a/lib/gitlab/ci/build/duration_parser.rb
+++ b/lib/gitlab/ci/build/duration_parser.rb
@@ -41,7 +41,7 @@ module Gitlab
def parse
return if never?
- ChronicDuration.parse(value)
+ ChronicDuration.parse(value, use_complete_matcher: true)
end
def validation_cache
diff --git a/lib/gitlab/ci/components/instance_path.rb b/lib/gitlab/ci/components/instance_path.rb
index e0ef598da1b..17c784c4d54 100644
--- a/lib/gitlab/ci/components/instance_path.rb
+++ b/lib/gitlab/ci/components/instance_path.rb
@@ -7,17 +7,19 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
LATEST_VERSION_KEYWORD = '~latest'
+ TEMPLATES_DIR = 'templates'
def self.match?(address)
address.include?('@') && address.start_with?(Settings.gitlab_ci['component_fqdn'])
end
- attr_reader :host
+ attr_reader :host, :project_file_path
def initialize(address:, content_filename:)
@full_path, @version = address.to_s.split('@', 2)
@content_filename = content_filename
@host = Settings.gitlab_ci['component_fqdn']
+ @project_file_path = nil
end
def fetch_content!(current_user:)
@@ -26,7 +28,7 @@ module Gitlab
raise Gitlab::Access::AccessDeniedError unless Ability.allowed?(current_user, :download_code, project)
- project.repository.blob_data_at(sha, project_file_path)
+ content(simple_template_path) || content(complex_template_path) || content(legacy_template_path)
end
def project
@@ -34,13 +36,6 @@ module Gitlab
end
strong_memoize_attr :project
- def project_file_path
- return unless project
-
- component_dir = instance_path.delete_prefix(project.full_path)
- File.join(component_dir, @content_filename).delete_prefix('/')
- end
-
def sha
return unless project
return latest_version_sha if version == LATEST_VERSION_KEYWORD
@@ -57,6 +52,11 @@ module Gitlab
@full_path.delete_prefix(host)
end
+ def component_path
+ instance_path.delete_prefix(project.full_path).delete_prefix('/')
+ end
+ strong_memoize_attr :component_path
+
# Given a path like "my-org/sub-group/the-project/path/to/component"
# find the project "my-org/sub-group/the-project" by looking at all possible paths.
def find_project_by_component_path(path)
@@ -75,6 +75,36 @@ module Gitlab
def latest_version_sha
project.releases.latest&.sha
end
+
+ # A simple template consists of a single file
+ def simple_template_path
+ # Extract this line and move to fetch_content once we remove legacy fetching
+ return unless templates_dir_exists? && component_path.index('/').nil?
+
+ @project_file_path = File.join(TEMPLATES_DIR, "#{component_path}.yml")
+ end
+
+ # A complex template is directory-based and may consist of multiple files.
+ # Given a path like "my-org/sub-group/the-project/templates/component"
+ # returns the entry point path: "templates/component/template.yml".
+ def complex_template_path
+ # Extract this line and move to fetch_content once we remove legacy fetching
+ return unless templates_dir_exists? && component_path.index('/').nil?
+
+ @project_file_path = File.join(TEMPLATES_DIR, component_path, @content_filename)
+ end
+
+ def legacy_template_path
+ @project_file_path = File.join(component_path, @content_filename).delete_prefix('/')
+ end
+
+ def templates_dir_exists?
+ project.repository.tree.trees.map(&:name).include?(TEMPLATES_DIR)
+ end
+
+ def content(path)
+ project.repository.blob_data_at(sha, path)
+ end
end
end
end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 0c293c3f0ef..73d329930a5 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -161,6 +161,7 @@ module Gitlab
def build_context(project:, pipeline:, sha:, user:, parent_pipeline:, pipeline_config:)
Config::External::Context.new(
project: project,
+ pipeline: pipeline,
sha: sha || find_sha(project),
user: user,
parent_pipeline: parent_pipeline,
diff --git a/lib/gitlab/ci/config/entry/bridge.rb b/lib/gitlab/ci/config/entry/bridge.rb
index ee99354cb28..1119afab24a 100644
--- a/lib/gitlab/ci/config/entry/bridge.rb
+++ b/lib/gitlab/ci/config/entry/bridge.rb
@@ -51,7 +51,7 @@ module Gitlab
entry :parallel, Entry::Product::Parallel,
description: 'Parallel configuration for this job.',
inherit: false,
- metadata: { allowed_strategies: %i(matrix) }
+ metadata: { allowed_strategies: %i[matrix] }
attributes :when, :allow_failure, :parallel
diff --git a/lib/gitlab/ci/config/entry/default.rb b/lib/gitlab/ci/config/entry/default.rb
index e996b6b1312..476b928e471 100644
--- a/lib/gitlab/ci/config/entry/default.rb
+++ b/lib/gitlab/ci/config/entry/default.rb
@@ -14,7 +14,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Inheritable
ALLOWED_KEYS = %i[before_script after_script hooks cache image services
- interruptible timeout retry tags artifacts].freeze
+ interruptible timeout retry tags artifacts id_tokens].freeze
validations do
validates :config, allowed_keys: ALLOWED_KEYS
@@ -65,6 +65,11 @@ module Gitlab
description: 'Default artifacts.',
inherit: false
+ entry :id_tokens, ::Gitlab::Config::Entry::ComposableHash,
+ description: 'Configured JWTs for this job',
+ inherit: false,
+ metadata: { composable_class: ::Gitlab::Ci::Config::Entry::IdToken }
+
private
def overwrite_entry(deps, key, current_entry)
diff --git a/lib/gitlab/ci/config/entry/include/rules.rb b/lib/gitlab/ci/config/entry/include/rules.rb
index 71418e6752d..a3799b36ece 100644
--- a/lib/gitlab/ci/config/entry/include/rules.rb
+++ b/lib/gitlab/ci/config/entry/include/rules.rb
@@ -19,11 +19,6 @@ module Gitlab
validates :config, type: Array
end
- # Remove this method when FF `ci_refactor_external_rules` is removed
- def value
- Feature.enabled?(:ci_refactor_external_rules) ? super : @config
- end
-
def composable_class
Entry::Include::Rules::Rule
end
diff --git a/lib/gitlab/ci/config/entry/include/rules/rule.rb b/lib/gitlab/ci/config/entry/include/rules/rule.rb
index 1a68e95913c..df8509eecc0 100644
--- a/lib/gitlab/ci/config/entry/include/rules/rule.rb
+++ b/lib/gitlab/ci/config/entry/include/rules/rule.rb
@@ -7,13 +7,17 @@ module Gitlab
class Include
class Rules::Rule < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
+ include ::Gitlab::Config::Entry::Configurable
include ::Gitlab::Config::Entry::Attributable
- ALLOWED_KEYS = %i[if exists when].freeze
+ ALLOWED_KEYS = %i[if exists when changes].freeze
ALLOWED_WHEN = %w[never always].freeze
attributes :if, :exists, :when
+ entry :changes, Entry::Rules::Rule::Changes,
+ description: 'File change condition rule.'
+
validations do
validates :config, presence: true
validates :config, type: { with: Hash }
@@ -27,7 +31,9 @@ module Gitlab
end
def value
- Feature.enabled?(:ci_refactor_external_rules) ? config.compact : super
+ config.merge(
+ changes: (changes_value if changes_defined?)
+ ).compact
end
end
end
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index d31d1b366c3..c40d665f320 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -13,7 +13,7 @@ module Gitlab
ALLOWED_WHEN = %w[on_success on_failure always manual delayed].freeze
ALLOWED_KEYS = %i[tags script image services start_in artifacts
cache dependencies before_script after_script hooks
- environment coverage retry parallel interruptible timeout
+ coverage retry parallel interruptible timeout
release id_tokens publish].freeze
validations do
@@ -102,10 +102,6 @@ module Gitlab
metadata: { allowed_needs: %i[job cross_dependency] },
inherit: false
- entry :environment, Entry::Environment,
- description: 'Environment configuration for this job.',
- inherit: false
-
entry :coverage, Entry::Coverage,
description: 'Coverage configuration for this job.',
inherit: false
@@ -124,7 +120,7 @@ module Gitlab
entry :id_tokens, ::Gitlab::Config::Entry::ComposableHash,
description: 'Configured JWTs for this job',
- inherit: false,
+ inherit: true,
metadata: { composable_class: ::Gitlab::Ci::Config::Entry::IdToken }
entry :publish, Entry::Publish,
@@ -160,13 +156,11 @@ module Gitlab
when: self.when,
start_in: self.start_in,
dependencies: dependencies,
- environment: environment_defined? ? environment_value : nil,
- environment_name: environment_defined? ? environment_value[:name] : nil,
coverage: coverage_defined? ? coverage_value : nil,
retry: retry_defined? ? retry_value : nil,
parallel: has_parallel? ? parallel_value : nil,
interruptible: interruptible_defined? ? interruptible_value : nil,
- timeout: has_timeout? ? ChronicDuration.parse(timeout.to_s) : nil,
+ timeout: parsed_timeout,
artifacts: artifacts_value,
release: release_value,
after_script: after_script_value,
@@ -180,6 +174,12 @@ module Gitlab
).compact
end
+ def parsed_timeout
+ return unless has_timeout?
+
+ ChronicDuration.parse(timeout.to_s, use_complete_matcher: true)
+ end
+
def ignored?
allow_failure_defined? ? static_allow_failure : manual_action?
end
diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb
index e0f0903174c..88734ac1186 100644
--- a/lib/gitlab/ci/config/entry/processable.rb
+++ b/lib/gitlab/ci/config/entry/processable.rb
@@ -15,7 +15,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Inheritable
PROCESSABLE_ALLOWED_KEYS = %i[extends stage only except rules variables
- inherit allow_failure when needs resource_group].freeze
+ inherit allow_failure when needs resource_group environment].freeze
MAX_NESTING_LEVEL = 10
included do
@@ -68,6 +68,10 @@ module Gitlab
inherit: false,
default: {}
+ entry :environment, Entry::Environment,
+ description: 'Environment configuration for this job.',
+ inherit: false
+
attributes :extends, :rules, :resource_group
end
@@ -125,6 +129,8 @@ module Gitlab
root_variables_inheritance: root_variables_inheritance,
only: only_value,
except: except_value,
+ environment: environment_defined? ? environment_value : nil,
+ environment_name: environment_defined? ? environment_value[:name] : nil,
resource_group: resource_group }.compact
end
diff --git a/lib/gitlab/ci/config/external/context.rb b/lib/gitlab/ci/config/external/context.rb
index c57391d355c..0a524fdba66 100644
--- a/lib/gitlab/ci/config/external/context.rb
+++ b/lib/gitlab/ci/config/external/context.rb
@@ -9,22 +9,21 @@ module Gitlab
TimeoutError = Class.new(StandardError)
- TEMP_MAX_INCLUDES = 100 # For logging; to be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/396776
-
include ::Gitlab::Utils::StrongMemoize
attr_reader :project, :sha, :user, :parent_pipeline, :variables, :pipeline_config
- attr_reader :expandset, :execution_deadline, :logger, :max_includes, :max_total_yaml_size_bytes
+ attr_reader :pipeline, :expandset, :execution_deadline, :logger, :max_includes, :max_total_yaml_size_bytes
attr_accessor :total_file_size_in_bytes
delegate :instrument, to: :logger
def initialize(
- project: nil, sha: nil, user: nil, parent_pipeline: nil, variables: nil,
+ project: nil, pipeline: nil, sha: nil, user: nil, parent_pipeline: nil, variables: nil,
pipeline_config: nil, logger: nil
)
@project = project
+ @pipeline = pipeline
@sha = sha
@user = user
@parent_pipeline = parent_pipeline
@@ -60,6 +59,7 @@ module Gitlab
def mutate(attrs = {})
self.class.new(**attrs) do |ctx|
+ ctx.pipeline = pipeline
ctx.expandset = expandset
ctx.execution_deadline = execution_deadline
ctx.logger = logger
@@ -106,7 +106,7 @@ module Gitlab
protected
- attr_writer :expandset, :execution_deadline, :logger, :max_includes, :max_total_yaml_size_bytes
+ attr_writer :pipeline, :expandset, :execution_deadline, :logger, :max_includes, :max_total_yaml_size_bytes
private
diff --git a/lib/gitlab/ci/config/external/file/component.rb b/lib/gitlab/ci/config/external/file/component.rb
index 15cc0783b86..de6de1bb7a8 100644
--- a/lib/gitlab/ci/config/external/file/component.rb
+++ b/lib/gitlab/ci/config/external/file/component.rb
@@ -18,6 +18,8 @@ module Gitlab
def content
return unless component_result.success?
+ ::Gitlab::UsageDataCounters::HLLRedisCounter.track_event('cicd_component_usage', values: context.user.id)
+
component_result.payload.fetch(:content)
end
strong_memoize_attr :content
diff --git a/lib/gitlab/ci/config/external/mapper/verifier.rb b/lib/gitlab/ci/config/external/mapper/verifier.rb
index 580cae8a207..0e296aa0b5b 100644
--- a/lib/gitlab/ci/config/external/mapper/verifier.rb
+++ b/lib/gitlab/ci/config/external/mapper/verifier.rb
@@ -40,7 +40,7 @@ module Gitlab
file.validate_content! if file.valid?
file.load_and_validate_expanded_hash! if file.valid?
- next unless Feature.enabled?(:introduce_ci_max_total_yaml_size_bytes, context.project) && file.valid?
+ next unless file.valid?
# We are checking the file.content.to_s because that is returning the actual content of the file,
# whereas file.content would return the BatchLoader.
diff --git a/lib/gitlab/ci/config/external/rules.rb b/lib/gitlab/ci/config/external/rules.rb
index 0e6209460e0..05266fbff0c 100644
--- a/lib/gitlab/ci/config/external/rules.rb
+++ b/lib/gitlab/ci/config/external/rules.rb
@@ -5,29 +5,19 @@ module Gitlab
class Config
module External
class Rules
- # Remove these two constants when FF `ci_refactor_external_rules` is removed
- ALLOWED_KEYS = Entry::Include::Rules::Rule::ALLOWED_KEYS
- ALLOWED_WHEN = Entry::Include::Rules::Rule::ALLOWED_WHEN
-
InvalidIncludeRulesError = Class.new(Mapper::Error)
def initialize(rule_hashes)
- if Feature.enabled?(:ci_refactor_external_rules)
- return unless rule_hashes
-
- # We must compose the include rules entry here because included
- # files are expanded before `@root.compose!` runs in Ci::Config.
- rules_entry = Entry::Include::Rules.new(rule_hashes)
- rules_entry.compose!
+ return unless rule_hashes
- raise InvalidIncludeRulesError, "include:#{rules_entry.errors.first}" unless rules_entry.valid?
+ # We must compose the include rules entry here because included
+ # files are expanded before `@root.compose!` runs in Ci::Config.
+ rules_entry = Entry::Include::Rules.new(rule_hashes)
+ rules_entry.compose!
- @rule_list = Build::Rules::Rule.fabricate_list(rules_entry.value)
- else
- validate(rule_hashes)
+ raise InvalidIncludeRulesError, "include:#{rules_entry.errors.first}" unless rules_entry.valid?
- @rule_list = Build::Rules::Rule.fabricate_list(rule_hashes)
- end
+ @rule_list = Build::Rules::Rule.fabricate_list(rules_entry.value)
end
def evaluate(context)
@@ -38,28 +28,14 @@ module Gitlab
else
Result.new('never')
end
+ rescue Build::Rules::Rule::Clause::ParseError => e
+ raise InvalidIncludeRulesError, "include:#{e.message}"
end
private
def match_rule(context)
- @rule_list.find { |rule| rule.matches?(nil, context) }
- end
-
- # Remove this method when FF `ci_refactor_external_rules` is removed
- def validate(rule_hashes)
- return unless rule_hashes.is_a?(Array)
-
- rule_hashes.each do |rule_hash|
- next if (rule_hash.keys - ALLOWED_KEYS).empty? && valid_when?(rule_hash)
-
- raise InvalidIncludeRulesError, "invalid include rule: #{rule_hash}"
- end
- end
-
- # Remove this method when FF `ci_refactor_external_rules` is removed
- def valid_when?(rule_hash)
- rule_hash[:when].nil? || rule_hash[:when].in?(ALLOWED_WHEN)
+ @rule_list.find { |rule| rule.matches?(context.pipeline, context) }
end
Result = Struct.new(:when) do
diff --git a/lib/gitlab/ci/config/interpolation/interpolator.rb b/lib/gitlab/ci/config/interpolation/interpolator.rb
index 58965890184..95c419d7427 100644
--- a/lib/gitlab/ci/config/interpolation/interpolator.rb
+++ b/lib/gitlab/ci/config/interpolation/interpolator.rb
@@ -37,7 +37,12 @@ module Gitlab
def interpolate!
return @errors.push(config.error) unless config.valid?
- return @errors.push('unknown input arguments') if inputs_without_header?
+
+ if inputs_without_header?
+ return @errors.push(
+ _('Given inputs not defined in the `spec` section of the included configuration file'))
+ end
+
return @result ||= config.content unless config.has_header?
return @errors.concat(header.errors) unless header.valid?
diff --git a/lib/gitlab/ci/jwt_v2.rb b/lib/gitlab/ci/jwt_v2.rb
index 8c730a9548f..29beba4774a 100644
--- a/lib/gitlab/ci/jwt_v2.rb
+++ b/lib/gitlab/ci/jwt_v2.rb
@@ -61,10 +61,6 @@ module Gitlab
pipeline_source: pipeline.source&.to_sym,
pipeline_source_bridge: pipeline.source_bridge
)
- rescue StandardError => e
- # We don't want endpoints relying on this code to fail if there's an error here.
- Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e, pipeline_id: pipeline.id)
- nil
end
strong_memoize_attr(:project_config)
diff --git a/lib/gitlab/ci/parsers/sbom/cyclonedx.rb b/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
index bc62fbe55ec..1e5200e8682 100644
--- a/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
+++ b/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
@@ -58,6 +58,15 @@ module Gitlab
properties = data.dig('metadata', 'properties')
source = CyclonedxProperties.parse_source(properties)
report.set_source(source) if source
+
+ tools = data.dig('metadata', 'tools')
+ authors = data.dig('metadata', 'authors')
+
+ report.metadata = ::Gitlab::Ci::Reports::Sbom::Metadata.new.tap do |metadata|
+ metadata.tools = tools if tools
+ metadata.authors = authors if authors
+ metadata.properties = properties if properties
+ end
end
def parse_components
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index 4bc2f6c7be7..cc3aa33e93b 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -128,10 +128,6 @@ module Gitlab
.observe({ plan: project.actual_plan_name }, jobs_count)
end
- def observe_pipeline_includes_count(pipeline)
- logger.observe(:pipeline_includes_count, pipeline.config_metadata&.[](:includes)&.count, once: true)
- end
-
def increment_pipeline_failure_reason_counter(reason)
metrics.pipeline_failure_reason_counter
.increment(reason: (reason || :unknown_failure).to_s)
diff --git a/lib/gitlab/ci/pipeline/chain/sequence.rb b/lib/gitlab/ci/pipeline/chain/sequence.rb
index dd097187955..de147914850 100644
--- a/lib/gitlab/ci/pipeline/chain/sequence.rb
+++ b/lib/gitlab/ci/pipeline/chain/sequence.rb
@@ -30,7 +30,6 @@ module Gitlab
@command.observe_creation_duration(current_monotonic_time - @start)
@command.observe_pipeline_size(@pipeline)
@command.observe_jobs_count_in_alive_pipelines
- @command.observe_pipeline_includes_count(@pipeline)
@pipeline
end
diff --git a/lib/gitlab/ci/queue/metrics.rb b/lib/gitlab/ci/queue/metrics.rb
index a18542288c9..db1b53e52e0 100644
--- a/lib/gitlab/ci/queue/metrics.rb
+++ b/lib/gitlab/ci/queue/metrics.rb
@@ -14,7 +14,6 @@ module Gitlab
METRICS_SHARD_TAG_PREFIX = 'metrics_shard::'
DEFAULT_METRICS_SHARD = 'default'
- JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET = 5
OPERATION_COUNTERS = [
:build_can_pick,
@@ -57,7 +56,7 @@ module Gitlab
def register_success(job)
labels = { shared_runner: runner.instance_type?,
- jobs_running_for_project: jobs_running_for_project(job),
+ jobs_running_for_project: job.project_jobs_running_on_instance_runners_count,
shard: DEFAULT_METRICS_SHARD }
if runner.instance_type?
@@ -65,7 +64,7 @@ module Gitlab
labels[:shard] = shard.gsub(METRICS_SHARD_TAG_PREFIX, '') if shard
end
- self.class.job_queue_duration_seconds.observe(labels, Time.current - job.queued_at) unless job.queued_at.nil?
+ self.class.job_queue_duration_seconds.observe(labels, job.time_in_queue_seconds) unless job.queued_at.nil?
self.class.attempt_counter.increment
end
@@ -231,28 +230,6 @@ module Gitlab
Gitlab::Metrics.histogram(name, comment, labels, buckets)
end
end
-
- private
-
- # rubocop: disable CodeReuse/ActiveRecord
- def jobs_running_for_project(job)
- return '+Inf' unless runner.instance_type?
-
- # excluding currently started job
- running_jobs_count = running_jobs_relation(job)
- .limit(JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET + 1).count - 1
-
- if running_jobs_count < JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET
- running_jobs_count
- else
- "#{JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET}+"
- end
- end
-
- def running_jobs_relation(job)
- ::Ci::RunningBuild.instance_type.where(project_id: job.project_id)
- end
- # rubocop: enable CodeReuse/ActiveRecord
end
end
end
diff --git a/lib/gitlab/ci/reports/codequality_reports.rb b/lib/gitlab/ci/reports/codequality_reports.rb
index aba2d2e8b19..edcb17a61a7 100644
--- a/lib/gitlab/ci/reports/codequality_reports.rb
+++ b/lib/gitlab/ci/reports/codequality_reports.rb
@@ -6,7 +6,7 @@ module Gitlab
class CodequalityReports
attr_reader :degradations, :error_message
- SEVERITY_PRIORITIES = %w(blocker critical major minor info unknown).map.with_index.to_h.freeze # { "blocker" => 0, "critical" => 1 ... }
+ SEVERITY_PRIORITIES = %w[blocker critical major minor info unknown].map.with_index.to_h.freeze # { "blocker" => 0, "critical" => 1 ... }
CODECLIMATE_SCHEMA_PATH = Rails.root.join('app', 'validators', 'json_schemas', 'codeclimate.json').to_s
def initialize
diff --git a/lib/gitlab/ci/reports/sbom/component.rb b/lib/gitlab/ci/reports/sbom/component.rb
index 51fd6af7bc4..59816e75b2c 100644
--- a/lib/gitlab/ci/reports/sbom/component.rb
+++ b/lib/gitlab/ci/reports/sbom/component.rb
@@ -7,7 +7,7 @@ module Gitlab
class Component
include Gitlab::Utils::StrongMemoize
- attr_reader :component_type, :version
+ attr_reader :component_type, :version, :path
def initialize(type:, name:, purl:, version:)
@component_type = type
@@ -31,12 +31,24 @@ module Gitlab
end
strong_memoize_attr :purl
+ def purl_type
+ purl.type
+ end
+
+ def type
+ component_type
+ end
+
def name
return @name unless purl
[purl.namespace, purl.name].compact.join('/')
end
+ def key
+ [name, version, purl&.type]
+ end
+
private
def supported_component_type?
diff --git a/lib/gitlab/ci/reports/sbom/metadata.rb b/lib/gitlab/ci/reports/sbom/metadata.rb
new file mode 100644
index 00000000000..8945259d331
--- /dev/null
+++ b/lib/gitlab/ci/reports/sbom/metadata.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Reports
+ module Sbom
+ class Metadata
+ attr_accessor :tools, :authors, :properties, :timestamp
+
+ def initialize(tools: [], authors: [], properties: [])
+ @tools = tools
+ @authors = authors
+ @properties = properties
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/reports/sbom/report.rb b/lib/gitlab/ci/reports/sbom/report.rb
index 51fa8ce0d2e..9a71c67388d 100644
--- a/lib/gitlab/ci/reports/sbom/report.rb
+++ b/lib/gitlab/ci/reports/sbom/report.rb
@@ -5,10 +5,24 @@ module Gitlab
module Reports
module Sbom
class Report
- attr_reader :components, :source, :errors
+ # This represents the attributes defined in cycloneDX Schema
+ # https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/validators/json_schemas/cyclonedx_report.json#L7
+ BOM_FORMAT = 'CycloneDX'
+ SPEC_VERSION = '1.4'
+ VERSION = 1
+
+ attr_reader :source, :errors
+ attr_accessor :sbom_attributes, :metadata, :components
def initialize
+ @sbom_attributes = {
+ bom_format: BOM_FORMAT,
+ spec_version: SPEC_VERSION,
+ serial_number: "urn:uuid:#{SecureRandom.uuid}",
+ version: VERSION
+ }
@components = []
+ @metadata = ::Gitlab::Ci::Reports::Sbom::Metadata.new
@errors = []
end
diff --git a/lib/gitlab/ci/reports/test_reports_comparer.rb b/lib/gitlab/ci/reports/test_reports_comparer.rb
index 497831ae5a7..0ea2d793eea 100644
--- a/lib/gitlab/ci/reports/test_reports_comparer.rb
+++ b/lib/gitlab/ci/reports/test_reports_comparer.rb
@@ -29,7 +29,7 @@ module Gitlab
end
end
- %w(total_count resolved_count failed_count error_count).each do |method|
+ %w[total_count resolved_count failed_count error_count].each do |method|
define_method(method) do
# rubocop: disable CodeReuse/ActiveRecord
suite_comparers.sum { |suite| suite.public_send(method) } # rubocop:disable GitlabSecurity/PublicSend
diff --git a/lib/gitlab/ci/reports/test_suite.rb b/lib/gitlab/ci/reports/test_suite.rb
index dcc593b4403..c681727a43d 100644
--- a/lib/gitlab/ci/reports/test_suite.rb
+++ b/lib/gitlab/ci/reports/test_suite.rb
@@ -77,7 +77,7 @@ module Gitlab
def +(other)
self.class.new.tap do |test_suite|
- test_suite.name = self.name
+ test_suite.name = other.name
test_suite.test_cases = self.test_cases.deep_merge(other.test_cases)
test_suite.total_time = self.total_time + other.total_time
end
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 6e2faf33a2f..fa1d8bec7e6 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -65,6 +65,10 @@ variables:
DOCKER_TLS_CERTDIR: "" # https://gitlab.com/gitlab-org/gitlab-runner/issues/4501
+ # License-Scanning job is removed from GitLab 16.3
+ # This is the fix for https://gitlab.com/gitlab-org/gitlab/-/issues/422791
+ LICENSE_MANAGEMENT_DISABLED: "true"
+
stages:
- build
- test
diff --git a/lib/gitlab/ci/templates/Cosign.gitlab-ci.yml b/lib/gitlab/ci/templates/Cosign.gitlab-ci.yml
new file mode 100644
index 00000000000..48c9422b469
--- /dev/null
+++ b/lib/gitlab/ci/templates/Cosign.gitlab-ci.yml
@@ -0,0 +1,22 @@
+# To contribute improvements to CI/CD templates, please follow the Development guide at:
+# https://docs.gitlab.com/ee/development/cicd/templates.html
+# This specific template is located at:
+# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Cosign.gitlab-ci.yml
+
+# This template extends Docker.gitlab-ci.yml to sign the image with Cosign after building.
+# This allows you to verify that an image was built by a trusted pipeline before running it.
+# See https://docs.gitlab.com/ee/ci/yaml/signing_examples.html for more details.
+
+include:
+ template: Docker.gitlab-ci.yml
+
+docker-build:
+ variables:
+ COSIGN_YES: "true" # Used by Cosign to skip confirmation prompts for non-destructive operations
+ id_tokens:
+ SIGSTORE_ID_TOKEN: # Used by Cosign to get certificate from Fulcio
+ aud: sigstore
+ after_script:
+ - apk add --update cosign
+ - IMAGE_DIGEST="$(docker inspect --format='{{index .RepoDigests 0}}' "$DOCKER_IMAGE_NAME")"
+ - cosign sign "$IMAGE_DIGEST"
diff --git a/lib/gitlab/ci/templates/Docker.gitlab-ci.yml b/lib/gitlab/ci/templates/Docker.gitlab-ci.yml
index 8f5f0e2c451..1aa346aec67 100644
--- a/lib/gitlab/ci/templates/Docker.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Docker.gitlab-ci.yml
@@ -15,21 +15,20 @@ docker-build:
stage: build
services:
- docker:dind
+ variables:
+ DOCKER_IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- # Default branch leaves tag empty (= latest tag)
- # All other branches are tagged with the escaped branch name (commit ref slug)
+ # All branches are tagged with $DOCKER_IMAGE_NAME (defaults to commit ref slug)
+ # Default branch is also tagged with `latest`
script:
+ - docker build --pull -t "$DOCKER_IMAGE_NAME" .
+ - docker push "$DOCKER_IMAGE_NAME"
- |
if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
- tag=""
- echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
- else
- tag=":$CI_COMMIT_REF_SLUG"
- echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
+ docker tag "$DOCKER_IMAGE_NAME" "$CI_REGISTRY_IMAGE:latest"
+ docker push "$CI_REGISTRY_IMAGE:latest"
fi
- - docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" .
- - docker push "$CI_REGISTRY_IMAGE${tag}"
# Run this job in a branch where a Dockerfile exists
rules:
- if: $CI_COMMIT_BRANCH
diff --git a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
index c1aedbe1111..07bc3fbe795 100644
--- a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_BUILD_IMAGE_VERSION: 'v1.38.1'
+ AUTO_BUILD_IMAGE_VERSION: 'v1.41.0'
build:
stage: build
diff --git a/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml
index c1aedbe1111..07bc3fbe795 100644
--- a/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Build.latest.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_BUILD_IMAGE_VERSION: 'v1.38.1'
+ AUTO_BUILD_IMAGE_VERSION: 'v1.41.0'
build:
stage: build
diff --git a/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml
index 192d06bfa14..5cee19a746c 100644
--- a/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Container-Scanning.gitlab-ci.yml
@@ -40,6 +40,7 @@ container_scanning:
reports:
container_scanning: gl-container-scanning-report.json
dependency_scanning: gl-dependency-scanning-report.json
+ cyclonedx: "**/gl-sbom-*.cdx.json"
paths: [gl-container-scanning-report.json, gl-dependency-scanning-report.json, "**/gl-sbom-*.cdx.json"]
dependencies: []
script:
diff --git a/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml
index 9a4c75e7402..ade4be99f18 100644
--- a/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Container-Scanning.latest.gitlab-ci.yml
@@ -40,6 +40,7 @@ container_scanning:
reports:
container_scanning: gl-container-scanning-report.json
dependency_scanning: gl-dependency-scanning-report.json
+ cyclonedx: "**/gl-sbom-*.cdx.json"
paths: [gl-container-scanning-report.json, gl-dependency-scanning-report.json, "**/gl-sbom-*.cdx.json"]
dependencies: []
script:
diff --git a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
index 7b2fb49b65e..e9ba938142d 100644
--- a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.53.0'
+ DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.56.0'
.dast-auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index 1e482ccca82..eaaf171e4b5 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_DEPLOY_IMAGE_VERSION: 'v2.53.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.56.0'
.auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
index 6eac691b293..d2e448fb6a1 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
@@ -1,5 +1,5 @@
variables:
- AUTO_DEPLOY_IMAGE_VERSION: 'v2.53.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.56.0'
.auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml b/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
index 30767e66649..1468cf9c7c6 100644
--- a/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
@@ -3,17 +3,17 @@
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
-# Use this template to run MATLAB and Simulink as part of your CI/CD pipeline. The template includes three jobs:
+# Use this template to build and test your MATLAB project as part of your CI/CD pipeline. The template includes four jobs:
# - `command`: Run MATLAB scripts, functions, and statements.
# - `test`: Run tests authored using the MATLAB unit testing framework or Simulink Test.
# - `test_artifacts`: Run MATLAB and Simulink tests, and generate test and coverage artifacts.
+# - `build`: Run a build using the MATLAB build tool.
#
# The jobs in the template use the `matlab -batch` syntax to start MATLAB. The `-batch` option is supported
# in MATLAB R2019a and later.
#
# You can copy and paste one or more jobs in this template into your `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
-#
# Your runner must use the Docker executor to run MATLAB within a container. The [MATLAB Container on Docker Hub][1]
# lets you run your build using MATLAB R2020b or a later release. If your build requires additional toolboxes, use a
@@ -24,7 +24,7 @@
# [2] https://www.mathworks.com/help/cloudcenter/ug/create-a-custom-matlab-container.html
# The jobs in this template incorporate the contents of a hidden `.matlab_defaults` job. You need to
-# configure this job before running the `command`, `test`, and `test_artifacts` jobs. To configure the job:
+# configure this job before running the `command`, `test`, `test_artifacts`, and `build` jobs. To configure the job:
# - Specify the name of the MATLAB container image you want to use.
# - Set the `MLM_LICENSE_FILE` environment variable using the port number and DNS address for your network license manager.
#
@@ -40,17 +40,17 @@
#
command:
extends: .matlab_defaults
- script: matlab -batch mycommand
+ script: matlab -batch "mycommand"
# If you specify more than one script, function, or statement, use a comma or semicolon to separate them.
# For example, to run `myscript.m` in a folder named `myfolder` located in the root of the repository,
-# you can specify `mycommand` like this:
+# you can specify `"mycommand"` like this:
#
# "addpath('myfolder'), myscript"
#
# MATLAB exits with exit code 0 if the specified script, function, or statement executes successfully without
# error. Otherwise, MATLAB terminates with a nonzero exit code, which causes the job to fail. To have the
-# job fail in certain conditions, use the [`assert`][3] or [`error`][4] functions.
+# job fail in certain conditions, use the [`assert`][3] or [`error`][4] function.
#
# [3] https://www.mathworks.com/help/matlab/ref/assert.html
# [4] https://www.mathworks.com/help/matlab/ref/error.html
@@ -62,7 +62,7 @@ test:
extends: .matlab_defaults
script: matlab -batch "results = runtests('IncludeSubfolders',true), assertSuccess(results);"
-# By default, the job includes any files in your [MATLAB Project][7] that have a `Test` label. If your repository
+# By default, the job includes any files in your [MATLAB project][7] that have a `Test` label. If your repository
# does not have a MATLAB project, then the job includes all tests in the root of your repository or in any of
# its subfolders.
#
@@ -71,9 +71,9 @@ test:
# [7] https://www.mathworks.com/help/matlab/projects.html
# The `test_artifacts` job runs your tests and additionally generates test and coverage artifacts.
-# It uses the plugin classes in the [`matlab.unittest.plugins`][8] package to generate a JUnit test results
-# report and a Cobertura code coverage report. Like the `test` job, this job runs all the tests in your
-# project and fails the build if any of the tests fail.
+# It uses the plugin classes in the [`matlab.unittest.plugins`][8] package to produce test results
+# in JUnit-style XML format and code coverage results in Cobertura XML format. Like the `test` job,
+# this job runs all the tests in your project and fails the build if any of the tests fail.
#
test_artifacts:
extends: .matlab_defaults
@@ -110,3 +110,22 @@ test_artifacts:
#
# [8] https://www.mathworks.com/help/matlab/ref/matlab.unittest.plugins-package.html
# [9] https://www.mathworks.com/help/matlab/matlab_prog/generate-artifacts-using-matlab-unit-test-plugins.html
+
+# Starting in R2022b, the `build` job runs a build using the MATLAB build tool. You can use this job to run the
+# tasks specified in a file named `buildfile.m` in the root of your repository.
+#
+build:
+ extends: .matlab_defaults
+ script: matlab -batch "buildtool"
+
+# The job executes the [`buildtool`][10] command to run a build using the default tasks in `buildfile.m`
+# as well as all the tasks on which they depend. To run specific tasks instead, specify them as a space-separated
+# list in the job. For example, to run the tasks named `task1` and `task2` and their dependencies, substitute
+# `"buildtool"` with `"buildtool task1 task2"`.
+#
+# MATLAB exits with exit code 0 if the build runs successfully. Otherwise, MATLAB terminates with a nonzero
+# exit code, which causes the job to fail. For more information about the MATLAB build tool,
+# see [Create and Run Tasks Using Build Tool][11].
+#
+# [10] https://www.mathworks.com/help/matlab/ref/buildtool.html
+# [11] https://www.mathworks.com/help/matlab/matlab_prog/create-and-run-tasks-using-build-tool.html
diff --git a/lib/gitlab/ci/trace.rb b/lib/gitlab/ci/trace.rb
index 2dc7bbc391e..f4ba9100812 100644
--- a/lib/gitlab/ci/trace.rb
+++ b/lib/gitlab/ci/trace.rb
@@ -30,9 +30,9 @@ module Gitlab
@job = job
end
- def html(last_lines: nil)
+ def html(last_lines: nil, max_size: nil)
read do |stream|
- stream.html(last_lines: last_lines)
+ stream.html(last_lines: last_lines, max_size: max_size)
end
end
@@ -290,7 +290,7 @@ module Gitlab
if consistent_archived_trace?(build)
::Ci::Build
.sticking
- .unstick_or_continue_sticking(LOAD_BALANCING_STICKING_NAMESPACE, build.id)
+ .find_caught_up_replica(LOAD_BALANCING_STICKING_NAMESPACE, build.id)
end
yield
diff --git a/lib/gitlab/ci/trace/stream.rb b/lib/gitlab/ci/trace/stream.rb
index dd435ba05b7..ef494a79d9a 100644
--- a/lib/gitlab/ci/trace/stream.rb
+++ b/lib/gitlab/ci/trace/stream.rb
@@ -53,18 +53,20 @@ module Gitlab
append(data, 0)
end
- def raw(last_lines: nil)
+ def raw(last_lines: nil, max_size: nil)
return unless valid?
- if last_lines.to_i > 0
+ if max_size.to_i > 0
+ read_last_lines_with_max_size(last_lines, max_size)
+ elsif last_lines.to_i > 0
read_last_lines(last_lines)
else
stream.read
end.force_encoding(Encoding.default_external)
end
- def html(last_lines: nil)
- text = raw(last_lines: last_lines)
+ def html(last_lines: nil, max_size: nil)
+ text = raw(last_lines: last_lines, max_size: max_size)
buffer = StringIO.new(text)
::Gitlab::Ci::Ansi2html.convert(buffer).html
end
@@ -117,6 +119,37 @@ module Gitlab
to_enum(:reverse_line).first(limit).reverse.join
end
+ def read_last_lines_with_max_size(limit, max_size)
+ linesleft = limit
+ result = ''
+
+ reverse_line_with_max_size(max_size) do |line|
+ result = line + result
+ unless linesleft.nil?
+ linesleft -= 1
+ break if linesleft <= 0
+ end
+ end
+
+ result
+ end
+
+ def reverse_line_with_max_size(max_size)
+ stream.seek(0, IO::SEEK_END)
+ debris = ''
+ sizeleft = max_size
+
+ until sizeleft <= 0 || (buf = read_backward([BUFFER_SIZE, sizeleft].min)).empty?
+ sizeleft -= buf.bytesize
+ debris, *lines = (buf + debris).each_line.to_a
+ lines.reverse_each do |line|
+ yield(line.force_encoding(Encoding.default_external))
+ end
+ end
+
+ yield(debris.force_encoding(Encoding.default_external)) unless debris.empty?
+ end
+
def reverse_line
stream.seek(0, IO::SEEK_END)
debris = ''
diff --git a/lib/gitlab/ci/variables/builder.rb b/lib/gitlab/ci/variables/builder.rb
index cae3a966bc6..c279af6acfc 100644
--- a/lib/gitlab/ci/variables/builder.rb
+++ b/lib/gitlab/ci/variables/builder.rb
@@ -17,7 +17,7 @@ module Gitlab
def scoped_variables(job, environment:, dependencies:)
Gitlab::Ci::Variables::Collection.new.tap do |variables|
- variables.concat(predefined_variables(job))
+ variables.concat(predefined_variables(job, environment))
variables.concat(project.predefined_variables)
variables.concat(pipeline_variables_builder.predefined_variables)
variables.concat(job.runner.predefined_variables) if job.runnable? && job.runner
@@ -126,7 +126,7 @@ module Gitlab
delegate :project, to: :pipeline
- def predefined_variables(job)
+ def predefined_variables(job, environment)
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'CI_JOB_NAME', value: job.name)
variables.append(key: 'CI_JOB_NAME_SLUG', value: job_name_slug(job))
@@ -137,8 +137,12 @@ module Gitlab
variables.append(key: 'CI_NODE_INDEX', value: job.options[:instance].to_s) if job.options&.include?(:instance)
variables.append(key: 'CI_NODE_TOTAL', value: ci_node_total_value(job).to_s)
- # Set environment name here so we can access it when evaluating the job's rules
- variables.append(key: 'CI_ENVIRONMENT_NAME', value: job.environment) if job.environment
+ if environment.present?
+ variables.append(key: 'CI_ENVIRONMENT_NAME', value: environment)
+ variables.append(key: 'CI_ENVIRONMENT_ACTION', value: job.environment_action)
+ variables.append(key: 'CI_ENVIRONMENT_TIER', value: job.environment_tier)
+ variables.append(key: 'CI_ENVIRONMENT_URL', value: job.environment_url) if job.environment_url
+ end
end
end
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index c69d9218a66..3a0173d1548 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -129,6 +129,12 @@ module Gitlab
error!("#{name} job: undefined #{dependency_type}: #{dependency}")
end
+ # A parallel job's name is expanded in Config::Normalizer so we must revalidate the name length here
+ if dependency_type == 'need' && dependency.length > ::Ci::BuildNeed::MAX_JOB_NAME_LENGTH
+ error!("#{name} job: need `#{dependency}` name is too long " \
+ "(maximum is #{::Ci::BuildNeed::MAX_JOB_NAME_LENGTH} characters)")
+ end
+
job_stage_index = stage_index(name)
dependency_stage_index = stage_index(dependency)
diff --git a/lib/gitlab/cleanup/orphan_job_artifact_files.rb b/lib/gitlab/cleanup/orphan_job_artifact_files.rb
index 90123b9d000..486d53eb870 100644
--- a/lib/gitlab/cleanup/orphan_job_artifact_files.rb
+++ b/lib/gitlab/cleanup/orphan_job_artifact_files.rb
@@ -9,7 +9,7 @@ module Gitlab
LOST_AND_FOUND = File.join(ABSOLUTE_ARTIFACT_DIR, '-', 'lost+found').freeze
BATCH_SIZE = 500
DEFAULT_NICENESS = 'best-effort'
- VALID_NICENESS_LEVELS = %w{none realtime best-effort idle}.freeze
+ VALID_NICENESS_LEVELS = %w[none realtime best-effort idle].freeze
attr_accessor :batch, :total_found, :total_cleaned
attr_reader :dry_run, :niceness, :logger
diff --git a/lib/gitlab/cluster/rack_timeout_observer.rb b/lib/gitlab/cluster/rack_timeout_observer.rb
index 15dd6a59e19..8e9fc16c588 100644
--- a/lib/gitlab/cluster/rack_timeout_observer.rb
+++ b/lib/gitlab/cluster/rack_timeout_observer.rb
@@ -4,7 +4,7 @@ module Gitlab
module Cluster
class RackTimeoutObserver
include ActionView::Helpers::SanitizeHelper
- TRANSITION_STATES = %i(ready active).freeze
+ TRANSITION_STATES = %i[ready active].freeze
def initialize
@counter = Gitlab::Metrics.counter(:rack_requests_total, 'Number of requests in a given rack state')
diff --git a/lib/gitlab/composer/version_index.rb b/lib/gitlab/composer/version_index.rb
index fdff8fb32d3..bfa3112b795 100644
--- a/lib/gitlab/composer/version_index.rb
+++ b/lib/gitlab/composer/version_index.rb
@@ -48,7 +48,8 @@ module Gitlab
end
def package_source(package)
- git_url = package.project.http_url_to_repo
+ use_http_url = package.project.public? || Feature.disabled?(:composer_use_ssh_source_urls, package.project)
+ git_url = use_http_url ? package.project.http_url_to_repo : package.project.ssh_url_to_repo
{
'type' => 'git',
diff --git a/lib/gitlab/config/entry/legacy_validation_helpers.rb b/lib/gitlab/config/entry/legacy_validation_helpers.rb
index 415f6f77214..ec67d65c526 100644
--- a/lib/gitlab/config/entry/legacy_validation_helpers.rb
+++ b/lib/gitlab/config/entry/legacy_validation_helpers.rb
@@ -12,7 +12,7 @@ module Gitlab
if parser && parser.respond_to?(:validate_duration)
parser.validate_duration(value)
else
- ChronicDuration.parse(value)
+ ChronicDuration.parse(value, use_complete_matcher: true)
end
rescue ChronicDuration::DurationParseError
false
@@ -24,8 +24,12 @@ module Gitlab
if parser && parser.respond_to?(:validate_duration_limit)
parser.validate_duration_limit(value, limit)
else
- ChronicDuration.parse(value).second.from_now <
- ChronicDuration.parse(limit).second.from_now
+ ChronicDuration.parse(
+ value, use_complete_matcher: true
+ ).second.from_now <
+ ChronicDuration.parse(
+ limit, use_complete_matcher: true
+ ).second.from_now
end
rescue ChronicDuration::DurationParseError
false
diff --git a/lib/gitlab/content_security_policy/config_loader.rb b/lib/gitlab/content_security_policy/config_loader.rb
index 59a4e425b85..87a6d4ada70 100644
--- a/lib/gitlab/content_security_policy/config_loader.rb
+++ b/lib/gitlab/content_security_policy/config_loader.rb
@@ -29,6 +29,7 @@ module Gitlab
allow_customersdot(directives)
allow_review_apps(directives)
csp_level_3_backport(directives)
+ add_browsersdk_tracking(directives)
directives
end
@@ -83,6 +84,16 @@ module Gitlab
append_to_directive(directives, 'connect_src', url)
end
+ def add_browsersdk_tracking(directives)
+ return if directives.blank?
+ return unless Gitlab.com? && Feature.enabled?(:browsersdk_tracking) && ENV['GITLAB_ANALYTICS_URL'].present?
+
+ default_connect_src = directives['connect-src'] || directives['default-src']
+ connect_src_values = Array.wrap(default_connect_src) | [ENV['GITLAB_ANALYTICS_URL']]
+
+ append_to_directive(directives, 'connect_src', connect_src_values.join(' '))
+ end
+
def allow_lfs(directives)
return unless Gitlab.config.lfs.enabled && LfsObjectUploader.object_store_enabled? && LfsObjectUploader.direct_download_enabled?
diff --git a/lib/gitlab/data_builder/deployment.rb b/lib/gitlab/data_builder/deployment.rb
index b26f9a61ee1..915d606feb9 100644
--- a/lib/gitlab/data_builder/deployment.rb
+++ b/lib/gitlab/data_builder/deployment.rb
@@ -9,7 +9,7 @@ module Gitlab
def build(deployment, status, status_changed_at)
# Deployments will not have a deployable when created using the API.
deployable_url =
- if deployment.deployable
+ if deployment.deployable.instance_of?(::Ci::Build)
Gitlab::UrlBuilder.build(deployment.deployable)
end
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index 89065c11c4f..6222155d812 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -185,37 +185,6 @@ module Gitlab
end
# rubocop: enable CodeReuse/ActiveRecord
- def self.check_postgres_version_and_print_warning
- return if Gitlab::Runtime.rails_runner?
-
- database_base_models.each do |name, model|
- database = Gitlab::Database::Reflection.new(model)
-
- next if database.postgresql_minimum_supported_version?
-
- Kernel.warn ERB.new(Rainbow.new.wrap(<<~EOS).red).result
-
- ██†██†█████†██████†███†██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ€ ██†██████â€
- ██†██â€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â€â€â€â€â€
- ██†█†██â€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ ███â€
- ██â€â–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€
- â€â–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ â€â–ˆâ–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ â€â–ˆâ–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â€
-
- ******************************************************************************
- You are using PostgreSQL #{database.version} for the #{name} database, but this version of GitLab requires PostgreSQL >= <%= Gitlab::Database::MINIMUM_POSTGRES_VERSION %>.
- <% if Rails.env.development? || Rails.env.test? %>
- If using gitlab-development-kit, please find the relevant steps here:
- https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/postgresql.md#upgrade-postgresql
- <% end %>
- Please upgrade your environment to a supported PostgreSQL version. See
- https://docs.gitlab.com/ee/install/requirements.html#database for details.
- ******************************************************************************
- EOS
- rescue ActiveRecord::ActiveRecordError, PG::Error
- # ignore - happens when Rake tasks yet have to create a database, e.g. for testing
- end
- end
-
def self.random
"RANDOM()"
end
diff --git a/lib/gitlab/database/as_with_materialized.rb b/lib/gitlab/database/as_with_materialized.rb
index 417e9f211b9..a6a7e7455e9 100644
--- a/lib/gitlab/database/as_with_materialized.rb
+++ b/lib/gitlab/database/as_with_materialized.rb
@@ -4,31 +4,15 @@ module Gitlab
module Database
# This class is a special Arel node which allows optionally define the `MATERIALIZED` keyword for CTE and Recursive CTE queries.
class AsWithMaterialized < Arel::Nodes::As
- extend Gitlab::Utils::StrongMemoize
-
MATERIALIZED = 'MATERIALIZED '
def initialize(left, right, materialized: true)
- if materialized && self.class.materialized_supported?
+ if materialized
right.prepend(MATERIALIZED)
end
super(left, right)
end
-
- # Note: to be deleted after the minimum PG version is set to 12.0
- def self.materialized_supported?
- strong_memoize(:materialized_supported) do
- ApplicationRecord.database.version.match?(/^1[2-9]\./) # version 12.x and above
- end
- end
-
- # Note: to be deleted after the minimum PG version is set to 12.0
- # Update the documentation together when deleting the method
- # https://docs.gitlab.com/ee/development/merge_request_concepts/performance.html#use-ctes-wisely
- def self.materialized_if_supported
- materialized_supported? ? 'MATERIALIZED' : ''
- end
end
end
end
diff --git a/lib/gitlab/database/async_indexes/migration_helpers.rb b/lib/gitlab/database/async_indexes/migration_helpers.rb
index db05635c73d..28a61dad3b5 100644
--- a/lib/gitlab/database/async_indexes/migration_helpers.rb
+++ b/lib/gitlab/database/async_indexes/migration_helpers.rb
@@ -39,6 +39,7 @@ module Gitlab
Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_ddl_mode!
return unless async_index_creation_available?
+ raise "Table #{table_name} does not exist" unless table_exists?(table_name)
index_name = options[:name] || index_name(table_name, column_name)
diff --git a/lib/gitlab/database/bulk_update.rb b/lib/gitlab/database/bulk_update.rb
index 36dbb157b0d..51f39419ddb 100644
--- a/lib/gitlab/database/bulk_update.rb
+++ b/lib/gitlab/database/bulk_update.rb
@@ -114,7 +114,7 @@ module Gitlab
def sql
<<~SQL
- WITH cte(#{list_of(cte_columns)}) AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (VALUES #{list_of(values)})
+ WITH cte(#{list_of(cte_columns)}) AS MATERIALIZED (VALUES #{list_of(values)})
UPDATE #{table_name} SET #{list_of(updates)} FROM cte WHERE cte_id = id
SQL
end
diff --git a/lib/gitlab/database/load_balancing/connection_proxy.rb b/lib/gitlab/database/load_balancing/connection_proxy.rb
index 2c480eb2cdc..67cde3e687d 100644
--- a/lib/gitlab/database/load_balancing/connection_proxy.rb
+++ b/lib/gitlab/database/load_balancing/connection_proxy.rb
@@ -17,22 +17,22 @@ module Gitlab
# These methods perform writes after which we need to stick to the
# primary.
- STICKY_WRITES = %i(
+ STICKY_WRITES = %i[
delete
delete_all
insert
update
update_all
exec_insert_all
- ).freeze
+ ].freeze
- NON_STICKY_READS = %i(
+ NON_STICKY_READS = %i[
sanitize_limit
select
select_one
select_rows
quote_column_name
- ).freeze
+ ].freeze
# hosts - The hosts to use for load balancing.
def initialize(load_balancer)
diff --git a/lib/gitlab/database/load_balancing/host.rb b/lib/gitlab/database/load_balancing/host.rb
index f8ed5fcd4cc..880324f3ae4 100644
--- a/lib/gitlab/database/load_balancing/host.rb
+++ b/lib/gitlab/database/load_balancing/host.rb
@@ -80,11 +80,26 @@ module Gitlab
start_time = ::Gitlab::Metrics::System.monotonic_time
while (::Gitlab::Metrics::System.monotonic_time - start_time) <= timeout
- break if pool.connections.none?(&:in_use?)
+ return if try_disconnect
sleep(2)
end
+ force_disconnect!
+ end
+
+ # Attempt to disconnect the pool if all connections are no longer in use.
+ # Returns true if the pool was disconnected, false if not.
+ def try_disconnect
+ if pool.connections.none?(&:in_use?)
+ pool.disconnect!
+ return true
+ end
+
+ false
+ end
+
+ def force_disconnect!
pool.disconnect!
end
@@ -104,16 +119,19 @@ module Gitlab
def online?
return @online unless check_replica_status?
+ was_online = @online
refresh_status
- if @online
+ # Log that the host came back online if it was previously offline
+ if @online && !was_online
::Gitlab::Database::LoadBalancing::Logger.info(
event: :host_online,
message: 'Host is online after replica status check',
db_host: @host,
db_port: @port
)
- else
+ # Always log if the host goes offline
+ elsif !@online
::Gitlab::Database::LoadBalancing::Logger.warn(
event: :host_offline,
message: 'Host is offline after replica status check',
diff --git a/lib/gitlab/database/load_balancing/load_balancer.rb b/lib/gitlab/database/load_balancing/load_balancer.rb
index f6144b7b772..9495648d069 100644
--- a/lib/gitlab/database/load_balancing/load_balancer.rb
+++ b/lib/gitlab/database/load_balancing/load_balancer.rb
@@ -8,6 +8,10 @@ module Gitlab
# Each host in the load balancer uses the same credentials as the primary
# database.
class LoadBalancer
+ ANY_CAUGHT_UP = :any
+ ALL_CAUGHT_UP = :all
+ NONE_CAUGHT_UP = :none
+
CACHE_KEY = :gitlab_load_balancer_host
REPLICA_SUFFIX = '_replica'
@@ -178,16 +182,32 @@ module Gitlab
raise 'Failed to determine the write location of the primary database'
end
- # Returns true if there was at least one host that has caught up with the given transaction.
+ # Finds any up to date replica for the given LSN location and stores an up to date replica in the
+ # SafeRequestStore to be used later for read-only queries. It returns a symbol to indicate if :any, :all or
+ # :none were found to be caught up.
def select_up_to_date_host(location)
all_hosts = @host_list.hosts.shuffle
- host = all_hosts.find { |host| host.caught_up?(location) }
+ first_caught_up_host = nil
+
+ # We must loop through all of them so that we know if all are caught up. Some callers only care about finding
+ # one caught up host and storing it in request_cache. But Sticking needs to know if ALL_CAUGHT_UP so that it
+ # can clear the LSN position from Redis and not ask again in future.
+ results = all_hosts.map do |host|
+ caught_up = host.caught_up?(location)
+ first_caught_up_host ||= host if caught_up
+ caught_up
+ end
+
+ ActiveSupport::Notifications.instrument(
+ 'caught_up_replica_pick.load_balancing',
+ { result: first_caught_up_host.present? }
+ )
- return false unless host
+ return NONE_CAUGHT_UP unless first_caught_up_host
- request_cache[CACHE_KEY] = host
+ request_cache[CACHE_KEY] = first_caught_up_host
- true
+ results.all? ? ALL_CAUGHT_UP : ANY_CAUGHT_UP
end
# Yields a block, retrying it upon error using an exponential backoff.
diff --git a/lib/gitlab/database/load_balancing/rack_middleware.rb b/lib/gitlab/database/load_balancing/rack_middleware.rb
index 99b1c31b04b..554205c8dcc 100644
--- a/lib/gitlab/database/load_balancing/rack_middleware.rb
+++ b/lib/gitlab/database/load_balancing/rack_middleware.rb
@@ -18,7 +18,7 @@ module Gitlab
# doesn't linger around.
clear
- unstick_or_continue_sticking(env)
+ find_caught_up_replica(env)
result = @app.call(env)
@@ -35,20 +35,22 @@ module Gitlab
#
# Typically this code will only be reachable for Rails requests as
# Grape data is not yet available at this point.
- def unstick_or_continue_sticking(env)
+ def find_caught_up_replica(env)
namespaces_and_ids = sticking_namespaces(env)
namespaces_and_ids.each do |(sticking, namespace, id)|
- sticking.unstick_or_continue_sticking(namespace, id)
+ sticking.find_caught_up_replica(namespace, id)
end
end
# Determine if we need to stick after handling a request.
def stick_if_necessary(env)
+ return unless ::Gitlab::Database::LoadBalancing::Session.current.performed_write?
+
namespaces_and_ids = sticking_namespaces(env)
namespaces_and_ids.each do |sticking, namespace, id|
- sticking.stick_if_necessary(namespace, id)
+ sticking.stick(namespace, id)
end
end
diff --git a/lib/gitlab/database/load_balancing/service_discovery.rb b/lib/gitlab/database/load_balancing/service_discovery.rb
index a0b0ad19f73..1f9ab1cfe98 100644
--- a/lib/gitlab/database/load_balancing/service_discovery.rb
+++ b/lib/gitlab/database/load_balancing/service_discovery.rb
@@ -118,7 +118,7 @@ module Gitlab
# The return value is the amount of time (in seconds) to wait before
# checking the DNS record for any changes.
def refresh_if_necessary
- interval, from_dns = addresses_from_dns
+ wait_time, from_dns = addresses_from_dns
current = addresses_from_load_balancer
@@ -132,7 +132,7 @@ module Gitlab
replace_hosts(from_dns)
end
- interval
+ wait_time
end
# Replaces all the hosts in the load balancer with the new ones,
@@ -151,8 +151,12 @@ module Gitlab
# started just before we added the new hosts it will use an old
# host/connection. While this connection will be checked in and out,
# it won't be explicitly disconnected.
- old_hosts.each do |host|
- host.disconnect!(timeout: disconnect_timeout)
+ if Gitlab::Utils.to_boolean(ENV['LOAD_BALANCER_PARALLEL_DISCONNECT'], default: false)
+ disconnect_old_hosts(old_hosts)
+ else
+ old_hosts.each do |host|
+ host.disconnect!(timeout: disconnect_timeout)
+ end
end
end
@@ -250,6 +254,41 @@ module Gitlab
@sampler ||= ::Gitlab::Database::LoadBalancing::ServiceDiscovery::Sampler
.new(max_replica_pools: @max_replica_pools)
end
+
+ def disconnect_old_hosts(hosts)
+ return unless hosts.present?
+
+ gentle_disconnect_start = ::Gitlab::Metrics::System.monotonic_time
+ gentle_disconnect_deadline = gentle_disconnect_start + disconnect_timeout
+
+ hosts_to_disconnect = hosts
+
+ gentle_disconnect_duration = Benchmark.realtime do
+ while ::Gitlab::Metrics::System.monotonic_time < gentle_disconnect_deadline
+ hosts_to_disconnect = hosts_to_disconnect.reject(&:try_disconnect)
+
+ break if hosts_to_disconnect.empty?
+
+ sleep(2)
+ end
+ end
+
+ force_disconnect_duration = Benchmark.realtime do
+ # This may wait up to 2 * pool.checkout_timeout per host (default 10 seconds per host)
+ hosts_to_disconnect.each(&:force_disconnect!)
+ end
+
+ formatted_hosts = hosts_to_disconnect.map { |h| "#{h.host}:#{h.port}" }
+ total_disconnect_duration = gentle_disconnect_duration + force_disconnect_duration
+
+ ::Gitlab::Database::LoadBalancing::Logger.info(
+ event: :host_list_disconnection,
+ message: "Disconnected #{formatted_hosts} old load balancing hosts after #{total_disconnect_duration}s",
+ gentle_disconnect_duration_s: gentle_disconnect_duration,
+ force_disconnect_duration_s: force_disconnect_duration,
+ total_disconnect_duration_s: total_disconnect_duration
+ )
+ end
end
end
end
diff --git a/lib/gitlab/database/load_balancing/service_discovery/sampler.rb b/lib/gitlab/database/load_balancing/service_discovery/sampler.rb
index 71870214156..4fc11cc1035 100644
--- a/lib/gitlab/database/load_balancing/service_discovery/sampler.rb
+++ b/lib/gitlab/database/load_balancing/service_discovery/sampler.rb
@@ -16,7 +16,7 @@ module Gitlab
def sample(addresses)
return addresses if @max_replica_pools.nil? || addresses.count <= @max_replica_pools
- ::Gitlab::Database::LoadBalancing::Logger.info(
+ ::Gitlab::Database::LoadBalancing::Logger.debug(
event: :host_list_limit_exceeded,
message: "Host list length exceeds max_replica_pools so random hosts will be chosen.",
max_replica_pools: @max_replica_pools,
diff --git a/lib/gitlab/database/load_balancing/sticking.rb b/lib/gitlab/database/load_balancing/sticking.rb
index f5cb83e398a..df07f510c8d 100644
--- a/lib/gitlab/database/load_balancing/sticking.rb
+++ b/lib/gitlab/database/load_balancing/sticking.rb
@@ -14,81 +14,38 @@ module Gitlab
@load_balancer = load_balancer
end
- # Unsticks or continues sticking the current request.
- #
- # This method also updates the Rack environment so #call can later
- # determine if we still need to stick or not.
- #
- # env - The Rack environment.
- # namespace - The namespace to use for sticking.
- # id - The identifier to use for sticking.
- # model - The ActiveRecord model to scope sticking to.
- def stick_or_unstick_request(env, namespace, id)
- unstick_or_continue_sticking(namespace, id)
-
- env[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT] ||= Set.new
- env[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT] << [self, namespace, id]
- end
-
- # Sticks to the primary if a write was performed.
- def stick_if_necessary(namespace, id)
- stick(namespace, id) if ::Gitlab::Database::LoadBalancing::Session.current.performed_write?
- end
-
- def all_caught_up?(namespace, id)
- location = last_write_location_for(namespace, id)
-
- return true unless location
-
- @load_balancer.select_up_to_date_host(location).tap do |found|
- ActiveSupport::Notifications.instrument(
- 'caught_up_replica_pick.load_balancing',
- { result: found }
- )
-
- unstick(namespace, id) if found
- end
- end
-
- # Selects hosts that have caught up with the primary. This ensures
- # atomic selection of the host to prevent the host list changing
- # in another thread.
- #
- # Returns true if one host was selected.
- def select_caught_up_replicas(namespace, id)
+ # Returns true if any caught up replica is found. This does not mean all replicas are caught up but the found
+ # caught up replica will be stored in the SafeRequestStore available as LoadBalancer#host for future queries.
+ # With use_primary_on_empty_location: true we will assume you need the primary if we can't find a matching
+ # location for the namespace, id pair. You should only use use_primary_on_empty_location in rare cases because
+ # we unstick once we find all replicas are caught up one time so it can be wasteful on the primary.
+ def find_caught_up_replica(namespace, id, use_primary_on_failure: true, use_primary_on_empty_location: false)
location = last_write_location_for(namespace, id)
- # Unlike all_caught_up?, we return false if no write location exists.
- # We want to be sure we talk to a replica that has caught up for a specific
- # write location. If no such location exists, err on the side of caution.
- return false unless location
-
- @load_balancer.select_up_to_date_host(location).tap do |selected|
- unstick(namespace, id) if selected
- end
- end
+ result = if location
+ up_to_date_result = @load_balancer.select_up_to_date_host(location)
- # Sticks to the primary if necessary, otherwise unsticks an object (if
- # it was previously stuck to the primary).
- def unstick_or_continue_sticking(namespace, id)
- return if all_caught_up?(namespace, id)
+ unstick(namespace, id) if up_to_date_result == LoadBalancer::ALL_CAUGHT_UP
- ::Gitlab::Database::LoadBalancing::Session.current.use_primary!
- end
+ up_to_date_result != LoadBalancer::NONE_CAUGHT_UP
+ else
+ # Some callers want to err on the side of caution and be really sure that a caught up replica was
+ # found. If we did not have any location to check then we must force `use_primary!` if they they
+ # use_primary_on_empty_location
+ !use_primary_on_empty_location
+ end
- # Select a replica that has caught up with the primary. If one has not been
- # found, stick to the primary.
- def select_valid_host(namespace, id)
- replica_selected =
- select_caught_up_replicas(namespace, id)
+ ::Gitlab::Database::LoadBalancing::Session.current.use_primary! if !result && use_primary_on_failure
- ::Gitlab::Database::LoadBalancing::Session.current.use_primary! unless replica_selected
+ result
end
# Starts sticking to the primary for the given namespace and id, using
# the latest WAL pointer from the primary.
def stick(namespace, id)
- mark_primary_write_location(namespace, id)
+ with_primary_write_location do |location|
+ set_write_location_for(namespace, id, location)
+ end
::Gitlab::Database::LoadBalancing::Session.current.use_primary!
end
@@ -102,6 +59,8 @@ module Gitlab
::Gitlab::Database::LoadBalancing::Session.current.use_primary!
end
+ private
+
def with_primary_write_location
# When only using the primary, there's no point in getting write
# locations, as the primary is always in sync with itself.
@@ -114,12 +73,6 @@ module Gitlab
yield(location)
end
- def mark_primary_write_location(namespace, id)
- with_primary_write_location do |location|
- set_write_location_for(namespace, id, location)
- end
- end
-
def unstick(namespace, id)
with_redis do |redis|
redis.del(redis_key_for(namespace, id))
@@ -144,8 +97,6 @@ module Gitlab
"database-load-balancing/write-location/#{name}/#{namespace}/#{id}"
end
- private
-
def with_redis(&block)
Gitlab::Redis::DbLoadBalancing.with(&block)
end
diff --git a/lib/gitlab/database/load_balancing/wal_tracking_receiver.rb b/lib/gitlab/database/load_balancing/wal_tracking_receiver.rb
index ef9bee42277..99af167bfc4 100644
--- a/lib/gitlab/database/load_balancing/wal_tracking_receiver.rb
+++ b/lib/gitlab/database/load_balancing/wal_tracking_receiver.rb
@@ -11,7 +11,7 @@ module Gitlab
::Gitlab::Database::LoadBalancing.each_load_balancer.all? do |lb|
if (location = wal_locations.with_indifferent_access[lb.name])
- lb.select_up_to_date_host(location)
+ lb.select_up_to_date_host(location) != LoadBalancer::NONE_CAUGHT_UP
else
true
end
diff --git a/lib/gitlab/database/migration_helpers/cascading_namespace_settings.rb b/lib/gitlab/database/migration_helpers/cascading_namespace_settings.rb
index 8a37e619285..6a82f3813d6 100644
--- a/lib/gitlab/database/migration_helpers/cascading_namespace_settings.rb
+++ b/lib/gitlab/database/migration_helpers/cascading_namespace_settings.rb
@@ -53,7 +53,7 @@ module Gitlab
def check_cascading_namespace_setting_consistency(setting_name, lock_name)
existing_columns = []
- %w(namespace_settings application_settings).each do |table|
+ %w[namespace_settings application_settings].each do |table|
existing_columns << "#{table}.#{setting_name}" if column_exists?(table.to_sym, setting_name)
existing_columns << "#{table}.#{lock_name}" if column_exists?(table.to_sym, lock_name)
end
diff --git a/lib/gitlab/database/migrations/instrumentation.rb b/lib/gitlab/database/migrations/instrumentation.rb
index 5f87bc6bbe2..5a120227d50 100644
--- a/lib/gitlab/database/migrations/instrumentation.rb
+++ b/lib/gitlab/database/migrations/instrumentation.rb
@@ -31,6 +31,8 @@ module Gitlab
observation
rescue StandardError => error
observation.error_message = error.message
+
+ raise
ensure
observation.walltime = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
diff --git a/lib/gitlab/database/partitioning.rb b/lib/gitlab/database/partitioning.rb
index 48f58920d52..d6cb9d25728 100644
--- a/lib/gitlab/database/partitioning.rb
+++ b/lib/gitlab/database/partitioning.rb
@@ -20,19 +20,21 @@ module Gitlab
registered_tables.merge(tables)
end
- def sync_partitions_ignore_db_error
- sync_partitions unless ENV['DISABLE_POSTGRES_PARTITION_CREATION_ON_STARTUP']
+ def sync_partitions_ignore_db_error(analyze: false)
+ sync_partitions(analyze: analyze) unless ENV['DISABLE_POSTGRES_PARTITION_CREATION_ON_STARTUP']
rescue ActiveRecord::ActiveRecordError, PG::Error
# ignore - happens when Rake tasks yet have to create a database, e.g. for testing
end
- def sync_partitions(models_to_sync = registered_for_sync, only_on: nil)
+ def sync_partitions(models_to_sync = registered_for_sync, only_on: nil, analyze: true)
+ return if Feature.enabled?(:disallow_database_ddl_feature_flags, type: :ops)
+
return unless Feature.enabled?(:partition_manager_sync_partitions, type: :ops)
Gitlab::AppLogger.info(message: 'Syncing dynamic postgres partitions')
Gitlab::Database::EachDatabase.each_model_connection(models_to_sync, only_on: only_on) do |model|
- PartitionManager.new(model).sync_partitions
+ PartitionManager.new(model).sync_partitions(analyze: analyze)
end
unless only_on
@@ -42,7 +44,7 @@ module Gitlab
model_connection_name = model.connection_db_config.name
Gitlab::Database::EachDatabase.each_connection(include_shared: false) do |connection, connection_name|
if connection_name != model_connection_name
- PartitionManager.new(model, connection: connection).sync_partitions
+ PartitionManager.new(model, connection: connection).sync_partitions(analyze: analyze)
end
end
end
@@ -60,6 +62,8 @@ module Gitlab
end
def drop_detached_partitions
+ return if Feature.enabled?(:disallow_database_ddl_feature_flags, type: :ops)
+
return unless Feature.enabled?(:partition_manager_sync_partitions, type: :ops)
Gitlab::AppLogger.info(message: 'Dropping detached postgres partitions')
diff --git a/lib/gitlab/database/partitioning/monthly_strategy.rb b/lib/gitlab/database/partitioning/monthly_strategy.rb
index 0f08a47d754..e6af4ac4574 100644
--- a/lib/gitlab/database/partitioning/monthly_strategy.rb
+++ b/lib/gitlab/database/partitioning/monthly_strategy.rb
@@ -4,18 +4,21 @@ module Gitlab
module Database
module Partitioning
class MonthlyStrategy
- attr_reader :model, :partitioning_key, :retain_for, :retain_non_empty_partitions
+ attr_reader :model, :partitioning_key, :retain_for, :retain_non_empty_partitions, :analyze_interval
# We create this many partitions in the future
HEADROOM = 6.months
delegate :table_name, to: :model
- def initialize(model, partitioning_key, retain_for: nil, retain_non_empty_partitions: false)
+ def initialize(
+ model, partitioning_key, retain_for: nil, retain_non_empty_partitions: false,
+ analyze_interval: nil)
@model = model
@partitioning_key = partitioning_key
@retain_for = retain_for
@retain_non_empty_partitions = retain_non_empty_partitions
+ @analyze_interval = analyze_interval
end
def current_partitions
diff --git a/lib/gitlab/database/partitioning/partition_manager.rb b/lib/gitlab/database/partitioning/partition_manager.rb
index 124fae582d3..cc5c49cc24a 100644
--- a/lib/gitlab/database/partitioning/partition_manager.rb
+++ b/lib/gitlab/database/partitioning/partition_manager.rb
@@ -4,9 +4,12 @@ module Gitlab
module Database
module Partitioning
class PartitionManager
+ include ::Gitlab::Utils::StrongMemoize
+
UnsafeToDetachPartitionError = Class.new(StandardError)
- LEASE_TIMEOUT = 1.minute
+ LEASE_TIMEOUT = 1.hour
+ STATEMENT_TIMEOUT = 1.hour
MANAGEMENT_LEASE_KEY = 'database_partition_management_%s'
RETAIN_DETACHED_PARTITIONS_FOR = 1.week
@@ -16,7 +19,7 @@ module Gitlab
@connection_name = @connection.pool.db_config.name
end
- def sync_partitions
+ def sync_partitions(analyze: true)
return skip_synching_partitions unless table_partitioned?
Gitlab::AppLogger.info(
@@ -33,6 +36,8 @@ module Gitlab
create(partitions_to_create) unless partitions_to_create.empty?
detach(partitions_to_detach) unless partitions_to_detach.empty?
+
+ run_analyze_on_partitioned_table if analyze
end
rescue ArgumentError => e
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
@@ -146,6 +151,61 @@ module Gitlab
connection_name: @connection_name
)
end
+
+ def run_analyze_on_partitioned_table
+ return if Feature.disabled?(:database_analyze_on_partitioned_tables)
+ return if ineligible_for_analyzing?
+
+ primary_transaction(statement_timeout: STATEMENT_TIMEOUT) do
+ # Running ANALYZE on partitioned table will go through itself and its partitions
+ connection.execute("ANALYZE VERBOSE #{model.quoted_table_name}")
+ end
+ end
+
+ def ineligible_for_analyzing?
+ analyze_interval.blank? ||
+ first_model_partition.blank? ||
+ last_analyzed_at_within_interval?
+ end
+
+ def last_analyzed_at_within_interval?
+ table_to_query = first_model_partition.identifier
+
+ primary_transaction do
+ # We don't need to get the last_analyze_time from partitioned table,
+ # because it's not supported and always returns NULL for PG version below 14
+ # Therefore, we can always get the last_analyze_time from the first partition
+ last_analyzed_at = connection.select_value(
+ "SELECT pg_stat_get_last_analyze_time('#{table_to_query}'::regclass)"
+ )
+ last_analyzed_at.present? && last_analyzed_at >= Time.current - analyze_interval
+ end
+ end
+
+ def first_model_partition
+ Gitlab::Database::SharedModel.using_connection(connection) do
+ Gitlab::Database::PostgresPartition.for_parent_table(model.table_name).first
+ end
+ end
+ strong_memoize_attr :first_model_partition
+
+ def analyze_interval
+ model.partitioning_strategy.analyze_interval
+ end
+
+ def primary_transaction(statement_timeout: nil)
+ Gitlab::Database::LoadBalancing::Session.current.use_primary do
+ connection.transaction(requires_new: false) do
+ if statement_timeout.present?
+ connection.execute(
+ format("SET LOCAL statement_timeout TO '%ds'", statement_timeout)
+ )
+ end
+
+ yield
+ end
+ end
+ end
end
end
end
diff --git a/lib/gitlab/database/partitioning/sliding_list_strategy.rb b/lib/gitlab/database/partitioning/sliding_list_strategy.rb
index 8f8afdfc551..77997e93480 100644
--- a/lib/gitlab/database/partitioning/sliding_list_strategy.rb
+++ b/lib/gitlab/database/partitioning/sliding_list_strategy.rb
@@ -4,15 +4,16 @@ module Gitlab
module Database
module Partitioning
class SlidingListStrategy
- attr_reader :model, :partitioning_key, :next_partition_if, :detach_partition_if
+ attr_reader :model, :partitioning_key, :next_partition_if, :detach_partition_if, :analyze_interval
delegate :table_name, to: :model
- def initialize(model, partitioning_key, next_partition_if:, detach_partition_if:)
+ def initialize(model, partitioning_key, next_partition_if:, detach_partition_if:, analyze_interval: nil)
@model = model
@partitioning_key = partitioning_key
@next_partition_if = next_partition_if
@detach_partition_if = detach_partition_if
+ @analyze_interval = analyze_interval
ensure_partitioning_column_ignored_or_readonly!
end
diff --git a/lib/gitlab/database/postgres_hll/batch_distinct_counter.rb b/lib/gitlab/database/postgres_hll/batch_distinct_counter.rb
index 4e973efebca..c8f6b2ada63 100644
--- a/lib/gitlab/database/postgres_hll/batch_distinct_counter.rb
+++ b/lib/gitlab/database/postgres_hll/batch_distinct_counter.rb
@@ -137,7 +137,7 @@ module Gitlab
# AND %{column} IS NOT NULL
def bucketed_data_sql
<<~SQL
- WITH hashed_attributes AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (%{source_query})
+ WITH hashed_attributes AS MATERIALIZED (%{source_query})
SELECT (attr_hash_32_bits & #{BIT_32_NORMALIZED_BUCKET_ID_MASK})::int AS bucket_num,
(31 - floor(log(2, min((attr_hash_32_bits & #{BIT_31_MASK})::int))))::int as bucket_hash
FROM hashed_attributes
diff --git a/lib/gitlab/database/query_analyzers/prevent_cross_database_modification.rb b/lib/gitlab/database/query_analyzers/prevent_cross_database_modification.rb
index b5a45eed3a4..a9f2b963340 100644
--- a/lib/gitlab/database/query_analyzers/prevent_cross_database_modification.rb
+++ b/lib/gitlab/database/query_analyzers/prevent_cross_database_modification.rb
@@ -202,6 +202,7 @@ module Gitlab
Rails.env.test? && caller_locations.any? do |l|
l.path.end_with?('lib/factory_bot/evaluation.rb') && l.label == 'create' ||
l.path.end_with?('lib/factory_bot/strategy/create.rb') ||
+ l.path.end_with?('lib/factory_bot/strategy/build.rb') ||
l.path.end_with?('shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb') && l.label == 'create_existing_record'
end
end
diff --git a/lib/gitlab/database/reindexing.rb b/lib/gitlab/database/reindexing.rb
index 4a1b0be848e..c7c93e6f292 100644
--- a/lib/gitlab/database/reindexing.rb
+++ b/lib/gitlab/database/reindexing.rb
@@ -6,7 +6,7 @@ module Gitlab
# Number of indexes to reindex per invocation
DEFAULT_INDEXES_PER_INVOCATION = 2
- SUPPORTED_TYPES = %w(btree gist).freeze
+ SUPPORTED_TYPES = %w[btree gist].freeze
# When dropping an index, we acquire a SHARE UPDATE EXCLUSIVE lock,
# which only conflicts with DDL and vacuum. We therefore execute this with a rather
@@ -16,6 +16,8 @@ module Gitlab
REMOVE_INDEX_RETRY_CONFIG = [[1.minute, 9.minutes]] * 30
def self.enabled?
+ return false if Feature.enabled?(:disallow_database_ddl_feature_flags, type: :ops)
+
Feature.enabled?(:database_reindexing, type: :ops)
end
@@ -26,9 +28,15 @@ module Gitlab
Gitlab::Database::SharedModel.logger = Logger.new($stdout) if Gitlab::Utils.to_boolean(ENV['LOG_QUERIES_TO_CONSOLE'], default: false)
# Hack: Before we do actual reindexing work, create async indexes
- Gitlab::Database::AsyncIndexes.create_pending_indexes! if Feature.enabled?(:database_async_index_creation, type: :ops)
+ if Feature.disabled?(:disallow_database_ddl_feature_flags, type: :ops) && Feature.enabled?(:database_async_index_creation, type: :ops)
+ Gitlab::Database::AsyncIndexes.create_pending_indexes!
+ end
+
Gitlab::Database::AsyncIndexes.drop_pending_indexes!
- Gitlab::Database::AsyncConstraints.validate_pending_entries! if Feature.enabled?(:database_async_foreign_key_validation, type: :ops)
+
+ if Feature.disabled?(:disallow_database_ddl_feature_flags, type: :ops) && Feature.enabled?(:database_async_foreign_key_validation, type: :ops)
+ Gitlab::Database::AsyncConstraints.validate_pending_entries!
+ end
automatic_reindexing
end
diff --git a/lib/gitlab/database/tables_truncate.rb b/lib/gitlab/database/tables_truncate.rb
index 7ae1981fa2b..f91146fff3d 100644
--- a/lib/gitlab/database/tables_truncate.rb
+++ b/lib/gitlab/database/tables_truncate.rb
@@ -5,7 +5,7 @@ module Gitlab
class TablesTruncate
GITLAB_SCHEMAS_TO_IGNORE = %i[gitlab_geo gitlab_embedding].freeze
- def initialize(database_name:, min_batch_size:, logger: nil, until_table: nil, dry_run: false)
+ def initialize(database_name:, min_batch_size: 5, logger: nil, until_table: nil, dry_run: false)
@database_name = database_name
@min_batch_size = min_batch_size
@logger = logger
@@ -19,19 +19,6 @@ module Gitlab
logger&.info "DRY RUN:" if dry_run
- schemas_for_connection = Gitlab::Database.gitlab_schemas_for_connection(connection)
- tables_to_truncate = Gitlab::Database::GitlabSchema.tables_to_schema.reject do |_, schema_name|
- GITLAB_SCHEMAS_TO_IGNORE.union(schemas_for_connection).include?(schema_name)
- end.keys
-
- Gitlab::Database::SharedModel.using_connection(connection) do
- Postgresql::DetachedPartition.find_each do |detached_partition|
- next if GITLAB_SCHEMAS_TO_IGNORE.union(schemas_for_connection).include?(detached_partition.table_schema)
-
- tables_to_truncate << detached_partition.fully_qualified_table_name
- end
- end
-
tables_sorted = Gitlab::Database::TablesSortedByForeignKeys.new(connection, tables_to_truncate).execute
# Checking if all the tables have the write-lock triggers
# to make sure we are deleting the right tables on the right database.
@@ -63,10 +50,41 @@ module Gitlab
truncate_tables_in_batches(tables_sorted)
end
+ def needs_truncation?
+ return false if single_database_setup?
+
+ sql = tables_to_truncate.map { |table_name| "(SELECT EXISTS( SELECT * FROM #{table_name} ))" }.join("\nUNION\n")
+
+ result = with_suppressed_query_analyzers do
+ connection.execute(sql).to_a
+ end
+
+ result.to_a.any? { |row| row['exists'] == true }
+ end
+
private
attr_accessor :database_name, :min_batch_size, :logger, :dry_run, :until_table
+ def tables_to_truncate
+ @tables_to_truncate ||= begin
+ schemas_for_connection = Gitlab::Database.gitlab_schemas_for_connection(connection)
+ tables = Gitlab::Database::GitlabSchema.tables_to_schema.reject do |_, schema_name|
+ GITLAB_SCHEMAS_TO_IGNORE.union(schemas_for_connection).include?(schema_name)
+ end.keys
+
+ Gitlab::Database::SharedModel.using_connection(connection) do
+ Postgresql::DetachedPartition.find_each do |detached_partition|
+ next if GITLAB_SCHEMAS_TO_IGNORE.union(schemas_for_connection).include?(detached_partition.table_schema)
+
+ tables << detached_partition.fully_qualified_table_name
+ end
+ end
+
+ tables
+ end
+ end
+
def connection
@connection ||= Gitlab::Database.database_base_models[database_name].connection
end
@@ -133,6 +151,12 @@ module Gitlab
ci_base_model = Gitlab::Database.database_base_models[:ci]
!!Gitlab::Database.db_config_share_with(ci_base_model.connection_db_config)
end
+
+ def with_suppressed_query_analyzers(&block)
+ Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection.with_suppressed do
+ Gitlab::Database::QueryAnalyzers::Ci::PartitioningRoutingAnalyzer.with_suppressed(&block)
+ end
+ end
end
end
end
diff --git a/lib/gitlab/database_importers/work_items/base_type_importer.rb b/lib/gitlab/database_importers/work_items/base_type_importer.rb
index 990fd53a370..000a1f50a92 100644
--- a/lib/gitlab/database_importers/work_items/base_type_importer.rb
+++ b/lib/gitlab/database_importers/work_items/base_type_importer.rb
@@ -20,7 +20,7 @@ module Gitlab
requirement_legacy: 'Requirement legacy',
test_reports: 'Test reports',
notifications: 'Notifications',
- current_user_todos: "Current user todos",
+ current_user_todos: 'Current user todos',
award_emoji: 'Award emoji',
linked_items: 'Linked items'
}.freeze
@@ -124,6 +124,7 @@ module Gitlab
:health_status,
:status,
:notifications,
+ :current_user_todos,
:award_emoji,
:linked_items
],
@@ -140,7 +141,8 @@ module Gitlab
:health_status,
:notifications,
:current_user_todos,
- :award_emoji
+ :award_emoji,
+ :linked_items
]
}.freeze
diff --git a/lib/gitlab/database_warnings.rb b/lib/gitlab/database_warnings.rb
new file mode 100644
index 00000000000..8df60ac6404
--- /dev/null
+++ b/lib/gitlab/database_warnings.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module DatabaseWarnings
+ def self.check_postgres_version_and_print_warning
+ return if Gitlab::Runtime.rails_runner?
+
+ Gitlab::Database.database_base_models.each do |name, model|
+ database = Gitlab::Database::Reflection.new(model)
+
+ next if database.postgresql_minimum_supported_version?
+
+ Kernel.warn ERB.new(Rainbow.new.wrap(<<~WARNING).red).result
+
+ ██†██†█████†██████†███†██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ€ ██†██████â€
+ ██†██â€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â€â€â€â€â€
+ ██†█†██â€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ ███â€
+ ██â€â–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€
+ â€â–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ â€â–ˆâ–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ â€â–ˆâ–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â€
+
+ ******************************************************************************
+ You are using PostgreSQL #{database.version} for the #{name} database, but this version of GitLab requires PostgreSQL >= <%= Gitlab::Database::MINIMUM_POSTGRES_VERSION %>.
+ <% if Rails.env.development? || Rails.env.test? %>
+ If using gitlab-development-kit, please find the relevant steps here:
+ https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/postgresql.md#upgrade-postgresql
+ <% end %>
+ Please upgrade your environment to a supported PostgreSQL version. See
+ https://docs.gitlab.com/ee/install/requirements.html#database for details.
+ ******************************************************************************
+ WARNING
+ rescue ActiveRecord::ActiveRecordError, PG::Error
+ # ignore - happens when Rake tasks yet have to create a database, e.g. for testing
+ end
+ end
+
+ def self.check_single_connection_and_print_warning
+ return if Gitlab::Runtime.rails_runner?
+ return unless Gitlab::Database.database_mode == Gitlab::Database::MODE_SINGLE_DATABASE
+
+ Kernel.warn ERB.new(Rainbow.new.wrap(<<~WARNING).red).result
+
+ ██†██†█████†██████†███†██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ€ ██†██████â€
+ ██†██â€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â€â€â€â€â€
+ ██†█†██â€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ ███â€
+ ██â€â–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â€â–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ ██â€
+ â€â–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ ██â€â–ˆâ–ˆâ€ â€â–ˆâ–ˆâ–ˆâ–ˆâ€â–ˆâ–ˆâ€â–ˆâ–ˆâ€ â€â–ˆâ–ˆâ–ˆâ–ˆâ€â€â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ€â€
+
+ ******************************************************************************
+ Your database has a single connection, and single connections were
+ deprecated in GitLab 15.9 https://docs.gitlab.com/ee/update/deprecations.html#single-database-connection-is-deprecated.
+
+ Please add a :ci section to your database, following these instructions:
+ https://docs.gitlab.com/ee/install/installation.html#configure-gitlab-db-settings.
+ ******************************************************************************
+ WARNING
+ end
+ end
+end
+
+Gitlab::DatabaseWarnings.prepend_mod_with('Gitlab::DatabaseWarnings')
diff --git a/lib/gitlab/dependency_linker/base_linker.rb b/lib/gitlab/dependency_linker/base_linker.rb
index aba6e0f033a..ff17010c11c 100644
--- a/lib/gitlab/dependency_linker/base_linker.rb
+++ b/lib/gitlab/dependency_linker/base_linker.rb
@@ -62,9 +62,9 @@ module Gitlab
end
def link_tag(name, url)
- href_attribute = %{href="#{ERB::Util.html_escape_once(url)}" } if Gitlab::UrlSanitizer.valid_web?(url)
+ href_attribute = %(href="#{ERB::Util.html_escape_once(url)}" ) if Gitlab::UrlSanitizer.valid_web?(url)
- %{<a #{href_attribute}rel="nofollow noreferrer noopener" target="_blank">#{ERB::Util.html_escape_once(name)}</a>}.html_safe
+ %(<a #{href_attribute}rel="nofollow noreferrer noopener" target="_blank">#{ERB::Util.html_escape_once(name)}</a>).html_safe
end
# Links package names based on regex.
diff --git a/lib/gitlab/diff/char_diff.rb b/lib/gitlab/diff/char_diff.rb
index 1b3af8f75ca..d686c43185b 100644
--- a/lib/gitlab/diff/char_diff.rb
+++ b/lib/gitlab/diff/char_diff.rb
@@ -47,7 +47,7 @@ module Gitlab
def to_html
@changes.map do |op, text|
- %{<span class="#{html_class_names(op)}">#{ERB::Util.html_escape(text)}</span>}
+ %(<span class="#{html_class_names(op)}">#{ERB::Util.html_escape(text)}</span>)
end.join.html_safe
end
diff --git a/lib/gitlab/diff/inline_diff_marker.rb b/lib/gitlab/diff/inline_diff_marker.rb
index c8cc1c0e649..f5afe189697 100644
--- a/lib/gitlab/diff/inline_diff_marker.rb
+++ b/lib/gitlab/diff/inline_diff_marker.rb
@@ -9,7 +9,7 @@ module Gitlab
def mark(line_inline_diffs)
super(line_inline_diffs) do |text, left:, right:, mode:|
- %{<span class="#{html_class_names(left, right, mode)}">#{text}</span>}.html_safe
+ %(<span class="#{html_class_names(left, right, mode)}">#{text}</span>).html_safe
end
end
diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb
index 75127098600..bb138115c7d 100644
--- a/lib/gitlab/diff/line.rb
+++ b/lib/gitlab/diff/line.rb
@@ -6,7 +6,7 @@ module Gitlab
# When SERIALIZE_KEYS is updated, to reset the redis cache entries you'll
# need to bump the VERSION constant on Gitlab::Diff::HighlightCache
#
- SERIALIZE_KEYS = %i(line_code rich_text text type index old_pos new_pos).freeze
+ SERIALIZE_KEYS = %i[line_code rich_text text type index old_pos new_pos].freeze
attr_reader :marker_ranges
attr_writer :text, :rich_text
diff --git a/lib/gitlab/doorkeeper_secret_storing/token/unique_application_token.rb b/lib/gitlab/doorkeeper_secret_storing/token/unique_application_token.rb
new file mode 100644
index 00000000000..e2ad2544b6c
--- /dev/null
+++ b/lib/gitlab/doorkeeper_secret_storing/token/unique_application_token.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module DoorkeeperSecretStoring
+ module Token
+ class UniqueApplicationToken
+ # Acronym for 'GitLab OAuth Application Secret'
+ OAUTH_APPLICATION_SECRET_PREFIX_FORMAT = "gloas-%{token}"
+
+ # Maintains compatibility with ::Doorkeeper::OAuth::Helpers::UniqueToken
+ # Returns a secure random token, prefixed with a GitLab identifier.
+ def self.generate(*)
+ format(OAUTH_APPLICATION_SECRET_PREFIX_FORMAT, token: SecureRandom.hex(32))
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/email/handler/create_note_handler.rb b/lib/gitlab/email/handler/create_note_handler.rb
index e6c64e2b1d6..7daa1bb96a1 100644
--- a/lib/gitlab/email/handler/create_note_handler.rb
+++ b/lib/gitlab/email/handler/create_note_handler.rb
@@ -50,7 +50,7 @@ module Gitlab
end
def create_note
- external_author = from_address if author == User.support_bot
+ external_author = from_address if author == Users::Internal.support_bot
sent_notification.create_reply(note_message, external_author)
end
@@ -67,7 +67,7 @@ module Gitlab
def validate_from_address!
# Recipieint is always set to Support bot for ServiceDesk issues so we should exclude those.
- return if author == User.support_bot
+ return if author == Users::Internal.support_bot
raise UserNotFoundError unless from_address && author.verified_email?(from_address)
end
diff --git a/lib/gitlab/email/handler/service_desk_handler.rb b/lib/gitlab/email/handler/service_desk_handler.rb
index 5d0e6ea61e1..949fa554aeb 100644
--- a/lib/gitlab/email/handler/service_desk_handler.rb
+++ b/lib/gitlab/email/handler/service_desk_handler.rb
@@ -117,7 +117,7 @@ module Gitlab
def create_issue!
result = ::Issues::CreateService.new(
container: project,
- current_user: User.support_bot,
+ current_user: Users::Internal.support_bot,
params: {
title: mail.subject,
description: message_including_template,
@@ -199,7 +199,7 @@ module Gitlab
def create_note(note)
::Notes::CreateService.new(
project,
- User.support_bot,
+ Users::Internal.support_bot,
noteable: @issue,
note: note
).execute
@@ -214,7 +214,7 @@ module Gitlab
end
def author
- User.support_bot
+ Users::Internal.support_bot
end
def add_email_participant
diff --git a/lib/gitlab/email/message/in_product_marketing.rb b/lib/gitlab/email/message/in_product_marketing.rb
deleted file mode 100644
index bd2c91755c8..00000000000
--- a/lib/gitlab/email/message/in_product_marketing.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- UnknownTrackError = Class.new(StandardError)
-
- def self.for(track)
- valid_tracks = Namespaces::InProductMarketingEmailsService::TRACKS.keys
- raise UnknownTrackError unless valid_tracks.include?(track)
-
- "Gitlab::Email::Message::InProductMarketing::#{track.to_s.classify}".constantize
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/message/in_product_marketing/admin_verify.rb b/lib/gitlab/email/message/in_product_marketing/admin_verify.rb
deleted file mode 100644
index 888f84cde23..00000000000
--- a/lib/gitlab/email/message/in_product_marketing/admin_verify.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- class AdminVerify < Base
- def subject_line
- s_('InProductMarketing|Create a custom CI runner with just a few clicks')
- end
-
- def tagline
- nil
- end
-
- def title
- s_('InProductMarketing|Spin up an autoscaling runner in GitLab')
- end
-
- def subtitle
- s_('InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!')
- end
-
- def body_line1
- ''
- end
-
- def body_line2
- ''
- end
-
- def cta_text
- s_('InProductMarketing|Create a custom runner')
- end
-
- def progress
- super(track_name: 'Admin')
- end
-
- def invite_members?
- user.can?(:admin_group_member, group)
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/message/in_product_marketing/base.rb b/lib/gitlab/email/message/in_product_marketing/base.rb
deleted file mode 100644
index bd20b7e5fc7..00000000000
--- a/lib/gitlab/email/message/in_product_marketing/base.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- class Base
- include Gitlab::Email::Message::InProductMarketing::Helper
- include Gitlab::Routing
- include Gitlab::Experiment::Dsl
-
- attr_accessor :format
-
- def initialize(group:, user:, series:, format: :html)
- @series = series
- @group = group
- @user = user
- @format = format
-
- validate_series!
- end
-
- def subject_line
- raise NotImplementedError
- end
-
- def tagline
- raise NotImplementedError
- end
-
- def title
- raise NotImplementedError
- end
-
- def subtitle
- raise NotImplementedError
- end
-
- def body_line1
- raise NotImplementedError
- end
-
- def body_line2
- raise NotImplementedError
- end
-
- def cta_text
- raise NotImplementedError
- end
-
- def cta_link
- case format
- when :html
- ActionController::Base.helpers.link_to cta_text, group_email_campaigns_url(group, track: track, series: series), target: '_blank', rel: 'noopener noreferrer'
- else
- [cta_text, group_email_campaigns_url(group, track: track, series: series)].join(' >> ')
- end
- end
-
- def invite_members?
- false
- end
-
- def invite_text
- s_('InProductMarketing|Do you have a teammate who would be perfect for this task?')
- end
-
- def invite_link
- action_link(s_('InProductMarketing|Invite them to help out.'), group_url(group, open_modal: 'invite_members_for_task'))
- end
-
- def unsubscribe
- self_managed_preferences_link = marketing_preference_link(track, series)
- unsubscribe_message(self_managed_preferences_link)
- end
-
- def progress(current: series + 1, total: total_series, track_name: track.to_s.humanize)
- if Gitlab.com?
- s_('InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series.') % { current_series: current, total_series: total, track: track_name }
- else
- s_('InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}.') % { current_series: current, total_series: total, track: track_name, unsubscribe_link: unsubscribe_link }
- end
- end
-
- def logo_path
- ["mailers/in_product_marketing", "#{track}-#{series}.png"].join('/')
- end
-
- def series?
- total_series > 0
- end
-
- protected
-
- attr_reader :group, :user, :series
-
- private
-
- def track
- self.class.name.demodulize.underscore.to_sym
- end
-
- def total_series
- Namespaces::InProductMarketingEmailsService::TRACKS[track][:interval_days].size
- end
-
- def marketing_preference_link(track, series)
- params = {
- utm_source: 'SM',
- utm_medium: 'email',
- utm_campaign: 'onboarding',
- utm_term: "#{track}_#{series}"
- }
-
- preference_link = "https://about.gitlab.com/company/preference-center/?#{params.to_query}"
-
- link(s_('InProductMarketing|update your preferences'), preference_link)
- end
-
- def validate_series!
- raise ArgumentError, "Only #{total_series} series available for this track." unless @series.between?(0, total_series - 1)
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/message/in_product_marketing/create.rb b/lib/gitlab/email/message/in_product_marketing/create.rb
deleted file mode 100644
index 68f9a9a21c9..00000000000
--- a/lib/gitlab/email/message/in_product_marketing/create.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- class Create < Base
- def subject_line
- [
- s_('InProductMarketing|Create a project in GitLab in 5 minutes'),
- s_('InProductMarketing|Import your project and code from GitHub, Bitbucket and others'),
- s_('InProductMarketing|Understand repository mirroring')
- ][series]
- end
-
- def tagline
- [
- s_('InProductMarketing|Get started today'),
- s_('InProductMarketing|Get our import guides'),
- s_('InProductMarketing|Need an alternative to importing?')
- ][series]
- end
-
- def title
- [
- s_('InProductMarketing|Take your first steps with GitLab'),
- s_('InProductMarketing|Start by importing your projects'),
- s_('InProductMarketing|How (and why) mirroring makes sense')
- ][series]
- end
-
- def subtitle
- [
- s_('InProductMarketing|Dig in and create a project and a repo'),
- s_("InProductMarketing|Here's what you need to know"),
- s_('InProductMarketing|Try it out')
- ][series]
- end
-
- def body_line1
- [
- s_("InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}.") % { project_link: project_link, repo_link: repo_link },
- s_("InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}.") % { github_link: github_link, bitbucket_link: bitbucket_link },
- s_("InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool.") % { mirroring_link: mirroring_link }
- ][series]
- end
-
- def body_line2
- [
- s_("InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started.") % { basics_link: basics_link },
- s_("InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}.") % { import_link: import_link },
- s_("InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD.") % { external_repo_link: external_repo_link }
- ][series]
- end
-
- def cta_text
- [
- s_('InProductMarketing|Create your first project!'),
- s_('InProductMarketing|Master the art of importing!'),
- s_('InProductMarketing|Understand your project options')
- ][series]
- end
-
- def invite_members?
- user.can?(:admin_group_member, group)
- end
-
- private
-
- def project_link
- link(s_('InProductMarketing|create a project'), help_page_url('user/project/index'))
- end
-
- def repo_link
- link(s_('InProductMarketing|set up a repo'), help_page_url('user/project/repository/index', anchor: 'create-a-repository'))
- end
-
- def github_link
- link(s_('InProductMarketing|GitHub Enterprise projects to GitLab'), help_page_url('user/project/import/github'))
- end
-
- def bitbucket_link
- link(s_('InProductMarketing|from Bitbucket'), help_page_url('user/project/import/bitbucket_server'))
- end
-
- def mirroring_link
- link(s_('InProductMarketing|repository mirroring'), help_page_url('user/project/repository/mirror/index'))
- end
-
- def basics_link
- link(s_('InProductMarketing|Git basics'), help_page_url('topics/git/index'))
- end
-
- def import_link
- link(s_('InProductMarketing|comprehensive guide'), help_page_url('user/project/import/index'))
- end
-
- def external_repo_link
- link(s_('InProductMarketing|connect an external repository'), new_project_url(anchor: 'cicd_for_external_repo'))
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/message/in_product_marketing/helper.rb b/lib/gitlab/email/message/in_product_marketing/helper.rb
index 73d1e0743cc..0770e5f4d76 100644
--- a/lib/gitlab/email/message/in_product_marketing/helper.rb
+++ b/lib/gitlab/email/message/in_product_marketing/helper.rb
@@ -64,15 +64,6 @@ module Gitlab
]
end
- def list(array)
- case format
- when :html
- tag.ul { array.map { |item| tag.li item } }
- else
- '- ' + array.join("\n- ")
- end
- end
-
def strong_options
case format
when :html
diff --git a/lib/gitlab/email/message/in_product_marketing/team.rb b/lib/gitlab/email/message/in_product_marketing/team.rb
deleted file mode 100644
index ca99dd12c8e..00000000000
--- a/lib/gitlab/email/message/in_product_marketing/team.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- class Team < Base
- def subject_line
- [
- s_('InProductMarketing|Working in GitLab = more efficient'),
- s_("InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"),
- s_('InProductMarketing|Your teams can be more efficient')
- ][series]
- end
-
- def tagline
- [
- s_('InProductMarketing|Invite your colleagues to join in less than one minute'),
- s_('InProductMarketing|Get your team set up on GitLab'),
- nil
- ][series]
- end
-
- def title
- [
- s_('InProductMarketing|Team work makes the dream work'),
- s_('InProductMarketing|*GitLab*, noun: a synonym for efficient teams'),
- s_('InProductMarketing|Find out how your teams are really doing')
- ][series]
- end
-
- def subtitle
- [
- s_('InProductMarketing|Actually, GitLab makes the team work (better)'),
- s_('InProductMarketing|Our tool brings all the things together'),
- s_("InProductMarketing|It's all in the stats")
- ][series]
- end
-
- def body_line1
- [
- [
- s_('InProductMarketing|Did you know teams that use GitLab are far more efficient?'),
- list([
- s_('InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day'),
- s_('InProductMarketing|Ticketmaster decreased their CI build time by 15X')
- ])
- ].join("\n"),
- s_("InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."),
- [
- s_('InProductMarketing|Stop wondering and use GitLab to answer questions like:'),
- list([
- s_('InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?'),
- s_('InProductMarketing|How many days does it take our team to complete various tasks?'),
- s_('InProductMarketing|What does our value stream timeline look like from product to development to review and production?')
- ])
- ].join("\n")
- ][series]
- end
-
- def body_line2
- [
- s_('InProductMarketing|Invite your colleagues and start shipping code faster.'),
- s_("InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."),
- s_('InProductMarketing|When your team is on GitLab these answers are a click away.')
- ][series]
- end
-
- def cta_text
- [
- s_('InProductMarketing|Invite your colleagues today'),
- s_('InProductMarketing|Invite your team in less than 60 seconds'),
- s_('InProductMarketing|Invite your team now')
- ][series]
- end
-
- def progress
- super(current: series + 2, total: 4)
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/message/in_product_marketing/team_short.rb b/lib/gitlab/email/message/in_product_marketing/team_short.rb
deleted file mode 100644
index 1d60a5fe4e5..00000000000
--- a/lib/gitlab/email/message/in_product_marketing/team_short.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- class TeamShort < Base
- def subject_line
- s_('InProductMarketing|Team up in GitLab for greater efficiency')
- end
-
- def tagline
- nil
- end
-
- def title
- s_('InProductMarketing|Turn coworkers into collaborators')
- end
-
- def subtitle
- s_('InProductMarketing|Invite your team today to build better code (and processes) together')
- end
-
- def body_line1
- ''
- end
-
- def body_line2
- ''
- end
-
- def cta_text
- s_('InProductMarketing|Invite your colleagues today')
- end
-
- def progress
- super(total: 4, track_name: 'Team')
- end
-
- def logo_path
- 'mailers/in_product_marketing/team-0.png'
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/message/in_product_marketing/trial.rb b/lib/gitlab/email/message/in_product_marketing/trial.rb
deleted file mode 100644
index 720262816b4..00000000000
--- a/lib/gitlab/email/message/in_product_marketing/trial.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- class Trial < Base
- def subject_line
- [
- s_('InProductMarketing|Go farther with GitLab'),
- s_('InProductMarketing|Automated security scans directly within GitLab'),
- s_('InProductMarketing|Take your source code management to the next level')
- ][series]
- end
-
- def tagline
- [
- s_('InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required'),
- s_('InProductMarketing|Improve app security with a 30-day trial'),
- s_('InProductMarketing|Start with a GitLab Ultimate free trial')
- ][series]
- end
-
- def title
- [
- s_('InProductMarketing|Give us one minute...'),
- s_("InProductMarketing|Security that's integrated into your development lifecycle"),
- s_('InProductMarketing|Improve code quality and streamline reviews')
- ][series]
- end
-
- def subtitle
- [
- s_('InProductMarketing|...and you can get a free trial of GitLab Ultimate'),
- s_('InProductMarketing|Try GitLab Ultimate for free'),
- s_('InProductMarketing|Better code in less time')
- ][series]
- end
-
- def body_line1
- [
- [
- s_("InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"),
- list([
- s_('InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels').html_safe % strong_options,
- s_('InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals').html_safe % strong_options,
- s_('InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection').html_safe % strong_options,
- s_('InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream').html_safe % strong_options
- ])
- ].join("\n"),
- s_('InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance.'),
- s_('InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process.')
- ][series]
- end
-
- def body_line2
- [
- s_('InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required.'),
- s_('InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required.'),
- s_('InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required.')
- ][series]
- end
-
- def cta_text
- [
- s_('InProductMarketing|Start a trial'),
- s_('InProductMarketing|Beef up your security'),
- s_('InProductMarketing|Start your trial now!')
- ][series]
- end
-
- def progress
- super(current: series + 2, total: 4)
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/message/in_product_marketing/trial_short.rb b/lib/gitlab/email/message/in_product_marketing/trial_short.rb
deleted file mode 100644
index 0fcd3fde4a6..00000000000
--- a/lib/gitlab/email/message/in_product_marketing/trial_short.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- class TrialShort < Base
- def subject_line
- s_('InProductMarketing|Be a DevOps hero')
- end
-
- def tagline
- nil
- end
-
- def title
- s_('InProductMarketing|Expand your DevOps journey with a free GitLab trial')
- end
-
- def subtitle
- s_('InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!')
- end
-
- def body_line1
- ''
- end
-
- def body_line2
- ''
- end
-
- def cta_text
- s_('InProductMarketing|Start a trial')
- end
-
- def progress
- super(total: 4, track_name: 'Trial')
- end
-
- def logo_path
- 'mailers/in_product_marketing/trial-0.png'
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/message/in_product_marketing/verify.rb b/lib/gitlab/email/message/in_product_marketing/verify.rb
deleted file mode 100644
index 3982a8b87fd..00000000000
--- a/lib/gitlab/email/message/in_product_marketing/verify.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Email
- module Message
- module InProductMarketing
- class Verify < Base
- def subject_line
- [
- s_('InProductMarketing|Feel the need for speed?'),
- s_('InProductMarketing|3 ways to dive into GitLab CI/CD'),
- s_('InProductMarketing|Explore the power of GitLab CI/CD')
- ][series]
- end
-
- def tagline
- [
- s_('InProductMarketing|Use GitLab CI/CD'),
- s_('InProductMarketing|Test, create, deploy'),
- s_('InProductMarketing|Are your runners ready?')
- ][series]
- end
-
- def title
- [
- s_('InProductMarketing|Rapid development, simplified'),
- s_('InProductMarketing|Get started with GitLab CI/CD'),
- s_('InProductMarketing|Launch GitLab CI/CD in 20 minutes or less')
- ][series]
- end
-
- def subtitle
- [
- s_('InProductMarketing|How to build and test faster'),
- s_('InProductMarketing|Explore the options'),
- s_('InProductMarketing|Follow our steps')
- ][series]
- end
-
- def body_line1
- [
- s_("InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}.") % { ci_link: ci_link },
- s_("InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"),
- s_("InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy.") % { quick_start_link: quick_start_link }
- ][series]
- end
-
- def body_line2
- [
- nil,
- list([
- s_('InProductMarketing|Start by %{performance_link}').html_safe % { performance_link: performance_link },
- s_('InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}').html_safe % { ci_template_link: ci_template_link },
- s_('InProductMarketing|And finally %{deploy_link} a Python application.').html_safe % { deploy_link: deploy_link }
- ]),
- nil
- ][series]
- end
-
- def cta_text
- [
- s_('InProductMarketing|Get to know GitLab CI/CD'),
- s_('InProductMarketing|Try it yourself'),
- s_('InProductMarketing|Explore GitLab CI/CD')
- ][series]
- end
-
- def invite_members?
- user.can?(:admin_group_member, group)
- end
-
- private
-
- def ci_link
- link(s_('InProductMarketing|how easy it is to get started'), help_page_url('ci/index'))
- end
-
- def quick_start_link
- link(s_('InProductMarketing|quick start guide'), help_page_url('ci/quick_start/index'))
- end
-
- def performance_link
- link(s_('InProductMarketing|testing browser performance'), help_page_url('user/project/merge_requests/browser_performance_testing'))
- end
-
- def ci_template_link
- link(s_('InProductMarketing|using a CI/CD template'), help_page_url('user/project/pages/getting_started/pages_ci_cd_template'))
- end
-
- def deploy_link
- link(s_('InProductMarketing|test and deploy'), help_page_url('ci/examples/test-and-deploy-python-application-to-heroku'))
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/email/service_desk/custom_email.rb b/lib/gitlab/email/service_desk/custom_email.rb
new file mode 100644
index 00000000000..30ae435a6ec
--- /dev/null
+++ b/lib/gitlab/email/service_desk/custom_email.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Email
+ module ServiceDesk
+ # Doesn't include Gitlab::Email::Common because a custom email doesn't
+ # support all features and methods of ingestable email addresses like
+ # incoming_email and service_desk_email.
+ module CustomEmail
+ class << self
+ def reply_address(issue, reply_key)
+ return if reply_key.nil?
+
+ custom_email = issue&.project&.service_desk_setting&.custom_email
+ return if custom_email.nil?
+
+ # Reply keys for custom email addresses always go before the @.
+ # We don't have a placeholder.
+ custom_email.sub('@', "+#{reply_key}@")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/etag_caching/middleware.rb b/lib/gitlab/etag_caching/middleware.rb
index 786a68c86f2..5f06f37821c 100644
--- a/lib/gitlab/etag_caching/middleware.rb
+++ b/lib/gitlab/etag_caching/middleware.rb
@@ -57,7 +57,7 @@ module Gitlab
end
def weak_etag_format(value)
- %{W/"#{value}"}
+ %(W/"#{value}")
end
def handle_cache_hit(etag, route, request)
diff --git a/lib/gitlab/etag_caching/router/graphql.rb b/lib/gitlab/etag_caching/router/graphql.rb
index 7946e768e00..50cdde88e2d 100644
--- a/lib/gitlab/etag_caching/router/graphql.rb
+++ b/lib/gitlab/etag_caching/router/graphql.rb
@@ -9,7 +9,7 @@ module Gitlab
ROUTES = [
[
- %r(\Apipelines/id/\d+\z),
+ %r{\Apipelines/id/\d+\z},
'pipelines_graph',
'continuous_integration'
],
@@ -19,12 +19,12 @@ module Gitlab
'pipeline_composition'
],
[
- %r(\Aon_demand_scan/counts/),
+ %r{\Aon_demand_scan/counts/},
'on_demand_scans',
'dynamic_application_security_testing'
],
[
- %r(\A/projects/.+/-/environments.json\z),
+ %r{\A/projects/.+/-/environments.json\z},
'environment_details',
'continuous_delivery'
]
diff --git a/lib/gitlab/etag_caching/router/rails.rb b/lib/gitlab/etag_caching/router/rails.rb
index 5fd592c43e4..333bffd371f 100644
--- a/lib/gitlab/etag_caching/router/rails.rb
+++ b/lib/gitlab/etag_caching/router/rails.rb
@@ -10,9 +10,8 @@ module Gitlab
# To match a regex the path needs to match the following:
# - Don't contain a reserved word (expect for the words used in the
# regex itself)
- # - Ending in `noteable/issue/<id>/notes` for the `issue_notes` route
# - Ending in `issues/id`/realtime_changes` for the `issue_title` route
- USED_IN_ROUTES = %w[noteable issue notes issues realtime_changes
+ USED_IN_ROUTES = %w[noteable issue issues realtime_changes
commit pipelines merge_requests builds
new environments].freeze
RESERVED_WORDS = Gitlab::PathRegex::ILLEGAL_PROJECT_PATH_WORDS - USED_IN_ROUTES
@@ -21,85 +20,73 @@ module Gitlab
ROUTES = [
[
- %r(#{RESERVED_WORDS_PREFIX}/noteable/issue/\d+/notes\z),
- 'issue_notes',
- ::Projects::NotesController,
- :index
- ],
- [
- %r(#{RESERVED_WORDS_PREFIX}/noteable/merge_request/\d+/notes\z),
- 'merge_request_notes',
- ::Projects::NotesController,
- :index
- ],
- [
- %r(#{RESERVED_WORDS_PREFIX}/issues/\d+/realtime_changes\z),
+ %r{#{RESERVED_WORDS_PREFIX}/issues/\d+/realtime_changes\z},
'issue_title',
::Projects::IssuesController,
:realtime_changes
],
[
- %r(#{RESERVED_WORDS_PREFIX}/commit/\S+/pipelines\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/commit/\S+/pipelines\.json\z},
'commit_pipelines',
::Projects::CommitController,
:pipelines
],
[
- %r(#{RESERVED_WORDS_PREFIX}/merge_requests/new\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/merge_requests/new\.json\z},
'new_merge_request_pipelines',
::Projects::MergeRequests::CreationsController,
:new
],
[
- %r(#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/pipelines\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/pipelines\.json\z},
'merge_request_pipelines',
::Projects::MergeRequestsController,
:pipelines
],
[
- %r(#{RESERVED_WORDS_PREFIX}/pipelines\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/pipelines\.json\z},
'project_pipelines',
::Projects::PipelinesController,
:index
],
[
- %r(#{RESERVED_WORDS_PREFIX}/pipelines/\d+\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/pipelines/\d+\.json\z},
'project_pipeline',
::Projects::PipelinesController,
:show
],
[
- %r(#{RESERVED_WORDS_PREFIX}/builds/\d+\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/builds/\d+\.json\z},
'project_build',
::Projects::BuildsController,
:show
],
[
- %r(#{RESERVED_WORDS_PREFIX}/clusters/\d+/environments\z),
+ %r{#{RESERVED_WORDS_PREFIX}/clusters/\d+/environments\z},
'cluster_environments',
::Groups::ClustersController,
:environments
],
[
- %r(#{RESERVED_WORDS_PREFIX}/-/environments\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/-/environments\.json\z},
'environments',
::Projects::EnvironmentsController,
:index
],
[
- %r(#{RESERVED_WORDS_PREFIX}/import/github/realtime_changes\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/import/github/realtime_changes\.json\z},
'realtime_changes_import_github',
::Import::GithubController,
:realtime_changes
],
[
- %r(#{RESERVED_WORDS_PREFIX}/import/gitea/realtime_changes\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/import/gitea/realtime_changes\.json\z},
'realtime_changes_import_gitea',
::Import::GiteaController,
:realtime_changes
],
[
- %r(#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/cached_widget\.json\z),
+ %r{#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/cached_widget\.json\z},
'merge_request_widget',
::Projects::MergeRequests::ContentController,
:cached_widget
diff --git a/lib/gitlab/etag_caching/store.rb b/lib/gitlab/etag_caching/store.rb
index f36a7a0603c..5fdf5ac9436 100644
--- a/lib/gitlab/etag_caching/store.rb
+++ b/lib/gitlab/etag_caching/store.rb
@@ -31,9 +31,7 @@ module Gitlab
private
def with_redis(&blk)
- # We use multistore as n interweaving double-write will result in n-1 subsequent requests
- # becoming a cache-miss, however, 2 interweaving .touch will lead to 1 cache miss anyway.
- Gitlab::Redis::EtagCache.with(&blk) # rubocop:disable CodeReuse/ActiveRecord
+ Gitlab::Redis::Cache.with(&blk) # rubocop:disable CodeReuse/ActiveRecord
end
def generate_etag
diff --git a/lib/gitlab/event_store.rb b/lib/gitlab/event_store.rb
index 474aac8073e..1e397b52ddf 100644
--- a/lib/gitlab/event_store.rb
+++ b/lib/gitlab/event_store.rb
@@ -36,26 +36,6 @@ module Gitlab
store.subscribe ::MergeRequests::UpdateHeadPipelineWorker, to: ::Ci::PipelineCreatedEvent
store.subscribe ::Namespaces::UpdateRootStatisticsWorker, to: ::Projects::ProjectDeletedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Pages::PageDeployedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Pages::PageDeletedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Projects::ProjectDeletedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Projects::ProjectCreatedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Projects::ProjectPathChangedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Projects::ProjectArchivedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Projects::ProjectTransferedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker,
- to: ::Projects::ProjectAttributesChangedEvent,
- if: -> (event) { event.pages_related? }
- store.subscribe ::Pages::InvalidateDomainCacheWorker,
- to: ::Projects::ProjectFeaturesChangedEvent,
- if: -> (event) { event.pages_related? }
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Groups::GroupTransferedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Groups::GroupPathChangedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Groups::GroupDeletedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::PagesDomains::PagesDomainDeletedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::PagesDomains::PagesDomainUpdatedEvent
- store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::PagesDomains::PagesDomainCreatedEvent
-
store.subscribe ::MergeRequests::CreateApprovalEventWorker, to: ::MergeRequests::ApprovedEvent
store.subscribe ::MergeRequests::CreateApprovalNoteWorker, to: ::MergeRequests::ApprovedEvent
store.subscribe ::MergeRequests::ResolveTodosAfterApprovalWorker, to: ::MergeRequests::ApprovedEvent
diff --git a/lib/gitlab/event_store/store.rb b/lib/gitlab/event_store/store.rb
index 2e5e0215687..318745cc192 100644
--- a/lib/gitlab/event_store/store.rb
+++ b/lib/gitlab/event_store/store.rb
@@ -15,12 +15,12 @@ module Gitlab
lock!
end
- def subscribe(worker, to:, if: nil)
+ def subscribe(worker, to:, if: nil, delay: nil)
condition = binding.local_variable_get('if')
Array(to).each do |event|
validate_subscription!(worker, event)
- subscriptions[event] << Gitlab::EventStore::Subscription.new(worker, condition)
+ subscriptions[event] << Gitlab::EventStore::Subscription.new(worker, condition, delay)
end
end
diff --git a/lib/gitlab/event_store/subscription.rb b/lib/gitlab/event_store/subscription.rb
index 01986355d2d..81a65f9a8ff 100644
--- a/lib/gitlab/event_store/subscription.rb
+++ b/lib/gitlab/event_store/subscription.rb
@@ -3,17 +3,22 @@
module Gitlab
module EventStore
class Subscription
- attr_reader :worker, :condition
+ attr_reader :worker, :condition, :delay
- def initialize(worker, condition)
+ def initialize(worker, condition, delay)
@worker = worker
@condition = condition
+ @delay = delay
end
def consume_event(event)
return unless condition_met?(event)
- worker.perform_async(event.class.name, event.data.deep_stringify_keys)
+ if delay
+ worker.perform_in(delay, event.class.name, event.data.deep_stringify_keys)
+ else
+ worker.perform_async(event.class.name, event.data.deep_stringify_keys)
+ end
# We rescue and track any exceptions here because we don't want to
# impact other subscribers if one is faulty.
diff --git a/lib/gitlab/fips.rb b/lib/gitlab/fips.rb
index b2c22182d4b..c71bd0e1ac9 100644
--- a/lib/gitlab/fips.rb
+++ b/lib/gitlab/fips.rb
@@ -8,15 +8,15 @@ module Gitlab
Technology = Gitlab::SSHPublicKey::Technology
SSH_KEY_TECHNOLOGIES = [
- Technology.new(:rsa, SSHData::PublicKey::RSA, [3072, 4096], %w(ssh-rsa)),
- Technology.new(:dsa, SSHData::PublicKey::DSA, [], %w(ssh-dss)),
- Technology.new(:ecdsa, SSHData::PublicKey::ECDSA, [256, 384, 521], %w(ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521)),
- Technology.new(:ed25519, SSHData::PublicKey::ED25519, [256], %w(ssh-ed25519)),
- Technology.new(:ecdsa_sk, SSHData::PublicKey::SKECDSA, [256], %w(sk-ecdsa-sha2-nistp256@openssh.com)),
- Technology.new(:ed25519_sk, SSHData::PublicKey::SKED25519, [256], %w(sk-ssh-ed25519@openssh.com))
+ Technology.new(:rsa, SSHData::PublicKey::RSA, [3072, 4096], %w[ssh-rsa]),
+ Technology.new(:dsa, SSHData::PublicKey::DSA, [], %w[ssh-dss]),
+ Technology.new(:ecdsa, SSHData::PublicKey::ECDSA, [256, 384, 521], %w[ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521]),
+ Technology.new(:ed25519, SSHData::PublicKey::ED25519, [256], %w[ssh-ed25519]),
+ Technology.new(:ecdsa_sk, SSHData::PublicKey::SKECDSA, [256], %w[sk-ecdsa-sha2-nistp256@openssh.com]),
+ Technology.new(:ed25519_sk, SSHData::PublicKey::SKED25519, [256], %w[sk-ssh-ed25519@openssh.com])
].freeze
- OPENSSL_DIGESTS = %i(SHA1 SHA256 SHA384 SHA512).freeze
+ OPENSSL_DIGESTS = %i[SHA1 SHA256 SHA384 SHA512].freeze
class << self
# Returns whether we should be running in FIPS mode or not
diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb
index ca1a2b2a077..b3f4f4fb933 100644
--- a/lib/gitlab/fogbugz_import/importer.rb
+++ b/lib/gitlab/fogbugz_import/importer.rb
@@ -115,13 +115,13 @@ module Gitlab
labels = []
[bug['sCategory'], bug['sPriority']].each do |label|
- unless label.blank?
- labels << label
+ next if label.blank?
- unless @known_labels.include?(label)
- create_label(label)
- @known_labels << label
- end
+ labels << label
+
+ unless @known_labels.include?(label)
+ create_label(label)
+ @known_labels << label
end
end
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 4e574d6de74..9150213020e 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -21,6 +21,7 @@ module Gitlab
InvalidPageToken = Class.new(BaseError)
InvalidRefFormatError = Class.new(BaseError)
ReferencesLockedError = Class.new(BaseError)
+ ReferenceStateMismatchError = Class.new(BaseError)
class ResourceExhaustedError < BaseError
def initialize(msg = nil, retry_after = 0)
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index bb5bbeeb27e..ae90291c0a3 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -120,7 +120,7 @@ module Gitlab
end
def initialize(options)
- %w(id name path size data mode commit_id binary).each do |key|
+ %w[id name path size data mode commit_id binary].each do |key|
self.__send__("#{key}=", options[key.to_sym]) # rubocop:disable GitlabSecurity/PublicSend
end
diff --git a/lib/gitlab/git/diff.rb b/lib/gitlab/git/diff.rb
index 72f7413500f..de25fa7e099 100644
--- a/lib/gitlab/git/diff.rb
+++ b/lib/gitlab/git/diff.rb
@@ -31,9 +31,9 @@ module Gitlab
# persisting limits over that.
MAX_PATCH_BYTES_UPPER_BOUND = 500.kilobytes
- SERIALIZE_KEYS = %i(diff new_path old_path a_mode b_mode new_file renamed_file deleted_file too_large).freeze
+ SERIALIZE_KEYS = %i[diff new_path old_path a_mode b_mode new_file renamed_file deleted_file too_large].freeze
- BINARY_NOTICE_PATTERN = %r(Binary files a\/(.*) and b\/(.*) differ).freeze
+ BINARY_NOTICE_PATTERN = %r{Binary files a\/(.*) and b\/(.*) differ}.freeze
class << self
def between(repo, head, base, options = {}, *paths)
@@ -81,7 +81,7 @@ module Gitlab
# exceeded
def filter_diff_options(options, default_options = {})
allowed_options = [:ignore_whitespace_change, :max_files, :max_lines,
- :limits, :expanded]
+ :limits, :expanded, :collect_all_paths]
if default_options
actual_defaults = default_options.dup
@@ -126,6 +126,10 @@ module Gitlab
limit / 10
end
+ def collect_patch_overage?
+ !!Feature.enabled?(:collect_all_diff_paths)
+ end
+
# Returns the limit for a single diff file (patch).
#
# Patches surpassing this limit shouldn't be persisted in the database
@@ -198,9 +202,13 @@ module Gitlab
# This is used by `to_hash` and `init_from_hash`.
alias_method :too_large, :too_large?
- def too_large!
+ def prune!
@diff = ''
@line_count = 0
+ end
+
+ def too_large!
+ prune!
@too_large = true
end
@@ -211,11 +219,19 @@ module Gitlab
end
def collapse!
- @diff = ''
- @line_count = 0
+ prune!
@collapsed = true
end
+ def overflow?
+ return @overflow if defined?(@overflow)
+
+ # If overflow is not defined, we're
+ # not recieveing a diff from Gitaly
+ # and overflow has no meaning
+ false
+ end
+
def json_safe_diff
return @diff unless detect_binary?(@diff)
@@ -248,7 +264,7 @@ module Gitlab
end
def init_from_gitaly(gitaly_diff)
- @diff = gitaly_diff.respond_to?(:patch) ? encode!(gitaly_diff.patch) : ''
+ @diff = gitaly_diff.try(:patch).present? ? encode!(gitaly_diff.patch) : ''
@new_path = encode!(gitaly_diff.to_path.dup)
@old_path = encode!(gitaly_diff.from_path.dup)
@a_mode = gitaly_diff.old_mode.to_s(8)
@@ -257,11 +273,19 @@ module Gitlab
@renamed_file = gitaly_diff.from_path != gitaly_diff.to_path
@deleted_file = gitaly_diff.to_id == BLANK_SHA
@too_large = gitaly_diff.too_large if gitaly_diff.respond_to?(:too_large)
+ gitaly_overflow = gitaly_diff.try(:overflow_marker)
+ @overflow = Diff.collect_patch_overage? && gitaly_overflow
collapse! if gitaly_diff.respond_to?(:collapsed) && gitaly_diff.collapsed
+ # Diffs exceeding limits returned from gitaly when "collect_all_paths" are enabled
+ # are already pruned, but should be "collapsed" as they have no content
+ @collapsed = true if @overflow
end
def prune_diff_if_eligible
+ # If we have overflow, diffs are already pruned, retain line counts
+ return if overflow?
+
if too_large?
::Gitlab::Metrics.add_event(:patch_hard_limit_bytes_hit)
diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb
index b4dd880ceb7..c021268a62a 100644
--- a/lib/gitlab/git/diff_collection.rb
+++ b/lib/gitlab/git/diff_collection.rb
@@ -13,6 +13,10 @@ module Gitlab
{ max_files: ::Commit.diff_safe_max_files, max_lines: ::Commit.diff_safe_max_lines }
end
+ def self.collect_all_paths?(collect_all_paths)
+ Gitlab::Git::Diff.collect_patch_overage? ? collect_all_paths : false
+ end
+
def self.limits(options = {})
limits = {}
defaults = default_limits
@@ -25,7 +29,7 @@ module Gitlab
limits[:safe_max_bytes] = limits[:safe_max_files] * 5.kilobytes # Average 5 KB per file
limits[:max_patch_bytes] = Gitlab::Git::Diff.patch_hard_limit_bytes
limits[:max_patch_bytes_for_file_extension] = options.fetch(:max_patch_bytes_for_file_extension, {})
-
+ limits[:collect_all_paths] = collect_all_paths?(options.fetch(:collect_all_paths, false))
limits
end
@@ -164,7 +168,12 @@ module Gitlab
if raw.overflow_marker
@overflow = true
- break
+ # If we're requesting patches with `collect_all_paths` enabled, then
+ # Once we hit the overflow marker, gitlay has still returned diffs, just without
+ # patches, only metadata
+ unless @limits[:collect_all_paths]
+ break
+ end
end
yield @array[i] = diff
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index d27f721bb2c..dfbf8292f54 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -763,6 +763,20 @@ module Gitlab
BatchedGitRefUpdates::Deletion.bulk_insert!(records)
end
+ # Update a list of references from X -> Y
+ #
+ # Ref list is expected to be an array of hashes in the form:
+ # old_sha:
+ # new_sha
+ # reference:
+ #
+ # When new_sha is Gitlab::Git::BLANK_SHA, then this will be deleted
+ def update_refs(ref_list)
+ wrapped_gitaly_errors do
+ gitaly_ref_client.update_refs(ref_list: ref_list) if ref_list.any?
+ end
+ end
+
def delete_refs(...)
wrapped_gitaly_errors do
gitaly_delete_refs(...)
@@ -959,10 +973,6 @@ module Gitlab
gitaly_repository_client.create_from_bundle(bundle_path)
end
- def create_from_snapshot(url, auth)
- gitaly_repository_client.create_from_snapshot(url, auth)
- end
-
def rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:, push_options: [], &block)
wrapped_gitaly_errors do
gitaly_operation_client.rebase(
diff --git a/lib/gitlab/git/rugged_impl/repository.rb b/lib/gitlab/git/rugged_impl/repository.rb
index ea10b4e7cd8..cd4eefa158e 100644
--- a/lib/gitlab/git/rugged_impl/repository.rb
+++ b/lib/gitlab/git/rugged_impl/repository.rb
@@ -13,7 +13,7 @@ module Gitlab
extend ::Gitlab::Utils::Override
include Gitlab::Git::RuggedImpl::UseRugged
- FEATURE_FLAGS = %i(rugged_find_commit rugged_tree_entries rugged_tree_entry rugged_commit_is_ancestor rugged_commit_tree_entry rugged_list_commits_by_oid).freeze
+ FEATURE_FLAGS = %i[rugged_find_commit rugged_tree_entries rugged_tree_entry rugged_commit_is_ancestor rugged_commit_tree_entry rugged_list_commits_by_oid].freeze
def alternate_object_directories
relative_object_directories.map { |d| File.join(path, d) }
diff --git a/lib/gitlab/git/tree.rb b/lib/gitlab/git/tree.rb
index 0895c0b8a22..6e97e412b91 100644
--- a/lib/gitlab/git/tree.rb
+++ b/lib/gitlab/git/tree.rb
@@ -71,7 +71,7 @@ module Gitlab
end
def initialize(options)
- %w(id name path flat_path type mode commit_id).each do |key|
+ %w[id name path flat_path type mode commit_id].each do |key|
self.send("#{key}=", options[key.to_sym]) # rubocop:disable GitlabSecurity/PublicSend
end
end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index a28952ab7bc..45283d51b1b 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -38,8 +38,8 @@ module Gitlab
Timing information for debugging purposes:
MESSAGE
- DOWNLOAD_COMMANDS = %w{git-upload-pack git-upload-archive}.freeze
- PUSH_COMMANDS = %w{git-receive-pack}.freeze
+ DOWNLOAD_COMMANDS = %w[git-upload-pack git-upload-archive].freeze
+ PUSH_COMMANDS = %w[git-receive-pack].freeze
ALL_COMMANDS = DOWNLOAD_COMMANDS + PUSH_COMMANDS
attr_reader :actor, :protocol, :authentication_abilities,
diff --git a/lib/gitlab/git_access_design.rb b/lib/gitlab/git_access_design.rb
index fb8df0d217a..bf89c01305a 100644
--- a/lib/gitlab/git_access_design.rb
+++ b/lib/gitlab/git_access_design.rb
@@ -4,23 +4,6 @@ module Gitlab
class GitAccessDesign < GitAccess
extend ::Gitlab::Utils::Override
- # TODO Re-factor so that correct container is passed to the constructor
- # and this method can be removed from here
- # https://gitlab.com/gitlab-org/gitlab/-/issues/409454
- def initialize(
- actor, container, protocol, authentication_abilities:, repository_path: nil, redirected_path: nil,
- auth_result_type: nil)
- super(
- actor,
- select_container(container),
- protocol,
- authentication_abilities: authentication_abilities,
- repository_path: repository_path,
- redirected_path: redirected_path,
- auth_result_type: auth_result_type
- )
- end
-
def check(_cmd, _changes)
check_protocol!
check_can_create_design!
@@ -35,10 +18,6 @@ module Gitlab
private
- def select_container(container)
- container.is_a?(::DesignManagement::Repository) ? container.project : container
- end
-
def check_protocol!
if protocol != 'web'
raise ::Gitlab::GitAccess::ForbiddenError, "Designs are only accessible using the web interface"
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 77d2ba315a8..f2ea6f17d90 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -128,7 +128,7 @@ module Gitlab
raise "storage #{storage.inspect} is missing a gitaly_address"
end
- unless %w(tcp unix tls dns).include?(URI(address).scheme)
+ unless %w[tcp unix tls dns].include?(URI(address).scheme)
raise "Unsupported Gitaly address: #{address.inspect} does not use URL scheme 'tcp' or 'unix' or 'tls' or 'dns'"
end
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 1ef5b0f96c2..573e3547202 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -418,6 +418,9 @@ module Gitlab
response = gitaly_client_call(@repository.storage, :commit_service, :raw_blame, request, timeout: GitalyClient.medium_timeout)
response.reduce([]) { |memo, msg| memo << msg.data }.join
+ # Temporary fix, use structured errors when they are available: https://gitlab.com/gitlab-org/gitaly/-/issues/5594
+ rescue GRPC::Internal
+ ""
end
def find_commit(revision)
diff --git a/lib/gitlab/gitaly_client/diff.rb b/lib/gitlab/gitaly_client/diff.rb
index dd192ccde1a..c30b8ab1bc8 100644
--- a/lib/gitlab/gitaly_client/diff.rb
+++ b/lib/gitlab/gitaly_client/diff.rb
@@ -3,7 +3,7 @@
module Gitlab
module GitalyClient
class Diff
- ATTRS = %i(from_path to_path old_mode new_mode from_id to_id patch overflow_marker collapsed too_large).freeze
+ ATTRS = %i[from_path to_path old_mode new_mode from_id to_id patch overflow_marker collapsed too_large].freeze
include AttributesBag
end
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index fe76543548b..905588c2afc 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -553,7 +553,8 @@ module Gitlab
message: encode_binary(message),
start_branch_name: encode_binary(start_branch_name.to_s),
start_repository: start_repository.gitaly_repository,
- dry_run: dry_run
+ dry_run: dry_run,
+ timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
gitaly_client_call(
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index 45edfd4cbbf..c251c126b07 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -122,6 +122,37 @@ module Gitlab
end
end
+ def update_refs(ref_list:)
+ request = Enumerator.new do |y|
+ ref_list.each_slice(100) do |refs|
+ updates = refs.map do |ref_pair|
+ Gitaly::UpdateReferencesRequest::Update.new(
+ old_object_id: ref_pair[:old_sha],
+ new_object_id: ref_pair[:new_sha],
+ reference: encode_binary(ref_pair[:reference])
+ )
+ end
+
+ y.yield Gitaly::UpdateReferencesRequest.new(repository: @gitaly_repo, updates: updates)
+ end
+ end
+
+ gitaly_client_call(@repository.storage, :ref_service, :update_references, request, timeout: GitalyClient.long_timeout)
+ rescue GRPC::BadStatus => e
+ detailed_error = GitalyClient.decode_detailed_error(e)
+
+ case detailed_error.try(:error)
+ when :invalid_format
+ raise Gitlab::Git::InvalidRefFormatError, "references have an invalid format: #{detailed_error.invalid_format.refs.join(",")}"
+ when :references_locked
+ raise Gitlab::Git::ReferencesLockedError
+ when :reference_state_mismatch
+ raise Gitlab::Git::ReferenceStateMismatchError
+ else
+ raise e
+ end
+ end
+
def delete_refs(refs: [], except_with_prefixes: [])
request = Gitaly::DeleteRefsRequest.new(
repository: @gitaly_repo,
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index b2d5f9c7e13..9ea541e083d 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -237,22 +237,6 @@ module Gitlab
)
end
- def create_from_snapshot(http_url, http_auth)
- request = Gitaly::CreateRepositoryFromSnapshotRequest.new(
- repository: @gitaly_repo,
- http_url: http_url,
- http_auth: http_auth
- )
-
- gitaly_client_call(
- @storage,
- :repository_service,
- :create_repository_from_snapshot,
- request,
- timeout: GitalyClient.long_timeout
- )
- end
-
def write_ref(ref_path, ref, old_ref)
request = Gitaly::WriteRefRequest.new(
repository: @gitaly_repo,
diff --git a/lib/gitlab/gitaly_client/wiki_page.rb b/lib/gitlab/gitaly_client/wiki_page.rb
index 757a429fb8a..f6ea2c96bbb 100644
--- a/lib/gitlab/gitaly_client/wiki_page.rb
+++ b/lib/gitlab/gitaly_client/wiki_page.rb
@@ -3,7 +3,7 @@
module Gitlab
module GitalyClient
class WikiPage
- ATTRS = %i(title format url_path path name historical raw_data).freeze
+ ATTRS = %i[title format url_path path name historical raw_data].freeze
include AttributesBag
include Gitlab::EncodingHelper
diff --git a/lib/gitlab/github_import.rb b/lib/gitlab/github_import.rb
index 3b19b9d16d2..d48b25842b3 100644
--- a/lib/gitlab/github_import.rb
+++ b/lib/gitlab/github_import.rb
@@ -26,7 +26,7 @@ module Gitlab
def self.ghost_user_id
key = 'github-import/ghost-user-id'
- Gitlab::Cache::Import::Caching.read_integer(key) || Gitlab::Cache::Import::Caching.write(key, User.select(:id).ghost.id)
+ Gitlab::Cache::Import::Caching.read_integer(key) || Gitlab::Cache::Import::Caching.write(key, Users::Internal.ghost.id)
end
# Get formatted GitHub import URL. If github.com is in the import URL, this will return nil and octokit will use the default github.com API URL
diff --git a/lib/gitlab/github_import/attachments_downloader.rb b/lib/gitlab/github_import/attachments_downloader.rb
index b71d5f753f2..4db55a6aabb 100644
--- a/lib/gitlab/github_import/attachments_downloader.rb
+++ b/lib/gitlab/github_import/attachments_downloader.rb
@@ -8,15 +8,17 @@ module Gitlab
include ::BulkImports::FileDownloads::Validations
DownloadError = Class.new(StandardError)
+ UnsupportedAttachmentError = Class.new(StandardError)
FILENAME_SIZE_LIMIT = 255 # chars before the extension
DEFAULT_FILE_SIZE_LIMIT = 25.megabytes
TMP_DIR = File.join(Dir.tmpdir, 'github_attachments').freeze
- attr_reader :file_url, :filename, :file_size_limit
+ attr_reader :file_url, :filename, :file_size_limit, :options
- def initialize(file_url, file_size_limit: DEFAULT_FILE_SIZE_LIMIT)
+ def initialize(file_url, options: {}, file_size_limit: DEFAULT_FILE_SIZE_LIMIT)
@file_url = file_url
+ @options = options
@file_size_limit = file_size_limit
filename = URI(file_url).path.split('/').last
@@ -27,7 +29,9 @@ module Gitlab
validate_content_length
validate_filepath
- file = download
+ redirection_url = get_assets_download_redirection_url
+ file = download_from(redirection_url)
+
validate_symlink
file
end
@@ -47,9 +51,34 @@ module Gitlab
Gitlab::HTTP.perform_request(Net::HTTP::Head, file_url, {}).headers
end
- def download
+ # Github /assets redirection link will redirect to aws which has its own authorization.
+ # Keeping our bearer token will cause request rejection
+ # eg. Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter,
+ # Signature query string parameter or the Authorization header should be specified.
+ def get_assets_download_redirection_url
+ return file_url unless file_url.starts_with?(github_assets_url_regex)
+
+ options[:follow_redirects] = false
+ response = Gitlab::HTTP.perform_request(Net::HTTP::Get, file_url, options)
+ raise_error("expected a redirect response, got #{response.code}") unless response.redirection?
+
+ redirection_url = response.headers[:location]
+ filename = URI.parse(redirection_url).path
+
+ unless Gitlab::GithubImport::Markdown::Attachment::MEDIA_TYPES.any? { |type| filename.ends_with?(type) }
+ raise UnsupportedAttachmentError
+ end
+
+ redirection_url
+ end
+
+ def github_assets_url_regex
+ %r{#{Regexp.escape(::Gitlab::GithubImport::MarkdownText.github_url)}/.*/assets/}
+ end
+
+ def download_from(url)
file = File.open(filepath, 'wb')
- Gitlab::HTTP.perform_request(Net::HTTP::Get, file_url, stream_body: true) { |batch| file.write(batch) }
+ Gitlab::HTTP.perform_request(Net::HTTP::Get, url, stream_body: true) { |batch| file.write(batch) }
file
end
diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb
index 886563a6f69..23d4faa3dde 100644
--- a/lib/gitlab/github_import/client.rb
+++ b/lib/gitlab/github_import/client.rb
@@ -67,10 +67,18 @@ module Gitlab
end
# Returns the details of a GitHub user.
+ # 304 (Not Modified) status means the user is cached - API won't return user data.
#
- # username - The username of the user.
- def user(username)
- with_rate_limit { octokit.user(username).to_h }
+ # @param username[String] the username of the user.
+ # @param options[Hash] the optional parameters.
+ def user(username, options = {})
+ with_rate_limit do
+ user = octokit.user(username, options)
+
+ next if octokit.last_response&.status == 304
+
+ user.to_h
+ end
end
def pull_request_reviews(repo_name, iid)
diff --git a/lib/gitlab/github_import/importer/note_attachments_importer.rb b/lib/gitlab/github_import/importer/note_attachments_importer.rb
index 266ee2938ba..26472b0d468 100644
--- a/lib/gitlab/github_import/importer/note_attachments_importer.rb
+++ b/lib/gitlab/github_import/importer/note_attachments_importer.rb
@@ -4,14 +4,15 @@ module Gitlab
module GithubImport
module Importer
class NoteAttachmentsImporter
- attr_reader :note_text, :project
+ attr_reader :note_text, :project, :client
# note_text - An instance of `Gitlab::GithubImport::Representation::NoteText`.
# project - An instance of `Project`.
# client - An instance of `Gitlab::GithubImport::Client`.
- def initialize(note_text, project, _client = nil)
+ def initialize(note_text, project, client)
@note_text = note_text
@project = project
+ @client = client
end
def execute
@@ -33,7 +34,7 @@ module Gitlab
if attachment.part_of_project_blob?(project_import_source)
convert_project_content_link(attachment.url, project_import_source)
- elsif attachment.media? || attachment.doc_belongs_to_project?(project_import_source)
+ elsif attachment.media?(project_import_source) || attachment.doc_belongs_to_project?(project_import_source)
download_attachment(attachment)
else # url to other GitHub project
attachment.url
@@ -53,14 +54,24 @@ module Gitlab
# in: an instance of Gitlab::GithubImport::Markdown::Attachment
# out: gitlab attachment markdown url
def download_attachment(attachment)
- downloader = ::Gitlab::GithubImport::AttachmentsDownloader.new(attachment.url)
+ downloader = ::Gitlab::GithubImport::AttachmentsDownloader.new(attachment.url, options: options)
file = downloader.perform
uploader = UploadService.new(project, file, FileUploader).execute
uploader.to_h[:url]
+ rescue ::Gitlab::GithubImport::AttachmentsDownloader::UnsupportedAttachmentError
+ attachment.url
ensure
downloader&.delete
end
+ def options
+ {
+ headers: {
+ 'Authorization' => "Bearer #{client.octokit.access_token}"
+ }
+ }
+ end
+
def update_note_record(text)
case note_text.record_type
when ::Release.name
diff --git a/lib/gitlab/github_import/markdown/attachment.rb b/lib/gitlab/github_import/markdown/attachment.rb
index e270cfba619..0d8f3196719 100644
--- a/lib/gitlab/github_import/markdown/attachment.rb
+++ b/lib/gitlab/github_import/markdown/attachment.rb
@@ -57,7 +57,8 @@ module Gitlab
def github_url?(url, docs: false, media: false)
if media
- url.start_with?(::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN)
+ url.start_with?(::Gitlab::GithubImport::MarkdownText.github_url,
+ ::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN)
elsif docs
url.start_with?(::Gitlab::GithubImport::MarkdownText.github_url)
end
@@ -65,6 +66,9 @@ module Gitlab
def whitelisted_type?(url, docs: false, media: false)
if media
+ # We do not know the file extension type from the /assets markdown
+ return true if url.start_with?(::Gitlab::GithubImport::MarkdownText.github_url)
+
MEDIA_TYPES.any? { |type| url.end_with?(type) }
elsif docs
DOC_TYPES.any? { |type| url.end_with?(type) }
@@ -91,8 +95,11 @@ module Gitlab
)
end
- def media?
- url.start_with?(::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN)
+ def media?(import_source)
+ url.start_with?(
+ "#{::Gitlab::GithubImport::MarkdownText.github_url}/#{import_source}/assets",
+ ::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN
+ )
end
def inspect
diff --git a/lib/gitlab/github_import/object_counter.rb b/lib/gitlab/github_import/object_counter.rb
index 7ee64b2abac..88e91800cee 100644
--- a/lib/gitlab/github_import/object_counter.rb
+++ b/lib/gitlab/github_import/object_counter.rb
@@ -14,6 +14,8 @@ module Gitlab
CACHING = Gitlab::Cache::Import::Caching
+ IMPORT_CACHING_TIMEOUT = 2.weeks.to_i
+
class << self
# Increments the project and the global counters if the given value is >= 1
def increment(project, object_type, operation, value: 1)
@@ -36,7 +38,7 @@ module Gitlab
# After import is completed we store this information in project's import_checksums
return cached_summary if cached_summary != EMPTY_SUMMARY || project.import_state.blank?
- project.import_state.in_progress? ? cached_summary : project.import_checksums
+ project.import_state.completed? ? project.import_checksums : cached_summary
end
private
@@ -50,7 +52,7 @@ module Gitlab
.sort
.each do |counter|
object_type = counter.split('/').last
- result[operation][object_type] = CACHING.read_integer(counter)
+ result[operation][object_type] = CACHING.read_integer(counter) || 0
end
end
end
@@ -84,11 +86,11 @@ module Gitlab
add_counter_to_list(project, operation, counter_key)
- CACHING.increment_by(counter_key, value)
+ CACHING.increment_by(counter_key, value, timeout: IMPORT_CACHING_TIMEOUT)
end
def add_counter_to_list(project, operation, key)
- CACHING.set_add(counter_list_key(project, operation), key)
+ CACHING.set_add(counter_list_key(project, operation), key, timeout: IMPORT_CACHING_TIMEOUT)
end
def counter_list_key(project, operation)
diff --git a/lib/gitlab/github_import/user_finder.rb b/lib/gitlab/github_import/user_finder.rb
index 57365ebe206..1832f071a44 100644
--- a/lib/gitlab/github_import/user_finder.rb
+++ b/lib/gitlab/github_import/user_finder.rb
@@ -28,6 +28,17 @@ module Gitlab
EMAIL_FOR_USERNAME_CACHE_KEY =
'github-import/user-finder/email-for-username/%s'
+ # The base cache key to use for caching the user ETAG response headers
+ USERNAME_ETAG_CACHE_KEY = 'github-import/user-finder/user-etag/%s'
+
+ # The base cache key to store whether an email has been fetched for a project
+ EMAIL_FETCHED_FOR_PROJECT_CACHE_KEY = 'github-import/user-finder/%{project}/email-fetched/%{username}'
+
+ EMAIL_API_CALL_LOGGING_MESSAGE = {
+ true => 'Fetching email from GitHub with ETAG header',
+ false => 'Fetching email from GitHub'
+ }.freeze
+
# project - An instance of `Project`
# client - An instance of `Gitlab::GithubImport::Client`
def initialize(project, client)
@@ -109,24 +120,39 @@ module Gitlab
id_for_github_id(id) || id_for_github_email(email)
end
- # Find the public email of a given username in GitHub. The public email is cached to avoid multiple calls to
- # GitHub. In case the username does not exist or the public email is nil, a blank value is cached to also prevent
- # multiple calls to GitHub.
+ # Find the public email of a given username in GitHub.
+ # The email is cached to avoid multiple calls to GitHub. The cache is shared among all projects.
+ # If the email was not found, a blank email is cached.
+ # If the email is blank, we attempt to fetch it from GitHub using an ETAG request once for every project.
+
+ # @param username [String] The username of the GitHub user.
#
# @return [String] If public email is found
# @return [Nil] If public email or username does not exist
def email_for_github_username(username)
- cache_key = EMAIL_FOR_USERNAME_CACHE_KEY % username
- email = Gitlab::Cache::Import::Caching.read(cache_key)
+ email = read_email_from_cache(username)
+
+ if email.blank? && !email_fetched_for_project?(username)
+ # If an ETAG is available, make an API call with the ETAG.
+ # Only make a rate-limited API call if the ETAG is not available and the email is nil.
+ etag = read_etag_from_cache(username)
+ email = fetch_email_from_github(username, etag: etag) || email
- if email.nil?
- user = client.user(username)
- email = Gitlab::Cache::Import::Caching.write(cache_key, user[:email].to_s, timeout: timeout(user[:email]))
+ cache_email!(username, email)
+ cache_etag!(username) if email.blank? && etag.nil?
+
+ # If a non-blank email is cached, we don't need the ETAG or project check caches.
+ # Otherwise, indicate that the project has been checked.
+ if email.present?
+ clear_caches!(username)
+ else
+ set_project_as_checked!(username)
+ end
end
email.presence
rescue ::Octokit::NotFound
- Gitlab::Cache::Import::Caching.write(cache_key, '')
+ cache_email!(username, '')
nil
end
@@ -192,12 +218,66 @@ module Gitlab
private
- def timeout(email)
- if email
- Gitlab::Cache::Import::Caching::TIMEOUT
- else
- Gitlab::Cache::Import::Caching::SHORTER_TIMEOUT
- end
+ def read_email_from_cache(username)
+ Gitlab::Cache::Import::Caching.read(email_cache_key(username))
+ end
+
+ def read_etag_from_cache(username)
+ Gitlab::Cache::Import::Caching.read(etag_cache_key(username))
+ end
+
+ def email_fetched_for_project?(username)
+ email_fetched_for_project_cache_key = email_fetched_for_project_cache_key(username)
+ Gitlab::Cache::Import::Caching.read(email_fetched_for_project_cache_key)
+ end
+
+ def fetch_email_from_github(username, etag: nil)
+ log(EMAIL_API_CALL_LOGGING_MESSAGE[etag.present?], username: username)
+ user = client.user(username, { headers: { 'If-None-Match' => etag }.compact })
+
+ user[:email] || '' if user
+ end
+
+ def cache_email!(username, email)
+ return unless email
+
+ Gitlab::Cache::Import::Caching.write(email_cache_key(username), email)
+ end
+
+ def cache_etag!(username)
+ etag = client.octokit.last_response.headers[:etag]
+ Gitlab::Cache::Import::Caching.write(etag_cache_key(username), etag)
+ end
+
+ def set_project_as_checked!(username)
+ Gitlab::Cache::Import::Caching.write(email_fetched_for_project_cache_key(username), 1)
+ end
+
+ def clear_caches!(username)
+ Gitlab::Cache::Import::Caching.expire(etag_cache_key(username), 0)
+ Gitlab::Cache::Import::Caching.expire(email_fetched_for_project_cache_key(username), 0)
+ end
+
+ def email_cache_key(username)
+ EMAIL_FOR_USERNAME_CACHE_KEY % username
+ end
+
+ def etag_cache_key(username)
+ USERNAME_ETAG_CACHE_KEY % username
+ end
+
+ def email_fetched_for_project_cache_key(username)
+ format(EMAIL_FETCHED_FOR_PROJECT_CACHE_KEY, project: project.id, username: username)
+ end
+
+ def log(message, username: nil)
+ Gitlab::Import::Logger.info(
+ import_type: :github,
+ project_id: project.id,
+ class: self.class.name,
+ username: username,
+ message: message
+ )
end
end
end
diff --git a/lib/gitlab/gl_repository.rb b/lib/gitlab/gl_repository.rb
index 9161a1a138f..5745b65b6fc 100644
--- a/lib/gitlab/gl_repository.rb
+++ b/lib/gitlab/gl_repository.rb
@@ -34,7 +34,8 @@ module Gitlab
DESIGN = ::Gitlab::GlRepository::RepoType.new(
name: :design,
access_checker_class: ::Gitlab::GitAccessDesign,
- repository_resolver: -> (project) { project.find_or_create_design_management_repository.repository },
+ repository_resolver: -> (design_management_repository) { design_management_repository.repository },
+ project_resolver: -> (design_management_repository) { design_management_repository&.project },
suffix: :design,
container_class: DesignManagement::Repository
).freeze
diff --git a/lib/gitlab/gl_repository/repo_type.rb b/lib/gitlab/gl_repository/repo_type.rb
index 26b0ff86f67..0c0d9bafa85 100644
--- a/lib/gitlab/gl_repository/repo_type.rb
+++ b/lib/gitlab/gl_repository/repo_type.rb
@@ -2,6 +2,18 @@
module Gitlab
class GlRepository
+ class ContainerClassMismatchError < StandardError
+ def initialize(container_class, repo_type)
+ @container_class = container_class
+ @repo_type = repo_type
+ end
+
+ def message
+ "Expected container class to be #{@repo_type.container_class} for " \
+ "repo type #{@repo_type.name}, but found #{@container_class} instead."
+ end
+ end
+
class RepoType
attr_reader :name,
:access_checker_class,
@@ -53,13 +65,14 @@ module Gitlab
end
def repository_for(container)
+ check_container(container)
return unless container
- repository_resolver.call(select_container(container))
+ repository_resolver.call(container)
end
def project_for(container)
- return select_container(container) unless project_resolver
+ return container unless project_resolver
project_resolver.call(container)
end
@@ -74,13 +87,20 @@ module Gitlab
private
- def select_container(container)
- container.is_a?(::DesignManagement::Repository) ? container.project : container
- end
-
def default_container_class
Project
end
+
+ def check_container(container)
+ # Don't check container for wiki or project because these repo types
+ # accept several container types.
+ return if wiki? || project?
+
+ return unless container.present? && container_class.present?
+ return if container.is_a?(container_class)
+
+ raise ContainerClassMismatchError.new(container.class.name, self)
+ end
end
end
end
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 27c4ec2f7be..eefa23142af 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -17,6 +17,8 @@ module Gitlab
gon.markdown_surround_selection = current_user&.markdown_surround_selection
gon.markdown_automatic_lists = current_user&.markdown_automatic_lists
+ add_browsersdk_tracking
+
if Gitlab.config.sentry.enabled
gon.sentry_dsn = Gitlab.config.sentry.clientside_dsn
gon.sentry_environment = Gitlab.config.sentry.environment
@@ -28,6 +30,7 @@ module Gitlab
current_user) && Gitlab::CurrentSettings.sentry_enabled
gon.sentry_dsn = Gitlab::CurrentSettings.sentry_clientside_dsn
gon.sentry_environment = Gitlab::CurrentSettings.sentry_environment
+ gon.sentry_clientside_traces_sample_rate = Gitlab::CurrentSettings.sentry_clientside_traces_sample_rate
end
gon.recaptcha_api_server_url = ::Recaptcha.configuration.api_server_url
@@ -52,6 +55,7 @@ module Gitlab
gon.uf_error_prefix = ::Gitlab::Utils::ErrorMessage::UF_ERROR_PREFIX
gon.pat_prefix = Gitlab::CurrentSettings.current_application_settings.personal_access_token_prefix
gon.use_new_navigation = NavHelper.show_super_sidebar?(current_user)
+ gon.keyboard_shortcuts_enabled = current_user ? current_user.keyboard_shortcuts_enabled : true
gon.diagramsnet_url = Gitlab::CurrentSettings.diagramsnet_url if Gitlab::CurrentSettings.diagramsnet_enabled
@@ -71,12 +75,11 @@ module Gitlab
push_frontend_feature_flag(:source_editor_toolbar)
push_frontend_feature_flag(:vscode_web_ide, current_user)
push_frontend_feature_flag(:unbatch_graphql_queries, current_user)
- push_frontend_feature_flag(:command_palette, current_user)
+ push_frontend_feature_flag(:server_side_frecent_namespaces, current_user)
# To be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/399248
push_frontend_feature_flag(:remove_monitor_metrics)
push_frontend_feature_flag(:gitlab_duo, current_user)
push_frontend_feature_flag(:custom_emoji)
- push_frontend_feature_flag(:super_sidebar_flyout_menus, current_user)
end
# Exposes the state of a feature flag to the frontend code.
@@ -116,6 +119,14 @@ module Gitlab
URI.join(Gitlab.config.gitlab.url,
ActionController::Base.helpers.image_path('no_avatar.png')).to_s
end
+
+ def add_browsersdk_tracking
+ return unless Gitlab.com? && Feature.enabled?(:browsersdk_tracking)
+ return if ENV['GITLAB_ANALYTICS_URL'].blank? || ENV['GITLAB_ANALYTICS_ID'].blank?
+
+ gon.analytics_url = ENV['GITLAB_ANALYTICS_URL']
+ gon.analytics_id = ENV['GITLAB_ANALYTICS_ID']
+ end
end
end
diff --git a/lib/gitlab/graphql/deprecations.rb b/lib/gitlab/graphql/deprecations.rb
index 9cd8462f2e8..221b19bf8a3 100644
--- a/lib/gitlab/graphql/deprecations.rb
+++ b/lib/gitlab/graphql/deprecations.rb
@@ -27,7 +27,6 @@ module Gitlab
end
# GitLab allows items to be marked as "alpha", which leverages GraphQL deprecations.
- # TODO remove
deprecation_args = kwargs.extract!(:alpha, :deprecated)
self.deprecation = Deprecation.parse(**deprecation_args)
diff --git a/lib/gitlab/graphql/deprecations/deprecation.rb b/lib/gitlab/graphql/deprecations/deprecation.rb
index dfcca5ee75b..0cf555b0e34 100644
--- a/lib/gitlab/graphql/deprecations/deprecation.rb
+++ b/lib/gitlab/graphql/deprecations/deprecation.rb
@@ -5,7 +5,7 @@ module Gitlab
module Deprecations
class Deprecation
REASON_RENAMED = :renamed
- REASON_ALPHA = :alpha # TODO remove support in this class
+ REASON_ALPHA = :alpha
REASONS = {
REASON_RENAMED => 'This was renamed.',
@@ -27,7 +27,7 @@ module Gitlab
return unless options
if alpha
- raise ArgumentError, '`experiment` and `deprecated` arguments cannot be passed at the same time' \
+ raise ArgumentError, '`alpha` and `deprecated` arguments cannot be passed at the same time' \
if deprecated
options[:reason] = :alpha
diff --git a/lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb b/lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb
index 4e90e4c912f..34856cfc238 100644
--- a/lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb
+++ b/lib/gitlab/graphql/query_analyzers/ast/recursion_analyzer.rb
@@ -7,7 +7,7 @@ module Gitlab
module QueryAnalyzers
module AST
class RecursionAnalyzer < GraphQL::Analysis::AST::Analyzer
- IGNORED_FIELDS = %w(node edges nodes ofType).freeze
+ IGNORED_FIELDS = %w[node edges nodes ofType].freeze
RECURSION_THRESHOLD = 2
def initialize(query)
diff --git a/lib/gitlab/hook_data/user_builder.rb b/lib/gitlab/hook_data/user_builder.rb
index 54f03b863e5..d450bf80cd1 100644
--- a/lib/gitlab/hook_data/user_builder.rb
+++ b/lib/gitlab/hook_data/user_builder.rb
@@ -49,5 +49,3 @@ module Gitlab
end
end
end
-
-Gitlab::HookData::UserBuilder.prepend_mod_with('Gitlab::HookData::UserBuilder')
diff --git a/lib/gitlab/hotlinking_detector.rb b/lib/gitlab/hotlinking_detector.rb
index e81983cd014..bfcc1735cb0 100644
--- a/lib/gitlab/hotlinking_detector.rb
+++ b/lib/gitlab/hotlinking_detector.rb
@@ -2,11 +2,11 @@
module Gitlab
class HotlinkingDetector
- IMAGE_FORMATS = %w(image/jpeg image/apng image/png image/webp image/svg+xml image/*).freeze
- MEDIA_FORMATS = %w(video/webm video/ogg video/* application/ogg audio/webm audio/ogg audio/wav audio/*).freeze
- CSS_FORMATS = %w(text/css).freeze
+ IMAGE_FORMATS = %w[image/jpeg image/apng image/png image/webp image/svg+xml image/*].freeze
+ MEDIA_FORMATS = %w[video/webm video/ogg video/* application/ogg audio/webm audio/ogg audio/wav audio/*].freeze
+ CSS_FORMATS = %w[text/css].freeze
INVALID_FORMATS = (IMAGE_FORMATS + MEDIA_FORMATS + CSS_FORMATS).freeze
- INVALID_FETCH_MODES = %w(cors no-cors websocket).freeze
+ INVALID_FETCH_MODES = %w[cors no-cors websocket].freeze
class << self
def intercept_hotlinking?(request)
diff --git a/lib/gitlab/http.rb b/lib/gitlab/http.rb
index 8b19611e5c0..feb54fcca0c 100644
--- a/lib/gitlab/http.rb
+++ b/lib/gitlab/http.rb
@@ -1,9 +1,13 @@
# frozen_string_literal: true
-# This class is used as a proxy for all outbounding http connection
-# coming from callbacks, services and hooks. The direct use of the HTTParty
-# is discouraged because it can lead to several security problems, like SSRF
-# calling internal IP or services.
+#
+# IMPORTANT: With the new development of the 'gitlab-http' gem (https://gitlab.com/gitlab-org/gitlab/-/issues/415686),
+# no additional change should be implemented in this class. This class will be removed after migrating all
+# the usages to the new gem.
+#
+
+require_relative 'http_connection_adapter'
+
module Gitlab
class HTTP
BlockedUrlError = Class.new(StandardError)
@@ -42,7 +46,7 @@ module Gitlab
alias_method :httparty_perform_request, :perform_request
end
- connection_adapter HTTPConnectionAdapter
+ connection_adapter ::Gitlab::HTTPConnectionAdapter
def self.perform_request(http_method, path, options, &block)
raise_if_blocked_by_silent_mode(http_method)
diff --git a/lib/gitlab/http_connection_adapter.rb b/lib/gitlab/http_connection_adapter.rb
index afb740a902b..822b8a9f8d9 100644
--- a/lib/gitlab/http_connection_adapter.rb
+++ b/lib/gitlab/http_connection_adapter.rb
@@ -18,6 +18,8 @@
# to read header data. It is a modified version of Net::BufferedIO that
# raises a timeout error if reading header data takes too much time.
+require_relative 'utils/override'
+
module Gitlab
class HTTPConnectionAdapter < HTTParty::ConnectionAdapter
extend ::Gitlab::Utils::Override
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index 6b154c7033f..f8e7e66a8a5 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -48,24 +48,24 @@ module Gitlab
'de' => 96,
'en' => 100,
'eo' => 0,
- 'es' => 29,
+ 'es' => 28,
'fil_PH' => 0,
'fr' => 99,
'gl_ES' => 0,
'id_ID' => 0,
'it' => 1,
'ja' => 99,
- 'ko' => 20,
+ 'ko' => 23,
'nb_NO' => 21,
'nl_NL' => 0,
'pl_PL' => 3,
'pt_BR' => 55,
- 'ro_RO' => 78,
+ 'ro_RO' => 76,
'ru' => 22,
- 'si_LK' => 9,
- 'tr_TR' => 9,
- 'uk' => 52,
- 'zh_CN' => 98,
+ 'si_LK' => 12,
+ 'tr_TR' => 8,
+ 'uk' => 51,
+ 'zh_CN' => 99,
'zh_HK' => 1,
'zh_TW' => 99
}.freeze
diff --git a/lib/gitlab/import.rb b/lib/gitlab/import.rb
new file mode 100644
index 00000000000..3f3692d4c0c
--- /dev/null
+++ b/lib/gitlab/import.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Import
+ JOB_WAITER_TTL = 1.week.to_i
+ end
+end
diff --git a/lib/gitlab/import_export/base/relation_object_saver.rb b/lib/gitlab/import_export/base/relation_object_saver.rb
index 986191bdb6b..62bd650c1d5 100644
--- a/lib/gitlab/import_export/base/relation_object_saver.rb
+++ b/lib/gitlab/import_export/base/relation_object_saver.rb
@@ -15,7 +15,6 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
BATCH_SIZE = 100
- MIN_RECORDS_SIZE = 1
attr_reader :invalid_subrelations
@@ -82,7 +81,7 @@ module Gitlab
subrelation = relation_object.public_send(definition)
association = relation_object.class.reflect_on_association(definition)
- next unless association&.collection? && subrelation.size > MIN_RECORDS_SIZE
+ next unless association&.collection?
collection_subrelations[definition] = subrelation.records
diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb
index 924ca4e83ea..dfe0815f0a0 100644
--- a/lib/gitlab/import_export/command_line_util.rb
+++ b/lib/gitlab/import_export/command_line_util.rb
@@ -37,7 +37,7 @@ module Gitlab
def gzip_with_options(dir:, filename:, options: nil)
filepath = File.join(dir, filename)
- cmd = %W(gzip #{filepath})
+ cmd = %W[gzip #{filepath}]
cmd << "-#{options}" if options
_, status = Gitlab::Popen.popen(cmd)
@@ -68,6 +68,8 @@ module Gitlab
File.open(upload_path, 'wb') do |file|
current_size = 0
+ # When migrating from Gitlab::HTTP to Gitlab:HTTP_V2, we need to pass `extra_allowed_uris` as an option
+ # instead of `allow_object_storage`.
Gitlab::HTTP.get(url, stream_body: true, allow_object_storage: true) do |fragment|
if [301, 302, 303, 307].include?(fragment.code)
Gitlab::Import::Logger.warn(message: "received redirect fragment", fragment_code: fragment.code)
@@ -87,12 +89,12 @@ module Gitlab
end
def tar_with_options(archive:, dir:, options:)
- execute_cmd(%W(tar -#{options} #{archive} -C #{dir} .))
+ execute_cmd(%W[tar -#{options} #{archive} -C #{dir} .])
end
def untar_with_options(archive:, dir:, options:)
- execute_cmd(%W(tar -#{options} #{archive} -C #{dir}))
- execute_cmd(%W(chmod -R #{UNTAR_MASK} #{dir}))
+ execute_cmd(%W[tar -#{options} #{archive} -C #{dir}])
+ execute_cmd(%W[chmod -R #{UNTAR_MASK} #{dir}])
clean_extraction_dir!(dir)
end
diff --git a/lib/gitlab/import_export/decompressed_archive_size_validator.rb b/lib/gitlab/import_export/decompressed_archive_size_validator.rb
index 3609df89958..13510cb43ca 100644
--- a/lib/gitlab/import_export/decompressed_archive_size_validator.rb
+++ b/lib/gitlab/import_export/decompressed_archive_size_validator.rb
@@ -5,13 +5,10 @@ module Gitlab
class DecompressedArchiveSizeValidator
include Gitlab::Utils::StrongMemoize
- TIMEOUT_LIMIT = 210.seconds
-
ServiceError = Class.new(StandardError)
- def initialize(archive_path:, max_bytes: self.class.max_bytes)
+ def initialize(archive_path:)
@archive_path = archive_path
- @max_bytes = max_bytes
end
def valid?
@@ -20,10 +17,6 @@ module Gitlab
end
end
- def self.max_bytes
- Gitlab::CurrentSettings.current_application_settings.max_decompressed_archive_size.megabytes
- end
-
private
def validate
@@ -32,7 +25,7 @@ module Gitlab
validate_archive_path
- Timeout.timeout(TIMEOUT_LIMIT) do
+ Timeout.timeout(timeout) do
stderr_r, stderr_w = IO.pipe
stdout, wait_threads = Open3.pipeline_r(*command, pgroup: true, err: stderr_w)
@@ -51,7 +44,7 @@ module Gitlab
if status.success?
result = stdout.readline
- if @max_bytes > 0 && result.to_i > @max_bytes
+ if max_bytes > 0 && result.to_i > max_bytes
valid_archive = false
log_error('Decompressed archive size limit reached')
@@ -70,7 +63,7 @@ module Gitlab
valid_archive
rescue Timeout::Error
- log_error('Timeout reached during archive decompression')
+ log_error("Timeout of #{timeout} seconds reached during archive decompression")
pgrps.each { |pgrp| Process.kill(-1, pgrp) } if pgrps
@@ -107,6 +100,14 @@ module Gitlab
import_upload_archive_size: archive_size
)
end
+
+ def timeout
+ Gitlab::CurrentSettings.current_application_settings.decompress_archive_file_timeout
+ end
+
+ def max_bytes
+ Gitlab::CurrentSettings.current_application_settings.max_decompressed_archive_size.megabytes
+ end
end
end
end
diff --git a/lib/gitlab/import_export/json/ndjson_writer.rb b/lib/gitlab/import_export/json/ndjson_writer.rb
index e303ac6eefa..60ae163cad5 100644
--- a/lib/gitlab/import_export/json/ndjson_writer.rb
+++ b/lib/gitlab/import_export/json/ndjson_writer.rb
@@ -44,12 +44,11 @@ module Gitlab
def with_file(*path)
file_path = File.join(@dir_path, *path)
- raise ArgumentError, "The #{file_path} already exist" if File.exist?(file_path)
# ensure that path is created
mkdir_p(File.dirname(file_path))
- File.open(file_path, "wb") do |file|
+ File.open(file_path, "ab+") do |file|
yield(file)
end
end
diff --git a/lib/gitlab/import_export/json/streaming_serializer.rb b/lib/gitlab/import_export/json/streaming_serializer.rb
index 2c64ca53f76..b0951f24628 100644
--- a/lib/gitlab/import_export/json/streaming_serializer.rb
+++ b/lib/gitlab/import_export/json/streaming_serializer.rb
@@ -75,10 +75,12 @@ module Gitlab
def serialize_many_relations(key, records, options)
log_relation_export(key, records.size)
- enumerator = Enumerator.new do |items|
- key_preloads = preloads&.dig(key)
+ key_preloads = preloads&.dig(key)
+
+ batch(records, key) do |batch|
+ next if batch.empty?
- batch(records, key) do |batch|
+ batch_enumerator = Enumerator.new do |items|
batch = batch.preload(key_preloads) if key_preloads
batch.each do |record|
@@ -91,9 +93,11 @@ module Gitlab
after_read_callback(record)
end
end
- end
- json_writer.write_relation_array(@exportable_path, key, enumerator)
+ json_writer.write_relation_array(@exportable_path, key, batch_enumerator)
+
+ Gitlab::SafeRequestStore.clear!
+ end
end
def exportable_json_record(record, options, key)
diff --git a/lib/gitlab/import_export/project/import_export.yml b/lib/gitlab/import_export/project/import_export.yml
index 850c89c1fb1..1b04e55e0c7 100644
--- a/lib/gitlab/import_export/project/import_export.yml
+++ b/lib/gitlab/import_export/project/import_export.yml
@@ -116,7 +116,6 @@ tree:
- :project_badges
- :ci_cd_settings
- :error_tracking_setting
- - :metrics_setting
- boards:
- lists:
- label:
@@ -156,10 +155,6 @@ included_attributes:
- :group_runners_enabled
- :runner_token_expiration_interval
- :default_git_depth
- metrics_setting:
- - :dashboard_timezone
- - :external_dashboard_url
- - :project_id
project_badges:
- :created_at
- :image_url
diff --git a/lib/gitlab/import_export/project/relation_factory.rb b/lib/gitlab/import_export/project/relation_factory.rb
index 7af65235492..840621a94a2 100644
--- a/lib/gitlab/import_export/project/relation_factory.rb
+++ b/lib/gitlab/import_export/project/relation_factory.rb
@@ -38,7 +38,6 @@ module Gitlab
ci_cd_settings: 'ProjectCiCdSetting',
error_tracking_setting: 'ErrorTracking::ProjectErrorTrackingSetting',
links: 'Releases::Link',
- metrics_setting: 'ProjectMetricsSetting',
commit_author: 'MergeRequest::DiffCommitUser',
committer: 'MergeRequest::DiffCommitUser',
merge_request_diff_commits: 'MergeRequestDiffCommit',
@@ -180,7 +179,7 @@ module Gitlab
# When author is not present for source release set the author as ghost user.
if @relation_hash['author_id'].blank?
- @relation_hash['author_id'] = User.select(:id).ghost.id
+ @relation_hash['author_id'] = Users::Internal.ghost.id
end
end
diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb
index d7d262501de..1861a92100e 100644
--- a/lib/gitlab/import_export/repo_restorer.rb
+++ b/lib/gitlab/import_export/repo_restorer.rb
@@ -42,7 +42,7 @@ module Gitlab
def ensure_repository_does_not_exist!
if repository.exists?
shared.logger.info(
- message: %{Deleting existing "#{repository.disk_path}" to re-import it.}
+ message: %(Deleting existing "#{repository.disk_path}" to re-import it.)
)
Repositories::DestroyService.new(repository).execute
diff --git a/lib/gitlab/import_sources.rb b/lib/gitlab/import_sources.rb
index 37bcc53019f..fec8b3a7708 100644
--- a/lib/gitlab/import_sources.rb
+++ b/lib/gitlab/import_sources.rb
@@ -20,9 +20,6 @@ module Gitlab
ImportSource.new('manifest', 'Manifest file', nil)
].freeze
- LEGACY_IMPORT_TABLE = IMPORT_TABLE.deep_dup
- LEGACY_IMPORT_TABLE[2].importer = Gitlab::BitbucketServerImport::Importer
-
class << self
prepend_mod_with('Gitlab::ImportSources') # rubocop: disable Cop/InjectEnterpriseEditionModule
@@ -47,9 +44,15 @@ module Gitlab
end
def import_table
- return IMPORT_TABLE if Feature.enabled?(:bitbucket_server_parallel_importer)
+ bitbucket_parallel_enabled = Feature.enabled?(:bitbucket_parallel_importer)
+
+ return IMPORT_TABLE unless bitbucket_parallel_enabled
+
+ import_table = IMPORT_TABLE.deep_dup
+
+ import_table[1].importer = Gitlab::BitbucketImport::ParallelImporter if bitbucket_parallel_enabled
- LEGACY_IMPORT_TABLE
+ import_table
end
end
end
diff --git a/lib/gitlab/instrumentation/redis_base.rb b/lib/gitlab/instrumentation/redis_base.rb
index 70aaa59f912..e39bbb36680 100644
--- a/lib/gitlab/instrumentation/redis_base.rb
+++ b/lib/gitlab/instrumentation/redis_base.rb
@@ -110,6 +110,16 @@ module Gitlab
@request_counter.increment({ storage: storage_key }, amount)
end
+ def instance_count_pipelined_request(size)
+ @pipeline_size_histogram ||= Gitlab::Metrics.histogram(
+ :gitlab_redis_client_requests_pipelined_commands,
+ 'Client side Redis request pipeline size, per Redis server',
+ {},
+ [10, 100, 1000, 10_000]
+ )
+ @pipeline_size_histogram.observe({ storage: storage_key }, size)
+ end
+
def instance_count_exception(ex)
# This metric is meant to give a client side view of how the Redis
# server is doing. Redis itself does not expose error counts. This
diff --git a/lib/gitlab/instrumentation/redis_interceptor.rb b/lib/gitlab/instrumentation/redis_interceptor.rb
index b3fbe30e583..20ba1ab82a7 100644
--- a/lib/gitlab/instrumentation/redis_interceptor.rb
+++ b/lib/gitlab/instrumentation/redis_interceptor.rb
@@ -12,7 +12,7 @@ module Gitlab
end
def call_pipeline(pipeline)
- instrument_call(pipeline.commands) do
+ instrument_call(pipeline.commands, true) do
super
end
end
@@ -30,9 +30,10 @@ module Gitlab
private
- def instrument_call(commands)
+ def instrument_call(commands, pipelined = false)
start = Gitlab::Metrics::System.monotonic_time # must come first so that 'start' is always defined
instrumentation_class.instance_count_request(commands.size)
+ instrumentation_class.instance_count_pipelined_request(commands.size) if pipelined
if !instrumentation_class.redis_cluster_validate!(commands) && ::RequestStore.active?
instrumentation_class.increment_cross_slot_request_count
diff --git a/lib/gitlab/jira_import/metadata_collector.rb b/lib/gitlab/jira_import/metadata_collector.rb
index 090b95ac14a..de5d636cc5b 100644
--- a/lib/gitlab/jira_import/metadata_collector.rb
+++ b/lib/gitlab/jira_import/metadata_collector.rb
@@ -11,8 +11,8 @@ module Gitlab
end
def execute
- add_field(%w(issuetype name), 'Issue type')
- add_field(%w(priority name), 'Priority')
+ add_field(%w[issuetype name], 'Issue type')
+ add_field(%w[priority name], 'Priority')
add_field('environment', 'Environment')
add_field('duedate', 'Due date')
add_parent
diff --git a/lib/gitlab/job_waiter.rb b/lib/gitlab/job_waiter.rb
index 880b112d815..e53bfb40654 100644
--- a/lib/gitlab/job_waiter.rb
+++ b/lib/gitlab/job_waiter.rb
@@ -22,14 +22,16 @@ module Gitlab
STARTED_METRIC = :gitlab_job_waiter_started_total
TIMEOUTS_METRIC = :gitlab_job_waiter_timeouts_total
- def self.notify(key, jid)
+ # This TTL needs to be long enough to allow whichever Sidekiq job calls
+ # JobWaiter#wait to reach BLPOP.
+ DEFAULT_TTL = 6.hours.to_i
+
+ def self.notify(key, jid, ttl: DEFAULT_TTL)
Gitlab::Redis::SharedState.with do |redis|
# Use a Redis MULTI transaction to ensure we always set an expiry
redis.multi do |multi|
multi.lpush(key, jid)
- # This TTL needs to be long enough to allow whichever Sidekiq job calls
- # JobWaiter#wait to reach BLPOP.
- multi.expire(key, 6.hours.to_i)
+ multi.expire(key, ttl)
end
end
end
@@ -42,6 +44,10 @@ module Gitlab
"#{KEY_PREFIX}:#{SecureRandom.uuid}"
end
+ def self.delete_key(key)
+ Gitlab::Redis::SharedState.with { |redis| redis.del(key) } if key?(key)
+ end
+
attr_reader :key, :finished, :worker_label
attr_accessor :jobs_remaining
diff --git a/lib/gitlab/kas.rb b/lib/gitlab/kas.rb
index 255d8802c1c..de391c45121 100644
--- a/lib/gitlab/kas.rb
+++ b/lib/gitlab/kas.rb
@@ -51,7 +51,7 @@ module Gitlab
# Legacy code path. Will be removed when all distributions provide a sane default here
uri = URI.join(external_url, K8S_PROXY_PATH)
- uri.scheme = uri.scheme.in?(%w(grpcs wss)) ? 'https' : 'http'
+ uri.scheme = uri.scheme.in?(%w[grpcs wss]) ? 'https' : 'http'
uri.to_s
end
diff --git a/lib/gitlab/kroki.rb b/lib/gitlab/kroki.rb
index 5fa77c1f1ba..84dc081d9d7 100644
--- a/lib/gitlab/kroki.rb
+++ b/lib/gitlab/kroki.rb
@@ -14,8 +14,8 @@ module Gitlab
packetdiag
rackdiag
].freeze
- DIAGRAMS_FORMATS = (::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES - %w(mermaid)).freeze
- DIAGRAMS_FORMATS_WO_PLANTUML = (DIAGRAMS_FORMATS - %w(plantuml)).freeze
+ DIAGRAMS_FORMATS = (::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES - %w[mermaid]).freeze
+ DIAGRAMS_FORMATS_WO_PLANTUML = (DIAGRAMS_FORMATS - %w[plantuml]).freeze
# Get the list of diagram formats that are currently enabled
#
diff --git a/lib/gitlab/kubernetes/kubectl_cmd.rb b/lib/gitlab/kubernetes/kubectl_cmd.rb
index f3ac19e210a..28a010ec191 100644
--- a/lib/gitlab/kubernetes/kubectl_cmd.rb
+++ b/lib/gitlab/kubernetes/kubectl_cmd.rb
@@ -5,23 +5,23 @@ module Gitlab
module KubectlCmd
class << self
def delete(*args)
- %w(kubectl delete).concat(args).shelljoin
+ %w[kubectl delete].concat(args).shelljoin
end
def apply_file(filename, *args)
raise ArgumentError, "filename is not present" unless filename.present?
- %w(kubectl apply -f).concat([filename], args).shelljoin
+ %w[kubectl apply -f].concat([filename], args).shelljoin
end
def delete_crds_from_group(group)
- api_resources_args = %w(-o name --api-group).push(group)
+ api_resources_args = %w[-o name --api-group].push(group)
PodCmd.retry_command(api_resources(*api_resources_args) + " | xargs -r " + delete('--ignore-not-found', 'crd'))
end
def api_resources(*args)
- %w(kubectl api-resources).concat(args).shelljoin
+ %w[kubectl api-resources].concat(args).shelljoin
end
end
end
diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb
index 53ad0d9cb4d..cc172bb9b85 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -27,7 +27,7 @@ module Gitlab
return [] unless File.readable?(path)
- tail_output, _ = Gitlab::Popen.popen(%W(tail -n 2000 #{path}))
+ tail_output, _ = Gitlab::Popen.popen(%W[tail -n 2000 #{path}])
tail_output.split("\n")
end
diff --git a/lib/gitlab/lograge/custom_options.rb b/lib/gitlab/lograge/custom_options.rb
index f8ec58cf217..6f180f89db0 100644
--- a/lib/gitlab/lograge/custom_options.rb
+++ b/lib/gitlab/lograge/custom_options.rb
@@ -6,7 +6,7 @@ module Gitlab
include ::Gitlab::Logging::CloudflareHelper
LIMITED_ARRAY_SENTINEL = { key: 'truncated', value: '...' }.freeze
- IGNORE_PARAMS = Set.new(%w(controller action format)).freeze
+ IGNORE_PARAMS = Set.new(%w[controller action format]).freeze
KNOWN_PAYLOAD_PARAMS = [:remote_ip, :user_id, :username, :ua, :queue_duration_s, :response_bytes,
:etag_route, :request_urgency, :target_duration_s] + CLOUDFLARE_CUSTOM_HEADERS.values
diff --git a/lib/gitlab/manifest_import/metadata.rb b/lib/gitlab/manifest_import/metadata.rb
index 81711be729e..b2871b96ad6 100644
--- a/lib/gitlab/manifest_import/metadata.rb
+++ b/lib/gitlab/manifest_import/metadata.rb
@@ -40,13 +40,9 @@ module Gitlab
"#{KEY_PREFIX}:{#{user.id}}:#{field}"
end
- def key_for(field)
- "#{KEY_PREFIX}:#{user.id}:#{field}"
- end
-
def redis_get(field)
Gitlab::Redis::SharedState.with do |redis|
- redis.get(hashtag_key_for(field)) || redis.get(key_for(field))
+ redis.get(hashtag_key_for(field))
end
end
end
diff --git a/lib/gitlab/metrics/background_transaction.rb b/lib/gitlab/metrics/background_transaction.rb
index 54095461dd4..7ffec7b0141 100644
--- a/lib/gitlab/metrics/background_transaction.rb
+++ b/lib/gitlab/metrics/background_transaction.rb
@@ -8,7 +8,7 @@ module Gitlab
# metadata such as endpoint_id, queue, and feature category.
class BackgroundTransaction < Transaction
THREAD_KEY = :_gitlab_metrics_background_transaction
- BASE_LABEL_KEYS = %i(queue endpoint_id feature_category).freeze
+ BASE_LABEL_KEYS = %i[queue endpoint_id feature_category].freeze
class << self
def current
diff --git a/lib/gitlab/metrics/dashboard/cache.rb b/lib/gitlab/metrics/dashboard/cache.rb
deleted file mode 100644
index 54b5250d209..00000000000
--- a/lib/gitlab/metrics/dashboard/cache.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-require 'set'
-
-module Gitlab
- module Metrics
- module Dashboard
- class Cache
- CACHE_KEYS = 'all_cached_metric_dashboards'
-
- class << self
- # This class method (Gitlab::Metrics::Dashboard::Cache.fetch) can be used
- # when the key does not need to be deleted by `delete_all!`.
- # For example, out of the box dashboard caches do not need to be deleted.
- delegate :fetch, to: :"Rails.cache"
-
- alias_method :for, :new
- end
-
- def initialize(project)
- @project = project
- end
-
- # Stores a dashboard in the cache, documenting the key
- # so the cache can be cleared in bulk at another time.
- def fetch(key)
- register_key(key)
-
- Rails.cache.fetch(key) { yield }
- end
-
- # Resets all dashboard caches, such that all
- # dashboard content will be loaded from source on
- # subsequent dashboard calls.
- def delete_all!
- all_keys.each { |key| Rails.cache.delete(key) }
-
- Rails.cache.delete(catalog_key)
- end
-
- private
-
- def register_key(key)
- new_keys = all_keys.add(key).to_a.join('|')
-
- Rails.cache.write(catalog_key, new_keys)
- end
-
- def all_keys
- keys = Rails.cache.read(catalog_key)&.split('|')
- Set.new(keys)
- end
-
- # One key to store them all...
- # This key is used to store the names of all the keys that contain this
- # project's dashboards.
- def catalog_key
- "#{CACHE_KEYS}_#{@project.id}"
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/metrics/dashboard/errors.rb b/lib/gitlab/metrics/dashboard/errors.rb
deleted file mode 100644
index 1a951172f74..00000000000
--- a/lib/gitlab/metrics/dashboard/errors.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-# Central point for managing errors from within the metrics
-# dashboard module. Handles errors from dashboard retrieval
-# and processing steps, as well as defines shared error classes.
-module Gitlab
- module Metrics
- module Dashboard
- module Errors
- DashboardProcessingError = Class.new(StandardError)
- PanelNotFoundError = Class.new(StandardError)
- MissingIntegrationError = Class.new(StandardError)
- LayoutError = Class.new(DashboardProcessingError)
- MissingQueryError = Class.new(DashboardProcessingError)
-
- NOT_FOUND_ERROR = Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError
-
- def handle_errors(error)
- case error
- when DashboardProcessingError
- error(error.message, :unprocessable_entity)
- when NOT_FOUND_ERROR
- error(_("%{dashboard_path} could not be found.") % { dashboard_path: dashboard_path }, :not_found)
- when PanelNotFoundError
- error(error.message, :not_found)
- when ::Grafana::Client::Error
- error(error.message, :service_unavailable)
- when MissingIntegrationError
- error(_('Proxy support for this API is not available currently'), :bad_request)
- else
- raise error
- end
- end
-
- def panels_not_found!(opts)
- raise PanelNotFoundError, _("No panels matching properties %{opts}") % { opts: opts }
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/metrics/dashboard/processor.rb b/lib/gitlab/metrics/dashboard/processor.rb
deleted file mode 100644
index 9566e5afb9a..00000000000
--- a/lib/gitlab/metrics/dashboard/processor.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Metrics
- module Dashboard
- # Responsible for processesing a dashboard hash, inserting
- # relevant DB records & sorting for proper rendering in
- # the UI. These includes shared metric info, custom metrics
- # info, and alerts (only in EE).
- class Processor
- def initialize(project, dashboard, sequence, params)
- @project = project
- @dashboard = dashboard
- @sequence = sequence
- @params = params
- end
-
- # Returns a new dashboard hash with the results of
- # running transforms on the dashboard.
- # @return [Hash, nil]
- def process
- return unless @dashboard
-
- @dashboard.deep_symbolize_keys.tap do |dashboard|
- @sequence.each do |stage|
- stage.new(@project, dashboard, @params).transform!
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/metrics/dashboard/repo_dashboard_finder.rb b/lib/gitlab/metrics/dashboard/repo_dashboard_finder.rb
deleted file mode 100644
index 8b791e110ba..00000000000
--- a/lib/gitlab/metrics/dashboard/repo_dashboard_finder.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-# Provides methods to list and read dashboard yaml files from a project's repository.
-module Gitlab
- module Metrics
- module Dashboard
- class RepoDashboardFinder
- DASHBOARD_ROOT = ".gitlab/dashboards"
- DASHBOARD_EXTENSION = '.yml'
-
- class << self
- # Returns list of all user-defined dashboard paths. Used to populate
- # Repository model cache (Repository#user_defined_metrics_dashboard_paths).
- # Also deletes all dashboard cache entries.
- # @return [Array] ex) ['.gitlab/dashboards/dashboard1.yml']
- def list_dashboards(project)
- Gitlab::Metrics::Dashboard::Cache.for(project).delete_all!
-
- file_finder(project).list_files_for(DASHBOARD_ROOT)
- end
-
- # Reads the given dashboard from repository, and returns the content as a string.
- # @return [String]
- def read_dashboard(project, dashboard_path)
- file_finder(project).read(dashboard_path)
- end
-
- private
-
- def file_finder(project)
- Gitlab::Template::Finders::RepoTemplateFinder.new(project, DASHBOARD_ROOT, DASHBOARD_EXTENSION)
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/metrics/dashboard/stages/base_stage.rb b/lib/gitlab/metrics/dashboard/stages/base_stage.rb
deleted file mode 100644
index b869a633030..00000000000
--- a/lib/gitlab/metrics/dashboard/stages/base_stage.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Metrics
- module Dashboard
- module Stages
- class BaseStage
- attr_reader :project, :dashboard, :params
-
- def initialize(project, dashboard, params)
- @project = project
- @dashboard = dashboard
- @params = params
- end
-
- # Entry-point to the stage
- def transform!
- raise NotImplementedError
- end
-
- protected
-
- def missing_panel_groups!
- raise Errors::LayoutError, 'Top-level key :panel_groups must be an array'
- end
-
- def missing_panels!
- raise Errors::LayoutError, 'Each "panel_group" must define an array :panels'
- end
-
- def missing_metrics!
- raise Errors::LayoutError, 'Each "panel" must define an array :metrics'
- end
-
- def for_metrics
- missing_panel_groups! unless dashboard[:panel_groups].is_a?(Array)
-
- for_panel_groups do |panel_group|
- for_panels_in(panel_group) do |panel|
- missing_metrics! unless panel[:metrics].is_a?(Array)
-
- panel[:metrics].each do |metric|
- yield metric
- end
- end
- end
- end
-
- def for_variables
- return unless dashboard.dig(:templating, :variables).is_a?(Hash)
-
- dashboard.dig(:templating, :variables).each do |variable_name, variable|
- yield variable_name, variable
- end
- end
-
- def for_panel_groups
- dashboard[:panel_groups].each do |panel_group|
- yield panel_group
- end
- end
-
- def for_panels_in(panel_group)
- missing_panels! unless panel_group[:panels].is_a?(Array)
-
- panel_group[:panels].each do |panel|
- yield panel
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/metrics/dashboard/stages/url_validator.rb b/lib/gitlab/metrics/dashboard/stages/url_validator.rb
deleted file mode 100644
index ad9d78133af..00000000000
--- a/lib/gitlab/metrics/dashboard/stages/url_validator.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Metrics
- module Dashboard
- module Stages
- class UrlValidator < BaseStage
- def transform!
- validate_dashboard_links(dashboard)
-
- validate_chart_links(dashboard)
- end
-
- private
-
- def blocker_args
- {
- schemes: %w(http https),
- ports: [],
- allow_localhost: allow_setting_local_requests?,
- allow_local_network: allow_setting_local_requests?,
- ascii_only: false,
- enforce_user: false,
- enforce_sanitization: false,
- dns_rebind_protection: true
- }
- end
-
- def allow_setting_local_requests?
- Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
- end
-
- def validate_dashboard_links(dashboard)
- validate_links(dashboard[:links])
- end
-
- def validate_chart_links(dashboard)
- dashboard[:panel_groups].each do |panel_group|
- panel_group[:panels].each do |panel|
- validate_links(panel[:links])
- end
- end
- end
-
- def validate_links(links)
- links&.each do |link|
- next unless link.is_a? Hash
-
- Gitlab::UrlBlocker.validate!(link[:url], **blocker_args)
- rescue Gitlab::UrlBlocker::BlockedUrlError
- link[:url] = ''
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/metrics/dashboard/transformers/errors.rb b/lib/gitlab/metrics/dashboard/transformers/errors.rb
deleted file mode 100644
index bc85dc4e131..00000000000
--- a/lib/gitlab/metrics/dashboard/transformers/errors.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Metrics
- module Dashboard
- module Transformers
- module Errors
- BaseError = Class.new(StandardError)
-
- class MissingAttribute < BaseError
- def initialize(attribute_name)
- super("Missing attribute: '#{attribute_name}'")
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/metrics/dashboard/url.rb b/lib/gitlab/metrics/dashboard/url.rb
deleted file mode 100644
index e7b901861ef..00000000000
--- a/lib/gitlab/metrics/dashboard/url.rb
+++ /dev/null
@@ -1,133 +0,0 @@
-# frozen_string_literal: true
-
-# Manages url matching for metrics dashboards.
-module Gitlab
- module Metrics
- module Dashboard
- class Url
- class << self
- include Gitlab::Utils::StrongMemoize
-
- QUERY_PATTERN = '(?<query>\?[a-zA-Z0-9%.()+_=-]+(&[a-zA-Z0-9%.()+_=-]+)*)?'
- ANCHOR_PATTERN = '(?<anchor>\#[a-z0-9_-]+)?'
- DASH_PATTERN = '(?:/-)'
-
- # Matches dashboard urls for a Grafana embed.
- #
- # EX - https://<host>/<namespace>/<project>/grafana/metrics_dashboard
- def grafana_regex
- strong_memoize(:grafana_regex) do
- regex_for_project_metrics(
- %r{
- #{DASH_PATTERN}?
- /grafana
- /metrics_dashboard
- }xo
- )
- end
- end
-
- # Matches dashboard urls for a metric chart embed
- # for cluster metrics.
- # This regex needs to match the dashboard URL as well, not just the trigger URL.
- # The inline_metrics_redactor_filter.rb uses this regex to match against
- # the dashboard URL.
- #
- # EX - https://<host>/<namespace>/<project>/-/clusters/<cluster_id>/?group=Cluster%20Health&title=Memory%20Usage&y_label=Memory%20(GiB)
- # dashboard URL - https://<host>/<namespace>/<project>/-/clusters/<cluster_id>/metrics_dashboard?group=Cluster%20Health&title=Memory%20Usage&y_label=Memory%20(GiB)
- def clusters_regex
- strong_memoize(:clusters_regex) do
- regex_for_project_metrics(
- %r{
- #{DASH_PATTERN}?
- /clusters
- /(?<cluster_id>\d+)
- /?
- ( (/metrics) | ( /metrics_dashboard\.json ) )?
- }xo
- )
- end
- end
-
- # Matches dashboard urls for a metric chart embed
- # for a specifc firing GitLab alert
- #
- # EX - https://<host>/<namespace>/<project>/prometheus/alerts/<alert_id>/metrics_dashboard
- def alert_regex
- strong_memoize(:alert_regex) do
- regex_for_project_metrics(
- %r{
- #{DASH_PATTERN}?
- /prometheus
- /alerts
- /(?<alert>\d+)
- /metrics_dashboard(\.json)?
- }xo
- )
- end
- end
-
- # Parses query params out from full url string into hash.
- #
- # Ex) 'https://<root>/<project>/<environment>/metrics?title=Title&group=Group'
- # --> { title: 'Title', group: 'Group' }
- def parse_query(url)
- query_string = URI.parse(url).query.to_s
-
- CGI.parse(query_string)
- .transform_values { |value| value.first }
- .symbolize_keys
- end
-
- private
-
- def environment_metrics_regex
- %r{
- #{DASH_PATTERN}?
- /environments
- /(?<environment>\d+)
- /(metrics_dashboard|metrics)
- }xo
- end
-
- def non_environment_metrics_regex
- %r{
- #{DASH_PATTERN}
- /metrics
- (?= # Lookahead to ensure there is an environment query param
- \?
- .*
- environment=(?<environment>\d+)
- .*
- )
- }xo
- end
-
- def regex_for_project_metrics(path_suffix_pattern)
- %r{
- ^(?<url>
- #{gitlab_host_pattern}
- #{project_path_pattern}
- #{path_suffix_pattern}
- #{QUERY_PATTERN}
- #{ANCHOR_PATTERN}
- )$
- }x
- end
-
- def gitlab_host_pattern
- Regexp.escape(gitlab_domain)
- end
-
- def project_path_pattern
- "\/#{Project.reference_pattern}"
- end
-
- def gitlab_domain
- Gitlab.config.gitlab.url
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/metrics/requests_rack_middleware.rb b/lib/gitlab/metrics/requests_rack_middleware.rb
index b4baeba72e8..c299fa37e7a 100644
--- a/lib/gitlab/metrics/requests_rack_middleware.rb
+++ b/lib/gitlab/metrics/requests_rack_middleware.rb
@@ -4,13 +4,13 @@ module Gitlab
module Metrics
class RequestsRackMiddleware
HTTP_METHODS = {
- "delete" => %w(200 202 204 303 400 401 403 404 500 503),
- "get" => %w(200 204 301 302 303 304 307 400 401 403 404 410 422 429 500 503),
- "head" => %w(200 204 301 302 303 401 403 404 410 500),
- "options" => %w(200 404),
- "patch" => %w(200 202 204 400 403 404 409 416 500),
- "post" => %w(200 201 202 204 301 302 303 304 400 401 403 404 406 409 410 412 422 429 500 503),
- "put" => %w(200 202 204 400 401 403 404 405 406 409 410 422 500)
+ "delete" => %w[200 202 204 303 400 401 403 404 500 503],
+ "get" => %w[200 204 301 302 303 304 307 400 401 403 404 410 422 429 500 503],
+ "head" => %w[200 204 301 302 303 401 403 404 410 500],
+ "options" => %w[200 404],
+ "patch" => %w[200 202 204 400 403 404 409 416 500],
+ "post" => %w[200 201 202 204 301 302 303 304 400 401 403 404 406 409 410 412 422 429 500 503],
+ "put" => %w[200 202 204 400 401 403 404 405 406 409 410 422 500]
}.freeze
HEALTH_ENDPOINT = %r{^/-/(liveness|readiness|health|metrics)/?$}.freeze
diff --git a/lib/gitlab/metrics/samplers/database_sampler.rb b/lib/gitlab/metrics/samplers/database_sampler.rb
index 86372973c82..8d4f4570c21 100644
--- a/lib/gitlab/metrics/samplers/database_sampler.rb
+++ b/lib/gitlab/metrics/samplers/database_sampler.rb
@@ -54,7 +54,7 @@ module Gitlab
next if load_balancer.primary_only?
load_balancer.host_list.hosts.each do |host|
- stats << { labels: labels_for_replica_host(load_balancer, host), stats: host.connection.pool.stat }
+ stats << { labels: labels_for_replica_host(load_balancer, host), stats: host.pool.stat }
end
end
end
@@ -73,7 +73,7 @@ module Gitlab
host: host.host,
port: host.port,
class: load_balancer.configuration.connection_specification_name,
- db_config_name: Gitlab::Database.db_config_name(host.connection)
+ db_config_name: host.pool.db_config.name
}
end
end
diff --git a/lib/gitlab/metrics/subscribers/action_view.rb b/lib/gitlab/metrics/subscribers/action_view.rb
index bc9032a6942..ce2cc88e035 100644
--- a/lib/gitlab/metrics/subscribers/action_view.rb
+++ b/lib/gitlab/metrics/subscribers/action_view.rb
@@ -21,7 +21,7 @@ module Gitlab
tags = tags_for(event)
current_transaction.observe(:gitlab_view_rendering_duration_seconds, event.duration, tags) do
docstring 'View rendering time'
- label_keys %i(view)
+ label_keys %i[view]
buckets [0.001, 0.01, 0.1, 1, 10.0]
with_feature :prometheus_metrics_view_instrumentation
end
diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb
index 10bb358a292..f9749b65888 100644
--- a/lib/gitlab/metrics/subscribers/active_record.rb
+++ b/lib/gitlab/metrics/subscribers/active_record.rb
@@ -9,15 +9,15 @@ module Gitlab
attach_to :active_record
- DB_COUNTERS = %i{count write_count cached_count}.freeze
+ DB_COUNTERS = %i[count write_count cached_count].freeze
SQL_COMMANDS_WITH_COMMENTS_REGEX = %r{\A(/\*.*\*/\s)?((?!(.*[^\w'"](DELETE|UPDATE|INSERT INTO)[^\w'"])))(WITH.*)?(SELECT)((?!(FOR UPDATE|FOR SHARE)).)*$}i.freeze
SQL_DURATION_BUCKET = [0.05, 0.1, 0.25].freeze
TRANSACTION_DURATION_BUCKET = [0.1, 0.25, 1].freeze
- DB_LOAD_BALANCING_ROLES = %i{replica primary}.freeze
- DB_LOAD_BALANCING_COUNTERS = %i{count cached_count wal_count wal_cached_count}.freeze
- DB_LOAD_BALANCING_DURATIONS = %i{duration_s}.freeze
+ DB_LOAD_BALANCING_ROLES = %i[replica primary].freeze
+ DB_LOAD_BALANCING_COUNTERS = %i[count cached_count wal_count wal_cached_count].freeze
+ DB_LOAD_BALANCING_DURATIONS = %i[duration_s].freeze
SQL_WAL_LOCATION_REGEX = /(pg_current_wal_insert_lsn\(\)::text|pg_last_wal_replay_lsn\(\)::text)/.freeze
diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb
index 56a310548a7..a57a859acfe 100644
--- a/lib/gitlab/metrics/transaction.rb
+++ b/lib/gitlab/metrics/transaction.rb
@@ -7,7 +7,7 @@ module Gitlab
include Gitlab::Metrics::Methods
# labels that potentially contain sensitive information and will be filtered
- FILTERED_LABEL_KEYS = %i(branch path).freeze
+ FILTERED_LABEL_KEYS = %i[branch path].freeze
# The series to store events (e.g. Git pushes) in.
EVENT_SERIES = 'events'
diff --git a/lib/gitlab/metrics/web_transaction.rb b/lib/gitlab/metrics/web_transaction.rb
index fcfa86734e8..f3c1e6897af 100644
--- a/lib/gitlab/metrics/web_transaction.rb
+++ b/lib/gitlab/metrics/web_transaction.rb
@@ -9,7 +9,7 @@ module Gitlab
# etc.
class WebTransaction < Transaction
THREAD_KEY = :_gitlab_metrics_transaction
- BASE_LABEL_KEYS = %i(controller action feature_category).freeze
+ BASE_LABEL_KEYS = %i[controller action feature_category].freeze
CONTROLLER_KEY = 'action_controller.instance'
ENDPOINT_KEY = 'api.endpoint'
diff --git a/lib/gitlab/middleware/read_only/controller.rb b/lib/gitlab/middleware/read_only/controller.rb
index 69e2ae55cb0..09a813fa4c3 100644
--- a/lib/gitlab/middleware/read_only/controller.rb
+++ b/lib/gitlab/middleware/read_only/controller.rb
@@ -4,26 +4,26 @@ module Gitlab
module Middleware
class ReadOnly
class Controller
- DISALLOWED_METHODS = %w(POST PATCH PUT DELETE).freeze
+ DISALLOWED_METHODS = %w[POST PATCH PUT DELETE].freeze
APPLICATION_JSON = 'application/json'
- APPLICATION_JSON_TYPES = %W{#{APPLICATION_JSON} application/vnd.git-lfs+json}.freeze
+ APPLICATION_JSON_TYPES = %W[#{APPLICATION_JSON} application/vnd.git-lfs+json].freeze
ERROR_MESSAGE = 'You cannot perform write operations on a read-only instance'
ALLOWLISTED_GIT_READ_ONLY_ROUTES = {
- 'repositories/git_http' => %w{git_upload_pack}
+ 'repositories/git_http' => %w[git_upload_pack]
}.freeze
ALLOWLISTED_GIT_LFS_BATCH_ROUTES = {
- 'repositories/lfs_api' => %w{batch}
+ 'repositories/lfs_api' => %w[batch]
}.freeze
ALLOWLISTED_GIT_REVISION_ROUTES = {
- 'projects/compare' => %w{create}
+ 'projects/compare' => %w[create]
}.freeze
ALLOWLISTED_SESSION_ROUTES = {
- 'sessions' => %w{destroy},
- 'admin/sessions' => %w{create destroy}
+ 'sessions' => %w[destroy],
+ 'admin/sessions' => %w[create destroy]
}.freeze
GRAPHQL_URL = '/api/graphql'
diff --git a/lib/gitlab/observability.rb b/lib/gitlab/observability.rb
index b500df86363..a4e18cc170b 100644
--- a/lib/gitlab/observability.rb
+++ b/lib/gitlab/observability.rb
@@ -27,13 +27,8 @@ module Gitlab
"#{Gitlab::Observability.observability_url}/v1/auth/start"
end
- def tracing_url(project)
- "#{Gitlab::Observability.observability_url}/query/#{project.group.id}/#{project.id}/v1/traces"
- end
-
- def provisioning_url(_project)
- # TODO Change to correct endpoint when API is ready
- Gitlab::Observability.observability_url.to_s
+ def provisioning_url(project)
+ "#{Gitlab::Observability.observability_url}/v3/tenant/#{project.id}"
end
# Returns true if the GitLab Observability UI (GOUI) feature flag is enabled
@@ -46,11 +41,6 @@ module Gitlab
Feature.enabled?(:observability_group_tab)
end
- # Returns true if Tracing UI is enabled
- def tracing_enabled?(project)
- Feature.enabled?(:observability_tracing, project)
- end
-
# Returns the embeddable Observability URL of a given URL
#
# - Validates the URL
@@ -163,3 +153,5 @@ module Gitlab
end
end
end
+
+Gitlab::Observability.prepend_mod_with('Gitlab::Observability')
diff --git a/lib/gitlab/pages.rb b/lib/gitlab/pages.rb
index 4e0e5102bec..defe054d631 100644
--- a/lib/gitlab/pages.rb
+++ b/lib/gitlab/pages.rb
@@ -5,6 +5,7 @@ module Gitlab
VERSION = File.read(Rails.root.join("GITLAB_PAGES_VERSION")).strip.freeze
INTERNAL_API_REQUEST_HEADER = 'Gitlab-Pages-Api-Request'
MAX_SIZE = 1.terabyte
+ DEPLOYMENT_EXPIRATION = 24.hours
include JwtAuthenticatable
@@ -23,6 +24,29 @@ module Gitlab
::Gitlab.config.pages.access_control &&
::Gitlab::CurrentSettings.current_application_settings.force_pages_access_control
end
+
+ def enabled?
+ Gitlab.config.pages.enabled
+ end
+
+ def add_unique_domain_to(project)
+ return unless enabled?
+ # If the project used a unique domain once, it'll always use the same
+ return if project.project_setting.pages_unique_domain_in_database.present?
+
+ project.project_setting.pages_unique_domain_enabled = true
+ project.project_setting.pages_unique_domain = Gitlab::Pages::RandomDomain.generate(
+ project_path: project.path,
+ namespace_path: project.parent.full_path)
+ end
+
+ def multiple_versions_enabled_for?(project)
+ return false if project.blank?
+
+ ::Feature.enabled?(:pages_multiple_versions_setting, project) &&
+ project.licensed_feature_available?(:pages_multiple_versions) &&
+ project.project_setting.pages_multiple_versions_enabled
+ end
end
end
end
diff --git a/lib/gitlab/pages/virtual_host_finder.rb b/lib/gitlab/pages/virtual_host_finder.rb
index 88ee0e44c00..e9ac86f0d47 100644
--- a/lib/gitlab/pages/virtual_host_finder.rb
+++ b/lib/gitlab/pages/virtual_host_finder.rb
@@ -38,15 +38,9 @@ module Gitlab
return if namespace.blank?
- cache = if Feature.enabled?(:cache_pages_domain_api, namespace)
- ::Gitlab::Pages::CacheControl.for_namespace(namespace.id)
- end
-
::Pages::VirtualDomain.new(
trim_prefix: namespace.full_path,
- projects: namespace.all_projects_with_pages,
- cache: cache
- )
+ projects: namespace.all_projects_with_pages)
end
def by_custom_domain(host)
@@ -54,15 +48,7 @@ module Gitlab
return unless domain&.pages_deployed?
- cache = if Feature.enabled?(:cache_pages_domain_api, domain.project.root_namespace)
- ::Gitlab::Pages::CacheControl.for_domain(domain.id)
- end
-
- ::Pages::VirtualDomain.new(
- projects: [domain.project],
- domain: domain,
- cache: cache
- )
+ ::Pages::VirtualDomain.new(projects: [domain.project], domain: domain)
end
end
end
diff --git a/lib/gitlab/pagination/cursor_based_keyset.rb b/lib/gitlab/pagination/cursor_based_keyset.rb
index ee8259cc671..592f635c14e 100644
--- a/lib/gitlab/pagination/cursor_based_keyset.rb
+++ b/lib/gitlab/pagination/cursor_based_keyset.rb
@@ -10,6 +10,20 @@ module Gitlab
::Packages::BuildInfo => { id: :desc }
}.freeze
+ SUPPORTED_MULTI_ORDERING = {
+ Group => { name: [:asc] },
+ AuditEvent => { id: [:desc] },
+ User => {
+ id: [:asc, :desc],
+ name: [:asc, :desc],
+ username: [:asc, :desc],
+ created_at: [:asc, :desc],
+ updated_at: [:asc, :desc]
+ },
+ ::Ci::Build => { id: [:desc] },
+ ::Packages::BuildInfo => { id: [:desc] }
+ }.freeze
+
# Relation types that are enforced in this list
# enforce the use of keyset pagination, thus erroring out requests
# made with offset pagination above a certain limit.
@@ -19,7 +33,11 @@ module Gitlab
ENFORCED_TYPES = [Group].freeze
def self.available_for_type?(relation)
- SUPPORTED_ORDERING.key?(relation.klass)
+ if Feature.enabled?(:api_keyset_pagination_multi_order)
+ SUPPORTED_MULTI_ORDERING.key?(relation.klass)
+ else
+ SUPPORTED_ORDERING.key?(relation.klass)
+ end
end
def self.available?(cursor_based_request_context, relation)
@@ -32,9 +50,16 @@ module Gitlab
end
def self.order_satisfied?(relation, cursor_based_request_context)
- order_by_from_request = cursor_based_request_context.order_by
+ if Feature.enabled?(:api_keyset_pagination_multi_order)
+ order_by_from_request = cursor_based_request_context.order
+ sort_from_request = cursor_based_request_context.sort
+
+ SUPPORTED_MULTI_ORDERING[relation.klass][order_by_from_request]&.include?(sort_from_request)
+ else
+ order_by_from_request = cursor_based_request_context.order_by
- SUPPORTED_ORDERING[relation.klass] == order_by_from_request
+ SUPPORTED_ORDERING[relation.klass] == order_by_from_request
+ end
end
private_class_method :order_satisfied?
end
diff --git a/lib/gitlab/pagination/keyset/cursor_based_request_context.rb b/lib/gitlab/pagination/keyset/cursor_based_request_context.rb
index 41b90846345..f90574c86ab 100644
--- a/lib/gitlab/pagination/keyset/cursor_based_request_context.rb
+++ b/lib/gitlab/pagination/keyset/cursor_based_request_context.rb
@@ -32,6 +32,14 @@ module Gitlab
def order_by
{ (params[:order_by]&.to_sym || DEFAULT_SORT_COLUMN) => (params[:sort]&.to_sym || DEFAULT_SORT_DIRECTION) }
end
+
+ def order
+ params[:order_by]&.to_sym || DEFAULT_SORT_COLUMN
+ end
+
+ def sort
+ params[:sort]&.to_sym || DEFAULT_SORT_DIRECTION
+ end
end
end
end
diff --git a/lib/gitlab/patch/redis_cache_store.rb b/lib/gitlab/patch/redis_cache_store.rb
index ea6e1f11bc9..96729056ce5 100644
--- a/lib/gitlab/patch/redis_cache_store.rb
+++ b/lib/gitlab/patch/redis_cache_store.rb
@@ -3,8 +3,6 @@
module Gitlab
module Patch
module RedisCacheStore
- PIPELINE_BATCH_SIZE = 100
-
# We will try keep patched code explicit and matching the original signature in
# https://github.com/rails/rails/blob/v6.1.7.2/activesupport/lib/active_support/cache/redis_cache_store.rb#L361
def read_multi_mget(*names) # rubocop:disable Style/ArgumentsForwarding
@@ -21,7 +19,7 @@ module Gitlab
delete_count = 0
redis.with do |conn|
- entries.each_slice(PIPELINE_BATCH_SIZE) do |subset|
+ entries.each_slice(pipeline_batch_size) do |subset|
delete_count += Gitlab::Redis::CrossSlot::Pipeline.new(conn).pipelined do |pipeline|
subset.each { |entry| pipeline.del(entry) }
end.sum
@@ -59,7 +57,7 @@ module Gitlab
end
def pipeline_mget(conn, keys)
- keys.each_slice(PIPELINE_BATCH_SIZE).flat_map do |subset|
+ keys.each_slice(pipeline_batch_size).flat_map do |subset|
Gitlab::Redis::CrossSlot::Pipeline.new(conn).pipelined do |p|
subset.each { |key| p.get(key) }
end
@@ -68,6 +66,10 @@ module Gitlab
private
+ def pipeline_batch_size
+ @pipeline_batch_size ||= [ENV['GITLAB_REDIS_CLUSTER_PIPELINE_BATCH_LIMIT'].to_i, 1000].max
+ end
+
def enable_rails_cache_pipeline_patch?
redis.with { |c| ::Gitlab::Redis::ClusterUtil.cluster?(c) }
end
diff --git a/lib/gitlab/patch/sidekiq_scheduled_enq.rb b/lib/gitlab/patch/sidekiq_scheduled_enq.rb
new file mode 100644
index 00000000000..de0e8465f97
--- /dev/null
+++ b/lib/gitlab/patch/sidekiq_scheduled_enq.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+# Patch to address https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/2286
+# Using a dual-namespace poller eliminates the need for script based migration of
+# schedule-related sets in Sidekiq.
+module Gitlab
+ module Patch
+ module SidekiqScheduledEnq
+ # The patched enqueue_jobs will poll non-namespaced scheduled sets before doing the same for
+ # namespaced sets via super and vice-versa depending on how Sidekiq.redis was configured
+ def enqueue_jobs(sorted_sets = Sidekiq::Scheduled::SETS)
+ # checks the other namespace
+ if Gitlab::Utils.to_boolean(ENV['SIDEKIQ_ENABLE_DUAL_NAMESPACE_POLLING'], default: true)
+ # Refer to https://github.com/sidekiq/sidekiq/blob/v6.5.7/lib/sidekiq/scheduled.rb#L25
+ # this portion swaps out Sidekiq.redis for Gitlab::Redis::Queues
+ Gitlab::Redis::Queues.with do |conn| # rubocop:disable Cop/RedisQueueUsage
+ sorted_sets.each do |sorted_set|
+ # adds namespace if `super` polls with a non-namespaced Sidekiq.redis
+ if Gitlab::Utils.to_boolean(ENV['SIDEKIQ_ENQUEUE_NON_NAMESPACED'])
+ sorted_set = "#{Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE}:#{sorted_set}" # rubocop:disable Cop/RedisQueueUsage
+ end
+
+ while !@done && (job = zpopbyscore(conn, keys: [sorted_set], argv: [Time.now.to_f.to_s])) # rubocop:disable Gitlab/ModuleWithInstanceVariables, Lint/AssignmentInCondition
+ Sidekiq::Client.push(Sidekiq.load_json(job)) # rubocop:disable Cop/SidekiqApiUsage
+ Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" }
+ end
+ end
+ end
+ end
+
+ # calls original enqueue_jobs which may or may not be namespaced depending on SIDEKIQ_ENQUEUE_NON_NAMESPACED
+ super
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index b4297cc695b..6b198d5d950 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -68,7 +68,7 @@ module Gitlab
def limited_notes_count
return @limited_notes_count if defined?(@limited_notes_count)
- types = %w(issue merge_request commit snippet)
+ types = %w[issue merge_request commit snippet]
@limited_notes_count = 0
types.each do |type|
diff --git a/lib/gitlab/prometheus/additional_metrics_parser.rb b/lib/gitlab/prometheus/additional_metrics_parser.rb
deleted file mode 100644
index f5eb27b6916..00000000000
--- a/lib/gitlab/prometheus/additional_metrics_parser.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Prometheus
- module AdditionalMetricsParser
- CONFIG_ROOT = 'config/prometheus'
- MUTEX = Mutex.new
- extend self
-
- def load_groups_from_yaml(file_name)
- yaml_metrics_raw(file_name).map(&method(:group_from_entry))
- end
-
- private
-
- def validate!(obj)
- raise ParsingError, obj.errors.full_messages.join('\n') unless obj.valid?
- end
-
- def group_from_entry(entry)
- entry[:name] = entry.delete(:group)
- entry[:metrics]&.map! do |entry|
- Metric.new(entry).tap(&method(:validate!))
- end
-
- MetricGroup.new(entry).tap(&method(:validate!))
- end
-
- def yaml_metrics_raw(file_name)
- load_yaml_file(file_name)&.map(&:deep_symbolize_keys).freeze
- end
-
- # rubocop:disable Gitlab/ModuleWithInstanceVariables
- def load_yaml_file(file_name)
- return YAML.load_file(Rails.root.join(CONFIG_ROOT, file_name)) if Rails.env.development?
-
- MUTEX.synchronize do
- @loaded_yaml_cache ||= {}
- @loaded_yaml_cache[file_name] ||= YAML.load_file(Rails.root.join(CONFIG_ROOT, file_name))
- end
- end
- # rubocop:enable Gitlab/ModuleWithInstanceVariables
- end
- end
-end
diff --git a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb
deleted file mode 100644
index ab6ef7d5466..00000000000
--- a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Prometheus
- module Queries
- class AdditionalMetricsDeploymentQuery < BaseQuery
- include QueryAdditionalMetrics
-
- # rubocop: disable CodeReuse/ActiveRecord
- def query(deployment_id)
- Deployment.find_by(id: deployment_id).try do |deployment|
- query_metrics(
- deployment.project,
- deployment.environment,
- common_query_context(
- deployment.environment,
- timeframe_start: (deployment.created_at - 30.minutes).to_f,
- timeframe_end: (deployment.created_at + 30.minutes).to_f
- )
- )
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
- end
- end
- end
-end
diff --git a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb
deleted file mode 100644
index c49877ddf9d..00000000000
--- a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Prometheus
- module Queries
- class AdditionalMetricsEnvironmentQuery < BaseQuery
- include QueryAdditionalMetrics
-
- # rubocop: disable CodeReuse/ActiveRecord
- def query(environment_id, timeframe_start = 8.hours.ago, timeframe_end = Time.now)
- ::Environment.find_by(id: environment_id).try do |environment|
- query_metrics(
- environment.project,
- environment,
- common_query_context(
- environment,
- timeframe_start: timeframe_start.to_f,
- timeframe_end: timeframe_end.to_f
- )
- )
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
- end
- end
- end
-end
diff --git a/lib/gitlab/prometheus/query_variables.rb b/lib/gitlab/prometheus/query_variables.rb
index 5b688f83545..6a6e5c22d63 100644
--- a/lib/gitlab/prometheus/query_variables.rb
+++ b/lib/gitlab/prometheus/query_variables.rb
@@ -9,7 +9,7 @@ module Gitlab
__range: range(start_time, end_time),
ci_environment_slug: environment.slug,
kube_namespace: environment.deployment_namespace || '',
- environment_filter: %{container_name!="POD",environment="#{environment.slug}"},
+ environment_filter: %(container_name!="POD",environment="#{environment.slug}"),
ci_project_name: environment.project.name,
ci_project_namespace: environment.project.namespace.name,
ci_project_path: environment.project.full_path,
diff --git a/lib/gitlab/query_limiting/transaction.rb b/lib/gitlab/query_limiting/transaction.rb
index 498da38e268..f44e5383b4f 100644
--- a/lib/gitlab/query_limiting/transaction.rb
+++ b/lib/gitlab/query_limiting/transaction.rb
@@ -68,7 +68,7 @@ module Gitlab
GEO_NODES_LOAD = 'SELECT 1 AS one FROM "geo_nodes" LIMIT 1'
LICENSES_LOAD = 'SELECT "licenses".* FROM "licenses" ORDER BY "licenses"."id"'
- SCHEMA_INTROSPECTION = %r/SELECT.*(FROM|JOIN) (pg_attribute|pg_class)/m.freeze
+ SCHEMA_INTROSPECTION = %r{SELECT.*(FROM|JOIN) (pg_attribute|pg_class)}m.freeze
# queries can be safely ignored if they are amoritized in regular usage
# (i.e. only requested occasionally and otherwise cached).
diff --git a/lib/gitlab/rack_attack.rb b/lib/gitlab/rack_attack.rb
index 829b305d1ee..2182f5b56e4 100644
--- a/lib/gitlab/rack_attack.rb
+++ b/lib/gitlab/rack_attack.rb
@@ -81,6 +81,55 @@ module Gitlab
user_allowlist
end
+ ThrottleDefinition = Struct.new(:options, :request_identifier)
+ def self.throttle_definitions
+ {
+ 'throttle_unauthenticated_web' => ThrottleDefinition.new(
+ Gitlab::Throttle.unauthenticated_web_options,
+ ->(req) { req.ip if req.throttle_unauthenticated_web? }
+ ),
+ # Product analytics feature is in experimental stage.
+ # At this point we want to limit amount of events registered
+ # per application (aid stands for application id).
+ 'throttle_product_analytics_collector' => ThrottleDefinition.new(
+ { limit: 100, period: 60 },
+ ->(req) { req.params['aid'] if req.product_analytics_collector_request? }
+ ),
+ 'throttle_authenticated_web' => ThrottleDefinition.new(
+ Gitlab::Throttle.authenticated_web_options,
+ ->(req) { req.throttled_identifer([:api, :rss, :ics]) if req.throttle_authenticated_web? }
+ ),
+ 'throttle_unauthenticated_protected_paths' => ThrottleDefinition.new(
+ Gitlab::Throttle.protected_paths_options,
+ ->(req) { req.ip if req.throttle_unauthenticated_protected_paths? }
+ ),
+ 'throttle_authenticated_protected_paths_api' => ThrottleDefinition.new(
+ Gitlab::Throttle.protected_paths_options,
+ ->(req) { req.throttled_identifer([:api]) if req.throttle_authenticated_protected_paths_api? }
+ ),
+ 'throttle_authenticated_protected_paths_web' => ThrottleDefinition.new(
+ Gitlab::Throttle.protected_paths_options,
+ ->(req) { req.throttled_identifer([:api, :rss, :ics]) if req.throttle_authenticated_protected_paths_web? }
+ ),
+ 'throttle_unauthenticated_get_protected_paths' => ThrottleDefinition.new(
+ Gitlab::Throttle.protected_paths_options,
+ ->(req) { req.ip if req.throttle_unauthenticated_get_protected_paths? }
+ ),
+ 'throttle_authenticated_get_protected_paths_api' => ThrottleDefinition.new(
+ Gitlab::Throttle.protected_paths_options,
+ ->(req) { req.throttled_identifer([:api]) if req.throttle_authenticated_get_protected_paths_api? }
+ ),
+ 'throttle_authenticated_get_protected_paths_web' => ThrottleDefinition.new(
+ Gitlab::Throttle.protected_paths_options,
+ ->(req) { req.throttled_identifer([:api, :rss, :ics]) if req.throttle_authenticated_get_protected_paths_web? }
+ ),
+ 'throttle_authenticated_git_lfs' => ThrottleDefinition.new(
+ Gitlab::Throttle.throttle_authenticated_git_lfs_options,
+ ->(req) { req.throttled_identifer([:api]) if req.throttle_authenticated_git_lfs? }
+ )
+ }
+ end
+
def self.configure_throttles(rack_attack)
# Each of these settings follows the same pattern of specifying separate
# authenticated and unauthenticated rates via settings
@@ -100,49 +149,8 @@ module Gitlab
end
end
- throttle_or_track(rack_attack, 'throttle_unauthenticated_web', Gitlab::Throttle.unauthenticated_web_options) do |req|
- if req.throttle_unauthenticated_web?
- req.ip
- end
- end
-
- # Product analytics feature is in experimental stage.
- # At this point we want to limit amount of events registered
- # per application (aid stands for application id).
- throttle_or_track(rack_attack, 'throttle_product_analytics_collector', limit: 100, period: 60) do |req|
- if req.product_analytics_collector_request?
- req.params['aid']
- end
- end
-
- throttle_or_track(rack_attack, 'throttle_authenticated_web', Gitlab::Throttle.authenticated_web_options) do |req|
- if req.throttle_authenticated_web?
- req.throttled_identifer([:api, :rss, :ics])
- end
- end
-
- throttle_or_track(rack_attack, 'throttle_unauthenticated_protected_paths', Gitlab::Throttle.protected_paths_options) do |req|
- if req.throttle_unauthenticated_protected_paths?
- req.ip
- end
- end
-
- throttle_or_track(rack_attack, 'throttle_authenticated_protected_paths_api', Gitlab::Throttle.protected_paths_options) do |req|
- if req.throttle_authenticated_protected_paths_api?
- req.throttled_identifer([:api])
- end
- end
-
- throttle_or_track(rack_attack, 'throttle_authenticated_protected_paths_web', Gitlab::Throttle.protected_paths_options) do |req|
- if req.throttle_authenticated_protected_paths_web?
- req.throttled_identifer([:api, :rss, :ics])
- end
- end
-
- throttle_or_track(rack_attack, 'throttle_authenticated_git_lfs', Gitlab::Throttle.throttle_authenticated_git_lfs_options) do |req|
- if req.throttle_authenticated_git_lfs?
- req.throttled_identifer([:api])
- end
+ throttle_definitions.each do |name, definition|
+ throttle_or_track(rack_attack, name, definition.options, &definition.request_identifier)
end
rack_attack.safelist('throttle_bypass_header') do |req|
diff --git a/lib/gitlab/rack_attack/request.rb b/lib/gitlab/rack_attack/request.rb
index d7abacb5b67..a03116f5bb2 100644
--- a/lib/gitlab/rack_attack/request.rb
+++ b/lib/gitlab/rack_attack/request.rb
@@ -71,6 +71,10 @@ module Gitlab
matches?(protected_paths_regex)
end
+ def get_request_protected_path?
+ matches?(protected_paths_for_get_request_regex)
+ end
+
def throttle?(throttle, authenticated:)
fragment = Gitlab::Throttle.throttle_fragment!(throttle, authenticated: authenticated)
@@ -133,6 +137,28 @@ module Gitlab
Gitlab::Throttle.protected_paths_enabled?
end
+ def throttle_unauthenticated_get_protected_paths?
+ get? &&
+ !should_be_skipped? &&
+ get_request_protected_path? &&
+ Gitlab::Throttle.protected_paths_enabled? &&
+ unauthenticated?
+ end
+
+ def throttle_authenticated_get_protected_paths_api?
+ get? &&
+ api_request? &&
+ get_request_protected_path? &&
+ Gitlab::Throttle.protected_paths_enabled?
+ end
+
+ def throttle_authenticated_get_protected_paths_web?
+ get? &&
+ web_request? &&
+ get_request_protected_path? &&
+ Gitlab::Throttle.protected_paths_enabled?
+ end
+
def throttle_unauthenticated_packages_api?
packages_api_path? &&
Gitlab::Throttle.settings.throttle_unauthenticated_packages_api_enabled &&
@@ -199,6 +225,14 @@ module Gitlab
Regexp.union(protected_paths.map { |path| /\A#{Regexp.escape(path)}/ })
end
+ def protected_paths_for_get_request
+ Gitlab::CurrentSettings.current_application_settings.protected_paths_for_get_request
+ end
+
+ def protected_paths_for_get_request_regex
+ Regexp.union(protected_paths_for_get_request.map { |path| /\A#{Regexp.escape(path)}/ })
+ end
+
def packages_api_path?
matches?(::Gitlab::Regex::Packages::API_PATH_REGEX)
end
diff --git a/lib/gitlab/rack_load_balancing_helpers.rb b/lib/gitlab/rack_load_balancing_helpers.rb
new file mode 100644
index 00000000000..5d7228a38fd
--- /dev/null
+++ b/lib/gitlab/rack_load_balancing_helpers.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module RackLoadBalancingHelpers
+ def load_balancer_stick_request(model, namespace, id)
+ request.env[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT] ||= Set.new
+ request.env[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT] << [model.sticking, namespace, id]
+
+ model
+ .sticking
+ .find_caught_up_replica(namespace, id)
+ end
+ end
+end
diff --git a/lib/gitlab/redis.rb b/lib/gitlab/redis.rb
index e760a576253..89ec996488f 100644
--- a/lib/gitlab/redis.rb
+++ b/lib/gitlab/redis.rb
@@ -13,12 +13,15 @@ module Gitlab
Gitlab::Redis::DbLoadBalancing,
Gitlab::Redis::FeatureFlag,
Gitlab::Redis::Queues,
+ Gitlab::Redis::QueuesMetadata,
+ Gitlab::Redis::Pubsub,
Gitlab::Redis::RateLimiting,
Gitlab::Redis::RepositoryCache,
Gitlab::Redis::Sessions,
Gitlab::Redis::SharedState,
Gitlab::Redis::TraceChunks,
- Gitlab::Redis::Chat
+ Gitlab::Redis::Chat,
+ Gitlab::Redis::Workhorse
].freeze
end
end
diff --git a/lib/gitlab/redis/etag_cache.rb b/lib/gitlab/redis/etag_cache.rb
deleted file mode 100644
index 6aafdc8e518..00000000000
--- a/lib/gitlab/redis/etag_cache.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Redis
- class EtagCache < ::Gitlab::Redis::Wrapper
- class << self
- def store_name
- 'Cache'
- end
-
- private
-
- def redis
- primary_store = ::Redis.new(Gitlab::Redis::Cache.params)
- secondary_store = ::Redis.new(Gitlab::Redis::SharedState.params)
-
- MultiStore.new(primary_store, secondary_store, name.demodulize)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/redis/multi_store.rb b/lib/gitlab/redis/multi_store.rb
index 7f4d611a490..9ce030c0bbe 100644
--- a/lib/gitlab/redis/multi_store.rb
+++ b/lib/gitlab/redis/multi_store.rb
@@ -19,8 +19,12 @@ module Gitlab
end
class MethodMissingError < StandardError
+ def initialize(cmd)
+ @cmd = cmd
+ end
+
def message
- 'Method missing. Falling back to execute method on the redis default store in Rails.env.production.'
+ "Method missing #{@cmd}. Falling back to execute method on the redis default store in Rails.env.production."
end
end
@@ -38,6 +42,17 @@ module Gitlab
SKIP_LOG_METHOD_MISSING_FOR_COMMANDS = %i[info].freeze
+ # _client and without_reconnect are Redis::Client methods which may be called through multistore
+ REDIS_CLIENT_COMMANDS = %i[
+ _client
+ without_reconnect
+ ].freeze
+
+ PUBSUB_SUBSCRIBE_COMMANDS = %i[
+ subscribe
+ unsubscribe
+ ].freeze
+
READ_COMMANDS = %i[
exists
exists?
@@ -71,6 +86,7 @@ module Gitlab
incr
incrby
mapped_hmset
+ publish
rpush
sadd
sadd?
@@ -126,7 +142,7 @@ module Gitlab
end
# rubocop:disable GitlabSecurity/PublicSend
- READ_COMMANDS.each do |name|
+ (READ_COMMANDS + REDIS_CLIENT_COMMANDS + PUBSUB_SUBSCRIBE_COMMANDS).each do |name|
define_method(name) do |*args, **kwargs, &block|
if use_primary_and_secondary_stores?
read_command(name, *args, **kwargs, &block)
@@ -246,9 +262,9 @@ module Gitlab
def log_method_missing(command_name, *_args)
return if SKIP_LOG_METHOD_MISSING_FOR_COMMANDS.include?(command_name)
- raise MethodMissingError if Rails.env.test? || Rails.env.development?
+ raise MethodMissingError, command_name if Rails.env.test? || Rails.env.development?
- log_error(MethodMissingError.new, command_name)
+ log_error(MethodMissingError.new(command_name), command_name)
increment_method_missing_count(command_name)
end
diff --git a/lib/gitlab/redis/pubsub.rb b/lib/gitlab/redis/pubsub.rb
new file mode 100644
index 00000000000..b5022f467a2
--- /dev/null
+++ b/lib/gitlab/redis/pubsub.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Redis
+ class Pubsub < ::Gitlab::Redis::Wrapper
+ class << self
+ def config_fallback
+ SharedState
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/redis/queues_metadata.rb b/lib/gitlab/redis/queues_metadata.rb
new file mode 100644
index 00000000000..bb83e7709e1
--- /dev/null
+++ b/lib/gitlab/redis/queues_metadata.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Redis
+ class QueuesMetadata < ::Gitlab::Redis::Wrapper
+ class << self
+ def config_fallback
+ Queues
+ end
+
+ private
+
+ def redis
+ primary_store = ::Redis.new(params)
+ secondary_store = ::Redis.new(config_fallback.params)
+
+ MultiStore.new(primary_store, secondary_store, name.demodulize)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/redis/workhorse.rb b/lib/gitlab/redis/workhorse.rb
new file mode 100644
index 00000000000..ea0fca515fe
--- /dev/null
+++ b/lib/gitlab/redis/workhorse.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Redis
+ class Workhorse < ::Gitlab::Redis::Wrapper
+ class << self
+ def config_fallback
+ SharedState
+ end
+
+ private
+
+ def redis
+ primary_store = ::Redis.new(params)
+ secondary_store = ::Redis.new(config_fallback.params)
+
+ MultiStore.new(primary_store, secondary_store, store_name)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/redis/wrapper.rb b/lib/gitlab/redis/wrapper.rb
index 45fe04835cc..1ec8818d3f5 100644
--- a/lib/gitlab/redis/wrapper.rb
+++ b/lib/gitlab/redis/wrapper.rb
@@ -16,6 +16,8 @@ require 'redis/store/factory'
module Gitlab
module Redis
class Wrapper
+ InvalidPathError = Class.new(StandardError)
+
class << self
delegate :params, :url, :store, to: :new
@@ -122,12 +124,14 @@ module Gitlab
config = raw_config_hash
config[:instrumentation_class] ||= self.class.instrumentation_class
- if config[:cluster].present?
- config[:db] = 0 # Redis Cluster only supports db 0
- config
- else
- parse_redis_url(config)
- end
+ result = if config[:cluster].present?
+ config[:db] = 0 # Redis Cluster only supports db 0
+ config
+ else
+ parse_redis_url(config)
+ end
+
+ parse_client_tls_options(result)
end
def parse_redis_url(config)
@@ -153,6 +157,33 @@ module Gitlab
end
end
+ def parse_client_tls_options(config)
+ return config unless config&.key?(:ssl_params)
+
+ # Only cert_file and key_file are handled in this method. ca_file and
+ # ca_path are Strings, so they can be passed as-is. cert_store is not
+ # currently supported.
+
+ cert_file = config[:ssl_params].delete(:cert_file)
+ key_file = config[:ssl_params].delete(:key_file)
+
+ unless ::File.exist?(cert_file)
+ raise InvalidPathError,
+ "Certificate file #{cert_file} specified in in `resque.yml` does not exist."
+ end
+
+ config[:ssl_params][:cert] = OpenSSL::X509::Certificate.new(File.read(cert_file))
+
+ unless ::File.exist?(key_file)
+ raise InvalidPathError,
+ "Key file #{key_file} specified in in `resque.yml` does not exist."
+ end
+
+ config[:ssl_params][:key] = OpenSSL::PKey.read(File.read(key_file))
+
+ config
+ end
+
def raw_config_hash
config_data = fetch_config
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 783b68fac12..a5e3806735f 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -3,9 +3,9 @@
module Gitlab
# Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor < Banzai::ReferenceExtractor
- REFERABLES = %i(user issue label milestone mentioned_user mentioned_group mentioned_project
+ REFERABLES = %i[user issue label milestone mentioned_user mentioned_group mentioned_project
merge_request snippet commit commit_range directly_addressed_user epic vulnerability
- alert).freeze
+ alert].freeze
attr_accessor :project, :current_user, :author
def initialize(project, current_user = nil)
@@ -43,7 +43,7 @@ module Gitlab
@references[type] ||= references(type)
end
- next unless %w(mentioned_user mentioned_group mentioned_project).include?(type.to_s)
+ next unless %w[mentioned_user mentioned_group mentioned_project].include?(type.to_s)
define_method("#{type}_ids") do
@references[type] ||= references(type, ids_only: true)
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 40facabff23..8ef455efe07 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -3,7 +3,6 @@
module Gitlab
module Regex
extend self
- extend BulkImports
extend MergeRequests
extend Packages
@@ -13,7 +12,7 @@ module Gitlab
# contains only alphanumeric characters, periods, and underscores,
# does not end with a period or forward slash, and has no leading or trailing forward slashes
# eg 'destination-path' or 'destination_pth' not 'example/com/destination/full/path'
- @group_path_regex ||= %r/\A[.]?[^\W]([.]?[0-9a-z][-_]*)+\z/i
+ @group_path_regex ||= %r{\A[.]?[^\W]([.]?[0-9a-z][-_]*)+\z}i
end
def group_path_regex_message
@@ -107,7 +106,7 @@ module Gitlab
end
def cluster_agent_name_regex_message
- %q{can contain only lowercase letters, digits, and '-', but cannot start or end with '-'}
+ %q(can contain only lowercase letters, digits, and '-', but cannot start or end with '-')
end
def kubernetes_namespace_regex
@@ -314,7 +313,7 @@ module Gitlab
# One or more `part`s, separated by separator
def sep_by_1(separator, part)
- %r(#{part} (#{separator} #{part})*)x
+ %r{#{part} (#{separator} #{part})*}x
end
def x509_subject_key_identifier_regex
diff --git a/lib/gitlab/regex/bulk_imports.rb b/lib/gitlab/regex/bulk_imports.rb
deleted file mode 100644
index 65c23b9d2e6..00000000000
--- a/lib/gitlab/regex/bulk_imports.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Regex
- module BulkImports
- def bulk_import_source_full_path_regex_message
- bulk_import_destination_namespace_path_regex_message
- end
-
- def bulk_import_destination_namespace_path_regex_message
- "must have a relative path structure " \
- "with no HTTP protocol characters, or leading or trailing forward slashes. " \
- "Path segments must not start or end with a special character, " \
- "and must not contain consecutive special characters."
- end
- end
- end
-end
diff --git a/lib/gitlab/repo_path.rb b/lib/gitlab/repo_path.rb
index a4d1adf7671..f91dccfec7c 100644
--- a/lib/gitlab/repo_path.rb
+++ b/lib/gitlab/repo_path.rb
@@ -54,6 +54,10 @@ module Gitlab
wiki = find_wiki(full_path)
[wiki, wiki.try(:project)]
+ elsif type.design?
+ design_management_repository = find_design_management_repository(full_path)
+
+ [design_management_repository, design_management_repository.project]
else
project = find_project(full_path)
@@ -95,6 +99,10 @@ module Gitlab
container&.try(:wiki)
end
+ def self.find_design_management_repository(full_path)
+ find_project(full_path)&.design_management_repository
+ end
+
def self.extract_snippet_info(snippet_path)
path_segments = snippet_path.split('/')
snippet_id = path_segments.pop
diff --git a/lib/gitlab/saas.rb b/lib/gitlab/saas.rb
index 722475ce61d..754eed4f253 100644
--- a/lib/gitlab/saas.rb
+++ b/lib/gitlab/saas.rb
@@ -18,7 +18,7 @@ module Gitlab
end
def self.subdomain_regex
- %r{\Ahttps://[a-z0-9-]+\.gitlab\.com\z}.freeze
+ %r{\Ahttps://[a-z0-9-]+\.gitlab\.com\z}
end
def self.dev_url
diff --git a/lib/gitlab/sanitizers/exception_message.rb b/lib/gitlab/sanitizers/exception_message.rb
index 11c91093d88..27885c27ee0 100644
--- a/lib/gitlab/sanitizers/exception_message.rb
+++ b/lib/gitlab/sanitizers/exception_message.rb
@@ -4,8 +4,8 @@ module Gitlab
module Sanitizers
module ExceptionMessage
FILTERED_STRING = '[FILTERED]'
- EXCEPTION_NAMES = %w(URI::InvalidURIError Addressable::URI::InvalidURIError).freeze
- MESSAGE_REGEX = %r{(\A[^:]+:\s).*\Z}.freeze
+ EXCEPTION_NAMES = %w[URI::InvalidURIError Addressable::URI::InvalidURIError].freeze
+ MESSAGE_REGEX = %r{(\A[^:]+:\s).*\Z}
class << self
def clean(exception_name, message)
diff --git a/lib/gitlab/sanitizers/exif.rb b/lib/gitlab/sanitizers/exif.rb
index e302729df66..93deb97c841 100644
--- a/lib/gitlab/sanitizers/exif.rb
+++ b/lib/gitlab/sanitizers/exif.rb
@@ -4,7 +4,7 @@ module Gitlab
module Sanitizers
class Exif
# these tags are not removed from the image
- WHITELISTED_TAGS = %w(
+ WHITELISTED_TAGS = %w[
ResolutionUnit
XResolution
YResolution
@@ -17,13 +17,13 @@ module Gitlab
Copyright
CopyrightNotice
Orientation
- ).freeze
+ ].freeze
# these tags are common in exiftool output, these
# do not contain any sensitive information, but
# we don't need to preserve them when removing
# exif tags
- IGNORED_TAGS = %w(
+ IGNORED_TAGS = %w[
ColorComponents
EncodingProcess
ExifByteOrder
@@ -41,11 +41,11 @@ module Gitlab
FileType
FileTypeExtension
MIMEType
- ).freeze
+ ].freeze
ALLOWED_TAGS = WHITELISTED_TAGS + IGNORED_TAGS
EXCLUDE_PARAMS = WHITELISTED_TAGS.map { |tag| "-#{tag}" }
- ALLOWED_MIME_TYPES = %w(image/jpeg image/tiff).freeze
+ ALLOWED_MIME_TYPES = %w[image/jpeg image/tiff].freeze
attr_reader :logger
diff --git a/lib/gitlab/sanitizers/svg.rb b/lib/gitlab/sanitizers/svg.rb
index 98f78c5e74b..0d4e6be2129 100644
--- a/lib/gitlab/sanitizers/svg.rb
+++ b/lib/gitlab/sanitizers/svg.rb
@@ -9,7 +9,7 @@ module Gitlab
class Scrubber < Loofah::Scrubber
# http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#embedding-custom-non-visible-data-with-the-data-*-attributes
- DATA_ATTR_PATTERN = /\Adata-(?!xml)[a-z_][\w.\u00E0-\u00F6\u00F8-\u017F\u01DD-\u02AF-]*\z/u.freeze
+ DATA_ATTR_PATTERN = /\Adata-(?!xml)[a-z_][\w.\u00E0-\u00F6\u00F8-\u017F\u01DD-\u02AF-]*\z/u
def scrub(node)
unless Whitelist::ALLOWED_ELEMENTS.include?(node.name)
diff --git a/lib/gitlab/search/abuse_detection.rb b/lib/gitlab/search/abuse_detection.rb
index 8711d078ea9..1e4169f3fd7 100644
--- a/lib/gitlab/search/abuse_detection.rb
+++ b/lib/gitlab/search/abuse_detection.rb
@@ -7,9 +7,9 @@ module Gitlab
include AbuseValidators
ABUSIVE_TERM_SIZE = 100
- ALLOWED_CHARS_REGEX = %r{\A[[:alnum:]_\-\/\.!]+\z}.freeze
+ ALLOWED_CHARS_REGEX = %r{\A[[:alnum:]_\-\/\.!]+\z}
- ALLOWED_SCOPES = %w(
+ ALLOWED_SCOPES = %w[
blobs
code
commits
@@ -22,20 +22,20 @@ module Gitlab
snippet_titles
users
wiki_blobs
- ).freeze
+ ].freeze
- READABLE_PARAMS = %i(
+ READABLE_PARAMS = %i[
group_id
project_id
project_ref
query_string
repository_ref
scope
- ).freeze
+ ].freeze
- STOP_WORDS = %w(
+ STOP_WORDS = %w[
a an and are as at be but by for if in into is it no not of on or such that the their then there these they this to was will with
- ).freeze
+ ].freeze
validates :project_id, :group_id,
numericality: { only_integer: true, message: "abusive ID detected" }, allow_blank: true
diff --git a/lib/gitlab/search/found_blob.rb b/lib/gitlab/search/found_blob.rb
index c9051b6a5ff..eb4d61977ea 100644
--- a/lib/gitlab/search/found_blob.rb
+++ b/lib/gitlab/search/found_blob.rb
@@ -11,8 +11,8 @@ module Gitlab
attr_reader :project, :content_match, :blob_path, :highlight_line, :matched_lines_count, :group_level_blob, :group
- PATH_REGEXP = /\A(?<ref>[^:]*):(?<path>[^\x00]*)\x00/.freeze
- CONTENT_REGEXP = /^(?<ref>[^:]*):(?<path>[^\x00]*)\x00(?<startline>\d+)\x00/.freeze
+ PATH_REGEXP = /\A(?<ref>[^:]*):(?<path>[^\x00]*)\x00/
+ CONTENT_REGEXP = /^(?<ref>[^:]*):(?<path>[^\x00]*)\x00(?<startline>\d+)\x00/
def self.preload_blobs(blobs)
to_fetch = blobs.select { |blob| blob.is_a?(self) && blob.blob_path }
diff --git a/lib/gitlab/search/query.rb b/lib/gitlab/search/query.rb
index 360bbc073c5..bafe7876acd 100644
--- a/lib/gitlab/search/query.rb
+++ b/lib/gitlab/search/query.rb
@@ -5,8 +5,8 @@ module Gitlab
class Query < SimpleDelegator
include EncodingHelper
- QUOTES_REGEXP = %r{\A"|"\Z}.freeze
- TOKEN_WITH_QUOTES_REGEXP = %r{\s(?=(?:[^"]|"[^"]*")*$)}.freeze
+ QUOTES_REGEXP = %r{\A"|"\Z}
+ TOKEN_WITH_QUOTES_REGEXP = %r{\s(?=(?:[^"]|"[^"]*")*$)}
def initialize(query, filter_opts = {}, &block)
@raw_query = query.dup
diff --git a/lib/gitlab/search_context.rb b/lib/gitlab/search_context.rb
index 04ef2be87f8..9a7f5fc7328 100644
--- a/lib/gitlab/search_context.rb
+++ b/lib/gitlab/search_context.rb
@@ -130,7 +130,7 @@ module Gitlab
elsif view_context.current_controller?(:commits)
'commits'
elsif view_context.current_controller?(:groups)
- if %w(issues merge_requests).include?(view_context.controller.action_name)
+ if %w[issues merge_requests].include?(view_context.controller.action_name)
view_context.controller.action_name
end
end
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index 0e419d0162c..35e01101b3b 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -181,10 +181,7 @@ module Gitlab
def projects
scope = limit_projects
-
- if Feature.enabled?(:search_projects_hide_archived, current_user) && !filters[:include_archived]
- scope = scope.non_archived
- end
+ scope = scope.non_archived unless filters[:include_archived]
scope.search(query)
end
@@ -193,8 +190,13 @@ module Gitlab
issues = IssuesFinder.new(current_user, issuable_params.merge(finder_params)).execute
unless default_project_filter
- issues = issues.in_projects(project_ids_relation)
- .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/420046")
+ project_ids = project_ids_relation
+ if Feature.enabled?(:search_issues_hide_archived_projects, current_user) && !filters[:include_archived]
+ project_ids = project_ids.non_archived
+ end
+
+ issues = issues.in_projects(project_ids)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/420046')
end
apply_sort(issues, scope: 'issues')
@@ -233,22 +235,21 @@ module Gitlab
# Filter milestones by authorized projects.
# For performance reasons project_id is being plucked
# to be used on a smaller query.
- #
- # rubocop: disable CodeReuse/ActiveRecord
def filter_milestones_by_project(milestones)
- project_ids =
- milestones.where(project_id: project_ids_relation)
- .select(:project_id).distinct
- .pluck(:project_id)
+ candidate_project_ids = project_ids_relation
+
+ if Feature.enabled?(:search_milestones_hide_archived_projects, current_user) && !filters[:include_archived]
+ candidate_project_ids = candidate_project_ids.non_archived
+ end
+
+ project_ids = milestones.of_projects(candidate_project_ids).select(:project_id).distinct.pluck(:project_id) # rubocop: disable CodeReuse/ActiveRecord
return Milestone.none if project_ids.nil?
- authorized_project_ids_relation =
- Project.where(id: project_ids).ids_with_issuables_available_for(current_user)
+ authorized_project_ids_relation = Project.id_in(project_ids).ids_with_issuables_available_for(current_user)
- milestones.where(project_id: authorized_project_ids_relation)
+ milestones.of_projects(authorized_project_ids_relation)
end
- # rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def project_ids_relation
diff --git a/lib/gitlab/security/scan_configuration.rb b/lib/gitlab/security/scan_configuration.rb
index 9b09ccdeb8e..18767dd332a 100644
--- a/lib/gitlab/security/scan_configuration.rb
+++ b/lib/gitlab/security/scan_configuration.rb
@@ -33,6 +33,10 @@ module Gitlab
def meta_info_path; end
+ def on_demand_available?
+ false
+ end
+
private
attr_reader :project, :configured
diff --git a/lib/gitlab/setup_helper.rb b/lib/gitlab/setup_helper.rb
index 2e09a4fce12..8f737977e80 100644
--- a/lib/gitlab/setup_helper.rb
+++ b/lib/gitlab/setup_helper.rb
@@ -38,11 +38,11 @@ module Gitlab
end
def redis_url
- Gitlab::Redis::SharedState.url
+ Gitlab::Redis::Workhorse.url
end
def redis_db
- Gitlab::Redis::SharedState.params.fetch(:db, 0)
+ Gitlab::Redis::Workhorse.params.fetch(:db, 0)
end
def get_config_path(dir, _)
diff --git a/lib/gitlab/sidekiq_config/worker_matcher.rb b/lib/gitlab/sidekiq_config/worker_matcher.rb
index d615d5ecba4..e6b628da0e6 100644
--- a/lib/gitlab/sidekiq_config/worker_matcher.rb
+++ b/lib/gitlab/sidekiq_config/worker_matcher.rb
@@ -7,7 +7,7 @@ module Gitlab
QUERY_OR_OPERATOR = '|'
QUERY_AND_OPERATOR = '&'
QUERY_CONCATENATE_OPERATOR = ','
- QUERY_TERM_REGEX = %r{^(\w+)(!?=)([\w:#{QUERY_CONCATENATE_OPERATOR}]+)}.freeze
+ QUERY_TERM_REGEX = %r{^(\w+)(!?=)([\w:#{QUERY_CONCATENATE_OPERATOR}]+)}
QUERY_PREDICATES = {
worker_name: :to_s,
diff --git a/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb b/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb
index 46939d70c9e..7cc57f9497f 100644
--- a/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb
+++ b/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb
@@ -257,7 +257,12 @@ module Gitlab
end
def with_redis(&block)
- Gitlab::Redis::Queues.with(&block) # rubocop:disable Cop/RedisQueueUsage, CodeReuse/ActiveRecord
+ if Feature.enabled?(:use_primary_and_secondary_stores_for_queues_metadata) ||
+ Feature.enabled?(:use_primary_store_as_default_for_queues_metadata)
+ Gitlab::Redis::QueuesMetadata.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ else
+ Gitlab::Redis::Queues.with(&block) # rubocop:disable Cop/RedisQueueUsage, CodeReuse/ActiveRecord
+ end
end
end
end
diff --git a/lib/gitlab/silent_mode.rb b/lib/gitlab/silent_mode.rb
index 7c7cbf8f1d9..f33654c5545 100644
--- a/lib/gitlab/silent_mode.rb
+++ b/lib/gitlab/silent_mode.rb
@@ -6,6 +6,10 @@ module Gitlab
Gitlab::CurrentSettings.silent_mode_enabled?
end
+ def self.enable!
+ Gitlab::CurrentSettings.update!(silent_mode_enabled: true)
+ end
+
def self.log_info(data)
Gitlab::AppJsonLogger.info(**add_silent_mode_log_data(data))
end
diff --git a/lib/gitlab/slash_commands/deploy.rb b/lib/gitlab/slash_commands/deploy.rb
index 16a4875be91..ee2747c0732 100644
--- a/lib/gitlab/slash_commands/deploy.rb
+++ b/lib/gitlab/slash_commands/deploy.rb
@@ -3,7 +3,7 @@
module Gitlab
module SlashCommands
class Deploy < BaseCommand
- DEPLOY_REGEX = /\Adeploy\s/.freeze
+ DEPLOY_REGEX = /\Adeploy\s/
def self.match(text)
return unless text&.match?(DEPLOY_REGEX)
diff --git a/lib/gitlab/slash_commands/presenters/base.rb b/lib/gitlab/slash_commands/presenters/base.rb
index 55497c5e365..9baae1cb627 100644
--- a/lib/gitlab/slash_commands/presenters/base.rb
+++ b/lib/gitlab/slash_commands/presenters/base.rb
@@ -111,7 +111,7 @@ module Gitlab
end
def fields_with_markdown
- %i(title pretext fields)
+ %i[title pretext fields]
end
end
end
diff --git a/lib/gitlab/slug/path.rb b/lib/gitlab/slug/path.rb
index 434f36829a6..893fccb807e 100644
--- a/lib/gitlab/slug/path.rb
+++ b/lib/gitlab/slug/path.rb
@@ -3,10 +3,10 @@
module Gitlab
module Slug
class Path
- LEADING_DASHES = /\A-+/.freeze
+ LEADING_DASHES = /\A-+/
# 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
+ EXTRACT_LOCAL_EMAIL_PART = /@.*\z/
+ FORBIDDEN_CHARACTERS = /[^a-zA-Z0-9_\-.]/
PATH_TRAILING_VIOLATIONS = %w[.git .atom .].freeze
DEFAULT_SLUG = 'blank'
diff --git a/lib/gitlab/spamcheck/client.rb b/lib/gitlab/spamcheck/client.rb
index d13c3be0a09..d92f8c8df7a 100644
--- a/lib/gitlab/spamcheck/client.rb
+++ b/lib/gitlab/spamcheck/client.rb
@@ -15,7 +15,7 @@ module Gitlab
update: ::Spamcheck::Action::UPDATE
}.freeze
- URL_SCHEME_REGEX = %r{^grpc://|^tls://}.freeze
+ URL_SCHEME_REGEX = %r{^grpc://|^tls://}
def initialize
@endpoint_url = Gitlab::CurrentSettings.current_application_settings.spam_check_endpoint_url
diff --git a/lib/gitlab/sql/pattern.rb b/lib/gitlab/sql/pattern.rb
index 6563968f315..9fedb2d174f 100644
--- a/lib/gitlab/sql/pattern.rb
+++ b/lib/gitlab/sql/pattern.rb
@@ -6,15 +6,31 @@ module Gitlab
extend ActiveSupport::Concern
MIN_CHARS_FOR_PARTIAL_MATCHING = 3
- REGEX_QUOTED_TERM = /(?<=\A| )"[^"]+"(?= |\z)/.freeze
+ REGEX_QUOTED_TERM = /(?<=\A| )"[^"]+"(?= |\z)/
class_methods do
- def fuzzy_search(query, columns, use_minimum_char_limit: true)
+ def fuzzy_search(query, columns, use_minimum_char_limit: true, exact_matches_first: false)
matches = columns.map do |col|
fuzzy_arel_match(col, query, use_minimum_char_limit: use_minimum_char_limit)
end.compact.reduce(:or)
- where(matches)
+ matches = where(matches)
+
+ return matches unless exact_matches_first
+
+ matches.order(exact_matches_first_sql(query, columns))
+ end
+
+ def exact_matches_first_sql(query, columns)
+ cases_sql = columns.map do |column|
+ arel_column = column.is_a?(Arel::Attributes::Attribute) ? column : arel_table[column]
+ match_sql = arel_column.matches(sanitize_sql_like(query)).to_sql
+ "WHEN #{match_sql} THEN 1"
+ end
+
+ cases_sql << "ELSE 2"
+
+ Arel.sql("CASE\n#{cases_sql.join("\n")}\nEND")
end
def to_pattern(query, use_minimum_char_limit: true)
diff --git a/lib/gitlab/ssh_public_key.rb b/lib/gitlab/ssh_public_key.rb
index 707f7f3fc0a..2b9bfa526cb 100644
--- a/lib/gitlab/ssh_public_key.rb
+++ b/lib/gitlab/ssh_public_key.rb
@@ -9,12 +9,12 @@ module Gitlab
# See https://man.openbsd.org/sshd#AUTHORIZED_KEYS_FILE_FORMAT for the list of
# supported algorithms.
TECHNOLOGIES = [
- Technology.new(:rsa, SSHData::PublicKey::RSA, [1024, 2048, 3072, 4096], %w(ssh-rsa)),
- Technology.new(:dsa, SSHData::PublicKey::DSA, [1024, 2048, 3072], %w(ssh-dss)),
- Technology.new(:ecdsa, SSHData::PublicKey::ECDSA, [256, 384, 521], %w(ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521)),
- Technology.new(:ed25519, SSHData::PublicKey::ED25519, [256], %w(ssh-ed25519)),
- Technology.new(:ecdsa_sk, SSHData::PublicKey::SKECDSA, [256], %w(sk-ecdsa-sha2-nistp256@openssh.com)),
- Technology.new(:ed25519_sk, SSHData::PublicKey::SKED25519, [256], %w(sk-ssh-ed25519@openssh.com))
+ Technology.new(:rsa, SSHData::PublicKey::RSA, [1024, 2048, 3072, 4096], %w[ssh-rsa]),
+ Technology.new(:dsa, SSHData::PublicKey::DSA, [1024, 2048, 3072], %w[ssh-dss]),
+ Technology.new(:ecdsa, SSHData::PublicKey::ECDSA, [256, 384, 521], %w[ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521]),
+ Technology.new(:ed25519, SSHData::PublicKey::ED25519, [256], %w[ssh-ed25519]),
+ Technology.new(:ecdsa_sk, SSHData::PublicKey::SKECDSA, [256], %w[sk-ecdsa-sha2-nistp256@openssh.com]),
+ Technology.new(:ed25519_sk, SSHData::PublicKey::SKED25519, [256], %w[sk-ssh-ed25519@openssh.com])
].freeze
def self.technologies
diff --git a/lib/gitlab/task_helpers.rb b/lib/gitlab/task_helpers.rb
index f756d229ba1..78c0f04e07e 100644
--- a/lib/gitlab/task_helpers.rb
+++ b/lib/gitlab/task_helpers.rb
@@ -26,7 +26,7 @@ module Gitlab
def ask_to_continue
return if Gitlab::Utils.to_boolean(ENV['GITLAB_ASSUME_YES'])
- answer = prompt("Do you want to continue (yes/no)? ".color(:blue), %w{yes no})
+ answer = prompt("Do you want to continue (yes/no)? ".color(:blue), %w[yes no])
raise Gitlab::TaskAbortedByUserError unless answer == "yes"
end
@@ -35,7 +35,7 @@ module Gitlab
# It will primarily use lsb_relase to determine the OS.
# It has fallbacks to Debian, SuSE, OS X and systems running systemd.
def os_name
- os_name = run_command(%w(lsb_release -irs))
+ os_name = run_command(%w[lsb_release -irs])
os_name ||=
if File.readable?('/etc/system-release')
File.read('/etc/system-release')
@@ -43,7 +43,7 @@ module Gitlab
"Debian #{File.read('/etc/debian_version')}"
elsif File.readable?('/etc/SuSE-release')
File.read('/etc/SuSE-release')
- elsif os_x_version = run_command(%w(sw_vers -productVersion))
+ elsif os_x_version = run_command(%w[sw_vers -productVersion])
"Mac OS X #{os_x_version}"
elsif File.readable?('/etc/os-release')
File.read('/etc/os-release').match(/PRETTY_NAME=\"(.+)\"/)[1]
@@ -115,7 +115,7 @@ module Gitlab
end
def uid_for(user_name)
- run_command(%W(id -u #{user_name})).chomp.to_i
+ run_command(%W[id -u #{user_name}]).chomp.to_i
end
def gid_for(group_name)
@@ -130,7 +130,7 @@ module Gitlab
def gitlab_user?
strong_memoize(:is_gitlab_user) do
- current_user = run_command(%w(whoami)).chomp
+ current_user = run_command(%w[whoami]).chomp
current_user == gitlab_user
end
end
@@ -139,7 +139,7 @@ module Gitlab
return if gitlab_user?
strong_memoize(:warned_user_not_gitlab) do
- current_user = run_command(%w(whoami)).chomp
+ current_user = run_command(%w[whoami]).chomp
puts " Warning ".color(:black).background(:yellow)
puts " You are running as user #{current_user.color(:magenta)}, we hope you know what you are doing."
diff --git a/lib/gitlab/themes.rb b/lib/gitlab/themes.rb
index ec2ec0d801f..102104644f7 100644
--- a/lib/gitlab/themes.rb
+++ b/lib/gitlab/themes.rb
@@ -7,7 +7,7 @@ module Gitlab
extend self
# Theme ID used when no `default_theme` configuration setting is provided.
- APPLICATION_DEFAULT = 1
+ APPLICATION_DEFAULT = 3
# Struct class representing a single Theme
Theme = Struct.new(:id, :name, :css_class, :css_filename, :primary_color)
@@ -15,17 +15,17 @@ module Gitlab
# All available Themes
def available_themes
[
- Theme.new(1, s_('NavigationTheme|Indigo'), 'ui-indigo', 'theme_indigo', '#292961'),
- Theme.new(6, s_('NavigationTheme|Light Indigo'), 'ui-light-indigo', 'theme_light_indigo', '#4b4ba3'),
- Theme.new(4, s_('NavigationTheme|Blue'), 'ui-blue', 'theme_blue', '#1a3652'),
- Theme.new(7, s_('NavigationTheme|Light Blue'), 'ui-light-blue', 'theme_light_blue', '#2261a1'),
- Theme.new(5, s_('NavigationTheme|Green'), 'ui-green', 'theme_green', '#0d4524'),
- Theme.new(8, s_('NavigationTheme|Light Green'), 'ui-light-green', 'theme_light_green', '#156b39'),
- Theme.new(9, s_('NavigationTheme|Red'), 'ui-red', 'theme_red', '#691a16'),
- Theme.new(10, s_('NavigationTheme|Light Red'), 'ui-light-red', 'theme_light_red', '#a62e21'),
- Theme.new(2, s_('NavigationTheme|Gray'), 'ui-gray', 'theme_gray', '#303030'),
- Theme.new(3, s_('NavigationTheme|Light Gray'), 'ui-light-gray', 'theme_light_gray', '#666'),
- Theme.new(11, s_('NavigationTheme|Dark Mode (alpha)'), 'gl-dark', nil, '#303030')
+ Theme.new(1, s_('NavigationTheme|Indigo'), 'ui-indigo', 'theme_indigo', '#222261'),
+ Theme.new(6, s_('NavigationTheme|Light Indigo'), 'ui-light-indigo', 'theme_light_indigo', '#41419f'),
+ Theme.new(4, s_('NavigationTheme|Blue'), 'ui-blue', 'theme_blue', '#0b2640'),
+ Theme.new(7, s_('NavigationTheme|Light Blue'), 'ui-light-blue', 'theme_light_blue', '#145aa1'),
+ Theme.new(5, s_('NavigationTheme|Green'), 'ui-green', 'theme_green', '#0e4328'),
+ Theme.new(8, s_('NavigationTheme|Light Green'), 'ui-light-green', 'theme_light_green', '#1b653f'),
+ Theme.new(9, s_('NavigationTheme|Red'), 'ui-red', 'theme_red', '#580d02'),
+ Theme.new(10, s_('NavigationTheme|Light Red'), 'ui-light-red', 'theme_light_red', '#a02e1c'),
+ Theme.new(2, s_('NavigationTheme|Gray'), 'ui-gray', 'theme_gray', '#333238'),
+ Theme.new(3, s_('NavigationTheme|Light Gray'), 'ui-light-gray', 'theme_light_gray', '#ececef'),
+ Theme.new(11, s_('NavigationTheme|Dark Mode (alpha)'), 'gl-dark', nil, '#1f1e24')
]
end
diff --git a/lib/gitlab/time_tracking_formatter.rb b/lib/gitlab/time_tracking_formatter.rb
index 7094db14c5d..26efb3b918d 100644
--- a/lib/gitlab/time_tracking_formatter.rb
+++ b/lib/gitlab/time_tracking_formatter.rb
@@ -8,6 +8,8 @@ module Gitlab
CUSTOM_DAY_AND_MONTH_LENGTH = { hours_per_day: 8, days_per_month: 20 }.freeze
def parse(string, keep_zero: false)
+ return unless string
+
negative_time = string.start_with?('-')
string = string.delete_prefix('-')
@@ -15,7 +17,10 @@ module Gitlab
begin
ChronicDuration.parse(
string,
- CUSTOM_DAY_AND_MONTH_LENGTH.merge(default_unit: 'hours', keep_zero: keep_zero))
+ CUSTOM_DAY_AND_MONTH_LENGTH.merge(
+ default_unit: 'hours', keep_zero: keep_zero,
+ use_complete_matcher: true
+ ))
rescue StandardError
nil
end
diff --git a/lib/gitlab/tracking/destinations/database_events_snowplow.rb b/lib/gitlab/tracking/destinations/database_events_snowplow.rb
index e3512bc4916..458d7f0c129 100644
--- a/lib/gitlab/tracking/destinations/database_events_snowplow.rb
+++ b/lib/gitlab/tracking/destinations/database_events_snowplow.rb
@@ -16,7 +16,7 @@ module Gitlab
override :hostname
def hostname
- return HOSTNAME if ::Gitlab.com?
+ return Gitlab::CurrentSettings.snowplow_database_collector_hostname || HOSTNAME if ::Gitlab.com?
'localhost:9091'
end
diff --git a/lib/gitlab/tracking/service_ping_context.rb b/lib/gitlab/tracking/service_ping_context.rb
index d31ca69a10c..2135101e0e3 100644
--- a/lib/gitlab/tracking/service_ping_context.rb
+++ b/lib/gitlab/tracking/service_ping_context.rb
@@ -3,19 +3,18 @@
module Gitlab
module Tracking
class ServicePingContext
- SCHEMA_URL = 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-0'
+ SCHEMA_URL = 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-1'
REDISHLL_SOURCE = :redis_hll
REDIS_SOURCE = :redis
ALLOWED_SOURCES = [REDISHLL_SOURCE, REDIS_SOURCE].freeze
- def initialize(data_source:, event: nil, key_path: nil)
- check_configuration(data_source, event, key_path)
+ def initialize(data_source:, event: nil)
+ check_configuration(data_source, event)
@payload = { data_source: data_source }
- payload[:event_name] = event if data_source.eql? REDISHLL_SOURCE
- payload[:key_path] = key_path if data_source.eql? REDIS_SOURCE
+ payload[:event_name] = event
end
def to_context
@@ -33,18 +32,14 @@ module Gitlab
attr_reader :payload
- def check_configuration(data_source, event, key_path)
- unless ALLOWED_SOURCES.include?(data_source)
+ def check_configuration(data_source, event)
+ unless ALLOWED_SOURCES.include?(data_source.to_sym)
configuration_error("#{data_source} is not acceptable data source for ServicePingContext")
end
- if REDISHLL_SOURCE.eql?(data_source) && event.nil?
- configuration_error("event attribute can not be missing for #{REDISHLL_SOURCE} data source")
- end
-
- return unless REDIS_SOURCE.eql?(data_source) && key_path.nil?
+ return unless event.nil?
- configuration_error("key_path attribute can not be missing for #{REDIS_SOURCE} data source")
+ configuration_error("event attribute is required")
end
def configuration_error(message)
diff --git a/lib/gitlab/tracking/standard_context.rb b/lib/gitlab/tracking/standard_context.rb
index 61d6fdc6dca..4c04fa7d525 100644
--- a/lib/gitlab/tracking/standard_context.rb
+++ b/lib/gitlab/tracking/standard_context.rb
@@ -50,6 +50,7 @@ module Gitlab
plan: plan_name,
extra: extra,
user_id: user_id,
+ is_gitlab_team_member: gitlab_team_member?(user_id),
namespace_id: namespace_id,
project_id: project_id,
context_generated_at: Time.current
@@ -63,6 +64,13 @@ module Gitlab
" Should be one of #{allowed_classes.map(&:to_s)}"
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(ArgumentError.new(exception))
end
+
+ # Overridden in EE
+ def gitlab_team_member?(_user_id)
+ nil
+ end
end
end
end
+
+Gitlab::Tracking::StandardContext.prepend_mod
diff --git a/lib/gitlab/unicode.rb b/lib/gitlab/unicode.rb
index f291ea1b4ee..b78393dd101 100644
--- a/lib/gitlab/unicode.rb
+++ b/lib/gitlab/unicode.rb
@@ -7,13 +7,13 @@ module Gitlab
#
# Documentation on how this works:
# https://idiosyncratic-ruby.com/41-proper-unicoding.html
- BIDI_REGEXP = /\p{Bidi Control}/.freeze
+ BIDI_REGEXP = /\p{Bidi Control}/
# Regular expression for identifying space characters
#
# In web browsers space characters can be confused with simple
# spaces which may be misleading
- SPACE_REGEXP = /\p{Space_Separator}/.freeze
+ SPACE_REGEXP = /\p{Space_Separator}/
class << self
# Warning message used to highlight bidi characters in the GUI
diff --git a/lib/gitlab/untrusted_regexp/ruby_syntax.rb b/lib/gitlab/untrusted_regexp/ruby_syntax.rb
index 1f1da592ce0..db01875d080 100644
--- a/lib/gitlab/untrusted_regexp/ruby_syntax.rb
+++ b/lib/gitlab/untrusted_regexp/ruby_syntax.rb
@@ -6,7 +6,7 @@ module Gitlab
# and converts that to RE2 representation:
# /<regexp>/<flags>
class RubySyntax
- PATTERN = %r{^/(?<regexp>.*)/(?<flags>[ismU]*)$}.freeze
+ PATTERN = %r{^/(?<regexp>.*)/(?<flags>[ismU]*)$}
# Checks if pattern matches a regexp pattern
# but does not enforce it's validity
diff --git a/lib/gitlab/url_blocker.rb b/lib/gitlab/url_blocker.rb
index 31256101bd2..57d3b3ec6f9 100644
--- a/lib/gitlab/url_blocker.rb
+++ b/lib/gitlab/url_blocker.rb
@@ -260,7 +260,7 @@ module Gitlab
return true if /\n|\r/.match?(url)
# Google Cloud Storage uses a multi-line, encoded Signature query string
- return false if %w(http https).include?(parsed_url.scheme&.downcase)
+ return false if %w[http https].include?(parsed_url.scheme&.downcase)
CGI.unescape(url) =~ /\n|\r/
end
diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb
index 79e124a58f5..20cbde0e700 100644
--- a/lib/gitlab/url_sanitizer.rb
+++ b/lib/gitlab/url_sanitizer.rb
@@ -26,6 +26,12 @@ module Gitlab
#{URI::REGEXP::PATTERN::HOSTPORT}
)
}x
+ # This expression is derived from `URI::REGEXP::PATTERN::USERINFO` but with the
+ # addition of `{` and `}` in the list of allowed characters to account for the
+ # possibility of the userinfo portion of a URL containing masked segments.
+ # e.g.
+ # http://myuser:{masked_password}@{masked_domain}.com/{masked_hook}
+ MASKED_USERINFO_REGEX = %r{(?:[\\-_.!~*'()a-zA-Z\d;:&=+$,{}]|%[a-fA-F\d]{2})*}
def self.sanitize(content)
content.gsub(URI_REGEXP) do |url|
@@ -50,6 +56,14 @@ module Gitlab
valid?(url, allowed_schemes: ALLOWED_WEB_SCHEMES)
end
+ # The url associated with records like `WebHookLog` may contain masked
+ # portions represented by paired curly brackets in the URL. As this
+ # prohibits straightforward parsing of the URL, we can use a variation of
+ # the existing USERINFO regex for these cases.
+ def self.sanitize_masked_url(url)
+ url.gsub(%r{//#{MASKED_USERINFO_REGEX}@}o, '//*****:*****@')
+ end
+
def initialize(url, credentials: nil)
%i[user password].each do |symbol|
credentials[symbol] = credentials[symbol].presence if credentials&.key?(symbol)
diff --git a/lib/gitlab/usage/metric_definition.rb b/lib/gitlab/usage/metric_definition.rb
index bd42586731e..450575b7223 100644
--- a/lib/gitlab/usage/metric_definition.rb
+++ b/lib/gitlab/usage/metric_definition.rb
@@ -4,7 +4,6 @@ module Gitlab
module Usage
class MetricDefinition
METRIC_SCHEMA_PATH = Rails.root.join('config', 'metrics', 'schema.json')
- SKIP_VALIDATION_STATUS = 'removed'
AVAILABLE_STATUSES = %w[active broken].to_set.freeze
VALID_SERVICE_PING_STATUSES = %w[active broken].to_set.freeze
@@ -26,6 +25,18 @@ module Gitlab
events_from_new_structure || events_from_old_structure || {}
end
+ def to_context
+ return unless %w[redis redis_hll].include?(data_source)
+
+ event_name = if data_source == 'redis_hll'
+ options[:events].first
+ elsif data_source == 'redis'
+ Gitlab::Usage::Metrics::Instrumentations::RedisMetric.new(attributes).redis_key
+ end
+
+ Gitlab::Tracking::ServicePingContext.new(data_source: data_source, event: event_name)
+ end
+
def to_h
attributes
end
@@ -98,6 +109,10 @@ module Gitlab
all.select { |definition| definition.attributes[:instrumentation_class].present? && definition.available? }
end
+ def context_for(key_path)
+ definitions[key_path].to_context
+ end
+
def schemer
@schemer ||= ::JSONSchemer.schema(Pathname.new(METRIC_SCHEMA_PATH))
end
@@ -161,7 +176,7 @@ module Gitlab
end
def skip_validation?
- !!attributes[:skip_validation] || @skip_validation || attributes[:status] == SKIP_VALIDATION_STATUS
+ !!attributes[:skip_validation] || @skip_validation
end
def events_from_new_structure
diff --git a/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb b/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb
index f5d963cf522..807e0ee071a 100644
--- a/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric.rb
@@ -27,6 +27,10 @@ module Gitlab
}
end
end
+
+ def to_sql
+ relation.unscope(:order).to_sql
+ end
end
end
end
diff --git a/lib/gitlab/usage/metrics/instrumentations/count_connected_agents_metric.rb b/lib/gitlab/usage/metrics/instrumentations/count_connected_agents_metric.rb
new file mode 100644
index 00000000000..dea3f73c008
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/count_connected_agents_metric.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class CountConnectedAgentsMetric < DatabaseMetric
+ operation :count
+
+ relation do
+ Clusters::AgentToken.connected
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric.rb b/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric.rb
index 109d2245635..4430c7453e6 100644
--- a/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric.rb
@@ -10,8 +10,8 @@ module Gitlab
relation { Project }
operation :count
- IMPORT_TYPES = %w(gitlab_project gitlab github bitbucket bitbucket_server gitea git manifest
- gitlab_migration).freeze
+ IMPORT_TYPES = %w[gitlab_project gitlab github bitbucket bitbucket_server gitea git manifest
+ gitlab_migration].freeze
def value
count(project_relation) + count(entity_relation)
diff --git a/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric.rb b/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric.rb
index e6093691f48..745d147ac88 100644
--- a/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/count_issues_created_manually_from_alerts_metric.rb
@@ -13,7 +13,7 @@ module Gitlab
cache_start_and_finish_as :issue
relation do
- Issue.with_alert_management_alerts.not_authored_by(::User.alert_bot)
+ Issue.with_alert_management_alerts.not_authored_by(::Users::Internal.alert_bot)
end
def value
diff --git a/lib/gitlab/usage/metrics/instrumentations/database_metric.rb b/lib/gitlab/usage/metrics/instrumentations/database_metric.rb
index 2af7c208fce..7133c815e10 100644
--- a/lib/gitlab/usage/metrics/instrumentations/database_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/database_metric.rb
@@ -18,7 +18,7 @@ module Gitlab
UnimplementedOperationError = Class.new(StandardError) # rubocop:disable UsageData/InstrumentationSuperclass
class << self
- IMPLEMENTED_OPERATIONS = %i(count distinct_count estimate_batch_distinct_count sum average).freeze
+ IMPLEMENTED_OPERATIONS = %i[count distinct_count estimate_batch_distinct_count sum average].freeze
private_constant :IMPLEMENTED_OPERATIONS
diff --git a/lib/gitlab/usage/metrics/instrumentations/issues_created_from_alerts_metric.rb b/lib/gitlab/usage/metrics/instrumentations/issues_created_from_alerts_metric.rb
index e430bc8eb71..d88128216d6 100644
--- a/lib/gitlab/usage/metrics/instrumentations/issues_created_from_alerts_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/issues_created_from_alerts_metric.rb
@@ -7,8 +7,7 @@ module Gitlab
class IssuesCreatedFromAlertsMetric < NumbersMetric
ISSUES_FROM_ALERTS_METRICS = [
IssuesWithAlertManagementAlertsMetric,
- IssuesWithPrometheusAlertEvents,
- IssuesWithSelfManagedPrometheusAlertEvents
+ IssuesWithPrometheusAlertEvents
].freeze
operation :add
diff --git a/lib/gitlab/usage/metrics/instrumentations/issues_with_self_managed_prometheus_alert_events.rb b/lib/gitlab/usage/metrics/instrumentations/issues_with_self_managed_prometheus_alert_events.rb
deleted file mode 100644
index fdbaa65bc68..00000000000
--- a/lib/gitlab/usage/metrics/instrumentations/issues_with_self_managed_prometheus_alert_events.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Usage
- module Metrics
- module Instrumentations
- class IssuesWithSelfManagedPrometheusAlertEvents < DatabaseMetric
- # this metric is used in IssuesCreatedFromAlertsMetric
- # do not report metric directly in service ping
- available? { false }
-
- operation :count
-
- start { Issue.minimum(:id) }
- finish { Issue.maximum(:id) }
-
- relation { Issue.with_self_managed_prometheus_alert_events }
-
- cache_start_and_finish_as :issue
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb b/lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb
index 67fcd226a0a..f168837bd50 100644
--- a/lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb
@@ -21,7 +21,7 @@ module Gitlab
UnimplementedOperationError = Class.new(StandardError) # rubocop:disable UsageData/InstrumentationSuperclass
class << self
- IMPLEMENTED_OPERATIONS = %i(add).freeze
+ IMPLEMENTED_OPERATIONS = %i[add].freeze
private_constant :IMPLEMENTED_OPERATIONS
diff --git a/lib/gitlab/usage/metrics/instrumentations/redis_metric.rb b/lib/gitlab/usage/metrics/instrumentations/redis_metric.rb
index ca5e5b706c4..217fa6aca49 100644
--- a/lib/gitlab/usage/metrics/instrumentations/redis_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/redis_metric.rb
@@ -48,8 +48,6 @@ module Gitlab
end
end
- private
-
def redis_key
key = metric_event.dup
key.prepend("#{prefix}_") if prefix
diff --git a/lib/gitlab/usage/time_series_storable.rb b/lib/gitlab/usage/time_series_storable.rb
new file mode 100644
index 00000000000..83f62b8c1c7
--- /dev/null
+++ b/lib/gitlab/usage/time_series_storable.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module TimeSeriesStorable
+ # requires a #redis_key(event, date) method to be defined
+ def keys_for_aggregation(events:, start_date:, end_date:)
+ # we always keep 1 week of margin
+ # .end_of_week is necessary to make sure this works for 1 week long periods too
+ end_date = end_date.end_of_week - 1.week
+ (start_date.to_date..end_date.to_date).flat_map do |date|
+ events.map { |event| redis_key(event, date) }
+ end.uniq
+ end
+
+ def apply_time_aggregation(key, time)
+ year_week = time.strftime('%G-%V')
+ "#{key}-#{year_week}"
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index ab041a31bde..c3378856633 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -20,7 +20,7 @@ module Gitlab
class UsageData
MAX_GENERATION_TIME_FOR_SAAS = 40.hours
- CE_MEMOIZED_VALUES = %i(
+ CE_MEMOIZED_VALUES = %i[
issue_minimum_id
issue_maximum_id
project_minimum_id
@@ -31,7 +31,7 @@ module Gitlab
deployment_maximum_id
auth_providers
recorded_at
- ).freeze
+ ].freeze
class << self
include Gitlab::Utils::UsageData
@@ -96,7 +96,7 @@ module Gitlab
issues_with_embedded_grafana_charts_approx: grafana_embed_usage_data,
issues_created_from_alerts: total_alert_issues,
incident_issues: count(::Issue.with_issue_type(:incident), start: minimum_id(Issue), finish: maximum_id(Issue)),
- alert_bot_incident_issues: count(::Issue.authored(::User.alert_bot), start: minimum_id(Issue), finish: maximum_id(Issue)),
+ alert_bot_incident_issues: count(::Issue.authored(::Users::Internal.alert_bot), start: minimum_id(Issue), finish: maximum_id(Issue)),
keys: count(Key),
label_lists: count(List.label),
lfs_objects: count(LfsObject),
@@ -529,7 +529,7 @@ module Gitlab
service_desk_issues: count(
::Issue.where(
project: projects_with_service_desk,
- author: ::User.support_bot,
+ author: ::Users::Internal.support_bot,
confidential: true
)
)
diff --git a/lib/gitlab/usage_data/topology.rb b/lib/gitlab/usage_data/topology.rb
index b823d6cc2bf..d9f23d2d887 100644
--- a/lib/gitlab/usage_data/topology.rb
+++ b/lib/gitlab/usage_data/topology.rb
@@ -130,7 +130,7 @@ module Gitlab
client.query(query)
end
- map_instance_labels(node_uname_info, %w(machine sysname release))
+ map_instance_labels(node_uname_info, %w[machine sysname release])
end
def topology_all_service_memory(client)
diff --git a/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb b/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
index 21cc9368f44..eb141a2e2f6 100644
--- a/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
@@ -38,7 +38,7 @@ module Gitlab::UsageDataCounters
expanded_template_name = expand_template_name(template_name)
results = [expanded_template_name].tap do |result|
template = Gitlab::Template::GitlabCiYmlTemplate.find(template_name.chomp('.gitlab-ci.yml'))
- data = Gitlab::Ci::Config::Yaml.load!(template.content)
+ data = Gitlab::Ci::Config::Yaml::Loader.new(template.content).load.content
[data[:include]].compact.flatten.each do |ci_include|
if ci_include_template = ci_include[:template]
result.concat(all_included_templates(ci_include_template))
diff --git a/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter.rb
index b30c4b675f9..be566617bd4 100644
--- a/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/gitlab_cli_activity_unique_counter.rb
@@ -6,7 +6,7 @@ module Gitlab
GITLAB_CLI_API_REQUEST_ACTION = 'i_code_review_user_gitlab_cli_api_request'
# This regex will match to user agents ending with GitLab CLI or starting with glab/v"
- GITLAB_CLI_USER_AGENT_REGEX = %r{(GitLab\sCLI$|^glab/v)}.freeze
+ GITLAB_CLI_USER_AGENT_REGEX = %r{(GitLab\sCLI$|^glab/v)}
class << self
def track_api_request_when_trackable(user_agent:, user:)
diff --git a/lib/gitlab/usage_data_counters/hll_redis_counter.rb b/lib/gitlab/usage_data_counters/hll_redis_counter.rb
index 53594a27867..f9dc8bd8a3c 100644
--- a/lib/gitlab/usage_data_counters/hll_redis_counter.rb
+++ b/lib/gitlab/usage_data_counters/hll_redis_counter.rb
@@ -18,6 +18,7 @@ module Gitlab
class << self
include Gitlab::Utils::UsageData
include Gitlab::Usage::TimeFrame
+ include Gitlab::Usage::TimeSeriesStorable
# Track unique events
#
@@ -78,13 +79,6 @@ module Gitlab
redis_usage_data { Gitlab::Redis::HLL.count(keys: keys) }
end
- def keys_for_aggregation(events:, start_date:, end_date:)
- end_date = end_date.end_of_week - 1.week
- (start_date.to_date..end_date.to_date).map do |date|
- events.map { |event| redis_key(event, date) }
- end.flatten.uniq
- end
-
def load_events
events = Gitlab::Usage::MetricDefinition.all.map do |d|
next unless d.available?
@@ -109,7 +103,6 @@ module Gitlab
known_events.select { |event| event_names.include?(event[:name]) }
end
- # Compose the key in order to store events daily or weekly
def redis_key(event, time)
raise UnknownEvent, "Unknown event #{event[:name]}" unless known_events_names.include?(event[:name].to_s)
diff --git a/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
index 54464b63fce..39d9560c0fb 100644
--- a/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
@@ -38,170 +38,120 @@ module Gitlab
class << self
def track_issue_created_action(author:, namespace:)
- track_internal_action(ISSUE_CREATED, author, namespace)
+ track_internal_event(ISSUE_CREATED, author, namespace)
end
def track_issue_title_changed_action(author:, project:)
- track_snowplow_action(ISSUE_TITLE_CHANGED, author, project)
- track_unique_action(ISSUE_TITLE_CHANGED, author)
+ track_internal_event(ISSUE_TITLE_CHANGED, author, project)
end
def track_issue_description_changed_action(author:, project:)
- track_snowplow_action(ISSUE_DESCRIPTION_CHANGED, author, project)
- track_unique_action(ISSUE_DESCRIPTION_CHANGED, author)
+ track_internal_event(ISSUE_DESCRIPTION_CHANGED, author, project)
end
def track_issue_assignee_changed_action(author:, project:)
- track_snowplow_action(ISSUE_ASSIGNEE_CHANGED, author, project)
- track_unique_action(ISSUE_ASSIGNEE_CHANGED, author)
+ track_internal_event(ISSUE_ASSIGNEE_CHANGED, author, project)
end
def track_issue_made_confidential_action(author:, project:)
- track_snowplow_action(ISSUE_MADE_CONFIDENTIAL, author, project)
- track_unique_action(ISSUE_MADE_CONFIDENTIAL, author)
+ track_internal_event(ISSUE_MADE_CONFIDENTIAL, author, project)
end
def track_issue_made_visible_action(author:, project:)
- track_snowplow_action(ISSUE_MADE_VISIBLE, author, project)
- track_unique_action(ISSUE_MADE_VISIBLE, author)
+ track_internal_event(ISSUE_MADE_VISIBLE, author, project)
end
def track_issue_closed_action(author:, project:)
- track_snowplow_action(ISSUE_CLOSED, author, project)
- track_unique_action(ISSUE_CLOSED, author)
+ track_internal_event(ISSUE_CLOSED, author, project)
end
def track_issue_reopened_action(author:, project:)
- track_snowplow_action(ISSUE_REOPENED, author, project)
- track_unique_action(ISSUE_REOPENED, author)
+ track_internal_event(ISSUE_REOPENED, author, project)
end
def track_issue_label_changed_action(author:, project:)
- track_snowplow_action(ISSUE_LABEL_CHANGED, author, project)
- track_unique_action(ISSUE_LABEL_CHANGED, author)
+ track_internal_event(ISSUE_LABEL_CHANGED, author, project)
end
def track_issue_milestone_changed_action(author:, project:)
- track_snowplow_action(ISSUE_MILESTONE_CHANGED, author, project)
- track_unique_action(ISSUE_MILESTONE_CHANGED, author)
+ track_internal_event(ISSUE_MILESTONE_CHANGED, author, project)
end
def track_issue_cross_referenced_action(author:, project:)
- track_snowplow_action(ISSUE_CROSS_REFERENCED, author, project)
- track_unique_action(ISSUE_CROSS_REFERENCED, author)
+ track_internal_event(ISSUE_CROSS_REFERENCED, author, project)
end
def track_issue_moved_action(author:, project:)
- track_snowplow_action(ISSUE_MOVED, author, project)
- track_unique_action(ISSUE_MOVED, author)
+ track_internal_event(ISSUE_MOVED, author, project)
end
def track_issue_related_action(author:, project:)
- track_snowplow_action(ISSUE_RELATED, author, project)
- track_unique_action(ISSUE_RELATED, author)
+ track_internal_event(ISSUE_RELATED, author, project)
end
def track_issue_unrelated_action(author:, project:)
- track_snowplow_action(ISSUE_UNRELATED, author, project)
- track_unique_action(ISSUE_UNRELATED, author)
+ track_internal_event(ISSUE_UNRELATED, author, project)
end
def track_issue_marked_as_duplicate_action(author:, project:)
- track_snowplow_action(ISSUE_MARKED_AS_DUPLICATE, author, project)
- track_unique_action(ISSUE_MARKED_AS_DUPLICATE, author)
+ track_internal_event(ISSUE_MARKED_AS_DUPLICATE, author, project)
end
def track_issue_locked_action(author:, project:)
- track_snowplow_action(ISSUE_LOCKED, author, project)
- track_unique_action(ISSUE_LOCKED, author)
+ track_internal_event(ISSUE_LOCKED, author, project)
end
def track_issue_unlocked_action(author:, project:)
- track_snowplow_action(ISSUE_UNLOCKED, author, project)
- track_unique_action(ISSUE_UNLOCKED, author)
+ track_internal_event(ISSUE_UNLOCKED, author, project)
end
def track_issue_designs_added_action(author:, project:)
- track_snowplow_action(ISSUE_DESIGNS_ADDED, author, project)
- track_unique_action(ISSUE_DESIGNS_ADDED, author)
+ track_internal_event(ISSUE_DESIGNS_ADDED, author, project)
end
def track_issue_designs_modified_action(author:, project:)
- track_snowplow_action(ISSUE_DESIGNS_MODIFIED, author, project)
- track_unique_action(ISSUE_DESIGNS_MODIFIED, author)
+ track_internal_event(ISSUE_DESIGNS_MODIFIED, author, project)
end
def track_issue_designs_removed_action(author:, project:)
- track_snowplow_action(ISSUE_DESIGNS_REMOVED, author, project)
- track_unique_action(ISSUE_DESIGNS_REMOVED, author)
+ track_internal_event(ISSUE_DESIGNS_REMOVED, author, project)
end
def track_issue_due_date_changed_action(author:, project:)
- track_snowplow_action(ISSUE_DUE_DATE_CHANGED, author, project)
- track_unique_action(ISSUE_DUE_DATE_CHANGED, author)
+ track_internal_event(ISSUE_DUE_DATE_CHANGED, author, project)
end
def track_issue_time_estimate_changed_action(author:, project:)
- track_snowplow_action(ISSUE_TIME_ESTIMATE_CHANGED, author, project)
- track_unique_action(ISSUE_TIME_ESTIMATE_CHANGED, author)
+ track_internal_event(ISSUE_TIME_ESTIMATE_CHANGED, author, project)
end
def track_issue_time_spent_changed_action(author:, project:)
- track_snowplow_action(ISSUE_TIME_SPENT_CHANGED, author, project)
- track_unique_action(ISSUE_TIME_SPENT_CHANGED, author)
+ track_internal_event(ISSUE_TIME_SPENT_CHANGED, author, project)
end
def track_issue_comment_added_action(author:, project:)
- track_snowplow_action(ISSUE_COMMENT_ADDED, author, project)
- track_unique_action(ISSUE_COMMENT_ADDED, author)
+ track_internal_event(ISSUE_COMMENT_ADDED, author, project)
end
def track_issue_comment_edited_action(author:, project:)
- track_snowplow_action(ISSUE_COMMENT_EDITED, author, project)
- track_unique_action(ISSUE_COMMENT_EDITED, author)
+ track_internal_event(ISSUE_COMMENT_EDITED, author, project)
end
def track_issue_comment_removed_action(author:, project:)
- track_snowplow_action(ISSUE_COMMENT_REMOVED, author, project)
- track_unique_action(ISSUE_COMMENT_REMOVED, author)
+ track_internal_event(ISSUE_COMMENT_REMOVED, author, project)
end
def track_issue_cloned_action(author:, project:)
- track_snowplow_action(ISSUE_CLONED, author, project)
- track_unique_action(ISSUE_CLONED, author)
+ track_internal_event(ISSUE_CLONED, author, project)
end
def track_issue_design_comment_removed_action(author:, project:)
- track_snowplow_action(ISSUE_DESIGN_COMMENT_REMOVED, author, project)
- track_unique_action(ISSUE_DESIGN_COMMENT_REMOVED, author)
+ track_internal_event(ISSUE_DESIGN_COMMENT_REMOVED, author, project)
end
private
- def track_snowplow_action(event_name, author, container)
- namespace, project = get_params_from_container(container)
-
- return unless author
-
- Gitlab::Tracking.event(
- ISSUE_CATEGORY,
- ISSUE_ACTION,
- label: ISSUE_LABEL,
- property: event_name,
- project: project,
- namespace: namespace,
- user: author,
- context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context]
- )
- end
-
- def track_unique_action(event_name, author)
- return unless author
-
- Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: author.id)
- end
-
- def track_internal_action(event_name, author, container)
+ def track_internal_event(event_name, author, container)
return unless author
namespace, project = get_params_from_container(container)
diff --git a/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb
index f3d5be5e28f..42387b0d7f4 100644
--- a/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter.rb
@@ -4,7 +4,7 @@ module Gitlab
module UsageDataCounters
module JetBrainsPluginActivityUniqueCounter
JETBRAINS_API_REQUEST_ACTION = 'i_code_review_user_jetbrains_api_request'
- JETBRAINS_USER_AGENT_REGEX = /\Agitlab-jetbrains-plugin/.freeze
+ JETBRAINS_USER_AGENT_REGEX = /\Agitlab-jetbrains-plugin/
class << self
def track_api_request_when_trackable(user_agent:, user:)
diff --git a/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb b/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
index 9e8c207a19a..f4a1dd692b7 100644
--- a/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
+++ b/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
@@ -10,6 +10,7 @@ module Gitlab
flux_git_push_notifications_total
k8s_api_proxy_requests_via_ci_access
k8s_api_proxy_requests_via_user_access
+ k8s_api_proxy_requests_via_pat_access
].freeze
class << self
diff --git a/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter.rb
index 703c4885b04..7b3df134ba3 100644
--- a/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter.rb
@@ -4,7 +4,7 @@ module Gitlab
module UsageDataCounters
module VSCodeExtensionActivityUniqueCounter
VS_CODE_API_REQUEST_ACTION = 'i_code_review_user_vs_code_api_request'
- VS_CODE_USER_AGENT_REGEX = /\Avs-code-gitlab-workflow/.freeze
+ VS_CODE_USER_AGENT_REGEX = /\Avs-code-gitlab-workflow/
class << self
def track_api_request_when_trackable(user_agent:, user:)
diff --git a/lib/gitlab/utils/link_header_parser.rb b/lib/gitlab/utils/link_header_parser.rb
index d98c237baf3..a766be93b7e 100644
--- a/lib/gitlab/utils/link_header_parser.rb
+++ b/lib/gitlab/utils/link_header_parser.rb
@@ -19,9 +19,9 @@ module Gitlab
# }
# }
class LinkHeaderParser
- REL_PATTERN = %r{rel="(\w+)"}.freeze
+ REL_PATTERN = %r{rel="(\w+)"}
# to avoid parse really long URIs we limit the amount of characters allowed
- URI_PATTERN = %r{<(.{1,500})>}.freeze
+ URI_PATTERN = %r{<(.{1,500})>}
def initialize(header)
@header = header
diff --git a/lib/gitlab/utils/markdown.rb b/lib/gitlab/utils/markdown.rb
index c041953e7c8..750789430d9 100644
--- a/lib/gitlab/utils/markdown.rb
+++ b/lib/gitlab/utils/markdown.rb
@@ -3,8 +3,8 @@
module Gitlab
module Utils
module Markdown
- PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u.freeze
- PRODUCT_SUFFIX = /\s*\**\((core|starter|premium|ultimate|free|bronze|silver|gold)(\s+(all|only|self|saas))?\)\**/.freeze
+ PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u
+ PRODUCT_SUFFIX = /\s*\**\((premium|ultimate|free|beta|experiment)(\s+(all|self|saas))?(\s+(beta|experiment))?\)\**/
def string_to_anchor(string)
string
diff --git a/lib/gitlab/utils/override.rb b/lib/gitlab/utils/override.rb
index 10370811bb5..9bc37746349 100644
--- a/lib/gitlab/utils/override.rb
+++ b/lib/gitlab/utils/override.rb
@@ -3,6 +3,9 @@
require 'gitlab/utils/all'
require_relative '../environment'
+# See https://docs.gitlab.com/ee/development/utilities.html#override for
+# more information
+
module Gitlab
module Utils
module Override
diff --git a/lib/gitlab/utils/sanitize_node_link.rb b/lib/gitlab/utils/sanitize_node_link.rb
index 183741ff5f5..2723ef137c3 100644
--- a/lib/gitlab/utils/sanitize_node_link.rb
+++ b/lib/gitlab/utils/sanitize_node_link.rb
@@ -5,8 +5,8 @@ require_dependency 'gitlab/utils'
module Gitlab
module Utils
module SanitizeNodeLink
- UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze
- ATTRS_TO_SANITIZE = %w(href src data-src data-canonical-src).freeze
+ UNSAFE_PROTOCOLS = %w[data javascript vbscript].freeze
+ ATTRS_TO_SANITIZE = %w[href src data-src data-canonical-src].freeze
# sanitize 6.0 requires only a context argument. Do not add any default
# arguments to this method.
diff --git a/lib/gitlab/uuid.rb b/lib/gitlab/uuid.rb
index a3abe90a412..9087e20bbb8 100644
--- a/lib/gitlab/uuid.rb
+++ b/lib/gitlab/uuid.rb
@@ -9,7 +9,7 @@ module Gitlab
production: "58dc0f06-936c-43b3-93bb-71693f1b6570"
}.freeze
- UUID_V5_PATTERN = /\h{8}-\h{4}-5\h{3}-\h{4}-\h{12}/.freeze
+ UUID_V5_PATTERN = /\h{8}-\h{4}-5\h{3}-\h{4}-\h{12}/
class << self
def v5(name, namespace_id: default_namespace_id)
diff --git a/lib/gitlab/web_hooks/rate_limiter.rb b/lib/gitlab/web_hooks/rate_limiter.rb
index 73d59f6f786..e68e97a29c5 100644
--- a/lib/gitlab/web_hooks/rate_limiter.rb
+++ b/lib/gitlab/web_hooks/rate_limiter.rb
@@ -9,7 +9,7 @@ module Gitlab
NO_LIMIT = 0
# SystemHooks (instance admin hooks) and ServiceHooks (integration hooks)
# are not rate-limited.
- EXCLUDED_HOOK_TYPES = %w(SystemHook ServiceHook).freeze
+ EXCLUDED_HOOK_TYPES = %w[SystemHook ServiceHook].freeze
def initialize(hook)
@hook = hook
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 79131404465..d19dd6cd856 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -15,7 +15,7 @@ module Gitlab
NOTIFICATION_PREFIX = 'workhorse:notifications:'
ALLOWED_GIT_HTTP_ACTIONS = %w[git_receive_pack git_upload_pack info_refs].freeze
DETECT_HEADER = 'Gitlab-Workhorse-Detect-Content-Type'
- ARCHIVE_FORMATS = %w(zip tar.gz tar.bz2 tar).freeze
+ ARCHIVE_FORMATS = %w[zip tar.gz tar.bz2 tar].freeze
include JwtAuthenticatable
@@ -184,11 +184,17 @@ module Gitlab
]
end
- def send_dependency(headers, url)
+ def send_dependency(headers, url, upload_config: {})
params = {
- 'Header' => headers,
- 'Url' => url
+ 'Headers' => headers.transform_values { |v| Array.wrap(v) },
+ 'Url' => url,
+ 'UploadConfig' => {
+ 'Method' => upload_config[:method],
+ 'Url' => upload_config[:url],
+ 'Headers' => (upload_config[:headers] || {}).transform_values { |v| Array.wrap(v) }
+ }.compact_blank!
}
+ params.compact_blank!
[
SEND_DATA_HEADER,
@@ -227,8 +233,12 @@ module Gitlab
Gitlab.config.workhorse.secret_file
end
+ def cleanup_key(key)
+ with_redis { |redis| redis.del(key) }
+ end
+
def set_key_and_notify(key, value, expire: nil, overwrite: true)
- Gitlab::Redis::SharedState.with do |redis|
+ with_redis do |redis|
result = redis.set(key, value, ex: expire, nx: !overwrite)
if result
redis.publish(NOTIFICATION_PREFIX + key, value)
@@ -249,6 +259,15 @@ module Gitlab
protected
+ def with_redis(&blk)
+ if Feature.enabled?(:use_primary_and_secondary_stores_for_workhorse) ||
+ Feature.enabled?(:use_primary_store_as_default_for_workhorse)
+ Gitlab::Redis::Workhorse.with(&blk) # rubocop:disable CodeReuse/ActiveRecord
+ else
+ Gitlab::Redis::SharedState.with(&blk) # rubocop:disable CodeReuse/ActiveRecord
+ end
+ end
+
# This is the outermost encoding of a senddata: header. It is safe for
# inclusion in HTTP response headers
def encode(hash)
diff --git a/lib/gitlab/x509/certificate.rb b/lib/gitlab/x509/certificate.rb
index 98688f504eb..e1ba5cdac7d 100644
--- a/lib/gitlab/x509/certificate.rb
+++ b/lib/gitlab/x509/certificate.rb
@@ -3,7 +3,7 @@
module Gitlab
module X509
class Certificate
- CERT_REGEX = /-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/.freeze
+ CERT_REGEX = /-----BEGIN CERTIFICATE-----(?:.|\n)+?-----END CERTIFICATE-----/
attr_reader :key, :cert, :ca_certs
diff --git a/lib/gitlab/x509/signature.rb b/lib/gitlab/x509/signature.rb
index 649e5379927..74d861c8701 100644
--- a/lib/gitlab/x509/signature.rb
+++ b/lib/gitlab/x509/signature.rb
@@ -39,6 +39,8 @@ module Gitlab
return :unverified if
x509_certificate.nil? ||
x509_certificate.revoked? ||
+ certificate_subject.nil? ||
+ certificate_crl.nil? ||
!verified_signature ||
signed_by_user.nil?
@@ -127,6 +129,7 @@ module Gitlab
def certificate_crl
extension = get_certificate_extension('crlDistributionPoints')
+
return if extension.nil?
crl_url = nil
@@ -185,7 +188,7 @@ module Gitlab
end
def x509_issuer
- return if verified_signature.nil? || issuer_subject_key_identifier.nil? || certificate_crl.nil?
+ return if verified_signature.nil? || issuer_subject_key_identifier.nil? || certificate_issuer.nil?
attributes = {
subject_key_identifier: issuer_subject_key_identifier,
diff --git a/lib/gitlab/zoom_link_extractor.rb b/lib/gitlab/zoom_link_extractor.rb
index 7ac14eb2d4f..92b3d6d5d3c 100644
--- a/lib/gitlab/zoom_link_extractor.rb
+++ b/lib/gitlab/zoom_link_extractor.rb
@@ -8,7 +8,7 @@
module Gitlab
class ZoomLinkExtractor
- ZOOM_REGEXP = %r{https://(?:[\w-]+\.)?zoom\.us/(?:s|j|my)/\S+}.freeze
+ ZOOM_REGEXP = %r{https://(?:[\w-]+\.)?zoom\.us/(?:s|j|my)/\S+}
def initialize(text)
@text = text.to_s
diff --git a/lib/grafana/validator.rb b/lib/grafana/validator.rb
index 616bb6aaaf0..a6386a39394 100644
--- a/lib/grafana/validator.rb
+++ b/lib/grafana/validator.rb
@@ -9,13 +9,13 @@ module Grafana
attr_reader :grafana_dashboard, :datasource, :panel, :query_params
- UNSUPPORTED_GRAFANA_GLOBAL_VARS = %w(
+ UNSUPPORTED_GRAFANA_GLOBAL_VARS = %w[
$__interval_ms
$__timeFilter
$__name
$timeFilter
$interval
- ).freeze
+ ].freeze
def initialize(grafana_dashboard, datasource, panel, query_params)
@grafana_dashboard = grafana_dashboard
diff --git a/lib/omni_auth/strategies/jwt.rb b/lib/omni_auth/strategies/jwt.rb
index 2f3d477a591..68d11fdd6d5 100644
--- a/lib/omni_auth/strategies/jwt.rb
+++ b/lib/omni_auth/strategies/jwt.rb
@@ -16,7 +16,7 @@ module OmniAuth
option :secret, nil
option :algorithm, 'HS256'
option :uid_claim, 'email'
- option :required_claims, %w(name email)
+ option :required_claims, %w[name email]
option :info_map, { name: "name", email: "email" }
option :auth_url, nil
option :valid_within, nil
@@ -44,7 +44,7 @@ module OmniAuth
OpenSSL::PKey::RSA.new(options.secret).public_key
when *%w[ES256 ES384 ES512]
OpenSSL::PKey::EC.new(options.secret).tap { |key| key.private_key = nil }
- when *%w(HS256 HS384 HS512)
+ when *%w[HS256 HS384 HS512]
options.secret
else
raise NotImplementedError, "Unsupported algorithm: #{options.algorithm}"
diff --git a/lib/peek/views/click_house.rb b/lib/peek/views/click_house.rb
index cc109ccea51..97f02ad3dab 100644
--- a/lib/peek/views/click_house.rb
+++ b/lib/peek/views/click_house.rb
@@ -39,7 +39,7 @@ module Peek
{
start: start,
duration: finish - start,
- sql: data[:query].strip,
+ sql: data[:query].to_sql.strip,
backtrace: Gitlab::BacktraceCleaner.clean_backtrace(caller),
database: "database: #{data[:database]}",
statistics: "query stats: #{data[:statistics]}"
diff --git a/lib/quality/seeders/issues.rb b/lib/quality/seeders/issues.rb
index fb3d78bc8d2..813ff0bf097 100644
--- a/lib/quality/seeders/issues.rb
+++ b/lib/quality/seeders/issues.rb
@@ -5,7 +5,7 @@ module Quality
module Seeders
class Issues
DEFAULT_BACKFILL_WEEKS = 52
- DEFAULT_AVERAGE_ISSUES_PER_WEEK = 10
+ DEFAULT_AVERAGE_ISSUES_PER_WEEK = 20
attr_reader :project, :user
@@ -14,23 +14,27 @@ module Quality
end
def seed(backfill_weeks: DEFAULT_BACKFILL_WEEKS, average_issues_per_week: DEFAULT_AVERAGE_ISSUES_PER_WEEK)
+ create_milestones!
+ create_team_members!
+
created_at = backfill_weeks.to_i.weeks.ago
team = project.team.users
created_issues_count = 0
loop do
- rand(average_issues_per_week * 2).times do
+ rand(1..average_issues_per_week).times do
params = {
title: FFaker::Lorem.sentence(6),
description: FFaker::Lorem.sentence,
created_at: created_at + rand(6).days,
state: %w[opened closed].sample,
- milestone: project.milestones.sample,
- assignee_ids: Array(team.pluck(:id).sample(3)),
+ milestone_id: project.milestones.sample&.id,
+ assignee_ids: Array(team.pluck(:id).sample(rand(3))),
+ due_date: rand(10).days.from_now,
labels: labels.join(',')
- }
- params[:closed_at] = params[:created_at] + rand(35).days if params[:state] == 'closed'
+ }.merge(additional_params)
+ params[:closed_at] = params[:created_at] + rand(35).days if params[:state] == 'closed'
create_result = ::Issues::CreateService.new(container: project, current_user: team.sample, params: params, perform_spam_check: false).execute_without_rate_limiting
if create_result.success?
@@ -49,6 +53,49 @@ module Quality
private
+ # Overriden on Quality::Seeders::Insights::Issues
+ def additional_params
+ {}
+ end
+
+ def create_team_members!
+ 3.times do |i|
+ user = FactoryBot.create(
+ :user,
+ name: "I User#{i}",
+ username: "i-user-#{i}-#{suffix}",
+ email: "i-user-#{i}@#{suffix}.com"
+ )
+
+ # need owner access to allow changing Issue#created_at
+ project.add_owner(user)
+ end
+
+ Sidekiq::Worker.skipping_transaction_check do
+ AuthorizedProjectUpdate::ProjectRecalculateService.new(project).execute
+ end
+
+ # Refind object toreload ProjectTeam association which is memoized at Project model
+ @project = Project.find(project.id)
+ end
+
+ def create_milestones!
+ 3.times do |i|
+ params = {
+ project: project,
+ title: "Sprint #{i + suffix}",
+ description: FFaker::Lorem.sentence,
+ state: [:active, :closed].sample
+ }
+
+ FactoryBot.create(:milestone, **params)
+ end
+ end
+
+ def suffix
+ @suffix ||= Time.now.to_i
+ end
+
def labels
@labels_pool ||= project.labels.limit(rand(3)).pluck(:title).tap do |labels_array|
labels_array.concat(project.group.labels.limit(rand(3)).pluck(:title)) if project.group
diff --git a/lib/release_highlights/validator/entry.rb b/lib/release_highlights/validator/entry.rb
index fc9ce3a3fd0..9968f7ca33a 100644
--- a/lib/release_highlights/validator/entry.rb
+++ b/lib/release_highlights/validator/entry.rb
@@ -5,7 +5,7 @@ module ReleaseHighlights
include ActiveModel::Validations
include ActiveModel::Validations::Callbacks
- AVAILABLE_IN = %w(Free Premium Ultimate).freeze
+ AVAILABLE_IN = %w[Free Premium Ultimate].freeze
HYPHENATED_ATTRIBUTES = [:self_managed, :gitlab_com].freeze
attr_reader :entry
diff --git a/lib/sbom/package_url/argument_validator.rb b/lib/sbom/package_url/argument_validator.rb
index 639ee9f89b6..da761270950 100644
--- a/lib/sbom/package_url/argument_validator.rb
+++ b/lib/sbom/package_url/argument_validator.rb
@@ -3,8 +3,8 @@
module Sbom
class PackageUrl
class ArgumentValidator
- QUALIFIER_KEY_REGEXP = /^[A-Za-z\d._-]+$/.freeze
- START_WITH_NUMBER_REGEXP = /^\d/.freeze
+ QUALIFIER_KEY_REGEXP = /^[A-Za-z\d._-]+$/
+ START_WITH_NUMBER_REGEXP = /^\d/
def initialize(package)
@type = package.type
diff --git a/lib/security/ci_configuration/sast_build_action.rb b/lib/security/ci_configuration/sast_build_action.rb
index 2b1964f7c87..5ac23f29fe5 100644
--- a/lib/security/ci_configuration/sast_build_action.rb
+++ b/lib/security/ci_configuration/sast_build_action.rb
@@ -105,13 +105,13 @@ module Security
end
def global_variables
- %w(
+ %w[
SECURE_ANALYZERS_PREFIX
- )
+ ]
end
def sast_variables
- %w(
+ %w[
SAST_EXCLUDED_PATHS
SEARCH_MAX_DEPTH
SAST_EXCLUDED_ANALYZERS
@@ -119,7 +119,7 @@ module Security
SAST_BANDIT_EXCLUDED_PATHS
SAST_FLAWFINDER_LEVEL
SAST_GOSEC_LEVEL
- )
+ ]
end
end
end
diff --git a/lib/sidebars/admin/panel.rb b/lib/sidebars/admin/panel.rb
index 4f14c4ffb49..7f7d7ec843c 100644
--- a/lib/sidebars/admin/panel.rb
+++ b/lib/sidebars/admin/panel.rb
@@ -21,10 +21,7 @@ module Sidebars
override :super_sidebar_context_header
def super_sidebar_context_header
- @super_sidebar_context_header ||= {
- title: aria_label,
- icon: 'admin'
- }
+ aria_label
end
def add_menus
diff --git a/lib/sidebars/concerns/has_avatar.rb b/lib/sidebars/concerns/has_avatar.rb
new file mode 100644
index 00000000000..71eb8172bf4
--- /dev/null
+++ b/lib/sidebars/concerns/has_avatar.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# This module has the necessary methods to show
+# avatars next to the menu item.
+module Sidebars
+ module Concerns
+ module HasAvatar
+ def avatar
+ nil
+ end
+
+ def avatar_shape
+ 'rect'
+ end
+
+ def entity_id
+ nil
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/explore/panel.rb b/lib/sidebars/explore/panel.rb
index 9a585a99705..6260df6bb5f 100644
--- a/lib/sidebars/explore/panel.rb
+++ b/lib/sidebars/explore/panel.rb
@@ -20,10 +20,7 @@ module Sidebars
override :super_sidebar_context_header
def super_sidebar_context_header
- {
- title: aria_label,
- icon: 'compass'
- }
+ aria_label
end
private
diff --git a/lib/sidebars/groups/menus/packages_registries_menu.rb b/lib/sidebars/groups/menus/packages_registries_menu.rb
index b2d6aec1a78..19a6e210231 100644
--- a/lib/sidebars/groups/menus/packages_registries_menu.rb
+++ b/lib/sidebars/groups/menus/packages_registries_menu.rb
@@ -57,8 +57,7 @@ module Sidebars
end
def harbor_registry_menu_item
- if Feature.disabled?(:harbor_registry_integration) ||
- context.group.harbor_integration.nil? ||
+ if context.group.harbor_integration.nil? ||
!context.group.harbor_integration.activated?
return nil_menu_item(:harbor_registry)
end
diff --git a/lib/sidebars/groups/menus/scope_menu.rb b/lib/sidebars/groups/menus/scope_menu.rb
index 5505f56a6d3..5f6663e9919 100644
--- a/lib/sidebars/groups/menus/scope_menu.rb
+++ b/lib/sidebars/groups/menus/scope_menu.rb
@@ -36,8 +36,8 @@ module Sidebars
override :serialize_as_menu_item_args
def serialize_as_menu_item_args
super.merge({
- title: _('Group overview'),
- sprite_icon: 'group',
+ avatar: context.group.avatar_url,
+ entity_id: context.group.id,
super_sidebar_parent: ::Sidebars::StaticMenu,
item_id: :group_overview
})
diff --git a/lib/sidebars/groups/super_sidebar_panel.rb b/lib/sidebars/groups/super_sidebar_panel.rb
index 1f79dff398e..01c6f88dcc0 100644
--- a/lib/sidebars/groups/super_sidebar_panel.rb
+++ b/lib/sidebars/groups/super_sidebar_panel.rb
@@ -35,11 +35,7 @@ module Sidebars
override :super_sidebar_context_header
def super_sidebar_context_header
- {
- title: context.group.name,
- avatar: context.group.avatar_url,
- id: context.group.id
- }
+ _('Group')
end
end
end
diff --git a/lib/sidebars/menu.rb b/lib/sidebars/menu.rb
index 73d6f733da5..ee02429baf3 100644
--- a/lib/sidebars/menu.rb
+++ b/lib/sidebars/menu.rb
@@ -8,6 +8,7 @@ module Sidebars
include Gitlab::Allowable
include ::Sidebars::Concerns::HasPill
include ::Sidebars::Concerns::HasIcon
+ include ::Sidebars::Concerns::HasAvatar
include ::Sidebars::Concerns::PositionableList
include ::Sidebars::Concerns::Renderable
include ::Sidebars::Concerns::ContainerWithHtmlOptions
@@ -81,6 +82,9 @@ module Sidebars
{
title: title,
icon: sprite_icon,
+ avatar: avatar,
+ avatar_shape: avatar_shape,
+ entity_id: entity_id,
link: link,
is_active: is_active,
pill_count: has_pill? ? pill_count : nil,
diff --git a/lib/sidebars/menu_item.rb b/lib/sidebars/menu_item.rb
index 227a6970b2c..bd538d2fa90 100644
--- a/lib/sidebars/menu_item.rb
+++ b/lib/sidebars/menu_item.rb
@@ -4,11 +4,11 @@ module Sidebars
class MenuItem
include ::Sidebars::Concerns::LinkWithHtmlOptions
- attr_reader :title, :link, :active_routes, :item_id, :container_html_options, :sprite_icon, :sprite_icon_html_options, :hint_html_options, :has_pill, :pill_count, :super_sidebar_parent
+ attr_reader :title, :link, :active_routes, :item_id, :container_html_options, :sprite_icon, :sprite_icon_html_options, :hint_html_options, :has_pill, :pill_count, :super_sidebar_parent, :avatar, :entity_id
alias_method :has_pill?, :has_pill
# rubocop: disable Metrics/ParameterLists
- def initialize(title:, link:, active_routes:, item_id: nil, container_html_options: {}, sprite_icon: nil, sprite_icon_html_options: {}, hint_html_options: {}, has_pill: false, pill_count: nil, super_sidebar_parent: nil)
+ def initialize(title:, link:, active_routes:, item_id: nil, container_html_options: {}, sprite_icon: nil, sprite_icon_html_options: {}, hint_html_options: {}, has_pill: false, pill_count: nil, super_sidebar_parent: nil, avatar: nil, entity_id: nil)
@title = title
@link = link
@active_routes = active_routes
@@ -16,6 +16,8 @@ module Sidebars
@container_html_options = { aria: { label: title } }.merge(container_html_options)
@sprite_icon = sprite_icon
@sprite_icon_html_options = sprite_icon_html_options
+ @avatar = avatar
+ @entity_id = entity_id
@hint_html_options = hint_html_options
@has_pill = has_pill
@pill_count = pill_count
@@ -36,6 +38,8 @@ module Sidebars
id: item_id,
title: title,
icon: sprite_icon,
+ avatar: avatar,
+ entity_id: entity_id,
link: link,
active_routes: active_routes,
pill_count: has_pill ? pill_count : nil,
diff --git a/lib/sidebars/organizations/menus/scope_menu.rb b/lib/sidebars/organizations/menus/scope_menu.rb
index 86f0a083731..ba46dd7911f 100644
--- a/lib/sidebars/organizations/menus/scope_menu.rb
+++ b/lib/sidebars/organizations/menus/scope_menu.rb
@@ -34,8 +34,8 @@ module Sidebars
override :serialize_as_menu_item_args
def serialize_as_menu_item_args
super.merge({
- title: s_('Organization|Organization overview'),
- sprite_icon: 'organization',
+ avatar: nil,
+ entity_id: context.container.id,
super_sidebar_parent: ::Sidebars::StaticMenu,
item_id: :organization_overview
})
diff --git a/lib/sidebars/organizations/super_sidebar_panel.rb b/lib/sidebars/organizations/super_sidebar_panel.rb
index acc3d9a0ddf..f7b5c50bb05 100644
--- a/lib/sidebars/organizations/super_sidebar_panel.rb
+++ b/lib/sidebars/organizations/super_sidebar_panel.rb
@@ -23,10 +23,7 @@ module Sidebars
override :super_sidebar_context_header
def super_sidebar_context_header
- {
- title: context.container.name,
- id: context.container.id
- }
+ _('Organization')
end
end
end
diff --git a/lib/sidebars/panel.rb b/lib/sidebars/panel.rb
index 4c0d4caf81e..518b13f0fae 100644
--- a/lib/sidebars/panel.rb
+++ b/lib/sidebars/panel.rb
@@ -52,7 +52,7 @@ module Sidebars
raise NotImplementedError
end
- def has_renderable_menus?
+ def render?
renderable_menus.any?
end
diff --git a/lib/sidebars/projects/menus/issues_menu.rb b/lib/sidebars/projects/menus/issues_menu.rb
index dc40b84529f..e599b764ed9 100644
--- a/lib/sidebars/projects/menus/issues_menu.rb
+++ b/lib/sidebars/projects/menus/issues_menu.rb
@@ -44,7 +44,7 @@ module Sidebars
override :active_routes
def active_routes
- { controller: 'projects/issues' }
+ { path: %w[projects/issues#index projects/issues#show projects/issues#new] }
end
override :has_pill?
diff --git a/lib/sidebars/projects/menus/monitor_menu.rb b/lib/sidebars/projects/menus/monitor_menu.rb
index 87b09e42fe1..a74448d0bdc 100644
--- a/lib/sidebars/projects/menus/monitor_menu.rb
+++ b/lib/sidebars/projects/menus/monitor_menu.rb
@@ -8,7 +8,6 @@ module Sidebars
def configure_menu_items
return false unless feature_enabled?
- add_item(tracing_menu_item)
add_item(error_tracking_menu_item)
add_item(alert_management_menu_item)
add_item(incidents_menu_item)
@@ -63,20 +62,6 @@ module Sidebars
)
end
- def tracing_menu_item
- unless Gitlab::Observability.tracing_enabled?(context.project)
- return ::Sidebars::NilMenuItem.new(item_id: :tracing)
- end
-
- ::Sidebars::MenuItem.new(
- title: _('Tracing'),
- link: project_tracing_index_path(context.project),
- super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::MonitorMenu,
- active_routes: { controller: :tracing },
- item_id: :tracing
- )
- end
-
def alert_management_menu_item
unless can?(context.current_user, :read_alert_management_alert, context.project)
return ::Sidebars::NilMenuItem.new(item_id: :alert_management)
diff --git a/lib/sidebars/projects/menus/packages_registries_menu.rb b/lib/sidebars/projects/menus/packages_registries_menu.rb
index 053ce5e82fd..5a378d5f9a8 100644
--- a/lib/sidebars/projects/menus/packages_registries_menu.rb
+++ b/lib/sidebars/projects/menus/packages_registries_menu.rb
@@ -75,8 +75,7 @@ module Sidebars
end
def harbor_registry_menu_item
- if Feature.disabled?(:harbor_registry_integration, context.project) ||
- context.project.harbor_integration.nil? ||
+ if context.project.harbor_integration.nil? ||
!context.project.harbor_integration.activated?
return ::Sidebars::NilMenuItem.new(item_id: :harbor_registry)
end
diff --git a/lib/sidebars/projects/menus/repository_menu.rb b/lib/sidebars/projects/menus/repository_menu.rb
index 22f7b553884..259e3285338 100644
--- a/lib/sidebars/projects/menus/repository_menu.rb
+++ b/lib/sidebars/projects/menus/repository_menu.rb
@@ -69,7 +69,7 @@ module Sidebars
title: _('Commits'),
link: link,
super_sidebar_parent: ::Sidebars::Projects::SuperSidebarMenus::CodeMenu,
- active_routes: { controller: %w(commit commits) },
+ active_routes: { controller: %w[commit commits] },
item_id: :commits,
container_html_options: { id: 'js-onboarding-commits-link', class: 'shortcuts-commits' }
)
diff --git a/lib/sidebars/projects/menus/scope_menu.rb b/lib/sidebars/projects/menus/scope_menu.rb
index 7e2286633e5..f388c814bd7 100644
--- a/lib/sidebars/projects/menus/scope_menu.rb
+++ b/lib/sidebars/projects/menus/scope_menu.rb
@@ -43,8 +43,8 @@ module Sidebars
override :serialize_as_menu_item_args
def serialize_as_menu_item_args
super.merge({
- title: _('Project overview'),
- sprite_icon: 'project',
+ avatar: context.project.avatar_url,
+ entity_id: context.project.id,
super_sidebar_parent: ::Sidebars::StaticMenu,
item_id: :project_overview
})
diff --git a/lib/sidebars/projects/super_sidebar_panel.rb b/lib/sidebars/projects/super_sidebar_panel.rb
index e9de4c2d92c..57959318582 100644
--- a/lib/sidebars/projects/super_sidebar_panel.rb
+++ b/lib/sidebars/projects/super_sidebar_panel.rb
@@ -37,11 +37,7 @@ module Sidebars
override :super_sidebar_context_header
def super_sidebar_context_header
- {
- title: context.project.name,
- avatar: context.project.avatar_url,
- id: context.project.id
- }
+ _('Project')
end
end
end
diff --git a/lib/sidebars/search/panel.rb b/lib/sidebars/search/panel.rb
index 83079fa8e72..014d45a0845 100644
--- a/lib/sidebars/search/panel.rb
+++ b/lib/sidebars/search/panel.rb
@@ -8,12 +8,17 @@ module Sidebars
_('Search results')
end
+ # The Search Panel is a special candidate and renderable,
+ # even though it has no backend-defined menus.
+ # It will receive it's menu items in the frontend
+ override :render?
+ def render?
+ true
+ end
+
override :super_sidebar_context_header
def super_sidebar_context_header
- @super_sidebar_context_header ||= {
- title: aria_label,
- icon: 'search-results'
- }
+ aria_label
end
end
end
diff --git a/lib/sidebars/user_profile/menus/overview_menu.rb b/lib/sidebars/user_profile/menus/overview_menu.rb
index e9fa515e9bc..598f8b2d052 100644
--- a/lib/sidebars/user_profile/menus/overview_menu.rb
+++ b/lib/sidebars/user_profile/menus/overview_menu.rb
@@ -4,25 +4,49 @@ module Sidebars
module UserProfile
module Menus
class OverviewMenu < ::Sidebars::UserProfile::BaseMenu
+ include UsersHelper
+
override :link
def link
- user_path(context.container)
+ user_path(user)
end
override :title
def title
- s_('UserProfile|Overview')
+ user_name
+ end
+
+ override :avatar
+ def avatar
+ user.avatar_url
end
- override :sprite_icon
- def sprite_icon
- 'overview'
+ override :avatar_shape
+ def avatar_shape
+ 'circle'
+ end
+
+ override :entity_id
+ def entity_id
+ user.id
end
override :active_routes
def active_routes
{ path: 'users#show' }
end
+
+ private
+
+ def user
+ context.container
+ end
+
+ def user_name
+ return user_display_name(user) if user.blocked? || !user.confirmed?
+
+ user.name
+ end
end
end
end
diff --git a/lib/sidebars/user_profile/panel.rb b/lib/sidebars/user_profile/panel.rb
index 1852ef928f4..b15538c698b 100644
--- a/lib/sidebars/user_profile/panel.rb
+++ b/lib/sidebars/user_profile/panel.rb
@@ -20,25 +20,11 @@ module Sidebars
override :super_sidebar_context_header
def super_sidebar_context_header
- @super_sidebar_context_header ||= {
- title: user_name,
- avatar: context.container.avatar_url,
- avatar_shape: 'circle'
- }
+ _('Profile')
end
private
- def user
- context.container
- end
-
- def user_name
- return user_display_name(user) if user.blocked? || !user.confirmed?
-
- user.name
- end
-
def add_menus
add_menu(Sidebars::UserProfile::Menus::OverviewMenu.new(context))
add_menu(Sidebars::UserProfile::Menus::ActivityMenu.new(context))
diff --git a/lib/sidebars/user_settings/panel.rb b/lib/sidebars/user_settings/panel.rb
index 683a0e34570..b61cb3ed144 100644
--- a/lib/sidebars/user_settings/panel.rb
+++ b/lib/sidebars/user_settings/panel.rb
@@ -20,15 +20,14 @@ module Sidebars
override :super_sidebar_context_header
def super_sidebar_context_header
- @super_sidebar_context_header ||= {
- title: aria_label,
- avatar: context.current_user.avatar_url
- }
+ aria_label
end
private
def add_menus
+ return unless context.current_user
+
add_menu(Sidebars::UserSettings::Menus::ProfileMenu.new(context))
add_menu(Sidebars::UserSettings::Menus::AccountMenu.new(context))
add_menu(Sidebars::UserSettings::Menus::ApplicationsMenu.new(context))
diff --git a/lib/sidebars/your_work/menus/organizations_menu.rb b/lib/sidebars/your_work/menus/organizations_menu.rb
new file mode 100644
index 00000000000..1e3d0297f22
--- /dev/null
+++ b/lib/sidebars/your_work/menus/organizations_menu.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module YourWork
+ module Menus
+ class OrganizationsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ organizations_path
+ end
+
+ override :title
+ def title
+ _('Organizations')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'organization'
+ end
+
+ override :render?
+ def render?
+ !!context.current_user && Feature.enabled?(:ui_for_organizations, context.current_user)
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: 'organizations/organizations', actions: %w[index new] }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/your_work/panel.rb b/lib/sidebars/your_work/panel.rb
index 5f917976872..6316023a8cb 100644
--- a/lib/sidebars/your_work/panel.rb
+++ b/lib/sidebars/your_work/panel.rb
@@ -20,17 +20,17 @@ module Sidebars
override :super_sidebar_context_header
def super_sidebar_context_header
- @super_sidebar_context_header ||= {
- title: aria_label,
- icon: 'work'
- }
+ aria_label
end
private
def add_menus
+ return unless context.current_user
+
add_menu(Sidebars::YourWork::Menus::ProjectsMenu.new(context))
add_menu(Sidebars::YourWork::Menus::GroupsMenu.new(context))
+ add_menu(Sidebars::YourWork::Menus::OrganizationsMenu.new(context))
add_menu(Sidebars::YourWork::Menus::IssuesMenu.new(context))
add_menu(Sidebars::YourWork::Menus::MergeRequestsMenu.new(context))
add_menu(Sidebars::YourWork::Menus::TodosMenu.new(context))
diff --git a/lib/system_check/app/migrations_are_up_check.rb b/lib/system_check/app/migrations_are_up_check.rb
index b12e9ac6bba..e248e03e5e0 100644
--- a/lib/system_check/app/migrations_are_up_check.rb
+++ b/lib/system_check/app/migrations_are_up_check.rb
@@ -6,7 +6,7 @@ module SystemCheck
set_name 'All migrations up?'
def check?
- migration_status, _ = Gitlab::Popen.popen(%w(bundle exec rake db:migrate:status))
+ migration_status, _ = Gitlab::Popen.popen(%w[bundle exec rake db:migrate:status])
migration_status !~ /down\s+\d{14}/
end
diff --git a/lib/system_check/app/table_truncate_check.rb b/lib/system_check/app/table_truncate_check.rb
new file mode 100644
index 00000000000..57b5950c21d
--- /dev/null
+++ b/lib/system_check/app/table_truncate_check.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module SystemCheck
+ module App
+ class TableTruncateCheck < SystemCheck::BaseCheck
+ set_name 'Tables are truncated?'
+
+ def skip?
+ Gitlab::Database.database_mode != Gitlab::Database::MODE_MULTIPLE_DATABASES
+ end
+
+ def check?
+ @rake_tasks = []
+ Gitlab::Database.database_base_models_with_gitlab_shared.keys.each_with_object({}) do |database_name, _h|
+ if Gitlab::Database::TablesTruncate.new(database_name: database_name).needs_truncation?
+ @rake_tasks << "gitlab:db:truncate_legacy_tables:#{database_name}"
+ end
+ end
+
+ @rake_tasks.empty?
+ end
+
+ def show_error
+ try_fixing_it(
+ sudo_gitlab("bundle exec rake #{@rake_tasks.join(' ')}")
+ )
+ for_more_information(
+ "doc/development/database/multiple_databases.md in section 'Truncating tables'"
+ )
+ fix_and_rerun
+ end
+ end
+ end
+end
diff --git a/lib/system_check/incoming_email/mail_room_running_check.rb b/lib/system_check/incoming_email/mail_room_running_check.rb
index 38bb1e46364..5235e4a9977 100644
--- a/lib/system_check/incoming_email/mail_room_running_check.rb
+++ b/lib/system_check/incoming_email/mail_room_running_check.rb
@@ -45,7 +45,7 @@ module SystemCheck
end
def mail_room_running?
- ps_ux, _ = Gitlab::Popen.popen(%w(ps uxww))
+ ps_ux, _ = Gitlab::Popen.popen(%w[ps uxww])
ps_ux.include?("mail_room")
end
end
diff --git a/lib/system_check/rake_task/app_task.rb b/lib/system_check/rake_task/app_task.rb
index 20332d4b24b..8e711138856 100644
--- a/lib/system_check/rake_task/app_task.rb
+++ b/lib/system_check/rake_task/app_task.rb
@@ -13,6 +13,7 @@ module SystemCheck
def self.checks
[
SystemCheck::App::DatabaseConfigExistsCheck,
+ SystemCheck::App::TableTruncateCheck,
SystemCheck::App::MigrationsAreUpCheck,
SystemCheck::App::OrphanedGroupMembersCheck,
SystemCheck::App::GitlabConfigExistsCheck,
diff --git a/lib/system_check/sidekiq_check.rb b/lib/system_check/sidekiq_check.rb
index 777e06f7501..f1e2566db29 100644
--- a/lib/system_check/sidekiq_check.rb
+++ b/lib/system_check/sidekiq_check.rb
@@ -60,12 +60,12 @@ module SystemCheck
end
def sidekiq_worker_process_count
- ps_ux, _ = Gitlab::Popen.popen(%w(ps uxww))
+ ps_ux, _ = Gitlab::Popen.popen(%w[ps uxww])
ps_ux.lines.grep(/sidekiq \d+\.\d+\.\d+/).count
end
def sidekiq_cluster_process_count
- ps_ux, _ = Gitlab::Popen.popen(%w(ps uxww))
+ ps_ux, _ = Gitlab::Popen.popen(%w[ps uxww])
ps_ux.lines.grep(/sidekiq-cluster/).count
end
end
diff --git a/lib/tasks/cleanup.rake b/lib/tasks/cleanup.rake
index c13da77217e..31695d3da79 100644
--- a/lib/tasks/cleanup.rake
+++ b/lib/tasks/cleanup.rake
@@ -10,7 +10,7 @@ namespace :gitlab do
Gitlab.config.repositories.storages.each do |name, repository_storage|
repo_root = repository_storage.legacy_disk_path.chomp('/')
# Look for global repos (legacy, depth 1) and normal repos (depth 2)
- IO.popen(%W(find #{repo_root} -mindepth 1 -maxdepth 2 -name *+moved*.git)) do |find|
+ IO.popen(%W[find #{repo_root} -mindepth 1 -maxdepth 2 -name *+moved*.git]) do |find|
find.each_line do |path|
path.chomp!
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index 546f5621515..cf52a219e83 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -258,6 +258,18 @@ namespace :gitlab do
end
end
+ def disabled_db_flags_note
+ return unless Feature.enabled?(:disallow_database_ddl_feature_flags, type: :ops)
+
+ puts <<~NOTE.color(:yellow)
+ Note: disallow_database_ddl_feature_flags feature is currently enabled. Disable it to proceed.
+
+ Disable with: Feature.disable(:disallow_database_ddl_feature_flags)
+ NOTE
+
+ yield if block_given?
+ end
+
desc 'Enqueue an index for reindexing'
task :enqueue_reindexing_action, [:index_name, :database] => :environment do |_, args|
model = Gitlab::Database.database_base_models[args.fetch(:database, Gitlab::Database::PRIMARY_DATABASE_NAME)]
@@ -269,7 +281,9 @@ namespace :gitlab do
puts "There are #{Gitlab::Database::Reindexing::QueuedAction.queued.size} queued actions in total."
end
- unless Feature.enabled?(:database_reindexing, type: :ops)
+ disabled_db_flags_note
+
+ if Feature.disabled?(:database_reindexing, type: :ops)
puts <<~NOTE.color(:yellow)
Note: database_reindexing feature is currently disabled.
@@ -283,6 +297,8 @@ namespace :gitlab do
task database_name, [:pick] => :environment do |_, args|
args.with_defaults(pick: 2)
+ disabled_db_flags_note { exit }
+
if Feature.disabled?(:database_async_index_operations, type: :ops)
puts <<~NOTE.color(:yellow)
Note: database async index operations feature is currently disabled.
@@ -313,6 +329,8 @@ namespace :gitlab do
task database_name, [:pick] => :environment do |_, args|
args.with_defaults(pick: 2)
+ disabled_db_flags_note { exit }
+
if Feature.disabled?(:database_async_foreign_key_validation, type: :ops)
puts <<~NOTE.color(:yellow)
Note: database async foreign key validation feature is currently disabled.
diff --git a/lib/tasks/gitlab/generate_sample_prometheus_data.rake b/lib/tasks/gitlab/generate_sample_prometheus_data.rake
deleted file mode 100644
index 4cd75af9d00..00000000000
--- a/lib/tasks/gitlab/generate_sample_prometheus_data.rake
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-namespace :gitlab do
- desc "GitLab | Generate Sample Prometheus Data"
- task :generate_sample_prometheus_data, [:environment_id] => :gitlab_environment do |_, args|
- environment = Environment.find(args[:environment_id])
- metrics = PrometheusMetric.where(project_id: [environment.project.id, nil])
- query_variables = Gitlab::Prometheus::QueryVariables.call(environment)
-
- sample_metrics_directory_name = Metrics::SampleMetricsService::DIRECTORY
- FileUtils.mkdir_p(sample_metrics_directory_name)
-
- sample_metrics_intervals = [30.minutes, 180.minutes, 8.hours, 24.hours, 72.hours, 7.days]
-
- metrics.each do |metric|
- query = metric.query % query_variables
-
- next unless metric.identifier
-
- result = sample_metrics_intervals.each_with_object({}) do |interval, memo|
- memo[interval.to_i / 60] = environment.prometheus_adapter.prometheus_client.query_range(query, start: interval.ago)
- end
-
- File.write("#{sample_metrics_directory_name}/#{metric.identifier}.yml", result.to_yaml)
- end
- end
-end
diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake
index 26ffe2c3f7b..9752a6c0886 100644
--- a/lib/tasks/gitlab/info.rake
+++ b/lib/tasks/gitlab/info.rake
@@ -5,17 +5,17 @@ namespace :gitlab do
desc 'GitLab | Env | Show information about GitLab and its environment'
task info: :gitlab_environment do
# check if there is an RVM environment
- rvm_version = run_and_match(%w(rvm --version), /[\d\.]+/).try(:to_s)
+ rvm_version = run_and_match(%w[rvm --version], /[\d\.]+/).try(:to_s)
# check Ruby version
- ruby_version = run_and_match(%w(ruby --version), /[\d\.p]+/).try(:to_s)
+ ruby_version = run_and_match(%w[ruby --version], /[\d\.p]+/).try(:to_s)
# check Gem version
- gem_version = run_command(%w(gem --version))
+ gem_version = run_command(%w[gem --version])
# check Bundler version
- bunder_version = run_and_match(%w(bundle --version), /[\d\.]+/).try(:to_s)
+ bunder_version = run_and_match(%w[bundle --version], /[\d\.]+/).try(:to_s)
# check Rake version
- rake_version = run_and_match(%w(rake --version), /[\d\.]+/).try(:to_s)
+ rake_version = run_and_match(%w[rake --version], /[\d\.]+/).try(:to_s)
# check redis version
- redis_version = run_and_match(%w(redis-cli --version), /redis-cli (\d+\.\d+\.\d+)/).to_a
+ redis_version = run_and_match(%w[redis-cli --version], /redis-cli (\d+\.\d+\.\d+)/).to_a
# check for system defined proxies
if Gitlab.ee?
@@ -23,7 +23,7 @@ namespace :gitlab do
end
# check Go version
- go_version = run_and_match(%w(go version), /go version (.+)/).to_a
+ go_version = run_and_match(%w[go version], /go version (.+)/).to_a
puts ""
puts "System information".color(:yellow)
@@ -33,7 +33,7 @@ namespace :gitlab do
puts "Proxy:\t\t#{proxies.present? ? proxies.color(:green) : "no"}"
end
- puts "Current User:\t#{run_command(%w(whoami))}"
+ puts "Current User:\t#{run_command(%w[whoami])}"
puts "Using RVM:\t#{rvm_version.present? ? "yes".color(:green) : "no"}"
puts "RVM Version:\t#{rvm_version}" if rvm_version.present?
puts "Ruby Version:\t#{ruby_version || "unknown".color(:red)}"
diff --git a/lib/tasks/gitlab/list_repos.rake b/lib/tasks/gitlab/list_repos.rake
index 56ec94d2aef..c0929466b7c 100644
--- a/lib/tasks/gitlab/list_repos.rake
+++ b/lib/tasks/gitlab/list_repos.rake
@@ -2,6 +2,9 @@
namespace :gitlab do
task list_repos: :environment do
+ warn "The Rake task gitlab:list_repos is deprecated in 16.4 and will be removed in 17.0: " \
+ "https://gitlab.com/gitlab-org/gitlab/-/issues/384361"
+
scope = Project
if ENV['SINCE']
date = Time.parse(ENV['SINCE'])
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index 8b305d68c68..23a518564e1 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -30,8 +30,8 @@ namespace :gitlab do
File.open("config.yml", "w+") { |f| f.puts config.to_yaml }
[
- %w(bin/install) + repository_storage_paths_args,
- %w(make build)
+ %w[bin/install] + repository_storage_paths_args,
+ %w[make build]
].each do |cmd|
unless Kernel.system(*cmd)
raise "command failed: #{cmd.join(' ')}"
diff --git a/lib/tasks/gitlab/update_templates.rake b/lib/tasks/gitlab/update_templates.rake
index e87f478ac42..b2a255ca765 100644
--- a/lib/tasks/gitlab/update_templates.rake
+++ b/lib/tasks/gitlab/update_templates.rake
@@ -82,9 +82,9 @@ namespace :gitlab do
Gitlab::TaskHelpers.run_command!(['tar', 'xf', 'archive.tar.gz'])
extracted_project_basename = Dir['*/'].first
Dir.chdir(extracted_project_basename) do
- Gitlab::TaskHelpers.run_command!(%w(git init --initial-branch=master))
- Gitlab::TaskHelpers.run_command!(%W(git remote add origin #{local_remote}))
- Gitlab::TaskHelpers.run_command!(%w(git add .))
+ Gitlab::TaskHelpers.run_command!(%w[git init --initial-branch=master])
+ Gitlab::TaskHelpers.run_command!(%W[git remote add origin #{local_remote}])
+ Gitlab::TaskHelpers.run_command!(%w[git add .])
Gitlab::TaskHelpers.run_command!(['git', 'commit', '--author', 'GitLab <root@localhost>', '--message', commit_message])
Gitlab::TaskHelpers.run_command!(['git', 'push', '-u', 'origin', 'master'])
end
diff --git a/lib/tasks/tanuki_emoji.rake b/lib/tasks/tanuki_emoji.rake
index de2ae656952..b3099853434 100644
--- a/lib/tasks/tanuki_emoji.rake
+++ b/lib/tasks/tanuki_emoji.rake
@@ -139,7 +139,7 @@ namespace :tanuki_emoji do
puts "\n"
- style_path = Rails.root.join(*%w(app assets stylesheets emoji_sprites.scss))
+ style_path = Rails.root.join(*%w[app assets stylesheets emoji_sprites.scss])
print 'Compiling sprites regular sprites... '
diff --git a/lib/users/internal.rb b/lib/users/internal.rb
new file mode 100644
index 00000000000..30ef20dbd7b
--- /dev/null
+++ b/lib/users/internal.rb
@@ -0,0 +1,151 @@
+# frozen_string_literal: true
+
+module Users
+ class Internal
+ class << self
+ # rubocop:disable CodeReuse/ActiveRecord
+
+ # Return (create if necessary) the ghost user. The ghost user
+ # owns records previously belonging to deleted users.
+ def ghost
+ email = 'ghost%s@example.com'
+ unique_internal(User.where(user_type: :ghost), 'ghost', email) do |u|
+ u.bio = _('This is a "Ghost User", created to hold all issues authored by users that have ' \
+ 'since been deleted. This user cannot be removed.')
+ u.name = 'Ghost User'
+ end
+ end
+
+ def alert_bot
+ email_pattern = "alert%s@#{Settings.gitlab.host}"
+
+ unique_internal(User.where(user_type: :alert_bot), 'alert-bot', email_pattern) do |u|
+ u.bio = 'The GitLab alert bot'
+ u.name = 'GitLab Alert Bot'
+ u.avatar = bot_avatar(image: 'alert-bot.png')
+ end
+ end
+
+ def migration_bot
+ email_pattern = "noreply+gitlab-migration-bot%s@#{Settings.gitlab.host}"
+
+ unique_internal(User.where(user_type: :migration_bot), 'migration-bot', email_pattern) do |u|
+ u.bio = 'The GitLab migration bot'
+ u.name = 'GitLab Migration Bot'
+ u.confirmed_at = Time.zone.now
+ end
+ end
+
+ def security_bot
+ email_pattern = "security-bot%s@#{Settings.gitlab.host}"
+
+ unique_internal(User.where(user_type: :security_bot), 'GitLab-Security-Bot', email_pattern) do |u|
+ u.bio = 'System bot that monitors detected vulnerabilities for solutions ' \
+ 'and creates merge requests with the fixes.'
+ u.name = 'GitLab Security Bot'
+ u.website_url = Gitlab::Routing.url_helpers.help_page_url('user/application_security/security_bot/index.md')
+ u.avatar = bot_avatar(image: 'security-bot.png')
+ u.confirmed_at = Time.zone.now
+ end
+ end
+
+ def support_bot
+ email_pattern = "support%s@#{Settings.gitlab.host}"
+
+ unique_internal(User.where(user_type: :support_bot), 'support-bot', email_pattern) do |u|
+ u.bio = 'The GitLab support bot used for Service Desk'
+ u.name = 'GitLab Support Bot'
+ u.avatar = bot_avatar(image: 'support-bot.png')
+ u.confirmed_at = Time.zone.now
+ end
+ end
+
+ def automation_bot
+ email_pattern = "automation%s@#{Settings.gitlab.host}"
+
+ unique_internal(User.where(user_type: :automation_bot), 'automation-bot', email_pattern) do |u|
+ u.bio = 'The GitLab automation bot used for automated workflows and tasks'
+ u.name = 'GitLab Automation Bot'
+ u.avatar = bot_avatar(image: 'support-bot.png') # todo: add an avatar for automation-bot
+ end
+ end
+
+ def llm_bot
+ email_pattern = "llm-bot%s@#{Settings.gitlab.host}"
+
+ unique_internal(User.where(user_type: :llm_bot), 'GitLab-Llm-Bot', email_pattern) do |u|
+ u.bio = 'The Gitlab LLM bot used for fetching LLM-generated content'
+ u.name = 'GitLab LLM Bot'
+ u.avatar = bot_avatar(image: 'support-bot.png') # todo: add an avatar for llm-bot
+ u.confirmed_at = Time.zone.now
+ end
+ end
+
+ def admin_bot
+ email_pattern = "admin-bot%s@#{Settings.gitlab.host}"
+
+ unique_internal(User.where(user_type: :admin_bot), 'GitLab-Admin-Bot', email_pattern) do |u|
+ u.bio = 'Admin bot used for tasks that require admin privileges'
+ u.name = 'GitLab Admin Bot'
+ u.avatar = bot_avatar(image: 'admin-bot.png')
+ u.admin = true
+ u.confirmed_at = Time.zone.now
+ end
+ end
+
+ # rubocop:enable CodeReuse/ActiveRecord
+
+ private
+
+ def bot_avatar(image:)
+ Rails.root.join('lib', 'assets', 'images', 'bot_avatars', image).open
+ end
+
+ def unique_internal(scope, username, email_pattern, &block)
+ scope.first || create_unique_internal(scope, username, email_pattern, &block)
+ end
+
+ def create_unique_internal(scope, username, email_pattern, &creation_block)
+ # Since we only want a single one of these in an instance, we use an
+ # exclusive lease to ensure than this block is never run concurrently.
+ lease_key = "user:unique_internal:#{username}"
+ lease = Gitlab::ExclusiveLease.new(lease_key, timeout: 1.minute.to_i)
+
+ uuid = lease.try_obtain
+ until uuid.present?
+ # Keep trying until we obtain the lease. To prevent hammering Redis too
+ # much we'll wait for a bit between retries.
+ sleep(1)
+ uuid = lease.try_obtain
+ end
+
+ # Recheck if the user is already present. One might have been
+ # added between the time we last checked (first line of this method)
+ # and the time we acquired the lock.
+ existing_user = scope.model.uncached { scope.first }
+ return existing_user if existing_user.present?
+
+ uniquify = Gitlab::Utils::Uniquify.new
+
+ username = uniquify.string(username) { |s| User.find_by_username(s) }
+
+ email = uniquify.string(->(n) { Kernel.sprintf(email_pattern, n) }) do |s|
+ User.find_by_email(s)
+ end
+
+ user = scope.build(
+ username: username,
+ email: email,
+ &creation_block
+ )
+
+ Users::UpdateService.new(user, user: user).execute(validate: false)
+ user
+ ensure
+ Gitlab::ExclusiveLease.cancel(lease_key, uuid)
+ end
+ end
+ end
+end
+
+Users::Internal.prepend_mod
diff --git a/locale/am_ET/gitlab.po b/locale/am_ET/gitlab.po
index 058522fe930..a8366332919 100644
--- a/locale/am_ET/gitlab.po
+++ b/locale/am_ET/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: am\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:37\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr " እና "
msgid " and %{sliced}"
msgstr " እና %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " ወይሠ"
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr "መለያዠበራሱ ከመወገዱ በáŠá‰µ %{days} ቀናት ይቀራሉ"
@@ -718,7 +720,7 @@ msgstr "%{edit_in_new_fork_notice} እንደገና á‹á‹­áˆ ለመጫን ይሞ
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} አáˆá‰°áŒˆáŠ˜áˆ"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po
index cba057323a8..8ded56ba2a9 100644
--- a/locale/ar_SA/gitlab.po
+++ b/locale/ar_SA/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ar\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -49,6 +49,15 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid " or "
msgstr ""
@@ -1054,9 +1063,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -1102,7 +1108,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -1180,6 +1186,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1255,6 +1267,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1783,10 +1798,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1897,6 +1912,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2470,15 +2488,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2518,12 +2545,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2545,6 +2590,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2560,6 +2608,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2572,6 +2623,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2584,9 +2638,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2791,9 +2842,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2908,6 +2956,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2965,6 +3016,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -3016,6 +3070,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -3196,6 +3253,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3508,6 +3568,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3532,6 +3595,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3559,7 +3625,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4399,7 +4465,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -5023,6 +5089,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5461,9 +5530,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5554,6 +5620,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5743,6 +5812,9 @@ msgstr[5] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5758,6 +5830,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5872,6 +5950,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5917,15 +5998,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5947,6 +6031,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5962,6 +6052,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -6004,24 +6097,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6820,9 +6919,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6907,7 +7003,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -7072,6 +7168,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -7294,6 +7393,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7411,6 +7513,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8338,7 +8443,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8353,15 +8458,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8383,6 +8491,9 @@ msgstr[5] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8395,6 +8506,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8422,6 +8539,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8470,6 +8590,9 @@ msgstr[5] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8503,9 +8626,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8593,9 +8713,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9682,7 +9799,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9778,7 +9895,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -10165,6 +10282,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -10255,6 +10375,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -10321,7 +10444,7 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10576,6 +10699,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10777,15 +10903,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10837,9 +10963,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10861,12 +10984,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10882,9 +11017,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -11047,6 +11179,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11344,15 +11479,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11647,6 +11776,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11671,6 +11803,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -12094,9 +12229,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -12166,31 +12298,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -12265,6 +12394,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12628,9 +12760,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12676,6 +12805,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12733,7 +12865,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12949,15 +13081,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -13021,6 +13156,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -13192,6 +13330,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13726,6 +13867,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13759,6 +13903,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13771,9 +13939,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13861,6 +14038,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14407,6 +14593,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14785,9 +14974,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -15130,9 +15316,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -15316,6 +15499,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15406,6 +15592,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15628,6 +15817,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -16141,9 +16333,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -16270,9 +16459,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16513,6 +16699,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16531,6 +16720,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16726,6 +16918,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16753,7 +16951,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16768,7 +16966,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16792,6 +16990,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16852,7 +17053,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16870,10 +17071,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16957,6 +17158,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -17032,9 +17239,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -17047,6 +17251,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -17062,12 +17284,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -17137,12 +17362,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -18361,9 +18580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18406,6 +18622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18544,9 +18763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18568,7 +18784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18682,9 +18898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18796,7 +19009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18943,12 +19156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18994,6 +19213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -19030,6 +19255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -19132,6 +19360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19891,6 +20125,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -20137,6 +20374,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20806,9 +21046,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20833,9 +21070,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -21208,33 +21442,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21937,6 +22144,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -22264,6 +22477,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -22279,6 +22495,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -22294,12 +22513,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22420,7 +22633,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22438,6 +22651,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22459,6 +22675,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22471,6 +22690,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22540,9 +22762,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22573,6 +22792,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22813,6 +23035,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22828,7 +23056,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22939,6 +23167,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -23005,9 +23236,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -23383,7 +23611,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23572,7 +23800,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23584,7 +23812,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23602,9 +23830,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -24034,6 +24259,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -24301,9 +24529,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -24343,6 +24568,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24526,6 +24757,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24949,7 +25186,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24976,6 +25213,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -25018,381 +25261,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -25408,66 +25342,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25897,6 +25780,24 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -26257,6 +26158,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -26293,15 +26197,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -26383,9 +26281,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26722,18 +26617,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26983,10 +26872,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26995,16 +26896,28 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -27052,6 +26965,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -27388,6 +27304,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27886,6 +27805,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27937,6 +27859,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -28033,9 +27958,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -28306,9 +28228,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -28405,6 +28324,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -29134,6 +29056,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -29143,6 +29068,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29548,6 +29476,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29563,6 +29497,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29575,6 +29512,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29881,6 +29821,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -30151,6 +30187,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30583,9 +30622,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30682,6 +30718,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31570,10 +31609,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31651,6 +31690,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31681,15 +31723,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31708,12 +31753,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31732,6 +31783,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31960,9 +32017,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -32170,6 +32224,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -32194,6 +32251,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -32212,10 +32275,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -32272,9 +32338,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -32326,6 +32389,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33559,6 +33628,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33586,9 +33658,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33751,24 +33820,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34486,6 +34591,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34633,7 +34741,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -35080,9 +35191,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -35197,12 +35305,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35653,6 +35755,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35776,9 +35881,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -36301,9 +36403,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -36415,6 +36514,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36538,9 +36640,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36556,9 +36655,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36595,9 +36691,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36658,6 +36751,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36682,9 +36778,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36916,7 +37009,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -37351,9 +37444,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37843,6 +37933,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37978,6 +38074,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -38050,6 +38149,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38869,6 +38971,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38941,7 +39049,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -39004,10 +39112,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -39019,6 +39130,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -39037,6 +39151,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -39094,9 +39211,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -39163,9 +39277,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39526,9 +39637,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39673,34 +39781,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -40039,9 +40123,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -40054,6 +40135,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -40063,9 +40147,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -40345,12 +40426,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40681,9 +40756,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -41113,6 +41185,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41563,6 +41638,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41857,7 +41935,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41944,6 +42022,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -42157,6 +42238,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -42265,9 +42349,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -42280,7 +42361,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -42406,10 +42487,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -42424,6 +42508,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -42436,7 +42538,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -42448,7 +42550,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -42460,6 +42562,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -42487,9 +42595,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42601,6 +42718,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42670,13 +42790,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42949,6 +43066,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -43105,6 +43225,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -43114,7 +43240,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -43171,6 +43303,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -43243,7 +43378,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -43255,12 +43390,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -43531,6 +43672,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -43543,13 +43687,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43579,13 +43723,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43594,6 +43744,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43663,9 +43819,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43720,6 +43873,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43735,9 +43891,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43768,6 +43930,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43885,9 +44050,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43936,7 +44098,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -44284,9 +44446,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -44356,6 +44515,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -44380,12 +44542,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -44413,9 +44587,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -44425,27 +44605,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -44485,15 +44698,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -44521,6 +44764,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44641,6 +44887,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44719,6 +44968,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45562,6 +45814,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45655,9 +45910,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46606,6 +46858,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46753,6 +47017,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46771,6 +47038,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -47440,6 +47710,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -47452,7 +47725,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -48313,9 +48592,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -48490,6 +48766,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -48508,9 +48787,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48760,6 +49036,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48844,6 +49123,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -49348,9 +49630,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -49369,10 +49657,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -49522,7 +49810,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49648,7 +49936,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49669,7 +49957,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -50104,7 +50392,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -50386,6 +50674,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -50470,6 +50761,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -50500,9 +50794,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -50575,6 +50875,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50944,9 +51256,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -51034,6 +51343,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -51067,9 +51379,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -51148,6 +51457,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -51523,6 +51835,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -51544,10 +51859,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51595,6 +51910,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51661,13 +51979,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -52345,6 +52663,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -53056,6 +53377,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -53083,16 +53407,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -53335,6 +53662,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -53449,10 +53779,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -53488,6 +53815,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53815,6 +54145,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53917,15 +54253,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -54292,6 +54619,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -54388,9 +54721,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -54409,9 +54739,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -54430,13 +54757,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -54580,9 +54913,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54613,7 +54943,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54712,9 +55042,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54979,6 +55306,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54988,6 +55318,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -55186,9 +55519,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55693,9 +56023,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55819,9 +56146,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55846,6 +56170,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -56023,6 +56350,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -56140,6 +56470,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56698,6 +57031,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56773,6 +57109,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56863,9 +57202,6 @@ msgstr[5] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -57145,6 +57481,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -57640,6 +57979,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -57649,6 +57991,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57676,6 +58021,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57733,6 +58081,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -58066,6 +58417,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -58108,6 +58462,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -58156,9 +58513,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -58219,6 +58573,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/as_IN/gitlab.po b/locale/as_IN/gitlab.po
index 84bf00f07e6..3577def8603 100644
--- a/locale/as_IN/gitlab.po
+++ b/locale/as_IN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: as\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/az_AZ/gitlab.po b/locale/az_AZ/gitlab.po
index 3ade2a4c53c..28d7b7ac265 100644
--- a/locale/az_AZ/gitlab.po
+++ b/locale/az_AZ/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: az\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ba_RU/gitlab.po b/locale/ba_RU/gitlab.po
index 058cfec79c3..dd8636a5815 100644
--- a/locale/ba_RU/gitlab.po
+++ b/locale/ba_RU/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ba\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -44,6 +44,10 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+
msgid " or "
msgstr ""
@@ -574,9 +578,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -622,7 +623,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -700,6 +701,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -775,6 +782,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1203,10 +1213,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1312,6 +1322,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1755,15 +1768,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1803,12 +1825,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1830,6 +1870,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1845,6 +1888,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -1857,6 +1903,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -1869,9 +1918,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2076,9 +2122,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2193,6 +2236,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2250,6 +2296,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2301,6 +2350,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2481,6 +2533,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2793,6 +2848,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2817,6 +2875,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2844,7 +2905,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3684,7 +3745,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4308,6 +4369,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4746,9 +4810,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4839,6 +4900,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5023,6 +5087,9 @@ msgstr[0] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5038,6 +5105,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5147,6 +5220,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5192,15 +5268,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5222,6 +5301,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5237,6 +5322,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5279,24 +5367,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6045,9 +6139,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6127,7 +6218,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6267,6 +6358,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6474,6 +6568,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6591,6 +6688,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7518,7 +7618,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7533,15 +7633,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7558,6 +7661,9 @@ msgstr[0] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7570,6 +7676,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7597,6 +7709,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7640,6 +7755,9 @@ msgstr[0] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7673,9 +7791,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7763,9 +7878,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -8837,7 +8949,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -8933,7 +9045,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9320,6 +9432,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9410,6 +9525,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9466,7 +9584,7 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -9922,15 +10043,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -9982,9 +10103,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10006,12 +10124,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10027,9 +10157,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10187,6 +10314,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10484,15 +10614,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10782,6 +10906,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10806,6 +10933,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11229,9 +11359,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11301,31 +11428,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11753,9 +11880,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11801,6 +11925,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11858,7 +11985,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12074,15 +12201,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12146,6 +12276,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12317,6 +12450,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -12836,6 +12972,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -12869,6 +13008,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -12881,9 +13044,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -12971,6 +13143,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13517,6 +13698,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -13895,9 +14079,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14235,9 +14416,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14411,6 +14589,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14501,6 +14682,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14723,6 +14907,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15226,9 +15413,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15350,9 +15534,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15568,6 +15749,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15586,6 +15770,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15766,6 +15953,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15793,7 +15986,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -15808,7 +16001,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -15832,6 +16025,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -15892,7 +16088,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -15910,10 +16106,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -15997,6 +16193,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16067,9 +16269,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16082,6 +16281,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16097,12 +16314,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16172,12 +16392,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17366,9 +17580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17411,6 +17622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17549,9 +17763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17573,7 +17784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17687,9 +17898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -17801,7 +18009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -17948,12 +18156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -17999,6 +18213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18035,6 +18255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18137,6 +18360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18891,6 +19120,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19137,6 +19369,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19791,9 +20026,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -19818,9 +20050,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20188,33 +20417,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20907,6 +21109,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21234,6 +21442,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21249,6 +21460,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21264,12 +21478,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21390,7 +21598,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21429,6 +21640,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21441,6 +21655,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21510,9 +21727,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21543,6 +21757,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21783,6 +22000,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -21798,7 +22021,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -21975,9 +22201,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22353,7 +22576,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22542,7 +22765,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22554,7 +22777,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22572,9 +22795,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -22994,6 +23214,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23256,9 +23479,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23298,6 +23518,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23481,6 +23707,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23889,7 +24121,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -23916,6 +24148,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -23958,381 +24196,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24348,66 +24277,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24837,6 +24715,14 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25192,6 +25078,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25228,15 +25117,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25318,9 +25201,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25652,18 +25532,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25913,10 +25787,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -25925,16 +25811,23 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -25982,6 +25875,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26318,6 +26214,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26816,6 +26715,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -26867,6 +26769,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -26963,9 +26868,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27226,9 +27128,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27325,6 +27224,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28019,6 +27921,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28028,6 +27933,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28433,6 +28341,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28448,6 +28362,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28460,6 +28377,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28766,6 +28686,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29021,6 +29037,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29453,9 +29472,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29552,6 +29568,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30430,10 +30449,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30511,6 +30530,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30541,15 +30563,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30568,12 +30593,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30592,6 +30623,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -30815,9 +30852,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31025,6 +31059,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31049,6 +31086,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31067,10 +31110,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31127,9 +31173,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31181,6 +31224,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32379,6 +32428,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32406,9 +32458,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32571,24 +32620,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33301,6 +33386,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33448,7 +33536,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33895,9 +33986,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34012,12 +34100,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34468,6 +34550,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34591,9 +34676,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35116,9 +35198,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35230,6 +35309,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35353,9 +35435,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35371,9 +35450,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35410,9 +35486,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35473,6 +35546,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35497,9 +35573,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35731,7 +35804,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36166,9 +36239,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36658,6 +36728,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -36793,6 +36869,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -36865,6 +36944,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37684,6 +37766,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37756,7 +37844,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -37809,10 +37897,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -37824,6 +37915,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -37842,6 +37936,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -37899,9 +37996,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -37968,9 +38062,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38331,9 +38422,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38473,34 +38561,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38834,9 +38898,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -38849,6 +38910,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -38858,9 +38922,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39140,12 +39201,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39446,9 +39501,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -39858,6 +39910,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40283,6 +40338,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40567,7 +40625,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40649,6 +40707,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40857,6 +40918,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -40965,9 +41029,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -40980,7 +41041,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41106,10 +41167,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41124,6 +41188,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41136,7 +41218,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41148,7 +41230,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41160,6 +41242,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41187,9 +41275,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41301,6 +41398,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41370,13 +41470,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41594,6 +41691,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41750,6 +41850,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -41759,7 +41865,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -41888,7 +42003,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -41900,12 +42015,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42171,6 +42292,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42183,13 +42307,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42219,13 +42343,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42234,6 +42364,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42303,9 +42439,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42360,6 +42493,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42375,9 +42511,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42408,6 +42550,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42525,9 +42670,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42571,7 +42713,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -42919,9 +43061,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -42991,6 +43130,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43015,12 +43157,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43048,9 +43202,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43060,27 +43220,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43120,15 +43313,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43156,6 +43379,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43276,6 +43502,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43354,6 +43583,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44187,6 +44419,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44280,9 +44515,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45231,6 +45463,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45378,6 +45622,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45396,6 +45643,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46055,6 +46305,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46067,7 +46320,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47070,6 +47326,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47088,9 +47347,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47340,6 +47596,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47424,6 +47683,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47928,9 +48190,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -47949,10 +48217,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48102,7 +48370,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48228,7 +48496,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48249,7 +48517,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48669,7 +48937,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48951,6 +49219,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49030,6 +49301,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49060,9 +49334,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49135,6 +49415,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49499,9 +49791,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49589,6 +49878,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49622,9 +49914,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49703,6 +49992,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50078,6 +50370,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50099,10 +50394,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50150,6 +50445,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50216,13 +50514,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -50895,6 +51193,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51596,6 +51897,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51623,16 +51927,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -51875,6 +52182,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -51989,10 +52299,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52028,6 +52335,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52355,6 +52665,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52457,15 +52773,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -52817,6 +53124,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -52908,9 +53221,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -52929,9 +53239,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -52950,13 +53257,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53100,9 +53413,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53133,7 +53443,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53232,9 +53542,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53494,6 +53801,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53503,6 +53813,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53701,9 +54014,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54319,9 +54626,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54346,6 +54650,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54513,6 +54820,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54620,6 +54930,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55128,6 +55441,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55193,6 +55509,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55278,9 +55597,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55540,6 +55856,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56010,6 +56329,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56019,6 +56341,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56046,6 +56371,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56103,6 +56431,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56396,6 +56727,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56438,6 +56772,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56486,9 +56823,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56544,6 +56878,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/be_BY/gitlab.po b/locale/be_BY/gitlab.po
index f8424fa73f3..a9b11141a8b 100644
--- a/locale/be_BY/gitlab.po
+++ b/locale/be_BY/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: be\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -47,6 +47,13 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr ""
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -910,7 +914,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -988,6 +992,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1063,6 +1073,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,10 +1564,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1663,6 +1676,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2730,6 +2782,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2910,6 +2965,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3222,6 +3280,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3246,6 +3307,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3273,7 +3337,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4113,7 +4177,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4737,6 +4801,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5175,9 +5242,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5268,6 +5332,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5455,6 +5522,9 @@ msgstr[3] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5470,6 +5540,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6595,7 +6689,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6750,6 +6844,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6966,6 +7063,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8053,6 +8159,9 @@ msgstr[3] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8065,6 +8174,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8171,9 +8292,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8261,9 +8379,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,7 +9555,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9827,6 +9942,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9979,7 +10100,7 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10435,15 +10559,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10703,6 +10833,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11000,15 +11133,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11301,6 +11428,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11325,6 +11455,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11748,9 +11881,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12383,7 +12513,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12599,15 +12729,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12671,6 +12804,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14429,9 +14616,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16342,6 +16532,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16369,7 +16565,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16384,7 +16580,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16408,6 +16604,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16468,7 +16667,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16486,10 +16685,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16661,6 +16863,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16676,12 +16896,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17963,9 +18180,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18008,6 +18222,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18146,9 +18363,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18398,7 +18609,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18545,12 +18756,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18596,6 +18813,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19737,6 +19972,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21852,6 +22063,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22008,7 +22219,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22128,9 +22348,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22527,6 +22753,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22593,9 +22822,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22971,7 +23197,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23160,7 +23386,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23172,7 +23398,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23190,9 +23416,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23618,6 +23841,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23883,9 +24109,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23925,6 +24148,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24108,6 +24337,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24984,66 +24916,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25867,15 +25765,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26294,18 +26183,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26555,10 +26438,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26567,16 +26462,26 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27458,6 +27369,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27509,6 +27423,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27605,9 +27522,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27973,6 +27884,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28688,6 +28602,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29117,6 +29043,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29129,6 +29058,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29435,6 +29367,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31225,15 +31259,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31252,12 +31289,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31276,6 +31319,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31712,6 +31758,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31736,6 +31785,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,10 +31809,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31814,9 +31872,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33087,6 +33148,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33279,24 +33340,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34012,6 +34109,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34159,7 +34259,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34606,9 +34709,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34723,12 +34823,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35179,6 +35273,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35827,9 +35921,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35941,6 +36032,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36877,9 +36962,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37504,6 +37592,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37576,6 +37667,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38395,6 +38489,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39048,9 +39151,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39581,9 +39657,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40187,9 +40254,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42150,13 +42262,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results..."
-msgstr ""
-
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42407,6 +42516,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44095,6 +44333,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46203,6 +46459,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46221,6 +46480,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46898,7 +47163,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47940,9 +48211,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48276,6 +48547,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,10 +49081,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48954,7 +49234,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,7 +49360,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49101,7 +49381,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50966,10 +51273,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51083,13 +51393,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51765,6 +52075,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53333,15 +53661,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53817,9 +54139,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56141,6 +56469,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56229,9 +56560,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57398,6 +57741,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57440,6 +57786,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57488,9 +57837,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index 036a1548059..3714d6ad14b 100644
--- a/locale/bg/gitlab.po
+++ b/locale/bg/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: bg\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "ÐаиÑтина ли иÑкате да изтриете този план за Ñхема?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "ЧаÑова зона за „Cron“"
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr "Задайте потребителÑки шаблон, използва
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "Шаблон за интервала"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr "ПоÑледна Ñхема"
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr "Ðов план"
-
msgid "New snippet"
msgstr "Ðов отрÑзък"
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "ÐÑма планове"
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr "Опции"
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "Включено"
-
msgid "PipelineSchedules|Active"
msgstr "Ðктивно"
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Променливи"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr "Запазване на плана за Ñхема"
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/bn_BD/gitlab.po b/locale/bn_BD/gitlab.po
index 853ac012c75..d21dc7e2a7a 100644
--- a/locale/bn_BD/gitlab.po
+++ b/locale/bn_BD/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: bn\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/bn_IN/gitlab.po b/locale/bn_IN/gitlab.po
index dafba920c19..85d81a23e29 100644
--- a/locale/bn_IN/gitlab.po
+++ b/locale/bn_IN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: bn-IN\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/br_FR/gitlab.po b/locale/br_FR/gitlab.po
index 11754bab138..0f4ad32fd2e 100644
--- a/locale/br_FR/gitlab.po
+++ b/locale/br_FR/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: br-FR\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -48,6 +48,14 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid " or "
msgstr ""
@@ -958,9 +966,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -1006,7 +1011,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -1084,6 +1089,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1159,6 +1170,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1667,10 +1681,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1780,6 +1794,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2327,15 +2344,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2375,12 +2401,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2402,6 +2446,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2417,6 +2464,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2429,6 +2479,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2441,9 +2494,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2648,9 +2698,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2765,6 +2812,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2822,6 +2872,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2873,6 +2926,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -3053,6 +3109,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3365,6 +3424,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3389,6 +3451,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3416,7 +3481,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4256,7 +4321,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4880,6 +4945,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5318,9 +5386,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5411,6 +5476,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5599,6 +5667,9 @@ msgstr[4] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5614,6 +5685,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5727,6 +5804,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5772,15 +5852,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5802,6 +5885,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5817,6 +5906,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5859,24 +5951,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6665,9 +6763,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6751,7 +6846,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6911,6 +7006,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -7130,6 +7228,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7247,6 +7348,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8174,7 +8278,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8189,15 +8293,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8218,6 +8325,9 @@ msgstr[4] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8230,6 +8340,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8257,6 +8373,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8304,6 +8423,9 @@ msgstr[4] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8337,9 +8459,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8427,9 +8546,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9513,7 +9629,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9609,7 +9725,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9996,6 +10112,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -10086,6 +10205,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -10150,7 +10272,7 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10405,6 +10527,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10606,15 +10731,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10666,9 +10791,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10690,12 +10812,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10711,9 +10845,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10875,6 +11006,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11172,15 +11306,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11474,6 +11602,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11498,6 +11629,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11921,9 +12055,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11993,31 +12124,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -12091,6 +12219,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12453,9 +12584,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12501,6 +12629,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12558,7 +12689,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12774,15 +12905,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12846,6 +12980,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -13017,6 +13154,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13548,6 +13688,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13581,6 +13724,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13593,9 +13760,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13683,6 +13859,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14229,6 +14414,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14607,9 +14795,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14951,9 +15136,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -15135,6 +15317,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15225,6 +15410,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15447,6 +15635,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15958,9 +16149,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -16086,9 +16274,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16324,6 +16509,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16342,6 +16530,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16534,6 +16725,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16561,7 +16758,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16576,7 +16773,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16600,6 +16797,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16660,7 +16860,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16678,10 +16878,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16765,6 +16965,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16839,9 +17045,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16854,6 +17057,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16869,12 +17090,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16944,12 +17168,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -18162,9 +18380,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18207,6 +18422,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18345,9 +18563,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18369,7 +18584,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18483,9 +18698,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18597,7 +18809,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18744,12 +18956,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18795,6 +19013,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18831,6 +19055,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18933,6 +19160,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19691,6 +19924,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19937,6 +20173,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20603,9 +20842,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20630,9 +20866,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -21004,33 +21237,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21731,6 +21937,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -22058,6 +22270,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -22073,6 +22288,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -22088,12 +22306,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22214,7 +22426,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22232,6 +22444,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22253,6 +22468,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22265,6 +22483,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22334,9 +22555,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22367,6 +22585,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22607,6 +22828,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22622,7 +22849,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22733,6 +22960,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22799,9 +23029,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -23177,7 +23404,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23366,7 +23593,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23378,7 +23605,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23396,9 +23623,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23826,6 +24050,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -24092,9 +24319,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -24134,6 +24358,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24317,6 +24547,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24737,7 +24973,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24764,6 +25000,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24806,381 +25048,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -25196,66 +25129,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25685,6 +25567,22 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -26044,6 +25942,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -26080,15 +25981,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -26170,9 +26065,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26508,18 +26400,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26769,10 +26655,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26781,16 +26679,27 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26838,6 +26747,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -27174,6 +27086,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27672,6 +27587,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27723,6 +27641,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27819,9 +27740,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -28090,9 +28008,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -28189,6 +28104,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28911,6 +28829,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28920,6 +28841,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29325,6 +29249,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29340,6 +29270,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29352,6 +29285,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29658,6 +29594,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29925,6 +29957,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30357,9 +30392,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30456,6 +30488,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31342,10 +31377,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31423,6 +31458,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31453,15 +31491,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31480,12 +31521,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31504,6 +31551,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31731,9 +31784,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31941,6 +31991,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31965,6 +32018,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31983,10 +32042,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -32043,9 +32105,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -32097,6 +32156,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33323,6 +33388,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33350,9 +33418,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33515,24 +33580,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34249,6 +34350,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34396,7 +34500,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34843,9 +34950,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34960,12 +35064,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35416,6 +35514,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35539,9 +35640,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -36064,9 +36162,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -36178,6 +36273,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36301,9 +36399,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36319,9 +36414,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36358,9 +36450,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36421,6 +36510,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36445,9 +36537,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36679,7 +36768,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -37114,9 +37203,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37606,6 +37692,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37741,6 +37833,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37813,6 +37908,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38632,6 +38730,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38704,7 +38808,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38765,10 +38869,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38780,6 +38887,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38798,6 +38908,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38855,9 +38968,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38924,9 +39034,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39287,9 +39394,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39433,34 +39537,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39798,9 +39878,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39813,6 +39890,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39822,9 +39902,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -40104,12 +40181,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40434,9 +40505,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40862,6 +40930,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41307,6 +41378,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41599,7 +41673,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41685,6 +41759,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41897,6 +41974,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -42005,9 +42085,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -42020,7 +42097,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -42146,10 +42223,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -42164,6 +42244,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -42176,7 +42274,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -42188,7 +42286,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -42200,6 +42298,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -42227,9 +42331,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42341,6 +42454,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42410,13 +42526,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42678,6 +42791,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42834,6 +42950,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42843,7 +42965,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42900,6 +43028,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42972,7 +43103,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42984,12 +43115,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -43259,6 +43396,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -43271,13 +43411,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43307,13 +43447,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43322,6 +43468,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43391,9 +43543,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43448,6 +43597,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43463,9 +43615,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43496,6 +43654,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43613,9 +43774,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43663,7 +43821,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -44011,9 +44169,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -44083,6 +44238,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -44107,12 +44265,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -44140,9 +44310,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -44152,27 +44328,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -44212,15 +44421,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -44248,6 +44487,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44368,6 +44610,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44446,6 +44691,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45287,6 +45535,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45380,9 +45631,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46331,6 +46579,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46478,6 +46738,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46496,6 +46759,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -47163,6 +47429,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -47175,7 +47444,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -48029,9 +48304,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -48206,6 +48478,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -48224,9 +48499,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48476,6 +48748,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48560,6 +48835,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -49064,9 +49342,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -49085,10 +49369,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -49238,7 +49522,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49364,7 +49648,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49385,7 +49669,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49817,7 +50101,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -50099,6 +50383,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -50182,6 +50469,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -50212,9 +50502,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -50287,6 +50583,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50655,9 +50963,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50745,6 +51050,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50778,9 +51086,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50859,6 +51164,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -51234,6 +51542,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -51255,10 +51566,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51306,6 +51617,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51372,13 +51686,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -52055,6 +52369,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52764,6 +53081,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52791,16 +53111,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -53043,6 +53366,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -53157,10 +53483,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -53196,6 +53519,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53523,6 +53849,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53625,15 +53957,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53997,6 +54320,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -54092,9 +54421,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -54113,9 +54439,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -54134,13 +54457,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -54284,9 +54613,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54317,7 +54643,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54416,9 +54742,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54682,6 +55005,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54691,6 +55017,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54889,9 +55218,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55394,9 +55720,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55519,9 +55842,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55546,6 +55866,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55721,6 +56044,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55836,6 +56162,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56384,6 +56713,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56457,6 +56789,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56546,9 +56881,6 @@ msgstr[4] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56824,6 +57156,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -57314,6 +57649,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -57323,6 +57661,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57350,6 +57691,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57407,6 +57751,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57732,6 +58079,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57774,6 +58124,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57822,9 +58175,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57884,6 +58234,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/bs_BA/gitlab.po b/locale/bs_BA/gitlab.po
index ed47c829e32..a0a92a91b6c 100644
--- a/locale/bs_BA/gitlab.po
+++ b/locale/bs_BA/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: bs\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -46,6 +46,12 @@ msgstr " i "
msgid " and %{sliced}"
msgstr " i %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid " or "
msgstr " ili "
@@ -766,9 +772,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -814,7 +817,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -892,6 +895,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -967,6 +976,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1435,10 +1447,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1546,6 +1558,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2041,15 +2056,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2089,12 +2113,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2116,6 +2158,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2131,6 +2176,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2143,6 +2191,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2155,9 +2206,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2362,9 +2410,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2479,6 +2524,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2536,6 +2584,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2587,6 +2638,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2767,6 +2821,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3079,6 +3136,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3103,6 +3163,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3130,7 +3193,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3970,7 +4033,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4594,6 +4657,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5032,9 +5098,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5125,6 +5188,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5311,6 +5377,9 @@ msgstr[2] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5326,6 +5395,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5437,6 +5512,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5482,15 +5560,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5512,6 +5593,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5527,6 +5614,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5569,24 +5659,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6355,9 +6451,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6439,7 +6532,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6589,6 +6682,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6802,6 +6898,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6919,6 +7018,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7846,7 +7948,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7861,15 +7963,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7888,6 +7993,9 @@ msgstr[2] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7900,6 +8008,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7927,6 +8041,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7972,6 +8089,9 @@ msgstr[2] ""
msgid "Blocked issue"
msgstr "Blokirani zadaci"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8005,9 +8125,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8095,9 +8212,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9175,7 +9289,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9271,7 +9385,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9658,6 +9772,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9748,6 +9865,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9808,7 +9928,7 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10063,6 +10183,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10264,15 +10387,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10324,9 +10447,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10348,12 +10468,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10369,9 +10501,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10531,6 +10660,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10828,15 +10960,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11128,6 +11254,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11152,6 +11281,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11575,9 +11707,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11647,31 +11776,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11743,6 +11869,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12103,9 +12232,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12151,6 +12277,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12208,7 +12337,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12424,15 +12553,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12496,6 +12628,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12667,6 +12802,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13192,6 +13330,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13225,6 +13366,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13237,9 +13402,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13327,6 +13501,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13873,6 +14056,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14251,9 +14437,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14593,9 +14776,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14773,6 +14953,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14863,6 +15046,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15085,6 +15271,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15592,9 +15781,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15718,9 +15904,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15946,6 +16129,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15964,6 +16150,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16150,6 +16339,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16177,7 +16372,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16192,7 +16387,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16216,6 +16411,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16276,7 +16474,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16294,10 +16492,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16381,6 +16579,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16453,9 +16657,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16468,6 +16669,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16483,12 +16702,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16558,12 +16780,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17764,9 +17980,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17809,6 +18022,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17947,9 +18163,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17971,7 +18184,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18085,9 +18298,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18199,7 +18409,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18346,12 +18556,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18397,6 +18613,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18433,6 +18655,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18535,6 +18760,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19291,6 +19522,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19537,6 +19771,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20197,9 +20434,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20224,9 +20458,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20596,33 +20827,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21319,6 +21523,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21646,6 +21856,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21661,6 +21874,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21676,12 +21892,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21802,7 +22012,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21820,6 +22030,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21841,6 +22054,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21853,6 +22069,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21922,9 +22141,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21955,6 +22171,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22195,6 +22414,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22210,7 +22435,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22321,6 +22546,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22387,9 +22615,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22765,7 +22990,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22954,7 +23179,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22966,7 +23191,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22984,9 +23209,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23410,6 +23632,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23674,9 +23899,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23716,6 +23938,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23899,6 +24127,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24313,7 +24547,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24340,6 +24574,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24382,381 +24622,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24772,66 +24703,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25261,6 +25141,18 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25618,6 +25510,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25654,15 +25549,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25744,9 +25633,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26080,18 +25966,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26341,10 +26221,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26353,16 +26245,25 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26410,6 +26311,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26746,6 +26650,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27244,6 +27151,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27295,6 +27205,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27391,9 +27304,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27658,9 +27568,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27757,6 +27664,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28465,6 +28375,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28474,6 +28387,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28879,6 +28795,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28894,6 +28816,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28906,6 +28831,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29212,6 +29140,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29473,6 +29497,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29905,9 +29932,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30004,6 +30028,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30886,10 +30913,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30967,6 +30994,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30997,15 +31027,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31024,12 +31057,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31048,6 +31087,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31273,9 +31318,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31483,6 +31525,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31507,6 +31552,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31525,10 +31576,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31585,9 +31639,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31639,6 +31690,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32851,6 +32908,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32878,9 +32938,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33043,24 +33100,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33775,6 +33868,9 @@ msgstr "Stranice"
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33922,7 +34018,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34369,9 +34468,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34486,12 +34582,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34942,6 +35032,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35065,9 +35158,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35590,9 +35680,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35704,6 +35791,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35827,9 +35917,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35845,9 +35932,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35884,9 +35968,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35947,6 +36028,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35971,9 +36055,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36205,7 +36286,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36640,9 +36721,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37132,6 +37210,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37267,6 +37351,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37339,6 +37426,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38158,6 +38248,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38230,7 +38326,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38287,10 +38383,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38302,6 +38401,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38320,6 +38422,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38377,9 +38482,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38446,9 +38548,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr "Javno"
@@ -38809,9 +38908,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38953,34 +39049,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39316,9 +39388,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39331,6 +39400,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39340,9 +39412,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39622,12 +39691,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39940,9 +40003,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40360,6 +40420,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40795,6 +40858,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41083,7 +41149,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41167,6 +41233,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41377,6 +41446,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41485,9 +41557,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41500,7 +41569,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41626,10 +41695,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41644,6 +41716,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41656,7 +41746,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41668,7 +41758,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41680,6 +41770,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41707,9 +41803,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41821,6 +41926,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41890,13 +41998,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42136,6 +42241,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42292,6 +42400,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42301,7 +42415,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42358,6 +42478,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42430,7 +42553,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42442,12 +42565,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42715,6 +42844,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42727,13 +42859,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42763,13 +42895,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42778,6 +42916,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42847,9 +42991,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42904,6 +43045,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42919,9 +43063,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42952,6 +43102,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43069,9 +43222,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43117,7 +43267,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43465,9 +43615,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43537,6 +43684,9 @@ msgstr ""
msgid "Service Desk"
msgstr "TehniÄka PodrÅ¡ka"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43561,12 +43711,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43594,9 +43756,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43606,27 +43774,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43666,15 +43867,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43702,6 +43933,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43822,6 +44056,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43900,6 +44137,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44737,6 +44977,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44830,9 +45073,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45781,6 +46021,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45928,6 +46180,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45946,6 +46201,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46609,6 +46867,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46621,7 +46882,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47461,9 +47728,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47638,6 +47902,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47656,9 +47923,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47908,6 +48172,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47992,6 +48259,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48496,9 +48766,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48517,10 +48793,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48670,7 +48946,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48796,7 +49072,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48817,7 +49093,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49243,7 +49519,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49525,6 +49801,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49606,6 +49885,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49636,9 +49918,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49711,6 +49999,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50077,9 +50377,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50167,6 +50464,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50200,9 +50500,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50281,6 +50578,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50656,6 +50956,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50677,10 +50980,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50728,6 +51031,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50794,13 +51100,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51475,6 +51781,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52180,6 +52489,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52207,16 +52519,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52459,6 +52774,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52573,10 +52891,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52612,6 +52927,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52939,6 +53257,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53041,15 +53365,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53407,6 +53722,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53500,9 +53821,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53521,9 +53839,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53542,13 +53857,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53692,9 +54013,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53725,7 +54043,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53824,9 +54142,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54088,6 +54403,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54097,6 +54415,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54295,9 +54616,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54796,9 +55114,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54919,9 +55234,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54946,6 +55258,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55117,6 +55432,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55228,6 +55546,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55756,6 +56077,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55825,6 +56149,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55912,9 +56239,6 @@ msgstr[2] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56182,6 +56506,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56662,6 +56989,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56671,6 +57001,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56698,6 +57031,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56755,6 +57091,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57064,6 +57403,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57106,6 +57448,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57154,9 +57499,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57214,6 +57556,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po
index 8f750e74d7f..c00a3826cdd 100644
--- a/locale/ca_ES/gitlab.po
+++ b/locale/ca_ES/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ca\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr " Des de %{start} fins %{end}"
@@ -45,6 +45,11 @@ msgstr " i "
msgid " and %{sliced}"
msgstr " i %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " o "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} no disponible"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr "Afegeix a l'arbre"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr "Trieu una plantilla..."
msgid "Choose a type..."
msgstr "Trieu un tipus..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr "Tots els entorns"
@@ -10359,6 +10487,9 @@ msgstr "Clients"
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr "Confidencialitat"
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Tasca"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr "Filtra..."
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr "Crea una mètrica"
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po
index eb344262981..ea04ea3d60f 100644
--- a/locale/cs_CZ/gitlab.po
+++ b/locale/cs_CZ/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: cs\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -47,6 +47,13 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr ""
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -910,7 +914,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -988,6 +992,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1063,6 +1073,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,10 +1564,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1663,6 +1676,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2730,6 +2782,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2910,6 +2965,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3222,6 +3280,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3246,6 +3307,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3273,7 +3337,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4113,7 +4177,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4737,6 +4801,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5175,9 +5242,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5268,6 +5332,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5455,6 +5522,9 @@ msgstr[3] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5470,6 +5540,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6595,7 +6689,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6750,6 +6844,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6966,6 +7063,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8053,6 +8159,9 @@ msgstr[3] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8065,6 +8174,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8171,9 +8292,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8261,9 +8379,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,7 +9555,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9827,6 +9942,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9979,7 +10100,7 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10435,15 +10559,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10703,6 +10833,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11000,15 +11133,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11301,6 +11428,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11325,6 +11455,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11748,9 +11881,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12383,7 +12513,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12599,15 +12729,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12671,6 +12804,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14429,9 +14616,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16342,6 +16532,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16369,7 +16565,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16384,7 +16580,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16408,6 +16604,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16468,7 +16667,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16486,10 +16685,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16661,6 +16863,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16676,12 +16896,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17963,9 +18180,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18008,6 +18222,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18146,9 +18363,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18398,7 +18609,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18545,12 +18756,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18596,6 +18813,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19737,6 +19972,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21852,6 +22063,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22008,7 +22219,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22128,9 +22348,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22527,6 +22753,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22593,9 +22822,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22971,7 +23197,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23160,7 +23386,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23172,7 +23398,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23190,9 +23416,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23618,6 +23841,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23883,9 +24109,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23925,6 +24148,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24108,6 +24337,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24984,66 +24916,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25867,15 +25765,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26294,18 +26183,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26555,10 +26438,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26567,16 +26462,26 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27458,6 +27369,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27509,6 +27423,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27605,9 +27522,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27973,6 +27884,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28688,6 +28602,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29117,6 +29043,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29129,6 +29058,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29435,6 +29367,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31225,15 +31259,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31252,12 +31289,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31276,6 +31319,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31712,6 +31758,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31736,6 +31785,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,10 +31809,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31814,9 +31872,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33087,6 +33148,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33279,24 +33340,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34012,6 +34109,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34159,7 +34259,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34606,9 +34709,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34723,12 +34823,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35179,6 +35273,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35827,9 +35921,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35941,6 +36032,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36877,9 +36962,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37504,6 +37592,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37576,6 +37667,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38395,6 +38489,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39048,9 +39151,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39581,9 +39657,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40187,9 +40254,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42150,13 +42262,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results..."
-msgstr ""
-
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42407,6 +42516,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44095,6 +44333,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46203,6 +46459,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46221,6 +46480,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46898,7 +47163,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47940,9 +48211,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48276,6 +48547,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,10 +49081,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48954,7 +49234,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,7 +49360,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49101,7 +49381,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50966,10 +51273,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51083,13 +51393,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51765,6 +52075,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53333,15 +53661,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53817,9 +54139,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56141,6 +56469,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56229,9 +56560,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57398,6 +57741,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57440,6 +57786,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57488,9 +57837,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/cy_GB/gitlab.po b/locale/cy_GB/gitlab.po
index 728db904f91..1e194d28a5e 100644
--- a/locale/cy_GB/gitlab.po
+++ b/locale/cy_GB/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: cy\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr " %{start} i %{end}"
@@ -49,6 +49,15 @@ msgstr " a "
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid " or "
msgstr " neu "
@@ -1054,9 +1063,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} diwrnod nes bod tagiau'n cael eu tynnu'n awtomatig"
@@ -1102,7 +1108,7 @@ msgstr "%{edit_in_new_fork_notice} Ceisiwch lwytho ffeil eto."
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -1180,6 +1186,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1255,6 +1267,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1783,10 +1798,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1897,6 +1912,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2470,15 +2488,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2518,12 +2545,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2545,6 +2590,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2560,6 +2608,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2572,6 +2623,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2584,9 +2638,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2791,9 +2842,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2908,6 +2956,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2965,6 +3016,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -3016,6 +3070,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -3196,6 +3253,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3508,6 +3568,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3532,6 +3595,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3559,7 +3625,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4399,7 +4465,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -5023,6 +5089,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5461,9 +5530,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5554,6 +5620,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5743,6 +5812,9 @@ msgstr[5] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5758,6 +5830,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5872,6 +5950,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5917,15 +5998,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5947,6 +6031,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5962,6 +6052,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -6004,24 +6097,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6820,9 +6919,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6907,7 +7003,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -7072,6 +7168,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -7294,6 +7393,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7411,6 +7513,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8338,7 +8443,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8353,15 +8458,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8383,6 +8491,9 @@ msgstr[5] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8395,6 +8506,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8422,6 +8539,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8470,6 +8590,9 @@ msgstr[5] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8503,9 +8626,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8593,9 +8713,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9682,7 +9799,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9778,7 +9895,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -10165,6 +10282,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -10255,6 +10375,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -10321,7 +10444,7 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10576,6 +10699,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10777,15 +10903,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10837,9 +10963,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10861,12 +10984,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10882,9 +11017,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -11047,6 +11179,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11344,15 +11479,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11647,6 +11776,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11671,6 +11803,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -12094,9 +12229,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -12166,31 +12298,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -12265,6 +12394,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12628,9 +12760,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12676,6 +12805,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12733,7 +12865,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12949,15 +13081,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -13021,6 +13156,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -13192,6 +13330,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13726,6 +13867,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13759,6 +13903,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13771,9 +13939,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13861,6 +14038,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14407,6 +14593,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14785,9 +14974,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -15130,9 +15316,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -15316,6 +15499,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15406,6 +15592,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15628,6 +15817,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -16141,9 +16333,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -16270,9 +16459,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16513,6 +16699,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16531,6 +16720,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16726,6 +16918,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16753,7 +16951,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16768,7 +16966,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16792,6 +16990,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16852,7 +17053,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16870,10 +17071,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16957,6 +17158,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -17032,9 +17239,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -17047,6 +17251,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -17062,12 +17284,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -17137,12 +17362,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -18361,9 +18580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18406,6 +18622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18544,9 +18763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18568,7 +18784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18682,9 +18898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18796,7 +19009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18943,12 +19156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18994,6 +19213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -19030,6 +19255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -19132,6 +19360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19891,6 +20125,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -20137,6 +20374,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20806,9 +21046,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20833,9 +21070,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -21208,33 +21442,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21937,6 +22144,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -22264,6 +22477,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -22279,6 +22495,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -22294,12 +22513,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22420,7 +22633,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22438,6 +22651,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22459,6 +22675,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22471,6 +22690,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22540,9 +22762,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22573,6 +22792,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22813,6 +23035,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22828,7 +23056,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22939,6 +23167,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -23005,9 +23236,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -23383,7 +23611,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23572,7 +23800,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23584,7 +23812,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23602,9 +23830,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -24034,6 +24259,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -24301,9 +24529,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -24343,6 +24568,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24526,6 +24757,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24949,7 +25186,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24976,6 +25213,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -25018,381 +25261,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -25408,66 +25342,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25897,6 +25780,24 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -26257,6 +26158,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -26293,15 +26197,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -26383,9 +26281,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26722,18 +26617,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26983,10 +26872,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26995,16 +26896,28 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -27052,6 +26965,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -27388,6 +27304,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27886,6 +27805,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27937,6 +27859,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -28033,9 +27958,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -28306,9 +28228,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -28405,6 +28324,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -29134,6 +29056,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -29143,6 +29068,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29548,6 +29476,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29563,6 +29497,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29575,6 +29512,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29881,6 +29821,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -30151,6 +30187,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30583,9 +30622,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30682,6 +30718,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31570,10 +31609,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31651,6 +31690,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31681,15 +31723,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31708,12 +31753,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31732,6 +31783,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31960,9 +32017,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -32170,6 +32224,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -32194,6 +32251,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -32212,10 +32275,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -32272,9 +32338,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -32326,6 +32389,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33559,6 +33628,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33586,9 +33658,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33751,24 +33820,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34486,6 +34591,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34633,7 +34741,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -35080,9 +35191,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -35197,12 +35305,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35653,6 +35755,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35776,9 +35881,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -36301,9 +36403,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -36415,6 +36514,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36538,9 +36640,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36556,9 +36655,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36595,9 +36691,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36658,6 +36751,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36682,9 +36778,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36916,7 +37009,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -37351,9 +37444,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37843,6 +37933,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37978,6 +38074,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -38050,6 +38149,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38869,6 +38971,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38941,7 +39049,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -39004,10 +39112,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -39019,6 +39130,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -39037,6 +39151,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -39094,9 +39211,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -39163,9 +39277,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39526,9 +39637,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39673,34 +39781,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -40039,9 +40123,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -40054,6 +40135,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -40063,9 +40147,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -40345,12 +40426,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40681,9 +40756,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -41113,6 +41185,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41563,6 +41638,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41857,7 +41935,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41944,6 +42022,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -42157,6 +42238,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -42265,9 +42349,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -42280,7 +42361,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -42406,10 +42487,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -42424,6 +42508,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -42436,7 +42538,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -42448,7 +42550,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -42460,6 +42562,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -42487,9 +42595,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42601,6 +42718,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42670,13 +42790,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42949,6 +43066,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -43105,6 +43225,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -43114,7 +43240,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -43171,6 +43303,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -43243,7 +43378,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -43255,12 +43390,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -43531,6 +43672,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -43543,13 +43687,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43579,13 +43723,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43594,6 +43744,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43663,9 +43819,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43720,6 +43873,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43735,9 +43891,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43768,6 +43930,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43885,9 +44050,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43936,7 +44098,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -44284,9 +44446,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -44356,6 +44515,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -44380,12 +44542,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -44413,9 +44587,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -44425,27 +44605,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -44485,15 +44698,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -44521,6 +44764,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44641,6 +44887,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44719,6 +44968,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45562,6 +45814,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45655,9 +45910,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46606,6 +46858,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46753,6 +47017,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46771,6 +47038,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -47440,6 +47710,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -47452,7 +47725,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -48313,9 +48592,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -48490,6 +48766,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -48508,9 +48787,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48760,6 +49036,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48844,6 +49123,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -49348,9 +49630,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -49369,10 +49657,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -49522,7 +49810,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49648,7 +49936,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49669,7 +49957,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -50104,7 +50392,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -50386,6 +50674,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -50470,6 +50761,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -50500,9 +50794,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -50575,6 +50875,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50944,9 +51256,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -51034,6 +51343,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -51067,9 +51379,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -51148,6 +51457,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -51523,6 +51835,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -51544,10 +51859,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51595,6 +51910,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51661,13 +51979,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -52345,6 +52663,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -53056,6 +53377,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -53083,16 +53407,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -53335,6 +53662,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -53449,10 +53779,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -53488,6 +53815,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53815,6 +54145,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53917,15 +54253,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -54292,6 +54619,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -54388,9 +54721,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -54409,9 +54739,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -54430,13 +54757,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -54580,9 +54913,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54613,7 +54943,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54712,9 +55042,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54979,6 +55306,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54988,6 +55318,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -55186,9 +55519,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55693,9 +56023,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55819,9 +56146,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55846,6 +56170,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -56023,6 +56350,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -56140,6 +56470,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56698,6 +57031,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56773,6 +57109,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56863,9 +57202,6 @@ msgstr[5] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -57145,6 +57481,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -57640,6 +57979,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -57649,6 +57991,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57676,6 +58021,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57733,6 +58081,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -58066,6 +58417,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -58108,6 +58462,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -58156,9 +58513,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -58219,6 +58573,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po
index 16f7c357d60..a7d5bfb42d0 100644
--- a/locale/da_DK/gitlab.po
+++ b/locale/da_DK/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: da\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr " %{start} til %{end}"
@@ -45,6 +45,11 @@ msgstr " og "
msgid " and %{sliced}"
msgstr " og %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " eller "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr "%{count} vægt i alt"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} blev ikke fundet."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} dage før mærkater fjernes automatisk"
@@ -718,7 +720,7 @@ msgstr "%{edit_in_new_fork_notice} Prøv at uploade en fil igen."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr "%{issuesSize} med en grænse på %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Nyheder%{italic_end} er inaktiv og kan ikke vises."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} problemstillinger med en grænse på %{maxIssueCount}"
@@ -871,6 +879,9 @@ msgstr "%{labelStart}Uændret svar:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} utilgængelig"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,11 +1330,11 @@ msgstr "%{verb} %{time_spent_value} brugt tid."
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} gør det muligt for dig at sende underretninger til webprogrammer som svar til begivenheder i en gruppe eller et projekt."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} gør det muligt for dig at sende underretninger til webprogrammer som svar til begivenheder i en gruppe eller et projekt. Vi anbefaler at bruge en %{integrations_link_start}integrering%{link_end} i stedet for en webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr ""
@@ -1429,6 +1440,9 @@ msgstr "+ %{amount} mere"
msgid "+ %{count} more"
msgstr "+ %{count} mere"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} mere"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Accepter invitation"
@@ -2444,6 +2494,9 @@ msgstr "Grupper"
msgid "AccessDropdown|Roles"
msgstr "Roller"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "Brugere"
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr "Handling"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr "Tilføj forslag til batch"
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "Tilføj tekst til indlogningssiden. Markdown er aktiveret."
@@ -2960,6 +3019,9 @@ msgstr "Tilføj til kontrol"
msgid "Add to tree"
msgstr "Tilføj til træ"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,8 +3049,8 @@ msgstr "Tilføj/fjern"
msgid "AddMember|Invite email is invalid"
msgstr "Invitations e-mail er ugyldig"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "Invitationsgrænse på %{daily_invites} pr. dag overskredet"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr ""
@@ -3827,7 +3889,7 @@ msgstr "Blokering af brugeren har følgende indvirkninger:"
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr "Tilføj ny integrering"
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr "Der opstod en fejl ved forhåndsvisning af blob'en"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr "Der opstod en fejl ved opdatering af titlen"
@@ -4982,6 +5044,9 @@ msgstr "Der opstod en fejl under hentning af problemstillinger."
msgid "An error occurred while fetching label colors."
msgstr "Der opstod en fejl under hentning af etiketfarver."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr "Der opstod en fejl under hentning af deltagere"
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "Der opstod en fejl under udløsning af jobbet."
@@ -5182,6 +5250,12 @@ msgstr "Der opstod en fejl under forsøg på at køre en ny pipeline til sammenl
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "Der opstod en fejl under opdatering af godkendere"
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr "Er du sikker på, at du vil slette enheden? Handlingen kan ikke fortryde
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Er du sikker på, at du vil slette pipeline-planlægningen?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr "Er du sikker på, at du vil nulstille tokenen til registrering?"
msgid "Are you sure you want to retry this migration?"
msgstr "Er du sikker på, at du vil prøve migreringen igen?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr "Kommasepareret liste over grene som automatisk skal inspiceres. Lad den
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "Spørg igen senere"
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr "Kan ikke fjerne brugeren"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr "Direkte medlemskaber"
msgid "Billing|Enter at least three characters to search."
msgstr "Indtast mindst tre tegn for at søge."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr "Ingen brugere at vise."
@@ -7735,6 +7842,12 @@ msgstr "Projektinvitation"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "Fjern brugeren %{username} fra dit abonnement"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] "Blokeret af %d problemstillinger"
msgid "Blocked issue"
msgstr "Blokeret problemstilling"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr "Blokerende"
@@ -7839,9 +7958,6 @@ msgstr "Ingen matchende resultater"
msgid "BoardNewEpic|Search groups"
msgstr "Søg efter grupper"
-msgid "BoardNewEpic|Select a group"
-msgstr "Vælg en gruppe"
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr "Vælg milepæl"
-msgid "BoardScope|Select weight"
-msgstr "Vælg vægt"
-
msgid "BoardScope|Started"
msgstr "Startet"
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,8 +9215,8 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr "Kan udsendes manuelt til"
-msgid "Can create groups:"
-msgstr "Kan oprette grupper:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr ""
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Tjekker tilgængelighed af %{text} …"
@@ -9637,8 +9756,8 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText}-plan"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr "Vælg en skabelon ..."
msgid "Choose a type..."
msgstr "Vælg en type ..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Vælg fil …"
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "Kan ikke bruge maskeret variabel med nuværende værdi"
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr "Miljøer"
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr "Fjern variabel"
-msgid "CiVariables|Remove variable row"
-msgstr "Fjern variabelrække"
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Type"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Værdi"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (alle miljøer)"
-
msgid "CiVariable|All environments"
msgstr "Alle miljøer"
@@ -10359,6 +10487,9 @@ msgstr "Klienter"
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Klon"
@@ -10656,15 +10787,9 @@ msgstr "Klyngehelbred"
msgid "Cluster cache cleared."
msgstr "Klyngemellemlager ryddet."
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr "Klynge kræves for Stages::ClusterEndpointInserter"
-
msgid "Cluster level"
msgstr "Klyngeniveau"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr "Agenten har ingen tokens"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr "Kodekontrol"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "Kodekontrolanalyse viser en tabel over åbne sammenlægningsanmodninger, som anses for at være under kodekontrol. Der er i øjeblikket ingen sammenlægningsanmodninger under kontrol for projektet og/eller filtrene."
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr "Sammenfold"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr "Sammenfold alle tråde"
@@ -11928,9 +12056,6 @@ msgstr "Der opstod en fejl under indlæsning af gren-/mærkatlisten. Prøv venli
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "Der opstod en fejl under søgning i gren-/mærkatlisten. Prøv venligst igen."
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "Der opstod en fejl under opdatering af gren-/mærkatlisten. Prøv venligst igen."
-
msgid "CompareRevisions|View open merge request"
msgstr "Vis åben sammenlægningsanmodning"
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr "Overholdelsesframework"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Tilføj framework"
@@ -12033,7 +12161,7 @@ msgstr "Fejl ved hentning af overholdelsesframeworkdata. Opdater venligst siden
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr "Fortrolighed"
msgid "Configuration help"
msgstr "Konfigurationshjælp"
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr "Konfigurer %{repository_checks_link_start}depottjek%{link_end} og %{housekeeping_link_start}husarbejde%{link_end} på depoter."
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr "Fejl ved forbindelse"
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "Kontakt support"
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr "Opret udgivelse"
msgid "Create requirement"
msgstr "Opret krav"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "Tidszone for Cron"
-
msgid "Cron time zone"
msgstr "Cron-tidszone"
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr "Slet etiket: %{labelName}"
msgid "Delete pipeline"
msgstr "Slet pipeline"
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr "Slet projekt"
@@ -15757,6 +15939,9 @@ msgstr "Placering og afhængighedssti"
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "SÃ¥rbarhedsliste til/fra"
@@ -15958,6 +16146,12 @@ msgstr "Tidszone"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} andre"
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr "Nuværende projekt"
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr "Indlæser udsendelsesnøgler"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr "Tillader skrivebeskyttet adgang til depotet."
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr "Kopiér udsendelsestoken"
@@ -16084,7 +16281,7 @@ msgstr "Omfang"
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr "Brugernavn"
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} af %{designs_count}"
@@ -17565,9 +17780,6 @@ msgstr "E-mail sendt"
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr "E-mail:"
@@ -17610,6 +17822,9 @@ msgstr "%{emails}, %{andMore} vil blive underrettet om din kommentar."
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "og %{moreCount} mere"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "E-mails"
@@ -17748,9 +17963,6 @@ msgstr "Aktivér grupperunnere"
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr "Miljøomfang"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Job"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr "Lær mere om at stoppe miljøer"
@@ -18198,6 +18413,12 @@ msgstr "Tilbagerul miljøet %{name}?"
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr "Kommende"
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr "Udfold"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Udfold alle"
@@ -19337,6 +19570,9 @@ msgstr "https://example.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr "Filtrér efter testsager som i øjeblikket er arkiveret."
msgid "Filter by test cases that are currently open."
msgstr "Filtrér efter testsager som i øjeblikket er åbne."
-msgid "Filter by user"
-msgstr "Filtrér efter bruger"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr "Filtrér resultater ..."
msgid "Filter users"
msgstr "Filtrér brugere"
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr "FÃ¥ en gratis instanskontrol"
msgid "Get a support subscription"
msgstr "FÃ¥ et abonnement med support"
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Kom godt i gang"
@@ -21440,6 +21649,9 @@ msgstr "Ubekræftet"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr "Gitaly-servere"
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr "Gitaly-timeouts"
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr "Fik adgang %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr "Gruppeavatar"
msgid "Group by"
msgstr "Gruppér efter"
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "Gruppebeskrivelse (valgfrit)"
@@ -22181,9 +22408,6 @@ msgstr "Gruppenavn (din organisation)"
msgid "Group navigation"
msgstr "Gruppenavigation"
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr "Indhold for gruppeoversigt"
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr "Overholdelsesframeworks"
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,8 +22972,8 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "En gruppe er en samling af projekter."
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
msgid "GroupsEmptyState|Create new project"
msgstr ""
@@ -22760,8 +22984,8 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Hvis du organiserer dine projekter under en gruppe, så virker det som en mappe."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
msgid "GroupsEmptyState|No archived projects."
msgstr ""
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr "Hjælper med at forhindre botter i at udføre brute-force-angreb."
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "Jeg vil gerne modtage opdateringer om GitLab via e-mail"
-
msgid "I'm signing up for GitLab because:"
msgstr "Jeg tilmelder mig GitLab fordi:"
@@ -23507,6 +23728,12 @@ msgstr "Valgmuligheden er deaktiveret fordi du ikke har tilladelse til at oprett
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr "Valgmuligheden er deaktiveret fordi du ikke har skrivetilladelser til den nuværende gren."
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "INFO: Din SSH-nøgle er udløbet. Generer venligst en ny nøgle."
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr "Forbedr kundesupport med serviceskranke"
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr "%{strong_start}Flere godkendelsesroller%{strong_end} — herunder kodeejere og krævede sammenlægningsgodkendelser"
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...og du kan få en gratis prøveperiode af GitLab Ultimate"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "Er dine runnere klar?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "Bedre kode på mindre tid"
-
msgid "InProductMarketing|Blog"
msgstr "Blog"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr "Ved at aktivere kodeejere og krævede sammenlægningsgodkendelser vil den korrekte person kontrollere den rette sammenlægningsanmodning. Det har flere fordele: renere kode og en mere effektiv kontrolproces."
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr "Opret en tilpasset CI-runner med få klik"
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr "Opret en tilpasset runner"
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "Opret et projekt i GitLab på 5 minutter"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "Opret dit første projekt!"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "Udforsk GitLab CI/CD"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "Udforsk mulighederne"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "Gratis 30-dages prøveperiode"
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr "Kom godt i gang i dag"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr "Har du en anden instans du vil importere? Her er vores %{import_link}."
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr "Forbedr programsikkerhed på en 30-dages prøveperiode"
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr "Øg driftseffektivitet"
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "Inviter dine kollegaer og begynd at sende kode hurtigere afsted."
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "Inviter dine kollegaer til at deltage på under ét minut"
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "Inviter dit team på mindre end 60 sekunder"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "Inviter dit team nu"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr "Start GitLab CI/CD på 20 minutter eller mindre"
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr "Har du brug for et alternativ til at importere?"
-
msgid "InProductMarketing|No credit card required."
msgstr "Ingen kreditkort kræves."
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "Start med at importere dine projekter"
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "Start med en gratis prøveperiode af GitLab Ultimate"
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr "Test, opret, udsend"
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr "Dette er e-mail %{current_series} af %{total_series} i serien %{track}."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "Prøv GitLab Ultimate, gratis"
-
-msgid "InProductMarketing|Try it out"
-msgstr "Prøv det"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "Prøv det selv"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "omfattende vejledning"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr "opret et projekt"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "fra Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr "fjern abonnering"
-msgid "InProductMarketing|update your preferences"
-msgstr "opdater dine præferencer"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "du kan når som helst %{unsubscribe_link}."
@@ -25049,6 +24928,16 @@ msgstr "Indlejret"
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr "Indtast værtsnøgler manuelt"
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr "Interne brugere kan ikke deaktiveres"
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "Intervalmønster"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr "Ugyldig totrinskode."
-msgid "Invalid yaml"
-msgstr "Ugyldig yaml"
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr "Lukket"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Lukket (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr "duplikeret"
@@ -26127,28 +26004,48 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr ""
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Gns./måned:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "Sidste 12 måneder"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Beklager, dit filter gav ingen resultater"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr ""
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr "Kursiv tekst"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr "Gennemløb"
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr "Tilmeldt %{time_ago}"
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr "Sidste aktivitet"
msgid "Last Name"
msgstr "Efternavn"
-msgid "Last Pipeline"
-msgstr "Sidste pipeline"
-
msgid "Last Seen"
msgstr "Sidst set"
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr "hos"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "Seneste ændringer"
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr "LÃ¥s ikke fundet"
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr "Mattermost-URL:"
msgid "Mattermost notifications"
msgstr "Mattermost-underretninger"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr "Tilføj til Mattermost"
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr "Forslag:"
@@ -28989,6 +28913,102 @@ msgstr "%{member_name} inviterede dig til at deltage i GitLab"
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr "Invitation til at deltage i %{project_or_group} %{project_or_group_name}"
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr "Sammenlægningscommit-meddelelse"
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr "Opret måling"
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr "Nyt svar til problemstilling #%{issue_iid}:"
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr "Ny planlægning"
-
msgid "New snippet"
msgstr "Nyt udklip"
@@ -31254,6 +31292,9 @@ msgstr "Ingen gennemløb"
msgid "No label"
msgstr "Ingen etiket"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr "Ingen medlemmer fundet"
@@ -31296,11 +31343,14 @@ msgstr "Ingen milepæl"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
-msgstr "Ingen paneler matcher egenskaberne %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
+msgstr ""
msgid "No parent group"
msgstr "Ingen forældergruppe"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "Ingen planlægninger"
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr "Valgmuligheder"
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr "Forælderløst medlem"
@@ -33538,6 +33627,9 @@ msgstr "Sider"
msgid "Pages Domain"
msgstr "Pages-domæne"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr "Første"
@@ -33685,7 +33777,10 @@ msgstr "Sti"
msgid "Path:"
msgstr "Sti:"
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "Aktiveret"
-
msgid "PipelineSchedules|Active"
msgstr "Aktiv"
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Variabler"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr "Oprettet"
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr "Udløserforfatter"
-msgid "Pipeline|Triggerer"
-msgstr "Udløsere"
-
msgid "Pipeline|Variables"
msgstr "Variabler"
@@ -35353,9 +35439,6 @@ msgstr "Bredde på layout"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "Skal være et tal fra %{min} til %{max}"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr "Forrige uløste debat"
msgid "Primary Action"
msgstr "Primær handling"
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr "Rediger profil"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr "Projektsti"
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr "Forgreninger"
@@ -37030,6 +37110,9 @@ msgstr "Offentlig"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr "Squashing udføres aldrig og afkrydsningsboksen er skjult."
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr "Hvad er beskyttede grene?"
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} vil være skrivbar for udviklere. Er du sikker?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr "Vælg brugere"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr "Offentlige"
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr "Modtag underretninger om din egen aktivitet"
-msgid "Receive product marketing emails"
-msgstr "Modtag e-mails om markedsføring af produkter"
-
msgid "Recent"
msgstr "Seneste"
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr "Fjern prioritet"
-msgid "Remove report"
-msgstr "Fjern rapport"
-
msgid "Remove reviewer"
msgstr "Fjern kontrollant"
@@ -39090,6 +39155,9 @@ msgstr "Fjern sekundære e-mail"
msgid "Remove spent time"
msgstr "Fjern brugt tid"
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr "Fjern tidsestimat"
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr "Fjern bruger"
-msgid "Remove user & report"
-msgstr "Fjern bruger og rapport"
-
msgid "Remove user from group"
msgstr "Fjern bruger fra gruppe"
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Rapporteret %{timeAgo} af %{reportedBy}"
-msgid "Reported by"
-msgstr "Rapporteret af"
-
-msgid "Reported by %{reporter}"
-msgstr "Rapporteret af %{reporter}"
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr "Gem adgangskode"
-msgid "Save pipeline schedule"
-msgstr "Gem pipelineplanlægning"
-
msgid "Saving"
msgstr "Gemmer"
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr "Søg efter en gruppe"
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "Søg efter tildelere"
@@ -41630,15 +41734,12 @@ msgstr "Søg efter milepæle"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
-msgstr "Søg efter eller filtrér resultater ..."
-
msgid "Search or filter results…"
msgstr "Søg efter eller filtrér resultater …"
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr ""
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr "Sikkerhedsbetjeningspanel"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr "En sammenlægningsgodkendelse kræves når testdækning afviser."
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "Tilføj eller fjern projekter som skal overvåges i sikkerhedsområdet. Projekter som er medtaget i listen får deres resultater vist i sikkerhedsbetjeningspanelet og sårbarhedsrapporten."
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "Afskedig sårbarhed"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr "Send e-mail i multipart-format (HTML og ren tekst). Fravælg for kun at
msgid "Send email notification"
msgstr "Send e-mail-underretning"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "Send e-mails som hjælp til at vejlede nye brugere gennem indførelsesprocessen."
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr "Serviceskranke"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr "Serviceskranke giver personer mulighed for at oprette problemstillinger i din GitLab-instans uden deres egen brugerkonto. Det giver en unik e-mailadressen til slutbrugeren som kan bruges til at oprette problemstillinger i et projekt. Svar kan enten sendes gennem GitLab-grænsefladen eller med e-mail. Kun slutbrugere ser tråde via e-mail."
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr "Aktivér serviceskranke"
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr "Kontakt venligst en administrator for at få hjælp med at opsætning serviceskranken til din instans."
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr "Problemstillinger som er oprettet med e-mails fra serviceskranken vises her. Hver kommentar bliver en del af e-mail-samtalen."
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr "For at aktivere serviceskranke i instansen skal en instansadministrator først opsætte indgående e-mail."
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr "Brug serviceskranke til at skabe forbindelse med dine brugere og tilbyde kundesupport gennem e-mail direkte i GitLab"
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr "Dine brugere kan sende e-mails til denne adresse:"
@@ -43429,6 +43656,9 @@ msgstr "Session-id"
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "Indstil %{epic_ref} som forælderepicen."
@@ -43549,6 +43779,9 @@ msgstr "Indstil tidsestimat til %{time_estimate}."
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr "Din status nulstilles %{date}."
msgid "Sets %{epic_ref} as parent epic."
msgstr "Indstiller %{epic_ref} som forælderepic."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "Noget gik galt"
@@ -44555,9 +44794,6 @@ msgstr "Noget gik galt under hentning af beskrivelsesændringer. Prøv venligst
msgid "Something went wrong while fetching details"
msgstr "Noget gik galt under hentning af detaljer"
-msgid "Something went wrong while fetching latest comments."
-msgstr "Noget gik galt under hentning af seneste kommentarer."
-
msgid "Something went wrong while fetching projects"
msgstr "Noget gik galt under hentning af projekter"
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr "Tilføj sæder"
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr "Slettede WebAuthn-enhed."
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr "Fjernelse af udelukkelse lykkedes"
msgid "Successfully unblocked"
msgstr "Fjernelse fra blokering lykkedes"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr "MÃ¥lsti"
msgid "Target branch"
msgstr "MÃ¥lgren"
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr "Siden kunne ikke vises fordi den fik timeout."
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr "Forælderepicen er fortrolig og kan kun indeholde fortrolige epics og problemstillinger"
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr "Adgangskoden til Jenkins-serveren."
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "Der er sammenlægningskonflikter"
@@ -47372,9 +47635,6 @@ msgstr "Der er ingen SSH-nøgler med adgang til din konto."
msgid "There are no Spam Logs"
msgstr "Der er ingen spamlogge"
-msgid "There are no abuse reports!"
-msgstr "Der er ingen misbrugsrapporter!"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr "Der var en fejl ved hentning af topetiketterne for den valgte gruppe"
msgid "There was an error fetching the variables."
msgstr "Der opstod en fejl ved hentning af variablerne."
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr "Der opstod en fejl med reCAPTCHA'en. Løs venligst reCAPTCHA'en igen."
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr "Sammenlægningsanmodningen er fra et privat projekt til et internt proje
msgid "This merge request is from an internal project to a public project."
msgstr "Sammenlægningsanmodningen er fra et internt projekt til et offentligt projekt."
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Sammenlægningsanmodningen er låst."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,11 +48505,11 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
-msgstr "Pipelinen blev udløst af en planlægning."
+msgid "This pipeline was created by a schedule."
+msgstr ""
msgid "This process deletes the project repository and all related resources."
msgstr ""
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr "Tidszone"
msgid "TimeTrackingEstimated|Est"
msgstr "Est."
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr "Log ind på GitLab på %{gitlab_url} for at genaktivere din konto."
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "I morgen"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr "I alt"
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr "Kerner i alt (CPU'er)"
@@ -49348,9 +49626,15 @@ msgstr "1000+"
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr "Tracing"
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr "URL eller anmodnings-id"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr "BRUGEREN %{user_name} FJERNES! Er du sikker?"
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "BRUGEREN %{user} FJERNES! Er du sikker?"
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "BRUGEREN VIL BLIVE BLOKERET! Er du sikker?"
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr "Kan ikke opdatere epicen på nuværende tidspunkt."
msgid "Unable to update this issue at this time."
msgstr "Kan ikke opdatere problemstillingen på nuværende tidspunkt."
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr "Utilfreds?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr "Kodepakker og beholderaftryk."
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr "Brugernavnet er tilgængeligt."
msgid "Username or email"
msgstr "Brugernavn eller e-mail"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Brugernavn:"
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,17 +52223,20 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Bekræftet%{statusEnd} %{timeago} af %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "%{statusStart}Registreret%{statusEnd} %{timeago} i pipelinen %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Afskediget%{statusEnd} %{timeago} af %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Løst%{statusEnd} %{timeago} af %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr ""
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr "Hændelser for udgivelser"
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr "Velkommen, %{name}!"
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr "Du kan oprette en ny personlig adgangstoken ved at besøge %{link}"
msgid "You can create a new SSH key by visiting %{link}"
msgstr "Du kan oprette en ny SSH-nøgle ved at besøge %{link}"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr "Du kan oprette en ny en eller tjekke dem i dine indstillinger for %{pat_link_start}personlige adgangstokens%{pat_link_end}."
@@ -53800,6 +54114,9 @@ msgstr "Du kan oprette en ny en eller tjekke dem i dine indstillinger for %{ssh_
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr "Du kan oprette en ny en eller tjekke dem i dine indstillinger for SSH-nøgler %{ssh_key_link}."
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr "Du kan oprette en ny en eller tjekke dem i dine indstillinger for personlige adgangstokens %{pat_link}."
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr "Din browser understøtter ikke iFrames"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr "Din browser understøtter ikke WebAuthn. Brug venligst en browser som understøttes, f.eks. Chrome (67+) eller Firefox (60+)."
@@ -54619,9 +54930,6 @@ msgstr "Din personlige adgangstoken vil udløbe om %{days_to_expire} dage eller
msgid "Your profile"
msgstr "Din profil"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "Din projektgrænse er %{limit} projekter! Kontakt venligst din administrator for at øge den"
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr "Din søgning matchede ikke nogen commits."
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr "må mislykkes"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr "oprettet af"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr "f.eks. %{token}"
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] "filer"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr "den er for stor"
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr "min-fantastiske-gruppe"
@@ -56429,6 +56761,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item} og %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr "%{slash_command} tilføjer eller fratrækker tid som allerede er brugt."
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "startede en debat på %{design_link}"
@@ -56772,6 +57110,9 @@ msgstr "mærkatnavn"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr "udløst"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr "indstillinger for totrinsgodkendelse"
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "version %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "via %{closed_via}"
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index 487b0ff48f0..35e4355b968 100644
--- a/locale/de/gitlab.po
+++ b/locale/de/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: de\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr " %{start} bis %{end}"
@@ -45,6 +45,11 @@ msgstr " und "
msgid " and %{sliced}"
msgstr " und %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] " außer Branch:"
+msgstr[1] " außer Branches:"
+
msgid " or "
msgstr " oder "
@@ -670,9 +675,6 @@ msgstr "%{count} Tags"
msgid "%{count} total weight"
msgstr "%{count} Gesamtgewichtung"
-msgid "%{dashboard_path} could not be found."
-msgstr "Konnte %{dashboard_path} nicht finden."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} Tage, bis Tags automatisch entfernt werden"
@@ -718,8 +720,8 @@ msgstr "%{edit_in_new_fork_notice} Versuche erneut, eine Datei hochzuladen."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@firma.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr "%{enable_service_ping_link_start}Aktiviere%{link_end} oder %{generate_manually_link_start}generiere%{link_end} ein Service+Ping, um die Nutzdaten des Dienstes in der Vorschau anzuzeigen und herunterzuladen."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr ""
msgid "%{extra} more downstream pipelines"
msgstr "%{extra} weitere Downstream-Pipelines"
@@ -796,6 +798,12 @@ msgstr "%{issuesSize} mit einem Limit von %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Neue Funktionen%{italic_end} ist inaktiv und kann nicht angezeigt werden."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr "%{item_ids} konnte aufgrund unzureichender Berechtigungen nicht entfernt werden"
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr "%{item_ids} konnte aufgrund fehlender Verknüpfung nicht entfernt werden"
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} Tickets mit einem Limit von %{maxIssueCount}"
@@ -871,6 +879,9 @@ msgstr "%{labelStart}Unveränderte Antwort:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} nicht verfügbar"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr "%{label_name} wurde entfernt"
@@ -1319,11 +1330,11 @@ msgstr "%{verb} %{time_spent_value} verbrachte Zeit."
msgid "%{verb} this %{noun} as a draft."
msgstr "%{noun} als Entwurf %{verb}."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} ermöglicht das Senden von Benachrichtigungen an Web-Anwendungen als Reaktion auf Ereignisse in einer Gruppe oder einem Projekt."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} ermöglichen es dir, als Reaktion auf Ereignisse in einer Gruppe oder einem Projekt Benachrichtigungen an Webanwendungen zu senden."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} kannst du Benachrichtigungen an Webanwendungen als Reaktion auf Ereignisse in einer Gruppe oder einem Projekt senden. Wir empfehlen die Verwendung einer %{integrations_link_start}Integration%{link_end} anstelle eines Webhooks."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} ermöglichen es dir, als Reaktion auf Ereignisse in einer Gruppe oder einem Projekt Benachrichtigungen an Webanwendungen zu senden. Wir empfehlen die Verwendung einer %{integrations_link_start}Integration %{integrations_link_end} anstelle eines Webhooks."
msgid "%{widget} options"
msgstr "%{widget} Optionen"
@@ -1429,6 +1440,9 @@ msgstr "+ %{amount} weitere"
msgid "+ %{count} more"
msgstr "+ %{count} weitere"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr "+ %{hiddenBranchesLength} weitere"
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} weitere"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr "KI-generierte Erklärungen werden hier angezeigt."
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr "Ein %{linkStart}Experiment%{linkEnd} ist eine Funktion, die aktuell entwickelt wird. Es ist nicht produktionsreif. Wir freuen uns, wenn Benutzer(innen) die Beta-Funktionen ausprobieren und Feedback geben. Ein Experiment: %{bullets}"
+
msgid "AI|Apply AI-generated description"
msgstr "KI-generierte Beschreibung anwenden"
+msgid "AI|Ask GitLab Duo"
+msgstr "Frag GitLab Duo"
+
msgid "AI|Ask a question"
msgstr "Stelle eine Frage"
msgid "AI|Autocomplete"
msgstr "Autovervollständigung"
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr "Schließe die Code-Erklärung"
@@ -1946,12 +1969,30 @@ msgstr "Ticketbeschreibung generieren"
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr "Erhält keinen Support und ist möglicherweise nicht dokumentiert"
+
msgid "AI|Helpful"
msgstr "Hilfreich"
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr "Ich weiß nicht, wie ich helfen kann. Bitte gib genauere Anweisungen!"
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr "Kann unangemessene Antworten liefern, die nicht den Ansichten von GitLab entsprechen. Gib keine personenbezogenen Daten ein."
@@ -1973,6 +2014,9 @@ msgstr "Chat-Nachricht senden"
msgid "AI|Something went wrong. Please try again later"
msgstr "Etwas ist schiefgelaufen. Bitte versuche es später erneut"
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr "Das Containerelement wurde nicht gefunden; stoppe KI Genie"
@@ -1988,6 +2032,9 @@ msgstr "Diese Funktionen können Leistungs- und Stabilitätsprobleme verursachen
msgid "AI|Third-party AI services"
msgstr "KI-Dienste von Drittanbietern"
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr "Nicht hilfreich"
@@ -2000,6 +2047,9 @@ msgstr "KI-Dienste von Drittanbietern verwenden"
msgid "AI|What does the selected code mean?"
msgstr "Was bedeutet der ausgewählte Code?"
+msgid "AI|What's an Experiment?"
+msgstr "Was ist ein Experiment?"
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr "Schreibe eine kurze Beschreibung und lasse die KI die Details befüllen."
@@ -2012,9 +2062,6 @@ msgstr "Falsch"
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr "Du darfst keinen Teil dieser Ausgabe in Tickets, Kommentare, GitLab-Quellcode, Commit-Nachrichten, Merge Requests oder eine andere Benutzeroberfläche in den Gruppen %{gitlabOrg} oder %{gitlabCom} kopieren."
-msgid "AI|You can ask AI for more information."
-msgstr "Du kannst die KI um weitere Informationen bitten."
-
msgid "AI|finding"
msgstr "Fund"
@@ -2219,9 +2266,6 @@ msgstr "Keine Berichte gefunden"
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr "%{reportLinkStart}Gemeldet%{reportLinkEnd} für %{category} %{timeAgo}."
-msgid "AbuseReport|Abuse reports"
-msgstr "Missbrauchsmeldungen"
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr "Missbrauch nicht bestätigt"
@@ -2336,6 +2380,9 @@ msgstr "Beleidigend oder anstößig"
msgid "AbuseReport|Other"
msgstr "Andere"
+msgid "AbuseReport|Past abuse reports"
+msgstr "Vergangene Missbrauchsberichte"
+
msgid "AbuseReport|Personal information or credentials"
msgstr "Persönliche oder Anmeldeinformationen"
@@ -2393,6 +2440,9 @@ msgstr "Verifizierung"
msgid "AbuseReport|View screenshot"
msgstr "Screenshot anzeigen"
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Einladung annehmen"
@@ -2444,6 +2494,9 @@ msgstr "Gruppen"
msgid "AccessDropdown|Roles"
msgstr "Rollen"
+msgid "AccessDropdown|Select"
+msgstr "Auswählen"
+
msgid "AccessDropdown|Users"
msgstr "Benutzer(innen)"
@@ -2624,6 +2677,9 @@ msgstr "Bestätigung"
msgid "Action"
msgstr "Aktion"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr "Aktion '%{action}' in Registry-Eintrag %{registry_id} wird nicht unterstützt."
@@ -2936,6 +2992,9 @@ msgstr "Vorschlag zum Stapel hinzufügen"
msgid "Add tag"
msgstr "Tag hinzufügen"
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "Text zur Anmeldeseite hinzufügen. Markdown ist aktiviert."
@@ -2960,6 +3019,9 @@ msgstr "Zum Review hinzufügen"
msgid "Add to tree"
msgstr "Zum Verzeichnisbaum hinzufügen"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr "Füge Themen zu Projekten hinzu, damit Benutzer(innen) sie leichter finden können."
@@ -2987,8 +3049,8 @@ msgstr "Hinzufügen/Entfernen"
msgid "AddMember|Invite email is invalid"
msgstr "Einladungs-E-Mail ist ungültig"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "Einladungslimit von %{daily_invites} pro Tag überschritten"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "Einladungen können nicht leer sein"
@@ -3827,8 +3889,8 @@ msgstr "Wenn der/die Benutzer(in) blockiert wird, hat dies folgende Auswirkungen
msgid "AdminUsers|Bot"
msgstr "Bot"
-msgid "AdminUsers|Can create group"
-msgstr "Kann Gruppe erstellen"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "Kann sich nicht anmelden oder auf Instanzinformationen zugreifen"
@@ -4451,6 +4513,9 @@ msgstr "Titel ist ein Pflichtfeld für Warnungen in GitLab. Sollte das von deine
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr "Für die Integration werden eine Webhook-URL und ein Autorisierungsschlüssel generiert. Beide werden nach dem Speichern der Integration auf der Registerkarte „Anmeldeinformationen anzeigen“ angezeigt."
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr "Neue Integration hinzufügen"
@@ -4889,9 +4954,6 @@ msgstr "Beim Abrufen der öffentlichen Bereitstellungsschlüssel ist ein Fehler
msgid "An error occurred previewing the blob"
msgstr "Bei der Vorschau des Blobs ist ein Fehler aufgetreten"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr "Beim Laden der Benutzerüberprüfungs-Anforderung ist ein Fehler aufgetreten. Aktualisiere, um es erneut zu versuchen."
-
msgid "An error occurred when updating the title"
msgstr "Beim Aktualisieren des Titels ist ein Fehler aufgetreten"
@@ -4982,6 +5044,9 @@ msgstr "Beim Abrufen von Tickets ist ein Fehler aufgetreten."
msgid "An error occurred while fetching label colors."
msgstr "Beim Abrufen der Label-Farben ist ein Fehler aufgetreten."
+msgid "An error occurred while fetching labels, please try again."
+msgstr "Beim Abrufen der Labels ist ein Fehler aufgetreten. Bitte versuche es erneut."
+
msgid "An error occurred while fetching participants"
msgstr "Beim Abrufen der Teilnehmer(innen) ist ein Fehler aufgetreten"
@@ -5167,6 +5232,9 @@ msgstr[1] "Beim Speichern der Einstellung ist ein Fehler aufgetreten"
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "Beim Speichern deiner Einstellungen ist ein Fehler aufgetreten. Versuche erneut, sie zu speichern."
+msgid "An error occurred while searching for labels, please try again."
+msgstr "Bei der Suche nach Labeln ist ein Fehler aufgetreten. Bitte versuche es erneut."
+
msgid "An error occurred while triggering the job."
msgstr "Beim Starten des Jobs ist ein Fehler aufgetreten."
@@ -5182,6 +5250,12 @@ msgstr "Beim Versuch, eine neue Pipeline für diesen Merge Request auszuführen,
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr "Beim Versuch, diesem/dieser Benutzer(in) nicht mehr zu folgen, ist ein Fehler aufgetreten. Bitte erneut versuchen."
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "Beim Ändern der Genehmigungsberechtigten ist ein Fehler aufgetreten"
@@ -5292,6 +5366,9 @@ msgstr "Analyseeinstellungen"
msgid "Analytics|A visualization with that name already exists."
msgstr "Es ist bereits eine Visualisierung mit diesem Namen vorhanden."
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr "Visualisierungen hinzufügen"
@@ -5337,15 +5414,18 @@ msgstr "Dashboard-Projekt konfigurieren"
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
+msgid "Analytics|Create your dashboard"
+msgstr ""
+
msgid "Analytics|Custom dashboards"
msgstr "Benutzerdefinierte Dashboards"
-msgid "Analytics|Dashboard Title"
-msgstr "Dashboard-Titel"
-
msgid "Analytics|Dashboard not found"
msgstr "Dashboard nicht gefunden"
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr "Dashboard wurde erfolgreich gespeichert"
@@ -5367,6 +5447,12 @@ msgstr "Daten und Uhrzeiten werden in der UTC-Zeitzone angezeigt"
msgid "Analytics|Edit"
msgstr "Bearbeiten"
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr "Gib einen Visualisierungsnamen ein"
@@ -5382,6 +5468,9 @@ msgstr "Fehler beim Abrufen von Daten"
msgid "Analytics|Host"
msgstr "Host"
+msgid "Analytics|Invalid visualization configuration"
+msgstr "Ungültige Visualisierungskonfiguration"
+
msgid "Analytics|Language"
msgstr "Sprache"
@@ -5424,24 +5513,30 @@ msgstr "Referer"
msgid "Analytics|Resulting Data"
msgstr "Ergebnisdaten"
-msgid "Analytics|Save"
-msgstr "Speichern"
-
msgid "Analytics|Save and add to Dashboard"
msgstr "Speichern und zum Dashboard hinzufügen"
msgid "Analytics|Save new visualization"
msgstr "Neue Visualisierung speichern"
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr "Wähle ein Maß aus"
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr "Wähle einen Visualisierungstyp aus"
msgid "Analytics|Single Statistic"
msgstr "Einzelne Statistik"
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr "Mit deiner Panel-Visualisierungskonfiguration stimmt etwas nicht. Siehe %{linkStart}Dokumentation zur Fehlerbehebung%{linkEnd}."
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr "Beim Herstellen einer Verbindung zu deiner Datenquelle ist ein Fehler aufgetreten. Siehe %{linkStart}Dokumentation zur Fehlerbehebung%{linkEnd}."
@@ -5515,7 +5610,7 @@ msgid "Another issue tracker is already in use. Only one issue tracker service c
msgstr "Ein anderer Ticket-Aufzeichnungs-Dienst wird bereits verwendet. Es kann jedoch nur ein Ticket-Aufzeichnungs-Dienst aktiv sein"
msgid "Another open merge request already exists for this source branch: %{conflicting_mr_reference}"
-msgstr ""
+msgstr "Für diesen Quellbranch ist bereits ein weiterer offener Merge Request vorhanden: %{conflicting_mr_reference}"
msgid "Another third-party wiki is already in use. Only one third-party wiki integration can be active at a time"
msgstr "Es wird bereits ein anderes Wiki eines Drittanbieters verwendet. Es kann jeweils nur eine Drittanbieter-Wiki-Integration aktiv sein"
@@ -6200,9 +6295,6 @@ msgstr "Möchtest du dieses Gerät wirklich löschen? Diese Aktion kann nicht rÃ
msgid "Are you sure you want to delete this label?"
msgstr "Möchtest du dieses Label wirklich löschen?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Bist Du sicher, dass Du diesen Pipeline-Zeitplan löschen möchtest?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "Möchtest du wirklich diese Pipeline löschen? Dabei verfallen alle Pipeline-Caches und alle zugehörigen Objekte, wie Builds, Protokolle, Artefakte und Trigger werden gelöscht. Diese Aktion kann nicht rückgängig gemacht werden."
@@ -6283,8 +6375,8 @@ msgstr "Bist du sicher, dass du den Registrierungstoken zurücksetzen möchtest?
msgid "Are you sure you want to retry this migration?"
msgstr "Bist du sicher, dass du diese Migration erneut versuchen möchtest?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "Willst du diesen %{accessTokenType} wirklich widerrufen? Diese Aktion kann nicht rückgängig gemacht werden."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr "Möchtest du das %{accessTokenType} „%{tokenName}“ wirklich widerrufen? Diese Aktion kann nicht rückgängig gemacht werden."
msgid "Are you sure you want to revoke this SSH key?"
msgstr "Bist du dir sicher, dass du den SSH-Key widerrufen willst?"
@@ -6428,6 +6520,9 @@ msgstr "Komma-separierte Liste von Branches, die automatisch überprüft werden.
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr "Benutzerspezifischer Zugriffstoken. Der/die Benutzer(in) muss Zugriff auf die Aufgabe haben. Alle Kommentare werden diesem/dieser Benutzer(in) zugeschrieben."
+msgid "Ask a maintainer to check the import status for more details."
+msgstr "Bitte eine(n) Betreuer(in), den Importstatus auf weitere Details zu überprüfen."
+
msgid "Ask again later"
msgstr "Frag später noch einmal"
@@ -6638,6 +6733,9 @@ msgstr "Ein Header mit diesem Namen ist bereits vorhanden."
msgid "AuditStreams|Active"
msgstr "Aktiv"
+msgid "AuditStreams|Add a new private key"
+msgstr "Neuen privaten Schlüssel hinzufügen"
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr "Füge einen HTTP-Endpunkt hinzu, um Audit-Logs in Systemen von Drittanbietern zu verwalten."
@@ -6755,6 +6853,9 @@ msgstr "Dies könnte vertrauliche Informationen enthalten. Stelle sicher, dass d
msgid "AuditStreams|This is great for keeping everything one place."
msgstr "Das ist ideal, um alles übersichtlich zu halten"
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr "Verwende die Google Cloud-Konsole, um den privaten Schlüssel anzuzeigen. Um den privaten Schlüssel zu ändern, ersetze ihn durch einen neuen privaten Schlüssel."
+
msgid "AuditStreams|Value"
msgstr "Wert"
@@ -7682,8 +7783,8 @@ msgstr "Beim Laden der GitLab-Abonnementdetails ist ein Fehler aufgetreten."
msgid "Billing|An error occurred while loading billable members list."
msgstr "Beim Laden der Liste der abrechenbaren Mitglieder ist ein Fehler aufgetreten."
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
-msgstr "Beim Laden der Details für das Add-on „Code-Vorschläge“ ist ein Fehler aufgetreten."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "Beim Laden der Details für das Add-on „Code-Vorschläge“ ist ein Fehler aufgetreten. Wenn das Problem weiterhin besteht, %{supportLinkStart}wende dich bitte an den Support%{supportLinkEnd}."
msgid "Billing|An error occurred while loading pending members list"
msgstr "Beim Laden der Liste der ausstehende Mitglieder ist ein Fehler aufgetreten"
@@ -7697,15 +7798,18 @@ msgstr "Anmeldung des Mitglieds ausstehend"
msgid "Billing|Cannot remove user"
msgstr "Benutzer(in) kann nicht entfernt werden"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr "Direkte Mitgliedschaften"
msgid "Billing|Enter at least three characters to search."
msgstr "Mindestens 3 Zeichen eingeben, um zu suchen."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr "Fehler beim Zuweisen des Add-Ons „Code-Vorschläge“"
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr "Fehler beim Aufheben der Zuweisung des Add-Ons „Code-Vorschläge“"
+
msgid "Billing|Explore paid plans"
msgstr "Kostenplichtige Tarife erkunden"
@@ -7723,6 +7827,9 @@ msgstr[1] "Gruppen in der kostenlosen Stufe sind auf %d Plätze begrenzt"
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "Mitglieder, die über eine Gruppeneinladung eingeladen wurden, können nicht entfernt werden. Du kannst entweder die gesamte Gruppe entfernen oder eine(n) Eigentümer(in) der eingeladenen Gruppe bitten, das Mitglied zu entfernen."
+msgid "Billing|No seats available"
+msgstr "Keine Plätze verfügbar"
+
msgid "Billing|No users to display."
msgstr "Keine Benutzer(innen) zum Anzeigen."
@@ -7735,6 +7842,12 @@ msgstr "Projekt-Einladung"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "Benutzer(in) %{username} aus deinem Abonnement entfernen"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr "Ausstehende Genehmigungen anzeigen"
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "Du bist dabei, Benutzer(in) %{username} aus deinem Abonnement zu entfernen. Wenn du fortfährst, wird der/die Benutzer(in) aus der %{namespace} Gruppe und allen seiner Untergruppen und Projekte entfernt. Diese Aktion kann nicht rückgängig gemacht werden."
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr "Du hast alle verfügbaren Plätze für das Add-On „Code-Vorschläge“ zugewiesen. Bitte %{salesLinkStart}wende dich an den Vertrieb%{salesLinkEnd}, wenn du weitere Plätze erwerben möchtest."
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr "Deine Gruppe hat kürzlich zum kostenlosen Tarif gewechselt. %{over_limit_message} Du kannst Platz für neue Mitglieder freimachen, indem du diejenigen entfernst, die keinen Zugang mehr benötigen, oder sie auf „über Limit“ schaltest. Wenn du eine unbegrenzte Anzahl von Mitgliedern haben möchtest, kannst du %{link_start}auf eine kostenpflichtige Stufe upgraden%{link_end}."
@@ -7806,6 +7922,9 @@ msgstr[1] "Blockiert durch %d Aufgaben"
msgid "Blocked issue"
msgstr "Blockiertes Ticket"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr "Gesperrte Workitems sind für den aktuellen Abonnementstarif nicht verfügbar"
+
msgid "Blocking"
msgstr "Blockieren"
@@ -7839,9 +7958,6 @@ msgstr "Keine zutreffenden Ergebnisse"
msgid "BoardNewEpic|Search groups"
msgstr "Gruppen suchen"
-msgid "BoardNewEpic|Select a group"
-msgstr "Gruppe auswählen"
-
msgid "BoardNewIssue|No matching results"
msgstr "Keine zutreffenden Ergebnisse"
@@ -7929,9 +8045,6 @@ msgstr "Label auswählen"
msgid "BoardScope|Select milestone"
msgstr "Meilenstein auswählen"
-msgid "BoardScope|Select weight"
-msgstr "Gewichtung auswählen"
-
msgid "BoardScope|Started"
msgstr "Gestartet"
@@ -8549,7 +8662,7 @@ msgid "BroadcastMessages|Indigo"
msgstr "Indigo"
msgid "BroadcastMessages|Leave blank to target all group and project pages."
-msgstr ""
+msgstr "Leer lassen, um alle Gruppen- und Projektseiten als Ziele zu verwenden."
msgid "BroadcastMessages|Light"
msgstr "Hell"
@@ -8579,16 +8692,16 @@ msgid "BroadcastMessages|Notification"
msgstr "Benachrichtigung"
msgid "BroadcastMessages|One or more roles is required."
-msgstr ""
+msgstr "Eine oder mehrere Rollen sind erforderlich."
msgid "BroadcastMessages|Paths can contain wildcards, like */welcome."
-msgstr ""
+msgstr "Pfade können Platzhalter wie */welcome enthalten."
msgid "BroadcastMessages|Red"
msgstr "Rot"
msgid "BroadcastMessages|Select at least one role."
-msgstr ""
+msgstr "Wähle mindestens eine Rolle aus."
msgid "BroadcastMessages|Show only to users who have specific roles on groups/project pages"
msgstr "Nur für Benutzer anzeigen, die bestimmte Rollen auf Gruppen-/Projektseiten haben"
@@ -9006,8 +9119,8 @@ msgstr "Zugriff %{italicEnd}aus%{italicStart} diesem Projekt beschränken (veral
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr "Zugriff %{italicStart}auf%{italicEnd} dieses Projekt beschränken"
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
-msgstr "Verhindere, dass CI/CD-JOB-Token aus diesem Projekt für den Zugriff auf andere Projekte verwendet werden, es sei denn, das andere Projekt wird der Zulassungsliste hinzugefügt. Es stellt ein Sicherheitsrisiko dar, diese Funktion zu deaktivieren, da nicht autorisierte Projekte versuchen könnten, ein aktives Token abzurufen und auf die API zuzugreifen. %{linkStart}Erfahre mehr.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
+msgstr "Verhindere, dass CI/CD-Job-Token aus diesem Projekt für den Zugriff auf andere Projekte verwendet werden, es sei denn, das andere Projekt wird der Zulassungsliste hinzugefügt. Diese Funktion zu deaktivieren stellt ein Sicherheitsrisiko dar, da nicht autorisierte Projekte versuchen könnten, ein aktives Token abzurufen und auf die API zuzugreifen. %{linkStart}Mehr erfahren%{linkEnd}."
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
msgstr "Verhindere den Zugriff auf dieses Projekt über andere Projekt-CI/CD-JOB-Token, es sei denn, das andere Projekt wird der Zulassungsliste hinzugefügt. Es stellt ein Sicherheitsrisiko dar, diese Funktion zu deaktivieren, da nicht autorisierte Projekte versuchen könnten, ein aktives Token abzurufen und auf die API zuzugreifen. %{linkStart}Erfahre mehr.%{linkEnd}"
@@ -9102,8 +9215,8 @@ msgstr "Die Subdomain %{code_open}.campfirenow.com%{code_close}."
msgid "Can be manually deployed to"
msgstr "Kann manuell bereitgestellt werden für"
-msgid "Can create groups:"
-msgstr "Kann Gruppen erstellen:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr "Primärschulung kann nicht gelöscht werden"
@@ -9489,6 +9602,9 @@ msgstr "Änderungen am Titel wurden nicht gespeichert"
msgid "Changes:"
msgstr "Änderungen:"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr "Das Ändern eines der folgenden Einstellungen erfordert keinen Neustart der Anwendung"
+
msgid "Changing any setting here requires an application restart"
msgstr "Das Ändern einer Einstellung hier erfordert einen Neustart der Anwendung"
@@ -9579,6 +9695,9 @@ msgstr "Überprüfe deine Docker Images auf bekannte Schwachstellen."
msgid "Check your sign-up restrictions"
msgstr "Überprüfe Deine Anmeldebeschränkungen"
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Prüfe %{text} Verfügbarkeit…"
@@ -9637,8 +9756,8 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] "%{quantity} Speicherpaket"
msgstr[1] "%{quantity} Speicherpakete"
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText}-Tarif"
+msgid "Checkout|%{selectedPlanText}"
+msgstr "%{selectedPlanText}"
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr "Vorlage auswählen ..."
msgid "Choose a type..."
msgstr "Typ auswählen..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Datei auswählen…"
@@ -9926,7 +10048,7 @@ msgid "CiCatalog|About this project"
msgstr "Ãœber dieses Projekt"
msgid "CiCatalog|Back to the CI/CD Catalog"
-msgstr ""
+msgstr "Zurück zum CI/CD-Katalog"
msgid "CiCatalog|CI/CD Catalog"
msgstr "CI/CD-Katalog"
@@ -9935,7 +10057,7 @@ msgid "CiCatalog|CI/CD Catalog resource"
msgstr "CI/CD-Katalogressource"
msgid "CiCatalog|Component ID not found, or you do not have permission to access component."
-msgstr ""
+msgstr "Komponenten-ID wurde nicht gefunden oder du hast keine Zugriffsberechtigung für die Komponente."
msgid "CiCatalog|Create a pipeline component repository and make reusing pipeline configurations faster and easier."
msgstr "Erstelle ein Repository für die Pipeline-Komponenten und mache die Wiederverwendung von Pipeline-Konfigurationen schneller und einfacher."
@@ -9956,7 +10078,7 @@ msgid "CiCatalog|Mark project as a CI/CD Catalog resource. %{linkStart}What is t
msgstr "Projekt als CI/CD-Katalogressource markieren. %{linkStart}Was ist der CI/CD-Katalog?%{linkEnd}"
msgid "CiCatalog|No component available"
-msgstr ""
+msgstr "Keine Komponente verfügbar"
msgid "CiCatalog|No release available"
msgstr "Keine Veröffentlichung verfügbar"
@@ -10093,15 +10215,15 @@ msgstr "CI/CD-Variablen"
msgid "CiVariables|Cancel"
msgstr "Abbrechen"
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "Maskierte Variable kann mit dem aktuellem Wert nicht verwendet werden"
-
msgid "CiVariables|Delete variable"
msgstr "Variable löschen"
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr "Möchtest du die Variable %{key} löschen?"
+msgid "CiVariables|Edit Variable"
+msgstr "Variable bearbeiten"
+
msgid "CiVariables|Environments"
msgstr "Umgebungen"
@@ -10153,9 +10275,6 @@ msgstr "Eingaben entfernen"
msgid "CiVariables|Remove variable"
msgstr "Variable entfernen"
-msgid "CiVariables|Remove variable row"
-msgstr "Variable jetzt löschen"
-
msgid "CiVariables|Run job"
msgstr "Job ausführen"
@@ -10177,12 +10296,24 @@ msgstr "Es gab einen Fehler beim Abrufen der geerbten CI-Variablen."
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr "Diese %{entity} hat %{currentVariableCount} definierte CI/CD-Variablen. Die maximale Anzahl an Variablen pro %{entity} ist %{maxVariableLimit}. Um neue Variablen hinzuzufügen, musst du die Anzahl der definierten Variablen reduzieren."
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Typ"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Wert"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr "Variablen speichern Informationen wie Passwörter und geheime Schlüssel
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr "Du hast die maximale Anzahl verfügbarer Variablen erreicht. Um neue Variablen hinzuzufügen, musst Du die Anzahl der definierten Variablen reduzieren."
-msgid "CiVariable|* (All environments)"
-msgstr "* (Alle Umgebungen)"
-
msgid "CiVariable|All environments"
msgstr "Alle Umgebungen"
@@ -10211,7 +10339,7 @@ msgid "CiVariable|Define a CI/CD variable in the UI"
msgstr "Definiere eine CI/CD-Variable in der Benutzeroberfläche"
msgid "CiVariable|GitLab CI/CD supports OpenID Connect (OIDC) to give your build and deployment jobs access to cloud credentials and services. %{linkStart}How do I configure OIDC for my cloud provider?%{linkEnd}"
-msgstr ""
+msgstr "GitLab CI/CD unterstützt OpenID Connect (OIDC), um deinen Build- und Bereitstellungsjobs Zugriff auf Cloud-Zugangsdaten und -Dienste zu gewähren. %{linkStart}Wie kann ich OIDC für meinen Cloud-Anbieter konfigurieren?%{linkEnd}"
msgid "CiVariable|Maximum of %{limit} environments listed. For more environments, enter a search query."
msgstr "Maximale Anzahl (%{limit}) der Umgebungen aufgelistet. Nutze eine Suchanfrage, um weitere Umgebungen zu erhalten."
@@ -10223,7 +10351,7 @@ msgid "CiVariable|Search environments"
msgstr "Umgebungen durchsuchen"
msgid "CiVariable|Use OIDC to securely connect to cloud services"
-msgstr ""
+msgstr "OIDC verwenden, um eine sichere Verbindung zu Cloud-Diensten herzustellen"
msgid "CiVariable|Variable %{key} has been deleted."
msgstr "Die Variable %{key} wurde gelöscht."
@@ -10359,6 +10487,9 @@ msgstr "Kunden"
msgid "Clientside DSN"
msgstr "Clientseitiger DSN"
+msgid "Clientside traces sample rate"
+msgstr "Sample-Rate für clientseitige Traces"
+
msgid "Clone"
msgstr "Klonen"
@@ -10656,15 +10787,9 @@ msgstr "Cluster-Zustand"
msgid "Cluster cache cleared."
msgstr "Cluster-Cache geleert."
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr "Cluster ist erforderlich für Stages::ClusterEndpointInserter"
-
msgid "Cluster level"
msgstr "Cluster-Level"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr "Cluster-Typ muss für Phasen::ClusterEndpointInserter angegeben werden"
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr "%{linkStart}In der Dokumentation%{linkEnd} findest du weitere Infos zur erweiterten Installation. Vergewissere dich, dass du dein Zugriffstoken zur Verfügung hast."
@@ -10955,6 +11080,9 @@ msgstr "Dieser Agent hat keine Token"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "Um den Agenten zu entfernen, gib zur Bestätigung %{name} ein:"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr "%{linkStart}Nutze Terraform%{linkEnd}, um weitere Agenten zu verwalten."
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr "Um den Token zu widerrufen, gib zur Bestätigung %{name} ein:"
@@ -10979,6 +11107,9 @@ msgstr "Alle %{number} Agenten anzeigen"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "Alle %{number} Cluster anzeigen"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr "Wir unterstützen nur 100 Agenten auf der Benutzeroberfläche."
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "Wir würden uns sehr freuen, mehr über deine Erfahrungen mit dem GitLab-Agenten zu erfahren."
@@ -11402,9 +11533,6 @@ msgstr "Code Review"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "Code-Überprüfung-Analytik zeigt eine Tabelle offener Merge Requests an, die als in Code-Überprüfung gekennzeichnet sind. Derzeit gibt es keine Merge Requests für dieses Projekt und/oder Filter."
-msgid "Code Suggestions add-on"
-msgstr "Add-On „Code-Vorschläge“"
-
msgid "Code Suggestions add-on status"
msgstr "Status des Add-Ons „Code-Vorschläge“"
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr "Gib ein neues persönliches Zugriffstoken ein"
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
-msgstr ""
-
-msgid "CodeSuggestionsSM|Personal access token"
-msgstr "Persönliches Zugriffstoken"
-
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
-msgstr "%{code_suggestions_link_start}Codevorschläge%{link_end} nutzt jetzt KI-Dienste von Drittanbietern, um noch bessere Vorschläge zu machen. Du kannst %{third_party_link_start}Dienste von Drittanbietern%{link_end} für deine Gruppe blockieren oder Codevorschläge in %{profile_settings_link_start}deinem Benutzerprofil%{link_end} ganz deaktivieren."
-
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
-msgstr "Wir nutzen KI-Dienste von Drittanbietern, um Codevorschläge zu verbessern."
-
msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr "%{link_start}Was sind Codevorschläge?%{link_end}"
msgid "CodeSuggestions|Code Suggestions"
msgstr "Codevorschläge"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
+msgstr ""
+
msgid "CodeSuggestions|Enable Code Suggestions"
msgstr "Code-Vorschläge aktivieren"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
+msgstr ""
+
msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgstr "Erhalte Codevorschläge, während du Code in deiner IDE schreibst. %{link_start}Mehr erfahren%{link_end}."
+
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
+msgstr "Einführung zur Erweiterung „Code-Vorschläge“"
+
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr "Benutzerkohorten werden für die letzten %{months_included} Monate angez
msgid "Collapse"
msgstr "Reduzieren"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr "Alle Threads einklappen"
@@ -11928,9 +12056,6 @@ msgstr "Beim Laden der Branch-/Tag-Liste ist ein Fehler aufgetreten. Bitte versu
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "Beim Durchsuchen der Branch/Tag-Liste ist ein Fehler aufgetreten. Bitte versuche es erneut."
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "Beim Aktualisieren der Branch/Tag-Liste ist ein Fehler aufgetreten. Bitte versuche es erneut."
-
msgid "CompareRevisions|View open merge request"
msgstr "Offene Merge Request anzeigen"
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr "Compliance Framework"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr "Aktive Konformitäts-Frameworks"
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Framework hinzufügen"
@@ -12033,8 +12161,8 @@ msgstr "Fehler beim Abrufen von Compliance-Frameworks-Daten. Bitte aktualisiere
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr "Fehler beim Setzen der Standard-Compliance-Frameworks"
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
-msgstr "Hinzugefügte Frameworks werden hier angezeigt"
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr "Hinzugefügte Frameworks werden hier angezeigt. Erstelle zunächst oben ein neues Framework."
msgid "ComplianceFrameworks|Invalid format"
msgstr "Ungültiges Format"
@@ -12157,7 +12285,7 @@ msgid "ComplianceReport|No projects found that match filters"
msgstr "Keine Projekte gefunden, die den Filtern entsprechen"
msgid "ComplianceReport|No projects with standards adherence checks found"
-msgstr ""
+msgstr "Keine Projekte mit Prüfungen zur Einhaltung von Normen gefunden"
msgid "ComplianceReport|No violations found"
msgstr "Keine Verstöße gefunden"
@@ -12249,15 +12377,18 @@ msgstr "Vertraulichkeit"
msgid "Configuration help"
msgstr "Konfigurationshilfe"
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "Konfigurieren von Aussehen und Inhalt der Box %{italic_start}Neue Funktionen%{italic_end}."
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
-msgstr "Konfiguriere %{link}, um Ereignisse zu verfolgen. %{link_start}Mehr erfahren.%{link_end}"
-
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr "Konfiguriere %{repository_checks_link_start}Repository-Prüfungen%{link_end} und %{housekeeping_link_start}Housekeeping%{link_end} für Repositorys."
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr "Konfiguriere %{snowplow_link_start}Snowplow%{snowplow_link_end}, um Ereignisse nachzuverfolgen. %{help_link_start}Mehr erfahren.%{help_link_end}"
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr "Konfiguriere CAPTCHAs, IP-Adressbeschränkungen und andere Anti-Spam-Maßnahmen."
@@ -12321,6 +12452,9 @@ msgstr "Konfiguriere erweiterte Berechtigungen, Large File Storage, Zwei-Faktor-
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr "Konfiguriere erweiterte Berechtigungen, Speicherung großer Dateien, Zwei-Faktor-Authentifizierung sowie die Einstellungen für Kund(inn)enbeziehungen."
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr "Konfiguriere benutzerdefinierte Regeln für den Abgleich von Jira-Tickets"
@@ -12492,6 +12626,9 @@ msgstr "Verbindungsfehler"
msgid "Consistency guarantee method"
msgstr "Konsistenzgarantiemethode"
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "Support kontaktieren"
@@ -12620,7 +12757,7 @@ msgid "ContainerRegistry|Created %{time}"
msgstr "Erstellt %{time}"
msgid "ContainerRegistry|Delete image repository"
-msgstr ""
+msgstr "Image-Repository löschen"
msgid "ContainerRegistry|Delete image repository?"
msgstr "Bildersammlung löschen?"
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr "Genehmigte Merge Requests %{targetLink} in %{resourceParentLink}."
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr "Archivierter Entwurf in %{resourceParentLink}."
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr "Epic geschlossen %{targetLink}in %{resourceParentLink}."
@@ -13047,6 +13187,30 @@ msgstr "Epic geschlossen %{targetLink}in %{resourceParentLink}."
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr "Testfall geschlossen %{targetLink}in %{resourceParentLink}."
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr "%{noteableLink} kommentiert."
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr "Epic %{noteableLink} in %{resourceParentLink} kommentiert."
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr "Commit %{noteableLink} in %{resourceParentLink} kommentiert."
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr "Design %{noteableLink} in %{resourceParentLink} kommentiert."
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr "Ticket %{noteableLink} in %{resourceParentLink} kommentiert."
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr "Merge Request %{noteableLink} in %{resourceParentLink} kommentiert."
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr "Code-Schnipsel %{noteableLink} in %{resourceParentLink} kommentiert."
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr "Code-Schnipsel %{noteableLink} kommentiert."
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr "Gelöschter Branch %{refLink} in %{resourceParentLink}."
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr "Gelöschter Meilenstein in %{resourceParentLink}."
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr "Gelöschter Tag %{refLink} in %{resourceParentLink}."
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr "Gelöschte Wiki-Seite in %{resourceParentLink}."
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr "Projekt %{resourceParentLink} beigetreten."
@@ -13117,37 +13290,46 @@ msgid "ContributionEvent|Removed due to membership expiration from %{resourcePar
msgstr "Aufgrund des Ablaufs der Mitgliedschaft von %{resourceParentLink} entfernt."
msgid "ContributionEvent|Reopened Epic %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Epic %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened incident %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Vorfall %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened issue %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Ticket %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened key result %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Schlüsselergebnis %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened merge request %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Merge Request %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened milestone %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Meilenstein %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened objective %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Ziel %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened requirement %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Anforderung %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened resource."
-msgstr ""
+msgstr "Ressource erneut geöffnet."
msgid "ContributionEvent|Reopened task %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Aufgabe %{targetLink} in %{resourceParentLink} erneut geöffnet."
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "Testfall %{targetLink} in %{resourceParentLink} erneut geöffnet."
+
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr "Design %{targetLink} in %{resourceParentLink} aktualisiert."
+
+msgid "ContributionEvent|Updated resource."
+msgstr "Ressource aktualisiert."
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr "Wiki-Seite %{targetLink} in %{resourceParentLink} aktualisiert."
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr "… und %{count} weitere Commits. %{linkStart}Vergleichen%{linkEnd}."
@@ -13681,7 +13863,7 @@ msgid "Create phone verification exemption"
msgstr ""
msgid "Create pipeline trigger token"
-msgstr ""
+msgstr "Pipeline-Trigger-Token erstellen"
msgid "Create project"
msgstr "Projekt anlegen"
@@ -13695,6 +13877,9 @@ msgstr "Release erstellen"
msgid "Create requirement"
msgstr "Anforderung erstellen"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr "Neues Service-Konto hinzufügen"
@@ -13918,7 +14103,7 @@ msgid "Created %{timeAgo} by %{author}"
msgstr "Erstellt %{timeAgo} von %{author}"
msgid "Created %{timeAgo} by %{email} via %{author}"
-msgstr ""
+msgstr "Erstellt %{timeAgo} von %{email} über %{author}"
msgid "Created %{time_ago}"
msgstr "Erstellt %{time_ago}"
@@ -14073,9 +14258,6 @@ msgstr "Organisation wurde hinzugefügt."
msgid "Crm|Organization has been updated."
msgstr "Organisation wurde aktualisiert."
-msgid "Cron Timezone"
-msgstr "Cron-Zeitzone"
-
msgid "Cron time zone"
msgstr "Cron Zeitzone"
@@ -14414,9 +14596,6 @@ msgstr "Zeit zur Wiederherstellung des Dienstes"
msgid "CycleAnalytics|Total time"
msgstr "Gesamtzeit"
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "Gruppen-Dropdown-Filter"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr "nicht erlaubt für das angegebene Startereignis"
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr "Durchsatz der Merge Requests"
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr "Metrikvergleich für das Projekt %{name}"
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr "Metrikvergleich für die Gruppe %{name}"
@@ -14632,10 +14814,10 @@ msgid "DORA4Metrics|Show forecast"
msgstr "Prognose anzeigen"
msgid "DORA4Metrics|Some metric charts failed to load"
-msgstr ""
+msgstr "Fehler beim Laden einiger Metrik-Diagramme"
msgid "DORA4Metrics|Some metric comparisons failed to load"
-msgstr ""
+msgstr "Fehler beim Laden einiger Metrik-Vergleiche"
msgid "DORA4Metrics|Something went wrong while getting change failure rate data."
msgstr "Beim Abrufen der Daten zur Änderungsfehlerrate ist etwas schiefgelaufen."
@@ -14682,6 +14864,9 @@ msgstr "Zeit bis zur Wiederherstellung des Dienstes (mittlere Anzahl an Tagen)"
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr "Minimum = 0 (kein Timeout aktiviert), Maximum = 2880 Minuten"
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "Minimum = 1 Sekunde, Maximum = 3600 Sekunden"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr "Wenn du die URL änderst, werden alle zuvor eingegebenen Werte für die zusätzlichen Anfrage-Header und Passwort-Felder gelöscht."
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr "Überwacht alle an das Ziel gesendeten HTTP-Anforderungen, um mögliche Schwachstellen zu finden."
@@ -15401,7 +15589,7 @@ msgid "DefaultBranchProtection|Protected against pushes"
msgstr "Geschützt vor Pushs"
msgid "Define a custom deploy freeze pattern with %{cronSyntaxStart}cron syntax%{cronSyntaxEnd}."
-msgstr ""
+msgstr "Definiere ein benutzerdefiniertes Bereitstellungs-Freeze-Muster mit %{cronSyntaxStart}Cron-Syntax%{cronSyntaxEnd}."
msgid "Define a custom pattern with cron syntax"
msgstr "Erstelle ein benutzerdefiniertes Muster mittels Cron-Syntax"
@@ -15409,9 +15597,6 @@ msgstr "Erstelle ein benutzerdefiniertes Muster mittels Cron-Syntax"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr "Definiere benutzerdefinierte Regeln für das, was Spam ausmacht, unabhängig von Akismet"
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "Definiere Umgebungen in der/den Bereitstellungsphase(n) in %{code_open}.gitlab-ci.yml%{code_close}, um Bereitstellungen hier nachzuverfolgen."
-
msgid "Define how approval rules are applied to merge requests."
msgstr "Definiere, wie Genehmigungsregeln auf Merge Requests angewendet werden."
@@ -15534,9 +15719,6 @@ msgstr "Etikett löschen: %{labelName}"
msgid "Delete pipeline"
msgstr "Pipeline löschen"
-msgid "Delete pipeline schedule"
-msgstr "Pipeline-Zeitplan löschen"
-
msgid "Delete project"
msgstr "Projekt löschen"
@@ -15757,6 +15939,9 @@ msgstr "Speicherort und Abhängigkeitspfade"
msgid "Dependencies|Packager"
msgstr "Packer"
+msgid "Dependencies|Project list unavailable"
+msgstr "Projektliste nicht verfügbar"
+
msgid "Dependencies|Projects"
msgstr "Projekte"
@@ -15775,6 +15960,9 @@ msgstr "Der Komponentenabhängigkeitspfad basiert auf der Sperrdatei. Es kann me
msgid "Dependencies|There may be multiple paths"
msgstr "Möglicherweise gibt es mehrere Pfade"
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr "Diese Gruppe überschreitet die maximale Anzahl von Untergruppen in Höhe von 600. Zurzeit können wir keine genaue Projektliste anzeigen. Rufe die Abhängigkeitenliste einer Untergruppe auf, um diese Informationen anzuzeigen, oder lies die Hilfeseite zur %{linkStart}Abhängigkeitenliste%{linkEnd}, um mehr zu erfahren."
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "Liste der Sicherheitslücken umschalten"
@@ -15938,7 +16126,7 @@ msgid "DeployFreeze|Deploy freeze from %{start} to %{end} in %{timezone} will be
msgstr "Einfrieren der Bereitstellung von %{start} bis %{end} %{timezone} wird entfernt. Bist du dir sicher?"
msgid "DeployFreeze|Deploy freezes"
-msgstr ""
+msgstr "Bereitstellungs-Freezes"
msgid "DeployFreeze|Freeze end"
msgstr "Bereitstellung einfrieren"
@@ -15947,7 +16135,7 @@ msgid "DeployFreeze|Freeze start"
msgstr "Einfrieren Beginn"
msgid "DeployFreeze|No deploy freezes exist for this project. To add one, select %{strongStart}Add deploy freeze%{strongEnd} above."
-msgstr ""
+msgstr "Für dieses Projekt gibt es keine Bereitstellungs-Freezes. Wähle oben %{strongStart}Bereitstellungs-Freeze hinzufügen%{strongEnd} aus, um ein Bereitstellungs-Freeze hinzuzufügen."
msgid "DeployFreeze|Specify deploy freezes using %{cron_syntax_link_start}cron syntax%{cron_syntax_link_end}."
msgstr "Gib Deploy-Freezes mit %{cron_syntax_link_start}cron syntax%{cron_syntax_link_end} an."
@@ -15958,6 +16146,12 @@ msgstr "Zeitzone"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} andere"
+msgid "DeployKeys|Add new deploy key"
+msgstr "Neuen Bereitstellungsschlüssel hinzufügen"
+
+msgid "DeployKeys|Add new key"
+msgstr "Neuen Schlüssel hinzufügen"
+
msgid "DeployKeys|Current project"
msgstr "Aktuelles Projekt"
@@ -15985,8 +16179,8 @@ msgstr "Schreibrechte für diesen Schlüssel gewähren"
msgid "DeployKeys|Loading deploy keys"
msgstr "Lade Bereitstellungsschlüssel"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "Keine Bereitstellungsschlüssel gefunden. Erstelle einem mit dem Formular oben."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr "Keine Bereitstellungsschlüssel gefunden. Füge zunächst oben einen neuen hinzu."
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "Privat zugängliche Bereitstellungsschlüssel"
@@ -16000,8 +16194,8 @@ msgstr "Öffentlich zugängliche Bereitstellungsschlüssel"
msgid "DeployKeys|Read access only"
msgstr "Nur Lesezugriff"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "Aktive Bereitstellungstoken (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr "Aktive Bereitstellungstoken"
msgid "DeployTokens|Allows read and write access to registry images."
msgstr "Ermöglicht Lese- und Schreibzugriff auf Registry-Images."
@@ -16024,6 +16218,9 @@ msgstr "Ermöglicht schreibgeschützten Zugriff auf das Repository."
msgid "DeployTokens|Allows write access to registry images."
msgstr "Ermöglicht Schreibzugriff auf Registry-Images."
+msgid "DeployTokens|Cancel"
+msgstr "Abbrechen"
+
msgid "DeployTokens|Copy deploy token"
msgstr "BereitstellungsToken kopieren"
@@ -16084,8 +16281,8 @@ msgstr "Gültigkeitsbereiche"
msgid "DeployTokens|Scopes (select at least one)"
msgstr "Gültigkeitsbereiche (wähle mindestens einen)"
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
-msgstr "Diese %{entity_type} hat keine aktiven Deploy-Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
+msgstr "Diese(r) %{entity_type} hat keine aktiven Bereitstellungstoken."
msgid "DeployTokens|This action cannot be undone."
msgstr "Diese Aktion kann nicht rückgängig gemacht werden."
@@ -16102,12 +16299,12 @@ msgstr "Benutzername"
msgid "DeployTokens|Username (optional)"
msgstr "Benutzername (optional)"
-msgid "DeployTokens|Your New Deploy Token"
-msgstr "Dein neues Bereitstellungstoken"
-
msgid "DeployTokens|Your new Deploy Token username"
msgstr "Dein neuer Bereitstellungs-Token Nutzername"
+msgid "DeployTokens|Your new deploy token"
+msgstr "Dein neues Bereitstellungstoken"
+
msgid "DeployTokens|Your new group deploy token has been created."
msgstr "Dein neues Gruppenbereitstellungstoken wurde erstellt."
@@ -16189,6 +16386,12 @@ msgstr "Von dir genehmigt %{time}"
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr "Durch das Genehmigen wird der manuelle Job der Bereitstellung %{deploymentIid} ausgeführt. Ablehnung führt zum Fehlschlagen des manuellen Jobs."
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr "Bereitstellungsstufe: %{tier}"
@@ -16260,9 +16463,6 @@ msgstr "Definiere Umgebungen in der/den Bereitstellungsphase(n) in der Datei %{c
msgid "Deployments|You don't have any deployments right now."
msgstr "Du hast derzeit keine Deployments."
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "Abgebrochen"
@@ -16275,6 +16475,24 @@ msgstr "Bereitstellungs-ID"
msgid "Deployment|Failed"
msgstr "Fehlgeschlagen"
+msgid "Deployment|Flux sync failed"
+msgstr "Flux-Synchronisierung fehlgeschlagen"
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr "Flux-Synchronisierung erfolgreich abgeglichen"
+
+msgid "Deployment|Flux sync reconciling"
+msgstr "Flux-Synchronisierungsabgleich"
+
+msgid "Deployment|Flux sync stalled"
+msgstr "Flux-Synchronisierung blockiert"
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr "Flux-Synchronisierungsstatus ist nicht verfügbar"
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr "Flux-Synchronisierungsstatus ist unbekannt"
+
msgid "Deployment|Latest Deployed"
msgstr "Zuletzt bereitgestellt"
@@ -16290,12 +16508,15 @@ msgstr "Ãœbersprungen"
msgid "Deployment|Success"
msgstr "Erfolg"
-msgid "Deployment|This deployment was created using the API"
-msgstr "Diese Bereitstellung wurde mithilfe der API erstellt"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr "Der Synchronisierungsstatus ist unbekannt. %{linkStart}Wie kann ich Flux für meine Bereitstellung konfigurieren?%{linkEnd}"
msgid "Deployment|Triggerer"
msgstr "Auslöser"
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr "Status kann nicht erkannt werden. %{linkStart}Wie werden Zustände erkannt?%{linkEnd}"
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr "Design"
msgid "Design Management files and data"
msgstr "Designmanagement Dateien und Daten"
-msgid "Design repositories"
-msgstr "Repositorys entwerfen"
-
-msgid "Design repository"
-msgstr "Repository entwerfen"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} von %{designs_count}"
@@ -17565,9 +17780,6 @@ msgstr "E-Mail verschickt"
msgid "Email the pipeline status to a list of recipients."
msgstr "Sende den Pipeline-Status an eine Liste von Empfängern."
-msgid "Email updates (optional)"
-msgstr "Email Update (optional)"
-
msgid "Email:"
msgstr "E-Mail:"
@@ -17610,6 +17822,9 @@ msgstr "%{emails}, %{andMore} werden über deinen Kommentar benachrichtigt."
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "und %{moreCount} mehr"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr "Aktualisiere deine E-Mail auf eine gültige dauerhafte Adresse. Wenn du eine temporäre E-Mail verwendest, kannst du dich später nicht mehr anmelden."
+
msgid "Emails"
msgstr "E-Mails"
@@ -17748,9 +17963,6 @@ msgstr "Aktiviere Gruppen-Runners"
msgid "Enable header and footer in emails"
msgstr "Kopf- und Fußzeile in E-Mails aktivieren"
-msgid "Enable in-product marketing emails"
-msgstr "Produkt-Marketing E-Mailsb erhalten"
-
msgid "Enable incident management inbound alert limit"
msgstr "Eingehendes Alarmlimit für Vorfallmanagement aktivieren"
@@ -17772,8 +17984,8 @@ msgstr "Nur für vertrauliche Anwendungen aktivieren, die ausschließlich von ei
msgid "Enable or disable version check and Service Ping."
msgstr "Versionsprüfung und den Service Ping aktivieren oder deaktivieren."
-msgid "Enable rate limiting for POST requests to the specified paths"
-msgstr "Aktiviere die Begrenzung der Abfrageraten für POST-Anfragen auf die angegebenen Pfade."
+msgid "Enable rate limiting for requests to the specified paths"
+msgstr ""
msgid "Enable reCAPTCHA"
msgstr "reCAPTCHA aktivieren"
@@ -17886,9 +18098,6 @@ msgstr "Zwei-Faktor-Authentifizierung für alle Benutzeranmeldungen erzwingen."
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr "Verbessere die Sicherheit durch Speicherung von Service-Account-Schlüsseln in Geheimnis-Managern. Mehr darüber erfährst du unter %{docLinkStart}Geheimnismanagement mit GitLab%{docLinkEnd}"
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr "Stelle sicher, dass deine %{linkStart}Umgebung Teil der Bereitstellungsphase%{linkEnd} deiner CI-Pipeline ist, um Bereitstellungen in deinem Cluster nachzuverfolgen."
@@ -18000,8 +18209,8 @@ msgstr "Umgebung"
msgid "Environment scope"
msgstr "Umgebungsumfang"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr "Umgebungsvariablen auf dieser GitLab-Instanz sind standardmäßig auf %{link_start}geschützt%{link_end} gesetzt."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr "Umgebungsvariablen auf dieser GitLab-Instanz sind standardmäßig %{help_link_start}geschützt%{help_link_end}."
msgid "Environment:"
msgstr "Umgebung:"
@@ -18147,12 +18356,18 @@ msgstr "Erste Schritte mit Umgebungen"
msgid "Environments|GitLab agent"
msgstr "GitLab-Agent"
+msgid "Environments|HelmReleases"
+msgstr "HelmReleases"
+
msgid "Environments|Job"
msgstr "Job"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr "Kustomizations"
+
msgid "Environments|Learn more about stopping environments"
msgstr "Erfahre mehr über das Stoppen von Umgebungen"
@@ -18198,6 +18413,12 @@ msgstr "Umgebung %{name} zurücksetzen?"
msgid "Environments|Search by environment name"
msgstr "Suche nach Umgebungsnamen"
+msgid "Environments|Select Flux resource"
+msgstr "Flux-Ressource auswählen"
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr "Flux-Ressource auswählen (optional)"
+
msgid "Environments|Select agent"
msgstr "Agent auswählen"
@@ -18234,6 +18455,9 @@ msgstr "Diese Aktion wird mit der Commit-ID %{commitId}, für diese Umgebung, %{
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr "Diese Aktion führt einen %{docsStart}Rollback dieser Umgebung%{docsEnd} auf eine zuvor erfolgreiche Bereitstellung für den Commit %{commitId} durch. Möchtest du wirklich fortfahren?"
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr "Aus dieser Umgebung hast du keinen Zugriff auf die folgenden Ressourcen. Überprüfe deine Genehmigung auf Folgendes und versuche es erneut:"
+
msgid "Environments|Upcoming"
msgstr "Anstehend"
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr "Es gab einen Fehler beim Abrufen von %{resourceType}."
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr "Aus dieser Umgebung hast du keinen Zugriff auf %{resourceType}."
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr "Vorhandene Anmeldemethoden können entfernt werden"
msgid "Expand"
msgstr "Aufklappen"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Alle erweitern"
@@ -19337,6 +19570,9 @@ msgstr "https://example.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr "Fehlschlag"
@@ -19426,13 +19662,13 @@ msgid "Failed to create resources"
msgstr "Fehler beim Erstellen der Ressourcen"
msgid "Failed to create target branch rule"
-msgstr ""
+msgstr "Fehler beim Erstellen der Zielbranch-Regel"
msgid "Failed to create wiki"
msgstr "Wiki konnte nicht erstellt werden"
msgid "Failed to delete custom emoji. Please try again."
-msgstr ""
+msgstr "Benutzerdefiniertes Emoji konnte nicht gelöscht werden. Bitte erneut versuchen."
msgid "Failed to deploy to"
msgstr "Bereitstellung fehlgeschlagen für"
@@ -19994,9 +20230,6 @@ msgstr "Filtere nach Testfällen, die derzeit archiviert sind."
msgid "Filter by test cases that are currently open."
msgstr "Filtere nach Testfällen, die derzeit offen sind."
-msgid "Filter by user"
-msgstr "Filtere nach Benutzer(in)"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr "Filterparameter sind nicht gültig. Stelle sicher, dass das Enddatum nach dem Startdatum liegt."
@@ -20021,9 +20254,6 @@ msgstr "Ergebnisse filtern …"
msgid "Filter users"
msgstr "Benutzer(innen) filtern"
-msgid "Filter..."
-msgstr "Filter..."
-
msgid "Finalizing"
msgstr "Finalisieren"
@@ -20392,33 +20622,6 @@ msgstr "Freie Gruppen auf oberster Stufe werden demnächst auf %{free_users_limi
msgid "Free trial will expire in %{days}"
msgstr "Die kostenlose Testversion läuft in %{days} ab"
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "Alternativ kannst du auf GitLab Premium oder GitLab Ultimate upgraden:"
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "Kostenpflichtige Tarife erkunden"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "Kostenpflichtige Tarife erkunden:"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr "Laut unserer Prüfung am %{date_time} hast du das Limit von %{free_user_limit} Mitgliedern für „%{namespace_name}“ erreicht. Du kannst keine weiteren Mitglieder hinzufügen, aber du kannst die vorhandenen Mitglieder verwalten, z. B. indem du inaktive Mitglieder entfernst und durch neue Mitglieder ersetzt."
-
-msgid "FreeUserCap|Manage members"
-msgstr "Mitglieder verwalten"
-
-msgid "FreeUserCap|Manage members:"
-msgstr "Mitglieder verwalten:"
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr "Um mehr Mitglieder zu erhalten, %{trial_link_start}probiere die Testversion%{trial_link_end} aus oder %{upgrade_link_start}upgrade%{upgrade_link_end} auf GitLab Premium oder GitLab Ultimate."
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr "Um mehr Mitglieder zu erhalten, probiere die Testversion aus:"
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr "Du hast das Mitgliederlimit erreicht!"
-
msgid "Freeze end"
msgstr "Ende einfrieren"
@@ -20754,7 +20957,7 @@ msgid "Geo|Last event ID from primary"
msgstr "Letzte Ereignis-ID von primär"
msgid "Geo|Last event ID processed"
-msgstr ""
+msgstr "Letzte verarbeitete Ereignis-ID"
msgid "Geo|Last repository check run"
msgstr "Letzte Repository-Überprüfung"
@@ -21113,6 +21316,12 @@ msgstr "Erhalte eine kostenlose Instanzprüfung"
msgid "Get a support subscription"
msgstr "Hole dir ein Support-Abonnement"
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Loslegen"
@@ -21440,6 +21649,9 @@ msgstr "Ungeprüft"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Deine Pages-Konfiguration wird aktualisiert..."
+msgid "GitLabPages|Use multiple versions"
+msgstr "Verwende mehrere Versionen"
+
msgid "GitLabPages|Use unique domain"
msgstr "Verwende eine eindeutige Domain"
@@ -21455,6 +21667,9 @@ msgstr "Wenn aktiviert, wird eine eindeutige Domain für den Zugriff auf Pages g
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr "Wenn aktiviert, werden alle Versuche, deine Website über HTTP zu besuchen, automatisch mit einer Antwort mit dem Statuscode 301 auf HTTPS umgeleitet. Benötigt ein gültiges Zertifikat für alle Domänen. %{docs_link_start}Erfahre mehr.%{link_end}"
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr "Wenn dies aktiviert ist, kannst du mehrere Versionen deiner Seiten erstellen"
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr "GitLabPages|Bei der Verwendung von Seiten unter der allgemeinen Domain einer GitLab-Instanz (%{pages_host}) kannst du HTTPS nicht mit Subdomains von Subdomains verwenden. Wenn dein Namespace oder Gruppenname einen Punkt enthält, funktioniert er nicht. Dies ist eine Einschränkung des HTTP Over TLS-Protokolls. HTTP-Seiten funktionieren, wenn du HTTP nicht zu HTTPS weiterleitest. %{docs_link_start}Mehr erfahren.%{link_end}"
@@ -21470,12 +21685,6 @@ msgstr "Dein Projekt wurde für Pages konfiguriert. Jetzt müssen wir warten, bi
msgid "Gitaly Servers"
msgstr "Gitaly-Server"
-msgid "Gitaly relative path:"
-msgstr "Gitaly relativer Pfad:"
-
-msgid "Gitaly storage name:"
-msgstr "Gitaly Speichername:"
-
msgid "Gitaly timeouts"
msgstr "Gitaly-Zeitüberschreitungen"
@@ -21596,8 +21805,8 @@ msgstr "Die URL zu deiner Gitpod-Instanz, die zum Lesen deiner GitLab-Projekte k
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr "Um Gitpod zu verwenden, musst du die Funktion zuerst im Abschnitt „Integrationen“ in deinen %{linkStart}Benutzereinstellungen%{linkEnd} aktivieren."
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
-msgstr "Um die Integration zu verwenden, müssen alle Benutzer(innen) Gitpod in ihren GitLab-Konten aktivieren. %{link_start}Wie funktioniert die Aktivierung?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr "Um die Integration zu verwenden, müssen alle Benutzer(innen) Gitpod in ihren GitLab-Konten aktivieren. %{help_link_start}Wie funktioniert die Aktivierung?%{help_link_end}"
msgid "Gitpod|https://gitpod.example.com"
msgstr "https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr "Zugriff vor %{time_ago} gewährt"
msgid "Given epic is already related to this epic."
msgstr "Das gegebene Epic ist bereits mit diesem Epic verwandt."
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr "Bei Eingaben, die nicht im Abschnitt „spec“ der einbezogenen Konfigurationsdatei definiert sind"
+
msgid "Global SAML group membership lock"
msgstr "Globale SAML-Gruppenmitgliedschaftssperre"
@@ -21635,6 +21847,9 @@ msgstr " %{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr "%{count} Standard-Ergebnisse gefunden. Verwende die Aufwärts- und Abwärtspfeiltasten, um durch die Ergebnisliste zu navigieren."
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr "Die %{link_start}exakte Codesuche (powered by Zoekt)%{link_end} ist aktiviert"
+
msgid "GlobalSearch|Aggregations load error."
msgstr "Fehler beim Laden von Aggregationen."
@@ -21647,6 +21862,9 @@ msgstr "Schließen"
msgid "GlobalSearch|Fetching aggregations error."
msgstr "Aggregationsfehler werden abgerufen."
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "Gruppe"
@@ -21716,9 +21934,6 @@ msgstr "Suche"
msgid "GlobalSearch|Search GitLab"
msgstr "GitLab durchsuchen"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr "Suche GitLab %{kbdOpen}/%{kbdClose}"
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "Suche nach Projekten, Tickets, etc."
@@ -21749,6 +21964,9 @@ msgstr "Beim Abrufen der Vorschläge zur Autovervollständigung der Suche ist ei
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr "Beim Abrufen des Dokuments „Syntax-Optionen“ ist ein Fehler aufgetreten."
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr "Zu suchender %{kbdOpen}/%{kbdClose} Typ"
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "Gib Text ein und drücke die Eingabetaste, um die Suche auszuführen."
@@ -21771,13 +21989,13 @@ msgid "GlobalSearch|in %{scope}"
msgstr "in %{scope}"
msgid "GlobalShortcuts|Copied reference to clipboard."
-msgstr ""
+msgstr "Referenz wurde in die Zwischenablage kopiert."
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr "Quellbranch Name wurde in die Zwischenablage kopiert."
msgid "GlobalShortcuts|Unable to copy the reference at this time."
-msgstr ""
+msgstr "Die Referenz kann derzeit nicht kopiert werden."
msgid "GlobalShortcuts|Unable to copy the source branch name at this time."
msgstr "Der Name der Quellbranch konnte dieses Mal nicht kopiert werden."
@@ -21989,6 +22207,12 @@ msgstr "GoogleCloud|Berechtigungen widerrufen"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "GoogleCloud|Widerrufe GitLab gewährte Autorisierungen. Dienstkonten werden dadurch nicht ungültig."
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr "Lege Variablen nur für geschützte Branches und Tags fest"
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr "Nur geschützte Branches und Tags"
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr "Ziehe deine Schlüsseldatei hierher oder %{linkStart}klicke zum Hochladen%{linkEnd}."
@@ -22004,8 +22228,8 @@ msgstr "Google Play"
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr "Leer lassen, um Ihren aktuellen Dienstkontoschlüssel zu verwenden."
-msgid "GooglePlay|Service account key (.json)"
-msgstr "Dienstkontoschlüssel (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
+msgstr "Dienstkontoschlüssel (.JSON)"
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
msgstr "Lade einen neuen Dienstkontoschlüssel hoch (ersetze %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr "Gruppenavatar"
msgid "Group by"
msgstr "Gruppieren nach"
+msgid "Group by:"
+msgstr "Gruppieren nach:"
+
msgid "Group description (optional)"
msgstr "Gruppenbeschreibung (optional)"
@@ -22181,9 +22408,6 @@ msgstr "Gruppenname (deine Organisation)"
msgid "Group navigation"
msgstr "Gruppennavigation"
-msgid "Group overview"
-msgstr "Gruppenübersicht"
-
msgid "Group overview content"
msgstr "Inhalt der Gruppenübersicht"
@@ -22559,8 +22783,8 @@ msgstr "Wähle die Merge Request-Prüfungen für Projekte in dieser Gruppe aus.
msgid "GroupSettings|Compliance frameworks"
msgstr "Compliance-Frameworks"
-msgid "GroupSettings|Configure analytics features for this group"
-msgstr "Analysefunktionen für diese Gruppe konfigurieren"
+msgid "GroupSettings|Configure analytics features for this group."
+msgstr "Konfiguriere Analysefunktionen für diese Gruppe."
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
msgstr "Konfiguriere Compliance-Frameworks, um sie Projekten in dieser Gruppe zur Verfügung zu stellen. %{linkStart}Was sind Compliance-Frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr "Dieses Feature erfordert einen Browser, der LocalStorage unterstützt"
msgid "GroupsDropdown|Toggle edit mode"
msgstr "Bearbeitungsmodus umschalten"
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr "Eine Gruppe ist eine Ansammlung mehrerer Projekte."
msgid "GroupsEmptyState|Create new project"
@@ -22760,8 +22984,8 @@ msgstr "Neue Untergruppe erstellen"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "Gruppen sind die beste Möglichkeit, mehrere Projekte und Mitglieder zu verwalten."
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Wenn du deine Projekte in einer Gruppe organisierst, funktioniert dies wie ein Ordner."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr "Wenn du deine Projekte in einer Gruppe organisierst, fungiert diese als Ordner. Du kannst die Berechtigungen deiner Gruppenmitglieder und den Zugriff auf jedes Projekt in der Gruppe verwalten."
msgid "GroupsEmptyState|No archived projects."
msgstr "Keine archivierten Projekte."
@@ -22778,9 +23002,6 @@ msgstr "Keine Untergruppen oder Projekte."
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "Projekte sind der Ort, an dem du deinen Code speichern, auf Tickets, Wiki und andere Funktionen von Gitlab zugreifen kannst."
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "Du kannst die Berechtigungen deiner Gruppenmitglieder und den Zugriff auf jedes Projekt in der Gruppe verwalten."
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "Du hast nicht die erforderlichen Berechtigungen, um eine Untergruppe oder ein Projekt in dieser Gruppe zu erstellen. Bitte kontaktiere eine(n) Eigentümer(in) dieser Gruppe, um eine neue Untergruppe oder ein Projekt zu erstellen."
@@ -23202,6 +23423,9 @@ msgstr "Hilf mit, GitLab in deine Sprache zu übersetzen"
msgid "Help translate to your language"
msgstr "Hilf mit, in deine Sprache zu übersetzen "
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr "Verhindert, dass Bots Brute-Force-Angriffe ausführen."
@@ -23465,9 +23689,6 @@ msgstr "Ich möchte meinen Code ablegen"
msgid "I want to use GitLab CI with my existing repository"
msgstr "Ich möchte GitLab CI mit meinem bestehenden Repository verwenden"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "Ich möchte Updates über GitLab per E-Mail erhalten"
-
msgid "I'm signing up for GitLab because:"
msgstr "Ich melde mich aus folgenden Gründen bei GitLab an:"
@@ -23507,6 +23728,12 @@ msgstr "Diese Option ist deaktiviert, da du nicht berechtigt bist, Merge Request
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr "Diese Option ist deaktiviert, da du keine Schreibrechte für den aktuellen Branch hast."
+msgid "IDs with errors: %{error_messages}."
+msgstr "IDs mit Fehlern: %{error_messages}."
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr "WICHTIG: Verwende diese Einstellung nur für SEHR strenge Auditing-Zwecke. Wenn sie aktiviert ist, kann niemand das Label von Merge Requests entfernen, nachdem sie zusammengeführt wurden. Außerdem kann niemand diese Einstellung deaktivieren oder dieses Label löschen."
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "INFO: Dein SSH-Schlüssel ist abgelaufen. Bitte generiere einen neuen Schlüssel."
@@ -23690,6 +23917,12 @@ msgstr "Zahlungsmethode verifizieren"
msgid "IdentityVerification|Verify phone number"
msgstr "Telefonnummer verifizieren"
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr "Willst du dich stattdessen mit einer Kreditkarte verifizieren?"
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr "Willst du dich stattdessen mit einer Telefonnummer verifizieren?"
+
msgid "IdentityVerification|Verify your identity"
msgstr "Verifiziere deine Identität"
@@ -24101,8 +24334,8 @@ msgstr "Beim Abrufen der Importdetails ist ein Fehler aufgetreten."
msgid "Import|GitHub import details"
msgstr "GitHub-Importdetails"
-msgid "Import|Maximum decompressed size (MiB)"
-msgstr "Maximale dekomprimierte Größe (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
+msgstr "Maximale dekomprimierte Dateigröße für Archive aus Importen (MiB)"
msgid "Import|Maximum import remote file size (MB)"
msgstr "Maximale Import-Remote-Dateigröße (MB)"
@@ -24128,6 +24361,12 @@ msgstr "Das Repository konnte nicht importiert werden."
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr "Es gibt kein gültiges Git-Repository unter dieser URL. Falls dein HTTP-Repository nicht öffentlich zugänglich ist, überprüfe deine Zugangsdaten."
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr "Timeout für die Dekomprimierung archivierter Dateien (Sekunden)"
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr "Timeout für die Dekomprimierung archivierter Dateien."
+
msgid "Improve customer support with Service Desk"
msgstr "Verbessere den Kundensupport mit Service-Desk"
@@ -24170,381 +24409,72 @@ msgstr "In Benutzung"
msgid "InProductMarketing|%{organization_name} logo"
msgstr "Logo von %{organization_name}"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr "%{strong_start}Erweiterte Anwendungssicherheit%{strong_end} – einschließlich SAST-, DAST-Scans, FUZZ-Tests, Abhängigkeits-Scans, Lizenz-Compliance, Secret-Erkennung"
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr "%{strong_start}Unternehmensweites Portfoliomanagement%{strong_end} — einschließlich mehrstufiger Epics, Labels mit Geltungsbereich"
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr "%{strong_start}Executive Level Einblicke%{strong_end} — einschließlich Berichte über Produktivität, Aufgaben nach Typ, Tage bis zur Fertigstellung, Value-Stream"
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr "%{strong_start} GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr "%{strong_start}Mehrere Genehmigungsrollen%{strong_end} — einschließlich Code-Eigentümer(in) und erforderliche Merge-Genehmigungen"
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr "*GitLab*, Substantiv: ein Synonym für effiziente Teams"
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...und du erhältst eine kostenlose Testversion von GitLab Ultimate"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr "3 Möglichkeiten, GitLab CI/CD kennenlernen"
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr "Eigentlich sorgt GitLab dafür, dass das Team (besser) arbeitet"
-
msgid "InProductMarketing|Advanced security testing"
msgstr "Erweiterte Sicherheitstests"
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr "Und schließlich %{deploy_link} eine Python-Anwendung."
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "Sind deine Runner bereit?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr "Automatisierte Sicherheitsscans direkt in GitLab"
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "Sei ein(e) DevOps-Held(in)"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr "Erhöhe deine Sicherheit"
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "Besserer Code in kürzerer Zeit"
-
msgid "InProductMarketing|Blog"
msgstr "Blog"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr "iOS Entwickler? Bei uns bist du an der richtigen Adresse."
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr "Durch die Aktivierung von Code-Eigentümern und erforderlichen Merge-Genehmigungen wird die richtige Person die richtige MR überprüfen. Das ist eine Win-Win-Situation: saubererer Code und ein effizienterer Überprüfungsprozess."
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr "Code-Eigentümer(in) und erforderliche Merge-Genehmigungen sind Teil der bezahlten Stufen von GitLab. Du kannst eine kostenlose 30-Tage-Testversion von GitLab Ultimate starten und diese Funktionen in weniger als 5 Minuten ohne Kreditkarte aktivieren."
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr "Erstelle mit nur wenigen Klicks einen benutzerdefinierten CI-Runner"
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr "Erstelle einen benutzerdefinierten Runner"
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "Projekt in GitLab in 5 Minuten erstellen"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "Erstelle dein erstes Projekt!"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr "Bessere Produkte schneller liefern"
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr "Wusstest du, dass Teams mit GitLab viel effizienter arbeiten?"
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr "Lege los und erstelle ein Projekt und ein Repository."
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr "Kennst du einen Teamkollegen, der für diese Aufgabe perfekt wäre?"
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr "Erweitere deine DevOps-Reise mit einer kostenlosen GitLab-Testversion"
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "Erkunde GitLab CI/CD"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "Erkunde die Optionen"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr "Entdecke die Leistungsfähigkeit von GitLab CI / CD"
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr "Fühlst du das Bedürfnis nach Geschwindigkeit?"
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr "Überblicke den tatsächlichen Fortschritt deiner Teams."
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "Folge unseren Schritten"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "Kostenlose 30-Tage-Testversion"
msgid "InProductMarketing|Free guest users"
msgstr "Kostenlose Gastbenutzer(innen)"
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr "Schneller Einstieg in CI/CD mit unserem %{quick_start_link}. Beginne mit einem verfügbaren Runner und erstelle dann eine CI-.yml-Datei – so einfach ist das."
-
-msgid "InProductMarketing|Get our import guides"
-msgstr "Entdecke unsere Import-Anleitungen"
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr "Bereite dich auf die Erstellung für iOS vor"
-msgid "InProductMarketing|Get started today"
-msgstr "Starte noch heute"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr "Starte noch heute mit einer 30-tägigen GitLab-Ultimate-Testversion – keine Kreditkarte erforderlich."
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr "Erste Schritte mit GitLab CI / CD"
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr "Lerne GitLab CI/CD kennen"
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr "Richte dein Team auf GitLab ein"
-
-msgid "InProductMarketing|Git basics"
-msgstr "Git Grundlagen"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr "GitHub-Enterprise-Projekte nach GitLab"
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr "GitLab bietet statische Anwendungssicherheitstests (SAST), dynamische Anwendungssicherheitstests (DAST), Container-Scans und Abhängigkeits-Scans, um dich bei der Bereitstellung sicherer Anwendungen und der Lizenzkonformität zu unterstützen."
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr "Die CI/CD-Funktionen von GitLab erleichtern die Softwareentwicklung. Du glaubst uns nicht? Mit den folgenden drei Möglichkeiten kannst du es im Handumdrehen selbst ausprobieren (und genießen):"
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr "Die GitLab-Premiumstufen bieten mehr Effizienz und Sicherheit für dich, dein Team und deine Anwendung. Mit den Premiumstufen erhältst du unter anderem die folgenden Funktionen:"
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "Gib uns eine Minute..."
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr "Erreiche mehr mit GitLab"
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr "Goldman Sachs hat sich von einem Build alle zwei Wochen zu Tausenden Builds pro Tag verbessert."
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr "Hast du eine andere Instanz, die du importieren möchtest? Hier ist unser %{import_link}."
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr "Hier ist, was du wissen musst"
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr "Wie (und warum) Spiegeln Sinn macht"
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr "Wie lange brauchen wir, um Tickets/MRs in den Bereichen Funktionsanfragen, Bugs, technische Schulden oder Sicherheit zu schließen?"
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr "Wie viele Tage braucht unser Team, um bestimmte Aufgaben zu erledigen?"
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr "Schnelleres Erstellen und Testen"
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr "Wenn du keine Marketing-E-Mails von GitLab erhalten möchtest: %{marketing_preference_link}."
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr "Wenn du keine Marketing-E-Mails mehr von uns erhalten möchtest,"
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr "Importiere dein Projekt und deinen Code aus GitHub, Bitbucket und anderen Lösungen."
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr "Verbessere deine App-Sicherheit mit einer 30-tägigen Testversion."
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr "Verbessere die Codequalität und vereinfache Reviews."
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr "Steigerung der betrieblichen Effizienz"
-msgid "InProductMarketing|Invite them to help out."
-msgstr "Lade sie ein, dir zu helfen."
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr "Lade unbegrenzt viele Kollegen und Kolleginnen ein"
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "Lade deine Kolleg(inn)en ein und liefere deinen Code schneller aus."
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "Lade deine Kolleg(inn)en in dazu ein, in weniger als einer Minute beizutreten."
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "Lade deine Kolleg(inn)en noch heute ein."
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "Lade dein Team in weniger als 60 Sekunden ein."
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "Lade dein Team jetzt ein."
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr "Lade dein Team noch heute ein, um gemeinsam besseren Code (und Prozesse) zu erstellen"
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr "Die Statistiken lügen nicht."
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr "Es ist auch möglich, einfach %{external_repo_link} zu verwenden, um die CI/CD von GitLab zu nutzen."
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr "GitLab CI/CD in 20 Minuten oder weniger starten"
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr "Erfahre, wie du für iOS entwickeln kannst"
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr "Wie wäre es mit einem Wechsel? Es ist einfacher als du denkst, deine Projekte nach GitLab zu importieren. Nutze die Funktionen zum Verschieben %{github_link} oder Importieren %{bitbucket_link}."
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr "Werde Importkünstler(in)!"
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr "Erstelle mühelos eine Pages-Website: %{ci_template_link}."
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr "Mehrere Eigentümer(innen), verwirrende Arbeitsabläufe? Wir helfen dir weiter."
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr "Brauchst du eine Alternative zum Importieren?"
-
msgid "InProductMarketing|No credit card required."
msgstr "Keine Kreditkarte erforderlich."
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr "Unser Tool bringt alles unter ein Dach."
-
msgid "InProductMarketing|Portfolio management"
msgstr "Portfolio-Management"
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr "Schnelle und einfache Entwicklung"
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr "Sicherheits- und Compliance-Risiken reduzieren"
msgid "InProductMarketing|Security risk mitigation"
msgstr "Minderung des Sicherheitsrisikos"
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr "In den Entwicklungslebenszyklus integrierte Sicherheit"
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr "Manchmal ist ein vollständiger Umstieg auf ein neues Tool zu kompliziert. Wenn du nicht bereit bist, dich vollständig zu binden, kannst du %{mirroring_link} nutzen, um GitLab risikofrei parallel zu deinem aktuellen Tool auszuprobieren."
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr "Setze einen automatisch skalierenden Runner in GitLab auf"
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "Starte noch heute in weniger als einer Minute eine GitLab-Ultimate-Testversion – keine Kreditkarte erforderlich."
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr "Starte eine selbstverwaltete Testversion"
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "Starte eine kostenlose Testversion von GitLab Ultimate – keine Kreditkarte erforderlich"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "Kostenlose Testversion starten"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "Beginne wie folgt: %{performance_link}"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "Importiere zunächst deine Projekte."
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "Starte mit einer kostenlosen Testversion von GitLab Ultimate."
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "Starte jetzt die Testversion!"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr "Starte deine Testversion noch heute, um den Erfolg einer einzelnen Anwendung zu erleben und alle Funktionen von GitLab Ultimate kostenlos zu entdecken!"
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr "Nutze GitLab, um Fragen zu beantworten, wie etwa:"
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr "Vereinfache Code-Reviews, überblicke jederzeit die Verfügbarkeit aller Beteiligten, kommuniziere mit Kommentaren oder E-Mails und nutze die Slack-Integration, um dein Team zu synchronisieren."
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr "Entdecke GitLab."
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr "Erlebe die nächste Generation von Quellcodeverwaltung."
-
msgid "InProductMarketing|Team members collaborating"
msgstr "Zusammenarbeitende Teammitglieder"
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr "Verbünde dich in GitLab für mehr Effizienz"
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr "Teamarbeit macht den Traum wahr"
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr "Testen, erstellen, bereitstellen"
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr "Mehr brauchst du nicht, um mit GitLab loszulegen. Falls du jedoch noch nie mit Git gearbeitet hast, findest du unter %{basics_link} hilfreiche Tipps und Tricks für den Einstieg."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr "Dies ist die E-Mail Nummer %{current_series} von %{total_series} in der %{track}-Reihe."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr "Dies ist die E-Mail Nummer %{current_series} von %{total_series} in der %{track}-Reihe. Wende dich an deine(n) Administrator(in) oder nutze den Link zum %{unsubscribe_link}, um Benachrichtigungs-E-Mails von deiner lokalen GitLab-Instanz zu deaktivieren."
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr "Ticketmaster konnte die CI-Builddauer um den Faktor 15 reduzieren."
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr "Du hast es satt, mit unterschiedlichen Toolketten, Informationssilos und ineffizienten Prozessen zu kämpfen? Das CI/CD von GitLab basiert auf einer DevOps-Plattform mit Quellcodeverwaltung, Planung, Überwachung und mehr. Finde es heraus %{ci_link}."
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr "Um diese E-Mails abzulehnen, klicke hier: %{unsubscribe_link}."
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr "Um GitLab kennenzulernen und optimal zu nutzen, solltest du zunächst %{project_link}. Repositorys in GitLab sind Teil eines Projekts. Nachdem du also dein Projekt erstellt hast, kannst du %{repo_link}."
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "Probiere GitLab Ultimate kostenlos aus."
-
-msgid "InProductMarketing|Try it out"
-msgstr "Probiere es aus"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "Probiere selbst"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr "Verwandle Mitarbeiter in Mitstreiter"
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr "Mehr zum Thema Repository-Spiegelung"
-
-msgid "InProductMarketing|Understand your project options"
-msgstr "Mehr zu deinen Projektoptionen"
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr "GitLab CI/CD verwenden"
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr "Verwende unsere AWS-Cloudformation-Vorlage, um deine Runner mit nur wenigen Klicks aufzusetzen!"
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr "Wird von mehr als 100.000 Unternehmen aus der ganzen Welt verwendet:"
@@ -24560,66 +24490,15 @@ msgstr "Möchtest du GitLab auf deinen Servern hosten?"
msgid "InProductMarketing|Watch iOS building in action."
msgstr "Sieh dir iOS-Veröffentlichungen in Aktion an."
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr "Was Effizienz angeht, kennen wir uns aus, und dieses Wissen teilen wir gerne. Melde dich für eine kostenlose Testversion von GitLab Ultimate an, damit deine Teams vom ersten Tag an dabei sind."
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr "Wie sieht die Zeitleiste unserer Wertschöpfungskette vom Produkt über Entwicklung und Review bis hin zum Produktionseinsatz aus?"
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr "Wenn dein Team mit GitLab arbeitet, sind diese Antworten nur einen Klick entfernt."
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr "Mehr Effizienz mit GitLab"
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr "Deine Teams können effizienter sein"
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "Umfassende Anleitung"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "Externes Repository verbinden"
-
-msgid "InProductMarketing|create a project"
-msgstr "Ein Projekt erstellen"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "von Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "Gehe zu about.gitlab.com"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "Müheloser Einstieg"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "Schnellstartanleitung"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "Repository-Spiegelung"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "Repository einrichten"
-
-msgid "InProductMarketing|test and deploy"
-msgstr "testen und bereitstellen"
-
-msgid "InProductMarketing|testing browser performance"
-msgstr "Browser-Performance testen"
-
msgid "InProductMarketing|unsubscribe"
msgstr "abmelden"
-msgid "InProductMarketing|update your preferences"
-msgstr "deine Einstellungen aktualisieren"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr "eine CI/CD-Vorlage verwenden"
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "Du kannst jederzeit %{unsubscribe_link}."
@@ -25049,6 +24928,16 @@ msgstr "In der Reihe"
msgid "Inline math"
msgstr "Inline-Mathematik"
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] "1 Codequalität-Fund erkannt"
+msgstr[1] "%d Codequalität-Funde erkannt"
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] "1 SAST-Fund erkannt"
+msgstr[1] "%d SAST-Funde erkannt"
+
msgid "Input host keys manually"
msgstr "Gib die Host-Schlüssel manuell ein"
@@ -25405,6 +25294,9 @@ msgstr "ZenTao-Tickets werden hier angezeigt, wenn du Tickets in deinem Projekt
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr "können nicht %{recipients_limit} überschreiten"
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr "Branches, für die Benachrichtigungen gesendet werden sollen"
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr "IntelliJ IDEA (HTTPS)"
@@ -25441,15 +25333,9 @@ msgstr "Interne Benutzer(innen) können nicht deaktiviert werden"
msgid "Interval"
msgstr "Intervall"
-msgid "Interval Pattern"
-msgstr "Intervallmuster"
-
msgid "Introducing Your DevOps Reports"
msgstr "Wir stellen vor: Deine DevOps-Berichte"
-msgid "Introducing the Code Suggestions add-on"
-msgstr "Einführung zur Erweiterung „Code-Vorschläge“"
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr "Ungültige Tags"
msgid "Invalid two-factor code."
msgstr "Ungültiger Zwei-Faktor-Code."
-msgid "Invalid yaml"
-msgstr "Ungültiges YAML"
-
msgid "Invalidated"
msgstr "ungültig gemacht"
@@ -25866,18 +25749,12 @@ msgstr "hat alle Threads aufgelöst"
msgid "IssuableEvents|unassigned"
msgstr "Nicht zugewiesen"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type} erstellt %{created_at} von "
-
msgid "IssuableStatus|Closed"
msgstr "Geschlossen"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Geschlossen (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "Erstellt %{created_at} von"
-
msgid "IssuableStatus|duplicated"
msgstr "Duplikat"
@@ -26127,29 +26004,49 @@ msgstr "Tickets ohne Epic-Zuordnung"
msgid "Issues, merge requests, pushes, and comments."
msgstr "Tickets, Merge Requests, Pushes und Kommentare."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "Sobald du Tickets für deine Projekte erstellst, können wir dafür Metriken erfassen und anzeigen"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Durchschnitt/Monat:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr "Tickets erstellt"
msgid "IssuesAnalytics|Issues created per month"
msgstr "Erstellte Tickets pro Monat"
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "Letzten 12 Monate"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr "Letzte 12 Monate (%{chartDateRange})"
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Dein Filter hat leider keine Ergebnisse geliefert"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "Es gibt keine Tickets für die Projekte in deiner Gruppe"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "Um deine Suche auszuweiten, ändere oder entferne Filter in der Filterleiste oben"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr "Um deine Suche zu erweitern, ändere oder entferne die Filter in der Filterleiste oben."
msgid "IssuesAnalytics|Total:"
msgstr "Insgesamt:"
@@ -26196,6 +26093,9 @@ msgstr "Kursiv (%{modifierKey}I)"
msgid "Italic text"
msgstr "Kursiver Text"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr "Element mit ID: %{id} kann nicht hinzugefügt werden. Du hast nicht die Berechtigung, diese Aktion auszuführen."
+
msgid "Iteration"
msgstr "Iteration"
@@ -26532,6 +26432,9 @@ msgstr "Keine Gruppen gefunden."
msgid "JiraConnect|No linked groups"
msgstr "Keine verknüpften Gruppen"
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr "Du kannst deine Gruppen nicht sehen? Hier können nur Gruppen angezeigt werden, auf die du Zugriff hast."
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr "Siehst du deine Gruppen nicht? Hier werden nur Gruppen angezeigt, für die du mindestens die Rolle „Betreuer(in)“ hast."
@@ -27030,6 +26933,9 @@ msgstr "Dauer"
msgid "Job|Erase job log and artifacts"
msgstr "Job-Protokoll und Artefakte löschen"
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr "Fehlgeschlagen"
@@ -27081,6 +26987,9 @@ msgstr "Erneut versuchen"
msgid "Job|Run again"
msgstr "Erneut ausführen"
+msgid "Job|Runner type"
+msgstr "Runner-Typ"
+
msgid "Job|Running"
msgstr "Läuft"
@@ -27177,9 +27086,6 @@ msgstr "Einem Projekt beitreten"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr "Tritt deinem Team auf GitLab bei und trage zu einem bestehenden Projekt bei."
-msgid "Joined %{time_ago}"
-msgstr "%{time_ago} beigetreten"
-
msgid "Joined %{user_created_time}"
msgstr "Vor %{user_created_time} beigetreten"
@@ -27442,9 +27348,6 @@ msgstr "Letzte Aktivität"
msgid "Last Name"
msgstr "Nachname"
-msgid "Last Pipeline"
-msgstr "Letzte Pipeline"
-
msgid "Last Seen"
msgstr "Zuletzt angesehen am"
@@ -27541,6 +27444,9 @@ msgstr "Du hast gepusht zu"
msgid "LastPushEvent|at"
msgstr "am"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "Letzte Änderungen"
@@ -27602,7 +27508,7 @@ msgid "Learn more about Needs relationships"
msgstr "Erfahre mehr über Needs-Beziehungen."
msgid "Learn more about Service Desk"
-msgstr ""
+msgstr "Erfahre mehr über den Service-Desk"
msgid "Learn more about Web Terminal"
msgstr "Erfahre mehr über das Web-Terminal"
@@ -28242,6 +28148,9 @@ msgstr "%{issuableType} sperren"
msgid "Lock File?"
msgstr "Datei sperren?"
+msgid "Lock label after a merge request is merged"
+msgstr "Label sperren, nachdem ein Merge Request zusammengeführt wurde"
+
msgid "Lock memberships to LDAP synchronization"
msgstr "Beschränke Mitgliedschaften auf die LDAP-Synchronisierung"
@@ -28251,6 +28160,9 @@ msgstr "Sperre Mitgliedschaften für die Synchronisierung von SAML-Gruppenlinks"
msgid "Lock not found"
msgstr "Sperrung nicht gefunden"
+msgid "Lock on merge"
+msgstr "Sperren beim Zusammenführen"
+
msgid "Lock status"
msgstr "Sperrstatus"
@@ -28285,7 +28197,7 @@ msgid "LoggedOutMarketingHeader|About GitLab"
msgstr "Ãœber GitLab"
msgid "LoggedOutMarketingHeader|Contact Sales"
-msgstr ""
+msgstr "Vertrieb kontaktieren"
msgid "LoggedOutMarketingHeader|Explore GitLab"
msgstr "GitLab erkunden"
@@ -28315,7 +28227,7 @@ msgid "LoggedOutMarketingHeader|Talk to an expert"
msgstr "Sprich mit einem Experten/einer Expertin"
msgid "LoggedOutMarketingHeader|Why GitLab"
-msgstr ""
+msgstr "Gründe, die für GitLab sprechen"
msgid "Login with smartcard"
msgstr "Mit Smartcard einloggen"
@@ -28656,6 +28568,12 @@ msgstr "Mattermost-URL:"
msgid "Mattermost notifications"
msgstr "Mattermost-Benachrichtigungen"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr "Zu Mattermost hinzufügen"
@@ -28671,6 +28589,9 @@ msgstr "Füllen das Wort ein, das für dein Team am besten funktioniert."
msgid "MattermostService|Install"
msgstr "Installieren"
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr "Request URL"
@@ -28683,6 +28604,9 @@ msgstr "Antwort Icon"
msgid "MattermostService|Response username"
msgstr "Antwort-Benutzername"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr "Vorschläge:"
@@ -28989,6 +28913,102 @@ msgstr "%{member_name} hat dich eingeladen, GitLab beizutreten"
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr "Einladung zum Beitritt zu %{project_or_group} %{project_or_group_name}"
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr "%{requirement} muss aktiviert sein, um %{permission} zu aktivieren."
@@ -29247,6 +29267,9 @@ msgstr "Merge Commit-Nachricht"
msgid "Merge conflicts"
msgstr "Merge-Konflikte"
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr "Details des Merges"
@@ -29679,9 +29702,6 @@ msgstr "Metriken und Profiling"
msgid "Metrics:"
msgstr "Metriken:"
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr "kann nicht vor dem Start_at time sein"
-
msgid "Metrics|Create metric"
msgstr "Metrik erstellen"
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr "Synchronisiere Gruppenmitgliedschaften von Microsoft Azure, wenn die SAML-Antwort einen Überschussanspruch enthält."
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,12 +30681,12 @@ msgstr "Welche Aktionen werden eingeschränkt?"
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr "Du nutzt %{used_storage_percentage} des Speicherkontingents für %{name_with_link} (%{current_size} von %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
+msgstr ""
+
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr "Du nutzt %{used_storage_percentage} des Speicherkontingents für %{name} (%{current_size} von %{limit})."
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
-msgstr "Du nutzt %{used_storage_percentage} %% des Speicherkontingents für %{namespace_name}"
-
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
msgstr "Ausstehende Benutzer(innen) müssen von einem/einer Gruppeneigentümer(in) überprüft und genehmigt werden. Erfahre mehr über %{user_caps_link_start}Benutzerobergrenzen%{link_end} und %{users_pending_approval_link_start}Benutzer(innen) mit ausstehender Genehmigung%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr "Analysieren"
msgid "Navigation|Build"
msgstr "Build"
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr "Code"
@@ -30769,15 +30795,18 @@ msgstr "Gruppen, die du oft besuchst, werden hier angezeigt."
msgid "Navigation|Leave admin mode"
msgstr "Adminmodus verlassen"
-msgid "Navigation|Main navigation"
-msgstr "Hauptnavigation"
-
msgid "Navigation|Manage"
msgstr "Verwalten"
+msgid "Navigation|Merge requests settings"
+msgstr ""
+
msgid "Navigation|Monitor"
msgstr "Ãœberwachen"
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr "Keine Gruppentreffer gefunden"
@@ -30796,12 +30825,18 @@ msgstr "Angeheftet"
msgid "Navigation|Plan"
msgstr "Planen"
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr "Projekte"
msgid "Navigation|Projects you visit often will appear here."
msgstr "Projekte, die du oft besuchst, werden hier angezeigt."
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr "Suchergebnisse abrufen"
@@ -30820,6 +30855,12 @@ msgstr "Beim Abrufen der Suchergebnisse ist ein Fehler aufgetreten."
msgid "Navigation|Unpin item"
msgstr "Element lösen"
+msgid "Navigation|View all my groups"
+msgstr "Alle meine Gruppen anzeigen"
+
+msgid "Navigation|View all my projects"
+msgstr "Alle meine Projekte anzeigen"
+
msgid "Navigation|View all your groups"
msgstr "Alle deine Gruppen anzeigen"
@@ -31044,9 +31085,6 @@ msgstr "Neue Antwort bei Ticket #%{issue_iid}:"
msgid "New runners registration token has been generated!"
msgstr "Neues Registrierungstoken für Runner wurde generiert!"
-msgid "New schedule"
-msgstr "Neuer Zeitplan"
-
msgid "New snippet"
msgstr "Neuer Code-Schnipsel"
@@ -31254,6 +31292,9 @@ msgstr "Neue Iteration"
msgid "No label"
msgstr "Kein Etikett"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "Keine Labels mit einem solchen Namen oder einer solchen Beschreibung"
@@ -31278,6 +31319,12 @@ msgstr "Keine passenden Ergebnisse"
msgid "No matching results for \"%{query}\""
msgstr "Keine passenden Ergebnisse für „%{query}“"
+msgid "No matching work item found."
+msgstr "Kein passendes Workitem gefunden."
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr "Kein passendes Workitem gefunden. Stelle sicher, dass du eine gültige ID hinzugefügt und Zugriff auf das Item hast."
+
msgid "No members found"
msgstr "Keine Mitglieder gefunden"
@@ -31296,12 +31343,15 @@ msgstr "Kein Meilenstein"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr "Es können nicht mehr als %{max_issues} Tickets gleichzeitig aktualisiert werden. "
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr "Es können nicht mehr als %{max_work_items} Workitems gleichzeitig geändert werden."
+
+msgid "No options found"
+msgstr ""
+
msgid "No other labels with such name or description"
msgstr "Keine anderen Labels mit einem solchen Namen oder einer solchen Beschreibung"
-msgid "No panels matching properties %{opts}"
-msgstr "Keine Panels mit den Eigenschaften %{opts}"
-
msgid "No parent group"
msgstr "Keine übergeordnete Gruppe"
@@ -31356,9 +31406,6 @@ msgstr "Keine Ergebnisse gefunden."
msgid "No runner executable"
msgstr "Kein Runner ausführbar"
-msgid "No schedules"
-msgstr "Keine Zeitpläne"
-
msgid "No service accounts"
msgstr "Keine Dienstkonten"
@@ -31410,6 +31457,12 @@ msgstr "Keine Webhook-Ereignisse"
msgid "No webhooks enabled. Select trigger events above."
msgstr "Keine Webhooks aktiviert. Wähle oben Trigger-Ereignisse aus."
+msgid "No work item IDs provided."
+msgstr "Es wurden keine Workitem-IDs bereitgestellt."
+
+msgid "No work item found."
+msgstr "Kein Workitem-Link gefunden."
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] "Keine Sorge, du kannst noch alle %{strong}%{plan_name}%{strong_close}-Funktionen verwenden. Du hast %{remaining_days}, um dein Abonnement zu verlängern."
@@ -32615,6 +32668,9 @@ msgstr "Ein oder mehrere deiner persönlichen Zugriffstoken sind abgelaufen."
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr "Eines oder mehrere deiner persönlichen Zugriffstoken laufen in %{days_to_expire} Tagen oder weniger ab:"
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr "Nur %{workspaceType}-Mitglieder mit %{permissions} können diesen %{issuableType} anzeigen oder entsprechende Benachrichtigungen erhalten."
@@ -32642,9 +32698,6 @@ msgstr "Nur zugänglich für %{membersPageLinkStart}Projektmitglieder%{membersPa
msgid "Only active projects show up in the search and on the dashboard."
msgstr "Nur aktive Projekte werden in der Suche und auf dem Dashboard angezeigt."
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr "Nur wirksam, wenn Remote-Speicher aktiviert ist. Auf 0 setzen für keine Größenbeschränkung."
-
msgid "Only include features new to your current subscription tier."
msgstr "Füge nur Funktionen hinzu, die neu in deinem aktuellen Abonnement-Level sind."
@@ -32807,24 +32860,60 @@ msgstr "Optionen"
msgid "Ordered list"
msgstr "Sortierte Liste"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "Organisationen"
-msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
msgstr ""
+msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgstr "Beim Laden der Gruppen ist ein Fehler aufgetreten. Bitte aktualisiere die Seite, um es erneut zu versuchen."
+
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr "Organisations-ID kopieren"
+
+msgid "Organization|Frequently visited groups"
+msgstr "Häufig besuchte Gruppen"
+
+msgid "Organization|Frequently visited projects"
+msgstr "Häufig besuchte Projekte"
+
+msgid "Organization|New organization"
+msgstr "Neue Organisation"
+
+msgid "Organization|Org ID"
+msgstr "Organisations-ID"
+
msgid "Organization|Organization navigation"
msgstr "Navigation der Organisation"
msgid "Organization|Organization overview"
msgstr "Überblick über die Organisation"
+msgid "Organization|Organizations"
+msgstr "Organisationen"
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr "Public – Auf die Organisation kann ohne Authentifizierung zugegriffen werden."
+
msgid "Organization|Search or filter list"
msgstr "Suchen oder Liste filtern"
+msgid "Organization|View all"
+msgstr "Alle anzeigen"
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr "Verwaistes Mitglied"
@@ -33538,6 +33627,9 @@ msgstr "Seiten"
msgid "Pages Domain"
msgstr "Seiten Domain"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr "Zertifikatsschlüssel ist zu lang. (Max. %d Bytes)"
+
msgid "Pagination|First"
msgstr "Erste"
@@ -33685,8 +33777,11 @@ msgstr "Pfad"
msgid "Path:"
msgstr "Pfad:"
-msgid "Paths to protect with rate limiting"
-msgstr "Zu schützende Pfade mit Ratenbegrenzung"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
+msgstr ""
msgid "Pause"
msgstr "Pausieren"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr "Eine geplante Pipeline startet automatisch in regelmäßigen Abständen, z. B. täglich oder wöchentlich. Die Pipeline: "
-msgid "PipelineSchedules|Activated"
-msgstr "Aktiviert"
-
msgid "PipelineSchedules|Active"
msgstr "Aktiv"
@@ -34193,7 +34285,7 @@ msgid "PipelineSchedules|Next Run"
msgstr "Nächste Durchführung"
msgid "PipelineSchedules|No pipeline schedules"
-msgstr ""
+msgstr "Keine Pipeline-Zeitpläne"
msgid "PipelineSchedules|None"
msgstr "Nichts"
@@ -34249,12 +34341,6 @@ msgstr "Beim Ausführen des Pipeline-Zeitplans ist ein Problem aufgetreten."
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr "Beim Ãœbernehmen der Inhaberschaft des Pipeline-Zeitplans ist ein Problem aufgetreten."
-msgid "PipelineSchedules|Variables"
-msgstr "Variablen"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr "Ãœbernimm Inhaberschaft zum Bearbeiten"
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34705,6 +34791,9 @@ msgstr "Pipeline-Status konnte nicht abgerufen werden. Hinweise zur Fehlerbehebu
msgid "Pipeline|Created"
msgstr "Erstellt"
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr "Erstellen einer Pipeline."
@@ -34828,9 +34917,6 @@ msgstr "Die übrigen Jobs findest du auf der Registerkarte %{boldStart}Jobs%{bol
msgid "Pipeline|Trigger author"
msgstr "Trigger-Autor(in)"
-msgid "Pipeline|Triggerer"
-msgstr "Auslöser"
-
msgid "Pipeline|Variables"
msgstr "Variabeln"
@@ -35353,9 +35439,6 @@ msgstr "Layoutbreite"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "Muss eine Zahl zwischen %{min} und %{max} sein"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr "Hinweis: Du hast die neue Navigation aktiviert, sodass nur das Design im dunklen Modus das Aussehen von GitLab erheblich verändert."
-
msgid "Preferences|Preview"
msgstr "Vorschau"
@@ -35467,6 +35550,9 @@ msgstr "Vorherige ungelöste Diskussion"
msgid "Primary Action"
msgstr "Primäre Aktion"
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr "Zurück zu Dashboards"
msgid "ProductAnalytics|Click Events"
msgstr "Klick Ereignisse"
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr "Vergleicht alle Ereignisse miteinander"
@@ -35608,9 +35691,6 @@ msgstr "Vergleicht die Funktionsnutzung aller Funktionen mit einander"
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr "Vergleicht Seitenaufrufe aller Seiten gegeneinander"
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr "Visualisierung erstellen"
@@ -35618,7 +35698,7 @@ msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr "Erstellen deiner Produkt-Analyseinstanz..."
msgid "ProductAnalytics|Cube API key"
-msgstr ""
+msgstr "Cube API-Schlüssel"
msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr "Details zur Konfiguration der Produktanalyse für die Datenerfassung."
@@ -35647,9 +35727,6 @@ msgstr "Weitere Informationen findest du in den %{linkStart}Dokumenten%{linkEnd}
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr "Füge den Analytics-Tracking-Code zu deinem Projekt hinzu, um Daten im Produktanalyse-Dashboard anzuzeigen."
-msgid "ProductAnalytics|Go back"
-msgstr "Zurück"
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr "Anzahl der Sitzungen eines/einer Benutzer(in)"
@@ -35710,8 +35787,11 @@ msgstr "Produktanalysen einrichten"
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr "Richte die Nachverfolgung der Leistung deines Produkts ein und optimiere deine Produkt- und Entwicklungsprozesse."
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr "Verbindungszeichenfolge des Snowplow-Konfigurators"
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
-msgstr ""
+msgstr "Die Verbindungszeichenfolge für deine Snowplow-Konfiguratorinstanz."
msgid "ProductAnalytics|The host to send all tracking events to"
msgstr "Der Host, an den alle Tracking-Ereignisse gesendet werden"
@@ -35734,11 +35814,8 @@ msgstr "Verfolge bestimmte Funktionen"
msgid "ProductAnalytics|Unique Users"
msgstr "Eindeutige Benutzer(innen)"
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
-msgstr ""
+msgstr "Wird verwendet, um Dashboard-Daten aus der Cube-Instanz abzurufen."
msgid "ProductAnalytics|User Sessions"
msgstr "Benutzersitzungen"
@@ -35876,7 +35953,7 @@ msgid "Profiles|Add new email"
msgstr "Neue E-Mail-Adresse hinzufügen"
msgid "Profiles|Add new mirror repository"
-msgstr ""
+msgstr "Neues Mirror-Repository hinzufügen"
msgid "Profiles|An error occurred while updating your username, please try again."
msgstr "Beim Aktualisieren des Nutzernamens ist ein Fehler aufgetreten. Bitte versuche es erneut."
@@ -35968,8 +36045,8 @@ msgstr "Zeige keine aktivitätsbezogenen persönlichen Informationen in deinem P
msgid "Profiles|Edit Profile"
msgstr "Profil bearbeiten"
-msgid "Profiles|Email"
-msgstr "E-Mail"
+msgid "Profiles|Email address"
+msgstr "E-Mail-Adresse"
msgid "Profiles|Email addresses"
msgstr "E-Mail-Adressen"
@@ -36403,9 +36480,6 @@ msgstr "Projekt oder Gruppe"
msgid "Project order will not be saved as local storage is not available."
msgstr "Die Projektreihenfolge wird nicht gespeichert, da kein lokaler Speicher verfügbar ist."
-msgid "Project overview"
-msgstr "Projektübersicht"
-
msgid "Project path"
msgstr "Projektpfad"
@@ -36895,6 +36969,12 @@ msgstr "Feature-Flags"
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "Flexibles Tool, um gemeinsam Ideen zu entwickeln und die Arbeit in diesem Projekt zu planen."
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr "Speicherort der Daten für Gitaly im Speicher. Speicherort der Daten für Gitaly Cluster auf dem virtuellen Speicher."
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr "Name des Speichers für Gitaly, in dem das Repository gespeichert ist. Name des virtuellen Speichers für Gitaly Cluster, in dem das Repository gespeichert ist."
+
msgid "ProjectSettings|Forks"
msgstr "Forks"
@@ -37030,6 +37110,9 @@ msgstr "Öffentlich"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr "Pakete in einem Projekt veröffentlichen, speichern und anzeigen."
+msgid "ProjectSettings|Relative path:"
+msgstr "Relativer Pfad:"
+
msgid "ProjectSettings|Releases"
msgstr "Veröffentlichung"
@@ -37102,6 +37185,9 @@ msgstr "Squashing wird nie durchgeführt, Kontrollkästchen ist nicht sichtbar."
msgid "ProjectSettings|Status checks must succeed"
msgstr "Statusüberprüfungen müssen erfolgreich sein"
+msgid "ProjectSettings|Storage name:"
+msgstr "Name des Speichers:"
+
msgid "ProjectSettings|Store custom configuration files."
msgstr "Speichert benutzerdefinierte Konfigurationsdateien."
@@ -37921,6 +38007,12 @@ msgstr "Code-Eigentümer-Genehmigung"
msgid "ProtectedBranch|Create wildcard"
msgstr "Platzhalter erstellen"
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr "Die Vergabe von Merge-Rechten für einen geschützten Branch verleiht auch erweiterte Rechte für bestimmte CI/CD-Funktionen."
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr "Vererbt – Diese Einstellung kann auf Gruppenebene geändert werden"
@@ -37970,7 +38062,7 @@ msgid "ProtectedBranch|Tag"
msgstr "Tag"
msgid "ProtectedBranch|There are currently no protected branches, to protect a branch start by creating a new one above."
-msgstr ""
+msgstr "Derzeit gibt es keine geschützten Branches. Erstelle zunächst oben einen neuen Branch, um einen Branch zu schützen."
msgid "ProtectedBranch|Toggle allowed to force push"
msgstr "Push erzwingen erlaubt umschalten"
@@ -37993,8 +38085,8 @@ msgstr "Geschützte Branches als Branch-Regeln anzeigen"
msgid "ProtectedBranch|What are protected branches?"
msgstr "Was sind geschützte Branches?"
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
-msgstr ""
+msgid "ProtectedBranch|What are the security implications?"
+msgstr "Was sind die Auswirkungen auf die Sicherheit?"
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
msgstr "Du kannst nur Gruppen hinzufügen, die dieses Projekt freigegeben haben. %{learn_more_link}"
@@ -38048,12 +38140,15 @@ msgstr "Bereitstellungsregel löschen"
msgid "ProtectedEnvironments|Edit"
msgstr "Bearbeiten"
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
-msgstr "Liste der geschützten Umgebungen (%{protectedEnvironmentsCount})"
-
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr "Die Anzahl der Genehmigungen muss zwischen 1 und 5 liegen"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr "Schütze eine Umgebung"
+
+msgid "ProtectedEnvironments|Protected environments"
+msgstr "Geschützte Umgebungen"
+
msgid "ProtectedEnvironments|Remove approval rule"
msgstr "Entferne die Genehmigungsregel."
@@ -38063,6 +38158,9 @@ msgstr "Erforderliche Anzahl der Genehmigungen"
msgid "ProtectedEnvironments|Save"
msgstr "Speichern"
+msgid "ProtectedEnvironments|Select users"
+msgstr "Benutzer(innen) auswählen"
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr "Lege fest, welche Gruppen, Zugriffsebenen oder Benutzer(innen) genehmigt werden müssen."
@@ -38081,6 +38179,9 @@ msgstr "Benutzer(innen)"
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} wird für Entwickler(innen) änderbar sein. Bist du sicher?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr "Neue geschützte Umgebung hinzufügen"
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr "Alle Umgebungen, die mit den unten aufgeführten Bereitstellungsstufen angegeben sind, werden durch eine übergeordnete Gruppe geschützt. %{link_start}Mehr erfahren%{link_end}."
@@ -38138,9 +38239,6 @@ msgstr "Umgebung auswählen"
msgid "ProtectedEnvironment|Select groups"
msgstr "Gruppen auswählen"
-msgid "ProtectedEnvironment|Select users"
-msgstr "Benutzer(innen) auswählen"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr "Bereitstellungsanweisungen"
msgid "Provisioned by:"
msgstr "Bereitgestellt von:"
-msgid "Proxy support for this API is not available currently"
-msgstr "Proxy-Unterstützung für diese API ist derzeit nicht verfügbar."
-
msgid "Public"
msgstr "Öffentlich"
@@ -38570,9 +38665,6 @@ msgstr "Benachrichtigung über Missbrauchsmeldungen per E-Mail erhalten."
msgid "Receive notifications about your own activity"
msgstr "Erhalte Benachrichtigungen über deine Aktivitäten"
-msgid "Receive product marketing emails"
-msgstr "Produktmarketing-E-Mails erhalten"
-
msgid "Recent"
msgstr "Kürzlich"
@@ -38713,35 +38805,11 @@ msgstr "E-Mails an Benutzer(innen) senden"
msgid "RegistrationFeatures|use this feature"
msgstr "diese Funktion verwenden"
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr "Möchtest du diesen Schritt wirklich überspringen?"
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr "Kostenlose Compute-Minuten aktivieren"
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr "GitLab belastet deine Karte nicht, sie wird nur für die Validierung verwendet."
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr "Pipelines, die gemeinsam genutzte GitLab-Runner verwenden, schlagen fehl, bis du dein Konto validierst."
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr "Vorerst überspringen"
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr "Um GitLab vor Spam und Missbrauch zu schützen, bitten wir dich, deine Identität mit einer gültigen Zahlungsmethode zu verifizieren, z. B. mit einer Debit- oder Kreditkarte. Bis dahin kannst du zum Erstellen deiner Anwendung keine kostenlosen Compute-Minuten verwenden."
-
-msgid "RegistrationVerification|Validate account"
-msgstr "Konto validieren"
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr "Identität verifizieren"
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr "Ja, überspringen"
+msgid "Registries enqueued to be resynced"
+msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
-msgstr "Du kannst dein Konto jederzeit zu einem späteren Zeitpunkt verifizieren."
+msgid "Registries enqueued to be reverified"
+msgstr ""
msgid "Registry entry enqueued to be resynced"
msgstr "Registry-Eintrag in der Warteschlange zur Neusynchronisierung"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr "Priorität entfernen"
-msgid "Remove report"
-msgstr "Bericht entfernen"
-
msgid "Remove reviewer"
msgstr "Prüfer(in) entfernen"
@@ -39090,6 +39155,9 @@ msgstr "Sekundäre E-Mail-Adresse entfernen"
msgid "Remove spent time"
msgstr "Aufwände entfernen"
+msgid "Remove summary"
+msgstr "Zusammenfassung entfernen"
+
msgid "Remove time estimate"
msgstr "Geschätzte Zeit entfernen"
@@ -39099,9 +39167,6 @@ msgstr "Themen-Avatar entfernen"
msgid "Remove user"
msgstr "Benutzer(in) entfernen"
-msgid "Remove user & report"
-msgstr "Nutzer & Bericht entfernen"
-
msgid "Remove user from group"
msgstr "Benutzer(in) aus der Gruppe entfernen"
@@ -39381,12 +39446,6 @@ msgstr "Warum meldest du diesen/diese Benutzer(in)?"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Gemeldet %{timeAgo} von %{reportedBy}"
-msgid "Reported by"
-msgstr "Gemeldet von"
-
-msgid "Reported by %{reporter}"
-msgstr "Gemeldet von %{reporter}"
-
msgid "Reporter"
msgstr "Reporter"
@@ -39693,9 +39752,6 @@ msgstr "Neuberechnung der Repository-Nutzung gestartet"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr "Repository:%{counter_repositories}/ Wikis:%{counter_wikis}/Build-Artefakte:%{counter_build_artifacts}/ Pipeline-Artefakte:%{counter_pipeline_artifacts}/ LFS:%{counter_lfs_objects}/ Snippets:%{counter_snippets}/ Pakete:%{counter_packages}/ Uploads: %{counter_uploads}"
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "Auswählen"
-
msgid "Request"
msgstr "Anfrage"
@@ -40109,6 +40165,9 @@ msgstr "Die Ursachenanalyse ist eine Funktion, die deine Protokolle analysiert,
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr "Regelname ist bereits vergeben."
@@ -40459,7 +40518,7 @@ msgid "Runners|GitLab Runner must be installed before you can register a runner.
msgstr "GitLab Runner muss installiert sein, bevor du einen Runner registrieren kannst. %{linkStart}Wie installiere ich GitLab Runner?%{linkEnd}"
msgid "Runners|Go to %{groupLink} to enable them."
-msgstr ""
+msgstr "Öffne %{groupLink} für Aktivierungsoptionen."
msgid "Runners|Go to runners page"
msgstr "Gehe zur Runners-Seite"
@@ -40539,6 +40598,9 @@ msgstr "Mitglieder des %{type} können Runners registrieren "
msgid "Runners|Minor version upgrades are available."
msgstr "Minor-Versions-Upgrades sind verfügbar."
+msgid "Runners|Most recent failures"
+msgstr "Letzte Fehler"
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr "Mehrere Tags müssen durch Komma getrennt werden. Zum Beispiel %{example}."
@@ -40825,11 +40887,11 @@ msgstr "Projekte auswählen, die diesem Runner zugewiesen werden sollen"
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr "Wähle deinen bevorzugten Runner und dann die Kapazität für den Runner in der AWS CloudFormation Konsole aus."
-msgid "Runners|Shared runners are disabled in the group settings"
-msgstr "Gemeinsame Runner sind in den Gruppeneinstellungen deaktiviert"
+msgid "Runners|Shared runners are disabled in the group settings."
+msgstr "Gemeinsam genutzte Runner sind in den Gruppeneinstellungen deaktiviert."
msgid "Runners|Shared runners are disabled."
-msgstr ""
+msgstr "Gemeinsam genutzte Runner sind deaktiviert."
msgid "Runners|Shared runners will be disabled for all projects and subgroups in this group. If you proceed, you must manually re-enable shared runners in the settings of each project and subgroup."
msgstr "Gemeinsame Runner werden für alle Projekte und Untergruppen in dieser Gruppe deaktiviert. Wenn du fortfährst, musst du gemeinsame Runner in den Einstellungen jedes Projekts und jeder Untergruppe manuell wieder aktivieren."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr "Die eindeutige ID für jeden Runner, der diese Konfiguration verwendet."
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr "Es gibt keine aktuellen Runner-Fehler für deine Instanz-Runner. Wenn Runner fehlschlagen, werden hier Fehlermeldungen angezeigt."
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40956,7 +41021,7 @@ msgid "Runners|To register new runners, contact your administrator."
msgstr "Kontaktiere Deinen Administrator, um neue Runner zu registrieren."
msgid "Runners|To register them, go to the %{link_start}group's Runners page%{link_end}."
-msgstr "Um sie zu registrieren, gehe auf %{link_end}die Seite der Runner dieser Gruppe%{link_start}."
+msgstr "Um sie zu registrieren, gehe auf %{link_start}die Seite der Runner dieser Gruppe%{link_end}."
msgid "Runners|To view the runner, go to %{runnerListName}."
msgstr "Um den Runner anzuzeigen, gehe zu %{runnerListName}."
@@ -41117,6 +41182,9 @@ msgstr "Melde dich mit Single Sign-On an und wähle dann %{strongOpen}Autorisier
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "Das SSO deiner Organisation wurde mit deinem GitLab-Konto verbunden"
+msgid "SBOMs last updated"
+msgstr "Zuletzt aktualisierte SBOMs"
+
msgid "SCIM|SCIM Token"
msgstr "SCIM-Token"
@@ -41225,9 +41293,6 @@ msgstr "Interne Notiz speichern"
msgid "Save password"
msgstr "Passwort speichern"
-msgid "Save pipeline schedule"
-msgstr "Zeitplan der Pipeline speichern"
-
msgid "Saving"
msgstr "Speichern"
@@ -41240,11 +41305,11 @@ msgstr "Zeitzone von %{hostname}"
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr "%{period} %{days} um %{time} %{timezoneLabel} %{timezone}"
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
-msgstr ""
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
+msgstr "%{rules} Aktionen für %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
-msgstr ""
+msgstr "%{rules} jedes Mal, wenn eine Pipeline für %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} ausgeführt wird"
msgid "ScanExecutionPolicy|A runner will be selected automatically from those available."
msgstr ""
@@ -41366,11 +41431,14 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
-msgstr ""
+msgid "ScanResultPolicy|Attribute is:"
+msgstr "Das Attribut lautet:"
-msgid "ScanResultPolicy|Choose an option"
-msgstr "Wähle eine Option aus"
+msgid "ScanResultPolicy|Attribute:"
+msgstr "Attribut:"
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
+msgstr "Attribute werden automatisch von den Scannern angewendet"
msgid "ScanResultPolicy|Choose criteria type"
msgstr "Wähle den Kriterientyp aus"
@@ -41384,6 +41452,24 @@ msgstr "Benutzerdefinierte CI-Variablen"
msgid "ScanResultPolicy|Except"
msgstr "Außer"
+msgid "ScanResultPolicy|False positive"
+msgstr "Falsch positiv"
+
+msgid "ScanResultPolicy|Fix available"
+msgstr "Fix verfügbar"
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr "Der verfügbare Fix gilt nur für das Scannen von Containern und Abhängigkeiten"
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr "Ist"
+
+msgid "ScanResultPolicy|Is not"
+msgstr "Ist nicht"
+
msgid "ScanResultPolicy|License is:"
msgstr "Die Lizenz lautet:"
@@ -41396,8 +41482,8 @@ msgstr "Ãœbereinstimmung"
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
-msgstr "Neuer Schweregrad"
+msgid "ScanResultPolicy|New attribute"
+msgstr "Neues Attribut"
msgid "ScanResultPolicy|New status"
msgstr "Neuer Status"
@@ -41408,18 +41494,24 @@ msgstr "Neu erkannt"
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
-msgstr ""
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
+msgstr "Es sind nur 2 Attributkriterien zulässig"
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Override project approval settings"
-msgstr ""
+msgstr "Projektgenehmigungseinstellungen überschreiben"
msgid "ScanResultPolicy|Pre-existing"
msgstr "Bereits vorhanden"
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr "Wähle einen Scan-Typ aus, bevor du Kriterien hinzufügst"
@@ -41447,9 +41539,18 @@ msgstr "Wenn %{scanType} %{scanners} für %{branches} %{branchExceptions} ausgef
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr "Wenn %{scanType} in einem offenen Merge Request %{branches} %{branchExceptions} prüft und die Lizenzen alle der folgenden Kriterien erfüllen:"
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr "Wenn %{scanners} scanner-spezifische Bedingungen in einem offenen Merge-Request zu den %{branches} %{branchExceptions} finden und %{boldDescription} der folgenden Kriterien übereinstimmen"
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr "Lizenzstatus"
@@ -41561,6 +41662,9 @@ msgstr "Suche eine Gruppe"
msgid "Search an environment spec"
msgstr "Suche eine Umgebungsspezifikation"
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "Beauftragte suchen"
@@ -41630,15 +41734,12 @@ msgstr "Suche Meilensteine"
msgid "Search or filter commits"
msgstr "Commits suchen oder filtern"
-msgid "Search or filter results"
-msgstr "Ergebnisse suchen oder filtern"
-
-msgid "Search or filter results..."
-msgstr "Ergebnisse suchen oder filtern..."
-
msgid "Search or filter results…"
msgstr "Ergebnisse durchsuchen oder filtern …"
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr "Seite durchsuchen"
@@ -41865,6 +41966,9 @@ msgstr "Sicherheitskonfiguration"
msgid "Security dashboard"
msgstr "Sicherheits-Dashboard"
+msgid "Security reports last updated"
+msgstr "Zuletzt aktualisierte Sicherheitsberichte"
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr "Eine Genehmigung des Merge Requests ist erforderlich, wenn die Testabdeckung abgelehnt wird."
@@ -42021,6 +42125,12 @@ msgstr "und "
msgid "SecurityOrchestration| and all the following apply:"
msgstr "und alle folgenden zutreffen:"
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr "oder "
@@ -42030,8 +42140,14 @@ msgstr "mit den Eigenschaften %{licenseState} und"
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr "%{agent} für %{namespaces}"
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
-msgstr ""
+msgid "SecurityOrchestration|%{branchName}"
+msgstr "%{branchName}"
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr "%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
+msgstr "%{cadence} in %{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
msgstr "%{licenses} und %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr "Beim Abrufen der Scan-Ergebnisrichtlinien ist ein Fehler aufgetreten."
msgid "SecurityOrchestration|And scans to be performed:"
msgstr "Und durchzuführende Scans:"
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr "Möchtest du diese Richtlinie wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden."
@@ -42159,8 +42278,8 @@ msgstr "Aktiviert"
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr "Sicherheit für dieses Projekt durchsetzen. %{linkStart}Weitere Informationen.%{linkEnd}"
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
-msgstr ""
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
+msgstr "Jedes Mal, wenn eine Pipeline für %{branches}%{branchExceptionsString} ausgeführt wird"
msgid "SecurityOrchestration|Exceptions"
msgstr "Ausnahmen"
@@ -42171,12 +42290,18 @@ msgstr "Fehler beim Laden der Cluster-Agenten."
msgid "SecurityOrchestration|Failed to load images."
msgstr "Fehler beim Laden der Images."
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr "In großen Gruppen kann die Anwendung von Richtlinienänderungen auf bereits vorhandene Merge Requests erheblich verzögert werden. Bei neu erstellten Merge Requests werden Richtlinienänderungen in der Regel praktisch sofort übernommen."
msgid "SecurityOrchestration|Groups"
msgstr "Gruppen"
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr "Zusätzliche Branches ausblenden"
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr "Wenn ein Scanner eine neu entdeckte kritische Sicherheitslückee in einem offenen Merge Request findet, die auf den Masterbranch abzielt, müssen zwei Genehmigungen von einem beliebigen Mitglied der App-Sicherheit eingeholt werden."
@@ -42443,6 +42568,9 @@ msgstr "Verwende eine Richtlinie für Scan-Ergebnisse, um Regeln zu erstellen, d
msgid "SecurityOrchestration|View policy project"
msgstr "Richtlinienprojekt anzeigen"
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr "Sicherheitslücken %{vulnerabilityStates}."
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr "Sicherheitslücken sind %{vulnerabilityStates}."
@@ -42455,14 +42583,14 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
-msgstr ""
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
+msgstr "Wenn %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in einem offenen Merge Request findet, die %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr ""
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "Wenn der Lizenzscanner in einem offenen Merge Request eine Lizenz außer %{licenses}%{detection} findet, die %{targeting}%{branches}%{branchExceptionsString}"
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr ""
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "Wenn der Lizenzscanner in einem offenen Merge Request eine Lizenz findet, die mit %{licenses}%{detection} übereinstimmt, und %{targeting}%{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|With the following customized CI variables:"
msgstr ""
@@ -42491,14 +42619,20 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr "ein Sicherheitsscanner findet"
+msgid "SecurityOrchestration|are false positives"
+msgstr "sind falsch positiv"
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr "sind nicht falsch positiv"
+
msgid "SecurityOrchestration|branch"
msgstr "Branch"
msgid "SecurityOrchestration|branches"
msgstr "Branches"
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
-msgstr "vom Agenten namens %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
+msgstr "durch den Agenten namens %{agents} %{cadence}%{branchExceptionsString}"
msgid "SecurityOrchestration|group level branch input"
msgstr "Branch-Input auf Gruppenebene"
@@ -42506,6 +42640,12 @@ msgstr "Branch-Input auf Gruppenebene"
msgid "SecurityOrchestration|group level branch selector"
msgstr "Branch-Selector auf Gruppenebene"
+msgid "SecurityOrchestration|have a fix available"
+msgstr "haben einen verfügbaren Fix"
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr "haben keinen verfügbaren Fix"
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr "mehr als %{allowed}"
@@ -42575,9 +42715,6 @@ msgstr "Einen Kommentar hinzufügen (erforderlich)"
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr "Kommentar oder Grund für die Ablehnung angeben"
-msgid "SecurityReports|Add comment & dismiss"
-msgstr "Kommentar hinzufügen & ablehnen"
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "Hier kannst du Projekte, die im Sicherheitsbereich überwacht werden sollen, hinzufügen oder entfernen. Die Überprüfungsergebnisse der Projekte in dieser Liste werden im Sicherheits-Dashboard und im Sicherheitslückenbericht angezeigt."
@@ -42591,7 +42728,7 @@ msgid "SecurityReports|All clusters"
msgstr "Alle Cluster"
msgid "SecurityReports|All dismissal reasons"
-msgstr ""
+msgstr "Alle Ablehnungsgründe"
msgid "SecurityReports|All images"
msgstr "Alle Bilder"
@@ -42632,6 +42769,9 @@ msgstr "Kommentar zu „%{vulnerabilityName}“ bearbeitet"
msgid "SecurityReports|Configure security testing"
msgstr "Sicherheitstests konfigurieren"
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr "Ticket erstellen"
@@ -42647,9 +42787,15 @@ msgstr "Erkennung"
msgid "SecurityReports|Development vulnerabilities"
msgstr "Entwicklungssicherheitslücken"
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "Sicherheitslücke verwerfen"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "„%{vulnerabilityName}“ verworfen"
@@ -42657,10 +42803,10 @@ msgid "SecurityReports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismi
msgstr "„%{vulnerabilityName}“ abgelehnt. Deaktiviere die Option zum Ausblenden verworfener Elemente, um sie anzuzeigen."
msgid "SecurityReports|Dismissed (all reasons)"
-msgstr ""
+msgstr "Abgelehnt (alle Gründe)"
msgid "SecurityReports|Dismissed as..."
-msgstr ""
+msgstr "Abgelehnt als …"
msgid "SecurityReports|Does not have issue"
msgstr "Hat keine Tickets"
@@ -42680,6 +42826,9 @@ msgstr "Gescannte URLs herunterladen"
msgid "SecurityReports|Download the patch to apply it manually"
msgstr "Patch herunterladen und manuell anwenden"
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr "Du hast keine Berechtigung, dieses Dashboard anzuzeigen, oder das Dashboard wurde nicht eingerichtet. Überprüfe deine Berechtigungseinstellungen mit deinem/deiner Administrator(in) oder überprüfe deine Dashboard-Konfigurationen, um fortzufahren."
@@ -42797,9 +42946,6 @@ msgstr "Bericht ist abgelaufen"
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr "Die Ergebnisse zeigen Sicherheitslücken, die durch den Merge Request eingeführt wurden, zusätzlich zu den vorhandenen Sicherheitslücken aus der neuesten erfolgreichen Pipeline im Standardbranch deines Projekts."
-msgid "SecurityReports|Save comment"
-msgstr "Kommentar speichern"
-
msgid "SecurityReports|Scan details"
msgstr "Scan-Details"
@@ -42844,8 +42990,8 @@ msgstr "Immer noch erkannt"
msgid "SecurityReports|Submit vulnerability"
msgstr "Sicherheitslücke absenden"
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
-msgstr "Der Sicherheitslückenbericht zeigt die Ergebnisse erfolgreicher Scans im Standardbranch deines Projekts, manuell hinzugefügte Sicherheitslückendatensätze und Sicherheitslücken, die beim Scannen von Betriebsumgebungen gefunden wurden. %{linkStart}Mehr erfahren.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
msgstr "Die folgenden Sicherheitsberichte enthalten eine oder mehrere Sicherheitslücken, die nicht geparst werden konnten und nicht aufgezeichnet wurden. Lade die Artefakte in der Jobausgabe herunter, um einen Bericht zu untersuchen. Stelle sicher, dass der Sicherheitsbericht dem entsprechenden %{helpPageLinkStart}JSON-Schema%{helpPageLinkEnd} entspricht."
@@ -43192,9 +43338,6 @@ msgstr "Sende E-Mails im mehrteiligen Format (HTML und Klartext). Deaktiviere di
msgid "Send email notification"
msgstr "E-Mail-Benachrichtigung senden"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "E-Mails senden, um neue Benutzer(innen) durch den Onboarding-Prozess zu führen."
-
msgid "Send emails to users upon account deactivation."
msgstr "Sende E-Mails an Benutzer(innen) nach der Deaktivierung des Kontos."
@@ -43264,6 +43407,9 @@ msgstr "Dienstkontenschlüssel autorisieren GitLab zur Bereitstellung deines Goo
msgid "Service Desk"
msgstr "Service-Desk"
+msgid "Service Desk Ticket"
+msgstr "Service-Desk-Ticket"
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr "Mit dem Service-Desk können Benutzer(innen) Tickets in deiner GitLab-Instanz erstellen, ohne ein eigenes Benutzerkonto zu besitzen. Dies stellt eine eindeutige E-Mail-Adresse für Endbenutzer(innen) zur Verfügung, um Tickets in einem Projekt zu erstellen. Antworten können entweder über die GitLab-Schnittstelle oder per E-Mail gesendet werden. Endbenutzer(innen) sehen Threads nur per E-Mail."
@@ -43288,23 +43434,35 @@ msgstr "Der/die Benutzer(in) ist nicht berechtigt, ein Dienstkonto in diesem Nam
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr "Der/die Benutzer(in) ist nicht berechtigt, ein Dienstkonto zu erstellen."
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr "%{customEmail} mit SMTP-Host %{smtpAddress} ist %{badgeStart}verifiziert%{badgeEnd}"
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr "Es konnte keine Verbindung zum angegebenen Host hergestellt werden oder es ist ein SSL-Problem aufgetreten."
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr "Eine Bestätigungs-E-Mail wurde an eine Unteradresse deiner benutzerdefinierten E-Mail-Adresse gesendet. Dies kann bis zu 30 Minuten dauern. Der Bildschirm wird automatisch aktualisiert."
+
msgid "ServiceDesk|Cannot create custom email"
msgstr "Benutzerdefinierte E-Mail kann nicht erstellt werden"
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr "Prüfe deine Weiterleitungseinstellungen und stelle sicher, dass der ursprüngliche E-Mail-Absender im Absender-Header verbleibt."
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
-msgstr ""
+msgstr "Standardports sind: 587 mit TLS und 25 ohne TLS."
msgid "ServiceDesk|Configure a custom email address"
msgstr "Konfiguriere eine benutzerdefinierte E-Mail-Adresse"
msgid "ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials."
-msgstr ""
+msgstr "Verbinde eine benutzerdefinierte E-Mail-Adresse, mit der deine Kunden Service-Desk-Tickets erstellen können. Leite alle E-Mails von deiner benutzerdefinierten E-Mail-Adresse an die Service-Desk-E-Mail-Adresse dieses Projekts weiter. GitLab sendet Service-Desk-E-Mails von der benutzerdefinierten Adresse in deinem Namen und mit deinen SMTP-Zugangsdaten."
msgid "ServiceDesk|Copy Service Desk email address"
-msgstr ""
+msgstr "Service-Desk-E-Mail-Adresse kopieren"
msgid "ServiceDesk|Custom email address"
msgstr ""
@@ -43321,26 +43479,50 @@ msgstr "Die Überprüfung der benutzerdefinierten E-Mail-Adresse wurde bereits d
msgid "ServiceDesk|Custom email already exists"
msgstr "Die benutzerdefinierte E-Mail ist bereits vorhanden"
+msgid "ServiceDesk|Custom email disabled."
+msgstr "Benutzerdefinierte E-Mail-Adresse ist deaktiviert."
+
msgid "ServiceDesk|Custom email does not exist"
msgstr "Die benutzerdefinierte E-Mail ist nicht vorhanden"
+msgid "ServiceDesk|Custom email enabled."
+msgstr "Benutzerdefinierte E-Mail-Adresse ist aktiviert."
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
-msgstr ""
+msgstr "Die benutzerdefinierte E-Mail-Adresse ist erforderlich und muss ein gültiges Format besitzen."
msgid "ServiceDesk|Email address your customers can use to send support requests. It must support sub-addressing."
-msgstr ""
+msgstr "E-Mail-Adresse, an die deine Kunden Supportanfragen senden können. Die Adresse muss Unteradressierung unterstützen."
msgid "ServiceDesk|Enable Service Desk"
msgstr "Service-Desk aktivieren"
+msgid "ServiceDesk|Enable custom email address"
+msgstr "Aktiviere benutzerdefinierte E-Mail-Adresse"
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr "Wenn du Hilfe bei der Einrichtung des Service-Desks für deine Instanz benötigst, wende dich bitte an einen Administrator."
+msgid "ServiceDesk|Incorrect From header"
+msgstr "Falscher Absender-Header"
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr "Falsches Verifizierungstoken"
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr "Ungültige Zugangsdaten"
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr "Tickets, die aus Service-Desk-E-Mails erstellt wurden, werden hier angezeigt. Jeder Kommentar wird Teil der E-Mail-Konversation."
+msgid "ServiceDesk|Keep custom email"
+msgstr "Benutzerdefinierte E-Mail-Adresse behalten"
+
msgid "ServiceDesk|Minimum 8 characters long."
-msgstr ""
+msgstr "Mindestens 8 Zeichen lang."
+
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr "Oder setze eine neue benutzerdefinierte E-Mail-Adresse zurück und verbinde sie mit diesem Service-Desk."
msgid "ServiceDesk|Parameters missing"
msgstr "Parameter fehlen"
@@ -43348,38 +43530,53 @@ msgstr "Parameter fehlen"
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr "Bitte teile dein Feedback zu dieser Funktion im %{linkStart}Feedback-Ticket%{linkEnd}"
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr "Bitte erneut versuchen. Überprüfe die Einstellungen und Zugangsdaten für die E-Mail-Weiterleitung, und starte die Verifizierung erneut."
+
+msgid "ServiceDesk|Reset custom email"
+msgstr "Benutzerdefinierte E-Mail-Adresse zurücksetzen"
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr "Benutzerdefinierte E-Mail-Adresse zurücksetzen und Zugangsdaten löschen"
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr "Benutzerdefinierte E-Mail-Adresse zurücksetzen"
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
-msgstr ""
+msgstr "Die SMTP-Adresse ist erforderlich und muss auflösbar sein."
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr "SMTP-Host-Problem"
+
msgid "ServiceDesk|SMTP password"
msgstr ""
msgid "ServiceDesk|SMTP password is required and must be at least 8 characters long."
-msgstr ""
+msgstr "Das SMTP-Passwort ist erforderlich und muss mindestens 8 Zeichen lang sein."
msgid "ServiceDesk|SMTP port"
msgstr ""
msgid "ServiceDesk|SMTP port is required and must be a port number larger than 0."
-msgstr ""
+msgstr "Der SMTP-Port ist erforderlich. Die Portnummer muss größer als 0 sein."
msgid "ServiceDesk|SMTP username"
msgstr ""
msgid "ServiceDesk|SMTP username is required."
-msgstr ""
+msgstr "Der SMTP-Benutzername ist erforderlich."
msgid "ServiceDesk|Save and test connection"
-msgstr ""
+msgstr "Verbindung speichern und testen"
msgid "ServiceDesk|Saved custom email address and started verification."
-msgstr ""
+msgstr "Benutzerdefinierte E-Mail-Adresse gespeichert und Verifizierung gestartet."
msgid "ServiceDesk|Service Desk email address to forward emails to"
-msgstr ""
+msgstr "Service-Desk-E-Mail-Adresse, an die E-Mails weitergeleitet werden sollen"
msgid "ServiceDesk|Service Desk is not enabled"
msgstr "Service-Desk ist nicht aktiviert"
@@ -43393,15 +43590,45 @@ msgstr "Service-Desk-Einstellung fehlt"
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr "Einstellung oder Verifizierungsobjekt fehlt"
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr "Die angegebenen Zugangsdaten (Benutzername und Passwort) wurden vom SMTP-Server abgelehnt."
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr "Die empfangene E-Mail enthielt nicht das Verifizierungstoken, das an deine E-Mail-Adresse gesendet wurde."
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr "Die Verifizierungs-E-Mail wurde nicht rechtzeitig empfangen. Es braucht etwa 30 Minuten, bis Verifizierungs-E-Mails im Service-Desk deiner Instanz erscheinen. Stelle sicher, dass du die E-Mail-Weiterleitung korrekt eingerichtet hast."
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr "Um den Service-Desk auf dieser Instanz zu aktivieren, muss ein(e) Instanzadministrator(in) zunächst eingehende E-Mails einrichten."
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr "Um eine benutzerdefinierte E-Mail-Adresse für diesen Service-Desk zu verwenden, musst du eine E-Mail-Adresse erneut konfigurieren und überprüfen."
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr "Verwende den Service-Desk, um dich mit deinen Benutzer(inne)n zu verbinden und Kundensupport per E-Mail direkt in GitLab anzubieten"
msgid "ServiceDesk|User cannot manage project."
msgstr "Der/die Benutzer(in) darf das Projekt nicht verwalten."
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr "Verifizierungs-E-Mail nicht innerhalb des Zeitrahmens erhalten"
+
+msgid "ServiceDesk|Verification failed"
+msgstr "Überprüfung fehlgeschlagen"
+
+msgid "ServiceDesk|Verification started"
+msgstr "Überprüfung gestartet"
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr "%{customEmail} mit SMTP-Host %{smtpAddress} verifizieren:"
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr "Wenn diese Option aktiviert ist, werden Service-Desk-E-Mails mit den angegebenen Zugangsdaten gesendet."
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr "Du bist dabei, die %{strongStart}benutzerdefinierte E-Mail-Adresse%{strongEnd} %{customEmail} %{strongStart}zu deaktivieren und ihre Zugangsdaten zu löschen%{strongEnd}."
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr "Deine Benutzer(innen) können E-Mails an diese Adresse senden:"
@@ -43429,6 +43656,9 @@ msgstr "Session ID"
msgid "Session duration (minutes)"
msgstr "Sitzungsdauer (Minuten)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr "Benutzer(in) kann nicht verifiziert werden. Beim Laden der Benutzerüberprüfung ist ein Fehler aufgetreten. Aktualisiere, um es erneut zu versuchen."
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "%{epic_ref} als übergeordnetes Epic gesetzt."
@@ -43549,6 +43779,9 @@ msgstr "Lege %{time_estimate} als geschätzte Dauer fest."
msgid "Set to 0 for no size limit."
msgstr "Setze dies auf 0, um die Größenbegrenzung zu deaktivieren."
+msgid "Set to 0 to disable timeout."
+msgstr "Auf 0 setzen, um die Zeitüberschreitung zu deaktivieren."
+
msgid "Set to auto-merge"
msgstr "Auf Auto-Merge setzen"
@@ -43627,6 +43860,9 @@ msgstr "Dein Status wird am %{date} zurückgesetzt."
msgid "Sets %{epic_ref} as parent epic."
msgstr "Setzt %{epic_ref} als übergeordnetes Epic."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr "Lege %{health_status} als Integritätsstatus fest."
@@ -44462,6 +44698,9 @@ msgstr "Jemand hat sich von einem neuen Standort aus bei Deinem %{host} Konto an
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Jemand, hoffentlich du, hat darum gebeten, das Passwort für dein GitLab-Konto unter %{link_to_gitlab} zurückzusetzen."
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "Etwas ist schief gelaufen"
@@ -44555,9 +44794,6 @@ msgstr "Fehler beim Abrufen von Beschreibungsänderungen. Versuche es erneut."
msgid "Something went wrong while fetching details"
msgstr "Beim Abrufen von Details ist etwas schief gelaufen"
-msgid "Something went wrong while fetching latest comments."
-msgstr "Beim Abrufen der letzten Kommentare ist etwas schiefgelaufen."
-
msgid "Something went wrong while fetching projects"
msgstr "Beim Abrufen von Projekten ist etwas schief gelaufen"
@@ -45222,7 +45458,7 @@ msgid "StatusCheck|Apply this status check to all branches or a specific protect
msgstr "Wende diese Statusprüfung auf alle Branches oder einen bestimmten geschützten Branch an."
msgid "StatusCheck|Check for a status response in merge requests. %{linkStart}Learn more%{linkEnd}."
-msgstr ""
+msgstr "Prüfe auf eine Statusantwort in Merge Requests. %{linkStart}Mehr erfahren%{linkEnd}."
msgid "StatusCheck|Examples: QA, Security."
msgstr "Beispiele: QA, Sicherheit."
@@ -45483,7 +45719,7 @@ msgid "Subscription deletion failed."
msgstr "Löschen des Abonnements fehlgeschlagen."
msgid "Subscription for %{subscription} will be removed. Do you want to continue?"
-msgstr ""
+msgstr "Abonnement für %{subscription} wird entfernt. Möchtest du fortfahren?"
msgid "Subscription service outage"
msgstr "Ausfall des Abonnementdienstes"
@@ -45506,6 +45742,18 @@ msgstr "Lizenznutzungsdatei exportieren"
msgid "SubscriptionBanner|Upload new license"
msgstr "Neue Lizenz hochladen"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr "Wenn du weitere Plätze hinzufügen, dein Abo upgraden oder zusätzliche Produkte kaufen möchtest, wende dich an deine(n) GitLab-Vertriebsmitarbeiter(in)."
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr "Dies ist ein benutzerdefiniertes Abonnement, das vom GitLab-Vertriebsteam verwaltet wird."
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr "Um Änderungen an einem schreibgeschützten Abonnement vorzunehmen oder zusätzliche Produkte zu kaufen, wende dich an deinen GitLab-Partner."
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr "Dein Abonnement ist schreibgeschützt"
+
msgid "SubscriptionTable|Add seats"
msgstr "Plätze hinzufügen"
@@ -45653,6 +45901,9 @@ msgstr "Erfolgreich deaktiviert"
msgid "Successfully deleted WebAuthn device."
msgstr "Das WebAuthn-Gerät wurde erfolgreich gelöscht."
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr "ID(s) erfolgreich verknüpft: %{item_ids}."
+
msgid "Successfully removed email."
msgstr "E-Mail erfolgreich entfernt."
@@ -45671,6 +45922,9 @@ msgstr "Erfolgreich entsperrt"
msgid "Successfully unblocked"
msgstr "Erfolgreich gesperrt"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr "Die Verknüpfung der folgenden IDs wurde erfolgreich aufgehoben: %{item_ids}."
+
msgid "Successfully unlocked"
msgstr "Erfolgreich entsperrt"
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr "Was ist ein Fork?"
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr "Ziel"
@@ -46344,8 +46601,14 @@ msgstr "Zielpfad"
msgid "Target branch"
msgstr "Zielbranch"
-msgid "Target branch or tag"
-msgstr "Zielbranch oder -Tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
+msgstr ""
msgid "Target branch: %{target_branch}"
msgstr "Zielbranch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr "Die Seite konnte nicht angezeigt werden, da sie abgelaufen ist."
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr "Das Eltern-Epic ist vertraulich und kann nur vertrauliche Epics und Tickets enthalten"
-msgid "The parsed YAML is too big"
-msgstr "Die geparste YAML ist zu groß"
-
msgid "The password for the Jenkins server."
msgstr "Das Passwort für den Jenkins-Server."
@@ -47354,6 +47614,9 @@ msgstr "Die Sicherheitslücke wird nicht mehr erkannt. Überprüfe, ob sie behob
msgid "There are currently no mirrored repositories."
msgstr "Derzeit gibt es keine gespiegelten Repositorys."
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "Es sind Merge-Konflikte vorhanden."
@@ -47372,9 +47635,6 @@ msgstr "Es gibt keine SSH-Schlüssel mit Zugriff auf dein Konto."
msgid "There are no Spam Logs"
msgstr "Es gibt keine Spam-Protokolle"
-msgid "There are no abuse reports!"
-msgstr "Es gibt keine Missbrauchsberichte!"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr "Für den angegebenen Parameter „represent_as“ existieren keine Genehmigungsregeln. Verwende stattdessen einen gültigen Benutzer-/Gruppen-/Rollennamen."
@@ -47547,7 +47807,7 @@ msgid "There was a problem fetching the latest pipeline status."
msgstr "Beim Abrufen des neuesten Pipeline-Status ist ein Fehler aufgetreten."
msgid "There was a problem fetching the pipeline stage."
-msgstr ""
+msgstr "Beim Abrufen der Pipeline-Phase ist ein Fehler aufgetreten."
msgid "There was a problem fetching the pipeline stages."
msgstr "Beim Abrufen der Pipeline-Stufen ist ein Fehler aufgetreten."
@@ -47624,6 +47884,9 @@ msgstr "Fehler beim Abrufen der Top-Labels für die ausgewählte Gruppe."
msgid "There was an error fetching the variables."
msgstr "Fehler beim Abrufen der Variablen."
+msgid "There was an error fetching this merge request's pipelines."
+msgstr "Beim Abrufen der Pipelines für diesen Merge Request ist ein Fehler aufgetreten."
+
msgid "There was an error fetching value stream analytics stages."
msgstr "Beim Datenabruf der Analysephasen der Wertschöpfungskette ist ein Fehler aufgetreten."
@@ -47708,11 +47971,14 @@ msgstr "Es ist ein Fehler mit dem reCAPTCHA aufgetreten. Bitte löse das reCAPTC
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr "Diese Branchen haben bereits einen offenen Merge Request: %{link_to_mr}. Wähle einen anderen Quell- oder Ziel-Branch aus."
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr "Diese Daten beeinflussen die Darstellung deiner Epics in der Roadmap. Lege ein festes Datum oder ein Datum der Meilensteine – welche einem der Tickets in diesem Epic zugewiesen wurden – fest."
msgid "These examples show common methods of triggering a pipeline with a pipeline trigger token. The URL and ID for this project is prefilled."
-msgstr ""
+msgstr "Diese Beispiele zeigen gängige Methoden zum Auslösen einer Pipeline mit einem Pipeline-Trigger-Token. URL und ID für dieses Projekt werden vorausgefüllt."
msgid "These existing issues have a similar title. It might be better to comment there instead of creating another similar issue."
msgstr "Es gibt bereits Tickets mit ähnlichem Namen. Es könnte besser sein, dort zu kommentieren, anstatt ein weiteres, ähnliches Ticket zu erstellen."
@@ -48212,9 +48478,15 @@ msgstr "Dieser Merge Request verläuft von einem privaten Projekt zu einem inter
msgid "This merge request is from an internal project to a public project."
msgstr "Dieser Merge Request verläuft von einem internen Projekt zu einem öffentlichen Projekt."
+msgid "This merge request is hidden because its author has been banned"
+msgstr "Dieser Merge Request ist verborgen, weil sein(e) Autor(in) gesperrt wurde"
+
msgid "This merge request is locked."
msgstr "Dieser Merge Request ist gesperrt."
+msgid "This merge request is locked. Only project members can comment."
+msgstr "Dieser Merge Request ist gesperrt. Nur Projektmitglieder können kommentieren."
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr "Dieser Merge Request wurde zusammengeführt. Bearbeite diese Datei direkt, um den Vorschlag anzuwenden."
@@ -48233,11 +48505,11 @@ msgstr "Diese Pipeline nutzt eine vordefinierte CI/CD-Konfiguration mit UnterstÃ
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr "Diese Pipeline nutzt eine vordefinierte CI/CD-Konfiguration, die durch Auto DevOps aktiviert wird."
-msgid "This pipeline was triggered by a schedule"
-msgstr "Diese Pipeline wurde durch einen Zeitplan ausgelöst"
+msgid "This pipeline was created by a schedule"
+msgstr ""
-msgid "This pipeline was triggered by a schedule."
-msgstr "Diese Pipeline wurde durch einen Zeitplan ausgelöst."
+msgid "This pipeline was created by a schedule."
+msgstr ""
msgid "This process deletes the project repository and all related resources."
msgstr "Dieser Prozess löscht das Projekt-Repository und alle zugehörigen Ressourcen."
@@ -48386,8 +48658,8 @@ msgstr "Dieser/diese Benutzer(in) ist Autor(in) von %{workItemType}."
msgid "This variable value does not meet the masking requirements."
msgstr "Dieser Variablenwert entspricht nicht den Maskierungsanforderungen."
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
-msgstr "Diese Sicherheitslücke wurde automatisch behoben, da der Sicherheitslückentyp in diesem Projekt deaktiviert oder aus dem GitLab-Standardregelsatz entfernt wurde."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
+msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr "Dadurch werden deine registrierten Anwendungen und WebAuthn-Geräte ungültig."
@@ -48512,8 +48784,8 @@ msgstr "Zeitzone"
msgid "TimeTrackingEstimated|Est"
msgstr "Geschätzt"
-msgid "TimeTrackingReport|From"
-msgstr "Von"
+msgid "TimeTrackingReport|From the start of"
+msgstr "Ab dem Anfang von"
msgid "TimeTrackingReport|Run report"
msgstr "Bericht ausführen"
@@ -48533,8 +48805,8 @@ msgstr "Zusammenfassung"
msgid "TimeTrackingReport|Time spent"
msgstr "Verbrachte Zeit"
-msgid "TimeTrackingReport|To"
-msgstr "Bis"
+msgid "TimeTrackingReport|To the end of"
+msgstr "Bis zum Ende von"
msgid "TimeTrackingReport|Total time spent: "
msgstr "Insgesamt verbrachte Zeit: "
@@ -48552,7 +48824,7 @@ msgid "TimeTracking|An error occurred while removing the timelog."
msgstr "Beim Entfernen des Zeitprotokolls ist ein Fehler aufgetreten."
msgid "TimeTracking|An error occurred while saving the time estimate."
-msgstr ""
+msgstr "Beim Speichern der Zeitschätzung ist ein Fehler aufgetreten."
msgid "TimeTracking|Delete time spent"
msgstr "Zeitaufwand löschen"
@@ -48561,10 +48833,10 @@ msgid "TimeTracking|Edit estimate"
msgstr ""
msgid "TimeTracking|Edit time estimate"
-msgstr ""
+msgstr "Zeitschätzung bearbeiten"
msgid "TimeTracking|Enter time as a total duration (for example, 1mo 2w 3d 5h 10m), or specify hours and minutes (for example, 75:30)."
-msgstr ""
+msgstr "Gib die Zeit entweder als Gesamtdauer (z. B. 1 Monat, 2 Wochen, 3 Tage, 5 Stunden, 10 Minuten) oder als Stunden und Minuten an (z. B. 75:30)."
msgid "TimeTracking|Estimate"
msgstr ""
@@ -48573,7 +48845,7 @@ msgid "TimeTracking|Estimated:"
msgstr "Geschätzt:"
msgid "TimeTracking|How do I estimate and track time?"
-msgstr ""
+msgstr "Wie kann ich die Zeit abschätzen und nachverfolgen?"
msgid "TimeTracking|Over by %{timeRemainingHumanReadable}"
msgstr "Ãœberschritten um %{timeRemainingHumanReadable}"
@@ -48582,10 +48854,10 @@ msgid "TimeTracking|Set estimate"
msgstr ""
msgid "TimeTracking|Set estimated time to complete this %{issuableTypeName}."
-msgstr ""
+msgstr "Lege die geschätzte Bearbeitungsdauer für dieses/diesen %{issuableTypeName} fest."
msgid "TimeTracking|Set time estimate"
-msgstr ""
+msgstr "Geschätzte Dauer festlegen"
msgid "TimeTracking|Spent"
msgstr "Verbracht"
@@ -48927,7 +49199,7 @@ msgid "To manage seats for all members associated with this group and its subgro
msgstr "Um die Plätze für alle Mitglieder dieser Gruppe und ihrer Untergruppen und Projekte zu verwalten, besuche die Seite %{link_start}Kontingente%{link_end}."
msgid "To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
-msgstr ""
+msgstr "Um die Auswirkungen von Speicherbeschränkungen auf kostenlose Hauptgruppen zu minimieren, bietet GitLab für eine begrenzte Zeit einen %{promotion_link_start}einmaligen Rabatt von 70 Prozent%{link_end} auf den Listenpreis für %{offer_availability_link_start}qualifizierte Hauptgruppen%{link_end} beim Abschluss eines neuen, einjährigen Abonnements von GitLab Premium SaaS an. Dieses Angebot gilt bis zum 31.10.2023."
msgid "To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here."
msgstr "Um ein komplettes GitLab-Projekt von einer GitLab-Installation zu einer anderen umzuziehen oder zu kopieren, navigiere zur Einstellungsseite des Originalprojektes, erzeuge eine Export-Datei und lade sie hier hoch."
@@ -48956,8 +49228,8 @@ msgstr "Melde dich unter %{gitlab_url} bei GitLab an, um dein Konto zu reaktivie
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr "Um den %{link_start}Schreibschutz%{link_end} aufzuheben und den Schreibzugriff wiederherzustellen, bitte den/die Eigentümer(innen) der Gruppe der obersten Ebene, die Anzahl der Benutzer(innen) in deiner Gruppe der obersten Ebene auf maximal %{free_limit} Benutzer(innen) zu reduzieren oder ein Upgrade auf einen kostenpflichtigen Tarif ohne Benutzer-Limit durchzuführen."
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
-msgstr "Um den Status %{link_start}Schreibgeschützt%{link_end} aufzuheben und wieder Schreibrechte zu erhalten, kannst du die Benutzeranzahl in deiner obersten Stufe auf %{free_limit} Benutzer(innen) oder weniger reduzieren. Du kannst auch auf einen kostenpflichtigen Tarif upgraden, bei dem es keine Benutzer-Limits gibt. Wenn du mehr Zeit brauchst, kannst du eine kostenlose 30-Tage-Testversion mit beliebig vielen Benutzer(innen) starten. Um die Auswirkungen auf den Betrieb so gering wie möglich zu halten, bietet GitLab für einen begrenzten Zeitraum einen %{promotion_link_start}einmaligen Rabatt von 70 Prozent%{link_end} auf den Listenpreis zum Zeitpunkt des Kaufs eines neuen, einjährigen Abonnements von GitLab Premium SaaS für %{offer_availability_link_start}qualifizierte Gruppen der obersten Stufe%{link_end}. Das Angebot ist bis zum %{offer_date} gültig."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr "Um den %{link_start}Schreibschutz%{link_end} aufzuheben und den Schreibzugriff wiederherzustellen, kannst du die Anzahl der Benutzer(innen) in deiner Gruppe der obersten Ebene auf maximal %{free_limit} Benutzer(innen) reduzieren. Du kannst auch ein Upgrade auf einen kostenpflichtigen Tarif ohne Benutzer-Limits durchführen. Wenn du mehr Zeit benötigst, kannst du eine kostenlose 30-Tage-Testversion starten, die unbegrenzt viele Benutzer(innen) umfasst."
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
msgstr ""
@@ -49238,6 +49510,9 @@ msgstr "Dieses persönliche Zugriffstoken wurde bei der Erkennung automatisch wi
msgid "Tomorrow"
msgstr "Morgen"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr "Zu viele Namensräume aktiviert. Verwalte sie über die Konsole oder die API."
@@ -49318,6 +49593,9 @@ msgstr "Gesamt"
msgid "Total Score"
msgstr "Gesamtpunktzahl"
+msgid "Total Spans"
+msgstr "Gesamtumfang"
+
msgid "Total cores (CPUs)"
msgstr "Gesamtkerne (CPUs)"
@@ -49348,9 +49626,15 @@ msgstr "Mehr als 1000"
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr "Nachverfolgungsstart"
+
msgid "Tracing"
msgstr "Nachverfolgung"
+msgid "Tracing|%{ms} ms"
+msgstr "%{ms} ms"
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr "Bereichsdetails"
+
+msgid "Tracing|Span ID"
+msgstr "Bereichs-ID"
+
+msgid "Tracing|Status Code"
+msgstr "Statuscode"
+
+msgid "Tracing|Toggle children spans"
+msgstr "Untergeordnete Bereiche umschalten"
+
msgid "Tracing|Trace ID"
msgstr "Spur-ID"
@@ -49547,13 +49843,13 @@ msgid "Trials|Day %{daysUsed}/%{duration}"
msgstr "Tag %{daysUsed}/%{duration}"
msgid "Trials|Looking to do more with GitLab?"
-msgstr ""
+msgstr "Möchtest du mit GitLab mehr erreichen?"
msgid "Trials|Upgrade your plan for more security features"
-msgstr ""
+msgstr "Tarif erweitern für mehr Sicherheitsfunktionen"
msgid "Trials|With GitLab Ultimate you can detect and address vulnerabilities in your application."
-msgstr ""
+msgstr "Mit GitLab Ultimate kannst du Sicherheitslücken in deiner Anwendung erkennen und beheben."
msgid "Trials|You can apply your trial to a new group or an existing group."
msgstr "Du kannst deine Testversion auf eine neue oder eine vorhandene Gruppe anwenden."
@@ -49564,7 +49860,7 @@ msgstr[0] "Du hast %{daysRemaining} Tag für GitLab %{planName} verbleibend!"
msgstr[1] "Du hast %{daysRemaining} Tage für GitLab %{planName} verbleibend!"
msgid "Trials|Your 30-day trial has ended"
-msgstr ""
+msgstr "Deine 30-Tage-Testversion ist abgelaufen."
msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
msgstr "Deine Testversion endet am %{boldStart}%{trialEndDate}%{boldEnd}. Wir hoffen, dass dir die Funktionen von GitLab %{planName} gefallen. Um diese Funktionen nach Ablauf Ihrer Testversion beizubehalten, musst du ein Abonnement erwerben. (Du kannst auch GitLab Premium wählen, wenn es deinen Anforderungen entspricht.)"
@@ -49788,9 +50084,6 @@ msgstr "URL oder Anfrage-ID"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr "BENUTZER(IN) %{user_name} WIRD ENTFERNT! Bist du sicher?"
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "BENUTZER(IN) %{user} WIRD ENTFERNT! Möchtest du wirklich fortfahren?"
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "BENUTZER(IN) WIRD BLOCKIERT! Möchtest du wirklich fortfahren?"
@@ -49878,6 +50171,9 @@ msgstr "Das Merge-Request-Widget konnte nicht geladen werden. Versuche, die Seit
msgid "Unable to load the page"
msgstr "Seite kann nicht geladen werden"
+msgid "Unable to load user list. Reload the page and try again."
+msgstr "Die Benutzerliste konnte nicht geladen werden. Lade die Seite erneut, um es noch einmal zu versuchen."
+
msgid "Unable to parse JSON"
msgstr "JSON konnte nicht geparst werden"
@@ -49911,9 +50207,6 @@ msgstr "Dieser Epic kann derzeit nicht aktualisiert werden."
msgid "Unable to update this issue at this time."
msgstr "Dieses Ticket kann gerade nicht aktualisiert werden."
-msgid "Unable to verify the user"
-msgstr "Es ist nicht möglich, den/die Benutzer(in) zu überprüfen"
-
msgid "Unapprove a merge request"
msgstr "Genehmigung eines Merge Requests aufheben"
@@ -49992,6 +50285,9 @@ msgstr "Leider konnte deine E-Mail an GitLab nicht verarbeitet werden."
msgid "Unhappy?"
msgstr "Unzufrieden?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr "d"
@@ -50367,6 +50663,9 @@ msgstr "Zusätzliche Compute-Minuten kaufen"
msgid "UsageQuota|Buy storage"
msgstr "Speicher kaufen"
+msgid "UsageQuota|Code Suggestions"
+msgstr "Code-Vorschläge"
+
msgid "UsageQuota|Code packages and container images."
msgstr "Code-Pakete und Container-Images."
@@ -50388,12 +50687,12 @@ msgstr "Container-Registry"
msgid "UsageQuota|Dependency proxy"
msgstr "Abhängigkeits-Proxy"
-msgid "UsageQuota|Filter chart by month"
-msgstr "Diagramm nach Monat filtern"
-
msgid "UsageQuota|Filter charts by year"
msgstr "Diagramme nach Jahr filtern"
+msgid "UsageQuota|Filter projects data by month"
+msgstr "Projektdaten nach Monat filtern"
+
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
msgstr "Weitere Informationen zu Speicherlimits findest du in unseren %{faq_link_start}FAQ%{link_end}."
@@ -50404,7 +50703,7 @@ msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker
msgstr "Mit GitLab integrierte Docker-Container-Registry zum Speichern von Docker Images."
msgid "UsageQuota|Group settings %{gt} Usage quotas"
-msgstr ""
+msgstr "Gruppeneinstellungen %{gt} Nutzungskontingente"
msgid "UsageQuota|Included in %{planName} subscription"
msgstr "Inbegriffen in Abonnement %{planName}"
@@ -50439,6 +50738,9 @@ msgstr "Namensraumübersicht"
msgid "UsageQuota|Namespace storage used"
msgstr "Verwendeter Namensraumspeicher"
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr "Der Gesamtspeicher des Namensraums ist die Summe des von allen Projekten, der Container-Registry und dem Abhängigkeits-Proxy verbrauchten Speichers."
+
msgid "UsageQuota|No compute usage data available."
msgstr "Keine Daten zur Nutzung des Rechenkontingents verfügbar."
@@ -50505,15 +50807,15 @@ msgstr "Dies wirkt sich auf die Gruppe %{strong_start}%{context_name}%{strong_en
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr "Dies wirkt sich auf das Projekt %{strong_start}%{context_name}%{strong_end} aus. "
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr "Das Diagramm und die folgende Tabelle zeigen die Verwendung für %{month} %{year}"
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
-msgstr ""
+msgstr "Der Namensraum verwendet derzeit %{strong_start}%{used_storage}%{strong_end} des Namensraum-Speichers. Gruppeneigentümer(innen) können die Nutzung des Namensraum-Speichers anzeigen und unter %{strong_start}%{usage_quotas_nav_instruction}%{strong_end} mehr Speicherplatz erwerben. %{docs_link_start}Wie kann ich meinen Speicher verwalten%{link_end}?"
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr "Der Namensraum verwendet derzeit %{strong_start}%{used_storage}%{strong_end} des Speichers für Namensräume. Hier kannst du die Nutzung anzeigen und verwalten %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Erfahre mehr%{link_end} darüber, wie du deinen Speicherverbrauch reduzieren kannst."
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr "Die folgende Tabelle zeigt die Nutzung seit %{usageSince}."
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr "Dieser Namensraum hat %{planLimit} Speicherplatz. %{linkStart}Wie werden Limits angewendet?%{linkEnd}"
@@ -50572,7 +50874,7 @@ msgid "UsageQuota|Usage of resources across your projects"
msgstr "Nutzung von Ressourcen in deinen Projekten"
msgid "UsageQuota|User settings %{gt} Usage quotas"
-msgstr ""
+msgstr "Benutzereinstellungen %{gt} Nutzungskontingente"
msgid "UsageQuota|Wiki content."
msgstr "Wiki-Inhalt."
@@ -51185,6 +51487,9 @@ msgstr "Benutzername ist verfügbar."
msgid "Username or email"
msgstr "Benutzername oder E-Mail"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Nutzername:"
@@ -51312,25 +51617,25 @@ msgid "Validations failed."
msgstr "Überprüfungen fehlgeschlagen."
msgid "Validation|can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"
-msgstr ""
+msgstr "darf nur Kleinbuchstaben, Ziffern sowie _ und - enthalten Muss mit einem Buchstaben beginnen und darf nicht mit - oder _ enden"
msgid "Validation|groupId parameter is invalid"
-msgstr ""
+msgstr "groupId-Parameter ist ungültig."
msgid "Validation|must belong to the same project"
-msgstr ""
+msgstr "muss zum gleichen Projekt gehören"
msgid "Validation|parameters are invalid"
-msgstr ""
+msgstr "Parameter sind ungültig"
msgid "Validation|percentage must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "Prozentwert muss eine Zeichenfolge zwischen 0 und 100 (jeweils inklusive) sein"
msgid "Validation|rollout must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "Rollout muss eine Zeichenfolge zwischen 0 und 100 (jeweils inklusive) sein"
msgid "Validation|strategy name is invalid"
-msgstr ""
+msgstr "Strategiename ist ungültig"
msgid "Value"
msgstr "Wert"
@@ -51748,7 +52053,7 @@ msgid "View the latest successful deployment to this environment"
msgstr "Letzte erfolgreiche Bereitstellung in dieser Umgebung anzeigen"
msgid "View trigger token usage examples"
-msgstr ""
+msgstr "Nutzungsbeispiele für Trigger-Token anzeigen"
msgid "View usage details"
msgstr "Nutzungsdetails anzeigen"
@@ -51888,6 +52193,9 @@ msgstr "Details"
msgid "VulnerabilityExport|Detected At"
msgstr "Erkennungszeitpunkt"
+msgid "VulnerabilityExport|Full Path"
+msgstr "Vollständiger Pfad"
+
msgid "VulnerabilityExport|Group Name"
msgstr "Gruppenname"
@@ -51915,17 +52223,20 @@ msgstr "Tool"
msgid "VulnerabilityExport|Vulnerability"
msgstr "Sicherheitslücke"
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Bestätigt%{statusEnd} %{timeago} von %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{statusStart}Bestätigung von%{statusEnd} · %{timeago} durch %{user}"
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr "%{statusStart}Erkennung von%{statusEnd} · %{timeago} in Pipeline %{pipelineLink}"
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "%{statusStart}Erkannt%{statusEnd} %{timeago} in Pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{statusStart}Verwerfung von%{statusEnd} · %{timeago} durch %{user}"
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Verworfen%{statusEnd} %{timeago} von %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr "%{statusStart}Verwerfung von%{statusEnd}: %{dismissalReason} · %{timeago} durch %{user}"
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Aufgelöst%{statusEnd} %{timeago} von %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{statusStart}Auflösung von%{statusEnd} · %{timeago} durch %{user}"
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr "(Optional) Gib die Lösung für die Sicherheitslücke an, falls vorhanden."
@@ -52060,7 +52371,7 @@ msgid "VulnerabilityStatusTypes|Resolved"
msgstr "Behoben"
msgid "Vulnerability|%{file} was not found in commit %{ref}"
-msgstr ""
+msgstr "%{file} konnte in Commit %{ref} nicht gefunden werden."
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (Version %{scannerVersion})"
@@ -52167,6 +52478,9 @@ msgstr "Datei:"
msgid "Vulnerability|GitLab Security Report"
msgstr "GitLab-Sicherheitsbericht"
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr "GitLab hat vertrauliche Zeichenfolgen im Code-Schnipsel für die KI-Eingabeaufforderung identifiziert, die auf ein möglicherweise durchgesickertes Geheimnis hinweisen. Bitte überprüfe deinen Code, bevor du die Funktion „Erklärung zu dieser Sicherheitslücke“ verwendest. Wenn du trotzdem fortfährst und den %{linkStart}Code%{linkEnd} an die KI senden möchtest, klicke auf das Kontrollkästchen unten."
+
msgid "Vulnerability|Hide prompt"
msgstr "Eingabeaufforderung ausblenden"
@@ -52264,7 +52578,7 @@ msgid "Vulnerability|Show prompt"
msgstr "Eingabeaufforderung anzeigen"
msgid "Vulnerability|Something went wrong while trying to get the source file."
-msgstr ""
+msgstr "Fehler beim Versuch, die Quelldatei abzurufen"
msgid "Vulnerability|Stacktrace snippet:"
msgstr ""
@@ -52281,11 +52595,8 @@ msgstr "Der Scanner hat festgestellt, dass es sich bei dieser Sicherheitslücke
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr "Die unveränderte Antwort ist die ursprüngliche Antwort, bei der keine Mutationen an der Anfrage vorgenommen wurden"
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr "Es ist ein unerwarteter Fehler aufgetreten. %{linkStart}Bitte versuche es erneut%{linkEnd}."
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
-msgstr "Dies ist eine experimentelle Funktion, die KI verwendet, um die Sicherheitslücke zu erklären und Empfehlungen abzugeben. Verwende diese Funktion mit Vorsicht, während wir sie weiterentwickeln. Bitte gib dein Feedback und deine Ideen in %{linkStart}diesem Ticket%{linkEnd} an."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgstr "Dies ist eine Beta-Funktion, die KI verwendet, um die Sicherheitslücke zu erklären und Empfehlungen abzugeben. Verwende diese Funktion mit Vorsicht, während wir sie weiterentwickeln. Wir freuen uns über dein Feedback und deine Ideen in %{linkStart}diesem Ticket%{linkEnd}."
msgid "Vulnerability|Tool"
msgstr "Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr "Warnung: mögliche Geheimnisse entdeckt"
+
msgid "WARNING:"
msgstr "WARNUNG:"
@@ -52647,6 +52961,12 @@ msgstr "Reguläre Ausdrücke wie %{REGEX_CODE} werden unterstützt."
msgid "Webhooks|Releases events"
msgstr "Veröffentlichungsereignisse"
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr "SSL-Verifizierung"
@@ -52749,15 +53069,6 @@ msgstr "Willkommen zu einem neuen Navigationserlebnis"
msgid "Welcome, %{name}!"
msgstr "Willkommen, %{name}!"
-msgid "What are group audit events?"
-msgstr "Was sind Gruppen-Audit-Ereignisse?"
-
-msgid "What are instance audit events?"
-msgstr "Was sind Instanz-Audit-Ereignisse?"
-
-msgid "What are project audit events?"
-msgstr "Was sind Projekt-Audit-Ereignisse?"
-
msgid "What are some examples?"
msgstr "Wie lauten einige Beispiele?"
@@ -53112,6 +53423,12 @@ msgstr "Limit für offene Elemente"
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr "Workitems sind bereits verknüpft"
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr "Dieses Workitem würde die maximale Anzahl der verknüpften Elemente überschreiten."
+
msgid "WorkItem|%{count} more assignees"
msgstr "%{count} weitere Beauftragte"
@@ -53204,9 +53521,6 @@ msgstr "E-Mail-Adresse von %{workItemType} kopieren"
msgid "WorkItem|Create %{workItemType}"
msgstr "%{workItemType} erstellen"
-msgid "WorkItem|Create objective"
-msgstr "Ziel erstellen"
-
msgid "WorkItem|Create work item"
msgstr "Workitem erstellen"
@@ -53225,9 +53539,6 @@ msgstr "Fälligkeitsdatum"
msgid "WorkItem|Existing task"
msgstr "Vorhandene Aufgabe"
-msgid "WorkItem|Health status"
-msgstr "Integritätsstatus"
-
msgid "WorkItem|History only"
msgstr "Nur Verlauf"
@@ -53246,14 +53557,20 @@ msgstr "Schlüsselergebnis"
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr "Als erledigt markieren"
msgid "WorkItem|Milestone"
msgstr "Meilenstein"
-msgid "WorkItem|New objective"
-msgstr "Neues Ziel"
+msgid "WorkItem|New %{workItemType}"
+msgstr "Neue(r, s) %{workItemType}"
msgid "WorkItem|New task"
msgstr "Neue Aufgabe"
@@ -53337,7 +53654,7 @@ msgid "WorkItem|Something went wrong when fetching work item types. Please try a
msgstr "Beim Abrufen der Workitem-Typen ist etwas schiefgelaufen. Bitte erneut versuchen"
msgid "WorkItem|Something went wrong when fetching work items. Please try again."
-msgstr ""
+msgstr "Fehler beim Abrufen der Arbeitsaufgaben Bitte erneut versuchen."
msgid "WorkItem|Something went wrong when trying to add a child. Please try again."
msgstr "Beim Versuch, ein untergeordnetes Element hinzuzufügen, ist ein Fehler aufgetreten. Bitte erneut versuchen."
@@ -53396,9 +53713,6 @@ msgstr "Testfall"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr "Dieses Element (%{workItemType}) ist vertraulich und sollte nur für Teammitglieder mit mindestens der Rolle Reporter(in) sichtbar sein."
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr "Dieses Ziel ist vertraulich und sollte nur für Teammitglieder mit mindestens der Rolle Reporter(in) sichtbar sein."
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr "Dieser Arbeitsaufgabe ist nicht verfügbar. Entweder existiert sie nicht oder Du hast nicht die Berechtigung, sie anzuzeigen."
@@ -53429,8 +53743,8 @@ msgstr "Du siehst nur %{boldStart}andere Aktivitäten%{boldEnd} im Feed. Wechsle
msgid "Workspaces"
msgstr "Arbeitsbereiche"
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
-msgstr "Ein Arbeitsbereich ist eine virtuelle Sandbox-Umgebung für deinen Code in GitLab. Du kannst einen Arbeitsbereich für ein öffentliches Projekt erstellen."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
+msgstr ""
msgid "Workspaces|Cancel"
msgstr "Abbrechen"
@@ -53528,9 +53842,6 @@ msgstr "Unbekannter Status"
msgid "Workspaces|Workspaces"
msgstr "Arbeitsbereiche"
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr "Du kannst nur einen Arbeitsbereich für öffentliche Projekte erstellen."
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr "Du kannst keinen Arbeitsbereich für dieses Projekt erstellen."
@@ -53791,6 +54102,9 @@ msgstr "Du kannst ein neues persönliches Zugriffstoken erstellen, indem du %{li
msgid "You can create a new SSH key by visiting %{link}"
msgstr "Du kannst einen neuen SSH-Schlüssel erstellen, indem du %{link} besuchst"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr "Du kannst ein neues Token erstellen oder sie in den Einstellungen für deine %{pat_link_start}persönlichen Zugriffstoken%{pat_link_end} überprüfen."
@@ -53800,6 +54114,9 @@ msgstr "Du kannst einen neuen erstellen oder sie in deinen %{ssh_key_link_start}
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr "Du kannst einen neuen erstellen oder sie in deinen SSH-Schlüsseleinstellungen %{ssh_key_link} überprüfen."
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr "Du kannst ein neues erstellen oder sie in den Einstellungen zu deinen persönlichen Zugriffstoken (%{pat_link}) überprüfen."
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr "Du hast momentan keine Bereitstellungen."
-
msgid "You don't have any open merge requests"
msgstr "Du hast keine offene Merge Requests"
@@ -54073,7 +54387,7 @@ msgid "You have insufficient permissions to create a Todo for this alert"
msgstr "Du hast keine Berechtigung, um eine Aufgabe für diesen Alarm zu erstellen."
msgid "You have insufficient permissions to create a target branch rule"
-msgstr ""
+msgstr "Du hast nicht die erforderlichen Berechtigungen, um eine Zielbranch-Regel zu erstellen."
msgid "You have insufficient permissions to create an HTTP integration for this project"
msgstr "Du hast nicht genügend Berechtigungen, um eine HTTP-Integration für dieses Projekt zu erstellen"
@@ -54387,7 +54701,7 @@ msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limi
msgstr ""
msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. You should reduce the number of users or upgrade to a paid tier %{strong_start}before%{strong_end} you manage your storage usage. Otherwise, your Free top-level group will become read-only immediately because the 5-user limit applies. For more information, see our %{faq_link_start}FAQ%{link_end}.%{br_tag}%{br_tag}To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
-msgstr ""
+msgstr "Deine kostenlose Hauptgruppe %{group_name} hat mehr als %{free_users_limit} Benutzer(innen) und nutzt mehr als %{free_storage_limit} an Daten. Beim Anwenden der Nutzungsbeschränkungen für kostenlose Hauptgruppen werden die Projekte in dieser Gruppe als %{read_only_link_start}schreibgeschützt%{link_end} festgelegt. Reduziere die Anzahl der Benutzer(innen) oder führe ein Upgrade auf einen kostenpflichtigen Tarif durch, %{strong_start}bevor%{strong_end} du deine Speichernutzung verwaltest. Andernfalls wird deine kostenlose Hauptgruppe sofort als schreibgeschützt festgelegt, da der Grenzwert von fünf Benutzer(inne)n gilt. Weitere Informationen findest du in unseren %{faq_link_start}häufig gestellten Fragen (FAQ)%{link_end}.%{br_tag}%{br_tag}Um die Auswirkungen von Speicherbeschränkungen auf kostenlose Hauptgruppen zu minimieren, bietet GitLab für eine begrenzte Zeit einen %{promotion_link_start}einmaligen Rabatt von 70 Prozent%{link_end} auf den Listenpreis für %{offer_availability_link_start}qualifizierte Hauptgruppen%{link_end} beim Abschluss eines neuen, einjährigen Abonnements von GitLab Premium SaaS an. Dieses Angebot gilt bis zum 31.10.2023."
msgid "Your GPG keys"
msgstr "Deine GPG-Schlüssel"
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "Deine autorisierten Anwendungen"
-msgid "Your browser does not support iFrames"
-msgstr "Dein Browser unterstützt keine iFrames"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr "Dein Browser unterstützt WebAuthn nicht. Bitte verwende einen unterstützten Browser, z. B. Chrome (67+) oder Firefox (60+)."
@@ -54619,9 +54930,6 @@ msgstr "Eines oder mehrere deiner persönlichen Zugriffstoken laufen in %{days_t
msgid "Your profile"
msgstr "Dein Profil"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr "Dein Projekt erhält seit 01.07.2022 keine Ultimate-Vorteile mehr. Wie bereits in der App mitgeteilt, können sich öffentliche Open-Source-Projekte aus der Free-Version für das „GitLab für Open Source“-Programm bewerben, um die Ultimate-Vorteile zu erhalten. Weitere Informationen findest Du in den %{faq_link_start}FAQs%{link_end}."
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "Dein Projektlimit ist %{limit} Projekte! Bitte kontaktieren deine(n) Administrator(in), um es zu erhöhen"
@@ -54646,6 +54954,9 @@ msgstr "Deine Anforderungen werden importiert. Sobald du fertig bist, erhältst
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr "Deine Anforderungen werden im Hintergrund importiert. Sobald dieser Prozess abgeschlossen ist, erhältst du eine Bestätigungs-E-Mail."
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr "Deine Suche hat keine Commits gefunden."
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr "scheitern erlaubt"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr "bereits aus dem Namensraum verbannt"
@@ -54924,6 +55238,9 @@ msgstr "kann nicht zu %{new_type} umgewandelt werden"
msgid "can not be changed when assigned to an epic"
msgstr "kann nicht geändert werden, wenn es einem Epic zugewiesen ist"
+msgid "can not be set for template labels"
+msgstr "kann für Vorlagenbeschriftungen nicht festgelegt werden"
+
msgid "can not be set for this resource"
msgstr "kann für diese Ressource nicht festgelegt werden"
@@ -55437,11 +55754,14 @@ msgid "created %{timeAgo} by %{author} in %{project_link}"
msgstr "vor %{timeAgo} erstellt von %{author} in %{project_link}"
msgid "created %{timeAgo} by %{email} via %{author}"
-msgstr ""
+msgstr "Erstellt %{timeAgo} von %{email} über %{author}"
msgid "created by"
msgstr "erstellt von"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr "täglich"
@@ -55509,6 +55829,9 @@ msgstr "z. B. %{token}"
msgid "eg party_tanuki"
msgstr "z.B. party_tanuki"
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr "Element ist keine Hierarchie"
@@ -55595,9 +55918,6 @@ msgstr[1] "Dateien"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "Fund wurde nicht gefunden oder ist bereits mit einer Sicherheitslücke verknüpft."
-msgid "for Workspace is required to be public"
-msgstr "für den Arbeitsbereich ist erforderlich, um öffentlich zu sein"
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr "für den Arbeitsbereich muss eine zugehörige RemoteDevelopmentAgentConfig vorhanden sein"
@@ -55861,6 +56181,9 @@ msgstr "ist zu groß"
msgid "jigsaw is not defined"
msgstr "jigsaw ist nicht definiert"
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr "kuromoji benutzerdefinierter Analysator"
@@ -56336,6 +56659,9 @@ msgstr "muss sich innerhalb des Fork-Netzwerks befinden"
msgid "must be less than the limit of %{tag_limit} tags"
msgstr "muss kleiner als das Limit von %{tag_limit} Tags sein"
+msgid "must be owned by the user's enterprise group"
+msgstr "muss im Besitz der Enterprise-Gruppe des/der Benutzer(in) sein"
+
msgid "must be set for a project namespace"
msgstr "muss für einen Projektnamensraum gesetzt werden"
@@ -56345,6 +56671,9 @@ msgstr "muss angegeben werden"
msgid "must be unique by status and elapsed time within a policy"
msgstr "muss nach Status und verstrichener Zeit innerhalb einer Richtlinie eindeutig sein"
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr "muss einmalig sein. Diese CA wurde bereits für einen anderen Namensraum konfiguriert."
+
msgid "must belong to same project of its requirement object."
msgstr "muss zum gleichen Projekt gehören wie seine abhängigen Objekte."
@@ -56372,6 +56701,9 @@ msgstr "darf nicht Eigentümer(in) des Namensraums sein"
msgid "must not contain commonly used combinations of words and letters"
msgstr "darf keine häufig verwendeten Kombinationen von Wörtern und Buchstaben enthalten"
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr "meine-tolle-gruppe"
@@ -56429,6 +56761,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, und %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr "am oder nach"
@@ -56730,6 +57065,9 @@ msgstr "%{slash_command} addiert oder subtrahiert die bereits aufgewendete Zeit.
msgid "ssh:"
msgstr "SSH:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "hat eine Diskussion auf %{design_link} begonnen"
@@ -56772,6 +57110,9 @@ msgstr "Tag-Name"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr "Terraform-Status"
@@ -56820,9 +57161,6 @@ msgstr "Wert muss kleiner als oder gleich %{size} sein."
msgid "triggered"
msgstr "ausgelöst"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr "hat Pipeline für Commit %{linkStart}%{shortId}%{linkEnd} ausgelöst"
-
msgid "two-factor authentication settings"
msgstr "Einrichtung Zwei-Faktor-Authentifizierung"
@@ -56879,6 +57217,9 @@ msgstr "Version %{report_version} vom Reporttyp %{report_type} ist veraltet. Git
msgid "version %{versionIndex}"
msgstr "Version %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "durch %{closed_via}"
diff --git a/locale/el_GR/gitlab.po b/locale/el_GR/gitlab.po
index 158f8a8034d..14fbe30506c 100644
--- a/locale/el_GR/gitlab.po
+++ b/locale/el_GR/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: el\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/en_GB/gitlab.po b/locale/en_GB/gitlab.po
index ff22308d1a0..21df082bd4e 100644
--- a/locale/en_GB/gitlab.po
+++ b/locale/en_GB/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: en-GB\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr " %{start} to %{end}"
@@ -45,6 +45,11 @@ msgstr " and "
msgid " and %{sliced}"
msgstr " and %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " or "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr "%{count} total weight"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} could not be found."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} days until tags are automatically removed"
@@ -718,8 +720,8 @@ msgstr "%{edit_in_new_fork_notice} Try to upload a file again."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr ""
msgid "%{extra} more downstream pipelines"
msgstr "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr "%{issuesSize} with a limit of %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} issues with a limit of %{maxIssueCount}"
@@ -871,6 +879,9 @@ msgstr "%{labelStart}Unmodified response:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} unavailable"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,8 +3889,8 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
-msgstr "Can create group"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr ""
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr "An error occurred while fetching label colours."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "An error occurred while saving your settings. Try saving them again."
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr "A header with this name already exists."
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "Value"
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr "Configure advanced permissions, Large File Storage, two-factor authentic
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr "This action will %{docsStart}retry the latest deployment%{docsEnd} with
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr "This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Updating your Pages configuration..."
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr " %{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr "Create new subgroup"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "Groups are the best way to manage multiple projects and members."
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr "No subgroups or projects."
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "Projects are where you can store your code, access issues, wiki, and other features of GitLab."
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
@@ -32642,9 +32698,6 @@ msgstr "Only accessible by %{membersPageLinkStart}project members%{membersPageLi
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr "Ordered list"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr "Don't display activity-related personal information on your profile."
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr "Select groups"
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "Your organisation's SSO has been connected to your GitLab account"
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr "Failed to load cluster agents."
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr "Upload new licence"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr "already banned from namespace"
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr "kuromoji custom analyser"
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index 0c9f24585df..4141ac368b5 100644
--- a/locale/eo/gitlab.po
+++ b/locale/eo/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: eo\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Ĉu vi certe volas forigi ĉi tiun ĉenstablan planon?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "Horzono por Cron"
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr "Difini propran Åablonon, uzante la sintakson de Cron"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "Intervala Åablono"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr "Lasta ĉenstablo"
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr "Nova plano"
-
msgid "New snippet"
msgstr "Nova kodaĵo"
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "Ne estas planoj"
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr "Opcioj"
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "Åœaltita"
-
msgid "PipelineSchedules|Active"
msgstr "Åœaltitaj"
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Variabloj"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr "Konservi ĉenstablan planon"
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index dd2ac2943bb..aae7c53d1e7 100644
--- a/locale/es/gitlab.po
+++ b/locale/es/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: es-ES\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr " %{start} hasta %{end}"
@@ -45,6 +45,11 @@ msgstr " y "
msgid " and %{sliced}"
msgstr " y %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " o "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr "%{count} peso total"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} no se ha encontrado."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} días hasta que las etiquetas se eliminen automáticamente"
@@ -718,7 +720,7 @@ msgstr "%{edit_in_new_fork_notice} Intente subir un archivo de nuevo."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@empresa.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr "%{issuesSize} con un límite de %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Novedades%{italic_end} está inactivo y no se puede ver."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} incidencias con un límite de %{maxIssueCount}"
@@ -871,9 +879,12 @@ msgstr "%{labelStart}Respuesta sin modificar:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} no disponible"
-msgid "%{label_name} was removed"
+msgid "%{label_name} is locked and was not removed"
msgstr ""
+msgid "%{label_name} was removed"
+msgstr "%{label_name} fue eliminado"
+
msgid "%{lessThan} 1 hour"
msgstr "%{lessThan} 1 hora"
@@ -1319,11 +1330,11 @@ msgstr "%{verb} %{time_spent_value} tiempo gastado."
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} le permiten enviar notificaciones a aplicaciones web en respuesta a los eventos generados en un grupo o en un proyecto."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} te permite mandar notificaciones a aplicaciones web como respuesta a los eventos de un grupo o proyecto."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} le permiten enviar notificaciones a aplicaciones web en respuesta a los eventos generados en un grupo o en un proyecto. Recomendamos utilizar una %{integrations_link_start}integración%{link_end} en lugar de un webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr "%{widget} opciones"
@@ -1429,6 +1440,9 @@ msgstr "+ %{amount} más"
msgid "+ %{count} more"
msgstr "+ %{count} más"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} más"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Aceptar invitación"
@@ -2444,6 +2494,9 @@ msgstr "Grupos"
msgid "AccessDropdown|Roles"
msgstr "Roles"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "Usuarios"
@@ -2624,6 +2677,9 @@ msgstr "Aceptar"
msgid "Action"
msgstr "Acción"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr "Añadir sugerencia para el lote"
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr "Añadir a revisión"
msgid "Add to tree"
msgstr "Añadir al árbol"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr "AddContextCommits|Añadir/eliminar"
msgid "AddMember|Invite email is invalid"
msgstr "El correo electrónico de invitación no es válido"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,8 +3889,8 @@ msgstr "Bloquear usuario tiene los siguientes efectos:"
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
-msgstr "Puede crear grupo"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "No se puede iniciar sesión ni accesar a la información de la instancia"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr "Añadir nueva integración"
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr "Ha ocurrido un error visualizando el blob"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr "Se ha producido un error al actualizar el título"
@@ -4982,6 +5044,9 @@ msgstr "Se ha producido un error al obtener las incidencias."
msgid "An error occurred while fetching label colors."
msgstr "Se ha producido un error al obtener los colores de las etiquetas."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr "Se ha producido un error al obtener los participantes"
@@ -5167,6 +5232,9 @@ msgstr[1] "Se han producido un error al guardar los ajustes."
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "Se ha producido un error al ejecutar el trabajo."
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "Se ha producido un error al actualizar los aprobadores"
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,9 +5468,12 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
-msgid "Analytics|Language"
+msgid "Analytics|Invalid visualization configuration"
msgstr ""
+msgid "Analytics|Language"
+msgstr "Idioma"
+
msgid "Analytics|Line Chart"
msgstr ""
@@ -5407,7 +5496,7 @@ msgid "Analytics|OS Version"
msgstr ""
msgid "Analytics|Page Language"
-msgstr ""
+msgstr "Idioma de la página"
msgid "Analytics|Page Path"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr "¿Está seguro de que desea borrar este dispositivo? Esta acción no se
msgid "Are you sure you want to delete this label?"
msgstr "¿Está seguro de que quiere borrar esta etiqueta?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "¿Estás seguro que deseas eliminar esta programación del pipeline?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "¿Está seguro que desea eliminar este pipeline? Al hacerlo caducarán todas las cachés del pipeline y se eliminarán todos los objetos relacionados, como construcciones, logs, artefactos y disparadores. Esta acción no se puede deshacer."
@@ -6283,7 +6375,7 @@ msgstr "¿Estás seguro de que desea restablecer el token de registro?"
msgid "Are you sure you want to retry this migration?"
msgstr "¿Está seguro de que desea volver a intentar esta migración?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "Pregunta de nuevo más tarde"
@@ -6638,6 +6733,9 @@ msgstr "AuditStreams|Ya existe un cabecera con este nombre."
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "AuditStreams|Valor"
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr "No es posible eliminar al usuario"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr "Membresías directas"
msgid "Billing|Enter at least three characters to search."
msgstr "Introduzca al menos tres caracteres para buscar."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr "No hay usuarios para mostrar."
@@ -7735,6 +7842,12 @@ msgstr "Invitación al proyecto"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "Eliminar al usuario %{username} de su suscripción"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "Está a punto de eliminar al usuario %{username} de su suscripción. Si continua, el usuario será eliminado del grupo %{namespace} y todos sus subgrupos y proyectos. Esta acción no se puede deshacer."
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] "Bloqueado por %d las incidencia"
msgid "Blocked issue"
msgstr "Incidencia bloqueada"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr "Bloqueando"
@@ -7839,9 +7958,6 @@ msgstr "No hay resultados coincidentes"
msgid "BoardNewEpic|Search groups"
msgstr "Buscar grupos"
-msgid "BoardNewEpic|Select a group"
-msgstr "Seleccionar un grupo"
-
msgid "BoardNewIssue|No matching results"
msgstr "No hay resultados coincidentes"
@@ -7929,9 +8045,6 @@ msgstr "Seleccione las etiquetas"
msgid "BoardScope|Select milestone"
msgstr "Seleccionar hito"
-msgid "BoardScope|Select weight"
-msgstr "Seleccionar peso"
-
msgid "BoardScope|Started"
msgstr "Iniciado"
@@ -8342,7 +8455,7 @@ msgid "BranchRules|Users"
msgstr ""
msgid "BranchRules|View details"
-msgstr ""
+msgstr "Ver detalles"
msgid "BranchRules|default"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,8 +9215,8 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr "Puede ser desplegado manualmente en"
-msgid "Can create groups:"
-msgstr "Puede crear grupos:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr ""
@@ -9489,6 +9602,9 @@ msgstr "No se han guardado los cambios en el título"
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr "Compruebe sus imágenes de Docker para detectar vulnerabilidades conocid
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Comprobando disponibilidad de %{text}..."
@@ -9637,8 +9756,8 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "plan %{selectedPlanText}"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr "Elegir una plantilla..."
msgid "Choose a type..."
msgstr "Elegir un tipo..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Seleccione un archivo…"
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "No se puede utilizar una variable enmascarada con el valor actual"
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr "Entornos"
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr "Eliminar fila de variables"
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Tipo"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Valor"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (Todos los entornos)"
-
msgid "CiVariable|All environments"
msgstr "Todos los entornos"
@@ -10359,6 +10487,9 @@ msgstr "Clientes"
msgid "Clientside DSN"
msgstr "DSN del lado del cliente"
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Clonar"
@@ -10656,15 +10787,9 @@ msgstr "Estado de salud del clúster"
msgid "Cluster cache cleared."
msgstr "Borrada la caché del clúster."
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr "Nivel de clúster"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr "Este agente no tiene tokens"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "Para eliminar el agente, escriba %{name} para confirmar:"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr "Ver todos los agentes %{number}"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "Ver todos los %{number} clústeres"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "Nos encantaría saber más sobre su experiencia con GitLab Agent."
@@ -11402,9 +11533,6 @@ msgstr "Revisión de código"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
-msgstr ""
-
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr "Contraer"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr "Contraer todos los hilos"
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr "Framework de cumplimiento"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Añadir framework"
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr "Confidencialidad"
msgid "Configuration help"
msgstr "Ayuda de configuración"
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr "Error de conexión"
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "Contactar con soporte"
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr "Crear versión"
msgid "Create requirement"
msgstr "Crear requisito"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr "Crear cuenta de servicio"
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "Zona horaria del Cron"
-
msgid "Cron time zone"
msgstr "Zona horaria Cron"
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr "Mínimo = 0 (sin tiempo de espera habilitado), Máximo = 2880 minutos"
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "Mínimo = 1 segundo, Máximo = 3600 segundos"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr "Definir un patrón personalizado con la sintaxis de cron"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr "Eliminar pipeline"
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr "Eliminar proyecto"
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr "Empaquetador"
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr "Zona horaria"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} otros"
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr "Proyecto actual"
@@ -15985,8 +16179,8 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr "Cargando claves de despliegue"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "No se han encontrado claves de despliegue. Puede crear unas utilizando el formulario de arriba."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "Claves de despliegue accesibles de modo privado"
@@ -16000,8 +16194,8 @@ msgstr "Claves de despliegue accesibles de modo públco"
msgid "DeployKeys|Read access only"
msgstr "Acceso de sólo lectura"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "Claves de despliegue activas (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
msgstr ""
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr "Copiar token de despliegue"
@@ -16084,7 +16281,7 @@ msgstr "Ãmbitos"
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr "Nombre de usuario"
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "Cancelado"
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr "Falló"
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr "Último despliegue"
@@ -16290,12 +16508,15 @@ msgstr "Omitido"
msgid "Deployment|Success"
msgstr "Éxito"
-msgid "Deployment|This deployment was created using the API"
-msgstr "Este despliegue se creó utilizando el API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr "Repositorios de diseño"
-
-msgid "Design repository"
-msgstr "Repositorio de diseño"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} de %{designs_count}"
@@ -17565,9 +17780,6 @@ msgstr "Correo enviado"
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr "Actualizaciones por correo electrónico (opcional)"
-
msgid "Email:"
msgstr "Correo electrónico:"
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "Correos electrónicos"
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr "Habilitar el encabezado y pie de página en los correos electrónicos"
-msgid "Enable in-product marketing emails"
-msgstr "Habilitar correos electrónicos de marketing en el producto"
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr "Habilitar o deshabilitar la comprobación de la versión y el servicio Ping."
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Trabajo"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr "Obtenga más información sobre cómo detener los entornos"
@@ -18198,6 +18413,12 @@ msgstr "¿Desea restaurar el entorno %{name}?"
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr "Próximos"
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr "Expandir"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Expandir todo"
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr "Filtrar por usuario"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr "Filtrar resultados..."
msgid "Filter users"
msgstr "Filtrar usuarios"
-msgid "Filter..."
-msgstr "Filtrar..."
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr "Obtenga una revisión de instancia gratuita"
msgid "Get a support subscription"
msgstr "Obtenga una suscripción de soporte"
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Empezar"
@@ -21440,6 +21649,9 @@ msgstr "Sin verificar"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Actualizando su configuración de Pages..."
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr "Servidores de Gitaly"
-msgid "Gitaly relative path:"
-msgstr "Ruta relativa de Gitaly:"
-
-msgid "Gitaly storage name:"
-msgstr "Nombre de almacenamiento de Gitaly:"
-
msgid "Gitaly timeouts"
msgstr "Tiempos de espera de Gitaly"
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr "Acceso concedido %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr "La tarea épica indicada ya está relacionada con esta tarea épica."
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr " %{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21672,7 +21890,7 @@ msgid "GlobalSearch|Labels"
msgstr ""
msgid "GlobalSearch|Language"
-msgstr ""
+msgstr "Lenguaje"
msgid "GlobalSearch|Merge requests I've created"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr "Buscar en GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr "Avatar del grupo"
msgid "Group by"
msgstr "Agrupar por"
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "Descripción del grupo (opcional)"
@@ -22181,9 +22408,6 @@ msgstr "Nombre del grupo (su organización)"
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr "Resumen del contenido del grupo"
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,8 +22972,8 @@ msgstr "Esta característica requiere localStorage en su navegador web"
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "Un grupo es una colección de varios proyectos."
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
msgid "GroupsEmptyState|Create new project"
msgstr "GroupsEmptyState|Crear nuevo proyecto"
@@ -22760,8 +22984,8 @@ msgstr "GroupsEmptyState|Crear nuevo subgrupo"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Al organizar sus proyectos como un grupo, estos funcionan de la misma forma que una carpeta."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
msgid "GroupsEmptyState|No archived projects."
msgstr ""
@@ -22778,9 +23002,6 @@ msgstr "No hay subgrupos ni proyectos."
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "Puede administrar los permisos y el acceso de cada miembro del grupo a cada proyecto del grupo."
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23200,6 +23421,9 @@ msgid "Help translate GitLab into your language"
msgstr ""
msgid "Help translate to your language"
+msgstr "Ayuda a traducir a tu idioma"
+
+msgid "Helpful"
msgstr ""
msgid "Helps prevent bots from brute-force attacks."
@@ -23465,9 +23689,6 @@ msgstr "Quiero almacenar mi código"
msgid "I want to use GitLab CI with my existing repository"
msgstr "Quiero utilizar GitLab CI con mi repositorio de código existente"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "Me gustaría recibir actualizaciones sobre GitLab por correo electrónico"
-
msgid "I'm signing up for GitLab because:"
msgstr "Me registro en GitLab porque:"
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "INFO: Su clave SSH ha caducado. Por favor, genere una nueva clave."
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr "Verifique su identidad"
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "¿Sus ejecutores están preparados?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "Conviértase en un héroe de DevOps"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr "Refuerce su seguridad"
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "Cree un proyecto en GitLab en 5 minutos"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "¡Cree su primer proyecto!"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr "¿Tiene un compañero que sería perfecto para esta tarea?"
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr "Amplíe su viaje de DevOps con una prueba gratuita de GitLab"
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "Explore GitLab CI/CD"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "Explore las opciones"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "Siga nuestros pasos"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "Prueba gratuita de 30 días"
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr "Obtenga nuestras guías de importación"
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr "Comience hoy"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr "Conceptos básicos de Git"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "InProductMarketing|Danos un minuto..."
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr "InProductMarketing|Cómo construir y probar más rápido"
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr "InProductMarketing|Si no desea seguir recibiendo correos electrónicos de marketing directamente desde GitLab, %{marketing_preference_link}."
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "InProductMarketing|Invite a sus compañeros a unirse en menos de un minuto"
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "InProductMarketing|Invite a sus colegas hoy"
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "InProductMarketing|Invite a su equipo en menos de 60 segundos"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "InProductMarketing|Invite a su equipo ahora"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr "InProductMarketing|Invite a su equipo hoy mismo a crear mejor código y mejores procesos juntos"
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr "InProductMarketing|Está todo en las estadísticas"
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr "No es necesaria una tarjeta de crédito."
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr "InProductMarketing|Nuestra herramienta reúne todas las cosas"
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr "InProductMarketing|Desarrollo rápido, simplificado"
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr "InProductMarketing|Seguridad integrada en su ciclo de vida de desarrollo"
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr "InProductMarketing|Ponga un ejecutor con escalado automático en GitLab"
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "InProductMarketing|Comience una prueba de GitLab Ultimate hoy en menos de un minuto, sin necesidad de tarjeta de crédito."
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr "InProductMarketing|Comenzar una prueba autogestionada"
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "InProductMarketing|Comience una prueba gratuita de GitLab Ultimate: sin necesidad de una tarjeta de crédito"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "InProductMarketing|Iniciar una prueba"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "InProductMarketing|Comenzar por %{performance_link}"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "InProductMarketing|¡Comience su prueba ahora!"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr "InProductMarketing|Pruébalo"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "InProductMarketing|Pruébelo usted mismo"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr "Trabajar en GitLab = más eficiente"
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr "Sus equipos pueden ser más eficientes"
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "guía completa"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "Conectar un repositorio externo"
-
-msgid "InProductMarketing|create a project"
-msgstr "Crear un proyecto"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "Desde Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "Ir a about.gitlab.com"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "Qué fácil es empezar"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "Guía de inicio rápido"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "Replicación del repositorio"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "Configurar un repositorio"
-
-msgid "InProductMarketing|test and deploy"
-msgstr "probar y desplegar"
-
-msgid "InProductMarketing|testing browser performance"
-msgstr "probar el rendimiento del navegador"
-
msgid "InProductMarketing|unsubscribe"
msgstr "cancelar suscripción"
-msgid "InProductMarketing|update your preferences"
-msgstr "actualizar sus preferencias"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr "utilizando una plantilla CI/CD"
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr "En línea"
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr "Introducir las claves del host manualmente"
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "Patrón de intervalo"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr "Código de dos factores no válido."
-msgid "Invalid yaml"
-msgstr "Yaml no válido"
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr "Cerrada"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Cerrada (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr "duplicada"
@@ -26127,29 +26004,49 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr "Incidencias, merge requests, pushes y comentarios."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "Una vez haya comenzado a crear incidencias, podremos iniciar el seguimiento y mostrar distintas métricas para sus proyectos"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Promedio mensual:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "Últimos 12 meses"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Lo sentimos, su filtro no ha producido ningún resultado."
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "No hay incidencias para los proyectos contenidos en su grupo"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "Para ampliar su búsqueda, cambie o elimine los filtros en la barra de filtros que se muestra en la parte superior"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr "Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr "Texto en cursiva"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr "Iteración"
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr "Unirse a un proyecto"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr "Se unió el %{time_ago}"
-
msgid "Joined %{user_created_time}"
msgstr "Se unió el %{user_created_time}"
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr "Último Pipeline"
-
msgid "Last Seen"
msgstr "Visto por última vez"
@@ -27541,6 +27444,9 @@ msgstr "Ha hecho push a"
msgid "LastPushEvent|at"
msgstr "en"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "Últimos cambios"
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr "Bloquear membresías a la sincronización LDAP"
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr "Bloqueo no encontrado"
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr "URL de Mattermost:"
msgid "Mattermost notifications"
msgstr "Notificaciones de Mattermost"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr "MattermostService|Añadir a Mattermost"
@@ -28671,6 +28589,9 @@ msgstr "Escriba la palabra que mejor describa a su equipo."
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr "URL de la petición"
@@ -28683,6 +28604,9 @@ msgstr "Icono de respuesta"
msgid "MattermostService|Response username"
msgstr "Nombre de usuario de respuesta"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr "Sugerencias:"
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr "Mensaje del merge commit"
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr "Métricas e informes"
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr "Crear métrica"
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr "Nueva respuesta para la incidencia #%{issue_iid}:"
msgid "New runners registration token has been generated!"
msgstr "¡Se ha generado el token de registro para los nuevos ejecutores!"
-msgid "New schedule"
-msgstr "Nueva programación"
-
msgid "New snippet"
msgstr "Nuevo fragmento de código"
@@ -31254,6 +31292,9 @@ msgstr "Sin iteración"
msgid "No label"
msgstr "Sin etiqueta"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "No hay etiquetas con ese nombre o descripción"
@@ -31278,6 +31319,12 @@ msgstr "No se han encontrado resultados"
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr "No se han encontrado miembros"
@@ -31296,12 +31343,15 @@ msgstr "Sin hito"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
+msgstr ""
+
msgid "No other labels with such name or description"
msgstr "No hay otras etiquetas con ese nombre o descripción"
-msgid "No panels matching properties %{opts}"
-msgstr "No hay paneles que coincidan con las propiedades %{opts}"
-
msgid "No parent group"
msgstr "Ningún grupo padre"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "No hay programaciones"
-
msgid "No service accounts"
msgstr "Sin cuentas de servicio"
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr "Opciones"
msgid "Ordered list"
msgstr "Lista ordenada"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "Organización"
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr "Miembro huérfano"
@@ -33538,6 +33627,9 @@ msgstr "Páginas"
msgid "Pages Domain"
msgstr "Dominio de Pages"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr "Primero"
@@ -33685,7 +33777,10 @@ msgstr "Ruta"
msgid "Path:"
msgstr "Ruta:"
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "Activado"
-
msgid "PipelineSchedules|Active"
msgstr "Activos"
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Variables"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr "Creado"
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr "Disparador"
-
msgid "Pipeline|Variables"
msgstr "Variables"
@@ -35353,9 +35439,6 @@ msgstr "Ancho de diseño"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr "Acción primaria"
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr "Editar perfil"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr "El orden del proyecto no se guardará ya que el almacenamiento local no está disponible."
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr "Ruta del proyecto"
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr "Público"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr "Aprobación del propietario del código"
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protect an environment"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} podrá modificarse por los desarrolladores. ¿Estás seguro de que desea continuar?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr "Seleccionar grupos"
-msgid "ProtectedEnvironment|Select users"
-msgstr "Seleccionar usuarios"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr "Público"
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr "Recibir notificaciones acerca de su propia actividad"
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr "Reciente"
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr "Eliminar prioridad"
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr "Eliminar el tiempo gastado"
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr "Eliminar el tiempo estimado"
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Denunciado %{timeAgo} por %{reportedBy}"
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr "Reportado por %{reporter}"
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "Seleccionar"
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr "Guardar nota interna"
msgid "Save password"
msgstr "Guardar la contraseña"
-msgid "Save pipeline schedule"
-msgstr "Guardar programación del pipeline"
-
msgid "Saving"
msgstr "Guardando"
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr "Buscar un entorno específico"
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,15 +41734,12 @@ msgstr "Buscar hitos"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
-msgstr "Buscar o filtrar resultados..."
-
msgid "Search or filter results…"
msgstr "Buscar o filtrar resultados…"
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr ""
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr "Tablero de seguridad"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr "Forzar la seguridad para este proyecto. %{linkStart}Más información%{linkEnd}"
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr "Se ha producido un error al cargar los agentes del clúster."
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr "Comentario editado en '%{vulnerabilityName}'"
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr "vulnerabilidades de desarrollo"
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "Descartar vulnerabilidad"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "Descartada '%{vulnerabilityName}'"
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr "Enviar notificación por correo electrónico"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr "Service Desk"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr "ID de sesión"
msgid "Session duration (minutes)"
msgstr "Duración de la sesión (minutos)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "Establece %{epic_ref} como la tarea épica principal."
@@ -43549,6 +43779,9 @@ msgstr "Establecer el tiempo estimado a %{time_estimate}."
msgid "Set to 0 for no size limit."
msgstr "Establézcalo a 0 para deshabilitar la limitación de tamaño."
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr "Tu estado se restablece en %{date}."
msgid "Sets %{epic_ref} as parent epic."
msgstr "Establecer %{epic_ref} cómo tarea épica principal."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Alguien, esperemos que usted, ha solicitado restablecer la contraseña de su cuenta de GitLab en %{link_to_gitlab}."
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr "Se ha producido un error al recuperar los cambios de descripción. Por f
msgid "Something went wrong while fetching details"
msgstr "Se ha producido un error al obtener los detalles"
-msgid "Something went wrong while fetching latest comments."
-msgstr "Se ha producido un error al obtener los últimos comentarios."
-
msgid "Something went wrong while fetching projects"
msgstr "Se ha producido un error al obtener los proyectos"
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr "Cargar nueva licencia"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr "Desactivado correctamente"
msgid "Successfully deleted WebAuthn device."
msgstr "Se ha eliminado correctamente el dispositivo WebAuthn."
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "Correo electrónico eliminado con éxito."
@@ -45671,6 +45922,9 @@ msgstr "Desbloqueado con éxito"
msgid "Successfully unblocked"
msgstr "Desbloqueado con éxito"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr "Desbloqueado con éxito"
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr "Ruta de destino"
msgid "Target branch"
msgstr "Rama de destino"
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr "La contraseña para el servidor de Jenkins."
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr "No hay claves SSH con acceso a su cuenta."
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr "Se ha producido un error al recuperar las variables."
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr "Se ha producido un error con reCAPTCHA. Por favor, resuelva el reCAPTCHA
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Este merge request está bloqueado."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,11 +48505,11 @@ msgstr "Este pipeline utiliza una configuración de CI/CD predefinida habilitada
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
-msgstr "Este pipeline se ejecutó mediante una programación."
+msgid "This pipeline was created by a schedule."
+msgstr ""
msgid "This process deletes the project repository and all related resources."
msgstr ""
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr "Est"
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "Mañana"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr "Total"
msgid "Total Score"
msgstr "Puntuación total"
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr "Núcleos totales (CPUs)"
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr "Seguimiento"
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr "URL o ID de solicitud"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "¡EL USUARIO %{user} SERà ELIMINADO! ¿Está seguro?"
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "¡EL USUARIO SERà BLOQUEADO! ¿Está usted seguro?"
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr "No se puede analizar JSON"
@@ -49911,9 +50207,6 @@ msgstr "No se puede actualizar la tarea epíca en este momento."
msgid "Unable to update this issue at this time."
msgstr "No se puede actualizar esta incidencia en este momento."
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr "Desafortunadamente, su mensaje de correo electrónico a GitLab no pudo s
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr "El nombre de usuario está disponible."
msgid "Username or email"
msgstr "Nombre de usuario o email"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Nombre de usuario:"
@@ -51489,7 +51794,7 @@ msgid "Variable"
msgstr "Variable"
msgid "Variable (default)"
-msgstr ""
+msgstr "Variable (por defecto)"
msgid "Variable name '%{variable}' must not start with '%{prefix}'"
msgstr ""
@@ -51736,7 +52041,7 @@ msgid "View summary notes"
msgstr ""
msgid "View supported languages and frameworks"
-msgstr "Ver idiomas y marcos soportados"
+msgstr "Ver los lenguajes y marcos de trabajo con soporte"
msgid "View the %{code_open}last_activity_at%{code_close} attribute for %{project_link} using the %{projects_api_link}."
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr "Verificación SSL"
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr "¿Qué son los eventos de auditoría de los grupos?"
-
-msgid "What are instance audit events?"
-msgstr "¿Qué son los eventos de auditoría de las instancias?"
-
-msgid "What are project audit events?"
-msgstr "¿Qué son los eventos de auditoría de los proyectos?"
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr "Puede crear un nuevo token de acceso personal visitando %{link}"
msgid "You can create a new SSH key by visiting %{link}"
msgstr "Puede crear una nueva clave SSH visitando %{link}"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr "Puedes crear uno nuevo o comprobarlo en la configuración de sus %{ssh_k
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr "No tienes ningún despliegue en este momento."
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "Sus aplicaciones autorizadas"
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr "Sus tokens de acceso personal caducarán en %{days_to_expire} días o me
msgid "Your profile"
msgstr "Su perfil"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "¡Su límite de proyecto es %{limit} proyectos! Por favor, contacte con su administrador para aumentarlo"
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr "Su búsqueda no coincide con ningún commit."
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr "permitido fallar"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr "ya está baneado de este espacio de nombres"
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr "por ejemplo %{token}"
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr "el elemento no es una jerarquía"
@@ -55595,9 +55918,6 @@ msgstr[1] "archivos"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr "es demasiado grande"
msgid "jigsaw is not defined"
msgstr "jigsaw no está definido"
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr "mi-asombroso-grupo"
@@ -56429,6 +56761,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, y %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "inició una discusión en %{design_link}"
@@ -56772,6 +57110,9 @@ msgstr "nombre de la etiqueta"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr "disparado"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr "configuración de la autenticación de doble factor"
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "versión %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "vía %{closed_via}"
diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po
index 59cd38d7e91..e8913f83e3c 100644
--- a/locale/et_EE/gitlab.po
+++ b/locale/et_EE/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: et\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/fa_IR/gitlab.po b/locale/fa_IR/gitlab.po
index e66467cad9d..8f43bdd1c67 100644
--- a/locale/fa_IR/gitlab.po
+++ b/locale/fa_IR/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: fa\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/fi_FI/gitlab.po b/locale/fi_FI/gitlab.po
index 0a892419841..44981a5705a 100644
--- a/locale/fi_FI/gitlab.po
+++ b/locale/fi_FI/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: fi\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po
index f83f57640ba..0eeb91367b6 100644
--- a/locale/fil_PH/gitlab.po
+++ b/locale/fil_PH/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: fil\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index 9644dac5c6b..1e7aba65797 100644
--- a/locale/fr/gitlab.po
+++ b/locale/fr/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: fr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr " %{start} à %{end}"
@@ -45,6 +45,11 @@ msgstr " et "
msgid " and %{sliced}"
msgstr " et %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] " à l'exception de la branche suivante :"
+msgstr[1] " à l'exception des branches suivantes :"
+
msgid " or "
msgstr " ou "
@@ -670,9 +675,6 @@ msgstr "%{count} étiquettes"
msgid "%{count} total weight"
msgstr "%{count} poids total"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} est introuvable."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} jours avant la suppression automatique des étiquettes"
@@ -718,8 +720,8 @@ msgstr "%{edit_in_new_fork_notice} Réessayez de téléverser un fichier."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@societe.fr"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr "%{enable_service_ping_link_start}Activez%{link_end} ou %{generate_manually_link_start}générez%{link_end} le Ping de Service pour prévisualiser et télécharger la charge utile des données d'utilisation du service."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr "%{enable_service_ping_link_start}Activez%{enable_service_ping_link_end} ou %{generate_manually_link_start}générez%{generate_manually_link_end} le ping de service pour prévisualiser et télécharger la charge utile des données d'utilisation du service."
msgid "%{extra} more downstream pipelines"
msgstr "%{extra} pipelines de plus en aval"
@@ -796,6 +798,12 @@ msgstr "%{issuesSize} avec une limite de %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "Les %{italic_start}Nouveautés%{italic_end} ne sont pas actives et ne peuvent pas être affichées."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr "Impossible de supprimer %{item_ids} en raison d'autorisations insuffisantes"
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr "Impossible de supprimer %{item_ids} en raison de l'absence de liaison"
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} tickets avec une limite de %{maxIssueCount}"
@@ -871,6 +879,9 @@ msgstr "%{labelStart}Réponse non modifiée°:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} indisponible"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr "%{label_name} a été supprimé"
@@ -1319,11 +1330,11 @@ msgstr "%{verb} un temps passé de %{time_spent_value}."
msgid "%{verb} this %{noun} as a draft."
msgstr "%{verb} cette %{noun} comme brouillon."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "Les %{webhooks_link_start}%{webhook_type}%{link_end} vous permettent d'envoyer des notifications aux applications Web en réponse aux événements d'un groupe ou d'un projet."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr "Les %{webhooks_link_start}%{webhook_type}%{webhooks_link_end} vous permettent d'envoyer des notifications aux applications Web suite à des événements qui se produisent dans un groupe ou un projet."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "Les %{webhooks_link_start}%{webhook_type}%{link_end} vous permettent d'envoyer des notifications aux applications Web en réponse aux événements d'un groupe ou d'un projet. Nous recommandons d'utiliser une %{integrations_link_start}intégration%{link_end} plutôt qu'un crochet Web."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr "Les %{webhooks_link_start}%{webhook_type}%{webhooks_link_end} vous permettent d'envoyer des notifications aux applications Web suite à des événements qui se produisent dans un groupe ou un projet. Nous recommandons d'utiliser une %{integrations_link_start}intégration%{integrations_link_end} plutôt qu'un crochet Web."
msgid "%{widget} options"
msgstr "Options du %{widget}"
@@ -1429,6 +1440,9 @@ msgstr "+ %{amount} de plus"
msgid "+ %{count} more"
msgstr "+ %{count} de plus"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr "+ %{hiddenBranchesLength} de plus"
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} de plus"
@@ -1752,7 +1766,7 @@ msgid "A complete DevOps platform"
msgstr "Une plateforme DevOps complète"
msgid "A confidential issue must have only confidential children. Make any child items confidential and try again."
-msgstr ""
+msgstr "Un ticket confidentiel ne doit avoir que des enfants confidentiels. Rendez tous les éléments enfants confidentiels et réessayez."
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr "Un élément de travail confidentiel ne peut pas avoir un parent qui a déjà un enfant non confidentiel."
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr "Les explications générées par l'IA apparaîtront ici."
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr "Une %{linkStart}version expérimentale%{linkEnd} est une fonctionnalité en cours de développement. Celle-ci n'est pas prête pour la phase de production. Nous encourageons les utilisateurs à essayer les fonctionnalités expérimentales et à donner leur avis. Une version expérimentale : %{bullets}"
+
msgid "AI|Apply AI-generated description"
msgstr "Appliquer la description générée par l'IA"
+msgid "AI|Ask GitLab Duo"
+msgstr "Poser une question à GitLab Duo"
+
msgid "AI|Ask a question"
msgstr "Poser une question"
msgid "AI|Autocomplete"
msgstr "Saisie automatique"
+msgid "AI|Can be removed at any time"
+msgstr "Peut être supprimée à tout moment"
+
msgid "AI|Close the Code Explanation"
msgstr "Fermer l'explication du code"
@@ -1946,12 +1969,30 @@ msgstr "Générer une description du ticket"
msgid "AI|GitLab Duo"
msgstr "GitLab Duo"
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr "Ne bénéficie d'aucune assistance et parfois même d'aucune documentation"
+
msgid "AI|Helpful"
msgstr "Utile"
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr "Je ne vois pas comment je peux aider. Veuillez fournir de meilleures instructions !"
+msgid "AI|May be unstable"
+msgstr "Peut être instable"
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr "Peut fournir des réponses inappropriées ne représentant pas les opinions de GitLab. Ne saisissez pas de données personnelles."
@@ -1973,6 +2014,9 @@ msgstr "Envoyer un message de chat."
msgid "AI|Something went wrong. Please try again later"
msgstr "Une erreur s'est produite. Veuillez réessayer plus tard"
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr "L'élément du conteneur n'a pas été trouvé, ce qui a interrompu AI Genie."
@@ -1988,6 +2032,9 @@ msgstr "Ces fonctionnalités peuvent provoquer des problèmes de performance et
msgid "AI|Third-party AI services"
msgstr "Services d'IA tiers"
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr "Inutile"
@@ -2000,6 +2047,9 @@ msgstr "Utilisez des services d'IA tiers"
msgid "AI|What does the selected code mean?"
msgstr "Que signifie le code sélectionné ?"
+msgid "AI|What's an Experiment?"
+msgstr "Qu'est-ce qu'une version expérimentale ?"
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr "Rédigez une brève description et l'IA complètera les détails."
@@ -2012,9 +2062,6 @@ msgstr "Incorrect"
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr "Vous n'avez pas la permission de copier ce texte, en intégralité ou une partie, dans des tickets, des commentaires, du code source de GitLab, des messages de validation, des requêtes de fusion ou toute autre interface utilisateur dans les groupes %{gitlabOrg} ou %{gitlabCom}."
-msgid "AI|You can ask AI for more information."
-msgstr "Vous pouvez demander plus d'informations à l'IA."
-
msgid "AI|finding"
msgstr "en train de rechercher"
@@ -2219,9 +2266,6 @@ msgstr "Aucun rapport trouvé"
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr "%{reportLinkStart}Rapporté%{reportLinkEnd} pour %{category} %{timeAgo}."
-msgid "AbuseReport|Abuse reports"
-msgstr "Signalements d'abus"
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr "Abus non confirmé"
@@ -2336,6 +2380,9 @@ msgstr "Offensant ou abusif"
msgid "AbuseReport|Other"
msgstr "Autre"
+msgid "AbuseReport|Past abuse reports"
+msgstr "Rapports d'abus précédents"
+
msgid "AbuseReport|Personal information or credentials"
msgstr "Informations personnelles ou identifiants"
@@ -2393,6 +2440,9 @@ msgstr "Vérification"
msgid "AbuseReport|View screenshot"
msgstr "Voir la capture d'écran"
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Accepter l'invitation"
@@ -2444,6 +2494,9 @@ msgstr "Groupes"
msgid "AccessDropdown|Roles"
msgstr "Rôles"
+msgid "AccessDropdown|Select"
+msgstr "Sélectionner"
+
msgid "AccessDropdown|Users"
msgstr "Utilisateurs"
@@ -2624,6 +2677,9 @@ msgstr "Acquitter"
msgid "Action"
msgstr "Action"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr "L'action « %{action} » dans l'entrée de registre %{registry_id} n'est pas prise en charge."
@@ -2658,7 +2714,7 @@ msgid "Active personal access tokens"
msgstr "Jetons d'accès personnels actifs"
msgid "Active pipeline trigger tokens"
-msgstr ""
+msgstr "Jetons de déclenchement de pipeline actifs"
msgid "Active project access tokens"
msgstr "Jetons d'accès au projet actifs"
@@ -2889,7 +2945,7 @@ msgid "Add new pipeline subscription"
msgstr ""
msgid "Add new pipeline trigger token"
-msgstr ""
+msgstr "Ajouter un nouveau jeton de déclenchement de pipeline"
msgid "Add new token"
msgstr "Ajouter un nouveau jeton"
@@ -2936,6 +2992,9 @@ msgstr "Ajouter une suggestion au lot"
msgid "Add tag"
msgstr "Ajouter une étiquette"
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "Ajouter du texte à la page de connexion. Markdown activé."
@@ -2960,6 +3019,9 @@ msgstr "Ajouter à la revue de code"
msgid "Add to tree"
msgstr "Ajouter à l'arborescence"
+msgid "Add token"
+msgstr "Ajouter un jeton"
+
msgid "Add topics to projects to help users find them."
msgstr "Ajouter des sujets aux projets pour aider les utilisateurs à les trouver."
@@ -2987,8 +3049,8 @@ msgstr "Ajouter/supprimer"
msgid "AddMember|Invite email is invalid"
msgstr "L'adresse de courriel d'invitation n'est pas valide"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "Limite de %{daily_invites} invitation(s) par jour dépassée"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "Les invitations ne peuvent pas être vides"
@@ -3827,8 +3889,8 @@ msgstr "Bloquer un utilisateur aura les conséquences suivantes :"
msgid "AdminUsers|Bot"
msgstr "Bot"
-msgid "AdminUsers|Can create group"
-msgstr "Peuvent créer des groupes"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "Impossible de se connecter ou d'accéder aux informations de l'instance"
@@ -4451,6 +4513,9 @@ msgstr "Le titre est un champ requis pour les alertes de GitLab. Dans l'hypothè
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr "Une URL de crochet Web et une clé d'autorisation sont générées pour l'intégration. Après avoir enregistré cette dernière, les deux sont visibles dans l'onglet « Afficher les identifiants°»."
+msgid "AlertSettings|Active alerts"
+msgstr "Alertes actives"
+
msgid "AlertSettings|Add new integration"
msgstr "Ajouter une nouvelle intégration"
@@ -4889,9 +4954,6 @@ msgstr "Une erreur s'est produite lors de la récupération des clés de déploi
msgid "An error occurred previewing the blob"
msgstr "Une erreur s'est produite lors de la prévisualisation du blob"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr "Une erreur s'est produite lors du chargement du défi de vérification de l'utilisateur. Actualisez pour réessayer."
-
msgid "An error occurred when updating the title"
msgstr "Une erreur s'est produite lors de la mise à jour du titre"
@@ -4982,6 +5044,9 @@ msgstr "Une erreur s'est produite lors de la récupération des tickets."
msgid "An error occurred while fetching label colors."
msgstr "Une erreur s'est produite lors de la récupération des couleurs de label."
+msgid "An error occurred while fetching labels, please try again."
+msgstr "Une erreur s'est produite lors de la récupération des labels, veuillez réessayer."
+
msgid "An error occurred while fetching participants"
msgstr "Une erreur s'est produite lors de la récupération des participants"
@@ -5167,6 +5232,9 @@ msgstr[1] "Une erreur s'est produite lors de la sauvegarde des paramètres"
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "Une erreur s'est produite lors de la sauvegarde de vos paramètres. Essayez de les sauvegarder de nouveau."
+msgid "An error occurred while searching for labels, please try again."
+msgstr "Une erreur s'est produite lors de la recherche des labels, veuillez réessayer."
+
msgid "An error occurred while triggering the job."
msgstr "Une erreur s'est produite lors du déclenchement du job."
@@ -5182,6 +5250,12 @@ msgstr "Une erreur s'est produite lors de la tentative d'exécution d'un nouveau
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr "Une erreur s'est produite lors de la tentative pour ne plus suivre cet utilisateur. Veuillez réessayer."
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr "Une erreur s'est produite lors de la tentative de mise à jour des registres : « %{error_message} »."
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr "Une erreur s'est produite lors de la tentative de mise à jour du registre : « %{error_message} »."
+
msgid "An error occurred while updating approvers"
msgstr "Une erreur s'est produite lors de la mise à jour des approbateurs"
@@ -5292,6 +5366,9 @@ msgstr "Paramètres d'analyse"
msgid "Analytics|A visualization with that name already exists."
msgstr "Une visualisation portant ce nom existe déjà."
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr "Ajouter des visualisations"
@@ -5337,15 +5414,18 @@ msgstr "Configurer le tableau de bord du projet"
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr "Créer le tableau de bord %{dashboardSlug}"
+msgid "Analytics|Create your dashboard"
+msgstr "Créer votre tableau de bord"
+
msgid "Analytics|Custom dashboards"
msgstr "Tableaux de bord personnalisés"
-msgid "Analytics|Dashboard Title"
-msgstr "Titre du tableau de bord"
-
msgid "Analytics|Dashboard not found"
msgstr "Tableau de bord introuvable"
+msgid "Analytics|Dashboard title"
+msgstr "Titre du tableau de bord"
+
msgid "Analytics|Dashboard was saved successfully"
msgstr "Le tableau de bord a été enregistré avec succès"
@@ -5367,6 +5447,12 @@ msgstr "Les dates et heures sont affichées dans le fuseau horaire UTC"
msgid "Analytics|Edit"
msgstr "Modifier"
+msgid "Analytics|Edit your dashboard"
+msgstr "Modifier votre tableau de bord"
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr "Entrer un nom de visualisation"
@@ -5382,6 +5468,9 @@ msgstr "Échec de la récupération des données"
msgid "Analytics|Host"
msgstr "Hôte"
+msgid "Analytics|Invalid visualization configuration"
+msgstr "Configuration de visualisation non valide"
+
msgid "Analytics|Language"
msgstr "Langue"
@@ -5424,24 +5513,30 @@ msgstr "Référent"
msgid "Analytics|Resulting Data"
msgstr "Données de résultats"
-msgid "Analytics|Save"
-msgstr "Enregistrer"
-
msgid "Analytics|Save and add to Dashboard"
msgstr "Enregistrer et ajouter au tableau de bord"
msgid "Analytics|Save new visualization"
msgstr "Enregistrer une nouvelle visualisation"
+msgid "Analytics|Save your dashboard"
+msgstr "Enregistrer votre tableau de bord"
+
msgid "Analytics|Select a measurement"
msgstr "Sélectionner une mesure"
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr "Sélectionner un type de visualisation"
msgid "Analytics|Single Statistic"
msgstr "Statistique unique"
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr "Une erreur s'est produite dans la configuration de visualisation de votre panneau. Référez-vous à la %{linkStart}documentation de dépannage%{linkEnd}."
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr "Une erreur s'est produite lors de la connexion à votre source de données. Consultez la %{linkStart}documentation à propos du dépannage%{linkEnd}."
@@ -5515,7 +5610,7 @@ msgid "Another issue tracker is already in use. Only one issue tracker service c
msgstr "Un autre gestionnaire de tickets de suivi est déjà en cours d'utilisation. Un seul peut être actif à la fois"
msgid "Another open merge request already exists for this source branch: %{conflicting_mr_reference}"
-msgstr ""
+msgstr "Une autre demande de fusion ouverte existe déjà pour cette branche source : %{conflicting_mr_reference}"
msgid "Another third-party wiki is already in use. Only one third-party wiki integration can be active at a time"
msgstr "Un autre wiki tiers est déjà utilisé. Une seule intégration de wiki tiers peut être active à la fois"
@@ -6200,9 +6295,6 @@ msgstr "Voulez-vous vraiment supprimer cet appareil ? Cette action ne peut pas
msgid "Are you sure you want to delete this label?"
msgstr "Voulez-vous vraiment supprimer ce label ?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Voulez-vous vraiment supprimer cette planification de pipeline ?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "Voulez-vous vraiment supprimer ce pipeline ? Cette action provoquera l'expiration de tous les caches du pipeline et supprimera tous les objets associés, tels que les compilations, les journaux, les artefacts et les déclencheurs. Cette action ne peut pas être annulée."
@@ -6283,8 +6375,8 @@ msgstr "Voulez-vous vraiment réinitialiser le jeton d'inscription ?"
msgid "Are you sure you want to retry this migration?"
msgstr "Voulez-vous vraiment retenter cette migration°?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "Voulez-vous vraiment révoquer ce %{accessTokenType} ? Cette action ne peut pas être annulée."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
msgstr "Voulez-vous vraiment révoquer cette clé SSH ?"
@@ -6428,6 +6520,9 @@ msgstr "Liste des branches à inspecter automatiquement, séparées par des virg
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr "Jeton d'accès personnel de l'utilisateur. L'utilisateur doit avoir accès à la tâche. Toutes les validations lui seront attribuées."
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "Redemander plus tard"
@@ -6638,6 +6733,9 @@ msgstr "Un en-tête portant ce nom existe déjà."
msgid "AuditStreams|Active"
msgstr "Actif"
+msgid "AuditStreams|Add a new private key"
+msgstr "Ajouter une nouvelle clé privée"
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr "Ajoutez un point de terminaison HTTP pour gérer les journaux d'audit dans des systèmes tiers."
@@ -6755,6 +6853,9 @@ msgstr "Cela peut inclure des données sensibles. Assurez-vous de pouvoir faire
msgid "AuditStreams|This is great for keeping everything one place."
msgstr "C'est l'idéal pour garder tout à un seul endroit."
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr "Utilisez la console Google Cloud pour afficher la clé privée. Pour la modifier, remplacez-la par une nouvelle."
+
msgid "AuditStreams|Value"
msgstr "Valeur"
@@ -7682,8 +7783,8 @@ msgstr "Une erreur s'est produite lors du chargement des détails de l'abonnemen
msgid "Billing|An error occurred while loading billable members list."
msgstr "Une erreur s'est produite lors du chargement de la liste des membres facturables."
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
-msgstr "Une erreur s'est produite lors du chargement des détails du module complémentaire Suggestions de code."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "Une erreur s'est produite lors du chargement des détails du module Suggestions de code. Si le problème persiste, veuillez %{supportLinkStart}contacter le support%{supportLinkEnd}."
msgid "Billing|An error occurred while loading pending members list"
msgstr "Une erreur s'est produite lors du chargement de la liste des membres en attente"
@@ -7697,15 +7798,18 @@ msgstr "En attente de l'inscription du membre"
msgid "Billing|Cannot remove user"
msgstr "Impossible de supprimer l'utilisateur"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr "Module complémentaire Suggestions de code attribué"
-
msgid "Billing|Direct memberships"
msgstr "Adhésions directes"
msgid "Billing|Enter at least three characters to search."
msgstr "Entrez au moins trois caractères pour effectuer une recherche."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr "Erreur lors de l'assignation du module complémentaire Suggestions de code"
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr "Erreur lors de l'annulation de l'assignation du module complémentaire Suggestions de code"
+
msgid "Billing|Explore paid plans"
msgstr "Découvrir les forfaits payants"
@@ -7723,6 +7827,9 @@ msgstr[1] "Les groupes utilisant le forfait Gratuit sont limités à %d sièges
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "Les membres qui ont été invités via une invitation de groupe ne peuvent pas être supprimés. Vous pouvez soit supprimer l'ensemble du groupe, soit demander à un Propriétaire du groupe invité d'en supprimer le membre."
+msgid "Billing|No seats available"
+msgstr "Aucun siège disponible"
+
msgid "Billing|No users to display."
msgstr "Aucun utilisateur à afficher."
@@ -7735,6 +7842,12 @@ msgstr "Invitation au projet"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "Supprimer l'utilisateur %{username} de votre abonnement"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "Une erreur s'est produite lors de l'assignation du module à ce membre. Si le problème persiste, veuillez %{supportLinkStart}contacter le support%{supportLinkEnd}."
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "Une erreur s'est produite lors de l'annulation de l'assignation du module complémentaire à ce membre. Si le problème persiste, veuillez %{supportLinkStart}contacter l'équipe d'assistance%{supportLinkEnd}."
+
msgid "Billing|Subscription end"
msgstr "Fin de l'abonnement"
@@ -7762,6 +7875,9 @@ msgstr "Afficher les approbations en attente"
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "Vous êtes sur le point de supprimer l'utilisateur %{username} de votre abonnement. Si vous continuez, l'utilisateur sera supprimé du groupe %{namespace} ainsi que de tous ses sous-groupes et projets. Cette action ne pourra pas être annulée."
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr "Vous avez assigné tous les sièges disponibles pour le module complémentaire Suggestions de code. Veuillez %{salesLinkStart}contacter le service commercial%{salesLinkEnd} si vous souhaitez acheter plus de sièges."
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr "Votre groupe est récemment passé au forfait Gratuit. %{over_limit_message} Vous pouvez libérer de l'espace pour les nouveaux membres en supprimant ceux qui n'ont plus besoin d'accès ou en les basculant au-delà de la limite. Pour que le nombre de membres ne soit plus limité, vous pouvez %{link_start}mettre à niveau%{link_end} vers une édition payante."
@@ -7806,6 +7922,9 @@ msgstr[1] "Bloqué par %d tickets"
msgid "Blocked issue"
msgstr "Ticket bloqué"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr "Les éléments de travail bloqués ne sont pas disponibles pour l'édition correspondant à votre abonnement actuel."
+
msgid "Blocking"
msgstr "Bloquant"
@@ -7839,9 +7958,6 @@ msgstr "Aucun résultat correspondant"
msgid "BoardNewEpic|Search groups"
msgstr "Rechercher des groupes"
-msgid "BoardNewEpic|Select a group"
-msgstr "Sélectionnez un groupe"
-
msgid "BoardNewIssue|No matching results"
msgstr "Aucun résultat correspondant"
@@ -7929,9 +8045,6 @@ msgstr "Sélectionner des labels"
msgid "BoardScope|Select milestone"
msgstr "Sélectionner un jalon"
-msgid "BoardScope|Select weight"
-msgstr "Sélectionnez le poids"
-
msgid "BoardScope|Started"
msgstr "Commencé"
@@ -8549,7 +8662,7 @@ msgid "BroadcastMessages|Indigo"
msgstr "Indigo"
msgid "BroadcastMessages|Leave blank to target all group and project pages."
-msgstr ""
+msgstr "Laissez vide pour cibler toutes les pages de groupe et de projet."
msgid "BroadcastMessages|Light"
msgstr "Clair"
@@ -8579,16 +8692,16 @@ msgid "BroadcastMessages|Notification"
msgstr "Notification"
msgid "BroadcastMessages|One or more roles is required."
-msgstr ""
+msgstr "Un ou plusieurs rôles sont requis."
msgid "BroadcastMessages|Paths can contain wildcards, like */welcome."
-msgstr ""
+msgstr "Les chemins d'accès peuvent contenir des jokers, comme */bienvenue."
msgid "BroadcastMessages|Red"
msgstr "Rouge"
msgid "BroadcastMessages|Select at least one role."
-msgstr ""
+msgstr "Sélectionnez au moins un rôle."
msgid "BroadcastMessages|Show only to users who have specific roles on groups/project pages"
msgstr "N'afficher que pour les utilisateurs qui ont des rôles spécifiques sur les pages de groupes/projets"
@@ -9006,8 +9119,8 @@ msgstr "CICD|Limiter l'accès %{italicStart}depuis%{italicEnd} ce projet (obsolÃ
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr "CICD|Limiter l'accès %{italicStart}à%{italicEnd} ce projet"
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
-msgstr "CICD|Empêchez l'utilisation des jetons de job CI/CD de ce projet pour accéder à d'autres projets à moins que l'autre projet ne soit ajouté à la liste d'autorisations. Désactiver cette fonctionnalité constitue un risque pour la sécurité, car des projets non autorisés peuvent tenter de récupérer un jeton actif et d'accéder à l'API. %{linkStart}En savoir plus.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
+msgstr "Empêchez l'utilisation des jetons de job CI/CD de ce projet pour accéder à d'autres projets à moins que l'autre projet ne soit ajouté à la liste d'autorisations. Désactiver cette fonctionnalité constitue un risque pour la sécurité, car des projets non autorisés peuvent tenter de récupérer un jeton actif et d'accéder à l'API. %{linkStart}En savoir plus%{linkEnd}."
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
msgstr "CICD|Empêchez l'accès à ce projet à partir d'autres jetons de job CI/CD du projet, à moins que l'autre projet ne soit ajouté à la liste d'autorisations. Désactiver cette fonctionnalité constitue un risque pour la sécurité, car des projets non autorisés peuvent tenter de récupérer un jeton actif et d'accéder à l'API. %{linkStart}En savoir plus.%{linkEnd}"
@@ -9102,8 +9215,8 @@ msgstr "Le sous-domaine %{code_open}.campfirenow.com%{code_close}."
msgid "Can be manually deployed to"
msgstr "Peut être déployé manuellement dans"
-msgid "Can create groups:"
-msgstr "Peut créer des groupes°:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr "Impossible de supprimer la formation prioritaire"
@@ -9361,7 +9474,7 @@ msgid "Change branches"
msgstr "Modifier les branches"
msgid "Change confidentiality"
-msgstr ""
+msgstr "Modifier la confidentialité"
msgid "Change label"
msgstr "Modifier le label"
@@ -9489,6 +9602,9 @@ msgstr "Les modifications apportées au titre n'ont pas été enregistrées"
msgid "Changes:"
msgstr "Modifications :"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr "Toute modification de paramètre ci-dessous ne nécessite pas de redémarrage de l'application"
+
msgid "Changing any setting here requires an application restart"
msgstr "Toute modification de paramètre nécessitera un redémarrage de l'application"
@@ -9579,6 +9695,9 @@ msgstr "Vérifiez les vulnérabilités connues de vos images Docker."
msgid "Check your sign-up restrictions"
msgstr "Vérifier vos restrictions d'inscription"
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Vérification de la disponibilité de %{text}…"
@@ -9637,8 +9756,8 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] "%{quantity} pack de stockage"
msgstr[1] "%{quantity} packs de stockage"
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "Forfait %{selectedPlanText}"
+msgid "Checkout|%{selectedPlanText}"
+msgstr "%{selectedPlanText}"
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr "Choisir un modèle…"
msgid "Choose a type..."
msgstr "Choisir un type…"
+msgid "Choose an option"
+msgstr "Choisir une option"
+
msgid "Choose file…"
msgstr "Choisir un fichier…"
@@ -9926,7 +10048,7 @@ msgid "CiCatalog|About this project"
msgstr "À propos de ce projet"
msgid "CiCatalog|Back to the CI/CD Catalog"
-msgstr ""
+msgstr "Retour au catalogue CI/CD"
msgid "CiCatalog|CI/CD Catalog"
msgstr "Catalogue CI/CD"
@@ -9935,7 +10057,7 @@ msgid "CiCatalog|CI/CD Catalog resource"
msgstr "Ressource du catalogue CI/CD"
msgid "CiCatalog|Component ID not found, or you do not have permission to access component."
-msgstr ""
+msgstr "L’ID du composant n’a pas été trouvé, ou vous n’avez pas la permission d’y accéder."
msgid "CiCatalog|Create a pipeline component repository and make reusing pipeline configurations faster and easier."
msgstr "Créez un dépôt de composants de pipeline et rendez la réutilisation des configurations de pipeline plus rapide et plus simple."
@@ -9956,7 +10078,7 @@ msgid "CiCatalog|Mark project as a CI/CD Catalog resource. %{linkStart}What is t
msgstr "Marquez le projet comme une ressource de catalogue CI/CD. %{linkStart}Qu'est-ce que le catalogue CI/CD ?%{linkEnd}"
msgid "CiCatalog|No component available"
-msgstr ""
+msgstr "Aucun composant disponible"
msgid "CiCatalog|No release available"
msgstr "Aucune version de release disponible"
@@ -10093,15 +10215,15 @@ msgstr "Variables CI/CD"
msgid "CiVariables|Cancel"
msgstr "Annuler"
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "Impossible d'utiliser une variable masquée avec la valeur actuelle"
-
msgid "CiVariables|Delete variable"
msgstr "Supprimer la variable"
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr "Voulez-vous vraiment supprimer la variable %{key} ?"
+msgid "CiVariables|Edit Variable"
+msgstr "Modifier la variable"
+
msgid "CiVariables|Environments"
msgstr "Environnements"
@@ -10153,9 +10275,6 @@ msgstr "Supprimer les saisies"
msgid "CiVariables|Remove variable"
msgstr "Supprimer la variable"
-msgid "CiVariables|Remove variable row"
-msgstr "Supprimer cette variable"
-
msgid "CiVariables|Run job"
msgstr "Exécuter le job"
@@ -10177,12 +10296,24 @@ msgstr "Une erreur s'est produite lors de la récupération des variables CI hé
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr "Ce %{entity} comporte %{currentVariableCount} variables CI/CD définies. Le nombre maximum de variables par %{entity} est de %{maxVariableLimit}. Pour en ajouter de nouvelles, vous devez réduire le nombre de variables définies."
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Type"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Valeur"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr "La variable sera masquée dans les journaux de jobs. Nécessite des valeurs pour répondre aux exigences des expressions rationnelles."
@@ -10198,9 +10329,6 @@ msgstr "Les variables stockent des informations, telles que des mots de passe et
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr "Vous avez atteint le nombre maximum de variables disponibles. Pour en ajouter de nouvelles, vous devez réduire le nombre de variables définies."
-msgid "CiVariable|* (All environments)"
-msgstr "* (Tous les environnements)"
-
msgid "CiVariable|All environments"
msgstr "Tous les environnements"
@@ -10211,7 +10339,7 @@ msgid "CiVariable|Define a CI/CD variable in the UI"
msgstr "Définir une variable CI/CD dans l'UI"
msgid "CiVariable|GitLab CI/CD supports OpenID Connect (OIDC) to give your build and deployment jobs access to cloud credentials and services. %{linkStart}How do I configure OIDC for my cloud provider?%{linkEnd}"
-msgstr ""
+msgstr "GitLab CI/CD prend en charge OpenID Connect (OIDC) pour donner à vos jobs de développement et de déploiement l'accès aux identifiants et aux services Cloud. %{linkStart}Comment configurer OIDC pour mon fournisseur de Cloud ?%{linkEnd}"
msgid "CiVariable|Maximum of %{limit} environments listed. For more environments, enter a search query."
msgstr "%{limit} environnements au maximum sont répertoriés. Pour plus d'environnements, entrez une requête de recherche."
@@ -10223,7 +10351,7 @@ msgid "CiVariable|Search environments"
msgstr "Chercher des environnements"
msgid "CiVariable|Use OIDC to securely connect to cloud services"
-msgstr ""
+msgstr "Utiliser OIDC pour vous connecter en toute sécurité aux services Cloud"
msgid "CiVariable|Variable %{key} has been deleted."
msgstr "La variable %{key} a été supprimée."
@@ -10359,6 +10487,9 @@ msgstr "Clients"
msgid "Clientside DSN"
msgstr "DSN côté client"
+msgid "Clientside traces sample rate"
+msgstr "Fréquence d'échantillonnage des traces côté client"
+
msgid "Clone"
msgstr "Cloner"
@@ -10656,15 +10787,9 @@ msgstr "Santé du cluster"
msgid "Cluster cache cleared."
msgstr "Cache du cluster vidé."
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr "Un cluster est requis pour Stages::ClusterEndpointInserter"
-
msgid "Cluster level"
msgstr "Niveau de cluster"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr "Le type de cluster doit être spécifié pour Stages::ClusterEndpointInserter"
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr "%{linkStart}Voir la documentation%{linkEnd} de l'installation avancée. Assurez-vous d'être en possession de votre jeton d'accès."
@@ -10955,6 +11080,9 @@ msgstr "Cet agent n'a aucun jeton"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "Pour supprimer l'agent, tapez %{name} pour confirmer :"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr "Pour gérer plus d’agents, %{linkStart}utilisez Terraform%{linkEnd}."
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr "Pour révoquer le jeton, tapez %{name} pour confirmer :"
@@ -10979,6 +11107,9 @@ msgstr "Voir tous les %{number} agents"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "Voir toutes les %{number} clusters"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr "L'interface graphique ne prend en charge que 100 agents."
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "Nous aimerions en savoir plus sur votre expérience avec l'agent GitLab."
@@ -11402,9 +11533,6 @@ msgstr "Revue de code"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "Les données d'analyse de revue de code offrent un tableau des requêtes de fusion ouvertes et considérées comme étant en revue de code. Il n'y a actuellement aucune requête de fusion en cours de revue pour ce projet et/ou pour ces filtres."
-msgid "Code Suggestions add-on"
-msgstr "Module complémentaire Suggestions de code"
-
msgid "Code Suggestions add-on status"
msgstr "Statut du module complémentaire Suggestions de code"
@@ -11474,33 +11602,30 @@ msgstr "Activer les suggestions de code pour cette instance %{beta}"
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr "Activer les suggestions de code pour les utilisateurs de cette instance. %{link_start}Que sont les suggestions de code ?%{link_end}"
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr "Entrer un nouveau jeton d'accès personnel"
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
-msgstr "Sur GitLab.com, créez un jeton. Celui-ci est nécessaire pour utiliser les Suggestions de code sur votre instance GitLab Auto-géré. %{link_start}Comment créer un jeton ?%{link_end}"
-
-msgid "CodeSuggestionsSM|Personal access token"
-msgstr "Jeton d'accès personnel"
-
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
-msgstr "Les %{code_suggestions_link_start}suggestions de code%{link_end} utilisent désormais des services d'IA tiers pour fournir des suggestions de meilleure qualité. Vous pouvez %{third_party_link_start}désactiver les services tiers%{link_end} pour votre groupe ou désactiver entièrement les suggestions de code dans %{profile_settings_link_start}votre profil d'utilisateur%{link_end}."
-
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
-msgstr "Nous utilisons des services d'IA tiers pour améliorer les suggestions de code."
-
msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr "%{link_start}Que sont les suggestions de code ?%{link_end}"
msgid "CodeSuggestions|Code Suggestions"
msgstr "Suggestions de code"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
+msgstr ""
+
msgid "CodeSuggestions|Enable Code Suggestions"
msgstr "Activer les suggestions de code"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
+msgstr ""
+
msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr "Obtenez des suggestions de code au fur et à mesure que vous écrivez du code dans votre EDI. %{link_start}En savoir plus%{link_end}."
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
+msgstr "Présentation du module complémentaire Suggestions de code"
+
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
+msgstr ""
+
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
msgstr "Les projets dans ce groupe peuvent utiliser les suggestions de code"
@@ -11569,6 +11694,9 @@ msgstr "Les cohortes d'utilisateurs présentées concernent les %{months_include
msgid "Collapse"
msgstr "Réduire"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr "Réduire tous les fils de conversation"
@@ -11928,9 +12056,6 @@ msgstr "Une erreur s'est produite lors du chargement de la liste des branches/é
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "Une erreur s'est produite lors de la recherche de la liste des branches/étiquettes. Veuillez réessayer."
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "Une erreur s'est produite lors de la mise à jour de la liste des branches/étiquettes. Veuillez réessayer."
-
msgid "CompareRevisions|View open merge request"
msgstr "Voir la requête de fusion ouverte"
@@ -11976,6 +12101,9 @@ msgstr "Centre de conformité"
msgid "Compliance framework"
msgstr "Cadriciel de conformité"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr "Cadriciels de conformité actifs"
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Ajouter un cadriciel"
@@ -12033,8 +12161,8 @@ msgstr "Erreur lors de la récupération des données des cadriciels de conformi
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr "Erreur lors de la configuration des cadriciels de conformité par défaut"
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
-msgstr "Les cadres de conformité qui ont été ajoutés apparaîtront ici."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr "Les cadriciels de conformité qui ont été ajoutés apparaîtront ici. Commencez par en créer un ci-dessus."
msgid "ComplianceFrameworks|Invalid format"
msgstr "Format non valide"
@@ -12249,15 +12377,18 @@ msgstr "Confidentialité"
msgid "Configuration help"
msgstr "Aide à la configuration"
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "Configurer l'affichage et le contenu des %{italic_start}Nouveautés%{italic_end}."
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
-msgstr "Configurez %{link} pour suivre les événements. %{link_start}En savoir plus.%{link_end}"
-
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr "Configurez des %{repository_checks_link_start}vérifications de dépôt%{link_end} et la %{housekeeping_link_start}maintenance%{link_end} sur les dépôts."
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr "Configurez %{snowplow_link_start}Snowplow%{snowplow_link_end} pour faire le suivi des événements. %{help_link_start}En savoir plus.%{help_link_end}"
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr "Configurer les CAPTCHA, limitations d'adresse IP et autres mesures antispam."
@@ -12321,6 +12452,9 @@ msgstr "Configurez les permissions avancées, Large File Storage, l'authentifica
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr "Configurez les autorisations avancées, la fonctionnalité Stockage de fichiers volumineux, l'authentification à deux facteurs et les paramètres de relation client."
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr "Configurer les règles personnalisées pour établir la correspondance avec les clés de tickets Jira"
@@ -12492,6 +12626,9 @@ msgstr "Échec de connexion"
msgid "Consistency guarantee method"
msgstr "Méthode de garantie de cohérence"
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "Contacter le support"
@@ -12620,7 +12757,7 @@ msgid "ContainerRegistry|Created %{time}"
msgstr "Création le %{time}"
msgid "ContainerRegistry|Delete image repository"
-msgstr ""
+msgstr "Supprimer le dépôt d’images"
msgid "ContainerRegistry|Delete image repository?"
msgstr "Supprimer le dépôt d’images°?"
@@ -13014,6 +13151,9 @@ msgstr "Ajout du design %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr "Requête de fusion %{targetLink} approuvée dans %{resourceParentLink}."
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr "Design archivé dans %{resourceParentLink}."
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr "A fermé l'épopée %{targetLink} dans %{resourceParentLink}."
@@ -13047,6 +13187,30 @@ msgstr "ÉvénementContribution|Tâche fermée %{targetLink} dans %{resourcePare
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr "ÉvénementContribution|Cas de test fermé %{targetLink} dans %{resourceParentLink}."
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr "A commenté l'élément suivant : %{noteableLink}."
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr "A commenté l'épopée %{noteableLink} dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr "A commenté la validation %{noteableLink} dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr "A commenté le design %{noteableLink} dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr "A commenté le ticket %{noteableLink} dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr "A commenté la requête de fusion %{noteableLink} dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr "A commenté l'extrait de code %{noteableLink} dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr "A commenté l'extrait de code %{noteableLink}."
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr "A créé le projet %{resourceParentLink}."
@@ -13059,9 +13223,18 @@ msgstr "A créé la page de wiki %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr "Suppression de la branche %{refLink} dans %{resourceParentLink}."
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr "Jalon supprimé dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Deleted resource."
+msgstr "Ressource supprimée."
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr "Suppression de l'étiquette %{refLink} dans %{resourceParentLink}."
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr "Page de wiki supprimée dans %{resourceParentLink}."
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr "Projet %{resourceParentLink} rejoint."
@@ -13117,37 +13290,46 @@ msgid "ContributionEvent|Removed due to membership expiration from %{resourcePar
msgstr "Suppression due à l'expiration de l'abonnement de %{resourceParentLink}."
msgid "ContributionEvent|Reopened Epic %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert l'épopée %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened incident %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert l'incident %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened issue %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert le ticket %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened key result %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert le résultat clé %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened merge request %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert la demande de fusion %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened milestone %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert le jalon %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened objective %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert l'objectif %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened requirement %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert l'exigence %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened resource."
-msgstr ""
+msgstr "A rouvert la ressource."
msgid "ContributionEvent|Reopened task %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert la tâche %{targetLink} dans %{resourceParentLink}."
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "A rouvert le scénario de test %{targetLink} dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr "A mis à jour le design %{targetLink} dans %{resourceParentLink}."
+
+msgid "ContributionEvent|Updated resource."
+msgstr "A mis à jour une ressource."
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr "A mis à jour la page de wiki %{targetLink} sur %{resourceParentLink}."
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr "…et %{count} validations en plus. %{linkStart}Comparer%{linkEnd}."
@@ -13681,7 +13863,7 @@ msgid "Create phone verification exemption"
msgstr "Créer une exemption de vérification par téléphone"
msgid "Create pipeline trigger token"
-msgstr ""
+msgstr "Créer un jeton de déclenchement de pipeline"
msgid "Create project"
msgstr "Créer le projet"
@@ -13695,6 +13877,9 @@ msgstr "Créer une release"
msgid "Create requirement"
msgstr "Créer une exigence"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr "Créer un compte de service"
@@ -13918,10 +14103,10 @@ msgid "Created %{timeAgo} by %{author}"
msgstr "Création : %{timeAgo} par %{author}"
msgid "Created %{timeAgo} by %{email} via %{author}"
-msgstr ""
+msgstr "Création il y a %{timeAgo} par %{email} via %{author}"
msgid "Created %{time_ago}"
-msgstr ""
+msgstr "Créé %{time_ago}"
msgid "Created %{timestamp}"
msgstr "Créé %{timestamp}"
@@ -14073,9 +14258,6 @@ msgstr "L'organisation a été ajoutée."
msgid "Crm|Organization has been updated."
msgstr "L'organisation a été mise à jour."
-msgid "Cron Timezone"
-msgstr "Fuseau horaire des tâches planifiées cron"
-
msgid "Cron time zone"
msgstr "Fuseau horaire Cron"
@@ -14414,9 +14596,6 @@ msgstr "Délai de restauration de service"
msgid "CycleAnalytics|Total time"
msgstr "Durée totale"
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "filtre de la liste déroulante des groupes"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr "n'est pas autorisé pour l'événement de début donné"
@@ -14592,6 +14771,9 @@ msgstr "Niveau moyen"
msgid "DORA4Metrics|Merge request throughput"
msgstr "Débit des requêtes de fusion"
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr "Comparaison de métriques pour %{name}"
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr "Comparaison des métriques pour le groupe %{name}"
@@ -14632,10 +14814,10 @@ msgid "DORA4Metrics|Show forecast"
msgstr "Afficher les prévisions"
msgid "DORA4Metrics|Some metric charts failed to load"
-msgstr ""
+msgstr "Certains graphiques de métriques n'ont pas réussi à charger"
msgid "DORA4Metrics|Some metric comparisons failed to load"
-msgstr ""
+msgstr "Certaines comparaisons de métriques n'ont pas réussi à charger"
msgid "DORA4Metrics|Something went wrong while getting change failure rate data."
msgstr "Une erreur s'est produite lors de l'obtention des données sur le taux d'échec des modifications."
@@ -14682,6 +14864,9 @@ msgstr "Délai de restauration de service (jours médians)"
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr "Pour nous aider à améliorer la fonctionnalité Afficher les prévisions, veuillez partager votre expérience en mettant un commentaire sur %{linkStart}ce ticket%{linkEnd}."
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr "Pour nous aider à améliorer le tableau de bord de la gestion de la chaîne de valeur, veuillez partager votre expérience en participant à cette %{linkStart}enquête%{linkEnd}."
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr "1 jour ou moins est nécessaire pour restaurer le service en cas d'incident ou de défaut ayant un impact sur les utilisateurs."
@@ -14904,6 +15089,9 @@ msgstr "Minimum = 0 (délai d'attente non activé), Maximum = 2880°minutes"
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "Minimum = 1 seconde, Maximum = 3 600°secondes"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr "Surveille toutes les requêtes HTTP envoyées vers la cible pour trouver des vulnérabilités potentielles."
@@ -15401,7 +15589,7 @@ msgid "DefaultBranchProtection|Protected against pushes"
msgstr "Protégée contre les poussées"
msgid "Define a custom deploy freeze pattern with %{cronSyntaxStart}cron syntax%{cronSyntaxEnd}."
-msgstr ""
+msgstr "Définissez un motif de gel de déploiement personnalisé avec la %{cronSyntaxStart}syntaxe cron%{cronSyntaxEnd}."
msgid "Define a custom pattern with cron syntax"
msgstr "Définir un schéma personnalisé avec une syntaxe cron"
@@ -15409,9 +15597,6 @@ msgstr "Définir un schéma personnalisé avec une syntaxe cron"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr "Mise en place de règles personnalisées pour définir ce qui constitue du spam, indépendamment d'Akismet"
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "Définissez des environnements pour les étapes de déploiement dans %{code_open}.gitlab-ci.yml%{code_close} pour y suivre celles-ci."
-
msgid "Define how approval rules are applied to merge requests."
msgstr "Définir comment les règles d'approbation sont appliquées aux requêtes de fusion."
@@ -15534,9 +15719,6 @@ msgstr "Supprimer le label : %{labelName}"
msgid "Delete pipeline"
msgstr "Supprimer le pipeline"
-msgid "Delete pipeline schedule"
-msgstr "Supprimer la planification de pipeline"
-
msgid "Delete project"
msgstr "Supprimer le projet"
@@ -15757,6 +15939,9 @@ msgstr "Emplacement et chemin de dépendance"
msgid "Dependencies|Packager"
msgstr "Empaqueteur"
+msgid "Dependencies|Project list unavailable"
+msgstr "La liste de projets n'est pas disponible"
+
msgid "Dependencies|Projects"
msgstr "Projets"
@@ -15775,6 +15960,9 @@ msgstr "Le chemin de dépendance du composant est basé sur le fichier verrou. I
msgid "Dependencies|There may be multiple paths"
msgstr "Il peut y avoir plusieurs chemins d'accès"
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr "Ce groupe dépasse le nombre maximum de 600 sous-groupes. Nous ne pouvons pas afficher avec précision une liste de projets pour le moment. Veuillez accéder à une liste des dépendances du sous-groupe pour afficher ces informations ou consultez la page d'%{linkStart}aide de la liste des dépendances%{linkEnd} pour en savoir plus."
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "Basculer la liste des vulnérabilités"
@@ -15938,7 +16126,7 @@ msgid "DeployFreeze|Deploy freeze from %{start} to %{end} in %{timezone} will be
msgstr "Le gel de déploiement du %{start} au %{end} dans %{timezone} sera supprimé. Voulez-vous vraiment continuer ?"
msgid "DeployFreeze|Deploy freezes"
-msgstr ""
+msgstr "Gels de déploiement"
msgid "DeployFreeze|Freeze end"
msgstr "Fin du gel"
@@ -15947,7 +16135,7 @@ msgid "DeployFreeze|Freeze start"
msgstr "Début du gel"
msgid "DeployFreeze|No deploy freezes exist for this project. To add one, select %{strongStart}Add deploy freeze%{strongEnd} above."
-msgstr ""
+msgstr "Il n'y a aucun gel de déploiement pour ce projet. Pour en ajouter un, sélectionnez %{strongStart}Ajouter un gel de déploiement%{strongEnd} ci-dessus."
msgid "DeployFreeze|Specify deploy freezes using %{cron_syntax_link_start}cron syntax%{cron_syntax_link_end}."
msgstr "Spécifiez les gels de déploiement avec la %{cron_syntax_link_start}syntaxe cron%{cron_syntax_link_end}."
@@ -15958,6 +16146,12 @@ msgstr "Fuseau horaire"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} autres"
+msgid "DeployKeys|Add new deploy key"
+msgstr "Ajouter une nouvelle clé de déploiement"
+
+msgid "DeployKeys|Add new key"
+msgstr "Ajouter une nouvelle clé"
+
msgid "DeployKeys|Current project"
msgstr "Projet actuel"
@@ -15985,8 +16179,8 @@ msgstr "Accorder des autorisations d'écriture à cette clé"
msgid "DeployKeys|Loading deploy keys"
msgstr "Chargement des clés de déploiement"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "Aucune clé de déploiement trouvée. Créez-en une avec le formulaire ci-dessous."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr "Aucune clé de déploiement trouvée, commencez par en ajouter une nouvelle ci-dessus."
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "Clés de déploiement à accès privé"
@@ -16000,8 +16194,8 @@ msgstr "Clés de déploiement à accès public"
msgid "DeployKeys|Read access only"
msgstr "Accès en lecture seule"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "Jetons de déploiement actifs (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr "Jetons de déploiement actifs"
msgid "DeployTokens|Allows read and write access to registry images."
msgstr "Autorise l'accès en lecture et écriture aux images du registre."
@@ -16024,6 +16218,9 @@ msgstr "Autorise l'accès en lecture seule au dépôt."
msgid "DeployTokens|Allows write access to registry images."
msgstr "Autorise l'accès en écriture aux images de registre."
+msgid "DeployTokens|Cancel"
+msgstr "Annuler"
+
msgid "DeployTokens|Copy deploy token"
msgstr "Copier le jeton de déploiement"
@@ -16084,8 +16281,8 @@ msgstr "Champs d'application"
msgid "DeployTokens|Scopes (select at least one)"
msgstr "Portées (en sélectionner au moins une)"
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
-msgstr "Ce %{entity_type} ne possède aucun jeton de déploiement actif."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
+msgstr "L'élément %{entity_type} n'a pas de jeton de déploiement actif."
msgid "DeployTokens|This action cannot be undone."
msgstr "Cette action ne peut pas être annulée."
@@ -16102,12 +16299,12 @@ msgstr "Nom d'utilisateur"
msgid "DeployTokens|Username (optional)"
msgstr "Nom d'utilisateur (facultatif)"
-msgid "DeployTokens|Your New Deploy Token"
-msgstr "Votre nouveau jeton de déploiement"
-
msgid "DeployTokens|Your new Deploy Token username"
msgstr "Le nom d'utilisateur de votre nouveau jeton de déploiement"
+msgid "DeployTokens|Your new deploy token"
+msgstr "Votre nouveau jeton de déploiement"
+
msgid "DeployTokens|Your new group deploy token has been created."
msgstr "Votre nouveau jeton de déploiement de groupe a été créé."
@@ -16189,6 +16386,12 @@ msgstr "Approuvé par vous %{time}"
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr "Approuver exécutera le job manuel depuis le déploiement #%{deploymentIid}. Rejeter fera échouer le job manuel."
+msgid "DeploymentApproval|Deployment approved"
+msgstr "Déploiement approuvé"
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr "Déploiement rejeté"
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr "Étape du déploiement : %{tier}"
@@ -16260,9 +16463,6 @@ msgstr "Définissez les environnements pour la ou les étapes de déploiement da
msgid "Deployments|You don't have any deployments right now."
msgstr "Vous n'avez aucun déploiement pour le moment."
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "Annulé"
@@ -16275,6 +16475,24 @@ msgstr "ID de déploiement"
msgid "Deployment|Failed"
msgstr "Échec"
+msgid "Deployment|Flux sync failed"
+msgstr "Échec de la synchronisation Flux"
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr "Rapprochement de la synchronisation Flux réussi"
+
+msgid "Deployment|Flux sync reconciling"
+msgstr "Rapprochement de la synchronisation Flux"
+
+msgid "Deployment|Flux sync stalled"
+msgstr "Synchronisation Flux retardée"
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr "Le statut de la synchronisation de Flux est inconnu"
+
msgid "Deployment|Latest Deployed"
msgstr "Dernier déploiement"
@@ -16290,17 +16508,20 @@ msgstr "Ignoré"
msgid "Deployment|Success"
msgstr "Succès"
-msgid "Deployment|This deployment was created using the API"
-msgstr "Ce déploiement a été créé à l'aide de l'API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr "Le statut de la synchronisation est inconnu. %{linkStart}Comment puis-je configurer Flux pour mon déploiement ?%{linkEnd}"
msgid "Deployment|Triggerer"
msgstr "Déclenché par"
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr "Impossible de détecter le statut. %{linkStart}Comment les statuts sont-ils détectés ?%{linkEnd}"
+
msgid "Deployment|Unavailable"
msgstr "Non disponible"
msgid "Deployment|Unknown"
-msgstr ""
+msgstr "Inconnu"
msgid "Deployment|Waiting"
msgstr "En attente"
@@ -16365,12 +16586,6 @@ msgstr "Design"
msgid "Design Management files and data"
msgstr "Fichiers et données de la gestion des designs"
-msgid "Design repositories"
-msgstr "Dépôts de designs"
-
-msgid "Design repository"
-msgstr "Dépôt de designs"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} sur %{designs_count}"
@@ -17565,9 +17780,6 @@ msgstr "Le courriel a été envoyé"
msgid "Email the pipeline status to a list of recipients."
msgstr "Envoyez l'état du pipeline par courriel à une liste de destinataires."
-msgid "Email updates (optional)"
-msgstr "Envoyer des actualités par courriel (facultatif)"
-
msgid "Email:"
msgstr "Courriel°:"
@@ -17610,6 +17822,9 @@ msgstr "%{emails}, %{andMore} seront informés de votre commentaire."
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "et %{moreCount} de plus"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr "Mettez à jour votre adresse de courriel en indiquant une adresse permanente valide. Si vous utilisez une adresse de courriel temporaire, vous ne pourrez pas vous connecter ultérieurement."
+
msgid "Emails"
msgstr "Courriels"
@@ -17748,9 +17963,6 @@ msgstr "Activer les runners de groupe"
msgid "Enable header and footer in emails"
msgstr "Activer l'en-tête et le pied de page dans les courriels"
-msgid "Enable in-product marketing emails"
-msgstr "Activer les courriels marketing au sein du produit"
-
msgid "Enable incident management inbound alert limit"
msgstr "Activer la limite d'alerte entrante de la gestion des incidents"
@@ -17772,8 +17984,8 @@ msgstr "N'activer que pour les applications confidentielles utilisées exclusive
msgid "Enable or disable version check and Service Ping."
msgstr "Activer ou désactiver le contrôle de version et le Ping de Service."
-msgid "Enable rate limiting for POST requests to the specified paths"
-msgstr "Activer la limitation de fréquence pour les requêtes POST vers les chemins spécifiés"
+msgid "Enable rate limiting for requests to the specified paths"
+msgstr ""
msgid "Enable reCAPTCHA"
msgstr "Activer le reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr "Imposer l'authentification à deux facteurs pour toutes les connexions d
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr "Améliorez la sécurité en stockant les clés de compte de service dans des gestionnaires de secrets. En savoir plus sur la %{docLinkStart}gestion de secrets avec GitLab%{docLinkEnd}"
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr "Améliorez votre expérience de codage avec des recommandations intelligentes. Les %{linkStart}suggestions de code%{linkEnd} utilisent une IA générative pour proposer du code pendant que vous êtes en train de développer. Non disponible pour les utilisateurs ayant le rôle Invité."
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr "Assurez-vous que votre %{linkStart}environnement fait partie de l'étape de déploiement%{linkEnd} de votre pipeline CI pour pouvoir suivre les déploiements dans votre cluster."
@@ -18000,8 +18209,8 @@ msgstr "Environnement"
msgid "Environment scope"
msgstr "Portée de l'environnement"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr "Les variables d'environnement de cette instance GitLab sont configurées pour être %{link_start}protégées%{link_end} par défaut."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr "Sur cette instance GitLab, les variables d'environnement sont configurées pour être %{help_link_start}protégées%{help_link_end} par défaut."
msgid "Environment:"
msgstr "Environnement :"
@@ -18147,12 +18356,18 @@ msgstr "Premiers pas avec les environnements"
msgid "Environments|GitLab agent"
msgstr "Agent GitLab"
+msgid "Environments|HelmReleases"
+msgstr "HelmReleases"
+
msgid "Environments|Job"
msgstr "Job"
msgid "Environments|Kubernetes namespace (optional)"
msgstr "Espace de nommage Kubernetes (facultatif)"
+msgid "Environments|Kustomizations"
+msgstr "Personnalisations à l'aide de l'outil Kustomize"
+
msgid "Environments|Learn more about stopping environments"
msgstr "En savoir plus sur l'arrêt des environnements"
@@ -18198,6 +18413,12 @@ msgstr "Restaurer l'environment %{name} ?"
msgid "Environments|Search by environment name"
msgstr "Rechercher par nom d'environnement"
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr "Sélectionner un agent"
@@ -18234,6 +18455,9 @@ msgstr "Cette action va %{docsStart}réessayer d'effectuer le dernier déploieme
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr "Cette action va %{docsStart}restaurer cet environnement%{docsEnd} en revenant à un déploiement précédemment réussi pour la validation %{commitId}. Voulez-vous vraiment continuer ?"
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr "Impossible d'accéder aux ressources suivantes à partir de cet environnement. Vérifiez votre autorisation en lien avec l'élément suivant et réessayez :"
+
msgid "Environments|Upcoming"
msgstr "À venir"
@@ -18319,7 +18543,7 @@ msgid "Environment|Services"
msgstr "Services"
msgid "Environment|Stalled"
-msgstr ""
+msgstr "Point mort"
msgid "Environment|StatefulSets"
msgstr "StatefulSets"
@@ -18331,11 +18555,17 @@ msgid "Environment|Summary"
msgstr "Résumé"
msgid "Environment|Sync status"
-msgstr ""
+msgstr "État de la synchronisation"
msgid "Environment|There was an error connecting to the cluster agent."
msgstr "Une erreur s'est produite lors de la connexion à l'agent de cluster."
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr "Une erreur s'est produite lors de la récupération de %{resourceType}."
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr "Absence d'autorisation d'accès à %{resourceType} depuis cet environnement."
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr "Non autorisé à accéder à l'agent de cluster à partir de cet environnement. Vérifiez votre authentification et réessayez."
@@ -19091,6 +19321,9 @@ msgstr "Les méthodes de connexion existantes peuvent être supprimées"
msgid "Expand"
msgstr "Étendre"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Tout étendre"
@@ -19337,6 +19570,9 @@ msgstr "https://exemple.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr "Échec"
@@ -19426,7 +19662,7 @@ msgid "Failed to create resources"
msgstr "Échec de la création de ressources"
msgid "Failed to create target branch rule"
-msgstr ""
+msgstr "Échec de la création de la règle de branche cible"
msgid "Failed to create wiki"
msgstr "Échec de la création du wiki"
@@ -19994,9 +20230,6 @@ msgstr "Définissez un filtre sur les scénarios de test actuellement archivés.
msgid "Filter by test cases that are currently open."
msgstr "Filtrer par cas de tests actuellement ouverts."
-msgid "Filter by user"
-msgstr "Filtrer par utilisateur"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr "Les paramètres du filtre ne sont pas valides. Assurez-vous que la date de fin est postérieure à la date de début."
@@ -20021,9 +20254,6 @@ msgstr "Filtrer les résultats…"
msgid "Filter users"
msgstr "Filtrer les utilisateurs"
-msgid "Filter..."
-msgstr "Filtrer…"
-
msgid "Finalizing"
msgstr "Finalisation"
@@ -20181,7 +20411,7 @@ msgid "For additional information, review your %{link_to} or contact your group
msgstr "Pour plus d'informations, examinez votre %{link_to} ou contactez le propriétaire de votre groupe."
msgid "For additional information, review your %{project_or_group} membership: %{url} or contact your %{project_or_group} owner."
-msgstr ""
+msgstr "Pour plus d'informations, examinez vos attributions de droits à %{project_or_group} : %{url} ou contactez le propriétaire de %{project_or_group}."
msgid "For additional information, review your group membership: %{link_to} or contact your group owner."
msgstr "Pour plus d'informations, examinez votre adhésion au groupe°: %{link_to} ou contactez le propriétaire de votre groupe."
@@ -20392,33 +20622,6 @@ msgstr "Les groupes principaux gratuits seront bientôt limités à %{free_users
msgid "Free trial will expire in %{days}"
msgstr "La période d'essai gratuit se termine dans %{days}"
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "Vous pouvez également faire une mise à niveau vers GitLab Premium ou GitLab Ultimate :"
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "Explorer les forfaits payants"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "Explorez les forfaits payants :"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr "D'après la vérification qui a été faite le %{date_time}, il semble que vous ayez atteint la limite de %{free_user_limit} membres pour « %{namespace_name} ». Vous ne pouvez pas en ajouter plus, mais vous pouvez gérer vos membres existants, par exemple, en supprimant ceux qui sont inactifs pour les remplacer par des nouveaux."
-
-msgid "FreeUserCap|Manage members"
-msgstr "Gérer les membres"
-
-msgid "FreeUserCap|Manage members:"
-msgstr "Gérez les membres :"
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr "Afin ajouter plus de membres, %{trial_link_start}démarrez une période d'essai%{trial_link_end} ou %{upgrade_link_start}faites une mise à niveau%{upgrade_link_end} vers GitLab Premium ou GitLab Ultimate."
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr "Afin ajouter plus de membres, démarrez une période d'essai :"
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr "Vous avez atteint le nombre limite de membres !"
-
msgid "Freeze end"
msgstr "Fin du gel"
@@ -21113,6 +21316,12 @@ msgstr "Obtenez une revue d'instance gratuite"
msgid "Get a support subscription"
msgstr "Obtenir un abonnement au support"
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Lancez-vous"
@@ -21440,6 +21649,9 @@ msgstr "Non vérifiée"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Mise à jour en cours de la configuration de vos Pages..."
+msgid "GitLabPages|Use multiple versions"
+msgstr "Utiliser plusieurs versions"
+
msgid "GitLabPages|Use unique domain"
msgstr "Utiliser un domaine unique"
@@ -21455,6 +21667,9 @@ msgstr "Lorsque cette option est activée, un domaine unique est généré pour
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr "Lorsque cette option est activée, toutes les tentatives pour se rendre sur votre site Web via HTTP sont automatiquement redirigées vers HTTPS à l'aide d'une réponse avec le code d'état 301. Cette action nécessite un certificat valide pour tous les domaines. %{docs_link_start}En savoir plus.%{link_end}"
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr "Lorsque cette option est activée, vous pouvez créer plusieurs versions du site de vos pages."
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr "Lors de l'utilisation de Pages sous le domaine générique d'une instance GitLab (%{pages_host}), vous ne pouvez pas utiliser HTTPS avec des sous-domaines de sous-domaines. Si votre espace de nommage ou nom de groupe contient un point, il ne fonctionnera pas. Il s'agit d'une limitation du protocole HTTP Over TLS. Les pages HTTP fonctionneront si vous ne redirigez pas HTTP vers HTTPS. %{docs_link_start}En savoir plus.%{link_end}"
@@ -21470,12 +21685,6 @@ msgstr "Votre projet a été configuré pour Pages. Il faut à présent attendre
msgid "Gitaly Servers"
msgstr "Serveurs Gitaly"
-msgid "Gitaly relative path:"
-msgstr "Chemin d'accès relatif de Gitaly :"
-
-msgid "Gitaly storage name:"
-msgstr "Nom du stockage Gitaly :"
-
msgid "Gitaly timeouts"
msgstr "Délais d'expiration de Gitaly"
@@ -21596,8 +21805,8 @@ msgstr "L'URL de votre instance Gitpod configurée pour lire vos projets GitLab,
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr "Pour utiliser Gitpod, vous devez au préalable activer la fonctionnalité dans la section Intégrations de vos %{linkStart}préférences utilisateur%{linkEnd}."
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
-msgstr "Pour utiliser l'intégration, chaque utilisateur doit également activer Gitpod sur son compte. %{link_start}Comment puis-je l'activer ?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr "Pour utiliser l'intégration, chaque utilisateur doit également activer Gitpod sur son compte GitLab. %{help_link_start}Comment puis-je l'activer ?%{help_link_end}"
msgid "Gitpod|https://gitpod.example.com"
msgstr "https://gitpod.exemple.com"
@@ -21614,6 +21823,9 @@ msgstr "Accès donné %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr "L'épopée fournie est déjà associée à cette épopée."
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr "Verrouillage global de l'attribution des droits du groupe SAML"
@@ -21635,6 +21847,9 @@ msgstr " %{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr "%{count} résultats par défaut fournis. Utilisez les touches fléchées haut et bas pour parcourir la liste des résultats de la recherche."
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr "%{link_start}La recherche de code exact (optimisée par Zoekt)%{link_end} est activée"
+
msgid "GlobalSearch|Aggregations load error."
msgstr "Erreur lors du chargement des agrégations."
@@ -21647,6 +21862,9 @@ msgstr "Fermer"
msgid "GlobalSearch|Fetching aggregations error."
msgstr "Erreur de récupération des agrégations."
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "Groupe"
@@ -21687,7 +21905,7 @@ msgid "GlobalSearch|No labels found"
msgstr "Aucun label trouvé"
msgid "GlobalSearch|Places"
-msgstr ""
+msgstr "Lieux"
msgid "GlobalSearch|Project"
msgstr "Projet"
@@ -21716,9 +21934,6 @@ msgstr "Rechercher"
msgid "GlobalSearch|Search GitLab"
msgstr "Rechercher sur GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr "Rechercher sur GitLab %{kbdOpen}/%{kbdClose}"
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "Rechercher des projets, des tickets et d'autres choses."
@@ -21749,6 +21964,9 @@ msgstr "Une erreur s'est produite lors de la récupération des suggestions d'au
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr "Une erreur s'est produite lors de la récupération du document « Options de syntaxe »."
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr "Saisissez %{kbdOpen}/%{kbdClose} pour lancer une recherche"
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "Écrivez puis appuyez sur la touche Entrée pour soumettre la recherche."
@@ -21989,6 +22207,12 @@ msgstr "Révoquer les autorisations"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "Révoquer les autorisations accordées à GitLab. Cela n'invalide pas les comptes de service."
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr "Définir des variables uniquement sur les étiquettes et les branches protégées"
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr "Étiquettes et branches protégées uniquement"
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr "Faites glisser votre fichier de clé ici ou %{linkStart}cliquez pour le téléverser%{linkEnd}."
@@ -22004,8 +22228,8 @@ msgstr "Google Play"
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr "Laissez vide pour utiliser votre clé de compte de service actuelle."
-msgid "GooglePlay|Service account key (.json)"
-msgstr "Clé de compte de service (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
+msgstr "Clé de compte de service (.JSON)"
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
msgstr "Téléversez une nouvelle clé de compte de service (en remplacement de %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr "Avatar de groupe"
msgid "Group by"
msgstr "Regrouper par"
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "Description du groupe (optionnel)"
@@ -22181,9 +22408,6 @@ msgstr "Nom du groupe (votre organisation)"
msgid "Group navigation"
msgstr "Navigation dans les groupes"
-msgid "Group overview"
-msgstr "Vue d'ensemble du groupe"
-
msgid "Group overview content"
msgstr "Contenu de la vue d'ensemble du groupe"
@@ -22559,8 +22783,8 @@ msgstr "Choisissez les vérifications des requêtes de fusion pour les projets d
msgid "GroupSettings|Compliance frameworks"
msgstr "Cadriciels de conformité"
-msgid "GroupSettings|Configure analytics features for this group"
-msgstr "Configurer les fonctionnalités analytiques pour ce groupe"
+msgid "GroupSettings|Configure analytics features for this group."
+msgstr "Configurez les fonctionnalités analytiques pour ce groupe."
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
msgstr "Configurez les cadriciels de conformité pour les mettre à disposition des projets de ce groupe. %{linkStart}Que sont les cadriciels de conformité ?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr "Cette fonctionnalité nécessite la prise en charge de localStorage par
msgid "GroupsDropdown|Toggle edit mode"
msgstr "Basculer vers le mode édition"
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr "Un groupe est une collection de plusieurs projets."
msgid "GroupsEmptyState|Create new project"
@@ -22760,8 +22984,8 @@ msgstr "Créer un nouveau sous-groupe"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "Les groupes sont la manière la plus efficace de gérer plusieurs projets et membres."
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Si vous organisez vos projets au sein d'un groupe, cela fonctionne comme un dossier."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr "Si vous organisez vos projets au sein d'un groupe, ce dernier fonctionne comme un dossier. Vous pouvez gérer les autorisations des membres de votre groupe et accéder à chacun de ses projets."
msgid "GroupsEmptyState|No archived projects."
msgstr "Aucun projet archivé."
@@ -22778,9 +23002,6 @@ msgstr "Aucun sous-groupe ou projet."
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "Les projets sont l'endroit où vous pouvez stocker votre code et accéder aux tickets, au wiki et aux autres fonctionnalités de GitLab."
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "Vous pouvez gérer les autorisations des membres de votre groupe et accéder à chacun de ses projets."
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "Vous n'avez pas les permissions nécessaires pour créer un sous-groupe ou un projet dans ce groupe. Veuillez contacter un propriétaire de ce groupe pour créer un nouveau sous-groupe ou projet."
@@ -23202,6 +23423,9 @@ msgstr "Aidez-nous à traduire GitLab dans votre langue"
msgid "Help translate to your language"
msgstr "Contribuez à la traduction dans votre langue"
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr "Contribue à empêcher les attaques par force brute lancées par des bots."
@@ -23465,9 +23689,6 @@ msgstr "Je souhaite stocker mon code"
msgid "I want to use GitLab CI with my existing repository"
msgstr "Je souhaite utiliser GitLab CI avec mon dépôt existant"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "Je souhaite recevoir des actualités concernant GitLab par courriel"
-
msgid "I'm signing up for GitLab because:"
msgstr "Je m'inscris sur GitLab car :"
@@ -23507,6 +23728,12 @@ msgstr "Cette option est désactivée : vous ne disposez pas des permissions nÃ
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr "Cette option est désactivée : vous n'avez pas les droits d'écriture pour la branche actuelle."
+msgid "IDs with errors: %{error_messages}."
+msgstr "ID comportant des erreurs : %{error_messages}."
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr "IMPORTANT : utilisez ce paramètre uniquement à des fins d'audit TRÈS strictes. Lorsque cette option est activée, aucun utilisateur ne peut supprimer la label des requêtes de fusion après leur fusion. De plus, aucun utilisateur ne peut désactiver ce paramètre ni supprimer ce label."
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "NOTE : votre clé SSH a expiré. Veuillez générer une nouvelle clé."
@@ -23690,6 +23917,12 @@ msgstr "Vérifier la méthode de paiement"
msgid "IdentityVerification|Verify phone number"
msgstr "Vérifier le numéro de téléphone"
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr "Vérifier votre identité"
@@ -24101,8 +24334,8 @@ msgstr "Une erreur s'est produite lors de la récupération des détails de l'im
msgid "Import|GitHub import details"
msgstr "Détails de l'importation GitHub"
-msgid "Import|Maximum decompressed size (MiB)"
-msgstr "Taille maximale décompressée (Mio)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
+msgstr ""
msgid "Import|Maximum import remote file size (MB)"
msgstr "Importer|Taille maximale (Mo) des fichiers distants pour les importations"
@@ -24128,6 +24361,12 @@ msgstr "Le dépôt n'a pas pu être importé."
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr "Il n'y a pas de dépôt Git valide à cette URL. Si votre dépôt HTTP n'est pas publiquement accessible, vérifiez vos identifiants."
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr "Délai d'expiration pour la décompression des fichiers archivés (secondes)"
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr "Délai d'expiration pour la décompression des fichiers archivés."
+
msgid "Improve customer support with Service Desk"
msgstr "Améliorer le support client avec Service Desk"
@@ -24170,381 +24409,72 @@ msgstr "Est utilisé"
msgid "InProductMarketing|%{organization_name} logo"
msgstr "Logo de %{organization_name}"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr "%{strong_start}Sécurité avancée des applications%{strong_end}: cela inclut les analyses SAST et DAST, les tests à données aléatoires, l'analyse des dépendances, la conformité des licences et la détection de secrets"
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr "%{strong_start}Gestion de portefeuille à l'échelle de l'entreprise%{strong_end}°: cela inclut des épopées à plusieurs niveaux, des labels à portée limitée"
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr "%{strong_start}Analyses de niveau exécutif%{strong_end}°: cela inclut les rapports sur la productivité, les tâches par type, le nombre de jours avant réalisation, la chaîne de valeurs"
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr "%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr "%{strong_start}Rôles d'approbation multiples%{strong_end}°: cela inclut les propriétaires de code et les approbations de fusion requises"
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr "*GitLab*, nom°: synonyme d'équipes efficaces"
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...et vous pouvez obtenir un essai gratuit de GitLab Ultimate"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr "3°façons de plonger dans GitLab CI/CD"
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr "GitLab facilite (vraiment) le travail d'équipe"
-
msgid "InProductMarketing|Advanced security testing"
msgstr "Test de sécurité avancé"
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr "Et enfin %{deploy_link} une application Python."
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "Vos runners sont-ils prêts°?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr "Analyses de sécurité automatisées directement au sein de GitLab"
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "Soyez un héros du DevOps"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr "Renforcez votre sécurité"
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "Un code optimisé en moins de temps"
-
msgid "InProductMarketing|Blog"
msgstr "Blog"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr "Vous développez pour iOS ? Nous avons ce qu'il vous faut."
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr "En définissant des propriétaires de code et des approbations de fusion obligatoires, chaque MR sera examinée par l'utilisateur approprié. Il s'agit d'un véritable avantage, car cela aboutit à un code plus propre et à un processus d'examen plus efficace."
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr "Les propriétaires de code et les approbations de fusion requises font partie des éditions payantes de GitLab. Vous pouvez commencer une période d'essai de 30 jours de GitLab Ultimate et activer ces fonctionnalités en moins de 5 minutes sans avoir besoin de carte bancaire."
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr "Créer un runner CI personnalisé en quelques clics"
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr "Créer un runner personnalisé"
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "Créer un projet dans GitLab en 5°minutes"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "Créez votre premier projet."
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr "Livrer de Meilleurs Produits plus Rapidement"
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr "Saviez-vous que les équipes qui utilisent GitLab sont bien plus efficaces°?"
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr "Lancez-vous et créez un projet et un dépôt"
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr "Avez-vous un coéquipier qui serait parfait pour cette tâche ?"
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr "Développez votre parcours DevOps avec un essai gratuit de GitLab"
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "Explorez GitLab CI/CD"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "Explorer les options"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr "Explorez la puissance de GitLab CI/CD"
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr "Vous ressentez le besoin d'aller plus vite°?"
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr "Découvrez comment vos équipes s'en sortent réellement"
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "Suivez nos étapes"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "Essai gratuit de 30 jours"
msgid "InProductMarketing|Free guest users"
msgstr "Utilisateurs invités gratuits"
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr "Démarrez rapidement avec CI/CD en utilisant notre %{quick_start_link}. Commencez avec un runner disponible, puis créez un fichier CI .yml. C'est aussi simple que cela."
-
-msgid "InProductMarketing|Get our import guides"
-msgstr "Obtenez nos guides sur l'importation"
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr "Commencez à développer pour iOS"
-msgid "InProductMarketing|Get started today"
-msgstr "Commencez dès aujourd'hui"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr "Débutez dès aujourd'hui avec un essai gratuit de 30 jours de GitLab Ultimate, aucune carte de crédit n'est requise."
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr "Premiers pas avec GitLab CI/CD"
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr "Apprenez à connaître GitLab CI/CD"
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr "Mettez votre équipe en place sur GitLab"
-
-msgid "InProductMarketing|Git basics"
-msgstr "Bases sur Git"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr "Des projets GitHub Enterprise sur GitLab"
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr "GitLab propose des tests statiques de la sécurité des applications (SAST), des tests dynamiques de la sécurité des applications (DAST), des analyses de conteneurs ainsi que des analyses de dépendances pour contribuer à la livraison d'applications sécurisées et à la conformité des licences."
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr "L'approche CI/CD de GitLab facilite le développement logiciel. Vous ne nous croyez pas°? Voici trois façons de l'utiliser pour effectuer un essai rapide (et concluant)°:"
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr "Les éditions payantes de GitLab sont conçues pour vous aider, ainsi que votre équipe et votre application, à gagner en efficacité et en sécurité grâce à des fonctionnalités, qui comprennent, sans s'y limiter :"
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "Accordez-nous une minute..."
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr "Allez plus loin avec GitLab"
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr "Goldman Sachs est passé de 1°compilation toutes les deux semaines à des milliers par jour"
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr "Vous avez une autre instance que vous souhaitez importer°? Voici notre %{import_link}."
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr "Voici ce que vous devez savoir"
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr "De quelle manière (et pour quelle raison) la mise en miroir montre sa pertinence"
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr "Combien de temps nous faut-il pour clôturer des tickets/MR selon leurs types, comme des demandes de fonctionnalités, des bogues, une dette technique, la sécurité°?"
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr "Combien de jours faut-il à notre équipe pour effectuer différentes tâches°?"
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr "Comment compiler et tester plus rapidement"
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr "Si vous ne souhaitez pas recevoir de courriels commerciaux directement de GitLab, %{marketing_preference_link}."
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr "Si vous ne souhaitez plus recevoir de courriels commerciaux de notre part,"
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr "Importez votre projet et votre code depuis GitHub, Bitbucket et d'autres"
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr "Améliorez la sécurité des applications grâce à un essai de 30°jours"
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr "Améliorez la qualité du code et rationalisez son examen"
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr "Augmenter l'Efficacité Opérationnelle"
-msgid "InProductMarketing|Invite them to help out."
-msgstr "Invitez-les à vous aider."
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr "Inviter un nombre illimité de collègues"
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "Invitez vos collègues et commencez à livrer du code plus rapidement."
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "Invitez vos collègues à vous rejoindre en moins d'une minute"
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "Invitez vos collègues aujourd'hui"
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "Invitez votre équipe en moins de 60°secondes"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "Invitez votre équipe maintenant"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr "Invitez votre équipe dès aujourd'hui pour créer ensemble du code (et des processus) de meilleure qualité"
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr "Tout est dans les statistiques"
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr "Il est également possible de simplement %{external_repo_link} pour tirer profit des fonctionnalités CI/CD de GitLab."
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr "Lancez GitLab CI/CD en 20°minutes ou moins"
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr "Apprenez à développer pour iOS"
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr "Prêt pour la transition°? Il est plus facile que vous ne le pensez d'importer vos projets dans GitLab. Migrez %{github_link} ou importez quelque chose %{bitbucket_link}."
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr "Maîtrisez l'art de l'importation°!"
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr "Effectuez la transition pour créer facilement un site Web Pages %{ci_template_link}"
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr "Plusieurs propriétaires, des flux de travail déroutants°? Nous sommes là pour vous simplifier la vie"
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr "Besoin d'une alternative à l'importation°?"
-
msgid "InProductMarketing|No credit card required."
msgstr "Aucune carte de crédit requise."
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr "Notre outil centralise tout"
-
msgid "InProductMarketing|Portfolio management"
msgstr "Gestion de portefeuille"
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr "Développement rapide et simplifié"
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr "Réduire les risques de sécurité et de conformité"
msgid "InProductMarketing|Security risk mitigation"
msgstr "Atténuation des risques de sécurité"
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr "Une sécurité intégrée dans votre cycle de développement"
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr "Il se peut que vous ne soyez pas prêt pour une transition complète vers un nouvel outil. Si nous n'êtes pas prêt pour y passer totalement, la %{mirroring_link} vous donne une solution sûre pour toujours utiliser votre outil actuel tout en essayant GitLab en parallèle."
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr "Faire tourner un runner à dimensionnement automatique dans GitLab"
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "Commencez un essai GitLab Ultimate aujourd'hui en moins d'une minute, sans avoir besoin de carte de crédit."
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr "Démarrer un essai auto-géré"
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "Commencer un essai gratuit de GitLab Ultimate – pas besoin de carte bancaire"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "Commencer un essai"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "Commencez par %{performance_link}"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "Commencez par importer vos projets"
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "Commencer avec un essai gratuit de GitLab Ultimate"
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "Démarrer votre essai maintenant !"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr "Commencez votre essai aujourd'hui pour réussir avec une application unique et découvrir gratuitement toutes les fonctionnalités de GitLab Ultimate !"
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr "Arrêtez de vous interroger et utilisez GitLab pour répondre à des questions telles que°:"
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr "Rationalisez la revue de code, voyez en un clin d'œil qui n'est pas disponible, communiquez via les commentaires ou par courriel et intégrez Slack afin que tout le monde soit sur la même longueur d'onde."
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr "Faites vos premiers pas avec GitLab"
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr "Passez la gestion de votre code source au niveau supérieur"
-
msgid "InProductMarketing|Team members collaborating"
msgstr "Membres de l'équipe collaborant"
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr "Faites équipe sur GitLab pour une plus grande efficacité"
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr "Le travail d'équipe fait du rêve une réalité"
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr "Tester, créer, déployer"
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr "C'est tout ce qu'il faut pour démarrer avec GitLab, mais si vous travaillez avec Git pour la première fois, consultez nos %{basics_link} pour obtenir des conseils et astuces qui seront utiles pour débuter."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr "Ceci est le courriel %{current_series} sur %{total_series} dans la série %{track}."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr "Il s'agit du courriel %{current_series} sur %{total_series} de la série %{track}. Pour désactiver l'envoi de courriels de notification par votre instance GitLab locale, vous pouvez soit contacter votre administrateur, soit vous %{unsubscribe_link}."
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr "Ticketmaster a réduit son temps de compilation CI d'un facteur 15"
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr "Vous en avez assez de lutter avec des chaînes d'outils disparates, des silos d'informations et des processus inefficaces ? GitLab CI/CD est basé sur une plateforme DevOps avec gestion du code source, planification, supervision et bien plus encore. Découvrez %{ci_link}."
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr "Pour ne plus recevoir ces courriels d'intégration, %{unsubscribe_link}."
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr "Pour comprendre GitLab et en tirer le meilleur parti, commencez par le début et %{project_link}. Dans GitLab, les dépôts faisant partie d'un projet, une fois que vous avez créé votre projet, vous pouvez continuer et %{repo_link}."
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "Essayez GitLab Ultimate gratuitement"
-
-msgid "InProductMarketing|Try it out"
-msgstr "Essayez-le"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "Essayez-le vous-même"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr "Transformez vos collègues en collaborateurs"
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr "Comprendre la mise en miroir du dépôt"
-
-msgid "InProductMarketing|Understand your project options"
-msgstr "Comprendre les options de votre projet"
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr "Utiliser GitLab CI/CD"
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr "Utilisez notre modèle AWS cloudformation pour faire tourner vos runners en quelques clics !"
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr "Utilisé par plus de 100 000 entreprises dans le monde entier :"
@@ -24560,66 +24490,15 @@ msgstr "Vous souhaitez héberger GitLab sur vos serveurs ?"
msgid "InProductMarketing|Watch iOS building in action."
msgstr "Voyez le développement pour iOS à l'œuvre."
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr "Nous connaissons deux ou trois choses pour être efficace et nous ne pouvons pas les garder pour nous. Inscrivez-vous pour un essai gratuit de GitLab Ultimate et vos équipes seront à pied d'œuvre dès le premier jour."
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr "À quoi ressemble la chronologie de notre chaîne de valeurs, du produit à la production, en passant par le développement et la revue de code°?"
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr "Lorsque votre équipe est sur GitLab, ces réponses sont à portée de clic."
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr "Travailler sur GitLab est synonyme d'efficacité accrue"
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr "Vos équipes gagnent en efficacité"
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "guide complet"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "connecter un dépôt externe"
-
-msgid "InProductMarketing|create a project"
-msgstr "créer un projet"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "depuis Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "accéder à la page about.gitlab.com"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "comme il est facile de se lancer"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "guide de démarrage rapide"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "mise en miroir de dépôt"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "mettre en place un dépôt"
-
-msgid "InProductMarketing|test and deploy"
-msgstr "tester et déployer"
-
-msgid "InProductMarketing|testing browser performance"
-msgstr "tester les performances du navigateur"
-
msgid "InProductMarketing|unsubscribe"
msgstr "désabonner"
-msgid "InProductMarketing|update your preferences"
-msgstr "mettre à jour vos préférences"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr "en utilisant un modèle CI/CD"
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "vous pouvez vous %{unsubscribe_link} à tout moment."
@@ -25049,6 +24928,16 @@ msgstr "En ligne"
msgid "Inline math"
msgstr "Maths intégrées"
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] "1 découverte de vulnérabilité détectée dans la qualité du code"
+msgstr[1] "%d découvertes de vulnérabilité détectées dans la qualité du code"
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] "1 découverte de vulnérabilité détectée dans SAST"
+msgstr[1] "%d découvertes de vulnérabilité détectées dans SAST"
+
msgid "Input host keys manually"
msgstr "Entrer les clés d'hôte manuellement"
@@ -25405,6 +25294,9 @@ msgstr "Les tickets ZenTao apparaissent ici lorsque vous créez des tickets dans
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr "ne peut pas dépasser %{recipients_limit}"
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr "Branches pour lesquelles des notifications doivent être envoyées"
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr "IntelliJ IDEA (HTTPS)"
@@ -25441,15 +25333,9 @@ msgstr "Les utilisateurs internes ne peuvent pas être désactivés"
msgid "Interval"
msgstr "Intervalle"
-msgid "Interval Pattern"
-msgstr "Modèle d'intervalle"
-
msgid "Introducing Your DevOps Reports"
msgstr "Présentation de Vos Rapports DevOps"
-msgid "Introducing the Code Suggestions add-on"
-msgstr "Présentation du module complémentaire Suggestions de code"
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr "'schemaVersion' '%{schema_version}' non valide"
@@ -25531,9 +25417,6 @@ msgstr "Étiquettes non valides"
msgid "Invalid two-factor code."
msgstr "Code à deux facteurs non valide."
-msgid "Invalid yaml"
-msgstr "Yaml non valide"
-
msgid "Invalidated"
msgstr "Invalidé"
@@ -25866,18 +25749,12 @@ msgstr "a résolu tous les fils de conversation"
msgid "IssuableEvents|unassigned"
msgstr "plus assigné"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type} créé(e) %{created_at} par "
-
msgid "IssuableStatus|Closed"
msgstr "Fermé"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Fermé (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "Création %{created_at} par"
-
msgid "IssuableStatus|duplicated"
msgstr "doublon"
@@ -26127,29 +26004,49 @@ msgstr "Tickets sans épopée assignée"
msgid "Issues, merge requests, pushes, and comments."
msgstr "Tickets, requêtes de fusion, poussées et commentaires."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "Une fois que vous aurez commencé à créer des tickets en relation avec vos projets, nous pourrons commencer à en effectuer le suivi et à afficher des statistiques les concernant"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Moyenne/mois :"
+msgid "IssuesAnalytics|Closed"
+msgstr "Fermés"
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr "Échec du chargement du graphique. Veuillez réessayer."
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr "Tickets ouverts et fermés"
+
msgid "IssuesAnalytics|Issues created"
msgstr "Tickets créés"
msgid "IssuesAnalytics|Issues created per month"
msgstr "Tickets créés par mois"
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "Les 12 derniers mois"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr "Les 12 derniers mois (%{chartDateRange})"
+
+msgid "IssuesAnalytics|Opened"
+msgstr "Ouverts"
+
+msgid "IssuesAnalytics|Overview"
+msgstr "Vue d'ensemble"
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Désolé, aucun résultat ne correspond à vos critères de recherche"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "Il n'y a aucun ticket concernant les projets de votre groupe"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "Afin d'élargir votre recherche, modifiez ou supprimez les critères de recherche dans la barre de filtrage ciâ€dessus"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr "Pour élargir votre recherche, modifiez ou supprimez les critères de recherche dans la barre de filtrage ciâ€dessus."
msgid "IssuesAnalytics|Total:"
msgstr "Total :"
@@ -26196,6 +26093,9 @@ msgstr "Italique (%{modifierKey}I)"
msgid "Italic text"
msgstr "Texte en italique"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr "L'élément avec l'ID : %{id} ne peut pas être ajouté. Vous n'avez pas la permission d'effectuer cette action."
+
msgid "Iteration"
msgstr "Itération"
@@ -26532,6 +26432,9 @@ msgstr "Aucun groupe trouvé."
msgid "JiraConnect|No linked groups"
msgstr "Aucun groupe associé"
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr "Vos groupes n'apparaissent pas ? Seuls les groupes auxquels vous avez accès apparaissent ici."
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr "Vous ne voyez pas vos groupes ? Seuls les groupes pour lesquels vous avez au moins le rôle de Chargé de maintenance apparaissent ici."
@@ -27030,6 +26933,9 @@ msgstr "Durée"
msgid "Job|Erase job log and artifacts"
msgstr "Effacer le journal des jobs et les artefacts"
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr "Échoué"
@@ -27081,6 +26987,9 @@ msgstr "Réessayer"
msgid "Job|Run again"
msgstr "Exécuter à nouveau"
+msgid "Job|Runner type"
+msgstr "Type de runner"
+
msgid "Job|Running"
msgstr "En cours"
@@ -27177,9 +27086,6 @@ msgstr "Rejoindre un projet"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr "Rejoignez votre équipe sur GitLab et contribuez à un projet existant"
-msgid "Joined %{time_ago}"
-msgstr "A rejoint %{time_ago}"
-
msgid "Joined %{user_created_time}"
msgstr "Nous a rejoint %{user_created_time}"
@@ -27442,9 +27348,6 @@ msgstr "Dernière Activité"
msgid "Last Name"
msgstr "Nom"
-msgid "Last Pipeline"
-msgstr "Dernier pipeline"
-
msgid "Last Seen"
msgstr "Vu pour la dernière fois"
@@ -27541,6 +27444,9 @@ msgstr "Vous avez poussé sur"
msgid "LastPushEvent|at"
msgstr "à"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "Derniers changements"
@@ -27602,7 +27508,7 @@ msgid "Learn more about Needs relationships"
msgstr "En savoir plus sur les relations de besoins"
msgid "Learn more about Service Desk"
-msgstr ""
+msgstr "En savoir plus sur le service d'assistance"
msgid "Learn more about Web Terminal"
msgstr "En savoir plus sur le Terminal Web"
@@ -28242,6 +28148,9 @@ msgstr "Verrouiller %{issuableType}"
msgid "Lock File?"
msgstr "Verrouiller le fichier ?"
+msgid "Lock label after a merge request is merged"
+msgstr "Verrouiller la label après la fusion d'une requête de fusion"
+
msgid "Lock memberships to LDAP synchronization"
msgstr "Verrouiller les adhésions à la synchronisation LDAP"
@@ -28251,6 +28160,9 @@ msgstr "Verrouiller les attributions de droits à la synchronisation des liens d
msgid "Lock not found"
msgstr "Verrou non trouvé"
+msgid "Lock on merge"
+msgstr "Verrouiller lors de la fusion"
+
msgid "Lock status"
msgstr "État de verrouillage"
@@ -28285,7 +28197,7 @@ msgid "LoggedOutMarketingHeader|About GitLab"
msgstr "À propos de GitLab"
msgid "LoggedOutMarketingHeader|Contact Sales"
-msgstr ""
+msgstr "Contacter le service commercial"
msgid "LoggedOutMarketingHeader|Explore GitLab"
msgstr "Explorer GitLab"
@@ -28315,7 +28227,7 @@ msgid "LoggedOutMarketingHeader|Talk to an expert"
msgstr "Parler à un expert"
msgid "LoggedOutMarketingHeader|Why GitLab"
-msgstr ""
+msgstr "Les raisons de choisir GitLab"
msgid "Login with smartcard"
msgstr "Se connecter avec une carte à puce"
@@ -28549,7 +28461,7 @@ msgid "Markdown enabled."
msgstr "Markdown activé."
msgid "Markdown is supported"
-msgstr ""
+msgstr "Markdown est pris en charge"
msgid "Markdown supported."
msgstr "Markdown pris en charge."
@@ -28656,6 +28568,12 @@ msgstr "URL de Mattermost :"
msgid "Mattermost notifications"
msgstr "Notifications Mattermost"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr "%{link_start}Ajouter une commande barre oblique %{icon}%{link_end} à votre équipe Mattermost à l'aide des options listées ci-dessous."
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr "%{link_start}Activer les commandes barre oblique personnalisées %{icon}%{link_end} sur votre installation Mattermost."
+
msgid "MattermostService|Add to Mattermost"
msgstr "Ajouter à Mattermost"
@@ -28671,6 +28589,9 @@ msgstr "Saisissez le mot qui convient le mieux à votre équipe."
msgid "MattermostService|Install"
msgstr "Installer"
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr "Coller le jeton dans le champ %{strong_start}Jeton%{strong_end}."
+
msgid "MattermostService|Request URL"
msgstr "URL de la requête"
@@ -28683,6 +28604,9 @@ msgstr "Icône pour la réponse"
msgid "MattermostService|Response username"
msgstr "Nom d'utilisateur pour la réponse"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr "Cocher la case %{strong_start}Actif%{strong_end} puis sélectionner %{strong_start}Enregistrer les modifications%{strong_end} pour commencer à utiliser GitLab depuis Mattermost !"
+
msgid "MattermostService|Suggestions:"
msgstr "Suggestions :"
@@ -28989,6 +28913,102 @@ msgstr "%{member_name} vous a envoyé une invitation à rejoindre GitLab"
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr "Invitation à rejoindre le %{project_or_group} %{project_or_group_name}"
+msgid "MemberRoles|Actions"
+msgstr "Actions"
+
+msgid "MemberRoles|Add new role"
+msgstr "Ajouter un nouveau rôle"
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr "Autorise un accès administrateur aux rapports de vulnérabilités. « Lire les vulnérabilités » doit être sélectionné pour que cela prenne effet."
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr "Autorise un accès en lecture seule au code source."
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr "Autorise un accès en lecture seule aux rapports de vulnérabilités."
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr "Voulez-vous vraiment supprimer ce rôle ?"
+
+msgid "MemberRoles|Base role"
+msgstr "Rôle de base"
+
+msgid "MemberRoles|Base role to use as template"
+msgstr "Rôle de base à utiliser comme modèle"
+
+msgid "MemberRoles|Create new role"
+msgstr "Créer un nouveau rôle"
+
+msgid "MemberRoles|Custom roles"
+msgstr "Rôles personnalisés"
+
+msgid "MemberRoles|Delete role"
+msgstr "Supprimer le rôle"
+
+msgid "MemberRoles|Description"
+msgstr "Description"
+
+msgid "MemberRoles|Enter a short name."
+msgstr "Entrez un nom court."
+
+msgid "MemberRoles|Failed to create role."
+msgstr "Échec de la création du rôle."
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr "Échec de la suppression du rôle."
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr "Échec de la récupération des rôles."
+
+msgid "MemberRoles|ID"
+msgstr "ID"
+
+msgid "MemberRoles|Incident manager"
+msgstr "Gestionnaire d'incidents"
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr "Assurez-vous que le groupe a une licence Ultimate."
+
+msgid "MemberRoles|Name"
+msgstr "Nom"
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr "Aucun rôle personnalisé pour ce groupe"
+
+msgid "MemberRoles|Permissions"
+msgstr "Permissions"
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr "Nom du rôle"
+
+msgid "MemberRoles|Role successfully created."
+msgstr "Rôle créé avec succès."
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr "Rôle supprimé avec succès."
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr "Pour ajouter un nouveau rôle, sélectionnez un groupe, puis « Ajouter un nouveau rôle »."
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr "%{requirement} doit être activé pour pouvoir activer %{permission}."
@@ -29247,6 +29267,9 @@ msgstr "Message du commit de fusion"
msgid "Merge conflicts"
msgstr "Conflits de fusion"
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr "Détails de la fusion"
@@ -29679,9 +29702,6 @@ msgstr "Statistiques et rapports"
msgid "Metrics:"
msgstr "Métriques :"
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr "ne peut pas être avant l'heure de début starting_at"
-
msgid "Metrics|Create metric"
msgstr "Créer une métrique"
@@ -29778,6 +29798,9 @@ msgstr "Échec de l'enregistrement des paramètres d'intégration de Microsoft A
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr "Les paramètres d'intégration de Microsoft Azure ont été mis à jour avec succès."
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr "Synchroniser les attributions des droits d'accès au groupe à partir de Microsoft Azure lorsque la réponse SAML inclut une réclamation en lien avec un dépassement."
+
msgid "Microsoft|Tenant ID"
msgstr "ID du locataire"
@@ -30658,12 +30681,12 @@ msgstr "Quelles actions seront restreintes ?"
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr "Vous avez utilisé %{used_storage_percentage} du quota de stockage pour %{name_with_link} (%{current_size} sur %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
+msgstr "Vous avez utilisé %{used_storage_percentage} du quota de stockage pour %{namespace_name}"
+
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr "Vous avez utilisé %{used_storage_percentage} du quota de stockage pour %{name} (%{current_size} sur %{limit})."
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
-msgstr "Vous avez utilisé %{used_storage_percentage} %% du quota de stockage pour %{namespace_name}"
-
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
msgstr "Les utilisateurs en attente doivent être examinés et approuvés par un propriétaire de groupe. En savoir plus sur la %{user_caps_link_start}limitation du nombre d'utilisateurs%{link_end} et sur l'%{users_pending_approval_link_start}approbation d'utilisateurs en attente%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr "Analyse"
msgid "Navigation|Build"
msgstr "Compilation"
+msgid "Navigation|CI/CD settings"
+msgstr "Paramètres CI/CD"
+
msgid "Navigation|Code"
msgstr "Code"
@@ -30769,15 +30795,18 @@ msgstr "Les groupes que vous consultez souvent apparaîtront ici."
msgid "Navigation|Leave admin mode"
msgstr "Quitter le mode administrateur"
-msgid "Navigation|Main navigation"
-msgstr "Navigation principale"
-
msgid "Navigation|Manage"
msgstr "Gestion"
+msgid "Navigation|Merge requests settings"
+msgstr ""
+
msgid "Navigation|Monitor"
msgstr "Surveillance"
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr "Aucun groupe correspondant trouvé"
@@ -30796,12 +30825,18 @@ msgstr "Épinglé"
msgid "Navigation|Plan"
msgstr "Programmation"
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr "Projets"
msgid "Navigation|Projects you visit often will appear here."
msgstr "Les projets que vous consultez souvent apparaîtront ici."
+msgid "Navigation|Repository settings"
+msgstr "Paramètres du dépôt"
+
msgid "Navigation|Retrieving search results"
msgstr "Récupération des résultats de recherche"
@@ -30820,6 +30855,12 @@ msgstr "Une erreur s'est produite lors de la récupération des résultats de re
msgid "Navigation|Unpin item"
msgstr "Désépingler l'élément"
+msgid "Navigation|View all my groups"
+msgstr "Voir tous mes groupes"
+
+msgid "Navigation|View all my projects"
+msgstr "Voir tous mes projets"
+
msgid "Navigation|View all your groups"
msgstr "Voir tous vos groupes"
@@ -31044,9 +31085,6 @@ msgstr "Nouvelle réponse pour le ticket n°%{issue_iid} :"
msgid "New runners registration token has been generated!"
msgstr "Un nouveau jeton d'inscription de runners a été généré."
-msgid "New schedule"
-msgstr "Nouvelle planification"
-
msgid "New snippet"
msgstr "Nouvel extrait de code"
@@ -31254,6 +31292,9 @@ msgstr "Aucune itération"
msgid "No label"
msgstr "Aucun label"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "Aucun label avec un tel nom ou une telle description"
@@ -31278,6 +31319,12 @@ msgstr "Aucun résultat correspondant"
msgid "No matching results for \"%{query}\""
msgstr "Aucun résultat correspondant pour « %{query} »"
+msgid "No matching work item found."
+msgstr "Aucun élément de travail correspondant n'a été trouvé."
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr "Aucun élément de travail correspondant n'a été trouvé. Vérifiez que vous ajoutez un ID valide et que vous avez accès à l'élément."
+
msgid "No members found"
msgstr "Aucun membre trouvé"
@@ -31296,12 +31343,15 @@ msgstr "Aucun jalon"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr "%{max_issues} tickets au maximum peuvent être mis à jour en même temps"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr "Vous ne pouvez pas modifier plus de %{max_work_items} éléments de travail en même temps."
+
+msgid "No options found"
+msgstr "Aucune option trouvée"
+
msgid "No other labels with such name or description"
msgstr "Aucun autre label avec un tel nom ou une telle description"
-msgid "No panels matching properties %{opts}"
-msgstr "Aucun panneau ne correspond aux propriétés %{opts}"
-
msgid "No parent group"
msgstr "Aucun groupe parent"
@@ -31356,9 +31406,6 @@ msgstr "Aucun résultat trouvé."
msgid "No runner executable"
msgstr "Aucun runner exécutable"
-msgid "No schedules"
-msgstr "Aucune planification"
-
msgid "No service accounts"
msgstr "Aucun compte de service"
@@ -31410,6 +31457,12 @@ msgstr "Aucun événement de crochet Web"
msgid "No webhooks enabled. Select trigger events above."
msgstr "Aucun crochet Web activé. Sélectionnez les événements déclencheurs ci-dessus."
+msgid "No work item IDs provided."
+msgstr "Aucun ID d'élément de travail n'a été fourni."
+
+msgid "No work item found."
+msgstr "Aucun élément de travail n'a été trouvé."
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] "Pas de soucis, vous pouvez toujours utiliser toutes les fonctionnalités de %{strong}%{plan_name}%{strong_close} pour le moment. Vous avez %{remaining_days} jour pour renouveler votre abonnement."
@@ -32615,6 +32668,9 @@ msgstr "Un ou plusieurs de vos jetons d'accès personnels ont expiré."
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr "Un ou plusieurs de vos jetons d'accès personnels expireront dans %{days_to_expire} jours ou moins :"
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr "Seuls les membres du %{workspaceType} ayant le rôle suivant : %{permissions} peuvent voir ce(tte) %{issuableType} et recevoir des notifications à son sujet."
@@ -32642,9 +32698,6 @@ msgstr "Accessible uniquement aux %{membersPageLinkStart}membres du projet%{memb
msgid "Only active projects show up in the search and on the dashboard."
msgstr "Seuls les projets actifs remontent dans la recherche et sur le tableau de bord."
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr "Effectif uniquement lorsque le stockage distant est activé. Définissez sur 0 pour qu'il n'y ait aucune limite de taille."
-
msgid "Only include features new to your current subscription tier."
msgstr "N'inclure que les fonctionnalités nouvellement apparues dans l'édition correspondant à votre abonnement actuel."
@@ -32807,24 +32860,60 @@ msgstr "Options"
msgid "Ordered list"
msgstr "Liste numérotée"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "Entreprises"
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr "Une erreur s'est produite lors du chargement des groupes. Veuillez actualiser la page pour réessayer."
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr "Une erreur s'est produite lors du chargement des projets. Veuillez actualiser la page pour réessayer."
+msgid "Organization|Copy organization ID"
+msgstr "Copier l'ID de l'entreprise"
+
+msgid "Organization|Frequently visited groups"
+msgstr "Groupes fréquemment consultés"
+
+msgid "Organization|Frequently visited projects"
+msgstr "Projets fréquemment consultés"
+
+msgid "Organization|New organization"
+msgstr "Nouvelle entreprise"
+
+msgid "Organization|Org ID"
+msgstr "ID de l'organisation"
+
msgid "Organization|Organization navigation"
msgstr "Navigation dans l'organisation"
msgid "Organization|Organization overview"
msgstr "Présentation de l'organisation"
+msgid "Organization|Organizations"
+msgstr "Entreprises"
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr "Publique - l'organisation est accessible sans authentification."
+
msgid "Organization|Search or filter list"
msgstr "Organisation|Rechercher ou filtrer la liste"
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr "Membre orphelin"
@@ -33538,6 +33627,9 @@ msgstr "Pages"
msgid "Pages Domain"
msgstr "Domaine des pages"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr "La clé de certificat est trop longue (maximum %d octets)."
+
msgid "Pagination|First"
msgstr "Première"
@@ -33685,8 +33777,11 @@ msgstr "Chemin"
msgid "Path:"
msgstr "Chemin d'accès :"
-msgid "Paths to protect with rate limiting"
-msgstr "Chemins à protéger avec une limitation de fréquence"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
+msgstr ""
msgid "Pause"
msgstr "Pause"
@@ -33962,7 +34057,7 @@ msgid "Pipeline subscriptions trigger a new pipeline on the default branch of th
msgstr "Les abonnements de pipeline déclenchent un nouveau pipeline sur la branche par défaut de ce projet quand un pipeline se termine avec succès pour une nouvelle étiquette de la %{default_branch_docs} du projet souscrit."
msgid "Pipeline trigger tokens"
-msgstr ""
+msgstr "Jetons de déclenchement de pipeline"
msgid "Pipeline triggers"
msgstr "Déclencheurs de pipeline"
@@ -34132,9 +34227,6 @@ msgstr "Personnalisé (%{linkStart}En savoir plus%{linkEnd}.)"
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr "Un pipeline programmé démarre automatiquement à intervalles réguliers, par exemple de manière quotidienne ou hebdomadaire. Le pipeline : "
-msgid "PipelineSchedules|Activated"
-msgstr "Activé"
-
msgid "PipelineSchedules|Active"
msgstr "Actif"
@@ -34193,7 +34285,7 @@ msgid "PipelineSchedules|Next Run"
msgstr "Prochaine exécution"
msgid "PipelineSchedules|No pipeline schedules"
-msgstr ""
+msgstr "Aucun pipeline programmé"
msgid "PipelineSchedules|None"
msgstr "Aucun"
@@ -34249,12 +34341,6 @@ msgstr "Une erreur s'est produite lors de l'exécution de la planification de pi
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr "Une erreur s'est produite lors du changement de propriétaire de la planification de pipeline."
-msgid "PipelineSchedules|Variables"
-msgstr "Variables"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr "Assumer la propriété pour modifier"
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34705,6 +34791,9 @@ msgstr "Impossible de récupérer l'état du pipeline. Pour connaître les étap
msgid "Pipeline|Created"
msgstr "Créé"
+msgid "Pipeline|Created by"
+msgstr "Créé par"
+
msgid "Pipeline|Creating pipeline."
msgstr "Création du pipeline."
@@ -34757,7 +34846,7 @@ msgid "Pipeline|Raw text search is not currently supported. Please use the avail
msgstr "La recherche de texte brut n'est pas prise en charge actuellement. Veuillez utiliser les jetons de recherche disponibles."
msgid "Pipeline|Run again"
-msgstr ""
+msgstr "Réexécuter"
msgid "Pipeline|Run for branch name or tag"
msgstr "Exécuter pour une étiquette ou un nom de branche"
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr "Auteur du déclencheur"
-msgid "Pipeline|Triggerer"
-msgstr "Déclenché par"
-
msgid "Pipeline|Variables"
msgstr "Variables"
@@ -35353,9 +35439,6 @@ msgstr "Largeur de la mise en page"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "Doit être un nombre compris entre %{min} et %{max}"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr "Remarque : vous avez activé la nouvelle navigation, donc seul le thème Dark Mode change significativement l'apparence de GitLab."
-
msgid "Preferences|Preview"
msgstr "Aperçu"
@@ -35467,6 +35550,9 @@ msgstr "Discussion non résolue précédente"
msgid "Primary Action"
msgstr "Action principale"
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr "Imprimer en PDF"
@@ -35590,9 +35676,6 @@ msgstr "Retour aux tableaux de bord"
msgid "ProductAnalytics|Click Events"
msgstr "Événements de clic"
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr "URL de Clickhouse"
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr "Compare tous les événements les uns par rapport aux autres"
@@ -35608,9 +35691,6 @@ msgstr "Compare l'utilisation des fonctionnalités les unes par rapport aux autr
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr "Compare les vues de pages les unes aux autres pour toutes les pages"
-msgid "ProductAnalytics|Connection string"
-msgstr "Chaîne de connexion"
-
msgid "ProductAnalytics|Create a visualization"
msgstr "Créer une visualisation"
@@ -35618,7 +35698,7 @@ msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr "Création de l'instance de vos données d'analyse de produits..."
msgid "ProductAnalytics|Cube API key"
-msgstr ""
+msgstr "Clé d'API de Cube"
msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr "Informations sur la configuration des données d'analyse des produits pour collecter des données."
@@ -35647,9 +35727,6 @@ msgstr "Pour en savoir plus, consultez les %{linkStart}documents%{linkEnd}."
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr "Pour que le tableau de bord des données d'analyse des produits commence à afficher des données, vous devez ajouter le code de suivi des données d'analyse à votre projet."
-msgid "ProductAnalytics|Go back"
-msgstr "Retour"
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr "Nombre de sessions d'un utilisateur"
@@ -35710,9 +35787,12 @@ msgstr "Configurer les données d'analyse des produits"
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr "Configurez pour suivre la performance de votre produit et optimiser vos processus de produit et de développement."
-msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
+msgid "ProductAnalytics|Snowplow configurator connection string"
msgstr ""
+msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
+msgstr "La chaîne de connexion de votre instance de configurateur Snowplow."
+
msgid "ProductAnalytics|The host to send all tracking events to"
msgstr "L'hôte auquel envoyer tous les événements de suivi"
@@ -35734,11 +35814,8 @@ msgstr "Suivre des fonctionnalités spécifiques"
msgid "ProductAnalytics|Unique Users"
msgstr "Utilisateurs uniques"
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
-msgstr ""
+msgstr "Utilisée pour récupérer les données des tableaux de bord depuis l'instance Cube."
msgid "ProductAnalytics|User Sessions"
msgstr "Sessions utilisateurs"
@@ -35876,7 +35953,7 @@ msgid "Profiles|Add new email"
msgstr "Ajouter une nouvelle adresse de courriel"
msgid "Profiles|Add new mirror repository"
-msgstr ""
+msgstr "Ajouter un nouveau dépôt miroir"
msgid "Profiles|An error occurred while updating your username, please try again."
msgstr "Une erreur s'est produite lors de la mise à jour de votre nom d'utilisateur, veuillez réessayer."
@@ -35968,8 +36045,8 @@ msgstr "N'affichez pas les informations personnelles liées à l'activité sur v
msgid "Profiles|Edit Profile"
msgstr "Modifier le profil"
-msgid "Profiles|Email"
-msgstr "Courriel"
+msgid "Profiles|Email address"
+msgstr "Adresse de courriel"
msgid "Profiles|Email addresses"
msgstr "Adresses de courriel"
@@ -36403,9 +36480,6 @@ msgstr "Projet ou groupe"
msgid "Project order will not be saved as local storage is not available."
msgstr "L'ordre de classement des projets ne sera pas enregistré, car le stockage local n'est pas disponible."
-msgid "Project overview"
-msgstr "Vue d'ensemble du projet"
-
msgid "Project path"
msgstr "Chemin du projet"
@@ -36895,6 +36969,12 @@ msgstr "Feature flags"
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "Un outil souple pour développer des idées collaborativement et pour planifier le travail sur ce projet."
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr "Pour Gitaly, emplacement des données sur l'espace de stockage. Pour Gitaly Cluster, emplacement des données sur l'espace de stockage virtuel."
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr "Pour Gitaly, nom de l'espace de stockage qui stocke le dépôt. Pour Gitaly Cluster, nom de l'espace de stockage virtuel qui stocke le dépôt."
+
msgid "ProjectSettings|Forks"
msgstr "Bifurcations"
@@ -37030,6 +37110,9 @@ msgstr "Publique"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr "Publiez, stockez et visualisez les paquets dans un projet."
+msgid "ProjectSettings|Relative path:"
+msgstr "Chemin relatif :"
+
msgid "ProjectSettings|Releases"
msgstr "Releases"
@@ -37102,6 +37185,9 @@ msgstr "Le squashing n'est jamais effectué et la case à cocher est masquée."
msgid "ProjectSettings|Status checks must succeed"
msgstr "Les vérifications de statut doivent réussir"
+msgid "ProjectSettings|Storage name:"
+msgstr "Nom du stockage :"
+
msgid "ProjectSettings|Store custom configuration files."
msgstr "ParamètresProjet|Stockez les fichiers de configuration personnalisés."
@@ -37921,6 +38007,12 @@ msgstr "Approbation du propriétaire du code"
msgid "ProtectedBranch|Create wildcard"
msgstr "Créer un joker"
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr "Octroyer des droits de fusion à une branche protégée accorde également des autorisations élevées pour certaines fonctionnalités de CI/CD."
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr "Hérité : ce paramètre peut être modifié au niveau du groupe"
@@ -37970,7 +38062,7 @@ msgid "ProtectedBranch|Tag"
msgstr "Étiquette"
msgid "ProtectedBranch|There are currently no protected branches, to protect a branch start by creating a new one above."
-msgstr ""
+msgstr "Il n'y a actuellement aucune branche protégée. Pour protéger une branche, commencez par en créer une nouvelle ci-dessus."
msgid "ProtectedBranch|Toggle allowed to force push"
msgstr "Inverser l'autorisation de forcer les poussées"
@@ -37993,8 +38085,8 @@ msgstr "Voir les branches protégées comme règles de branche"
msgid "ProtectedBranch|What are protected branches?"
msgstr "Que sont les branches protégées ?"
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
-msgstr "Lorsque vous poussez directement vers la branche. Ne s'applique pas aux utilisateurs **Autorisés à pousser**. Les sections facultatives ne sont pas respectées."
+msgid "ProtectedBranch|What are the security implications?"
+msgstr "Quelles sont les implications en matière de sécurité ?"
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
msgstr "Vous ne pouvez ajouter que des groupes avec lesquels ce projet est partagé. %{learn_more_link}"
@@ -38048,12 +38140,15 @@ msgstr "Supprimer la règle de déploiement"
msgid "ProtectedEnvironments|Edit"
msgstr "Modifier"
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
-msgstr "Liste des environnements protégés (%{protectedEnvironmentsCount})"
-
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr "Le nombre d'approbations doit être compris entre 1 et 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr "Protéger un environnement"
+
+msgid "ProtectedEnvironments|Protected environments"
+msgstr "Environnements protégés"
+
msgid "ProtectedEnvironments|Remove approval rule"
msgstr "Supprimer la règle d'approbation"
@@ -38063,6 +38158,9 @@ msgstr "Nombre d'approbations requises"
msgid "ProtectedEnvironments|Save"
msgstr "Enregistrer"
+msgid "ProtectedEnvironments|Select users"
+msgstr "Sélectionner les utilisateurs"
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr "Définissez quels sont les groupes, niveaux d'accès ou utilisateurs requis pour approuver."
@@ -38081,6 +38179,9 @@ msgstr "Utilisateurs"
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} sera accessible en écriture aux développeurs. Voulez-vous vraiment continuer ?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr "Ajouter un nouvel environnement protégé"
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr "Tous les environnements dont les niveaux de déploiement sont indiqués ci-dessous sont protégés par un groupe parent. %{link_start}En savoir plus%{link_end}."
@@ -38138,9 +38239,6 @@ msgstr "Sélectionner un environnement"
msgid "ProtectedEnvironment|Select groups"
msgstr "Sélectionner des groupes"
-msgid "ProtectedEnvironment|Select users"
-msgstr "Sélectionnez des utilisateurs"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr "Il n'y a actuellement aucun environnement protégé."
@@ -38207,9 +38305,6 @@ msgstr "Instructions de provisionnement"
msgid "Provisioned by:"
msgstr "Fourni par :"
-msgid "Proxy support for this API is not available currently"
-msgstr "Le support du proxy pour cette API n'est pas disponible pour le moment"
-
msgid "Public"
msgstr "Public"
@@ -38570,9 +38665,6 @@ msgstr "Recevoir une notification de rapports d'abus par courriel."
msgid "Receive notifications about your own activity"
msgstr "Recevoir des notifications sur votre propre activité"
-msgid "Receive product marketing emails"
-msgstr "Recevoir des courriels commerciaux sur le produit"
-
msgid "Recent"
msgstr "Récent"
@@ -38713,35 +38805,11 @@ msgstr "envoyer des courriels aux utilisateurs"
msgid "RegistrationFeatures|use this feature"
msgstr "utiliser cette fonctionnalité"
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr "Voulez-vous vraiment ignorer cette étape ?"
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr "Activer les minutes de calcul gratuites"
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr "GitLab ne débitera pas votre carte, elle ne sera utilisée que pour la validation."
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr "Les pipelines utilisant les runners partagés de GitLab échoueront tant que vous n'aurez pas validé votre compte."
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr "Ignorer cela pour l'instant"
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr "Pour garder GitLab à l'abri du pourriel et des abus, nous vous demandons de vérifier votre identité avec un moyen de paiement valide, comme une carte de débit ou de crédit. Tant que ce n'est pas fait, vous ne pouvez pas utiliser les minutes de calcul gratuites pour construire votre application."
-
-msgid "RegistrationVerification|Validate account"
-msgstr "Valider le compte"
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr "Vérifiez votre identité"
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr "Oui, je voudrais l'ignorer"
+msgid "Registries enqueued to be resynced"
+msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
-msgstr "Vous pourrez toujours vérifier votre compte ultérieurement."
+msgid "Registries enqueued to be reverified"
+msgstr ""
msgid "Registry entry enqueued to be resynced"
msgstr "Entrée de registre mise en file d'attente pour être resynchronisée"
@@ -39075,9 +39143,6 @@ msgstr "Supprimer l'exemption de vérification par téléphone"
msgid "Remove priority"
msgstr "Supprimer la priorité"
-msgid "Remove report"
-msgstr "Supprimer le rapport"
-
msgid "Remove reviewer"
msgstr "Supprimer le relecteur"
@@ -39090,6 +39155,9 @@ msgstr "Supprimer l'adresse de courriel secondaire"
msgid "Remove spent time"
msgstr "Supprimer le temps passé"
+msgid "Remove summary"
+msgstr "Supprimer le résumé"
+
msgid "Remove time estimate"
msgstr "Supprimer l'estimation du temps"
@@ -39099,9 +39167,6 @@ msgstr "Supprimer l'avatar du sujet"
msgid "Remove user"
msgstr "Supprimer l'utilisateur"
-msgid "Remove user & report"
-msgstr "Supprimer l'utilisateur et le rapport"
-
msgid "Remove user from group"
msgstr "Supprimer l'utilisateur du groupe"
@@ -39381,12 +39446,6 @@ msgstr "Pourquoi signalez-vous cet utilisateur ?"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Signalée %{timeAgo} par %{reportedBy}"
-msgid "Reported by"
-msgstr "Signalé par"
-
-msgid "Reported by %{reporter}"
-msgstr "Signalé par %{reporter}"
-
msgid "Reporter"
msgstr "Rapporteur"
@@ -39693,9 +39752,6 @@ msgstr "Le recalcul de l'utilisation du dépôt a démarré"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr "Dépôt : %{counter_repositories} / Wikis  %{counter_wikis} / Artefacts de Construction : %{counter_build_artifacts} / Artefacts de Pipeline : %{counter_pipeline_artifacts} / LFS : %{counter_lfs_objects} / Extraits : %{counter_snippets} / Paquets : %{counter_packages} / Téléversements : %{counter_uploads}"
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "Sélectionner"
-
msgid "Request"
msgstr "Requête"
@@ -40109,6 +40165,9 @@ msgstr "L'analyse des causes profondes est une fonctionnalité qui analyse vos j
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr "Nom de la règle"
+
msgid "Rule name is already taken."
msgstr "Le nom de la règle est déjà pris."
@@ -40131,7 +40190,7 @@ msgid "Run CI/CD pipelines with Jenkins."
msgstr "Exécuter des pipelines CI/CD avec Jenkins."
msgid "Run again"
-msgstr "Exécuter à nouveau"
+msgstr "Réexécuter"
msgid "Run housekeeping"
msgstr "Démarrer la maintenance"
@@ -40459,7 +40518,7 @@ msgid "Runners|GitLab Runner must be installed before you can register a runner.
msgstr "GitLab Runner doit être installé pour que vous puissiez enregistrer un runner. %{linkStart}Comment puis-je installer GitLab Runner ?%{linkEnd}"
msgid "Runners|Go to %{groupLink} to enable them."
-msgstr ""
+msgstr "Allez sur %{groupLink} pour les activer."
msgid "Runners|Go to runners page"
msgstr "Aller à la page des runners"
@@ -40539,6 +40598,9 @@ msgstr "Les membres du %{type} peuvent enregistrer des runners"
msgid "Runners|Minor version upgrades are available."
msgstr "Des mises à jour de version mineure sont disponibles."
+msgid "Runners|Most recent failures"
+msgstr "Échecs les plus récents"
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr "S'il y en a plusieurs, les étiquettes doivent être séparées par une virgule. Par exemple : %{example}."
@@ -40825,11 +40887,11 @@ msgstr "Sélectionnez les projets à attribuer à ce runner"
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr "Sélectionnez votre runner préféré, puis choisissez sa capacité dans la console AWS CloudFormation."
-msgid "Runners|Shared runners are disabled in the group settings"
-msgstr "Les runners partagés sont désactivés dans les paramètres du groupe"
+msgid "Runners|Shared runners are disabled in the group settings."
+msgstr "Les runners partagés sont désactivés dans les paramètres du groupe."
msgid "Runners|Shared runners are disabled."
-msgstr ""
+msgstr "Les runners partagés sont désactivés."
msgid "Runners|Shared runners will be disabled for all projects and subgroups in this group. If you proceed, you must manually re-enable shared runners in the settings of each project and subgroup."
msgstr "Les runners partagés seront désactivés pour tous les projets et sous-groupes de ce groupe. Si vous continuez, vous devrez les réactiver manuellement dans les paramètres de chaque projet et sous-groupe."
@@ -40908,6 +40970,9 @@ msgstr "Le temps qu'il faut à un runner d'instance pour récupérer un job. Les
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr "L'ID unique pour chaque runner qui utilise cette configuration."
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr "Il n'y a pas d'échecs de runner récents pour vos runners d'instance. Les messages d'erreur s'afficheront ici si les runners échouent."
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr "Il n'y a aucun runner qui exécute des jobs en ce moment même. Les runners actifs s'afficheront ici au fur et à mesure qu'ils trouveront des jobs."
@@ -41117,6 +41182,9 @@ msgstr "Pour autoriser %{strongOpen}%{group_name}%{strongClose} à gérer votre
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "Le SSO de votre organisation a été connecté à votre compte GitLab"
+msgid "SBOMs last updated"
+msgstr "Dernière mise à jour des SBOM"
+
msgid "SCIM|SCIM Token"
msgstr "Jeton SCIM"
@@ -41225,9 +41293,6 @@ msgstr "Enregistrer la note interne"
msgid "Save password"
msgstr "Enregistrer le mot de passe"
-msgid "Save pipeline schedule"
-msgstr "Sauvegarder la planification du pipeline"
-
msgid "Saving"
msgstr "Sauvegarde"
@@ -41240,11 +41305,11 @@ msgstr "Fuseau horaire de : %{hostname}"
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr "%{period} %{days} à %{time} %{timezoneLabel} %{timezone}"
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
-msgstr ""
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
+msgstr "Actions %{rules} pour %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
-msgstr ""
+msgstr "%{rules} chaque fois qu'un pipeline s'exécute pour %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
msgid "ScanExecutionPolicy|A runner will be selected automatically from those available."
msgstr "Un runner sera sélectionné automatiquement parmi ceux disponibles."
@@ -41366,11 +41431,14 @@ msgstr "Le critère d'âge ne peut être ajouté que pour des vulnérabilités p
msgid "ScanResultPolicy|Age is:"
msgstr "L’âge est :"
-msgid "ScanResultPolicy|Block users from unprotecting branches"
-msgstr ""
+msgid "ScanResultPolicy|Attribute is:"
+msgstr "L'attribut est :"
-msgid "ScanResultPolicy|Choose an option"
-msgstr "Choisir une option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr "Attribut :"
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
+msgstr "Les attributs sont automatiquement appliqués par les scanners"
msgid "ScanResultPolicy|Choose criteria type"
msgstr "Choisir un type de critères"
@@ -41384,6 +41452,24 @@ msgstr "Variables CI personnalisées"
msgid "ScanResultPolicy|Except"
msgstr "Sauf"
+msgid "ScanResultPolicy|False positive"
+msgstr "Faux positif"
+
+msgid "ScanResultPolicy|Fix available"
+msgstr "Correctif disponible"
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr "Le correctif disponible ne s'applique qu'à l'analyse des conteneurs et des dépendances"
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr "Est"
+
+msgid "ScanResultPolicy|Is not"
+msgstr "N'est pas"
+
msgid "ScanResultPolicy|License is:"
msgstr "La licence est :"
@@ -41396,8 +41482,8 @@ msgstr "Correspondant à"
msgid "ScanResultPolicy|New age"
msgstr "Nouvel âge"
-msgid "ScanResultPolicy|New severity"
-msgstr "Nouvelle gravité"
+msgid "ScanResultPolicy|New attribute"
+msgstr "Nouvel attribut"
msgid "ScanResultPolicy|New status"
msgstr "Nouveau statut"
@@ -41408,18 +41494,24 @@ msgstr "Nouvellement détectées"
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr "Un seul critère d'âge est autorisé"
-msgid "ScanResultPolicy|Only 1 severity is allowed"
-msgstr "Une seule gravité est autorisée"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
+msgstr "Seuls 2 critères d'attribut sont autorisés"
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
msgstr "Seuls 2 critères de statut sont autorisés"
msgid "ScanResultPolicy|Override project approval settings"
-msgstr ""
+msgstr "Remplacer les paramètres d'approbation du projet"
msgid "ScanResultPolicy|Pre-existing"
msgstr "Préexistantes"
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr "Paramètres des branches protégées"
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr "Sélectionner un type d'analyse avant d'ajouter des critères"
@@ -41447,9 +41539,18 @@ msgstr "PolitiqueRésultatAcquisition|Quand %{scanType} %{scanners} s'exécute(n
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr "PolitiqueRésultatAcquisition|Lorsqu'une analyse %{scanType} dans une requête de fusion ouverte cible les %{branches} %{branchExceptions} et que les licences correspondent à tous les critères suivants :"
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr "PolitiqueRésultatAcquisition|Lorsque %{scanners} rencontrent les conditions spécifiées du scanner dans une requête de fusion ouverte ciblant %{branches} %{branchExceptions} et correspondant à %{boldDescription} des critères suivants"
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr "statut de licence"
@@ -41561,6 +41662,9 @@ msgstr "Rechercher un groupe"
msgid "Search an environment spec"
msgstr "Rechercher une spécification d'environnement"
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "Rechercher des personnes assignées"
@@ -41630,15 +41734,12 @@ msgstr "Rechercher des jalons"
msgid "Search or filter commits"
msgstr "Rechercher ou filtrer les validations"
-msgid "Search or filter results"
-msgstr "Rechercher ou filtrer les résultats"
-
-msgid "Search or filter results..."
-msgstr "Rechercher ou filtrer les résultats…"
-
msgid "Search or filter results…"
msgstr "Rechercher ou filtrer les résultats…"
+msgid "Search or go to…"
+msgstr "Rechercher ou aller à…"
+
msgid "Search page"
msgstr "Rechercher dans la page"
@@ -41865,6 +41966,9 @@ msgstr "Configuration de la sécurité"
msgid "Security dashboard"
msgstr "Tableau de bord de sécurité"
+msgid "Security reports last updated"
+msgstr "Dernière mise à jour des rapports de sécurité"
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr "Une approbation de requête de fusion est requise lorsque la couverture de tests diminue."
@@ -42021,6 +42125,12 @@ msgstr "et "
msgid "SecurityOrchestration| and all the following apply:"
msgstr "et que toutes les conditions suivantes s'appliquent :"
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr " ou "
@@ -42030,8 +42140,14 @@ msgstr " qui est %{licenseState} et est"
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr "%{agent} pour %{namespaces}"
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
-msgstr "%{cadence} sur %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr "%{branchName}"
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr "%{branchName} (dans %{codeStart}%{fullPath}%{codeEnd})"
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
+msgstr "%{cadence} sur %{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
msgstr "%{licenses} et %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr "Une erreur s'est produite lors de la récupération des politiques de rÃ
msgid "SecurityOrchestration|And scans to be performed:"
msgstr "Et analyses à effectuer :"
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr "Voulez-vous vraiment supprimer cette politique ? Cette action ne pourra pas être annulée."
@@ -42159,8 +42278,8 @@ msgstr "Activée"
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr "Forcer la sécurité pour ce projet. %{linkStart}Plus d'informations.%{linkEnd}"
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
-msgstr "Chaque fois qu'un pipeline s'exécute pour %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
+msgstr "Chaque fois qu'un pipeline s'exécute pour %{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|Exceptions"
msgstr "Exceptions"
@@ -42171,12 +42290,18 @@ msgstr "Échec du chargement des agents du cluster."
msgid "SecurityOrchestration|Failed to load images."
msgstr "Le chargement des images a échoué."
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr "Pour les groupes nombreux, l'application des modifications de la stratégie aux requêtes de fusion préexistantes peut connaître un délai important. Les modifications de stratégie s'appliquent en général presque immédiatement pour les requêtes de fusion nouvellement créées."
msgid "SecurityOrchestration|Groups"
msgstr "Groupes"
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr "Masquer les branches supplémentaires"
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr "Si un scanner quelconque trouve une vulnérabilité critique récemment détectée dans une requête de fusion ouverte ciblant la branche maître, alors exiger deux approbations de tout membre de l'Appli sécurité."
@@ -42443,6 +42568,9 @@ msgstr "Utilisez une stratégie de résultats d'analyse pour créer des règles
msgid "SecurityOrchestration|View policy project"
msgstr "Afficher le projet de politique"
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr "Vulnérabilités %{vulnerabilityStates}."
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr "Les vulnérabilités sont %{vulnerabilityStates}."
@@ -42455,14 +42583,14 @@ msgstr "L'âge de la vulnérabilité est inférieur à %{vulnerabilityAge}."
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr "L'âge de la vulnérabilité nécessite des statuts de vulnérabilité existants (détectés, confirmés, résolus ou rejetés)"
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
-msgstr "Lorsque les %{scanners} de %{vulnerability} %{vulnerabilitiesAllowed} dans une requête de fusion ouverte, %{targeting}%{branches}, %{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
+msgstr "Lorsque les %{scanners} de %{vulnerability} %{vulnerabilitiesAllowed} dans une requête de fusion ouverte %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr "Lorsque le scanner de licences trouve toute licence hormis %{licenses}%{detection} dans une requête de fusion ouverte %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "Lorsque le scanner de licences trouve une licence à l'exception de %{licenses}%{detection} dans une requête de fusion ouverte %{targeting}%{branches}%{branchExceptionsString}"
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr "Lorsque le scanner de licences trouve toute licence correspondant à %{licenses}%{detection} dans une requête de fusion ouverte %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "Lorsque le scanner de licences trouve une licence correspondant à %{licenses}%{detection} dans une requête de fusion ouverte %{targeting}%{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|With the following customized CI variables:"
msgstr "Avec les variables CI personnalisées suivantes :"
@@ -42491,14 +42619,20 @@ msgstr "toute branche protégée"
msgid "SecurityOrchestration|any security scanner finds"
msgstr "tout scanner de sécurité trouve"
+msgid "SecurityOrchestration|are false positives"
+msgstr "sont des faux positifs"
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr "ne sont pas des faux positifs"
+
msgid "SecurityOrchestration|branch"
msgstr "branche"
msgid "SecurityOrchestration|branches"
msgstr "branches"
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
-msgstr "par l'agent nommé %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
+msgstr "par l'agent nommé %{agents} %{cadence}%{branchExceptionsString}"
msgid "SecurityOrchestration|group level branch input"
msgstr "saisie de branche au niveau du groupe"
@@ -42506,6 +42640,12 @@ msgstr "saisie de branche au niveau du groupe"
msgid "SecurityOrchestration|group level branch selector"
msgstr "sélecteur de branche au niveau du groupe"
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr "plus de %{allowed}"
@@ -42575,9 +42715,6 @@ msgstr "Ajouter un commentaire (obligatoire)"
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr "Ajouter un commentaire ou une raison pour le rejet"
-msgid "SecurityReports|Add comment & dismiss"
-msgstr "Ajouter un commentaire et rejeter"
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "Ajoutez ou supprimez des projets à superviser dans la zone de sécurité. Les résultats des projets inclus dans cette liste seront présentés sur le tableau de bord de sécurité et dans le rapport de vulnérabilités."
@@ -42591,7 +42728,7 @@ msgid "SecurityReports|All clusters"
msgstr "Tous les clusters"
msgid "SecurityReports|All dismissal reasons"
-msgstr ""
+msgstr "Toutes les raisons de rejet"
msgid "SecurityReports|All images"
msgstr "Toutes les images"
@@ -42632,6 +42769,9 @@ msgstr "Commentaire modifié sur « %{vulnerabilityName} »"
msgid "SecurityReports|Configure security testing"
msgstr "Configurer le test de sécurité"
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr "Créer un ticket"
@@ -42647,9 +42787,15 @@ msgstr "Détection"
msgid "SecurityReports|Development vulnerabilities"
msgstr "Vulnérabilités de développement"
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "Rejeter la vulnérabilité"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "« %{vulnerabilityName} » rejetée"
@@ -42657,10 +42803,10 @@ msgid "SecurityReports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismi
msgstr "« %{vulnerabilityName} » rejetée. Désactivez le masquage des rejets pour l'afficher."
msgid "SecurityReports|Dismissed (all reasons)"
-msgstr ""
+msgstr "Rejeté (toutes raisons)"
msgid "SecurityReports|Dismissed as..."
-msgstr ""
+msgstr "Rejeté en tant que..."
msgid "SecurityReports|Does not have issue"
msgstr "N'a pas de ticket"
@@ -42680,6 +42826,9 @@ msgstr "Télécharger les URL analysées"
msgid "SecurityReports|Download the patch to apply it manually"
msgstr "Télécharger le correctif pour l'appliquer manuellement"
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr "Il est possible que vous n'ayez pas les permissions nécessaires pour voir ce tableau de bord, ou que celui-ci n'ait pas été configuré. Veuillez vérifier vos permissions avec votre administrateur ou vos configurations de tableau de bord pour pouvoir continuer."
@@ -42797,9 +42946,6 @@ msgstr "Le rapport a expiré"
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr "Les résultats montrent les vulnérabilités introduites par la requête de fusion, en plus des vulnérabilités existantes du dernier pipeline réussi dans la branche par défaut de votre projet."
-msgid "SecurityReports|Save comment"
-msgstr "Enregistrer le commentaire"
-
msgid "SecurityReports|Scan details"
msgstr "Détails de l'analyse"
@@ -42844,8 +42990,8 @@ msgstr "Détection toujours active"
msgid "SecurityReports|Submit vulnerability"
msgstr "Soumettre une vulnérabilité"
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
-msgstr "Le rapport de vulnérabilités montre les résultats des analyses réussies sur la branche par défaut de votre projet, les enregistrements des vulnérabilités ajoutées manuellement et les vulnérabilités trouvées à partir de l'analyse d'environnements opérationnels. %{linkStart}En savoir plus.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
msgstr "Les rapports de sécurité suivants signalent la découverte d'une ou plusieurs vulnérabilités qui n'ont pas pu être traitées et qui n'ont pas été enregistrées. Pour étudier un rapport, téléchargez les artefacts issus du job. Assurez-vous que le rapport de sécurité est bien conforme au %{helpPageLinkStart}schéma JSON%{helpPageLinkEnd} approprié."
@@ -43052,7 +43198,7 @@ msgid "Select color"
msgstr "Sélectionner une couleur"
msgid "Select confidentiality"
-msgstr ""
+msgstr "Sélectionnez la confidentialité"
msgid "Select default branch"
msgstr "Sélectionner la branche par défaut"
@@ -43192,9 +43338,6 @@ msgstr "Envoyez des courriels au format multipart (HTML et texte brut). Décoche
msgid "Send email notification"
msgstr "Envoyer une notification par courriel"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "Envoyer des courriels pour contribuer à guider les nouveaux utilisateurs tout au long du processus d'intégration."
-
msgid "Send emails to users upon account deactivation."
msgstr "Envoyer des courriels aux utilisateurs lors de la désactivation de compte."
@@ -43264,6 +43407,9 @@ msgstr "Les clés de Comptes de Service autorisent GitLab à déployer votre pro
msgid "Service Desk"
msgstr "Service d'assistance"
+msgid "Service Desk Ticket"
+msgstr "Ticket du module Service Desk"
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr "Service Desk permet à l'utilisateur de créer des tickets sur votre instance GitLab sans qu'il ait besoin d'avoir son propre compte. Une adresse de courriel est fournie pour que les utilisateurs finaux créent des tickets sur un projet. Les réponses peuvent être envoyées soit via l'interface de GitLab, soit par courriel. Les utilisateurs finaux ne voient les fils de discussion qu'au moyen des courriels."
@@ -43288,12 +43434,24 @@ msgstr "L'utilisateur n'a pas l'autorisation de créer un compte de service dans
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr "L'utilisateur n'a pas l'autorisation de créer un compte de service."
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr "%{customEmail} avec l'hôte SMTP %{smtpAddress} est %{badgeStart}vérifié%{badgeEnd}"
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr "La connexion avec l'hôte spécifié est impossible ou une erreur SSL s'est produite."
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr "Impossible de créer une adresse de courriel personnalisée"
msgid "ServiceDesk|Cannot update custom email"
msgstr "Impossible de mettre à jour l'adresse de courriel personnalisée"
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr "Vérifiez vos paramètres de transfert et assurez-vous que l'expéditeur du courriel original apparaît toujours dans l'en-tête De."
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr "Les ports habituels sont 587 lorsque TLS est utilisé et 25 lorsque ce n'est pas le cas."
@@ -43301,10 +43459,10 @@ msgid "ServiceDesk|Configure a custom email address"
msgstr "BureauService|Configurer une adresse e-mail personnalisée"
msgid "ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials."
-msgstr ""
+msgstr "Connectez une adresse de courriel personnalisée que vos clients peuvent utiliser pour créer des tickets destinés au Service Desk. Transférez tous les courriels destinés à votre adresse de courriel personnalisée à l'adresse de courriel Service Desk de ce projet. GitLab transférera des courriels au Service Desk à partir de l'adresse personnalisée en votre nom en utilisant vos identifiants SMTP."
msgid "ServiceDesk|Copy Service Desk email address"
-msgstr ""
+msgstr "Copier l'adresse de courriel du service d'assistance"
msgid "ServiceDesk|Custom email address"
msgstr "Adresse de courriel personnalisée"
@@ -43321,65 +43479,104 @@ msgstr "La vérification de l'adresse de courriel personnalisée a déjà été
msgid "ServiceDesk|Custom email already exists"
msgstr "Une adresse de courriel personnalisée existe déjà"
+msgid "ServiceDesk|Custom email disabled."
+msgstr "Adresse de courriel personnalisée désactivée."
+
msgid "ServiceDesk|Custom email does not exist"
msgstr "L'adresse de courriel personnalisée n'existe pas"
+msgid "ServiceDesk|Custom email enabled."
+msgstr "Adresse de courriel personnalisée activée."
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
-msgstr ""
+msgstr "Une adresse de courriel personnalisée est requise et doit être valide."
msgid "ServiceDesk|Email address your customers can use to send support requests. It must support sub-addressing."
-msgstr ""
+msgstr "Adresse de courriel à laquelle vos clients peuvent envoyer les demandes de support. Elle doit prendre en charge le sous-adressage."
msgid "ServiceDesk|Enable Service Desk"
msgstr "Activer le Service d'Assistance"
+msgid "ServiceDesk|Enable custom email address"
+msgstr "Activer l'adresse de courriel personnalisée"
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr "Pour obtenir de l'aide sur la mise en place du Service d'Assistance sur votre instance, veuillez contacter un administrateur."
+msgid "ServiceDesk|Incorrect From header"
+msgstr "En-tête De incorrect"
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr "Jeton de vérification incorrect"
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr "Identifiants non valides"
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr "Les tickets créés à partir des courriels du Service d'Assistance apparaîtront ici. Chaque commentaire devient un élément de la discussion par courriel."
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr "Minimum 8 caractères."
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr "Vous pouvez également réinitialiser et connecter une nouvelle adresse de courriel personnalisée à ce module Service Desk."
+
msgid "ServiceDesk|Parameters missing"
msgstr "Paramètres manquants"
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr "BureauService|Veuillez partager vos commentaires sur cette fonctionnalité dans le %{linkStart}ticket Commentaires%{linkEnd}"
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr "Veuillez réessayer. Vérifiez les paramètres de transfert des courriels et les identifiants, puis relancez la vérification."
+
+msgid "ServiceDesk|Reset custom email"
+msgstr "Réinitialiser l'adresse de courriel personnalisée"
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr "Réinitialiser l'adresse de courriel personnalisée et supprimer les identifiants"
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr "Réinitialisez l'adresse de courriel personnalisée."
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
-msgstr ""
+msgstr "L'adresse SMTP est requise et doit pouvoir être résolue."
msgid "ServiceDesk|SMTP host"
msgstr "Hôte SMTP"
+msgid "ServiceDesk|SMTP host issue"
+msgstr "Problème d'hôte SMTP"
+
msgid "ServiceDesk|SMTP password"
msgstr "Mot de passe SMTP"
msgid "ServiceDesk|SMTP password is required and must be at least 8 characters long."
-msgstr ""
+msgstr "Le mot de passe SMTP est requis et doit comporter au moins 8 caractères."
msgid "ServiceDesk|SMTP port"
msgstr "Port SMTP"
msgid "ServiceDesk|SMTP port is required and must be a port number larger than 0."
-msgstr ""
+msgstr "Le port SMTP est requis et doit être un numéro de port supérieur à 0."
msgid "ServiceDesk|SMTP username"
msgstr "Nom d'utilisateur SMTP"
msgid "ServiceDesk|SMTP username is required."
-msgstr ""
+msgstr "Le nom d’utilisateur SMTP est requis."
msgid "ServiceDesk|Save and test connection"
msgstr "Enregistrer et tester la connexion"
msgid "ServiceDesk|Saved custom email address and started verification."
-msgstr ""
+msgstr "L'adresse de courriel personnalisée a été enregistrée et la vérification a commencé."
msgid "ServiceDesk|Service Desk email address to forward emails to"
-msgstr ""
+msgstr "Adresse de courriel du service d'assistance vers laquelle rediriger les courriels"
msgid "ServiceDesk|Service Desk is not enabled"
msgstr "Le Service d'Assistance n'est pas activé"
@@ -43393,15 +43590,45 @@ msgstr "Configuration du Service Desk absente"
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr "Paramètre du Service Desk ou objet de vérification manquant"
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr "Les identifiants fournis (nom d'utilisateur et mot de passe) ont été rejetés par le serveur SMTP."
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr "Le courriel reçu ne contenait pas le jeton de vérification qui avait été envoyé à votre adresse de courriel."
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr "Le courriel de vérification n'a pas été reçu à temps. Un délai de 30 minutes est nécessaire pour que les courriels de vérification apparaissent dans le module Service Desk de votre instance. Vérifiez que vous avez correctement configuré le transfert des courriels."
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr "Pour activer le Service d'Assistance sur cette instance, un administrateur de celle-ci doit au préalable définir une adresse de courriel entrant."
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr "Afin d'utiliser une adresse de courriel personnalisée pour ce module Service Desk, vous devez à nouveau configurer et vérifier une adresse de courriel."
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr "Utilisez le Service d'Assistance pour être en contact avec vos utilisateurs et proposer un support client par courriel directement dans GitLab"
msgid "ServiceDesk|User cannot manage project."
msgstr "L'utilisateur ne peut pas gérer le projet."
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr "Le courriel de vérification n'a pas été reçu à temps"
+
+msgid "ServiceDesk|Verification failed"
+msgstr "La vérification a échoué"
+
+msgid "ServiceDesk|Verification started"
+msgstr "La vérification a commencé"
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr "Vérifier %{customEmail} avec l'hôte SMTP %{smtpAddress} :"
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr "Lorsque cette option est activée, les courriels Service Desk sont envoyés à l'aide des identifiants fournis."
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr "Vous êtes sur le point de %{strongStart}désactiver l’adresse de courriel personnalisée%{strongEnd} %{customEmail} %{strongStart}et de supprimer ses identifiants%{strongEnd}."
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr "Vos utilisateurs peuvent envoyer des courriels à cette adresse :"
@@ -43429,6 +43656,9 @@ msgstr "ID de session"
msgid "Session duration (minutes)"
msgstr "Durée de session (minutes)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr "Impossible de vérifier l'utilisateur. Une erreur s'est produite lors du chargement du défi de vérification de l'utilisateur. Actualisez pour réessayer."
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "Définir %{epic_ref} comme épopée parent."
@@ -43549,6 +43779,9 @@ msgstr "Estimation du temps définie à %{time_estimate}."
msgid "Set to 0 for no size limit."
msgstr "Définir à 0 pour qu'il n'y ait pas de limite."
+msgid "Set to 0 to disable timeout."
+msgstr "Définir à 0 pour désactiver le délai d'expiration."
+
msgid "Set to auto-merge"
msgstr "Configurer la fusion automatique"
@@ -43627,6 +43860,9 @@ msgstr "Votre statut est réinitialisé le %{date}."
msgid "Sets %{epic_ref} as parent epic."
msgstr "Définit %{epic_ref} comme épopée parente."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr "Définit l'état de santé sur %{health_status}."
@@ -44462,6 +44698,9 @@ msgstr "Quelqu'un s'est connecté à votre compte %{host} à partir d'un nouvel
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Quelqu'un, en espérant qu'il s'agit de vous, a demandé la réinitialisation du mot de passe de votre compte GitLab sur %{link_to_gitlab}."
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "Une erreur s'est produite"
@@ -44555,9 +44794,6 @@ msgstr "Une erreur s'est produite lors de la récupération des modifications de
msgid "Something went wrong while fetching details"
msgstr "Une erreur s'est produite lors de la récupération des détails"
-msgid "Something went wrong while fetching latest comments."
-msgstr "Une erreur s'est produite lors de la récupération des derniers commentaires."
-
msgid "Something went wrong while fetching projects"
msgstr "Une erreur s'est produite lors de la récupération des projets"
@@ -45222,7 +45458,7 @@ msgid "StatusCheck|Apply this status check to all branches or a specific protect
msgstr "Appliquer cette vérification d'état à toutes les branches ou à une branche protégée spécifique."
msgid "StatusCheck|Check for a status response in merge requests. %{linkStart}Learn more%{linkEnd}."
-msgstr ""
+msgstr "Vérifiez la réponse relative à un statut dans les requêtes de fusion. %{linkStart}En savoir plus%{linkEnd}."
msgid "StatusCheck|Examples: QA, Security."
msgstr "Exemples : QA, sécurité."
@@ -45483,7 +45719,7 @@ msgid "Subscription deletion failed."
msgstr "La suppression de l'abonnement a échoué."
msgid "Subscription for %{subscription} will be removed. Do you want to continue?"
-msgstr ""
+msgstr "L'abonnement à %{subscription} sera supprimé. Voulez-vous continuer ?"
msgid "Subscription service outage"
msgstr "Panne du service abonnement"
@@ -45506,6 +45742,18 @@ msgstr "Exporter le fichier d'utilisation de licence"
msgid "SubscriptionBanner|Upload new license"
msgstr "Téléverser une nouvelle licence"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr "Si vous souhaitez ajouter plus de sièges, mettre à niveau votre forfait ou acheter des produits supplémentaires, contactez votre représentant commercial GitLab."
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr "Il s'agit d'un abonnement personnalisé géré par l'équipe commerciale de GitLab"
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr "Pour apporter des modifications à un abonnement en lecture seule ou acheter des produits supplémentaires, contactez votre partenaire GitLab."
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr "Votre abonnement est en mode lecture seule"
+
msgid "SubscriptionTable|Add seats"
msgstr "Ajouter des sièges"
@@ -45653,6 +45901,9 @@ msgstr "Désactivé avec succès"
msgid "Successfully deleted WebAuthn device."
msgstr "L'appareil WebAuthn a été supprimé avec succès."
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "Courriel supprimé avec succès."
@@ -45671,6 +45922,9 @@ msgstr "Débloqué avec succès"
msgid "Successfully unblocked"
msgstr "Débloqué avec succès"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr "ID dont la liaison a échoué : %{item_ids}."
+
msgid "Successfully unlocked"
msgstr "Déverrouillé avec succès"
@@ -46332,6 +46586,9 @@ msgstr "Une erreur s'est produite lors de la communication avec GitLab Duo Chat.
msgid "TanukiBot|What is a fork?"
msgstr "Qu'est-ce qu'une bifurcation ?"
+msgid "Targe branch"
+msgstr "Branche cible"
+
msgid "Target"
msgstr "Cible"
@@ -46344,8 +46601,14 @@ msgstr "Chemin cible"
msgid "Target branch"
msgstr "Branche cible"
-msgid "Target branch or tag"
-msgstr "Branche ou étiquette cible"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
+msgstr ""
msgid "Target branch: %{target_branch}"
msgstr "Branche cible : %{target_branch}"
@@ -46916,7 +47179,7 @@ msgid "The current user is not authorized to create the pipeline schedule"
msgstr "L'utilisateur actuel n'est pas autorisé à créer la planification de pipeline"
msgid "The current user is not authorized to set pipeline schedule variables"
-msgstr ""
+msgstr "L'utilisateur actuel n'est pas autorisé à définir les variables de programmation de pipeline"
msgid "The current user is not authorized to update the pipeline schedule"
msgstr "L'utilisateur actuel n'est pas autorisé à mettre à jour planification de pipeline"
@@ -47177,9 +47440,6 @@ msgstr "La page n'a pas pu être affichée, car le délai d'attente a expiré."
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr "L'épopée parente est confidentielle et ne peut contenir que des épopées et des tickets confidentiels"
-msgid "The parsed YAML is too big"
-msgstr "Le YAML analysé est trop volumineux"
-
msgid "The password for the Jenkins server."
msgstr "Le mot de passe du serveur Jenkins."
@@ -47354,6 +47614,9 @@ msgstr "La vulnérabilité n'est plus détectée. Vérifiez qu'elle a été remÃ
msgid "There are currently no mirrored repositories."
msgstr "Il n'y a actuellement aucun dépôt mis en miroir."
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "Il y a des conflits de fusion"
@@ -47372,9 +47635,6 @@ msgstr "Aucune clé SSH n'a accès à votre compte."
msgid "There are no Spam Logs"
msgstr "Il n'y a pas de journaux d'indésirables"
-msgid "There are no abuse reports!"
-msgstr "Il n'y a aucun rapport d'abus !"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr "Il n'y a aucune règle d'approbation pour le paramètre « represent_as » donné. Utilisez plutôt un nom d'utilisateur/de groupe/de rôle valide."
@@ -47547,7 +47807,7 @@ msgid "There was a problem fetching the latest pipeline status."
msgstr "Une erreur s'est produite lors de la récupération de l'état du dernier pipeline."
msgid "There was a problem fetching the pipeline stage."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération de l'étape du pipeline."
msgid "There was a problem fetching the pipeline stages."
msgstr "Une erreur s'est produite lors de la récupération des étapes du pipeline."
@@ -47624,6 +47884,9 @@ msgstr "Une erreur s'est produite lors de la récupération des labels les mieux
msgid "There was an error fetching the variables."
msgstr "Une erreur s'est produite lors de la récupération des variables."
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr "Une erreur s'est produite lors de la récupération des étapes de l'analyse des chaînes de valeur."
@@ -47708,11 +47971,14 @@ msgstr "Une erreur s'est produite avec le reCAPTCHA. Veuillez le résoudre à no
msgid "There was an summarizing your pending comments."
msgstr "Il y avait un résumé de vos commentaires en attente."
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr "Une requête de fusion est déjà ouverte pour les branches suivantes : %{link_to_mr}. Sélectionnez une autre branche source ou cible."
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr "Ces dates affectent la façon dont vos épopées apparaissent sur la feuille de route. Fixez une date ou choisissez de l'hériter des jalons attribués aux tickets de cette épopée."
msgid "These examples show common methods of triggering a pipeline with a pipeline trigger token. The URL and ID for this project is prefilled."
-msgstr ""
+msgstr "Ces exemples montrent des méthodes courantes pour déclencher un pipeline avec un jeton de déclenchement de pipeline. L'URL et l'ID de ce projet sont préremplis."
msgid "These existing issues have a similar title. It might be better to comment there instead of creating another similar issue."
msgstr "Ces tickets existants ont presque le même titre. Il serait peut-être préférable d'y ajouter un commentaire plutôt que de créer un autre ticket similaire."
@@ -48212,9 +48478,15 @@ msgstr "Cette requête de fusion est issue d'un projet privé converti en projet
msgid "This merge request is from an internal project to a public project."
msgstr "Cette requête de fusion est issue d'un projet interne converti en projet public."
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Cette requête de fusion est verrouillée."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr "Cette requête de fusion a été fusionnée. Pour appliquer cette suggestion, modifiez ce fichier directement."
@@ -48233,11 +48505,11 @@ msgstr "Ce pipeline fait usage d'une configuration CI/CD prédéfinie activée p
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr "Ce pipeline fait usage d'une configuration CI/CD prédéfinie activée par Auto DevOps."
-msgid "This pipeline was triggered by a schedule"
-msgstr "Ce pipeline a été déclenché par une programmation"
+msgid "This pipeline was created by a schedule"
+msgstr ""
-msgid "This pipeline was triggered by a schedule."
-msgstr "Ce pipeline a été déclenché par une planification."
+msgid "This pipeline was created by a schedule."
+msgstr ""
msgid "This process deletes the project repository and all related resources."
msgstr "Ce processus supprime le dépôt du projet et toutes les ressources associées."
@@ -48386,8 +48658,8 @@ msgstr "Cet utilisateur est l'auteur de l'élément suivant : %{workItemType}."
msgid "This variable value does not meet the masking requirements."
msgstr "Cette valeur variable ne répond pas aux exigences de masquage."
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
-msgstr "Cette vulnérabilité a été automatiquement résolue, car son type de vulnérabilité a été désactivé dans ce projet ou supprimé du jeu de règles par défaut de GitLab."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
+msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr "Cette action va invalider vos applications et appareils WebAuthn enregistrés."
@@ -48512,8 +48784,8 @@ msgstr "Fuseau horaire"
msgid "TimeTrackingEstimated|Est"
msgstr "Est"
-msgid "TimeTrackingReport|From"
-msgstr "Du"
+msgid "TimeTrackingReport|From the start of"
+msgstr ""
msgid "TimeTrackingReport|Run report"
msgstr "Exécuter le rapport"
@@ -48533,8 +48805,8 @@ msgstr "Résumé"
msgid "TimeTrackingReport|Time spent"
msgstr "Temps passé"
-msgid "TimeTrackingReport|To"
-msgstr "Au"
+msgid "TimeTrackingReport|To the end of"
+msgstr ""
msgid "TimeTrackingReport|Total time spent: "
msgstr "Temps total passé : "
@@ -48552,40 +48824,40 @@ msgid "TimeTracking|An error occurred while removing the timelog."
msgstr "Une erreur s'est produite lors de la suppression de l'entrée de temps passé."
msgid "TimeTracking|An error occurred while saving the time estimate."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'enregistrement de l'estimation de temps."
msgid "TimeTracking|Delete time spent"
msgstr "Supprimer le temps passé"
msgid "TimeTracking|Edit estimate"
-msgstr ""
+msgstr "Modifier l’estimation"
msgid "TimeTracking|Edit time estimate"
-msgstr ""
+msgstr "Modifier l'estimation de temps"
msgid "TimeTracking|Enter time as a total duration (for example, 1mo 2w 3d 5h 10m), or specify hours and minutes (for example, 75:30)."
msgstr ""
msgid "TimeTracking|Estimate"
-msgstr ""
+msgstr "Estimation"
msgid "TimeTracking|Estimated:"
msgstr "Estimé :"
msgid "TimeTracking|How do I estimate and track time?"
-msgstr ""
+msgstr "Comment puis-je estimer et suivre le temps ?"
msgid "TimeTracking|Over by %{timeRemainingHumanReadable}"
msgstr "Dépassement de %{timeRemainingHumanReadable}"
msgid "TimeTracking|Set estimate"
-msgstr ""
+msgstr "Définir l’estimation"
msgid "TimeTracking|Set estimated time to complete this %{issuableTypeName}."
msgstr ""
msgid "TimeTracking|Set time estimate"
-msgstr ""
+msgstr "Définir l'estimation de temps"
msgid "TimeTracking|Spent"
msgstr "Passé"
@@ -48927,7 +49199,7 @@ msgid "To manage seats for all members associated with this group and its subgro
msgstr "Pour gérer les sièges de tous les membres associés à ce groupe, ses sous-groupes et projets, visitez la %{link_start}page quotas d'utilisation%{link_end}."
msgid "To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
-msgstr ""
+msgstr "Afin de minimiser l'impact des limites de stockage sur les groupes principaux du forfait Gratuit, pendant une durée limitée, GitLab offre une %{promotion_link_start}réduction unique de 70 %%{link_end} sur le prix catalogue pour les %{offer_availability_link_start}groupes principaux éligibles%{link_end} lorsque vous achetez un nouvel abonnement d'un an à GitLab Premium SaaS. Cette offre est valable jusqu'au 31/10/2023."
msgid "To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here."
msgstr "Pour déplacer ou copier un projet GitLab entier depuis une autre installation de GitLab vers celleâ€ci, accédez à la page des paramètres du projet d'origine, générez un fichier d'exportation et téléversezâ€le ici."
@@ -48956,8 +49228,8 @@ msgstr "Pour réactiver votre compte, connectez-vous à GitLab sur %{gitlab_url}
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr "Pour supprimer le statut %{link_start}lecture seule%{link_end} et retrouver l'accès en écriture, demandez au(x) propriétaire(s) de votre groupe principal de réduire le nombre d'utilisateurs dans celui-ci à %{free_limit} ou moins, ou de passer à une édition payante qui n'a pas de limite d'utilisateurs."
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
-msgstr "Pour supprimer le mode de %{link_start}lecture seule%{link_end} et retrouver l'accès en écriture, vous pouvez réduire le nombre d'utilisateurs dans votre groupe principal à %{free_limit} ou moins. Vous pouvez également passer à une édition payante, sans limite d'utilisateurs. Si vous avez besoin d'un temps de réflexion, vous pouvez démarrer un essai gratuit de 30 jours qui comprend un nombre illimité d'utilisateurs. Pour minimiser l'impact sur les opérations, pour une durée limitée, GitLab offre une %{promotion_link_start}réduction unique de 70 %%{link_end} sur le prix catalogue au moment de l'achat d'un nouvel abonnement d'un an à GitLab SaaS Premium aux %{offer_availability_link_start}groupes principaux éligibles%{link_end}. L'offre est valable jusqu'au %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
msgstr "Pour remplacer la vérification par téléphone par la vérification par carte de crédit, créez une exemption de vérification par téléphone en utilisant le bouton ci-dessous."
@@ -49238,6 +49510,9 @@ msgstr "Ce jeton d'accès personnel a été automatiquement révoqué lorsqu'il
msgid "Tomorrow"
msgstr "Demain"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr "Il y a trop d'espaces de nommage activés. Gérez-les à travers la console ou l'API."
@@ -49318,6 +49593,9 @@ msgstr "Total"
msgid "Total Score"
msgstr "Note totale"
+msgid "Total Spans"
+msgstr "Nombre total d'intervalles"
+
msgid "Total cores (CPUs)"
msgstr "Nombre de cœurs (CPU)"
@@ -49348,9 +49626,15 @@ msgstr "Plus de 1 000"
msgid "Trace Details"
msgstr "Détails à propos de la trace"
+msgid "Trace Start"
+msgstr "Début du traçage"
+
msgid "Tracing"
msgstr "Traçage"
+msgid "Tracing|%{ms} ms"
+msgstr "%{ms} ms"
+
msgid "Tracing|Check again"
msgstr "Revérifier"
@@ -49373,10 +49657,10 @@ msgid "Tracing|Failed to load page."
msgstr "Échec du chargement de la page."
msgid "Tracing|Failed to load trace details."
-msgstr ""
+msgstr "Échec du chargement des informations de traçage."
msgid "Tracing|Failed to load traces."
-msgstr ""
+msgstr "Échec du chargement des traces."
msgid "Tracing|Filter Traces"
msgstr "Suivi|Filtrer les traces"
@@ -49412,22 +49696,34 @@ msgid "Tracing|Monitor your applications with GitLab Distributed Tracing."
msgstr ""
msgid "Tracing|No traces to display."
-msgstr ""
+msgstr "Aucune trace à afficher."
msgid "Tracing|Operation"
msgstr "Opération"
msgid "Tracing|Period"
-msgstr ""
+msgstr "Période"
msgid "Tracing|Service"
msgstr "Service"
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr "Activer/désactiver les portées enfants"
+
msgid "Tracing|Trace ID"
msgstr "Suivi|ID de trace"
msgid "Tracing|Traces"
-msgstr ""
+msgstr "Traces"
msgid "Tracing|longer than"
msgstr "Suivi|de plus que"
@@ -49547,13 +49843,13 @@ msgid "Trials|Day %{daysUsed}/%{duration}"
msgstr "Jour %{daysUsed}/%{duration}"
msgid "Trials|Looking to do more with GitLab?"
-msgstr ""
+msgstr "Vous cherchez à en faire plus avec GitLab ?"
msgid "Trials|Upgrade your plan for more security features"
-msgstr ""
+msgstr "Passer à un forfait supérieur pour plus de fonctionnalités de sécurité"
msgid "Trials|With GitLab Ultimate you can detect and address vulnerabilities in your application."
-msgstr ""
+msgstr "Avec GitLab Ultimate, il est possible de détecter et corriger les vulnérabilités de votre application."
msgid "Trials|You can apply your trial to a new group or an existing group."
msgstr "Vous pouvez appliquer votre essai à un nouveau groupe ou à un groupe existant."
@@ -49564,7 +49860,7 @@ msgstr[0] "Il vous reste %{daysRemaining} jour sur GitLab %{planName} !"
msgstr[1] "Il vous reste %{daysRemaining} jours sur GitLab %{planName} !"
msgid "Trials|Your 30-day trial has ended"
-msgstr ""
+msgstr "Votre période d'essai de 30 jours est terminée"
msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
msgstr "Votre essai se termine le %{boldStart}%{trialEndDate}%{boldEnd}. Nous espérons que vous appréciez les fonctionnalités de GitLab %{planName}. Pour conserver celles-ci après la fin de votre période d'essai, vous devez souscrire à un abonnement. (Vous pouvez également choisir GitLab Premium si cela répond à vos besoins.)"
@@ -49788,9 +50084,6 @@ msgstr "URL ou ID de requête"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr "L'UTILISATEUR %{user_name} SERA SUPPRIMÉ ! Voulez-vous vraiment continuer ?"
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "L'UTILISATEUR %{user} SERA SUPPRIMÉ. Confirmez-vous ?"
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "L'UTILISATEUR SERA BLOQUÉ. Confirmez-vous ?"
@@ -49878,6 +50171,9 @@ msgstr "Impossible de charger le widget de requête de fusion. Essayez de rechar
msgid "Unable to load the page"
msgstr "Impossible de charger la page"
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr "Impossible d'analyser le JSON"
@@ -49911,9 +50207,6 @@ msgstr "Impossible de mettre à jour cette épopée pour le moment."
msgid "Unable to update this issue at this time."
msgstr "Impossible de mettre à jour ce ticket pour le moment."
-msgid "Unable to verify the user"
-msgstr "Impossible de vérifier l'utilisateur"
-
msgid "Unapprove a merge request"
msgstr "Désapprouver une requête de fusion"
@@ -49992,6 +50285,9 @@ msgstr "Malheureusement, votre courriel à GitLab n'a pas pu être traité."
msgid "Unhappy?"
msgstr "Non satisfait ?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr "j"
@@ -50367,6 +50663,9 @@ msgstr "Acheter des minutes de calcul supplémentaires"
msgid "UsageQuota|Buy storage"
msgstr "Acheter du stockage"
+msgid "UsageQuota|Code Suggestions"
+msgstr "Suggestions de code"
+
msgid "UsageQuota|Code packages and container images."
msgstr "Paquets de code et images de conteneur."
@@ -50388,12 +50687,12 @@ msgstr "Registre de conteneur"
msgid "UsageQuota|Dependency proxy"
msgstr "Proxy de dépendance"
-msgid "UsageQuota|Filter chart by month"
-msgstr "Filtrer le graphique par mois"
-
msgid "UsageQuota|Filter charts by year"
msgstr "Filtrer les graphiques par année"
+msgid "UsageQuota|Filter projects data by month"
+msgstr "Filtrer les données des projets par mois"
+
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
msgstr "Pour plus d'informations sur les limites de stockage, consultez notre %{faq_link_start}FAQ%{link_end}."
@@ -50404,7 +50703,7 @@ msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker
msgstr "Registre de conteneurs Docker intégré à GitLab pour le stockage d'images Docker."
msgid "UsageQuota|Group settings %{gt} Usage quotas"
-msgstr ""
+msgstr "Paramètres de groupe %{gt} Quotas d'utilisation"
msgid "UsageQuota|Included in %{planName} subscription"
msgstr "Inclus dans l'abonnement %{planName}"
@@ -50439,6 +50738,9 @@ msgstr "Vue d'ensemble de l'espace de nommage"
msgid "UsageQuota|Namespace storage used"
msgstr "Stockage utilisé par les espaces de nommage"
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr "Le stockage total de l'espace de nommage représente la somme du stockage consommé par tous les projets, le registre de conteneurs et le proxy de dépendance."
+
msgid "UsageQuota|No compute usage data available."
msgstr "Aucune donnée disponible sur les unités de calcul utilisées."
@@ -50505,15 +50807,15 @@ msgstr "Cela affectera le groupe %{strong_start}%{context_name}%{strong_end}. "
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr "Cela affectera le projet %{strong_start}%{context_name}%{strong_end}. "
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr "Le graphique et le tableau ci-dessous montrent l'utilisation pendant la période suivante : %{month} %{year}"
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
-msgstr ""
+msgstr "L'espace de noms utilise actuellement %{strong_start}%{used_storage}%{strong_end} du stockage de l'espace de noms. Les propriétaires du groupe peuvent voir l'utilisation du stockage d'espace de noms et en acheter davantage depuis les %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Comment puis-je gérer mon stockage%{link_end} ?"
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr "L'espace de nommage utilise actuellement %{strong_start}%{used_storage}%{strong_end} du stockage de l'espace de nommage. Consultez et gérez votre utilisation depuis %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}En savoir plus%{link_end} sur la manière de diminuer votre stockage."
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr "Le tableau ci-dessous montre l'utilisation depuis le %{usageSince}"
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr "Cet espace de nommage dispose de %{planLimit} de stockage. %{linkStart}Comment les limites sont-elles appliquées ?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr "Ce nom d'utilisateur est disponible."
msgid "Username or email"
msgstr "Nom d'utilisateur ou adresse de courriel"
+msgid "Username or primary email"
+msgstr "Nom d'utilisateur ou adresse de courriel principale"
+
msgid "Username:"
msgstr "Nom d'utilisateur :"
@@ -51312,25 +51617,25 @@ msgid "Validations failed."
msgstr "Les validations ont échoué."
msgid "Validation|can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"
-msgstr ""
+msgstr "ne peut contenir que des lettres minuscules, des chiffres, « _ » et « - ». Doit commencer par une lettre et ne peut pas se terminer par « - » ni par « _ »"
msgid "Validation|groupId parameter is invalid"
-msgstr ""
+msgstr "le paramètre groupId n'est pas valide"
msgid "Validation|must belong to the same project"
msgstr ""
msgid "Validation|parameters are invalid"
-msgstr ""
+msgstr "les paramètres ne sont pas valides"
msgid "Validation|percentage must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "le pourcentage doit être une chaîne comprise entre 0 et 100 inclus"
msgid "Validation|rollout must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "le déploiement doit être une chaîne comprise entre 0 et 100 inclus"
msgid "Validation|strategy name is invalid"
-msgstr ""
+msgstr "le nom de la stratégie n'est pas valide"
msgid "Value"
msgstr "Valeur"
@@ -51534,7 +51839,7 @@ msgid "VerificationReminder|You’ll now be able to take advantage of free compu
msgstr ""
msgid "Verifications status"
-msgstr ""
+msgstr "État des vérifications"
msgid "Verified"
msgstr "Vérifiée"
@@ -51748,7 +52053,7 @@ msgid "View the latest successful deployment to this environment"
msgstr "Voir le dernier déploiement réussi dans cet environnement"
msgid "View trigger token usage examples"
-msgstr ""
+msgstr "Voir des exemples d'utilisation des jetons de déclenchement"
msgid "View usage details"
msgstr "Afficher les détails d'utilisation"
@@ -51888,6 +52193,9 @@ msgstr "Détails"
msgid "VulnerabilityExport|Detected At"
msgstr "Détectée le"
+msgid "VulnerabilityExport|Full Path"
+msgstr "Chemin complet"
+
msgid "VulnerabilityExport|Group Name"
msgstr "Nom du groupe"
@@ -51915,17 +52223,20 @@ msgstr "Outil"
msgid "VulnerabilityExport|Vulnerability"
msgstr "Vulnérabilité"
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Confirmée%{statusEnd} %{timeago} par %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{statusStart}Confirmée%{statusEnd} · %{timeago} par %{user}"
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "%{statusStart}Détectée%{statusEnd} %{timeago} dans le pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr "%{statusStart}Détectée%{statusEnd} · %{timeago} dans le pipeline %{pipelineLink}"
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Rejetée%{statusEnd} %{timeago} par %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{statusStart}Rejetée%{statusEnd} · %{timeago} par %{user}"
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Résolue%{statusEnd} %{timeago} par %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr "%{statusStart}Rejetée%{statusEnd} : %{dismissalReason} · %{timeago} par %{user}"
+
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{statusStart}Résolue%{statusEnd} · %{timeago} par %{user}"
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr "(facultatif) Inclure la solution à la vulnérabilité si disponible."
@@ -52060,7 +52371,7 @@ msgid "VulnerabilityStatusTypes|Resolved"
msgstr "Résolu"
msgid "Vulnerability|%{file} was not found in commit %{ref}"
-msgstr ""
+msgstr "%{file} n'a pas été trouvé dans la validation %{ref}"
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (version %{scannerVersion})"
@@ -52167,6 +52478,9 @@ msgstr "Fichier :"
msgid "Vulnerability|GitLab Security Report"
msgstr "Rapport de Sécurité de GitLab"
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52264,7 +52578,7 @@ msgid "Vulnerability|Show prompt"
msgstr ""
msgid "Vulnerability|Something went wrong while trying to get the source file."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la tentative d'obtenir le fichier source."
msgid "Vulnerability|Stacktrace snippet:"
msgstr "Extrait de la trace de pile :"
@@ -52281,11 +52595,8 @@ msgstr "Le scanner a déterminé que cette vulnérabilité est un faux positif.
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr "La réponse non modifiée est la réponse originale qui n'a subi aucune altération suite à la requête"
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr "Une erreur inattendue s'est produite. %{linkStart}Veuillez réessayer%{linkEnd}."
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
-msgstr "Il s'agit d'une fonctionnalité expérimentale qui utilise l'IA pour expliquer la vulnérabilité et fournir des recommandations. Utilisez cette fonctionnalité avec prudence, car elle est en évolution constante. Veuillez partager vos commentaires et vos idées sur %{linkStart}ce ticket%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgstr "Il s'agit d'une fonctionnalité bêta qui utilise l'IA pour expliquer la vulnérabilité et fournir des recommandations. Utilisez-la avec prudence, car elle est en évolution constante. Veuillez partager vos commentaires et vos idées sur %{linkStart}ce ticket%{linkEnd}."
msgid "Vulnerability|Tool"
msgstr "Outil"
@@ -52320,6 +52631,9 @@ msgstr "Classe vulnérable :"
msgid "Vulnerability|Vulnerable method:"
msgstr "Méthode vulnérable :"
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr "AVERTISSEMENT :"
@@ -52647,6 +52961,12 @@ msgstr "Les expressions rationnelles telles que %{REGEX_CODE} sont prises en cha
msgid "Webhooks|Releases events"
msgstr "Événements concernant les releases"
+msgid "Webhooks|Response body is empty"
+msgstr "Le corps de la réponse est vide"
+
+msgid "Webhooks|Response headers data is empty"
+msgstr "Les données des en-têtes de réponse sont vides"
+
msgid "Webhooks|SSL verification"
msgstr "Vérification SSL"
@@ -52749,15 +53069,6 @@ msgstr "Bienvenue dans une nouvelle expérience de navigation"
msgid "Welcome, %{name}!"
msgstr "Bienvenue, %{name} !"
-msgid "What are group audit events?"
-msgstr "Que sont les événements d'audit de groupe ?"
-
-msgid "What are instance audit events?"
-msgstr "Que sont les événements d'audit d'instance ?"
-
-msgid "What are project audit events?"
-msgstr "Que sont les événements d'audit de projet ?"
-
msgid "What are some examples?"
msgstr "Des exemples sont-ils disponibles ?"
@@ -53112,6 +53423,12 @@ msgstr "Limite du travail en cours"
msgid "Work item promoted successfully."
msgstr "Élément de travail promu avec succès."
+msgid "Work items are already linked"
+msgstr "Les éléments de travail sont déjà liés"
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr "Cet élément de travail dépasserait le nombre maximal d'éléments liés."
+
msgid "WorkItem|%{count} more assignees"
msgstr "%{count} autres personnes assignées"
@@ -53204,9 +53521,6 @@ msgstr "Copier l'adresse de courriel %{workItemType}"
msgid "WorkItem|Create %{workItemType}"
msgstr "Créer %{workItemType}"
-msgid "WorkItem|Create objective"
-msgstr "Créer un objectif"
-
msgid "WorkItem|Create work item"
msgstr "Créer un élément de travail"
@@ -53225,9 +53539,6 @@ msgstr "Date d'échéance"
msgid "WorkItem|Existing task"
msgstr "Tâche existante"
-msgid "WorkItem|Health status"
-msgstr "État de santé"
-
msgid "WorkItem|History only"
msgstr "Historique uniquement"
@@ -53244,7 +53555,13 @@ msgid "WorkItem|Key Result"
msgstr "Résultat clé"
msgid "WorkItem|Key result"
-msgstr ""
+msgstr "Résultat clé"
+
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr "Reliez des éléments de travail pour mettre en évidence leur relation ou le fait que l'un d'eux bloque les autres."
+
+msgid "WorkItem|Linked Items"
+msgstr "Éléments liés"
msgid "WorkItem|Mark as done"
msgstr "Marquer comme terminé"
@@ -53252,8 +53569,8 @@ msgstr "Marquer comme terminé"
msgid "WorkItem|Milestone"
msgstr "Jalon"
-msgid "WorkItem|New objective"
-msgstr "Nouvel objectif"
+msgid "WorkItem|New %{workItemType}"
+msgstr "Nouveau type de %{workItemType}"
msgid "WorkItem|New task"
msgstr "Nouvelle tâche"
@@ -53396,9 +53713,6 @@ msgstr "Scénario de test"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr "Ce(tte) %{workItemType} est confidentiel(le) et ne devrait être visible que par les membres de l'équipe disposant au moins d'un accès rapporteur"
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr "Cet objectif est confidentiel et ne devrait être visible que par les membres de l'équipe disposant au moins d'un accès rapporteur"
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr "Cet élément de travail n'est pas disponible. Soit il n'existe pas, soit vous n'avez pas la permission de le voir."
@@ -53429,8 +53743,8 @@ msgstr "Vous ne voyez que les %{boldStart}autres activités%{boldEnd} dans le fl
msgid "Workspaces"
msgstr "Espaces de travail"
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
-msgstr "Un espace de travail est un environnement de bac à sable virtuel dans GitLab pour votre code. Vous pouvez en créer un pour un projet public."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
+msgstr ""
msgid "Workspaces|Cancel"
msgstr "Annuler"
@@ -53528,9 +53842,6 @@ msgstr "Statut inconnu"
msgid "Workspaces|Workspaces"
msgstr "Espaces de travail"
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr "Vous ne pouvez créer un espace de travail que pour les projets publics."
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr "Vous ne pouvez pas créer d'espace de travail pour ce projet"
@@ -53791,6 +54102,9 @@ msgstr "Vous pouvez créer un nouveau jeton d'accès personnel en visitant %{lin
msgid "You can create a new SSH key by visiting %{link}"
msgstr "Vous pouvez créer une nouvelle clé SSH en visitant %{link}"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr "Vous pouvez en créer un nouveau ou les vérifier dans vos paramètres de %{link_start}jetons d'accès%{link_end}."
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr "Vous pouvez en créer un nouveau ou les vérifier dans vos paramètres de %{pat_link_start}jetons d'accès personnels%{pat_link_end}."
@@ -53800,6 +54114,9 @@ msgstr "Vous pouvez en créer une nouvelle ou les vérifier dans vos paramètres
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr "Vous pouvez en créer une nouvelle ou les vérifier dans vos paramètres de clés SSH %{ssh_key_link}."
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr "Vous pouvez en créer un nouveau ou les vérifier dans vos paramètres de jetons d'accès : %{target_url}"
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr "Vous pouvez en créer un nouveau ou les vérifier dans vos paramètres de jetons d'accès personnels %{pat_link}."
@@ -53998,9 +54315,6 @@ msgstr "Vous ne disposez d’aucune application."
msgid "You don't have any authorized applications."
msgstr "Vous ne disposez d’aucune application autorisée."
-msgid "You don't have any deployments right now."
-msgstr "Vous n'avez aucun déploiement pour le moment."
-
msgid "You don't have any open merge requests"
msgstr "Vous n'avez aucune requête de fusion ouverte"
@@ -54073,7 +54387,7 @@ msgid "You have insufficient permissions to create a Todo for this alert"
msgstr "Vous n'avez pas les autorisations suffisantes pour créer un pense-bête pour cette alerte"
msgid "You have insufficient permissions to create a target branch rule"
-msgstr ""
+msgstr "Vous n'avez pas les permissions suffisantes pour créer une règle de branche cible"
msgid "You have insufficient permissions to create an HTTP integration for this project"
msgstr "Vous n'avez pas les permissions suffisantes pour créer une intégration HTTP pour ce projet"
@@ -54387,7 +54701,7 @@ msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limi
msgstr "Le groupe principal de votre forfait Gratuit,%{group_name}, compte plus de %{free_users_limit} utilisateurs et utilise plus %{free_storage_limit} de données. Une fois les limites d'utilisation appliquées aux groupes principaux du forfait Gratuit, les projets de ce groupe seront en %{read_only_link_start}mode lecture seule%{link_end}. Pour éviter que votre groupe ne passe en lecture seule, vous devez contacter un utilisateur ayant le rôle de Propriétaire pour ce groupe afin de passer à une édition payante ou de gérer votre utilisation. Pour plus d'informations sur les limites d'utilisation à venir, consultez notre %{faq_link_start}FAQ%{link_end}."
msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. You should reduce the number of users or upgrade to a paid tier %{strong_start}before%{strong_end} you manage your storage usage. Otherwise, your Free top-level group will become read-only immediately because the 5-user limit applies. For more information, see our %{faq_link_start}FAQ%{link_end}.%{br_tag}%{br_tag}To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
-msgstr ""
+msgstr "Le groupe principal de votre forfait Gratuit, %{group_name}, compte plus de %{free_users_limit} utilisateurs et utilise plus %{free_storage_limit} de données. Une fois les limites d'utilisation appliquées aux groupes principaux du forfait Gratuit, les projets de ce groupe seront en %{read_only_link_start}mode lecture seule%{link_end}. Vous devez réduire le nombre d'utilisateurs ou passer à une édition payante %{strong_start}avant%{strong_end} de gérer votre utilisation du stockage. Sinon, le groupe principal de votre forfait Gratuit sera immédiatement en lecture seule, car la limite de 5 utilisateurs s'applique. Pour plus d'informations, consultez notre %{faq_link_start}FAQ%{link_end}.%{br_tag}%{br_tag}Afin de réduire l'impact des limites de stockage sur les groupes principaux du forfait Gratuit, pendant une durée limitée, GitLab offre une %{promotion_link_start}réduction unique de 70 %%{link_end} sur le prix catalogue pour les %{offer_availability_link_start}groupes principaux éligibles%{link_end} lorsque vous achetez un nouvel abonnement d'un an à GitLab Premium SaaS. Cette offre est valable jusqu'au 31/10/2023."
msgid "Your GPG keys"
msgstr "Vos clés GPG"
@@ -54497,9 +54811,6 @@ msgstr "Vos applications"
msgid "Your authorized applications"
msgstr "Vos applications autorisées"
-msgid "Your browser does not support iFrames"
-msgstr "Votre navigateur ne prend pas en charge les iFrames"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr "Votre navigateur ne prend pas en charge WebAuthn. Veuillez utiliser un navigateur pris en charge comme Chrome (67+) ou Firefox (60+)."
@@ -54619,9 +54930,6 @@ msgstr "Vos jetons d'accès personnels expireront dans %{days_to_expire} jours o
msgid "Your profile"
msgstr "Votre profil"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr "Votre projet ne bénéficie plus des avantages de GitLab Ultimate depuis le 01/07/2022. Comme précédemment notifié dans l'application, les projets open source publics du forfait Gratuit peuvent postuler au programme GitLab for Open Source pour profiter des avantages GitLab Ultimate. Veuillez consulter les %{faq_link_start}FAQ%{link_end} pour plus d'informations."
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "Votre limite de projets est de %{limit} projets. Veuillez contacter votre administrateur pour l'augmenter"
@@ -54646,6 +54954,9 @@ msgstr "Vos exigences sont en cours d'importation. Une fois que cette opération
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr "Vos exigences seront importées en arrière-plan. Après la fin de l'importation, vous recevrez un courriel de confirmation."
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr "Vos jetons d'accès aux ressources expireront dans %{days_to_expire} ou moins"
+
msgid "Your search didn't match any commits."
msgstr "Votre recherche ne correspond à aucune validation."
@@ -54815,6 +55126,9 @@ msgstr "toutes les branches protégées"
msgid "allowed to fail"
msgstr "échec autorisé"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr "déjà banni de l'espace de nommage"
@@ -54924,6 +55238,9 @@ msgstr "ne peut pas être changé en %{new_type}"
msgid "can not be changed when assigned to an epic"
msgstr "ne peut pas être modifié lorsqu'il est assigné à une épopée"
+msgid "can not be set for template labels"
+msgstr "ne peut pas être défini pour les labels de modèle"
+
msgid "can not be set for this resource"
msgstr "ne peut pas être défini pour cette ressource"
@@ -55437,11 +55754,14 @@ msgid "created %{timeAgo} by %{author} in %{project_link}"
msgstr "création %{timeAgo} par %{author} dans %{project_link}"
msgid "created %{timeAgo} by %{email} via %{author}"
-msgstr ""
+msgstr "création il y a %{timeAgo} par %{email} via %{author}"
msgid "created by"
msgstr "créé par"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr "tous les jours"
@@ -55507,7 +55827,10 @@ msgid "e.g. %{token}"
msgstr "par ex. %{token}"
msgid "eg party_tanuki"
-msgstr ""
+msgstr "par exemple party_tanuki"
+
+msgid "eg. dev/*"
+msgstr "par exemple dev/*"
msgid "element is not a hierarchy"
msgstr "l'élément n'est pas une hiérarchie"
@@ -55595,9 +55918,6 @@ msgstr[1] "fichiers"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "la découverte est introuvable ou est déjà rattachée à une vulnérabilité"
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr "il est trop volumineux"
msgid "jigsaw is not defined"
msgstr "jigsaw n'est pas défini"
+msgid "key result"
+msgstr "résultat clé"
+
msgid "kuromoji custom analyzer"
msgstr "analyseur personnalisé kuromoji"
@@ -56301,7 +56624,7 @@ msgid "must be a valid syntax highlighting theme ID"
msgstr "doit être un ID de thème de coloration syntaxique valide"
msgid "must be a value between 0 and 1"
-msgstr ""
+msgstr "doit être une valeur comprise entre 0 et 1"
msgid "must be after start"
msgstr "doit être après le début"
@@ -56336,6 +56659,9 @@ msgstr "doit se trouver à l'intérieur d'un réseau de bifurcations"
msgid "must be less than the limit of %{tag_limit} tags"
msgstr "doit être inférieur à la limite de %{tag_limit} étiquettes"
+msgid "must be owned by the user's enterprise group"
+msgstr "doit appartenir au groupe de l'entreprise de l'utilisateur"
+
msgid "must be set for a project namespace"
msgstr "doit être défini pour un espace de nommage de projet"
@@ -56345,6 +56671,9 @@ msgstr "doit être renseigné"
msgid "must be unique by status and elapsed time within a policy"
msgstr "doit être unique au niveau état et temps écoulé dans une politique"
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr "doit être unique. Cette autorité de certification a déjà été configurée pour un autre espace de nommage."
+
msgid "must belong to same project of its requirement object."
msgstr "doit appartenir au même projet que son objet exigences."
@@ -56372,6 +56701,9 @@ msgstr "ne doit pas être un propriétaire de l'espace de nommage"
msgid "must not contain commonly used combinations of words and letters"
msgstr "ne doit pas contenir des combinaisons de mots ou de lettres couramment utilisées"
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr "mon-super-groupe"
@@ -56429,6 +56761,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item} et %{lastItem}"
+msgid "objective"
+msgstr "objectif"
+
msgid "on or after"
msgstr "le ou après le"
@@ -56730,6 +57065,9 @@ msgstr "%{slash_command} ajoute ou soustrait du temps déjà passé."
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "a démarré une discussion sur %{design_link}"
@@ -56772,6 +57110,9 @@ msgstr "nom d'étiquette"
msgid "targeting "
msgstr "ciblage "
+msgid "task"
+msgstr "tâche"
+
msgid "terraform states"
msgstr "états terraform"
@@ -56820,9 +57161,6 @@ msgstr "le total doit être inférieur ou égal à %{size}"
msgid "triggered"
msgstr "déclenché"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr "a déclenché un pipeline pour la validation %{linkStart}%{shortId}%{linkEnd}"
-
msgid "two-factor authentication settings"
msgstr "paramètres d'authentification à deux facteurs"
@@ -56879,6 +57217,9 @@ msgstr "La version %{report_version} du type de rapport %{report_type} est obsol
msgid "version %{versionIndex}"
msgstr "version %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "via %{closed_via}"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 226085ef41a..bf468a3b209 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -45,6 +45,14 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " and leave a comment on"
+msgstr ""
+
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -247,6 +255,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d environment found"
+msgid_plural "%d environments found"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] ""
@@ -670,9 +683,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -796,6 +806,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1120,9 +1136,6 @@ msgstr ""
msgid "%{startDate} – No due date"
msgstr ""
-msgid "%{start} to %{end}"
-msgstr ""
-
msgid "%{statusStart}Dismissed%{statusEnd}"
msgstr ""
@@ -1322,10 +1335,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1432,6 +1445,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1670,12 +1686,6 @@ msgstr ""
msgid "2FADevice|Registered On"
msgstr ""
-msgid "3 hours"
-msgstr ""
-
-msgid "30 minutes"
-msgstr ""
-
msgid "30+ contributions"
msgstr ""
@@ -1703,9 +1713,6 @@ msgstr ""
msgid "409|There was a conflict with your request."
msgstr ""
-msgid "8 hours"
-msgstr ""
-
msgid ":%{startLine} to %{endLine}"
msgstr ""
@@ -1892,24 +1899,30 @@ msgstr ""
msgid "AI| %{link_start}How is my data used?%{link_end}"
msgstr ""
-msgid "AI| %{link_start}What are Experiment features?%{link_end}"
-msgstr ""
-
msgid "AI|%{tool} is %{transition} an answer"
msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1922,19 +1935,13 @@ msgstr ""
msgid "AI|Description is required"
msgstr ""
-msgid "AI|Enabling these features is your acceptance of the %{link_start}GitLab Testing Agreement%{link_end}."
-msgstr ""
-
msgid "AI|Experiment"
msgstr ""
-msgid "AI|Experiment features"
-msgstr ""
-
msgid "AI|Explain the code from %{filePath} in human understandable language presented in Markdown format. In the response add neither original code snippet nor any title. `%{text}`. If it is not programming code, say `The selected text is not code. I am afraid this feature is for explaining code only. Would you like to ask a different question about the selected text?` and wait for another question."
msgstr ""
-msgid "AI|Explain your rating (optional)"
+msgid "AI|Explain your rating to help us improve! (optional)"
msgstr ""
msgid "AI|Features that use third-party AI services require transmission of data, including personal data."
@@ -1949,12 +1956,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1976,6 +2001,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1985,16 +2013,13 @@ msgstr ""
msgid "AI|There is too much text in the chat. Please try again with a shorter text."
msgstr ""
-msgid "AI|These features can cause performance and stability issues and may change over time."
-msgstr ""
-
msgid "AI|Third-party AI services"
msgstr ""
-msgid "AI|Unhelpful"
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
msgstr ""
-msgid "AI|Use Experiment features"
+msgid "AI|Unhelpful"
msgstr ""
msgid "AI|Use third-party AI services"
@@ -2003,6 +2028,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2015,9 +2043,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2222,9 +2247,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2339,6 +2361,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2396,6 +2421,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,9 +2472,15 @@ msgstr ""
msgid "AccessDropdown|Groups"
msgstr ""
+msgid "AccessDropdown|No role"
+msgstr ""
+
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2627,6 +2661,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2939,6 +2976,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2993,7 +3033,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3233,9 +3273,6 @@ msgstr ""
msgid "AdminArea|Sign up for the GitLab newsletter"
msgstr ""
-msgid "AdminArea|Stop all jobs"
-msgstr ""
-
msgid "AdminArea|Total Billable users"
msgstr ""
@@ -3359,6 +3396,9 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Code can be imported from enabled sources during project creation. OmniAuth must be configured for GitHub %{github_docs_link_start}%{icon}%{github_docs_link_end} and Bitbucket %{bitbucket_docs_link_start}%{icon}%{bitbucket_docs_link_end}."
+msgstr ""
+
msgid "AdminSettings|Collector host"
msgstr ""
@@ -3404,9 +3444,6 @@ msgstr ""
msgid "AdminSettings|Elasticsearch indexing"
msgstr ""
-msgid "AdminSettings|Email from GitLab - email users right from the Admin Area. %{link_start}Learn more%{link_end}."
-msgstr ""
-
msgid "AdminSettings|Enable Registration Features"
msgstr ""
@@ -3446,6 +3483,9 @@ msgstr ""
msgid "AdminSettings|Feed token"
msgstr ""
+msgid "AdminSettings|For a list of included Registration Features, see %{link_start}the documentation%{link_end}."
+msgstr ""
+
msgid "AdminSettings|Git abuse rate limit"
msgstr ""
@@ -3491,9 +3531,6 @@ msgstr ""
msgid "AdminSettings|Let's Encrypt email"
msgstr ""
-msgid "AdminSettings|Limit project size at a global, group, and project level. %{link_start}Learn more%{link_end}."
-msgstr ""
-
msgid "AdminSettings|Limit the number of namespaces and projects that can be indexed."
msgstr ""
@@ -3560,9 +3597,6 @@ msgstr ""
msgid "AdminSettings|Protect CI/CD variables by default"
msgstr ""
-msgid "AdminSettings|Registration Features include:"
-msgstr ""
-
msgid "AdminSettings|Requeue indexing workers"
msgstr ""
@@ -3575,9 +3609,6 @@ msgstr ""
msgid "AdminSettings|Requires %{linkStart}email notifications%{linkEnd}"
msgstr ""
-msgid "AdminSettings|Restrict group access by IP address. %{link_start}Learn more%{link_end}."
-msgstr ""
-
msgid "AdminSettings|Restricted visibility levels"
msgstr ""
@@ -3632,6 +3663,9 @@ msgstr ""
msgid "AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
msgstr ""
+msgid "AdminSettings|Set visibility of project contents and configure Git access protocols."
+msgstr ""
+
msgid "AdminSettings|Setting must be greater than 0."
msgstr ""
@@ -3653,6 +3687,9 @@ msgstr ""
msgid "AdminSettings|The maximum number of included files per pipeline."
msgstr ""
+msgid "AdminSettings|The selected level must be different from the selected default group and project visibility."
+msgstr ""
+
msgid "AdminSettings|The template for the required pipeline configuration can be one of the GitLab-provided templates, or a custom template added to an instance template repository. %{link_start}How do I create an instance template repository?%{link_end}"
msgstr ""
@@ -3833,7 +3870,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4775,7 +4812,7 @@ msgstr ""
msgid "Allow users to extend their session"
msgstr ""
-msgid "Allow users to register any application to use GitLab as an OAuth provider"
+msgid "Allow users to register any application to use GitLab as an OAuth provider. This setting does not affect group-level OAuth applications."
msgstr ""
msgid "Allowed"
@@ -4898,9 +4935,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4991,6 +5025,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5176,6 +5213,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5191,6 +5231,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5301,6 +5347,15 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
+msgid "Analytics|Add to dashboard"
+msgstr ""
+
+msgid "Analytics|Add visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5328,6 +5383,9 @@ msgstr ""
msgid "Analytics|Cancel"
msgstr ""
+msgid "Analytics|Charts"
+msgstr ""
+
msgid "Analytics|Choose a chart type on the right"
msgstr ""
@@ -5346,15 +5404,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5376,6 +5437,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5391,6 +5458,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5433,15 +5503,15 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
@@ -5451,12 +5521,24 @@ msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Single stats"
+msgstr ""
+
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
+msgid "Analytics|Something went wrong while loading the dashboard. Refresh the page to try again or see %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong."
msgstr ""
+msgid "Analytics|Tables"
+msgstr ""
+
msgid "Analytics|To create your own dashboards, first configure a project to store your dashboards."
msgstr ""
@@ -6209,10 +6291,10 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
+msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
+msgid "Are you sure you want to delete this target branch rule?"
msgstr ""
msgid "Are you sure you want to deploy this environment?"
@@ -6292,7 +6374,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6393,18 +6475,12 @@ msgstr ""
msgid "Artifacts|Delete selected"
msgstr ""
-msgid "Artifacts|Help us improve this page"
-msgstr ""
-
msgid "Artifacts|Maximum selected artifacts limit reached"
msgstr ""
msgid "Artifacts|Something went wrong while deleting. Please refresh the page to try again."
msgstr ""
-msgid "Artifacts|Take a quick survey"
-msgstr ""
-
msgid "Artifacts|The selected artifact will be permanently deleted. Any reports generated from these artifacts will be empty."
msgid_plural "Artifacts|The selected artifacts will be permanently deleted. Any reports generated from these artifacts will be empty."
msgstr[0] ""
@@ -6416,9 +6492,6 @@ msgstr ""
msgid "Artifacts|Total artifacts size"
msgstr ""
-msgid "Artifacts|We want you to be able to use this page to easily manage your CI/CD job artifacts. We are working to improve this experience and would appreciate any feedback you have about the improvements we are making."
-msgstr ""
-
msgid "As this is a newly created account, to get started, click the link below to confirm your account."
msgstr ""
@@ -6650,6 +6723,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6767,6 +6843,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7709,9 +7788,6 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
@@ -7872,9 +7948,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7962,9 +8035,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -8722,7 +8792,7 @@ msgstr ""
msgid "BulkImport|Destination"
msgstr ""
-msgid "BulkImport|Direct transfer maximum download file size (MB)"
+msgid "BulkImport|Direct transfer maximum download file size (MiB)"
msgstr ""
msgid "BulkImport|Existing groups"
@@ -8836,6 +8906,9 @@ msgstr ""
msgid "BulkImport|must be a group"
msgstr ""
+msgid "BulkImport|must have a relative path structure with no HTTP protocol characters, or leading or trailing forward slashes. Path segments must not start or end with a special character, and must not contain consecutive special characters"
+msgstr ""
+
msgid "Bulkmport|Over six imports in one minute were attempted. Wait at least one minute and try again."
msgstr ""
@@ -9039,7 +9112,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,6 +9175,18 @@ msgstr ""
msgid "CVE|Why Request a CVE ID?"
msgstr ""
+msgid "CVS|By enabling this feature, you accept the %{linkStart}Testing Terms of Use%{linkEnd}"
+msgstr ""
+
+msgid "CVS|Continuous Vulnerability Scan"
+msgstr ""
+
+msgid "CVS|Detect vulnerabilities outside a pipeline as new data is added to the GitLab Advisory Database."
+msgstr ""
+
+msgid "CVS|Toggle CVS"
+msgstr ""
+
msgid "Cadence is not automated"
msgstr ""
@@ -9135,7 +9220,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9522,6 +9607,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9534,9 +9622,6 @@ msgstr ""
msgid "Chat"
msgstr ""
-msgid "Chat not available."
-msgstr ""
-
msgid "ChatMessage|%{project_link}: Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status} in %{duration}"
msgstr ""
@@ -9612,6 +9697,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9670,7 +9758,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10129,15 +10217,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10189,9 +10277,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10213,12 +10298,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10234,9 +10331,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10395,6 +10489,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11438,18 +11535,12 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
msgid "Code block"
msgstr ""
-msgid "Code can be imported from enabled sources during project creation. OmniAuth must be configured for GitHub"
-msgstr ""
-
msgid "Code coverage statistics for %{ref} %{start_date} - %{end_date}"
msgstr ""
@@ -11510,33 +11601,39 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
+msgid "CodeSuggestions|%{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|A user can be assigned a Code Suggestion seat only once each billable month."
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Code Suggestions seats used"
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
+msgstr ""
+
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
+msgstr ""
+
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
msgstr ""
@@ -11605,6 +11702,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11964,9 +12064,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12195,9 +12292,6 @@ msgstr ""
msgid "ComplianceReport|No projects found that match filters"
msgstr ""
-msgid "ComplianceReport|No projects with standards adherence checks found"
-msgstr ""
-
msgid "ComplianceReport|No violations found"
msgstr ""
@@ -12231,6 +12325,9 @@ msgstr ""
msgid "ComplianceStandardsAdherence|At least two approvals"
msgstr ""
+msgid "ComplianceStandardsAdherence|Failure reason"
+msgstr ""
+
msgid "ComplianceStandardsAdherence|Have a valid rule that prevents author approved merge requests"
msgstr ""
@@ -12240,15 +12337,54 @@ msgstr ""
msgid "ComplianceStandardsAdherence|Have a valid rule that requires any merge request to have more than two approvals"
msgstr ""
+msgid "ComplianceStandardsAdherence|How to fix"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|Merge request approval rules"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|No projects with standards adherence checks found"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|No rule configured to prevent merge requests approved by committers."
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|No rule is configured to prevent author approved merge requests."
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|No rule is configured to require two approvals."
+msgstr ""
+
msgid "ComplianceStandardsAdherence|Prevent authors as approvers"
msgstr ""
msgid "ComplianceStandardsAdherence|Prevent committers as approvers"
msgstr ""
+msgid "ComplianceStandardsAdherence|Requirement"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|The following features help satisfy this requirement."
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|Unable to load the standards adherence report. Refresh the page and try again."
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|Update approval settings in the project's merge request settings to satisfy this requirement."
+msgstr ""
+
msgid "ComplianceStandardsAdherence|View details"
msgstr ""
+msgid "ComplianceViolations|Compliance Violations Export"
+msgstr ""
+
+msgid "ComplianceViolations|Your Compliance Violations CSV export for the group \"%{group_name}\" has been attached to this email."
+msgstr ""
+
+msgid "ComplianceViolations|Your Compliance Violations CSV export for the group %{group_link} has been attached to this email."
+msgstr ""
+
msgid "Component"
msgstr ""
@@ -12288,6 +12424,9 @@ msgstr ""
msgid "Configuration help"
msgstr ""
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
@@ -12360,9 +12499,15 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
+msgid "Configure import sources and settings related to import and export features."
+msgstr ""
+
msgid "Configure pipeline"
msgstr ""
@@ -12531,6 +12676,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13053,6 +13201,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13122,9 +13273,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13212,6 +13372,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13758,6 +13927,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14136,9 +14308,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14250,9 +14419,6 @@ msgstr ""
msgid "Custom range"
msgstr ""
-msgid "Custom range (UTC)"
-msgstr ""
-
msgid "Customer contacts"
msgstr ""
@@ -14477,9 +14643,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14655,6 +14818,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14745,6 +14911,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15475,9 +15644,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15600,9 +15766,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15823,6 +15986,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15841,6 +16007,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16341,9 +16510,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16392,9 +16558,6 @@ msgstr ""
msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
-msgstr ""
-
msgid "Deployment|Triggerer"
msgstr ""
@@ -16470,12 +16633,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17124,6 +17281,9 @@ msgstr ""
msgid "Do not force push over diverged refs. After the mirror is created, this setting can only be modified using the API. %{mirroring_docs_link_start}Learn more about this option%{link_closing_tag} and %{mirroring_api_docs_link_start}the API.%{link_closing_tag}"
msgstr ""
+msgid "Do not include the username in the URL, use the username field below if required: %{code_open}https://gitlab.company.com/group/project.git%{code_close}."
+msgstr ""
+
msgid "Do you want to remove this deploy key?"
msgstr ""
@@ -17856,9 +18016,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17877,10 +18034,13 @@ msgstr ""
msgid "Enable only for confidential applications exclusively used by a trusted backend server that can securely store the client secret. Do not enable for native-mobile, single-page, or other JavaScript applications because they cannot keep the client secret confidential."
msgstr ""
+msgid "Enable or disable keyboard shortcuts in your %{linkStart}user preferences%{linkEnd}."
+msgstr ""
+
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17994,9 +18154,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18093,9 +18250,6 @@ msgstr ""
msgid "Enterprise User Account on GitLab"
msgstr ""
-msgid "EnterpriseUsers|The user detail cannot be updated"
-msgstr ""
-
msgid "EnterpriseUsers|The user does not match the \"Enterprise User\" definition for the group"
msgstr ""
@@ -19220,6 +19374,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19466,6 +19623,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19563,6 +19723,9 @@ msgstr ""
msgid "Failed to delete custom emoji. Please try again."
msgstr ""
+msgid "Failed to delete target branch rule"
+msgstr ""
+
msgid "Failed to deploy to"
msgstr ""
@@ -20123,9 +20286,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20150,9 +20310,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20498,9 +20655,6 @@ msgstr ""
msgid "ForksDivergence|View merge request"
msgstr ""
-msgid "Format: %{dateFormat}"
-msgstr ""
-
msgid "Framework successfully deleted"
msgstr ""
@@ -21215,6 +21369,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21542,6 +21702,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21557,6 +21720,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21710,6 +21876,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21731,6 +21900,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21743,6 +21915,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21812,9 +21987,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21845,6 +22017,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22217,6 +22392,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22283,9 +22461,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22616,6 +22791,9 @@ msgstr ""
msgid "GroupSelect|Select a group"
msgstr ""
+msgid "GroupSettings| %{link_start}What are Experiment features?%{link_end}"
+msgstr ""
+
msgid "GroupSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave empty for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{project_sharing_docs_link_start}project sharing%{link_end} and %{group_sharing_docs_link_start}group sharing%{link_end}."
msgstr ""
@@ -22688,6 +22866,12 @@ msgstr ""
msgid "GroupSettings|Enable overview background aggregation for Value Streams Dashboard"
msgstr ""
+msgid "GroupSettings|Enabling these features is your acceptance of the %{link_start}GitLab Testing Agreement%{link_end}."
+msgstr ""
+
+msgid "GroupSettings|Experiment features"
+msgstr ""
+
msgid "GroupSettings|Export group"
msgstr ""
@@ -22766,6 +22950,9 @@ msgstr ""
msgid "GroupSettings|There was a problem updating the pipeline settings: %{error_messages}."
msgstr ""
+msgid "GroupSettings|These features can cause performance and stability issues and may change over time."
+msgstr ""
+
msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
msgstr ""
@@ -22778,6 +22965,9 @@ msgstr ""
msgid "GroupSettings|Transfer group"
msgstr ""
+msgid "GroupSettings|Use Experiment features"
+msgstr ""
+
msgid "GroupSettings|Users can create %{link_start_project}project access tokens%{link_end} and %{link_start_group}group access tokens%{link_end} in this group"
msgstr ""
@@ -22850,7 +23040,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22862,7 +23052,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22880,9 +23070,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23304,6 +23491,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23573,6 +23763,9 @@ msgstr ""
msgid "I'm signing up for GitLab because:"
msgstr ""
+msgid "I'm sorry, I was not able to find any documentation to answer your question."
+msgstr ""
+
msgid "ID"
msgstr ""
@@ -23609,6 +23802,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23828,6 +24027,9 @@ msgstr ""
msgid "IdentityVerification|Your verification code expires after %{expires_in_minutes} minutes."
msgstr ""
+msgid "Identity|Active"
+msgstr ""
+
msgid "Identity|Provider ID"
msgstr ""
@@ -24012,6 +24214,9 @@ msgstr ""
msgid "Import and export rate limits"
msgstr ""
+msgid "Import and export settings"
+msgstr ""
+
msgid "Import failed due to a GitHub error: %{original} (HTTP %{code})"
msgstr ""
@@ -24209,10 +24414,10 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
-msgid "Import|Maximum import remote file size (MB)"
+msgid "Import|Maximum import remote file size (MiB)"
msgstr ""
msgid "Import|Maximum remote file size for imports from external object storages. For example, AWS S3."
@@ -24236,6 +24441,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24275,390 +24486,60 @@ msgstr ""
msgid "In use"
msgstr ""
-msgid "InProductMarketing|%{organization_name} logo"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
-msgid "InProductMarketing|Advanced security testing"
-msgstr ""
-
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
-msgid "InProductMarketing|Deliver Better Products Faster"
-msgstr ""
-
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
+msgid "InProductMarketing|Built-in security"
msgstr ""
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
+msgid "InProductMarketing|Ensure compliance"
msgstr ""
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
-msgid "InProductMarketing|Free 30-day trial"
-msgstr ""
-
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
-msgid "InProductMarketing|Increase Operational Efficiencies"
-msgstr ""
-
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
-msgid "InProductMarketing|No credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
-msgid "InProductMarketing|Portfolio management"
-msgstr ""
-
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
-msgid "InProductMarketing|Reduce Security and Compliance Risk"
-msgstr ""
-
-msgid "InProductMarketing|Security risk mitigation"
-msgstr ""
-
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
+msgid "InProductMarketing|No credit card required"
msgstr ""
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
+msgid "InProductMarketing|Start your 30-day free trial"
msgstr ""
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
-msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
-msgstr ""
-
-msgid "InProductMarketing|Value stream management"
-msgstr ""
-
msgid "InProductMarketing|Want to get your iOS app up and running, including publishing all the way to TestFlight? Follow our guide to set up GitLab and fastlane to publish iOS apps to the App Store."
msgstr ""
@@ -24668,66 +24549,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25028,9 +24858,6 @@ msgstr ""
msgid "Include the name of the author of the issue, merge request or comment in the email body. By default, GitLab overrides the email sender's name. Some email servers don't support that option."
msgstr ""
-msgid "Include the username in the URL if required: %{code_open}https://username@gitlab.company.com/group/project.git%{code_close}."
-msgstr ""
-
msgid "Includes LFS objects. It can be overridden per group, or per project. Set to 0 for no limit."
msgstr ""
@@ -25157,6 +24984,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25297,7 +25134,7 @@ msgstr ""
msgid "Integrations"
msgstr ""
-msgid "Integrations|%{integrationTitle}: active"
+msgid "Integrations|%{integrationTitle}: %{status}"
msgstr ""
msgid "Integrations|%{integration} settings saved and active."
@@ -25513,6 +25350,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25549,15 +25389,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25582,9 +25416,6 @@ msgstr ""
msgid "Invalid date format. Please use UTC format as YYYY-MM-DD"
msgstr ""
-msgid "Invalid date range"
-msgstr ""
-
msgid "Invalid dates set"
msgstr ""
@@ -25702,12 +25533,6 @@ msgstr ""
msgid "InviteEmail|You have been invited to join the %{project_or_group_name} %{project_or_group} as a %{role}"
msgstr ""
-msgid "InviteEmail|You were assigned the following tasks:"
-msgstr ""
-
-msgid "InviteEmail|and has assigned you the following tasks:"
-msgstr ""
-
msgid "InviteMembersBanner|Collaborate with your team"
msgstr ""
@@ -25732,18 +25557,12 @@ msgstr ""
msgid "InviteMembersModal|Cancel"
msgstr ""
-msgid "InviteMembersModal|Choose a project for the issues"
-msgstr ""
-
msgid "InviteMembersModal|Close invite team members"
msgstr ""
msgid "InviteMembersModal|Congratulations on creating your project, you're almost there!"
msgstr ""
-msgid "InviteMembersModal|Create issues for your new team member to work on (optional)"
-msgstr ""
-
msgid "InviteMembersModal|During your trial, you can invite as many members to %{groupName} as you like. When the trial ends, you'll have a maximum of %{dashboardLimit} members on the Free tier. To get more members, %{linkStart}upgrade to a paid plan%{linkEnd}."
msgstr ""
@@ -25809,9 +25628,6 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
-msgstr ""
-
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
@@ -25971,18 +25787,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26232,10 +26042,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26244,16 +26066,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26904,6 +26734,9 @@ msgstr ""
msgid "Job Failed #%{build_id}"
msgstr ""
+msgid "Job ID"
+msgstr ""
+
msgid "Job artifacts"
msgstr ""
@@ -27099,16 +26932,16 @@ msgstr ""
msgid "Jobs|You're about to retry a job that failed because it attempted to deploy code that is older than the latest deployment. Retrying this job could result in overwriting the environment with the older source code."
msgstr ""
-msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id}"
+msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status}"
msgstr ""
-msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source}"
+msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status} for %{mrId} with %{source}"
msgstr ""
-msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into %{target}"
+msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status} for %{ref}"
msgstr ""
-msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}"
+msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into %{target}"
msgstr ""
msgid "Job|%{searchLength} results found for %{searchTerm}"
@@ -27141,6 +26974,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27192,6 +27028,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27288,9 +27127,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27324,6 +27160,9 @@ msgstr ""
msgid "Keep divergent refs"
msgstr ""
+msgid "Keep sidebar visible"
+msgstr ""
+
msgid "Kerberos access denied"
msgstr ""
@@ -27553,9 +27392,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27652,6 +27488,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -27757,9 +27596,6 @@ msgstr ""
msgid "Learn more about shards and replicas in the %{configuration_link_start}Advanced Search configuration%{configuration_link_end} documentation. Changes don't take place until you %{recreated_link_start}recreate%{recreated_link_end} the index."
msgstr ""
-msgid "Learn more in the"
-msgstr ""
-
msgid "Learn more."
msgstr ""
@@ -28353,6 +28189,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28362,6 +28201,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28584,6 +28426,9 @@ msgstr ""
msgid "Manage projects."
msgstr ""
+msgid "Manage rules"
+msgstr ""
+
msgid "Manage two-factor authentication"
msgstr ""
@@ -28767,6 +28612,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28782,6 +28633,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28794,6 +28648,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29100,6 +28957,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29118,9 +29071,6 @@ msgstr ""
msgid "MemberRole|maximum number of Member Roles are already in use by the group hierarchy. Please delete an existing Member Role."
msgstr ""
-msgid "MemberRole|minimal base access level must be %{min_access_level}."
-msgstr ""
-
msgid "MemberRole|must be top-level namespace"
msgstr ""
@@ -29358,6 +29308,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29790,9 +29743,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30772,10 +30722,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30853,10 +30803,10 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
-msgid "Navigation|Code"
+msgid "Navigation|CI/CD settings"
msgstr ""
-msgid "Navigation|Context navigation"
+msgid "Navigation|Code"
msgstr ""
msgid "Navigation|Deploy"
@@ -30874,31 +30824,28 @@ msgstr ""
msgid "Navigation|Frequently visited projects"
msgstr ""
-msgid "Navigation|Groups"
-msgstr ""
-
msgid "Navigation|Groups you visit often will appear here."
msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
-msgid "Navigation|No group matches found"
+msgid "Navigation|Monitor settings"
msgstr ""
-msgid "Navigation|No project matches found"
+msgid "Navigation|Operate"
msgstr ""
-msgid "Navigation|Operate"
+msgid "Navigation|Pin %{title}"
msgstr ""
msgid "Navigation|Pin item"
@@ -30910,25 +30857,19 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
-msgid "Navigation|Projects"
+msgid "Navigation|Primary"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
-msgid "Navigation|Retrieving search results"
-msgstr ""
-
-msgid "Navigation|Search your projects or groups"
+msgid "Navigation|Repository settings"
msgstr ""
msgid "Navigation|Secure"
msgstr ""
-msgid "Navigation|Switch context"
-msgstr ""
-
-msgid "Navigation|There was an error fetching search results."
+msgid "Navigation|Unpin %{title}"
msgstr ""
msgid "Navigation|Unpin item"
@@ -30940,12 +30881,6 @@ msgstr ""
msgid "Navigation|View all my projects"
msgstr ""
-msgid "Navigation|View all your groups"
-msgstr ""
-
-msgid "Navigation|View all your projects"
-msgstr ""
-
msgid "Navigation|Your pinned items appear here."
msgstr ""
@@ -31164,9 +31099,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31374,6 +31306,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31422,13 +31357,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No more than %{max_work_items} work items can be linked at the same time."
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31485,9 +31420,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31539,6 +31471,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -31586,9 +31524,6 @@ msgstr ""
msgid "NorthstarNavigation|New navigation"
msgstr ""
-msgid "NorthstarNavigation|Provide feedback"
-msgstr ""
-
msgid "NorthstarNavigation|Toggle new navigation"
msgstr ""
@@ -32744,6 +32679,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32936,24 +32874,63 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|Manage"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33667,6 +33644,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33814,7 +33794,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34261,9 +34244,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34378,12 +34358,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34834,6 +34808,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34957,9 +34934,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35185,7 +35159,7 @@ msgstr ""
msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please review the %{linkStart}contribution guidelines%{linkEnd} for this project."
+msgid "Please review the %{strong_start}%{contribution_guidelines_start}contribution guidelines%{contribution_guidelines_end}%{strong_end} for this project."
msgstr ""
msgid "Please review the updated escalation policies for %{project_link}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage."
@@ -35389,6 +35363,9 @@ msgstr ""
msgid "Preferences saved."
msgstr ""
+msgid "Preferences|%{link_start}List of keyboard shortcuts%{link_end}"
+msgstr ""
+
msgid "Preferences|Automatically add new list items"
msgstr ""
@@ -35458,6 +35435,9 @@ msgstr ""
msgid "Preferences|Enable integrated code intelligence on code views"
msgstr ""
+msgid "Preferences|Enable keyboard shortcuts"
+msgstr ""
+
msgid "Preferences|Failed to save preferences."
msgstr ""
@@ -35476,6 +35456,9 @@ msgstr ""
msgid "Preferences|Integrations"
msgstr ""
+msgid "Preferences|Keyboard shortcuts"
+msgstr ""
+
msgid "Preferences|Layout width"
msgstr ""
@@ -35593,6 +35576,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35614,6 +35600,9 @@ msgstr ""
msgid "Priority"
msgstr ""
+msgid "Privacy"
+msgstr ""
+
msgid "Private"
msgstr ""
@@ -35716,9 +35705,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35734,12 +35720,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
-msgid "ProductAnalytics|Create a visualization"
-msgstr ""
-
msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
@@ -35773,9 +35753,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35836,6 +35813,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35860,9 +35840,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36529,9 +36506,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36823,6 +36797,9 @@ msgstr ""
msgid "ProjectService|Trigger event for pushes to the repository."
msgstr ""
+msgid "ProjectService|Trigger event when a build is created."
+msgstr ""
+
msgid "ProjectService|Trigger event when a commit is created or updated."
msgstr ""
@@ -36886,6 +36863,9 @@ msgstr ""
msgid "ProjectSettings|Allow anyone to pull from Package Registry"
msgstr ""
+msgid "ProjectSettings|Allow skipping the merge train"
+msgstr ""
+
msgid "ProjectSettings|Always show thumbs-up and thumbs-down emoji buttons on issues, merge requests, and snippets."
msgstr ""
@@ -37105,6 +37085,9 @@ msgstr ""
msgid "ProjectSettings|Merge requests approved for merge are queued, and pipelines validate the combined results of the source and target branches before merge. %{link_start}What are merge trains?%{link_end}"
msgstr ""
+msgid "ProjectSettings|Merge requests can be set to merge immediately without interrupting the merge train. Commits in earlier merge train pipelines might not get validated with immediately merged commits."
+msgstr ""
+
msgid "ProjectSettings|Merge suggestions"
msgstr ""
@@ -37723,9 +37706,6 @@ msgstr ""
msgid "PrometheusService|Monitor application health with Prometheus metrics and dashboards"
msgstr ""
-msgid "PrometheusService|More information"
-msgstr ""
-
msgid "PrometheusService|New metric"
msgstr ""
@@ -38059,6 +38039,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38131,7 +38117,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38204,6 +38190,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38282,9 +38271,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38351,9 +38337,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38612,9 +38595,6 @@ msgstr ""
msgid "Quick help"
msgstr ""
-msgid "Quick range"
-msgstr ""
-
msgid "README"
msgstr ""
@@ -38714,9 +38694,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38857,34 +38834,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38920,6 +38873,9 @@ msgstr ""
msgid "Related issues"
msgstr ""
+msgid "Related jobs"
+msgstr ""
+
msgid "Related merge request %{link_to_merge_request} to merge %{link_to_merge_request_source_branch}"
msgstr ""
@@ -39219,9 +39175,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39234,6 +39187,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39243,9 +39199,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39525,12 +39478,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39837,9 +39784,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40253,6 +40197,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40683,6 +40630,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41052,6 +41002,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41372,9 +41325,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41387,7 +41337,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41522,9 +41472,6 @@ msgstr ""
msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
-msgstr ""
-
msgid "ScanResultPolicy|Choose criteria type"
msgstr ""
@@ -41534,6 +41481,9 @@ msgstr ""
msgid "ScanResultPolicy|Customized CI Variables"
msgstr ""
+msgid "ScanResultPolicy|Don't show me this again"
+msgstr ""
+
msgid "ScanResultPolicy|Except"
msgstr ""
@@ -41546,6 +41496,12 @@ msgstr ""
msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
msgstr ""
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} for approval rules created by this policy."
+msgstr ""
+
msgid "ScanResultPolicy|Is"
msgstr ""
@@ -41561,13 +41517,13 @@ msgstr ""
msgid "ScanResultPolicy|Matching"
msgstr ""
-msgid "ScanResultPolicy|New age"
+msgid "ScanResultPolicy|Merge request approval settings"
msgstr ""
-msgid "ScanResultPolicy|New attribute"
+msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41579,9 +41535,6 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
-msgstr ""
-
msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
@@ -41594,6 +41547,27 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent approval by anyone who added a commit"
+msgstr ""
+
+msgid "ScanResultPolicy|Prevent approval by merge request's author"
+msgstr ""
+
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
+msgid "ScanResultPolicy|Recommended setting"
+msgstr ""
+
+msgid "ScanResultPolicy|Remove all approvals when commit is added"
+msgstr ""
+
+msgid "ScanResultPolicy|Require the user's password to approve"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41621,9 +41595,24 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|When enabled, two person approval will be required on all MRs as merge request authors cannot approve their own MRs and merge them unilaterally"
+msgstr ""
+
+msgid "ScanResultPolicy|You have selected any protected branch option as a condition. To better protect your project, it is recommended to enable the protect branch settings. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41681,9 +41670,6 @@ msgstr ""
msgid "Schedules to merge this merge request (%{strategy})."
msgstr ""
-msgid "Scheduling Pipelines"
-msgstr ""
-
msgid "Scope"
msgstr ""
@@ -41735,6 +41721,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41804,13 +41793,13 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
+msgid "Search or filter dependencies..."
msgstr ""
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42198,6 +42187,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42207,7 +42202,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42264,6 +42265,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42336,7 +42340,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42348,16 +42352,19 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
-msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
+msgid "SecurityOrchestration|Hide extra branches"
msgstr ""
-msgid "SecurityOrchestration|Important info about protected branch"
+msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
msgid "SecurityOrchestration|Individual users"
@@ -42638,16 +42645,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
-msgstr ""
-
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When this policy is enabled, protected branches cannot be unprotected and users will not be allowed to force push to protected branches."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42689,7 +42693,7 @@ msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42773,9 +42777,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42830,6 +42831,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42845,9 +42849,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42878,6 +42888,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42995,9 +43008,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43042,7 +43052,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43390,9 +43400,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43483,6 +43490,9 @@ msgstr ""
msgid "Service usage data"
msgstr ""
+msgid "ServiceAccount|No more seats are available to create Service Account User"
+msgstr ""
+
msgid "ServiceAccount|User does not have permission to create a service account in this namespace."
msgstr ""
@@ -43513,7 +43523,7 @@ msgstr ""
msgid "ServiceDesk|Configure a custom email address"
msgstr ""
-msgid "ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials."
+msgid "ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials. %{linkStart}Learn more about prerequisites and the verification process%{linkEnd}."
msgstr ""
msgid "ServiceDesk|Copy Service Desk email address"
@@ -43711,6 +43721,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43831,6 +43844,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43861,9 +43877,6 @@ msgstr ""
msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
msgstr ""
-msgid "Set visibility of project contents. Configure import sources and Git access protocols."
-msgstr ""
-
msgid "Set weight"
msgstr ""
@@ -43909,6 +43922,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44136,9 +44152,6 @@ msgstr ""
msgid "Show project milestones"
msgstr ""
-msgid "Show sidebar"
-msgstr ""
-
msgid "Show sub-group milestones"
msgstr ""
@@ -44390,6 +44403,27 @@ msgstr ""
msgid "Signing in using your %{label} account without a pre-existing GitLab account is not allowed."
msgstr ""
+msgid "SilentMode|All outbound communications are blocked. %{link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "SilentMode|Enable silent mode"
+msgstr ""
+
+msgid "SilentMode|Silent mode"
+msgstr ""
+
+msgid "SilentMode|Silent mode %{status}"
+msgstr ""
+
+msgid "SilentMode|Silent mode is enabled"
+msgstr ""
+
+msgid "SilentMode|Suppress outbound communication, such as emails, from GitLab."
+msgstr ""
+
+msgid "SilentMode|There was an error updating the Silent Mode Settings."
+msgstr ""
+
msgid "Similar issues"
msgstr ""
@@ -44744,6 +44778,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44837,9 +44874,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45788,6 +45822,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45956,6 +46002,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46486,9 +46535,6 @@ msgstr ""
msgid "Tags this commit to %{tag_name}."
msgstr ""
-msgid "Tags:"
-msgstr ""
-
msgid "TagsPage|Are you sure you want to delete this tag?"
msgstr ""
@@ -46617,6 +46663,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46629,34 +46678,37 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
msgstr ""
-msgid "Target branch: %{target_branch}"
+msgid "Target branch rule created."
msgstr ""
-msgid "Target roles"
+msgid "Target branch rule deleted."
msgstr ""
-msgid "Target-Branch"
+msgid "Target branch rule does not exist"
msgstr ""
-msgid "Task"
+msgid "Target branch rules"
msgstr ""
-msgid "Task ID: %{elastic_task}"
+msgid "Target branch: %{target_branch}"
msgstr ""
-msgid "Task list"
+msgid "Target roles"
+msgstr ""
+
+msgid "Target-Branch"
msgstr ""
-msgid "TasksToBeDone|Create/import code into a project (repository)"
+msgid "Task"
msgstr ""
-msgid "TasksToBeDone|Create/import issues (tickets) to collaborate on ideas and plan work"
+msgid "Task ID: %{elastic_task}"
msgstr ""
-msgid "TasksToBeDone|Set up CI/CD pipelines to build, test, deploy, and monitor code"
+msgid "Task list"
msgstr ""
msgid "Tasks|%{complete_count} of %{total_count} %{checklist_item_noun} completed"
@@ -46722,6 +46774,9 @@ msgstr ""
msgid "Terminal sync service is running"
msgstr ""
+msgid "Terms"
+msgstr ""
+
msgid "Terms of Service Agreement and Privacy Policy"
msgstr ""
@@ -47084,10 +47139,10 @@ msgstr ""
msgid "That's it, well done!"
msgstr ""
-msgid "The %{link_start}true-up model%{link_end} allows having more users, and additional users will incur a retroactive charge on renewal."
+msgid "The %{plan_name} is no longer available to purchase. For more information about how this will impact you, check our %{faq_link_start}frequently asked questions%{faq_link_end}."
msgstr ""
-msgid "The %{plan_name} is no longer available to purchase. For more information about how this will impact you, check our %{faq_link_start}frequently asked questions%{faq_link_end}."
+msgid "The %{true_up_start}true-up model%{true_up_end} allows having more users, and additional users will incur a retroactive charge on renewal."
msgstr ""
msgid "The %{type} contains the following error:"
@@ -47306,9 +47361,6 @@ msgstr[1] ""
msgid "The form contains the following warning:"
msgstr ""
-msgid "The full package metadata sync can add up to 30 GB to GitLab PostgreSQL database. Ensure you have provisioned enough disk space for the database before enabling this feature. We are actively working on reducing this data size in %{link_start}epic 10415%{link_end}."
-msgstr ""
-
msgid "The git server, Gitaly, is not available at this time. Please contact your administrator."
msgstr ""
@@ -47327,6 +47379,9 @@ msgstr ""
msgid "The group_project_ids parameter is only allowed for a group"
msgstr ""
+msgid "The hook URL has changed, and this log entry cannot be retried"
+msgstr ""
+
msgid "The hostname of your PlantUML server."
msgstr ""
@@ -47462,9 +47517,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47477,9 +47529,6 @@ msgstr ""
msgid "The pipeline has been deleted"
msgstr ""
-msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
-msgstr ""
-
msgid "The project has already been added to your dashboard."
msgstr ""
@@ -47639,6 +47688,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47657,9 +47709,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47909,6 +47958,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48338,7 +48390,7 @@ msgstr ""
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the number of %{billable_users_link_start}billable users%{link_end} on your installation, and this is the minimum number you need to purchase when you renew your license."
+msgid "This is the number of %{billable_users_link_start}billable users%{billable_users_link_end} on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
msgid "This is the only time the secret is accessible. Copy the secret and store it securely."
@@ -48500,9 +48552,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48521,10 +48579,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48674,7 +48732,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48800,7 +48858,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48821,7 +48879,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49526,6 +49584,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49606,6 +49667,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49636,9 +49700,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49711,6 +49781,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49896,7 +49978,7 @@ msgstr ""
msgid "Trigger token:"
msgstr ""
-msgid "Trigger variables:"
+msgid "Trigger variables"
msgstr ""
msgid "Trigger was created successfully."
@@ -50076,9 +50158,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50166,6 +50245,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50199,9 +50281,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50280,6 +50359,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50643,6 +50725,9 @@ msgstr ""
msgid "UsageQuota|%{percentageRemaining}%% namespace storage remaining."
msgstr ""
+msgid "UsageQuota|%{percentageRemaining}%% purchased storage remaining."
+msgstr ""
+
msgid "UsageQuota|%{storage_limit_link_start}A namespace storage limit%{link_end} will soon be enforced for the %{strong_start}%{namespace_name}%{strong_end} namespace. %{extra_message}"
msgstr ""
@@ -50655,6 +50740,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50727,6 +50815,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50808,9 +50899,15 @@ msgstr ""
msgid "UsageQuota|This namespace has no projects which used shared runners in the current period"
msgstr ""
+msgid "UsageQuota|This namespace is under project-level limits, so only repository and LFS storage usage above the limit included in the plan is counted as excess storage. You can increase excess storage limit by purchasing storage packages."
+msgstr ""
+
msgid "UsageQuota|This table omits projects that used 0 compute minutes or 0 shared runners duration"
msgstr ""
+msgid "UsageQuota|Total excess storage"
+msgstr ""
+
msgid "UsageQuota|Total purchased storage"
msgstr ""
@@ -51464,6 +51561,9 @@ msgstr ""
msgid "Username (optional)"
msgstr ""
+msgid "Username and Password"
+msgstr ""
+
msgid "Username is already taken."
msgstr ""
@@ -51473,6 +51573,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51893,6 +51996,9 @@ msgstr ""
msgid "View alert details."
msgstr ""
+msgid "View all"
+msgstr ""
+
msgid "View all environments."
msgstr ""
@@ -52176,6 +52282,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52203,16 +52312,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52572,9 +52684,6 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -52941,6 +53050,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53043,15 +53158,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53409,6 +53515,9 @@ msgstr ""
msgid "Work items are already linked"
msgstr ""
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53471,6 +53580,12 @@ msgid_plural "WorkItem|Assignees"
msgstr[0] ""
msgstr[1] ""
+msgid "WorkItem|Blocked by"
+msgstr ""
+
+msgid "WorkItem|Blocking"
+msgstr ""
+
msgid "WorkItem|Cancel"
msgstr ""
@@ -53501,9 +53616,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53522,9 +53634,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53543,13 +53652,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53594,6 +53709,9 @@ msgstr ""
msgid "WorkItem|Promoted to objective."
msgstr ""
+msgid "WorkItem|Related to"
+msgstr ""
+
msgid "WorkItem|Remove"
msgstr ""
@@ -53693,9 +53811,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53726,7 +53841,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53825,9 +53940,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53965,7 +54077,7 @@ msgstr ""
msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
+msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see%{commentText} this %{issuableType}."
msgstr ""
msgid "You are going to turn on confidentiality. Only %{context} members with %{strongStart}%{permissions}%{strongEnd} can view or be notified about this %{issuableType}."
@@ -54088,6 +54200,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54097,6 +54212,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54295,9 +54413,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54378,6 +54493,9 @@ msgstr ""
msgid "You have insufficient permissions to create an on-call schedule for this project"
msgstr ""
+msgid "You have insufficient permissions to delete a target branch rule"
+msgstr ""
+
msgid "You have insufficient permissions to manage alerts for this project"
msgstr ""
@@ -54552,7 +54670,7 @@ msgstr ""
msgid "You won't be able to create new projects because you have reached your project limit."
msgstr ""
-msgid "You'll be charged for %{true_up_link_start}users over license%{link_end} on a quarterly or annual basis, depending on the terms of your agreement."
+msgid "You'll be charged for %{true_up_start}users over license%{true_up_end} on a quarterly or annual basis, depending on the terms of your agreement."
msgstr ""
msgid "You'll be signed out from your current account automatically."
@@ -54794,9 +54912,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54916,9 +55031,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54943,6 +55055,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55112,6 +55227,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55742,6 +55860,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55809,6 +55930,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55895,9 +56019,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56161,6 +56282,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56555,7 +56679,7 @@ msgstr ""
msgid "mrWidget|The %{type} branch %{codeStart}%{name}%{codeEnd} does not exist."
msgstr ""
-msgid "mrWidget|The source branch is %{link} the target branch"
+msgid "mrWidget|The source branch is %{link} the target branch."
msgstr ""
msgid "mrWidget|This merge request failed to be merged automatically"
@@ -56636,6 +56760,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56675,6 +56802,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56732,6 +56862,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56749,6 +56882,9 @@ msgstr[1] ""
msgid "or"
msgstr ""
+msgid "or sign in with"
+msgstr ""
+
msgid "organizations can only be added to root groups"
msgstr ""
@@ -56790,9 +56926,6 @@ msgstr ""
msgid "pipeline"
msgstr ""
-msgid "pipeline schedules documentation"
-msgstr ""
-
msgid "pipelineEditorWalkthrough|Let's do this!"
msgstr ""
@@ -57033,6 +57166,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57075,6 +57211,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57123,9 +57262,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57182,6 +57318,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po
index 44d622b2706..f994eb117b7 100644
--- a/locale/gl_ES/gitlab.po
+++ b/locale/gl_ES/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: gl\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr " %{start} a %{end}"
@@ -45,6 +45,11 @@ msgstr " e "
msgid " and %{sliced}"
msgstr " e %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " ou "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po
index ccab955fd50..fd964442731 100644
--- a/locale/he_IL/gitlab.po
+++ b/locale/he_IL/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: he\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:59\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -47,6 +47,13 @@ msgstr " ×•×’× "
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr " ×ו "
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -910,7 +914,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -988,6 +992,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1063,6 +1073,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,10 +1564,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1663,6 +1676,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "קבלת הזמנה"
@@ -2730,6 +2782,9 @@ msgstr "קבוצות"
msgid "AccessDropdown|Roles"
msgstr "תפקידי×"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "משתמשי×"
@@ -2910,6 +2965,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3222,6 +3280,9 @@ msgstr "הוספת הצעה ל×וסף"
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "הוספת טקסט לעמוד הכניסה. ×פשר Markdown."
@@ -3246,6 +3307,9 @@ msgstr "הוספה לסקירה"
msgid "Add to tree"
msgstr "הוספה לעץ"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3273,7 +3337,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4113,7 +4177,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4737,6 +4801,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5175,9 +5242,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5268,6 +5332,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5455,6 +5522,9 @@ msgstr[3] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5470,6 +5540,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6595,7 +6689,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6750,6 +6844,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6966,6 +7063,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8053,6 +8159,9 @@ msgstr[3] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8065,6 +8174,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8171,9 +8292,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8261,9 +8379,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,7 +9555,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9827,6 +9942,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9979,7 +10100,7 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10435,15 +10559,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10703,6 +10833,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11000,15 +11133,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11301,6 +11428,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11325,6 +11455,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11748,9 +11881,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12383,7 +12513,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12599,15 +12729,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12671,6 +12804,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14429,9 +14616,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16342,6 +16532,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16369,7 +16565,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16384,7 +16580,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16408,6 +16604,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16468,7 +16667,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16486,10 +16685,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16661,6 +16863,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16676,12 +16896,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17963,9 +18180,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18008,6 +18222,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18146,9 +18363,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18398,7 +18609,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18545,12 +18756,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18596,6 +18813,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19737,6 +19972,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21852,6 +22063,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22008,7 +22219,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22128,9 +22348,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22527,6 +22753,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22593,9 +22822,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22971,7 +23197,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23160,7 +23386,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23172,7 +23398,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23190,9 +23416,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23618,6 +23841,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23883,9 +24109,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23925,6 +24148,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24108,6 +24337,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24984,66 +24916,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25867,15 +25765,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26294,18 +26183,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26555,10 +26438,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26567,16 +26462,26 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27458,6 +27369,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27509,6 +27423,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27605,9 +27522,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27973,6 +27884,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28688,6 +28602,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29117,6 +29043,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29129,6 +29058,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29435,6 +29367,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31225,15 +31259,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31252,12 +31289,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31276,6 +31319,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31712,6 +31758,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31736,6 +31785,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,10 +31809,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31814,9 +31872,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33087,6 +33148,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33279,24 +33340,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34012,6 +34109,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34159,7 +34259,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34606,9 +34709,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34723,12 +34823,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35179,6 +35273,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35827,9 +35921,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35941,6 +36032,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36877,9 +36962,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37504,6 +37592,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37576,6 +37667,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38395,6 +38489,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39048,9 +39151,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39581,9 +39657,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40187,9 +40254,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42150,13 +42262,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results..."
-msgstr ""
-
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42407,6 +42516,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44095,6 +44333,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46203,6 +46459,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46221,6 +46480,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46898,7 +47163,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47940,9 +48211,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48276,6 +48547,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,10 +49081,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48954,7 +49234,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,7 +49360,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49101,7 +49381,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50966,10 +51273,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51083,13 +51393,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51765,6 +52075,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53333,15 +53661,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53817,9 +54139,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56141,6 +56469,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56229,9 +56560,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57398,6 +57741,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57440,6 +57786,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57488,9 +57837,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/hi_IN/gitlab.po b/locale/hi_IN/gitlab.po
index 540292123d9..0035adafbdb 100644
--- a/locale/hi_IN/gitlab.po
+++ b/locale/hi_IN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: hi\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/hr_HR/gitlab.po b/locale/hr_HR/gitlab.po
index 6944a9b308e..a4e022f402e 100644
--- a/locale/hr_HR/gitlab.po
+++ b/locale/hr_HR/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: hr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -46,6 +46,12 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid " or "
msgstr ""
@@ -766,9 +772,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -814,7 +817,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -892,6 +895,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -967,6 +976,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1435,10 +1447,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1546,6 +1558,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2041,15 +2056,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2089,12 +2113,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2116,6 +2158,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2131,6 +2176,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2143,6 +2191,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2155,9 +2206,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2362,9 +2410,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2479,6 +2524,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2536,6 +2584,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2587,6 +2638,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2767,6 +2821,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3079,6 +3136,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3103,6 +3163,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3130,7 +3193,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3970,7 +4033,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4594,6 +4657,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5032,9 +5098,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5125,6 +5188,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5311,6 +5377,9 @@ msgstr[2] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5326,6 +5395,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5437,6 +5512,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5482,15 +5560,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5512,6 +5593,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5527,6 +5614,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5569,24 +5659,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6355,9 +6451,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6439,7 +6532,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6589,6 +6682,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6802,6 +6898,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6919,6 +7018,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7846,7 +7948,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7861,15 +7963,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7888,6 +7993,9 @@ msgstr[2] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7900,6 +8008,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7927,6 +8041,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7972,6 +8089,9 @@ msgstr[2] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8005,9 +8125,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8095,9 +8212,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9175,7 +9289,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9271,7 +9385,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9658,6 +9772,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9748,6 +9865,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9808,7 +9928,7 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10063,6 +10183,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10264,15 +10387,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10324,9 +10447,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10348,12 +10468,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10369,9 +10501,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10531,6 +10660,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10828,15 +10960,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11128,6 +11254,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11152,6 +11281,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11575,9 +11707,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11647,31 +11776,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11743,6 +11869,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12103,9 +12232,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12151,6 +12277,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12208,7 +12337,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12424,15 +12553,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12496,6 +12628,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12667,6 +12802,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13192,6 +13330,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13225,6 +13366,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13237,9 +13402,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13327,6 +13501,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13873,6 +14056,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14251,9 +14437,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14593,9 +14776,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14773,6 +14953,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14863,6 +15046,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15085,6 +15271,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15592,9 +15781,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15718,9 +15904,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15946,6 +16129,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15964,6 +16150,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16150,6 +16339,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16177,7 +16372,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16192,7 +16387,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16216,6 +16411,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16276,7 +16474,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16294,10 +16492,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16381,6 +16579,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16453,9 +16657,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16468,6 +16669,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16483,12 +16702,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16558,12 +16780,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17764,9 +17980,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17809,6 +18022,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17947,9 +18163,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17971,7 +18184,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18085,9 +18298,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18199,7 +18409,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18346,12 +18556,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18397,6 +18613,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18433,6 +18655,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18535,6 +18760,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19291,6 +19522,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19537,6 +19771,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20197,9 +20434,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20224,9 +20458,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20596,33 +20827,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21319,6 +21523,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21646,6 +21856,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21661,6 +21874,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21676,12 +21892,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21802,7 +22012,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21820,6 +22030,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21841,6 +22054,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21853,6 +22069,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21922,9 +22141,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21955,6 +22171,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22195,6 +22414,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22210,7 +22435,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22321,6 +22546,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22387,9 +22615,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22765,7 +22990,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22954,7 +23179,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22966,7 +23191,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22984,9 +23209,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23410,6 +23632,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23674,9 +23899,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23716,6 +23938,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23899,6 +24127,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24313,7 +24547,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24340,6 +24574,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24382,381 +24622,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24772,66 +24703,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25261,6 +25141,18 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25618,6 +25510,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25654,15 +25549,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25744,9 +25633,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26080,18 +25966,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26341,10 +26221,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26353,16 +26245,25 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26410,6 +26311,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26746,6 +26650,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27244,6 +27151,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27295,6 +27205,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27391,9 +27304,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27658,9 +27568,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27757,6 +27664,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28465,6 +28375,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28474,6 +28387,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28879,6 +28795,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28894,6 +28816,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28906,6 +28831,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29212,6 +29140,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29473,6 +29497,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29905,9 +29932,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30004,6 +30028,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30886,10 +30913,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30967,6 +30994,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30997,15 +31027,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31024,12 +31057,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31048,6 +31087,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31273,9 +31318,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31483,6 +31525,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31507,6 +31552,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31525,10 +31576,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31585,9 +31639,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31639,6 +31690,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32851,6 +32908,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32878,9 +32938,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33043,24 +33100,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33775,6 +33868,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33922,7 +34018,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34369,9 +34468,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34486,12 +34582,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34942,6 +35032,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35065,9 +35158,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35590,9 +35680,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35704,6 +35791,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35827,9 +35917,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35845,9 +35932,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35884,9 +35968,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35947,6 +36028,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35971,9 +36055,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36205,7 +36286,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36640,9 +36721,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37132,6 +37210,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37267,6 +37351,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37339,6 +37426,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38158,6 +38248,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38230,7 +38326,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38287,10 +38383,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38302,6 +38401,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38320,6 +38422,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38377,9 +38482,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38446,9 +38548,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38809,9 +38908,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38953,34 +39049,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39316,9 +39388,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39331,6 +39400,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39340,9 +39412,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39622,12 +39691,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39940,9 +40003,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40360,6 +40420,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40795,6 +40858,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41083,7 +41149,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41167,6 +41233,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41377,6 +41446,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41485,9 +41557,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41500,7 +41569,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41626,10 +41695,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41644,6 +41716,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41656,7 +41746,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41668,7 +41758,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41680,6 +41770,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41707,9 +41803,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41821,6 +41926,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41890,13 +41998,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42136,6 +42241,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42292,6 +42400,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42301,7 +42415,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42358,6 +42478,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42430,7 +42553,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42442,12 +42565,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42715,6 +42844,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42727,13 +42859,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42763,13 +42895,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42778,6 +42916,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42847,9 +42991,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42904,6 +43045,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42919,9 +43063,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42952,6 +43102,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43069,9 +43222,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43117,7 +43267,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43465,9 +43615,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43537,6 +43684,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43561,12 +43711,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43594,9 +43756,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43606,27 +43774,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43666,15 +43867,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43702,6 +43933,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43822,6 +44056,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43900,6 +44137,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44737,6 +44977,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44830,9 +45073,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45781,6 +46021,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45928,6 +46180,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45946,6 +46201,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46609,6 +46867,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46621,7 +46882,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47461,9 +47728,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47638,6 +47902,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47656,9 +47923,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47908,6 +48172,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47992,6 +48259,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48496,9 +48766,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48517,10 +48793,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48670,7 +48946,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48796,7 +49072,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48817,7 +49093,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49243,7 +49519,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49525,6 +49801,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49606,6 +49885,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49636,9 +49918,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49711,6 +49999,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50077,9 +50377,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50167,6 +50464,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50200,9 +50500,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50281,6 +50578,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50656,6 +50956,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50677,10 +50980,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50728,6 +51031,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50794,13 +51100,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51475,6 +51781,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52180,6 +52489,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52207,16 +52519,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52459,6 +52774,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52573,10 +52891,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52612,6 +52927,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52939,6 +53257,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53041,15 +53365,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53407,6 +53722,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53500,9 +53821,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53521,9 +53839,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53542,13 +53857,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53692,9 +54013,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53725,7 +54043,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53824,9 +54142,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54088,6 +54403,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54097,6 +54415,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54295,9 +54616,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54796,9 +55114,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54919,9 +55234,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54946,6 +55258,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55117,6 +55432,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55228,6 +55546,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55756,6 +56077,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55825,6 +56149,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55912,9 +56239,6 @@ msgstr[2] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56182,6 +56506,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56662,6 +56989,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56671,6 +57001,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56698,6 +57031,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56755,6 +57091,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57064,6 +57403,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57106,6 +57448,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57154,9 +57499,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57214,6 +57556,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/hu_HU/gitlab.po b/locale/hu_HU/gitlab.po
index 97b1f2d04ba..2b2e2b80aef 100644
--- a/locale/hu_HU/gitlab.po
+++ b/locale/hu_HU/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: hu\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/hy_AM/gitlab.po b/locale/hy_AM/gitlab.po
index f85c5983fe9..40768354afb 100644
--- a/locale/hy_AM/gitlab.po
+++ b/locale/hy_AM/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: hy-AM\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po
index 2ededf76f09..ba5b42e56d4 100644
--- a/locale/id_ID/gitlab.po
+++ b/locale/id_ID/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: id\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -44,6 +44,10 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+
msgid " or "
msgstr ""
@@ -574,9 +578,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -622,7 +623,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -700,6 +701,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -775,6 +782,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1203,10 +1213,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1312,6 +1322,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1755,15 +1768,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1803,12 +1825,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1830,6 +1870,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1845,6 +1888,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -1857,6 +1903,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -1869,9 +1918,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2076,9 +2122,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2193,6 +2236,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2250,6 +2296,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2301,6 +2350,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2481,6 +2533,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2793,6 +2848,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2817,6 +2875,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2844,7 +2905,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3684,7 +3745,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4308,6 +4369,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4746,9 +4810,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4839,6 +4900,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5023,6 +5087,9 @@ msgstr[0] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5038,6 +5105,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5147,6 +5220,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5192,15 +5268,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5222,6 +5301,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5237,6 +5322,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5279,24 +5367,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6045,9 +6139,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6127,7 +6218,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6267,6 +6358,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6474,6 +6568,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6591,6 +6688,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7518,7 +7618,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7533,15 +7633,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7558,6 +7661,9 @@ msgstr[0] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7570,6 +7676,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7597,6 +7709,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7640,6 +7755,9 @@ msgstr[0] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7673,9 +7791,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7763,9 +7878,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -8837,7 +8949,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -8933,7 +9045,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9320,6 +9432,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9410,6 +9525,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9466,7 +9584,7 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -9922,15 +10043,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -9982,9 +10103,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10006,12 +10124,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10027,9 +10157,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10187,6 +10314,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10484,15 +10614,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10782,6 +10906,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10806,6 +10933,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11229,9 +11359,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11301,31 +11428,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11753,9 +11880,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11801,6 +11925,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11858,7 +11985,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12074,15 +12201,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12146,6 +12276,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12317,6 +12450,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -12836,6 +12972,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -12869,6 +13008,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -12881,9 +13044,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -12971,6 +13143,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13517,6 +13698,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -13895,9 +14079,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14235,9 +14416,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14411,6 +14589,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14501,6 +14682,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14723,6 +14907,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15226,9 +15413,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15350,9 +15534,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15568,6 +15749,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15586,6 +15770,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15766,6 +15953,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15793,7 +15986,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -15808,7 +16001,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -15832,6 +16025,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -15892,7 +16088,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -15910,10 +16106,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -15997,6 +16193,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16067,9 +16269,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16082,6 +16281,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16097,12 +16314,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16172,12 +16392,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17366,9 +17580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17411,6 +17622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17549,9 +17763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17573,7 +17784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17687,9 +17898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -17801,7 +18009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -17948,12 +18156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -17999,6 +18213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18035,6 +18255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18137,6 +18360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18891,6 +19120,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19137,6 +19369,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19791,9 +20026,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -19818,9 +20050,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20188,33 +20417,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20907,6 +21109,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21234,6 +21442,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21249,6 +21460,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21264,12 +21478,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21390,7 +21598,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21429,6 +21640,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21441,6 +21655,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21510,9 +21727,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21543,6 +21757,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21783,6 +22000,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -21798,7 +22021,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -21975,9 +22201,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22353,7 +22576,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22542,7 +22765,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22554,7 +22777,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22572,9 +22795,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -22994,6 +23214,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23256,9 +23479,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23298,6 +23518,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23481,6 +23707,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23889,7 +24121,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -23916,6 +24148,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -23958,381 +24196,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24348,66 +24277,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24837,6 +24715,14 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25192,6 +25078,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25228,15 +25117,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25318,9 +25201,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25652,18 +25532,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25913,10 +25787,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -25925,16 +25811,23 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -25982,6 +25875,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26318,6 +26214,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26816,6 +26715,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -26867,6 +26769,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -26963,9 +26868,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27226,9 +27128,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27325,6 +27224,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28019,6 +27921,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28028,6 +27933,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28433,6 +28341,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28448,6 +28362,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28460,6 +28377,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28766,6 +28686,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29021,6 +29037,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29453,9 +29472,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29552,6 +29568,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30430,10 +30449,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30511,6 +30530,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30541,15 +30563,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30568,12 +30593,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30592,6 +30623,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -30815,9 +30852,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31025,6 +31059,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31049,6 +31086,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31067,10 +31110,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31127,9 +31173,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31181,6 +31224,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32379,6 +32428,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32406,9 +32458,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32571,24 +32620,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33301,6 +33386,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33448,7 +33536,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33895,9 +33986,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34012,12 +34100,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34468,6 +34550,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34591,9 +34676,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35116,9 +35198,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35230,6 +35309,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35353,9 +35435,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35371,9 +35450,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35410,9 +35486,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35473,6 +35546,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35497,9 +35573,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35731,7 +35804,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36166,9 +36239,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36658,6 +36728,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -36793,6 +36869,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -36865,6 +36944,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37684,6 +37766,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37756,7 +37844,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -37809,10 +37897,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -37824,6 +37915,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -37842,6 +37936,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -37899,9 +37996,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -37968,9 +38062,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38331,9 +38422,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38473,34 +38561,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38834,9 +38898,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -38849,6 +38910,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -38858,9 +38922,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39140,12 +39201,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39446,9 +39501,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -39858,6 +39910,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40283,6 +40338,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40567,7 +40625,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40649,6 +40707,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40857,6 +40918,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -40965,9 +41029,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -40980,7 +41041,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41106,10 +41167,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41124,6 +41188,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41136,7 +41218,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41148,7 +41230,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41160,6 +41242,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41187,9 +41275,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41301,6 +41398,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41370,13 +41470,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41594,6 +41691,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41750,6 +41850,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -41759,7 +41865,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -41888,7 +42003,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -41900,12 +42015,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42171,6 +42292,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42183,13 +42307,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42219,13 +42343,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42234,6 +42364,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42303,9 +42439,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42360,6 +42493,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42375,9 +42511,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42408,6 +42550,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42525,9 +42670,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42571,7 +42713,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -42919,9 +43061,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -42991,6 +43130,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43015,12 +43157,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43048,9 +43202,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43060,27 +43220,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43120,15 +43313,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43156,6 +43379,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43276,6 +43502,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43354,6 +43583,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44187,6 +44419,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44280,9 +44515,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45231,6 +45463,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45378,6 +45622,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45396,6 +45643,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46055,6 +46305,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46067,7 +46320,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47070,6 +47326,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47088,9 +47347,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47340,6 +47596,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47424,6 +47683,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47928,9 +48190,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -47949,10 +48217,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48102,7 +48370,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48228,7 +48496,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48249,7 +48517,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48669,7 +48937,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48951,6 +49219,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49030,6 +49301,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49060,9 +49334,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49135,6 +49415,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49499,9 +49791,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49589,6 +49878,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49622,9 +49914,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49703,6 +49992,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50078,6 +50370,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50099,10 +50394,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50150,6 +50445,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50216,13 +50514,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -50895,6 +51193,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51596,6 +51897,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51623,16 +51927,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -51875,6 +52182,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -51989,10 +52299,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52028,6 +52335,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52355,6 +52665,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52457,15 +52773,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -52817,6 +53124,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -52908,9 +53221,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -52929,9 +53239,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -52950,13 +53257,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53100,9 +53413,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53133,7 +53443,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53232,9 +53542,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53494,6 +53801,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53503,6 +53813,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53701,9 +54014,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54319,9 +54626,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54346,6 +54650,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54513,6 +54820,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54620,6 +54930,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55128,6 +55441,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55193,6 +55509,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55278,9 +55597,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55540,6 +55856,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56010,6 +56329,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56019,6 +56341,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56046,6 +56371,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56103,6 +56431,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56396,6 +56727,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56438,6 +56772,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56486,9 +56823,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56544,6 +56878,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ig_NG/gitlab.po b/locale/ig_NG/gitlab.po
index 9e83cafe833..9a1a0546c20 100644
--- a/locale/ig_NG/gitlab.po
+++ b/locale/ig_NG/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ig\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:37\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -44,6 +44,10 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+
msgid " or "
msgstr ""
@@ -574,9 +578,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -622,7 +623,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -700,6 +701,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -775,6 +782,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1203,10 +1213,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1312,6 +1322,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1755,15 +1768,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1803,12 +1825,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1830,6 +1870,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1845,6 +1888,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -1857,6 +1903,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -1869,9 +1918,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2076,9 +2122,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2193,6 +2236,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2250,6 +2296,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2301,6 +2350,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2481,6 +2533,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2793,6 +2848,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2817,6 +2875,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2844,7 +2905,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3684,7 +3745,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4308,6 +4369,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4746,9 +4810,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4839,6 +4900,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5023,6 +5087,9 @@ msgstr[0] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5038,6 +5105,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5147,6 +5220,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5192,15 +5268,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5222,6 +5301,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5237,6 +5322,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5279,24 +5367,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6045,9 +6139,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6127,7 +6218,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6267,6 +6358,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6474,6 +6568,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6591,6 +6688,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7518,7 +7618,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7533,15 +7633,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7558,6 +7661,9 @@ msgstr[0] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7570,6 +7676,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7597,6 +7709,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7640,6 +7755,9 @@ msgstr[0] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7673,9 +7791,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7763,9 +7878,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -8837,7 +8949,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -8933,7 +9045,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9320,6 +9432,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9410,6 +9525,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9466,7 +9584,7 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -9922,15 +10043,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -9982,9 +10103,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10006,12 +10124,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10027,9 +10157,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10187,6 +10314,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10484,15 +10614,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10782,6 +10906,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10806,6 +10933,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11229,9 +11359,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11301,31 +11428,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11753,9 +11880,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11801,6 +11925,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11858,7 +11985,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12074,15 +12201,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12146,6 +12276,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12317,6 +12450,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -12836,6 +12972,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -12869,6 +13008,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -12881,9 +13044,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -12971,6 +13143,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13517,6 +13698,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -13895,9 +14079,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14235,9 +14416,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14411,6 +14589,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14501,6 +14682,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14723,6 +14907,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15226,9 +15413,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15350,9 +15534,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15568,6 +15749,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15586,6 +15770,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15766,6 +15953,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15793,7 +15986,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -15808,7 +16001,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -15832,6 +16025,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -15892,7 +16088,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -15910,10 +16106,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -15997,6 +16193,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16067,9 +16269,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16082,6 +16281,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16097,12 +16314,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16172,12 +16392,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17366,9 +17580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17411,6 +17622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17549,9 +17763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17573,7 +17784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17687,9 +17898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -17801,7 +18009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -17948,12 +18156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -17999,6 +18213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18035,6 +18255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18137,6 +18360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18891,6 +19120,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19137,6 +19369,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19791,9 +20026,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -19818,9 +20050,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20188,33 +20417,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20907,6 +21109,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21234,6 +21442,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21249,6 +21460,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21264,12 +21478,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21390,7 +21598,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21429,6 +21640,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21441,6 +21655,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21510,9 +21727,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21543,6 +21757,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21783,6 +22000,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -21798,7 +22021,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -21975,9 +22201,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22353,7 +22576,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22542,7 +22765,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22554,7 +22777,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22572,9 +22795,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -22994,6 +23214,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23256,9 +23479,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23298,6 +23518,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23481,6 +23707,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23889,7 +24121,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -23916,6 +24148,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -23958,381 +24196,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24348,66 +24277,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24837,6 +24715,14 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25192,6 +25078,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25228,15 +25117,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25318,9 +25201,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25652,18 +25532,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25913,10 +25787,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -25925,16 +25811,23 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -25982,6 +25875,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26318,6 +26214,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26816,6 +26715,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -26867,6 +26769,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -26963,9 +26868,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27226,9 +27128,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27325,6 +27224,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28019,6 +27921,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28028,6 +27933,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28433,6 +28341,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28448,6 +28362,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28460,6 +28377,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28766,6 +28686,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29021,6 +29037,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29453,9 +29472,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29552,6 +29568,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30430,10 +30449,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30511,6 +30530,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30541,15 +30563,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30568,12 +30593,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30592,6 +30623,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -30815,9 +30852,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31025,6 +31059,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31049,6 +31086,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31067,10 +31110,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31127,9 +31173,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31181,6 +31224,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32379,6 +32428,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32406,9 +32458,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32571,24 +32620,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33301,6 +33386,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33448,7 +33536,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33895,9 +33986,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34012,12 +34100,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34468,6 +34550,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34591,9 +34676,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35116,9 +35198,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35230,6 +35309,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35353,9 +35435,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35371,9 +35450,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35410,9 +35486,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35473,6 +35546,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35497,9 +35573,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35731,7 +35804,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36166,9 +36239,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36658,6 +36728,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -36793,6 +36869,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -36865,6 +36944,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37684,6 +37766,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37756,7 +37844,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -37809,10 +37897,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -37824,6 +37915,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -37842,6 +37936,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -37899,9 +37996,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -37968,9 +38062,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38331,9 +38422,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38473,34 +38561,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38834,9 +38898,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -38849,6 +38910,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -38858,9 +38922,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39140,12 +39201,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39446,9 +39501,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -39858,6 +39910,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40283,6 +40338,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40567,7 +40625,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40649,6 +40707,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40857,6 +40918,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -40965,9 +41029,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -40980,7 +41041,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41106,10 +41167,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41124,6 +41188,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41136,7 +41218,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41148,7 +41230,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41160,6 +41242,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41187,9 +41275,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41301,6 +41398,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41370,13 +41470,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41594,6 +41691,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41750,6 +41850,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -41759,7 +41865,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -41888,7 +42003,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -41900,12 +42015,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42171,6 +42292,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42183,13 +42307,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42219,13 +42343,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42234,6 +42364,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42303,9 +42439,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42360,6 +42493,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42375,9 +42511,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42408,6 +42550,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42525,9 +42670,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42571,7 +42713,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -42919,9 +43061,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -42991,6 +43130,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43015,12 +43157,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43048,9 +43202,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43060,27 +43220,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43120,15 +43313,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43156,6 +43379,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43276,6 +43502,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43354,6 +43583,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44187,6 +44419,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44280,9 +44515,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45231,6 +45463,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45378,6 +45622,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45396,6 +45643,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46055,6 +46305,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46067,7 +46320,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47070,6 +47326,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47088,9 +47347,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47340,6 +47596,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47424,6 +47683,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47928,9 +48190,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -47949,10 +48217,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48102,7 +48370,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48228,7 +48496,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48249,7 +48517,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48669,7 +48937,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48951,6 +49219,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49030,6 +49301,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49060,9 +49334,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49135,6 +49415,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49499,9 +49791,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49589,6 +49878,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49622,9 +49914,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49703,6 +49992,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50078,6 +50370,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50099,10 +50394,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50150,6 +50445,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50216,13 +50514,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -50895,6 +51193,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51596,6 +51897,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51623,16 +51927,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -51875,6 +52182,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -51989,10 +52299,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52028,6 +52335,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52355,6 +52665,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52457,15 +52773,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -52817,6 +53124,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -52908,9 +53221,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -52929,9 +53239,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -52950,13 +53257,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53100,9 +53413,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53133,7 +53443,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53232,9 +53542,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53494,6 +53801,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53503,6 +53813,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53701,9 +54014,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54319,9 +54626,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54346,6 +54650,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54513,6 +54820,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54620,6 +54930,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55128,6 +55441,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55193,6 +55509,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55278,9 +55597,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55540,6 +55856,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56010,6 +56329,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56019,6 +56341,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56046,6 +56371,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56103,6 +56431,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56396,6 +56727,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56438,6 +56772,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56486,9 +56823,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56544,6 +56878,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/is_IS/gitlab.po b/locale/is_IS/gitlab.po
index f33c22dca4c..1a3cd566a2e 100644
--- a/locale/is_IS/gitlab.po
+++ b/locale/is_IS/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: is\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index ab2eab08916..7ab766aea08 100644
--- a/locale/it/gitlab.po
+++ b/locale/it/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: it\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " o "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} non disponibile"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr "+ %{count} ulteriori"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} più"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Sei sicuro di voler cancellare questa pipeline programmata?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Controllo disponibilità per %{text}…"
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "Timezone del Cron"
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr "Definisci un patter personalizzato mediante la sintassi cron"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "E-mail"
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Job"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "Intervallo di Pattern"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr "Ultima Pipeline"
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr "Nuova pianficazione"
-
msgid "New snippet"
msgstr "Nuovo snippet"
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "Nessuna pianificazione"
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr "Opzioni"
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "Attivata"
-
msgid "PipelineSchedules|Active"
msgstr "Attiva"
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Variabili"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protect an environment"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr "Salva pianificazione pipeline"
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index 3bd4e9ab25a..aa10fb3d0bf 100644
--- a/locale/ja/gitlab.po
+++ b/locale/ja/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ja\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr " %{start}ã‹ã‚‰%{end}ã¾ã§"
@@ -44,6 +44,10 @@ msgstr "ã¨"
msgid " and %{sliced}"
msgstr "ã¨%{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] "ブランãƒã‚’除ã:"
+
msgid " or "
msgstr "ã¾ãŸã¯"
@@ -574,9 +578,6 @@ msgstr "%{count}ã‚¿ã‚°"
msgid "%{count} total weight"
msgstr "åˆè¨ˆã‚¦ã‚§ã‚¤ãƒˆ%{count}"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
-
msgid "%{days} days until tags are automatically removed"
msgstr "ã‚¿ã‚°ãŒè‡ªå‹•çš„ã«å‰Šé™¤ã•ã‚Œã‚‹ã¾ã§ %{days} æ—¥"
@@ -622,8 +623,8 @@ msgstr "%{edit_in_new_fork_notice} ã‚‚ã†ä¸€åº¦ãƒ•ã‚¡ã‚¤ãƒ«ã‚’アップロード
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr "Service Pingã‚’%{enable_service_ping_link_start}有効化%{link_end}ã¾ãŸã¯%{generate_manually_link_start}生æˆ%{link_end}ã—ã¦ã€ã‚µãƒ¼ãƒ“ス利用データペイロードをプレビューãŠã‚ˆã³ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ã¾ã™ã€‚"
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr "%{generate_manually_link_end}Service Ping%{enable_service_ping_link_start}を有効化%{enable_service_ping_link_end}ã¾ãŸã¯%{generate_manually_link_start}生æˆã—ã¦ã€ã‚µãƒ¼ãƒ“ス利用データペイロードをプレビューãŠã‚ˆã³ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ã¾ã™ã€‚"
msgid "%{extra} more downstream pipelines"
msgstr "%{extra} 個ã®ãƒ€ã‚¦ãƒ³ã‚¹ãƒˆãƒªãƒ¼ãƒ ãƒ‘イプライン"
@@ -700,6 +701,12 @@ msgstr "最大 %{maxIssueCount} 件中ã€%{issuesSize} 件"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}新機能%{italic_end}ã¯éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–ã§ã€è¡¨ç¤ºã§ãã¾ã›ã‚“。"
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr "権é™ãŒä¸è¶³ã—ã¦ã„ã‚‹ãŸã‚ã€%{item_ids} を削除ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr "%{item_ids} ã¯ãƒªãƒ³ã‚¯ã•ã‚Œã¦ã„ãªã„ãŸã‚削除ã§ãã¾ã›ã‚“ã§ã—ãŸ"
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "上é™%{maxIssueCount}件ã®ã†ã¡%{itemsCount}件ã®ã‚¤ã‚·ãƒ¥ãƒ¼"
@@ -775,6 +782,9 @@ msgstr "%{labelStart}修正ã•ã‚Œã¦ã„ãªã„レスãƒãƒ³ã‚¹:%{labelEnd} %{heade
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} ã¯åˆ©ç”¨ä¸å¯"
+msgid "%{label_name} is locked and was not removed"
+msgstr "%{label_name} ã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã€å‰Šé™¤ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ"
+
msgid "%{label_name} was removed"
msgstr "%{label_name} ã¯å‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
@@ -1203,11 +1213,11 @@ msgstr "%{verb}ã—ã¦%{time_spent_value}ãŒçµŒéŽã—ã¾ã—ãŸã€‚"
msgid "%{verb} this %{noun} as a draft."
msgstr "ã“ã®%{noun}をドラフトã¨ã—ã¦%{verb}"
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end}を使ã†ã¨ã€ã‚°ãƒ«ãƒ¼ãƒ—ã¾ãŸã¯ãƒ—ロジェクトã®ã‚¤ãƒ™ãƒ³ãƒˆã«å¿œã˜ã¦ã‚¦ã‚§ãƒ–アプリケーションã«é€šçŸ¥ã‚’é€ä¿¡ã§ãã¾ã™ã€‚"
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end}を使ã†ã¨ã€ã‚°ãƒ«ãƒ¼ãƒ—ã¾ãŸã¯ãƒ—ロジェクトã®ã‚¤ãƒ™ãƒ³ãƒˆã«å¿œã˜ã¦ã‚¦ã‚§ãƒ–アプリケーションã«é€šçŸ¥ã‚’é€ä¿¡ã§ãã¾ã™ã€‚"
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—ã¾ãŸã¯ãƒ—ロジェクトã®ã‚¤ãƒ™ãƒ³ãƒˆã«å¿œç­”ã—㦠Web アプリケーションã¸é€šçŸ¥ã‚’é€ä¿¡ã§ãるよã†ã«ã—ã¾ã™ã€‚Webhook よりも%{integrations_link_start}インテグレーション%{link_end}を使用ã™ã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚"
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end}を使ã†ã¨ã€ã‚°ãƒ«ãƒ¼ãƒ—ã¾ãŸã¯ãƒ—ロジェクトã®ã‚¤ãƒ™ãƒ³ãƒˆã«å¿œã˜ã¦ã‚¦ã‚§ãƒ–アプリケーションã«é€šçŸ¥ã‚’é€ä¿¡ã§ãã¾ã™ã€‚Webhookよりもã€%{integrations_link_start}インテグレーション%{integrations_link_end}を使用ã™ã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚"
msgid "%{widget} options"
msgstr "%{widget}オプション"
@@ -1312,6 +1322,9 @@ msgstr "+ ãã®ä»– %{amount} 件"
msgid "+ %{count} more"
msgstr "+ %{count}以上"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr "+ %{hiddenBranchesLength}以上"
+
msgid "+ %{moreCount} more"
msgstr "+ 他%{moreCount}件"
@@ -1609,7 +1622,7 @@ msgid "A complete DevOps platform"
msgstr "完全㪠DevOps ã®ãƒ—ラットフォーム"
msgid "A confidential issue must have only confidential children. Make any child items confidential and try again."
-msgstr ""
+msgstr "éžå…¬é–‹ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã®å­ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã¯ã™ã¹ã¦éžå…¬é–‹ã«è¨­å®šã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。対応ã™ã‚‹å­ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’éžå…¬é–‹ã«è¨­å®šã—ã¦ã‹ã‚‰å†è©¦è¡Œã—ã¦ãã ã•ã„。"
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr "éžå…¬é–‹ã®ä½œæ¥­é …ç›®ã¯ã€å…¬é–‹æ¸ˆã¿ã®å­ã‚’æŒã¤è¦ªã‚’æŒã¤ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
@@ -1750,20 +1763,29 @@ msgid "AI| %{link_start}What are Experiment features?%{link_end}"
msgstr "%{link_start}実験的機能ã¨ã¯ä½•ã§ã™ã‹?%{link_end}"
msgid "AI|%{tool} is %{transition} an answer"
-msgstr ""
+msgstr "%{tool} 㯠%{transition} ã®ç­”ãˆã§ã™"
msgid "AI|AI generated explanations will appear here."
msgstr "AIãŒç”Ÿæˆã—ãŸèª¬æ˜Žã‚’ã“ã“ã«è¡¨ç¤ºã—ã¾ã™ã€‚"
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr "%{linkStart}実験的%{linkEnd} ã¯é–‹ç™ºä¸­ã®æ©Ÿèƒ½ã§ã™ã€‚本番環境ã«å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“。ユーザーã«ã¯ã€å®Ÿé¨“çš„ãªæ©Ÿèƒ½ã‚’試ã—ã¦ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã‚’æä¾›ã™ã‚‹ã“ã¨ã‚’ãŠå‹§ã‚ã—ã¾ã™ã€‚実験: %{bullets}"
+
msgid "AI|Apply AI-generated description"
msgstr "AI ã§ç”Ÿæˆã—ãŸèª¬æ˜Žã‚’é©ç”¨"
+msgid "AI|Ask GitLab Duo"
+msgstr "GitLab Duoã«èžã"
+
msgid "AI|Ask a question"
msgstr "質å•ã™ã‚‹"
msgid "AI|Autocomplete"
msgstr "オートコンプリート"
+msgid "AI|Can be removed at any time"
+msgstr "ã„ã¤ã§ã‚‚削除ã§ãã¾ã™"
+
msgid "AI|Close the Code Explanation"
msgstr "コードã®èª¬æ˜Žã‚’é–‰ã˜ã‚‹"
@@ -1801,14 +1823,32 @@ msgid "AI|Generate issue description"
msgstr "イシューã®èª¬æ˜Žã‚’生æˆ"
msgid "AI|GitLab Duo"
+msgstr "GitLab Duo"
+
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
msgstr ""
+msgid "AI|Has no support and might not be documented"
+msgstr "サãƒãƒ¼ãƒˆãŒãªã„ãŸã‚文書化ã•ã‚Œã¦ã„ãªã„å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™"
+
msgid "AI|Helpful"
msgstr "å½¹ã«ç«‹ã¤"
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr "ã©ã®ã‚ˆã†ã«ãŠæ‰‹ä¼ã„ã™ã‚Œã°ã‚ˆã„ã‹ã‚ã‹ã‚Šã¾ã›ã‚“。よりã‚ã‹ã‚Šã‚„ã™ã指示ã—ã¦ãã ã•ã„!"
+msgid "AI|May be unstable"
+msgstr "ä¸å®‰å®šãªå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™"
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr "GitLabã®è¦‹è§£ã‚’代表ã—ã¦ã„ãªã„ã€ä¸é©åˆ‡ãªè¿”答をæä¾›ã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚個人データを入力ã—ãªã„ã§ãã ã•ã„。"
@@ -1830,6 +1870,9 @@ msgstr "ãƒãƒ£ãƒƒãƒˆãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’é€ä¿¡"
msgid "AI|Something went wrong. Please try again later"
msgstr "å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚後ã»ã©ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„"
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr "コンテナè¦ç´ ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚AI Genieã‚’åœæ­¢ã—ã¾ã™ã€‚"
@@ -1845,6 +1888,9 @@ msgstr "ã“れらã®æ©Ÿèƒ½ã¯ãƒ‘フォーマンスã¨å®‰å®šæ€§ã®å•é¡Œã‚’引ã
msgid "AI|Third-party AI services"
msgstr "サードパーティ製AIサービス"
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr "å½¹ã«ç«‹ãŸãªã„"
@@ -1857,6 +1903,9 @@ msgstr "サードパーティ製AIサービスã®ä½¿ç”¨"
msgid "AI|What does the selected code mean?"
msgstr "é¸æŠžã—ãŸã‚³ãƒ¼ãƒ‰ã¯ä½•ã‚’æ„味ã—ã¾ã™ã‹?"
+msgid "AI|What's an Experiment?"
+msgstr "実験ã¨ã¯?"
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr "ç°¡å˜ãªèª¬æ˜Žã‚’入力ã—ã€è©³ç´°ã¯AIã«è¨˜å…¥ã•ã›ã¾ã™ã€‚"
@@ -1869,9 +1918,6 @@ msgstr "é–“é•ã„"
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr "ã“ã®å‡ºåŠ›ã®ä¸€éƒ¨ã‚’次ã®ã‚‚ã®ã«ã‚³ãƒ”ーã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“:イシューã€ã‚³ãƒ¡ãƒ³ãƒˆã€GitLabã®ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã€ã‚³ãƒŸãƒƒãƒˆãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã€%{gitlabOrg}ã¾ãŸã¯%{gitlabCom}グループ内ã®ãã®ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ã‚¤ã‚¹ã€‚"
-msgid "AI|You can ask AI for more information."
-msgstr "AIã«è©³ç´°æƒ…報を求ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
-
msgid "AI|finding"
msgstr "発見"
@@ -1978,7 +2024,7 @@ msgid "APIFuzzing|Tip: Insert this part below all stages"
msgstr "ヒント: ã“ã®éƒ¨åˆ†ã‚’ã™ã¹ã¦ã®stageã®ä¸‹ã«æŒ¿å…¥ã—ã¾ã™"
msgid "APIFuzzing|To prevent a security leak, authentication info must be added as a %{ciVariablesLinkStart}CI variable%{ciVariablesLinkEnd}. A user with maintainer access rights can manage CI variables in the %{ciSettingsLinkStart}Settings%{ciSettingsLinkEnd} area. We detected that you are not a maintainer. Commit your changes and assign them to a maintainer to update the credentials before merging."
-msgstr ""
+msgstr "情報æ¼æ´©ã‚’防ããŸã‚ã«ã€èªè¨¼æƒ…報を%{ciVariablesLinkStart}CI変数%{ciVariablesLinkEnd}ã«è¿½åŠ ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚メンテナーã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ã€%{ciSettingsLinkStart}設定%{ciSettingsLinkEnd}ã§CI変数を管ç†ã§ãã¾ã™ã€‚ã‚ãªãŸãŒãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼ã§ã¯ãªã„ã“ã¨ãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸã€‚変更をコミットã—ã€ãれらをメンテナーã«å‰²ã‚Šå½“ã¦ã¦ã€ãƒžãƒ¼ã‚¸ã™ã‚‹å‰ã«èªè¨¼æƒ…報を更新ã—ã¦ãã ã•ã„。"
msgid "APIFuzzing|To prevent a security leak, authentication info must be added as a %{ciVariablesLinkStart}CI variable%{ciVariablesLinkEnd}. As a user with maintainer access rights, you can manage CI variables in the %{ciSettingsLinkStart}Settings%{ciSettingsLinkEnd} area."
msgstr "情報æ¼æ´©ã‚’防ããŸã‚ã«ã€èªè¨¼æƒ…報を%{ciVariablesLinkStart}CI変数%{ciVariablesLinkEnd}ã«è¿½åŠ ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚メンテナーã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¨ã—ã¦ã€%{ciSettingsLinkStart}設定%{ciSettingsLinkEnd}ã§CI変数を管ç†ã§ãã¾ã™ã€‚"
@@ -2076,9 +2122,6 @@ msgstr "レãƒãƒ¼ãƒˆãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr "%{category}ã¨ã—ã¦%{timeAgo}ã«%{reportLinkStart}報告済ã¿%{reportLinkEnd}"
-msgid "AbuseReport|Abuse reports"
-msgstr "ä¸æ­£åˆ©ç”¨ã®å ±å‘Š"
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr "ä¸æ­£åˆ©ç”¨ã¯æœªç¢ºèª"
@@ -2193,6 +2236,9 @@ msgstr "攻撃的ã¾ãŸã¯è™å¾…çš„"
msgid "AbuseReport|Other"
msgstr "ãã®ä»–"
+msgid "AbuseReport|Past abuse reports"
+msgstr "éŽåŽ»ã®ä¸æ­£åˆ©ç”¨ã®å ±å‘Š"
+
msgid "AbuseReport|Personal information or credentials"
msgstr "個人情報ã¾ãŸã¯è³‡æ ¼æƒ…å ±"
@@ -2250,6 +2296,9 @@ msgstr "検証"
msgid "AbuseReport|View screenshot"
msgstr "スクリーンショットを表示"
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "招待をå—ã‘入れる"
@@ -2301,6 +2350,9 @@ msgstr "グループ"
msgid "AccessDropdown|Roles"
msgstr "役割"
+msgid "AccessDropdown|Select"
+msgstr "é¸æŠž"
+
msgid "AccessDropdown|Users"
msgstr "ユーザー"
@@ -2481,6 +2533,9 @@ msgstr "承èªã™ã‚‹"
msgid "Action"
msgstr "アクション"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr "レジストリ%{registry_id}エントリã§ã®ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã€Œ%{action}ã€ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。"
@@ -2515,7 +2570,7 @@ msgid "Active personal access tokens"
msgstr "有効ãªãƒ‘ーソナルアクセストークン"
msgid "Active pipeline trigger tokens"
-msgstr ""
+msgstr "有効ãªãƒ‘イプライントリガートークン"
msgid "Active project access tokens"
msgstr "有効ãªãƒ—ロジェクトアクセストークン"
@@ -2743,10 +2798,10 @@ msgid "Add new key"
msgstr "æ–°ã—ã„キーを追加"
msgid "Add new pipeline subscription"
-msgstr ""
+msgstr "æ–°ã—ã„パイプラインサブスクリプションを追加"
msgid "Add new pipeline trigger token"
-msgstr ""
+msgstr "æ–°ã—ã„パイプライン トリガー トークンを追加ã™ã‚‹"
msgid "Add new token"
msgstr "æ–°ã—ã„トークンを追加"
@@ -2776,7 +2831,7 @@ msgid "Add projects"
msgstr "プロジェクトを追加"
msgid "Add protected branch"
-msgstr ""
+msgstr "ä¿è­·ãƒ–ランãƒã‚’追加ã™ã‚‹"
msgid "Add reaction"
msgstr "リアクションを追加"
@@ -2793,6 +2848,9 @@ msgstr "æ案をãƒãƒƒãƒã«è¿½åŠ "
msgid "Add tag"
msgstr "タグを追加"
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "サインインページã«ãƒ†ã‚­ã‚¹ãƒˆã‚’追加ã—ã¾ã™ã€‚Markdown ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚"
@@ -2817,6 +2875,9 @@ msgstr "レビューã®è¡Œæ•°ã‚’増やã™"
msgid "Add to tree"
msgstr "ツリーã«è¿½åŠ "
+msgid "Add token"
+msgstr "トークンã®è¿½åŠ "
+
msgid "Add topics to projects to help users find them."
msgstr "プロジェクトã«ãƒˆãƒ”ックを追加ã—ã¦ã€ãƒ¦ãƒ¼ã‚¶ãŒãƒ—ロジェクトを見ã¤ã‘ã‚„ã™ãã—ã¾ã™ã€‚"
@@ -2844,8 +2905,8 @@ msgstr "追加/削除"
msgid "AddMember|Invite email is invalid"
msgstr "招待メールãŒç„¡åŠ¹ã§ã™"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "1æ—¥ã‚ãŸã‚Šã®æ‹›å¾…制é™æ•°%{daily_invites}を超ãˆã¾ã—ãŸ"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "招待を空白ã«ã§ãã¾ã›ã‚“"
@@ -3684,8 +3745,8 @@ msgstr "ユーザーã®ãƒ–ロックã«ã¯æ¬¡ã®åŠ¹æžœãŒã‚ã‚Šã¾ã™:"
msgid "AdminUsers|Bot"
msgstr "ボット"
-msgid "AdminUsers|Can create group"
-msgstr "グループを作æˆã§ãã¾ã™"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "サインインã¾ãŸã¯ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹æƒ…å ±ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“"
@@ -4308,6 +4369,9 @@ msgstr "タイトルã¯GitLabã®ã‚¢ãƒ©ãƒ¼ãƒˆã«å¿…è¦ã§ã™ã€‚指定ã—ãŸãƒšã‚¤
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr "インテグレーションã®ãŸã‚ã®Webhookã®URLã¨èªè¨¼ã‚­ãƒ¼ãŒç”Ÿæˆã•ã‚Œã¾ã™ã€‚çµ±åˆã‚’ä¿å­˜ã—ãŸå¾Œã€èªè¨¼æƒ…報を表示タブã®ä¸‹ã«ä¸¡æ–¹ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
+msgid "AlertSettings|Active alerts"
+msgstr "有効ãªã‚¢ãƒ©ãƒ¼ãƒˆ"
+
msgid "AlertSettings|Add new integration"
msgstr "æ–°ã—ã„インテグレーションを追加"
@@ -4746,9 +4810,6 @@ msgstr "公開デプロイキーã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚
msgid "An error occurred previewing the blob"
msgstr "blobã®ãƒ—レビュー中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr "ユーザーèªè¨¼ãƒãƒ£ãƒ¬ãƒ³ã‚¸ã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ページを更新ã—ã¦ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。"
-
msgid "An error occurred when updating the title"
msgstr "タイトルã®æ›´æ–°æ™‚ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -4839,6 +4900,9 @@ msgstr "イシューã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "An error occurred while fetching label colors."
msgstr "ラベルã®è‰²ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "An error occurred while fetching labels, please try again."
+msgstr "ラベルã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
+
msgid "An error occurred while fetching participants"
msgstr "å‚加者ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -5023,6 +5087,9 @@ msgstr[0] "設定ã®ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "設定ã®ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ä¿å­˜ã—ã¦ãã ã•ã„。"
+msgid "An error occurred while searching for labels, please try again."
+msgstr "ラベルã®æ¤œç´¢ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
+
msgid "An error occurred while triggering the job."
msgstr "ジョブã®ãƒˆãƒªã‚¬ãƒ¼ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -5038,6 +5105,12 @@ msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ãŸã‚ã«æ–°ã—ã„パイプラインを
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr "ユーザーã®ãƒ•ã‚©ãƒ­ãƒ¼ã‚’解除ã™ã‚‹ã¨ãã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "承èªè€…ã®æ›´æ–°ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -5147,6 +5220,9 @@ msgstr "分æžè¨­å®š"
msgid "Analytics|A visualization with that name already exists."
msgstr "åŒåã®å¯è¦–化ãŒå­˜åœ¨ã—ã¾ã™ã€‚"
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr "å¯è¦–化を追加"
@@ -5192,15 +5268,18 @@ msgstr "ダッシュボードプロジェクトã®è¨­å®š"
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr "ダッシュボード %{dashboardSlug}を作æˆ"
+msgid "Analytics|Create your dashboard"
+msgstr ""
+
msgid "Analytics|Custom dashboards"
msgstr "カスタムダッシュボード"
-msgid "Analytics|Dashboard Title"
-msgstr "ダッシュボードタイトル"
-
msgid "Analytics|Dashboard not found"
msgstr "ダッシュボードãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr "ダッシュボードã¯æ­£å¸¸ã«ä¿å­˜ã•ã‚Œã¾ã—ãŸ"
@@ -5222,6 +5301,12 @@ msgstr "日付ã¨æ™‚刻ã¯UTCタイムゾーンã§è¡¨ç¤ºã—ã¾ã™"
msgid "Analytics|Edit"
msgstr "編集"
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr "å¯è¦–化ã®åå‰ã‚’入力"
@@ -5237,6 +5322,9 @@ msgstr "データã®å–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸ"
msgid "Analytics|Host"
msgstr "ホスト"
+msgid "Analytics|Invalid visualization configuration"
+msgstr "無効ãªå¯è¦–化設定"
+
msgid "Analytics|Language"
msgstr "言語"
@@ -5279,24 +5367,30 @@ msgstr "リファラ"
msgid "Analytics|Resulting Data"
msgstr "çµæžœãƒ‡ãƒ¼ã‚¿"
-msgid "Analytics|Save"
-msgstr "ä¿å­˜"
-
msgid "Analytics|Save and add to Dashboard"
msgstr "ä¿å­˜ã—ã¦ãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ã«è¿½åŠ "
msgid "Analytics|Save new visualization"
msgstr "æ–°ã—ã„å¯è¦–化をä¿å­˜"
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr "測定をé¸æŠž"
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr "å¯è¦–化ã®ç¨®é¡žã‚’é¸æŠž"
msgid "Analytics|Single Statistic"
msgstr "å˜ä¸€çµ±è¨ˆ"
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr "パãƒãƒ«ã®å¯è¦–化設定ã«å•é¡ŒãŒã‚ã‚Šã¾ã™ã€‚%{linkStart}トラブルシューティングã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ%{linkEnd}ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr "データソースã¸ã®æŽ¥ç¶šä¸­ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ %{linkStart}トラブルシューティングドキュメント%{linkEnd} ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
@@ -5370,7 +5464,7 @@ msgid "Another issue tracker is already in use. Only one issue tracker service c
msgstr "別ã®ã‚¤ã‚·ãƒ¥ãƒ¼ãƒˆãƒ©ãƒƒã‚«ãƒ¼ã‚’ã™ã§ã«ä½¿ç”¨ã—ã¦ã„ã¾ã™ã€‚一度ã«ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ã«ã§ãるイシュートラッカーサービスã¯1ã¤ã ã‘ã§ã™"
msgid "Another open merge request already exists for this source branch: %{conflicting_mr_reference}"
-msgstr ""
+msgstr "ã“ã®ãƒ–ランãƒã«ã¯åˆ¥ã®ãƒžãƒ¼ã‚¸ リクエストãŒã™ã§ã«å­˜åœ¨ã—ã¾ã™: %{conflicting_mr_reference}"
msgid "Another third-party wiki is already in use. Only one third-party wiki integration can be active at a time"
msgstr "ä»–ã®ã‚µãƒ¼ãƒ‰ãƒ‘ーティーã®WikiãŒã™ã§ã«ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™ã€‚一度ã«æœ‰åŠ¹ã«ã§ãã‚‹ã®ã¯1ã¤ã®ã‚µãƒ¼ãƒ‰ãƒ‘ーティーã®Wikiã¨ã®ã‚¤ãƒ³ãƒ†ã‚°ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã ã‘ã§ã™ã€‚"
@@ -6045,9 +6139,6 @@ msgstr "本当ã«ã€ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã‚’削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹? ã
msgid "Are you sure you want to delete this label?"
msgstr "ã“ã®ãƒ©ãƒ™ãƒ«ã‚’削除ã—ã¦ã‚ˆã‚ã—ã„ã§ã™ã‹?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "本当ã«ã“ã®ãƒ‘イプラインスケジュールを削除ã—ã¾ã™ã‹ ?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "ã“ã®ãƒ‘イプラインを削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹? ã“ã‚Œã«ã‚ˆã‚Šã€ã™ã¹ã¦ã®ãƒ‘イプラインキャッシュãŒæœŸé™åˆ‡ã‚Œã«ãªã‚Šã€ãƒ“ルドã€ãƒ­ã‚°ã€ã‚¢ãƒ¼ãƒ†ã‚£ãƒ•ã‚¡ã‚¯ãƒˆã€ãƒˆãƒªã‚¬ãƒ¼ãªã©ã®é–¢é€£ã‚ªãƒ–ジェクトãŒã™ã¹ã¦å‰Šé™¤ã•ã‚Œã¾ã™ã€‚ã“ã®ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¯å…ƒã«æˆ»ã›ã¾ã›ã‚“。"
@@ -6127,8 +6218,8 @@ msgstr "本当ã«ç™»éŒ²ãƒˆãƒ¼ã‚¯ãƒ³ã‚’リセットã—ã¾ã™ã‹?"
msgid "Are you sure you want to retry this migration?"
msgstr "本当ã«ã“ã®ç§»è¡Œã‚’å†ãƒˆãƒ©ã‚¤ã—ã¾ã™ã‹?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "本当ã«ã€ã“ã®%{accessTokenType}を無効ã«ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹?ã“ã®ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¯å…ƒã«æˆ»ã™ã“ã¨ãŒã§ãã¾ã›ã‚“。"
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
msgstr "ã“ã®SSHキーを失効ã•ã›ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹?"
@@ -6267,6 +6358,9 @@ msgstr "自動的ã«æ¤œæŸ»ã™ã‚‹ãƒ–ランãƒã®ã‚«ãƒ³ãƒžåŒºåˆ‡ã‚Šãƒªã‚¹ãƒˆã€‚ã™
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr "ユーザーã®ãƒ‘ーソナルアクセストークン。ユーザーã¯ã‚¿ã‚¹ã‚¯ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã™ã¹ã¦ã®ã‚³ãƒ¡ãƒ³ãƒˆã¯ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«å±žã—ã¾ã™ã€‚"
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "後ã§ã‚‚ã†ä¸€åº¦èžã„ã¦ãã ã•ã„"
@@ -6474,6 +6568,9 @@ msgstr "ã“ã®åå‰ã®ãƒ˜ãƒƒãƒ€ãƒ¼ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™ã€‚"
msgid "AuditStreams|Active"
msgstr "アクティブ"
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr "サードパーティシステムã®ç›£æŸ»ãƒ­ã‚°ã‚’管ç†ã™ã‚‹HTTP エンドãƒã‚¤ãƒ³ãƒˆã‚’追加ã—ã¾ã™ã€‚"
@@ -6591,6 +6688,9 @@ msgstr "ã“ã¡ã‚‰ã«ã¯æ©Ÿå¯†æƒ…å ±ãŒå«ã¾ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚å®›
msgid "AuditStreams|This is great for keeping everything one place."
msgstr "ã“ã‚Œã¯ã™ã¹ã¦ã‚’1ã¤ã®å ´æ‰€ã«ä¿ã¤ã®ã«æœ€é©ã§ã™ã€‚"
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "値"
@@ -7162,7 +7262,7 @@ msgid "BetaBadge|Is supported by a commercially reasonable effort."
msgstr "商業的ã«åˆç†çš„ãªåŠªåŠ›ã«ã‚ˆã£ã¦ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã™ã€‚"
msgid "BetaBadge|May be unstable."
-msgstr ""
+msgstr "ä¸å®‰å®šã«ãªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "BetaBadge|Should not cause data loss."
msgstr "データãŒå¤±ã‚れるã¹ãã§ã¯ã‚ã‚Šã¾ã›ã‚“。"
@@ -7518,8 +7618,8 @@ msgstr "GitLabサブスクリプションã®è©³ç´°ã‚’読ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼
msgid "Billing|An error occurred while loading billable members list."
msgstr "請求å¯èƒ½ãªãƒ¡ãƒ³ãƒãƒ¼ã®ãƒªã‚¹ãƒˆã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
-msgstr "コードæ案アドオンã®è©³ç´°ã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "コードæ案アドオンã®è©³ç´°ã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚å•é¡ŒãŒè§£æ±ºã—ãªã„å ´åˆã¯ã€ %{supportLinkStart}サãƒãƒ¼ãƒˆã«ãŠå•ã„åˆã‚ã›%{supportLinkEnd}ãã ã•ã„。"
msgid "Billing|An error occurred while loading pending members list"
msgstr "ä¿ç•™ä¸­ã®ãƒ¡ãƒ³ãƒãƒ¼ã®ãƒªã‚¹ãƒˆã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -7533,15 +7633,18 @@ msgstr "メンãƒãƒ¼ç™»éŒ²å¾…ã¡"
msgid "Billing|Cannot remove user"
msgstr "ユーザーを削除ã§ãã¾ã›ã‚“"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr "コードæ案アドオンãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¾ã—ãŸ"
-
msgid "Billing|Direct memberships"
msgstr "ダイレクトメンãƒãƒ¼"
msgid "Billing|Enter at least three characters to search."
msgstr "å°‘ãªãã¨ã‚‚3文字以上ã§æ¤œç´¢ã—ã¦ãã ã•ã„."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr "コードæ案アドオンã®å‰²ã‚Šå½“ã¦ã‚¨ãƒ©ãƒ¼"
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr "コードæ案アドオンã®å‰²ã‚Šå½“ã¦è§£é™¤ã‚¨ãƒ©ãƒ¼"
+
msgid "Billing|Explore paid plans"
msgstr "有料プランを探索"
@@ -7558,6 +7661,9 @@ msgstr[0] "無料枠ã®ã‚°ãƒ«ãƒ¼ãƒ—ã¯%d人ã«åˆ¶é™ã•ã‚Œã¦ã„ã¾ã™"
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "グループ招待ã§æ‹›å¾…ã•ã‚ŒãŸãƒ¡ãƒ³ãƒãƒ¼ã¯å‰Šé™¤ã§ãã¾ã›ã‚“。グループ全体を削除ã™ã‚‹ã‹ã€æ‹›å¾…ã•ã‚ŒãŸã‚°ãƒ«ãƒ¼ãƒ—ã®ã‚ªãƒ¼ãƒŠãƒ¼ã«ãƒ¡ãƒ³ãƒãƒ¼ã‚’削除ã™ã‚‹ã‚ˆã†ä¾é ¼ã—ã¦ãã ã•ã„。"
+msgid "Billing|No seats available"
+msgstr "利用å¯èƒ½ãªã‚·ãƒ¼ãƒˆã¯ã‚ã‚Šã¾ã›ã‚“"
+
msgid "Billing|No users to display."
msgstr "表示ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ã„ã¾ã›ã‚“。"
@@ -7570,6 +7676,12 @@ msgstr "プロジェクトã¸ã®æ‹›å¾…"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "サブスクリプションã‹ã‚‰ãƒ¦ãƒ¼ã‚¶ãƒ¼%{username}を削除ã—ã¾ã™"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "ã“ã®ãƒ¡ãƒ³ãƒãƒ¼ã«ã‚¢ãƒ‰ã‚ªãƒ³ã‚’割り当ã¦ã‚‹ã¨ãã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚å•é¡ŒãŒè§£æ±ºã—ãªã„å ´åˆã¯ã€ %{supportLinkStart}サãƒãƒ¼ãƒˆã«ãŠå•ã„åˆã‚ã›%{supportLinkEnd}ãã ã•ã„。"
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "ã“ã®ãƒ¡ãƒ³ãƒãƒ¼ã«ã‚¢ãƒ‰ã‚ªãƒ³ã‚’割り当ã¦ã‚’解除ã™ã‚‹ã¨ãã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚å•é¡ŒãŒè§£æ±ºã—ãªã„å ´åˆã¯ã€ %{supportLinkStart}サãƒãƒ¼ãƒˆã«ãŠå•ã„åˆã‚ã›%{supportLinkEnd}ãã ã•ã„。"
+
msgid "Billing|Subscription end"
msgstr "サブスクリプション終了"
@@ -7597,6 +7709,9 @@ msgstr "ä¿ç•™ä¸­ã®æ‰¿èªã‚’表示"
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "ユーザー%{username}をサブスクリプションã‹ã‚‰å‰Šé™¤ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚続行ã™ã‚‹ã¨ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯%{namespace}グループã¨ãã®ã™ã¹ã¦ã®ã‚µãƒ–グループãŠã‚ˆã³ãƒ—ロジェクトã‹ã‚‰å‰Šé™¤ã•ã‚Œã¾ã™ã€‚ã“ã®ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¯å…ƒã«æˆ»ã›ã¾ã›ã‚“。"
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr "利用å¯èƒ½ãªã™ã¹ã¦ã®ã‚³ãƒ¼ãƒ‰æ案アドオンシートを割り当ã¦ã¾ã—ãŸã€‚ã‚‚ã£ã¨ã‚·ãƒ¼ãƒˆã‚’購入ã—ãŸã„%{salesLinkEnd}å ´åˆã¯ã€ã‚»ãƒ¼ãƒ«ã‚¹ãƒãƒ¼ãƒ  %{salesLinkStart}ã¾ã§ã”連絡ãã ã•ã„。"
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr "ã‚ãªãŸã®ã‚°ãƒ«ãƒ¼ãƒ—ã¯æœ€è¿‘ã€ç„¡æ–™ãƒ—ランを使用ã™ã‚‹ã‚ˆã†ã«å¤‰æ›´ã•ã‚Œã¾ã—ãŸã€‚%{over_limit_message}アクセスã™ã‚‹å¿…è¦ãŒãªããªã£ãŸãƒ¡ãƒ³ãƒãƒ¼ã‚’削除ã—ã¦ã€æ–°ã—ã„メンãƒãƒ¼ã®ãŸã‚ã«ã‚¹ãƒšãƒ¼ã‚¹ã‚’作るã‹ã€åˆ¶é™ã‚’増やã™ã‚ˆã†ã«åˆ‡ã‚Šæ›¿ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚無制é™ã®æ•°ã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’å¾—ã‚‹ã«ã¯ã€ãƒ—ランを有料枠ã«%{link_start}アップグレード%{link_end}ã—ã¦ãã ã•ã„。"
@@ -7640,6 +7755,9 @@ msgstr[0] "%d件ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã«ã‚ˆã£ã¦ãƒ–ロックã•ã‚Œã¾ã—ãŸ"
msgid "Blocked issue"
msgstr "ブロックã•ã‚ŒãŸã‚¤ã‚·ãƒ¥ãƒ¼"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr "ブロックã•ã‚ŒãŸä½œæ¥­é …ç›®ã¯ã€ç¾åœ¨ã®ã‚µãƒ–スクリプション階層ã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“"
+
msgid "Blocking"
msgstr "ブロック"
@@ -7673,9 +7791,6 @@ msgstr "一致ã™ã‚‹çµæžœãŒã‚ã‚Šã¾ã›ã‚“"
msgid "BoardNewEpic|Search groups"
msgstr "グループを検索"
-msgid "BoardNewEpic|Select a group"
-msgstr "グループをé¸æŠž"
-
msgid "BoardNewIssue|No matching results"
msgstr "一致ã™ã‚‹çµæžœãŒã‚ã‚Šã¾ã›ã‚“"
@@ -7763,9 +7878,6 @@ msgstr "ラベルをé¸æŠž"
msgid "BoardScope|Select milestone"
msgstr "マイルストーンをé¸æŠž"
-msgid "BoardScope|Select weight"
-msgstr "ウェイトをé¸æŠž"
-
msgid "BoardScope|Started"
msgstr "開始済ã¿"
@@ -8381,7 +8493,7 @@ msgid "BroadcastMessages|Indigo"
msgstr "インディゴ"
msgid "BroadcastMessages|Leave blank to target all group and project pages."
-msgstr ""
+msgstr "ã™ã¹ã¦ã®ã‚°ãƒ«ãƒ¼ãƒ—ã¨ãƒ—ロジェクトã®ãƒšãƒ¼ã‚¸ã‚’ターゲットã«ã™ã‚‹ã«ã¯ç©ºç™½ã®ã¾ã¾ã«ã—ã¾ã™ã€‚"
msgid "BroadcastMessages|Light"
msgstr "ライト"
@@ -8411,16 +8523,16 @@ msgid "BroadcastMessages|Notification"
msgstr "通知"
msgid "BroadcastMessages|One or more roles is required."
-msgstr ""
+msgstr "1ã¤ä»¥ä¸Šã®ãƒ­ãƒ¼ãƒ«ãŒå¿…è¦ã§ã™ã€‚"
msgid "BroadcastMessages|Paths can contain wildcards, like */welcome."
-msgstr ""
+msgstr "パスã«ã¯ã€*/welcomeã®ã‚ˆã†ãªãƒ¯ã‚¤ãƒ«ãƒ‰ã‚«ãƒ¼ãƒ‰ã‚’å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™."
msgid "BroadcastMessages|Red"
msgstr "赤"
msgid "BroadcastMessages|Select at least one role."
-msgstr ""
+msgstr "å°‘ãªãã¨ã‚‚1ã¤ã®ãƒ­ãƒ¼ãƒ«ã‚’é¸æŠžã—ã¾ã™ã€‚"
msgid "BroadcastMessages|Show only to users who have specific roles on groups/project pages"
msgstr "グループ/プロジェクトページã§ç‰¹å®šã®ãƒ­ãƒ¼ãƒ«ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã®ã¿è¡¨ç¤º"
@@ -8837,8 +8949,8 @@ msgstr "ã“ã®ãƒ—ロジェクト%{italicStart}ã‹ã‚‰%{italicEnd} ã®ã‚¢ã‚¯ã‚»ã‚¹
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr "ã“ã®ãƒ—ロジェクト%{italicStart}ã¸%{italicEnd} ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’制é™ã—ã¾ã™(éžæŽ¨å¥¨"
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
-msgstr "ä»–ã®ãƒ—ロジェクトãŒè¨±å¯ãƒªã‚¹ãƒˆã«è¿½åŠ ã•ã‚Œãªã„é™ã‚Šã€ã“ã®ãƒ—ロジェクトã‹ã‚‰CI/CDジョブトークンãŒä»–ã®ãƒ—ロジェクトã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã‚’防ãŽã¾ã™ã€‚ 許å¯ã•ã‚Œã¦ã„ãªã„プロジェクトãŒã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªãƒˆãƒ¼ã‚¯ãƒ³ã‚’å–å¾—ã—ã¦APIã«ã‚¢ã‚¯ã‚»ã‚¹ã—よã†ã¨ã™ã‚‹å¯èƒ½æ€§ãŒã‚ã‚‹ãŸã‚ã€ã“ã®æ©Ÿèƒ½ã‚’無効ã«ã™ã‚‹ã“ã¨ã¯ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒªã‚¹ã‚¯ãŒã‚ã‚Šã¾ã™ã€‚ %{linkStart}詳細ã¯ã“ã¡ã‚‰ã€‚%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
+msgstr "ä»–ã®ãƒ—ロジェクトãŒè¨±å¯ãƒªã‚¹ãƒˆã«è¿½åŠ ã•ã‚Œã¦ã„ãªã„é™ã‚Šã€ã“ã®ãƒ—ロジェクトã®CI/CDジョブトークンを他ã®ãƒ—ロジェクトã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã“ã¨ã‚’ç¦æ­¢ã—ã¾ã™ã€‚承èªã•ã‚Œã¦ã„ãªã„プロジェクトãŒã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªãƒˆãƒ¼ã‚¯ãƒ³ã‚’å–å¾—ã—ã¦APIã«ã‚¢ã‚¯ã‚»ã‚¹ã—よã†ã¨ã™ã‚‹å¯èƒ½æ€§ãŒã‚ã‚‹ãŸã‚ã€ã“ã®æ©Ÿèƒ½ã‚’無効ã«ã™ã‚‹ã¨ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒªã‚¹ã‚¯ãŒç”Ÿã˜ã¾ã™ã€‚%{linkStart}詳細ã¯ã“ã¡ã‚‰%{linkEnd} 。"
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
msgstr "ä»–ã®ãƒ—ロジェクトãŒè¨±å¯ãƒªã‚¹ãƒˆã«è¿½åŠ ã•ã‚Œãªã„é™ã‚Šã€ä»–ã®ãƒ—ロジェクト CI/CD ジョブトークンã‹ã‚‰ã“ã®ãƒ—ロジェクトã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’ç¦æ­¢ã—ã¾ã™ã€‚ 許å¯ã•ã‚Œã¦ã„ãªã„プロジェクトãŒã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªãƒˆãƒ¼ã‚¯ãƒ³ã‚’å–å¾—ã—ã¦APIã«ã‚¢ã‚¯ã‚»ã‚¹ã—よã†ã¨ã™ã‚‹å¯èƒ½æ€§ãŒã‚ã‚‹ãŸã‚ã€ã“ã®æ©Ÿèƒ½ã‚’無効ã«ã™ã‚‹ã“ã¨ã«ã¯ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒªã‚¹ã‚¯ãŒã‚ã‚Šã¾ã™ã€‚ %{linkStart}詳細ã¯ã“ã¡ã‚‰ã€‚%{linkEnd}"
@@ -8933,8 +9045,8 @@ msgstr "%{code_open}.campfirenow.com%{code_close}ã®ã‚µãƒ–ドメイン。"
msgid "Can be manually deployed to"
msgstr "手動デプロイå¯èƒ½å…ˆ"
-msgid "Can create groups:"
-msgstr "グループを作æˆã§ãã‚‹:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr "プライマリートレーニングを削除ã§ãã¾ã›ã‚“。"
@@ -9192,7 +9304,7 @@ msgid "Change branches"
msgstr "ブランãƒã‚’変更"
msgid "Change confidentiality"
-msgstr ""
+msgstr "機密性ã®å¤‰æ›´"
msgid "Change label"
msgstr "ラベルを変更"
@@ -9320,6 +9432,9 @@ msgstr "タイトルã®å¤‰æ›´ã¯ä¿å­˜ã•ã‚Œã¦ã„ã¾ã›ã‚“"
msgid "Changes:"
msgstr "変更:"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr "ã“ã“ã§è¨­å®šã‚’変更ã™ã‚‹ãŸã‚ã«ã¯ã‚¢ãƒ—リケーションã®å†èµ·å‹•ãŒå¿…è¦ã§ã™"
@@ -9410,6 +9525,9 @@ msgstr "Docker イメージã«æ—¢çŸ¥ã®è„†å¼±æ€§ãŒãªã„ã‹ç¢ºèªã™ã‚‹ã€‚"
msgid "Check your sign-up restrictions"
msgstr "サインアップ制é™ã‚’確èªã—ã¦ãã ã•ã„"
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "%{text}ãŒåˆ©ç”¨å¯èƒ½ã‹ç¢ºèªã—ã¦ã„ã¾ã™â€¦"
@@ -9466,8 +9584,8 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] "%{quantity} ストレージ パック"
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText} プラン"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} ã‹ã‚‰ %{endDate} ã¾ã§"
@@ -9721,6 +9839,9 @@ msgstr "テンプレートをé¸æŠžã—ã¦ãã ã•ã„..."
msgid "Choose a type..."
msgstr "タイプをé¸æŠžã—ã¦ãã ã•ã„..."
+msgid "Choose an option"
+msgstr "オプションをé¸æŠž"
+
msgid "Choose file…"
msgstr "ファイルをé¸æŠž..."
@@ -9755,7 +9876,7 @@ msgid "CiCatalog|About this project"
msgstr "ã“ã®ãƒ—ロジェクトã«ã¤ã„ã¦"
msgid "CiCatalog|Back to the CI/CD Catalog"
-msgstr ""
+msgstr "CI/CDカタログã«æˆ»ã‚‹"
msgid "CiCatalog|CI/CD Catalog"
msgstr "CI/CDカタログ"
@@ -9764,7 +9885,7 @@ msgid "CiCatalog|CI/CD Catalog resource"
msgstr "CI/CDカタログリソース"
msgid "CiCatalog|Component ID not found, or you do not have permission to access component."
-msgstr ""
+msgstr "コンãƒãƒ¼ãƒãƒ³ãƒˆ ID ãŒè¦‹ã¤ã‹ã‚‰ãªã„ã‹ã€ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。"
msgid "CiCatalog|Create a pipeline component repository and make reusing pipeline configurations faster and easier."
msgstr "パイプラインコンãƒãƒ¼ãƒãƒ³ãƒˆãƒªãƒã‚¸ãƒˆãƒªã‚’作æˆã—ã€ãƒ‘イプライン構æˆã®å†åˆ©ç”¨ã‚’迅速ã‹ã¤å®¹æ˜“ã«ã—ã¾ã™ã€‚"
@@ -9785,7 +9906,7 @@ msgid "CiCatalog|Mark project as a CI/CD Catalog resource. %{linkStart}What is t
msgstr "プロジェクトをCI/CDカタログリソースã¨ã—ã¦ãƒžãƒ¼ã‚¯ã—ã¾ã™ã€‚%{linkStart}CI/CDカタログã¨ã¯ä½•ã§ã™ã‹?%{linkEnd}"
msgid "CiCatalog|No component available"
-msgstr ""
+msgstr "利用å¯èƒ½ãªã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆãŒã‚ã‚Šã¾ã›ã‚“"
msgid "CiCatalog|No release available"
msgstr "利用å¯èƒ½ãªãƒªãƒªãƒ¼ã‚¹ã¯ã‚ã‚Šã¾ã›ã‚“"
@@ -9922,15 +10043,15 @@ msgstr "CI/CD変数"
msgid "CiVariables|Cancel"
msgstr "キャンセル"
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "ç¾åœ¨ã®å€¤ã§ã¯ãƒžã‚¹ã‚¯ã•ã‚ŒãŸå¤‰æ•°ã‚’使用ã§ãã¾ã›ã‚“"
-
msgid "CiVariables|Delete variable"
msgstr "変数を削除"
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr "本当ã«å¤‰æ•°%{key}を削除ã—ã¾ã™ã‹?"
+msgid "CiVariables|Edit Variable"
+msgstr "変数を編集"
+
msgid "CiVariables|Environments"
msgstr "環境"
@@ -9982,9 +10103,6 @@ msgstr "入力を削除"
msgid "CiVariables|Remove variable"
msgstr "変数を削除"
-msgid "CiVariables|Remove variable row"
-msgstr "環境変数を消去"
-
msgid "CiVariables|Run job"
msgstr "ジョブã®å®Ÿè¡Œ"
@@ -10006,12 +10124,24 @@ msgstr "継承ã•ã‚ŒãŸCI変数ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr "ã“ã®%{entity}ã«ã¯ã€å®šç¾©æ¸ˆã¿ã®CI/CD変数ãŒ%{currentVariableCount}個ã‚ã‚Šã¾ã™ã€‚%{entity}ã‚ãŸã‚Šã®å¤‰æ•°ã®æœ€å¤§æ•°ã¯%{maxVariableLimit}ã§ã™ã€‚æ–°ã—ã„変数を追加ã™ã‚‹ã«ã¯ã€å®šç¾©ã•ã‚ŒãŸå¤‰æ•°ã®æ•°ã‚’減らã™å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "種類"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "値"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr "変数ã¯ã‚¸ãƒ§ãƒ–ã®ãƒ­ã‚°ã§ãƒžã‚¹ã‚¯ã•ã‚Œã¾ã™ã€‚æ­£è¦è¡¨ç¾ã®æ¡ä»¶ã‚’満ãŸã™ã«ã¯ã€å€¤ãŒå¿…è¦ã§ã™ã€‚"
@@ -10027,9 +10157,6 @@ msgstr "変数ã¯ã€ã‚¸ãƒ§ãƒ–スクリプトã§ä½¿ç”¨ã§ãるパスワードや
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr "利用å¯èƒ½ãªå¤‰æ•°ã®æœ€å¤§æ•°ã«é”ã—ã¾ã—ãŸã€‚æ–°ã—ã„変数を追加ã™ã‚‹ã«ã¯ã€å®šç¾©ã•ã‚ŒãŸå¤‰æ•°ã®æ•°ã‚’減らã™å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
-msgid "CiVariable|* (All environments)"
-msgstr "* (ã™ã¹ã¦ã®ç’°å¢ƒ)"
-
msgid "CiVariable|All environments"
msgstr "ã™ã¹ã¦ã®ç’°å¢ƒ"
@@ -10040,7 +10167,7 @@ msgid "CiVariable|Define a CI/CD variable in the UI"
msgstr "UIã§CI/CD変数を定義"
msgid "CiVariable|GitLab CI/CD supports OpenID Connect (OIDC) to give your build and deployment jobs access to cloud credentials and services. %{linkStart}How do I configure OIDC for my cloud provider?%{linkEnd}"
-msgstr ""
+msgstr "GitLab CI/CD 㯠OpenID Connect (OIDC) をサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™ã€‚ ã“れを使用ã™ã‚‹ã¨ã€ã‚ãªãŸã®ç’°å¢ƒãŠã‚ˆã³ãƒ‡ãƒ—ロイ環境ã‹ã‚‰ã‚¯ãƒ©ã‚¦ãƒ‰ä¸Šã®èªè¨¼æƒ…å ±ã¨ã‚µãƒ¼ãƒ“スã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚ %{linkStart}OIDC を設定ã™ã‚‹ã«ã¯%{linkEnd}"
msgid "CiVariable|Maximum of %{limit} environments listed. For more environments, enter a search query."
msgstr "一覧ã«è¡¨ç¤ºã•ã‚Œã‚‹æœ€å¤§æ•°%{limit}ã®ç’°å¢ƒã€‚ã•ã‚‰ã«å¤šãã®ç’°å¢ƒãŒã‚ã‚‹å ´åˆã€æ¤œç´¢ã‚¯ã‚¨ãƒªã‚’入力ã—ã¦ãã ã•ã„。"
@@ -10052,7 +10179,7 @@ msgid "CiVariable|Search environments"
msgstr "環境を検索"
msgid "CiVariable|Use OIDC to securely connect to cloud services"
-msgstr ""
+msgstr "OIDC を使用ã—ã¦ã‚¯ãƒ©ã‚¦ãƒ‰ サービスã«å®‰å…¨ã«æŽ¥ç¶š"
msgid "CiVariable|Variable %{key} has been deleted."
msgstr "変数%{key}ãŒå‰Šé™¤ã•ã‚Œã¾ã—ãŸã€‚"
@@ -10187,6 +10314,9 @@ msgstr "クライアント"
msgid "Clientside DSN"
msgstr "クライアントサイド DSN"
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "クローン"
@@ -10484,15 +10614,9 @@ msgstr "クラスターã®å¥åº·çŠ¶æ…‹"
msgid "Cluster cache cleared."
msgstr "クラスターã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’削除ã—ã¾ã—ãŸ"
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr "Stages::ClusterEndpointInserter ã«ã¯ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ãŒå¿…è¦ã§ã™"
-
msgid "Cluster level"
msgstr "クラスターã®ãƒ¬ãƒ™ãƒ«"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr "Stages::ClusterEndpointInserter ã«ã¯ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã‚¿ã‚¤ãƒ—を指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™"
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr "高度ãªã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã«ã¤ã„ã¦ã¯ã€%{linkStart}文書をå‚ç…§%{linkEnd}ã—ã¦ãã ã•ã„。アクセストークンãŒåˆ©ç”¨å¯èƒ½ã§ã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
@@ -10782,6 +10906,9 @@ msgstr "ã“ã®ã‚¨ãƒ¼ã‚¸ã‚§ãƒ³ãƒˆã«ã¯ãƒˆãƒ¼ã‚¯ãƒ³ãŒã‚ã‚Šã¾ã›ã‚“"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "エージェントを削除ã™ã‚‹ã«ã¯ã€ç¢ºèªã®ãŸã‚ã«%{name}を入力ã—ã¦ãã ã•ã„:"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr "ä»–ã®ã‚¨ãƒ¼ã‚¸ã‚§ãƒ³ãƒˆã‚’管ç†ã™ã‚‹ã«ã¯ã€ %{linkStart}Terraformを使用ã—ã¾ã™ã€‚%{linkEnd}"
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr "トークンをå–り消ã™ã«ã¯ã€ç¢ºèªã®ãŸã‚ã«%{name}を入力ã—ã¦ãã ã•ã„:"
@@ -10806,6 +10933,9 @@ msgstr "%{number} 件ã®ã‚¨ãƒ¼ã‚¸ã‚§ãƒ³ãƒˆã‚’表示"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "%{number} 件ã®ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã‚’表示"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr "UIã§ã¯100人ã®ã‚¨ãƒ¼ã‚¸ã‚§ãƒ³ãƒˆã®ã¿ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™ã€‚"
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "GitLab Agent ã®ä½¿ç”¨æ„Ÿã«ã¤ã„ã¦ã€ãœã²ãŠèžã‹ã›ãã ã•ã„。"
@@ -11229,9 +11359,6 @@ msgstr "コードレビュー"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "コードレビュー分æžã§ã¯ã€ã‚³ãƒ¼ãƒ‰ãƒ¬ãƒ“ュー中ã¨ã¿ãªã•ã‚Œã‚‹ã‚ªãƒ¼ãƒ—ンãªãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ãƒ†ãƒ¼ãƒ–ルãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®ãƒ—ロジェクトやフィルターã«ã¯ã€ç¾åœ¨ã€ãƒ¬ãƒ“ュー中ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ã‚ã‚Šã¾ã›ã‚“。"
-msgid "Code Suggestions add-on"
-msgstr "コードæ案アドオン"
-
msgid "Code Suggestions add-on status"
msgstr "コードæ案アドオンã®çŠ¶æ…‹"
@@ -11301,31 +11428,28 @@ msgstr "ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®ã‚³ãƒ¼ãƒ‰ã®æ案を有効ã«ã™ã‚‹ %{beta}"
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr "ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã¤ã„ã¦ã€ã‚³ãƒ¼ãƒ‰ã®æ案を有効ã«ã—ã¾ã™ã€‚ %{link_start}コードã®æ案ã¨ã¯ä½•ã§ã™ã‹ï¼Ÿ%{link_end}"
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr "æ–°ã—ã„パーソナルアクセストークンを入力"
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
-msgstr "GitLab.com ã§ãƒˆãƒ¼ã‚¯ãƒ³ã‚’作æˆã—ã¾ã™ã€‚ã“ã®ãƒˆãƒ¼ã‚¯ãƒ³ã¯ã€è‡ªå·±ç®¡ç†ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã§ã‚³ãƒ¼ãƒ‰ã®æ案を使用ã™ã‚‹ãŸã‚ã«å¿…è¦ã§ã™ã€‚ %{link_start}トークンを作æˆã™ã‚‹ã«ã¯ã€ã©ã†ã™ã‚Œã°ã„ã„ã®ã§ã™ã‹ï¼Ÿ%{link_end}"
-
-msgid "CodeSuggestionsSM|Personal access token"
-msgstr "パーソナルアクセストークン"
-
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
-msgstr "より高å“質ãªæ案をæä¾›ã™ã‚‹ãŸã‚ã€ç¾åœ¨%{code_suggestions_link_start}コードã®æ案%{link_end}ã§ã¯ã‚µãƒ¼ãƒ‰ãƒ‘ーティã®AIサービスを導入ã—ã¦ã„ã¾ã™ã€‚グループã®%{third_party_link_start}サードパーティサービスを無効ã«ã™ã‚‹%{link_end}ã‹ã€%{profile_settings_link_start}ユーザープロフィール%{link_end}ã§ã‚³ãƒ¼ãƒ‰ã®æ案全体を無効ã«ã§ãã¾ã™ã€‚"
-
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
-msgstr "コードã®æ案を改善ã™ã‚‹ãŸã‚ã€ã‚µãƒ¼ãƒ‰ãƒ‘ーティã®AIサービスを使用ã—ã¦ã„ã¾ã™ã€‚"
-
msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr "%{link_start}コードæ案ã¨ã¯?%{link_end}"
msgid "CodeSuggestions|Code Suggestions"
msgstr "コードã®æ案"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
+msgstr ""
+
msgid "CodeSuggestions|Enable Code Suggestions"
msgstr "コードã®æ案を有効化"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
+msgstr ""
+
msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgstr "IDEã§ã®ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã§ã‚µã‚¸ã‚§ã‚¹ãƒãƒ§ãƒ³æ©Ÿèƒ½ã‚’使ã„ã¾ã—ょã†ã€‚ %{link_start}詳細ã¯ã“ã¡ã‚‰%{link_end}。"
+
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
+msgstr ""
+
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr "éŽåŽ»%{months_included}ã‹æœˆåˆ†ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã‚³ãƒ›ãƒ¼ãƒˆãŒè¡¨ç¤º
msgid "Collapse"
msgstr "折りãŸãŸã‚€"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr "ã™ã¹ã¦ã®ã‚¹ãƒ¬ãƒƒãƒ‰ã‚’éžè¡¨ç¤ºã«ã™ã‚‹"
@@ -11753,9 +11880,6 @@ msgstr "ブランãƒ/ã‚¿ã‚° リストã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "ブランãƒ/タグリストã®æ¤œç´¢ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "ブランãƒ/ã‚¿ã‚° リストã®æ›´æ–°ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-
msgid "CompareRevisions|View open merge request"
msgstr "オープン中ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’表示"
@@ -11801,6 +11925,9 @@ msgstr "コンプライアンスセンター"
msgid "Compliance framework"
msgstr "コンプライアンスフレームワーク"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr "コンプライアンスフレームワークを有効化"
+
msgid "ComplianceFrameworks|Add framework"
msgstr "フレームワークを追加"
@@ -11858,8 +11985,8 @@ msgstr "コンプライアンスフレームワークã®ãƒ‡ãƒ¼ã‚¿å–得中ã«ã‚¨
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr "デフォルトã®ã‚³ãƒ³ãƒ—ライアンスフレームワークã®è¨­å®šã‚¨ãƒ©ãƒ¼"
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
-msgstr "追加ã•ã‚ŒãŸãƒ•ãƒ¬ãƒ¼ãƒ ãƒ¯ãƒ¼ã‚¯ã‚’ã“ã“ã«è¡¨ç¤ºã—ã¾ã™ã€‚"
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr "追加ã•ã‚ŒãŸãƒ•ãƒ¬ãƒ¼ãƒ ãƒ¯ãƒ¼ã‚¯ã‚’ã“ã“ã«è¡¨ç¤ºã—ã¾ã™ã€‚上記ã®æ–°ã—ã„フレームワークを作æˆã—ã¦é–‹å§‹ã—ã¾ã™ã€‚"
msgid "ComplianceFrameworks|Invalid format"
msgstr "無効ãªå½¢å¼"
@@ -11982,7 +12109,7 @@ msgid "ComplianceReport|No projects found that match filters"
msgstr "フィルターã«ä¸€è‡´ã™ã‚‹ãƒ—ロジェクトãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
msgid "ComplianceReport|No projects with standards adherence checks found"
-msgstr ""
+msgstr "ãƒã‚§ãƒƒã‚¯ã®ã‚るプロジェクトãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
msgid "ComplianceReport|No violations found"
msgstr "é•åã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
@@ -12074,15 +12201,18 @@ msgstr "機密性"
msgid "Configuration help"
msgstr "設定ヘルプ"
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "%{italic_start}新機能%{italic_end}ã®ãƒ‰ãƒ­ãƒ¯ãƒ¼ã¨ã‚³ãƒ³ãƒ†ãƒ³ãƒ„を設定ã—ã¾ã™ã€‚"
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
-msgstr "イベントを追跡ã™ã‚‹ã‚ˆã†ã«%{link}を設定ã—ã¾ã™ã€‚%{link_start}詳細ã¯ã“ã¡ã‚‰ã€‚%{link_end}"
-
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr "リãƒã‚¸ãƒˆãƒªã®%{repository_checks_link_start}リãƒã‚¸ãƒˆãƒªãƒã‚§ãƒƒã‚¯%{link_end}ã¨%{housekeeping_link_start}ãƒã‚¦ã‚¹ã‚­ãƒ¼ãƒ”ング%{link_end}を設定ã—ã¾ã™ã€‚"
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr "イベントを追跡ã™ã‚‹ã‚ˆã†ã«%{snowplow_link_start}Snowplow%{snowplow_link_end}を設定ã—ã¾ã™ã€‚%{help_link_start}詳細ã¯ã“ã¡ã‚‰ã€‚%{help_link_end}"
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr "CAPTCHAã€IP アドレス制é™ã€ãã®ä»–を使ã£ã¦ã‚¹ãƒ‘ム対策を設定ã—ã¾ã™ã€‚"
@@ -12146,6 +12276,9 @@ msgstr "高度ãªæ¨©é™ã€Large File Storageã€2è¦ç´ èªè¨¼ã€CI/CDã®è¨­å®šã‚’
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr "権é™ã€Large File Storageã€2è¦ç´ èªè¨¼ã¨é¡§å®¢é–¢ä¿‚ã®é«˜åº¦ãªè¨­å®š"
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr "Jiraイシューキーã®ãƒžãƒƒãƒãƒ³ã‚°ã®ãŸã‚ã®ã‚«ã‚¹ã‚¿ãƒ ãƒ«ãƒ¼ãƒ«ã‚’設定ã™ã‚‹"
@@ -12317,6 +12450,9 @@ msgstr "接続ã«å¤±æ•—ã—ã¾ã—ãŸ"
msgid "Consistency guarantee method"
msgstr "一貫性をä¿è¨¼ã™ã‚‹æ–¹æ³•"
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "サãƒãƒ¼ãƒˆã¸ã®ãŠå•ã„åˆã‚ã›"
@@ -12443,7 +12579,7 @@ msgid "ContainerRegistry|Created %{time}"
msgstr "作æˆæ—¥æ™‚:%{time}"
msgid "ContainerRegistry|Delete image repository"
-msgstr ""
+msgstr "イメージリãƒã‚¸ãƒˆãƒªã‚’削除"
msgid "ContainerRegistry|Delete image repository?"
msgstr "イメージリãƒã‚¸ãƒˆãƒªã‚’削除ã—ã¾ã™ã‹?"
@@ -12836,6 +12972,9 @@ msgstr " %{resourceParentLink} ã«%{targetLink} を追加ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr "%{resourceParentLink}ã§æ‰¿èªã•ã‚ŒãŸãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆ%{targetLink}。"
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr "%{resourceParentLink}ã«ãƒ‡ã‚¶ã‚¤ãƒ³ã‚’アーカイブã—ã¾ã—ãŸã€‚"
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr " %{resourceParentLink} ã§ã‚¨ãƒ”ック %{targetLink} をクローズã—ã¾ã—ãŸã€‚"
@@ -12869,6 +13008,30 @@ msgstr " %{resourceParentLink} ã§ã‚¿ã‚¹ã‚¯ %{targetLink} をクローズã—ã¾ã
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr " %{resourceParentLink} ã§ãƒ†ã‚¹ãƒˆã‚±ãƒ¼ã‚¹ %{targetLink} をクローズã—ã¾ã—ãŸã€‚"
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr "%{noteableLink} ã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¾ã—ãŸã€‚"
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr "%{noteableLink}ã§ã‚¨ãƒ”ックã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¾ã—㟠%{resourceParentLink}。"
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr "%{noteableLink}%{resourceParentLink}ã§ã‚³ãƒŸãƒƒãƒˆã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¾ã—ãŸã€‚"
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr "%{noteableLink}%{resourceParentLink}ã§ãƒ‡ã‚¶ã‚¤ãƒ³ã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¾ã—ãŸã€‚"
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr "%{noteableLink}%{resourceParentLink}ã§ã‚¤ã‚·ãƒ¥ãƒ¼ã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¾ã—ãŸã€‚"
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr "%{noteableLink}%{resourceParentLink}ã§ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¾ã— ãŸã€‚"
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr "%{noteableLink}%{resourceParentLink}ã§ã‚¹ãƒ‹ãƒšãƒƒãƒˆã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¾ã—ãŸã€‚"
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr "スニペットã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¾ã—ãŸ%{noteableLink}。"
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr "プロジェクト%{resourceParentLink} を作æˆã—ã¾ã—ãŸã€‚"
@@ -12881,9 +13044,18 @@ msgstr " %{resourceParentLink} ã« wiki ページ%{targetLink}を作æˆã—ã¾ã—
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr " %{resourceParentLink} ã®%{refLink} ブランãƒã‚’削除ã—ã¾ã—ãŸã€‚"
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr "%{resourceParentLink}ã®ãƒžã‚¤ãƒ«ã‚¹ãƒˆãƒ¼ãƒ³ã‚’削除ã—ã¾ã—ãŸã€‚"
+
+msgid "ContributionEvent|Deleted resource."
+msgstr "リソースを削除ã—ã¾ã—ãŸã€‚"
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr " %{resourceParentLink} ã®%{refLink} タグを削除ã—ã¾ã—ãŸã€‚"
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr "%{resourceParentLink}ã®wikiページを削除ã—ã¾ã—ãŸã€‚"
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr "プロジェクト(%{resourceParentLink})ã«å‚加ã—ã¾ã—ãŸã€‚"
@@ -12939,37 +13111,46 @@ msgid "ContributionEvent|Removed due to membership expiration from %{resourcePar
msgstr "メンãƒãƒ¼ã‚·ãƒƒãƒ—ã®æœ‰åŠ¹æœŸé™ã®ãŸã‚ã€%{resourceParentLink}ã‹ã‚‰å‰Šé™¤ã•ã‚ŒãŸã€‚"
msgid "ContributionEvent|Reopened Epic %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§ã‚¨ãƒ”ック%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened incident %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§ã‚¤ãƒ³ã‚·ãƒ‡ãƒ³ãƒˆ%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened issue %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§ã‚¤ã‚·ãƒ¥ãƒ¼%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened key result %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§é‡è¦çµæžœ%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened merge request %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆ%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened milestone %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§ãƒžã‚¤ãƒ«ã‚¹ãƒˆãƒ¼ãƒ³%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened objective %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§ç›®æ¨™%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened requirement %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§è¦æ±‚事項%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened resource."
-msgstr ""
+msgstr "リソースをå†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened task %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§ã‚¿ã‚¹ã‚¯%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "%{resourceParentLink}ã§ãƒ†ã‚¹ãƒˆã‚±ãƒ¼ã‚¹%{targetLink}ã‚’å†é–‹ã—ã¾ã—ãŸã€‚"
+
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr "%{targetLink}%{resourceParentLink}ã«ãƒ‡ã‚¶ã‚¤ãƒ³ã‚’æ›´æ–°ã—ã¾ã—ãŸã€‚"
+
+msgid "ContributionEvent|Updated resource."
+msgstr "æ›´æ–°ã•ã‚ŒãŸãƒªã‚½ãƒ¼ã‚¹ã€‚"
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr "%{targetLink}%{resourceParentLink}ã«wikiページを更新ã—ã¾ã—ãŸã€‚"
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr "…ãã®ä»– %{count} 件ã®ã‚³ãƒŸãƒƒãƒˆã‚り。%{linkStart}比較%{linkEnd}"
@@ -13503,7 +13684,7 @@ msgid "Create phone verification exemption"
msgstr "電話ã«ã‚ˆã‚‹èªè¨¼ã®å…除を作æˆ"
msgid "Create pipeline trigger token"
-msgstr ""
+msgstr "パイプライン トリガー トークンを作æˆã™ã‚‹"
msgid "Create project"
msgstr "プロジェクトを作æˆ"
@@ -13517,6 +13698,9 @@ msgstr "リリースを作æˆ"
msgid "Create requirement"
msgstr "è¦æ±‚事項を作æˆ"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr "サービスアカウントを作æˆ"
@@ -13740,7 +13924,7 @@ msgid "Created %{timeAgo} by %{author}"
msgstr "%{author}ãŒ%{timeAgo}ã«ä½œæˆã—ã¾ã—ãŸ"
msgid "Created %{timeAgo} by %{email} via %{author}"
-msgstr ""
+msgstr "%{author}ãŒ%{email}ã§%{timeAgo}ã«ä½œæˆ"
msgid "Created %{time_ago}"
msgstr "%{time_ago} ã«ä½œæˆ"
@@ -13895,9 +14079,6 @@ msgstr "組織ãŒè¿½åŠ ã•ã‚Œã¾ã—ãŸã€‚"
msgid "Crm|Organization has been updated."
msgstr "組織ãŒæ›´æ–°ã•ã‚Œã¾ã—ãŸã€‚"
-msgid "Cron Timezone"
-msgstr "Cronã®ã‚¿ã‚¤ãƒ ã‚¾ãƒ¼ãƒ³"
-
msgid "Cron time zone"
msgstr "Cron タイムゾーン"
@@ -14235,9 +14416,6 @@ msgstr "サービス復元ã¾ã§ã®æ™‚é–“"
msgid "CycleAnalytics|Total time"
msgstr "åˆè¨ˆæ™‚é–“"
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "グループドロップダウンフィルター"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr "指定ã•ã‚ŒãŸé–‹å§‹ã‚¤ãƒ™ãƒ³ãƒˆã«ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“"
@@ -14411,6 +14589,9 @@ msgstr "中"
msgid "DORA4Metrics|Merge request throughput"
msgstr "マージリクエストã®ã‚¹ãƒ«ãƒ¼ãƒ—ット"
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr "プロジェクトã®ãƒ¡ãƒˆãƒªã‚¯ã‚¹æ¯”較%{name}"
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr "%{name}グループã®ãƒ¡ãƒˆãƒªã‚¯ã‚¹æ¯”較"
@@ -14451,10 +14632,10 @@ msgid "DORA4Metrics|Show forecast"
msgstr "予測を表示"
msgid "DORA4Metrics|Some metric charts failed to load"
-msgstr ""
+msgstr "一部ã®ãƒ¡ãƒˆãƒªã‚¯ã‚¹ãƒãƒ£ãƒ¼ãƒˆã®èª­ã¿è¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸ"
msgid "DORA4Metrics|Some metric comparisons failed to load"
-msgstr ""
+msgstr "一部ã®ãƒ¡ãƒˆãƒªã‚¯ã‚¹æ¯”較ã®èª­ã¿è¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸ"
msgid "DORA4Metrics|Something went wrong while getting change failure rate data."
msgstr "変更失敗率データã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -14501,6 +14682,9 @@ msgstr "サービスã®å¾©å…ƒã¾ã§ã®æ™‚é–“ (中央値日数)"
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr "予測ã®è¡¨ç¤ºæ©Ÿèƒ½ã®æ”¹å–„ã«å½¹ç«‹ã¦ã‚‹ãŸã‚ã€%{linkStart}ã“ã®å•é¡Œ%{linkEnd}ã«é–¢ã™ã‚‹ã”æ„見を共有ã—ã¦ãã ã•ã„ 。"
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr "サービスインシデントã¾ãŸã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«å½±éŸ¿ã‚’与ãˆã‚‹æ¬ é™¥ãŒç™ºç”Ÿã—ãŸéš›ã«ã€1日以内ã«ã‚µãƒ¼ãƒ“スを復元ã—ã¾ã—ãŸã€‚"
@@ -14723,6 +14907,9 @@ msgstr "最å°= 0 (タイムアウトã¯ç„¡åŠ¹)ã€æœ€å¤§= 2880 分"
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "最å°ã¯ 1 秒ã€æœ€å¤§ã¯ 3600 秒"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr "潜在的ãªè„†å¼±æ€§ã‚’見ã¤ã‘ã‚‹ãŸã‚ã«ã‚¿ãƒ¼ã‚²ãƒƒãƒˆã«é€ä¿¡ã•ã‚ŒãŸã™ã¹ã¦ã®HTTPリクエストを監視ã—ã¾ã™ã€‚"
@@ -15218,7 +15405,7 @@ msgid "DefaultBranchProtection|Protected against pushes"
msgstr "プッシュã‹ã‚‰ä¿è­·"
msgid "Define a custom deploy freeze pattern with %{cronSyntaxStart}cron syntax%{cronSyntaxEnd}."
-msgstr ""
+msgstr "%{cronSyntaxStart}Cron ã®æ§‹æ–‡%{cronSyntaxEnd}ã§ã€ã‚«ã‚¹ã‚¿ãƒ ãƒ‡ãƒ—ロイã®ãƒ•ãƒªãƒ¼ã‚ºãƒ‘ターンを定義ã—ã¾ã™."
msgid "Define a custom pattern with cron syntax"
msgstr "Cron構文ã§ã‚«ã‚¹ã‚¿ãƒ ãƒ‘ターンを定義"
@@ -15226,9 +15413,6 @@ msgstr "Cron構文ã§ã‚«ã‚¹ã‚¿ãƒ ãƒ‘ターンを定義"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr "Akismet ã‹ã‚‰ç‹¬ç«‹ã—ã¦ã€ã‚¹ãƒ‘ムを構æˆã™ã‚‹ã‚‚ã®ã®ã‚«ã‚¹ã‚¿ãƒ ãƒ«ãƒ¼ãƒ«ã‚’定義ã—ã¾ã™"
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "デプロイステージã®ç’°å¢ƒã‚’ %{code_open}.gitlab-ci.yml%{code_close} ã§å®šç¾©ã—ã¦ã€ãƒ‡ãƒ—ロイを追跡ã—ã¾ã™ã€‚"
-
msgid "Define how approval rules are applied to merge requests."
msgstr "マージリクエストã«æ‰¿èªãƒ«ãƒ¼ãƒ«ã‚’é©ç”¨ã™ã‚‹æ–¹æ³•ã‚’定義ã—ã¾ã™ã€‚"
@@ -15318,7 +15502,7 @@ msgid "Delete corpus"
msgstr "コーパスを削除"
msgid "Delete custom emoji"
-msgstr ""
+msgstr "カスタム絵文字を削除"
msgid "Delete deploy key"
msgstr "デプロイキーを削除"
@@ -15350,9 +15534,6 @@ msgstr "ラベルを削除: %{labelName}"
msgid "Delete pipeline"
msgstr "パイプラインを削除"
-msgid "Delete pipeline schedule"
-msgstr "パイプラインスケジュールを削除"
-
msgid "Delete project"
msgstr "プロジェクトを削除"
@@ -15568,6 +15749,9 @@ msgstr "場所ã¨ä¾å­˜é–¢ä¿‚ã®ãƒ‘ス"
msgid "Dependencies|Packager"
msgstr "パッケージャー"
+msgid "Dependencies|Project list unavailable"
+msgstr "プロジェクトリストã¯åˆ©ç”¨ã§ãã¾ã›ã‚“"
+
msgid "Dependencies|Projects"
msgstr "プロジェクト"
@@ -15586,6 +15770,9 @@ msgstr "コンãƒãƒ¼ãƒãƒ³ãƒˆã®ä¾å­˜é–¢ä¿‚ã®ãƒ‘スã¯ãƒ­ãƒƒã‚¯ãƒ•ã‚¡ã‚¤ãƒ«ã«
msgid "Dependencies|There may be multiple paths"
msgstr "複数ã®ãƒ‘スãŒå­˜åœ¨ã™ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™"
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã¯ã‚µãƒ–グループã®æœ€å¤§æ•°600を超ãˆã¦ã„ã¾ã™ã€‚ç¾æ™‚点ã§ã¯ãƒ—ロジェクトリストを正確ã«è¡¨ç¤ºã§ãã¾ã›ã‚“。サブグループã®ä¾å­˜é–¢ä¿‚リストã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ã“ã®æƒ…報を表示ã™ã‚‹ã‹ã€è©³ç´°ã‚’%{linkStart}ä¾å­˜é–¢ä¿‚リストã®ãƒ˜ãƒ«ãƒ—%{linkEnd}ページã§å‚ç…§ã—ã¦ãã ã•ã„。"
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "脆弱性リストã®åˆ‡ã‚Šæ›¿ãˆ"
@@ -15746,7 +15933,7 @@ msgid "DeployFreeze|Deploy freeze from %{start} to %{end} in %{timezone} will be
msgstr "%{timezone}ã§%{start}ã‹ã‚‰%{end}ã¾ã§ã®ãƒ•ãƒªãƒ¼ã‚ºæœŸé–“ãŒå‰Šé™¤ã•ã‚Œã¾ã™ã€‚よã‚ã—ã„ã§ã™ã‹?"
msgid "DeployFreeze|Deploy freezes"
-msgstr ""
+msgstr "デプロイフリーズ"
msgid "DeployFreeze|Freeze end"
msgstr "デプロイフリーズ: 終了"
@@ -15755,7 +15942,7 @@ msgid "DeployFreeze|Freeze start"
msgstr "デプロイフリーズ: 開始"
msgid "DeployFreeze|No deploy freezes exist for this project. To add one, select %{strongStart}Add deploy freeze%{strongEnd} above."
-msgstr ""
+msgstr "ã“ã®ãƒ—ロジェクトã«ã¯ãƒ‡ãƒ—ロイフリーズãŒã‚ã‚Šã¾ã›ã‚“。追加ã™ã‚‹ã«ã¯ã€%{strongStart}デプロイフリーズã®è¿½åŠ %{strongEnd}ã‚’é¸æŠžã—ã¦ãã ã•ã„."
msgid "DeployFreeze|Specify deploy freezes using %{cron_syntax_link_start}cron syntax%{cron_syntax_link_end}."
msgstr "%{cron_syntax_link_start}cron構文%{cron_syntax_link_end}を使用ã—ã¦ãƒ‡ãƒ—ロイフリーズを指定ã—ã¾ã™ã€‚"
@@ -15766,6 +15953,12 @@ msgstr "タイムゾーン"
msgid "DeployKeys|+%{count} others"
msgstr "ãã®ä»–%{count}件"
+msgid "DeployKeys|Add new deploy key"
+msgstr "æ–°è¦ãƒ‡ãƒ—ロイキーを追加"
+
+msgid "DeployKeys|Add new key"
+msgstr "æ–°ã—ã„キーを追加"
+
msgid "DeployKeys|Current project"
msgstr "ç¾åœ¨ã®ãƒ—ロジェクト"
@@ -15793,8 +15986,8 @@ msgstr "ã“ã®ã‚­ãƒ¼ã«æ›¸ãè¾¼ã¿æ¨©é™ã‚’与ãˆã‚‹"
msgid "DeployKeys|Loading deploy keys"
msgstr "デプロイキーを読ã¿è¾¼ã¿ä¸­"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "デプロイキーãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。上記ã®ãƒ•ã‚©ãƒ¼ãƒ ã§ä½œæˆã—ã¦ãã ã•ã„。"
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr "デプロイキーãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。上記ã®æ–°ã—ã„キーを追加ã—ã¦ãã ã•ã„。"
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "プライベートアクセスãŒå¯èƒ½ãªãƒ‡ãƒ—ロイキー"
@@ -15808,8 +16001,8 @@ msgstr "パブリックアクセスãŒå¯èƒ½ãªãƒ‡ãƒ—ロイキー"
msgid "DeployKeys|Read access only"
msgstr "読ã¿å–り専用"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "有効ãªãƒ‡ãƒ—ロイトークン (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr "アクティブãªãƒ‡ãƒ—ロイトークン"
msgid "DeployTokens|Allows read and write access to registry images."
msgstr "レジストリイメージã¸ã®èª­ã¿æ›¸ãアクセスを許å¯ã—ã¾ã™ã€‚"
@@ -15832,6 +16025,9 @@ msgstr "リãƒã‚¸ãƒˆãƒªã¸ã®èª­ã¿å–り専用アクセスを許å¯ã™ã‚‹ã€‚"
msgid "DeployTokens|Allows write access to registry images."
msgstr "レジストリイメージã¸ã®æ›¸ãè¾¼ã¿ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã—ã¾ã™ã€‚"
+msgid "DeployTokens|Cancel"
+msgstr "キャンセル"
+
msgid "DeployTokens|Copy deploy token"
msgstr "デプロイトークンをコピー"
@@ -15892,7 +16088,7 @@ msgstr "スコープ"
msgid "DeployTokens|Scopes (select at least one)"
msgstr "スコープ(å°‘ãªãã¨ã‚‚1ã¤é¸æŠž)"
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr "ã“ã® %{entity_type} ã«ã¯ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªãƒ‡ãƒ—ロイトークンã¯ã‚ã‚Šã¾ã›ã‚“。"
msgid "DeployTokens|This action cannot be undone."
@@ -15910,12 +16106,12 @@ msgstr "ユーザーå"
msgid "DeployTokens|Username (optional)"
msgstr "ユーザーå(ä»»æ„)"
-msgid "DeployTokens|Your New Deploy Token"
-msgstr "æ–°è¦ãƒ‡ãƒ—ロイトークン"
-
msgid "DeployTokens|Your new Deploy Token username"
msgstr "æ–°ã—ã„デプロイトークンã®ãƒ¦ãƒ¼ã‚¶ãƒ¼å"
+msgid "DeployTokens|Your new deploy token"
+msgstr "æ–°è¦ãƒ‡ãƒ—ロイトークン"
+
msgid "DeployTokens|Your new group deploy token has been created."
msgstr "æ–°ã—ã„グループデプロイトークンãŒä½œæˆã•ã‚Œã¾ã—ãŸã€‚"
@@ -15997,6 +16193,12 @@ msgstr "ã‚ãªãŸã«ã‚ˆã£ã¦%{time}ã«æ‰¿èªã•ã‚ŒãŸ"
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr "承èªã™ã‚‹ã¨ãƒ‡ãƒ—ロイメント#%{deploymentIid}ã‹ã‚‰ã®ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«ã‚¸ãƒ§ãƒ–ãŒå®Ÿè¡Œã•ã‚Œã¾ã™ã€‚å´ä¸‹ã™ã‚‹ã¨ã€ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«ã‚¸ãƒ§ãƒ–ãŒå¤±æ•—ã—ã¾ã™ã€‚"
+msgid "DeploymentApproval|Deployment approved"
+msgstr "デプロイãŒæ‰¿èªã•ã‚Œã¾ã—ãŸ"
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr "デプロイãŒæ‹’å¦ã•ã‚Œã¾ã—ãŸ"
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr "デプロイ階層: %{tier}"
@@ -16067,9 +16269,6 @@ msgstr "デプロイステージã®ç’°å¢ƒã‚’%{code_open}.gitlab-ci.yml%{code_clo
msgid "Deployments|You don't have any deployments right now."
msgstr "ç¾åœ¨ãƒ‡ãƒ—ロイãŒã‚ã‚Šã¾ã›ã‚“。"
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "キャンセル済ã¿"
@@ -16082,6 +16281,24 @@ msgstr "デプロイ ID"
msgid "Deployment|Failed"
msgstr "失敗済"
+msgid "Deployment|Flux sync failed"
+msgstr "Fluxã®åŒæœŸã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr "Fluxã®åŒæœŸãŒæ­£å¸¸ã«èª¿æ•´ã•ã‚Œã¾ã—ãŸ"
+
+msgid "Deployment|Flux sync reconciling"
+msgstr "Fluxã®åŒæœŸã‚’調整ã—ã¦ã„ã¾ã™"
+
+msgid "Deployment|Flux sync stalled"
+msgstr "Fluxã®åŒæœŸãŒåœæ­¢ã—ã¾ã—ãŸ"
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr "Fluxã®åŒæœŸã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã‚’使用ã§ãã¾ã›ã‚“"
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr "Fluxã®åŒæœŸã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãŒä¸æ˜Žã§ã™"
+
msgid "Deployment|Latest Deployed"
msgstr "最新ã®ãƒ‡ãƒ—ロイ"
@@ -16097,17 +16314,20 @@ msgstr "スキップ"
msgid "Deployment|Success"
msgstr "æˆåŠŸ"
-msgid "Deployment|This deployment was created using the API"
-msgstr "ã“ã®ãƒ‡ãƒ—ロイ㯠API を使用ã—ã¦ä½œæˆã•ã‚Œã¾ã—ãŸ"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr "åŒæœŸã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãŒä¸æ˜Žã§ã™ã€‚%{linkStart}デプロイメント用ã«Fluxを構æˆã™ã‚‹ã«ã¯?%{linkEnd}"
msgid "Deployment|Triggerer"
msgstr "トリガー"
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr "ステータスを検出ã§ãã¾ã›ã‚“。%{linkStart}ステータスã¯ã©ã®ã‚ˆã†ã«æ¤œå‡ºã•ã‚Œã¾ã™ã‹ï¼Ÿ%{linkEnd}"
+
msgid "Deployment|Unavailable"
-msgstr ""
+msgstr "利用ä¸å¯"
msgid "Deployment|Unknown"
-msgstr ""
+msgstr "ä¸æ˜Ž"
msgid "Deployment|Waiting"
msgstr "待機中"
@@ -16172,12 +16392,6 @@ msgstr "デザイン"
msgid "Design Management files and data"
msgstr "デザインマãƒã‚¸ãƒ¡ãƒ³ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã¨ãƒ‡ãƒ¼ã‚¿"
-msgid "Design repositories"
-msgstr "デザインリãƒã‚¸ãƒˆãƒª"
-
-msgid "Design repository"
-msgstr "デザインリãƒã‚¸ãƒˆãƒª"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{designs_count}/%{current_design}"
@@ -16785,7 +16999,7 @@ msgstr "ã‚„ã‚ã‚‹"
msgid "Dismissed (%d reason)"
msgid_plural "Dismissed (%d reasons)"
-msgstr[0] ""
+msgstr[0] "å´ä¸‹ã—ã¾ã—㟠(%d 件ã®ç†ç”±)"
msgid "Display"
msgstr "ディスプレイ"
@@ -16902,7 +17116,7 @@ msgid "DomainVerification|To verify ownership of your domain, add the above key
msgstr "ドメインã®æ‰€æœ‰æ¨©ã‚’確èªã™ã‚‹ã«ã¯ã€7日以内ã«DNS設定内ã®TXTレコードã«ä¸Šè¨˜ã®ã‚­ãƒ¼ã‚’追加ã—ã¾ã™ã€‚%{link_to_help}"
msgid "Domains"
-msgstr ""
+msgstr "ドメイン"
msgid "Don't have a group?"
msgstr "グループをãŠæŒã¡ã§ã¯ã‚ã‚Šã¾ã›ã‚“ã‹?"
@@ -17366,9 +17580,6 @@ msgstr "メールé€ä¿¡å®Œäº†"
msgid "Email the pipeline status to a list of recipients."
msgstr "メールã§ã€ãƒ‘イプラインã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã‚’å—信者ã®ãƒªã‚¹ãƒˆã«é€ä¿¡ã—ã¾ã™ã€‚"
-msgid "Email updates (optional)"
-msgstr "メールã®æ›´æ–°(オプション)"
-
msgid "Email:"
msgstr "メール:"
@@ -17411,6 +17622,9 @@ msgstr "%{emails}ã€%{andMore}ã« ã§ã‚ãªãŸã®ã‚³ãƒ¡ãƒ³ãƒˆã‚’通知ã—ã¾ã™ã
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "ãŠã‚ˆã³ãã®ä»–%{moreCount}"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr "有効ãªæ°¸ç¶šçš„ãªã‚¢ãƒ‰ãƒ¬ã‚¹ã«ãƒ¡ãƒ¼ãƒ«ã‚’æ›´æ–°ã—ã¾ã™ã€‚一時的ãªãƒ¡ãƒ¼ãƒ«ã‚’使用ã™ã‚‹å ´åˆã¯ã€å¾Œã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
+
msgid "Emails"
msgstr "メール"
@@ -17549,9 +17763,6 @@ msgstr "グループRunnerを有効ã«ã™ã‚‹"
msgid "Enable header and footer in emails"
msgstr "メールã®ãƒ˜ãƒƒãƒ€ãƒ¼ã¨ãƒ•ãƒƒã‚¿ãƒ¼ã‚’有効ã«ã™ã‚‹"
-msgid "Enable in-product marketing emails"
-msgstr "商å“内マーケティングメールを有効ã«ã™ã‚‹"
-
msgid "Enable incident management inbound alert limit"
msgstr "インシデント管ç†ã‚¤ãƒ³ãƒã‚¦ãƒ³ãƒ‰ã‚¢ãƒ©ãƒ¼ãƒˆåˆ¶é™ã‚’有効ã«ã™ã‚‹"
@@ -17573,8 +17784,8 @@ msgstr "クライアントシークレットを安全ã«ä¿å­˜ã§ãã‚‹ä¿¡é ¼ã§
msgid "Enable or disable version check and Service Ping."
msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãƒã‚§ãƒƒã‚¯ã¨ã‚µãƒ¼ãƒ“ス ping を有効ã¾ãŸã¯ç„¡åŠ¹ã«ã—ã¾ã™ã€‚"
-msgid "Enable rate limiting for POST requests to the specified paths"
-msgstr "指定ã•ã‚ŒãŸãƒ‘スã¸ã® POST リクエストã®ãƒ¬ãƒ¼ãƒˆåˆ¶é™ã‚’有効ã«ã™ã‚‹"
+msgid "Enable rate limiting for requests to the specified paths"
+msgstr ""
msgid "Enable reCAPTCHA"
msgstr "reCAPTCHAを有効ã«ã™ã‚‹"
@@ -17687,9 +17898,6 @@ msgstr "ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã‚µã‚¤ãƒ³ã‚¤ãƒ³æ™‚ã« 2è¦ç´ èªè¨¼ã‚’実施ã
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr "サービスアカウントキーをシークレットマãƒãƒ¼ã‚¸ãƒ£ãƒ¼ã«ä¿å­˜ã™ã‚‹ã“ã¨ã§ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚’強化 - %{docLinkStart}GitLabã§ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆãƒžãƒãƒ¼ã‚¸ãƒ¡ãƒ³ãƒˆ%{docLinkEnd}ã®è©³ç´°ã«ã¤ã„ã¦"
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr "%{linkStart}コードã®æ案%{linkEnd} ã¯ã€é–‹ç™ºä¸­ã«ã‚³ãƒ¼ãƒ‰ã‚’æ案ã™ã‚‹ãŸã‚ã«ç”Ÿæˆã•ã‚ŒãŸAIを使用ã—ã¾ã™ã€‚ゲストã®å½¹å‰²ã§ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“。"
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr "%{linkStart}環境㌠CI パイプラインã®ãƒ‡ãƒ—ロイステージã®ä¸€éƒ¨ %{linkEnd}ã§ã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ã€ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã¸ã®ãƒ‡ãƒ—ロイを追跡ã—ã¾ã™ã€‚"
@@ -17801,8 +18009,8 @@ msgstr "環境"
msgid "Environment scope"
msgstr "環境範囲"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr "ã“ã®GitLabインスタンスã®ç’°å¢ƒå¤‰æ•°ã¯ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã§%{link_start}ä¿è­·%{link_end}ã•ã‚Œã‚‹ã‚ˆã†ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ã€‚"
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr "ã“ã®GitLabインスタンスã®ç’°å¢ƒå¤‰æ•°ã¯ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã§%{help_link_start}ä¿è­·%{help_link_end}ã•ã‚Œã‚‹ã‚ˆã†ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ã€‚"
msgid "Environment:"
msgstr "環境:"
@@ -17948,12 +18156,18 @@ msgstr "環境を始ã‚ã¾ã—ょã†"
msgid "Environments|GitLab agent"
msgstr "GitLabエージェント"
+msgid "Environments|HelmReleases"
+msgstr "HelmReleases"
+
msgid "Environments|Job"
msgstr "ジョブ"
msgid "Environments|Kubernetes namespace (optional)"
msgstr "Kubernetes åå‰ç©ºé–“(オプション)"
+msgid "Environments|Kustomizations"
+msgstr "Kustomizations"
+
msgid "Environments|Learn more about stopping environments"
msgstr "環境ã®åœæ­¢ã®è©³ç´°ã«ã¤ã„ã¦"
@@ -17999,6 +18213,12 @@ msgstr "環境 %{name} をロールãƒãƒƒã‚¯ã—ã¾ã™ã‹?"
msgid "Environments|Search by environment name"
msgstr "環境åã§æ¤œç´¢"
+msgid "Environments|Select Flux resource"
+msgstr "Fluxリソースをé¸æŠž"
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr "Flux リソースをé¸æŠž (オプション)"
+
msgid "Environments|Select agent"
msgstr "エージェントをé¸æŠž"
@@ -18035,6 +18255,9 @@ msgstr "ã“ã®ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¯ã€ã“ã®ç’°å¢ƒã«å¯¾ã—ã¦ã€%{commitId}コミã
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr "ã“ã®ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã¯%{commitId}ã®ã‚³ãƒŸãƒƒãƒˆã§ä»¥å‰ã«æˆåŠŸã—ãŸãƒ‡ãƒ—ロイã®%{docsStart}環境ã«ãƒ­ãƒ¼ãƒ«ãƒãƒƒã‚¯ã—ã¾ã™ã€‚%{docsEnd}本当ã«ç¶šè¡Œã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr "ã“ã®ç’°å¢ƒã‹ã‚‰æ¬¡ã®ãƒªã‚½ãƒ¼ã‚¹ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。以下ã®èªè¨¼ã‚’確èªã—ã¦å†åº¦ãŠè©¦ã—下ã•ã„:"
+
msgid "Environments|Upcoming"
msgstr "今後"
@@ -18105,10 +18328,10 @@ msgid "Environment|Ports"
msgstr "ãƒãƒ¼ãƒˆ"
msgid "Environment|Reconciled"
-msgstr ""
+msgstr "ç…§åˆæ¸ˆã¿"
msgid "Environment|Reconciling"
-msgstr ""
+msgstr "ç…§åˆä¸­"
msgid "Environment|ReplicaSets"
msgstr "ReplicaSets"
@@ -18120,7 +18343,7 @@ msgid "Environment|Services"
msgstr "サービス"
msgid "Environment|Stalled"
-msgstr ""
+msgstr "åœæ­¢ä¸­"
msgid "Environment|StatefulSets"
msgstr "StatefulSets"
@@ -18132,11 +18355,17 @@ msgid "Environment|Summary"
msgstr "概è¦"
msgid "Environment|Sync status"
-msgstr ""
+msgstr "åŒæœŸçŠ¶æ…‹"
msgid "Environment|There was an error connecting to the cluster agent."
msgstr "クラスターエージェントã¸ã®æŽ¥ç¶šä¸­ã«ã€ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr "%{resourceType} ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr "ã“ã®ç’°å¢ƒã‹ã‚‰ %{resourceType} ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。"
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr "ã“ã®ç’°å¢ƒã‹ã‚‰ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã‚¨ãƒ¼ã‚¸ã‚§ãƒ³ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。èªè¨¼ã‚’確èªã—ã¦ã€ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -18270,7 +18499,7 @@ msgid "Error creating or updating PreScanVerificationStep: %{errors}"
msgstr "PreScanVerificationStepã®ä½œæˆã¾ãŸã¯æ›´æ–°ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ: %{errors}"
msgid "Error creating repository for snippet with id %{snippet_id}"
-msgstr ""
+msgstr "id ㌠%{snippet_id} ã®ã‚¹ãƒ‹ãƒšãƒƒãƒˆç”¨ãƒªãƒã‚¸ãƒˆãƒªã®ä½œæˆã‚¨ãƒ©ãƒ¼"
msgid "Error creating the snippet"
msgstr "スニペットã®ä½œæˆã‚¨ãƒ©ãƒ¼"
@@ -18891,6 +19120,9 @@ msgstr "既存ã®ã‚µã‚¤ãƒ³ã‚¤ãƒ³æ–¹æ³•ã¯å‰Šé™¤ã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™"
msgid "Expand"
msgstr "展開"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "ã™ã¹ã¦å±•é–‹"
@@ -19137,6 +19369,9 @@ msgstr "https://example.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr "失敗"
@@ -19224,13 +19459,13 @@ msgid "Failed to create resources"
msgstr "リソースã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸ"
msgid "Failed to create target branch rule"
-msgstr ""
+msgstr "ターゲットブランãƒãƒ«ãƒ¼ãƒ«ã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸ"
msgid "Failed to create wiki"
msgstr "wiki を作æˆã§ãã¾ã›ã‚“ã§ã—ãŸ"
msgid "Failed to delete custom emoji. Please try again."
-msgstr ""
+msgstr "カスタム絵文字ã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„."
msgid "Failed to deploy to"
msgstr "次ã¸ã®ãƒ‡ãƒ—ロイã«å¤±æ•—ã—ã¾ã—ãŸ:"
@@ -19791,9 +20026,6 @@ msgstr "ç¾åœ¨ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–ã•ã‚ŒãŸãƒ†ã‚¹ãƒˆã‚±ãƒ¼ã‚¹ã§ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼"
msgid "Filter by test cases that are currently open."
msgstr "ç¾æ™‚点ã§æœªè§£æ±ºã®ãƒ†ã‚¹ãƒˆã‚±ãƒ¼ã‚¹ã§ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã™ã‚‹"
-msgid "Filter by user"
-msgstr "ユーザーã§ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr "フィルターパラメータãŒç„¡åŠ¹ã§ã™ã€‚終了日ãŒé–‹å§‹æ—¥ã‚ˆã‚Šå¾Œã§ã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
@@ -19818,9 +20050,6 @@ msgstr "çµæžœã‚’絞り込む..."
msgid "Filter users"
msgstr "ユーザーをフィルター"
-msgid "Filter..."
-msgstr "フィルター..."
-
msgid "Finalizing"
msgstr "完了中"
@@ -20188,33 +20417,6 @@ msgstr "Freeã®æœ€ä¸Šä½ã‚°ãƒ«ãƒ¼ãƒ—ã¯ã¾ã‚‚ãªãユーザー数ãŒ%{free_user
msgid "Free trial will expire in %{days}"
msgstr "無料トライアルã¯%{days}後ã«æœŸé™åˆ‡ã‚Œã«ãªã‚Šã¾ã™"
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "ã‚ã‚‹ã„ã¯GitLab Premiumã¾ãŸã¯GitLab Ultimateã«ã‚¢ãƒƒãƒ—グレードã§ãã¾ã™:"
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "有料プランを探索ã™ã‚‹"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "有料プランを探索ã™ã‚‹:"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr "%{date_time}ã«å®Ÿè¡Œã—ãŸãƒã‚§ãƒƒã‚¯ã«ã‚ˆã‚‹ã¨ã€ã€Œ%{namespace_name}ã€ã®ãƒ¡ãƒ³ãƒãƒ¼æ•°ãŒä¸Šé™ (%{free_user_limit}) ã«é”ã—ãŸã‚ˆã†ã§ã™ã€‚ã“れ以上追加ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“ãŒã€ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ã§ãªã„メンãƒãƒ¼ã‚’削除ã—ã¦æ–°è¦ãƒ¡ãƒ³ãƒãƒ¼ã«ç½®ãæ›ãˆã‚‹ãªã©ã€æ—¢å­˜ã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’管ç†ã§ãã¾ã™ã€‚"
-
-msgid "FreeUserCap|Manage members"
-msgstr "メンãƒãƒ¼ã®ç®¡ç†"
-
-msgid "FreeUserCap|Manage members:"
-msgstr "メンãƒãƒ¼ã®ç®¡ç†:"
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr "より多ãã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’ç²å¾—ã™ã‚‹ã«ã¯GitLab Premiumã¾ãŸã¯GitLab Ultimateã®%{trial_link_start}試用版を開始%{trial_link_end}ã¾ãŸã¯%{upgrade_link_start}ã“れらã«ã‚¢ãƒƒãƒ—グレード%{upgrade_link_end}ã—ã¾ã™ã€‚"
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr "より多ãã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’ç²å¾—ã™ã‚‹ã«ã¯ã€è©¦ç”¨ç‰ˆã‚’開始ã—ã¾ã™:"
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr "メンãƒãƒ¼ã®ä¸Šé™ã«é”ã—ã¾ã—ãŸ!"
-
msgid "Freeze end"
msgstr "フリーズ終了"
@@ -20548,7 +20750,7 @@ msgid "Geo|Last event ID from primary"
msgstr "プライマリã®æœ€çµ‚イベントID"
msgid "Geo|Last event ID processed"
-msgstr ""
+msgstr "最後ã«å‡¦ç†ã•ã‚ŒãŸã‚¤ãƒ™ãƒ³ãƒˆ ID"
msgid "Geo|Last repository check run"
msgstr "最後ã®ãƒªãƒã‚¸ãƒˆãƒªãƒã‚§ãƒƒã‚¯ã‚’実行"
@@ -20907,6 +21109,12 @@ msgstr "ç„¡æ–™ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãƒ¬ãƒ“ューã®å–å¾—"
msgid "Get a support subscription"
msgstr "サãƒãƒ¼ãƒˆã‚µãƒ–スクリプションã®å–å¾—"
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "ã¯ã˜ã‚ã‚‹"
@@ -21234,6 +21442,9 @@ msgstr "未確èª"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Pagesã®æ§‹æˆã‚’æ›´æ–°ã—ã¦ã„ã¾ã™..."
+msgid "GitLabPages|Use multiple versions"
+msgstr "複数ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’使用"
+
msgid "GitLabPages|Use unique domain"
msgstr "一æ„ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã‚’使用"
@@ -21249,6 +21460,9 @@ msgstr "有効ã«ã™ã‚‹ã¨ã€ãƒšãƒ¼ã‚¸ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã«ä¸€æ„ã®ãƒ‰
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr "ã“れを有効ã«ã™ã‚‹ã¨ã€HTTP経由ã§ã‚¦ã‚§ãƒ–サイトã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹æ™‚ã€ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã‚³ãƒ¼ãƒ‰301ã®å¿œç­”を使用ã—ã¦è‡ªå‹•çš„ã«HTTPSã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã•ã‚Œã¾ã™ã€‚ã™ã¹ã¦ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã«æœ‰åŠ¹ãªè¨¼æ˜Žæ›¸ãŒå¿…è¦ã§ã™ã€‚%{docs_link_start}詳ã—ãã¯ã“ã¡ã‚‰ã€‚%{link_end}"
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr "有効ã«ã™ã‚‹ã¨ã€ãƒšãƒ¼ã‚¸ã‚µã‚¤ãƒˆã®è¤‡æ•°ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’作æˆã§ãã¾ã™ã€‚"
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr "GitLabインスタンスã®æ¨™æº–ドメイン(%{pages_host})ã§Pagesを使用ã™ã‚‹å ´åˆã€ã‚µãƒ–サブドメインã§HTTPSを使用ã§ãã¾ã›ã‚“。ã“ã‚Œã¯ã€åå‰ç©ºé–“やグループåã«ãƒ‰ãƒƒãƒˆãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã«æ©Ÿèƒ½ã—ãªã„ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚ã“ã‚Œã¯ã€HTTP over TLSプロトコルã®åˆ¶é™ã§ã™ã€‚HTTPã‚’HTTPSã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã—ãªã„é™ã‚Šã€HTTPã®ãƒšãƒ¼ã‚¸ã¯å¼•ã続ã機能ã—ã¾ã™ã€‚%{docs_link_start}詳細ã¯ã“ã¡ã‚‰ã€‚%{link_end}"
@@ -21264,12 +21478,6 @@ msgstr "ã‚ãªãŸã®ãƒ—ロジェクトã¯Pages用ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ã€‚ã
msgid "Gitaly Servers"
msgstr "Gitalyサーãƒãƒ¼"
-msgid "Gitaly relative path:"
-msgstr "Gitaly相対パス:"
-
-msgid "Gitaly storage name:"
-msgstr "Gitalyストレージå:"
-
msgid "Gitaly timeouts"
msgstr "Gitalyタイムアウト"
@@ -21390,8 +21598,8 @@ msgstr "https://gitpod.example.comãªã©ã®ã‚ˆã†ãªã€GitLabプロジェクトã
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr "Gitpod を使用ã™ã‚‹ã«ã¯ã€%{linkStart}ユーザー設定%{linkEnd}ã®çµ±åˆã‚»ã‚¯ã‚·ãƒ§ãƒ³ã§ã“ã®æ©Ÿèƒ½ã‚’有効ã«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
-msgstr "ã“ã®ã‚¤ãƒ³ãƒ†ã‚°ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã‚’使用ã™ã‚‹ã«ã¯ã€å„ユーザー ㌠GitLab アカウント㧠Gitpod を有効ã«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚%{link_start}ã©ã†ã™ã‚Œã°æœ‰åŠ¹ã«ã§ãã¾ã™ã‹?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr "ã“ã®ã‚¤ãƒ³ãƒ†ã‚°ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã‚’使用ã™ã‚‹ã«ã¯ã€å„ユーザーãŒGitLabアカウントã§Gitpodを有効ã«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚%{help_link_start}ã©ã†ã™ã‚Œã°æœ‰åŠ¹ã«ã§ãã¾ã™ã‹?%{help_link_end}"
msgid "Gitpod|https://gitpod.example.com"
msgstr "https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr "%{time_ago} ã«ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯"
msgid "Given epic is already related to this epic."
msgstr "指定ã•ã‚ŒãŸã‚¨ãƒ”ックã¯ã™ã§ã«ã“ã®ã‚¨ãƒ”ックã¨é–¢é€£ã—ã¦ã„ã¾ã™ã€‚"
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr "インクルードã•ã‚ŒãŸè¨­å®šãƒ•ã‚¡ã‚¤ãƒ«ã® `spec` セクションã«å…¥åŠ›ãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
msgid "Global SAML group membership lock"
msgstr "グローãƒãƒ«SAMLグループã®ãƒ¡ãƒ³ãƒãƒ¼ã‚·ãƒƒãƒ—ロック"
@@ -21429,6 +21640,9 @@ msgstr "%{search}%{description}%{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr "%{count} 件ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®çµæžœãŒæä¾›ã•ã‚Œã¾ã™ã€‚上下矢å°ã‚­ãƒ¼ã‚’使用ã—ã¦ã€æ¤œç´¢çµæžœãƒªã‚¹ãƒˆã‚’ナビゲートã—ã¾ã™ã€‚"
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr "集約ã®èª­ã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼ã€‚"
@@ -21441,6 +21655,9 @@ msgstr "é–‰ã˜ã‚‹"
msgid "GlobalSearch|Fetching aggregations error."
msgstr "集計エラーをå–得中ã§ã™ã€‚"
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "グループ"
@@ -21481,7 +21698,7 @@ msgid "GlobalSearch|No labels found"
msgstr "ラベルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
msgid "GlobalSearch|Places"
-msgstr ""
+msgstr "場所"
msgid "GlobalSearch|Project"
msgstr "プロジェクト"
@@ -21510,9 +21727,6 @@ msgstr "検索"
msgid "GlobalSearch|Search GitLab"
msgstr "GitLab を検索"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr "GitLabを検索%{kbdOpen}/%{kbdClose}"
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "プロジェクトやイシューãªã©ã‚’検索ã—ã¾ã™ã€‚"
@@ -21543,6 +21757,9 @@ msgstr "検索オートコンプリート候補ã®å–得中ã«ã€ã‚¨ãƒ©ãƒ¼ãŒç™º
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr "「構文オプションã€ã®æ–‡æ›¸ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr "検索ã™ã‚‹ã«ã¯ %{kbdOpen}/%{kbdClose} ã¨å…¥åŠ›ã—ã¦ãã ã•ã„"
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "検索をé€ä¿¡ã™ã‚‹ã«ã¯ã€Enter キーを入力ã—ã¦ãã ã•ã„。"
@@ -21565,13 +21782,13 @@ msgid "GlobalSearch|in %{scope}"
msgstr "%{scope}内"
msgid "GlobalShortcuts|Copied reference to clipboard."
-msgstr ""
+msgstr "å‚照をクリップボードã«ã‚³ãƒ”ーã—ã¾ã—ãŸã€‚"
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr "ソースブランãƒåをクリップボードã«ã‚³ãƒ”ーã—ã¾ã—ãŸã€‚"
msgid "GlobalShortcuts|Unable to copy the reference at this time."
-msgstr ""
+msgstr "ç¾åœ¨ã€å‚照をコピーã§ãã¾ã›ã‚“。"
msgid "GlobalShortcuts|Unable to copy the source branch name at this time."
msgstr "ç¾åœ¨ã‚½ãƒ¼ã‚¹ãƒ–ランãƒåをコピーã§ãã¾ã›ã‚“。"
@@ -21783,6 +22000,12 @@ msgstr "èªè¨¼ã‚’失効ã™ã‚‹"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "GitLabã«ä»˜ä¸Žã•ã‚ŒãŸèªè¨¼ã‚’失効ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã£ã¦ã‚µãƒ¼ãƒ“スアカウントãŒç„¡åŠ¹ã«ãªã‚‹ã“ã¨ã¯ã‚ã‚Šã¾ã›ã‚“。"
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr "ä¿è­·ãƒ–ランãƒã¨ä¿è­·ã‚¿ã‚°ã«ã®ã¿å¤‰æ•°ã‚’設定ã™ã‚‹"
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr "ä¿è­·ãƒ–ランãƒã¨ä¿è­·ã‚¿ã‚°ã®ã¿"
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr "ã“ã“ã«ã‚­ãƒ¼ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ドラッグã™ã‚‹ã‹ã€%{linkStart}ã“ã“をクリックã—ã¦%{linkEnd}キーファイルをアップロードã—ã¾ã™ã€‚"
@@ -21798,7 +22021,7 @@ msgstr "Google Play"
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr "ç¾åœ¨ã®ã‚µãƒ¼ãƒ“スアカウントキーを使用ã™ã‚‹ã«ã¯ç©ºã®ã¾ã¾ã«ã—ã¦ãã ã•ã„。"
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr "サービスアカウントキー (.json)"
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr "グループアãƒã‚¿ãƒ¼"
msgid "Group by"
msgstr "グループæ¡ä»¶"
+msgid "Group by:"
+msgstr "グループæ¡ä»¶"
+
msgid "Group description (optional)"
msgstr "グループã®èª¬æ˜Ž (オプション)"
@@ -21975,9 +22201,6 @@ msgstr "グループå (ã‚ãªãŸã®çµ„ç¹”)"
msgid "Group navigation"
msgstr "グループナビゲーション"
-msgid "Group overview"
-msgstr "グループã®æ¦‚è¦"
-
msgid "Group overview content"
msgstr "グループ概è¦ã®å†…容"
@@ -22353,8 +22576,8 @@ msgstr "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—内ã®ãƒ—ロジェクトã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®
msgid "GroupSettings|Compliance frameworks"
msgstr "コンプライアンスフレームワーク"
-msgid "GroupSettings|Configure analytics features for this group"
-msgstr "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®åˆ†æžæ©Ÿèƒ½ã‚’設定ã™ã‚‹"
+msgid "GroupSettings|Configure analytics features for this group."
+msgstr "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®åˆ†æžæ©Ÿèƒ½ã‚’設定ã™ã‚‹."
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
msgstr "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒ—ロジェクトã§åˆ©ç”¨ã§ãるよã†ã«ã‚³ãƒ³ãƒ—ライアンスフレームワークを設定ã—ã¾ã™ã€‚%{linkStart}コンプライアンスフレームワークã¨ã¯ä½•ã§ã™ã‹? %{linkEnd}"
@@ -22542,8 +22765,8 @@ msgstr "ã“ã®æ©Ÿèƒ½ã‚’使用ã™ã‚‹ã«ã¯ã€ãƒ–ラウザーãŒlocalStorageã«å¯¾
msgid "GroupsDropdown|Toggle edit mode"
msgstr "編集モードã®åˆ‡ã‚Šæ›¿ãˆ"
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "グループã¯è¤‡æ•°ã®ãƒ—ロジェクトã®é›†åˆä½“ã§ã™ã€‚"
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr "グループã¨ã¯ã€è¤‡æ•°ã®ãƒ—ロジェクトã®é›†åˆä½“ã§ã™"
msgid "GroupsEmptyState|Create new project"
msgstr "æ–°è¦ãƒ—ロジェクトを作æˆ"
@@ -22554,8 +22777,8 @@ msgstr "æ–°ã—ã„サブグループを作æˆ"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "グループã¯ã€è¤‡æ•°ã®ãƒ—ロジェクトã¨ãƒ¡ãƒ³ãƒãƒ¼ã‚’管ç†ã™ã‚‹ãŸã‚ã®æœ€è‰¯ã®æ–¹æ³•ã§ã™ã€‚"
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "グループを使用ã—ã¦ãƒ—ロジェクトを整ç†ã™ã‚‹ã¨ã€ãƒ•ã‚©ãƒ«ãƒ€ã®ã‚ˆã†ã«æ©Ÿèƒ½ã—ã¾ã™ã€‚"
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr "グループã®ä¸‹ã§ãƒ—ロジェクトを整ç†ã™ã‚‹ã¨ã€ãƒ•ã‚©ãƒ«ãƒ€ã®ã‚ˆã†ã«å‹•ä½œã—ã¾ã™ã€‚ グループメンãƒãƒ¼ã®æ¨©é™ã‚’管ç†ã—ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®å„プロジェクトã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚"
msgid "GroupsEmptyState|No archived projects."
msgstr "アーカイブã•ã‚ŒãŸãƒ—ロジェクトã¯ã‚ã‚Šã¾ã›ã‚“。"
@@ -22572,9 +22795,6 @@ msgstr "サブグループやプロジェクトã¯ã‚ã‚Šã¾ã›ã‚“。"
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "プロジェクトã¯ã‚³ãƒ¼ãƒ‰ã‚’ä¿å­˜ã—ãŸã‚Šã€ã‚¤ã‚·ãƒ¥ãƒ¼ã€Wikiã€GitLabã®ãã®ä»–ã®æ©Ÿèƒ½ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãる場所ã§ã™ã€‚"
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "グループメンãƒãƒ¼ã®æ¨©é™ã€ãŠã‚ˆã³ã‚°ãƒ«ãƒ¼ãƒ—内ã®å„プロジェクトã¸ã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©é™ã‚’管ç†ã§ãã¾ã™ã€‚"
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«ã‚µãƒ–グループã¾ãŸã¯ãƒ—ロジェクトを作æˆã™ã‚‹ãŸã‚ã«å¿…è¦ãªæ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。新ã—ã„サブグループã¾ãŸã¯ãƒ—ロジェクトを作æˆã™ã‚‹ã«ã¯ã€ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ã‚ªãƒ¼ãƒŠãƒ¼ã«é€£çµ¡ã—ã¦ãã ã•ã„。"
@@ -22994,6 +23214,9 @@ msgstr "æ¯èªžã¸ã®GitLabã®ç¿»è¨³ã‚’支æ´ã™ã‚‹"
msgid "Help translate to your language"
msgstr "自分ã®è¨€èªžã«ç¿»è¨³ã™ã‚‹ã®ã‚’助ã‘ã‚‹"
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr "ボットãŒãƒ–ルートフォース攻撃を防ãã®ã«å½¹ç«‹ã¡ã¾ã™ã€‚"
@@ -23256,9 +23479,6 @@ msgstr "コードをä¿å­˜ã—ãŸã„"
msgid "I want to use GitLab CI with my existing repository"
msgstr "既存リãƒã‚¸ãƒˆãƒªã§ GitLab CI を使用ã—ãŸã„"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "GitLabã«ã¤ã„ã¦ã®æœ€æ–°æƒ…報をメールã§å—ã‘å–ã‚‹ã“ã¨ã‚’希望ã—ã¾ã™"
-
msgid "I'm signing up for GitLab because:"
msgstr "GitLab ã«ç™»éŒ²ã™ã‚‹ç†ç”±:"
@@ -23298,6 +23518,12 @@ msgstr "ã“ã®ãƒ—ロジェクトã§ã¯ã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’作æˆã™ã‚‹
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr "ç¾åœ¨ã®ãƒ–ランãƒã«å¯¾ã™ã‚‹æ›¸ãè¾¼ã¿æ¨©é™ãŒãªã„ãŸã‚ã€ã“ã®ã‚ªãƒ—ションã¯ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚"
+msgid "IDs with errors: %{error_messages}."
+msgstr "エラーã®ã‚ã‚‹ID: %{error_messages}."
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr "é‡è¦ï¼šã“ã®è¨­å®šã¯éžå¸¸ã«åŽ³ã—ã„監査目的ã§ã®ã¿ä½¿ç”¨ã—ã¦ãã ã•ã„。オンã«ã™ã‚‹ã¨ã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã•ã‚ŒãŸãƒ©ãƒ™ãƒ«ãŒãƒžãƒ¼ã‚¸ã•ã‚ŒãŸå¾Œã¯èª°ã‚‚を削除ã§ããªããªã‚Šã¾ã™ã€‚ ã•ã‚‰ã«ã€èª°ã‚‚ã“ã®è¨­å®šã‚’オフã«ã—ãŸã‚Šã€ãƒ©ãƒ™ãƒ«ã‚’削除ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "情報: SSHキーã®æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¦ã„ã¾ã™ã€‚æ–°ã—ã„SSHキーを生æˆã—ã¦ãã ã•ã„。"
@@ -23481,6 +23707,12 @@ msgstr "ãŠæ”¯æ‰•ã„方法ã®ç¢ºèª"
msgid "IdentityVerification|Verify phone number"
msgstr "電話番å·ã‚’確èª"
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr "代ã‚ã‚Šã«ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆã‚«ãƒ¼ãƒ‰ã§ç¢ºèªã—ã¾ã™ã‹ï¼Ÿ"
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr "代ã‚ã‚Šã«é›»è©±ç•ªå·ã§ç¢ºèªã—ã¾ã™ã‹ï¼Ÿ"
+
msgid "IdentityVerification|Verify your identity"
msgstr "本人確èªã‚’è¡Œã†"
@@ -23889,8 +24121,8 @@ msgstr "インãƒãƒ¼ãƒˆã®è©³ç´°ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚
msgid "Import|GitHub import details"
msgstr "GitHubインãƒãƒ¼ãƒˆã®è©³ç´°"
-msgid "Import|Maximum decompressed size (MiB)"
-msgstr "最大展開サイズ (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
+msgstr "インãƒãƒ¼ãƒˆã‹ã‚‰ã®ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–ã®æœ€å¤§è§£å‡ãƒ•ã‚¡ã‚¤ãƒ«ã‚µã‚¤ã‚º(MiB)"
msgid "Import|Maximum import remote file size (MB)"
msgstr "最大インãƒãƒ¼ãƒˆãƒªãƒ¢ãƒ¼ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚µã‚¤ã‚º (MB)"
@@ -23916,6 +24148,12 @@ msgstr "リãƒã‚¸ãƒˆãƒªã‚’インãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr "ã“ã® URL ã¯æœ‰åŠ¹ãª Git リãƒã‚¸ãƒˆãƒªã§ã¯ã‚ã‚Šã¾ã›ã‚“。HTTP ã®ãƒªãƒã‚¸ãƒˆãƒªãŒå…¬é–‹ã•ã‚Œã¦ã„ãªã„å ´åˆã¯ã€èªè¨¼æƒ…報を確èªã—ã¦ãã ã•ã„。"
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr "アーカイブã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’解å‡ã™ã‚‹ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆï¼ˆç§’)"
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr "アーカイブã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’解å‡ã™ã‚‹ãŸã‚ã®ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã€‚"
+
msgid "Improve customer support with Service Desk"
msgstr "サービスデスクã§ã‚«ã‚¹ã‚¿ãƒžãƒ¼ã‚µãƒãƒ¼ãƒˆã‚’改善ã—ã¾ã™"
@@ -23958,381 +24196,72 @@ msgstr "使用中"
msgid "InProductMarketing|%{organization_name} logo"
msgstr "%{organization_name} ロゴ"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr "%{strong_start}アプリケーションã®é«˜åº¦ãªã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£%{strong_end} — SASTã€DASTスキャンã€FUZZテストã€ä¾å­˜é–¢ä¿‚スキャンã€ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã‚³ãƒ³ãƒ—ライアンスã€ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆæ¤œå‡ºã‚’å«ã‚€"
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr "%{strong_start}全社的ãªãƒãƒ¼ãƒˆãƒ•ã‚©ãƒªã‚ªç®¡ç†%{strong_end} — マルãƒãƒ¬ãƒ™ãƒ«ã®ã‚¨ãƒ”ックã€ã‚¹ã‚³ãƒ¼ãƒ—ラベルをå«ã‚€"
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr "%{strong_start}エグゼクティブレベルã®æ´žå¯Ÿ%{strong_end} — 生産性ã€ã‚¿ã‚¤ãƒ—別ã®ã‚¿ã‚¹ã‚¯ã€å®Œäº†ã¾ã§ã®æ—¥æ•°ã€ãƒãƒªãƒ¥ãƒ¼ã‚¹ãƒˆãƒªãƒ¼ãƒ ã«ã¤ã„ã¦ã®ãƒ¬ãƒãƒ¼ãƒˆã‚’å«ã‚€"
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr "%{strong_start}GitLab Inc.%{strong_end}268 Bush Street, #350, San Francisco, CA 94104, USA"
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr "%{strong_start}複数ã®æ‰¿èªãƒ­ãƒ¼ãƒ«%{strong_end} — コードオーナーã¨ãƒžãƒ¼ã‚¸æ‰¿èªã«å¿…è¦ãªãƒ­ãƒ¼ãƒ«ã‚’å«ã‚€"
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr "*GitLab*ã€å詞:効率的ãªãƒãƒ¼ãƒ ã®åŒç¾©èªž"
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...ãã—ã¦GitLab Ultimateã®ç„¡æ–™ãƒˆãƒ©ã‚¤ã‚¢ãƒ«ã‚’入手ã§ãã¾ã™"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr "GitLab CI/CD を始ã‚ã‚‹3ã¤ã®æ–¹æ³•"
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr "実際ã€GitLabã¯ãƒãƒ¼ãƒ ãƒ¯ãƒ¼ã‚¯ã‚’より良ã„ã‚‚ã®ã«ã—ã¾ã™"
-
msgid "InProductMarketing|Advanced security testing"
msgstr "高度ãªã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ†ã‚¹ãƒˆ"
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr "ãã—ã¦æœ€å¾Œã«Pythonアプリケーションを%{deploy_link}ã—ã¾ã™ã€‚"
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "Runner ã®æº–å‚™ã¯ã§ãã¦ã„ã¾ã™ã‹?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr "GitLab内ã®ç›´æŽ¥è‡ªå‹•ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚¹ã‚­ãƒ£ãƒ³"
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "DevOps ã®ãƒ’ーローã«ãªã‚‹"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr "セキュリティを強化"
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "短ã„時間ã§ã‚ˆã‚Šè‰¯ã„コード"
-
msgid "InProductMarketing|Blog"
msgstr "ブログ"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr "iOSå‘ã‘ã®ãƒ“ルドã§ã™ã‹?ç§ãŸã¡ã¯ã‚«ãƒãƒ¼ã—ã¦ã„ã¾ã™ã€‚"
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr "コードオーナーã¨ãƒžãƒ¼ã‚¸æ‰¿èªå¿…須化を有効化ã™ã‚‹ã“ã¨ã§ã€å€‹ã€…ã®MRã‚’é©åˆ‡ãªäººãŒãƒ¬ãƒ“ューã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šç°¡æ½”ãªã‚³ãƒ¼ãƒ‰ã¨åŠ¹çŽ‡çš„ãªãƒ¬ãƒ“ュープロセスãŒå®Ÿç¾ã—ã¾ã™ã€‚"
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr "コードオーナーã¨ãƒžãƒ¼ã‚¸æ‰¿èªãƒ­ãƒ¼ãƒ«ã¯ã€GitLabã®æœ‰æ–™æ©Ÿèƒ½ã®ä¸€éƒ¨ã§ã™ã€‚GitLab Ultimateã®30日間ã®ç„¡æ–™ãƒˆãƒ©ã‚¤ã‚¢ãƒ«ã‚’開始ã—ã¾ã—ょã†ã€‚クレジットカードを必è¦ã¨ã›ãšã«5分以内ã«ã“れらã®æ©Ÿèƒ½ã‚’有効ã«ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr "数回ã®ã‚¯ãƒªãƒƒã‚¯ã§ã‚«ã‚¹ã‚¿ãƒ  CI Runner を作æˆ"
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr "カスタム Runner を作æˆ"
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "5分ã§GitLabã®ãƒ—ロジェクトを作æˆã™ã‚‹"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "最åˆã®ãƒ—ロジェクトを作æˆã—ã¾ã—ょã†!"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr "優れãŸè£½å“ã‚’ã™ã°ã‚„ã届ã‘ã‚‹"
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr "GitLabを使用ã™ã‚‹ãƒãƒ¼ãƒ ãŒã¯ã‚‹ã‹ã«åŠ¹çŽ‡çš„ã§ã‚ã‚‹ã“ã¨ã‚’ã”存知ã§ã—ãŸã‹?"
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr "プロジェクトã¨ãƒªãƒã‚¸ãƒˆãƒªã‚’掘り下ã’ã¦ä½œæˆ"
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr "ã“ã®ã‚¿ã‚¹ã‚¯ã«æœ€é©ãªãƒãƒ¼ãƒ ãƒ¡ã‚¤ãƒˆãŒã„ã¾ã™ã‹?"
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr "GitLab ã®ç„¡æ–™ãƒˆãƒ©ã‚¤ã‚¢ãƒ«ã§ DevOps ã®å¯èƒ½æ€§ã‚’広ã’ã¾ã—ょã†"
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "GitLab CI/CDã®æŽ¢ç´¢"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "オプションã®æŽ¢ç´¢"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr "GitLab CI/CDã®ãƒ‘ワーを探索"
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr "スピードã¯å¿…è¦ã ã¨æ€ã„ã¾ã›ã‚“ã‹?"
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr "ãƒãƒ¼ãƒ ãŒå®Ÿéš›ã«ã©ã®ã‚ˆã†ã«å–り組んã§ã„ã‚‹ã‹ã‚’知る"
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "手順ã«å¾“ã£ã¦ãã ã•ã„"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "30 日間無料トライアル"
msgid "InProductMarketing|Free guest users"
msgstr "無料ゲストユーザー"
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr "%{quick_start_link}を使用ã—ã¦ã€CI/CDã‚’ç´ æ—©ã利用ã§ãã¾ã™ã€‚利用å¯èƒ½ãªRunnerã‹ã‚‰å§‹ã‚ã¦ã€CIã®.ymlファイルを作æˆã—ã¾ã™ã€‚ã“ã‚Œã¯æœ¬å½“ã«ç°¡å˜ã§ã™ã€‚"
-
-msgid "InProductMarketing|Get our import guides"
-msgstr "インãƒãƒ¼ãƒˆã‚¬ã‚¤ãƒ‰ã‚’手ã«ã„れよã†"
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr "iOSå‘ã‘ã«ãƒ“ルドをセットアップã™ã‚‹"
-msgid "InProductMarketing|Get started today"
-msgstr "今日ã‹ã‚‰å§‹ã‚ã‚‹"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr "30日間ã®GitLab Ultimate試用版を今ã™ã始ã‚ã¾ã—ょã†ã€‚クレジットカードã¯å¿…è¦ã‚ã‚Šã¾ã›ã‚“。"
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr "GitLab CI/CDを始ã‚ã‚‹"
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr "GitLab CI/CDを知る"
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr "GitLabã§ãƒãƒ¼ãƒ ã‚’セットアップã™ã‚‹"
-
-msgid "InProductMarketing|Git basics"
-msgstr "Gitã®åŸºæœ¬"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr "GitHub EnterpriseプロジェクトをGitLabã¸"
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr "GitLabã¯é™çš„アプリケーションセキュリティテスト(SAST)ã€å‹•çš„アプリケーションセキュリティテスト(DAST)ã€ã‚³ãƒ³ãƒ†ãƒŠã‚¹ã‚­ãƒ£ãƒ³ã€ãŠã‚ˆã³ä¾å­˜é–¢ä¿‚スキャンをæä¾›ã—ã¾ã™ã€‚ã“れらã¯ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã‚³ãƒ³ãƒ—ライアンスã«æº–æ‹ ã—ãŸå®‰å…¨ãªã‚¢ãƒ—リケーションをæä¾›ã™ã‚‹ã®ã«å½¹ç«‹ã¡ã¾ã™ã€‚"
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr "GitLabã®CI/CDã¯ã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢é–‹ç™ºã‚’ç°¡å˜ã«ã—ã¾ã™ã€‚ä¿¡ã˜ã‚‰ã‚Œã¾ã›ã‚“ã‹? 以下ã®3ã¤ã®æ–¹æ³•ã§ã€è¿…速ã‹ã¤æº€è¶³ã®ã„ãテストを実ç¾ã§ãã¾ã™:"
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr "GitLabã®ãƒ—レミアムã¯ã€ã‚ãªãŸã€ã‚ãªãŸã®ãƒãƒ¼ãƒ ã€ãŠã‚ˆã³ã‚ãªãŸã®ã‚¢ãƒ—リケーションをより効率的ã‹ã¤ã‚ˆã‚Šå®‰å…¨ã«ãªã‚‹ã‚ˆã†ã«ã€æ¬¡ã®æ©Ÿèƒ½ã‚’å«ã‚€ã•ã¾ã–ã¾ãªæ©Ÿèƒ½ã‚’ã‚‚ã£ã¦ã„ã¾ã™:"
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "ç§ãŸã¡ã«1分ãã ã•ã„。"
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr "GitLabã§ã•ã‚‰ã«è©³ã—ã"
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr "ゴールドマン・サックスã¯2週間ã”ã¨ã«1æ—¥1回ã®ãƒ“ルドã‹ã‚‰1日数åƒå›žã®ãƒ“ルドã«ç§»è¡Œã—ã¾ã—ãŸ"
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr "インãƒãƒ¼ãƒˆã—ãŸã„別ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã‚ã‚Šã¾ã™ã‹ï¼Ÿã“ã¡ %{import_link}を利用ã—ã¦ãã ã•ã„。"
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr "知ã£ã¦ãŠãå¿…è¦ã®ã‚ã‚‹ã“ã¨ã‚’挙ã’ã¾ã™ã€‚"
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr "ミラーリングãŒã©ã®ã‚ˆã†ã«è¡Œãªãˆã€ãã—ã¦ãªãœå¿…è¦ã‹"
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr "機能リクエストã€ãƒã‚°ã€æŠ€è¡“的負債ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãªã©ã®ã‚¿ã‚¤ãƒ—毎ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚„マージリクエストを解決ã™ã‚‹ã®ã«ã©ã®ãらã„時間ãŒã‹ã‹ã‚Šã¾ã™ã‹?"
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr "ãƒãƒ¼ãƒ ãŒæ§˜ã€…ãªã‚¿ã‚¹ã‚¯ã‚’完了ã•ã›ã‚‹ã®ã«ä½•æ—¥ã‹ã‹ã‚Šã¾ã™ã‹?"
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr "ビルドã¨ãƒ†ã‚¹ãƒˆã‚’高速化ã™ã‚‹æ–¹æ³•"
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr "GitLabã‹ã‚‰ç›´æŽ¥ãƒžãƒ¼ã‚±ãƒ†ã‚£ãƒ³ã‚°ãƒ¡ãƒ¼ãƒ«ã‚’å—ä¿¡ã—ãŸããªã„å ´åˆã€%{marketing_preference_link}を押下ã—ã¦ãã ã•ã„。"
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr "ç§ãŸã¡ã‹ã‚‰ãƒžãƒ¼ã‚±ãƒ†ã‚£ãƒ³ã‚°ãƒ¡ãƒ¼ãƒ«ã‚’å—ä¿¡ã—ãŸããªã„å ´åˆ"
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr "GitHubã€Bitbucketã‚„ãã®ä»–ã‹ã‚‰ãƒ—ロジェクトã¨ã‚³ãƒ¼ãƒ‰ã‚’インãƒãƒ¼ãƒˆ"
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr "30日間ã®è©¦ç”¨ç‰ˆã§ã‚¢ãƒ—リã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚’å‘上"
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr "コードå“質を改善ã•ã›ã€ãƒ¬ãƒ“ューをåˆç†åŒ–ã™ã‚‹"
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr "é‹ç”¨åŠ¹çŽ‡ã®å‘上"
-msgid "InProductMarketing|Invite them to help out."
-msgstr "招待ã—ã¦æ‰‹ä¼ã£ã¦ã‚‚らã„ã¾ã—ょã†ã€‚"
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr "何人ã§ã‚‚ãŠå¥½ããªã ã‘åŒåƒšã‚’招待"
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "åŒåƒšã‚’招待ã—ã€ã‚³ãƒ¼ãƒ‰ã®å‡ºè·ã‚’速ãã—ã¾ã™ã€‚"
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "1分以内ã«åŒåƒšã‚’招待ã™ã‚‹"
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "今日ã€ã‚ãªãŸã®åŒåƒšã‚’招待ã—ã¾ã—ょã†"
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "60秒以内ã«ãƒãƒ¼ãƒ ã‚’招待ã™ã‚‹"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "今ã™ããƒãƒ¼ãƒ ã‚’招待ã™ã‚‹"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr "ãƒãƒ¼ãƒ ã‚’招待ã—ã¦ã€ã‚ˆã‚Šè‰¯ã„コード (ãŠã‚ˆã³ãƒ—ロセス) を作æˆã—ã¾ã—ょã†"
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr "ã™ã¹ã¦çµ±è¨ˆã«å«ã¾ã‚Œã¦ã„ã¾ã™"
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr "GitLabã®CI/CDを利用ã™ã‚‹ãŸã‚ã«ã¯ã€å˜ç´”ã«%{external_repo_link}ã ã‘ã§ã‚‚å¯èƒ½ã§ã™ã€‚"
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr "20分以内ã«GitLab CI/CDã‚’èµ·å‹•"
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr "iOS用ã®ãƒ“ルド方法を学ã¶"
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr "切り替ãˆã¾ã™ã‹? プロジェクトをGitLabã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã®ã¯ã‚ãªãŸãŒè€ƒãˆã¦ã„るより簡å˜ã§ã™ã€‚移動も%{github_link}インãƒãƒ¼ãƒˆ%{bitbucket_link}ã‚‚ã§ãã¾ã™ã€‚"
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr "インãƒãƒ¼ãƒˆæŠ€è¡“をマスターã—よã†!"
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr "ページã®ã‚¦ã‚§ãƒ–サイト %{ci_template_link}ã‚’ç°¡å˜ã«ä½œæˆã™ã‚‹ãŸã‚ã«ç§»å‹•ã—ã¾ã™"
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr "所有者ãŒè¤‡æ•°ã„ãŸã‚Šã€ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒˆãƒªãƒ¼ãƒ ãŒæ··ä¹±ã—ã¦ã„ã¾ã›ã‚“ã‹? ç§ãŸã¡ã¯ã©ã¡ã‚‰ã‚‚ã‚«ãƒãƒ¼ã§ãã¾ã™"
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr "インãƒãƒ¼ãƒˆã«ä»£ã‚ã‚‹ã‚‚ã®ãŒå¿…è¦ã§ã™ã‹ï¼Ÿ"
-
msgid "InProductMarketing|No credit card required."
msgstr "クレジットカードã¯å¿…è¦ã‚ã‚Šã¾ã›ã‚“。"
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr "ç§ãŸã¡ã®ãƒ„ールã¯ã™ã¹ã¦ã®ã‚‚ã®ã‚’ã¾ã¨ã‚ã¦ã„ã¾ã™"
-
msgid "InProductMarketing|Portfolio management"
msgstr "ãƒãƒ¼ãƒˆãƒ•ã‚©ãƒªã‚ªç®¡ç†"
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr "迅速ãªé–‹ç™ºã€ç°¡ç•¥åŒ–"
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr "セキュリティã¨ã‚³ãƒ³ãƒ—ライアンスリスクã®ä½Žæ¸›"
msgid "InProductMarketing|Security risk mitigation"
msgstr "セキュリティリスクã®è»½æ¸›"
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr "開発ライフサイクルã«çµ±åˆã•ã‚ŒãŸã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£"
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr "æ–°ã—ã„ツールã«å®Œå…¨ã«ç§»è¡Œã™ã‚‹æº–å‚™ãŒã§ãã¦ã„ãªã„å ´åˆãŒã‚ã‚Šã¾ã™ã€‚完全ã«ç§»è¡Œã§ãã‚‹ã¨æ˜Žè¨€ã§ããªã„å ´åˆã€%{mirroring_link}ã¯ç¾åœ¨ã®ãƒ„ールã¨ä¸¦è¡Œã—ã¦GitLabを試ã™å®‰å…¨ãªæ–¹æ³•ã‚’æä¾›ã—ã¾ã™ã€‚"
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr "GitLab ã§è‡ªå‹•ã‚¹ã‚±ãƒ¼ãƒªãƒ³ã‚°ãƒ©ãƒ³ãƒŠãƒ¼ã‚’スピンアップ"
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "今ã™ãGitLab Ultimateã®è©¦ç”¨ç‰ˆã‚’1分未満ã§é–‹å§‹ã—ã¾ã—ょã†ã€‚クレジットカードã¯å¿…è¦ã‚ã‚Šã¾ã›ã‚“。"
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr "自己管ç†åž‹ãƒˆãƒ©ã‚¤ã‚¢ãƒ«ã‚’始ã‚ã‚‹"
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "GitLab Ultimate ã®ç„¡æ–™ãƒˆãƒ©ã‚¤ã‚¢ãƒ«ã‚’開始 – クレジットカードã¯ä¸è¦ã§ã™"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "試用版を開始"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "%{performance_link} ã§é–‹å§‹"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "プロジェクトをインãƒãƒ¼ãƒˆã—ã¦å§‹ã‚ã‚‹"
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "GitLab Ultimateã®ç„¡æ–™è©¦ç”¨ç‰ˆã‚’始ã‚ã‚‹"
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "試用版を開始!"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr "今ã™ã試用版を開始ã—ã€ã‚·ãƒ³ã‚°ãƒ«ã‚¢ãƒ—リケーションã®æ€§èƒ½ã‚’体験ã—ã€GitLab Ultimate ã®å…¨æ©Ÿèƒ½ã‚’ç„¡æ–™ã§ãŠè©¦ã—ãã ã•ã„!"
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr "ç–‘å•ã«æ€ã†ã®ã‚’ã‚„ã‚ã¦ã€GitLabを使ã£ã¦ä»¥ä¸‹ã®ã‚ˆã†ãªè³ªå•ã«ç­”ãˆã¦ãã ã•ã„:"
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr "コードレビューをåˆç†åŒ–ã—ã€ã ã‚ŒãŒåˆ©ç”¨ã§ããªã„ã®ã‹ã‚’一目ã§çŸ¥ã‚Šã€ã‚³ãƒ¡ãƒ³ãƒˆã‚„メールã§ã‚³ãƒŸãƒ¥ãƒ‹ã‚±ãƒ¼ã‚·ãƒ§ãƒ³ã‚’å–ã‚Šã€Slackã¨çµ±åˆã™ã‚‹ã“ã¨ã§ã€ã ã‚Œã‚‚ãŒåŒã˜ãƒšãƒ¼ã‚¸ã«ã„ã‚‹ã®ã§ã™ã€‚"
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr "GitLabã®æœ€åˆã®ã‚¹ãƒ†ãƒƒãƒ—を実行ã™ã‚‹"
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr "ソースコード管ç†ã‚’次ã®ãƒ¬ãƒ™ãƒ«ã«å¼•ã上ã’よã†"
-
msgid "InProductMarketing|Team members collaborating"
msgstr "ãƒãƒ¼ãƒ ãƒ¡ãƒ³ãƒãƒ¼ã®ã‚³ãƒ©ãƒœãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³"
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr "GitLab ã§å”力ã—ã¦åŠ¹çŽ‡ã‚¢ãƒƒãƒ—"
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr "ãƒãƒ¼ãƒ ãƒ¯ãƒ¼ã‚¯ã§å¤¢ã‚’実ç¾ã—ã¾ã—ょã†"
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr "テストã€ä½œæˆã€ãƒ‡ãƒ—ロイ"
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr "GitLabを使ã†ã®ã¯ãã‚Œã ã‘ã§ã™ã€‚ã‚‚ã—Gitを使ã†ã®ãŒåˆã‚ã¦ã®å ´åˆã€ç§ãŸã¡ã®%{basics_link}を見ã¦ã€å§‹ã‚ã‚‹ãŸã‚ã®ãƒ’ントやコツをã”覧ãã ã•ã„。"
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr "ã“ã‚Œã¯ã€%{track} シリーズã®ãƒ¡ãƒ¼ãƒ« (%{current_series} / %{total_series}) ã§ã™ã€‚"
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr "ã“ã‚Œã¯ã€%{track} シリーズã®ãƒ¡ãƒ¼ãƒ«(%{current_series} / %{total_series})ã§ã™ã€‚ローカル㮠GitLab インスタンスã‹ã‚‰ã®é€šçŸ¥ãƒ¡ãƒ¼ãƒ«ã‚’無効ã«ã™ã‚‹ã«ã¯ã€ç®¡ç†è€…ã«é€£çµ¡ã™ã‚‹ã‹ã€%{unsubscribe_link}をクリックã—ã¦ãã ã•ã„。"
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr "Ticketmasterã®CI ビルド時間を15分ã®1ã«çŸ­ç¸®ã—ã¾ã—ãŸ"
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr "ã•ã¾ã–ã¾ãªãƒ„ールãƒã‚§ãƒ¼ãƒ³ã€æƒ…å ±ã®ã‚µã‚¤ãƒ­åŒ–ã€éžåŠ¹çŽ‡ãªãƒ—ロセスã¨ã®èª¿æ•´ã«ã†ã‚“ã–ã‚Šã—ã¦ã„ã¾ã›ã‚“ã‹? GitLabã®CI/CDã¯ã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ç®¡ç†ã€è¨ˆç”»ã€ç›£è¦–ã€æº–å‚™ãŒæ•´ã£ãŸDevOpsプラットフォーム上ã«æ§‹ç¯‰ã•ã‚Œã¦ã„ã¾ã™ã€‚%{ci_link} ã‚’ã”覧ãã ã•ã„。"
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr "ã“れらã®ã‚ªãƒ³ãƒœãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ãƒ¡ãƒ¼ãƒ«ã‹ã‚‰é™¤å¤–ã™ã‚‹ã«ã¯ã€%{unsubscribe_link}."
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr "GitLab ã‚’ç†è§£ã—ã€æœ€å¤§é™ã«æ´»ç”¨ã™ã‚‹ãŸã‚ã«ã€æœ€åˆã¯ %{project_link}ã‹ã‚‰å§‹ã‚ã¾ã™ã€‚GitLab ã§ã¯ã€ãƒªãƒã‚¸ãƒˆãƒªã¯ãƒ—ロジェクトã®ä¸€éƒ¨ã§ã‚ã‚‹ãŸã‚ã€ãƒ—ロジェクトを作æˆã—ãŸå¾Œã€ã™ãã«å…ˆã¸é€²ã‚€ã“ã¨ãŒã§ãã¾ã™ %{repo_link}。"
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "GitLab Ultimateã‚’ç„¡æ–™ã§è©¦ã—ã¾ã—ょã†"
-
-msgid "InProductMarketing|Try it out"
-msgstr "試ã—ã¦ã¿ã‚‹"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "自分ã§è©¦ã™"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr "åŒåƒšã¨ã‚³ãƒ©ãƒœãƒ¬ãƒ¼ãƒˆã—ã¾ã—ょã†"
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr "リãƒã‚¸ãƒˆãƒªã®ãƒŸãƒ©ãƒ¼ãƒªãƒ³ã‚°ã‚’ç†è§£"
-
-msgid "InProductMarketing|Understand your project options"
-msgstr "プロジェクトオプションをç†è§£"
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr "GitLab CI/CD ã®ä½¿ç”¨"
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr "AWS ã®ã‚¯ãƒ©ã‚¦ãƒ‰ãƒ•ã‚©ãƒ¼ãƒ¡ãƒ¼ã‚·ãƒ§ãƒ³ãƒ†ãƒ³ãƒ—レートを使用ã™ã‚‹ã¨ã€æ•°å›žã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã ã‘㧠Runner ã‚’èµ·å‹•ã§ãã¾ã™!"
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr "世界中㮠10 万以上ã®çµ„ç¹”ã§ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™:"
@@ -24348,66 +24277,15 @@ msgstr "自分ã®ã‚µãƒ¼ãƒãƒ¼ã§ GitLab をホストã—ãŸã„ã§ã™ã‹?"
msgid "InProductMarketing|Watch iOS building in action."
msgstr "iOSã®ãƒ“ルドを実際ã«è¦‹ã¦ã¿ã¾ã—ょã†ã€‚"
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr "効率性ã«ã¤ã„ã¦ã¯1ã¤ã¾ãŸã¯2ã¤ã®ã“ã¨ã‚’知ã£ã¦ã„ã¾ã™ãŒã€ãれを自分自身ã«éš ã—ãŸãã¯ã‚ã‚Šã¾ã›ã‚“。GitLab Ultimateã®ç„¡æ–™ãƒˆãƒ©ã‚¤ã‚¢ãƒ«ã«ã‚µã‚¤ãƒ³ã‚¢ãƒƒãƒ—ã™ã‚‹ã¨ã€ãƒãƒ¼ãƒ ã¯åˆæ—¥ã‹ã‚‰ä½¿ç”¨ã§ãã¾ã™ã€‚"
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr "製å“ã‹ã‚‰é–‹ç™ºã€ãƒ¬ãƒ“ューã€å®Ÿç¨¼åƒã¾ã§ã®ãƒãƒªãƒ¥ãƒ¼ã‚¹ãƒˆãƒªãƒ¼ãƒ ã®ã‚¿ã‚¤ãƒ ãƒ©ã‚¤ãƒ³ã¯ã©ã®ã‚ˆã†ã«ãªã£ã¦ã„ã¾ã™ã‹ ?"
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr "ã‚ãªãŸã®ãƒãƒ¼ãƒ ãŒGitLab を使用ã—ã¦ã„ã‚‹ãªã‚‰ã€ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã ã‘ã§ç­”ãŒå¾—られã¾ã™ã€‚"
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr "GitLab ã§ã®ä½œæ¥­ã¯ã¨ã¦ã‚‚効率的ã§ã™"
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr "ãƒãƒ¼ãƒ ã‚’より効率的ã«ã§ãã¾ã™"
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "包括的ãªã‚¬ã‚¤ãƒ‰"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "外部リãƒã‚¸ãƒˆãƒªã«æŽ¥ç¶š"
-
-msgid "InProductMarketing|create a project"
-msgstr "プロジェクトを作æˆ"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "Bitbucket ã‹ã‚‰"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "about.gitlab.com ã«ç§»å‹•"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "始ã‚ã‚‹ã®ãŒã„ã‹ã«ç°¡å˜ã‹"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "クイックスタートガイド"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "リãƒã‚¸ãƒˆãƒªãƒŸãƒ©ãƒ¼ãƒªãƒ³ã‚°"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "リãƒã‚¸ãƒˆãƒªã‚’設定"
-
-msgid "InProductMarketing|test and deploy"
-msgstr "テストã¨ãƒ‡ãƒ—ロイ"
-
-msgid "InProductMarketing|testing browser performance"
-msgstr "ブラウザーã®ãƒ‘フォーマンスをテスト"
-
msgid "InProductMarketing|unsubscribe"
msgstr "購読解除"
-msgid "InProductMarketing|update your preferences"
-msgstr "設定を更新ã™ã‚‹"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr "CI/CD ã®ãƒ†ãƒ³ãƒ—レートã®ä½¿ç”¨"
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "ã„ã¤ã§ã‚‚ %{unsubscribe_link} ã§ãã¾ã™ã€‚"
@@ -24837,6 +24715,14 @@ msgstr "インライン"
msgid "Inline math"
msgstr "インライン数å¼"
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] "%dコードå“質調査çµæžœãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸ"
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] "%d SAST調査çµæžœãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸ"
+
msgid "Input host keys manually"
msgstr "ホストキーã®æ‰‹å‹•å…¥åŠ›"
@@ -25192,6 +25078,9 @@ msgstr "ZenTao ã§ãƒ—ロジェクトã«ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆã™ã‚‹ã¨ã€ZenTao ã
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr "%{recipients_limit} を超ãˆã‚‰ã‚Œã¾ã›ã‚“"
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr "IntelliJ IDEA (HTTPS)"
@@ -25228,15 +25117,9 @@ msgstr "内部ユーザーを無効ã«ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
msgid "Interval"
msgstr "インターãƒãƒ«"
-msgid "Interval Pattern"
-msgstr "é–“éš”ã®ãƒ‘ターン"
-
msgid "Introducing Your DevOps Reports"
msgstr "DevOps レãƒãƒ¼ãƒˆã®ç´¹ä»‹"
-msgid "Introducing the Code Suggestions add-on"
-msgstr "コードã®æ案ã®ã€ã‚¢ãƒ‰ã‚ªãƒ³ã®ç´¹ä»‹"
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr "「schemaVersionã€ã€Œ%{schema_version}ã€ãŒç„¡åŠ¹ã§ã™"
@@ -25318,9 +25201,6 @@ msgstr "無効ãªã‚¿ã‚°"
msgid "Invalid two-factor code."
msgstr "無効㪠2è¦ç´ èªè¨¼ã‚³ãƒ¼ãƒ‰ã§ã™ã€‚"
-msgid "Invalid yaml"
-msgstr "無効ãªyaml"
-
msgid "Invalidated"
msgstr "å´ä¸‹"
@@ -25652,18 +25532,12 @@ msgstr "ã™ã¹ã¦ã®ã‚¹ãƒ¬ãƒƒãƒ‰ãŒè§£æ±ºã—ã¾ã—ãŸ"
msgid "IssuableEvents|unassigned"
msgstr "未割り当ã¦"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type}作æˆ%{created_at}者"
-
msgid "IssuableStatus|Closed"
msgstr "完了"
msgid "IssuableStatus|Closed (%{link})"
msgstr "完了 (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "作æˆ%{created_at}者"
-
msgid "IssuableStatus|duplicated"
msgstr "é‡è¤‡"
@@ -25913,29 +25787,48 @@ msgstr "エピックãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ãªã„イシュー"
msgid "Issues, merge requests, pushes, and comments."
msgstr "イシューã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã€ãƒ—ッシュã€ã‚³ãƒ¡ãƒ³ãƒˆ"
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "プロジェクトã®ã‚¤ã‚·ãƒ¥ãƒ¼ã®ä½œæˆã‚’開始ã—ãŸã‚‰ã€ãƒ—ロジェクトã®ãƒ¡ãƒˆãƒªã‚¯ã‚¹ã‚’追跡ã—ã¦è¡¨ç¤ºã§ãã¾ã™"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "月平å‡:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr "作æˆã•ã‚ŒãŸã‚¤ã‚·ãƒ¥ãƒ¼"
msgid "IssuesAnalytics|Issues created per month"
msgstr "月ã‚ãŸã‚Šã®ä½œæˆã•ã‚ŒãŸã‚¤ã‚·ãƒ¥ãƒ¼"
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "éŽåŽ»12ã‹æœˆé–“"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr "éŽåŽ» 12 ヶ月 (%{chartDateRange})"
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "申ã—訳ã‚ã‚Šã¾ã›ã‚“。指定ã—ãŸãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã§ã¯è©²å½“ã™ã‚‹çµæžœãŒã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "ã‚ãªãŸã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒ—ロジェクトã«ã¯ã‚¤ã‚·ãƒ¥ãƒ¼ãŒã‚ã‚Šã¾ã›ã‚“"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "検索範囲を拡大ã™ã‚‹ã«ã¯ã€ä¸Šè¨˜ã®ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ãƒãƒ¼ã§ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚’変更ã¾ãŸã¯å‰Šé™¤ã—ã¾ã™"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr "検索を拡大ã™ã‚‹ã«ã¯ã€ä¸Šè¨˜ã®ãƒ•ã‚£ãƒ«ã‚¿ãƒãƒ¼ã§ãƒ•ã‚£ãƒ«ã‚¿ã‚’変更ã¾ãŸã¯å‰Šé™¤ã—ã¾ã™."
msgid "IssuesAnalytics|Total:"
msgstr "åˆè¨ˆ:"
@@ -25982,6 +25875,9 @@ msgstr "斜体(%{modifierKey}I)"
msgid "Italic text"
msgstr "斜体"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr "ID:%{id}ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’追加ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。ã“ã®ã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã‚’実行ã™ã‚‹ãŸã‚ã®å分ãªæ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。"
+
msgid "Iteration"
msgstr "イテレーション"
@@ -26318,6 +26214,9 @@ msgstr "グループãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
msgid "JiraConnect|No linked groups"
msgstr "リンクã•ã‚ŒãŸã‚°ãƒ«ãƒ¼ãƒ—ãŒã‚ã‚Šã¾ã›ã‚“"
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr "グループãŒè¡¨ç¤ºã•ã‚Œã¾ã›ã‚“ã‹? ã“ã“ã«ã¯ã€ã‚¢ã‚¯ã‚»ã‚¹ã§ãるグループã®ã¿ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr "グループãŒè¡¨ç¤ºã•ã‚Œã¾ã›ã‚“ã‹? ã“ã“ã«ã¯ã€å°‘ãªãã¨ã‚‚メンテナーロールãŒã‚るグループã®ã¿ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
@@ -26816,6 +26715,9 @@ msgstr "所è¦æ™‚é–“"
msgid "Job|Erase job log and artifacts"
msgstr "ジョブã®ãƒ­ã‚°ã¨ã‚¢ãƒ¼ãƒ†ã‚£ãƒ•ã‚¡ã‚¯ãƒˆã‚’消去"
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr "失敗"
@@ -26867,6 +26769,9 @@ msgstr "å†è©¦è¡Œ"
msgid "Job|Run again"
msgstr "å†å®Ÿè¡Œ"
+msgid "Job|Runner type"
+msgstr "Runner ã®ã‚¿ã‚¤ãƒ—"
+
msgid "Job|Running"
msgstr "実行中"
@@ -26963,9 +26868,6 @@ msgstr "プロジェクトã«å‚加"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr "GitLabã§ãƒãƒ¼ãƒ ã«å‚加ã—ã€æ—¢å­˜ã®ãƒ—ロジェクトã«è²¢çŒ®ã—ã¾ã™ã€‚"
-msgid "Joined %{time_ago}"
-msgstr "%{time_ago}ã«å‚加ã—ã¾ã—ãŸ"
-
msgid "Joined %{user_created_time}"
msgstr "%{user_created_time}ã«å‚加ã—ã¾ã—ãŸ"
@@ -27226,9 +27128,6 @@ msgstr "å‰å›žã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティ"
msgid "Last Name"
msgstr "åå­—"
-msgid "Last Pipeline"
-msgstr "最新パイプライン"
-
msgid "Last Seen"
msgstr "最近見ãŸé †"
@@ -27325,6 +27224,9 @@ msgstr "プッシュ先:"
msgid "LastPushEvent|at"
msgstr "ã“ã®æ™‚刻ã«"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "最新ã®å¤‰æ›´"
@@ -27386,7 +27288,7 @@ msgid "Learn more about Needs relationships"
msgstr "ニーズ関係ã«ã¤ã„ã¦ã‚‚ã£ã¨è©³ã—ã"
msgid "Learn more about Service Desk"
-msgstr ""
+msgstr "サービスデスクã«ã¤ã„ã¦ã‚‚ã£ã¨è©³ã—ã"
msgid "Learn more about Web Terminal"
msgstr "Web ターミナルã®è©³ç´°"
@@ -28019,6 +27921,9 @@ msgstr "%{issuableType}をロック"
msgid "Lock File?"
msgstr "ファイルをロックã—ã¾ã™ã‹?"
+msgid "Lock label after a merge request is merged"
+msgstr "マージリクエストã®ãƒžãƒ¼ã‚¸å¾Œã«ãƒ©ãƒ™ãƒ«ã‚’ロック"
+
msgid "Lock memberships to LDAP synchronization"
msgstr "メンãƒãƒ¼ã‚·ãƒƒãƒ—ã‚’ LDAP åŒæœŸã«é™å®š"
@@ -28028,6 +27933,9 @@ msgstr "メンãƒãƒ¼ã‚·ãƒƒãƒ—ã‚’SAMLグループリンクåŒæœŸã«é™å®š"
msgid "Lock not found"
msgstr "ロックãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+msgid "Lock on merge"
+msgstr "マージ時ã«ãƒ­ãƒƒã‚¯"
+
msgid "Lock status"
msgstr "ロック状態"
@@ -28062,7 +27970,7 @@ msgid "LoggedOutMarketingHeader|About GitLab"
msgstr "GitLab ã«ã¤ã„ã¦"
msgid "LoggedOutMarketingHeader|Contact Sales"
-msgstr ""
+msgstr "営業担当者ã«é€£çµ¡"
msgid "LoggedOutMarketingHeader|Explore GitLab"
msgstr "GitLab を見る"
@@ -28092,7 +28000,7 @@ msgid "LoggedOutMarketingHeader|Talk to an expert"
msgstr "専門家ã¨è©±ã™"
msgid "LoggedOutMarketingHeader|Why GitLab"
-msgstr ""
+msgstr "GitLab ã®ç†ç”±"
msgid "Login with smartcard"
msgstr "スマートカードã§ãƒ­ã‚°ã‚¤ãƒ³"
@@ -28326,7 +28234,7 @@ msgid "Markdown enabled."
msgstr "Markdown を使用ã§ãã¾ã™ã€‚"
msgid "Markdown is supported"
-msgstr ""
+msgstr "マークダウンをサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™ã€‚"
msgid "Markdown supported."
msgstr "Markdown をサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™ã€‚"
@@ -28433,6 +28341,12 @@ msgstr "Mattermost URL:"
msgid "Mattermost notifications"
msgstr "Mattermost 通知"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr "Mattermost ã«è¿½åŠ "
@@ -28448,6 +28362,9 @@ msgstr "ãƒãƒ¼ãƒ ã«æœ€é©ãªãƒ¯ãƒ¼ãƒ‰ã‚’入力ã—ã¦ãã ã•ã„。"
msgid "MattermostService|Install"
msgstr "インストール"
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr "リクエスト URL"
@@ -28460,6 +28377,9 @@ msgstr "応答アイコン"
msgid "MattermostService|Response username"
msgstr "応答ユーザーå"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr "æ案:"
@@ -28766,6 +28686,102 @@ msgstr "%{member_name}ãŒã‚ãªãŸã‚’GitLabã«å‚加ã™ã‚‹ã‚ˆã†æ‹›å¾…ã—ã¾ã—ã
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr "%{project_or_group}ã®%{project_or_group_name}å‚加ã¸ã®æ‹›å¾…"
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr "%{permission}を有効ã«ã™ã‚‹ã«ã¯ã€%{requirement}を有効ã«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -28862,7 +28878,7 @@ msgid "Members|An error occurred while updating the member's role, please try ag
msgstr "メンãƒãƒ¼ã®ãƒ­ãƒ¼ãƒ«ã®æ›´æ–°ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
msgid "Members|Are you sure you want to deny %{usersName}'s request to join \"%{source}\""
-msgstr ""
+msgstr "%{usersName}ã®ã€Œ%{source}ã€ã¸ã®å‚加リクエストを本当ã«æ‹’å¦ã—ã¾ã™ã‹?"
msgid "Members|Are you sure you want to disable the two-factor authentication for %{userName}?"
msgstr "%{userName}ã®äºŒè¦ç´ èªè¨¼ã‚’無効ã«ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹?"
@@ -29021,6 +29037,9 @@ msgstr "マージコミットメッセージ"
msgid "Merge conflicts"
msgstr "マージã®å•é¡Œ"
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr "マージã®è©³ç´°"
@@ -29453,9 +29472,6 @@ msgstr "メトリクスã¨ãƒ—ロファイリング"
msgid "Metrics:"
msgstr "メトリクス:"
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr "starting_at よりå‰ã«å®Ÿè¡Œã§ãã¾ã›ã‚“"
-
msgid "Metrics|Create metric"
msgstr "メトリクスを作æˆ"
@@ -29552,6 +29568,9 @@ msgstr "Microsoft Azure インテグレーションã®è¨­å®šã®ä¿å­˜ã«å¤±æ•—ã
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr "Microsoft Azure インテグレーションã®è¨­å®šãŒæ­£å¸¸ã«æ›´æ–°ã•ã‚Œã¾ã—ãŸã€‚"
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr "SAML応答ã«è¶…éŽã‚¯ãƒ¬ãƒ¼ãƒ ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã€Microsoft Azureã‹ã‚‰ã‚°ãƒ«ãƒ¼ãƒ—メンãƒãƒ¼ã‚·ãƒƒãƒ—ã‚’åŒæœŸã—ã¾ã™ã€‚"
+
msgid "Microsoft|Tenant ID"
msgstr "テナント ID"
@@ -30430,12 +30449,12 @@ msgstr "ã©ã‚“ãªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ãŒåˆ¶é™ã•ã‚Œã¦ã„ã¾ã™ã‹ï¼Ÿ"
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr "%{name_with_link}ã®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸å®¹é‡ã‚’%{used_storage_percentage}ã¾ã§ä½¿ç”¨ã—ã¾ã—ãŸ(%{current_size} / %{limit})。"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
+msgstr ""
+
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr "%{name}ã®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸å®¹é‡ã‚’%{used_storage_percentage}ã¾ã§ä½¿ç”¨ã—ã¾ã—ãŸ(%{current_size} / %{limit})。"
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
-msgstr "%{namespace_name}ã®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸å®¹é‡ã‚’%{used_storage_percentage} %%ã¾ã§ä½¿ç”¨ã—ã¾ã—ãŸ"
-
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
msgstr "ä¿ç•™ä¸­ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—オーナーã«ã‚ˆã£ã¦å¯©æŸ»ã•ã‚Œæ‰¿èªã•ã‚Œãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。%{user_caps_link_start}ユーザーキャップ%{link_end}㨠%{users_pending_approval_link_start}承èªå¾…ã¡ãƒ¦ãƒ¼ã‚¶ãƒ¼%{link_end}ã«ã¤ã„ã¦ã¯ãƒªãƒ³ã‚¯å…ˆã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
@@ -30511,6 +30530,9 @@ msgstr "分æž"
msgid "Navigation|Build"
msgstr "ビルド"
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr "コード"
@@ -30541,15 +30563,18 @@ msgstr "よã使ã†ã‚°ãƒ«ãƒ¼ãƒ—ã¯ã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™."
msgid "Navigation|Leave admin mode"
msgstr "管ç†è€…モードを終了ã™ã‚‹"
-msgid "Navigation|Main navigation"
-msgstr "メインナビゲーション"
-
msgid "Navigation|Manage"
msgstr "管ç†"
+msgid "Navigation|Merge requests settings"
+msgstr ""
+
msgid "Navigation|Monitor"
msgstr "モニター"
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr "グループãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
@@ -30568,12 +30593,18 @@ msgstr "ピン留ã‚"
msgid "Navigation|Plan"
msgstr "計画"
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr "プロジェクト"
msgid "Navigation|Projects you visit often will appear here."
msgstr "よã使ã†ãƒ—ロジェクトをã“ã“ã«è¡¨ç¤ºã—ã¾ã™."
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr "検索çµæžœã®å–å¾—"
@@ -30592,6 +30623,12 @@ msgstr "検索çµæžœã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "Navigation|Unpin item"
msgstr "アイテムã®ãƒ”ン留ã‚を解除"
+msgid "Navigation|View all my groups"
+msgstr "ã™ã¹ã¦ã®ã‚°ãƒ«ãƒ¼ãƒ—を表示"
+
+msgid "Navigation|View all my projects"
+msgstr "ã™ã¹ã¦ã®ãƒ—ロジェクトを表示"
+
msgid "Navigation|View all your groups"
msgstr "ã™ã¹ã¦ã®ã‚°ãƒ«ãƒ¼ãƒ—を表示"
@@ -30815,9 +30852,6 @@ msgstr "イシュー#%{issue_iid}ã¸ã®æ–°ã—ã„レスãƒãƒ³ã‚¹"
msgid "New runners registration token has been generated!"
msgstr "æ–°ã—ã„ランナー登録トークンを生æˆã—ã¾ã—ãŸ!"
-msgid "New schedule"
-msgstr "æ–°ã—ã„スケジュール"
-
msgid "New snippet"
msgstr "æ–°ã—ã„スニペット"
@@ -31025,6 +31059,9 @@ msgstr "イテレーションãŒã‚ã‚Šã¾ã›ã‚“"
msgid "No label"
msgstr "ラベルãŒã‚ã‚Šã¾ã›ã‚“"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "ãã®åå‰ã¾ãŸã¯èª¬æ˜Žã®ãƒ©ãƒ™ãƒ«ãŒã‚ã‚Šã¾ã›ã‚“"
@@ -31049,6 +31086,12 @@ msgstr "一致ã™ã‚‹çµæžœãŒã‚ã‚Šã¾ã›ã‚“"
msgid "No matching results for \"%{query}\""
msgstr "「%{query}ã€ã«ä¸€è‡´ã™ã‚‹çµæžœãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+msgid "No matching work item found."
+msgstr "一致ã™ã‚‹ä½œæ¥­ã‚¢ã‚¤ãƒ†ãƒ ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr "一致ã™ã‚‹ä½œæ¥­ã‚¢ã‚¤ãƒ†ãƒ ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。有効ãªIDを追加ã—ã¦ãŠã‚Šã€ã‚¢ã‚¤ãƒ†ãƒ ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
+
msgid "No members found"
msgstr "メンãƒãƒ¼ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
@@ -31067,12 +31110,15 @@ msgstr "マイルストーンãªã—"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr "%{max_issues}件以上ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’åŒæ™‚ã«æ›´æ–°ã§ãã¾ã›ã‚“"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr "%{max_work_items}件以上ã®ä½œæ¥­ã‚¢ã‚¤ãƒ†ãƒ ã‚’åŒæ™‚ã«ä¿®æ­£ã§ãã¾ã›ã‚“。"
+
+msgid "No options found"
+msgstr ""
+
msgid "No other labels with such name or description"
msgstr "ãã®åå‰ã¾ãŸã¯èª¬æ˜Žã®ãƒ©ãƒ™ãƒ«ã¯ä»–ã«ã¯ã‚ã‚Šã¾ã›ã‚“"
-msgid "No panels matching properties %{opts}"
-msgstr "プロパティ%{opts}ã«ä¸€è‡´ã™ã‚‹ãƒ‘ãƒãƒ«ã¯ã‚ã‚Šã¾ã›ã‚“"
-
msgid "No parent group"
msgstr "親グループã¯ã‚ã‚Šã¾ã›ã‚“"
@@ -31127,9 +31173,6 @@ msgstr "çµæžœãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
msgid "No runner executable"
msgstr "実行å¯èƒ½ãªRunner ã¯ã‚ã‚Šã¾ã›ã‚“"
-msgid "No schedules"
-msgstr "スケジュールãªã—"
-
msgid "No service accounts"
msgstr "サービスアカウントãŒã‚ã‚Šã¾ã›ã‚“"
@@ -31181,6 +31224,12 @@ msgstr "Webhook イベントã¯ã‚ã‚Šã¾ã›ã‚“"
msgid "No webhooks enabled. Select trigger events above."
msgstr "Webhook ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã›ã‚“。上記ã®ãƒˆãƒªã‚¬ãƒ¼ã‚¤ãƒ™ãƒ³ãƒˆã‚’é¸æŠžã—ã¦ãã ã•ã„。"
+msgid "No work item IDs provided."
+msgstr "指定ã•ã‚ŒãŸä½œæ¥­ã‚¢ã‚¤ãƒ†ãƒ IDã¯ã‚ã‚Šã¾ã›ã‚“。"
+
+msgid "No work item found."
+msgstr "作業アイテムãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] "心é…ã¯ã„ã‚Šã¾ã›ã‚“。ç¾æ™‚点ã§ã€%{strong}%{plan_name}%{strong_close}ã®å…¨æ©Ÿèƒ½ã‚’ã”利用ã„ãŸã ã‘ã¾ã™ã€‚%{remaining_days} 日以内ã«ã‚µãƒ–スクリプションを更新ã—ã¦ãã ã•ã„。"
@@ -32379,6 +32428,9 @@ msgstr "一ã¤ä»¥ä¸Šã®ãƒ‘ーソナルアクセストークンã®æœŸé™ãŒåˆ‡ã‚Œ
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr "1ã¤ä»¥ä¸Šã®ãƒ‘ーソナルアクセストークンãŒ%{days_to_expire}日以内ã«å¤±åŠ¹ã—ã¾ã™"
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr "%{permissions}ã‚’æŒã¤%{workspaceType}メンãƒãƒ¼ã®ã¿ãŒã“ã®%{issuableType}ã«ã¤ã„ã¦é€šçŸ¥ã‚’å—ã‘å–ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
@@ -32406,9 +32458,6 @@ msgstr "%{membersPageLinkStart}プロジェクトメンãƒãƒ¼%{membersPageLinkEn
msgid "Only active projects show up in the search and on the dashboard."
msgstr "検索やダッシュボードã«è¡¨ç¤ºã•ã‚Œã‚‹ã®ã¯ã€ã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªãƒ—ロジェクトã®ã¿ã§ã™ã€‚"
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr "リモートストレージãŒæœ‰åŠ¹ãªå ´åˆã®ã¿æœ‰åŠ¹ã§ã™ã€‚サイズ制é™ã‚’設ã‘ãªã„å ´åˆã¯ 0 を設定ã—ã¾ã™ã€‚"
-
msgid "Only include features new to your current subscription tier."
msgstr "ç¾åœ¨ã®ã‚µãƒ–スクリプションレベルã«ã€æ–°æ©Ÿèƒ½ã®ã¿ã‚’å«ã‚ã¾ã™ã€‚"
@@ -32571,24 +32620,60 @@ msgstr "オプション"
msgid "Ordered list"
msgstr "é †åºä»˜ãリスト"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "組織"
-msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
msgstr ""
+msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgstr "グループã®èª­ã¿è¾¼ã¿ä¸­ã«ã€ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ページを更新ã—ã¦ã€ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。"
+
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr "プロジェクトã®èª­ã¿è¾¼ã¿ä¸­ã«ã€ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ページを更新ã—ã¦ã€ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。"
+msgid "Organization|Copy organization ID"
+msgstr "組織IDをコピー"
+
+msgid "Organization|Frequently visited groups"
+msgstr "よã訪れるグループ"
+
+msgid "Organization|Frequently visited projects"
+msgstr "よã訪れるプロジェクト"
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr "組織ID"
+
msgid "Organization|Organization navigation"
msgstr "組織ã®ãƒŠãƒ“ゲーション"
msgid "Organization|Organization overview"
msgstr "組織ã®æ¦‚è¦"
+msgid "Organization|Organizations"
+msgstr "組織"
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr "パブリック- 組織ã¯èªè¨¼ãªã—ã§ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚"
+
msgid "Organization|Search or filter list"
msgstr "リストを検索ã¾ãŸã¯ãƒ•ã‚£ãƒ«ã‚¿"
+msgid "Organization|View all"
+msgstr "ã™ã¹ã¦è¡¨ç¤º"
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr "孤立ã—ãŸãƒ¡ãƒ³ãƒãƒ¼"
@@ -33301,6 +33386,9 @@ msgstr "Pages"
msgid "Pages Domain"
msgstr "ページドメイン"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr "証明書キーãŒé•·ã™ãŽã¾ã™ã€‚(最大 %d ãƒã‚¤ãƒˆã¾ã§)"
+
msgid "Pagination|First"
msgstr "最åˆ"
@@ -33448,8 +33536,11 @@ msgstr "パス"
msgid "Path:"
msgstr "パス:"
-msgid "Paths to protect with rate limiting"
-msgstr "レート制é™ã«ã‚ˆã‚Šä¿è­·ã™ã‚‹ãƒ‘ス"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
+msgstr ""
msgid "Pause"
msgstr "åœæ­¢"
@@ -33725,7 +33816,7 @@ msgid "Pipeline subscriptions trigger a new pipeline on the default branch of th
msgstr "サブスクリプションã®å¯¾è±¡ãƒ—ロジェクトã§%{default_branch_docs}ã®æ–°ã—ã„ã‚¿ã‚°ã®ãƒ‘イプラインãŒæ­£å¸¸ã«å®Œäº†ã™ã‚‹ã¨ã€ãƒ‘イプラインã®ã‚µãƒ–スクリプションã«ã‚ˆã£ã¦ã€ã“ã®ãƒ—ロジェクト上ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆãƒ–ランãƒã§æ–°ã—ã„パイプラインãŒãƒˆãƒªã‚¬ãƒ¼ã•ã‚Œã¾ã™ã€‚"
msgid "Pipeline trigger tokens"
-msgstr ""
+msgstr "パイプライントリガートークン"
msgid "Pipeline triggers"
msgstr "パイプラインã®ãƒˆãƒªã‚¬ãƒ¼"
@@ -33895,9 +33986,6 @@ msgstr "カスタム (%{linkStart}詳ã—ãã¯ã“ã¡ã‚‰%{linkEnd}.)"
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr "スケジュールã—ãŸãƒ‘イプラインã¯ã€æ¯Žæ—¥ã¾ãŸã¯æ¯Žé€±ã¨ã„ã£ãŸå®šæœŸçš„ãªé–“éš”ã§è‡ªå‹•çš„ã«é–‹å§‹ã•ã‚Œã¾ã™ã€‚パイプラインã¯ä»¥ä¸‹ã®ã¨ãŠã‚Šã§ã™ã€‚"
-msgid "PipelineSchedules|Activated"
-msgstr "有効化"
-
msgid "PipelineSchedules|Active"
msgstr "有効"
@@ -33956,7 +34044,7 @@ msgid "PipelineSchedules|Next Run"
msgstr "次ã®å®Ÿè¡Œ"
msgid "PipelineSchedules|No pipeline schedules"
-msgstr ""
+msgstr "パイプラインã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ãŒã‚ã‚Šã¾ã›ã‚“"
msgid "PipelineSchedules|None"
msgstr "ãªã—"
@@ -34012,12 +34100,6 @@ msgstr "パイプラインスケジュールã®å®Ÿè¡Œä¸­ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr "パイプラインスケジュールã®æ‰€æœ‰æ¨©ã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-msgid "PipelineSchedules|Variables"
-msgstr "変数"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr "所有権をå–å¾—ã—ã¦ç·¨é›†"
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34468,6 +34550,9 @@ msgstr "パイプラインステータスをå–å¾—ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ト
msgid "Pipeline|Created"
msgstr "作æˆæ¸ˆã¿"
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr "パイプラインを作æˆã€‚"
@@ -34520,7 +34605,7 @@ msgid "Pipeline|Raw text search is not currently supported. Please use the avail
msgstr "rawテキスト検索ã¯ç¾åœ¨ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。利用å¯èƒ½ãªæ¤œç´¢ãƒˆãƒ¼ã‚¯ãƒ³ã‚’使用ã—ã¦ãã ã•ã„。"
msgid "Pipeline|Run again"
-msgstr ""
+msgstr "å†å®Ÿè¡Œ"
msgid "Pipeline|Run for branch name or tag"
msgstr "ブランãƒåã¾ãŸã¯ã‚¿ã‚°ã§å®Ÿè¡Œ"
@@ -34591,9 +34676,6 @@ msgstr "残りã®ã‚¸ãƒ§ãƒ–を表示ã™ã‚‹ã«ã¯ã€%{boldStart}ジョブ%{boldEnd
msgid "Pipeline|Trigger author"
msgstr "トリガー作æˆè€…"
-msgid "Pipeline|Triggerer"
-msgstr "トリガー"
-
msgid "Pipeline|Variables"
msgstr "変数"
@@ -34697,7 +34779,7 @@ msgid "Please check your email %{email} to confirm your account"
msgstr "メール (%{email}) を確èªã—ã¦ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’承èªã—ã¦ãã ã•ã„"
msgid "Please check your email (%{email}) to verify that you own this address and unlock the power of CI/CD. Didn't receive it? %{resend_link}. Wrong email address? %{update_link}."
-msgstr ""
+msgstr "メール(%{email})をãƒã‚§ãƒƒã‚¯ã—ã¦ã€ã“ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’所有ã—ã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã€CI/CDã®ãƒ­ãƒƒã‚¯ã‚’解除ã—ã¦ãã ã•ã„。電å­ãƒ¡ãƒ¼ãƒ«ã‚’å—ã‘å–ã£ã¦ã„ãªã„? %{resend_link} メールアドレスを間é•ã£ã¦ã„ã¾ã›ã‚“ã‹ï¼Ÿ %{update_link}"
msgid "Please click the link in the confirmation email before continuing. It was sent to %{html_tag_strong_start}%{email}%{html_tag_strong_end}."
msgstr "続行ã™ã‚‹å‰ã«ç¢ºèªãƒ¡ãƒ¼ãƒ«ã®ãƒªãƒ³ã‚¯ã‚’クリックã—ã¦ãã ã•ã„。ã“ã®ãƒªãƒ³ã‚¯ã¯%{html_tag_strong_start}%{email}%{html_tag_strong_end}ã«é€ä¿¡ã•ã‚Œã¾ã—ãŸã€‚"
@@ -35116,9 +35198,6 @@ msgstr "レイアウトã®å¹…"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "%{min} ã‹ã‚‰ %{max} ã¾ã§ã®æ•°å­—ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr "注: æ–°ã—ã„ナビゲーションãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã‚‹ãŸã‚ã€GitLabã®å¤–観ã¯å¤§å¹…ã«å¤‰ã‚ã‚‹ã®ã¯ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã®ãƒ†ãƒ¼ãƒžã‚’é©ç”¨ã—ãŸå ´åˆã®ã¿ã§ã™ã€‚"
-
msgid "Preferences|Preview"
msgstr "プレビュー"
@@ -35230,9 +35309,12 @@ msgstr "å‰ã®æœªè§£æ±ºã®ãƒ‡ã‚£ã‚¹ã‚«ãƒƒã‚·ãƒ§ãƒ³ã¸"
msgid "Primary Action"
msgstr "プライマリーアクション"
-msgid "Print as PDF"
+msgid "Primary navigation sidebar"
msgstr ""
+msgid "Print as PDF"
+msgstr "PDFã¨ã—ã¦å°åˆ·"
+
msgid "Print codes"
msgstr "コードをå°åˆ·"
@@ -35353,9 +35435,6 @@ msgstr "ダッシュボードã«æˆ»ã‚‹"
msgid "ProductAnalytics|Click Events"
msgstr "クリックイベント"
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr "ã™ã¹ã¦ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’互ã„ã«æ¯”較"
@@ -35371,9 +35450,6 @@ msgstr "ã™ã¹ã¦ã®æ©Ÿèƒ½ã®ä½¿ç”¨çŠ¶æ³ã‚’互ã„ã«æ¯”較"
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr "ã™ã¹ã¦ã®ãƒšãƒ¼ã‚¸ã®ãƒšãƒ¼ã‚¸ãƒ“ューを互ã„ã«æ¯”較"
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr "å¯è¦–化を作æˆ"
@@ -35381,7 +35457,7 @@ msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr "プロダクト分æžã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®ä½œæˆä¸­..."
msgid "ProductAnalytics|Cube API key"
-msgstr ""
+msgstr "Cube APIキー"
msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr "データをåŽé›†ã™ã‚‹ãŸã‚ã«è£½å“分æžã‚’構æˆã™ã‚‹æ–¹æ³•ã®è©³ç´°ã€‚"
@@ -35410,9 +35486,6 @@ msgstr "詳細ã«ã¤ã„ã¦ã¯ã€%{linkStart}文書%{linkEnd}ã‚’å‚ç…§ã—ã¦ãã
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr "製å“分æžãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ã§ãƒ‡ãƒ¼ã‚¿ã®è¡¨ç¤ºã‚’開始ã™ã‚‹ã«ã¯ã€åˆ†æžãƒˆãƒ©ãƒƒã‚­ãƒ³ã‚°ã‚³ãƒ¼ãƒ‰ã‚’プロジェクトã«è¿½åŠ ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
-msgid "ProductAnalytics|Go back"
-msgstr "戻る"
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr "ユーザーã®ã‚»ãƒƒã‚·ãƒ§ãƒ³æ•°"
@@ -35473,8 +35546,11 @@ msgstr "製å“分æžã®è¨­å®š"
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr "製å“ã®å‹•ä½œã‚’追跡ã—ã€è£½å“ã¨é–‹ç™ºãƒ—ロセスを最é©åŒ–ã™ã‚‹ãŸã‚ã«è¨­å®šã—ã¾ã™ã€‚"
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr "Snowplowコンフィギュレーター接続文字列"
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
-msgstr ""
+msgstr "Snowplow コンフィギュレーターインスタンスã®æŽ¥ç¶šæ–‡å­—列"
msgid "ProductAnalytics|The host to send all tracking events to"
msgstr "ã™ã¹ã¦ã®ãƒˆãƒ©ãƒƒã‚­ãƒ³ã‚°ã‚¤ãƒ™ãƒ³ãƒˆã‚’é€ä¿¡ã™ã‚‹ãƒ›ã‚¹ãƒˆ"
@@ -35497,11 +35573,8 @@ msgstr "特定ã®æ©Ÿèƒ½ã‚’追跡"
msgid "ProductAnalytics|Unique Users"
msgstr "ユニークユーザー"
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
-msgstr ""
+msgstr "Cubeインスタンスã‹ã‚‰ãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ãƒ‡ãƒ¼ã‚¿ã‚’å–å¾—ã™ã‚‹éš›ã«ä½¿ç”¨ã—ã¾ã™ã€‚"
msgid "ProductAnalytics|User Sessions"
msgstr "ユーザーセッション"
@@ -35639,7 +35712,7 @@ msgid "Profiles|Add new email"
msgstr "æ–°ã—ã„メールアドレスを追加"
msgid "Profiles|Add new mirror repository"
-msgstr ""
+msgstr "æ–°ã—ã„ミラーリãƒã‚¸ãƒˆãƒªã‚’追加"
msgid "Profiles|An error occurred while updating your username, please try again."
msgstr "ユーザーåã®æ›´æ–°ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -35731,8 +35804,8 @@ msgstr "プロフィールã«æ´»å‹•ã«é–¢ã™ã‚‹å€‹äººæƒ…報を表示ã—ãªã„ã§
msgid "Profiles|Edit Profile"
msgstr "プロフィールを編集"
-msgid "Profiles|Email"
-msgstr "メール"
+msgid "Profiles|Email address"
+msgstr "メールアドレス"
msgid "Profiles|Email addresses"
msgstr "メールアドレス"
@@ -36166,9 +36239,6 @@ msgstr "プロジェクトã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—"
msgid "Project order will not be saved as local storage is not available."
msgstr "ローカルストレージãŒåˆ©ç”¨ã§ããªã„ãŸã‚ã€ãƒ—ロジェクトã®é †åºã¯ä¿å­˜ã•ã‚Œã¾ã›ã‚“。"
-msgid "Project overview"
-msgstr "プロジェクトã®æ¦‚è¦"
-
msgid "Project path"
msgstr "プロジェクトパス"
@@ -36658,6 +36728,12 @@ msgstr "機能フラグ"
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "ã“ã®ãƒ—ロジェクトã§ã‚¢ã‚¤ãƒ‡ã‚¢ã‚’å…±åŒé–‹ç™ºã—ã€ä½œæ¥­ã‚’計画ã™ã‚‹æŸ”軟ãªãƒ„ール。"
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr "Gitaly ã§ã¯ã€ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ä¸Šã®ãƒ‡ãƒ¼ã‚¿ã®å ´æ‰€ã‚’指定ã—ã¾ã™ã€‚Gitaly Clusterã§ã¯ã€ä»®æƒ³ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ä¸Šã®ãƒ‡ãƒ¼ã‚¿ã‚’指定ã—ã¾ã™ã€‚"
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr "Gitaly ã®å ´åˆã€ãƒªãƒã‚¸ãƒˆãƒªã‚’æ ¼ç´ã™ã‚‹ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã®åå‰ã§ã™ã€‚Gitaly Clusterã®å ´åˆã€ãƒªãƒã‚¸ãƒˆãƒªã‚’æ ¼ç´ã™ã‚‹ä»®æƒ³ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã®åå‰ã§ã™ã€‚"
+
msgid "ProjectSettings|Forks"
msgstr "フォーク"
@@ -36793,6 +36869,9 @@ msgstr "公開"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr "プロジェクトã®ãƒ‘ッケージを公開ã€ä¿å­˜ã€ãŠã‚ˆã³è¡¨ç¤ºã—ã¾ã™ã€‚"
+msgid "ProjectSettings|Relative path:"
+msgstr "相対パス:"
+
msgid "ProjectSettings|Releases"
msgstr "リリース"
@@ -36865,6 +36944,9 @@ msgstr "スカッシングã¯å®Ÿè¡Œã•ã‚Œãšã€ãƒã‚§ãƒƒã‚¯ãƒœãƒƒã‚¯ã‚¹ã¯éžè¡¨
msgid "ProjectSettings|Status checks must succeed"
msgstr "ステータスãƒã‚§ãƒƒã‚¯ã¯æˆåŠŸã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+msgid "ProjectSettings|Storage name:"
+msgstr "ストレージå:"
+
msgid "ProjectSettings|Store custom configuration files."
msgstr "カスタム設定ファイルをä¿å­˜ã™ã‚‹ã€‚"
@@ -37684,6 +37766,12 @@ msgstr "コードオーナーã®æ‰¿èª"
msgid "ProtectedBranch|Create wildcard"
msgstr "ワイルドカードを作æˆ"
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr "ä¿è­·ãƒ–ランãƒã¸ã®ãƒžãƒ¼ã‚¸æ¨©é™ã‚’与ãˆã‚‹ã“ã¨ã«ã‚ˆã‚Šã€ç‰¹å®šã®CI/CD機能ã«å¯¾ã™ã‚‹æ¨©é™ã‚‚高ããªã‚Šã¾ã™ã€‚"
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr "継承ã•ã‚ŒãŸ - ã“ã®è¨­å®šã¯ã‚°ãƒ«ãƒ¼ãƒ—レベルã§å¤‰æ›´ã§ãã¾ã™"
@@ -37733,7 +37821,7 @@ msgid "ProtectedBranch|Tag"
msgstr "ã‚¿ã‚°"
msgid "ProtectedBranch|There are currently no protected branches, to protect a branch start by creating a new one above."
-msgstr ""
+msgstr "ç¾åœ¨ã€ä¿è­·ãƒ–ランãƒãŒã‚ã‚Šã¾ã›ã‚“。ブランãƒã®ä¿è­·ã‚’開始ã™ã‚‹ã«ã¯ã€ä¸Šã®ãƒ•ã‚©ãƒ¼ãƒ ã§ãƒ–ランãƒã‚’ä¿è­·ã—ã¦ãã ã•ã„。"
msgid "ProtectedBranch|Toggle allowed to force push"
msgstr "強制プッシュ許å¯ã®åˆ‡ã‚Šæ›¿ãˆ"
@@ -37756,8 +37844,8 @@ msgstr "ブランãƒãƒ«ãƒ¼ãƒ«ã¨ã—ã¦ä¿è­·ã•ã‚ŒãŸãƒ–ランãƒã‚’表示"
msgid "ProtectedBranch|What are protected branches?"
msgstr "ä¿è­·ãƒ–ランãƒã¨ã¯"
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
-msgstr "ブランãƒã«ç›´æŽ¥ãƒ—ッシュã™ã‚‹å ´åˆã€‚ユーザーã«ã¯ã€**プッシュ許å¯** ã¯é©ç”¨ã•ã‚Œã¾ã›ã‚“。 オプションã®ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã¯å®Ÿæ–½ã•ã‚Œã¾ã›ã‚“。"
+msgid "ProtectedBranch|What are the security implications?"
+msgstr "セキュリティã¸ã®å½±éŸ¿ã¯ä½•ã§ã™ã‹?"
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
msgstr "ã“ã®ãƒ—ロジェクトを共有ã—ã¦ã„るグループã®ã¿ã‚’追加ã§ãã¾ã™ã€‚%{learn_more_link}"
@@ -37809,12 +37897,15 @@ msgstr "デプロイヤールールを削除"
msgid "ProtectedEnvironments|Edit"
msgstr "編集"
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
-msgstr "ä¿è­·ç’°å¢ƒã®ãƒªã‚¹ãƒˆ(%{protectedEnvironmentsCount})"
-
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr "承èªæ•°ã¯1ã‹ã‚‰5ã®é–“ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr "環境をä¿è­·"
+
+msgid "ProtectedEnvironments|Protected environments"
+msgstr "ä¿è­·ç’°å¢ƒ"
+
msgid "ProtectedEnvironments|Remove approval rule"
msgstr "承èªãƒ«ãƒ¼ãƒ«ã‚’削除"
@@ -37824,6 +37915,9 @@ msgstr "å¿…è¦ãªæ‰¿èªã®æ•°"
msgid "ProtectedEnvironments|Save"
msgstr "ä¿å­˜"
+msgid "ProtectedEnvironments|Select users"
+msgstr "ユーザーをé¸æŠž"
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr "ã©ã®ã‚°ãƒ«ãƒ¼ãƒ—ã€ã‚¢ã‚¯ã‚»ã‚¹ãƒ¬ãƒ™ãƒ«ã€ã¾ãŸã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’承èªã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã‚’設定ã—ã¾ã™ã€‚"
@@ -37842,6 +37936,9 @@ msgstr "ユーザー"
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name}ã¯ãƒ‡ãƒ™ãƒ­ãƒƒãƒ‘ー権é™ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒæ›¸ãè¾¼ã¿å¯èƒ½ã«ãªã‚Šã¾ã™ã€‚本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ ?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr "æ–°ã—ã„ä¿è­·ç’°å¢ƒã‚’追加"
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr "以下ã®ãƒ‡ãƒ—ロイ階層ã§ç‰¹å®šã•ã‚Œã‚‹ã™ã¹ã¦ã®ç’°å¢ƒã¯ã€è¦ªã‚°ãƒ«ãƒ¼ãƒ—ã«ã‚ˆã£ã¦ä¿è­·ã•ã‚Œã¦ã„ã¾ã™ã€‚%{link_start}詳ã—ãã¯ã“ã¡ã‚‰%{link_end}。"
@@ -37899,9 +37996,6 @@ msgstr "環境をé¸æŠž"
msgid "ProtectedEnvironment|Select groups"
msgstr "グループã®é¸æŠž"
-msgid "ProtectedEnvironment|Select users"
-msgstr "ユーザーをé¸æŠž"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr "ä¿è­·ã•ã‚ŒãŸç’°å¢ƒã¯ç¾åœ¨ã‚ã‚Šã¾ã›ã‚“。"
@@ -37968,9 +38062,6 @@ msgstr "プロビジョニングã®æ‰‹é †"
msgid "Provisioned by:"
msgstr "プロビジョニング担当者:"
-msgid "Proxy support for this API is not available currently"
-msgstr "ã“ã®APIã®ãƒ—ロキシサãƒãƒ¼ãƒˆã¯ç¾åœ¨åˆ©ç”¨ã§ãã¾ã›ã‚“"
-
msgid "Public"
msgstr "公開"
@@ -38331,9 +38422,6 @@ msgstr "迷惑メール通知をメールã§å—ä¿¡ã—ã¾ã™ã€‚"
msgid "Receive notifications about your own activity"
msgstr "自身ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティã«é–¢ã™ã‚‹é€šçŸ¥ã‚’å—ä¿¡ã™ã‚‹"
-msgid "Receive product marketing emails"
-msgstr "製å“マーケティングメールをå—ä¿¡ã™ã‚‹"
-
msgid "Recent"
msgstr "最近"
@@ -38473,35 +38561,11 @@ msgstr "ユーザーã«ãƒ¡ãƒ¼ãƒ«ã‚’é€ä¿¡"
msgid "RegistrationFeatures|use this feature"
msgstr "ã“ã®æ©Ÿèƒ½ã‚’使用ã™ã‚‹"
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr "ã“ã®æ‰‹é †ã‚’スキップã—ã¦ã‚‚本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹?"
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr "ç„¡æ–™ã®ã‚³ãƒ³ãƒ”ューティング時間を有効ã«ã™ã‚‹"
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr "GitLab ã¯ã‚«ãƒ¼ãƒ‰ã«è«‹æ±‚ã›ãšã€æ¤œè¨¼ã«ã®ã¿ä½¿ç”¨ã—ã¾ã™ã€‚"
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr "共有 GitLab Runner を使用ã—ãŸãƒ‘イプラインã¯ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’検証ã™ã‚‹ã¾ã§å¤±æ•—ã—ã¾ã™ã€‚"
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr "今ã®ã¨ã“ã‚スキップã™ã‚‹"
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr "GitLabをスパムやä¸æ­£åˆ©ç”¨ã‹ã‚‰å®ˆã‚‹ãŸã‚ã€ãƒ‡ãƒ“ットカードやクレジットカードãªã©ã®æœ‰åŠ¹ãªæ”¯æ‰•ã„方法ã§æœ¬äººç¢ºèªã‚’ãŠé¡˜ã„ã—ã¦ã„ã¾ã™ã€‚本人確èªãŒã§ãã‚‹ã¾ã§ã¯ã€ç„¡æ–™ã®ã‚³ãƒ³ãƒ”ューティング時間を使用ã—ã¦ã‚¢ãƒ—リケーションをビルドã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
-
-msgid "RegistrationVerification|Validate account"
-msgstr "アカウントã®æ¤œè¨¼"
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr "本人確èªã‚’è¡Œã†"
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr "ã¯ã„ã€ã‚¹ã‚­ãƒƒãƒ—ã—ã¾ã™"
+msgid "Registries enqueued to be resynced"
+msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
-msgstr "アカウントã®ç¢ºèªã¯å¾Œã»ã©è¡Œã†ã“ã¨ãŒã§ãã¾ã™ã€‚"
+msgid "Registries enqueued to be reverified"
+msgstr ""
msgid "Registry entry enqueued to be resynced"
msgstr "レジストリエントリã¯å†åŒæœŸã™ã‚‹ãŸã‚ã«ã‚­ãƒ¥ãƒ¼ã«å…¥ã£ã¦ã„ã¾ã™"
@@ -38834,9 +38898,6 @@ msgstr "電話ã«ã‚ˆã‚‹èªè¨¼ã®å…除をãªãã™"
msgid "Remove priority"
msgstr "優先度を消去"
-msgid "Remove report"
-msgstr "レãƒãƒ¼ãƒˆã‚’削除"
-
msgid "Remove reviewer"
msgstr "レビュアーを削除"
@@ -38849,6 +38910,9 @@ msgstr "セカンダリメールを削除"
msgid "Remove spent time"
msgstr "作業時間ã®å‰Šé™¤"
+msgid "Remove summary"
+msgstr "概è¦ã‚’削除"
+
msgid "Remove time estimate"
msgstr "見ç©æ™‚間を削除"
@@ -38858,9 +38922,6 @@ msgstr "トピックアãƒã‚¿ãƒ¼ã‚’削除"
msgid "Remove user"
msgstr "ユーザーを削除"
-msgid "Remove user & report"
-msgstr "ユーザーã¨ãƒ¬ãƒãƒ¼ãƒˆã‚’削除"
-
msgid "Remove user from group"
msgstr "ユーザーをグループã‹ã‚‰å‰Šé™¤"
@@ -39140,12 +39201,6 @@ msgstr "ãªãœã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’報告ã™ã‚‹ã®ã§ã™ã‹ï¼Ÿ"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "%{timeAgo} ã« %{reportedBy} ã«ã‚ˆã‚Šå ±å‘Š"
-msgid "Reported by"
-msgstr "報告者"
-
-msgid "Reported by %{reporter}"
-msgstr "%{reporter}ã«ã‚ˆã‚Šå ±å‘Šã•ã‚Œã¾ã—ãŸ"
-
msgid "Reporter"
msgstr "レãƒãƒ¼ã‚¿ãƒ¼"
@@ -39446,9 +39501,6 @@ msgstr "リãƒã‚¸ãƒˆãƒªã®ä½¿ç”¨é‡ã®å†è¨ˆç®—ãŒé–‹å§‹ã•ã‚Œã¾ã—ãŸ"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr "リãƒã‚¸ãƒˆãƒª: %{counter_repositories}/ Wiki: %{counter_wikis}/ ビルドアーティファクト: %{counter_build_artifacts}/ パイプラインアーティファクト: %{counter_pipeline_artifacts}/ LFS: %{counter_lfs_objects}/ スニペット: %{counter_snippets}/ パッケージ: %{counter_packages}/ æ›´æ–°: %{counter_uploads}"
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "é¸æŠž"
-
msgid "Request"
msgstr "リクエスト"
@@ -39858,6 +39910,9 @@ msgstr "根本原因ã®åˆ†æžã¯ã€ãƒ­ã‚°ã‚’分æžã—ã¦ã€ã‚¸ãƒ§ãƒ–ãŒå¤±æ•—ã—
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr "ãã®ãƒ«ãƒ¼ãƒ«åã¯æ—¢ã«ä½¿ã‚ã‚Œã¦ã„ã¾ã™ã€‚"
@@ -40203,7 +40258,7 @@ msgid "Runners|GitLab Runner must be installed before you can register a runner.
msgstr "GitLab Runnerを登録ã™ã‚‹ã«ã¯ã€GitLab Runnerをインストールã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚%{linkStart}GitLab Runnerをインストールã™ã‚‹ã«ã¯ã©ã†ã™ã‚Œã°ã„ã„ã§ã™ã‹? %{linkEnd}"
msgid "Runners|Go to %{groupLink} to enable them."
-msgstr ""
+msgstr "%{groupLink} ã«ç§»å‹•ã—ã¦æœ‰åŠ¹ã«ã™ã‚‹ã€‚"
msgid "Runners|Go to runners page"
msgstr "Runnerページã¸"
@@ -40283,6 +40338,9 @@ msgstr "%{type}ã®ãƒ¡ãƒ³ãƒãƒ¼ã¯ Runner を登録ã§ãã¾ã™"
msgid "Runners|Minor version upgrades are available."
msgstr "マイナーãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ã‚¢ãƒƒãƒ—グレードã¯å¯èƒ½ã§ã™ã€‚"
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr "複数ã®ã‚¿ã‚°ã¯ã‚«ãƒ³ãƒžã§åŒºåˆ‡ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚例ãˆã°ã€%{example}。"
@@ -40567,11 +40625,11 @@ msgstr "ã“ã®Runnerã«å‰²ã‚Šå½“ã¦ã‚‹ãƒ—ロジェクトをé¸æŠž"
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr "ã“ã“ã§ãŠå¥½ã¿ã®Runnerã‚’é¸æŠžã—ã¾ã™ã€‚次ã®ã‚¹ãƒ†ãƒƒãƒ—ã§ã¯ã€AWS CloudFormationコンソールã§ãã®Runnerã®å®¹é‡ã‚’é¸æŠžã§ãã¾ã™ã€‚"
-msgid "Runners|Shared runners are disabled in the group settings"
-msgstr "共有Runnerã¯ã‚°ãƒ«ãƒ¼ãƒ—設定ã§ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™"
+msgid "Runners|Shared runners are disabled in the group settings."
+msgstr "共有Runnerã¯ã‚°ãƒ«ãƒ¼ãƒ—設定ã§ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™."
msgid "Runners|Shared runners are disabled."
-msgstr ""
+msgstr "共有 Runner ã¯ç„¡åŠ¹ã§ã™ã€‚"
msgid "Runners|Shared runners will be disabled for all projects and subgroups in this group. If you proceed, you must manually re-enable shared runners in the settings of each project and subgroup."
msgstr "共有Runnerã¯ã€ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—内ã®ã™ã¹ã¦ã®ãƒ—ロジェクトã¨ã‚µãƒ–グループã§ç„¡åŠ¹ã«ãªã‚Šã¾ã™ã€‚続行ã™ã‚‹å ´åˆã€å„プロジェクトãŠã‚ˆã³ã‚µãƒ–グループã®è¨­å®šã§å…±æœ‰Runnerを手動ã§æœ‰åŠ¹åŒ–ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -40649,6 +40707,9 @@ msgstr "インスタンスランナーãŒã‚¸ãƒ§ãƒ–を拾ã†ã®ã«ã‹ã‹ã‚‹æ™‚é–“
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr "ã“ã®è¨­å®šã‚’使用ã™ã‚‹ãƒ©ãƒ³ãƒŠãƒ¼ã”ã¨ã®ä¸€æ„ã®ID。"
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr "ç¾åœ¨ã‚¸ãƒ§ãƒ–を実行ã—ã¦ã„ã‚‹ Runner ã¯ã‚ã‚Šã¾ã›ã‚“。有効㪠Runner ãŒã‚¸ãƒ§ãƒ–を開始ã™ã‚‹ã¨ã€ã“ã“ã«è¿½åŠ ã•ã‚Œã¾ã™ã€‚"
@@ -40857,6 +40918,9 @@ msgstr "シングルサインオンを使用ã—ã¦æ­£å¸¸ã«ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã—ãŸ
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "ã‚ãªãŸã®çµ„ç¹”ã®SSOã¯GitLabアカウントã«æŽ¥ç¶šã•ã‚Œã¾ã—ãŸ"
+msgid "SBOMs last updated"
+msgstr "SBOMã®æœ€çµ‚æ›´æ–°æ—¥"
+
msgid "SCIM|SCIM Token"
msgstr "SCIMトークン"
@@ -40965,9 +41029,6 @@ msgstr "内部ノートをä¿å­˜"
msgid "Save password"
msgstr "パスワードをä¿å­˜"
-msgid "Save pipeline schedule"
-msgstr "パイプラインスケジュールをä¿å­˜"
-
msgid "Saving"
msgstr "ä¿å­˜ä¸­"
@@ -40980,11 +41041,11 @@ msgstr "%{hostname}ã®ã‚¿ã‚¤ãƒ ã‚¾ãƒ¼ãƒ³"
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr "%{time}%{timezoneLabel}%{timezone}ã«ãŠã‘ã‚‹%{period}%{days}"
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
-msgstr ""
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
+msgstr "%{scopes}%{branches}%{agents}%{branchExceptions}%{namespaces}%{period}ã«å¯¾ã™ã‚‹%{rules}アクション"
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
-msgstr ""
+msgstr "%{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}ã«å¯¾ã—ã¦ãƒ‘イプランを実行ã™ã‚‹ãŸã³ã«%{rules}"
msgid "ScanExecutionPolicy|A runner will be selected automatically from those available."
msgstr "Runner ã¯ã€åˆ©ç”¨å¯èƒ½ãª Runner ã‹ã‚‰è‡ªå‹•çš„ã«é¸æŠžã•ã‚Œã¾ã™ã€‚"
@@ -41106,11 +41167,14 @@ msgstr "経éŽæœŸé–“ã®æ¡ä»¶ã¯ã€æ—¢å­˜ã®è„†å¼±æ€§ã«å¯¾ã—ã¦ã®ã¿è¿½åŠ ã§
msgid "ScanResultPolicy|Age is:"
msgstr "経éŽæœŸé–“:"
-msgid "ScanResultPolicy|Block users from unprotecting branches"
-msgstr ""
+msgid "ScanResultPolicy|Attribute is:"
+msgstr "属性:"
-msgid "ScanResultPolicy|Choose an option"
-msgstr "オプションをé¸æŠž"
+msgid "ScanResultPolicy|Attribute:"
+msgstr "属性:"
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
+msgstr "属性ã¯ã‚¹ã‚­ãƒ£ãƒŠãƒ¼ã«ã‚ˆã£ã¦è‡ªå‹•çš„ã«é©ç”¨ã•ã‚Œã¾ã™"
msgid "ScanResultPolicy|Choose criteria type"
msgstr "基準ã®ç¨®é¡žã‚’é¸æŠž"
@@ -41124,6 +41188,24 @@ msgstr "カスタマイズã—ãŸCI変数"
msgid "ScanResultPolicy|Except"
msgstr "次を除ã"
+msgid "ScanResultPolicy|False positive"
+msgstr "誤検知"
+
+msgid "ScanResultPolicy|Fix available"
+msgstr "修正ãŒåˆ©ç”¨å¯èƒ½"
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr "利用å¯èƒ½ãªä¿®æ­£ã¯ã‚³ãƒ³ãƒ†ãƒŠã¨ä¾å­˜é–¢ä¿‚ã®ã‚¹ã‚­ãƒ£ãƒ³ã«ã®ã¿é©ç”¨ã§ãã¾ã™"
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr "次ã®ã¨ãŠã‚Šã§ã™"
+
+msgid "ScanResultPolicy|Is not"
+msgstr "次ã®ã¨ãŠã‚Šã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
msgid "ScanResultPolicy|License is:"
msgstr "ライセンス:"
@@ -41136,8 +41218,8 @@ msgstr "一致"
msgid "ScanResultPolicy|New age"
msgstr "æ–°è¦ã®çµŒéŽæœŸé–“"
-msgid "ScanResultPolicy|New severity"
-msgstr "æ–°ãŸãªé‡è¦åº¦"
+msgid "ScanResultPolicy|New attribute"
+msgstr "æ–°è¦ã®å±žæ€§"
msgid "ScanResultPolicy|New status"
msgstr "æ–°ãŸãªçŠ¶æ…‹"
@@ -41148,18 +41230,24 @@ msgstr "æ–°ãŸã«æ¤œå‡º"
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr "経éŽæœŸé–“ã®æ¡ä»¶ã¯ 1 ã¤ã®ã¿æŒ‡å®šã§ãã¾ã™"
-msgid "ScanResultPolicy|Only 1 severity is allowed"
-msgstr "é‡è¦åº¦ã¯ 1 ã¤ã®ã¿æŒ‡å®šã§ãã¾ã™"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
+msgstr "属性æ¡ä»¶ã¯2ã¤ã®ã¿æŒ‡å®šã§ãã¾ã™"
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
msgstr "状態ã®æ¡ä»¶ã¯ 2 ã¤ã®ã¿æŒ‡å®šã§ãã¾ã™"
msgid "ScanResultPolicy|Override project approval settings"
-msgstr ""
+msgstr "プロジェクト承èªè¨­å®šã‚’上書ã"
msgid "ScanResultPolicy|Pre-existing"
msgstr "既存"
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr "基準を追加ã™ã‚‹å‰ã«ã‚¹ã‚­ãƒ£ãƒ³ã‚¿ã‚¤ãƒ—ã‚’é¸æŠžã—ã¦ãã ã•ã„"
@@ -41187,9 +41275,18 @@ msgstr " %{scanType} %{scanners} ã‚’ %{branches} %{branchExceptions} ã«å¯¾ã—ã
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr " %{branches} %{branchExceptions} を対象ã¨ã™ã‚‹ã‚ªãƒ¼ãƒ—ンマージリクエスト内㮠%{scanType} ã¨ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ãŒã€æ¬¡ã®åŸºæº–ã‚’ã™ã¹ã¦æº€ãŸã—ã¦ã„ã‚‹å ´åˆ:"
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr " %{scanners} ㌠%{branches} %{branchExceptions} を対象ã¨ã—ãŸã‚ªãƒ¼ãƒ—ンマージリクエスト内ã§æŒ‡å®šã•ã‚ŒãŸæ¡ä»¶ã«åˆã£ãŸã‚¹ã‚­ãƒ£ãƒŠãƒ¼ã‚’見ã¤ã‘ã€ãã‚ŒãŒæ¬¡ã®åŸºæº–ã® %{boldDescription} ã«ä¸€è‡´ã™ã‚‹å ´åˆ"
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr "ライセンスã®çŠ¶æ…‹"
@@ -41301,6 +41398,9 @@ msgstr "グループã®æ¤œç´¢"
msgid "Search an environment spec"
msgstr "環境スペックを検索"
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "担当者を検索"
@@ -41370,15 +41470,12 @@ msgstr "マイルストーンを検索"
msgid "Search or filter commits"
msgstr "コミットを検索ã¾ãŸã¯ãƒ•ã‚£ãƒ«ã‚¿ã™ã‚‹"
-msgid "Search or filter results"
-msgstr "çµæžœã‚’検索ã¾ãŸã¯ãƒ•ã‚£ãƒ«ã‚¿ã™ã‚‹"
-
-msgid "Search or filter results..."
-msgstr "çµæžœã‚’検索ã¾ãŸã¯ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚’ã‹ã‘ã‚‹..."
-
msgid "Search or filter results…"
msgstr "çµæžœã‚’検索ã¾ãŸã¯ãƒ•ã‚£ãƒ«ã‚¿ãƒªãƒ³ã‚°ã™ã‚‹..."
+msgid "Search or go to…"
+msgstr "検索ã¾ãŸã¯ç§»å‹•å…ˆ..."
+
msgid "Search page"
msgstr "ページ検索"
@@ -41594,6 +41691,9 @@ msgstr "セキュリティ設定"
msgid "Security dashboard"
msgstr "セキュリティダッシュボード"
+msgid "Security reports last updated"
+msgstr "セキュリティレãƒãƒ¼ãƒˆã®æœ€çµ‚æ›´æ–°æ—¥"
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr "テストカãƒãƒ¬ãƒƒã‚¸ãŒä½Žä¸‹ã™ã‚‹å ´åˆã«ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®æ‰¿èªãŒå¿…è¦ã§ã™ã€‚"
@@ -41750,6 +41850,12 @@ msgstr "ãŠã‚ˆã³"
msgid "SecurityOrchestration| and all the following apply:"
msgstr "ãŠã‚ˆã³æ¬¡ã®ã™ã¹ã¦ã‚’満ãŸã™å ´åˆ:"
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr "ã¾ãŸã¯"
@@ -41759,8 +41865,14 @@ msgstr "%{licenseState}ã§ã€"
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr "%{namespaces}ã®%{agent}"
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
-msgstr "%{branches}ブランãƒã®%{cadence}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr "%{branchName}"
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr "%{branchName} (%{codeStart}%{fullPath}%{codeEnd}内)"
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
+msgstr "%{branches}%{branchExceptionsString}上ã®%{cadence}"
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
msgstr "%{licenses}ã¨%{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr "スキャンçµæžœãƒãƒªã‚·ãƒ¼ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—
msgid "SecurityOrchestration|And scans to be performed:"
msgstr "ã¾ãŸã€æ¬¡ã®ã‚¹ã‚­ãƒ£ãƒ³ãŒå®Ÿè¡Œã•ã‚Œã¾ã™:"
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr "本当ã«ã“ã®ãƒãƒªã‚·ãƒ¼ã‚’削除ã—ã¾ã™ã‹ ?ã“ã®æ“作ã¯å…ƒã«æˆ»ã›ã¾ã›ã‚“。"
@@ -41888,8 +42003,8 @@ msgstr "有効"
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr "ã“ã®ãƒ—ロジェクトã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚’強化ã—ã¾ã™ã€‚%{linkStart}詳細情報。%{linkEnd}"
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
-msgstr "%{branches}ã§ãƒ‘イプラインを実行ã™ã‚‹ãŸã³"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
+msgstr "%{branches}%{branchExceptionsString}ã§ãƒ‘イプラインを実行ã™ã‚‹ãŸã³"
msgid "SecurityOrchestration|Exceptions"
msgstr "例外"
@@ -41900,12 +42015,18 @@ msgstr "クラスタエージェントã®èª­ã¿è¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
msgid "SecurityOrchestration|Failed to load images."
msgstr "イメージã®èª­ã¿è¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr "大è¦æ¨¡ãªã‚°ãƒ«ãƒ¼ãƒ—ã®å ´åˆã€æ—¢å­˜ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ãƒãƒªã‚·ãƒ¼ã®å¤‰æ›´ã‚’é©ç”¨ã™ã‚‹éš›ã«å¤§å¹…ãªé…延ãŒç”Ÿã˜ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚ãƒãƒªã‚·ãƒ¼ã®å¤‰æ›´ã¯é€šå¸¸ã€æ–°ã—ã作æˆã•ã‚ŒãŸãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã™ãã«é©ç”¨ã•ã‚Œã¾ã™ã€‚"
msgid "SecurityOrchestration|Groups"
msgstr "グループ"
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr "余計ãªãƒ–ランãƒã‚’éžè¡¨ç¤ºã«ã™ã‚‹"
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr "ã„ãšã‚Œã‹ã®ã‚¹ã‚­ãƒ£ãƒŠãƒ¼ãŒã€masterブランãƒã‚’対象ã¨ã—ãŸã‚ªãƒ¼ãƒ—ンマージリクエストã§æ–°ãŸã«æ¤œå‡ºã•ã‚ŒãŸé‡å¤§ãªè„†å¼±æ€§ã‚’発見ã—ãŸå ´åˆã€ã‚¢ãƒ—リセキュリティã®ã„ãšã‚Œã‹ã®ãƒ¡ãƒ³ãƒãƒ¼ã‹ã‚‰2件ã®æ‰¿èªã‚’å¾—ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -42171,6 +42292,9 @@ msgstr "マージリクエストをマージã™ã‚‹å‰ã«ã€ã‚¹ã‚­ãƒ£ãƒ³çµæžœãƒ
msgid "SecurityOrchestration|View policy project"
msgstr "ãƒãƒªã‚·ãƒ¼ãƒ—ロジェクトを表示"
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr "脆弱性%{vulnerabilityStates}"
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr "%{vulnerabilityStates}ã®è„†å¼±æ€§ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -42183,14 +42307,14 @@ msgstr "脆弱性ã®æœŸé–“㯠%{vulnerabilityAge} 未満ã§ã™ã€‚"
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr "脆弱性ã®çµŒéŽæœŸé–“ã«ã¯ã€æ—¢å­˜ã®è„†å¼±æ€§ã®çŠ¶æ…‹ (検出ã€ç¢ºèªã€è§£æ±ºã€å‰Šé™¤) ãŒå¿…è¦ã§ã™"
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
-msgstr "%{scanners}ãŒ%{targeting}%{branches}%{criteriaApply}を対象ã¨ã™ã‚‹ã‚ªãƒ¼ãƒ—ンマージリクエスト内ã§%{vulnerability}ã‚’%{vulnerabilitiesAllowed}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
+msgstr "%{scanners}ãŒ%{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}を対象ã¨ã™ã‚‹ã‚ªãƒ¼ãƒ—ンマージリクエスト内ã§%{vulnerability}ã‚’%{vulnerabilitiesAllowed}"
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr "ライセンススキャナーãŒ%{targeting}%{branches}を対象ã¨ã™ã‚‹ã‚ªãƒ¼ãƒ—ンマージリクエスト内ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹%{licenses}%{detection}を見ã¤ã‘ãŸå ´åˆã€‚"
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "ライセンススキャナーãŒã‚ªãƒ¼ãƒ—ンマージリクエスト内ã®%{licenses}%{detection}以外ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã‚’見ã¤ã‘ãŸå ´åˆ%{targeting}%{branches}%{branchExceptionsString}"
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr "ライセンススキャナーãŒ%{targeting}%{branches}を対象ã¨ã™ã‚‹ã‚ªãƒ¼ãƒ—ンマージリクエスト内ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹%{licenses}%{detection}を見ã¤ã‘ãŸå ´åˆã€‚"
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "ライセンススキャナーãŒã‚ªãƒ¼ãƒ—ンマージリクエスト内ã®ä¸€è‡´ã™ã‚‹%{licenses}%{detection}内ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã‚’見ã¤ã‘ãŸå ´åˆ%{targeting}%{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|With the following customized CI variables:"
msgstr "以下ã®ã€ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚ºã•ã‚ŒãŸ CI 変数ã§:"
@@ -42219,14 +42343,20 @@ msgstr "ä»»æ„ã®ä¿è­·ã•ã‚ŒãŸãƒ–ランãƒ"
msgid "SecurityOrchestration|any security scanner finds"
msgstr "ä»»æ„ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚¹ã‚­ãƒ£ãƒŠãƒ¼ãŒæ¬¡ã‚’見ã¤ã‘ãŸå ´åˆ:"
+msgid "SecurityOrchestration|are false positives"
+msgstr "誤検出ã§ã™"
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr "誤検出ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
+
msgid "SecurityOrchestration|branch"
msgstr "ブランãƒ"
msgid "SecurityOrchestration|branches"
msgstr "ブランãƒ"
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
-msgstr "%{agents}ã¨ã„ã†åå‰ã®ã‚¨ãƒ¼ã‚¸ã‚§ãƒ³ãƒˆã«ã‚ˆã£ã¦%{cadence}ã§"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
+msgstr "%{agents}%{cadence}%{branchExceptionsString}ã¨ã„ã†åå‰ã®ã‚¨ãƒ¼ã‚¸ã‚§ãƒ³ãƒˆã«ã‚ˆã£ã¦"
msgid "SecurityOrchestration|group level branch input"
msgstr "グループレベルã®ãƒ–ランãƒå…¥åŠ›"
@@ -42234,6 +42364,12 @@ msgstr "グループレベルã®ãƒ–ランãƒå…¥åŠ›"
msgid "SecurityOrchestration|group level branch selector"
msgstr "グループレベルã®ãƒ–ランãƒã‚»ãƒ¬ã‚¯ã‚¿ãƒ¼"
+msgid "SecurityOrchestration|have a fix available"
+msgstr "利用å¯èƒ½ãªä¿®æ­£ãŒã‚ã‚Šã¾ã™"
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr "利用å¯èƒ½ãªä¿®æ­£ãŒã‚ã‚Šã¾ã›ã‚“"
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr "%{allowed}より多ã„"
@@ -42303,9 +42439,6 @@ msgstr "コメントを追加 (必須)"
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr "コメントã¾ãŸã¯å´ä¸‹ç†ç”±ã‚’追加"
-msgid "SecurityReports|Add comment & dismiss"
-msgstr "コメントを追加ã—ã¦é–‰ã˜ã‚‹"
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "セキュリティエリアã§ç›£è¦–ã™ã‚‹ãƒ—ロジェクトを追加ã¾ãŸã¯å‰Šé™¤ã—ã¾ã™ã€‚ã“ã®ä¸€è¦§ã«å«ã¾ã‚Œã‚‹ãƒ—ロジェクトã§ã¯ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ã¨è„†å¼±æ€§ãƒ¬ãƒãƒ¼ãƒˆã«çµæžœãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
@@ -42319,7 +42452,7 @@ msgid "SecurityReports|All clusters"
msgstr "ã™ã¹ã¦ã®ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼"
msgid "SecurityReports|All dismissal reasons"
-msgstr ""
+msgstr "ã™ã¹ã¦ã®å´ä¸‹ç†ç”±"
msgid "SecurityReports|All images"
msgstr "ã™ã¹ã¦ã®ã‚¤ãƒ¡ãƒ¼ã‚¸"
@@ -42360,6 +42493,9 @@ msgstr "「%{vulnerabilityName}〠ã®ç·¨é›†ã•ã‚ŒãŸã‚³ãƒ¡ãƒ³ãƒˆ"
msgid "SecurityReports|Configure security testing"
msgstr "セキュリティテストを設定"
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr "イシューを作æˆã™ã‚‹"
@@ -42375,9 +42511,15 @@ msgstr "検出"
msgid "SecurityReports|Development vulnerabilities"
msgstr "開発ã®è„†å¼±æ€§"
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "脆弱性をéžè¡¨ç¤ºã«ã™ã‚‹"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "éžè¡¨ç¤ºã«ã•ã‚ŒãŸ 「%{vulnerabilityName}ã€"
@@ -42385,10 +42527,10 @@ msgid "SecurityReports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismi
msgstr "「%{vulnerabilityName}ã€ã‚’éžè¡¨ç¤ºã«ã—ã¾ã—ãŸã€‚表示ã™ã‚‹ã«ã¯ã€éžè¡¨ç¤ºã‚’ã‚„ã‚るをオフã«åˆ‡ã‚Šæ›¿ãˆã¾ã™ã€‚"
msgid "SecurityReports|Dismissed (all reasons)"
-msgstr ""
+msgstr "å´ä¸‹ï¼ˆã™ã¹ã¦ã®ç†ç”±ï¼‰"
msgid "SecurityReports|Dismissed as..."
-msgstr ""
+msgstr "å´ä¸‹ã•ã‚ŒãŸç†ç”±..."
msgid "SecurityReports|Does not have issue"
msgstr "イシューã¯ã‚ã‚Šã¾ã›ã‚“"
@@ -42408,6 +42550,9 @@ msgstr "スキャンã—㟠URL をダウンロード"
msgid "SecurityReports|Download the patch to apply it manually"
msgstr "パッãƒã‚’ダウンロードã—ã¦æ‰‹å‹•ã§é©ç”¨ã™ã‚‹"
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr "ã“ã®ãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ã‚’表示ã™ã‚‹æ¨©é™ãŒãªã„ã‹ã€ãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ãŒã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—ã§ãã¦ã„ãªã„ã‹ã®ã©ã¡ã‚‰ã‹ã§ã™ã€‚続行ã™ã‚‹ã«ã¯ã€ç®¡ç†è€…ã«è¨±å¯è¨­å®šã‚’確èªã—ã¦ãã ã•ã„。ã¾ãŸã¯ã€ãƒ€ãƒƒã‚·ãƒ¥ãƒœãƒ¼ãƒ‰ã®è¨­å®šã‚’確èªã—ã¦ãã ã•ã„。"
@@ -42525,9 +42670,6 @@ msgstr "レãƒãƒ¼ãƒˆã®æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¾ã—ãŸ"
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr "çµæžœã«ã¯ã€ãƒ—ロジェクトã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆãƒ–ランãƒã«ã‚る最新ã®æˆåŠŸã—ãŸãƒ‘イプラインã‹ã‚‰ã®æ—¢å­˜ã®è„†å¼±æ€§ã«åŠ ãˆã¦ã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚ˆã£ã¦ã‚‚ãŸã‚‰ã•ã‚ŒãŸè„†å¼±æ€§ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚"
-msgid "SecurityReports|Save comment"
-msgstr "コメントをä¿å­˜"
-
msgid "SecurityReports|Scan details"
msgstr "スキャンã®è©³ç´°"
@@ -42571,8 +42713,8 @@ msgstr "ã¾ã æ¤œå‡ºã•ã‚Œã¦ã„ã¾ã™"
msgid "SecurityReports|Submit vulnerability"
msgstr "脆弱性をé€ä¿¡"
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
-msgstr "脆弱性レãƒãƒ¼ãƒˆã«ã¯ã€ãƒ—ロジェクトã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆãƒ–ランãƒã®æˆåŠŸã—ãŸã‚¹ã‚­ãƒ£ãƒ³çµæžœã€æ‰‹å‹•ã§è¿½åŠ ã•ã‚ŒãŸè„†å¼±æ€§ãƒ¬ã‚³ãƒ¼ãƒ‰ã€ãŠã‚ˆã³é‹ç”¨ç’°å¢ƒã®ã‚¹ã‚­ãƒ£ãƒ³ã‹ã‚‰æ¤œå‡ºã•ã‚ŒãŸè„†å¼±æ€§ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚%{linkStart}詳細ã¯ã“ã¡ã‚‰ã€‚%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
msgstr "次ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ¬ãƒãƒ¼ãƒˆã«ã¯ã€è§£æžã§ããšã«è¨˜éŒ²ã•ã‚Œãªã‹ã£ãŸè„†å¼±æ€§ã®æ¤œå‡ºçµæžœãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚レãƒãƒ¼ãƒˆã‚’調査ã™ã‚‹ã«ã¯ã€ã‚¸ãƒ§ãƒ–出力ã®ã‚¢ãƒ¼ãƒ†ã‚£ãƒ•ã‚¡ã‚¯ãƒˆã‚’ダウンロードã—ã¦ãã ã•ã„。セキュリティレãƒãƒ¼ãƒˆãŒã€é–¢é€£ã™ã‚‹%{helpPageLinkStart}JSONスキーマ%{helpPageLinkEnd}ã«æº–æ‹ ã—ã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
@@ -42779,7 +42921,7 @@ msgid "Select color"
msgstr "色ã®é¸æŠž"
msgid "Select confidentiality"
-msgstr ""
+msgstr "機密性をé¸æŠž"
msgid "Select default branch"
msgstr "デフォルトブランãƒã‚’é¸æŠž"
@@ -42919,9 +43061,6 @@ msgstr "マルãƒãƒ‘ãƒ¼ãƒˆå½¢å¼ (HTMLã¨ãƒ—レーンテキスト) ã§ãƒ¡ãƒ¼ãƒ«ã
msgid "Send email notification"
msgstr "メール通知をé€ä¿¡"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "オンボーディングプロセスを通ã˜ã¦æ–°è¦ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’ガイドã™ã‚‹ã®ã«å½¹ç«‹ã¤ãƒ¡ãƒ¼ãƒ«ã‚’é€ä¿¡ã—ã¾ã™ã€‚"
-
msgid "Send emails to users upon account deactivation."
msgstr "アカウントã®ç„¡åŠ¹åŒ–時ã«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ãƒ¡ãƒ¼ãƒ«ã‚’é€ä¿¡ã—ã¾ã™ã€‚"
@@ -42991,6 +43130,9 @@ msgstr "サービスアカウントキーã¯ã€GitLab ㌠Google Cloud プロジ
msgid "Service Desk"
msgstr "サービスデスク"
+msgid "Service Desk Ticket"
+msgstr "サービスデスクãƒã‚±ãƒƒãƒˆ"
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr "サービスデスクã¯ã€GitLabインスタンスã§ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãªã—ã«ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆã™ã‚‹æ–¹æ³•ã§ã™ã€‚エンドユーザーãŒãƒ—ロジェクトã§ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆã™ã‚‹ãŸã‚ã®ãƒ¦ãƒ‹ãƒ¼ã‚¯ãªãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’æä¾›ã—ã¾ã™ã€‚返信ã¯GitLabインターフェイスã¾ãŸã¯ãƒ¡ãƒ¼ãƒ«ã§é€ä¿¡ã§ãã¾ã™ã€‚エンドユーザーã¯ãƒ¡ãƒ¼ãƒ«ã§ã®ã¿ã‚¹ãƒ¬ãƒƒãƒ‰ã‚’表示ã—ã¾ã™ã€‚"
@@ -43015,26 +43157,38 @@ msgstr "ã“ã®åå‰ç©ºé–“ã§ã‚µãƒ¼ãƒ“スアカウントを作æˆã™ã‚‹æ¨©é™ãŒ
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr "サービスアカウントを作æˆã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。"
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr "SMTPホスト%{smtpAddress}ã®%{customEmail}ã¯%{badgeStart}検証済ã¿%{badgeEnd}"
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr "指定ã•ã‚ŒãŸãƒ›ã‚¹ãƒˆã¸æŽ¥ç¶šã§ããªã‹ã£ãŸã‹ã€SSLã®å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr "確èªãƒ¡ãƒ¼ãƒ«ãŒã‚ãªãŸã®ã‚«ã‚¹ã‚¿ãƒ ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã®ã‚µãƒ–アドレスã«é€ä¿¡ã•ã‚Œã¾ã—ãŸã€‚ã“ã‚Œã«ã¯æœ€å¤§30分ã‹ã‹ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚ç”»é¢ã¯è‡ªå‹•çš„ã«æ›´æ–°ã•ã‚Œã¾ã™ã€‚"
+
msgid "ServiceDesk|Cannot create custom email"
msgstr "カスタムメールを作æˆã§ãã¾ã›ã‚“"
msgid "ServiceDesk|Cannot update custom email"
msgstr "カスタムメールを更新ã§ãã¾ã›ã‚“"
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr "転é€è¨­å®šã‚’確èªã—ã€Fromヘッダーã«å…ƒã®ãƒ¡ãƒ¼ãƒ«é€ä¿¡è€…ãŒæ®‹ã£ã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
-msgstr ""
+msgstr "TLSを使用ã—ã¦ã„ã‚‹å ´åˆã¯å…±é€šãƒãƒ¼ãƒˆã¯587ã€ãã†ã§ãªã„å ´åˆã¯25ã§ã™ã€‚"
msgid "ServiceDesk|Configure a custom email address"
msgstr "カスタムメールアドレスを設定"
msgid "ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials."
-msgstr ""
+msgstr "顧客ãŒã‚µãƒ¼ãƒ“スデスクã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã§ãるカスタムメールアドレスを接続ã—ã¾ã™ã€‚ カスタムメールアドレスã‹ã‚‰ã™ã¹ã¦ã®ãƒ¡ãƒ¼ãƒ«ã‚’ã“ã®ãƒ—ロジェクトã®ã‚µãƒ¼ãƒ“スデスクã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã«è»¢é€ã—ã¾ã™ã€‚ GitLabã¯ãŠå®¢æ§˜ã®SMTPèªè¨¼æƒ…報を使用ã—ã¦ã€ãŠå®¢æ§˜ã®ä»£ã‚ã‚Šã«ã‚«ã‚¹ã‚¿ãƒ ã‚¢ãƒ‰ãƒ¬ã‚¹ã‹ã‚‰ã‚µãƒ¼ãƒ“スデスクメールをé€ä¿¡ã—ã¾ã™ã€‚"
msgid "ServiceDesk|Copy Service Desk email address"
-msgstr ""
+msgstr "サービスデスクã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’コピー"
msgid "ServiceDesk|Custom email address"
-msgstr ""
+msgstr "カスタムメールアドレス"
msgid "ServiceDesk|Custom email address could not be verified."
msgstr "カスタムメールアドレスã¯æ¤œè¨¼ã§ãã¾ã›ã‚“。"
@@ -43048,26 +43202,50 @@ msgstr "カスタムメールアドレスã®æ¤œè¨¼å‡¦ç†ã¯æ—¢ã«å®Œäº†ã—ã€å¤±
msgid "ServiceDesk|Custom email already exists"
msgstr "カスタムメールã¯ã™ã§ã«å­˜åœ¨ã—ã¾ã™"
+msgid "ServiceDesk|Custom email disabled."
+msgstr "カスタムメールã¯ç„¡åŠ¹ã§ã™ã€‚"
+
msgid "ServiceDesk|Custom email does not exist"
msgstr "カスタムメールã¯å­˜åœ¨ã—ã¾ã›ã‚“。"
+msgid "ServiceDesk|Custom email enabled."
+msgstr "ServiceDesk|カスタム電å­ãƒ¡ãƒ¼ãƒ«ãŒæœ‰åŠ¹ã§ã™ã€‚"
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
-msgstr ""
+msgstr "カスタムメールアドレスã¯å¿…é ˆã§ã€æœ‰åŠ¹ãªãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã§ã‚ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "ServiceDesk|Email address your customers can use to send support requests. It must support sub-addressing."
-msgstr ""
+msgstr "顧客ãŒã‚µãƒãƒ¼ãƒˆãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’é€ä¿¡ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã§ãるメールアドレス。サブアドレスをサãƒãƒ¼ãƒˆã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "ServiceDesk|Enable Service Desk"
msgstr "サービスデスクを有効ã«ã™ã‚‹"
+msgid "ServiceDesk|Enable custom email address"
+msgstr "カスタムメールを有効化"
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr "インスタンスã®ã‚µãƒ¼ãƒ“スデスクã®è¨­å®šã«ã¤ã„ã¦ã¯ã€ç®¡ç†è€…ã«å•ã„åˆã‚ã›ã¦ãã ã•ã„。"
+msgid "ServiceDesk|Incorrect From header"
+msgstr "ä¸æ­£ãª From ヘッダー"
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr "èªè¨¼ãƒˆãƒ¼ã‚¯ãƒ³ãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“"
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr "無効ãªèªè¨¼æƒ…å ±"
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr "サービスデスクã®ãƒ¡ãƒ¼ãƒ«ã‹ã‚‰ä½œæˆã•ã‚ŒãŸã‚¤ã‚·ãƒ¥ãƒ¼ã¯ã€ã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚å„コメントã¯ã€ãƒ¡ãƒ¼ãƒ«ã®ä¼šè©±ã®ä¸€éƒ¨ã¨ãªã‚Šã¾ã™ã€‚"
+msgid "ServiceDesk|Keep custom email"
+msgstr "カスタムメールをä¿æŒ"
+
msgid "ServiceDesk|Minimum 8 characters long."
-msgstr ""
+msgstr "8文字以上ã§ã™ã€‚"
+
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr "ã¾ãŸã¯ã€æ–°ã—ã„カスタムメールアドレスをã“ã®ã‚µãƒ¼ãƒ“スデスクã«ãƒªã‚»ãƒƒãƒˆã—ã¦æŽ¥ç¶šã—ã¾ã™ã€‚"
msgid "ServiceDesk|Parameters missing"
msgstr "パラメータãŒã‚ã‚Šã¾ã›ã‚“"
@@ -43075,38 +43253,53 @@ msgstr "パラメータãŒã‚ã‚Šã¾ã›ã‚“"
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr "%{linkStart}フィードãƒãƒƒã‚¯ã‚¤ã‚·ãƒ¥ãƒ¼%{linkEnd} ã§ã“ã®æ©Ÿèƒ½ã«é–¢ã™ã‚‹ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã‚’æä¾›ã—ã¦ãã ã•ã„"
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr "ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。メール転é€è¨­å®šã¨èªè¨¼æƒ…報を確èªã—ã€èªè¨¼ã‚’å†é–‹ã—ã¦ãã ã•ã„。"
+
+msgid "ServiceDesk|Reset custom email"
+msgstr "カスタムメールをリセット"
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr "カスタムメールリセットã—ã€èªè¨¼ã‚’削除"
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr "カスタムメールをリセット。"
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
-msgstr ""
+msgstr "SMTPアドレスã¯å¿…é ˆã§ã€åå‰è§£æ±ºãŒå¯èƒ½ã§ãªã‘ã‚Œãªãªã‚Šã¾ã›ã‚“。"
msgid "ServiceDesk|SMTP host"
-msgstr ""
+msgstr "SMTPホスト"
+
+msgid "ServiceDesk|SMTP host issue"
+msgstr "SMTPホストã®å•é¡Œ"
msgid "ServiceDesk|SMTP password"
-msgstr ""
+msgstr "SMTPパスワード"
msgid "ServiceDesk|SMTP password is required and must be at least 8 characters long."
-msgstr ""
+msgstr "SMTPパスワードã¯å¿…é ˆã§ã€8文字以上ã§ã‚ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "ServiceDesk|SMTP port"
-msgstr ""
+msgstr "SMTPãƒãƒ¼ãƒˆ"
msgid "ServiceDesk|SMTP port is required and must be a port number larger than 0."
-msgstr ""
+msgstr "SMTPãƒãƒ¼ãƒˆã¯å¿…é ˆã§ã‚ã‚Šã€0より大ãã„ãƒãƒ¼ãƒˆç•ªå·ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。"
msgid "ServiceDesk|SMTP username"
-msgstr ""
+msgstr "SMTPユーザーå"
msgid "ServiceDesk|SMTP username is required."
-msgstr ""
+msgstr "SMTPユーザーåãŒå¿…è¦ã§ã™ã€‚"
msgid "ServiceDesk|Save and test connection"
-msgstr ""
+msgstr "接続ã®ä¿å­˜ã¨ãƒ†ã‚¹ãƒˆ"
msgid "ServiceDesk|Saved custom email address and started verification."
-msgstr ""
+msgstr "カスタムメールアドレスをä¿å­˜ã—ã€èªè¨¼ã‚’開始ã—ã¾ã—ãŸã€‚"
msgid "ServiceDesk|Service Desk email address to forward emails to"
-msgstr ""
+msgstr "メールを転é€ã™ã‚‹ãŸã‚ã®ã‚µãƒ¼ãƒ“スデスクã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹"
msgid "ServiceDesk|Service Desk is not enabled"
msgstr "サービスデスクãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã›ã‚“"
@@ -43120,15 +43313,45 @@ msgstr "サービスデスクã®è¨­å®šãŒã‚ã‚Šã¾ã›ã‚“"
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr "サービスデスクã®è¨­å®šã¾ãŸã¯æ¤œè¨¼ã‚ªãƒ–ジェクトãŒã‚ã‚Šã¾ã›ã‚“"
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr "指定ã•ã‚ŒãŸãƒ­ã‚°ã‚¤ãƒ³æƒ…å ±(ユーザーåã¨ãƒ‘スワード)ãŒSMTP サーãƒãƒ¼ã«ã‚ˆã£ã¦æ‹’å¦ã•ã‚Œã¾ã—ãŸã€‚"
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr "å—ä¿¡ã—ãŸãƒ¡ãƒ¼ãƒ«ã«ã€ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã«é€ä¿¡ã•ã‚ŒãŸèªè¨¼ãƒˆãƒ¼ã‚¯ãƒ³ãŒå«ã¾ã‚Œã¦ã„ã¾ã›ã‚“。"
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr "確èªãƒ¡ãƒ¼ãƒ«ã‚’時間内ã«å—ä¿¡ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚確èªãƒ¡ãƒ¼ãƒ«ãŒã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®ã‚µãƒ¼ãƒ“スデスクã«è¡¨ç¤ºã•ã‚Œã‚‹ã¾ã§ã«30分間ã®æ™‚é–“æž ãŒã‚ã‚Šã¾ã™ã€‚ メール転é€ã‚’æ­£ã—ã設定ã—ã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr "ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã§ã‚µãƒ¼ãƒ“スデスクを有効ã«ã™ã‚‹ã«ã¯ã€ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ç®¡ç†è€…ãŒæœ€åˆã«å—信メールを設定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr "ã“ã®ã‚µãƒ¼ãƒ“スデスクã®ã‚«ã‚¹ã‚¿ãƒ ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’使用ã™ã‚‹ã«ã¯ã€ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã®å†è¨­å®šã¨å†ç¢ºèªãŒå¿…è¦ã§ã™ã€‚"
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr "サービスデスクを使用ã—ã¦ã€GitLab 内㮠メールã§ãƒ¦ãƒ¼ã‚¶ã¨æŽ¥ç¶šã—ã€GitLab 内ã®ãƒ¡ãƒ¼ãƒ«ã§é¡§å®¢ã‚µãƒãƒ¼ãƒˆã‚’è¡Œã†"
msgid "ServiceDesk|User cannot manage project."
msgstr "ユーザーã¯ãƒ—ロジェクトを管ç†ã§ãã¾ã›ã‚“。"
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr "確èªãƒ¡ãƒ¼ãƒ«ã¯æ™‚間枠内ã§å—ä¿¡ã•ã‚Œã¦ã„ã¾ã›ã‚“"
+
+msgid "ServiceDesk|Verification failed"
+msgstr "èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸ"
+
+msgid "ServiceDesk|Verification started"
+msgstr "èªè¨¼ãŒé–‹å§‹ã•ã‚Œã¾ã—ãŸ"
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr "SMTPホスト%{smtpAddress}㧠%{customEmail} ã‚’ç¢ºèª :"
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr "有効ã«ã™ã‚‹ã¨ã€æä¾›ã•ã‚ŒãŸèªè¨¼æƒ…報を使用ã—ã¦ã‚µãƒ¼ãƒ“スデスクメールãŒé€ä¿¡ã•ã‚Œã¾ã™ã€‚"
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr "%{strongStart}カスタムメールアドレス%{strongEnd} %{customEmail} %{strongStart}を無効ã«ã—ã€ãã®è³‡æ ¼æƒ…å ±%{strongEnd} を削除ã—ã¾ã™ã€‚"
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr "ユーザã¯ã“ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã«ãƒ¡ãƒ¼ãƒ«ã‚’é€ä¿¡ã§ãã¾ã™ã€‚"
@@ -43156,6 +43379,9 @@ msgstr "セッションID"
msgid "Session duration (minutes)"
msgstr "セッション期間 (分)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr "ユーザーを検証ã§ãã¾ã›ã‚“。ユーザーèªè¨¼ãƒãƒ£ãƒ¬ãƒ³ã‚¸ã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ページを更新ã—ã¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "%{epic_ref} を親エピックã¨ã—ã¦è¨­å®šã—ã¾ã—㟠。"
@@ -43276,6 +43502,9 @@ msgstr "見ç©æ™‚é–“ã‚’ %{time_estimate} ã«è¨­å®šã€‚"
msgid "Set to 0 for no size limit."
msgstr "サイズ制é™ãªã—ã®å ´åˆã¯0ã«è¨­å®šã—ã¦ãã ã•ã„。"
+msgid "Set to 0 to disable timeout."
+msgstr "タイムアウトを無効ã«ã™ã‚‹ã«ã¯0ã«è¨­å®šã—ã¦ãã ã•ã„。"
+
msgid "Set to auto-merge"
msgstr "自動マージã«è¨­å®š"
@@ -43354,6 +43583,9 @@ msgstr "ステータスを %{date} ã«ãƒªã‚»ãƒƒãƒˆã—ã¾ã™ã€‚"
msgid "Sets %{epic_ref} as parent epic."
msgstr "%{epic_ref} を親エピックã¨ã—ã¦è¨­å®šã€‚"
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr "å¥å…¨æ€§ã®çŠ¶æ…‹ã‚’%{health_status}ã«è¨­å®šã—ã¾ã™ã€‚"
@@ -43416,7 +43648,7 @@ msgid "Share"
msgstr "共有"
msgid "Share the %{strong_open}GitLab single sign-on URL%{strong_close} with members so they can sign in to your group through your identity provider"
-msgstr ""
+msgstr "メンãƒãƒ¼ã¨%{strong_open}GitLabã®ã‚·ãƒ³ã‚°ãƒ«ã‚µã‚¤ãƒ³ã‚ªãƒ³URL%{strong_close}を共有ã™ã‚‹ã¨ã€è‡ªèº«ã® ID プロãƒã‚¤ãƒ€ãƒ¼ã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™"
msgid "Shared Runners"
msgstr "共有Runner"
@@ -44187,6 +44419,9 @@ msgstr "ã ã‚Œã‹ãŒæ–°ã—ã„場所ã‹ã‚‰ã‚ãªãŸã®%{host}アカウントã«ã‚
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "ã ã‚Œã‹ãŒ (ãŠãらã本人) ãŒ%{link_to_gitlab}ã® GitLab アカウントã®ãƒ‘スワードをリセットã™ã‚‹ã‚ˆã†ã«ãƒªã‚¯ã‚¨ã‚¹ãƒˆã—ã¾ã—ãŸã€‚"
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -44280,9 +44515,6 @@ msgstr "説明変更ã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ãŠ
msgid "Something went wrong while fetching details"
msgstr "詳細ã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸ"
-msgid "Something went wrong while fetching latest comments."
-msgstr "最新コメントã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-
msgid "Something went wrong while fetching projects"
msgstr "プロジェクト情報をå–å¾—ã™ã‚‹é–“ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -44614,7 +44846,7 @@ msgid "Source is not available"
msgstr "ソースã¯åˆ©ç”¨ã§ãã¾ã›ã‚“"
msgid "Source project"
-msgstr ""
+msgstr "ソースプロジェクト"
msgid "Source project cannot be found."
msgstr "ソースプロジェクトãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
@@ -44947,7 +45179,7 @@ msgid "StatusCheck|Apply this status check to all branches or a specific protect
msgstr "ã“ã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒã‚§ãƒƒã‚¯ã‚’ä»»æ„ã®ãƒ–ランãƒã¾ãŸã¯ç‰¹å®šã®ä¿è­·ã•ã‚ŒãŸãƒ–ランãƒã«é©ç”¨ã—ã¾ã™ã€‚"
msgid "StatusCheck|Check for a status response in merge requests. %{linkStart}Learn more%{linkEnd}."
-msgstr ""
+msgstr "マージリクエストã§ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹å¿œç­”を確èªã—ã¾ã™ã€‚%{linkStart}詳細ã¯ã“ã¡ã‚‰ã§ã™%{linkEnd}。"
msgid "StatusCheck|Examples: QA, Security."
msgstr "例: QAã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã€‚"
@@ -45208,7 +45440,7 @@ msgid "Subscription deletion failed."
msgstr "サブスクリプションã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
msgid "Subscription for %{subscription} will be removed. Do you want to continue?"
-msgstr ""
+msgstr "%{subscription} ã®ã‚µãƒ–スクリプションã¯å‰Šé™¤ã•ã‚Œã¾ã™ã€‚続行ã—ã¾ã™ã‹ï¼Ÿ"
msgid "Subscription service outage"
msgstr "サブスクリプションサービスã®åœæ­¢"
@@ -45231,6 +45463,18 @@ msgstr "ライセンス使用状æ³ãƒ•ã‚¡ã‚¤ãƒ«ã‚’エクスãƒãƒ¼ãƒˆ"
msgid "SubscriptionBanner|Upload new license"
msgstr "æ–°ã—ã„ライセンスをアップロード"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr "シートã®è¿½åŠ ã€ãƒ—ランã®ã‚¢ãƒƒãƒ—グレードã€è¿½åŠ ã®è£½å“を購入ã™ã‚‹å ´åˆã¯ã€GitLabã®å–¶æ¥­æ‹…当者ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。"
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr "ã“ã‚Œã¯GitLabセールスãƒãƒ¼ãƒ ãŒç®¡ç†ã™ã‚‹ã‚«ã‚¹ã‚¿ãƒ ã‚µãƒ–スクリプションã§ã™"
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr "読ã¿å–り専用ã®ã‚µãƒ–スクリプションを変更ã—ãŸã‚Šã€è¿½åŠ ã®è£½å“を購入ã—ãŸã‚Šã™ã‚‹ã«ã¯ã€GitLabパートナーã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。"
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr "サブスクリプションã¯èª­ã¿å–り専用モードã§ã™"
+
msgid "SubscriptionTable|Add seats"
msgstr "シートã®è¿½åŠ "
@@ -45378,6 +45622,9 @@ msgstr "無効化ã«æˆåŠŸã—ã¾ã—ãŸ"
msgid "Successfully deleted WebAuthn device."
msgstr "WebAuthnデãƒã‚¤ã‚¹ã‚’正常ã«å‰Šé™¤ã—ã¾ã—ãŸã€‚"
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr "ID:%{item_ids}ãŒæ­£å¸¸ã«ãƒªãƒ³ã‚¯ã•ã‚Œã¾ã—㟠。"
+
msgid "Successfully removed email."
msgstr "メールを削除ã—ã¾ã—ãŸã€‚"
@@ -45396,6 +45643,9 @@ msgstr "正常㫠BAN を解除ã—ã¾ã—ãŸ"
msgid "Successfully unblocked"
msgstr "正常ã«ãƒ–ロックãŒè§£é™¤ã•ã‚Œã¾ã—ãŸ"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr "正常ã«ãƒªãƒ³ã‚¯è§£é™¤ã•ã‚ŒãŸID: %{item_ids}."
+
msgid "Successfully unlocked"
msgstr "正常ã«ãƒ­ãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã¾ã—ãŸ"
@@ -46055,6 +46305,9 @@ msgstr "GitLab Duo ãƒãƒ£ãƒƒãƒˆã¨ã®é€šä¿¡ä¸­ã«ã€ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ã
msgid "TanukiBot|What is a fork?"
msgstr "フォークã¨ã¯?"
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr "ターゲット"
@@ -46067,8 +46320,14 @@ msgstr "対象パス"
msgid "Target branch"
msgstr "ターゲットブランãƒ"
-msgid "Target branch or tag"
-msgstr "ターゲットブランãƒã¾ãŸã¯ã‚¿ã‚°"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
+msgstr ""
msgid "Target branch: %{target_branch}"
msgstr "ターゲットブランãƒ: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr "タイムアウトã®ãŸã‚ã€ãƒšãƒ¼ã‚¸ãŒè¡¨ç¤ºã§ãã¾ã›ã‚“ã§ã—ãŸ
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr "親エピックã¯ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«ã§ã€ã‚³ãƒ³ãƒ•ã‚£ãƒ‡ãƒ³ã‚·ãƒ£ãƒ«ã®ã‚¨ãƒ”ックã¨ã‚¤ã‚·ãƒ¥ãƒ¼ã ã‘ã‚’å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™"
-msgid "The parsed YAML is too big"
-msgstr "パースã•ã‚ŒãŸYAMLãŒå¤§ãã™ãŽã¾ã™"
-
msgid "The password for the Jenkins server."
msgstr "Jenkins サーãƒãƒ¼ã®ãƒ‘スワード。"
@@ -47070,6 +47326,9 @@ msgstr "脆弱性ãŒæ¤œå‡ºã•ã‚Œãªããªã‚Šã¾ã—ãŸã€‚ステータスを変更
msgid "There are currently no mirrored repositories."
msgstr "ç¾åœ¨ã€ãƒŸãƒ©ãƒ¼ãƒªãƒ³ã‚°ã•ã‚ŒãŸãƒªãƒã‚¸ãƒˆãƒªã¯ã‚ã‚Šã¾ã›ã‚“。"
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "マージã®ç«¶åˆãŒã‚ã‚Šã¾ã™"
@@ -47088,9 +47347,6 @@ msgstr "ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã‚‹SSHキーã¯å­˜åœ¨ã—
msgid "There are no Spam Logs"
msgstr "スパムログã¯ã‚ã‚Šã¾ã›ã‚“"
-msgid "There are no abuse reports!"
-msgstr "ä¸æ­£åˆ©ç”¨å ±å‘Šã¯ã‚ã‚Šã¾ã›ã‚“!"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr "指定ã•ã‚ŒãŸ `represent_as` パラメータã«ã¯æ‰¿èªãƒ«ãƒ¼ãƒ«ãŒã‚ã‚Šã¾ã›ã‚“。代ã‚ã‚Šã«æœ‰åŠ¹ãªãƒ¦ãƒ¼ã‚¶ãƒ¼/グループ/ロールåを使用ã—ã¦ãã ã•ã„。"
@@ -47263,7 +47519,7 @@ msgid "There was a problem fetching the latest pipeline status."
msgstr "最新ã®ãƒ‘イプラインã®çŠ¶æ…‹ã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "There was a problem fetching the pipeline stage."
-msgstr ""
+msgstr "パイプラインã®ã‚¹ãƒ†ãƒ¼ã‚¸ã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "There was a problem fetching the pipeline stages."
msgstr "パイプラインã®ã‚¹ãƒ†ãƒ¼ã‚¸ã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -47340,6 +47596,9 @@ msgstr "é¸æŠžã—ãŸã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒˆãƒƒãƒ—ラベルã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒ
msgid "There was an error fetching the variables."
msgstr "変数ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "There was an error fetching this merge request's pipelines."
+msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ãƒ‘イプラインã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+
msgid "There was an error fetching value stream analytics stages."
msgstr "ãƒãƒªãƒ¥ãƒ¼ã‚¹ãƒˆãƒªãƒ¼ãƒ åˆ†æžã‚¹ãƒ†ãƒ¼ã‚¸ã‚’å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -47424,11 +47683,14 @@ msgstr "reCAPTCHA ã«ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã—ãŸã€‚reCAPTCHA ã‚’ã‚‚ã†ä¸€åº¦å®Ÿæ
msgid "There was an summarizing your pending comments."
msgstr "ä¿ç•™ä¸­ã®ã‚³ãƒ¡ãƒ³ãƒˆã®è¦ç´„ãŒã‚ã‚Šã¾ã—ãŸã€‚"
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr "ã“れらã®ãƒ–ランãƒã«ã¯ã™ã§ã«ã‚ªãƒ¼ãƒ—ンãªãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒã‚ã‚Šã¾ã™: %{link_to_mr}。別ã®ã‚½ãƒ¼ã‚¹ãƒ–ランãƒã¾ãŸã¯ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒ–ランãƒã‚’é¸æŠžã—ã¾ã™ã€‚"
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr "ã“れらã®æ—¥ä»˜ã¯ã€ã‚¨ãƒ”ックãŒãƒ­ãƒ¼ãƒ‰ãƒžãƒƒãƒ—ã«ã©ã®ã‚ˆã†ã«è¡¨ç¤ºã•ã‚Œã‚‹ã‹ã«å½±éŸ¿ã—ã¾ã™ã€‚ã“ã®ã‚¨ãƒ”ックã®ã‚¤ã‚·ãƒ¥ãƒ¼ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸãƒžã‚¤ãƒ«ã‚¹ãƒˆãƒ¼ãƒ³ã‹ã‚‰ç¶™æ‰¿ã•ã‚ŒãŸæ—¥ä»˜ã¾ãŸã¯å›ºå®šå€¤ã‚’設定ã—ã¾ã™ã€‚"
msgid "These examples show common methods of triggering a pipeline with a pipeline trigger token. The URL and ID for this project is prefilled."
-msgstr ""
+msgstr "ã“れらã®ä¾‹ã¯ã€ãƒ‘イプライントリガートークンを使用ã—ã¦ãƒ‘イプラインをトリガーã™ã‚‹ä¸€èˆ¬çš„ãªæ–¹æ³•ã‚’示ã—ã¦ã„ã¾ã™ã€‚ã“ã®ãƒ—ロジェクト㮠URL 㨠ID ã¯äº‹å‰ã«å…¥åŠ›ã•ã‚Œã¦ã„ã¾ã™ã€‚"
msgid "These existing issues have a similar title. It might be better to comment there instead of creating another similar issue."
msgstr "既存ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã«åŒæ§˜ã®ã‚¿ã‚¤ãƒˆãƒ«ãŒã‚ã‚Šã¾ã™ã€‚別ã®ä¼¼ãŸã‚ˆã†ãªã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆã™ã‚‹ã‚ˆã‚Šã€ãã“ã«ã‚³ãƒ¡ãƒ³ãƒˆã™ã‚‹æ–¹ãŒè‰¯ã„ã§ã™ã€‚"
@@ -47928,9 +48190,15 @@ msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ãƒ—ライベートプロジェクトã‹
msgid "This merge request is from an internal project to a public project."
msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯å†…部プロジェクトã‹ã‚‰ãƒ‘ブリックプロジェクトã¸ã®ã‚‚ã®ã§ã™ã€‚"
+msgid "This merge request is hidden because its author has been banned"
+msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ä½œæˆè€…ãŒBANã•ã‚Œã¦ã„ã‚‹ãŸã‚éžè¡¨ç¤ºã«ãªã£ã¦ã„ã¾ã™"
+
msgid "This merge request is locked."
msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚"
+msgid "This merge request is locked. Only project members can comment."
+msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚プロジェクトメンãƒãƒ¼ã®ã¿ã‚³ãƒ¡ãƒ³ãƒˆã§ãã¾ã™ã€‚"
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ãƒžãƒ¼ã‚¸ã—ã¦ã„ã¾ã™ã€‚ã“ã®æ案をé©ç”¨ã™ã‚‹ã«ã¯ã€ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’直接編集ã—ã¦ãã ã•ã„。"
@@ -47949,11 +48217,11 @@ msgstr "ã“ã®ãƒ‘イプラインã¯ã€%{strongStart}Auto DevOps%{strongEnd} ã«ã
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr "ã“ã®ãƒ‘イプラインã¯ã€Auto DevOpsã«ã‚ˆã£ã¦æœ‰åŠ¹åŒ–ã•ã‚ŒãŸå®šç¾©æ¸ˆã¿ã®CI/CD設定を利用ã—ã¾ã™ã€‚"
-msgid "This pipeline was triggered by a schedule"
-msgstr "ã“ã®ãƒ‘イプラインã¯ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã«ã‚ˆã£ã¦ãƒˆãƒªã‚¬ãƒ¼ã•ã‚Œã¾ã—ãŸ"
+msgid "This pipeline was created by a schedule"
+msgstr ""
-msgid "This pipeline was triggered by a schedule."
-msgstr "ã“ã®ãƒ‘イプラインã¯ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã«ã‚ˆã£ã¦ãƒˆãƒªã‚¬ãƒ¼ã—ã¾ã—ãŸã€‚"
+msgid "This pipeline was created by a schedule."
+msgstr ""
msgid "This process deletes the project repository and all related resources."
msgstr "ã“ã®ãƒ—ロセスã¯ã€ãƒ—ロジェクトリãƒã‚¸ãƒˆãƒªã¨é–¢é€£ã™ã‚‹ã™ã¹ã¦ã®ãƒªã‚½ãƒ¼ã‚¹ã‚’削除ã—ã¾ã™ã€‚"
@@ -48040,7 +48308,7 @@ msgid "This repository is currently empty. A new Auto DevOps pipeline will be cr
msgstr "ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã¯ç¾åœ¨ç©ºã§ã™ã€‚æ–°ã—ã„ファイルãŒãƒ–ランãƒã«ãƒ—ッシュã•ã‚ŒãŸå¾Œã€æ–°ã—ã„ Auto DevOps パイプラインãŒä½œæˆã•ã‚Œã¾ã™ã€‚"
msgid "This repository was last checked %{last_check_timestamp}. The check %{strong_start}failed.%{strong_end} See the 'repocheck.log' file for error messages."
-msgstr ""
+msgstr "ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã‚’最後ã«ãƒã‚§ãƒƒã‚¯ã—ãŸã®ã¯ %{last_check_timestamp} ã§ã™ã€‚ãƒã‚§ãƒƒã‚¯ã« %{strong_start}失敗%{strong_end} ã—ã¾ã—ãŸã€‚エラーメッセージ㯠'repocheck.log' ファイルをå‚ç…§ã—ã¦ãã ã•ã„。"
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
msgstr "ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã®æœ€å¾Œã®ãƒã‚§ãƒƒã‚¯ã¯%{last_check_timestamp} ã§ã—ãŸã€‚ãƒã‚§ãƒƒã‚¯ã¯å®Œäº†ã—ã¾ã—ãŸã€‚"
@@ -48102,8 +48370,8 @@ msgstr "ã“ã¡ã‚‰ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ã“ã®%{workItemType}ã®ä½œæˆè€…ã§ã™ã€‚"
msgid "This variable value does not meet the masking requirements."
msgstr "ã“ã®å¤‰æ•°ã®å€¤ã¯ãƒžã‚¹ã‚­ãƒ³ã‚°è¦ä»¶ã‚’満ãŸã—ã¦ã„ã¾ã›ã‚“。"
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
-msgstr "ã“ã®è„†å¼±æ€§ã¯ã€ã“ã®ãƒ—ロジェクトã§è„†å¼±æ€§ã®ç¨®é¡žãŒç„¡åŠ¹ã«ãªã£ãŸã‹ã€GitLabã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®ãƒ«ãƒ¼ãƒ«ã‚»ãƒƒãƒˆã‹ã‚‰å‰Šé™¤ã•ã‚ŒãŸãŸã‚ã€è‡ªå‹•çš„ã«è§£æ±ºã•ã‚Œã¾ã—ãŸã€‚"
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
+msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr "ã“ã‚Œã«ã‚ˆã‚Šç™»éŒ²ã•ã‚ŒãŸã‚¢ãƒ—リケーションã¨WebAuthnデãƒã‚¤ã‚¹ã‚’無効ã«ã—ã¾ã™ã€‚"
@@ -48228,8 +48496,8 @@ msgstr "タイムゾーン"
msgid "TimeTrackingEstimated|Est"
msgstr "見ç©ã‚‚り時間"
-msgid "TimeTrackingReport|From"
-msgstr "開始日"
+msgid "TimeTrackingReport|From the start of"
+msgstr ""
msgid "TimeTrackingReport|Run report"
msgstr "レãƒãƒ¼ãƒˆã®å®Ÿè¡Œ"
@@ -48249,8 +48517,8 @@ msgstr "サマリ"
msgid "TimeTrackingReport|Time spent"
msgstr "経éŽæ™‚é–“"
-msgid "TimeTrackingReport|To"
-msgstr "終了日"
+msgid "TimeTrackingReport|To the end of"
+msgstr ""
msgid "TimeTrackingReport|Total time spent: "
msgstr "全経éŽæ™‚é–“: "
@@ -48268,40 +48536,40 @@ msgid "TimeTracking|An error occurred while removing the timelog."
msgstr "タイムログã®å‰Šé™¤ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "TimeTracking|An error occurred while saving the time estimate."
-msgstr ""
+msgstr "時間見ç©ã‚‚ã‚Šã®ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "TimeTracking|Delete time spent"
msgstr "費やã—ãŸæ™‚間を削除"
msgid "TimeTracking|Edit estimate"
-msgstr ""
+msgstr "見ç©ã‚‚りを編集"
msgid "TimeTracking|Edit time estimate"
-msgstr ""
+msgstr "見ç©ã‚‚り時間を編集"
msgid "TimeTracking|Enter time as a total duration (for example, 1mo 2w 3d 5h 10m), or specify hours and minutes (for example, 75:30)."
-msgstr ""
+msgstr "åˆè¨ˆæœŸé–“ã¨ã—ã¦æ™‚間を入力ã—ã¾ã™(ãŸã¨ãˆã°ã€1mo 2w 3d 5h 10mãªã©)ã€ã¾ãŸã¯æ™‚é–“ã¨åˆ†ã§æŒ‡å®šã—ã¾ã™(ãŸã¨ãˆã°ã€75:30)。"
msgid "TimeTracking|Estimate"
-msgstr ""
+msgstr "見ç©ã‚‚ã‚Š"
msgid "TimeTracking|Estimated:"
msgstr "見ç©ã‚‚り時間:"
msgid "TimeTracking|How do I estimate and track time?"
-msgstr ""
+msgstr "時間ã®è¦‹ç©ã‚‚ã‚Šã¨è¿½è·¡ã¯ã©ã†ã™ã‚Œã°ã„ã„ã§ã™ã‹?"
msgid "TimeTracking|Over by %{timeRemainingHumanReadable}"
msgstr "超éŽæ™‚é–“ %{timeRemainingHumanReadable}"
msgid "TimeTracking|Set estimate"
-msgstr ""
+msgstr "見ç©ã‚‚りを設定"
msgid "TimeTracking|Set estimated time to complete this %{issuableTypeName}."
-msgstr ""
+msgstr "ã“ã® %{issuableTypeName}ã®å®Œäº†ã«å¿…è¦ãªæŽ¨å®šæ™‚間を設定ã—ã¾ã™ã€‚"
msgid "TimeTracking|Set time estimate"
-msgstr ""
+msgstr "見ç©ã‚‚り時間を設定"
msgid "TimeTracking|Spent"
msgstr "費やã—ãŸæ™‚é–“"
@@ -48640,7 +48908,7 @@ msgid "To manage seats for all members associated with this group and its subgro
msgstr "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã¨ãã®ã‚µãƒ–グループãŠã‚ˆã³ãƒ—ロジェクトã«é–¢é€£ä»˜ã‘られã¦ã„ã‚‹ã™ã¹ã¦ã®ãƒ¡ãƒ³ãƒãƒ¼ã®ã‚·ãƒ¼ãƒˆã‚’管ç†ã™ã‚‹ã«ã¯ã€%{link_start}使用割り当ã¦ãƒšãƒ¼ã‚¸%{link_end}ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ãã ã•ã„。"
msgid "To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
-msgstr ""
+msgstr "Free ã®ãƒˆãƒƒãƒ—レベル グループã¸ã®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸åˆ¶é™ã®å½±éŸ¿ã‚’最å°é™ã«æŠ‘ãˆã‚‹ãŸã‚ã«ã€GitLab ã¯æœŸé–“é™å®šã§ã€å¯¾è±¡ã¨ãªã‚‹ %{offer_availability_link_start}トップレベル グループã«å¯¾ã—ã¦%{link_end}定価ã‹ã‚‰ %{promotion_link_start}1 回é™ã‚Šã® 70 パーセント割引を%{link_end} æ–°è¦è³¼å…¥æ™‚ã«æä¾›ã—ã¾ã™ã€‚GitLab Premium SaaS ã®1年間サブスクリプション。ã“ã®ç‰¹å…¸ã¯ 2023å¹´10月31æ—¥ã¾ã§æœ‰åŠ¹ã§ã™ã€‚"
msgid "To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here."
msgstr "GitLabプロジェクト全体を別ã®GitLabインストールã‹ã‚‰ã“ã®ãƒ—ロジェクトã«ç§»å‹•ã¾ãŸã¯ã‚³ãƒ”ーã™ã‚‹ã«ã¯ã€å…ƒã®ãƒ—ロジェクトã®è¨­å®šãƒšãƒ¼ã‚¸ã«ç§»å‹•ã—ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’生æˆã—ã¦ã“ã“ã«ã‚¢ãƒƒãƒ—ロードã—ã¾ã™ã€‚"
@@ -48669,8 +48937,8 @@ msgstr "アカウントをå†ã³æœ‰åŠ¹åŒ–ã™ã‚‹ã«ã¯ã€%{gitlab_url} 㧠GitLab
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr "%{link_start}読ã¿å–り専用%{link_end}状態を削除ã—ã¦æ›¸ãè¾¼ã¿ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’å†å–å¾—ã™ã‚‹ã«ã¯ã€ãƒˆãƒƒãƒ—レベルグループã®ã‚ªãƒ¼ãƒŠãƒ¼ã«ä¾é ¼ã—ã¦ã€ãƒˆãƒƒãƒ—レベルグループã®ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ã‚’%{free_limit}ユーザー以下ã«æ¸›ã‚‰ã™ã‹ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ã®åˆ¶é™ã®ãªã„有料プランã«ã‚¢ãƒƒãƒ—グレードã—ã¦ãã ã•ã„。"
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
-msgstr "%{link_start}読ã¿å–り専用%{link_end}状態を削除ã—ã¦æ›¸ãè¾¼ã¿ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’回復ã™ã‚‹ã«ã¯ã€ãƒˆãƒƒãƒ—レベルグループã®ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ã‚’%{free_limit}以下ã«æ¸›ã‚‰ã—ã¦ãã ã•ã„。ã¾ãŸã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ã®åˆ¶é™ã®ãªã„有料プランã«ã‚¢ãƒƒãƒ—グレードã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ã•ã‚‰ã«æ™‚é–“ãŒå¿…è¦ãªå ´åˆã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ç„¡åˆ¶é™ã®30日間ã®ç„¡æ–™ãƒˆãƒ©ã‚¤ã‚¢ãƒ«ã‚’開始ã§ãã¾ã™ã€‚é‹ç”¨ã¸ã®å½±éŸ¿ã‚’最å°é™ã«æŠ‘ãˆã‚‹ãŸã‚ã«ã€GitLabã§ã¯æœŸé–“é™å®šã§ã€GitLab Premium SaaSã®æ–°è¦ã®1å¹´é–“ã®ã‚µãƒ–スクリプションã§ã€%{offer_availability_link_start}資格ã®ã‚るトップレベルグループ%{link_end}ã«å¯¾ã—ã¦ã€è³¼å…¥æ™‚ã®å®šä¾¡ã‹ã‚‰%{promotion_link_start}1回é™ã‚Šã®70%割引%{link_end}ã‚’æä¾›ã—ã¦ã„ ã¾ã™ã€‚ã“ã®ç‰¹å…¸ã¯%{offer_date}ã¾ã§æœ‰åŠ¹ã§ã™ã€‚"
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr "%{link_start}読ã¿å–り専用%{link_end}状態を削除ã—ã¦æ›¸ãè¾¼ã¿ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’å†å–å¾—ã™ã‚‹ã«ã¯ã€ãƒˆãƒƒãƒ—レベルグループã®ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ã‚’%{free_limit}以下ã«æ¸›ã‚‰ã—ã¦ãã ã•ã„。ã¾ãŸã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ã®åˆ¶é™ã®ãªã„有料プランã«ã‚¢ãƒƒãƒ—グレードã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ã‚‚ã†å°‘ã—時間ãŒå¿…è¦ãªå ´åˆã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼æ•°ç„¡åˆ¶é™ã®30日間ã®ç„¡æ–™ãƒˆãƒ©ã‚¤ã‚¢ãƒ«ã‚’開始ã§ãã¾ã™ã€‚"
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
msgstr "電話ã«ã‚ˆã‚‹èªè¨¼ã‚’クレジットカードã«ã‚ˆã‚‹èªè¨¼ã§ç½®ãæ›ãˆã‚‹ã«ã¯ã€ä¸‹ã®ãƒœã‚¿ãƒ³ã‚’使用ã—ã¦ã€é›»è©±ã«ã‚ˆã‚‹èªè¨¼ã®å…除を作æˆã—ã¾ã™ã€‚"
@@ -48951,6 +49219,9 @@ msgstr "ã“ã®ãƒ‘ーソナルアクセストークンã¯ã€æ¤œå‡ºæ™‚ã«è‡ªå‹•çš„
msgid "Tomorrow"
msgstr "明日"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr "有効ã«ãªã£ã¦ã„ã‚‹åå‰ç©ºé–“ãŒå¤šã™ãŽã¾ã™ã€‚コンソールã¾ãŸã¯APIを使用ã—ã¦ç®¡ç†ã—ã¦ãã ã•ã„。"
@@ -49030,6 +49301,9 @@ msgstr "åˆè¨ˆ"
msgid "Total Score"
msgstr "åˆè¨ˆå¾—点"
+msgid "Total Spans"
+msgstr "åˆè¨ˆã‚¹ãƒ‘ン"
+
msgid "Total cores (CPUs)"
msgstr "全コア(CPU)"
@@ -49060,9 +49334,15 @@ msgstr "1000+"
msgid "Trace Details"
msgstr "トレースã®è©³ç´°"
+msgid "Trace Start"
+msgstr "トレースã®é–‹å§‹"
+
msgid "Tracing"
msgstr "トレーシング"
+msgid "Tracing|%{ms} ms"
+msgstr "%{ms} ミリ秒"
+
msgid "Tracing|Check again"
msgstr "ã‚‚ã†ä¸€åº¦ãƒã‚§ãƒƒã‚¯"
@@ -49073,7 +49353,7 @@ msgid "Tracing|Duration"
msgstr "期間"
msgid "Tracing|Duration (ms)"
-msgstr ""
+msgstr "期間(ミリ秒)"
msgid "Tracing|Enable"
msgstr "有効ã«ã™ã‚‹"
@@ -49130,11 +49410,23 @@ msgid "Tracing|Operation"
msgstr "æ“作"
msgid "Tracing|Period"
-msgstr ""
+msgstr "期間"
msgid "Tracing|Service"
msgstr "サービス"
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr "トレース ID"
@@ -49259,13 +49551,13 @@ msgid "Trials|Day %{daysUsed}/%{duration}"
msgstr "%{daysUsed}æ—¥ã‚/%{duration}"
msgid "Trials|Looking to do more with GitLab?"
-msgstr ""
+msgstr "GitLabã§ã•ã‚‰ã«æ´»ç”¨ã—ã¾ã™ã‹ï¼Ÿ"
msgid "Trials|Upgrade your plan for more security features"
-msgstr ""
+msgstr "より多ãã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£æ©Ÿèƒ½ã®ãŸã‚ã«ãƒ—ランをアップグレード"
msgid "Trials|With GitLab Ultimate you can detect and address vulnerabilities in your application."
-msgstr ""
+msgstr "GitLab Ultimate を使用ã™ã‚‹ã¨ã€ã‚¢ãƒ—リケーションã®è„†å¼±æ€§ã‚’検出ã—ã¦å¯¾å‡¦ã§ãã¾ã™ã€‚"
msgid "Trials|You can apply your trial to a new group or an existing group."
msgstr "試用版を新ã—ã„グループã¾ãŸã¯æ—¢å­˜ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«é©ç”¨ã§ãã¾ã™ã€‚"
@@ -49275,7 +49567,7 @@ msgid_plural "Trials|You've got %{daysRemaining} days remaining on GitLab %{plan
msgstr[0] "GitLab (%{planName}) ã¯ã€ã‚ã¨%{daysRemaining}日間ã”利用ã„ãŸã ã‘ã¾ã™ !"
msgid "Trials|Your 30-day trial has ended"
-msgstr ""
+msgstr "30日間ã®è©¦ç”¨æœŸé–“ãŒçµ‚了ã—ã¾ã—ãŸ"
msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
msgstr "トライアルã¯%{boldStart}%{trialEndDate}%{boldEnd}ã§çµ‚了ã—ã¾ã™ã€‚GitLab %{planName}ã®æ©Ÿèƒ½ã‚’楽ã—ã‚“ã§ã„ãŸã ã‘ãŸã§ã—ょã†ã‹? トライアル終了後もã“れらã®æ©Ÿèƒ½ã‚’使ã„続ã‘ã‚‹ã«ã¯ã€ã‚µãƒ–スクリプションを購入ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ (ニーズã«åˆã‚ã›ã¦ GitLab Premium ã‚’é¸æŠžã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™)。"
@@ -49499,9 +49791,6 @@ msgstr "URL ã¾ãŸã¯ リクエスト ID"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr "ユーザー%{user_name}ãŒå‰Šé™¤ã•ã‚Œã¾ã™ã€‚本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹?"
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "ユーザー%{user}ãŒå‰Šé™¤ã•ã‚Œã¾ã™! 本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹?"
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "ユーザーãŒãƒ–ロックã•ã‚Œã¾ã™! 本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹?"
@@ -49589,6 +49878,9 @@ msgstr "マージリクエストウィジェットをロードã§ãã¾ã›ã‚“。
msgid "Unable to load the page"
msgstr "ページを読ã¿è¾¼ã‚ã¾ã›ã‚“"
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr "JSONを解æžã§ãã¾ã›ã‚“"
@@ -49622,9 +49914,6 @@ msgstr "ç¾æ™‚点ã§ã¯ã“ã®ã‚¨ãƒ”ックを更新ã§ãã¾ã›ã‚“。"
msgid "Unable to update this issue at this time."
msgstr "ç¾æ™‚点ã§ã¯ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’æ›´æ–°ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。"
-msgid "Unable to verify the user"
-msgstr "ユーザーを検証ã§ãã¾ã›ã‚“ã§ã—ãŸ"
-
msgid "Unapprove a merge request"
msgstr "マージリクエストã®æ‰¿èªã‚’å–り消ã™"
@@ -49703,6 +49992,9 @@ msgstr "残念ãªãŒã‚‰ã€GitLab ã¸ã®ãƒ¡ãƒ¼ãƒ«å‡¦ç†ã¯ã§ãã¾ã›ã‚“ã§ã—ã
msgid "Unhappy?"
msgstr "ä¸æº€?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr "æ—¥"
@@ -50078,6 +50370,9 @@ msgstr "追加ã®ã‚³ãƒ³ãƒ”ューティング時間を購入"
msgid "UsageQuota|Buy storage"
msgstr "ストレージを購入"
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr "コードパッケージã¨ã‚³ãƒ³ãƒ†ãƒŠã‚¤ãƒ¡ãƒ¼ã‚¸ã€‚"
@@ -50099,12 +50394,12 @@ msgstr "コンテナレジストリ"
msgid "UsageQuota|Dependency proxy"
msgstr "ä¾å­˜ãƒ—ロキシ"
-msgid "UsageQuota|Filter chart by month"
-msgstr "ãƒãƒ£ãƒ¼ãƒˆã‚’月別ã«ãƒ•ã‚£ãƒ«ã‚¿ãƒªãƒ³ã‚°ã™ã‚‹"
-
msgid "UsageQuota|Filter charts by year"
msgstr "ãƒãƒ£ãƒ¼ãƒˆã‚’年別ã«ãƒ•ã‚£ãƒ«ã‚¿ãƒªãƒ³ã‚°ã™ã‚‹"
+msgid "UsageQuota|Filter projects data by month"
+msgstr "プロジェクトã®ãƒ‡ãƒ¼ã‚¿ã‚’月別ã«çµžã‚Šè¾¼ã¿ã¾ã™"
+
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
msgstr "ストレージ制é™ã®è©³ç´°ã«ã¤ã„ã¦ã¯ã€%{faq_link_start}FAQ%{link_end}ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
@@ -50115,7 +50410,7 @@ msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker
msgstr "Dockerイメージを格ç´ã™ã‚‹ãŸã‚ã®Gitlabçµ±åˆDockerコンテナレジストリ。"
msgid "UsageQuota|Group settings %{gt} Usage quotas"
-msgstr ""
+msgstr "グループ設定 %{gt} 使用クオータ"
msgid "UsageQuota|Included in %{planName} subscription"
msgstr "%{planName}サブスクリプションã«å«ã¾ã‚Œã¦ã„ã¾ã™"
@@ -50150,6 +50445,9 @@ msgstr "åå‰ç©ºé–“ã®æ¦‚è¦"
msgid "UsageQuota|Namespace storage used"
msgstr "使用済ã¿ã®åå‰ç©ºé–“ã®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸"
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr "åå‰ç©ºé–“ã®åˆè¨ˆã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã¯ã€ã™ã¹ã¦ã®ãƒ—ロジェクトã€ã‚³ãƒ³ãƒ†ãƒŠãƒ¬ã‚¸ã‚¹ãƒˆãƒªã€ãŠã‚ˆã³ä¾å­˜é–¢ä¿‚プロキシã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã®åˆè¨ˆã‚’示ã—ã¦ã„ã¾ã™ã€‚"
+
msgid "UsageQuota|No compute usage data available."
msgstr "利用å¯èƒ½ãªã‚³ãƒ³ãƒ”ューティング使用状æ³ãƒ‡ãƒ¼ã‚¿ãŒã‚ã‚Šã¾ã›ã‚“。"
@@ -50216,15 +50514,15 @@ msgstr "%{strong_start}%{context_name}%{strong_end}グループã¯ã“ã‚Œã«ã‚ˆã
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr "%{strong_start}%{context_name}%{strong_end}プロジェクトã¯ã“ã‚Œã«ã‚ˆã£ã¦å½±éŸ¿ã‚’å—ã‘ã¾ã™ã€‚"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr "グラフã¨ä¸‹ã®è¡¨ã¯%{month}%{year}ã®ä½¿ç”¨çŠ¶æ³ã‚’示ã—ã¦ã„ã¾ã™"
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
-msgstr ""
+msgstr "ã“ã®åå‰ç©ºé–“ã¯ç¾åœ¨ã€%{strong_start}%{used_storage}%{strong_end}ã®åå‰ç©ºé–“ストレージを使用ã—ã¦ã„ã¾ã™ã€‚グループã®ã‚ªãƒ¼ãƒŠãƒ¼ã¯åå‰ç©ºé–“ã®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ä½¿ç”¨é‡ã‚’確èªã§ãã€%{strong_start}%{usage_quotas_nav_instruction}%{strong_end}ã‹ã‚‰è¿½åŠ è³¼å…¥ã§ãã¾ã™ã€‚%{docs_link_start}ストレージをã©ã®ã‚ˆã†ã«ç®¡ç†ã™ã‚Œã°ã‚ˆã„ã§ã™ã‹%{link_end}?"
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr "åå‰ç©ºé–“ã¯ç¾åœ¨ã€åå‰ç©ºé–“ストレージã®%{strong_start}%{used_storage}%{strong_end}を使用ã—ã¦ã„ã¾ã™ã€‚%{strong_start}%{usage_quotas_nav_instruction}%{strong_end}ã®ä½¿ç”¨çŠ¶æ³ã‚’表示ãŠã‚ˆã³ç®¡ç†ã—ã¾ã™ã€‚ストレージを削減ã™ã‚‹æ–¹æ³•ã®%{docs_link_start}詳細ã«ã¤ã„ã¦%{link_end}ã¯ã“ã¡ã‚‰ã‚’ã”覧ãã ã•ã„。"
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr "下ã®è¡¨ã¯%{usageSince}以é™ã®ä½¿ç”¨çŠ¶æ³ã‚’示ã—ã¦ã„ã¾ã™"
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr "ã“ã®åå‰ç©ºé–“ã«ã¯ %{planLimit} ã®ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ãŒã‚ã‚Šã¾ã™ã€‚ %{linkStart}制é™ã¯ã©ã®ã‚ˆã†ã«é©ç”¨ã•ã‚Œã¾ã™ã‹ï¼Ÿ%{linkEnd}"
@@ -50283,7 +50581,7 @@ msgid "UsageQuota|Usage of resources across your projects"
msgstr "プロジェクト全体ã®ãƒªã‚½ãƒ¼ã‚¹ã®ä½¿ç”¨çŠ¶æ³"
msgid "UsageQuota|User settings %{gt} Usage quotas"
-msgstr ""
+msgstr "ユーザー設定 %{gt} 使用クォータ"
msgid "UsageQuota|Wiki content."
msgstr "Wiki ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„。"
@@ -50895,6 +51193,9 @@ msgstr "ãã®ãƒ¦ãƒ¼ã‚¶ãƒ¼åã¯ä½¿ç”¨å¯èƒ½ã§ã™ã€‚"
msgid "Username or email"
msgstr "ユーザーåã¾ãŸã¯ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "ユーザå:"
@@ -51022,25 +51323,25 @@ msgid "Validations failed."
msgstr "検証ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
msgid "Validation|can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"
-msgstr ""
+msgstr "å°æ–‡å­—ã€æ•°å­—ã€'_' ãŠã‚ˆã³ '-' ã®ã¿ã‚’å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚文字ã§å§‹ã¾ã‚‹å¿…è¦ãŒã‚ã‚Šã€'-' ã¾ãŸã¯ '_' ã§çµ‚ã‚ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
msgid "Validation|groupId parameter is invalid"
-msgstr ""
+msgstr "グループIDパラメータãŒç„¡åŠ¹ã§ã™"
msgid "Validation|must belong to the same project"
-msgstr ""
+msgstr "åŒã˜ãƒ—ロジェクトã«å±žã—ã¦ã„ã¾ã›ã‚“。"
msgid "Validation|parameters are invalid"
-msgstr ""
+msgstr "パラメータãŒç„¡åŠ¹ã§ã™"
msgid "Validation|percentage must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "パーセント㯠0 ã‹ã‚‰ 100 ã¾ã§ã®æ–‡å­—列ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
msgid "Validation|rollout must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "ロールアウト㯠0 ã‹ã‚‰ 100 ã¾ã§ã®æ–‡å­—列ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
msgid "Validation|strategy name is invalid"
-msgstr ""
+msgstr "ストラテジーåãŒç„¡åŠ¹ã§ã™"
msgid "Value"
msgstr "値"
@@ -51244,7 +51545,7 @@ msgid "VerificationReminder|You’ll now be able to take advantage of free compu
msgstr "ã“ã‚Œã§ã€å…±æœ‰ãƒ©ãƒ³ãƒŠãƒ¼ã§ç„¡æ–™ã®ã‚³ãƒ³ãƒ”ューティング時間を利用ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚"
msgid "Verifications status"
-msgstr ""
+msgstr "検証ステータス"
msgid "Verified"
msgstr "検証済ã¿"
@@ -51456,7 +51757,7 @@ msgid "View the latest successful deployment to this environment"
msgstr "ã“ã®ç’°å¢ƒã¸ã®æœ€æ–°ã®æˆåŠŸã—ãŸãƒ‡ãƒ—ロイメントを表示ã™ã‚‹"
msgid "View trigger token usage examples"
-msgstr ""
+msgstr "トリガトークンã®ä½¿ç”¨ä¾‹ã‚’表示"
msgid "View usage details"
msgstr "使用状æ³ã®è©³ç´°ã‚’表示"
@@ -51596,6 +51897,9 @@ msgstr "詳細"
msgid "VulnerabilityExport|Detected At"
msgstr "検出日時"
+msgid "VulnerabilityExport|Full Path"
+msgstr "フルパス"
+
msgid "VulnerabilityExport|Group Name"
msgstr "グループå"
@@ -51623,17 +51927,20 @@ msgstr "ツール"
msgid "VulnerabilityExport|Vulnerability"
msgstr "脆弱性"
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{user}ãŒ%{timeago}å‰ã«%{statusStart}承èª%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{user}ã«ã‚ˆã‚Š%{timeago}å‰ã«%{statusStart}確èªã•ã‚Œã¾ã—ãŸ%{statusEnd}"
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "パイプラインã®%{pipelineLink}ã§%{timeago}å‰ã«%{statusStart}検出%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr "パイプライン%{pipelineLink}ã§%{timeago}å‰ã«%{statusStart}検出ã•ã‚Œã¾ã—ãŸ%{statusEnd}"
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{user}ãŒ%{timeago}å‰ã«%{statusStart}å´ä¸‹%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{user}ã«ã‚ˆã‚Š%{timeago}å‰ã«%{statusStart}å´ä¸‹ã•ã‚Œã¾ã—ãŸ%{statusEnd}"
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "%{user}ãŒ%{timeago}å‰ã«%{statusStart}解決%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr "%{user}ã«ã‚ˆã‚Š%{dismissalReason} %{timeago}å‰ã«%{statusStart}å´ä¸‹ã•ã‚Œã¾ã—ãŸ%{statusEnd}"
+
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{user}ã«ã‚ˆã‚Š%{timeago}å‰ã«%{statusStart}解決ã•ã‚Œã¾ã—ãŸ%{statusEnd} "
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr "(オプション)利用å¯èƒ½ãªå ´åˆã¯ã€è„†å¼±æ€§ã®è§£æ±ºç­–ã‚’å«ã‚ã¾ã™ã€‚"
@@ -51768,7 +52075,7 @@ msgid "VulnerabilityStatusTypes|Resolved"
msgstr "解決済ã¿"
msgid "Vulnerability|%{file} was not found in commit %{ref}"
-msgstr ""
+msgstr "コミット %{ref}ã®ä¸­ã«%{file} ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %{scannerVersion})"
@@ -51875,6 +52182,9 @@ msgstr "ファイル:"
msgid "Vulnerability|GitLab Security Report"
msgstr "GitLabセキュリティレãƒãƒ¼ãƒˆ"
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr "GitLabã¯ã€AIプロンプトã®ã‚³ãƒ¼ãƒ‰ã‚¹ãƒ‹ãƒšãƒƒãƒˆå†…ã®æ©Ÿå¯†æ–‡å­—列を特定ã—ã€æ¼æ´©ã—ãŸå¯èƒ½æ€§ã®ã‚るシークレットを示ã—ã¾ã™ã€‚ã“ã®è„†å¼±æ€§ã‚’説明ã™ã‚‹æ©Ÿèƒ½ã‚’利用るå‰ã«ã€ã‚³ãƒ¼ãƒ‰ã‚’確èªã—ã¦ãã ã•ã„。 ãã‚Œã§ã‚‚続行ã—ã¦AIã«%{linkStart}コード%{linkEnd}ã‚’é€ä¿¡ã™ã‚‹å ´åˆã¯ã€ä»¥ä¸‹ã®ãƒã‚§ãƒƒã‚¯ãƒœãƒƒã‚¯ã‚¹ã‚’クリックã—ã¦ãã ã•ã„。"
+
msgid "Vulnerability|Hide prompt"
msgstr "プロンプトを隠ã™"
@@ -51972,7 +52282,7 @@ msgid "Vulnerability|Show prompt"
msgstr "プロンプトを表示"
msgid "Vulnerability|Something went wrong while trying to get the source file."
-msgstr ""
+msgstr "ソースファイルã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "Vulnerability|Stacktrace snippet:"
msgstr "Stacktrace スニペット:"
@@ -51989,11 +52299,8 @@ msgstr "スキャナーã«ã‚ˆã£ã¦ã€ã“ã®è„†å¼±æ€§ã¯å½é™½æ€§ã¨åˆ¤å®šã•ã‚Œ
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr "変更ã•ã‚Œã¦ã„ãªã„レスãƒãƒ³ã‚¹ã¯ã€ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«å¯¾ã—ã¦å¤‰æ›´ãŒè¡Œã‚ã‚Œã¦ã„ãªã„å…ƒã®ãƒ¬ã‚¹ãƒãƒ³ã‚¹ã§ã™ã€‚"
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr "予期ã—ãªã„エラーãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚%{linkStart}ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。%{linkEnd}"
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
-msgstr "ã“ã‚Œã¯ã€AIを使用ã—ã¦è„†å¼±æ€§ã‚’説明ã—ã€æŽ¨å¥¨äº‹é …ã‚’æä¾›ã™ã‚‹å®Ÿé¨“çš„ãªæ©Ÿèƒ½ã§ã™ã€‚イテレーションを継続ã—ã¦è¡Œã£ã¦ã„ããŸã‚ã€ã“ã®æ©Ÿèƒ½ã¯æ³¨æ„ã—ã¦ä½¿ç”¨ã—ã¦ãã ã•ã„。%{linkStart}ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼%{linkEnd}ã«é–¢ã™ã‚‹ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã¨ã‚¢ã‚¤ãƒ‡ã‚¢ã‚’ãŠå¯„ã›ãã ã•ã„。"
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgstr "ã“ã‚Œã¯ã€AIを使用ã—ã¦è„†å¼±æ€§ã‚’説明ã—ã€æŽ¨å¥¨äº‹é …ã‚’æä¾›ã™ã‚‹ãƒ™ãƒ¼ã‚¿æ©Ÿèƒ½ã§ã™ã€‚イテレーションを継続ã—ã¦è¡Œã£ã¦ã„ããŸã‚ã€ã“ã®æ©Ÿèƒ½ã¯æ³¨æ„ã—ã¦ä½¿ç”¨ã—ã¦ãã ã•ã„。%{linkStart}ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼%{linkEnd}ã«é–¢ã™ã‚‹ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã¨ã‚¢ã‚¤ãƒ‡ã‚¢ã‚’ãŠå¯„ã›ãã ã•ã„。"
msgid "Vulnerability|Tool"
msgstr "ツール"
@@ -52028,6 +52335,9 @@ msgstr "脆弱クラス:"
msgid "Vulnerability|Vulnerable method:"
msgstr "脆弱メソッド:"
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr "警告: 機密情報ãŒæ¤œå‡ºã•ã‚ŒãŸå¯èƒ½æ€§ã‚ã‚Š"
+
msgid "WARNING:"
msgstr "警告:"
@@ -52355,6 +52665,12 @@ msgstr "%{REGEX_CODE}ãªã©ã®æ­£è¦è¡¨ç¾ãŒã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã™ã€‚"
msgid "Webhooks|Releases events"
msgstr "リリースイベント"
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr "SSL検証"
@@ -52457,15 +52773,6 @@ msgstr "æ–°ã—ã„ナビゲーション体験ã¸ã‚ˆã†ã“ã"
msgid "Welcome, %{name}!"
msgstr "%{name}ã•ã‚“ã€ã‚ˆã†ã“ã!"
-msgid "What are group audit events?"
-msgstr "グループ監査イベントã¨ã¯ä½•ã§ã™ã‹?"
-
-msgid "What are instance audit events?"
-msgstr "インスタンス監査イベントã¨ã¯ä½•ã§ã™ã‹?"
-
-msgid "What are project audit events?"
-msgstr "プロジェクト監査イベントã¨ã¯ä½•ã§ã™ã‹?"
-
msgid "What are some examples?"
msgstr "例ã¨ã—ã¦ã¯ã©ã®ã‚ˆã†ãªã‚‚ã®ãŒã‚ã‚Šã¾ã™ã‹ ?"
@@ -52817,6 +53124,12 @@ msgstr "作業中ã®ä¸Šé™"
msgid "Work item promoted successfully."
msgstr "作業アイテムã¯æ­£å¸¸ã«ãƒ—ロモートã•ã‚Œã¾ã—ãŸã€‚"
+msgid "Work items are already linked"
+msgstr "作業アイテムã¯ã™ã§ã«ãƒªãƒ³ã‚¯ã•ã‚Œã¦ã„ã¾ã™"
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr "ãã®ä»–%{count}人ã®æ‹…当者"
@@ -52908,9 +53221,6 @@ msgstr "%{workItemType}ã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’コピー"
msgid "WorkItem|Create %{workItemType}"
msgstr "%{workItemType}を作æˆ"
-msgid "WorkItem|Create objective"
-msgstr "目標を作æˆ"
-
msgid "WorkItem|Create work item"
msgstr "作業アイテムを作æˆ"
@@ -52929,9 +53239,6 @@ msgstr "期é™"
msgid "WorkItem|Existing task"
msgstr "既存ã®ã‚¿ã‚¹ã‚¯"
-msgid "WorkItem|Health status"
-msgstr "å¥å…¨æ€§ã®çŠ¶æ…‹"
-
msgid "WorkItem|History only"
msgstr "履歴ã®ã¿"
@@ -52948,6 +53255,12 @@ msgid "WorkItem|Key Result"
msgstr "主ãªçµæžœ"
msgid "WorkItem|Key result"
+msgstr "主ãªçµæžœ"
+
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
msgstr ""
msgid "WorkItem|Mark as done"
@@ -52956,8 +53269,8 @@ msgstr "完了ã¨ã—ã¦ãƒžãƒ¼ã‚¯"
msgid "WorkItem|Milestone"
msgstr "マイルストーン"
-msgid "WorkItem|New objective"
-msgstr "æ–°ã—ã„目標"
+msgid "WorkItem|New %{workItemType}"
+msgstr "æ–°è¦%{workItemType}"
msgid "WorkItem|New task"
msgstr "æ–°è¦ã‚¿ã‚¹ã‚¯"
@@ -53041,7 +53354,7 @@ msgid "WorkItem|Something went wrong when fetching work item types. Please try a
msgstr "作業アイテムã®ç¨®é¡žã‚’å–å¾—ã™ã‚‹ã¨ãã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
msgid "WorkItem|Something went wrong when fetching work items. Please try again."
-msgstr ""
+msgstr "作業アイテムをå–å¾—ã™ã‚‹ã¨ãã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
msgid "WorkItem|Something went wrong when trying to add a child. Please try again."
msgstr "å­ã‚’追加ã™ã‚‹ã¨ãã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -53100,9 +53413,6 @@ msgstr "テストケース"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr "ã“ã®%{workItemType}ã¯æ©Ÿå¯†ã§ã‚ã‚Šã€ãƒ¬ãƒãƒ¼ã‚¿ãƒ¼ä»¥ä¸Šã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’æŒã¤ãƒãƒ¼ãƒ ãƒ¡ãƒ³ãƒãƒ¼ã«ã—ã‹è¡¨ç¤ºã•ã‚Œã¾ã›ã‚“"
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr "ã“ã®ç›®æ¨™ã¯æ©Ÿå¯†ã§ã‚ã‚Šã€ãƒ¬ãƒãƒ¼ã‚¿ãƒ¼ä»¥ä¸Šã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’æŒã¤ãƒãƒ¼ãƒ ãƒ¡ãƒ³ãƒãƒ¼ã«ã—ã‹è¡¨ç¤ºã•ã‚Œã¾ã›ã‚“"
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr "ã“ã®ä½œæ¥­é …ç›®ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“。存在ã—ãªã„ã‹ã€è¡¨ç¤ºã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。"
@@ -53133,8 +53443,8 @@ msgstr "フィードã«ã¯%{boldStart}ã»ã‹ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティ%{boldEnd}ã
msgid "Workspaces"
msgstr "ワークスペース"
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
-msgstr "ワークスペースã¯ã€GitLab内ã®ã‚³ãƒ¼ãƒ‰ã®ä»®æƒ³ã‚µãƒ³ãƒ‰ãƒœãƒƒã‚¯ã‚¹ç’°å¢ƒã§ã™ã€‚公開プロジェクト用ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã‚’作æˆã§ãã¾ã™ã€‚"
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
+msgstr ""
msgid "Workspaces|Cancel"
msgstr "キャンセル"
@@ -53232,9 +53542,6 @@ msgstr "ä¸æ˜ŽãªçŠ¶æ…‹"
msgid "Workspaces|Workspaces"
msgstr "ワークスペース"
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr "公開プロジェクト用ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã®ã¿ä½œæˆã§ãã¾ã™ã€‚"
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr "ã“ã®ãƒ—ロジェクト用ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã‚’作æˆã§ãã¾ã™"
@@ -53494,6 +53801,9 @@ msgstr "%{link}ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ã€æ–°ã—ã„パーソナルアクセストãƒ
msgid "You can create a new SSH key by visiting %{link}"
msgstr "%{link}ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ã€æ–°ã—ã„SSHキーを作æˆã§ãã¾ã™"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr "%{pat_link_start}パーソナルアクセストークン%{pat_link_end}ã®è¨­å®šã§ã€æ–°è¦ã«ä½œæˆã—ãŸã‚Šã€ç¢ºèªã—ãŸã‚Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
@@ -53503,6 +53813,9 @@ msgstr "%{ssh_key_link_start}SSHキー%{ssh_key_link_end}ã®è¨­å®šã§æ–°è¦ã«ä½
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr "SSHキーã®è¨­å®š%{ssh_key_link}ã§æ–°è¦ã«ä½œæˆã™ã‚‹ã‹ç¢ºèªã§ãã¾ã™ã€‚"
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr "パーソナルアクセストークンã®è¨­å®š %{pat_link} ã§ã€æ–°è¦ã«ä½œæˆã—ãŸã‚Šã€ç¢ºèªã—ãŸã‚Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
@@ -53701,9 +54014,6 @@ msgstr "アプリケーションãŒã‚ã‚Šã¾ã›ã‚“."
msgid "You don't have any authorized applications."
msgstr "承èªã•ã‚ŒãŸã‚¢ãƒ—リケーションãŒã‚ã‚Šã¾ã›ã‚“."
-msgid "You don't have any deployments right now."
-msgstr "ç¾åœ¨ãƒ‡ãƒ—ロイãŒã‚ã‚Šã¾ã›ã‚“。"
-
msgid "You don't have any open merge requests"
msgstr "オープンã—ã¦ã„るマージリクエストã¯ã‚ã‚Šã¾ã›ã‚“"
@@ -53775,7 +54085,7 @@ msgid "You have insufficient permissions to create a Todo for this alert"
msgstr "ã“ã®ã‚¢ãƒ©ãƒ¼ãƒˆã®Todoを作æˆã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。"
msgid "You have insufficient permissions to create a target branch rule"
-msgstr ""
+msgstr "ターゲットブランãƒãƒ«ãƒ¼ãƒ«ã‚’作æˆã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“"
msgid "You have insufficient permissions to create an HTTP integration for this project"
msgstr "ã“ã®ãƒ—ロジェクトã®HTTPçµ±åˆã‚’作æˆã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“"
@@ -54085,7 +54395,7 @@ msgid "Your DevOps Reports give an overview of how you are using GitLab from a f
msgstr "DevOpsレãƒãƒ¼ãƒˆã§ã¯ã€æ©Ÿèƒ½ã®è¦³ç‚¹ã‹ã‚‰GitLabã‚’ã©ã®ã‚ˆã†ã«ä½¿ç”¨ã—ã¦ã„ã‚‹ã‹ã®æ¦‚è¦ã‚’説明ã—ã¾ã™ã€‚ãれらを使用ã—ã¦ã€ã»ã‹ã®çµ„ç¹”ã¨ã®æ¯”較方法ã€ãŠã‚ˆã³ãƒãƒ¼ãƒ é–“ã®æ¯”較方法を表示ã§ãã¾ã™ã€‚"
msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. To ensure that your group does not become read-only, you should contact a user with the Owner role for this group to upgrade to a paid tier, or manage your usage. For more information about the upcoming usage limits, see our %{faq_link_start}FAQ%{link_end}."
-msgstr "ç„¡æ–™ã®ãƒˆãƒƒãƒ—レベルグループã®%{group_name}ã«ã¯%{free_users_limit}人以上ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒã„ã¦ã€%{free_storage_limit}より多ãã®ãƒ‡ãƒ¼ã‚¿ã‚’使用ã—ã¦ã„ã¾ã™ã€‚ç„¡æ–™ã®ãƒˆãƒƒãƒ—レベルグループã«ä½¿ç”¨åˆ¶é™ãŒé©ç”¨ã•ã‚Œã‚‹ã¨ã€ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—内ã®ãƒ—ロジェクトã¯%{read_only_link_start}読ã¿å–り専用ã«ãªã‚Šã¾ã™%{link_end}。グループãŒèª­ã¿å–り専用ã«ãªã‚‰ãªã„よã†ã«ã™ã‚‹ã«ã¯ã€ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ã‚ªãƒ¼ãƒŠãƒ¼ãƒ­ãƒ¼ãƒ«ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€£çµ¡ã—ã¦ã€æœ‰æ–™ãƒ—ランã«ã‚¢ãƒƒãƒ—グレードã™ã‚‹ã‹ã€ä½¿ç”¨é‡ã‚’管ç†ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚今後ã®ä½¿ç”¨åˆ¶é™ã®è©³ç´°ã«ã¤ã„ã¦ã¯ã€%{faq_link_start}FAQã‚’å‚ç…§ã—ã¦ãã ã•ã„%{link_end} 。"
+msgstr "ç„¡æ–™ã®ãƒˆãƒƒãƒ—レベルグループã®%%{group_name}ã«ã¯%%{free_users_limit}人以上ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒã„ã¦ã€%%{free_storage_limit}より多ãã®ãƒ‡ãƒ¼ã‚¿ã‚’使用ã—ã¦ã„ã¾ã™ã€‚ç„¡æ–™ã®ãƒˆãƒƒãƒ—レベルグループã«ä½¿ç”¨åˆ¶é™ãŒé©ç”¨ã•ã‚Œã‚‹ã¨ã€ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—内ã®ãƒ—ロジェクトã¯%%{read_only_link_start}読ã¿å–り専用ã«ãªã‚Šã¾ã™%%{link_end}。グループãŒèª­ã¿å–り専用ã«ãªã‚‰ãªã„よã†ã«ã™ã‚‹ã«ã¯ã€ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ã‚ªãƒ¼ãƒŠãƒ¼ãƒ­ãƒ¼ãƒ«ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€£çµ¡ã—ã¦ã€æœ‰æ–™ãƒ—ランã«ã‚¢ãƒƒãƒ—グレードã™ã‚‹ã‹ã€ä½¿ç”¨é‡ã‚’管ç†ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚今後ã®ä½¿ç”¨åˆ¶é™ã®è©³ç´°ã«ã¤ã„ã¦ã¯ã€%%{faq_link_start}FAQã‚’å‚ç…§ã—ã¦ãã ã•ã„%%{link_end} 。"
msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. You should reduce the number of users or upgrade to a paid tier %{strong_start}before%{strong_end} you manage your storage usage. Otherwise, your Free top-level group will become read-only immediately because the 5-user limit applies. For more information, see our %{faq_link_start}FAQ%{link_end}.%{br_tag}%{br_tag}To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr "アプリケーション"
msgid "Your authorized applications"
msgstr "承èªã•ã‚ŒãŸã‚¢ãƒ—リケーション"
-msgid "Your browser does not support iFrames"
-msgstr "ãŠä½¿ã„ã®ãƒ–ラウザー㯠iframe をサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr "ãŠä½¿ã„ã®ãƒ–ラウザã¯WebAuthnをサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。例ãˆã°Chrome (v67以é™)ã‚„Firefox(v60以é™)ãªã©ã®å¯¾å¿œã—ã¦ã„るブラウザを使用ã—ã¦ãã ã•ã„。"
@@ -54319,9 +54626,6 @@ msgstr "パーソナルアクセストークンã¯%{days_to_expire}æ—¥ã§æœ‰åŠ¹æ
msgid "Your profile"
msgstr "自分ã®ãƒ—ロフィール"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr "ã‚ãªãŸã®ãƒ—ロジェクトã¯ã€2022-07-01ã®æ™‚点ã§GitLab Ultimateã®ç‰¹å…¸ã‚’å—ã‘られãªããªã‚Šã¾ã—ãŸã€‚以å‰ã«ã‚¢ãƒ—リ内ã§ã‚‚通知ã—ãŸã‚ˆã†ã«ã€ç„¡æ–™ãƒ—ランã®ãƒ‘ブリックオープンソースプロジェクトã¯ã€GitLab for Open Source Programã«ç”³è«‹ã—ã¦GitLab Ultimateã®ç‰¹å…¸ã‚’å—ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚詳細ã«ã¤ã„ã¦ã¯ã€%{faq_link_start}FAQ%{link_end}ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "ã‚ãªãŸã®ãƒ—ロジェクト数㯠%{limit} 以下ã«åˆ¶é™ã•ã‚Œã¦ã„ã¾ã™ã€‚ã“ã®ä¸Šé™ã‚’増やã™ã«ã¯ã‚ãªãŸã®ç®¡ç†è€…ã«é€£çµ¡ã—ã¦ãã ã•ã„"
@@ -54346,6 +54650,9 @@ msgstr "ã‚ãªãŸã®è¦æ±‚時効ã¯ã‚¤ãƒ³ãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã™ã€‚終了ã™
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr "ã‚ãªãŸã®è¦æ±‚事項ã¯ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰å‡¦ç†ã§ã‚¤ãƒ³ãƒãƒ¼ãƒˆã•ã‚Œã¾ã™ã€‚終了後ã«ã€ç¢ºèªãƒ¡ãƒ¼ãƒ«ãŒå±Šãã¾ã™ã€‚"
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr "ã©ã®ã‚³ãƒŸãƒƒãƒˆã«ã‚‚一致ã—ã¾ã›ã‚“ã§ã—ãŸã€‚"
@@ -54513,6 +54820,9 @@ msgstr "ã™ã¹ã¦ã®ä¿è­·ã•ã‚ŒãŸãƒ–ランãƒ"
msgid "allowed to fail"
msgstr "失敗å¯èƒ½"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr "æ—¢ã«åå‰ç©ºé–“ã‹ã‚‰BANã•ã‚Œã¦ã„ã¾ã™"
@@ -54620,6 +54930,9 @@ msgstr "%{new_type}ã«ã¯å¤‰æ›´ã§ãã¾ã›ã‚“"
msgid "can not be changed when assigned to an epic"
msgstr "エピックã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸã¨ãã«å¤‰æ›´ã§ãã¾ã›ã‚“"
+msgid "can not be set for template labels"
+msgstr "テンプレートラベルã«è¨­å®šã§ãã¾ã›ã‚“"
+
msgid "can not be set for this resource"
msgstr "ã“ã®ãƒªã‚½ãƒ¼ã‚¹ã«ã¯è¨­å®šã§ãã¾ã›ã‚“"
@@ -55123,11 +55436,14 @@ msgid "created %{timeAgo} by %{author} in %{project_link}"
msgstr "%{project_link}ã§%{author}ã«ã‚ˆã£ã¦%{timeAgo}ã«ä½œæˆã•ã‚Œã¾ã—ãŸ"
msgid "created %{timeAgo} by %{email} via %{author}"
-msgstr ""
+msgstr "%{author}ãŒ%{email}ã§%{timeAgo}ã«ä½œæˆ"
msgid "created by"
msgstr "作æˆè€…:"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr "毎日"
@@ -55193,6 +55509,9 @@ msgstr "例: %{token}"
msgid "eg party_tanuki"
msgstr "例 party_tanuki"
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr "è¦ç´ ã¯éšŽå±¤ã§ã¯ã‚ã‚Šã¾ã›ã‚“"
@@ -55278,9 +55597,6 @@ msgstr[0] "ファイル"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "発見ã•ã‚Œãªã„ã‹ã€ã™ã§ã«è„†å¼±æ€§ã«é–¢é€£ä»˜ã‘られã¦ã„ã¾ã™"
-msgid "for Workspace is required to be public"
-msgstr "ワークスペースã¯å…¬é–‹ã•ã‚Œã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚‹ãŸã‚"
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr "ワークスペースã«ã¯RemoteDevelopmentAgentConfigãŒé–¢é€£ä»˜ã‘られã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚‹ãŸã‚"
@@ -55540,6 +55856,9 @@ msgstr "大ãã™ãŽã§ã™"
msgid "jigsaw is not defined"
msgstr "jigsaw ãŒæœªå®šç¾©ã§ã™"
+msgid "key result"
+msgstr "主ãªçµæžœ"
+
msgid "kuromoji custom analyzer"
msgstr "kuromojiカスタムアナライザー"
@@ -55975,7 +56294,7 @@ msgid "must be a valid syntax highlighting theme ID"
msgstr "テーマIDã‚’ãƒã‚¤ãƒ©ã‚¤ãƒˆã—ã¦ã„る有効ãªæ§‹æ–‡ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
msgid "must be a value between 0 and 1"
-msgstr ""
+msgstr "0 ã¨1 ã®é–“ã®å€¤ã§ã‚ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "must be after start"
msgstr "開始後ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
@@ -56010,6 +56329,9 @@ msgstr "フォークãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯å†…ã«ã‚ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™"
msgid "must be less than the limit of %{tag_limit} tags"
msgstr "%{tag_limit}ã‚¿ã‚°ã®ä¸Šé™ã‚ˆã‚Šã‚‚å°ã•ããªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+msgid "must be owned by the user's enterprise group"
+msgstr "ユーザーã®ã‚¨ãƒ³ã‚¿ãƒ¼ãƒ—ライズグループãŒæ‰€æœ‰ã—ã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™"
+
msgid "must be set for a project namespace"
msgstr "プロジェクトåå‰ç©ºé–“ã«è¨­å®šã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
@@ -56019,6 +56341,9 @@ msgstr "指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™"
msgid "must be unique by status and elapsed time within a policy"
msgstr "ãƒãƒªã‚·ãƒ¼å†…ã®çŠ¶æ…‹ã¨çµŒéŽæ™‚é–“ã§ä¸€æ„ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr "一æ„ã§ã‚ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã“ã® CA ã¯æ—¢ã«åˆ¥ã®åå‰ç©ºé–“用ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ã€‚"
+
msgid "must belong to same project of its requirement object."
msgstr "è¦æ±‚オブジェクトã¨åŒã˜ãƒ—ロジェクトã«å±žã—ã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -56046,6 +56371,9 @@ msgstr "åå‰ç©ºé–“ã®ã‚ªãƒ¼ãƒŠãƒ¼ã§ã‚ã£ã¦ã¯ãªã‚Šã¾ã›ã‚“"
msgid "must not contain commonly used combinations of words and letters"
msgstr "一般的ã«ä½¿ç”¨ã•ã‚Œã‚‹å˜èªžã¨æ–‡å­—ã®çµ„ã¿åˆã‚ã›ã‚’å«ã‚ã¦ã¯ã„ã‘ã¾ã›ã‚“"
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr "ç§ã®ç´ æ™´ã‚‰ã—ã„グループ"
@@ -56103,6 +56431,9 @@ msgstr "%{item}ã€%{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}ã¨%{lastItem}"
+msgid "objective"
+msgstr "目標"
+
msgid "on or after"
msgstr "以後"
@@ -56396,6 +56727,9 @@ msgstr "%{slash_command}ã¯ã™ã§ã«è²»ã‚„ã•ã‚ŒãŸæ™‚間を加算ã¾ãŸã¯æ¸›ç®
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "㌠%{design_link} ã§ãƒ‡ã‚£ã‚¹ã‚«ãƒƒã‚·ãƒ§ãƒ³ã‚’始ã‚ã¾ã—ãŸ"
@@ -56438,6 +56772,9 @@ msgstr "ã‚¿ã‚°å"
msgid "targeting "
msgstr "ターゲティング"
+msgid "task"
+msgstr "タスク"
+
msgid "terraform states"
msgstr "terraformã®çŠ¶æ…‹"
@@ -56486,9 +56823,6 @@ msgstr "åˆè¨ˆã¯%{size}以下ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
msgid "triggered"
msgstr "トリガーã•ã‚ŒãŸ"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr "コミット%{linkStart}%{shortId}%{linkEnd}ã®ãŸã‚ã«ãƒˆãƒªã‚¬ãƒ¼ã•ã‚ŒãŸãƒ‘イプライン"
-
msgid "two-factor authentication settings"
msgstr "二è¦ç´ èªè¨¼ã®è¨­å®š"
@@ -56544,6 +56878,9 @@ msgstr "レãƒãƒ¼ãƒˆã‚¿ã‚¤ãƒ—%{report_type}ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³%{report_version}ã
msgid "version %{versionIndex}"
msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "%{closed_via} ã«ã‚ˆã‚Š"
diff --git a/locale/ka_GE/gitlab.po b/locale/ka_GE/gitlab.po
index da2221c8b50..241bd7ae21c 100644
--- a/locale/ka_GE/gitlab.po
+++ b/locale/ka_GE/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ka\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/kab/gitlab.po b/locale/kab/gitlab.po
index 5ea04ae65f7..98b95966340 100644
--- a/locale/kab/gitlab.po
+++ b/locale/kab/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: kab\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:37\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index bb2f7aab48c..fe6713026fa 100644
--- a/locale/ko/gitlab.po
+++ b/locale/ko/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ko\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr " %{start}부터 %{end}까지"
@@ -44,6 +44,10 @@ msgstr " 그리고 "
msgid " and %{sliced}"
msgstr " 그리고 %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] "제외 브랜치:"
+
msgid " or "
msgstr " ë˜ëŠ” "
@@ -60,7 +64,7 @@ msgid " or %{emphasisStart}&epic id%{emphasisEnd}"
msgstr " ë˜ëŠ” %{emphasisStart}&ì—픽 id%{emphasisEnd}"
msgid " or references"
-msgstr ""
+msgstr " ë˜ëŠ” 참조"
msgid " reacted with :%{name}:"
msgstr " :%{name}: ë¡œ ë°˜ì‘했습니다."
@@ -72,7 +76,7 @@ msgid "\"%{repository_name}\" size (%{repository_size}) is larger than the limit
msgstr "\"%{repository_name}\"ì˜ í¬ê¸° %{repository_size}는 최대 ì œí•œì¸ %{limit}보다 í½ë‹ˆë‹¤."
msgid "### Rich text editor"
-msgstr ""
+msgstr "### 리치 í…스트 편집기"
msgid "##### ERROR ##### You have used %{usage_percentage} of the storage quota for %{namespace_name} (%{current_size} of %{size_limit}). %{namespace_name} is now read-only. Projects under this namespace are locked and actions will be restricted. To manage storage, or purchase additional storage, see %{manage_storage_url}. To learn more about restricted actions, see %{restricted_actions_url}"
msgstr ""
@@ -400,22 +404,22 @@ msgstr[0] "%dê°œì˜ ê²½ê³  발견:"
msgid "%d week"
msgid_plural "%d weeks"
-msgstr[0] ""
+msgstr[0] "%d 주"
msgid "%d work item"
msgid_plural "%d work items"
-msgstr[0] ""
+msgstr[0] "%dê°œì˜ ìž‘ì—… 항목"
msgid "%d year"
msgid_plural "%d years"
-msgstr[0] ""
+msgstr[0] "%d ë…„"
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s 추가 ì»¤ë°‹ì€ ì„±ëŠ¥ ì´ìŠˆë¥¼ 방지하기 위해 ìƒëžµë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "%{actionText} %{actionDetail}"
-msgstr ""
+msgstr "%{actionText} %{actionDetail}"
msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
msgstr ""
@@ -484,7 +488,7 @@ msgid "%{commit_author_link} authored %{commit_authored_timeago} and %{commit_co
msgstr "%{commit_author_link}ê°€ %{commit_authored_timeago}ì— ìž‘ì„±í•˜ê³  %{commit_committer_avatar} %{commit_committer_link}ê°€ %{commit_committer_timeago}ì— ì»¤ë°‹í•¨"
msgid "%{completedCount} completed weight"
-msgstr ""
+msgstr "%{completedCount}ê°œì˜ ì™„ë£Œëœ ê°€ì¤‘ì¹˜"
msgid "%{completedCount} of %{count} checklist item completed"
msgid_plural "%{completedCount} of %{count} checklist items completed"
@@ -497,7 +501,7 @@ msgid "%{completed} of %{total} issues closed"
msgstr "%{total}중 %{completed}ê°œì˜ ì´ìŠˆ 닫힘"
msgid "%{completed} of %{total} weight completed"
-msgstr ""
+msgstr "가중치 %{total} 중 %{completed} 작업 완료"
msgid "%{cores} cores"
msgstr "%{cores} 코어"
@@ -510,7 +514,7 @@ msgstr "%{count}ê°œì˜ LOC ë˜ëŠ” 커밋"
msgid "%{count} Participant"
msgid_plural "%{count} Participants"
-msgstr[0] ""
+msgstr[0] "%{count}ëª…ì˜ ì°¸ê°€ìž"
msgid "%{count} approval required from %{name}"
msgid_plural "%{count} approvals required from %{name}"
@@ -528,7 +532,7 @@ msgstr "%{count} 파ì¼ì´ 변경ë˜ì—ˆìŠµë‹ˆë‹¤"
msgid "%{count} group"
msgid_plural "%{count} groups"
-msgstr[0] ""
+msgstr[0] "%{count}ê°œì˜ ê·¸ë£¹"
msgid "%{count} issue"
msgid_plural "%{count} issues"
@@ -563,19 +567,16 @@ msgstr "%{total} 중 %{count}"
msgid "%{count} project"
msgid_plural "%{count} projects"
-msgstr[0] ""
+msgstr[0] "%{count} ê°œì˜ í”„ë¡œì íŠ¸"
msgid "%{count} selected"
msgstr "%{count}ê°œ ì„ íƒë¨"
msgid "%{count} tags"
-msgstr ""
+msgstr "%{count}ê°œì˜ íƒœê·¸"
msgid "%{count} total weight"
-msgstr ""
-
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path}(ì„)를 ì°¾ì„ ìˆ˜ 없습니다."
+msgstr "%{count} ì´ ê°€ì¤‘ì¹˜"
msgid "%{days} days until tags are automatically removed"
msgstr "태그가 ìžë™ìœ¼ë¡œ 제거 ë  ë•Œê¹Œì§€ %{days}ì¼"
@@ -622,7 +623,7 @@ msgstr "%{edit_in_new_fork_notice} 파ì¼ì„ 다시 업로드하십시오."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -677,10 +678,10 @@ msgid "%{integrations_link_start}Integrations%{link_end} enable you to make thir
msgstr ""
msgid "%{issuableDisplayName} locked."
-msgstr ""
+msgstr "%{issuableDisplayName} 잠금."
msgid "%{issuableDisplayName} unlocked."
-msgstr ""
+msgstr "%{issuableDisplayName} 잠금해제."
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType}ì´ ì‚­ì œë©ë‹ˆë‹¤! 확실합니까?"
@@ -700,6 +701,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}새로운 기능%{italic_end} 메뉴는 비활성화ë˜ì–´ ë³¼ 수 없습니다."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -775,6 +782,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} 사용할 수 ì—†ìŒ"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -818,7 +828,7 @@ msgid "%{milliseconds}ms"
msgstr "%{milliseconds}ms"
msgid "%{minutesUsed} units"
-msgstr ""
+msgstr "%{minutesUsed} 단위"
msgid "%{model_name} not found"
msgstr "%{model_name} ì°¾ì„ ìˆ˜ ì—†ìŒ"
@@ -921,10 +931,10 @@ msgid "%{ref} cannot be added: %{error}"
msgstr "%{ref}(ì„)를 추가 í•  수 없습니다: %{error}"
msgid "%{relation_type} epic does not exist."
-msgstr ""
+msgstr "%{relation_type} ì—í”½ì´ ì¡´ìž¬í•˜ì§€ 않습니다."
msgid "%{relation_type} epic is not present."
-msgstr ""
+msgstr "%{relation_type} ì—í”½ì´ ì¡´ìž¬í•˜ì§€ 않습니다."
msgid "%{releases} release"
msgid_plural "%{releases} releases"
@@ -970,7 +980,7 @@ msgstr[0] ""
msgid "%{selectedLabelsCount} label"
msgid_plural "%{selectedLabelsCount} labels"
-msgstr[0] ""
+msgstr[0] "ë¼ë²¨ %{selectedLabelsCount} ê°œ"
msgid "%{selectedProjectsCount} project"
msgid_plural "%{selectedProjectsCount} projects"
@@ -1135,7 +1145,7 @@ msgid "%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)"
msgstr ""
msgid "%{totalWeight} total weight"
-msgstr ""
+msgstr "%{totalWeight}ê°œì˜ ì´ ê°€ì¤‘ì¹˜"
msgid "%{total_warnings} warning(s) found:"
msgstr "%{total_warnings}ê°œì˜ ê²½ê³  발견ë¨:"
@@ -1203,11 +1213,11 @@ msgstr "%{verb} %{time_spent_value} ì‹œê°„ì´ ì§€ë‚¬ìŠµë‹ˆë‹¤."
msgid "%{verb} this %{noun} as a draft."
msgstr "%{verb} ì´ %{noun} ì„ ì´ˆì•ˆìœ¼ë¡œ."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end}ì„ ì‚¬ìš©í•˜ë©´ 그룹 ë˜ëŠ” 프로ì íŠ¸ì˜ ì´ë²¤íŠ¸ì— 대한 ì‘답으로 웹 애플리케ì´ì…˜ì— ì•Œë¦¼ì„ ë³´ë‚¼ 수 있습니다. Webhook보다 %{integrations_link_start}통합%{link_end}ì„ ì‚¬ìš©í•˜ëŠ” ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr "%{widget} 옵션"
@@ -1259,7 +1269,7 @@ msgid "(No changes)"
msgstr "(변경사항 ì—†ìŒ)"
msgid "(Unlimited pipeline minutes)"
-msgstr ""
+msgstr "(무제한 파ì´í”„ë¼ì¸ 실행시간)"
msgid "(check progress)"
msgstr "(진행 ìƒí™© 확ì¸)"
@@ -1312,6 +1322,9 @@ msgstr "+ %{amount}ê°œ ë” ìžˆìŒ"
msgid "+ %{count} more"
msgstr "+ %{count} ë”보기"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} ë”"
@@ -1388,7 +1401,7 @@ msgid "- of - issues closed"
msgstr "-ê°œ 중 -ê°œì˜ ì´ìŠˆ 닫힘"
msgid "- of - weight completed"
-msgstr ""
+msgstr "- of - ë§Œí¼ ê°€ì¤‘ì¹˜ 완료"
msgid "- show less"
msgstr "-ëœ ë³´ê¸°"
@@ -1490,7 +1503,7 @@ msgstr[0] "%dê°œì˜ ì—­í• "
msgid "1 user"
msgid_plural "%d users"
-msgstr[0] ""
+msgstr[0] "ì‚¬ìš©ìž %d 명"
msgid "1 week remaining"
msgid_plural "%d weeks remaining"
@@ -1555,7 +1568,7 @@ msgid "409|Please contact your GitLab administrator if you think this is a mista
msgstr "ì´ê²ƒì´ 실수ë¼ê³  ìƒê°í•œë‹¤ë©´ GitLab 관리ìžì—게 문ì˜í•˜ì„¸ìš”."
msgid "409|There was a conflict with your request."
-msgstr ""
+msgstr "ê·€í•˜ì˜ ìš”ì²­ê³¼ 충ëŒì´ 있습니다."
msgid "8 hours"
msgstr "8 시간"
@@ -1702,7 +1715,7 @@ msgid "A project containing issues for each audit inquiry in the HIPAA Audit Pro
msgstr ""
msgid "A project’s repository name defines its URL (the one you use to access the project via a browser) and its place on the file disk where GitLab is installed. %{link_start}Learn more.%{link_end}"
-msgstr "프로ì íŠ¸ì˜ 저장소 ì´ë¦„ì€ URL(브ë¼ìš°ì €ë¥¼ 통해 프로ì íŠ¸ì— 액세스하는 ë° ì‚¬ìš©í•˜ëŠ” ì´ë¦„)ê³¼ GitLabì´ ì„¤ì¹˜ëœ íŒŒì¼ ë””ìŠ¤í¬ì˜ 위치를 ì •ì˜í•©ë‹ˆë‹¤. %{link_start}ë” ì•Œì•„ë³´ê¸°%{link_end}"
+msgstr "프로ì íŠ¸ì˜ 리í¬ì§€í† ë¦¬ ì´ë¦„ì€ URL(브ë¼ìš°ì €ë¥¼ 통해 프로ì íŠ¸ì— 액세스하는 ë° ì‚¬ìš©í•˜ëŠ” ì´ë¦„)ê³¼ GitLabì´ ì„¤ì¹˜ëœ íŒŒì¼ ë””ìŠ¤í¬ì˜ 위치를 ì •ì˜í•©ë‹ˆë‹¤. %{link_start}ë” ì•Œì•„ë³´ê¸°%{link_end}"
msgid "A quarterly reconciliation is due on %{date}"
msgstr ""
@@ -1738,7 +1751,7 @@ msgid "AI-generated summary"
msgstr "AI ìƒì„± 요약"
msgid "AISummary|Generates a summary of all comments"
-msgstr ""
+msgstr "모든 ëŒ“ê¸€ì˜ ìš”ì•½ì„ ìƒì„±í•©ë‹ˆë‹¤."
msgid "AISummary|View summary"
msgstr "요약 보기"
@@ -1755,18 +1768,27 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
-msgid "AI|Apply AI-generated description"
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
msgstr ""
+msgid "AI|Apply AI-generated description"
+msgstr "AI ìƒì„± 설명 ì ìš©"
+
+msgid "AI|Ask GitLab Duo"
+msgstr "GitLab Duoì—게 묻기"
+
msgid "AI|Ask a question"
msgstr "질문하기"
msgid "AI|Autocomplete"
msgstr "ìžë™ 완성"
-msgid "AI|Close the Code Explanation"
+msgid "AI|Can be removed at any time"
msgstr ""
+msgid "AI|Close the Code Explanation"
+msgstr "코드 설명 닫기"
+
msgid "AI|Code Explanation"
msgstr "코드 설명"
@@ -1783,7 +1805,7 @@ msgid "AI|Experiment"
msgstr ""
msgid "AI|Experiment features"
-msgstr ""
+msgstr "실험 기능"
msgid "AI|Explain the code from %{filePath} in human understandable language presented in Markdown format. In the response add neither original code snippet nor any title. `%{text}`. If it is not programming code, say `The selected text is not code. I am afraid this feature is for explaining code only. Would you like to ask a different question about the selected text?` and wait for another question."
msgstr ""
@@ -1792,7 +1814,7 @@ msgid "AI|Explain your rating (optional)"
msgstr ""
msgid "AI|Features that use third-party AI services require transmission of data, including personal data."
-msgstr ""
+msgstr "타사 AI 서비스를 사용하는 ê¸°ëŠ¥ì€ ê°œì¸ ë°ì´í„°ë¥¼ í¬í•¨í•œ ë°ì´í„° ì „ì†¡ì´ í•„ìš”í•©ë‹ˆë‹¤."
msgid "AI|For example: Organizations should be able to forecast into the future by using value stream analytics charts. This feature would help them understand how their metrics are trending."
msgstr ""
@@ -1801,64 +1823,91 @@ msgid "AI|Generate issue description"
msgstr ""
msgid "AI|GitLab Duo"
+msgstr "GitLab Duo"
+
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
msgstr ""
+msgid "AI|Has no support and might not be documented"
+msgstr "지ì›ì´ 제공ë˜ì§€ 않으며 문서화ë˜ì§€ ì•Šì„ ìˆ˜ 있ìŒ"
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr "ë‚´ê°€ 어떻게 ë„울 수 있ì„지 모르겠습니다. ë” ë‚˜ì€ ì§€ì¹¨ì„ ì œê³µí•˜ì‹­ì‹œì˜¤!"
-msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
+msgid "AI|May be unstable"
msgstr ""
+msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
+msgstr "GitLabì˜ ì˜ê²¬ì´ ì•„ë‹Œ 부ì ì ˆí•œ ì‘ë‹µì„ ì œê³µí•  수 있습니다. ê°œì¸ ì •ë³´ë¥¼ 입력하지 마십시오."
+
msgid "AI|New chat"
-msgstr ""
+msgstr "새로운 채팅"
msgid "AI|Populate issue description"
msgstr ""
msgid "AI|Replace the existing description with an AI-generated description? Any changes you have made will be lost."
-msgstr ""
+msgstr "기존 ì„¤ëª…ì„ AI ìƒì„± 설명으로 바꾸시겠습니까? 모든 변경 ì‚¬í•­ì´ ì†ì‹¤ë©ë‹ˆë‹¤."
msgid "AI|Responses generated by AI"
-msgstr ""
+msgstr "AIì— ì˜í•´ ìƒì„±ëœ 답변"
msgid "AI|Send chat message."
-msgstr ""
+msgstr "채팅 메시지 보내기"
msgid "AI|Something went wrong. Please try again later"
msgstr ""
-msgid "AI|The container element wasn't found, stopping AI Genie."
+msgid "AI|Thank you for your feedback."
msgstr ""
+msgid "AI|The container element wasn't found, stopping AI Genie."
+msgstr "컨테ì´ë„ˆ 요소를 ì°¾ì„ ìˆ˜ 없어 AI Genieê°€ 중지ë˜ì—ˆìŠµë‹ˆë‹¤."
+
msgid "AI|The existing description will be replaced when you submit."
-msgstr ""
+msgstr "제출하면 ê¸°ì¡´ì˜ ì„¤ëª…ì„ ëŒ€ì²´ë©ë‹ˆë‹¤."
msgid "AI|There is too much text in the chat. Please try again with a shorter text."
-msgstr ""
+msgstr "ì±„íŒ…ì— í…스트가 너무 많습니다. ë” ì§§ì€ í…스트로 다시 ì‹œë„하십시오."
msgid "AI|These features can cause performance and stability issues and may change over time."
msgstr ""
msgid "AI|Third-party AI services"
+msgstr "타사 AI 서비스"
+
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
msgstr ""
msgid "AI|Unhelpful"
-msgstr ""
+msgstr "ë„ì›€ì´ ë˜ì§€ ì•ŠìŒ"
msgid "AI|Use Experiment features"
-msgstr ""
+msgstr "실험 기능 사용"
msgid "AI|Use third-party AI services"
-msgstr ""
+msgstr "타사 AI 서비스 사용"
msgid "AI|What does the selected code mean?"
-msgstr ""
+msgstr "ì„ íƒí•œ 코드는 ë¬´ì—‡ì„ ì˜ë¯¸í•©ë‹ˆê¹Œ?"
+
+msgid "AI|What's an Experiment?"
+msgstr "실험 기능 ì´ëž€?"
msgid "AI|Write a brief description and have AI fill in the details."
-msgstr ""
+msgstr "간단한 ì„¤ëª…ì„ ìž‘ì„±í•˜ë©´ AIê°€ 세부 정보를 입력하ë„ë¡ í•©ë‹ˆë‹¤."
msgid "AI|Write a summary to fill out the selected issue template"
msgstr ""
@@ -1869,20 +1918,17 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
msgid "AI|generating"
-msgstr ""
+msgstr "ìƒì„±ì¤‘"
msgid "AI|producing"
msgstr ""
msgid "AI|working on"
-msgstr ""
+msgstr "작업 중"
msgid "API"
msgstr "API"
@@ -1990,16 +2036,16 @@ msgid "APIFuzzing|You may need a maintainer's help to secure your credentials."
msgstr ""
msgid "APIFuzzing|folder/example.postman_collection.json"
-msgstr ""
+msgstr "folder/example.postman_collection.json"
msgid "APIFuzzing|folder/example_fuzz.har"
-msgstr ""
+msgstr "folder/example_fuzz.har"
msgid "APIFuzzing|folder/openapi.json"
-msgstr ""
+msgstr "folder/openapi.json"
msgid "AWS"
-msgstr ""
+msgstr "AWS"
msgid "AWS Access Key"
msgstr "AWS 엑세스 키"
@@ -2041,7 +2087,7 @@ msgid "Abuse reports notification email"
msgstr "ì•…ìš© ì‹ ê³  알림 ì´ë©”ì¼"
msgid "AbuseReportEvent|Successfully banned the user"
-msgstr ""
+msgstr "성공ì ìœ¼ë¡œ 계정 정지ë¨"
msgid "AbuseReportEvent|Successfully banned the user and closed the report"
msgstr ""
@@ -2071,14 +2117,11 @@ msgid "AbuseReports|Deleted user"
msgstr "ì‚­ì œëœ ì‚¬ìš©ìž"
msgid "AbuseReports|No reports found"
-msgstr ""
+msgstr "리í¬íŠ¸ë¥¼ 찾지 못함"
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2095,10 +2138,10 @@ msgid "AbuseReport|Admin profile"
msgstr "ê´€ë¦¬ìž í”„ë¡œí•„"
msgid "AbuseReport|Ban user"
-msgstr ""
+msgstr "계정정지"
msgid "AbuseReport|Block user"
-msgstr ""
+msgstr "ì‚¬ìš©ìž ì°¨ë‹¨"
msgid "AbuseReport|Card matches %{cardMatchesLinkStart}%{count} accounts%{cardMatchesLinkEnd}"
msgstr ""
@@ -2113,7 +2156,7 @@ msgid "AbuseReport|Comments"
msgstr "댓글"
msgid "AbuseReport|Confirm"
-msgstr ""
+msgstr "확ì¸"
msgid "AbuseReport|Confirmed crypto mining"
msgstr ""
@@ -2188,19 +2231,22 @@ msgid "AbuseReport|Normal location"
msgstr "ì •ìƒì ì¸ 위치"
msgid "AbuseReport|Offensive or Abusive"
-msgstr ""
+msgstr "공격ì ì´ê±°ë‚˜ 모욕ì ìž„"
msgid "AbuseReport|Other"
msgstr "기타"
-msgid "AbuseReport|Personal information or credentials"
+msgid "AbuseReport|Past abuse reports"
msgstr ""
+msgid "AbuseReport|Personal information or credentials"
+msgstr "ê°œì¸ ì •ë³´ ë˜ëŠ” ìžê²© ì¦ëª…"
+
msgid "AbuseReport|Phishing"
msgstr "피싱"
msgid "AbuseReport|Phone"
-msgstr ""
+msgstr "ì „í™”"
msgid "AbuseReport|Reason"
msgstr "사유"
@@ -2230,7 +2276,7 @@ msgid "AbuseReport|Reported profile"
msgstr "ì‹ ê³ ëœ í”„ë¡œí•„"
msgid "AbuseReport|Screenshot of reported abuse"
-msgstr ""
+msgstr "ì‹ ê³ ëœ ë¶€ì ì ˆí•œ 사용 스í¬ë¦°ìƒ·"
msgid "AbuseReport|Snippets"
msgstr "스니펫"
@@ -2242,14 +2288,17 @@ msgid "AbuseReport|Spam"
msgstr "스팸"
msgid "AbuseReport|Tier"
-msgstr ""
+msgstr "í‹°ì–´"
msgid "AbuseReport|Verification"
-msgstr ""
+msgstr "ì¸ì¦"
msgid "AbuseReport|View screenshot"
msgstr "스í¬ë¦°ìƒ· 보기"
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "초대 수ë½"
@@ -2263,7 +2312,7 @@ msgid "Access Denied"
msgstr "ì ‘ê·¼ì´ ê±°ë¶€ë˜ì—ˆìŠµë‹ˆë‹¤"
msgid "Access Git repositories or the API."
-msgstr "Git 저장소 ë˜ëŠ” APIì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤."
+msgstr "Git 리í¬ì§€í† ë¦¬ ë˜ëŠ” APIì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤."
msgid "Access Token"
msgstr "액세스 토í°"
@@ -2301,6 +2350,9 @@ msgstr "그룹"
msgid "AccessDropdown|Roles"
msgstr "ì—­í• "
+msgid "AccessDropdown|Select"
+msgstr "ì„ íƒ"
+
msgid "AccessDropdown|Users"
msgstr "사용ìž"
@@ -2311,7 +2363,7 @@ msgid "AccessTokens|Access token limit reached"
msgstr "액세스 í† í° í•œë„ ë„달"
msgid "AccessTokens|Add a %{type}"
-msgstr ""
+msgstr "%{type} 추가"
msgid "AccessTokens|Are you sure?"
msgstr "확실한가요?"
@@ -2329,19 +2381,19 @@ msgid "AccessTokens|Copy incoming email token"
msgstr "수신 ì´ë©”ì¼ í† í° ë³µì‚¬"
msgid "AccessTokens|Copy static object token"
-msgstr ""
+msgstr "ì •ì  ê°œì²´ í† í° ë³µì‚¬"
msgid "AccessTokens|Create %{type}"
msgstr "%{type} ìƒì„±"
msgid "AccessTokens|Created"
-msgstr ""
+msgstr "ìƒì„±ë¨"
msgid "AccessTokens|Feed token"
msgstr "피드 토í°"
msgid "AccessTokens|For example, the application using the token or the purpose of the token."
-msgstr ""
+msgstr "예를 들면, 토í°ì„ 사용하는 애플리케ì´ì…˜ ë˜ëŠ” 토í°ì˜ ìš©ë„입니다."
msgid "AccessTokens|For example, the application using the token or the purpose of the token. Do not give sensitive information for the name of the token, as it will be visible to all %{resource_type} members."
msgstr ""
@@ -2446,7 +2498,7 @@ msgid "AccountValidation|Looks like you'll need to validate your account to use
msgstr ""
msgid "AccountValidation|Validate your account"
-msgstr ""
+msgstr "계정 ì¸ì¦"
msgid "AccountValidation|Verification is required to discourage and reduce the abuse on GitLab infrastructure. If you verify with a credit or debit card, %{strong_start}GitLab will not charge your card, it will only be used for validation.%{strong_end} %{learn_more_link}"
msgstr ""
@@ -2476,11 +2528,14 @@ msgid "Achievements|View your achievements on your profile."
msgstr ""
msgid "Acknowledge"
-msgstr ""
+msgstr "확ì¸í•¨"
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2509,7 +2564,7 @@ msgid "Active chat names (%{count})"
msgstr "활성 채팅 ì´ë¦„(%{count})"
msgid "Active group access tokens"
-msgstr ""
+msgstr "그룹 액세스 í† í° í™œì„±í™”"
msgid "Active personal access tokens"
msgstr ""
@@ -2557,7 +2612,7 @@ msgid "Add README"
msgstr "README 추가"
msgid "Add Wiki"
-msgstr ""
+msgstr "위키 추가"
msgid "Add Zoom meeting"
msgstr "Zoom 미팅 추가"
@@ -2581,7 +2636,7 @@ msgid "Add a checklist"
msgstr "ì²´í¬ë¦¬ìŠ¤íŠ¸ 추가"
msgid "Add a collapsible section"
-msgstr ""
+msgstr "ì ‘ì„ ìˆ˜ 있는 섹션 추가"
msgid "Add a comment to this line"
msgstr "ì´ ë¼ì¸ì— 댓글 추가"
@@ -2620,7 +2675,7 @@ msgid "Add a related issue"
msgstr "관련 ì´ìŠˆ 추가"
msgid "Add a reply"
-msgstr ""
+msgstr "답글 추가"
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -2689,7 +2744,7 @@ msgid "Add deploy freeze"
msgstr ""
msgid "Add deploy keys to grant read/write access to this repository. %{link_start}What are deploy keys?%{link_end}"
-msgstr "ì´ ì €ìž¥ì†Œì— ëŒ€í•œ ì½ê¸°/쓰기 액세스 ê¶Œí•œì„ ë¶€ì—¬í•˜ë ¤ë©´ ë°°í¬ í‚¤ë¥¼ 추가하세요. %{link_start}ë°°í¬ í‚¤ëž€ ​​무엇입니까?%{link_end}"
+msgstr "ì´ ë¦¬í¬ì§€í† ë¦¬ì— 대한 ì½ê¸°/쓰기 액세스 ê¶Œí•œì„ ë¶€ì—¬í•˜ë ¤ë©´ ë°°í¬ í‚¤ë¥¼ 추가하세요. %{link_start}ë°°í¬ í‚¤ëž€ ​​무엇입니까?%{link_end}"
msgid "Add email participant(s)"
msgstr "ì´ë©”ì¼ ì°¸ê°€ìž ì¶”ê°€"
@@ -2737,22 +2792,22 @@ msgid "Add new directory"
msgstr "새 디렉토리 추가"
msgid "Add new emoji"
-msgstr ""
+msgstr "새 ì´ëª¨ì§€ 추가"
msgid "Add new key"
-msgstr ""
+msgstr "새 키 추가"
msgid "Add new pipeline subscription"
-msgstr ""
+msgstr "새 파ì´í”„ë¼ì¸ êµ¬ë… ì¶”ê°€"
msgid "Add new pipeline trigger token"
-msgstr ""
+msgstr "새 파ì´í”„ë¼ì¸ 트리거 í† í° ì¶”ê°€"
msgid "Add new token"
-msgstr ""
+msgstr "ì‹ ê·œ í† í° ì¶”ê°€"
msgid "Add new webhook"
-msgstr ""
+msgstr "새 웹훅 추가"
msgid "Add or remove a user."
msgstr ""
@@ -2776,7 +2831,7 @@ msgid "Add projects"
msgstr "프로ì íŠ¸ 추가"
msgid "Add protected branch"
-msgstr ""
+msgstr "ë³´í˜¸ëœ ë¸Œëžœì¹˜ 추가"
msgid "Add reaction"
msgstr "ë°˜ì‘ ì¶”ê°€"
@@ -2785,19 +2840,22 @@ msgid "Add request manually"
msgstr ""
msgid "Add start and due date"
-msgstr ""
+msgstr "ì‹œìž‘ì¼ ë° ê¸°í•œ 추가"
msgid "Add suggestion to batch"
msgstr ""
msgid "Add tag"
+msgstr "태그 추가"
+
+msgid "Add target branch rule"
msgstr ""
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "ë¡œê·¸ì¸ íŽ˜ì´ì§€ì— í…스트를 추가합니다. 마í¬ë‹¤ìš´ì´ 활성화ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Add time entry"
-msgstr ""
+msgstr "시간 항목 추가"
msgid "Add to board"
msgstr "ë³´ë“œì— ì¶”ê°€"
@@ -2817,6 +2875,9 @@ msgstr "리뷰 추가"
msgid "Add to tree"
msgstr "íŠ¸ë¦¬ì— ì¶”ê°€"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr "사용ìžê°€ 쉽게 ì°¾ì„ ìˆ˜ 있ë„ë¡ í”„ë¡œì íŠ¸ì— 주제를 추가합니다"
@@ -2844,8 +2905,8 @@ msgstr "추가/제거"
msgid "AddMember|Invite email is invalid"
msgstr "초대 ì´ë©”ì¼ì´ 유효하지 않습니다"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "ì¼ì¼ 초대 í•œë„ %{daily_invites} 초과"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "초대 í•­ëª©ì€ ë¹„ì›Œë‘˜ 수 없습니다."
@@ -2905,7 +2966,7 @@ msgid "Additional text to show on the sign-in page"
msgstr "ë¡œê·¸ì¸ íŽ˜ì´ì§€ì— 표시할 추가 í…스트"
msgid "Additional units"
-msgstr ""
+msgstr "추가 컴퓨팅 단위"
msgid "Address"
msgstr "주소"
@@ -2953,7 +3014,7 @@ msgid "Admin Area"
msgstr "ê´€ë¦¬ìž ì˜ì—­"
msgid "Admin Area / Dashboard"
-msgstr ""
+msgstr "ê´€ë¦¬ìž ì˜ì—­ / 대시 ë³´ë“œ"
msgid "Admin Note"
msgstr "ê´€ë¦¬ìž ë…¸íŠ¸"
@@ -2962,10 +3023,10 @@ msgid "Admin Notifications"
msgstr "ê´€ë¦¬ìž ì•Œë¦¼"
msgid "Admin message"
-msgstr ""
+msgstr "ê´€ë¦¬ìž ë©”ì‹œì§€"
msgid "Admin mode"
-msgstr ""
+msgstr "ê´€ë¦¬ìž ëª¨ë“œ"
msgid "Admin mode already enabled"
msgstr "ê´€ë¦¬ìž ëª¨ë“œ ì´ë¯¸ 활성화 ë¨"
@@ -2989,7 +3050,7 @@ msgid "AdminArea|All users created in the instance, including users who are not
msgstr ""
msgid "AdminArea|Are you sure?"
-msgstr ""
+msgstr "확실합니까?"
msgid "AdminArea|Blocked users"
msgstr "ì°¨ë‹¨ëœ ì‚¬ìš©ìž"
@@ -3088,10 +3149,10 @@ msgid "AdminArea|Stop all jobs"
msgstr "모든 작업 중지"
msgid "AdminArea|Total Billable users"
-msgstr ""
+msgstr "ì´ ì²­êµ¬ 가능 ì‚¬ìš©ìž ìˆ˜"
msgid "AdminArea|Total Non-Billable users"
-msgstr ""
+msgstr "ì´ ì²­êµ¬ 불가 ì‚¬ìš©ìž ìˆ˜"
msgid "AdminArea|Total users"
msgstr "ì´ ì‚¬ìš©ìž"
@@ -3148,10 +3209,10 @@ msgid "AdminEmail|Body"
msgstr "본문"
msgid "AdminEmail|Body is required."
-msgstr ""
+msgstr "ë³¸ë¬¸ì´ í•„ìš”í•©ë‹ˆë‹¤."
msgid "AdminEmail|Loading groups and projects."
-msgstr ""
+msgstr "그룹과 프로ì íŠ¸ë¥¼ 로드 중입니다."
msgid "AdminEmail|No groups or projects found."
msgstr "그룹ì´ë‚˜ 프로ì íŠ¸ë¥¼ ì°¾ì„ ìˆ˜ 없습니다."
@@ -3160,7 +3221,7 @@ msgid "AdminEmail|Recipient group or project"
msgstr "ìˆ˜ì‹ ìž ê·¸ë£¹ ë˜ëŠ” 프로ì íŠ¸"
msgid "AdminEmail|Recipient group or project is required."
-msgstr ""
+msgstr "ìˆ˜ì‹ ìž ê·¸ë£¹ ë˜ëŠ” 프로ì íŠ¸ê°€ 필요합니다."
msgid "AdminEmail|Subject"
msgstr "제목"
@@ -3217,7 +3278,7 @@ msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Let's Encrypt 설정"
msgid "AdminSettings|Configure limits on the number of repositories users can download, clone, or fork in a given time."
-msgstr ""
+msgstr "사용ìžê°€ 주어진 ì‹œê°„ì— ë‹¤ìš´ë¡œë“œ, clone, forkí•  수 있는 리í¬ì§€í† ë¦¬ì˜ 수를 제한하는 ì„¤ì •ì„ êµ¬ì„±í•˜ì‹­ì‹œì˜¤."
msgid "AdminSettings|Configure product analytics to track events within your project applications."
msgstr ""
@@ -3310,7 +3371,7 @@ msgid "AdminSettings|If no unit is written, it defaults to seconds. For example,
msgstr "단위를 쓰지 않으면 기본ì ìœ¼ë¡œ 초가 사용ë©ë‹ˆë‹¤. 예를 들어, %{oneDayInSeconds}, %{oneDayInHoursHumanReadable}ë˜ëŠ” %{oneDayHumanReadable}는 ëª¨ë‘ ë™ì¼í•©ë‹ˆë‹¤. ìµœì†Œê°’ì€ 2시간입니다. %{linkStart}ìžì„¸ížˆ 알아보십시오.%{linkEnd}"
msgid "AdminSettings|If not specified at the group or instance level, the default is %{default_initial_branch_name}. Does not affect existing repositories."
-msgstr "그룹 ë˜ëŠ” ì¸ìŠ¤í„´ìŠ¤ 수준ì—ì„œ 지정ë˜ì§€ ì•Šì€ ê²½ìš° ê¸°ë³¸ê°’ì€ %{default_initial_branch_name}입니다. 기존 ì €ìž¥ì†Œì— ì˜í–¥ì„ 주지 않습니다."
+msgstr "그룹 ë˜ëŠ” ì¸ìŠ¤í„´ìŠ¤ 수준ì—ì„œ 지정ë˜ì§€ ì•Šì€ ê²½ìš° ê¸°ë³¸ê°’ì€ %{default_initial_branch_name}입니다. 기존 리í¬ì§€í† ë¦¬ì— ì˜í–¥ì„ 주지 않습니다."
msgid "AdminSettings|If selected, only administrators are able to create internal groups, projects, and snippets."
msgstr "ì„ íƒí•˜ë©´ 관리ìžë§Œ ë‚´ë¶€ì˜ ê·¸ë£¹, 프로ì íŠ¸ ë° ìŠ¤ë‹ˆíŽ«ì„ ìƒì„±í•  수 있습니다."
@@ -3430,7 +3491,7 @@ msgid "AdminSettings|Restrict group access by IP address. %{link_start}Learn mor
msgstr "IP 주소로 그룹 액세스를 제한합니다. %{link_start}ìžì„¸ížˆ 알아보기%{link_end}."
msgid "AdminSettings|Restricted visibility levels"
-msgstr ""
+msgstr "ì œí•œëœ ê³µê°œ 수준"
msgid "AdminSettings|Save %{name} limits"
msgstr ""
@@ -3463,7 +3524,7 @@ msgid "AdminSettings|Set a CI/CD template as the required pipeline configuration
msgstr ""
msgid "AdminSettings|Set options for cost factors of forks"
-msgstr ""
+msgstr "í¬í¬ì˜ 비용 íŒ©í„°ì— ëŒ€í•œ 옵션 설정"
msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered group runners."
msgstr "새로 등ë¡ëœ 그룹 ëŸ¬ë„ˆì˜ ì¸ì¦ í† í° ë§Œë£Œ ì‹œê°„ì„ ì„¤ì •í•©ë‹ˆë‹¤."
@@ -3496,13 +3557,13 @@ msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Dep
msgstr ""
msgid "AdminSettings|The host of your data collector instance."
-msgstr ""
+msgstr "ë°ì´í„° 수집 ì¸ìŠ¤í„´ìŠ¤ì˜ 호스트입니다."
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
msgid "AdminSettings|The maximum number of included files per pipeline."
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ë‹¹ í¬í•¨ëœ 최대 파ì¼ì˜ 개수입니다."
msgid "AdminSettings|The template for the required pipeline configuration can be one of the GitLab-provided templates, or a custom template added to an instance template repository. %{link_start}How do I create an instance template repository?%{link_end}"
msgstr ""
@@ -3511,7 +3572,7 @@ msgid "AdminSettings|There are Advanced Search migrations pending that require i
msgstr ""
msgid "AdminSettings|This cost factor will be applied to the storage consumed by forks."
-msgstr ""
+msgstr "ì´ ë¹„ìš© 팩터는 í¬í¬ê°€ 사용하는 ìŠ¤í† ë¦¬ì§€ì— ì ìš©ë©ë‹ˆë‹¤."
msgid "AdminSettings|This limit cannot be disabled. Set to 0 to block all DAG dependencies."
msgstr ""
@@ -3601,7 +3662,7 @@ msgid "AdminUsers|Access"
msgstr "액세스"
msgid "AdminUsers|Access Git repositories"
-msgstr "Git ì €ìž¥ì†Œì— ì ‘ê·¼"
+msgstr "Git 리í¬ì§€í† ë¦¬ì— ì ‘ê·¼"
msgid "AdminUsers|Access level"
msgstr "액세스 레벨"
@@ -3684,8 +3745,8 @@ msgstr "사용ìžë¥¼ 차단하면 다ìŒê³¼ ê°™ì€ íš¨ê³¼ê°€ 있습니다."
msgid "AdminUsers|Bot"
msgstr "ë´‡"
-msgid "AdminUsers|Can create group"
-msgstr "그룹 ìƒì„± 가능"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr ""
@@ -3739,7 +3800,7 @@ msgid "AdminUsers|External"
msgstr "외부"
msgid "AdminUsers|External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects, groups, or personal snippets."
-msgstr ""
+msgstr "외부 사용ìžëŠ” 액세스가 명시ì ìœ¼ë¡œ 부여ë˜ì§€ 않는 í•œ 내부 ë˜ëŠ” 비공개 프로ì íŠ¸ë¥¼ ë³¼ 수 없습니다. ë˜í•œ 외부 사용ìžëŠ” 프로ì íŠ¸, 그룹 ë˜ëŠ” ê°œì¸ ìŠ¤ë‹ˆíŽ«ì„ ìƒì„±í•  수 없습니다."
msgid "AdminUsers|For more information, please refer to the %{link_start}user account deletion documentation.%{link_end}"
msgstr "ìžì„¸í•œ ë‚´ìš©ì€ %{link_start}ì‚¬ìš©ìž ê³„ì • ì‚­ì œ 문서%{link_end}를 참조하십시오."
@@ -4003,52 +4064,52 @@ msgid "Admin|Applications"
msgstr ""
msgid "Admin|CI/CD"
-msgstr ""
+msgstr "CI/CD"
msgid "Admin|Credentials"
msgstr ""
msgid "Admin|Deploy Keys"
-msgstr ""
+msgstr "ë°°í¬ í‚¤"
msgid "Admin|Geo"
-msgstr ""
+msgstr "Geo"
msgid "Admin|Kubernetes"
-msgstr ""
+msgstr "Kubernetes"
msgid "Admin|Labels"
-msgstr ""
+msgstr "관리ìž|ë¼ë²¨"
msgid "Admin|Learn more about quarterly reconciliation"
msgstr ""
msgid "Admin|Messages"
-msgstr ""
+msgstr "메시지"
msgid "Admin|Monitoring"
-msgstr ""
+msgstr "모니터ë§"
msgid "Admin|Note"
msgstr ""
msgid "Admin|Overview"
-msgstr ""
+msgstr "개요"
msgid "Admin|Push Rules"
-msgstr ""
+msgstr "푸시 규칙"
msgid "Admin|Quarterly reconciliation will occur on %{qrtlyDate}"
msgstr ""
msgid "Admin|Settings"
-msgstr ""
+msgstr "설정"
msgid "Admin|Spam Logs"
-msgstr ""
+msgstr "스팸 로그"
msgid "Admin|Subscription"
-msgstr ""
+msgstr "구ë…"
msgid "Admin|System Hooks"
msgstr ""
@@ -4285,7 +4346,7 @@ msgid "AlertManagement|Value"
msgstr "ê°’"
msgid "AlertManagement|View incident"
-msgstr ""
+msgstr "ì¸ì‹œë˜íŠ¸ 보기"
msgid "AlertMappingBuilder|Define fallback"
msgstr ""
@@ -4308,6 +4369,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4372,7 +4436,7 @@ msgid "AlertSettings|Proceed with editing"
msgstr ""
msgid "AlertSettings|Prometheus"
-msgstr ""
+msgstr "Prometheus"
msgid "AlertSettings|Reset Key"
msgstr "키 리셋"
@@ -4423,10 +4487,10 @@ msgid "AlertSettings|View credentials"
msgstr ""
msgid "AlertSettings|Webhook URL"
-msgstr ""
+msgstr "Webhook URL"
msgid "AlertSettings|You can map default GitLab alert fields to your payload keys in the dropdowns below."
-msgstr ""
+msgstr "아래 드롭다운ì—ì„œ 기본 GitLab 경고 필드를 페ì´ë¡œë“œ í‚¤ì— ë§¤í•‘í•  수 있습니다."
msgid "AlertSettings|{ \"events\": [{ \"application\": \"Name of application\" }] }"
msgstr ""
@@ -4495,7 +4559,7 @@ msgid "All Members"
msgstr "모든 구성ì›"
msgid "All activity"
-msgstr ""
+msgstr "모든 활ë™"
msgid "All branch names must match %{link_start}this regular expression%{link_end}. If empty, any branch name is allowed."
msgstr ""
@@ -4627,7 +4691,7 @@ msgid "Allow users to register any application to use GitLab as an OAuth provide
msgstr ""
msgid "Allowed"
-msgstr ""
+msgstr "허용ë¨"
msgid "Allowed email domain restriction only permitted for top-level groups"
msgstr ""
@@ -4654,7 +4718,7 @@ msgid "Almost there"
msgstr "ê±°ì˜ ë‹¤ ë났습니다"
msgid "Almost there..."
-msgstr ""
+msgstr "ê±°ì˜ ë‹¤ ë습니다..."
msgid "Already blocked"
msgstr "ì´ë¯¸ 차단ë¨"
@@ -4723,7 +4787,7 @@ msgid "An error has occurred"
msgstr "ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error in reporting in which a test result incorrectly indicates the presence of a vulnerability in a system when the vulnerability is not present."
-msgstr ""
+msgstr "취약ì ì´ 존재하지 ì•ŠìŒì—ë„, 검사 결과가 ì‹œìŠ¤í…œì— ì·¨ì•½ì ì´ 있다고 잘못 표시하는 ë³´ê³  오류입니다."
msgid "An error occurred creating the new branch."
msgstr "새 브랜치를 만드는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -4746,14 +4810,11 @@ msgstr "공개 ë°°í¬ í‚¤ë¥¼ 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë
msgid "An error occurred previewing the blob"
msgstr "BLOB 미리보기 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr "ì œëª©ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” ë„중 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while acknowledging the notification. Refresh the page and try again."
-msgstr ""
+msgstr "ì•Œë¦¼ì„ í™•ì¸í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 페ì´ì§€ë¥¼ 새로고침하고 다시 ì‹œë„하세요."
msgid "An error occurred while adding approvers"
msgstr "승ì¸ìžë¥¼ 추가하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -4828,7 +4889,7 @@ msgid "An error occurred while fetching environments."
msgstr "í™˜ê²½ì„ ê°€ì ¸ì˜¤ëŠ” ë„중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
msgid "An error occurred while fetching exposed artifacts."
-msgstr ""
+msgstr "ë…¸ì¶œëœ ì•„í‹°íŒ©íŠ¸ë¥¼ 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while fetching folder content."
msgstr "í´ë” ë‚´ìš©ì„ ê°€ì ¸ 오는 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -4837,22 +4898,25 @@ msgid "An error occurred while fetching issues."
msgstr "ì´ìŠˆë¥¼ 가져오는 ë„중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
msgid "An error occurred while fetching label colors."
+msgstr "ë¼ë²¨ 색ìƒì„ 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+
+msgid "An error occurred while fetching labels, please try again."
msgstr ""
msgid "An error occurred while fetching participants"
-msgstr ""
+msgstr "참가ìžë¥¼ 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while fetching participants."
-msgstr ""
+msgstr "참가ìžë¥¼ 가져오는 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while fetching pending comments"
msgstr "ëŒ“ê¸€ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while fetching reference"
-msgstr ""
+msgstr "참조를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while fetching reviewers."
-msgstr ""
+msgstr "리뷰어를 가져오는 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while fetching tags. Retry the search."
msgstr "태그를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 검색해 보세요."
@@ -4969,7 +5033,7 @@ msgid "An error occurred while making the request."
msgstr "ìš”ì²­ì„ ìƒì„±í•˜ëŠ” 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while moving the issue."
-msgstr ""
+msgstr "ì´ìŠˆë¥¼ 옮기는 ë„중 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
msgid "An error occurred while parsing recent searches"
msgstr ""
@@ -5023,6 +5087,9 @@ msgstr[0] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "ì„¤ì •ì„ ì €ìž¥í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 저장해 보세요."
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "ìž‘ì—…ì„ íŠ¸ë¦¬ê±°í•˜ëŠ” 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -5038,11 +5105,17 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "승ì¸ìžë¥¼ ì—…ë°ì´íŠ¸í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
msgid "An error occurred while updating assignees."
-msgstr ""
+msgstr "담당ìžë¥¼ ì—…ë°ì´íŠ¸í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while updating configuration."
msgstr "ì„¤ì •ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -5051,10 +5124,10 @@ msgid "An error occurred while updating labels."
msgstr "ë¼ë²¨ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while updating the configuration."
-msgstr ""
+msgstr "ì„¤ì •ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” ë„중 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
msgid "An error occurred while updating the notification settings. Please try again."
-msgstr ""
+msgstr "알림 ì„¤ì •ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” ë„중 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤. 다시 ì‹œë„하십시오."
msgid "An error occurred while uploading the file. Please try again."
msgstr "파ì¼ì„ 업로드하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."
@@ -5066,7 +5139,7 @@ msgid "An error occurred while validating username"
msgstr "ì‚¬ìš©ìž ì´ë¦„ì„ í™•ì¸í•˜ëŠ” 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
msgid "An error occurred. Please sign in again."
-msgstr ""
+msgstr "오류가 ë°œìƒ í•˜ì˜€ìŠµë‹ˆë‹¤, 다시 ë¡œê·¸ì¸ í•˜ì‹œê¸° ë°”ëžë‹ˆë‹¤."
msgid "An error occurred. Please try again."
msgstr "오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."
@@ -5090,7 +5163,7 @@ msgid "An incident has been triggered in %{project_path}."
msgstr ""
msgid "An integer value is required for seconds"
-msgstr ""
+msgstr "ì´ˆ 항목ì—는 정수 ê°’ì´ í•„ìš”í•©ë‹ˆë‹¤."
msgid "An issue already exists"
msgstr "ì´ë¯¸ 존재하는 ì´ìŠˆìž…니다."
@@ -5103,7 +5176,7 @@ msgid "An unauthenticated user"
msgstr "ì¸ì¦ë˜ì§€ ì•Šì€ ì‚¬ìš©ìž"
msgid "An unexpected error occurred"
-msgstr ""
+msgstr "예ìƒì¹˜ 못한 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤"
msgid "An unexpected error occurred while checking the project environment."
msgstr "프로ì íŠ¸ í™˜ê²½ì„ í™•ì¸í•˜ë˜ ë„중 예ìƒì¹˜ ì•Šì€ ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -5118,7 +5191,7 @@ msgid "An unexpected error occurred while loading the Sast diff."
msgstr ""
msgid "An unexpected error occurred while loading the code quality diff."
-msgstr ""
+msgstr "코드 품질 ì°¨ì´ë¥¼ 로드하는 ë™ì•ˆ 예기치 ì•Šì€ ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An unexpected error occurred while starting the Web Terminal."
msgstr "웹 터미ë„ì„ ì‹œìž‘í•˜ë˜ ë„중 예ìƒì¹˜ ì•Šì€ ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -5130,7 +5203,7 @@ msgid "An unexpected error occurred. Please try again."
msgstr ""
msgid "An unknown error occurred while loading this graph."
-msgstr ""
+msgstr "ì´ ê·¸ëž˜í”„ë¥¼ 로드하는 ë™ì•ˆ ì•Œ 수 없는 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An unknown error occurred."
msgstr "ì•Œ 수 없는 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -5147,68 +5220,74 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
-msgid "Analytics|Add visualizations"
+msgid "Analytics|Add a visualization"
msgstr ""
+msgid "Analytics|Add visualizations"
+msgstr "ì‹œê°í™” 추가"
+
msgid "Analytics|An error occurred while loading data"
-msgstr ""
+msgstr "ë°ì´í„°ë¥¼ 불러오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
-msgstr ""
+msgstr "%{visualizationTitle} ì‹œê°í™”를 로드하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "Analytics|Analytics dashboards"
-msgstr ""
+msgstr "ë¶„ì„ ëŒ€ì‹œë³´ë“œ"
msgid "Analytics|Analytics settings for '%{project_name}' were successfully updated."
-msgstr ""
+msgstr "'%{project_name}'ì— ëŒ€í•œ ë¶„ì„ ì„¤ì •ì´ ì„±ê³µì ìœ¼ë¡œ ì—…ë°ì´íŠ¸ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Analytics|Browser"
-msgstr ""
+msgstr "브ë¼ìš°ì €"
msgid "Analytics|Browser Family"
-msgstr ""
+msgstr "브ë¼ìš°ì € 제품군"
msgid "Analytics|By GitLab"
-msgstr ""
+msgstr "GitLab 제공"
msgid "Analytics|Cancel"
-msgstr ""
+msgstr "취소"
msgid "Analytics|Choose a chart type on the right"
-msgstr ""
+msgstr "오른쪽ì—ì„œ 차트 유형 ì„ íƒ"
msgid "Analytics|Choose a measurement to start"
-msgstr ""
+msgstr "시작할 측정 ì„ íƒ"
msgid "Analytics|Code"
-msgstr ""
+msgstr "코드"
msgid "Analytics|Column Chart"
-msgstr ""
+msgstr "막대 그래프"
msgid "Analytics|Configure Dashboard Project"
-msgstr ""
+msgstr "대시보드 프로ì íŠ¸ 구성"
msgid "Analytics|Create dashboard %{dashboardSlug}"
-msgstr ""
+msgstr "대시보드 만들기 %{dashboardSlug}"
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
-msgstr "대시보드 제목"
+msgid "Analytics|Custom dashboards"
+msgstr "ì‚¬ìš©ìž ëŒ€ì‹œë³´ë“œ"
msgid "Analytics|Dashboard not found"
msgstr "대시보드를 ì°¾ì„ ìˆ˜ 없습니다"
-msgid "Analytics|Dashboard was saved successfully"
+msgid "Analytics|Dashboard title"
msgstr ""
+msgid "Analytics|Dashboard was saved successfully"
+msgstr "대시보드가 성공ì ìœ¼ë¡œ 저장ë˜ì—ˆìŠµë‹ˆë‹¤"
+
msgid "Analytics|Dashboards are created by editing the groups dashboard files."
-msgstr ""
+msgstr "대시보드는 그룹 대시보드 파ì¼ì„ 편집하여 ìƒì„±ë©ë‹ˆë‹¤."
msgid "Analytics|Dashboards are created by editing the projects dashboard files."
-msgstr ""
+msgstr "대시보드는 프로ì íŠ¸ 대시보드 파ì¼ì„ íŽ¸ì§‘í•¨ìœ¼ë¡œì¨ ìƒì„±ë©ë‹ˆë‹¤."
msgid "Analytics|Data"
msgstr "ë°ì´í„°"
@@ -5222,38 +5301,47 @@ msgstr "날짜 ë° ì‹œê°„ì€ UTC 시간대로 표시ë©ë‹ˆë‹¤."
msgid "Analytics|Edit"
msgstr "편집"
-msgid "Analytics|Enter a visualization name"
+msgid "Analytics|Edit your dashboard"
msgstr ""
-msgid "Analytics|Error while saving dashboard"
+msgid "Analytics|Enter a dashboard title"
msgstr ""
+msgid "Analytics|Enter a visualization name"
+msgstr "ì‹œê°í™” ì´ë¦„ ìž…ë ¥"
+
+msgid "Analytics|Error while saving dashboard"
+msgstr "대시보드 저장 중 오류"
+
msgid "Analytics|Error while saving visualization."
-msgstr ""
+msgstr "ì‹œê°í™”를 저장하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "Analytics|Failed to fetch data"
-msgstr ""
+msgstr "ë°ì´í„°ë¥¼ 가져오지 못했습니다."
msgid "Analytics|Host"
msgstr "호스트"
+msgid "Analytics|Invalid visualization configuration"
+msgstr "ìž˜ëª»ëœ ì‹œê°í™” 구성"
+
msgid "Analytics|Language"
msgstr "언어"
msgid "Analytics|Line Chart"
-msgstr ""
+msgstr "ë¼ì¸ 차트"
msgid "Analytics|New analytics visualization name"
-msgstr ""
+msgstr "새 ë¶„ì„ ì‹œê°í™” ì´ë¦„"
msgid "Analytics|New dashboard"
msgstr "새 대시보드"
msgid "Analytics|No dashboard matches the specified URL path."
-msgstr ""
+msgstr "ì§€ì •ëœ URL 경로와 ì¼ì¹˜í•˜ëŠ” 대시보드가 없습니다."
msgid "Analytics|No results match your query or filter."
-msgstr ""
+msgstr "쿼리 ë˜ëŠ” 필터와 ì¼ì¹˜í•˜ëŠ” 결과가 없습니다."
msgid "Analytics|OS"
msgstr "ìš´ì˜ì²´ì œ(OS)"
@@ -5279,29 +5367,35 @@ msgstr "참조ìž"
msgid "Analytics|Resulting Data"
msgstr "ê²°ê³¼ ë°ì´í„°"
-msgid "Analytics|Save"
-msgstr "저장"
-
msgid "Analytics|Save and add to Dashboard"
msgstr "ëŒ€ì‹œë³´ë“œì— ì €ìž¥ ë° ì¶”ê°€"
msgid "Analytics|Save new visualization"
msgstr "새 ì‹œê°í™” 저장"
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr "측정 ì„ íƒ"
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr "ì‹œê°í™” 유형 ì„ íƒ"
msgid "Analytics|Single Statistic"
msgstr "ë‹¨ì¼ í†µê³„"
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr "íŒ¨ë„ ì‹œê°í™” êµ¬ì„±ì— ë¬¸ì œê°€ 있습니다. %{linkStart}문제 í•´ê²° 문서%{linkEnd}ì„ ì°¸ì¡°í•˜ì‹­ì‹œì˜¤."
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
-msgstr ""
+msgstr "ë°ì´í„° ì†ŒìŠ¤ì— ì—°ê²°í•˜ëŠ” ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. %{linkStart}문제 í•´ê²° 문서%{linkEnd}ì„ ì°¸ì¡°í•˜ì‹­ì‹œì˜¤."
msgid "Analytics|Something went wrong."
-msgstr ""
+msgstr "문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "Analytics|To create your own dashboards, first configure a project to store your dashboards."
msgstr "ìžì‹ ë§Œì˜ 대시보드를 ìƒì„±í•˜ë ¤ë©´, 먼저 대시보드를 저장할 프로ì íŠ¸ë¥¼ 구성하십시오."
@@ -5310,10 +5404,10 @@ msgid "Analytics|URL"
msgstr "URL"
msgid "Analytics|Updating dashboard %{dashboardSlug}"
-msgstr ""
+msgstr "대시보드 ì—…ë°ì´íŠ¸ 중 %{dashboardSlug}"
msgid "Analytics|Updating visualization %{visualizationName}"
-msgstr ""
+msgstr "ì‹œê°í™” ì—…ë°ì´íŠ¸ 중 %{visualizationName}"
msgid "Analytics|Users"
msgstr "사용ìž"
@@ -5328,22 +5422,22 @@ msgid "Analytics|Visualization"
msgstr "ì‹œê°í™”"
msgid "Analytics|Visualization Designer"
-msgstr ""
+msgstr "ì‹œê°í™” ë””ìžì´ë„ˆ"
msgid "Analytics|Visualization Type"
-msgstr ""
+msgstr "ì‹œê°í™” 유형"
msgid "Analytics|Visualization designer"
-msgstr ""
+msgstr "ì‹œê°í™” ë””ìžì´ë„ˆ"
msgid "Analytics|Visualization was saved successfully"
-msgstr ""
+msgstr "ì‹œê°í™”ê°€ 성공ì ìœ¼ë¡œ 저장ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Analyze your dependencies for known vulnerabilities."
-msgstr ""
+msgstr "알려진 취약ì ì— 대한 ì˜ì¡´ì„±ë“¤ì„ 분ì„하세요"
msgid "Analyze your infrastructure as code configuration files for known vulnerabilities."
-msgstr ""
+msgstr "알려진 취약ì ì— 대한 코드 설정 파ì¼ë¡œ ì¸í”„ë¼ë¥¼ 분ì„합니다."
msgid "Analyze your source code and git history for secrets."
msgstr ""
@@ -5355,7 +5449,7 @@ msgid "Analyzing file…"
msgstr ""
msgid "Ancestors"
-msgstr ""
+msgstr "ì¡°ìƒ"
msgid "And this registration token:"
msgstr "그리고 ì´ ë“±ë¡ í† í°:"
@@ -5370,7 +5464,7 @@ msgid "Another issue tracker is already in use. Only one issue tracker service c
msgstr ""
msgid "Another open merge request already exists for this source branch: %{conflicting_mr_reference}"
-msgstr ""
+msgstr "ì´ ì†ŒìŠ¤ ë¸Œëžœì¹˜ì— ëŒ€í•œ 다른 열린 머지 리퀘스트가 ì´ë¯¸ 있습니다: %{conflicting_mr_reference}"
msgid "Another third-party wiki is already in use. Only one third-party wiki integration can be active at a time"
msgstr ""
@@ -5388,7 +5482,7 @@ msgid "Any Author"
msgstr "모든 작성ìž"
msgid "Any Milestone"
-msgstr ""
+msgstr "모든 마ì¼ìŠ¤í†¤"
msgid "Any encrypted tokens"
msgstr ""
@@ -5433,22 +5527,22 @@ msgid "AppleAppStore|Leave empty to use your current Private Key."
msgstr ""
msgid "AppleAppStore|Only set variables on protected branches and tags"
-msgstr ""
+msgstr "ë³´í˜¸ëœ ë¸Œëžœì¹˜ ë° íƒœê·¸ì—만 변수 설정"
msgid "AppleAppStore|Protected branches and tags only"
-msgstr ""
+msgstr "ë³´í˜¸ëœ ë¸Œëžœì¹˜ ë° íƒœê·¸ë§Œ"
msgid "AppleAppStore|The Apple App Store Connect Issuer ID."
-msgstr ""
+msgstr "애플 앱스토어 Connect ë°œí–‰ìž ID."
msgid "AppleAppStore|The Apple App Store Connect Key ID."
-msgstr ""
+msgstr "애플 앱스토어 Connect 키 ID"
msgid "AppleAppStore|The Apple App Store Connect Private Key (.p8)"
-msgstr ""
+msgstr "애플 앱스토어 Connect ê°œì¸ í‚¤ (.p8)"
msgid "AppleAppStore|Upload a new Apple App Store Connect Private Key (replace %{currentFileName})"
-msgstr ""
+msgstr "새로운 애플 앱스토어 Connect ê°œì¸ í‚¤ 업로드 (í˜„ìž¬ì˜ %{currentFileName} êµì²´)"
msgid "AppleAppStore|Use GitLab to build and release an app in the Apple App Store."
msgstr ""
@@ -5528,19 +5622,19 @@ msgid "ApplicationSettings|By making this change, you will automatically approve
msgstr ""
msgid "ApplicationSettings|Denied domains for sign-ups"
-msgstr ""
+msgstr "ê°€ìž…ì´ ê±°ë¶€ëœ ë„ë©”ì¸"
msgid "ApplicationSettings|Denylist file"
-msgstr ""
+msgstr "거부 ëª©ë¡ íŒŒì¼"
msgid "ApplicationSettings|Domain denylist"
-msgstr ""
+msgstr "ë„ë©”ì¸ ê±°ë¶€ 목ë¡"
msgid "ApplicationSettings|Email confirmation settings"
msgstr ""
msgid "ApplicationSettings|Email restrictions"
-msgstr ""
+msgstr "ì´ë©”ì¼ ì œí•œ 사항"
msgid "ApplicationSettings|Email restrictions for sign-ups"
msgstr ""
@@ -5549,13 +5643,13 @@ msgid "ApplicationSettings|Enable GitLab for Slack app"
msgstr ""
msgid "ApplicationSettings|Enable domain denylist for sign-ups"
-msgstr ""
+msgstr "ê°€ìž…ì„ ìœ„í•œ ë„ë©”ì¸ ê±°ë¶€ ëª©ë¡ í™œì„±í™”"
msgid "ApplicationSettings|Enable email restrictions for sign-ups"
-msgstr ""
+msgstr "ê°€ìž…ì— ëŒ€í•œ ì´ë©”ì¼ ì œí•œ 활성화"
msgid "ApplicationSettings|Enter denylist manually"
-msgstr ""
+msgstr "수ë™ìœ¼ë¡œ 거부 ëª©ë¡ ìž…ë ¥"
msgid "ApplicationSettings|Hard"
msgstr ""
@@ -5719,22 +5813,22 @@ msgid "ApprovalRule|A merge request author collaborating with a merge request ap
msgstr ""
msgid "ApprovalRule|Add approvers"
-msgstr ""
+msgstr "승ì¸ìž 추가"
msgid "ApprovalRule|Any"
msgstr ""
msgid "ApprovalRule|Approval rules"
-msgstr ""
+msgstr "ìŠ¹ì¸ ê·œì¹™"
msgid "ApprovalRule|Approvals required"
-msgstr ""
+msgstr "ìŠ¹ì¸ í•„ìš”"
msgid "ApprovalRule|Approver Type"
-msgstr ""
+msgstr "승ì¸ìž 유형"
msgid "ApprovalRule|Approvers"
-msgstr ""
+msgstr "승ì¸ìž"
msgid "ApprovalRule|Confirmed"
msgstr ""
@@ -5743,16 +5837,16 @@ msgid "ApprovalRule|Dismissed"
msgstr ""
msgid "ApprovalRule|Examples: QA, Security."
-msgstr ""
+msgstr "예: QA, 보안."
msgid "ApprovalRule|Greater than"
msgstr ""
msgid "ApprovalRule|Improve your organization's code review with required approvals."
-msgstr ""
+msgstr "ìš”ì²­ëœ ìŠ¹ì¸ìœ¼ë¡œ ì¡°ì§ì˜ 코드 리뷰를 개선하십시오."
msgid "ApprovalRule|Increase quality and maintain standards."
-msgstr ""
+msgstr "í’ˆì§ˆì„ ë†’ì´ê³  í‘œì¤€ì„ ìœ ì§€í•©ë‹ˆë‹¤."
msgid "ApprovalRule|Learn more about merge request approval rules."
msgstr "머지 리퀘스트 ìŠ¹ì¸ ê·œì¹™ì— ëŒ€í•´ ìžì„¸ížˆ 알아보세요."
@@ -5800,7 +5894,7 @@ msgid "ApprovalRule|Target branch"
msgstr "ëŒ€ìƒ ë¸Œëžœì¹˜"
msgid "ApprovalRule|Try for free"
-msgstr ""
+msgstr "무료로 사용해 보기"
msgid "ApprovalRule|all groups"
msgstr "모든 그룹"
@@ -5983,7 +6077,7 @@ msgid "Archived in this version"
msgstr "ì´ ë²„ì „ì—ì„œ ë³´ê´€ë¨"
msgid "Archived project! Repository and other project resources are read-only"
-msgstr "ë³´ê´€ëœ í”„ë¡œì íŠ¸! 저장소 ë° ê¸°íƒ€ 프로ì íŠ¸ 리소스는 ì½ê¸° 전용입니다."
+msgstr "ë³´ê´€ëœ í”„ë¡œì íŠ¸! 리í¬ì§€í† ë¦¬ ë° ê¸°íƒ€ 프로ì íŠ¸ 리소스는 ì½ê¸° 전용입니다."
msgid "Archived projects"
msgstr "ì•„ì¹´ì´ë¸Œëœ 프로ì íŠ¸"
@@ -6045,9 +6139,6 @@ msgstr "ì´ ê¸°ê¸°ë¥¼ 삭제하시겠습니까? ì´ ìž‘ì—…ì€ ì·¨ì†Œí•  수 ì—†ì
msgid "Are you sure you want to delete this label?"
msgstr "ì´ ë¼ë²¨ì„ 삭제하시겠습니까?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "ì´ íŒŒì´í”„ë¼ì¸ ìŠ¤ì¼€ì¥´ì„ ì‚­ì œ 하시겠습니까?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "ì´ íŒŒì´í”„ë¼ì¸ì„ 삭제하시겠습니까? 그렇게 하면 모든 파ì´í”„ë¼ì¸ ìºì‹œê°€ 만료ë˜ê³  빌드, 로그, 아티팩트 ë° íŠ¸ë¦¬ê±°ì™€ ê°™ì€ ëª¨ë“  관련 개체가 ì‚­ì œë©ë‹ˆë‹¤. ì´ ìž‘ì—…ì€ ì·¨ì†Œí•  수 없습니다."
@@ -6127,8 +6218,8 @@ msgstr "ë“±ë¡ í† í°ì„ 초기화 하시겠습니까?"
msgid "Are you sure you want to retry this migration?"
msgstr "ì´ ë§ˆì´ê·¸ë ˆì´ì…˜ì„ 다시 ì‹œë„하시겠습니까?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "ì´ %{accessTokenType}ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? ì´ ìž‘ì—…ì€ ë˜ëŒë¦´ 수 없습니다."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
msgstr ""
@@ -6222,23 +6313,23 @@ msgid "Artifacts|Delete artifact"
msgstr "아티팩트 삭제"
msgid "Artifacts|Delete selected"
-msgstr ""
+msgstr "ì„ íƒ í•­ëª© ì‚­ì œ"
msgid "Artifacts|Help us improve this page"
-msgstr ""
+msgstr "ì´ íŽ˜ì´ì§€ ê°œì„ ì„ ë„와주세요"
msgid "Artifacts|Maximum selected artifacts limit reached"
-msgstr ""
+msgstr "ì„ íƒí•œ 최대 아티팩트 ì œí•œì— ë„달했습니다."
msgid "Artifacts|Something went wrong while deleting. Please refresh the page to try again."
-msgstr ""
+msgstr "삭제하는 ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 페ì´ì§€ë¥¼ 새로 고침하여 다시 ì‹œë„í•´ 주세요."
msgid "Artifacts|Take a quick survey"
msgstr "간단한 설문조사 참여"
msgid "Artifacts|The selected artifact will be permanently deleted. Any reports generated from these artifacts will be empty."
msgid_plural "Artifacts|The selected artifacts will be permanently deleted. Any reports generated from these artifacts will be empty."
-msgstr[0] ""
+msgstr[0] "ì„ íƒëœ 아티팩트는 ì˜êµ¬ì ìœ¼ë¡œ ì‚­ì œë©ë‹ˆë‹¤. ì´ëŸ¬í•œ 아티팩트ì—ì„œ ìƒì„±ëœ 모든 보고서는 비어 ìžˆì„ ê²ƒìž…ë‹ˆë‹¤."
msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
msgstr "ì´ ì•„í‹°íŒ©íŠ¸ëŠ” ì˜êµ¬ì ìœ¼ë¡œ ì‚­ì œë©ë‹ˆë‹¤. ì´ ì•„í‹°íŒ©íŠ¸ì—ì„œ ìƒì„±ëœ 모든 보고서는 비워집니다."
@@ -6247,10 +6338,10 @@ msgid "Artifacts|Total artifacts size"
msgstr "ì´ ì•„í‹°íŒ©íŠ¸ í¬ê¸°"
msgid "Artifacts|We want you to be able to use this page to easily manage your CI/CD job artifacts. We are working to improve this experience and would appreciate any feedback you have about the improvements we are making."
-msgstr ""
+msgstr "ì´ íŽ˜ì´ì§€ë¥¼ 사용하여 CI/CD ìž‘ì—… 아티팩트를 쉽게 관리할 수 있기를 ë°”ëžë‹ˆë‹¤. 우리는 ì´ ê²½í—˜ì„ ê°œì„ í•˜ê¸° 위해 노력하고 있으며 우리가 만들고 있는 개선 ì‚¬í•­ì— ëŒ€í•œ í”¼ë“œë°±ì„ ì£¼ì‹œë©´ ê°ì‚¬í•˜ê² ìŠµë‹ˆë‹¤."
msgid "As this is a newly created account, to get started, click the link below to confirm your account."
-msgstr ""
+msgstr "새로 ìƒì„±ëœ 계정ì´ë¯€ë¡œ 시작하려면 아래 ë§í¬ë¥¼ í´ë¦­í•˜ì—¬ ê³„ì •ì„ ì¸ì¦í•˜ì„¸ìš”."
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -6267,6 +6358,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr "ìžì„¸í•œ 정보를 보려면 관리ìžì—게 가져오기 ìƒíƒœë¥¼ 확ì¸ì„ 요청하세요."
+
msgid "Ask again later"
msgstr ""
@@ -6304,7 +6398,7 @@ msgid "Assign reviewer"
msgstr "리뷰어 지정하기"
msgid "Assign reviewers"
-msgstr ""
+msgstr "리뷰어 지정하기"
msgid "Assign severity"
msgstr "심ê°ë„ 지정"
@@ -6322,7 +6416,7 @@ msgid "Assign to me"
msgstr "나ì—게 할당"
msgid "Assign yourself"
-msgstr ""
+msgstr "ìžì‹ ì„ 할당"
msgid "Assigned"
msgstr ""
@@ -6368,7 +6462,7 @@ msgid "Assignees"
msgstr "담당ìž"
msgid "Assignees & reviewers"
-msgstr ""
+msgstr "ë‹´ë‹¹ìž & 리뷰어"
msgid "Assigns %{assignee_users_sentence}."
msgstr ""
@@ -6474,6 +6568,9 @@ msgstr "ì´ ì´ë¦„ì„ ê°€ì§„ í—¤ë”ê°€ ì´ë¯¸ 존재합니다."
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6514,13 +6611,13 @@ msgid "AuditStreams|Custom HTTP headers (optional)"
msgstr "ì‚¬ìš©ìž ì •ì˜ HTTP í—¤ë”(옵션)"
msgid "AuditStreams|Delete destination"
-msgstr ""
+msgstr "ëŒ€ìƒ ì‚­ì œ"
msgid "AuditStreams|Deleting the streaming destination %{destination} will stop audit events being streamed"
-msgstr ""
+msgstr "ìŠ¤íŠ¸ë¦¬ë° ëŒ€ìƒ %{destination} ì„ ì‚­ì œí•˜ë©´ 스트리ë°ë˜ëŠ” ê°ì‚¬ ì´ë²¤íŠ¸ê°€ 중지ë©ë‹ˆë‹¤."
msgid "AuditStreams|Destination Name"
-msgstr ""
+msgstr "ëŒ€ìƒ ì´ë¦„"
msgid "AuditStreams|Destination URL"
msgstr "ëŒ€ìƒ URL"
@@ -6538,49 +6635,49 @@ msgid "AuditStreams|Filter by audit event type"
msgstr ""
msgid "AuditStreams|Google Cloud Logging"
-msgstr ""
+msgstr "Google í´ë¼ìš°ë“œ 로깅"
msgid "AuditStreams|HTTP endpoint"
-msgstr ""
+msgstr "HTTP endpoint"
msgid "AuditStreams|Header"
msgstr "í—¤ë”"
msgid "AuditStreams|Log ID"
-msgstr ""
+msgstr "로그 ID"
msgid "AuditStreams|Maximum of %{number} HTTP headers has been reached."
msgstr "최대 %{number} ê°œì˜ HTTP í—¤ë”ì— ë„달했습니다."
msgid "AuditStreams|No header created yet."
-msgstr ""
+msgstr "í—¤ë”ê°€ ì•„ì§ ìƒì„±ë˜ì§€ 않았습니다."
msgid "AuditStreams|Private key"
-msgstr ""
+msgstr "ê°œì¸ í‚¤"
msgid "AuditStreams|Project ID"
-msgstr ""
+msgstr "프로ì íŠ¸ ID"
msgid "AuditStreams|Remove custom header"
msgstr "ì‚¬ìš©ìž ì •ì˜ í—¤ë” ì œê±°"
msgid "AuditStreams|Save external stream destination"
-msgstr ""
+msgstr "외부 스트림 ëŒ€ìƒ ì €ìž¥"
msgid "AuditStreams|Select events"
-msgstr ""
+msgstr "ì´ë²¤íŠ¸ ì„ íƒ"
msgid "AuditStreams|Setup streaming for audit events"
msgstr ""
msgid "AuditStreams|Stream added successfully"
-msgstr ""
+msgstr "ìŠ¤íŠ¸ë¦¼ì´ ì„±ê³µì ìœ¼ë¡œ 추가ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "AuditStreams|Stream deleted successfully"
-msgstr ""
+msgstr "ìŠ¤íŠ¸ë¦¼ì´ ì„±ê³µì ìœ¼ë¡œ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "AuditStreams|Stream updated successfully"
-msgstr ""
+msgstr "ìŠ¤íŠ¸ë¦¼ì´ ì„±ê³µì ìœ¼ë¡œ ì—…ë°ì´íŠ¸ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "AuditStreams|Streams"
msgstr ""
@@ -6591,6 +6688,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "ê°’"
@@ -7006,7 +7106,7 @@ msgid "BambooService|Bamboo URL"
msgstr "Bamboo URL"
msgid "BambooService|Bamboo build plan key."
-msgstr ""
+msgstr "Bamboo 빌드 êµ¬ë… í‚¤."
msgid "BambooService|Bamboo service root URL."
msgstr ""
@@ -7015,7 +7115,7 @@ msgid "BambooService|Enter new build key"
msgstr "새 빌드 키 입력"
msgid "BambooService|Leave blank to use your current build key."
-msgstr ""
+msgstr "현재 빌드 키를 사용하려면 비워 둡니다."
msgid "BambooService|Run CI/CD pipelines with Atlassian Bamboo."
msgstr ""
@@ -7276,7 +7376,7 @@ msgid "BillingPlans|Executive level insights"
msgstr ""
msgid "BillingPlans|Faster code reviews"
-msgstr ""
+msgstr "ë” ë¹ ë¥¸ 코드 리뷰"
msgid "BillingPlans|Free"
msgstr ""
@@ -7453,7 +7553,7 @@ msgid "Billings|Free seats used"
msgstr ""
msgid "Billings|Free tier and trial groups can invite a maximum of 20 members per day."
-msgstr "Billings|무료 요금제 ë° í‰ê°€íŒì—ì„œ ê·¸ë£¹ì€ í•˜ë£¨ì— ìµœëŒ€ 20ëª…ì˜ íšŒì›ì„ 초대할 수 있습니다."
+msgstr "Free í‹°ì–´ ë° í‰ê°€íŒì—ì„œ ê·¸ë£¹ì€ í•˜ë£¨ì— ìµœëŒ€ 20ëª…ì˜ íšŒì›ì„ 초대할 수 있습니다."
msgid "Billings|In a seat"
msgstr ""
@@ -7518,7 +7618,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7533,15 +7633,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr "사용ìžë¥¼ 제거할 수 ì—†ìŒ"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr "유료 요금제 살펴보기"
@@ -7553,11 +7656,14 @@ msgstr ""
msgid "Billing|Groups in the Free tier are limited to %d seat"
msgid_plural "Billing|Groups in the Free tier are limited to %d seats"
-msgstr[0] "Billings|프리 ìš”ê¸ˆì œì˜ ê·¸ë£¹ì€ %d 명으로 제한ë©ë‹ˆë‹¤."
+msgstr[0] "Free í‹°ì–´ì˜ ê·¸ë£¹ì€ %d 명으로 제한ë©ë‹ˆë‹¤."
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr "Billing|표시할 사용ìžê°€ 없습니다."
@@ -7570,6 +7676,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7597,9 +7709,12 @@ msgstr "대기 ì¤‘ì¸ ìŠ¹ì¸ ìš”ì²­"
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
-msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
msgstr ""
+msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
+msgstr "ê·€í•˜ì˜ ê·¸ë£¹ì€ ìµœê·¼ 무료 요금제를 사용하ë„ë¡ ë³€ê²½ë˜ì—ˆìŠµë‹ˆë‹¤. %{over_limit_message} ë” ì´ìƒ 액세스할 필요가 없는 사용ìžë¥¼ 제거하거나 초과 제한으로 전환하여 새 회ì›ì„ 위한 ê³µê°„ì„ í™•ë³´í•  수 있습니다. 무제한 회ì›ì„ 추가하려면 유료 요금제로 %{link_start}업그레ì´ë“œ%{link_end}를 í•  수 있습니다."
+
msgid "Bitbucket Server Import"
msgstr "Bitbucket 서버ì—ì„œ 가져 오기"
@@ -7640,6 +7755,9 @@ msgstr[0] ""
msgid "Blocked issue"
msgstr "ì°¨ë‹¨ëœ ì´ìŠˆ"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr "차단"
@@ -7673,9 +7791,6 @@ msgstr "ì¼ì¹˜í•˜ëŠ” 결과가 없습니다"
msgid "BoardNewEpic|Search groups"
msgstr "그룹 검색"
-msgid "BoardNewEpic|Select a group"
-msgstr "그룹 ì„ íƒ"
-
msgid "BoardNewIssue|No matching results"
msgstr "ì¼ì¹˜í•˜ëŠ” 결과가 없습니다"
@@ -7763,9 +7878,6 @@ msgstr "ë¼ë²¨ ì„ íƒ"
msgid "BoardScope|Select milestone"
msgstr "마ì¼ìŠ¤í†¤ ì„ íƒ"
-msgid "BoardScope|Select weight"
-msgstr "가중치 ì„ íƒ"
-
msgid "BoardScope|Started"
msgstr ""
@@ -7991,7 +8103,7 @@ msgid "Branch"
msgstr "브랜치"
msgid "Branch %{branchName} was not found in this project's repository."
-msgstr "%{branchName} 브랜치는 ì´ í”„ë¡œì íŠ¸ ì €ìž¥ì†Œì— ì—†ìŠµë‹ˆë‹¤."
+msgstr "%{branchName} 브랜치는 ì´ í”„ë¡œì íŠ¸ 리í¬ì§€í† ë¦¬ì— 없습니다."
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
@@ -8342,7 +8454,7 @@ msgid "BroadcastMessages|Add broadcast message"
msgstr ""
msgid "BroadcastMessages|Add new message"
-msgstr ""
+msgstr "새 메시지 추가"
msgid "BroadcastMessages|Allow users to dismiss the broadcast message"
msgstr ""
@@ -8489,13 +8601,13 @@ msgid "Build cannot be erased"
msgstr "빌드를 지울 수 없습니다."
msgid "BuildArtifacts|An error occurred while fetching the artifacts"
-msgstr ""
+msgstr "아티팩트를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "BuildArtifacts|Loading artifacts"
-msgstr ""
+msgstr "아티팩트 로드 중"
msgid "Building your merge request… This page will update when the build is complete."
-msgstr ""
+msgstr "머지 리퀘스트를 빌드 중입니다... 빌드가 완료ë˜ë©´ 페ì´ì§€ê°€ ì—…ë°ì´íŠ¸ ë©ë‹ˆë‹¤."
msgid "Built-in"
msgstr "내장ëœ"
@@ -8837,7 +8949,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -8886,7 +8998,7 @@ msgid "CVE|CVE ID Request"
msgstr ""
msgid "CVE|Common Vulnerability Enumeration (CVE) identifiers are used to track distinct vulnerabilities in specific versions of code."
-msgstr ""
+msgstr "CVE(Common Vulnerability Enumeration) ì‹ë³„ìžëŠ” 특정 ë²„ì „ì˜ ì½”ë“œì—ì„œ 고유한 취약ì ì„ 추ì í•˜ëŠ” ë° ì‚¬ìš©ë©ë‹ˆë‹¤."
msgid "CVE|Create CVE ID Request"
msgstr ""
@@ -8933,8 +9045,8 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
-msgstr "그룹 ìƒì„± 가능:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr ""
@@ -8988,7 +9100,7 @@ msgid "Canary Ingress does not exist in the environment."
msgstr ""
msgid "Canary weight must be specified and valid range (0..100)."
-msgstr ""
+msgstr "Canary ê°€ì¤‘ì¹˜ì˜ ìœ íš¨í•œ 범위(0..100)를 지정해야 합니다."
msgid "CanaryIngress|%{boldStart}Canary:%{boldEnd} %{canary}"
msgstr ""
@@ -9320,6 +9432,9 @@ msgstr ""
msgid "Changes:"
msgstr "변경사항:"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9410,6 +9525,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "%{text}ì´(ê°€) 사용 가능한지 í™•ì¸ ì¤‘â€¦"
@@ -9466,7 +9584,7 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr "템플릿 ì„ íƒ..."
msgid "Choose a type..."
msgstr "ìœ í˜•ì„ ì„ íƒ..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "íŒŒì¼ ì„ íƒâ€¦"
@@ -9728,7 +9849,7 @@ msgid "Choose protected branch"
msgstr ""
msgid "Choose the top-level group for your repository imports."
-msgstr "저장소 ê°€ì ¸ì˜¤ê¸°ì— ëŒ€í•œ 최ìƒìœ„ ê·¸ë£¹ì„ ì„ íƒí•˜ì„¸ìš”."
+msgstr "리í¬ì§€í† ë¦¬ë¥¼ 가져오기 위해 최ìƒìœ„ ê·¸ë£¹ì„ ì„ íƒí•˜ì„¸ìš”."
msgid "Choose visibility level, enable/disable project features and their permissions, disable email notifications, and show default emoji reactions."
msgstr ""
@@ -9797,7 +9918,7 @@ msgid "CiCatalog|Released %{timeAgo} by %{author}"
msgstr ""
msgid "CiCatalog|Repositories of pipeline components available in this namespace."
-msgstr ""
+msgstr "ì´ ë„¤ìž„ìŠ¤íŽ˜ì´ìŠ¤ì— 사용 가능한 파ì´í”„ë¼ì¸ ì»´í¬ë„ŒíŠ¸ 리í¬ì§€í† ë¦¬ìž…니다."
msgid "CiCatalog|The project must contain a README.md file and a template.yml file. When enabled, the repository is available in the CI/CD Catalog."
msgstr "프로ì íŠ¸ëŠ” README.md 파ì¼ê³¼ template.yml 파ì¼ì„ í¬í•¨í•´ì•¼ 합니다. 활성화ë˜ë©´ CI/CD 카탈로그ì—ì„œ 리í¬ì§€í† ë¦¬ë¥¼ 사용할 수 있습니다."
@@ -9922,15 +10043,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -9982,9 +10103,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr "변수 행 제거"
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10006,12 +10124,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10027,9 +10157,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (모든 환경)"
-
msgid "CiVariable|All environments"
msgstr "모든 환경"
@@ -10137,19 +10264,19 @@ msgid "Clear this checkbox to use an external authentication provider instead."
msgstr ""
msgid "Clear weight"
-msgstr ""
+msgstr "가중치 삭제"
msgid "Cleared health status."
msgstr ""
msgid "Cleared weight."
-msgstr ""
+msgstr "가중치 ì‚­ì œë¨."
msgid "Clears health status."
msgstr ""
msgid "Clears weight."
-msgstr ""
+msgstr "가중치 삭제."
msgid "Click %{link_start}here%{link_end} to view the request."
msgstr ""
@@ -10187,6 +10314,9 @@ msgstr "í´ë¼ì´ì–¸íŠ¸"
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Clone"
@@ -10484,15 +10614,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10782,6 +10906,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10806,6 +10933,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11224,13 +11354,10 @@ msgid "Code Quality scans found %{findings}."
msgstr ""
msgid "Code Review"
-msgstr "코드 검토"
+msgstr "코드 리뷰"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
-msgstr ""
-
-msgid "Code Suggestions add-on"
-msgstr ""
+msgstr "코드 리뷰 분ì„ì€ ì½”ë“œ ê²€í† ì— ìžˆëŠ” 것으로 간주ë˜ëŠ” 열린 머지 리퀘스트 í…Œì´ë¸”ì„ í‘œì‹œí•©ë‹ˆë‹¤. 현재 ì´ í”„ë¡œì íŠ¸ ë°/ë˜ëŠ” í•„í„°ì— ëŒ€í•´ 검토 ì¤‘ì¸ ë¨¸ì§€ 리퀘스트가 없습니다."
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11301,31 +11428,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
-msgstr ""
-
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr ""
msgid "Collapse"
msgstr "ê°ì¶”기"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11753,9 +11880,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11801,6 +11925,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11858,7 +11985,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12074,13 +12201,16 @@ msgstr "대외비"
msgid "Configuration help"
msgstr ""
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "%{italic_start}새로운 기능%{italic_end} 메뉴 내용 구성"
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
-msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
msgstr ""
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
@@ -12146,6 +12276,9 @@ msgstr "고급 권한, 대용량 íŒŒì¼ ì €ìž¥ì†Œ, 2단계 ì¸ì¦ ë° CI/CD 설ì
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12201,7 +12334,7 @@ msgid "Configure with a merge request"
msgstr ""
msgid "Configure your environments to be deployed to specific geographical regions"
-msgstr ""
+msgstr "특정 ì§€ë¦¬ì  ì§€ì—­ì— ë°°í¬í•  환경 설정"
msgid "Confirm"
msgstr "확ì¸"
@@ -12264,7 +12397,7 @@ msgid "Confluence Cloud Workspace URL"
msgstr ""
msgid "ConfluenceService|Confluence Workspace"
-msgstr ""
+msgstr "Confluence Workspace"
msgid "ConfluenceService|Link to a Confluence Workspace from the sidebar."
msgstr ""
@@ -12288,10 +12421,10 @@ msgid "Connect a cluster"
msgstr ""
msgid "Connect all repositories"
-msgstr "모든 저장소 연결"
+msgstr "모든 리í¬ì§€í† ë¦¬ ì—°ê²°"
msgid "Connect repositories from GitHub"
-msgstr "GitHub으로부터 저장소 연결"
+msgstr "GitHub 리í¬ì§€í† ë¦¬ ì—°ê²°"
msgid "Connect your external repositories, and CI/CD pipelines will run for new commits. A GitLab project will be created with only CI/CD features enabled."
msgstr "ë‹¹ì‹ ì˜ ì™¸ë¶€ 저장소를 연결하면 CI/CD 파ì´í”„ë¼ì¸ì´ 새로운 ì»¤ë°‹ì— ëŒ€í•´ 실행ë©ë‹ˆë‹¤. GitLab 프로ì íŠ¸ëŠ” CI/CD기능만 사용하여 ìƒì„±ë©ë‹ˆë‹¤."
@@ -12317,6 +12450,9 @@ msgstr "연결 실패"
msgid "Consistency guarantee method"
msgstr "ì¼ê´€ì„± 보장 방법"
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "ê³ ê° ì§€ì› ë¬¸ì˜"
@@ -12368,7 +12504,7 @@ msgid "ContainerRegistry|-- tags"
msgstr ""
msgid "ContainerRegistry|Build an image"
-msgstr ""
+msgstr "ì´ë¯¸ì§€ 빌드"
msgid "ContainerRegistry|CLI Commands"
msgstr ""
@@ -12539,7 +12675,7 @@ msgid "ContainerRegistry|Remember to run %{docLinkStart}garbage collection%{docL
msgstr ""
msgid "ContainerRegistry|Remove repository"
-msgstr "저장소 제거"
+msgstr "리í¬ì§€í† ë¦¬ 제거"
msgid "ContainerRegistry|Remove tag"
msgid_plural "ContainerRegistry|Remove tags"
@@ -12836,6 +12972,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -12869,6 +13008,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -12881,9 +13044,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -12971,6 +13143,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13380,7 +13561,7 @@ msgid "Create a new project"
msgstr ""
msgid "Create a new repository"
-msgstr "새 저장소 만들기"
+msgstr "새 리í¬ì§€í† ë¦¬ 만들기"
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "%{protocol}ì„ (를) 통해 Pull 하거나 Push í•  ê°œì¸ ì•¡ì„¸ìŠ¤ 토í°ì„ 만드십시오."
@@ -13517,6 +13698,9 @@ msgstr "릴리스 ìƒì„±"
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -13895,9 +14079,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "Cron 시간대"
-
msgid "Cron time zone"
msgstr ""
@@ -14235,9 +14416,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14411,6 +14589,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14501,6 +14682,9 @@ msgstr "DORA4Metrics|서비스 ë³µì› ì‹œê°„ (median days)"
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14723,6 +14907,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15226,9 +15413,6 @@ msgstr "cron êµ¬ë¬¸ì„ ì‚¬ìš©í•˜ì—¬ ì‚¬ìš©ìž ì •ì˜ íŒ¨í„´ ì •ì˜"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15350,9 +15534,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr "파ì´í”„ë¼ì¸ ì‚­ì œ"
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr "프로ì íŠ¸ ì‚­ì œ"
@@ -15472,7 +15653,7 @@ msgid "Deleting the project will delete its repository and all related resources
msgstr ""
msgid "Deletion pending. This project will be deleted on %{date}. Repository and other project resources are read-only."
-msgstr "ì‚­ì œ 대기 중. ì´ í”„ë¡œì íŠ¸ëŠ” %{date}ì— ì‚­ì œë©ë‹ˆë‹¤. 저장소와 다른 프로ì íŠ¸ 리소스는 ì½ê¸° 전용입니다."
+msgstr "ì‚­ì œ 대기 중. ì´ í”„ë¡œì íŠ¸ëŠ” %{date}ì— ì‚­ì œë©ë‹ˆë‹¤. 리í¬ì§€í† ë¦¬ì™€ 다른 프로ì íŠ¸ 리소스는 ì½ê¸° 전용입니다."
msgid "DeletionSettings|Deletion protection"
msgstr "삭제 방지"
@@ -15518,7 +15699,7 @@ msgstr[0] ""
msgid "Dependencies|%d vulnerability detected"
msgid_plural "Dependencies|%d vulnerabilities detected"
-msgstr[0] ""
+msgstr[0] "%dê°œì˜ ì·¨ì•½ì„± ê°ì§€ë¨"
msgid "Dependencies|%{locationCount} locations"
msgstr ""
@@ -15568,6 +15749,9 @@ msgstr "위치 ë° ì¢…ì†ì„± 경로"
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15586,6 +15770,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15766,6 +15953,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} 기타"
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr "현재 프로ì íŠ¸"
@@ -15793,8 +15986,8 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr "ë°°í¬í‚¤ 로드"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "ë°°í¬í‚¤ê°€ 존재하지 않습니다. ìœ„ì˜ ì–‘ì‹ì„ ì´ìš©í•´ 만드세요."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "비공개ì ìœ¼ë¡œ 엑세스 가능한 ë°°í¬í‚¤"
@@ -15808,8 +16001,8 @@ msgstr "공개ì ìœ¼ë¡œ 엑세스 가능한 ë°°í¬í‚¤"
msgid "DeployKeys|Read access only"
msgstr "ì½ê¸° 엑세스 ì „ìš©"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "활성 ë°°í¬ í† í° (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
msgstr ""
@@ -15832,6 +16025,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -15892,7 +16088,7 @@ msgstr "범위"
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -15910,10 +16106,10 @@ msgstr "ì‚¬ìš©ìž ì´ë¦„"
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -15997,6 +16193,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16067,9 +16269,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16082,6 +16281,24 @@ msgstr "ë°°í¬ ID"
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16097,12 +16314,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16172,12 +16392,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr "ë””ìžì¸ 리í¬ì§€í† ë¦¬"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17139,7 +17353,7 @@ msgid "Edit Deploy Key"
msgstr "ë°°í¬ í‚¤ 편집"
msgid "Edit Geo Site"
-msgstr ""
+msgstr "Geo 사ì´íŠ¸ 수정"
msgid "Edit Group Hook"
msgstr ""
@@ -17220,7 +17434,7 @@ msgid "Edit image description"
msgstr ""
msgid "Edit in pipeline editor"
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ 편집기ì—ì„œ 편집"
msgid "Edit in single-file editor"
msgstr ""
@@ -17366,9 +17580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17411,6 +17622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "ì´ë©”ì¼"
@@ -17549,9 +17763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr "ë©”ì¼ ë¨¸ë¦¬ë§ ë° ê¼¬ë¦¬ë§ ì‚¬ìš©"
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17573,7 +17784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17687,14 +17898,11 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
msgid "Enter %{weights_link_start}weights%{weights_link_end} for storages for new repositories. Configured storages appear below."
-msgstr ""
+msgstr "새 리í¬ì§€í† ë¦¬ì˜ ì €ìž¥ê³µê°„ì— ëŒ€í•´ %{weights_link_start}가중치%{weights_link_end} ì„ ìž…ë ¥í•©ë‹ˆë‹¤. ì„¤ì •ëœ ì €ìž¥ê³µê°„ì´ ì•„ëž˜ì— ë‚˜íƒ€ë‚©ë‹ˆë‹¤."
msgid "Enter a URL for your custom emoji"
msgstr ""
@@ -17801,7 +18009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -17948,12 +18156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "ìž‘ì—…"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr "환경 ì •ì§€ì— ëŒ€í•´ ìžì„¸ížˆ 알아보기"
@@ -17999,6 +18213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18035,6 +18255,9 @@ msgstr "ì´ ìž‘ì—…ì€ ì»¤ë°‹ %{commitId}ë¡œ ì´ í™˜ê²½ì— ëŒ€í•´ %{docsStart}ì§
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr "ì´ ìž‘ì—…ì€ ì»¤ë°‹ %{commitId}ë¡œ ì´ì „ì— ì„±ê³µí•œ ë°°í¬ë¡œ %{docsStart}ì´ í™˜ê²½ì„ ë¡¤ë°±%{docsEnd} 합니다. 계ì†í•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18137,6 +18360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18805,7 +19034,7 @@ msgid "Everyone can contribute"
msgstr "모ë‘ê°€ 기여할 수 있ìŒ."
msgid "Everything on your to-do list is marked as done."
-msgstr ""
+msgstr "í•  ì¼ ëª©ë¡ì˜ 모든 í•­ëª©ì´ ì™„ë£Œë¡œ 표시ë©ë‹ˆë‹¤."
msgid "Everything you need to create a GitLab Pages site using Bridgetown"
msgstr ""
@@ -18891,6 +19120,9 @@ msgstr ""
msgid "Expand"
msgstr "펼치기"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "ëª¨ë‘ í™•ìž¥"
@@ -19039,13 +19271,13 @@ msgid "External authorization denied access to this project"
msgstr "외부 ì¸ì¦ì´ ì´ í”„ë¡œì íŠ¸ì— 대한 액세스를 거부했습니다."
msgid "External storage URL"
-msgstr ""
+msgstr "외부 저장공간 URL"
msgid "External storage authentication token"
-msgstr ""
+msgstr "외부 저장공간 ì¸ì¦ 토í°"
msgid "External storage for repository static objects"
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ ì •ì  ê°œì²´ë¥¼ 위한 외부 저장공간"
msgid "ExternalAuthorizationService|Classification label"
msgstr ""
@@ -19137,6 +19369,9 @@ msgstr ""
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19209,7 +19444,7 @@ msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
msgid "Failed to create a to-do item for the design."
-msgstr ""
+msgstr "ë””ìžì¸ì— 대한 í•  ì¼ ëª©ë¡ì„ ìƒì„±í•˜ì§€ 못했습니다."
msgid "Failed to create framework"
msgstr ""
@@ -19323,7 +19558,7 @@ msgid "Failed to load stacktrace."
msgstr ""
msgid "Failed to make repository read-only. %{reason}"
-msgstr "저장소를 ì½ê¸° 전용으로 만들지 못했습니다. %{reason}"
+msgstr "리í¬ì§€í† ë¦¬ë¥¼ ì½ê¸° 전용으로 설정하지 못했습니다. %{reason}"
msgid "Failed to mark this issue as a duplicate because referenced issue was not found."
msgstr ""
@@ -19353,7 +19588,7 @@ msgid "Failed to remove a Zoom meeting"
msgstr ""
msgid "Failed to remove a to-do item for the design."
-msgstr ""
+msgstr "ë””ìžì¸ì˜ í•  ì¼ ëª©ë¡ ì‚­ì œì— ì‹¤íŒ¨í•˜ì˜€ìŠµë‹ˆë‹¤."
msgid "Failed to remove emoji. Please try again"
msgstr ""
@@ -19791,9 +20026,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr "사용ìžë¡œ í•„í„°ë§"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -19818,9 +20050,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr "í•„í„°..."
-
msgid "Finalizing"
msgstr ""
@@ -20020,7 +20249,7 @@ msgid "For the GitLab Team to keep your subscription data up to date, this is a
msgstr ""
msgid "For the next few releases, you can go to your avatar at any time to turn the new navigation on and off."
-msgstr ""
+msgstr "ë‹¤ìŒ ëª‡ë²ˆì˜ ë°°í¬ì—서는 언제든지 아바타로 ì´ë™í•˜ì—¬ 새 íƒìƒ‰ì„ 켜고 ëŒ ìˆ˜ 있습니다."
msgid "Forbidden"
msgstr "금지ë¨"
@@ -20059,7 +20288,7 @@ msgid "ForkProject|Fork project"
msgstr ""
msgid "ForkProject|Forking a repository allows you to make changes without affecting the original project."
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ë¥¼ í¬í¬í•˜ë©´ ì›ëž˜ 프로ì íŠ¸ì— ì˜í–¥ì„ 주지 ì•Šê³  ë‚´ìš©ì„ ë³€ê²½í•  수 있습니다."
msgid "ForkProject|Internal"
msgstr ""
@@ -20125,7 +20354,7 @@ msgid "ForksDivergence|%{behindLinkStart}%{behind} %{commit_word} behind%{behind
msgstr ""
msgid "ForksDivergence|%{messages} the upstream repository."
-msgstr ""
+msgstr "업스트림 리í¬ì§€í† ë¦¬ì˜ %{messages}입니다."
msgid "ForksDivergence|Check out to a branch, and merge the changes from the upstream project's default branch. You likely need to resolve conflicts during this step."
msgstr ""
@@ -20149,7 +20378,7 @@ msgid "ForksDivergence|Source project has a limited visibility."
msgstr ""
msgid "ForksDivergence|Successfully fetched and merged from the upstream repository."
-msgstr ""
+msgstr "업스트림 리í¬ì§€í† ë¦¬ì—ì„œ 성공ì ìœ¼ë¡œ 가져오고 merge하였습니다."
msgid "ForksDivergence|The upstream changes could not be synchronized to this project due to file conflicts in the default branch. You must resolve the conflicts manually:"
msgstr ""
@@ -20188,33 +20417,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "ë˜ëŠ” GitLab Premium ë˜ëŠ” GitLab Ultimateë¡œ 업그레ì´ë“œí•  수 있습니다."
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20342,7 +20544,7 @@ msgid "Geo Settings"
msgstr "Geo 설정"
msgid "Geo Sites"
-msgstr ""
+msgstr "Geo 사ì´íŠ¸"
msgid "Geo sites"
msgstr "Geo 사ì´íŠ¸"
@@ -20368,22 +20570,22 @@ msgid "Geo|%{label} %{timeAgo}"
msgstr "Geo|%{label} %{timeAgo}"
msgid "Geo|%{label} can't be blank"
-msgstr ""
+msgstr "%{label}ì€ ë¹„ì›Œë‘˜ 수 없습니다."
msgid "Geo|%{label} should be between 1-999"
-msgstr ""
+msgstr "%{label}ì€ 1-999 사ì´ì—¬ì•¼ 합니다."
msgid "Geo|%{name} is scheduled for re-sync"
-msgstr ""
+msgstr "%{name}ì€ ìž¬ë™ê¸°í™”ê°€ 예정ë˜ì–´ 있습니다."
msgid "Geo|%{name} is scheduled for re-verify"
-msgstr ""
+msgstr "%{name}ì€ ìž¬í™•ì¸ì´ 예정ë˜ì–´ 있습니다."
msgid "Geo|%{timeAgoStr} (%{pendingEvents} events)"
msgstr "%{timeAgoStr} (%{pendingEvents} ì´ë²¤íŠ¸)"
msgid "Geo|%{title} checksum progress"
-msgstr ""
+msgstr "%{title} ì²´í¬ì„¬ 진행 중"
msgid "Geo|Add New Site"
msgstr "새 사ì´íŠ¸ 추가"
@@ -20422,25 +20624,25 @@ msgid "Geo|Allowed Geo IP should contain valid IP addresses"
msgstr "í—ˆìš©ëœ ì§€ì—­ IPì—는 유효한 IP 주소가 í¬í•¨ë˜ì–´ì•¼ 합니다."
msgid "Geo|Checksummed"
-msgstr ""
+msgstr "ì²´í¬ì„¬ë¨"
msgid "Geo|Choose specific groups or storage shards"
-msgstr ""
+msgstr "특정 그룹 í˜¹ì€ ìŠ¤í† ë¦¬ì§€ 샤드 ì„ íƒ"
msgid "Geo|Comma-separated, e.g. '1.1.1.1, 2.2.2.0/24'"
msgstr "쉼표로 구분ë¨(예시: '1.1.1.1, 2.2.2.0/24')"
msgid "Geo|Configure various settings for your %{siteType} site. %{linkStart}Learn more%{linkEnd}"
-msgstr ""
+msgstr "Geo| %{siteType} 사ì´íŠ¸ì— 대한 다양한 ì„¤ì •ì„ êµ¬ì„±í•©ë‹ˆë‹¤. %{linkStart}ìžì„¸ížˆ 알아보기%{linkEnd}"
msgid "Geo|Connection timeout"
msgstr "연결 시간 초과"
msgid "Geo|Connection timeout can't be blank"
-msgstr ""
+msgstr "ì—°ê²° 제한 ì‹œê°„ì€ ë¹„ì›Œë‘˜ 수 없습니다"
msgid "Geo|Connection timeout must be a number"
-msgstr ""
+msgstr "ì—°ê²° 제한 ì‹œê°„ì€ ìˆ«ìžì—¬ì•¼ 합니다"
msgid "Geo|Connection timeout should be between 1-120"
msgstr ""
@@ -20449,7 +20651,7 @@ msgid "Geo|Consult Geo troubleshooting information"
msgstr "Geo 문제 í•´ê²° 문서 확ì¸í•˜ê¸°"
msgid "Geo|Container repositories synchronization concurrency limit"
-msgstr ""
+msgstr "컨테ì´ë„ˆ 리í¬ì§€í† ë¦¬ ë™ê¸°í™” ë™ì‹œì„± 제한"
msgid "Geo|Could not remove tracking entry for an existing project."
msgstr ""
@@ -20473,7 +20675,7 @@ msgid "Geo|Edit %{siteType} site"
msgstr ""
msgid "Geo|Edit Geo Site"
-msgstr ""
+msgstr "Geo 사ì´íŠ¸ 수정"
msgid "Geo|Edit your search and try again."
msgstr ""
@@ -20491,7 +20693,7 @@ msgid "Geo|File synchronization concurrency limit"
msgstr ""
msgid "Geo|Filter Geo sites"
-msgstr ""
+msgstr "Geo 사ì´íŠ¸ë¡œ í•„í„°ë§"
msgid "Geo|Filter by name"
msgstr "ì´ë¦„으로 í•„í„°ë§"
@@ -20500,43 +20702,43 @@ msgid "Geo|Filter by status"
msgstr "ìƒíƒœë¡œ í•„í„°ë§"
msgid "Geo|Geo Settings"
-msgstr ""
+msgstr "Geo 설정"
msgid "Geo|Geo Status"
-msgstr ""
+msgstr "Geo ìƒíƒœ"
msgid "Geo|Geo allows you to choose specific groups or storage shards to replicate."
-msgstr ""
+msgstr "Geo를 사용하면 복제할 특정 그룹 ë˜ëŠ” 스토리지 샤드를 ì„ íƒí•  수 있습니다."
msgid "Geo|Geo can replicate objects stored in Object Storage (AWS S3, or other compatible object storage)."
-msgstr ""
+msgstr "Geo는 개체 스토리지(AWS S3 ë˜ëŠ” 기타 호환 가능한 개체 스토리지)ì— ì €ìž¥ëœ ê°œì²´ë¥¼ 복제할 수 있습니다."
msgid "Geo|Geo sites"
msgstr "Geo 사ì´íŠ¸"
msgid "Geo|Geo sites are paused using a command run on the site"
-msgstr ""
+msgstr "Geo 사ì´íŠ¸ëŠ” 사ì´íŠ¸ì—ì„œ 실행ë˜ëŠ” ëª…ë ¹ì„ ì‚¬ìš©í•˜ì—¬ ì¼ì‹œ 중지ë©ë‹ˆë‹¤"
msgid "Geo|Go to the primary site"
-msgstr ""
+msgstr "프ë¼ì´ë¨¸ë¦¬ 사ì´íŠ¸ë¡œ ì´ë™"
msgid "Geo|Groups to synchronize"
-msgstr ""
+msgstr "ë™ê¸°í™” í•  그룹"
msgid "Geo|Healthy"
-msgstr ""
+msgstr "ì •ìƒ"
msgid "Geo|If enabled, GitLab will handle Object Storage replication using Geo."
-msgstr ""
+msgstr "만약 í™œì„±í™”ëœ ê²½ìš°, GitLabì€ Geo를 사용하여 개체 스토리지 복제를 처리합니다."
msgid "Geo|If you want to make changes, you must visit the primary site."
msgstr ""
msgid "Geo|In progress"
-msgstr ""
+msgstr "진행 중"
msgid "Geo|Internal URL"
-msgstr ""
+msgstr "내부 URL"
msgid "Geo|Internal URL (optional)"
msgstr ""
@@ -20551,43 +20753,43 @@ msgid "Geo|Last event ID processed"
msgstr ""
msgid "Geo|Last repository check run"
-msgstr ""
+msgstr "마지막 리í¬ì§€í† ë¦¬ ì ê²€ 실행"
msgid "Geo|Last successful sync"
-msgstr ""
+msgstr "마지막으로 성공한 ë™ê¸°í™”"
msgid "Geo|Last sync attempt"
-msgstr ""
+msgstr "마지막 ë™ê¸°í™” ì‹œë„"
msgid "Geo|Last time verified"
-msgstr ""
+msgstr "마지막으로 ì¸ì¦ë¨"
msgid "Geo|Learn more about Geo"
-msgstr ""
+msgstr "Geoì— ëŒ€í•´ ë” ìžì„¸ížˆ 알아보기"
msgid "Geo|Learn more about Geo site statuses"
-msgstr ""
+msgstr "Geo 사ì´íŠ¸ ìƒíƒœì— 대해 ë” ìžì„¸ížˆ 알아보기"
msgid "Geo|Limit the number of concurrent operations this secondary site can run in the background."
-msgstr ""
+msgstr "ì´ ì„¸ì»¨ë”리 사ì´íŠ¸ê°€ 백그ë¼ìš´ë“œì—ì„œ 실행할 수 있는 ë™ì‹œ ìž‘ì—… 수를 제한합니다."
msgid "Geo|Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
-msgstr ""
+msgstr "íŒ€ì˜ ëª¨ë“  구성ì›ì´ ìž¥ì†Œì— ê´€ê³„ì—†ì´ ìƒì‚°ì„±ì„ ë†’ì¼ ìˆ˜ 있게 í•´ì¤ë‹ˆë‹¤. GitLab Geo는 GitLab ì¸ìŠ¤í„´ìŠ¤ì˜ ì½ê¸° ì „ìš© 미러를 ìƒì„±í•˜ì—¬ 대규모 ë ˆí¬ì§€í„°ë¦¬ë¥¼ clone 하고 fetch í•˜ëŠ”ë° ê±¸ë¦¬ëŠ” ì‹œê°„ì„ ì¤„ì—¬ì¤ë‹ˆë‹¤."
msgid "Geo|Minimum interval in days"
-msgstr ""
+msgstr "최소 간격(ì¼)"
msgid "Geo|Must match with the %{codeStart}external_url%{codeEnd} in %{codeStart}/etc/gitlab/gitlab.rb%{codeEnd}."
msgstr ""
msgid "Geo|Must match with the %{codeStart}geo_node_name%{codeEnd} in %{codeStart}/etc/gitlab/gitlab.rb%{codeEnd}."
-msgstr ""
+msgstr "%{codeStart}/etc/gitlab/gitlab.rb%{codeEnd}ì˜ %{codeStart}geo_node_name%{codeEnd}와 ì¼ì¹˜í•´ì•¼ 합니다."
msgid "Geo|Never"
-msgstr ""
+msgstr "ì—†ìŒ"
msgid "Geo|Next sync scheduled at"
-msgstr ""
+msgstr "ë‹¤ìŒ ë™ê¸°í™” 시간"
msgid "Geo|No %{replicable_type} were found. If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
msgstr ""
@@ -20599,25 +20801,25 @@ msgid "Geo|No Geo site found"
msgstr "Geo 사ì´íŠ¸ë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ"
msgid "Geo|No available replication slots"
-msgstr ""
+msgstr "사용 가능한 복제 슬롯 ì—†ìŒ"
msgid "Geo|Nothing found…"
-msgstr ""
+msgstr "ì•„ë¬´ê²ƒë„ ì°¾ì„ ìˆ˜ ì—†ìŒ"
msgid "Geo|Nothing to checksum"
-msgstr ""
+msgstr "ì²´í¬ì„¬í•  항목 ì—†ìŒ"
msgid "Geo|Nothing to synchronize"
-msgstr ""
+msgstr "ë™ê¸°í™”í•  항목 ì—†ìŒ"
msgid "Geo|Nothing to verify"
-msgstr ""
+msgstr "확ì¸í•  사항 ì—†ìŒ"
msgid "Geo|Object Storage replication"
-msgstr ""
+msgstr "개체 스토리지 복제"
msgid "Geo|Offline"
-msgstr ""
+msgstr "오프ë¼ì¸"
msgid "Geo|Pending synchronization"
msgstr "대기 ì¤‘ì¸ ë™ê¸°í™”"
@@ -20626,73 +20828,73 @@ msgid "Geo|Pending verification"
msgstr "ì¸ì¦ 대기 중"
msgid "Geo|Primary"
-msgstr ""
+msgstr "프ë¼ì´ë¨¸ë¦¬"
msgid "Geo|Primary site"
-msgstr ""
+msgstr "프ë¼ì´ë¨¸ë¦¬ 사ì´íŠ¸"
msgid "Geo|Project (ID: %{project_id}) no longer exists on the primary. It is safe to remove this entry, as this will not remove any data on disk."
msgstr ""
msgid "Geo|Projects in certain groups"
-msgstr ""
+msgstr "특정 ê·¸ë£¹ì˜ í”„ë¡œì íŠ¸"
msgid "Geo|Projects in certain storage shards"
-msgstr ""
+msgstr "특정 스토리지 ìƒ¤ë“œì˜ í”„ë¡œì íŠ¸"
msgid "Geo|Queued"
-msgstr ""
+msgstr "대기 중"
msgid "Geo|Re-verification interval"
-msgstr ""
+msgstr "재ì¸ì¦ 간격"
msgid "Geo|Remove"
-msgstr ""
+msgstr "제거"
msgid "Geo|Remove %{siteType} site"
msgstr ""
msgid "Geo|Remove entry"
-msgstr ""
+msgstr "항목 제거"
msgid "Geo|Remove site"
-msgstr ""
+msgstr "사ì´íŠ¸ 제거"
msgid "Geo|Remove tracking database entry"
msgstr ""
msgid "Geo|Removing a Geo site stops the synchronization to and from that site. Are you sure?"
-msgstr ""
+msgstr "Geo 사ì´íŠ¸ë¥¼ 제거하면 해당 사ì´íŠ¸ì™€ì˜ ë™ê¸°í™”ê°€ 중지ë©ë‹ˆë‹¤. 확실합니까?"
msgid "Geo|Replicated data is verified with the secondary site(s) using checksums"
-msgstr ""
+msgstr "ë³µì œëœ ë°ì´í„°ëŠ” ì²´í¬ì„¬ì„ 사용하여 세컨ë”리 사ì´íŠ¸ì—ì„œ ì¸ì¦ë©ë‹ˆë‹¤."
msgid "Geo|Replicated data is verified with the secondary site(s) using checksums."
-msgstr ""
+msgstr "ë³µì œëœ ë°ì´í„°ëŠ” ì²´í¬ì„¬ì„ 사용하여 세컨ë”리 사ì´íŠ¸ì—ì„œ ì¸ì¦ë©ë‹ˆë‹¤."
msgid "Geo|Replication Details"
-msgstr ""
+msgstr "레플리케ì´ì…˜ 세부 ì •ë³´"
msgid "Geo|Replication slot WAL"
-msgstr ""
+msgstr "레플리케ì´ì…˜ 슬롯 WAL"
msgid "Geo|Replication slots"
-msgstr ""
+msgstr "레플리케ì´ì…˜ 슬롯"
msgid "Geo|Replication status"
-msgstr ""
+msgstr "레플리케ì´ì…˜ ìƒíƒœ"
msgid "Geo|Replication summary"
-msgstr ""
+msgstr "레플리케ì´ì…˜ 요약"
msgid "Geo|Repository synchronization concurrency limit"
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ ë™ê¸°í™” ë™ì‹œ 실행 제한"
msgid "Geo|Resync"
-msgstr ""
+msgstr "재ë™ê¸°í™”"
msgid "Geo|Resync all"
-msgstr ""
+msgstr "ì „ì²´ 재ë™ê¸°í™”"
msgid "Geo|Resync all %{projects_count} projects"
msgstr ""
@@ -20701,64 +20903,64 @@ msgid "Geo|Resync all %{total}%{replicableType}"
msgstr ""
msgid "Geo|Resync project"
-msgstr ""
+msgstr "프로ì íŠ¸ 재ë™ê¸°í™”"
msgid "Geo|Retry count"
msgstr "ìž¬ì‹œë„ íšŸìˆ˜"
msgid "Geo|Reverify"
-msgstr ""
+msgstr "재ì¸ì¦"
msgid "Geo|Reverify all"
-msgstr ""
+msgstr "ì „ì²´ 재ì¸ì¦"
msgid "Geo|Reverify all %{projects_count} projects"
msgstr ""
msgid "Geo|Reverify project"
-msgstr ""
+msgstr "프로ì íŠ¸ 재ì¸ì¦"
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary site."
-msgstr ""
+msgstr "레플리케ì´ì…˜ ìƒíƒœë¥¼ 리뷰하고, í•­ëª©ì„ í”„ë¼ì´ë¨¸ë¦¬ 사ì´íŠ¸ì™€ 재ë™ê¸°í™” ë° ìž¬ì¸ì¦í•©ë‹ˆë‹¤."
msgid "Geo|Secondary"
-msgstr ""
+msgstr "세컨ë”리"
msgid "Geo|Secondary site"
-msgstr ""
+msgstr "세컨ë”리 사ì´íŠ¸"
msgid "Geo|Select groups to replicate"
-msgstr ""
+msgstr "복제할 그룹 ì„ íƒ"
msgid "Geo|Select shards to replicate"
-msgstr ""
+msgstr "복제할 샤드 ì„ íƒ"
msgid "Geo|Selective (%{syncLabel})"
-msgstr ""
+msgstr "ì„ íƒì  (%{syncLabel})"
msgid "Geo|Selective synchronization"
-msgstr ""
+msgstr "ì„ íƒì  ë™ê¸°í™”"
msgid "Geo|Set the timeout in seconds to send a secondary site status to the primary and IPs allowed for the secondary sites."
-msgstr ""
+msgstr "프ë¼ì´ë¨¸ë¦¬ 사ì´íŠ¸ ë˜ëŠ” 세컨ë”리 사ì´íŠ¸ì— í—ˆìš©ëœ IPì— ì„¸ì»¨ë”리 사ì´íŠ¸ ìƒíƒœë¥¼ 보내기 위해 제한시간(ì´ˆ)ì„ ì„¤ì •í•˜ì‹­ì‹œì˜¤."
msgid "Geo|Set verification limit and frequency."
-msgstr ""
+msgstr "ì¸ì¦ 제한 ë° ë¹ˆë„를 설정하십시오."
msgid "Geo|Set what should be replicated by this secondary site."
-msgstr ""
+msgstr "ì´ ì„¸ì»¨ë”리 사ì´íŠ¸ì—ì„œ 복제해야 하는 í•­ëª©ì„ ì„¤ì •í•˜ì‹­ì‹œì˜¤."
msgid "Geo|Shards to synchronize"
-msgstr ""
+msgstr "ë™ê¸°í™” í•  샤드"
msgid "Geo|Show more"
-msgstr ""
+msgstr "ë”보기"
msgid "Geo|Site name can't be blank"
-msgstr ""
+msgstr "사ì´íŠ¸ ì´ë¦„ì€ ë¹„ì›Œë‘˜ 수 없습니다."
msgid "Geo|Site name should be between 1 and 255 characters"
-msgstr ""
+msgstr "사ì´íŠ¸ ì´ë¦„ì€ 1~255ìž ì‚¬ì´ì—¬ì•¼ 합니다."
msgid "Geo|Site's status was updated %{timeAgo}."
msgstr "사ì´íŠ¸ì˜ ìƒíƒœê°€ %{timeAgo} ì „ ì—…ë°ì´íŠ¸ ë˜ì—ˆìŠµë‹ˆë‹¤."
@@ -20767,139 +20969,139 @@ msgid "Geo|Status"
msgstr "ìƒíƒœ"
msgid "Geo|Storage config"
-msgstr ""
+msgstr "스토리지 설정"
msgid "Geo|Synced"
msgstr "ë™ê¸°í™” ë¨"
msgid "Geo|Synchronization"
-msgstr ""
+msgstr "ë™ê¸°í™”"
msgid "Geo|Synchronization failed - %{error}"
msgstr "ë™ê¸°í™” 실패 - %{error}"
msgid "Geo|Synchronization settings"
-msgstr ""
+msgstr "ë™ê¸°í™” 설정"
msgid "Geo|Synchronization status"
-msgstr ""
+msgstr "ë™ê¸°í™” ìƒíƒœ"
msgid "Geo|The URL of the primary site that is used internally by the secondary sites."
-msgstr ""
+msgstr "세컨ë”리 사ì´íŠ¸ì—ì„œ 내부ì ìœ¼ë¡œ 사용하는 기본 사ì´íŠ¸ì˜ URL."
msgid "Geo|The URL of the secondary site that is used internally by the primary site."
-msgstr ""
+msgstr "기본 사ì´íŠ¸ì—ì„œ 내부ì ìœ¼ë¡œ 사용하는 세컨ë”리 사ì´íŠ¸ì˜ URL."
msgid "Geo|The database is currently %{db_lag} behind the primary site."
-msgstr ""
+msgstr "ë°ì´í„°ë² ì´ìŠ¤ëŠ” 현재 기본 사ì´íŠ¸ë³´ë‹¤ %{db_lag}분 늦습니다."
msgid "Geo|The site is currently %{minutes_behind} behind the primary site."
-msgstr ""
+msgstr "사ì´íŠ¸ëŠ” 현재 기본 사ì´íŠ¸ë³´ë‹¤ %{minutes_behind}분 늦습니다."
msgid "Geo|There are no %{replicable_type} to show"
-msgstr ""
+msgstr "표시할 %{replicable_type} ì´ ì—†ìŠµë‹ˆë‹¤"
msgid "Geo|There are no %{replicable} to show"
msgstr ""
msgid "Geo|There was an error deleting the Geo Site"
-msgstr ""
+msgstr "Geo 사ì´íŠ¸ë¥¼ 삭제하는 ì¤‘ì— ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
msgid "Geo|There was an error fetching the Geo Settings"
-msgstr ""
+msgstr "Geo ì„¤ì •ì„ ê°€ì ¸ì˜¤ëŠ” ì¤‘ì— ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
msgid "Geo|There was an error fetching the Geo Sites"
msgstr "Geo 사ì´íŠ¸ë¥¼ 가져오는 ì¤‘ì— ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "Geo|There was an error fetching the Sites's Groups"
-msgstr ""
+msgstr "사ì´íŠ¸ ê·¸ë£¹ì„ ê°€ì ¸ì˜¤ëŠ” ì¤‘ì— ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "Geo|There was an error saving this Geo Site"
msgstr "Geo 사ì´íŠ¸ë¥¼ 저장하는 ì¤‘ì— ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "Geo|There was an error updating the Geo Settings"
-msgstr ""
+msgstr "Geo ì„¤ì •ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” ì¤‘ì— ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
msgstr "ì´ GitLab ì¸ìŠ¤í„´ìŠ¤ëŠ” %{insufficient_license} ìš”ê¸ˆì œì— ê°€ìž…ë˜ì–´ 있습니다. Geo는 최소한 Premium 구ë…ì´ ìžˆëŠ” 사용ìžë§Œ 사용할 수 있습니다."
msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
-msgstr ""
+msgstr "ì´ê²ƒì€ 모든 %{replicableType}ì„(를) 재ë™ê¸°í™”합니다. 완료하는 ë° ì‹œê°„ì´ ê±¸ë¦´ 수 있습니다. ì •ë§ë¡œ 진행하시겠습니까?"
msgid "Geo|This will resync all projects. It may take some time to complete. Are you sure you want to continue?"
-msgstr ""
+msgstr "ì´ê²ƒì€ 모든 프로ì íŠ¸ë¥¼ 재ë™ê¸°í™”합니다. 완료하는 ë° ì‹œê°„ì´ ê±¸ë¦´ 수 있습니다. ì •ë§ë¡œ 진행하시겠습니까?"
msgid "Geo|This will reverify all projects. It may take some time to complete. Are you sure you want to continue?"
-msgstr ""
+msgstr "ì´ê²ƒì€ 모든 프로ì íŠ¸ë¥¼ 재ì¸ì¦í•©ë‹ˆë‹¤. 완료하는 ë° ì‹œê°„ì´ ê±¸ë¦´ 수 있습니다. ì •ë§ë¡œ 진행하시겠습니까?"
msgid "Geo|Time in seconds"
-msgstr ""
+msgstr "시간 (초)"
msgid "Geo|Tracking database entry will be removed. Are you sure?"
-msgstr ""
+msgstr "ë°ì´í„°ë² ì´ìŠ¤ 항목 추ì ì´ 제거ë©ë‹ˆë‹¤. 확실합니까?"
msgid "Geo|Tracking entry for project (%{project_id}) was successfully removed."
-msgstr ""
+msgstr "프로ì íŠ¸ %{project_id}ì— ëŒ€í•œ 항목 추ì ì´ 성공ì ìœ¼ë¡œ 제거ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Geo|Tuning settings"
-msgstr ""
+msgstr "설정 조정"
msgid "Geo|URL can't be blank"
-msgstr ""
+msgstr "URLì€ ë¹„ì›Œë‘˜ 수 없습니다"
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
-msgstr ""
+msgstr "URLì€ ìœ íš¨í•œ URLì´ì–´ì•¼ 합니다 (예: https://gitlab.com)"
msgid "Geo|Undefined"
-msgstr ""
+msgstr "ì •ì˜ë˜ì§€ ì•ŠìŒ"
msgid "Geo|Unhealthy"
-msgstr ""
+msgstr "비정ìƒ"
msgid "Geo|Unknown"
-msgstr ""
+msgstr "ì•Œ 수 ì—†ìŒ"
msgid "Geo|Updated %{timeAgo}"
msgstr "%{timeAgo} ì „ ì—…ë°ì´íŠ¸ ë¨"
msgid "Geo|Verification"
-msgstr ""
+msgstr "ê²€ì¦"
msgid "Geo|Verification concurrency limit"
-msgstr ""
+msgstr "ê²€ì¦ ë™ì‹œì„± 제한"
msgid "Geo|Verification failed - %{error}"
msgstr "í™•ì¸ ì‹¤íŒ¨- %{error}"
msgid "Geo|Verification information"
-msgstr ""
+msgstr "ê²€ì¦ ì •ë³´"
msgid "Geo|Verification status"
-msgstr ""
+msgstr "ê²€ì¦ ìƒíƒœ"
msgid "Geo|Verified"
-msgstr ""
+msgstr "ê²€ì¦ë¨"
msgid "Geo|Waiting for scheduler"
msgstr "스케줄러 대기 중"
msgid "Geo|With GitLab Geo, you can install a special read-only and replicated instance anywhere."
-msgstr ""
+msgstr "GitLab Geo를 사용하면, ì–´ë””ì—나 특별한 ì½ê¸° ì „ìš© 복제 ì¸ìŠ¤í„´ìŠ¤ë¥¼ 설치할 수 있습니다."
msgid "Geo|You are on a secondary, %{b_open}read-only%{b_close} Geo site."
-msgstr ""
+msgstr "ë‹¹ì‹ ì€ ì„¸ì»¨ë”리, %{b_open}ì½ê¸° ì „ìš©%{b_close} Geo 사ì´íŠ¸ì— 있습니다."
msgid "Geo|You may be able to make a limited amount of changes or perform a limited amount of actions on this page."
-msgstr ""
+msgstr "ì´ íŽ˜ì´ì§€ì—ì„œ ì¼ì • í•œë„만í¼ë§Œ 변경 ë˜ëŠ” ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있습니다."
msgid "Geo|misconfigured"
-msgstr ""
+msgstr "잘못 설정ë¨"
msgid "Geo|primary"
-msgstr ""
+msgstr "프ë¼ì´ë¨¸ë¦¬"
msgid "Geo|secondary"
-msgstr ""
+msgstr "세컨ë”리"
msgid "Get a free instance review"
msgstr ""
@@ -20907,6 +21109,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -20938,7 +21146,7 @@ msgid "Git global setup"
msgstr ""
msgid "Git repository URL"
-msgstr "Git 저장소 URL"
+msgstr "Git 리í¬ì§€í† ë¦¬ URL"
msgid "Git revision"
msgstr "Git 리비전"
@@ -20962,13 +21170,13 @@ msgid "GitAbuse|Excluded users"
msgstr "ì œì™¸ëœ ì‚¬ìš©ìž"
msgid "GitAbuse|Number of repositories"
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ 갯수"
msgid "GitAbuse|Number of repositories can't be blank. Set to 0 for no limit."
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ 갯수는 비워둘 수 없습니다. ì œí•œì´ ì—†ëŠ” 경우 0으로 설정합니다."
msgid "GitAbuse|Number of repositories must be a number."
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ 갯수는 숫ìžì´ì–´ì•¼ 합니다."
msgid "GitAbuse|Number of repositories should be between %{minNumRepos}-%{maxNumRepos}."
msgstr ""
@@ -21234,6 +21442,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21249,6 +21460,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21264,12 +21478,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr "Gitaly 서버"
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21390,7 +21598,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr "%{time_ago} ì „ 엑세스 권한 부여ë¨"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21429,6 +21640,9 @@ msgstr "%{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr "%{count}ê°œì˜ ê¸°ë³¸ 결과가 제공ë˜ì—ˆìŠµë‹ˆë‹¤. 위/아래 화살표 키를 사용하여 검색 결과를 íƒìƒ‰í•˜ì„¸ìš”."
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21441,6 +21655,9 @@ msgstr "닫기"
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "그룹"
@@ -21510,9 +21727,6 @@ msgstr "검색"
msgid "GlobalSearch|Search GitLab"
msgstr "GitLab 검색"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "프로ì íŠ¸, ì´ìŠˆ, 기타 검색"
@@ -21543,6 +21757,9 @@ msgstr "검색 ìžë™ 완성 ì œì•ˆì„ ê°€ì ¸ì˜¤ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠ
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "입력하고 엔터 키를 눌러 검색하세요."
@@ -21673,7 +21890,7 @@ msgid "Go to releases"
msgstr "릴리스로 ì´ë™"
msgid "Go to repository charts"
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ 차트로 ì´ë™"
msgid "Go to repository graph"
msgstr "리í¬ì§€í† ë¦¬ 그래프로 ì´ë™"
@@ -21783,6 +22000,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "GitLabì— ë¶€ì—¬ëœ ìŠ¹ì¸ì„ 취소합니다. ì´ê²ƒì´ 서비스 ê³„ì •ì„ ë¬´íš¨í™”í•˜ì§€ëŠ” 않습니다."
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -21798,7 +22021,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr "그룹 아바타"
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "그룹 설명 (ì„ íƒ ì‚¬í•­)"
@@ -21975,9 +22201,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22353,7 +22576,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22542,8 +22765,8 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "ê·¸ë£¹ì€ ì—¬ëŸ¬ 프로ì íŠ¸ì˜ 모ìŒìž…니다."
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
msgid "GroupsEmptyState|Create new project"
msgstr "GroupsEmptyState|새 프로ì íŠ¸ ìƒì„±"
@@ -22554,8 +22777,8 @@ msgstr "GroupsEmptyState|새 하위 그룹 만들기"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "GroupsEmptyState|ê·¸ë£¹ì€ ì—¬ëŸ¬ 프로ì íŠ¸ì™€ 구성ì›ì„ 관리하는 가장 ì¢‹ì€ ë°©ë²•ìž…ë‹ˆë‹¤."
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "프로ì íŠ¸ë¥¼ ê·¸ë£¹ì— êµ¬ì„±í•˜ë©´, 마치 í´ë”처럼 ë™ìž‘합니다."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
msgid "GroupsEmptyState|No archived projects."
msgstr ""
@@ -22572,9 +22795,6 @@ msgstr "GroupsEmptyState|하위 그룹ì´ë‚˜ 프로ì íŠ¸ê°€ 없습니다."
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "GroupsEmptyState|프로ì íŠ¸ëŠ” 코드, 액세스 문제, Wiki ë° Gitlabì˜ ê¸°íƒ€ ê¸°ëŠ¥ì„ ì €ìž¥í•  수 있는 곳입니다."
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "그룹 구성ì›ì˜ 사용 ê¶Œí•œì„ ê´€ë¦¬í•˜ê³  ê·¸ë£¹ì˜ ê° í”„ë¡œì íŠ¸ì— ì ‘ê·¼ í•  수 있습니다."
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "GroupsEmptyState|ì´ ê·¸ë£¹ì— í•˜ìœ„ 그룹ì´ë‚˜ 프로ì íŠ¸ë¥¼ 만드는 ë° í•„ìš”í•œ ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤. 새 하위 그룹ì´ë‚˜ 프로ì íŠ¸ë¥¼ 만들려면 ì´ ê·¸ë£¹ì˜ ì†Œìœ ìžì—게 문ì˜í•˜ì‹­ì‹œì˜¤."
@@ -22896,7 +23116,7 @@ msgid "HarborRegistry|With the Harbor Registry, every project can have its own s
msgstr ""
msgid "Hashed Storage must be enabled to use Geo"
-msgstr ""
+msgstr "Geo를 사용하려면 해시 스토리지를 활성화해야 합니다."
msgid "Hashed repository storage paths"
msgstr ""
@@ -22994,6 +23214,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23256,9 +23479,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr "기존 리í¬ì§€í† ë¦¬ì— GitLab CI를 사용하고 싶습니다."
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23298,6 +23518,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23481,6 +23707,12 @@ msgstr "ê²°ì œ 수단 확ì¸"
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23724,7 +23956,7 @@ msgid "Import issues"
msgstr "ì´ìŠˆ 가져오기"
msgid "Import multiple repositories by uploading a manifest file."
-msgstr "manifest 파ì¼ì„ 업로드하여 ì—¬ëŸ¬ê°œì˜ ì €ìž¥ì†Œë¥¼ 가져오세요."
+msgstr "manifest 파ì¼ì„ 업로드하여 ì—¬ëŸ¬ê°œì˜ ë¦¬í¬ì§€í† ë¦¬ë¥¼ 가져오세요."
msgid "Import project"
msgstr "프로ì íŠ¸ 가져오기"
@@ -23748,13 +23980,13 @@ msgid "Import projects from Gitea"
msgstr ""
msgid "Import repositories from Bitbucket Server"
-msgstr "Bitbucket 서버ì—ì„œ 저장소 가져오기"
+msgstr "Bitbucket 서버ì—ì„œ 리í¬ì§€í† ë¦¬ 가져오기"
msgid "Import repositories from GitHub"
-msgstr "GitHub으로 부터 저장소 가져오기"
+msgstr "GitHub으로 부터 리í¬ì§€í† ë¦¬ 가져오기"
msgid "Import repository"
-msgstr "저장소 가져 오기"
+msgstr "리í¬ì§€í† ë¦¬ 가져 오기"
msgid "Import requirements"
msgstr ""
@@ -23889,7 +24121,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -23916,6 +24148,12 @@ msgstr "Import|저장소를 ìž„í¬íŠ¸ í•  수 없습니다. "
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -23958,381 +24196,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr "무료 게스트 사용ìž"
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
-msgstr ""
-
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
+msgstr "iOS용 빌드 방법 알아보기"
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr "Ticketmaster는 CI 구축 ì‹œê°„ì„ 15ë°° 단축했습니다."
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24348,66 +24277,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "외부 리í¬ì§€í† ë¦¬ ì—°ê²°"
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "리í¬ì§€í† ë¦¬ 미러ë§"
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24837,6 +24715,14 @@ msgstr "ì¸ë¼ì¸"
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+
msgid "Input host keys manually"
msgstr "호스트 키를 수ë™ìœ¼ë¡œ ìž…ë ¥"
@@ -25192,6 +25078,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25228,15 +25117,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "주기 패턴"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25318,9 +25201,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr "무효화ë¨"
@@ -25427,7 +25307,7 @@ msgid "InviteMembersModal|Create issues for your new team member to work on (opt
msgstr ""
msgid "InviteMembersModal|During your trial, you can invite as many members to %{groupName} as you like. When the trial ends, you'll have a maximum of %{dashboardLimit} members on the Free tier. To get more members, %{linkStart}upgrade to a paid plan%{linkEnd}."
-msgstr ""
+msgstr "ì²´í—˜ 기간 ë™ì•ˆ ì›í•˜ëŠ” ë§Œí¼ ë§Žì€ íšŒì›ì„ %{groupName} ì— ì´ˆëŒ€í•  수 있습니다. í‰ê°€íŒì´ 종료ë˜ë©´ 프리 í‹°ì–´ì— ìµœëŒ€ %{dashboardLimit} 구성ì›ì´ ìžˆì„ ìˆ˜ 있습니다. ë” ë§Žì€ íšŒì›ì„ 확보하려면 %{linkStart} 유료 요금제로 업그레ì´ë“œí•˜ì‹­ì‹œì˜¤%{linkEnd}."
msgid "InviteMembersModal|GitLab is better with colleagues!"
msgstr ""
@@ -25652,18 +25532,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type}ì´ %{created_at}ì— ìƒì„±ë¨. ìž‘ì„±ìž "
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "%{created_at}ì— ìƒì„±ë¨ ìž‘ì„±ìž "
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25719,7 +25593,7 @@ msgid "Issue cannot be found."
msgstr ""
msgid "Issue created from vulnerability %{vulnerability_link}"
-msgstr ""
+msgstr "ì·¨ì•½ì  %{vulnerability_link}ì—ì„œ ìƒì„±ëœ ì´ìŠˆ"
msgid "Issue creation requests"
msgstr ""
@@ -25794,7 +25668,7 @@ msgid "IssueAnalytics|Status"
msgstr ""
msgid "IssueAnalytics|Weight"
-msgstr ""
+msgstr "가중치"
msgid "IssueBoards|Board"
msgstr "보드"
@@ -25913,10 +25787,22 @@ msgstr "ì—í”½ì´ í• ë‹¹ë˜ì§€ ì•Šì€ ì´ìŠˆ"
msgid "Issues, merge requests, pushes, and comments."
msgstr "ì´ìŠˆ, 머지 리퀘스트, 푸시 ë° ëŒ“ê¸€."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
+msgstr ""
+
+msgid "IssuesAnalytics|Closed"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -25925,16 +25811,23 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -25982,6 +25875,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr "ì´í„°ë ˆì´ì…˜"
@@ -26244,7 +26140,7 @@ msgid "JiraConnect|Create branch for Jira issue %{jiraIssue}"
msgstr ""
msgid "JiraConnect|Enable public key storage"
-msgstr ""
+msgstr "공개 키 저장소 활성화"
msgid "JiraConnect|Ensure your instance URL is correct and your instance is configured correctly. %{linkStart}Learn more%{linkEnd}."
msgstr ""
@@ -26318,6 +26214,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26816,6 +26715,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -26867,6 +26769,9 @@ msgstr ""
msgid "Job|Run again"
msgstr "다시 실행"
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -26963,9 +26868,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27226,9 +27128,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr "최근 파ì´í”„ë¼ì¸"
-
msgid "Last Seen"
msgstr ""
@@ -27325,6 +27224,9 @@ msgstr "푸쉬: "
msgid "LastPushEvent|at"
msgstr "at"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "최근 변경사항"
@@ -27386,7 +27288,7 @@ msgid "Learn more about Needs relationships"
msgstr ""
msgid "Learn more about Service Desk"
-msgstr ""
+msgstr "서비스 ë°ìŠ¤í¬ì— 대해 ìžì„¸ížˆ 알아보기"
msgid "Learn more about Web Terminal"
msgstr "Web Terminalì— ëŒ€í•˜ì—¬ ë” ìžì„¸ížˆ 알아보기"
@@ -27446,7 +27348,7 @@ msgid "LearnGitLab|1. Add code to your project"
msgstr ""
msgid "LearnGitLab|2. Build"
-msgstr ""
+msgstr "2. 빌드"
msgid "LearnGitLab|Add code"
msgstr ""
@@ -27500,10 +27402,10 @@ msgid "LearnGitLab|Ready to get started with GitLab? Follow these steps to set u
msgstr ""
msgid "LearnGitLab|Review and edit proposed changes to source code."
-msgstr ""
+msgstr "소스 ì½”ë“œì— ëŒ€í•´ ì œì•ˆëœ ë³€ê²½ ì‚¬í•­ì„ ê²€í† í•˜ê³  편집합니다."
msgid "LearnGitLab|Route code reviews to the right reviewers, every time."
-msgstr ""
+msgstr "언제든지 올바른 리뷰어ì—게 코드 리뷰를 ë¼ìš°íŒ…합니다."
msgid "LearnGitLab|Save time by automating your integration and deployment tasks."
msgstr ""
@@ -27960,7 +27862,7 @@ msgid "List view"
msgstr "ëª©ë¡ ë³´ê¸°"
msgid "List your Bitbucket Server repositories"
-msgstr "Bitbucket Server 저장소 목ë¡"
+msgstr "Bitbucket Server 리í¬ì§€í† ë¦¬ 목ë¡"
msgid "List your Gitea repositories"
msgstr ""
@@ -28019,6 +27921,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28028,6 +27933,9 @@ msgstr ""
msgid "Lock not found"
msgstr "ìž ê¸ˆì„ ì°¾ì„ ìˆ˜ 없습니다."
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28194,7 +28102,7 @@ msgid "Make and review changes in the browser with the Web IDE"
msgstr "웹 IDE를 사용하여 브ë¼ìš°ì €ì—ì„œ 변경 ì‚¬í•­ì„ ìž‘ì„±í•˜ê³  검토하세요."
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
-msgstr ""
+msgstr "íŒ€ì˜ ëª¨ë“  구성ì›ì´ ìž¥ì†Œì— ê´€ê³„ì—†ì´ ìƒì‚°ì„±ì„ ë†’ì¼ ìˆ˜ 있게 í•´ì¤ë‹ˆë‹¤. GitLab Geo는 GitLab ì¸ìŠ¤í„´ìŠ¤ì˜ ì½ê¸° ì „ìš© 미러를 ìƒì„±í•˜ì—¬ 대규모 리í¬ì§€í† ë¦¬ë¥¼ í´ë¡ í•˜ê³  ê°€ì ¸ì˜¤ëŠ”ë° ê±¸ë¦¬ëŠ” ì‹œê°„ì„ ì¤„ì—¬ì¤ë‹ˆë‹¤."
msgid "Make new users' profiles private by default"
msgstr ""
@@ -28433,6 +28341,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr "아래 ë‚˜ì—´ëœ ì˜µì…˜ì„ ì‚¬ìš©í•˜ì—¬ Mattermost íŒ€ì— %{link_start} 슬래시 ëª…ë ¹ì„ ì¶”ê°€í•˜ê¸°%{icon}%{link_end}"
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr "Mattermost 설치ì—ì„œ %{link_start}ì‚¬ìš©ìž ì •ì˜ ìŠ¬ëž˜ì‹œ ëª…ë ¹ì„ í™œì„±í™”%{icon}%{link_end}"
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28448,6 +28362,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr "토í°ì„ %{strong_start}Token%{strong_end} í•„ë“œì— ë¶™ì—¬ë„£ìŠµë‹ˆë‹¤."
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28460,6 +28377,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr "%{strong_start}활성%{strong_end} ì²´í¬ë°•ìŠ¤ë¥¼ ì„ íƒí•œ ë‹¤ìŒ %{strong_start}변경 사항 저장%{strong_end} ì„ íƒí•˜ì—¬ Mattermost ë‚´ì—ì„œ GitLabì„ ì‚¬ìš©í•´ë³´ì„¸ìš”!"
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28766,6 +28686,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29021,6 +29037,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29453,9 +29472,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29552,6 +29568,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -29779,7 +29798,7 @@ msgid "Mirror only protected branches"
msgstr ""
msgid "Mirror repository"
-msgstr "미러 저장소"
+msgstr "미러 리í¬ì§€í† ë¦¬"
msgid "Mirror settings are only available to GitLab administrators."
msgstr ""
@@ -29797,7 +29816,7 @@ msgid "Mirrored repositories"
msgstr "미러ë§ëœ 저장소"
msgid "Mirroring repositories"
-msgstr "ë¯¸ëŸ¬ë§ ì €ìž¥ì†Œ"
+msgstr "리í¬ì§€í† ë¦¬ 미러ë§"
msgid "Mirroring settings were successfully updated."
msgstr ""
@@ -30037,7 +30056,7 @@ msgid "More than %{number_commits_distance} commits different with %{default_bra
msgstr ""
msgid "More topics"
-msgstr ""
+msgstr "ë” ë§Žì€ ì£¼ì œ"
msgid "Most common"
msgstr ""
@@ -30283,7 +30302,7 @@ msgid "NamespaceLimits|Exclusion added successfully"
msgstr ""
msgid "NamespaceLimits|Free Tier"
-msgstr ""
+msgstr "Free í‹°ì–´"
msgid "NamespaceLimits|NONE"
msgstr ""
@@ -30376,7 +30395,7 @@ msgid "NamespaceStorageSize|To remove the read-only state, reduce git repository
msgstr ""
msgid "NamespaceStorageSize|You have consumed all available storage and you can't push or add large files to projects over the free tier limit (%{free_size_limit})."
-msgstr ""
+msgstr "사용 가능한 모든 스토리지를 사용했으며 Free í‹°ì–´ í•œë„(%{free_size_limit})ì„ ì´ˆê³¼í•˜ì—¬ 프로ì íŠ¸ì— 대용량 파ì¼ì„ 푸시하거나 추가할 수 없습니다."
msgid "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} for %{namespace_name}"
msgstr ""
@@ -30430,10 +30449,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30455,7 +30474,7 @@ msgid "Naming"
msgstr ""
msgid "Naming, topics, avatar"
-msgstr ""
+msgstr "ì´ë¦„, 주제, 아바타"
msgid "Naming, visibility"
msgstr ""
@@ -30509,6 +30528,9 @@ msgid "Navigation|Analyze"
msgstr ""
msgid "Navigation|Build"
+msgstr "빌드"
+
+msgid "Navigation|CI/CD settings"
msgstr ""
msgid "Navigation|Code"
@@ -30541,15 +30563,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30568,12 +30593,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30592,6 +30623,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr "ë‚´ 모든 프로ì íŠ¸ 보기"
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -30795,7 +30832,7 @@ msgid "New project pages"
msgstr ""
msgid "New project/repository"
-msgstr "새 프로ì íŠ¸/저장소"
+msgstr "새 프로ì íŠ¸/리í¬ì§€í† ë¦¬"
msgid "New public deploy key"
msgstr ""
@@ -30815,9 +30852,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr "새 ì¼ì •"
-
msgid "New snippet"
msgstr "새 스니펫"
@@ -30876,7 +30910,7 @@ msgid "No %{header} for this request."
msgstr ""
msgid "No %{providerTitle} repositories found"
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ì—ì„œ %{providerTitle}ì„(를) ì°¾ì„ ìˆ˜ 없습니다"
msgid "No CSV data to display."
msgstr ""
@@ -31025,6 +31059,9 @@ msgstr ""
msgid "No label"
msgstr "ë¼ë²¨ ì—†ìŒ"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "그런 ì´ë¦„ ë˜ëŠ” 설명ì´ìžˆëŠ” ë ˆì´ë¸”ì´ ì—†ìŠµë‹ˆë‹¤."
@@ -31049,6 +31086,12 @@ msgstr "ì¼ì¹˜í•˜ëŠ” 결과가 없습니다."
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31067,12 +31110,15 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
-msgstr "그런 ì´ë¦„ ë˜ëŠ” 설명ì´ìžˆëŠ” 다른 ë ˆì´ë¸”ì´ ì—†ìŠµë‹ˆë‹¤."
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
msgstr ""
+msgid "No other labels with such name or description"
+msgstr "그런 ì´ë¦„ ë˜ëŠ” 설명ì´ìžˆëŠ” 다른 ë ˆì´ë¸”ì´ ì—†ìŠµë‹ˆë‹¤."
+
msgid "No parent group"
msgstr ""
@@ -31113,7 +31159,7 @@ msgid "No regions configured"
msgstr ""
msgid "No repository"
-msgstr "저장소 ì—†ìŒ"
+msgstr "리í¬ì§€í† ë¦¬ ì—†ìŒ"
msgid "No results"
msgstr "ê²°ê³¼ ì—†ìŒ"
@@ -31127,9 +31173,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "ì¼ì • ì—†ìŒ"
-
msgid "No service accounts"
msgstr ""
@@ -31181,6 +31224,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -31219,19 +31268,19 @@ msgid "Normal view"
msgstr ""
msgid "NorthstarNavigation|Could not update the new navigation preference. Please try again later."
-msgstr ""
+msgstr "새 메뉴 환경 ì„¤ì •ì„ ì—…ë°ì´íŠ¸í•  수 없습니다. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„해주세요."
msgid "NorthstarNavigation|Navigation redesign"
msgstr ""
msgid "NorthstarNavigation|New navigation"
-msgstr ""
+msgstr "새로운 메뉴"
msgid "NorthstarNavigation|Provide feedback"
msgstr ""
msgid "NorthstarNavigation|Toggle new navigation"
-msgstr ""
+msgstr "새 메뉴 토글"
msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in, even from an unsupported browser."
msgstr ""
@@ -32368,7 +32417,7 @@ msgid "One or more of your %{provider} projects cannot be imported into GitLab d
msgstr ""
msgid "One or more of your dependency files are not supported, and the dependency list may be incomplete. Below is a list of supported file types."
-msgstr ""
+msgstr "하나 ì´ìƒì˜ 종ì†ì„± 파ì¼ì´ 지ì›ë˜ì§€ 않으며 종ì†ì„± 목ë¡ì´ 불완전할 수 있습니다. 다ìŒì€ 지ì›ë˜ëŠ” íŒŒì¼ í˜•ì‹ ëª©ë¡ìž…니다."
msgid "One or more of your personal access tokens has expired."
msgstr "하나 ì´ìƒì˜ ê°œì¸ ì•¡ì„¸ìŠ¤ 토í°ì´ 만료ë˜ì—ˆìŠµë‹ˆë‹¤."
@@ -32379,6 +32428,9 @@ msgstr "하나 ì´ìƒì˜ ê°œì¸ ì•¡ì„¸ìŠ¤ 토í°ì´ 만료ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr "ê°œì¸ ì•¡ì„¸ìŠ¤ 토í°ì´ %{days_to_expire}ì¼ ì´ë‚´ì— 만료ë©ë‹ˆë‹¤."
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32406,9 +32458,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32571,24 +32620,60 @@ msgstr ""
msgid "Ordered list"
msgstr "번호순 목ë¡"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr "공개 - ì¸ì¦ ì—†ì´ ì¡°ì§ì— 액세스할 수 있습니다."
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -32989,7 +33074,7 @@ msgid "PackageRegistry|Forward package requests"
msgstr ""
msgid "PackageRegistry|Forward package requests to a public registry if the packages are not found in the GitLab package registry."
-msgstr ""
+msgstr "GitLab 패키지 레지스트리ì—ì„œ 패키지를 ì°¾ì„ ìˆ˜ 없는 경우 공용 레지스트리로 패키지 ìš”ì²­ì„ ì „ë‹¬í•©ë‹ˆë‹¤."
msgid "PackageRegistry|Generic"
msgstr ""
@@ -33301,6 +33386,9 @@ msgstr "페ì´ì§€"
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33448,7 +33536,10 @@ msgstr ""
msgid "Path:"
msgstr "경로:"
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33503,7 +33594,7 @@ msgid "Perform advanced options such as changing path, transferring, exporting,
msgstr ""
msgid "Perform code reviews and enhance collaboration with merge requests."
-msgstr ""
+msgstr "머지 리퀘스트로 코드 리뷰를 수행하고 í˜‘ì—…ì„ ê°•í™”í•©ë‹ˆë‹¤."
msgid "Perform common operations on GitLab project"
msgstr ""
@@ -33683,7 +33774,7 @@ msgid "Pipeline %{label} for \"%{dataTitle}\""
msgstr ""
msgid "Pipeline Editor|Are you sure you want to reset the file to its last committed version?"
-msgstr ""
+msgstr "파ì¼ì„ 마지막 ì»¤ë°‹ëœ ë²„ì „ìœ¼ë¡œ 재설정하시겠습니까?"
msgid "Pipeline ID"
msgstr ""
@@ -33707,7 +33798,7 @@ msgid "Pipeline durations for the last 30 commits"
msgstr ""
msgid "Pipeline editor"
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ 편집기"
msgid "Pipeline ran in fork of project"
msgstr ""
@@ -33764,22 +33855,22 @@ msgid "PipelineCharts|Total:"
msgstr "합계 :"
msgid "PipelineEditorFileTree|Configuration files added with the include keyword"
-msgstr ""
+msgstr "include 키워드로 구성 파ì¼ì´ 추가ë¨"
msgid "PipelineEditorFileTree|When you use the include keyword to add pipeline configuration from files in the project, those files will be listed here."
-msgstr ""
+msgstr "include 키워드를 사용하여 프로ì íŠ¸ì˜ 파ì¼ì—ì„œ 파ì´í”„ë¼ì¸ êµ¬ì„±ì„ ì¶”ê°€í•˜ë©´ 해당 파ì¼ì´ ì—¬ê¸°ì— ë‚˜ì—´ë©ë‹ˆë‹¤."
msgid "PipelineEditorTutorial|Browse %{linkStart}CI/CD examples and templates%{linkEnd}"
-msgstr ""
+msgstr "찾아보기 %{linkStart}CI/CD 예제 ë° í…œí”Œë¦¿%{linkEnd}"
msgid "PipelineEditorTutorial|Commit the file to your repository. The pipeline then runs automatically."
msgstr "파ì¼ì„ 리í¬ì§€í† ë¦¬ì— 커밋합니다. 그러면 파ì´í”„ë¼ì¸ì´ ìžë™ìœ¼ë¡œ 실행ë©ë‹ˆë‹¤."
msgid "PipelineEditorTutorial|Get started with GitLab CI/CD"
-msgstr ""
+msgstr "GitLab CI/CD 시작하기"
msgid "PipelineEditorTutorial|GitLab CI/CD can automatically build, test, and deploy your application."
-msgstr ""
+msgstr "GitLab CI/CD는 애플리케ì´ì…˜ì„ ìžë™ìœ¼ë¡œ 빌드, 테스트 ë° ë°°í¬í•  수 있습니다."
msgid "PipelineEditorTutorial|If you’re using a self-managed GitLab instance, %{linkStart}make sure your instance has runners available.%{linkEnd}"
msgstr ""
@@ -33791,10 +33882,10 @@ msgid "PipelineEditorTutorial|Make your pipeline more efficient with the %{linkS
msgstr ""
msgid "PipelineEditorTutorial|Resources to help with your CI/CD configuration:"
-msgstr ""
+msgstr "CI/CD êµ¬ì„±ì— ë„ì›€ì´ ë˜ëŠ” 리소스:"
msgid "PipelineEditorTutorial|Select the pipeline ID to view the full details about your first pipeline run."
-msgstr ""
+msgstr "첫 번째 파ì´í”„ë¼ì¸ ì‹¤í–‰ì— ëŒ€í•œ ì „ì²´ 세부 정보를 보려면 파ì´í”„ë¼ì¸ ID를 ì„ íƒí•©ë‹ˆë‹¤."
msgid "PipelineEditorTutorial|The pipeline stages and jobs are defined in a %{codeStart}.gitlab-ci.yml%{codeEnd} file. You can edit, visualize and validate the syntax in this file by using the Pipeline Editor."
msgstr ""
@@ -33806,19 +33897,19 @@ msgid "PipelineEditorTutorial|This template creates a simple test pipeline. To u
msgstr ""
msgid "PipelineEditorTutorial|Use the Visualize and Lint tabs in the Pipeline Editor to visualize your pipeline and check for any errors or warnings before committing your changes."
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ íŽ¸ì§‘ê¸°ì˜ ì‹œê°í™” ë° Lint íƒ­ì„ ì‚¬ìš©í•˜ì—¬ 파ì´í”„ë¼ì¸ì„ ì‹œê°í™”하고 변경 ì‚¬í•­ì„ ì»¤ë°‹í•˜ê¸° ì „ì— ì˜¤ë¥˜ë‚˜ 경고가 있는지 확ì¸í•©ë‹ˆë‹¤."
msgid "PipelineEditorTutorial|View %{linkStart}.gitlab-ci.yml syntax reference%{linkEnd}"
-msgstr ""
+msgstr "보기 %{linkStart}.gitlab-ci.yml 구문 참조%{linkEnd}"
msgid "PipelineEditorTutorial|âš™ï¸ Pipeline configuration reference"
-msgstr ""
+msgstr "âš™ï¸ íŒŒì´í”„ë¼ì¸ 구성 참조"
msgid "PipelineEditorTutorial|💡 Tip: Visualize and validate your pipeline"
-msgstr ""
+msgstr "💡 íŒ: 파ì´í”„ë¼ì¸ ì‹œê°í™” ë° ê²€ì¦"
msgid "PipelineEditorTutorial|🚀 Run your first pipeline"
-msgstr ""
+msgstr "🚀 첫 번째 파ì´í”„ë¼ì¸ 실행"
msgid "PipelineEditor|Configuration content has changed. Re-run validation for updated results."
msgstr "설정 ë‚´ìš©ì´ ë³€ê²½ë˜ì—ˆìŠµë‹ˆë‹¤. ì—…ë°ì´íŠ¸ëœ ê²°ê³¼ì— ëŒ€í•œ 유효성 검사를 다시 실행합니다."
@@ -33842,7 +33933,7 @@ msgid "PipelineEditor|Pipeline behavior will be simulated including the %{codeSt
msgstr "%{codeEnd} 와 %{codeStart}ì€%{codeEnd} ìž‘ì—… 종ì†ì„±ì„ 필요로 하는 ê²ƒì„ ì œì™¸í•˜ê³  %{codeStart}ê°œì˜ ê·œì¹™%{codeEnd} %{codeStart}만%{codeEnd} %{codeStart}를 í¬í•¨í•˜ì—¬ 파ì´í”„ë¼ì¸ ë™ìž‘ì´ ì‹œë®¬ë ˆì´ì…˜ë©ë‹ˆë‹¤. %{linkStart}ìžì„¸ížˆ 알아보기%{linkEnd}"
msgid "PipelineEditor|Pipeline simulation completed with errors"
-msgstr ""
+msgstr "오류와 함께 파ì´í”„ë¼ì¸ 시뮬레ì´ì…˜ì´ 완료ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "PipelineEditor|Simulated a %{codeStart}git push%{codeEnd} event for a default branch. %{codeStart}Rules%{codeEnd}, %{codeStart}only%{codeEnd}, %{codeStart}except%{codeEnd}, and %{codeStart}needs%{codeEnd} job dependencies logic have been evaluated. %{linkStart}Learn more%{linkEnd}"
msgstr ""
@@ -33851,16 +33942,16 @@ msgid "PipelineEditor|Simulation completed successfully"
msgstr "시뮬레ì´ì…˜ì´ 성공ì ìœ¼ë¡œ 완료ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "PipelineEditor|The CI/CD configuration is continuously validated. Errors and warnings are displayed when the CI/CD configuration file is not empty."
-msgstr ""
+msgstr "CI/CD êµ¬ì„±ì´ ì§€ì†ì ìœ¼ë¡œ ê²€ì¦ë©ë‹ˆë‹¤. CI/CD 구성 파ì¼ì´ 비어 있지 않으면 오류 ë° ê²½ê³ ê°€ 표시ë©ë‹ˆë‹¤."
msgid "PipelineEditor|The full configuration view is displayed when the CI/CD configuration file has valid syntax."
-msgstr ""
+msgstr "ì „ì²´ 구성 보기는 CI/CD 구성 파ì¼ì´ 유효한 문법으로 ë˜ì–´ ìžˆì„ ë•Œ 표시ë©ë‹ˆë‹¤."
msgid "PipelineEditor|The pipeline visualization is displayed when the CI/CD configuration file has valid syntax."
-msgstr ""
+msgstr "CI/CD 구성 파ì¼ì— 유효한 문법으로 ë˜ì–´ 있는 경우 파ì´í”„ë¼ì¸ ì‹œê°í™”ê°€ 표시ë©ë‹ˆë‹¤."
msgid "PipelineEditor|This tab will be usable when the CI/CD configuration file is populated with valid syntax."
-msgstr ""
+msgstr "ì´ íƒ­ì€ CI/CD 구성 파ì¼ì´ 유효한 문법으로 êµ¬ì„±ëœ ê²½ìš° 사용할 수 있습니다."
msgid "PipelineEditor|Validate pipeline"
msgstr "파ì´í”„ë¼ì¸ 유효성 ê²€ì¦"
@@ -33895,9 +33986,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "활성화 ë¨"
-
msgid "PipelineSchedules|Active"
msgstr "활성"
@@ -34012,12 +34100,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "변수"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34157,7 +34239,7 @@ msgid "Pipelines|Build with confidence"
msgstr "ìžì‹ ìžˆê²Œ 빌드하세요"
msgid "Pipelines|Building for iOS?"
-msgstr ""
+msgstr "iOS용 빌드?"
msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
msgstr ""
@@ -34199,7 +34281,7 @@ msgid "Pipelines|Edit"
msgstr ""
msgid "Pipelines|Editor"
-msgstr ""
+msgstr "편집기"
msgid "Pipelines|Failed to update. Please reload page to update the list of artifacts."
msgstr ""
@@ -34226,7 +34308,7 @@ msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to
msgstr ""
msgid "Pipelines|Go to the pipeline editor"
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ 편집기로 ì´ë™"
msgid "Pipelines|If you are unsure, ask a project maintainer to review it for you."
msgstr ""
@@ -34271,7 +34353,7 @@ msgid "Pipelines|Owner"
msgstr ""
msgid "Pipelines|Pipeline Editor"
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ 편집기"
msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
msgstr ""
@@ -34468,6 +34550,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr "다ìŒì— ì˜í•´ ìƒì„±ë¨"
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34591,9 +34676,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr "변수"
@@ -35116,9 +35198,6 @@ msgstr "ë ˆì´ì•„웃 너비"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "%{min}와 %{max} 사ì´ì˜ 숫ìžì—¬ì•¼ 합니다."
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35230,6 +35309,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35353,9 +35435,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35371,9 +35450,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35410,9 +35486,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35473,6 +35546,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35497,9 +35573,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35639,7 +35712,7 @@ msgid "Profiles|Add new email"
msgstr ""
msgid "Profiles|Add new mirror repository"
-msgstr ""
+msgstr "새 미러 리í¬ì§€í† ë¦¬ 추가"
msgid "Profiles|An error occurred while updating your username, please try again."
msgstr ""
@@ -35731,14 +35804,14 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr "프로필 편집"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
msgstr ""
msgid "Profiles|Ensure you have two-factor authentication recovery codes stored in a safe place."
-msgstr ""
+msgstr "2단계 ì¸ì¦ 복구 코드가 안전한 ìž¥ì†Œì— ì €ìž¥ë˜ì–´ 있는지 확ì¸í•˜ì„¸ìš”."
msgid "Profiles|Enter how your name is pronounced to help people address you correctly."
msgstr "ì‚¬ëžŒë“¤ì´ ë‹¹ì‹ ì„ ì˜¬ë°”ë¥´ê²Œ 부를 수 있ë„ë¡ ë‹¹ì‹ ì˜ ì´ë¦„ì„ ë°œìŒí•˜ëŠ” ë°©ë²•ì„ ìž…ë ¥í•˜ì‹­ì‹œì˜¤."
@@ -36092,7 +36165,7 @@ msgid "Project already deleted"
msgstr "프로ì íŠ¸ê°€ ì´ë¯¸ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Project and wiki repositories"
-msgstr ""
+msgstr "프로ì íŠ¸ ë° ìœ„í‚¤ 리í¬ì§€í† ë¦¬"
msgid "Project audit events"
msgstr ""
@@ -36166,9 +36239,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr "프로ì íŠ¸ 경로"
@@ -36419,7 +36489,7 @@ msgid "ProjectService|Mock service URL"
msgstr ""
msgid "ProjectService|Must have permission to trigger a manual build in TeamCity."
-msgstr ""
+msgstr "TeamCityì—ì„œ ìˆ˜ë™ ë¹Œë“œë¥¼ 트리거할 수 있는 ê¶Œí•œì´ ìžˆì–´ì•¼ 합니다."
msgid "ProjectService|Perform common operations on GitLab project: %{project_name}"
msgstr ""
@@ -36437,7 +36507,7 @@ msgid "ProjectService|TeamCity server URL"
msgstr ""
msgid "ProjectService|The build configuration ID of the TeamCity project."
-msgstr ""
+msgstr "TeamCity 프로ì íŠ¸ì˜ 빌드 설정 ID입니다."
msgid "ProjectService|The token you get after you create a Buildkite pipeline with a GitLab repository."
msgstr ""
@@ -36473,7 +36543,7 @@ msgid "ProjectService|Trigger event when a group is mentioned in a confidential
msgstr ""
msgid "ProjectService|Trigger event when a group is mentioned in a public context."
-msgstr ""
+msgstr "공개 컨í…스트ì—ì„œ ê·¸ë£¹ì´ ì–¸ê¸‰ë  ë•Œ ì´ë²¤íŠ¸ë¥¼ 트리거합니다."
msgid "ProjectService|Trigger event when a merge request is created, updated, or merged."
msgstr ""
@@ -36548,7 +36618,7 @@ msgid "ProjectSettings|Branches created from issues follow this pattern."
msgstr ""
msgid "ProjectSettings|Build, test, and deploy your changes."
-msgstr ""
+msgstr "변경 ì‚¬í•­ì„ ë¹Œë“œ, 테스트 ë° ë°°í¬í•©ë‹ˆë‹¤."
msgid "ProjectSettings|Checkbox is visible and selected by default."
msgstr ""
@@ -36658,6 +36728,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -36761,7 +36837,7 @@ msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off
msgstr ""
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
-msgstr "ì´ ì €ìž¥ì†Œì—는 ì„œëª…ëœ ì»¤ë°‹ë§Œ 푸쉬할 수 있습니다."
+msgstr "ì´ ë¦¬í¬ì§€í† ë¦¬ì—는 ì„œëª…ëœ ì»¤ë°‹ë§Œ 푸쉬할 수 있습니다."
msgid "ProjectSettings|Override instance analytics configuration for this project"
msgstr ""
@@ -36793,6 +36869,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr "릴리스"
@@ -36865,6 +36944,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -36914,7 +36996,7 @@ msgid "ProjectSettings|Topics"
msgstr ""
msgid "ProjectSettings|Topics are publicly visible even on private projects. Do not include sensitive information in topic names. %{linkStart}Learn more%{linkEnd}."
-msgstr ""
+msgstr "주제는 비공개 프로ì íŠ¸ì—ì„œë„ ê³µê°œì ìœ¼ë¡œ 표시ë©ë‹ˆë‹¤. 주제 ì´ë¦„ì— ë¯¼ê°í•œ 정보를 í¬í•¨í•˜ì§€ 마십시오. %{linkStart}ìžì„¸ížˆ 알아보기%{linkEnd}."
msgid "ProjectSettings|Track machine learning model experiments and artifacts."
msgstr ""
@@ -37487,7 +37569,7 @@ msgid "Promotions|Get started with GitLab Mobile DevOps"
msgstr ""
msgid "Promotions|Improve issues management with Issue weight and GitLab Enterprise Edition."
-msgstr ""
+msgstr "ì´ìŠˆ 가중치 ë° GitLab Enterprise Edition으로 ì´ìŠˆ 관리를 개선합니다."
msgid "Promotions|Improve merge requests and customer support with GitLab Enterprise Edition."
msgstr ""
@@ -37571,13 +37653,13 @@ msgid "Promotions|Webhooks allow you to trigger a URL if, for example, new code
msgstr ""
msgid "Promotions|Weight"
-msgstr ""
+msgstr "가중치"
msgid "Promotions|Weighting your issue"
-msgstr ""
+msgstr "ì´ìŠˆì— 가중치 부여"
msgid "Promotions|When you have a lot of issues, it can be hard to get an overview. By adding a weight to your issues, you can get a better idea of the effort, cost, required time, or value of each, and so better manage them."
-msgstr ""
+msgstr "ì´ìŠˆê°€ 많으면 ìš”ì ì„ 파악하기 어려울 수 있습니다. ì´ìŠˆì— 가중치를 추가하면 ê°ê°ì˜ 노력, 비용, 필요한 시간 ë˜ëŠ” ê°€ì¹˜ì— ëŒ€í•´ ë” ìž˜ ì´í•´í•  수 있으므로 문제를 ë” ìž˜ 관리할 수 있습니다."
msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
msgstr ""
@@ -37684,6 +37766,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37756,7 +37844,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -37809,10 +37897,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -37824,6 +37915,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -37842,6 +37936,9 @@ msgstr "사용ìž"
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr "아래 ë°°í¬ ê³„ì¸µìœ¼ë¡œ ì§€ì •ëœ ëª¨ë“  í™˜ê²½ì€ ìƒìœ„ ê·¸ë£¹ì— ì˜í•´ 보호ë©ë‹ˆë‹¤. %{link_start}ìžì„¸ížˆ 알아보기%{link_end}."
@@ -37899,9 +37996,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr "ProtectedEnvironment|그룹 ì„ íƒ"
-msgid "ProtectedEnvironment|Select users"
-msgstr "ì‚¬ìš©ìž ì„ íƒ"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -37968,9 +38062,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -37993,7 +38084,7 @@ msgid "Public projects are an easy way to allow everyone to have read-only acces
msgstr ""
msgid "Public projects compute cost factor"
-msgstr ""
+msgstr "공개 프로ì íŠ¸ 컴퓨팅 비용 팩터"
msgid "Publish to status page"
msgstr ""
@@ -38331,9 +38422,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38473,34 +38561,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38834,9 +38898,6 @@ msgstr ""
msgid "Remove priority"
msgstr "우선 순위 삭제"
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr "리뷰어 제거"
@@ -38849,6 +38910,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -38858,9 +38922,6 @@ msgstr ""
msgid "Remove user"
msgstr "ì‚¬ìš©ìž ì‚­ì œ"
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr "그룹ì—ì„œ ì‚¬ìš©ìž ì œê±°"
@@ -39140,12 +39201,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr "%{reporter}ì— ì˜í•´ ë³´ê³ ë¨"
-
msgid "Reporter"
msgstr "리í¬í„°"
@@ -39256,10 +39311,10 @@ msgid "Reports|Tool"
msgstr ""
msgid "Reports|Vulnerability"
-msgstr "취약ì "
+msgstr "취약성"
msgid "Reports|Vulnerability Name"
-msgstr ""
+msgstr "ì·¨ì•½ì  ì´ë¦„"
msgid "Reports|metrics report"
msgstr "Reports|메트릭 보고서"
@@ -39357,7 +39412,7 @@ msgid "RepositoriesAnalytics|There was an error fetching the projects."
msgstr ""
msgid "Repository"
-msgstr "저장소"
+msgstr "리í¬ì§€í† ë¦¬"
msgid "Repository Analytics"
msgstr ""
@@ -39366,7 +39421,7 @@ msgid "Repository Graph"
msgstr ""
msgid "Repository Settings"
-msgstr "저장소 설정"
+msgstr "리í¬ì§€í† ë¦¬ 설정"
msgid "Repository already read-only"
msgstr ""
@@ -39405,16 +39460,16 @@ msgid "Repository has an invalid default branch name."
msgstr ""
msgid "Repository has more than one branch."
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ì— 둘 ì´ìƒì˜ 브랜치가 있습니다."
msgid "Repository has no locks."
-msgstr "ì €ìž¥ì†Œì— ìž ê¸ˆì´ ì—†ìŠµë‹ˆë‹¤."
+msgstr "리í¬ì§€í† ë¦¬ì— ìž ê¸ˆì´ ì—†ìŠµë‹ˆë‹¤."
msgid "Repository has tags."
msgstr "리í¬ì§€í† ë¦¬ì— 태그가 있습니다."
msgid "Repository maintenance"
-msgstr "저장소 유지 보수"
+msgstr "리í¬ì§€í† ë¦¬ 유지 보수"
msgid "Repository mirroring"
msgstr "리í¬ì§€í† ë¦¬ 미러ë§"
@@ -39435,20 +39490,17 @@ msgid "Repository size limit (MiB)"
msgstr "리í¬ì§€í† ë¦¬ í¬ê¸° 제한 (MiB)"
msgid "Repository storage"
-msgstr "ì €ìž¥ì†Œì˜ ì €ìž¥ê³µê°„"
+msgstr "리í¬ì§€í† ë¦¬ 저장공간"
msgid "Repository update events"
msgstr ""
msgid "Repository usage recalculation started"
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ 사용량 재계산 시작ë¨"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "ì„ íƒ"
-
msgid "Request"
msgstr ""
@@ -39858,6 +39910,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -39886,7 +39941,7 @@ msgid "Run housekeeping"
msgstr "정리 실행"
msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
-msgstr ""
+msgstr "관리 ìž‘ì—…ì„ ì‹¤í–‰í•˜ì—¬ 깃 리í¬ì§€í† ë¦¬ë¥¼ ìžë™ìœ¼ë¡œ 최ì í™”합니다. ì´ ì˜µì…˜ì„ ë¹„í™œì„±í™”í•˜ë©´ ì‹œê°„ì´ ì§€ë‚¨ì— ë”°ë¼ ì„±ëŠ¥ì´ ì €í•˜ë©ë‹ˆë‹¤."
msgid "Run job"
msgstr ""
@@ -40283,6 +40338,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40567,7 +40625,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40649,6 +40707,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40810,7 +40871,7 @@ msgid "Running"
msgstr "실행중"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
-msgstr "현재 저장소ì—ì„œ íŒŒì¼ ê¸°ë¡ì„ 압축하거나, ë„달할 수 없는 ê°ì²´ë¥¼ 제거하여 정리를 실행합니다."
+msgstr "현재 리í¬ì§€í† ë¦¬ì—ì„œ íŒŒì¼ ê¸°ë¡ì„ 압축하거나, ë„달할 수 없는 ê°ì²´ë¥¼ 제거하여 정리를 실행합니다."
msgid "SAML"
msgstr ""
@@ -40857,6 +40918,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "ì¡°ì§ì˜ SSOê°€ GitLab ê³„ì •ì— ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤."
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -40965,9 +41029,6 @@ msgstr ""
msgid "Save password"
msgstr "비밀번호 저장"
-msgid "Save pipeline schedule"
-msgstr "파ì´í”„ë¼ì¸ 스케줄 저장"
-
msgid "Saving"
msgstr ""
@@ -40980,7 +41041,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41106,10 +41167,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41124,6 +41188,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41136,7 +41218,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41148,7 +41230,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41160,6 +41242,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41187,9 +41275,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41209,7 +41306,7 @@ msgid "ScanResultPolicy|vulnerabilities that match all"
msgstr ""
msgid "ScanResultPolicy|vulnerability states"
-msgstr ""
+msgstr "취약성 ìƒíƒœ"
msgid "Scanner"
msgstr ""
@@ -41301,6 +41398,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41370,15 +41470,12 @@ msgstr "마ì¼ìŠ¤í†¤ 검색"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
-msgstr "검색 ë˜ëŠ” ê²°ê³¼ í•„í„°..."
-
msgid "Search or filter results…"
msgstr "검색 ë˜ëŠ” ê²°ê³¼ í•„í„°..."
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr ""
@@ -41594,6 +41691,9 @@ msgstr ""
msgid "Security dashboard"
msgstr "보안 대시보드"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41739,7 +41839,7 @@ msgid "SecurityConfiguration|Using custom settings. You won't receive automatic
msgstr ""
msgid "SecurityConfiguration|Vulnerability Management"
-msgstr ""
+msgstr "ì·¨ì•½ì  ê´€ë¦¬"
msgid "SecurityConfiguration|Vulnerability details and statistics in the merge request"
msgstr ""
@@ -41750,6 +41850,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -41759,7 +41865,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -41888,7 +42003,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -41900,12 +42015,18 @@ msgstr "SecurityOrchestration|í´ëŸ¬ìŠ¤í„° ì—ì´ì „트를 로드하지 못했ìŠ
msgid "SecurityOrchestration|Failed to load images."
msgstr "SecurityOrchestration|ì´ë¯¸ì§€ë¥¼ 로드하지 못했습니다."
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42145,7 +42266,7 @@ msgid "SecurityOrchestration|This project"
msgstr ""
msgid "SecurityOrchestration|This view only shows scan results for the agent %{agent}. You can view scan results for all agents in the %{linkStart}Operational Vulnerabilities tab of the vulnerability report%{linkEnd}."
-msgstr ""
+msgstr "ì´ ë³´ê¸°ì—는 %{agent} ì—ì´ì „íŠ¸ì— ëŒ€í•œ 검색 결과만 표시ë©ë‹ˆë‹¤. 취약성 ë³´ê³ ì„œ %{linkEnd}ì˜ %{linkStart}ìš´ì˜ ì·¨ì•½ì„± 탭ì—ì„œ 모든 ì—ì´ì „íŠ¸ì— ëŒ€í•œ 검색 결과를 ë³¼ 수 있습니다."
msgid "SecurityOrchestration|Timezone is invalid"
msgstr ""
@@ -42171,6 +42292,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42183,13 +42307,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42219,13 +42343,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42234,6 +42364,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42303,9 +42439,6 @@ msgstr "댓글 추가 (필수)"
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "보안 ì˜ì—­ì—ì„œ 모니터ë§í•  프로ì íŠ¸ë¥¼ 추가하거나 제거합니다. ì´ ëª©ë¡ì— í¬í•¨ëœ 프로ì íŠ¸ì˜ 결과는 보안 대시보드 ë° ì·¨ì•½ì  ë³´ê³ ì„œì— í‘œì‹œë©ë‹ˆë‹¤."
@@ -42349,17 +42482,20 @@ msgid "SecurityReports|Cluster"
msgstr "í´ëŸ¬ìŠ¤í„°"
msgid "SecurityReports|Comment added to '%{vulnerabilityName}'"
-msgstr ""
+msgstr "'%{vulnerabilityName}'ì— ëŒ“ê¸€ì´ ì¶”ê°€ë˜ì—ˆìŠµë‹ˆë‹¤"
msgid "SecurityReports|Comment deleted on '%{vulnerabilityName}'"
-msgstr ""
+msgstr "%{vulnerabilityName}'ì—ì„œ ëŒ“ê¸€ì´ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤"
msgid "SecurityReports|Comment edited on '%{vulnerabilityName}'"
-msgstr ""
+msgstr "'%{vulnerabilityName}'ì— íŽ¸ì§‘ëœ ëŒ“ê¸€"
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42375,14 +42511,20 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
+msgstr "ì·¨ì•½ì  ë¬´ì‹œ"
+
+msgid "SecurityReports|Dismissal comment"
msgstr ""
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
-msgstr ""
+msgstr "%{vulnerabilityName}ê°€ 무시ë¨"
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view."
-msgstr ""
+msgstr "%{vulnerabilityName}ê°€ 무시ë˜ì—ˆìŠµë‹ˆë‹¤. 보려면 숨기기 í•´ì œ í† ê¸€ì„ ë•ë‹ˆë‹¤."
msgid "SecurityReports|Dismissed (all reasons)"
msgstr ""
@@ -42408,6 +42550,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr "ì´ ëŒ€ì‹œë³´ë“œë¥¼ ë³¼ 수 있는 ê¶Œí•œì´ ì—†ê±°ë‚˜ 대시보드가 설정ë˜ì§€ 않았습니다. 계ì†í•˜ë ¤ë©´ 관리ìžì—게 권한 ì„¤ì •ì„ í™•ì¸í•˜ê±°ë‚˜ 대시보드 ì„¤ì •ì„ í™•ì¸í•˜ì„¸ìš”."
@@ -42418,10 +42563,10 @@ msgid "SecurityReports|Error fetching the vulnerabilities over time. Please chec
msgstr ""
msgid "SecurityReports|Error fetching the vulnerability counts. Please check your network connection and try again."
-msgstr ""
+msgstr "취약성 수를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë„¤íŠ¸ì›Œí¬ ì—°ê²°ì„ í™•ì¸í•˜ê³  다시 ì‹œë„하십시오."
msgid "SecurityReports|Error fetching the vulnerability list. Please check your network connection and try again."
-msgstr ""
+msgstr "취약성 목ë¡ì„ 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë„¤íŠ¸ì›Œí¬ ì—°ê²°ì„ í™•ì¸í•˜ê³  다시 ì‹œë„하십시오."
msgid "SecurityReports|Error parsing security reports"
msgstr ""
@@ -42451,7 +42596,7 @@ msgid "SecurityReports|Issue Created"
msgstr ""
msgid "SecurityReports|Issues created from a vulnerability cannot be removed."
-msgstr ""
+msgstr "취약성ì—ì„œ ìƒì„±ëœ 문제는 제거할 수 없습니다."
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr "대시보드 ì„¤ì •ì— ëŒ€í•´ ìžì„¸ížˆ 알아보기"
@@ -42525,9 +42670,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr "댓글 저장"
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42569,13 +42711,13 @@ msgid "SecurityReports|Still detected"
msgstr "ì•„ì§ ê°ì§€ë¨"
msgid "SecurityReports|Submit vulnerability"
-msgstr ""
+msgstr "취약성 제출"
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
-msgstr ""
+msgstr "ë‹¤ìŒ ë³´ì•ˆ ë³´ê³ ì„œì—는 구문 분ì„í•  수 없고 기ë¡ë˜ì§€ ì•Šì€ í•˜ë‚˜ ì´ìƒì˜ 취약ì ì´ í¬í•¨ë˜ì–´ 있습니다. 보고서를 조사하려면 ìž‘ì—… 출력ì—ì„œ 아티팩트를 다운로드하십시오. 보안 보고서가 관련 %{helpPageLinkStart}JSON 스키마%{helpPageLinkEnd}ì„ ì¤€ìˆ˜í•˜ëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤."
msgid "SecurityReports|The security report for this pipeline has %{helpPageLinkStart}expired%{helpPageLinkEnd}. Re-run the pipeline to generate a new security report."
msgstr ""
@@ -42608,7 +42750,7 @@ msgid "SecurityReports|There was an error dismissing the vulnerabilities."
msgstr ""
msgid "SecurityReports|There was an error dismissing the vulnerability."
-msgstr ""
+msgstr "ì·¨ì•½ì„±ì„ ì œê±°í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "SecurityReports|There was an error fetching the finding. Please try again."
msgstr ""
@@ -42749,7 +42891,7 @@ msgid "Select a role"
msgstr ""
msgid "Select a template repository"
-msgstr "저장소 템플릿 ì„ íƒ"
+msgstr "리í¬ì§€í† ë¦¬ 템플릿 ì„ íƒ"
msgid "Select all"
msgstr "ëª¨ë‘ ì„ íƒ"
@@ -42824,7 +42966,7 @@ msgid "Select project"
msgstr "프로ì íŠ¸ ì„ íƒ"
msgid "Select project to create %{type}"
-msgstr ""
+msgstr "%{type}ì„ ìƒì„±í•  프로ì íŠ¸ ì„ íƒ"
msgid "Select projects"
msgstr "프로ì íŠ¸ ì„ íƒ"
@@ -42919,9 +43061,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -42991,6 +43130,9 @@ msgstr ""
msgid "Service Desk"
msgstr "서비스 ë°ìŠ¤í¬"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43015,12 +43157,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43048,9 +43202,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43060,27 +43220,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43120,15 +43313,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43156,6 +43379,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr "세션 시간 (분)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43276,6 +43502,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43310,10 +43539,10 @@ msgid "Set visibility of project contents. Configure import sources and Git acce
msgstr ""
msgid "Set weight"
-msgstr ""
+msgstr "가중치 설정"
msgid "Set weight to %{weight}."
-msgstr ""
+msgstr "가중치를 %{weight}로 설정하십시오."
msgid "SetStatusModal|Clear status"
msgstr "ìƒíƒœ 지우기"
@@ -43354,6 +43583,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -43376,7 +43608,7 @@ msgid "Sets time estimate to %{time_estimate}."
msgstr ""
msgid "Sets weight to %{weight}."
-msgstr ""
+msgstr "가중치를 %{weight}로 설정합니다."
msgid "Setting"
msgstr ""
@@ -43473,7 +43705,7 @@ msgid "Shimo|Shimo Workspace integration is enabled"
msgstr ""
msgid "Shimo|You've enabled the Shimo Workspace integration. You can view your wiki directly in Shimo."
-msgstr ""
+msgstr "Shimo ìž‘ì—… ê³µê°„ì„ í™œì„±í™”í–ˆìŠµë‹ˆë‹¤. Shimoì—ì„œ ë‹¹ì‹ ì˜ ìœ„í‚¤ë¥¼ ì§ì ‘ ë³¼ 수 있습니다."
msgid "Short name"
msgstr ""
@@ -43855,7 +44087,7 @@ msgid "Size Limits"
msgstr ""
msgid "Size limit per repository (MiB)"
-msgstr "저장소당 í¬ê¸° 제한 (MiB)"
+msgstr "리í¬ì§€í† ë¦¬ë‹¹ í¬ê¸° 제한 (MiB)"
msgid "Skip to main content"
msgstr ""
@@ -43996,7 +44228,7 @@ msgid "SlackIntegration|When GitLab releases new features for the GitLab for Sla
msgstr ""
msgid "SlackIntegration|You can now close this window and go to your Slack workspace."
-msgstr ""
+msgstr "ë‹¹ì‹ ì€ ì´ì œ ì´ ì°½ì„ ë‹«ê³  Slack ìž‘ì—… 공간으로 ì´ë™í•  수 있습니다."
msgid "SlackIntegration|You don't have to reauthorize this application if the permission scope changes in future releases."
msgstr ""
@@ -44035,7 +44267,7 @@ msgid "SlackService|After setup, get a list of available Slack slash commands by
msgstr ""
msgid "SlackService|Fill in the word that works best for your team."
-msgstr ""
+msgstr "ë‹¹ì‹ ì˜ íŒ€ì— ê°€ìž¥ ì í•©í•œ 단어를 입력하세요."
msgid "SlackService|Perform common operations in this project by entering slash commands in Slack."
msgstr ""
@@ -44187,6 +44419,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44280,9 +44515,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -44452,7 +44684,7 @@ msgid "SortOptions|Largest group"
msgstr "í° ê·¸ë£¹"
msgid "SortOptions|Largest repository"
-msgstr "í° ì €ìž¥ì†Œ"
+msgstr "가장 í° ë¦¬í¬ì§€í† ë¦¬"
msgid "SortOptions|Last Contact"
msgstr ""
@@ -44467,7 +44699,7 @@ msgid "SortOptions|Least popular"
msgstr "ëœ ì¸ê¸°ìžˆëŠ”"
msgid "SortOptions|Less weight"
-msgstr ""
+msgstr "가중치 ìž‘ì€"
msgid "SortOptions|Manual"
msgstr ""
@@ -44491,7 +44723,7 @@ msgid "SortOptions|Milestone due soon"
msgstr "마ì¼ìŠ¤í†¤ 마ê°ì¼ì´ 가까운"
msgid "SortOptions|More weight"
-msgstr ""
+msgstr "가중치 í°"
msgid "SortOptions|Most popular"
msgstr "ë” ì¸ê¸°ìžˆëŠ”"
@@ -44575,7 +44807,7 @@ msgid "SortOptions|Version"
msgstr ""
msgid "SortOptions|Weight"
-msgstr ""
+msgstr "가중치"
msgid "Source"
msgstr "소스"
@@ -44872,7 +45104,7 @@ msgid "Started %{startsIn}"
msgstr ""
msgid "Started asynchronous removal of all repository check states."
-msgstr ""
+msgstr "모든 리í¬ì§€í† ë¦¬ ì ì„¬ ìƒíƒœì˜ 비ë™ê¸° 제거를 시작했습니다."
msgid "Started escalation for this incident."
msgstr ""
@@ -45082,7 +45314,7 @@ msgid "Storage"
msgstr "스토리지"
msgid "Storage nodes for new repositories"
-msgstr ""
+msgstr "새 ì €ìž¥ì†Œì˜ ìŠ¤í† ë¦¬ì§€ 노드"
msgid "Storage:"
msgstr "저장소:"
@@ -45231,6 +45463,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr "새 ë¼ì´ì„ ìŠ¤ 업로드"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45343,7 +45587,7 @@ msgid "Subscriptions|Start date"
msgstr ""
msgid "Subscription|Your subscription for %{strong}%{namespace_name}%{strong_close} has expired and you are now on %{pricing_link_start}the GitLab Free tier%{pricing_link_end}. Don't worry, your data is safe. Get in touch with our support team (%{support_email}). They'll gladly help with your subscription renewal."
-msgstr ""
+msgstr "%{strong}%{namespace_name}%{strong_close} ì— ëŒ€í•œ 구ë…ì´ ë§Œë£Œë˜ì–´ 현재 %{pricing_link_start}GitLab 프리 í‹°ì–´%{pricing_link_end}ì— ìžˆìŠµë‹ˆë‹¤. 걱정하지 마세요. ë°ì´í„°ëŠ” 안전합니다. ì§€ì› íŒ€ì— ë¬¸ì˜í•˜ì‹­ì‹œì˜¤(%{support_email}). ê·€í•˜ì˜ êµ¬ë… ê°±ì‹ ì„ ë„와드릴 것입니다."
msgid "Subtracted"
msgstr ""
@@ -45378,6 +45622,9 @@ msgstr "비활성화했습니다."
msgid "Successfully deleted WebAuthn device."
msgstr "성공ì ìœ¼ë¡œ WebAuthn 장치를 제거했습니다."
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "성공ì ìœ¼ë¡œ ì´ë©”ì¼ì„ 제거했습니다."
@@ -45396,6 +45643,9 @@ msgstr "성공ì ìœ¼ë¡œ 차단 해제했습니다."
msgid "Successfully unblocked"
msgstr "성공ì ìœ¼ë¡œ 차단 해제했습니다."
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -45989,7 +46239,7 @@ msgid "TagsPage|Only a project maintainer or owner can delete a protected tag"
msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
-msgstr ""
+msgstr "ì„ íƒì ìœ¼ë¡œ íƒœê·¸ì— ë©”ì‹œì§€ë¥¼ 추가합니다. ì´ í•­ëª©ì„ ë¹„ì›Œë‘ë©´ %{link_start}경량 태그%{link_end}ê°€ ìƒì„±ë©ë‹ˆë‹¤."
msgid "TagsPage|Permanently delete protected tag?"
msgstr ""
@@ -46055,6 +46305,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46067,7 +46320,13 @@ msgstr ""
msgid "Target branch"
msgstr "ëŒ€ìƒ ë¸Œëžœì¹˜"
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -46113,7 +46372,7 @@ msgid "TeamcityIntegration|Trigger TeamCity CI after a merge request has been cr
msgstr ""
msgid "TeamcityIntegration|Trigger TeamCity CI after every push to the repository, except branch delete"
-msgstr ""
+msgstr "브랜치 삭제를 제외하고 리í¬ì§€í† ë¦¬ì— 푸쉬할 때마다 TeamCity CI 트리거"
msgid "TelegramIntegration|Leave blank to use your current token."
msgstr ""
@@ -46598,7 +46857,7 @@ msgid "The complete DevOps platform. One application with endless possibilities.
msgstr ""
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
-msgstr ""
+msgstr "%{timeout} ì´í›„ ì—°ê²° ì‹œê°„ì´ ì´ˆê³¼ë©ë‹ˆë‹¤. 리í¬ì§€í† ë¦¬ê°€ ëŠë¦° 경우 clone/push ì¡°í•©ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤."
msgid "The contact does not belong to the issue group's root ancestor"
msgstr ""
@@ -46613,7 +46872,7 @@ msgid "The content for this wiki page failed to render."
msgstr ""
msgid "The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository."
-msgstr ""
+msgstr "ì´ íŽ˜ì´ì§€ì˜ ë‚´ìš©ì€ UTF-8ë¡œ ì¸ì½”딩ë˜ì§€ 않습니다. íŽ¸ì§‘ì€ Git 리í¬ì§€í† ë¦¬ë¥¼ 통해서만 수행할 수 있습니다."
msgid "The contents of this group, its subgroups and projects will be permanently removed after %{deletion_adjourned_period} days on %{date}. After this point, your data cannot be recovered."
msgstr ""
@@ -46855,7 +47114,7 @@ msgid "The maximum file size is %{size}."
msgstr ""
msgid "The maximum number of tags that a single worker accepts for cleanup. If the number of tags goes above this limit, the list of tags to delete is truncated to this number. To remove this limit, set it to 0."
-msgstr ""
+msgstr "ë‹¨ì¼ ìž‘ì—…ìžê°€ 정리를 위해 허용하는 최대 태그 수입니다. 태그 수가 ì´ ì œí•œì„ ì´ˆê³¼í•˜ë©´ 삭제할 태그 목ë¡ì´ ì´ ì œí•œ 값으로 버려집니다. ì´ ì œí•œì„ ì œê±°í•˜ë ¤ë©´ 0으로 설정하십시오."
msgid "The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally."
msgstr ""
@@ -46879,7 +47138,7 @@ msgid "The name of the Jenkins project. Copy the name from the end of the URL to
msgstr ""
msgid "The number of changes to fetch from GitLab when cloning a repository. Lower values can speed up pipeline execution. Set to %{code_open}0%{code_close} or blank to fetch all branches and tags for each job"
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ë¥¼ cloneí•  ë•Œ GitLabì—ì„œ 가져올 변경 ì‚¬í•­ì˜ ìˆ˜ìž…ë‹ˆë‹¤. ë‚®ì€ ê°’ì€ íŒŒì´í”„ë¼ì¸ 실행 ì†ë„를 ë†’ì¼ ìˆ˜ 있습니다. ê° ìž‘ì—…ì— ëŒ€í•œ 모든 브랜치 ë° íƒœê·¸ë¥¼ 가져오려면 %{code_open}0%{code_close} ë˜ëŠ” 공백으로 설정하세요."
msgid "The number of merge requests merged by month."
msgstr ""
@@ -46893,9 +47152,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -46930,7 +47186,7 @@ msgid "The project was successfully imported."
msgstr ""
msgid "The related CI build failed."
-msgstr ""
+msgstr "관련 CI ë¹Œë“œì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤."
msgid "The remote mirror URL is invalid."
msgstr ""
@@ -46939,7 +47195,7 @@ msgid "The remote mirror took to long to complete."
msgstr ""
msgid "The remote repository is being updated..."
-msgstr ""
+msgstr "remote 리í¬ì§€í† ë¦¬ë¥¼ ì—…ë°ì´íŠ¸í•˜ëŠ” 중..."
msgid "The report artifact provided by the CI build couldn't be parsed."
msgstr ""
@@ -46948,13 +47204,13 @@ msgid "The report has been successfully prepared."
msgstr ""
msgid "The repository can be committed to, and issues, comments and other entities can be created."
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬ë¥¼ 커밋할 수 있고 ì´ìŠˆ, 댓글 ë° ê¸°íƒ€ ë‚´ìš©ì„ ìƒì„±í•  수 있습니다."
msgid "The repository for this project does not exist."
-msgstr "ì´ í”„ë¡œì íŠ¸ì˜ 저장소가 존재하지 않습니다."
+msgstr "ì´ í”„ë¡œì íŠ¸ì˜ 리í¬ì§€í† ë¦¬ê°€ 존재하지 않습니다."
msgid "The repository for this project is empty"
-msgstr "ì´ í”„ë¡œì íŠ¸ì˜ 저장소가 비어있습니다."
+msgstr "ì´ í”„ë¡œì íŠ¸ì˜ 리í¬ì§€í† ë¦¬ê°€ 비어있습니다."
msgid "The repository is being updated..."
msgstr "리í¬ì§€í† ë¦¬ë¥¼ ì—…ë°ì´íŠ¸í•˜ëŠ” 중입니다..."
@@ -46987,7 +47243,7 @@ msgid "The snippet can be accessed without any authentication."
msgstr "ì´ í”„ë¡œì íŠ¸ëŠ” ì¸ì¦ì—†ì´ 액세스 í•  수 있습니다."
msgid "The snippet can be accessed without any authentication. To embed snippets, a project must be public."
-msgstr ""
+msgstr "ìŠ¤ë‹ˆíŽ«ì€ ì¸ì¦ ì—†ì´ ì•¡ì„¸ìŠ¤í•  수 있습니다. ìŠ¤ë‹ˆíŽ«ì„ í¬í•¨í•˜ë ¤ë©´ 프로ì íŠ¸ê°€ 공개ë˜ì–´ì•¼ 합니다."
msgid "The snippet is visible only to me."
msgstr ""
@@ -47029,7 +47285,7 @@ msgid "The time period in seconds that the maximum requests per project limit ap
msgstr ""
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
-msgstr ""
+msgstr "ì—…ë°ì´íŠ¸ ìž‘ì—…ì€ %{number_of_minutes} 분 í›„ì— ì‹œê°„ 초과ë©ë‹ˆë‹¤. í° ë¦¬í¬ì§€í† ë¦¬ì˜ 경우 clone/push ì¡°í•©ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤."
msgid "The uploaded file was invalid. Supported file extensions are %{extensions}."
msgstr ""
@@ -47070,6 +47326,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47088,9 +47347,6 @@ msgstr "ê³„ì •ì— ì•¡ì„¸ìŠ¤í•  수 있는 SSH 키가 없습니다."
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47176,7 +47432,7 @@ msgid "There is already a repository with that name on disk"
msgstr "디스í¬ì— 해당 ì´ë¦„ì„ ê°€ì§„ 리í¬ì§€í† ë¦¬ê°€ ì´ë¯¸ 있습니다."
msgid "There is already a to-do item for this design."
-msgstr ""
+msgstr "ì´ ë””ìžì¸ì— 대한 í•  ì¼ ëª©ë¡ì´ ì´ë¯¸ 있습니다."
msgid "There is no chart data available."
msgstr "사용 가능한 차트 ë°ì´í„°ê°€ 없습니다."
@@ -47340,6 +47596,9 @@ msgstr "ì„ íƒí•œ ê·¸ë£¹ì˜ ìƒìœ„ ë¼ë²¨ì„ 가져오는 ë™ì•ˆ 오류가 ë°œìƒ
msgid "There was an error fetching the variables."
msgstr "변수를 가져오는 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47424,6 +47683,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47668,7 +47930,7 @@ msgid "This epic would exceed maximum number of related epics."
msgstr ""
msgid "This feature requires local storage to be enabled"
-msgstr ""
+msgstr "ì´ ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ë ¤ë©´ 로컬 저장소를 활성화해야 합니다."
msgid "This field is auto-calculated based on the Progress score of its direct children. You can overwrite this value but it will be replaced by the auto-calculation anytime the Progress score of its direct children are updated."
msgstr ""
@@ -47902,7 +48164,7 @@ msgid "This may expose confidential information as the selected fork is in anoth
msgstr ""
msgid "This means you can not push code until you create an empty repository or import existing one."
-msgstr "즉, 빈 저장소를 만들거나 기존 저장소를 가져올 때까지 코드를 Push 할 수 없습니다."
+msgstr "즉, 빈 리í¬ì§€í† ë¦¬ë¥¼ 만들거나 기존 저장소를 가져올 때까지 코드를 Push í•  수 없습니다."
msgid "This merge request branch is protected from force push."
msgstr ""
@@ -47928,9 +48190,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "ì´ ë¨¸ì§€ 리퀘스트(MR)는 잠겨있습니다."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -47949,11 +48217,11 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
-msgstr ""
+msgid "This pipeline was created by a schedule"
+msgstr "ì´ íŒŒì´í”„ë¼ì¸ì€ ì˜ˆì •ëœ ì¼ì •ì— ë”°ë¼ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤"
-msgid "This pipeline was triggered by a schedule."
-msgstr ""
+msgid "This pipeline was created by a schedule."
+msgstr "ì´ íŒŒì´í”„ë¼ì¸ì€ ì˜ˆì •ëœ ì¼ì •ì— ë”°ë¼ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "This process deletes the project repository and all related resources."
msgstr "ì´ í”„ë¡œì„¸ìŠ¤ëŠ” 프로ì íŠ¸ 리í¬ì§€í† ë¦¬ ë° ëª¨ë“  관련 리소스를 삭제합니다."
@@ -48031,19 +48299,19 @@ msgid "This report uses a supported MAJOR.MINOR schema version but the PATCH ver
msgstr "ì´ ë³´ê³ ì„œëŠ” 지ì›ë˜ëŠ” MAJOR.MINOR 스키마 ë²„ì „ì„ ì‚¬ìš©í•˜ì§€ë§Œ PATCH ë²„ì „ì€ ê³µê¸‰ì—…ì²´ 스키마 버전과 ì¼ì¹˜í•˜ì§€ 않습니다. 버전 %{find_latest_patch_version}ì— ëŒ€í•´ 유효성 검사를 ì‹œë„합니다."
msgid "This repository"
-msgstr "ì´ ì €ìž¥ì†Œ"
+msgstr "ì´ ë¦¬í¬ì§€í† ë¦¬"
msgid "This repository has never been checked."
-msgstr ""
+msgstr "ì´ ë¦¬í¬ì§€í† ë¦¬ëŠ” 확ì¸ëœ ì ì´ 없습니다."
msgid "This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch."
msgstr "ì´ ë¦¬í¬ì§€í† ë¦¬ëŠ” 현재 비어 있습니다. 새 파ì¼ì´ ë¸Œëžœì¹˜ì— í‘¸ì‹œëœ í›„ 새 Auto DevOps 파ì´í”„ë¼ì¸ì´ ìƒì„±ë©ë‹ˆë‹¤."
msgid "This repository was last checked %{last_check_timestamp}. The check %{strong_start}failed.%{strong_end} See the 'repocheck.log' file for error messages."
-msgstr ""
+msgstr "ì´ ë¦¬í¬ì§€í† ë¦¬ëŠ” %{last_check_timestamp}ì— ë§ˆì§€ë§‰ìœ¼ë¡œ ì ê²€í•˜ì˜€ìŠµë‹ˆë‹¤. ì ê²€ì— %{strong_start}실패%{strong_end}했습니다. ì—러 메시지는 'repocheck.log' 파ì¼ì„ 참조하십시오."
msgid "This repository was last checked %{last_check_timestamp}. The check passed."
-msgstr ""
+msgstr "ì´ ë¦¬í¬ì§€í† ë¦¬ëŠ” %{last_check_timestamp}ì— ë§ˆì§€ë§‰ìœ¼ë¡œ ì ê²€ë˜ì—ˆìŠµë‹ˆë‹¤ . ì ê²€ ê²°ê³¼ 성공ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "This runner will only run on pipelines triggered on protected branches"
msgstr ""
@@ -48102,7 +48370,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48142,7 +48410,7 @@ msgid "TierBadgePopover|Explore paid plans"
msgstr ""
msgid "TierBadgePopover|Start a free trial"
-msgstr ""
+msgstr "무료 í‰ê°€íŒ 시작"
msgid "TierBadgePopover|This group and all its related projects use the %{tier} GitLab tier. %{copyEnd}"
msgstr ""
@@ -48154,7 +48422,7 @@ msgid "TierBadgePopover|Want to enhance team productivity and access advanced fe
msgstr "팀 ìƒì‚°ì„±ì„ í–¥ìƒí•˜ê³  머지 승ì¸, 푸시 규칙, ì—픽, 코드 리뷰 ë¶„ì„ ë° ì»¨í…Œì´ë„ˆ 스캔과 ê°™ì€ ê³ ê¸‰ ê¸°ëŠ¥ì— ì•¡ì„¸ìŠ¤í•˜ê³  싶습니까? GitLabì´ ì œê³µí•˜ëŠ” 모든 ê¸°ëŠ¥ì„ 30ì¼ ë™ì•ˆ 무료로 사용해 보세요. ì‹ ìš© 카드가 필요하지 않습니다."
msgid "TierBadge|Free"
-msgstr ""
+msgstr "Free"
msgid "Time"
msgstr "시간"
@@ -48228,7 +48496,7 @@ msgstr "시간대"
msgid "TimeTrackingEstimated|Est"
msgstr "Est"
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48249,7 +48517,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48525,7 +48793,7 @@ msgid "To %{link_to_help} of your domain, add the above key to a TXT record with
msgstr ""
msgid "To Do"
-msgstr "í•  ì¼ ëª©ë¡"
+msgstr "í•  ì¼"
msgid "To GitLab"
msgstr "GitLab으로"
@@ -48558,16 +48826,16 @@ msgid "To complete registration, we need additional details from you."
msgstr ""
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
-msgstr ""
+msgstr "GitHub 리í¬ì§€í† ë¦¬ë¥¼ 연결하기 위해 %{personal_access_token_link}ì„ ì‚¬ìš©í•  수 있습니다. ê°œì¸ ì•¡ì„¸ìŠ¤ 토í°ì„ ìƒì„±í•  ë•Œ %{code_open}저장소%{code_close} 범위를 ì„ íƒí•´ì•¼ ì—°ê²°í•  수 있는 공개 ë° ê°œì¸ ë¦¬í¬ì§€í† ë¦¬ 목ë¡ì„ 표시할 수 있습니다."
msgid "To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories."
msgstr "GitHub 리í¬ì§€í† ë¦¬ë¥¼ 연결하려면 먼저 GitHub 리í¬ì§€í† ë¦¬ì†Œ 목ë¡ì— 접근할 수 있ë„ë¡ GitLabì— ê¶Œí•œì„ ë¶€ì—¬í•´ì•¼ 합니다."
msgid "To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:"
-msgstr "GitHub ì €ìž¥ì†Œì— ì—°ê²°í•˜ë ¤ë©´, 먼저 GitHub 저장소 목ë¡ì„ 액세스 í•  수 있ë„ë¡ GitLabì— ì—‘ì„¸ìŠ¤ ê¶Œí•œì„ ë¶€ì—¬í•´ì•¼í•©ë‹ˆë‹¤:"
+msgstr "GitHub 리í¬ì§€í† ë¦¬ì— 연결하려면, 먼저 GitHub 리í¬ì§€í† ë¦¬ 목ë¡ì„ 액세스 í•  수 있ë„ë¡ GitLabì— ì—‘ì„¸ìŠ¤ ê¶Œí•œì„ ë¶€ì—¬í•´ì•¼í•©ë‹ˆë‹¤:"
msgid "To connect an SVN repository, check out %{svn_link}."
-msgstr "SVN ì €ìž¥ì†Œì— ì—°ê²°í•˜ë ¤ë©´ %{svn_link}ì„ í™•ì¸í•˜ì‹­ì‹œì˜¤."
+msgstr "SVN 리í¬ì§€í† ë¦¬ì— 연결하려면 %{svn_link}ì„ í™•ì¸í•˜ì‹­ì‹œì˜¤."
msgid "To continue using GitLab Enterprise Edition, upload the %{codeOpen}.gitlab-license%{codeClose} file or enter the license key you have received from GitLab Inc."
msgstr ""
@@ -48597,7 +48865,7 @@ msgid "To ensure no loss of personal content, this account should only be used f
msgstr ""
msgid "To find the state of this project's repository at the time of any of these versions, check out %{link_start}the tags%{link_end}"
-msgstr ""
+msgstr "ì´ëŸ¬í•œ ë²„ì „ì´ ìžˆì„ ë•Œ ì´ í”„ë¡œì íŠ¸ 리í¬ì§€í† ë¦¬ì˜ ìƒíƒœë¥¼ 찾으려면 %{link_start}태그%{link_end}를 확ì¸í•˜ì‹­ì‹œì˜¤."
msgid "To further protect your account, consider configuring a %{mfa_link_start}two-factor authentication%{mfa_link_end} method."
msgstr ""
@@ -48625,7 +48893,7 @@ msgstr "SVN 저장소ì—ì„œ 가져오려면, %{svn_link}(ì„)를 확ì¸í•˜ì„¸ìš”
msgid "To invite more users, you can reduce the number of users in your top-level group to %{free_limit} user or less. You can also upgrade to a paid tier which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgid_plural "To invite more users, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
-msgstr[0] ""
+msgstr[0] "ë” ë§Žì€ ì‚¬ìš©ìžë¥¼ 초대하려면 최ìƒìœ„ ê·¸ë£¹ì˜ ì‚¬ìš©ìž ìˆ˜ë¥¼ %{free_limit}명 ì´í•˜ë¡œ ì¤„ì¼ ìˆ˜ 있습니다. ì‚¬ìš©ìž ì œí•œì´ ì—†ëŠ” 유료 요금제로 업그레ì´ë“œí•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. 추가 ì‹œê°„ì´ í•„ìš”í•œ 경우, 무제한 사용ìžê°€ í¬í•¨ëœ 30ì¼ ë¬´ë£Œ í‰ê°€íŒì„ 시작할 수 있습니다."
msgid "To keep this project going, create a new issue"
msgstr ""
@@ -48667,10 +48935,10 @@ msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
-msgstr ""
+msgstr "%{link_start}ì½ê¸° ì „ìš©%{link_end} ìƒíƒœë¥¼ 제거하고 쓰기 ê¶Œí•œì„ ë‹¤ì‹œ 얻으려면 최ìƒìœ„ 그룹 소유ìžì—게 최ìƒìœ„ ê·¸ë£¹ì˜ ì‚¬ìš©ìž ìˆ˜ë¥¼ %{free_limit} 명 ì´í•˜ë¡œ 줄ì´ê±°ë‚˜ ì‚¬ìš©ìž ì œí•œì´ ì—†ëŠ” 유료 요금제로 업그레ì´ë“œí•˜ë„ë¡ ìš”ì²­í•˜ì‹­ì‹œì˜¤. ."
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
-msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr "%{link_start}ì½ê¸° ì „ìš©%{link_end} ìƒíƒœë¥¼ 제거하고 쓰기 액세스 ê¶Œí•œì„ ë‹¤ì‹œ 얻으려면 최ìƒìœ„ ê·¸ë£¹ì˜ ì‚¬ìš©ìž ìˆ˜ë¥¼ %{free_limit} 명 ì´í•˜ë¡œ ì¤„ì¼ ìˆ˜ 있습니다. ì‚¬ìš©ìž ì œí•œì´ ì—†ëŠ” 유료 등급으로 업그레ì´ë“œí•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. 추가 ì‹œê°„ì´ í•„ìš”í•œ 경우 무제한 사용ìžê°€ í¬í•¨ëœ 무료 30ì¼ í‰ê°€íŒì„ 시작할 수 있습니다."
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
msgstr ""
@@ -48844,7 +49112,7 @@ msgid "Todos|Undo mark all as done"
msgstr "ëª¨ë‘ ì™„ë£Œë¡œ 표시한 ê²ƒì„ ì·¨ì†Œ"
msgid "Todos|When an issue or merge request is assigned to you, or when you receive a %{strongStart}@mention%{strongEnd} in a comment, this automatically triggers a new item in your To-Do List."
-msgstr ""
+msgstr "ì´ìŠˆ ë˜ëŠ” 머지 리퀘스트가 나ì—게 할당ë˜ê±°ë‚˜ 댓글ì—ì„œ %{strongStart}@멘션%{strongEnd} ì„ ë°›ìœ¼ë©´ í•  ì¼ ëª©ë¡ì— 새 í•­ëª©ì´ ìžë™ìœ¼ë¡œ 트리거ë©ë‹ˆë‹¤."
msgid "Todos|You're all done!"
msgstr "ëª¨ë‘ ì™„ë£Œí•˜ì˜€ìŠµë‹ˆë‹¤!"
@@ -48951,6 +49219,9 @@ msgstr "ì´ ê°œì¸ ì•¡ì„¸ìŠ¤ 토í°ì€ íƒì§€ ì‹œ ìžë™ìœ¼ë¡œ 취소ë˜ì—ˆìŠµë‹
msgid "Tomorrow"
msgstr "ë‚´ì¼"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49016,7 +49287,7 @@ msgid "TopicSelect|Select a topic"
msgstr "TopicSelect|주제 ì„ íƒ"
msgid "Topics"
-msgstr ""
+msgstr "주제"
msgid "Topics could not be merged!"
msgstr "주제를 병합할 수 없습니다!"
@@ -49030,6 +49301,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49060,9 +49334,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49135,6 +49415,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49247,7 +49539,7 @@ msgid "Trending"
msgstr "ì¸ê¸°"
msgid "Trials|%{planName} Trial"
-msgstr ""
+msgstr "%{planName} í‰ê°€íŒ"
msgid "Trials|Compare all plans"
msgstr ""
@@ -49473,7 +49765,7 @@ msgid "URL is triggered when a merge request is created, updated, or merged"
msgstr ""
msgid "URL is triggered when a new tag is pushed to the repository"
-msgstr "새 태그가 ì €ìž¥ì†Œì— í‘¸ì‰¬ë˜ë©´ URLì´ íŠ¸ë¦¬ê±°ë©ë‹ˆë‹¤."
+msgstr "새 태그가 리í¬ì§€í† ë¦¬ì— 푸쉬ë˜ë©´ URLì´ íŠ¸ë¦¬ê±°ë©ë‹ˆë‹¤."
msgid "URL is triggered when repository is updated"
msgstr "리í¬ì§€í† ë¦¬ê°€ ì—…ë°ì´íŠ¸ë  ë•Œ URLì´ íŠ¸ë¦¬ê±°ë©ë‹ˆë‹¤."
@@ -49499,9 +49791,6 @@ msgstr "URL ë˜ëŠ” 요청 ID"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "사용ìžê°€ 차단ë©ë‹ˆë‹¤! 확실합니까?"
@@ -49512,7 +49801,7 @@ msgid "Unable to apply suggestions to a deleted line."
msgstr ""
msgid "Unable to build Slack link."
-msgstr ""
+msgstr "Slack ë§í¬ë¥¼ 빌드할 수 없습니다."
msgid "Unable to collect CPU info"
msgstr ""
@@ -49589,6 +49878,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49622,9 +49914,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr "사용ìžë¥¼ 확ì¸í•  수 ì—†ìŒ"
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49703,6 +49992,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -49953,7 +50245,7 @@ msgid "UpdateProject|Prune unreachable objects"
msgstr ""
msgid "UpdateProject|Pruning unreachable objects can lead to repository corruption."
-msgstr ""
+msgstr "접근할 수 없는 개체를 정리하면 리í¬ì§€í† ë¦¬ê°€ ì†ìƒë  수 있습니다"
msgid "UpdateRepositoryStorage|Failed to verify %{type} repository checksum from %{old} to %{new}"
msgstr "%{old}ì—ì„œ %{new}ë¡œ %{type} 리í¬ì§€í† ë¦¬ ì²´í¬ì„¬ì„ 확ì¸í•˜ì§€ 못했습니다."
@@ -50078,6 +50370,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50099,10 +50394,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50150,6 +50445,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50216,15 +50514,15 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr ""
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr "네임스페ì´ìŠ¤ëŠ” 현재 %{strong_start}%{used_storage}%{strong_end} 네임스페ì´ìŠ¤ 저장소를 사용하고 있습니다. %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}ì—ì„œ ì‚¬ìš©ëŸ‰ì„ ë³´ê³  관리합니다. %{docs_link_start}스토리지를 줄ì´ëŠ” 방법%{link_end}."
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr ""
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr ""
@@ -50415,7 +50713,7 @@ msgid "Use issue count"
msgstr ""
msgid "Use issue weight"
-msgstr ""
+msgstr "ì´ìŠˆ 가중치 사용"
msgid "Use issues to collaborate on ideas, solve problems, and plan work"
msgstr "ì´ìŠˆë¥¼ 사용하여 ì•„ì´ë””ì–´ì— ëŒ€í•œ ê³µë™ ìž‘ì—…, 문제 í•´ê²° ë° ìž‘ì—… 계íš"
@@ -50869,7 +51167,7 @@ msgid "UserProfile|You haven't created any snippets."
msgstr ""
msgid "UserProfile|Your projects can be available publicly, internally, or privately, at your choice."
-msgstr ""
+msgstr "프로ì íŠ¸ëŠ” 공개ì ìœ¼ë¡œ, 내부ì ìœ¼ë¡œ, ë˜ëŠ” ê°œì¸ì ìœ¼ë¡œ ì›í•˜ëŠ” 대로 사용할 수 있습니다."
msgid "UserProfile|at"
msgstr ""
@@ -50895,6 +51193,9 @@ msgstr ""
msgid "Username or email"
msgstr "사용ìžëª… ë˜ëŠ” ì´ë©”ì¼"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51507,13 +51808,13 @@ msgid "VisibilityLevel|The group and any internal projects can be viewed by any
msgstr ""
msgid "VisibilityLevel|The group and any public projects can be viewed without any authentication."
-msgstr ""
+msgstr "그룹 ë° ê³µê°œ 프로ì íŠ¸ëŠ” ì¸ì¦ ì—†ì´ ë³¼ 수 있습니다."
msgid "VisibilityLevel|The group and its projects can only be viewed by members."
msgstr ""
msgid "VisibilityLevel|The group, any public projects, and any of their members, issues, and merge requests can be viewed without authentication. Public groups and projects will be indexed by search engines. Read more about %{free_user_limit_doc_link_start}free user limits%{link_end}, or %{group_billings_link_start}upgrade to a paid tier%{link_end}."
-msgstr ""
+msgstr "그룹, 모든 공개 프로ì íŠ¸ ë° í•´ë‹¹ 멤버, ì´ìŠˆ ë° ë¨¸ì§€ ë¦¬í€˜ìŠ¤íŠ¸ì€ ì¸ì¦ ì—†ì´ ë³¼ 수 있습니다. 공개 그룹 ë° í”„ë¡œì íŠ¸ëŠ” 검색 ì—”ì§„ì— ì˜í•´ ì¸ë±ì‹±ë©ë‹ˆë‹¤. %{free_user_limit_doc_link_start} 무료 ì‚¬ìš©ìž í•œë„ì— ëŒ€í•´ ìžì„¸ížˆ 알아보십시오. %{link_end} ë˜ëŠ” %{group_billings_link_start}유료 요금제로 업그레ì´ë“œ%{link_end} 하십시오."
msgid "VisibilityLevel|The project can be accessed by any logged in user except external users."
msgstr "외부 사용ìžë¥¼ 제외한 모든 ë¡œê·¸ì¸ ì‚¬ìš©ìžê°€ 프로ì íŠ¸ì— 접근할 수 있습니다."
@@ -51537,28 +51838,28 @@ msgid "Vulnerabilities over time"
msgstr ""
msgid "Vulnerability"
-msgstr ""
+msgstr "취약성"
msgid "Vulnerability Report"
-msgstr ""
+msgstr "취약성 보고서"
msgid "Vulnerability remediated. Review before resolving."
msgstr ""
msgid "Vulnerability report"
-msgstr ""
+msgstr "취약성 보고서"
msgid "Vulnerability resolved in %{branch}"
-msgstr ""
+msgstr "ì·¨ì•½ì„±ì´ %{branch}ì—ì„œ í•´ê²°ë¨"
msgid "Vulnerability resolved in the default branch"
-msgstr ""
+msgstr "기본 브랜치ì—ì„œ ì·¨ì•½ì„±ì´ í™•ì¸ë¨"
msgid "VulnerabilityChart|%{formattedStartDate} to today"
msgstr ""
msgid "VulnerabilityChart|Severity"
-msgstr ""
+msgstr "심ê°ë„"
msgid "VulnerabilityDismissalReasons|Acceptable risk"
msgstr ""
@@ -51596,6 +51897,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51623,16 +51927,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -51648,7 +51955,7 @@ msgid "VulnerabilityManagement|A verified true-positive vulnerability"
msgstr ""
msgid "VulnerabilityManagement|Add vulnerability finding"
-msgstr ""
+msgstr "ì·¨ì•½ì  ì°¾ê¸° 추가"
msgid "VulnerabilityManagement|An unverified non-confirmed finding"
msgstr ""
@@ -51678,7 +51985,7 @@ msgid "VulnerabilityManagement|Identifier code and URL are required fields"
msgstr ""
msgid "VulnerabilityManagement|Manually add a vulnerability entry into the vulnerability report."
-msgstr ""
+msgstr "ì´ ì·¨ì•½ì„± ë³´ê³ ì„œì— ì·¨ì•½ì„± í•­ëª©ì„ ìˆ˜ë™ìœ¼ë¡œ 추가합니다."
msgid "VulnerabilityManagement|Name is a required field"
msgstr ""
@@ -51699,16 +52006,16 @@ msgid "VulnerabilityManagement|Select a method"
msgstr ""
msgid "VulnerabilityManagement|Select a severity level"
-msgstr ""
+msgstr "심ê°ë„ 수준 ì„ íƒ"
msgid "VulnerabilityManagement|Select a status"
-msgstr ""
+msgstr "ìƒíƒœ ì„ íƒ"
msgid "VulnerabilityManagement|Severity is a required field"
-msgstr ""
+msgstr "심ê°ë„는 필수 필드입니다."
msgid "VulnerabilityManagement|Something went wrong while creating vulnerability"
-msgstr ""
+msgstr "ì·¨ì•½ì„±ì„ ìƒì„±í•˜ëŠ” ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
msgstr "ëŒ“ê¸€ì„ ì‚­ì œí•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„하십시오."
@@ -51717,34 +52024,34 @@ msgid "VulnerabilityManagement|Something went wrong while trying to fetch relate
msgstr "ê´€ë ¨ëœ Jira ì´ìŠˆë¥¼ 가져오는 ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. %{linkStart}Jira 통합 설정 %{linkEnd}ì„(를) 확ì¸í•˜ê³  다시 ì‹œë„하십시오"
msgid "VulnerabilityManagement|Something went wrong while trying to refresh the vulnerability. Please try again later."
-msgstr ""
+msgstr "ì·¨ì•½ì„±ì„ ìƒˆë¡œ 고치는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„하십시오."
msgid "VulnerabilityManagement|Something went wrong while trying to retrieve the vulnerability history. Please try again later."
-msgstr ""
+msgstr "취약성 기ë¡ì„ 검색하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„하십시오."
msgid "VulnerabilityManagement|Something went wrong while trying to save the comment. Please try again later."
msgstr "ëŒ“ê¸€ì„ ì €ìž¥í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„하십시오."
msgid "VulnerabilityManagement|Something went wrong while trying to unlink the issue. Please try again later."
-msgstr ""
+msgstr "ì´ìŠˆì˜ ì—°ê²°ì„ í•´ì œí•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë‚˜ì¤‘ì— ë‹¤ì‹œ ì‹œë„하십시오."
msgid "VulnerabilityManagement|Something went wrong, could not get user."
-msgstr ""
+msgstr "문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 사용ìžë¥¼ 가져올 수 없습니다."
msgid "VulnerabilityManagement|Something went wrong, could not update vulnerability state."
-msgstr ""
+msgstr "문제가 ë°œìƒí•˜ì—¬ 취약성 ìƒíƒœë¥¼ ì—…ë°ì´íŠ¸í•  수 없습니다."
msgid "VulnerabilityManagement|Status is a required field"
-msgstr ""
+msgstr "ìƒíƒœëŠ” 필수 필드입니다."
msgid "VulnerabilityManagement|Submit vulnerability"
-msgstr ""
+msgstr "ì·¨ì•½ì  ì œì¶œ"
msgid "VulnerabilityManagement|Summary, detailed description, steps to reproduce, etc."
-msgstr ""
+msgstr "요약, ìƒì„¸í•œ 설명, 재현 단계 등"
msgid "VulnerabilityManagement|Verified as fixed or mitigated"
-msgstr ""
+msgstr "ê³ ì • ë˜ëŠ” ì™„í™”ëœ ê²ƒìœ¼ë¡œ 확ì¸"
msgid "VulnerabilityManagement|Vulnerability name or type. Ex: Cross-site scripting"
msgstr ""
@@ -51756,16 +52063,16 @@ msgid "VulnerabilityManagement|invalid issue link or ID"
msgstr ""
msgid "VulnerabilityStatusTypes|Confirmed"
-msgstr ""
+msgstr "확ì¸ë¨"
msgid "VulnerabilityStatusTypes|Dismissed"
-msgstr ""
+msgstr "무시ë¨"
msgid "VulnerabilityStatusTypes|Needs triage"
-msgstr ""
+msgstr "분류 필요"
msgid "VulnerabilityStatusTypes|Resolved"
-msgstr ""
+msgstr "í•´ê²°ë¨"
msgid "Vulnerability|%{file} was not found in commit %{ref}"
msgstr ""
@@ -51777,7 +52084,7 @@ msgid "Vulnerability|Activity"
msgstr "활ë™"
msgid "Vulnerability|Actual Response"
-msgstr ""
+msgstr "실제 ì‘답"
msgid "Vulnerability|Actual received response is the one received when this fault was detected"
msgstr ""
@@ -51786,28 +52093,28 @@ msgid "Vulnerability|Actual response:"
msgstr ""
msgid "Vulnerability|Add another identifier"
-msgstr ""
+msgstr "다른 ì‹ë³„ìž ì¶”ê°€"
msgid "Vulnerability|Additional Info"
-msgstr ""
+msgstr "추가 정보"
msgid "Vulnerability|Assert:"
msgstr ""
msgid "Vulnerability|Bug Bounty"
-msgstr ""
+msgstr "버그 바운티"
msgid "Vulnerability|CVSS v3"
-msgstr ""
+msgstr "CVSS v3"
msgid "Vulnerability|Class"
-msgstr ""
+msgstr "등급"
msgid "Vulnerability|Cluster"
-msgstr ""
+msgstr "í´ëŸ¬ìŠ¤í„°"
msgid "Vulnerability|Code Review"
-msgstr ""
+msgstr "코드 리뷰"
msgid "Vulnerability|Comments"
msgstr "댓글"
@@ -51816,16 +52123,16 @@ msgid "Vulnerability|Could not load prompt."
msgstr ""
msgid "Vulnerability|Crash address"
-msgstr ""
+msgstr "ì¶©ëŒ ì£¼ì†Œ"
msgid "Vulnerability|Crash address:"
msgstr ""
msgid "Vulnerability|Crash state"
-msgstr ""
+msgstr "ì¶©ëŒ ìƒíƒœ"
msgid "Vulnerability|Crash type"
-msgstr ""
+msgstr "ì¶©ëŒ ìœ í˜•"
msgid "Vulnerability|Crash type:"
msgstr ""
@@ -51834,22 +52141,22 @@ msgid "Vulnerability|Description"
msgstr "설명"
msgid "Vulnerability|Details"
-msgstr ""
+msgstr "세부사항"
msgid "Vulnerability|Detected"
-msgstr ""
+msgstr "ê°ì§€"
msgid "Vulnerability|Detection method"
-msgstr ""
+msgstr "ê°ì§€ 방법"
msgid "Vulnerability|Download"
-msgstr ""
+msgstr "다운로드"
msgid "Vulnerability|Enter the associated CVE or CWE entries for this vulnerability."
msgstr ""
msgid "Vulnerability|Evidence"
-msgstr ""
+msgstr "ì¦ê±°"
msgid "Vulnerability|Evidence:"
msgstr ""
@@ -51861,7 +52168,7 @@ msgid "Vulnerability|Explain this vulnerability and how to mitigate it with AI"
msgstr ""
msgid "Vulnerability|External Security Report"
-msgstr ""
+msgstr "외부 보안 보고서"
msgid "Vulnerability|False positive detected"
msgstr ""
@@ -51873,22 +52180,25 @@ msgid "Vulnerability|File:"
msgstr "파ì¼:"
msgid "Vulnerability|GitLab Security Report"
+msgstr "GitLab 보안 보고서"
+
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
msgstr ""
msgid "Vulnerability|Hide prompt"
msgstr ""
msgid "Vulnerability|Identifier"
-msgstr ""
+msgstr "ì‹ë³„ìž"
msgid "Vulnerability|Identifier URL"
-msgstr ""
+msgstr "ì‹ë³„ìž URL"
msgid "Vulnerability|Identifier code"
-msgstr ""
+msgstr "ì‹ë³„ìž ì½”ë“œ"
msgid "Vulnerability|Identifiers"
-msgstr ""
+msgstr "ì‹ë³„ìž"
msgid "Vulnerability|Image"
msgstr "ì´ë¯¸ì§€"
@@ -51906,7 +52216,7 @@ msgid "Vulnerability|Location"
msgstr "위치"
msgid "Vulnerability|Method"
-msgstr ""
+msgstr "방법"
msgid "Vulnerability|Namespace"
msgstr "네임스페ì´ìŠ¤"
@@ -51924,31 +52234,31 @@ msgid "Vulnerability|Providing the source code improves the response quality. If
msgstr ""
msgid "Vulnerability|Remove identifier row"
-msgstr ""
+msgstr "ì‹ë³„ìž í–‰ 제거"
msgid "Vulnerability|Reproduction Assets"
-msgstr ""
+msgstr "재ìƒì‚° ìžì‚°"
msgid "Vulnerability|Request"
-msgstr ""
+msgstr "요청"
msgid "Vulnerability|Request/Response"
-msgstr ""
+msgstr "요청/ì‘답"
msgid "Vulnerability|Response generated by AI"
msgstr ""
msgid "Vulnerability|Scanner Provider"
-msgstr ""
+msgstr "스ìºë„ˆ 공급ìž"
msgid "Vulnerability|Scanner:"
msgstr ""
msgid "Vulnerability|Security Audit"
-msgstr ""
+msgstr "보안 ê°ì‚¬"
msgid "Vulnerability|Select a severity"
-msgstr ""
+msgstr "심ê°ë„ ì„ íƒ"
msgid "Vulnerability|Send code with prompt"
msgstr ""
@@ -51960,7 +52270,7 @@ msgid "Vulnerability|Sent request:"
msgstr ""
msgid "Vulnerability|Set the status of the vulnerability finding based on the information available to you."
-msgstr ""
+msgstr "사용ìžê°€ 사용할 수 있는 정보를 기반으로 취약성 검색 ìƒíƒœë¥¼ 설정합니다."
msgid "Vulnerability|Severity"
msgstr "심ê°ë„"
@@ -51984,28 +52294,25 @@ msgid "Vulnerability|Status:"
msgstr "ìƒíƒœ:"
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
-msgstr ""
+msgstr "스ìºë„ˆì—ì„œ ì´ ì·¨ì•½ì„±ì´ ì˜¤ë¥˜ìœ¼ë¡œ 확ì¸ë˜ì—ˆìŠµë‹ˆë‹¤. ìƒíƒœë¥¼ 변경하기 ì „ì— í‰ê°€ë¥¼ 확ì¸í•˜ì‹­ì‹œì˜¤. %{linkStart}오류 íƒì§€ì— 대해 ìžì„¸ížˆ 알아봅니다.%{linkEnd}"
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
-msgstr ""
+msgstr "ë„구"
msgid "Vulnerability|Tool:"
msgstr "ë„구:"
msgid "Vulnerability|Training"
-msgstr ""
+msgstr "êµìœ¡"
msgid "Vulnerability|Training not available for this vulnerability."
-msgstr ""
+msgstr "ì´ ì·¨ì•½ì„±ì— ëŒ€í•œ êµìœ¡ì„ 사용할 수 없습니다."
msgid "Vulnerability|Try it out"
msgstr ""
@@ -52014,13 +52321,13 @@ msgid "Vulnerability|URL:"
msgstr ""
msgid "Vulnerability|Unmodified Response"
-msgstr ""
+msgstr "수정ë˜ì§€ ì•Šì€ ì‘답"
msgid "Vulnerability|Unmodified response:"
msgstr ""
msgid "Vulnerability|View training"
-msgstr ""
+msgstr "êµìœ¡ 보기"
msgid "Vulnerability|Vulnerable class:"
msgstr ""
@@ -52028,6 +52335,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr "경고:"
@@ -52155,7 +52465,7 @@ msgid "WebAuthn Devices (%{length})"
msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
+msgstr "WebAuthnì€ HTTPS ì§€ì› ì›¹ 사ì´íŠ¸ì—서만 ìž‘ë™í•©ë‹ˆë‹¤. ìžì„¸í•œ ë‚´ìš©ì€ ê´€ë¦¬ìžì—게 문ì˜í•˜ì‹­ì‹œì˜¤."
msgid "WebIDE|Fork project"
msgstr ""
@@ -52332,7 +52642,7 @@ msgid "Webhooks|Job events"
msgstr "ìž‘ì—… ì´ë²¤íŠ¸"
msgid "Webhooks|Mask portions of URL"
-msgstr "URLì˜ ë§ˆìŠ¤í¬ ë¶€ë¶„"
+msgstr ""
msgid "Webhooks|Member events"
msgstr ""
@@ -52355,6 +52665,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr "릴리스 ì´ë²¤íŠ¸"
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52457,15 +52773,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr "몇 가지 예가 있습니까?"
@@ -52550,11 +52857,11 @@ msgstr ""
msgid "When your trial ends, you'll have a maximum of %d member on the Free tier, or you can get more by upgrading to a paid tier."
msgid_plural "When your trial ends, you'll have a maximum of %d members on the Free tier, or you can get more by upgrading to a paid tier."
-msgstr[0] ""
+msgstr[0] "í‰ê°€íŒì´ 종료ë˜ë©´ 프리 í‹°ì–´ì— ìµœëŒ€ %dëª…ì˜ íšŒì›ì„ 유지하거나, 유료 요금제로 업그레ì´ë“œí•˜ì—¬ ë” ë§Žì€ íšŒì›ì„ 추가할 수 있습니다."
msgid "When your trial ends, you'll move to the Free tier, which has a limit of %{free_user_limit} seat. %{free_user_limit} seat will remain active, and members not occupying a seat will have the %{link_start}Over limit status%{link_end} and lose access to this group."
msgid_plural "When your trial ends, you'll move to the Free tier, which has a limit of %{free_user_limit} seats. %{free_user_limit} seats will remain active, and members not occupying a seat will have the %{link_start}Over limit status%{link_end} and lose access to this group."
-msgstr[0] ""
+msgstr[0] "í‰ê°€íŒì´ 종료ë˜ë©´ %{free_user_limit} 시트로 제한ë˜ëŠ” Free í‹°ì–´ë¡œ ì´ë™í•©ë‹ˆë‹¤. %{free_user_limit} 시트는 활성 ìƒíƒœë¡œ 유지ë˜ë©°, 시트를 차지하지 않는 구성ì›ì€ %{link_start}í•œë„ ì´ˆê³¼ ìƒíƒœ%{link_end} ì´ ë˜ì–´ ì´ ê·¸ë£¹ì— ì•¡ì„¸ìŠ¤í•  수 없게 ë©ë‹ˆë‹¤."
msgid "When:"
msgstr ""
@@ -52680,7 +52987,7 @@ msgid "WikiEmpty|You must be a project member in order to add wiki pages."
msgstr ""
msgid "WikiEmpty|You've enabled the Confluence Workspace integration. Your wiki will be viewable directly within Confluence. We are hard at work integrating Confluence more seamlessly into GitLab. If you'd like to stay up to date, follow our %{wiki_confluence_epic_link_start}Confluence epic%{wiki_confluence_epic_link_end}."
-msgstr ""
+msgstr "Confluence 워í¬ìŠ¤íŽ˜ì´ìŠ¤ í†µí•©ì„ í™œì„±í™” 하였습니다. ê·€í•˜ì˜ ìœ„í‚¤ëŠ” Confluence ë‚´ì—ì„œ ì§ì ‘ ë³¼ 수 있습니다. Confluence를 GitLabì— ë³´ë‹¤ ì›í™œí•˜ê²Œ 통합하기 위해 열심히 노력하고 있습니다. 최신 정보를 확ì¸í•˜ë ¤ë©´ %{wiki_confluence_epic_link_start}Confluence ì—픽%{wiki_confluence_epic_link_end}ì„ íŒ”ë¡œìš°í•˜ì„¸ìš”."
msgid "WikiHistoricalPage|Browse history"
msgstr ""
@@ -52817,6 +53124,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -52908,9 +53221,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -52929,9 +53239,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -52950,13 +53257,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr "ì—°ê²°ëœ í•­ëª©"
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53100,9 +53413,6 @@ msgstr "테스트 ì¼€ì´ìŠ¤"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr "ì´ ìž‘ì—… í•­ëª©ì€ ì‚¬ìš©í•  수 없습니다. 존재하지 않거나 ë³¼ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
@@ -53133,7 +53443,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53232,9 +53542,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr "공개 프로ì íŠ¸ì— 대해서만 ìž‘ì—… ê³µê°„ì„ ìƒì„±í•  수 있습니다."
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53494,6 +53801,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53503,6 +53813,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr "새 토í°ì„ 만들거나 ê°œì¸ ì•¡ì„¸ìŠ¤ í† í° ì„¤ì • %{pat_link}ì—ì„œ 확ì¸í•  수 있습니다."
@@ -53633,7 +53946,7 @@ msgid "You cannot set yourself to awaiting"
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
-msgstr ""
+msgstr "ì½ê¸° ì „ìš© 세컨ë”리 GitLab Geo ì¸ìŠ¤í„´ìŠ¤ì—는 쓸 수 없습니다. 대신 %{link_to_primary_node}ì„(를) 사용하십시오."
msgid "You cannot write to this read-only GitLab instance."
msgstr "ì½ê¸° ì „ìš© GitLab ì¸ìŠ¤í„´ìŠ¤ì—는 쓰기가 불가능합니다."
@@ -53701,9 +54014,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54085,10 +54395,10 @@ msgid "Your DevOps Reports give an overview of how you are using GitLab from a f
msgstr ""
msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. To ensure that your group does not become read-only, you should contact a user with the Owner role for this group to upgrade to a paid tier, or manage your usage. For more information about the upcoming usage limits, see our %{faq_link_start}FAQ%{link_end}."
-msgstr ""
+msgstr "무료 최ìƒìœ„ ê·¸ë£¹ì¸ %{group_name}ì—는 %{free_users_limit}를 초과하는 사용ìžê°€ 있고 %{free_storage_limit}를 초과하는 ë°ì´í„°ë¥¼ 사용합니다. 사용 í•œë„ê°€ 무료 최ìƒìœ„ ê·¸ë£¹ì— ì ìš©ëœ 후 ì´ ê·¸ë£¹ì˜ í”„ë¡œì íŠ¸ëŠ” %{read_only_link_start}ì½ê¸° ì „ìš© ìƒíƒœ%{link_end}ê°€ ë©ë‹ˆë‹¤. ê·¸ë£¹ì´ ì½ê¸° ì „ìš©ì´ ë˜ì§€ ì•Šë„ë¡ í•˜ë ¤ë©´ ì´ ê·¸ë£¹ì˜ ì†Œìœ ìž ì—­í• ì„ ê°€ì§„ 사용ìžì—게 ì—°ë½í•˜ì—¬ 유료 계층으로 업그레ì´ë“œí•˜ê±°ë‚˜ ì‚¬ìš©ëŸ‰ì„ ê´€ë¦¬í•´ì•¼ 합니다. ì˜ˆì •ëœ ì‚¬ìš© ì œí•œì— ëŒ€í•œ ìžì„¸í•œ ë‚´ìš©ì€ %{faq_link_start}FAQ%{link_end}참조하십시오."
msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. You should reduce the number of users or upgrade to a paid tier %{strong_start}before%{strong_end} you manage your storage usage. Otherwise, your Free top-level group will become read-only immediately because the 5-user limit applies. For more information, see our %{faq_link_start}FAQ%{link_end}.%{br_tag}%{br_tag}To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
-msgstr ""
+msgstr "무료 최ìƒìœ„ ê·¸ë£¹ì¸ %%{group_name}ì—는 %%{free_users_limit} ì´ìƒì˜ 사용ìžê°€ 있고 %%{free_storage_limit} ì´ìƒì˜ ë°ì´í„°ë¥¼ 사용합니다. 사용 ì œí•œì´ ë¬´ë£Œ 최ìƒìœ„ ê·¸ë£¹ì— ì ìš©ëœ 후 ì´ ê·¸ë£¹ì˜ í”„ë¡œì íŠ¸ëŠ” %%{read_only_link_start}ì½ê¸° ì „ìš© ìƒíƒœ%%{link_end}ë©ë‹ˆë‹¤. 스토리지 ì‚¬ìš©ëŸ‰ì„ ê´€ë¦¬í•˜ê¸° ì „ì— ì‚¬ìš©ìž ìˆ˜ë¥¼ 줄ì´ê±°ë‚˜%%{strong_end} 계층 %%{strong_start}ë¡œ 업그레ì´ë“œí•´ì•¼ 합니다. 그렇지 않으면 5ëª…ì˜ ì‚¬ìš©ìž ì œí•œì´ ì ìš©ë˜ë¯€ë¡œ 무료 최ìƒìœ„ ê·¸ë£¹ì€ ì¦‰ì‹œ ì½ê¸° ì „ìš©ì´ ë©ë‹ˆë‹¤. ìžì„¸í•œ ë‚´ìš©ì€ %%{faq_link_start}FAQ%{link_end}참조하십시오.%%{br_tag}%%{br_tag} %%{offer_availability_link_start}제한ì´%%{link_end} 최ìƒìœ„ ê·¸ë£¹ì— ë¯¸ì¹˜ëŠ” ì˜í–¥%%{link_end} 최소화하기 위해 GitLabì€ ì œí•œëœ ì‹œê°„ ë™ì•ˆ %%{promotion_link_start}ì¼íšŒì„± 70%% í• ì¸ì„ 제공합니다 , GitLab Premium SaaS 1ë…„ 구ë…. ì´ ì œì•ˆì€ 2023-10-31까지 유효합니다."
msgid "Your GPG keys"
msgstr ""
@@ -54112,7 +54422,7 @@ msgid "Your GitLab group"
msgstr ""
msgid "Your GitLab instance allows anyone to register for an account, which is a security risk on public-facing GitLab instances. You should deactivate new sign ups if public users aren't expected to register for an account."
-msgstr ""
+msgstr "GitLab ì¸ìŠ¤í„´ìŠ¤ì—서는 누구나 ê³„ì •ì„ ë“±ë¡í•  수 있습니다. ì´ëŠ” 공용 GitLab ì¸ìŠ¤í„´ìŠ¤ì˜ 보안 위험입니다. 공용 사용ìžê°€ ê³„ì •ì„ ë“±ë¡í•  것으로 예ìƒë˜ì§€ 않는 경우 새 등ë¡ì„ 비활성화해야 합니다."
msgid "Your GitLab version"
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "승ì¸ëœ 애플리케ì´ì…˜"
-msgid "Your browser does not support iFrames"
-msgstr "브ë¼ìš°ì €ê°€ iFrames를 지ì›í•˜ì§€ 않습니다"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54319,9 +54626,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54346,6 +54650,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr "검색어와 ì¼ì¹˜í•˜ëŠ” ì»¤ë°‹ì´ ì—†ìŠµë‹ˆë‹¤."
@@ -54456,10 +54763,10 @@ msgid "[No reason]"
msgstr ""
msgid "[REDACTED]"
-msgstr ""
+msgstr "[REDACTED]"
msgid "[Redacted]"
-msgstr ""
+msgstr "[Redacted]"
msgid "[Supports GitLab-flavored markdown, including quick actions]"
msgstr ""
@@ -54513,6 +54820,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54594,7 +54904,7 @@ msgid "branch name"
msgstr "브랜치 ì´ë¦„"
msgid "builds"
-msgstr ""
+msgstr "빌드"
msgid "by"
msgstr "by"
@@ -54620,6 +54930,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -54789,7 +55102,7 @@ msgid "ciReport|All tools"
msgstr ""
msgid "ciReport|Analyze a deployed version of your web application for known vulnerabilities by examining it from the outside in. DAST works by simulating external attacks on your application while it is running."
-msgstr ""
+msgstr "웹 ì‘ìš© í”„ë¡œê·¸ëž¨ì˜ ë°°í¬ëœ 버전ì—ì„œ 알려진 취약ì ì„ 검사하여 분ì„합니다. DAST는 ì‘ìš© í”„ë¡œê·¸ëž¨ì´ ì‹¤í–‰ë˜ëŠ” ë™ì•ˆ ì‘ìš© í”„ë¡œê·¸ëž¨ì— ëŒ€í•œ 외부 ê³µê²©ì„ ì‹œë®¬ë ˆì´ì…˜í•˜ì—¬ ìž‘ë™í•©ë‹ˆë‹¤."
msgid "ciReport|Automatically apply the patch in a new branch"
msgstr ""
@@ -54918,7 +55231,7 @@ msgid "ciReport|Generic Report"
msgstr "ì¼ë°˜ ë³´ê³ "
msgid "ciReport|Investigate this vulnerability by creating an issue"
-msgstr ""
+msgstr "ì´ìŠˆ ìƒì„±ì„ 위한 취약성 조사"
msgid "ciReport|License Compliance"
msgstr ""
@@ -55021,7 +55334,7 @@ msgid "ciReport|There was an error creating the merge request. Please try again.
msgstr "머지 리퀘스트 ìƒì„±ì— ì—러가 ìƒê²¼ìŠµë‹ˆë‹¤. 다시 ì‹œë„해주세요."
msgid "ciReport|There was an error dismissing the vulnerability. Please try again."
-msgstr ""
+msgstr "ì·¨ì•½ì  í•´ì œì— ì—러가 ìƒê²¼ìŠµë‹ˆë‹¤. 다시 ì‹œë„해주세요."
msgid "ciReport|There was an error dismissing the vulnerability: %{error}"
msgstr ""
@@ -55128,6 +55441,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr "커밋 %{linkStart}%{shortId}%{linkEnd}ì— ëŒ€í•œ 파ì´í”„ë¼ì¸ ìƒì„±ë¨"
+
msgid "daily"
msgstr "ì¼ë³„"
@@ -55193,6 +55509,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55276,10 +55595,7 @@ msgid_plural "files"
msgstr[0] "파ì¼"
msgid "finding is not found or is already attached to a vulnerability"
-msgstr ""
-
-msgid "for Workspace is required to be public"
-msgstr ""
+msgstr "ì°¾ì„ ìˆ˜ 없거나 취약ì ì— ì´ë¯¸ 첨부ë˜ì–´ 있습니다."
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55323,7 +55639,7 @@ msgid_plural "had %{count} failed jobs"
msgstr[0] "실패한 ìž‘ì—…ì´ %{count} ê°œ 있었습니다."
msgid "has already been linked to another vulnerability"
-msgstr ""
+msgstr "ì´ë¯¸ 다른 ì·¨ì•½ì„±ì— ë§í¬ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "has already been taken"
msgstr ""
@@ -55540,6 +55856,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56010,6 +56329,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56019,6 +56341,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56046,6 +56371,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56103,6 +56431,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr "목표"
+
msgid "on or after"
msgstr ""
@@ -56163,13 +56494,13 @@ msgid "pipeline schedules documentation"
msgstr ""
msgid "pipelineEditorWalkthrough|Let's do this!"
-msgstr ""
+msgstr "시작해봅시다!"
msgid "pipelineEditorWalkthrough|See how GitLab pipelines work"
-msgstr ""
+msgstr "GitLab 파ì´í”„ë¼ì¸ì´ 어떻게 ìž‘ë™í•˜ëŠ”지 살펴보세요"
msgid "pipelineEditorWalkthrough|This %{codeStart}.gitlab-ci.yml%{codeEnd} file creates a simple test pipeline."
-msgstr ""
+msgstr "ì´ %{codeStart}.gitlab-ci.yml%{codeEnd} 파ì¼ì€ 간단한 테스트 파ì´í”„ë¼ì¸ì„ ìƒì„±í•©ë‹ˆë‹¤."
msgid "pipelineEditorWalkthrough|Use the %{boldStart}commit changes%{boldEnd} button at the bottom of the page to run the pipeline."
msgstr ""
@@ -56261,7 +56592,7 @@ msgid "remove start date"
msgstr ""
msgid "remove weight"
-msgstr ""
+msgstr "가중치 제거"
msgid "removed a %{link_type} link"
msgstr "%{link_type} ë§í¬ë¥¼ 제거했습니다"
@@ -56280,14 +56611,14 @@ msgid "reply should have same confidentiality as top-level note"
msgstr ""
msgid "repositories"
-msgstr ""
+msgstr "리í¬ì§€í† ë¦¬"
msgid "repository"
msgid_plural "repositories"
msgstr[0] "리í¬ì§€í† ë¦¬"
msgid "repository:"
-msgstr "저장소:"
+msgstr "리í¬ì§€í† ë¦¬:"
msgid "role's base access level does not match the access level of the membership"
msgstr "ì—­í• ì˜ ê¸°ë³¸ 액세스 ìˆ˜ì¤€ì´ ë©¤ë²„ì‹­ì˜ ì•¡ì„¸ìŠ¤ 수준과 ì¼ì¹˜í•˜ì§€ 않습니다."
@@ -56396,6 +56727,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr "시작ë¨"
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56438,6 +56772,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56486,9 +56823,6 @@ msgstr "합계는 %{size} 보다 작거나 같아야 함"
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56544,6 +56878,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "버전 %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
@@ -56570,16 +56907,16 @@ msgid "vulnerability|Add a comment"
msgstr "댓글 추가"
msgid "vulnerability|Add a comment or reason for dismissal"
-msgstr ""
+msgstr "ëŒ“ê¸€ì„ ë‹¬ê±°ë‚˜ 종류 ì´ìœ  추가"
msgid "vulnerability|Add comment"
msgstr "댓글 추가"
msgid "vulnerability|Add comment & dismiss"
-msgstr ""
+msgstr "댓글 추가하고 종료"
msgid "vulnerability|Add comment and dismiss"
-msgstr ""
+msgstr "ëŒ“ê¸€ì„ ì¶”ê°€í•˜ê³  종료"
msgid "vulnerability|Dismiss vulnerability"
msgstr ""
@@ -56591,7 +56928,7 @@ msgid "vulnerability|Undo dismiss"
msgstr ""
msgid "vulnerability|dismissed"
-msgstr ""
+msgstr "무시ë¨"
msgid "was set to auto-merge by"
msgstr ""
diff --git a/locale/ku_TR/gitlab.po b/locale/ku_TR/gitlab.po
index 8ba4492f62d..92a1e129428 100644
--- a/locale/ku_TR/gitlab.po
+++ b/locale/ku_TR/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ku\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ky_KG/gitlab.po b/locale/ky_KG/gitlab.po
index 03d9cef8edf..ce10d500df6 100644
--- a/locale/ky_KG/gitlab.po
+++ b/locale/ky_KG/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ky\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/lt_LT/gitlab.po b/locale/lt_LT/gitlab.po
index a6a9032ae06..6b31e7e24d2 100644
--- a/locale/lt_LT/gitlab.po
+++ b/locale/lt_LT/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: lt\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -47,6 +47,13 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr ""
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -910,7 +914,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -988,6 +992,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1063,6 +1073,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,10 +1564,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1663,6 +1676,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2730,6 +2782,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2910,6 +2965,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3222,6 +3280,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3246,6 +3307,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3273,7 +3337,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4113,7 +4177,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4737,6 +4801,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5175,9 +5242,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5268,6 +5332,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5455,6 +5522,9 @@ msgstr[3] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5470,6 +5540,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6595,7 +6689,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6750,6 +6844,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6966,6 +7063,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8053,6 +8159,9 @@ msgstr[3] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8065,6 +8174,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8171,9 +8292,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8261,9 +8379,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,7 +9555,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9827,6 +9942,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9979,7 +10100,7 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10435,15 +10559,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10703,6 +10833,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11000,15 +11133,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11301,6 +11428,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11325,6 +11455,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11748,9 +11881,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12383,7 +12513,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12599,15 +12729,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12671,6 +12804,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14429,9 +14616,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16342,6 +16532,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16369,7 +16565,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16384,7 +16580,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16408,6 +16604,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16468,7 +16667,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16486,10 +16685,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16661,6 +16863,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16676,12 +16896,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17963,9 +18180,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18008,6 +18222,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18146,9 +18363,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18398,7 +18609,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18545,12 +18756,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18596,6 +18813,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19737,6 +19972,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21852,6 +22063,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22008,7 +22219,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22128,9 +22348,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22527,6 +22753,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22593,9 +22822,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22971,7 +23197,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23160,7 +23386,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23172,7 +23398,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23190,9 +23416,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23618,6 +23841,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23883,9 +24109,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23925,6 +24148,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24108,6 +24337,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24984,66 +24916,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25867,15 +25765,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26294,18 +26183,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26555,10 +26438,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26567,16 +26462,26 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27458,6 +27369,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27509,6 +27423,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27605,9 +27522,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27973,6 +27884,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28688,6 +28602,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29117,6 +29043,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29129,6 +29058,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29435,6 +29367,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31225,15 +31259,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31252,12 +31289,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31276,6 +31319,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31712,6 +31758,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31736,6 +31785,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,10 +31809,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31814,9 +31872,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33087,6 +33148,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33279,24 +33340,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34012,6 +34109,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34159,7 +34259,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34606,9 +34709,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34723,12 +34823,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35179,6 +35273,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35827,9 +35921,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35941,6 +36032,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36877,9 +36962,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37504,6 +37592,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37576,6 +37667,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38395,6 +38489,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39048,9 +39151,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39581,9 +39657,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40187,9 +40254,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42150,13 +42262,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results..."
-msgstr ""
-
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42407,6 +42516,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44095,6 +44333,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46203,6 +46459,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46221,6 +46480,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46898,7 +47163,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47940,9 +48211,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48276,6 +48547,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,10 +49081,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48954,7 +49234,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,7 +49360,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49101,7 +49381,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50966,10 +51273,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51083,13 +51393,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51765,6 +52075,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53333,15 +53661,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53817,9 +54139,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56141,6 +56469,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56229,9 +56560,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57398,6 +57741,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57440,6 +57786,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57488,9 +57837,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/mk_MK/gitlab.po b/locale/mk_MK/gitlab.po
index 685b8639770..e29d291ecaa 100644
--- a/locale/mk_MK/gitlab.po
+++ b/locale/mk_MK/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: mk\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:32\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ml_IN/gitlab.po b/locale/ml_IN/gitlab.po
index 9f2e8202a18..7b2272d26d7 100644
--- a/locale/ml_IN/gitlab.po
+++ b/locale/ml_IN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ml-IN\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/mn_MN/gitlab.po b/locale/mn_MN/gitlab.po
index fadcfcbd279..6f11f719795 100644
--- a/locale/mn_MN/gitlab.po
+++ b/locale/mn_MN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: mn\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ms_MY/gitlab.po b/locale/ms_MY/gitlab.po
index b2fe15a7569..7adee22d83f 100644
--- a/locale/ms_MY/gitlab.po
+++ b/locale/ms_MY/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ms\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -44,6 +44,10 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+
msgid " or "
msgstr ""
@@ -574,9 +578,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -622,7 +623,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -700,6 +701,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -775,6 +782,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1203,10 +1213,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1312,6 +1322,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1755,15 +1768,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1803,12 +1825,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1830,6 +1870,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1845,6 +1888,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -1857,6 +1903,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -1869,9 +1918,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2076,9 +2122,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2193,6 +2236,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2250,6 +2296,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2301,6 +2350,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2481,6 +2533,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2793,6 +2848,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2817,6 +2875,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2844,7 +2905,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3684,7 +3745,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4308,6 +4369,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4746,9 +4810,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4839,6 +4900,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5023,6 +5087,9 @@ msgstr[0] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5038,6 +5105,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5147,6 +5220,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5192,15 +5268,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5222,6 +5301,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5237,6 +5322,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5279,24 +5367,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6045,9 +6139,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6127,7 +6218,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6267,6 +6358,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6474,6 +6568,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6591,6 +6688,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7518,7 +7618,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7533,15 +7633,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7558,6 +7661,9 @@ msgstr[0] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7570,6 +7676,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7597,6 +7709,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7640,6 +7755,9 @@ msgstr[0] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7673,9 +7791,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7763,9 +7878,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -8837,7 +8949,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -8933,7 +9045,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9320,6 +9432,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9410,6 +9525,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9466,7 +9584,7 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -9922,15 +10043,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -9982,9 +10103,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10006,12 +10124,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10027,9 +10157,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10187,6 +10314,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10484,15 +10614,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10782,6 +10906,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10806,6 +10933,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11229,9 +11359,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11301,31 +11428,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11753,9 +11880,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11801,6 +11925,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11858,7 +11985,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12074,15 +12201,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12146,6 +12276,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12317,6 +12450,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -12836,6 +12972,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -12869,6 +13008,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -12881,9 +13044,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -12971,6 +13143,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13517,6 +13698,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -13895,9 +14079,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14235,9 +14416,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14411,6 +14589,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14501,6 +14682,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14723,6 +14907,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15226,9 +15413,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15350,9 +15534,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15568,6 +15749,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15586,6 +15770,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15766,6 +15953,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15793,7 +15986,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -15808,7 +16001,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -15832,6 +16025,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -15892,7 +16088,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -15910,10 +16106,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -15997,6 +16193,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16067,9 +16269,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16082,6 +16281,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16097,12 +16314,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16172,12 +16392,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17366,9 +17580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17411,6 +17622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17549,9 +17763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17573,7 +17784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17687,9 +17898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -17801,7 +18009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -17948,12 +18156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -17999,6 +18213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18035,6 +18255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18137,6 +18360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18891,6 +19120,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19137,6 +19369,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19791,9 +20026,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -19818,9 +20050,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20188,33 +20417,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20907,6 +21109,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21234,6 +21442,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21249,6 +21460,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21264,12 +21478,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21390,7 +21598,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21429,6 +21640,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21441,6 +21655,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21510,9 +21727,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21543,6 +21757,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21783,6 +22000,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -21798,7 +22021,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -21975,9 +22201,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22353,7 +22576,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22542,7 +22765,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22554,7 +22777,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22572,9 +22795,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -22994,6 +23214,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23256,9 +23479,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23298,6 +23518,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23481,6 +23707,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23889,7 +24121,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -23916,6 +24148,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -23958,381 +24196,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24348,66 +24277,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24837,6 +24715,14 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25192,6 +25078,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25228,15 +25117,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25318,9 +25201,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25652,18 +25532,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25913,10 +25787,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -25925,16 +25811,23 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -25982,6 +25875,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26318,6 +26214,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26816,6 +26715,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -26867,6 +26769,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -26963,9 +26868,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27226,9 +27128,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27325,6 +27224,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28019,6 +27921,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28028,6 +27933,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28433,6 +28341,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28448,6 +28362,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28460,6 +28377,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28766,6 +28686,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29021,6 +29037,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29453,9 +29472,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29552,6 +29568,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30430,10 +30449,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30511,6 +30530,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30541,15 +30563,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30568,12 +30593,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30592,6 +30623,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -30815,9 +30852,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31025,6 +31059,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31049,6 +31086,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31067,10 +31110,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31127,9 +31173,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31181,6 +31224,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32379,6 +32428,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32406,9 +32458,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32571,24 +32620,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33301,6 +33386,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33448,7 +33536,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33895,9 +33986,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34012,12 +34100,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34468,6 +34550,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34591,9 +34676,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35116,9 +35198,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35230,6 +35309,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35353,9 +35435,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35371,9 +35450,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35410,9 +35486,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35473,6 +35546,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35497,9 +35573,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35731,7 +35804,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36166,9 +36239,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36658,6 +36728,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -36793,6 +36869,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -36865,6 +36944,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37684,6 +37766,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37756,7 +37844,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -37809,10 +37897,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -37824,6 +37915,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -37842,6 +37936,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -37899,9 +37996,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -37968,9 +38062,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38331,9 +38422,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38473,34 +38561,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38834,9 +38898,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -38849,6 +38910,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -38858,9 +38922,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39140,12 +39201,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39446,9 +39501,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -39858,6 +39910,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40283,6 +40338,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40567,7 +40625,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40649,6 +40707,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40857,6 +40918,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -40965,9 +41029,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -40980,7 +41041,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41106,10 +41167,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41124,6 +41188,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41136,7 +41218,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41148,7 +41230,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41160,6 +41242,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41187,9 +41275,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41301,6 +41398,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41370,13 +41470,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41594,6 +41691,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41750,6 +41850,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -41759,7 +41865,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -41888,7 +42003,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -41900,12 +42015,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42171,6 +42292,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42183,13 +42307,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42219,13 +42343,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42234,6 +42364,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42303,9 +42439,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42360,6 +42493,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42375,9 +42511,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42408,6 +42550,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42525,9 +42670,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42571,7 +42713,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -42919,9 +43061,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -42991,6 +43130,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43015,12 +43157,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43048,9 +43202,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43060,27 +43220,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43120,15 +43313,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43156,6 +43379,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43276,6 +43502,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43354,6 +43583,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44187,6 +44419,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44280,9 +44515,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45231,6 +45463,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45378,6 +45622,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45396,6 +45643,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46055,6 +46305,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46067,7 +46320,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47070,6 +47326,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47088,9 +47347,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47340,6 +47596,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47424,6 +47683,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47928,9 +48190,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -47949,10 +48217,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48102,7 +48370,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48228,7 +48496,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48249,7 +48517,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48669,7 +48937,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48951,6 +49219,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49030,6 +49301,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49060,9 +49334,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49135,6 +49415,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49499,9 +49791,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49589,6 +49878,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49622,9 +49914,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49703,6 +49992,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50078,6 +50370,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50099,10 +50394,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50150,6 +50445,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50216,13 +50514,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -50895,6 +51193,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51596,6 +51897,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51623,16 +51927,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -51875,6 +52182,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -51989,10 +52299,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52028,6 +52335,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52355,6 +52665,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52457,15 +52773,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -52817,6 +53124,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -52908,9 +53221,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -52929,9 +53239,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -52950,13 +53257,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53100,9 +53413,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53133,7 +53443,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53232,9 +53542,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53494,6 +53801,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53503,6 +53813,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53701,9 +54014,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54319,9 +54626,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54346,6 +54650,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54513,6 +54820,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54620,6 +54930,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55128,6 +55441,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55193,6 +55509,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55278,9 +55597,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55540,6 +55856,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56010,6 +56329,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56019,6 +56341,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56046,6 +56371,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56103,6 +56431,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56396,6 +56727,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56438,6 +56772,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56486,9 +56823,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56544,6 +56878,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/nb_NO/gitlab.po b/locale/nb_NO/gitlab.po
index 734919c3938..09d76f98138 100644
--- a/locale/nb_NO/gitlab.po
+++ b/locale/nb_NO/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: nb\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr " %{start} til %{end}"
@@ -45,6 +45,11 @@ msgstr " og "
msgid " and %{sliced}"
msgstr " og %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " eller "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr "%{count} totalvekt"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} kunne ikke bli funnet."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} dager til etikettene fjernes automatisk"
@@ -718,7 +720,7 @@ msgstr "%{edit_in_new_fork_notice} Prøv å laste opp en fil igjen."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr "%{issuesSize} med en grense på %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Hva er nytt%{italic_end} er inaktiv og kan ikke vises."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} saker med en grense på %{maxIssueCount}"
@@ -871,6 +879,9 @@ msgstr "%{labelStart}Uendret svar:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} utilgjengelig"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,11 +1330,11 @@ msgstr "%{verb} %{time_spent_value} brukt tid."
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} lar deg sende varsler til nettapplikasjoner som svar på hendelser i en gruppe eller et prosjekt."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} lar deg sende varsler til nettapplikasjoner som svar på hendelser i en gruppe eller et prosjekt. Vi anbefaler at du bruker en %{integrations_link_start}integrasjon%{link_end} som det foretrukne fremfor en webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr "%{widget} alternativer"
@@ -1429,6 +1440,9 @@ msgstr "+ %{amount} til"
msgid "+ %{count} more"
msgstr "+ %{count} til"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} til"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr "Automatisk fullføring"
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr "Hjelpsom"
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr "Lite hjelpsom"
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr "Feil"
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr "Rapporter over misbruk"
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr "Verifisering"
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Aksepter invitasjon"
@@ -2444,6 +2494,9 @@ msgstr "Grupper"
msgid "AccessDropdown|Roles"
msgstr "Roller"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "Brukere"
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr "Handling"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr "Legg til forslag i bunken"
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr "Legg til vurdering"
msgid "Add to tree"
msgstr "Legg til i treet"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr "Legg til/Fjern"
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr "Å blokkere brukeren har følgende effekter:"
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr "En feil oppstod under forhåndsvisning av blobben"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr "En feil oppstod under innhenting av saker."
msgid "An error occurred while fetching label colors."
msgstr "En feil oppstod under innhenting av stempelfarger."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "En feil oppstod under trigging av jobben."
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "En feil oppstod under oppdatering av godkjennere"
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr "Vert"
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr "Språk"
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr "Er du sikker på at du vil slette denne enheten? Denne handlingen kan ik
msgid "Are you sure you want to delete this label?"
msgstr "Er du sikker på at du vil slette dette stempelet?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Er du sikker på at du vil slette denne rørledningsplanleggingen?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "Er du sikker på at du vil slette denne rørledningen? Dette vil tidsutløpe alle rørledningsmellombuffere og slette relaterte objekter, slik som byggversjoner, loggføringer, artefakter og triggere. Denne handlingen kan ikke angres på."
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "Spør igjen senere"
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr "Aktiv"
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "Verdi"
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr "Kan ikke fjerne brukeren"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr "Direkte medlemskap"
msgid "Billing|Enter at least three characters to search."
msgstr "Skriv inn minst tre tegn for å søke."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr "Ingen brukere å vise."
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] "Forhindret av %d saker"
msgid "Blocked issue"
msgstr "Blokkert sak"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr "Blokkering"
@@ -7839,9 +7958,6 @@ msgstr "Ingen samsvarende resultater"
msgid "BoardNewEpic|Search groups"
msgstr "Søk etter grupper"
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr "Ingen samsvarende resultater"
@@ -7929,9 +8045,6 @@ msgstr "Velg stempler"
msgid "BoardScope|Select milestone"
msgstr "Velg milepæl"
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr "Startet"
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,8 +9215,8 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr "Kan distribueres manuelt til"
-msgid "Can create groups:"
-msgstr "Kan opprette grupper:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr ""
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr "Endringer:"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Kontrollerer %{text} tilgjengelighet …"
@@ -9637,8 +9756,8 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText}-plan"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr "Velg en mal …"
msgid "Choose a type..."
msgstr "Velg en type …"
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Velg fil …"
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr "Avbryt"
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr "Miljøer"
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr "Fjern variabel"
-msgid "CiVariables|Remove variable row"
-msgstr "Fjern variabel-rad"
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Type"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Verdi"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (Alle miljøer)"
-
msgid "CiVariable|All environments"
msgstr "Alle miljøer"
@@ -10359,6 +10487,9 @@ msgstr "Klienter"
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Klone"
@@ -10656,15 +10787,9 @@ msgstr "Klynge-helse"
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr "Klynge-nivå"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr "Kodevurdering"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr "Brukerkohorter vises for de siste %{months_included} månedene. Bare bru
msgid "Collapse"
msgstr "Folde sammen"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr "Vis åpne fletteforespørsler"
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr "Konfidensialitet"
msgid "Configuration help"
msgstr "Oppsettshjelp"
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr "Feil ved tilkobling"
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "Kontakt kundestøtte"
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr "Opprett utgivelse"
msgid "Create requirement"
msgstr "Opprett krav"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "Cron-tidssone"
-
msgid "Cron time zone"
msgstr "Cron-tidssone"
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "Minimum = 1 sekund, Maks = 3600 sekunder"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr "Slett stempel: %{labelName}"
msgid "Delete pipeline"
msgstr "Slett rørledning"
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr "Slett prosjekt"
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr "Innpakker"
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "Skru av/på sårbarhetsliste"
@@ -15958,6 +16146,12 @@ msgstr "Tidssone"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} andre"
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr "Nåværende prosjekt"
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr "Kun lesetilgang"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr "Omfang"
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr "Brukernavn"
msgid "DeployTokens|Username (optional)"
msgstr "Brukernavn (valgfritt)"
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "Avbrutt"
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr "Mislyktes"
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr "Hoppet over"
msgid "Deployment|Success"
msgstr "Suksess"
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr "Design"
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} av %{designs_count}"
@@ -17565,9 +17780,6 @@ msgstr "E-post sendt"
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr "E-postoppdateringer (valgfritt)"
-
msgid "Email:"
msgstr "E-post:"
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "E-poster"
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr "Miljø"
msgid "Environment scope"
msgstr "Miljøomfang"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Jobb"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr "Lær mer om hvordan stoppe miljøer"
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr "Kommende"
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr "Utvid"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Utvid alle"
@@ -19337,6 +19570,9 @@ msgstr "https://example.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr "Filtrer etter user"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr "Filtrer resultater …"
msgid "Filter users"
msgstr "Filtrer brukere"
-msgid "Filter..."
-msgstr "Filter..."
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Kom i gang"
@@ -21440,6 +21649,9 @@ msgstr "Uverifisert"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr "Gitaly-tjenere"
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr "Gitaly-lagringsnavn:"
-
msgid "Gitaly timeouts"
msgstr "Gitaly-tidsavbrudd"
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr "Gitt tilgang %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr "Lukk"
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "Gruppe"
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr "Søk på GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr "Søk på GitLab %{kbdOpen}/%{kbdClose}"
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "GlobalSearch|Søk etter prosjekter, problemer, osv."
@@ -21749,6 +21964,9 @@ msgstr "Det oppsto en feil under henting av forslag til autofullføring av søk.
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "Skriv inn og trykk Enter-tasten for å sende inn et søk."
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr "Google Play"
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr "Gruppeavatar"
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "Gruppebeskrivelse (valgfritt)"
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr "Gruppenavigasjon"
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr "Gruppeoversikts-innhold"
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,8 +22972,8 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "En gruppe er en samling med flere prosjekter."
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
msgid "GroupsEmptyState|Create new project"
msgstr "Opprett et nytt prosjekt"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr "Jeg vil lagre koden min"
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr "Jeg lager en konto på GitLab fordi:"
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "SSH-nøkkelen din har utløpt. Vennligst generer en ny nøkkel."
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr "%{organization_name}-logo"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr "%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "Vær en DevOps-helt"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "Bedre kode på mindre tid"
-
msgid "InProductMarketing|Blog"
msgstr "Blogg"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr "Utforsk kraften til GitLab CI/CD"
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "Følg våre trinn"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "Gratis 30-dagers prøveperiode"
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr "Sett i gang i dag"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr "Grunnleggende om Git"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "Gi oss ett minutt …"
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr "GÃ¥ lengre med GitLab"
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "Inviter teamet ditt nå"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr "Ingen bankkort behøves."
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr "Begynn en prøveperiode"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr "Ta dine første skritt med GitLab"
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr "Prøv det ut"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "Prøv det ut selv"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr "Bruk GitLab-CI/CD"
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr "opprett et prosjekt"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "fra Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr "hurtigstartsguide"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "kodelager-speiling"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "sett opp et kodelager"
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr "InProductMarketing|avabonner"
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr "Integrert"
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr "Intervall"
-msgid "Interval Pattern"
-msgstr "Intervallmønster"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr "Ugyldig 2-trinnskode."
-msgid "Invalid yaml"
-msgstr "Ugyldig yaml"
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr "Lukket"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Lukket (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "Opprettet for %{created_at} av"
-
msgid "IssuableStatus|duplicated"
msgstr "duplisert"
@@ -26127,28 +26004,48 @@ msgstr "Saker uten noen tilordnede eposer"
msgid "Issues, merge requests, pushes, and comments."
msgstr "Saker, fletteforespørsler, pushinger og kommentarer."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr ""
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Gj.snitt/måned:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr "Saker åpnet"
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "Seneste 12 måneder"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Beklager, filteret ditt ga ingen resultater"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "Det er ingen saker for prosjektene i gruppen din"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr "Kursiv tekst"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr "Iterasjon"
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr "Varighet"
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr "Mislyktes"
@@ -27081,6 +26987,9 @@ msgstr "Prøv igjen"
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr "Kjører"
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr "Ble med %{time_ago}"
-
msgid "Joined %{user_created_time}"
msgstr "Ble med %{user_created_time}"
@@ -27442,9 +27348,6 @@ msgstr "Nyeste aktivitet"
msgid "Last Name"
msgstr "Etternavn"
-msgid "Last Pipeline"
-msgstr "Nyeste rørledning"
-
msgid "Last Seen"
msgstr "Sist sett"
@@ -27541,6 +27444,9 @@ msgstr "Du pushet til"
msgid "LastPushEvent|at"
msgstr "den"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "Siste endringer"
@@ -28242,6 +28148,9 @@ msgstr "LÃ¥s %{issuableType}"
msgid "Lock File?"
msgstr "Vil du låse filen?"
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr "LÃ¥s ikke funnet"
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr "Mattermost-URL:"
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr "Legg til i Mattermost"
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr "Forslag:"
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr "Innflettingscommit-melding"
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr "Flettedetaljer"
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr "Opprett metrikk"
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr "Analyser"
msgid "Navigation|Build"
msgstr "Bygg"
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr "Kode"
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
-msgstr ""
-
msgid "Navigation|Manage"
msgstr "Behandle"
+msgid "Navigation|Merge requests settings"
+msgstr ""
+
msgid "Navigation|Monitor"
msgstr "Skjerm"
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr "Plan"
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr "Prosjekt"
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr "Ny tidsplan"
-
msgid "New snippet"
msgstr "Nytt utdrag"
@@ -31254,6 +31292,9 @@ msgstr "Ingen iterasjon"
msgid "No label"
msgstr "Ingen etikett"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr "Ingen samsvarende resultater"
msgid "No matching results for \"%{query}\""
msgstr "Ingen samsvarende resultater for \"%{query}\""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr "Ingen medlemmer ble funnet"
@@ -31296,12 +31343,15 @@ msgstr "Ingen milepæl"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
-msgstr "Ingen andre stempler med sådan navn eller beskrivelse"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
msgstr ""
+msgid "No other labels with such name or description"
+msgstr "Ingen andre stempler med sådan navn eller beskrivelse"
+
msgid "No parent group"
msgstr "Ingen overgruppe"
@@ -31356,9 +31406,6 @@ msgstr "Ingen resultater funnet."
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "Ingen tidsplaner"
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr "Innstillinger"
msgid "Ordered list"
msgstr "Sortert liste"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr "Sider"
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr "Første"
@@ -33685,7 +33777,10 @@ msgstr "Sti"
msgid "Path:"
msgstr "Filbane:"
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "Aktivert"
-
msgid "PipelineSchedules|Active"
msgstr "Aktiv"
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Variabler"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr "Opprettet"
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr "Variabler"
@@ -35353,9 +35439,6 @@ msgstr "Utformingsbredde"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "Må være et nummer mellom %{min} og %{max}"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr "Forhåndvisning"
@@ -35467,6 +35550,9 @@ msgstr "Forrige uoppklarte diskusjon"
msgid "Primary Action"
msgstr "Hovedhandling"
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr "GÃ¥ tilbake"
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr "Rediger profil"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr "Prosjektoversikt"
-
msgid "Project path"
msgstr "Prosjektfilbane"
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr "Utgreininger"
@@ -37030,6 +37110,9 @@ msgstr "Offentlig"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr "Utgivelser"
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr "Brukere"
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} vil være skrivbar for utviklere. Er du sikker?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr "Velg brukere"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr "Offentlig"
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr "Nylig"
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr "Fjern prioritet"
-msgid "Remove report"
-msgstr "Fjern rapporten"
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr "Fjern sekundær E-post"
msgid "Remove spent time"
msgstr "Fjern brukt tid"
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr "Fjern tidsanslag"
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr "Fjern bruker"
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr "Fjern bruker fra gruppe"
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Rapportert %{timeAgo} av %{reportedBy}"
-msgid "Reported by"
-msgstr "Rapportert av"
-
-msgid "Reported by %{reporter}"
-msgstr "Rapportert av %{reporter}"
-
msgid "Reporter"
msgstr "Reporter"
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "Velg"
-
msgid "Request"
msgstr "Forespørsel"
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr "Dette regelnavnet er allerede brukt."
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr "Lagre passord"
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr "Lagrer"
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "Søk blant tilordnede"
@@ -41630,15 +41734,12 @@ msgstr "Søk i milepæler"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr "Søk eller filtrer resultater"
-
-msgid "Search or filter results..."
-msgstr "Søk eller filtrer resultater …"
-
msgid "Search or filter results…"
msgstr "Søk blant eller filtrer resultater …"
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr "Søkeside"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr "Sikkerhetskontrollpanel"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr "Skrudd på"
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr "Grupper"
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "Legg til eller fjern prosjekter som skal overvåkes i sikkerhetsområdet. Prosjekter som er inkludert i denne listen vil få sine resultater vist i sikkerhetskontrollpanelet og sårbarhetsrapporten."
@@ -42632,6 +42769,9 @@ msgstr "SecurityReports|Kommentar redigert på '%{vulnerabilityName}'"
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr "Identifisering"
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "Avfei sårbarhet"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "Avfeide '%{vulnerabilityName}'"
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr "Enten har du ikke tillatelse til å se dette kontrollpanelet, eller så har kontrollpanelet ikke blitt konfigurert. Kontroller tillatelsesinnstillingene dine med administratoren din, eller sjekk kontrollpanelkonfigurasjonene sine for å fortsette."
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr "Lagre kommentar"
-
msgid "SecurityReports|Scan details"
msgstr "Skanningsdetaljer"
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr "Send E-postvarsel"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr "Tjenestedesk"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr "Tjenestedesken lar folk opprette saksrapporter i din GitLab-forekomst uten å ha sin egen brukerkonto. Det sørger for en unik e-postadresse for sluttbrukere til å opprette saksrapporter i et prosjekt. Svar kan sendes enten via GitLab-grensesnittet eller via e-post. Sluttbrukere ser kun tråden via e-post."
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr "Økt-ID"
msgid "Session duration (minutes)"
msgstr "Øktvarighet (i minutter)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "Noe gikk galt"
@@ -44555,9 +44794,6 @@ msgstr "Noe gikk galt under innhenting av beskrivelsesendringer. Vennligst prøv
msgid "Something went wrong while fetching details"
msgstr "Noe gikk galt under innhenting av detaljer"
-msgid "Something went wrong while fetching latest comments."
-msgstr "Noe gikk galt under innhenting av de nyeste commitene."
-
msgid "Something went wrong while fetching projects"
msgstr "Noe gikk galt under innhenting av prosjekter"
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr "Legg til seter"
@@ -45653,6 +45901,9 @@ msgstr "Vellykket deaktivering"
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "Lyktes i å fjerne E-posten."
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr "Opphevde blokkeringen vellykket"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr "Opplåsingen var vellykket"
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr "MÃ¥l"
@@ -46344,7 +46601,13 @@ msgstr "MÃ¥lsti"
msgid "Target branch"
msgstr "MÃ¥lgren"
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr "Passordet til Jenkins-tjeneren."
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "Flettekonflikter er til stede"
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr "Det er ingen spam-logger"
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr "Det oppstod en feil under innhenting av variablene."
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr "Det oppstod en feil med reCAPTCHA-en. Vennligst løs reCAPTCHA-en på ny
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Denne fletteforespørselen er låst."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,8 +48784,8 @@ msgstr "Tidssone"
msgid "TimeTrackingEstimated|Est"
msgstr "Ansl."
-msgid "TimeTrackingReport|From"
-msgstr "Fra"
+msgid "TimeTrackingReport|From the start of"
+msgstr ""
msgid "TimeTrackingReport|Run report"
msgstr ""
@@ -48533,7 +48805,7 @@ msgstr "Sammendrag"
msgid "TimeTrackingReport|Time spent"
msgstr "Tid brukt"
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr "For å aktivere kontoen din på nytt, logg på GitLab på %{gitlab_url}.
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "I morgen"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr "Totalt"
msgid "Total Score"
msgstr "Totalscore"
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr "Totalt antall kjerner (CPU-er)"
@@ -49348,9 +49626,15 @@ msgstr "1000+"
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr "Sporing"
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr "URL eller forespørsels-ID"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr "Kan ikke oppdatere dette eposet på dette tidspunktet."
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr "Misfornøyd?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr "d"
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr "Container-register"
msgid "UsageQuota|Dependency proxy"
msgstr "Avhengighetsmellomtjener"
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr "Brukernavnet er tilgjengelig."
msgid "Username or email"
msgstr "Brukernavn eller E-postadresse"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Brukernavn:"
@@ -51888,6 +52193,9 @@ msgstr "Detaljer"
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr "Gruppenavn"
@@ -51915,16 +52223,19 @@ msgstr "Verktøy"
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr "Fil:"
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr "ADVARSEL:"
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr "SSL-verifisering"
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr "Velkommen, %{name}!"
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr "%{count} flere tilordnede"
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr "Forfallsdato"
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr "Helsestatus"
-
msgid "WorkItem|History only"
msgstr "Kun historikk"
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr "Milepæl"
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr "Arbeidsområder"
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr "Arbeidsområder"
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr "Du har ingen åpne fletteforespørsler"
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "Dine autoriserte applikasjoner"
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr "Din profil"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "Prosjektgrensen din er %{limit} prosjekter! Kontakt administratoren din for å øke den"
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr "Søket ditt samsvarte ikke med noen commiter."
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr "tillatt å mislykkes"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr "kan ikke endres til %{new_type}"
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr "laget av"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr "f.eks. %{token}"
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] "filer"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr "den er for stor"
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr "må spesifiseres"
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr "min-kule-gruppe"
@@ -56429,6 +56761,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, og %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "startet en diskusjon på %{design_link}"
@@ -56772,6 +57110,9 @@ msgstr "etikettnavn"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr "utløst"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "versjon %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "via %{closed_via}"
diff --git a/locale/ne_NP/gitlab.po b/locale/ne_NP/gitlab.po
new file mode 100644
index 00000000000..377acb6b396
--- /dev/null
+++ b/locale/ne_NP/gitlab.po
@@ -0,0 +1,57314 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: gitlab-ee\n"
+"Report-Msgid-Bugs-To: \n"
+"Last-Translator: \n"
+"Language-Team: Nepali\n"
+"Language: ne_NP\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Crowdin-Project: gitlab-ee\n"
+"X-Crowdin-Project-ID: 288872\n"
+"X-Crowdin-Language: ne-NP\n"
+"X-Crowdin-File: /master/locale/gitlab.pot\n"
+"X-Crowdin-File-ID: 16\n"
+"PO-Revision-Date: 2023-09-12 12:37\n"
+
+msgid " %{start} to %{end}"
+msgstr ""
+
+msgid " (from %{timeoutSource})"
+msgstr ""
+
+msgid " (squashes %{strongStart}%{count}%{strongEnd} commit)"
+msgid_plural " (squashes %{strongStart}%{count}%{strongEnd} commits)"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid " Collected %{time}"
+msgstr ""
+
+msgid " Please sign in."
+msgstr ""
+
+msgid " Try to %{action} this file again."
+msgstr ""
+
+msgid " You need to do this before %{grace_period_deadline}."
+msgstr ""
+
+msgid " and "
+msgstr ""
+
+msgid " and %{sliced}"
+msgstr ""
+
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid " or "
+msgstr ""
+
+msgid " or %{emphasisStart}!merge request id%{emphasisEnd}"
+msgstr ""
+
+msgid " or %{emphasisStart}#id%{emphasisEnd}"
+msgstr ""
+
+msgid " or %{emphasisStart}#issue id%{emphasisEnd}"
+msgstr ""
+
+msgid " or %{emphasisStart}&epic id%{emphasisEnd}"
+msgstr ""
+
+msgid " or references"
+msgstr ""
+
+msgid " reacted with :%{name}:"
+msgstr ""
+
+msgid "\"%{path}\" did not exist on \"%{ref}\""
+msgstr ""
+
+msgid "\"%{repository_name}\" size (%{repository_size}) is larger than the limit of %{limit}."
+msgstr ""
+
+msgid "### Rich text editor"
+msgstr ""
+
+msgid "##### ERROR ##### You have used %{usage_percentage} of the storage quota for %{namespace_name} (%{current_size} of %{size_limit}). %{namespace_name} is now read-only. Projects under this namespace are locked and actions will be restricted. To manage storage, or purchase additional storage, see %{manage_storage_url}. To learn more about restricted actions, see %{restricted_actions_url}"
+msgstr ""
+
+msgid "##### WARNING ##### You have used %{usage_percentage} of the storage quota for %{namespace_name} (%{current_size} of %{size_limit}). If %{namespace_name} exceeds the storage quota, all projects in the namespace will be locked and actions will be restricted. To manage storage, or purchase additional storage, see %{manage_storage_url}. To learn more about restricted actions, see %{restricted_actions_url}"
+msgstr ""
+
+msgid "#%{issueIid} (closed)"
+msgstr ""
+
+msgid "#general, #development"
+msgstr ""
+
+msgid "%d Alert"
+msgid_plural "%d Alerts"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Module"
+msgid_plural "%d Modules"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Scanned URL"
+msgid_plural "%d Scanned URLs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d URL scanned"
+msgid_plural "%d URLs scanned"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d additional approver"
+msgid_plural "%d additional approvers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d additional assignee"
+msgid_plural "%d additional assignees"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d additional commenter"
+msgid_plural "%d additional commenters"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d additional committer"
+msgid_plural "%d additional committers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d additional user"
+msgid_plural "%d additional users"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d approver"
+msgid_plural "%d approvers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d approver (you've approved)"
+msgid_plural "%d approvers (you've approved)"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d artifact"
+msgid_plural "%d artifacts"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d assigned issue"
+msgid_plural "%d assigned issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d author"
+msgid_plural "%d authors"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d changed file"
+msgid_plural "%d changed files"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d character remaining"
+msgid_plural "%d characters remaining"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d child epic"
+msgid_plural "%d child epics"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d code quality issue"
+msgid_plural "%d code quality issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d comment on this commit"
+msgid_plural "%d comments on this commit"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d commenter"
+msgid_plural "%d commenters"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d commit"
+msgid_plural "%d commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d commit author"
+msgid_plural "%d commit authors"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d commit behind"
+msgid_plural "%d commits behind"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d commit,"
+msgid_plural "%d commits,"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d contribution"
+msgid_plural "%d contributions"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d contributor"
+msgid_plural "%d contributors"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d day"
+msgid_plural "%d days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d epic"
+msgid_plural "%d epics"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d exporter"
+msgid_plural "%d exporters"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d failed security job"
+msgid_plural "%d failed security jobs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d file"
+msgid_plural "%d files"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d fork"
+msgid_plural "%d forks"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d group"
+msgid_plural "%d groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d group found"
+msgid_plural "%d groups found"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d hour"
+msgid_plural "%d hours"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d inaccessible merge request"
+msgid_plural "%d inaccessible merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d issue"
+msgid_plural "%d issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d issue in this group"
+msgid_plural "%d issues in this group"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d issue successfully imported with the label"
+msgid_plural "%d issues successfully imported with the label"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d job"
+msgid_plural "%d jobs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d layer"
+msgid_plural "%d layers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d merge request"
+msgid_plural "%d merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d merge request that you don't have access to."
+msgid_plural "%d merge requests that you don't have access to."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d merge requests"
+msgid_plural "%d merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d metric"
+msgid_plural "%d metrics"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d milestone"
+msgid_plural "%d milestones"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d minute"
+msgid_plural "%d minutes"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d month"
+msgid_plural "%d months"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d more comment"
+msgid_plural "%d more comments"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d package"
+msgid_plural "%d packages"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d personal project will be removed and cannot be restored."
+msgid_plural "%d personal projects will be removed and cannot be restored."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d previously merged commit"
+msgid_plural "%d previously merged commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d project"
+msgid_plural "%d projects"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d push"
+msgid_plural "%d pushes"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d remaining"
+msgid_plural "%d remaining"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d reply"
+msgid_plural "%d replies"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d second"
+msgid_plural "%d seconds"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d snippet"
+msgid_plural "%d snippets"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d stage"
+msgid_plural "%d stages"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d star"
+msgid_plural "%d stars"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d tag"
+msgid_plural "%d tags"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d unresolved thread"
+msgid_plural "%d unresolved threads"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d version"
+msgid_plural "%d versions"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d vulnerability"
+msgid_plural "%d vulnerabilities"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d vulnerability dismissed"
+msgid_plural "%d vulnerabilities dismissed"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d vulnerability set to confirmed"
+msgid_plural "%d vulnerabilities set to confirmed"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d vulnerability set to dismissed"
+msgid_plural "%d vulnerabilities set to dismissed"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d vulnerability set to needs triage"
+msgid_plural "%d vulnerabilities set to needs triage"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d vulnerability set to resolved"
+msgid_plural "%d vulnerabilities set to resolved"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d week"
+msgid_plural "%d weeks"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d work item"
+msgid_plural "%d work items"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d year"
+msgid_plural "%d years"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%s additional commit has been omitted to prevent performance issues."
+msgid_plural "%s additional commits have been omitted to prevent performance issues."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{actionText} %{actionDetail}"
+msgstr ""
+
+msgid "%{actionText} %{actionDetail} %{timeago} by %{author}"
+msgstr ""
+
+msgid "%{actionText} & %{openOrClose} %{noteable}"
+msgstr ""
+
+msgid "%{actionText} & close %{noteable}"
+msgstr ""
+
+msgid "%{actionText} & reopen %{noteable}"
+msgstr ""
+
+msgid "%{address} is an invalid IP address range"
+msgstr ""
+
+msgid "%{author_link} cloned %{original_issue} to %{new_issue}."
+msgstr ""
+
+msgid "%{author_link} cloned %{original_issue}. You don't have access to the new project."
+msgstr ""
+
+msgid "%{author_link} wrote:"
+msgstr ""
+
+msgid "%{authorsName}'s thread"
+msgstr ""
+
+msgid "%{author} requested to merge %{source_branch} %{copy_button} into %{target_branch} %{created_at}"
+msgstr ""
+
+msgid "%{board_target} not found"
+msgstr ""
+
+msgid "%{bold_start}%{count}%{bold_end} issue"
+msgid_plural "%{bold_start}%{count}%{bold_end} issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{bold_start}%{count}%{bold_end} member"
+msgid_plural "%{bold_start}%{count}%{bold_end} members"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{bold_start}%{count}%{bold_end} opened merge request"
+msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{chartTitle} no data series"
+msgstr ""
+
+msgid "%{codeStart}$%{codeEnd} will be treated as the start of a reference to another variable."
+msgstr ""
+
+msgid "%{code_open}Expanded:%{code_close} Variables with %{code_open}$%{code_close} will be treated as the start of a reference to another variable."
+msgstr ""
+
+msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
+msgstr ""
+
+msgid "%{code_open}Protected:%{code_close} Only exposed to protected branches or protected tags."
+msgstr ""
+
+msgid "%{commit_author_link} authored %{commit_authored_timeago}"
+msgstr ""
+
+msgid "%{commit_author_link} authored %{commit_authored_timeago} and %{commit_committer_avatar} %{commit_committer_link} committed %{commit_committer_timeago}"
+msgstr ""
+
+msgid "%{completedCount} completed weight"
+msgstr ""
+
+msgid "%{completedCount} of %{count} checklist item completed"
+msgid_plural "%{completedCount} of %{count} checklist items completed"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{completedWeight} of %{totalWeight} weight completed"
+msgstr ""
+
+msgid "%{completed} of %{total} issues closed"
+msgstr ""
+
+msgid "%{completed} of %{total} weight completed"
+msgstr ""
+
+msgid "%{cores} cores"
+msgstr ""
+
+msgid "%{count} %{scope} for term '%{term}'"
+msgstr ""
+
+msgid "%{count} LOC/commit"
+msgstr ""
+
+msgid "%{count} Participant"
+msgid_plural "%{count} Participants"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} approval required from %{name}"
+msgid_plural "%{count} approvals required from %{name}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} approvals from %{name}"
+msgstr ""
+
+msgid "%{count} contact"
+msgid_plural "%{count} contacts"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} files touched"
+msgstr ""
+
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} item"
+msgid_plural "%{count} items"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} items per page"
+msgstr ""
+
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} more"
+msgstr ""
+
+msgid "%{count} more assignees"
+msgstr ""
+
+msgid "%{count} more release"
+msgid_plural "%{count} more releases"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} of %{required} approvals from %{name}"
+msgstr ""
+
+msgid "%{count} of %{total}"
+msgstr ""
+
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} selected"
+msgstr ""
+
+msgid "%{count} tags"
+msgstr ""
+
+msgid "%{count} total weight"
+msgstr ""
+
+msgid "%{days} days until tags are automatically removed"
+msgstr ""
+
+msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last seen: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
+msgstr ""
+
+msgid "%{doc_link_start}Advanced search%{doc_link_end} is disabled since %{ref_elem} is not the default branch. %{docs_link}"
+msgstr ""
+
+msgid "%{doc_link_start}Advanced search%{doc_link_end} is enabled."
+msgstr ""
+
+msgid "%{docs_link_start}Learn about visibility levels.%{docs_link_end}"
+msgstr ""
+
+msgid "%{docs_link_start}Setting up a verified domain%{docs_link_end} requires being linked to a project."
+msgstr ""
+
+msgid "%{docs_link_start}What is Large File Storage?%{docs_link_end}"
+msgstr ""
+
+msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
+msgstr ""
+
+msgid "%{duration}, queued for %{queuedDuration} seconds"
+msgstr ""
+
+msgid "%{duration}ms"
+msgstr ""
+
+msgid "%{edit_in_new_fork_notice} Try to cherry-pick this commit again."
+msgstr ""
+
+msgid "%{edit_in_new_fork_notice} Try to create a new directory again."
+msgstr ""
+
+msgid "%{edit_in_new_fork_notice} Try to revert this commit again."
+msgstr ""
+
+msgid "%{edit_in_new_fork_notice} Try to upload a file again."
+msgstr ""
+
+msgid "%{emailPrefix}@company.com"
+msgstr ""
+
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr ""
+
+msgid "%{extra} more downstream pipelines"
+msgstr ""
+
+msgid "%{filePath} deleted"
+msgstr ""
+
+msgid "%{firstLabel} +%{labelCount} more"
+msgstr ""
+
+msgid "%{firstMilestoneName} + %{numberOfOtherMilestones} more"
+msgstr ""
+
+msgid "%{fork_icon} %{source_project_path}:%{source_branch}"
+msgstr ""
+
+msgid "%{gitlab_experience_text}. Don't worry, this information isn't shared outside of your self-managed GitLab instance."
+msgstr ""
+
+msgid "%{gitlab_experience_text}. We won't share this information with anyone."
+msgstr ""
+
+msgid "%{global_id} is not a valid ID for %{expected_types}."
+msgstr ""
+
+msgid "%{group_name} activity"
+msgstr ""
+
+msgid "%{group_name} group members"
+msgstr ""
+
+msgid "%{group_name} is approaching the limit of available seats"
+msgstr ""
+
+msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
+msgstr ""
+
+msgid "%{group_name}&%{epic_iid} &middot; created %{epic_created} by %{author}"
+msgstr ""
+
+msgid "%{host} sign-in from new location"
+msgstr ""
+
+msgid "%{human_readable_key} exceeds %{max_value_length} characters"
+msgstr ""
+
+msgid "%{human_readable_key} is less than %{min_value_length} characters"
+msgstr ""
+
+msgid "%{integrations_link_start}Integrations%{link_end} enable you to make third-party applications part of your GitLab workflow. If the available integrations don't meet your needs, consider using a %{webhooks_link_start}webhook%{link_end}."
+msgstr ""
+
+msgid "%{issuableDisplayName} locked."
+msgstr ""
+
+msgid "%{issuableDisplayName} unlocked."
+msgstr ""
+
+msgid "%{issuableType} will be removed! Are you sure?"
+msgstr ""
+
+msgid "%{issuable_class_name} doesn't exist or you don't have permission to add timelog to it."
+msgstr ""
+
+msgid "%{issuable}(s) already assigned"
+msgstr ""
+
+msgid "%{issueType} actions"
+msgstr ""
+
+msgid "%{issuesSize} with a limit of %{maxIssueCount}"
+msgstr ""
+
+msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
+msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
+
+msgid "%{jobName} job is being retried"
+msgstr ""
+
+msgid "%{jobs} Jobs"
+msgstr ""
+
+msgid "%{key} is not a valid URL."
+msgstr ""
+
+msgid "%{key} is not a valid action."
+msgstr ""
+
+msgid "%{labelStart}Actual response:%{labelEnd} %{headers}"
+msgstr ""
+
+msgid "%{labelStart}Assert:%{labelEnd} %{assertion}"
+msgstr ""
+
+msgid "%{labelStart}Class:%{labelEnd} %{class}"
+msgstr ""
+
+msgid "%{labelStart}Crash Address:%{labelEnd} %{crash_address}"
+msgstr ""
+
+msgid "%{labelStart}Crash State:%{labelEnd} %{crash_state}"
+msgstr ""
+
+msgid "%{labelStart}Crash State:%{labelEnd} %{stacktrace_snippet}"
+msgstr ""
+
+msgid "%{labelStart}Crash Type:%{labelEnd} %{crash_type}"
+msgstr ""
+
+msgid "%{labelStart}Evidence:%{labelEnd} %{evidence}"
+msgstr ""
+
+msgid "%{labelStart}File:%{labelEnd} %{file}"
+msgstr ""
+
+msgid "%{labelStart}Image:%{labelEnd} %{image}"
+msgstr ""
+
+msgid "%{labelStart}Method:%{labelEnd} %{method}"
+msgstr ""
+
+msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
+msgstr ""
+
+msgid "%{labelStart}Project:%{labelEnd} %{project}"
+msgstr ""
+
+msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
+msgstr ""
+
+msgid "%{labelStart}Sent request:%{labelEnd} %{headers}"
+msgstr ""
+
+msgid "%{labelStart}Severity:%{labelEnd} %{severity}"
+msgstr ""
+
+msgid "%{labelStart}Tool:%{labelEnd} %{reportType}"
+msgstr ""
+
+msgid "%{labelStart}URL:%{labelEnd} %{url}"
+msgstr ""
+
+msgid "%{labelStart}Unmodified response:%{labelEnd} %{headers}"
+msgstr ""
+
+msgid "%{label_for_message} unavailable"
+msgstr ""
+
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
+msgid "%{label_name} was removed"
+msgstr ""
+
+msgid "%{lessThan} 1 hour"
+msgstr ""
+
+msgid "%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA) that issues digital certificates to enable HTTPS (SSL/TLS) for sites."
+msgstr ""
+
+msgid "%{level_name} is not allowed in a %{group_level_name} group."
+msgstr ""
+
+msgid "%{level_name} is not allowed since the fork source project has lower visibility."
+msgstr ""
+
+msgid "%{linkStart} Learn more%{linkEnd}."
+msgstr ""
+
+msgid "%{linkStart}%{linkEnd} review summary"
+msgstr ""
+
+msgid "%{listToShow}, and %{awardsListLength} more"
+msgstr ""
+
+msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
+msgstr ""
+
+msgid "%{locked} created %{timeago}"
+msgstr ""
+
+msgid "%{mergeLength}/%{usersLength} can merge"
+msgstr ""
+
+msgid "%{message} showing first %{warnings_displayed}"
+msgstr ""
+
+msgid "%{milestone} (expired)"
+msgstr ""
+
+msgid "%{milliseconds}ms"
+msgstr ""
+
+msgid "%{minutesUsed} units"
+msgstr ""
+
+msgid "%{model_name} not found"
+msgstr ""
+
+msgid "%{mrText}, this issue will be closed automatically."
+msgstr ""
+
+msgid "%{name_with_link} namespace has %{percent} or less Shared Runner Pipeline minutes remaining. Once it runs out, no new jobs or pipelines in its projects will run."
+msgstr ""
+
+msgid "%{name_with_link} namespace has run out of Shared Runner Pipeline minutes. No new jobs or pipelines in its projects will run."
+msgstr ""
+
+msgid "%{name} (Busy)"
+msgstr ""
+
+msgid "%{name} is already being used for another emoji"
+msgstr ""
+
+msgid "%{name} is reserved for %{type} report type"
+msgstr ""
+
+msgid "%{name} is scheduled for %{action}"
+msgstr ""
+
+msgid "%{name}'s avatar"
+msgstr ""
+
+msgid "%{name}(%{url}) namespace has %{percent} or less Shared Runner Pipeline minutes remaining. After it runs out, no new jobs or pipelines in its projects will run."
+msgstr ""
+
+msgid "%{name}(%{url}) namespace has run out of Shared Runner Pipeline minutes so no new jobs or pipelines in its projects will run."
+msgstr ""
+
+msgid "%{name}, confirm your email address now!"
+msgstr ""
+
+msgid "%{name}: %{resultsString}"
+msgstr ""
+
+msgid "%{no_of_days} day"
+msgid_plural "%{no_of_days} days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{numberOfSelectedTags} tags"
+msgstr ""
+
+msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
+msgstr ""
+
+msgid "%{oneMonthAgo} - %{today}"
+msgstr ""
+
+msgid "%{oneWeekAgo} - %{today}"
+msgstr ""
+
+msgid "%{oneYearAgo} - %{today}"
+msgstr ""
+
+msgid "%{openedEpics} open, %{closedEpics} closed"
+msgstr ""
+
+msgid "%{openedIssues} open, %{closedIssues} closed"
+msgstr ""
+
+msgid "%{over_limit_message} To get more seats, %{link_start}upgrade to a paid tier%{link_end}."
+msgstr ""
+
+msgid "%{percentageUsed}%% used"
+msgstr ""
+
+msgid "%{percentage}%% issues closed"
+msgstr ""
+
+msgid "%{percentage}%% weight completed"
+msgstr ""
+
+msgid "%{percent}%% complete"
+msgstr ""
+
+msgid "%{percent}%{percentSymbol} complete"
+msgstr ""
+
+msgid "%{placeholder} is not a valid color scheme"
+msgstr ""
+
+msgid "%{placeholder} is not a valid theme"
+msgstr ""
+
+msgid "%{policy_link} (notifying after %{elapsed_time} minutes unless %{status})"
+msgstr ""
+
+msgid "%{project_name}"
+msgstr ""
+
+msgid "%{project_path} is a project that you can use to add a README to your GitLab profile. Create a public project and initialize the repository with a README to get started. %{help_link_start}Learn more%{help_link_end}."
+msgstr ""
+
+msgid "%{ref} cannot be added: %{error}"
+msgstr ""
+
+msgid "%{relation_type} epic does not exist."
+msgstr ""
+
+msgid "%{relation_type} epic is not present."
+msgstr ""
+
+msgid "%{releases} release"
+msgid_plural "%{releases} releases"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{remaining_approvals} left"
+msgstr ""
+
+msgid "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approval%{approvalEnd} from:"
+msgid_plural "%{requireStart}Require%{requireEnd} %{approvalsRequired} %{approvalStart}approvals%{approvalEnd} from:"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}attach a new file%{newFileButtonEnd}."
+msgstr ""
+
+msgid "%{reviewer_names} was added as a reviewer."
+msgid_plural "%{reviewer_names} were added as reviewers."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{reviewer_names} was removed from reviewers."
+msgid_plural "%{reviewer_names} were removed from reviewers."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{rotation} has been recalculated with the remaining participants. Please review the new setup for %{rotation_link}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage."
+msgstr ""
+
+msgid "%{rotation} has been recalculated with the remaining participants. Please review the new setup for %{rotation}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage."
+msgstr ""
+
+msgid "%{scope} results for term '%{term}'"
+msgstr ""
+
+msgid "%{seconds}s"
+msgstr ""
+
+msgid "%{securityScanner} is not enabled for this project. %{linkStart}More information%{linkEnd}"
+msgid_plural "%{securityScanner} are not enabled for this project. %{linkStart}More information%{linkEnd}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{securityScanner} result is not available because a pipeline has not been run since it was enabled. %{linkStart}Run a pipeline%{linkEnd}"
+msgid_plural "%{securityScanner} results are not available because a pipeline has not been run since it was enabled. %{linkStart}Run a pipeline%{linkEnd}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{selectedLabelsCount} label"
+msgid_plural "%{selectedLabelsCount} labels"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{selectedProjectsCount} project"
+msgid_plural "%{selectedProjectsCount} projects"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{size} B"
+msgstr ""
+
+msgid "%{size} GiB"
+msgstr ""
+
+msgid "%{size} KiB"
+msgstr ""
+
+msgid "%{size} MiB"
+msgstr ""
+
+msgid "%{sourceBranch} into %{targetBranch}"
+msgstr ""
+
+msgid "%{source_project_path}:%{source_branch}"
+msgstr ""
+
+msgid "%{source} %{copyButton} into %{target}"
+msgstr ""
+
+msgid "%{spammable_titlecase} was submitted to Akismet successfully."
+msgstr ""
+
+msgid "%{spanStart}at line%{spanEnd} %{errorLine}%{errorColumn}"
+msgstr ""
+
+msgid "%{spanStart}in%{spanEnd} %{errorFn}"
+msgstr ""
+
+msgid "%{startDate} – %{dueDate}"
+msgstr ""
+
+msgid "%{startDate} – No due date"
+msgstr ""
+
+msgid "%{start} to %{end}"
+msgstr ""
+
+msgid "%{statusStart}Dismissed%{statusEnd}"
+msgstr ""
+
+msgid "%{statusStart}Dismissed%{statusEnd} at %{projectLink}"
+msgstr ""
+
+msgid "%{statusStart}Dismissed%{statusEnd} on pipeline %{pipelineLink}"
+msgstr ""
+
+msgid "%{statusStart}Dismissed%{statusEnd} on pipeline %{pipelineLink} at %{projectLink}"
+msgstr ""
+
+msgid "%{statusStart}Dismissed%{statusEnd}: %{dismissalReason}"
+msgstr ""
+
+msgid "%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} at %{projectLink}"
+msgstr ""
+
+msgid "%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} on pipeline %{pipelineLink}"
+msgstr ""
+
+msgid "%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} on pipeline %{pipelineLink} at %{projectLink}"
+msgstr ""
+
+msgid "%{strongOpen}Warning:%{strongClose} SAML group links can cause GitLab to automatically change member roles or remove members from groups."
+msgstr ""
+
+msgid "%{strongStart}%{count}%{strongEnd} commit"
+msgid_plural "%{strongStart}%{count}%{strongEnd} commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strongStart}Tip:%{strongEnd} You can also %{linkStart}check out with merge request ID%{linkEnd}."
+msgstr ""
+
+msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
+msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{commit_count}%{strong_end} Commit"
+msgid_plural "%{strong_start}%{commit_count}%{strong_end} Commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{count} approval rule%{strong_end} requires eligible members to approve before merging."
+msgid_plural "%{strong_start}%{count} approval rules%{strong_end} require eligible members to approve before merging."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{count} eligible member%{strong_end} must approve to merge."
+msgid_plural "%{strong_start}%{count} eligible members%{strong_end} must approve to merge."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{count} member%{strong_end} must approve to merge. Anyone with role Developer or higher can approve."
+msgid_plural "%{strong_start}%{count} members%{strong_end} must approve to merge. Anyone with role Developer or higher can approve."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{count}%{strong_end} Environment"
+msgid_plural "%{strong_start}%{count}%{strong_end} Environments"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{errors}%{strong_end} %{prefix} finding"
+msgid_plural "%{strong_start}%{errors}%{strong_end} %{prefix} findings"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{human_size}%{strong_end} Project Storage"
+msgstr ""
+
+msgid "%{strong_start}%{release_count}%{strong_end} Release"
+msgid_plural "%{strong_start}%{release_count}%{strong_end} Releases"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{tag_count}%{strong_end} Tag"
+msgid_plural "%{strong_start}%{tag_count}%{strong_end} Tags"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{strong_start}%{terraform_states_count}%{strong_end} Terraform State"
+msgid_plural "%{strong_start}%{terraform_states_count}%{strong_end} Terraform States"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{tabname} changed"
+msgstr ""
+
+msgid "%{tags} tag per image name"
+msgstr ""
+
+msgid "%{tags} tags per image name"
+msgstr ""
+
+msgid "%{tag}-%{evidence}-%{filename}"
+msgstr ""
+
+msgid "%{templateType} template applied"
+msgstr ""
+
+msgid "%{template_project_id} is unknown or invalid"
+msgstr ""
+
+msgid "%{text} is available"
+msgstr ""
+
+msgid "%{time_ago}"
+msgstr ""
+
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
+msgid "%{time} UTC"
+msgstr ""
+
+msgid "%{title} changes"
+msgstr ""
+
+msgid "%{totalCpu} (%{freeSpacePercentage}%{percentSymbol} free)"
+msgstr ""
+
+msgid "%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)"
+msgstr ""
+
+msgid "%{totalWeight} total weight"
+msgstr ""
+
+msgid "%{total_warnings} warning(s) found:"
+msgstr ""
+
+msgid "%{total} remaining issue weight"
+msgstr ""
+
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
+
+msgid "%{type} must be a %{help_link}"
+msgstr ""
+
+msgid "%{type} only supports %{name} name"
+msgstr ""
+
+msgid "%{url} (optional)"
+msgstr ""
+
+msgid "%{userName}'s avatar"
+msgstr ""
+
+msgid "%{user_name} (%{user_username}) was removed from %{rotation} in %{schedule} in %{project}. "
+msgstr ""
+
+msgid "%{user_name} (%{user_username}) was removed from the following escalation policies in %{project_link}: "
+msgstr ""
+
+msgid "%{user_name} (%{user_username}) was removed from the following escalation policies in %{project}:"
+msgstr ""
+
+msgid "%{user_name} profile page"
+msgstr ""
+
+msgid "%{username} has asked for a GitLab account on your instance %{host}:"
+msgstr ""
+
+msgid "%{username} marked merge request %{mr_link} as draft"
+msgstr ""
+
+msgid "%{username} marked merge request %{mr_link} as ready"
+msgstr ""
+
+msgid "%{username}'s avatar"
+msgstr ""
+
+msgid "%{user} created a merge request: %{mr_link}"
+msgstr ""
+
+msgid "%{user} created an epic: %{epic_link}"
+msgstr ""
+
+msgid "%{user} created an issue: %{issue_link}"
+msgstr ""
+
+msgid "%{user} user’s menu"
+msgstr ""
+
+msgid "%{value} is not included in the list"
+msgstr ""
+
+msgid "%{verb} %{time_spent_value} spent time."
+msgstr ""
+
+msgid "%{verb} this %{noun} as a draft."
+msgstr ""
+
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr ""
+
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
+
+msgid "%{widget} options"
+msgstr ""
+
+msgid "%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}v*%{code_tag_end} or %{code_tag_start}*-release%{code_tag_end} are supported."
+msgstr ""
+
+msgid "'%{level}' is not a valid visibility level"
+msgstr ""
+
+msgid "'%{source}' is not a import source"
+msgstr ""
+
+msgid "'%{template_name}' is unknown or invalid"
+msgstr ""
+
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
+msgid "'projects' is not yet supported"
+msgstr ""
+
+msgid "'schemaVersion' '%{given_version}' is not supported, it must be '%{required_version}'"
+msgstr ""
+
+msgid "'starterProjects' is not yet supported"
+msgstr ""
+
+msgid "(%d closed)"
+msgid_plural "(%d closed)"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "(%{mrCount} merged)"
+msgstr ""
+
+msgid "(%{value}) has already been taken"
+msgstr ""
+
+msgid "(+%{count}&nbsp;rules)"
+msgstr ""
+
+msgid "(Group Managed Account)"
+msgstr ""
+
+msgid "(Limited to %{quota} pipeline minutes per month)"
+msgstr ""
+
+msgid "(No changes)"
+msgstr ""
+
+msgid "(Unlimited pipeline minutes)"
+msgstr ""
+
+msgid "(check progress)"
+msgstr ""
+
+msgid "(deleted)"
+msgstr ""
+
+msgid "(expired)"
+msgstr ""
+
+msgid "(external link)"
+msgstr ""
+
+msgid "(external participant)"
+msgstr ""
+
+msgid "(leave blank if you don't want to change it)"
+msgstr ""
+
+msgid "(max size 15 MB)"
+msgstr ""
+
+msgid "(no user)"
+msgstr ""
+
+msgid "(optional)"
+msgstr ""
+
+msgid "(removed)"
+msgstr ""
+
+msgid "(required)"
+msgstr ""
+
+msgid "(revoked)"
+msgstr ""
+
+msgid "(this user)"
+msgstr ""
+
+msgid "(we need your current password to confirm your changes)"
+msgstr ""
+
+msgid "* All times are in UTC unless specified"
+msgstr ""
+
+msgid "+ %{amount} more"
+msgstr ""
+
+msgid "+ %{count} more"
+msgstr ""
+
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
+msgid "+ %{moreCount} more"
+msgstr ""
+
+msgid "+ %{numberOfHiddenAssignees} more"
+msgstr ""
+
+msgid "+%d more"
+msgid_plural "+%d more"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "+%{more_assignees_count}"
+msgstr ""
+
+msgid "+%{more_assignees_count} more assignees"
+msgstr ""
+
+msgid "+%{more_reviewers_count}"
+msgstr ""
+
+msgid "+%{more_reviewers_count} more reviewers"
+msgstr ""
+
+msgid "+%{tags} more"
+msgstr ""
+
+msgid ", "
+msgstr ""
+
+msgid ", or "
+msgstr ""
+
+msgid "- %{policy_name} (notifying after %{elapsed_time} minutes unless %{status})"
+msgstr ""
+
+msgid "- Add or remove a user."
+msgstr ""
+
+msgid "- Available to run jobs."
+msgstr ""
+
+msgid "- Create or close an issue."
+msgstr ""
+
+msgid "- Create, update, or delete a merge request."
+msgstr ""
+
+msgid "- Event"
+msgid_plural "- Events"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "- Go to the Activity page for %{project_name}."
+msgstr ""
+
+msgid "- List the visible events for %{project_name} using the Events API %{events_api_link}."
+msgstr ""
+
+msgid "- Not available to run jobs."
+msgstr ""
+
+msgid "- Push code to the repository."
+msgstr ""
+
+msgid "- Select -"
+msgstr ""
+
+msgid "- User"
+msgid_plural "- Users"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "- View the last_activity_at attribute for %{project_name} using the Project API %{projects_api_link}."
+msgstr ""
+
+msgid "- of - issues closed"
+msgstr ""
+
+msgid "- of - weight completed"
+msgstr ""
+
+msgid "- show less"
+msgstr ""
+
+msgid "."
+msgstr ""
+
+msgid ".gitlab-ci.yml with aliases/anchors is not supported. Please change the CI configuration manually."
+msgstr ""
+
+msgid "/"
+msgstr ""
+
+msgid "/day"
+msgstr ""
+
+msgid "0 B"
+msgstr ""
+
+msgid "1 Code Quality finding"
+msgid_plural "%d Code Quality findings"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 Day"
+msgid_plural "%d Days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 closed issue"
+msgid_plural "%{issues} closed issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 closed merge request"
+msgid_plural "%{merge_requests} closed merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 day"
+msgid_plural "%d days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 day remaining"
+msgid_plural "%d days remaining"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 day selected"
+msgid_plural "%d days selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 group"
+msgid_plural "%d groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 hour"
+msgid_plural "%d hours"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 issue selected"
+msgid_plural "%d issues selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 merge request selected"
+msgid_plural "%d merge requests selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 merged merge request"
+msgid_plural "%{merge_requests} merged merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 minute"
+msgid_plural "%d minutes"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 month remaining"
+msgid_plural "%d months remaining"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 open issue"
+msgid_plural "%{issues} open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 open merge request"
+msgid_plural "%{merge_requests} open merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 pipeline"
+msgid_plural "%d pipelines"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 role"
+msgid_plural "%d roles"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 user"
+msgid_plural "%d users"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 week remaining"
+msgid_plural "%d weeks remaining"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1 year remaining"
+msgid_plural "%d years remaining"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "1-9 contributions"
+msgstr ""
+
+msgid "10-19 contributions"
+msgstr ""
+
+msgid "1000+"
+msgstr ""
+
+msgid "192.168.0.0/24 or 2001:0DB8:1234::/48"
+msgstr ""
+
+msgid "1st contribution!"
+msgstr ""
+
+msgid "20-29 contributions"
+msgstr ""
+
+msgid "2FA"
+msgstr ""
+
+msgid "2FADevice|Registered On"
+msgstr ""
+
+msgid "3 hours"
+msgstr ""
+
+msgid "30 minutes"
+msgstr ""
+
+msgid "30+ contributions"
+msgstr ""
+
+msgid "403|Please contact your GitLab administrator to get permission."
+msgstr ""
+
+msgid "403|You don't have the permission to access this page."
+msgstr ""
+
+msgid "404|Make sure the address is correct and the page hasn't moved."
+msgstr ""
+
+msgid "404|Not found"
+msgstr ""
+
+msgid "404|Page Not Found"
+msgstr ""
+
+msgid "404|Please contact your GitLab administrator if you think this is a mistake."
+msgstr ""
+
+msgid "409|Please contact your GitLab administrator if you think this is a mistake."
+msgstr ""
+
+msgid "409|There was a conflict with your request."
+msgstr ""
+
+msgid "8 hours"
+msgstr ""
+
+msgid ":%{startLine} to %{endLine}"
+msgstr ""
+
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
+msgid "A %{linkStart}merge train%{linkEnd} is a queued list of merge requests, each waiting to be merged into the target branch."
+msgstr ""
+
+msgid "A .NET Core console application template, customizable for any .NET Core project"
+msgstr ""
+
+msgid "A CI/CD pipeline must run and be successful before merge."
+msgstr ""
+
+msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
+msgstr ""
+
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
+msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
+msgstr ""
+
+msgid "A Hugo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
+msgstr ""
+
+msgid "A Jekyll site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
+msgstr ""
+
+msgid "A Let's Encrypt SSL certificate can not be obtained until your domain is verified."
+msgstr ""
+
+msgid "A Work Item can be a parent or a child, but not both."
+msgstr ""
+
+msgid "A basic folder structure of a Laravel application, to help you get started."
+msgstr ""
+
+msgid "A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages"
+msgstr ""
+
+msgid "A basic template for developing Linux programs using Kotlin Native"
+msgstr ""
+
+msgid "A complete DevOps platform"
+msgstr ""
+
+msgid "A confidential issue must have only confidential children. Make any child items confidential and try again."
+msgstr ""
+
+msgid "A confidential work item cannot have a parent that already has non-confidential children."
+msgstr ""
+
+msgid "A deleted user"
+msgstr ""
+
+msgid "A different reason"
+msgstr ""
+
+msgid "A file has been changed."
+msgstr ""
+
+msgid "A file was not found."
+msgstr ""
+
+msgid "A file with this name already exists."
+msgstr ""
+
+msgid "A group is a collection of several projects"
+msgstr ""
+
+msgid "A group represents your organization in GitLab. Groups allow you to manage users and collaborate across multiple projects."
+msgstr ""
+
+msgid "A job artifact is an archive of files and directories saved by a job when it finishes."
+msgstr ""
+
+msgid "A limit of %{ci_project_subscriptions_limit} subscriptions to or from a project applies."
+msgstr ""
+
+msgid "A management, operational, or technical control (that is, safeguard or countermeasure) employed by an organization that provides equivalent or comparable protection for an information system."
+msgstr ""
+
+msgid "A member of the abuse team will review your report as soon as possible."
+msgstr ""
+
+msgid "A new Auto DevOps pipeline has been created, go to the Pipelines page for details"
+msgstr ""
+
+msgid "A new Release %{tag} for %{name} was published. Visit the %{release_link_start}Releases page%{release_link_end} to read more about it."
+msgstr ""
+
+msgid "A new Release %{tag} for %{name} was published. Visit the Releases page to read more about it:"
+msgstr ""
+
+msgid "A new email address has been added to your GitLab account: %{email}"
+msgstr ""
+
+msgid "A new personal access token has been created"
+msgstr ""
+
+msgid "A new personal access token, named %{code_start}%{token_name}%{code_end}, has been created."
+msgstr ""
+
+msgid "A new personal access token, named %{token_name}, has been created."
+msgstr ""
+
+msgid "A non-confidential epic cannot be assigned to a confidential parent epic"
+msgstr ""
+
+msgid "A non-confidential issue cannot have a confidential parent."
+msgstr ""
+
+msgid "A non-confidential work item cannot have a confidential parent."
+msgstr ""
+
+msgid "A parent must be provided when bulk updating issuables"
+msgstr ""
+
+msgid "A personal access token has been revoked"
+msgstr ""
+
+msgid "A personal access token, named %{code_start}%{token_name}%{code_end}, has been revoked."
+msgstr ""
+
+msgid "A personal access token, named %{token_name}, has been revoked."
+msgstr ""
+
+msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
+msgstr ""
+
+msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
+msgstr ""
+
+msgid "A project boilerplate for Tencent Serverless Framework that uses Next.js SSR"
+msgstr ""
+
+msgid "A project containing issues for each audit inquiry in the HIPAA Audit Protocol published by the U.S. Department of Health & Human Services"
+msgstr ""
+
+msgid "A project’s repository name defines its URL (the one you use to access the project via a browser) and its place on the file disk where GitLab is installed. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "A quarterly reconciliation is due on %{date}"
+msgstr ""
+
+msgid "A ready-to-go template for use with Android apps"
+msgstr ""
+
+msgid "A ready-to-go template for use with iOS Swift apps"
+msgstr ""
+
+msgid "A rebase is already in progress."
+msgstr ""
+
+msgid "A sign-in to your account has been made from the following IP address: %{ip}"
+msgstr ""
+
+msgid "A template for starting a new TYPO3 project"
+msgstr ""
+
+msgid "A title is required"
+msgstr ""
+
+msgid "A user with write access to the source branch selected this option"
+msgstr ""
+
+msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '%{domain}'"
+msgstr ""
+
+msgid "AI actions"
+msgstr ""
+
+msgid "AI-generated summary"
+msgstr ""
+
+msgid "AISummary|Generates a summary of all comments"
+msgstr ""
+
+msgid "AISummary|View summary"
+msgstr ""
+
+msgid "AI| %{link_start}How is my data used?%{link_end}"
+msgstr ""
+
+msgid "AI| %{link_start}What are Experiment features?%{link_end}"
+msgstr ""
+
+msgid "AI|%{tool} is %{transition} an answer"
+msgstr ""
+
+msgid "AI|AI generated explanations will appear here."
+msgstr ""
+
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
+msgid "AI|Apply AI-generated description"
+msgstr ""
+
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
+msgid "AI|Ask a question"
+msgstr ""
+
+msgid "AI|Autocomplete"
+msgstr ""
+
+msgid "AI|Can be removed at any time"
+msgstr ""
+
+msgid "AI|Close the Code Explanation"
+msgstr ""
+
+msgid "AI|Code Explanation"
+msgstr ""
+
+msgid "AI|Creates issue description based on a short prompt"
+msgstr ""
+
+msgid "AI|Description is required"
+msgstr ""
+
+msgid "AI|Enabling these features is your acceptance of the %{link_start}GitLab Testing Agreement%{link_end}."
+msgstr ""
+
+msgid "AI|Experiment"
+msgstr ""
+
+msgid "AI|Experiment features"
+msgstr ""
+
+msgid "AI|Explain the code from %{filePath} in human understandable language presented in Markdown format. In the response add neither original code snippet nor any title. `%{text}`. If it is not programming code, say `The selected text is not code. I am afraid this feature is for explaining code only. Would you like to ask a different question about the selected text?` and wait for another question."
+msgstr ""
+
+msgid "AI|Explain your rating (optional)"
+msgstr ""
+
+msgid "AI|Features that use third-party AI services require transmission of data, including personal data."
+msgstr ""
+
+msgid "AI|For example: Organizations should be able to forecast into the future by using value stream analytics charts. This feature would help them understand how their metrics are trending."
+msgstr ""
+
+msgid "AI|Generate issue description"
+msgstr ""
+
+msgid "AI|GitLab Duo"
+msgstr ""
+
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
+msgid "AI|Helpful"
+msgstr ""
+
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
+msgid "AI|I don't see how I can help. Please give better instructions!"
+msgstr ""
+
+msgid "AI|May be unstable"
+msgstr ""
+
+msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
+msgstr ""
+
+msgid "AI|New chat"
+msgstr ""
+
+msgid "AI|Populate issue description"
+msgstr ""
+
+msgid "AI|Replace the existing description with an AI-generated description? Any changes you have made will be lost."
+msgstr ""
+
+msgid "AI|Responses generated by AI"
+msgstr ""
+
+msgid "AI|Send chat message."
+msgstr ""
+
+msgid "AI|Something went wrong. Please try again later"
+msgstr ""
+
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
+msgid "AI|The container element wasn't found, stopping AI Genie."
+msgstr ""
+
+msgid "AI|The existing description will be replaced when you submit."
+msgstr ""
+
+msgid "AI|There is too much text in the chat. Please try again with a shorter text."
+msgstr ""
+
+msgid "AI|These features can cause performance and stability issues and may change over time."
+msgstr ""
+
+msgid "AI|Third-party AI services"
+msgstr ""
+
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
+msgid "AI|Unhelpful"
+msgstr ""
+
+msgid "AI|Use Experiment features"
+msgstr ""
+
+msgid "AI|Use third-party AI services"
+msgstr ""
+
+msgid "AI|What does the selected code mean?"
+msgstr ""
+
+msgid "AI|What's an Experiment?"
+msgstr ""
+
+msgid "AI|Write a brief description and have AI fill in the details."
+msgstr ""
+
+msgid "AI|Write a summary to fill out the selected issue template"
+msgstr ""
+
+msgid "AI|Wrong"
+msgstr ""
+
+msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
+msgstr ""
+
+msgid "AI|finding"
+msgstr ""
+
+msgid "AI|generating"
+msgstr ""
+
+msgid "AI|producing"
+msgstr ""
+
+msgid "AI|working on"
+msgstr ""
+
+msgid "API"
+msgstr ""
+
+msgid "API Fuzzing"
+msgstr ""
+
+msgid "API Help"
+msgstr ""
+
+msgid "API key"
+msgstr ""
+
+msgid "API?"
+msgstr ""
+
+msgid "APIFuzzing|$VARIABLE_WITH_PASSWORD"
+msgstr ""
+
+msgid "APIFuzzing|$VARIABLE_WITH_USERNAME"
+msgstr ""
+
+msgid "APIFuzzing|API Fuzzing Configuration"
+msgstr ""
+
+msgid "APIFuzzing|Base URL of API testing target. For example, http://www.example.com."
+msgstr ""
+
+msgid "APIFuzzing|Choose a method"
+msgstr ""
+
+msgid "APIFuzzing|Choose a profile"
+msgstr ""
+
+msgid "APIFuzzing|Configure HTTP basic authentication values. Other authentication methods are supported. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "APIFuzzing|Customize your project's API fuzzing configuration options and copy the code snippet to your .gitlab-ci.yml file to apply any changes. Note that this tool does not reflect or update your .gitlab-ci.yml file automatically. For details of more advanced configuration options, see the %{docsLinkStart}GitLab API Fuzzing documentation%{docsLinkEnd}."
+msgstr ""
+
+msgid "APIFuzzing|Enable authentication"
+msgstr ""
+
+msgid "APIFuzzing|Enter the name of the CI variable containing the password. For example, $VARIABLE_WITH_PASSWORD."
+msgstr ""
+
+msgid "APIFuzzing|Enter the name of the CI variable containing the username. For example, $VARIABLE_WITH_USERNAME."
+msgstr ""
+
+msgid "APIFuzzing|File path or URL to APIs to be tested. For example, folder/example_fuzz.har. HAR files may contain sensitive information such as authentication tokens, API keys, and session cookies. We recommend that you review the HAR files' contents before adding them to a repository."
+msgstr ""
+
+msgid "APIFuzzing|File path or URL to OpenAPI specification. For example, folder/openapi.json or http://www.example.com/openapi.json."
+msgstr ""
+
+msgid "APIFuzzing|File path or URL to requests to be tested. For example, folder/example.postman_collection.json."
+msgstr ""
+
+msgid "APIFuzzing|Generate code snippet"
+msgstr ""
+
+msgid "APIFuzzing|Make sure your credentials are secured"
+msgstr ""
+
+msgid "APIFuzzing|Password for basic authentication"
+msgstr ""
+
+msgid "APIFuzzing|Predefined profiles"
+msgstr ""
+
+msgid "APIFuzzing|Scan mode"
+msgstr ""
+
+msgid "APIFuzzing|Scan profile"
+msgstr ""
+
+msgid "APIFuzzing|Show code snippet for the profile"
+msgstr ""
+
+msgid "APIFuzzing|Target URL"
+msgstr ""
+
+msgid "APIFuzzing|There are three ways to perform scans."
+msgstr ""
+
+msgid "APIFuzzing|Tip: Insert the following variables anywhere below stages and include"
+msgstr ""
+
+msgid "APIFuzzing|Tip: Insert this part below all include"
+msgstr ""
+
+msgid "APIFuzzing|Tip: Insert this part below all stages"
+msgstr ""
+
+msgid "APIFuzzing|To prevent a security leak, authentication info must be added as a %{ciVariablesLinkStart}CI variable%{ciVariablesLinkEnd}. A user with maintainer access rights can manage CI variables in the %{ciSettingsLinkStart}Settings%{ciSettingsLinkEnd} area. We detected that you are not a maintainer. Commit your changes and assign them to a maintainer to update the credentials before merging."
+msgstr ""
+
+msgid "APIFuzzing|To prevent a security leak, authentication info must be added as a %{ciVariablesLinkStart}CI variable%{ciVariablesLinkEnd}. As a user with maintainer access rights, you can manage CI variables in the %{ciSettingsLinkStart}Settings%{ciSettingsLinkEnd} area."
+msgstr ""
+
+msgid "APIFuzzing|Username for basic authentication"
+msgstr ""
+
+msgid "APIFuzzing|You may need a maintainer's help to secure your credentials."
+msgstr ""
+
+msgid "APIFuzzing|folder/example.postman_collection.json"
+msgstr ""
+
+msgid "APIFuzzing|folder/example_fuzz.har"
+msgstr ""
+
+msgid "APIFuzzing|folder/openapi.json"
+msgstr ""
+
+msgid "AWS"
+msgstr ""
+
+msgid "AWS Access Key"
+msgstr ""
+
+msgid "AWS OpenSearch IAM credentials"
+msgstr ""
+
+msgid "AWS Secret Access Key"
+msgstr ""
+
+msgid "AWS access key ID (Optional)"
+msgstr ""
+
+msgid "AWS secret access key (Optional)"
+msgstr ""
+
+msgid "Abort"
+msgstr ""
+
+msgid "About GitLab"
+msgstr ""
+
+msgid "About auto deploy"
+msgstr ""
+
+msgid "About this feature"
+msgstr ""
+
+msgid "About your company"
+msgstr ""
+
+msgid "Abuse Reports"
+msgstr ""
+
+msgid "Abuse reports"
+msgstr ""
+
+msgid "Abuse reports notification email"
+msgstr ""
+
+msgid "AbuseReportEvent|Successfully banned the user"
+msgstr ""
+
+msgid "AbuseReportEvent|Successfully banned the user and closed the report"
+msgstr ""
+
+msgid "AbuseReportEvent|Successfully blocked the user"
+msgstr ""
+
+msgid "AbuseReportEvent|Successfully blocked the user and closed the report"
+msgstr ""
+
+msgid "AbuseReportEvent|Successfully closed the report"
+msgstr ""
+
+msgid "AbuseReportEvent|Successfully scheduled the user for deletion"
+msgstr ""
+
+msgid "AbuseReportEvent|Successfully scheduled the user for deletion and closed the report"
+msgstr ""
+
+msgid "AbuseReports|%{reportedUser} reported for %{category} by %{count} users"
+msgstr ""
+
+msgid "AbuseReports|%{reportedUser} reported for %{category} by %{reporter}"
+msgstr ""
+
+msgid "AbuseReports|Deleted user"
+msgstr ""
+
+msgid "AbuseReports|No reports found"
+msgstr ""
+
+msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
+msgstr ""
+
+msgid "AbuseReport|Abuse unconfirmed"
+msgstr ""
+
+msgid "AbuseReport|Action"
+msgstr ""
+
+msgid "AbuseReport|Actions"
+msgstr ""
+
+msgid "AbuseReport|Activity"
+msgstr ""
+
+msgid "AbuseReport|Admin profile"
+msgstr ""
+
+msgid "AbuseReport|Ban user"
+msgstr ""
+
+msgid "AbuseReport|Block user"
+msgstr ""
+
+msgid "AbuseReport|Card matches %{cardMatchesLinkStart}%{count} accounts%{cardMatchesLinkEnd}"
+msgstr ""
+
+msgid "AbuseReport|Close report"
+msgstr ""
+
+msgid "AbuseReport|Comment"
+msgstr ""
+
+msgid "AbuseReport|Comments"
+msgstr ""
+
+msgid "AbuseReport|Confirm"
+msgstr ""
+
+msgid "AbuseReport|Confirmed crypto mining"
+msgstr ""
+
+msgid "AbuseReport|Confirmed offensive or abusive behavior"
+msgstr ""
+
+msgid "AbuseReport|Confirmed phishing"
+msgstr ""
+
+msgid "AbuseReport|Confirmed posting of malware"
+msgstr ""
+
+msgid "AbuseReport|Confirmed posting of personal information or credentials"
+msgstr ""
+
+msgid "AbuseReport|Confirmed spam"
+msgstr ""
+
+msgid "AbuseReport|Confirmed violation of a copyright or a trademark"
+msgstr ""
+
+msgid "AbuseReport|Copyright or trademark violation"
+msgstr ""
+
+msgid "AbuseReport|Credit card"
+msgstr ""
+
+msgid "AbuseReport|Crypto Mining"
+msgstr ""
+
+msgid "AbuseReport|Delete user"
+msgstr ""
+
+msgid "AbuseReport|Email"
+msgstr ""
+
+msgid "AbuseReport|Go to comment"
+msgstr ""
+
+msgid "AbuseReport|Go to content"
+msgstr ""
+
+msgid "AbuseReport|Go to issue"
+msgstr ""
+
+msgid "AbuseReport|Go to merge request"
+msgstr ""
+
+msgid "AbuseReport|Go to profile"
+msgstr ""
+
+msgid "AbuseReport|Groups"
+msgstr ""
+
+msgid "AbuseReport|Last login"
+msgstr ""
+
+msgid "AbuseReport|Malware"
+msgstr ""
+
+msgid "AbuseReport|Member since"
+msgstr ""
+
+msgid "AbuseReport|No action"
+msgstr ""
+
+msgid "AbuseReport|No user found"
+msgstr ""
+
+msgid "AbuseReport|Normal location"
+msgstr ""
+
+msgid "AbuseReport|Offensive or Abusive"
+msgstr ""
+
+msgid "AbuseReport|Other"
+msgstr ""
+
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
+msgid "AbuseReport|Personal information or credentials"
+msgstr ""
+
+msgid "AbuseReport|Phishing"
+msgstr ""
+
+msgid "AbuseReport|Phone"
+msgstr ""
+
+msgid "AbuseReport|Reason"
+msgstr ""
+
+msgid "AbuseReport|Registered with name %{name}."
+msgstr ""
+
+msgid "AbuseReport|Reported by"
+msgstr ""
+
+msgid "AbuseReport|Reported by %{name} for %{category}."
+msgstr ""
+
+msgid "AbuseReport|Reported comment"
+msgstr ""
+
+msgid "AbuseReport|Reported content"
+msgstr ""
+
+msgid "AbuseReport|Reported issue"
+msgstr ""
+
+msgid "AbuseReport|Reported merge request"
+msgstr ""
+
+msgid "AbuseReport|Reported profile"
+msgstr ""
+
+msgid "AbuseReport|Screenshot of reported abuse"
+msgstr ""
+
+msgid "AbuseReport|Snippets"
+msgstr ""
+
+msgid "AbuseReport|Something else"
+msgstr ""
+
+msgid "AbuseReport|Spam"
+msgstr ""
+
+msgid "AbuseReport|Tier"
+msgstr ""
+
+msgid "AbuseReport|Verification"
+msgstr ""
+
+msgid "AbuseReport|View screenshot"
+msgstr ""
+
+msgid "Abusive or offensive"
+msgstr ""
+
+msgid "Accept invitation"
+msgstr ""
+
+msgid "Accept terms"
+msgstr ""
+
+msgid "Acceptable for use in this project"
+msgstr ""
+
+msgid "Access Denied"
+msgstr ""
+
+msgid "Access Git repositories or the API."
+msgstr ""
+
+msgid "Access Token"
+msgstr ""
+
+msgid "Access Tokens"
+msgstr ""
+
+msgid "Access denied"
+msgstr ""
+
+msgid "Access denied for your LDAP account."
+msgstr ""
+
+msgid "Access expires"
+msgstr ""
+
+msgid "Access forbidden. Check your access level."
+msgstr ""
+
+msgid "Access granted"
+msgstr ""
+
+msgid "Access requests"
+msgstr ""
+
+msgid "Access to '%{classification_label}' not allowed"
+msgstr ""
+
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
+msgid "AccessDropdown|Groups"
+msgstr ""
+
+msgid "AccessDropdown|Roles"
+msgstr ""
+
+msgid "AccessDropdown|Select"
+msgstr ""
+
+msgid "AccessDropdown|Users"
+msgstr ""
+
+msgid "AccessTokens|Access Tokens"
+msgstr ""
+
+msgid "AccessTokens|Access token limit reached"
+msgstr ""
+
+msgid "AccessTokens|Add a %{type}"
+msgstr ""
+
+msgid "AccessTokens|Are you sure?"
+msgstr ""
+
+msgid "AccessTokens|Are you sure? Any RSS or calendar URLs currently in use will stop working."
+msgstr ""
+
+msgid "AccessTokens|Are you sure? Any issue email addresses currently in use will stop working."
+msgstr ""
+
+msgid "AccessTokens|Copy feed token"
+msgstr ""
+
+msgid "AccessTokens|Copy incoming email token"
+msgstr ""
+
+msgid "AccessTokens|Copy static object token"
+msgstr ""
+
+msgid "AccessTokens|Create %{type}"
+msgstr ""
+
+msgid "AccessTokens|Created"
+msgstr ""
+
+msgid "AccessTokens|Feed token"
+msgstr ""
+
+msgid "AccessTokens|For example, the application using the token or the purpose of the token."
+msgstr ""
+
+msgid "AccessTokens|For example, the application using the token or the purpose of the token. Do not give sensitive information for the name of the token, as it will be visible to all %{resource_type} members."
+msgstr ""
+
+msgid "AccessTokens|Incoming email token"
+msgstr ""
+
+msgid "AccessTokens|It cannot be used to access any other data."
+msgstr ""
+
+msgid "AccessTokens|Keep this token secret. Anyone who has it can access repository static objects as if they were you. If that ever happens, %{linkStart}reset this token%{linkEnd}."
+msgstr ""
+
+msgid "AccessTokens|Keep this token secret. Anyone who has it can create issues as if they were you. If that happens, %{linkStart}reset this token%{linkEnd}."
+msgstr ""
+
+msgid "AccessTokens|Keep this token secret. Anyone who has it can read activity and issue RSS feeds or your calendar feed as if they were you. If that happens, %{linkStart}reset this token%{linkEnd}."
+msgstr ""
+
+msgid "AccessTokens|Personal Access Tokens"
+msgstr ""
+
+msgid "AccessTokens|Scopes set the permission levels granted to the token."
+msgstr ""
+
+msgid "AccessTokens|Select a role"
+msgstr ""
+
+msgid "AccessTokens|Select scopes"
+msgstr ""
+
+msgid "AccessTokens|Static object token"
+msgstr ""
+
+msgid "AccessTokens|The last time a token was used"
+msgstr ""
+
+msgid "AccessTokens|They are the only accepted password when you have Two-Factor Authentication (2FA) enabled."
+msgstr ""
+
+msgid "AccessTokens|Token name"
+msgstr ""
+
+msgid "AccessTokens|You can also use personal access tokens to authenticate against Git over HTTP."
+msgstr ""
+
+msgid "AccessTokens|You can generate a personal access token for each application you use that needs access to the GitLab API."
+msgstr ""
+
+msgid "AccessTokens|You can only have one active project access token with a trial license. You cannot generate a new token until the existing token is deleted, or you upgrade your subscription."
+msgstr ""
+
+msgid "AccessTokens|Your feed token authenticates you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar. It is visible in those feed URLs."
+msgstr ""
+
+msgid "AccessTokens|Your incoming email token authenticates you when you create a new issue by email, and is included in your personal project-specific email addresses."
+msgstr ""
+
+msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
+msgstr ""
+
+msgid "AccessibilityReport|Message: %{message}"
+msgstr ""
+
+msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
+msgstr ""
+
+msgid "Accessible by any user who is logged in."
+msgstr ""
+
+msgid "Accessible by anyone, regardless of authentication."
+msgstr ""
+
+msgid "Account"
+msgstr ""
+
+msgid "Account ID"
+msgstr ""
+
+msgid "Account and limit"
+msgstr ""
+
+msgid "Account:"
+msgstr ""
+
+msgid "Account: %{account}"
+msgstr ""
+
+msgid "AccountValidation|Fix your pipelines by validating your account"
+msgstr ""
+
+msgid "AccountValidation|I'll bring my own runners"
+msgstr ""
+
+msgid "AccountValidation|In order to use free compute minutes on shared runners, you'll need to validate your account using one of our verification options. If you prefer not to, you can run pipelines by bringing your own runners and disabling shared runners for your project."
+msgstr ""
+
+msgid "AccountValidation|Learn more."
+msgstr ""
+
+msgid "AccountValidation|Looks like you'll need to validate your account to use free compute minutes"
+msgstr ""
+
+msgid "AccountValidation|Validate your account"
+msgstr ""
+
+msgid "AccountValidation|Verification is required to discourage and reduce the abuse on GitLab infrastructure. If you verify with a credit or debit card, %{strong_start}GitLab will not charge your card, it will only be used for validation.%{strong_end} %{learn_more_link}"
+msgstr ""
+
+msgid "Achievements"
+msgstr ""
+
+msgid "Achievements|%{namespace_full_path} awarded you the %{achievement_name} achievement"
+msgstr ""
+
+msgid "Achievements|%{namespace_full_path} awarded you the %{achievement_name} achievement!"
+msgstr ""
+
+msgid "Achievements|%{namespace_link} awarded you the %{bold_start}%{achievement_name}%{bold_end} achievement!"
+msgstr ""
+
+msgid "Achievements|Awarded %{timeAgo} by %{namespace}"
+msgstr ""
+
+msgid "Achievements|Awarded %{timeAgo} by a private namespace"
+msgstr ""
+
+msgid "Achievements|View your achievements on your %{link_start}profile%{link_end}."
+msgstr ""
+
+msgid "Achievements|View your achievements on your profile."
+msgstr ""
+
+msgid "Acknowledge"
+msgstr ""
+
+msgid "Action"
+msgstr ""
+
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
+msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
+msgstr ""
+
+msgid "Action not allowed."
+msgstr ""
+
+msgid "Action to take when receiving an alert. %{docsLink}"
+msgstr ""
+
+msgid "Actions"
+msgstr ""
+
+msgid "Activate Service Desk"
+msgstr ""
+
+msgid "Activated"
+msgstr ""
+
+msgid "Active"
+msgstr ""
+
+msgid "Active Sessions"
+msgstr ""
+
+msgid "Active chat names (%{count})"
+msgstr ""
+
+msgid "Active group access tokens"
+msgstr ""
+
+msgid "Active personal access tokens"
+msgstr ""
+
+msgid "Active pipeline trigger tokens"
+msgstr ""
+
+msgid "Active project access tokens"
+msgstr ""
+
+msgid "Activity"
+msgstr ""
+
+msgid "Activity|An error occurred while retrieving activity. Reload the page to try again."
+msgstr ""
+
+msgid "Add"
+msgstr ""
+
+msgid "Add \"%{value}\""
+msgstr ""
+
+msgid "Add %{linkStart}assets%{linkEnd} to your Release. GitLab automatically includes read-only assets, like source code and release evidence."
+msgstr ""
+
+msgid "Add CHANGELOG"
+msgstr ""
+
+msgid "Add CONTRIBUTING"
+msgstr ""
+
+msgid "Add Kubernetes cluster"
+msgstr ""
+
+msgid "Add LICENSE"
+msgstr ""
+
+msgid "Add License"
+msgstr ""
+
+msgid "Add New Site"
+msgstr ""
+
+msgid "Add README"
+msgstr ""
+
+msgid "Add Wiki"
+msgstr ""
+
+msgid "Add Zoom meeting"
+msgstr ""
+
+msgid "Add a GCP region"
+msgstr ""
+
+msgid "Add a GPG key"
+msgstr ""
+
+msgid "Add a GPG key for secure access to GitLab. %{help_link_start}Learn more%{help_link_end}."
+msgstr ""
+
+msgid "Add a Terms of Service agreement and Privacy Policy for users of this GitLab instance."
+msgstr ""
+
+msgid "Add a bullet list"
+msgstr ""
+
+msgid "Add a checklist"
+msgstr ""
+
+msgid "Add a collapsible section"
+msgstr ""
+
+msgid "Add a comment to this line"
+msgstr ""
+
+msgid "Add a comment to this line or drag for multiple lines"
+msgstr ""
+
+msgid "Add a confidential internal note to this %{noteableDisplayName}."
+msgstr ""
+
+msgid "Add a custom message with details about the instance's shared runners. The message is visible when you view runners for projects and groups. Markdown is supported."
+msgstr ""
+
+msgid "Add a general comment to this %{noteableDisplayName}."
+msgstr ""
+
+msgid "Add a homepage to your wiki that contains information about your project and GitLab will display it here instead of this message."
+msgstr ""
+
+msgid "Add a new comment template"
+msgstr ""
+
+msgid "Add a new issue"
+msgstr ""
+
+msgid "Add a numbered list"
+msgstr ""
+
+msgid "Add a quick action"
+msgstr ""
+
+msgid "Add a related epic"
+msgstr ""
+
+msgid "Add a related issue"
+msgstr ""
+
+msgid "Add a reply"
+msgstr ""
+
+msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "Add a table"
+msgstr ""
+
+msgid "Add a timeline event to incident"
+msgstr ""
+
+msgid "Add a title..."
+msgstr ""
+
+msgid "Add a to do"
+msgstr ""
+
+msgid "Add an SSH key"
+msgstr ""
+
+msgid "Add an SSH key for secure access to GitLab. %{help_link_start}Learn more%{help_link_end}."
+msgstr ""
+
+msgid "Add an existing issue"
+msgstr ""
+
+msgid "Add an impersonation token"
+msgstr ""
+
+msgid "Add another link"
+msgstr ""
+
+msgid "Add approval rule"
+msgstr ""
+
+msgid "Add approvers"
+msgstr ""
+
+msgid "Add child epic to an epic"
+msgstr ""
+
+msgid "Add comment now"
+msgstr ""
+
+msgid "Add comment to design"
+msgstr ""
+
+msgid "Add comment to incident timeline"
+msgstr ""
+
+msgid "Add comment..."
+msgstr ""
+
+msgid "Add commit messages as comments to Asana tasks. %{docs_link}"
+msgstr ""
+
+msgid "Add commit messages as comments to Pivotal Tracker stories. %{docs_link}"
+msgstr ""
+
+msgid "Add customer relation contact(s)."
+msgstr ""
+
+msgid "Add customer relation contacts"
+msgstr ""
+
+msgid "Add deploy freeze"
+msgstr ""
+
+msgid "Add deploy keys to grant read/write access to this repository. %{link_start}What are deploy keys?%{link_end}"
+msgstr ""
+
+msgid "Add email participant(s)"
+msgstr ""
+
+msgid "Add environment"
+msgstr ""
+
+msgid "Add existing confidential %{issuableType}"
+msgstr ""
+
+msgid "Add existing issue"
+msgstr ""
+
+msgid "Add header and footer to emails. Please note that color settings will only be applied within the application interface"
+msgstr ""
+
+msgid "Add image comment"
+msgstr ""
+
+msgid "Add internal note"
+msgstr ""
+
+msgid "Add key"
+msgstr ""
+
+msgid "Add labels"
+msgstr ""
+
+msgid "Add license"
+msgstr ""
+
+msgid "Add list"
+msgstr ""
+
+msgid "Add new"
+msgstr ""
+
+msgid "Add new application"
+msgstr ""
+
+msgid "Add new comment template"
+msgstr ""
+
+msgid "Add new directory"
+msgstr ""
+
+msgid "Add new emoji"
+msgstr ""
+
+msgid "Add new key"
+msgstr ""
+
+msgid "Add new pipeline subscription"
+msgstr ""
+
+msgid "Add new pipeline trigger token"
+msgstr ""
+
+msgid "Add new token"
+msgstr ""
+
+msgid "Add new webhook"
+msgstr ""
+
+msgid "Add or remove a user."
+msgstr ""
+
+msgid "Add or remove previously merged commits"
+msgstr ""
+
+msgid "Add or subtract spent time"
+msgstr ""
+
+msgid "Add people"
+msgstr ""
+
+msgid "Add previously merged commits"
+msgstr ""
+
+msgid "Add project"
+msgstr ""
+
+msgid "Add projects"
+msgstr ""
+
+msgid "Add protected branch"
+msgstr ""
+
+msgid "Add reaction"
+msgstr ""
+
+msgid "Add request manually"
+msgstr ""
+
+msgid "Add start and due date"
+msgstr ""
+
+msgid "Add suggestion to batch"
+msgstr ""
+
+msgid "Add tag"
+msgstr ""
+
+msgid "Add target branch rule"
+msgstr ""
+
+msgid "Add text to the sign-in page. Markdown enabled."
+msgstr ""
+
+msgid "Add time entry"
+msgstr ""
+
+msgid "Add to board"
+msgstr ""
+
+msgid "Add to epic"
+msgstr ""
+
+msgid "Add to merge train"
+msgstr ""
+
+msgid "Add to merge train when pipeline succeeds"
+msgstr ""
+
+msgid "Add to review"
+msgstr ""
+
+msgid "Add to tree"
+msgstr ""
+
+msgid "Add token"
+msgstr ""
+
+msgid "Add topics to projects to help users find them."
+msgstr ""
+
+msgid "Add variable"
+msgstr ""
+
+msgid "Add vulnerability finding"
+msgstr ""
+
+msgid "Add webhook"
+msgstr ""
+
+msgid "Add your team members and others to GitLab."
+msgstr ""
+
+msgid "Add/remove"
+msgstr ""
+
+msgid "AddContextCommits|Add previously merged commits"
+msgstr ""
+
+msgid "AddContextCommits|Add/remove"
+msgstr ""
+
+msgid "AddMember|Invite email is invalid"
+msgstr ""
+
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
+
+msgid "AddMember|Invites cannot be blank"
+msgstr ""
+
+msgid "AddMember|No invite source provided."
+msgstr ""
+
+msgid "AddMember|No users specified."
+msgstr ""
+
+msgid "AddMember|Too many users specified (limit is %{user_limit})"
+msgstr ""
+
+msgid "Added"
+msgstr ""
+
+msgid "Added %{epic_ref} as a child epic."
+msgstr ""
+
+msgid "Added %{label_references} %{label_text}."
+msgstr ""
+
+msgid "Added a to do."
+msgstr ""
+
+msgid "Added an issue to an epic."
+msgstr ""
+
+msgid "Added for this merge request"
+msgstr ""
+
+msgid "Added in this version"
+msgstr ""
+
+msgid "Adding new applications is disabled in your GitLab instance. Please contact your GitLab administrator to get the permission."
+msgstr ""
+
+msgid "Additional compute minutes:"
+msgstr ""
+
+msgid "Additional diagram formats"
+msgstr ""
+
+msgid "Additional text"
+msgstr ""
+
+msgid "Additional text for deactivation email"
+msgstr ""
+
+msgid "Additional text for the sign-in and Help page."
+msgstr ""
+
+msgid "Additional text to show on the Help page"
+msgstr ""
+
+msgid "Additional text to show on the sign-in page"
+msgstr ""
+
+msgid "Additional units"
+msgstr ""
+
+msgid "Address"
+msgstr ""
+
+msgid "Adds"
+msgstr ""
+
+msgid "Adds %{epic_ref} as child epic."
+msgstr ""
+
+msgid "Adds %{labels} %{label_text}."
+msgstr ""
+
+msgid "Adds a Zoom meeting."
+msgstr ""
+
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
+msgid "Adds a timeline event to incident."
+msgstr ""
+
+msgid "Adds a to do."
+msgstr ""
+
+msgid "Adds an issue to an epic."
+msgstr ""
+
+msgid "Adds email participant(s)."
+msgstr ""
+
+msgid "Adds this %{issuable_type} as related to the %{issuable_type} it was created from"
+msgstr ""
+
+msgid "Adjust how frequently the GitLab UI polls for updates."
+msgstr ""
+
+msgid "Admin"
+msgstr ""
+
+msgid "Admin Area"
+msgstr ""
+
+msgid "Admin Area / Dashboard"
+msgstr ""
+
+msgid "Admin Note"
+msgstr ""
+
+msgid "Admin Notifications"
+msgstr ""
+
+msgid "Admin message"
+msgstr ""
+
+msgid "Admin mode"
+msgstr ""
+
+msgid "Admin mode already enabled"
+msgstr ""
+
+msgid "Admin mode disabled"
+msgstr ""
+
+msgid "Admin mode enabled"
+msgstr ""
+
+msgid "Admin notes"
+msgstr ""
+
+msgid "AdminArea|%{billable_users_link_start}Learn more%{billable_users_link_end} about what defines a billable user"
+msgstr ""
+
+msgid "AdminArea|Active users"
+msgstr ""
+
+msgid "AdminArea|All users created in the instance, including users who are not %{billable_users_link_start}billable users%{billable_users_link_end}."
+msgstr ""
+
+msgid "AdminArea|Are you sure?"
+msgstr ""
+
+msgid "AdminArea|Blocked users"
+msgstr ""
+
+msgid "AdminArea|Bots"
+msgstr ""
+
+msgid "AdminArea|Breakdown of Billable users"
+msgstr ""
+
+msgid "AdminArea|Breakdown of Non-Billable users"
+msgstr ""
+
+msgid "AdminArea|Cancel all jobs"
+msgstr ""
+
+msgid "AdminArea|Cancel all running and pending jobs"
+msgstr ""
+
+msgid "AdminArea|Canceling jobs failed"
+msgstr ""
+
+msgid "AdminArea|Components"
+msgstr ""
+
+msgid "AdminArea|Developer"
+msgstr ""
+
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Get security updates from GitLab and stay up to date"
+msgstr ""
+
+msgid "AdminArea|Groups"
+msgstr ""
+
+msgid "AdminArea|Guest"
+msgstr ""
+
+msgid "AdminArea|Included Free in license"
+msgstr ""
+
+msgid "AdminArea|Instance OAuth applications"
+msgstr ""
+
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
+msgid "AdminArea|Maintainer"
+msgstr ""
+
+msgid "AdminArea|Manage applications for your instance that can use GitLab as an %{docs_link_start}OAuth provider%{docs_link_end}."
+msgstr ""
+
+msgid "AdminArea|Manage applications for your instance that can use GitLab as an OAuth provider, start by creating a new one above."
+msgstr ""
+
+msgid "AdminArea|Minimal access"
+msgstr ""
+
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
+msgid "AdminArea|No applications found"
+msgstr ""
+
+msgid "AdminArea|Owner"
+msgstr ""
+
+msgid "AdminArea|Projects"
+msgstr ""
+
+msgid "AdminArea|Reporter"
+msgstr ""
+
+msgid "AdminArea|Sign up for the GitLab Security Newsletter to get notified for security updates."
+msgstr ""
+
+msgid "AdminArea|Sign up for the GitLab newsletter"
+msgstr ""
+
+msgid "AdminArea|Stop all jobs"
+msgstr ""
+
+msgid "AdminArea|Total Billable users"
+msgstr ""
+
+msgid "AdminArea|Total Non-Billable users"
+msgstr ""
+
+msgid "AdminArea|Total users"
+msgstr ""
+
+msgid "AdminArea|Totals"
+msgstr ""
+
+msgid "AdminArea|Updated %{last_update_time}"
+msgstr ""
+
+msgid "AdminArea|Users"
+msgstr ""
+
+msgid "AdminArea|Users statistics"
+msgstr ""
+
+msgid "AdminArea|Users with highest role"
+msgstr ""
+
+msgid "AdminArea|Users with highest role guest and with a %{strongOpen}Custom Role%{strongClose}."
+msgstr ""
+
+msgid "AdminArea|Users without a Group and Project"
+msgstr ""
+
+msgid "AdminArea|View latest groups"
+msgstr ""
+
+msgid "AdminArea|View latest projects"
+msgstr ""
+
+msgid "AdminArea|View latest users"
+msgstr ""
+
+msgid "AdminArea|Yes, proceed"
+msgstr ""
+
+msgid "AdminArea|You're about to cancel all running and pending jobs across this instance. Do you want to proceed?"
+msgstr ""
+
+msgid "AdminArea|active users + blocked users"
+msgstr ""
+
+msgid "AdminArea|total billable + total non-billable"
+msgstr ""
+
+msgid "AdminDashboard|Error loading the statistics. Please try again"
+msgstr ""
+
+msgid "AdminEmail|An error occurred fetching the groups and projects. Please refresh the page to try again."
+msgstr ""
+
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Loading groups and projects."
+msgstr ""
+
+msgid "AdminEmail|No groups or projects found."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
+msgid "AdminLabels|Define your default set of project labels"
+msgstr ""
+
+msgid "AdminLabels|Labels created here will be automatically added to new projects."
+msgstr ""
+
+msgid "AdminLabels|They can be used to categorize issues and merge requests."
+msgstr ""
+
+msgid "AdminProjects| You’re about to permanently delete the project %{projectName}, its repository, and all related resources, including issues and merge requests. After you confirm and press %{strong_start}Delete project%{strong_end}, it cannot be undone or recovered."
+msgstr ""
+
+msgid "AdminProjects|Delete"
+msgstr ""
+
+msgid "AdminProjects|Delete Project %{projectName}?"
+msgstr ""
+
+msgid "AdminSettings|%{strongStart}WARNING:%{strongEnd} Environment variable %{environment_variable} does not exist or is not pointing to a valid directory. %{icon_link}"
+msgstr ""
+
+msgid "AdminSettings|A Let's Encrypt account will be configured for this GitLab instance using this email address. You will receive emails to warn of expiring certificates. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "AdminSettings|Affects all new and existing groups."
+msgstr ""
+
+msgid "AdminSettings|All new projects can use the instance's shared runners by default."
+msgstr ""
+
+msgid "AdminSettings|Allow migrating GitLab groups and projects by direct transfer"
+msgstr ""
+
+msgid "AdminSettings|Auto DevOps domain"
+msgstr ""
+
+msgid "AdminSettings|By default, set a limit to 0 to have no limit."
+msgstr ""
+
+msgid "AdminSettings|CI/CD limits"
+msgstr ""
+
+msgid "AdminSettings|Collector host"
+msgstr ""
+
+msgid "AdminSettings|Configure Let's Encrypt"
+msgstr ""
+
+msgid "AdminSettings|Configure limits on the number of repositories users can download, clone, or fork in a given time."
+msgstr ""
+
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
+msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
+msgstr ""
+
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Delete inactive projects"
+msgstr ""
+
+msgid "AdminSettings|Delete inactive projects that exceed"
+msgstr ""
+
+msgid "AdminSettings|Delete project after"
+msgstr ""
+
+msgid "AdminSettings|Disable Elasticsearch until indexing completes."
+msgstr ""
+
+msgid "AdminSettings|Disable feed token"
+msgstr ""
+
+msgid "AdminSettings|Disable public access to Pages sites"
+msgstr ""
+
+msgid "AdminSettings|Display a banner on merge requests in projects with no pipelines to initiate steps to add a .gitlab-ci.yml file."
+msgstr ""
+
+msgid "AdminSettings|Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "AdminSettings|Elasticsearch indexing"
+msgstr ""
+
+msgid "AdminSettings|Email from GitLab - email users right from the Admin Area. %{link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "AdminSettings|Enable Registration Features"
+msgstr ""
+
+msgid "AdminSettings|Enable Service Ping"
+msgstr ""
+
+msgid "AdminSettings|Enable collection of application metrics. Restart required. %{link_start}Learn how to export metrics to Prometheus%{link_end}."
+msgstr ""
+
+msgid "AdminSettings|Enable kuromoji custom analyzer: Indexing"
+msgstr ""
+
+msgid "AdminSettings|Enable kuromoji custom analyzer: Search"
+msgstr ""
+
+msgid "AdminSettings|Enable pipeline suggestion banner"
+msgstr ""
+
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
+msgid "AdminSettings|Enable shared runners for new projects"
+msgstr ""
+
+msgid "AdminSettings|Enable smartcn custom analyzer: Indexing"
+msgstr ""
+
+msgid "AdminSettings|Enable smartcn custom analyzer: Search"
+msgstr ""
+
+msgid "AdminSettings|Enabled"
+msgstr ""
+
+msgid "AdminSettings|Enforce invitation flow for groups and projects"
+msgstr ""
+
+msgid "AdminSettings|Feed token"
+msgstr ""
+
+msgid "AdminSettings|Git abuse rate limit"
+msgstr ""
+
+msgid "AdminSettings|Group runners expiration"
+msgstr ""
+
+msgid "AdminSettings|I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)."
+msgstr ""
+
+msgid "AdminSettings|If no unit is written, it defaults to seconds. For example, these are all equivalent: %{oneDayInSeconds}, %{oneDayInHoursHumanReadable}, or %{oneDayHumanReadable}. Minimum value is two hours. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "AdminSettings|If not specified at the group or instance level, the default is %{default_initial_branch_name}. Does not affect existing repositories."
+msgstr ""
+
+msgid "AdminSettings|If selected, only administrators are able to create internal groups, projects, and snippets."
+msgstr ""
+
+msgid "AdminSettings|If selected, only administrators are able to create private groups, projects, and snippets."
+msgstr ""
+
+msgid "AdminSettings|If selected, only administrators are able to create public groups, projects, and snippets. Also, profiles are only visible to authenticated users."
+msgstr ""
+
+msgid "AdminSettings|If there isn't any existing index, GitLab creates one."
+msgstr ""
+
+msgid "AdminSettings|Import sources"
+msgstr ""
+
+msgid "AdminSettings|Improve non-code indexing throughput by enqueuing Sidekiq jobs until all documents are processed."
+msgstr ""
+
+msgid "AdminSettings|Inactive project deletion"
+msgstr ""
+
+msgid "AdminSettings|Instance runners expiration"
+msgstr ""
+
+msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
+msgstr ""
+
+msgid "AdminSettings|Let's Encrypt email"
+msgstr ""
+
+msgid "AdminSettings|Limit project size at a global, group, and project level. %{link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "AdminSettings|Limit the number of namespaces and projects that can be indexed."
+msgstr ""
+
+msgid "AdminSettings|Maximum duration of a session for Git operations when 2FA is enabled."
+msgstr ""
+
+msgid "AdminSettings|Maximum includes"
+msgstr ""
+
+msgid "AdminSettings|Maximum number of DAG dependencies that a job can have"
+msgstr ""
+
+msgid "AdminSettings|Maximum number of custom domains per project"
+msgstr ""
+
+msgid "AdminSettings|Maximum number of downstream pipelines in a pipeline's hierarchy tree"
+msgstr ""
+
+msgid "AdminSettings|Maximum number of jobs in a single pipeline"
+msgstr ""
+
+msgid "AdminSettings|Maximum number of pipeline schedules"
+msgstr ""
+
+msgid "AdminSettings|Maximum number of pipeline subscriptions to and from a project"
+msgstr ""
+
+msgid "AdminSettings|Maximum number of runners registered per group"
+msgstr ""
+
+msgid "AdminSettings|Maximum number of runners registered per project"
+msgstr ""
+
+msgid "AdminSettings|Minimum size must be at least 0."
+msgstr ""
+
+msgid "AdminSettings|New CI/CD variables in projects and groups default to protected."
+msgstr ""
+
+msgid "AdminSettings|No required pipeline"
+msgstr ""
+
+msgid "AdminSettings|Only enable search after installing the plugin, enabling indexing, and recreating the index."
+msgstr ""
+
+msgid "AdminSettings|Package registry metadata to sync"
+msgstr ""
+
+msgid "AdminSettings|Pause Elasticsearch indexing"
+msgstr ""
+
+msgid "AdminSettings|Prevent non-administrators from using the selected visibility levels for groups, projects and snippets."
+msgstr ""
+
+msgid "AdminSettings|Preview payload"
+msgstr ""
+
+msgid "AdminSettings|Project export"
+msgstr ""
+
+msgid "AdminSettings|Project runners expiration"
+msgstr ""
+
+msgid "AdminSettings|Protect CI/CD variables by default"
+msgstr ""
+
+msgid "AdminSettings|Registration Features include:"
+msgstr ""
+
+msgid "AdminSettings|Requeue indexing workers"
+msgstr ""
+
+msgid "AdminSettings|Require users to prove ownership of custom domains"
+msgstr ""
+
+msgid "AdminSettings|Required pipeline configuration"
+msgstr ""
+
+msgid "AdminSettings|Requires %{linkStart}email notifications%{linkEnd}"
+msgstr ""
+
+msgid "AdminSettings|Restrict group access by IP address. %{link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "AdminSettings|Restricted visibility levels"
+msgstr ""
+
+msgid "AdminSettings|Save %{name} limits"
+msgstr ""
+
+msgid "AdminSettings|Search with Elasticsearch enabled"
+msgstr ""
+
+msgid "AdminSettings|Select a CI/CD template"
+msgstr ""
+
+msgid "AdminSettings|Select a group to use as a source of custom templates for new projects. %{link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "AdminSettings|Select to disable public access for Pages sites, which requires users to sign in for access to the Pages sites in your instance. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "AdminSettings|Send email to maintainers after project is inactive for"
+msgstr ""
+
+msgid "AdminSettings|Send warning email"
+msgstr ""
+
+msgid "AdminSettings|Service ping is disabled in your configuration file, and cannot be enabled through this form. For more information, see the documentation on %{link_start}deactivating service ping%{link_end}."
+msgstr ""
+
+msgid "AdminSettings|Session duration for Git operations when 2FA is enabled (minutes)"
+msgstr ""
+
+msgid "AdminSettings|Set a CI/CD template as the required pipeline configuration for all projects in the instance. Project CI/CD configuration merges into the required pipeline configuration when the pipeline runs. %{link_start}What is a required pipeline configuration?%{link_end}"
+msgstr ""
+
+msgid "AdminSettings|Set options for cost factors of forks"
+msgstr ""
+
+msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered group runners."
+msgstr ""
+
+msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered instance runners. Authentication tokens are automatically reset at these intervals."
+msgstr ""
+
+msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered project runners."
+msgstr ""
+
+msgid "AdminSettings|Set the initial name and protections for the default branch of new repositories created in the instance."
+msgstr ""
+
+msgid "AdminSettings|Set the maximum number of GitLab Pages custom domains per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "AdminSettings|Setting must be greater than 0."
+msgstr ""
+
+msgid "AdminSettings|Size and domain settings for Pages static sites."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
+msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
+msgstr ""
+
+msgid "AdminSettings|The host of your data collector instance."
+msgstr ""
+
+msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
+msgstr ""
+
+msgid "AdminSettings|The maximum number of included files per pipeline."
+msgstr ""
+
+msgid "AdminSettings|The template for the required pipeline configuration can be one of the GitLab-provided templates, or a custom template added to an instance template repository. %{link_start}How do I create an instance template repository?%{link_end}"
+msgstr ""
+
+msgid "AdminSettings|There are Advanced Search migrations pending that require indexing to pause. Indexing must remain paused until GitLab completes the migrations."
+msgstr ""
+
+msgid "AdminSettings|This cost factor will be applied to the storage consumed by forks."
+msgstr ""
+
+msgid "AdminSettings|This limit cannot be disabled. Set to 0 to block all DAG dependencies."
+msgstr ""
+
+msgid "AdminSettings|To enable Registration Features, first enable Service Ping."
+msgstr ""
+
+msgid "AdminSettings|To help improve GitLab and its user experience, GitLab periodically collects usage information. %{link_start}What information is shared with GitLab Inc.?%{link_end}"
+msgstr ""
+
+msgid "AdminSettings|Total number of jobs in currently active pipelines"
+msgstr ""
+
+msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
+msgstr ""
+
+msgid "AdminSettings|Use for cluster and index migrations. When indexing is paused, GitLab still tracks changes."
+msgstr ""
+
+msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
+msgstr ""
+
+msgid "AdminSettings|When to delete inactive projects"
+msgstr ""
+
+msgid "AdminSettings|You can enable Registration Features because Service Ping is enabled. To continue using Registration Features in the future, you will also need to register with GitLab via a new cloud licensing service."
+msgstr ""
+
+msgid "AdminSettings|You can't delete projects before the warning email is sent."
+msgstr ""
+
+msgid "AdminStatistics|Active Users"
+msgstr ""
+
+msgid "AdminStatistics|Forks"
+msgstr ""
+
+msgid "AdminStatistics|Issues"
+msgstr ""
+
+msgid "AdminStatistics|Merge requests"
+msgstr ""
+
+msgid "AdminStatistics|Milestones"
+msgstr ""
+
+msgid "AdminStatistics|Notes"
+msgstr ""
+
+msgid "AdminStatistics|SSH Keys"
+msgstr ""
+
+msgid "AdminStatistics|Snippets"
+msgstr ""
+
+msgid "AdminUsers|(Admin)"
+msgstr ""
+
+msgid "AdminUsers|(Banned)"
+msgstr ""
+
+msgid "AdminUsers|(Blocked)"
+msgstr ""
+
+msgid "AdminUsers|(Deactivated)"
+msgstr ""
+
+msgid "AdminUsers|(Internal)"
+msgstr ""
+
+msgid "AdminUsers|(Locked)"
+msgstr ""
+
+msgid "AdminUsers|(Pending approval)"
+msgstr ""
+
+msgid "AdminUsers|2FA Disabled"
+msgstr ""
+
+msgid "AdminUsers|2FA Enabled"
+msgstr ""
+
+msgid "AdminUsers|A user can validate themselves by inputting a credit/debit card, or an admin can manually validate a user. Validated users can use free CI minutes on shared runners."
+msgstr ""
+
+msgid "AdminUsers|Access"
+msgstr ""
+
+msgid "AdminUsers|Access Git repositories"
+msgstr ""
+
+msgid "AdminUsers|Access level"
+msgstr ""
+
+msgid "AdminUsers|Access the API"
+msgstr ""
+
+msgid "AdminUsers|Activate"
+msgstr ""
+
+msgid "AdminUsers|Activate user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Active"
+msgstr ""
+
+msgid "AdminUsers|Adjust the user cap setting on your instance"
+msgstr ""
+
+msgid "AdminUsers|Admin"
+msgstr ""
+
+msgid "AdminUsers|Administrator"
+msgstr ""
+
+msgid "AdminUsers|Admins"
+msgstr ""
+
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
+msgid "AdminUsers|Approve"
+msgstr ""
+
+msgid "AdminUsers|Approve user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Approved users can:"
+msgstr ""
+
+msgid "AdminUsers|Auditor"
+msgstr ""
+
+msgid "AdminUsers|Auditors have read-only access to all groups, projects, and users."
+msgstr ""
+
+msgid "AdminUsers|Automatically marked as default internal user"
+msgstr ""
+
+msgid "AdminUsers|Avatar"
+msgstr ""
+
+msgid "AdminUsers|Ban user"
+msgstr ""
+
+msgid "AdminUsers|Ban user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Banned"
+msgstr ""
+
+msgid "AdminUsers|Be added to groups and projects"
+msgstr ""
+
+msgid "AdminUsers|Block"
+msgstr ""
+
+msgid "AdminUsers|Block user"
+msgstr ""
+
+msgid "AdminUsers|Block user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Blocked"
+msgstr ""
+
+msgid "AdminUsers|Blocking user has the following effects:"
+msgstr ""
+
+msgid "AdminUsers|Bot"
+msgstr ""
+
+msgid "AdminUsers|Can create top level group"
+msgstr ""
+
+msgid "AdminUsers|Cannot sign in or access instance information"
+msgstr ""
+
+msgid "AdminUsers|Cannot unblock LDAP blocked users"
+msgstr ""
+
+msgid "AdminUsers|Cohorts"
+msgstr ""
+
+msgid "AdminUsers|Compute quota"
+msgstr ""
+
+msgid "AdminUsers|Confirm user"
+msgstr ""
+
+msgid "AdminUsers|Confirm user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Could not load user group counts. Please refresh the page to try again."
+msgstr ""
+
+msgid "AdminUsers|Deactivate"
+msgstr ""
+
+msgid "AdminUsers|Deactivate user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Deactivated"
+msgstr ""
+
+msgid "AdminUsers|Deactivating a user has the following effects:"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username} and contributions?"
+msgstr ""
+
+msgid "AdminUsers|Delete User %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Delete user"
+msgstr ""
+
+msgid "AdminUsers|Delete user and contributions"
+msgstr ""
+
+msgid "AdminUsers|Export permissions as CSV (max 100,000 users)"
+msgstr ""
+
+msgid "AdminUsers|External"
+msgstr ""
+
+msgid "AdminUsers|External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects, groups, or personal snippets."
+msgstr ""
+
+msgid "AdminUsers|For more information, please refer to the %{link_start}user account deletion documentation.%{link_end}"
+msgstr ""
+
+msgid "AdminUsers|Here are some helpful links to help you manage your instance:"
+msgstr ""
+
+msgid "AdminUsers|If you have any questions about this process please consult our %{doc_link} or %{support_link}."
+msgstr ""
+
+msgid "AdminUsers|Important information about usage on your GitLab instance"
+msgstr ""
+
+msgid "AdminUsers|Is using seat"
+msgstr ""
+
+msgid "AdminUsers|It's you!"
+msgstr ""
+
+msgid "AdminUsers|LDAP Blocked"
+msgstr ""
+
+msgid "AdminUsers|Learn more about %{link_start}banned users.%{link_end}"
+msgstr ""
+
+msgid "AdminUsers|Limits"
+msgstr ""
+
+msgid "AdminUsers|Linkedin"
+msgstr ""
+
+msgid "AdminUsers|Locked"
+msgstr ""
+
+msgid "AdminUsers|Log in"
+msgstr ""
+
+msgid "AdminUsers|Manage (accept/reject) pending user sign ups"
+msgstr ""
+
+msgid "AdminUsers|New user"
+msgstr ""
+
+msgid "AdminUsers|No users found"
+msgstr ""
+
+msgid "AdminUsers|Owned groups will be left"
+msgstr ""
+
+msgid "AdminUsers|Pending approval"
+msgstr ""
+
+msgid "AdminUsers|Personal projects will be left"
+msgstr ""
+
+msgid "AdminUsers|Personal projects, group and user history will be left intact"
+msgstr ""
+
+msgid "AdminUsers|Private profile"
+msgstr ""
+
+msgid "AdminUsers|Projects, issues, merge requests, and comments of this user are hidden from other users."
+msgstr ""
+
+msgid "AdminUsers|Reactivating a user will:"
+msgstr ""
+
+msgid "AdminUsers|Regular"
+msgstr ""
+
+msgid "AdminUsers|Regular users have access to their groups and projects."
+msgstr ""
+
+msgid "AdminUsers|Reject"
+msgstr ""
+
+msgid "AdminUsers|Reject user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Rejected users:"
+msgstr ""
+
+msgid "AdminUsers|Reset link will be generated and sent to the user. User will be forced to set the password on first sign in."
+msgstr ""
+
+msgid "AdminUsers|Restore user access to the account, including web, Git and API."
+msgstr ""
+
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
+
+msgid "AdminUsers|Search users"
+msgstr ""
+
+msgid "AdminUsers|Send email to users"
+msgstr ""
+
+msgid "AdminUsers|Skype"
+msgstr ""
+
+msgid "AdminUsers|Sort by"
+msgstr ""
+
+msgid "AdminUsers|The maximum compute minutes that jobs in this namespace can use on shared runners each month. Set 0 for unlimited. Set empty to inherit the global setting of %{minutes}"
+msgstr ""
+
+msgid "AdminUsers|The user can't access git repositories."
+msgstr ""
+
+msgid "AdminUsers|The user can't log in."
+msgstr ""
+
+msgid "AdminUsers|The user has unlimited access to all groups, projects, users, and features."
+msgstr ""
+
+msgid "AdminUsers|The user will be logged out"
+msgstr ""
+
+msgid "AdminUsers|The user will not be able to access git repositories"
+msgstr ""
+
+msgid "AdminUsers|The user will not be able to access the API"
+msgstr ""
+
+msgid "AdminUsers|The user will not be able to use slash commands"
+msgstr ""
+
+msgid "AdminUsers|The user will not receive any notifications"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{projectName}"
+msgstr ""
+
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
+
+msgid "AdminUsers|Unban user"
+msgstr ""
+
+msgid "AdminUsers|Unban user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Unblock"
+msgstr ""
+
+msgid "AdminUsers|Unblock user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|Unlock user %{username}?"
+msgstr ""
+
+msgid "AdminUsers|User administration"
+msgstr ""
+
+msgid "AdminUsers|User will not be able to access git repositories"
+msgstr ""
+
+msgid "AdminUsers|User will not be able to login"
+msgstr ""
+
+msgid "AdminUsers|Users"
+msgstr ""
+
+msgid "AdminUsers|Users can still be invited to your instance and/or add themselves if permitted based on your settings. They will not have access to your instance, nor count towards your subscribed seat count until you %{approve_link}."
+msgstr ""
+
+msgid "AdminUsers|Validate user account"
+msgstr ""
+
+msgid "AdminUsers|View pending member requests"
+msgstr ""
+
+msgid "AdminUsers|Website URL"
+msgstr ""
+
+msgid "AdminUsers|What can I do?"
+msgstr ""
+
+msgid "AdminUsers|What does this mean?"
+msgstr ""
+
+msgid "AdminUsers|When banned:"
+msgstr ""
+
+msgid "AdminUsers|When the user logs back in, their account will reactivate as a fully active account"
+msgstr ""
+
+msgid "AdminUsers|Will be deleted"
+msgstr ""
+
+msgid "AdminUsers|Without projects"
+msgstr ""
+
+msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgstr ""
+
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
+
+msgid "AdminUsers|You can always block their account again if needed."
+msgstr ""
+
+msgid "AdminUsers|You can always deactivate their account again if needed."
+msgstr ""
+
+msgid "AdminUsers|You can always re-activate their account, their data will remain intact."
+msgstr ""
+
+msgid "AdminUsers|You can always unblock their account, their data will remain intact."
+msgstr ""
+
+msgid "AdminUsers|You can ban their account in the future if necessary."
+msgstr ""
+
+msgid "AdminUsers|You can unban their account in the future. Their data remains intact."
+msgstr ""
+
+msgid "AdminUsers|You cannot remove your own administrator access."
+msgstr ""
+
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
+msgid "AdminUsers|Your GitLab instance has reached the maximum allowed %{user_doc_link} set by an instance admin."
+msgstr ""
+
+msgid "AdminUsers|approve them"
+msgstr ""
+
+msgid "AdminUsers|contact our support team"
+msgstr ""
+
+msgid "AdminUsers|docs"
+msgstr ""
+
+msgid "AdminUsers|user cap"
+msgstr ""
+
+msgid "Administrators"
+msgstr ""
+
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
+msgid "Admin|Abuse Reports"
+msgstr ""
+
+msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
+msgstr ""
+
+msgid "Admin|Admin Area"
+msgstr ""
+
+msgid "Admin|Admin notes"
+msgstr ""
+
+msgid "Admin|Analytics"
+msgstr ""
+
+msgid "Admin|Applications"
+msgstr ""
+
+msgid "Admin|CI/CD"
+msgstr ""
+
+msgid "Admin|Credentials"
+msgstr ""
+
+msgid "Admin|Deploy Keys"
+msgstr ""
+
+msgid "Admin|Geo"
+msgstr ""
+
+msgid "Admin|Kubernetes"
+msgstr ""
+
+msgid "Admin|Labels"
+msgstr ""
+
+msgid "Admin|Learn more about quarterly reconciliation"
+msgstr ""
+
+msgid "Admin|Messages"
+msgstr ""
+
+msgid "Admin|Monitoring"
+msgstr ""
+
+msgid "Admin|Note"
+msgstr ""
+
+msgid "Admin|Overview"
+msgstr ""
+
+msgid "Admin|Push Rules"
+msgstr ""
+
+msgid "Admin|Quarterly reconciliation will occur on %{qrtlyDate}"
+msgstr ""
+
+msgid "Admin|Settings"
+msgstr ""
+
+msgid "Admin|Spam Logs"
+msgstr ""
+
+msgid "Admin|Subscription"
+msgstr ""
+
+msgid "Admin|System Hooks"
+msgstr ""
+
+msgid "Admin|The number of max seats in your namespace exceeds the number of seats in your subscription. On %{qrtlyDate}, quarterly reconciliation occurs and you are automatically billed a prorated amount for the overage. No action is needed from you. If you have a credit card on file, it will be charged. Otherwise, you will receive an invoice. For more information about the timing of the invoicing process, view the documentation."
+msgstr ""
+
+msgid "Admin|The number of max users in your instance exceeds the number of users in your license. On %{qrtlyDate}, quarterly reconciliation occurs and you are automatically billed a prorated amount for the overage. No action is needed from you. If you have a credit card on file, it will be charged. Otherwise, you will receive an invoice. For more information about the timing of the invoicing process, view the documentation."
+msgstr ""
+
+msgid "Admin|View pending user approvals"
+msgstr ""
+
+msgid "Admin|Your instance has reached its user cap"
+msgstr ""
+
+msgid "Advanced"
+msgstr ""
+
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Settings"
+msgstr ""
+
+msgid "Advanced export options"
+msgstr ""
+
+msgid "AdvancedSearch|Could not fetch index entities. Please try again later."
+msgstr ""
+
+msgid "AdvancedSearch|Elasticsearch version not compatible"
+msgstr ""
+
+msgid "AdvancedSearch|Introduced in GitLab 13.1, before using %{reindexing_link_start}zero-downtime reindexing%{link_end} and %{migrations_link_start}Advanced Search migrations%{link_end}, you need to %{recreate_link_start}recreate your index%{link_end}."
+msgstr ""
+
+msgid "AdvancedSearch|None. Select namespaces to index."
+msgstr ""
+
+msgid "AdvancedSearch|None. Select projects to index."
+msgstr ""
+
+msgid "AdvancedSearch|Pause indexing and upgrade Elasticsearch to a supported version."
+msgstr ""
+
+msgid "AdvancedSearch|Reindex recommended"
+msgstr ""
+
+msgid "AdvancedSearch|Reindex required"
+msgstr ""
+
+msgid "AdvancedSearch|Select namespaces to index"
+msgstr ""
+
+msgid "AdvancedSearch|Select projects to index"
+msgstr ""
+
+msgid "AdvancedSearch|You are using outdated code search mappings. To improve code search quality, we recommend you use %{reindexing_link_start}zero-downtime reindexing%{link_end} or %{recreate_link_start}re-create your index%{link_end}."
+msgstr ""
+
+msgid "AdvancedSearch|You have %{count} pending %{migrations_link_start}advanced search migrations%{link_end} that are obsolete. These migrations might affect your search experience. To resolve the issue, you must %{recreate_link_start}recreate your index%{link_end}."
+msgstr ""
+
+msgid "AdvancedSearch|You have pending obsolete migrations"
+msgstr ""
+
+msgid "After a successful password update you will be redirected to login screen."
+msgstr ""
+
+msgid "After it is removed, the fork relationship can only be restored by using the API. This project will no longer be able to receive or send merge requests to the upstream project or other forks."
+msgstr ""
+
+msgid "After the Apple App Store Connect integration is activated, the following protected variables will be created for CI/CD use."
+msgstr ""
+
+msgid "After the export is complete, download the data file from a notification email or from this page. You can then import the data file from the %{strong_text_start}Create new group%{strong_text_end} page of another GitLab instance."
+msgstr ""
+
+msgid "After you enable the integration, the following protected variable is created for CI/CD use:"
+msgstr ""
+
+msgid "After you've reviewed these contribution guidelines, you'll be all set to"
+msgstr ""
+
+msgid "Akismet"
+msgstr ""
+
+msgid "Akismet API Key"
+msgstr ""
+
+msgid "Akismet helps prevent the creation of spam issues in public projects."
+msgstr ""
+
+msgid "Alert"
+msgstr ""
+
+msgid "AlertManagement|Acknowledged"
+msgstr ""
+
+msgid "AlertManagement|Activity feed"
+msgstr ""
+
+msgid "AlertManagement|Alert"
+msgstr ""
+
+msgid "AlertManagement|Alert assignees: %{assignees}"
+msgstr ""
+
+msgid "AlertManagement|Alert detail"
+msgstr ""
+
+msgid "AlertManagement|Alert details"
+msgstr ""
+
+msgid "AlertManagement|Alert status: %{status}"
+msgstr ""
+
+msgid "AlertManagement|Alerts"
+msgstr ""
+
+msgid "AlertManagement|All alerts"
+msgstr ""
+
+msgid "AlertManagement|Assign status"
+msgstr ""
+
+msgid "AlertManagement|Assignees"
+msgstr ""
+
+msgid "AlertManagement|Authorize external service"
+msgstr ""
+
+msgid "AlertManagement|Create incident"
+msgstr ""
+
+msgid "AlertManagement|Display alerts from all your monitoring tools directly within GitLab. Streamline the investigation of your alerts and the escalation of alerts to incidents."
+msgstr ""
+
+msgid "AlertManagement|Edit"
+msgstr ""
+
+msgid "AlertManagement|Environment"
+msgstr ""
+
+msgid "AlertManagement|Events"
+msgstr ""
+
+msgid "AlertManagement|Incident"
+msgstr ""
+
+msgid "AlertManagement|Key"
+msgstr ""
+
+msgid "AlertManagement|Metrics"
+msgstr ""
+
+msgid "AlertManagement|More information"
+msgstr ""
+
+msgid "AlertManagement|No alert data to display."
+msgstr ""
+
+msgid "AlertManagement|No alerts available to display. See %{linkStart}enabling alert management%{linkEnd} for more information on adding alerts to the list."
+msgstr ""
+
+msgid "AlertManagement|No alerts to display."
+msgstr ""
+
+msgid "AlertManagement|None"
+msgstr ""
+
+msgid "AlertManagement|Open"
+msgstr ""
+
+msgid "AlertManagement|Please try again."
+msgstr ""
+
+msgid "AlertManagement|Reported %{when}"
+msgstr ""
+
+msgid "AlertManagement|Reported %{when} by %{tool}"
+msgstr ""
+
+msgid "AlertManagement|Resolved"
+msgstr ""
+
+msgid "AlertManagement|Runbook"
+msgstr ""
+
+msgid "AlertManagement|Service"
+msgstr ""
+
+msgid "AlertManagement|Severity"
+msgstr ""
+
+msgid "AlertManagement|Start time"
+msgstr ""
+
+msgid "AlertManagement|Status"
+msgstr ""
+
+msgid "AlertManagement|Surface alerts in GitLab"
+msgstr ""
+
+msgid "AlertManagement|There was an error displaying the alert. Please refresh the page to try again."
+msgstr ""
+
+msgid "AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear."
+msgstr ""
+
+msgid "AlertManagement|There was an error while updating the assignees list. Please try again."
+msgstr ""
+
+msgid "AlertManagement|There was an error while updating the assignees of the alert. Please try again."
+msgstr ""
+
+msgid "AlertManagement|There was an error while updating the status of the alert."
+msgstr ""
+
+msgid "AlertManagement|There was an error while updating the to-do item of the alert."
+msgstr ""
+
+msgid "AlertManagement|This assignee cannot be assigned to this alert."
+msgstr ""
+
+msgid "AlertManagement|Tool"
+msgstr ""
+
+msgid "AlertManagement|Triggered"
+msgstr ""
+
+msgid "AlertManagement|Value"
+msgstr ""
+
+msgid "AlertManagement|View incident"
+msgstr ""
+
+msgid "AlertMappingBuilder|Define fallback"
+msgstr ""
+
+msgid "AlertMappingBuilder|GitLab alert key"
+msgstr ""
+
+msgid "AlertMappingBuilder|Make selection"
+msgstr ""
+
+msgid "AlertMappingBuilder|Payload alert key"
+msgstr ""
+
+msgid "AlertMappingBuilder|Select key"
+msgstr ""
+
+msgid "AlertMappingBuilder|Title is a required field for alerts in GitLab. Should the payload field you specified not be available, specifiy which field we should use instead. "
+msgstr ""
+
+msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
+msgstr ""
+
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
+msgid "AlertSettings|Add new integration"
+msgstr ""
+
+msgid "AlertSettings|Alert settings"
+msgstr ""
+
+msgid "AlertSettings|Authorization key"
+msgstr ""
+
+msgid "AlertSettings|Configure details"
+msgstr ""
+
+msgid "AlertSettings|Current integrations"
+msgstr ""
+
+msgid "AlertSettings|Customize alert payload mapping (optional)"
+msgstr ""
+
+msgid "AlertSettings|Delete integration"
+msgstr ""
+
+msgid "AlertSettings|Edit integration"
+msgstr ""
+
+msgid "AlertSettings|Edit payload"
+msgstr ""
+
+msgid "AlertSettings|Enable integration"
+msgstr ""
+
+msgid "AlertSettings|Enter an example payload from your selected monitoring tool. This supports sending alerts to a GitLab endpoint."
+msgstr ""
+
+msgid "AlertSettings|Enter integration name"
+msgstr ""
+
+msgid "AlertSettings|Free versions of GitLab are limited to one integration per type. To add more, %{linkStart}upgrade your subscription%{linkEnd}."
+msgstr ""
+
+msgid "AlertSettings|GitLab has created a URL and authorization key for your integration. You can use them to set up a webhook and authorize your endpoint to send alerts to GitLab."
+msgstr ""
+
+msgid "AlertSettings|HTTP Endpoint"
+msgstr ""
+
+msgid "AlertSettings|If you edit the payload, you must re-map the fields again."
+msgstr ""
+
+msgid "AlertSettings|If you reset the authorization key for this project, you must update the key in every enabled alert source."
+msgstr ""
+
+msgid "AlertSettings|Integration successfully saved"
+msgstr ""
+
+msgid "AlertSettings|Name integration"
+msgstr ""
+
+msgid "AlertSettings|Parse payload fields"
+msgstr ""
+
+msgid "AlertSettings|Proceed with editing"
+msgstr ""
+
+msgid "AlertSettings|Prometheus"
+msgstr ""
+
+msgid "AlertSettings|Reset Key"
+msgstr ""
+
+msgid "AlertSettings|Reset the mapping"
+msgstr ""
+
+msgid "AlertSettings|Sample payload has been parsed. You can now map the fields."
+msgstr ""
+
+msgid "AlertSettings|Save & create test alert"
+msgstr ""
+
+msgid "AlertSettings|Save integration"
+msgstr ""
+
+msgid "AlertSettings|Save integration & send"
+msgstr ""
+
+msgid "AlertSettings|Select integration type"
+msgstr ""
+
+msgid "AlertSettings|Send test alert"
+msgstr ""
+
+msgid "AlertSettings|Send without saving"
+msgstr ""
+
+msgid "AlertSettings|The form has unsaved changes"
+msgstr ""
+
+msgid "AlertSettings|The form has unsaved changes. How would you like to proceed?"
+msgstr ""
+
+msgid "AlertSettings|To create a custom mapping, enter an example payload from your monitoring tool, in JSON format. Select the \"Parse payload fields\" button to continue."
+msgstr ""
+
+msgid "AlertSettings|Use the URL and authorization key below to configure how Prometheus sends alerts to GitLab. Review the %{linkStart}GitLab documentation%{linkEnd} to learn how to configure your endpoint."
+msgstr ""
+
+msgid "AlertSettings|Use the URL and authorization key below to configure how an external service sends alerts to GitLab. %{linkStart}How do I configure the endpoint?%{linkEnd}"
+msgstr ""
+
+msgid "AlertSettings|View URL and authorization key"
+msgstr ""
+
+msgid "AlertSettings|View credentials"
+msgstr ""
+
+msgid "AlertSettings|Webhook URL"
+msgstr ""
+
+msgid "AlertSettings|You can map default GitLab alert fields to your payload keys in the dropdowns below."
+msgstr ""
+
+msgid "AlertSettings|{ \"events\": [{ \"application\": \"Name of application\" }] }"
+msgstr ""
+
+msgid "Alerts"
+msgstr ""
+
+msgid "AlertsIntegrations|Alerts will be created through this integration"
+msgstr ""
+
+msgid "AlertsIntegrations|Alerts will not be created through this integration"
+msgstr ""
+
+msgid "AlertsIntegrations|If you delete the %{integrationName} integration, alerts are no longer sent from this endpoint. This action cannot be undone."
+msgstr ""
+
+msgid "AlertsIntegrations|Integration Name"
+msgstr ""
+
+msgid "AlertsIntegrations|Integration payload is invalid."
+msgstr ""
+
+msgid "AlertsIntegrations|No integrations have been added yet."
+msgstr ""
+
+msgid "AlertsIntegrations|The current integration could not be updated. Please try again."
+msgstr ""
+
+msgid "AlertsIntegrations|The integration could not be added. Please try again."
+msgstr ""
+
+msgid "AlertsIntegrations|The integration could not be deleted. Please try again."
+msgstr ""
+
+msgid "AlertsIntegrations|The integration is currently inactive. Enable the integration to send the test alert."
+msgstr ""
+
+msgid "AlertsIntegrations|The integration is deleted."
+msgstr ""
+
+msgid "AlertsIntegrations|The integration is saved."
+msgstr ""
+
+msgid "AlertsIntegrations|The integration token could not be reset. Please try again."
+msgstr ""
+
+msgid "AlertsIntegrations|The test alert should now be visible in your alerts list."
+msgstr ""
+
+msgid "Algorithm"
+msgstr ""
+
+msgid "All"
+msgstr ""
+
+msgid "All %{replicableType} are being scheduled for %{action}"
+msgstr ""
+
+msgid "All (default)"
+msgstr ""
+
+msgid "All GitLab"
+msgstr ""
+
+msgid "All Members"
+msgstr ""
+
+msgid "All activity"
+msgstr ""
+
+msgid "All branch names must match %{link_start}this regular expression%{link_end}. If empty, any branch name is allowed."
+msgstr ""
+
+msgid "All branches"
+msgstr ""
+
+msgid "All changes are committed"
+msgstr ""
+
+msgid "All eligible users"
+msgstr ""
+
+msgid "All environments"
+msgstr ""
+
+msgid "All groups and projects"
+msgstr ""
+
+msgid "All issues"
+msgstr ""
+
+msgid "All issues for this milestone are closed."
+msgstr ""
+
+msgid "All issues for this milestone are closed. You may close this milestone now."
+msgstr ""
+
+msgid "All merge conflicts were resolved. The merge request can now be merged."
+msgstr ""
+
+msgid "All merge request dependencies have been merged"
+msgstr ""
+
+msgid "All paths are relative to the GitLab URL. Do not include %{relative_url_link_start}relative URLs%{relative_url_link_end}."
+msgstr ""
+
+msgid "All project members"
+msgstr ""
+
+msgid "All projects"
+msgstr ""
+
+msgid "All projects selected"
+msgstr ""
+
+msgid "All protected branches"
+msgstr ""
+
+msgid "All threads resolved!"
+msgstr ""
+
+msgid "All users in this group must set up two-factor authentication"
+msgstr ""
+
+msgid "All users must accept the Terms of Service and Privacy Policy to access GitLab"
+msgstr ""
+
+msgid "All users must have a name."
+msgstr ""
+
+msgid "All users with matching cards"
+msgstr ""
+
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
+
+msgid "Allow access to members of the following group"
+msgstr ""
+
+msgid "Allow access to the following IP addresses"
+msgstr ""
+
+msgid "Allow commits from members who can merge to the target branch. %{link_start}About this feature.%{link_end}"
+msgstr ""
+
+msgid "Allow group owners to manage LDAP-related settings"
+msgstr ""
+
+msgid "Allow job retries even if the deployment job is outdated."
+msgstr ""
+
+msgid "Allow job retries for rollback deployments"
+msgstr ""
+
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
+msgid "Allow non-administrators access to the performance bar"
+msgstr ""
+
+msgid "Allow only the selected protocols to be used for Git access."
+msgstr ""
+
+msgid "Allow owners to manage default branch protection per group."
+msgstr ""
+
+msgid "Allow owners to manually add users outside of LDAP"
+msgstr ""
+
+msgid "Allow password authentication for Git over HTTP(S)"
+msgstr ""
+
+msgid "Allow password authentication for the web interface"
+msgstr ""
+
+msgid "Allow possible spam"
+msgstr ""
+
+msgid "Allow project maintainers to configure repository mirroring"
+msgstr ""
+
+msgid "Allow projects and subgroups to override the group setting"
+msgstr ""
+
+msgid "Allow public access to pipelines and job details, including output logs and artifacts."
+msgstr ""
+
+msgid "Allow this key to push to this repository"
+msgstr ""
+
+msgid "Allow use of licensed EE features"
+msgstr ""
+
+msgid "Allow users to extend their session"
+msgstr ""
+
+msgid "Allow users to register any application to use GitLab as an OAuth provider"
+msgstr ""
+
+msgid "Allowed"
+msgstr ""
+
+msgid "Allowed email domain restriction only permitted for top-level groups"
+msgstr ""
+
+msgid "Allowed to create"
+msgstr ""
+
+msgid "Allowed to delete projects"
+msgstr ""
+
+msgid "Allowed to fail"
+msgstr ""
+
+msgid "Allows projects or subgroups in this group to override the global setting."
+msgstr ""
+
+msgid "Allows projects to track errors using an Opstrace integration."
+msgstr ""
+
+msgid "Allows you to add and manage Kubernetes clusters."
+msgstr ""
+
+msgid "Almost there"
+msgstr ""
+
+msgid "Almost there..."
+msgstr ""
+
+msgid "Already blocked"
+msgstr ""
+
+msgid "Already have an account?"
+msgstr ""
+
+msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
+msgstr ""
+
+msgid "Also called \"Relying party service URL\" or \"Reply URL\""
+msgstr ""
+
+msgid "Also remove direct user membership from subgroups and projects"
+msgstr ""
+
+msgid "Also unassign this user from related issues and merge requests"
+msgstr ""
+
+msgid "Alt text"
+msgstr ""
+
+msgid "Alternate support URL for Help page and Help dropdown."
+msgstr ""
+
+msgid "Alternatively, you can convert your account to a managed account by the %{group_name} group."
+msgstr ""
+
+msgid "Amazon EKS"
+msgstr ""
+
+msgid "Amazon EKS integration allows you to provision EKS clusters from GitLab."
+msgstr ""
+
+msgid "An %{link_start}alert%{link_end} with the same fingerprint is already open. To change the status of this alert, resolve the linked alert."
+msgstr ""
+
+msgid "An Administrator has set the maximum expiration date to %{maxDate}. %{helpLinkStart}Learn more%{helpLinkEnd}."
+msgstr ""
+
+msgid "An Enterprise User GitLab account has been created for you by your organization:"
+msgstr ""
+
+msgid "An administrator changed the password for your GitLab account on %{link_to}."
+msgstr ""
+
+msgid "An alert has been resolved in %{project_path}."
+msgstr ""
+
+msgid "An alert has been triggered in %{project_path}."
+msgstr ""
+
+msgid "An application called %{link_to_client} is requesting access to your GitLab account."
+msgstr ""
+
+msgid "An email notification was recently sent from the admin panel. Please wait %{wait_time_in_words} before attempting to send another message."
+msgstr ""
+
+msgid "An email will be sent with the report attached after it is generated."
+msgstr ""
+
+msgid "An empty GitLab User field will add the FogBugz user's full name (e.g. \"By John Smith\") in the description of all issues and comments. It will also associate and/or assign these issues and comments with the project creator."
+msgstr ""
+
+msgid "An error has occurred"
+msgstr ""
+
+msgid "An error in reporting in which a test result incorrectly indicates the presence of a vulnerability in a system when the vulnerability is not present."
+msgstr ""
+
+msgid "An error occurred creating the new branch."
+msgstr ""
+
+msgid "An error occurred fetching the approval rules."
+msgstr ""
+
+msgid "An error occurred fetching the approvers for the new rule."
+msgstr ""
+
+msgid "An error occurred fetching the dropdown data."
+msgstr ""
+
+msgid "An error occurred fetching the project authors."
+msgstr ""
+
+msgid "An error occurred fetching the public deploy keys. Please try again."
+msgstr ""
+
+msgid "An error occurred previewing the blob"
+msgstr ""
+
+msgid "An error occurred when updating the title"
+msgstr ""
+
+msgid "An error occurred while acknowledging the notification. Refresh the page and try again."
+msgstr ""
+
+msgid "An error occurred while adding approvers"
+msgstr ""
+
+msgid "An error occurred while adding formatted title for epic"
+msgstr ""
+
+msgid "An error occurred while approving, please try again."
+msgstr ""
+
+msgid "An error occurred while checking group path. Please refresh and try again."
+msgstr ""
+
+msgid "An error occurred while creating the issue. Please try again."
+msgstr ""
+
+msgid "An error occurred while decoding the file."
+msgstr ""
+
+msgid "An error occurred while deleting an issuable."
+msgstr ""
+
+msgid "An error occurred while deleting the approvers group"
+msgstr ""
+
+msgid "An error occurred while deleting the comment"
+msgstr ""
+
+msgid "An error occurred while deleting the pipeline."
+msgstr ""
+
+msgid "An error occurred while detecting host keys"
+msgstr ""
+
+msgid "An error occurred while disabling Service Desk."
+msgstr ""
+
+msgid "An error occurred while dismissing the alert. Refresh the page and try again."
+msgstr ""
+
+msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
+msgstr ""
+
+msgid "An error occurred while drawing job relationship links."
+msgstr ""
+
+msgid "An error occurred while enabling Service Desk."
+msgstr ""
+
+msgid "An error occurred while fetching Markdown preview"
+msgstr ""
+
+msgid "An error occurred while fetching ancestors"
+msgstr ""
+
+msgid "An error occurred while fetching branches. Retry the search."
+msgstr ""
+
+msgid "An error occurred while fetching codequality mr diff reports."
+msgstr ""
+
+msgid "An error occurred while fetching commit data."
+msgstr ""
+
+msgid "An error occurred while fetching commits. Retry the search."
+msgstr ""
+
+msgid "An error occurred while fetching coverage reports."
+msgstr ""
+
+msgid "An error occurred while fetching environments."
+msgstr ""
+
+msgid "An error occurred while fetching exposed artifacts."
+msgstr ""
+
+msgid "An error occurred while fetching folder content."
+msgstr ""
+
+msgid "An error occurred while fetching issues."
+msgstr ""
+
+msgid "An error occurred while fetching label colors."
+msgstr ""
+
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
+msgid "An error occurred while fetching participants"
+msgstr ""
+
+msgid "An error occurred while fetching participants."
+msgstr ""
+
+msgid "An error occurred while fetching pending comments"
+msgstr ""
+
+msgid "An error occurred while fetching reference"
+msgstr ""
+
+msgid "An error occurred while fetching reviewers."
+msgstr ""
+
+msgid "An error occurred while fetching tags. Retry the search."
+msgstr ""
+
+msgid "An error occurred while fetching terraform reports."
+msgstr ""
+
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
+msgid "An error occurred while fetching the job log."
+msgstr ""
+
+msgid "An error occurred while fetching the job logs."
+msgstr ""
+
+msgid "An error occurred while fetching the job."
+msgstr ""
+
+msgid "An error occurred while fetching the jobs."
+msgstr ""
+
+msgid "An error occurred while fetching the latest pipeline."
+msgstr ""
+
+msgid "An error occurred while fetching the pipelines jobs."
+msgstr ""
+
+msgid "An error occurred while fetching the releases. Please try again."
+msgstr ""
+
+msgid "An error occurred while fetching the template: %{err}"
+msgstr ""
+
+msgid "An error occurred while fetching this tab."
+msgstr ""
+
+msgid "An error occurred while getting files for - %{branchId}"
+msgstr ""
+
+msgid "An error occurred while getting issue counts"
+msgstr ""
+
+msgid "An error occurred while initializing path locks"
+msgstr ""
+
+msgid "An error occurred while loading a section of this page."
+msgstr ""
+
+msgid "An error occurred while loading all the files."
+msgstr ""
+
+msgid "An error occurred while loading chart data"
+msgstr ""
+
+msgid "An error occurred while loading commit signatures"
+msgstr ""
+
+msgid "An error occurred while loading designs. Please try again."
+msgstr ""
+
+msgid "An error occurred while loading diff"
+msgstr ""
+
+msgid "An error occurred while loading filenames"
+msgstr ""
+
+msgid "An error occurred while loading group members."
+msgstr ""
+
+msgid "An error occurred while loading issues"
+msgstr ""
+
+msgid "An error occurred while loading merge requests."
+msgstr ""
+
+msgid "An error occurred while loading projects."
+msgstr ""
+
+msgid "An error occurred while loading the blob controls."
+msgstr ""
+
+msgid "An error occurred while loading the file"
+msgstr ""
+
+msgid "An error occurred while loading the file content."
+msgstr ""
+
+msgid "An error occurred while loading the file."
+msgstr ""
+
+msgid "An error occurred while loading the file. Please try again later."
+msgstr ""
+
+msgid "An error occurred while loading the file. Please try again."
+msgstr ""
+
+msgid "An error occurred while loading the merge request changes."
+msgstr ""
+
+msgid "An error occurred while loading the merge request version data."
+msgstr ""
+
+msgid "An error occurred while loading the merge request."
+msgstr ""
+
+msgid "An error occurred while loading the notification settings. Please try again."
+msgstr ""
+
+msgid "An error occurred while loading the pipelines jobs."
+msgstr ""
+
+msgid "An error occurred while making the request."
+msgstr ""
+
+msgid "An error occurred while moving the issue."
+msgstr ""
+
+msgid "An error occurred while parsing recent searches"
+msgstr ""
+
+msgid "An error occurred while parsing the file."
+msgstr ""
+
+msgid "An error occurred while pasting text in the editor. Please try again."
+msgstr ""
+
+msgid "An error occurred while performing this action."
+msgstr ""
+
+msgid "An error occurred while removing epics."
+msgstr ""
+
+msgid "An error occurred while removing issues."
+msgstr ""
+
+msgid "An error occurred while rendering the editor"
+msgstr ""
+
+msgid "An error occurred while reordering issues."
+msgstr ""
+
+msgid "An error occurred while resetting the compute usage."
+msgstr ""
+
+msgid "An error occurred while retrieving calendar activity"
+msgstr ""
+
+msgid "An error occurred while retrieving diff"
+msgstr ""
+
+msgid "An error occurred while retrieving diff files"
+msgstr ""
+
+msgid "An error occurred while retrieving projects."
+msgstr ""
+
+msgid "An error occurred while retrieving your settings. Reload the page to try again."
+msgstr ""
+
+msgid "An error occurred while saving changes: %{error}"
+msgstr ""
+
+msgid "An error occurred while saving the setting"
+msgid_plural "An error occurred while saving the settings"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "An error occurred while saving your settings. Try saving them again."
+msgstr ""
+
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
+msgid "An error occurred while triggering the job."
+msgstr ""
+
+msgid "An error occurred while trying to follow this user, please try again."
+msgstr ""
+
+msgid "An error occurred while trying to render the content editor. Please try again."
+msgstr ""
+
+msgid "An error occurred while trying to run a new pipeline for this merge request."
+msgstr ""
+
+msgid "An error occurred while trying to unfollow this user, please try again."
+msgstr ""
+
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while updating approvers"
+msgstr ""
+
+msgid "An error occurred while updating assignees."
+msgstr ""
+
+msgid "An error occurred while updating configuration."
+msgstr ""
+
+msgid "An error occurred while updating labels."
+msgstr ""
+
+msgid "An error occurred while updating the configuration."
+msgstr ""
+
+msgid "An error occurred while updating the notification settings. Please try again."
+msgstr ""
+
+msgid "An error occurred while uploading the file. Please try again."
+msgstr ""
+
+msgid "An error occurred while validating group path"
+msgstr ""
+
+msgid "An error occurred while validating username"
+msgstr ""
+
+msgid "An error occurred. Please sign in again."
+msgstr ""
+
+msgid "An error occurred. Please try again."
+msgstr ""
+
+msgid "An error occurred. Unable to reopen this merge request."
+msgstr ""
+
+msgid "An example project for managing Kubernetes clusters integrated with GitLab"
+msgstr ""
+
+msgid "An example project that shows off the best practices for setting up GitLab for your own organization, including sample issues, merge requests, and milestones"
+msgstr ""
+
+msgid "An example showing how to use Jsonnet with GitLab dynamic child pipelines"
+msgstr ""
+
+msgid "An incident has been resolved in %{project_path}."
+msgstr ""
+
+msgid "An incident has been triggered in %{project_path}."
+msgstr ""
+
+msgid "An integer value is required for seconds"
+msgstr ""
+
+msgid "An issue already exists"
+msgstr ""
+
+msgid "An issue has been assigned to you."
+msgid_plural "%d issues have been assigned to you."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "An unauthenticated user"
+msgstr ""
+
+msgid "An unexpected error occurred"
+msgstr ""
+
+msgid "An unexpected error occurred while checking the project environment."
+msgstr ""
+
+msgid "An unexpected error occurred while checking the project runners."
+msgstr ""
+
+msgid "An unexpected error occurred while communicating with the Web Terminal."
+msgstr ""
+
+msgid "An unexpected error occurred while loading the Sast diff."
+msgstr ""
+
+msgid "An unexpected error occurred while loading the code quality diff."
+msgstr ""
+
+msgid "An unexpected error occurred while starting the Web Terminal."
+msgstr ""
+
+msgid "An unexpected error occurred while stopping the Web Terminal."
+msgstr ""
+
+msgid "An unexpected error occurred. Please try again."
+msgstr ""
+
+msgid "An unknown error occurred while loading this graph."
+msgstr ""
+
+msgid "An unknown error occurred."
+msgstr ""
+
+msgid "Analytics"
+msgstr ""
+
+msgid "Analytics dashboards"
+msgstr ""
+
+msgid "Analytics settings"
+msgstr ""
+
+msgid "Analytics|A visualization with that name already exists."
+msgstr ""
+
+msgid "Analytics|Add a visualization"
+msgstr ""
+
+msgid "Analytics|Add visualizations"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading data"
+msgstr ""
+
+msgid "Analytics|An error occurred while loading the %{visualizationTitle} visualization."
+msgstr ""
+
+msgid "Analytics|Analytics dashboards"
+msgstr ""
+
+msgid "Analytics|Analytics settings for '%{project_name}' were successfully updated."
+msgstr ""
+
+msgid "Analytics|Browser"
+msgstr ""
+
+msgid "Analytics|Browser Family"
+msgstr ""
+
+msgid "Analytics|By GitLab"
+msgstr ""
+
+msgid "Analytics|Cancel"
+msgstr ""
+
+msgid "Analytics|Choose a chart type on the right"
+msgstr ""
+
+msgid "Analytics|Choose a measurement to start"
+msgstr ""
+
+msgid "Analytics|Code"
+msgstr ""
+
+msgid "Analytics|Column Chart"
+msgstr ""
+
+msgid "Analytics|Configure Dashboard Project"
+msgstr ""
+
+msgid "Analytics|Create dashboard %{dashboardSlug}"
+msgstr ""
+
+msgid "Analytics|Create your dashboard"
+msgstr ""
+
+msgid "Analytics|Custom dashboards"
+msgstr ""
+
+msgid "Analytics|Dashboard not found"
+msgstr ""
+
+msgid "Analytics|Dashboard title"
+msgstr ""
+
+msgid "Analytics|Dashboard was saved successfully"
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the groups dashboard files."
+msgstr ""
+
+msgid "Analytics|Dashboards are created by editing the projects dashboard files."
+msgstr ""
+
+msgid "Analytics|Data"
+msgstr ""
+
+msgid "Analytics|Data Table"
+msgstr ""
+
+msgid "Analytics|Dates and times are displayed in the UTC timezone"
+msgstr ""
+
+msgid "Analytics|Edit"
+msgstr ""
+
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
+msgid "Analytics|Enter a visualization name"
+msgstr ""
+
+msgid "Analytics|Error while saving dashboard"
+msgstr ""
+
+msgid "Analytics|Error while saving visualization."
+msgstr ""
+
+msgid "Analytics|Failed to fetch data"
+msgstr ""
+
+msgid "Analytics|Host"
+msgstr ""
+
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
+msgid "Analytics|Language"
+msgstr ""
+
+msgid "Analytics|Line Chart"
+msgstr ""
+
+msgid "Analytics|New analytics visualization name"
+msgstr ""
+
+msgid "Analytics|New dashboard"
+msgstr ""
+
+msgid "Analytics|No dashboard matches the specified URL path."
+msgstr ""
+
+msgid "Analytics|No results match your query or filter."
+msgstr ""
+
+msgid "Analytics|OS"
+msgstr ""
+
+msgid "Analytics|OS Version"
+msgstr ""
+
+msgid "Analytics|Page Language"
+msgstr ""
+
+msgid "Analytics|Page Path"
+msgstr ""
+
+msgid "Analytics|Page Title"
+msgstr ""
+
+msgid "Analytics|Pages"
+msgstr ""
+
+msgid "Analytics|Referer"
+msgstr ""
+
+msgid "Analytics|Resulting Data"
+msgstr ""
+
+msgid "Analytics|Save and add to Dashboard"
+msgstr ""
+
+msgid "Analytics|Save new visualization"
+msgstr ""
+
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
+msgid "Analytics|Select a measurement"
+msgstr ""
+
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
+msgid "Analytics|Select a visualization type"
+msgstr ""
+
+msgid "Analytics|Single Statistic"
+msgstr ""
+
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
+msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
+msgid "Analytics|Something went wrong."
+msgstr ""
+
+msgid "Analytics|To create your own dashboards, first configure a project to store your dashboards."
+msgstr ""
+
+msgid "Analytics|URL"
+msgstr ""
+
+msgid "Analytics|Updating dashboard %{dashboardSlug}"
+msgstr ""
+
+msgid "Analytics|Updating visualization %{visualizationName}"
+msgstr ""
+
+msgid "Analytics|Users"
+msgstr ""
+
+msgid "Analytics|View available dashboards"
+msgstr ""
+
+msgid "Analytics|Viewport"
+msgstr ""
+
+msgid "Analytics|Visualization"
+msgstr ""
+
+msgid "Analytics|Visualization Designer"
+msgstr ""
+
+msgid "Analytics|Visualization Type"
+msgstr ""
+
+msgid "Analytics|Visualization designer"
+msgstr ""
+
+msgid "Analytics|Visualization was saved successfully"
+msgstr ""
+
+msgid "Analyze your dependencies for known vulnerabilities."
+msgstr ""
+
+msgid "Analyze your infrastructure as code configuration files for known vulnerabilities."
+msgstr ""
+
+msgid "Analyze your source code and git history for secrets."
+msgstr ""
+
+msgid "Analyze your source code for known vulnerabilities."
+msgstr ""
+
+msgid "Analyzing file…"
+msgstr ""
+
+msgid "Ancestors"
+msgstr ""
+
+msgid "And this registration token:"
+msgstr ""
+
+msgid "Anonymous"
+msgstr ""
+
+msgid "Anonymous user"
+msgstr ""
+
+msgid "Another issue tracker is already in use. Only one issue tracker service can be active at a time"
+msgstr ""
+
+msgid "Another open merge request already exists for this source branch: %{conflicting_mr_reference}"
+msgstr ""
+
+msgid "Another third-party wiki is already in use. Only one third-party wiki integration can be active at a time"
+msgstr ""
+
+msgid "Anti-spam verification"
+msgstr ""
+
+msgid "Any"
+msgstr ""
+
+msgid "Any %{header}"
+msgstr ""
+
+msgid "Any Author"
+msgstr ""
+
+msgid "Any Milestone"
+msgstr ""
+
+msgid "Any encrypted tokens"
+msgstr ""
+
+msgid "Any label"
+msgstr ""
+
+msgid "Any member with at least Developer permissions on the project."
+msgstr ""
+
+msgid "Any milestone"
+msgstr ""
+
+msgid "App ID"
+msgstr ""
+
+msgid "Appearance"
+msgstr ""
+
+msgid "Appearance was successfully created."
+msgstr ""
+
+msgid "Appearance was successfully updated."
+msgstr ""
+
+msgid "Append the comment with %{shrug}"
+msgstr ""
+
+msgid "Append the comment with %{tableflip}"
+msgstr ""
+
+msgid "AppleAppStore|Drag your Private Key file here or %{linkStart}click to upload%{linkEnd}."
+msgstr ""
+
+msgid "AppleAppStore|Drop your Private Key file to start the upload."
+msgstr ""
+
+msgid "AppleAppStore|Error: You are trying to upload something other than a Private Key file."
+msgstr ""
+
+msgid "AppleAppStore|Leave empty to use your current Private Key."
+msgstr ""
+
+msgid "AppleAppStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "AppleAppStore|Protected branches and tags only"
+msgstr ""
+
+msgid "AppleAppStore|The Apple App Store Connect Issuer ID."
+msgstr ""
+
+msgid "AppleAppStore|The Apple App Store Connect Key ID."
+msgstr ""
+
+msgid "AppleAppStore|The Apple App Store Connect Private Key (.p8)"
+msgstr ""
+
+msgid "AppleAppStore|Upload a new Apple App Store Connect Private Key (replace %{currentFileName})"
+msgstr ""
+
+msgid "AppleAppStore|Use GitLab to build and release an app in the Apple App Store."
+msgstr ""
+
+msgid "Application"
+msgstr ""
+
+msgid "Application ID"
+msgstr ""
+
+msgid "Application analytics"
+msgstr ""
+
+msgid "Application limits saved successfully"
+msgstr ""
+
+msgid "Application settings saved successfully"
+msgstr ""
+
+msgid "Application settings saved successfully."
+msgstr ""
+
+msgid "Application settings update failed"
+msgstr ""
+
+msgid "Application was successfully destroyed."
+msgstr ""
+
+msgid "Application was successfully updated."
+msgstr ""
+
+msgid "Application: %{name}"
+msgstr ""
+
+msgid "ApplicationSettings|A Metrics Dashboard menu item appears in the Monitoring section of the Admin Area."
+msgstr ""
+
+msgid "ApplicationSettings|Add a link to Grafana"
+msgstr ""
+
+msgid "ApplicationSettings|After sign-up text"
+msgstr ""
+
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgstr ""
+
+msgid "ApplicationSettings|Allowed domains for sign-ups"
+msgstr ""
+
+msgid "ApplicationSettings|Allows users to delete their own accounts"
+msgstr ""
+
+msgid "ApplicationSettings|Any user that visits %{host} and creates an account must be explicitly approved by an administrator before they can sign in. Only effective if sign-ups are enabled."
+msgstr ""
+
+msgid "ApplicationSettings|Any user that visits %{host} can create an account."
+msgstr ""
+
+msgid "ApplicationSettings|Approve %d user"
+msgid_plural "ApplicationSettings|Approve %d users"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ApplicationSettings|Approve users"
+msgstr ""
+
+msgid "ApplicationSettings|Approve users in the pending approval status?"
+msgstr ""
+
+msgid "ApplicationSettings|Approve users who are pending approval?"
+msgstr ""
+
+msgid "ApplicationSettings|By making this change, you will automatically approve %d user who is pending approval."
+msgid_plural "ApplicationSettings|By making this change, you will automatically approve %d users who are pending approval."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ApplicationSettings|By making this change, you will automatically approve all users who are pending approval."
+msgstr ""
+
+msgid "ApplicationSettings|Denied domains for sign-ups"
+msgstr ""
+
+msgid "ApplicationSettings|Denylist file"
+msgstr ""
+
+msgid "ApplicationSettings|Domain denylist"
+msgstr ""
+
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
+msgid "ApplicationSettings|Email restrictions"
+msgstr ""
+
+msgid "ApplicationSettings|Email restrictions for sign-ups"
+msgstr ""
+
+msgid "ApplicationSettings|Enable GitLab for Slack app"
+msgstr ""
+
+msgid "ApplicationSettings|Enable domain denylist for sign-ups"
+msgstr ""
+
+msgid "ApplicationSettings|Enable email restrictions for sign-ups"
+msgstr ""
+
+msgid "ApplicationSettings|Enter denylist manually"
+msgstr ""
+
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
+msgid "ApplicationSettings|Minimum password length (number of characters)"
+msgstr ""
+
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
+msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
+msgstr ""
+
+msgid "ApplicationSettings|Require admin approval for new sign-ups"
+msgstr ""
+
+msgid "ApplicationSettings|Require lowercase letters"
+msgstr ""
+
+msgid "ApplicationSettings|Require numbers"
+msgstr ""
+
+msgid "ApplicationSettings|Require symbols"
+msgstr ""
+
+msgid "ApplicationSettings|Require uppercase letters"
+msgstr ""
+
+msgid "ApplicationSettings|Restricts sign-ups for email addresses that match the given regex. %{linkStart}What is the supported syntax?%{linkEnd}"
+msgstr ""
+
+msgid "ApplicationSettings|Save changes"
+msgstr ""
+
+msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
+msgstr ""
+
+msgid "ApplicationSettings|Send a confirmation email during sign up. New users can log in immediately, but must confirm their email within three days."
+msgstr ""
+
+msgid "ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in."
+msgstr ""
+
+msgid "ApplicationSettings|Sign-up enabled"
+msgstr ""
+
+msgid "ApplicationSettings|Soft"
+msgstr ""
+
+msgid "ApplicationSettings|Text shown after a user signs up. Markdown enabled."
+msgstr ""
+
+msgid "ApplicationSettings|Upload denylist file"
+msgstr ""
+
+msgid "ApplicationSettings|User cap"
+msgstr ""
+
+msgid "ApplicationSettings|Users with e-mail addresses that match these domain(s) cannot sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
+msgstr ""
+
+msgid "ApplicationSettings|Users with e-mail addresses that match these domain(s) cannot sign up. Wildcards allowed. Use separate lines or commas for multiple entries."
+msgstr ""
+
+msgid "ApplicationSettings|When enabled, new passwords must contain at least one lowercase letter (a-z)."
+msgstr ""
+
+msgid "ApplicationSettings|When enabled, new passwords must contain at least one number (0-9)."
+msgstr ""
+
+msgid "ApplicationSettings|When enabled, new passwords must contain at least one symbol."
+msgstr ""
+
+msgid "ApplicationSettings|When enabled, new passwords must contain at least one uppercase letter (A-Z)."
+msgstr ""
+
+msgid "ApplicationSettings|domain.com"
+msgstr ""
+
+msgid "Applications"
+msgstr ""
+
+msgid "Applied"
+msgstr ""
+
+msgid "Apply"
+msgstr ""
+
+msgid "Apply %d suggestion"
+msgid_plural "Apply %d suggestions"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Apply a label"
+msgstr ""
+
+msgid "Apply a template"
+msgstr ""
+
+msgid "Apply suggestion"
+msgstr ""
+
+msgid "Apply template"
+msgstr ""
+
+msgid "Apply this approval rule to all branches or a specific protected branch."
+msgstr ""
+
+msgid "Applying"
+msgstr ""
+
+msgid "Applying a template will replace the existing issue description. Any changes you have made will be lost."
+msgstr ""
+
+msgid "Applying command"
+msgstr ""
+
+msgid "Applying command to %{commandDescription}"
+msgstr ""
+
+msgid "Applying multiple commands"
+msgstr ""
+
+msgid "Applying suggestion..."
+msgstr ""
+
+msgid "Applying suggestions..."
+msgstr ""
+
+msgid "Approval options"
+msgstr ""
+
+msgid "Approval rules"
+msgstr ""
+
+msgid "Approval rules reset to project defaults"
+msgstr ""
+
+msgid "Approval settings"
+msgstr ""
+
+msgid "ApprovalRuleRemove|%d member"
+msgid_plural "ApprovalRuleRemove|%d members"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ApprovalRuleRemove|You are about to remove the %{name} approver group which has %{strongStart}%{count} member%{strongEnd}. Approvals from this member are not revoked."
+msgid_plural "ApprovalRuleRemove|You are about to remove the %{name} approver group which has %{strongStart}%{count} members%{strongEnd}. Approvals from these members are not revoked."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ApprovalRuleSummary|%d member"
+msgid_plural "ApprovalRuleSummary|%d members"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ApprovalRuleSummary|%{count} approval required from %{membersCount}"
+msgid_plural "ApprovalRuleSummary|%{count} approvals required from %{membersCount}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ApprovalRule|A merge request author collaborating with a merge request approver"
+msgstr ""
+
+msgid "ApprovalRule|Add approvers"
+msgstr ""
+
+msgid "ApprovalRule|Any"
+msgstr ""
+
+msgid "ApprovalRule|Approval rules"
+msgstr ""
+
+msgid "ApprovalRule|Approvals required"
+msgstr ""
+
+msgid "ApprovalRule|Approver Type"
+msgstr ""
+
+msgid "ApprovalRule|Approvers"
+msgstr ""
+
+msgid "ApprovalRule|Confirmed"
+msgstr ""
+
+msgid "ApprovalRule|Dismissed"
+msgstr ""
+
+msgid "ApprovalRule|Examples: QA, Security."
+msgstr ""
+
+msgid "ApprovalRule|Greater than"
+msgstr ""
+
+msgid "ApprovalRule|Improve your organization's code review with required approvals."
+msgstr ""
+
+msgid "ApprovalRule|Increase quality and maintain standards."
+msgstr ""
+
+msgid "ApprovalRule|Learn more about merge request approval rules."
+msgstr ""
+
+msgid "ApprovalRule|Less than"
+msgstr ""
+
+msgid "ApprovalRule|More than"
+msgstr ""
+
+msgid "ApprovalRule|Name"
+msgstr ""
+
+msgid "ApprovalRule|Need triage"
+msgstr ""
+
+msgid "ApprovalRule|Needs triage"
+msgstr ""
+
+msgid "ApprovalRule|New"
+msgstr ""
+
+msgid "ApprovalRule|Previously existing"
+msgstr ""
+
+msgid "ApprovalRule|Reduce your time to merge."
+msgstr ""
+
+msgid "ApprovalRule|Resolved"
+msgstr ""
+
+msgid "ApprovalRule|Rule name"
+msgstr ""
+
+msgid "ApprovalRule|Search in"
+msgstr ""
+
+msgid "ApprovalRule|Search users or groups"
+msgstr ""
+
+msgid "ApprovalRule|Select eligible approvers by expertise or files changed."
+msgstr ""
+
+msgid "ApprovalRule|Target branch"
+msgstr ""
+
+msgid "ApprovalRule|Try for free"
+msgstr ""
+
+msgid "ApprovalRule|all groups"
+msgstr ""
+
+msgid "ApprovalRule|day(s)"
+msgstr ""
+
+msgid "ApprovalRule|month(s)"
+msgstr ""
+
+msgid "ApprovalRule|project groups"
+msgstr ""
+
+msgid "ApprovalRule|week(s)"
+msgstr ""
+
+msgid "ApprovalRule||year(s)"
+msgstr ""
+
+msgid "ApprovalSettings|Keep approvals"
+msgstr ""
+
+msgid "ApprovalSettings|Merge request approval settings have been updated."
+msgstr ""
+
+msgid "ApprovalSettings|Prevent approval by author"
+msgstr ""
+
+msgid "ApprovalSettings|Prevent approvals by users who add commits"
+msgstr ""
+
+msgid "ApprovalSettings|Prevent editing approval rules in merge requests"
+msgstr ""
+
+msgid "ApprovalSettings|Prevent editing approval rules in projects and merge requests"
+msgstr ""
+
+msgid "ApprovalSettings|Prevent editing approval rules in projects and merge requests."
+msgstr ""
+
+msgid "ApprovalSettings|Remove all approvals"
+msgstr ""
+
+msgid "ApprovalSettings|Remove approvals by Code Owners if their files changed"
+msgstr ""
+
+msgid "ApprovalSettings|Require user password to approve"
+msgstr ""
+
+msgid "ApprovalSettings|There was an error loading merge request approval settings."
+msgstr ""
+
+msgid "ApprovalSettings|There was an error updating merge request approval settings."
+msgstr ""
+
+msgid "ApprovalSettings|This setting is configured at the instance level and can only be changed by an administrator."
+msgstr ""
+
+msgid "ApprovalSettings|This setting is configured in %{groupName} and can only be changed in the group settings by an administrator or group owner."
+msgstr ""
+
+msgid "ApprovalSettings|When a commit is added:"
+msgstr ""
+
+msgid "Approvals"
+msgstr ""
+
+msgid "Approvals are optional."
+msgstr ""
+
+msgid "Approvals required"
+msgstr ""
+
+msgid "Approvals|%{count} of %{total}"
+msgstr ""
+
+msgid "Approvals|Action required"
+msgstr ""
+
+msgid "Approvals|Auto approved"
+msgstr ""
+
+msgid "Approvals|It looks like there was a conflict between the rules for approving this Merge Request and the users who were eligible to approve it. As a result, the system has automatically approved it to keep things moving."
+msgstr ""
+
+msgid "Approvals|Rule automatically approved"
+msgstr ""
+
+msgid "Approvals|Rule cannot be approved"
+msgstr ""
+
+msgid "Approvals|Section: %section"
+msgstr ""
+
+msgid "Approvals|The number of people who need to approve this is more than those who are allowed to. Please ask the project owner to update %{securityPolicy}."
+msgstr ""
+
+msgid "Approvals|Verify the number of %{linkStart}eligible security approvers%{linkEnd} matches the required approvers for the security policy."
+msgstr ""
+
+msgid "Approvals|Verify your %{eligibleApproverLinkStart}eligible approvers%{eligibleApproverLinkEnd} and %{approvalSettingsLinkStart}approval settings%{approvalSettingsLinkEnd} agree with each other."
+msgstr ""
+
+msgid "Approvals|Verify your %{linkStart}approval settings%{linkEnd} do not conflict with this rule."
+msgstr ""
+
+msgid "Approve"
+msgstr ""
+
+msgid "Approve All"
+msgstr ""
+
+msgid "Approve a merge request"
+msgstr ""
+
+msgid "Approve a pending member"
+msgid_plural "Approve %d pending members"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Approve merge request"
+msgstr ""
+
+msgid "Approve the current merge request."
+msgstr ""
+
+msgid "Approved"
+msgstr ""
+
+msgid "Approved members will use an additional seat in your subscription, which may override your user cap."
+msgid_plural "Approved members will use an additional %d seats in your subscription, which may override your user cap."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Approved members will use an additional seat in your subscription."
+msgid_plural "Approved members will use an additional %d seats in your subscription."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Approved the current merge request."
+msgstr ""
+
+msgid "Approved-By"
+msgstr ""
+
+msgid "Approver"
+msgstr ""
+
+msgid "Approvers"
+msgstr ""
+
+msgid "Approvers from private group(s) not shown"
+msgstr ""
+
+msgid "Apr"
+msgstr ""
+
+msgid "April"
+msgstr ""
+
+msgid "Architecture not found for OS"
+msgstr ""
+
+msgid "Archive"
+msgstr ""
+
+msgid "Archive jobs"
+msgstr ""
+
+msgid "Archive project"
+msgstr ""
+
+msgid "Archive test case"
+msgstr ""
+
+msgid "Archived"
+msgstr ""
+
+msgid "Archived (%{movedToStart}moved%{movedToEnd})"
+msgstr ""
+
+msgid "Archived in this version"
+msgstr ""
+
+msgid "Archived project! Repository and other project resources are read-only"
+msgstr ""
+
+msgid "Archived projects"
+msgstr ""
+
+msgid "Archiving the project makes it entirely read-only. It is hidden from the dashboard and doesn't display in searches. %{strong_start}The repository cannot be committed to, and no issues, comments, or other entities can be created.%{strong_end} %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Are you ABSOLUTELY SURE you wish to remove this group?"
+msgstr ""
+
+msgid "Are you absolutely sure?"
+msgstr ""
+
+msgid "Are you sure that you want to archive this project?"
+msgstr ""
+
+msgid "Are you sure that you want to destroy %{application}"
+msgstr ""
+
+msgid "Are you sure that you want to unarchive this project?"
+msgstr ""
+
+msgid "Are you sure you want to %{action} %{name}?"
+msgstr ""
+
+msgid "Are you sure you want to approve %{user}?"
+msgstr ""
+
+msgid "Are you sure you want to attempt to merge?"
+msgstr ""
+
+msgid "Are you sure you want to cancel editing this %{commentType}?"
+msgstr ""
+
+msgid "Are you sure you want to close this blocked issue?"
+msgstr ""
+
+msgid "Are you sure you want to delete %{name}?"
+msgstr ""
+
+msgid "Are you sure you want to delete %{name}? This action cannot be undone."
+msgstr ""
+
+msgid "Are you sure you want to delete this %{commentType}?"
+msgstr ""
+
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
+msgid "Are you sure you want to delete this comment?"
+msgstr ""
+
+msgid "Are you sure you want to delete this deploy key?"
+msgstr ""
+
+msgid "Are you sure you want to delete this device? This action cannot be undone."
+msgstr ""
+
+msgid "Are you sure you want to delete this label?"
+msgstr ""
+
+msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
+msgstr ""
+
+msgid "Are you sure you want to deploy this environment?"
+msgstr ""
+
+msgid "Are you sure you want to discard this comment?"
+msgstr ""
+
+msgid "Are you sure you want to discard your changes?"
+msgstr ""
+
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Are you sure you want to leave the Web IDE? All unsaved changes will be lost."
+msgstr ""
+
+msgid "Are you sure you want to lock %{path}?"
+msgstr ""
+
+msgid "Are you sure you want to lock this directory?"
+msgstr ""
+
+msgid "Are you sure you want to lose unsaved changes?"
+msgstr ""
+
+msgid "Are you sure you want to lose your issue information?"
+msgstr ""
+
+msgid "Are you sure you want to merge immediately?"
+msgstr ""
+
+msgid "Are you sure you want to re-deploy this environment?"
+msgstr ""
+
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
+msgid "Are you sure you want to remove %{email}?"
+msgstr ""
+
+msgid "Are you sure you want to remove %{group_name}?"
+msgstr ""
+
+msgid "Are you sure you want to remove %{topic_name}?"
+msgstr ""
+
+msgid "Are you sure you want to remove the attachment?"
+msgstr ""
+
+msgid "Are you sure you want to remove the license?"
+msgstr ""
+
+msgid "Are you sure you want to remove this deploy key? If anything is still using this key, it will stop working."
+msgstr ""
+
+msgid "Are you sure you want to remove this identity?"
+msgstr ""
+
+msgid "Are you sure you want to remove this list?"
+msgstr ""
+
+msgid "Are you sure you want to remove this nickname?"
+msgstr ""
+
+msgid "Are you sure you want to reset the error tracking access token?"
+msgstr ""
+
+msgid "Are you sure you want to reset the health check token?"
+msgstr ""
+
+msgid "Are you sure you want to reset the registration token?"
+msgstr ""
+
+msgid "Are you sure you want to retry this migration?"
+msgstr ""
+
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr ""
+
+msgid "Are you sure you want to revoke this SSH key?"
+msgstr ""
+
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
+
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
+msgid "Are you sure you want to revoke this project access token? This action cannot be undone."
+msgstr ""
+
+msgid "Are you sure you want to stop this environment?"
+msgstr ""
+
+msgid "Are you sure you want to unlock %{path_lock_path}?"
+msgstr ""
+
+msgid "Are you sure you want to unlock %{path}?"
+msgstr ""
+
+msgid "Are you sure you want to unlock this directory?"
+msgstr ""
+
+msgid "Are you sure you want to unsubscribe from the %{type}: %{link_to_noteable_text}?"
+msgstr ""
+
+msgid "Are you sure?"
+msgstr ""
+
+msgid "Are you sure? All commits that were signed with this GPG key will be unverified."
+msgstr ""
+
+msgid "Are you sure? Removing this GPG key does not affect already signed commits."
+msgstr ""
+
+msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
+msgstr ""
+
+msgid "Artifact"
+msgstr ""
+
+msgid "Artifact could not be deleted."
+msgstr ""
+
+msgid "Artifact was successfully deleted."
+msgstr ""
+
+msgid "Artifacts"
+msgstr ""
+
+msgid "Artifacts|%d selected artifact deleted"
+msgid_plural "Artifacts|%d selected artifacts deleted"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Artifacts|%{strongStart}%{count}%{strongEnd} artifact selected"
+msgid_plural "Artifacts|%{strongStart}%{count}%{strongEnd} artifacts selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while deleting. Some artifacts may not have been deleted."
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Clear selection"
+msgstr ""
+
+msgid "Artifacts|Delete %d artifact"
+msgid_plural "Artifacts|Delete %d artifacts"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Artifacts|Delete %d artifact?"
+msgid_plural "Artifacts|Delete %d artifacts?"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|Delete selected"
+msgstr ""
+
+msgid "Artifacts|Help us improve this page"
+msgstr ""
+
+msgid "Artifacts|Maximum selected artifacts limit reached"
+msgstr ""
+
+msgid "Artifacts|Something went wrong while deleting. Please refresh the page to try again."
+msgstr ""
+
+msgid "Artifacts|Take a quick survey"
+msgstr ""
+
+msgid "Artifacts|The selected artifact will be permanently deleted. Any reports generated from these artifacts will be empty."
+msgid_plural "Artifacts|The selected artifacts will be permanently deleted. Any reports generated from these artifacts will be empty."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
+msgid "Artifacts|We want you to be able to use this page to easily manage your CI/CD job artifacts. We are working to improve this experience and would appreciate any feedback you have about the improvements we are making."
+msgstr ""
+
+msgid "As this is a newly created account, to get started, click the link below to confirm your account."
+msgstr ""
+
+msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
+msgstr ""
+
+msgid "AsanaService|%{user} pushed to branch %{branch} of %{project_name} ( %{commit_url} ):"
+msgstr ""
+
+msgid "AsanaService|Add commit messages as comments to Asana tasks."
+msgstr ""
+
+msgid "AsanaService|Comma-separated list of branches to be automatically inspected. Leave blank to include all branches."
+msgstr ""
+
+msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
+msgstr ""
+
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
+msgid "Ask again later"
+msgstr ""
+
+msgid "Ask someone with write access to resolve it."
+msgstr ""
+
+msgid "Ask your group owner to set up a group runner."
+msgstr ""
+
+msgid "Assertion consumer service URL"
+msgstr ""
+
+msgid "Assets"
+msgstr ""
+
+msgid "Assets:"
+msgstr ""
+
+msgid "Assign"
+msgstr ""
+
+msgid "Assign Iteration"
+msgstr ""
+
+msgid "Assign To"
+msgstr ""
+
+msgid "Assign custom color like #FF0000"
+msgstr ""
+
+msgid "Assign labels"
+msgstr ""
+
+msgid "Assign reviewer"
+msgstr ""
+
+msgid "Assign reviewers"
+msgstr ""
+
+msgid "Assign severity"
+msgstr ""
+
+msgid "Assign some issues to this milestone."
+msgstr ""
+
+msgid "Assign to"
+msgstr ""
+
+msgid "Assign to commenting user"
+msgstr ""
+
+msgid "Assign to me"
+msgstr ""
+
+msgid "Assign yourself"
+msgstr ""
+
+msgid "Assigned"
+msgstr ""
+
+msgid "Assigned %{assignee_users_sentence}."
+msgstr ""
+
+msgid "Assigned %{reviewer_users_sentence} as %{reviewer_text}."
+msgstr ""
+
+msgid "Assigned Issues"
+msgstr ""
+
+msgid "Assigned merge requests"
+msgstr ""
+
+msgid "Assigned projects"
+msgstr ""
+
+msgid "Assigned to %{assigneeName}"
+msgstr ""
+
+msgid "Assigned to %{assignee_name}"
+msgstr ""
+
+msgid "Assigned to me"
+msgstr ""
+
+msgid "Assignee"
+msgid_plural "%d Assignees"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Assignee (optional)"
+msgstr ""
+
+msgid "Assignee has no permissions"
+msgstr ""
+
+msgid "Assignee lists not available with your current license"
+msgstr ""
+
+msgid "Assignees"
+msgstr ""
+
+msgid "Assignees & reviewers"
+msgstr ""
+
+msgid "Assigns %{assignee_users_sentence}."
+msgstr ""
+
+msgid "Assigns %{reviewer_users_sentence} as %{reviewer_text}."
+msgstr ""
+
+msgid "At least one approval from a code owner is required to change files matching the respective CODEOWNER rules."
+msgstr ""
+
+msgid "At least one field of %{one_of_required_fields} must be present"
+msgstr ""
+
+msgid "At least one of group_id or project_id must be specified"
+msgstr ""
+
+msgid "At least one of your Personal Access Tokens is expired. %{generate_new}"
+msgstr ""
+
+msgid "At least one of your Personal Access Tokens will expire soon. %{generate_new}"
+msgstr ""
+
+msgid "At risk"
+msgstr ""
+
+msgid "Attach a file or image"
+msgstr ""
+
+msgid "Attaching File - %{progress}"
+msgstr ""
+
+msgid "Attaching a file"
+msgid_plural "Attaching %d files"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Attaching the file failed."
+msgstr ""
+
+msgid "Attempted sign in to %{host} using an incorrect verification code"
+msgstr ""
+
+msgid "Audit Events"
+msgstr ""
+
+msgid "Audit events"
+msgstr ""
+
+msgid "AuditLogs|(removed)"
+msgstr ""
+
+msgid "AuditLogs|Action"
+msgstr ""
+
+msgid "AuditLogs|Author"
+msgstr ""
+
+msgid "AuditLogs|Date"
+msgstr ""
+
+msgid "AuditLogs|Failed to find %{type}. Please search for another %{type}."
+msgstr ""
+
+msgid "AuditLogs|Failed to find %{type}. Please try again."
+msgstr ""
+
+msgid "AuditLogs|Group Events"
+msgstr ""
+
+msgid "AuditLogs|IP Address"
+msgstr ""
+
+msgid "AuditLogs|Log"
+msgstr ""
+
+msgid "AuditLogs|Member Events"
+msgstr ""
+
+msgid "AuditLogs|No matching %{type} found."
+msgstr ""
+
+msgid "AuditLogs|Object"
+msgstr ""
+
+msgid "AuditLogs|Project Events"
+msgstr ""
+
+msgid "AuditLogs|Target"
+msgstr ""
+
+msgid "AuditLogs|This month"
+msgstr ""
+
+msgid "AuditLogs|User Events"
+msgstr ""
+
+msgid "AuditStreams|%d destination"
+msgid_plural "AuditStreams|%d destinations"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "AuditStreams|A header with this name already exists."
+msgstr ""
+
+msgid "AuditStreams|Active"
+msgstr ""
+
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
+msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
+msgstr ""
+
+msgid "AuditStreams|Add another custom header"
+msgstr ""
+
+msgid "AuditStreams|Add external stream destination"
+msgstr ""
+
+msgid "AuditStreams|Add header"
+msgstr ""
+
+msgid "AuditStreams|Add streaming destination"
+msgstr ""
+
+msgid "AuditStreams|An error occurred when creating external audit event stream destination. Please try it again."
+msgstr ""
+
+msgid "AuditStreams|An error occurred when deleting external audit event stream destination. Please try it again."
+msgstr ""
+
+msgid "AuditStreams|An error occurred when fetching external audit event streams. Please try it again"
+msgstr ""
+
+msgid "AuditStreams|An error occurred when updating external audit event stream destination. Please try it again."
+msgstr ""
+
+msgid "AuditStreams|Are you sure about deleting this destination?"
+msgstr ""
+
+msgid "AuditStreams|Cancel editing"
+msgstr ""
+
+msgid "AuditStreams|Client Email"
+msgstr ""
+
+msgid "AuditStreams|Custom HTTP headers (optional)"
+msgstr ""
+
+msgid "AuditStreams|Delete destination"
+msgstr ""
+
+msgid "AuditStreams|Deleting the streaming destination %{destination} will stop audit events being streamed"
+msgstr ""
+
+msgid "AuditStreams|Destination Name"
+msgstr ""
+
+msgid "AuditStreams|Destination URL"
+msgstr ""
+
+msgid "AuditStreams|Destination has filters applied. %{linkStart}What are filters?%{linkEnd}"
+msgstr ""
+
+msgid "AuditStreams|Destinations receive all audit event data"
+msgstr ""
+
+msgid "AuditStreams|Event filtering (optional)"
+msgstr ""
+
+msgid "AuditStreams|Filter by audit event type"
+msgstr ""
+
+msgid "AuditStreams|Google Cloud Logging"
+msgstr ""
+
+msgid "AuditStreams|HTTP endpoint"
+msgstr ""
+
+msgid "AuditStreams|Header"
+msgstr ""
+
+msgid "AuditStreams|Log ID"
+msgstr ""
+
+msgid "AuditStreams|Maximum of %{number} HTTP headers has been reached."
+msgstr ""
+
+msgid "AuditStreams|No header created yet."
+msgstr ""
+
+msgid "AuditStreams|Private key"
+msgstr ""
+
+msgid "AuditStreams|Project ID"
+msgstr ""
+
+msgid "AuditStreams|Remove custom header"
+msgstr ""
+
+msgid "AuditStreams|Save external stream destination"
+msgstr ""
+
+msgid "AuditStreams|Select events"
+msgstr ""
+
+msgid "AuditStreams|Setup streaming for audit events"
+msgstr ""
+
+msgid "AuditStreams|Stream added successfully"
+msgstr ""
+
+msgid "AuditStreams|Stream deleted successfully"
+msgstr ""
+
+msgid "AuditStreams|Stream updated successfully"
+msgstr ""
+
+msgid "AuditStreams|Streams"
+msgstr ""
+
+msgid "AuditStreams|This could include sensitive information. Make sure you trust the destination endpoint."
+msgstr ""
+
+msgid "AuditStreams|This is great for keeping everything one place."
+msgstr ""
+
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
+msgid "AuditStreams|Value"
+msgstr ""
+
+msgid "AuditStreams|Verification token"
+msgstr ""
+
+msgid "AuditStreams|audit-events"
+msgstr ""
+
+msgid "AuditStreams|ex: 1000"
+msgstr ""
+
+msgid "AuditStreams|ex: limitation"
+msgstr ""
+
+msgid "AuditStreams|filtered"
+msgstr ""
+
+msgid "AuditStreams|my-email@my-google-project.iam.gservice.account.com"
+msgstr ""
+
+msgid "AuditStreams|my-google-project"
+msgstr ""
+
+msgid "Aug"
+msgstr ""
+
+msgid "August"
+msgstr ""
+
+msgid "Authenticate"
+msgstr ""
+
+msgid "Authenticate user SSH keys without requiring additional configuration. Performance of GitLab can be improved by using the GitLab database instead. %{link_start}How do I configure authentication using the GitLab database? %{link_end}"
+msgstr ""
+
+msgid "Authenticate with GitHub"
+msgstr ""
+
+msgid "Authenticated API rate limit period in seconds"
+msgstr ""
+
+msgid "Authenticated API requests"
+msgstr ""
+
+msgid "Authenticated Git LFS rate limit period in seconds"
+msgstr ""
+
+msgid "Authenticated Git LFS request rate limit"
+msgstr ""
+
+msgid "Authenticated Git LFS requests"
+msgstr ""
+
+msgid "Authenticated web rate limit period in seconds"
+msgstr ""
+
+msgid "Authenticated web requests"
+msgstr ""
+
+msgid "Authentication"
+msgstr ""
+
+msgid "Authentication Failure"
+msgstr ""
+
+msgid "Authentication Log"
+msgstr ""
+
+msgid "Authentication error: enable 2FA in your profile settings to continue using GitLab: %{mfa_help_page}"
+msgstr ""
+
+msgid "Authentication failed: %{error_message}"
+msgstr ""
+
+msgid "Authentication log"
+msgstr ""
+
+msgid "Authentication method"
+msgstr ""
+
+msgid "Authentication method updated"
+msgstr ""
+
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
+msgid "Author"
+msgstr ""
+
+msgid "Author: %{author_name}"
+msgstr ""
+
+msgid "Authored %{timeago}"
+msgstr ""
+
+msgid "Authored %{timeago} by %{author}"
+msgstr ""
+
+msgid "Authorization code:"
+msgstr ""
+
+msgid "Authorization token duration (minutes)"
+msgstr ""
+
+msgid "Authorization was granted by entering your username and password in the application."
+msgstr ""
+
+msgid "Authorize"
+msgstr ""
+
+msgid "Authorize %{link_to_client} to use your account?"
+msgstr ""
+
+msgid "Authorized %{new_chat_name}"
+msgstr ""
+
+msgid "Authorized At"
+msgstr ""
+
+msgid "Authorized applications"
+msgstr ""
+
+msgid "AuthorizedApplication|Application secret was successfully renewed."
+msgstr ""
+
+msgid "AuthorizedApplication|Are you sure you want to renew this secret? Any applications using the old secret will no longer be able to authenticate with GitLab."
+msgstr ""
+
+msgid "AuthorizedApplication|Are you sure you want to revoke this application?"
+msgstr ""
+
+msgid "AuthorizedApplication|Renew secret"
+msgstr ""
+
+msgid "AuthorizedApplication|Renew secret?"
+msgstr ""
+
+msgid "AuthorizedApplication|Revoke application"
+msgstr ""
+
+msgid "AuthorizedApplication|There was an error trying to renew the application secret. Please try again."
+msgstr ""
+
+msgid "Authors: %{authors}"
+msgstr ""
+
+msgid "Auto DevOps"
+msgstr ""
+
+msgid "Auto DevOps enabled"
+msgstr ""
+
+msgid "Auto stop successfully canceled."
+msgstr ""
+
+msgid "Auto-cancel redundant pipelines"
+msgstr ""
+
+msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
+msgstr ""
+
+msgid "AutoDevOps|Auto DevOps"
+msgstr ""
+
+msgid "AutoDevOps|Auto DevOps documentation"
+msgstr ""
+
+msgid "AutoDevOps|Dismiss Auto DevOps box"
+msgstr ""
+
+msgid "AutoDevOps|Enable in settings"
+msgstr ""
+
+msgid "AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
+msgstr ""
+
+msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
+msgstr ""
+
+msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found."
+msgstr ""
+
+msgid "AutoDevopsAlert|Security testing tools enabled with %{linkStart}Auto DevOps%{linkEnd}"
+msgstr ""
+
+msgid "AutoRemediation| 1 Merge Request"
+msgstr ""
+
+msgid "AutoRemediation|%{mrsCount} ready for review"
+msgstr ""
+
+msgid "AutoRemediation|Auto-fix"
+msgstr ""
+
+msgid "AutoRemediation|Auto-fix solutions"
+msgstr ""
+
+msgid "AutoRemediation|If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities."
+msgstr ""
+
+msgid "AutoRemediation|Introducing GitLab auto-fix"
+msgstr ""
+
+msgid "AutoRollback|Automatic rollbacks start when a critical alert is triggered. If the last successful deployment fails to roll back automatically, it can still be done manually."
+msgstr ""
+
+msgid "AutoRollback|Automatically roll back to the last successful deployment when a critical problem is detected."
+msgstr ""
+
+msgid "AutoRollback|Enable automatic rollbacks"
+msgstr ""
+
+msgid "Autocomplete"
+msgstr ""
+
+msgid "Autocomplete description"
+msgstr ""
+
+msgid "Autocomplete hint"
+msgstr ""
+
+msgid "Autocomplete usage hint"
+msgstr ""
+
+msgid "Automatic certificate management using %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}"
+msgstr ""
+
+msgid "Automatic certificate management using Let's Encrypt"
+msgstr ""
+
+msgid "Automatic deployment rollbacks"
+msgstr ""
+
+msgid "Automatic event tracking provides a traceable history for audits."
+msgstr ""
+
+msgid "Automatically close associated incident when a recovery alert notification resolves an alert"
+msgstr ""
+
+msgid "Automatically resolved"
+msgstr ""
+
+msgid "Automatically update this project's branches and tags from the upstream repository."
+msgstr ""
+
+msgid "Automation"
+msgstr ""
+
+msgid "Automation|Automation App"
+msgstr ""
+
+msgid "Autosave|Note"
+msgstr ""
+
+msgid "Available"
+msgstr ""
+
+msgid "Available ID"
+msgstr ""
+
+msgid "Available group runners: %{runners}"
+msgstr ""
+
+msgid "Available on demand"
+msgstr ""
+
+msgid "Avatar for %{assigneeName}"
+msgstr ""
+
+msgid "Avatar will be removed. Are you sure?"
+msgstr ""
+
+msgid "Average per day: %{average}"
+msgstr ""
+
+msgid "Awaiting user signup"
+msgstr ""
+
+msgid "AwardEmoji|No emoji found."
+msgstr ""
+
+msgid "Back"
+msgstr ""
+
+msgid "Back to page %{number}"
+msgstr ""
+
+msgid "Background Color"
+msgstr ""
+
+msgid "Background Jobs"
+msgstr ""
+
+msgid "Background Migrations"
+msgstr ""
+
+msgid "Background color"
+msgstr ""
+
+msgid "BackgroundMigrations|Background Migrations"
+msgstr ""
+
+msgid "BackgroundMigrations|Background migrations are used to perform data migrations whenever a migration exceeds the time limits in our guidelines. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "BackgroundMigrations|Batch size"
+msgstr ""
+
+msgid "BackgroundMigrations|Database"
+msgstr ""
+
+msgid "BackgroundMigrations|Failed jobs:"
+msgstr ""
+
+msgid "BackgroundMigrations|Finished at"
+msgstr ""
+
+msgid "BackgroundMigrations|Started at"
+msgstr ""
+
+msgid "Badge"
+msgstr ""
+
+msgid "Badges"
+msgstr ""
+
+msgid "Badges|Add badge"
+msgstr ""
+
+msgid "Badges|Add new badge"
+msgstr ""
+
+msgid "Badges|Adding the badge failed, please check the entered URLs and try again."
+msgstr ""
+
+msgid "Badges|Badge image URL"
+msgstr ""
+
+msgid "Badges|Badge image preview"
+msgstr ""
+
+msgid "Badges|Badge saved."
+msgstr ""
+
+msgid "Badges|Delete badge?"
+msgstr ""
+
+msgid "Badges|Deleting the badge failed, please try again."
+msgstr ""
+
+msgid "Badges|Edit badge"
+msgstr ""
+
+msgid "Badges|Enter a valid URL"
+msgstr ""
+
+msgid "Badges|Example: %{exampleUrl}"
+msgstr ""
+
+msgid "Badges|Group Badge"
+msgstr ""
+
+msgid "Badges|Link"
+msgstr ""
+
+msgid "Badges|Name"
+msgstr ""
+
+msgid "Badges|New badge added."
+msgstr ""
+
+msgid "Badges|No badge image"
+msgstr ""
+
+msgid "Badges|No image to preview"
+msgstr ""
+
+msgid "Badges|Project Badge"
+msgstr ""
+
+msgid "Badges|Reload badge image"
+msgstr ""
+
+msgid "Badges|Save changes"
+msgstr ""
+
+msgid "Badges|Saving the badge failed, please check the entered URLs and try again."
+msgstr ""
+
+msgid "Badges|Supported %{docsLinkStart}variables%{docsLinkEnd}: %{placeholders}"
+msgstr ""
+
+msgid "Badges|The badge was deleted."
+msgstr ""
+
+msgid "Badges|This group has no badges, start by creating a new one above."
+msgstr ""
+
+msgid "Badges|This project has no badges, start by creating a new one above."
+msgstr ""
+
+msgid "Badges|You are going to delete this badge. Deleted badges %{strongStart}cannot%{strongEnd} be restored."
+msgstr ""
+
+msgid "Badges|Your badges"
+msgstr ""
+
+msgid "BambooService|Atlassian Bamboo"
+msgstr ""
+
+msgid "BambooService|Bamboo URL"
+msgstr ""
+
+msgid "BambooService|Bamboo build plan key."
+msgstr ""
+
+msgid "BambooService|Bamboo service root URL."
+msgstr ""
+
+msgid "BambooService|Enter new build key"
+msgstr ""
+
+msgid "BambooService|Leave blank to use your current build key."
+msgstr ""
+
+msgid "BambooService|Run CI/CD pipelines with Atlassian Bamboo."
+msgstr ""
+
+msgid "BambooService|Run CI/CD pipelines with Atlassian Bamboo. You must set up automatic revision labeling and a repository trigger in Bamboo. %{docs_link}"
+msgstr ""
+
+msgid "BambooService|The user with API access to the Bamboo server."
+msgstr ""
+
+msgid "Banned"
+msgstr ""
+
+msgid "Banner message"
+msgstr ""
+
+msgid "Based on"
+msgstr ""
+
+msgid "Batch size"
+msgstr ""
+
+msgid "Batched Job|Background Migrations"
+msgstr ""
+
+msgid "Batched Job|Batched Job (Id: %{id})"
+msgstr ""
+
+msgid "BatchedJob|Attempts"
+msgstr ""
+
+msgid "BatchedJob|Batch size"
+msgstr ""
+
+msgid "BatchedJob|Batched Jobs"
+msgstr ""
+
+msgid "BatchedJob|Created At"
+msgstr ""
+
+msgid "BatchedJob|Created at"
+msgstr ""
+
+msgid "BatchedJob|Exception Class"
+msgstr ""
+
+msgid "BatchedJob|Exception Message"
+msgstr ""
+
+msgid "BatchedJob|Exception class"
+msgstr ""
+
+msgid "BatchedJob|Exception message"
+msgstr ""
+
+msgid "BatchedJob|Finished at"
+msgstr ""
+
+msgid "BatchedJob|Max Value"
+msgstr ""
+
+msgid "BatchedJob|Max value"
+msgstr ""
+
+msgid "BatchedJob|Min Value"
+msgstr ""
+
+msgid "BatchedJob|Min value"
+msgstr ""
+
+msgid "BatchedJob|Next Status"
+msgstr ""
+
+msgid "BatchedJob|Next status"
+msgstr ""
+
+msgid "BatchedJob|Pause ms"
+msgstr ""
+
+msgid "BatchedJob|Pause time (ms)"
+msgstr ""
+
+msgid "BatchedJob|Previous Status"
+msgstr ""
+
+msgid "BatchedJob|Previous status"
+msgstr ""
+
+msgid "BatchedJob|Started at"
+msgstr ""
+
+msgid "BatchedJob|Transition logs:"
+msgstr ""
+
+msgid "Be careful. Changing the project's namespace can have unintended side effects."
+msgstr ""
+
+msgid "Be careful. Renaming a project's repository can have unintended side effects."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
+msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
+msgstr ""
+
+msgid "Before inserting code, be sure to read the comment that separated each code group."
+msgstr ""
+
+msgid "Before this can be merged, a Jira issue must be linked in the title or description"
+msgstr ""
+
+msgid "Begin with the selected commit"
+msgstr ""
+
+msgid "Below are the fingerprints for the current instance SSH host keys."
+msgstr ""
+
+msgid "Below are the settings for %{link_to_gitlab_pages}."
+msgstr ""
+
+msgid "Below you will find all the groups that are public."
+msgstr ""
+
+msgid "Beta"
+msgstr ""
+
+msgid "BetaBadge|A Beta feature is not production-ready, but is unlikely to change drastically before it's released. We encourage users to try Beta features and provide feedback."
+msgstr ""
+
+msgid "BetaBadge|A Beta feature:"
+msgstr ""
+
+msgid "BetaBadge|Beta"
+msgstr ""
+
+msgid "BetaBadge|Is complete or near completion."
+msgstr ""
+
+msgid "BetaBadge|Is supported by a commercially reasonable effort."
+msgstr ""
+
+msgid "BetaBadge|May be unstable."
+msgstr ""
+
+msgid "BetaBadge|Should not cause data loss."
+msgstr ""
+
+msgid "BetaBadge|What's Beta?"
+msgstr ""
+
+msgid "Bi-weekly code coverage"
+msgstr ""
+
+msgid "Billable Users"
+msgstr ""
+
+msgid "Billing"
+msgstr ""
+
+msgid "BillingPlans|%{group_name} is currently using the %{plan_name}"
+msgstr ""
+
+msgid "BillingPlans|10,000 compute minutes per month"
+msgstr ""
+
+msgid "BillingPlans|10000 compute minutes"
+msgstr ""
+
+msgid "BillingPlans|10GB transfer per month"
+msgstr ""
+
+msgid "BillingPlans|400 compute minutes"
+msgstr ""
+
+msgid "BillingPlans|400 compute minutes per month"
+msgstr ""
+
+msgid "BillingPlans|5 users per namespace"
+msgstr ""
+
+msgid "BillingPlans|50,000 compute minutes per month"
+msgstr ""
+
+msgid "BillingPlans|50000 compute minutes"
+msgstr ""
+
+msgid "BillingPlans|5GB storage"
+msgstr ""
+
+msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name}."
+msgstr ""
+
+msgid "BillingPlans|Advanced CI/CD"
+msgstr ""
+
+msgid "BillingPlans|Advanced application security"
+msgstr ""
+
+msgid "BillingPlans|All plans have unlimited (private) repositories."
+msgstr ""
+
+msgid "BillingPlans|All stages of the DevOps lifecycle"
+msgstr ""
+
+msgid "BillingPlans|All the benefits of Free +"
+msgstr ""
+
+msgid "BillingPlans|All the benefits of Premium +"
+msgstr ""
+
+msgid "BillingPlans|All the features from Free"
+msgstr ""
+
+msgid "BillingPlans|All the features from Premium"
+msgstr ""
+
+msgid "BillingPlans|Billed annually at %{price_per_year} USD"
+msgstr ""
+
+msgid "BillingPlans|Bring your own CI runners"
+msgstr ""
+
+msgid "BillingPlans|Bring your own production environment"
+msgstr ""
+
+msgid "BillingPlans|Check out all groups"
+msgstr ""
+
+msgid "BillingPlans|Company wide portfolio management"
+msgstr ""
+
+msgid "BillingPlans|Compliance"
+msgstr ""
+
+msgid "BillingPlans|Compliance automation"
+msgstr ""
+
+msgid "BillingPlans|Congratulations, your free trial is activated."
+msgstr ""
+
+msgid "BillingPlans|Cross-team project management"
+msgstr ""
+
+msgid "BillingPlans|End of availability for the Bronze Plan"
+msgstr ""
+
+msgid "BillingPlans|Enhance team productivity and collaboration"
+msgstr ""
+
+msgid "BillingPlans|Enterprise agile planning"
+msgstr ""
+
+msgid "BillingPlans|Executive level insights"
+msgstr ""
+
+msgid "BillingPlans|Faster code reviews"
+msgstr ""
+
+msgid "BillingPlans|Free"
+msgstr ""
+
+msgid "BillingPlans|Free forever features for individual users"
+msgstr ""
+
+msgid "BillingPlans|Free guest users"
+msgstr ""
+
+msgid "BillingPlans|Free upgrade!"
+msgstr ""
+
+msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
+msgstr ""
+
+msgid "BillingPlans|Includes"
+msgstr ""
+
+msgid "BillingPlans|Includes free static websites"
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}, or start a free 30-day trial of GitLab.com Ultimate."
+msgstr ""
+
+msgid "BillingPlans|Learn more about each plan by visiting our %{pricing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Looking to purchase or manage a subscription for your group? Navigate to your %{groups_link} and go to %{strong_open}Settings &gt; Billing.%{strong_close}"
+msgstr ""
+
+msgid "BillingPlans|Loved and trusted by our customers"
+msgstr ""
+
+msgid "BillingPlans|Manage plan"
+msgstr ""
+
+msgid "BillingPlans|Multi-region support"
+msgstr ""
+
+msgid "BillingPlans|Multiple approval rules"
+msgstr ""
+
+msgid "BillingPlans|Not the group you're looking for? %{all_groups_link}."
+msgstr ""
+
+msgid "BillingPlans|Open Source - MIT License"
+msgstr ""
+
+msgid "BillingPlans|Organization wide security, compliance and planning"
+msgstr ""
+
+msgid "BillingPlans|Portfolio management"
+msgstr ""
+
+msgid "BillingPlans|Premium"
+msgstr ""
+
+msgid "BillingPlans|Pricing page"
+msgstr ""
+
+msgid "BillingPlans|Priority support"
+msgstr ""
+
+msgid "BillingPlans|Ready to explore the value of the paid features today? Start a trial, no credit card required."
+msgstr ""
+
+msgid "BillingPlans|Recommended"
+msgstr ""
+
+msgid "BillingPlans|Release controls"
+msgstr ""
+
+msgid "BillingPlans|Security risk mitigation"
+msgstr ""
+
+msgid "BillingPlans|See all %{plan_name} features"
+msgstr ""
+
+msgid "BillingPlans|Self-managed reliability"
+msgstr ""
+
+msgid "BillingPlans|Spans the DevOps lifecycle"
+msgstr ""
+
+msgid "BillingPlans|Start a free Ultimate trial"
+msgstr ""
+
+msgid "BillingPlans|Still have questions?"
+msgstr ""
+
+msgid "BillingPlans|Support"
+msgstr ""
+
+msgid "BillingPlans|Talk to an expert today."
+msgstr ""
+
+msgid "BillingPlans|Then %{move_link_start}move any projects%{move_link_end} you wish to use with your subscription to that group."
+msgstr ""
+
+msgid "BillingPlans|This group uses the plan associated with its parent group."
+msgstr ""
+
+msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
+msgstr ""
+
+msgid "BillingPlans|Ultimate"
+msgstr ""
+
+msgid "BillingPlans|Upgrade"
+msgstr ""
+
+msgid "BillingPlans|Upgrade to Premium"
+msgstr ""
+
+msgid "BillingPlans|Upgrade to Ultimate"
+msgstr ""
+
+msgid "BillingPlans|Value stream management"
+msgstr ""
+
+msgid "BillingPlans|We're here to help."
+msgstr ""
+
+msgid "BillingPlans|While GitLab is ending availability of the Bronze plan, you can still renew your Bronze subscription one additional time before %{eoa_bronze_plan_end_date}. We are also offering a limited time free upgrade to our Premium Plan (up to 25 users)! Learn more about the changes and offers in our %{announcement_link}."
+msgstr ""
+
+msgid "BillingPlans|You don't have any groups. You'll need to %{create_group_link_start}create one%{create_group_link_end} and %{move_link_start}move your projects to it%{move_link_end}."
+msgstr ""
+
+msgid "BillingPlans|Your GitLab.com %{plan} trial will %{strong_open}expire after %{expiration_date}%{strong_close}. You can retain access to the %{plan} features by upgrading below."
+msgstr ""
+
+msgid "BillingPlans|Your GitLab.com trial expired on %{expiration_date}. You can restore access to the features at any time by upgrading below."
+msgstr ""
+
+msgid "BillingPlans|Your current plan"
+msgstr ""
+
+msgid "BillingPlans|billed annually at %{price_per_year}"
+msgstr ""
+
+msgid "BillingPlans|for the remainder of your subscription"
+msgstr ""
+
+msgid "BillingPlans|frequently asked questions"
+msgstr ""
+
+msgid "BillingPlans|group"
+msgstr ""
+
+msgid "BillingPlans|monthly"
+msgstr ""
+
+msgid "BillingPlans|per user"
+msgstr ""
+
+msgid "BillingPlans|per user/month"
+msgstr ""
+
+msgid "BillingPlan|Upgrade"
+msgstr ""
+
+msgid "BillingPlan|Upgrade for free"
+msgstr ""
+
+msgid "Billings|Error validating card details"
+msgstr ""
+
+msgid "Billings|Free groups are limited to %{number} seats."
+msgstr ""
+
+msgid "Billings|Free seats used"
+msgstr ""
+
+msgid "Billings|Free tier and trial groups can invite a maximum of 20 members per day."
+msgstr ""
+
+msgid "Billings|In a seat"
+msgstr ""
+
+msgid "Billings|Seats in use / Seats available"
+msgstr ""
+
+msgid "Billings|Seats in use / Seats in subscription"
+msgstr ""
+
+msgid "Billings|Shared runners cannot be enabled until a valid credit card is on file."
+msgstr ""
+
+msgid "Billings|To use free compute minutes on shared runners, you'll need to validate your account with a credit card. If you prefer not to provide one, you can run pipelines by bringing your own runners and disabling shared runners for your project. This is required to discourage and reduce abuse on GitLab infrastructure. %{strongStart}GitLab will not charge your card, it will only be used for validation.%{strongEnd} %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "Billings|To use free compute minutes on shared runners, you'll need to validate your account with a credit card. This is required to discourage and reduce abuse on GitLab infrastructure. %{strongStart}GitLab will not charge your card, it will only be used for validation.%{strongEnd}"
+msgstr ""
+
+msgid "Billings|User validation required"
+msgstr ""
+
+msgid "Billings|Validate account"
+msgstr ""
+
+msgid "Billings|Validate user account"
+msgstr ""
+
+msgid "Billings|You'll now be able to take advantage of free compute minutes on shared runners."
+msgstr ""
+
+msgid "Billings|Your account has been validated"
+msgstr ""
+
+msgid "Billing|%{plan} SaaS Plan seats used"
+msgstr ""
+
+msgid "Billing|%{user} was successfully approved"
+msgstr ""
+
+msgid "Billing|Add seats"
+msgstr ""
+
+msgid "Billing|All members were successfully approved"
+msgstr ""
+
+msgid "Billing|An email address is only visible for users with public emails."
+msgstr ""
+
+msgid "Billing|An error occurred while approving %{user}"
+msgstr ""
+
+msgid "Billing|An error occurred while approving all members"
+msgstr ""
+
+msgid "Billing|An error occurred while getting a billable member details."
+msgstr ""
+
+msgid "Billing|An error occurred while loading GitLab subscription details."
+msgstr ""
+
+msgid "Billing|An error occurred while loading billable members list."
+msgstr ""
+
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|An error occurred while loading pending members list"
+msgstr ""
+
+msgid "Billing|An error occurred while removing a billable member."
+msgstr ""
+
+msgid "Billing|Awaiting member signup"
+msgstr ""
+
+msgid "Billing|Cannot remove user"
+msgstr ""
+
+msgid "Billing|Direct memberships"
+msgstr ""
+
+msgid "Billing|Enter at least three characters to search."
+msgstr ""
+
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Explore paid plans"
+msgstr ""
+
+msgid "Billing|Export list"
+msgstr ""
+
+msgid "Billing|Group invite"
+msgstr ""
+
+msgid "Billing|Groups in the Free tier are limited to %d seat"
+msgid_plural "Billing|Groups in the Free tier are limited to %d seats"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
+msgstr ""
+
+msgid "Billing|No seats available"
+msgstr ""
+
+msgid "Billing|No users to display."
+msgstr ""
+
+msgid "Billing|Private"
+msgstr ""
+
+msgid "Billing|Project invite"
+msgstr ""
+
+msgid "Billing|Remove user %{username} from your subscription"
+msgstr ""
+
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Subscription end"
+msgstr ""
+
+msgid "Billing|Subscription start"
+msgstr ""
+
+msgid "Billing|To ensure all members can access the group when your trial ends, you can upgrade to a paid tier."
+msgstr ""
+
+msgid "Billing|Toggle seat details"
+msgstr ""
+
+msgid "Billing|Type %{username} to confirm"
+msgstr ""
+
+msgid "Billing|Unlimited members during your trial"
+msgstr ""
+
+msgid "Billing|User was successfully removed"
+msgstr ""
+
+msgid "Billing|View pending approvals"
+msgstr ""
+
+msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
+msgstr ""
+
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
+msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
+msgstr ""
+
+msgid "Bitbucket Server Import"
+msgstr ""
+
+msgid "Bitbucket Server import"
+msgstr ""
+
+msgid "Bitbucket import"
+msgstr ""
+
+msgid "Blame"
+msgstr ""
+
+msgid "Blame could not be loaded as a single page."
+msgstr ""
+
+msgid "Blame for binary files is not supported."
+msgstr ""
+
+msgid "BlobViewer|If you delete the file, it will be removed from the branch %{branch}."
+msgstr ""
+
+msgid "BlobViewer|This file will still take up space in your LFS storage. %{linkStart}How do I remove tracked objects from Git LFS?%{linkEnd}"
+msgstr ""
+
+msgid "BlobViewer|View on %{environmentName}"
+msgstr ""
+
+msgid "Block user"
+msgstr ""
+
+msgid "Blocked"
+msgstr ""
+
+msgid "Blocked by %d issue"
+msgid_plural "Blocked by %d issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Blocked issue"
+msgstr ""
+
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
+msgid "Blocking"
+msgstr ""
+
+msgid "Blocking epics"
+msgstr ""
+
+msgid "Blocking issues"
+msgstr ""
+
+msgid "Blocks"
+msgstr ""
+
+msgid "Blog"
+msgstr ""
+
+msgid "Board scope affects which epics are displayed for anyone who visits this board"
+msgstr ""
+
+msgid "Board scope affects which issues are displayed for anyone who visits this board"
+msgstr ""
+
+msgid "BoardNewEpic|Groups"
+msgstr ""
+
+msgid "BoardNewEpic|Loading groups"
+msgstr ""
+
+msgid "BoardNewEpic|No matching results"
+msgstr ""
+
+msgid "BoardNewEpic|Search groups"
+msgstr ""
+
+msgid "BoardNewIssue|No matching results"
+msgstr ""
+
+msgid "BoardNewIssue|Projects"
+msgstr ""
+
+msgid "BoardNewIssue|Search projects"
+msgstr ""
+
+msgid "BoardNewIssue|Select a project"
+msgstr ""
+
+msgid "BoardScope|%{iterationTitle} iteration in %{iterationCadence}"
+msgstr ""
+
+msgid "BoardScope|An error occurred while getting iterations. Please try again."
+msgstr ""
+
+msgid "BoardScope|An error occurred while getting milestones, please try again."
+msgstr ""
+
+msgid "BoardScope|An error occurred while searching for labels, please try again."
+msgstr ""
+
+msgid "BoardScope|An error occurred while searching for users, please try again."
+msgstr ""
+
+msgid "BoardScope|Any Milestone"
+msgstr ""
+
+msgid "BoardScope|Any assignee"
+msgstr ""
+
+msgid "BoardScope|Any iteration"
+msgstr ""
+
+msgid "BoardScope|Any label"
+msgstr ""
+
+msgid "BoardScope|Assignee"
+msgstr ""
+
+msgid "BoardScope|Choose labels"
+msgstr ""
+
+msgid "BoardScope|Current iteration"
+msgstr ""
+
+msgid "BoardScope|Don't filter milestone"
+msgstr ""
+
+msgid "BoardScope|Edit"
+msgstr ""
+
+msgid "BoardScope|Iteration"
+msgstr ""
+
+msgid "BoardScope|Labels"
+msgstr ""
+
+msgid "BoardScope|Milestone"
+msgstr ""
+
+msgid "BoardScope|No iteration"
+msgstr ""
+
+msgid "BoardScope|No milestone"
+msgstr ""
+
+msgid "BoardScope|Search iterations"
+msgstr ""
+
+msgid "BoardScope|Search milestones"
+msgstr ""
+
+msgid "BoardScope|Select assignee"
+msgstr ""
+
+msgid "BoardScope|Select iteration"
+msgstr ""
+
+msgid "BoardScope|Select labels"
+msgstr ""
+
+msgid "BoardScope|Select milestone"
+msgstr ""
+
+msgid "BoardScope|Started"
+msgstr ""
+
+msgid "BoardScope|Upcoming"
+msgstr ""
+
+msgid "BoardScope|Weight"
+msgstr ""
+
+msgid "Boards"
+msgstr ""
+
+msgid "Boards and board lists"
+msgstr ""
+
+msgid "Boards|+ %{displayedIssuablesCount} more %{issuableType}"
+msgid_plural "Boards|+ %{displayedIssuablesCount} more %{issuableType}s"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Boards|An error occurred while creating the %{issuableType}. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while creating the epic. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while creating the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while creating the list. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while deleting the list. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching a list. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching board details. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching board. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching boards. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching child groups. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching epics. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching group projects. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching groups. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching issues. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching iterations. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching labels. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching labels. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching list's information. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching milestones. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching recent boards. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board epics. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board lists. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching unassigned issues. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching users. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while generating lists. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the %{issuableType}. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the epic. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the list. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while removing the list. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while selecting the card. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the board list. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
+msgstr ""
+
+msgid "Boards|Blocked by %{blockedByCount} %{issuableType}"
+msgid_plural "Boards|Blocked by %{blockedByCount} %{issuableType}s"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Boards|Collapse"
+msgstr ""
+
+msgid "Boards|Create new epic"
+msgstr ""
+
+msgid "Boards|Create new issue"
+msgstr ""
+
+msgid "Boards|Edit board"
+msgstr ""
+
+msgid "Boards|Edit list settings"
+msgstr ""
+
+msgid "Boards|Expand"
+msgstr ""
+
+msgid "Boards|Failed to fetch blocking %{issuableType}s"
+msgstr ""
+
+msgid "Boards|Move card"
+msgstr ""
+
+msgid "Boards|Move to end of list"
+msgstr ""
+
+msgid "Boards|Move to start of list"
+msgstr ""
+
+msgid "Boards|New board"
+msgstr ""
+
+msgid "Boards|Retrieving blocking %{issuableType}s"
+msgstr ""
+
+msgid "Boards|View all blocking %{issuableType}s"
+msgstr ""
+
+msgid "Boards|View scope"
+msgstr ""
+
+msgid "Board|Are you sure you want to delete this board?"
+msgstr ""
+
+msgid "Board|Board scope"
+msgstr ""
+
+msgid "Board|Create board"
+msgstr ""
+
+msgid "Board|Create new board"
+msgstr ""
+
+msgid "Board|Delete board"
+msgstr ""
+
+msgid "Board|Edit board"
+msgstr ""
+
+msgid "Board|Enter board name"
+msgstr ""
+
+msgid "Board|Failed to delete board. Please try again."
+msgstr ""
+
+msgid "Board|Load more epics"
+msgstr ""
+
+msgid "Board|Load more issues"
+msgstr ""
+
+msgid "Board|Loading epics"
+msgstr ""
+
+msgid "Bold (%{modifierKey}B)"
+msgstr ""
+
+msgid "Bold text"
+msgstr ""
+
+msgid "Bot"
+msgstr ""
+
+msgid "Both SSH and HTTP(S)"
+msgstr ""
+
+msgid "Branch"
+msgstr ""
+
+msgid "Branch %{branchName} was not found in this project's repository."
+msgstr ""
+
+msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
+msgstr ""
+
+msgid "Branch Rules"
+msgstr ""
+
+msgid "Branch already exists"
+msgstr ""
+
+msgid "Branch changed"
+msgstr ""
+
+msgid "Branch defaults"
+msgstr ""
+
+msgid "Branch has been updated since the merge was requested."
+msgstr ""
+
+msgid "Branch is already taken"
+msgstr ""
+
+msgid "Branch name"
+msgstr ""
+
+msgid "Branch name template"
+msgstr ""
+
+msgid "Branch not loaded - %{branchId}"
+msgstr ""
+
+msgid "Branch rules"
+msgstr ""
+
+msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/ are supported"
+msgstr ""
+
+msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/* are supported."
+msgstr ""
+
+msgid "BranchRules|%{total} approval %{subject}"
+msgstr ""
+
+msgid "BranchRules|%{total} matching %{subject}"
+msgstr ""
+
+msgid "BranchRules|%{total} status %{subject}"
+msgstr ""
+
+msgid "BranchRules|Add branch rule"
+msgstr ""
+
+msgid "BranchRules|After a protected branch is created, it will show up in the list as a branch rule."
+msgstr ""
+
+msgid "BranchRules|All branches"
+msgstr ""
+
+msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
+msgstr ""
+
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
+msgid "BranchRules|Allowed to merge"
+msgstr ""
+
+msgid "BranchRules|Allowed to merge (%{total})"
+msgstr ""
+
+msgid "BranchRules|Allowed to push and merge"
+msgstr ""
+
+msgid "BranchRules|Allowed to push and merge (%{total})"
+msgstr ""
+
+msgid "BranchRules|Allows force push"
+msgstr ""
+
+msgid "BranchRules|Also accepts code pushes that change files listed in CODEOWNERS file."
+msgstr ""
+
+msgid "BranchRules|Also rejects code pushes that change files listed in CODEOWNERS file."
+msgstr ""
+
+msgid "BranchRules|An error occurred while fetching branches."
+msgstr ""
+
+msgid "BranchRules|Approvals"
+msgstr ""
+
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "BranchRules|Branch"
+msgstr ""
+
+msgid "BranchRules|Branch name or pattern"
+msgstr ""
+
+msgid "BranchRules|Branch rules details"
+msgstr ""
+
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "BranchRules|Create protected branch"
+msgstr ""
+
+msgid "BranchRules|Create wildcard: %{searchTerm}"
+msgstr ""
+
+msgid "BranchRules|Does not allow force push"
+msgstr ""
+
+msgid "BranchRules|Does not require approval from code owners"
+msgstr ""
+
+msgid "BranchRules|From users with push access."
+msgstr ""
+
+msgid "BranchRules|Groups"
+msgstr ""
+
+msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
+msgstr ""
+
+msgid "BranchRules|Manage in merge request approvals"
+msgstr ""
+
+msgid "BranchRules|Manage in protected branches"
+msgstr ""
+
+msgid "BranchRules|Manage in status checks"
+msgstr ""
+
+msgid "BranchRules|No data to display"
+msgstr ""
+
+msgid "BranchRules|No matching results"
+msgstr ""
+
+msgid "BranchRules|Protect branch"
+msgstr ""
+
+msgid "BranchRules|Protections"
+msgstr ""
+
+msgid "BranchRules|Reject code pushes that change files listed in the CODEOWNERS file."
+msgstr ""
+
+msgid "BranchRules|Require approval from code owners."
+msgstr ""
+
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
+msgid "BranchRules|Requires approval from code owners"
+msgstr ""
+
+msgid "BranchRules|Roles"
+msgstr ""
+
+msgid "BranchRules|Status checks"
+msgstr ""
+
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
+msgid "BranchRules|Target branch"
+msgstr ""
+
+msgid "BranchRules|To create a branch rule, you first need to create a protected branch."
+msgstr ""
+
+msgid "BranchRules|Users"
+msgstr ""
+
+msgid "BranchRules|View details"
+msgstr ""
+
+msgid "BranchRules|default"
+msgstr ""
+
+msgid "BranchRules|protected"
+msgstr ""
+
+msgid "Branches"
+msgstr ""
+
+msgid "Branches: %{source_branch} to %{target_branch}"
+msgstr ""
+
+msgid "Branches: %{source_branch} → %{target_branch}"
+msgstr ""
+
+msgid "Branches|A branch won't be deleted if it is protected or associated with an open merge request."
+msgstr ""
+
+msgid "Branches|Active"
+msgstr ""
+
+msgid "Branches|Active branches"
+msgstr ""
+
+msgid "Branches|After you confirm and select %{strongStart}%{buttonText},%{strongEnd} you cannot recover this branch."
+msgstr ""
+
+msgid "Branches|All"
+msgstr ""
+
+msgid "Branches|Cancel, keep branch"
+msgstr ""
+
+msgid "Branches|Can’t find HEAD commit for this branch"
+msgstr ""
+
+msgid "Branches|Compare"
+msgstr ""
+
+msgid "Branches|Delete all merged branches?"
+msgstr ""
+
+msgid "Branches|Delete branch"
+msgstr ""
+
+msgid "Branches|Delete branch. Are you ABSOLUTELY SURE?"
+msgstr ""
+
+msgid "Branches|Delete merged branches"
+msgstr ""
+
+msgid "Branches|Delete protected branch"
+msgstr ""
+
+msgid "Branches|Delete protected branch. Are you ABSOLUTELY SURE?"
+msgstr ""
+
+msgid "Branches|Deleting the %{strongStart}%{branchName}%{strongEnd} branch cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "Branches|Filter by branch name"
+msgstr ""
+
+msgid "Branches|New branch"
+msgstr ""
+
+msgid "Branches|No branches to show"
+msgstr ""
+
+msgid "Branches|Overview"
+msgstr ""
+
+msgid "Branches|Please type the following to confirm:"
+msgstr ""
+
+msgid "Branches|Plese type the following to confirm: %{codeStart}delete%{codeEnd}."
+msgstr ""
+
+msgid "Branches|See all branch-related settings together with branch rules"
+msgstr ""
+
+msgid "Branches|Show active branches"
+msgstr ""
+
+msgid "Branches|Show all branches"
+msgstr ""
+
+msgid "Branches|Show more active branches"
+msgstr ""
+
+msgid "Branches|Show more stale branches"
+msgstr ""
+
+msgid "Branches|Show overview of the branches"
+msgstr ""
+
+msgid "Branches|Show stale branches"
+msgstr ""
+
+msgid "Branches|Stale"
+msgstr ""
+
+msgid "Branches|Stale branches"
+msgstr ""
+
+msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart."
+msgstr ""
+
+msgid "Branches|This branch hasn't been merged into %{defaultBranchName}. To avoid data loss, consider merging this branch before deleting it."
+msgstr ""
+
+msgid "Branches|This bulk action is %{strongStart}permanent and cannot be undone or recovered%{strongEnd}."
+msgstr ""
+
+msgid "Branches|This may include merged branches that are not visible on the current screen."
+msgstr ""
+
+msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
+msgstr ""
+
+msgid "Branches|Unable to load branches"
+msgstr ""
+
+msgid "Branches|View branch rules"
+msgstr ""
+
+msgid "Branches|Yes, delete branch"
+msgstr ""
+
+msgid "Branches|Yes, delete protected branch"
+msgstr ""
+
+msgid "Branches|You are about to %{strongStart}delete all branches%{strongEnd} that were merged into %{codeStart}%{defaultBranch}%{codeEnd}."
+msgstr ""
+
+msgid "Branches|You can now find an overview of settings for protected branches, merge request approvals, status checks, and security approvals conveniently in one spot."
+msgstr ""
+
+msgid "Branches|You're about to permanently delete the branch %{branchName}."
+msgstr ""
+
+msgid "Branches|You're about to permanently delete the protected branch %{branchName}."
+msgstr ""
+
+msgid "Branches|diverged from upstream"
+msgstr ""
+
+msgid "Branches|protected"
+msgstr ""
+
+msgid "Breadcrumbs"
+msgstr ""
+
+msgid "Broadcast Message was successfully created."
+msgstr ""
+
+msgid "Broadcast Message was successfully updated."
+msgstr ""
+
+msgid "Broadcast Messages"
+msgstr ""
+
+msgid "BroadcastMessages|Add broadcast message"
+msgstr ""
+
+msgid "BroadcastMessages|Add new message"
+msgstr ""
+
+msgid "BroadcastMessages|Allow users to dismiss the broadcast message"
+msgstr ""
+
+msgid "BroadcastMessages|Banner"
+msgstr ""
+
+msgid "BroadcastMessages|Blue"
+msgstr ""
+
+msgid "BroadcastMessages|Dark"
+msgstr ""
+
+msgid "BroadcastMessages|Delete broadcast message"
+msgstr ""
+
+msgid "BroadcastMessages|Delete message"
+msgstr ""
+
+msgid "BroadcastMessages|Dismissable"
+msgstr ""
+
+msgid "BroadcastMessages|Do you really want to delete this broadcast message?"
+msgstr ""
+
+msgid "BroadcastMessages|Ends at"
+msgstr ""
+
+msgid "BroadcastMessages|Git remote responses"
+msgstr ""
+
+msgid "BroadcastMessages|Green"
+msgstr ""
+
+msgid "BroadcastMessages|Indigo"
+msgstr ""
+
+msgid "BroadcastMessages|Leave blank to target all group and project pages."
+msgstr ""
+
+msgid "BroadcastMessages|Light"
+msgstr ""
+
+msgid "BroadcastMessages|Light Blue"
+msgstr ""
+
+msgid "BroadcastMessages|Light Green"
+msgstr ""
+
+msgid "BroadcastMessages|Light Indigo"
+msgstr ""
+
+msgid "BroadcastMessages|Light Red"
+msgstr ""
+
+msgid "BroadcastMessages|Message"
+msgstr ""
+
+msgid "BroadcastMessages|Messages"
+msgstr ""
+
+msgid "BroadcastMessages|No broadcast messages defined yet."
+msgstr ""
+
+msgid "BroadcastMessages|Notification"
+msgstr ""
+
+msgid "BroadcastMessages|One or more roles is required."
+msgstr ""
+
+msgid "BroadcastMessages|Paths can contain wildcards, like */welcome."
+msgstr ""
+
+msgid "BroadcastMessages|Red"
+msgstr ""
+
+msgid "BroadcastMessages|Select at least one role."
+msgstr ""
+
+msgid "BroadcastMessages|Show only to users who have specific roles on groups/project pages"
+msgstr ""
+
+msgid "BroadcastMessages|Show the broadcast message in a command-line interface as a Git remote response"
+msgstr ""
+
+msgid "BroadcastMessages|Show to all users on all pages"
+msgstr ""
+
+msgid "BroadcastMessages|Show to all users on specific matching pages"
+msgstr ""
+
+msgid "BroadcastMessages|Starts at"
+msgstr ""
+
+msgid "BroadcastMessages|Target Path"
+msgstr ""
+
+msgid "BroadcastMessages|Target broadcast message"
+msgstr ""
+
+msgid "BroadcastMessages|Target roles"
+msgstr ""
+
+msgid "BroadcastMessages|Theme"
+msgstr ""
+
+msgid "BroadcastMessages|There was an error adding broadcast message."
+msgstr ""
+
+msgid "BroadcastMessages|There was an error updating broadcast message."
+msgstr ""
+
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
+msgid "BroadcastMessages|Type"
+msgstr ""
+
+msgid "BroadcastMessages|Update broadcast message"
+msgstr ""
+
+msgid "BroadcastMessages|Your message here"
+msgstr ""
+
+msgid "Browse CI/CD Catalog"
+msgstr ""
+
+msgid "Browse Directory"
+msgstr ""
+
+msgid "Browse File"
+msgstr ""
+
+msgid "Browse Files"
+msgstr ""
+
+msgid "Browse files"
+msgstr ""
+
+msgid "Browse templates"
+msgstr ""
+
+msgid "Build cannot be erased"
+msgstr ""
+
+msgid "BuildArtifacts|An error occurred while fetching the artifacts"
+msgstr ""
+
+msgid "BuildArtifacts|Loading artifacts"
+msgstr ""
+
+msgid "Building your merge request… This page will update when the build is complete."
+msgstr ""
+
+msgid "Built-in"
+msgstr ""
+
+msgid "Bulk edit"
+msgstr ""
+
+msgid "Bulk request concurrency"
+msgstr ""
+
+msgid "Bulk update"
+msgstr ""
+
+msgid "BulkImport| %{host} is running outdated GitLab version (v%{version})"
+msgstr ""
+
+msgid "BulkImport|%{feature} (require v%{version})"
+msgstr ""
+
+msgid "BulkImport|Be aware of %{linkStart}visibility rules%{linkEnd} when importing groups."
+msgstr ""
+
+msgid "BulkImport|Destination"
+msgstr ""
+
+msgid "BulkImport|Direct transfer maximum download file size (MB)"
+msgstr ""
+
+msgid "BulkImport|Existing groups"
+msgstr ""
+
+msgid "BulkImport|Filter by source group"
+msgstr ""
+
+msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
+msgstr ""
+
+msgid "BulkImport|GitLab Migration history"
+msgstr ""
+
+msgid "BulkImport|History"
+msgstr ""
+
+msgid "BulkImport|Import failed: Destination cannot be a subgroup of the source group. Change the destination and try again."
+msgstr ""
+
+msgid "BulkImport|Import groups from GitLab"
+msgstr ""
+
+msgid "BulkImport|Import is finished. Pick another name for re-import"
+msgstr ""
+
+msgid "BulkImport|Import with projects"
+msgstr ""
+
+msgid "BulkImport|Import without projects"
+msgstr ""
+
+msgid "BulkImport|Importing projects is a %{docsLinkStart}Beta%{docsLinkEnd} feature."
+msgstr ""
+
+msgid "BulkImport|Importing the group failed."
+msgstr ""
+
+msgid "BulkImport|Last imported to %{link}"
+msgstr ""
+
+msgid "BulkImport|Maximum download file size when importing from source GitLab instances by direct transfer."
+msgstr ""
+
+msgid "BulkImport|Name already exists."
+msgstr ""
+
+msgid "BulkImport|Name already used as a target for another group."
+msgstr ""
+
+msgid "BulkImport|New group"
+msgstr ""
+
+msgid "BulkImport|No additional information provided."
+msgstr ""
+
+msgid "BulkImport|No groups found"
+msgstr ""
+
+msgid "BulkImport|No history is available"
+msgstr ""
+
+msgid "BulkImport|No parent"
+msgstr ""
+
+msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
+msgstr ""
+
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
+msgid "BulkImport|Project import history"
+msgstr ""
+
+msgid "BulkImport|Re-import creates a new group. It does not sync with the existing group."
+msgstr ""
+
+msgid "BulkImport|Showing %{start}-%{end} of %{total}"
+msgstr ""
+
+msgid "BulkImport|Showing %{start}-%{end} of %{total} that you own from %{link}"
+msgstr ""
+
+msgid "BulkImport|Showing %{start}-%{end} of %{total} that you own matching filter \"%{filter}\" from %{link}"
+msgstr ""
+
+msgid "BulkImport|Source"
+msgstr ""
+
+msgid "BulkImport|Source group"
+msgstr ""
+
+msgid "BulkImport|Template / File-based import / GitLab Migration"
+msgstr ""
+
+msgid "BulkImport|Update of import statuses with realtime changes failed"
+msgstr ""
+
+msgid "BulkImport|Your imported groups and projects will appear here."
+msgstr ""
+
+msgid "BulkImport|Your imported projects will appear here."
+msgstr ""
+
+msgid "BulkImport|expected an associated Group but has an associated Project"
+msgstr ""
+
+msgid "BulkImport|expected an associated Project but has an associated Group"
+msgstr ""
+
+msgid "BulkImport|must be a group"
+msgstr ""
+
+msgid "Bulkmport|Over six imports in one minute were attempted. Wait at least one minute and try again."
+msgstr ""
+
+msgid "Bullet list"
+msgstr ""
+
+msgid "Burndown chart"
+msgstr ""
+
+msgid "BurndownChartLabel|Remaining"
+msgstr ""
+
+msgid "Burnup chart"
+msgstr ""
+
+msgid "Burnup chart could not be generated due to too many events"
+msgstr ""
+
+msgid "Business"
+msgstr ""
+
+msgid "Business metrics (Custom)"
+msgstr ""
+
+msgid "Busy"
+msgstr ""
+
+msgid "Buy CI Minutes"
+msgstr ""
+
+msgid "Buy Storage"
+msgstr ""
+
+msgid "Buy more Pipeline minutes"
+msgstr ""
+
+msgid "By %{user_name}"
+msgstr ""
+
+msgid "By authenticating with an account tied to an Enterprise e-mail address, it is understood that this account is an Enterprise User. "
+msgstr ""
+
+msgid "By default, all projects and groups use the global notifications setting."
+msgstr ""
+
+msgid "By month"
+msgstr ""
+
+msgid "By quarter"
+msgstr ""
+
+msgid "By using a primary email tied to an Enterprise email address, you acknowledge that this account is an Enterprise User."
+msgstr ""
+
+msgid "By week"
+msgstr ""
+
+msgid "ByAuthor|by"
+msgstr ""
+
+msgid "CHANGELOG"
+msgstr ""
+
+msgid "CI"
+msgstr ""
+
+msgid "CI Lint"
+msgstr ""
+
+msgid "CI configuration validated, including all configuration added with the %{codeStart}include%{codeEnd} keyword. %{link}"
+msgstr ""
+
+msgid "CI settings"
+msgstr ""
+
+msgid "CI variables"
+msgstr ""
+
+msgid "CI/CD"
+msgstr ""
+
+msgid "CI/CD Analytics"
+msgstr ""
+
+msgid "CI/CD Settings"
+msgstr ""
+
+msgid "CI/CD analytics"
+msgstr ""
+
+msgid "CI/CD configuration"
+msgstr ""
+
+msgid "CI/CD configuration file"
+msgstr ""
+
+msgid "CI/CD limits"
+msgstr ""
+
+msgid "CI/CD|No projects have been added to the scope"
+msgstr ""
+
+msgid "CICDAnalytics|%{percent}%{percentSymbol}"
+msgstr ""
+
+msgid "CICDAnalytics|All time"
+msgstr ""
+
+msgid "CICDAnalytics|Change failure rate"
+msgstr ""
+
+msgid "CICDAnalytics|Deployment frequency"
+msgstr ""
+
+msgid "CICDAnalytics|Lead time"
+msgstr ""
+
+msgid "CICDAnalytics|No shared runner minute usage data available"
+msgstr ""
+
+msgid "CICDAnalytics|Projects with releases"
+msgstr ""
+
+msgid "CICDAnalytics|Release"
+msgid_plural "CICDAnalytics|Releases"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "CICDAnalytics|Release statistics"
+msgstr ""
+
+msgid "CICDAnalytics|Releases"
+msgstr ""
+
+msgid "CICDAnalytics|Shared runner duration is the total runtime of all jobs that ran on shared runners"
+msgstr ""
+
+msgid "CICDAnalytics|Shared runner pipeline minute duration by month"
+msgstr ""
+
+msgid "CICDAnalytics|Something went wrong while fetching release statistics"
+msgstr ""
+
+msgid "CICDAnalytics|Time to restore service"
+msgstr ""
+
+msgid "CICDAnalytics|What is shared runner duration?"
+msgstr ""
+
+msgid "CICD|Add a %{base_domain_link_start}base domain%{link_end} to your %{kubernetes_cluster_link_start}Kubernetes cluster%{link_end} for your deployment strategy to work."
+msgstr ""
+
+msgid "CICD|Add a %{kubernetes_cluster_link_start}Kubernetes cluster integration%{link_end} with a domain, or create an AUTO_DEVOPS_PLATFORM_TARGET CI variable."
+msgstr ""
+
+msgid "CICD|Add an existing project to the scope"
+msgstr ""
+
+msgid "CICD|Allow CI job tokens from the following projects to access this project"
+msgstr ""
+
+msgid "CICD|Auto DevOps"
+msgstr ""
+
+msgid "CICD|Automatic deployment to staging, manual deployment to production"
+msgstr ""
+
+msgid "CICD|Continuous deployment to production"
+msgstr ""
+
+msgid "CICD|Continuous deployment to production using timed incremental rollout"
+msgstr ""
+
+msgid "CICD|Default to Auto DevOps pipeline"
+msgstr ""
+
+msgid "CICD|Default to Auto DevOps pipeline for all projects"
+msgstr ""
+
+msgid "CICD|Deployment strategy"
+msgstr ""
+
+msgid "CICD|Disabling this feature is a permanent change."
+msgstr ""
+
+msgid "CICD|Enable feature to allow job token access by the following projects."
+msgstr ""
+
+msgid "CICD|Enable feature to limit job token access to the following projects."
+msgstr ""
+
+msgid "CICD|Jobs"
+msgstr ""
+
+msgid "CICD|Limit"
+msgstr ""
+
+msgid "CICD|Limit access %{italicStart}from%{italicEnd} this project (Deprecated)"
+msgstr ""
+
+msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
+msgstr ""
+
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "CICD|The %{boldStart}Limit CI_JOB_TOKEN%{boldEnd} scope is deprecated and will be removed the 17.0 milestone. Configure the %{boldStart}CI_JOB_TOKEN%{boldEnd} allowlist instead. %{linkStart}How do I do this?%{linkEnd}"
+msgstr ""
+
+msgid "CICD|The Auto DevOps pipeline runs by default in all projects with no CI/CD configuration file. %{link_start}What is Auto DevOps?%{link_end}"
+msgstr ""
+
+msgid "CICD|The Auto DevOps pipeline runs if no alternative CI configuration file is found."
+msgstr ""
+
+msgid "CICD|There are several CI/CD limits in place."
+msgstr ""
+
+msgid "CICD|Unprotected branches will not have access to the cache from protected branches."
+msgstr ""
+
+msgid "CICD|Use separate caches for protected branches"
+msgstr ""
+
+msgid "CICD|group enabled"
+msgstr ""
+
+msgid "CICD|instance enabled"
+msgstr ""
+
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
+msgid "CONTRIBUTING"
+msgstr ""
+
+msgid "CPU"
+msgstr ""
+
+msgid "CSV is being generated and will be emailed to you upon completion."
+msgstr ""
+
+msgid "CVE|As a maintainer, requesting a CVE for a vulnerability in your project will help your users stay secure and informed."
+msgstr ""
+
+msgid "CVE|CVE ID Request"
+msgstr ""
+
+msgid "CVE|Common Vulnerability Enumeration (CVE) identifiers are used to track distinct vulnerabilities in specific versions of code."
+msgstr ""
+
+msgid "CVE|Create CVE ID Request"
+msgstr ""
+
+msgid "CVE|Enable CVE ID requests in the issue sidebar"
+msgstr ""
+
+msgid "CVE|Request CVE ID"
+msgstr ""
+
+msgid "CVE|Why Request a CVE ID?"
+msgstr ""
+
+msgid "Cadence is not automated"
+msgstr ""
+
+msgid "Calculate the number of slices during reindexing. The multiplier is applied to the number of shards per index. Learn more about %{slice_multiplier_link_start}slice multiplier configuration%{slice_multiplier_link_end}."
+msgstr ""
+
+msgid "Callback URL"
+msgstr ""
+
+msgid "Campfire room ID (optional)"
+msgstr ""
+
+msgid "Campfire subdomain (optional)"
+msgstr ""
+
+msgid "Campfire token"
+msgstr ""
+
+msgid "CampfireService|API authentication token from Campfire."
+msgstr ""
+
+msgid "CampfireService|From the end of the room URL."
+msgstr ""
+
+msgid "CampfireService|Send notifications about push events to Campfire chat rooms. %{docs_link}"
+msgstr ""
+
+msgid "CampfireService|The %{code_open}.campfirenow.com%{code_close} subdomain."
+msgstr ""
+
+msgid "Can be manually deployed to"
+msgstr ""
+
+msgid "Can create top level groups:"
+msgstr ""
+
+msgid "Can not delete primary training"
+msgstr ""
+
+msgid "Can't apply as the source branch was deleted."
+msgstr ""
+
+msgid "Can't apply as these lines were changed in a more recent version."
+msgstr ""
+
+msgid "Can't apply as this line was changed in a more recent version."
+msgstr ""
+
+msgid "Can't apply this suggestion."
+msgstr ""
+
+msgid "Can't be empty"
+msgstr ""
+
+msgid "Can't contain %{chars}"
+msgstr ""
+
+msgid "Can't contain spaces"
+msgstr ""
+
+msgid "Can't contain spaces, %{chars}"
+msgstr ""
+
+msgid "Can't create snippet: %{err}"
+msgstr ""
+
+msgid "Can't fetch content for the blob: %{err}"
+msgstr ""
+
+msgid "Can't find HEAD commit for this branch"
+msgstr ""
+
+msgid "Can't find variable: ZiteReader"
+msgstr ""
+
+msgid "Can't scan the code?"
+msgstr ""
+
+msgid "Can't update snippet: %{err}"
+msgstr ""
+
+msgid "Canary"
+msgstr ""
+
+msgid "Canary Ingress does not exist in the environment."
+msgstr ""
+
+msgid "Canary weight must be specified and valid range (0..100)."
+msgstr ""
+
+msgid "CanaryIngress|%{boldStart}Canary:%{boldEnd} %{canary}"
+msgstr ""
+
+msgid "CanaryIngress|%{boldStart}Stable:%{boldEnd} %{stable}"
+msgstr ""
+
+msgid "CanaryIngress|Canary"
+msgstr ""
+
+msgid "CanaryIngress|Change ratio"
+msgstr ""
+
+msgid "CanaryIngress|Change the ratio of canary deployments?"
+msgstr ""
+
+msgid "CanaryIngress|Doing so will set a deployment change in progress. This temporarily blocks any further configuration until the deployment is finished."
+msgstr ""
+
+msgid "CanaryIngress|Stable"
+msgstr ""
+
+msgid "CanaryIngress|You are changing the ratio of the canary rollout for %{environment} compared to the stable deployment to:"
+msgstr ""
+
+msgid "Cancel"
+msgstr ""
+
+msgid "Cancel and close"
+msgstr ""
+
+msgid "Cancel downstream pipeline"
+msgstr ""
+
+msgid "Cancel editing"
+msgstr ""
+
+msgid "Cancel index deletion"
+msgstr ""
+
+msgid "Cancel pipeline"
+msgstr ""
+
+msgid "Cancel the running pipeline"
+msgstr ""
+
+msgid "Cancel this job"
+msgstr ""
+
+msgid "Cancel your account"
+msgstr ""
+
+msgid "Cancel, keep project"
+msgstr ""
+
+msgid "Canceled deployment to"
+msgstr ""
+
+msgid "Cancelled"
+msgstr ""
+
+msgid "Cancelling Preview"
+msgstr ""
+
+msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
+msgstr ""
+
+msgid "Cannot be merged automatically"
+msgstr ""
+
+msgid "Cannot create the abuse report. The reported user was invalid. Please try again or contact support."
+msgstr ""
+
+msgid "Cannot create the abuse report. The user has been deleted."
+msgstr ""
+
+msgid "Cannot create the abuse report. This user has been banned."
+msgstr ""
+
+msgid "Cannot delete %{profile_name} referenced in security policy"
+msgstr ""
+
+msgid "Cannot delete the default framework"
+msgstr ""
+
+msgid "Cannot delete the default organization"
+msgstr ""
+
+msgid "Cannot have multiple Jira imports running at the same time"
+msgstr ""
+
+msgid "Cannot have multiple unresolved alerts"
+msgstr ""
+
+msgid "Cannot import because issues are not available in this project."
+msgstr ""
+
+msgid "Cannot load the diagram into the diagrams.net editor"
+msgstr ""
+
+msgid "Cannot make the epic confidential if it contains non-confidential child epics"
+msgstr ""
+
+msgid "Cannot make the epic confidential if it contains non-confidential issues"
+msgstr ""
+
+msgid "Cannot merge"
+msgstr ""
+
+msgid "Cannot modify %{profile_name} referenced in security policy"
+msgstr ""
+
+msgid "Cannot modify managed Kubernetes cluster"
+msgstr ""
+
+msgid "Cannot modify provider during creation"
+msgstr ""
+
+msgid "Cannot promote issue because it does not belong to a group."
+msgstr ""
+
+msgid "Cannot promote issue due to insufficient permissions."
+msgstr ""
+
+msgid "Cannot push to source branch"
+msgstr ""
+
+msgid "Cannot refer to a group milestone by an internal id!"
+msgstr ""
+
+msgid "Cannot show preview. For previews on sketch files, they must have the file format introduced by Sketch version 43 and above."
+msgstr ""
+
+msgid "Cannot skip two factor authentication setup"
+msgstr ""
+
+msgid "Capacity threshold"
+msgstr ""
+
+msgid "Card holder name"
+msgstr ""
+
+msgid "Card number:"
+msgstr ""
+
+msgid "CascadingSettings|Enforce for all subgroups"
+msgstr ""
+
+msgid "CascadingSettings|Setting enforced"
+msgstr ""
+
+msgid "CascadingSettings|Subgroups cannot change this setting."
+msgstr ""
+
+msgid "CascadingSettings|This setting has been enforced by an instance admin."
+msgstr ""
+
+msgid "CascadingSettings|This setting has been enforced by an owner of %{link}."
+msgstr ""
+
+msgid "CascadingSettings|cannot be changed because it is locked by an ancestor"
+msgstr ""
+
+msgid "CascadingSettings|cannot be nil when locking the attribute"
+msgstr ""
+
+msgid "Category"
+msgstr ""
+
+msgid "Cause identified"
+msgstr ""
+
+msgid "Certain user content will be moved to a system-wide \"Ghost User\" in order to maintain content for posterity. For further information, please refer to the %{link_start}user account deletion documentation.%{link_end}"
+msgstr ""
+
+msgid "Certificate"
+msgstr ""
+
+msgid "Certificate (PEM)"
+msgstr ""
+
+msgid "Certificate Issuer"
+msgstr ""
+
+msgid "Certificate Subject"
+msgstr ""
+
+msgid "Change Failure Rate"
+msgstr ""
+
+msgid "Change assignee"
+msgstr ""
+
+msgid "Change assignees"
+msgstr ""
+
+msgid "Change assignees."
+msgstr ""
+
+msgid "Change branches"
+msgstr ""
+
+msgid "Change confidentiality"
+msgstr ""
+
+msgid "Change label"
+msgstr ""
+
+msgid "Change made by"
+msgstr ""
+
+msgid "Change milestone"
+msgstr ""
+
+msgid "Change path"
+msgstr ""
+
+msgid "Change reviewers"
+msgstr ""
+
+msgid "Change reviewers."
+msgstr ""
+
+msgid "Change role"
+msgstr ""
+
+msgid "Change status"
+msgstr ""
+
+msgid "Change subscription"
+msgstr ""
+
+msgid "Change template"
+msgstr ""
+
+msgid "Change title"
+msgstr ""
+
+msgid "Change work item type"
+msgstr ""
+
+msgid "Change your password"
+msgstr ""
+
+msgid "Change your password or recover your current one."
+msgstr ""
+
+msgid "Change your password."
+msgstr ""
+
+msgid "ChangeReviewer|All reviewers were removed."
+msgstr ""
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr ""
+
+msgid "ChangeTypeAction|GitLab will create a branch in your fork and start a merge request."
+msgstr ""
+
+msgid "ChangeTypeAction|Pick into branch"
+msgstr ""
+
+msgid "ChangeTypeAction|Pick into project"
+msgstr ""
+
+msgid "ChangeTypeAction|Revert"
+msgstr ""
+
+msgid "ChangeTypeAction|Revert in branch"
+msgstr ""
+
+msgid "ChangeTypeAction|Search branches"
+msgstr ""
+
+msgid "ChangeTypeAction|Search projects"
+msgstr ""
+
+msgid "ChangeTypeAction|Start a %{newMergeRequest} with these changes"
+msgstr ""
+
+msgid "ChangeTypeAction|Switch branch"
+msgstr ""
+
+msgid "ChangeTypeAction|Switch project"
+msgstr ""
+
+msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
+msgstr ""
+
+msgid "ChangeTypeAction|Your changes will be committed to %{branchName} because a merge request is open."
+msgstr ""
+
+msgid "Changed"
+msgstr ""
+
+msgid "Changed assignees."
+msgstr ""
+
+msgid "Changed merge method to %{merge_method}"
+msgstr ""
+
+msgid "Changed reviewers."
+msgstr ""
+
+msgid "Changed squash option to %{squash_option}"
+msgstr ""
+
+msgid "Changed the title to \"%{title_param}\"."
+msgstr ""
+
+msgid "Changelog"
+msgstr ""
+
+msgid "Changes"
+msgstr ""
+
+msgid "Changes saved."
+msgstr ""
+
+msgid "Changes suppressed. Click to show."
+msgstr ""
+
+msgid "Changes the title to \"%{title_param}\"."
+msgstr ""
+
+msgid "Changes to the title have not been saved"
+msgstr ""
+
+msgid "Changes:"
+msgstr ""
+
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
+msgid "Changing any setting here requires an application restart"
+msgstr ""
+
+msgid "Characters left"
+msgstr ""
+
+msgid "Characters over limit"
+msgstr ""
+
+msgid "Chat"
+msgstr ""
+
+msgid "Chat not available."
+msgstr ""
+
+msgid "ChatMessage|%{project_link}: Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status} in %{duration}"
+msgstr ""
+
+msgid "ChatMessage|Branch"
+msgstr ""
+
+msgid "ChatMessage|Commit"
+msgstr ""
+
+msgid "ChatMessage|Failed job"
+msgstr ""
+
+msgid "ChatMessage|Failed stage"
+msgstr ""
+
+msgid "ChatMessage|Invalid CI config YAML file"
+msgstr ""
+
+msgid "ChatMessage|Pipeline #%{pipeline_id} %{humanized_status} in %{duration}"
+msgstr ""
+
+msgid "ChatMessage|Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status}"
+msgstr ""
+
+msgid "ChatMessage|Pipeline name"
+msgstr ""
+
+msgid "ChatMessage|Tag"
+msgstr ""
+
+msgid "ChatMessage|and [%{count} more](%{pipeline_failed_jobs_url})"
+msgstr ""
+
+msgid "ChatMessage|has failed"
+msgstr ""
+
+msgid "ChatMessage|has passed"
+msgstr ""
+
+msgid "ChatMessage|has passed with warnings"
+msgstr ""
+
+msgid "ChatMessage|in %{duration}"
+msgstr ""
+
+msgid "ChatMessage|in %{project_link}"
+msgstr ""
+
+msgid "Check again"
+msgstr ""
+
+msgid "Check feature availability on namespace plan"
+msgstr ""
+
+msgid "Check out branch"
+msgstr ""
+
+msgid "Check out, review, and resolve locally"
+msgstr ""
+
+msgid "Check the %{code_open}elasticsearch.log%{code_close} file to debug why the migration halted and make any changes before retrying the migration. When you fix the cause of the failure, select %{strong_open}Retry migration%{strong_close}, and the migration is scheduled to retry in the background."
+msgstr ""
+
+msgid "Check the current instance configuration "
+msgstr ""
+
+msgid "Check with your administrator."
+msgstr ""
+
+msgid "Check your Docker images for known vulnerabilities."
+msgstr ""
+
+msgid "Check your sign-up restrictions"
+msgstr ""
+
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
+msgid "Checking %{text} availability…"
+msgstr ""
+
+msgid "Checking approval status"
+msgstr ""
+
+msgid "Checking branch availability..."
+msgstr ""
+
+msgid "Checking branch availability…"
+msgstr ""
+
+msgid "Checking group path availability..."
+msgstr ""
+
+msgid "Checking username availability..."
+msgstr ""
+
+msgid "Checkout"
+msgstr ""
+
+msgid "Checkout|$%{pricePerUserPerYear} per user per year"
+msgstr ""
+
+msgid "Checkout|$%{selectedPlanPrice} per 10 GB storage pack per year"
+msgstr ""
+
+msgid "Checkout|$%{selectedPlanPrice} per pack of 1,000 compute minutes"
+msgstr ""
+
+msgid "Checkout|%d compute pack"
+msgid_plural "Checkout|%d compute packs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Checkout|%{cardType} ending in %{lastFourDigits}"
+msgstr ""
+
+msgid "Checkout|%{name}'s GitLab subscription"
+msgstr ""
+
+msgid "Checkout|%{name}'s compute minutes"
+msgstr ""
+
+msgid "Checkout|%{name}'s storage subscription"
+msgstr ""
+
+msgid "Checkout|%{quantity} GB of storage"
+msgstr ""
+
+msgid "Checkout|%{quantity} compute minutes"
+msgstr ""
+
+msgid "Checkout|%{quantity} storage pack"
+msgid_plural "Checkout|%{quantity} storage packs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
+
+msgid "Checkout|%{startDate} - %{endDate}"
+msgstr ""
+
+msgid "Checkout|(may be %{linkStart}charged upon purchase%{linkEnd})"
+msgstr ""
+
+msgid "Checkout|(x%{numberOfUsers})"
+msgstr ""
+
+msgid "Checkout|(x%{quantity})"
+msgstr ""
+
+msgid "Checkout|Add active users before adding a coupon."
+msgstr ""
+
+msgid "Checkout|An unknown error has occurred. Please try again by refreshing this page."
+msgstr ""
+
+msgid "Checkout|Billing address"
+msgstr ""
+
+msgid "Checkout|CI minutes"
+msgstr ""
+
+msgid "Checkout|Calculating your subscription..."
+msgstr ""
+
+msgid "Checkout|Checkout"
+msgstr ""
+
+msgid "Checkout|City"
+msgstr ""
+
+msgid "Checkout|Compute pack"
+msgstr ""
+
+msgid "Checkout|Compute packs are only used after you've used your subscription's monthly quota. The additional compute minutes will roll over month to month and are valid for one year."
+msgstr ""
+
+msgid "Checkout|Confirm purchase"
+msgstr ""
+
+msgid "Checkout|Confirming..."
+msgstr ""
+
+msgid "Checkout|Continue to billing"
+msgstr ""
+
+msgid "Checkout|Continue to payment"
+msgstr ""
+
+msgid "Checkout|Country"
+msgstr ""
+
+msgid "Checkout|Coupon code (optional)"
+msgstr ""
+
+msgid "Checkout|Coupon has been applied and by continuing with your purchase, you accept and agree to the %{linkStart}Coupon Terms%{linkEnd}."
+msgstr ""
+
+msgid "Checkout|Create a new group"
+msgstr ""
+
+msgid "Checkout|Credit card form failed to load. Please try again."
+msgstr ""
+
+msgid "Checkout|Credit card form failed to load: %{message}"
+msgstr ""
+
+msgid "Checkout|Discount"
+msgstr ""
+
+msgid "Checkout|Edit"
+msgstr ""
+
+msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
+msgstr ""
+
+msgid "Checkout|Failed to load countries. Please try again."
+msgstr ""
+
+msgid "Checkout|Failed to load states. Please try again."
+msgstr ""
+
+msgid "Checkout|Failed to load the payment form. Refresh the page and try again."
+msgstr ""
+
+msgid "Checkout|Failed to register credit card. Please try again."
+msgstr ""
+
+msgid "Checkout|GB"
+msgstr ""
+
+msgid "Checkout|GitLab group"
+msgstr ""
+
+msgid "Checkout|GitLab plan"
+msgstr ""
+
+msgid "Checkout|Group"
+msgstr ""
+
+msgid "Checkout|Invalid coupon code. Enter a valid coupon code."
+msgstr ""
+
+msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
+msgstr ""
+
+msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use, plus all over limit members) or more. To buy fewer seats, remove members from the group."
+msgstr ""
+
+msgid "Checkout|Must be 1 or more. Cannot be a decimal."
+msgstr ""
+
+msgid "Checkout|Name of company or organization using GitLab"
+msgstr ""
+
+msgid "Checkout|Name: %{errorMessage}"
+msgstr ""
+
+msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
+msgstr ""
+
+msgid "Checkout|Network Error: %{message}"
+msgstr ""
+
+msgid "Checkout|Number of users"
+msgstr ""
+
+msgid "Checkout|Payment method"
+msgstr ""
+
+msgid "Checkout|Pricing reflective of %{linkStart}limited-time offer%{linkEnd}."
+msgstr ""
+
+msgid "Checkout|Purchase details"
+msgstr ""
+
+msgid "Checkout|Select"
+msgstr ""
+
+msgid "Checkout|Select a country"
+msgstr ""
+
+msgid "Checkout|Select a state"
+msgstr ""
+
+msgid "Checkout|Something went wrong while loading price details."
+msgstr ""
+
+msgid "Checkout|State"
+msgstr ""
+
+msgid "Checkout|Storage packs"
+msgstr ""
+
+msgid "Checkout|Street address"
+msgstr ""
+
+msgid "Checkout|Submitting the credit card form failed with code %{errorCode}: %{errorMessage}"
+msgstr ""
+
+msgid "Checkout|Subscription details"
+msgstr ""
+
+msgid "Checkout|Subtotal"
+msgstr ""
+
+msgid "Checkout|Success: subscription"
+msgstr ""
+
+msgid "Checkout|Tax"
+msgstr ""
+
+msgid "Checkout|Total"
+msgstr ""
+
+msgid "Checkout|Total compute minutes: %{quantity}"
+msgstr ""
+
+msgid "Checkout|Total storage: %{quantity} GB"
+msgstr ""
+
+msgid "Checkout|Users"
+msgstr ""
+
+msgid "Checkout|You'll create your new group after checkout"
+msgstr ""
+
+msgid "Checkout|Your organization"
+msgstr ""
+
+msgid "Checkout|Your storage subscription has the same term as your main subscription, and the price is prorated accordingly."
+msgstr ""
+
+msgid "Checkout|Your subscription will be applied to this group"
+msgstr ""
+
+msgid "Checkout|Zip code"
+msgstr ""
+
+msgid "Checkout|a storage subscription"
+msgstr ""
+
+msgid "Checkout|company or team"
+msgstr ""
+
+msgid "Checkout|compute minutes"
+msgstr ""
+
+msgid "Checkout|x %{quantity} %{units} per pack"
+msgstr ""
+
+msgid "Checkout|x %{quantity} %{units} per pack ="
+msgstr ""
+
+msgid "Cherry-pick this commit"
+msgstr ""
+
+msgid "Cherry-pick this merge request"
+msgstr ""
+
+msgid "Child"
+msgstr ""
+
+msgid "Child epic"
+msgstr ""
+
+msgid "Child issues and epics"
+msgstr ""
+
+msgid "Chinese language support using"
+msgstr ""
+
+msgid "Choose File..."
+msgstr ""
+
+msgid "Choose a file"
+msgstr ""
+
+msgid "Choose a group"
+msgstr ""
+
+msgid "Choose a template"
+msgstr ""
+
+msgid "Choose a template..."
+msgstr ""
+
+msgid "Choose a type..."
+msgstr ""
+
+msgid "Choose an option"
+msgstr ""
+
+msgid "Choose file…"
+msgstr ""
+
+msgid "Choose protected branch"
+msgstr ""
+
+msgid "Choose the top-level group for your repository imports."
+msgstr ""
+
+msgid "Choose visibility level, enable/disable project features and their permissions, disable email notifications, and show default emoji reactions."
+msgstr ""
+
+msgid "Choose what content you want to see on a group’s overview page."
+msgstr ""
+
+msgid "Choose which Git strategy to use when fetching the project."
+msgstr ""
+
+msgid "Choose which branches should be mirrored"
+msgstr ""
+
+msgid "Choose which repositories you want to connect and run CI/CD pipelines."
+msgstr ""
+
+msgid "Choose your framework"
+msgstr ""
+
+msgid "Ci config already present"
+msgstr ""
+
+msgid "CiCatalog|About this project"
+msgstr ""
+
+msgid "CiCatalog|Back to the CI/CD Catalog"
+msgstr ""
+
+msgid "CiCatalog|CI/CD Catalog"
+msgstr ""
+
+msgid "CiCatalog|CI/CD Catalog resource"
+msgstr ""
+
+msgid "CiCatalog|Component ID not found, or you do not have permission to access component."
+msgstr ""
+
+msgid "CiCatalog|Create a pipeline component repository and make reusing pipeline configurations faster and easier."
+msgstr ""
+
+msgid "CiCatalog|Get started with the CI/CD Catalog"
+msgstr ""
+
+msgid "CiCatalog|Go to the project"
+msgstr ""
+
+msgid "CiCatalog|Last release at %{date}"
+msgstr ""
+
+msgid "CiCatalog|Mark project as a CI/CD Catalog resource"
+msgstr ""
+
+msgid "CiCatalog|Mark project as a CI/CD Catalog resource. %{linkStart}What is the CI/CD Catalog?%{linkEnd}"
+msgstr ""
+
+msgid "CiCatalog|No component available"
+msgstr ""
+
+msgid "CiCatalog|No release available"
+msgstr ""
+
+msgid "CiCatalog|Page %{currentPage} of %{totalPage}"
+msgstr ""
+
+msgid "CiCatalog|Released %{timeAgo} by %{author}"
+msgstr ""
+
+msgid "CiCatalog|Repositories of pipeline components available in this namespace."
+msgstr ""
+
+msgid "CiCatalog|The project must contain a README.md file and a template.yml file. When enabled, the repository is available in the CI/CD Catalog."
+msgstr ""
+
+msgid "CiCatalog|There was a problem fetching the CI/CD Catalog setting."
+msgstr ""
+
+msgid "CiCatalog|There was a problem marking the project as a CI/CD Catalog resource."
+msgstr ""
+
+msgid "CiCatalog|There was an error fetching CI/CD Catalog resources."
+msgstr ""
+
+msgid "CiCatalog|This project is now a CI/CD Catalog resource."
+msgstr ""
+
+msgid "CiCatalog|This project will be marked as a CI/CD Catalog resource and will be visible in the CI/CD Catalog. This action is not reversible."
+msgstr ""
+
+msgid "CiCatalog|Unreleased"
+msgstr ""
+
+msgid "CiCatalog|We want to help you create and manage pipeline component repositories, while also making it easier to reuse pipeline configurations. Let us know how we're doing!"
+msgstr ""
+
+msgid "CiCdAnalytics|Date range: %{range}"
+msgstr ""
+
+msgid "CiStatusLabel|canceled"
+msgstr ""
+
+msgid "CiStatusLabel|created"
+msgstr ""
+
+msgid "CiStatusLabel|failed"
+msgstr ""
+
+msgid "CiStatusLabel|manual action"
+msgstr ""
+
+msgid "CiStatusLabel|passed"
+msgstr ""
+
+msgid "CiStatusLabel|passed with warnings"
+msgstr ""
+
+msgid "CiStatusLabel|pending"
+msgstr ""
+
+msgid "CiStatusLabel|preparing"
+msgstr ""
+
+msgid "CiStatusLabel|scheduled"
+msgstr ""
+
+msgid "CiStatusLabel|skipped"
+msgstr ""
+
+msgid "CiStatusLabel|waiting for delayed job"
+msgstr ""
+
+msgid "CiStatusLabel|waiting for manual action"
+msgstr ""
+
+msgid "CiStatusLabel|waiting for resource"
+msgstr ""
+
+msgid "CiStatusText|blocked"
+msgstr ""
+
+msgid "CiStatusText|canceled"
+msgstr ""
+
+msgid "CiStatusText|created"
+msgstr ""
+
+msgid "CiStatusText|delayed"
+msgstr ""
+
+msgid "CiStatusText|failed"
+msgstr ""
+
+msgid "CiStatusText|manual"
+msgstr ""
+
+msgid "CiStatusText|passed"
+msgstr ""
+
+msgid "CiStatusText|pending"
+msgstr ""
+
+msgid "CiStatusText|preparing"
+msgstr ""
+
+msgid "CiStatusText|scheduled"
+msgstr ""
+
+msgid "CiStatusText|skipped"
+msgstr ""
+
+msgid "CiStatusText|waiting"
+msgstr ""
+
+msgid "CiStatusText|warning"
+msgstr ""
+
+msgid "CiStatus|running"
+msgstr ""
+
+msgid "CiVariables|Add Variable"
+msgstr ""
+
+msgid "CiVariables|Add variable"
+msgstr ""
+
+msgid "CiVariables|Attributes"
+msgstr ""
+
+msgid "CiVariables|CI/CD Variables"
+msgstr ""
+
+msgid "CiVariables|Cancel"
+msgstr ""
+
+msgid "CiVariables|Delete variable"
+msgstr ""
+
+msgid "CiVariables|Do you want to delete the variable %{key}?"
+msgstr ""
+
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
+msgid "CiVariables|Environments"
+msgstr ""
+
+msgid "CiVariables|Expand variable reference"
+msgstr ""
+
+msgid "CiVariables|Expanded"
+msgstr ""
+
+msgid "CiVariables|Export variable to pipelines running on protected branches and tags only."
+msgstr ""
+
+msgid "CiVariables|File"
+msgstr ""
+
+msgid "CiVariables|Group"
+msgstr ""
+
+msgid "CiVariables|Input variable key"
+msgstr ""
+
+msgid "CiVariables|Input variable value"
+msgstr ""
+
+msgid "CiVariables|Key"
+msgstr ""
+
+msgid "CiVariables|Mask variable"
+msgstr ""
+
+msgid "CiVariables|Masked"
+msgstr ""
+
+msgid "CiVariables|Maximum number of Inherited Group CI variables loaded (2000)"
+msgstr ""
+
+msgid "CiVariables|Maximum number of variables reached."
+msgstr ""
+
+msgid "CiVariables|Protect variable"
+msgstr ""
+
+msgid "CiVariables|Protected"
+msgstr ""
+
+msgid "CiVariables|Remove inputs"
+msgstr ""
+
+msgid "CiVariables|Remove variable"
+msgstr ""
+
+msgid "CiVariables|Run job"
+msgstr ""
+
+msgid "CiVariables|Run job again"
+msgstr ""
+
+msgid "CiVariables|Scope"
+msgstr ""
+
+msgid "CiVariables|Specify variable values to be used in this run. The variables specified in the configuration file and %{linkStart}CI/CD settings%{linkEnd} are used by default."
+msgstr ""
+
+msgid "CiVariables|State"
+msgstr ""
+
+msgid "CiVariables|There was an error fetching the inherited CI variables."
+msgstr ""
+
+msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
+msgstr ""
+
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
+msgid "CiVariables|Type"
+msgstr ""
+
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
+msgid "CiVariables|Value"
+msgstr ""
+
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
+msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
+msgstr ""
+
+msgid "CiVariables|Variables"
+msgstr ""
+
+msgid "CiVariables|Variables specified here are %{boldStart}expanded%{boldEnd} and not %{boldStart}masked.%{boldEnd}"
+msgstr ""
+
+msgid "CiVariables|Variables store information, like passwords and secret keys, that you can use in job scripts. Each %{entity} can define a maximum of %{limit} variables."
+msgstr ""
+
+msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
+msgstr ""
+
+msgid "CiVariable|All environments"
+msgstr ""
+
+msgid "CiVariable|Create wildcard"
+msgstr ""
+
+msgid "CiVariable|Define a CI/CD variable in the UI"
+msgstr ""
+
+msgid "CiVariable|GitLab CI/CD supports OpenID Connect (OIDC) to give your build and deployment jobs access to cloud credentials and services. %{linkStart}How do I configure OIDC for my cloud provider?%{linkEnd}"
+msgstr ""
+
+msgid "CiVariable|Maximum of %{limit} environments listed. For more environments, enter a search query."
+msgstr ""
+
+msgid "CiVariable|New environment"
+msgstr ""
+
+msgid "CiVariable|Search environments"
+msgstr ""
+
+msgid "CiVariable|Use OIDC to securely connect to cloud services"
+msgstr ""
+
+msgid "CiVariable|Variable %{key} has been deleted."
+msgstr ""
+
+msgid "CiVariable|Variable %{key} has been successfully added."
+msgstr ""
+
+msgid "CiVariable|Variable %{key} has been updated."
+msgstr ""
+
+msgid "Classification Label (optional)"
+msgstr ""
+
+msgid "ClassificationLabelUnavailable|is unavailable: %{reason}"
+msgstr ""
+
+msgid "Clean up after running %{link_start}git filter-repo%{link_end} on the repository."
+msgstr ""
+
+msgid "Cleanup policies are executed by background workers. This setting defines the maximum number of workers that can run concurrently. Set it to 0 to remove all workers and not execute the cleanup policies."
+msgstr ""
+
+msgid "Cleanup policy maximum number of tags to be deleted"
+msgstr ""
+
+msgid "Cleanup policy maximum processing time (seconds)"
+msgstr ""
+
+msgid "Cleanup policy maximum workers running concurrently"
+msgstr ""
+
+msgid "Clear"
+msgstr ""
+
+msgid "Clear %{count} image from cache?"
+msgid_plural "Clear %{count} images from cache?"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Clear All"
+msgstr ""
+
+msgid "Clear all"
+msgstr ""
+
+msgid "Clear all repository checks"
+msgstr ""
+
+msgid "Clear chart filters"
+msgstr ""
+
+msgid "Clear due date"
+msgstr ""
+
+msgid "Clear health status"
+msgstr ""
+
+msgid "Clear recent searches"
+msgstr ""
+
+msgid "Clear repository checks"
+msgstr ""
+
+msgid "Clear search"
+msgstr ""
+
+msgid "Clear search input"
+msgstr ""
+
+msgid "Clear start date"
+msgstr ""
+
+msgid "Clear templates search input"
+msgstr ""
+
+msgid "Clear this checkbox to use a personal access token instead."
+msgstr ""
+
+msgid "Clear this checkbox to use a personal access token or LDAP password instead."
+msgstr ""
+
+msgid "Clear this checkbox to use an external authentication provider instead."
+msgstr ""
+
+msgid "Clear weight"
+msgstr ""
+
+msgid "Cleared health status."
+msgstr ""
+
+msgid "Cleared weight."
+msgstr ""
+
+msgid "Clears health status."
+msgstr ""
+
+msgid "Clears weight."
+msgstr ""
+
+msgid "Click %{link_start}here%{link_end} to view the request."
+msgstr ""
+
+msgid "Click %{link_to} to view the request."
+msgstr ""
+
+msgid "Click the link below to confirm your email address (%{email})"
+msgstr ""
+
+msgid "Click the link below to confirm your email address."
+msgstr ""
+
+msgid "Click to expand"
+msgstr ""
+
+msgid "Click to expand it."
+msgstr ""
+
+msgid "Click to expand text"
+msgstr ""
+
+msgid "Click to hide"
+msgstr ""
+
+msgid "Click to reveal"
+msgstr ""
+
+msgid "Client request timeout"
+msgstr ""
+
+msgid "Clients"
+msgstr ""
+
+msgid "Clientside DSN"
+msgstr ""
+
+msgid "Clientside traces sample rate"
+msgstr ""
+
+msgid "Clone"
+msgstr ""
+
+msgid "Clone repository"
+msgstr ""
+
+msgid "Clone this issue"
+msgstr ""
+
+msgid "Clone with %{http_label}"
+msgstr ""
+
+msgid "Clone with %{protocol}"
+msgstr ""
+
+msgid "Clone with KRB5"
+msgstr ""
+
+msgid "Clone with SSH"
+msgstr ""
+
+msgid "CloneIssue|Cannot clone issue due to insufficient permissions!"
+msgstr ""
+
+msgid "CloneIssue|Cannot clone issue to target project as it is pending deletion."
+msgstr ""
+
+msgid "CloneIssue|Cannot clone issues of '%{issue_type}' type."
+msgstr ""
+
+msgid "Cloned this issue to %{path_to_project}."
+msgstr ""
+
+msgid "Clones this issue, without comments, to %{project}."
+msgstr ""
+
+msgid "Close"
+msgstr ""
+
+msgid "Close %{issuableType}"
+msgstr ""
+
+msgid "Close %{issueType}"
+msgstr ""
+
+msgid "Close %{noteable}"
+msgstr ""
+
+msgid "Close %{tabname}"
+msgstr ""
+
+msgid "Close %{workItemType}"
+msgstr ""
+
+msgid "Close design"
+msgstr ""
+
+msgid "Close epic"
+msgstr ""
+
+msgid "Close milestone"
+msgstr ""
+
+msgid "Close sidebar"
+msgstr ""
+
+msgid "Close this %{quick_action_target}"
+msgstr ""
+
+msgid "Closed"
+msgstr ""
+
+msgid "Closed %{epicTimeagoDate}"
+msgstr ""
+
+msgid "Closed (moved)"
+msgstr ""
+
+msgid "Closed date"
+msgstr ""
+
+msgid "Closed issues"
+msgstr ""
+
+msgid "Closed this %{quick_action_target}."
+msgstr ""
+
+msgid "Closed this issue. Marked as related to, and a duplicate of, %{duplicate_param}."
+msgstr ""
+
+msgid "Closed: %{closed}"
+msgstr ""
+
+msgid "Closes this %{quick_action_target}."
+msgstr ""
+
+msgid "Closes this issue. Marks as related to, and a duplicate of, %{duplicate_reference}."
+msgstr ""
+
+msgid "Closing %{issuableType}..."
+msgstr ""
+
+msgid "Cloud Run"
+msgstr ""
+
+msgid "Cloud SQL instances are fully managed, relational MySQL databases. Google handles replication, patch management, and database management to ensure availability and performance."
+msgstr ""
+
+msgid "Cloud SQL instances are fully managed, relational SQL Server databases. Google handles replication, patch management, and database management to ensure availability and performance."
+msgstr ""
+
+msgid "Cloud Storage"
+msgstr ""
+
+msgid "CloudSeed|AI / ML"
+msgstr ""
+
+msgid "CloudSeed|All"
+msgstr ""
+
+msgid "CloudSeed|AlloyDB for Postgres"
+msgstr ""
+
+msgid "CloudSeed|Available database services through which instances may be created"
+msgstr ""
+
+msgid "CloudSeed|Cancel"
+msgstr ""
+
+msgid "CloudSeed|Cloud Firestore"
+msgstr ""
+
+msgid "CloudSeed|Cloud SQL for MySQL"
+msgstr ""
+
+msgid "CloudSeed|Cloud SQL for Postgres"
+msgstr ""
+
+msgid "CloudSeed|Cloud SQL for SQL Server"
+msgstr ""
+
+msgid "CloudSeed|Cloud SQL instance creation request successful. Expected resolution time is ~5 minutes."
+msgstr ""
+
+msgid "CloudSeed|Cloud SQL instances are fully managed, relational PostgreSQL databases. Google handles replication, patch management, and database management to ensure availability and performance."
+msgstr ""
+
+msgid "CloudSeed|CloudSQL Instance"
+msgstr ""
+
+msgid "CloudSeed|Configuration"
+msgstr ""
+
+msgid "CloudSeed|Configure via Merge Request"
+msgstr ""
+
+msgid "CloudSeed|Create MySQL Instance"
+msgstr ""
+
+msgid "CloudSeed|Create Postgres Instance"
+msgstr ""
+
+msgid "CloudSeed|Create cluster"
+msgstr ""
+
+msgid "CloudSeed|Create database"
+msgstr ""
+
+msgid "CloudSeed|Create instance"
+msgstr ""
+
+msgid "CloudSeed|Database instance is generated within the selected Google Cloud project"
+msgstr ""
+
+msgid "CloudSeed|Database instances associated with this project"
+msgstr ""
+
+msgid "CloudSeed|Database version"
+msgstr ""
+
+msgid "CloudSeed|Databases"
+msgstr ""
+
+msgid "CloudSeed|Deployments"
+msgstr ""
+
+msgid "CloudSeed|Derive insights from unstructured text using Google machine learning"
+msgstr ""
+
+msgid "CloudSeed|Derive insights from your images in the cloud or at the edge"
+msgstr ""
+
+msgid "CloudSeed|Description"
+msgstr ""
+
+msgid "CloudSeed|Determines memory and virtual cores available to your instance"
+msgstr ""
+
+msgid "CloudSeed|Enhance security by storing database variables in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
+msgstr ""
+
+msgid "CloudSeed|Environment"
+msgstr ""
+
+msgid "CloudSeed|Flexible, scalable NoSQL cloud database for client- and server-side development"
+msgstr ""
+
+msgid "CloudSeed|Fully managed PostgreSQL-compatible service for high-demand workloads"
+msgstr ""
+
+msgid "CloudSeed|Fully managed relational database service for MySQL"
+msgstr ""
+
+msgid "CloudSeed|Fully managed relational database service for PostgreSQL"
+msgstr ""
+
+msgid "CloudSeed|Fully managed relational database service for SQL Server"
+msgstr ""
+
+msgid "CloudSeed|Generated database instance is linked to the selected branch or tag"
+msgstr ""
+
+msgid "CloudSeed|Google Cloud Error - %{message}"
+msgstr ""
+
+msgid "CloudSeed|Google Cloud Project"
+msgstr ""
+
+msgid "CloudSeed|Google Cloud project"
+msgstr ""
+
+msgid "CloudSeed|Google Cloud's AI tools are armed with the best of Google's research and technology to help developers focus exclusively on solving problems that matter"
+msgstr ""
+
+msgid "CloudSeed|I accept Google Cloud pricing and responsibilities involved with managing database instances"
+msgstr ""
+
+msgid "CloudSeed|Instances"
+msgstr ""
+
+msgid "CloudSeed|Language AI"
+msgstr ""
+
+msgid "CloudSeed|Learn more about pricing for %{cloudsqlPricingStart}Cloud SQL%{cloudsqlPricingEnd}, %{alloydbPricingStart}Alloy DB%{alloydbPricingEnd}, %{memorystorePricingStart}Memorystore%{memorystorePricingEnd} and %{firestorePricingStart}Firestore%{firestorePricingEnd}."
+msgstr ""
+
+msgid "CloudSeed|Machine type"
+msgstr ""
+
+msgid "CloudSeed|Make your content and apps multilingual with fast, dynamic machine translation"
+msgstr ""
+
+msgid "CloudSeed|Memorystore for Redis"
+msgstr ""
+
+msgid "CloudSeed|No instances"
+msgstr ""
+
+msgid "CloudSeed|Refs"
+msgstr ""
+
+msgid "CloudSeed|Regions"
+msgstr ""
+
+msgid "CloudSeed|Scalable, secure, and highly available in-memory service for Redis"
+msgstr ""
+
+msgid "CloudSeed|Service"
+msgstr ""
+
+msgid "CloudSeed|Service Account"
+msgstr ""
+
+msgid "CloudSeed|Services"
+msgstr ""
+
+msgid "CloudSeed|There are no instances to display."
+msgstr ""
+
+msgid "CloudSeed|Translation AI"
+msgstr ""
+
+msgid "CloudSeed|Version"
+msgstr ""
+
+msgid "CloudSeed|Vision AI"
+msgstr ""
+
+msgid "Cluster"
+msgstr ""
+
+msgid "Cluster Health"
+msgstr ""
+
+msgid "Cluster cache cleared."
+msgstr ""
+
+msgid "Cluster level"
+msgstr ""
+
+msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
+msgstr ""
+
+msgid "ClusterAgents|%{name} successfully deleted"
+msgstr ""
+
+msgid "ClusterAgents|%{name} successfully revoked"
+msgstr ""
+
+msgid "ClusterAgents|%{number} of %{total} agents"
+msgstr ""
+
+msgid "ClusterAgents|%{number} of %{total} clusters connected through cluster certificates"
+msgstr ""
+
+msgid "ClusterAgents|%{titleIcon}Connected"
+msgstr ""
+
+msgid "ClusterAgents|%{titleIcon}Not connected"
+msgstr ""
+
+msgid "ClusterAgents|%{tokenName} created"
+msgstr ""
+
+msgid "ClusterAgents|%{tokenName} revoked"
+msgstr ""
+
+msgid "ClusterAgents|Access tokens"
+msgstr ""
+
+msgid "ClusterAgents|Add an agent configuration file to %{linkStart}this repository%{linkEnd} and select it, or create a new one to register with GitLab:"
+msgstr ""
+
+msgid "ClusterAgents|Advanced installation methods"
+msgstr ""
+
+msgid "ClusterAgents|Agent"
+msgstr ""
+
+msgid "ClusterAgents|Agent %{strongStart}connected%{strongEnd}"
+msgstr ""
+
+msgid "ClusterAgents|Agent %{strongStart}disconnected%{strongEnd}"
+msgstr ""
+
+msgid "ClusterAgents|Agent ID #%{agentId}"
+msgstr ""
+
+msgid "ClusterAgents|Agent access token:"
+msgstr ""
+
+msgid "ClusterAgents|Agent might not be connected to GitLab"
+msgstr ""
+
+msgid "ClusterAgents|Agent never connected to GitLab"
+msgstr ""
+
+msgid "ClusterAgents|Agent version mismatch"
+msgstr ""
+
+msgid "ClusterAgents|Agent version mismatch and update"
+msgstr ""
+
+msgid "ClusterAgents|Agent version update required"
+msgstr ""
+
+msgid "ClusterAgents|All"
+msgstr ""
+
+msgid "ClusterAgents|An error occurred while loading your agent"
+msgstr ""
+
+msgid "ClusterAgents|An error occurred while loading your agents"
+msgstr ""
+
+msgid "ClusterAgents|An error occurred while retrieving agent activity. Reload the page to try again."
+msgstr ""
+
+msgid "ClusterAgents|An unknown error occurred. Please try again."
+msgstr ""
+
+msgid "ClusterAgents|Are you sure you want to delete this agent? You cannot undo this."
+msgstr ""
+
+msgid "ClusterAgents|Are you sure you want to revoke this token? You cannot undo this action."
+msgstr ""
+
+msgid "ClusterAgents|CI/CD workflow with restricted access"
+msgstr ""
+
+msgid "ClusterAgents|Certificate"
+msgstr ""
+
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect a Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterAgents|Connect a cluster"
+msgstr ""
+
+msgid "ClusterAgents|Connect a cluster (agent)"
+msgstr ""
+
+msgid "ClusterAgents|Connect a cluster (certificate - deprecated)"
+msgstr ""
+
+msgid "ClusterAgents|Connect a cluster (deprecated)"
+msgstr ""
+
+msgid "ClusterAgents|Connected"
+msgstr ""
+
+msgid "ClusterAgents|Connection status"
+msgstr ""
+
+msgid "ClusterAgents|Copy command"
+msgstr ""
+
+msgid "ClusterAgents|Copy token"
+msgstr ""
+
+msgid "ClusterAgents|Create a cluster"
+msgstr ""
+
+msgid "ClusterAgents|Create agent access token"
+msgstr ""
+
+msgid "ClusterAgents|Create agent: %{searchTerm}"
+msgstr ""
+
+msgid "ClusterAgents|Create token"
+msgstr ""
+
+msgid "ClusterAgents|Created by"
+msgstr ""
+
+msgid "ClusterAgents|Created by %{name} %{time}"
+msgstr ""
+
+msgid "ClusterAgents|Date created"
+msgstr ""
+
+msgid "ClusterAgents|Default configuration"
+msgstr ""
+
+msgid "ClusterAgents|Delete"
+msgstr ""
+
+msgid "ClusterAgents|Delete agent"
+msgstr ""
+
+msgid "ClusterAgents|Deprecated"
+msgstr ""
+
+msgid "ClusterAgents|Description"
+msgstr ""
+
+msgid "ClusterAgents|Event occurred"
+msgstr ""
+
+msgid "ClusterAgents|External project"
+msgstr ""
+
+msgid "ClusterAgents|Failed to create a token"
+msgstr ""
+
+msgid "ClusterAgents|Failed to register an agent"
+msgstr ""
+
+msgid "ClusterAgents|From a terminal, connect to your cluster and run this command. The token is included in the command."
+msgstr ""
+
+msgid "ClusterAgents|GitLab agent"
+msgstr ""
+
+msgid "ClusterAgents|GitLab agent for Kubernetes"
+msgstr ""
+
+msgid "ClusterAgents|Give feedback"
+msgstr ""
+
+msgid "ClusterAgents|How do I register an agent?"
+msgstr ""
+
+msgid "ClusterAgents|How to update an agent?"
+msgstr ""
+
+msgid "ClusterAgents|Install using Helm (recommended)"
+msgstr ""
+
+msgid "ClusterAgents|Integration Status"
+msgstr ""
+
+msgid "ClusterAgents|Last connected %{timeAgo}."
+msgstr ""
+
+msgid "ClusterAgents|Last contact"
+msgstr ""
+
+msgid "ClusterAgents|Learn how to troubleshoot"
+msgstr ""
+
+msgid "ClusterAgents|Make sure you are using a valid token."
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|Never"
+msgstr ""
+
+msgid "ClusterAgents|Never connected"
+msgstr ""
+
+msgid "ClusterAgents|No activity occurred in the past day"
+msgid_plural "ClusterAgents|No activity occurred in the past %d days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ClusterAgents|No agent access token"
+msgstr ""
+
+msgid "ClusterAgents|No agents"
+msgstr ""
+
+msgid "ClusterAgents|No clusters connected through cluster certificates"
+msgstr ""
+
+msgid "ClusterAgents|Not connected"
+msgstr ""
+
+msgid "ClusterAgents|Premium"
+msgstr ""
+
+msgid "ClusterAgents|Recommended"
+msgstr ""
+
+msgid "ClusterAgents|Register"
+msgstr ""
+
+msgid "ClusterAgents|Registering agent"
+msgstr ""
+
+msgid "ClusterAgents|Requires a Maintainer or greater role to delete agents"
+msgstr ""
+
+msgid "ClusterAgents|Requires a Maintainer or greater role to perform these actions"
+msgstr ""
+
+msgid "ClusterAgents|Requires a Maintainer or greater role to perform this action"
+msgstr ""
+
+msgid "ClusterAgents|Revoke access token?"
+msgstr ""
+
+msgid "ClusterAgents|Revoke token"
+msgstr ""
+
+msgid "ClusterAgents|Security"
+msgstr ""
+
+msgid "ClusterAgents|See agent activity updates, like tokens created or revoked and clusters connected or not connected."
+msgstr ""
+
+msgid "ClusterAgents|Select an agent or enter a name to create new"
+msgstr ""
+
+msgid "ClusterAgents|Tell us what you think"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab agent provides an increased level of security when connecting Kubernetes clusters to GitLab. %{linkStart}Learn more about the GitLab agent.%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The agent has not been connected in a long time. There might be a connectivity issue. Last contact was %{timeAgo}."
+msgstr ""
+
+msgid "ClusterAgents|The agent uses the token to connect with GitLab."
+msgstr ""
+
+msgid "ClusterAgents|The agent version do not match each other across your cluster's pods. This can happen when a new agent version was just deployed and Kubernetes is shutting down the old pods."
+msgstr ""
+
+msgid "ClusterAgents|This agent has no tokens"
+msgstr ""
+
+msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
+msgstr ""
+
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
+msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
+msgstr ""
+
+msgid "ClusterAgents|Token created by %{userName}"
+msgstr ""
+
+msgid "ClusterAgents|Token revoked by %{userName}"
+msgstr ""
+
+msgid "ClusterAgents|Unknown user"
+msgstr ""
+
+msgid "ClusterAgents|Use a Helm version compatible with your Kubernetes version (see %{linkStart}Helm version support policy%{linkEnd})."
+msgstr ""
+
+msgid "ClusterAgents|Valid access token"
+msgstr ""
+
+msgid "ClusterAgents|View all %{number} agents"
+msgstr ""
+
+msgid "ClusterAgents|View all %{number} clusters"
+msgstr ""
+
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
+msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
+msgstr ""
+
+msgid "ClusterAgents|What is agent activity?"
+msgstr ""
+
+msgid "ClusterAgents|What is default configuration?"
+msgstr ""
+
+msgid "ClusterAgents|You cannot see this token again after you close this window."
+msgstr ""
+
+msgid "ClusterAgents|You will need to create a token to connect to your agent"
+msgstr ""
+
+msgid "ClusterAgents|Your agent version is out of sync with your GitLab version (v%{version}), which might cause compatibility problems. Update the agent installed on your cluster to the most recent version."
+msgstr ""
+
+msgid "ClusterAgents|Your instance doesn't have the %{linkStart}GitLab Agent Server (KAS)%{linkEnd} set up. Ask a GitLab Administrator to install it."
+msgstr ""
+
+msgid "ClusterAgents|shared"
+msgstr ""
+
+msgid "ClusterAgent|An agent can have only two active tokens at a time"
+msgstr ""
+
+msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
+msgstr ""
+
+msgid "ClusterAgent|User has insufficient permissions to revoke the token for this project"
+msgstr ""
+
+msgid "ClusterAgent|You have insufficient permissions to create a cluster agent for this project"
+msgstr ""
+
+msgid "ClusterAgent|You have insufficient permissions to delete this cluster agent"
+msgstr ""
+
+msgid "ClusterIntegration|%{linkStart}More information%{linkEnd}"
+msgstr ""
+
+msgid "ClusterIntegration|A cluster management project can be used to run deployment jobs with Kubernetes %{code_open}cluster-admin%{code_close} privileges."
+msgstr ""
+
+msgid "ClusterIntegration|A service token scoped to %{code}kube-system%{end_code} with %{code}cluster-admin%{end_code} privileges."
+msgstr ""
+
+msgid "ClusterIntegration|API URL"
+msgstr ""
+
+msgid "ClusterIntegration|API URL should be a valid http/https url."
+msgstr ""
+
+msgid "ClusterIntegration|Add Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Adding a Kubernetes cluster to your group will automatically share the cluster across all your projects. Use review apps, deploy your applications, and easily run your pipelines for all projects using the same cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Adding a Kubernetes cluster will automatically share the cluster across all projects. Use review apps, deploy your applications, and easily run your pipelines for all projects using the same cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Adding an integration to your group will share the cluster across all your projects."
+msgstr ""
+
+msgid "ClusterIntegration|Adding an integration will share the cluster across all projects."
+msgstr ""
+
+msgid "ClusterIntegration|Advanced options on this Kubernetes cluster’s integration"
+msgstr ""
+
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Amazon EKS"
+msgstr ""
+
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
+msgid "ClusterIntegration|Any project namespaces"
+msgstr ""
+
+msgid "ClusterIntegration|Apply for credit"
+msgstr ""
+
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
+msgid "ClusterIntegration|Base domain"
+msgstr ""
+
+msgid "ClusterIntegration|CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
+msgstr ""
+
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose which of your environments will use this cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Civo Kubernetes"
+msgstr ""
+
+msgid "ClusterIntegration|Clear cluster cache"
+msgstr ""
+
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|Cluster management project"
+msgstr ""
+
+msgid "ClusterIntegration|Cluster name is required."
+msgstr ""
+
+msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
+msgid "ClusterIntegration|Connect a Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Connect your cluster to GitLab through %{linkStart}cluster certificates%{linkEnd}."
+msgstr ""
+
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
+msgid "ClusterIntegration|Copy API URL"
+msgstr ""
+
+msgid "ClusterIntegration|Copy CA Certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Copy Kubernetes cluster name"
+msgstr ""
+
+msgid "ClusterIntegration|Create a Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Did you know?"
+msgstr ""
+
+msgid "ClusterIntegration|Elastic Kubernetes Service"
+msgstr ""
+
+msgid "ClusterIntegration|Enable or disable GitLab's connection to your Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Enable this setting if using role-based access control (RBAC)."
+msgstr ""
+
+msgid "ClusterIntegration|Enter details about your cluster. %{linkStart}How do I use a certificate to connect to my cluster?%{linkEnd}"
+msgstr ""
+
+msgid "ClusterIntegration|Enter new Service Token"
+msgstr ""
+
+msgid "ClusterIntegration|Enter your Kubernetes cluster certificate details"
+msgstr ""
+
+msgid "ClusterIntegration|Environment scope"
+msgstr ""
+
+msgid "ClusterIntegration|Environment scope is required."
+msgstr ""
+
+msgid "ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab's Google Kubernetes Engine Integration."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab Integration"
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab-managed cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Google GKE"
+msgstr ""
+
+msgid "ClusterIntegration|Google Kubernetes Engine"
+msgstr ""
+
+msgid "ClusterIntegration|Group cluster"
+msgstr ""
+
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
+msgid "ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration."
+msgstr ""
+
+msgid "ClusterIntegration|Instance cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Integration disabled"
+msgstr ""
+
+msgid "ClusterIntegration|Integration enabled"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster is being created..."
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster name"
+msgstr ""
+
+msgid "ClusterIntegration|Kubernetes cluster was successfully created."
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about Kubernetes."
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about group Kubernetes clusters"
+msgstr ""
+
+msgid "ClusterIntegration|Learn more about instance Kubernetes clusters"
+msgstr ""
+
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
+msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
+msgstr ""
+
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
+msgid "ClusterIntegration|Project cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace (optional, unique)"
+msgstr ""
+
+msgid "ClusterIntegration|Project namespace prefix (optional, unique)"
+msgstr ""
+
+msgid "ClusterIntegration|Provider details"
+msgstr ""
+
+msgid "ClusterIntegration|RBAC-enabled cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Remove Kubernetes cluster integration"
+msgstr ""
+
+msgid "ClusterIntegration|Remove integration"
+msgstr ""
+
+msgid "ClusterIntegration|Remove integration and resources"
+msgstr ""
+
+msgid "ClusterIntegration|Remove integration and resources?"
+msgstr ""
+
+msgid "ClusterIntegration|Remove integration?"
+msgstr ""
+
+msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
+msgstr ""
+
+msgid "ClusterIntegration|Save changes"
+msgstr ""
+
+msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Service Token"
+msgstr ""
+
+msgid "ClusterIntegration|Service token is required."
+msgstr ""
+
+msgid "ClusterIntegration|Set a prefix for your namespaces. If not set, defaults to your project path. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong on our end."
+msgstr ""
+
+msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster"
+msgstr ""
+
+msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{linkStart}Auto DevOps.%{linkEnd} The domain should have a wildcard DNS configured matching the domain. "
+msgstr ""
+
+msgid "ClusterIntegration|The Kubernetes certificate used to authenticate to the cluster."
+msgstr ""
+
+msgid "ClusterIntegration|The URL used to access the Kubernetes API."
+msgstr ""
+
+msgid "ClusterIntegration|The certificate-based Kubernetes integration is deprecated and will be removed in the future. You should %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. For more information, see the %{deprecationLinkStart}deprecation epic%{deprecationLinkEnd}, or contact GitLab support."
+msgstr ""
+
+msgid "ClusterIntegration|The certificate-based Kubernetes integration is deprecated and will be removed in the future. You should %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. For more information, see the %{deprecationLinkStart}deprecation epic%{deprecationLinkEnd}."
+msgstr ""
+
+msgid "ClusterIntegration|The certificate-based method to connect clusters to GitLab was %{linkStart}deprecated%{linkEnd} in GitLab 14.5."
+msgstr ""
+
+msgid "ClusterIntegration|The namespace associated with your project. This will be used for deploy boards, and Web terminals."
+msgstr ""
+
+msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
+msgstr ""
+
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
+msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
+msgstr ""
+
+msgid "ClusterIntegration|This process is %{issue_link_start}deprecated%{issue_link_end}. Use the %{docs_link_start}the GitLab agent for Kubernetes%{docs_link_end} instead."
+msgstr ""
+
+msgid "ClusterIntegration|This will permanently delete the following resources:"
+msgstr ""
+
+msgid "ClusterIntegration|To remove your integration and resources, type %{clusterName} to confirm:"
+msgstr ""
+
+msgid "ClusterIntegration|To remove your integration, type %{clusterName} to confirm:"
+msgstr ""
+
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
+msgid "ClusterIntegration|Use GitLab to deploy to your cluster, run jobs, use review apps, and more."
+msgstr ""
+
+msgid "ClusterIntegration|Use the %{linkStart}GitLab agent%{linkEnd} to safely connect your Kubernetes clusters to GitLab. You can deploy your applications, run your pipelines, use Review Apps, and much more."
+msgstr ""
+
+msgid "ClusterIntegration|Using AutoDevOps with multiple clusters? %{help_link_start}Read this first.%{help_link_end}"
+msgstr ""
+
+msgid "ClusterIntegration|Where do you want to create a cluster?"
+msgstr ""
+
+msgid "ClusterIntegration|You are about to remove your cluster integration and all GitLab-created resources associated with this cluster."
+msgstr ""
+
+msgid "ClusterIntegration|You are about to remove your cluster integration."
+msgstr ""
+
+msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
+msgstr ""
+
+msgid "ClusterIntegration|sign up"
+msgstr ""
+
+msgid "Clusters|An error occurred while loading clusters"
+msgstr ""
+
+msgid "Code"
+msgstr ""
+
+msgid "Code Coverage: %{coveragePercentage}%{percentSymbol}"
+msgstr ""
+
+msgid "Code Coverage| Empty code coverage data"
+msgstr ""
+
+msgid "Code Coverage|Couldn't fetch the code coverage data"
+msgstr ""
+
+msgid "Code Owner"
+msgstr ""
+
+msgid "Code Owners"
+msgstr ""
+
+msgid "Code Quality"
+msgstr ""
+
+msgid "Code Quality scans found %{degradation} and %{improvement}."
+msgstr ""
+
+msgid "Code Quality scans found %{findings}."
+msgstr ""
+
+msgid "Code Review"
+msgstr ""
+
+msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
+msgstr ""
+
+msgid "Code Suggestions add-on status"
+msgstr ""
+
+msgid "Code block"
+msgstr ""
+
+msgid "Code can be imported from enabled sources during project creation. OmniAuth must be configured for GitHub"
+msgstr ""
+
+msgid "Code coverage statistics for %{ref} %{start_date} - %{end_date}"
+msgstr ""
+
+msgid "Code owner approval is required"
+msgstr ""
+
+msgid "Code review"
+msgstr ""
+
+msgid "Code review analytics"
+msgstr ""
+
+msgid "Code snippet"
+msgstr ""
+
+msgid "Code snippet copied. Insert it in the correct location in the YAML file."
+msgstr ""
+
+msgid "CodeIntelligence|This is the definition"
+msgstr ""
+
+msgid "CodeNavigation|No references found"
+msgstr ""
+
+msgid "CodeOwners|An error occurred while loading code owners."
+msgstr ""
+
+msgid "CodeOwners|Assign users and groups as approvers for specific file changes."
+msgstr ""
+
+msgid "CodeOwners|Code owners"
+msgstr ""
+
+msgid "CodeOwners|Code owners are users and groups that can approve specific file changes."
+msgstr ""
+
+msgid "CodeOwners|Hide all"
+msgstr ""
+
+msgid "CodeOwners|Learn more."
+msgstr ""
+
+msgid "CodeOwners|Show all"
+msgstr ""
+
+msgid "CodeOwner|Pattern"
+msgstr ""
+
+msgid "CodeSuggestionsSM|By enabling this feature, you agree to the %{terms_link_start}GitLab Testing Agreement%{link_end} and acknowledge that GitLab will send data from the instance, including personal data, to our %{ai_docs_link_start}AI providers%{link_end} to provide this feature."
+msgstr ""
+
+msgid "CodeSuggestionsSM|Code Suggestions"
+msgstr ""
+
+msgid "CodeSuggestionsSM|Enable Code Suggestions for this instance %{beta}"
+msgstr ""
+
+msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
+msgstr ""
+
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgstr ""
+
+msgid "CodeSuggestions|Code Suggestions"
+msgstr ""
+
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
+msgstr ""
+
+msgid "CodeSuggestions|Enable Code Suggestions"
+msgstr ""
+
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
+msgstr ""
+
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
+msgstr ""
+
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
+msgstr ""
+
+msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
+msgstr ""
+
+msgid "CodeSuggestions|Subject to the %{terms_link_start}Testing Terms of Use%{link_end}. Code Suggestions currently uses third-party AI services unless those are %{third_party_features_link_start}disabled%{link_end}."
+msgstr ""
+
+msgid "CodeownersValidation|An error occurred while loading the validation errors. Please try again later."
+msgstr ""
+
+msgid "CodeownersValidation|Contains %d syntax error."
+msgid_plural "CodeownersValidation|Contains %d syntax errors."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "CodeownersValidation|Entries with spaces"
+msgstr ""
+
+msgid "CodeownersValidation|Hide errors"
+msgstr ""
+
+msgid "CodeownersValidation|How are errors handled?"
+msgstr ""
+
+msgid "CodeownersValidation|Inaccessible owners"
+msgstr ""
+
+msgid "CodeownersValidation|Less than 1 required approvals"
+msgstr ""
+
+msgid "CodeownersValidation|Line"
+msgstr ""
+
+msgid "CodeownersValidation|Missing section name"
+msgstr ""
+
+msgid "CodeownersValidation|Show errors"
+msgstr ""
+
+msgid "CodeownersValidation|Syntax is valid."
+msgstr ""
+
+msgid "CodeownersValidation|Unparsable sections"
+msgstr ""
+
+msgid "CodeownersValidation|Zero owners"
+msgstr ""
+
+msgid "Cohorts|Inactive users"
+msgstr ""
+
+msgid "Cohorts|Month %{month_index}"
+msgstr ""
+
+msgid "Cohorts|New users"
+msgstr ""
+
+msgid "Cohorts|Registration month"
+msgstr ""
+
+msgid "Cohorts|Returning users"
+msgstr ""
+
+msgid "Cohorts|User cohorts are shown for the last %{months_included} months. Only users with activity are counted in the 'New users' column; inactive users are counted separately."
+msgstr ""
+
+msgid "Collapse"
+msgstr ""
+
+msgid "Collapse AI-generated summary"
+msgstr ""
+
+msgid "Collapse all threads"
+msgstr ""
+
+msgid "Collapse eligible approvers"
+msgstr ""
+
+msgid "Collapse issues"
+msgstr ""
+
+msgid "Collapse jobs"
+msgstr ""
+
+msgid "Collapse merge details"
+msgstr ""
+
+msgid "Collapse milestones"
+msgstr ""
+
+msgid "Collapse replies"
+msgstr ""
+
+msgid "Collapse settings section"
+msgstr ""
+
+msgid "Collapse sidebar"
+msgstr ""
+
+msgid "Collapses this file (only for you) until it’s changed again."
+msgstr ""
+
+msgid "Collector hostname"
+msgstr ""
+
+msgid "Color"
+msgstr ""
+
+msgid "ColorWidget|An error occurred while updating color."
+msgstr ""
+
+msgid "ColorWidget|Assign epic color"
+msgstr ""
+
+msgid "ColorWidget|Color"
+msgstr ""
+
+msgid "ColorWidget|Error fetching epic color."
+msgstr ""
+
+msgid "Colorize messages"
+msgstr ""
+
+msgid "ComboSearch is not defined"
+msgstr ""
+
+msgid "Comma-separated list of email addresses."
+msgstr ""
+
+msgid "Command"
+msgstr ""
+
+msgid "Command id '%{command}' must not start with '%{prefix}'"
+msgstr ""
+
+msgid "Command line instructions"
+msgstr ""
+
+msgid "CommandPalette|Global Commands"
+msgstr ""
+
+msgid "CommandPalette|Pages"
+msgstr ""
+
+msgid "CommandPalette|Project files"
+msgstr ""
+
+msgid "CommandPalette|Type %{commandHandle} for command, %{userHandle} for user, %{projectHandle} for project, %{pathHandle} for project file, or perform generic search..."
+msgstr ""
+
+msgid "CommandPalette|command"
+msgstr ""
+
+msgid "CommandPalette|go to project file"
+msgstr ""
+
+msgid "CommandPalette|issue (enter at least 3 chars)"
+msgstr ""
+
+msgid "CommandPalette|project (enter at least 3 chars)"
+msgstr ""
+
+msgid "CommandPalette|user (enter at least 3 chars)"
+msgstr ""
+
+msgid "Commands applied"
+msgstr ""
+
+msgid "Commands did not apply"
+msgstr ""
+
+msgid "Comment"
+msgstr ""
+
+msgid "Comment '%{label}' position"
+msgstr ""
+
+msgid "Comment Templates"
+msgstr ""
+
+msgid "Comment added to the timeline."
+msgstr ""
+
+msgid "Comment form position"
+msgstr ""
+
+msgid "Comment is being updated"
+msgstr ""
+
+msgid "Comment on lines %{startLine} to %{endLine}"
+msgstr ""
+
+msgid "Comment on this file"
+msgstr ""
+
+msgid "Comment template actions"
+msgstr ""
+
+msgid "Comment templates"
+msgstr ""
+
+msgid "Comment templates can be used when creating comments inside issues, merge requests, and epics."
+msgstr ""
+
+msgid "Comment type"
+msgstr ""
+
+msgid "Comment/Reply (quoting selected text)"
+msgstr ""
+
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
+msgstr ""
+
+msgid "Comments"
+msgstr ""
+
+msgid "Commit"
+msgid_plural "Commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Commit %{commit_id}"
+msgstr ""
+
+msgid "Commit (when editing commit message)"
+msgstr ""
+
+msgid "Commit Message"
+msgstr ""
+
+msgid "Commit SHA"
+msgstr ""
+
+msgid "Commit changes"
+msgstr ""
+
+msgid "Commit deleted"
+msgstr ""
+
+msgid "Commit message"
+msgstr ""
+
+msgid "Commit message generated by AI"
+msgstr ""
+
+msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
+msgstr ""
+
+msgid "CommitBoxTitle|Commit"
+msgstr ""
+
+msgid "CommitMessage|Add %{file_name}"
+msgstr ""
+
+msgid "CommitSignature|This commit was signed with a key that was revoked."
+msgstr ""
+
+msgid "CommitSignature|Unverified"
+msgstr ""
+
+msgid "CommitSignature|Unverified signature"
+msgstr ""
+
+msgid "CommitWidget|authored"
+msgstr ""
+
+msgid "Commits"
+msgstr ""
+
+msgid "Commits & branches"
+msgstr ""
+
+msgid "Commits feed"
+msgstr ""
+
+msgid "Commits per day hour (UTC)"
+msgstr ""
+
+msgid "Commits per day of month"
+msgstr ""
+
+msgid "Commits per weekday"
+msgstr ""
+
+msgid "Commits to"
+msgstr ""
+
+msgid "Commits you select appear here. Go to the first tab and select commits to add to this merge request."
+msgstr ""
+
+msgid "Commits:"
+msgstr ""
+
+msgid "Commits|An error occurred while fetching merge requests data."
+msgstr ""
+
+msgid "Commits|No related merge requests found"
+msgstr ""
+
+msgid "Committed by"
+msgstr ""
+
+msgid "Committed-after"
+msgstr ""
+
+msgid "Committed-before"
+msgstr ""
+
+msgid "Commit|Branches"
+msgstr ""
+
+msgid "Commit|Tags"
+msgstr ""
+
+msgid "Commit|There was an error fetching the commit references. Please try again later."
+msgstr ""
+
+msgid "Commit|containing commit"
+msgstr ""
+
+msgid "Community forum"
+msgstr ""
+
+msgid "Company"
+msgstr ""
+
+msgid "Company Name"
+msgstr ""
+
+msgid "Compare"
+msgstr ""
+
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
+msgid "Compare GitLab editions"
+msgstr ""
+
+msgid "Compare GitLab plans"
+msgstr ""
+
+msgid "Compare branches and continue"
+msgstr ""
+
+msgid "Compare changes"
+msgstr ""
+
+msgid "Compare changes with the last commit"
+msgstr ""
+
+msgid "Compare changes with the merge request target branch"
+msgstr ""
+
+msgid "Compare revisions"
+msgstr ""
+
+msgid "Compare submodule commit revisions"
+msgstr ""
+
+msgid "Compare with previous version"
+msgstr ""
+
+msgid "CompareRevisions|%{source_branch} and %{target_branch} are the same."
+msgstr ""
+
+msgid "CompareRevisions|Branches"
+msgstr ""
+
+msgid "CompareRevisions|Changes are shown as if the %{boldStart}source%{boldEnd} revision was being merged into the %{boldStart}target%{boldEnd} revision. %{linkStart}Learn more about comparing revisions.%{linkEnd}"
+msgstr ""
+
+msgid "CompareRevisions|Commits on Source (%{commits_amount})"
+msgstr ""
+
+msgid "CompareRevisions|Compare"
+msgstr ""
+
+msgid "CompareRevisions|Compare revisions"
+msgstr ""
+
+msgid "CompareRevisions|Create merge request"
+msgstr ""
+
+msgid "CompareRevisions|Filter by Git revision"
+msgstr ""
+
+msgid "CompareRevisions|Include changes to target since source was created"
+msgstr ""
+
+msgid "CompareRevisions|Only incoming changes from source"
+msgstr ""
+
+msgid "CompareRevisions|Select Git revision"
+msgstr ""
+
+msgid "CompareRevisions|Select branch/tag"
+msgstr ""
+
+msgid "CompareRevisions|Select target project"
+msgstr ""
+
+msgid "CompareRevisions|Show changes"
+msgstr ""
+
+msgid "CompareRevisions|Swap"
+msgstr ""
+
+msgid "CompareRevisions|Swap revisions"
+msgstr ""
+
+msgid "CompareRevisions|Tags"
+msgstr ""
+
+msgid "CompareRevisions|There isn't anything to compare."
+msgstr ""
+
+msgid "CompareRevisions|There was an error while loading the branch/tag list. Please try again."
+msgstr ""
+
+msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
+msgstr ""
+
+msgid "CompareRevisions|View open merge request"
+msgstr ""
+
+msgid "Complete"
+msgstr ""
+
+msgid "Complete verification to sign in."
+msgstr ""
+
+msgid "Complete verification to sign up."
+msgstr ""
+
+msgid "Complete with errors"
+msgstr ""
+
+msgid "Completed"
+msgstr ""
+
+msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
+msgstr ""
+
+msgid "Compliance Center|Export frameworks as CSV. You will be emailed after the export is processed."
+msgstr ""
+
+msgid "Compliance Center|Export full report as CSV"
+msgstr ""
+
+msgid "Compliance Center|Export merge request violations as CSV. You will be emailed after the export is processed."
+msgstr ""
+
+msgid "Compliance Center|Frameworks"
+msgstr ""
+
+msgid "Compliance Center|Standards Adherence"
+msgstr ""
+
+msgid "Compliance Center|Violations"
+msgstr ""
+
+msgid "Compliance center"
+msgstr ""
+
+msgid "Compliance framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
+msgid "ComplianceFrameworks|Add framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|Background color"
+msgstr ""
+
+msgid "ComplianceFrameworks|Cancel"
+msgstr ""
+
+msgid "ComplianceFrameworks|Compliance Frameworks Export"
+msgstr ""
+
+msgid "ComplianceFrameworks|Compliance framework created"
+msgstr ""
+
+msgid "ComplianceFrameworks|Compliance framework deleted successfully"
+msgstr ""
+
+msgid "ComplianceFrameworks|Compliance pipeline configuration (optional)"
+msgstr ""
+
+msgid "ComplianceFrameworks|Configuration not found"
+msgstr ""
+
+msgid "ComplianceFrameworks|Default compliance framework successfully updated"
+msgstr ""
+
+msgid "ComplianceFrameworks|Delete compliance framework %{framework}"
+msgstr ""
+
+msgid "ComplianceFrameworks|Delete framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|Description"
+msgstr ""
+
+msgid "ComplianceFrameworks|Description is required"
+msgstr ""
+
+msgid "ComplianceFrameworks|Edit compliance framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|Edit framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|Error deleting the compliance framework. Please try again"
+msgstr ""
+
+msgid "ComplianceFrameworks|Error fetching compliance frameworks data. Please refresh the page"
+msgstr ""
+
+msgid "ComplianceFrameworks|Error fetching compliance frameworks data. Please refresh the page or try a different framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
+msgstr ""
+
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr ""
+
+msgid "ComplianceFrameworks|Invalid format"
+msgstr ""
+
+msgid "ComplianceFrameworks|Name"
+msgstr ""
+
+msgid "ComplianceFrameworks|Name is required"
+msgstr ""
+
+msgid "ComplianceFrameworks|New compliance framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|No compliance frameworks are set up yet"
+msgstr ""
+
+msgid "ComplianceFrameworks|No framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|Remove default"
+msgstr ""
+
+msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}See some examples%{linkEnd}."
+msgstr ""
+
+msgid "ComplianceFrameworks|Requires Ultimate subscription"
+msgstr ""
+
+msgid "ComplianceFrameworks|Saved changes to compliance framework"
+msgstr ""
+
+msgid "ComplianceFrameworks|Set compliance pipeline configuration for projects that use this framework. %{linkStart}How do I create the configuration?%{linkEnd}"
+msgstr ""
+
+msgid "ComplianceFrameworks|Set default"
+msgstr ""
+
+msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
+msgstr ""
+
+msgid "ComplianceFrameworks|You are about to permanently delete the compliance framework %{framework} from all projects which currently have it applied, which may remove other functionality. This cannot be undone."
+msgstr ""
+
+msgid "ComplianceFrameworks|Your Compliance Frameworks CSV export for the group \"%{group_name}\" has been attached to this email."
+msgstr ""
+
+msgid "ComplianceFrameworks|Your Compliance Frameworks CSV export for the group %{group_link} has been attached to this email."
+msgstr ""
+
+msgid "ComplianceFrameworks|default"
+msgstr ""
+
+msgid "ComplianceFramework|Add a framework to %{linkStart}%{groupName}%{linkEnd} and it will appear here."
+msgstr ""
+
+msgid "ComplianceFramework|Add framework in %{groupName}"
+msgstr ""
+
+msgid "ComplianceFramework|After a framework is added to %{linkStart}%{groupName}%{linkEnd}, it will appear here."
+msgstr ""
+
+msgid "ComplianceFramework|Edit compliance framework"
+msgstr ""
+
+msgid "ComplianceFramework|New compliance framework"
+msgstr ""
+
+msgid "ComplianceFramework|No compliance frameworks are set up yet"
+msgstr ""
+
+msgid "ComplianceFramework|No pipeline configuration found"
+msgstr ""
+
+msgid "ComplianceReport|Add framework"
+msgstr ""
+
+msgid "ComplianceReport|Apply framework to selected projects"
+msgstr ""
+
+msgid "ComplianceReport|Approved by author"
+msgstr ""
+
+msgid "ComplianceReport|Approved by committer"
+msgstr ""
+
+msgid "ComplianceReport|Choose one bulk action"
+msgstr ""
+
+msgid "ComplianceReport|Choose one framework"
+msgstr ""
+
+msgid "ComplianceReport|Compliance framework"
+msgstr ""
+
+msgid "ComplianceReport|Create a new framework"
+msgstr ""
+
+msgid "ComplianceReport|Do you want to refresh the filtered results to include your change?"
+msgstr ""
+
+msgid "ComplianceReport|Edit the framework"
+msgstr ""
+
+msgid "ComplianceReport|Framework successfully applied"
+msgstr ""
+
+msgid "ComplianceReport|Framework successfully removed"
+msgstr ""
+
+msgid "ComplianceReport|Full target branch name"
+msgstr ""
+
+msgid "ComplianceReport|Less than 2 approvers"
+msgstr ""
+
+msgid "ComplianceReport|No projects found"
+msgstr ""
+
+msgid "ComplianceReport|No projects found that match filters"
+msgstr ""
+
+msgid "ComplianceReport|No projects with standards adherence checks found"
+msgstr ""
+
+msgid "ComplianceReport|No violations found"
+msgstr ""
+
+msgid "ComplianceReport|No violations found. Change search options and try again"
+msgstr ""
+
+msgid "ComplianceReport|Remove framework from selected projects"
+msgstr ""
+
+msgid "ComplianceReport|Retrieving the compliance framework report failed. Refresh the page and try again."
+msgstr ""
+
+msgid "ComplianceReport|Search target branch"
+msgstr ""
+
+msgid "ComplianceReport|Select at least one project to apply the bulk action"
+msgstr ""
+
+msgid "ComplianceReport|Unable to load the compliance framework report. Refresh the page and try again."
+msgstr ""
+
+msgid "ComplianceReport|Unable to load the compliance violations report. Refresh the page and try again."
+msgstr ""
+
+msgid "ComplianceReport|Update filtered results?"
+msgstr ""
+
+msgid "ComplianceReport|Update result"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|At least two approvals"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|Have a valid rule that prevents author approved merge requests"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|Have a valid rule that prevents merge requests approved by committers"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|Have a valid rule that requires any merge request to have more than two approvals"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|Prevent authors as approvers"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|Prevent committers as approvers"
+msgstr ""
+
+msgid "ComplianceStandardsAdherence|View details"
+msgstr ""
+
+msgid "Component"
+msgstr ""
+
+msgid "Component name '%{component}' for command id '%{command}' must not start with '%{prefix}'"
+msgstr ""
+
+msgid "Component name '%{component}' must not start with '%{prefix}'"
+msgstr ""
+
+msgid "Component type '%{type}' is not yet supported"
+msgstr ""
+
+msgid "Components must have a 'name'"
+msgstr ""
+
+msgid "Compute minutes"
+msgstr ""
+
+msgid "Compute quota"
+msgstr ""
+
+msgid "Compute quota:"
+msgstr ""
+
+msgid "Confidential"
+msgstr ""
+
+msgid "Confidential issue"
+msgstr ""
+
+msgid "Confidential note"
+msgstr ""
+
+msgid "Confidentiality"
+msgstr ""
+
+msgid "Configuration help"
+msgstr ""
+
+msgid "Configure"
+msgstr ""
+
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgstr ""
+
+msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
+msgstr ""
+
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
+msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
+msgstr ""
+
+msgid "Configure Container Scanning in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings) to customize Container Scanning settings."
+msgstr ""
+
+msgid "Configure Container Scanning in `.gitlab-ci.yml`, creating this file if it does not already exist"
+msgstr ""
+
+msgid "Configure Dependency Scanning in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings) to customize Dependency Scanning settings."
+msgstr ""
+
+msgid "Configure Dependency Scanning in `.gitlab-ci.yml`, creating this file if it does not already exist"
+msgstr ""
+
+msgid "Configure Error Tracking"
+msgstr ""
+
+msgid "Configure GitLab"
+msgstr ""
+
+msgid "Configure GitLab runners to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
+msgstr ""
+
+msgid "Configure Gitaly timeouts."
+msgstr ""
+
+msgid "Configure Integrations"
+msgstr ""
+
+msgid "Configure SAST IaC in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) to customize SAST IaC settings."
+msgstr ""
+
+msgid "Configure SAST IaC in `.gitlab-ci.yml`, creating this file if it does not already exist"
+msgstr ""
+
+msgid "Configure SAST in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) to customize SAST settings."
+msgstr ""
+
+msgid "Configure SAST in `.gitlab-ci.yml`, creating this file if it does not already exist"
+msgstr ""
+
+msgid "Configure Secret Detection in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings) to customize Secret Detection settings."
+msgstr ""
+
+msgid "Configure Secret Detection in `.gitlab-ci.yml`, creating this file if it does not already exist"
+msgstr ""
+
+msgid "Configure Sentry integration for error tracking"
+msgstr ""
+
+msgid "Configure a %{codeStart}.gitlab-webide.yml%{codeEnd} file in the %{codeStart}.gitlab%{codeEnd} directory to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
+msgstr ""
+
+msgid "Configure advanced permissions"
+msgstr ""
+
+msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and CI/CD settings."
+msgstr ""
+
+msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
+msgstr ""
+
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
+msgid "Configure custom rules for Jira issue key matching"
+msgstr ""
+
+msgid "Configure pipeline"
+msgstr ""
+
+msgid "Configure pipelines to deploy web apps, backend services, APIs and static resources to Google Cloud"
+msgstr ""
+
+msgid "Configure region"
+msgstr ""
+
+msgid "Configure region for environment"
+msgstr ""
+
+msgid "Configure regions"
+msgstr ""
+
+msgid "Configure repository mirroring."
+msgstr ""
+
+msgid "Configure repository storage."
+msgstr ""
+
+msgid "Configure settings for Advanced Search with Elasticsearch."
+msgstr ""
+
+msgid "Configure specific limits for Files API requests that supersede the general user and IP rate limits."
+msgstr ""
+
+msgid "Configure specific limits for Git LFS requests that supersede the general user and IP rate limits."
+msgstr ""
+
+msgid "Configure specific limits for deprecated API requests that supersede the general user and IP rate limits."
+msgstr ""
+
+msgid "Configure the %{link} integration."
+msgstr ""
+
+msgid "Configure the default first day of the week, time tracking units, and default language."
+msgstr ""
+
+msgid "Configure the way a user creates a new account."
+msgstr ""
+
+msgid "Configure via Merge Request"
+msgstr ""
+
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
+msgid "Configure with a merge request"
+msgstr ""
+
+msgid "Configure your environments to be deployed to specific geographical regions"
+msgstr ""
+
+msgid "Confirm"
+msgstr ""
+
+msgid "Confirm approval"
+msgstr ""
+
+msgid "Confirm destroy application"
+msgstr ""
+
+msgid "Confirm new password"
+msgstr ""
+
+msgid "Confirm user"
+msgstr ""
+
+msgid "Confirm your account"
+msgstr ""
+
+msgid "Confirm your email address"
+msgstr ""
+
+msgid "Confirmation email sent to %{email}"
+msgstr ""
+
+msgid "Confirmation required"
+msgstr ""
+
+msgid "Confirmed at:"
+msgstr ""
+
+msgid "Confirmed:"
+msgstr ""
+
+msgid "Conflict: This file was added both in the source and target branches, but with different contents."
+msgstr ""
+
+msgid "Conflict: This file was modified in both the source and target branches."
+msgstr ""
+
+msgid "Conflict: This file was modified in the source branch, but removed in the target branch."
+msgstr ""
+
+msgid "Conflict: This file was removed in the source branch, but modified in the target branch."
+msgstr ""
+
+msgid "Conflict: This file was removed in the source branch, but renamed in the target branch."
+msgstr ""
+
+msgid "Conflict: This file was renamed differently in the source and target branches."
+msgstr ""
+
+msgid "Conflict: This file was renamed in the source branch, but removed in the target branch."
+msgstr ""
+
+msgid "Confluence"
+msgstr ""
+
+msgid "Confluence Cloud Workspace URL"
+msgstr ""
+
+msgid "ConfluenceService|Confluence Workspace"
+msgstr ""
+
+msgid "ConfluenceService|Link to a Confluence Workspace from the sidebar."
+msgstr ""
+
+msgid "ConfluenceService|Link to a Confluence Workspace from the sidebar. Enabling this integration replaces the \"Wiki\" sidebar link with a link to the Confluence Workspace. The GitLab wiki is still available at the original URL."
+msgstr ""
+
+msgid "ConfluenceService|Your GitLab wiki is still available at %{wiki_link}. To re-enable the link to the GitLab wiki, disable this integration."
+msgstr ""
+
+msgid "Congratulations, your free trial is activated."
+msgstr ""
+
+msgid "Connect"
+msgstr ""
+
+msgid "Connect a Kubernetes Cluster"
+msgstr ""
+
+msgid "Connect a cluster"
+msgstr ""
+
+msgid "Connect all repositories"
+msgstr ""
+
+msgid "Connect repositories from GitHub"
+msgstr ""
+
+msgid "Connect your external repositories, and CI/CD pipelines will run for new commits. A GitLab project will be created with only CI/CD features enabled."
+msgstr ""
+
+msgid "Connected"
+msgstr ""
+
+msgid "Connecting"
+msgstr ""
+
+msgid "Connecting to terminal sync service"
+msgstr ""
+
+msgid "Connecting to the remote environment..."
+msgstr ""
+
+msgid "Connecting..."
+msgstr ""
+
+msgid "Connection failure"
+msgstr ""
+
+msgid "Consistency guarantee method"
+msgstr ""
+
+msgid "Contact sales"
+msgstr ""
+
+msgid "Contact support"
+msgstr ""
+
+msgid "Contacts"
+msgstr ""
+
+msgid "Container Registry"
+msgstr ""
+
+msgid "Container Repository"
+msgstr ""
+
+msgid "Container Scanning"
+msgstr ""
+
+msgid "Container must be a group."
+msgstr ""
+
+msgid "Container must be a project or a group."
+msgstr ""
+
+msgid "Container registry images"
+msgstr ""
+
+msgid "Container registry is not enabled on this GitLab instance. Ask an administrator to enable it in order for Auto DevOps to work."
+msgstr ""
+
+msgid "ContainerRegistry| Please visit the %{linkStart}administration settings%{linkEnd} to enable this feature."
+msgstr ""
+
+msgid "ContainerRegistry|%{count} Image repository"
+msgid_plural "ContainerRegistry|%{count} Image repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ContainerRegistry|%{count} tag"
+msgid_plural "ContainerRegistry|%{count} tags"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ContainerRegistry|%{strongStart}Disabled%{strongEnd} - Tags will not be automatically deleted."
+msgstr ""
+
+msgid "ContainerRegistry|%{strongStart}Enabled%{strongEnd} - Tags that match the rules on this page are automatically scheduled for deletion."
+msgstr ""
+
+msgid "ContainerRegistry|%{title} was successfully scheduled for deletion"
+msgstr ""
+
+msgid "ContainerRegistry|-- tags"
+msgstr ""
+
+msgid "ContainerRegistry|Build an image"
+msgstr ""
+
+msgid "ContainerRegistry|CLI Commands"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup disabled"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup in progress"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup incomplete"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup is currently removing tags"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup is disabled for this project"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup is not scheduled."
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup is ongoing"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup pending"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup policies"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup policy for tags is disabled"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup policy successfully saved."
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup ran but some tags were not removed"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup will run %{time}"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup will run in %{time}"
+msgstr ""
+
+msgid "ContainerRegistry|Cleanup will run soon"
+msgstr ""
+
+msgid "ContainerRegistry|Configuration digest: %{digest}"
+msgstr ""
+
+msgid "ContainerRegistry|Configure in settings"
+msgstr ""
+
+msgid "ContainerRegistry|Container Registry"
+msgstr ""
+
+msgid "ContainerRegistry|Copy build command"
+msgstr ""
+
+msgid "ContainerRegistry|Copy image path"
+msgstr ""
+
+msgid "ContainerRegistry|Copy login command"
+msgstr ""
+
+msgid "ContainerRegistry|Copy push command"
+msgstr ""
+
+msgid "ContainerRegistry|Created %{time}"
+msgstr ""
+
+msgid "ContainerRegistry|Delete image repository"
+msgstr ""
+
+msgid "ContainerRegistry|Delete image repository?"
+msgstr ""
+
+msgid "ContainerRegistry|Delete selected tags"
+msgstr ""
+
+msgid "ContainerRegistry|Delete tag"
+msgstr ""
+
+msgid "ContainerRegistry|Deleting the image repository will delete all images and tags inside. This action cannot be undone. Please type the following to confirm: %{code}"
+msgstr ""
+
+msgid "ContainerRegistry|Digest: %{imageId}"
+msgstr ""
+
+msgid "ContainerRegistry|Docker connection error"
+msgstr ""
+
+msgid "ContainerRegistry|Edit cleanup rules"
+msgstr ""
+
+msgid "ContainerRegistry|Enable cleanup policy"
+msgstr ""
+
+msgid "ContainerRegistry|If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have %{twofaDocLinkStart}Two-Factor Authentication%{twofaDocLinkEnd} enabled, use a %{personalAccessTokensDocLinkStart}Personal Access Token%{personalAccessTokensDocLinkEnd} instead of a password."
+msgstr ""
+
+msgid "ContainerRegistry|Image repository deletion failed"
+msgstr ""
+
+msgid "ContainerRegistry|Image repository not found"
+msgstr ""
+
+msgid "ContainerRegistry|Image repository temporarily cannot be marked for deletion. Please try again in a few minutes. %{docLinkStart}More details%{docLinkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|Image repository will be deleted"
+msgstr ""
+
+msgid "ContainerRegistry|Image repository with no name located at the project URL."
+msgstr ""
+
+msgid "ContainerRegistry|Image tags"
+msgstr ""
+
+msgid "ContainerRegistry|Invalid tag: missing manifest digest"
+msgstr ""
+
+msgid "ContainerRegistry|Keep tags matching:"
+msgstr ""
+
+msgid "ContainerRegistry|Keep the most recent:"
+msgstr ""
+
+msgid "ContainerRegistry|Keep these tags"
+msgstr ""
+
+msgid "ContainerRegistry|Login"
+msgstr ""
+
+msgid "ContainerRegistry|Manifest digest: %{digest}"
+msgstr ""
+
+msgid "ContainerRegistry|Missing or insufficient permission, delete button disabled"
+msgstr ""
+
+msgid "ContainerRegistry|Next cleanup scheduled to run on:"
+msgstr ""
+
+msgid "ContainerRegistry|Not yet scheduled"
+msgstr ""
+
+msgid "ContainerRegistry|Note: Any policy update will result in a change to the scheduled run date and time"
+msgstr ""
+
+msgid "ContainerRegistry|Partial cleanup complete"
+msgstr ""
+
+msgid "ContainerRegistry|Please try different search criteria"
+msgstr ""
+
+msgid "ContainerRegistry|Published %{timeInfo}"
+msgstr ""
+
+msgid "ContainerRegistry|Published to the %{repositoryPath} image repository at %{time} on %{date}"
+msgstr ""
+
+msgid "ContainerRegistry|Push an image"
+msgstr ""
+
+msgid "ContainerRegistry|Remember to run %{docLinkStart}garbage collection%{docLinkEnd} to remove the stale data from storage."
+msgstr ""
+
+msgid "ContainerRegistry|Remove repository"
+msgstr ""
+
+msgid "ContainerRegistry|Remove tag"
+msgid_plural "ContainerRegistry|Remove tags"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ContainerRegistry|Remove tags matching:"
+msgstr ""
+
+msgid "ContainerRegistry|Remove tags older than:"
+msgstr ""
+
+msgid "ContainerRegistry|Remove these tags"
+msgstr ""
+
+msgid "ContainerRegistry|Run cleanup:"
+msgstr ""
+
+msgid "ContainerRegistry|Save storage space by automatically deleting tags from the container registry and keeping the ones you want. %{linkStart}How does cleanup work?%{linkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|Set cleanup rules"
+msgstr ""
+
+msgid "ContainerRegistry|Set rules to automatically remove unused packages to save storage space."
+msgstr ""
+
+msgid "ContainerRegistry|Set up cleanup"
+msgstr ""
+
+msgid "ContainerRegistry|Show full path"
+msgstr ""
+
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while fetching the image details."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while fetching the repository list."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while fetching the tags list."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while marking the tag for deletion."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while marking the tags for deletion."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while scheduling %{title} for deletion. Please try again."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while scheduling the image for deletion."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while updating the cleanup policy."
+msgstr ""
+
+msgid "ContainerRegistry|Sorry, your filter produced no results."
+msgstr ""
+
+msgid "ContainerRegistry|Tag successfully marked for deletion."
+msgstr ""
+
+msgid "ContainerRegistry|Tags successfully marked for deletion."
+msgstr ""
+
+msgid "ContainerRegistry|Tags that match %{strongStart}any of%{strongEnd} these rules are %{strongStart}kept%{strongEnd}, even if they match a removal rule below. The %{strongStart}latest%{strongEnd} tag is always kept."
+msgstr ""
+
+msgid "ContainerRegistry|Tags that match these rules are %{strongStart}removed%{strongEnd}, unless a rule above says to keep them."
+msgstr ""
+
+msgid "ContainerRegistry|Tags with names that match this regex pattern are kept. %{linkStart}View regex examples.%{linkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|Tags with names that match this regex pattern are removed. %{linkStart}View regex examples.%{linkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}run cleanup now manually%{adminLinkEnd} or you can wait for the next scheduled run of the cleanup policy. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|The cleanup will continue within %{time}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|The filter returned no results"
+msgstr ""
+
+msgid "ContainerRegistry|The image repository could not be found."
+msgstr ""
+
+msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
+msgstr ""
+
+msgid "ContainerRegistry|The requested image repository does not exist or has been deleted. If you think this is an error, try refreshing the page."
+msgstr ""
+
+msgid "ContainerRegistry|The value of this input should be less than 256 characters"
+msgstr ""
+
+msgid "ContainerRegistry|There are no container images available in this group"
+msgstr ""
+
+msgid "ContainerRegistry|There are no container images stored for this project"
+msgstr ""
+
+msgid "ContainerRegistry|There was an error during the deletion of this image repository, please try again."
+msgstr ""
+
+msgid "ContainerRegistry|This image has no active tags"
+msgstr ""
+
+msgid "ContainerRegistry|This image repository has failed to be deleted"
+msgstr ""
+
+msgid "ContainerRegistry|This image repository is scheduled for deletion"
+msgstr ""
+
+msgid "ContainerRegistry|This image repository will be deleted. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|This project's cleanup policy for tags is not enabled."
+msgstr ""
+
+msgid "ContainerRegistry|To widen your search, change or remove the filters above."
+msgstr ""
+
+msgid "ContainerRegistry|We are having trouble connecting to the Container Registry. Please try refreshing the page. If this error persists, please review %{docLinkStart}the troubleshooting documentation%{docLinkEnd}."
+msgstr ""
+
+msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. %{docLinkStart}More Information%{docLinkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. Push at least one Docker image in one of this group's projects in order to show up here. %{docLinkStart}More Information%{docLinkEnd}"
+msgstr ""
+
+msgid "ContainerRegistry|You are about to remove %{item} tags. Are you sure?"
+msgstr ""
+
+msgid "ContainerRegistry|You are about to remove %{item}. Are you sure?"
+msgstr ""
+
+msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
+msgstr ""
+
+msgid "Containers"
+msgstr ""
+
+msgid "Contains only whitespace changes."
+msgstr ""
+
+msgid "Content"
+msgstr ""
+
+msgid "Content parsed with %{link}."
+msgstr ""
+
+msgid "ContentEditor|You have to provide a renderMarkdown function or a custom serializer"
+msgstr ""
+
+msgid "Contents of .gitlab-ci.yml"
+msgstr ""
+
+msgid "ContextCommits|Failed to create context commits. Please try again."
+msgstr ""
+
+msgid "ContextCommits|Failed to create/remove context commits. Please try again."
+msgstr ""
+
+msgid "ContextCommits|Failed to delete context commits. Please try again."
+msgstr ""
+
+msgid "Continue"
+msgstr ""
+
+msgid "Continue editing"
+msgstr ""
+
+msgid "Continue to the next step"
+msgstr ""
+
+msgid "Continue with overages"
+msgstr ""
+
+msgid "Continue…"
+msgstr ""
+
+msgid "Continuous Integration and Deployment"
+msgstr ""
+
+msgid "Contribute to GitLab"
+msgstr ""
+
+msgid "Contribution"
+msgstr ""
+
+msgid "Contribution Analytics"
+msgstr ""
+
+msgid "Contribution analytics"
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{createdCount} created, %{mergedCount} merged, %{closedCount} closed."
+msgstr ""
+
+msgid "ContributionAnalytics|%{pushCount} by %{authorCount}."
+msgstr ""
+
+msgid "ContributionAnalytics|Approved MRs"
+msgstr ""
+
+msgid "ContributionAnalytics|Closed MRs"
+msgstr ""
+
+msgid "ContributionAnalytics|Closed issues"
+msgstr ""
+
+msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
+msgstr ""
+
+msgid "ContributionAnalytics|Contributions per group member"
+msgstr ""
+
+msgid "ContributionAnalytics|Failed to load the contribution stats"
+msgstr ""
+
+msgid "ContributionAnalytics|Issues"
+msgstr ""
+
+msgid "ContributionAnalytics|Last 3 months"
+msgstr ""
+
+msgid "ContributionAnalytics|Last month"
+msgstr ""
+
+msgid "ContributionAnalytics|Last week"
+msgstr ""
+
+msgid "ContributionAnalytics|Loading contribution stats for group members"
+msgstr ""
+
+msgid "ContributionAnalytics|Merge requests"
+msgstr ""
+
+msgid "ContributionAnalytics|Merged MRs"
+msgstr ""
+
+msgid "ContributionAnalytics|Name"
+msgstr ""
+
+msgid "ContributionAnalytics|No issues for the selected time period."
+msgstr ""
+
+msgid "ContributionAnalytics|No merge requests for the selected time period."
+msgstr ""
+
+msgid "ContributionAnalytics|No pushes for the selected time period."
+msgstr ""
+
+msgid "ContributionAnalytics|Opened MRs"
+msgstr ""
+
+msgid "ContributionAnalytics|Opened issues"
+msgstr ""
+
+msgid "ContributionAnalytics|Pushed"
+msgstr ""
+
+msgid "ContributionAnalytics|The given date range is larger than %{number_of_days} days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
+msgid "ContributionAnalytics|Total Contributions"
+msgstr ""
+
+msgid "ContributionEvent|Accepted merge request %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Added design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed incident %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed issue %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed key result %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed merge request %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed milestone %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed objective %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed requirement %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed resource."
+msgstr ""
+
+msgid "ContributionEvent|Closed task %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Created project %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Created resource."
+msgstr ""
+
+msgid "ContributionEvent|Created wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
+msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Joined project %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Left project %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Made a private contribution."
+msgstr ""
+
+msgid "ContributionEvent|Opened Epic %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened incident %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened issue %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened key result %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened merge request %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened milestone %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened objective %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened requirement %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened task %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Opened test case %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Pushed a new branch %{refLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Pushed a new tag %{refLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Pushed to branch %{refLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Pushed to tag %{refLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Removed due to membership expiration from %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened Epic %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened incident %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened issue %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened key result %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened merge request %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened milestone %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened objective %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened requirement %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened resource."
+msgstr ""
+
+msgid "ContributionEvent|Reopened task %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
+msgstr ""
+
+msgid "Contributions for %{calendar_date}"
+msgstr ""
+
+msgid "Contributor"
+msgstr ""
+
+msgid "Contributor statistics"
+msgstr ""
+
+msgid "Control how the CI_JOB_TOKEN CI/CD variable is used for API access between projects."
+msgstr ""
+
+msgid "Control whether to display customer experience improvement content and third-party offers in GitLab."
+msgstr ""
+
+msgid "Converts work item to %{type}. Widgets not supported in new type are removed."
+msgstr ""
+
+msgid "Cookie domain"
+msgstr ""
+
+msgid "Copied"
+msgstr ""
+
+msgid "Copied labels and milestone from %{source_issuable_reference}."
+msgstr ""
+
+msgid "Copy"
+msgstr ""
+
+msgid "Copy %{accessTokenType}"
+msgstr ""
+
+msgid "Copy %{http_label} clone URL"
+msgstr ""
+
+msgid "Copy %{issueType} email address"
+msgstr ""
+
+msgid "Copy %{name}"
+msgstr ""
+
+msgid "Copy %{protocol} clone URL"
+msgstr ""
+
+msgid "Copy ID"
+msgstr ""
+
+msgid "Copy KRB5 clone URL"
+msgstr ""
+
+msgid "Copy SSH clone URL"
+msgstr ""
+
+msgid "Copy SSH public key"
+msgstr ""
+
+msgid "Copy URL"
+msgstr ""
+
+msgid "Copy audio URL"
+msgstr ""
+
+msgid "Copy branch name"
+msgstr ""
+
+msgid "Copy code"
+msgstr ""
+
+msgid "Copy codes"
+msgstr ""
+
+msgid "Copy command"
+msgstr ""
+
+msgid "Copy commands"
+msgstr ""
+
+msgid "Copy commit SHA"
+msgstr ""
+
+msgid "Copy diagram URL"
+msgstr ""
+
+msgid "Copy environment"
+msgstr ""
+
+msgid "Copy epic URL"
+msgstr ""
+
+msgid "Copy evidence SHA"
+msgstr ""
+
+msgid "Copy failed. Please manually copy the value."
+msgstr ""
+
+msgid "Copy file contents"
+msgstr ""
+
+msgid "Copy file path"
+msgstr ""
+
+msgid "Copy image URL"
+msgstr ""
+
+msgid "Copy issue URL"
+msgstr ""
+
+msgid "Copy issue URL to clipboard"
+msgstr ""
+
+msgid "Copy key"
+msgstr ""
+
+msgid "Copy labels and milestone from %{source_issuable_reference}."
+msgstr ""
+
+msgid "Copy labels and milestone from other issue or merge request in this project"
+msgstr ""
+
+msgid "Copy link"
+msgstr ""
+
+msgid "Copy link URL"
+msgstr ""
+
+msgid "Copy merge request URL"
+msgstr ""
+
+msgid "Copy reference"
+msgstr ""
+
+msgid "Copy secret"
+msgstr ""
+
+msgid "Copy source branch name"
+msgstr ""
+
+msgid "Copy to clipboard"
+msgstr ""
+
+msgid "Copy token"
+msgstr ""
+
+msgid "Copy value"
+msgstr ""
+
+msgid "Copy video URL"
+msgstr ""
+
+msgid "Corpus Management"
+msgstr ""
+
+msgid "Corpus Management|Are you sure you want to delete the corpus?"
+msgstr ""
+
+msgid "CorpusManagement|A corpus is used by fuzz testing to improve coverage. Corpus files can be manually created or auto-generated. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "CorpusManagement|Actions"
+msgstr ""
+
+msgid "CorpusManagement|Corpus file"
+msgstr ""
+
+msgid "CorpusManagement|Corpus files are used in coverage-guided fuzz testing as seed inputs to improve testing."
+msgstr ""
+
+msgid "CorpusManagement|Corpus files must be in *.zip format. Maximum 5 GB"
+msgstr ""
+
+msgid "CorpusManagement|Corpus name"
+msgstr ""
+
+msgid "CorpusManagement|Currently, there are no uploaded or generated corpuses."
+msgstr ""
+
+msgid "CorpusManagement|File too large, Maximum 5 GB"
+msgstr ""
+
+msgid "CorpusManagement|Filename can contain only lowercase letters (a-z), uppercase letter (A-Z), numbers (0-9), dots (.), hyphens (-), or underscores (_)."
+msgstr ""
+
+msgid "CorpusManagement|Fuzz testing corpus management"
+msgstr ""
+
+msgid "CorpusManagement|Last updated"
+msgstr ""
+
+msgid "CorpusManagement|Last used"
+msgstr ""
+
+msgid "CorpusManagement|Latest Job:"
+msgstr ""
+
+msgid "CorpusManagement|Manage your fuzz testing corpus files"
+msgstr ""
+
+msgid "CorpusManagement|New corpus"
+msgstr ""
+
+msgid "CorpusManagement|New upload"
+msgstr ""
+
+msgid "CorpusManagement|Not Set"
+msgstr ""
+
+msgid "CorpusManagement|Target"
+msgstr ""
+
+msgid "CorpusManagement|To use this corpus, edit the corresponding YAML file"
+msgstr ""
+
+msgid "CorpusManagement|Total Size: %{totalSize}"
+msgstr ""
+
+msgid "Cost Factor Settings"
+msgstr ""
+
+msgid "Cost factor for forks of projects"
+msgstr ""
+
+msgid "Could not access the Wiki Repository at this time."
+msgstr ""
+
+msgid "Could not apply %{name} command."
+msgstr ""
+
+msgid "Could not apply %{name} command. %{message}."
+msgstr ""
+
+msgid "Could not authorize chat nickname. Try again!"
+msgstr ""
+
+msgid "Could not change HEAD: branch '%{branch}' does not exist"
+msgstr ""
+
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
+msgid "Could not connect to FogBugz, check your URL"
+msgstr ""
+
+msgid "Could not connect to Sentry. Refresh the page to try again."
+msgstr ""
+
+msgid "Could not connect to Web IDE file mirror service."
+msgstr ""
+
+msgid "Could not create Wiki Repository at this time. Please try again later."
+msgstr ""
+
+msgid "Could not create issue"
+msgstr ""
+
+msgid "Could not create wiki page"
+msgstr ""
+
+msgid "Could not delete chat nickname %{chat_name}."
+msgstr ""
+
+msgid "Could not delete wiki page"
+msgstr ""
+
+msgid "Could not draw the lines for job relationships"
+msgstr ""
+
+msgid "Could not fetch policy because existing policy YAML is invalid"
+msgstr ""
+
+msgid "Could not fetch training providers. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "Could not find design."
+msgstr ""
+
+msgid "Could not find iteration"
+msgstr ""
+
+msgid "Could not get the data properly"
+msgstr ""
+
+msgid "Could not load the user chart. Please refresh the page to try again."
+msgstr ""
+
+msgid "Could not load usage counts. Please refresh the page to try again."
+msgstr ""
+
+msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
+msgstr ""
+
+msgid "Could not remove the trigger."
+msgstr ""
+
+msgid "Could not restore the group"
+msgstr ""
+
+msgid "Could not retrieve the list of branches. Use the YAML editor mode, or refresh this page later. To view the list of branches, go to %{boldStart}Code - Branches%{boldEnd}"
+msgstr ""
+
+msgid "Could not retrieve the list of protected branches. Use the YAML editor mode, or refresh this page later. To view the list of protected branches, go to %{boldStart}Settings - Branches%{boldEnd} and expand %{boldStart}Protected branches%{boldEnd}."
+msgstr ""
+
+msgid "Could not revoke access token %{access_token_name}."
+msgstr ""
+
+msgid "Could not revoke impersonation token %{token_name}."
+msgstr ""
+
+msgid "Could not revoke personal access token %{personal_access_token_name}."
+msgstr ""
+
+msgid "Could not save configuration. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "Could not update the LDAP settings"
+msgstr ""
+
+msgid "Could not update wiki page"
+msgstr ""
+
+msgid "Could not upload your designs as one or more files uploaded are not supported."
+msgstr ""
+
+msgid "Couldn't assign policy to project or group"
+msgstr ""
+
+msgid "Couldn't find event type filters where audit event type(s): %{missing_filters}"
+msgstr ""
+
+msgid "Couldn't link %{issuable}. You must have at least the Reporter role in both projects."
+msgstr ""
+
+msgid "Country / Region"
+msgstr ""
+
+msgid "Counts"
+msgstr ""
+
+msgid "Counts reflect children you may not have access to."
+msgstr ""
+
+msgid "Coverage"
+msgstr ""
+
+msgid "Coverage Fuzzing"
+msgstr ""
+
+msgid "Create"
+msgstr ""
+
+msgid "Create %{environment}"
+msgstr ""
+
+msgid "Create %{humanized_resource_name}"
+msgstr ""
+
+msgid "Create %{workspace} label"
+msgstr ""
+
+msgid "Create AI-generated commit message"
+msgstr ""
+
+msgid "Create New Directory"
+msgstr ""
+
+msgid "Create New Domain"
+msgstr ""
+
+msgid "Create a GitLab account first, and then connect it to your %{label} account."
+msgstr ""
+
+msgid "Create a Kubernetes cluster"
+msgstr ""
+
+msgid "Create a Mattermost team for this group"
+msgstr ""
+
+msgid "Create a cluster"
+msgstr ""
+
+msgid "Create a group"
+msgstr ""
+
+msgid "Create a merge request"
+msgstr ""
+
+msgid "Create a new %{codeStart}.gitlab-ci.yml%{codeEnd} file at the root of the repository to get started."
+msgstr ""
+
+msgid "Create a new branch"
+msgstr ""
+
+msgid "Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes."
+msgstr ""
+
+msgid "Create a new fork"
+msgstr ""
+
+msgid "Create a new issue"
+msgstr ""
+
+msgid "Create a new project"
+msgstr ""
+
+msgid "Create a new repository"
+msgstr ""
+
+msgid "Create a personal access token on your account to pull or push via %{protocol}."
+msgstr ""
+
+msgid "Create a project"
+msgstr ""
+
+msgid "Create an account using:"
+msgstr ""
+
+msgid "Create an incident. Incidents are created for each alert triggered."
+msgstr ""
+
+msgid "Create and provide your GitHub %{link_start}Personal Access Token%{link_end}. You will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to import."
+msgstr ""
+
+msgid "Create branch"
+msgstr ""
+
+msgid "Create commit"
+msgstr ""
+
+msgid "Create commit..."
+msgstr ""
+
+msgid "Create common files more quickly, and standardize their format."
+msgstr ""
+
+msgid "Create confidential merge request"
+msgstr ""
+
+msgid "Create confidential merge request and branch"
+msgstr ""
+
+msgid "Create custom type"
+msgstr ""
+
+msgid "Create directory"
+msgstr ""
+
+msgid "Create empty repository"
+msgstr ""
+
+msgid "Create epic"
+msgstr ""
+
+msgid "Create file"
+msgstr ""
+
+msgid "Create from"
+msgstr ""
+
+msgid "Create group"
+msgstr ""
+
+msgid "Create group label"
+msgstr ""
+
+msgid "Create issue"
+msgstr ""
+
+msgid "Create label"
+msgstr ""
+
+msgid "Create list"
+msgstr ""
+
+msgid "Create lists from labels. Issues with that label appear in that list."
+msgstr ""
+
+msgid "Create merge request"
+msgstr ""
+
+msgid "Create merge request and branch"
+msgstr ""
+
+msgid "Create milestone"
+msgstr ""
+
+msgid "Create new"
+msgstr ""
+
+msgid "Create new %{name} by email"
+msgstr ""
+
+msgid "Create new branch"
+msgstr ""
+
+msgid "Create new confidential %{issuableType}"
+msgstr ""
+
+msgid "Create new directory"
+msgstr ""
+
+msgid "Create new file"
+msgstr ""
+
+msgid "Create new file or directory"
+msgstr ""
+
+msgid "Create new label"
+msgstr ""
+
+msgid "Create new..."
+msgstr ""
+
+msgid "Create one"
+msgstr ""
+
+msgid "Create or close an issue."
+msgstr ""
+
+msgid "Create or edit diagram"
+msgstr ""
+
+msgid "Create or import your first project"
+msgstr ""
+
+msgid "Create phone verification exemption"
+msgstr ""
+
+msgid "Create pipeline trigger token"
+msgstr ""
+
+msgid "Create project"
+msgstr ""
+
+msgid "Create project label"
+msgstr ""
+
+msgid "Create release"
+msgstr ""
+
+msgid "Create requirement"
+msgstr ""
+
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
+msgid "Create service account"
+msgstr ""
+
+msgid "Create snippet"
+msgstr ""
+
+msgid "Create testing scenarios by defining project conditions in your development platform."
+msgstr ""
+
+msgid "Create topic"
+msgstr ""
+
+msgid "Create user"
+msgstr ""
+
+msgid "Create wildcard"
+msgstr ""
+
+msgid "Create wildcard: %{searchTerm}"
+msgstr ""
+
+msgid "Create your first page"
+msgstr ""
+
+msgid "Create your group"
+msgstr ""
+
+msgid "Create, update, or delete a merge request."
+msgstr ""
+
+msgid "CreateGitTag|Add a message to the tag. Leaving this blank creates a lightweight tag."
+msgstr ""
+
+msgid "CreateGitTag|Set tag message"
+msgstr ""
+
+msgid "CreateGroup|You don’t have permission to create a subgroup in this group."
+msgstr ""
+
+msgid "CreateGroup|You don’t have permission to create groups."
+msgstr ""
+
+msgid "CreateTag|Tag"
+msgstr ""
+
+msgid "CreateTimelogForm|Add time entry"
+msgstr ""
+
+msgid "CreateTimelogForm|An error occurred while saving the time entry."
+msgstr ""
+
+msgid "CreateTimelogForm|Cancel"
+msgstr ""
+
+msgid "CreateTimelogForm|Example: 1h 30m"
+msgstr ""
+
+msgid "CreateTimelogForm|How do I track and estimate time?"
+msgstr ""
+
+msgid "CreateTimelogForm|Save"
+msgstr ""
+
+msgid "CreateTimelogForm|Spent at"
+msgstr ""
+
+msgid "CreateTimelogForm|Summary"
+msgstr ""
+
+msgid "CreateTimelogForm|Time spent"
+msgstr ""
+
+msgid "CreateTimelogForm|Track time spent on this %{issuableTypeNameStart}%{issuableTypeNameEnd}. %{timeTrackingDocsLinkStart}%{timeTrackingDocsLinkEnd}"
+msgstr ""
+
+msgid "CreateTimelogForm|issue"
+msgstr ""
+
+msgid "CreateTimelogForm|merge request"
+msgstr ""
+
+msgid "CreateValueStreamForm|%{name} (default)"
+msgstr ""
+
+msgid "CreateValueStreamForm|'%{name}' Value Stream created"
+msgstr ""
+
+msgid "CreateValueStreamForm|'%{name}' Value Stream saved"
+msgstr ""
+
+msgid "CreateValueStreamForm|Add another stage"
+msgstr ""
+
+msgid "CreateValueStreamForm|Add stage"
+msgstr ""
+
+msgid "CreateValueStreamForm|All default stages are currently visible"
+msgstr ""
+
+msgid "CreateValueStreamForm|Code stage start"
+msgstr ""
+
+msgid "CreateValueStreamForm|Create from default template"
+msgstr ""
+
+msgid "CreateValueStreamForm|Create from no template"
+msgstr ""
+
+msgid "CreateValueStreamForm|Create new Value Stream"
+msgstr ""
+
+msgid "CreateValueStreamForm|Create value stream"
+msgstr ""
+
+msgid "CreateValueStreamForm|Default stages"
+msgstr ""
+
+msgid "CreateValueStreamForm|Default stages can only be hidden or re-ordered"
+msgstr ""
+
+msgid "CreateValueStreamForm|Edit value stream"
+msgstr ""
+
+msgid "CreateValueStreamForm|Editing stage"
+msgstr ""
+
+msgid "CreateValueStreamForm|End event"
+msgstr ""
+
+msgid "CreateValueStreamForm|End event label"
+msgstr ""
+
+msgid "CreateValueStreamForm|End event: "
+msgstr ""
+
+msgid "CreateValueStreamForm|Enter stage name"
+msgstr ""
+
+msgid "CreateValueStreamForm|Enter value stream name"
+msgstr ""
+
+msgid "CreateValueStreamForm|Issue stage end"
+msgstr ""
+
+msgid "CreateValueStreamForm|Maximum length %{maxLength} characters"
+msgstr ""
+
+msgid "CreateValueStreamForm|Minimum length %{minLength} characters"
+msgstr ""
+
+msgid "CreateValueStreamForm|Name is required"
+msgstr ""
+
+msgid "CreateValueStreamForm|New stage"
+msgstr ""
+
+msgid "CreateValueStreamForm|Plan stage start"
+msgstr ""
+
+msgid "CreateValueStreamForm|Please select a start event first"
+msgstr ""
+
+msgid "CreateValueStreamForm|Please select an end event"
+msgstr ""
+
+msgid "CreateValueStreamForm|Recover hidden stage"
+msgstr ""
+
+msgid "CreateValueStreamForm|Restore defaults"
+msgstr ""
+
+msgid "CreateValueStreamForm|Restore stage"
+msgstr ""
+
+msgid "CreateValueStreamForm|Save value stream"
+msgstr ""
+
+msgid "CreateValueStreamForm|Select end event"
+msgstr ""
+
+msgid "CreateValueStreamForm|Select start event"
+msgstr ""
+
+msgid "CreateValueStreamForm|Stage %{index}"
+msgstr ""
+
+msgid "CreateValueStreamForm|Stage name already exists"
+msgstr ""
+
+msgid "CreateValueStreamForm|Stage name is required"
+msgstr ""
+
+msgid "CreateValueStreamForm|Start event"
+msgstr ""
+
+msgid "CreateValueStreamForm|Start event changed, please select a valid end event"
+msgstr ""
+
+msgid "CreateValueStreamForm|Start event label"
+msgstr ""
+
+msgid "CreateValueStreamForm|Start event: "
+msgstr ""
+
+msgid "CreateValueStreamForm|Update stage"
+msgstr ""
+
+msgid "CreateValueStreamForm|Value Stream name"
+msgstr ""
+
+msgid "Created"
+msgstr ""
+
+msgid "Created %{epicTimeagoDate}"
+msgstr ""
+
+msgid "Created %{timeAgo}"
+msgstr ""
+
+msgid "Created %{timeAgo} by %{author}"
+msgstr ""
+
+msgid "Created %{timeAgo} by %{email} via %{author}"
+msgstr ""
+
+msgid "Created %{time_ago}"
+msgstr ""
+
+msgid "Created %{timestamp}"
+msgstr ""
+
+msgid "Created At"
+msgstr ""
+
+msgid "Created On"
+msgstr ""
+
+msgid "Created a branch and a merge request to resolve this issue."
+msgstr ""
+
+msgid "Created branch '%{branch_name}' and a merge request to resolve this issue."
+msgstr ""
+
+msgid "Created by %{job}"
+msgstr ""
+
+msgid "Created by me"
+msgstr ""
+
+msgid "Created by:"
+msgstr ""
+
+msgid "Created compliance violations if any were found"
+msgstr ""
+
+msgid "Created date"
+msgstr ""
+
+msgid "Created issue %{issueLink}"
+msgstr ""
+
+msgid "Created issue %{issueLink} at %{projectLink}"
+msgstr ""
+
+msgid "Created merge request %{mergeRequestLink}"
+msgstr ""
+
+msgid "Created merge request %{mergeRequestLink} at %{projectLink}"
+msgstr ""
+
+msgid "Created on"
+msgstr ""
+
+msgid "Created on %{created_at}"
+msgstr ""
+
+msgid "Created on:"
+msgstr ""
+
+msgid "Creates a branch and a merge request to resolve this issue."
+msgstr ""
+
+msgid "Creates a summary of all comments"
+msgstr ""
+
+msgid "Creates branch '%{branch_name}' and a merge request to resolve this issue."
+msgstr ""
+
+msgid "Creating"
+msgstr ""
+
+msgid "Creating epic"
+msgstr ""
+
+msgid "Creator"
+msgstr ""
+
+msgid "Credentials"
+msgstr ""
+
+msgid "CredentialsInventory|GPG Keys"
+msgstr ""
+
+msgid "CredentialsInventory|No credentials found"
+msgstr ""
+
+msgid "CredentialsInventory|Personal Access Tokens"
+msgstr ""
+
+msgid "CredentialsInventory|Project and Group Access Tokens"
+msgstr ""
+
+msgid "CredentialsInventory|SSH Keys"
+msgstr ""
+
+msgid "Credit card required to be on file in order to create a pipeline"
+msgstr ""
+
+msgid "Credit card:"
+msgstr ""
+
+msgid "Critical - S1"
+msgstr ""
+
+msgid "Critical vulnerabilities present"
+msgstr ""
+
+msgid "Crm|Active"
+msgstr ""
+
+msgid "Crm|Contact"
+msgstr ""
+
+msgid "Crm|Contact has been added."
+msgstr ""
+
+msgid "Crm|Contact has been updated."
+msgstr ""
+
+msgid "Crm|Customer relations contacts"
+msgstr ""
+
+msgid "Crm|Customer relations organizations"
+msgstr ""
+
+msgid "Crm|Default rate"
+msgstr ""
+
+msgid "Crm|Edit contact"
+msgstr ""
+
+msgid "Crm|Edit organization"
+msgstr ""
+
+msgid "Crm|New contact"
+msgstr ""
+
+msgid "Crm|New organization"
+msgstr ""
+
+msgid "Crm|No contacts found"
+msgstr ""
+
+msgid "Crm|No organization"
+msgstr ""
+
+msgid "Crm|No organizations found"
+msgstr ""
+
+msgid "Crm|Organization"
+msgstr ""
+
+msgid "Crm|Organization has been added."
+msgstr ""
+
+msgid "Crm|Organization has been updated."
+msgstr ""
+
+msgid "Cron time zone"
+msgstr ""
+
+msgid "Crowd"
+msgstr ""
+
+msgid "CsvParser|Failed to render the CSV file for the following reasons:"
+msgstr ""
+
+msgid "CsvParser|Quoted field unterminated"
+msgstr ""
+
+msgid "CsvParser|Too few fields"
+msgstr ""
+
+msgid "CsvParser|Too many fields"
+msgstr ""
+
+msgid "CsvParser|Trailing quote on quoted field is malformed"
+msgstr ""
+
+msgid "CsvParser|Unable to auto-detect delimiter; defaulted to \",\""
+msgstr ""
+
+msgid "Current"
+msgstr ""
+
+msgid "Current Branch"
+msgstr ""
+
+msgid "Current Project"
+msgstr ""
+
+msgid "Current node must be the primary node or you will be locking yourself out"
+msgstr ""
+
+msgid "Current password"
+msgstr ""
+
+msgid "Current sign-in IP:"
+msgstr ""
+
+msgid "Current sign-in at:"
+msgstr ""
+
+msgid "Current sign-in ip"
+msgstr ""
+
+msgid "Current vulnerabilities count"
+msgstr ""
+
+msgid "CurrentUser|Buy Pipeline minutes"
+msgstr ""
+
+msgid "CurrentUser|Edit profile"
+msgstr ""
+
+msgid "CurrentUser|One of your groups is running out"
+msgstr ""
+
+msgid "CurrentUser|Preferences"
+msgstr ""
+
+msgid "CurrentUser|Start an Ultimate trial"
+msgstr ""
+
+msgid "CurrentUser|Switch to GitLab Next"
+msgstr ""
+
+msgid "Currently unable to fetch data for this pipeline."
+msgstr ""
+
+msgid "Custom (%{language})"
+msgstr ""
+
+msgid "Custom Attributes"
+msgstr ""
+
+msgid "Custom Git clone URL for HTTP(S)"
+msgstr ""
+
+msgid "Custom analyzers: language support"
+msgstr ""
+
+msgid "Custom emoji"
+msgstr ""
+
+msgid "Custom emoji will be available to use in every project in group."
+msgstr ""
+
+msgid "Custom hostname (for private commit emails)"
+msgstr ""
+
+msgid "Custom metrics"
+msgstr ""
+
+msgid "Custom notification events"
+msgstr ""
+
+msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notificationLinkStart}notification emails%{notificationLinkEnd}."
+msgstr ""
+
+msgid "Custom project templates"
+msgstr ""
+
+msgid "Custom project templates have not been set up for groups that you are a member of. They are enabled from a group’s settings page. Contact your group’s Owner or Maintainer to setup custom project templates."
+msgstr ""
+
+msgid "Custom range"
+msgstr ""
+
+msgid "Custom range (UTC)"
+msgstr ""
+
+msgid "Customer contacts"
+msgstr ""
+
+msgid "Customer experience improvement and third-party offers"
+msgstr ""
+
+msgid "Customer organizations"
+msgstr ""
+
+msgid "Customer relations"
+msgstr ""
+
+msgid "Customer relations contacts"
+msgstr ""
+
+msgid "Customer relations organizations"
+msgstr ""
+
+msgid "Customize CI/CD settings, including Auto DevOps, shared runners, and job artifacts."
+msgstr ""
+
+msgid "Customize colors"
+msgstr ""
+
+msgid "Customize how FogBugz email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import."
+msgstr ""
+
+msgid "Customize icon"
+msgstr ""
+
+msgid "Customize language and region related settings."
+msgstr ""
+
+msgid "Customize name"
+msgstr ""
+
+msgid "Customize your pipeline configuration."
+msgstr ""
+
+msgid "Cycle Time"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|%{label_reference} label was added to the issue"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|%{label_reference} label was added to the merge request"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|%{label_reference} label was removed from the issue"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|%{label_reference} label was removed from the merge request"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue closed"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue created"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue first added to a board"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue first assigned"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue first associated with a milestone or first added to a board"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue label was added"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue label was removed"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Issue last edited"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request closed"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request created"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request first assigned"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request first commit time"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request first deployed to production"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request label was added"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request label was removed"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request last build finish time"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request last build start time"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request last edited"
+msgstr ""
+
+msgid "CycleAnalyticsEvent|Merge request merged"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Code"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Issue"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Plan"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Review"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Staging"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Test"
+msgstr ""
+
+msgid "CycleAnalyticsStage|Total"
+msgstr ""
+
+msgid "CycleAnalyticsStage|is not available for the selected group"
+msgstr ""
+
+msgid "CycleAnalytics|%{selectedLabelsCount} selected (%{maxLabels} max)"
+msgstr ""
+
+msgid "CycleAnalytics|'%{name}' is collecting the data. This can take a few minutes."
+msgstr ""
+
+msgid "CycleAnalytics|Average time to completion"
+msgstr ""
+
+msgid "CycleAnalytics|Average time to completion (days)"
+msgstr ""
+
+msgid "CycleAnalytics|Change Failure Rate"
+msgstr ""
+
+msgid "CycleAnalytics|Create a custom value stream to view metrics about stages specific to your development process. Use your value stream to visualize your DevSecOps lifecycle, determine the velocity of your group, and identify inefficient processes."
+msgstr ""
+
+msgid "CycleAnalytics|Custom value streams to measure your DevSecOps lifecycle"
+msgstr ""
+
+msgid "CycleAnalytics|Data is collecting and loading."
+msgstr ""
+
+msgid "CycleAnalytics|Date"
+msgstr ""
+
+msgid "CycleAnalytics|Display chart filters"
+msgstr ""
+
+msgid "CycleAnalytics|If you have recently upgraded your GitLab license from a tier without this feature, it can take up to 30 minutes for data to collect and display."
+msgstr ""
+
+msgid "CycleAnalytics|Lead Time for Changes"
+msgstr ""
+
+msgid "CycleAnalytics|New value stream…"
+msgstr ""
+
+msgid "CycleAnalytics|No data"
+msgstr ""
+
+msgid "CycleAnalytics|Number of tasks"
+msgstr ""
+
+msgid "CycleAnalytics|Only %{maxLabels} labels can be selected at this time"
+msgstr ""
+
+msgid "CycleAnalytics|Project selected"
+msgid_plural "CycleAnalytics|%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "CycleAnalytics|Select labels"
+msgstr ""
+
+msgid "CycleAnalytics|Show"
+msgstr ""
+
+msgid "CycleAnalytics|Stage time: %{title}"
+msgstr ""
+
+msgid "CycleAnalytics|The average time items spent in this stage. Data limited to items completed within this date range."
+msgstr ""
+
+msgid "CycleAnalytics|The given date range is larger than 180 days"
+msgstr ""
+
+msgid "CycleAnalytics|The total time items spent across each value stream stage. Data limited to items completed within this date range."
+msgstr ""
+
+msgid "CycleAnalytics|There is no data for 'Stage time' available. Adjust the current filters."
+msgstr ""
+
+msgid "CycleAnalytics|There is no data for 'Total time' available. Adjust the current filters."
+msgstr ""
+
+msgid "CycleAnalytics|Time to Restore Service"
+msgstr ""
+
+msgid "CycleAnalytics|Total time"
+msgstr ""
+
+msgid "CycleAnalytics|not allowed for the given start event"
+msgstr ""
+
+msgid "CycleAnalytics|project dropdown filter"
+msgstr ""
+
+msgid "CycleAnalytics|the assigned object is not supported"
+msgstr ""
+
+msgid "DAG visualization requires at least 3 dependent jobs."
+msgstr ""
+
+msgid "DAST configuration not found"
+msgstr ""
+
+msgid "DAST profile not found: %{name}"
+msgstr ""
+
+msgid "DAST profiles"
+msgstr ""
+
+msgid "DNS"
+msgstr ""
+
+msgid "DORA4Metrics|%d project"
+msgid_plural "DORA4Metrics|%d projects"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "DORA4Metrics|Accept testing terms"
+msgstr ""
+
+msgid "DORA4Metrics|Accept testing terms of use?"
+msgstr ""
+
+msgid "DORA4Metrics|All labels"
+msgstr ""
+
+msgid "DORA4Metrics|Analytics Dashboards"
+msgstr ""
+
+msgid "DORA4Metrics|Average (last %{days}d)"
+msgstr ""
+
+msgid "DORA4Metrics|By enabling this feature, you accept the %{url}"
+msgstr ""
+
+msgid "DORA4Metrics|Change Failure Rate"
+msgstr ""
+
+msgid "DORA4Metrics|Change Failure Rate (Quality)"
+msgstr ""
+
+msgid "DORA4Metrics|Change failure rate"
+msgstr ""
+
+msgid "DORA4Metrics|Change failure rate (percentage)"
+msgstr ""
+
+msgid "DORA4Metrics|Closed issues"
+msgstr ""
+
+msgid "DORA4Metrics|Critical Vulnerabilities over time"
+msgstr ""
+
+msgid "DORA4Metrics|Cycle time"
+msgstr ""
+
+msgid "DORA4Metrics|Date"
+msgstr ""
+
+msgid "DORA4Metrics|Days for an open incident"
+msgstr ""
+
+msgid "DORA4Metrics|Days from merge to deploy"
+msgstr ""
+
+msgid "DORA4Metrics|Deployment Frequency"
+msgstr ""
+
+msgid "DORA4Metrics|Deployment Frequency (Velocity)"
+msgstr ""
+
+msgid "DORA4Metrics|Deployment frequency"
+msgstr ""
+
+msgid "DORA4Metrics|Deploys"
+msgstr ""
+
+msgid "DORA4Metrics|Failed to generate forecast. Try again later. If the problem persists, consider %{linkStart}creating an issue%{linkEnd}."
+msgstr ""
+
+msgid "DORA4Metrics|Failed to load DORA performance scores for Namespace: %{fullPath}"
+msgstr ""
+
+msgid "DORA4Metrics|Failed to load YAML config from Project: %{fullPath}"
+msgstr ""
+
+msgid "DORA4Metrics|Failed to load comparison chart for Namespace: %{fullPath}"
+msgstr ""
+
+msgid "DORA4Metrics|Failed to load labels matching the filter: %{labels}"
+msgstr ""
+
+msgid "DORA4Metrics|Filtered by"
+msgstr ""
+
+msgid "DORA4Metrics|Forecast"
+msgstr ""
+
+msgid "DORA4Metrics|Go to docs"
+msgstr ""
+
+msgid "DORA4Metrics|Has no calculated data."
+msgid_plural "DORA4Metrics|Have no calculated data."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "DORA4Metrics|Have 30 or more deploys to production per day."
+msgstr ""
+
+msgid "DORA4Metrics|Have between 1 to 29 deploys to production per day."
+msgstr ""
+
+msgid "DORA4Metrics|Have less than 1 deploy to production per day."
+msgstr ""
+
+msgid "DORA4Metrics|High"
+msgstr ""
+
+msgid "DORA4Metrics|High Vulnerabilities over time"
+msgstr ""
+
+msgid "DORA4Metrics|Lead Time for Changes"
+msgstr ""
+
+msgid "DORA4Metrics|Lead Time for Changes (Velocity)"
+msgstr ""
+
+msgid "DORA4Metrics|Lead time"
+msgstr ""
+
+msgid "DORA4Metrics|Lead time for changes"
+msgstr ""
+
+msgid "DORA4Metrics|Lead time for changes (median days)"
+msgstr ""
+
+msgid "DORA4Metrics|Low"
+msgstr ""
+
+msgid "DORA4Metrics|Made 15%% or less changes to production resulted in degraded service."
+msgstr ""
+
+msgid "DORA4Metrics|Made between 16%% to 44%% of changes to production resulted in degraded service."
+msgstr ""
+
+msgid "DORA4Metrics|Made more than 45%% of changes to production resulted in degraded service."
+msgstr ""
+
+msgid "DORA4Metrics|Median (last %{days}d)"
+msgstr ""
+
+msgid "DORA4Metrics|Median time (last %{days}d)"
+msgstr ""
+
+msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
+msgstr ""
+
+msgid "DORA4Metrics|Medium"
+msgstr ""
+
+msgid "DORA4Metrics|Merge request throughput"
+msgstr ""
+
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
+msgid "DORA4Metrics|Metrics comparison for %{name} group"
+msgstr ""
+
+msgid "DORA4Metrics|Metrics comparison for %{name} project"
+msgstr ""
+
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
+msgid "DORA4Metrics|New issues"
+msgstr ""
+
+msgid "DORA4Metrics|No data available for Namespace: %{fullPath}"
+msgstr ""
+
+msgid "DORA4Metrics|No incidents during this period"
+msgstr ""
+
+msgid "DORA4Metrics|No merge requests were deployed during this period"
+msgstr ""
+
+msgid "DORA4Metrics|Not included"
+msgstr ""
+
+msgid "DORA4Metrics|Number of incidents divided by the number of deployments to a production environment in the given time period."
+msgstr ""
+
+msgid "DORA4Metrics|Past 6 Months"
+msgstr ""
+
+msgid "DORA4Metrics|Percentage of failed deployments"
+msgstr ""
+
+msgid "DORA4Metrics|Predicted number of deployments"
+msgstr ""
+
+msgid "DORA4Metrics|Show forecast"
+msgstr ""
+
+msgid "DORA4Metrics|Some metric charts failed to load"
+msgstr ""
+
+msgid "DORA4Metrics|Some metric comparisons failed to load"
+msgstr ""
+
+msgid "DORA4Metrics|Something went wrong while getting change failure rate data."
+msgstr ""
+
+msgid "DORA4Metrics|Something went wrong while getting deployment frequency data."
+msgstr ""
+
+msgid "DORA4Metrics|Something went wrong while getting lead time data."
+msgstr ""
+
+msgid "DORA4Metrics|Something went wrong while getting time to restore service data."
+msgstr ""
+
+msgid "DORA4Metrics|The Value Streams Dashboard allows all stakeholders from executives to individual contributors to identify trends, patterns, and opportunities for software development improvements."
+msgstr ""
+
+msgid "DORA4Metrics|The chart displays the frequency of deployments to production environment(s) that are based on the %{linkStart}deployment_tier%{linkEnd} value."
+msgstr ""
+
+msgid "DORA4Metrics|The chart displays the median time between a merge request being merged and deployed to production environment(s) that are based on the %{linkStart}deployment_tier%{linkEnd} value."
+msgstr ""
+
+msgid "DORA4Metrics|The forecast might be inaccurate. To improve it, select a wider time frame or try again when more data is available"
+msgstr ""
+
+msgid "DORA4Metrics|This is a lower-bound approximation. Your group has too many issues and MRs to calculate in real time."
+msgstr ""
+
+msgid "DORA4Metrics|This visualization is not supported for project namespaces."
+msgstr ""
+
+msgid "DORA4Metrics|Time to Restore Service"
+msgstr ""
+
+msgid "DORA4Metrics|Time to Restore Service (Quality)"
+msgstr ""
+
+msgid "DORA4Metrics|Time to restore service"
+msgstr ""
+
+msgid "DORA4Metrics|Time to restore service (median days)"
+msgstr ""
+
+msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
+msgstr ""
+
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
+msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
+msgstr ""
+
+msgid "DORA4Metrics|Took 7 days or less to go from code committed to code successfully running in production."
+msgstr ""
+
+msgid "DORA4Metrics|Took between 2 to 6 days to restore service when a service incident or a defect that impacts users occurs."
+msgstr ""
+
+msgid "DORA4Metrics|Took between 8 to 29 days to go from code committed to code successfully running in production."
+msgstr ""
+
+msgid "DORA4Metrics|Took more than 30 days to go from code committed to code successfully running in production."
+msgstr ""
+
+msgid "DORA4Metrics|Took more than 7 days to restore service when a service incident or a defect that impacts users occurs."
+msgstr ""
+
+msgid "DORA4Metrics|Total projects (%{count}) by DORA performers score for %{groupName} group"
+msgstr ""
+
+msgid "DORA4Metrics|Total projects by DORA performers score"
+msgstr ""
+
+msgid "DORA4Metrics|Value Streams Dashboard"
+msgstr ""
+
+msgid "DSN"
+msgstr ""
+
+msgid "Dashboard"
+msgstr ""
+
+msgid "DashboardProjects|All"
+msgstr ""
+
+msgid "DashboardProjects|Personal"
+msgstr ""
+
+msgid "Dashboards"
+msgstr ""
+
+msgid "Dashboard|%{firstProject} and %{secondProject}"
+msgstr ""
+
+msgid "Dashboard|%{firstProject}, %{rest}, and %{secondProject}"
+msgstr ""
+
+msgid "Dashboard|Unable to add %{invalidProjects}. This dashboard is available for public projects, and private projects in groups with a Premium plan."
+msgstr ""
+
+msgid "DastConfig|Customize DAST settings to suit your requirements. Configuration changes made here override those provided by GitLab and are excluded from updates. For details of more advanced configuration options, see the %{docsLinkStart}GitLab DAST documentation%{docsLinkEnd}."
+msgstr ""
+
+msgid "DastConfig|DAST CI/CD configuration"
+msgstr ""
+
+msgid "DastConfig|Enable DAST to automatically test for vulnerabilities in your project's running application, website, or API, in the CI/CD pipeline. Configuration changes must be applied to your .gitlab-ci.yml file to take effect. For details of all configuration options, see the %{linkStart}GitLab DAST documentation%{linkEnd}."
+msgstr ""
+
+msgid "DastConfig|Enabled"
+msgstr ""
+
+msgid "DastConfig|Generate code snippet"
+msgstr ""
+
+msgid "DastConfig|Last scan triggered %{runTimeAgo} in pipeline "
+msgstr ""
+
+msgid "DastConfig|No previous scans found for this project"
+msgstr ""
+
+msgid "DastConfig|Not enabled"
+msgstr ""
+
+msgid "DastProfiles|/graphql"
+msgstr ""
+
+msgid "DastProfiles|A passive scan monitors all HTTP messages (requests and responses) sent to the target. An active scan attacks the target to find potential vulnerabilities."
+msgstr ""
+
+msgid "DastProfiles|A scanner profile defines the configuration details of a security scanner. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "DastProfiles|A site profile defines the attributes and configuration details of your deployed application, website, or API. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "DastProfiles|AJAX spider"
+msgstr ""
+
+msgid "DastProfiles|API"
+msgstr ""
+
+msgid "DastProfiles|API endpoint URL"
+msgstr ""
+
+msgid "DastProfiles|Active"
+msgstr ""
+
+msgid "DastProfiles|Additional request headers (optional)"
+msgstr ""
+
+msgid "DastProfiles|Are you sure you want to delete this profile?"
+msgstr ""
+
+msgid "DastProfiles|Attacks the target to find potential vulnerabilities. Active scans are potentially harmful to the site being scanned."
+msgstr ""
+
+msgid "DastProfiles|Authentication"
+msgstr ""
+
+msgid "DastProfiles|Authentication URL"
+msgstr ""
+
+msgid "DastProfiles|Branch missing"
+msgstr ""
+
+msgid "DastProfiles|Change scanner profile"
+msgstr ""
+
+msgid "DastProfiles|Change site profile"
+msgstr ""
+
+msgid "DastProfiles|Choose a scan method"
+msgstr ""
+
+msgid "DastProfiles|Could not create the scanner profile. Please try again."
+msgstr ""
+
+msgid "DastProfiles|Could not create the site profile. Please try again."
+msgstr ""
+
+msgid "DastProfiles|Could not delete scanner profile. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not delete scanner profiles:"
+msgstr ""
+
+msgid "DastProfiles|Could not delete site profile. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not delete site profiles:"
+msgstr ""
+
+msgid "DastProfiles|Could not fetch scanner profiles. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
+msgid "DastProfiles|Could not update the site profile. Please try again."
+msgstr ""
+
+msgid "DastProfiles|DAST profile library"
+msgstr ""
+
+msgid "DastProfiles|Debug messages"
+msgstr ""
+
+msgid "DastProfiles|Delete profile"
+msgstr ""
+
+msgid "DastProfiles|Edit profile"
+msgstr ""
+
+msgid "DastProfiles|Edit scanner profile"
+msgstr ""
+
+msgid "DastProfiles|Edit site profile"
+msgstr ""
+
+msgid "DastProfiles|Enable Authentication"
+msgstr ""
+
+msgid "DastProfiles|Enable Basic Authentication"
+msgstr ""
+
+msgid "DastProfiles|Enter URLs in a comma-separated list."
+msgstr ""
+
+msgid "DastProfiles|Enter a comma-separated list of request header names and values. DAST adds header to every request."
+msgstr ""
+
+msgid "DastProfiles|Error Details"
+msgstr ""
+
+msgid "DastProfiles|Excluded URLs"
+msgstr ""
+
+msgid "DastProfiles|Excluded URLs (optional)"
+msgstr ""
+
+msgid "DastProfiles|Excluded paths"
+msgstr ""
+
+msgid "DastProfiles|Excluded paths (optional)"
+msgstr ""
+
+msgid "DastProfiles|Headers will appear in vulnerability reports. %{linkStart}Only some headers are automatically masked%{linkEnd}."
+msgstr ""
+
+msgid "DastProfiles|Hide debug messages"
+msgstr ""
+
+msgid "DastProfiles|Include debug messages in the DAST console output."
+msgstr ""
+
+msgid "DastProfiles|Manage %{profileType} profiles"
+msgstr ""
+
+msgid "DastProfiles|Manage profiles"
+msgstr ""
+
+msgid "DastProfiles|Minimum = 0 (no timeout enabled), Maximum = 2880 minutes"
+msgstr ""
+
+msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
+msgstr ""
+
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
+msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
+msgstr ""
+
+msgid "DastProfiles|Must allow introspection queries to request the API schema. %{linkStart}How do I enable introspection%{linkEnd}?"
+msgstr ""
+
+msgid "DastProfiles|New scanner profile"
+msgstr ""
+
+msgid "DastProfiles|New site profile"
+msgstr ""
+
+msgid "DastProfiles|No scanner profile selected"
+msgstr ""
+
+msgid "DastProfiles|No scanner profiles created yet"
+msgstr ""
+
+msgid "DastProfiles|No site profile selected"
+msgstr ""
+
+msgid "DastProfiles|No site profiles created yet"
+msgstr ""
+
+msgid "DastProfiles|Not Validated"
+msgstr ""
+
+msgid "DastProfiles|Passive"
+msgstr ""
+
+msgid "DastProfiles|Password"
+msgstr ""
+
+msgid "DastProfiles|Password form field"
+msgstr ""
+
+msgid "DastProfiles|Profile in use and cannot be renamed"
+msgstr ""
+
+msgid "DastProfiles|Profile is being used by this on-demand scan"
+msgstr ""
+
+msgid "DastProfiles|Profile name"
+msgstr ""
+
+msgid "DastProfiles|Request headers"
+msgstr ""
+
+msgid "DastProfiles|Retry"
+msgstr ""
+
+msgid "DastProfiles|Run the AJAX spider, in addition to the traditional spider, to crawl the target site."
+msgstr ""
+
+msgid "DastProfiles|Save commonly used configurations for target sites and scan specifications as profiles. Use these with an on-demand scan."
+msgstr ""
+
+msgid "DastProfiles|Save profile"
+msgstr ""
+
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
+msgid "DastProfiles|Scan method"
+msgstr ""
+
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
+msgid "DastProfiles|Scanner name"
+msgstr ""
+
+msgid "DastProfiles|Scanner profile"
+msgstr ""
+
+msgid "DastProfiles|Scanner profiles"
+msgstr ""
+
+msgid "DastProfiles|Select a scanner profile to run a DAST scan"
+msgstr ""
+
+msgid "DastProfiles|Select a site profile to run a DAST scan"
+msgstr ""
+
+msgid "DastProfiles|Select branch"
+msgstr ""
+
+msgid "DastProfiles|Select scanner profile"
+msgstr ""
+
+msgid "DastProfiles|Select site profile"
+msgstr ""
+
+msgid "DastProfiles|Show debug messages"
+msgstr ""
+
+msgid "DastProfiles|Site name"
+msgstr ""
+
+msgid "DastProfiles|Site profile"
+msgstr ""
+
+msgid "DastProfiles|Site profiles"
+msgstr ""
+
+msgid "DastProfiles|Site type"
+msgstr ""
+
+msgid "DastProfiles|Spider timeout"
+msgstr ""
+
+msgid "DastProfiles|Submit button"
+msgstr ""
+
+msgid "DastProfiles|Submit button (optional)"
+msgstr ""
+
+msgid "DastProfiles|Target URL"
+msgstr ""
+
+msgid "DastProfiles|Target timeout"
+msgstr ""
+
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
+msgstr ""
+
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgstr ""
+
+msgid "DastProfiles|This profile is currently being used in a policy."
+msgstr ""
+
+msgid "DastProfiles|This scanner profile is currently being used by a policy. To make edits you must remove it from the active policy."
+msgstr ""
+
+msgid "DastProfiles|This site profile is currently being used by a policy. To make edits you must remove it from the active policy."
+msgstr ""
+
+msgid "DastProfiles|Turn on AJAX spider"
+msgstr ""
+
+msgid "DastProfiles|URL"
+msgstr ""
+
+msgid "DastProfiles|URLs to skip during the authenticated scan."
+msgstr ""
+
+msgid "DastProfiles|Username"
+msgstr ""
+
+msgid "DastProfiles|Username form field"
+msgstr ""
+
+msgid "DastProfiles|Validate"
+msgstr ""
+
+msgid "DastProfiles|Validate site profile"
+msgstr ""
+
+msgid "DastProfiles|Validated"
+msgstr ""
+
+msgid "DastProfiles|Validation status"
+msgstr ""
+
+msgid "DastProfiles|Website"
+msgstr ""
+
+msgid "DastProfiles|What does each method do?"
+msgstr ""
+
+msgid "DastProfiles|You can either choose a passive scan or validate the target site from the site profile management page. %{docsLinkStart}Learn more about site validation.%{docsLinkEnd}"
+msgstr ""
+
+msgid "DastProfiles|You cannot run an active scan against an unvalidated site."
+msgstr ""
+
+msgid "DastProfiles|https://example.com/dast_example.har"
+msgstr ""
+
+msgid "DastProfiles|https://example.com/openapi.json"
+msgstr ""
+
+msgid "DastProfiles|https://example.com/postman_collection.json"
+msgstr ""
+
+msgid "DastSiteValidation|Copy HTTP header to clipboard"
+msgstr ""
+
+msgid "DastSiteValidation|Copy Meta tag to clipboard"
+msgstr ""
+
+msgid "DastSiteValidation|Could not create validation token. Please try again."
+msgstr ""
+
+msgid "DastSiteValidation|Could not revoke validation. Please try again."
+msgstr ""
+
+msgid "DastSiteValidation|Download validation text file"
+msgstr ""
+
+msgid "DastSiteValidation|Header validation"
+msgstr ""
+
+msgid "DastSiteValidation|Meta tag validation"
+msgstr ""
+
+msgid "DastSiteValidation|Not validated"
+msgstr ""
+
+msgid "DastSiteValidation|Retry validation"
+msgstr ""
+
+msgid "DastSiteValidation|Revoke validation"
+msgstr ""
+
+msgid "DastSiteValidation|Step 1 - Choose site validation method."
+msgstr ""
+
+msgid "DastSiteValidation|Step 2 - Add the following HTTP header to your site."
+msgstr ""
+
+msgid "DastSiteValidation|Step 2 - Add the following meta tag to your site."
+msgstr ""
+
+msgid "DastSiteValidation|Step 2 - Download the following text file, then upload it to the target site."
+msgstr ""
+
+msgid "DastSiteValidation|Step 3 - Confirm header location."
+msgstr ""
+
+msgid "DastSiteValidation|Step 3 - Confirm meta tag location."
+msgstr ""
+
+msgid "DastSiteValidation|Step 3 - Confirm text file location."
+msgstr ""
+
+msgid "DastSiteValidation|Text file validation"
+msgstr ""
+
+msgid "DastSiteValidation|The validation has failed. Please try again."
+msgstr ""
+
+msgid "DastSiteValidation|The validation is in progress. Please wait..."
+msgstr ""
+
+msgid "DastSiteValidation|This will affect %d other profile targeting the same URL."
+msgid_plural "DastSiteValidation|This will affect %d other profiles targeting the same URL."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "DastSiteValidation|To run an active scan, validate your site. Site profile validation reduces the risk of running an active scan against the wrong website. All site profiles that share the same base URL share the same validation status."
+msgstr ""
+
+msgid "DastSiteValidation|Validate"
+msgstr ""
+
+msgid "DastSiteValidation|Validate site"
+msgstr ""
+
+msgid "DastSiteValidation|Validated"
+msgstr ""
+
+msgid "DastSiteValidation|Validating..."
+msgstr ""
+
+msgid "DastSiteValidation|Validation failed"
+msgstr ""
+
+msgid "DastSiteValidation|Validation failed for %{url}. %{retryButtonStart}Retry validation%{retryButtonEnd}."
+msgstr ""
+
+msgid "DastSiteValidation|Validation succeeded. Both active and passive scans can be run against the target site."
+msgstr ""
+
+msgid "DastSiteValidation|You will not be able to run active scans against %{url}."
+msgstr ""
+
+msgid "Data is still calculating..."
+msgstr ""
+
+msgid "Data refresh"
+msgstr ""
+
+msgid "Data type"
+msgstr ""
+
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but this version of GitLab requires PostgreSQL %{pg_version_minimum}. Please upgrade your environment to a supported PostgreSQL version. See %{pg_requirements_url} for details."
+msgstr ""
+
+msgid "Database update failed"
+msgstr ""
+
+msgid "DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog."
+msgstr ""
+
+msgid "DatadogIntegration|(Advanced) The full URL for your Datadog site."
+msgstr ""
+
+msgid "DatadogIntegration|API URL"
+msgstr ""
+
+msgid "DatadogIntegration|Custom tags in Datadog. Enter one tag per line in the %{codeOpen}key:value%{codeClose} format. %{linkOpen}How do I use tags?%{linkClose}"
+msgstr ""
+
+msgid "DatadogIntegration|Environment"
+msgstr ""
+
+msgid "DatadogIntegration|For self-managed deployments, set the %{codeOpen}env%{codeClose} tag for all the data sent to Datadog. %{linkOpen}How do I use tags?%{linkClose}"
+msgstr ""
+
+msgid "DatadogIntegration|How do I set up this integration?"
+msgstr ""
+
+msgid "DatadogIntegration|Send CI/CD pipeline information to Datadog to monitor for job failures and troubleshoot performance issues. %{docs_link}"
+msgstr ""
+
+msgid "DatadogIntegration|Service"
+msgstr ""
+
+msgid "DatadogIntegration|Tag all data from this GitLab instance in Datadog. Useful when managing several self-managed deployments."
+msgstr ""
+
+msgid "DatadogIntegration|Tags"
+msgstr ""
+
+msgid "DatadogIntegration|The Datadog site to send data to. To send data to the EU site, use %{codeOpen}datadoghq.eu%{codeClose}."
+msgstr ""
+
+msgid "DatadogIntegration|Trace your GitLab pipelines with Datadog."
+msgstr ""
+
+msgid "DatadogIntegration|have an invalid format"
+msgstr ""
+
+msgid "Date"
+msgstr ""
+
+msgid "Date merged"
+msgstr ""
+
+msgid "Date range"
+msgstr ""
+
+msgid "Date range limited to %d day"
+msgid_plural "Date range limited to %d days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Date range limited to %{number} days"
+msgstr ""
+
+msgid "Date range must be shorter than %{max_range} days."
+msgstr ""
+
+msgid "Date range too large"
+msgstr ""
+
+msgid "DateRange|%{start_date}–%{end_date}"
+msgstr ""
+
+msgid "Day of month"
+msgstr ""
+
+msgid "DayTitle|F"
+msgstr ""
+
+msgid "DayTitle|M"
+msgstr ""
+
+msgid "DayTitle|S"
+msgstr ""
+
+msgid "DayTitle|W"
+msgstr ""
+
+msgid "Days"
+msgstr ""
+
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
+msgid "Days to merge"
+msgstr ""
+
+msgid "Deactivate"
+msgstr ""
+
+msgid "Deactivate dormant users after a period of inactivity"
+msgstr ""
+
+msgid "Dear Administrator,"
+msgstr ""
+
+msgid "Debug"
+msgstr ""
+
+msgid "Dec"
+msgstr ""
+
+msgid "December"
+msgstr ""
+
+msgid "Decline"
+msgstr ""
+
+msgid "Decline and sign out"
+msgstr ""
+
+msgid "Decompressed archive size validation failed."
+msgstr ""
+
+msgid "Decrease"
+msgstr ""
+
+msgid "Decrement suggestion line end"
+msgstr ""
+
+msgid "Decrement suggestion line start"
+msgstr ""
+
+msgid "Default - Never run"
+msgstr ""
+
+msgid "Default CI/CD configuration file"
+msgstr ""
+
+msgid "Default artifacts expiration"
+msgstr ""
+
+msgid "Default branch"
+msgstr ""
+
+msgid "Default branch and protected branches"
+msgstr ""
+
+msgid "Default description template for issues"
+msgstr ""
+
+msgid "Default description template for merge requests"
+msgstr ""
+
+msgid "Default first day of the week"
+msgstr ""
+
+msgid "Default first day of the week in calendars and date pickers."
+msgstr ""
+
+msgid "Default language"
+msgstr ""
+
+msgid "Default language for users who are not logged in."
+msgstr ""
+
+msgid "Default projects limit"
+msgstr ""
+
+msgid "Default timeout"
+msgstr ""
+
+msgid "Default: Map a FogBugz account ID to a full name"
+msgstr ""
+
+msgid "DefaultBranchLabel|default"
+msgstr ""
+
+msgid "DefaultBranchProtection|Both developers and maintainers can push new commits, but cannot force push."
+msgstr ""
+
+msgid "DefaultBranchProtection|Both developers and maintainers can push new commits, force push, or delete the branch."
+msgstr ""
+
+msgid "DefaultBranchProtection|Developers can push the initial commit to a repository, but none afterward. Maintainers can always push. No one can force push."
+msgstr ""
+
+msgid "DefaultBranchProtection|Developers cannot push new commits, but are allowed to accept merge requests to the branch. Maintainers can push to the branch."
+msgstr ""
+
+msgid "DefaultBranchProtection|Developers cannot push new commits, but maintainers can. No one can force push."
+msgstr ""
+
+msgid "DefaultBranchProtection|Fully protected"
+msgstr ""
+
+msgid "DefaultBranchProtection|Fully protected after initial push"
+msgstr ""
+
+msgid "DefaultBranchProtection|Not protected"
+msgstr ""
+
+msgid "DefaultBranchProtection|Partially protected"
+msgstr ""
+
+msgid "DefaultBranchProtection|Protected against pushes"
+msgstr ""
+
+msgid "Define a custom deploy freeze pattern with %{cronSyntaxStart}cron syntax%{cronSyntaxEnd}."
+msgstr ""
+
+msgid "Define a custom pattern with cron syntax"
+msgstr ""
+
+msgid "Define custom rules for what constitutes spam, independent of Akismet"
+msgstr ""
+
+msgid "Define how approval rules are applied to merge requests."
+msgstr ""
+
+msgid "Define rules for who can push, merge, and the required approvals for each branch."
+msgstr ""
+
+msgid "Definition"
+msgstr ""
+
+msgid "Delay 2FA enforcement (hours)"
+msgstr ""
+
+msgid "DelayedJobs|Are you sure you want to run %{jobName} immediately? Otherwise this job will run automatically after its timer finishes."
+msgstr ""
+
+msgid "DelayedJobs|Are you sure you want to run %{job_name} immediately? This job will run automatically after it's timer finishes."
+msgstr ""
+
+msgid "DelayedJobs|Are you sure you want to run %{job_name} immediately? This job will run automatically after its timer finishes."
+msgstr ""
+
+msgid "DelayedJobs|Run the delayed job now?"
+msgstr ""
+
+msgid "DelayedJobs|Start now"
+msgstr ""
+
+msgid "DelayedJobs|Unschedule"
+msgstr ""
+
+msgid "DelayedJobs|delayed"
+msgstr ""
+
+msgid "Delete"
+msgstr ""
+
+msgid "Delete %{issuableType}"
+msgstr ""
+
+msgid "Delete %{issuableType}?"
+msgstr ""
+
+msgid "Delete %{name}"
+msgstr ""
+
+msgid "Delete Comment"
+msgstr ""
+
+msgid "Delete File"
+msgstr ""
+
+msgid "Delete Key"
+msgstr ""
+
+msgid "Delete Value Stream"
+msgstr ""
+
+msgid "Delete account"
+msgstr ""
+
+msgid "Delete asset"
+msgstr ""
+
+msgid "Delete audio"
+msgstr ""
+
+msgid "Delete badge"
+msgstr ""
+
+msgid "Delete code block"
+msgstr ""
+
+msgid "Delete column"
+msgid_plural "Delete %d columns"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Delete comment"
+msgstr ""
+
+msgid "Delete comment template"
+msgstr ""
+
+msgid "Delete comment?"
+msgstr ""
+
+msgid "Delete corpus"
+msgstr ""
+
+msgid "Delete custom emoji"
+msgstr ""
+
+msgid "Delete deploy key"
+msgstr ""
+
+msgid "Delete diagram"
+msgstr ""
+
+msgid "Delete epic"
+msgstr ""
+
+msgid "Delete file"
+msgstr ""
+
+msgid "Delete identity"
+msgstr ""
+
+msgid "Delete image"
+msgstr ""
+
+msgid "Delete internal note"
+msgstr ""
+
+msgid "Delete label"
+msgstr ""
+
+msgid "Delete label: %{labelName}"
+msgstr ""
+
+msgid "Delete pipeline"
+msgstr ""
+
+msgid "Delete project"
+msgstr ""
+
+msgid "Delete release"
+msgstr ""
+
+msgid "Delete release %{release}?"
+msgstr ""
+
+msgid "Delete row"
+msgid_plural "Delete %d rows"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Delete selected"
+msgstr ""
+
+msgid "Delete snippet"
+msgstr ""
+
+msgid "Delete snippet?"
+msgstr ""
+
+msgid "Delete source branch"
+msgstr ""
+
+msgid "Delete source branch when merge request is accepted."
+msgstr ""
+
+msgid "Delete subscription"
+msgstr ""
+
+msgid "Delete table"
+msgstr ""
+
+msgid "Delete this attachment"
+msgstr ""
+
+msgid "Delete this epic and all descendants?"
+msgstr ""
+
+msgid "Delete this project"
+msgstr ""
+
+msgid "Delete user list"
+msgstr ""
+
+msgid "Delete variable"
+msgstr ""
+
+msgid "Delete video"
+msgstr ""
+
+msgid "DeleteProject|Failed to remove design repository. Please try again or contact administrator."
+msgstr ""
+
+msgid "DeleteProject|Failed to remove events. Please try again or contact administrator."
+msgstr ""
+
+msgid "DeleteProject|Failed to remove project repository. Please try again or contact administrator."
+msgstr ""
+
+msgid "DeleteProject|Failed to remove project snippets. Please try again or contact administrator."
+msgstr ""
+
+msgid "DeleteProject|Failed to remove some tags in project container registry. Please try again or contact administrator."
+msgstr ""
+
+msgid "DeleteProject|Failed to remove webhooks. Please try again or contact administrator."
+msgstr ""
+
+msgid "DeleteProject|Failed to remove wiki repository. Please try again or contact administrator."
+msgstr ""
+
+msgid "DeleteRelease|Are you sure you want to delete this release?"
+msgstr ""
+
+msgid "DeleteRelease|For more details, see %{docsPathStart}Deleting a release%{docsPathEnd}."
+msgstr ""
+
+msgid "DeleteRelease|You are about to delete release %{release} and its assets. The Git tag %{tag} will not be deleted."
+msgstr ""
+
+msgid "DeleteValueStream|'%{name}' Value Stream deleted"
+msgstr ""
+
+msgid "DeleteValueStream|Are you sure you want to delete the \"%{name}\" Value Stream?"
+msgstr ""
+
+msgid "DeleteValueStream|Delete %{name}"
+msgstr ""
+
+msgid "Deleted"
+msgstr ""
+
+msgid "Deleted chat nickname: %{chat_name}!"
+msgstr ""
+
+msgid "Deleted commits:"
+msgstr ""
+
+msgid "Deleted projects cannot be restored!"
+msgstr ""
+
+msgid "Deleted the source branch."
+msgstr ""
+
+msgid "Deletes the source branch"
+msgstr ""
+
+msgid "Deleting"
+msgstr ""
+
+msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "Deleting the project will delete its repository and all related resources, including issues and merge requests."
+msgstr ""
+
+msgid "Deletion pending. This project will be deleted on %{date}. Repository and other project resources are read-only."
+msgstr ""
+
+msgid "DeletionSettings|Deletion protection"
+msgstr ""
+
+msgid "DeletionSettings|Keep deleted projects for %{number} day"
+msgid_plural "DeletionSettings|Keep deleted projects for %{number} days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "DeletionSettings|Only administrators can delete projects."
+msgstr ""
+
+msgid "DeletionSettings|Owners and administrators can delete projects."
+msgstr ""
+
+msgid "DeletionSettings|Period that deleted groups and projects will remain restorable for. Personal projects are always deleted immediately."
+msgstr ""
+
+msgid "Denied"
+msgstr ""
+
+msgid "Denied authorization of chat nickname %{user_name}."
+msgstr ""
+
+msgid "Deny"
+msgstr ""
+
+msgid "Deny access request"
+msgstr ""
+
+msgid "Dependencies"
+msgstr ""
+
+msgid "Dependencies help page link"
+msgstr ""
+
+msgid "Dependencies|%d additional vulnerability not shown"
+msgid_plural "Dependencies|%d additional vulnerabilities not shown"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Dependencies|%d more"
+msgid_plural "Dependencies|%d more"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Dependencies|%d vulnerability detected"
+msgid_plural "Dependencies|%d vulnerabilities detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Dependencies|%{locationCount} locations"
+msgstr ""
+
+msgid "Dependencies|%{projectCount} projects"
+msgstr ""
+
+msgid "Dependencies|%{remainingLicensesCount} more"
+msgstr ""
+
+msgid "Dependencies|(top level)"
+msgstr ""
+
+msgid "Dependencies|All"
+msgstr ""
+
+msgid "Dependencies|Component"
+msgstr ""
+
+msgid "Dependencies|Component name"
+msgstr ""
+
+msgid "Dependencies|Dependency path"
+msgstr ""
+
+msgid "Dependencies|Error exporting the dependency list. Please reload the page."
+msgstr ""
+
+msgid "Dependencies|Export as JSON"
+msgstr ""
+
+msgid "Dependencies|Job failed to generate the dependency list"
+msgstr ""
+
+msgid "Dependencies|Learn more about dependency paths"
+msgstr ""
+
+msgid "Dependencies|License"
+msgstr ""
+
+msgid "Dependencies|Location"
+msgstr ""
+
+msgid "Dependencies|Location and dependency path"
+msgstr ""
+
+msgid "Dependencies|Packager"
+msgstr ""
+
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
+msgid "Dependencies|Projects"
+msgstr ""
+
+msgid "Dependencies|Software Bill of Materials (SBOM) based on the %{linkStart}latest successful%{linkEnd} scan"
+msgstr ""
+
+msgid "Dependencies|Software Bill of Materials (SBOM) based on the latest successful scan of each project."
+msgstr ""
+
+msgid "Dependencies|The %{codeStartTag}dependency_scanning%{codeEndTag} job has failed and cannot generate the list. Please ensure the job is running properly and run the pipeline again."
+msgstr ""
+
+msgid "Dependencies|The component dependency path is based on the lock file. There may be several paths. In these cases, the longest path is displayed."
+msgstr ""
+
+msgid "Dependencies|There may be multiple paths"
+msgstr ""
+
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
+msgid "Dependencies|Toggle vulnerability list"
+msgstr ""
+
+msgid "Dependencies|Unsupported file(s) detected"
+msgstr ""
+
+msgid "Dependencies|Vulnerable components"
+msgstr ""
+
+msgid "Dependencies|unknown"
+msgstr ""
+
+msgid "Dependency List has no entries"
+msgstr ""
+
+msgid "Dependency Proxy"
+msgstr ""
+
+msgid "Dependency Scanning"
+msgstr ""
+
+msgid "Dependency chains are not supported"
+msgstr ""
+
+msgid "Dependency list"
+msgstr ""
+
+msgid "DependencyProxy|%{docLinkStart}See the documentation%{docLinkEnd} for other ways to store Docker images in Dependency Proxy cache."
+msgstr ""
+
+msgid "DependencyProxy|All items in the cache are scheduled for removal."
+msgstr ""
+
+msgid "DependencyProxy|Cached %{time}"
+msgstr ""
+
+msgid "DependencyProxy|Clear cache"
+msgstr ""
+
+msgid "DependencyProxy|Clear the Dependency Proxy cache automatically"
+msgstr ""
+
+msgid "DependencyProxy|Configure in settings"
+msgstr ""
+
+msgid "DependencyProxy|Contains %{count} blobs of images (%{size})"
+msgstr ""
+
+msgid "DependencyProxy|Copy example"
+msgstr ""
+
+msgid "DependencyProxy|Copy image path"
+msgstr ""
+
+msgid "DependencyProxy|Copy prefix"
+msgstr ""
+
+msgid "DependencyProxy|Dependency Proxy"
+msgstr ""
+
+msgid "DependencyProxy|Dependency Proxy image prefix"
+msgstr ""
+
+msgid "DependencyProxy|Digest: %{shortDigest}"
+msgstr ""
+
+msgid "DependencyProxy|Enable Dependency Proxy"
+msgstr ""
+
+msgid "DependencyProxy|Enable the Dependency Proxy to cache container images from Docker Hub and automatically clear the cache."
+msgstr ""
+
+msgid "DependencyProxy|Image list"
+msgstr ""
+
+msgid "DependencyProxy|Pull image by digest example"
+msgstr ""
+
+msgid "DependencyProxy|Scheduled for deletion"
+msgstr ""
+
+msgid "DependencyProxy|There are no images in the cache"
+msgstr ""
+
+msgid "DependencyProxy|To see the image prefix and what is in the cache, visit the %{linkStart}Dependency Proxy%{linkEnd}"
+msgstr ""
+
+msgid "DependencyProxy|To store docker images in Dependency Proxy cache, pull an image by tag in your %{codeStart}.gitlab-ci.yml%{codeEnd} file. In this example, the image is %{codeStart}alpine:latest%{codeEnd}"
+msgstr ""
+
+msgid "DependencyProxy|When enabled, images older than 90 days will be removed from the cache."
+msgstr ""
+
+msgid "Depends on %d merge request being merged"
+msgid_plural "Depends on %d merge requests being merged"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Depends on %{strongStart}%{closedCount} closed%{strongEnd} merge request."
+msgid_plural "Depends on %{strongStart}%{closedCount} closed%{strongEnd} merge requests."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Deploy"
+msgid_plural "Deploys"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Deploy Key"
+msgstr ""
+
+msgid "Deploy Keys"
+msgstr ""
+
+msgid "Deploy Token"
+msgstr ""
+
+msgid "Deploy container based web apps on Google managed clusters"
+msgstr ""
+
+msgid "Deploy freezes"
+msgstr ""
+
+msgid "Deploy key was successfully updated."
+msgstr ""
+
+msgid "Deploy keys"
+msgstr ""
+
+msgid "Deploy keys grant read/write access to all repositories in your instance, start by creating a new one above."
+msgstr ""
+
+msgid "Deploy progress not found. To see pods, ensure your environment matches %{linkStart}deploy board criteria%{linkEnd}."
+msgstr ""
+
+msgid "Deploy static assets and resources to Google managed CDN"
+msgstr ""
+
+msgid "Deploy to..."
+msgstr ""
+
+msgid "DeployBoards|To see deployment progress for your environments, make sure you are deploying to %{codeStart}$KUBE_NAMESPACE%{codeEnd} and annotating with %{codeStart}app.gitlab.com/app=$CI_PROJECT_PATH_SLUG%{codeEnd} and %{codeStart}app.gitlab.com/env=$CI_ENVIRONMENT_SLUG%{codeEnd}."
+msgstr ""
+
+msgid "DeployBoard|Kubernetes Pods"
+msgstr ""
+
+msgid "DeployFreeze|Add a freeze period to prevent unintended releases during a period of time for a given environment. You must update the deployment jobs in %{filename} according to the deploy freezes added here. %{freeze_period_link_start}Learn more.%{freeze_period_link_end}"
+msgstr ""
+
+msgid "DeployFreeze|Add deploy freeze"
+msgstr ""
+
+msgid "DeployFreeze|Delete deploy freeze?"
+msgstr ""
+
+msgid "DeployFreeze|Delete freeze period"
+msgstr ""
+
+msgid "DeployFreeze|Deploy freeze from %{start} to %{end} in %{timezone} will be removed. Are you sure?"
+msgstr ""
+
+msgid "DeployFreeze|Deploy freezes"
+msgstr ""
+
+msgid "DeployFreeze|Freeze end"
+msgstr ""
+
+msgid "DeployFreeze|Freeze start"
+msgstr ""
+
+msgid "DeployFreeze|No deploy freezes exist for this project. To add one, select %{strongStart}Add deploy freeze%{strongEnd} above."
+msgstr ""
+
+msgid "DeployFreeze|Specify deploy freezes using %{cron_syntax_link_start}cron syntax%{cron_syntax_link_end}."
+msgstr ""
+
+msgid "DeployFreeze|Time zone"
+msgstr ""
+
+msgid "DeployKeys|+%{count} others"
+msgstr ""
+
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
+msgid "DeployKeys|Current project"
+msgstr ""
+
+msgid "DeployKeys|Deploy key"
+msgstr ""
+
+msgid "DeployKeys|Enabled deploy keys"
+msgstr ""
+
+msgid "DeployKeys|Error enabling deploy key"
+msgstr ""
+
+msgid "DeployKeys|Error getting deploy keys"
+msgstr ""
+
+msgid "DeployKeys|Error removing deploy key"
+msgstr ""
+
+msgid "DeployKeys|Expand %{count} other projects"
+msgstr ""
+
+msgid "DeployKeys|Grant write permissions to this key"
+msgstr ""
+
+msgid "DeployKeys|Loading deploy keys"
+msgstr ""
+
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr ""
+
+msgid "DeployKeys|Privately accessible deploy keys"
+msgstr ""
+
+msgid "DeployKeys|Project usage"
+msgstr ""
+
+msgid "DeployKeys|Publicly accessible deploy keys"
+msgstr ""
+
+msgid "DeployKeys|Read access only"
+msgstr ""
+
+msgid "DeployTokens|Active deploy tokens"
+msgstr ""
+
+msgid "DeployTokens|Allows read and write access to registry images."
+msgstr ""
+
+msgid "DeployTokens|Allows read and write access to the package registry."
+msgstr ""
+
+msgid "DeployTokens|Allows read, write and delete access to the package registry."
+msgstr ""
+
+msgid "DeployTokens|Allows read-only access to registry images."
+msgstr ""
+
+msgid "DeployTokens|Allows read-only access to the package registry."
+msgstr ""
+
+msgid "DeployTokens|Allows read-only access to the repository."
+msgstr ""
+
+msgid "DeployTokens|Allows write access to registry images."
+msgstr ""
+
+msgid "DeployTokens|Cancel"
+msgstr ""
+
+msgid "DeployTokens|Copy deploy token"
+msgstr ""
+
+msgid "DeployTokens|Copy username"
+msgstr ""
+
+msgid "DeployTokens|Create a new deploy token for all projects in this group. %{link_start}What are deploy tokens?%{link_end}"
+msgstr ""
+
+msgid "DeployTokens|Create deploy token"
+msgstr ""
+
+msgid "DeployTokens|Created"
+msgstr ""
+
+msgid "DeployTokens|Deploy tokens"
+msgstr ""
+
+msgid "DeployTokens|Deploy tokens allow access to packages, your repository, and registry images."
+msgstr ""
+
+msgid "DeployTokens|Enter a unique name for your deploy token."
+msgstr ""
+
+msgid "DeployTokens|Enter a username for your token. Defaults to %{code_start}gitlab+deploy-token-{n}%{code_end}."
+msgstr ""
+
+msgid "DeployTokens|Enter an expiration date for your token. Defaults to never expire."
+msgstr ""
+
+msgid "DeployTokens|Expiration date (optional)"
+msgstr ""
+
+msgid "DeployTokens|Expires"
+msgstr ""
+
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
+msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
+msgstr ""
+
+msgid "DeployTokens|Name"
+msgstr ""
+
+msgid "DeployTokens|New deploy token"
+msgstr ""
+
+msgid "DeployTokens|Revoke"
+msgstr ""
+
+msgid "DeployTokens|Revoke %{name}"
+msgstr ""
+
+msgid "DeployTokens|Scopes"
+msgstr ""
+
+msgid "DeployTokens|Scopes (select at least one)"
+msgstr ""
+
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
+msgstr ""
+
+msgid "DeployTokens|This action cannot be undone."
+msgstr ""
+
+msgid "DeployTokens|This username supports access. %{link_start}What kind of access?%{link_end}"
+msgstr ""
+
+msgid "DeployTokens|Use this token as a password. Save it. This password can %{i_start}not%{i_end} be recovered."
+msgstr ""
+
+msgid "DeployTokens|Username"
+msgstr ""
+
+msgid "DeployTokens|Username (optional)"
+msgstr ""
+
+msgid "DeployTokens|Your new Deploy Token username"
+msgstr ""
+
+msgid "DeployTokens|Your new deploy token"
+msgstr ""
+
+msgid "DeployTokens|Your new group deploy token has been created."
+msgstr ""
+
+msgid "DeployTokens|Your new project deploy token has been created."
+msgstr ""
+
+msgid "Deployed"
+msgstr ""
+
+msgid "Deployed to"
+msgstr ""
+
+msgid "Deployed-after"
+msgstr ""
+
+msgid "Deployed-before"
+msgstr ""
+
+msgid "Deploying to"
+msgstr ""
+
+msgid "Deployment"
+msgstr ""
+
+msgid "Deployment Frequency"
+msgstr ""
+
+msgid "Deployment Target|%{linkStart}How to provision or deploy to Kubernetes clusters from GitLab?%{linkEnd}"
+msgstr ""
+
+msgid "Deployment Target|Project deployment target (optional)"
+msgstr ""
+
+msgid "Deployment Target|Select the deployment target"
+msgstr ""
+
+msgid "Deployment approvals is not configured for this environment."
+msgstr ""
+
+msgid "Deployment frequency"
+msgstr ""
+
+msgid "DeploymentApprovals|Allow pipeline triggerer to approve deployment."
+msgstr ""
+
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Set how approval rules are applied to deployments in protected environments."
+msgstr ""
+
+msgid "DeploymentApproval| Current approvals: %{current}"
+msgstr ""
+
+msgid "DeploymentApproval|Approval options"
+msgstr ""
+
+msgid "DeploymentApproval|Approve or reject deployment #%{deploymentIid}"
+msgstr ""
+
+msgid "DeploymentApproval|Approved %{time}"
+msgstr ""
+
+msgid "DeploymentApproval|Approved by you %{time}"
+msgstr ""
+
+msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
+msgstr ""
+
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment tier: %{tier}"
+msgstr ""
+
+msgid "DeploymentApproval|Environment: %{environment}"
+msgstr ""
+
+msgid "DeploymentApproval|Manual job: %{jobName}"
+msgstr ""
+
+msgid "DeploymentApproval|Rejected %{time}"
+msgstr ""
+
+msgid "DeploymentApproval|Rejected by you %{time}"
+msgstr ""
+
+msgid "DeploymentTarget|Edge Computing (e.g. Cloudflare Workers)"
+msgstr ""
+
+msgid "DeploymentTarget|GitLab Pages"
+msgstr ""
+
+msgid "DeploymentTarget|Heroku"
+msgstr ""
+
+msgid "DeploymentTarget|Infrastructure provider (Terraform, Cloudformation, and so on)"
+msgstr ""
+
+msgid "DeploymentTarget|Kubernetes (GKE, EKS, OpenShift, and so on)"
+msgstr ""
+
+msgid "DeploymentTarget|Managed container runtime (Fargate, Cloud Run, DigitalOcean App)"
+msgstr ""
+
+msgid "DeploymentTarget|Mobile app store"
+msgstr ""
+
+msgid "DeploymentTarget|No deployment planned"
+msgstr ""
+
+msgid "DeploymentTarget|Other hosting service"
+msgstr ""
+
+msgid "DeploymentTarget|Registry (package or container)"
+msgstr ""
+
+msgid "DeploymentTarget|Self-managed container runtime (Podman, Docker Swarm, Docker Compose)"
+msgstr ""
+
+msgid "DeploymentTarget|Serverless backend (Lambda, Cloud functions)"
+msgstr ""
+
+msgid "DeploymentTarget|Virtual machine (for example, EC2)"
+msgstr ""
+
+msgid "DeploymentTarget|Web Deployment Platform (Netlify, Vercel, Gatsby)"
+msgstr ""
+
+msgid "Deployments"
+msgstr ""
+
+msgid "Deployments|%{deployments} environment impacted."
+msgid_plural "Deployments|%{deployments} environments impacted."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Deployments|Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
+msgstr ""
+
+msgid "Deployments|You don't have any deployments right now."
+msgstr ""
+
+msgid "Deployment|Cancelled"
+msgstr ""
+
+msgid "Deployment|Created"
+msgstr ""
+
+msgid "Deployment|Deployment ID"
+msgstr ""
+
+msgid "Deployment|Failed"
+msgstr ""
+
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
+msgid "Deployment|Latest Deployed"
+msgstr ""
+
+msgid "Deployment|Needs Approval"
+msgstr ""
+
+msgid "Deployment|Running"
+msgstr ""
+
+msgid "Deployment|Skipped"
+msgstr ""
+
+msgid "Deployment|Success"
+msgstr ""
+
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr ""
+
+msgid "Deployment|Triggerer"
+msgstr ""
+
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
+msgid "Deployment|Unavailable"
+msgstr ""
+
+msgid "Deployment|Unknown"
+msgstr ""
+
+msgid "Deployment|Waiting"
+msgstr ""
+
+msgid "Deployment|blocked"
+msgstr ""
+
+msgid "Deployment|canceled"
+msgstr ""
+
+msgid "Deployment|created"
+msgstr ""
+
+msgid "Deployment|failed"
+msgstr ""
+
+msgid "Deployment|running"
+msgstr ""
+
+msgid "Deployment|skipped"
+msgstr ""
+
+msgid "Deployment|success"
+msgstr ""
+
+msgid "Deprecated API rate limits"
+msgstr ""
+
+msgid "Deprioritize label"
+msgstr ""
+
+msgid "Describe the goal of the changes and what reviewers should be aware of."
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
+msgid "Description (optional)"
+msgstr ""
+
+msgid "Description parsed with %{link_start}GitLab Flavored Markdown%{link_end}"
+msgstr ""
+
+msgid "Description parsed with %{link_start}GitLab Flavored Markdown%{link_end}."
+msgstr ""
+
+msgid "Description:"
+msgstr ""
+
+msgid "Descriptions"
+msgstr ""
+
+msgid "Descriptive label"
+msgstr ""
+
+msgid "Deselect all"
+msgstr ""
+
+msgid "Design"
+msgstr ""
+
+msgid "Design Management files and data"
+msgstr ""
+
+msgid "DesignManagement|%{current_design} of %{designs_count}"
+msgstr ""
+
+msgid "DesignManagement|%{filename} did not change."
+msgid_plural "DesignManagement|The designs you tried uploading did not change."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "DesignManagement|Adding a design with the same filename replaces the file in a new version."
+msgstr ""
+
+msgid "DesignManagement|Archive design"
+msgstr ""
+
+msgid "DesignManagement|Archive designs"
+msgstr ""
+
+msgid "DesignManagement|Archive selected"
+msgstr ""
+
+msgid "DesignManagement|Archived designs will still be available in previous versions of the design collection."
+msgstr ""
+
+msgid "DesignManagement|Are you sure you want to archive the selected designs?"
+msgstr ""
+
+msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
+msgstr ""
+
+msgid "DesignManagement|Are you sure you want to cancel editing this comment?"
+msgstr ""
+
+msgid "DesignManagement|Cancel"
+msgstr ""
+
+msgid "DesignManagement|Click the image where you'd like to start a new discussion"
+msgstr ""
+
+msgid "DesignManagement|Comment"
+msgstr ""
+
+msgid "DesignManagement|Continue creating"
+msgstr ""
+
+msgid "DesignManagement|Continue editing"
+msgstr ""
+
+msgid "DesignManagement|Could not add a new comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not create new discussion. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not delete comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update comment. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update description. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Could not update discussion. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Deselect all"
+msgstr ""
+
+msgid "DesignManagement|Design description"
+msgstr ""
+
+msgid "DesignManagement|Designs"
+msgstr ""
+
+msgid "DesignManagement|Discard changes"
+msgstr ""
+
+msgid "DesignManagement|Discussion"
+msgstr ""
+
+msgid "DesignManagement|Download design"
+msgstr ""
+
+msgid "DesignManagement|Edit description"
+msgstr ""
+
+msgid "DesignManagement|Error uploading a new design. Please try again."
+msgstr ""
+
+msgid "DesignManagement|Go back to designs"
+msgstr ""
+
+msgid "DesignManagement|Go to next design"
+msgstr ""
+
+msgid "DesignManagement|Go to previous design"
+msgstr ""
+
+msgid "DesignManagement|None"
+msgstr ""
+
+msgid "DesignManagement|Requested design version does not exist. Showing latest version instead"
+msgstr ""
+
+msgid "DesignManagement|Resolve thread"
+msgstr ""
+
+msgid "DesignManagement|Resolved Comments"
+msgstr ""
+
+msgid "DesignManagement|Save"
+msgstr ""
+
+msgid "DesignManagement|Save comment"
+msgstr ""
+
+msgid "DesignManagement|Select all"
+msgstr ""
+
+msgid "DesignManagement|Some of the designs you tried uploading did not change: %{skippedFiles} and %{moreCount} more."
+msgstr ""
+
+msgid "DesignManagement|Some of the designs you tried uploading did not change: %{skippedFiles}."
+msgstr ""
+
+msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
+msgstr ""
+
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have an admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
+msgstr ""
+
+msgid "DesignManagement|Unresolve thread"
+msgstr ""
+
+msgid "DesignManagement|Upload designs"
+msgstr ""
+
+msgid "DesignManagement|Upload skipped. %{reason}"
+msgstr ""
+
+msgid "DesignManagement|Write a comment or drag your files here…"
+msgstr ""
+
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
+msgid "Designs"
+msgstr ""
+
+msgid "Destroy"
+msgstr ""
+
+msgid "Detail"
+msgstr ""
+
+msgid "Details"
+msgstr ""
+
+msgid "Details (default)"
+msgstr ""
+
+msgid "Details block"
+msgstr ""
+
+msgid "Detect host keys"
+msgstr ""
+
+msgid "DevOps Adoption"
+msgstr ""
+
+msgid "DevOps Reports"
+msgstr ""
+
+msgid "DevOps adoption"
+msgstr ""
+
+msgid "Developer"
+msgstr ""
+
+msgid "Device name"
+msgstr ""
+
+msgid "Devices (optional)"
+msgstr ""
+
+msgid "DevopsAdoption|%{adoptedCount}/%{featuresCount} %{title} features adopted"
+msgstr ""
+
+msgid "DevopsAdoption|Add a group to get started"
+msgstr ""
+
+msgid "DevopsAdoption|Add or remove groups"
+msgstr ""
+
+msgid "DevopsAdoption|Add or remove subgroups"
+msgstr ""
+
+msgid "DevopsAdoption|Adopted"
+msgstr ""
+
+msgid "DevopsAdoption|Adoption by group"
+msgstr ""
+
+msgid "DevopsAdoption|Adoption by subgroup"
+msgstr ""
+
+msgid "DevopsAdoption|Adoption over time"
+msgstr ""
+
+msgid "DevopsAdoption|An error occurred while removing the group. Please try again."
+msgstr ""
+
+msgid "DevopsAdoption|Approvals"
+msgstr ""
+
+msgid "DevopsAdoption|Are you sure that you would like to remove %{name} from the table?"
+msgstr ""
+
+msgid "DevopsAdoption|At least one approval on a merge request"
+msgstr ""
+
+msgid "DevopsAdoption|At least one deploy"
+msgstr ""
+
+msgid "DevopsAdoption|At least one issue created"
+msgstr ""
+
+msgid "DevopsAdoption|At least one merge request created"
+msgstr ""
+
+msgid "DevopsAdoption|At least one pipeline successfully run"
+msgstr ""
+
+msgid "DevopsAdoption|Code owners"
+msgstr ""
+
+msgid "DevopsAdoption|Code owners enabled for at least one project"
+msgstr ""
+
+msgid "DevopsAdoption|Confirm remove Group"
+msgstr ""
+
+msgid "DevopsAdoption|DAST"
+msgstr ""
+
+msgid "DevopsAdoption|DAST enabled for at least one project"
+msgstr ""
+
+msgid "DevopsAdoption|Dependency Scanning"
+msgstr ""
+
+msgid "DevopsAdoption|Dependency Scanning enabled for at least one project"
+msgstr ""
+
+msgid "DevopsAdoption|Deploys"
+msgstr ""
+
+msgid "DevopsAdoption|Dev"
+msgstr ""
+
+msgid "DevopsAdoption|DevOps adoption tracks the use of key features across your favorite groups. Add a group to the table to begin."
+msgstr ""
+
+msgid "DevopsAdoption|Edit groups"
+msgstr ""
+
+msgid "DevopsAdoption|Edit subgroups"
+msgstr ""
+
+msgid "DevopsAdoption|Feature adoption is based on usage in the previous calendar month. Data is updated at the beginning of each month. Last updated: %{timestamp}."
+msgstr ""
+
+msgid "DevopsAdoption|Fuzz Testing"
+msgstr ""
+
+msgid "DevopsAdoption|Fuzz Testing enabled for at least one project"
+msgstr ""
+
+msgid "DevopsAdoption|Issues"
+msgstr ""
+
+msgid "DevopsAdoption|MRs"
+msgstr ""
+
+msgid "DevopsAdoption|No results…"
+msgstr ""
+
+msgid "DevopsAdoption|No tracked features"
+msgstr ""
+
+msgid "DevopsAdoption|Not adopted"
+msgstr ""
+
+msgid "DevopsAdoption|Ops"
+msgstr ""
+
+msgid "DevopsAdoption|Overall adoption"
+msgstr ""
+
+msgid "DevopsAdoption|Pipelines"
+msgstr ""
+
+msgid "DevopsAdoption|Remove Group"
+msgstr ""
+
+msgid "DevopsAdoption|Remove Group from the table."
+msgstr ""
+
+msgid "DevopsAdoption|Runner configured for project/group"
+msgstr ""
+
+msgid "DevopsAdoption|Runners"
+msgstr ""
+
+msgid "DevopsAdoption|SAST"
+msgstr ""
+
+msgid "DevopsAdoption|SAST enabled for at least one project"
+msgstr ""
+
+msgid "DevopsAdoption|Sec"
+msgstr ""
+
+msgid "DevopsAdoption|There was an error enabling the current group. Please refresh the page."
+msgstr ""
+
+msgid "DevopsAdoption|There was an error fetching Group adoption data. Please refresh the page."
+msgstr ""
+
+msgid "DevopsAdoption|There was an error fetching Groups. Please refresh the page."
+msgstr ""
+
+msgid "DevopsAdoption|This group has no subgroups"
+msgstr ""
+
+msgid "DevopsAdoption|Total number of features adopted"
+msgstr ""
+
+msgid "DevopsAdoption|You cannot remove the group you are currently in."
+msgstr ""
+
+msgid "DevopsReport|DevOps Score"
+msgstr ""
+
+msgid "DevopsReport|DevOps score metrics are based on usage over the last 30 days. Last updated: %{timestamp}."
+msgstr ""
+
+msgid "DevopsReport|High"
+msgstr ""
+
+msgid "DevopsReport|Leader usage"
+msgstr ""
+
+msgid "DevopsReport|Low"
+msgstr ""
+
+msgid "DevopsReport|Moderate"
+msgstr ""
+
+msgid "DevopsReport|Overview"
+msgstr ""
+
+msgid "DevopsReport|Score"
+msgstr ""
+
+msgid "DevopsReport|Your score"
+msgstr ""
+
+msgid "DevopsReport|Your usage"
+msgstr ""
+
+msgid "Diagram (%{language})"
+msgstr ""
+
+msgid "Diagram saved successfully."
+msgstr ""
+
+msgid "Diagrams.net"
+msgstr ""
+
+msgid "Diagrams.net URL"
+msgstr ""
+
+msgid "Did not delete the source branch."
+msgstr ""
+
+msgid "Didn't receive a confirmation email?"
+msgstr ""
+
+msgid "Didn't receive confirmation instructions?"
+msgstr ""
+
+msgid "Didn't receive unlock instructions?"
+msgstr ""
+
+msgid "Diff files surpassing this limit will be presented as 'too large' and won't be expandable."
+msgstr ""
+
+msgid "Diff limits"
+msgstr ""
+
+msgid "Diff notes"
+msgstr ""
+
+msgid "Difference between start date and now"
+msgstr ""
+
+msgid "Different user's signature"
+msgstr ""
+
+msgid "DiffsCompareBaseBranch|(HEAD)"
+msgstr ""
+
+msgid "DiffsCompareBaseBranch|(base)"
+msgstr ""
+
+msgid "Diffs|%d addition"
+msgid_plural "Diffs|%d additions"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Diffs|%d deletion"
+msgid_plural "Diffs|%d deletions"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Diffs|Expand all lines"
+msgstr ""
+
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
+msgid "Diffs|Next 20 lines"
+msgstr ""
+
+msgid "Diffs|No file name available"
+msgstr ""
+
+msgid "Diffs|Previous 20 lines"
+msgstr ""
+
+msgid "Diffs|Show %{unfoldCount} lines"
+msgstr ""
+
+msgid "Diffs|Show all unchanged lines"
+msgstr ""
+
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
+msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
+msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Diffs|Side-by-side"
+msgstr ""
+
+msgid "Diffs|Something went wrong while fetching diff lines."
+msgstr ""
+
+msgid "Diffs|with %{additions} and %{deletions}"
+msgstr ""
+
+msgid "Dimension"
+msgstr ""
+
+msgid "Direct member"
+msgstr ""
+
+msgid "Direct members"
+msgstr ""
+
+msgid "Direct non-authenticated users to this page."
+msgstr ""
+
+msgid "Direct users to this page after they sign out."
+msgstr ""
+
+msgid "Direction"
+msgstr ""
+
+msgid "Directory name"
+msgstr ""
+
+msgid "Disable"
+msgstr ""
+
+msgid "Disable Two-factor Authentication"
+msgstr ""
+
+msgid "Disable What's new"
+msgstr ""
+
+msgid "Disable for this project"
+msgstr ""
+
+msgid "Disable group runners"
+msgstr ""
+
+msgid "Disable two-factor authentication"
+msgstr ""
+
+msgid "Disabled"
+msgstr ""
+
+msgid "Disabled by %{parent} owner"
+msgstr ""
+
+msgid "Disabled mirrors can only be enabled by instance owners. It is recommended that you delete them."
+msgstr ""
+
+msgid "Discard"
+msgstr ""
+
+msgid "Discard all changes"
+msgstr ""
+
+msgid "Discard all changes?"
+msgstr ""
+
+msgid "Discard changes"
+msgstr ""
+
+msgid "Discard changes to %{path}?"
+msgstr ""
+
+msgid "Discard draft"
+msgstr ""
+
+msgid "DiscordService|Discord Notifications"
+msgstr ""
+
+msgid "DiscordService|Override the default webhook (e.g. https://discord.com/api/webhooks/…)"
+msgstr ""
+
+msgid "DiscordService|Send notifications about project events to a Discord channel."
+msgstr ""
+
+msgid "Discover GitLab Geo"
+msgstr ""
+
+msgid "Discover|Check your application for security vulnerabilities that may lead to unauthorized access, data leaks, and denial of services."
+msgstr ""
+
+msgid "Discover|For code that's already live in production, our dashboards give you an easy way to prioritize any issues that are found, empowering your team to ship quickly and securely."
+msgstr ""
+
+msgid "Discover|GitLab will perform static and dynamic tests on the code of your application, looking for known flaws and report them in the merge request so you can fix them before merging."
+msgstr ""
+
+msgid "Discover|Security capabilities, integrated into your development lifecycle"
+msgstr ""
+
+msgid "Discover|See the other features of the %{linkStart}ultimate plan%{linkEnd}"
+msgstr ""
+
+msgid "Discover|Start a free trial"
+msgstr ""
+
+msgid "Discover|Upgrade now"
+msgstr ""
+
+msgid "Discuss a specific suggestion or question internally that needs to be resolved."
+msgstr ""
+
+msgid "Discuss a specific suggestion or question internally."
+msgstr ""
+
+msgid "Discuss a specific suggestion or question that needs to be resolved."
+msgstr ""
+
+msgid "Discuss a specific suggestion or question."
+msgstr ""
+
+msgid "Discussion to reply to cannot be found"
+msgstr ""
+
+msgid "Disk Usage"
+msgstr ""
+
+msgid "Dismiss"
+msgstr ""
+
+msgid "Dismiss %d selected vulnerability as"
+msgid_plural "Dismiss %d selected vulnerabilities as"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Dismiss Alert"
+msgstr ""
+
+msgid "Dismiss merge request promotion"
+msgstr ""
+
+msgid "Dismiss selected"
+msgstr ""
+
+msgid "Dismiss trial promotion"
+msgstr ""
+
+msgid "Dismissed"
+msgstr ""
+
+msgid "Dismissed (%d reason)"
+msgid_plural "Dismissed (%d reasons)"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Display"
+msgstr ""
+
+msgid "Display alerts from all configured monitoring tools."
+msgstr ""
+
+msgid "Display as:"
+msgstr ""
+
+msgid "Display milestones"
+msgstr ""
+
+msgid "Display name"
+msgstr ""
+
+msgid "Display progress of child issues"
+msgstr ""
+
+msgid "Display rendered file"
+msgstr ""
+
+msgid "Display source"
+msgstr ""
+
+msgid "Display time tracking in issues in total hours only. %{link_start}What is time tracking?%{link_end}"
+msgstr ""
+
+msgid "Do not display content for customer experience improvement and offers from third parties"
+msgstr ""
+
+msgid "Do not force push over diverged refs. After the mirror is created, this setting can only be modified using the API. %{mirroring_docs_link_start}Learn more about this option%{link_closing_tag} and %{mirroring_api_docs_link_start}the API.%{link_closing_tag}"
+msgstr ""
+
+msgid "Do you want to remove this deploy key?"
+msgstr ""
+
+msgid "Dockerfile"
+msgstr ""
+
+msgid "Documentation"
+msgstr ""
+
+msgid "Documentation for popular identity providers"
+msgstr ""
+
+msgid "Documentation pages URL"
+msgstr ""
+
+msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
+msgstr ""
+
+msgid "Domain"
+msgstr ""
+
+msgid "Domain Name"
+msgstr ""
+
+msgid "Domain Verification"
+msgstr ""
+
+msgid "DomainVerification|Add Domain"
+msgstr ""
+
+msgid "DomainVerification|Are you sure you want to delete this domain?"
+msgstr ""
+
+msgid "DomainVerification|Delete domain"
+msgstr ""
+
+msgid "DomainVerification|Domain was added"
+msgstr ""
+
+msgid "DomainVerification|Domain was removed"
+msgstr ""
+
+msgid "DomainVerification|Domain was updated"
+msgstr ""
+
+msgid "DomainVerification|Edit Domain"
+msgstr ""
+
+msgid "DomainVerification|Enter your domain"
+msgstr ""
+
+msgid "DomainVerification|Failed to verify domain ownership"
+msgstr ""
+
+msgid "DomainVerification|How do I configure a domain?"
+msgstr ""
+
+msgid "DomainVerification|How to set up DNS records?"
+msgstr ""
+
+msgid "DomainVerification|Manually enter certificate information"
+msgstr ""
+
+msgid "DomainVerification|New Domain"
+msgstr ""
+
+msgid "DomainVerification|No domains configured. Create a domain in a project in this group hierarchy."
+msgstr ""
+
+msgid "DomainVerification|Remove certificate"
+msgstr ""
+
+msgid "DomainVerification|Successfully verified domain ownership"
+msgstr ""
+
+msgid "DomainVerification|The following domains are configured for projects in this group. Users with email addresses that match a verified domain do not need to confirm their account."
+msgstr ""
+
+msgid "DomainVerification|To verify ownership of your domain, add the above key to a TXT record within your DNS configuration within seven days. %{link_to_help}"
+msgstr ""
+
+msgid "Domains"
+msgstr ""
+
+msgid "Don't have a group?"
+msgstr ""
+
+msgid "Don't have an account yet?"
+msgstr ""
+
+msgid "Don't include description in commit message"
+msgstr ""
+
+msgid "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'."
+msgstr ""
+
+msgid "Don't send service data"
+msgstr ""
+
+msgid "Don't show again"
+msgstr ""
+
+msgid "Don't show this again"
+msgstr ""
+
+msgid "Done"
+msgstr ""
+
+msgid "Dormant users"
+msgstr ""
+
+msgid "Download"
+msgstr ""
+
+msgid "Download %{format}"
+msgstr ""
+
+msgid "Download %{format}:"
+msgstr ""
+
+msgid "Download (%{fileSizeReadable})"
+msgstr ""
+
+msgid "Download (%{size})"
+msgstr ""
+
+msgid "Download PDF"
+msgstr ""
+
+msgid "Download artifacts"
+msgstr ""
+
+msgid "Download artifacts archive"
+msgstr ""
+
+msgid "Download codes"
+msgstr ""
+
+msgid "Download export"
+msgstr ""
+
+msgid "Download image"
+msgstr ""
+
+msgid "Download payload"
+msgstr ""
+
+msgid "Download raw data (.csv)"
+msgstr ""
+
+msgid "Download source code"
+msgstr ""
+
+msgid "Download this directory"
+msgstr ""
+
+msgid "DownloadCommit|Plain Diff"
+msgstr ""
+
+msgid "DownloadSource|Download"
+msgstr ""
+
+msgid "Downloads"
+msgstr ""
+
+msgid "Downstream"
+msgstr ""
+
+msgid "Downvotes"
+msgstr ""
+
+msgid "Draft"
+msgstr ""
+
+msgid "Draft: %{filename}"
+msgstr ""
+
+msgid "Drag to reorder prioritized labels and change their relative priority."
+msgstr ""
+
+msgid "Drag your designs here or %{linkStart}click to upload%{linkEnd}."
+msgstr ""
+
+msgid "Drop or %{linkStart}upload%{linkEnd} file to attach"
+msgstr ""
+
+msgid "Drop or %{linkStart}upload%{linkEnd} files to attach"
+msgstr ""
+
+msgid "Drop your designs to start your upload."
+msgstr ""
+
+msgid "Drop your files to start your upload."
+msgstr ""
+
+msgid "DropdownWidget|An error occurred while fetching the assigned %{issuableAttribute} of the selected %{issuableType}."
+msgstr ""
+
+msgid "DropdownWidget|Assign %{issuableAttribute}"
+msgstr ""
+
+msgid "DropdownWidget|Cancel"
+msgstr ""
+
+msgid "DropdownWidget|Edit %{issuableAttribute}"
+msgstr ""
+
+msgid "DropdownWidget|Failed to fetch the %{issuableAttribute} for this %{issuableType}. Please try again."
+msgstr ""
+
+msgid "DropdownWidget|Failed to set %{issuableAttribute} on this %{issuableType}. Please try again."
+msgstr ""
+
+msgid "DropdownWidget|No %{issuableAttribute}"
+msgstr ""
+
+msgid "DropdownWidget|No %{issuableAttribute} found"
+msgstr ""
+
+msgid "DropdownWidget|No open %{issuableAttribute} found"
+msgstr ""
+
+msgid "DropdownWidget|You do not have permission to view the currently assigned %{issuableAttribute} and will not be able to choose it again if you reassign it."
+msgstr ""
+
+msgid "DropdownWidget|You don't have permission to view this %{issuableAttribute}."
+msgstr ""
+
+msgid "Due Date"
+msgstr ""
+
+msgid "Due date"
+msgstr ""
+
+msgid "Due to inactivity, the %{project_link} project is scheduled to be deleted on %{b_open}%{deletion_date}%{b_close}. To unschedule the deletion of %{project_link}, perform some activity on it. For example:"
+msgstr ""
+
+msgid "Due to inactivity, the %{project_name} (%{project_link}) project is scheduled to be deleted on %{deletion_date}. To unschedule the deletion of %{project_name}, perform some activity on it. For example:"
+msgstr ""
+
+msgid "Due to inactivity, this project is scheduled to be deleted on %{deletion_date}. %{link_start}Why is this scheduled?%{link_end}"
+msgstr ""
+
+msgid "Duplicate page: A page with that title already exists"
+msgstr ""
+
+msgid "Duration"
+msgstr ""
+
+msgid "Duration (min)"
+msgstr ""
+
+msgid "Duration|%s days"
+msgstr ""
+
+msgid "Duration|%s hours"
+msgstr ""
+
+msgid "Duration|%s minutes"
+msgstr ""
+
+msgid "Duration|%s months"
+msgstr ""
+
+msgid "Duration|%s seconds"
+msgstr ""
+
+msgid "Duration|%s weeks"
+msgstr ""
+
+msgid "Duration|%s years"
+msgstr ""
+
+msgid "Duration|1 day"
+msgstr ""
+
+msgid "Duration|1 hour"
+msgstr ""
+
+msgid "Duration|1 minute"
+msgstr ""
+
+msgid "Duration|1 month"
+msgstr ""
+
+msgid "Duration|1 week"
+msgstr ""
+
+msgid "Duration|1 year"
+msgstr ""
+
+msgid "During this process, you’ll be asked for URLs from GitLab’s side. Use the URLs shown below."
+msgstr ""
+
+msgid "Dynamic Application Security Testing (DAST)"
+msgstr ""
+
+msgid "E-mail:"
+msgstr ""
+
+msgid "Each project can also have an issue tracker and a wiki."
+msgstr ""
+
+msgid "Edit"
+msgstr ""
+
+msgid "Edit %{name}"
+msgstr ""
+
+msgid "Edit %{profileType} profile"
+msgstr ""
+
+msgid "Edit Comment"
+msgstr ""
+
+msgid "Edit Deploy Key"
+msgstr ""
+
+msgid "Edit Geo Site"
+msgstr ""
+
+msgid "Edit Group Hook"
+msgstr ""
+
+msgid "Edit Identity"
+msgstr ""
+
+msgid "Edit Label"
+msgstr ""
+
+msgid "Edit Milestone"
+msgstr ""
+
+msgid "Edit Password"
+msgstr ""
+
+msgid "Edit Pipeline Schedule"
+msgstr ""
+
+msgid "Edit Release"
+msgstr ""
+
+msgid "Edit Slack integration"
+msgstr ""
+
+msgid "Edit Snippet"
+msgstr ""
+
+msgid "Edit System Hook"
+msgstr ""
+
+msgid "Edit application"
+msgstr ""
+
+msgid "Edit audio description"
+msgstr ""
+
+msgid "Edit comment"
+msgstr ""
+
+msgid "Edit comment template"
+msgstr ""
+
+msgid "Edit commit message"
+msgstr ""
+
+msgid "Edit deploy freeze"
+msgstr ""
+
+msgid "Edit deploy key"
+msgstr ""
+
+msgid "Edit description"
+msgstr ""
+
+msgid "Edit diagram description"
+msgstr ""
+
+msgid "Edit environment"
+msgstr ""
+
+msgid "Edit files in the editor and commit changes here"
+msgstr ""
+
+msgid "Edit fork in Web IDE"
+msgstr ""
+
+msgid "Edit group application"
+msgstr ""
+
+msgid "Edit group: %{group_name}"
+msgstr ""
+
+msgid "Edit identity for %{user_name}"
+msgstr ""
+
+msgid "Edit image description"
+msgstr ""
+
+msgid "Edit in pipeline editor"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
+msgid "Edit inline"
+msgstr ""
+
+msgid "Edit link"
+msgstr ""
+
+msgid "Edit project: %{project_name}"
+msgstr ""
+
+msgid "Edit public deploy key"
+msgstr ""
+
+msgid "Edit sidebar"
+msgstr ""
+
+msgid "Edit single file"
+msgstr ""
+
+msgid "Edit table"
+msgstr ""
+
+msgid "Edit this file only."
+msgstr ""
+
+msgid "Edit this release"
+msgstr ""
+
+msgid "Edit title and description"
+msgstr ""
+
+msgid "Edit topic: %{topic_name}"
+msgstr ""
+
+msgid "Edit user: %{user_name}"
+msgstr ""
+
+msgid "Edit video description"
+msgstr ""
+
+msgid "Edit wiki page"
+msgstr ""
+
+msgid "Edit your most recent comment in a thread (from an empty textarea)"
+msgstr ""
+
+msgid "Edit your search and try again"
+msgstr ""
+
+msgid "Edit your search filter and try again."
+msgstr ""
+
+msgid "Edit, lint, and visualize your pipeline."
+msgstr ""
+
+msgid "Edited"
+msgstr ""
+
+msgid "Edited %{timeago}"
+msgstr ""
+
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Editing"
+msgstr ""
+
+msgid "Edits"
+msgstr ""
+
+msgid "Elapsed time"
+msgstr ""
+
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
+msgid "Elasticsearch indexing restrictions"
+msgstr ""
+
+msgid "Elasticsearch indexing started"
+msgstr ""
+
+msgid "Elasticsearch migration halted"
+msgstr ""
+
+msgid "Elasticsearch reindexing is already in progress"
+msgstr ""
+
+msgid "Elasticsearch reindexing triggered"
+msgstr ""
+
+msgid "Elasticsearch reindexing was not started: %{errors}"
+msgstr ""
+
+msgid "Elasticsearch zero-downtime reindexing"
+msgstr ""
+
+msgid "Email"
+msgstr ""
+
+msgid "Email %{number}"
+msgstr ""
+
+msgid "Email Notification"
+msgstr ""
+
+msgid "Email a new %{name} to this project"
+msgstr ""
+
+msgid "Email address copied"
+msgstr ""
+
+msgid "Email address suffix"
+msgstr ""
+
+msgid "Email address to use for Service Desk"
+msgstr ""
+
+msgid "Email could not be sent"
+msgstr ""
+
+msgid "Email display name"
+msgstr ""
+
+msgid "Email must be provided."
+msgstr ""
+
+msgid "Email not verified. Please verify your email in Salesforce."
+msgstr ""
+
+msgid "Email notification for unknown sign-ins"
+msgstr ""
+
+msgid "Email patch"
+msgstr ""
+
+msgid "Email sent"
+msgstr ""
+
+msgid "Email the pipeline status to a list of recipients."
+msgstr ""
+
+msgid "Email:"
+msgstr ""
+
+msgid "Email: %{email}"
+msgstr ""
+
+msgid "EmailError|It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies."
+msgstr ""
+
+msgid "EmailError|The thread you are replying to no longer exists, perhaps it was deleted? If you believe this is in error, contact a staff member."
+msgstr ""
+
+msgid "EmailError|We couldn't figure out what the email is for. Please create your issue or comment through the web interface."
+msgstr ""
+
+msgid "EmailError|We couldn't figure out what the email is in reply to. Please create your comment through the web interface."
+msgstr ""
+
+msgid "EmailError|We couldn't figure out what user corresponds to the email. Please create your comment through the web interface."
+msgstr ""
+
+msgid "EmailError|We couldn't find the project. Please check if there's any typo."
+msgstr ""
+
+msgid "EmailError|We couldn't process your email because it is too large. Please create your issue or comment through the web interface."
+msgstr ""
+
+msgid "EmailError|You are not allowed to perform this action. If you believe this is in error, contact a staff member."
+msgstr ""
+
+msgid "EmailError|Your account has been blocked. If you believe this is in error, contact a staff member."
+msgstr ""
+
+msgid "EmailParticipantsWarning|%{emails} will be notified of your comment."
+msgstr ""
+
+msgid "EmailParticipantsWarning|%{emails}, %{andMore} will be notified of your comment."
+msgstr ""
+
+msgid "EmailParticipantsWarning|and %{moreCount} more"
+msgstr ""
+
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
+msgid "Emails"
+msgstr ""
+
+msgid "Emails sent to %{email} are also supported."
+msgstr ""
+
+msgid "EmailsOnPushService|Disable code diffs"
+msgstr ""
+
+msgid "EmailsOnPushService|Don't include possibly sensitive code diffs in notification body."
+msgstr ""
+
+msgid "EmailsOnPushService|Email the commits and diff of each push to a list of recipients."
+msgstr ""
+
+msgid "EmailsOnPushService|Emails on push"
+msgstr ""
+
+msgid "EmailsOnPushService|Emails separated by whitespace."
+msgstr ""
+
+msgid "EmailsOnPushService|Send from committer"
+msgstr ""
+
+msgid "EmailsOnPushService|Send notifications from the committer's email address if the domain matches the domain used by your GitLab instance (such as %{domains})."
+msgstr ""
+
+msgid "EmailsOnPushService|tanuki@example.com gitlab@example.com"
+msgstr ""
+
+msgid "Embed"
+msgstr ""
+
+msgid "Emoji"
+msgstr ""
+
+msgid "Empty file"
+msgstr ""
+
+msgid "Enable"
+msgstr ""
+
+msgid "Enable Akismet"
+msgstr ""
+
+msgid "Enable Amazon EKS integration"
+msgstr ""
+
+msgid "Enable Auto DevOps"
+msgstr ""
+
+msgid "Enable GitLab Error Tracking"
+msgstr ""
+
+msgid "Enable GitLab Prometheus metrics endpoint"
+msgstr ""
+
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
+msgid "Enable Invisible Captcha during sign up"
+msgstr ""
+
+msgid "Enable Kroki"
+msgstr ""
+
+msgid "Enable Mailgun event receiver"
+msgstr ""
+
+msgid "Enable PlantUML"
+msgstr ""
+
+msgid "Enable SSL verification"
+msgstr ""
+
+msgid "Enable Sentry error tracking"
+msgstr ""
+
+msgid "Enable Snowplow tracking"
+msgstr ""
+
+msgid "Enable Spam Check via external API endpoint"
+msgstr ""
+
+msgid "Enable What's new: All tiers"
+msgstr ""
+
+msgid "Enable What's new: Current tier only"
+msgstr ""
+
+msgid "Enable access to the performance bar for non-administrators in a given group."
+msgstr ""
+
+msgid "Enable admin mode"
+msgstr ""
+
+msgid "Enable and disable Service Desk. Some additional configuration might be required. %{link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "Enable authenticated API request rate limit"
+msgstr ""
+
+msgid "Enable authenticated Git LFS request rate limit"
+msgstr ""
+
+msgid "Enable authenticated web request rate limit"
+msgstr ""
+
+msgid "Enable automatic repository housekeeping"
+msgstr ""
+
+msgid "Enable cleanup policies for projects created earlier than GitLab 12.7."
+msgstr ""
+
+msgid "Enable cleanup policy caching."
+msgstr ""
+
+msgid "Enable diagrams.net"
+msgstr ""
+
+msgid "Enable email notification"
+msgstr ""
+
+msgid "Enable feature to choose access level"
+msgstr ""
+
+msgid "Enable for this project"
+msgstr ""
+
+msgid "Enable group runners"
+msgstr ""
+
+msgid "Enable header and footer in emails"
+msgstr ""
+
+msgid "Enable incident management inbound alert limit"
+msgstr ""
+
+msgid "Enable integration"
+msgstr ""
+
+msgid "Enable logs collection"
+msgstr ""
+
+msgid "Enable maintenance mode"
+msgstr ""
+
+msgid "Enable multipart emails"
+msgstr ""
+
+msgid "Enable only for confidential applications exclusively used by a trusted backend server that can securely store the client secret. Do not enable for native-mobile, single-page, or other JavaScript applications because they cannot keep the client secret confidential."
+msgstr ""
+
+msgid "Enable or disable version check and Service Ping."
+msgstr ""
+
+msgid "Enable rate limiting for requests to the specified paths"
+msgstr ""
+
+msgid "Enable reCAPTCHA"
+msgstr ""
+
+msgid "Enable reCAPTCHA for login."
+msgstr ""
+
+msgid "Enable repository checks"
+msgstr ""
+
+msgid "Enable security training"
+msgstr ""
+
+msgid "Enable security training to help your developers learn how to fix vulnerabilities. Developers can view security training from selected educational providers, relevant to the detected vulnerability."
+msgstr ""
+
+msgid "Enable shared runners for all projects and subgroups in this group."
+msgstr ""
+
+msgid "Enable shared runners for this group"
+msgstr ""
+
+msgid "Enable shared runners for this project"
+msgstr ""
+
+msgid "Enable two-factor authentication"
+msgstr ""
+
+msgid "Enable unauthenticated API request rate limit"
+msgstr ""
+
+msgid "Enable unauthenticated web request rate limit"
+msgstr ""
+
+msgid "Enable user deactivation emails"
+msgstr ""
+
+msgid "Enable version check"
+msgstr ""
+
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
+msgstr ""
+
+msgid "Enabled"
+msgstr ""
+
+msgid "Enabled Git access protocols"
+msgstr ""
+
+msgid "Enabled OAuth authentication sources"
+msgstr ""
+
+msgid "End Time"
+msgstr ""
+
+msgid "End time"
+msgstr ""
+
+msgid "Endpoint name '%{endpoint}' of component '%{component}' must not start with '%{prefix}'"
+msgstr ""
+
+msgid "Ends"
+msgstr ""
+
+msgid "Ends on"
+msgstr ""
+
+msgid "Ends: %{endsAt}"
+msgstr ""
+
+msgid "Enforce two-factor authentication"
+msgstr ""
+
+msgid "Enforce two-factor authentication for all user sign-ins."
+msgstr ""
+
+msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
+msgstr ""
+
+msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
+msgstr ""
+
+msgid "Enter %{weights_link_start}weights%{weights_link_end} for storages for new repositories. Configured storages appear below."
+msgstr ""
+
+msgid "Enter a URL for your custom emoji"
+msgstr ""
+
+msgid "Enter a name for your comment template"
+msgstr ""
+
+msgid "Enter a number"
+msgstr ""
+
+msgid "Enter admin mode"
+msgstr ""
+
+msgid "Enter an integer number between 0 and 100"
+msgstr ""
+
+msgid "Enter any color or choose one of the suggested colors below."
+msgstr ""
+
+msgid "Enter any color."
+msgstr ""
+
+msgid "Enter at least three characters to search"
+msgstr ""
+
+msgid "Enter at least three characters to search."
+msgstr ""
+
+msgid "Enter in your Bitbucket Server URL and personal access token below"
+msgstr ""
+
+msgid "Enter license key"
+msgstr ""
+
+msgid "Enter merge request URLs"
+msgstr ""
+
+msgid "Enter new AWS Secret Access Key"
+msgstr ""
+
+msgid "Enter number of issues"
+msgstr ""
+
+msgid "Enter one or more user ID separated by commas"
+msgstr ""
+
+msgid "Enter the %{name} description"
+msgstr ""
+
+msgid "Enter the %{name} title"
+msgstr ""
+
+msgid "Enter the code from your two-factor authenticator app. If you've lost your device, you can enter one of your recovery codes."
+msgstr ""
+
+msgid "Enter the following to confirm:"
+msgstr ""
+
+msgid "Enter the number of seconds, or other human-readable input, like \"1 hour\". This timeout takes precedence over lower timeouts set for the project."
+msgstr ""
+
+msgid "Enter the password for password-protected Elasticsearch servers."
+msgstr ""
+
+msgid "Enter the username for password-protected Elasticsearch servers."
+msgstr ""
+
+msgid "Enter verification code"
+msgstr ""
+
+msgid "Enter your Packagist server. Defaults to https://packagist.org."
+msgstr ""
+
+msgid "Enter your Packagist token."
+msgstr ""
+
+msgid "Enter your Packagist username."
+msgstr ""
+
+msgid "Enter your password to approve"
+msgstr ""
+
+msgid "Enterprise"
+msgstr ""
+
+msgid "Enterprise User"
+msgstr ""
+
+msgid "Enterprise User Account on GitLab"
+msgstr ""
+
+msgid "EnterpriseUsers|The user detail cannot be updated"
+msgstr ""
+
+msgid "EnterpriseUsers|The user does not match the \"Enterprise User\" definition for the group"
+msgstr ""
+
+msgid "EnterpriseUsers|The user is already an enterprise user of the group"
+msgstr ""
+
+msgid "Environment"
+msgstr ""
+
+msgid "Environment scope"
+msgstr ""
+
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr ""
+
+msgid "Environment:"
+msgstr ""
+
+msgid "EnvironmentDashboard|API"
+msgstr ""
+
+msgid "EnvironmentDashboard|Created through the Deployment API"
+msgstr ""
+
+msgid "EnvironmentDashboard|You are looking at the last updated environment"
+msgstr ""
+
+msgid "Environments"
+msgstr ""
+
+msgid "Environments Dashboard"
+msgstr ""
+
+msgid "Environments allow you to track deployments of your application. To protect this environment, go to the CI/CD settings %{linkStart}Protected environments%{linkEnd} section."
+msgstr ""
+
+msgid "Environments allow you to track deployments of your application.%{linkStart} More information.%{linkEnd}"
+msgstr ""
+
+msgid "Environments in %{name}"
+msgstr ""
+
+msgid "EnvironmentsAlert|%{severity} • %{title} %{text}. %{linkStart}View Details%{linkEnd} · %{startedAt} "
+msgstr ""
+
+msgid "EnvironmentsDashboard|Add a project to the dashboard"
+msgstr ""
+
+msgid "EnvironmentsDashboard|Add projects"
+msgstr ""
+
+msgid "EnvironmentsDashboard|Environments Dashboard"
+msgstr ""
+
+msgid "EnvironmentsDashboard|Job: %{job}"
+msgstr ""
+
+msgid "EnvironmentsDashboard|More actions"
+msgstr ""
+
+msgid "EnvironmentsDashboard|Remove"
+msgstr ""
+
+msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
+msgstr ""
+
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
+msgid "Environments|A freeze period is in effect from %{startTime} to %{endTime}. Deployments might fail during this time. For more information, see the %{docsLinkStart}deploy freeze documentation%{docsLinkEnd}."
+msgstr ""
+
+msgid "Environments|An error occurred while canceling the auto stop, please try again"
+msgstr ""
+
+msgid "Environments|An error occurred while deleting the environment. Check if the environment stopped; if not, stop it and try again."
+msgstr ""
+
+msgid "Environments|An error occurred while fetching the environments."
+msgstr ""
+
+msgid "Environments|An error occurred while making the request."
+msgstr ""
+
+msgid "Environments|An error occurred while re-deploying the environment, please try again"
+msgstr ""
+
+msgid "Environments|An error occurred while rolling back the environment, please try again"
+msgstr ""
+
+msgid "Environments|An error occurred while stopping the environment, please try again"
+msgstr ""
+
+msgid "Environments|Are you sure you want to stop this environment?"
+msgstr ""
+
+msgid "Environments|Auto stop"
+msgstr ""
+
+msgid "Environments|Auto stops %{autoStopAt}"
+msgstr ""
+
+msgid "Environments|Clean up"
+msgstr ""
+
+msgid "Environments|Clean up environments"
+msgstr ""
+
+msgid "Environments|Commit"
+msgstr ""
+
+msgid "Environments|Create an environment"
+msgstr ""
+
+msgid "Environments|Delete"
+msgstr ""
+
+msgid "Environments|Delete '%{environmentName}'?"
+msgstr ""
+
+msgid "Environments|Delete environment"
+msgstr ""
+
+msgid "Environments|Deleting the '%{environmentName}' environment cannot be undone. Do you want to delete it anyway?"
+msgstr ""
+
+msgid "Environments|Deploy to..."
+msgstr ""
+
+msgid "Environments|Deployment"
+msgstr ""
+
+msgid "Environments|Deployment %{status}"
+msgstr ""
+
+msgid "Environments|Edit your search and try again"
+msgstr ""
+
+msgid "Environments|Enable Review Apps"
+msgstr ""
+
+msgid "Environments|Enable review apps"
+msgstr ""
+
+msgid "Environments|Environment"
+msgstr ""
+
+msgid "Environments|Environments"
+msgstr ""
+
+msgid "Environments|Environments are places where code gets deployed, such as staging or production. You can create an environment in the UI or in your .gitlab-ci.yml file. You can also enable review apps, which assist with providing an environment to showcase product changes. %{linkStart}Learn more%{linkEnd} about environments."
+msgstr ""
+
+msgid "Environments|Get started with environments"
+msgstr ""
+
+msgid "Environments|GitLab agent"
+msgstr ""
+
+msgid "Environments|HelmReleases"
+msgstr ""
+
+msgid "Environments|Job"
+msgstr ""
+
+msgid "Environments|Kubernetes namespace (optional)"
+msgstr ""
+
+msgid "Environments|Kustomizations"
+msgstr ""
+
+msgid "Environments|Learn more about stopping environments"
+msgstr ""
+
+msgid "Environments|New"
+msgstr ""
+
+msgid "Environments|New Environment"
+msgstr ""
+
+msgid "Environments|New environment"
+msgstr ""
+
+msgid "Environments|No deployments yet"
+msgstr ""
+
+msgid "Environments|No results found"
+msgstr ""
+
+msgid "Environments|Note that this action will stop the environment, but it will %{emphasisStart}not%{emphasisEnd} have an effect on any existing deployment due to no “stop environment action†being defined in the %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd} file."
+msgstr ""
+
+msgid "Environments|Open"
+msgstr ""
+
+msgid "Environments|Open live environment"
+msgstr ""
+
+msgid "Environments|Re-deploy environment"
+msgstr ""
+
+msgid "Environments|Re-deploy environment %{name}?"
+msgstr ""
+
+msgid "Environments|Re-deploy to environment"
+msgstr ""
+
+msgid "Environments|Rollback environment"
+msgstr ""
+
+msgid "Environments|Rollback environment %{name}?"
+msgstr ""
+
+msgid "Environments|Search by environment name"
+msgstr ""
+
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
+msgid "Environments|Select agent"
+msgstr ""
+
+msgid "Environments|Select namespace"
+msgstr ""
+
+msgid "Environments|Select which environments to clean up. Protected environments are excluded. Learn more about cleaning up environments."
+msgstr ""
+
+msgid "Environments|Show all"
+msgstr ""
+
+msgid "Environments|Stop"
+msgstr ""
+
+msgid "Environments|Stop environment"
+msgstr ""
+
+msgid "Environments|Stop environments that have not been updated since the specified date:"
+msgstr ""
+
+msgid "Environments|Stop unused environments"
+msgstr ""
+
+msgid "Environments|Stopping %{environmentName}"
+msgstr ""
+
+msgid "Environments|There are no deployments for this environment yet. %{linkStart}Learn more about setting up deployments.%{linkEnd}"
+msgstr ""
+
+msgid "Environments|This action will %{docsStart}retry the latest deployment%{docsEnd} with the commit %{commitId}, for this environment. Are you sure you want to continue?"
+msgstr ""
+
+msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
+msgstr ""
+
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
+msgid "Environments|Upcoming"
+msgstr ""
+
+msgid "Environments|Upcoming deployment"
+msgstr ""
+
+msgid "Environments|Updated"
+msgstr ""
+
+msgid "Environments|by %{avatar}"
+msgstr ""
+
+msgid "Environments|protected"
+msgstr ""
+
+msgid "Environment|Age"
+msgstr ""
+
+msgid "Environment|Auto stop %{time}"
+msgstr ""
+
+msgid "Environment|Cluster IP"
+msgstr ""
+
+msgid "Environment|Cluster agent not found."
+msgstr ""
+
+msgid "Environment|CronJobs"
+msgstr ""
+
+msgid "Environment|DaemonSets"
+msgstr ""
+
+msgid "Environment|Deployment tier"
+msgstr ""
+
+msgid "Environment|Deployments"
+msgstr ""
+
+msgid "Environment|Environment health"
+msgstr ""
+
+msgid "Environment|External IP"
+msgstr ""
+
+msgid "Environment|Failed"
+msgstr ""
+
+msgid "Environment|Forbidden to access the cluster agent from this environment."
+msgstr ""
+
+msgid "Environment|Healthy"
+msgstr ""
+
+msgid "Environment|Jobs"
+msgstr ""
+
+msgid "Environment|Kubernetes overview"
+msgstr ""
+
+msgid "Environment|Pending"
+msgstr ""
+
+msgid "Environment|Pods"
+msgstr ""
+
+msgid "Environment|Ports"
+msgstr ""
+
+msgid "Environment|Reconciled"
+msgstr ""
+
+msgid "Environment|Reconciling"
+msgstr ""
+
+msgid "Environment|ReplicaSets"
+msgstr ""
+
+msgid "Environment|Running"
+msgstr ""
+
+msgid "Environment|Services"
+msgstr ""
+
+msgid "Environment|Stalled"
+msgstr ""
+
+msgid "Environment|StatefulSets"
+msgstr ""
+
+msgid "Environment|Succeeded"
+msgstr ""
+
+msgid "Environment|Summary"
+msgstr ""
+
+msgid "Environment|Sync status"
+msgstr ""
+
+msgid "Environment|There was an error connecting to the cluster agent."
+msgstr ""
+
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
+msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
+msgstr ""
+
+msgid "Environment|Unhealthy"
+msgstr ""
+
+msgid "Epic"
+msgstr ""
+
+msgid "Epic Boards"
+msgstr ""
+
+msgid "Epic ID"
+msgstr ""
+
+msgid "Epic actions"
+msgstr ""
+
+msgid "Epic boards"
+msgstr ""
+
+msgid "Epic cannot be found."
+msgstr ""
+
+msgid "Epic details"
+msgstr ""
+
+msgid "Epic events"
+msgstr ""
+
+msgid "Epic not found for given params"
+msgstr ""
+
+msgid "Epic summary"
+msgstr ""
+
+msgid "Epic title"
+msgstr ""
+
+msgid "Epics"
+msgstr ""
+
+msgid "Epics Roadmap"
+msgstr ""
+
+msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
+msgstr ""
+
+msgid "Epics, issues, and merge requests"
+msgstr ""
+
+msgid "Epics|Add a new epic"
+msgstr ""
+
+msgid "Epics|Add an existing epic"
+msgstr ""
+
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
+
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
+
+msgid "Epics|Leave empty to inherit from milestone dates"
+msgstr ""
+
+msgid "Epics|Remove epic"
+msgstr ""
+
+msgid "Epics|Remove issue"
+msgstr ""
+
+msgid "Epics|Something went wrong while creating child epics."
+msgstr ""
+
+msgid "Epics|Something went wrong while creating issue."
+msgstr ""
+
+msgid "Epics|Something went wrong while fetching child epics."
+msgstr ""
+
+msgid "Epics|Something went wrong while fetching epics list."
+msgstr ""
+
+msgid "Epics|Something went wrong while moving item."
+msgstr ""
+
+msgid "Epics|Something went wrong while ordering item."
+msgstr ""
+
+msgid "Epics|Something went wrong while updating epics."
+msgstr ""
+
+msgid "Epics|The color for the epic when it's visualized, such as on roadmap timeline bars."
+msgstr ""
+
+msgid "Epics|This epic and any containing child epics are confidential and should only be visible to team members with at least Reporter access."
+msgstr ""
+
+msgid "Epics|This will also remove any descendents of %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}. Are you sure?"
+msgstr ""
+
+msgid "Epics|Unable to save epic. Please try again"
+msgstr ""
+
+msgid "Erased"
+msgstr ""
+
+msgid "Error"
+msgstr ""
+
+msgid "Error Details"
+msgstr ""
+
+msgid "Error Tracking"
+msgstr ""
+
+msgid "Error creating epic"
+msgstr ""
+
+msgid "Error creating label."
+msgstr ""
+
+msgid "Error creating new directory. Please try again."
+msgstr ""
+
+msgid "Error creating new iteration"
+msgstr ""
+
+msgid "Error creating or updating PreScanVerificationStep: %{errors}"
+msgstr ""
+
+msgid "Error creating repository for snippet with id %{snippet_id}"
+msgstr ""
+
+msgid "Error creating the snippet"
+msgstr ""
+
+msgid "Error creating vulnerability finding: %{errors}"
+msgstr ""
+
+msgid "Error fetching branches"
+msgstr ""
+
+msgid "Error fetching burnup chart data"
+msgstr ""
+
+msgid "Error fetching data. Please try again."
+msgstr ""
+
+msgid "Error fetching diverging counts for branches. Please try again."
+msgstr ""
+
+msgid "Error fetching forked projects. Please try again."
+msgstr ""
+
+msgid "Error fetching labels."
+msgstr ""
+
+msgid "Error fetching network graph."
+msgstr ""
+
+msgid "Error fetching payload data."
+msgstr ""
+
+msgid "Error fetching the dependency list. Please check your network connection and try again."
+msgstr ""
+
+msgid "Error loading branch data. Please try again."
+msgstr ""
+
+msgid "Error loading branches."
+msgstr ""
+
+msgid "Error loading burndown chart data"
+msgstr ""
+
+msgid "Error loading file viewer."
+msgstr ""
+
+msgid "Error loading issues"
+msgstr ""
+
+msgid "Error loading iterations"
+msgstr ""
+
+msgid "Error loading last commit."
+msgstr ""
+
+msgid "Error loading markdown preview"
+msgstr ""
+
+msgid "Error loading merge requests."
+msgstr ""
+
+msgid "Error loading milestone tab"
+msgstr ""
+
+msgid "Error loading project data. Please try again."
+msgstr ""
+
+msgid "Error loading template types."
+msgstr ""
+
+msgid "Error loading template."
+msgstr ""
+
+msgid "Error loading viewer"
+msgstr ""
+
+msgid "Error occurred when fetching sidebar data"
+msgstr ""
+
+msgid "Error occurred when saving assignees"
+msgstr ""
+
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
+msgid "Error occurred while updating the issue status"
+msgstr ""
+
+msgid "Error occurred. A blocked user cannot be deactivated"
+msgstr ""
+
+msgid "Error occurred. A blocked user must be unblocked to be activated"
+msgstr ""
+
+msgid "Error occurred. User was not banned"
+msgstr ""
+
+msgid "Error occurred. User was not blocked"
+msgstr ""
+
+msgid "Error occurred. User was not confirmed"
+msgstr ""
+
+msgid "Error occurred. User was not unbanned"
+msgstr ""
+
+msgid "Error occurred. User was not unblocked"
+msgstr ""
+
+msgid "Error occurred. User was not unlocked"
+msgstr ""
+
+msgid "Error parsing CSV file. Please make sure it has"
+msgstr ""
+
+msgid "Error promoting the note to timeline event: %{error}"
+msgstr ""
+
+msgid "Error rendering Markdown preview"
+msgstr ""
+
+msgid "Error saving label update."
+msgstr ""
+
+msgid "Error setting up editor. Please try again."
+msgstr ""
+
+msgid "Error tracking"
+msgstr ""
+
+msgid "Error updating %{issuableType}"
+msgstr ""
+
+msgid "Error updating status for all to-do items."
+msgstr ""
+
+msgid "Error updating status of to-do item."
+msgstr ""
+
+msgid "Error updating the snippet"
+msgstr ""
+
+msgid "Error uploading file"
+msgstr ""
+
+msgid "Error uploading file. Please try again."
+msgstr ""
+
+msgid "Error while loading the merge request. Please try again."
+msgstr ""
+
+msgid "Error while migrating %{upload_id}: %{error_message}"
+msgstr ""
+
+msgid "Error with Akismet. Please check the logs for more info."
+msgstr ""
+
+msgid "Error: %{error_message}"
+msgstr ""
+
+msgid "Error: %{error}"
+msgstr ""
+
+msgid "Error: Can't edit this file. The fork and upstream project have diverged. %{link_start}Edit the file on the fork %{icon}%{link_end}, and create a merge request."
+msgstr ""
+
+msgid "Error: Couldn't load some or all of the changes."
+msgstr ""
+
+msgid "Error: Gitaly is unavailable. Contact your administrator."
+msgstr ""
+
+msgid "Error: Unable to create deploy freeze"
+msgstr ""
+
+msgid "Error: Unable to delete deploy freeze"
+msgstr ""
+
+msgid "ErrorTracking|Access token is %{token_in_code_tag}"
+msgstr ""
+
+msgid "ErrorTracking|Active"
+msgstr ""
+
+msgid "ErrorTracking|After adding your Auth Token, select the Connect button to load projects."
+msgstr ""
+
+msgid "ErrorTracking|Auth Token"
+msgstr ""
+
+msgid "ErrorTracking|Click Connect to reestablish the connection to Sentry and activate the dropdown."
+msgstr ""
+
+msgid "ErrorTracking|Connection failed. Check Auth Token and try again."
+msgstr ""
+
+msgid "ErrorTracking|Enable error tracking"
+msgstr ""
+
+msgid "ErrorTracking|Error tracking backend"
+msgstr ""
+
+msgid "ErrorTracking|If you self-host Sentry, enter your Sentry instance's full URL. If you use Sentry's hosted solution, enter https://sentry.io"
+msgstr ""
+
+msgid "ErrorTracking|Integrated error tracking is %{epicLinkStart}turned off by default%{epicLinkEnd} and no longer active for this project. To re-enable error tracking on self-hosted instances, you can either %{flagLinkStart}turn on the feature flag%{flagLinkEnd} for integrated error tracking, or provide a %{settingsLinkStart}Sentry API URL and Auth Token%{settingsLinkEnd} on your project settings page. However, error tracking is not ready for production use and cannot be enabled on GitLab.com."
+msgstr ""
+
+msgid "ErrorTracking|Integrated error tracking is %{epicLinkStart}turned off by default%{epicLinkEnd} and no longer active for this project. To re-enable error tracking on self-hosted instances, you can either %{flagLinkStart}turn on the feature flag%{flagLinkEnd} for integrated error tracking, or provide a Sentry API URL and Auth Token below. However, error tracking is not ready for production use and cannot be enabled on GitLab.com."
+msgstr ""
+
+msgid "ErrorTracking|No projects available"
+msgstr ""
+
+msgid "ErrorTracking|Select project"
+msgstr ""
+
+msgid "ErrorTracking|To enable project selection, enter a valid Auth Token."
+msgstr ""
+
+msgid "ErrorTracking|View project settings"
+msgstr ""
+
+msgid "Errors"
+msgstr ""
+
+msgid "Errors found on line %{line_number}: %{error_lines}. Please check if these lines have a requirement title."
+msgstr ""
+
+msgid "Escalate this incident"
+msgstr ""
+
+msgid "Escalation Policies"
+msgstr ""
+
+msgid "Escalation policies"
+msgstr ""
+
+msgid "Escalation policies may not have more than %{rule_count} rules"
+msgstr ""
+
+msgid "Escalation policies must have at least one rule"
+msgstr ""
+
+msgid "Escalation policy"
+msgstr ""
+
+msgid "Escalation policy:"
+msgstr ""
+
+msgid "EscalationPolicies|%{clockIcon} IF alert is not %{alertStatus} in %{minutes}"
+msgstr ""
+
+msgid "EscalationPolicies|%{notificationIcon} THEN %{doAction} %{forScheduleOrUser}"
+msgstr ""
+
+msgid "EscalationPolicies|+ Add an additional rule"
+msgstr ""
+
+msgid "EscalationPolicies|A schedule is required for adding an escalation policy."
+msgstr ""
+
+msgid "EscalationPolicies|A schedule is required for adding an escalation policy. Please create an on-call schedule first."
+msgstr ""
+
+msgid "EscalationPolicies|A user is required for adding an escalation policy."
+msgstr ""
+
+msgid "EscalationPolicies|Add an escalation policy"
+msgstr ""
+
+msgid "EscalationPolicies|Add escalation policy"
+msgstr ""
+
+msgid "EscalationPolicies|Add policy"
+msgstr ""
+
+msgid "EscalationPolicies|Are you sure you want to delete the \"%{escalationPolicy}\" escalation policy? This action cannot be undone."
+msgstr ""
+
+msgid "EscalationPolicies|Choose who to email if those contacted first about an alert don't respond."
+msgstr ""
+
+msgid "EscalationPolicies|Choose who to email if those contacted first about an alert don't respond. To access this feature, ask %{linkStart}a project Owner%{linkEnd} to grant you at least the Maintainer role."
+msgstr ""
+
+msgid "EscalationPolicies|Create an escalation policy in GitLab"
+msgstr ""
+
+msgid "EscalationPolicies|Delete escalation policy"
+msgstr ""
+
+msgid "EscalationPolicies|Distinguishes this policy from others you may create (for example, \"Critical alert escalation\")."
+msgstr ""
+
+msgid "EscalationPolicies|Edit escalation policy"
+msgstr ""
+
+msgid "EscalationPolicies|Email on-call user in schedule"
+msgstr ""
+
+msgid "EscalationPolicies|Email user"
+msgstr ""
+
+msgid "EscalationPolicies|Escalation policies"
+msgstr ""
+
+msgid "EscalationPolicies|Escalation policy %{obstacle} in project %{project}"
+msgstr ""
+
+msgid "EscalationPolicies|Escalation policy successfully created"
+msgstr ""
+
+msgid "EscalationPolicies|Escalation rules"
+msgstr ""
+
+msgid "EscalationPolicies|Failed to load oncall-schedules"
+msgstr ""
+
+msgid "EscalationPolicies|IF alert is not %{alertStatus} in %{minutes} minutes"
+msgstr ""
+
+msgid "EscalationPolicies|Maximum of 10 rules has been reached."
+msgstr ""
+
+msgid "EscalationPolicies|Minutes must be between 0 and 1440."
+msgstr ""
+
+msgid "EscalationPolicies|More detailed information about your policy."
+msgstr ""
+
+msgid "EscalationPolicies|Remove escalation rule"
+msgstr ""
+
+msgid "EscalationPolicies|Search for user"
+msgstr ""
+
+msgid "EscalationPolicies|Select schedule"
+msgstr ""
+
+msgid "EscalationPolicies|THEN %{doAction} %{scheduleOrUser}"
+msgstr ""
+
+msgid "EscalationPolicies|The escalation policy could not be deleted. Please try again."
+msgstr ""
+
+msgid "EscalationPolicies|The escalation policy could not be updated. Please try again"
+msgstr ""
+
+msgid "EscalationPolicies|This policy has no escalation rules."
+msgstr ""
+
+msgid "EscalationPolicies|When a new alert is received, the users specified in the policy receive an email."
+msgstr ""
+
+msgid "EscalationPolicies|mins"
+msgstr ""
+
+msgid "EscalationStatus|Acknowledged"
+msgstr ""
+
+msgid "EscalationStatus|Resolved"
+msgstr ""
+
+msgid "EscalationStatus|Triggered"
+msgstr ""
+
+msgid "Estimate"
+msgstr ""
+
+msgid "Estimated"
+msgstr ""
+
+msgid "Even if you reach the number of seats in your subscription, you can continue to add users, and GitLab will bill you for the overage."
+msgstr ""
+
+msgid "Event '%{event}' of type '%{event_type}' must not start with '%{prefix}'"
+msgstr ""
+
+msgid "Event tag (optional)"
+msgstr ""
+
+msgid "Event type '%{type}' is not yet supported"
+msgstr ""
+
+msgid "EventFilterBy|Filter by all"
+msgstr ""
+
+msgid "EventFilterBy|Filter by comments"
+msgstr ""
+
+msgid "EventFilterBy|Filter by designs"
+msgstr ""
+
+msgid "EventFilterBy|Filter by epic events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by issue events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by merge events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by push events"
+msgstr ""
+
+msgid "EventFilterBy|Filter by team"
+msgstr ""
+
+msgid "EventFilterBy|Filter by wiki"
+msgstr ""
+
+msgid "Events"
+msgstr ""
+
+msgid "Events API"
+msgstr ""
+
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
+msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
+msgstr ""
+
+msgid "Every 3 months"
+msgstr ""
+
+msgid "Every 3 months on the %{day} at %{time} %{timezone}"
+msgstr ""
+
+msgid "Every 6 months"
+msgstr ""
+
+msgid "Every 6 months on the %{day} at %{time} %{timezone}"
+msgstr ""
+
+msgid "Every day"
+msgstr ""
+
+msgid "Every day (at %{time})"
+msgstr ""
+
+msgid "Every day at %{time} %{timezone}"
+msgstr ""
+
+msgid "Every month"
+msgstr ""
+
+msgid "Every month (Day %{day} at %{time})"
+msgstr ""
+
+msgid "Every month on the %{day} at %{time} %{timezone}"
+msgstr ""
+
+msgid "Every three months"
+msgstr ""
+
+msgid "Every two weeks"
+msgstr ""
+
+msgid "Every week"
+msgid_plural "Every %d weeks"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Every week (%{weekday} at %{time})"
+msgstr ""
+
+msgid "Every week on %{day} at %{time} %{timezone}"
+msgstr ""
+
+msgid "Every year"
+msgstr ""
+
+msgid "Every year on %{day} at %{time} %{timezone}"
+msgstr ""
+
+msgid "Everyone With Access"
+msgstr ""
+
+msgid "Everyone can access the wiki."
+msgstr ""
+
+msgid "Everyone can contribute"
+msgstr ""
+
+msgid "Everything on your to-do list is marked as done."
+msgstr ""
+
+msgid "Everything you need to create a GitLab Pages site using Bridgetown"
+msgstr ""
+
+msgid "Everything you need to create a GitLab Pages site using Gatsby"
+msgstr ""
+
+msgid "Everything you need to create a GitLab Pages site using Hexo"
+msgstr ""
+
+msgid "Everything you need to create a GitLab Pages site using Hugo"
+msgstr ""
+
+msgid "Everything you need to create a GitLab Pages site using Jekyll"
+msgstr ""
+
+msgid "Everything you need to create a GitLab Pages site using Middleman"
+msgstr ""
+
+msgid "Everything you need to create a GitLab Pages site using Pelican"
+msgstr ""
+
+msgid "Everything you need to create a GitLab Pages site using plain HTML"
+msgstr ""
+
+msgid "Evidence collection"
+msgstr ""
+
+msgid "Exactly one of %{attributes} is required"
+msgstr ""
+
+msgid "Example"
+msgstr ""
+
+msgid "Example: (feature|hotfix)\\/*"
+msgstr ""
+
+msgid "Example: (jar|exe)$"
+msgstr ""
+
+msgid "Example: @sub\\.company\\.com$"
+msgstr ""
+
+msgid "Example: Fixes \\d+\\..*"
+msgstr ""
+
+msgid "Example: ssh\\:\\/\\/"
+msgstr ""
+
+msgid "Examples"
+msgstr ""
+
+msgid "Except policy:"
+msgstr ""
+
+msgid "Exceptions"
+msgstr ""
+
+msgid "Excluding USB security keys, you should include the browser name together with the device name."
+msgstr ""
+
+msgid "Excluding merge commits. Limited to %{limit} commits."
+msgstr ""
+
+msgid "Excluding merge commits. Limited to 6,000 commits."
+msgstr ""
+
+msgid "Execution time"
+msgstr ""
+
+msgid "Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "Existing projects may be moved into a group"
+msgstr ""
+
+msgid "Existing projects will be able to use cleanup policies. Avoid enabling this if an external Container Registry is being used, as there is a performance risk if many images exist on one project."
+msgstr ""
+
+msgid "Existing sign in methods may be removed"
+msgstr ""
+
+msgid "Expand"
+msgstr ""
+
+msgid "Expand AI-generated summary"
+msgstr ""
+
+msgid "Expand all"
+msgstr ""
+
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand eligible approvers"
+msgstr ""
+
+msgid "Expand file"
+msgstr ""
+
+msgid "Expand issues"
+msgstr ""
+
+msgid "Expand jobs"
+msgstr ""
+
+msgid "Expand merge details"
+msgstr ""
+
+msgid "Expand milestones"
+msgstr ""
+
+msgid "Expand settings section"
+msgstr ""
+
+msgid "Expand sidebar"
+msgstr ""
+
+msgid "Expand variable reference"
+msgstr ""
+
+msgid "Expected documents: %{expected_documents}"
+msgstr ""
+
+msgid "Experiment"
+msgstr ""
+
+msgid "Experiment features' settings not allowed."
+msgstr ""
+
+msgid "Experiments"
+msgstr ""
+
+msgid "Expiration"
+msgstr ""
+
+msgid "Expiration date"
+msgstr ""
+
+msgid "Expiration date (optional)"
+msgstr ""
+
+msgid "Expiration date:"
+msgstr ""
+
+msgid "Expired"
+msgstr ""
+
+msgid "Expired %{expiredOn}"
+msgstr ""
+
+msgid "Expired:"
+msgstr ""
+
+msgid "Expires"
+msgstr ""
+
+msgid "Expires %{preposition} %{expires_at}"
+msgstr ""
+
+msgid "Explain why you're reporting the user."
+msgstr ""
+
+msgid "Explore"
+msgstr ""
+
+msgid "Explore groups"
+msgstr ""
+
+msgid "Explore paid plans"
+msgstr ""
+
+msgid "Explore projects"
+msgstr ""
+
+msgid "Explore public projects"
+msgstr ""
+
+msgid "Explore snippets"
+msgstr ""
+
+msgid "Explore topics"
+msgstr ""
+
+msgid "Export"
+msgstr ""
+
+msgid "Export %{requirementsCount} requirements?"
+msgstr ""
+
+msgid "Export as CSV"
+msgstr ""
+
+msgid "Export commit custody report"
+msgstr ""
+
+msgid "Export group"
+msgstr ""
+
+msgid "Export issues"
+msgstr ""
+
+msgid "Export merge requests"
+msgstr ""
+
+msgid "Export project"
+msgstr ""
+
+msgid "Export requirements"
+msgstr ""
+
+msgid "Export this group with all related data."
+msgstr ""
+
+msgid "Export this project with all its related data in order to move it to a new GitLab instance. When the exported file is ready, you can download it from this page or from the download link in the email notification you will receive. You can then import it when creating a new project. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Export variable to pipelines running on protected branches and tags only."
+msgstr ""
+
+msgid "Exported requirements"
+msgstr ""
+
+msgid "External URL"
+msgstr ""
+
+msgid "External User:"
+msgstr ""
+
+msgid "External authorization denied access to this project"
+msgstr ""
+
+msgid "External storage URL"
+msgstr ""
+
+msgid "External storage authentication token"
+msgstr ""
+
+msgid "External storage for repository static objects"
+msgstr ""
+
+msgid "ExternalAuthorizationService|Classification label"
+msgstr ""
+
+msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
+msgstr ""
+
+msgid "ExternalAuthorization|Access to projects is validated on an external service using their classification label."
+msgstr ""
+
+msgid "ExternalAuthorization|Allow deploy tokens and deploy keys to be used with external authorization"
+msgstr ""
+
+msgid "ExternalAuthorization|Certificate used to authenticate with the external authorization service. If blank, the server certificate is validated when accessing over HTTPS."
+msgstr ""
+
+msgid "ExternalAuthorization|Classification label to use when requesting authorization if no specific label is defined on the project."
+msgstr ""
+
+msgid "ExternalAuthorization|Client authorization certificate"
+msgstr ""
+
+msgid "ExternalAuthorization|Client authorization key"
+msgstr ""
+
+msgid "ExternalAuthorization|Client authorization key password (optional)"
+msgstr ""
+
+msgid "ExternalAuthorization|Default classification label"
+msgstr ""
+
+msgid "ExternalAuthorization|Does not apply if service URL is specified."
+msgstr ""
+
+msgid "ExternalAuthorization|Enable classification control using an external service"
+msgstr ""
+
+msgid "ExternalAuthorization|External authorization"
+msgstr ""
+
+msgid "ExternalAuthorization|External authorization request timeout (seconds)"
+msgstr ""
+
+msgid "ExternalAuthorization|External classification policy authorization."
+msgstr ""
+
+msgid "ExternalAuthorization|Passphrase required to decrypt the private key. Encrypted when stored."
+msgstr ""
+
+msgid "ExternalAuthorization|Period GitLab waits for a response from the external service. If there is no response, access is denied. Default: 0.5 seconds."
+msgstr ""
+
+msgid "ExternalAuthorization|Private key of client authentication certificate. Encrypted when stored."
+msgstr ""
+
+msgid "ExternalAuthorization|Service URL"
+msgstr ""
+
+msgid "ExternalAuthorization|URL to which the projects make authorization requests. If the URL is blank, cross-project features are available and can still specify classification labels for projects."
+msgstr ""
+
+msgid "ExternalIssueIntegration|Another issue tracker is already in use"
+msgstr ""
+
+msgid "ExternalIssueIntegration|Not all data may be displayed here. To view more details or make changes to this issue, go to %{linkStart}%{trackerName}%{linkEnd}."
+msgstr ""
+
+msgid "ExternalIssueIntegration|Only one issue tracker integration can be active at a time. Please disable the active tracker first and try again."
+msgstr ""
+
+msgid "ExternalIssueIntegration|This issue is synchronized with %{trackerName}"
+msgstr ""
+
+msgid "ExternalWikiService|Enter the URL to the external wiki."
+msgstr ""
+
+msgid "ExternalWikiService|External wiki"
+msgstr ""
+
+msgid "ExternalWikiService|External wiki URL"
+msgstr ""
+
+msgid "ExternalWikiService|Link to an external wiki from the sidebar."
+msgstr ""
+
+msgid "ExternalWikiService|https://example.com/xxx/wiki/..."
+msgstr ""
+
+msgid "Facebook"
+msgstr ""
+
+msgid "Factually incorrect"
+msgstr ""
+
+msgid "Fail"
+msgstr ""
+
+msgid "Failed"
+msgstr ""
+
+msgid "Failed Jobs"
+msgstr ""
+
+msgid "Failed job"
+msgid_plural "Failed jobs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Failed jobs (%{count})"
+msgstr ""
+
+msgid "Failed on"
+msgstr ""
+
+msgid "Failed to %{action} this work item: %{reason}."
+msgstr ""
+
+msgid "Failed to add a Zoom meeting"
+msgstr ""
+
+msgid "Failed to add a resource link"
+msgstr ""
+
+msgid "Failed to add emoji. Please try again"
+msgstr ""
+
+msgid "Failed to apply commands."
+msgstr ""
+
+msgid "Failed to archive a design. Please try again."
+msgid_plural "Failed to archive designs. Please try again."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Failed to assign a reviewer because no user was specified."
+msgstr ""
+
+msgid "Failed to assign a user because no user was found."
+msgstr ""
+
+msgid "Failed to assign you issues related to the merge request."
+msgstr ""
+
+msgid "Failed to cancel auto stop because failed to update the environment."
+msgstr ""
+
+msgid "Failed to cancel auto stop because the environment is not set as auto stop."
+msgstr ""
+
+msgid "Failed to cancel auto stop because you do not have permission to update the environment."
+msgstr ""
+
+msgid "Failed to change the owner"
+msgstr ""
+
+msgid "Failed to check related branches."
+msgstr ""
+
+msgid "Failed to clone this issue because target project doesn't exist."
+msgstr ""
+
+msgid "Failed to clone this issue: wrong parameters."
+msgstr ""
+
+msgid "Failed to create a branch for this issue. Please try again."
+msgstr ""
+
+msgid "Failed to create a to-do item for the design."
+msgstr ""
+
+msgid "Failed to create framework"
+msgstr ""
+
+msgid "Failed to create import label for jira import."
+msgstr ""
+
+msgid "Failed to create repository"
+msgstr ""
+
+msgid "Failed to create resources"
+msgstr ""
+
+msgid "Failed to create target branch rule"
+msgstr ""
+
+msgid "Failed to create wiki"
+msgstr ""
+
+msgid "Failed to delete custom emoji. Please try again."
+msgstr ""
+
+msgid "Failed to deploy to"
+msgstr ""
+
+msgid "Failed to enqueue the rebase operation, possibly due to a long-lived transaction. Try again later."
+msgstr ""
+
+msgid "Failed to fetch the iteration for this issue. Please try again."
+msgstr ""
+
+msgid "Failed to fetch the iterations for the group. Please try again."
+msgstr ""
+
+msgid "Failed to find import label for Jira import."
+msgstr ""
+
+msgid "Failed to find users for %{missing}"
+msgstr ""
+
+msgid "Failed to generate description"
+msgstr ""
+
+msgid "Failed to generate export, please try again later."
+msgstr ""
+
+msgid "Failed to generate report, please try again after sometime"
+msgstr ""
+
+msgid "Failed to get ref."
+msgstr ""
+
+msgid "Failed to load"
+msgstr ""
+
+msgid "Failed to load Roadmap"
+msgstr ""
+
+msgid "Failed to load assignees."
+msgstr ""
+
+msgid "Failed to load assignees. Please try again."
+msgstr ""
+
+msgid "Failed to load authors. Please try again."
+msgstr ""
+
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
+msgid "Failed to load error details from Sentry."
+msgstr ""
+
+msgid "Failed to load errors from Sentry."
+msgstr ""
+
+msgid "Failed to load group activity metrics. Please try again."
+msgstr ""
+
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
+msgid "Failed to load groups."
+msgstr ""
+
+msgid "Failed to load iteration cadences."
+msgstr ""
+
+msgid "Failed to load iterations."
+msgstr ""
+
+msgid "Failed to load labels. Please try again."
+msgstr ""
+
+msgid "Failed to load milestones."
+msgstr ""
+
+msgid "Failed to load milestones. Please try again."
+msgstr ""
+
+msgid "Failed to load projects"
+msgstr ""
+
+msgid "Failed to load related branches"
+msgstr ""
+
+msgid "Failed to load stacktrace."
+msgstr ""
+
+msgid "Failed to make repository read-only. %{reason}"
+msgstr ""
+
+msgid "Failed to mark this issue as a duplicate because referenced issue was not found."
+msgstr ""
+
+msgid "Failed to move this issue because label was not found."
+msgstr ""
+
+msgid "Failed to move this issue because only a single label can be provided."
+msgstr ""
+
+msgid "Failed to move this issue because target project doesn't exist."
+msgstr ""
+
+msgid "Failed to promote label due to internal error. Please contact administrators."
+msgstr ""
+
+msgid "Failed to protect the branch"
+msgstr ""
+
+msgid "Failed to protect the environment"
+msgstr ""
+
+msgid "Failed to publish issue on status page."
+msgstr ""
+
+msgid "Failed to remove a Zoom meeting"
+msgstr ""
+
+msgid "Failed to remove a to-do item for the design."
+msgstr ""
+
+msgid "Failed to remove emoji. Please try again"
+msgstr ""
+
+msgid "Failed to remove mirror."
+msgstr ""
+
+msgid "Failed to remove the pipeline schedule"
+msgstr ""
+
+msgid "Failed to remove timelog"
+msgstr ""
+
+msgid "Failed to remove user identity."
+msgstr ""
+
+msgid "Failed to remove user key."
+msgstr ""
+
+msgid "Failed to retrieve page"
+msgstr ""
+
+msgid "Failed to save merge conflicts resolutions. Please try again!"
+msgstr ""
+
+msgid "Failed to save namespace commit email."
+msgstr ""
+
+msgid "Failed to save new settings"
+msgstr ""
+
+msgid "Failed to save preferences (%{error_message})."
+msgstr ""
+
+msgid "Failed to save preferences."
+msgstr ""
+
+msgid "Failed to save timelog"
+msgstr ""
+
+msgid "Failed to set due date because the date format is invalid."
+msgstr ""
+
+msgid "Failed to set iteration on this issue. Please try again."
+msgstr ""
+
+msgid "Failed to signing using smartcard authentication"
+msgstr ""
+
+msgid "Failed to toggle the to-do status for the design."
+msgstr ""
+
+msgid "Failed to update branch!"
+msgstr ""
+
+msgid "Failed to update environment!"
+msgstr ""
+
+msgid "Failed to update framework"
+msgstr ""
+
+msgid "Failed to update issue status"
+msgstr ""
+
+msgid "Failed to update the Canary Ingress."
+msgstr ""
+
+msgid "Failed to upload object map file"
+msgstr ""
+
+msgid "Failure"
+msgstr ""
+
+msgid "False positive"
+msgstr ""
+
+msgid "Fast timeout"
+msgstr ""
+
+msgid "Faster releases. Better code. Less pain."
+msgstr ""
+
+msgid "Favicon"
+msgstr ""
+
+msgid "Favicon was successfully removed."
+msgstr ""
+
+msgid "Favicon will be removed. Are you sure?"
+msgstr ""
+
+msgid "Feature Flags"
+msgstr ""
+
+msgid "Feature flag status"
+msgstr ""
+
+msgid "Feature flag was not removed."
+msgstr ""
+
+msgid "Feature flag was successfully removed."
+msgstr ""
+
+msgid "FeatureFlags|%d user"
+msgid_plural "FeatureFlags|%d users"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "FeatureFlags|%{percent} by available ID"
+msgstr ""
+
+msgid "FeatureFlags|%{percent} by session ID"
+msgstr ""
+
+msgid "FeatureFlags|%{percent} by user ID"
+msgstr ""
+
+msgid "FeatureFlags|%{percent} randomly"
+msgstr ""
+
+msgid "FeatureFlags|* (All Environments)"
+msgstr ""
+
+msgid "FeatureFlags|API URL"
+msgstr ""
+
+msgid "FeatureFlags|Active"
+msgstr ""
+
+msgid "FeatureFlags|Add strategy"
+msgstr ""
+
+msgid "FeatureFlags|All Environments"
+msgstr ""
+
+msgid "FeatureFlags|All Users"
+msgstr ""
+
+msgid "FeatureFlags|All users"
+msgstr ""
+
+msgid "FeatureFlags|Configure"
+msgstr ""
+
+msgid "FeatureFlags|Configure feature flags"
+msgstr ""
+
+msgid "FeatureFlags|Consider using the more flexible \"Percent rollout\" strategy instead."
+msgstr ""
+
+msgid "FeatureFlags|Create feature flag"
+msgstr ""
+
+msgid "FeatureFlags|Delete %{name}?"
+msgstr ""
+
+msgid "FeatureFlags|Delete feature flag"
+msgstr ""
+
+msgid "FeatureFlags|Description"
+msgstr ""
+
+msgid "FeatureFlags|Edit Feature flag"
+msgstr ""
+
+msgid "FeatureFlags|Edit User List"
+msgstr ""
+
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
+msgstr ""
+
+msgid "FeatureFlags|Environment Specs"
+msgstr ""
+
+msgid "FeatureFlags|Feature Flag behavior is built up by creating a set of rules to define the status of target environments. A default wildcard rule %{codeStart}*%{codeEnd} for %{boldStart}All Environments%{boldEnd} is set, and you are able to add as many rules as you need by choosing environment specs below. You can toggle the behavior for each of your rules to set them %{boldStart}Active%{boldEnd} or %{boldStart}Inactive%{boldEnd}."
+msgstr ""
+
+msgid "FeatureFlags|Feature Flag has no strategies"
+msgstr ""
+
+msgid "FeatureFlags|Feature flag"
+msgstr ""
+
+msgid "FeatureFlags|Feature flag %{name} will be removed. Are you sure?"
+msgstr ""
+
+msgid "FeatureFlags|Feature flag User Lists"
+msgstr ""
+
+msgid "FeatureFlags|Feature flag user list details"
+msgstr ""
+
+msgid "FeatureFlags|Feature flags"
+msgstr ""
+
+msgid "FeatureFlags|Feature flags allow you to configure your code into different flavors by dynamically toggling certain functionality."
+msgstr ""
+
+msgid "FeatureFlags|Feature flags limit reached (%{featureFlagsLimit}). Delete one or more feature flags before adding new ones."
+msgstr ""
+
+msgid "FeatureFlags|Get started with feature flags"
+msgstr ""
+
+msgid "FeatureFlags|ID"
+msgstr ""
+
+msgid "FeatureFlags|Inactive"
+msgstr ""
+
+msgid "FeatureFlags|Inactive flag for %{scope}"
+msgstr ""
+
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
+msgstr ""
+
+msgid "FeatureFlags|Instance ID"
+msgstr ""
+
+msgid "FeatureFlags|List details"
+msgstr ""
+
+msgid "FeatureFlags|Loading feature flags"
+msgstr ""
+
+msgid "FeatureFlags|More information"
+msgstr ""
+
+msgid "FeatureFlags|Name"
+msgstr ""
+
+msgid "FeatureFlags|New"
+msgstr ""
+
+msgid "FeatureFlags|New User List"
+msgstr ""
+
+msgid "FeatureFlags|New feature flag"
+msgstr ""
+
+msgid "FeatureFlags|No user list selected"
+msgstr ""
+
+msgid "FeatureFlags|Percent of users"
+msgstr ""
+
+msgid "FeatureFlags|Percent rollout"
+msgstr ""
+
+msgid "FeatureFlags|Percent rollout must be an integer number between 0 and 100"
+msgstr ""
+
+msgid "FeatureFlags|Remove"
+msgstr ""
+
+msgid "FeatureFlags|Search code references"
+msgstr ""
+
+msgid "FeatureFlags|Set the Unleash client application name to the name of the environment your application runs in. This value is used to match environment scopes. See the %{linkStart}example client configuration%{linkEnd}."
+msgstr ""
+
+msgid "FeatureFlags|Status"
+msgstr ""
+
+msgid "FeatureFlags|Strategies"
+msgstr ""
+
+msgid "FeatureFlags|There was an error fetching the feature flags."
+msgstr ""
+
+msgid "FeatureFlags|To prevent accidental actions we ask you to confirm your intention. Please type %{projectName} to proceed or close this modal to cancel."
+msgstr ""
+
+msgid "FeatureFlags|Try again in a few moments or contact your support team."
+msgstr ""
+
+msgid "FeatureFlags|User IDs"
+msgstr ""
+
+msgid "FeatureFlags|User List"
+msgstr ""
+
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
+msgid "FeatureFlags|View user lists"
+msgstr ""
+
+msgid "FeatureFlag|Percentage"
+msgstr ""
+
+msgid "FeatureFlag|Select a user list"
+msgstr ""
+
+msgid "FeatureFlag|Select the environment scope for this feature flag"
+msgstr ""
+
+msgid "FeatureFlag|There are no configured user lists"
+msgstr ""
+
+msgid "FeatureFlag|Type"
+msgstr ""
+
+msgid "FeatureFlag|User IDs"
+msgstr ""
+
+msgid "FeatureFlag|User List"
+msgstr ""
+
+msgid "Feb"
+msgstr ""
+
+msgid "February"
+msgstr ""
+
+msgid "Fetch and check out this merge request's feature branch:"
+msgstr ""
+
+msgid "Fetching incoming email"
+msgstr ""
+
+msgid "File"
+msgstr ""
+
+msgid "File %{current} of %{total}"
+msgstr ""
+
+msgid "File Hooks"
+msgstr ""
+
+msgid "File Tree"
+msgstr ""
+
+msgid "File added"
+msgstr ""
+
+msgid "File browser"
+msgstr ""
+
+msgid "File deleted"
+msgstr ""
+
+msgid "File hooks are similar to system hooks but are executed as files instead of sending data to a URL."
+msgstr ""
+
+msgid "File is too big (%{fileSize}MiB). Max filesize: %{maxFileSize}MiB."
+msgstr ""
+
+msgid "File mode changed from %{a_mode} to %{b_mode}"
+msgstr ""
+
+msgid "File moved"
+msgstr ""
+
+msgid "File name"
+msgstr ""
+
+msgid "File permissions"
+msgstr ""
+
+msgid "File renamed with no changes."
+msgstr ""
+
+msgid "File suppressed by a .gitattributes entry or the file's encoding is unsupported."
+msgstr ""
+
+msgid "File templates"
+msgstr ""
+
+msgid "File too large. Secure Files must be less than %{limit} MB."
+msgstr ""
+
+msgid "File upload error."
+msgstr ""
+
+msgid "Filename"
+msgstr ""
+
+msgid "Files"
+msgstr ""
+
+msgid "Files API Rate Limits"
+msgstr ""
+
+msgid "Files breadcrumb"
+msgstr ""
+
+msgid "Files with large changes are collapsed by default."
+msgstr ""
+
+msgid "Files, directories, and submodules in the path %{path} for commit reference %{ref}"
+msgstr ""
+
+msgid "Fill in merge request template"
+msgstr ""
+
+msgid "Fill in the fields below, turn on %{strong_open}Enable SAML authentication for this group%{strong_close}, and press %{strong_open}Save changes%{strong_close}"
+msgstr ""
+
+msgid "Filter"
+msgstr ""
+
+msgid "Filter activity"
+msgstr ""
+
+msgid "Filter by"
+msgstr ""
+
+msgid "Filter by %{page_context_word} that are currently open."
+msgstr ""
+
+msgid "Filter by issues that are currently closed."
+msgstr ""
+
+msgid "Filter by issues that are currently opened."
+msgstr ""
+
+msgid "Filter by label"
+msgstr ""
+
+msgid "Filter by merge requests that are currently closed and unmerged."
+msgstr ""
+
+msgid "Filter by merge requests that are currently merged."
+msgstr ""
+
+msgid "Filter by milestone name"
+msgstr ""
+
+msgid "Filter by name"
+msgstr ""
+
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently open."
+msgstr ""
+
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
+msgid "Filter pipelines"
+msgstr ""
+
+msgid "Filter reports"
+msgstr ""
+
+msgid "Filter results"
+msgstr ""
+
+msgid "Filter results by group"
+msgstr ""
+
+msgid "Filter results by project"
+msgstr ""
+
+msgid "Filter results..."
+msgstr ""
+
+msgid "Filter users"
+msgstr ""
+
+msgid "Finalizing"
+msgstr ""
+
+msgid "Find File"
+msgstr ""
+
+msgid "Find bugs in your code with API fuzzing."
+msgstr ""
+
+msgid "Find bugs in your code with coverage-guided fuzzing."
+msgstr ""
+
+msgid "Find by path"
+msgstr ""
+
+msgid "Find file"
+msgstr ""
+
+msgid "FindFile|Switch branch/tag"
+msgstr ""
+
+msgid "FindingsDrawer|Category:"
+msgstr ""
+
+msgid "FindingsDrawer|Engine:"
+msgstr ""
+
+msgid "FindingsDrawer|Other locations:"
+msgstr ""
+
+msgid "FindingsDrawer|Severity:"
+msgstr ""
+
+msgid "Fingerprint (MD5)"
+msgstr ""
+
+msgid "Fingerprint (SHA256)"
+msgstr ""
+
+msgid "Fingerprints"
+msgstr ""
+
+msgid "Finish editing this message first!"
+msgstr ""
+
+msgid "Finish review"
+msgstr ""
+
+msgid "Finish setting up your dedicated account for %{group_name}."
+msgstr ""
+
+msgid "Finished"
+msgstr ""
+
+msgid "First Name"
+msgstr ""
+
+msgid "First Seen"
+msgstr ""
+
+msgid "First day of the week"
+msgstr ""
+
+msgid "First name"
+msgstr ""
+
+msgid "First seen"
+msgstr ""
+
+msgid "Fixed"
+msgstr ""
+
+msgid "Fixed burndown chart"
+msgstr ""
+
+msgid "Fixed:"
+msgstr ""
+
+msgid "Flags"
+msgstr ""
+
+msgid "FloC|Configure whether you want to participate in FLoC. %{floc_link_start}What is FLoC?%{floc_link_end}"
+msgstr ""
+
+msgid "FloC|Federated Learning of Cohorts (FLoC)"
+msgstr ""
+
+msgid "FloC|Participate in FLoC"
+msgstr ""
+
+msgid "Focus filter bar"
+msgstr ""
+
+msgid "FogBugz Email"
+msgstr ""
+
+msgid "FogBugz Import"
+msgstr ""
+
+msgid "FogBugz Password"
+msgstr ""
+
+msgid "FogBugz URL"
+msgstr ""
+
+msgid "FogBugz import"
+msgstr ""
+
+msgid "Fogbugz|Fogbugz import failed due to an error: %{error}"
+msgstr ""
+
+msgid "Fogbugz|Project %{repo} could not be found"
+msgstr ""
+
+msgid "Folder/%{name}"
+msgstr ""
+
+msgid "Follow"
+msgstr ""
+
+msgid "Followed Users' Activity"
+msgstr ""
+
+msgid "Followed users"
+msgstr ""
+
+msgid "Following tags don't exist"
+msgstr ""
+
+msgid "Font Color"
+msgstr ""
+
+msgid "Footer message"
+msgstr ""
+
+msgid "For %{link_to_pipeline_ref}"
+msgstr ""
+
+msgid "For %{ref}"
+msgstr ""
+
+msgid "For a faster browsing experience, only %{strongStart}%{visible} of %{total}%{strongEnd} files are shown. Download one of the files below to see all changes."
+msgstr ""
+
+msgid "For a faster browsing experience, only %{strong_open}%{display_size} of %{real_size}%{strong_close} files are shown. Download one of the files below to see all changes."
+msgstr ""
+
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
+msgid "For additional information, review your %{link_to} or contact your %{project_or_group} owner."
+msgstr ""
+
+msgid "For additional information, review your %{link_to} or contact your group owner."
+msgstr ""
+
+msgid "For additional information, review your %{project_or_group} membership: %{url} or contact your %{project_or_group} owner."
+msgstr ""
+
+msgid "For additional information, review your group membership: %{link_to} or contact your group owner."
+msgstr ""
+
+msgid "For each job, clone the repository."
+msgstr ""
+
+msgid "For each job, re-use the project workspace. If the workspace doesn't exist, use %{code_open}git clone%{code_close}."
+msgstr ""
+
+msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
+msgstr ""
+
+msgid "For general work"
+msgstr ""
+
+msgid "For individual use, create a separate account under your personal email address, not tied to the Enterprise email domain or group."
+msgstr ""
+
+msgid "For individual use, create a separate account under your personal email address, not tied to the Enterprise email domain."
+msgstr ""
+
+msgid "For investigating IT service disruptions or outages"
+msgstr ""
+
+msgid "For more info, read the documentation."
+msgstr ""
+
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
+msgid "For more information, go to the "
+msgstr ""
+
+msgid "For more information, see the File Hooks documentation."
+msgstr ""
+
+msgid "For the GitLab Team to keep your subscription data up to date, this is a reminder to report your license usage on a monthly basis, or at the cadence set in your agreement with GitLab. This allows us to simplify the billing process for overages and renewals. To report your usage data, export your license usage file and email it to %{renewal_service_email}. If you need an updated license, GitLab will send the license to the email address registered in the %{customers_dot}, and you can upload this license to your instance."
+msgstr ""
+
+msgid "For the next few releases, you can go to your avatar at any time to turn the new navigation on and off."
+msgstr ""
+
+msgid "Forbidden"
+msgstr ""
+
+msgid "Forecast horizon must be positive and %{max_horizon} days at the most."
+msgstr ""
+
+msgid "Forgot your password?"
+msgstr ""
+
+msgid "Fork"
+msgstr ""
+
+msgid "Fork Error!"
+msgstr ""
+
+msgid "Fork project"
+msgstr ""
+
+msgid "Fork project?"
+msgstr ""
+
+msgid "ForkProject|A fork is a copy of a project."
+msgstr ""
+
+msgid "ForkProject|An error occurred while forking the project. Please try again."
+msgstr ""
+
+msgid "ForkProject|Cancel"
+msgstr ""
+
+msgid "ForkProject|Create a group"
+msgstr ""
+
+msgid "ForkProject|Fork project"
+msgstr ""
+
+msgid "ForkProject|Forking a repository allows you to make changes without affecting the original project."
+msgstr ""
+
+msgid "ForkProject|Internal"
+msgstr ""
+
+msgid "ForkProject|Please select a namespace"
+msgstr ""
+
+msgid "ForkProject|Please select a visibility level"
+msgstr ""
+
+msgid "ForkProject|Private"
+msgstr ""
+
+msgid "ForkProject|Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group."
+msgstr ""
+
+msgid "ForkProject|Public"
+msgstr ""
+
+msgid "ForkProject|Select a namespace"
+msgstr ""
+
+msgid "ForkProject|Something went wrong while loading data. Please refresh the page to try again."
+msgstr ""
+
+msgid "ForkProject|The project can be accessed by any logged in user."
+msgstr ""
+
+msgid "ForkProject|The project can be accessed without any authentication."
+msgstr ""
+
+msgid "ForkProject|Visibility level"
+msgstr ""
+
+msgid "ForkProject|Want to organize several dependent projects under the same namespace?"
+msgstr ""
+
+msgid "ForkSuggestion|Cancel"
+msgstr ""
+
+msgid "ForkSuggestion|Fork"
+msgstr ""
+
+msgid "ForkSuggestion|You can’t %{edit_start}edit%{edit_end} files directly in this project. Fork this project and submit a merge request with your changes."
+msgstr ""
+
+msgid "ForkedFromProjectPath|Forked from"
+msgstr ""
+
+msgid "ForkedFromProjectPath|Forked from an inaccessible project."
+msgstr ""
+
+msgid "Forking in progress"
+msgstr ""
+
+msgid "Forks"
+msgstr ""
+
+msgid "ForksDivergence|%{aheadLinkStart}%{ahead} %{commit_word} ahead%{aheadLinkEnd} of"
+msgstr ""
+
+msgid "ForksDivergence|%{behindLinkStart}%{behind} %{commit_word} behind%{behindLinkEnd}"
+msgstr ""
+
+msgid "ForksDivergence|%{messages} the upstream repository."
+msgstr ""
+
+msgid "ForksDivergence|Check out to a branch, and merge the changes from the upstream project's default branch. You likely need to resolve conflicts during this step."
+msgstr ""
+
+msgid "ForksDivergence|Create merge request"
+msgstr ""
+
+msgid "ForksDivergence|Failed to fetch fork details. Try again later."
+msgstr ""
+
+msgid "ForksDivergence|Fetch the latest changes from the upstream repository's default branch:"
+msgstr ""
+
+msgid "ForksDivergence|Push the updates to remote:"
+msgstr ""
+
+msgid "ForksDivergence|Resolve merge conflicts manually"
+msgstr ""
+
+msgid "ForksDivergence|Source project has a limited visibility."
+msgstr ""
+
+msgid "ForksDivergence|Successfully fetched and merged from the upstream repository."
+msgstr ""
+
+msgid "ForksDivergence|The upstream changes could not be synchronized to this project due to file conflicts in the default branch. You must resolve the conflicts manually:"
+msgstr ""
+
+msgid "ForksDivergence|This fork has diverged from the upstream repository."
+msgstr ""
+
+msgid "ForksDivergence|Up to date with the upstream repository."
+msgstr ""
+
+msgid "ForksDivergence|Update fork"
+msgstr ""
+
+msgid "ForksDivergence|View merge request"
+msgstr ""
+
+msgid "Format: %{dateFormat}"
+msgstr ""
+
+msgid "Framework successfully deleted"
+msgstr ""
+
+msgid "Frameworks can not be added to projects in personal namespaces. %{linkStart}What are personal namespaces?%{linkEnd}"
+msgstr ""
+
+msgid "Free Trial of GitLab.com Ultimate"
+msgstr ""
+
+msgid "Free groups are limited to %{free_user_limit} member and the remaining members will get a status of over-limit and lose access to the group."
+msgid_plural "Free groups are limited to %{free_user_limit} members and the remaining members will get a status of over-limit and lose access to the group."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Free top-level groups will soon be limited to %{free_users_limit} users and %{free_storage_limit} of data"
+msgstr ""
+
+msgid "Free trial will expire in %{days}"
+msgstr ""
+
+msgid "Freeze end"
+msgstr ""
+
+msgid "Freeze start"
+msgstr ""
+
+msgid "Frequency"
+msgstr ""
+
+msgid "Frequently searched"
+msgstr ""
+
+msgid "Fri"
+msgstr ""
+
+msgid "Friday"
+msgstr ""
+
+msgid "From"
+msgstr ""
+
+msgid "From %{code_open}%{source_title}%{code_close} into"
+msgstr ""
+
+msgid "From %{providerTitle}"
+msgstr ""
+
+msgid "From issue creation until deploy to production"
+msgstr ""
+
+msgid "From line %{line1} to %{line2}"
+msgstr ""
+
+msgid "From merge request merge until deploy to production"
+msgstr ""
+
+msgid "Full"
+msgstr ""
+
+msgid "Full log"
+msgstr ""
+
+msgid "Full name"
+msgstr ""
+
+msgid "GCP region configured"
+msgstr ""
+
+msgid "GPG Key ID:"
+msgstr ""
+
+msgid "GPG Keys"
+msgstr ""
+
+msgid "GPG key mismatch"
+msgstr ""
+
+msgid "GPG keys allow you to verify signed commits."
+msgstr ""
+
+msgid "GPG signature (loading...)"
+msgstr ""
+
+msgid "General"
+msgstr ""
+
+msgid "General Settings"
+msgstr ""
+
+msgid "General pipelines"
+msgstr ""
+
+msgid "General settings"
+msgstr ""
+
+msgid "Generate API key at %{site}"
+msgstr ""
+
+msgid "Generate a default set of labels"
+msgstr ""
+
+msgid "Generate group access tokens scoped to this group for your applications that need access to the GitLab API."
+msgstr ""
+
+msgid "Generate new export"
+msgstr ""
+
+msgid "Generate project access tokens scoped to this project for your applications that need access to the GitLab API."
+msgstr ""
+
+msgid "Generate root cause analysis"
+msgstr ""
+
+msgid "Generate site and private keys at"
+msgstr ""
+
+msgid "Generated with JSON data"
+msgstr ""
+
+msgid "Generic"
+msgstr ""
+
+msgid "Generic package file size in bytes"
+msgstr ""
+
+msgid "GenericReport|After"
+msgstr ""
+
+msgid "GenericReport|Before"
+msgstr ""
+
+msgid "GenericReport|Diff"
+msgstr ""
+
+msgid "Geo"
+msgstr ""
+
+msgid "Geo Replication"
+msgstr ""
+
+msgid "Geo Replication - %{node_name}"
+msgstr ""
+
+msgid "Geo Settings"
+msgstr ""
+
+msgid "Geo Sites"
+msgstr ""
+
+msgid "Geo sites"
+msgstr ""
+
+msgid "Geo|%d group selected"
+msgid_plural "Geo|%d groups selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Geo|%d shard selected"
+msgid_plural "Geo|%d shards selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Geo|%{boldStart}Not applicable%{boldEnd}: Geo does not verify this component yet. See the %{linkStart}data types we plan to support%{linkEnd}."
+msgstr ""
+
+msgid "Geo|%{component} synced"
+msgstr ""
+
+msgid "Geo|%{component} verified"
+msgstr ""
+
+msgid "Geo|%{label} %{timeAgo}"
+msgstr ""
+
+msgid "Geo|%{label} can't be blank"
+msgstr ""
+
+msgid "Geo|%{label} should be between 1-999"
+msgstr ""
+
+msgid "Geo|%{name} is scheduled for re-sync"
+msgstr ""
+
+msgid "Geo|%{name} is scheduled for re-verify"
+msgstr ""
+
+msgid "Geo|%{timeAgoStr} (%{pendingEvents} events)"
+msgstr ""
+
+msgid "Geo|%{title} checksum progress"
+msgstr ""
+
+msgid "Geo|Add New Site"
+msgstr ""
+
+msgid "Geo|Add site"
+msgstr ""
+
+msgid "Geo|All"
+msgstr ""
+
+msgid "Geo|All %{replicable_name}"
+msgstr ""
+
+msgid "Geo|All projects"
+msgstr ""
+
+msgid "Geo|All projects are being scheduled for resync"
+msgstr ""
+
+msgid "Geo|All projects are being scheduled for reverify"
+msgstr ""
+
+msgid "Geo|Allow this secondary site to replicate content on Object Storage"
+msgstr ""
+
+msgid "Geo|Allowed Geo IP"
+msgstr ""
+
+msgid "Geo|Allowed Geo IP can't be blank"
+msgstr ""
+
+msgid "Geo|Allowed Geo IP should be between 1 and 255 characters"
+msgstr ""
+
+msgid "Geo|Allowed Geo IP should contain valid IP addresses"
+msgstr ""
+
+msgid "Geo|Checksummed"
+msgstr ""
+
+msgid "Geo|Choose specific groups or storage shards"
+msgstr ""
+
+msgid "Geo|Comma-separated, e.g. '1.1.1.1, 2.2.2.0/24'"
+msgstr ""
+
+msgid "Geo|Configure various settings for your %{siteType} site. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "Geo|Connection timeout"
+msgstr ""
+
+msgid "Geo|Connection timeout can't be blank"
+msgstr ""
+
+msgid "Geo|Connection timeout must be a number"
+msgstr ""
+
+msgid "Geo|Connection timeout should be between 1-120"
+msgstr ""
+
+msgid "Geo|Consult Geo troubleshooting information"
+msgstr ""
+
+msgid "Geo|Container repositories synchronization concurrency limit"
+msgstr ""
+
+msgid "Geo|Could not remove tracking entry for an existing project."
+msgstr ""
+
+msgid "Geo|Data replication lag"
+msgstr ""
+
+msgid "Geo|Data type"
+msgstr ""
+
+msgid "Geo|Disabled"
+msgstr ""
+
+msgid "Geo|Discover GitLab Geo"
+msgstr ""
+
+msgid "Geo|Does not match the primary storage configuration"
+msgstr ""
+
+msgid "Geo|Edit %{siteType} site"
+msgstr ""
+
+msgid "Geo|Edit Geo Site"
+msgstr ""
+
+msgid "Geo|Edit your search and try again."
+msgstr ""
+
+msgid "Geo|Errors:"
+msgstr ""
+
+msgid "Geo|External URL"
+msgstr ""
+
+msgid "Geo|Failed"
+msgstr ""
+
+msgid "Geo|File synchronization concurrency limit"
+msgstr ""
+
+msgid "Geo|Filter Geo sites"
+msgstr ""
+
+msgid "Geo|Filter by name"
+msgstr ""
+
+msgid "Geo|Filter by status"
+msgstr ""
+
+msgid "Geo|Geo Settings"
+msgstr ""
+
+msgid "Geo|Geo Status"
+msgstr ""
+
+msgid "Geo|Geo allows you to choose specific groups or storage shards to replicate."
+msgstr ""
+
+msgid "Geo|Geo can replicate objects stored in Object Storage (AWS S3, or other compatible object storage)."
+msgstr ""
+
+msgid "Geo|Geo sites"
+msgstr ""
+
+msgid "Geo|Geo sites are paused using a command run on the site"
+msgstr ""
+
+msgid "Geo|Go to the primary site"
+msgstr ""
+
+msgid "Geo|Groups to synchronize"
+msgstr ""
+
+msgid "Geo|Healthy"
+msgstr ""
+
+msgid "Geo|If enabled, GitLab will handle Object Storage replication using Geo."
+msgstr ""
+
+msgid "Geo|If you want to make changes, you must visit the primary site."
+msgstr ""
+
+msgid "Geo|In progress"
+msgstr ""
+
+msgid "Geo|Internal URL"
+msgstr ""
+
+msgid "Geo|Internal URL (optional)"
+msgstr ""
+
+msgid "Geo|Last event ID"
+msgstr ""
+
+msgid "Geo|Last event ID from primary"
+msgstr ""
+
+msgid "Geo|Last event ID processed"
+msgstr ""
+
+msgid "Geo|Last repository check run"
+msgstr ""
+
+msgid "Geo|Last successful sync"
+msgstr ""
+
+msgid "Geo|Last sync attempt"
+msgstr ""
+
+msgid "Geo|Last time verified"
+msgstr ""
+
+msgid "Geo|Learn more about Geo"
+msgstr ""
+
+msgid "Geo|Learn more about Geo site statuses"
+msgstr ""
+
+msgid "Geo|Limit the number of concurrent operations this secondary site can run in the background."
+msgstr ""
+
+msgid "Geo|Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
+msgstr ""
+
+msgid "Geo|Minimum interval in days"
+msgstr ""
+
+msgid "Geo|Must match with the %{codeStart}external_url%{codeEnd} in %{codeStart}/etc/gitlab/gitlab.rb%{codeEnd}."
+msgstr ""
+
+msgid "Geo|Must match with the %{codeStart}geo_node_name%{codeEnd} in %{codeStart}/etc/gitlab/gitlab.rb%{codeEnd}."
+msgstr ""
+
+msgid "Geo|Never"
+msgstr ""
+
+msgid "Geo|Next sync scheduled at"
+msgstr ""
+
+msgid "Geo|No %{replicable_type} were found. If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
+msgstr ""
+
+msgid "Geo|No %{replicable} were found. If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
+msgstr ""
+
+msgid "Geo|No Geo site found"
+msgstr ""
+
+msgid "Geo|No available replication slots"
+msgstr ""
+
+msgid "Geo|Nothing found…"
+msgstr ""
+
+msgid "Geo|Nothing to checksum"
+msgstr ""
+
+msgid "Geo|Nothing to synchronize"
+msgstr ""
+
+msgid "Geo|Nothing to verify"
+msgstr ""
+
+msgid "Geo|Object Storage replication"
+msgstr ""
+
+msgid "Geo|Offline"
+msgstr ""
+
+msgid "Geo|Pending synchronization"
+msgstr ""
+
+msgid "Geo|Pending verification"
+msgstr ""
+
+msgid "Geo|Primary"
+msgstr ""
+
+msgid "Geo|Primary site"
+msgstr ""
+
+msgid "Geo|Project (ID: %{project_id}) no longer exists on the primary. It is safe to remove this entry, as this will not remove any data on disk."
+msgstr ""
+
+msgid "Geo|Projects in certain groups"
+msgstr ""
+
+msgid "Geo|Projects in certain storage shards"
+msgstr ""
+
+msgid "Geo|Queued"
+msgstr ""
+
+msgid "Geo|Re-verification interval"
+msgstr ""
+
+msgid "Geo|Remove"
+msgstr ""
+
+msgid "Geo|Remove %{siteType} site"
+msgstr ""
+
+msgid "Geo|Remove entry"
+msgstr ""
+
+msgid "Geo|Remove site"
+msgstr ""
+
+msgid "Geo|Remove tracking database entry"
+msgstr ""
+
+msgid "Geo|Removing a Geo site stops the synchronization to and from that site. Are you sure?"
+msgstr ""
+
+msgid "Geo|Replicated data is verified with the secondary site(s) using checksums"
+msgstr ""
+
+msgid "Geo|Replicated data is verified with the secondary site(s) using checksums."
+msgstr ""
+
+msgid "Geo|Replication Details"
+msgstr ""
+
+msgid "Geo|Replication slot WAL"
+msgstr ""
+
+msgid "Geo|Replication slots"
+msgstr ""
+
+msgid "Geo|Replication status"
+msgstr ""
+
+msgid "Geo|Replication summary"
+msgstr ""
+
+msgid "Geo|Repository synchronization concurrency limit"
+msgstr ""
+
+msgid "Geo|Resync"
+msgstr ""
+
+msgid "Geo|Resync all"
+msgstr ""
+
+msgid "Geo|Resync all %{projects_count} projects"
+msgstr ""
+
+msgid "Geo|Resync all %{total}%{replicableType}"
+msgstr ""
+
+msgid "Geo|Resync project"
+msgstr ""
+
+msgid "Geo|Retry count"
+msgstr ""
+
+msgid "Geo|Reverify"
+msgstr ""
+
+msgid "Geo|Reverify all"
+msgstr ""
+
+msgid "Geo|Reverify all %{projects_count} projects"
+msgstr ""
+
+msgid "Geo|Reverify project"
+msgstr ""
+
+msgid "Geo|Review replication status, and resynchronize and reverify items with the primary site."
+msgstr ""
+
+msgid "Geo|Secondary"
+msgstr ""
+
+msgid "Geo|Secondary site"
+msgstr ""
+
+msgid "Geo|Select groups to replicate"
+msgstr ""
+
+msgid "Geo|Select shards to replicate"
+msgstr ""
+
+msgid "Geo|Selective (%{syncLabel})"
+msgstr ""
+
+msgid "Geo|Selective synchronization"
+msgstr ""
+
+msgid "Geo|Set the timeout in seconds to send a secondary site status to the primary and IPs allowed for the secondary sites."
+msgstr ""
+
+msgid "Geo|Set verification limit and frequency."
+msgstr ""
+
+msgid "Geo|Set what should be replicated by this secondary site."
+msgstr ""
+
+msgid "Geo|Shards to synchronize"
+msgstr ""
+
+msgid "Geo|Show more"
+msgstr ""
+
+msgid "Geo|Site name can't be blank"
+msgstr ""
+
+msgid "Geo|Site name should be between 1 and 255 characters"
+msgstr ""
+
+msgid "Geo|Site's status was updated %{timeAgo}."
+msgstr ""
+
+msgid "Geo|Status"
+msgstr ""
+
+msgid "Geo|Storage config"
+msgstr ""
+
+msgid "Geo|Synced"
+msgstr ""
+
+msgid "Geo|Synchronization"
+msgstr ""
+
+msgid "Geo|Synchronization failed - %{error}"
+msgstr ""
+
+msgid "Geo|Synchronization settings"
+msgstr ""
+
+msgid "Geo|Synchronization status"
+msgstr ""
+
+msgid "Geo|The URL of the primary site that is used internally by the secondary sites."
+msgstr ""
+
+msgid "Geo|The URL of the secondary site that is used internally by the primary site."
+msgstr ""
+
+msgid "Geo|The database is currently %{db_lag} behind the primary site."
+msgstr ""
+
+msgid "Geo|The site is currently %{minutes_behind} behind the primary site."
+msgstr ""
+
+msgid "Geo|There are no %{replicable_type} to show"
+msgstr ""
+
+msgid "Geo|There are no %{replicable} to show"
+msgstr ""
+
+msgid "Geo|There was an error deleting the Geo Site"
+msgstr ""
+
+msgid "Geo|There was an error fetching the Geo Settings"
+msgstr ""
+
+msgid "Geo|There was an error fetching the Geo Sites"
+msgstr ""
+
+msgid "Geo|There was an error fetching the Sites's Groups"
+msgstr ""
+
+msgid "Geo|There was an error saving this Geo Site"
+msgstr ""
+
+msgid "Geo|There was an error updating the Geo Settings"
+msgstr ""
+
+msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
+msgstr ""
+
+msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
+msgstr ""
+
+msgid "Geo|This will resync all projects. It may take some time to complete. Are you sure you want to continue?"
+msgstr ""
+
+msgid "Geo|This will reverify all projects. It may take some time to complete. Are you sure you want to continue?"
+msgstr ""
+
+msgid "Geo|Time in seconds"
+msgstr ""
+
+msgid "Geo|Tracking database entry will be removed. Are you sure?"
+msgstr ""
+
+msgid "Geo|Tracking entry for project (%{project_id}) was successfully removed."
+msgstr ""
+
+msgid "Geo|Tuning settings"
+msgstr ""
+
+msgid "Geo|URL can't be blank"
+msgstr ""
+
+msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
+msgstr ""
+
+msgid "Geo|Undefined"
+msgstr ""
+
+msgid "Geo|Unhealthy"
+msgstr ""
+
+msgid "Geo|Unknown"
+msgstr ""
+
+msgid "Geo|Updated %{timeAgo}"
+msgstr ""
+
+msgid "Geo|Verification"
+msgstr ""
+
+msgid "Geo|Verification concurrency limit"
+msgstr ""
+
+msgid "Geo|Verification failed - %{error}"
+msgstr ""
+
+msgid "Geo|Verification information"
+msgstr ""
+
+msgid "Geo|Verification status"
+msgstr ""
+
+msgid "Geo|Verified"
+msgstr ""
+
+msgid "Geo|Waiting for scheduler"
+msgstr ""
+
+msgid "Geo|With GitLab Geo, you can install a special read-only and replicated instance anywhere."
+msgstr ""
+
+msgid "Geo|You are on a secondary, %{b_open}read-only%{b_close} Geo site."
+msgstr ""
+
+msgid "Geo|You may be able to make a limited amount of changes or perform a limited amount of actions on this page."
+msgstr ""
+
+msgid "Geo|misconfigured"
+msgstr ""
+
+msgid "Geo|primary"
+msgstr ""
+
+msgid "Geo|secondary"
+msgstr ""
+
+msgid "Get a free instance review"
+msgstr ""
+
+msgid "Get a support subscription"
+msgstr ""
+
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
+msgid "Get started"
+msgstr ""
+
+msgid "Get started with GitLab"
+msgstr ""
+
+msgid "Get started with error tracking"
+msgstr ""
+
+msgid "Get started!"
+msgstr ""
+
+msgid "Git"
+msgstr ""
+
+msgid "Git LFS Rate Limits"
+msgstr ""
+
+msgid "Git LFS is not enabled on this GitLab server, contact your admin."
+msgstr ""
+
+msgid "Git LFS objects will be synced if LFS is %{docs_link_start}enabled for the project%{docs_link_end}. Push mirrors will %{strong_open}not%{strong_close} sync LFS objects over SSH."
+msgstr ""
+
+msgid "Git LFS status:"
+msgstr ""
+
+msgid "Git global setup"
+msgstr ""
+
+msgid "Git repository URL"
+msgstr ""
+
+msgid "Git revision"
+msgstr ""
+
+msgid "Git shallow clone"
+msgstr ""
+
+msgid "Git strategy"
+msgstr ""
+
+msgid "Git transfer in progress"
+msgstr ""
+
+msgid "Git version"
+msgstr ""
+
+msgid "GitAbuse|Automatically ban users from this %{scope} when they exceed the specified limits"
+msgstr ""
+
+msgid "GitAbuse|Excluded users"
+msgstr ""
+
+msgid "GitAbuse|Number of repositories"
+msgstr ""
+
+msgid "GitAbuse|Number of repositories can't be blank. Set to 0 for no limit."
+msgstr ""
+
+msgid "GitAbuse|Number of repositories must be a number."
+msgstr ""
+
+msgid "GitAbuse|Number of repositories should be between %{minNumRepos}-%{maxNumRepos}."
+msgstr ""
+
+msgid "GitAbuse|Reporting time period (seconds)"
+msgstr ""
+
+msgid "GitAbuse|Reporting time period can't be blank. Set to 0 for no limit."
+msgstr ""
+
+msgid "GitAbuse|Reporting time period must be a number."
+msgstr ""
+
+msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
+msgstr ""
+
+msgid "GitAbuse|Select between %{minAlertedUsers} and %{maxAlertedUsers} users to notify."
+msgstr ""
+
+msgid "GitAbuse|Send notifications to"
+msgstr ""
+
+msgid "GitAbuse|The maximum number of unique repositories a user can download in the specified time period before they're banned."
+msgstr ""
+
+msgid "GitAbuse|Users who are emailed when Git abuse rate limit is exceeded."
+msgstr ""
+
+msgid "GitAbuse|Users who are excluded from the Git abuse rate limit."
+msgstr ""
+
+msgid "GitAbuse|You cannot specify more than %{maxAllowedUsers} excluded users."
+msgstr ""
+
+msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
+msgstr ""
+
+msgid "GitHub import"
+msgstr ""
+
+msgid "GitHubImporter|*Merged by: %{author} at %{timestamp}*"
+msgstr ""
+
+msgid "GitLab"
+msgstr ""
+
+msgid "GitLab (self-managed)"
+msgstr ""
+
+msgid "GitLab / Unsubscribe"
+msgstr ""
+
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Account Request"
+msgstr ""
+
+msgid "GitLab Billing Team."
+msgstr ""
+
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
+msgid "GitLab Error Tracking"
+msgstr ""
+
+msgid "GitLab Import"
+msgstr ""
+
+msgid "GitLab KAS"
+msgstr ""
+
+msgid "GitLab Pages"
+msgstr ""
+
+msgid "GitLab Pages has moved"
+msgstr ""
+
+msgid "GitLab Shell"
+msgstr ""
+
+msgid "GitLab Support Bot"
+msgstr ""
+
+msgid "GitLab Ultimate trial"
+msgstr ""
+
+msgid "GitLab User"
+msgstr ""
+
+msgid "GitLab Workhorse"
+msgstr ""
+
+msgid "GitLab account request rejected"
+msgstr ""
+
+msgid "GitLab commit"
+msgstr ""
+
+msgid "GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code"
+msgstr ""
+
+msgid "GitLab detected an attempt to sign in to your %{host} account using an incorrect verification code from the following IP address: %{ip}, at %{time}"
+msgstr ""
+
+msgid "GitLab documentation"
+msgstr ""
+
+msgid "GitLab events trigger webhooks. Use the request details of a webhook to help troubleshoot problems. %{link_start}How do I troubleshoot?%{link_end}"
+msgstr ""
+
+msgid "GitLab export"
+msgstr ""
+
+msgid "GitLab for Jira Cloud"
+msgstr ""
+
+msgid "GitLab group: %{source_link}"
+msgstr ""
+
+msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
+msgstr ""
+
+msgid "GitLab is a complete DevOps platform, delivered as a single application, fundamentally changing the way Development, Security, and Ops teams collaborate"
+msgstr ""
+
+msgid "GitLab is a complete DevOps platform, delivered as a single application, fundamentally changing the way%{br_tag}Development, Security, and Ops teams collaborate"
+msgstr ""
+
+msgid "GitLab is a single application for the entire software development lifecycle. From project planning and source code management to CI/CD, monitoring, and security."
+msgstr ""
+
+msgid "GitLab is free to use. Many features for larger teams are part of our %{link_start}paid products%{link_end}. You can try Ultimate for free without any obligation or payment details."
+msgstr ""
+
+msgid "GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later."
+msgstr ""
+
+msgid "GitLab is open source software to collaborate on code."
+msgstr ""
+
+msgid "GitLab is undergoing maintenance"
+msgstr ""
+
+msgid "GitLab logo"
+msgstr ""
+
+msgid "GitLab metadata URL"
+msgstr ""
+
+msgid "GitLab project export"
+msgstr ""
+
+msgid "GitLab single sign-on URL"
+msgstr ""
+
+msgid "GitLab username"
+msgstr ""
+
+msgid "GitLab uses %{linkStart}Sidekiq%{linkEnd} to process background jobs"
+msgstr ""
+
+msgid "GitLab version"
+msgstr ""
+
+msgid "GitLab will create a branch in your fork and start a merge request."
+msgstr ""
+
+msgid "GitLab.com (SaaS)"
+msgstr ""
+
+msgid "GitLab.com import"
+msgstr ""
+
+msgid "GitLabPagesDomains|Retry"
+msgstr ""
+
+msgid "GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}."
+msgstr ""
+
+msgid "GitLabPages|Access Control is enabled for this Pages website; only authorized users will be able to access it. To make your website publicly available, navigate to your project's %{strong_start}Settings &gt; General &gt; Visibility%{strong_end} and select %{strong_start}Everyone%{strong_end} in pages section. Read the %{link_start}documentation%{link_end} for more information."
+msgstr ""
+
+msgid "GitLabPages|Access pages"
+msgstr ""
+
+msgid "GitLabPages|Are you sure?"
+msgstr ""
+
+msgid "GitLabPages|Can be overridden per project. For no limit, enter 0. To inherit the value, leave empty."
+msgstr ""
+
+msgid "GitLabPages|Certificate: %{subject}"
+msgstr ""
+
+msgid "GitLabPages|Check the Pipeline Status"
+msgstr ""
+
+msgid "GitLabPages|Configure pages"
+msgstr ""
+
+msgid "GitLabPages|Domains"
+msgstr ""
+
+msgid "GitLabPages|Edit"
+msgstr ""
+
+msgid "GitLabPages|Expired"
+msgstr ""
+
+msgid "GitLabPages|Force HTTPS (requires valid certificates)"
+msgstr ""
+
+msgid "GitLabPages|GitLab Pages are disabled for this project. You can enable them on your project's %{strong_start}Settings &gt; General &gt; Visibility%{strong_end} page."
+msgstr ""
+
+msgid "GitLabPages|Maximum size (MB)"
+msgstr ""
+
+msgid "GitLabPages|New Domain"
+msgstr ""
+
+msgid "GitLabPages|Only project maintainers can remove pages"
+msgstr ""
+
+msgid "GitLabPages|Pages"
+msgstr ""
+
+msgid "GitLabPages|Remove"
+msgstr ""
+
+msgid "GitLabPages|Remove certificate"
+msgstr ""
+
+msgid "GitLabPages|Remove domain"
+msgstr ""
+
+msgid "GitLabPages|Remove pages"
+msgstr ""
+
+msgid "GitLabPages|Removing pages will prevent them from being exposed to the outside world."
+msgstr ""
+
+msgid "GitLabPages|Save changes"
+msgstr ""
+
+msgid "GitLabPages|Something went wrong while obtaining the Let's Encrypt certificate for %{domain}. To retry visit your %{link_start}domain details%{link_end}."
+msgstr ""
+
+msgid "GitLabPages|Start over"
+msgstr ""
+
+msgid "GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it."
+msgstr ""
+
+msgid "GitLabPages|Unverified"
+msgstr ""
+
+msgid "GitLabPages|Updating your Pages configuration..."
+msgstr ""
+
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
+msgid "GitLabPages|Use unique domain"
+msgstr ""
+
+msgid "GitLabPages|Verified"
+msgstr ""
+
+msgid "GitLabPages|Waiting for the Pages Pipeline to complete..."
+msgstr ""
+
+msgid "GitLabPages|When enabled, a unique domain is generated to access pages."
+msgstr ""
+
+msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
+msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "GitLabPages|With GitLab Pages you can host your static website directly from your GitLab repository. %{docs_link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "GitLabPages|Your Pages site is not configured yet. See the %{docs_link_start}GitLab Pages documentation%{link_end} to learn how to upload your static site and have GitLab serve it. You can also take some inspiration from the %{samples_link_start}sample Pages projects%{link_end}."
+msgstr ""
+
+msgid "GitLabPages|Your Project has been configured for Pages. Now we have to wait for the Pipeline to succeed for the first time."
+msgstr ""
+
+msgid "Gitaly Servers"
+msgstr ""
+
+msgid "Gitaly timeouts"
+msgstr ""
+
+msgid "Gitaly|Address"
+msgstr ""
+
+msgid "Gitea host URL"
+msgstr ""
+
+msgid "Gitea import"
+msgstr ""
+
+msgid "GithubImporter|%{noteable_type} comment %{note_id}"
+msgstr ""
+
+msgid "GithubImporter|Collaborators"
+msgstr ""
+
+msgid "GithubImporter|Gist with id %{gist_id} failed due to error: %{error}."
+msgstr ""
+
+msgid "GithubImporter|GitHub Gists import finished with errors"
+msgstr ""
+
+msgid "GithubImporter|GitHub gists that were not imported:"
+msgstr ""
+
+msgid "GithubImporter|GitHub gists with more than 10 files must be manually migrated."
+msgstr ""
+
+msgid "GithubImporter|Issue %{issue_iid} attachment"
+msgstr ""
+
+msgid "GithubImporter|Issue links"
+msgstr ""
+
+msgid "GithubImporter|Merge request %{merge_request_iid} attachment"
+msgstr ""
+
+msgid "GithubImporter|Merge request links"
+msgstr ""
+
+msgid "GithubImporter|Note attachment"
+msgstr ""
+
+msgid "GithubImporter|Note links"
+msgstr ""
+
+msgid "GithubImporter|PR mergers"
+msgstr ""
+
+msgid "GithubImporter|PR reviews"
+msgstr ""
+
+msgid "GithubImporter|Please follow %{import_snippets_link_start}Import GitHub gists into GitLab snippets%{import_snippets_link_end} for more details."
+msgstr ""
+
+msgid "GithubImporter|Please follow %{import_snippets_url} for more details."
+msgstr ""
+
+msgid "GithubImporter|Pull request %{pull_request_iid} merger"
+msgstr ""
+
+msgid "GithubImporter|Pull request %{pull_request_iid} review request"
+msgstr ""
+
+msgid "GithubImporter|Pull request review %{review_id}"
+msgstr ""
+
+msgid "GithubImporter|Pull request review comment %{note_id}"
+msgstr ""
+
+msgid "GithubImporter|Pull requests"
+msgstr ""
+
+msgid "GithubImporter|Release %{tag} attachment"
+msgstr ""
+
+msgid "GithubImporter|Release links"
+msgstr ""
+
+msgid "GithubImporter|Your import of GitHub gists into GitLab snippets is complete."
+msgstr ""
+
+msgid "GithubIntegration|Create a %{token_link_start}personal access token%{token_link_end} with %{status_html} access granted and paste it here."
+msgstr ""
+
+msgid "GithubIntegration|Enable static status check names"
+msgstr ""
+
+msgid "GithubIntegration|Obtain statuses for commits and pull requests."
+msgstr ""
+
+msgid "GithubIntegration|Repository URL"
+msgstr ""
+
+msgid "GithubIntegration|Select this if you want GitHub to mark status checks as \"Required\". %{learn_more_link_start}Learn more%{learn_more_link_end}."
+msgstr ""
+
+msgid "GithubIntegration|Static status check names (optional)"
+msgstr ""
+
+msgid "GithubIntegration|This requires mirroring your GitHub repository to this project. %{docs_link}"
+msgstr ""
+
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|The URL to your Gitpod instance configured to read your GitLab projects, such as https://gitpod.example.com."
+msgstr ""
+
+msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
+msgstr ""
+
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr ""
+
+msgid "Gitpod|https://gitpod.example.com"
+msgstr ""
+
+msgid "Give feedback"
+msgstr ""
+
+msgid "Give us some feedback"
+msgstr ""
+
+msgid "Given access %{time_ago}"
+msgstr ""
+
+msgid "Given epic is already related to this epic."
+msgstr ""
+
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
+msgid "Global SAML group membership lock"
+msgstr ""
+
+msgid "Global Search is disabled for this scope"
+msgstr ""
+
+msgid "Global Shortcuts"
+msgstr ""
+
+msgid "Global notification email"
+msgstr ""
+
+msgid "Global notification level"
+msgstr ""
+
+msgid "GlobalSearch| %{search} %{description} %{scope}"
+msgstr ""
+
+msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
+msgstr ""
+
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
+msgid "GlobalSearch|Aggregations load error."
+msgstr ""
+
+msgid "GlobalSearch|Archived"
+msgstr ""
+
+msgid "GlobalSearch|Close"
+msgstr ""
+
+msgid "GlobalSearch|Fetching aggregations error."
+msgstr ""
+
+msgid "GlobalSearch|Filters"
+msgstr ""
+
+msgid "GlobalSearch|Group"
+msgstr ""
+
+msgid "GlobalSearch|Groups"
+msgstr ""
+
+msgid "GlobalSearch|Help"
+msgstr ""
+
+msgid "GlobalSearch|In this project"
+msgstr ""
+
+msgid "GlobalSearch|Include archived"
+msgstr ""
+
+msgid "GlobalSearch|Issues I've created"
+msgstr ""
+
+msgid "GlobalSearch|Issues assigned to me"
+msgstr ""
+
+msgid "GlobalSearch|Labels"
+msgstr ""
+
+msgid "GlobalSearch|Language"
+msgstr ""
+
+msgid "GlobalSearch|Merge requests I've created"
+msgstr ""
+
+msgid "GlobalSearch|Merge requests assigned to me"
+msgstr ""
+
+msgid "GlobalSearch|Merge requests that I'm a reviewer"
+msgstr ""
+
+msgid "GlobalSearch|No labels found"
+msgstr ""
+
+msgid "GlobalSearch|Places"
+msgstr ""
+
+msgid "GlobalSearch|Project"
+msgstr ""
+
+msgid "GlobalSearch|Projects"
+msgstr ""
+
+msgid "GlobalSearch|Recent epics"
+msgstr ""
+
+msgid "GlobalSearch|Recent issues"
+msgstr ""
+
+msgid "GlobalSearch|Recent merge requests"
+msgstr ""
+
+msgid "GlobalSearch|Result count is over limit."
+msgstr ""
+
+msgid "GlobalSearch|Results updated. %{count} results available. Use the up and down arrow keys to navigate search results list, or ENTER to submit."
+msgstr ""
+
+msgid "GlobalSearch|Search"
+msgstr ""
+
+msgid "GlobalSearch|Search GitLab"
+msgstr ""
+
+msgid "GlobalSearch|Search for projects, issues, etc."
+msgstr ""
+
+msgid "GlobalSearch|Search labels"
+msgstr ""
+
+msgid "GlobalSearch|Search results are loading"
+msgstr ""
+
+msgid "GlobalSearch|Settings"
+msgstr ""
+
+msgid "GlobalSearch|Show more"
+msgstr ""
+
+msgid "GlobalSearch|Showing top %{maxItems}"
+msgstr ""
+
+msgid "GlobalSearch|Syntax options"
+msgstr ""
+
+msgid "GlobalSearch|The search term must be at least 3 characters long."
+msgstr ""
+
+msgid "GlobalSearch|There was an error fetching search autocomplete suggestions."
+msgstr ""
+
+msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
+msgstr ""
+
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
+msgid "GlobalSearch|Type and press the enter key to submit search."
+msgstr ""
+
+msgid "GlobalSearch|Type for new suggestions to appear below."
+msgstr ""
+
+msgid "GlobalSearch|Use the shortcut key %{kbdOpen}/%{kbdClose} to start a search"
+msgstr ""
+
+msgid "GlobalSearch|Users"
+msgstr ""
+
+msgid "GlobalSearch|What are you searching for?"
+msgstr ""
+
+msgid "GlobalSearch|all GitLab"
+msgstr ""
+
+msgid "GlobalSearch|in %{scope}"
+msgstr ""
+
+msgid "GlobalShortcuts|Copied reference to clipboard."
+msgstr ""
+
+msgid "GlobalShortcuts|Copied source branch name to clipboard."
+msgstr ""
+
+msgid "GlobalShortcuts|Unable to copy the reference at this time."
+msgstr ""
+
+msgid "GlobalShortcuts|Unable to copy the source branch name at this time."
+msgstr ""
+
+msgid "Globally-allowed IP ranges"
+msgstr ""
+
+msgid "Go Back"
+msgstr ""
+
+msgid "Go Micro is a framework for micro service development"
+msgstr ""
+
+msgid "Go back"
+msgstr ""
+
+msgid "Go back (while searching for files)"
+msgstr ""
+
+msgid "Go back to configuration"
+msgstr ""
+
+msgid "Go full screen"
+msgstr ""
+
+msgid "Go to %{source_name}"
+msgstr ""
+
+msgid "Go to commits"
+msgstr ""
+
+msgid "Go to definition"
+msgstr ""
+
+msgid "Go to environments"
+msgstr ""
+
+msgid "Go to epic"
+msgstr ""
+
+msgid "Go to file"
+msgstr ""
+
+msgid "Go to file permalink (while viewing a file)"
+msgstr ""
+
+msgid "Go to files"
+msgstr ""
+
+msgid "Go to find file"
+msgstr ""
+
+msgid "Go to issue boards"
+msgstr ""
+
+msgid "Go to issues"
+msgstr ""
+
+msgid "Go to jobs"
+msgstr ""
+
+msgid "Go to kubernetes"
+msgstr ""
+
+msgid "Go to merge requests"
+msgstr ""
+
+msgid "Go to next page"
+msgstr ""
+
+msgid "Go to next unresolved thread"
+msgstr ""
+
+msgid "Go to page %{page}"
+msgstr ""
+
+msgid "Go to parent"
+msgstr ""
+
+msgid "Go to parent directory"
+msgstr ""
+
+msgid "Go to pipelines"
+msgstr ""
+
+msgid "Go to previous page"
+msgstr ""
+
+msgid "Go to previous unresolved thread"
+msgstr ""
+
+msgid "Go to primary site"
+msgstr ""
+
+msgid "Go to project"
+msgstr ""
+
+msgid "Go to releases"
+msgstr ""
+
+msgid "Go to repository charts"
+msgstr ""
+
+msgid "Go to repository graph"
+msgstr ""
+
+msgid "Go to snippets"
+msgstr ""
+
+msgid "Go to the %{b_open}Activity%{b_close} page for %{project_link}."
+msgstr ""
+
+msgid "Go to the 'Admin area &gt; Sign-up restrictions', and check 'Allowed domains for sign-ups'."
+msgstr ""
+
+msgid "Go to the 'Admin area &gt; Sign-up restrictions', and check 'Email restrictions for sign-ups'."
+msgstr ""
+
+msgid "Go to the 'Admin area &gt; Sign-up restrictions', and check the 'Domain denylist'."
+msgstr ""
+
+msgid "Go to the activity feed"
+msgstr ""
+
+msgid "Go to the group’s 'Settings &gt; General' page, and check 'Restrict membership by email domain'."
+msgstr ""
+
+msgid "Go to the milestone list"
+msgstr ""
+
+msgid "Go to the project's activity feed"
+msgstr ""
+
+msgid "Go to the project's overview page"
+msgstr ""
+
+msgid "Go to wiki"
+msgstr ""
+
+msgid "Go to your To-Do list"
+msgstr ""
+
+msgid "Go to your fork"
+msgstr ""
+
+msgid "Go to your groups"
+msgstr ""
+
+msgid "Go to your issues"
+msgstr ""
+
+msgid "Go to your merge requests"
+msgstr ""
+
+msgid "Go to your projects"
+msgstr ""
+
+msgid "Go to your review requests"
+msgstr ""
+
+msgid "Go to your snippets"
+msgstr ""
+
+msgid "Google Cloud"
+msgstr ""
+
+msgid "Google Cloud Error - %{error}"
+msgstr ""
+
+msgid "Google Cloud Project"
+msgstr ""
+
+msgid "Google Cloud authorizations required"
+msgstr ""
+
+msgid "GoogleCloud|Cancel"
+msgstr ""
+
+msgid "GoogleCloud|Configured region is linked to the selected branch or tag"
+msgstr ""
+
+msgid "GoogleCloud|Create service account"
+msgstr ""
+
+msgid "GoogleCloud|Generated service account is linked to the selected branch or tag"
+msgstr ""
+
+msgid "GoogleCloud|Google Cloud project"
+msgstr ""
+
+msgid "GoogleCloud|Google OAuth2 token revocation request failed"
+msgstr ""
+
+msgid "GoogleCloud|Google OAuth2 token revocation requested"
+msgstr ""
+
+msgid "GoogleCloud|I understand the responsibilities involved with managing service account keys"
+msgstr ""
+
+msgid "GoogleCloud|New service account is generated for the selected Google Cloud project"
+msgstr ""
+
+msgid "GoogleCloud|Refs"
+msgstr ""
+
+msgid "GoogleCloud|Revoke authorizations"
+msgstr ""
+
+msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
+msgstr ""
+
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
+msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
+msgstr ""
+
+msgid "GooglePlay|Drag your key file to start the upload."
+msgstr ""
+
+msgid "GooglePlay|Error: The file you're trying to upload is not a service account key."
+msgstr ""
+
+msgid "GooglePlay|Google Play"
+msgstr ""
+
+msgid "GooglePlay|Leave empty to use your current service account key."
+msgstr ""
+
+msgid "GooglePlay|Service account key (.JSON)"
+msgstr ""
+
+msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
+msgstr ""
+
+msgid "GooglePlay|Use GitLab to build and release an app in Google Play."
+msgstr ""
+
+msgid "Got it"
+msgstr ""
+
+msgid "Got it!"
+msgstr ""
+
+msgid "Grafana URL"
+msgstr ""
+
+msgid "Grant access"
+msgstr ""
+
+msgid "Grant write permissions to this key"
+msgstr ""
+
+msgid "Graph"
+msgstr ""
+
+msgid "GraphQL"
+msgstr ""
+
+msgid "GraphQL endpoint path"
+msgstr ""
+
+msgid "GraphViewType|Job dependencies"
+msgstr ""
+
+msgid "GraphViewType|Show dependencies"
+msgstr ""
+
+msgid "GraphViewType|Stage"
+msgstr ""
+
+msgid "Gravatar"
+msgstr ""
+
+msgid "Gravatar enabled"
+msgstr ""
+
+msgid "Grid"
+msgstr ""
+
+msgid "Group"
+msgstr ""
+
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
+msgid "Group %{group_name} couldn't be exported."
+msgstr ""
+
+msgid "Group %{group_name} was exported successfully."
+msgstr ""
+
+msgid "Group %{group_name} was scheduled for deletion."
+msgstr ""
+
+msgid "Group %{group_name} was successfully created."
+msgstr ""
+
+msgid "Group '%{group_name}' could not be updated."
+msgstr ""
+
+msgid "Group '%{group_name}' was successfully updated."
+msgstr ""
+
+msgid "Group Access Tokens"
+msgstr ""
+
+msgid "Group Git LFS status:"
+msgstr ""
+
+msgid "Group Hooks"
+msgstr ""
+
+msgid "Group Owner must have signed in with SAML before enabling Group Managed Accounts"
+msgstr ""
+
+msgid "Group SAML must be enabled to test"
+msgstr ""
+
+msgid "Group URL"
+msgstr ""
+
+msgid "Group access token creation is disabled in this group."
+msgstr ""
+
+msgid "Group application: %{name}"
+msgstr ""
+
+msgid "Group applications"
+msgstr ""
+
+msgid "Group audit events"
+msgstr ""
+
+msgid "Group avatar"
+msgstr ""
+
+msgid "Group by"
+msgstr ""
+
+msgid "Group by:"
+msgstr ""
+
+msgid "Group description (optional)"
+msgstr ""
+
+msgid "Group export could not be started."
+msgstr ""
+
+msgid "Group export download requests"
+msgstr ""
+
+msgid "Group export error"
+msgstr ""
+
+msgid "Group export link has expired. Please generate a new export from your group settings."
+msgstr ""
+
+msgid "Group export requests"
+msgstr ""
+
+msgid "Group export started. A download link will be sent by email and made available on this page."
+msgstr ""
+
+msgid "Group has been already marked for deletion"
+msgstr ""
+
+msgid "Group has not been marked for deletion"
+msgstr ""
+
+msgid "Group import could not be scheduled"
+msgstr ""
+
+msgid "Group import requests"
+msgstr ""
+
+msgid "Group info:"
+msgstr ""
+
+msgid "Group information"
+msgstr ""
+
+msgid "Group jobs by"
+msgstr ""
+
+msgid "Group members"
+msgstr ""
+
+msgid "Group membership expiration date changed"
+msgstr ""
+
+msgid "Group membership expiration date removed"
+msgstr ""
+
+msgid "Group mention in private"
+msgstr ""
+
+msgid "Group mention in public"
+msgstr ""
+
+msgid "Group milestone"
+msgstr ""
+
+msgid "Group name (your organization)"
+msgstr ""
+
+msgid "Group navigation"
+msgstr ""
+
+msgid "Group overview content"
+msgstr ""
+
+msgid "Group path is already taken. We've suggested one that is available."
+msgstr ""
+
+msgid "Group path is available."
+msgstr ""
+
+msgid "Group pipeline minutes were successfully reset."
+msgstr ""
+
+msgid "Group project URLs are prefixed with the group namespace"
+msgstr ""
+
+msgid "Group requires separate account"
+msgstr ""
+
+msgid "Group runners"
+msgstr ""
+
+msgid "Group runners can be managed with the %{link}."
+msgstr ""
+
+msgid "Group variables (inherited)"
+msgstr ""
+
+msgid "Group was exported"
+msgstr ""
+
+msgid "Group was successfully updated."
+msgstr ""
+
+msgid "Group wikis"
+msgstr ""
+
+msgid "Group-level wiki is disabled."
+msgstr ""
+
+msgid "Group: %{group_name}"
+msgstr ""
+
+msgid "GroupActivityMetrics|Issues created"
+msgstr ""
+
+msgid "GroupActivityMetrics|Members added"
+msgstr ""
+
+msgid "GroupActivityMetrics|Merge requests created"
+msgstr ""
+
+msgid "GroupActivityMetrics|Recent activity"
+msgstr ""
+
+msgid "GroupImport|Failed to import group: %{error}"
+msgstr ""
+
+msgid "GroupImport|Group '%{group_name}' is being imported."
+msgstr ""
+
+msgid "GroupImport|Group could not be imported: %{errors}"
+msgstr ""
+
+msgid "GroupImport|Please wait while we import the group for you. Refresh at will."
+msgstr ""
+
+msgid "GroupImport|The group was successfully imported."
+msgstr ""
+
+msgid "GroupImport|Unable to process group import file"
+msgstr ""
+
+msgid "GroupPage|Copy group ID"
+msgstr ""
+
+msgid "GroupPage|Group ID: %{group_id}"
+msgstr ""
+
+msgid "GroupRoadmap|%{dateWord} – No end date"
+msgstr ""
+
+msgid "GroupRoadmap|%{startDateInWords} – %{endDateInWords}"
+msgstr ""
+
+msgid "GroupRoadmap|Loading epics"
+msgstr ""
+
+msgid "GroupRoadmap|New epic"
+msgstr ""
+
+msgid "GroupRoadmap|No start and end date"
+msgstr ""
+
+msgid "GroupRoadmap|No start date – %{dateWord}"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching epics"
+msgstr ""
+
+msgid "GroupRoadmap|Something went wrong while fetching milestones"
+msgstr ""
+
+msgid "GroupRoadmap|Sorry, no epics matched your search"
+msgstr ""
+
+msgid "GroupRoadmap|The roadmap shows the progress of your epics along a timeline"
+msgstr ""
+
+msgid "GroupRoadmap|This quarter"
+msgstr ""
+
+msgid "GroupRoadmap|This year"
+msgstr ""
+
+msgid "GroupRoadmap|To make your epics appear in the roadmap, add start or due dates to them."
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a start or due date to one of the %{linkStart}child epics%{linkEnd}."
+msgstr ""
+
+msgid "GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|To widen your search, change or remove filters; from %{startDate} to %{endDate}."
+msgstr ""
+
+msgid "GroupRoadmap|View epics list"
+msgstr ""
+
+msgid "GroupRoadmap|Within 3 years"
+msgstr ""
+
+msgid "GroupSAML|\"persistent\" recommended"
+msgstr ""
+
+msgid "GroupSAML|%{group_name} SAML authentication failed: %{message}"
+msgstr ""
+
+msgid "GroupSAML|%{strongOpen}Warning%{strongClose} - Enable %{linkStart}SSO enforcement%{linkEnd} to reduce security risks."
+msgstr ""
+
+msgid "GroupSAML|Active SAML Group Links (%{count})"
+msgstr ""
+
+msgid "GroupSAML|An error occurred generating your SCIM token. Please try again."
+msgstr ""
+
+msgid "GroupSAML|An error occurred resetting your SCIM token. Please try again."
+msgstr ""
+
+msgid "GroupSAML|Are you sure you want to remove the SAML group link?"
+msgstr ""
+
+msgid "GroupSAML|Are you sure you want to reset the SCIM token? SCIM provisioning will stop working until the new token is updated."
+msgstr ""
+
+msgid "GroupSAML|Before enforcing SSO, enable SAML authentication."
+msgstr ""
+
+msgid "GroupSAML|Before enforcing SSO-only authentication for Git activity of all users, enable SSO-only authentication for web activity."
+msgstr ""
+
+msgid "GroupSAML|Certificate fingerprint"
+msgstr ""
+
+msgid "GroupSAML|Configuration"
+msgstr ""
+
+msgid "GroupSAML|Copy SAML Response XML"
+msgstr ""
+
+msgid "GroupSAML|Could not create SAML group link: %{errors}."
+msgstr ""
+
+msgid "GroupSAML|Default membership role"
+msgstr ""
+
+msgid "GroupSAML|Enable SAML authentication for this group"
+msgstr ""
+
+msgid "GroupSAML|Enforce SSO-only authentication for Git and Dependency Proxy activity for this group"
+msgstr ""
+
+msgid "GroupSAML|Enforce SSO-only authentication for web activity for this group"
+msgstr ""
+
+msgid "GroupSAML|Enforce users to have dedicated group-managed accounts for this group"
+msgstr ""
+
+msgid "GroupSAML|Generate a SCIM token"
+msgstr ""
+
+msgid "GroupSAML|Generate a SCIM token to set up your System for Cross-Domain Identity Management."
+msgstr ""
+
+msgid "GroupSAML|Identifier"
+msgstr ""
+
+msgid "GroupSAML|Identity provider single sign-on URL"
+msgstr ""
+
+msgid "GroupSAML|Make sure you save this token — you won't be able to access it again."
+msgstr ""
+
+msgid "GroupSAML|Manage your group’s membership while adding another level of security with SAML."
+msgstr ""
+
+msgid "GroupSAML|Members"
+msgstr ""
+
+msgid "GroupSAML|Members will be forwarded here when signing in to your group. Get this from your identity provider, where it can also be called \"SSO Service Location\", \"SAML Token Issuance Endpoint\", or \"SAML 2.0/W-Federation URL\"."
+msgstr ""
+
+msgid "GroupSAML|NameID"
+msgstr ""
+
+msgid "GroupSAML|NameID Format"
+msgstr ""
+
+msgid "GroupSAML|New SAML group link saved."
+msgstr ""
+
+msgid "GroupSAML|No active SAML group links"
+msgstr ""
+
+msgid "GroupSAML|Prohibit outer forks for this group"
+msgstr ""
+
+msgid "GroupSAML|Reset SCIM token"
+msgstr ""
+
+msgid "GroupSAML|Role to assign members of this SAML group."
+msgstr ""
+
+msgid "GroupSAML|SAML Group Links"
+msgstr ""
+
+msgid "GroupSAML|SAML Group Name"
+msgstr ""
+
+msgid "GroupSAML|SAML Group Name: %{saml_group_name}"
+msgstr ""
+
+msgid "GroupSAML|SAML Name ID and email address do not match your user account. Contact an administrator."
+msgstr ""
+
+msgid "GroupSAML|SAML Response Output"
+msgstr ""
+
+msgid "GroupSAML|SAML Response XML"
+msgstr ""
+
+msgid "GroupSAML|SAML Single Sign On"
+msgstr ""
+
+msgid "GroupSAML|SAML Single Sign On Settings"
+msgstr ""
+
+msgid "GroupSAML|SAML group link was successfully removed."
+msgstr ""
+
+msgid "GroupSAML|SCIM Token"
+msgstr ""
+
+msgid "GroupSAML|SHA1 fingerprint of the SAML token signing certificate. Get this from your identity provider, where it can also be called \"Thumbprint\"."
+msgstr ""
+
+msgid "GroupSAML|Some branches are inaccessible because your SAML session has expired. To access the branches, select the group’s path to reauthenticate."
+msgstr ""
+
+msgid "GroupSAML|Some to-do items may be hidden because your SAML session has expired. Select the group’s path to reauthenticate and view the hidden to-do items."
+msgstr ""
+
+msgid "GroupSAML|The SCIM token is now hidden. To see the value of the token again, you need to %{linkStart}reset it%{linkEnd}."
+msgstr ""
+
+msgid "GroupSAML|The case-sensitive group name that will be sent by the SAML identity provider."
+msgstr ""
+
+msgid "GroupSAML|This will be set as the access level of users added to the group."
+msgstr ""
+
+msgid "GroupSAML|To be able to enable group-managed accounts, you first need to enable enforced SSO."
+msgstr ""
+
+msgid "GroupSAML|To be able to prohibit outer forks, you first need to enforce dedicate group managed accounts."
+msgstr ""
+
+msgid "GroupSAML|Use SAML group links to manage group membership using SAML."
+msgstr ""
+
+msgid "GroupSAML|Valid SAML Response"
+msgstr ""
+
+msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
+msgstr ""
+
+msgid "GroupSAML|as %{access_level}"
+msgstr ""
+
+msgid "GroupSAML|must match stored NameID of \"%{extern_uid}\" to identify user and allow sign in"
+msgstr ""
+
+msgid "GroupSAML|recommend persistent ID instead of email"
+msgstr ""
+
+msgid "GroupSaml|Copy SCIM API endpoint URL"
+msgstr ""
+
+msgid "GroupSaml|Copy SCIM token"
+msgstr ""
+
+msgid "GroupSaml|SCIM API endpoint URL"
+msgstr ""
+
+msgid "GroupSaml|Your SCIM token"
+msgstr ""
+
+msgid "GroupSelect|An error occurred fetching the groups. Please refresh the page to try again."
+msgstr ""
+
+msgid "GroupSelect|No matching results"
+msgstr ""
+
+msgid "GroupSelect|Search groups"
+msgstr ""
+
+msgid "GroupSelect|Select a group"
+msgstr ""
+
+msgid "GroupSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave empty for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{project_sharing_docs_link_start}project sharing%{link_end} and %{group_sharing_docs_link_start}group sharing%{link_end}."
+msgstr ""
+
+msgid "GroupSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave empty for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{project_sharing_docs_link_start}project sharing%{link_end} and %{group_sharing_docs_link_start}group sharing%{link_end}. Increasing the user cap does not automatically approve pending users."
+msgstr ""
+
+msgid "GroupSettings|Analytics"
+msgstr ""
+
+msgid "GroupSettings|Analytics Dashboards"
+msgstr ""
+
+msgid "GroupSettings|Applied to all subgroups unless overridden by a group owner. Groups already added to the project lose access."
+msgstr ""
+
+msgid "GroupSettings|Auto DevOps pipeline was updated for the group"
+msgstr ""
+
+msgid "GroupSettings|Available only on the top-level group. Applies to all subgroups. Groups already shared with a group outside %{group} are still shared unless removed manually."
+msgstr ""
+
+msgid "GroupSettings|Badges"
+msgstr ""
+
+msgid "GroupSettings|Be careful. Changing a group's parent can have unintended side effects. %{learn_more_link_start}Learn more.%{learn_more_link_end}"
+msgstr ""
+
+msgid "GroupSettings|Cannot update the path because there are projects under this group that contain Docker images in their Container Registry. Please remove the images from your projects first and try again."
+msgstr ""
+
+msgid "GroupSettings|Change group URL"
+msgstr ""
+
+msgid "GroupSettings|Changing a group's URL can have unintended side effects."
+msgstr ""
+
+msgid "GroupSettings|Choose a group path that does not start with a dash or end with a period. It can also contain alphanumeric characters and underscores."
+msgstr ""
+
+msgid "GroupSettings|Choose the merge request checks for projects in this group. This setting overrides the same settings configured on each project in this group."
+msgstr ""
+
+msgid "GroupSettings|Compliance frameworks"
+msgstr ""
+
+msgid "GroupSettings|Configure analytics features for this group."
+msgstr ""
+
+msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
+msgstr ""
+
+msgid "GroupSettings|Configure limits on the number of repositories users can download, clone, or fork in a given time."
+msgstr ""
+
+msgid "GroupSettings|Custom project templates"
+msgstr ""
+
+msgid "GroupSettings|Customer relations is enabled"
+msgstr ""
+
+msgid "GroupSettings|Customize this group's badges."
+msgstr ""
+
+msgid "GroupSettings|Default to Auto DevOps pipeline for all projects within this group"
+msgstr ""
+
+msgid "GroupSettings|Email notifications are disabled"
+msgstr ""
+
+msgid "GroupSettings|Enable overview background aggregation for Value Streams Dashboard"
+msgstr ""
+
+msgid "GroupSettings|Export group"
+msgstr ""
+
+msgid "GroupSettings|Git abuse rate limit"
+msgstr ""
+
+msgid "GroupSettings|Group members are not notified if the group is mentioned."
+msgstr ""
+
+msgid "GroupSettings|Group mentions are disabled"
+msgstr ""
+
+msgid "GroupSettings|If not specified at the group or instance level, the default is %{default_initial_branch_name}. Does not affect existing repositories."
+msgstr ""
+
+msgid "GroupSettings|If the parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility."
+msgstr ""
+
+msgid "GroupSettings|Members cannot invite groups outside of %{group} and its subgroups"
+msgstr ""
+
+msgid "GroupSettings|Organizations and contacts can be created and associated with issues."
+msgstr ""
+
+msgid "GroupSettings|Overrides user notification preferences for all members of the group, subgroups, and projects."
+msgstr ""
+
+msgid "GroupSettings|Pipeline settings was updated for the group"
+msgstr ""
+
+msgid "GroupSettings|Please choose a group URL with no special characters or spaces."
+msgstr ""
+
+msgid "GroupSettings|Prevent forking outside of the group"
+msgstr ""
+
+msgid "GroupSettings|Prevent forking setting was not saved"
+msgstr ""
+
+msgid "GroupSettings|Projects in %{group} cannot be shared with other groups"
+msgstr ""
+
+msgid "GroupSettings|Reporting"
+msgstr ""
+
+msgid "GroupSettings|Select a subgroup to use as a source of custom templates for new projects in this group. %{link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "GroupSettings|Select parent group"
+msgstr ""
+
+msgid "GroupSettings|Select the project containing Analytics Dashboards configuration files"
+msgstr ""
+
+msgid "GroupSettings|Select the project containing Analytics Dashboards configuration files."
+msgstr ""
+
+msgid "GroupSettings|Select the project containing the %{code_start}.gitlab/insights.yml%{code_end} file"
+msgstr ""
+
+msgid "GroupSettings|Select the project containing your custom Insights file."
+msgstr ""
+
+msgid "GroupSettings|Set a size limit for all content in each Pages site in this group. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "GroupSettings|Set the initial name and protections for the default branch of new repositories created in the group."
+msgstr ""
+
+msgid "GroupSettings|The Auto DevOps pipeline runs if no alternative CI configuration file is found."
+msgstr ""
+
+msgid "GroupSettings|There was a problem updating Auto DevOps pipeline: %{error_messages}."
+msgstr ""
+
+msgid "GroupSettings|There was a problem updating the pipeline settings: %{error_messages}."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}."
+msgstr ""
+
+msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
+msgstr ""
+
+msgid "GroupSettings|Transfer group"
+msgstr ""
+
+msgid "GroupSettings|Users can create %{link_start_project}project access tokens%{link_end} and %{link_start_group}group access tokens%{link_end} in this group"
+msgstr ""
+
+msgid "GroupSettings|Value Streams Dashboard"
+msgstr ""
+
+msgid "GroupSettings|What are badges?"
+msgstr ""
+
+msgid "GroupSettings|What is Analytics Dashboards?"
+msgstr ""
+
+msgid "GroupSettings|What is Insights?"
+msgstr ""
+
+msgid "GroupSettings|You must have the Owner role in the target group"
+msgstr ""
+
+msgid "GroupSettings|You will need to update your local repositories to point to the new location."
+msgstr ""
+
+msgid "GroupSettings|cannot be changed by you"
+msgstr ""
+
+msgid "GroupSettings|cannot be disabled when the parent group \"Share with group lock\" is enabled, except by the owner of the parent group"
+msgstr ""
+
+msgid "GroupSettings|cannot change when group contains projects with NPM packages"
+msgstr ""
+
+msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name}"
+msgstr ""
+
+msgid "Groups"
+msgstr ""
+
+msgid "Groups (%{count})"
+msgstr ""
+
+msgid "Groups and projects"
+msgstr ""
+
+msgid "Groups are a great way to organize projects and people."
+msgstr ""
+
+msgid "Groups are the best way to manage projects and members."
+msgstr ""
+
+msgid "GroupsDropdown|Frequently visited"
+msgstr ""
+
+msgid "GroupsDropdown|Groups you visit often will appear here"
+msgstr ""
+
+msgid "GroupsDropdown|Loading groups"
+msgstr ""
+
+msgid "GroupsDropdown|Search your groups"
+msgstr ""
+
+msgid "GroupsDropdown|Something went wrong on our end."
+msgstr ""
+
+msgid "GroupsDropdown|Sorry, no groups matched your search"
+msgstr ""
+
+msgid "GroupsDropdown|This feature requires browser localStorage support"
+msgstr ""
+
+msgid "GroupsDropdown|Toggle edit mode"
+msgstr ""
+
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
+
+msgid "GroupsEmptyState|Create new project"
+msgstr ""
+
+msgid "GroupsEmptyState|Create new subgroup"
+msgstr ""
+
+msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
+msgstr ""
+
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
+
+msgid "GroupsEmptyState|No archived projects."
+msgstr ""
+
+msgid "GroupsEmptyState|No groups found"
+msgstr ""
+
+msgid "GroupsEmptyState|No shared projects."
+msgstr ""
+
+msgid "GroupsEmptyState|No subgroups or projects."
+msgstr ""
+
+msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
+msgstr ""
+
+msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
+msgstr ""
+
+msgid "GroupsNew|%{groupsLinkStart}Groups%{groupsLinkEnd} and %{subgroupsLinkStart}subgroups%{subgroupsLinkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects."
+msgstr ""
+
+msgid "GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects."
+msgstr ""
+
+msgid "GroupsNew|Assemble related projects together and grant members access to several projects at once."
+msgstr ""
+
+msgid "GroupsNew|Connect instance"
+msgstr ""
+
+msgid "GroupsNew|Create a token with %{code_start}api%{code_end} and %{code_start}read_repository%{code_end} scopes in the %{pat_link_start}user settings%{pat_link_end} of the source GitLab instance. For %{short_living_link_start}security reasons%{short_living_link_end}, set a short expiration date for the token. Keep in mind that large migrations take more time."
+msgstr ""
+
+msgid "GroupsNew|Create group"
+msgstr ""
+
+msgid "GroupsNew|Create new group"
+msgstr ""
+
+msgid "GroupsNew|Create subgroup"
+msgstr ""
+
+msgid "GroupsNew|Enter the URL for the source instance."
+msgstr ""
+
+msgid "GroupsNew|GitLab source instance URL"
+msgstr ""
+
+msgid "GroupsNew|Groups"
+msgstr ""
+
+msgid "GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}."
+msgstr ""
+
+msgid "GroupsNew|Import a group and related data from another GitLab instance."
+msgstr ""
+
+msgid "GroupsNew|Import group"
+msgstr ""
+
+msgid "GroupsNew|Import groups by direct transfer"
+msgstr ""
+
+msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
+msgstr ""
+
+msgid "GroupsNew|New group"
+msgstr ""
+
+msgid "GroupsNew|New subgroup"
+msgstr ""
+
+msgid "GroupsNew|Not all group items are migrated. %{docs_link_start}What items are migrated%{docs_link_end}?"
+msgstr ""
+
+msgid "GroupsNew|Personal access token"
+msgstr ""
+
+msgid "GroupsNew|Please %{admin_link_start}enable it in the Admin settings%{admin_link_end}."
+msgstr ""
+
+msgid "GroupsNew|Please ask your Administrator to enable it in the Admin settings."
+msgstr ""
+
+msgid "GroupsNew|Please fill in your personal access token."
+msgstr ""
+
+msgid "GroupsNew|Provide credentials for the source instance to import from. You can provide this instance as a source to move groups in this instance."
+msgstr ""
+
+msgid "GroupsNew|Remember to enable it also on the instance you are migrating from."
+msgstr ""
+
+msgid "GroupsNew|This feature is deprecated and replaced by group migration by direct transfer. %{docs_link_start}Learn more%{docs_link_end}."
+msgstr ""
+
+msgid "GroupsNew|To import a group, navigate to the group settings for the GitLab source instance, %{link_start}generate an export file%{link_end}, and upload it here."
+msgstr ""
+
+msgid "GroupsNew|Upload file"
+msgstr ""
+
+msgid "GroupsNew|You can also %{linkStart}import an existing group%{linkEnd}."
+msgstr ""
+
+msgid "GroupsNew|e.g. h8d3f016698e..."
+msgstr ""
+
+msgid "GroupsTree|Are you sure you want to leave the \"%{fullName}\" group?"
+msgstr ""
+
+msgid "GroupsTree|Delete"
+msgstr ""
+
+msgid "GroupsTree|Edit"
+msgstr ""
+
+msgid "GroupsTree|Failed to leave the group. Please make sure you are not the only owner."
+msgstr ""
+
+msgid "GroupsTree|Leave group"
+msgstr ""
+
+msgid "GroupsTree|Loading groups"
+msgstr ""
+
+msgid "GroupsTree|Options"
+msgstr ""
+
+msgid "GroupsTree|Search by name"
+msgstr ""
+
+msgid "Groups|Avatar will be removed. Are you sure?"
+msgstr ""
+
+msgid "Groups|Changing group URL can have unintended side effects."
+msgstr ""
+
+msgid "Groups|Checking group URL availability..."
+msgstr ""
+
+msgid "Groups|Create and add README"
+msgstr ""
+
+msgid "Groups|Creating README"
+msgstr ""
+
+msgid "Groups|Enter a descriptive name for your group."
+msgstr ""
+
+msgid "Groups|Group ID"
+msgstr ""
+
+msgid "Groups|Group README"
+msgstr ""
+
+msgid "Groups|Group URL"
+msgstr ""
+
+msgid "Groups|Group avatar"
+msgstr ""
+
+msgid "Groups|Group description (optional)"
+msgstr ""
+
+msgid "Groups|Group name"
+msgstr ""
+
+msgid "Groups|Group path is available."
+msgstr ""
+
+msgid "Groups|Group path is unavailable. Path has been replaced with a suggested available path."
+msgstr ""
+
+msgid "Groups|Learn more about subgroups"
+msgstr ""
+
+msgid "Groups|Members, projects, trials, and paid subscriptions are tied to a specific top-level group. If you are already a member of a top-level group, you can create a subgroup so your new work is part of your existing top-level group. Do you want to create a subgroup instead?"
+msgstr ""
+
+msgid "Groups|Must start with letter, digit, emoji, or underscore. Can also contain periods, dashes, spaces, and parentheses."
+msgstr ""
+
+msgid "Groups|Remove avatar"
+msgstr ""
+
+msgid "Groups|Save changes"
+msgstr ""
+
+msgid "Groups|Subgroup URL"
+msgstr ""
+
+msgid "Groups|Subgroup name"
+msgstr ""
+
+msgid "Groups|Subgroup slug"
+msgstr ""
+
+msgid "Groups|There was an error creating the Group README."
+msgstr ""
+
+msgid "Groups|This will create a README.md for project %{path}."
+msgstr ""
+
+msgid "Groups|This will create a project %{path} and add a README.md."
+msgstr ""
+
+msgid "Groups|You're creating a new top-level group"
+msgstr ""
+
+msgid "Guest"
+msgstr ""
+
+msgid "Guideline"
+msgstr ""
+
+msgid "HAR (HTTP Archive)"
+msgstr ""
+
+msgid "HAR file URL"
+msgstr ""
+
+msgid "HAR file path or URL"
+msgstr ""
+
+msgid "HTTP Archive (HAR)"
+msgstr ""
+
+msgid "HTTP Basic: Access denied. The provided password or token is incorrect or your account has 2FA enabled and you must use a personal access token instead of a password. See %{help_page_url}"
+msgstr ""
+
+msgid "Harbor Registry"
+msgstr ""
+
+msgid "HarborIntegration|After the Harbor integration is activated, global variables `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` and `$HARBOR_PROJECT` will be created for CI/CD use."
+msgstr ""
+
+msgid "HarborIntegration|Base URL of the Harbor instance."
+msgstr ""
+
+msgid "HarborIntegration|Enter new Harbor password"
+msgstr ""
+
+msgid "HarborIntegration|Harbor URL"
+msgstr ""
+
+msgid "HarborIntegration|Harbor password"
+msgstr ""
+
+msgid "HarborIntegration|Harbor project name"
+msgstr ""
+
+msgid "HarborIntegration|Harbor username"
+msgstr ""
+
+msgid "HarborIntegration|Leave blank to use your current password."
+msgstr ""
+
+msgid "HarborIntegration|Password for your Harbor username."
+msgstr ""
+
+msgid "HarborIntegration|The name of the project in Harbor."
+msgstr ""
+
+msgid "HarborIntegration|Use Harbor as this project's container registry."
+msgstr ""
+
+msgid "HarborRegistry|%d artifact"
+msgid_plural "HarborRegistry|%d artifacts"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "HarborRegistry|%{count} Image repository"
+msgid_plural "HarborRegistry|%{count} Image repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "HarborRegistry|-- artifacts"
+msgstr ""
+
+msgid "HarborRegistry|-- tags"
+msgstr ""
+
+msgid "HarborRegistry|Digest: %{imageId}"
+msgstr ""
+
+msgid "HarborRegistry|Harbor Registry"
+msgstr ""
+
+msgid "HarborRegistry|Harbor connection error"
+msgstr ""
+
+msgid "HarborRegistry|Please try different search criteria"
+msgstr ""
+
+msgid "HarborRegistry|Published %{timeInfo}"
+msgstr ""
+
+msgid "HarborRegistry|Root image"
+msgstr ""
+
+msgid "HarborRegistry|Something went wrong while fetching the artifact list."
+msgstr ""
+
+msgid "HarborRegistry|Something went wrong while fetching the repository list."
+msgstr ""
+
+msgid "HarborRegistry|Something went wrong while fetching the tags."
+msgstr ""
+
+msgid "HarborRegistry|Sorry, your filter produced no results."
+msgstr ""
+
+msgid "HarborRegistry|Tag"
+msgstr ""
+
+msgid "HarborRegistry|The filter returned no results"
+msgstr ""
+
+msgid "HarborRegistry|There are no harbor images stored for this project"
+msgstr ""
+
+msgid "HarborRegistry|This image has no artifacts"
+msgstr ""
+
+msgid "HarborRegistry|To widen your search, change or remove the filters above."
+msgstr ""
+
+msgid "HarborRegistry|We are having trouble connecting to the Harbor Registry. Please try refreshing the page. If this error persists, please review %{docLinkStart}the documentation%{docLinkEnd}."
+msgstr ""
+
+msgid "HarborRegistry|With the Harbor Registry, every project can connect to a harbor space to store its Docker images."
+msgstr ""
+
+msgid "HarborRegistry|With the Harbor Registry, every project can have its own space to store images. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
+msgid "Hashed Storage must be enabled to use Geo"
+msgstr ""
+
+msgid "Hashed repository storage paths"
+msgstr ""
+
+msgid "Hashed storage can't be disabled anymore for new projects"
+msgstr ""
+
+msgid "Header logo"
+msgstr ""
+
+msgid "Header logo was successfully removed."
+msgstr ""
+
+msgid "Header logo will be removed. Are you sure?"
+msgstr ""
+
+msgid "Header message"
+msgstr ""
+
+msgid "HeaderAction|Notifications and other %{issueType} actions have moved to this menu."
+msgstr ""
+
+msgid "HeaderAction|Okay!"
+msgstr ""
+
+msgid "Headers"
+msgstr ""
+
+msgid "Heading 1"
+msgstr ""
+
+msgid "Heading 2"
+msgstr ""
+
+msgid "Heading 3"
+msgstr ""
+
+msgid "Heading 4"
+msgstr ""
+
+msgid "Health"
+msgstr ""
+
+msgid "Health Check"
+msgstr ""
+
+msgid "Health information can be retrieved from the following endpoints. More information is available"
+msgstr ""
+
+msgid "Health status"
+msgstr ""
+
+msgid "HealthCheck|Access token is"
+msgstr ""
+
+msgid "HealthCheck|Healthy"
+msgstr ""
+
+msgid "HealthCheck|No Health Problems Detected"
+msgstr ""
+
+msgid "HealthCheck|Unhealthy"
+msgstr ""
+
+msgid "Hello %{name},"
+msgstr ""
+
+msgid "Hello, %{name}!"
+msgstr ""
+
+msgid "Hello, %{username}!"
+msgstr ""
+
+msgid "HelloMessage|%{handshake_emoji} Contribute to GitLab: %{contribute_link}"
+msgstr ""
+
+msgid "HelloMessage|%{magnifier_emoji} Create a new GitLab issue: %{new_issue_link}"
+msgstr ""
+
+msgid "HelloMessage|%{rocket_emoji} We like your curiosity! Help us improve GitLab by joining the team: %{jobs_page_link}"
+msgstr ""
+
+msgid "HelloMessage|Does this page need fixes or improvements? Open an issue or contribute a merge request to help make GitLab more lovable. At GitLab, everyone can contribute!"
+msgstr ""
+
+msgid "HelloMessage|Welcome to GitLab!"
+msgstr ""
+
+msgid "Help"
+msgstr ""
+
+msgid "Help translate GitLab into your language"
+msgstr ""
+
+msgid "Help translate to your language"
+msgstr ""
+
+msgid "Helpful"
+msgstr ""
+
+msgid "Helps prevent bots from brute-force attacks."
+msgstr ""
+
+msgid "Helps prevent bots from creating accounts."
+msgstr ""
+
+msgid "Helps prevent bots from creating accounts. %{link_start}How do I configure it?%{link_end}"
+msgstr ""
+
+msgid "Helps prevent bots from creating issues."
+msgstr ""
+
+msgid "Helps prevent malicious users hide their activity."
+msgstr ""
+
+msgid "Helps reduce request volume (for example, from crawlers or abusive bots)"
+msgstr ""
+
+msgid "Helps reduce request volume for protected paths."
+msgstr ""
+
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
+msgid "Hi %{username}!"
+msgstr ""
+
+msgid "Hi %{username},"
+msgstr ""
+
+msgid "Hidden"
+msgstr ""
+
+msgid "Hide"
+msgstr ""
+
+msgid "Hide Live Preview"
+msgstr ""
+
+msgid "Hide archived projects"
+msgstr ""
+
+msgid "Hide comments"
+msgstr ""
+
+msgid "Hide comments on this file"
+msgstr ""
+
+msgid "Hide details"
+msgstr ""
+
+msgid "Hide file browser (or press F)"
+msgstr ""
+
+msgid "Hide file contents"
+msgstr ""
+
+msgid "Hide group projects"
+msgstr ""
+
+msgid "Hide host keys manual input"
+msgstr ""
+
+msgid "Hide list"
+msgstr ""
+
+msgid "Hide marketing-related entries from the Help page"
+msgstr ""
+
+msgid "Hide password"
+msgstr ""
+
+msgid "Hide payload"
+msgstr ""
+
+msgid "Hide shared projects"
+msgstr ""
+
+msgid "Hide sidebar"
+msgstr ""
+
+msgid "Hide thread"
+msgstr ""
+
+msgid "Hide tooltips or popovers"
+msgstr ""
+
+msgid "Hide value"
+msgid_plural "Hide values"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Hide values"
+msgstr ""
+
+msgid "Hierarchy|Current structure"
+msgstr ""
+
+msgid "Hierarchy|Deliver value more efficiently by breaking down necessary work into a hierarchical structure. This structure helps teams understand scope, priorities, and how work cascades up toward larger goals."
+msgstr ""
+
+msgid "Hierarchy|Help us improve work items in GitLab!"
+msgstr ""
+
+msgid "Hierarchy|Is there a framework or type of work item you wish you had access to in GitLab? Give us your feedback and help us build the experiences valuable to you."
+msgstr ""
+
+msgid "Hierarchy|Planning hierarchy"
+msgstr ""
+
+msgid "Hierarchy|Something went wrong while fetching children."
+msgstr ""
+
+msgid "Hierarchy|Take the work items survey"
+msgstr ""
+
+msgid "Hierarchy|These items are unavailable in the current structure."
+msgstr ""
+
+msgid "Hierarchy|Unavailable structure"
+msgstr ""
+
+msgid "Hierarchy|You can start using these items now."
+msgstr ""
+
+msgid "High - S2"
+msgstr ""
+
+msgid "High or unknown vulnerabilities present"
+msgstr ""
+
+msgid "Highest role:"
+msgstr ""
+
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
+msgid "HighlightBar|Time to SLA:"
+msgstr ""
+
+msgid "Historical release"
+msgstr ""
+
+msgid "History"
+msgstr ""
+
+msgid "History of authentications"
+msgstr ""
+
+msgid "Holder name:"
+msgstr ""
+
+msgid "Home page URL"
+msgstr ""
+
+msgid "Homepage"
+msgstr ""
+
+msgid "Hook execution failed. Ensure the group has a project with commits."
+msgstr ""
+
+msgid "Horizontal rule"
+msgstr ""
+
+msgid "Hostname"
+msgstr ""
+
+msgid "Hostname used in private commit emails. %{learn_more}"
+msgstr ""
+
+msgid "Hour"
+msgstr ""
+
+msgid "Hour (UTC)"
+msgstr ""
+
+msgid "Housekeeping"
+msgstr ""
+
+msgid "Housekeeping successfully started"
+msgstr ""
+
+msgid "How do I change my password in GitLab?"
+msgstr ""
+
+msgid "How do I clone a repository?"
+msgstr ""
+
+msgid "How do I configure Akismet?"
+msgstr ""
+
+msgid "How do I configure this integration?"
+msgstr ""
+
+msgid "How do I create a template?"
+msgstr ""
+
+msgid "How do I fork a project?"
+msgstr ""
+
+msgid "How do I generate it?"
+msgstr ""
+
+msgid "How do I get started?"
+msgstr ""
+
+msgid "How do I mirror repositories?"
+msgstr ""
+
+msgid "How do I rename an environment?"
+msgstr ""
+
+msgid "How do I set up a Google Chat webhook?"
+msgstr ""
+
+msgid "How do I set up this service?"
+msgstr ""
+
+msgid "How do I use a web terminal?"
+msgstr ""
+
+msgid "How does pull mirroring work?"
+msgstr ""
+
+msgid "How is progress calculated?"
+msgstr ""
+
+msgid "How many seconds an IP counts toward the IP address limit."
+msgstr ""
+
+msgid "How the job limiter handles jobs exceeding the thresholds specified below. The 'track' mode only logs the jobs. The 'compress' mode compresses the jobs and raises an exception if the compressed size exceeds the limit."
+msgstr ""
+
+msgid "How to track time"
+msgstr ""
+
+msgid "I accept the %{terms_link}"
+msgstr ""
+
+msgid "I forgot my password"
+msgstr ""
+
+msgid "I want to explore GitLab to see if it’s worth switching to"
+msgstr ""
+
+msgid "I want to learn the basics of Git"
+msgstr ""
+
+msgid "I want to move my repository to GitLab from somewhere else"
+msgstr ""
+
+msgid "I want to store my code"
+msgstr ""
+
+msgid "I want to use GitLab CI with my existing repository"
+msgstr ""
+
+msgid "I'm signing up for GitLab because:"
+msgstr ""
+
+msgid "ID"
+msgstr ""
+
+msgid "ID:"
+msgstr ""
+
+msgid "IDE"
+msgstr ""
+
+msgid "IDE|Commit"
+msgstr ""
+
+msgid "IDE|Commit to %{branchName} branch"
+msgstr ""
+
+msgid "IDE|Edit"
+msgstr ""
+
+msgid "IDE|Go to project"
+msgstr ""
+
+msgid "IDE|Review"
+msgstr ""
+
+msgid "IDE|Start a new merge request"
+msgstr ""
+
+msgid "IDE|Successful commit"
+msgstr ""
+
+msgid "IDE|This option is disabled because you are not allowed to create merge requests in this project."
+msgstr ""
+
+msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
+msgstr ""
+
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
+msgid "INFO: Your SSH key has expired. Please generate a new key."
+msgstr ""
+
+msgid "INFO: Your SSH key is expiring soon. Please generate a new key."
+msgstr ""
+
+msgid "IP Address"
+msgstr ""
+
+msgid "IP address expiration time"
+msgstr ""
+
+msgid "IP address restrictions"
+msgstr ""
+
+msgid "IP addresses per user"
+msgstr ""
+
+msgid "IP subnet restriction only allowed for top-level groups"
+msgstr ""
+
+msgid "Icon will be removed. Are you sure?"
+msgstr ""
+
+msgid "Id"
+msgstr ""
+
+msgid "Identifier"
+msgstr ""
+
+msgid "Identifiers"
+msgstr ""
+
+msgid "Identities"
+msgstr ""
+
+msgid "IdentityVerification|%{linkStart}Enter a new phone number%{linkEnd}"
+msgstr ""
+
+msgid "IdentityVerification|A code has already been sent to this email address. Check your spam folder or enter another email address."
+msgstr ""
+
+msgid "IdentityVerification|A new code has been sent to your updated email address."
+msgstr ""
+
+msgid "IdentityVerification|A new code has been sent."
+msgstr ""
+
+msgid "IdentityVerification|Before you finish creating your account, we need to verify your identity. On the verification page, enter the following code."
+msgstr ""
+
+msgid "IdentityVerification|Before you sign in, we need to verify your identity. Enter the following code on the sign-in page."
+msgstr ""
+
+msgid "IdentityVerification|Complete verification to sign in."
+msgstr ""
+
+msgid "IdentityVerification|Confirm your email address"
+msgstr ""
+
+msgid "IdentityVerification|Didn't receive a code?"
+msgstr ""
+
+msgid "IdentityVerification|Didn't receive a code? %{linkStart}Send a new code%{linkEnd}"
+msgstr ""
+
+msgid "IdentityVerification|Email update is only offered once."
+msgstr ""
+
+msgid "IdentityVerification|Enter a code."
+msgstr ""
+
+msgid "IdentityVerification|Enter a valid code."
+msgstr ""
+
+msgid "IdentityVerification|For added security, you'll need to verify your identity in a few quick steps."
+msgstr ""
+
+msgid "IdentityVerification|For added security, you'll need to verify your identity."
+msgstr ""
+
+msgid "IdentityVerification|For added security, you'll need to verify your identity. We've sent a verification code to %{email}"
+msgstr ""
+
+msgid "IdentityVerification|GitLab will not charge or store your payment information, it will only be used for verification."
+msgstr ""
+
+msgid "IdentityVerification|Help us keep GitLab secure"
+msgstr ""
+
+msgid "IdentityVerification|Help us protect your account"
+msgstr ""
+
+msgid "IdentityVerification|If you have not recently tried to sign into GitLab, we recommend %{password_link_start}changing your password%{link_end} and %{two_fa_link_start}setting up Two-Factor Authentication%{link_end} to keep your account safe. Your verification code expires after %{expires_in_minutes} minutes."
+msgstr ""
+
+msgid "IdentityVerification|If you have not recently tried to sign into GitLab, we recommend changing your password (%{password_link}) and setting up Two-Factor Authentication (%{two_fa_link}) to keep your account safe."
+msgstr ""
+
+msgid "IdentityVerification|If you've lost access to the email associated to this account or having trouble with the code, %{link_start}here are some other steps you can take.%{link_end}"
+msgstr ""
+
+msgid "IdentityVerification|International dial code"
+msgstr ""
+
+msgid "IdentityVerification|Maximum login attempts exceeded. Wait %{interval} and try again."
+msgstr ""
+
+msgid "IdentityVerification|Phone number"
+msgstr ""
+
+msgid "IdentityVerification|Phone number is required."
+msgstr ""
+
+msgid "IdentityVerification|Phone number must be %{maxLength} digits or fewer."
+msgstr ""
+
+msgid "IdentityVerification|Phone number must contain only digits."
+msgstr ""
+
+msgid "IdentityVerification|Please enter a valid code"
+msgstr ""
+
+msgid "IdentityVerification|Please enter a valid email address."
+msgstr ""
+
+msgid "IdentityVerification|Resend code"
+msgstr ""
+
+msgid "IdentityVerification|Send a new code"
+msgstr ""
+
+msgid "IdentityVerification|Send code"
+msgstr ""
+
+msgid "IdentityVerification|Something went wrong. Please try again."
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
+msgstr ""
+
+msgid "IdentityVerification|The code has expired. Send a new code and try again."
+msgstr ""
+
+msgid "IdentityVerification|The code is incorrect. Enter it again, or send a new code."
+msgstr ""
+
+msgid "IdentityVerification|There was a problem with the credit card details you entered. Use a different credit card and try again."
+msgstr ""
+
+msgid "IdentityVerification|Update email"
+msgstr ""
+
+msgid "IdentityVerification|Verification code"
+msgstr ""
+
+msgid "IdentityVerification|Verification code can't be blank."
+msgstr ""
+
+msgid "IdentityVerification|Verification code must be a number."
+msgstr ""
+
+msgid "IdentityVerification|Verification successful"
+msgstr ""
+
+msgid "IdentityVerification|Verify code"
+msgstr ""
+
+msgid "IdentityVerification|Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Verify payment method"
+msgstr ""
+
+msgid "IdentityVerification|Verify phone number"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify your identity"
+msgstr ""
+
+msgid "IdentityVerification|We sent a new code to +%{phoneNumber}"
+msgstr ""
+
+msgid "IdentityVerification|We've sent a verification code to %{email}"
+msgstr ""
+
+msgid "IdentityVerification|We've sent a verification code to +%{phoneNumber}"
+msgstr ""
+
+msgid "IdentityVerification|You will receive a text containing a code. Standard charges may apply."
+msgstr ""
+
+msgid "IdentityVerification|You've reached the maximum amount of resends. Wait %{interval} and try again."
+msgstr ""
+
+msgid "IdentityVerification|You've reached the maximum amount of tries. Wait %{interval} and try again."
+msgstr ""
+
+msgid "IdentityVerification|You've reached the maximum amount of tries. Wait %{interval} or send a new code and try again."
+msgstr ""
+
+msgid "IdentityVerification|Your account has been successfully verified. You'll be redirected to your account in just a moment. You can also %{redirect_url_start}refresh the page%{redirect_url_end}."
+msgstr ""
+
+msgid "IdentityVerification|Your verification code expires after %{expires_in_minutes} minutes."
+msgstr ""
+
+msgid "Identity|Provider ID"
+msgstr ""
+
+msgid "If any indexed field exceeds this limit, it is truncated to this number of characters. The rest of the content is neither indexed nor searchable. This does not apply to repository and wiki indexing. For unlimited characters, set this to 0."
+msgstr ""
+
+msgid "If blank, defaults to %{code_open}Retry later%{code_close}."
+msgstr ""
+
+msgid "If blank, set allowable lifetime to %{instance_level_policy_in_words}, as defined by the instance admin. Once set, existing tokens for users in this group may be revoked."
+msgstr ""
+
+msgid "If checked, group owners can manage LDAP group links and LDAP member overrides"
+msgstr ""
+
+msgid "If checked, new group memberships and permissions can only be added via LDAP synchronization"
+msgstr ""
+
+msgid "If checked, new group memberships and permissions can only be added via SAML Group Links synchronization"
+msgstr ""
+
+msgid "If disabled, a diverged local branch will not be automatically updated with commits from its remote counterpart, to prevent local data loss. If the default branch (%{default_branch}) has diverged and cannot be updated, mirroring will fail. Other diverged branches are silently ignored. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "If disabled, only administrators can configure repository mirroring."
+msgstr ""
+
+msgid "If enabled, all branches will be mirrored."
+msgstr ""
+
+msgid "If enabled, only protected branches will be mirrored."
+msgstr ""
+
+msgid "If the email address is incorrect, you can %{registration_link_start}register again with a different email%{registration_link_end}."
+msgstr ""
+
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
+msgid "If this email was added in error, you can remove it here:"
+msgstr ""
+
+msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
+msgstr ""
+
+msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
+msgstr ""
+
+msgid "If this was a mistake you can leave the %{source_type}."
+msgstr ""
+
+msgid "If using GitHub, you’ll see pipeline statuses on GitHub for your commits and pull requests. %{more_info_link}"
+msgstr ""
+
+msgid "If you add %{codeStart}needs%{codeEnd} to jobs in your pipeline you'll be able to view the %{codeStart}needs%{codeEnd} relationships between jobs in this tab as a %{linkStart}Directed Acyclic Graph (DAG)%{linkEnd}."
+msgstr ""
+
+msgid "If you are unable to sign in or recover your password, contact a GitLab administrator."
+msgstr ""
+
+msgid "If you did not initiate these sign-in attempts, please reach out to your administrator or enable two-factor authentication (2FA) on your account."
+msgstr ""
+
+msgid "If you did not initiate this change, please contact your administrator immediately."
+msgstr ""
+
+msgid "If you did not perform this request, you can safely ignore this email."
+msgstr ""
+
+msgid "If you did not recently sign in, you should immediately %{password_link_start}change your password%{password_link_end}."
+msgstr ""
+
+msgid "If you did not recently sign in, you should immediately change your password: %{password_link}."
+msgstr ""
+
+msgid "If you did not recently try to sign in, you should immediately %{password_link_start}change your password%{password_link_end}."
+msgstr ""
+
+msgid "If you did not recently try to sign in, you should immediately change your password: %{password_link}."
+msgstr ""
+
+msgid "If you do not renew by %{strong}%{downgrades_on}%{strong_close}, you can't use merge approvals, %{end_message}"
+msgstr ""
+
+msgid "If you don't renew by %{strong}%{downgrades_on}%{strong_close} your instance will become read-only, and you won't be able to create issues or merge requests. You will also lose access to your paid features and support entitlement. %{learn_more_link}"
+msgstr ""
+
+msgid "If you get a lot of false alarms from repository checks, you can clear all repository check information from the database."
+msgstr ""
+
+msgid "If you lose your recovery codes you can generate new ones, invalidating all previous codes."
+msgstr ""
+
+msgid "If you recently signed in and recognize the IP address, you may disregard this email."
+msgstr ""
+
+msgid "If you recently tried to sign in, but mistakenly entered an incorrect verification code, you can ignore this email."
+msgstr ""
+
+msgid "If you want to re-enable two-factor authentication, visit %{two_factor_link}"
+msgstr ""
+
+msgid "If you want to re-enable two-factor authentication, visit the %{settings_link_to} page."
+msgstr ""
+
+msgid "If you want to remove this email address, visit %{profile_link}"
+msgstr ""
+
+msgid "If you want to remove this email address, visit the %{settings_link_to} page."
+msgstr ""
+
+msgid "If you've purchased or renewed your subscription and have an activation code, please enter it below to start the activation process."
+msgstr ""
+
+msgid "If your HTTP repository is not publicly accessible, add your credentials."
+msgstr ""
+
+msgid "Ignore"
+msgstr ""
+
+msgid "Ignored"
+msgstr ""
+
+msgid "Image"
+msgstr ""
+
+msgid "ImageDiffViewer|2-up"
+msgstr ""
+
+msgid "ImageDiffViewer|Onion skin"
+msgstr ""
+
+msgid "ImageDiffViewer|Swipe"
+msgstr ""
+
+msgid "ImageViewerDimensions|H"
+msgstr ""
+
+msgid "ImageViewerDimensions|W"
+msgstr ""
+
+msgid "Images with incorrect dimensions are not resized automatically, and may result in unexpected behavior."
+msgstr ""
+
+msgid "Impact detected"
+msgstr ""
+
+msgid "Impact mitigated"
+msgstr ""
+
+msgid "Impersonate"
+msgstr ""
+
+msgid "Impersonation Tokens"
+msgstr ""
+
+msgid "Impersonation has been disabled"
+msgstr ""
+
+msgid "Impersonation tokens"
+msgstr ""
+
+msgid "Import"
+msgstr ""
+
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import CSV"
+msgstr ""
+
+msgid "Import an exported GitLab project"
+msgstr ""
+
+msgid "Import and export rate limits"
+msgstr ""
+
+msgid "Import failed due to a GitHub error: %{original} (HTTP %{code})"
+msgstr ""
+
+msgid "Import from"
+msgstr ""
+
+msgid "Import from Jira"
+msgstr ""
+
+msgid "Import group"
+msgstr ""
+
+msgid "Import group from file"
+msgstr ""
+
+msgid "Import groups"
+msgstr ""
+
+msgid "Import history"
+msgstr ""
+
+msgid "Import in progress"
+msgstr ""
+
+msgid "Import in progress. Refresh page to see newly added issues."
+msgstr ""
+
+msgid "Import issues"
+msgstr ""
+
+msgid "Import multiple repositories by uploading a manifest file."
+msgstr ""
+
+msgid "Import project"
+msgstr ""
+
+msgid "Import project from"
+msgstr ""
+
+msgid "Import projects from Bitbucket"
+msgstr ""
+
+msgid "Import projects from Bitbucket Server"
+msgstr ""
+
+msgid "Import projects from FogBugz"
+msgstr ""
+
+msgid "Import projects from GitLab.com"
+msgstr ""
+
+msgid "Import projects from Gitea"
+msgstr ""
+
+msgid "Import repositories from Bitbucket Server"
+msgstr ""
+
+msgid "Import repositories from GitHub"
+msgstr ""
+
+msgid "Import repository"
+msgstr ""
+
+msgid "Import requirements"
+msgstr ""
+
+msgid "Import started by: %{importInitiator}"
+msgstr ""
+
+msgid "Import timed out. Import took longer than %{import_jobs_expiration} seconds"
+msgstr ""
+
+msgid "Import with projects"
+msgstr ""
+
+msgid "Import without projects"
+msgstr ""
+
+msgid "ImportAProjectModal|Import from a project"
+msgstr ""
+
+msgid "ImportAProjectModal|Import members from another project"
+msgstr ""
+
+msgid "ImportAProjectModal|Import project members"
+msgstr ""
+
+msgid "ImportAProjectModal|Only project members (not group members) are imported, and they get the same permissions as the project you import from."
+msgstr ""
+
+msgid "ImportAProjectModal|Successfully imported"
+msgstr ""
+
+msgid "ImportAProjectModal|Unable to import project members"
+msgstr ""
+
+msgid "ImportAProjectModal|You're importing members to the %{strongStart}%{name}%{strongEnd} project."
+msgstr ""
+
+msgid "ImportButtons|Connect repositories from"
+msgstr ""
+
+msgid "ImportProjects|%{provider} rate limit exceeded. Try again later"
+msgstr ""
+
+msgid "ImportProjects|Advanced import settings"
+msgstr ""
+
+msgid "ImportProjects|All organizations"
+msgstr ""
+
+msgid "ImportProjects|Blocked import URL: %{message}"
+msgstr ""
+
+msgid "ImportProjects|Cancel import"
+msgstr ""
+
+msgid "ImportProjects|Cancelling project import failed"
+msgstr ""
+
+msgid "ImportProjects|Cancelling project import failed: %{reason}"
+msgstr ""
+
+msgid "ImportProjects|Collaborated"
+msgstr ""
+
+msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
+msgstr ""
+
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
+msgid "ImportProjects|Imported files will be kept. You can import this repository again later."
+msgstr ""
+
+msgid "ImportProjects|Importing the project failed"
+msgstr ""
+
+msgid "ImportProjects|Importing the project failed: %{reason}"
+msgstr ""
+
+msgid "ImportProjects|Organization"
+msgstr ""
+
+msgid "ImportProjects|Organizations"
+msgstr ""
+
+msgid "ImportProjects|Owned"
+msgstr ""
+
+msgid "ImportProjects|Re-import creates a new project. It does not sync with the existing project."
+msgstr ""
+
+msgid "ImportProjects|Repository above permitted size limit."
+msgstr ""
+
+msgid "ImportProjects|Requesting namespaces failed"
+msgstr ""
+
+msgid "ImportProjects|Requesting your %{provider} repositories failed"
+msgstr ""
+
+msgid "ImportProjects|Select the repositories you want to import"
+msgstr ""
+
+msgid "ImportProjects|The more information you select, the longer it will take to import"
+msgstr ""
+
+msgid "ImportProjects|The remote data could not be imported."
+msgstr ""
+
+msgid "ImportProjects|The repository could not be created."
+msgstr ""
+
+msgid "ImportProjects|Update of imported projects with realtime changes failed"
+msgstr ""
+
+msgid "Imported requirements"
+msgstr ""
+
+msgid "Importing %d repository"
+msgid_plural "Importing %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Importing GitLab projects? Migrating GitLab projects when migrating groups by direct transfer is in Beta. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Importing..."
+msgstr ""
+
+msgid "Import|An error occurred while fetching import details."
+msgstr ""
+
+msgid "Import|GitHub import details"
+msgstr ""
+
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
+msgstr ""
+
+msgid "Import|Maximum import remote file size (MB)"
+msgstr ""
+
+msgid "Import|Maximum remote file size for imports from external object storages. For example, AWS S3."
+msgstr ""
+
+msgid "Import|Maximum size of decompressed archive."
+msgstr ""
+
+msgid "Import|No import details"
+msgstr ""
+
+msgid "Import|Partially completed"
+msgstr ""
+
+msgid "Import|See failures"
+msgstr ""
+
+msgid "Import|The repository could not be imported."
+msgstr ""
+
+msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
+msgid "Improve customer support with Service Desk"
+msgstr ""
+
+msgid "Improve indexing performance by increasing Sidekiq load. Values greater than the current shard limit (%{limit}) are not allowed."
+msgstr ""
+
+msgid "Improve quality with test cases"
+msgstr ""
+
+msgid "In GitLab"
+msgstr ""
+
+msgid "In case of pull mirroring, your user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
+msgstr ""
+
+msgid "In each example, replace %{code_start}TOKEN%{code_end} with the trigger token you generated and replace %{code_start}REF_NAME%{code_end} with the branch or tag name."
+msgstr ""
+
+msgid "In progress"
+msgstr ""
+
+msgid "In progress, queued for %{queuedDuration} seconds"
+msgstr ""
+
+msgid "In the background, we're attempting to connect you again."
+msgstr ""
+
+msgid "In this group"
+msgstr ""
+
+msgid "In this page you will find information about the settings that are used in your current instance."
+msgstr ""
+
+msgid "In this project"
+msgstr ""
+
+msgid "In use"
+msgstr ""
+
+msgid "InProductMarketing|%{organization_name} logo"
+msgstr ""
+
+msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
+msgstr ""
+
+msgid "InProductMarketing|Advanced security testing"
+msgstr ""
+
+msgid "InProductMarketing|Blog"
+msgstr ""
+
+msgid "InProductMarketing|Building for iOS? We've got you covered."
+msgstr ""
+
+msgid "InProductMarketing|Deliver Better Products Faster"
+msgstr ""
+
+msgid "InProductMarketing|Facebook"
+msgstr ""
+
+msgid "InProductMarketing|Free 30-day trial"
+msgstr ""
+
+msgid "InProductMarketing|Free guest users"
+msgstr ""
+
+msgid "InProductMarketing|Get set up to build for iOS"
+msgstr ""
+
+msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
+msgstr ""
+
+msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
+msgstr ""
+
+msgid "InProductMarketing|Increase Operational Efficiencies"
+msgstr ""
+
+msgid "InProductMarketing|Invite unlimited colleagues"
+msgstr ""
+
+msgid "InProductMarketing|Learn how to build for iOS"
+msgstr ""
+
+msgid "InProductMarketing|No credit card required."
+msgstr ""
+
+msgid "InProductMarketing|Portfolio management"
+msgstr ""
+
+msgid "InProductMarketing|Reduce Security and Compliance Risk"
+msgstr ""
+
+msgid "InProductMarketing|Security risk mitigation"
+msgstr ""
+
+msgid "InProductMarketing|Start a Self-Managed trial"
+msgstr ""
+
+msgid "InProductMarketing|Team members collaborating"
+msgstr ""
+
+msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
+msgstr ""
+
+msgid "InProductMarketing|Twitter"
+msgstr ""
+
+msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
+msgstr ""
+
+msgid "InProductMarketing|Value stream management"
+msgstr ""
+
+msgid "InProductMarketing|Want to get your iOS app up and running, including publishing all the way to TestFlight? Follow our guide to set up GitLab and fastlane to publish iOS apps to the App Store."
+msgstr ""
+
+msgid "InProductMarketing|Want to host GitLab on your servers?"
+msgstr ""
+
+msgid "InProductMarketing|Watch iOS building in action."
+msgstr ""
+
+msgid "InProductMarketing|YouTube"
+msgstr ""
+
+msgid "InProductMarketing|go to about.gitlab.com"
+msgstr ""
+
+msgid "InProductMarketing|unsubscribe"
+msgstr ""
+
+msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
+msgstr ""
+
+msgid "Inactive"
+msgstr ""
+
+msgid "Incident"
+msgstr ""
+
+msgid "Incident Management Limits"
+msgstr ""
+
+msgid "Incident creation cancelled."
+msgstr ""
+
+msgid "Incident details"
+msgstr ""
+
+msgid "Incident template (optional)."
+msgstr ""
+
+msgid "Incident title"
+msgstr ""
+
+msgid "IncidentManagement|%{hours} hours, %{minutes} minutes remaining"
+msgstr ""
+
+msgid "IncidentManagement|%{minutes} minutes remaining"
+msgstr ""
+
+msgid "IncidentManagement|Achieved SLA"
+msgstr ""
+
+msgid "IncidentManagement|Acknowledged"
+msgstr ""
+
+msgid "IncidentManagement|All"
+msgstr ""
+
+msgid "IncidentManagement|All alerts promoted to incidents are automatically displayed within the list."
+msgstr ""
+
+msgid "IncidentManagement|All alerts promoted to incidents are automatically displayed within the list. You can also create a new incident using the button below."
+msgstr ""
+
+msgid "IncidentManagement|An error occurred while fetching the incident status. Please reload the page."
+msgstr ""
+
+msgid "IncidentManagement|An error occurred while updating the incident status. Please reload the page and try again."
+msgstr ""
+
+msgid "IncidentManagement|Assign paging status"
+msgstr ""
+
+msgid "IncidentManagement|Assignees"
+msgstr ""
+
+msgid "IncidentManagement|Closed"
+msgstr ""
+
+msgid "IncidentManagement|Create incident"
+msgstr ""
+
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
+msgid "IncidentManagement|Date created"
+msgstr ""
+
+msgid "IncidentManagement|Display your incidents in a dedicated view"
+msgstr ""
+
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
+msgid "IncidentManagement|Incident"
+msgstr ""
+
+msgid "IncidentManagement|Incidents"
+msgstr ""
+
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
+msgid "IncidentManagement|Missed SLA"
+msgstr ""
+
+msgid "IncidentManagement|No incidents to display."
+msgstr ""
+
+msgid "IncidentManagement|None"
+msgstr ""
+
+msgid "IncidentManagement|Open"
+msgstr ""
+
+msgid "IncidentManagement|Page your team with escalation policies"
+msgstr ""
+
+msgid "IncidentManagement|Paged"
+msgstr ""
+
+msgid "IncidentManagement|Published"
+msgstr ""
+
+msgid "IncidentManagement|Published to status page"
+msgstr ""
+
+msgid "IncidentManagement|Resolved"
+msgstr ""
+
+msgid "IncidentManagement|Severity"
+msgstr ""
+
+msgid "IncidentManagement|Status"
+msgstr ""
+
+msgid "IncidentManagement|Stops paging"
+msgstr ""
+
+msgid "IncidentManagement|There are no closed incidents"
+msgstr ""
+
+msgid "IncidentManagement|There was an error displaying the incidents."
+msgstr ""
+
+msgid "IncidentManagement|Time to SLA"
+msgstr ""
+
+msgid "IncidentManagement|Triggered"
+msgstr ""
+
+msgid "IncidentManagement|Unassigned"
+msgstr ""
+
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
+msgid "IncidentManagement|Unpublished"
+msgstr ""
+
+msgid "IncidentManagement|Use escalation policies to automatically page your team when incidents are created."
+msgstr ""
+
+msgid "IncidentSettings|Activate \"time to SLA\" countdown timer"
+msgstr ""
+
+msgid "IncidentSettings|Fine-tune incident settings and set up integrations with external tools to help better manage incidents."
+msgstr ""
+
+msgid "IncidentSettings|Grafana integration"
+msgstr ""
+
+msgid "IncidentSettings|Incident settings"
+msgstr ""
+
+msgid "IncidentSettings|Incidents"
+msgstr ""
+
+msgid "IncidentSettings|Introduce a countdown timer in incident issues to better track Service Level Agreements (SLAs). The timer starts automatically when the incident is created, and sets a time limit for resolving the incident. When activated, the time to SLA countdown appears on all new incidents."
+msgstr ""
+
+msgid "IncidentSettings|PagerDuty integration"
+msgstr ""
+
+msgid "IncidentSettings|Time limit"
+msgstr ""
+
+msgid "IncidentSettings|Time limit must be a multiple of 15 minutes."
+msgstr ""
+
+msgid "IncidentSettings|Time limit must be a valid number."
+msgstr ""
+
+msgid "IncidentSettings|Time limit must be greater than 0."
+msgstr ""
+
+msgid "IncidentSettings|When activated, this applies to all new incidents in the project."
+msgstr ""
+
+msgid "IncidentSettings|hours"
+msgstr ""
+
+msgid "IncidentSettings|minutes"
+msgstr ""
+
+msgid "Incidents"
+msgstr ""
+
+msgid "Incidents|Add image details"
+msgstr ""
+
+msgid "Incidents|Add text or a link to display with your image. If you don't add either, the file name displays instead."
+msgstr ""
+
+msgid "Incidents|Drop or %{linkStart}upload%{linkEnd} a metric screenshot to attach it to the incident"
+msgstr ""
+
+msgid "Incidents|Must start with http or https"
+msgstr ""
+
+msgid "Incident|Add new timeline event"
+msgstr ""
+
+msgid "Incident|Adding an event tag associates the timeline comment with specific incident metrics."
+msgstr ""
+
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Are you sure you want to delete this event?"
+msgstr ""
+
+msgid "Incident|Are you sure you wish to delete this image?"
+msgstr ""
+
+msgid "Incident|Delete event"
+msgstr ""
+
+msgid "Incident|Delete image"
+msgstr ""
+
+msgid "Incident|Deleting %{filename}"
+msgstr ""
+
+msgid "Incident|Edit image text or link"
+msgstr ""
+
+msgid "Incident|Editing %{filename}"
+msgstr ""
+
+msgid "Incident|Error creating incident timeline event: %{error}"
+msgstr ""
+
+msgid "Incident|Error deleting incident timeline event: %{error}"
+msgstr ""
+
+msgid "Incident|Error updating incident timeline event: %{error}"
+msgstr ""
+
+msgid "Incident|Event tag"
+msgstr ""
+
+msgid "Incident|Incident"
+msgstr ""
+
+msgid "Incident|Metrics"
+msgstr ""
+
+msgid "Incident|No timeline items have been added yet."
+msgstr ""
+
+msgid "Incident|Save and add another event"
+msgstr ""
+
+msgid "Incident|Something went wrong while creating the incident timeline event."
+msgstr ""
+
+msgid "Incident|Something went wrong while deleting the incident timeline event."
+msgstr ""
+
+msgid "Incident|Something went wrong while fetching incident timeline events."
+msgstr ""
+
+msgid "Incident|Something went wrong while updating the incident timeline event."
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
+msgid "Incident|There was an issue loading incident data. Please try again."
+msgstr ""
+
+msgid "Incident|Timeline"
+msgstr ""
+
+msgid "Incident|Timeline text"
+msgstr ""
+
+msgid "Incident|Timeline text..."
+msgstr ""
+
+msgid "Include author name in notification email body"
+msgstr ""
+
+msgid "Include description in commit message"
+msgstr ""
+
+msgid "Include new features from all tiers."
+msgstr ""
+
+msgid "Include the name of the author of the issue, merge request or comment in the email body. By default, GitLab overrides the email sender's name. Some email servers don't support that option."
+msgstr ""
+
+msgid "Include the username in the URL if required: %{code_open}https://username@gitlab.company.com/group/project.git%{code_close}."
+msgstr ""
+
+msgid "Includes LFS objects. It can be overridden per group, or per project. Set to 0 for no limit."
+msgstr ""
+
+msgid "Includes an MVC structure to help you get started"
+msgstr ""
+
+msgid "Includes an MVC structure, Gemfile, Rakefile, along with many others, to help you get started"
+msgstr ""
+
+msgid "Includes an MVC structure, mvnw and pom.xml to help you get started"
+msgstr ""
+
+msgid "Incoming email"
+msgstr ""
+
+msgid "Incoming!"
+msgstr ""
+
+msgid "Incompatible options set!"
+msgstr ""
+
+msgid "Incompatible project"
+msgstr ""
+
+msgid "Incomplete"
+msgstr ""
+
+msgid "Increase"
+msgstr ""
+
+msgid "Increment suggestion line end"
+msgstr ""
+
+msgid "Increment suggestion line start"
+msgstr ""
+
+msgid "Incubation|%{featureName} is in incubating phase"
+msgstr ""
+
+msgid "Incubation|GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited."
+msgstr ""
+
+msgid "Incubation|Give feedback on this feature"
+msgstr ""
+
+msgid "Incubation|Learn more about incubating features"
+msgstr ""
+
+msgid "Indent line"
+msgstr ""
+
+msgid "Index"
+msgstr ""
+
+msgid "Index all projects"
+msgstr ""
+
+msgid "Index deletion is canceled"
+msgstr ""
+
+msgid "Indicates whether this runner can pick jobs without tags"
+msgstr ""
+
+msgid "Inform users without uploaded SSH keys that they can't push over SSH until one is added"
+msgstr ""
+
+msgid "Infrastructure"
+msgstr ""
+
+msgid "Infrastructure Registry"
+msgstr ""
+
+msgid "Infrastructure as Code (IaC) Scanning"
+msgstr ""
+
+msgid "InfrastructureRegistry|Copy Terraform Command"
+msgstr ""
+
+msgid "InfrastructureRegistry|Copy Terraform Setup Command"
+msgstr ""
+
+msgid "InfrastructureRegistry|Copy and paste into your Terraform configuration, insert the variables, and run Terraform init:"
+msgstr ""
+
+msgid "InfrastructureRegistry|For more information on the Terraform registry, %{linkStart}see our documentation%{linkEnd}."
+msgstr ""
+
+msgid "InfrastructureRegistry|Publish and share your modules. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
+msgid "InfrastructureRegistry|Terraform"
+msgstr ""
+
+msgid "InfrastructureRegistry|Terraform Module Registry"
+msgstr ""
+
+msgid "InfrastructureRegistry|Terraform modules are the main way to package and reuse resource configurations with Terraform. Learn more about how to %{noPackagesLinkStart}create Terraform modules%{noPackagesLinkEnd} in GitLab."
+msgstr ""
+
+msgid "InfrastructureRegistry|To authorize access to the Terraform registry:"
+msgstr ""
+
+msgid "InfrastructureRegistry|You have no Terraform modules in your project"
+msgstr ""
+
+msgid "Inherited"
+msgstr ""
+
+msgid "Inherited:"
+msgstr ""
+
+msgid "Inheriting from 'parent' is not yet supported"
+msgstr ""
+
+msgid "Initial default branch name"
+msgstr ""
+
+msgid "Initial default branch protection"
+msgstr ""
+
+msgid "Inline"
+msgstr ""
+
+msgid "Inline math"
+msgstr ""
+
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Input host keys manually"
+msgstr ""
+
+msgid "Input the remote repository URL"
+msgstr ""
+
+msgid "Insert"
+msgstr ""
+
+msgid "Insert a %{rows}×%{cols} table"
+msgstr ""
+
+msgid "Insert a quote"
+msgstr ""
+
+msgid "Insert code"
+msgstr ""
+
+msgid "Insert column after"
+msgstr ""
+
+msgid "Insert column before"
+msgstr ""
+
+msgid "Insert comment template"
+msgstr ""
+
+msgid "Insert link (%{modifierKey}K)"
+msgstr ""
+
+msgid "Insert or edit diagram"
+msgstr ""
+
+msgid "Insert row after"
+msgstr ""
+
+msgid "Insert row before"
+msgstr ""
+
+msgid "Insert suggestion"
+msgstr ""
+
+msgid "Insert table"
+msgstr ""
+
+msgid "Insights"
+msgstr ""
+
+msgid "Insights|Configure a custom report for insights into your group processes such as amount of issues, bugs, and merge requests per month. %{linkStart}How do I configure an insights report?%{linkEnd}"
+msgstr ""
+
+msgid "Insights|Some items are not visible beacuse the project was filtered out in the insights.yml file (see the projects.only config in the YAML file or the enabled project features (issues, merge requests) in the project settings)."
+msgstr ""
+
+msgid "Insights|This project is filtered out in the insights.yml file (see the projects.only config for more information)."
+msgstr ""
+
+msgid "Install GitLab Runner and ensure it's running."
+msgstr ""
+
+msgid "Installation"
+msgstr ""
+
+msgid "Instance"
+msgid_plural "Instances"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Instance Configuration"
+msgstr ""
+
+msgid "Instance access request"
+msgstr ""
+
+msgid "Instance access request approved"
+msgstr ""
+
+msgid "Instance access request rejected"
+msgstr ""
+
+msgid "Instance audit events"
+msgstr ""
+
+msgid "Instance overview"
+msgstr ""
+
+msgid "Insufficient permissions"
+msgstr ""
+
+msgid "Insufficient permissions for dast_configuration keyword"
+msgstr ""
+
+msgid "Integration"
+msgstr ""
+
+msgid "Integration Settings"
+msgstr ""
+
+msgid "IntegrationEvents|A comment is added"
+msgstr ""
+
+msgid "IntegrationEvents|A confidential issue is created, closed, or reopened"
+msgstr ""
+
+msgid "IntegrationEvents|A deployment is started or finished"
+msgstr ""
+
+msgid "IntegrationEvents|A merge request is created, merged, closed, or reopened"
+msgstr ""
+
+msgid "IntegrationEvents|A new, unique alert is recorded"
+msgstr ""
+
+msgid "IntegrationEvents|A new, unique vulnerability is recorded (available only in GitLab Ultimate)"
+msgstr ""
+
+msgid "IntegrationEvents|A pipeline status changes"
+msgstr ""
+
+msgid "IntegrationEvents|A push is made to the repository"
+msgstr ""
+
+msgid "IntegrationEvents|A tag is pushed to the repository or removed"
+msgstr ""
+
+msgid "IntegrationEvents|A wiki page is created or updated"
+msgstr ""
+
+msgid "IntegrationEvents|An incident is created, closed, or reopened"
+msgstr ""
+
+msgid "IntegrationEvents|An internal note or comment on a confidential issue is added"
+msgstr ""
+
+msgid "IntegrationEvents|An issue is created, closed, or reopened"
+msgstr ""
+
+msgid "Integrations"
+msgstr ""
+
+msgid "Integrations|%{integrationTitle}: active"
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
+msgid "Integrations|Active integrations"
+msgstr ""
+
+msgid "Integrations|Add an integration"
+msgstr ""
+
+msgid "Integrations|All details"
+msgstr ""
+
+msgid "Integrations|All projects inheriting these settings will also be reset."
+msgstr ""
+
+msgid "Integrations|An application called %{integration_name} is requesting access to your GitLab account. This application was created by GitLab Inc."
+msgstr ""
+
+msgid "Integrations|An error occurred while loading projects using custom settings."
+msgstr ""
+
+msgid "Integrations|An event will be triggered when one of the following items happen."
+msgstr ""
+
+msgid "Integrations|Authorize %{integration_name} (%{user}) to use your account?"
+msgstr ""
+
+msgid "Integrations|Branches for which notifications are to be sent"
+msgstr ""
+
+msgid "Integrations|Clear if using a self-signed certificate."
+msgstr ""
+
+msgid "Integrations|Comment detail:"
+msgstr ""
+
+msgid "Integrations|Comment settings:"
+msgstr ""
+
+msgid "Integrations|Configure the scope of notifications."
+msgstr ""
+
+msgid "Integrations|Connection details"
+msgstr ""
+
+msgid "Integrations|Connection failed. Check your integration settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
+msgid "Integrations|Create new issue in Jira"
+msgstr ""
+
+msgid "Integrations|Create new issue in ZenTao"
+msgstr ""
+
+msgid "Integrations|Default settings are inherited from the group level."
+msgstr ""
+
+msgid "Integrations|Default settings are inherited from the instance level."
+msgstr ""
+
+msgid "Integrations|Drag your file here or %{linkStart}click to upload%{linkEnd}."
+msgstr ""
+
+msgid "Integrations|Drop your file to start the upload."
+msgstr ""
+
+msgid "Integrations|Edit project alias"
+msgstr ""
+
+msgid "Integrations|Enable SSL verification"
+msgstr ""
+
+msgid "Integrations|Enable comments"
+msgstr ""
+
+msgid "Integrations|Enable slash commands and notifications for a Slack workspace."
+msgstr ""
+
+msgid "Integrations|Enter your alias"
+msgstr ""
+
+msgid "Integrations|Error: You are trying to upload something other than an allowed file."
+msgstr ""
+
+msgid "Integrations|GitLab administrators can set up integrations that all groups and projects inherit and use by default. These integrations apply to all groups and projects that don't already use custom settings. You can override custom settings for a group or project if the settings are necessary at that level. Learn more about %{integrations_link_start}instance-level integration management%{link_end}."
+msgstr ""
+
+msgid "Integrations|GitLab administrators can set up integrations that all projects in a group inherit and use by default. These integrations apply to all projects that don't already use custom settings. You can override custom settings for a project if the settings are necessary at that level. Learn more about %{integrations_link_start}group-level integration management%{link_end}."
+msgstr ""
+
+msgid "Integrations|GitLab for Slack app"
+msgstr ""
+
+msgid "Integrations|GitLab for Slack app must be reinstalled to enable notifications"
+msgstr ""
+
+msgid "Integrations|Group-level integration management"
+msgstr ""
+
+msgid "Integrations|Includes Standard, plus the entire commit message, commit hash, and issue IDs"
+msgstr ""
+
+msgid "Integrations|Includes commit title and branch."
+msgstr ""
+
+msgid "Integrations|Instance-level integration management"
+msgstr ""
+
+msgid "Integrations|Integration details"
+msgstr ""
+
+msgid "Integrations|Issues created in Jira are shown here once you have created the issues in project setup in Jira."
+msgstr ""
+
+msgid "Integrations|Keep your PHP dependencies updated on Packagist."
+msgstr ""
+
+msgid "Integrations|Mattermost slash commands"
+msgstr ""
+
+msgid "Integrations|Notification settings"
+msgstr ""
+
+msgid "Integrations|Perform common tasks with slash commands."
+msgstr ""
+
+msgid "Integrations|Projects using custom settings"
+msgstr ""
+
+msgid "Integrations|Projects using custom settings will not be affected."
+msgstr ""
+
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use parent level defaults."
+msgstr ""
+
+msgid "Integrations|Reset integration?"
+msgstr ""
+
+msgid "Integrations|Resetting this integration will clear the settings and deactivate this integration."
+msgstr ""
+
+msgid "Integrations|Restrict to branch (optional)"
+msgstr ""
+
+msgid "Integrations|SSL verification"
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
+msgid "Integrations|Search Jira issues"
+msgstr ""
+
+msgid "Integrations|Search ZenTao issues"
+msgstr ""
+
+msgid "Integrations|Send notifications about project events to Unify Circuit."
+msgstr ""
+
+msgid "Integrations|Send notifications about project events to a Unify Circuit conversation. %{docs_link}"
+msgstr ""
+
+msgid "Integrations|Standard"
+msgstr ""
+
+msgid "Integrations|There are no projects using custom settings"
+msgstr ""
+
+msgid "Integrations|This integration, and inheriting projects were reset."
+msgstr ""
+
+msgid "Integrations|To keep this project going, create a new issue."
+msgstr ""
+
+msgid "Integrations|Trigger"
+msgstr ""
+
+msgid "Integrations|Unable to post to %{channel_list}, please add the GitLab Slack app to any private Slack channels"
+msgstr ""
+
+msgid "Integrations|Use custom settings"
+msgstr ""
+
+msgid "Integrations|Use default settings"
+msgstr ""
+
+msgid "Integrations|You can close this window."
+msgstr ""
+
+msgid "Integrations|You can use this alias in your Slack commands"
+msgstr ""
+
+msgid "Integrations|You haven't activated any integrations yet."
+msgstr ""
+
+msgid "Integrations|You've activated every integration 🎉"
+msgstr ""
+
+msgid "Integrations|ZenTao issues display here when you create issues in your project in ZenTao."
+msgstr ""
+
+msgid "Integrations|can't exceed %{recipients_limit}"
+msgstr ""
+
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
+msgid "IntelliJ IDEA (HTTPS)"
+msgstr ""
+
+msgid "IntelliJ IDEA (SSH)"
+msgstr ""
+
+msgid "Interactive mode"
+msgstr ""
+
+msgid "Interested parties can even contribute by pushing commits if they want to."
+msgstr ""
+
+msgid "Internal"
+msgstr ""
+
+msgid "Internal - The group and any internal projects can be viewed by any logged in user except external users."
+msgstr ""
+
+msgid "Internal - The project can be accessed by any logged in user except external users."
+msgstr ""
+
+msgid "Internal error occurred while delivering this webhook."
+msgstr ""
+
+msgid "Internal note"
+msgstr ""
+
+msgid "Internal users"
+msgstr ""
+
+msgid "Internal users cannot be deactivated"
+msgstr ""
+
+msgid "Interval"
+msgstr ""
+
+msgid "Introducing Your DevOps Reports"
+msgstr ""
+
+msgid "Invalid 'schemaVersion' '%{schema_version}'"
+msgstr ""
+
+msgid "Invalid Insights config file detected"
+msgstr ""
+
+msgid "Invalid OS"
+msgstr ""
+
+msgid "Invalid URL"
+msgstr ""
+
+msgid "Invalid URL: %{url}"
+msgstr ""
+
+msgid "Invalid context type. %{type} is expected."
+msgstr ""
+
+msgid "Invalid date"
+msgstr ""
+
+msgid "Invalid date format. Please use UTC format as YYYY-MM-DD"
+msgstr ""
+
+msgid "Invalid date range"
+msgstr ""
+
+msgid "Invalid dates set"
+msgstr ""
+
+msgid "Invalid feature"
+msgstr ""
+
+msgid "Invalid field"
+msgstr ""
+
+msgid "Invalid file format with specified file type"
+msgstr ""
+
+msgid "Invalid file."
+msgstr ""
+
+msgid "Invalid format selected"
+msgstr ""
+
+msgid "Invalid hash"
+msgstr ""
+
+msgid "Invalid input, please avoid emoji"
+msgstr ""
+
+msgid "Invalid login or password"
+msgstr ""
+
+msgid "Invalid period"
+msgstr ""
+
+msgid "Invalid pin code."
+msgstr ""
+
+msgid "Invalid policy type"
+msgstr ""
+
+msgid "Invalid repository bundle for snippet with id %{snippet_id}"
+msgstr ""
+
+msgid "Invalid repository path"
+msgstr ""
+
+msgid "Invalid server response"
+msgstr ""
+
+msgid "Invalid status"
+msgstr ""
+
+msgid "Invalid tags"
+msgstr ""
+
+msgid "Invalid two-factor code."
+msgstr ""
+
+msgid "Invalidated"
+msgstr ""
+
+msgid "Investigate vulnerability: %{title}"
+msgstr ""
+
+msgid "Invisible Captcha"
+msgstr ""
+
+msgid "Invisible Captcha helps prevent the creation of spam accounts. It adds a honeypot field and time-sensitive form submission to the account signup form."
+msgstr ""
+
+msgid "Invitation"
+msgstr ""
+
+msgid "Invitation declined"
+msgstr ""
+
+msgid "Invite \"%{email}\" by email"
+msgstr ""
+
+msgid "Invite Members"
+msgstr ""
+
+msgid "Invite a group"
+msgstr ""
+
+msgid "Invite members"
+msgstr ""
+
+msgid "InviteEmail|%{inviter} invited you to join the %{project_or_group_name} %{project_or_group} as a %{role}"
+msgstr ""
+
+msgid "InviteEmail|%{inviter} invited you to join the %{strong_start}%{project_or_group_name}%{strong_end}%{br_tag}%{project_or_group} as a %{role}"
+msgstr ""
+
+msgid "InviteEmail|%{project_or_group} details"
+msgstr ""
+
+msgid "InviteEmail|Groups assemble related projects together and grant members access to several projects at once."
+msgstr ""
+
+msgid "InviteEmail|Join now"
+msgstr ""
+
+msgid "InviteEmail|Join your team on GitLab! %{inviter} invited you to %{project_or_group_name}"
+msgstr ""
+
+msgid "InviteEmail|Join your team on GitLab! You are invited to %{project_or_group_name}"
+msgstr ""
+
+msgid "InviteEmail|Projects are used to host and collaborate on code, track issues, and continuously build, test, and deploy your app with built-in GitLab CI/CD."
+msgstr ""
+
+msgid "InviteEmail|What's it about?"
+msgstr ""
+
+msgid "InviteEmail|You are invited to join the %{strong_start}%{project_or_group_name}%{strong_end}%{br_tag}%{project_or_group} as a %{role}"
+msgstr ""
+
+msgid "InviteEmail|You have been invited to join the %{project_or_group_name} %{project_or_group} as a %{role}"
+msgstr ""
+
+msgid "InviteEmail|You were assigned the following tasks:"
+msgstr ""
+
+msgid "InviteEmail|and has assigned you the following tasks:"
+msgstr ""
+
+msgid "InviteMembersBanner|Collaborate with your team"
+msgstr ""
+
+msgid "InviteMembersBanner|Invite your colleagues"
+msgstr ""
+
+msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
+msgstr ""
+
+msgid "InviteMembersModal| To get more members, the owner of this top-level group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
+msgstr ""
+
+msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Add unlimited members with your trial"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a project for the issues"
+msgstr ""
+
+msgid "InviteMembersModal|Close invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Congratulations on creating your project, you're almost there!"
+msgstr ""
+
+msgid "InviteMembersModal|Create issues for your new team member to work on (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|During your trial, you can invite as many members to %{groupName} as you like. When the trial ends, you'll have a maximum of %{dashboardLimit} members on the Free tier. To get more members, %{linkStart}upgrade to a paid plan%{linkEnd}."
+msgstr ""
+
+msgid "InviteMembersModal|GitLab is better with colleagues!"
+msgstr ""
+
+msgid "InviteMembersModal|How about inviting a colleague or two to join you?"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite a group"
+msgstr ""
+
+msgid "InviteMembersModal|Invite members"
+msgstr ""
+
+msgid "InviteMembersModal|Inviting a group %{linkStart}adds its members to your group%{linkEnd}, including members who join after the invite. This might put your group over the free %{count} user limit."
+msgstr ""
+
+msgid "InviteMembersModal|Inviting a group %{linkStart}adds its members to your project%{linkEnd}, including members who join after the invite. This might put your group over the free %{count} user limit."
+msgstr ""
+
+msgid "InviteMembersModal|Manage members"
+msgstr ""
+
+msgid "InviteMembersModal|Members were successfully added"
+msgstr ""
+
+msgid "InviteMembersModal|Please add members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|Review the invite errors and try again:"
+msgstr ""
+
+msgid "InviteMembersModal|Search for a group to invite"
+msgstr ""
+
+msgid "InviteMembersModal|Select a group to invite"
+msgstr ""
+
+msgid "InviteMembersModal|Select a role"
+msgstr ""
+
+msgid "InviteMembersModal|Select members or type email addresses"
+msgstr ""
+
+msgid "InviteMembersModal|Show less"
+msgstr ""
+
+msgid "InviteMembersModal|Show more (%{count})"
+msgstr ""
+
+msgid "InviteMembersModal|Something went wrong"
+msgstr ""
+
+msgid "InviteMembersModal|The following %{errorMembersLength} out of %{totalMembersCount} members could not be added"
+msgstr ""
+
+msgid "InviteMembersModal|The following member couldn't be invited"
+msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
+msgstr ""
+
+msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
+msgstr ""
+
+msgid "InviteMembersModal|To invite new users to this top-level group, you must remove existing users. You can still add existing users from the top-level group, including any subgroups and projects."
+msgstr ""
+
+msgid "InviteMembersModal|Username or email address"
+msgstr ""
+
+msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting a group to the %{strongStart}%{name}%{strongEnd} group."
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting a group to the %{strongStart}%{name}%{strongEnd} project."
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{strongStart}%{name}%{strongEnd} group."
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{strongStart}%{name}%{strongEnd} project."
+msgstr ""
+
+msgid "InviteMembersModal|You've reached your %{count} %{members} limit for %{name}"
+msgstr ""
+
+msgid "InviteMembers|Invite a group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
+msgid "InviteMember|Add members to this project and start collaborating with your team."
+msgstr ""
+
+msgid "InviteMember|Invite Members (optional)"
+msgstr ""
+
+msgid "InviteMember|Invite another member"
+msgstr ""
+
+msgid "InviteMember|Invite members"
+msgstr ""
+
+msgid "InviteMember|Invite your team"
+msgstr ""
+
+msgid "InviteMember|Invited users will be added with developer level permissions. %{linkStart}View the documentation%{linkEnd} to see how to change this later."
+msgstr ""
+
+msgid "InviteReminderEmail|%{inviter} is still waiting for you to join GitLab"
+msgstr ""
+
+msgid "InviteReminderEmail|%{inviter} is waiting for you to join GitLab"
+msgstr ""
+
+msgid "InviteReminderEmail|%{inviter} is waiting for you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}."
+msgstr ""
+
+msgid "InviteReminderEmail|%{inviter}'s invitation to GitLab is pending"
+msgstr ""
+
+msgid "InviteReminderEmail|Accept invitation"
+msgstr ""
+
+msgid "InviteReminderEmail|Accept invitation: %{invite_url}"
+msgstr ""
+
+msgid "InviteReminderEmail|Decline invitation"
+msgstr ""
+
+msgid "InviteReminderEmail|Decline invitation: %{decline_url}"
+msgstr ""
+
+msgid "InviteReminderEmail|Hey there %{wave_emoji}"
+msgstr ""
+
+msgid "InviteReminderEmail|Hey there!"
+msgstr ""
+
+msgid "InviteReminderEmail|In case you missed it..."
+msgstr ""
+
+msgid "InviteReminderEmail|Invitation pending"
+msgstr ""
+
+msgid "InviteReminderEmail|It's been %{invitation_age} days since %{inviter} invited you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}. What would you like to do?"
+msgstr ""
+
+msgid "InviteReminderEmail|This is a friendly reminder that %{inviter} invited you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}."
+msgstr ""
+
+msgid "Invited"
+msgstr ""
+
+msgid "Invited group allowed email domains must contain a subset of the allowed email domains of the root ancestor group. Go to the group's 'Settings &gt; General' page and check 'Restrict membership by email domain'."
+msgstr ""
+
+msgid "IrkerService|Channels and users separated by whitespaces. %{recipients_docs_link}"
+msgstr ""
+
+msgid "IrkerService|Default IRC URI (optional)"
+msgstr ""
+
+msgid "IrkerService|How to enter channels or users?"
+msgstr ""
+
+msgid "IrkerService|Recipients"
+msgstr ""
+
+msgid "IrkerService|Send update messages to an irker server."
+msgstr ""
+
+msgid "IrkerService|Send update messages to an irker server. Before you can use this, you need to set up the irker daemon. %{docs_link}"
+msgstr ""
+
+msgid "IrkerService|Server host (optional)"
+msgstr ""
+
+msgid "IrkerService|Server port (optional)"
+msgstr ""
+
+msgid "IrkerService|URI to add before each recipient."
+msgstr ""
+
+msgid "IrkerService|irker (IRC gateway)"
+msgstr ""
+
+msgid "IrkerService|irker daemon hostname (defaults to localhost)."
+msgstr ""
+
+msgid "IrkerService|irker daemon port (defaults to 6659)."
+msgstr ""
+
+msgid "Is blocked by"
+msgstr ""
+
+msgid "Is using license seat:"
+msgstr ""
+
+msgid "Is using seat"
+msgstr ""
+
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
+msgid "IssuableEvents|removed review request for"
+msgstr ""
+
+msgid "IssuableEvents|requested review from"
+msgstr ""
+
+msgid "IssuableEvents|resolved all threads"
+msgstr ""
+
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
+msgid "IssuableStatus|Closed"
+msgstr ""
+
+msgid "IssuableStatus|Closed (%{link})"
+msgstr ""
+
+msgid "IssuableStatus|duplicated"
+msgstr ""
+
+msgid "IssuableStatus|moved"
+msgstr ""
+
+msgid "IssuableStatus|promoted"
+msgstr ""
+
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
+msgid "Issue"
+msgstr ""
+
+msgid "Issue %{issue_reference} has already been added to epic %{epic_reference}."
+msgstr ""
+
+msgid "Issue Analytics"
+msgstr ""
+
+msgid "Issue Boards"
+msgstr ""
+
+msgid "Issue ID"
+msgstr ""
+
+msgid "Issue Type"
+msgstr ""
+
+msgid "Issue already promoted to epic."
+msgstr ""
+
+msgid "Issue analytics"
+msgstr ""
+
+msgid "Issue board"
+msgstr ""
+
+msgid "Issue boards"
+msgstr ""
+
+msgid "Issue cannot be found."
+msgstr ""
+
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
+msgid "Issue creation requests"
+msgstr ""
+
+msgid "Issue details"
+msgstr ""
+
+msgid "Issue events"
+msgstr ""
+
+msgid "Issue first deployed to production"
+msgstr ""
+
+msgid "Issue has been promoted to incident"
+msgstr ""
+
+msgid "Issue label"
+msgstr ""
+
+msgid "Issue or merge request ID is required"
+msgstr ""
+
+msgid "Issue published on status page."
+msgstr ""
+
+msgid "Issue summary"
+msgstr ""
+
+msgid "Issue title"
+msgstr ""
+
+msgid "Issue type"
+msgstr ""
+
+msgid "Issue types"
+msgstr ""
+
+msgid "Issue update failed"
+msgstr ""
+
+msgid "Issue was closed by %{name} %{reason}"
+msgstr ""
+
+msgid "Issue weight"
+msgstr ""
+
+msgid "IssueAnalytics|Age"
+msgstr ""
+
+msgid "IssueAnalytics|Assignees"
+msgstr ""
+
+msgid "IssueAnalytics|Created by"
+msgstr ""
+
+msgid "IssueAnalytics|Due date"
+msgstr ""
+
+msgid "IssueAnalytics|Failed to load issues. Please try again."
+msgstr ""
+
+msgid "IssueAnalytics|Issue"
+msgstr ""
+
+msgid "IssueAnalytics|Iteration"
+msgstr ""
+
+msgid "IssueAnalytics|Milestone"
+msgstr ""
+
+msgid "IssueAnalytics|Status"
+msgstr ""
+
+msgid "IssueAnalytics|Weight"
+msgstr ""
+
+msgid "IssueBoards|Board"
+msgstr ""
+
+msgid "IssueBoards|Boards"
+msgstr ""
+
+msgid "IssueBoards|Create new board"
+msgstr ""
+
+msgid "IssueBoards|Delete board"
+msgstr ""
+
+msgid "IssueBoards|No matching boards found"
+msgstr ""
+
+msgid "IssueBoards|Some of your boards are hidden, add a license to see them again."
+msgstr ""
+
+msgid "IssueBoards|Switch board"
+msgstr ""
+
+msgid "IssueList|created %{timeAgoString} by %{user}"
+msgstr ""
+
+msgid "IssueTracker|Custom issue tracker"
+msgstr ""
+
+msgid "IssueTracker|Issue URL"
+msgstr ""
+
+msgid "IssueTracker|New issue URL"
+msgstr ""
+
+msgid "IssueTracker|The URL to create an issue in the external issue tracker."
+msgstr ""
+
+msgid "IssueTracker|The URL to the project in the external issue tracker."
+msgstr ""
+
+msgid "IssueTracker|The URL to view an issue in the external issue tracker. Must contain %{colon_id}."
+msgstr ""
+
+msgid "IssueTracker|Use Bugzilla as this project's issue tracker."
+msgstr ""
+
+msgid "IssueTracker|Use Bugzilla as this project's issue tracker. %{docs_link}"
+msgstr ""
+
+msgid "IssueTracker|Use ClickUp as this project's issue tracker. %{docs_link}"
+msgstr ""
+
+msgid "IssueTracker|Use Clickup as this project's issue tracker."
+msgstr ""
+
+msgid "IssueTracker|Use IBM Engineering Workflow Management as this project's issue tracker."
+msgstr ""
+
+msgid "IssueTracker|Use IBM Engineering Workflow Management as this project's issue tracker. %{docs_link}"
+msgstr ""
+
+msgid "IssueTracker|Use Redmine as the issue tracker. %{docs_link}"
+msgstr ""
+
+msgid "IssueTracker|Use Redmine as this project's issue tracker."
+msgstr ""
+
+msgid "IssueTracker|Use YouTrack as this project's issue tracker."
+msgstr ""
+
+msgid "IssueTracker|Use YouTrack as this project's issue tracker. %{docs_link}"
+msgstr ""
+
+msgid "IssueTracker|Use a custom issue tracker as this project's issue tracker."
+msgstr ""
+
+msgid "IssueTracker|Use a custom issue tracker that is not in the integration list. %{docs_link}"
+msgstr ""
+
+msgid "Issues"
+msgstr ""
+
+msgid "Issues Completed"
+msgstr ""
+
+msgid "Issues Rate Limits"
+msgstr ""
+
+msgid "Issues and merge requests"
+msgstr ""
+
+msgid "Issues are being rebalanced at the moment, so manual reordering is disabled."
+msgstr ""
+
+msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
+msgstr ""
+
+msgid "Issues closed"
+msgstr ""
+
+msgid "Issues exist in projects, so to create an issue, first create a project."
+msgstr ""
+
+msgid "Issues must match this scope to appear in this list."
+msgstr ""
+
+msgid "Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities"
+msgstr ""
+
+msgid "Issues with label %{label}"
+msgstr ""
+
+msgid "Issues with no epic assigned"
+msgstr ""
+
+msgid "Issues, merge requests, pushes, and comments."
+msgstr ""
+
+msgid "IssuesAnalytics|Avg/Month:"
+msgstr ""
+
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues created"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues created per month"
+msgstr ""
+
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
+
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr ""
+
+msgid "IssuesAnalytics|Total:"
+msgstr ""
+
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
+msgid "Issue|Title"
+msgstr ""
+
+msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
+msgstr ""
+
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
+msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
+msgstr ""
+
+msgid "It seems like the Dependency Scanning job ran successfully, but no dependencies have been detected in your project."
+msgstr ""
+
+msgid "It seems that there is currently no available data for code coverage"
+msgstr ""
+
+msgid "It's you"
+msgstr ""
+
+msgid "Italic (%{modifierKey}I)"
+msgstr ""
+
+msgid "Italic text"
+msgstr ""
+
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
+msgid "Iteration"
+msgstr ""
+
+msgid "Iteration cannot be created for cadence"
+msgstr ""
+
+msgid "Iteration changed to"
+msgstr ""
+
+msgid "Iteration lists not available with your current license"
+msgstr ""
+
+msgid "Iteration removed"
+msgstr ""
+
+msgid "Iteration updated"
+msgstr ""
+
+msgid "Iterations"
+msgstr ""
+
+msgid "Iterations cadence not found"
+msgstr ""
+
+msgid "Iterations cannot be manually added to cadences that use automatic scheduling"
+msgstr ""
+
+msgid "IterationsCadence|The automation start date must come after the active iteration %{iteration_dates}."
+msgstr ""
+
+msgid "IterationsCadence|The automation start date must come after the past iteration %{iteration_dates}."
+msgstr ""
+
+msgid "IterationsCadence|The automation start date would retroactively create a past iteration. %{start_date} is the earliest possible start date."
+msgstr ""
+
+msgid "Iterations|Add iteration"
+msgstr ""
+
+msgid "Iterations|All"
+msgstr ""
+
+msgid "Iterations|All scheduled iterations will remain scheduled even if you use a smaller number."
+msgstr ""
+
+msgid "Iterations|Automatic scheduling"
+msgstr ""
+
+msgid "Iterations|Automation start date"
+msgstr ""
+
+msgid "Iterations|Cadence configuration is invalid."
+msgstr ""
+
+msgid "Iterations|Cadence name"
+msgstr ""
+
+msgid "Iterations|Cancel"
+msgstr ""
+
+msgid "Iterations|Couldn't find iteration cadence"
+msgstr ""
+
+msgid "Iterations|Create cadence"
+msgstr ""
+
+msgid "Iterations|Create iteration"
+msgstr ""
+
+msgid "Iterations|Create iterations automatically on a regular schedule."
+msgstr ""
+
+msgid "Iterations|Delete cadence"
+msgstr ""
+
+msgid "Iterations|Delete iteration cadence?"
+msgstr ""
+
+msgid "Iterations|Delete iteration?"
+msgstr ""
+
+msgid "Iterations|Description"
+msgstr ""
+
+msgid "Iterations|Done"
+msgstr ""
+
+msgid "Iterations|Due date"
+msgstr ""
+
+msgid "Iterations|Duration"
+msgstr ""
+
+msgid "Iterations|Edit cadence"
+msgstr ""
+
+msgid "Iterations|Edit iteration"
+msgstr ""
+
+msgid "Iterations|Edit iteration cadence"
+msgstr ""
+
+msgid "Iterations|Enable automatic scheduling"
+msgstr ""
+
+msgid "Iterations|Enable roll over"
+msgstr ""
+
+msgid "Iterations|Error loading iteration cadences."
+msgstr ""
+
+msgid "Iterations|Incomplete issues will be added to the next iteration at %{strongStart}midnight, %{timezone}%{strongEnd}."
+msgstr ""
+
+msgid "Iterations|Iteration cadences"
+msgstr ""
+
+msgid "Iterations|Iterations are scheduled to start on %{weekday}s."
+msgstr ""
+
+msgid "Iterations|New iteration"
+msgstr ""
+
+msgid "Iterations|New iteration cadence"
+msgstr ""
+
+msgid "Iterations|No closed iterations."
+msgstr ""
+
+msgid "Iterations|No iteration cadences to show."
+msgstr ""
+
+msgid "Iterations|No iterations found"
+msgstr ""
+
+msgid "Iterations|No iterations in cadence."
+msgstr ""
+
+msgid "Iterations|No open iterations."
+msgstr ""
+
+msgid "Iterations|Number of upcoming iterations that should be scheduled at a time."
+msgstr ""
+
+msgid "Iterations|Open"
+msgstr ""
+
+msgid "Iterations|Roll over issues"
+msgstr ""
+
+msgid "Iterations|Save changes"
+msgstr ""
+
+msgid "Iterations|Select duration"
+msgstr ""
+
+msgid "Iterations|Select number"
+msgstr ""
+
+msgid "Iterations|Select start date"
+msgstr ""
+
+msgid "Iterations|Start date"
+msgstr ""
+
+msgid "Iterations|The date of the first iteration to schedule. This date determines the day of the week when each iteration starts."
+msgstr ""
+
+msgid "Iterations|The duration of each iteration (in weeks)."
+msgstr ""
+
+msgid "Iterations|The iteration has been deleted."
+msgstr ""
+
+msgid "Iterations|This will delete the cadence as well as all of the iterations within it."
+msgstr ""
+
+msgid "Iterations|This will remove the iteration from any issues that are assigned to it."
+msgstr ""
+
+msgid "Iterations|Title"
+msgstr ""
+
+msgid "Iterations|Unable to find iteration cadence."
+msgstr ""
+
+msgid "Iterations|Unable to find iteration."
+msgstr ""
+
+msgid "Iterations|Unable to save cadence. Please try again."
+msgstr ""
+
+msgid "Iterations|Upcoming iterations"
+msgstr ""
+
+msgid "Iteration|Dates cannot overlap with other existing Iterations within this iterations cadence"
+msgstr ""
+
+msgid "Iteration|cannot be more than 500 years in the future"
+msgstr ""
+
+msgid "Jan"
+msgstr ""
+
+msgid "January"
+msgstr ""
+
+msgid "Japanese language support using"
+msgstr ""
+
+msgid "Jira display name"
+msgstr ""
+
+msgid "Jira import is already running."
+msgstr ""
+
+msgid "Jira integration not configured."
+msgstr ""
+
+msgid "Jira issue matching"
+msgstr ""
+
+msgid "Jira project key is not configured."
+msgstr ""
+
+msgid "Jira project: %{importProject}"
+msgstr ""
+
+msgid "Jira service not configured."
+msgstr ""
+
+msgid "Jira user"
+msgstr ""
+
+msgid "Jira users have been imported from the configured Jira instance. They can be mapped by selecting a GitLab user from the dropdown in the \"GitLab username\" column. When the form appears, the dropdown defaults to the user conducting the import."
+msgstr ""
+
+msgid "Jira-GitLab user mapping template"
+msgstr ""
+
+msgid "JiraConnect|Are you a GitLab administrator?"
+msgstr ""
+
+msgid "JiraConnect|Cannot find namespace. Make sure you have sufficient permissions."
+msgstr ""
+
+msgid "JiraConnect|Change GitLab version"
+msgstr ""
+
+msgid "JiraConnect|Configure your Jira Connect Application ID."
+msgstr ""
+
+msgid "JiraConnect|Continue setup in GitLab"
+msgstr ""
+
+msgid "JiraConnect|Could not fetch user information from Jira. Check the permissions in Jira and try again."
+msgstr ""
+
+msgid "JiraConnect|Create branch for Jira issue %{jiraIssue}"
+msgstr ""
+
+msgid "JiraConnect|Enable public key storage"
+msgstr ""
+
+msgid "JiraConnect|Ensure your instance URL is correct and your instance is configured correctly. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "JiraConnect|Failed to create branch."
+msgstr ""
+
+msgid "JiraConnect|Failed to create branch. Please try again."
+msgstr ""
+
+msgid "JiraConnect|Failed to link group. Please try again."
+msgstr ""
+
+msgid "JiraConnect|Failed to load Jira Connect Application ID. Please try again."
+msgstr ""
+
+msgid "JiraConnect|Failed to load groups. Please try again."
+msgstr ""
+
+msgid "JiraConnect|Failed to load subscriptions."
+msgstr ""
+
+msgid "JiraConnect|Failed to sign in to GitLab."
+msgstr ""
+
+msgid "JiraConnect|Failed to unlink group. Please try again."
+msgstr ""
+
+msgid "JiraConnect|Failed to update the GitLab instance. See the %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
+msgid "JiraConnect|For example: https://gitlab.example.com"
+msgstr ""
+
+msgid "JiraConnect|GitLab for Jira App"
+msgstr ""
+
+msgid "JiraConnect|GitLab for Jira Configuration"
+msgstr ""
+
+msgid "JiraConnect|GitLab instance URL"
+msgstr ""
+
+msgid "JiraConnect|Group successfully linked"
+msgstr ""
+
+msgid "JiraConnect|Groups are the GitLab groups and subgroups you link to this Jira instance."
+msgstr ""
+
+msgid "JiraConnect|In order to complete the set up, you’ll need to complete a few steps in GitLab."
+msgstr ""
+
+msgid "JiraConnect|Jira Connect Application ID"
+msgstr ""
+
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
+msgid "JiraConnect|Link groups"
+msgstr ""
+
+msgid "JiraConnect|Linked groups"
+msgstr ""
+
+msgid "JiraConnect|New branch was successfully created."
+msgstr ""
+
+msgid "JiraConnect|No groups found."
+msgstr ""
+
+msgid "JiraConnect|No linked groups"
+msgstr ""
+
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
+msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
+msgstr ""
+
+msgid "JiraConnect|Setting up this integration is only possible if you're a GitLab administrator."
+msgstr ""
+
+msgid "JiraConnect|Sign in to %{url}"
+msgstr ""
+
+msgid "JiraConnect|Sign in to GitLab to get started."
+msgstr ""
+
+msgid "JiraConnect|Sign in to GitLab to link groups."
+msgstr ""
+
+msgid "JiraConnect|Sign in to link groups"
+msgstr ""
+
+msgid "JiraConnect|Tell us what you think!"
+msgstr ""
+
+msgid "JiraConnect|The Jira user is not a site administrator. Check the permissions in Jira and try again."
+msgstr ""
+
+msgid "JiraConnect|We would love to learn more about your experience with the GitLab for Jira Cloud App."
+msgstr ""
+
+msgid "JiraConnect|Welcome to GitLab for Jira"
+msgstr ""
+
+msgid "JiraConnect|What version of GitLab are you using?"
+msgstr ""
+
+msgid "JiraConnect|You can now close this window and return to Jira."
+msgstr ""
+
+msgid "JiraConnect|You don't have permission to create branches for this project. Select a different project or contact the project owner for access. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "JiraConnect|You must use a %{linkStart}supported browser%{linkEnd} to use the GitLab for Jira app."
+msgstr ""
+
+msgid "JiraConnect|You should now see GitLab.com activity inside your Jira Cloud issues. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "JiraConnect|Your browser is not supported"
+msgstr ""
+
+msgid "JiraRequest|A connection error occurred while connecting to Jira. Try your request again."
+msgstr ""
+
+msgid "JiraRequest|A timeout error occurred while connecting to Jira. Try your request again."
+msgstr ""
+
+msgid "JiraRequest|An SSL error occurred while connecting to Jira: %{message}. Try your request again."
+msgstr ""
+
+msgid "JiraRequest|An error occurred while requesting data from Jira. Check your %{docs_link_start}Jira integration configuration%{docs_link_end} and try again."
+msgstr ""
+
+msgid "JiraRequest|An error occurred while requesting data from Jira: %{messages}. Check your %{docs_link_start}Jira integration configuration%{docs_link_end} and try again."
+msgstr ""
+
+msgid "JiraRequest|The Jira API URL for connecting to Jira is not valid. Check your Jira integration API URL and try again."
+msgstr ""
+
+msgid "JiraRequest|The credentials for accessing Jira are not allowed to access the data. Check your %{docs_link_start}Jira integration credentials%{docs_link_end} and try again."
+msgstr ""
+
+msgid "JiraRequest|The credentials for accessing Jira are not valid. Check your %{docs_link_start}Jira integration credentials%{docs_link_end} and try again."
+msgstr ""
+
+msgid "JiraService| on branch %{branch_link}"
+msgstr ""
+
+msgid "JiraService|%{jiraDocsLinkStart}Enable the Jira integration%{jiraDocsLinkEnd} to view your Jira issues in GitLab."
+msgstr ""
+
+msgid "JiraService|%{jira_docs_link_start}Enable the Jira integration%{jira_docs_link_end} to view your Jira issues in GitLab."
+msgstr ""
+
+msgid "JiraService|%{user_link} mentioned this issue in %{entity_link} of %{project_link}%{branch}:{quote}%{entity_message}{quote}"
+msgstr ""
+
+msgid "JiraService|API token for Jira Cloud or password for Jira Data Center and Jira Server"
+msgstr ""
+
+msgid "JiraService|API token or password"
+msgstr ""
+
+msgid "JiraService|An error occurred while fetching issue list"
+msgstr ""
+
+msgid "JiraService|Authentication type"
+msgstr ""
+
+msgid "JiraService|Automatically transitions Jira issues to the \"Done\" category. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "JiraService|Base URL of the Jira instance"
+msgstr ""
+
+msgid "JiraService|Basic"
+msgstr ""
+
+msgid "JiraService|Define the type of Jira issue to create from a vulnerability."
+msgstr ""
+
+msgid "JiraService|Displaying Jira issues while leaving GitLab issues also enabled might be confusing. Consider %{gitlab_issues_link_start}disabling GitLab issues%{link_end} if they won't otherwise be used."
+msgstr ""
+
+msgid "JiraService|Email for Jira Cloud or username for Jira Data Center and Jira Server"
+msgstr ""
+
+msgid "JiraService|Email or username"
+msgstr ""
+
+msgid "JiraService|Enable Jira issue creation from vulnerabilities"
+msgstr ""
+
+msgid "JiraService|Enable Jira issues"
+msgstr ""
+
+msgid "JiraService|Enable Jira transitions"
+msgstr ""
+
+msgid "JiraService|Events for %{noteable_model_name} are disabled."
+msgstr ""
+
+msgid "JiraService|Failed to load Jira issue. View the issue in Jira, or reload the page."
+msgstr ""
+
+msgid "JiraService|Fetch issue types for this Jira project"
+msgstr ""
+
+msgid "JiraService|For Jira Cloud, the authentication type must be %{basic}"
+msgstr ""
+
+msgid "JiraService|For example, 12, 24"
+msgstr ""
+
+msgid "JiraService|For example, AB"
+msgstr ""
+
+msgid "JiraService|IDs must be a list of numbers that can be split with , or ;"
+msgstr ""
+
+msgid "JiraService|If different from the Web URL"
+msgstr ""
+
+msgid "JiraService|Issues created from vulnerabilities in this project will be Jira issues, even if GitLab issues are enabled."
+msgstr ""
+
+msgid "JiraService|Jira API URL"
+msgstr ""
+
+msgid "JiraService|Jira comments are created when an issue is referenced in a commit."
+msgstr ""
+
+msgid "JiraService|Jira comments are created when an issue is referenced in a merge request."
+msgstr ""
+
+msgid "JiraService|Jira issue prefix"
+msgstr ""
+
+msgid "JiraService|Jira issue regex"
+msgstr ""
+
+msgid "JiraService|Jira issues"
+msgstr ""
+
+msgid "JiraService|Jira personal access token"
+msgstr ""
+
+msgid "JiraService|Jira personal access token (Jira Data Center and Jira Server only)"
+msgstr ""
+
+msgid "JiraService|Jira project key"
+msgstr ""
+
+msgid "JiraService|Leave blank to use your current configuration"
+msgstr ""
+
+msgid "JiraService|Move to Done"
+msgstr ""
+
+msgid "JiraService|New API token or password"
+msgstr ""
+
+msgid "JiraService|New Jira personal access token"
+msgstr ""
+
+msgid "JiraService|Open Jira"
+msgstr ""
+
+msgid "JiraService|Project key changed, refresh list"
+msgstr ""
+
+msgid "JiraService|Project key is required to generate issue types"
+msgstr ""
+
+msgid "JiraService|Recommended. Only available for Jira Data Center and Jira Server."
+msgstr ""
+
+msgid "JiraService|Select issue type"
+msgstr ""
+
+msgid "JiraService|Set a custom final state by using transition IDs. %{linkStart}Learn about transition IDs%{linkEnd}"
+msgstr ""
+
+msgid "JiraService|Sign in to GitLab to get started."
+msgstr ""
+
+msgid "JiraService|This feature requires a Premium plan."
+msgstr ""
+
+msgid "JiraService|Transition Jira issues to their final state:"
+msgstr ""
+
+msgid "JiraService|Use Jira as this project's issue tracker."
+msgstr ""
+
+msgid "JiraService|Use a prefix to match Jira issue keys."
+msgstr ""
+
+msgid "JiraService|Use custom transitions"
+msgstr ""
+
+msgid "JiraService|Use regular expression to match Jira issue keys."
+msgstr ""
+
+msgid "JiraService|Using Jira for issue tracking?"
+msgstr ""
+
+msgid "JiraService|Warning: All GitLab users with access to this GitLab project can view all issues from the Jira project you select."
+msgstr ""
+
+msgid "JiraService|Web URL"
+msgstr ""
+
+msgid "JiraService|When a Jira issue is mentioned in a commit or merge request, a remote link and comment (if enabled) will be created."
+msgstr ""
+
+msgid "JiraService|Work on Jira issues without leaving GitLab. Add a Jira menu to access a read-only list of your Jira issues."
+msgstr ""
+
+msgid "JiraService|Work on Jira issues without leaving GitLab. Add a Jira menu to access a read-only list of your Jira issues. %{jira_issues_link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "JiraService|You must configure Jira before enabling this integration. %{jira_doc_link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Job"
+msgstr ""
+
+msgid "Job %{jobName}"
+msgstr ""
+
+msgid "Job Failed #%{build_id}"
+msgstr ""
+
+msgid "Job artifacts"
+msgstr ""
+
+msgid "Job has been erased"
+msgstr ""
+
+msgid "Job has been successfully erased!"
+msgstr ""
+
+msgid "Job has wrong arguments format."
+msgstr ""
+
+msgid "Job is stuck. Check runners."
+msgstr ""
+
+msgid "Job logs and artifacts"
+msgstr ""
+
+msgid "Job was retried"
+msgstr ""
+
+msgid "JobAssistant|Add job"
+msgstr ""
+
+msgid "JobAssistant|Add path"
+msgstr ""
+
+msgid "JobAssistant|Add service"
+msgstr ""
+
+msgid "JobAssistant|Allow failure"
+msgstr ""
+
+msgid "JobAssistant|Artifacts and cache"
+msgstr ""
+
+msgid "JobAssistant|Artifacts exclude paths (optional)"
+msgstr ""
+
+msgid "JobAssistant|Artifacts paths (optional)"
+msgstr ""
+
+msgid "JobAssistant|Cache key (optional)"
+msgstr ""
+
+msgid "JobAssistant|Cache paths (optional)"
+msgstr ""
+
+msgid "JobAssistant|Error - Valid value is between 1 second and 1 week"
+msgstr ""
+
+msgid "JobAssistant|Image"
+msgstr ""
+
+msgid "JobAssistant|Image entrypoint (optional)"
+msgstr ""
+
+msgid "JobAssistant|Image name (optional)"
+msgstr ""
+
+msgid "JobAssistant|Include or exclude jobs in pipelines. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "JobAssistant|Input format"
+msgstr ""
+
+msgid "JobAssistant|Job Setup"
+msgstr ""
+
+msgid "JobAssistant|Job assistant"
+msgstr ""
+
+msgid "JobAssistant|Job name"
+msgstr ""
+
+msgid "JobAssistant|Please enter the parameters."
+msgstr ""
+
+msgid "JobAssistant|Please separate array type fields with new lines"
+msgstr ""
+
+msgid "JobAssistant|Rules"
+msgstr ""
+
+msgid "JobAssistant|Script"
+msgstr ""
+
+msgid "JobAssistant|Service entrypoint (optional)"
+msgstr ""
+
+msgid "JobAssistant|Service name (optional)"
+msgstr ""
+
+msgid "JobAssistant|Services"
+msgstr ""
+
+msgid "JobAssistant|Specify a Docker image that the job runs in. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "JobAssistant|Specify any additional Docker images that your scripts require to run successfully. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "JobAssistant|Specify the %{artifactsLinkStart}artifacts%{artifactsLinkEnd} and %{cacheLinkStart}cache%{cacheLinkEnd} of the job."
+msgstr ""
+
+msgid "JobAssistant|Stage (optional)"
+msgstr ""
+
+msgid "JobAssistant|Tags (optional)"
+msgstr ""
+
+msgid "JobAssistant|When"
+msgstr ""
+
+msgid "JobAssistant|always"
+msgstr ""
+
+msgid "JobAssistant|day(s)"
+msgstr ""
+
+msgid "JobAssistant|delayed"
+msgstr ""
+
+msgid "JobAssistant|manual"
+msgstr ""
+
+msgid "JobAssistant|minute(s)"
+msgstr ""
+
+msgid "JobAssistant|never"
+msgstr ""
+
+msgid "JobAssistant|on_failure"
+msgstr ""
+
+msgid "JobAssistant|on_success"
+msgstr ""
+
+msgid "JobAssistant|second(s)"
+msgstr ""
+
+msgid "JobAssistant|week(s)"
+msgstr ""
+
+msgid "Jobs"
+msgstr ""
+
+msgid "Jobs fail if they run longer than the timeout time. Input value is in seconds by default. Human readable input is also accepted, for example %{code_open}1 hour%{code_close}."
+msgstr ""
+
+msgid "Jobs older than the configured time are considered expired and are archived. Archived jobs can no longer be retried. Leave empty to never archive jobs automatically. The default unit is in days, but you can use other units, for example %{code_open}15 days%{code_close}, %{code_open}1 month%{code_close}, %{code_open}2 years%{code_close}. Minimum value is 1 day."
+msgstr ""
+
+msgid "Jobs|All"
+msgstr ""
+
+msgid "Jobs|Are you sure you want to proceed?"
+msgstr ""
+
+msgid "Jobs|Are you sure you want to retry this job?"
+msgstr ""
+
+msgid "Jobs|Create CI/CD configuration file"
+msgstr ""
+
+msgid "Jobs|Filter jobs"
+msgstr ""
+
+msgid "Jobs|Finished"
+msgstr ""
+
+msgid "Jobs|Job is stuck. Check runners."
+msgstr ""
+
+msgid "Jobs|Jobs are the building blocks of a GitLab CI/CD pipeline. Each job has a specific task, like testing code. To set up jobs in a CI/CD pipeline, add a CI/CD configuration file to your project."
+msgstr ""
+
+msgid "Jobs|No jobs to show"
+msgstr ""
+
+msgid "Jobs|Raw text search is not currently supported for the jobs filtered search feature. Please use the available search tokens."
+msgstr ""
+
+msgid "Jobs|Root cause analysis"
+msgstr ""
+
+msgid "Jobs|There was a problem fetching the failed jobs."
+msgstr ""
+
+msgid "Jobs|Use jobs to automate your tasks"
+msgstr ""
+
+msgid "Jobs|You're about to retry a job that failed because it attempted to deploy code that is older than the latest deployment. Retrying this job could result in overwriting the environment with the older source code."
+msgstr ""
+
+msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id}"
+msgstr ""
+
+msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source}"
+msgstr ""
+
+msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into %{target}"
+msgstr ""
+
+msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}"
+msgstr ""
+
+msgid "Job|%{searchLength} results found for %{searchTerm}"
+msgstr ""
+
+msgid "Job|Are you sure you want to erase this job log and artifacts?"
+msgstr ""
+
+msgid "Job|Browse"
+msgstr ""
+
+msgid "Job|Cancel"
+msgstr ""
+
+msgid "Job|Canceled"
+msgstr ""
+
+msgid "Job|Complete Raw"
+msgstr ""
+
+msgid "Job|Created"
+msgstr ""
+
+msgid "Job|Download"
+msgstr ""
+
+msgid "Job|Duration"
+msgstr ""
+
+msgid "Job|Erase job log and artifacts"
+msgstr ""
+
+msgid "Job|External links"
+msgstr ""
+
+msgid "Job|Failed"
+msgstr ""
+
+msgid "Job|Finished at"
+msgstr ""
+
+msgid "Job|Job artifacts"
+msgstr ""
+
+msgid "Job|Job artifacts are files that are configured to be uploaded when a job finishes execution. Artifacts could be compiled files, unit tests or scanning reports, or any other files generated by a job."
+msgstr ""
+
+msgid "Job|Job has been erased"
+msgstr ""
+
+msgid "Job|Job has been erased by %{userLink}"
+msgstr ""
+
+msgid "Job|Job log search"
+msgstr ""
+
+msgid "Job|Keep"
+msgstr ""
+
+msgid "Job|Manual"
+msgstr ""
+
+msgid "Job|No job log"
+msgstr ""
+
+msgid "Job|No search results found"
+msgstr ""
+
+msgid "Job|Passed"
+msgstr ""
+
+msgid "Job|Pending"
+msgstr ""
+
+msgid "Job|Preparing"
+msgstr ""
+
+msgid "Job|Queued"
+msgstr ""
+
+msgid "Job|Retry"
+msgstr ""
+
+msgid "Job|Run again"
+msgstr ""
+
+msgid "Job|Runner type"
+msgstr ""
+
+msgid "Job|Running"
+msgstr ""
+
+msgid "Job|Scheduled"
+msgstr ""
+
+msgid "Job|Scroll to bottom"
+msgstr ""
+
+msgid "Job|Scroll to next failure"
+msgstr ""
+
+msgid "Job|Scroll to top"
+msgstr ""
+
+msgid "Job|Search for substrings in your job log output. Currently search is only supported for the visible job log output, not for any log output that is truncated due to size."
+msgstr ""
+
+msgid "Job|Search job log"
+msgstr ""
+
+msgid "Job|Show complete raw"
+msgstr ""
+
+msgid "Job|Skipped"
+msgstr ""
+
+msgid "Job|Status"
+msgstr ""
+
+msgid "Job|The artifacts were removed"
+msgstr ""
+
+msgid "Job|The artifacts will be removed"
+msgstr ""
+
+msgid "Job|There was a problem retrying the failed job."
+msgstr ""
+
+msgid "Job|These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available."
+msgstr ""
+
+msgid "Job|This job failed because the necessary resources were not successfully created."
+msgstr ""
+
+msgid "Job|This job is stuck because of one of the following problems. There are no active runners online, no runners for the %{linkStart}protected branch%{linkEnd}, or no runners that match all of the job's tags:"
+msgstr ""
+
+msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it."
+msgstr ""
+
+msgid "Job|This job is stuck because you don't have any active runners that can run this job."
+msgstr ""
+
+msgid "Job|Update CI/CD variables"
+msgstr ""
+
+msgid "Job|Waiting for resource"
+msgstr ""
+
+msgid "Job|We could not find this element"
+msgstr ""
+
+msgid "Job|You cannot rerun trigger jobs from this list."
+msgstr ""
+
+msgid "Job|You do not have permission to read this job's log."
+msgstr ""
+
+msgid "Job|You do not have permission to run this job again."
+msgstr ""
+
+msgid "Job|allowed to fail"
+msgstr ""
+
+msgid "Job|delayed"
+msgstr ""
+
+msgid "Job|manual"
+msgstr ""
+
+msgid "Job|triggered"
+msgstr ""
+
+msgid "Join GitLab today! You and your team can plan, build, and ship secure code all in one application. Get started here for free!"
+msgstr ""
+
+msgid "Join Zoom meeting"
+msgstr ""
+
+msgid "Join a project"
+msgstr ""
+
+msgid "Join your team on GitLab and contribute to an existing project"
+msgstr ""
+
+msgid "Joined %{user_created_time}"
+msgstr ""
+
+msgid "Joined projects (%{projects_count})"
+msgstr ""
+
+msgid "Jul"
+msgstr ""
+
+msgid "July"
+msgstr ""
+
+msgid "Jun"
+msgstr ""
+
+msgid "June"
+msgstr ""
+
+msgid "Just me"
+msgstr ""
+
+msgid "KEY"
+msgstr ""
+
+msgid "Keep"
+msgstr ""
+
+msgid "Keep artifacts from most recent successful jobs"
+msgstr ""
+
+msgid "Keep divergent refs"
+msgstr ""
+
+msgid "Kerberos access denied"
+msgstr ""
+
+msgid "Key"
+msgstr ""
+
+msgid "Key (PEM)"
+msgstr ""
+
+msgid "Key details"
+msgstr ""
+
+msgid "Key result"
+msgstr ""
+
+msgid "Key:"
+msgstr ""
+
+msgid "Keyboard shortcuts"
+msgstr ""
+
+msgid "KeyboardKey|Alt"
+msgstr ""
+
+msgid "KeyboardKey|Ctrl"
+msgstr ""
+
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
+msgid "KeyboardKey|Enter"
+msgstr ""
+
+msgid "KeyboardKey|Esc"
+msgstr ""
+
+msgid "KeyboardKey|Shift"
+msgstr ""
+
+msgid "KeyboardShortcuts|No shortcuts matched your search"
+msgstr ""
+
+msgid "KeyboardShortcuts|Search keyboard shortcuts"
+msgstr ""
+
+msgid "Keys"
+msgstr ""
+
+msgid "Ki"
+msgstr ""
+
+msgid "Kroki"
+msgstr ""
+
+msgid "Kubernetes"
+msgstr ""
+
+msgid "Kubernetes Cluster"
+msgstr ""
+
+msgid "Kubernetes Clusters"
+msgstr ""
+
+msgid "Kubernetes cluster"
+msgstr ""
+
+msgid "Kubernetes cluster integration and resources are being removed."
+msgstr ""
+
+msgid "Kubernetes cluster integration was successfully removed."
+msgstr ""
+
+msgid "Kubernetes cluster was successfully updated."
+msgstr ""
+
+msgid "Kubernetes clusters"
+msgstr ""
+
+msgid "Kubernetes deployment not found"
+msgstr ""
+
+msgid "LDAP"
+msgstr ""
+
+msgid "LDAP Synchronization"
+msgstr ""
+
+msgid "LDAP group settings"
+msgstr ""
+
+msgid "LDAP settings"
+msgstr ""
+
+msgid "LDAP settings updated"
+msgstr ""
+
+msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
+msgstr ""
+
+msgid "LDAP synchronizations"
+msgstr ""
+
+msgid "LDAP uid:"
+msgstr ""
+
+msgid "LDAP|Add synchronization"
+msgstr ""
+
+msgid "LDAP|LDAP access"
+msgstr ""
+
+msgid "LDAP|LDAP group cn"
+msgstr ""
+
+msgid "LDAP|LDAP server"
+msgstr ""
+
+msgid "LDAP|LDAP user filter"
+msgstr ""
+
+msgid "LDAP|Sync method"
+msgstr ""
+
+msgid "LFS"
+msgstr ""
+
+msgid "LFS objects"
+msgstr ""
+
+msgid "LFSStatus|Disabled"
+msgstr ""
+
+msgid "LFSStatus|Enabled"
+msgstr ""
+
+msgid "LICENSE"
+msgstr ""
+
+msgid "Label"
+msgstr ""
+
+msgid "Label actions dropdown"
+msgstr ""
+
+msgid "Label added: %{labels}"
+msgid_plural "Labels added: %{labels}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Label priority"
+msgstr ""
+
+msgid "Label was created"
+msgstr ""
+
+msgid "Label was successfully updated."
+msgstr ""
+
+msgid "LabelSelect|%{firstLabelName} +%{remainingLabelCount} more"
+msgstr ""
+
+msgid "LabelSelect|%{labelsString}, and %{remainingLabelCount} more"
+msgstr ""
+
+msgid "LabelSelect|Labels"
+msgstr ""
+
+msgid "Labels"
+msgstr ""
+
+msgid "Labels can be applied to issues and merge requests to categorize them."
+msgstr ""
+
+msgid "Labels can be applied to issues and merge requests. Group labels are available for any project within the group."
+msgstr ""
+
+msgid "Labels can be applied to issues and merge requests. Star a label to make it a priority label."
+msgstr ""
+
+msgid "Labels can be applied to issues, merge requests, and epics. Group labels are available for any project within the group."
+msgstr ""
+
+msgid "Labels with no issues in this iteration:"
+msgstr ""
+
+msgid "Labels|%{spanStart}Promote label%{spanEnd} %{labelTitle} %{spanStart}to Group Label?%{spanEnd}"
+msgstr ""
+
+msgid "Labels|Promote Label"
+msgstr ""
+
+msgid "Labels|Promoting %{labelTitle} will make it available for all projects inside %{groupName}. Existing project labels with the same title will be merged. If a group label with the same title exists, it will also be merged. This action cannot be reversed."
+msgstr ""
+
+msgid "Label|Assignee"
+msgstr ""
+
+msgid "Language"
+msgstr ""
+
+msgid "Language type"
+msgstr ""
+
+msgid "Large File Storage"
+msgstr ""
+
+msgid "Last %d day"
+msgid_plural "Last %d days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Last %{days} days"
+msgstr ""
+
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 24 hours"
+msgstr ""
+
+msgid "Last Accessed On"
+msgstr ""
+
+msgid "Last Activity"
+msgstr ""
+
+msgid "Last Name"
+msgstr ""
+
+msgid "Last Seen"
+msgstr ""
+
+msgid "Last Used"
+msgstr ""
+
+msgid "Last accessed on"
+msgstr ""
+
+msgid "Last activity"
+msgstr ""
+
+msgid "Last commit"
+msgstr ""
+
+msgid "Last contact"
+msgstr ""
+
+msgid "Last edited %{date}"
+msgstr ""
+
+msgid "Last edited by %{link_start}%{avatar} %{name}%{link_end}"
+msgstr ""
+
+msgid "Last event"
+msgstr ""
+
+msgid "Last login"
+msgstr ""
+
+msgid "Last modified"
+msgstr ""
+
+msgid "Last month"
+msgstr ""
+
+msgid "Last name"
+msgstr ""
+
+msgid "Last reply by"
+msgstr ""
+
+msgid "Last repository check (%{last_check_timestamp}) failed. See the 'repocheck.log' file for error messages."
+msgstr ""
+
+msgid "Last seen"
+msgstr ""
+
+msgid "Last sign-in"
+msgstr ""
+
+msgid "Last sign-in IP:"
+msgstr ""
+
+msgid "Last sign-in at:"
+msgstr ""
+
+msgid "Last successful update"
+msgstr ""
+
+msgid "Last successful update %{time}."
+msgstr ""
+
+msgid "Last update"
+msgstr ""
+
+msgid "Last update attempt"
+msgstr ""
+
+msgid "Last updated"
+msgstr ""
+
+msgid "Last updated %{time} ago"
+msgstr ""
+
+msgid "Last used"
+msgstr ""
+
+msgid "Last used %{last_used_at} ago"
+msgstr ""
+
+msgid "Last week"
+msgstr ""
+
+msgid "Last year"
+msgstr ""
+
+msgid "LastCommit|authored"
+msgstr ""
+
+msgid "LastPushEvent|You pushed to"
+msgstr ""
+
+msgid "LastPushEvent|at"
+msgstr ""
+
+msgid "Latest AI-generated summary"
+msgstr ""
+
+msgid "Latest changes"
+msgstr ""
+
+msgid "Latest pipeline for the most recent commit on this branch"
+msgstr ""
+
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
+msgid "Layout|Fixed"
+msgstr ""
+
+msgid "Layout|Fluid"
+msgstr ""
+
+msgid "Lead Time"
+msgstr ""
+
+msgid "Lead Time for Changes"
+msgstr ""
+
+msgid "Lead time"
+msgstr ""
+
+msgid "Learn GitLab"
+msgstr ""
+
+msgid "Learn More"
+msgstr ""
+
+msgid "Learn More."
+msgstr ""
+
+msgid "Learn about signing commits"
+msgstr ""
+
+msgid "Learn about signing commits with SSH keys."
+msgstr ""
+
+msgid "Learn how to %{link_start}contribute to the built-in templates%{link_end}"
+msgstr ""
+
+msgid "Learn how to %{no_packages_link_start}publish and share your packages%{no_packages_link_end} with GitLab."
+msgstr ""
+
+msgid "Learn more"
+msgstr ""
+
+msgid "Learn more about %{name}"
+msgstr ""
+
+msgid "Learn more about Auto DevOps"
+msgstr ""
+
+msgid "Learn more about GitLab"
+msgstr ""
+
+msgid "Learn more about Needs relationships"
+msgstr ""
+
+msgid "Learn more about Service Desk"
+msgstr ""
+
+msgid "Learn more about Web Terminal"
+msgstr ""
+
+msgid "Learn more about X.509 signed commits"
+msgstr ""
+
+msgid "Learn more about adding certificates to your project by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}."
+msgstr ""
+
+msgid "Learn more about custom project templates"
+msgstr ""
+
+msgid "Learn more about deploying to a cluster"
+msgstr ""
+
+msgid "Learn more about group-level project templates"
+msgstr ""
+
+msgid "Learn more about groups."
+msgstr ""
+
+msgid "Learn more about issues."
+msgstr ""
+
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
+msgid "Learn more about max seats used"
+msgstr ""
+
+msgid "Learn more about seats owed"
+msgstr ""
+
+msgid "Learn more about shards and replicas in the %{configuration_link_start}Advanced Search configuration%{configuration_link_end} documentation. Changes don't take place until you %{recreated_link_start}recreate%{recreated_link_end} the index."
+msgstr ""
+
+msgid "Learn more in the"
+msgstr ""
+
+msgid "Learn more."
+msgstr ""
+
+msgid "Learn more: %{url}"
+msgstr ""
+
+msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
+msgstr ""
+
+msgid "LearnGitLab|1. Add code to your project"
+msgstr ""
+
+msgid "LearnGitLab|2. Build"
+msgstr ""
+
+msgid "LearnGitLab|Add code"
+msgstr ""
+
+msgid "LearnGitLab|Add code owners"
+msgstr ""
+
+msgid "LearnGitLab|Analyze your application for vulnerabilities with DAST"
+msgstr ""
+
+msgid "LearnGitLab|Complete these tasks first so you can enjoy GitLab's features to their fullest:"
+msgstr ""
+
+msgid "LearnGitLab|Create a repository"
+msgstr ""
+
+msgid "LearnGitLab|Create a workflow for your new workspace, and learn how GitLab features work together:"
+msgstr ""
+
+msgid "LearnGitLab|Create an issue"
+msgstr ""
+
+msgid "LearnGitLab|Create or import your first repository into your new project."
+msgstr ""
+
+msgid "LearnGitLab|Create/import issues (tickets) to collaborate on ideas and plan work."
+msgstr ""
+
+msgid "LearnGitLab|Deploy"
+msgstr ""
+
+msgid "LearnGitLab|Enable require merge approvals"
+msgstr ""
+
+msgid "LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features."
+msgstr ""
+
+msgid "LearnGitLab|Invite your colleagues"
+msgstr ""
+
+msgid "LearnGitLab|Learn GitLab"
+msgstr ""
+
+msgid "LearnGitLab|Plan and execute"
+msgstr ""
+
+msgid "LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths."
+msgstr ""
+
+msgid "LearnGitLab|Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project."
+msgstr ""
+
+msgid "LearnGitLab|Review and edit proposed changes to source code."
+msgstr ""
+
+msgid "LearnGitLab|Route code reviews to the right reviewers, every time."
+msgstr ""
+
+msgid "LearnGitLab|Save time by automating your integration and deployment tasks."
+msgstr ""
+
+msgid "LearnGitLab|Scan dependencies for licenses"
+msgstr ""
+
+msgid "LearnGitLab|Scan dependencies for vulnerabilities"
+msgstr ""
+
+msgid "LearnGitLab|Set up CI/CD"
+msgstr ""
+
+msgid "LearnGitLab|Set up your first project's CI/CD"
+msgstr ""
+
+msgid "LearnGitLab|Set up your workspace"
+msgstr ""
+
+msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
+msgstr ""
+
+msgid "LearnGitLab|Start with the WebIDE"
+msgstr ""
+
+msgid "LearnGitLab|Submit a merge request (MR)"
+msgstr ""
+
+msgid "LearnGitLab|Try GitLab Ultimate for free"
+msgstr ""
+
+msgid "LearnGitLab|Try all GitLab features for 30 days, no credit card required."
+msgstr ""
+
+msgid "LearnGitLab|Use the built-in editor to create or upload files."
+msgstr ""
+
+msgid "LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:"
+msgstr ""
+
+msgid "LearnGitLab|Your team is growing! You've successfully invited new team members to the %{projectName} project."
+msgstr ""
+
+msgid "LearnGitlab|- Included in trial"
+msgstr ""
+
+msgid "LearnGitlab|Contact your administrator to enable this action."
+msgstr ""
+
+msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
+msgstr ""
+
+msgid "LearnGitlab|Ok, let's go"
+msgstr ""
+
+msgid "LearnGitlab|View administrator list"
+msgstr ""
+
+msgid "Leave"
+msgstr ""
+
+msgid "Leave admin mode"
+msgstr ""
+
+msgid "Leave edit mode? All unsaved changes will be lost."
+msgstr ""
+
+msgid "Leave feedback"
+msgstr ""
+
+msgid "Leave feedback."
+msgstr ""
+
+msgid "Leave group"
+msgstr ""
+
+msgid "Leave project"
+msgstr ""
+
+msgid "Leave zen mode"
+msgstr ""
+
+msgid "Legacy Prometheus integrations cannot currently be removed"
+msgstr ""
+
+msgid "Legacy Web IDE"
+msgstr ""
+
+msgid "Legacy burndown chart"
+msgstr ""
+
+msgid "Legacy license"
+msgstr ""
+
+msgid "Less Details"
+msgstr ""
+
+msgid "Less restrictive visibility"
+msgstr ""
+
+msgid "Let's Encrypt does not accept emails on example.com"
+msgstr ""
+
+msgid "Let's Encrypt is a free, automated, and open certificate authority (CA) that gives digital certificates in order to enable HTTPS (SSL/TLS) for websites. Learn more about Let's Encrypt configuration by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}."
+msgstr ""
+
+msgid "License Compliance"
+msgstr ""
+
+msgid "License Compliance| Used by %{dependencies}"
+msgstr ""
+
+msgid "License compliance"
+msgstr ""
+
+msgid "License key"
+msgstr ""
+
+msgid "License overview"
+msgstr ""
+
+msgid "LicenseCompliance|%{docLinkStart}License Approvals%{docLinkEnd} are active"
+msgstr ""
+
+msgid "LicenseCompliance|%{docLinkStart}License Approvals%{docLinkEnd} are inactive"
+msgstr ""
+
+msgid "LicenseCompliance|Acceptable for use in this project"
+msgstr ""
+
+msgid "LicenseCompliance|Acceptable license to be used in the project"
+msgstr ""
+
+msgid "LicenseCompliance|Add license and related policy"
+msgstr ""
+
+msgid "LicenseCompliance|Add license policy"
+msgstr ""
+
+msgid "LicenseCompliance|Allow"
+msgstr ""
+
+msgid "LicenseCompliance|Allowed"
+msgstr ""
+
+msgid "LicenseCompliance|Denied"
+msgstr ""
+
+msgid "LicenseCompliance|Deny"
+msgstr ""
+
+msgid "LicenseCompliance|Disallow merge request if detected and will instruct developer to remove"
+msgstr ""
+
+msgid "LicenseCompliance|Learn more about %{linkStart}License Approvals%{linkEnd}"
+msgstr ""
+
+msgid "LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only"
+msgid_plural "LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only; approval required"
+msgid_plural "LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only; approval required"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "LicenseCompliance|License Compliance detected %d license for the source branch only"
+msgid_plural "LicenseCompliance|License Compliance detected %d licenses for the source branch only"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "LicenseCompliance|License Compliance detected %d new license"
+msgid_plural "LicenseCompliance|License Compliance detected %d new licenses"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "LicenseCompliance|License Compliance detected %d new license and policy violation"
+msgid_plural "LicenseCompliance|License Compliance detected %d new licenses and policy violations"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "LicenseCompliance|License Compliance detected %d new license and policy violation; approval required"
+msgid_plural "LicenseCompliance|License Compliance detected %d new licenses and policy violations; approval required"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "LicenseCompliance|License Compliance detected no licenses for the source branch only"
+msgstr ""
+
+msgid "LicenseCompliance|License Compliance detected no new licenses"
+msgstr ""
+
+msgid "LicenseCompliance|License name"
+msgstr ""
+
+msgid "LicenseCompliance|No policy matches this license"
+msgstr ""
+
+msgid "LicenseCompliance|Out-of-compliance with the project's policies and should be removed"
+msgstr ""
+
+msgid "LicenseCompliance|Remove license"
+msgstr ""
+
+msgid "LicenseCompliance|Remove license?"
+msgstr ""
+
+msgid "LicenseCompliance|There are currently no policies in this project."
+msgstr ""
+
+msgid "LicenseCompliance|There are currently no policies that match in this project."
+msgstr ""
+
+msgid "LicenseCompliance|This license already exists in this project."
+msgstr ""
+
+msgid "LicenseCompliance|Uncategorized"
+msgstr ""
+
+msgid "LicenseCompliance|Update approvals"
+msgstr ""
+
+msgid "LicenseCompliance|You are about to remove the license, %{name}, from this project."
+msgstr ""
+
+msgid "LicenseManagement|Allowed"
+msgstr ""
+
+msgid "LicenseManagement|Denied"
+msgstr ""
+
+msgid "LicenseManagement|Uncategorized"
+msgstr ""
+
+msgid "Licensed Enterprise Edition features can be used if the project namespace's plan includes the feature, or if the project is public."
+msgstr ""
+
+msgid "Licensed Features"
+msgstr ""
+
+msgid "Licensed to:"
+msgstr ""
+
+msgid "Licenses"
+msgstr ""
+
+msgid "Licenses|%{remainingComponentsCount} more"
+msgstr ""
+
+msgid "Licenses|Acceptable license to be used in the project"
+msgstr ""
+
+msgid "Licenses|Component"
+msgstr ""
+
+msgid "Licenses|Components"
+msgstr ""
+
+msgid "Licenses|Displays licenses detected in the project that are out of compliance with the project's policies, based on the %{linkStart}latest successful%{linkEnd} scan"
+msgstr ""
+
+msgid "Licenses|Drag your license file here or %{linkStart}click to upload%{linkEnd}."
+msgstr ""
+
+msgid "Licenses|Drop your license file to start the upload."
+msgstr ""
+
+msgid "Licenses|Error fetching the license list. Please check your network connection and try again."
+msgstr ""
+
+msgid "Licenses|Error: You are trying to upload something other than a file"
+msgstr ""
+
+msgid "Licenses|License Compliance"
+msgstr ""
+
+msgid "Licenses|Name"
+msgstr ""
+
+msgid "Licenses|Policy"
+msgstr ""
+
+msgid "Licenses|Policy violation: denied"
+msgstr ""
+
+msgid "Licenses|The file could not be uploaded."
+msgstr ""
+
+msgid "Licenses|The license list details information about the licenses used within your project."
+msgstr ""
+
+msgid "Licenses|Unacceptable license, if detected it will disallow a merge request until it's removed"
+msgstr ""
+
+msgid "Licenses|View license details for your project"
+msgstr ""
+
+msgid "Limit display of time tracking units to hours."
+msgstr ""
+
+msgid "Limit sign in from multiple IP addresses"
+msgstr ""
+
+msgid "Limit the number of inbound incident management alerts that can be sent to a project."
+msgstr ""
+
+msgid "Limit the number of issues and epics per minute a user can create through web and API requests."
+msgstr ""
+
+msgid "Limit the number of pipeline creation requests per minute. This limit includes pipelines created through the UI, the API, and by background processing."
+msgstr ""
+
+msgid "Limit the size of Sidekiq jobs stored in Redis."
+msgstr ""
+
+msgid "Limitation on this view"
+msgstr ""
+
+msgid "Limiting mode"
+msgstr ""
+
+msgid "Line"
+msgid_plural "Lines"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Line changes"
+msgstr ""
+
+msgid "Link"
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
+msgid "Link (optional)"
+msgstr ""
+
+msgid "Link Sentry to GitLab to discover and view the errors your application generates."
+msgstr ""
+
+msgid "Link an external wiki from the project's sidebar. %{docs_link}"
+msgstr ""
+
+msgid "Link copied to clipboard."
+msgstr ""
+
+msgid "Link does not exist"
+msgstr ""
+
+msgid "Link text"
+msgstr ""
+
+msgid "Link title"
+msgstr ""
+
+msgid "Link title is required"
+msgstr ""
+
+msgid "Link to go to GitLab pipeline documentation"
+msgstr ""
+
+msgid "Link to your Grafana instance."
+msgstr ""
+
+msgid "Linked epics"
+msgstr ""
+
+msgid "Linked incidents or issues"
+msgstr ""
+
+msgid "Linked items"
+msgstr ""
+
+msgid "LinkedIn"
+msgstr ""
+
+msgid "LinkedIn:"
+msgstr ""
+
+msgid "LinkedPipelines|%{counterLabel} more downstream pipelines"
+msgstr ""
+
+msgid "LinkedResources|Add"
+msgstr ""
+
+msgid "LinkedResources|Add a resource link"
+msgstr ""
+
+msgid "LinkedResources|Cancel"
+msgstr ""
+
+msgid "LinkedResources|Error creating resource link for the incident: %{error}"
+msgstr ""
+
+msgid "LinkedResources|Error deleting the linked resource for the incident: %{error}"
+msgstr ""
+
+msgid "LinkedResources|Fetching linked resources"
+msgstr ""
+
+msgid "LinkedResources|Link"
+msgstr ""
+
+msgid "LinkedResources|Linked resources"
+msgstr ""
+
+msgid "LinkedResources|Remove"
+msgstr ""
+
+msgid "LinkedResources|Something went wrong while creating the resource link for the incident."
+msgstr ""
+
+msgid "LinkedResources|Something went wrong while deleting the linked resource for the incident."
+msgstr ""
+
+msgid "LinkedResources|Something went wrong while fetching linked resources for the incident."
+msgstr ""
+
+msgid "LinkedResources|Text (Optional)"
+msgstr ""
+
+msgid "LinkedResources|Use this space to add links to the resources your team needs as they work to resolve the incident."
+msgstr ""
+
+msgid "Links"
+msgstr ""
+
+msgid "List"
+msgstr ""
+
+msgid "List available repositories"
+msgstr ""
+
+msgid "List of all commits"
+msgstr ""
+
+msgid "List of suitable GCP locations"
+msgstr ""
+
+msgid "List of users who are allowed to exceed the rate limit. Example: username1, username2"
+msgstr ""
+
+msgid "List options"
+msgstr ""
+
+msgid "List settings"
+msgstr ""
+
+msgid "List the merge requests that must be merged before this one."
+msgstr ""
+
+msgid "List the visible events for %{project_link} using the %{events_api_link}."
+msgstr ""
+
+msgid "List view"
+msgstr ""
+
+msgid "List your Bitbucket Server repositories"
+msgstr ""
+
+msgid "List your Gitea repositories"
+msgstr ""
+
+msgid "Load more"
+msgstr ""
+
+msgid "Load more users"
+msgstr ""
+
+msgid "Loading"
+msgstr ""
+
+msgid "Loading %{name}"
+msgstr ""
+
+msgid "Loading files, directories, and submodules in the path %{path} for commit reference %{ref}"
+msgstr ""
+
+msgid "Loading full blame..."
+msgstr ""
+
+msgid "Loading more"
+msgstr ""
+
+msgid "Loading snippet"
+msgstr ""
+
+msgid "Loading the GitLab IDE"
+msgstr ""
+
+msgid "Loading..."
+msgstr ""
+
+msgid "Loading…"
+msgstr ""
+
+msgid "Localization"
+msgstr ""
+
+msgid "Location"
+msgstr ""
+
+msgid "Location:"
+msgstr ""
+
+msgid "Lock"
+msgstr ""
+
+msgid "Lock %{issuableDisplayName}"
+msgstr ""
+
+msgid "Lock %{issuableType}"
+msgstr ""
+
+msgid "Lock File?"
+msgstr ""
+
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
+msgid "Lock memberships to LDAP synchronization"
+msgstr ""
+
+msgid "Lock memberships to SAML Group Links synchronization"
+msgstr ""
+
+msgid "Lock not found"
+msgstr ""
+
+msgid "Lock on merge"
+msgstr ""
+
+msgid "Lock status"
+msgstr ""
+
+msgid "Lock the discussion"
+msgstr ""
+
+msgid "Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment."
+msgstr ""
+
+msgid "Lock to current projects"
+msgstr ""
+
+msgid "Locked"
+msgstr ""
+
+msgid "Locked by %{fileLockUserName}"
+msgstr ""
+
+msgid "Locked files"
+msgstr ""
+
+msgid "Locked the discussion."
+msgstr ""
+
+msgid "Locking %{issuableDisplayName}"
+msgstr ""
+
+msgid "Locks the discussion."
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|About GitLab"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|Contact Sales"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|Explore GitLab"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|Get started"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|GitLab Learn"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|GitLab docs"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|GitLab: the DevOps platform"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|How GitLab compares"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|Install GitLab"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|Pricing"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|Talk to an expert"
+msgstr ""
+
+msgid "LoggedOutMarketingHeader|Why GitLab"
+msgstr ""
+
+msgid "Login with smartcard"
+msgstr ""
+
+msgid "Logo was successfully removed."
+msgstr ""
+
+msgid "Logo will be removed. Are you sure?"
+msgstr ""
+
+msgid "Logs"
+msgstr ""
+
+msgid "Low - S4"
+msgstr ""
+
+msgid "Low vulnerabilities present"
+msgstr ""
+
+msgid "MB"
+msgstr ""
+
+msgid "MD5"
+msgstr ""
+
+msgid "MLExperimentTracking|Delete candidate?"
+msgstr ""
+
+msgid "MLExperimentTracking|Delete experiment?"
+msgstr ""
+
+msgid "MR widget|Back to the merge request"
+msgstr ""
+
+msgid "MR widget|See your pipeline in action"
+msgstr ""
+
+msgid "MR widget|Take a look at our %{beginnerLinkStart}Beginner's Guide to Continuous Integration%{beginnerLinkEnd} and our %{exampleLinkStart}examples of GitLab CI/CD%{exampleLinkEnd} to learn more."
+msgstr ""
+
+msgid "MR widget|The pipeline will test your code on every commit. A %{codeQualityLinkStart}code quality report%{codeQualityLinkEnd} will appear in your merge requests to warn you about potential code degradations."
+msgstr ""
+
+msgid "MRApprovals|Approvals"
+msgstr ""
+
+msgid "MRApprovals|Approved by"
+msgstr ""
+
+msgid "MRApprovals|Approvers"
+msgstr ""
+
+msgid "MRApprovals|Commented by"
+msgstr ""
+
+msgid "MRDiffFile|Changes are too large to be shown."
+msgstr ""
+
+msgid "MRDiffFile|View file @ %{commitSha}"
+msgstr ""
+
+msgid "MRDiff|Show changes only"
+msgstr ""
+
+msgid "MRDiff|Show full file"
+msgstr ""
+
+msgid "Macbook Touch ID on Edge"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
+
+msgid "Mailgun"
+msgstr ""
+
+msgid "Mailgun HTTP webhook signing key"
+msgstr ""
+
+msgid "Mailgun events"
+msgstr ""
+
+msgid "Main menu"
+msgstr ""
+
+msgid "Maintainer"
+msgstr ""
+
+msgid "Maintenance mode"
+msgstr ""
+
+msgid "Make %{type} confidential"
+msgstr ""
+
+msgid "Make adjustments to how your GitLab instance is set up."
+msgstr ""
+
+msgid "Make and review changes in the browser with the Web IDE"
+msgstr ""
+
+msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
+msgstr ""
+
+msgid "Make new users' profiles private by default"
+msgstr ""
+
+msgid "Make sure you choose a strong, unique password."
+msgstr ""
+
+msgid "Make sure you have the correct permissions to link your project."
+msgstr ""
+
+msgid "Make sure you save it - you won't be able to access it again."
+msgstr ""
+
+msgid "Makes this %{type} confidential."
+msgstr ""
+
+msgid "Manage %{workspace} labels"
+msgstr ""
+
+msgid "Manage access"
+msgstr ""
+
+msgid "Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account."
+msgstr ""
+
+msgid "Manage applications that use GitLab as an OAuth provider."
+msgstr ""
+
+msgid "Manage applications that you've authorized to use your account."
+msgstr ""
+
+msgid "Manage branch rules"
+msgstr ""
+
+msgid "Manage git repositories with fine-grained access controls that keep your code secure."
+msgstr ""
+
+msgid "Manage group labels"
+msgstr ""
+
+msgid "Manage labels"
+msgstr ""
+
+msgid "Manage members"
+msgstr ""
+
+msgid "Manage milestones"
+msgstr ""
+
+msgid "Manage project labels"
+msgstr ""
+
+msgid "Manage projects."
+msgstr ""
+
+msgid "Manage two-factor authentication"
+msgstr ""
+
+msgid "Manage usage"
+msgstr ""
+
+msgid "Manage your subscription"
+msgstr ""
+
+msgid "Managed Account"
+msgstr ""
+
+msgid "Manifest"
+msgstr ""
+
+msgid "Manifest file"
+msgstr ""
+
+msgid "Manifest file import"
+msgstr ""
+
+msgid "Manifest import"
+msgstr ""
+
+msgid "Manual"
+msgstr ""
+
+msgid "ManualOrdering|Couldn't save the order of the issues"
+msgstr ""
+
+msgid "Manually link this issue by adding it to the linked issue section of the %{linkStart}originating vulnerability%{linkEnd}."
+msgstr ""
+
+msgid "Map a FogBugz account ID to a GitLab user"
+msgstr ""
+
+msgid "Map data from"
+msgstr ""
+
+msgid "Mar"
+msgstr ""
+
+msgid "March"
+msgstr ""
+
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
+msgid "Mark as done"
+msgstr ""
+
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
+msgid "Mark this issue as a duplicate of another issue"
+msgstr ""
+
+msgid "Mark this issue as blocked by other issues"
+msgstr ""
+
+msgid "Mark this issue as related to another issue"
+msgstr ""
+
+msgid "Mark to do as done"
+msgstr ""
+
+msgid "Markdown Help"
+msgstr ""
+
+msgid "Markdown enabled."
+msgstr ""
+
+msgid "Markdown is supported"
+msgstr ""
+
+msgid "Markdown supported."
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add strikethrough text (%{modifierKey}%{shiftKey}X)"
+msgstr ""
+
+msgid "MarkdownEditor|Add strikethrough text (%{modifierKey}⇧X)"
+msgstr ""
+
+msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
+msgstr ""
+
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
+msgid "MarkdownEditor|Indent line (%{modifierKey}])"
+msgstr ""
+
+msgid "MarkdownEditor|Indent line (%{modifier_key}])"
+msgstr ""
+
+msgid "MarkdownEditor|Outdent line (%{modifierKey}[)"
+msgstr ""
+
+msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
+msgstr ""
+
+msgid "MarkdownEditor|header"
+msgstr ""
+
+msgid "Marked"
+msgstr ""
+
+msgid "Marked %{target} as blocked by this issue."
+msgstr ""
+
+msgid "Marked For Deletion At - %{deletion_time}"
+msgstr ""
+
+msgid "Marked as draft. Can only be merged when marked as ready."
+msgstr ""
+
+msgid "Marked as ready. Merging is now allowed."
+msgstr ""
+
+msgid "Marked this %{noun} as ready."
+msgstr ""
+
+msgid "Marked this issue as blocked by %{target}."
+msgstr ""
+
+msgid "Marked this issue as related to %{issue_ref}."
+msgstr ""
+
+msgid "Marked to do as done."
+msgstr ""
+
+msgid "Marks"
+msgstr ""
+
+msgid "Marks this %{noun} as ready."
+msgstr ""
+
+msgid "Marks this issue as related to %{issue_ref}."
+msgstr ""
+
+msgid "Marks to do as done."
+msgstr ""
+
+msgid "Mask this variable in job logs if it meets %{linkStart}regular expression requirements%{linkEnd}."
+msgstr ""
+
+msgid "Mask variable"
+msgstr ""
+
+msgid "Match not found; try refining your search query."
+msgstr ""
+
+msgid "Mattermost"
+msgstr ""
+
+msgid "Mattermost URL:"
+msgstr ""
+
+msgid "Mattermost notifications"
+msgstr ""
+
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
+msgid "MattermostService|Add to Mattermost"
+msgstr ""
+
+msgid "MattermostService|After you configure the integration, view your new Mattermost commands by entering"
+msgstr ""
+
+msgid "MattermostService|Command trigger word"
+msgstr ""
+
+msgid "MattermostService|Fill in the word that works best for your team."
+msgstr ""
+
+msgid "MattermostService|Install"
+msgstr ""
+
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
+msgid "MattermostService|Request URL"
+msgstr ""
+
+msgid "MattermostService|Request method"
+msgstr ""
+
+msgid "MattermostService|Response icon"
+msgstr ""
+
+msgid "MattermostService|Response username"
+msgstr ""
+
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
+msgid "MattermostService|Suggestions:"
+msgstr ""
+
+msgid "MattermostService|Use this service to perform common tasks in your project by entering slash commands in Mattermost."
+msgstr ""
+
+msgid "Max 100,000 events"
+msgstr ""
+
+msgid "Max Value"
+msgstr ""
+
+msgid "Max authenticated Git LFS requests per period per user"
+msgstr ""
+
+msgid "Max file size is 200 KiB."
+msgstr ""
+
+msgid "Max role"
+msgstr ""
+
+msgid "Max seats used"
+msgstr ""
+
+msgid "Max session time"
+msgstr ""
+
+msgid "Maximum 20 characters"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Helm chart file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
+msgstr ""
+
+msgid "Maximum Terraform Module package file size in bytes"
+msgstr ""
+
+msgid "Maximum Users"
+msgstr ""
+
+msgid "Maximum allowable lifetime for access token (days)"
+msgstr ""
+
+msgid "Maximum allowed lifetime for SSH keys (days)"
+msgstr ""
+
+msgid "Maximum artifacts size"
+msgstr ""
+
+msgid "Maximum artifacts size (MB)"
+msgstr ""
+
+msgid "Maximum attachment size"
+msgstr ""
+
+msgid "Maximum attachment size (MiB)"
+msgstr ""
+
+msgid "Maximum authenticated API requests per rate limit period per user"
+msgstr ""
+
+msgid "Maximum authenticated web requests per rate limit period per user"
+msgstr ""
+
+msgid "Maximum bulk request size (MiB)"
+msgstr ""
+
+msgid "Maximum capacity"
+msgstr ""
+
+msgid "Maximum character limit - %{limit}"
+msgstr ""
+
+msgid "Maximum concurrency of Elasticsearch bulk requests per indexing operation."
+msgstr ""
+
+msgid "Maximum delay (Minutes)"
+msgstr ""
+
+msgid "Maximum diff patch size"
+msgstr ""
+
+msgid "Maximum diff patch size (bytes)"
+msgstr ""
+
+msgid "Maximum duration of a session."
+msgstr ""
+
+msgid "Maximum export size"
+msgstr ""
+
+msgid "Maximum export size (MiB)"
+msgstr ""
+
+msgid "Maximum field length"
+msgstr ""
+
+msgid "Maximum file size indexed (KiB)"
+msgstr ""
+
+msgid "Maximum file size is 1 MB. Image size must be 32 x 32 pixels. Allowed image formats are %{favicon_extension_allowlist}."
+msgstr ""
+
+msgid "Maximum file size is 1 MB. Pages are optimized for a 128x128 px logo."
+msgstr ""
+
+msgid "Maximum file size is 1MB."
+msgstr ""
+
+msgid "Maximum file size is 1MB. Pages are optimized for a 24px tall header logo"
+msgstr ""
+
+msgid "Maximum files in a diff"
+msgstr ""
+
+msgid "Maximum group export download requests per minute"
+msgstr ""
+
+msgid "Maximum group export requests per minute"
+msgstr ""
+
+msgid "Maximum group import requests per minute"
+msgstr ""
+
+msgid "Maximum import size"
+msgstr ""
+
+msgid "Maximum import size (MiB)"
+msgstr ""
+
+msgid "Maximum job artifact size"
+msgstr ""
+
+msgid "Maximum job timeout"
+msgstr ""
+
+msgid "Maximum job timeout has a value which could not be accepted"
+msgstr ""
+
+msgid "Maximum lines in a diff"
+msgstr ""
+
+msgid "Maximum npm package file size in bytes"
+msgstr ""
+
+msgid "Maximum number of %{name} (%{count}) exceeded"
+msgstr ""
+
+msgid "Maximum number of changes (branches or tags) in a single push above which a bulk push event is created (default is `3`). Setting to `0` does not disable throttling."
+msgstr ""
+
+msgid "Maximum number of changes (branches or tags) in a single push above which webhooks and integrations are not triggered (default is `3`). Setting to `0` does not disable throttling."
+msgstr ""
+
+msgid "Maximum number of comments exceeded"
+msgstr ""
+
+msgid "Maximum number of mirrors that can be synchronizing at the same time."
+msgstr ""
+
+msgid "Maximum number of projects."
+msgstr ""
+
+msgid "Maximum number of requests per minute"
+msgstr ""
+
+msgid "Maximum number of requests per minute for an authenticated user"
+msgstr ""
+
+msgid "Maximum number of requests per minute for an unauthenticated IP address"
+msgstr ""
+
+msgid "Maximum number of requests per minute for each raw path (default is `300`). Set to `0` to disable throttling."
+msgstr ""
+
+msgid "Maximum number of stages per value stream exceeded"
+msgstr ""
+
+msgid "Maximum number of unique IP addresses per user."
+msgstr ""
+
+msgid "Maximum number of value streams per namespace exceeded"
+msgstr ""
+
+msgid "Maximum number of variables loaded (2000)"
+msgstr ""
+
+msgid "Maximum of 255 characters"
+msgstr ""
+
+msgid "Maximum page reached"
+msgstr ""
+
+msgid "Maximum page size"
+msgstr ""
+
+msgid "Maximum project export download requests per minute"
+msgstr ""
+
+msgid "Maximum project export requests per minute"
+msgstr ""
+
+msgid "Maximum project import requests per minute"
+msgstr ""
+
+msgid "Maximum push size"
+msgstr ""
+
+msgid "Maximum push size (MiB)"
+msgstr ""
+
+msgid "Maximum requests per 10 minutes per IP address"
+msgstr ""
+
+msgid "Maximum requests per 10 minutes per user"
+msgstr ""
+
+msgid "Maximum requests per minute"
+msgstr ""
+
+msgid "Maximum running slices"
+msgstr ""
+
+msgid "Maximum size limit for a single commit."
+msgstr ""
+
+msgid "Maximum size limit for each repository."
+msgstr ""
+
+msgid "Maximum size of Elasticsearch bulk indexing requests."
+msgstr ""
+
+msgid "Maximum size of export files."
+msgstr ""
+
+msgid "Maximum size of import files."
+msgstr ""
+
+msgid "Maximum size of individual attachments in comments."
+msgstr ""
+
+msgid "Maximum size of pages (MiB)"
+msgstr ""
+
+msgid "Maximum snippet size"
+msgstr ""
+
+msgid "Maximum time between updates that a mirror can have when scheduled to synchronize."
+msgstr ""
+
+msgid "Maximum time that users are allowed to skip the setup of two-factor authentication (in hours). Set to 0 (zero) to enforce at next sign in."
+msgstr ""
+
+msgid "Maximum time, in seconds, for a web terminal websocket connection. 0 for unlimited."
+msgstr ""
+
+msgid "Maximum unauthenticated API requests per rate limit period per IP"
+msgstr ""
+
+msgid "Maximum unauthenticated web requests per rate limit period per IP"
+msgstr ""
+
+msgid "May"
+msgstr ""
+
+msgid "Mean time to merge"
+msgstr ""
+
+msgid "Measured in bytes of code. Excludes generated and vendored code."
+msgstr ""
+
+msgid "Medium - S3"
+msgstr ""
+
+msgid "Medium timeout"
+msgstr ""
+
+msgid "Medium vulnerabilities present"
+msgstr ""
+
+msgid "Member since"
+msgstr ""
+
+msgid "Member since %{date}"
+msgstr ""
+
+msgid "Member since:"
+msgstr ""
+
+msgid "MemberInviteEmail|%{member_name} invited you to join GitLab"
+msgstr ""
+
+msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
+msgstr ""
+
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
+msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
+msgstr ""
+
+msgid "MemberRole|%{role} - custom"
+msgstr ""
+
+msgid "MemberRole|can't be changed"
+msgstr ""
+
+msgid "MemberRole|cannot be changed because it is already assigned to a user. Please create a new Member Role instead"
+msgstr ""
+
+msgid "MemberRole|cannot be deleted because it is already assigned to a user. Please disassociate the member role from all users before deletion."
+msgstr ""
+
+msgid "MemberRole|maximum number of Member Roles are already in use by the group hierarchy. Please delete an existing Member Role."
+msgstr ""
+
+msgid "MemberRole|minimal base access level must be %{min_access_level}."
+msgstr ""
+
+msgid "MemberRole|must be top-level namespace"
+msgstr ""
+
+msgid "Members"
+msgstr ""
+
+msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}"
+msgstr ""
+
+msgid "Members listed as CODEOWNERS of affected files."
+msgstr ""
+
+msgid "Members of %{group} can also merge into this branch: %{branch}"
+msgstr ""
+
+msgid "Members of %{group} can also push to this branch: %{branch}"
+msgstr ""
+
+msgid "Members of a group may only view projects they have permission to access"
+msgstr ""
+
+msgid "MembersOverage|If you continue, the %{groupName} group will have %{quantity} seat in use and will be billed for the overage."
+msgid_plural "MembersOverage|If you continue, the %{groupName} group will have %{quantity} seats in use and will be billed for the overage."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "MembersOverage|You are about to incur additional charges"
+msgstr ""
+
+msgid "MembersOverage|Your subscription includes %d seat."
+msgid_plural "MembersOverage|Your subscription includes %d seats."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Membership"
+msgstr ""
+
+msgid "Members|%{group} by %{createdBy}"
+msgstr ""
+
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|%{userName} is currently an LDAP user. Editing their permissions will override the settings from the LDAP group sync."
+msgstr ""
+
+msgid "Members|2FA"
+msgstr ""
+
+msgid "Members|A group must have at least one owner. To leave this group, assign a new owner."
+msgstr ""
+
+msgid "Members|A group must have at least one owner. To remove the member, assign a new owner."
+msgstr ""
+
+msgid "Members|A personal project's owner cannot be removed."
+msgstr ""
+
+msgid "Members|Access granted"
+msgstr ""
+
+msgid "Members|Activity"
+msgstr ""
+
+msgid "Members|An error occurred while trying to enable LDAP override, please try again."
+msgstr ""
+
+msgid "Members|An error occurred while trying to revert to LDAP group sync settings, please try again."
+msgstr ""
+
+msgid "Members|An error occurred while updating the member's expiration date, please try again."
+msgstr ""
+
+msgid "Members|An error occurred while updating the member's role, please try again."
+msgstr ""
+
+msgid "Members|Are you sure you want to deny %{usersName}'s request to join \"%{source}\""
+msgstr ""
+
+msgid "Members|Are you sure you want to disable the two-factor authentication for %{userName}?"
+msgstr ""
+
+msgid "Members|Are you sure you want to leave \"%{source}\"?"
+msgstr ""
+
+msgid "Members|Are you sure you want to remove \"%{groupName}\"?"
+msgstr ""
+
+msgid "Members|Are you sure you want to remove %{userName} from \"%{group}\"?"
+msgstr ""
+
+msgid "Members|Are you sure you want to remove this orphaned member from \"%{group}\"?"
+msgstr ""
+
+msgid "Members|Are you sure you want to revoke the invitation for %{inviteEmail} to join \"%{source}\""
+msgstr ""
+
+msgid "Members|Are you sure you want to withdraw your access request for \"%{source}\""
+msgstr ""
+
+msgid "Members|Ban member"
+msgstr ""
+
+msgid "Members|Cannot leave \"%{source}\""
+msgstr ""
+
+msgid "Members|Direct"
+msgstr ""
+
+msgid "Members|Direct member by %{createdBy}"
+msgstr ""
+
+msgid "Members|Disable two-factor authentication"
+msgstr ""
+
+msgid "Members|Disabled"
+msgstr ""
+
+msgid "Members|Edit permissions"
+msgstr ""
+
+msgid "Members|Enabled"
+msgstr ""
+
+msgid "Members|Expiration date removed successfully."
+msgstr ""
+
+msgid "Members|Expiration date updated successfully."
+msgstr ""
+
+msgid "Members|Filter groups"
+msgstr ""
+
+msgid "Members|Filter members"
+msgstr ""
+
+msgid "Members|Inherited"
+msgstr ""
+
+msgid "Members|LDAP override enabled."
+msgstr ""
+
+msgid "Members|Last activity"
+msgstr ""
+
+msgid "Members|Leave \"%{source}\""
+msgstr ""
+
+msgid "Members|Membership"
+msgstr ""
+
+msgid "Members|Remove \"%{groupName}\""
+msgstr ""
+
+msgid "Members|Remove group"
+msgstr ""
+
+msgid "Members|Revert to LDAP group sync settings"
+msgstr ""
+
+msgid "Members|Reverted to LDAP group sync settings."
+msgstr ""
+
+msgid "Members|Role updated successfully."
+msgstr ""
+
+msgid "Members|Search groups"
+msgstr ""
+
+msgid "Members|Search invited"
+msgstr ""
+
+msgid "Members|User created"
+msgstr ""
+
+msgid "Members|You cannot remove yourself from a personal project."
+msgstr ""
+
+msgid "Member|Deny access"
+msgstr ""
+
+msgid "Member|Revoke invite"
+msgstr ""
+
+msgid "Memory Usage"
+msgstr ""
+
+msgid "Mentions"
+msgstr ""
+
+msgid "Menu"
+msgstr ""
+
+msgid "Merge"
+msgstr ""
+
+msgid "Merge %d cell"
+msgid_plural "Merge %d cells"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Merge Conflicts"
+msgstr ""
+
+msgid "Merge Request"
+msgstr ""
+
+msgid "Merge Request Analytics"
+msgstr ""
+
+msgid "Merge Requests"
+msgstr ""
+
+msgid "Merge Requests created"
+msgstr ""
+
+msgid "Merge Requests in Review"
+msgstr ""
+
+msgid "Merge Requests merged"
+msgstr ""
+
+msgid "Merge automatically (%{strategy})"
+msgstr ""
+
+msgid "Merge blocked: all merge request dependencies must be merged."
+msgstr ""
+
+msgid "Merge blocked: pipeline must succeed. It's waiting for a manual job to continue."
+msgstr ""
+
+msgid "Merge commit message"
+msgstr ""
+
+msgid "Merge conflicts"
+msgstr ""
+
+msgid "Merge date & time could not be determined"
+msgstr ""
+
+msgid "Merge details"
+msgstr ""
+
+msgid "Merge events"
+msgstr ""
+
+msgid "Merge immediately"
+msgstr ""
+
+msgid "Merge in progress"
+msgstr ""
+
+msgid "Merge options"
+msgstr ""
+
+msgid "Merge request"
+msgstr ""
+
+msgid "Merge request %{mr_link} was reviewed by %{mr_author}"
+msgstr ""
+
+msgid "Merge request ID"
+msgstr ""
+
+msgid "Merge request actions"
+msgstr ""
+
+msgid "Merge request analytics"
+msgstr ""
+
+msgid "Merge request approvals"
+msgstr ""
+
+msgid "Merge request change summary"
+msgstr ""
+
+msgid "Merge request commits"
+msgstr ""
+
+msgid "Merge request dependencies"
+msgstr ""
+
+msgid "Merge request events"
+msgstr ""
+
+msgid "Merge request not merged"
+msgstr ""
+
+msgid "Merge request reports"
+msgstr ""
+
+msgid "Merge request status"
+msgstr ""
+
+msgid "Merge request summaries"
+msgstr ""
+
+msgid "Merge request summary"
+msgstr ""
+
+msgid "Merge request title"
+msgstr ""
+
+msgid "Merge request was set to auto-merge"
+msgstr ""
+
+msgid "Merge requests"
+msgstr ""
+
+msgid "Merge requests and approvals settings have moved."
+msgstr ""
+
+msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
+msgstr ""
+
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
+msgid "Merge trains"
+msgstr ""
+
+msgid "Merge unverified changes"
+msgstr ""
+
+msgid "Merge unverified changes?"
+msgstr ""
+
+msgid "Merge when all merge checks pass"
+msgstr ""
+
+msgid "Merge when checks pass"
+msgstr ""
+
+msgid "Merge when pipeline succeeds"
+msgstr ""
+
+msgid "Merge..."
+msgstr ""
+
+msgid "MergeChecks|All threads must be resolved"
+msgstr ""
+
+msgid "MergeChecks|Enable \"Pipelines must succeed\" first."
+msgstr ""
+
+msgid "MergeChecks|Introduces the risk of merging changes that do not pass the pipeline."
+msgstr ""
+
+msgid "MergeChecks|Merge requests can't be merged if the latest pipeline did not succeed or is still running."
+msgstr ""
+
+msgid "MergeChecks|Pipelines must succeed"
+msgstr ""
+
+msgid "MergeChecks|Skipped pipelines are considered successful"
+msgstr ""
+
+msgid "MergeChecks|This setting is configured in group %{groupName} and can only be changed in the group settings by an administrator or group owner."
+msgstr ""
+
+msgid "MergeConflict|Commit to source branch"
+msgstr ""
+
+msgid "MergeConflict|Committing..."
+msgstr ""
+
+msgid "MergeConflict|HEAD//our changes"
+msgstr ""
+
+msgid "MergeConflict|Use ours"
+msgstr ""
+
+msgid "MergeConflict|Use theirs"
+msgstr ""
+
+msgid "MergeConflict|conflict"
+msgstr ""
+
+msgid "MergeConflict|conflicts"
+msgstr ""
+
+msgid "MergeConflict|origin//their changes"
+msgstr ""
+
+msgid "MergeRequestAnalytics|Assignees"
+msgstr ""
+
+msgid "MergeRequestAnalytics|Date Merged"
+msgstr ""
+
+msgid "MergeRequestAnalytics|Line changes"
+msgstr ""
+
+msgid "MergeRequestAnalytics|Merge Request"
+msgstr ""
+
+msgid "MergeRequestAnalytics|Milestone"
+msgstr ""
+
+msgid "MergeRequestAnalytics|Pipelines"
+msgstr ""
+
+msgid "MergeRequestAnalytics|Time to merge"
+msgstr ""
+
+msgid "MergeRequestApprovals|Define approval rules and settings to ensure %{link_start}separation of duties%{link_end} for new merge requests."
+msgstr ""
+
+msgid "MergeRequestApprovals|Enforce %{link_start}separation of duties%{link_end} for all projects."
+msgstr ""
+
+msgid "MergeRequestApprovals|Enforce %{separationLinkStart}separation of duties%{separationLinkEnd} for all projects. %{learnLinkStart}Learn more.%{learnLinkEnd}"
+msgstr ""
+
+msgid "MergeRequestDiffs|Commenting on lines %{selectStart}start%{selectEnd} to %{end}"
+msgstr ""
+
+msgid "MergeRequestDiffs|Select comment starting line"
+msgstr ""
+
+msgid "MergeRequests|Can't perform this action automatically. It may have already been done, or a more recent commit may have updated some of this content. Please perform this action locally."
+msgstr ""
+
+msgid "MergeRequests|Commit cherry-pick failed"
+msgstr ""
+
+msgid "MergeRequests|Commit revert failed"
+msgstr ""
+
+msgid "MergeRequests|Create issue to resolve thread"
+msgstr ""
+
+msgid "MergeRequests|Drafts cannot be merged until marked ready."
+msgstr ""
+
+msgid "MergeRequests|Mark as draft"
+msgstr ""
+
+msgid "MergeRequests|Merge request cherry-pick failed"
+msgstr ""
+
+msgid "MergeRequests|Merge request revert failed"
+msgstr ""
+
+msgid "MergeRequests|Reference copied"
+msgstr ""
+
+msgid "MergeRequests|Squashing failed: Squash the commits locally, resolve any conflicts, then push the branch."
+msgstr ""
+
+msgid "MergeRequests|Squashing not allowed: This project doesn't allow you to squash commits when merging."
+msgstr ""
+
+msgid "MergeRequests|Thread stays resolved"
+msgstr ""
+
+msgid "MergeRequests|Thread stays unresolved"
+msgstr ""
+
+msgid "MergeRequests|Thread will be resolved"
+msgstr ""
+
+msgid "MergeRequests|Thread will be unresolved"
+msgstr ""
+
+msgid "MergeRequests|View file @ %{commitId}"
+msgstr ""
+
+msgid "MergeRequests|View replaced file @ %{commitId}"
+msgstr ""
+
+msgid "MergeRequests|Your comment could not be submitted because %{reason}."
+msgstr ""
+
+msgid "MergeRequests|commented on commit %{commitLink}"
+msgstr ""
+
+msgid "MergeRequests|started a thread"
+msgstr ""
+
+msgid "MergeRequests|started a thread on %{linkStart}a file%{linkEnd}"
+msgstr ""
+
+msgid "MergeRequests|started a thread on %{linkStart}an old version of a file%{linkEnd}"
+msgstr ""
+
+msgid "MergeRequests|started a thread on %{linkStart}an old version of the diff%{linkEnd}"
+msgstr ""
+
+msgid "MergeRequests|started a thread on %{linkStart}the diff%{linkEnd}"
+msgstr ""
+
+msgid "MergeRequests|started a thread on an outdated change in commit %{linkStart}%{commitDisplay}%{linkEnd}"
+msgstr ""
+
+msgid "MergeRequests|started a thread on commit %{linkStart}%{commitDisplay}%{linkEnd}"
+msgstr ""
+
+msgid "MergeRequest|Approved by @%{username}"
+msgstr ""
+
+msgid "MergeRequest|Can't fetch the diff needed to update this view. Please reload this page."
+msgstr ""
+
+msgid "MergeRequest|Can't fetch the single file diff for the discussion. Please reload this page."
+msgstr ""
+
+msgid "MergeRequest|Can't show this merge request because of an internal error. Contact your administrator."
+msgstr ""
+
+msgid "MergeRequest|Can't show this merge request because the fork project was deleted."
+msgstr ""
+
+msgid "MergeRequest|Can't show this merge request because the source branch %{branch_badge} is missing from project %{path_badge}. Close this merge request or update the source branch."
+msgstr ""
+
+msgid "MergeRequest|Can't show this merge request because the target branch %{branch_badge} is missing from project %{path_badge}. Close this merge request or update the target branch."
+msgstr ""
+
+msgid "MergeRequest|Compare %{target} and %{source}"
+msgstr ""
+
+msgid "MergeRequest|Error dismissing suggestion popover. Please try again."
+msgstr ""
+
+msgid "MergeRequest|Error loading full diff. Please try again."
+msgstr ""
+
+msgid "MergeRequest|Failed to load the page"
+msgstr ""
+
+msgid "MergeRequest|No files found"
+msgstr ""
+
+msgid "MergeRequest|Reviewed by @%{username} but not yet approved"
+msgstr ""
+
+msgid "MergeRequest|Search (e.g. *.vue) (%{MODIFIER_KEY}P)"
+msgstr ""
+
+msgid "MergeRequest|Summaries are written by AI"
+msgstr ""
+
+msgid "MergeRequest|Summary notes"
+msgstr ""
+
+msgid "MergeRequest|This description was generated for revision %{revision} using AI"
+msgstr ""
+
+msgid "MergeRequest|This description was generated using AI"
+msgstr ""
+
+msgid "MergeTopics|%{sourceTopic} will be removed"
+msgstr ""
+
+msgid "MergeTopics|All assigned projects will be moved to %{targetTopic}"
+msgstr ""
+
+msgid "MergeTopics|Merge topics"
+msgstr ""
+
+msgid "MergeTopics|Merging topics will cause the following:"
+msgstr ""
+
+msgid "MergeTopics|Move all assigned projects from the source topic to the target topic and remove the source topic."
+msgstr ""
+
+msgid "MergeTopics|Source topic"
+msgstr ""
+
+msgid "MergeTopics|Target topic"
+msgstr ""
+
+msgid "MergeTopics|This action cannot be undone."
+msgstr ""
+
+msgid "Merged"
+msgstr ""
+
+msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes."
+msgstr ""
+
+msgid "Merged by"
+msgstr ""
+
+msgid "Merged this merge request."
+msgstr ""
+
+msgid "Merged: %{merged}"
+msgstr ""
+
+msgid "Merges this merge request immediately."
+msgstr ""
+
+msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
+msgstr ""
+
+msgid "Mermaid diagram"
+msgstr ""
+
+msgid "Message"
+msgstr ""
+
+msgid "Messages"
+msgstr ""
+
+msgid "Method"
+msgstr ""
+
+msgid "Method call threshold (ms)"
+msgstr ""
+
+msgid "Metric"
+msgstr ""
+
+msgid "Metric was successfully added."
+msgstr ""
+
+msgid "Metric was successfully updated."
+msgstr ""
+
+msgid "Metric:"
+msgstr ""
+
+msgid "MetricChart|Please select a metric"
+msgstr ""
+
+msgid "MetricChart|Selected"
+msgstr ""
+
+msgid "MetricChart|There is no data available. Please change your selection."
+msgstr ""
+
+msgid "MetricChart|There is too much data to calculate. Please change your selection."
+msgstr ""
+
+msgid "MetricImages|There was an issue deleting the image."
+msgstr ""
+
+msgid "MetricImages|There was an issue loading metric images."
+msgstr ""
+
+msgid "MetricImages|There was an issue updating your image."
+msgstr ""
+
+msgid "MetricImages|There was an issue uploading your image."
+msgstr ""
+
+msgid "Metrics - Grafana"
+msgstr ""
+
+msgid "Metrics - Prometheus"
+msgstr ""
+
+msgid "Metrics Dashboard"
+msgstr ""
+
+msgid "Metrics Dashboard YAML definition"
+msgstr ""
+
+msgid "Metrics Dashboard YAML definition is invalid:"
+msgstr ""
+
+msgid "Metrics Dashboard YAML definition is valid."
+msgstr ""
+
+msgid "Metrics and profiling"
+msgstr ""
+
+msgid "Metrics:"
+msgstr ""
+
+msgid "Metrics|Create metric"
+msgstr ""
+
+msgid "Metrics|Delete metric"
+msgstr ""
+
+msgid "Metrics|Delete metric?"
+msgstr ""
+
+msgid "Metrics|Edit metric"
+msgstr ""
+
+msgid "Metrics|For grouping similar metrics"
+msgstr ""
+
+msgid "Metrics|Label of the y-axis (usually the unit). The x-axis always represents time."
+msgstr ""
+
+msgid "Metrics|Legend label (optional)"
+msgstr ""
+
+msgid "Metrics|Must be a valid PromQL query."
+msgstr ""
+
+msgid "Metrics|New metric"
+msgstr ""
+
+msgid "Metrics|PromQL query is valid"
+msgstr ""
+
+msgid "Metrics|Prometheus Query Documentation"
+msgstr ""
+
+msgid "Metrics|There was an error trying to validate your query"
+msgstr ""
+
+msgid "Metrics|Unit label"
+msgstr ""
+
+msgid "Metrics|Used as a title for the chart"
+msgstr ""
+
+msgid "Metrics|Used if the query returns a single series. If it returns multiple series, their legend labels will be picked up from the response."
+msgstr ""
+
+msgid "Metrics|Validating query"
+msgstr ""
+
+msgid "Metrics|Y-axis label"
+msgstr ""
+
+msgid "Metrics|You're about to permanently delete this metric. This cannot be undone."
+msgstr ""
+
+msgid "Metrics|e.g. HTTP requests"
+msgstr ""
+
+msgid "Metrics|e.g. Requests/second"
+msgstr ""
+
+msgid "Metrics|e.g. Throughput"
+msgstr ""
+
+msgid "Metrics|e.g. rate(http_requests_total[5m])"
+msgstr ""
+
+msgid "Metrics|e.g. req/sec"
+msgstr ""
+
+msgid "Mi"
+msgstr ""
+
+msgid "Microsoft|Client ID"
+msgstr ""
+
+msgid "Microsoft|Client secret"
+msgstr ""
+
+msgid "Microsoft|Enable Microsoft Azure integration for this group"
+msgstr ""
+
+msgid "Microsoft|Graph API endpoint"
+msgstr ""
+
+msgid "Microsoft|Login API endpoint"
+msgstr ""
+
+msgid "Microsoft|Microsoft Azure Integration"
+msgstr ""
+
+msgid "Microsoft|Microsoft Azure integration settings failed to save. %{errors}"
+msgstr ""
+
+msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
+msgstr ""
+
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
+msgid "Microsoft|Tenant ID"
+msgstr ""
+
+msgid "Microsoft|Use the default value, unless you're using Azure AD for US Government or Azure AD China operated by 22Vianet."
+msgstr ""
+
+msgid "Microsoft|Use the default value, unless you're using using Microsoft Graph for US Government or Microsoft Graph China operated by 22Vianet."
+msgstr ""
+
+msgid "Migrated %{success_count}/%{total_count} files."
+msgstr ""
+
+msgid "Migration"
+msgstr ""
+
+msgid "Migration has been scheduled to be retried"
+msgstr ""
+
+msgid "Migration successful."
+msgstr ""
+
+msgid "Milestone"
+msgid_plural "Milestones"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Milestone actions"
+msgstr ""
+
+msgid "Milestone due date"
+msgstr ""
+
+msgid "Milestone id(s) not found: %{milestones}"
+msgstr ""
+
+msgid "Milestone lists not available with your current license"
+msgstr ""
+
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
+msgid "MilestoneCombobox|An error occurred while searching for milestones"
+msgstr ""
+
+msgid "MilestoneCombobox|Group milestones"
+msgstr ""
+
+msgid "MilestoneCombobox|Milestone"
+msgstr ""
+
+msgid "MilestoneCombobox|No matching results"
+msgstr ""
+
+msgid "MilestoneCombobox|No milestone"
+msgstr ""
+
+msgid "MilestoneCombobox|Project milestones"
+msgstr ""
+
+msgid "MilestoneCombobox|Search Milestones"
+msgstr ""
+
+msgid "MilestoneCombobox|Select milestone"
+msgstr ""
+
+msgid "MilestonePage|Copy milestone ID"
+msgstr ""
+
+msgid "MilestonePage|Milestone ID: %{milestone_id}"
+msgstr ""
+
+msgid "MilestoneSidebar|Closed:"
+msgstr ""
+
+msgid "MilestoneSidebar|Copy reference"
+msgstr ""
+
+msgid "MilestoneSidebar|Due date"
+msgstr ""
+
+msgid "MilestoneSidebar|Edit"
+msgstr ""
+
+msgid "MilestoneSidebar|From"
+msgstr ""
+
+msgid "MilestoneSidebar|Issues"
+msgstr ""
+
+msgid "MilestoneSidebar|Merge requests"
+msgstr ""
+
+msgid "MilestoneSidebar|Merged:"
+msgstr ""
+
+msgid "MilestoneSidebar|New Issue"
+msgstr ""
+
+msgid "MilestoneSidebar|New issue"
+msgstr ""
+
+msgid "MilestoneSidebar|No due date"
+msgstr ""
+
+msgid "MilestoneSidebar|No start date"
+msgstr ""
+
+msgid "MilestoneSidebar|None"
+msgstr ""
+
+msgid "MilestoneSidebar|Open:"
+msgstr ""
+
+msgid "MilestoneSidebar|Reference:"
+msgstr ""
+
+msgid "MilestoneSidebar|Start date"
+msgstr ""
+
+msgid "MilestoneSidebar|Toggle sidebar"
+msgstr ""
+
+msgid "MilestoneSidebar|Until"
+msgstr ""
+
+msgid "MilestoneSidebar|complete"
+msgstr ""
+
+msgid "Milestones"
+msgstr ""
+
+msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle} and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
+msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle}. This milestone is not currently used in any issues or merge requests."
+msgstr ""
+
+msgid "Milestones|Close Milestone"
+msgstr ""
+
+msgid "Milestones|Completed Issues (closed)"
+msgstr ""
+
+msgid "Milestones|Create a milestone to better track your issues and merge requests. %{learn_more_link}"
+msgstr ""
+
+msgid "Milestones|Delete milestone"
+msgstr ""
+
+msgid "Milestones|Delete milestone %{milestoneTitle}?"
+msgstr ""
+
+msgid "Milestones|Failed to delete milestone %{milestoneTitle}"
+msgstr ""
+
+msgid "Milestones|Group Milestone"
+msgstr ""
+
+msgid "Milestones|Milestone %{milestoneTitle} was not found"
+msgstr ""
+
+msgid "Milestones|Ongoing Issues (open and assigned)"
+msgstr ""
+
+msgid "Milestones|Organize issues and merge requests into a cohesive group, and set optional start and due dates. %{learn_more_link}"
+msgstr ""
+
+msgid "Milestones|Project Milestone"
+msgstr ""
+
+msgid "Milestones|Promote %{milestoneTitle} to group milestone?"
+msgstr ""
+
+msgid "Milestones|Promote Milestone"
+msgstr ""
+
+msgid "Milestones|Promote to Group Milestone"
+msgstr ""
+
+msgid "Milestones|Promoting %{milestoneTitle} will make it available for all projects inside %{groupName}. Existing project milestones with the same title will be merged."
+msgstr ""
+
+msgid "Milestones|Reopen Milestone"
+msgstr ""
+
+msgid "Milestones|There are no closed milestones"
+msgstr ""
+
+msgid "Milestones|There are no open milestones"
+msgstr ""
+
+msgid "Milestones|This action cannot be reversed."
+msgstr ""
+
+msgid "Milestones|Unstarted Issues (open and unassigned)"
+msgstr ""
+
+msgid "Milestones|Use milestones to track issues and merge requests over a fixed period of time"
+msgstr ""
+
+msgid "Milestone|%{percentage}%{percent} complete"
+msgstr ""
+
+msgid "Min Value"
+msgstr ""
+
+msgid "Minimal Access"
+msgstr ""
+
+msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
+msgstr ""
+
+msgid "Minutes"
+msgstr ""
+
+msgid "Mirror all branches"
+msgstr ""
+
+msgid "Mirror branches"
+msgstr ""
+
+msgid "Mirror direction"
+msgstr ""
+
+msgid "Mirror only protected branches"
+msgstr ""
+
+msgid "Mirror repository"
+msgstr ""
+
+msgid "Mirror settings are only available to GitLab administrators."
+msgstr ""
+
+msgid "Mirror specific branches"
+msgstr ""
+
+msgid "Mirror user"
+msgstr ""
+
+msgid "Mirrored from %{link}."
+msgstr ""
+
+msgid "Mirrored repositories"
+msgstr ""
+
+msgid "Mirroring repositories"
+msgstr ""
+
+msgid "Mirroring settings were successfully updated."
+msgstr ""
+
+msgid "Mirroring settings were successfully updated. The project is being updated."
+msgstr ""
+
+msgid "Mirroring was successfully disabled."
+msgstr ""
+
+msgid "Mirroring will only be available if the feature is included in the plan of the selected group or user."
+msgstr ""
+
+msgid "Miscellaneous"
+msgstr ""
+
+msgid "Missing"
+msgstr ""
+
+msgid "Missing OAuth configuration for GitHub."
+msgstr ""
+
+msgid "Missing OS"
+msgstr ""
+
+msgid "Missing arch"
+msgstr ""
+
+msgid "Missing commit signatures endpoint!"
+msgstr ""
+
+msgid "Missing/invalid scope"
+msgstr ""
+
+msgid "MissingSSHKeyWarningLink|Add SSH key"
+msgstr ""
+
+msgid "MissingSSHKeyWarningLink|Don't show again"
+msgstr ""
+
+msgid "MissingSSHKeyWarningLink|You can't push or pull repositories using SSH until you add an SSH key to your profile."
+msgstr ""
+
+msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
+msgstr ""
+
+msgid "MlExperimentTracking|-"
+msgstr ""
+
+msgid "MlExperimentTracking|Artifacts"
+msgstr ""
+
+msgid "MlExperimentTracking|Author"
+msgstr ""
+
+msgid "MlExperimentTracking|CI Job"
+msgstr ""
+
+msgid "MlExperimentTracking|Candidate removed"
+msgstr ""
+
+msgid "MlExperimentTracking|Create a new experiment"
+msgstr ""
+
+msgid "MlExperimentTracking|Create new candidates"
+msgstr ""
+
+msgid "MlExperimentTracking|Created at"
+msgstr ""
+
+msgid "MlExperimentTracking|Delete candidate"
+msgstr ""
+
+msgid "MlExperimentTracking|Delete experiment"
+msgstr ""
+
+msgid "MlExperimentTracking|Deleting this candidate will delete the associated parameters, metrics, and metadata."
+msgstr ""
+
+msgid "MlExperimentTracking|Deleting this experiment will also delete its candidates and their associated metadata."
+msgstr ""
+
+msgid "MlExperimentTracking|Details"
+msgstr ""
+
+msgid "MlExperimentTracking|Download as CSV"
+msgstr ""
+
+msgid "MlExperimentTracking|Experiment"
+msgstr ""
+
+msgid "MlExperimentTracking|Experiment removed"
+msgstr ""
+
+msgid "MlExperimentTracking|Experiments keep track of comparable model candidates, and determine which parameters provides the best performance. Create experiments using the MLflow client"
+msgstr ""
+
+msgid "MlExperimentTracking|Filter candidates"
+msgstr ""
+
+msgid "MlExperimentTracking|Get started with model experiments!"
+msgstr ""
+
+msgid "MlExperimentTracking|ID"
+msgstr ""
+
+msgid "MlExperimentTracking|Info"
+msgstr ""
+
+msgid "MlExperimentTracking|Logged candidates for experiment"
+msgstr ""
+
+msgid "MlExperimentTracking|MLflow run ID"
+msgstr ""
+
+msgid "MlExperimentTracking|Machine learning experiment tracking"
+msgstr ""
+
+msgid "MlExperimentTracking|Metadata"
+msgstr ""
+
+msgid "MlExperimentTracking|Metrics"
+msgstr ""
+
+msgid "MlExperimentTracking|Model candidate details"
+msgstr ""
+
+msgid "MlExperimentTracking|Model experiments"
+msgstr ""
+
+msgid "MlExperimentTracking|Model registry"
+msgstr ""
+
+msgid "MlExperimentTracking|Name"
+msgstr ""
+
+msgid "MlExperimentTracking|No artifacts"
+msgstr ""
+
+msgid "MlExperimentTracking|No candidates"
+msgstr ""
+
+msgid "MlExperimentTracking|No candidates logged for the query. Create new candidates using the MLflow client."
+msgstr ""
+
+msgid "MlExperimentTracking|No name"
+msgstr ""
+
+msgid "MlExperimentTracking|Parameters"
+msgstr ""
+
+msgid "MlExperimentTracking|Status"
+msgstr ""
+
+msgid "MlExperimentTracking|Triggered by"
+msgstr ""
+
+msgid "Modal updated"
+msgstr ""
+
+msgid "ModalButton|Add projects"
+msgstr ""
+
+msgid "Modal|Close"
+msgstr ""
+
+msgid "Model experiments"
+msgstr ""
+
+msgid "ModelRegistry|Model registry"
+msgstr ""
+
+msgid "Modified"
+msgstr ""
+
+msgid "Modified in this version"
+msgstr ""
+
+msgid "Modify commit message"
+msgstr ""
+
+msgid "Modify commit messages"
+msgstr ""
+
+msgid "Modify merge commit"
+msgstr ""
+
+msgid "Mon"
+msgstr ""
+
+msgid "Monday"
+msgstr ""
+
+msgid "Monitor"
+msgstr ""
+
+msgid "Monitor GitLab with Prometheus."
+msgstr ""
+
+msgid "Monitor Settings"
+msgstr ""
+
+msgid "Monitor your errors directly in GitLab."
+msgstr ""
+
+msgid "Month"
+msgstr ""
+
+msgid "Months"
+msgstr ""
+
+msgid "More Details"
+msgstr ""
+
+msgid "More Information"
+msgstr ""
+
+msgid "More actions"
+msgstr ""
+
+msgid "More details"
+msgstr ""
+
+msgid "More info"
+msgstr ""
+
+msgid "More information"
+msgstr ""
+
+msgid "More information is available|here"
+msgstr ""
+
+msgid "More options"
+msgstr ""
+
+msgid "More than %{number_commits_distance} commits different with %{default_branch}"
+msgstr ""
+
+msgid "More topics"
+msgstr ""
+
+msgid "Most common"
+msgstr ""
+
+msgid "Most relevant"
+msgstr ""
+
+msgid "Most starred"
+msgstr ""
+
+msgid "Move"
+msgstr ""
+
+msgid "Move down"
+msgstr ""
+
+msgid "Move issue"
+msgstr ""
+
+msgid "Move issue from one column of the board to another"
+msgstr ""
+
+msgid "Move selection down"
+msgstr ""
+
+msgid "Move selection up"
+msgstr ""
+
+msgid "Move test case"
+msgstr ""
+
+msgid "Move this issue to another project."
+msgstr ""
+
+msgid "Move up"
+msgstr ""
+
+msgid "MoveIssue|Cannot move issue due to insufficient permissions!"
+msgstr ""
+
+msgid "MoveIssue|Cannot move issue to project it originates from!"
+msgstr ""
+
+msgid "MoveIssue|Cannot move issues of '%{issue_type}' type."
+msgstr ""
+
+msgid "Moved issue to %{label} column in the board."
+msgstr ""
+
+msgid "Moved this issue to %{path_to_project}."
+msgstr ""
+
+msgid "Moves issue to %{label} column in the board."
+msgstr ""
+
+msgid "Moves this issue to %{path_to_project}."
+msgstr ""
+
+msgid "Moving issue"
+msgstr ""
+
+msgid "MrDeploymentActions|Deploy"
+msgstr ""
+
+msgid "MrDeploymentActions|Re-deploy"
+msgstr ""
+
+msgid "MrDeploymentActions|Stop environment"
+msgstr ""
+
+msgid "MrList|Assigned to %{name}"
+msgstr ""
+
+msgid "MrList|Review requested from %{name}"
+msgstr ""
+
+msgid "MrSurvey|By continuing, you acknowledge that responses will be used to improve GitLab and in accordance with the %{linkStart}GitLab Privacy Policy%{linkEnd}."
+msgstr ""
+
+msgid "MrSurvey|How satisfied are you with %{strongStart}speed/performance%{strongEnd} of merge requests?"
+msgstr ""
+
+msgid "MrSurvey|Merge request experience survey"
+msgstr ""
+
+msgid "MrSurvey|Overall, how satisfied are you with merge requests?"
+msgstr ""
+
+msgid "MrSurvey|Thank you for your feedback!"
+msgstr ""
+
+msgid "Multi-project"
+msgstr ""
+
+msgid "Multiple IP address ranges are supported. Does not affect access to the group's settings."
+msgstr ""
+
+msgid "Multiple Prometheus integrations are not supported"
+msgstr ""
+
+msgid "Multiple components '%{name}' have 'gl/inject-editor' attribute"
+msgstr ""
+
+msgid "Multiple integrations of a single type are not supported for this project"
+msgstr ""
+
+msgid "Multiple signatures"
+msgstr ""
+
+msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
+msgstr ""
+
+msgid "Must be 90 days or more."
+msgstr ""
+
+msgid "My awesome group"
+msgstr ""
+
+msgid "My comment templates"
+msgstr ""
+
+msgid "My company or team"
+msgstr ""
+
+msgid "My topic"
+msgstr ""
+
+msgid "My-Reaction"
+msgstr ""
+
+msgid "NEW"
+msgstr ""
+
+msgid "Name"
+msgstr ""
+
+msgid "Name can contain only lowercase or uppercase letters, digits, emoji, spaces, dots, underscores, dashes, or pluses."
+msgstr ""
+
+msgid "Name can't be blank"
+msgstr ""
+
+msgid "Name has already been taken"
+msgstr ""
+
+msgid "Name is already taken."
+msgstr ""
+
+msgid "Name must start with a letter, digit, emoji, or underscore."
+msgstr ""
+
+msgid "Name new label"
+msgstr ""
+
+msgid "Name to be used as the sender for emails from Service Desk."
+msgstr ""
+
+msgid "Name:"
+msgstr ""
+
+msgid "Namespace"
+msgstr ""
+
+msgid "Namespace ID:"
+msgstr ""
+
+msgid "Namespace Limits"
+msgstr ""
+
+msgid "Namespace Storage"
+msgstr ""
+
+msgid "Namespace doesn't exist or you don't have permission."
+msgstr ""
+
+msgid "Namespace must be provided."
+msgstr ""
+
+msgid "Namespace or group to import repository into does not exist."
+msgstr ""
+
+msgid "Namespace or project is required"
+msgstr ""
+
+msgid "Namespace:"
+msgstr ""
+
+msgid "NamespaceLimits|%{date} %{linkStart}%{username}%{linkEnd} changed the limit to %{limit}"
+msgstr ""
+
+msgid "NamespaceLimits|Add minimum free storage amount (in MiB) that will be used to enforce storage usage for namespaces on free plan. To remove the limit, set the value to 0 and click \"Update limit\" button."
+msgstr ""
+
+msgid "NamespaceLimits|Add minimum free storage amount (in MiB) that will be used to set the dashboard limit for namespaces on free plan. To remove the limit, set the value to 0 and click \"Update limit\" button."
+msgstr ""
+
+msgid "NamespaceLimits|Add minimum free storage amount (in MiB) that will be used to show notifications for namespace on free plan. To remove the limit, set the value to 0 and click \"Update limit\" button."
+msgstr ""
+
+msgid "NamespaceLimits|Confirm deletion"
+msgstr ""
+
+msgid "NamespaceLimits|Confirm limits change"
+msgstr ""
+
+msgid "NamespaceLimits|Dashboard Limit"
+msgstr ""
+
+msgid "NamespaceLimits|Dashboard limit was successfully added"
+msgstr ""
+
+msgid "NamespaceLimits|Dashboard limit was successfully removed"
+msgstr ""
+
+msgid "NamespaceLimits|Deletion confirmation"
+msgstr ""
+
+msgid "NamespaceLimits|Do you confirm the deletion of the selected namespace from the exclusion list?"
+msgstr ""
+
+msgid "NamespaceLimits|Enforcement Limit"
+msgstr ""
+
+msgid "NamespaceLimits|Enforcement limit was successfully added"
+msgstr ""
+
+msgid "NamespaceLimits|Enforcement limit was successfully removed"
+msgstr ""
+
+msgid "NamespaceLimits|Enter a valid number greater or equal to zero."
+msgstr ""
+
+msgid "NamespaceLimits|Exclude"
+msgstr ""
+
+msgid "NamespaceLimits|Exclude namespace"
+msgstr ""
+
+msgid "NamespaceLimits|Excluded Namespaces"
+msgstr ""
+
+msgid "NamespaceLimits|Exclusion added successfully"
+msgstr ""
+
+msgid "NamespaceLimits|Free Tier"
+msgstr ""
+
+msgid "NamespaceLimits|NONE"
+msgstr ""
+
+msgid "NamespaceLimits|Namespace limits could not be loaded. Reload the page to try again."
+msgstr ""
+
+msgid "NamespaceLimits|Notifications Limit"
+msgstr ""
+
+msgid "NamespaceLimits|Notifications limit was successfully added"
+msgstr ""
+
+msgid "NamespaceLimits|Notifications limit was successfully removed"
+msgstr ""
+
+msgid "NamespaceLimits|Reason"
+msgstr ""
+
+msgid "NamespaceLimits|Reason for excluding this namespace"
+msgstr ""
+
+msgid "NamespaceLimits|Set Dashboard limit"
+msgstr ""
+
+msgid "NamespaceLimits|Set Enforcement limit"
+msgstr ""
+
+msgid "NamespaceLimits|Set Notifications limit"
+msgstr ""
+
+msgid "NamespaceLimits|Storage Phased Notification"
+msgstr ""
+
+msgid "NamespaceLimits|There was an error deleting the namespace: \"%{errorMessage}\"."
+msgstr ""
+
+msgid "NamespaceLimits|There was an error fetching the exclusion list, try refreshing the page."
+msgstr ""
+
+msgid "NamespaceLimits|These namespaces won't receive any notifications nor any degraded functionality while they remain on this list"
+msgstr ""
+
+msgid "NamespaceLimits|This will change the dashboard limit for all free namespaces except the excluded namespaces, the limit can be removed later."
+msgstr ""
+
+msgid "NamespaceLimits|This will change when free namespaces get storage enforcement except the excluded namespaces, the limit can be removed later."
+msgstr ""
+
+msgid "NamespaceLimits|This will limit the amount of notifications all free namespaces receives except the excluded namespaces, the limit can be removed later."
+msgstr ""
+
+msgid "NamespaceLimits|Update limit"
+msgstr ""
+
+msgid "NamespaceLimits|You must select a namespace and add a reason for excluding it"
+msgstr ""
+
+msgid "NamespaceStorageSize|%{namespace_name} is now read-only. Your ability to write new data to this namespace is restricted. %{read_only_link_start}Which actions are restricted?%{link_end}"
+msgstr ""
+
+msgid "NamespaceStorageSize|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
+msgstr ""
+
+msgid "NamespaceStorageSize|If %{namespace_name} exceeds the storage quota, your ability to write new data to this namespace will be restricted. %{read_only_link_start}Which actions become restricted?%{link_end}"
+msgstr ""
+
+msgid "NamespaceStorageSize|If a project reaches 100%% of the storage quota (%{free_size_limit}) the project will be in a read-only state, and you won't be able to push to your repository or add large files."
+msgstr ""
+
+msgid "NamespaceStorageSize|To prevent your projects from being in a read-only state %{manage_storage_link_start}manage your storage usage%{link_end}, or %{purchase_more_link_start}purchase more storage%{link_end}."
+msgstr ""
+
+msgid "NamespaceStorageSize|To prevent your projects from being in a read-only state %{manage_storage_link_start}manage your storage usage%{link_end}, or contact a user with the %{group_member_link_start}owner role for this namespace%{link_end} and ask them to %{purchase_more_link_start}purchase more storage%{link_end}."
+msgstr ""
+
+msgid "NamespaceStorageSize|To reduce storage usage, reduce git repository and git LFS storage."
+msgstr ""
+
+msgid "NamespaceStorageSize|To remove the read-only state %{manage_storage_link_start}manage your storage usage%{link_end}, or %{purchase_more_link_start}purchase more storage%{link_end}."
+msgstr ""
+
+msgid "NamespaceStorageSize|To remove the read-only state %{manage_storage_link_start}manage your storage usage%{link_end}, or contact a user with the %{group_member_link_start}owner role for this namespace%{link_end} and ask them to %{purchase_more_link_start}purchase more storage%{link_end}."
+msgstr ""
+
+msgid "NamespaceStorageSize|To remove the read-only state, reduce git repository and git LFS storage, or %{purchase_more_link_start}purchase more storage%{link_end}."
+msgstr ""
+
+msgid "NamespaceStorageSize|To remove the read-only state, reduce git repository and git LFS storage, or contact a user with the %{group_member_link_start}owner role for this namespace%{link_end} and ask them to %{purchase_more_link_start}purchase more storage%{link_end}."
+msgstr ""
+
+msgid "NamespaceStorageSize|You have consumed all available storage and you can't push or add large files to projects over the free tier limit (%{free_size_limit})."
+msgstr ""
+
+msgid "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} for %{namespace_name}"
+msgstr ""
+
+msgid "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} on %{readonly_project_count} project"
+msgid_plural "NamespaceStorageSize|You have reached the free storage limit of %{free_size_limit} on %{readonly_project_count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "NamespaceStorageSize|You have used %{usage_in_percent} of the storage quota for %{namespace_name}"
+msgstr ""
+
+msgid "NamespaceStorageSize|You have used %{usage_in_percent} of the storage quota for %{namespace_name} (%{used_storage} of %{storage_limit})"
+msgstr ""
+
+msgid "NamespaceStorage|%{name_with_link} is now read-only. Projects under this namespace are locked and actions are restricted."
+msgstr ""
+
+msgid "NamespaceStorage|%{name} is now read-only. Projects under this namespace are locked and actions are restricted."
+msgstr ""
+
+msgid "NamespaceStorage|Action required: Storage has been exceeded for %{namespace_name}"
+msgstr ""
+
+msgid "NamespaceStorage|Buy more storage"
+msgstr ""
+
+msgid "NamespaceStorage|If %{name_with_link} exceeds the storage quota, all projects in the namespace will be locked and actions will be restricted."
+msgstr ""
+
+msgid "NamespaceStorage|If %{name} exceeds the storage quota, all projects in the namespace will be locked and actions will be restricted."
+msgstr ""
+
+msgid "NamespaceStorage|Learn about which actions are restricted: %{url}"
+msgstr ""
+
+msgid "NamespaceStorage|Learn about which actions become restricted: %{url}"
+msgstr ""
+
+msgid "NamespaceStorage|Manage your storage usage or purchase additional storage."
+msgstr ""
+
+msgid "NamespaceStorage|See storage usage statistics: %{url}"
+msgstr ""
+
+msgid "NamespaceStorage|Which actions are restricted?"
+msgstr ""
+
+msgid "NamespaceStorage|Which actions become restricted?"
+msgstr ""
+
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
+msgstr ""
+
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
+msgstr ""
+
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgstr ""
+
+msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
+msgstr ""
+
+msgid "NamespaceUserCap|View pending approvals"
+msgstr ""
+
+msgid "NamespaceUserCap|Your group has reached its billable member limit"
+msgstr ""
+
+msgid "Namespaces"
+msgstr ""
+
+msgid "Namespaces to index"
+msgstr ""
+
+msgid "Naming"
+msgstr ""
+
+msgid "Naming, topics, avatar"
+msgstr ""
+
+msgid "Naming, visibility"
+msgstr ""
+
+msgid "Navigate to the project to close the milestone."
+msgstr ""
+
+msgid "Navigation bar"
+msgstr ""
+
+msgid "Navigation sidebar"
+msgstr ""
+
+msgid "NavigationTheme|Blue"
+msgstr ""
+
+msgid "NavigationTheme|Dark Mode (alpha)"
+msgstr ""
+
+msgid "NavigationTheme|Gray"
+msgstr ""
+
+msgid "NavigationTheme|Green"
+msgstr ""
+
+msgid "NavigationTheme|Indigo"
+msgstr ""
+
+msgid "NavigationTheme|Light Blue"
+msgstr ""
+
+msgid "NavigationTheme|Light Gray"
+msgstr ""
+
+msgid "NavigationTheme|Light Green"
+msgstr ""
+
+msgid "NavigationTheme|Light Indigo"
+msgstr ""
+
+msgid "NavigationTheme|Light Red"
+msgstr ""
+
+msgid "NavigationTheme|Red"
+msgstr ""
+
+msgid "Navigation|Admin Area"
+msgstr ""
+
+msgid "Navigation|Analyze"
+msgstr ""
+
+msgid "Navigation|Build"
+msgstr ""
+
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
+msgid "Navigation|Code"
+msgstr ""
+
+msgid "Navigation|Context navigation"
+msgstr ""
+
+msgid "Navigation|Deploy"
+msgstr ""
+
+msgid "Navigation|Enter admin mode"
+msgstr ""
+
+msgid "Navigation|Explore"
+msgstr ""
+
+msgid "Navigation|Frequently visited groups"
+msgstr ""
+
+msgid "Navigation|Frequently visited projects"
+msgstr ""
+
+msgid "Navigation|Groups"
+msgstr ""
+
+msgid "Navigation|Groups you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Leave admin mode"
+msgstr ""
+
+msgid "Navigation|Manage"
+msgstr ""
+
+msgid "Navigation|Merge requests settings"
+msgstr ""
+
+msgid "Navigation|Monitor"
+msgstr ""
+
+msgid "Navigation|Monitor settings"
+msgstr ""
+
+msgid "Navigation|No group matches found"
+msgstr ""
+
+msgid "Navigation|No project matches found"
+msgstr ""
+
+msgid "Navigation|Operate"
+msgstr ""
+
+msgid "Navigation|Pin item"
+msgstr ""
+
+msgid "Navigation|Pinned"
+msgstr ""
+
+msgid "Navigation|Plan"
+msgstr ""
+
+msgid "Navigation|Primary"
+msgstr ""
+
+msgid "Navigation|Projects"
+msgstr ""
+
+msgid "Navigation|Projects you visit often will appear here."
+msgstr ""
+
+msgid "Navigation|Repository settings"
+msgstr ""
+
+msgid "Navigation|Retrieving search results"
+msgstr ""
+
+msgid "Navigation|Search your projects or groups"
+msgstr ""
+
+msgid "Navigation|Secure"
+msgstr ""
+
+msgid "Navigation|Switch context"
+msgstr ""
+
+msgid "Navigation|There was an error fetching search results."
+msgstr ""
+
+msgid "Navigation|Unpin item"
+msgstr ""
+
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
+msgid "Navigation|View all your groups"
+msgstr ""
+
+msgid "Navigation|View all your projects"
+msgstr ""
+
+msgid "Navigation|Your pinned items appear here."
+msgstr ""
+
+msgid "Navigation|Your work"
+msgstr ""
+
+msgid "Nav|Help"
+msgstr ""
+
+msgid "Nav|Home"
+msgstr ""
+
+msgid "Nav|Sign In / Register"
+msgstr ""
+
+msgid "Nav|Sign out and sign in with a different account"
+msgstr ""
+
+msgid "Needs"
+msgstr ""
+
+msgid "Needs attention"
+msgstr ""
+
+msgid "Network"
+msgstr ""
+
+msgid "Network:"
+msgstr ""
+
+msgid "Never"
+msgstr ""
+
+msgid "New"
+msgstr ""
+
+msgid "New %{type} in %{project}"
+msgstr ""
+
+msgid "New Application"
+msgstr ""
+
+msgid "New Branch"
+msgstr ""
+
+msgid "New Deploy Key"
+msgstr ""
+
+msgid "New Epic"
+msgstr ""
+
+msgid "New File"
+msgstr ""
+
+msgid "New Group"
+msgstr ""
+
+msgid "New Identity"
+msgstr ""
+
+msgid "New Issue"
+msgid_plural "New Issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "New Jira import"
+msgstr ""
+
+msgid "New Label"
+msgstr ""
+
+msgid "New Milestone"
+msgstr ""
+
+msgid "New Pages Domain"
+msgstr ""
+
+msgid "New Password"
+msgstr ""
+
+msgid "New Pipeline Schedule"
+msgstr ""
+
+msgid "New Project"
+msgstr ""
+
+msgid "New Protected Branch"
+msgstr ""
+
+msgid "New Requirement"
+msgstr ""
+
+msgid "New Security findings"
+msgstr ""
+
+msgid "New Snippet"
+msgstr ""
+
+msgid "New User"
+msgstr ""
+
+msgid "New branch"
+msgstr ""
+
+msgid "New branch unavailable"
+msgstr ""
+
+msgid "New code quality findings"
+msgstr ""
+
+msgid "New confidential epic title "
+msgstr ""
+
+msgid "New confidential issue title"
+msgstr ""
+
+msgid "New custom emoji"
+msgstr ""
+
+msgid "New deploy key"
+msgstr ""
+
+msgid "New directory"
+msgstr ""
+
+msgid "New email address added"
+msgstr ""
+
+msgid "New environment"
+msgstr ""
+
+msgid "New epic"
+msgstr ""
+
+msgid "New epic title"
+msgstr ""
+
+msgid "New error tracking access token has been generated!"
+msgstr ""
+
+msgid "New file"
+msgstr ""
+
+msgid "New group"
+msgstr ""
+
+msgid "New group name"
+msgstr ""
+
+msgid "New health check access token has been generated!"
+msgstr ""
+
+msgid "New identity"
+msgstr ""
+
+msgid "New incident"
+msgstr ""
+
+msgid "New incident has been created"
+msgstr ""
+
+msgid "New issue"
+msgstr ""
+
+msgid "New issue title"
+msgstr ""
+
+msgid "New iteration created"
+msgstr ""
+
+msgid "New label"
+msgstr ""
+
+msgid "New list"
+msgstr ""
+
+msgid "New merge request"
+msgstr ""
+
+msgid "New milestone"
+msgstr ""
+
+msgid "New name"
+msgstr ""
+
+msgid "New password"
+msgstr ""
+
+msgid "New project"
+msgstr ""
+
+msgid "New project page"
+msgstr ""
+
+msgid "New project pages"
+msgstr ""
+
+msgid "New project/repository"
+msgstr ""
+
+msgid "New public deploy key"
+msgstr ""
+
+msgid "New related %{issueType}"
+msgstr ""
+
+msgid "New release"
+msgstr ""
+
+msgid "New requirement"
+msgstr ""
+
+msgid "New response for issue #%{issue_iid}:"
+msgstr ""
+
+msgid "New runners registration token has been generated!"
+msgstr ""
+
+msgid "New snippet"
+msgstr ""
+
+msgid "New subgroup"
+msgstr ""
+
+msgid "New tag"
+msgstr ""
+
+msgid "New test case"
+msgstr ""
+
+msgid "New topic"
+msgstr ""
+
+msgid "New users set to external"
+msgstr ""
+
+msgid "New! Suggest changes directly"
+msgstr ""
+
+msgid "Newest first"
+msgstr ""
+
+msgid "Newly-registered users are external by default"
+msgstr ""
+
+msgid "Next"
+msgstr ""
+
+msgid "Next commit"
+msgstr ""
+
+msgid "Next design"
+msgstr ""
+
+msgid "Next file in diff"
+msgstr ""
+
+msgid "Next scan"
+msgstr ""
+
+msgid "Next unresolved discussion"
+msgstr ""
+
+msgid "Next update"
+msgstr ""
+
+msgid "Nickname"
+msgstr ""
+
+msgid "No"
+msgstr ""
+
+msgid "No %{header} for this request."
+msgstr ""
+
+msgid "No %{providerTitle} repositories found"
+msgstr ""
+
+msgid "No CSV data to display."
+msgstr ""
+
+msgid "No Epic"
+msgstr ""
+
+msgid "No Google Cloud projects - You need at least one Google Cloud project"
+msgstr ""
+
+msgid "No Matching Results"
+msgstr ""
+
+msgid "No Milestone"
+msgstr ""
+
+msgid "No Scopes"
+msgstr ""
+
+msgid "No Work Item Link found"
+msgstr ""
+
+msgid "No access"
+msgstr ""
+
+msgid "No activities found"
+msgstr ""
+
+msgid "No approvers"
+msgstr ""
+
+msgid "No artifacts found"
+msgstr ""
+
+msgid "No assignee"
+msgstr ""
+
+msgid "No authentication methods configured."
+msgstr ""
+
+msgid "No available branches"
+msgstr ""
+
+msgid "No branches found"
+msgstr ""
+
+msgid "No change to this %{noun}'s draft status."
+msgstr ""
+
+msgid "No changes"
+msgstr ""
+
+msgid "No changes between %{source} and %{target}"
+msgstr ""
+
+msgid "No child epics match applied filters"
+msgstr ""
+
+msgid "No commenters"
+msgstr ""
+
+msgid "No commits present here"
+msgstr ""
+
+msgid "No committers"
+msgstr ""
+
+msgid "No component has 'gl/inject-editor' attribute"
+msgstr ""
+
+msgid "No components present in devfile"
+msgstr ""
+
+msgid "No confirmation email received? Check your spam folder or %{request_link_start}request new confirmation email%{request_link_end}."
+msgstr ""
+
+msgid "No connection could be made to a Gitaly Server, please check your logs!"
+msgstr ""
+
+msgid "No contributions"
+msgstr ""
+
+msgid "No contributions were found"
+msgstr ""
+
+msgid "No credit card data for matching"
+msgstr ""
+
+msgid "No credit card required."
+msgstr ""
+
+msgid "No data"
+msgstr ""
+
+msgid "No data available"
+msgstr ""
+
+msgid "No deployments detected. Use environments to control your software's continuous deployment. %{linkStart}Learn more about deployment jobs.%{linkEnd}"
+msgstr ""
+
+msgid "No deployments found"
+msgstr ""
+
+msgid "No email participants were added. Either none were provided, or they already exist."
+msgstr ""
+
+msgid "No endpoint provided"
+msgstr ""
+
+msgid "No errors to display."
+msgstr ""
+
+msgid "No estimate or time spent"
+msgstr ""
+
+msgid "No file chosen."
+msgstr ""
+
+msgid "No file hooks found."
+msgstr ""
+
+msgid "No file selected"
+msgstr ""
+
+msgid "No files"
+msgstr ""
+
+msgid "No files found."
+msgstr ""
+
+msgid "No forks are available to you."
+msgstr ""
+
+msgid "No group provided"
+msgstr ""
+
+msgid "No grouping"
+msgstr ""
+
+msgid "No issues found"
+msgstr ""
+
+msgid "No iteration"
+msgstr ""
+
+msgid "No label"
+msgstr ""
+
+msgid "No labels found"
+msgstr ""
+
+msgid "No labels with such name or description"
+msgstr ""
+
+msgid "No linked issue matches the provided parameter."
+msgstr ""
+
+msgid "No matches found"
+msgstr ""
+
+msgid "No matching %{issuable} found. Make sure that you are adding a valid %{issuable} ID."
+msgstr ""
+
+msgid "No matching %{issuable} found. Make sure that you are adding a valid %{issuable} URL."
+msgstr ""
+
+msgid "No matching labels"
+msgstr ""
+
+msgid "No matching results"
+msgstr ""
+
+msgid "No matching results for \"%{query}\""
+msgstr ""
+
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
+msgid "No members found"
+msgstr ""
+
+msgid "No memberships found"
+msgstr ""
+
+msgid "No merge requests found"
+msgstr ""
+
+msgid "No messages were logged"
+msgstr ""
+
+msgid "No milestone"
+msgstr ""
+
+msgid "No more than %{max_issues} issues can be updated at the same time"
+msgstr ""
+
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
+msgstr ""
+
+msgid "No parent group"
+msgstr ""
+
+msgid "No plan"
+msgstr ""
+
+msgid "No policy matches this license"
+msgstr ""
+
+msgid "No preview for this file type"
+msgstr ""
+
+msgid "No prioritized labels with such name or description"
+msgstr ""
+
+msgid "No prioritized labels yet!"
+msgstr ""
+
+msgid "No project subscribes to the pipelines in this project."
+msgstr ""
+
+msgid "No projects available."
+msgstr ""
+
+msgid "No projects found"
+msgstr ""
+
+msgid "No public deploy keys"
+msgstr ""
+
+msgid "No public groups"
+msgstr ""
+
+msgid "No ref selected"
+msgstr ""
+
+msgid "No regions configured"
+msgstr ""
+
+msgid "No repository"
+msgstr ""
+
+msgid "No results"
+msgstr ""
+
+msgid "No results found"
+msgstr ""
+
+msgid "No results found."
+msgstr ""
+
+msgid "No runner executable"
+msgstr ""
+
+msgid "No service accounts"
+msgstr ""
+
+msgid "No severity matches the provided parameter"
+msgstr ""
+
+msgid "No slash-separated component can begin with %{sequencePrefixes}"
+msgstr ""
+
+msgid "No slash-separated component can end with %{sequencePostfixes}"
+msgstr ""
+
+msgid "No slash-separated tag name component can be empty"
+msgstr ""
+
+msgid "No source selected"
+msgstr ""
+
+msgid "No stack trace for this error"
+msgstr ""
+
+msgid "No starrers matched your search"
+msgstr ""
+
+msgid "No start date – %{dueDate}"
+msgstr ""
+
+msgid "No suggestions found"
+msgstr ""
+
+msgid "No template"
+msgstr ""
+
+msgid "No template selected"
+msgstr ""
+
+msgid "No test coverage"
+msgstr ""
+
+msgid "No user provided"
+msgstr ""
+
+msgid "No vulnerabilities present"
+msgstr ""
+
+msgid "No webhook events"
+msgstr ""
+
+msgid "No webhooks enabled. Select trigger events above."
+msgstr ""
+
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
+msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
+msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "No wrap"
+msgstr ""
+
+msgid "No. of commits"
+msgstr ""
+
+msgid "Nobody has starred this repository yet"
+msgstr ""
+
+msgid "Node was successfully created."
+msgstr ""
+
+msgid "Node was successfully updated."
+msgstr ""
+
+msgid "Nodes"
+msgstr ""
+
+msgid "Non-admin users are restricted to read-only access, in both GitLab UI and API."
+msgstr ""
+
+msgid "None"
+msgstr ""
+
+msgid "None of the group milestones have the same project as the release"
+msgstr ""
+
+msgid "Normal text"
+msgstr ""
+
+msgid "Normal view"
+msgstr ""
+
+msgid "NorthstarNavigation|Could not update the new navigation preference. Please try again later."
+msgstr ""
+
+msgid "NorthstarNavigation|Navigation redesign"
+msgstr ""
+
+msgid "NorthstarNavigation|New navigation"
+msgstr ""
+
+msgid "NorthstarNavigation|Provide feedback"
+msgstr ""
+
+msgid "NorthstarNavigation|Toggle new navigation"
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in, even from an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. You must save your recovery codes after you first register a two-factor authenticator to be able to sign in, even from an unsupported browser."
+msgstr ""
+
+msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
+msgstr ""
+
+msgid "Not applicable."
+msgstr ""
+
+msgid "Not available"
+msgstr ""
+
+msgid "Not available for private projects"
+msgstr ""
+
+msgid "Not available for protected branches"
+msgstr ""
+
+msgid "Not confidential"
+msgstr ""
+
+msgid "Not found"
+msgstr ""
+
+msgid "Not found."
+msgstr ""
+
+msgid "Not permitted to destroy framework"
+msgstr ""
+
+msgid "Not ready yet. Try again later."
+msgstr ""
+
+msgid "Not started"
+msgstr ""
+
+msgid "Not supported"
+msgstr ""
+
+msgid "Note"
+msgstr ""
+
+msgid "Note creation requests"
+msgstr ""
+
+msgid "Note parameters are invalid: %{errors}"
+msgstr ""
+
+msgid "Note: As an administrator you may like to configure %{github_integration_link}, which will allow login via GitHub and allow connecting repositories without generating a Personal Access Token."
+msgstr ""
+
+msgid "Note: As an administrator you may like to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
+msgstr ""
+
+msgid "Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow connecting repositories without generating a Personal Access Token."
+msgstr ""
+
+msgid "Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
+msgstr ""
+
+msgid "Note: current forks will keep their visibility level."
+msgstr ""
+
+msgid "NoteForm|Note"
+msgstr ""
+
+msgid "Notes"
+msgstr ""
+
+msgid "Notes rate limit"
+msgstr ""
+
+msgid "Notes|Are you sure you want to cancel creating this %{commentType}?"
+msgstr ""
+
+msgid "Notes|Are you sure you want to cancel creating this comment?"
+msgstr ""
+
+msgid "Notes|Attachments are sent by email. Attachments over 10 MB are sent as links to your GitLab instance, and only accessible to project members."
+msgstr ""
+
+msgid "Notes|Collapse replies"
+msgstr ""
+
+msgid "Notes|Expand replies"
+msgstr ""
+
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr ""
+
+msgid "Notes|Last reply by %{name}"
+msgstr ""
+
+msgid "Notes|Make this an internal note"
+msgstr ""
+
+msgid "Notes|Show all activity"
+msgstr ""
+
+msgid "Notes|Show comments only"
+msgstr ""
+
+msgid "Notes|Show history only"
+msgstr ""
+
+msgid "Notes|This comment has changed since you started editing, please review the %{open_link}updated comment%{close_link} to ensure information is not lost"
+msgstr ""
+
+msgid "Notes|This internal note will always remain confidential"
+msgstr ""
+
+msgid "Notes|You're only seeing %{boldStart}other activity%{boldEnd} in the feed. To add a comment, switch to one of the following options."
+msgstr ""
+
+msgid "Note|The created date provided is too far in the past."
+msgstr ""
+
+msgid "Nothing to preview."
+msgstr ""
+
+msgid "Notification events"
+msgstr ""
+
+msgid "Notification setting - %{notification_title}"
+msgstr ""
+
+msgid "Notification settings saved"
+msgstr ""
+
+msgid "NotificationEmail|Assignee"
+msgid_plural "NotificationEmail|Assignees"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "NotificationEmail|Assignee: %{users}"
+msgid_plural "NotificationEmail|Assignees: %{users}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "NotificationEmail|Reviewer"
+msgid_plural "NotificationEmail|Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "NotificationEmail|Reviewer: %{users}"
+msgid_plural "NotificationEmail|Reviewers: %{users}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
+msgid "NotificationEvent|Close issue"
+msgstr ""
+
+msgid "NotificationEvent|Close merge request"
+msgstr ""
+
+msgid "NotificationEvent|Failed pipeline"
+msgstr ""
+
+msgid "NotificationEvent|Fixed pipeline"
+msgstr ""
+
+msgid "NotificationEvent|Issue due"
+msgstr ""
+
+msgid "NotificationEvent|Merge merge request"
+msgstr ""
+
+msgid "NotificationEvent|Merge when pipeline succeeds"
+msgstr ""
+
+msgid "NotificationEvent|Moved project"
+msgstr ""
+
+msgid "NotificationEvent|New epic"
+msgstr ""
+
+msgid "NotificationEvent|New issue"
+msgstr ""
+
+msgid "NotificationEvent|New merge request"
+msgstr ""
+
+msgid "NotificationEvent|New note"
+msgstr ""
+
+msgid "NotificationEvent|New release"
+msgstr ""
+
+msgid "NotificationEvent|Push to merge request"
+msgstr ""
+
+msgid "NotificationEvent|Reassign issue"
+msgstr ""
+
+msgid "NotificationEvent|Reassign merge request"
+msgstr ""
+
+msgid "NotificationEvent|Reopen issue"
+msgstr ""
+
+msgid "NotificationEvent|Reopen merge request"
+msgstr ""
+
+msgid "NotificationEvent|Successful pipeline"
+msgstr ""
+
+msgid "NotificationLevel|Custom"
+msgstr ""
+
+msgid "NotificationLevel|Disabled"
+msgstr ""
+
+msgid "NotificationLevel|Global"
+msgstr ""
+
+msgid "NotificationLevel|On mention"
+msgstr ""
+
+msgid "NotificationLevel|Participate"
+msgstr ""
+
+msgid "NotificationLevel|Watch"
+msgstr ""
+
+msgid "Notifications"
+msgstr ""
+
+msgid "Notifications have been disabled by the project or group owner"
+msgstr ""
+
+msgid "Notifications off"
+msgstr ""
+
+msgid "Notifications on"
+msgstr ""
+
+msgid "Notifications turned off."
+msgstr ""
+
+msgid "Notifications turned on."
+msgstr ""
+
+msgid "Notify users by email when sign-in location is not recognized."
+msgstr ""
+
+msgid "Notify|%{author_link}'s issue %{issue_reference_link} is due soon."
+msgstr ""
+
+msgid "Notify|%{author_name} %{action_name} %{ref_type} %{ref_name} at %{project_link}"
+msgstr ""
+
+msgid "Notify|%{changed_files}:"
+msgstr ""
+
+msgid "Notify|%{commit_link} in %{mr_link}"
+msgstr ""
+
+msgid "Notify|%{commits_text} from branch `%{target_branch}`"
+msgstr ""
+
+msgid "Notify|%{committed_by_start} by %{author_name} %{committed_by_end} %{committed_at_start} at %{committed_date} %{committed_at_end}"
+msgstr ""
+
+msgid "Notify|%{invite_email}, now known as %{user_name}, has accepted your invitation to join the %{target_name} %{target_model_name}."
+msgstr ""
+
+msgid "Notify|%{invited_user} has %{highlight_start}declined%{highlight_end} your invitation to join the %{target_link} %{target_name}."
+msgstr ""
+
+msgid "Notify|%{issues} imported."
+msgstr ""
+
+msgid "Notify|%{member_link} requested %{member_role} access to the %{target_source_link} %{target_type}."
+msgstr ""
+
+msgid "Notify|%{mr_highlight}Merge request%{highlight_end} %{mr_link} %{reviewer_highlight}was approved by%{highlight_end} %{reviewer_avatar} %{reviewer_link}"
+msgstr ""
+
+msgid "Notify|%{mr_highlight}Merge request%{highlight_end} %{mr_link} %{reviewer_highlight}was unapproved by%{highlight_end} %{reviewer_avatar} %{reviewer_link}"
+msgstr ""
+
+msgid "Notify|%{name} requested a new review on %{mr_link}."
+msgstr ""
+
+msgid "Notify|%{p_start}To update the remote url in your local repository run (for ssh):%{p_end} %{ssh_url_to_repo} %{p_start}or for http(s):%{p_end} %{http_url_to_repo}"
+msgstr ""
+
+msgid "Notify|%{paragraph_start}Hi %{name}!%{paragraph_end} %{paragraph_start}A new public key was added to your account:%{paragraph_end} %{paragraph_start}title: %{key_title}%{paragraph_end} %{paragraph_start}If this key was added in error, you can remove it under %{removal_link}%{paragraph_end}"
+msgstr ""
+
+msgid "Notify|%{project_link_start}Download%{project_link_end} the project export."
+msgstr ""
+
+msgid "Notify|%{singular_or_plural_line} %{error_lines}: Work item type cannot be found or is not supported."
+msgstr ""
+
+msgid "Notify|%{singular_or_plural_line} %{error_lines}: Work item type is empty."
+msgstr ""
+
+msgid "Notify|%{singular_or_plural_line} %{error_lines}: Work item type is not available. Please check your license and permissions."
+msgstr ""
+
+msgid "Notify|%{strong_open}%{user_name}%{strong_close} updated the custom email address credentials for the Service Desk of %{project_link_start}%{project_name}%{project_link_end} and triggered the verification process."
+msgstr ""
+
+msgid "Notify|%{update_at_start} Last update at %{update_at_mid} %{last_update_at} %{update_at_end}"
+msgstr ""
+
+msgid "Notify|%{updated_by_user_name} pushed new commits to merge request %{mr_link}"
+msgstr ""
+
+msgid "Notify|%{work_items} successfully imported."
+msgstr ""
+
+msgid "Notify|A new GPG key was added to your account:"
+msgstr ""
+
+msgid "Notify|A remote mirror update has failed."
+msgstr ""
+
+msgid "Notify|After it expires, you can %{a_start} request a new one %{a_end}."
+msgstr ""
+
+msgid "Notify|All discussions on merge request %{mr_link} were resolved by %{name}"
+msgstr ""
+
+msgid "Notify|And %{total_stripped_new_commits_count} more"
+msgstr ""
+
+msgid "Notify|Assignee changed from %{fromNames} to %{toNames}"
+msgstr ""
+
+msgid "Notify|Assignee changed to %{toNames}"
+msgstr ""
+
+msgid "Notify|Author: %{author_name}"
+msgstr ""
+
+msgid "Notify|Auto DevOps pipeline was disabled for %{project}"
+msgstr ""
+
+msgid "Notify|CI/CD project settings"
+msgstr ""
+
+msgid "Notify|Check your forwarding settings and make sure the original email sender remains in the %{code_open}From%{code_end} header."
+msgstr ""
+
+msgid "Notify|Click here to set your password"
+msgstr ""
+
+msgid "Notify|Commit Author"
+msgstr ""
+
+msgid "Notify|Committed by"
+msgstr ""
+
+msgid "Notify|Could not find the following %{column} values in %{project}%{parent_groups_clause}: %{error_lines}"
+msgstr ""
+
+msgid "Notify|Don't want to receive updates from GitLab administrators?"
+msgstr ""
+
+msgid "Notify|Email could not be verified"
+msgstr ""
+
+msgid "Notify|Email successfully verified"
+msgstr ""
+
+msgid "Notify|Error parsing CSV file. Please make sure it has the correct format: a delimited text file that uses a comma to separate values."
+msgstr ""
+
+msgid "Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check if these lines have an issue title."
+msgstr ""
+
+msgid "Notify|Errors found on %{singular_or_plural_line}: %{error_lines}. Please check that these lines have the following fields: %{required_headers}."
+msgstr ""
+
+msgid "Notify|Fingerprint: %{fingerprint}"
+msgstr ""
+
+msgid "Notify|Here are the results for your CSV import for %{project_link}."
+msgstr ""
+
+msgid "Notify|Here are the results for your CSV import for %{project_name} (%{project_link})."
+msgstr ""
+
+msgid "Notify|Hi %{username}!"
+msgstr ""
+
+msgid "Notify|Hi %{user}!"
+msgstr ""
+
+msgid "Notify|If this key was added in error, you can remove it under %{removal_link}"
+msgstr ""
+
+msgid "Notify|If this was a mistake you can change these settings or deactivate the custom email address in the project settings."
+msgstr ""
+
+msgid "Notify|If you no longer wish to use this domain with GitLab Pages, please remove it from your GitLab project and delete any related DNS records."
+msgstr ""
+
+msgid "Notify|Incorrect %{code_open}From%{code_end} header:"
+msgstr ""
+
+msgid "Notify|Incorrect verification token:"
+msgstr ""
+
+msgid "Notify|Invalid credentials:"
+msgstr ""
+
+msgid "Notify|Issue was %{issue_status} by %{updated_by}"
+msgstr ""
+
+msgid "Notify|Issue was moved to another project."
+msgstr ""
+
+msgid "Notify|Learn more about Auto DevOps"
+msgstr ""
+
+msgid "Notify|Logs may contain sensitive data. Please consider before forwarding this email."
+msgstr ""
+
+msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict."
+msgstr ""
+
+msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
+msgstr ""
+
+msgid "Notify|Merge request %{merge_request} was merged"
+msgstr ""
+
+msgid "Notify|Merge request %{mr_link} was closed by %{closed_by}"
+msgstr ""
+
+msgid "Notify|Merge request URL: %{merge_request_url}"
+msgstr ""
+
+msgid "Notify|Merge request was approved"
+msgstr ""
+
+msgid "Notify|Merge request was approved (%{approvals}/%{required_approvals})"
+msgstr ""
+
+msgid "Notify|Merge request was unapproved"
+msgstr ""
+
+msgid "Notify|Merge request was unapproved (%{approvals_count}/%{approvals_required})"
+msgstr ""
+
+msgid "Notify|Milestone changed to %{milestone}"
+msgstr ""
+
+msgid "Notify|Milestone removed"
+msgstr ""
+
+msgid "Notify|New issue: %{project_issue_url}"
+msgstr ""
+
+msgid "Notify|No preview for this file type"
+msgstr ""
+
+msgid "Notify|No work items have been imported."
+msgstr ""
+
+msgid "Notify|Pipeline %{pipeline_link} triggered by"
+msgstr ""
+
+msgid "Notify|Pipeline %{pipeline_name_or_id} has failed!"
+msgstr ""
+
+msgid "Notify|Pipeline %{pipeline_name_or_id} has passed!"
+msgstr ""
+
+msgid "Notify|Pipeline has been fixed and %{pipeline_name_or_id} has passed!"
+msgstr ""
+
+msgid "Notify|Please check that your service provider supports email subaddressing and that you have set up email forwarding correctly."
+msgstr ""
+
+msgid "Notify|Please fix the errors above and try the CSV import again."
+msgstr ""
+
+msgid "Notify|Please fix the lines with errors and try the CSV import again."
+msgstr ""
+
+msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
+msgstr ""
+
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
+msgid "Notify|Project %{project_name} was exported successfully."
+msgstr ""
+
+msgid "Notify|Remote mirror"
+msgstr ""
+
+msgid "Notify|SMTP host issue:"
+msgstr ""
+
+msgid "Notify|Some values in the \"type\" column could not be matched with supported work item types:"
+msgstr ""
+
+msgid "Notify|The Administrator created an account for you. Now you are a member of the company GitLab application."
+msgstr ""
+
+msgid "Notify|The Auto DevOps pipeline failed for pipeline %{pipeline_link} and has been disabled for %{project_link}. In order to use the Auto DevOps pipeline with your project, please review the %{supported_langs_link}, adjust your project accordingly, and turn on the Auto DevOps pipeline within your %{settings_link}."
+msgstr ""
+
+msgid "Notify|The diff for this file was not included because it is too large."
+msgstr ""
+
+msgid "Notify|The diff was not included because it is too large."
+msgstr ""
+
+msgid "Notify|The download link will expire in 24 hours."
+msgstr ""
+
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
+msgid "Notify|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
+msgstr ""
+
+msgid "Notify|The provided custom email address is %{strong_open}%{email_address}%{strong_close} and uses the SMTP host %{strong_open}%{smtp_host}%{strong_close}."
+msgstr ""
+
+msgid "Notify|The push did not contain any new commits, but force pushed to delete the commits and changes below."
+msgstr ""
+
+msgid "Notify|This issue is due on: %{issue_due_date}"
+msgstr ""
+
+msgid "Notify|This link is valid for %{password_reset_token_valid_time}."
+msgstr ""
+
+msgid "Notify|To enable the custom email address, go to your %{settings_link_start}project's Service Desk settings page%{settings_link_end}."
+msgstr ""
+
+msgid "Notify|To restart the verification process, go to your %{settings_link_start}project's Service Desk settings page%{settings_link_end}."
+msgstr ""
+
+msgid "Notify|Unless you verify your domain by %{time_start}%{time}%{time_end} it will be removed from your GitLab project."
+msgstr ""
+
+msgid "Notify|Verification email not received within timeframe:"
+msgstr ""
+
+msgid "Notify|Verification for custom email %{email} for %{project_name} triggered"
+msgstr ""
+
+msgid "Notify|Verification result for custom email %{email} for %{project_name}"
+msgstr ""
+
+msgid "Notify|Verify custom email address %{email} for %{project_name}"
+msgstr ""
+
+msgid "Notify|We could not verify that we received the email we sent to your email inbox."
+msgstr ""
+
+msgid "Notify|We could not verify your email address %{strong_open}%{email_address}%{strong_close} for the Service Desk of %{project_link_start}%{project_name}%{project_link_end}."
+msgstr ""
+
+msgid "Notify|We did not receive the verification email we sent out to %{strong_open}%{email_address}%{strong_close} in time."
+msgstr ""
+
+msgid "Notify|We wait for 30 minutes for messages to appear in your instance's Service Desk inbox."
+msgstr ""
+
+msgid "Notify|We were not able to make a connection to the specified host or there was an SSL issue."
+msgstr ""
+
+msgid "Notify|You don't have access to the project."
+msgstr ""
+
+msgid "Notify|You have been mentioned in an issue."
+msgstr ""
+
+msgid "Notify|You have been mentioned in merge request %{mr_link}"
+msgstr ""
+
+msgid "Notify|You have been unsubscribed from receiving GitLab administrator notifications."
+msgstr ""
+
+msgid "Notify|Your CSV import for project %{project_link} has been completed."
+msgstr ""
+
+msgid "Notify|Your account has been created successfully."
+msgstr ""
+
+msgid "Notify|Your email address %{strong_open}%{email_address}%{strong_close} for the Service Desk of %{project_link_start}%{project_name}%{project_link_end} was verified successfully."
+msgstr ""
+
+msgid "Notify|Your request to join the %{target_to_join} %{target_type} has been %{denied_tag}."
+msgstr ""
+
+msgid "Notify|currently supported languages"
+msgstr ""
+
+msgid "Notify|deleted"
+msgstr ""
+
+msgid "Notify|login.........................................."
+msgstr ""
+
+msgid "Notify|pushed new"
+msgstr ""
+
+msgid "Notify|pushed to"
+msgstr ""
+
+msgid "Notify|successfully completed %{jobs} in %{stages}."
+msgstr ""
+
+msgid "Nov"
+msgstr ""
+
+msgid "November"
+msgstr ""
+
+msgid "Now, personalize your GitLab experience"
+msgstr ""
+
+msgid "Number of Elasticsearch shards and replicas per index:"
+msgstr ""
+
+msgid "Number of Git pushes after which Gitaly is asked to optimize a repository."
+msgstr ""
+
+msgid "Number of LOCs per commit"
+msgstr ""
+
+msgid "Number of Reports"
+msgstr ""
+
+msgid "Number of commits"
+msgstr ""
+
+msgid "Number of commits per MR"
+msgstr ""
+
+msgid "Number of employees"
+msgstr ""
+
+msgid "Number of events"
+msgstr ""
+
+msgid "Number of files touched"
+msgstr ""
+
+msgid "Number of replicas"
+msgstr ""
+
+msgid "Number of shards"
+msgstr ""
+
+msgid "Number of shards for non-code indexing"
+msgstr ""
+
+msgid "OK"
+msgstr ""
+
+msgid "OKR|Existing key result"
+msgstr ""
+
+msgid "OKR|Existing objective"
+msgstr ""
+
+msgid "OKR|New key result"
+msgstr ""
+
+msgid "OKR|New objective"
+msgstr ""
+
+msgid "Object does not exist on the server or you don't have permissions to access it"
+msgstr ""
+
+msgid "Objective"
+msgstr ""
+
+msgid "Observability"
+msgstr ""
+
+msgid "Observability|Dashboards"
+msgstr ""
+
+msgid "Observability|Data sources"
+msgstr ""
+
+msgid "Observability|Explore telemetry data"
+msgstr ""
+
+msgid "Observability|Manage dashboards"
+msgstr ""
+
+msgid "Oct"
+msgstr ""
+
+msgid "October"
+msgstr ""
+
+msgid "Off"
+msgstr ""
+
+msgid "Offline"
+msgstr ""
+
+msgid "Oh no!"
+msgstr ""
+
+msgid "Okay"
+msgstr ""
+
+msgid "Oldest first"
+msgstr ""
+
+msgid "OmniAuth"
+msgstr ""
+
+msgid "On"
+msgstr ""
+
+msgid "On %{end_date}, your trial will end and %{namespace_name} will be limited to %{free_user_limit} member"
+msgid_plural "On %{end_date}, your trial will end and %{namespace_name} will be limited to %{free_user_limit} members"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "On the left sidebar, select %{merge_requests_link} to view them."
+msgstr ""
+
+msgid "On track"
+msgstr ""
+
+msgid "On-call Schedules"
+msgstr ""
+
+msgid "On-call schedules"
+msgstr ""
+
+msgid "On-demand scans run outside of the DevOps cycle and find vulnerabilities in your projects"
+msgstr ""
+
+msgid "OnCallScheduless|Any escalation rules that are using this schedule will also be deleted."
+msgstr ""
+
+msgid "OnCallSchedules|1 day"
+msgstr ""
+
+msgid "OnCallSchedules|2 weeks"
+msgstr ""
+
+msgid "OnCallSchedules|Add a rotation"
+msgstr ""
+
+msgid "OnCallSchedules|Add an additional schedule to your project"
+msgstr ""
+
+msgid "OnCallSchedules|Add rotation"
+msgstr ""
+
+msgid "OnCallSchedules|Add schedule"
+msgstr ""
+
+msgid "OnCallSchedules|Are you sure you want to delete the \"%{deleteRotation}\" rotation? This action cannot be undone."
+msgstr ""
+
+msgid "OnCallSchedules|Are you sure you want to delete the \"%{deleteSchedule}\" schedule? This action cannot be undone."
+msgstr ""
+
+msgid "OnCallSchedules|Collapse schedule"
+msgstr ""
+
+msgid "OnCallSchedules|Create on-call schedules in GitLab"
+msgstr ""
+
+msgid "OnCallSchedules|Currently no rotation"
+msgstr ""
+
+msgid "OnCallSchedules|Delete rotation"
+msgstr ""
+
+msgid "OnCallSchedules|Delete schedule"
+msgstr ""
+
+msgid "OnCallSchedules|Edit rotation"
+msgstr ""
+
+msgid "OnCallSchedules|Edit schedule"
+msgstr ""
+
+msgid "OnCallSchedules|Enable end date"
+msgstr ""
+
+msgid "OnCallSchedules|Expand schedule"
+msgstr ""
+
+msgid "OnCallSchedules|Failed to add rotation"
+msgstr ""
+
+msgid "OnCallSchedules|Failed to add schedule"
+msgstr ""
+
+msgid "OnCallSchedules|Failed to edit schedule"
+msgstr ""
+
+msgid "OnCallSchedules|For this rotation, on-call will be:"
+msgstr ""
+
+msgid "OnCallSchedules|On-call schedule %{obstacle} in project %{project}"
+msgstr ""
+
+msgid "OnCallSchedules|On-call schedules"
+msgstr ""
+
+msgid "OnCallSchedules|Please note, rotations with shifts that are less than four hours are currently not supported in the weekly view."
+msgstr ""
+
+msgid "OnCallSchedules|Removing this user may put their on-call team at risk of missing a notification."
+msgstr ""
+
+msgid "OnCallSchedules|Removing yourself may put your on-call team at risk of missing a notification."
+msgstr ""
+
+msgid "OnCallSchedules|Restrict to time intervals"
+msgstr ""
+
+msgid "OnCallSchedules|Rotation end date/time must come after start date/time"
+msgstr ""
+
+msgid "OnCallSchedules|Rotation length"
+msgstr ""
+
+msgid "OnCallSchedules|Rotation length must be a positive number"
+msgstr ""
+
+msgid "OnCallSchedules|Rotation name cannot be empty"
+msgstr ""
+
+msgid "OnCallSchedules|Rotation participants cannot be empty"
+msgstr ""
+
+msgid "OnCallSchedules|Rotation start date cannot be empty"
+msgstr ""
+
+msgid "OnCallSchedules|Rotations"
+msgstr ""
+
+msgid "OnCallSchedules|Route alerts directly to specific members of your team"
+msgstr ""
+
+msgid "OnCallSchedules|Route alerts directly to specific members of your team. To access this feature, ask %{linkStart}a project Owner%{linkEnd} to grant you at least the Maintainer role."
+msgstr ""
+
+msgid "OnCallSchedules|Select participant"
+msgstr ""
+
+msgid "OnCallSchedules|Select timezone"
+msgstr ""
+
+msgid "OnCallSchedules|Sets the default timezone for the schedule, for all participants"
+msgstr ""
+
+msgid "OnCallSchedules|Successfully created a new rotation"
+msgstr ""
+
+msgid "OnCallSchedules|Successfully edited your rotation"
+msgstr ""
+
+msgid "OnCallSchedules|The rotation could not be deleted. Please try again."
+msgstr ""
+
+msgid "OnCallSchedules|The rotation could not be updated. Please try again."
+msgstr ""
+
+msgid "OnCallSchedules|The schedule could not be deleted. Please try again."
+msgstr ""
+
+msgid "OnCallSchedules|The schedule could not be updated. Please try again."
+msgstr ""
+
+msgid "OnCallSchedules|Try adding a rotation"
+msgstr ""
+
+msgid "OnCallSchedules|User %{name} is currently part of:"
+msgstr ""
+
+msgid "OnCallSchedules|View next timeframe"
+msgstr ""
+
+msgid "OnCallSchedules|View previous timeframe"
+msgstr ""
+
+msgid "OnCallSchedules|You are currently a part of:"
+msgstr ""
+
+msgid "OnCallSchedules|Your schedule has been successfully created. To add individual users to this schedule, use the Add a rotation button. To enable notifications for this schedule, you must also create an %{linkStart}escalation policy%{linkEnd}."
+msgstr ""
+
+msgid "OnDemandScans|%{learnMoreLinkStart}Learn more about on-demand scans%{learnMoreLinkEnd}."
+msgstr ""
+
+msgid "OnDemandScans|%{profileType} profile library"
+msgstr ""
+
+msgid "OnDemandScans|%{textStart}Tags specify which runners process this scan. Runners must have every tag selected.%{textEnd} %{linkStart}What are runner tags?%{linkEnd}"
+msgstr ""
+
+msgid "OnDemandScans|Add a schedule to run this scan at a specified date and time or on a recurring basis. Scheduled scans are automatically saved to scan library."
+msgstr ""
+
+msgid "OnDemandScans|Analyze a deployed version of your web application for known vulnerabilities by examining it from the outside in. DAST works by simulating external attacks on your application while it is running."
+msgstr ""
+
+msgid "OnDemandScans|Are you sure you want to delete this scan?"
+msgstr ""
+
+msgid "OnDemandScans|Cancel"
+msgstr ""
+
+msgid "OnDemandScans|Could not delete saved scan. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "OnDemandScans|Could not fetch on-demand scans. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "OnDemandScans|Could not run the scan. Please try again."
+msgstr ""
+
+msgid "OnDemandScans|DAST configuration"
+msgstr ""
+
+msgid "OnDemandScans|DAST scans for vulnerabilities in your project's running application, website, or API. For details of all configuration options, see the %{linkStart}GitLab DAST documentation%{linkEnd}."
+msgstr ""
+
+msgid "OnDemandScans|Define the fundamental configuration options for your on-demand scan."
+msgstr ""
+
+msgid "OnDemandScans|Delete profile"
+msgstr ""
+
+msgid "OnDemandScans|Description"
+msgstr ""
+
+msgid "OnDemandScans|Discard changes"
+msgstr ""
+
+msgid "OnDemandScans|Do you want to discard the changes or keep editing this profile? Unsaved changes will be lost."
+msgstr ""
+
+msgid "OnDemandScans|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
+msgid "OnDemandScans|Edit %{profileType} profile"
+msgstr ""
+
+msgid "OnDemandScans|Edit on-demand DAST scan"
+msgstr ""
+
+msgid "OnDemandScans|Edit on-demand scan"
+msgstr ""
+
+msgid "OnDemandScans|Edit profile"
+msgstr ""
+
+msgid "OnDemandScans|Enable scan schedule"
+msgstr ""
+
+msgid "OnDemandScans|For example: Tests the login page for SQL injections"
+msgstr ""
+
+msgid "OnDemandScans|Keep editing"
+msgstr ""
+
+msgid "OnDemandScans|My daily scan"
+msgstr ""
+
+msgid "OnDemandScans|New %{profileType} profile"
+msgstr ""
+
+msgid "OnDemandScans|New on-demand DAST scan"
+msgstr ""
+
+msgid "OnDemandScans|New on-demand scan"
+msgstr ""
+
+msgid "OnDemandScans|New profile"
+msgstr ""
+
+msgid "OnDemandScans|New scan"
+msgstr ""
+
+msgid "OnDemandScans|No %{profileType} profiles found for DAST"
+msgstr ""
+
+msgid "OnDemandScans|On-demand Scans"
+msgstr ""
+
+msgid "OnDemandScans|On-demand scans"
+msgstr ""
+
+msgid "OnDemandScans|On-demand scans run outside of DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}."
+msgstr ""
+
+msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
+msgstr ""
+
+msgid "OnDemandScans|Only project owners and maintainers can select runner tags."
+msgstr ""
+
+msgid "OnDemandScans|Pre-scan verification for %{profile_name} completed with"
+msgstr ""
+
+msgid "OnDemandScans|Repeats"
+msgstr ""
+
+msgid "OnDemandScans|Run scan"
+msgstr ""
+
+msgid "OnDemandScans|Runner tags"
+msgstr ""
+
+msgid "OnDemandScans|Save and run scan"
+msgstr ""
+
+msgid "OnDemandScans|Save scan"
+msgstr ""
+
+msgid "OnDemandScans|Scan configuration"
+msgstr ""
+
+msgid "OnDemandScans|Scan library"
+msgstr ""
+
+msgid "OnDemandScans|Scan name"
+msgstr ""
+
+msgid "OnDemandScans|Scan results will be associated with the selected branch."
+msgstr ""
+
+msgid "OnDemandScans|Scan schedule"
+msgstr ""
+
+msgid "OnDemandScans|Scan type"
+msgstr ""
+
+msgid "OnDemandScans|Select runner tags"
+msgstr ""
+
+msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
+msgstr ""
+
+msgid "OnDemandScans|Start time"
+msgstr ""
+
+msgid "OnDemandScans|Target"
+msgstr ""
+
+msgid "OnDemandScans|The scan could not be canceled."
+msgstr ""
+
+msgid "OnDemandScans|The scan could not be retried."
+msgstr ""
+
+msgid "OnDemandScans|There are no finished scans."
+msgstr ""
+
+msgid "OnDemandScans|There are no running scans."
+msgstr ""
+
+msgid "OnDemandScans|There are no saved scans."
+msgstr ""
+
+msgid "OnDemandScans|There are no scheduled scans."
+msgstr ""
+
+msgid "OnDemandScans|Timezone"
+msgstr ""
+
+msgid "OnDemandScans|Unable to fetch runner tags. Try reloading the page."
+msgstr ""
+
+msgid "OnDemandScans|Verify configuration"
+msgstr ""
+
+msgid "OnDemandScans|View results"
+msgstr ""
+
+msgid "OnDemandScans|You cannot perform any action on this page because you only have %{linkStart}auditor-level access%{linkEnd} and are not a member of the project."
+msgstr ""
+
+msgid "OnDemandScans|You have unsaved changes"
+msgstr ""
+
+msgid "OnDemandScans|You must create a repository within your project to run an on-demand scan."
+msgstr ""
+
+msgid "OnDemandScans|at"
+msgstr ""
+
+msgid "Once imported, repositories can be mirrored over SSH. Read more %{link_start}here%{link_end}."
+msgstr ""
+
+msgid "One more item"
+msgid_plural "%d more items"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "One or more arguments are invalid: %{args}."
+msgstr ""
+
+msgid "One or more contacts were successfully added."
+msgstr ""
+
+msgid "One or more contacts were successfully removed."
+msgstr ""
+
+msgid "One or more groups that you don't have access to."
+msgstr ""
+
+msgid "One or more of you personal access tokens were revoked"
+msgstr ""
+
+msgid "One or more of your %{provider} projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git."
+msgstr ""
+
+msgid "One or more of your dependency files are not supported, and the dependency list may be incomplete. Below is a list of supported file types."
+msgstr ""
+
+msgid "One or more of your personal access tokens has expired."
+msgstr ""
+
+msgid "One or more of your personal access tokens have expired."
+msgstr ""
+
+msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
+msgstr ""
+
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
+msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
+msgstr ""
+
+msgid "Only 'Reporter' roles and above on tiers Premium and above can see Value Stream Analytics."
+msgstr ""
+
+msgid "Only 1 appearances row can exist"
+msgstr ""
+
+msgid "Only HTTP(S)"
+msgstr ""
+
+msgid "Only Issue ID or merge request ID is required"
+msgstr ""
+
+msgid "Only Project Members"
+msgstr ""
+
+msgid "Only SSH"
+msgstr ""
+
+msgid "Only accessible by %{membersPageLinkStart}project members%{membersPageLinkEnd}. Membership must be explicitly granted to each user."
+msgstr ""
+
+msgid "Only active projects show up in the search and on the dashboard."
+msgstr ""
+
+msgid "Only include features new to your current subscription tier."
+msgstr ""
+
+msgid "Only log Akismet verdict, do not prevent issue or snippet creation when spam is detected."
+msgstr ""
+
+msgid "Only members of this group can access the wiki."
+msgstr ""
+
+msgid "Only one security policy bot is allowed per project"
+msgstr ""
+
+msgid "Only one source is required but both were provided"
+msgstr ""
+
+msgid "Only policy:"
+msgstr ""
+
+msgid "Only proceed if you trust %{idp_url} to control your GitLab account sign in."
+msgstr ""
+
+msgid "Only project members can comment."
+msgstr ""
+
+msgid "Only projects created under a Ultimate license are available in Security Dashboards."
+msgstr ""
+
+msgid "Only reCAPTCHA v2 is supported:"
+msgstr ""
+
+msgid "Only required if not using role instance credentials."
+msgstr ""
+
+msgid "Only use lowercase letters, numbers, and underscores."
+msgstr ""
+
+msgid "Only verified users with an email address in any of these domains can be added to the group. Multiple domains are supported."
+msgstr ""
+
+msgid "Only visible to you"
+msgstr ""
+
+msgid "Only ‘Reporter’ roles and above on tiers Premium and above can see Productivity Analytics."
+msgstr ""
+
+msgid "Oops, are you sure?"
+msgstr ""
+
+msgid "Open"
+msgstr ""
+
+msgid "Open Selection"
+msgstr ""
+
+msgid "Open color picker"
+msgstr ""
+
+msgid "Open errors"
+msgstr ""
+
+msgid "Open evidence JSON in new tab"
+msgstr ""
+
+msgid "Open full view"
+msgstr ""
+
+msgid "Open in Gitpod"
+msgstr ""
+
+msgid "Open in Web IDE"
+msgstr ""
+
+msgid "Open in file view"
+msgstr ""
+
+msgid "Open in your IDE"
+msgstr ""
+
+msgid "Open new window"
+msgstr ""
+
+msgid "Open raw"
+msgstr ""
+
+msgid "Open sidebar"
+msgstr ""
+
+msgid "Open: %{open}"
+msgstr ""
+
+msgid "OpenAPI"
+msgstr ""
+
+msgid "OpenAPI Specification file URL"
+msgstr ""
+
+msgid "OpenAPI Specification file path or URL"
+msgstr ""
+
+msgid "OpenSearch's region."
+msgstr ""
+
+msgid "Opened"
+msgstr ""
+
+msgid "OpenedNDaysAgo|Created"
+msgstr ""
+
+msgid "Opens in a new window"
+msgstr ""
+
+msgid "Opens new window"
+msgstr ""
+
+msgid "Operation not allowed"
+msgstr ""
+
+msgid "Operations"
+msgstr ""
+
+msgid "Operations Dashboard"
+msgstr ""
+
+msgid "OperationsDashboard|Add a project to the dashboard"
+msgstr ""
+
+msgid "OperationsDashboard|Add projects"
+msgstr ""
+
+msgid "OperationsDashboard|More information"
+msgstr ""
+
+msgid "OperationsDashboard|Operations Dashboard"
+msgstr ""
+
+msgid "OperationsDashboard|The Operations and Environments dashboards share the same list of projects. When you add or remove a project from one, GitLab adds or removes the project from the other. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
+msgid "OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses."
+msgstr ""
+
+msgid "Opstrace endpoint for Error Tracking integration"
+msgstr ""
+
+msgid "Optimize repository period"
+msgstr ""
+
+msgid "Optimize your workflow with CI/CD Pipelines"
+msgstr ""
+
+msgid "Optional"
+msgstr ""
+
+msgid "Optionally, you can %{link_to_customize} how FogBugz email addresses and usernames are imported into GitLab."
+msgstr ""
+
+msgid "Options"
+msgstr ""
+
+msgid "Ordered list"
+msgstr ""
+
+msgid "Organization"
+msgstr ""
+
+msgid "Organizations"
+msgstr ""
+
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
+msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgstr ""
+
+msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
+msgstr ""
+
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
+msgid "Organization|Organization navigation"
+msgstr ""
+
+msgid "Organization|Organization overview"
+msgstr ""
+
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
+msgid "Organization|Search or filter list"
+msgstr ""
+
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
+msgid "Orphaned member"
+msgstr ""
+
+msgid "Other available runners"
+msgstr ""
+
+msgid "Other information"
+msgstr ""
+
+msgid "Other labels"
+msgstr ""
+
+msgid "Other merge requests block this MR"
+msgstr ""
+
+msgid "Other versions"
+msgstr ""
+
+msgid "Other visibility settings have been disabled by the administrator."
+msgstr ""
+
+msgid "Otherwise, click the link below to complete the process."
+msgstr ""
+
+msgid "Otherwise, click the link below to complete the process:"
+msgstr ""
+
+msgid "Our team has been notified. Please try again."
+msgstr ""
+
+msgid "Out-of-compliance with this project's policies and should be removed"
+msgstr ""
+
+msgid "OutboundRequests|Allow requests to the local network from hooks and integrations."
+msgstr ""
+
+msgid "OutboundRequests|Allow requests to the local network from system hooks"
+msgstr ""
+
+msgid "OutboundRequests|Allow requests to the local network from webhooks and integrations"
+msgstr ""
+
+msgid "OutboundRequests|Block all requests, except for IP addresses, IP ranges, and domain names defined in the allowlist"
+msgstr ""
+
+msgid "OutboundRequests|Enforce DNS-rebinding attack protection"
+msgstr ""
+
+msgid "OutboundRequests|Local IP addresses and domain names that hooks and integrations can access"
+msgstr ""
+
+msgid "OutboundRequests|Outbound requests"
+msgstr ""
+
+msgid "OutboundRequests|Requests can be made to these IP addresses and domains even when local requests are not allowed. IP ranges such as %{code_start}1:0:0:0:0:0:0:0/124%{code_end} and %{code_start}127.0.0.0/28%{code_end} are supported. Domain wildcards are not supported. To separate entries, use commas, semicolons, or newlines. The allowlist can have a maximum of 1000 entries. Domains must be IDNA-encoded."
+msgstr ""
+
+msgid "OutboundRequests|Resolve IP addresses for outbound requests to prevent DNS-rebinding attacks."
+msgstr ""
+
+msgid "OutboundRequests|Webhooks and integrations might not work properly."
+msgstr ""
+
+msgid "OutdatedBrowser|GitLab may not work properly, because you are using an outdated web browser."
+msgstr ""
+
+msgid "OutdatedBrowser|Please install a %{browser_link_start}supported web browser%{browser_link_end} for a better experience."
+msgstr ""
+
+msgid "Outdent line"
+msgstr ""
+
+msgid "Overridden"
+msgstr ""
+
+msgid "Overview"
+msgstr ""
+
+msgid "Overwrite diverged branches"
+msgstr ""
+
+msgid "Owned by %{image_tag}"
+msgstr ""
+
+msgid "Owned by anyone"
+msgstr ""
+
+msgid "Owned by me"
+msgstr ""
+
+msgid "Owned by:"
+msgstr ""
+
+msgid "Owner"
+msgstr ""
+
+msgid "Owners and administrators"
+msgstr ""
+
+msgid "Owners can modify this selection."
+msgstr ""
+
+msgid "PQL|An error occurred while sending hand raise lead."
+msgstr ""
+
+msgid "PQL|By providing my contact information, I agree GitLab may contact me via email about its product, services and events. You may opt-out at any time by unsubscribing in emails or visiting our communication preference center."
+msgstr ""
+
+msgid "PQL|Cancel"
+msgstr ""
+
+msgid "PQL|Contact our Sales team"
+msgstr ""
+
+msgid "PQL|Contact sales"
+msgstr ""
+
+msgid "PQL|Hello %{userName}. Before putting you in touch with our sales team, we would like you to verify and complete the information below."
+msgstr ""
+
+msgid "PQL|Message for the Sales team (optional)"
+msgstr ""
+
+msgid "PQL|Please select a city or state"
+msgstr ""
+
+msgid "PQL|Submit information"
+msgstr ""
+
+msgid "PQL|Thank you for reaching out! Our sales team will get back to you soon."
+msgstr ""
+
+msgid "Package Registry"
+msgstr ""
+
+msgid "Package Registry: authenticated API requests"
+msgstr ""
+
+msgid "Package Registry: unauthenticated API requests"
+msgstr ""
+
+msgid "Package already exists"
+msgstr ""
+
+msgid "Package deleted successfully"
+msgstr ""
+
+msgid "Package file size limits"
+msgstr ""
+
+msgid "Package recipe already exists"
+msgstr ""
+
+msgid "Package registry rate limits"
+msgstr ""
+
+msgid "Package registry types for which metadata is stored, required for License Compliance for CycloneDX files."
+msgstr ""
+
+msgid "Package type"
+msgstr ""
+
+msgid "Package type must be Composer"
+msgstr ""
+
+msgid "Package type must be Conan"
+msgstr ""
+
+msgid "Package type must be Debian"
+msgstr ""
+
+msgid "Package type must be Helm"
+msgstr ""
+
+msgid "Package type must be Maven"
+msgstr ""
+
+msgid "Package type must be NPM"
+msgstr ""
+
+msgid "Package type must be NuGet"
+msgstr ""
+
+msgid "Package type must be PyPi"
+msgstr ""
+
+msgid "Package type must be RPM"
+msgstr ""
+
+msgid "Package type must be RubyGems"
+msgstr ""
+
+msgid "PackageRegistry|%{name} version %{version} was first created %{datetime}"
+msgstr ""
+
+msgid "PackageRegistry|Add Conan Remote"
+msgstr ""
+
+msgid "PackageRegistry|Add Gradle Groovy DSL repository command"
+msgstr ""
+
+msgid "PackageRegistry|Add Gradle Kotlin DSL repository command"
+msgstr ""
+
+msgid "PackageRegistry|Add NuGet Source"
+msgstr ""
+
+msgid "PackageRegistry|Add composer registry"
+msgstr ""
+
+msgid "PackageRegistry|Additional metadata"
+msgstr ""
+
+msgid "PackageRegistry|Allow duplicates"
+msgstr ""
+
+msgid "PackageRegistry|Allow packages with the same name and version to be uploaded to the registry. The newest version of a package is always used when installing."
+msgstr ""
+
+msgid "PackageRegistry|App group: %{group}"
+msgstr ""
+
+msgid "PackageRegistry|App name: %{name}"
+msgstr ""
+
+msgid "PackageRegistry|Built by pipeline %{link} triggered %{datetime} by %{author}"
+msgstr ""
+
+msgid "PackageRegistry|Composer"
+msgstr ""
+
+msgid "PackageRegistry|Composer.json with license: %{license} and version: %{version}"
+msgstr ""
+
+msgid "PackageRegistry|Conan"
+msgstr ""
+
+msgid "PackageRegistry|Conan Command"
+msgstr ""
+
+msgid "PackageRegistry|Configure in settings"
+msgstr ""
+
+msgid "PackageRegistry|Configure package forwarding and package file size limits."
+msgstr ""
+
+msgid "PackageRegistry|Copy .pypirc content"
+msgstr ""
+
+msgid "PackageRegistry|Copy Conan Command"
+msgstr ""
+
+msgid "PackageRegistry|Copy Conan Setup Command"
+msgstr ""
+
+msgid "PackageRegistry|Copy Gradle Groovy DSL install command"
+msgstr ""
+
+msgid "PackageRegistry|Copy Gradle Kotlin DSL install command"
+msgstr ""
+
+msgid "PackageRegistry|Copy Maven XML"
+msgstr ""
+
+msgid "PackageRegistry|Copy Maven command"
+msgstr ""
+
+msgid "PackageRegistry|Copy Maven registry XML"
+msgstr ""
+
+msgid "PackageRegistry|Copy NuGet Command"
+msgstr ""
+
+msgid "PackageRegistry|Copy NuGet Setup Command"
+msgstr ""
+
+msgid "PackageRegistry|Copy Pip command"
+msgstr ""
+
+msgid "PackageRegistry|Copy SHA"
+msgstr ""
+
+msgid "PackageRegistry|Copy add Gradle Groovy DSL repository command"
+msgstr ""
+
+msgid "PackageRegistry|Copy add Gradle Kotlin DSL repository command"
+msgstr ""
+
+msgid "PackageRegistry|Copy and paste this inside your %{codeStart}pom.xml%{codeEnd} %{codeStart}dependencies%{codeEnd} block."
+msgstr ""
+
+msgid "PackageRegistry|Copy npm command"
+msgstr ""
+
+msgid "PackageRegistry|Copy npm setup command"
+msgstr ""
+
+msgid "PackageRegistry|Copy registry include"
+msgstr ""
+
+msgid "PackageRegistry|Copy require package include"
+msgstr ""
+
+msgid "PackageRegistry|Copy target SHA"
+msgstr ""
+
+msgid "PackageRegistry|Copy yarn command"
+msgstr ""
+
+msgid "PackageRegistry|Copy yarn setup command"
+msgstr ""
+
+msgid "PackageRegistry|Created by commit %{link} on branch %{branch}"
+msgstr ""
+
+msgid "PackageRegistry|Debian"
+msgstr ""
+
+msgid "PackageRegistry|Delete %{count} assets"
+msgstr ""
+
+msgid "PackageRegistry|Delete Package Version"
+msgstr ""
+
+msgid "PackageRegistry|Delete asset"
+msgstr ""
+
+msgid "PackageRegistry|Delete package"
+msgstr ""
+
+msgid "PackageRegistry|Delete package asset"
+msgstr ""
+
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
+msgid "PackageRegistry|Delete packages"
+msgstr ""
+
+msgid "PackageRegistry|Delete selected"
+msgstr ""
+
+msgid "PackageRegistry|Delete this package"
+msgstr ""
+
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting this package while request forwarding is enabled for the project can pose a security risk. Do you want to delete %{name} version %{version} anyway? %{docLinkStart}What are the risks?%{docLinkEnd}"
+msgstr ""
+
+msgid "PackageRegistry|Duplicate packages"
+msgstr ""
+
+msgid "PackageRegistry|Enforce %{packageType} setting for all subgroups"
+msgstr ""
+
+msgid "PackageRegistry|Enforce %{package_type} setting for all subgroups"
+msgstr ""
+
+msgid "PackageRegistry|Error publishing"
+msgstr ""
+
+msgid "PackageRegistry|Examples of assets include .pom & .jar files"
+msgstr ""
+
+msgid "PackageRegistry|Failed to load the package data"
+msgstr ""
+
+msgid "PackageRegistry|Failed to load version data"
+msgstr ""
+
+msgid "PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}"
+msgstr ""
+
+msgid "PackageRegistry|For more information on the Conan registry, %{linkStart}see the documentation%{linkEnd}."
+msgstr ""
+
+msgid "PackageRegistry|For more information on the Maven registry, %{linkStart}see the documentation%{linkEnd}."
+msgstr ""
+
+msgid "PackageRegistry|For more information on the NuGet registry, %{linkStart}see the documentation%{linkEnd}."
+msgstr ""
+
+msgid "PackageRegistry|For more information on the PyPi registry, %{linkStart}see the documentation%{linkEnd}."
+msgstr ""
+
+msgid "PackageRegistry|Forward %{packageType} package requests"
+msgstr ""
+
+msgid "PackageRegistry|Forward %{package_type} package requests"
+msgstr ""
+
+msgid "PackageRegistry|Forward package requests"
+msgstr ""
+
+msgid "PackageRegistry|Forward package requests to a public registry if the packages are not found in the GitLab package registry."
+msgstr ""
+
+msgid "PackageRegistry|Generic"
+msgstr ""
+
+msgid "PackageRegistry|Gradle Groovy DSL"
+msgstr ""
+
+msgid "PackageRegistry|Gradle Groovy DSL install command"
+msgstr ""
+
+msgid "PackageRegistry|Gradle Kotlin DSL"
+msgstr ""
+
+msgid "PackageRegistry|Gradle Kotlin DSL install command"
+msgstr ""
+
+msgid "PackageRegistry|Helm"
+msgstr ""
+
+msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
+msgstr ""
+
+msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}pom.xml%{codeEnd} file."
+msgstr ""
+
+msgid "PackageRegistry|Install package version"
+msgstr ""
+
+msgid "PackageRegistry|Instance-level"
+msgstr ""
+
+msgid "PackageRegistry|Invalid Package: failed metadata extraction"
+msgstr ""
+
+msgid "PackageRegistry|Last downloaded %{dateTime}"
+msgstr ""
+
+msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
+msgstr ""
+
+msgid "PackageRegistry|License information located at %{link}"
+msgstr ""
+
+msgid "PackageRegistry|Manage storage used by package assets"
+msgstr ""
+
+msgid "PackageRegistry|Manually Published"
+msgstr ""
+
+msgid "PackageRegistry|Maven"
+msgstr ""
+
+msgid "PackageRegistry|Maven Command"
+msgstr ""
+
+msgid "PackageRegistry|Maven XML"
+msgstr ""
+
+msgid "PackageRegistry|NuGet"
+msgstr ""
+
+msgid "PackageRegistry|NuGet Command"
+msgstr ""
+
+msgid "PackageRegistry|Number of duplicate assets to keep"
+msgstr ""
+
+msgid "PackageRegistry|Other versions"
+msgstr ""
+
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
+msgid "PackageRegistry|Package asset deleted successfully"
+msgstr ""
+
+msgid "PackageRegistry|Package assets deleted successfully"
+msgstr ""
+
+msgid "PackageRegistry|Package deleted successfully"
+msgstr ""
+
+msgid "PackageRegistry|Package formats"
+msgstr ""
+
+msgid "PackageRegistry|Package forwarding"
+msgstr ""
+
+msgid "PackageRegistry|Package has %{updatesCount} archived update"
+msgid_plural "PackageRegistry|Package has %{updatesCount} archived updates"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, built by pipeline %{pipeline}, and published to the registry %{datetime}"
+msgstr ""
+
+msgid "PackageRegistry|Packages and assets cleanup is ready to be executed when the next cleanup job runs."
+msgstr ""
+
+msgid "PackageRegistry|Packages and assets will not be deleted until cleanup runs in %{nextRunAt}."
+msgstr ""
+
+msgid "PackageRegistry|Packages deleted successfully"
+msgstr ""
+
+msgid "PackageRegistry|Permanently delete"
+msgstr ""
+
+msgid "PackageRegistry|Permanently delete assets"
+msgstr ""
+
+msgid "PackageRegistry|Pip Command"
+msgstr ""
+
+msgid "PackageRegistry|Project-level"
+msgstr ""
+
+msgid "PackageRegistry|Publish packages if their name or version matches this regex."
+msgstr ""
+
+msgid "PackageRegistry|Published %{date}"
+msgstr ""
+
+msgid "PackageRegistry|Published by %{author}, %{date}"
+msgstr ""
+
+msgid "PackageRegistry|Published to %{projectName} by %{author}, %{date}"
+msgstr ""
+
+msgid "PackageRegistry|Published to %{projectName}, %{date}"
+msgstr ""
+
+msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
+msgstr ""
+
+msgid "PackageRegistry|PyPI"
+msgstr ""
+
+msgid "PackageRegistry|Recipe: %{recipe}"
+msgstr ""
+
+msgid "PackageRegistry|Registry setup"
+msgstr ""
+
+msgid "PackageRegistry|Remove package"
+msgstr ""
+
+msgid "PackageRegistry|Required Python: %{pythonVersion}"
+msgstr ""
+
+msgid "PackageRegistry|RubyGems"
+msgstr ""
+
+msgid "PackageRegistry|Show Composer commands"
+msgstr ""
+
+msgid "PackageRegistry|Show Conan commands"
+msgstr ""
+
+msgid "PackageRegistry|Show NPM commands"
+msgstr ""
+
+msgid "PackageRegistry|Show Nuget commands"
+msgstr ""
+
+msgid "PackageRegistry|Show PyPi commands"
+msgstr ""
+
+msgid "PackageRegistry|Show Yarn commands"
+msgstr ""
+
+msgid "PackageRegistry|Some of the selected package formats allow request forwarding. Deleting a package while request forwarding is enabled for the project can pose a security risk. Do you want to proceed with deleting the selected packages? %{docLinkStart}What are the risks?%{docLinkEnd}"
+msgstr ""
+
+msgid "PackageRegistry|Something went wrong while deleting packages."
+msgstr ""
+
+msgid "PackageRegistry|Something went wrong while deleting the package asset."
+msgstr ""
+
+msgid "PackageRegistry|Something went wrong while deleting the package assets."
+msgstr ""
+
+msgid "PackageRegistry|Something went wrong while deleting the package."
+msgstr ""
+
+msgid "PackageRegistry|Something went wrong while fetching package assets."
+msgstr ""
+
+msgid "PackageRegistry|Something went wrong while fetching the package history."
+msgstr ""
+
+msgid "PackageRegistry|Something went wrong while fetching the package metadata."
+msgstr ""
+
+msgid "PackageRegistry|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "PackageRegistry|Source project located at %{link}"
+msgstr ""
+
+msgid "PackageRegistry|Target SHA: %{sha}"
+msgstr ""
+
+msgid "PackageRegistry|There are no other versions of this package."
+msgstr ""
+
+msgid "PackageRegistry|There are no packages yet"
+msgstr ""
+
+msgid "PackageRegistry|There are security risks if packages are deleted while request forwarding is enabled. %{docLinkStart}What are the risks?%{docLinkEnd}"
+msgstr ""
+
+msgid "PackageRegistry|There are security risks if packages are deleted while request forwarding is enabled. %{docs_link_start}What are the risks?%{docs_link_end}"
+msgstr ""
+
+msgid "PackageRegistry|There was a problem fetching the details for this package."
+msgstr ""
+
+msgid "PackageRegistry|There was a timeout and the package was not published. Delete this package and try again."
+msgstr ""
+
+msgid "PackageRegistry|There was an error publishing a %{packageName} package"
+msgstr ""
+
+msgid "PackageRegistry|This NuGet package has no dependencies."
+msgstr ""
+
+msgid "PackageRegistry|To widen your search, change or remove the filters above."
+msgstr ""
+
+msgid "PackageRegistry|Unable to fetch package version information."
+msgstr ""
+
+msgid "PackageRegistry|Unable to load package"
+msgstr ""
+
+msgid "PackageRegistry|When a package with same name and version is uploaded to the registry, more assets are added to the package. To save storage space, keep only the most recent assets."
+msgstr ""
+
+msgid "PackageRegistry|Yes, delete package"
+msgstr ""
+
+msgid "PackageRegistry|Yes, delete selected packages"
+msgstr ""
+
+msgid "PackageRegistry|You are about to delete %{count} assets. This operation is irreversible."
+msgstr ""
+
+msgid "PackageRegistry|You are about to delete %{count} packages. This operation is irreversible."
+msgstr ""
+
+msgid "PackageRegistry|You are about to delete %{filename}. This is a destructive action that may render your package unusable. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|You are about to delete %{name}, are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|You are about to delete version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more."
+msgstr ""
+
+msgid "PackageRegistry|You will need a %{linkStart}personal access token%{linkEnd}."
+msgstr ""
+
+msgid "PackageRegistry|npm"
+msgstr ""
+
+msgid "PackageRegistry|published by %{author}"
+msgstr ""
+
+msgid "Packages"
+msgstr ""
+
+msgid "Packages and registries"
+msgstr ""
+
+msgid "Packages and registries settings"
+msgstr ""
+
+msgid "Page not found"
+msgstr ""
+
+msgid "PagerDutySettings|Active"
+msgstr ""
+
+msgid "PagerDutySettings|Create a GitLab incident for each PagerDuty incident by %{linkStart}configuring a webhook in PagerDuty%{linkEnd}"
+msgstr ""
+
+msgid "PagerDutySettings|Failed to update Webhook URL"
+msgstr ""
+
+msgid "PagerDutySettings|Reset webhook URL"
+msgstr ""
+
+msgid "PagerDutySettings|Resetting the webhook URL for this project will require updating this integration's settings in PagerDuty."
+msgstr ""
+
+msgid "PagerDutySettings|Webhook URL"
+msgstr ""
+
+msgid "PagerDutySettings|Webhook URL update was successful"
+msgstr ""
+
+msgid "Pages"
+msgstr ""
+
+msgid "Pages Domain"
+msgstr ""
+
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
+msgid "Pagination|First"
+msgstr ""
+
+msgid "Pagination|Go to first page"
+msgstr ""
+
+msgid "Pagination|Go to last page"
+msgstr ""
+
+msgid "Pagination|Go to next page"
+msgstr ""
+
+msgid "Pagination|Go to previous page"
+msgstr ""
+
+msgid "Pagination|Last"
+msgstr ""
+
+msgid "Pagination|Last »"
+msgstr ""
+
+msgid "Pagination|Next"
+msgstr ""
+
+msgid "Pagination|Prev"
+msgstr ""
+
+msgid "Pagination|« First"
+msgstr ""
+
+msgid "Parameter"
+msgstr ""
+
+msgid "Parent"
+msgstr ""
+
+msgid "Part of merge request changes"
+msgstr ""
+
+msgid "Participants"
+msgstr ""
+
+msgid "Pass job variables"
+msgstr ""
+
+msgid "Passed"
+msgstr ""
+
+msgid "Passed on"
+msgstr ""
+
+msgid "Password"
+msgstr ""
+
+msgid "Password (optional)"
+msgstr ""
+
+msgid "Password authentication is unavailable."
+msgstr ""
+
+msgid "Password confirmation"
+msgstr ""
+
+msgid "Password successfully changed"
+msgstr ""
+
+msgid "Password was successfully updated. Please sign in again."
+msgstr ""
+
+msgid "PasswordPrompt|Confirm password"
+msgstr ""
+
+msgid "PasswordPrompt|Confirm password to continue"
+msgstr ""
+
+msgid "PasswordPrompt|Password is required"
+msgstr ""
+
+msgid "PasswordPrompt|Please enter your password to confirm"
+msgstr ""
+
+msgid "Passwords should be unique and not used for any other sites or services."
+msgstr ""
+
+msgid "Password|Not satisfied"
+msgstr ""
+
+msgid "Password|Satisfied"
+msgstr ""
+
+msgid "Password|To be satisfied"
+msgstr ""
+
+msgid "Password|requires at least one lowercase letter"
+msgstr ""
+
+msgid "Password|requires at least one number"
+msgstr ""
+
+msgid "Password|requires at least one symbol character"
+msgstr ""
+
+msgid "Password|requires at least one uppercase letter"
+msgstr ""
+
+msgid "Past due"
+msgstr ""
+
+msgid "Paste a public key here."
+msgstr ""
+
+msgid "Paste a public key here. %{link_start}How do I generate it?%{link_end}"
+msgstr ""
+
+msgid "Paste confidential epic link"
+msgstr ""
+
+msgid "Paste confidential issue link"
+msgstr ""
+
+msgid "Paste epic link"
+msgstr ""
+
+msgid "Paste issue link"
+msgstr ""
+
+msgid "Paste link"
+msgstr ""
+
+msgid "Paste project path (i.e. gitlab-org/gitlab)"
+msgstr ""
+
+msgid "Paste this DSN into your Sentry SDK"
+msgstr ""
+
+msgid "Patch to apply"
+msgstr ""
+
+msgid "Patches"
+msgstr ""
+
+msgid "Path"
+msgstr ""
+
+msgid "Path:"
+msgstr ""
+
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
+msgstr ""
+
+msgid "Pause"
+msgstr ""
+
+msgid "Pause time (ms)"
+msgstr ""
+
+msgid "Paused"
+msgstr ""
+
+msgid "Paused runners don't accept new jobs"
+msgstr ""
+
+msgid "Peer review by"
+msgstr ""
+
+msgid "Pending"
+msgstr ""
+
+msgid "Pending Deletion"
+msgstr ""
+
+msgid "Pending comments"
+msgstr ""
+
+msgid "Pending comments are hidden until you submit your review."
+msgstr ""
+
+msgid "Pending deletion"
+msgstr ""
+
+msgid "Pending owner action"
+msgstr ""
+
+msgid "Pending sync…"
+msgstr ""
+
+msgid "People without permission will never get a notification and won't be able to comment."
+msgstr ""
+
+msgid "People without permission will never get a notification."
+msgstr ""
+
+msgid "Percent rollout must be an integer number between 0 and 100"
+msgstr ""
+
+msgid "Percentage"
+msgstr ""
+
+msgid "Perform advanced options such as changing path, transferring, exporting, or removing the group."
+msgstr ""
+
+msgid "Perform code reviews and enhance collaboration with merge requests."
+msgstr ""
+
+msgid "Perform common operations on GitLab project"
+msgstr ""
+
+msgid "Performance optimization"
+msgstr ""
+
+msgid "PerformanceBar|Backend"
+msgstr ""
+
+msgid "PerformanceBar|Bullet notifications"
+msgstr ""
+
+msgid "PerformanceBar|ClickHouse queries"
+msgstr ""
+
+msgid "PerformanceBar|DOM Content Loaded"
+msgstr ""
+
+msgid "PerformanceBar|Download"
+msgstr ""
+
+msgid "PerformanceBar|Elasticsearch calls"
+msgstr ""
+
+msgid "PerformanceBar|External Http calls"
+msgstr ""
+
+msgid "PerformanceBar|First Contentful Paint"
+msgstr ""
+
+msgid "PerformanceBar|Frontend resources"
+msgstr ""
+
+msgid "PerformanceBar|Gitaly calls"
+msgstr ""
+
+msgid "PerformanceBar|Memory"
+msgstr ""
+
+msgid "PerformanceBar|Memory report"
+msgstr ""
+
+msgid "PerformanceBar|Redis calls"
+msgstr ""
+
+msgid "PerformanceBar|Rugged calls"
+msgstr ""
+
+msgid "PerformanceBar|SQL queries"
+msgstr ""
+
+msgid "PerformanceBar|Sort by duration"
+msgstr ""
+
+msgid "PerformanceBar|Sort chronologically"
+msgstr ""
+
+msgid "PerformanceBar|Stats"
+msgstr ""
+
+msgid "PerformanceBar|Total duration"
+msgstr ""
+
+msgid "PerformanceBar|Trace"
+msgstr ""
+
+msgid "PerformanceBar|Zoekt calls"
+msgstr ""
+
+msgid "PerformanceBar|cpu"
+msgstr ""
+
+msgid "PerformanceBar|object"
+msgstr ""
+
+msgid "PerformanceBar|wall"
+msgstr ""
+
+msgid "Period in seconds"
+msgstr ""
+
+msgid "Permalink"
+msgstr ""
+
+msgid "Permanently remove group"
+msgstr ""
+
+msgid "Permissions"
+msgstr ""
+
+msgid "Permissions Help"
+msgstr ""
+
+msgid "Permissions and group features"
+msgstr ""
+
+msgid "Permissions and project features"
+msgstr ""
+
+msgid "Personal Access Token"
+msgstr ""
+
+msgid "Personal Access Token prefix"
+msgstr ""
+
+msgid "Personal access token"
+msgstr ""
+
+msgid "Personal project creation is not allowed. Please contact your administrator with questions"
+msgstr ""
+
+msgid "Personal projects"
+msgstr ""
+
+msgid "Personal projects limit:"
+msgstr ""
+
+msgid "PersonalProject|Learn to move a project to a group"
+msgstr ""
+
+msgid "PersonalProject|Some GitLab features, including the ability to upgrade to a paid plan or start a free trial, are only available for groups and projects inside groups. %{projectName} is a personal project, so none of this is available. We recommend you move your project to a group to unlock GitLab's full potential."
+msgstr ""
+
+msgid "PersonalProject|We have some instructions to help you create a group and move your project into it."
+msgstr ""
+
+msgid "PersonalProject|Your project %{projectName} is not in a group"
+msgstr ""
+
+msgid "Phone"
+msgstr ""
+
+msgid "Phone verification exemption"
+msgstr ""
+
+msgid "Phone verification exemption has been created."
+msgstr ""
+
+msgid "Phone verification exemption has been removed."
+msgstr ""
+
+msgid "PhoneVerification|Enter a valid code."
+msgstr ""
+
+msgid "PhoneVerification|Something went wrong. Please try again."
+msgstr ""
+
+msgid "PhoneVerification|The code has expired. Request a new code and try again."
+msgstr ""
+
+msgid "PhoneVerification|There was a problem with the phone number you entered. Enter a different phone number and try again."
+msgstr ""
+
+msgid "PhoneVerification|There was a problem with the phone number you entered. Enter a valid phone number."
+msgstr ""
+
+msgid "PhoneVerification|Verification code can't be blank."
+msgstr ""
+
+msgid "PhoneVerification|You've reached the maximum number of tries. Request a new code and try again."
+msgstr ""
+
+msgid "PhoneVerification|You've reached the maximum number of tries. Wait %{interval} and try again."
+msgstr ""
+
+msgid "Pick a name"
+msgstr ""
+
+msgid "Pipeline"
+msgstr ""
+
+msgid "Pipeline %{label}"
+msgstr ""
+
+msgid "Pipeline %{label} for \"%{dataTitle}\""
+msgstr ""
+
+msgid "Pipeline Editor|Are you sure you want to reset the file to its last committed version?"
+msgstr ""
+
+msgid "Pipeline ID"
+msgstr ""
+
+msgid "Pipeline IID"
+msgstr ""
+
+msgid "Pipeline Schedule"
+msgstr ""
+
+msgid "Pipeline Schedules"
+msgstr ""
+
+msgid "Pipeline URL"
+msgstr ""
+
+msgid "Pipeline creation rate limits"
+msgstr ""
+
+msgid "Pipeline durations for the last 30 commits"
+msgstr ""
+
+msgid "Pipeline editor"
+msgstr ""
+
+msgid "Pipeline ran in fork of project"
+msgstr ""
+
+msgid "Pipeline schedules"
+msgstr ""
+
+msgid "Pipeline status emails"
+msgstr ""
+
+msgid "Pipeline subscriptions"
+msgstr ""
+
+msgid "Pipeline subscriptions trigger a new pipeline on the default branch of this project when a pipeline successfully completes for a new tag on the %{default_branch_docs} of the subscribed project."
+msgstr ""
+
+msgid "Pipeline trigger tokens"
+msgstr ""
+
+msgid "Pipeline triggers"
+msgstr ""
+
+msgid "Pipeline: %{status}"
+msgstr ""
+
+msgid "PipelineCharts|An error has occurred when retrieving the analytics data"
+msgstr ""
+
+msgid "PipelineCharts|An error has occurred when retrieving the pipelines data"
+msgstr ""
+
+msgid "PipelineCharts|An unknown error occurred while processing CI/CD analytics."
+msgstr ""
+
+msgid "PipelineCharts|CI/CD Analytics"
+msgstr ""
+
+msgid "PipelineCharts|Failed:"
+msgstr ""
+
+msgid "PipelineCharts|Overall statistics"
+msgstr ""
+
+msgid "PipelineCharts|Success ratio:"
+msgstr ""
+
+msgid "PipelineCharts|Successful:"
+msgstr ""
+
+msgid "PipelineCharts|There was an error parsing the data for the charts."
+msgstr ""
+
+msgid "PipelineCharts|Total:"
+msgstr ""
+
+msgid "PipelineEditorFileTree|Configuration files added with the include keyword"
+msgstr ""
+
+msgid "PipelineEditorFileTree|When you use the include keyword to add pipeline configuration from files in the project, those files will be listed here."
+msgstr ""
+
+msgid "PipelineEditorTutorial|Browse %{linkStart}CI/CD examples and templates%{linkEnd}"
+msgstr ""
+
+msgid "PipelineEditorTutorial|Commit the file to your repository. The pipeline then runs automatically."
+msgstr ""
+
+msgid "PipelineEditorTutorial|Get started with GitLab CI/CD"
+msgstr ""
+
+msgid "PipelineEditorTutorial|GitLab CI/CD can automatically build, test, and deploy your application."
+msgstr ""
+
+msgid "PipelineEditorTutorial|If you’re using a self-managed GitLab instance, %{linkStart}make sure your instance has runners available.%{linkEnd}"
+msgstr ""
+
+msgid "PipelineEditorTutorial|Learn more about %{linkStart}GitLab CI/CD concepts%{linkEnd}"
+msgstr ""
+
+msgid "PipelineEditorTutorial|Make your pipeline more efficient with the %{linkStart}Needs keyword%{linkEnd}"
+msgstr ""
+
+msgid "PipelineEditorTutorial|Resources to help with your CI/CD configuration:"
+msgstr ""
+
+msgid "PipelineEditorTutorial|Select the pipeline ID to view the full details about your first pipeline run."
+msgstr ""
+
+msgid "PipelineEditorTutorial|The pipeline stages and jobs are defined in a %{codeStart}.gitlab-ci.yml%{codeEnd} file. You can edit, visualize and validate the syntax in this file by using the Pipeline Editor."
+msgstr ""
+
+msgid "PipelineEditorTutorial|The pipeline status is at the top of the page."
+msgstr ""
+
+msgid "PipelineEditorTutorial|This template creates a simple test pipeline. To use it:"
+msgstr ""
+
+msgid "PipelineEditorTutorial|Use the Visualize and Lint tabs in the Pipeline Editor to visualize your pipeline and check for any errors or warnings before committing your changes."
+msgstr ""
+
+msgid "PipelineEditorTutorial|View %{linkStart}.gitlab-ci.yml syntax reference%{linkEnd}"
+msgstr ""
+
+msgid "PipelineEditorTutorial|âš™ï¸ Pipeline configuration reference"
+msgstr ""
+
+msgid "PipelineEditorTutorial|💡 Tip: Visualize and validate your pipeline"
+msgstr ""
+
+msgid "PipelineEditorTutorial|🚀 Run your first pipeline"
+msgstr ""
+
+msgid "PipelineEditor|Configuration content has changed. Re-run validation for updated results."
+msgstr ""
+
+msgid "PipelineEditor|Current content in the Edit tab will be used for the simulation."
+msgstr ""
+
+msgid "PipelineEditor|Git push event to the default branch"
+msgstr ""
+
+msgid "PipelineEditor|Other pipeline sources are not available yet."
+msgstr ""
+
+msgid "PipelineEditor|Pipeline Source"
+msgstr ""
+
+msgid "PipelineEditor|Pipeline behavior will be simulated including the %{codeStart}rules%{codeEnd} %{codeStart}only%{codeEnd} %{codeStart}except%{codeEnd} and %{codeStart}needs%{codeEnd} job dependencies."
+msgstr ""
+
+msgid "PipelineEditor|Pipeline behavior will be simulated including the %{codeStart}rules%{codeEnd} %{codeStart}only%{codeEnd} %{codeStart}except%{codeEnd} and %{codeStart}needs%{codeEnd} job dependencies. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "PipelineEditor|Pipeline simulation completed with errors"
+msgstr ""
+
+msgid "PipelineEditor|Simulated a %{codeStart}git push%{codeEnd} event for a default branch. %{codeStart}Rules%{codeEnd}, %{codeStart}only%{codeEnd}, %{codeStart}except%{codeEnd}, and %{codeStart}needs%{codeEnd} job dependencies logic have been evaluated. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "PipelineEditor|Simulation completed successfully"
+msgstr ""
+
+msgid "PipelineEditor|The CI/CD configuration is continuously validated. Errors and warnings are displayed when the CI/CD configuration file is not empty."
+msgstr ""
+
+msgid "PipelineEditor|The full configuration view is displayed when the CI/CD configuration file has valid syntax."
+msgstr ""
+
+msgid "PipelineEditor|The pipeline visualization is displayed when the CI/CD configuration file has valid syntax."
+msgstr ""
+
+msgid "PipelineEditor|This tab will be usable when the CI/CD configuration file is populated with valid syntax."
+msgstr ""
+
+msgid "PipelineEditor|Validate pipeline"
+msgstr ""
+
+msgid "PipelineEditor|Validate pipeline under selected conditions"
+msgstr ""
+
+msgid "PipelineEditor|Validate pipeline under simulated conditions"
+msgstr ""
+
+msgid "PipelineEditor|Validating pipeline... It can take up to a minute."
+msgstr ""
+
+msgid "PipelineEditor|Waiting for CI content to load..."
+msgstr ""
+
+msgid "PipelineGraph|Are you sure you want to retry %{jobName}?"
+msgstr ""
+
+msgid "PipelineGraph|Downstream pipeline might not display in the graph while the new downstream pipeline is being created."
+msgstr ""
+
+msgid "PipelineGraph|Retrying a trigger job will create a new downstream pipeline."
+msgstr ""
+
+msgid "PipelineGraph|What is a downstream pipeline?"
+msgstr ""
+
+msgid "PipelineScheduleIntervalPattern|Custom (%{linkStart}Learn more%{linkEnd}.)"
+msgstr ""
+
+msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
+msgstr ""
+
+msgid "PipelineSchedules|Active"
+msgstr ""
+
+msgid "PipelineSchedules|All"
+msgstr ""
+
+msgid "PipelineSchedules|An error occurred while creating the pipeline schedule."
+msgstr ""
+
+msgid "PipelineSchedules|An error occurred while trying to fetch the pipeline schedule."
+msgstr ""
+
+msgid "PipelineSchedules|An error occurred while updating the pipeline schedule."
+msgstr ""
+
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
+msgid "PipelineSchedules|Can have custom CI/CD variables."
+msgstr ""
+
+msgid "PipelineSchedules|Create a new pipeline schedule"
+msgstr ""
+
+msgid "PipelineSchedules|Create pipeline schedule"
+msgstr ""
+
+msgid "PipelineSchedules|Cron timezone"
+msgstr ""
+
+msgid "PipelineSchedules|Delete pipeline schedule"
+msgstr ""
+
+msgid "PipelineSchedules|Description"
+msgstr ""
+
+msgid "PipelineSchedules|Edit pipeline schedule"
+msgstr ""
+
+msgid "PipelineSchedules|Inactive"
+msgstr ""
+
+msgid "PipelineSchedules|Interval Pattern"
+msgstr ""
+
+msgid "PipelineSchedules|Last Pipeline"
+msgstr ""
+
+msgid "PipelineSchedules|Learn more in the %{linkStart}scheduled pipelines documentation.%{linkEnd}"
+msgstr ""
+
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
+msgid "PipelineSchedules|Next Run"
+msgstr ""
+
+msgid "PipelineSchedules|No pipeline schedules"
+msgstr ""
+
+msgid "PipelineSchedules|None"
+msgstr ""
+
+msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?"
+msgstr ""
+
+msgid "PipelineSchedules|Owner"
+msgstr ""
+
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
+msgid "PipelineSchedules|Pipeline schedules"
+msgstr ""
+
+msgid "PipelineSchedules|Provide a short description for this pipeline"
+msgstr ""
+
+msgid "PipelineSchedules|Run pipeline schedule"
+msgstr ""
+
+msgid "PipelineSchedules|Runs for a specific branch or tag."
+msgstr ""
+
+msgid "PipelineSchedules|Runs with the same project permissions as the schedule owner."
+msgstr ""
+
+msgid "PipelineSchedules|Successfully scheduled a pipeline to run. Go to the %{linkStart}Pipelines page%{linkEnd} for details. "
+msgstr ""
+
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
+msgid "PipelineSchedules|Take ownership"
+msgstr ""
+
+msgid "PipelineSchedules|Take ownership of pipeline schedule"
+msgstr ""
+
+msgid "PipelineSchedules|Target"
+msgstr ""
+
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
+msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
+msgstr ""
+
+msgid "PipelineSchedules|There was a problem playing the pipeline schedule."
+msgstr ""
+
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
+msgid "PipelineSource|API"
+msgstr ""
+
+msgid "PipelineSource|Chat"
+msgstr ""
+
+msgid "PipelineSource|External"
+msgstr ""
+
+msgid "PipelineSource|External Pull Request"
+msgstr ""
+
+msgid "PipelineSource|Merge Request"
+msgstr ""
+
+msgid "PipelineSource|On-Demand DAST Scan"
+msgstr ""
+
+msgid "PipelineSource|On-Demand DAST Validation"
+msgstr ""
+
+msgid "PipelineSource|Parent Pipeline"
+msgstr ""
+
+msgid "PipelineSource|Pipeline"
+msgstr ""
+
+msgid "PipelineSource|Push"
+msgstr ""
+
+msgid "PipelineSource|Schedule"
+msgstr ""
+
+msgid "PipelineSource|Trigger"
+msgstr ""
+
+msgid "PipelineSource|Web"
+msgstr ""
+
+msgid "PipelineSource|Web IDE"
+msgstr ""
+
+msgid "PipelineStatusTooltip|Pipeline: %{ciStatus}"
+msgstr ""
+
+msgid "PipelineStatusTooltip|Pipeline: %{ci_status}"
+msgstr ""
+
+msgid "PipelineWizardDefaultCommitMessage|Add %{filename}"
+msgstr ""
+
+msgid "PipelineWizardDefaultCommitMessage|Update %{filename}"
+msgstr ""
+
+msgid "PipelineWizardInputValidation|At least one entry is required"
+msgstr ""
+
+msgid "PipelineWizardInputValidation|This field is required"
+msgstr ""
+
+msgid "PipelineWizardInputValidation|This value is not valid"
+msgstr ""
+
+msgid "PipelineWizardListWidget|add another step"
+msgstr ""
+
+msgid "PipelineWizardListWidget|remove step"
+msgstr ""
+
+msgid "PipelineWizard|Commit"
+msgstr ""
+
+msgid "PipelineWizard|Commit Message"
+msgstr ""
+
+msgid "PipelineWizard|Commit changes to your file"
+msgstr ""
+
+msgid "PipelineWizard|Commit file to Branch"
+msgstr ""
+
+msgid "PipelineWizard|Commit your new file"
+msgstr ""
+
+msgid "PipelineWizard|The file has been committed."
+msgstr ""
+
+msgid "PipelineWizard|There was a problem committing the changes."
+msgstr ""
+
+msgid "PipelineWizard|There was a problem while checking whether your file already exists in the specified branch."
+msgstr ""
+
+msgid "PipelineWizard|There was an unexpected error trying to set up the template. The error has been logged."
+msgstr ""
+
+msgid "Pipelines"
+msgstr ""
+
+msgid "Pipelines charts"
+msgstr ""
+
+msgid "Pipelines for new changes cause older pending or running pipelines on the same branch to be cancelled."
+msgstr ""
+
+msgid "Pipelines settings for '%{project_name}' were successfully updated."
+msgstr ""
+
+msgid "PipelinesAiAssistant|Ai assistant"
+msgstr ""
+
+msgid "PipelinesAiAssistant|Chat with AI assistant"
+msgstr ""
+
+msgid "Pipelines|\"Hello world\" with GitLab CI"
+msgstr ""
+
+msgid "Pipelines|1. Set up a runner"
+msgstr ""
+
+msgid "Pipelines|2. Configure deployment pipeline"
+msgstr ""
+
+msgid "Pipelines|API"
+msgstr ""
+
+msgid "Pipelines|Are you sure you want to run this pipeline?"
+msgstr ""
+
+msgid "Pipelines|Auto DevOps"
+msgstr ""
+
+msgid "Pipelines|Based on your project, we recommend this template:"
+msgstr ""
+
+msgid "Pipelines|Build with confidence"
+msgstr ""
+
+msgid "Pipelines|Building for iOS?"
+msgstr ""
+
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
+msgid "Pipelines|CI lint"
+msgstr ""
+
+msgid "Pipelines|CI/CD Catalog"
+msgstr ""
+
+msgid "Pipelines|Child pipeline (%{linkStart}parent%{linkEnd})"
+msgstr ""
+
+msgid "Pipelines|Clear runner caches"
+msgstr ""
+
+msgid "Pipelines|Configure pipeline"
+msgstr ""
+
+msgid "Pipelines|Continuous integration and deployment template to test and deploy your %{name} project."
+msgstr ""
+
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Could not load artifacts."
+msgstr ""
+
+msgid "Pipelines|Could not load full configuration content"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Don't need a guide? Jump in right away with a template."
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
+msgid "Pipelines|Editor"
+msgstr ""
+
+msgid "Pipelines|Failed to update. Please reload page to update the list of artifacts."
+msgstr ""
+
+msgid "Pipelines|Follow these instructions to install GitLab Runner on macOS."
+msgstr ""
+
+msgid "Pipelines|Full configuration"
+msgstr ""
+
+msgid "Pipelines|Full configuration is view only"
+msgstr ""
+
+msgid "Pipelines|Get familiar with GitLab CI syntax by setting up a simple pipeline running a \"Hello world\" script to see how it runs, explore how CI/CD works."
+msgstr ""
+
+msgid "Pipelines|Get started with GitLab CI/CD"
+msgstr ""
+
+msgid "Pipelines|GitLab CI/CD can automatically build, test, and deploy your code. Let GitLab take care of time consuming tasks, so you can spend more time creating."
+msgstr ""
+
+msgid "Pipelines|GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline."
+msgstr ""
+
+msgid "Pipelines|Go to the pipeline editor"
+msgstr ""
+
+msgid "Pipelines|If you are unsure, ask a project maintainer to review it for you."
+msgstr ""
+
+msgid "Pipelines|If you are unsure, please ask a project maintainer to review it for you."
+msgstr ""
+
+msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
+msgstr ""
+
+msgid "Pipelines|Last Used"
+msgstr ""
+
+msgid "Pipelines|Learn the basics of pipelines and .yml files"
+msgstr ""
+
+msgid "Pipelines|Let's get that runner set up! %{emojiStart}tada%{emojiEnd}"
+msgstr ""
+
+msgid "Pipelines|Lint"
+msgstr ""
+
+msgid "Pipelines|Loading Pipelines"
+msgstr ""
+
+msgid "Pipelines|Loading pipelines"
+msgstr ""
+
+msgid "Pipelines|More Information"
+msgstr ""
+
+msgid "Pipelines|Need more information to set up your runner? %{linkStart}Check out our documentation%{linkEnd}."
+msgstr ""
+
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Not building for iOS or not what you're looking for? %{linkStart}See what else%{linkEnd} GitLab CI/CD has to offer."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
+msgid "Pipelines|Pipeline Editor"
+msgstr ""
+
+msgid "Pipelines|Pipeline syntax is correct. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "Pipelines|Project cache successfully reset."
+msgstr ""
+
+msgid "Pipelines|Ready to set up CI/CD for your project?"
+msgstr ""
+
+msgid "Pipelines|Rebasing creates a pipeline that runs code originating from a forked project merge request. Consequently there are potential security implications, such as the exposure of CI variables."
+msgstr ""
+
+msgid "Pipelines|Retry %{jobName} Job"
+msgstr ""
+
+msgid "Pipelines|Revoke trigger"
+msgstr ""
+
+msgid "Pipelines|Scheduled"
+msgstr ""
+
+msgid "Pipelines|Set up a runner"
+msgstr ""
+
+msgid "Pipelines|Something went wrong while cleaning runners cache."
+msgstr ""
+
+msgid "Pipelines|The %{namespace_name} namespace has %{percentage}%% or less Shared Runner Pipeline minutes remaining. After it runs out, no new jobs or pipelines in its projects will run."
+msgstr ""
+
+msgid "Pipelines|The %{namespace_name} namespace has exceeded its pipeline minutes quota. Buy additional pipeline minutes, or no new jobs or pipelines in its projects will run."
+msgstr ""
+
+msgid "Pipelines|The CI configuration was not loaded, please try again."
+msgstr ""
+
+msgid "Pipelines|The GitLab CI configuration could not be updated."
+msgstr ""
+
+msgid "Pipelines|There are currently no finished pipelines."
+msgstr ""
+
+msgid "Pipelines|There are currently no pipelines."
+msgstr ""
+
+msgid "Pipelines|There was a problem with loading the pipeline data."
+msgstr ""
+
+msgid "Pipelines|There was an error fetching the pipelines."
+msgstr ""
+
+msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
+msgstr ""
+
+msgid "Pipelines|This GitLab CI configuration is invalid. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "Pipelines|This GitLab CI configuration is invalid:"
+msgstr ""
+
+msgid "Pipelines|This GitLab CI configuration is invalid: %{reason}. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "Pipelines|This GitLab CI configuration is valid."
+msgstr ""
+
+msgid "Pipelines|This pipeline is stuck"
+msgstr ""
+
+msgid "Pipelines|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch."
+msgstr ""
+
+msgid "Pipelines|This pipeline ran on the contents of this merge request's source branch, not the target branch."
+msgstr ""
+
+msgid "Pipelines|This pipeline will run code originating from a forked project merge request. This means that the code can potentially have security considerations like exposing CI variables."
+msgstr ""
+
+msgid "Pipelines|This project is not currently set up to run pipelines."
+msgstr ""
+
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Total amount of compute minutes used for the pipeline"
+msgstr ""
+
+msgid "Pipelines|Total number of jobs for the pipeline"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|Try again in a few moments or contact your support team."
+msgstr ""
+
+msgid "Pipelines|Try test template"
+msgstr ""
+
+msgid "Pipelines|Unable to create pipeline"
+msgstr ""
+
+msgid "Pipelines|Unable to validate CI/CD configuration. See the %{linkStart}GitLab CI/CD troubleshooting guide%{linkEnd} for more details."
+msgstr ""
+
+msgid "Pipelines|Use a sample %{codeStart}.gitlab-ci.yml%{codeEnd} template file to explore how CI/CD works."
+msgstr ""
+
+msgid "Pipelines|Use a template based on your project's language or framework to get started with GitLab CI/CD."
+msgstr ""
+
+msgid "Pipelines|Use template"
+msgstr ""
+
+msgid "Pipelines|Validate"
+msgstr ""
+
+msgid "Pipelines|Validating GitLab CI configuration…"
+msgstr ""
+
+msgid "Pipelines|Visualize"
+msgstr ""
+
+msgid "Pipelines|We'll continuously validate your pipeline configuration. The validation results will appear here."
+msgstr ""
+
+msgid "Pipelines|We'll guide you through a simple pipeline set-up."
+msgstr ""
+
+msgid "Pipelines|We'll walk you through how to deploy to iOS in two easy steps."
+msgstr ""
+
+msgid "Pipelines|You have runners available to run your job now. No need to do anything else."
+msgstr ""
+
+msgid "Pipelines|You should review the code thoroughly before running this pipeline with the parent project's CI/CD resources."
+msgstr ""
+
+msgid "Pipelines|You will see a maximum of 100 jobs in this list. To view all failed jobs, %{linkStart}go to the details page%{linkEnd} of this pipeline."
+msgstr ""
+
+msgid "Pipelines|Your changes have been successfully committed. Now redirecting to the new merge request page."
+msgstr ""
+
+msgid "Pipelines|created"
+msgstr ""
+
+msgid "Pipelines|error"
+msgstr ""
+
+msgid "Pipelines|finished"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
+msgid "Pipelines|latest"
+msgstr ""
+
+msgid "Pipelines|merge request"
+msgstr ""
+
+msgid "Pipelines|merge train"
+msgstr ""
+
+msgid "Pipelines|stuck"
+msgstr ""
+
+msgid "Pipelines|yaml invalid"
+msgstr ""
+
+msgid "Pipeline|Actions"
+msgstr ""
+
+msgid "Pipeline|Branch name"
+msgstr ""
+
+msgid "Pipeline|Branches or tags could not be loaded."
+msgstr ""
+
+msgid "Pipeline|Canceled"
+msgstr ""
+
+msgid "Pipeline|Checking pipeline status"
+msgstr ""
+
+msgid "Pipeline|Checking pipeline status."
+msgstr ""
+
+msgid "Pipeline|Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation%{linkEnd}."
+msgstr ""
+
+msgid "Pipeline|Created"
+msgstr ""
+
+msgid "Pipeline|Created by"
+msgstr ""
+
+msgid "Pipeline|Creating pipeline."
+msgstr ""
+
+msgid "Pipeline|Date"
+msgstr ""
+
+msgid "Pipeline|Failed"
+msgstr ""
+
+msgid "Pipeline|Manual"
+msgstr ""
+
+msgid "Pipeline|Merge request pipeline"
+msgstr ""
+
+msgid "Pipeline|Merge train pipeline"
+msgstr ""
+
+msgid "Pipeline|Merge train pipeline jobs can not be retried"
+msgstr ""
+
+msgid "Pipeline|Merged result pipeline"
+msgstr ""
+
+msgid "Pipeline|No failed jobs in this pipeline 🎉"
+msgstr ""
+
+msgid "Pipeline|Only the first 100 jobs per stage are displayed"
+msgstr ""
+
+msgid "Pipeline|Passed"
+msgstr ""
+
+msgid "Pipeline|Pending"
+msgstr ""
+
+msgid "Pipeline|Pipeline"
+msgstr ""
+
+msgid "Pipeline|Pipeline %{idStart}#%{idEnd} %{statusStart}%{statusEnd} for %{commitStart}%{commitEnd}"
+msgstr ""
+
+msgid "Pipeline|Pipeline cannot be run."
+msgstr ""
+
+msgid "Pipeline|Pipelines"
+msgstr ""
+
+msgid "Pipeline|Raw text search is not currently supported. Please use the available search tokens."
+msgstr ""
+
+msgid "Pipeline|Run again"
+msgstr ""
+
+msgid "Pipeline|Run for branch name or tag"
+msgstr ""
+
+msgid "Pipeline|Run merge request pipeline"
+msgstr ""
+
+msgid "Pipeline|Run pipeline"
+msgstr ""
+
+msgid "Pipeline|Running"
+msgstr ""
+
+msgid "Pipeline|Skipped"
+msgstr ""
+
+msgid "Pipeline|Source"
+msgstr ""
+
+msgid "Pipeline|Source|Security Policy"
+msgstr ""
+
+msgid "Pipeline|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used by default."
+msgstr ""
+
+msgid "Pipeline|Specify variable values to be used in this run. The variables specified in the configuration file as well as %{linkStart}CI/CD settings%{linkEnd} are used by default."
+msgstr ""
+
+msgid "Pipeline|Stages"
+msgstr ""
+
+msgid "Pipeline|Status"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline"
+msgstr ""
+
+msgid "Pipeline|Stop pipeline #%{pipelineId}?"
+msgstr ""
+
+msgid "Pipeline|Tag name"
+msgstr ""
+
+msgid "Pipeline|Test coverage"
+msgstr ""
+
+msgid "Pipeline|This change will decrease the overall test coverage if merged."
+msgstr ""
+
+msgid "Pipeline|This change will increase the overall test coverage if merged."
+msgstr ""
+
+msgid "Pipeline|This change will not change the overall test coverage if merged."
+msgstr ""
+
+msgid "Pipeline|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch."
+msgstr ""
+
+msgid "Pipeline|This pipeline ran on the contents of this merge request's source branch, not the target branch."
+msgstr ""
+
+msgid "Pipeline|To run a merge request pipeline, the jobs in the CI/CD configuration file %{linkStart}must be configured%{linkEnd} to run in merge request pipelines."
+msgstr ""
+
+msgid "Pipeline|To see the remaining jobs, go to the %{boldStart}Jobs%{boldEnd} tab."
+msgstr ""
+
+msgid "Pipeline|Trigger author"
+msgstr ""
+
+msgid "Pipeline|Variables"
+msgstr ""
+
+msgid "Pipeline|View commit"
+msgstr ""
+
+msgid "Pipeline|View pipeline"
+msgstr ""
+
+msgid "Pipeline|We are currently unable to fetch pipeline data"
+msgstr ""
+
+msgid "Pipeline|You’re about to stop pipeline #%{pipelineId}."
+msgstr ""
+
+msgid "Pipeline|for"
+msgstr ""
+
+msgid "Pipeline|merge request"
+msgstr ""
+
+msgid "Pipeline|merge train"
+msgstr ""
+
+msgid "Pipeline|on"
+msgstr ""
+
+msgid "Pipeline|with stage"
+msgstr ""
+
+msgid "Pipeline|with stages"
+msgstr ""
+
+msgid "PivotalTrackerService|Add commit messages as comments to Pivotal Tracker stories."
+msgstr ""
+
+msgid "PivotalTrackerService|Comma-separated list of branches to automatically inspect. Leave blank to include all branches."
+msgstr ""
+
+msgid "PivotalTrackerService|Pivotal Tracker API token. User must have access to the story. All comments are attributed to this user."
+msgstr ""
+
+msgid "Plain diff"
+msgstr ""
+
+msgid "Plain-text response to send to clients that hit a rate limit"
+msgstr ""
+
+msgid "Plan"
+msgstr ""
+
+msgid "Plan:"
+msgstr ""
+
+msgid "Planning hierarchy"
+msgstr ""
+
+msgid "PlantUML"
+msgstr ""
+
+msgid "PlantUML URL"
+msgstr ""
+
+msgid "PlantUML diagram"
+msgstr ""
+
+msgid "Play"
+msgstr ""
+
+msgid "Play all manual"
+msgstr ""
+
+msgid "Please %{link_to_register} or %{link_to_sign_in} to comment"
+msgstr ""
+
+msgid "Please %{registerLinkStart}register%{registerLinkEnd} or %{signInLinkStart}sign in%{signInLinkEnd} to reply."
+msgstr ""
+
+msgid "Please %{registerLinkStart}register%{registerLinkEnd} or %{signInLinkStart}sign in%{signInLinkEnd} to start a new discussion."
+msgstr ""
+
+msgid "Please %{startTagRegister}register%{endRegisterTag} or %{startTagSignIn}sign in%{endSignInTag} to reply"
+msgstr ""
+
+msgid "Please accept the Terms of Service before continuing."
+msgstr ""
+
+msgid "Please add a comment in the text area above"
+msgstr ""
+
+msgid "Please check the configuration file for this chart"
+msgstr ""
+
+msgid "Please check the configuration file to ensure that a collection of charts has been declared."
+msgstr ""
+
+msgid "Please check the configuration file to ensure that it is available and the YAML is valid"
+msgstr ""
+
+msgid "Please check your email %{email} to confirm your account"
+msgstr ""
+
+msgid "Please check your email (%{email}) to verify that you own this address and unlock the power of CI/CD. Didn't receive it? %{resend_link}. Wrong email address? %{update_link}."
+msgstr ""
+
+msgid "Please click the link in the confirmation email before continuing. It was sent to %{html_tag_strong_start}%{email}%{html_tag_strong_end}."
+msgstr ""
+
+msgid "Please complete the incident creation form."
+msgstr ""
+
+msgid "Please complete your profile with email address"
+msgstr ""
+
+msgid "Please confirm your email address"
+msgstr ""
+
+msgid "Please contact an admin to create runners."
+msgstr ""
+
+msgid "Please contact your GitLab administrator if you think this is an error."
+msgstr ""
+
+msgid "Please contact your administrator with any questions."
+msgstr ""
+
+msgid "Please contact your administrator."
+msgstr ""
+
+msgid "Please convert %{linkStart}them to Git%{linkEnd}, and go through the %{linkToImportFlow} again."
+msgstr ""
+
+msgid "Please copy, download, or print your recovery codes before proceeding."
+msgstr ""
+
+msgid "Please create a password for your new account."
+msgstr ""
+
+msgid "Please create a username with only alphanumeric characters."
+msgstr ""
+
+msgid "Please create an index before enabling indexing"
+msgstr ""
+
+msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
+msgstr ""
+
+msgid "Please enter a URL for the custom emoji."
+msgstr ""
+
+msgid "Please enter a name for the comment template."
+msgstr ""
+
+msgid "Please enter a name for the custom emoji."
+msgstr ""
+
+msgid "Please enter a non-negative number"
+msgstr ""
+
+msgid "Please enter a number greater than %{number} (from the project settings)"
+msgstr ""
+
+msgid "Please enter a valid URL format, ex: http://www.example.com/home"
+msgstr ""
+
+msgid "Please enter a valid hex (#RRGGBB or #RGB) color value"
+msgstr ""
+
+msgid "Please enter a valid number"
+msgstr ""
+
+msgid "Please enter a valid time interval"
+msgstr ""
+
+msgid "Please enter a value of 90 days or more"
+msgstr ""
+
+msgid "Please enter the comment template content."
+msgstr ""
+
+msgid "Please enter your current password."
+msgstr ""
+
+msgid "Please fill in a descriptive name for your group."
+msgstr ""
+
+msgid "Please fill in a name for your topic."
+msgstr ""
+
+msgid "Please fill in a title for your topic."
+msgstr ""
+
+msgid "Please fill out this field."
+msgstr ""
+
+msgid "Please follow the %{link_start}Let's Encrypt troubleshooting instructions%{link_end} to re-obtain your Let's Encrypt certificate."
+msgstr ""
+
+msgid "Please follow the Let's Encrypt troubleshooting instructions to re-obtain your Let's Encrypt certificate: %{docs_url}."
+msgstr ""
+
+msgid "Please migrate all existing projects to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
+msgstr ""
+
+msgid "Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access."
+msgstr ""
+
+msgid "Please provide a name"
+msgstr ""
+
+msgid "Please provide a name."
+msgstr ""
+
+msgid "Please provide a valid URL."
+msgstr ""
+
+msgid "Please provide a valid email address."
+msgstr ""
+
+msgid "Please provide attributes to update"
+msgstr ""
+
+msgid "Please reach out if you have any questions and we'll be happy to assist."
+msgstr ""
+
+msgid "Please review the %{linkStart}contribution guidelines%{linkEnd} for this project."
+msgstr ""
+
+msgid "Please review the updated escalation policies for %{project_link}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage."
+msgstr ""
+
+msgid "Please review the updated escalation policies for %{project}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage."
+msgstr ""
+
+msgid "Please select"
+msgstr ""
+
+msgid "Please select a Jira project"
+msgstr ""
+
+msgid "Please select a country / region"
+msgstr ""
+
+msgid "Please select a group"
+msgstr ""
+
+msgid "Please select a valid target branch"
+msgstr ""
+
+msgid "Please select a valid target branch."
+msgstr ""
+
+msgid "Please select and add a member"
+msgstr ""
+
+msgid "Please select at least one filter to see results"
+msgstr ""
+
+msgid "Please select what should be included in each exported requirement."
+msgstr ""
+
+msgid "Please select..."
+msgstr ""
+
+msgid "Please set a new password before proceeding."
+msgstr ""
+
+msgid "Please solve the captcha"
+msgstr ""
+
+msgid "Please try again"
+msgstr ""
+
+msgid "Please try and refresh the page. If the problem persists please contact support."
+msgstr ""
+
+msgid "Please type %{phrase_code} to proceed."
+msgstr ""
+
+msgid "Please use this form to report to the administrator users who create spam issues, comments or behave inappropriately."
+msgstr ""
+
+msgid "Please wait a few moments while we load the file history for this line."
+msgstr ""
+
+msgid "Please wait a moment, this page will automatically refresh when ready."
+msgstr ""
+
+msgid "Please wait for the current action to complete"
+msgstr ""
+
+msgid "Please wait while we connect to your repository. Refresh at will."
+msgstr ""
+
+msgid "Please wait while we import the repository for you. Refresh at will."
+msgstr ""
+
+msgid "Please wait while we prepare for verification."
+msgstr ""
+
+msgid "Pods in use"
+msgstr ""
+
+msgid "Point to any links you like: documentation, built binaries, or other related materials. These can be internal or external links from your GitLab instance. Each URL and link title must be unique."
+msgstr ""
+
+msgid "Policies"
+msgstr ""
+
+msgid "Policy '%{escalation_policy_name}' does not exist."
+msgstr ""
+
+msgid "Policy management project does not have any policies in %{policy_path}"
+msgstr ""
+
+msgid "Policy project doesn't exist"
+msgstr ""
+
+msgid "PolicyRuleMultiSelect|%{firstLabel} +%{numberOfAdditionalLabels} more"
+msgstr ""
+
+msgid "PolicyRuleMultiSelect|All %{itemTypeName}"
+msgstr ""
+
+msgid "PolicyRuleMultiSelect|Clear all"
+msgstr ""
+
+msgid "PolicyRuleMultiSelect|Select %{itemTypeName}"
+msgstr ""
+
+msgid "PolicyRuleMultiSelect|Select all"
+msgstr ""
+
+msgid "Polling interval multiplier"
+msgstr ""
+
+msgid "Popularity"
+msgstr ""
+
+msgid "Port"
+msgstr ""
+
+msgid "Possible to override in each project."
+msgstr ""
+
+msgid "Postman collection"
+msgstr ""
+
+msgid "Postman collection file URL"
+msgstr ""
+
+msgid "Postman collection file path or URL"
+msgstr ""
+
+msgid "Potentially unwanted character detected: Unicode BiDi Control"
+msgstr ""
+
+msgid "Pre-defined push rules"
+msgstr ""
+
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
+msgid "Preferences"
+msgstr ""
+
+msgid "Preferences saved."
+msgstr ""
+
+msgid "Preferences|Automatically add new list items"
+msgstr ""
+
+msgid "Preferences|Behavior"
+msgstr ""
+
+msgid "Preferences|Choose what content you want to see by default on your homepage."
+msgstr ""
+
+msgid "Preferences|Choose what content you want to see on a project’s overview page."
+msgstr ""
+
+msgid "Preferences|Code Suggestions"
+msgstr ""
+
+msgid "Preferences|Color for added lines"
+msgstr ""
+
+msgid "Preferences|Color for removed lines"
+msgstr ""
+
+msgid "Preferences|Color theme"
+msgstr ""
+
+msgid "Preferences|Configure how dates and times display for you."
+msgstr ""
+
+msgid "Preferences|Content will be a maximum of 1280 pixels wide."
+msgstr ""
+
+msgid "Preferences|Content will span %{percentage} of the page width."
+msgstr ""
+
+msgid "Preferences|Customize integrations with third party services."
+msgstr ""
+
+msgid "Preferences|Customize the appearance of the syntax."
+msgstr ""
+
+msgid "Preferences|Customize the behavior of the system layout and default views."
+msgstr ""
+
+msgid "Preferences|Customize the color of GitLab."
+msgstr ""
+
+msgid "Preferences|Customize the colors of removed and added lines in diffs."
+msgstr ""
+
+msgid "Preferences|Diff colors"
+msgstr ""
+
+msgid "Preferences|Enable %{link_start}Code Suggestions%{link_end} for the following groups.%{br_tag}Only groups that have purchased the Code Suggestion add-on and have available seats are listed here.%{br_tag} If you were expecting to see a group and it is missing from the list, please contact the group owner."
+msgstr ""
+
+msgid "Preferences|Enable Gitpod integration"
+msgstr ""
+
+msgid "Preferences|Enable Zoekt code search"
+msgstr ""
+
+msgid "Preferences|Enable follow users"
+msgstr ""
+
+msgid "Preferences|Enable follow users feature"
+msgstr ""
+
+msgid "Preferences|Enable integrated code intelligence on code views"
+msgstr ""
+
+msgid "Preferences|Failed to save preferences."
+msgstr ""
+
+msgid "Preferences|For example: 30 minutes ago."
+msgstr ""
+
+msgid "Preferences|Gitpod"
+msgstr ""
+
+msgid "Preferences|Homepage"
+msgstr ""
+
+msgid "Preferences|Instead of all the files changed, show only one file at a time. To switch between files, use the file browser."
+msgstr ""
+
+msgid "Preferences|Integrations"
+msgstr ""
+
+msgid "Preferences|Layout width"
+msgstr ""
+
+msgid "Preferences|Must be a number between %{min} and %{max}"
+msgstr ""
+
+msgid "Preferences|Preview"
+msgstr ""
+
+msgid "Preferences|Project overview content"
+msgstr ""
+
+msgid "Preferences|Render whitespace characters in the Web IDE"
+msgstr ""
+
+msgid "Preferences|Show one file at a time on merge request's Changes tab"
+msgstr ""
+
+msgid "Preferences|Show shortcut buttons above files on project overview"
+msgstr ""
+
+msgid "Preferences|Show whitespace changes in diffs"
+msgstr ""
+
+msgid "Preferences|Sourcegraph"
+msgstr ""
+
+msgid "Preferences|Surround text selection when typing quotes or brackets"
+msgstr ""
+
+msgid "Preferences|Syntax highlighting theme"
+msgstr ""
+
+msgid "Preferences|Tab width"
+msgstr ""
+
+msgid "Preferences|This feature is experimental and translations are not yet complete."
+msgstr ""
+
+msgid "Preferences|Time preferences"
+msgstr ""
+
+msgid "Preferences|Turns on or off the ability to follow or be followed by other users."
+msgstr ""
+
+msgid "Preferences|Turns on or off the preference to search with Zoekt instead of Elasticsearch."
+msgstr ""
+
+msgid "Preferences|Use relative times"
+msgstr ""
+
+msgid "Preferences|When you type in a description or comment box, pressing %{kbdOpen}Enter%{kbdClose} in a list adds a new item below."
+msgstr ""
+
+msgid "Preferences|When you type in a description or comment box, selected text is surrounded by the corresponding character after typing one of the following characters: %{supported_characters}."
+msgstr ""
+
+msgid "Preparing the report for the scan."
+msgstr ""
+
+msgid "Prev"
+msgstr ""
+
+msgid "Prevent auto-stopping"
+msgstr ""
+
+msgid "Prevent environment from auto-stopping"
+msgstr ""
+
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
+msgid "Prevent project forking outside current group"
+msgstr ""
+
+msgid "Prevent users from changing their profile name"
+msgstr ""
+
+msgid "Prevent users from performing write operations while GitLab maintenance is in progress."
+msgstr ""
+
+msgid "Preview"
+msgstr ""
+
+msgid "Preview Markdown"
+msgstr ""
+
+msgid "Preview changes"
+msgstr ""
+
+msgid "Preview diagram"
+msgstr ""
+
+msgid "Preview payload"
+msgstr ""
+
+msgid "Previous"
+msgstr ""
+
+msgid "Previous Artifacts"
+msgstr ""
+
+msgid "Previous commit"
+msgstr ""
+
+msgid "Previous design"
+msgstr ""
+
+msgid "Previous file in diff"
+msgstr ""
+
+msgid "Previous unresolved discussion"
+msgstr ""
+
+msgid "Primary Action"
+msgstr ""
+
+msgid "Primary navigation sidebar"
+msgstr ""
+
+msgid "Print as PDF"
+msgstr ""
+
+msgid "Print codes"
+msgstr ""
+
+msgid "Prioritize"
+msgstr ""
+
+msgid "Prioritize label"
+msgstr ""
+
+msgid "Prioritized"
+msgstr ""
+
+msgid "Prioritized labels"
+msgstr ""
+
+msgid "Priority"
+msgstr ""
+
+msgid "Private"
+msgstr ""
+
+msgid "Private - Guest users are not allowed to view detailed release information like title and source code."
+msgstr ""
+
+msgid "Private - Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group."
+msgstr ""
+
+msgid "Private - The group and its projects can only be viewed by members."
+msgstr ""
+
+msgid "Private group(s)"
+msgstr ""
+
+msgid "Private profile"
+msgstr ""
+
+msgid "Private profile:"
+msgstr ""
+
+msgid "Private projects can be created in your personal namespace with:"
+msgstr ""
+
+msgid "Private projects compute cost factor"
+msgstr ""
+
+msgid "Problem with %{name} command: %{message}."
+msgstr ""
+
+msgid "Proceed"
+msgstr ""
+
+msgid "Product Analytics"
+msgstr ""
+
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|1. Add the NPM package to your package.json using your preferred package manager"
+msgstr ""
+
+msgid "ProductAnalytics|2. Import the new package into your JS code"
+msgstr ""
+
+msgid "ProductAnalytics|3. Initiate the tracking"
+msgstr ""
+
+msgid "ProductAnalytics|Add another dimension"
+msgstr ""
+
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window"
+msgstr ""
+
+msgid "ProductAnalytics|Add the script to the page and assign the client SDK to window:"
+msgstr ""
+
+msgid "ProductAnalytics|After your application has been instrumented and data is being collected, you can visualize and monitor behaviors in your %{linkStart}analytics dashboards%{linkEnd}."
+msgstr ""
+
+msgid "ProductAnalytics|All Clicks Compared"
+msgstr ""
+
+msgid "ProductAnalytics|All Events Compared"
+msgstr ""
+
+msgid "ProductAnalytics|All Features"
+msgstr ""
+
+msgid "ProductAnalytics|All Pages"
+msgstr ""
+
+msgid "ProductAnalytics|All Sessions Compared"
+msgstr ""
+
+msgid "ProductAnalytics|An error occurred while fetching data. Refresh the page to try again."
+msgstr ""
+
+msgid "ProductAnalytics|Analyze your product with Product Analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Any Click on elements"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
+msgstr ""
+
+msgid "ProductAnalytics|Average Per User"
+msgstr ""
+
+msgid "ProductAnalytics|Average Session Duration"
+msgstr ""
+
+msgid "ProductAnalytics|Average duration in minutes"
+msgstr ""
+
+msgid "ProductAnalytics|Back to dashboards"
+msgstr ""
+
+msgid "ProductAnalytics|Click Events"
+msgstr ""
+
+msgid "ProductAnalytics|Compares all events against each other"
+msgstr ""
+
+msgid "ProductAnalytics|Compares all user sessions against each other"
+msgstr ""
+
+msgid "ProductAnalytics|Compares click events against each other"
+msgstr ""
+
+msgid "ProductAnalytics|Compares feature usage of all features against each other"
+msgstr ""
+
+msgid "ProductAnalytics|Compares page views of all pages against each other"
+msgstr ""
+
+msgid "ProductAnalytics|Create a visualization"
+msgstr ""
+
+msgid "ProductAnalytics|Creating your product analytics instance..."
+msgstr ""
+
+msgid "ProductAnalytics|Cube API key"
+msgstr ""
+
+msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
+msgstr ""
+
+msgid "ProductAnalytics|Dimensions"
+msgstr ""
+
+msgid "ProductAnalytics|Event Type"
+msgstr ""
+
+msgid "ProductAnalytics|Events"
+msgstr ""
+
+msgid "ProductAnalytics|Events grouped by %{granularity}"
+msgstr ""
+
+msgid "ProductAnalytics|Events over time"
+msgstr ""
+
+msgid "ProductAnalytics|Feature Usages"
+msgstr ""
+
+msgid "ProductAnalytics|For more information, see the %{linkStart}docs%{linkEnd}."
+msgstr ""
+
+msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
+msgstr ""
+
+msgid "ProductAnalytics|How many sessions a user has"
+msgstr ""
+
+msgid "ProductAnalytics|How often sessions are repeated"
+msgstr ""
+
+msgid "ProductAnalytics|Instrument your application"
+msgstr ""
+
+msgid "ProductAnalytics|Loading instance"
+msgstr ""
+
+msgid "ProductAnalytics|Measure All tracked Events"
+msgstr ""
+
+msgid "ProductAnalytics|Measure all or specific Page Views"
+msgstr ""
+
+msgid "ProductAnalytics|Measure all sessions"
+msgstr ""
+
+msgid "ProductAnalytics|Measure by unique users"
+msgstr ""
+
+msgid "ProductAnalytics|Measuring"
+msgstr ""
+
+msgid "ProductAnalytics|On what do you want to get insights?"
+msgstr ""
+
+msgid "ProductAnalytics|Page Views"
+msgstr ""
+
+msgid "ProductAnalytics|Product analytics onboarding"
+msgstr ""
+
+msgid "ProductAnalytics|Repeat Visit Percentage"
+msgstr ""
+
+msgid "ProductAnalytics|SDK application ID"
+msgstr ""
+
+msgid "ProductAnalytics|SDK clients"
+msgstr ""
+
+msgid "ProductAnalytics|SDK host"
+msgstr ""
+
+msgid "ProductAnalytics|Sessions"
+msgstr ""
+
+msgid "ProductAnalytics|Set up Product Analytics to track how your product is performing. Combine it with your GitLab data to better understand where you can improve your product and development processes."
+msgstr ""
+
+msgid "ProductAnalytics|Set up product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
+msgstr ""
+
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
+msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
+msgstr ""
+
+msgid "ProductAnalytics|The host to send all tracking events to"
+msgstr ""
+
+msgid "ProductAnalytics|The sender of tracking events"
+msgstr ""
+
+msgid "ProductAnalytics|There is no data for this type of chart currently. Please see the Setup tab if you have not configured the product analytics tool already."
+msgstr ""
+
+msgid "ProductAnalytics|This might take a while, feel free to navigate away from this page and come back later."
+msgstr ""
+
+msgid "ProductAnalytics|To instrument your application, select one of the options below. After an option has been instrumented and data is being collected, this page will progress to the next step."
+msgstr ""
+
+msgid "ProductAnalytics|Track specific features"
+msgstr ""
+
+msgid "ProductAnalytics|Unique Users"
+msgstr ""
+
+msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
+msgid "ProductAnalytics|User Sessions"
+msgstr ""
+
+msgid "ProductAnalytics|User activity"
+msgstr ""
+
+msgid "ProductAnalytics|Users"
+msgstr ""
+
+msgid "ProductAnalytics|Using JS module"
+msgstr ""
+
+msgid "ProductAnalytics|Waiting for events"
+msgstr ""
+
+msgid "ProductAnalytics|What do you want to measure?"
+msgstr ""
+
+msgid "ProductAnalytics|You can instrument your application using a JS module or an HTML script. Follow the instructions below for the option you prefer."
+msgstr ""
+
+msgid "Productivity"
+msgstr ""
+
+msgid "Productivity Analytics"
+msgstr ""
+
+msgid "Productivity analytics"
+msgstr ""
+
+msgid "Productivity analytics can help identify the problems that are delaying your team"
+msgstr ""
+
+msgid "ProductivityAanalytics|Merge requests"
+msgstr ""
+
+msgid "ProductivityAanalytics|is earlier than the allowed minimum date"
+msgstr ""
+
+msgid "ProductivityAnalytics|Ascending"
+msgstr ""
+
+msgid "ProductivityAnalytics|Days"
+msgstr ""
+
+msgid "ProductivityAnalytics|Days to merge"
+msgstr ""
+
+msgid "ProductivityAnalytics|Descending"
+msgstr ""
+
+msgid "ProductivityAnalytics|Hours"
+msgstr ""
+
+msgid "ProductivityAnalytics|List"
+msgstr ""
+
+msgid "ProductivityAnalytics|Merge Requests"
+msgstr ""
+
+msgid "ProductivityAnalytics|Merge date"
+msgstr ""
+
+msgid "ProductivityAnalytics|Merge requests"
+msgstr ""
+
+msgid "ProductivityAnalytics|Time to merge"
+msgstr ""
+
+msgid "ProductivityAnalytics|Trendline"
+msgstr ""
+
+msgid "ProductivityAnalytics|is earlier than the given merged at after date"
+msgstr ""
+
+msgid "Profile"
+msgstr ""
+
+msgid "Profile failed to delete"
+msgstr ""
+
+msgid "Profile image guideline"
+msgstr ""
+
+msgid "Profile page:"
+msgstr ""
+
+msgid "Profile parameter missing"
+msgstr ""
+
+msgid "ProfileSession|on"
+msgstr ""
+
+msgid "Profiles| You are about to permanently delete %{yourAccount}, and all of the issues, merge requests, and groups linked to your account. Once you confirm %{deleteAccount}, it cannot be undone or recovered."
+msgstr ""
+
+msgid "Profiles| You are about to permanently delete %{yourAccount}, and all of the issues, merge requests, and groups linked to your account. Once you confirm %{deleteAccount}, it cannot be undone or recovered. You might have to wait seven days before creating a new account with the same username or email."
+msgstr ""
+
+msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
+msgstr ""
+
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
+msgid "Profiles|@username"
+msgstr ""
+
+msgid "Profiles|Account could not be deleted. GitLab was unable to verify your identity."
+msgstr ""
+
+msgid "Profiles|Account deletion is not allowed by your administrator."
+msgstr ""
+
+msgid "Profiles|Account deletion is not allowed."
+msgstr ""
+
+msgid "Profiles|Account scheduled for removal."
+msgstr ""
+
+msgid "Profiles|Achievements"
+msgstr ""
+
+msgid "Profiles|Active"
+msgstr ""
+
+msgid "Profiles|Add email address"
+msgstr ""
+
+msgid "Profiles|Add key"
+msgstr ""
+
+msgid "Profiles|Add new email"
+msgstr ""
+
+msgid "Profiles|Add new mirror repository"
+msgstr ""
+
+msgid "Profiles|An error occurred while updating your username, please try again."
+msgstr ""
+
+msgid "Profiles|Avatar cropper"
+msgstr ""
+
+msgid "Profiles|Avatar will be removed. Are you sure?"
+msgstr ""
+
+msgid "Profiles|Begins with %{ssh_key_algorithms}."
+msgstr ""
+
+msgid "Profiles|Bio"
+msgstr ""
+
+msgid "Profiles|Change username"
+msgstr ""
+
+msgid "Profiles|Changing your username can have unintended side effects."
+msgstr ""
+
+msgid "Profiles|Choose file..."
+msgstr ""
+
+msgid "Profiles|Choose to show contributions of private projects on your public profile without any project, repository or organization information."
+msgstr ""
+
+msgid "Profiles|City, country"
+msgstr ""
+
+msgid "Profiles|Commit email"
+msgstr ""
+
+msgid "Profiles|Connect %{provider}"
+msgstr ""
+
+msgid "Profiles|Connect a service for sign-in."
+msgstr ""
+
+msgid "Profiles|Connected Accounts"
+msgstr ""
+
+msgid "Profiles|Control emails linked to your account"
+msgstr ""
+
+msgid "Profiles|Copy SSH key"
+msgstr ""
+
+msgid "Profiles|Created"
+msgstr ""
+
+msgid "Profiles|Current path: %{path}"
+msgstr ""
+
+msgid "Profiles|Current status"
+msgstr ""
+
+msgid "Profiles|Default notification email"
+msgstr ""
+
+msgid "Profiles|Delete account"
+msgstr ""
+
+msgid "Profiles|Deleting an account has the following effects:"
+msgstr ""
+
+msgid "Profiles|Disconnect"
+msgstr ""
+
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
+msgid "Profiles|Discord ID is too long (maximum is %{max_length} characters)."
+msgstr ""
+
+msgid "Profiles|Discord ID is too short (minimum is %{min_length} characters)."
+msgstr ""
+
+msgid "Profiles|Display achievements on your profile"
+msgstr ""
+
+msgid "Profiles|Do not show on profile"
+msgstr ""
+
+msgid "Profiles|Don't display activity-related personal information on your profile."
+msgstr ""
+
+msgid "Profiles|Edit Profile"
+msgstr ""
+
+msgid "Profiles|Email address"
+msgstr ""
+
+msgid "Profiles|Email addresses"
+msgstr ""
+
+msgid "Profiles|Ensure you have two-factor authentication recovery codes stored in a safe place."
+msgstr ""
+
+msgid "Profiles|Enter how your name is pronounced to help people address you correctly."
+msgstr ""
+
+msgid "Profiles|Enter your name, so people you know can recognize you."
+msgstr ""
+
+msgid "Profiles|Enter your password to confirm the email change"
+msgstr ""
+
+msgid "Profiles|Enter your pronouns to let people know how to refer to you."
+msgstr ""
+
+msgid "Profiles|Example: MacBook key"
+msgstr ""
+
+msgid "Profiles|Expiration date"
+msgstr ""
+
+msgid "Profiles|Expired"
+msgstr ""
+
+msgid "Profiles|Expires"
+msgstr ""
+
+msgid "Profiles|Feed token was successfully reset"
+msgstr ""
+
+msgid "Profiles|Full name"
+msgstr ""
+
+msgid "Profiles|GitLab is unable to verify your identity automatically. For security purposes, you must set a password by %{openingTag}resetting your password%{closingTag} to delete your account."
+msgstr ""
+
+msgid "Profiles|If after setting a password, the option to delete your account is still not available, please %{link_start}submit a request%{link_end} to begin the account deletion process."
+msgstr ""
+
+msgid "Profiles|Include private contributions on your profile"
+msgstr ""
+
+msgid "Profiles|Incoming email token was successfully reset"
+msgstr ""
+
+msgid "Profiles|Increase your account's security by enabling two-factor authentication (2FA)."
+msgstr ""
+
+msgid "Profiles|Invalid password"
+msgstr ""
+
+msgid "Profiles|Invalid username"
+msgstr ""
+
+msgid "Profiles|Job title"
+msgstr ""
+
+msgid "Profiles|Key"
+msgstr ""
+
+msgid "Profiles|Key becomes invalid on this date. Maximum lifetime for SSH keys is %{max_ssh_key_lifetime} days"
+msgstr ""
+
+msgid "Profiles|Key titles are publicly visible."
+msgstr ""
+
+msgid "Profiles|Last used"
+msgstr ""
+
+msgid "Profiles|Linked emails"
+msgstr ""
+
+msgid "Profiles|Location"
+msgstr ""
+
+msgid "Profiles|Made a private contribution"
+msgstr ""
+
+msgid "Profiles|Main settings"
+msgstr ""
+
+msgid "Profiles|Manage two-factor authentication"
+msgstr ""
+
+msgid "Profiles|No file chosen."
+msgstr ""
+
+msgid "Profiles|Optional but recommended. If set, key becomes invalid on the specified date."
+msgstr ""
+
+msgid "Profiles|Organization"
+msgstr ""
+
+msgid "Profiles|Path"
+msgstr ""
+
+msgid "Profiles|Position and size your new avatar"
+msgstr ""
+
+msgid "Profiles|Primary email"
+msgstr ""
+
+msgid "Profiles|Private contributions"
+msgstr ""
+
+msgid "Profiles|Profile was successfully updated"
+msgstr ""
+
+msgid "Profiles|Pronouns"
+msgstr ""
+
+msgid "Profiles|Pronunciation"
+msgstr ""
+
+msgid "Profiles|Public avatar"
+msgstr ""
+
+msgid "Profiles|Public email"
+msgstr ""
+
+msgid "Profiles|Publicly visible private SSH keys can compromise your system."
+msgstr ""
+
+msgid "Profiles|Remove avatar"
+msgstr ""
+
+msgid "Profiles|Resend confirmation email"
+msgstr ""
+
+msgid "Profiles|SSH Key: %{title}"
+msgstr ""
+
+msgid "Profiles|Select a service to sign in with."
+msgstr ""
+
+msgid "Profiles|Send confirmation email"
+msgstr ""
+
+msgid "Profiles|Service sign-in"
+msgstr ""
+
+msgid "Profiles|Set new profile picture"
+msgstr ""
+
+msgid "Profiles|Set your local time zone."
+msgstr ""
+
+msgid "Profiles|Some options are unavailable for LDAP accounts"
+msgstr ""
+
+msgid "Profiles|Static object token was successfully reset"
+msgstr ""
+
+msgid "Profiles|Tell us about yourself in fewer than 250 characters."
+msgstr ""
+
+msgid "Profiles|The ability to update your name has been disabled by your administrator."
+msgstr ""
+
+msgid "Profiles|The maximum file size allowed is 200KB."
+msgstr ""
+
+msgid "Profiles|This email will be displayed on your public profile."
+msgstr ""
+
+msgid "Profiles|This email will be used for web based operations, such as edits and merges. %{commit_email_link_start}Learn more.%{commit_email_link_end}"
+msgstr ""
+
+msgid "Profiles|This emoji and message will appear on your profile and throughout the interface."
+msgstr ""
+
+msgid "Profiles|This information will appear on your profile."
+msgstr ""
+
+msgid "Profiles|Time settings"
+msgstr ""
+
+msgid "Profiles|Title"
+msgstr ""
+
+msgid "Profiles|Two-factor authentication"
+msgstr ""
+
+msgid "Profiles|Type your %{confirmationValue} to confirm:"
+msgstr ""
+
+msgid "Profiles|Update profile settings"
+msgstr ""
+
+msgid "Profiles|Update username"
+msgstr ""
+
+msgid "Profiles|Upload new avatar"
+msgstr ""
+
+msgid "Profiles|Usage type"
+msgstr ""
+
+msgid "Profiles|Use a private email - %{email}"
+msgstr ""
+
+msgid "Profiles|User ID"
+msgstr ""
+
+msgid "Profiles|Username change failed - %{message}"
+msgstr ""
+
+msgid "Profiles|Username successfully changed"
+msgstr ""
+
+msgid "Profiles|Using emoji in names seems fun, but please try to set a status message instead"
+msgstr ""
+
+msgid "Profiles|Website url"
+msgstr ""
+
+msgid "Profiles|Who you represent or work for."
+msgstr ""
+
+msgid "Profiles|You can change your avatar here"
+msgstr ""
+
+msgid "Profiles|You can change your avatar here or remove the current avatar to revert to %{gravatar_link}"
+msgstr ""
+
+msgid "Profiles|You can upload your avatar here"
+msgstr ""
+
+msgid "Profiles|You can upload your avatar here or change it at %{gravatar_link}"
+msgstr ""
+
+msgid "Profiles|You don't have access to delete this user."
+msgstr ""
+
+msgid "Profiles|You must accept the Terms of Service in order to perform this action."
+msgstr ""
+
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
+msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
+msgstr ""
+
+msgid "Profiles|Your Discord user ID. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
+msgstr ""
+
+msgid "Profiles|Your LinkedIn profile name from linkedin.com/in/profilename"
+msgstr ""
+
+msgid "Profiles|Your account is currently an owner in these groups:"
+msgstr ""
+
+msgid "Profiles|Your email address was automatically set based on your %{provider_label} account"
+msgstr ""
+
+msgid "Profiles|Your location was automatically set based on your %{provider_label} account"
+msgstr ""
+
+msgid "Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you"
+msgstr ""
+
+msgid "Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you."
+msgstr ""
+
+msgid "Profiles|https://website.com"
+msgstr ""
+
+msgid "Profiles|username"
+msgstr ""
+
+msgid "Profiles|your account"
+msgstr ""
+
+msgid "Profile|%{job_title} at %{organization}"
+msgstr ""
+
+msgid "Profiling - Performance bar"
+msgstr ""
+
+msgid "Programming languages used in this repository"
+msgstr ""
+
+msgid "Progress"
+msgstr ""
+
+msgid "Progress tracking"
+msgstr ""
+
+msgid "Progressive Web App (PWA)"
+msgstr ""
+
+msgid "Progressive Web App (PWA) icon was successfully removed."
+msgstr ""
+
+msgid "Project"
+msgstr ""
+
+msgid "Project \"%{name}\" is no longer available. Select another project to continue."
+msgstr ""
+
+msgid "Project %{code_open}%{source_project}%{code_close} has more restricted access settings than %{code_open}%{target_project}%{code_close}. To avoid exposing private changes, make sure you're submitting changes to the correct project."
+msgstr ""
+
+msgid "Project %{project_repo} could not be found"
+msgstr ""
+
+msgid "Project & Group can not be assigned at the same time"
+msgstr ""
+
+msgid "Project '%{project_name}' is being imported."
+msgstr ""
+
+msgid "Project '%{project_name}' is in the process of being deleted."
+msgstr ""
+
+msgid "Project '%{project_name}' is restored."
+msgstr ""
+
+msgid "Project '%{project_name}' queued for deletion."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully created."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully updated."
+msgstr ""
+
+msgid "Project '%{project_name}' will be deleted on %{date}"
+msgstr ""
+
+msgid "Project Access Tokens"
+msgstr ""
+
+msgid "Project Badges"
+msgstr ""
+
+msgid "Project Files"
+msgstr ""
+
+msgid "Project ID"
+msgstr ""
+
+msgid "Project Templates"
+msgstr ""
+
+msgid "Project URL"
+msgstr ""
+
+msgid "Project access token creation is disabled in this group."
+msgstr ""
+
+msgid "Project already deleted"
+msgstr ""
+
+msgid "Project and wiki repositories"
+msgstr ""
+
+msgid "Project audit events"
+msgstr ""
+
+msgid "Project avatar"
+msgstr ""
+
+msgid "Project cannot be shared with the group it is in or one of its ancestors."
+msgstr ""
+
+msgid "Project configuration, excluding integrations"
+msgstr ""
+
+msgid "Project description (optional)"
+msgstr ""
+
+msgid "Project does not exist or you don't have permission to perform this action"
+msgstr ""
+
+msgid "Project does not have a policy configuration"
+msgstr ""
+
+msgid "Project export could not be deleted."
+msgstr ""
+
+msgid "Project export download requests"
+msgstr ""
+
+msgid "Project export has been deleted."
+msgstr ""
+
+msgid "Project export link has expired. Please generate a new export from your project settings."
+msgstr ""
+
+msgid "Project export requests"
+msgstr ""
+
+msgid "Project export started. A download link will be sent by email and made available on this page."
+msgstr ""
+
+msgid "Project has too many %{label_for_message} to search"
+msgstr ""
+
+msgid "Project import requests"
+msgstr ""
+
+msgid "Project info:"
+msgstr ""
+
+msgid "Project information"
+msgstr ""
+
+msgid "Project members"
+msgstr ""
+
+msgid "Project milestone"
+msgstr ""
+
+msgid "Project must have default branch"
+msgstr ""
+
+msgid "Project name"
+msgstr ""
+
+msgid "Project navigation"
+msgstr ""
+
+msgid "Project or Group"
+msgstr ""
+
+msgid "Project order will not be saved as local storage is not available."
+msgstr ""
+
+msgid "Project path"
+msgstr ""
+
+msgid "Project security status"
+msgstr ""
+
+msgid "Project security status help page"
+msgstr ""
+
+msgid "Project settings were successfully updated."
+msgstr ""
+
+msgid "Project slug"
+msgstr ""
+
+msgid "Project that can be accessed"
+msgstr ""
+
+msgid "Project uploads"
+msgstr ""
+
+msgid "Project visibility level is less restrictive than the group settings."
+msgstr ""
+
+msgid "Project visibility level will be changed to match namespace rules when transferring to a group."
+msgstr ""
+
+msgid "Project was created and assigned as security policy project, but failed adding users to the project."
+msgstr ""
+
+msgid "Project was not found or you do not have permission to add this project to Security Dashboards."
+msgstr ""
+
+msgid "Project with access"
+msgstr ""
+
+msgid "Project: %{name}"
+msgstr ""
+
+msgid "Project:Branches: %{source_project_path}:%{source_branch} to %{target_project_path}:%{target_branch}"
+msgstr ""
+
+msgid "Project:Branches: %{source_project_path}:%{source_branch} → %{target_project_path}:%{target_branch}"
+msgstr ""
+
+msgid "ProjectActivityRSS|Subscribe"
+msgstr ""
+
+msgid "ProjectCreationLevel|Allowed to create projects"
+msgstr ""
+
+msgid "ProjectCreationLevel|Default project creation protection"
+msgstr ""
+
+msgid "ProjectCreationLevel|Developers + Maintainers"
+msgstr ""
+
+msgid "ProjectCreationLevel|Maintainers"
+msgstr ""
+
+msgid "ProjectCreationLevel|No one"
+msgstr ""
+
+msgid "ProjectCreationLevel|Roles allowed to create projects"
+msgstr ""
+
+msgid "ProjectFileTree|Name"
+msgstr ""
+
+msgid "ProjectFileTree|Show more"
+msgstr ""
+
+msgid "ProjectLastActivity|Never"
+msgstr ""
+
+msgid "ProjectList|Starred"
+msgstr ""
+
+msgid "ProjectList|Yours"
+msgstr ""
+
+msgid "ProjectOverview|Create new fork"
+msgstr ""
+
+msgid "ProjectOverview|Forks"
+msgstr ""
+
+msgid "ProjectOverview|Go to your fork"
+msgstr ""
+
+msgid "ProjectOverview|Star"
+msgstr ""
+
+msgid "ProjectOverview|Starrer"
+msgstr ""
+
+msgid "ProjectOverview|Starrers"
+msgstr ""
+
+msgid "ProjectOverview|Unstar"
+msgstr ""
+
+msgid "ProjectOverview|You don't have permission to fork this project"
+msgstr ""
+
+msgid "ProjectOverview|You have reached your project limit"
+msgstr ""
+
+msgid "ProjectOverview|You must sign in to star a project"
+msgstr ""
+
+msgid "ProjectPage|Copy project ID"
+msgstr ""
+
+msgid "ProjectPage|Project ID: %{project_id}"
+msgstr ""
+
+msgid "ProjectQualitySummary|An error occurred while trying to fetch project quality statistics"
+msgstr ""
+
+msgid "ProjectQualitySummary|Analysis of your source code's quality and complexity."
+msgstr ""
+
+msgid "ProjectQualitySummary|Blocker"
+msgstr ""
+
+msgid "ProjectQualitySummary|Code quality"
+msgstr ""
+
+msgid "ProjectQualitySummary|Coverage"
+msgstr ""
+
+msgid "ProjectQualitySummary|Critical"
+msgstr ""
+
+msgid "ProjectQualitySummary|Failure"
+msgstr ""
+
+msgid "ProjectQualitySummary|Get insight into the overall percentage of tests in your project that succeed, fail and are skipped."
+msgstr ""
+
+msgid "ProjectQualitySummary|Help us improve this page"
+msgstr ""
+
+msgid "ProjectQualitySummary|Latest pipeline results"
+msgstr ""
+
+msgid "ProjectQualitySummary|Learn more about Code Quality"
+msgstr ""
+
+msgid "ProjectQualitySummary|Learn more about test coverage"
+msgstr ""
+
+msgid "ProjectQualitySummary|Learn more about test reports"
+msgstr ""
+
+msgid "ProjectQualitySummary|Measure of how much of your code is covered by tests."
+msgstr ""
+
+msgid "ProjectQualitySummary|Provide feedback"
+msgstr ""
+
+msgid "ProjectQualitySummary|See full report"
+msgstr ""
+
+msgid "ProjectQualitySummary|See project Code Coverage Statistics"
+msgstr ""
+
+msgid "ProjectQualitySummary|Set up test runs"
+msgstr ""
+
+msgid "ProjectQualitySummary|Set up test runs (opens in a new tab)"
+msgstr ""
+
+msgid "ProjectQualitySummary|Skipped"
+msgstr ""
+
+msgid "ProjectQualitySummary|Success"
+msgstr ""
+
+msgid "ProjectQualitySummary|Test coverage"
+msgstr ""
+
+msgid "ProjectQualitySummary|Test runs"
+msgstr ""
+
+msgid "ProjectQualitySummary|The percentage of tests that succeed, fail, or are skipped."
+msgstr ""
+
+msgid "ProjectQualitySummary|This page helps you understand the code testing trends for your project. Let us know how we can improve it!"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations"
+msgstr ""
+
+msgid "ProjectQualitySummary|Violations found"
+msgstr ""
+
+msgid "ProjectSelect|No matching results"
+msgstr ""
+
+msgid "ProjectSelect|Search for project"
+msgstr ""
+
+msgid "ProjectSelect|Search projects"
+msgstr ""
+
+msgid "ProjectSelect|Select a project"
+msgstr ""
+
+msgid "ProjectSelect|There was an error fetching the projects. Please try again."
+msgstr ""
+
+msgid "ProjectService|Drone server URL"
+msgstr ""
+
+msgid "ProjectService|Enter new API key"
+msgstr ""
+
+msgid "ProjectService|Enter new password"
+msgstr ""
+
+msgid "ProjectService|Enter new password."
+msgstr ""
+
+msgid "ProjectService|Enter new token"
+msgstr ""
+
+msgid "ProjectService|Jenkins server URL"
+msgstr ""
+
+msgid "ProjectService|Leave blank to use your current API key"
+msgstr ""
+
+msgid "ProjectService|Leave blank to use your current API key."
+msgstr ""
+
+msgid "ProjectService|Leave blank to use your current password"
+msgstr ""
+
+msgid "ProjectService|Leave blank to use your current password."
+msgstr ""
+
+msgid "ProjectService|Leave blank to use your current token."
+msgstr ""
+
+msgid "ProjectService|Mock service URL"
+msgstr ""
+
+msgid "ProjectService|Must have permission to trigger a manual build in TeamCity."
+msgstr ""
+
+msgid "ProjectService|Perform common operations on GitLab project: %{project_name}"
+msgstr ""
+
+msgid "ProjectService|Run CI/CD pipelines with Buildkite."
+msgstr ""
+
+msgid "ProjectService|Run CI/CD pipelines with Drone."
+msgstr ""
+
+msgid "ProjectService|Run CI/CD pipelines with JetBrains TeamCity."
+msgstr ""
+
+msgid "ProjectService|TeamCity server URL"
+msgstr ""
+
+msgid "ProjectService|The build configuration ID of the TeamCity project."
+msgstr ""
+
+msgid "ProjectService|The token you get after you create a Buildkite pipeline with a GitLab repository."
+msgstr ""
+
+msgid "ProjectService|To configure this integration, you should:"
+msgstr ""
+
+msgid "ProjectService|Token for the Drone project."
+msgstr ""
+
+msgid "ProjectService|Trigger event for new comments on confidential issues."
+msgstr ""
+
+msgid "ProjectService|Trigger event for new comments."
+msgstr ""
+
+msgid "ProjectService|Trigger event for new tags pushed to the repository."
+msgstr ""
+
+msgid "ProjectService|Trigger event for pushes to the repository."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a commit is created or updated."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a confidential issue is created, updated, or closed."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a deployment starts or finishes."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a group is mentioned in a confidential context."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a group is mentioned in a public context."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a merge request is created, updated, or merged."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a new, unique alert is recorded."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a new, unique vulnerability is recorded. (Note: This feature requires an Ultimate plan.)"
+msgstr ""
+
+msgid "ProjectService|Trigger event when a pipeline status changes."
+msgstr ""
+
+msgid "ProjectService|Trigger event when a wiki page is created or updated."
+msgstr ""
+
+msgid "ProjectService|Trigger event when an incident is created."
+msgstr ""
+
+msgid "ProjectService|Trigger event when an issue is created, updated, or closed."
+msgstr ""
+
+msgid "ProjectSettings|%{link_start}What are description templates?%{link_end}"
+msgstr ""
+
+msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
+msgstr ""
+
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
+msgid "ProjectSettings|Additional options"
+msgstr ""
+
+msgid "ProjectSettings|Additional settings that influence how and when merges are done."
+msgstr ""
+
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
+msgid "ProjectSettings|All your dashboard data sources."
+msgstr ""
+
+msgid "ProjectSettings|Allow"
+msgstr ""
+
+msgid "ProjectSettings|Allow anyone to pull from Package Registry"
+msgstr ""
+
+msgid "ProjectSettings|Always show thumbs-up and thumbs-down emoji buttons on issues, merge requests, and snippets."
+msgstr ""
+
+msgid "ProjectSettings|Analytics"
+msgstr ""
+
+msgid "ProjectSettings|Analytics Dashboards"
+msgstr ""
+
+msgid "ProjectSettings|Anyone can pull packages with a package manager API."
+msgstr ""
+
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
+msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
+msgstr ""
+
+msgid "ProjectSettings|Badges"
+msgstr ""
+
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
+msgid "ProjectSettings|Build, test, and deploy your changes."
+msgstr ""
+
+msgid "ProjectSettings|Checkbox is visible and selected by default."
+msgstr ""
+
+msgid "ProjectSettings|Checkbox is visible and unselected by default."
+msgstr ""
+
+msgid "ProjectSettings|Choose the method, options, checks, and squash options for merge requests. You can also set up merge request templates for different actions."
+msgstr ""
+
+msgid "ProjectSettings|Choose your merge method, merge options, merge checks, and merge suggestions."
+msgstr ""
+
+msgid "ProjectSettings|Choose your merge method, options, checks, and squash options."
+msgstr ""
+
+msgid "ProjectSettings|Collector host"
+msgstr ""
+
+msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
+msgstr ""
+
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
+msgid "ProjectSettings|Connect your instance"
+msgstr ""
+
+msgid "ProjectSettings|Contact an admin to change this setting."
+msgstr ""
+
+msgid "ProjectSettings|Container registry"
+msgstr ""
+
+msgid "ProjectSettings|Cube API URL"
+msgstr ""
+
+msgid "ProjectSettings|Custom dashboard projects"
+msgstr ""
+
+msgid "ProjectSettings|Customize this project's badges."
+msgstr ""
+
+msgid "ProjectSettings|Data sources"
+msgstr ""
+
+msgid "ProjectSettings|Determine what happens to the commit history when you merge a merge request."
+msgstr ""
+
+msgid "ProjectSettings|Do not allow"
+msgstr ""
+
+msgid "ProjectSettings|Enable \"Delete source branch\" option by default"
+msgstr ""
+
+msgid "ProjectSettings|Enable email notifications"
+msgstr ""
+
+msgid "ProjectSettings|Enable merge trains"
+msgstr ""
+
+msgid "ProjectSettings|Enable merged results pipelines"
+msgstr ""
+
+msgid "ProjectSettings|Enable sending email notifications for this project"
+msgstr ""
+
+msgid "ProjectSettings|Enable suggested reviewers"
+msgstr ""
+
+msgid "ProjectSettings|Encourage"
+msgstr ""
+
+msgid "ProjectSettings|Environments"
+msgstr ""
+
+msgid "ProjectSettings|Every merge creates a merge commit."
+msgstr ""
+
+msgid "ProjectSettings|Every project can have its own space to store its Docker images"
+msgstr ""
+
+msgid "ProjectSettings|Every project can make deployments to environments either via CI/CD or API calls. Non-project members have read-only access."
+msgstr ""
+
+msgid "ProjectSettings|Everyone"
+msgstr ""
+
+msgid "ProjectSettings|Existing merge requests and protected branches are not affected."
+msgstr ""
+
+msgid "ProjectSettings|Failed to protect the tag"
+msgstr ""
+
+msgid "ProjectSettings|Failed to update tag!"
+msgstr ""
+
+msgid "ProjectSettings|Fast-forward merge"
+msgstr ""
+
+msgid "ProjectSettings|Fast-forward merges only."
+msgstr ""
+
+msgid "ProjectSettings|Feature flags"
+msgstr ""
+
+msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
+msgid "ProjectSettings|Forks"
+msgstr ""
+
+msgid "ProjectSettings|Git Large File Storage (LFS)"
+msgstr ""
+
+msgid "ProjectSettings|Global"
+msgstr ""
+
+msgid "ProjectSettings|Highlight the usage of hidden unicode characters. These have innocent uses for right-to-left languages, but can also be used in potential exploits."
+msgstr ""
+
+msgid "ProjectSettings|Housekeeping, export, archive, change path, transfer, and delete."
+msgstr ""
+
+msgid "ProjectSettings|How do they differ?"
+msgstr ""
+
+msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
+msgstr ""
+
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
+msgid "ProjectSettings|Instrument your application"
+msgstr ""
+
+msgid "ProjectSettings|Instrumentation details"
+msgstr ""
+
+msgid "ProjectSettings|Internal"
+msgstr ""
+
+msgid "ProjectSettings|Issues"
+msgstr ""
+
+msgid "ProjectSettings|LFS objects from this repository are available to forks. %{linkStart}How do I remove them?%{linkEnd}"
+msgstr ""
+
+msgid "ProjectSettings|Leave empty to use default template."
+msgstr ""
+
+msgid "ProjectSettings|Make sure this pattern does not contradict the %{link_start}Push rules &gt; Branch name%{link_end} setting."
+msgstr ""
+
+msgid "ProjectSettings|Manage who can see the project in the public access directory."
+msgstr ""
+
+msgid "ProjectSettings|Manages large files such as audio, video, and graphics files."
+msgstr ""
+
+msgid "ProjectSettings|Maximum %{maxLength} characters."
+msgstr ""
+
+msgid "ProjectSettings|Merge checks"
+msgstr ""
+
+msgid "ProjectSettings|Merge commit"
+msgstr ""
+
+msgid "ProjectSettings|Merge commit message template"
+msgstr ""
+
+msgid "ProjectSettings|Merge commit with semi-linear history"
+msgstr ""
+
+msgid "ProjectSettings|Merge method"
+msgstr ""
+
+msgid "ProjectSettings|Merge options"
+msgstr ""
+
+msgid "ProjectSettings|Merge requests"
+msgstr ""
+
+msgid "ProjectSettings|Merge requests approved for merge are queued, and pipelines validate the combined results of the source and target branches before merge. %{link_start}What are merge trains?%{link_end}"
+msgstr ""
+
+msgid "ProjectSettings|Merge suggestions"
+msgstr ""
+
+msgid "ProjectSettings|Merging is only allowed when the source branch is up-to-date with its target."
+msgstr ""
+
+msgid "ProjectSettings|Model experiments"
+msgstr ""
+
+msgid "ProjectSettings|Monitor"
+msgstr ""
+
+msgid "ProjectSettings|Monitor the health of your project and respond to incidents."
+msgstr ""
+
+msgid "ProjectSettings|No merge commits are created."
+msgstr ""
+
+msgid "ProjectSettings|Note: The container registry is always visible when a project is public and the container registry is set to '%{access_level_description}'"
+msgstr ""
+
+msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
+msgstr ""
+
+msgid "ProjectSettings|Only signed commits can be pushed to this repository."
+msgstr ""
+
+msgid "ProjectSettings|Override instance analytics configuration for this project"
+msgstr ""
+
+msgid "ProjectSettings|Package registry"
+msgstr ""
+
+msgid "ProjectSettings|Pages"
+msgstr ""
+
+msgid "ProjectSettings|Pages for project documentation."
+msgstr ""
+
+msgid "ProjectSettings|Prevents direct linking to potentially sensitive media files"
+msgstr ""
+
+msgid "ProjectSettings|Private"
+msgstr ""
+
+msgid "ProjectSettings|Product analytics"
+msgstr ""
+
+msgid "ProjectSettings|Project visibility"
+msgstr ""
+
+msgid "ProjectSettings|Public"
+msgstr ""
+
+msgid "ProjectSettings|Publish, store, and view packages in a project."
+msgstr ""
+
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
+msgid "ProjectSettings|Releases"
+msgstr ""
+
+msgid "ProjectSettings|Repository"
+msgstr ""
+
+msgid "ProjectSettings|Require"
+msgstr ""
+
+msgid "ProjectSettings|Require an associated issue from Jira"
+msgstr ""
+
+msgid "ProjectSettings|Require authentication to view media files"
+msgstr ""
+
+msgid "ProjectSettings|Requirements"
+msgstr ""
+
+msgid "ProjectSettings|Requirements management system."
+msgstr ""
+
+msgid "ProjectSettings|Roll out new features without redeploying with feature flags."
+msgstr ""
+
+msgid "ProjectSettings|Search for topic"
+msgstr ""
+
+msgid "ProjectSettings|Security and Compliance"
+msgstr ""
+
+msgid "ProjectSettings|Security and compliance for this project."
+msgstr ""
+
+msgid "ProjectSettings|Select a project"
+msgstr ""
+
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
+msgid "ProjectSettings|Select the project containing Analytics Dashboards configuration files."
+msgstr ""
+
+msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
+msgstr ""
+
+msgid "ProjectSettings|Share code with others outside the project."
+msgstr ""
+
+msgid "ProjectSettings|Show default emoji reactions"
+msgstr ""
+
+msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
+msgstr ""
+
+msgid "ProjectSettings|Snippets"
+msgstr ""
+
+msgid "ProjectSettings|Squash commit message template"
+msgstr ""
+
+msgid "ProjectSettings|Squash commits when merging"
+msgstr ""
+
+msgid "ProjectSettings|Squashing is always performed. Checkbox is visible and selected, and users cannot change it."
+msgstr ""
+
+msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
+msgstr ""
+
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
+msgid "ProjectSettings|Store custom configuration files."
+msgstr ""
+
+msgid "ProjectSettings|Submit changes to be merged upstream."
+msgstr ""
+
+msgid "ProjectSettings|Target project"
+msgstr ""
+
+msgid "ProjectSettings|The URL of your Cube instance."
+msgstr ""
+
+msgid "ProjectSettings|The commit message used when applying merge request suggestions."
+msgstr ""
+
+msgid "ProjectSettings|The commit message used when merging, if the merge method creates a merge commit."
+msgstr ""
+
+msgid "ProjectSettings|The commit message used when squashing commits."
+msgstr ""
+
+msgid "ProjectSettings|The default target project for merge requests created in this fork project."
+msgstr ""
+
+msgid "ProjectSettings|The default template will be applied on save."
+msgstr ""
+
+msgid "ProjectSettings|The host of your data collector instance."
+msgstr ""
+
+msgid "ProjectSettings|These checks must pass before merge requests can be merged."
+msgstr ""
+
+msgid "ProjectSettings|This project"
+msgstr ""
+
+msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin."
+msgstr ""
+
+msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
+msgstr ""
+
+msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
+msgstr ""
+
+msgid "ProjectSettings|Topics"
+msgstr ""
+
+msgid "ProjectSettings|Topics are publicly visible even on private projects. Do not include sensitive information in topic names. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "ProjectSettings|Track machine learning model experiments and artifacts."
+msgstr ""
+
+msgid "ProjectSettings|Transfer project"
+msgstr ""
+
+msgid "ProjectSettings|Upstream project"
+msgstr ""
+
+msgid "ProjectSettings|Used for every new merge request."
+msgstr ""
+
+msgid "ProjectSettings|Users can copy the repository to a new project."
+msgstr ""
+
+msgid "ProjectSettings|Users can only push commits to this repository if the commit author name is consistent with their GitLab account name."
+msgstr ""
+
+msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
+msgstr ""
+
+msgid "ProjectSettings|Users can request access"
+msgstr ""
+
+msgid "ProjectSettings|View and edit files in this project."
+msgstr ""
+
+msgid "ProjectSettings|View and edit files in this project. When set to **Everyone With Access** non-project members have only read access."
+msgstr ""
+
+msgid "ProjectSettings|View project analytics."
+msgstr ""
+
+msgid "ProjectSettings|Visibility options for this fork are limited by the current visibility of the source project."
+msgstr ""
+
+msgid "ProjectSettings|Warn about Potentially Unwanted Characters"
+msgstr ""
+
+msgid "ProjectSettings|What are badges?"
+msgstr ""
+
+msgid "ProjectSettings|What are merge trains?"
+msgstr ""
+
+msgid "ProjectSettings|What is squashing?"
+msgstr ""
+
+msgid "ProjectSettings|When merge request pipelines are enabled in the CI/CD configuration file, pipelines validate the combined results of the source and target branches. %{link_start}How to configure merge request pipelines?%{link_end}"
+msgstr ""
+
+msgid "ProjectSettings|When semi-linear merge is not possible, the user is given the option to rebase."
+msgstr ""
+
+msgid "ProjectSettings|When there is a merge conflict, the user is given the option to rebase."
+msgstr ""
+
+msgid "ProjectSettings|Wiki"
+msgstr ""
+
+msgid "ProjectSettings|With GitLab Pages you can host your static websites on GitLab. GitLab Pages uses a caching mechanism for efficiency. Your changes may not take effect until that cache is invalidated, which usually takes less than a minute."
+msgstr ""
+
+msgid "ProjectSettings|You need to %{linkStart}set up product analytics%{linkEnd} before your application can be instrumented."
+msgstr ""
+
+msgid "ProjectSettings|Your project is set up. %{linkStart}View instrumentation instructions%{linkEnd}."
+msgstr ""
+
+msgid "ProjectSetting|already in use"
+msgstr ""
+
+msgid "ProjectTemplates|.NET Core"
+msgstr ""
+
+msgid "ProjectTemplates|Android"
+msgstr ""
+
+msgid "ProjectTemplates|GitLab Cluster Management"
+msgstr ""
+
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
+msgid "ProjectTemplates|Go Micro"
+msgstr ""
+
+msgid "ProjectTemplates|HIPAA Audit Protocol"
+msgstr ""
+
+msgid "ProjectTemplates|Jsonnet for Dynamic Child Pipelines"
+msgstr ""
+
+msgid "ProjectTemplates|Kotlin Native for Linux"
+msgstr ""
+
+msgid "ProjectTemplates|Laravel Framework"
+msgstr ""
+
+msgid "ProjectTemplates|Netlify/GitBook"
+msgstr ""
+
+msgid "ProjectTemplates|Netlify/Hexo"
+msgstr ""
+
+msgid "ProjectTemplates|Netlify/Hugo"
+msgstr ""
+
+msgid "ProjectTemplates|Netlify/Jekyll"
+msgstr ""
+
+msgid "ProjectTemplates|Netlify/Plain HTML"
+msgstr ""
+
+msgid "ProjectTemplates|NodeJS Express"
+msgstr ""
+
+msgid "ProjectTemplates|Pages/Bridgetown"
+msgstr ""
+
+msgid "ProjectTemplates|Pages/Gatsby"
+msgstr ""
+
+msgid "ProjectTemplates|Pages/Hexo"
+msgstr ""
+
+msgid "ProjectTemplates|Pages/Hugo"
+msgstr ""
+
+msgid "ProjectTemplates|Pages/Jekyll"
+msgstr ""
+
+msgid "ProjectTemplates|Pages/Middleman"
+msgstr ""
+
+msgid "ProjectTemplates|Pages/Pelican"
+msgstr ""
+
+msgid "ProjectTemplates|Pages/Plain HTML"
+msgstr ""
+
+msgid "ProjectTemplates|Ruby on Rails"
+msgstr ""
+
+msgid "ProjectTemplates|SalesforceDX"
+msgstr ""
+
+msgid "ProjectTemplates|Sample GitLab Project"
+msgstr ""
+
+msgid "ProjectTemplates|Serverless Framework/JS"
+msgstr ""
+
+msgid "ProjectTemplates|Spring"
+msgstr ""
+
+msgid "ProjectTemplates|TYPO3 Distribution"
+msgstr ""
+
+msgid "ProjectTemplates|Tencent Serverless Framework/NextjsSSR"
+msgstr ""
+
+msgid "ProjectTemplates|iOS (Swift)"
+msgstr ""
+
+msgid "ProjectTransfer|An error occurred fetching the transfer locations, please refresh the page and try again."
+msgstr ""
+
+msgid "ProjectView|Activity"
+msgstr ""
+
+msgid "ProjectView|Files and Readme (default)"
+msgstr ""
+
+msgid "ProjectView|Readme"
+msgstr ""
+
+msgid "ProjectView|Wiki"
+msgstr ""
+
+msgid "Projects"
+msgstr ""
+
+msgid "Projects (%{count})"
+msgstr ""
+
+msgid "Projects API"
+msgstr ""
+
+msgid "Projects API rate limit"
+msgstr ""
+
+msgid "Projects Successfully Retrieved"
+msgstr ""
+
+msgid "Projects are graded based on the highest severity vulnerability present"
+msgstr ""
+
+msgid "Projects are where you store your code, access issues, wiki and other features of GitLab."
+msgstr ""
+
+msgid "Projects contributed to"
+msgstr ""
+
+msgid "Projects help you organize your work. They contain your file repository, issues, merge requests, and so much more."
+msgstr ""
+
+msgid "Projects in this group can use Git LFS"
+msgstr ""
+
+msgid "Projects shared with %{group_name}"
+msgstr ""
+
+msgid "Projects to index"
+msgstr ""
+
+msgid "Projects with critical vulnerabilities"
+msgstr ""
+
+msgid "Projects with high or unknown vulnerabilities"
+msgstr ""
+
+msgid "Projects with low vulnerabilities"
+msgstr ""
+
+msgid "Projects with medium vulnerabilities"
+msgstr ""
+
+msgid "Projects with no vulnerabilities and security scanning enabled"
+msgstr ""
+
+msgid "Projects with this topic"
+msgstr ""
+
+msgid "Projects with write access"
+msgstr ""
+
+msgid "ProjectsDropdown|Frequently visited"
+msgstr ""
+
+msgid "ProjectsDropdown|Loading projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Projects you visit often will appear here"
+msgstr ""
+
+msgid "ProjectsDropdown|Search your projects"
+msgstr ""
+
+msgid "ProjectsDropdown|Something went wrong on our end."
+msgstr ""
+
+msgid "ProjectsDropdown|Sorry, no projects matched your search"
+msgstr ""
+
+msgid "ProjectsDropdown|This feature requires browser localStorage support"
+msgstr ""
+
+msgid "ProjectsDropdown|Toggle edit mode"
+msgstr ""
+
+msgid "ProjectsNew|Allows you to immediately clone this project’s repository. Skip this if you plan to push up an existing repository."
+msgstr ""
+
+msgid "ProjectsNew|An error occurred while checking group path. Please refresh and try again."
+msgstr ""
+
+msgid "ProjectsNew|Analyze your source code for known security vulnerabilities."
+msgstr ""
+
+msgid "ProjectsNew|Connect your external repository to GitLab CI/CD."
+msgstr ""
+
+msgid "ProjectsNew|Contact an administrator to enable options for importing your project."
+msgstr ""
+
+msgid "ProjectsNew|Create"
+msgstr ""
+
+msgid "ProjectsNew|Create a blank project to store your files, plan your work, and collaborate on code, among other things."
+msgstr ""
+
+msgid "ProjectsNew|Create a project pre-populated with the necessary files to get you started quickly."
+msgstr ""
+
+msgid "ProjectsNew|Create blank project"
+msgstr ""
+
+msgid "ProjectsNew|Create from template"
+msgstr ""
+
+msgid "ProjectsNew|Create new project"
+msgstr ""
+
+msgid "ProjectsNew|Description format"
+msgstr ""
+
+msgid "ProjectsNew|Enable Static Application Security Testing (SAST)"
+msgstr ""
+
+msgid "ProjectsNew|Group name"
+msgstr ""
+
+msgid "ProjectsNew|Import"
+msgstr ""
+
+msgid "ProjectsNew|Import project"
+msgstr ""
+
+msgid "ProjectsNew|Include a Getting Started README"
+msgstr ""
+
+msgid "ProjectsNew|Initialize repository with a README"
+msgstr ""
+
+msgid "ProjectsNew|Migrate your data from an external source like GitHub, Bitbucket, or another instance of GitLab."
+msgstr ""
+
+msgid "ProjectsNew|Must start with a lowercase or uppercase letter, digit, emoji, or underscore. Can also contain dots, pluses, dashes, or spaces."
+msgstr ""
+
+msgid "ProjectsNew|New project"
+msgstr ""
+
+msgid "ProjectsNew|No import options available"
+msgstr ""
+
+msgid "ProjectsNew|Pick a group or namespace"
+msgstr ""
+
+msgid "ProjectsNew|Pick a group or namespace where you want to create this project."
+msgstr ""
+
+msgid "ProjectsNew|Project Configuration"
+msgstr ""
+
+msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
+msgstr ""
+
+msgid "ProjectsNew|Project name"
+msgstr ""
+
+msgid "ProjectsNew|Projects"
+msgstr ""
+
+msgid "ProjectsNew|Projects are organized into groups"
+msgstr ""
+
+msgid "ProjectsNew|Recommended if you're new to GitLab"
+msgstr ""
+
+msgid "ProjectsNew|Run CI/CD for external repository"
+msgstr ""
+
+msgid "ProjectsNew|Unable to suggest a path. Please refresh and try again."
+msgstr ""
+
+msgid "ProjectsNew|Visibility Level"
+msgstr ""
+
+msgid "ProjectsNew|Want to organize several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}"
+msgstr ""
+
+msgid "ProjectsNew|You can always change your URL later"
+msgstr ""
+
+msgid "ProjectsNew|Your project will be created at:"
+msgstr ""
+
+msgid "Project|already in use"
+msgstr ""
+
+msgid "PrometheusAlerts|exceeded"
+msgstr ""
+
+msgid "PrometheusAlerts|is equal to"
+msgstr ""
+
+msgid "PrometheusAlerts|is less than"
+msgstr ""
+
+msgid "PrometheusService|%{exporters} with %{metrics} were found"
+msgstr ""
+
+msgid "PrometheusService|Active"
+msgstr ""
+
+msgid "PrometheusService|Auto configuration settings are used unless you override their values here."
+msgstr ""
+
+msgid "PrometheusService|Common metrics"
+msgstr ""
+
+msgid "PrometheusService|Common metrics are automatically monitored based on a library of metrics from popular exporters."
+msgstr ""
+
+msgid "PrometheusService|Configure GitLab to query a Prometheus installed in one of your clusters."
+msgstr ""
+
+msgid "PrometheusService|Custom metrics"
+msgstr ""
+
+msgid "PrometheusService|Custom metrics require Prometheus installed on a cluster with environment scope \"*\" OR a manually configured Prometheus to be available."
+msgstr ""
+
+msgid "PrometheusService|Enable Prometheus to define custom metrics, using either option above"
+msgstr ""
+
+msgid "PrometheusService|Finding and configuring metrics..."
+msgstr ""
+
+msgid "PrometheusService|Finding custom metrics..."
+msgstr ""
+
+msgid "PrometheusService|IAP_CLIENT_ID.apps.googleusercontent.com"
+msgstr ""
+
+msgid "PrometheusService|Manage clusters"
+msgstr ""
+
+msgid "PrometheusService|Manual configuration"
+msgstr ""
+
+msgid "PrometheusService|Metrics"
+msgstr ""
+
+msgid "PrometheusService|Missing environment variable"
+msgstr ""
+
+msgid "PrometheusService|Monitor application health with Prometheus metrics and dashboards"
+msgstr ""
+
+msgid "PrometheusService|More information"
+msgstr ""
+
+msgid "PrometheusService|New metric"
+msgstr ""
+
+msgid "PrometheusService|No %{docsUrlStart}common metrics%{docsUrlEnd} were found"
+msgstr ""
+
+msgid "PrometheusService|No custom metrics have been created. Create one using the button above"
+msgstr ""
+
+msgid "PrometheusService|Prometheus cluster integration"
+msgstr ""
+
+msgid "PrometheusService|Select this checkbox to override the auto configuration settings with your own settings."
+msgstr ""
+
+msgid "PrometheusService|The ID of the IAP-secured resource."
+msgstr ""
+
+msgid "PrometheusService|The Prometheus API base URL."
+msgstr ""
+
+msgid "PrometheusService|The contents of the credentials.json file of your service account."
+msgstr ""
+
+msgid "PrometheusService|These metrics will only be monitored after your first deployment to an environment"
+msgstr ""
+
+msgid "PrometheusService|To set up automatic monitoring, add the environment variable %{variable} to exporter's queries."
+msgstr ""
+
+msgid "PrometheusService|To use a Prometheus installed on a cluster, deactivate the manual configuration."
+msgstr ""
+
+msgid "PrometheusService|Waiting for your first deployment to an environment to find common metrics"
+msgstr ""
+
+msgid "PrometheusService|You have a cluster with the Prometheus integration enabled."
+msgstr ""
+
+msgid "PrometheusService|https://prometheus.example.com/"
+msgstr ""
+
+msgid "PrometheusService|{ \"type\": \"service_account\", \"project_id\": ... }"
+msgstr ""
+
+msgid "Promote"
+msgstr ""
+
+msgid "Promote issue to an epic"
+msgstr ""
+
+msgid "Promote issue to incident"
+msgstr ""
+
+msgid "Promote to epic"
+msgstr ""
+
+msgid "Promote to group label"
+msgstr ""
+
+msgid "Promote to objective"
+msgstr ""
+
+msgid "Promote work item"
+msgstr ""
+
+msgid "PromoteMilestone|Only project milestones can be promoted."
+msgstr ""
+
+msgid "PromoteMilestone|Project does not belong to a group."
+msgstr ""
+
+msgid "PromoteMilestone|Promotion failed - %{message}"
+msgstr ""
+
+msgid "Promoted issue to an epic."
+msgstr ""
+
+msgid "Promotes issue to incident"
+msgstr ""
+
+msgid "Promotes work item to %{type}."
+msgstr ""
+
+msgid "Promotion is not supported."
+msgstr ""
+
+msgid "Promotions|Add %{link_start} description templates %{link_end} to help your contributors to communicate effectively!"
+msgstr ""
+
+msgid "Promotions|Add Group Webhooks and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Promotions|Better Protected Branches"
+msgstr ""
+
+msgid "Promotions|Burndown Charts are visual representations of the progress of completing a milestone. At a glance, you see the current state for the completion a given milestone. Without them, you would have to organize the data from the milestone and plot it yourself to have the same sense of progress."
+msgstr ""
+
+msgid "Promotions|Buy EE"
+msgstr ""
+
+msgid "Promotions|Buy GitLab Enterprise Edition"
+msgstr ""
+
+msgid "Promotions|Configure Service Desk"
+msgstr ""
+
+msgid "Promotions|Contact an owner of group %{namespace_name} to upgrade the plan."
+msgstr ""
+
+msgid "Promotions|Contact owner %{link_start}%{owner_name}%{link_end} to upgrade the plan."
+msgstr ""
+
+msgid "Promotions|Contact your Administrator to upgrade your license."
+msgstr ""
+
+msgid "Promotions|Dismiss Service Desk promotion"
+msgstr ""
+
+msgid "Promotions|Dismiss burndown charts promotion"
+msgstr ""
+
+msgid "Promotions|Dismiss repository features promotion"
+msgstr ""
+
+msgid "Promotions|Don't show me this again"
+msgstr ""
+
+msgid "Promotions|Epics let you manage your portfolio of projects more efficiently and with less effort by tracking groups of issues that share a theme, across projects and milestones."
+msgstr ""
+
+msgid "Promotions|Get started with GitLab Mobile DevOps"
+msgstr ""
+
+msgid "Promotions|Improve issues management with Issue weight and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Promotions|Improve merge requests and customer support with GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Promotions|Improve milestones with Burndown Charts."
+msgstr ""
+
+msgid "Promotions|Improve repositories with GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Promotions|Improve search with Advanced Search and GitLab Enterprise Edition."
+msgstr ""
+
+msgid "Promotions|Keep track of events in your project"
+msgstr ""
+
+msgid "Promotions|Merge request approvals"
+msgstr ""
+
+msgid "Promotions|Not now, thanks!"
+msgstr ""
+
+msgid "Promotions|Push Rules"
+msgstr ""
+
+msgid "Promotions|Push Rules are defined per project so you can have different rules applied to different projects depends on your needs."
+msgstr ""
+
+msgid "Promotions|Repository Mirroring"
+msgstr ""
+
+msgid "Promotions|Repository Mirroring is a way to mirror repositories from external sources. It can be used to mirror all branches, tags, and commits that you have in your repository."
+msgstr ""
+
+msgid "Promotions|See the other features in the %{subscription_link_start}Premium plan%{subscription_link_end}"
+msgstr ""
+
+msgid "Promotions|Set the number of necessary approvals and define a list of approvers needed for every merge request in a project."
+msgstr ""
+
+msgid "Promotions|Ship faster with GitLab Mobile DevOps."
+msgstr ""
+
+msgid "Promotions|Start GitLab Ultimate trial"
+msgstr ""
+
+msgid "Promotions|The Advanced Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
+msgstr ""
+
+msgid "Promotions|This feature is locked."
+msgstr ""
+
+msgid "Promotions|Try it for free"
+msgstr ""
+
+msgid "Promotions|Upgrade plan"
+msgstr ""
+
+msgid "Promotions|Upgrade your plan to activate Advanced Search."
+msgstr ""
+
+msgid "Promotions|Upgrade your plan to activate Audit Events."
+msgstr ""
+
+msgid "Promotions|Upgrade your plan to activate Group Webhooks."
+msgstr ""
+
+msgid "Promotions|Upgrade your plan to improve merge requests."
+msgstr ""
+
+msgid "Promotions|Upgrade your plan to improve milestones with Burndown Charts."
+msgstr ""
+
+msgid "Promotions|Upgrade your plan to improve repositories."
+msgstr ""
+
+msgid "Promotions|Use GitLab Mobile DevOps to quickly build, sign, and release native and cross-platform mobile apps for Android and iOS using GitLab CI/CD."
+msgstr ""
+
+msgid "Promotions|Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
+msgstr ""
+
+msgid "Promotions|Weight"
+msgstr ""
+
+msgid "Promotions|Weighting your issue"
+msgstr ""
+
+msgid "Promotions|When you have a lot of issues, it can be hard to get an overview. By adding a weight to your issues, you can get a better idea of the effort, cost, required time, or value of each, and so better manage them."
+msgstr ""
+
+msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users."
+msgstr ""
+
+msgid "Prompt users to upload SSH keys"
+msgstr ""
+
+msgid "Property 'dedicatedPod' of component '%{name}' is not yet supported"
+msgstr ""
+
+msgid "Protect"
+msgstr ""
+
+msgid "Protect a tag"
+msgstr ""
+
+msgid "Protect variable"
+msgstr ""
+
+msgid "Protected"
+msgstr ""
+
+msgid "Protected Branch"
+msgstr ""
+
+msgid "Protected Branches"
+msgstr ""
+
+msgid "Protected Paths: requests"
+msgstr ""
+
+msgid "Protected Tag"
+msgstr ""
+
+msgid "Protected Tags"
+msgstr ""
+
+msgid "Protected branches"
+msgstr ""
+
+msgid "Protected environments"
+msgstr ""
+
+msgid "Protected paths"
+msgstr ""
+
+msgid "Protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported."
+msgstr ""
+
+msgid "ProtectedBranch|After you configure a protected branch, merge request approval, or status check, it appears here."
+msgstr ""
+
+msgid "ProtectedBranch|Allow all users with push access to %{tag_start}force push%{tag_end}."
+msgstr ""
+
+msgid "ProtectedBranch|Allow all users with push access to force push."
+msgstr ""
+
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
+msgid "ProtectedBranch|Allowed to force push"
+msgstr ""
+
+msgid "ProtectedBranch|Allowed to force push:"
+msgstr ""
+
+msgid "ProtectedBranch|Allowed to merge"
+msgstr ""
+
+msgid "ProtectedBranch|Allowed to merge:"
+msgstr ""
+
+msgid "ProtectedBranch|Allowed to push and merge"
+msgstr ""
+
+msgid "ProtectedBranch|Allowed to push and merge:"
+msgstr ""
+
+msgid "ProtectedBranch|An error occurred while loading branch rules. Please try again."
+msgstr ""
+
+msgid "ProtectedBranch|Branch"
+msgstr ""
+
+msgid "ProtectedBranch|Branch does not exist."
+msgstr ""
+
+msgid "ProtectedBranch|Branch will be writable for developers. Are you sure?"
+msgstr ""
+
+msgid "ProtectedBranch|Branch:"
+msgstr ""
+
+msgid "ProtectedBranch|By default, protected branches restrict who can modify the branch."
+msgstr ""
+
+msgid "ProtectedBranch|Code owner approval"
+msgstr ""
+
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
+msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
+msgstr ""
+
+msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
+msgstr ""
+
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
+msgid "ProtectedBranch|Learn more."
+msgstr ""
+
+msgid "ProtectedBranch|Manage branch related settings in one area with branch rules."
+msgstr ""
+
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
+msgid "ProtectedBranch|Only %{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported."
+msgstr ""
+
+msgid "ProtectedBranch|Protect"
+msgstr ""
+
+msgid "ProtectedBranch|Protect a branch"
+msgstr ""
+
+msgid "ProtectedBranch|Protected branches"
+msgstr ""
+
+msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
+msgstr ""
+
+msgid "ProtectedBranch|Require approval from code owners:"
+msgstr ""
+
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
+msgid "ProtectedBranch|Tag"
+msgstr ""
+
+msgid "ProtectedBranch|There are currently no protected branches, to protect a branch start by creating a new one above."
+msgstr ""
+
+msgid "ProtectedBranch|Toggle allowed to force push"
+msgstr ""
+
+msgid "ProtectedBranch|Toggle code owner approval"
+msgstr ""
+
+msgid "ProtectedBranch|Unprotect"
+msgstr ""
+
+msgid "ProtectedBranch|Unprotect branch"
+msgstr ""
+
+msgid "ProtectedBranch|View branch rule"
+msgstr ""
+
+msgid "ProtectedBranch|View protected branches as branch rules"
+msgstr ""
+
+msgid "ProtectedBranch|What are protected branches?"
+msgstr ""
+
+msgid "ProtectedBranch|What are the security implications?"
+msgstr ""
+
+msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
+msgstr ""
+
+msgid "ProtectedBranch|default"
+msgstr ""
+
+msgid "ProtectedEnvironments|%d Approval Rule"
+msgid_plural "ProtectedEnvironments|%d Approval Rules"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ProtectedEnvironments|%d Deployment Rule"
+msgid_plural "ProtectedEnvironments|%d Deployment Rules"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ProtectedEnvironments|Add approval rules"
+msgstr ""
+
+msgid "ProtectedEnvironments|Add deployment rules"
+msgstr ""
+
+msgid "ProtectedEnvironments|Allowed to approve"
+msgstr ""
+
+msgid "ProtectedEnvironments|Allowed to deploy"
+msgstr ""
+
+msgid "ProtectedEnvironments|An error occurred while fetching information on the selected approvers."
+msgstr ""
+
+msgid "ProtectedEnvironments|Approval rules"
+msgstr ""
+
+msgid "ProtectedEnvironments|Approvals required"
+msgstr ""
+
+msgid "ProtectedEnvironments|Create approval rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Create deployment rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete approver rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Delete deployer rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Edit"
+msgstr ""
+
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
+msgstr ""
+
+msgid "ProtectedEnvironments|Remove approval rule"
+msgstr ""
+
+msgid "ProtectedEnvironments|Required approval count"
+msgstr ""
+
+msgid "ProtectedEnvironments|Save"
+msgstr ""
+
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
+msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
+msgstr ""
+
+msgid "ProtectedEnvironments|Set which groups, access levels or users that are allowed to deploy to this environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|To configure unified approval rules, use the %{apiLinkStart}API%{apiLinkEnd}. Consider using %{docsLinkStart}multiple approval rules%{docsLinkEnd} instead."
+msgstr ""
+
+msgid "ProtectedEnvironments|Unprotect"
+msgstr ""
+
+msgid "ProtectedEnvironments|Users"
+msgstr ""
+
+msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
+msgstr ""
+
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
+msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
+msgstr ""
+
+msgid "ProtectedEnvironment|Allowed to deploy"
+msgstr ""
+
+msgid "ProtectedEnvironment|Allowed to deploy to %{project} / %{environment}"
+msgstr ""
+
+msgid "ProtectedEnvironment|Approvers"
+msgstr ""
+
+msgid "ProtectedEnvironment|Environment"
+msgstr ""
+
+msgid "ProtectedEnvironment|Environments protected upstream"
+msgstr ""
+
+msgid "ProtectedEnvironment|Failed to load details for this group."
+msgstr ""
+
+msgid "ProtectedEnvironment|No environments in this project are protected."
+msgstr ""
+
+msgid "ProtectedEnvironment|Only specified groups can execute deployments in protected environments."
+msgstr ""
+
+msgid "ProtectedEnvironment|Only specified users can execute deployments in a protected environment."
+msgstr ""
+
+msgid "ProtectedEnvironment|Parent group"
+msgstr ""
+
+msgid "ProtectedEnvironment|Protect"
+msgstr ""
+
+msgid "ProtectedEnvironment|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironment|Protected Environment (%{protected_environments_count})"
+msgstr ""
+
+msgid "ProtectedEnvironment|Protected Environments"
+msgstr ""
+
+msgid "ProtectedEnvironment|Required approvals"
+msgstr ""
+
+msgid "ProtectedEnvironment|Select an environment"
+msgstr ""
+
+msgid "ProtectedEnvironment|Select environment"
+msgstr ""
+
+msgid "ProtectedEnvironment|Select groups"
+msgstr ""
+
+msgid "ProtectedEnvironment|There are currently no protected environments."
+msgstr ""
+
+msgid "ProtectedEnvironment|Unprotect"
+msgstr ""
+
+msgid "ProtectedEnvironment|Unprotect environment"
+msgstr ""
+
+msgid "ProtectedEnvironment|Users with at least the Developer role can write to unprotected environments. Are you sure you want to unprotect %{environment_name}?"
+msgstr ""
+
+msgid "ProtectedEnvironment|Your environment can't be unprotected"
+msgstr ""
+
+msgid "ProtectedEnvironment|Your environment has been protected."
+msgstr ""
+
+msgid "ProtectedEnvironment|Your environment has been unprotected"
+msgstr ""
+
+msgid "ProtectedTags|Unprotect tag"
+msgstr ""
+
+msgid "ProtectedTags|default"
+msgstr ""
+
+msgid "ProtectedTag|By default, protected tags restrict who can modify the tag."
+msgstr ""
+
+msgid "ProtectedTag|Learn more."
+msgstr ""
+
+msgid "ProtectedTag|Limit access to creating and updating tags."
+msgstr ""
+
+msgid "ProtectedTag|Protected tags"
+msgstr ""
+
+msgid "ProtectedTag|What are protected tags?"
+msgstr ""
+
+msgid "ProtectedTag|default"
+msgstr ""
+
+msgid "Protip: %{linkStart}Auto DevOps%{linkEnd} uses Kubernetes clusters to deploy your code!"
+msgstr ""
+
+msgid "Provide Feedback"
+msgstr ""
+
+msgid "Provide a number our sales team can use to call you."
+msgstr ""
+
+msgid "Provide feedback"
+msgstr ""
+
+msgid "Provider"
+msgstr ""
+
+msgid "Provision instructions"
+msgstr ""
+
+msgid "Provisioned by:"
+msgstr ""
+
+msgid "Public"
+msgstr ""
+
+msgid "Public - The group and any public projects can be viewed without any authentication."
+msgstr ""
+
+msgid "Public - The project can be accessed without any authentication."
+msgstr ""
+
+msgid "Public Access Help"
+msgstr ""
+
+msgid "Public deploy keys"
+msgstr ""
+
+msgid "Public pipelines"
+msgstr ""
+
+msgid "Public projects are an easy way to allow everyone to have read-only access."
+msgstr ""
+
+msgid "Public projects compute cost factor"
+msgstr ""
+
+msgid "Publish to status page"
+msgstr ""
+
+msgid "Published"
+msgstr ""
+
+msgid "Published on status page"
+msgstr ""
+
+msgid "Publishes this issue to the associated status page."
+msgstr ""
+
+msgid "Pull"
+msgstr ""
+
+msgid "Pull mirroring updated %{time}."
+msgstr ""
+
+msgid "Pull requests from fork are not supported"
+msgstr ""
+
+msgid "Puma is running with a thread count above 1 and the Rugged service is enabled. This may decrease performance in some environments. See our %{link_start}documentation%{link_end} for details of this issue."
+msgstr ""
+
+msgid "PumbleIntegration|Send notifications about project events to Pumble."
+msgstr ""
+
+msgid "PumbleIntegration|Send notifications about project events to Pumble. %{docs_link}"
+msgstr ""
+
+msgid "Purchase more minutes"
+msgstr ""
+
+msgid "Purchase more storage"
+msgstr ""
+
+msgid "PurchaseStep|An error occurred in the purchase step. If the problem persists please contact support at https://support.gitlab.com."
+msgstr ""
+
+msgid "Purchase|A full name in your profile is required to make a purchase. Check that the full name field in your %{userProfileLinkStart}user profile%{userProfileLinkEnd} has both a first and last name, then retry the purchase. If the problem persists, %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Purchase|An error occurred with your purchase because your group is currently linked to an expired subscription. %{supportLinkStart}Open a support ticket%{supportLinkEnd}, and our support team will assist with a workaround."
+msgstr ""
+
+msgid "Purchase|An error occurred with your purchase. We detected a %{customersPortalLinkStart}Customers Portal%{customersPortalLinkEnd} account that matches your email address, but it has not been linked to your GitLab.com account. Follow the %{linkCustomersPortalHelpLinkStart}instructions to link your Customers Portal account%{linkCustomersPortalHelpLinkEnd}, and retry the purchase. If the problem persists, %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Purchase|Your card was declined due to insufficient funds. Make sure you have sufficient funds, then retry the purchase or use a different card. If the problem persists, %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Purchase|Your card was declined. Contact your card issuer for more information or %{salesLinkStart}contact our sales team%{salesLinkEnd} to pay with an alternative payment method."
+msgstr ""
+
+msgid "Push"
+msgstr ""
+
+msgid "Push Rule updated successfully."
+msgstr ""
+
+msgid "Push Rules"
+msgstr ""
+
+msgid "Push Rules updated successfully."
+msgstr ""
+
+msgid "Push an existing Git repository"
+msgstr ""
+
+msgid "Push an existing folder"
+msgstr ""
+
+msgid "Push code to the repository."
+msgstr ""
+
+msgid "Push commits to the source branch or add previously merged commits to review them."
+msgstr ""
+
+msgid "Push events"
+msgstr ""
+
+msgid "Push project from command line"
+msgstr ""
+
+msgid "Push the source branch up to GitLab."
+msgstr ""
+
+msgid "Push to create a project"
+msgstr ""
+
+msgid "PushRules|All branch names must match this %{wiki_syntax_link_start}regular expression%{wiki_syntax_link_end}. If empty, any branch name is allowed."
+msgstr ""
+
+msgid "PushRules|All commit author's email must match this %{wiki_syntax_link_start}regular expression%{wiki_syntax_link_end}. If empty, any email is allowed."
+msgstr ""
+
+msgid "PushRules|All commit messages must match this %{wiki_syntax_link_start}regular expression%{wiki_syntax_link_end}. If empty, commit messages are not required to match any expression."
+msgstr ""
+
+msgid "PushRules|All committed filenames cannot match this %{wiki_syntax_link_start}regular expression%{wiki_syntax_link_end}. If empty, any filename is allowed."
+msgstr ""
+
+msgid "PushRules|Branch name"
+msgstr ""
+
+msgid "PushRules|Check %{link_start}Branch defaults &gt; Branch name templates%{link_end} for potential conflicts."
+msgstr ""
+
+msgid "PushRules|Check whether the commit author is a GitLab user"
+msgstr ""
+
+msgid "PushRules|Commit author's email"
+msgstr ""
+
+msgid "PushRules|Commit messages cannot match this %{wiki_syntax_link_start}regular expression%{wiki_syntax_link_end}. If empty, commit messages are not rejected based on any expression."
+msgstr ""
+
+msgid "PushRules|Do not allow users to remove Git tags with %{code_block_start}git push%{code_block_end}"
+msgstr ""
+
+msgid "PushRules|Maximum file size (MB)"
+msgstr ""
+
+msgid "PushRules|Prevent pushing secret files"
+msgstr ""
+
+msgid "PushRules|Prohibited file names"
+msgstr ""
+
+msgid "PushRules|Reject any files likely to contain secrets. %{secret_files_link_start}What secret files are rejected?%{secret_files_link_end}"
+msgstr ""
+
+msgid "PushRules|Reject commits that aren't DCO certified"
+msgstr ""
+
+msgid "PushRules|Reject expression in commit messages"
+msgstr ""
+
+msgid "PushRules|Reject file sizes equal to or greater than this size. If set to 0, files of any size are allowed. This rule does not apply to files tracked by Git LFS."
+msgstr ""
+
+msgid "PushRules|Reject unsigned commits"
+msgstr ""
+
+msgid "PushRules|Require expression in commit messages"
+msgstr ""
+
+msgid "PushRules|Restrict commits to existing GitLab users."
+msgstr ""
+
+msgid "PushRules|Restrict push operations for this project."
+msgstr ""
+
+msgid "PushRules|Save push rules"
+msgstr ""
+
+msgid "PushRules|Select push rules"
+msgstr ""
+
+msgid "PushRules|Users can still delete tags through the GitLab UI."
+msgstr ""
+
+msgid "PushRule|Push rules"
+msgstr ""
+
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
+msgid "PushRule|Reject unverified users"
+msgstr ""
+
+msgid "Pushes"
+msgstr ""
+
+msgid "PushoverService|%{user_name} deleted branch \"%{ref}\"."
+msgstr ""
+
+msgid "PushoverService|%{user_name} push to branch \"%{ref}\"."
+msgstr ""
+
+msgid "PushoverService|%{user_name} pushed new branch \"%{ref}\"."
+msgstr ""
+
+msgid "PushoverService|Enter new user key"
+msgstr ""
+
+msgid "PushoverService|Enter your application key."
+msgstr ""
+
+msgid "PushoverService|Enter your user key."
+msgstr ""
+
+msgid "PushoverService|Get real-time notifications on your device."
+msgstr ""
+
+msgid "PushoverService|High priority"
+msgstr ""
+
+msgid "PushoverService|Leave blank for all active devices."
+msgstr ""
+
+msgid "PushoverService|Leave blank to use your current user key."
+msgstr ""
+
+msgid "PushoverService|Low priority"
+msgstr ""
+
+msgid "PushoverService|Lowest priority"
+msgstr ""
+
+msgid "PushoverService|Normal priority"
+msgstr ""
+
+msgid "PushoverService|See project %{project_full_name}"
+msgstr ""
+
+msgid "PushoverService|Total commits count: %{total_commits_count}"
+msgstr ""
+
+msgid "QualitySummary|Project quality"
+msgstr ""
+
+msgid "Query"
+msgstr ""
+
+msgid "Queued"
+msgstr ""
+
+msgid "Quick actions can be used in description and comment boxes."
+msgstr ""
+
+msgid "Quick help"
+msgstr ""
+
+msgid "Quick range"
+msgstr ""
+
+msgid "README"
+msgstr ""
+
+msgid "Rails"
+msgstr ""
+
+msgid "Rake Tasks Help"
+msgstr ""
+
+msgid "Random"
+msgstr ""
+
+msgid "Rate Limits"
+msgstr ""
+
+msgid "Rate limit"
+msgstr ""
+
+msgid "Rate limit access to specified paths."
+msgstr ""
+
+msgid "Rate limits can help reduce request volume (like from crawlers or abusive bots)."
+msgstr ""
+
+msgid "Raw blob request rate limit per minute"
+msgstr ""
+
+msgid "Raw blob requests"
+msgstr ""
+
+msgid "Re-authentication period expired or never requested. Please try again"
+msgstr ""
+
+msgid "Re-authentication required"
+msgstr ""
+
+msgid "Re-import"
+msgstr ""
+
+msgid "Re-import with projects"
+msgstr ""
+
+msgid "Re-import without projects"
+msgstr ""
+
+msgid "Re-request review"
+msgstr ""
+
+msgid "Read documentation"
+msgstr ""
+
+msgid "Read more"
+msgstr ""
+
+msgid "Read more about GitLab at %{link_to_promo}."
+msgstr ""
+
+msgid "Read more about the %{changes_link_start}changes%{link_end}, the %{vision_link_start}vision%{link_end}, and the %{design_link_start}design%{link_end}."
+msgstr ""
+
+msgid "Read the documentation before applying changes."
+msgstr ""
+
+msgid "Read their documentation."
+msgstr ""
+
+msgid "Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project."
+msgstr ""
+
+msgid "Ready to merge by members who can write to the target branch."
+msgstr ""
+
+msgid "Ready to merge!"
+msgstr ""
+
+msgid "Reauthenticating with SAML provider."
+msgstr ""
+
+msgid "Rebase completed"
+msgstr ""
+
+msgid "Rebase source branch"
+msgstr ""
+
+msgid "Rebase source branch on the target branch."
+msgstr ""
+
+msgid "Recaptcha verified?"
+msgstr ""
+
+msgid "Receive any notifications from GitLab."
+msgstr ""
+
+msgid "Receive notification of abuse reports by email."
+msgstr ""
+
+msgid "Receive notifications about your own activity"
+msgstr ""
+
+msgid "Recent"
+msgstr ""
+
+msgid "Recent Project Activity"
+msgstr ""
+
+msgid "Recent Searches Service is unavailable"
+msgstr ""
+
+msgid "Recent events"
+msgstr ""
+
+msgid "Recent searches"
+msgstr ""
+
+msgid "Recently used"
+msgstr ""
+
+msgid "Reconfigure"
+msgstr ""
+
+msgid "Recover password"
+msgstr ""
+
+msgid "Recovery Codes"
+msgstr ""
+
+msgid "Redirect to SAML provider to test configuration"
+msgstr ""
+
+msgid "Redirecting"
+msgstr ""
+
+msgid "Redis"
+msgstr ""
+
+msgid "Reduce incident management alert volume (for example, if too many issues are being created)."
+msgstr ""
+
+msgid "Reduce project visibility"
+msgstr ""
+
+msgid "Reduce risk and triage fewer vulnerabilities with security training"
+msgstr ""
+
+msgid "Reference"
+msgstr ""
+
+msgid "Reference copied"
+msgstr ""
+
+msgid "References"
+msgstr ""
+
+msgid "References should be in the form of path/to/project!merge_request_id"
+msgstr ""
+
+msgid "Refine your search criteria (select a %{strong_open}group%{strong_close} and %{strong_open}project%{strong_close} when possible)"
+msgstr ""
+
+msgid "Refresh the page and try again."
+msgstr ""
+
+msgid "Refresh the page to view sync status"
+msgstr ""
+
+msgid "Refreshing in a second to show the updated status..."
+msgid_plural "Refreshing in %d seconds to show the updated status..."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Refreshing..."
+msgstr ""
+
+msgid "Regenerate export"
+msgstr ""
+
+msgid "Regenerate instance ID"
+msgstr ""
+
+msgid "Regenerate recovery codes"
+msgstr ""
+
+msgid "Regenerating the instance ID can break integration depending on the client you are using."
+msgstr ""
+
+msgid "Regex pattern"
+msgstr ""
+
+msgid "Region"
+msgstr ""
+
+msgid "Regions"
+msgstr ""
+
+msgid "Register"
+msgstr ""
+
+msgid "Register / Sign In"
+msgstr ""
+
+msgid "Register a WebAuthn device"
+msgstr ""
+
+msgid "Register a one-time password authenticator"
+msgstr ""
+
+msgid "Register a one-time password authenticator or a WebAuthn device first."
+msgstr ""
+
+msgid "Register device"
+msgstr ""
+
+msgid "Register now"
+msgstr ""
+
+msgid "Register the runner with this URL:"
+msgstr ""
+
+msgid "Register with two-factor app"
+msgstr ""
+
+msgid "Register with:"
+msgstr ""
+
+msgid "RegistrationFeatures|Enable Service Ping and register for this feature."
+msgstr ""
+
+msgid "RegistrationFeatures|Read more about the %{link_start}Registration Features Program%{link_end}."
+msgstr ""
+
+msgid "RegistrationFeatures|Want to %{feature_title} for free?"
+msgstr ""
+
+msgid "RegistrationFeatures|send emails to users"
+msgstr ""
+
+msgid "RegistrationFeatures|use this feature"
+msgstr ""
+
+msgid "Registries enqueued to be resynced"
+msgstr ""
+
+msgid "Registries enqueued to be reverified"
+msgstr ""
+
+msgid "Registry entry enqueued to be resynced"
+msgstr ""
+
+msgid "Registry entry enqueued to be reverified"
+msgstr ""
+
+msgid "Registry setup"
+msgstr ""
+
+msgid "Reindexing Status: %{status} (Slice multiplier: %{multiplier}, Maximum running slices: %{max_slices})"
+msgstr ""
+
+msgid "Reject"
+msgstr ""
+
+msgid "Rejected (closed)"
+msgstr ""
+
+msgid "Relate to %{issuable_type} %{add_related_issue_link}"
+msgstr ""
+
+msgid "Related"
+msgstr ""
+
+msgid "Related branches"
+msgstr ""
+
+msgid "Related feature flags"
+msgstr ""
+
+msgid "Related issues"
+msgstr ""
+
+msgid "Related merge request %{link_to_merge_request} to merge %{link_to_merge_request_source_branch}"
+msgstr ""
+
+msgid "Related merge request %{link_to_merge_request} to merge %{link_to_merge_request_source_branch} into %{link_to_merge_request_target_branch}"
+msgstr ""
+
+msgid "Related merge requests"
+msgstr ""
+
+msgid "Relates to"
+msgstr ""
+
+msgid "Release"
+msgid_plural "Releases"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Release %{deletedRelease} has been successfully deleted."
+msgstr ""
+
+msgid "Release already exists"
+msgstr ""
+
+msgid "Release assets"
+msgstr ""
+
+msgid "Release assets documentation"
+msgstr ""
+
+msgid "Release date"
+msgstr ""
+
+msgid "Release does not exist"
+msgstr ""
+
+msgid "Release does not have the same project as the milestone"
+msgstr ""
+
+msgid "Release notes"
+msgstr ""
+
+msgid "Release notes:"
+msgstr ""
+
+msgid "Release title"
+msgstr ""
+
+msgid "Release with tag \"%{tag}\" was not found"
+msgstr ""
+
+msgid "Release:"
+msgstr ""
+
+msgid "ReleaseAssetLinkType|Image"
+msgstr ""
+
+msgid "ReleaseAssetLinkType|Images"
+msgstr ""
+
+msgid "ReleaseAssetLinkType|Other"
+msgstr ""
+
+msgid "ReleaseAssetLinkType|Package"
+msgstr ""
+
+msgid "ReleaseAssetLinkType|Packages"
+msgstr ""
+
+msgid "ReleaseAssetLinkType|Runbook"
+msgstr ""
+
+msgid "ReleaseAssetLinkType|Runbooks"
+msgstr ""
+
+msgid "Released"
+msgstr ""
+
+msgid "Released date"
+msgstr ""
+
+msgid "Releases"
+msgstr ""
+
+msgid "Releases are based on Git tags. We recommend tags that use semantic versioning, for example %{codeStart}1.0.0%{codeEnd}, %{codeStart}2.1.0-pre%{codeEnd}."
+msgstr ""
+
+msgid "Releases|New"
+msgstr ""
+
+msgid "Releases|Releases"
+msgstr ""
+
+msgid "Releases|Tag message"
+msgstr ""
+
+msgid "Release|Create a new release"
+msgstr ""
+
+msgid "Release|Create tag"
+msgstr ""
+
+msgid "Release|Create tag %{tag}"
+msgstr ""
+
+msgid "Release|Getting started with releases"
+msgstr ""
+
+msgid "Release|Include message from the annotated tag."
+msgstr ""
+
+msgid "Release|Learn more about releases"
+msgstr ""
+
+msgid "Release|More information"
+msgstr ""
+
+msgid "Release|Or type a new tag name"
+msgstr ""
+
+msgid "Release|Release %{createdRelease} has been successfully created."
+msgstr ""
+
+msgid "Release|Releases are based on Git tags and mark specific points in a project's development history. They can contain information about the type of changes and can also deliver binaries, like compiled versions of your software."
+msgstr ""
+
+msgid "Release|Search or create tag name"
+msgstr ""
+
+msgid "Release|Select another tag"
+msgstr ""
+
+msgid "Release|Something went wrong while creating a new release."
+msgstr ""
+
+msgid "Release|Something went wrong while deleting the release."
+msgstr ""
+
+msgid "Release|Something went wrong while getting the release details."
+msgstr ""
+
+msgid "Release|Something went wrong while saving the release details."
+msgstr ""
+
+msgid "Release|Unable to fetch the tag notes."
+msgstr ""
+
+msgid "Release|You can edit the content later by editing the release. %{linkStart}How do I edit a release?%{linkEnd}"
+msgstr ""
+
+msgid "Reload page"
+msgstr ""
+
+msgid "Reload the page to try again."
+msgstr ""
+
+msgid "Remediations"
+msgstr ""
+
+msgid "Remember me"
+msgstr ""
+
+msgid "Remind later"
+msgstr ""
+
+msgid "Remote object has no absolute path."
+msgstr ""
+
+msgid "Remove"
+msgstr ""
+
+msgid "Remove %{displayReference}"
+msgstr ""
+
+msgid "Remove Zoom meeting"
+msgstr ""
+
+msgid "Remove Zoom meeting."
+msgstr ""
+
+msgid "Remove access"
+msgstr ""
+
+msgid "Remove all or specific assignees"
+msgstr ""
+
+msgid "Remove all or specific labels"
+msgstr ""
+
+msgid "Remove all or specific reviewers"
+msgstr ""
+
+msgid "Remove approvers"
+msgstr ""
+
+msgid "Remove approvers?"
+msgstr ""
+
+msgid "Remove asset link"
+msgstr ""
+
+msgid "Remove assignee"
+msgstr ""
+
+msgid "Remove avatar"
+msgstr ""
+
+msgid "Remove card"
+msgstr ""
+
+msgid "Remove child epic from an epic"
+msgstr ""
+
+msgid "Remove customer relation contact(s)."
+msgstr ""
+
+msgid "Remove customer relation contacts"
+msgstr ""
+
+msgid "Remove deploy key"
+msgstr ""
+
+msgid "Remove description history"
+msgstr ""
+
+msgid "Remove due date"
+msgstr ""
+
+msgid "Remove epic reference"
+msgstr ""
+
+msgid "Remove favicon"
+msgstr ""
+
+msgid "Remove file"
+msgstr ""
+
+msgid "Remove fork relationship"
+msgstr ""
+
+msgid "Remove from batch"
+msgstr ""
+
+msgid "Remove from epic"
+msgstr ""
+
+msgid "Remove group"
+msgstr ""
+
+msgid "Remove header logo"
+msgstr ""
+
+msgid "Remove icon"
+msgstr ""
+
+msgid "Remove issue reference"
+msgstr ""
+
+msgid "Remove iteration"
+msgstr ""
+
+msgid "Remove license"
+msgstr ""
+
+msgid "Remove limit"
+msgstr ""
+
+msgid "Remove link"
+msgstr ""
+
+msgid "Remove link with another issue"
+msgstr ""
+
+msgid "Remove list"
+msgstr ""
+
+msgid "Remove log"
+msgstr ""
+
+msgid "Remove logo"
+msgstr ""
+
+msgid "Remove member"
+msgstr ""
+
+msgid "Remove merge request reference"
+msgstr ""
+
+msgid "Remove milestone"
+msgstr ""
+
+msgid "Remove parent epic from an epic"
+msgstr ""
+
+msgid "Remove phone verification exemption"
+msgstr ""
+
+msgid "Remove priority"
+msgstr ""
+
+msgid "Remove reviewer"
+msgstr ""
+
+msgid "Remove runner"
+msgstr ""
+
+msgid "Remove secondary email"
+msgstr ""
+
+msgid "Remove spent time"
+msgstr ""
+
+msgid "Remove summary"
+msgstr ""
+
+msgid "Remove time estimate"
+msgstr ""
+
+msgid "Remove topic avatar"
+msgstr ""
+
+msgid "Remove user"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
+msgid "Remove user from project"
+msgstr ""
+
+msgid "Removed"
+msgstr ""
+
+msgid "Removed %{assignee_text} %{assignee_references}."
+msgstr ""
+
+msgid "Removed %{epic_ref} from child epics."
+msgstr ""
+
+msgid "Removed %{iteration_reference} iteration."
+msgstr ""
+
+msgid "Removed %{label_references} %{label_text}."
+msgstr ""
+
+msgid "Removed %{milestone_reference} milestone."
+msgstr ""
+
+msgid "Removed %{reviewer_text} %{reviewer_references}."
+msgstr ""
+
+msgid "Removed all labels."
+msgstr ""
+
+msgid "Removed an issue from an epic."
+msgstr ""
+
+msgid "Removed group can not be restored!"
+msgstr ""
+
+msgid "Removed link with %{issue_ref}."
+msgstr ""
+
+msgid "Removed parent epic %{epic_ref}."
+msgstr ""
+
+msgid "Removed spent time."
+msgstr ""
+
+msgid "Removed the due date."
+msgstr ""
+
+msgid "Removed time estimate."
+msgstr ""
+
+msgid "Removed upload with id %{id}"
+msgstr ""
+
+msgid "RemovedProjects|No projects pending deletion found"
+msgstr ""
+
+msgid "RemovedProjects|Projects that are pending deletion that you have access to are listed here."
+msgstr ""
+
+msgid "Removes %{assignee_text} %{assignee_references}."
+msgstr ""
+
+msgid "Removes %{epic_ref} from child epics."
+msgstr ""
+
+msgid "Removes %{iteration_reference} iteration."
+msgstr ""
+
+msgid "Removes %{label_references} %{label_text}."
+msgstr ""
+
+msgid "Removes %{milestone_reference} milestone."
+msgstr ""
+
+msgid "Removes %{reviewer_text} %{reviewer_references}."
+msgstr ""
+
+msgid "Removes all labels."
+msgstr ""
+
+msgid "Removes an issue from an epic."
+msgstr ""
+
+msgid "Removes link with %{issue_ref}."
+msgstr ""
+
+msgid "Removes parent epic %{epic_ref}."
+msgstr ""
+
+msgid "Removes spent time."
+msgstr ""
+
+msgid "Removes the due date."
+msgstr ""
+
+msgid "Removes time estimate."
+msgstr ""
+
+msgid "Removing this group also removes all child projects, including archived projects, and their resources."
+msgstr ""
+
+msgid "Rename file"
+msgstr ""
+
+msgid "Rename folder"
+msgstr ""
+
+msgid "Rename/Move"
+msgstr ""
+
+msgid "Render diagrams in your documents using PlantUML."
+msgstr ""
+
+msgid "Render diagrams in your documents using diagrams.net."
+msgstr ""
+
+msgid "Renew subscription"
+msgstr ""
+
+msgid "Reopen"
+msgstr ""
+
+msgid "Reopen %{issuableType}"
+msgstr ""
+
+msgid "Reopen %{issueType}"
+msgstr ""
+
+msgid "Reopen %{noteable}"
+msgstr ""
+
+msgid "Reopen %{workItemType}"
+msgstr ""
+
+msgid "Reopen epic"
+msgstr ""
+
+msgid "Reopen milestone"
+msgstr ""
+
+msgid "Reopen test case"
+msgstr ""
+
+msgid "Reopen this %{quick_action_target}"
+msgstr ""
+
+msgid "Reopened this %{quick_action_target}."
+msgstr ""
+
+msgid "Reopening %{issuableType}..."
+msgstr ""
+
+msgid "Reopening..."
+msgstr ""
+
+msgid "Reopens this %{quick_action_target}."
+msgstr ""
+
+msgid "Replace"
+msgstr ""
+
+msgid "Replace %{name}"
+msgstr ""
+
+msgid "Replace all labels"
+msgstr ""
+
+msgid "Replace audio"
+msgstr ""
+
+msgid "Replace current template with filled in placeholders"
+msgstr ""
+
+msgid "Replace file"
+msgstr ""
+
+msgid "Replace image"
+msgstr ""
+
+msgid "Replace video"
+msgstr ""
+
+msgid "Replaced all labels with %{label_references} %{label_text}."
+msgstr ""
+
+msgid "Replaces the clone URL root."
+msgstr ""
+
+msgid "Reply"
+msgstr ""
+
+msgid "Reply by email"
+msgstr ""
+
+msgid "Reply internally"
+msgstr ""
+
+msgid "Reply to comment"
+msgstr ""
+
+msgid "Reply to this email directly or %{view_it_on_gitlab}."
+msgstr ""
+
+msgid "Reply…"
+msgstr ""
+
+msgid "Report Finding not found"
+msgstr ""
+
+msgid "Report abuse"
+msgstr ""
+
+msgid "Report abuse to administrator"
+msgstr ""
+
+msgid "Report and manage standards adherence, violations, and compliance frameworks for the group."
+msgstr ""
+
+msgid "Report couldn't be prepared."
+msgstr ""
+
+msgid "Report for the scan has been removed from the database."
+msgstr ""
+
+msgid "Report version not provided, %{report_type} report type supports versions: %{supported_schema_versions}. GitLab will attempt to validate this report against the earliest supported versions of this report type, to show all the errors but will not ingest the report"
+msgstr ""
+
+msgid "Report your license usage data to GitLab"
+msgstr ""
+
+msgid "ReportAbuse|Add another link"
+msgstr ""
+
+msgid "ReportAbuse|Link to spam"
+msgstr ""
+
+msgid "ReportAbuse|Report abuse to administrator"
+msgstr ""
+
+msgid "ReportAbuse|Screenshot"
+msgstr ""
+
+msgid "ReportAbuse|Screenshot of abuse"
+msgstr ""
+
+msgid "ReportAbuse|Something else."
+msgstr ""
+
+msgid "ReportAbuse|They're being offensive or abusive."
+msgstr ""
+
+msgid "ReportAbuse|They're crypto mining."
+msgstr ""
+
+msgid "ReportAbuse|They're phishing."
+msgstr ""
+
+msgid "ReportAbuse|They're posting malware."
+msgstr ""
+
+msgid "ReportAbuse|They're posting personal information or credentials."
+msgstr ""
+
+msgid "ReportAbuse|They're posting spam."
+msgstr ""
+
+msgid "ReportAbuse|They're violating a copyright or trademark."
+msgstr ""
+
+msgid "ReportAbuse|URL of this user posting spam"
+msgstr ""
+
+msgid "ReportAbuse|Why are you reporting this user?"
+msgstr ""
+
+msgid "Reported %{timeAgo} by %{reportedBy}"
+msgstr ""
+
+msgid "Reporter"
+msgstr ""
+
+msgid "Reporting"
+msgstr ""
+
+msgid "Reports|%{combinedString} and %{resolvedString}"
+msgstr ""
+
+msgid "Reports|%{recentlyFailed} out of %{failed} failed test has failed more than once in the last 14 days"
+msgstr ""
+
+msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more than once in the last 14 days"
+msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
+msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reports|Accessibility scanning detected no issues for the source branch only"
+msgstr ""
+
+msgid "Reports|Accessibility scanning failed loading results"
+msgstr ""
+
+msgid "Reports|Accessibility scanning results are being parsed"
+msgstr ""
+
+msgid "Reports|Actions"
+msgstr ""
+
+msgid "Reports|An error occurred while loading %{name} results"
+msgstr ""
+
+msgid "Reports|An error occurred while loading report"
+msgstr ""
+
+msgid "Reports|Base report parsing error:"
+msgstr ""
+
+msgid "Reports|Copy failed test names to run locally"
+msgstr ""
+
+msgid "Reports|Copy failed tests"
+msgstr ""
+
+msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
+msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
+msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reports|Fixed"
+msgstr ""
+
+msgid "Reports|Full report"
+msgstr ""
+
+msgid "Reports|Head report parsing error:"
+msgstr ""
+
+msgid "Reports|Identifier"
+msgstr ""
+
+msgid "Reports|Metrics report scanning detected no new changes"
+msgstr ""
+
+msgid "Reports|Metrics reports are loading"
+msgstr ""
+
+msgid "Reports|Metrics reports changed on %{numberOfChanges} %{pointsString}"
+msgstr ""
+
+msgid "Reports|Metrics reports did not change"
+msgstr ""
+
+msgid "Reports|Metrics reports failed loading results"
+msgstr ""
+
+msgid "Reports|Metrics reports failed to load results"
+msgstr ""
+
+msgid "Reports|Metrics reports: %{strong_start}%{numberOfChanges}%{strong_end} %{changes}"
+msgstr ""
+
+msgid "Reports|New"
+msgstr ""
+
+msgid "Reports|Scanner"
+msgstr ""
+
+msgid "Reports|Severity"
+msgstr ""
+
+msgid "Reports|Test summary"
+msgstr ""
+
+msgid "Reports|Test summary failed to load results"
+msgstr ""
+
+msgid "Reports|Test summary results are loading"
+msgstr ""
+
+msgid "Reports|Tool"
+msgstr ""
+
+msgid "Reports|Vulnerability"
+msgstr ""
+
+msgid "Reports|Vulnerability Name"
+msgstr ""
+
+msgid "Reports|metrics report"
+msgstr ""
+
+msgid "Repositories"
+msgstr ""
+
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Analyze repositories for projects in %{groupName}. Data doesn't include projects in subgroups. %{learnMoreLink}."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Average Coverage by Job"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Average coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Average test coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Code Coverage: %{averageCoverage}"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Coverage Jobs"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|In the last day, %{metricValue} job has code coverage."
+msgid_plural "RepositoriesAnalytics|In the last day, %{metricValue} jobs have code coverage."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "RepositoriesAnalytics|In the last day, %{metricValue} project in %{groupName} has code coverage enabled."
+msgid_plural "RepositoriesAnalytics|In the last day, %{metricValue} projects in %{groupName} have code coverage enabled."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "RepositoriesAnalytics|In the last day, on average, %{metricValue} of all jobs are covered."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Jobs with Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Jobs with Coverage: %{coverageCount}"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Last Update"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Last updated %{timeAgo}"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Latest test coverage results"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Latest test coverage results for all projects in %{groupName} (excluding projects in subgroups)."
+msgstr ""
+
+msgid "RepositoriesAnalytics|No test coverage to display"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Please select a project or multiple projects to display their most recent test coverage data."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Please select projects to display."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Projects with Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Projects with Coverage: %{projectCount}"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
+msgid "Repository"
+msgstr ""
+
+msgid "Repository Analytics"
+msgstr ""
+
+msgid "Repository Graph"
+msgstr ""
+
+msgid "Repository Settings"
+msgstr ""
+
+msgid "Repository already read-only"
+msgstr ""
+
+msgid "Repository analytics"
+msgstr ""
+
+msgid "Repository by URL"
+msgstr ""
+
+msgid "Repository check"
+msgstr ""
+
+msgid "Repository check was triggered."
+msgstr ""
+
+msgid "Repository checks"
+msgstr ""
+
+msgid "Repository cleanup"
+msgstr ""
+
+msgid "Repository cleanup has started. You will receive an email once the cleanup operation is complete."
+msgstr ""
+
+msgid "Repository clone URL"
+msgstr ""
+
+msgid "Repository files count over the limit"
+msgstr ""
+
+msgid "Repository graph"
+msgstr ""
+
+msgid "Repository has an invalid default branch name."
+msgstr ""
+
+msgid "Repository has more than one branch."
+msgstr ""
+
+msgid "Repository has no locks."
+msgstr ""
+
+msgid "Repository has tags."
+msgstr ""
+
+msgid "Repository maintenance"
+msgstr ""
+
+msgid "Repository mirroring"
+msgstr ""
+
+msgid "Repository mirroring configuration"
+msgstr ""
+
+msgid "Repository mirroring has been paused due to too many failed attempts. It can be resumed by a project maintainer or owner."
+msgstr ""
+
+msgid "Repository must contain at least 1 file."
+msgstr ""
+
+msgid "Repository size is above the limit."
+msgstr ""
+
+msgid "Repository size limit (MiB)"
+msgstr ""
+
+msgid "Repository storage"
+msgstr ""
+
+msgid "Repository update events"
+msgstr ""
+
+msgid "Repository usage recalculation started"
+msgstr ""
+
+msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
+msgstr ""
+
+msgid "Request"
+msgstr ""
+
+msgid "Request Access"
+msgstr ""
+
+msgid "Request Headers"
+msgstr ""
+
+msgid "Request a new one"
+msgstr ""
+
+msgid "Request data is too large"
+msgstr ""
+
+msgid "Request details"
+msgstr ""
+
+msgid "Request review from"
+msgstr ""
+
+msgid "Request time"
+msgstr ""
+
+msgid "Request to link SAML account must be authorized"
+msgstr ""
+
+msgid "Requested"
+msgstr ""
+
+msgid "Requested %{time_ago}"
+msgstr ""
+
+msgid "Requested design version does not exist."
+msgstr ""
+
+msgid "Requested review"
+msgstr ""
+
+msgid "Requested states are invalid"
+msgstr ""
+
+msgid "Requests"
+msgstr ""
+
+msgid "Requests for pages at %{code_start}%{help_text_url}%{code_end} redirect to the URL. The destination must meet certain requirements. %{docs_link_start}Learn more.%{docs_link_end}"
+msgstr ""
+
+msgid "Requests per period"
+msgstr ""
+
+msgid "Require additional authentication for administrative tasks."
+msgstr ""
+
+msgid "Required approvals (%{approvals_given} given)"
+msgstr ""
+
+msgid "Required approvals (%{approvals_given} given, you've approved)"
+msgstr ""
+
+msgid "Required in this project."
+msgstr ""
+
+msgid "Required only if you are not using role instance credentials."
+msgstr ""
+
+msgid "Requirement"
+msgstr ""
+
+msgid "Requirement %{reference} has been added"
+msgstr ""
+
+msgid "Requirement %{reference} has been archived"
+msgstr ""
+
+msgid "Requirement %{reference} has been reopened"
+msgstr ""
+
+msgid "Requirement %{reference} has been updated"
+msgstr ""
+
+msgid "Requirements"
+msgstr ""
+
+msgid "Requirements can be based on users, stakeholders, system, software, or anything else you find important to capture."
+msgstr ""
+
+msgid "Requirement|Legacy requirement ID: %{legacyId}"
+msgstr ""
+
+msgid "Requirement|Legacy requirement IDs are being deprecated. Update your links to reference this item's new ID %{id}. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "Requirement|Requirements have become work items and the legacy requirement IDs are being deprecated. Update your links to reference this item's new ID %{id}. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "Requires %d approval from eligible users."
+msgid_plural "Requires %d approvals from eligible users."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Requires %{count} approval from %{names}."
+msgid_plural "Requires %{count} approvals from %{names}."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Requires a verified GitLab email address."
+msgstr ""
+
+msgid "Requires you to deploy or set up cloud-hosted Sentry."
+msgstr ""
+
+msgid "Requires your primary GitLab email address."
+msgstr ""
+
+msgid "Resend"
+msgstr ""
+
+msgid "Resend Request"
+msgstr ""
+
+msgid "Resend confirmation e-mail"
+msgstr ""
+
+msgid "Resend confirmation email"
+msgstr ""
+
+msgid "Resend invite"
+msgstr ""
+
+msgid "Resend it"
+msgstr ""
+
+msgid "Resend unlock instructions"
+msgstr ""
+
+msgid "Reset"
+msgstr ""
+
+msgid "Reset error tracking access token"
+msgstr ""
+
+msgid "Reset file"
+msgstr ""
+
+msgid "Reset filters"
+msgstr ""
+
+msgid "Reset health check access token"
+msgstr ""
+
+msgid "Reset password"
+msgstr ""
+
+msgid "Reset registration token"
+msgstr ""
+
+msgid "Reset template"
+msgstr ""
+
+msgid "Reset to project defaults"
+msgstr ""
+
+msgid "Resolve"
+msgstr ""
+
+msgid "Resolve all with new issue"
+msgstr ""
+
+msgid "Resolve any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
+msgstr ""
+
+msgid "Resolve conflicts"
+msgstr ""
+
+msgid "Resolve conflicts on source branch"
+msgstr ""
+
+msgid "Resolve locally"
+msgstr ""
+
+msgid "Resolve these conflicts, or ask someone with write access to this repository to resolve them locally."
+msgstr ""
+
+msgid "Resolve thread"
+msgstr ""
+
+msgid "Resolved"
+msgstr ""
+
+msgid "Resolved 1 discussion."
+msgstr ""
+
+msgid "Resolved all discussions."
+msgstr ""
+
+msgid "Resolved by"
+msgstr ""
+
+msgid "Resolved by %{name}"
+msgstr ""
+
+msgid "Resource link added"
+msgstr ""
+
+msgid "Response"
+msgstr ""
+
+msgid "Response didn't include `service_desk_address`"
+msgstr ""
+
+msgid "Response generated by AI"
+msgstr ""
+
+msgid "Response initiated"
+msgstr ""
+
+msgid "Response metrics (AWS ELB)"
+msgstr ""
+
+msgid "Response metrics (Custom)"
+msgstr ""
+
+msgid "Response metrics (HA Proxy)"
+msgstr ""
+
+msgid "Response metrics (NGINX Ingress VTS)"
+msgstr ""
+
+msgid "Response metrics (NGINX Ingress)"
+msgstr ""
+
+msgid "Response metrics (NGINX)"
+msgstr ""
+
+msgid "Response text"
+msgstr ""
+
+msgid "Restart GitLab to apply changes."
+msgstr ""
+
+msgid "Restart Terminal"
+msgstr ""
+
+msgid "Restore"
+msgstr ""
+
+msgid "Restore group"
+msgstr ""
+
+msgid "Restore project"
+msgstr ""
+
+msgid "Restoring projects"
+msgstr ""
+
+msgid "Restoring the group will prevent the group, its subgroups and projects from being removed on this date."
+msgstr ""
+
+msgid "Restoring the project will prevent the project from being removed on this date and restore people's ability to make changes to it."
+msgstr ""
+
+msgid "Restrict access by IP address"
+msgstr ""
+
+msgid "Restrict membership by email domain"
+msgstr ""
+
+msgid "Restrict projects for this runner"
+msgstr ""
+
+msgid "Restricted shift times are not available for hourly shifts"
+msgstr ""
+
+msgid "Results limit reached"
+msgstr ""
+
+msgid "Resume"
+msgstr ""
+
+msgid "Retry"
+msgstr ""
+
+msgid "Retry all failed or cancelled jobs"
+msgstr ""
+
+msgid "Retry downstream pipeline"
+msgstr ""
+
+msgid "Retry job"
+msgstr ""
+
+msgid "Retry migration"
+msgstr ""
+
+msgid "Retry this job"
+msgstr ""
+
+msgid "Retry this job in order to create the necessary resources."
+msgstr ""
+
+msgid "Retry verification"
+msgstr ""
+
+msgid "Reveal value"
+msgid_plural "Reveal values"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reveal values"
+msgstr ""
+
+msgid "Revert this commit"
+msgstr ""
+
+msgid "Revert this merge request"
+msgstr ""
+
+msgid "Review"
+msgstr ""
+
+msgid "Review App|View app"
+msgstr ""
+
+msgid "Review App|View latest app"
+msgstr ""
+
+msgid "Review changes"
+msgstr ""
+
+msgid "Review requests"
+msgstr ""
+
+msgid "Review the changes locally."
+msgstr ""
+
+msgid "Review the process for configuring service providers in your identity provider — in this case, GitLab is the \"service provider\" or \"relying party\"."
+msgstr ""
+
+msgid "Review the target project before submitting to avoid exposing %{source} changes."
+msgstr ""
+
+msgid "Review time"
+msgstr ""
+
+msgid "Review time is the amount of time since the first comment in a merge request."
+msgstr ""
+
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewers"
+msgstr ""
+
+msgid "Reviewing"
+msgstr ""
+
+msgid "Reviewing (merge request !%{mergeRequestId})"
+msgstr ""
+
+msgid "Revoke"
+msgstr ""
+
+msgid "Revoke Key"
+msgstr ""
+
+msgid "Revoked"
+msgstr ""
+
+msgid "Revoked access token %{access_token_name}!"
+msgstr ""
+
+msgid "Revoked impersonation token %{token_name}!"
+msgstr ""
+
+msgid "Revoked personal access token %{personal_access_token_name}!"
+msgstr ""
+
+msgid "RightSidebar|Copy email address"
+msgstr ""
+
+msgid "RightSidebar|Issue email"
+msgstr ""
+
+msgid "Roadmap"
+msgstr ""
+
+msgid "Roadmap settings"
+msgstr ""
+
+msgid "Roadmap view"
+msgstr ""
+
+msgid "Role"
+msgstr ""
+
+msgid "Roles and Permissions"
+msgstr ""
+
+msgid "Rollback"
+msgstr ""
+
+msgid "Root cause analysis"
+msgstr ""
+
+msgid "Root cause analysis is a feature that analyzes your logs to determine why a job may have failed and the potential ways to fix it. To generate this analysis, we may share information in your job logs with %{linkStart}Third-Party AI providers%{linkEnd}. Before initiating this analysis, please do not include in your logs any information that could impact the security or privacy of your account."
+msgstr ""
+
+msgid "Ruby"
+msgstr ""
+
+msgid "Rule name"
+msgstr ""
+
+msgid "Rule name is already taken."
+msgstr ""
+
+msgid "Rules that define what git pushes are accepted for a project in this group. All newly created projects in this group will use these settings."
+msgstr ""
+
+msgid "Rules that define what git pushes are accepted for a project. All newly created projects will use these settings."
+msgstr ""
+
+msgid "Run %{code_start}git fsck%{code_end} periodically in all project and wiki repositories to look for silent disk corruption issues."
+msgstr ""
+
+msgid "Run CI/CD pipelines for external repositories"
+msgstr ""
+
+msgid "Run CI/CD pipelines with Jenkins when you push to a repository, or when a merge request is created, updated, or merged. %{docs_link}"
+msgstr ""
+
+msgid "Run CI/CD pipelines with Jenkins."
+msgstr ""
+
+msgid "Run again"
+msgstr ""
+
+msgid "Run housekeeping"
+msgstr ""
+
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
+msgid "Run job"
+msgstr ""
+
+msgid "Run manual or delayed jobs"
+msgstr ""
+
+msgid "Run tests against your code live using the Web Terminal"
+msgstr ""
+
+msgid "Run untagged jobs"
+msgstr ""
+
+msgid "Runner"
+msgstr ""
+
+msgid "Runner API"
+msgstr ""
+
+msgid "Runner tokens"
+msgstr ""
+
+msgid "Runner was not updated."
+msgstr ""
+
+msgid "Runner was successfully updated."
+msgstr ""
+
+msgid "RunnerTags|No matching results"
+msgstr ""
+
+msgid "RunnerTags|No tags exist"
+msgstr ""
+
+msgid "RunnerTags|Select runner tags"
+msgstr ""
+
+msgid "Runners"
+msgstr ""
+
+msgid "Runners are processes that pick up and execute CI/CD jobs for GitLab."
+msgstr ""
+
+msgid "Runners page."
+msgstr ""
+
+msgid "Runners|%d selected runner deleted"
+msgid_plural "Runners|%d selected runners deleted"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|%{count} runners in this group"
+msgstr ""
+
+msgid "Runners|%{highlightStart}%{duration}%{highlightEnd} second"
+msgid_plural "Runners|%{highlightStart}%{duration}%{highlightEnd} seconds"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|%{linkStart}Create a new runner%{linkEnd} to get started."
+msgstr ""
+
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
+msgid "Runners|%{percentage} spot."
+msgstr ""
+
+msgid "Runners|%{strongStart}%{count}%{strongEnd} runner selected"
+msgid_plural "Runners|%{strongStart}%{count}%{strongEnd} runners selected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|%{strongStart}%{count}%{strongEnd} runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
+msgid_plural "Runners|%{strongStart}%{count}%{strongEnd} runners will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|75th percentile"
+msgstr ""
+
+msgid "Runners|90th percentile"
+msgstr ""
+
+msgid "Runners|99th percentile"
+msgstr ""
+
+msgid "Runners|A capacity of 1 enables warm HA through Auto Scaling group re-spawn. A capacity of 2 enables hot HA because the service is available even when a node is lost. A capacity of 3 or more enables hot HA and manual scaling of runner fleet."
+msgstr ""
+
+msgid "Runners|A new version is available"
+msgstr ""
+
+msgid "Runners|A periodic background task deletes runners that haven't contacted GitLab in more than %{elapsedTime}. Only runners registered in this group are deleted. Runners in subgroups and projects are not. %{linkStart}Can I view how many runners were deleted?%{linkEnd}"
+msgstr ""
+
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Active runners"
+msgstr ""
+
+msgid "Runners|Add notes such as the runner owner or what it should be used for."
+msgstr ""
+
+msgid "Runners|Add tags for the types of jobs the runner processes to ensure that the runner only runs jobs that you intend it to. %{helpLinkStart}Learn more.%{helpLinkEnd}"
+msgstr ""
+
+msgid "Runners|Add your feedback to this issue"
+msgstr ""
+
+msgid "Runners|Admin area › Runners"
+msgstr ""
+
+msgid "Runners|Administrator"
+msgstr ""
+
+msgid "Runners|All"
+msgstr ""
+
+msgid "Runners|All group runners that have not contacted GitLab in more than %{elapsedTime} are deleted permanently. This task runs periodically in the background."
+msgstr ""
+
+msgid "Runners|Amazon Linux 2 Docker HA with manual scaling and optional scheduling. %{percentage} spot."
+msgstr ""
+
+msgid "Runners|Amazon Linux 2 Docker HA with manual scaling and optional scheduling. Non-spot."
+msgstr ""
+
+msgid "Runners|An error has occurred fetching instructions"
+msgstr ""
+
+msgid "Runners|An error occurred while creating the runner. Please try again."
+msgstr ""
+
+msgid "Runners|An error occurred while deleting. Some runners may not have been deleted."
+msgstr ""
+
+msgid "Runners|An upgrade is available for this runner"
+msgstr ""
+
+msgid "Runners|An upgrade is recommended for this runner"
+msgstr ""
+
+msgid "Runners|Arch/Platform"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Are you sure you want to disable shared runners for %{groupName}?"
+msgstr ""
+
+msgid "Runners|Assigned Group"
+msgstr ""
+
+msgid "Runners|Assigned Projects (%{projectCount})"
+msgstr ""
+
+msgid "Runners|Assigned project runners"
+msgstr ""
+
+msgid "Runners|Associated with one or more projects"
+msgstr ""
+
+msgid "Runners|Available"
+msgstr ""
+
+msgid "Runners|Available shared runners: %{count}"
+msgstr ""
+
+msgid "Runners|Available to all projects"
+msgstr ""
+
+msgid "Runners|Available to all projects and subgroups in the group"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Capacity of 1 enables warm HA through Auto Scaling group re-spawn. Capacity of 2 enables hot HA because the service is available even when a node is lost. Capacity of 3 or more enables hot HA and manual scaling of runner fleet."
+msgstr ""
+
+msgid "Runners|Checkbox"
+msgstr ""
+
+msgid "Runners|Choose an executor when prompted by the command line. Executors run builds in different environments. %{linkStart}Not sure which one to select?%{linkEnd}"
+msgstr ""
+
+msgid "Runners|Choose your preferred GitLab Runner"
+msgstr ""
+
+msgid "Runners|Clear selection"
+msgstr ""
+
+msgid "Runners|Command to register runner"
+msgstr ""
+
+msgid "Runners|Configuration"
+msgstr ""
+
+msgid "Runners|Containers"
+msgstr ""
+
+msgid "Runners|Copy and paste the following command into your command line to register the runner."
+msgstr ""
+
+msgid "Runners|Copy instructions"
+msgstr ""
+
+msgid "Runners|Copy registration token"
+msgstr ""
+
+msgid "Runners|Create a group runner"
+msgstr ""
+
+msgid "Runners|Create a group runner to generate a command that registers the runner with all its configurations."
+msgstr ""
+
+msgid "Runners|Create a project runner"
+msgstr ""
+
+msgid "Runners|Create a project runner to generate a command that registers the runner with all its configurations."
+msgstr ""
+
+msgid "Runners|Create an instance runner"
+msgstr ""
+
+msgid "Runners|Create an instance runner to generate a command that registers the runner with all its configurations."
+msgstr ""
+
+msgid "Runners|Create runner"
+msgstr ""
+
+msgid "Runners|Created %{timeAgo}"
+msgstr ""
+
+msgid "Runners|Created %{timeAgo} by %{avatar}"
+msgstr ""
+
+msgid "Runners|Delete"
+msgstr ""
+
+msgid "Runners|Delete %d runner"
+msgid_plural "Runners|Delete %d runners"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|Delete %{count} runners?"
+msgstr ""
+
+msgid "Runners|Delete runner"
+msgstr ""
+
+msgid "Runners|Delete runner %{name}?"
+msgstr ""
+
+msgid "Runners|Delete selected"
+msgstr ""
+
+msgid "Runners|Deploy GitLab Runner in AWS"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Details"
+msgstr ""
+
+msgid "Runners|Don't see what you are looking for? See the full list of options, including a fully customizable option %{linkStart}here%{linkEnd}."
+msgstr ""
+
+msgid "Runners|Download and install binary"
+msgstr ""
+
+msgid "Runners|Download latest binary"
+msgstr ""
+
+msgid "Runners|Edit your search and try again"
+msgstr ""
+
+msgid "Runners|Enable stale runner cleanup"
+msgstr ""
+
+msgid "Runners|Enable stale runner cleanup?"
+msgstr ""
+
+msgid "Runners|Enter the number of seconds."
+msgstr ""
+
+msgid "Runners|Environment"
+msgstr ""
+
+msgid "Runners|Executor"
+msgstr ""
+
+msgid "Runners|Existing runners are not affected. To permit runner registration for all groups, enable this setting in the Admin Area in Settings &gt; CI/CD."
+msgstr ""
+
+msgid "Runners|Existing runners are not affected. To permit runner registration for all projects, enable this setting in the Admin Area in Settings &gt; CI/CD."
+msgstr ""
+
+msgid "Runners|Failed adding runner to project"
+msgstr ""
+
+msgid "Runners|Fetch GitLab Runner release version data from GitLab.com"
+msgstr ""
+
+msgid "Runners|Filter projects"
+msgstr ""
+
+msgid "Runners|Fleet dashboard"
+msgstr ""
+
+msgid "Runners|Get started with runners"
+msgstr ""
+
+msgid "Runners|GitLab Runner must be installed before you can register a runner. %{linkStart}How do I install GitLab Runner?%{linkEnd}"
+msgstr ""
+
+msgid "Runners|Go to %{groupLink} to enable them."
+msgstr ""
+
+msgid "Runners|Go to runners page"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|Group area › Runners"
+msgstr ""
+
+msgid "Runners|How do runners pick up jobs?"
+msgstr ""
+
+msgid "Runners|How do we upgrade GitLab runner?"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Idle"
+msgstr ""
+
+msgid "Runners|If both settings are disabled, new runners cannot be registered."
+msgstr ""
+
+msgid "Runners|In GitLab Runner 15.6, the use of registration tokens and runner parameters in the 'register' command was deprecated. They have been replaced by authentication tokens. %{linkStart}How does this impact my current registration workflow?%{linkEnd}"
+msgstr ""
+
+msgid "Runners|Install GitLab Runner"
+msgstr ""
+
+msgid "Runners|Install a runner"
+msgstr ""
+
+msgid "Runners|Instance"
+msgstr ""
+
+msgid "Runners|Instance: Median job queued time"
+msgstr ""
+
+msgid "Runners|Jobs"
+msgstr ""
+
+msgid "Runners|Jobs in projects you have access to."
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Last contact: %{timeAgo}"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maintenance note"
+msgstr ""
+
+msgid "Runners|Make sure the runner is online and available to run jobs (not paused). Jobs display here when the runner picks them up."
+msgstr ""
+
+msgid "Runners|Manually verify that the runner is available to pick up jobs."
+msgstr ""
+
+msgid "Runners|Maximum amount of time the runner can run before it terminates. If a project has a shorter job timeout period, the job timeout period of the instance runner is used instead."
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Median"
+msgstr ""
+
+msgid "Runners|Members of the %{type} can register runners"
+msgstr ""
+
+msgid "Runners|Minor version upgrades are available."
+msgstr ""
+
+msgid "Runners|Most recent failures"
+msgstr ""
+
+msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Never contacted"
+msgstr ""
+
+msgid "Runners|Never contacted:"
+msgstr ""
+
+msgid "Runners|Never expires"
+msgstr ""
+
+msgid "Runners|New"
+msgstr ""
+
+msgid "Runners|New group runner"
+msgstr ""
+
+msgid "Runners|New group runners can be registered"
+msgstr ""
+
+msgid "Runners|New instance runner"
+msgstr ""
+
+msgid "Runners|New project runner"
+msgstr ""
+
+msgid "Runners|New project runners can be registered"
+msgstr ""
+
+msgid "Runners|New registration token generated!"
+msgstr ""
+
+msgid "Runners|New runner"
+msgstr ""
+
+msgid "Runners|No description"
+msgstr ""
+
+msgid "Runners|No results found"
+msgstr ""
+
+msgid "Runners|No spot. Default choice for Windows Shell executor."
+msgstr ""
+
+msgid "Runners|No spot. This is the default choice for Linux Docker executor."
+msgstr ""
+
+msgid "Runners|No, keep shared runners enabled"
+msgstr ""
+
+msgid "Runners|Not accepting jobs"
+msgstr ""
+
+msgid "Runners|Official runner version data is periodically fetched from GitLab.com to determine whether the runners need upgrades."
+msgstr ""
+
+msgid "Runners|Offline"
+msgstr ""
+
+msgid "Runners|Offline:"
+msgstr ""
+
+msgid "Runners|Online"
+msgstr ""
+
+msgid "Runners|Online:"
+msgstr ""
+
+msgid "Runners|Only administrators can view this."
+msgstr ""
+
+msgid "Runners|Operating systems"
+msgstr ""
+
+msgid "Runners|Owner"
+msgstr ""
+
+msgid "Runners|Pause from accepting jobs"
+msgstr ""
+
+msgid "Runners|Paused"
+msgstr ""
+
+msgid "Runners|Permanently delete %d runner"
+msgid_plural "Runners|Permanently delete %d runners"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|Permanently delete runner"
+msgid_plural "Runners|Permanently delete %d runners"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Project"
+msgstr ""
+
+msgid "Runners|Project runners"
+msgstr ""
+
+msgid "Runners|Project › CI/CD Settings › Runners"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Recommended"
+msgstr ""
+
+msgid "Runners|Register"
+msgstr ""
+
+msgid "Runners|Register \"%{runnerDescription}\" runner"
+msgstr ""
+
+msgid "Runners|Register a group runner"
+msgstr ""
+
+msgid "Runners|Register a project runner"
+msgstr ""
+
+msgid "Runners|Register a runner"
+msgstr ""
+
+msgid "Runners|Register an instance runner"
+msgstr ""
+
+msgid "Runners|Register as many runners as you want. You can register runners as separate users, on separate servers, and on your local machine."
+msgstr ""
+
+msgid "Runners|Register runner"
+msgstr ""
+
+msgid "Runners|Registration token"
+msgstr ""
+
+msgid "Runners|Registration token copied!"
+msgstr ""
+
+msgid "Runners|Reset token"
+msgstr ""
+
+msgid "Runners|Resume accepting jobs"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Runner"
+msgstr ""
+
+msgid "Runners|Runner #%{runner_id}"
+msgstr ""
+
+msgid "Runners|Runner %{name} was deleted"
+msgstr ""
+
+msgid "Runners|Runner %{runnerName} failed to delete"
+msgstr ""
+
+msgid "Runners|Runner Registration"
+msgstr ""
+
+msgid "Runners|Runner Registration token"
+msgstr ""
+
+msgid "Runners|Runner assigned to project."
+msgstr ""
+
+msgid "Runners|Runner authentication token expiration"
+msgstr ""
+
+msgid "Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired."
+msgstr ""
+
+msgid "Runners|Runner created."
+msgstr ""
+
+msgid "Runners|Runner description"
+msgstr ""
+
+msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
+msgstr ""
+
+msgid "Runners|Runner has never contacted GitLab (when you register a runner, use %{codeStart}gitlab-runner run%{codeEnd} to bring it online)"
+msgstr ""
+
+msgid "Runners|Runner has never contacted this instance"
+msgstr ""
+
+msgid "Runners|Runner has not contacted GitLab in more than %{elapsedTime}"
+msgstr ""
+
+msgid "Runners|Runner is locked and available for currently assigned projects only. Only administrators can change the assigned projects."
+msgstr ""
+
+msgid "Runners|Runner is offline; last contact was %{runner_contact} ago"
+msgstr ""
+
+msgid "Runners|Runner is offline; last contact was %{timeAgo}"
+msgstr ""
+
+msgid "Runners|Runner is online; last contact was %{runner_contact} ago"
+msgstr ""
+
+msgid "Runners|Runner is online; last contact was %{timeAgo}"
+msgstr ""
+
+msgid "Runners|Runner is stale; it has never contacted this instance"
+msgstr ""
+
+msgid "Runners|Runner is stale; last contact was %{runner_contact} ago"
+msgstr ""
+
+msgid "Runners|Runner is stale; last contact was %{timeAgo}"
+msgstr ""
+
+msgid "Runners|Runner performance insights"
+msgstr ""
+
+msgid "Runners|Runner registration"
+msgstr ""
+
+msgid "Runners|Runner statuses"
+msgstr ""
+
+msgid "Runners|Runner unassigned from project."
+msgstr ""
+
+msgid "Runners|Runner version management"
+msgstr ""
+
+msgid "Runners|Runners"
+msgstr ""
+
+msgid "Runners|Runners are either:"
+msgstr ""
+
+msgid "Runners|Runners are grouped when they have the same authentication token. This happens when you re-use a runner configuration in more than one runner manager. %{linkStart}How does this work?%{linkEnd}"
+msgstr ""
+
+msgid "Runners|Runners are the agents that run your CI/CD jobs."
+msgstr ""
+
+msgid "Runners|Runners performance"
+msgstr ""
+
+msgid "Runners|Running"
+msgstr ""
+
+msgid "Runners|Running Jobs"
+msgstr ""
+
+msgid "Runners|Runs untagged jobs"
+msgstr ""
+
+msgid "Runners|Search description..."
+msgstr ""
+
+msgid "Runners|Security or compatibility upgrades are recommended."
+msgstr ""
+
+msgid "Runners|See more %{linkStart}installation methods and architectures%{linkEnd}."
+msgstr ""
+
+msgid "Runners|Select all"
+msgstr ""
+
+msgid "Runners|Select platform specifications to install GitLab Runner."
+msgstr ""
+
+msgid "Runners|Select projects to assign to this runner"
+msgstr ""
+
+msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
+msgstr ""
+
+msgid "Runners|Shared runners are disabled in the group settings."
+msgstr ""
+
+msgid "Runners|Shared runners are disabled."
+msgstr ""
+
+msgid "Runners|Shared runners will be disabled for all projects and subgroups in this group. If you proceed, you must manually re-enable shared runners in the settings of each project and subgroup."
+msgstr ""
+
+msgid "Runners|Show only inherited"
+msgstr ""
+
+msgid "Runners|Show runner installation and registration instructions"
+msgstr ""
+
+msgid "Runners|Show runner installation instructions"
+msgstr ""
+
+msgid "Runners|Something went wrong while deleting. Please refresh the page to try again."
+msgstr ""
+
+msgid "Runners|Something went wrong while fetching runner data."
+msgstr ""
+
+msgid "Runners|Something went wrong while fetching the tags suggestions"
+msgstr ""
+
+msgid "Runners|Stale"
+msgstr ""
+
+msgid "Runners|Stale:"
+msgstr ""
+
+msgid "Runners|Status"
+msgstr ""
+
+msgid "Runners|Step 1"
+msgstr ""
+
+msgid "Runners|Step 2"
+msgstr ""
+
+msgid "Runners|Step 3 (optional)"
+msgstr ""
+
+msgid "Runners|Still using registration tokens?"
+msgstr ""
+
+msgid "Runners|Stop the runner from accepting new jobs."
+msgstr ""
+
+msgid "Runners|Support for registration tokens is deprecated"
+msgstr ""
+
+msgid "Runners|System ID"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Tags control which type of jobs a runner can handle. By tagging a runner, you make sure shared runners only handle the jobs they are equipped to run."
+msgstr ""
+
+msgid "Runners|The %{boldStart}runner token%{boldEnd} %{token} displays %{boldStart}only for a short time%{boldEnd}, and is stored in the %{codeStart}config.toml%{codeEnd} after you register the runner. It will not be visible once the runner is registered."
+msgstr ""
+
+msgid "Runners|The %{boldStart}runner token%{boldEnd} is no longer visible, it is stored in the %{codeStart}config.toml%{codeEnd} if you have registered the runner."
+msgstr ""
+
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
+msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
+msgid_plural "Runners|%d runners will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|The time it takes for an instance runner to pick up a job. Jobs waiting for runners are in the pending state. %{linkStart}How is this calculated?%{linkEnd}"
+msgstr ""
+
+msgid "Runners|The unique ID for each runner that uses this configuration."
+msgstr ""
+
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
+msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
+msgstr ""
+
+msgid "Runners|These runners are assigned to this project."
+msgstr ""
+
+msgid "Runners|This group currently has 1 stale runner."
+msgid_plural "Runners|This group currently has %d stale runners."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Runners|This group currently has no stale runners."
+msgstr ""
+
+msgid "Runners|This may not be needed if you manage your runner as a %{linkStart}system or user service%{linkEnd}."
+msgstr ""
+
+msgid "Runners|This registration process is not supported in GitLab Runner 15.9 or earlier and only available as an experimental feature in GitLab Runner 15.10 and 15.11. You should upgrade to %{linkStart}GitLab Runner 16.0%{linkEnd} or later to use a stable version of this registration process."
+msgstr ""
+
+msgid "Runners|This registration process is only supported in GitLab Runner 15.10 or later"
+msgstr ""
+
+msgid "Runners|This runner has not run any jobs"
+msgstr ""
+
+msgid "Runners|This runner has not run any jobs."
+msgstr ""
+
+msgid "Runners|This runner is associated with specific projects."
+msgstr ""
+
+msgid "Runners|This runner is available to all projects and subgroups in a group."
+msgstr ""
+
+msgid "Runners|This runner is outdated, an upgrade is recommended"
+msgstr ""
+
+msgid "Runners|To install Runner in Kubernetes follow the instructions described in the GitLab documentation."
+msgstr ""
+
+msgid "Runners|To install Runner in a container follow the instructions described in the GitLab documentation"
+msgstr ""
+
+msgid "Runners|To register new runners, contact your administrator."
+msgstr ""
+
+msgid "Runners|To register them, go to the %{link_start}group's Runners page%{link_end}."
+msgstr ""
+
+msgid "Runners|To view the runner, go to %{runnerListName}."
+msgstr ""
+
+msgid "Runners|Token expiry"
+msgstr ""
+
+msgid "Runners|Understand how long it takes for runners to pick up a job. %{linkStart}How is this calculated?%{linkEnd}"
+msgstr ""
+
+msgid "Runners|Unselect all"
+msgstr ""
+
+msgid "Runners|Up to date"
+msgstr ""
+
+msgid "Runners|Upgrade GitLab Runner to match the version of GitLab you're running. Both %{linkStart}major and minor versions%{linkEnd} should match."
+msgstr ""
+
+msgid "Runners|Upgrade Status"
+msgstr ""
+
+msgid "Runners|Upgrade available"
+msgstr ""
+
+msgid "Runners|Upgrade recommended"
+msgstr ""
+
+msgid "Runners|Use Group runners when you want all projects in a group to have access to a set of runners."
+msgstr ""
+
+msgid "Runners|Use the dashboard to view performance statistics of your runner fleet."
+msgstr ""
+
+msgid "Runners|Use the runner for jobs without tags in addition to tagged jobs."
+msgstr ""
+
+msgid "Runners|Use the runner for the currently assigned projects only. Only administrators can change the assigned projects."
+msgstr ""
+
+msgid "Runners|Use the runner on pipelines for protected branches only."
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
+msgid "Runners|Version %{version}"
+msgstr ""
+
+msgid "Runners|View installation instructions"
+msgstr ""
+
+msgid "Runners|View metrics"
+msgstr ""
+
+msgid "Runners|Wait time to pick a job"
+msgstr ""
+
+msgid "Runners|We've been making improvements to how you register runners so that it's more secure and efficient. Tell us how we're doing."
+msgstr ""
+
+msgid "Runners|We've made some changes and want your feedback"
+msgstr ""
+
+msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
+msgstr ""
+
+msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. Non-spot."
+msgstr ""
+
+msgid "Runners|Yes, disable shared runners"
+msgstr ""
+
+msgid "Runners|Yes, start deleting stale runners"
+msgstr ""
+
+msgid "Runners|You can set up a project runner to be used by multiple projects but you cannot make this a shared or group runner."
+msgstr ""
+
+msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
+msgstr ""
+
+msgid "Runners|You may lose access to the runner token if you leave this page."
+msgstr ""
+
+msgid "Runners|You've created a new runner!"
+msgstr ""
+
+msgid "Runners|active"
+msgstr ""
+
+msgid "Runners|group"
+msgstr ""
+
+msgid "Runners|paused"
+msgstr ""
+
+msgid "Runners|project"
+msgstr ""
+
+msgid "Runners|shared"
+msgstr ""
+
+msgid "Runner|Runner actions"
+msgstr ""
+
+msgid "Running"
+msgstr ""
+
+msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
+msgstr ""
+
+msgid "SAML"
+msgstr ""
+
+msgid "SAML SSO"
+msgstr ""
+
+msgid "SAML SSO for %{group_name}"
+msgstr ""
+
+msgid "SAML discovery tokens"
+msgstr ""
+
+msgid "SAML for %{group_name}"
+msgstr ""
+
+msgid "SAML group membership settings"
+msgstr ""
+
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr ""
+
+msgid "SAML|Sign in to %{groupName}"
+msgstr ""
+
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|The SAML response did not contain an email address. Either the SAML identity provider is not configured to send the attribute, or the identity provider directory does not have an email address value for your user."
+msgstr ""
+
+msgid "SAML|There is already a GitLab account associated with this email address. Sign in with your existing credentials to connect your organization's account"
+msgstr ""
+
+msgid "SAML|To access %{groupName}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr ""
+
+msgid "SAML|Your organization's SSO has been connected to your GitLab account"
+msgstr ""
+
+msgid "SBOMs last updated"
+msgstr ""
+
+msgid "SCIM|SCIM Token"
+msgstr ""
+
+msgid "SCIM|System for Cross-Domain Identity Management."
+msgstr ""
+
+msgid "SHA256"
+msgstr ""
+
+msgid "SSH Key"
+msgstr ""
+
+msgid "SSH Keys"
+msgstr ""
+
+msgid "SSH Keys Help"
+msgstr ""
+
+msgid "SSH fingerprints verify that the client is connecting to the correct host. Check the %{config_link_start}current instance configuration%{config_link_end}."
+msgstr ""
+
+msgid "SSH host key fingerprints"
+msgstr ""
+
+msgid "SSH host keys"
+msgstr ""
+
+msgid "SSH host keys are not available on this system. Please use %{ssh_keyscan} command or contact your GitLab administrator for more information."
+msgstr ""
+
+msgid "SSH key"
+msgstr ""
+
+msgid "SSH key fingerprint:"
+msgstr ""
+
+msgid "SSH keys"
+msgstr ""
+
+msgid "SSH keys allow you to establish a secure connection between your computer and GitLab."
+msgstr ""
+
+msgid "SSH keys with the following fingerprints are scheduled to expire soon. Expired SSH keys can not be used:"
+msgstr ""
+
+msgid "SSH keys with the following fingerprints have expired and can no longer be used:"
+msgstr ""
+
+msgid "SSH public key"
+msgstr ""
+
+msgid "SSHKey|Authentication"
+msgstr ""
+
+msgid "SSHKey|Authentication & Signing"
+msgstr ""
+
+msgid "SSHKey|Signing"
+msgstr ""
+
+msgid "SSL Verification:"
+msgstr ""
+
+msgid "SSL verification"
+msgstr ""
+
+msgid "SVG could not be rendered correctly: "
+msgstr ""
+
+msgid "Sat"
+msgstr ""
+
+msgid "Satisfied"
+msgstr ""
+
+msgid "Saturday"
+msgstr ""
+
+msgid "Save"
+msgstr ""
+
+msgid "Save %{name} size limits"
+msgstr ""
+
+msgid "Save Changes"
+msgstr ""
+
+msgid "Save application"
+msgstr ""
+
+msgid "Save changes"
+msgstr ""
+
+msgid "Save changes before testing"
+msgstr ""
+
+msgid "Save comment"
+msgstr ""
+
+msgid "Save deploy freeze"
+msgstr ""
+
+msgid "Save internal note"
+msgstr ""
+
+msgid "Save password"
+msgstr ""
+
+msgid "Saving"
+msgstr ""
+
+msgid "Saving project."
+msgstr ""
+
+msgid "ScanExecutionPolicy|%{hostname}'s timezone"
+msgstr ""
+
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
+msgstr ""
+
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
+msgstr ""
+
+msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
+msgstr ""
+
+msgid "ScanExecutionPolicy|A runner will be selected automatically from those available."
+msgstr ""
+
+msgid "ScanExecutionPolicy|Add condition"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Add new CI variable"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Conditions"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Create new scan profile"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Create new site profile"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Customized CI variables:"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Customized variables will overwrite ones defined in the project CI/CD file and settings"
+msgstr ""
+
+msgid "ScanExecutionPolicy|DAST scan profiles"
+msgstr ""
+
+msgid "ScanExecutionPolicy|DAST site profiles"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Key"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Kubernetes agent's timezone"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Maximum number of CI-criteria is one"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Only one variable can be added at a time."
+msgstr ""
+
+msgid "ScanExecutionPolicy|Run a %{scan} scan with the following options:"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Runner tags:"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Schedule rule component"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Schedules:"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Select a scanner"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Select branches"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Select or Create a Key"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Select scanner profile"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Select site profile"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Select timezone"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Triggers:"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Use a custom key"
+msgstr ""
+
+msgid "ScanExecutionPolicy|Value"
+msgstr ""
+
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
+msgid "ScanExecutionPolicy|branch"
+msgstr ""
+
+msgid "ScanExecutionPolicy|has specific tag"
+msgstr ""
+
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
+msgid "ScanExecutionPolicy|on %{hostname}"
+msgstr ""
+
+msgid "ScanExecutionPolicy|on the Kubernetes agent pod"
+msgstr ""
+
+msgid "ScanExecutionPolicy|selected automatically"
+msgstr ""
+
+msgid "ScanResultPolicy|%{count} licenses"
+msgstr ""
+
+msgid "ScanResultPolicy|Add new criteria"
+msgstr ""
+
+msgid "ScanResultPolicy|Age criteria can only be added for pre-existing vulnerabilities"
+msgstr ""
+
+msgid "ScanResultPolicy|Age is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
+msgstr ""
+
+msgid "ScanResultPolicy|Choose criteria type"
+msgstr ""
+
+msgid "ScanResultPolicy|Clear all"
+msgstr ""
+
+msgid "ScanResultPolicy|Customized CI Variables"
+msgstr ""
+
+msgid "ScanResultPolicy|Except"
+msgstr ""
+
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
+msgid "ScanResultPolicy|License is:"
+msgstr ""
+
+msgid "ScanResultPolicy|License scanning allows only one criteria: Status"
+msgstr ""
+
+msgid "ScanResultPolicy|Matching"
+msgstr ""
+
+msgid "ScanResultPolicy|New age"
+msgstr ""
+
+msgid "ScanResultPolicy|New attribute"
+msgstr ""
+
+msgid "ScanResultPolicy|New status"
+msgstr ""
+
+msgid "ScanResultPolicy|Newly Detected"
+msgstr ""
+
+msgid "ScanResultPolicy|Only 1 age criteria is allowed"
+msgstr ""
+
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
+msgstr ""
+
+msgid "ScanResultPolicy|Only 2 status criteria are allowed"
+msgstr ""
+
+msgid "ScanResultPolicy|Override project approval settings"
+msgstr ""
+
+msgid "ScanResultPolicy|Pre-existing"
+msgstr ""
+
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
+msgid "ScanResultPolicy|Select a scan type before adding criteria"
+msgstr ""
+
+msgid "ScanResultPolicy|Select all"
+msgstr ""
+
+msgid "ScanResultPolicy|Select license types"
+msgstr ""
+
+msgid "ScanResultPolicy|Select licenses"
+msgstr ""
+
+msgid "ScanResultPolicy|Severity is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Status is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Unknown"
+msgstr ""
+
+msgid "ScanResultPolicy|When %{scanType} %{scanners} runs against the %{branches} %{branchExceptions} and find(s) %{vulnerabilitiesNumber} %{boldDescription} of the following criteria:"
+msgstr ""
+
+msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
+msgstr ""
+
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
+msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
+msgstr ""
+
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
+msgid "ScanResultPolicy|license status"
+msgstr ""
+
+msgid "ScanResultPolicy|matching type"
+msgstr ""
+
+msgid "ScanResultPolicy|scanners"
+msgstr ""
+
+msgid "ScanResultPolicy|severity levels"
+msgstr ""
+
+msgid "ScanResultPolicy|vulnerabilities allowed"
+msgstr ""
+
+msgid "ScanResultPolicy|vulnerabilities that match all"
+msgstr ""
+
+msgid "ScanResultPolicy|vulnerability states"
+msgstr ""
+
+msgid "Scanner"
+msgstr ""
+
+msgid "Scanner profile failed to delete"
+msgstr ""
+
+msgid "Scanner profile not found for given parameters"
+msgstr ""
+
+msgid "Schedule a new pipeline"
+msgstr ""
+
+msgid "Schedule-based escalation rules must have a schedule in the same project as the policy"
+msgstr ""
+
+msgid "Scheduled"
+msgstr ""
+
+msgid "Scheduled Deletion At - %{permanent_deletion_time}"
+msgstr ""
+
+msgid "Scheduled a rebase of branch %{branch}."
+msgstr ""
+
+msgid "Scheduled pipelines cannot run more frequently than once per %{limit} minutes. A pipeline configured to run more frequently only starts after %{limit} minutes have elapsed since the last time it ran."
+msgstr ""
+
+msgid "Scheduled to merge this merge request (%{strategy})."
+msgstr ""
+
+msgid "Schedules"
+msgstr ""
+
+msgid "Schedules to merge this merge request (%{strategy})."
+msgstr ""
+
+msgid "Scheduling Pipelines"
+msgstr ""
+
+msgid "Scope"
+msgstr ""
+
+msgid "Scope board to current iteration"
+msgstr ""
+
+msgid "Scopes"
+msgstr ""
+
+msgid "Scopes (select at least one)"
+msgstr ""
+
+msgid "Scopes can't be blank"
+msgstr ""
+
+msgid "Scopes: %{scope_list}"
+msgstr ""
+
+msgid "Screenshot must be less than 1 MB."
+msgstr ""
+
+msgid "Scroll down"
+msgstr ""
+
+msgid "Scroll left"
+msgstr ""
+
+msgid "Scroll right"
+msgstr ""
+
+msgid "Scroll to bottom"
+msgstr ""
+
+msgid "Scroll to top"
+msgstr ""
+
+msgid "Scroll up"
+msgstr ""
+
+msgid "Search"
+msgstr ""
+
+msgid "Search Within"
+msgstr ""
+
+msgid "Search a group"
+msgstr ""
+
+msgid "Search an environment spec"
+msgstr ""
+
+msgid "Search artifacts"
+msgstr ""
+
+msgid "Search assignees"
+msgstr ""
+
+msgid "Search authors"
+msgstr ""
+
+msgid "Search branch"
+msgstr ""
+
+msgid "Search branches"
+msgstr ""
+
+msgid "Search branches and tags"
+msgstr ""
+
+msgid "Search branches, tags, and commits"
+msgstr ""
+
+msgid "Search by Git revision"
+msgstr ""
+
+msgid "Search by author"
+msgstr ""
+
+msgid "Search by message"
+msgstr ""
+
+msgid "Search by name"
+msgstr ""
+
+msgid "Search files"
+msgstr ""
+
+msgid "Search for Namespace"
+msgstr ""
+
+msgid "Search for a group"
+msgstr ""
+
+msgid "Search for an emoji"
+msgstr ""
+
+msgid "Search for projects, issues, etc."
+msgstr ""
+
+msgid "Search for this text"
+msgstr ""
+
+msgid "Search forks"
+msgstr ""
+
+msgid "Search groups"
+msgstr ""
+
+msgid "Search iterations"
+msgstr ""
+
+msgid "Search labels"
+msgstr ""
+
+msgid "Search merge requests"
+msgstr ""
+
+msgid "Search milestones"
+msgstr ""
+
+msgid "Search or filter commits"
+msgstr ""
+
+msgid "Search or filter results…"
+msgstr ""
+
+msgid "Search or go to…"
+msgstr ""
+
+msgid "Search page"
+msgstr ""
+
+msgid "Search project"
+msgstr ""
+
+msgid "Search projects"
+msgstr ""
+
+msgid "Search protected branches"
+msgstr ""
+
+msgid "Search rate limits"
+msgstr ""
+
+msgid "Search refs"
+msgstr ""
+
+msgid "Search requirements"
+msgstr ""
+
+msgid "Search results"
+msgstr ""
+
+msgid "Search settings"
+msgstr ""
+
+msgid "Search users"
+msgstr ""
+
+msgid "Search your projects"
+msgstr ""
+
+msgid "Search your%{visibility}projects"
+msgstr ""
+
+msgid "Search%{visibility}projects"
+msgstr ""
+
+msgid "SearchCodeResults|of %{link_to_project}"
+msgstr ""
+
+msgid "SearchError|A search query problem has occurred"
+msgstr ""
+
+msgid "SearchError|Learn more about %{search_syntax_link_start} Zoekt search syntax%{search_syntax_link_end}."
+msgstr ""
+
+msgid "SearchError|To resolve the problem, check the query syntax and try again."
+msgstr ""
+
+msgid "SearchResults|Showing %{count} %{scope} for %{term_element}"
+msgstr ""
+
+msgid "SearchResults|Showing %{count} %{scope} for %{term_element} in your personal and project snippets"
+msgstr ""
+
+msgid "SearchResults|Showing %{from} - %{to} of %{count} %{scope} for %{term_element}"
+msgstr ""
+
+msgid "SearchResults|Showing %{from} - %{to} of %{count} %{scope} for %{term_element} in your personal and project snippets"
+msgstr ""
+
+msgid "SearchResults|code result"
+msgid_plural "SearchResults|code results"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|comment"
+msgid_plural "SearchResults|comments"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|commit"
+msgid_plural "SearchResults|commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|issue"
+msgid_plural "SearchResults|issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|merge request"
+msgid_plural "SearchResults|merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|milestone"
+msgid_plural "SearchResults|milestones"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|project"
+msgid_plural "SearchResults|projects"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|snippet"
+msgid_plural "SearchResults|snippets"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|user"
+msgid_plural "SearchResults|users"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchResults|wiki result"
+msgid_plural "SearchResults|wiki results"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SearchToken|Assignee"
+msgstr ""
+
+msgid "SearchToken|Reviewer"
+msgstr ""
+
+msgid "Searching by both author and message is currently not supported."
+msgstr ""
+
+msgid "Seats"
+msgstr ""
+
+msgid "Seats owed"
+msgstr ""
+
+msgid "Secondary email:"
+msgstr ""
+
+msgid "Seconds"
+msgstr ""
+
+msgid "Secret"
+msgstr ""
+
+msgid "Secret Detection"
+msgstr ""
+
+msgid "Secret token"
+msgstr ""
+
+msgid "SecretDetection|This comment appears to have a token in it. Are you sure you want to add it?"
+msgstr ""
+
+msgid "SecretDetection|This description appears to have a token in it. Are you sure you want to add it?"
+msgstr ""
+
+msgid "Secure Code Warrior"
+msgstr ""
+
+msgid "Secure Files"
+msgstr ""
+
+msgid "Secure token that identifies an external storage request."
+msgstr ""
+
+msgid "SecureFiles|%{name} Metadata"
+msgstr ""
+
+msgid "SecureFiles|App"
+msgstr ""
+
+msgid "SecureFiles|Certificates"
+msgstr ""
+
+msgid "SecureFiles|Delete %{name}?"
+msgstr ""
+
+msgid "SecureFiles|Delete secure file"
+msgstr ""
+
+msgid "SecureFiles|Expires at"
+msgstr ""
+
+msgid "SecureFiles|Issuer"
+msgstr ""
+
+msgid "SecureFiles|Name"
+msgstr ""
+
+msgid "SecureFiles|Platforms"
+msgstr ""
+
+msgid "SecureFiles|Secure File %{name} will be permanently deleted. Are you sure?"
+msgstr ""
+
+msgid "SecureFiles|Serial"
+msgstr ""
+
+msgid "SecureFiles|Team"
+msgstr ""
+
+msgid "SecureFiles|UUID"
+msgstr ""
+
+msgid "Security"
+msgstr ""
+
+msgid "Security Dashboard"
+msgstr ""
+
+msgid "Security Finding not found"
+msgstr ""
+
+msgid "Security Policy project already exists."
+msgstr ""
+
+msgid "Security and Compliance"
+msgstr ""
+
+msgid "Security capabilities"
+msgstr ""
+
+msgid "Security configuration"
+msgstr ""
+
+msgid "Security dashboard"
+msgstr ""
+
+msgid "Security reports last updated"
+msgstr ""
+
+msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
+msgstr ""
+
+msgid "SecurityApprovals|Coverage-Check"
+msgstr ""
+
+msgid "SecurityApprovals|Learn more about Coverage-Check"
+msgstr ""
+
+msgid "SecurityApprovals|Requires approval for decreases in test coverage. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "SecurityConfiguration|%{featureName} merge request creation mutation failed"
+msgstr ""
+
+msgid "SecurityConfiguration|%{scanType} configuration code snippet"
+msgstr ""
+
+msgid "SecurityConfiguration|An error occurred while creating the merge request."
+msgstr ""
+
+msgid "SecurityConfiguration|Available with Ultimate"
+msgstr ""
+
+msgid "SecurityConfiguration|BAS"
+msgstr ""
+
+msgid "SecurityConfiguration|Breach and Attack Simulation (BAS)"
+msgstr ""
+
+msgid "SecurityConfiguration|Breach and Attack Simulation is an incubating feature extending existing security testing by simulating adversary activity."
+msgstr ""
+
+msgid "SecurityConfiguration|Configuration guide"
+msgstr ""
+
+msgid "SecurityConfiguration|Configuration history"
+msgstr ""
+
+msgid "SecurityConfiguration|Configure %{feature}"
+msgstr ""
+
+msgid "SecurityConfiguration|Configure with a merge request"
+msgstr ""
+
+msgid "SecurityConfiguration|Copy code and open .gitlab-ci.yml file"
+msgstr ""
+
+msgid "SecurityConfiguration|Copy code only"
+msgstr ""
+
+msgid "SecurityConfiguration|Could not retrieve configuration data. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "SecurityConfiguration|Create merge request"
+msgstr ""
+
+msgid "SecurityConfiguration|Customize common SAST settings to suit your requirements. Configuration changes made here override those provided by GitLab and are excluded from updates. For details of more advanced configuration options, see the %{linkStart}GitLab SAST documentation%{linkEnd}."
+msgstr ""
+
+msgid "SecurityConfiguration|Enable %{feature}"
+msgstr ""
+
+msgid "SecurityConfiguration|Enable Auto DevOps"
+msgstr ""
+
+msgid "SecurityConfiguration|Enable incubating Breach and Attack Simulation focused features such as callback attacks in your DAST scans."
+msgstr ""
+
+msgid "SecurityConfiguration|Enable security training to help your developers learn how to fix vulnerabilities. Developers can view security training from selected educational providers, relevant to the detected vulnerability."
+msgstr ""
+
+msgid "SecurityConfiguration|Enabled"
+msgstr ""
+
+msgid "SecurityConfiguration|High-level vulnerability statistics across projects and groups"
+msgstr ""
+
+msgid "SecurityConfiguration|Immediately begin risk analysis and remediation with application security features. Start with SAST and Secret Detection, available to all plans. Upgrade to Ultimate to get all features, including:"
+msgstr ""
+
+msgid "SecurityConfiguration|Incubating feature"
+msgstr ""
+
+msgid "SecurityConfiguration|Learn more about vulnerability training"
+msgstr ""
+
+msgid "SecurityConfiguration|Manage corpus"
+msgstr ""
+
+msgid "SecurityConfiguration|Manage corpus files used as seed inputs with coverage-guided fuzzing."
+msgstr ""
+
+msgid "SecurityConfiguration|Manage profiles"
+msgstr ""
+
+msgid "SecurityConfiguration|Manage profiles for use by DAST scans."
+msgstr ""
+
+msgid "SecurityConfiguration|More scan types, including DAST, Dependency Scanning, Fuzzing"
+msgstr ""
+
+msgid "SecurityConfiguration|Not enabled"
+msgstr ""
+
+msgid "SecurityConfiguration|Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan. An enabled scanner will not be reflected as such until the pipeline has been successfully executed and it has generated valid artifacts."
+msgstr ""
+
+msgid "SecurityConfiguration|Out-of-Band Application Security Testing (OAST)"
+msgstr ""
+
+msgid "SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}"
+msgstr ""
+
+msgid "SecurityConfiguration|Runtime security metrics for application environments"
+msgstr ""
+
+msgid "SecurityConfiguration|SAST configuration"
+msgstr ""
+
+msgid "SecurityConfiguration|Secure your project"
+msgstr ""
+
+msgid "SecurityConfiguration|Security testing"
+msgstr ""
+
+msgid "SecurityConfiguration|Security training"
+msgstr ""
+
+msgid "SecurityConfiguration|Simulate breach and attack scenarios against your running application by attempting to detect and exploit known vulnerabilities."
+msgstr ""
+
+msgid "SecurityConfiguration|Something went wrong. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "SecurityConfiguration|The status of the tools only applies to the default branch and is based on the %{linkStart}latest pipeline%{linkEnd}."
+msgstr ""
+
+msgid "SecurityConfiguration|Upgrade or start a free trial"
+msgstr ""
+
+msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
+msgstr ""
+
+msgid "SecurityConfiguration|Vulnerability Management"
+msgstr ""
+
+msgid "SecurityConfiguration|Vulnerability details and statistics in the merge request"
+msgstr ""
+
+msgid "SecurityOrchestration| and "
+msgstr ""
+
+msgid "SecurityOrchestration| and all the following apply:"
+msgstr ""
+
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
+msgid "SecurityOrchestration| or "
+msgstr ""
+
+msgid "SecurityOrchestration| that is %{licenseState} and is"
+msgstr ""
+
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{scanners}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{state} and %{statuses}"
+msgstr ""
+
+msgid "SecurityOrchestration|, and %{count} more"
+msgstr ""
+
+msgid "SecurityOrchestration|.yaml mode"
+msgstr ""
+
+msgid "SecurityOrchestration|.yaml preview"
+msgstr ""
+
+msgid "SecurityOrchestration|Actions"
+msgstr ""
+
+msgid "SecurityOrchestration|Add action"
+msgstr ""
+
+msgid "SecurityOrchestration|Add new approver"
+msgstr ""
+
+msgid "SecurityOrchestration|Add rule"
+msgstr ""
+
+msgid "SecurityOrchestration|After dismissing the alert, the information will never be shown again."
+msgstr ""
+
+msgid "SecurityOrchestration|After enabling a group-level policy, this policy automatically applies to all projects and sub-groups in this group."
+msgstr ""
+
+msgid "SecurityOrchestration|All sources"
+msgstr ""
+
+msgid "SecurityOrchestration|All types"
+msgstr ""
+
+msgid "SecurityOrchestration|An error occurred assigning your security policy project"
+msgstr ""
+
+msgid "SecurityOrchestration|An error occurred unassigning your security policy project"
+msgstr ""
+
+msgid "SecurityOrchestration|An error occurred while fetching the scan result policies."
+msgstr ""
+
+msgid "SecurityOrchestration|And scans to be performed:"
+msgstr ""
+
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
+msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
+msgid "SecurityOrchestration|Automatically selected runners"
+msgstr ""
+
+msgid "SecurityOrchestration|Branch types don't match any existing branches."
+msgstr ""
+
+msgid "SecurityOrchestration|Choose a project"
+msgstr ""
+
+msgid "SecurityOrchestration|Choose approver type"
+msgstr ""
+
+msgid "SecurityOrchestration|Choose specific role"
+msgstr ""
+
+msgid "SecurityOrchestration|Clear all"
+msgstr ""
+
+msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
+msgstr ""
+
+msgid "SecurityOrchestration|Create policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Create security policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Define this policy's location, conditions and actions."
+msgstr ""
+
+msgid "SecurityOrchestration|Delete policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Delete policy: %{policy}"
+msgstr ""
+
+msgid "SecurityOrchestration|Description"
+msgstr ""
+
+msgid "SecurityOrchestration|Details"
+msgstr ""
+
+msgid "SecurityOrchestration|Direct"
+msgstr ""
+
+msgid "SecurityOrchestration|Don't show the alert anymore"
+msgstr ""
+
+msgid "SecurityOrchestration|Edit policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Edit policy project"
+msgstr ""
+
+msgid "SecurityOrchestration|Edit scan execution policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Edit scan result policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Empty policy name"
+msgstr ""
+
+msgid "SecurityOrchestration|Enabled"
+msgstr ""
+
+msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
+msgstr ""
+
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
+msgstr ""
+
+msgid "SecurityOrchestration|Exceptions"
+msgstr ""
+
+msgid "SecurityOrchestration|Failed to load cluster agents."
+msgstr ""
+
+msgid "SecurityOrchestration|Failed to load images."
+msgstr ""
+
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
+msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
+msgstr ""
+
+msgid "SecurityOrchestration|Groups"
+msgstr ""
+
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
+msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
+msgstr ""
+
+msgid "SecurityOrchestration|Individual users"
+msgstr ""
+
+msgid "SecurityOrchestration|Inherited"
+msgstr ""
+
+msgid "SecurityOrchestration|Inherited from %{namespace}"
+msgstr ""
+
+msgid "SecurityOrchestration|Invalid branch type detected - rule will not be applied."
+msgstr ""
+
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Invalid policy type"
+msgstr ""
+
+msgid "SecurityOrchestration|Latest scan run against %{agent}"
+msgstr ""
+
+msgid "SecurityOrchestration|License Scan"
+msgstr ""
+
+msgid "SecurityOrchestration|Logic error"
+msgstr ""
+
+msgid "SecurityOrchestration|New policy"
+msgstr ""
+
+msgid "SecurityOrchestration|New scan execution policy"
+msgstr ""
+
+msgid "SecurityOrchestration|New scan result policy"
+msgstr ""
+
+msgid "SecurityOrchestration|No actions defined - policy will not run."
+msgstr ""
+
+msgid "SecurityOrchestration|No description"
+msgstr ""
+
+msgid "SecurityOrchestration|No exceptions"
+msgstr ""
+
+msgid "SecurityOrchestration|No rules defined - policy will not run."
+msgstr ""
+
+msgid "SecurityOrchestration|No tags available"
+msgstr ""
+
+msgid "SecurityOrchestration|Non-existing DAST profiles have been detected in the policy yaml. As a result, rule mode has been disabled. To enable rule mode, remove those non-existing profiles from the policy yaml."
+msgstr ""
+
+msgid "SecurityOrchestration|Non-existing tags have been detected in the policy yaml. As a result, rule mode has been disabled. To enable rule mode, remove those non-existing tags from the policy yaml."
+msgstr ""
+
+msgid "SecurityOrchestration|Not enabled"
+msgstr ""
+
+msgid "SecurityOrchestration|On runners with tag:"
+msgid_plural "SecurityOrchestration|On runners with the tags:"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SecurityOrchestration|Only owners can update Security Policy Project"
+msgstr ""
+
+msgid "SecurityOrchestration|Policies"
+msgstr ""
+
+msgid "SecurityOrchestration|Policy Type"
+msgstr ""
+
+msgid "SecurityOrchestration|Policy cannot be enabled for non-existing branches (%{branches})"
+msgstr ""
+
+msgid "SecurityOrchestration|Policy cannot be enabled without branch information"
+msgstr ""
+
+msgid "SecurityOrchestration|Policy changes may take some time to be applied."
+msgstr ""
+
+msgid "SecurityOrchestration|Policy definition"
+msgstr ""
+
+msgid "SecurityOrchestration|Policy editor"
+msgstr ""
+
+msgid "SecurityOrchestration|Policy status"
+msgstr ""
+
+msgid "SecurityOrchestration|Policy type"
+msgstr ""
+
+msgid "SecurityOrchestration|Require %{approvals} %{plural} from %{approvers} if any of the following occur:"
+msgstr ""
+
+msgid "SecurityOrchestration|Required approvals exceed eligible approvers."
+msgstr ""
+
+msgid "SecurityOrchestration|Roles"
+msgstr ""
+
+msgid "SecurityOrchestration|Rule mode"
+msgstr ""
+
+msgid "SecurityOrchestration|Rule mode is unavailable for this policy. In some cases, we cannot parse the YAML file back into the rules editor."
+msgstr ""
+
+msgid "SecurityOrchestration|Rules"
+msgstr ""
+
+msgid "SecurityOrchestration|Run %{scannerStart}%{scanner}%{scannerEnd} with the following options:"
+msgstr ""
+
+msgid "SecurityOrchestration|Run a DAST scan with Scan Profile A and Site Profile A when a pipeline run against the main branch."
+msgstr ""
+
+msgid "SecurityOrchestration|Save changes"
+msgstr ""
+
+msgid "SecurityOrchestration|Scan Execution"
+msgstr ""
+
+msgid "SecurityOrchestration|Scan Result"
+msgstr ""
+
+msgid "SecurityOrchestration|Scan execution"
+msgstr ""
+
+msgid "SecurityOrchestration|Scan execution policies can only be created by project owners."
+msgstr ""
+
+msgid "SecurityOrchestration|Scan execution policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Scan result"
+msgstr ""
+
+msgid "SecurityOrchestration|Scan result policies can only be created by project owners."
+msgstr ""
+
+msgid "SecurityOrchestration|Scan result policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Scan will automatically choose a runner to run on because there are no tags exist on runners. You can %{linkStart}create a new tag in settings%{linkEnd}."
+msgstr ""
+
+msgid "SecurityOrchestration|Security Approvals"
+msgstr ""
+
+msgid "SecurityOrchestration|Security Scan"
+msgstr ""
+
+msgid "SecurityOrchestration|Security policy project was linked successfully"
+msgstr ""
+
+msgid "SecurityOrchestration|Security policy project was unlinked successfully"
+msgstr ""
+
+msgid "SecurityOrchestration|Select a project to store your security policies in. %{linkStart}More information.%{linkEnd}"
+msgstr ""
+
+msgid "SecurityOrchestration|Select exception branches"
+msgstr ""
+
+msgid "SecurityOrchestration|Select groups"
+msgstr ""
+
+msgid "SecurityOrchestration|Select policy"
+msgstr ""
+
+msgid "SecurityOrchestration|Select scan type"
+msgstr ""
+
+msgid "SecurityOrchestration|Select security project"
+msgstr ""
+
+msgid "SecurityOrchestration|Select users"
+msgstr ""
+
+msgid "SecurityOrchestration|Severity is %{severity}."
+msgstr ""
+
+msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
+msgstr ""
+
+msgid "SecurityOrchestration|Sorry, your filter produced no results."
+msgstr ""
+
+msgid "SecurityOrchestration|Source"
+msgstr ""
+
+msgid "SecurityOrchestration|Status"
+msgstr ""
+
+msgid "SecurityOrchestration|Step 1: Choose a policy type"
+msgstr ""
+
+msgid "SecurityOrchestration|Step 2: Policy details"
+msgstr ""
+
+msgid "SecurityOrchestration|Summary"
+msgstr ""
+
+msgid "SecurityOrchestration|The following branches do not exist on this development project: %{branches}. Please review all protected branches to ensure the values are accurate before updating this policy."
+msgstr ""
+
+msgid "SecurityOrchestration|There was a problem creating the new security policy"
+msgstr ""
+
+msgid "SecurityOrchestration|This %{namespaceType} does not contain any security policies."
+msgstr ""
+
+msgid "SecurityOrchestration|This %{namespaceType} is not linked to a security policy project"
+msgstr ""
+
+msgid "SecurityOrchestration|This group"
+msgstr ""
+
+msgid "SecurityOrchestration|This is a group-level policy"
+msgstr ""
+
+msgid "SecurityOrchestration|This is a project-level policy"
+msgstr ""
+
+msgid "SecurityOrchestration|This policy is inherited from %{namespace}"
+msgstr ""
+
+msgid "SecurityOrchestration|This policy is inherited from the %{linkStart}namespace%{linkEnd} and must be edited there"
+msgstr ""
+
+msgid "SecurityOrchestration|This project"
+msgstr ""
+
+msgid "SecurityOrchestration|This view only shows scan results for the agent %{agent}. You can view scan results for all agents in the %{linkStart}Operational Vulnerabilities tab of the vulnerability report%{linkEnd}."
+msgstr ""
+
+msgid "SecurityOrchestration|Timezone is invalid"
+msgstr ""
+
+msgid "SecurityOrchestration|To widen your search, change filters above or select a different security policy project."
+msgstr ""
+
+msgid "SecurityOrchestration|Unlink project"
+msgstr ""
+
+msgid "SecurityOrchestration|Unlinking a security project removes all policies stored in the linked security project. Save to confirm this action."
+msgstr ""
+
+msgid "SecurityOrchestration|Update scan policies"
+msgstr ""
+
+msgid "SecurityOrchestration|Use a scan execution policy to create rules which enforce security scans for particular branches at a certain time. Supported types are SAST, SAST IaC, DAST, Secret detection, Container scanning, and Dependency scanning."
+msgstr ""
+
+msgid "SecurityOrchestration|Use a scan result policy to create rules that check for security vulnerabilities and license compliance before merging a merge request."
+msgstr ""
+
+msgid "SecurityOrchestration|View policy project"
+msgstr ""
+
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
+msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
+msgstr ""
+
+msgid "SecurityOrchestration|Vulnerability age is greater than %{vulnerabilityAge}."
+msgstr ""
+
+msgid "SecurityOrchestration|Vulnerability age is less than %{vulnerabilityAge}."
+msgstr ""
+
+msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
+msgstr ""
+
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
+msgstr ""
+
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr ""
+
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr ""
+
+msgid "SecurityOrchestration|With the following customized CI variables:"
+msgstr ""
+
+msgid "SecurityOrchestration|YAML"
+msgstr ""
+
+msgid "SecurityOrchestration|You don't have any security policies yet"
+msgstr ""
+
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|any"
+msgstr ""
+
+msgid "SecurityOrchestration|any branch"
+msgstr ""
+
+msgid "SecurityOrchestration|any default branch"
+msgstr ""
+
+msgid "SecurityOrchestration|any protected branch"
+msgstr ""
+
+msgid "SecurityOrchestration|any security scanner finds"
+msgstr ""
+
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|branch"
+msgstr ""
+
+msgid "SecurityOrchestration|branches"
+msgstr ""
+
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
+msgstr ""
+
+msgid "SecurityOrchestration|group level branch input"
+msgstr ""
+
+msgid "SecurityOrchestration|group level branch selector"
+msgstr ""
+
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|more than %{allowed}"
+msgstr ""
+
+msgid "SecurityOrchestration|or from:"
+msgstr ""
+
+msgid "SecurityOrchestration|scanner finds"
+msgstr ""
+
+msgid "SecurityOrchestration|scanners find"
+msgstr ""
+
+msgid "SecurityOrchestration|targeting %{branchTypeText}"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{branches}"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{branches} branch"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
+msgid "SecurityOrchestration|the default branch"
+msgstr ""
+
+msgid "SecurityOrchestration|with %{exceptionType}"
+msgstr ""
+
+msgid "SecurityOrchestration|with %{exceptionType} on %{branchSelector}"
+msgstr ""
+
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
+msgid "SecurityReports|%{count} Selected"
+msgstr ""
+
+msgid "SecurityReports|%{count}+ projects"
+msgstr ""
+
+msgid "SecurityReports|%{firstProject} and %{secondProject}"
+msgstr ""
+
+msgid "SecurityReports|%{firstProject}, %{secondProject}, and %{rest}"
+msgstr ""
+
+msgid "SecurityReports|A comment is required when dismissing."
+msgstr ""
+
+msgid "SecurityReports|Activity"
+msgstr ""
+
+msgid "SecurityReports|Add a comment"
+msgstr ""
+
+msgid "SecurityReports|Add a comment (required)"
+msgstr ""
+
+msgid "SecurityReports|Add a comment or reason for dismissal"
+msgstr ""
+
+msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
+msgstr ""
+
+msgid "SecurityReports|Add projects"
+msgstr ""
+
+msgid "SecurityReports|All activity"
+msgstr ""
+
+msgid "SecurityReports|All clusters"
+msgstr ""
+
+msgid "SecurityReports|All dismissal reasons"
+msgstr ""
+
+msgid "SecurityReports|All images"
+msgstr ""
+
+msgid "SecurityReports|All projects"
+msgstr ""
+
+msgid "SecurityReports|All severities"
+msgstr ""
+
+msgid "SecurityReports|All statuses"
+msgstr ""
+
+msgid "SecurityReports|All tools"
+msgstr ""
+
+msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
+msgstr ""
+
+msgid "SecurityReports|Change status"
+msgstr ""
+
+msgid "SecurityReports|Check the messages generated while parsing the following security reports, as they may prevent the results from being ingested by GitLab. Ensure the security report conforms to a supported %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
+msgstr ""
+
+msgid "SecurityReports|Cluster"
+msgstr ""
+
+msgid "SecurityReports|Comment added to '%{vulnerabilityName}'"
+msgstr ""
+
+msgid "SecurityReports|Comment deleted on '%{vulnerabilityName}'"
+msgstr ""
+
+msgid "SecurityReports|Comment edited on '%{vulnerabilityName}'"
+msgstr ""
+
+msgid "SecurityReports|Configure security testing"
+msgstr ""
+
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
+msgid "SecurityReports|Create Issue"
+msgstr ""
+
+msgid "SecurityReports|Create Jira issue"
+msgstr ""
+
+msgid "SecurityReports|Create issue"
+msgstr ""
+
+msgid "SecurityReports|Detection"
+msgstr ""
+
+msgid "SecurityReports|Development vulnerabilities"
+msgstr ""
+
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
+msgid "SecurityReports|Dismiss vulnerability"
+msgstr ""
+
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
+msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
+msgstr ""
+
+msgid "SecurityReports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view."
+msgstr ""
+
+msgid "SecurityReports|Dismissed (all reasons)"
+msgstr ""
+
+msgid "SecurityReports|Dismissed as..."
+msgstr ""
+
+msgid "SecurityReports|Does not have issue"
+msgstr ""
+
+msgid "SecurityReports|Download %{artifactName}"
+msgstr ""
+
+msgid "SecurityReports|Download patch to resolve"
+msgstr ""
+
+msgid "SecurityReports|Download results"
+msgstr ""
+
+msgid "SecurityReports|Download scanned URLs"
+msgstr ""
+
+msgid "SecurityReports|Download the patch to apply it manually"
+msgstr ""
+
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
+msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
+msgstr ""
+
+msgid "SecurityReports|Ensure that %{trackingStart}issue tracking%{trackingEnd} is enabled for this project and you have %{permissionsStart}permission to create new issues%{permissionsEnd}."
+msgstr ""
+
+msgid "SecurityReports|Error fetching the vulnerabilities over time. Please check your network connection and try again."
+msgstr ""
+
+msgid "SecurityReports|Error fetching the vulnerability counts. Please check your network connection and try again."
+msgstr ""
+
+msgid "SecurityReports|Error fetching the vulnerability list. Please check your network connection and try again."
+msgstr ""
+
+msgid "SecurityReports|Error parsing security reports"
+msgstr ""
+
+msgid "SecurityReports|Failed to get security report information. Please reload the page or try again later."
+msgstr ""
+
+msgid "SecurityReports|Failed updating vulnerabilities with the following IDs: %{ids}"
+msgstr ""
+
+msgid "SecurityReports|Has issue"
+msgstr ""
+
+msgid "SecurityReports|Hide dismissed"
+msgstr ""
+
+msgid "SecurityReports|Image"
+msgstr ""
+
+msgid "SecurityReports|Investigate this vulnerability by creating an issue"
+msgstr ""
+
+msgid "SecurityReports|Issue"
+msgstr ""
+
+msgid "SecurityReports|Issue Created"
+msgstr ""
+
+msgid "SecurityReports|Issues created from a vulnerability cannot be removed."
+msgstr ""
+
+msgid "SecurityReports|Learn more about setting up your dashboard"
+msgstr ""
+
+msgid "SecurityReports|Manage and track vulnerabilities identified in projects within your group. Vulnerabilities in projects are shown here when security testing is configured."
+msgstr ""
+
+msgid "SecurityReports|Manage and track vulnerabilities identified in your project. Vulnerabilities are shown here when security testing is configured."
+msgstr ""
+
+msgid "SecurityReports|Manage and track vulnerabilities identified in your selected projects. Vulnerabilities for selected projects with security testing configured are shown here."
+msgstr ""
+
+msgid "SecurityReports|Maximum selected projects limit reached"
+msgstr ""
+
+msgid "SecurityReports|Monitor vulnerabilities in all of your projects"
+msgstr ""
+
+msgid "SecurityReports|Monitor vulnerabilities in your group"
+msgstr ""
+
+msgid "SecurityReports|Monitor vulnerabilities in your project"
+msgstr ""
+
+msgid "SecurityReports|Monitored projects"
+msgstr ""
+
+msgid "SecurityReports|More info"
+msgstr ""
+
+msgid "SecurityReports|No longer detected"
+msgstr ""
+
+msgid "SecurityReports|No vulnerabilities found"
+msgstr ""
+
+msgid "SecurityReports|No vulnerabilities found for this pipeline"
+msgstr ""
+
+msgid "SecurityReports|Oops, something doesn't seem right."
+msgstr ""
+
+msgid "SecurityReports|Operational vulnerabilities"
+msgstr ""
+
+msgid "SecurityReports|Parsing errors and warnings in pipeline"
+msgstr ""
+
+msgid "SecurityReports|Parsing errors in pipeline"
+msgstr ""
+
+msgid "SecurityReports|Parsing warnings in pipeline"
+msgstr ""
+
+msgid "SecurityReports|Project"
+msgstr ""
+
+msgid "SecurityReports|Project was not found or you do not have permission to add this project to Security Dashboards."
+msgstr ""
+
+msgid "SecurityReports|Projects added"
+msgstr ""
+
+msgid "SecurityReports|Remove project from dashboard"
+msgstr ""
+
+msgid "SecurityReports|Report has expired"
+msgstr ""
+
+msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
+msgstr ""
+
+msgid "SecurityReports|Scan details"
+msgstr ""
+
+msgid "SecurityReports|Security dashboard"
+msgstr ""
+
+msgid "SecurityReports|Security reports can only be accessed by authorized users."
+msgstr ""
+
+msgid "SecurityReports|Security scans have run"
+msgstr ""
+
+msgid "SecurityReports|Select a project to add by using the project search field above."
+msgstr ""
+
+msgid "SecurityReports|Set dismissal reason"
+msgstr ""
+
+msgid "SecurityReports|Set status"
+msgstr ""
+
+msgid "SecurityReports|Severity"
+msgstr ""
+
+msgid "SecurityReports|Show %d item"
+msgid_plural "SecurityReports|Show %d items"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SecurityReports|Sometimes a scanner can't determine a finding's severity. Those findings may still be a potential source of risk though. Please review these manually."
+msgstr ""
+
+msgid "SecurityReports|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "SecurityReports|Status"
+msgstr ""
+
+msgid "SecurityReports|Still detected"
+msgstr ""
+
+msgid "SecurityReports|Submit vulnerability"
+msgstr ""
+
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
+msgstr ""
+
+msgid "SecurityReports|The security report for this pipeline has %{helpPageLinkStart}expired%{helpPageLinkEnd}. Re-run the pipeline to generate a new security report."
+msgstr ""
+
+msgid "SecurityReports|There was an error adding the comment."
+msgstr ""
+
+msgid "SecurityReports|There was an error creating a Jira issue for the finding. Please try again."
+msgstr ""
+
+msgid "SecurityReports|There was an error creating the issue."
+msgstr ""
+
+msgid "SecurityReports|There was an error creating the issue. Please try again."
+msgstr ""
+
+msgid "SecurityReports|There was an error creating the merge request."
+msgstr ""
+
+msgid "SecurityReports|There was an error creating the merge request. Please try again."
+msgstr ""
+
+msgid "SecurityReports|There was an error deleting the comment."
+msgstr ""
+
+msgid "SecurityReports|There was an error dismissing the finding. Please try again."
+msgstr ""
+
+msgid "SecurityReports|There was an error dismissing the vulnerabilities."
+msgstr ""
+
+msgid "SecurityReports|There was an error dismissing the vulnerability."
+msgstr ""
+
+msgid "SecurityReports|There was an error fetching the finding. Please try again."
+msgstr ""
+
+msgid "SecurityReports|There was an error reverting the dismissal."
+msgstr ""
+
+msgid "SecurityReports|There was an error reverting this dismissal."
+msgstr ""
+
+msgid "SecurityReports|There was an error while generating the report."
+msgstr ""
+
+msgid "SecurityReports|These vulnerabilities were detected in external sources. They are not necessarily tied to your GitLab project. For example, running containers, URLs, and so on."
+msgstr ""
+
+msgid "SecurityReports|This selection is required."
+msgstr ""
+
+msgid "SecurityReports|To widen your search, change or remove filters above"
+msgstr ""
+
+msgid "SecurityReports|Tool"
+msgstr ""
+
+msgid "SecurityReports|Unable to add %{invalidProjectsMessage}: %{errorMessage}"
+msgstr ""
+
+msgid "SecurityReports|Undo dismiss"
+msgstr ""
+
+msgid "SecurityReports|Vulnerability report"
+msgstr ""
+
+msgid "SecurityReports|Warning parsing security reports"
+msgstr ""
+
+msgid "SecurityReports|While it's rare to have no vulnerabilities for your pipeline, it can happen. In any event, we ask that you double check your settings to make sure all security scanning jobs have passed successfully."
+msgstr ""
+
+msgid "SecurityReports|You do not have sufficient permissions to access this report"
+msgstr ""
+
+msgid "SecurityReports|You must sign in as an authorized user to see this report"
+msgstr ""
+
+msgid "SecurityReports|scanned resources"
+msgstr ""
+
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
+msgid "SecurityTraining|Primary Training"
+msgstr ""
+
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
+msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
+msgstr ""
+
+msgid "See example DevOps Score page in our documentation."
+msgstr ""
+
+msgid "See our website for help"
+msgstr ""
+
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
+msgid "See the affected projects in the GitLab admin panel"
+msgstr ""
+
+msgid "See vulnerability %{vulnerability_link} for any Remediation details."
+msgstr ""
+
+msgid "See vulnerability %{vulnerability_link} for any Solution details."
+msgstr ""
+
+msgid "Select"
+msgstr ""
+
+msgid "Select Archive Format"
+msgstr ""
+
+msgid "Select Git revision"
+msgstr ""
+
+msgid "Select Profile"
+msgstr ""
+
+msgid "Select a LDAP group"
+msgstr ""
+
+msgid "Select a branch"
+msgstr ""
+
+msgid "Select a branch to compare"
+msgstr ""
+
+msgid "Select a cluster management project"
+msgstr ""
+
+msgid "Select a color"
+msgstr ""
+
+msgid "Select a color from the color picker or from the presets below."
+msgstr ""
+
+msgid "Select a compliance framework to apply to this project. %{linkStart}How are these added?%{linkEnd}"
+msgstr ""
+
+msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
+msgstr ""
+
+msgid "Select a group"
+msgstr ""
+
+msgid "Select a label"
+msgstr ""
+
+msgid "Select a milestone"
+msgstr ""
+
+msgid "Select a new namespace"
+msgstr ""
+
+msgid "Select a project"
+msgstr ""
+
+msgid "Select a reason"
+msgstr ""
+
+msgid "Select a repository containing templates for common files."
+msgstr ""
+
+msgid "Select a role"
+msgstr ""
+
+msgid "Select a template repository"
+msgstr ""
+
+msgid "Select all"
+msgstr ""
+
+msgid "Select an assignee"
+msgstr ""
+
+msgid "Select an iteration"
+msgstr ""
+
+msgid "Select assignee"
+msgstr ""
+
+msgid "Select assignees"
+msgstr ""
+
+msgid "Select branch"
+msgstr ""
+
+msgid "Select branch or create wildcard"
+msgstr ""
+
+msgid "Select branches"
+msgstr ""
+
+msgid "Select color"
+msgstr ""
+
+msgid "Select confidentiality"
+msgstr ""
+
+msgid "Select default branch"
+msgstr ""
+
+msgid "Select due date"
+msgstr ""
+
+msgid "Select epic"
+msgstr ""
+
+msgid "Select group"
+msgstr ""
+
+msgid "Select group or project"
+msgstr ""
+
+msgid "Select health status"
+msgstr ""
+
+msgid "Select iteration"
+msgstr ""
+
+msgid "Select label"
+msgstr ""
+
+msgid "Select labels"
+msgstr ""
+
+msgid "Select labels (optional)"
+msgstr ""
+
+msgid "Select merge moment"
+msgstr ""
+
+msgid "Select milestone"
+msgstr ""
+
+msgid "Select private project"
+msgstr ""
+
+msgid "Select project"
+msgstr ""
+
+msgid "Select project to create %{type}"
+msgstr ""
+
+msgid "Select projects"
+msgstr ""
+
+msgid "Select protected branch"
+msgstr ""
+
+msgid "Select protected branches"
+msgstr ""
+
+msgid "Select report"
+msgstr ""
+
+msgid "Select reviewers"
+msgstr ""
+
+msgid "Select severity (optional)"
+msgstr ""
+
+msgid "Select source"
+msgstr ""
+
+msgid "Select source branch"
+msgstr ""
+
+msgid "Select source project"
+msgstr ""
+
+msgid "Select start date"
+msgstr ""
+
+msgid "Select status"
+msgstr ""
+
+msgid "Select strategy activation method"
+msgstr ""
+
+msgid "Select subgroup"
+msgstr ""
+
+msgid "Select subscription"
+msgstr ""
+
+msgid "Select tags"
+msgstr ""
+
+msgid "Select target branch"
+msgstr ""
+
+msgid "Select target branch or tag"
+msgstr ""
+
+msgid "Select target project"
+msgstr ""
+
+msgid "Select timezone"
+msgstr ""
+
+msgid "Select type"
+msgstr ""
+
+msgid "Selected"
+msgstr ""
+
+msgid "Selected commits"
+msgstr ""
+
+msgid "Selected for all items."
+msgstr ""
+
+msgid "Selected for some items."
+msgstr ""
+
+msgid "Selected tag is already in use. Choose another option."
+msgstr ""
+
+msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
+msgstr ""
+
+msgid "Send"
+msgstr ""
+
+msgid "Send a single email notification to Owners and Maintainers for new alerts."
+msgstr ""
+
+msgid "Send email"
+msgstr ""
+
+msgid "Send email in multipart format (HTML and plain text). Uncheck to send email messages in plain text only."
+msgstr ""
+
+msgid "Send email notification"
+msgstr ""
+
+msgid "Send emails to users upon account deactivation."
+msgstr ""
+
+msgid "Send message"
+msgstr ""
+
+msgid "Send notifications about project events to Mattermost channels."
+msgstr ""
+
+msgid "Send notifications about project events to Mattermost channels. %{docs_link}"
+msgstr ""
+
+msgid "Send notifications about project events to a Discord channel. %{docs_link}"
+msgstr ""
+
+msgid "Send report"
+msgstr ""
+
+msgid "Send service data"
+msgstr ""
+
+msgid "Sentry"
+msgstr ""
+
+msgid "Sentry API URL"
+msgstr ""
+
+msgid "Sentry event"
+msgstr ""
+
+msgid "Sep"
+msgstr ""
+
+msgid "September"
+msgstr ""
+
+msgid "SeriesFinalConjunction|and"
+msgstr ""
+
+msgid "Serve repository static objects (for example, archives and blobs) from external storage."
+msgstr ""
+
+msgid "Server (optional)"
+msgstr ""
+
+msgid "Server supports batch API only, please update your Git LFS client to version 1.0.1 and up."
+msgstr ""
+
+msgid "Server version"
+msgstr ""
+
+msgid "Service"
+msgstr ""
+
+msgid "Service Account"
+msgstr ""
+
+msgid "Service Account Key"
+msgstr ""
+
+msgid "Service Accounts"
+msgstr ""
+
+msgid "Service Accounts keys authorize GitLab to deploy your Google Cloud project"
+msgstr ""
+
+msgid "Service Desk"
+msgstr ""
+
+msgid "Service Desk Ticket"
+msgstr ""
+
+msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
+msgstr ""
+
+msgid "Service Ping payload not found in the application cache"
+msgstr ""
+
+msgid "Service account"
+msgstr ""
+
+msgid "Service account generated successfully"
+msgstr ""
+
+msgid "Service accounts"
+msgstr ""
+
+msgid "Service usage data"
+msgstr ""
+
+msgid "ServiceAccount|User does not have permission to create a service account in this namespace."
+msgstr ""
+
+msgid "ServiceAccount|User does not have permission to create a service account."
+msgstr ""
+
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
+msgid "ServiceDesk|Cannot create custom email"
+msgstr ""
+
+msgid "ServiceDesk|Cannot update custom email"
+msgstr ""
+
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
+msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
+msgstr ""
+
+msgid "ServiceDesk|Configure a custom email address"
+msgstr ""
+
+msgid "ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials."
+msgstr ""
+
+msgid "ServiceDesk|Copy Service Desk email address"
+msgstr ""
+
+msgid "ServiceDesk|Custom email address"
+msgstr ""
+
+msgid "ServiceDesk|Custom email address could not be verified."
+msgstr ""
+
+msgid "ServiceDesk|Custom email address has already been verified."
+msgstr ""
+
+msgid "ServiceDesk|Custom email address verification has already been processed and failed."
+msgstr ""
+
+msgid "ServiceDesk|Custom email already exists"
+msgstr ""
+
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
+msgid "ServiceDesk|Custom email does not exist"
+msgstr ""
+
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
+msgid "ServiceDesk|Custom email is required and must be a valid email address."
+msgstr ""
+
+msgid "ServiceDesk|Email address your customers can use to send support requests. It must support sub-addressing."
+msgstr ""
+
+msgid "ServiceDesk|Enable Service Desk"
+msgstr ""
+
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
+msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
+msgstr ""
+
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
+msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
+msgstr ""
+
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
+msgid "ServiceDesk|Minimum 8 characters long."
+msgstr ""
+
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
+msgid "ServiceDesk|Parameters missing"
+msgstr ""
+
+msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
+msgstr ""
+
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
+msgid "ServiceDesk|SMTP address is required and must be resolvable."
+msgstr ""
+
+msgid "ServiceDesk|SMTP host"
+msgstr ""
+
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
+msgid "ServiceDesk|SMTP password"
+msgstr ""
+
+msgid "ServiceDesk|SMTP password is required and must be at least 8 characters long."
+msgstr ""
+
+msgid "ServiceDesk|SMTP port"
+msgstr ""
+
+msgid "ServiceDesk|SMTP port is required and must be a port number larger than 0."
+msgstr ""
+
+msgid "ServiceDesk|SMTP username"
+msgstr ""
+
+msgid "ServiceDesk|SMTP username is required."
+msgstr ""
+
+msgid "ServiceDesk|Save and test connection"
+msgstr ""
+
+msgid "ServiceDesk|Saved custom email address and started verification."
+msgstr ""
+
+msgid "ServiceDesk|Service Desk email address to forward emails to"
+msgstr ""
+
+msgid "ServiceDesk|Service Desk is not enabled"
+msgstr ""
+
+msgid "ServiceDesk|Service Desk is not supported"
+msgstr ""
+
+msgid "ServiceDesk|Service Desk setting missing"
+msgstr ""
+
+msgid "ServiceDesk|Service Desk setting or verification object missing"
+msgstr ""
+
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
+msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
+msgstr ""
+
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
+msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
+msgstr ""
+
+msgid "ServiceDesk|User cannot manage project."
+msgstr ""
+
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
+msgid "ServiceDesk|Your users can send emails to this address:"
+msgstr ""
+
+msgid "ServicePing|Service ping is off"
+msgstr ""
+
+msgid "ServicePing|This can be changed at any time in %{link_start}your settings%{link_end}."
+msgstr ""
+
+msgid "ServicePing|To help improve GitLab, we would like to periodically %{link_start}collect usage information%{link_end}."
+msgstr ""
+
+msgid "ServicePing|To view instance-level analytics, ask an admin to turn on %{docLinkStart}service ping%{docLinkEnd}."
+msgstr ""
+
+msgid "ServicePing|Turn on service ping"
+msgstr ""
+
+msgid "ServicePing|Turn on service ping to review instance-level analytics."
+msgstr ""
+
+msgid "Session ID"
+msgstr ""
+
+msgid "Session duration (minutes)"
+msgstr ""
+
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
+msgid "Set %{epic_ref} as the parent epic."
+msgstr ""
+
+msgid "Set a default description template to be used for new issues. %{link_start}What are description templates?%{link_end}"
+msgstr ""
+
+msgid "Set a group, access level or users who are required to deploy."
+msgstr ""
+
+msgid "Set a password on your account to pull or push via %{protocol}."
+msgstr ""
+
+msgid "Set any rate limit to %{code_open}0%{code_close} to disable the limit."
+msgstr ""
+
+msgid "Set due date"
+msgstr ""
+
+msgid "Set health status"
+msgstr ""
+
+msgid "Set health status to %{health_status}."
+msgstr ""
+
+msgid "Set iteration"
+msgstr ""
+
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
+msgid "Set limits for web and API requests."
+msgstr ""
+
+msgid "Set milestone"
+msgstr ""
+
+msgid "Set new password"
+msgstr ""
+
+msgid "Set parent epic to an epic"
+msgstr ""
+
+msgid "Set per-user rate limits for imports and exports of projects and groups."
+msgstr ""
+
+msgid "Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan."
+msgstr ""
+
+msgid "Set rate limits for package registry API requests that supersede the general user and IP rate limits."
+msgstr ""
+
+msgid "Set rate limits for searches performed by web or API requests."
+msgstr ""
+
+msgid "Set severity"
+msgstr ""
+
+msgid "Set sign-in restrictions for all users."
+msgstr ""
+
+msgid "Set size limits for displaying diffs in the browser."
+msgstr ""
+
+msgid "Set target branch"
+msgstr ""
+
+msgid "Set target branch to %{branch_name}."
+msgstr ""
+
+msgid "Set the Draft status"
+msgstr ""
+
+msgid "Set the Ready status"
+msgstr ""
+
+msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
+msgstr ""
+
+msgid "Set the due date to %{due_date}."
+msgstr ""
+
+msgid "Set the iteration to %{iteration_reference}."
+msgstr ""
+
+msgid "Set the maximum number of slices allowed to run concurrently during Elasticsearch reindexing. Learn more about %{max_slices_running_link_start}maximum running slices configuration%{max_slices_link_end}."
+msgstr ""
+
+msgid "Set the maximum session time for a web terminal."
+msgstr ""
+
+msgid "Set the milestone to %{milestone_reference}."
+msgstr ""
+
+msgid "Set the per-IP address rate limit applicable to unauthenticated requests for getting a list of projects via the API."
+msgstr ""
+
+msgid "Set the per-user rate limit for getting a user by ID via the API."
+msgstr ""
+
+msgid "Set the per-user rate limit for notes created by web or API requests."
+msgstr ""
+
+msgid "Set this issue as blocked by %{target}."
+msgstr ""
+
+msgid "Set this issue as blocking %{target}."
+msgstr ""
+
+msgid "Set this number to 0 to disable the limit."
+msgstr ""
+
+msgid "Set time estimate"
+msgstr ""
+
+msgid "Set time estimate to %{time_estimate}."
+msgstr ""
+
+msgid "Set to 0 for no size limit."
+msgstr ""
+
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
+msgid "Set to auto-merge"
+msgstr ""
+
+msgid "Set up"
+msgstr ""
+
+msgid "Set up CI/CD"
+msgstr ""
+
+msgid "Set up Jira Integration"
+msgstr ""
+
+msgid "Set up a %{type} runner for a project"
+msgstr ""
+
+msgid "Set up a hardware device to enable two-factor authentication (2FA)."
+msgstr ""
+
+msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
+msgstr ""
+
+msgid "Set up new device"
+msgstr ""
+
+msgid "Set up new password"
+msgstr ""
+
+msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
+msgstr ""
+
+msgid "Set visibility of project contents. Configure import sources and Git access protocols."
+msgstr ""
+
+msgid "Set weight"
+msgstr ""
+
+msgid "Set weight to %{weight}."
+msgstr ""
+
+msgid "SetStatusModal|Clear status"
+msgstr ""
+
+msgid "SetStatusModal|Clear status after"
+msgstr ""
+
+msgid "SetStatusModal|Displays that you are busy or not able to respond"
+msgstr ""
+
+msgid "SetStatusModal|Edit status"
+msgstr ""
+
+msgid "SetStatusModal|Remove status"
+msgstr ""
+
+msgid "SetStatusModal|Set a status"
+msgstr ""
+
+msgid "SetStatusModal|Set status"
+msgstr ""
+
+msgid "SetStatusModal|Set yourself as busy"
+msgstr ""
+
+msgid "SetStatusModal|Sorry, we weren't able to set your status. Please try again later."
+msgstr ""
+
+msgid "SetStatusModal|Status updated"
+msgstr ""
+
+msgid "SetStatusModal|What's your status?"
+msgstr ""
+
+msgid "SetStatusModal|Your status resets on %{date}."
+msgstr ""
+
+msgid "Sets %{epic_ref} as parent epic."
+msgstr ""
+
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
+msgid "Sets health status to %{health_status}."
+msgstr ""
+
+msgid "Sets target branch to %{branch_name}."
+msgstr ""
+
+msgid "Sets the due date to %{due_date}."
+msgstr ""
+
+msgid "Sets the iteration to %{iteration_reference}."
+msgstr ""
+
+msgid "Sets the milestone to %{milestone_reference}."
+msgstr ""
+
+msgid "Sets the severity"
+msgstr ""
+
+msgid "Sets time estimate to %{time_estimate}."
+msgstr ""
+
+msgid "Sets weight to %{weight}."
+msgstr ""
+
+msgid "Setting"
+msgstr ""
+
+msgid "Setting enforced"
+msgstr ""
+
+msgid "Setting saved successfully"
+msgid_plural "Settings saved successfully"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Settings"
+msgstr ""
+
+msgid "Settings for the License Compliance feature"
+msgstr ""
+
+msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
+msgstr ""
+
+msgid "Severity"
+msgstr ""
+
+msgid "Severity updated to %{severity}."
+msgstr ""
+
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
+msgid "Share"
+msgstr ""
+
+msgid "Share the %{strong_open}GitLab single sign-on URL%{strong_close} with members so they can sign in to your group through your identity provider"
+msgstr ""
+
+msgid "Shared Runners"
+msgstr ""
+
+msgid "Shared Runners:"
+msgstr ""
+
+msgid "Shared projects"
+msgstr ""
+
+msgid "Shared runners"
+msgstr ""
+
+msgid "Shared runners details"
+msgstr ""
+
+msgid "Shared runners enabled cannot be enabled until a valid credit card is on file"
+msgstr ""
+
+msgid "Shared runners help link"
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|Reset compute usage"
+msgstr ""
+
+msgid "SharedRunnersMinutesSettings|When you reset the compute usage for this namespace, the compute usage changes to zero."
+msgstr ""
+
+msgid "ShellOperations|Git SSH operations rate limit"
+msgstr ""
+
+msgid "ShellOperations|Limit the number of Git operations a user can perform per minute, per repository."
+msgstr ""
+
+msgid "ShellOperations|Maximum number of Git operations per minute"
+msgstr ""
+
+msgid "Shimo|Go to Shimo Workspace"
+msgstr ""
+
+msgid "Shimo|Link to a Shimo Workspace from the sidebar."
+msgstr ""
+
+msgid "Shimo|Shimo"
+msgstr ""
+
+msgid "Shimo|Shimo Workspace"
+msgstr ""
+
+msgid "Shimo|Shimo Workspace URL"
+msgstr ""
+
+msgid "Shimo|Shimo Workspace integration is enabled"
+msgstr ""
+
+msgid "Shimo|You've enabled the Shimo Workspace integration. You can view your wiki directly in Shimo."
+msgstr ""
+
+msgid "Short name"
+msgstr ""
+
+msgid "Should these changes be private?"
+msgstr ""
+
+msgid "Should you ever lose your phone or access to your one time password secret, each of these recovery codes can be used one time each to regain access to your account. Please save them in a safe place, or you %{boldStart}will%{boldEnd} lose access to your account."
+msgstr ""
+
+msgid "Show Pipeline ID"
+msgstr ""
+
+msgid "Show Pipeline IID"
+msgstr ""
+
+msgid "Show all %{issuable_type}."
+msgstr ""
+
+msgid "Show all activity"
+msgstr ""
+
+msgid "Show all breadcrumbs"
+msgstr ""
+
+msgid "Show all epics"
+msgstr ""
+
+msgid "Show all issues."
+msgstr ""
+
+msgid "Show all milestones"
+msgstr ""
+
+msgid "Show all test cases."
+msgstr ""
+
+msgid "Show archived projects"
+msgstr ""
+
+msgid "Show archived projects only"
+msgstr ""
+
+msgid "Show changes"
+msgstr ""
+
+msgid "Show closed epics"
+msgstr ""
+
+msgid "Show command"
+msgstr ""
+
+msgid "Show comments"
+msgstr ""
+
+msgid "Show comments on this file"
+msgstr ""
+
+msgid "Show comments only"
+msgstr ""
+
+msgid "Show complete raw log"
+msgstr ""
+
+msgid "Show details"
+msgstr ""
+
+msgid "Show file browser (or press F)"
+msgstr ""
+
+msgid "Show file contents"
+msgstr ""
+
+msgid "Show full blame"
+msgstr ""
+
+msgid "Show group milestones"
+msgstr ""
+
+msgid "Show labels"
+msgstr ""
+
+msgid "Show latest version"
+msgstr ""
+
+msgid "Show less"
+msgstr ""
+
+msgid "Show list"
+msgstr ""
+
+msgid "Show more"
+msgstr ""
+
+msgid "Show one file at a time"
+msgstr ""
+
+msgid "Show open epics"
+msgstr ""
+
+msgid "Show password"
+msgstr ""
+
+msgid "Show project milestones"
+msgstr ""
+
+msgid "Show sidebar"
+msgstr ""
+
+msgid "Show sub-group milestones"
+msgstr ""
+
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
+msgid "Show thread"
+msgstr ""
+
+msgid "Show whitespace changes"
+msgstr ""
+
+msgid "ShowcaseSecurity|Access a dedicated area for vulnerability management. This includes a security dashboard, vulnerability report, and settings."
+msgstr ""
+
+msgid "ShowcaseSecurity|Audit your Docker-based app. Scan for known vulnerabilities in the Docker images where your code is shipped."
+msgstr ""
+
+msgid "ShowcaseSecurity|Container scanning"
+msgstr ""
+
+msgid "ShowcaseSecurity|Dependency scanning"
+msgstr ""
+
+msgid "ShowcaseSecurity|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
+msgid "ShowcaseSecurity|Dynamically examine your application for vulnerabilities in deployed environments."
+msgstr ""
+
+msgid "ShowcaseSecurity|Enable SAST"
+msgstr ""
+
+msgid "ShowcaseSecurity|Enable Secret Detection"
+msgstr ""
+
+msgid "ShowcaseSecurity|Enable Static Application Security Testing (SAST)"
+msgstr ""
+
+msgid "ShowcaseSecurity|Find out if your external libraries are safe. Run dependency scanning jobs that check for known vulnerabilities in your external libraries."
+msgstr ""
+
+msgid "ShowcaseSecurity|Identify vulnerabilities in your code now"
+msgstr ""
+
+msgid "ShowcaseSecurity|Scan your code to detect unintentionally committed secrets, like keys, passwords, and API tokens."
+msgstr ""
+
+msgid "ShowcaseSecurity|Scan your source code using GitLab CI/CD and uncover vulnerabilities before deploying."
+msgstr ""
+
+msgid "ShowcaseSecurity|Start a free 30-day Ultimate trial or upgrade your instance to access organization-wide security and compliance features. See the other features of the Ultimate plan."
+msgstr ""
+
+msgid "ShowcaseSecurity|Start a free trial"
+msgstr ""
+
+msgid "ShowcaseSecurity|Take your security to the next level"
+msgstr ""
+
+msgid "ShowcaseSecurity|Upgrade now"
+msgstr ""
+
+msgid "ShowcaseSecurity|Use GitLab CI/CD to analyze your source code for known vulnerabilities. Compare the found vulnerabilities between your source and target branches."
+msgstr ""
+
+msgid "ShowcaseSecurity|Vulnerability management"
+msgstr ""
+
+msgid "Showing %{conflict}"
+msgstr ""
+
+msgid "Showing %{count} of %{total} projects"
+msgstr ""
+
+msgid "Showing %{count} project"
+msgid_plural "Showing %{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Showing %{limit} of %{total_count} issues. "
+msgstr ""
+
+msgid "Showing %{pageSize} of %{total} %{issuableType}"
+msgstr ""
+
+msgid "Showing all epics"
+msgstr ""
+
+msgid "Showing all issues"
+msgstr ""
+
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
+msgstr ""
+
+msgid "Showing first 50 actions."
+msgstr ""
+
+msgid "Showing last %{size} of log -"
+msgstr ""
+
+msgid "Showing latest version"
+msgstr ""
+
+msgid "Showing version #%{versionNumber}"
+msgstr ""
+
+msgid "Side-by-side"
+msgstr ""
+
+msgid "Sidebar|%{name}: %{value}"
+msgstr ""
+
+msgid "Sidebar|Assign health status"
+msgstr ""
+
+msgid "Sidebar|Health status"
+msgstr ""
+
+msgid "Sidebar|No status"
+msgstr ""
+
+msgid "Sidebar|None"
+msgstr ""
+
+msgid "Sidekiq job compression threshold (bytes)"
+msgstr ""
+
+msgid "Sidekiq job size limit (bytes)"
+msgstr ""
+
+msgid "Sidekiq job size limits"
+msgstr ""
+
+msgid "Sign in"
+msgstr ""
+
+msgid "Sign in as a user with the matching email address, add the email to this account, or sign-up for a new account using the matching email."
+msgstr ""
+
+msgid "Sign in preview"
+msgstr ""
+
+msgid "Sign in to GitLab"
+msgstr ""
+
+msgid "Sign in using smart card"
+msgstr ""
+
+msgid "Sign in via 2FA code"
+msgstr ""
+
+msgid "Sign in with"
+msgstr ""
+
+msgid "Sign in with single sign-on"
+msgstr ""
+
+msgid "Sign in with smart card"
+msgstr ""
+
+msgid "Sign in/Sign up pages"
+msgstr ""
+
+msgid "Sign out"
+msgstr ""
+
+msgid "Sign out & Register"
+msgstr ""
+
+msgid "Sign up"
+msgstr ""
+
+msgid "Sign up was successful! Please confirm your email to sign in."
+msgstr ""
+
+msgid "Sign-in and Help page"
+msgstr ""
+
+msgid "Sign-in count:"
+msgstr ""
+
+msgid "Sign-in page"
+msgstr ""
+
+msgid "Sign-in restrictions"
+msgstr ""
+
+msgid "Sign-in text"
+msgstr ""
+
+msgid "Sign-in using %{provider} auth failed"
+msgstr ""
+
+msgid "Sign-out page URL"
+msgstr ""
+
+msgid "Sign-up restrictions"
+msgstr ""
+
+msgid "SignUp|By clicking %{button_text} or registering through a third party you accept the GitLab%{link_start} Terms of Use and acknowledge the Privacy Policy and Cookie Policy%{link_end}"
+msgstr ""
+
+msgid "SignUp|By clicking %{button_text} or registering through a third party you accept the%{link_start} Terms of Use and acknowledge the Privacy Policy and Cookie Policy%{link_end}"
+msgstr ""
+
+msgid "SignUp|By clicking %{button_text}, I agree that I have read and accepted the %{link_start}Terms of Use and Privacy Policy%{link_end}"
+msgstr ""
+
+msgid "SignUp|By clicking %{button_text}, I agree that I have read and accepted the GitLab %{link_start}Terms of Use and Privacy Policy%{link_end}"
+msgstr ""
+
+msgid "SignUp|By signing in you accept the %{link_start}Terms of Use and acknowledge the Privacy Policy and Cookie Policy%{link_end}."
+msgstr ""
+
+msgid "SignUp|First name is too long (maximum is %{max_length} characters)."
+msgstr ""
+
+msgid "SignUp|Last name is too long (maximum is %{max_length} characters)."
+msgstr ""
+
+msgid "SignUp|Minimum length is %{minimum_password_length} characters."
+msgstr ""
+
+msgid "SignUp|Username is too long (maximum is %{max_length} characters)."
+msgstr ""
+
+msgid "SignUp|Username is too short (minimum is %{min_length} characters)."
+msgstr ""
+
+msgid "Signed in"
+msgstr ""
+
+msgid "Signed in to GitLab"
+msgstr ""
+
+msgid "Signed in to GitLab as %{user_link}"
+msgstr ""
+
+msgid "Signed in with %{authentication} authentication"
+msgstr ""
+
+msgid "Signing in using %{label} has been disabled"
+msgstr ""
+
+msgid "Signing in using your %{label} account without a pre-existing GitLab account is not allowed."
+msgstr ""
+
+msgid "Similar issues"
+msgstr ""
+
+msgid "Simulate a pipeline created for the default branch"
+msgstr ""
+
+msgid "Site profile failed to delete"
+msgstr ""
+
+msgid "Site profile not found for given parameters"
+msgstr ""
+
+msgid "Sites"
+msgstr ""
+
+msgid "Size"
+msgstr ""
+
+msgid "Size Limits"
+msgstr ""
+
+msgid "Size limit per repository (MiB)"
+msgstr ""
+
+msgid "Skip to main content"
+msgstr ""
+
+msgid "Skipped"
+msgstr ""
+
+msgid "Skipped deployment to"
+msgstr ""
+
+msgid "Skype:"
+msgstr ""
+
+msgid "Slack logo"
+msgstr ""
+
+msgid "Slack notifications integration is deprecated"
+msgstr ""
+
+msgid "Slack notifications will be brought into the GitLab for Slack app so you can manage both integrations from one place. %{learn_more_link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "Slack notifications will be deprecated"
+msgstr ""
+
+msgid "SlackIntegration|- *Notifications:* Get notifications to your team's Slack channel about events happening inside your GitLab projects."
+msgstr ""
+
+msgid "SlackIntegration|- *Slash commands:* Quickly open, access, or close issues from Slack using the `%{slash_command}` command. Streamline your GitLab deployments with ChatOps."
+msgstr ""
+
+msgid "SlackIntegration|Are you sure you want to remove this project from the GitLab for Slack app?"
+msgstr ""
+
+msgid "SlackIntegration|Client ID"
+msgstr ""
+
+msgid "SlackIntegration|Client secret"
+msgstr ""
+
+msgid "SlackIntegration|Configure your GitLab for Slack app."
+msgstr ""
+
+msgid "SlackIntegration|Copy the %{link_start}settings%{link_end} from %{strong_open}%{settings_heading}%{strong_close} in your GitLab for Slack app."
+msgstr ""
+
+msgid "SlackIntegration|Create Slack app"
+msgstr ""
+
+msgid "SlackIntegration|Create and read issue data and comments."
+msgstr ""
+
+msgid "SlackIntegration|Download latest manifest file"
+msgstr ""
+
+msgid "SlackIntegration|Generated for %{host} by GitLab %{version}."
+msgstr ""
+
+msgid "SlackIntegration|GitLab for Slack"
+msgstr ""
+
+msgid "SlackIntegration|GitLab for Slack was successfully installed."
+msgstr ""
+
+msgid "SlackIntegration|GitLab slash commands"
+msgstr ""
+
+msgid "SlackIntegration|Install GitLab for Slack app…"
+msgstr ""
+
+msgid "SlackIntegration|Interact with GitLab without leaving your Slack workspace!"
+msgstr ""
+
+msgid "SlackIntegration|Perform deployments."
+msgstr ""
+
+msgid "SlackIntegration|Project alias"
+msgstr ""
+
+msgid "SlackIntegration|Reinstall GitLab for Slack app…"
+msgstr ""
+
+msgid "SlackIntegration|Remove project"
+msgstr ""
+
+msgid "SlackIntegration|Run ChatOps jobs."
+msgstr ""
+
+msgid "SlackIntegration|See the list of available commands in Slack after setting up this integration by entering"
+msgstr ""
+
+msgid "SlackIntegration|Select a GitLab project to link with your Slack workspace."
+msgstr ""
+
+msgid "SlackIntegration|Sends notifications about project events to Slack channels."
+msgstr ""
+
+msgid "SlackIntegration|Signing secret"
+msgstr ""
+
+msgid "SlackIntegration|Step 1: Create your GitLab for Slack app"
+msgstr ""
+
+msgid "SlackIntegration|Step 2: Configure the app settings"
+msgstr ""
+
+msgid "SlackIntegration|Team name"
+msgstr ""
+
+msgid "SlackIntegration|This integration allows users to perform common operations on this project by entering slash commands in Slack."
+msgstr ""
+
+msgid "SlackIntegration|Update to the latest version"
+msgstr ""
+
+msgid "SlackIntegration|Update to the latest version of GitLab for Slack to get notifications"
+msgstr ""
+
+msgid "SlackIntegration|Update to the latest version to receive notifications from GitLab."
+msgstr ""
+
+msgid "SlackIntegration|Update your Slack app"
+msgstr ""
+
+msgid "SlackIntegration|Used for authenticating API requests from the GitLab for Slack app."
+msgstr ""
+
+msgid "SlackIntegration|Used for authenticating OAuth requests from the GitLab for Slack app."
+msgstr ""
+
+msgid "SlackIntegration|Used only for authenticating slash commands from the GitLab for Slack app. This method of authentication is deprecated by Slack."
+msgstr ""
+
+msgid "SlackIntegration|Verification token"
+msgstr ""
+
+msgid "SlackIntegration|When GitLab releases new features for the GitLab for Slack app, you might have to manually update your copy to use the new features."
+msgstr ""
+
+msgid "SlackIntegration|You can now close this window and go to your Slack workspace."
+msgstr ""
+
+msgid "SlackIntegration|You don't have to reauthorize this application if the permission scope changes in future releases."
+msgstr ""
+
+msgid "SlackIntegration|You may need to reinstall the GitLab for Slack app when we %{linkStart}make updates or change permissions%{linkEnd}."
+msgstr ""
+
+msgid "SlackIntegration|You must do this step only once."
+msgstr ""
+
+msgid "SlackIntegration|cannot have more than %{limit} channels"
+msgstr ""
+
+msgid "SlackIntegration|your-project-name-or-alias command"
+msgstr ""
+
+msgid "SlackModal|Are you sure you want to change the project?"
+msgstr ""
+
+msgid "SlackModal|If you change the project, you'll lose any text entered in the form."
+msgstr ""
+
+msgid "SlackModal|If you've entered some text, consider saving it somewhere to avoid losing any content."
+msgstr ""
+
+msgid "SlackService|1. %{slash_command_link_start}Add a slash command%{slash_command_link_end} in your Slack team using this information:"
+msgstr ""
+
+msgid "SlackService|2. Paste the token from Slack in the %{strong_open}Token%{strong_close} field below."
+msgstr ""
+
+msgid "SlackService|3. Select the %{strong_open}Active%{strong_close} checkbox, select %{strong_open}Save changes%{strong_close}, and start using slash commands in Slack!"
+msgstr ""
+
+msgid "SlackService|After setup, get a list of available Slack slash commands by entering"
+msgstr ""
+
+msgid "SlackService|Fill in the word that works best for your team."
+msgstr ""
+
+msgid "SlackService|Perform common operations in this project by entering slash commands in Slack."
+msgstr ""
+
+msgid "Slack|%{asterisk}Channel notifications%{asterisk}"
+msgstr ""
+
+msgid "Slack|%{asterisk}Slash commands%{asterisk}"
+msgstr ""
+
+msgid "Slack|%{emoji}Connected to GitLab account %{account}."
+msgstr ""
+
+msgid "Slack|%{emoji}Welcome to GitLab for Slack!"
+msgstr ""
+
+msgid "Slack|Connect your GitLab account"
+msgstr ""
+
+msgid "Slack|Control GitLab from Slack with %{startMarkup}slash commands%{endMarkup}. For a list of available commands, enter %{command}."
+msgstr ""
+
+msgid "Slack|GitLab for Slack now supports channel-based notifications. Let your team know when new issues are created or new CI/CD jobs are run.%{startMarkup}Learn more%{endMarkup}."
+msgstr ""
+
+msgid "Slack|To start using notifications, %{startMarkup}enable the GitLab for Slack app integration%{endMarkup} in your project settings."
+msgstr ""
+
+msgid "Slack|To start using slash commands, connect your GitLab account."
+msgstr ""
+
+msgid "Slice multiplier"
+msgstr ""
+
+msgid "Smartcard"
+msgstr ""
+
+msgid "Smartcard authentication failed: client certificate header is missing."
+msgstr ""
+
+msgid "Snippet"
+msgstr ""
+
+msgid "Snippets"
+msgstr ""
+
+msgid "Snippets with non-text files can only be edited via Git."
+msgstr ""
+
+msgid "SnippetsEmptyState|Code snippets"
+msgstr ""
+
+msgid "SnippetsEmptyState|Documentation"
+msgstr ""
+
+msgid "SnippetsEmptyState|New snippet"
+msgstr ""
+
+msgid "SnippetsEmptyState|No snippets found"
+msgstr ""
+
+msgid "SnippetsEmptyState|Store, share, and embed small pieces of code and text."
+msgstr ""
+
+msgid "SnippetsEmptyState|There are no snippets to show."
+msgstr ""
+
+msgid "Snippets|%{spammable_titlecase} was submitted to Akismet successfully."
+msgstr ""
+
+msgid "Snippets|Add another file %{num}/%{total}"
+msgstr ""
+
+msgid "Snippets|Delete file"
+msgstr ""
+
+msgid "Snippets|Describe what your snippet does or how to use it…"
+msgstr ""
+
+msgid "Snippets|Description (optional)"
+msgstr ""
+
+msgid "Snippets|Error with Akismet. Please check the logs for more info."
+msgstr ""
+
+msgid "Snippets|File name (e.g. test.rb)"
+msgstr ""
+
+msgid "Snippets|Files"
+msgstr ""
+
+msgid "Snippets|Snippets are limited to %{total} files."
+msgstr ""
+
+msgid "Snippets|Snippets can't contain empty files. Ensure all files have content, or delete them."
+msgstr ""
+
+msgid "Snowplow"
+msgstr ""
+
+msgid "Soft wrap"
+msgstr ""
+
+msgid "Solid"
+msgstr ""
+
+msgid "Solution"
+msgstr ""
+
+msgid "Some changes are not shown"
+msgstr ""
+
+msgid "Some changes are not shown."
+msgstr ""
+
+msgid "Some child epics may be hidden due to applied filters"
+msgstr ""
+
+msgid "Some common domains are not allowed. %{learn_more_link}."
+msgstr ""
+
+msgid "Someone edited the %{issuableType} at the same time you did. Review %{linkStart}the %{issuableType}%{linkEnd} and make sure you don't unintentionally overwrite their changes."
+msgstr ""
+
+msgid "Someone edited the file the same time you did. Please check out %{link_start}the file %{icon}%{link_end} and make sure your changes will not unintentionally remove theirs."
+msgstr ""
+
+msgid "Someone edited this %{issueType} at the same time you did. The description has been updated and you will need to make your changes again."
+msgstr ""
+
+msgid "Someone edited this %{model_name} at the same time you did. Please check out the %{link_to_model} and make sure your changes will not unintentionally remove theirs."
+msgstr ""
+
+msgid "Someone edited this %{model_name} at the same time you did. Please refresh your browser and make sure your changes will not unintentionally remove theirs."
+msgstr ""
+
+msgid "Someone edited this merge request at the same time you did. Please refresh the page to see changes."
+msgstr ""
+
+msgid "Someone edited this milestone at the same time you did. Please refresh the page to see changes."
+msgstr ""
+
+msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
+msgstr ""
+
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
+msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
+msgstr ""
+
+msgid "Something else"
+msgstr ""
+
+msgid "Something went wrong"
+msgstr ""
+
+msgid "Something went wrong on our end"
+msgstr ""
+
+msgid "Something went wrong on our end."
+msgstr ""
+
+msgid "Something went wrong on our end. Please try again!"
+msgstr ""
+
+msgid "Something went wrong on our end. Please try again."
+msgstr ""
+
+msgid "Something went wrong trying to change the locked state of this %{issuableDisplayName}"
+msgstr ""
+
+msgid "Something went wrong trying to load issue contacts."
+msgstr ""
+
+msgid "Something went wrong when deleting a comment. Please try again"
+msgstr ""
+
+msgid "Something went wrong when deleting a comment. Please try again."
+msgstr ""
+
+msgid "Something went wrong when reordering designs. Please try again"
+msgstr ""
+
+msgid "Something went wrong when sending the incident link to Slack."
+msgstr ""
+
+msgid "Something went wrong when updating a comment. Please try again"
+msgstr ""
+
+msgid "Something went wrong while adding timeline event."
+msgstr ""
+
+msgid "Something went wrong while adding your award. Please try again."
+msgstr ""
+
+msgid "Something went wrong while applying the batch of suggestions. Please try again."
+msgstr ""
+
+msgid "Something went wrong while applying the suggestion. Please try again."
+msgstr ""
+
+msgid "Something went wrong while archiving a requirement."
+msgstr ""
+
+msgid "Something went wrong while closing the epic. Please try again later."
+msgstr ""
+
+msgid "Something went wrong while closing the incident form."
+msgstr ""
+
+msgid "Something went wrong while closing the merge request. Please try again later."
+msgstr ""
+
+msgid "Something went wrong while creating a requirement."
+msgstr ""
+
+msgid "Something went wrong while deleting description changes. Please try again."
+msgstr ""
+
+msgid "Something went wrong while deleting the source branch. Please try again."
+msgstr ""
+
+msgid "Something went wrong while deleting your note. Please try again."
+msgstr ""
+
+msgid "Something went wrong while deploying this environment. Please try again."
+msgstr ""
+
+msgid "Something went wrong while editing your comment. Please try again."
+msgstr ""
+
+msgid "Something went wrong while exporting requirements"
+msgstr ""
+
+msgid "Something went wrong while fetching branches"
+msgstr ""
+
+msgid "Something went wrong while fetching comments. Please try again."
+msgstr ""
+
+msgid "Something went wrong while fetching description changes. Please try again."
+msgstr ""
+
+msgid "Something went wrong while fetching details"
+msgstr ""
+
+msgid "Something went wrong while fetching projects"
+msgstr ""
+
+msgid "Something went wrong while fetching projects."
+msgstr ""
+
+msgid "Something went wrong while fetching related merge requests."
+msgstr ""
+
+msgid "Something went wrong while fetching requirements count."
+msgstr ""
+
+msgid "Something went wrong while fetching requirements list."
+msgstr ""
+
+msgid "Something went wrong while fetching source branches."
+msgstr ""
+
+msgid "Something went wrong while fetching the environments for this merge request. Please try again."
+msgstr ""
+
+msgid "Something went wrong while fetching the packages list."
+msgstr ""
+
+msgid "Something went wrong while obtaining the Let's Encrypt certificate."
+msgstr ""
+
+msgid "Something went wrong while opening the incident form."
+msgstr ""
+
+msgid "Something went wrong while promoting the issue to an epic. Please try again."
+msgstr ""
+
+msgid "Something went wrong while promoting the note to timeline event."
+msgstr ""
+
+msgid "Something went wrong while reopening a requirement."
+msgstr ""
+
+msgid "Something went wrong while reopening the epic. Please try again later."
+msgstr ""
+
+msgid "Something went wrong while reopening the merge request. Please try again later."
+msgstr ""
+
+msgid "Something went wrong while resolving this discussion. Please try again."
+msgstr ""
+
+msgid "Something went wrong while setting %{issuableType} %{dateType} date."
+msgstr ""
+
+msgid "Something went wrong while setting %{issuableType} confidentiality."
+msgstr ""
+
+msgid "Something went wrong while setting %{issuableType} health status."
+msgstr ""
+
+msgid "Something went wrong while setting %{issuableType} notifications."
+msgstr ""
+
+msgid "Something went wrong while setting %{issuableType} to-do item."
+msgstr ""
+
+msgid "Something went wrong while setting %{issuableType} weight."
+msgstr ""
+
+msgid "Something went wrong while stopping this environment. Please try again."
+msgstr ""
+
+msgid "Something went wrong while updating a requirement."
+msgstr ""
+
+msgid "Something went wrong while updating assignees"
+msgstr ""
+
+msgid "Something went wrong while updating the modal."
+msgstr ""
+
+msgid "Something went wrong while updating your list settings"
+msgstr ""
+
+msgid "Something went wrong with your automatic subscription renewal."
+msgstr ""
+
+msgid "Something went wrong, unable to add %{project} to dashboard"
+msgstr ""
+
+msgid "Something went wrong, unable to delete project"
+msgstr ""
+
+msgid "Something went wrong, unable to get projects"
+msgstr ""
+
+msgid "Something went wrong, unable to search projects"
+msgstr ""
+
+msgid "Something went wrong. Please try again later"
+msgstr ""
+
+msgid "Something went wrong. Please try again."
+msgstr ""
+
+msgid "Something went wrong. Try again later."
+msgstr ""
+
+msgid "Something went wrong. Unable to create phone exemption."
+msgstr ""
+
+msgid "Something went wrong. Unable to remove phone exemption."
+msgstr ""
+
+msgid "Sorry, no projects matched your search"
+msgstr ""
+
+msgid "Sorry, you have exceeded the maximum browsable page number. Please use the API to explore further."
+msgstr ""
+
+msgid "Sorry, your filter produced no results"
+msgstr ""
+
+msgid "Sort by"
+msgstr ""
+
+msgid "Sort direction"
+msgstr ""
+
+msgid "Sort direction: Ascending"
+msgstr ""
+
+msgid "Sort direction: Descending"
+msgstr ""
+
+msgid "Sort or filter"
+msgstr ""
+
+msgid "SortOptions|Blocking"
+msgstr ""
+
+msgid "SortOptions|Closed date"
+msgstr ""
+
+msgid "SortOptions|Closed earlier"
+msgstr ""
+
+msgid "SortOptions|Closed recently"
+msgstr ""
+
+msgid "SortOptions|Created date"
+msgstr ""
+
+msgid "SortOptions|Due date"
+msgstr ""
+
+msgid "SortOptions|Due later"
+msgstr ""
+
+msgid "SortOptions|Due soon"
+msgstr ""
+
+msgid "SortOptions|Expired date"
+msgstr ""
+
+msgid "SortOptions|Label priority"
+msgstr ""
+
+msgid "SortOptions|Largest group"
+msgstr ""
+
+msgid "SortOptions|Largest repository"
+msgstr ""
+
+msgid "SortOptions|Last Contact"
+msgstr ""
+
+msgid "SortOptions|Last created"
+msgstr ""
+
+msgid "SortOptions|Latest version"
+msgstr ""
+
+msgid "SortOptions|Least popular"
+msgstr ""
+
+msgid "SortOptions|Less weight"
+msgstr ""
+
+msgid "SortOptions|Manual"
+msgstr ""
+
+msgid "SortOptions|Merged date"
+msgstr ""
+
+msgid "SortOptions|Merged earlier"
+msgstr ""
+
+msgid "SortOptions|Merged recently"
+msgstr ""
+
+msgid "SortOptions|Milestone due date"
+msgstr ""
+
+msgid "SortOptions|Milestone due later"
+msgstr ""
+
+msgid "SortOptions|Milestone due soon"
+msgstr ""
+
+msgid "SortOptions|More weight"
+msgstr ""
+
+msgid "SortOptions|Most popular"
+msgstr ""
+
+msgid "SortOptions|Most stars"
+msgstr ""
+
+msgid "SortOptions|Name"
+msgstr ""
+
+msgid "SortOptions|Name, ascending"
+msgstr ""
+
+msgid "SortOptions|Name, descending"
+msgstr ""
+
+msgid "SortOptions|Oldest created"
+msgstr ""
+
+msgid "SortOptions|Oldest last activity"
+msgstr ""
+
+msgid "SortOptions|Oldest sign in"
+msgstr ""
+
+msgid "SortOptions|Oldest starred"
+msgstr ""
+
+msgid "SortOptions|Oldest updated"
+msgstr ""
+
+msgid "SortOptions|Oldest version"
+msgstr ""
+
+msgid "SortOptions|Popularity"
+msgstr ""
+
+msgid "SortOptions|Priority"
+msgstr ""
+
+msgid "SortOptions|Project"
+msgstr ""
+
+msgid "SortOptions|Recent last activity"
+msgstr ""
+
+msgid "SortOptions|Recent sign in"
+msgstr ""
+
+msgid "SortOptions|Recently starred"
+msgstr ""
+
+msgid "SortOptions|Size"
+msgstr ""
+
+msgid "SortOptions|Sort by:"
+msgstr ""
+
+msgid "SortOptions|Sort direction"
+msgstr ""
+
+msgid "SortOptions|Stars"
+msgstr ""
+
+msgid "SortOptions|Start date"
+msgstr ""
+
+msgid "SortOptions|Start later"
+msgstr ""
+
+msgid "SortOptions|Start soon"
+msgstr ""
+
+msgid "SortOptions|Title"
+msgstr ""
+
+msgid "SortOptions|Type"
+msgstr ""
+
+msgid "SortOptions|Version"
+msgstr ""
+
+msgid "SortOptions|Weight"
+msgstr ""
+
+msgid "Source"
+msgstr ""
+
+msgid "Source (branch or tag)"
+msgstr ""
+
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source IP"
+msgstr ""
+
+msgid "Source branch"
+msgstr ""
+
+msgid "Source branch does not exist"
+msgstr ""
+
+msgid "Source branch is protected from force push"
+msgstr ""
+
+msgid "Source branch will be deleted."
+msgstr ""
+
+msgid "Source branch will not be deleted."
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
+msgid "Source code (%{fileExtension})"
+msgstr ""
+
+msgid "Source is not available"
+msgstr ""
+
+msgid "Source project"
+msgstr ""
+
+msgid "Source project cannot be found."
+msgstr ""
+
+msgid "SourceEditor|\"el\" parameter is required for createInstance()"
+msgstr ""
+
+msgid "SourceEditor|%{name} is not registered."
+msgstr ""
+
+msgid "SourceEditor|Extension definition should be either a class or a function"
+msgstr ""
+
+msgid "SourceEditor|Extension definition should be either class, function, or an Array of definitions."
+msgstr ""
+
+msgid "SourceEditor|Extensions Store is required to check for an extension."
+msgstr ""
+
+msgid "SourceEditor|Name conflict for \"%{prop}()\" method."
+msgstr ""
+
+msgid "SourceEditor|No extension for unuse has been specified."
+msgstr ""
+
+msgid "SourceEditor|`definition` property is expected on the extension."
+msgstr ""
+
+msgid "Sourcegraph"
+msgstr ""
+
+msgid "SourcegraphAdmin|Block on private and internal projects"
+msgstr ""
+
+msgid "SourcegraphAdmin|Configure the URL to a Sourcegraph instance which can read your GitLab projects."
+msgstr ""
+
+msgid "SourcegraphAdmin|Enable Sourcegraph"
+msgstr ""
+
+msgid "SourcegraphAdmin|Enable code intelligence powered by %{link_start}Sourcegraph%{link_end} on your GitLab instance's code views and merge requests."
+msgstr ""
+
+msgid "SourcegraphAdmin|Learn more."
+msgstr ""
+
+msgid "SourcegraphAdmin|Only public projects have code intelligence enabled and communicate with Sourcegraph."
+msgstr ""
+
+msgid "SourcegraphAdmin|Save changes"
+msgstr ""
+
+msgid "SourcegraphAdmin|Sourcegraph URL"
+msgstr ""
+
+msgid "SourcegraphAdmin|https://sourcegraph.example.com"
+msgstr ""
+
+msgid "SourcegraphPreferences|This feature is experimental and currently limited to certain projects."
+msgstr ""
+
+msgid "SourcegraphPreferences|This feature is experimental and limited to public projects."
+msgstr ""
+
+msgid "SourcegraphPreferences|This feature is experimental."
+msgstr ""
+
+msgid "SourcegraphPreferences|Uses %{linkStart}Sourcegraph.com%{linkEnd}."
+msgstr ""
+
+msgid "SourcegraphPreferences|Uses a custom %{linkStart}Sourcegraph instance%{linkEnd}."
+msgstr ""
+
+msgid "Spam Check"
+msgstr ""
+
+msgid "Spam Check API key"
+msgstr ""
+
+msgid "Spam Logs"
+msgstr ""
+
+msgid "Spam and Anti-bot Protection"
+msgstr ""
+
+msgid "Spam log successfully submitted as ham."
+msgstr ""
+
+msgid "Specific branches"
+msgstr ""
+
+msgid "Specified URL cannot be used: \"%{reason}\""
+msgstr ""
+
+msgid "Specifies that this issue blocks other issues"
+msgstr ""
+
+msgid "Specify IP ranges that are always allowed for inbound traffic, for use with group-level IP restrictions. Runner and Pages daemon internal IPs should be listed here so that they can access project artifacts."
+msgstr ""
+
+msgid "Specify an email address regex pattern to identify default internal users."
+msgstr ""
+
+msgid "Speed up your pipelines with Needs relationships"
+msgstr ""
+
+msgid "Spent at"
+msgstr ""
+
+msgid "Spent at can't be a future date and time."
+msgstr ""
+
+msgid "Split cell"
+msgstr ""
+
+msgid "Squash commit message"
+msgstr ""
+
+msgid "Squash commits"
+msgstr ""
+
+msgid "Squash commits when merge request is accepted."
+msgstr ""
+
+msgid "SquashTmIntegration|Secret token (optional)"
+msgstr ""
+
+msgid "SquashTmIntegration|Squash TM webhook URL"
+msgstr ""
+
+msgid "SquashTmIntegration|Update Squash TM requirements when GitLab issues are modified."
+msgstr ""
+
+msgid "SquashTmIntegration|Update Squash TM requirements when GitLab issues are modified. %{docs_link}"
+msgstr ""
+
+msgid "Stack trace"
+msgstr ""
+
+msgid "Stacktrace snippet"
+msgstr ""
+
+msgid "Stage"
+msgstr ""
+
+msgid "Stage:"
+msgstr ""
+
+msgid "Standard"
+msgstr ""
+
+msgid "Star labels to start sorting by priority."
+msgstr ""
+
+msgid "Star toggle failed. Try again later."
+msgstr ""
+
+msgid "StarProject|Star"
+msgstr ""
+
+msgid "Starred Projects"
+msgstr ""
+
+msgid "Starred Projects' Activity"
+msgstr ""
+
+msgid "Starred projects"
+msgstr ""
+
+msgid "StarredProjectsEmptyState|Visit a project page and press on a star icon. Then, you can find the project on this page."
+msgstr ""
+
+msgid "StarredProjectsEmptyState|You don't have starred projects yet."
+msgstr ""
+
+msgid "Starrers"
+msgstr ""
+
+msgid "Stars"
+msgstr ""
+
+msgid "Start Date"
+msgstr ""
+
+msgid "Start GitLab Ultimate free trial"
+msgstr ""
+
+msgid "Start Time"
+msgstr ""
+
+msgid "Start Web Terminal"
+msgstr ""
+
+msgid "Start a %{new_merge_request} with these changes"
+msgstr ""
+
+msgid "Start a Free Ultimate Trial"
+msgstr ""
+
+msgid "Start a new merge request with these changes"
+msgstr ""
+
+msgid "Start a review"
+msgstr ""
+
+msgid "Start another thread"
+msgstr ""
+
+msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
+msgstr ""
+
+msgid "Start cleanup"
+msgstr ""
+
+msgid "Start date"
+msgstr ""
+
+msgid "Start free trial"
+msgstr ""
+
+msgid "Start inputting changes and we will generate a YAML-file for you to add to your repository"
+msgstr ""
+
+msgid "Start internal thread"
+msgstr ""
+
+msgid "Start merge train"
+msgstr ""
+
+msgid "Start merge train..."
+msgstr ""
+
+msgid "Start remote connection"
+msgstr ""
+
+msgid "Start search"
+msgstr ""
+
+msgid "Start thread"
+msgstr ""
+
+msgid "Start time"
+msgstr ""
+
+msgid "Start your Free Ultimate Trial"
+msgstr ""
+
+msgid "Start your free trial"
+msgstr ""
+
+msgid "Started"
+msgstr ""
+
+msgid "Started %{startsIn}"
+msgstr ""
+
+msgid "Started asynchronous removal of all repository check states."
+msgstr ""
+
+msgid "Started escalation for this incident."
+msgstr ""
+
+msgid "Starting..."
+msgstr ""
+
+msgid "Starts"
+msgstr ""
+
+msgid "Starts %{startsIn}"
+msgstr ""
+
+msgid "Starts escalations for this incident"
+msgstr ""
+
+msgid "Starts on"
+msgstr ""
+
+msgid "Starts: %{startsAt}"
+msgstr ""
+
+msgid "State your message to activate"
+msgstr ""
+
+msgid "State/Province"
+msgstr ""
+
+msgid "State/Province/City"
+msgstr ""
+
+msgid "Static Application Security Testing (SAST)"
+msgstr ""
+
+msgid "Statistics"
+msgstr ""
+
+msgid "Status"
+msgstr ""
+
+msgid "Status (optional)"
+msgstr ""
+
+msgid "Status was retried."
+msgstr ""
+
+msgid "Status:"
+msgstr ""
+
+msgid "Status: %{title}"
+msgstr ""
+
+msgid "StatusCheck|%{failed} failed"
+msgstr ""
+
+msgid "StatusCheck|%{pending} pending"
+msgstr ""
+
+msgid "StatusCheck|API to check"
+msgstr ""
+
+msgid "StatusCheck|Add status check"
+msgstr ""
+
+msgid "StatusCheck|An error occurred deleting the %{name} status check."
+msgstr ""
+
+msgid "StatusCheck|An error occurred fetching the status checks."
+msgstr ""
+
+msgid "StatusCheck|Apply this status check to all branches or a specific protected branch."
+msgstr ""
+
+msgid "StatusCheck|Check for a status response in merge requests. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "StatusCheck|Examples: QA, Security."
+msgstr ""
+
+msgid "StatusCheck|External API is already in use by another status check."
+msgstr ""
+
+msgid "StatusCheck|Failed to load status checks"
+msgstr ""
+
+msgid "StatusCheck|Invoke an external API as part of the pipeline process."
+msgstr ""
+
+msgid "StatusCheck|No status checks are defined yet."
+msgstr ""
+
+msgid "StatusCheck|Remove status check"
+msgstr ""
+
+msgid "StatusCheck|Remove status check?"
+msgstr ""
+
+msgid "StatusCheck|Service name"
+msgstr ""
+
+msgid "StatusCheck|Status Check ID"
+msgstr ""
+
+msgid "StatusCheck|Status checks"
+msgstr ""
+
+msgid "StatusCheck|Status checks all passed"
+msgstr ""
+
+msgid "StatusCheck|Status checks are API calls to external systems that request the status of an external requirement."
+msgstr ""
+
+msgid "StatusCheck|Status checks are being fetched"
+msgstr ""
+
+msgid "StatusCheck|Status to check"
+msgstr ""
+
+msgid "StatusCheck|Target branch"
+msgstr ""
+
+msgid "StatusCheck|Update status check"
+msgstr ""
+
+msgid "StatusCheck|What is status check?"
+msgstr ""
+
+msgid "StatusCheck|You are about to remove the %{name} status check."
+msgstr ""
+
+msgid "StatusCheck|status checks"
+msgstr ""
+
+msgid "StatusPage|AWS %{docsLink}"
+msgstr ""
+
+msgid "StatusPage|AWS Secret access key"
+msgstr ""
+
+msgid "StatusPage|AWS access key ID"
+msgstr ""
+
+msgid "StatusPage|AWS region"
+msgstr ""
+
+msgid "StatusPage|Active"
+msgstr ""
+
+msgid "StatusPage|Bucket %{docsLink}"
+msgstr ""
+
+msgid "StatusPage|Configure file storage settings to link issues in this project to an external status page."
+msgstr ""
+
+msgid "StatusPage|S3 Bucket name"
+msgstr ""
+
+msgid "StatusPage|Status page"
+msgstr ""
+
+msgid "StatusPage|Status page URL"
+msgstr ""
+
+msgid "StatusPage|To publish incidents to an external status page, GitLab stores a JSON file in your Amazon S3 account at a location that your external status page service can access. Make sure to also set up %{docsLink}"
+msgstr ""
+
+msgid "StatusPage|configuration documentation"
+msgstr ""
+
+msgid "StatusPage|your status page frontend."
+msgstr ""
+
+msgid "Step %{currentStep} of %{stepCount}"
+msgstr ""
+
+msgid "Step 1."
+msgstr ""
+
+msgid "Step 2."
+msgstr ""
+
+msgid "Step 3."
+msgstr ""
+
+msgid "Step 4."
+msgstr ""
+
+msgid "Stop Terminal"
+msgstr ""
+
+msgid "Stop impersonating"
+msgstr ""
+
+msgid "Stop impersonation"
+msgstr ""
+
+msgid "Stop this environment"
+msgstr ""
+
+msgid "Stopped"
+msgstr ""
+
+msgid "Stopping..."
+msgstr ""
+
+msgid "Storage"
+msgstr ""
+
+msgid "Storage nodes for new repositories"
+msgstr ""
+
+msgid "Storage:"
+msgstr ""
+
+msgid "StorageSize|Unknown"
+msgstr ""
+
+msgid "Store your files, plan your work, collaborate on code, and more."
+msgstr ""
+
+msgid "Strikethrough (%{modifierKey}%{shiftKey}X)"
+msgstr ""
+
+msgid "Strikethrough text"
+msgstr ""
+
+msgid "Sub-batch size"
+msgstr ""
+
+msgid "Subdomains of the Pages root domain %{root_domain} are reserved and cannot be used as custom Pages domains."
+msgstr ""
+
+msgid "Subgroup information"
+msgstr ""
+
+msgid "Subgroup milestone"
+msgstr ""
+
+msgid "Subgroup navigation"
+msgstr ""
+
+msgid "SubgroupCreationLevel|Roles allowed to create subgroups"
+msgstr ""
+
+msgid "SubgroupCreationlevel|Allowed to create subgroups"
+msgstr ""
+
+msgid "SubgroupCreationlevel|Maintainers"
+msgstr ""
+
+msgid "SubgroupCreationlevel|Owners"
+msgstr ""
+
+msgid "Subgroups"
+msgstr ""
+
+msgid "Subgroups and projects"
+msgstr ""
+
+msgid "Subgroups can set up their own two-factor authentication rules"
+msgstr ""
+
+msgid "Subject Key Identifier:"
+msgstr ""
+
+msgid "Subkeys:"
+msgstr ""
+
+msgid "Submit"
+msgstr ""
+
+msgid "Submit a review"
+msgstr ""
+
+msgid "Submit as ham"
+msgstr ""
+
+msgid "Submit as spam"
+msgstr ""
+
+msgid "Submit feedback"
+msgstr ""
+
+msgid "Submit review"
+msgstr ""
+
+msgid "Submit search"
+msgstr ""
+
+msgid "Submit the current review."
+msgstr ""
+
+msgid "Submitted as ham"
+msgstr ""
+
+msgid "Submitted the current review."
+msgstr ""
+
+msgid "Subscribe"
+msgstr ""
+
+msgid "Subscribe at group level"
+msgstr ""
+
+msgid "Subscribe at project level"
+msgstr ""
+
+msgid "Subscribe to RSS feed"
+msgstr ""
+
+msgid "Subscribe to calendar"
+msgstr ""
+
+msgid "Subscribed"
+msgstr ""
+
+msgid "Subscribed to this %{quick_action_target}."
+msgstr ""
+
+msgid "Subscribed to this project"
+msgstr ""
+
+msgid "Subscribes to this %{quick_action_target}."
+msgstr ""
+
+msgid "Subscription"
+msgstr ""
+
+msgid "Subscription History"
+msgstr ""
+
+msgid "Subscription deletion failed."
+msgstr ""
+
+msgid "Subscription for %{subscription} will be removed. Do you want to continue?"
+msgstr ""
+
+msgid "Subscription service outage"
+msgstr ""
+
+msgid "Subscription successfully applied to \"%{group_name}\""
+msgstr ""
+
+msgid "Subscription successfully created."
+msgstr ""
+
+msgid "Subscription successfully deleted."
+msgstr ""
+
+msgid "SubscriptionBanner|Add new license"
+msgstr ""
+
+msgid "SubscriptionBanner|Export license usage file"
+msgstr ""
+
+msgid "SubscriptionBanner|Upload new license"
+msgstr ""
+
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
+msgid "SubscriptionTable|Add seats"
+msgstr ""
+
+msgid "SubscriptionTable|An error occurred while loading the subscription details."
+msgstr ""
+
+msgid "SubscriptionTable|Billing"
+msgstr ""
+
+msgid "SubscriptionTable|Free"
+msgstr ""
+
+msgid "SubscriptionTable|GitLab allows you to continue using your subscription even if you exceed the number of seats you purchased. You will be required to pay for these seats upon renewal."
+msgstr ""
+
+msgid "SubscriptionTable|Last invoice"
+msgstr ""
+
+msgid "SubscriptionTable|Last updated at %{seatsLastUpdated} UTC"
+msgstr ""
+
+msgid "SubscriptionTable|Loading subscriptions"
+msgstr ""
+
+msgid "SubscriptionTable|Manage"
+msgstr ""
+
+msgid "SubscriptionTable|Max seats used"
+msgstr ""
+
+msgid "SubscriptionTable|Next invoice"
+msgstr ""
+
+msgid "SubscriptionTable|Refresh Seats"
+msgstr ""
+
+msgid "SubscriptionTable|Renew"
+msgstr ""
+
+msgid "SubscriptionTable|Seats currently in use"
+msgstr ""
+
+msgid "SubscriptionTable|Seats in subscription"
+msgstr ""
+
+msgid "SubscriptionTable|Seats owed"
+msgstr ""
+
+msgid "SubscriptionTable|See usage"
+msgstr ""
+
+msgid "SubscriptionTable|Something went wrong trying to refresh seats"
+msgstr ""
+
+msgid "SubscriptionTable|Subscription end date"
+msgstr ""
+
+msgid "SubscriptionTable|Subscription start date"
+msgstr ""
+
+msgid "SubscriptionTable|This is the last time the GitLab.com team was in contact with you to settle any outstanding balances."
+msgstr ""
+
+msgid "SubscriptionTable|This is the maximum number of users that have existed at the same time since this subscription started."
+msgstr ""
+
+msgid "SubscriptionTable|This is the next date when the GitLab.com team is scheduled to get in contact with you to settle any outstanding balances."
+msgstr ""
+
+msgid "SubscriptionTable|This is the number of seats you will be required to purchase if you update to a paid plan."
+msgstr ""
+
+msgid "SubscriptionTable|Trial"
+msgstr ""
+
+msgid "SubscriptionTable|Trial end date"
+msgstr ""
+
+msgid "SubscriptionTable|Trial start date"
+msgstr ""
+
+msgid "SubscriptionTable|Up to date"
+msgstr ""
+
+msgid "SubscriptionTable|Usage"
+msgstr ""
+
+msgid "SubscriptionTable|Usage count is performed once a day at 12:00 PM."
+msgstr ""
+
+msgid "Subscriptions"
+msgstr ""
+
+msgid "Subscriptions|Activation date"
+msgstr ""
+
+msgid "Subscriptions|End date"
+msgstr ""
+
+msgid "Subscriptions|End date:"
+msgstr ""
+
+msgid "Subscriptions|Last sync"
+msgstr ""
+
+msgid "Subscriptions|None"
+msgstr ""
+
+msgid "Subscriptions|Start date"
+msgstr ""
+
+msgid "Subscription|Your subscription for %{strong}%{namespace_name}%{strong_close} has expired and you are now on %{pricing_link_start}the GitLab Free tier%{pricing_link_end}. Don't worry, your data is safe. Get in touch with our support team (%{support_email}). They'll gladly help with your subscription renewal."
+msgstr ""
+
+msgid "Subtracted"
+msgstr ""
+
+msgid "Subtracts"
+msgstr ""
+
+msgid "Succeeded"
+msgstr ""
+
+msgid "Success"
+msgstr ""
+
+msgid "Successfully activated"
+msgstr ""
+
+msgid "Successfully approved"
+msgstr ""
+
+msgid "Successfully banned"
+msgstr ""
+
+msgid "Successfully blocked"
+msgstr ""
+
+msgid "Successfully confirmed"
+msgstr ""
+
+msgid "Successfully deactivated"
+msgstr ""
+
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
+msgid "Successfully removed email."
+msgstr ""
+
+msgid "Successfully reset compute usage for namespace."
+msgstr ""
+
+msgid "Successfully scheduled a pipeline to run. Go to the %{pipelines_link_start}Pipelines page%{pipelines_link_end} for details."
+msgstr ""
+
+msgid "Successfully synced %{synced_timeago}."
+msgstr ""
+
+msgid "Successfully unbanned"
+msgstr ""
+
+msgid "Successfully unblocked"
+msgstr ""
+
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
+msgid "Successfully unlocked"
+msgstr ""
+
+msgid "Successfully updated %{last_updated_timeago}."
+msgstr ""
+
+msgid "Successfully updated the environment."
+msgstr ""
+
+msgid "Suggest code changes which can be immediately applied in one click. Try it out!"
+msgstr ""
+
+msgid "Suggest test cases"
+msgstr ""
+
+msgid "Suggested change"
+msgstr ""
+
+msgid "SuggestedColors|Blue"
+msgstr ""
+
+msgid "SuggestedColors|Blue-gray"
+msgstr ""
+
+msgid "SuggestedColors|Carrot orange"
+msgstr ""
+
+msgid "SuggestedColors|Charcoal grey"
+msgstr ""
+
+msgid "SuggestedColors|Crimson"
+msgstr ""
+
+msgid "SuggestedColors|Current addition color"
+msgstr ""
+
+msgid "SuggestedColors|Current removal color"
+msgstr ""
+
+msgid "SuggestedColors|Dark coral"
+msgstr ""
+
+msgid "SuggestedColors|Dark sea green"
+msgstr ""
+
+msgid "SuggestedColors|Dark violet"
+msgstr ""
+
+msgid "SuggestedColors|Deep violet"
+msgstr ""
+
+msgid "SuggestedColors|Default addition color"
+msgstr ""
+
+msgid "SuggestedColors|Default removal color"
+msgstr ""
+
+msgid "SuggestedColors|Gray"
+msgstr ""
+
+msgid "SuggestedColors|Green"
+msgstr ""
+
+msgid "SuggestedColors|Green-cyan"
+msgstr ""
+
+msgid "SuggestedColors|Lavender"
+msgstr ""
+
+msgid "SuggestedColors|Magenta-pink"
+msgstr ""
+
+msgid "SuggestedColors|Orange"
+msgstr ""
+
+msgid "SuggestedColors|Purple"
+msgstr ""
+
+msgid "SuggestedColors|Red"
+msgstr ""
+
+msgid "SuggestedColors|Rose red"
+msgstr ""
+
+msgid "SuggestedColors|Titanium yellow"
+msgstr ""
+
+msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
+msgstr ""
+
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
+msgid "SuggestedReviewers|Suggested reviewers"
+msgstr ""
+
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
+msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
+msgstr ""
+
+msgid "Suggestion is not applicable as the suggestion was not found."
+msgstr ""
+
+msgid "Suggestion(s)"
+msgstr ""
+
+msgid "Suggestions are not applicable as one or more suggestions were not found."
+msgstr ""
+
+msgid "Suggestions are not applicable as their lines cannot overlap."
+msgstr ""
+
+msgid "Suggestions must all be on the same branch."
+msgstr ""
+
+msgid "Suggestions:"
+msgstr ""
+
+msgid "Suite"
+msgstr ""
+
+msgid "Summarize comments"
+msgstr ""
+
+msgid "Summarize my pending comments"
+msgstr ""
+
+msgid "Summary"
+msgstr ""
+
+msgid "Summary / note"
+msgstr ""
+
+msgid "Summary comment (optional)"
+msgstr ""
+
+msgid "Summary generated by AI"
+msgstr ""
+
+msgid "Summary generated by AI (Experiment)"
+msgstr ""
+
+msgid "Summary will be generated with the next push to this merge request and will appear here."
+msgstr ""
+
+msgid "Sun"
+msgstr ""
+
+msgid "Sunday"
+msgstr ""
+
+msgid "SuperSonics|Activate subscription"
+msgstr ""
+
+msgid "SuperSonics|Activation code"
+msgstr ""
+
+msgid "SuperSonics|Activation not possible due to seat mismatch"
+msgstr ""
+
+msgid "SuperSonics|Activation not possible due to true-up value mismatch"
+msgstr ""
+
+msgid "SuperSonics|Add activation code"
+msgstr ""
+
+msgid "SuperSonics|An error occurred while adding your subscription"
+msgstr ""
+
+msgid "SuperSonics|Billable users"
+msgstr ""
+
+msgid "SuperSonics|Buy subscription"
+msgstr ""
+
+msgid "SuperSonics|Cannot activate instance due to a connectivity issue"
+msgstr ""
+
+msgid "SuperSonics|Cloud licensing"
+msgstr ""
+
+msgid "SuperSonics|Cloud licensing is now available. It's an easier way to activate instances and manage subscriptions. Read more about it in our %{blogPostLinkStart}blog post%{blogPostLinkEnd}. Activation codes are available in the %{portalLinkStart}Customers Portal%{portalLinkEnd}."
+msgstr ""
+
+msgid "SuperSonics|Customers Portal"
+msgstr ""
+
+msgid "SuperSonics|Export license usage file"
+msgstr ""
+
+msgid "SuperSonics|Free trial"
+msgstr ""
+
+msgid "SuperSonics|I agree that my use of the GitLab Software is subject to the Subscription Agreement located at the %{linkStart}Terms of Service%{linkEnd}, unless otherwise agreed to in writing with GitLab."
+msgstr ""
+
+msgid "SuperSonics|Learn how to %{linkStart}activate your subscription%{linkEnd}."
+msgstr ""
+
+msgid "SuperSonics|Learn more about %{activationLinkStart}activating your subscription%{activationLinkEnd}. If you need further assistance, %{supportLinkStart}contact GitLab Support%{supportLinkEnd}."
+msgstr ""
+
+msgid "SuperSonics|Licensed to"
+msgstr ""
+
+msgid "SuperSonics|Maximum users"
+msgstr ""
+
+msgid "SuperSonics|Offline license"
+msgstr ""
+
+msgid "SuperSonics|Online license"
+msgstr ""
+
+msgid "SuperSonics|Paste your activation code"
+msgstr ""
+
+msgid "SuperSonics|Please agree to the Subscription Agreement"
+msgstr ""
+
+msgid "SuperSonics|Ready to get started? A GitLab plan is ideal for scaling organizations and for multi team usage."
+msgstr ""
+
+msgid "SuperSonics|Start free trial"
+msgstr ""
+
+msgid "SuperSonics|Subscription detail synchronization has started and will complete soon."
+msgstr ""
+
+msgid "SuperSonics|Subscription details"
+msgstr ""
+
+msgid "SuperSonics|Subscription details did not synchronize due to a possible connectivity issue with GitLab servers. %{connectivityHelpLinkStart}How do I check connectivity%{connectivityHelpLinkEnd}?"
+msgstr ""
+
+msgid "SuperSonics|Subscription unavailable"
+msgstr ""
+
+msgid "SuperSonics|Sync subscription details"
+msgstr ""
+
+msgid "SuperSonics|Synchronization started"
+msgstr ""
+
+msgid "SuperSonics|The activation code is not valid. Please make sure to copy it exactly from the Customers Portal or confirmation email. Learn more about %{linkStart}activating your subscription%{linkEnd}."
+msgstr ""
+
+msgid "SuperSonics|The activation code should be a 24-character alphanumeric string"
+msgstr ""
+
+msgid "SuperSonics|There is a connectivity issue"
+msgstr ""
+
+msgid "SuperSonics|This is the highest peak of users on your installation since the license started."
+msgstr ""
+
+msgid "SuperSonics|This is the number of %{billableUsersLinkStart}billable users%{billableUsersLinkEnd} on your installation, and this is the minimum number you need to purchase when you renew your license."
+msgstr ""
+
+msgid "SuperSonics|To activate your subscription, your instance needs to connect to GitLab. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}."
+msgstr ""
+
+msgid "SuperSonics|User in subscription"
+msgid_plural "SuperSonics|Users in subscription"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "SuperSonics|Users in subscription"
+msgstr ""
+
+msgid "SuperSonics|Users over subscription"
+msgstr ""
+
+msgid "SuperSonics|Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
+msgstr ""
+
+msgid "SuperSonics|You can %{purchaseSubscriptionLinkStart}purchase a new subscription%{purchaseSubscriptionLinkEnd} and try again. If you need further assistance, please %{supportLinkStart}contact GitLab Support%{supportLinkEnd}."
+msgstr ""
+
+msgid "SuperSonics|You can start a free trial of GitLab Ultimate without any obligation or payment details."
+msgstr ""
+
+msgid "SuperSonics|You can sync your subscription data to ensure your details are up to date."
+msgstr ""
+
+msgid "SuperSonics|You do not have an active subscription"
+msgstr ""
+
+msgid "SuperSonics|You have a future dated license"
+msgstr ""
+
+msgid "SuperSonics|You have added a license that activates on %{date}. Please see the subscription history table below for more details."
+msgstr ""
+
+msgid "SuperSonics|You have applied a true-up for %{trueUpQuantity} %{trueUpQuantityUsers} but you need one for %{expectedTrueUpQuantity} %{expectedTrueUpQuantityUsers}. To pay for seat overages, contact your sales representative. For further assistance, contact %{licenseSupportLinkStart}GitLab support%{licenseSupportLinkEnd}."
+msgstr ""
+
+msgid "SuperSonics|You have successfully added a license that activates on %{date}. Please see the subscription history table below for more details."
+msgstr ""
+
+msgid "SuperSonics|You may have entered an expired or ineligible activation code. To request a new activation code, %{purchaseSubscriptionLinkStart}purchase a new subscription%{purchaseSubscriptionLinkEnd} or %{supportLinkStart}contact GitLab Support%{supportLinkEnd} for further assistance."
+msgstr ""
+
+msgid "SuperSonics|You'll be charged for %{trueUpLinkStart}users over license%{trueUpLinkEnd} on a quarterly or annual basis, depending on the terms of your agreement."
+msgstr ""
+
+msgid "SuperSonics|Your %{subscriptionEntryName} cannot be displayed at the moment. Please refresh the page to try again."
+msgstr ""
+
+msgid "SuperSonics|Your current GitLab installation has %{userCount} active %{userCountUsers}, which exceeds your new subscription seat count of %{licenseUserCount} by %{overageCount}. To activate your new subscription, %{purchaseLinkStart}purchase%{purchaseLinkEnd} an additional %{overageCount} %{overageCountSeats}, or %{deactivateLinkStart}deactivate%{deactivateLinkEnd} or %{blockLinkStart}block%{blockLinkEnd} %{overageCount} %{overageCountUsers}. For further assistance, contact %{licenseSupportLinkStart}GitLab support%{licenseSupportLinkEnd}."
+msgstr ""
+
+msgid "SuperSonics|Your future dated license was successfully added"
+msgstr ""
+
+msgid "SuperSonics|Your subscription"
+msgstr ""
+
+msgid "SuperSonics|Your subscription cannot be located"
+msgstr ""
+
+msgid "SuperSonics|Your subscription is expired"
+msgstr ""
+
+msgid "SuperSonics|Your subscription was successfully activated. You can see the details below."
+msgstr ""
+
+msgid "SuperSonics|current subscription"
+msgstr ""
+
+msgid "SuperSonics|future subscriptions"
+msgstr ""
+
+msgid "SuperSonics|past subscriptions"
+msgstr ""
+
+msgid "Support"
+msgstr ""
+
+msgid "Support for custom certificates is disabled. Ask your system's administrator to enable it."
+msgstr ""
+
+msgid "Support page URL"
+msgstr ""
+
+msgid "Surveys|Delighted"
+msgstr ""
+
+msgid "Surveys|Happy"
+msgstr ""
+
+msgid "Surveys|Neutral"
+msgstr ""
+
+msgid "Surveys|Sad"
+msgstr ""
+
+msgid "Surveys|Unhappy"
+msgstr ""
+
+msgid "Switch Branches"
+msgstr ""
+
+msgid "Switch branch"
+msgstr ""
+
+msgid "Switch branch/tag"
+msgstr ""
+
+msgid "Switch to GitLab Next"
+msgstr ""
+
+msgid "Switch to plain text editing"
+msgstr ""
+
+msgid "Switch to rich text editing"
+msgstr ""
+
+msgid "Switch to the source to copy the file contents"
+msgstr ""
+
+msgid "Symbolic link"
+msgstr ""
+
+msgid "Sync LDAP"
+msgstr ""
+
+msgid "Sync now"
+msgstr ""
+
+msgid "Synced"
+msgstr ""
+
+msgid "Synchronize LDAP"
+msgstr ""
+
+msgid "Syncing…"
+msgstr ""
+
+msgid "Syntax is correct."
+msgstr ""
+
+msgid "Syntax is incorrect."
+msgstr ""
+
+msgid "SynthaxHighlightingTheme|Dark"
+msgstr ""
+
+msgid "SynthaxHighlightingTheme|Light"
+msgstr ""
+
+msgid "SynthaxHighlightingTheme|Monokai"
+msgstr ""
+
+msgid "SynthaxHighlightingTheme|None"
+msgstr ""
+
+msgid "SynthaxHighlightingTheme|Solarized Dark"
+msgstr ""
+
+msgid "SynthaxHighlightingTheme|Solarized Light"
+msgstr ""
+
+msgid "System"
+msgstr ""
+
+msgid "System Hooks"
+msgstr ""
+
+msgid "System Hooks Help"
+msgstr ""
+
+msgid "System Info"
+msgstr ""
+
+msgid "System default (%{default})"
+msgstr ""
+
+msgid "System header and footer"
+msgstr ""
+
+msgid "System hooks are triggered on sets of events like creating a project or adding an SSH key. You can also enable extra triggers, such as push events."
+msgstr ""
+
+msgid "System metrics (Custom)"
+msgstr ""
+
+msgid "System metrics (Kubernetes)"
+msgstr ""
+
+msgid "System output"
+msgstr ""
+
+msgid "System started"
+msgstr ""
+
+msgid "TXT"
+msgstr ""
+
+msgid "Table of Contents"
+msgstr ""
+
+msgid "Table of contents"
+msgstr ""
+
+msgid "Tag"
+msgstr ""
+
+msgid "Tag does not exist"
+msgstr ""
+
+msgid "Tag list:"
+msgstr ""
+
+msgid "Tag name"
+msgstr ""
+
+msgid "Tag name cannot be one of the following: %{names}"
+msgstr ""
+
+msgid "Tag name is required."
+msgstr ""
+
+msgid "Tag name should not be empty"
+msgstr ""
+
+msgid "Tag name should not contain any control characters"
+msgstr ""
+
+msgid "Tag name should not contain any of the following: %{substrings}"
+msgstr ""
+
+msgid "Tag name should not end with %{postfixes}"
+msgstr ""
+
+msgid "Tag name should not start with %{prefixes}"
+msgstr ""
+
+msgid "Tag push"
+msgstr ""
+
+msgid "Tag push events"
+msgstr ""
+
+msgid "Tag this commit."
+msgstr ""
+
+msgid "Tagged this commit to %{tag_name} with \"%{message}\"."
+msgstr ""
+
+msgid "Tagged this commit to %{tag_name}."
+msgstr ""
+
+msgid "Tags"
+msgstr ""
+
+msgid "Tags are deleted until the timeout is reached. Any remaining tags are included the next time the policy runs. To remove the time limit, set it to 0."
+msgstr ""
+
+msgid "Tags feed"
+msgstr ""
+
+msgid "Tags this commit to %{tag_name} with \"%{message}\"."
+msgstr ""
+
+msgid "Tags this commit to %{tag_name}."
+msgstr ""
+
+msgid "Tags:"
+msgstr ""
+
+msgid "TagsPage|Are you sure you want to delete this tag?"
+msgstr ""
+
+msgid "TagsPage|Browse commits"
+msgstr ""
+
+msgid "TagsPage|Browse files"
+msgstr ""
+
+msgid "TagsPage|Can't find HEAD commit for this tag"
+msgstr ""
+
+msgid "TagsPage|Cancel"
+msgstr ""
+
+msgid "TagsPage|Cancel, keep tag"
+msgstr ""
+
+msgid "TagsPage|Create release"
+msgstr ""
+
+msgid "TagsPage|Create tag"
+msgstr ""
+
+msgid "TagsPage|Delete protected tag"
+msgstr ""
+
+msgid "TagsPage|Delete tag"
+msgstr ""
+
+msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} protected tag cannot be undone."
+msgstr ""
+
+msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone."
+msgstr ""
+
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
+msgid "TagsPage|Edit release"
+msgstr ""
+
+msgid "TagsPage|Existing branch name, tag, or commit SHA"
+msgstr ""
+
+msgid "TagsPage|Filter by tag name"
+msgstr ""
+
+msgid "TagsPage|New"
+msgstr ""
+
+msgid "TagsPage|New Tag"
+msgstr ""
+
+msgid "TagsPage|New tag"
+msgstr ""
+
+msgid "TagsPage|Only a project maintainer or owner can delete a protected tag"
+msgstr ""
+
+msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
+msgstr ""
+
+msgid "TagsPage|Permanently delete protected tag?"
+msgstr ""
+
+msgid "TagsPage|Permanently delete tag?"
+msgstr ""
+
+msgid "TagsPage|Please type the following to confirm:"
+msgstr ""
+
+msgid "TagsPage|Repository has no tags yet."
+msgstr ""
+
+msgid "TagsPage|Sorry, your filter produced no results."
+msgstr ""
+
+msgid "TagsPage|Tags"
+msgstr ""
+
+msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
+msgstr ""
+
+msgid "TagsPage|Unable to load tags"
+msgstr ""
+
+msgid "TagsPage|Use git tag command to add a new one:"
+msgstr ""
+
+msgid "TagsPage|Yes, delete protected tag"
+msgstr ""
+
+msgid "TagsPage|Yes, delete tag"
+msgstr ""
+
+msgid "TagsPage|protected"
+msgstr ""
+
+msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
+msgstr ""
+
+msgid "TanukiBot|Ask GitLab Duo"
+msgstr ""
+
+msgid "TanukiBot|Ask a question about GitLab"
+msgstr ""
+
+msgid "TanukiBot|For example, %{linkStart}what is a fork%{linkEnd}?"
+msgstr ""
+
+msgid "TanukiBot|GitLab Duo Chat"
+msgstr ""
+
+msgid "TanukiBot|Give feedback"
+msgstr ""
+
+msgid "TanukiBot|Source"
+msgid_plural "TanukiBot|Sources"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "TanukiBot|There was an error communicating with GitLab Duo Chat. Please try again later."
+msgstr ""
+
+msgid "TanukiBot|What is a fork?"
+msgstr ""
+
+msgid "Targe branch"
+msgstr ""
+
+msgid "Target"
+msgstr ""
+
+msgid "Target Branch"
+msgstr ""
+
+msgid "Target Path"
+msgstr ""
+
+msgid "Target branch"
+msgstr ""
+
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
+msgstr ""
+
+msgid "Target branch: %{target_branch}"
+msgstr ""
+
+msgid "Target roles"
+msgstr ""
+
+msgid "Target-Branch"
+msgstr ""
+
+msgid "Task"
+msgstr ""
+
+msgid "Task ID: %{elastic_task}"
+msgstr ""
+
+msgid "Task list"
+msgstr ""
+
+msgid "TasksToBeDone|Create/import code into a project (repository)"
+msgstr ""
+
+msgid "TasksToBeDone|Create/import issues (tickets) to collaborate on ideas and plan work"
+msgstr ""
+
+msgid "TasksToBeDone|Set up CI/CD pipelines to build, test, deploy, and monitor code"
+msgstr ""
+
+msgid "Tasks|%{complete_count} of %{total_count} %{checklist_item_noun} completed"
+msgstr ""
+
+msgid "Tasks|%{complete_count}/%{total_count} %{checklist_item_noun}"
+msgstr ""
+
+msgid "Team"
+msgstr ""
+
+msgid "Team domain"
+msgstr ""
+
+msgid "TeamcityIntegration|Trigger TeamCity CI after a merge request has been created or updated"
+msgstr ""
+
+msgid "TeamcityIntegration|Trigger TeamCity CI after every push to the repository, except branch delete"
+msgstr ""
+
+msgid "TelegramIntegration|Leave blank to use your current token."
+msgstr ""
+
+msgid "TelegramIntegration|New token"
+msgstr ""
+
+msgid "TelegramIntegration|Send notifications about project events to Telegram."
+msgstr ""
+
+msgid "TelegramIntegration|Send notifications about project events to Telegram. %{docs_link}"
+msgstr ""
+
+msgid "TelegramIntegration|Unique authentication token."
+msgstr ""
+
+msgid "Telephone number"
+msgstr ""
+
+msgid "Template"
+msgstr ""
+
+msgid "Template to append to all Service Desk issues"
+msgstr ""
+
+msgid "TemplateRepository|Create common files more quickly, and standardize their format."
+msgstr ""
+
+msgid "Templates"
+msgstr ""
+
+msgid "TemporaryStorageIncrease|can only be set once"
+msgstr ""
+
+msgid "TemporaryStorageIncrease|can only be set with more than %{percentage}%% usage"
+msgstr ""
+
+msgid "Terminal"
+msgstr ""
+
+msgid "Terminal for environment"
+msgstr ""
+
+msgid "Terminal sync service is running"
+msgstr ""
+
+msgid "Terms of Service Agreement and Privacy Policy"
+msgstr ""
+
+msgid "Terms of Service and Privacy Policy"
+msgstr ""
+
+msgid "Terms of service"
+msgstr ""
+
+msgid "Terraform Module Registry"
+msgstr ""
+
+msgid "Terraform modules"
+msgstr ""
+
+msgid "TerraformBanner|Learn more about GitLab's Backend State"
+msgstr ""
+
+msgid "TerraformBanner|The GitLab managed Terraform state backend can store your Terraform state easily and securely, and spares you from setting up additional remote resources. Its features include: versioning, encryption of the state file both in transit and at rest, locking, and remote Terraform plan/apply execution."
+msgstr ""
+
+msgid "TerraformBanner|Using Terraform? Try the GitLab Managed Terraform State"
+msgstr ""
+
+msgid "TerraformLimits|Learn more about Terraform limits."
+msgstr ""
+
+msgid "TerraformLimits|Limits for Terraform features"
+msgstr ""
+
+msgid "TerraformLimits|Maximum file size (in bytes) of Terraform state files. Set to 0 for no limit."
+msgstr ""
+
+msgid "TerraformLimits|Terraform limits"
+msgstr ""
+
+msgid "TerraformLimits|Terraform state size limit (bytes)"
+msgstr ""
+
+msgid "Terraform|%{name} successfully removed"
+msgstr ""
+
+msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
+msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report was generated in your pipelines"
+msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports were generated in your pipelines"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Terraform|%{user} updated %{timeAgo}"
+msgstr ""
+
+msgid "Terraform|A Terraform report failed to generate."
+msgstr ""
+
+msgid "Terraform|A Terraform report was generated in your pipelines."
+msgstr ""
+
+msgid "Terraform|Actions"
+msgstr ""
+
+msgid "Terraform|An error occurred while changing the state file"
+msgstr ""
+
+msgid "Terraform|An error occurred while loading your Terraform States"
+msgstr ""
+
+msgid "Terraform|Are you sure you want to remove the Terraform State %{name}?"
+msgstr ""
+
+msgid "Terraform|Cancel"
+msgstr ""
+
+msgid "Terraform|Cannot remove a locked state"
+msgstr ""
+
+msgid "Terraform|Copy Terraform init command"
+msgstr ""
+
+msgid "Terraform|Deletion in progress"
+msgstr ""
+
+msgid "Terraform|Details"
+msgstr ""
+
+msgid "Terraform|Download JSON"
+msgstr ""
+
+msgid "Terraform|Explore documentation"
+msgstr ""
+
+msgid "Terraform|Failed to load Terraform reports"
+msgstr ""
+
+msgid "Terraform|Generating the report caused an error."
+msgstr ""
+
+msgid "Terraform|Job status"
+msgstr ""
+
+msgid "Terraform|Loading Terraform reports..."
+msgstr ""
+
+msgid "Terraform|Lock"
+msgstr ""
+
+msgid "Terraform|Locked"
+msgstr ""
+
+msgid "Terraform|Locked by %{user} %{timeAgo}"
+msgstr ""
+
+msgid "Terraform|Locking state"
+msgstr ""
+
+msgid "Terraform|Name"
+msgstr ""
+
+msgid "Terraform|Pipeline"
+msgstr ""
+
+msgid "Terraform|Remove"
+msgstr ""
+
+msgid "Terraform|Remove state file and versions"
+msgstr ""
+
+msgid "Terraform|Removed"
+msgstr ""
+
+msgid "Terraform|Removing"
+msgstr ""
+
+msgid "Terraform|Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete"
+msgstr ""
+
+msgid "Terraform|Terraform init command"
+msgstr ""
+
+msgid "Terraform|Terraform states"
+msgstr ""
+
+msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
+msgstr ""
+
+msgid "Terraform|The job %{strong_start}%{name}%{strong_end} generated a report."
+msgstr ""
+
+msgid "Terraform|To get access to this terraform state from your local computer, run the following command at the command line. The first line requires a personal access token with API read and write access. %{linkStart}How do I create a personal access token?%{linkEnd}."
+msgstr ""
+
+msgid "Terraform|To remove the State file and its versions, type %{name} to confirm:"
+msgstr ""
+
+msgid "Terraform|Unknown User"
+msgstr ""
+
+msgid "Terraform|Unlock"
+msgstr ""
+
+msgid "Terraform|Unlocking state"
+msgstr ""
+
+msgid "Terraform|You are about to remove the state file %{name}. This will permanently delete all the State versions and history. The infrastructure provisioned previously will remain intact, and only the state file with all its versions will be removed. This action cannot be undone."
+msgstr ""
+
+msgid "Terraform|You have insufficient permissions to delete this state"
+msgstr ""
+
+msgid "Terraform|Your project doesn't have any Terraform state files"
+msgstr ""
+
+msgid "Test"
+msgstr ""
+
+msgid "Test case"
+msgstr ""
+
+msgid "Test cases"
+msgstr ""
+
+msgid "Test coverage value for this pipeline was calculated by the coverage value of %d job."
+msgid_plural "Test coverage value for this pipeline was calculated by averaging the resulting coverage values of %d jobs."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Test coverage: %d hit"
+msgid_plural "Test coverage: %d hits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Test generated by AI"
+msgstr ""
+
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|Move test case"
+msgstr ""
+
+msgid "TestCases|Moving test case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while adding test case to a to-do item."
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Something went wrong while marking test case to-do item as done."
+msgstr ""
+
+msgid "TestCases|Something went wrong while moving test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while updating the test case labels."
+msgstr ""
+
+msgid "TestCases|Something went wrong while updating the test case."
+msgstr ""
+
+msgid "TestCases|Submit test case"
+msgstr ""
+
+msgid "TestHooks|Ensure one of your projects has merge requests."
+msgstr ""
+
+msgid "TestHooks|Ensure the project has CI jobs."
+msgstr ""
+
+msgid "TestHooks|Ensure the project has CI pipelines."
+msgstr ""
+
+msgid "TestHooks|Ensure the project has deployments."
+msgstr ""
+
+msgid "TestHooks|Ensure the project has issues."
+msgstr ""
+
+msgid "TestHooks|Ensure the project has merge requests."
+msgstr ""
+
+msgid "TestHooks|Ensure the project has notes."
+msgstr ""
+
+msgid "TestHooks|Ensure the project has releases."
+msgstr ""
+
+msgid "TestHooks|Ensure the wiki is enabled and has pages."
+msgstr ""
+
+msgid "TestReports|%{count} errors"
+msgstr ""
+
+msgid "TestReports|%{count} failures"
+msgstr ""
+
+msgid "TestReports|%{count} tests"
+msgstr ""
+
+msgid "TestReports|%{rate}%{sign} success rate"
+msgstr ""
+
+msgid "TestReports|Attachment"
+msgstr ""
+
+msgid "TestReports|Copy test name to rerun locally"
+msgstr ""
+
+msgid "TestReports|Job artifacts are expired"
+msgstr ""
+
+msgid "TestReports|Jobs"
+msgstr ""
+
+msgid "TestReports|Learn how to upload pipeline test reports"
+msgstr ""
+
+msgid "TestReports|Learn more about pipeline test reports"
+msgstr ""
+
+msgid "TestReports|No test cases were found in the test report."
+msgstr ""
+
+msgid "TestReports|Test reports require job artifacts but all artifacts are expired. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "TestReports|There are no test cases to display."
+msgstr ""
+
+msgid "TestReports|There are no test reports for this pipeline"
+msgstr ""
+
+msgid "TestReports|There are no test suites to show."
+msgstr ""
+
+msgid "TestReports|There are no tests to display"
+msgstr ""
+
+msgid "TestReports|There was an error fetching the summary."
+msgstr ""
+
+msgid "TestReports|There was an error fetching the test suite."
+msgstr ""
+
+msgid "TestReports|You can configure your job to use unit test reports, and GitLab displays a report here and in the related merge request."
+msgstr ""
+
+msgid "Tests"
+msgstr ""
+
+msgid "Text"
+msgstr ""
+
+msgid "Text (optional)"
+msgstr ""
+
+msgid "Text added to the body of all email messages. %{character_limit} character limit"
+msgstr ""
+
+msgid "Text added to the body of user deactivation email messages. 1000 character limit."
+msgstr ""
+
+msgid "Text style"
+msgstr ""
+
+msgid "Thank you for your business."
+msgstr ""
+
+msgid "Thank you for your report. A GitLab administrator will look into it shortly."
+msgstr ""
+
+msgid "Thank you for your support request! We are tracking your request as ticket #%{issue_iid}, and will respond as soon as we can."
+msgstr ""
+
+msgid "Thanks for signing up to GitLab!"
+msgstr ""
+
+msgid "Thanks for your purchase!"
+msgstr ""
+
+msgid "That's OK, I don't want to renew"
+msgstr ""
+
+msgid "That's it, well done!"
+msgstr ""
+
+msgid "The %{link_start}true-up model%{link_end} allows having more users, and additional users will incur a retroactive charge on renewal."
+msgstr ""
+
+msgid "The %{plan_name} is no longer available to purchase. For more information about how this will impact you, check our %{faq_link_start}frequently asked questions%{faq_link_end}."
+msgstr ""
+
+msgid "The %{type} contains the following error:"
+msgid_plural "The %{type} contains the following errors:"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "The API key used by GitLab for accessing the Spam Check service endpoint."
+msgstr ""
+
+msgid "The CSV export will be created in the background. Once finished, it will be sent to %{email} in an attachment."
+msgstr ""
+
+msgid "The Code Suggestions add-on is not available."
+msgstr ""
+
+msgid "The GitLab subscription service (customers.gitlab.com) is currently experiencing an outage. You can monitor the status and get updates at %{linkStart}status.gitlab.com%{linkEnd}."
+msgstr ""
+
+msgid "The GitLab user to which the Jira user %{jiraDisplayName} will be mapped"
+msgstr ""
+
+msgid "The ID of the application."
+msgstr ""
+
+msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
+msgstr ""
+
+msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project."
+msgstr ""
+
+msgid "The Slack notifications integration is deprecated and will be removed in a future release. To continue to receive notifications from Slack, use the GitLab for Slack app instead. %{learn_more_link_start}Learn more%{link_end}."
+msgstr ""
+
+msgid "The Snowplow cookie domain."
+msgstr ""
+
+msgid "The URL of the Jenkins server."
+msgstr ""
+
+msgid "The URL should start with http:// or https://"
+msgstr ""
+
+msgid "The URLs for connecting to Elasticsearch. For clustering, add the URLs separated by commas."
+msgstr ""
+
+msgid "The `/merge` quick action requires the SHA of the head of the branch."
+msgstr ""
+
+msgid "The application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential."
+msgstr ""
+
+msgid "The associated issue #%{issueId} has been closed as the error is now resolved."
+msgstr ""
+
+msgid "The branch for this project has no active pipeline configuration."
+msgstr ""
+
+msgid "The branch or tag does not exist"
+msgstr ""
+
+msgid "The character highlighter helps you keep the subject line to %{titleLength} characters and wrap the body at %{bodyLength} so they are readable in git."
+msgstr ""
+
+msgid "The comment you are editing has been changed by another user. Would you like to keep your changes and overwrite the new description or discard your changes?"
+msgstr ""
+
+msgid "The commit does not exist"
+msgstr ""
+
+msgid "The comparison view may be inaccurate due to merge conflicts."
+msgstr ""
+
+msgid "The complete DevOps platform. One application with endless possibilities. Organizations rely on GitLab’s source code management, CI/CD, security, and more to deliver software rapidly."
+msgstr ""
+
+msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
+msgstr ""
+
+msgid "The contact does not belong to the issue group's root ancestor"
+msgstr ""
+
+msgid "The content editor may change the markdown formatting style of the document, which may not match your original markdown style."
+msgstr ""
+
+msgid "The content for this wiki page failed to load. To fix this error, reload the page."
+msgstr ""
+
+msgid "The content for this wiki page failed to render."
+msgstr ""
+
+msgid "The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository."
+msgstr ""
+
+msgid "The contents of this group, its subgroups and projects will be permanently removed after %{deletion_adjourned_period} days on %{date}. After this point, your data cannot be recovered."
+msgstr ""
+
+msgid "The current epic"
+msgstr ""
+
+msgid "The current incident"
+msgstr ""
+
+msgid "The current issue"
+msgstr ""
+
+msgid "The current user is not authorized to access the job log."
+msgstr ""
+
+msgid "The current user is not authorized to create the pipeline schedule"
+msgstr ""
+
+msgid "The current user is not authorized to set pipeline schedule variables"
+msgstr ""
+
+msgid "The current user is not authorized to update the pipeline schedule"
+msgstr ""
+
+msgid "The data in this pipeline is too old to be rendered as a graph. Please check the Jobs tab to access historical data."
+msgstr ""
+
+msgid "The date when the release is ready. A release with a date in the future is labeled as an %{linkStart}Upcoming Release%{linkEnd}."
+msgstr ""
+
+msgid "The default CI/CD configuration file and path for new projects."
+msgstr ""
+
+msgid "The default branch for this project has been changed. Please update your bookmarks."
+msgstr ""
+
+msgid "The default branch of this project clashes with another ref"
+msgstr ""
+
+msgid "The dependency list details information about the components used within your project."
+msgstr ""
+
+msgid "The deployment of this job to %{environmentLink} did not succeed."
+msgstr ""
+
+msgid "The diagrams.net editor could not be loaded."
+msgstr ""
+
+msgid "The directory has been successfully created."
+msgstr ""
+
+msgid "The domain you entered is misformatted."
+msgstr ""
+
+msgid "The domain you entered is not allowed."
+msgstr ""
+
+msgid "The download link will expire in 24 hours."
+msgstr ""
+
+msgid "The environment tiers must be from %{environment_tiers}."
+msgstr ""
+
+msgid "The errors we encountered were:"
+msgstr ""
+
+msgid "The file containing the export is not available yet; it may still be transferring. Please try again later."
+msgstr ""
+
+msgid "The file could not be displayed because it is empty or larger than the maximum file size indexed (%{size})."
+msgstr ""
+
+msgid "The file has been successfully created."
+msgstr ""
+
+msgid "The file has been successfully deleted."
+msgstr ""
+
+msgid "The file you're about to delete is tracked by LFS"
+msgstr ""
+
+msgid "The finding is not a vulnerability because it is part of a test or is test data."
+msgstr ""
+
+msgid "The following %{user} can also merge into this branch: %{branch}"
+msgstr ""
+
+msgid "The following %{user} can also push to this branch: %{branch}"
+msgstr ""
+
+msgid "The following Personal Access Token was revoked by an administrator, %{username}."
+msgstr ""
+
+msgid "The following SSH key was deleted by an administrator, %{username}."
+msgstr ""
+
+msgid "The following files or directories can only be modified by the user who locked them."
+msgstr ""
+
+msgid "The following items will NOT be exported:"
+msgstr ""
+
+msgid "The following items will be exported:"
+msgstr ""
+
+msgid "The following personal access token: %{token_names} was revoked, because a new policy to expire personal access tokens were set."
+msgid_plural "The following personal access tokens: %{token_names} were revoked, because a new policy to expire personal access tokens were set."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "The following personal access tokens have expired:"
+msgstr ""
+
+msgid "The fork relationship has been removed."
+msgstr ""
+
+msgid "The form contains the following error:"
+msgid_plural "The form contains the following errors:"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "The form contains the following warning:"
+msgstr ""
+
+msgid "The full package metadata sync can add up to 30 GB to GitLab PostgreSQL database. Ensure you have provisioned enough disk space for the database before enabling this feature. We are actively working on reducing this data size in %{link_start}epic 10415%{link_end}."
+msgstr ""
+
+msgid "The git server, Gitaly, is not available at this time. Please contact your administrator."
+msgstr ""
+
+msgid "The global settings require you to enable Two-Factor Authentication for your account."
+msgstr ""
+
+msgid "The group export can be downloaded from:"
+msgstr ""
+
+msgid "The group has already been shared with this group"
+msgstr ""
+
+msgid "The group settings for %{group_links} require you to enable Two-Factor Authentication for your account. You can %{leave_group_links}."
+msgstr ""
+
+msgid "The group_project_ids parameter is only allowed for a group"
+msgstr ""
+
+msgid "The hostname of your PlantUML server."
+msgstr ""
+
+msgid "The hostname of your Snowplow collector."
+msgstr ""
+
+msgid "The hostname of your diagrams.net server."
+msgstr ""
+
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
+msgid "The import is not complete."
+msgstr ""
+
+msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
+msgstr ""
+
+msgid "The interval must be one of %{intervals}."
+msgstr ""
+
+msgid "The invitation can not be found with the provided invite token."
+msgstr ""
+
+msgid "The invitation could not be accepted."
+msgstr ""
+
+msgid "The invitation could not be declined."
+msgstr ""
+
+msgid "The invitation has already been accepted."
+msgstr ""
+
+msgid "The invitation was successfully resent."
+msgstr ""
+
+msgid "The issue was successfully promoted to an epic. Redirecting to epic..."
+msgstr ""
+
+msgid "The last owner cannot be set to awaiting"
+msgstr ""
+
+msgid "The latest artifacts created by jobs in the most recent successful pipeline will be stored."
+msgstr ""
+
+msgid "The latest pipeline for this merge request did not succeed. The latest changes are unverified."
+msgstr ""
+
+msgid "The latest pipeline for this merge request has failed."
+msgstr ""
+
+msgid "The license key is invalid."
+msgstr ""
+
+msgid "The license key is invalid. Make sure it is exactly as you received it from GitLab Inc."
+msgstr ""
+
+msgid "The license was removed. GitLab has fallen back on the previous license."
+msgstr ""
+
+msgid "The license was removed. GitLab now no longer has a valid license."
+msgstr ""
+
+msgid "The license was successfully uploaded and is now active. You can see the details below."
+msgstr ""
+
+msgid "The license was successfully uploaded and will be active from %{starts_at}. You can see the details below."
+msgstr ""
+
+msgid "The license you uploaded is invalid. If the issue persists, contact support at %{link}."
+msgstr ""
+
+msgid "The list creation wizard is already open"
+msgstr ""
+
+msgid "The map can not be displayed because there was an error loading the GeoJSON file."
+msgstr ""
+
+msgid "The maximum amount of time users have to set up two-factor authentication before it's enforced."
+msgstr ""
+
+msgid "The maximum compute minutes that jobs in a namespace can use on shared runners each month. 0 for unlimited."
+msgstr ""
+
+msgid "The maximum file size allowed is %{size}."
+msgstr ""
+
+msgid "The maximum file size for job artifacts."
+msgstr ""
+
+msgid "The maximum file size in megabytes for individual job artifacts."
+msgstr ""
+
+msgid "The maximum file size is %{size}."
+msgstr ""
+
+msgid "The maximum number of tags that a single worker accepts for cleanup. If the number of tags goes above this limit, the list of tags to delete is truncated to this number. To remove this limit, set it to 0."
+msgstr ""
+
+msgid "The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally."
+msgstr ""
+
+msgid "The merge conflicts for this merge request have already been resolved."
+msgstr ""
+
+msgid "The merge conflicts for this merge request have already been resolved. Please return to the merge request."
+msgstr ""
+
+msgid "The metric must be one of %{metrics}."
+msgstr ""
+
+msgid "The name \"%{name}\" is already taken in this directory."
+msgstr ""
+
+msgid "The name of the CI/CD configuration file. A path relative to the root directory is optional (for example %{code_open}my/path/.myfile.yml%{code_close})."
+msgstr ""
+
+msgid "The name of the Jenkins project. Copy the name from the end of the URL to the project."
+msgstr ""
+
+msgid "The number of changes to fetch from GitLab when cloning a repository. Lower values can speed up pipeline execution. Set to %{code_open}0%{code_close} or blank to fetch all branches and tags for each job"
+msgstr ""
+
+msgid "The number of merge requests merged by month."
+msgstr ""
+
+msgid "The number of times an upload record could not find its file"
+msgstr ""
+
+msgid "The page could not be displayed because it timed out."
+msgstr ""
+
+msgid "The parent epic is confidential and can only contain confidential epics and issues"
+msgstr ""
+
+msgid "The password for the Jenkins server."
+msgstr ""
+
+msgid "The password for your GitLab account on %{gitlab_url} has successfully been changed."
+msgstr ""
+
+msgid "The password for your GitLab account on %{link_to_gitlab} has successfully been changed."
+msgstr ""
+
+msgid "The pipeline has been deleted"
+msgstr ""
+
+msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
+msgstr ""
+
+msgid "The project has already been added to your dashboard."
+msgstr ""
+
+msgid "The project is still being deleted. Please try again later."
+msgstr ""
+
+msgid "The project size exceeds the export limit."
+msgstr ""
+
+msgid "The project visibility may have been made more restrictive if the parent group's visibility changed while the deletion was scheduled."
+msgstr ""
+
+msgid "The project was successfully forked."
+msgstr ""
+
+msgid "The project was successfully imported."
+msgstr ""
+
+msgid "The related CI build failed."
+msgstr ""
+
+msgid "The remote mirror URL is invalid."
+msgstr ""
+
+msgid "The remote mirror took to long to complete."
+msgstr ""
+
+msgid "The remote repository is being updated..."
+msgstr ""
+
+msgid "The report artifact provided by the CI build couldn't be parsed."
+msgstr ""
+
+msgid "The report has been successfully prepared."
+msgstr ""
+
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
+msgstr ""
+
+msgid "The repository for this project does not exist."
+msgstr ""
+
+msgid "The repository for this project is empty"
+msgstr ""
+
+msgid "The repository is being updated..."
+msgstr ""
+
+msgid "The repository must be accessible over %{code_open}http://%{code_close}, %{code_open}https://%{code_close} or %{code_open}git://%{code_close}."
+msgstr ""
+
+msgid "The repository must be accessible over %{code_open}http://%{code_close}, %{code_open}https://%{code_close}, %{code_open}ssh://%{code_close} or %{code_open}git://%{code_close}."
+msgstr ""
+
+msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
+msgstr ""
+
+msgid "The scan has been created."
+msgstr ""
+
+msgid "The secret is only available when you create the application or renew the secret."
+msgstr ""
+
+msgid "The selected image is not a valid SVG diagram"
+msgstr ""
+
+msgid "The selected image is not an asset uploaded in the application"
+msgstr ""
+
+msgid "The selected image is too large."
+msgstr ""
+
+msgid "The snippet can be accessed without any authentication."
+msgstr ""
+
+msgid "The snippet can be accessed without any authentication. To embed snippets, a project must be public."
+msgstr ""
+
+msgid "The snippet is visible only to me."
+msgstr ""
+
+msgid "The snippet is visible only to project members."
+msgstr ""
+
+msgid "The snippet is visible to any logged in user except external users."
+msgstr ""
+
+msgid "The source project is a fork"
+msgstr ""
+
+msgid "The source project of this merge request has been removed."
+msgstr ""
+
+msgid "The source topic and the target topic are identical."
+msgstr ""
+
+msgid "The source topic is not a topic."
+msgstr ""
+
+msgid "The specified tab is invalid, please select another"
+msgstr ""
+
+msgid "The start date must be earlier than the end date."
+msgstr ""
+
+msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
+msgstr ""
+
+msgid "The tag name can't be changed for an existing release."
+msgstr ""
+
+msgid "The target topic is not a topic."
+msgstr ""
+
+msgid "The time period in seconds that the maximum requests per project limit applies to."
+msgstr ""
+
+msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
+msgstr ""
+
+msgid "The uploaded file was invalid. Supported file extensions are %{extensions}."
+msgstr ""
+
+msgid "The user is being deleted."
+msgstr ""
+
+msgid "The user map has been saved. Continue by selecting the projects you want to import."
+msgstr ""
+
+msgid "The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below."
+msgstr ""
+
+msgid "The user you are trying to approve is not pending approval"
+msgstr ""
+
+msgid "The user you are trying to deactivate has been active in the past %{minimum_inactive_days} days and cannot be deactivated"
+msgstr ""
+
+msgid "The username for the Jenkins server."
+msgstr ""
+
+msgid "The value of the provided variable exceeds the %{count} character limit"
+msgstr ""
+
+msgid "The vulnerability is known, and has not been remediated or mitigated, but is considered to be an acceptable business risk."
+msgstr ""
+
+msgid "The vulnerability is known, and has not been remediated or mitigated, but is considered to be in a part of the application that will not be updated."
+msgstr ""
+
+msgid "The vulnerability is no longer detected. Verify the vulnerability has been fixed or removed before changing its status."
+msgstr ""
+
+msgid "The vulnerability is no longer detected. Verify the vulnerability has been remediated before changing its status."
+msgstr ""
+
+msgid "There are currently no mirrored repositories."
+msgstr ""
+
+msgid "There are currently no target branch rules"
+msgstr ""
+
+msgid "There are merge conflicts"
+msgstr ""
+
+msgid "There are no GPG keys associated with this account."
+msgstr ""
+
+msgid "There are no GPG keys with access to your account."
+msgstr ""
+
+msgid "There are no SSH keys associated with this account."
+msgstr ""
+
+msgid "There are no SSH keys with access to your account."
+msgstr ""
+
+msgid "There are no Spam Logs"
+msgstr ""
+
+msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
+msgstr ""
+
+msgid "There are no archived requirements"
+msgstr ""
+
+msgid "There are no archived test cases"
+msgstr ""
+
+msgid "There are no changed labels"
+msgstr ""
+
+msgid "There are no changes"
+msgstr ""
+
+msgid "There are no charts configured for this page"
+msgstr ""
+
+msgid "There are no closed epics"
+msgstr ""
+
+msgid "There are no closed issues"
+msgstr ""
+
+msgid "There are no closed merge requests"
+msgstr ""
+
+msgid "There are no commits yet."
+msgstr ""
+
+msgid "There are no custom project templates set up for this GitLab instance. They are enabled from GitLab's Admin Area. Contact your GitLab instance administrator to setup custom project templates."
+msgstr ""
+
+msgid "There are no issues to show"
+msgstr ""
+
+msgid "There are no issues with the selected labels"
+msgstr ""
+
+msgid "There are no matching files"
+msgstr ""
+
+msgid "There are no open epics"
+msgstr ""
+
+msgid "There are no open issues"
+msgstr ""
+
+msgid "There are no open merge requests"
+msgstr ""
+
+msgid "There are no open requirements"
+msgstr ""
+
+msgid "There are no open test cases"
+msgstr ""
+
+msgid "There are no packages yet"
+msgstr ""
+
+msgid "There are no secure files yet."
+msgstr ""
+
+msgid "There are no topics to show."
+msgstr ""
+
+msgid "There are no variables yet."
+msgstr ""
+
+msgid "There are running deployments on the environment. Please retry later."
+msgstr ""
+
+msgid "There are several file size limits in place for the Package Registry."
+msgstr ""
+
+msgid "There are several rate limits in place to protect the system."
+msgstr ""
+
+msgid "There are several size limits in place."
+msgstr ""
+
+msgid "There is already a repository with that name on disk"
+msgstr ""
+
+msgid "There is already a to-do item for this design."
+msgstr ""
+
+msgid "There is no chart data available."
+msgstr ""
+
+msgid "There is no data available."
+msgstr ""
+
+msgid "There is no data available. Please change your selection."
+msgstr ""
+
+msgid "There is no table data available."
+msgstr ""
+
+msgid "There is too much data to calculate. Please change your selection."
+msgstr ""
+
+msgid "There was a problem communicating with your device."
+msgstr ""
+
+msgid "There was a problem creating the incident. Please try again."
+msgstr ""
+
+msgid "There was a problem fetching CRM contacts."
+msgstr ""
+
+msgid "There was a problem fetching CRM organizations."
+msgstr ""
+
+msgid "There was a problem fetching branches."
+msgstr ""
+
+msgid "There was a problem fetching emoji."
+msgstr ""
+
+msgid "There was a problem fetching epics."
+msgstr ""
+
+msgid "There was a problem fetching failed jobs"
+msgstr ""
+
+msgid "There was a problem fetching groups."
+msgstr ""
+
+msgid "There was a problem fetching iterations."
+msgstr ""
+
+msgid "There was a problem fetching labels."
+msgstr ""
+
+msgid "There was a problem fetching latest labels."
+msgstr ""
+
+msgid "There was a problem fetching linked pipelines."
+msgstr ""
+
+msgid "There was a problem fetching milestones."
+msgstr ""
+
+msgid "There was a problem fetching project branches."
+msgstr ""
+
+msgid "There was a problem fetching project tags."
+msgstr ""
+
+msgid "There was a problem fetching project users."
+msgstr ""
+
+msgid "There was a problem fetching recent groups."
+msgstr ""
+
+msgid "There was a problem fetching recent projects."
+msgstr ""
+
+msgid "There was a problem fetching releases."
+msgstr ""
+
+msgid "There was a problem fetching the job token scope value"
+msgstr ""
+
+msgid "There was a problem fetching the keep latest artifacts setting."
+msgstr ""
+
+msgid "There was a problem fetching the latest pipeline status."
+msgstr ""
+
+msgid "There was a problem fetching the pipeline stage."
+msgstr ""
+
+msgid "There was a problem fetching the pipeline stages."
+msgstr ""
+
+msgid "There was a problem fetching the projects"
+msgstr ""
+
+msgid "There was a problem fetching users."
+msgstr ""
+
+msgid "There was a problem handling the pipeline data."
+msgstr ""
+
+msgid "There was a problem sending the confirmation email"
+msgstr ""
+
+msgid "There was a problem updating the keep latest artifacts setting."
+msgstr ""
+
+msgid "There was an error creating the issue"
+msgstr ""
+
+msgid "There was an error fetching configuration for charts"
+msgstr ""
+
+msgid "There was an error fetching data for the selected stage"
+msgstr ""
+
+msgid "There was an error fetching data for the tasks by type chart"
+msgstr ""
+
+msgid "There was an error fetching label data for the selected group"
+msgstr ""
+
+msgid "There was an error fetching median data for stages"
+msgstr ""
+
+msgid "There was an error fetching projects"
+msgstr ""
+
+msgid "There was an error fetching stage total counts"
+msgstr ""
+
+msgid "There was an error fetching the %{replicableType}"
+msgstr ""
+
+msgid "There was an error fetching the cancelable jobs."
+msgstr ""
+
+msgid "There was an error fetching the deploy freezes."
+msgstr ""
+
+msgid "There was an error fetching the environments information."
+msgstr ""
+
+msgid "There was an error fetching the job."
+msgstr ""
+
+msgid "There was an error fetching the jobs for your project."
+msgstr ""
+
+msgid "There was an error fetching the jobs."
+msgstr ""
+
+msgid "There was an error fetching the number of jobs for your project."
+msgstr ""
+
+msgid "There was an error fetching the number of jobs."
+msgstr ""
+
+msgid "There was an error fetching the top labels for the selected group"
+msgstr ""
+
+msgid "There was an error fetching the variables."
+msgstr ""
+
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
+msgid "There was an error fetching value stream analytics stages."
+msgstr ""
+
+msgid "There was an error gathering the chart data"
+msgstr ""
+
+msgid "There was an error generating commit message."
+msgstr ""
+
+msgid "There was an error getting the epic participants."
+msgstr ""
+
+msgid "There was an error importing the Jira project."
+msgstr ""
+
+msgid "There was an error loading related feature flags"
+msgstr ""
+
+msgid "There was an error loading users activity calendar."
+msgstr ""
+
+msgid "There was an error parsing the data for this graph."
+msgstr ""
+
+msgid "There was an error removing the e-mail."
+msgstr ""
+
+msgid "There was an error retrieving LDAP groups. Please try again."
+msgstr ""
+
+msgid "There was an error retrieving the Jira users."
+msgstr ""
+
+msgid "There was an error running the job. Please try again."
+msgstr ""
+
+msgid "There was an error saving your changes."
+msgstr ""
+
+msgid "There was an error subscribing to this label."
+msgstr ""
+
+msgid "There was an error syncing project %{name}"
+msgstr ""
+
+msgid "There was an error syncing the %{replicableType}"
+msgstr ""
+
+msgid "There was an error trying to validate your query"
+msgstr ""
+
+msgid "There was an error updating the Maintenance Mode Settings"
+msgstr ""
+
+msgid "There was an error when reseting email token."
+msgstr ""
+
+msgid "There was an error when subscribing to this label."
+msgstr ""
+
+msgid "There was an error when unsubscribing from this label."
+msgstr ""
+
+msgid "There was an error while fetching the chart data. Please refresh the page to try again."
+msgstr ""
+
+msgid "There was an error while fetching the table data. Please refresh the page to try again."
+msgstr ""
+
+msgid "There was an error while fetching value stream analytics data."
+msgstr ""
+
+msgid "There was an error while fetching value stream analytics duration data."
+msgstr ""
+
+msgid "There was an error while retrying this job"
+msgstr ""
+
+msgid "There was an error with the reCAPTCHA. Please solve the reCAPTCHA again."
+msgstr ""
+
+msgid "There was an summarizing your pending comments."
+msgstr ""
+
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
+msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
+msgstr ""
+
+msgid "These examples show common methods of triggering a pipeline with a pipeline trigger token. The URL and ID for this project is prefilled."
+msgstr ""
+
+msgid "These existing issues have a similar title. It might be better to comment there instead of creating another similar issue."
+msgstr ""
+
+msgid "These runners are shared across projects in this group."
+msgstr ""
+
+msgid "These variables are inherited from the parent group."
+msgstr ""
+
+msgid "These will be sent to %{email} in an attachment once finished."
+msgstr ""
+
+msgid "Things to be aware of before transferring:"
+msgstr ""
+
+msgid "Third Party Advisory Link"
+msgstr ""
+
+msgid "Third party AI settings not allowed."
+msgstr ""
+
+msgid "This %{issuableDisplayName} is locked. Only project members can comment."
+msgstr ""
+
+msgid "This %{issuable} is hidden because its author has been banned"
+msgstr ""
+
+msgid "This %{issuable} is locked. Only %{strong_open}project members%{strong_close} can comment."
+msgstr ""
+
+msgid "This %{issuable} is locked. Only project members can comment."
+msgstr ""
+
+msgid "This %{noteableTypeText} is %{confidentialLinkStart}confidential%{confidentialLinkEnd} and %{lockedLinkStart}locked%{lockedLinkEnd}."
+msgstr ""
+
+msgid "This %{noteableTypeText} is locked."
+msgstr ""
+
+msgid "This %{viewer} could not be displayed because %{reason}. You can %{options} instead."
+msgstr ""
+
+msgid "This Cron pattern is invalid"
+msgstr ""
+
+msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
+msgstr ""
+
+msgid "This PDF is too large to display. Please download to view."
+msgstr ""
+
+msgid "This URL already exists."
+msgstr ""
+
+msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
+msgstr ""
+
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key. All commits signed using this SSH key will be marked as unverified."
+msgstr ""
+
+msgid "This action deletes %{codeOpen}%{project_path_with_namespace}%{codeClose} and everything this project contains. %{strongOpen}There is no going back.%{strongClose}"
+msgstr ""
+
+msgid "This action deletes %{codeOpen}%{project_path_with_namespace}%{codeClose} on %{date} and everything this project contains."
+msgstr ""
+
+msgid "This action deletes %{codeOpen}%{project_path_with_namespace}%{codeClose} on %{date} and everything this project contains. %{strongOpen}There is no going back.%{strongClose}"
+msgstr ""
+
+msgid "This action will %{strongOpen}permanently remove%{strongClose} %{codeOpen}%{group}%{codeClose} %{strongOpen}immediately%{strongClose}."
+msgstr ""
+
+msgid "This also resolves all related threads"
+msgstr ""
+
+msgid "This also resolves this thread"
+msgstr ""
+
+msgid "This application was created by %{user_link}."
+msgstr ""
+
+msgid "This application was created for group %{group_link}."
+msgstr ""
+
+msgid "This application will be able to:"
+msgstr ""
+
+msgid "This archive has been requested too many times. Try again later."
+msgstr ""
+
+msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{count} %{issuables} have been included. Consider re-exporting with a narrower selection of %{issuables}."
+msgstr ""
+
+msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of %{size_limit}. %{written_count} of %{total_count} %{object_type} have been included. Consider re-exporting with a narrower selection of %{object_type}."
+msgstr ""
+
+msgid "This block is self-referential"
+msgstr ""
+
+msgid "This board's scope is reduced"
+msgstr ""
+
+msgid "This branch has diverged from upstream."
+msgstr ""
+
+msgid "This change will remove %{strongOpen}ALL%{strongClose} Premium and Ultimate features for %{strongOpen}ALL%{strongClose} SaaS customers and make tests start failing."
+msgstr ""
+
+msgid "This chart could not be displayed"
+msgstr ""
+
+msgid "This clears repository check states for all projects in the database and cannot be undone. Are you sure?"
+msgstr ""
+
+msgid "This code snippet contains everything reflected in the configuration form. Copy and paste it into %{linkStart}.gitlab-ci.yml%{linkEnd} file and save your changes. Future %{scanType} scans will use these settings."
+msgstr ""
+
+msgid "This comment changed after you started editing it. Review the %{startTag}updated comment%{endTag} to ensure information is not lost."
+msgstr ""
+
+msgid "This comment was generated by AI"
+msgstr ""
+
+msgid "This commit is part of merge request %{link_to_merge_request}. Comments created here will be created in the context of that merge request."
+msgstr ""
+
+msgid "This commit was created in the GitLab UI, and signed with a GitLab-verified signature."
+msgstr ""
+
+msgid "This commit was signed with a %{strong_open}verified%{strong_close} signature and the committer email is verified to belong to the same user."
+msgstr ""
+
+msgid "This commit was signed with a different user's verified signature."
+msgstr ""
+
+msgid "This commit was signed with a verified signature and the committer email was verified to belong to the same user."
+msgstr ""
+
+msgid "This commit was signed with a verified signature, but the committer email is not associated with the GPG Key."
+msgstr ""
+
+msgid "This commit was signed with an %{strong_open}unverified%{strong_close} signature."
+msgstr ""
+
+msgid "This commit was signed with an unverified signature."
+msgstr ""
+
+msgid "This commit was signed with multiple signatures."
+msgstr ""
+
+msgid "This content could not be displayed because %{reason}. You can %{options} instead."
+msgstr ""
+
+msgid "This content could not be displayed because it is stored in LFS. You can %{linkStart}download it%{linkEnd} instead."
+msgstr ""
+
+msgid "This credential has expired"
+msgstr ""
+
+msgid "This deployment is not waiting for approvals."
+msgstr ""
+
+msgid "This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run."
+msgstr ""
+
+msgid "This deployment job does not run automatically and must be started manually, but you do not have access to this job's protected environment. The job can only be started by a project member allowed to deploy to the environment."
+msgstr ""
+
+msgid "This device has already been registered with us."
+msgstr ""
+
+msgid "This device has not been registered with us."
+msgstr ""
+
+msgid "This diff is collapsed."
+msgstr ""
+
+msgid "This directory"
+msgstr ""
+
+msgid "This domain is not verified. You will need to verify ownership before access is enabled."
+msgstr ""
+
+msgid "This email address does not look right, are you sure you typed it correctly?"
+msgstr ""
+
+msgid "This email supersedes any previous emails about scheduled deletion you may have received for %{project_link}."
+msgstr ""
+
+msgid "This email supersedes any previous emails about scheduled deletion you may have received for %{project_name}."
+msgstr ""
+
+msgid "This endpoint has been requested too many times. Try again later."
+msgstr ""
+
+msgid "This environment has no deployments yet."
+msgstr ""
+
+msgid "This environment is being deployed"
+msgstr ""
+
+msgid "This environment is being re-deployed"
+msgstr ""
+
+msgid "This environment is not protected."
+msgstr ""
+
+msgid "This environment's canary ingress has been updated recently. Please retry later."
+msgstr ""
+
+msgid "This epic already has the maximum number of child epics."
+msgstr ""
+
+msgid "This epic cannot be added. An epic cannot be added to itself."
+msgstr ""
+
+msgid "This epic cannot be added. It is already an ancestor of the parent epic."
+msgstr ""
+
+msgid "This epic cannot be added. It is already assigned to the parent epic."
+msgstr ""
+
+msgid "This epic cannot be added. One or more epics would exceed the maximum depth (%{max_depth}) from its most distant ancestor."
+msgstr ""
+
+msgid "This epic cannot be added. You don't have access to perform this action."
+msgstr ""
+
+msgid "This epic does not exist or you don't have sufficient permission."
+msgstr ""
+
+msgid "This epic would exceed maximum number of related epics."
+msgstr ""
+
+msgid "This feature requires local storage to be enabled"
+msgstr ""
+
+msgid "This field is auto-calculated based on the Progress score of its direct children. You can overwrite this value but it will be replaced by the auto-calculation anytime the Progress score of its direct children are updated."
+msgstr ""
+
+msgid "This field is required"
+msgstr ""
+
+msgid "This field is required."
+msgstr ""
+
+msgid "This file was modified for readability, and can't accept suggestions. Edit it directly."
+msgstr ""
+
+msgid "This form is disabled in preview"
+msgstr ""
+
+msgid "This group"
+msgstr ""
+
+msgid "This group and its subgroups and projects will be placed in a 'pending deletion' state for %{deletion_delayed_period} days, then permanently deleted on %{date}. The group can be fully restored before that date."
+msgstr ""
+
+msgid "This group can't be removed because it is linked to a subscription. To remove this group, %{linkStart}link the subscription%{linkEnd} with a different group."
+msgstr ""
+
+msgid "This group can't be transferred because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group."
+msgstr ""
+
+msgid "This group cannot be invited to a project inside a group with enforced SSO"
+msgstr ""
+
+msgid "This group does not have any group runners yet."
+msgstr ""
+
+msgid "This group has been scheduled for permanent removal on %{date}"
+msgstr ""
+
+msgid "This group has no active access tokens."
+msgstr ""
+
+msgid "This group has no projects yet"
+msgstr ""
+
+msgid "This group is linked to a subscription"
+msgstr ""
+
+msgid "This group is not permitted to create compliance violations"
+msgstr ""
+
+msgid "This group, its subgroups and projects has been scheduled for removal on %{date}."
+msgstr ""
+
+msgid "This group, its subgroups and projects will be removed on %{date} since its parent group '%{parent_group_name}' has been scheduled for removal."
+msgstr ""
+
+msgid "This incident is already escalated with '%{escalation_policy_name}'."
+msgstr ""
+
+msgid "This instance is now read-only. Don't worry, your data is safe. To change to GitLab Free and restore write access to this instance, delete your expired license."
+msgstr ""
+
+msgid "This invitation was sent to %{mail_to_invite_email}, but you are signed in as %{link_to_current_user} with email %{mail_to_current_user}."
+msgstr ""
+
+msgid "This is a \"Ghost User\", created to hold all issues authored by users that have since been deleted. This user cannot be removed."
+msgstr ""
+
+msgid "This is a Jira user."
+msgstr ""
+
+msgid "This is a child pipeline within the parent pipeline"
+msgstr ""
+
+msgid "This is a confidential %{noteableTypeText}."
+msgstr ""
+
+msgid "This is a delayed job to run in %{remainingTime}"
+msgstr ""
+
+msgid "This is a list of devices that have logged into your account. Revoke any sessions that you do not recognize."
+msgstr ""
+
+msgid "This is a private email address %{helpIcon} generated just for you. Anyone who has it can create issues or merge requests as if they were you. If that happens, %{resetLinkStart}reset this token%{resetLinkEnd}."
+msgstr ""
+
+msgid "This is a security log of authentication events involving your account."
+msgstr ""
+
+msgid "This is a self-managed instance of GitLab."
+msgstr ""
+
+msgid "This is an experimental feature developed by GitLab Incubation Engineering."
+msgstr ""
+
+msgid "This is the highest peak of users on your installation since the license started."
+msgstr ""
+
+msgid "This is the number of %{billable_users_link_start}billable users%{link_end} on your installation, and this is the minimum number you need to purchase when you renew your license."
+msgstr ""
+
+msgid "This is the only time the secret is accessible. Copy the secret and store it securely."
+msgstr ""
+
+msgid "This is your current session"
+msgstr ""
+
+msgid "This issue cannot be assigned to a confidential epic because it is public."
+msgstr ""
+
+msgid "This issue cannot be made public because it belongs to a confidential epic."
+msgstr ""
+
+msgid "This issue is confidential and should only be visible to team members with at least Reporter access."
+msgstr ""
+
+msgid "This issue is currently blocked by the following issues:"
+msgstr ""
+
+msgid "This issue is hidden because its author has been banned"
+msgstr ""
+
+msgid "This issue is in a child epic of the filtered epic"
+msgstr ""
+
+msgid "This issue is locked. Only project members can comment."
+msgstr ""
+
+msgid "This job could not start because it could not retrieve the needed artifacts%{punctuation}%{invalid_dependencies}"
+msgstr ""
+
+msgid "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
+msgstr ""
+
+msgid "This job deploys to the protected environment \"%{environment}\", which requires approvals. You can approve or reject the deployment on the environment details page."
+msgstr ""
+
+msgid "This job does not have a trace."
+msgstr ""
+
+msgid "This job does not run automatically and must be started manually, but you do not have access to it."
+msgstr ""
+
+msgid "This job does not start automatically and must be started manually. You can add CI/CD variables below for last-minute configuration changes before starting the job."
+msgstr ""
+
+msgid "This job has been canceled"
+msgstr ""
+
+msgid "This job has been skipped"
+msgstr ""
+
+msgid "This job has not been triggered yet"
+msgstr ""
+
+msgid "This job has not started yet"
+msgstr ""
+
+msgid "This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}."
+msgstr ""
+
+msgid "This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}. View the %{deploymentLink}."
+msgstr ""
+
+msgid "This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink}."
+msgstr ""
+
+msgid "This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink}. View the %{deploymentLink}."
+msgstr ""
+
+msgid "This job is an out-of-date deployment to %{environmentLink}."
+msgstr ""
+
+msgid "This job is an out-of-date deployment to %{environmentLink}. View the %{deploymentLink}."
+msgstr ""
+
+msgid "This job is archived. Only the complete pipeline can be retried."
+msgstr ""
+
+msgid "This job is creating a deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}."
+msgstr ""
+
+msgid "This job is creating a deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}. This will overwrite the %{deploymentLink}."
+msgstr ""
+
+msgid "This job is creating a deployment to %{environmentLink} using cluster %{clusterNameOrLink}."
+msgstr ""
+
+msgid "This job is creating a deployment to %{environmentLink} using cluster %{clusterNameOrLink}. This will overwrite the %{deploymentLink}."
+msgstr ""
+
+msgid "This job is creating a deployment to %{environmentLink}."
+msgstr ""
+
+msgid "This job is creating a deployment to %{environmentLink}. This will overwrite the %{deploymentLink}."
+msgstr ""
+
+msgid "This job is deployed to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}."
+msgstr ""
+
+msgid "This job is deployed to %{environmentLink} using cluster %{clusterNameOrLink}."
+msgstr ""
+
+msgid "This job is deployed to %{environmentLink}."
+msgstr ""
+
+msgid "This job is in pending state and is waiting to be picked by a runner"
+msgstr ""
+
+msgid "This job is performing tasks that must complete before it can start"
+msgstr ""
+
+msgid "This job is preparing to start"
+msgstr ""
+
+msgid "This job is waiting for resource: "
+msgstr ""
+
+msgid "This job requires a manual action"
+msgstr ""
+
+msgid "This job will automatically run after its timer finishes. Often they are used for incremental roll-out deploys to production environments. When unscheduled it converts into a manual action."
+msgstr ""
+
+msgid "This license has already expired."
+msgstr ""
+
+msgid "This link points to external content"
+msgstr ""
+
+msgid "This may expose confidential information as the selected fork is in another namespace that can have other members."
+msgstr ""
+
+msgid "This means you can not push code until you create an empty repository or import existing one."
+msgstr ""
+
+msgid "This merge request branch is protected from force push."
+msgstr ""
+
+msgid "This merge request cannot be rebased while there are conflicts."
+msgstr ""
+
+msgid "This merge request does not have accessibility reports"
+msgstr ""
+
+msgid "This merge request does not have codequality reports"
+msgstr ""
+
+msgid "This merge request is closed. To apply this suggestion, edit this file directly."
+msgstr ""
+
+msgid "This merge request is from a private project to a public project."
+msgstr ""
+
+msgid "This merge request is from a private project to an internal project."
+msgstr ""
+
+msgid "This merge request is from an internal project to a public project."
+msgstr ""
+
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
+msgid "This merge request is locked."
+msgstr ""
+
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
+msgid "This merge request was merged. To apply this suggestion, edit this file directly."
+msgstr ""
+
+msgid "This only applies to repository indexing operations."
+msgstr ""
+
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgstr ""
+
+msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}"
+msgstr ""
+
+msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
+msgstr ""
+
+msgid "This pipeline was created by a schedule"
+msgstr ""
+
+msgid "This pipeline was created by a schedule."
+msgstr ""
+
+msgid "This process deletes the project repository and all related resources."
+msgstr ""
+
+msgid "This project can be restored until %{date}."
+msgstr ""
+
+msgid "This project cannot be %{visibilityLevel} because the visibility of %{openShowLink}%{name}%{closeShowLink} is %{visibility}. To make this project %{visibilityLevel}, you must first %{openEditLink}change the visibility%{closeEditLink} of the parent group."
+msgstr ""
+
+msgid "This project does not belong to a group and cannot make use of group runners."
+msgstr ""
+
+msgid "This project does not have %{service_desk_link_start}Service Desk%{service_desk_link_end} enabled, so the user who created the issue will no longer receive email notifications about new activity."
+msgstr ""
+
+msgid "This project does not have a wiki homepage yet"
+msgstr ""
+
+msgid "This project has no active access tokens."
+msgstr ""
+
+msgid "This project is %{strongStart}NOT%{strongEnd} a fork, and has the following:"
+msgstr ""
+
+msgid "This project is %{strongStart}NOT%{strongEnd} a fork. This process deletes the project repository and all related resources."
+msgstr ""
+
+msgid "This project is archived and cannot be commented on."
+msgstr ""
+
+msgid "This project is archived and read-only. To resume pull mirroring, unarchive the project."
+msgstr ""
+
+msgid "This project is hidden because its creator has been banned"
+msgstr ""
+
+msgid "This project is licensed under the %{strong_start}%{license_name}%{strong_end}."
+msgstr ""
+
+msgid "This project is mirrored from %{link}."
+msgstr ""
+
+msgid "This project is not subscribed to any project pipelines."
+msgstr ""
+
+msgid "This project is public. Non-members can guess the Service Desk email address, because it contains the group and project name. %{linkStart}How do I create a custom email address?%{linkEnd}"
+msgstr ""
+
+msgid "This project manages its dependencies using %{strong_start}%{manager_name}%{strong_end}"
+msgstr ""
+
+msgid "This project path either does not exist or you do not have access."
+msgstr ""
+
+msgid "This project reached the limit of custom domains. (Max %d)"
+msgstr ""
+
+msgid "This project was scheduled for deletion, but failed with the following message:"
+msgstr ""
+
+msgid "This project will be deleted on %{date}"
+msgstr ""
+
+msgid "This project will be deleted on %{date} since its parent group '%{parent_group_name}' has been scheduled for deletion."
+msgstr ""
+
+msgid "This project's pipeline configuration is located outside this repository"
+msgstr ""
+
+msgid "This release was created with a date in the past. Evidence collection at the moment of the release is unavailable."
+msgstr ""
+
+msgid "This report uses a supported MAJOR.MINOR schema version but the PATCH version doesn't match any vendored schema version. Validation will be attempted against version %{find_latest_patch_version}"
+msgstr ""
+
+msgid "This repository"
+msgstr ""
+
+msgid "This repository has never been checked."
+msgstr ""
+
+msgid "This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch."
+msgstr ""
+
+msgid "This repository was last checked %{last_check_timestamp}. The check %{strong_start}failed.%{strong_end} See the 'repocheck.log' file for error messages."
+msgstr ""
+
+msgid "This repository was last checked %{last_check_timestamp}. The check passed."
+msgstr ""
+
+msgid "This runner will only run on pipelines triggered on protected branches"
+msgstr ""
+
+msgid "This setting can be overridden in each project."
+msgstr ""
+
+msgid "This setting has been configured at the instance level and cannot be overridden per group"
+msgstr ""
+
+msgid "This setting is allowed for forked projects only"
+msgstr ""
+
+msgid "This subscription is for"
+msgstr ""
+
+msgid "This suggestion already matches its content."
+msgstr ""
+
+msgid "This title already exists."
+msgstr ""
+
+msgid "This user cannot be unlocked manually from GitLab"
+msgstr ""
+
+msgid "This user has an unconfirmed email address (%{email}). You may force a confirmation."
+msgstr ""
+
+msgid "This user has an unconfirmed email address. You may force a confirmation."
+msgstr ""
+
+msgid "This user has no active %{accessTokenTypePlural}."
+msgstr ""
+
+msgid "This user has no identities"
+msgstr ""
+
+msgid "This user has no personal projects."
+msgstr ""
+
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is currently exempt from phone verification. Remove the exemption using the button below."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
+msgid "This user is the author of this %{workItemType}."
+msgstr ""
+
+msgid "This variable value does not meet the masking requirements."
+msgstr ""
+
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
+msgstr ""
+
+msgid "This will invalidate your registered applications and WebAuthn devices."
+msgstr ""
+
+msgid "This will remove the fork relationship between this project and %{fork_source}."
+msgstr ""
+
+msgid "This will remove the fork relationship between this project and other projects in the fork network."
+msgstr ""
+
+msgid "Thread options"
+msgstr ""
+
+msgid "Thread to reply to cannot be found"
+msgstr ""
+
+msgid "Threshold in bytes at which to compress Sidekiq job arguments."
+msgstr ""
+
+msgid "Threshold in bytes at which to reject Sidekiq jobs. Set this to 0 to if you don't want to limit Sidekiq jobs."
+msgstr ""
+
+msgid "Throughput"
+msgstr ""
+
+msgid "Thu"
+msgstr ""
+
+msgid "Thursday"
+msgstr ""
+
+msgid "TierBadgePopover|Enhance team productivity"
+msgstr ""
+
+msgid "TierBadgePopover|Explore paid plans"
+msgstr ""
+
+msgid "TierBadgePopover|Start a free trial"
+msgstr ""
+
+msgid "TierBadgePopover|This group and all its related projects use the %{tier} GitLab tier. %{copyEnd}"
+msgstr ""
+
+msgid "TierBadgePopover|This project uses the %{tier} GitLab tier. %{copyEnd}"
+msgstr ""
+
+msgid "TierBadgePopover|Want to enhance team productivity and access advanced features like Merge Approvals, Push rules, Epics, Code Review Analytics, and Container Scanning? Try all GitLab has to offer for free for 30 days. No credit card required."
+msgstr ""
+
+msgid "TierBadge|Free"
+msgstr ""
+
+msgid "Time"
+msgstr ""
+
+msgid "Time (in hours) that users are allowed to skip forced configuration of two-factor authentication."
+msgstr ""
+
+msgid "Time based: Yes"
+msgstr ""
+
+msgid "Time before an issue gets scheduled"
+msgstr ""
+
+msgid "Time before an issue starts implementation"
+msgstr ""
+
+msgid "Time between merge request creation and merge/close"
+msgstr ""
+
+msgid "Time estimate"
+msgstr ""
+
+msgid "Time from first comment to last commit"
+msgstr ""
+
+msgid "Time from first commit until first comment"
+msgstr ""
+
+msgid "Time from last commit to merge"
+msgstr ""
+
+msgid "Time of import: %{importTime}"
+msgstr ""
+
+msgid "Time remaining"
+msgstr ""
+
+msgid "Time spent"
+msgstr ""
+
+msgid "Time spent can't be zero."
+msgstr ""
+
+msgid "Time spent must be formatted correctly. For example: 1h 30m."
+msgstr ""
+
+msgid "Time to Merge"
+msgstr ""
+
+msgid "Time to Restore Service"
+msgstr ""
+
+msgid "Time to merge"
+msgstr ""
+
+msgid "Time to subtract exceeds the total time spent"
+msgstr ""
+
+msgid "Time tracking"
+msgstr ""
+
+msgid "Time tracking report"
+msgstr ""
+
+msgid "Time until first merge request"
+msgstr ""
+
+msgid "Time zone"
+msgstr ""
+
+msgid "TimeTrackingEstimated|Est"
+msgstr ""
+
+msgid "TimeTrackingReport|From the start of"
+msgstr ""
+
+msgid "TimeTrackingReport|Run report"
+msgstr ""
+
+msgid "TimeTrackingReport|Something went wrong. Please try again."
+msgstr ""
+
+msgid "TimeTrackingReport|Source"
+msgstr ""
+
+msgid "TimeTrackingReport|Spent at"
+msgstr ""
+
+msgid "TimeTrackingReport|Summary"
+msgstr ""
+
+msgid "TimeTrackingReport|Time spent"
+msgstr ""
+
+msgid "TimeTrackingReport|To the end of"
+msgstr ""
+
+msgid "TimeTrackingReport|Total time spent: "
+msgstr ""
+
+msgid "TimeTrackingReport|User"
+msgstr ""
+
+msgid "TimeTrackingReport|Username"
+msgstr ""
+
+msgid "TimeTracking|%{spentStart}Spent: %{spentEnd}"
+msgstr ""
+
+msgid "TimeTracking|An error occurred while removing the timelog."
+msgstr ""
+
+msgid "TimeTracking|An error occurred while saving the time estimate."
+msgstr ""
+
+msgid "TimeTracking|Delete time spent"
+msgstr ""
+
+msgid "TimeTracking|Edit estimate"
+msgstr ""
+
+msgid "TimeTracking|Edit time estimate"
+msgstr ""
+
+msgid "TimeTracking|Enter time as a total duration (for example, 1mo 2w 3d 5h 10m), or specify hours and minutes (for example, 75:30)."
+msgstr ""
+
+msgid "TimeTracking|Estimate"
+msgstr ""
+
+msgid "TimeTracking|Estimated:"
+msgstr ""
+
+msgid "TimeTracking|How do I estimate and track time?"
+msgstr ""
+
+msgid "TimeTracking|Over by %{timeRemainingHumanReadable}"
+msgstr ""
+
+msgid "TimeTracking|Set estimate"
+msgstr ""
+
+msgid "TimeTracking|Set estimated time to complete this %{issuableTypeName}."
+msgstr ""
+
+msgid "TimeTracking|Set time estimate"
+msgstr ""
+
+msgid "TimeTracking|Spent"
+msgstr ""
+
+msgid "TimeTracking|Time remaining: %{timeRemainingHumanReadable}"
+msgstr ""
+
+msgid "Timeago|%s days ago"
+msgstr ""
+
+msgid "Timeago|%s days remaining"
+msgstr ""
+
+msgid "Timeago|%s hours ago"
+msgstr ""
+
+msgid "Timeago|%s hours remaining"
+msgstr ""
+
+msgid "Timeago|%s minutes ago"
+msgstr ""
+
+msgid "Timeago|%s minutes remaining"
+msgstr ""
+
+msgid "Timeago|%s months ago"
+msgstr ""
+
+msgid "Timeago|%s months remaining"
+msgstr ""
+
+msgid "Timeago|%s seconds remaining"
+msgstr ""
+
+msgid "Timeago|%s weeks ago"
+msgstr ""
+
+msgid "Timeago|%s weeks remaining"
+msgstr ""
+
+msgid "Timeago|%s years ago"
+msgstr ""
+
+msgid "Timeago|%s years remaining"
+msgstr ""
+
+msgid "Timeago|1 day ago"
+msgstr ""
+
+msgid "Timeago|1 day remaining"
+msgstr ""
+
+msgid "Timeago|1 hour ago"
+msgstr ""
+
+msgid "Timeago|1 hour remaining"
+msgstr ""
+
+msgid "Timeago|1 minute ago"
+msgstr ""
+
+msgid "Timeago|1 minute remaining"
+msgstr ""
+
+msgid "Timeago|1 month ago"
+msgstr ""
+
+msgid "Timeago|1 month remaining"
+msgstr ""
+
+msgid "Timeago|1 week ago"
+msgstr ""
+
+msgid "Timeago|1 week remaining"
+msgstr ""
+
+msgid "Timeago|1 year ago"
+msgstr ""
+
+msgid "Timeago|1 year remaining"
+msgstr ""
+
+msgid "Timeago|Past due"
+msgstr ""
+
+msgid "Timeago|in %s days"
+msgstr ""
+
+msgid "Timeago|in %s hours"
+msgstr ""
+
+msgid "Timeago|in %s minutes"
+msgstr ""
+
+msgid "Timeago|in %s months"
+msgstr ""
+
+msgid "Timeago|in %s seconds"
+msgstr ""
+
+msgid "Timeago|in %s weeks"
+msgstr ""
+
+msgid "Timeago|in %s years"
+msgstr ""
+
+msgid "Timeago|in 1 day"
+msgstr ""
+
+msgid "Timeago|in 1 hour"
+msgstr ""
+
+msgid "Timeago|in 1 minute"
+msgstr ""
+
+msgid "Timeago|in 1 month"
+msgstr ""
+
+msgid "Timeago|in 1 week"
+msgstr ""
+
+msgid "Timeago|in 1 year"
+msgstr ""
+
+msgid "Timeago|just now"
+msgstr ""
+
+msgid "Timeago|right now"
+msgstr ""
+
+msgid "Timeline"
+msgstr ""
+
+msgid "Timeline event added successfully."
+msgstr ""
+
+msgid "Timeline|Turn recent updates view off"
+msgstr ""
+
+msgid "Timeline|Turn recent updates view on"
+msgstr ""
+
+msgid "Timelog doesn't exist or you don't have permission to delete it"
+msgstr ""
+
+msgid "Timeout"
+msgstr ""
+
+msgid "Timeout connecting to the Google API. Please try again."
+msgstr ""
+
+msgid "Timeout for moderately fast Gitaly operations (in seconds). Provide a value between Default timeout and Fast timeout."
+msgstr ""
+
+msgid "Timeout for most Gitaly operations (in seconds)."
+msgstr ""
+
+msgid "Timeout for the fastest Gitaly operations (in seconds)."
+msgstr ""
+
+msgid "Timezone"
+msgstr ""
+
+msgid "Time|A"
+msgstr ""
+
+msgid "Time|AM"
+msgstr ""
+
+msgid "Time|P"
+msgstr ""
+
+msgid "Time|PM"
+msgstr ""
+
+msgid "Time|a"
+msgstr ""
+
+msgid "Time|am"
+msgstr ""
+
+msgid "Time|hr"
+msgid_plural "Time|hrs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Time|min"
+msgid_plural "Time|mins"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Time|p"
+msgstr ""
+
+msgid "Time|pm"
+msgstr ""
+
+msgid "Time|s"
+msgstr ""
+
+msgid "Tip: Hover over a job to see the jobs it depends on to run."
+msgstr ""
+
+msgid "Tip: add a %{linkStart}CODEOWNERS%{linkEnd} to automatically add approvers based on file paths and file types."
+msgstr ""
+
+msgid "Title"
+msgstr ""
+
+msgid "Title (required)"
+msgstr ""
+
+msgid "Title:"
+msgstr ""
+
+msgid "Titles"
+msgstr ""
+
+msgid "To"
+msgstr ""
+
+msgid "To %{link_to_help} of your domain, add the above key to a TXT record within your DNS configuration within seven days."
+msgstr ""
+
+msgid "To Do"
+msgstr ""
+
+msgid "To GitLab"
+msgstr ""
+
+msgid "To accept this invitation, create an account or sign in."
+msgstr ""
+
+msgid "To accept this invitation, sign in or create an account."
+msgstr ""
+
+msgid "To accept this invitation, sign in."
+msgstr ""
+
+msgid "To access this domain create a new DNS record"
+msgstr ""
+
+msgid "To activate your trial, we need additional details from you."
+msgstr ""
+
+msgid "To add a custom suffix, set up a Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
+msgid "To add the entry manually, provide the following details to the application on your phone."
+msgstr ""
+
+msgid "To approve this merge request, please enter your password. This project requires all approvals to be authenticated."
+msgstr ""
+
+msgid "To complete registration, we need additional details from you."
+msgstr ""
+
+msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
+msgstr ""
+
+msgid "To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories."
+msgstr ""
+
+msgid "To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:"
+msgstr ""
+
+msgid "To connect an SVN repository, check out %{svn_link}."
+msgstr ""
+
+msgid "To continue using GitLab Enterprise Edition, upload the %{codeOpen}.gitlab-license%{codeClose} file or enter the license key you have received from GitLab Inc."
+msgstr ""
+
+msgid "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select %{strongStart}Resend confirmation email.%{strongEnd}"
+msgstr ""
+
+msgid "To define internal users, first enable new users set to external"
+msgstr ""
+
+msgid "To edit the pipeline configuration, you must go to the project or external site that hosts the file."
+msgstr ""
+
+msgid "To enable Registration Features, first enable Service Ping."
+msgstr ""
+
+msgid "To ensure %{project_link} is unscheduled for deletion, check that activity has been logged by GitLab. For example:"
+msgstr ""
+
+msgid "To ensure %{project_name} is unscheduled for deletion, check that activity has been logged by GitLab. For example:"
+msgstr ""
+
+msgid "To ensure no loss of access to personal content, only use this account for matters related to %{group_name}."
+msgstr ""
+
+msgid "To ensure no loss of personal content, this account should only be used for matters related to %{group_name}."
+msgstr ""
+
+msgid "To find the state of this project's repository at the time of any of these versions, check out %{link_start}the tags%{link_end}"
+msgstr ""
+
+msgid "To further protect your account, consider configuring a %{mfa_link_start}two-factor authentication%{mfa_link_end} method."
+msgstr ""
+
+msgid "To further protect your account, consider configuring a two-factor authentication method: %{mfa_link}."
+msgstr ""
+
+msgid "To get started you enter your FogBugz URL and login information below. In the next steps, you'll be able to map users and select the projects you want to import."
+msgstr ""
+
+msgid "To get started, click the link below to confirm your account."
+msgstr ""
+
+msgid "To get started, please enter your Gitea host URL and a %{link_to_personal_token}."
+msgstr ""
+
+msgid "To get started, use the link below to confirm your account."
+msgstr ""
+
+msgid "To go to GitLab Pages, on the left sidebar, select %{pages_link}."
+msgstr ""
+
+msgid "To import an SVN repository, check out %{svn_link}."
+msgstr ""
+
+msgid "To invite more users, you can reduce the number of users in your top-level group to %{free_limit} user or less. You can also upgrade to a paid tier which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgid_plural "To invite more users, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "To keep this project going, create a new issue"
+msgstr ""
+
+msgid "To keep this project going, create a new merge request"
+msgstr ""
+
+msgid "To learn more about this project, read %{link_to_wiki}"
+msgstr ""
+
+msgid "To manage seats for all members associated with this group and its subgroups and projects, visit the %{link_start}usage quotas page%{link_end}."
+msgstr ""
+
+msgid "To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
+msgstr ""
+
+msgid "To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here."
+msgstr ""
+
+msgid "To only use CI/CD features for an external repository, choose %{strong_open}CI/CD for external repo%{strong_close}."
+msgstr ""
+
+msgid "To pass variables to the triggered pipeline, add %{code_start}variables[VARIABLE]=VALUE%{code_end} to the API request."
+msgstr ""
+
+msgid "To personalize your GitLab experience, we'd like to know a bit more about you"
+msgstr ""
+
+msgid "To protect this issue's confidentiality, %{linkStart}fork this project%{linkEnd} and set the fork's visibility to private."
+msgstr ""
+
+msgid "To protect this issue's confidentiality, a private fork of this project was selected."
+msgstr ""
+
+msgid "To reactivate your account, %{gitlab_link_start}sign in to GitLab.%{link_end}"
+msgstr ""
+
+msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
+msgstr ""
+
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
+msgstr ""
+
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
+msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
+msgstr ""
+
+msgid "To resolve this, try to:"
+msgstr ""
+
+msgid "To run CI/CD pipelines with JetBrains TeamCity, input the GitLab project details in the TeamCity project Version Control Settings."
+msgstr ""
+
+msgid "To see all the user's personal access tokens you must impersonate them first."
+msgstr ""
+
+msgid "To see this project's operational details, %{linkStart}upgrade its group plan to Premium%{linkEnd}. You can also remove the project from the dashboard."
+msgstr ""
+
+msgid "To see this project's operational details, contact an owner of group %{groupName} to upgrade the plan. You can also remove the project from the dashboard."
+msgstr ""
+
+msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:"
+msgstr ""
+
+msgid "To set up this feature, contact your administrator."
+msgstr ""
+
+msgid "To set up this integration:"
+msgstr ""
+
+msgid "To specify the notification level per project of a group you belong to, visit the project page and change the notification level there."
+msgstr ""
+
+msgid "To start using GitLab Enterprise Edition, upload the %{codeOpen}.gitlab-license%{codeClose} file or enter the license key you have received from GitLab Inc."
+msgstr ""
+
+msgid "To submit your changes in a merge request, create a new fork."
+msgstr ""
+
+msgid "To submit your changes in a merge request, switch to one of these forks or create a new fork."
+msgstr ""
+
+msgid "To unsubscribe from this issue, please paste the following link into your browser:"
+msgstr ""
+
+msgid "To update Snippets with multiple files, you must use the `files` parameter"
+msgstr ""
+
+msgid "To use Service Desk in this project, you must %{linkStart}activate the issue tracker%{linkEnd}."
+msgstr ""
+
+msgid "To use the additional formats, you must start the required %{container_link_start}companion containers%{container_link_end}."
+msgstr ""
+
+msgid "To use the system's default, set this value to 0."
+msgstr ""
+
+msgid "To view all %{scannedResourcesCount} scanned URLs, %{linkStart}please download the CSV file%{linkEnd}"
+msgstr ""
+
+msgid "To view usage, refresh this page in a few minutes."
+msgstr ""
+
+msgid "To widen your search, change or remove filters above"
+msgstr ""
+
+msgid "To widen your search, change or remove filters above."
+msgstr ""
+
+msgid "To-Do List"
+msgstr ""
+
+msgid "To-Do list"
+msgstr ""
+
+msgid "To-do item successfully marked as done."
+msgstr ""
+
+msgid "Today"
+msgstr ""
+
+msgid "Todos count"
+msgstr ""
+
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
+msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
+msgstr ""
+
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Due %{due_date}"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
+msgid "Todos|Filter by author"
+msgstr ""
+
+msgid "Todos|Filter by group"
+msgstr ""
+
+msgid "Todos|Filter by project"
+msgstr ""
+
+msgid "Todos|Give yourself a pat on the back!"
+msgstr ""
+
+msgid "Todos|Good job! Looks like you don't have anything left on your To-Do List"
+msgstr ""
+
+msgid "Todos|Henceforth, you shall be known as \"To-Do Destroyer\""
+msgstr ""
+
+msgid "Todos|Isn't an empty To-Do List beautiful?"
+msgstr ""
+
+msgid "Todos|Issue"
+msgstr ""
+
+msgid "Todos|It's how you always know what to work on next."
+msgstr ""
+
+msgid "Todos|Mark all as done"
+msgstr ""
+
+msgid "Todos|Member access requested"
+msgstr ""
+
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
+msgid "Todos|Nothing is on your to-do list. Nice work!"
+msgstr ""
+
+msgid "Todos|Nothing left to do. High five!"
+msgstr ""
+
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed"
+msgstr ""
+
+msgid "Todos|Undo mark all as done"
+msgstr ""
+
+msgid "Todos|When an issue or merge request is assigned to you, or when you receive a %{strongStart}@mention%{strongEnd} in a comment, this automatically triggers a new item in your To-Do List."
+msgstr ""
+
+msgid "Todos|You're all done!"
+msgstr ""
+
+msgid "Todos|Your To-Do List shows what to work on next"
+msgstr ""
+
+msgid "Todos|added a to-do item"
+msgstr ""
+
+msgid "Todos|has requested access to %{what} %{which}"
+msgstr ""
+
+msgid "Todos|mentioned %{who}"
+msgstr ""
+
+msgid "Todos|requested a review"
+msgstr ""
+
+msgid "Todos|reviewed your merge request"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Toggle GitLab Next"
+msgstr ""
+
+msgid "Toggle Markdown preview"
+msgstr ""
+
+msgid "Toggle Sidebar"
+msgstr ""
+
+msgid "Toggle backtrace"
+msgstr ""
+
+msgid "Toggle comments for this file"
+msgstr ""
+
+msgid "Toggle commit description"
+msgstr ""
+
+msgid "Toggle commit list"
+msgstr ""
+
+msgid "Toggle details"
+msgstr ""
+
+msgid "Toggle emoji award"
+msgstr ""
+
+msgid "Toggle file browser"
+msgstr ""
+
+msgid "Toggle focus mode"
+msgstr ""
+
+msgid "Toggle keyboard shortcuts help dialog"
+msgstr ""
+
+msgid "Toggle navigation"
+msgstr ""
+
+msgid "Toggle project select"
+msgstr ""
+
+msgid "Toggle shortcuts"
+msgstr ""
+
+msgid "Toggle sidebar"
+msgstr ""
+
+msgid "Toggle the Performance Bar"
+msgstr ""
+
+msgid "Toggle the navigation sidebar"
+msgstr ""
+
+msgid "Toggled :%{name}: emoji award."
+msgstr ""
+
+msgid "Toggles :%{name}: emoji award."
+msgstr ""
+
+msgid "Token"
+msgstr ""
+
+msgid "Token Access"
+msgstr ""
+
+msgid "Token name"
+msgstr ""
+
+msgid "Token valid until revoked"
+msgstr ""
+
+msgid "TokenRevocation|This Personal Access Token has been automatically revoked on detection. Consider investigating and rotating before marking this vulnerability as resolved."
+msgstr ""
+
+msgid "Tomorrow"
+msgstr ""
+
+msgid "Too long"
+msgstr ""
+
+msgid "Too many namespaces enabled. Manage them through the console or the API."
+msgstr ""
+
+msgid "Too many projects enabled. Manage them through the console or the API."
+msgstr ""
+
+msgid "Too many references. Quick actions are limited to at most %{max_count} user references"
+msgstr ""
+
+msgid "Too many results to display. Edit your search or add a filter."
+msgstr ""
+
+msgid "Too many users found. Quick actions are limited to at most %{max_count} users"
+msgstr ""
+
+msgid "TopNav|Explore"
+msgstr ""
+
+msgid "TopNav|Go back"
+msgstr ""
+
+msgid "TopNav|Switch to"
+msgstr ""
+
+msgid "TopNav|Your dashboards"
+msgstr ""
+
+msgid "Topic %{source_topic} was successfully merged into topic %{target_topic}."
+msgstr ""
+
+msgid "Topic %{topic_name} was successfully created."
+msgstr ""
+
+msgid "Topic %{topic_name} was successfully removed."
+msgstr ""
+
+msgid "Topic avatar"
+msgstr ""
+
+msgid "Topic avatar for %{name} will be removed. This cannot be undone."
+msgstr ""
+
+msgid "Topic slug (name)"
+msgstr ""
+
+msgid "Topic title"
+msgstr ""
+
+msgid "Topic was successfully updated."
+msgstr ""
+
+msgid "TopicSelect|%d topic found"
+msgid_plural "TopicSelect|%d topics found"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "TopicSelect|No matching results"
+msgstr ""
+
+msgid "TopicSelect|Search topics"
+msgstr ""
+
+msgid "TopicSelect|Select a topic"
+msgstr ""
+
+msgid "Topics"
+msgstr ""
+
+msgid "Topics could not be merged!"
+msgstr ""
+
+msgid "Topics|Subscribe to the new projects feed"
+msgstr ""
+
+msgid "Total"
+msgstr ""
+
+msgid "Total Score"
+msgstr ""
+
+msgid "Total Spans"
+msgstr ""
+
+msgid "Total cores (CPUs)"
+msgstr ""
+
+msgid "Total issue weight"
+msgstr ""
+
+msgid "Total memory (GB)"
+msgstr ""
+
+msgid "Total test time for all commits/merges"
+msgstr ""
+
+msgid "Total users"
+msgstr ""
+
+msgid "Total weight"
+msgstr ""
+
+msgid "Total: %{total}"
+msgstr ""
+
+msgid "TotalMilestonesIndicator|1000+"
+msgstr ""
+
+msgid "TotalRefCountIndicator|1000+"
+msgstr ""
+
+msgid "Trace Details"
+msgstr ""
+
+msgid "Trace Start"
+msgstr ""
+
+msgid "Tracing"
+msgstr ""
+
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
+msgid "Tracing|Check again"
+msgstr ""
+
+msgid "Tracing|Date"
+msgstr ""
+
+msgid "Tracing|Duration"
+msgstr ""
+
+msgid "Tracing|Duration (ms)"
+msgstr ""
+
+msgid "Tracing|Enable"
+msgstr ""
+
+msgid "Tracing|Failed to enable tracing."
+msgstr ""
+
+msgid "Tracing|Failed to load page."
+msgstr ""
+
+msgid "Tracing|Failed to load trace details."
+msgstr ""
+
+msgid "Tracing|Failed to load traces."
+msgstr ""
+
+msgid "Tracing|Filter Traces"
+msgstr ""
+
+msgid "Tracing|Get started with Tracing"
+msgstr ""
+
+msgid "Tracing|Last 1 hour"
+msgstr ""
+
+msgid "Tracing|Last 1 minute"
+msgstr ""
+
+msgid "Tracing|Last 14 days"
+msgstr ""
+
+msgid "Tracing|Last 15 minutes"
+msgstr ""
+
+msgid "Tracing|Last 24 hours"
+msgstr ""
+
+msgid "Tracing|Last 30 days"
+msgstr ""
+
+msgid "Tracing|Last 30 minutes"
+msgstr ""
+
+msgid "Tracing|Last 7 days"
+msgstr ""
+
+msgid "Tracing|Monitor your applications with GitLab Distributed Tracing."
+msgstr ""
+
+msgid "Tracing|No traces to display."
+msgstr ""
+
+msgid "Tracing|Operation"
+msgstr ""
+
+msgid "Tracing|Period"
+msgstr ""
+
+msgid "Tracing|Service"
+msgstr ""
+
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
+msgid "Tracing|Trace ID"
+msgstr ""
+
+msgid "Tracing|Traces"
+msgstr ""
+
+msgid "Tracing|longer than"
+msgstr ""
+
+msgid "Tracing|shorter than"
+msgstr ""
+
+msgid "Track groups of issues that share a theme, across projects and milestones"
+msgstr ""
+
+msgid "Track important events in your GitLab instance."
+msgstr ""
+
+msgid "Track important events in your group."
+msgstr ""
+
+msgid "Track important events in your project."
+msgstr ""
+
+msgid "Track time with quick actions"
+msgstr ""
+
+msgid "Tracking"
+msgstr ""
+
+msgid "Training mode"
+msgstr ""
+
+msgid "Transfer"
+msgstr ""
+
+msgid "Transfer group to another parent group."
+msgstr ""
+
+msgid "Transfer ownership"
+msgstr ""
+
+msgid "Transfer project"
+msgstr ""
+
+msgid "Transfer your project into another namespace. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "TransferGroup|Cannot transfer group to one of its subgroup."
+msgstr ""
+
+msgid "TransferGroup|Cannot update the path because there are projects under this group that contain Docker images in their Container Registry. Please remove the images from your projects first and try again."
+msgstr ""
+
+msgid "TransferGroup|Database is not supported."
+msgstr ""
+
+msgid "TransferGroup|Group contains contacts/organizations and you don't have enough permissions to move them to the new root group."
+msgstr ""
+
+msgid "TransferGroup|Group contains projects with NPM packages scoped to the current root level group."
+msgstr ""
+
+msgid "TransferGroup|Group is already a root group."
+msgstr ""
+
+msgid "TransferGroup|Group is already associated to the parent group."
+msgstr ""
+
+msgid "TransferGroup|SAML Provider or SCIM Token is configured for this group."
+msgstr ""
+
+msgid "TransferGroup|The parent group already has a subgroup or a project with the same path."
+msgstr ""
+
+msgid "TransferGroup|Transfer failed: %{error_message}"
+msgstr ""
+
+msgid "TransferGroup|You don't have enough permissions."
+msgstr ""
+
+msgid "TransferProject|Cannot move project"
+msgstr ""
+
+msgid "TransferProject|Please select a new namespace for your project."
+msgstr ""
+
+msgid "TransferProject|Project cannot be transferred, because tags are present in its container registry"
+msgstr ""
+
+msgid "TransferProject|Project is already in this namespace."
+msgstr ""
+
+msgid "TransferProject|Project with same name or path in target namespace already exists"
+msgstr ""
+
+msgid "TransferProject|Root namespace can't be updated if the project has NPM packages scoped to the current root level namespace."
+msgstr ""
+
+msgid "TransferProject|You don't have permission to transfer projects into that namespace."
+msgstr ""
+
+msgid "TransferProject|You don't have permission to transfer this project."
+msgstr ""
+
+msgid "Tree view"
+msgstr ""
+
+msgid "Trending"
+msgstr ""
+
+msgid "Trials|%{planName} Trial"
+msgstr ""
+
+msgid "Trials|Compare all plans"
+msgstr ""
+
+msgid "Trials|Create a new group to start your GitLab Ultimate trial."
+msgstr ""
+
+msgid "Trials|Day %{daysUsed}/%{duration}"
+msgstr ""
+
+msgid "Trials|Looking to do more with GitLab?"
+msgstr ""
+
+msgid "Trials|Upgrade your plan for more security features"
+msgstr ""
+
+msgid "Trials|With GitLab Ultimate you can detect and address vulnerabilities in your application."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You've got %{daysRemaining} day remaining on GitLab %{planName}!"
+msgid_plural "Trials|You've got %{daysRemaining} days remaining on GitLab %{planName}!"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Trials|Your 30-day trial has ended"
+msgstr ""
+
+msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
+msgstr ""
+
+msgid "Trial|Allowed characters: +, 0-9, -, and spaces."
+msgstr ""
+
+msgid "Trial|Continue"
+msgstr ""
+
+msgid "Trial|Your GitLab Ultimate trial lasts for 30 days, but you can keep your free GitLab account forever. We just need some additional information to activate your trial."
+msgstr ""
+
+msgid "Trigger"
+msgstr ""
+
+msgid "Trigger a pipeline for a branch or tag by generating a trigger token and using it with an API call. The token impersonates a user's project access and permissions."
+msgstr ""
+
+msgid "Trigger cluster reindexing"
+msgstr ""
+
+msgid "Trigger cluster reindexing. Only use this with an index that was created in GitLab 13.0 or later."
+msgstr ""
+
+msgid "Trigger job"
+msgstr ""
+
+msgid "Trigger pipelines for mirror updates"
+msgstr ""
+
+msgid "Trigger pipelines when branches or tags are updated in the upstream repository. Depending on the activity of the upstream repository, this may greatly increase the load on your CI runners. Only enable this if you know they can handle the load. %{strong_start}CI will run using the credentials assigned above.%{strong_end} %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Trigger removed."
+msgstr ""
+
+msgid "Trigger repository check"
+msgstr ""
+
+msgid "Trigger token:"
+msgstr ""
+
+msgid "Trigger variables:"
+msgstr ""
+
+msgid "Trigger was created successfully."
+msgstr ""
+
+msgid "Trigger was successfully updated."
+msgstr ""
+
+msgid "Triggerer"
+msgstr ""
+
+msgid "Trigger|Description"
+msgstr ""
+
+msgid "Trigger|Trigger description"
+msgstr ""
+
+msgid "Trusted"
+msgstr ""
+
+msgid "Trusted applications are automatically authorized on GitLab OAuth flow. It's highly recommended for the security of users that trusted applications have the confidential setting set to true."
+msgstr ""
+
+msgid "Try adjusting the filters, or creating an issue or merge request to collect more data"
+msgstr ""
+
+msgid "Try again"
+msgstr ""
+
+msgid "Try again?"
+msgstr ""
+
+msgid "Try all GitLab features for free for 30 days. No credit card required."
+msgstr ""
+
+msgid "Try all GitLab has to offer for 30 days."
+msgstr ""
+
+msgid "Try changing or removing filters."
+msgstr ""
+
+msgid "Try grouping with different labels"
+msgstr ""
+
+msgid "Try out **styling** _your_ content right here or read the [direction](%{directionUrl})."
+msgstr ""
+
+msgid "Try out GitLab Pipelines"
+msgstr ""
+
+msgid "Try the rich text editor now"
+msgstr ""
+
+msgid "Try the troubleshooting steps here."
+msgstr ""
+
+msgid "Try to fork again"
+msgstr ""
+
+msgid "Try to keep the first line under 52 characters and the others under 72."
+msgstr ""
+
+msgid "Try using a different search term to find the file you are looking for."
+msgstr ""
+
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
+msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
+msgstr ""
+
+msgid "Tue"
+msgstr ""
+
+msgid "Tuesday"
+msgstr ""
+
+msgid "Turn off"
+msgstr ""
+
+msgid "Turn on"
+msgstr ""
+
+msgid "Twitter"
+msgstr ""
+
+msgid "Twitter:"
+msgstr ""
+
+msgid "Two-Factor Authentication"
+msgstr ""
+
+msgid "Two-factor Authentication"
+msgstr ""
+
+msgid "Two-factor Authentication Recovery codes"
+msgstr ""
+
+msgid "Two-factor Authentication:"
+msgstr ""
+
+msgid "Two-factor authentication"
+msgstr ""
+
+msgid "Two-factor authentication disabled"
+msgstr ""
+
+msgid "Two-factor authentication for admin mode"
+msgstr ""
+
+msgid "Two-factor authentication grace period"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled for this user"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled for your GitLab account."
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully!"
+msgstr ""
+
+msgid "Two-factor authentication is not enabled for this user"
+msgstr ""
+
+msgid "Two-factor grace period"
+msgstr ""
+
+msgid "Type"
+msgstr ""
+
+msgid "Type changed successfully."
+msgstr ""
+
+msgid "Type to search"
+msgstr ""
+
+msgid "URL"
+msgstr ""
+
+msgid "URL is required"
+msgstr ""
+
+msgid "URL is triggered for each branch updated to the repository"
+msgstr ""
+
+msgid "URL is triggered when a merge request is created, updated, or merged"
+msgstr ""
+
+msgid "URL is triggered when a new tag is pushed to the repository"
+msgstr ""
+
+msgid "URL is triggered when repository is updated"
+msgstr ""
+
+msgid "URL must be percent-encoded if necessary."
+msgstr ""
+
+msgid "URL must start with %{codeStart}http://%{codeEnd}, %{codeStart}https://%{codeEnd}, or %{codeStart}ftp://%{codeEnd}"
+msgstr ""
+
+msgid "URL of the Grafana instance to link to from the Metrics Dashboard menu item."
+msgstr ""
+
+msgid "URL of the external Spam Check endpoint"
+msgstr ""
+
+msgid "URL of the external storage to serve the repository static objects."
+msgstr ""
+
+msgid "URL or request ID"
+msgstr ""
+
+msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
+msgid "UTC"
+msgstr ""
+
+msgid "Unable to apply suggestions to a deleted line."
+msgstr ""
+
+msgid "Unable to build Slack link."
+msgstr ""
+
+msgid "Unable to collect CPU info"
+msgstr ""
+
+msgid "Unable to collect memory info"
+msgstr ""
+
+msgid "Unable to connect to server: %{error}"
+msgstr ""
+
+msgid "Unable to connect to the Jira instance. Please check your Jira integration configuration."
+msgstr ""
+
+msgid "Unable to create link to vulnerability"
+msgstr ""
+
+msgid "Unable to create pipeline"
+msgstr ""
+
+msgid "Unable to fetch branch list for this project."
+msgstr ""
+
+msgid "Unable to fetch branches list, please close the form and try again"
+msgstr ""
+
+msgid "Unable to fetch group. Reload the page to try again."
+msgstr ""
+
+msgid "Unable to fetch groups. Reload the page to try again."
+msgstr ""
+
+msgid "Unable to fetch project. Reload the page to try again."
+msgstr ""
+
+msgid "Unable to fetch projects. Reload the page to try again."
+msgstr ""
+
+msgid "Unable to fetch upstream and downstream pipelines."
+msgstr ""
+
+msgid "Unable to find Jira project to import data from."
+msgstr ""
+
+msgid "Unable to find comment template"
+msgstr ""
+
+msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
+msgstr ""
+
+msgid "Unable to generate new instance ID"
+msgstr ""
+
+msgid "Unable to generate tests for specified file."
+msgstr ""
+
+msgid "Unable to load commits. Try again later."
+msgstr ""
+
+msgid "Unable to load file contents. Try again later."
+msgstr ""
+
+msgid "Unable to load refs"
+msgstr ""
+
+msgid "Unable to load the diff"
+msgstr ""
+
+msgid "Unable to load the diff. %{button_try_again}"
+msgstr ""
+
+msgid "Unable to load the merge request widget. Try reloading the page."
+msgstr ""
+
+msgid "Unable to load the page"
+msgstr ""
+
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
+msgid "Unable to parse JSON"
+msgstr ""
+
+msgid "Unable to parse the vulnerability report's options."
+msgstr ""
+
+msgid "Unable to save iteration. Please try again"
+msgstr ""
+
+msgid "Unable to save your changes. Please try again."
+msgstr ""
+
+msgid "Unable to save your preference"
+msgstr ""
+
+msgid "Unable to schedule a pipeline to run immediately"
+msgstr ""
+
+msgid "Unable to sign you in to the group with SAML due to \"%{reason}\""
+msgstr ""
+
+msgid "Unable to suggest a path. Please refresh and try again."
+msgstr ""
+
+msgid "Unable to update label prioritization at this time"
+msgstr ""
+
+msgid "Unable to update this epic at this time."
+msgstr ""
+
+msgid "Unable to update this issue at this time."
+msgstr ""
+
+msgid "Unapprove a merge request"
+msgstr ""
+
+msgid "Unapprove the current merge request."
+msgstr ""
+
+msgid "Unapproved the current merge request."
+msgstr ""
+
+msgid "Unarchive project"
+msgstr ""
+
+msgid "Unarchiving the project restores its members' ability to make commits, and create issues, comments, and other entities. %{strong_start}After you unarchive the project, it displays in the search and on the dashboard.%{strong_end} %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Unassign from commenting user"
+msgstr ""
+
+msgid "Unassigned"
+msgstr ""
+
+msgid "Unauthenticated API rate limit period in seconds"
+msgstr ""
+
+msgid "Unauthenticated requests"
+msgstr ""
+
+msgid "Unauthenticated web rate limit period in seconds"
+msgstr ""
+
+msgid "Unauthorized to access the cluster agent in this project"
+msgstr ""
+
+msgid "Unauthorized to create an environment"
+msgstr ""
+
+msgid "Unauthorized to update the environment"
+msgstr ""
+
+msgid "Unavailable"
+msgstr ""
+
+msgid "Unban"
+msgstr ""
+
+msgid "Uncategorized"
+msgstr ""
+
+msgid "Uncommitted changes will be lost if you change branches. Do you want to continue?"
+msgstr ""
+
+msgid "Undo"
+msgstr ""
+
+msgid "Undo Ignore"
+msgstr ""
+
+msgid "Undo ignore"
+msgstr ""
+
+msgid "Unexpected error"
+msgstr ""
+
+msgid "Unexpected error: Cannot serialize resource"
+msgstr ""
+
+msgid "Unexpected scope"
+msgstr ""
+
+msgid "Unfollow"
+msgstr ""
+
+msgid "Unfortunately, your email message to GitLab could not be processed."
+msgstr ""
+
+msgid "Unhappy?"
+msgstr ""
+
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
+msgid "Units|d"
+msgstr ""
+
+msgid "Units|ms"
+msgstr ""
+
+msgid "Units|s"
+msgstr ""
+
+msgid "Units|sec"
+msgstr ""
+
+msgid "Unknown"
+msgstr ""
+
+msgid "Unknown Error"
+msgstr ""
+
+msgid "Unknown encryption strategy: %{encrypted_strategy}!"
+msgstr ""
+
+msgid "Unknown format"
+msgstr ""
+
+msgid "Unknown response text"
+msgstr ""
+
+msgid "Unknown user"
+msgstr ""
+
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
+msgid "Unlimited"
+msgstr ""
+
+msgid "UnlimitedMembersDuringTrialAlert|During your trial, invite as many members as you like to %{group_or_project} to collaborate with you."
+msgstr ""
+
+msgid "UnlimitedMembersDuringTrialAlert|Explore paid plans"
+msgstr ""
+
+msgid "UnlimitedMembersDuringTrialAlert|Get the most out of your trial with space for more members"
+msgstr ""
+
+msgid "UnlimitedMembersDuringTrialAlert|Invite more members"
+msgstr ""
+
+msgid "Unlink"
+msgstr ""
+
+msgid "Unlock"
+msgstr ""
+
+msgid "Unlock %{issuableDisplayName}"
+msgstr ""
+
+msgid "Unlock account"
+msgstr ""
+
+msgid "Unlock more features with GitLab Ultimate"
+msgstr ""
+
+msgid "Unlock the discussion"
+msgstr ""
+
+msgid "Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment."
+msgstr ""
+
+msgid "Unlocked"
+msgstr ""
+
+msgid "Unlocked the discussion."
+msgstr ""
+
+msgid "Unlocking %{issuableDisplayName}"
+msgstr ""
+
+msgid "Unlocks the discussion."
+msgstr ""
+
+msgid "Unreachable"
+msgstr ""
+
+msgid "Unrecognized approval status."
+msgstr ""
+
+msgid "Unresolve"
+msgstr ""
+
+msgid "Unresolve thread"
+msgstr ""
+
+msgid "Unresolved"
+msgstr ""
+
+msgid "Unschedule job"
+msgstr ""
+
+msgid "Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
+msgid "Unselect all"
+msgstr ""
+
+msgid "Unselected"
+msgstr ""
+
+msgid "Unstar"
+msgstr ""
+
+msgid "Unstarted"
+msgstr ""
+
+msgid "Unsubscribe"
+msgstr ""
+
+msgid "Unsubscribe at group level"
+msgstr ""
+
+msgid "Unsubscribe at project level"
+msgstr ""
+
+msgid "Unsubscribe from %{type}"
+msgstr ""
+
+msgid "Unsubscribed from this %{quick_action_target}."
+msgstr ""
+
+msgid "Unsubscribes from this %{quick_action_target}."
+msgstr ""
+
+msgid "Unsupported forecast type."
+msgstr ""
+
+msgid "Unsupported sort value."
+msgstr ""
+
+msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
+msgstr ""
+
+msgid "Untitled"
+msgstr ""
+
+msgid "Unused"
+msgstr ""
+
+msgid "Unused, previous indices: %{index_names} will be deleted after %{time} automatically."
+msgstr ""
+
+msgid "Unverified"
+msgstr ""
+
+msgid "Unverified signature"
+msgstr ""
+
+msgid "Up to date"
+msgstr ""
+
+msgid "Upcoming"
+msgstr ""
+
+msgid "Upcoming Release"
+msgstr ""
+
+msgid "Update"
+msgstr ""
+
+msgid "Update %{sourcePath} file"
+msgstr ""
+
+msgid "Update Now"
+msgstr ""
+
+msgid "Update Scheduled…"
+msgstr ""
+
+msgid "Update all"
+msgstr ""
+
+msgid "Update appearance settings"
+msgstr ""
+
+msgid "Update approval rule"
+msgstr ""
+
+msgid "Update approvers"
+msgstr ""
+
+msgid "Update failed"
+msgstr ""
+
+msgid "Update it"
+msgstr ""
+
+msgid "Update now"
+msgstr ""
+
+msgid "Update username"
+msgstr ""
+
+msgid "Update variable"
+msgstr ""
+
+msgid "Update your bookmarked URLs as filtered/sorted branches URL has been changed."
+msgstr ""
+
+msgid "Update your group name, description, avatar, and visibility."
+msgstr ""
+
+msgid "Update your project name and description."
+msgstr ""
+
+msgid "Update your project name, topics, description, and avatar."
+msgstr ""
+
+msgid "UpdateProject|Are you sure you want to prune unreachable objects?"
+msgstr ""
+
+msgid "UpdateProject|Are you sure you want to prune?"
+msgstr ""
+
+msgid "UpdateProject|Cancel"
+msgstr ""
+
+msgid "UpdateProject|Cannot rename project because it contains container registry tags!"
+msgstr ""
+
+msgid "UpdateProject|Could not set the default branch"
+msgstr ""
+
+msgid "UpdateProject|Could not set the default branch. Do you have a branch named 'HEAD' in your repository? (%{linkStart}How do I fix this?%{linkEnd})"
+msgstr ""
+
+msgid "UpdateProject|Learn more."
+msgstr ""
+
+msgid "UpdateProject|New visibility level not allowed!"
+msgstr ""
+
+msgid "UpdateProject|Project could not be updated!"
+msgstr ""
+
+msgid "UpdateProject|Prune"
+msgstr ""
+
+msgid "UpdateProject|Prune unreachable objects"
+msgstr ""
+
+msgid "UpdateProject|Pruning unreachable objects can lead to repository corruption."
+msgstr ""
+
+msgid "UpdateRepositoryStorage|Failed to verify %{type} repository checksum from %{old} to %{new}"
+msgstr ""
+
+msgid "UpdateRepositoryStorage|Timeout waiting for %{type} repository pushes"
+msgstr ""
+
+msgid "Updated"
+msgstr ""
+
+msgid "Updated %{timeAgo}"
+msgstr ""
+
+msgid "Updated %{updated_at} by %{updated_by}"
+msgstr ""
+
+msgid "Updated date"
+msgstr ""
+
+msgid "Updating"
+msgstr ""
+
+msgid "Updating…"
+msgstr ""
+
+msgid "Upgrade offers available!"
+msgstr ""
+
+msgid "Upload"
+msgstr ""
+
+msgid "Upload %{file_name} file"
+msgstr ""
+
+msgid "Upload CSV file"
+msgstr ""
+
+msgid "Upload File"
+msgstr ""
+
+msgid "Upload New File"
+msgstr ""
+
+msgid "Upload a certificate for your domain with all intermediates"
+msgstr ""
+
+msgid "Upload a private key for your certificate"
+msgstr ""
+
+msgid "Upload could not be deleted."
+msgstr ""
+
+msgid "Upload file"
+msgstr ""
+
+msgid "Upload new file"
+msgstr ""
+
+msgid "Upload object map"
+msgstr ""
+
+msgid "Uploaded date"
+msgstr ""
+
+msgid "Uploading changes to terminal"
+msgstr ""
+
+msgid "Uploading..."
+msgstr ""
+
+msgid "Uploading: %{progress}"
+msgstr ""
+
+msgid "Upstream"
+msgstr ""
+
+msgid "Upstream Gitaly has been exhausted. Try again later"
+msgstr ""
+
+msgid "Upvotes"
+msgstr ""
+
+msgid "Usage"
+msgstr ""
+
+msgid "Usage Trends"
+msgstr ""
+
+msgid "Usage statistics"
+msgstr ""
+
+msgid "UsageQuotas|(of %{totalStorageSize})"
+msgstr ""
+
+msgid "UsageQuotas|An error occurred loading the transfer data. Please refresh the page to try again."
+msgstr ""
+
+msgid "UsageQuotas|Container Registry storage statistics are not used to calculate the total project storage. Total project storage is calculated after namespace container deduplication, where the total of all unique containers is added to the namespace storage total."
+msgstr ""
+
+msgid "UsageQuotas|Namespace transfer data used"
+msgstr ""
+
+msgid "UsageQuota|%{linkStart}Shared runners%{linkEnd} are disabled, so there are no limits set on pipeline usage"
+msgstr ""
+
+msgid "UsageQuota|%{linkTitle} help link"
+msgstr ""
+
+msgid "UsageQuota|%{percentageRemaining}%% namespace storage remaining."
+msgstr ""
+
+msgid "UsageQuota|%{storage_limit_link_start}A namespace storage limit%{link_end} will soon be enforced for the %{strong_start}%{namespace_name}%{strong_end} namespace. %{extra_message}"
+msgstr ""
+
+msgid "UsageQuota|Audio samples, videos, datasets, and graphics."
+msgstr ""
+
+msgid "UsageQuota|Buy additional compute minutes"
+msgstr ""
+
+msgid "UsageQuota|Buy storage"
+msgstr ""
+
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
+msgid "UsageQuota|Code packages and container images."
+msgstr ""
+
+msgid "UsageQuota|Compute usage"
+msgstr ""
+
+msgid "UsageQuota|Compute usage by month"
+msgstr ""
+
+msgid "UsageQuota|Compute usage by project"
+msgstr ""
+
+msgid "UsageQuota|Compute usage since %{usageSince}"
+msgstr ""
+
+msgid "UsageQuota|Container Registry"
+msgstr ""
+
+msgid "UsageQuota|Dependency proxy"
+msgstr ""
+
+msgid "UsageQuota|Filter charts by year"
+msgstr ""
+
+msgid "UsageQuota|Filter projects data by month"
+msgstr ""
+
+msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
+msgstr ""
+
+msgid "UsageQuota|Git repository."
+msgstr ""
+
+msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker Images."
+msgstr ""
+
+msgid "UsageQuota|Group settings %{gt} Usage quotas"
+msgstr ""
+
+msgid "UsageQuota|Included in %{planName} subscription"
+msgstr ""
+
+msgid "UsageQuota|Includes artifacts, repositories, wiki, and other items."
+msgstr ""
+
+msgid "UsageQuota|Includes project artifacts, repositories, packages, and container registries."
+msgstr ""
+
+msgid "UsageQuota|Job artifacts created by CI/CD."
+msgstr ""
+
+msgid "UsageQuota|Learn more about usage quotas"
+msgstr ""
+
+msgid "UsageQuota|Learn more about usage quotas."
+msgstr ""
+
+msgid "UsageQuota|Local proxy used for frequently-accessed upstream Docker images. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
+msgid "UsageQuota|Month"
+msgstr ""
+
+msgid "UsageQuota|Namespace entities"
+msgstr ""
+
+msgid "UsageQuota|Namespace overview"
+msgstr ""
+
+msgid "UsageQuota|Namespace storage used"
+msgstr ""
+
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
+msgid "UsageQuota|No compute usage data available."
+msgstr ""
+
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
+msgid "UsageQuota|Pending Members"
+msgstr ""
+
+msgid "UsageQuota|Pipeline artifacts and job artifacts, created with CI/CD."
+msgstr ""
+
+msgid "UsageQuota|Pipelines"
+msgstr ""
+
+msgid "UsageQuota|Precise calculation of Container Registry storage size is delayed because it is too large for synchronous estimation. Precise evaluation will be scheduled within 24 hours."
+msgstr ""
+
+msgid "UsageQuota|Projects under this namespace have %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
+msgstr ""
+
+msgid "UsageQuota|Recalculate repository usage"
+msgstr ""
+
+msgid "UsageQuota|Registry"
+msgstr ""
+
+msgid "UsageQuota|Seats"
+msgstr ""
+
+msgid "UsageQuota|Shared bits of code and text."
+msgstr ""
+
+msgid "UsageQuota|Shared runner duration"
+msgstr ""
+
+msgid "UsageQuota|Something went wrong while fetching pipeline statistics"
+msgstr ""
+
+msgid "UsageQuota|Something went wrong while fetching project storage statistics"
+msgstr ""
+
+msgid "UsageQuota|Something went wrong while loading usage details"
+msgstr ""
+
+msgid "UsageQuota|Storage"
+msgstr ""
+
+msgid "UsageQuota|Storage per project included in %{planName} subscription"
+msgstr ""
+
+msgid "UsageQuota|Storage type"
+msgstr ""
+
+msgid "UsageQuota|Storage usage breakdown"
+msgstr ""
+
+msgid "UsageQuota|Storage used"
+msgstr ""
+
+msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} group will be affected by this. "
+msgstr ""
+
+msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
+msgstr ""
+
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr ""
+
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgstr ""
+
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgstr ""
+
+msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
+msgstr ""
+
+msgid "UsageQuota|This namespace has no projects which used shared runners in the current period"
+msgstr ""
+
+msgid "UsageQuota|This table omits projects that used 0 compute minutes or 0 shared runners duration"
+msgstr ""
+
+msgid "UsageQuota|Total purchased storage"
+msgstr ""
+
+msgid "UsageQuota|Total storage"
+msgstr ""
+
+msgid "UsageQuota|Transfer"
+msgstr ""
+
+msgid "UsageQuota|Transfer data used"
+msgstr ""
+
+msgid "UsageQuota|Transfer data used by month"
+msgstr ""
+
+msgid "UsageQuota|Transfer type"
+msgstr ""
+
+msgid "UsageQuota|Transfer usage breakout"
+msgstr ""
+
+msgid "UsageQuota|Usage"
+msgstr ""
+
+msgid "UsageQuota|Usage Quotas"
+msgstr ""
+
+msgid "UsageQuota|Usage breakdown"
+msgstr ""
+
+msgid "UsageQuota|Usage by month"
+msgstr ""
+
+msgid "UsageQuota|Usage by project"
+msgstr ""
+
+msgid "UsageQuota|Usage of group resources across the projects in the %{namespaceName} group"
+msgstr ""
+
+msgid "UsageQuota|Usage of group resources across the projects in the %{strong_start}%{group_name}%{strong_end} group"
+msgstr ""
+
+msgid "UsageQuota|Usage of project resources across the %{strong_start}%{project_name}%{strong_end} project"
+msgstr ""
+
+msgid "UsageQuota|Usage of resources across your projects"
+msgstr ""
+
+msgid "UsageQuota|User settings %{gt} Usage quotas"
+msgstr ""
+
+msgid "UsageQuota|Wiki content."
+msgstr ""
+
+msgid "UsageTrends|Could not load the issues and merge requests chart. Please refresh the page to try again."
+msgstr ""
+
+msgid "UsageTrends|Could not load the pipelines chart. Please refresh the page to try again."
+msgstr ""
+
+msgid "UsageTrends|Could not load the projects and groups chart. Please refresh the page to try again."
+msgstr ""
+
+msgid "UsageTrends|Groups"
+msgstr ""
+
+msgid "UsageTrends|Issues"
+msgstr ""
+
+msgid "UsageTrends|Issues & merge requests"
+msgstr ""
+
+msgid "UsageTrends|Items"
+msgstr ""
+
+msgid "UsageTrends|Merge requests"
+msgstr ""
+
+msgid "UsageTrends|Month"
+msgstr ""
+
+msgid "UsageTrends|No data available."
+msgstr ""
+
+msgid "UsageTrends|Pipelines"
+msgstr ""
+
+msgid "UsageTrends|Pipelines canceled"
+msgstr ""
+
+msgid "UsageTrends|Pipelines failed"
+msgstr ""
+
+msgid "UsageTrends|Pipelines skipped"
+msgstr ""
+
+msgid "UsageTrends|Pipelines succeeded"
+msgstr ""
+
+msgid "UsageTrends|Pipelines total"
+msgstr ""
+
+msgid "UsageTrends|Projects"
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the cancelled pipelines. Please try again."
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the failed pipelines. Please try again."
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the groups. Please try again."
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the issues. Please try again."
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the merge requests. Please try again."
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the projects. Please try again."
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the skipped pipelines. Please try again."
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the successful pipelines. Please try again."
+msgstr ""
+
+msgid "UsageTrends|There was an error fetching the total pipelines. Please try again."
+msgstr ""
+
+msgid "UsageTrends|Total groups"
+msgstr ""
+
+msgid "UsageTrends|Total projects"
+msgstr ""
+
+msgid "UsageTrends|Total projects & groups"
+msgstr ""
+
+msgid "UsageTrends|Users"
+msgstr ""
+
+msgid "Use %{code_start}::%{code_end} to create a %{link_start}scoped label set%{link_end} (eg. %{code_start}priority::1%{code_end})"
+msgstr ""
+
+msgid "Use .gitlab-ci.yml"
+msgstr ""
+
+msgid "Use Secure Files to store files used by your pipelines such as Android keystores, or Apple provisioning profiles and signing certificates."
+msgstr ""
+
+msgid "Use a one-time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
+msgstr ""
+
+msgid "Use authorized_keys file to authenticate SSH keys"
+msgstr ""
+
+msgid "Use banners and notifications to notify your users about scheduled maintenance, recent upgrades, and more."
+msgstr ""
+
+msgid "Use cURL"
+msgstr ""
+
+msgid "Use custom color #FF0000"
+msgstr ""
+
+msgid "Use double quotes for multiple keywords, such as %{code_open}\"your search\"%{code_close}"
+msgstr ""
+
+msgid "Use hashed storage"
+msgstr ""
+
+msgid "Use hashed storage paths for newly created and renamed repositories. Always enabled since 13.0. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Use issue count"
+msgstr ""
+
+msgid "Use issue weight"
+msgstr ""
+
+msgid "Use issues to collaborate on ideas, solve problems, and plan work"
+msgstr ""
+
+msgid "Use one line per URI"
+msgstr ""
+
+msgid "Use primary email (%{email})"
+msgstr ""
+
+msgid "Use shortcuts"
+msgstr ""
+
+msgid "Use slash commands."
+msgstr ""
+
+msgid "Use template"
+msgstr ""
+
+msgid "Use the %{strongStart}Test%{strongEnd} option above to create an event."
+msgstr ""
+
+msgid "Use the Apple App Store Connect integration to easily connect to the Apple App Store with Fastlane in CI/CD pipelines."
+msgstr ""
+
+msgid "Use the Google Play integration to connect to Google Play with fastlane in CI/CD pipelines."
+msgstr ""
+
+msgid "Use the link below to confirm your email address (%{email})"
+msgstr ""
+
+msgid "Use the link below to confirm your email address."
+msgstr ""
+
+msgid "Use the new rich text editor to see your text and tables fully formatted as you type. No need to remember any formatting syntax, or switch between preview and editing modes!"
+msgstr ""
+
+msgid "Use the public cloud instance URL (%{kroki_public_url}) or %{install_link_start}install Kroki%{install_link_end} on your own infrastructure and use your own instance URL."
+msgstr ""
+
+msgid "Use the search bar on the top of this page"
+msgstr ""
+
+msgid "Use this section to disable your one-time password authenticator and WebAuthn devices. You can also generate new recovery codes."
+msgstr ""
+
+msgid "Use this token to validate received payloads."
+msgstr ""
+
+msgid "Use webhook"
+msgstr ""
+
+msgid "Use your global notification setting"
+msgstr ""
+
+msgid "Use your smart card to authenticate with the LDAP server."
+msgstr ""
+
+msgid "Used"
+msgstr ""
+
+msgid "Used by %d package"
+msgid_plural "Used by %d packages"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Used by members to sign in to your group in GitLab"
+msgstr ""
+
+msgid "Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises."
+msgstr ""
+
+msgid "Used for account notifications if a %{openingTag}group-specific email address%{closingTag} is not set."
+msgstr ""
+
+msgid "Used for avatar detection. You can change it in your %{openingTag}profile settings%{closingTag}."
+msgstr ""
+
+msgid "Used for web based operations, such as edits and merges."
+msgstr ""
+
+msgid "Used programming language"
+msgstr ""
+
+msgid "Used to help configure your identity provider"
+msgstr ""
+
+msgid "User"
+msgstr ""
+
+msgid "User %{current_user_username} has started impersonating %{username}"
+msgstr ""
+
+msgid "User %{username} was successfully removed."
+msgstr ""
+
+msgid "User %{user} SCIM identity is deactivated"
+msgstr ""
+
+msgid "User %{user} SCIM identity is reactivated"
+msgstr ""
+
+msgid "User %{user} was removed from %{group}."
+msgstr ""
+
+msgid "User ID"
+msgstr ""
+
+msgid "User OAuth applications"
+msgstr ""
+
+msgid "User Settings"
+msgstr ""
+
+msgid "User Status"
+msgstr ""
+
+msgid "User and IP rate limits"
+msgstr ""
+
+msgid "User cap"
+msgstr ""
+
+msgid "User cap cannot be enabled. The group or one of its subgroups or projects is shared externally."
+msgstr ""
+
+msgid "User created at"
+msgstr ""
+
+msgid "User deleted own account on %{timestamp}"
+msgstr ""
+
+msgid "User does not have a pending request"
+msgstr ""
+
+msgid "User does not have permission to create a Security Policy project."
+msgstr ""
+
+msgid "User doesn't exist or you don't have permission to change namespace commit emails."
+msgstr ""
+
+msgid "User has already been deactivated"
+msgstr ""
+
+msgid "User identity was successfully created."
+msgstr ""
+
+msgid "User identity was successfully removed."
+msgstr ""
+
+msgid "User identity was successfully updated."
+msgstr ""
+
+msgid "User is blocked"
+msgstr ""
+
+msgid "User is not allowed to resolve thread"
+msgstr ""
+
+msgid "User key"
+msgstr ""
+
+msgid "User key was successfully removed."
+msgstr ""
+
+msgid "User list %{name} will be removed. Are you sure?"
+msgstr ""
+
+msgid "User map"
+msgstr ""
+
+msgid "User pipeline minutes were successfully reset."
+msgstr ""
+
+msgid "User restrictions"
+msgstr ""
+
+msgid "User settings"
+msgstr ""
+
+msgid "User was successfully banned."
+msgstr ""
+
+msgid "User was successfully created."
+msgstr ""
+
+msgid "User was successfully removed from group and any subgroups and projects."
+msgstr ""
+
+msgid "User was successfully removed from group."
+msgstr ""
+
+msgid "User was successfully removed from project."
+msgstr ""
+
+msgid "User was successfully unbanned."
+msgstr ""
+
+msgid "User was successfully updated."
+msgstr ""
+
+msgid "User-based escalation rules must have a user with access to the project"
+msgstr ""
+
+msgid "UserAvailability|%{author}%{badgeStart}Busy%{badgeEnd}"
+msgstr ""
+
+msgid "UserLists|Add"
+msgstr ""
+
+msgid "UserLists|Add Users"
+msgstr ""
+
+msgid "UserLists|Add users"
+msgstr ""
+
+msgid "UserLists|Cancel"
+msgstr ""
+
+msgid "UserLists|Create"
+msgstr ""
+
+msgid "UserLists|Define a set of users to be used within feature flag strategies"
+msgstr ""
+
+msgid "UserLists|Edit"
+msgstr ""
+
+msgid "UserLists|Edit %{name}"
+msgstr ""
+
+msgid "UserLists|Enter a comma separated list of user IDs. These IDs should be the users of the system in which the feature flag is set, not GitLab IDs"
+msgstr ""
+
+msgid "UserLists|Feature flag user list"
+msgstr ""
+
+msgid "UserLists|Get started with user lists"
+msgstr ""
+
+msgid "UserLists|Lists allow you to define a set of users to be used with feature flags. %{linkStart}Read more about feature flag lists.%{linkEnd}"
+msgstr ""
+
+msgid "UserLists|Loading user lists"
+msgstr ""
+
+msgid "UserLists|Name"
+msgstr ""
+
+msgid "UserLists|New list"
+msgstr ""
+
+msgid "UserLists|New user list"
+msgstr ""
+
+msgid "UserLists|Save"
+msgstr ""
+
+msgid "UserLists|There are no users"
+msgstr ""
+
+msgid "UserLists|There was an error fetching the user lists."
+msgstr ""
+
+msgid "UserLists|User ID"
+msgstr ""
+
+msgid "UserLists|User IDs"
+msgstr ""
+
+msgid "UserLists|User Lists"
+msgstr ""
+
+msgid "UserLists|User lists allow you to define a set of users to use with Feature Flags."
+msgstr ""
+
+msgid "UserList|Delete %{name}?"
+msgstr ""
+
+msgid "UserList|created %{timeago}"
+msgstr ""
+
+msgid "UserProfile|%{count} %{file}"
+msgstr ""
+
+msgid "UserProfile|%{id} · created %{created} by %{author}"
+msgstr ""
+
+msgid "UserProfile|Activity"
+msgstr ""
+
+msgid "UserProfile|An error occurred loading the activity. Please refresh the page to try again."
+msgstr ""
+
+msgid "UserProfile|An error occurred loading the followers. Please refresh the page to try again."
+msgstr ""
+
+msgid "UserProfile|An error occurred loading the following. Please refresh the page to try again."
+msgstr ""
+
+msgid "UserProfile|An error occurred loading the personal projects. Please refresh the page to try again."
+msgstr ""
+
+msgid "UserProfile|Blocked user"
+msgstr ""
+
+msgid "UserProfile|Bot activity"
+msgstr ""
+
+msgid "UserProfile|Busy"
+msgstr ""
+
+msgid "UserProfile|Contributed projects"
+msgstr ""
+
+msgid "UserProfile|Copy user ID"
+msgstr ""
+
+msgid "UserProfile|Copy user ID: %{id}"
+msgstr ""
+
+msgid "UserProfile|Edit profile"
+msgstr ""
+
+msgid "UserProfile|Explore public groups to find projects to contribute to."
+msgstr ""
+
+msgid "UserProfile|Failed to set avatar. Please reload the page to try again."
+msgstr ""
+
+msgid "UserProfile|Followers"
+msgstr ""
+
+msgid "UserProfile|Following"
+msgstr ""
+
+msgid "UserProfile|Get started with snippets"
+msgstr ""
+
+msgid "UserProfile|Groups"
+msgstr ""
+
+msgid "UserProfile|Groups are the best way to manage projects and members."
+msgstr ""
+
+msgid "UserProfile|Join or create a group to start contributing by commenting on issues or submitting merge requests!"
+msgstr ""
+
+msgid "UserProfile|Most Recent Activity"
+msgstr ""
+
+msgid "UserProfile|No snippets found."
+msgstr ""
+
+msgid "UserProfile|Overview"
+msgstr ""
+
+msgid "UserProfile|Personal projects"
+msgstr ""
+
+msgid "UserProfile|Pronounced as: %{pronunciation}"
+msgstr ""
+
+msgid "UserProfile|Retry"
+msgstr ""
+
+msgid "UserProfile|Snippets"
+msgstr ""
+
+msgid "UserProfile|Snippets in GitLab can either be private, internal, or public."
+msgstr ""
+
+msgid "UserProfile|Star projects to track their progress and show your appreciation."
+msgstr ""
+
+msgid "UserProfile|Starred projects"
+msgstr ""
+
+msgid "UserProfile|Store, share, and embed bits of code and text."
+msgstr ""
+
+msgid "UserProfile|Subscribe"
+msgstr ""
+
+msgid "UserProfile|There are no projects available to be displayed here."
+msgstr ""
+
+msgid "UserProfile|This user doesn't have any followers"
+msgstr ""
+
+msgid "UserProfile|This user doesn't have any followers."
+msgstr ""
+
+msgid "UserProfile|This user doesn't have any snippets"
+msgstr ""
+
+msgid "UserProfile|This user has a private profile"
+msgstr ""
+
+msgid "UserProfile|This user hasn't contributed to any projects"
+msgstr ""
+
+msgid "UserProfile|This user hasn't starred any projects"
+msgstr ""
+
+msgid "UserProfile|This user is blocked"
+msgstr ""
+
+msgid "UserProfile|This user isn't following other users"
+msgstr ""
+
+msgid "UserProfile|This user isn't following other users."
+msgstr ""
+
+msgid "UserProfile|Unconfirmed user"
+msgstr ""
+
+msgid "UserProfile|User ID copied to clipboard"
+msgstr ""
+
+msgid "UserProfile|User ID: %{id}"
+msgstr ""
+
+msgid "UserProfile|User profile navigation"
+msgstr ""
+
+msgid "UserProfile|View all"
+msgstr ""
+
+msgid "UserProfile|View user in admin area"
+msgstr ""
+
+msgid "UserProfile|You are not following other users"
+msgstr ""
+
+msgid "UserProfile|You are not following other users."
+msgstr ""
+
+msgid "UserProfile|You can create a group for several dependent projects."
+msgstr ""
+
+msgid "UserProfile|You do not have any followers"
+msgstr ""
+
+msgid "UserProfile|You do not have any followers."
+msgstr ""
+
+msgid "UserProfile|You haven't created any personal projects."
+msgstr ""
+
+msgid "UserProfile|You haven't created any snippets."
+msgstr ""
+
+msgid "UserProfile|Your projects can be available publicly, internally, or privately, at your choice."
+msgstr ""
+
+msgid "UserProfile|at"
+msgstr ""
+
+msgid "UserProfile|made a private contribution"
+msgstr ""
+
+msgid "UserProfile|updated %{updated}"
+msgstr ""
+
+msgid "Username"
+msgstr ""
+
+msgid "Username (optional)"
+msgstr ""
+
+msgid "Username is already taken."
+msgstr ""
+
+msgid "Username is available."
+msgstr ""
+
+msgid "Username or email"
+msgstr ""
+
+msgid "Username or primary email"
+msgstr ""
+
+msgid "Username:"
+msgstr ""
+
+msgid "Username: %{username}"
+msgstr ""
+
+msgid "Users"
+msgstr ""
+
+msgid "Users API rate limit"
+msgstr ""
+
+msgid "Users can launch a development environment from a GitLab browser tab when the %{linkStart}Gitpod%{linkEnd} integration is enabled."
+msgstr ""
+
+msgid "Users can reactivate their account by signing in. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Users can render diagrams in AsciiDoc, Markdown, reStructuredText, and Textile documents using Kroki."
+msgstr ""
+
+msgid "Users can request access (if visibility is public or internal)"
+msgstr ""
+
+msgid "Users can select 'Remember me' on sign-in to keep their session active beyond the session duration. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "Users cannot be added to projects in this group"
+msgstr ""
+
+msgid "Users in License"
+msgstr ""
+
+msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgstr ""
+
+msgid "Users over License"
+msgstr ""
+
+msgid "Users requesting access to"
+msgstr ""
+
+msgid "Users to exclude from the rate limit"
+msgstr ""
+
+msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
+msgstr ""
+
+msgid "UsersSelect|%{name} + %{length} more"
+msgstr ""
+
+msgid "UsersSelect|Any User"
+msgstr ""
+
+msgid "UsersSelect|Assignee"
+msgstr ""
+
+msgid "UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}"
+msgstr ""
+
+msgid "UsersSelect|Unassigned"
+msgstr ""
+
+msgid "User|Data Analyst"
+msgstr ""
+
+msgid "User|Development Team Lead"
+msgstr ""
+
+msgid "User|Devops Engineer"
+msgstr ""
+
+msgid "User|Other"
+msgstr ""
+
+msgid "User|Product Designer"
+msgstr ""
+
+msgid "User|Product Manager"
+msgstr ""
+
+msgid "User|Security Analyst"
+msgstr ""
+
+msgid "User|Software Developer"
+msgstr ""
+
+msgid "User|Systems Administrator"
+msgstr ""
+
+msgid "Uses GitLab as an alternative to Sentry."
+msgstr ""
+
+msgid "Using %{code_start}::%{code_end} denotes a %{link_start}scoped label set%{link_end}"
+msgstr ""
+
+msgid "Using HTML script"
+msgstr ""
+
+msgid "Using required encryption strategy when encrypted field is missing!"
+msgstr ""
+
+msgid "Using the %{codeStart}needs%{codeEnd} keyword makes jobs run before their stage is reached. Jobs run as soon as their %{codeStart}needs%{codeEnd} relationships are met, which speeds up your pipelines."
+msgstr ""
+
+msgid "Validate"
+msgstr ""
+
+msgid "Validate your GitLab CI configuration"
+msgstr ""
+
+msgid "Validate your GitLab CI configuration file"
+msgstr ""
+
+msgid "Validated at"
+msgstr ""
+
+msgid "Validated at:"
+msgstr ""
+
+msgid "Validated:"
+msgstr ""
+
+msgid "Validations failed."
+msgstr ""
+
+msgid "Validation|can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"
+msgstr ""
+
+msgid "Validation|groupId parameter is invalid"
+msgstr ""
+
+msgid "Validation|must belong to the same project"
+msgstr ""
+
+msgid "Validation|parameters are invalid"
+msgstr ""
+
+msgid "Validation|percentage must be a string between 0 and 100 inclusive"
+msgstr ""
+
+msgid "Validation|rollout must be a string between 0 and 100 inclusive"
+msgstr ""
+
+msgid "Validation|strategy name is invalid"
+msgstr ""
+
+msgid "Value"
+msgstr ""
+
+msgid "Value Stream Analytics"
+msgstr ""
+
+msgid "Value Stream Analytics can help you determine your team’s velocity"
+msgstr ""
+
+msgid "Value Streams Dashboard | DORA"
+msgstr ""
+
+msgid "Value might contain a variable reference"
+msgstr ""
+
+msgid "Value must meet regular expression requirements to be masked."
+msgstr ""
+
+msgid "Value stream"
+msgstr ""
+
+msgid "Value stream analytics"
+msgstr ""
+
+msgid "ValueStreamAnalyticsStage|There are 0 items to show in this stage, for these filters, within this time range."
+msgstr ""
+
+msgid "ValueStreamAnalytics|%{stageCount}+ items"
+msgstr ""
+
+msgid "ValueStreamAnalytics|%{value}M"
+msgstr ""
+
+msgid "ValueStreamAnalytics|%{value}d"
+msgstr ""
+
+msgid "ValueStreamAnalytics|%{value}h"
+msgstr ""
+
+msgid "ValueStreamAnalytics|%{value}m"
+msgstr ""
+
+msgid "ValueStreamAnalytics|%{value}w"
+msgstr ""
+
+msgid "ValueStreamAnalytics|&lt;1m"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Average number of deployments to production per day."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Average number of deployments to production per day. This metric measures how often value is delivered to end users."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Critical vulnerabilities over time."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Dashboard"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Edit Value Stream: %{name}"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Go to docs"
+msgstr ""
+
+msgid "ValueStreamAnalytics|High vulnerabilities over time."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Lifecycle metrics"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Median time an incident was open on a production environment in the given time period."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Median time between merge request merge and deployment to a production environment for all MRs deployed in the given time period."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Median time from issue created to issue closed."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Median time from the earliest commit of a linked issue's merge request to when that issue is closed."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Merge request analytics"
+msgstr ""
+
+msgid "ValueStreamAnalytics|New Value Stream"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Number of commits pushed to the default branch"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Number of issues closed by month."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Number of new issues created."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Percentage of deployments that cause an incident in production."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Shows %{selectedSubjectFilterText} and %{labelsCount} for group '%{groupName}' and %{projectsCount} from %{createdAfter} to %{createdBefore}"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Shows %{selectedSubjectFilterText} and %{labelsCount} for group '%{groupName}' from %{createdAfter} to %{createdBefore}"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Shows %{selectedSubjectFilterText} for group '%{groupName}' and %{projectsCount} from %{createdAfter} to %{createdBefore}"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Shows %{selectedSubjectFilterText} for group '%{groupName}' from %{createdAfter} to %{createdBefore}"
+msgstr ""
+
+msgid "ValueStreamAnalytics|Tasks by type"
+msgstr ""
+
+msgid "ValueStreamAnalytics|The number of merge requests merged by month."
+msgstr ""
+
+msgid "ValueStreamAnalytics|The time it takes an organization to recover from a failure in production."
+msgstr ""
+
+msgid "ValueStreamAnalytics|The time to successfully deliver a commit into production. This metric reflects the efficiency of CI/CD pipelines."
+msgstr ""
+
+msgid "ValueStreamAnalytics|There was an error while fetching value stream analytics %{requestTypeName} data."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Total number of deploys to production."
+msgstr ""
+
+msgid "ValueStreamAnalytics|Value stream"
+msgstr ""
+
+msgid "ValueStreamAnalytics|View details"
+msgstr ""
+
+msgid "ValueStreamEvent|Items in stage"
+msgstr ""
+
+msgid "ValueStreamEvent|Only items that reached their stop event."
+msgstr ""
+
+msgid "ValueStreamEvent|Stage time (median)"
+msgstr ""
+
+msgid "ValueStreamEvent|Start"
+msgstr ""
+
+msgid "ValueStreamEvent|Stop"
+msgstr ""
+
+msgid "Variable"
+msgstr ""
+
+msgid "Variable (default)"
+msgstr ""
+
+msgid "Variable name '%{variable}' must not start with '%{prefix}'"
+msgstr ""
+
+msgid "Variable value will be evaluated as raw string."
+msgstr ""
+
+msgid "Variables"
+msgstr ""
+
+msgid "Variables can be:"
+msgstr ""
+
+msgid "Variables can have several attributes."
+msgstr ""
+
+msgid "Variables store information, like passwords and secret keys, that you can use in job scripts. All projects on the instance can use these variables."
+msgstr ""
+
+msgid "Various container registry settings."
+msgstr ""
+
+msgid "Various email settings."
+msgstr ""
+
+msgid "Various settings that affect GitLab performance."
+msgstr ""
+
+msgid "Verification status"
+msgstr ""
+
+msgid "VerificationReminder|Pipeline failing? To keep GitLab spam and abuse free we ask that you verify your identity."
+msgstr ""
+
+msgid "VerificationReminder|Until then, shared runners will be unavailable. %{validateLinkStart}Validate your account%{validateLinkEnd} or %{docsLinkStart}use your own runners%{docsLinkEnd}."
+msgstr ""
+
+msgid "VerificationReminder|Your account has been validated"
+msgstr ""
+
+msgid "VerificationReminder|You’ll now be able to take advantage of free compute minutes on shared runners."
+msgstr ""
+
+msgid "Verifications status"
+msgstr ""
+
+msgid "Verified"
+msgstr ""
+
+msgid "Verified commit"
+msgstr ""
+
+msgid "Verify SAML Configuration"
+msgstr ""
+
+msgid "Verify code"
+msgstr ""
+
+msgid "Version"
+msgstr ""
+
+msgid "Version %{report_version} for report type %{report_type} is unsupported, supported versions for this report type are: %{supported_schema_versions}. GitLab will attempt to validate this report against the earliest supported versions of this report type, to show all the errors but will not ingest the report"
+msgstr ""
+
+msgid "Version %{versionNumber}"
+msgstr ""
+
+msgid "Version %{versionNumber} (latest)"
+msgstr ""
+
+msgid "VersionCheck|%{details}"
+msgstr ""
+
+msgid "VersionCheck|Important notice - Critical security release"
+msgstr ""
+
+msgid "VersionCheck|Learn more about this critical security release."
+msgstr ""
+
+msgid "VersionCheck|Remind me again in 3 days"
+msgstr ""
+
+msgid "VersionCheck|Up to date"
+msgstr ""
+
+msgid "VersionCheck|Update ASAP"
+msgstr ""
+
+msgid "VersionCheck|Update available"
+msgstr ""
+
+msgid "VersionCheck|Upgrade now"
+msgstr ""
+
+msgid "VersionCheck|You are currently on version %{currentVersion}! We strongly recommend upgrading your GitLab installation immediately."
+msgstr ""
+
+msgid "VersionCheck|You are currently on version %{currentVersion}! We strongly recommend upgrading your GitLab installation to one of the following versions immediately: %{latestStableVersions}."
+msgstr ""
+
+msgid "VersionCheck|Your GitLab Version"
+msgstr ""
+
+msgid "View File Metadata"
+msgstr ""
+
+msgid "View Stage: %{title}"
+msgstr ""
+
+msgid "View alert details at"
+msgstr ""
+
+msgid "View alert details."
+msgstr ""
+
+msgid "View all environments."
+msgstr ""
+
+msgid "View all groups"
+msgstr ""
+
+msgid "View all issues"
+msgstr ""
+
+msgid "View all projects"
+msgstr ""
+
+msgid "View blame"
+msgstr ""
+
+msgid "View blame as separate pages"
+msgstr ""
+
+msgid "View blame prior to this change"
+msgstr ""
+
+msgid "View card matches"
+msgstr ""
+
+msgid "View dependency details for your project"
+msgstr ""
+
+msgid "View deployment"
+msgstr ""
+
+msgid "View details"
+msgstr ""
+
+msgid "View details: %{details_url}"
+msgstr ""
+
+msgid "View documentation"
+msgstr ""
+
+msgid "View environment details page"
+msgstr ""
+
+msgid "View exposed artifact"
+msgid_plural "View %d exposed artifacts"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "View file @ "
+msgstr ""
+
+msgid "View file @ %{commitSha}"
+msgstr ""
+
+msgid "View group in admin area"
+msgstr ""
+
+msgid "View group labels"
+msgstr ""
+
+msgid "View group pipeline usage quota"
+msgstr ""
+
+msgid "View incident details at"
+msgstr ""
+
+msgid "View incident details."
+msgstr ""
+
+msgid "View incident issues."
+msgstr ""
+
+msgid "View issue"
+msgstr ""
+
+msgid "View issues"
+msgstr ""
+
+msgid "View it on GitLab"
+msgstr ""
+
+msgid "View job"
+msgstr ""
+
+msgid "View job currently using resource"
+msgstr ""
+
+msgid "View jobs"
+msgstr ""
+
+msgid "View labels"
+msgstr ""
+
+msgid "View log"
+msgstr ""
+
+msgid "View members"
+msgstr ""
+
+msgid "View milestones"
+msgstr ""
+
+msgid "View on %{url}"
+msgstr ""
+
+msgid "View open merge request"
+msgstr ""
+
+msgid "View page @ "
+msgstr ""
+
+msgid "View project in admin area"
+msgstr ""
+
+msgid "View project labels"
+msgstr ""
+
+msgid "View public GPG key"
+msgid_plural "View public GPG keys"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "View replaced file @ "
+msgstr ""
+
+msgid "View seat usage"
+msgstr ""
+
+msgid "View summary notes"
+msgstr ""
+
+msgid "View supported languages and frameworks"
+msgstr ""
+
+msgid "View the %{code_open}last_activity_at%{code_close} attribute for %{project_link} using the %{projects_api_link}."
+msgstr ""
+
+msgid "View the documentation"
+msgstr ""
+
+msgid "View the latest successful deployment to this environment"
+msgstr ""
+
+msgid "View trigger token usage examples"
+msgstr ""
+
+msgid "View usage details"
+msgstr ""
+
+msgid "View users statistics"
+msgstr ""
+
+msgid "Viewed"
+msgstr ""
+
+msgid "Viewing commit"
+msgstr ""
+
+msgid "Violation"
+msgstr ""
+
+msgid "Visibility and access controls"
+msgstr ""
+
+msgid "Visibility level"
+msgstr ""
+
+msgid "Visibility level:"
+msgstr ""
+
+msgid "Visibility settings have been disabled by the administrator."
+msgstr ""
+
+msgid "Visibility, project features, permissions"
+msgstr ""
+
+msgid "Visibility:"
+msgstr ""
+
+msgid "VisibilityLevel|Internal"
+msgstr ""
+
+msgid "VisibilityLevel|Private"
+msgstr ""
+
+msgid "VisibilityLevel|Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group."
+msgstr ""
+
+msgid "VisibilityLevel|Public"
+msgstr ""
+
+msgid "VisibilityLevel|The group and any internal projects can be viewed by any logged in user except external users."
+msgstr ""
+
+msgid "VisibilityLevel|The group and any public projects can be viewed without any authentication."
+msgstr ""
+
+msgid "VisibilityLevel|The group and its projects can only be viewed by members."
+msgstr ""
+
+msgid "VisibilityLevel|The group, any public projects, and any of their members, issues, and merge requests can be viewed without authentication. Public groups and projects will be indexed by search engines. Read more about %{free_user_limit_doc_link_start}free user limits%{link_end}, or %{group_billings_link_start}upgrade to a paid tier%{link_end}."
+msgstr ""
+
+msgid "VisibilityLevel|The project can be accessed by any logged in user except external users."
+msgstr ""
+
+msgid "VisibilityLevel|The project can be accessed without any authentication."
+msgstr ""
+
+msgid "VisibilityLevel|Unknown"
+msgstr ""
+
+msgid "Visual Studio Code (HTTPS)"
+msgstr ""
+
+msgid "Visual Studio Code (SSH)"
+msgstr ""
+
+msgid "Vulnerabilities"
+msgstr ""
+
+msgid "Vulnerabilities over time"
+msgstr ""
+
+msgid "Vulnerability"
+msgstr ""
+
+msgid "Vulnerability Report"
+msgstr ""
+
+msgid "Vulnerability remediated. Review before resolving."
+msgstr ""
+
+msgid "Vulnerability report"
+msgstr ""
+
+msgid "Vulnerability resolved in %{branch}"
+msgstr ""
+
+msgid "Vulnerability resolved in the default branch"
+msgstr ""
+
+msgid "VulnerabilityChart|%{formattedStartDate} to today"
+msgstr ""
+
+msgid "VulnerabilityChart|Severity"
+msgstr ""
+
+msgid "VulnerabilityDismissalReasons|Acceptable risk"
+msgstr ""
+
+msgid "VulnerabilityDismissalReasons|False positive"
+msgstr ""
+
+msgid "VulnerabilityDismissalReasons|Mitigating control"
+msgstr ""
+
+msgid "VulnerabilityDismissalReasons|Not applicable"
+msgstr ""
+
+msgid "VulnerabilityDismissalReasons|Used in tests"
+msgstr ""
+
+msgid "VulnerabilityExport|Activity"
+msgstr ""
+
+msgid "VulnerabilityExport|Additional Info"
+msgstr ""
+
+msgid "VulnerabilityExport|CVE"
+msgstr ""
+
+msgid "VulnerabilityExport|CWE"
+msgstr ""
+
+msgid "VulnerabilityExport|Comments"
+msgstr ""
+
+msgid "VulnerabilityExport|Details"
+msgstr ""
+
+msgid "VulnerabilityExport|Detected At"
+msgstr ""
+
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
+msgid "VulnerabilityExport|Group Name"
+msgstr ""
+
+msgid "VulnerabilityExport|Location"
+msgstr ""
+
+msgid "VulnerabilityExport|Other Identifiers"
+msgstr ""
+
+msgid "VulnerabilityExport|Project Name"
+msgstr ""
+
+msgid "VulnerabilityExport|Scanner Name"
+msgstr ""
+
+msgid "VulnerabilityExport|Severity"
+msgstr ""
+
+msgid "VulnerabilityExport|Status"
+msgstr ""
+
+msgid "VulnerabilityExport|Tool"
+msgstr ""
+
+msgid "VulnerabilityExport|Vulnerability"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
+msgstr ""
+
+msgid "VulnerabilityManagement|A removed or remediated vulnerability"
+msgstr ""
+
+msgid "VulnerabilityManagement|A true-positive and will fix"
+msgstr ""
+
+msgid "VulnerabilityManagement|A verified true-positive vulnerability"
+msgstr ""
+
+msgid "VulnerabilityManagement|Add vulnerability finding"
+msgstr ""
+
+msgid "VulnerabilityManagement|An unverified non-confirmed finding"
+msgstr ""
+
+msgid "VulnerabilityManagement|Change status"
+msgstr ""
+
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgstr ""
+
+msgid "VulnerabilityManagement|Create Jira issue"
+msgstr ""
+
+msgid "VulnerabilityManagement|Enter a name"
+msgstr ""
+
+msgid "VulnerabilityManagement|Enter the CVE or CWE code"
+msgstr ""
+
+msgid "VulnerabilityManagement|Enter the CVE or CWE identifier URL"
+msgstr ""
+
+msgid "VulnerabilityManagement|Fetching linked Jira issues"
+msgstr ""
+
+msgid "VulnerabilityManagement|Identifier code and URL are required fields"
+msgstr ""
+
+msgid "VulnerabilityManagement|Manually add a vulnerability entry into the vulnerability report."
+msgstr ""
+
+msgid "VulnerabilityManagement|Name is a required field"
+msgstr ""
+
+msgid "VulnerabilityManagement|Needs triage"
+msgstr ""
+
+msgid "VulnerabilityManagement|Read more about related issues"
+msgstr ""
+
+msgid "VulnerabilityManagement|Related Jira issues"
+msgstr ""
+
+msgid "VulnerabilityManagement|Requires assessment"
+msgstr ""
+
+msgid "VulnerabilityManagement|Select a method"
+msgstr ""
+
+msgid "VulnerabilityManagement|Select a severity level"
+msgstr ""
+
+msgid "VulnerabilityManagement|Select a status"
+msgstr ""
+
+msgid "VulnerabilityManagement|Severity is a required field"
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong while creating vulnerability"
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong while trying to fetch related Jira issues. Please check the %{linkStart}Jira integration settings%{linkEnd} and try again."
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong while trying to refresh the vulnerability. Please try again later."
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong while trying to retrieve the vulnerability history. Please try again later."
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong while trying to save the comment. Please try again later."
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong while trying to unlink the issue. Please try again later."
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong, could not get user."
+msgstr ""
+
+msgid "VulnerabilityManagement|Something went wrong, could not update vulnerability state."
+msgstr ""
+
+msgid "VulnerabilityManagement|Status is a required field"
+msgstr ""
+
+msgid "VulnerabilityManagement|Submit vulnerability"
+msgstr ""
+
+msgid "VulnerabilityManagement|Summary, detailed description, steps to reproduce, etc."
+msgstr ""
+
+msgid "VulnerabilityManagement|Verified as fixed or mitigated"
+msgstr ""
+
+msgid "VulnerabilityManagement|Vulnerability name or type. Ex: Cross-site scripting"
+msgstr ""
+
+msgid "VulnerabilityManagement|Will not fix or a false-positive"
+msgstr ""
+
+msgid "VulnerabilityManagement|invalid issue link or ID"
+msgstr ""
+
+msgid "VulnerabilityStatusTypes|Confirmed"
+msgstr ""
+
+msgid "VulnerabilityStatusTypes|Dismissed"
+msgstr ""
+
+msgid "VulnerabilityStatusTypes|Needs triage"
+msgstr ""
+
+msgid "VulnerabilityStatusTypes|Resolved"
+msgstr ""
+
+msgid "Vulnerability|%{file} was not found in commit %{ref}"
+msgstr ""
+
+msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
+msgstr ""
+
+msgid "Vulnerability|Activity"
+msgstr ""
+
+msgid "Vulnerability|Actual Response"
+msgstr ""
+
+msgid "Vulnerability|Actual received response is the one received when this fault was detected"
+msgstr ""
+
+msgid "Vulnerability|Actual response:"
+msgstr ""
+
+msgid "Vulnerability|Add another identifier"
+msgstr ""
+
+msgid "Vulnerability|Additional Info"
+msgstr ""
+
+msgid "Vulnerability|Assert:"
+msgstr ""
+
+msgid "Vulnerability|Bug Bounty"
+msgstr ""
+
+msgid "Vulnerability|CVSS v3"
+msgstr ""
+
+msgid "Vulnerability|Class"
+msgstr ""
+
+msgid "Vulnerability|Cluster"
+msgstr ""
+
+msgid "Vulnerability|Code Review"
+msgstr ""
+
+msgid "Vulnerability|Comments"
+msgstr ""
+
+msgid "Vulnerability|Could not load prompt."
+msgstr ""
+
+msgid "Vulnerability|Crash address"
+msgstr ""
+
+msgid "Vulnerability|Crash address:"
+msgstr ""
+
+msgid "Vulnerability|Crash state"
+msgstr ""
+
+msgid "Vulnerability|Crash type"
+msgstr ""
+
+msgid "Vulnerability|Crash type:"
+msgstr ""
+
+msgid "Vulnerability|Description"
+msgstr ""
+
+msgid "Vulnerability|Details"
+msgstr ""
+
+msgid "Vulnerability|Detected"
+msgstr ""
+
+msgid "Vulnerability|Detection method"
+msgstr ""
+
+msgid "Vulnerability|Download"
+msgstr ""
+
+msgid "Vulnerability|Enter the associated CVE or CWE entries for this vulnerability."
+msgstr ""
+
+msgid "Vulnerability|Evidence"
+msgstr ""
+
+msgid "Vulnerability|Evidence:"
+msgstr ""
+
+msgid "Vulnerability|Explain this vulnerability"
+msgstr ""
+
+msgid "Vulnerability|Explain this vulnerability and how to mitigate it with AI"
+msgstr ""
+
+msgid "Vulnerability|External Security Report"
+msgstr ""
+
+msgid "Vulnerability|False positive detected"
+msgstr ""
+
+msgid "Vulnerability|File"
+msgstr ""
+
+msgid "Vulnerability|File:"
+msgstr ""
+
+msgid "Vulnerability|GitLab Security Report"
+msgstr ""
+
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
+msgid "Vulnerability|Hide prompt"
+msgstr ""
+
+msgid "Vulnerability|Identifier"
+msgstr ""
+
+msgid "Vulnerability|Identifier URL"
+msgstr ""
+
+msgid "Vulnerability|Identifier code"
+msgstr ""
+
+msgid "Vulnerability|Identifiers"
+msgstr ""
+
+msgid "Vulnerability|Image"
+msgstr ""
+
+msgid "Vulnerability|Image:"
+msgstr ""
+
+msgid "Vulnerability|Information related to how the vulnerability was discovered and its impact on the system."
+msgstr ""
+
+msgid "Vulnerability|Links"
+msgstr ""
+
+msgid "Vulnerability|Location"
+msgstr ""
+
+msgid "Vulnerability|Method"
+msgstr ""
+
+msgid "Vulnerability|Namespace"
+msgstr ""
+
+msgid "Vulnerability|Namespace:"
+msgstr ""
+
+msgid "Vulnerability|Project"
+msgstr ""
+
+msgid "Vulnerability|Project:"
+msgstr ""
+
+msgid "Vulnerability|Providing the source code improves the response quality. If security is a concern, you can send basic vulnerability info for a generic example."
+msgstr ""
+
+msgid "Vulnerability|Remove identifier row"
+msgstr ""
+
+msgid "Vulnerability|Reproduction Assets"
+msgstr ""
+
+msgid "Vulnerability|Request"
+msgstr ""
+
+msgid "Vulnerability|Request/Response"
+msgstr ""
+
+msgid "Vulnerability|Response generated by AI"
+msgstr ""
+
+msgid "Vulnerability|Scanner Provider"
+msgstr ""
+
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
+msgid "Vulnerability|Security Audit"
+msgstr ""
+
+msgid "Vulnerability|Select a severity"
+msgstr ""
+
+msgid "Vulnerability|Send code with prompt"
+msgstr ""
+
+msgid "Vulnerability|Sending code to AI"
+msgstr ""
+
+msgid "Vulnerability|Sent request:"
+msgstr ""
+
+msgid "Vulnerability|Set the status of the vulnerability finding based on the information available to you."
+msgstr ""
+
+msgid "Vulnerability|Severity"
+msgstr ""
+
+msgid "Vulnerability|Severity:"
+msgstr ""
+
+msgid "Vulnerability|Show prompt"
+msgstr ""
+
+msgid "Vulnerability|Something went wrong while trying to get the source file."
+msgstr ""
+
+msgid "Vulnerability|Stacktrace snippet:"
+msgstr ""
+
+msgid "Vulnerability|Status"
+msgstr ""
+
+msgid "Vulnerability|Status:"
+msgstr ""
+
+msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
+msgstr ""
+
+msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
+msgstr ""
+
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgstr ""
+
+msgid "Vulnerability|Tool"
+msgstr ""
+
+msgid "Vulnerability|Tool:"
+msgstr ""
+
+msgid "Vulnerability|Training"
+msgstr ""
+
+msgid "Vulnerability|Training not available for this vulnerability."
+msgstr ""
+
+msgid "Vulnerability|Try it out"
+msgstr ""
+
+msgid "Vulnerability|URL:"
+msgstr ""
+
+msgid "Vulnerability|Unmodified Response"
+msgstr ""
+
+msgid "Vulnerability|Unmodified response:"
+msgstr ""
+
+msgid "Vulnerability|View training"
+msgstr ""
+
+msgid "Vulnerability|Vulnerable class:"
+msgstr ""
+
+msgid "Vulnerability|Vulnerable method:"
+msgstr ""
+
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
+msgid "WARNING:"
+msgstr ""
+
+msgid "WARNING: This snippet contains hidden files which might be used to mask malicious behavior. Exercise caution if cloning and executing code from this snippet."
+msgstr ""
+
+msgid "Wait for the file to load to copy its contents"
+msgstr ""
+
+msgid "Waiting for approvals"
+msgstr ""
+
+msgid "Waiting for merge (open and assigned)"
+msgstr ""
+
+msgid "Want to see the data? Please ask an administrator for access."
+msgstr ""
+
+msgid "Warning"
+msgstr ""
+
+msgid "Warning:"
+msgstr ""
+
+msgid "Warning: Displaying this diagram might cause performance issues on this page."
+msgstr ""
+
+msgid "Warning: Synchronizing LDAP removes direct members' access."
+msgstr ""
+
+msgid "We also use email for avatar detection if no avatar is uploaded."
+msgstr ""
+
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
+msgid "We are currently unable to fetch data for this graph."
+msgstr ""
+
+msgid "We could not determine the path to remove the epic"
+msgstr ""
+
+msgid "We could not determine the path to remove the issue"
+msgstr ""
+
+msgid "We couldn't find any %{scope} matching %{term}"
+msgstr ""
+
+msgid "We couldn't find any %{scope} matching %{term} in group %{group}"
+msgstr ""
+
+msgid "We couldn't find any %{scope} matching %{term} in project %{project}"
+msgstr ""
+
+msgid "We detected potential spam in the %{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
+msgstr ""
+
+msgid "We found your token in a public project and have automatically revoked it to protect your account."
+msgstr ""
+
+msgid "We have found the following errors:"
+msgstr ""
+
+msgid "We heard back from your device. You have been authenticated."
+msgstr ""
+
+msgid "We invite you to %{featureLinkStart}request a feature%{featureLinkEnd}, %{bugLinkStart}report a bug%{bugLinkEnd} or %{feedbackLinkStart}share feedback%{feedbackLinkEnd}"
+msgstr ""
+
+msgid "We recommend a work email address."
+msgstr ""
+
+msgid "We recommend that you buy additional Pipeline minutes to avoid any interruption of service."
+msgstr ""
+
+msgid "We recommend that you buy additional Pipeline minutes to resume normal service."
+msgstr ""
+
+msgid "We recommend using cloud-based authenticator applications that can restore access if you lose your hardware device."
+msgstr ""
+
+msgid "We sent you an email with reset password instructions"
+msgstr ""
+
+msgid "We tried to automatically renew your subscription for %{strong}%{namespace_name}%{strong_close} on %{expires_on} but something went wrong so your subscription was downgraded to the free plan. Don't worry, your data is safe. We suggest you check your payment method and get in touch with our support team (%{support_link}). They'll gladly help with your subscription renewal."
+msgstr ""
+
+msgid "We want to be sure it is you, please confirm you are not a robot."
+msgstr ""
+
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
+msgstr ""
+
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
+msgid "We'll use this to help surface the right features and information to you."
+msgstr ""
+
+msgid "We're experiencing difficulties and this tab content is currently unavailable."
+msgstr ""
+
+msgid "We've detected some unusual activity"
+msgstr ""
+
+msgid "We've detected unusual activity"
+msgstr ""
+
+msgid "We've found no vulnerabilities"
+msgstr ""
+
+msgid "Web IDE"
+msgstr ""
+
+msgid "Web Terminal"
+msgstr ""
+
+msgid "Web terminal"
+msgstr ""
+
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
+msgid "WebIDE|Fork project"
+msgstr ""
+
+msgid "WebIDE|Go to fork"
+msgstr ""
+
+msgid "WebIDE|Merge request"
+msgstr ""
+
+msgid "WebIDE|Quickly and easily edit multiple files in your project."
+msgstr ""
+
+msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
+msgstr ""
+
+msgid "WebIDE|This project does not accept unsigned commits."
+msgstr ""
+
+msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
+msgstr ""
+
+msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
+msgstr ""
+
+msgid "WebIDE|You can’t edit files directly in this project. Go to your fork and submit a merge request with your changes."
+msgstr ""
+
+msgid "WebIDE|You need permission to edit files directly in this project."
+msgstr ""
+
+msgid "WebexTeamsService|Send notifications about project events to Webex Teams."
+msgstr ""
+
+msgid "WebexTeamsService|Send notifications about project events to a Webex Teams conversation. %{docs_link}"
+msgstr ""
+
+msgid "WebexTeamsService|Webex Teams"
+msgstr ""
+
+msgid "Webhook"
+msgstr ""
+
+msgid "Webhook Logs"
+msgstr ""
+
+msgid "Webhook Settings"
+msgstr ""
+
+msgid "Webhook events will be displayed here."
+msgstr ""
+
+msgid "Webhook was created"
+msgstr ""
+
+msgid "Webhook was deleted"
+msgstr ""
+
+msgid "Webhook was scheduled for deletion"
+msgstr ""
+
+msgid "Webhook was updated"
+msgstr ""
+
+msgid "Webhook:"
+msgstr ""
+
+msgid "Webhooks"
+msgstr ""
+
+msgid "Webhooks Help"
+msgstr ""
+
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
+msgid "Webhooks|A comment is added to a confidential issue."
+msgstr ""
+
+msgid "Webhooks|A comment is added to an issue or merge request."
+msgstr ""
+
+msgid "Webhooks|A confidential issue is created, updated, closed, or reopened."
+msgstr ""
+
+msgid "Webhooks|A deployment starts, finishes, fails, or is canceled."
+msgstr ""
+
+msgid "Webhooks|A feature flag is turned on or off."
+msgstr ""
+
+msgid "Webhooks|A group member is created, updated, or removed."
+msgstr ""
+
+msgid "Webhooks|A job's status changes."
+msgstr ""
+
+msgid "Webhooks|A merge request is created, updated, or merged."
+msgstr ""
+
+msgid "Webhooks|A new tag is pushed to the repository."
+msgstr ""
+
+msgid "Webhooks|A pipeline's status changes."
+msgstr ""
+
+msgid "Webhooks|A release is created or updated."
+msgstr ""
+
+msgid "Webhooks|A subgroup is created or removed."
+msgstr ""
+
+msgid "Webhooks|A webhook in this group was automatically disabled after being retried multiple times."
+msgstr ""
+
+msgid "Webhooks|A webhook in this project was automatically disabled after being retried multiple times."
+msgstr ""
+
+msgid "Webhooks|A wiki page is created or updated."
+msgstr ""
+
+msgid "Webhooks|An emoji is awarded or revoked. %{help_link}?"
+msgstr ""
+
+msgid "Webhooks|An issue is created, updated, closed, or reopened."
+msgstr ""
+
+msgid "Webhooks|Are you sure you want to delete this group hook?"
+msgstr ""
+
+msgid "Webhooks|Are you sure you want to delete this project hook?"
+msgstr ""
+
+msgid "Webhooks|Are you sure you want to delete this webhook?"
+msgstr ""
+
+msgid "Webhooks|Confidential comments"
+msgstr ""
+
+msgid "Webhooks|Confidential issues events"
+msgstr ""
+
+msgid "Webhooks|Delete webhook"
+msgstr ""
+
+msgid "Webhooks|Deployment events"
+msgstr ""
+
+msgid "Webhooks|Do not show sensitive data such as tokens in the UI."
+msgstr ""
+
+msgid "Webhooks|Enable SSL verification"
+msgstr ""
+
+msgid "Webhooks|Failed to connect"
+msgstr ""
+
+msgid "Webhooks|Fails to connect"
+msgstr ""
+
+msgid "Webhooks|Feature flag events"
+msgstr ""
+
+msgid "Webhooks|Go to webhooks"
+msgstr ""
+
+msgid "Webhooks|How it looks in the UI"
+msgstr ""
+
+msgid "Webhooks|Issues events"
+msgstr ""
+
+msgid "Webhooks|Job events"
+msgstr ""
+
+msgid "Webhooks|Mask portions of URL"
+msgstr ""
+
+msgid "Webhooks|Member events"
+msgstr ""
+
+msgid "Webhooks|Merge request events"
+msgstr ""
+
+msgid "Webhooks|Must match part of URL"
+msgstr ""
+
+msgid "Webhooks|Pipeline events"
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
+msgid "Webhooks|Regular expressions such as %{REGEX_CODE} are supported."
+msgstr ""
+
+msgid "Webhooks|Releases events"
+msgstr ""
+
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
+msgid "Webhooks|SSL verification"
+msgstr ""
+
+msgid "Webhooks|Secret token"
+msgstr ""
+
+msgid "Webhooks|Sensitive portion of URL"
+msgstr ""
+
+msgid "Webhooks|Show full URL"
+msgstr ""
+
+msgid "Webhooks|Subgroup events"
+msgstr ""
+
+msgid "Webhooks|Tag push events"
+msgstr ""
+
+msgid "Webhooks|The webhook %{help_link_start}failed to connect%{help_link_end}, and will retry in %{retry_time}. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
+msgstr ""
+
+msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
+msgstr ""
+
+msgid "Webhooks|Trigger"
+msgstr ""
+
+msgid "Webhooks|URL must be percent-encoded if it contains one or more special characters."
+msgstr ""
+
+msgid "Webhooks|URL preview"
+msgstr ""
+
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
+msgstr ""
+
+msgid "Webhooks|Webhook disabled"
+msgstr ""
+
+msgid "Webhooks|Webhook failed to connect"
+msgstr ""
+
+msgid "Webhooks|Webhook fails to connect"
+msgstr ""
+
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
+msgstr ""
+
+msgid "Webhooks|Wiki page events"
+msgstr ""
+
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
+msgid "Website"
+msgstr ""
+
+msgid "Website:"
+msgstr ""
+
+msgid "Wed"
+msgstr ""
+
+msgid "Wednesday"
+msgstr ""
+
+msgid "Weekday"
+msgstr ""
+
+msgid "Weeks"
+msgstr ""
+
+msgid "Weight"
+msgstr ""
+
+msgid "Weight %{weight}"
+msgstr ""
+
+msgid "Welcome back! Your account had been deactivated due to inactivity but is now reactivated."
+msgstr ""
+
+msgid "Welcome to GitLab"
+msgstr ""
+
+msgid "Welcome to GitLab, %{first_name}!"
+msgstr ""
+
+msgid "Welcome to GitLab,%{br_tag}%{name}!"
+msgstr ""
+
+msgid "Welcome to a new navigation experience"
+msgstr ""
+
+msgid "Welcome, %{name}!"
+msgstr ""
+
+msgid "What are some examples?"
+msgstr ""
+
+msgid "What does the setting affect?"
+msgstr ""
+
+msgid "What does this command do?"
+msgstr ""
+
+msgid "What is GitLab Runner?"
+msgstr ""
+
+msgid "What is Markdown?"
+msgstr ""
+
+msgid "What is a compute quota?"
+msgstr ""
+
+msgid "What is listed here?"
+msgstr ""
+
+msgid "What is repository mirroring?"
+msgstr ""
+
+msgid "What is root cause analysis?"
+msgstr ""
+
+msgid "What is squashing?"
+msgstr ""
+
+msgid "What templates can I create?"
+msgstr ""
+
+msgid "What variables can I use?"
+msgstr ""
+
+msgid "What will you use this group for?"
+msgstr ""
+
+msgid "What would you like to do?"
+msgstr ""
+
+msgid "What's new"
+msgstr ""
+
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
+msgstr ""
+
+msgid "When a runner is locked, it cannot be assigned to other projects"
+msgstr ""
+
+msgid "When all the merge checks for this merge request pass, it will %{linkStart}automatically merge%{linkEnd}."
+msgstr ""
+
+msgid "When enabled, SSH keys with no expiry date or an invalid expiration date are no longer accepted. Leave blank for no limit."
+msgstr ""
+
+msgid "When enabled, cleanup policies execute faster but put more load on Redis."
+msgstr ""
+
+msgid "When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces."
+msgstr ""
+
+msgid "When left blank, default value of 365 is applied. When set, value must be 365 or less. When changed, existing access tokens with an expiration date beyond the maximum allowable lifetime are revoked."
+msgstr ""
+
+msgid "When merge requests and commits in the default branch close, any issues they reference also close."
+msgstr ""
+
+msgid "When the pipeline for this merge request succeeds, it will %{linkStart}automatically merge%{linkEnd}."
+msgstr ""
+
+msgid "When this merge request is accepted"
+msgid_plural "When these merge requests are accepted"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, please provide the exact URL to the repository. HTTP redirects will not be followed."
+msgstr ""
+
+msgid "When you transfer your project to a group, you can easily manage multiple projects, view usage quotas for storage, pipeline minutes, and users, and start a trial or upgrade to a paid tier."
+msgstr ""
+
+msgid "When your trial ends, you'll have a maximum of %d member on the Free tier, or you can get more by upgrading to a paid tier."
+msgid_plural "When your trial ends, you'll have a maximum of %d members on the Free tier, or you can get more by upgrading to a paid tier."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "When your trial ends, you'll move to the Free tier, which has a limit of %{free_user_limit} seat. %{free_user_limit} seat will remain active, and members not occupying a seat will have the %{link_start}Over limit status%{link_end} and lose access to this group."
+msgid_plural "When your trial ends, you'll move to the Free tier, which has a limit of %{free_user_limit} seats. %{free_user_limit} seats will remain active, and members not occupying a seat will have the %{link_start}Over limit status%{link_end} and lose access to this group."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "When:"
+msgstr ""
+
+msgid "Which API requests are affected?"
+msgstr ""
+
+msgid "Which emoji events trigger webhooks"
+msgstr ""
+
+msgid "While it's rare to have no vulnerabilities, it can happen. In any event, we ask that you please double check your settings to make sure you've set up your dashboard correctly."
+msgstr ""
+
+msgid "Who can approve?"
+msgstr ""
+
+msgid "Who can see this group?"
+msgstr ""
+
+msgid "Who will be able to see this group?"
+msgstr ""
+
+msgid "Who will be using GitLab?"
+msgstr ""
+
+msgid "Who will be using this GitLab subscription?"
+msgstr ""
+
+msgid "Who will be using this GitLab trial?"
+msgstr ""
+
+msgid "Who will be using this group?"
+msgstr ""
+
+msgid "Why are you signing up? (optional)"
+msgstr ""
+
+msgid "Why can't I approve?"
+msgstr ""
+
+msgid "Wiki"
+msgstr ""
+
+msgid "Wiki page"
+msgstr ""
+
+msgid "Wiki page was successfully created."
+msgstr ""
+
+msgid "Wiki page was successfully deleted."
+msgstr ""
+
+msgid "Wiki page was successfully updated."
+msgstr ""
+
+msgid "WikiClone|Clone your wiki"
+msgstr ""
+
+msgid "WikiClone|Git Access"
+msgstr ""
+
+msgid "WikiClone|Install Gollum"
+msgstr ""
+
+msgid "WikiClone|Start Gollum and edit locally"
+msgstr ""
+
+msgid "WikiEdit|There is already a page with the same title in that path."
+msgstr ""
+
+msgid "WikiEmptyIssueMessage|Suggest wiki improvement"
+msgstr ""
+
+msgid "WikiEmptyIssueMessage|You must be a group member in order to add wiki pages. If you have suggestions for how to improve the wiki for this group, consider opening an issue in the %{issues_link}."
+msgstr ""
+
+msgid "WikiEmptyIssueMessage|You must be a project member in order to add wiki pages. If you have suggestions for how to improve the wiki for this project, consider opening an issue in the %{issues_link}."
+msgstr ""
+
+msgid "WikiEmptyIssueMessage|issue tracker"
+msgstr ""
+
+msgid "WikiEmpty| Have a Confluence wiki already? Use that instead."
+msgstr ""
+
+msgid "WikiEmpty|A wiki is where you can store all the details about your group. This can include why you've created it, its principles, how to use it, and so on."
+msgstr ""
+
+msgid "WikiEmpty|A wiki is where you can store all the details about your project. This can include why you've created it, its principles, how to use it, and so on."
+msgstr ""
+
+msgid "WikiEmpty|Confluence is enabled"
+msgstr ""
+
+msgid "WikiEmpty|Create your first page"
+msgstr ""
+
+msgid "WikiEmpty|Enable the Confluence Wiki integration"
+msgstr ""
+
+msgid "WikiEmpty|Go to Confluence"
+msgstr ""
+
+msgid "WikiEmpty|Suggest wiki improvement"
+msgstr ""
+
+msgid "WikiEmpty|The wiki lets you write documentation for your group"
+msgstr ""
+
+msgid "WikiEmpty|The wiki lets you write documentation for your project"
+msgstr ""
+
+msgid "WikiEmpty|This group has no wiki pages"
+msgstr ""
+
+msgid "WikiEmpty|This project has no wiki pages"
+msgstr ""
+
+msgid "WikiEmpty|You must be a group member in order to add wiki pages."
+msgstr ""
+
+msgid "WikiEmpty|You must be a project member in order to add wiki pages."
+msgstr ""
+
+msgid "WikiEmpty|You've enabled the Confluence Workspace integration. Your wiki will be viewable directly within Confluence. We are hard at work integrating Confluence more seamlessly into GitLab. If you'd like to stay up to date, follow our %{wiki_confluence_epic_link_start}Confluence epic%{wiki_confluence_epic_link_end}."
+msgstr ""
+
+msgid "WikiHistoricalPage|Browse history"
+msgstr ""
+
+msgid "WikiHistoricalPage|Go to most recent version"
+msgstr ""
+
+msgid "WikiHistoricalPage|This is an old version of this page."
+msgstr ""
+
+msgid "WikiPageConfirmDelete|Are you sure you want to delete this page?"
+msgstr ""
+
+msgid "WikiPageConfirmDelete|Delete page"
+msgstr ""
+
+msgid "WikiPageConfirmDelete|Delete page %{pageTitle}?"
+msgstr ""
+
+msgid "WikiPageConflictMessage|Someone edited the page the same time you did. Please check out %{wikiLinkStart}the page%{wikiLinkEnd} and make sure your changes will not unintentionally remove theirs."
+msgstr ""
+
+msgid "WikiPage|Cancel"
+msgstr ""
+
+msgid "WikiPage|Commit message"
+msgstr ""
+
+msgid "WikiPage|Content"
+msgstr ""
+
+msgid "WikiPage|Create %{pageTitle}"
+msgstr ""
+
+msgid "WikiPage|Create page"
+msgstr ""
+
+msgid "WikiPage|Format"
+msgstr ""
+
+msgid "WikiPage|Learn more."
+msgstr ""
+
+msgid "WikiPage|Page title"
+msgstr ""
+
+msgid "WikiPage|Save changes"
+msgstr ""
+
+msgid "WikiPage|Tip: You can move this page by adding the path to the beginning of the title."
+msgstr ""
+
+msgid "WikiPage|Tip: You can specify the full path for the new file. We will automatically create any missing directories."
+msgstr ""
+
+msgid "WikiPage|Title"
+msgstr ""
+
+msgid "WikiPage|To link to a (new) page, simply type %{linkExample}. More examples are in the %{linkStart}documentation%{linkEnd}."
+msgstr ""
+
+msgid "WikiPage|Update %{pageTitle}"
+msgstr ""
+
+msgid "WikiPage|Write your content or drag files here…"
+msgstr ""
+
+msgid "Wiki|Create New Page"
+msgstr ""
+
+msgid "Wiki|Created date"
+msgstr ""
+
+msgid "Wiki|Edit Page"
+msgstr ""
+
+msgid "Wiki|New page"
+msgstr ""
+
+msgid "Wiki|Page history"
+msgstr ""
+
+msgid "Wiki|Page version"
+msgstr ""
+
+msgid "Wiki|Pages"
+msgstr ""
+
+msgid "Wiki|The sidebar failed to load. You can reload the page to try again."
+msgstr ""
+
+msgid "Wiki|Title"
+msgstr ""
+
+msgid "Wiki|View All Pages"
+msgstr ""
+
+msgid "Wiki|Wiki Pages"
+msgstr ""
+
+msgid "Will be created"
+msgstr ""
+
+msgid "Will be mapped to"
+msgstr ""
+
+msgid "Will be released"
+msgstr ""
+
+msgid "Will deploy to"
+msgstr ""
+
+msgid "Wireframe"
+msgstr ""
+
+msgid "With requirements, you can set criteria to check your products against."
+msgstr ""
+
+msgid "Withdraw Access Request"
+msgstr ""
+
+msgid "Won't fix / Accept risk"
+msgstr ""
+
+msgid "Work Item type with id %{id} was not found"
+msgstr ""
+
+msgid "Work in progress (open and unassigned)"
+msgstr ""
+
+msgid "Work in progress limit"
+msgstr ""
+
+msgid "Work item promoted successfully."
+msgstr ""
+
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
+msgid "WorkItem|%{count} more assignees"
+msgstr ""
+
+msgid "WorkItem|%{invalidWorkItemsList} cannot be added: Cannot assign a non-confidential %{childWorkItemType} to a confidential parent %{parentWorkItemType}. Make the selected %{childWorkItemType} confidential and try again."
+msgstr ""
+
+msgid "WorkItem|%{workItemType} deleted"
+msgstr ""
+
+msgid "WorkItem|A non-confidential %{workItemType} cannot be assigned to a confidential parent %{parentWorkItemType}."
+msgstr ""
+
+msgid "WorkItem|Activity"
+msgstr ""
+
+msgid "WorkItem|Add"
+msgstr ""
+
+msgid "WorkItem|Add %{workItemType}"
+msgstr ""
+
+msgid "WorkItem|Add %{workItemType}s"
+msgstr ""
+
+msgid "WorkItem|Add a title"
+msgstr ""
+
+msgid "WorkItem|Add a to do"
+msgstr ""
+
+msgid "WorkItem|Add assignee"
+msgstr ""
+
+msgid "WorkItem|Add assignees"
+msgstr ""
+
+msgid "WorkItem|Add due date"
+msgstr ""
+
+msgid "WorkItem|Add start date"
+msgstr ""
+
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
+msgid "WorkItem|All activity"
+msgstr ""
+
+msgid "WorkItem|Are you sure you want to cancel editing?"
+msgstr ""
+
+msgid "WorkItem|Are you sure you want to delete the %{workItemType}? This action cannot be reversed."
+msgstr ""
+
+msgid "WorkItem|Assignee"
+msgid_plural "WorkItem|Assignees"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "WorkItem|Cancel"
+msgstr ""
+
+msgid "WorkItem|Child objectives and key results"
+msgstr ""
+
+msgid "WorkItem|Child removal reverted"
+msgstr ""
+
+msgid "WorkItem|Child removed"
+msgstr ""
+
+msgid "WorkItem|Closed"
+msgstr ""
+
+msgid "WorkItem|Comments only"
+msgstr ""
+
+msgid "WorkItem|Convert to task"
+msgstr ""
+
+msgid "WorkItem|Converted to task"
+msgstr ""
+
+msgid "WorkItem|Copy %{workItemType} email address"
+msgstr ""
+
+msgid "WorkItem|Create %{workItemType}"
+msgstr ""
+
+msgid "WorkItem|Create work item"
+msgstr ""
+
+msgid "WorkItem|Dates"
+msgstr ""
+
+msgid "WorkItem|Delete %{workItemType}"
+msgstr ""
+
+msgid "WorkItem|Discard changes"
+msgstr ""
+
+msgid "WorkItem|Due date"
+msgstr ""
+
+msgid "WorkItem|Existing task"
+msgstr ""
+
+msgid "WorkItem|History only"
+msgstr ""
+
+msgid "WorkItem|Incident"
+msgstr ""
+
+msgid "WorkItem|Issue"
+msgstr ""
+
+msgid "WorkItem|Iteration"
+msgstr ""
+
+msgid "WorkItem|Key Result"
+msgstr ""
+
+msgid "WorkItem|Key result"
+msgstr ""
+
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
+msgid "WorkItem|Mark as done"
+msgstr ""
+
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|New %{workItemType}"
+msgstr ""
+
+msgid "WorkItem|New task"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
+msgid "WorkItem|No objectives or key results are currently assigned."
+msgstr ""
+
+msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
+msgstr ""
+
+msgid "WorkItem|None"
+msgstr ""
+
+msgid "WorkItem|Notifications"
+msgstr ""
+
+msgid "WorkItem|Notifications turned off."
+msgstr ""
+
+msgid "WorkItem|Notifications turned on."
+msgstr ""
+
+msgid "WorkItem|Objective"
+msgstr ""
+
+msgid "WorkItem|Only project members with at least the Reporter role, the author, and assignees can view or be notified about this %{workItemType}."
+msgstr ""
+
+msgid "WorkItem|Open"
+msgstr ""
+
+msgid "WorkItem|Promoted to objective."
+msgstr ""
+
+msgid "WorkItem|Remove"
+msgstr ""
+
+msgid "WorkItem|Requirements"
+msgstr ""
+
+msgid "WorkItem|Save and overwrite"
+msgstr ""
+
+msgid "WorkItem|Search existing %{workItemType}s"
+msgstr ""
+
+msgid "WorkItem|Select type"
+msgstr ""
+
+msgid "WorkItem|Someone edited the description at the same time you did. If you save it will overwrite their changes. Please confirm you'd like to save your edits."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when creating %{workItemType}. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when deleting the %{workItemType}. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when deleting the task. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching work items. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when trying to add a child. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while copying the %{workItemType} email address. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while copying the %{workItemType} reference. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while fetching work item award emojis. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while promoting the %{workItemType}. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while removing child."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while undoing child removal."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong while updating the work item. Please try again."
+msgstr ""
+
+msgid "WorkItem|Start date"
+msgstr ""
+
+msgid "WorkItem|Task"
+msgstr ""
+
+msgid "WorkItem|Task actions"
+msgstr ""
+
+msgid "WorkItem|Task deleted"
+msgstr ""
+
+msgid "WorkItem|Task reverted"
+msgstr ""
+
+msgid "WorkItem|Tasks"
+msgstr ""
+
+msgid "WorkItem|Test case"
+msgstr ""
+
+msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
+msgstr ""
+
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
+msgid "WorkItem|Turn off confidentiality"
+msgstr ""
+
+msgid "WorkItem|Turn on confidentiality"
+msgstr ""
+
+msgid "WorkItem|Undo"
+msgstr ""
+
+msgid "WorkItem|View current version"
+msgstr ""
+
+msgid "WorkItem|Work item"
+msgstr ""
+
+msgid "WorkItem|Work item not found"
+msgstr ""
+
+msgid "WorkItem|Work items"
+msgstr ""
+
+msgid "WorkItem|You're only seeing %{boldStart}other activity%{boldEnd} in the feed. To add a comment, switch to one of the following options."
+msgstr ""
+
+msgid "Workspaces"
+msgstr ""
+
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
+msgstr ""
+
+msgid "Workspaces|Cancel"
+msgstr ""
+
+msgid "Workspaces|Could not load workspaces"
+msgstr ""
+
+msgid "Workspaces|Could not retrieve cluster agents for this project"
+msgstr ""
+
+msgid "Workspaces|Create workspace"
+msgstr ""
+
+msgid "Workspaces|Creating"
+msgstr ""
+
+msgid "Workspaces|Develop anywhere"
+msgstr ""
+
+msgid "Workspaces|Error"
+msgstr ""
+
+msgid "Workspaces|Failed"
+msgstr ""
+
+msgid "Workspaces|Failed to create workspace"
+msgstr ""
+
+msgid "Workspaces|Failed to update workspace"
+msgstr ""
+
+msgid "Workspaces|GitLab Workspaces is a powerful collaborative platform that provides a comprehensive set of tools for software development teams to manage their entire development lifecycle."
+msgstr ""
+
+msgid "Workspaces|New workspace"
+msgstr ""
+
+msgid "Workspaces|Restart"
+msgstr ""
+
+msgid "Workspaces|Restarting"
+msgstr ""
+
+msgid "Workspaces|Running"
+msgstr ""
+
+msgid "Workspaces|Select cluster agent"
+msgstr ""
+
+msgid "Workspaces|Select default editor"
+msgstr ""
+
+msgid "Workspaces|Select project"
+msgstr ""
+
+msgid "Workspaces|Start"
+msgstr ""
+
+msgid "Workspaces|Starting"
+msgstr ""
+
+msgid "Workspaces|Stop"
+msgstr ""
+
+msgid "Workspaces|Stopped"
+msgstr ""
+
+msgid "Workspaces|Stopping"
+msgstr ""
+
+msgid "Workspaces|Terminate"
+msgstr ""
+
+msgid "Workspaces|Terminated"
+msgstr ""
+
+msgid "Workspaces|Terminating"
+msgstr ""
+
+msgid "Workspaces|Time before automatic termination"
+msgstr ""
+
+msgid "Workspaces|To create a workspace for this project, an administrator must %{linkStart}configure a cluster agent%{linkEnd} for the project's group."
+msgstr ""
+
+msgid "Workspaces|To create a workspace, add a devfile to this project. A devfile is a configuration file for your workspace."
+msgstr ""
+
+msgid "Workspaces|Unable to load current Workspaces. Please try again or contact an administrator."
+msgstr ""
+
+msgid "Workspaces|Unknown state"
+msgstr ""
+
+msgid "Workspaces|Workspaces"
+msgstr ""
+
+msgid "Workspaces|You can't create a workspace for this project"
+msgstr ""
+
+msgid "Workspaces|Your workspaces"
+msgstr ""
+
+msgid "Would you like to create a new branch?"
+msgstr ""
+
+msgid "Would you like to try auto-generating a branch name?"
+msgstr ""
+
+msgid "Write"
+msgstr ""
+
+msgid "Write a comment or drag your files here…"
+msgstr ""
+
+msgid "Write a comment…"
+msgstr ""
+
+msgid "Write a description or drag your files here…"
+msgstr ""
+
+msgid "Write a description..."
+msgstr ""
+
+msgid "Write a description…"
+msgstr ""
+
+msgid "Write an internal note or drag your files here…"
+msgstr ""
+
+msgid "Write comment template content here…"
+msgstr ""
+
+msgid "Write milestone description..."
+msgstr ""
+
+msgid "Write your release notes or drag your files here…"
+msgstr ""
+
+msgid "Writing just got easier"
+msgstr ""
+
+msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
+msgstr ""
+
+msgid "Xcode"
+msgstr ""
+
+msgid "YYYY-MM-DD"
+msgstr ""
+
+msgid "Yes"
+msgstr ""
+
+msgid "Yes or No"
+msgstr ""
+
+msgid "Yes, add it"
+msgstr ""
+
+msgid "Yes, close issue"
+msgstr ""
+
+msgid "Yes, delete project"
+msgstr ""
+
+msgid "Yesterday"
+msgstr ""
+
+msgid "You"
+msgstr ""
+
+msgid "You already have pending todo for this alert"
+msgstr ""
+
+msgid "You are about to add %{usersTag} people to the discussion. They will all receive a notification."
+msgstr ""
+
+msgid "You are about to clear %{count} image from the cache. Once you confirm, the next time a pipeline runs it must pull an image or tag from Docker Hub. Are you sure?"
+msgid_plural "You are about to clear %{count} images from the cache. Once you confirm, the next time a pipeline runs it must pull an image or tag from Docker Hub. Are you sure?"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "You are about to delete this forked project containing:"
+msgstr ""
+
+msgid "You are about to delete this project containing:"
+msgstr ""
+
+msgid "You are about to incur additional charges"
+msgstr ""
+
+msgid "You are about to transfer the control of your account to %{group_name} group. This action is NOT reversible, you won't be able to access any of your groups and projects outside of %{group_name} once this transfer is complete."
+msgstr ""
+
+msgid "You are already a member of this %{member_source}."
+msgstr ""
+
+msgid "You are already impersonating another user"
+msgstr ""
+
+msgid "You are an admin, which means granting access to %{client_name} will allow them to interact with GitLab as an admin as well. Proceed with caution."
+msgstr ""
+
+msgid "You are attempting to delete a file that has been previously updated."
+msgstr ""
+
+msgid "You are attempting to update a file that has changed since you started editing it."
+msgstr ""
+
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
+msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
+msgstr ""
+
+msgid "You are currently offline, or the GitLab instance is not reachable."
+msgstr ""
+
+msgid "You are going to delete %{project_full_name}. Deleted projects CANNOT be restored! Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove %{group_name}. This will also delete all of its subgroups and projects. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to transfer %{group_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
+msgstr ""
+
+msgid "You are going to turn on confidentiality. Only %{context} members with %{strongStart}%{permissions}%{strongEnd} can view or be notified about this %{issuableType}."
+msgstr ""
+
+msgid "You are not allowed to %{action} a user"
+msgstr ""
+
+msgid "You are not allowed to approve a user"
+msgstr ""
+
+msgid "You are not allowed to change the Work Item type to %{name}."
+msgstr ""
+
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
+msgid "You are not allowed to import projects in this namespace."
+msgstr ""
+
+msgid "You are not allowed to log in using password"
+msgstr ""
+
+msgid "You are not allowed to reject a user"
+msgstr ""
+
+msgid "You are not allowed to unlink your primary login account"
+msgstr ""
+
+msgid "You are not authorized to delete this site profile"
+msgstr ""
+
+msgid "You are not authorized to perform this action"
+msgstr ""
+
+msgid "You are not authorized to run this manual job"
+msgstr ""
+
+msgid "You are not authorized to update this profile"
+msgstr ""
+
+msgid "You are not authorized to update this scanner profile"
+msgstr ""
+
+msgid "You are not authorized to upload metric images"
+msgstr ""
+
+msgid "You are now impersonating %{username}"
+msgstr ""
+
+msgid "You are on a read-only GitLab instance."
+msgstr ""
+
+msgid "You are receiving this message because you are a GitLab administrator for %{url}."
+msgstr ""
+
+msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
+msgstr ""
+
+msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}."
+msgstr ""
+
+msgid "You can %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}."
+msgstr ""
+
+msgid "You can adjust rules on auto-banning %{link_start}here%{link_end}."
+msgstr ""
+
+msgid "You can adjust rules on auto-banning here: %{url}."
+msgstr ""
+
+msgid "You can also create a project from the command line."
+msgstr ""
+
+msgid "You can also press Ctrl-Enter"
+msgstr ""
+
+msgid "You can also press ⌘-Enter"
+msgstr ""
+
+msgid "You can also star a label to make it a priority label."
+msgstr ""
+
+msgid "You can also upload existing files from your computer using the instructions below."
+msgstr ""
+
+msgid "You can also use group access tokens with Git to authenticate over HTTP(S). %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "You can also use project access tokens with Git to authenticate over HTTP(S). %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "You can always edit this later"
+msgstr ""
+
+msgid "You can check it in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
+msgstr ""
+
+msgid "You can check it in your in your personal access tokens settings %{pat_link}."
+msgstr ""
+
+msgid "You can check your tokens or create a new one in your %{pat_link_start}personal access tokens settings%{pat_link_end}."
+msgstr ""
+
+msgid "You can check your tokens or create a new one in your personal access tokens settings %{pat_link}."
+msgstr ""
+
+msgid "You can create a new %{link}."
+msgstr ""
+
+msgid "You can create a new %{name} inside this project by sending an email to the following email address:"
+msgstr ""
+
+msgid "You can create a new Personal Access Token by visiting %{link}"
+msgstr ""
+
+msgid "You can create a new SSH key by visiting %{link}"
+msgstr ""
+
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
+msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
+msgstr ""
+
+msgid "You can create a new one or check them in your %{ssh_key_link_start}SSH keys%{ssh_key_link_end} settings."
+msgstr ""
+
+msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
+msgstr ""
+
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
+msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
+msgstr ""
+
+msgid "You can create new ones at your %{pat_link_start}Personal Access Tokens%{pat_link_end} settings"
+msgstr ""
+
+msgid "You can create new ones at your Personal Access Tokens settings %{pat_link}"
+msgstr ""
+
+msgid "You can easily contribute to them by requesting to join these groups."
+msgstr ""
+
+msgid "You can enable Registration Features because Service Ping is enabled. To continue using Registration Features in the future, you will also need to register with GitLab via a new cloud licensing service."
+msgstr ""
+
+msgid "You can enable group access token creation in %{link_start}group settings%{link_end}."
+msgstr ""
+
+msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
+msgstr ""
+
+msgid "You can enter up to 280 characters"
+msgstr ""
+
+msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
+msgstr ""
+
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
+msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
+msgstr ""
+
+msgid "You can invite a new member to %{project_name} or invite another group."
+msgstr ""
+
+msgid "You can invite a new member to %{project_name}."
+msgstr ""
+
+msgid "You can invite another group to %{project_name}."
+msgstr ""
+
+msgid "You can modify this job's CI/CD variables before running it again."
+msgstr ""
+
+msgid "You can move around the graph by using the arrow keys."
+msgstr ""
+
+msgid "You can notify the app / group or a project by sending them an email notification"
+msgstr ""
+
+msgid "You can now close this window."
+msgstr ""
+
+msgid "You can now submit a merge request to get this change into the original branch."
+msgstr ""
+
+msgid "You can now submit a merge request to get this change into the original project."
+msgstr ""
+
+msgid "You can only add up to %{max_contacts} contacts at one time"
+msgstr ""
+
+msgid "You can only edit files when you are on a branch"
+msgstr ""
+
+msgid "You can only merge once the items above are resolved."
+msgstr ""
+
+msgid "You can only transfer the project to namespaces you manage."
+msgstr ""
+
+msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}."
+msgstr ""
+
+msgid "You can set up jobs to only use runners with specific tags. Separate tags with commas."
+msgstr ""
+
+msgid "You can specify notification level per group or per project."
+msgstr ""
+
+msgid "You can still use and manage existing tokens. %{link_start}Learn more.%{link_end}"
+msgstr ""
+
+msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
+msgstr ""
+
+msgid "You can't approve because you added one or more commits to this merge request."
+msgstr ""
+
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
+msgstr ""
+
+msgid "You cannot %{action} %{state} users."
+msgstr ""
+
+msgid "You cannot access the raw file. Please wait a minute."
+msgstr ""
+
+msgid "You cannot add any more epics. This epic already has maximum number of child epics."
+msgstr ""
+
+msgid "You cannot approve your own deployment. This configuration can be adjusted in the protected environment settings."
+msgstr ""
+
+msgid "You cannot combine replace_ids with add_ids or remove_ids"
+msgstr ""
+
+msgid "You cannot impersonate a blocked user"
+msgstr ""
+
+msgid "You cannot impersonate a user who cannot log in"
+msgstr ""
+
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
+msgid "You cannot impersonate an internal user"
+msgstr ""
+
+msgid "You cannot play this scheduled pipeline at the moment. Please wait a minute."
+msgstr ""
+
+msgid "You cannot rename an environment after it's created."
+msgstr ""
+
+msgid "You cannot set yourself to awaiting"
+msgstr ""
+
+msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
+msgstr ""
+
+msgid "You cannot write to this read-only GitLab instance."
+msgstr ""
+
+msgid "You can’t edit files directly in this project."
+msgstr ""
+
+msgid "You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
+msgstr ""
+
+msgid "You could not create a new trigger."
+msgstr ""
+
+msgid "You currently have no custom domains."
+msgstr ""
+
+msgid "You do not belong to any groups yet."
+msgstr ""
+
+msgid "You do not belong to any projects yet."
+msgstr ""
+
+msgid "You do not have access to any projects for creating incidents."
+msgstr ""
+
+msgid "You do not have any subscriptions yet"
+msgstr ""
+
+msgid "You do not have permission to access DORA4 metrics."
+msgstr ""
+
+msgid "You do not have permission to access dora metrics."
+msgstr ""
+
+msgid "You do not have permission to approve a member"
+msgstr ""
+
+msgid "You do not have permission to leave this %{namespaceType}."
+msgstr ""
+
+msgid "You do not have permission to run a pipeline on this branch."
+msgstr ""
+
+msgid "You do not have permission to run the Web Terminal. Please contact a project administrator."
+msgstr ""
+
+msgid "You do not have permission to set a member awaiting"
+msgstr ""
+
+msgid "You do not have permission to update the environment."
+msgstr ""
+
+msgid "You do not have permissions to run the import."
+msgstr ""
+
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
+msgid "You don't have any active chat names."
+msgstr ""
+
+msgid "You don't have any applications."
+msgstr ""
+
+msgid "You don't have any authorized applications."
+msgstr ""
+
+msgid "You don't have any open merge requests"
+msgstr ""
+
+msgid "You don't have any recent searches"
+msgstr ""
+
+msgid "You don't have permission to approve this deployment. Contact the project or group owner for help."
+msgstr ""
+
+msgid "You don't have permission to view this epic"
+msgstr ""
+
+msgid "You don't have permissions to import this project"
+msgstr ""
+
+msgid "You don't have sufficient permission to perform this action."
+msgstr ""
+
+msgid "You don't have the %{role} role for any groups in this instance."
+msgstr ""
+
+msgid "You don't have write access to the source branch."
+msgstr ""
+
+msgid "You don’t have access to Productivity Analytics in this group"
+msgstr ""
+
+msgid "You don’t have access to Value Stream Analytics for this group"
+msgstr ""
+
+msgid "You have %{pendingMembersCount} pending member that needs approval."
+msgid_plural "You have %{pendingMembersCount} pending members that need approval."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "You have already reported this user"
+msgstr ""
+
+msgid "You have been granted %{access_level} access to the %{source_link} %{source_type}."
+msgstr ""
+
+msgid "You have been granted %{access_level} access to the %{source_name} %{source_type}."
+msgstr ""
+
+msgid "You have been granted %{member_human_access} access to group %{name}."
+msgstr ""
+
+msgid "You have been granted %{member_human_access} access to project %{name}."
+msgstr ""
+
+msgid "You have been invited by %{link_to_inviter} to join %{source_name} %{strong_open}%{link_to_source}%{strong_close} as %{role}"
+msgstr ""
+
+msgid "You have been redirected to the only result; see the %{a_start}search results%{a_end} instead."
+msgstr ""
+
+msgid "You have been unsubscribed from this thread."
+msgstr ""
+
+msgid "You have declined the invitation to join %{title} %{name}."
+msgstr ""
+
+msgid "You have imported from this project %{numberOfPreviousImports} times before. Each new import will create duplicate issues."
+msgstr ""
+
+msgid "You have insufficient permissions to configure escalation policies for this project"
+msgstr ""
+
+msgid "You have insufficient permissions to create a Todo for this alert"
+msgstr ""
+
+msgid "You have insufficient permissions to create a target branch rule"
+msgstr ""
+
+msgid "You have insufficient permissions to create an HTTP integration for this project"
+msgstr ""
+
+msgid "You have insufficient permissions to create an on-call schedule for this project"
+msgstr ""
+
+msgid "You have insufficient permissions to manage alerts for this project"
+msgstr ""
+
+msgid "You have insufficient permissions to manage resource links for this incident"
+msgstr ""
+
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
+msgid "You have insufficient permissions to manage timeline events for this incident"
+msgstr ""
+
+msgid "You have insufficient permissions to remove an on-call rotation from this project"
+msgstr ""
+
+msgid "You have insufficient permissions to remove an on-call schedule from this project"
+msgstr ""
+
+msgid "You have insufficient permissions to remove this HTTP integration"
+msgstr ""
+
+msgid "You have insufficient permissions to remove this Namespace Ban"
+msgstr ""
+
+msgid "You have insufficient permissions to set customer relations contacts for this issue"
+msgstr ""
+
+msgid "You have insufficient permissions to update an on-call schedule for this project"
+msgstr ""
+
+msgid "You have insufficient permissions to update this HTTP integration"
+msgstr ""
+
+msgid "You have insufficient permissions to view shifts for this rotation"
+msgstr ""
+
+msgid "You have more active users than are allowed by your license. Before %{date} GitLab must reconcile your subscription. To complete this process, export your license usage file and email it to %{renewal_service_email}. A new license will be emailed to the email address registered in the %{customers_dot}. You can add this license to your instance."
+msgstr ""
+
+msgid "You have more active users than are allowed by your license. GitLab must now reconcile your subscription. To complete this process, export your license usage file and email it to %{renewal_service_email}. A new license will be emailed to the email address registered in the %{customers_dot}. You can add this license to your instance."
+msgstr ""
+
+msgid "You have no permissions"
+msgstr ""
+
+msgid "You have no saved replies yet."
+msgstr ""
+
+msgid "You have not added any approvers. Start by adding users or groups."
+msgstr ""
+
+msgid "You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can %{anchorOpen}use that key to generate additional recovery codes%{anchorClose}."
+msgstr ""
+
+msgid "You have successfully purchased %{product}. You'll receive a receipt by email. Your purchase may take a minute to sync, so refresh the page if you don't see it yet."
+msgstr ""
+
+msgid "You have unsaved changes"
+msgstr ""
+
+msgid "You left the \"%{membershipable_human_name}\" %{source_type}."
+msgstr ""
+
+msgid "You may close the milestone now."
+msgstr ""
+
+msgid "You must be authenticated to access this path."
+msgstr ""
+
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
+msgid "You must confirm your email within %{cut_off_days} days of signing up. If you do not confirm your email in this timeframe, your account will be deleted and you will need to sign up for GitLab again."
+msgstr ""
+
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgstr ""
+
+msgid "You must have maintainer access to force delete a lock"
+msgstr ""
+
+msgid "You must provide a valid current password"
+msgstr ""
+
+msgid "You must provide a valid current password."
+msgstr ""
+
+msgid "You must provide at least one filter argument for this query"
+msgstr ""
+
+msgid "You must provide your current password in order to change it."
+msgstr ""
+
+msgid "You must save your recovery codes after you first register a two-factor authenticator, so you do not lose access to your account. %{linkStart}See the documentation on managing your WebAuthn device for more information.%{linkEnd}"
+msgstr ""
+
+msgid "You must sign in to search for specific projects."
+msgstr ""
+
+msgid "You must solve the CAPTCHA in order to submit"
+msgstr ""
+
+msgid "You need a different license to enable FileLocks feature"
+msgstr ""
+
+msgid "You need git-lfs version %{min_git_lfs_version} (or greater) to continue. Please visit https://git-lfs.github.com"
+msgstr ""
+
+msgid "You need permission."
+msgstr ""
+
+msgid "You need to register a two-factor authentication app before you can set up a device."
+msgstr ""
+
+msgid "You need to set terms to be enforced"
+msgstr ""
+
+msgid "You need to specify both an Access Token and a Host URL."
+msgstr ""
+
+msgid "You need to upload a GitLab project export archive (ending in .gz)."
+msgstr ""
+
+msgid "You need to verify your primary email first before enabling Two-Factor Authentication."
+msgstr ""
+
+msgid "You see projects here when you're added to a group or project."
+msgstr ""
+
+msgid "You should add a %{linkStart}.gitlab-ci.yml%{linkEnd} file to this project to avoid pipeline failures. %{compliancePipelineLinkStart}Why?%{compliancePipelineLinkEnd}"
+msgstr ""
+
+msgid "You successfully declined the invitation"
+msgstr ""
+
+msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
+msgstr ""
+
+msgid "You will be removed from existing projects/groups"
+msgstr ""
+
+msgid "You will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
+msgstr ""
+
+msgid "You will first need to set up Jira Integration to use this feature."
+msgstr ""
+
+msgid "You will lose all changes you've made to this file. This action cannot be undone."
+msgstr ""
+
+msgid "You will lose all uncommitted changes you've made in this project. This action cannot be undone."
+msgstr ""
+
+msgid "You will need to update your local repositories to point to the new location."
+msgstr ""
+
+msgid "You will not get any notifications via email"
+msgstr ""
+
+msgid "You will only receive notifications for the events you choose"
+msgstr ""
+
+msgid "You will only receive notifications for threads you have participated in"
+msgstr ""
+
+msgid "You will receive notifications for any activity"
+msgstr ""
+
+msgid "You will receive notifications only for comments in which you were @mentioned"
+msgstr ""
+
+msgid "You won't be able to create new projects because you have reached your project limit."
+msgstr ""
+
+msgid "You'll be charged for %{true_up_link_start}users over license%{link_end} on a quarterly or annual basis, depending on the terms of your agreement."
+msgstr ""
+
+msgid "You'll be signed out from your current account automatically."
+msgstr ""
+
+msgid "You'll need to use different branch names to get a valid comparison."
+msgstr ""
+
+msgid "You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end} in %{strong_start}%{group_name}%{strong_end}."
+msgstr ""
+
+msgid "You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end}."
+msgstr ""
+
+msgid "You're at the first commit"
+msgstr ""
+
+msgid "You're at the last commit"
+msgstr ""
+
+msgid "You're not allowed to %{tag_start}edit%{tag_end} files in this project directly. Please fork this project, make your changes there, and submit a merge request."
+msgstr ""
+
+msgid "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request."
+msgstr ""
+
+msgid "You're not allowed to make changes to this project directly. A fork of this project is being created that you can make changes in, so you can submit a merge request."
+msgstr ""
+
+msgid "You're receiving this email because of your account on %{host}."
+msgstr ""
+
+msgid "You're receiving this email because of your account on %{host}. %{manage_label_subscriptions_link_start}Manage label subscriptions%{manage_label_subscriptions_link_end} &middot; %{help_link_start}Help%{help_link_end}"
+msgstr ""
+
+msgid "You're receiving this email because of your account on %{host}. %{manage_notifications_link_start}Manage all notifications%{manage_notifications_link_end} &middot; %{help_link_start}Help%{help_link_end}"
+msgstr ""
+
+msgid "You're receiving this email because of your account on %{host}. %{unsubscribe_link_start}Unsubscribe%{unsubscribe_link_end} from this thread &middot; %{manage_notifications_link_start}Manage all notifications%{manage_notifications_link_end} &middot; %{help_link_start}Help%{help_link_end}"
+msgstr ""
+
+msgid "You're receiving this email because of your activity on %{host}."
+msgstr ""
+
+msgid "You're receiving this email because of your activity on %{host}. %{unsubscribe_link_start}Unsubscribe%{unsubscribe_link_end} from this thread &middot; %{manage_notifications_link_start}Manage all notifications%{manage_notifications_link_end} &middot; %{help_link_start}Help%{help_link_end}"
+msgstr ""
+
+msgid "You're receiving this email because you have been assigned an item on %{host}."
+msgstr ""
+
+msgid "You're receiving this email because you have been assigned an item on %{host}. %{unsubscribe_link_start}Unsubscribe%{unsubscribe_link_end} from this thread &middot; %{manage_notifications_link_start}Manage all notifications%{manage_notifications_link_end} &middot; %{help_link_start}Help%{help_link_end}"
+msgstr ""
+
+msgid "You're receiving this email because you have been mentioned on %{host}."
+msgstr ""
+
+msgid "You're receiving this email because you have been mentioned on %{host}. %{manage_notifications_link_start}Manage all notifications%{manage_notifications_link_end} &middot; %{help_link_start}Help%{help_link_end}"
+msgstr ""
+
+msgid "You're receiving this email because you have been mentioned on %{host}. %{unsubscribe_link_start}Unsubscribe%{unsubscribe_link_end} from this thread &middot; %{manage_notifications_link_start}Manage all notifications%{manage_notifications_link_end} &middot; %{help_link_start}Help%{help_link_end}"
+msgstr ""
+
+msgid "You're viewing members of %{strong_start}%{group_name}%{strong_end}."
+msgstr ""
+
+msgid "You've already enabled two-factor authentication using one time password authenticators. In order to register a different device, you must first disable two-factor authentication."
+msgstr ""
+
+msgid "You've rejected %{user}"
+msgstr ""
+
+msgid "You've successfully purchased the %{plan} plan subscription for 1 user and you'll receive a receipt by email. Your purchase may take a minute to sync, refresh the page if your subscription details haven't displayed yet."
+msgid_plural "You've successfully purchased the %{plan} plan subscription for %{quantity} users and you'll receive a receipt by email. Your purchase may take a minute to sync, refresh the page if your subscription details haven't displayed yet."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "YouTube"
+msgstr ""
+
+msgid "Your %{group} membership will now expire in %{days}."
+msgstr ""
+
+msgid "Your %{plan_name} subscription will expire on %{expires_on}"
+msgstr ""
+
+msgid "Your %{plan} plan will be applied to your group."
+msgstr ""
+
+msgid "Your %{spammable_entity_type} has been recognized as spam. Please, change the content or solve the reCAPTCHA to proceed."
+msgstr ""
+
+msgid "Your %{spammable_entity_type} has been recognized as spam. Please, change the content to proceed."
+msgstr ""
+
+msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
+msgstr ""
+
+msgid "Your Activity"
+msgstr ""
+
+msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details."
+msgstr ""
+
+msgid "Your CSV export has started. It will be emailed to %{email} when complete."
+msgstr ""
+
+msgid "Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment."
+msgstr ""
+
+msgid "Your CSV export of %{exported_objects} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
+msgstr ""
+
+msgid "Your CSV export request has succeeded. The result will be emailed to %{email}."
+msgstr ""
+
+msgid "Your CSV import for project"
+msgstr ""
+
+msgid "Your Chain of Custody CSV export for the group %{group_link} has been added to this email as an attachment."
+msgstr ""
+
+msgid "Your Chain of Custody CSV export for the group %{group_name} has been added to this email as an attachment."
+msgstr ""
+
+msgid "Your DevOps Reports give an overview of how you are using GitLab from a feature perspective. Use them to view how you compare with other organizations, and how your teams compare against each other."
+msgstr ""
+
+msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. To ensure that your group does not become read-only, you should contact a user with the Owner role for this group to upgrade to a paid tier, or manage your usage. For more information about the upcoming usage limits, see our %{faq_link_start}FAQ%{link_end}."
+msgstr ""
+
+msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. You should reduce the number of users or upgrade to a paid tier %{strong_start}before%{strong_end} you manage your storage usage. Otherwise, your Free top-level group will become read-only immediately because the 5-user limit applies. For more information, see our %{faq_link_start}FAQ%{link_end}.%{br_tag}%{br_tag}To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
+msgstr ""
+
+msgid "Your GPG keys"
+msgstr ""
+
+msgid "Your GitLab Ultimate free trial lasts for 30 days. After this period, you can maintain a GitLab Free account forever or upgrade to a paid plan."
+msgstr ""
+
+msgid "Your GitLab account has been locked due to an excessive number of unsuccessful sign in attempts. You can wait for your account to automatically unlock in %{duration} or you can click the link below to unlock now."
+msgstr ""
+
+msgid "Your GitLab account is now an %{source_link}:"
+msgstr ""
+
+msgid "Your GitLab account is now an Enterprise User (%{source_link}):"
+msgstr ""
+
+msgid "Your GitLab account request has been approved!"
+msgstr ""
+
+msgid "Your GitLab group"
+msgstr ""
+
+msgid "Your GitLab instance allows anyone to register for an account, which is a security risk on public-facing GitLab instances. You should deactivate new sign ups if public users aren't expected to register for an account."
+msgstr ""
+
+msgid "Your GitLab version"
+msgstr ""
+
+msgid "Your Groups"
+msgstr ""
+
+msgid "Your Personal Access Token was revoked"
+msgstr ""
+
+msgid "Your Projects (default)"
+msgstr ""
+
+msgid "Your Projects' Activity"
+msgstr ""
+
+msgid "Your SSH key has expired"
+msgstr ""
+
+msgid "Your SSH key is expiring soon."
+msgstr ""
+
+msgid "Your SSH key was deleted"
+msgstr ""
+
+msgid "Your SSH keys"
+msgstr ""
+
+msgid "Your Time-based OTP device was registered!"
+msgstr ""
+
+msgid "Your To-Do List"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
+msgstr ""
+
+msgid "Your access request to the %{source_type} has been withdrawn."
+msgstr ""
+
+msgid "Your account has been blocked. Contact %{support} for assistance."
+msgstr ""
+
+msgid "Your account has been blocked. Contact your GitLab administrator for assistance."
+msgstr ""
+
+msgid "Your account has been deactivated"
+msgstr ""
+
+msgid "Your account has been deactivated by your administrator. Please log back in to reactivate your account."
+msgstr ""
+
+msgid "Your account has been deactivated. You will not be able to: "
+msgstr ""
+
+msgid "Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_password_link_start}set a password%{link_end} or %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}."
+msgstr ""
+
+msgid "Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}."
+msgstr ""
+
+msgid "Your account is locked."
+msgstr ""
+
+msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
+msgstr ""
+
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
+msgid "Your action succeeded."
+msgstr ""
+
+msgid "Your activity"
+msgstr ""
+
+msgid "Your applications"
+msgstr ""
+
+msgid "Your authorized applications"
+msgstr ""
+
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
+msgid "Your changes can be committed to %{branch_name} because a merge request is open."
+msgstr ""
+
+msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
+msgstr ""
+
+msgid "Your changes have been saved"
+msgstr ""
+
+msgid "Your changes have been successfully committed."
+msgstr ""
+
+msgid "Your comment could not be submitted because %{reason}."
+msgstr ""
+
+msgid "Your comment could not be submitted! Please check your network connection and try again."
+msgstr ""
+
+msgid "Your comment could not be updated because %{reason}."
+msgstr ""
+
+msgid "Your comment will be discarded."
+msgstr ""
+
+msgid "Your current password is required to register a new device."
+msgstr ""
+
+msgid "Your current password is required to register a two-factor authenticator app."
+msgstr ""
+
+msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
+msgstr ""
+
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
+msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
+msgstr ""
+
+msgid "Your feedback is important to us 👋"
+msgstr ""
+
+msgid "Your file must contain a column named %{codeStart}title%{codeEnd}. A %{codeStart}description%{codeEnd} column is optional. The maximum file size allowed is 10 MB."
+msgstr ""
+
+msgid "Your free group is now limited to %d member"
+msgid_plural "Your free group is now limited to %d members"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Your instance has %{remaining_user_count} users remaining of the %{total_user_count} included in your subscription. You can add more users than the number included in your license, and we will include the overage in your next bill."
+msgstr ""
+
+msgid "Your instance has exceeded your subscription's licensed user count."
+msgstr ""
+
+msgid "Your instance is approaching its licensed user count"
+msgstr ""
+
+msgid "Your issues are being imported. Once finished, you'll get a confirmation email."
+msgstr ""
+
+msgid "Your issues will be imported in the background. Once finished, you'll get a confirmation email."
+msgstr ""
+
+msgid "Your license does not support on-call rotations"
+msgstr ""
+
+msgid "Your license does not support on-call schedules"
+msgstr ""
+
+msgid "Your license is valid from"
+msgstr ""
+
+msgid "Your membership in %{group} no longer expires."
+msgstr ""
+
+msgid "Your membership in %{link_to} %{project_or_group_name} will expire in %{days_formatted}."
+msgstr ""
+
+msgid "Your membership in %{project_or_group} %{project_or_group_name} will expire in %{days_formatted}."
+msgstr ""
+
+msgid "Your membership will expire in %{days_to_expire} days"
+msgstr ""
+
+msgid "Your name"
+msgstr ""
+
+msgid "Your new %{accessTokenType}"
+msgstr ""
+
+msgid "Your new %{accessTokenType} has been created."
+msgstr ""
+
+msgid "Your new comment"
+msgstr ""
+
+msgid "Your password"
+msgstr ""
+
+msgid "Your password reset token has expired."
+msgstr ""
+
+msgid "Your personal access tokens have expired"
+msgstr ""
+
+msgid "Your personal access tokens will expire in %{days_to_expire} days or less"
+msgstr ""
+
+msgid "Your profile"
+msgstr ""
+
+msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
+msgstr ""
+
+msgid "Your projects"
+msgstr ""
+
+msgid "Your public email will be displayed on your public profile."
+msgstr ""
+
+msgid "Your request for access could not be processed: %{error_message}"
+msgstr ""
+
+msgid "Your request for access has been queued for review."
+msgstr ""
+
+msgid "Your request to join %{host} has been rejected."
+msgstr ""
+
+msgid "Your requirements are being imported. Once finished, you'll receive a confirmation email."
+msgstr ""
+
+msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
+msgstr ""
+
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
+msgid "Your search didn't match any commits."
+msgstr ""
+
+msgid "Your search didn't match any commits. Try a different query."
+msgstr ""
+
+msgid "Your search timed out"
+msgstr ""
+
+msgid "Your sign-in page is %{url}."
+msgstr ""
+
+msgid "Your subscription expired!"
+msgstr ""
+
+msgid "Your subscription has %{remaining_seat_count} out of %{total_seat_count} seat remaining."
+msgid_plural "Your subscription has %{remaining_seat_count} out of %{total_seat_count} seats remaining."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Your top-level group %{namespace_name} has reached the %{free_limit} user limit"
+msgstr ""
+
+msgid "Your top-level group %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
+msgstr ""
+
+msgid "Your top-level group is over the user limit and has been placed in a read-only state."
+msgstr ""
+
+msgid "Your update failed. You can only upload one design when dropping onto an existing design."
+msgstr ""
+
+msgid "Your update failed. You must upload a file with the same file name when dropping onto an existing design."
+msgstr ""
+
+msgid "Your username is %{username}."
+msgstr ""
+
+msgid "Your work"
+msgstr ""
+
+msgid "Your work items are being imported. Once finished, you'll receive a confirmation email."
+msgstr ""
+
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
+msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
+msgstr ""
+
+msgid "ZenTaoIntegration|This is a ZenTao user."
+msgstr ""
+
+msgid "ZenTaoIntegration|ZenTao user"
+msgstr ""
+
+msgid "ZentaoIntegration|An error occurred while requesting data from the ZenTao service."
+msgstr ""
+
+msgid "ZentaoIntegration|Base URL of the ZenTao instance."
+msgstr ""
+
+msgid "ZentaoIntegration|Before you enable this integration, you must configure ZenTao. For more details, read the %{link_start}ZenTao integration documentation%{link_end}."
+msgstr ""
+
+msgid "ZentaoIntegration|Enter new ZenTao API token"
+msgstr ""
+
+msgid "ZentaoIntegration|If different from Web URL."
+msgstr ""
+
+msgid "ZentaoIntegration|Open ZenTao"
+msgstr ""
+
+msgid "ZentaoIntegration|Use ZenTao as this project's issue tracker."
+msgstr ""
+
+msgid "ZentaoIntegration|ZenTao"
+msgstr ""
+
+msgid "ZentaoIntegration|ZenTao API URL (optional)"
+msgstr ""
+
+msgid "ZentaoIntegration|ZenTao API token"
+msgstr ""
+
+msgid "ZentaoIntegration|ZenTao Product ID"
+msgstr ""
+
+msgid "ZentaoIntegration|ZenTao Web URL"
+msgstr ""
+
+msgid "ZentaoIntegration|ZenTao issues"
+msgstr ""
+
+msgid "Zoom in"
+msgstr ""
+
+msgid "Zoom meeting added"
+msgstr ""
+
+msgid "Zoom meeting removed"
+msgstr ""
+
+msgid "Zoom out"
+msgstr ""
+
+msgid "[No reason]"
+msgstr ""
+
+msgid "[REDACTED]"
+msgstr ""
+
+msgid "[Redacted]"
+msgstr ""
+
+msgid "[Supports GitLab-flavored markdown, including quick actions]"
+msgstr ""
+
+msgid "`end_time` should not exceed one month after `start_time`"
+msgstr ""
+
+msgid "`start_time` should precede `end_time`"
+msgstr ""
+
+msgid "a deleted user"
+msgstr ""
+
+msgid "about 1 hour"
+msgid_plural "about %d hours"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "access:"
+msgstr ""
+
+msgid "add at least one file to the repository"
+msgstr ""
+
+msgid "added %{emails}"
+msgstr ""
+
+msgid "added a %{link_type} link"
+msgstr ""
+
+msgid "added a Zoom call to this issue"
+msgstr ""
+
+msgid "ago"
+msgstr ""
+
+msgid "alert"
+msgstr ""
+
+msgid "all"
+msgstr ""
+
+msgid "all branches"
+msgstr ""
+
+msgid "all default branches"
+msgstr ""
+
+msgid "all protected branches"
+msgstr ""
+
+msgid "allowed to fail"
+msgstr ""
+
+msgid "already assigned to an epic"
+msgstr ""
+
+msgid "already banned from namespace"
+msgstr ""
+
+msgid "already being used for another group or project %{timebox_name}."
+msgstr ""
+
+msgid "already being used for another iteration within this cadence."
+msgstr ""
+
+msgid "already has a \"created\" issue link"
+msgstr ""
+
+msgid "already shared with this group"
+msgstr ""
+
+msgid "and"
+msgstr ""
+
+msgid "any-approver for the merge request already exists"
+msgstr ""
+
+msgid "any-approver for the project already exists"
+msgstr ""
+
+msgid "approval"
+msgid_plural "approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "archived"
+msgstr ""
+
+msgid "archived:"
+msgstr ""
+
+msgid "artifacts"
+msgstr ""
+
+msgid "assign yourself"
+msgstr ""
+
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
+msgid "at"
+msgstr ""
+
+msgid "at least the Reporter role"
+msgstr ""
+
+msgid "at least the Reporter role, the author, and assignees"
+msgstr ""
+
+msgid "attach a new file"
+msgstr ""
+
+msgid "authored"
+msgstr ""
+
+msgid "banned user already exists"
+msgstr ""
+
+msgid "before"
+msgstr ""
+
+msgid "beta"
+msgstr ""
+
+msgid "blocks"
+msgstr ""
+
+msgid "branch"
+msgid_plural "branches"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "branch name"
+msgstr ""
+
+msgid "builds"
+msgstr ""
+
+msgid "by"
+msgstr ""
+
+msgid "cURL:"
+msgstr ""
+
+msgid "can contain only digits"
+msgstr ""
+
+msgid "can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'"
+msgstr ""
+
+msgid "can contain only lowercase letters, digits, and '_'."
+msgstr ""
+
+msgid "can not be changed for existing notes"
+msgstr ""
+
+msgid "can not be changed to %{new_type}"
+msgstr ""
+
+msgid "can not be changed when assigned to an epic"
+msgstr ""
+
+msgid "can not be set for template labels"
+msgstr ""
+
+msgid "can not be set for this resource"
+msgstr ""
+
+msgid "can not be set for this type of note"
+msgstr ""
+
+msgid "can not be true if shared runners are enabled"
+msgstr ""
+
+msgid "can only be changed by a group admin."
+msgstr ""
+
+msgid "can only have one escalation policy"
+msgstr ""
+
+msgid "can't be blank"
+msgstr ""
+
+msgid "can't be enabled when delayed group deletion is disabled"
+msgstr ""
+
+msgid "can't be nil"
+msgstr ""
+
+msgid "can't be solely blank"
+msgstr ""
+
+msgid "can't be the same as the source project"
+msgstr ""
+
+msgid "can't include: %{invalid_storages}"
+msgstr ""
+
+msgid "can't reference a branch that does not exist"
+msgstr ""
+
+msgid "cannot assign a linked work item as a parent"
+msgstr ""
+
+msgid "cannot assign a non-confidential work item to a confidential parent. Make the work item confidential and try again."
+msgstr ""
+
+msgid "cannot be a date in the past"
+msgstr ""
+
+msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
+msgstr ""
+
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
+msgid "cannot be blank"
+msgstr ""
+
+msgid "cannot be changed"
+msgstr ""
+
+msgid "cannot be changed if a personal project has container registry tags."
+msgstr ""
+
+msgid "cannot be changed since member is associated with a custom role"
+msgstr ""
+
+msgid "cannot be changed to %{new_type} when linked to a parent %{parent_type}."
+msgstr ""
+
+msgid "cannot be changed to %{new_type} with these child item types."
+msgstr ""
+
+msgid "cannot be enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
+msgid "cannot be enabled unless all domains have TLS certificates"
+msgstr ""
+
+msgid "cannot be enabled until a valid credit card is on file"
+msgstr ""
+
+msgid "cannot be used because it belongs to a compromised private key. Stop using this key and generate a new one."
+msgstr ""
+
+msgid "cannot be used for user namespace"
+msgstr ""
+
+msgid "cannot contain HTML/XML tags, including any word between angle brackets (&lt;,&gt;)."
+msgstr ""
+
+msgid "cannot include leading slash or directory traversal."
+msgstr ""
+
+msgid "cannot merge"
+msgstr ""
+
+msgid "change"
+msgid_plural "changes"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "check"
+msgid_plural "checks"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "checklist item"
+msgid_plural "checklist items"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ci secure files"
+msgstr ""
+
+msgid "ciReport|%{criticalStart}critical%{criticalEnd}, %{highStart}high%{highEnd} and %{otherStart}others%{otherEnd}"
+msgstr ""
+
+msgid "ciReport|%{danger_start}%{degradedNum} degraded%{danger_end}, %{same_start}%{sameNum} same%{same_end}, and %{success_start}%{improvedNum} improved%{success_end}"
+msgstr ""
+
+msgid "ciReport|%{degradedNum} degraded"
+msgstr ""
+
+msgid "ciReport|%{improvedNum} improved"
+msgstr ""
+
+msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
+msgstr ""
+
+msgid "ciReport|%{prefix} %{strong_start}%{score}%{strong_end} %{delta} %{deltaPercent} in %{path}"
+msgstr ""
+
+msgid "ciReport|%{remainingPackagesCount} more"
+msgstr ""
+
+msgid "ciReport|%{sameNum} same"
+msgstr ""
+
+msgid "ciReport|%{scanner} detected %{atleastStart}at least%{atleastEnd} %{number} new potential %{vulnStr}"
+msgstr ""
+
+msgid "ciReport|%{scanner} detected %{number} new potential %{vulnStr}"
+msgstr ""
+
+msgid "ciReport|%{scanner} detected %{strong_start}%{number}%{strong_end} new potential %{vulnStr}"
+msgstr ""
+
+msgid "ciReport|%{scanner} detected no new %{vulnStr}"
+msgstr ""
+
+msgid "ciReport|%{scanner} detected no new potential vulnerabilities"
+msgstr ""
+
+msgid "ciReport|%{scanner}: Loading resulted in an error"
+msgstr ""
+
+msgid "ciReport|API Fuzzing"
+msgstr ""
+
+msgid "ciReport|API fuzzing"
+msgstr ""
+
+msgid "ciReport|All tools"
+msgstr ""
+
+msgid "ciReport|Analyze a deployed version of your web application for known vulnerabilities by examining it from the outside in. DAST works by simulating external attacks on your application while it is running."
+msgstr ""
+
+msgid "ciReport|Automatically apply the patch in a new branch"
+msgstr ""
+
+msgid "ciReport|Base pipeline codequality artifact not found"
+msgstr ""
+
+msgid "ciReport|Browser Performance"
+msgstr ""
+
+msgid "ciReport|Browser performance test metrics results are being parsed"
+msgstr ""
+
+msgid "ciReport|Browser performance test metrics: "
+msgstr ""
+
+msgid "ciReport|Browser performance test metrics: %{strong_start}%{changesFound}%{strong_end} change"
+msgid_plural "ciReport|Browser performance test metrics: %{strong_start}%{changesFound}%{strong_end} changes"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ciReport|Browser performance test metrics: No changes"
+msgstr ""
+
+msgid "ciReport|Checks"
+msgstr ""
+
+msgid "ciReport|Cluster Image Scanning"
+msgstr ""
+
+msgid "ciReport|Code Quality"
+msgstr ""
+
+msgid "ciReport|Code Quality failed to load results"
+msgstr ""
+
+msgid "ciReport|Code Quality hasn't changed."
+msgstr ""
+
+msgid "ciReport|Code Quality is loading"
+msgstr ""
+
+msgid "ciReport|Code quality degraded due to 1 new issue"
+msgid_plural "ciReport|Code quality degraded due to %d new issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ciReport|Code quality improved due to 1 resolved issue"
+msgid_plural "ciReport|Code quality improved due to %d resolved issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ciReport|Code quality scanning detected %{issueCount} changes in merged results"
+msgstr ""
+
+msgid "ciReport|Container Scanning"
+msgstr ""
+
+msgid "ciReport|Container scanning"
+msgstr ""
+
+msgid "ciReport|Container scanning detects known vulnerabilities in your docker images."
+msgstr ""
+
+msgid "ciReport|Coverage Fuzzing"
+msgstr ""
+
+msgid "ciReport|Coverage fuzzing"
+msgstr ""
+
+msgid "ciReport|Create Jira issue"
+msgstr ""
+
+msgid "ciReport|Create a merge request to implement this solution, or download and apply the patch manually."
+msgstr ""
+
+msgid "ciReport|Create issue"
+msgstr ""
+
+msgid "ciReport|DAST"
+msgstr ""
+
+msgid "ciReport|Dependency Scanning"
+msgstr ""
+
+msgid "ciReport|Dependency scanning"
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Download patch to resolve"
+msgstr ""
+
+msgid "ciReport|Download the patch to apply it manually"
+msgstr ""
+
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
+msgid "ciReport|Failed to load %{reportName} report"
+msgstr ""
+
+msgid "ciReport|Failed to load Code Quality report"
+msgstr ""
+
+msgid "ciReport|Fixed"
+msgstr ""
+
+msgid "ciReport|Fixed:"
+msgstr ""
+
+msgid "ciReport|Found %{issuesWithCount}"
+msgstr ""
+
+msgid "ciReport|Full report"
+msgstr ""
+
+msgid "ciReport|Generic Report"
+msgstr ""
+
+msgid "ciReport|Investigate this vulnerability by creating an issue"
+msgstr ""
+
+msgid "ciReport|License Compliance"
+msgstr ""
+
+msgid "ciReport|License Compliance failed loading results"
+msgstr ""
+
+msgid "ciReport|License Compliance test metrics results are being parsed"
+msgstr ""
+
+msgid "ciReport|Load Performance"
+msgstr ""
+
+msgid "ciReport|Load performance test metrics detected %{strong_start}%{changesFound}%{strong_end} change"
+msgid_plural "ciReport|Load performance test metrics detected %{strong_start}%{changesFound}%{strong_end} changes"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ciReport|Load performance test metrics results are being parsed"
+msgstr ""
+
+msgid "ciReport|Load performance test metrics: "
+msgstr ""
+
+msgid "ciReport|Load performance test metrics: No changes"
+msgstr ""
+
+msgid "ciReport|Loading %{reportName} report"
+msgstr ""
+
+msgid "ciReport|Loading Code Quality report"
+msgstr ""
+
+msgid "ciReport|Manage licenses"
+msgstr ""
+
+msgid "ciReport|Manually added"
+msgstr ""
+
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
+msgid "ciReport|No changes to code quality"
+msgstr ""
+
+msgid "ciReport|No code quality issues found"
+msgstr ""
+
+msgid "ciReport|RPS"
+msgstr ""
+
+msgid "ciReport|Resolve with merge request"
+msgstr ""
+
+msgid "ciReport|SAST"
+msgstr ""
+
+msgid "ciReport|SAST IaC"
+msgstr ""
+
+msgid "ciReport|Secret Detection"
+msgstr ""
+
+msgid "ciReport|Secret detection"
+msgstr ""
+
+msgid "ciReport|Security reports failed loading results"
+msgstr ""
+
+msgid "ciReport|Security scan results"
+msgstr ""
+
+msgid "ciReport|Security scanning"
+msgstr ""
+
+msgid "ciReport|Security scanning is loading"
+msgstr ""
+
+msgid "ciReport|Showing %{fetchedItems} of %{totalItems} items"
+msgstr ""
+
+msgid "ciReport|Solution"
+msgstr ""
+
+msgid "ciReport|Something went wrong while fetching the finding. Please try again later."
+msgstr ""
+
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
+msgid "ciReport|TTFB P90"
+msgstr ""
+
+msgid "ciReport|TTFB P95"
+msgstr ""
+
+msgid "ciReport|There was an error creating the issue. Please try again."
+msgstr ""
+
+msgid "ciReport|There was an error creating the merge request. Please try again."
+msgstr ""
+
+msgid "ciReport|There was an error dismissing the vulnerability. Please try again."
+msgstr ""
+
+msgid "ciReport|There was an error dismissing the vulnerability: %{error}"
+msgstr ""
+
+msgid "ciReport|There was an error fetching the codequality report."
+msgstr ""
+
+msgid "ciReport|There was an error reverting the dismissal. Please try again."
+msgstr ""
+
+msgid "ciReport|There was an error reverting the dismissal: %{error}"
+msgstr ""
+
+msgid "ciReport|This report contains all Code Quality issues in the source branch."
+msgstr ""
+
+msgid "ciReport|Used by %{packagesString}"
+msgid_plural "ciReport|Used by %{packagesString}, and %{lastPackage}"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ciReport|View full report"
+msgstr ""
+
+msgid "ciReport|in"
+msgstr ""
+
+msgid "closed"
+msgstr ""
+
+msgid "closed %{timeago}"
+msgstr ""
+
+msgid "closed issue"
+msgid_plural "closed issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "comment"
+msgstr ""
+
+msgid "commented"
+msgstr ""
+
+msgid "commented on %{link_to_project}"
+msgstr ""
+
+msgid "commit"
+msgid_plural "commits"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "commit %{commit_id}"
+msgstr ""
+
+msgid "committed"
+msgstr ""
+
+msgid "complete"
+msgstr ""
+
+msgid "compliance violation has already been recorded"
+msgstr ""
+
+msgid "contacts can only be added to root groups"
+msgstr ""
+
+msgid "container registry images"
+msgstr ""
+
+msgid "contains URLs that exceed the %{limit} character limit"
+msgstr ""
+
+msgid "contains URLs that exceed the 1024 character limit (%{urls})"
+msgstr ""
+
+msgid "contains invalid URLs (%{urls})"
+msgstr ""
+
+msgid "contribute to this project."
+msgstr ""
+
+msgid "could not read private key, is the passphrase correct?"
+msgstr ""
+
+msgid "created"
+msgstr ""
+
+msgid "created %{issuable_created} by %{author}"
+msgstr ""
+
+msgid "created %{timeAgoString} by %{email} via %{user}"
+msgstr ""
+
+msgid "created %{timeAgo}"
+msgstr ""
+
+msgid "created %{timeAgo} by %{author}"
+msgstr ""
+
+msgid "created %{timeAgo} by %{author} in %{project_link}"
+msgstr ""
+
+msgid "created %{timeAgo} by %{email} via %{author}"
+msgstr ""
+
+msgid "created by"
+msgstr ""
+
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
+msgid "daily"
+msgstr ""
+
+msgid "data"
+msgstr ""
+
+msgid "database"
+msgstr ""
+
+msgid "date must not be after 9999-12-31"
+msgstr ""
+
+msgid "day"
+msgid_plural "days"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "days"
+msgstr ""
+
+msgid "default"
+msgstr ""
+
+msgid "default branch"
+msgstr ""
+
+msgid "deleted"
+msgstr ""
+
+msgid "denied"
+msgstr ""
+
+msgid "deploy"
+msgstr ""
+
+msgid "design"
+msgstr ""
+
+msgid "disabled"
+msgstr ""
+
+msgid "does not exist"
+msgstr ""
+
+msgid "does not have a supported extension. Only %{extension_list} are supported"
+msgstr ""
+
+msgid "does not match dast_site.project"
+msgstr ""
+
+msgid "does not match dast_site_validation.project"
+msgstr ""
+
+msgid "download it"
+msgstr ""
+
+msgid "draft"
+msgid_plural "drafts"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "e.g. %{token}"
+msgstr ""
+
+msgid "eg party_tanuki"
+msgstr ""
+
+msgid "eg. dev/*"
+msgstr ""
+
+msgid "element is not a hierarchy"
+msgstr ""
+
+msgid "eligible users"
+msgstr ""
+
+msgid "email address settings"
+msgstr ""
+
+msgid "enabled"
+msgstr ""
+
+msgid "encrypted: needs to be a :required, :optional or :migrating!"
+msgstr ""
+
+msgid "ending with a reserved file extension is not allowed."
+msgstr ""
+
+msgid "entries cannot be larger than 255 characters"
+msgstr ""
+
+msgid "entries cannot be nil"
+msgstr ""
+
+msgid "entries cannot contain HTML tags"
+msgstr ""
+
+msgid "epic"
+msgstr ""
+
+msgid "error"
+msgstr ""
+
+msgid "estimateCommand|%{slash_command} overwrites the total estimated time."
+msgstr ""
+
+msgid "example.com"
+msgstr ""
+
+msgid "exceeds maximum length (100 user ids)"
+msgstr ""
+
+msgid "exceeds maximum length (100 usernames)"
+msgstr ""
+
+msgid "exceeds the limit of %{bytes} bytes"
+msgstr ""
+
+msgid "exceeds the limit of %{bytes} bytes for directory name \"%{dirname}\""
+msgstr ""
+
+msgid "exceeds the limit of %{count} links"
+msgstr ""
+
+msgid "expired on %{timebox_due_date}"
+msgstr ""
+
+msgid "expires on %{timebox_due_date}"
+msgstr ""
+
+msgid "external link"
+msgstr ""
+
+msgid "failed"
+msgstr ""
+
+msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
+msgstr ""
+
+msgid "failed to dismiss security finding: %{message}"
+msgstr ""
+
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
+msgid "failed to revoke token"
+msgstr ""
+
+msgid "file"
+msgid_plural "files"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "finding is not found or is already attached to a vulnerability"
+msgstr ""
+
+msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
+msgstr ""
+
+msgid "for this project"
+msgstr ""
+
+msgid "fork"
+msgstr ""
+
+msgid "from"
+msgstr ""
+
+msgid "from %d job"
+msgid_plural "from %d jobs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "from yourself"
+msgstr ""
+
+msgid "frontmatter"
+msgstr ""
+
+msgid "group"
+msgstr ""
+
+msgid "group access token"
+msgstr ""
+
+msgid "group access tokens"
+msgstr ""
+
+msgid "group members"
+msgstr ""
+
+msgid "groups"
+msgstr ""
+
+msgid "had %{count} failed job"
+msgid_plural "had %{count} failed jobs"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "has already been linked to another vulnerability"
+msgstr ""
+
+msgid "has already been taken"
+msgstr ""
+
+msgid "has already been taken as Codename"
+msgstr ""
+
+msgid "has already been taken as Suite"
+msgstr ""
+
+msgid "has been completed."
+msgstr ""
+
+msgid "has too deep level of nesting"
+msgstr ""
+
+msgid "help"
+msgstr ""
+
+msgid "hours"
+msgstr ""
+
+msgid "http:"
+msgstr ""
+
+msgid "http://www.example.com"
+msgstr ""
+
+msgid "https://bamboo.example.com"
+msgstr ""
+
+msgid "https://your-bitbucket-server"
+msgstr ""
+
+msgid "i18n|%{language} (%{percent_translated}%% translated)"
+msgstr ""
+
+msgid "if"
+msgstr ""
+
+msgid "image diff"
+msgstr ""
+
+msgid "impersonation token"
+msgstr ""
+
+msgid "impersonation tokens"
+msgstr ""
+
+msgid "import flow"
+msgstr ""
+
+msgid "in"
+msgstr ""
+
+msgid "in %{duration} and was queued for %{queued_duration}"
+msgstr ""
+
+msgid "in %{duration}, using %{compute_minutes} compute minutes, and was queued for %{queued_duration}"
+msgstr ""
+
+msgid "in group %{link_to_group}"
+msgstr ""
+
+msgid "in project %{link_to_project}"
+msgstr ""
+
+msgid "incident"
+msgstr ""
+
+msgid "instance completed"
+msgid_plural "instances completed"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "internal note"
+msgstr ""
+
+msgid "invalid milestone state `%{state}`"
+msgstr ""
+
+msgid "invalidated"
+msgstr ""
+
+msgid "is"
+msgstr ""
+
+msgid "is a parent or child of this %{item}"
+msgstr ""
+
+msgid "is already associated to a GitLab Issue. New issue will not be associated."
+msgstr ""
+
+msgid "is already linked to this vulnerability"
+msgstr ""
+
+msgid "is already present in ancestors"
+msgstr ""
+
+msgid "is an invalid IP address range"
+msgstr ""
+
+msgid "is blocked by"
+msgstr ""
+
+msgid "is currently immutable, and cannot be updated. Create a new agent instead."
+msgstr ""
+
+msgid "is forbidden by a top-level group"
+msgstr ""
+
+msgid "is invalid because there is downstream lock"
+msgstr ""
+
+msgid "is invalid because there is upstream lock"
+msgstr ""
+
+msgid "is not"
+msgstr ""
+
+msgid "is not a descendant of the Group owning the template"
+msgstr ""
+
+msgid "is not a valid X509 certificate."
+msgstr ""
+
+msgid "is not allowed for sign-up. Please use your regular email address."
+msgstr ""
+
+msgid "is not allowed for this group."
+msgstr ""
+
+msgid "is not allowed for this project."
+msgstr ""
+
+msgid "is not allowed since the group is not top-level group."
+msgstr ""
+
+msgid "is not allowed to add this type of parent"
+msgstr ""
+
+msgid "is not allowed to point to itself"
+msgstr ""
+
+msgid "is not allowed. Please use your regular email address."
+msgstr ""
+
+msgid "is not in the group enforcing Group Managed Account"
+msgstr ""
+
+msgid "is not in the member group"
+msgstr ""
+
+msgid "is not one of"
+msgstr ""
+
+msgid "is not the member project"
+msgstr ""
+
+msgid "is not valid. The iteration group has to match the iteration cadence group."
+msgstr ""
+
+msgid "is not verified."
+msgstr ""
+
+msgid "is one of"
+msgstr ""
+
+msgid "is read-only"
+msgstr ""
+
+msgid "is too long (%{current_value}). The maximum size is %{max_size}."
+msgstr ""
+
+msgid "is too long (%{size}). The maximum size is %{max_size}."
+msgstr ""
+
+msgid "is too long (maximum is %{count} characters)"
+msgstr ""
+
+msgid "is too long (maximum is 100 entries)"
+msgstr ""
+
+msgid "is too long (maximum is 1000 entries)"
+msgstr ""
+
+msgid "issue"
+msgid_plural "issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "issues at risk"
+msgstr ""
+
+msgid "issues need attention"
+msgstr ""
+
+msgid "issues on track"
+msgstr ""
+
+msgid "it is larger than %{limit}"
+msgstr ""
+
+msgid "it is stored as a job artifact"
+msgstr ""
+
+msgid "it is stored externally"
+msgstr ""
+
+msgid "it is stored in LFS"
+msgstr ""
+
+msgid "it is too large"
+msgstr ""
+
+msgid "jigsaw is not defined"
+msgstr ""
+
+msgid "key result"
+msgstr ""
+
+msgid "kuromoji custom analyzer"
+msgstr ""
+
+msgid "last commit:"
+msgstr ""
+
+msgid "latest"
+msgstr ""
+
+msgid "latest deployment"
+msgstr ""
+
+msgid "latest version"
+msgstr ""
+
+msgid "leave %{group_name}"
+msgstr ""
+
+msgid "less than a minute"
+msgstr ""
+
+msgid "level: %{level}"
+msgstr ""
+
+msgid "lfs objects"
+msgstr ""
+
+msgid "limit of %{project_limit} reached"
+msgstr ""
+
+msgid "line"
+msgid_plural "lines"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "load it anyway"
+msgstr ""
+
+msgid "loading"
+msgstr ""
+
+msgid "locked by %{path_lock_user_name} %{created_at}"
+msgstr ""
+
+msgid "manual"
+msgstr ""
+
+msgid "math|Displaying this math block may cause performance issues on this page."
+msgstr ""
+
+msgid "math|There was an error rendering this math block. %{katexMessage}"
+msgstr ""
+
+msgid "math|This math block exceeds %{maxMathChars} characters, and may cause performance issues on this page."
+msgstr ""
+
+msgid "math|Too many expansions. Consider using multiple math blocks."
+msgstr ""
+
+msgid "member"
+msgid_plural "members"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "merge request"
+msgid_plural "merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "mergedCommitsAdded| (commits were squashed)"
+msgstr ""
+
+msgid "milestone"
+msgstr ""
+
+msgid "milestone should belong either to a project or a group."
+msgstr ""
+
+msgid "missing"
+msgstr ""
+
+msgid "months"
+msgstr ""
+
+msgid "most recent deployment"
+msgstr ""
+
+msgid "mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}%{squashedCommits}."
+msgstr ""
+
+msgid "mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}."
+msgstr ""
+
+msgid "mrWidgetCommitsAdded|%{strongStart}1%{strongEnd} merge commit"
+msgstr ""
+
+msgid "mrWidgetCommitsAdded|Changes merged into %{targetBranch} with %{mergeCommitSha}%{squashedCommits}."
+msgstr ""
+
+msgid "mrWidgetCommitsAdded|The changes were not merged into %{targetBranch}."
+msgstr ""
+
+msgid "mrWidgetNothingToMerge|Merge request contains no changes"
+msgstr ""
+
+msgid "mrWidgetNothingToMerge|Use merge requests to propose changes to your project and discuss them with your team. To make changes, use the %{boldStart}Code%{boldEnd} dropdown list above, then test them with %{linkStart}CI/CD%{linkEnd} before merging."
+msgstr ""
+
+msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Select %{boldStart}Mark as ready%{boldEnd} to remove it from Draft status."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Users who can write to the source or target branches can resolve the conflicts."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} a Jira issue key must be mentioned in the title or description."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all required approvals must be given."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all status checks must pass."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} all threads must be resolved."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} denied licenses must be removed."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} fast-forward merge is not possible. To merge this request, first rebase locally."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} merge conflicts must be resolved."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} new changes were just added."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} pipeline must succeed. It's waiting for a manual action to continue."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} pipeline must succeed. Push a commit that fixes the failure or %{linkStart}learn about other solutions.%{linkEnd}"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} the source branch must be rebased onto the target branch."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} you can only merge after the above items are resolved."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge unavailable:%{boldEnd} merge requests are read-only in a secondary Geo node."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merge unavailable:%{boldEnd} merge requests are read-only on archived projects."
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Changes are being shipped…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Changes will land soon…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Drum roll, please…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Everything's good…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Lift-off in 5… 4… 3…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} Take a deep breath and relax…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} The changes are leaving the station…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} This is going to be great…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Merging!%{boldEnd} We're almost there…"
+msgstr ""
+
+msgid "mrWidget|%{boldStart}Ready to be merged automatically.%{boldEnd} Ask someone with write access to this repository to merge this request."
+msgstr ""
+
+msgid "mrWidget|%{dangerStart}%{rules} rule can't be approved%{dangerEnd}"
+msgstr ""
+
+msgid "mrWidget|%{dangerStart}%{rules} rules can't be approved%{dangerEnd}"
+msgstr ""
+
+msgid "mrWidget|%{mergeError}."
+msgstr ""
+
+msgid "mrWidget|%{mergeError}. Try again."
+msgstr ""
+
+msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} decreased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB"
+msgstr ""
+
+msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} increased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB"
+msgstr ""
+
+msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rule has been approved automatically"
+msgstr ""
+
+msgid "mrWidget|%{rules} invalid rules have been approved automatically"
+msgstr ""
+
+msgid "mrWidget|A new merge train has started and this merge request is the first of the queue."
+msgstr ""
+
+msgid "mrWidget|Added to the merge train by %{merge_author}"
+msgstr ""
+
+msgid "mrWidget|Added to the merge train. There are %{mergeTrainPosition} merge requests waiting to be merged"
+msgstr ""
+
+msgid "mrWidget|An error occurred while removing your approval."
+msgstr ""
+
+msgid "mrWidget|An error occurred while retrieving approval data for this merge request."
+msgstr ""
+
+msgid "mrWidget|An error occurred while submitting your approval."
+msgstr ""
+
+msgid "mrWidget|Approval is optional"
+msgstr ""
+
+msgid "mrWidget|Approval password is invalid."
+msgstr ""
+
+msgid "mrWidget|Approve"
+msgstr ""
+
+msgid "mrWidget|Approve additionally"
+msgstr ""
+
+msgid "mrWidget|Approved by"
+msgstr ""
+
+msgid "mrWidget|Approved by you"
+msgstr ""
+
+msgid "mrWidget|Approved by you and others"
+msgstr ""
+
+msgid "mrWidget|Are you sure you want to rebase?"
+msgstr ""
+
+msgid "mrWidget|Assign yourself to these issues"
+msgstr ""
+
+msgid "mrWidget|Assign yourself to this issue"
+msgstr ""
+
+msgid "mrWidget|Cancel auto-merge"
+msgstr ""
+
+msgid "mrWidget|Checking if merge request can be merged…"
+msgstr ""
+
+msgid "mrWidget|Cherry-pick"
+msgstr ""
+
+msgid "mrWidget|Cherry-pick this merge request in a new merge request"
+msgstr ""
+
+msgid "mrWidget|Closed"
+msgstr ""
+
+msgid "mrWidget|Closed by"
+msgstr ""
+
+msgid "mrWidget|Closes issue"
+msgid_plural "mrWidget|Closes issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "mrWidget|Delete source branch"
+msgstr ""
+
+msgid "mrWidget|Deployment statistics are not available currently"
+msgstr ""
+
+msgid "mrWidget|Did not close"
+msgstr ""
+
+msgid "mrWidget|Failed to load deployment statistics"
+msgstr ""
+
+msgid "mrWidget|GitLab %{linkStart}CI/CD can automatically build, test, and deploy your application.%{linkEnd} It only takes a few minutes to get started, and we can help you create a pipeline configuration file."
+msgstr ""
+
+msgid "mrWidget|Go to first unresolved thread"
+msgstr ""
+
+msgid "mrWidget|Hide %{widget} details"
+msgstr ""
+
+msgid "mrWidget|If the %{type} branch exists in your local repository, you can merge this merge request manually using the command line."
+msgstr ""
+
+msgid "mrWidget|If the last pipeline ran in the fork project, it may be inaccurate. Before merge, we advise running a pipeline in this project."
+msgstr ""
+
+msgid "mrWidget|Loading deployment statistics"
+msgstr ""
+
+msgid "mrWidget|Mark as ready"
+msgstr ""
+
+msgid "mrWidget|Members who can merge are allowed to add commits."
+msgstr ""
+
+msgid "mrWidget|Mentions issue"
+msgid_plural "mrWidget|Mentions issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "mrWidget|Merge blocked: all required approvals must be given."
+msgstr ""
+
+msgid "mrWidget|Merge failed."
+msgstr ""
+
+msgid "mrWidget|Merged by"
+msgstr ""
+
+msgid "mrWidget|Please restore it or use a different %{type} branch."
+msgstr ""
+
+msgid "mrWidget|Rebase"
+msgstr ""
+
+msgid "mrWidget|Rebase in progress"
+msgstr ""
+
+msgid "mrWidget|Rebase without pipeline"
+msgstr ""
+
+msgid "mrWidget|Refresh"
+msgstr ""
+
+msgid "mrWidget|Refresh now"
+msgstr ""
+
+msgid "mrWidget|Refreshing now"
+msgstr ""
+
+msgid "mrWidget|Remove from merge train"
+msgstr ""
+
+msgid "mrWidget|Resolve conflicts"
+msgstr ""
+
+msgid "mrWidget|Resolve locally"
+msgstr ""
+
+msgid "mrWidget|Revert"
+msgstr ""
+
+msgid "mrWidget|Revert this merge request in a new merge request"
+msgstr ""
+
+msgid "mrWidget|Revoke approval"
+msgstr ""
+
+msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
+msgstr ""
+
+msgid "mrWidget|Set by %{merge_author} to be merged automatically when all merge checks pass"
+msgstr ""
+
+msgid "mrWidget|Set by %{merge_author} to be merged automatically when the pipeline succeeds"
+msgstr ""
+
+msgid "mrWidget|Set by %{merge_author} to start a merge train when the pipeline succeeds"
+msgstr ""
+
+msgid "mrWidget|Show %{widget} details"
+msgstr ""
+
+msgid "mrWidget|The %{type} branch %{codeStart}%{name}%{codeEnd} does not exist."
+msgstr ""
+
+msgid "mrWidget|The source branch is %{link} the target branch"
+msgstr ""
+
+msgid "mrWidget|This merge request failed to be merged automatically"
+msgstr ""
+
+msgid "mrWidget|To approve this merge request, please enter your password. This project requires all approvals to be authenticated."
+msgstr ""
+
+msgid "mrWidget|To change these default messages, edit the templates for both the merge and squash commit messages. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "mrWidget|To change this default message, edit the template for merge commit messages. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "mrWidget|Your merge request is almost ready!"
+msgstr ""
+
+msgid "mrWidget|Your password"
+msgstr ""
+
+msgid "must be a Debian package"
+msgstr ""
+
+msgid "must be a boolean value"
+msgstr ""
+
+msgid "must be a root group."
+msgstr ""
+
+msgid "must be a root namespace"
+msgstr ""
+
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
+msgid "must be a valid json schema"
+msgstr ""
+
+msgid "must be a valid syntax highlighting theme ID"
+msgstr ""
+
+msgid "must be a value between 0 and 1"
+msgstr ""
+
+msgid "must be after start"
+msgstr ""
+
+msgid "must be an email you have verified"
+msgstr ""
+
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
+msgid "must be at least 1 day"
+msgstr ""
+
+msgid "must be before %{expiry_date}"
+msgstr ""
+
+msgid "must be false when email confirmation setting is off"
+msgstr ""
+
+msgid "must be greater than start date"
+msgstr ""
+
+msgid "must be in ISO 8601 format"
+msgstr ""
+
+msgid "must be in same hierarchy as custom role's namespace"
+msgstr ""
+
+msgid "must be inside the fork network"
+msgstr ""
+
+msgid "must be less than the limit of %{tag_limit} tags"
+msgstr ""
+
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
+msgid "must be set for a project namespace"
+msgstr ""
+
+msgid "must be specified"
+msgstr ""
+
+msgid "must be unique by status and elapsed time within a policy"
+msgstr ""
+
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
+msgid "must belong to same project of its requirement object."
+msgstr ""
+
+msgid "must belong to same project of the work item."
+msgstr ""
+
+msgid "must contain only a discord user ID."
+msgstr ""
+
+msgid "must have a repository"
+msgstr ""
+
+msgid "must have a valid format and be greater than or equal to zero."
+msgstr ""
+
+msgid "must match %{association}.project_id"
+msgstr ""
+
+msgid "must match one of the following file types: %{extension_list}"
+msgstr ""
+
+msgid "must not be an owner of the namespace"
+msgstr ""
+
+msgid "must not contain commonly used combinations of words and letters"
+msgstr ""
+
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
+msgid "my-awesome-group"
+msgstr ""
+
+msgid "my-channel"
+msgstr ""
+
+msgid "my-topic"
+msgstr ""
+
+msgid "needs to be between 10 minutes and 1 month"
+msgstr ""
+
+msgid "never"
+msgstr ""
+
+msgid "never expires"
+msgstr ""
+
+msgid "new merge request"
+msgstr ""
+
+msgid "no expiration"
+msgstr ""
+
+msgid "no name set"
+msgstr ""
+
+msgid "no one can merge"
+msgstr ""
+
+msgid "no scopes selected"
+msgstr ""
+
+msgid "none"
+msgstr ""
+
+msgid "not authorized to create member"
+msgstr ""
+
+msgid "not authorized to update member"
+msgstr ""
+
+msgid "not found"
+msgstr ""
+
+msgid "nounSeries|%{firstItem} and %{lastItem}"
+msgstr ""
+
+msgid "nounSeries|%{item}"
+msgstr ""
+
+msgid "nounSeries|%{item}, %{nextItem}"
+msgstr ""
+
+msgid "nounSeries|%{item}, and %{lastItem}"
+msgstr ""
+
+msgid "objective"
+msgstr ""
+
+msgid "on or after"
+msgstr ""
+
+msgid "only available on top-level groups."
+msgstr ""
+
+msgid "only supports valid HTTP(S) URLs"
+msgstr ""
+
+msgid "open issue"
+msgid_plural "open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "or"
+msgstr ""
+
+msgid "organizations can only be added to root groups"
+msgstr ""
+
+msgid "packages"
+msgstr ""
+
+msgid "pages"
+msgstr ""
+
+msgid "params is empty"
+msgstr ""
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "parent already has maximum number of children."
+msgstr ""
+
+msgid "parent must be in the same project as child."
+msgstr ""
+
+msgid "password"
+msgstr ""
+
+msgid "pending comment"
+msgstr ""
+
+msgid "pending deletion"
+msgstr ""
+
+msgid "personal access token"
+msgstr ""
+
+msgid "personal access tokens"
+msgstr ""
+
+msgid "pipeline"
+msgstr ""
+
+msgid "pipeline schedules documentation"
+msgstr ""
+
+msgid "pipelineEditorWalkthrough|Let's do this!"
+msgstr ""
+
+msgid "pipelineEditorWalkthrough|See how GitLab pipelines work"
+msgstr ""
+
+msgid "pipelineEditorWalkthrough|This %{codeStart}.gitlab-ci.yml%{codeEnd} file creates a simple test pipeline."
+msgstr ""
+
+msgid "pipelineEditorWalkthrough|Use the %{boldStart}commit changes%{boldEnd} button at the bottom of the page to run the pipeline."
+msgstr ""
+
+msgid "pipelineEditorWalkthrough|You can use the file tree to view your pipeline configuration files. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "point"
+msgid_plural "points"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "previously merged commits"
+msgstr ""
+
+msgid "private"
+msgstr ""
+
+msgid "private key does not match certificate."
+msgstr ""
+
+msgid "processing"
+msgstr ""
+
+msgid "project"
+msgid_plural "projects"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "project access token"
+msgstr ""
+
+msgid "project access tokens"
+msgstr ""
+
+msgid "project bots cannot be added to other groups / projects"
+msgstr ""
+
+msgid "project is read-only"
+msgstr ""
+
+msgid "project members"
+msgstr ""
+
+msgid "project name"
+msgstr ""
+
+msgid "project namespace cannot be the parent of another namespace"
+msgstr ""
+
+msgid "projects"
+msgstr ""
+
+msgid "random"
+msgstr ""
+
+msgid "reCAPTCHA"
+msgstr ""
+
+msgid "reCAPTCHA helps prevent credential stuffing."
+msgstr ""
+
+msgid "reCAPTCHA private key"
+msgstr ""
+
+msgid "reCAPTCHA site key"
+msgstr ""
+
+msgid "reached maximum depth"
+msgstr ""
+
+msgid "recent activity"
+msgstr ""
+
+msgid "register"
+msgstr ""
+
+msgid "relates to"
+msgstr ""
+
+msgid "remaining"
+msgstr ""
+
+msgid "remove"
+msgstr ""
+
+msgid "remove due date"
+msgstr ""
+
+msgid "remove start date"
+msgstr ""
+
+msgid "remove weight"
+msgstr ""
+
+msgid "removed a %{link_type} link"
+msgstr ""
+
+msgid "removed a Zoom call from this issue"
+msgstr ""
+
+msgid "rendered diff"
+msgstr ""
+
+msgid "reply"
+msgid_plural "replies"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "reply should have same confidentiality as top-level note"
+msgstr ""
+
+msgid "repositories"
+msgstr ""
+
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "repository:"
+msgstr ""
+
+msgid "role's base access level does not match the access level of the membership"
+msgstr ""
+
+msgid "rule"
+msgid_plural "rules"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "running"
+msgstr ""
+
+msgid "satisfied"
+msgstr ""
+
+msgid "scan-execution-policy: policy not applied, %{policy_path} file is invalid"
+msgstr ""
+
+msgid "scan-execution-policy: policy not applied, %{policy_path} file is missing"
+msgstr ""
+
+msgid "seat"
+msgid_plural "seats"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "security Reports|There was an error creating the merge request"
+msgstr ""
+
+msgid "selective_code_owner_removals can only be enabled when retain_approvals_on_push is enabled"
+msgstr ""
+
+msgid "severity|Blocker"
+msgstr ""
+
+msgid "severity|Critical"
+msgstr ""
+
+msgid "severity|High"
+msgstr ""
+
+msgid "severity|Info"
+msgstr ""
+
+msgid "severity|Low"
+msgstr ""
+
+msgid "severity|Major"
+msgstr ""
+
+msgid "severity|Medium"
+msgstr ""
+
+msgid "severity|Minor"
+msgstr ""
+
+msgid "severity|None"
+msgstr ""
+
+msgid "severity|Unknown"
+msgstr ""
+
+msgid "should be an array of %{object_name} objects"
+msgstr ""
+
+msgid "should be an array of existing user ids. %{invalid} does not exist"
+msgstr ""
+
+msgid "should be an array of existing usernames. %{invalid} does not exist"
+msgstr ""
+
+msgid "should be greater than or equal to %{access} inherited membership from group %{group_name}"
+msgstr ""
+
+msgid "show %{count} more"
+msgstr ""
+
+msgid "show fewer"
+msgstr ""
+
+msgid "show less"
+msgstr ""
+
+msgid "sign in"
+msgstr ""
+
+msgid "smartcn custom analyzer"
+msgstr ""
+
+msgid "snippet"
+msgstr ""
+
+msgid "source"
+msgstr ""
+
+msgid "source diff"
+msgstr ""
+
+msgid "specific protected branches"
+msgstr ""
+
+msgid "specified top is not part of the tree"
+msgstr ""
+
+msgid "spendCommand|%{slash_command} adds or subtracts time already spent."
+msgstr ""
+
+msgid "ssh:"
+msgstr ""
+
+msgid "started"
+msgstr ""
+
+msgid "started a discussion on %{design_link}"
+msgstr ""
+
+msgid "started on %{timebox_start_date}"
+msgstr ""
+
+msgid "starts on %{timebox_start_date}"
+msgstr ""
+
+msgid "structure is too large. Maximum size is %{max_size} characters"
+msgstr ""
+
+msgid "stuck"
+msgstr ""
+
+msgid "success"
+msgstr ""
+
+msgid "suggestPipeline|1/2: Choose a template"
+msgstr ""
+
+msgid "suggestPipeline|2/2: Commit your changes"
+msgstr ""
+
+msgid "suggestPipeline|Choose %{boldStart}Code Quality%{boldEnd} to add a pipeline that tests the quality of your code."
+msgstr ""
+
+msgid "suggestPipeline|The template is ready! You can now commit it to create your first pipeline."
+msgstr ""
+
+msgid "suggestPipeline|We’re adding a GitLab CI configuration file to add a pipeline to the project. You could create it manually, but we recommend that you start with a GitLab template that works out of the box."
+msgstr ""
+
+msgid "supported SSH public key."
+msgstr ""
+
+msgid "tag name"
+msgstr ""
+
+msgid "targeting "
+msgstr ""
+
+msgid "task"
+msgstr ""
+
+msgid "terraform states"
+msgstr ""
+
+msgid "test case"
+msgstr ""
+
+msgid "the correct format."
+msgstr ""
+
+msgid "the following epics"
+msgstr ""
+
+msgid "the following incidents or issues"
+msgstr ""
+
+msgid "the following issues"
+msgstr ""
+
+msgid "the wiki"
+msgstr ""
+
+msgid "then"
+msgstr ""
+
+msgid "this document"
+msgstr ""
+
+msgid "time summary"
+msgstr ""
+
+msgid "to yourself"
+msgstr ""
+
+msgid "today"
+msgstr ""
+
+msgid "toggle collapse"
+msgstr ""
+
+msgid "token already revoked"
+msgstr ""
+
+msgid "total must be less than or equal to %{size}"
+msgstr ""
+
+msgid "triggered"
+msgstr ""
+
+msgid "two-factor authentication settings"
+msgstr ""
+
+msgid "type must be Debian"
+msgstr ""
+
+msgid "type parameter is missing and is required"
+msgstr ""
+
+msgid "unicode domains should use IDNA encoding"
+msgstr ""
+
+msgid "updated"
+msgstr ""
+
+msgid "updated %{timeAgo}"
+msgstr ""
+
+msgid "updated %{time_ago}"
+msgstr ""
+
+msgid "uploads"
+msgstr ""
+
+msgid "user"
+msgid_plural "users"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "user avatar"
+msgstr ""
+
+msgid "user namespace cannot be the parent of another namespace"
+msgstr ""
+
+msgid "username"
+msgstr ""
+
+msgid "v%{version} published %{timeAgo}"
+msgstr ""
+
+msgid "value for '%{storage}' must be an integer"
+msgstr ""
+
+msgid "value for '%{storage}' must be between 0 and 100"
+msgstr ""
+
+msgid "verify ownership"
+msgstr ""
+
+msgid "version %{report_version} for report type %{report_type} is deprecated. However, GitLab will still attempt to parse and ingest this report. Upgrade the security report to one of the following versions: %{current_schema_versions}."
+msgstr ""
+
+msgid "version %{versionIndex}"
+msgstr ""
+
+msgid "via"
+msgstr ""
+
+msgid "via %{closed_via}"
+msgstr ""
+
+msgid "via merge request %{link}"
+msgstr ""
+
+msgid "view it on GitLab"
+msgstr ""
+
+msgid "view the blob"
+msgstr ""
+
+msgid "view the source"
+msgstr ""
+
+msgid "visibility"
+msgstr ""
+
+msgid "vulnerability"
+msgid_plural "vulnerabilities"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "vulnerability|Add a comment"
+msgstr ""
+
+msgid "vulnerability|Add a comment or reason for dismissal"
+msgstr ""
+
+msgid "vulnerability|Add comment"
+msgstr ""
+
+msgid "vulnerability|Add comment & dismiss"
+msgstr ""
+
+msgid "vulnerability|Add comment and dismiss"
+msgstr ""
+
+msgid "vulnerability|Dismiss vulnerability"
+msgstr ""
+
+msgid "vulnerability|Save comment"
+msgstr ""
+
+msgid "vulnerability|Undo dismiss"
+msgstr ""
+
+msgid "vulnerability|dismissed"
+msgstr ""
+
+msgid "was set to auto-merge by"
+msgstr ""
+
+msgid "weekly"
+msgstr ""
+
+msgid "wiki page"
+msgstr ""
+
+msgid "with %{additions} additions, %{deletions} deletions."
+msgstr ""
+
+msgid "with expiry changing from %{old_expiry} to %{new_expiry}"
+msgstr ""
+
+msgid "with expiry remaining unchanged at %{old_expiry}"
+msgstr ""
+
+msgid "yaml invalid"
+msgstr ""
+
+msgid "you"
+msgstr ""
+
+msgid "your GitLab instance"
+msgstr ""
+
+msgid "your group (%{group_name})"
+msgstr ""
+
+msgid "yyyy-mm-dd"
+msgstr ""
+
+msgid "{group}"
+msgstr ""
+
+msgid "{project}"
+msgstr ""
+
+msgid "✔"
+msgstr ""
+
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index 95a73dabb17..bcf9a3a32b9 100644
--- a/locale/nl_NL/gitlab.po
+++ b/locale/nl_NL/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: nl\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:00\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr "+ %{count} meer"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} meer"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/or_IN/gitlab.po b/locale/or_IN/gitlab.po
index d0f6af65ed8..d9eb08ea86b 100644
--- a/locale/or_IN/gitlab.po
+++ b/locale/or_IN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: or\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/pa_IN/gitlab.po b/locale/pa_IN/gitlab.po
index adfb2f5f326..9e20c69c1cd 100644
--- a/locale/pa_IN/gitlab.po
+++ b/locale/pa_IN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: pa-IN\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/pa_PK/gitlab.po b/locale/pa_PK/gitlab.po
index d5c0bbafe05..1654b2e0e65 100644
--- a/locale/pa_PK/gitlab.po
+++ b/locale/pa_PK/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: pa-PK\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:37\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index e4abb7eb632..8b834c73f4d 100644
--- a/locale/pl_PL/gitlab.po
+++ b/locale/pl_PL/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: pl\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr " %{start} do %{end}"
@@ -47,6 +47,13 @@ msgstr " i "
msgid " and %{sliced}"
msgstr " i %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr " lub "
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr "%{count} całkowitej wagi"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} nie może zostać znalezione."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} dni do automatycznego usunięcia tagów"
@@ -910,7 +914,7 @@ msgstr "%{edit_in_new_fork_notice} Spróbuj ponownie wysłać plik."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@firma.pl"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -988,6 +992,12 @@ msgstr "%{issuesSize} przy limicie %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Co nowego%{italic_end} jest nieaktywne i nie może zostać wyświetlone."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} problemów, z limitem %{maxIssueCount} problemów."
@@ -1063,6 +1073,9 @@ msgstr "%{labelStart}Zniezmodyfikowana odpowiedź:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} niedostępne"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,11 +1564,11 @@ msgstr "%{verb} %{time_spent_value} wykorzystanego czasu."
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} umożliwia wysyłanie powiadomień do aplikacji internetowych w odpowiedzi na zdarzenia w grupie lub projekcie."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start} %{webhook_type} %{link_end} umożliwia wysyłanie powiadomień do aplikacji sieci web w odpowiedzi na zdarzenia w grupie lub projekcie. Zalecamy użycie %{integrations_link_start}integracji%{link_end} zamiast elementu webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr ""
@@ -1663,6 +1676,9 @@ msgstr "+ %{amount} więcej"
msgid "+ %{count} more"
msgstr "+ %{count} więcej"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} więcej"
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Zaakceptuj zaproszenie"
@@ -2730,6 +2782,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2910,6 +2965,9 @@ msgstr ""
msgid "Action"
msgstr "Akcja"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3222,6 +3280,9 @@ msgstr "Dodaj sugestiÄ™ do zestawu"
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3246,6 +3307,9 @@ msgstr "Dodaj do recenzji"
msgid "Add to tree"
msgstr "Dodaj do drzewa"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3273,7 +3337,7 @@ msgstr "Dodaj/usuń"
msgid "AddMember|Invite email is invalid"
msgstr "Zapraszający e-mail jest nieprawidłowy"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4113,7 +4177,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4737,6 +4801,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5175,9 +5242,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr "Wystąpił błąd podczas aktualizacji tytułu"
@@ -5268,6 +5332,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5455,6 +5522,9 @@ msgstr[3] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5470,6 +5540,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6595,7 +6689,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6750,6 +6844,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6966,6 +7063,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8053,6 +8159,9 @@ msgstr[3] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8065,6 +8174,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8171,9 +8292,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8261,9 +8379,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,7 +9555,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9827,6 +9942,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9979,7 +10100,7 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10435,15 +10559,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10703,6 +10833,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11000,15 +11133,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11301,6 +11428,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11325,6 +11455,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11748,9 +11881,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12383,7 +12513,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12599,15 +12729,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12671,6 +12804,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14429,9 +14616,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16342,6 +16532,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16369,7 +16565,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16384,7 +16580,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16408,6 +16604,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16468,7 +16667,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16486,10 +16685,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16661,6 +16863,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16676,12 +16896,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17963,9 +18180,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18008,6 +18222,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18146,9 +18363,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18398,7 +18609,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18545,12 +18756,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18596,6 +18813,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19737,6 +19972,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21852,6 +22063,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22008,7 +22219,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22128,9 +22348,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22527,6 +22753,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22593,9 +22822,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22971,7 +23197,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23160,7 +23386,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23172,7 +23398,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23190,9 +23416,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23618,6 +23841,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23883,9 +24109,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23925,6 +24148,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24108,6 +24337,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24984,66 +24916,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25867,15 +25765,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26294,18 +26183,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26555,10 +26438,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26567,16 +26462,26 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27458,6 +27369,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27509,6 +27423,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27605,9 +27522,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27973,6 +27884,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28688,6 +28602,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29117,6 +29043,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29129,6 +29058,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29435,6 +29367,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31225,15 +31259,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31252,12 +31289,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31276,6 +31319,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31712,6 +31758,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31736,6 +31785,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,10 +31809,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31814,9 +31872,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33087,6 +33148,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33279,24 +33340,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34012,6 +34109,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34159,7 +34259,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34606,9 +34709,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34723,12 +34823,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35179,6 +35273,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35827,9 +35921,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35941,6 +36032,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36877,9 +36962,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37504,6 +37592,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37576,6 +37667,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38395,6 +38489,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39048,9 +39151,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39581,9 +39657,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40187,9 +40254,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "Wybierz"
-
msgid "Request"
msgstr ""
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42150,13 +42262,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results..."
-msgstr ""
-
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42407,6 +42516,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44095,6 +44333,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46203,6 +46459,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46221,6 +46480,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46898,7 +47163,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47940,9 +48211,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48276,6 +48547,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,10 +49081,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48954,7 +49234,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,7 +49360,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49101,7 +49381,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50966,10 +51273,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51083,13 +51393,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51765,6 +52075,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53333,15 +53661,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53817,9 +54139,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56141,6 +56469,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56229,9 +56560,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57398,6 +57741,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57440,6 +57786,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57488,9 +57837,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 2a158285f65..7ac437bfe90 100644
--- a/locale/pt_BR/gitlab.po
+++ b/locale/pt_BR/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: pt-BR\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr " %{start} até %{end}"
@@ -45,6 +45,11 @@ msgstr " e "
msgid " and %{sliced}"
msgstr " e %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " ou "
@@ -73,7 +78,7 @@ msgid "\"%{repository_name}\" size (%{repository_size}) is larger than the limit
msgstr "\"%{repository_name}\" tamanho (%{repository_size}) é maior que o limite de %{limit}."
msgid "### Rich text editor"
-msgstr ""
+msgstr "Editor de texto com formatação"
msgid "##### ERROR ##### You have used %{usage_percentage} of the storage quota for %{namespace_name} (%{current_size} of %{size_limit}). %{namespace_name} is now read-only. Projects under this namespace are locked and actions will be restricted. To manage storage, or purchase additional storage, see %{manage_storage_url}. To learn more about restricted actions, see %{restricted_actions_url}"
msgstr ""
@@ -670,9 +675,6 @@ msgstr "%{count} marcadores"
msgid "%{count} total weight"
msgstr "%{count} peso total"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} não foi encontrado."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} dias até as tags serem removidas automaticamente"
@@ -718,7 +720,7 @@ msgstr "%{edit_in_new_fork_notice} Tente carregar um arquivo novamente."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@empresa.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr "%{issuesSize} com um limite de %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Novidades%{italic_end} está inativo e não pode ser visto."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} issues com um limite de %{maxIssueCount}"
@@ -871,6 +879,9 @@ msgstr "%{labelStart}Resposta não modificada:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} indisponível"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,11 +1330,11 @@ msgstr "%{verb} %{time_spent_value} tempo gasto."
msgid "%{verb} this %{noun} as a draft."
msgstr "%{verb} este %{noun} como rascunho."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} permitem que você envie notificações para aplicativos da web em resposta a eventos de um grupo ou projeto."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} permitem que você envie notificações para aplicativos da web em resposta a eventos de um grupo ou projeto. Recomendamos usar uma %{integrations_link_start}integração%{link_end} em vez de um webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr "Opções do %{widget}"
@@ -1429,6 +1440,9 @@ msgstr "+ %{amount} mais"
msgid "+ %{count} more"
msgstr "+ %{count} mais"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "%{moreCount} mais"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr "As explicações geradas por IA aparecerão aqui."
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr "Faça uma pergunta"
msgid "AI|Autocomplete"
msgstr "Autocompletar"
+msgid "AI|Can be removed at any time"
+msgstr "Pode ser removido a qualquer momento"
+
msgid "AI|Close the Code Explanation"
msgstr "Fechar Explicação do código"
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr "Não tem suporte e pode não estar documentado"
+
msgid "AI|Helpful"
msgstr "Útil"
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr "Não vejo como posso ajudar. Por favor, dê instruções melhores!"
+msgid "AI|May be unstable"
+msgstr "Pode ser instável"
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr "Pode fornecer respostas inadequadas que não representam as opiniões do GitLab. Não insira dados pessoais."
@@ -1973,6 +2014,9 @@ msgstr "Enviar mensagem de bate-papo"
msgid "AI|Something went wrong. Please try again later"
msgstr "Algo deu errado. Por favor, tente novamente mais tarde"
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr "O elemento container não foi encontrado, parando o AI Genie."
@@ -1988,6 +2032,9 @@ msgstr "Esses recursos podem causar problemas de desempenho e estabilidade e pod
msgid "AI|Third-party AI services"
msgstr "Serviços de IA de terceiros"
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr "Inútil"
@@ -2000,6 +2047,9 @@ msgstr "Usar serviços IA de terceiros"
msgid "AI|What does the selected code mean?"
msgstr "O que significa o código selecionado?"
+msgid "AI|What's an Experiment?"
+msgstr "O que é um experimento?"
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr "Escreva uma breve descrição e faça com que a IA preencha os detalhes."
@@ -2012,9 +2062,6 @@ msgstr "Errado"
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr "Você não tem permissão para copiar qualquer parte desta saída em problemas, comentários, código-fonte do GitLab, mensagens de confirmação, solicitações de mesclagem ou qualquer outra interface de usuário nos grupos %{gitlabOrg} ou %{gitlabCom}."
-msgid "AI|You can ask AI for more information."
-msgstr "Você pode pedir mais informações para a AI."
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr "Nenhum relatório encontrado"
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr "Relatórios de abuso"
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr "Relatórios de abuso anteriores"
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr "Verificação"
msgid "AbuseReport|View screenshot"
msgstr "Ver captura de tela"
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Aceitar convite"
@@ -2444,6 +2494,9 @@ msgstr "Grupos"
msgid "AccessDropdown|Roles"
msgstr "Cargos"
+msgid "AccessDropdown|Select"
+msgstr "Selecionar"
+
msgid "AccessDropdown|Users"
msgstr "Usuários"
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr "Ação"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr "A ação '%{action}' no registro de entrada %{registry_id} não é suportada"
@@ -2658,10 +2714,10 @@ msgid "Active personal access tokens"
msgstr ""
msgid "Active pipeline trigger tokens"
-msgstr ""
+msgstr "Tokens de gatilho de pipeline ativo"
msgid "Active project access tokens"
-msgstr ""
+msgstr "Tokens de acesso a projeto ativos"
msgid "Activity"
msgstr "Atividade"
@@ -2868,7 +2924,7 @@ msgid "Add list"
msgstr "Adicionar lista"
msgid "Add new"
-msgstr ""
+msgstr "Adicionar novo"
msgid "Add new application"
msgstr "Adicionar novo aplicativo"
@@ -2883,19 +2939,19 @@ msgid "Add new emoji"
msgstr "Adicionar novo emoji"
msgid "Add new key"
-msgstr ""
+msgstr "Adicionar nova chave"
msgid "Add new pipeline subscription"
-msgstr ""
+msgstr "Adicionar nova assinatura de pipeline"
msgid "Add new pipeline trigger token"
-msgstr ""
+msgstr "Adicionar novo token de gatilho de pipeline"
msgid "Add new token"
-msgstr ""
+msgstr "Adicionar novo token"
msgid "Add new webhook"
-msgstr ""
+msgstr "Adicionar novo webhook"
msgid "Add or remove a user."
msgstr "Adicionar ou remover um usuário."
@@ -2934,6 +2990,9 @@ msgid "Add suggestion to batch"
msgstr "Adicionar sugestão ao lote"
msgid "Add tag"
+msgstr "Adicionar etiqueta"
+
+msgid "Add target branch rule"
msgstr ""
msgid "Add text to the sign-in page. Markdown enabled."
@@ -2960,6 +3019,9 @@ msgstr "Adicionar à revisão"
msgid "Add to tree"
msgstr "Adicionar à árvore"
+msgid "Add token"
+msgstr "Adicionar token"
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,8 +3049,8 @@ msgstr "Adicionar/remover"
msgid "AddMember|Invite email is invalid"
msgstr "E-mail de Convite é inválido"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "Excedido o limite de convite de %{daily_invites} por dia"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "Os convites não podem ficar em branco"
@@ -3827,8 +3889,8 @@ msgstr "Bloquear o usuário tem os seguintes efeitos:"
msgid "AdminUsers|Bot"
msgstr "Robô"
-msgid "AdminUsers|Can create group"
-msgstr "Pode criar grupo"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "Não é possível entrar ou acessar informações da instância"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr "Um URL de webhook e uma chave de autorização são gerados para a integração. Depois de salvar a integração, ambos ficam visíveis na guia “Exibir credenciaisâ€."
+msgid "AlertSettings|Active alerts"
+msgstr "Alertas ativos"
+
msgid "AlertSettings|Add new integration"
msgstr "Adicione uma nova integração"
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr "Erro ao pré-visualizar o blob"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr "Ocorreu um erro ao atualizar o título"
@@ -4982,6 +5044,9 @@ msgstr "Ocorreu um erro ao buscar issues."
msgid "An error occurred while fetching label colors."
msgstr "Ocorreu um erro ao buscar cores de rótulo."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr "Ocorreu um erro ao buscar os participantes"
@@ -5167,6 +5232,9 @@ msgstr[1] "Ocorreu um erro ao salvar as configurações"
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "Ocorreu um erro ao disparar a tarefa."
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "Ocorreu um erro ao atualizar os aprovadores"
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr "Já existe uma visualização com esse nome."
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr "Adicionar visualizações"
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
+msgid "Analytics|Create your dashboard"
+msgstr ""
+
msgid "Analytics|Custom dashboards"
msgstr "Painéis personalizados"
-msgid "Analytics|Dashboard Title"
-msgstr "Título do painel"
-
msgid "Analytics|Dashboard not found"
msgstr "Painel não encontrado"
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr "Editar"
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr "Insira um nome de visualização"
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr "Referenciador"
msgid "Analytics|Resulting Data"
msgstr "Dados resultantes"
-msgid "Analytics|Save"
-msgstr "Salvar"
-
msgid "Analytics|Save and add to Dashboard"
msgstr "Salvar e adicionar ao painel"
msgid "Analytics|Save new visualization"
msgstr "Salvar nova visualização"
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr "Estatística única"
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr "Tem certeza de que deseja excluir este dispositivo? Esta ação não pod
msgid "Are you sure you want to delete this label?"
msgstr "Você tem certeza que deseja excluir essa etiqueta?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Tem certeza que deseja excluir este agendamento de pipeline?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "Tem certeza de que deseja excluir este pipeline? Fazendo isso irá expirar todos os caches de pipeline e excluir todos os objetos relacionados, como builds, logs, artefatos e gatilhos. Esta ação não pode ser desfeita."
@@ -6283,8 +6375,8 @@ msgstr "Você tem certeza que quer recriar o token de registro?"
msgid "Are you sure you want to retry this migration?"
msgstr "Tem certeza de que deseja repetir esta migração?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "Tem certeza de que deseja revogar este %{accessTokenType}? Essa ação não pode ser desfeita."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
msgstr "Tem certeza que deseja revogar esta chave SSH?"
@@ -6394,7 +6486,7 @@ msgid "Artifacts|Something went wrong while deleting. Please refresh the page to
msgstr ""
msgid "Artifacts|Take a quick survey"
-msgstr ""
+msgstr "Faça uma pesquisa rápida"
msgid "Artifacts|The selected artifact will be permanently deleted. Any reports generated from these artifacts will be empty."
msgid_plural "Artifacts|The selected artifacts will be permanently deleted. Any reports generated from these artifacts will be empty."
@@ -6428,6 +6520,9 @@ msgstr "Lista de ramificações separadas por vírgulas para serem automaticamen
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr "Token de acesso pessoal do usuário. O usuário deve ter acesso à tarefa. Todos os comentários são atribuídos a este usuário."
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "Perguntar novamente mais tarde"
@@ -6530,7 +6625,7 @@ msgid "Assignees"
msgstr "Responsáveis"
msgid "Assignees & reviewers"
-msgstr ""
+msgstr "Responsáveis e revisores"
msgid "Assigns %{assignee_users_sentence}."
msgstr "Atribui %{assignee_users_sentence}."
@@ -6638,6 +6733,9 @@ msgstr "Já existe um cabeçalho com este nome."
msgid "AuditStreams|Active"
msgstr "Ativo"
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr "Adicione um HTTP final para gerenciar registros de auditoria em sistemas de terceiros."
@@ -6755,6 +6853,9 @@ msgstr "Isso pode incluir informações confidenciais. Certifique-se de confiar
msgid "AuditStreams|This is great for keeping everything one place."
msgstr "Isso é ótimo para manter tudo em um só lugar."
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "Valor"
@@ -6876,13 +6977,13 @@ msgid "Authorized At"
msgstr "Autorizado em"
msgid "Authorized applications"
-msgstr ""
+msgstr "Aplicativos autorizados"
msgid "AuthorizedApplication|Application secret was successfully renewed."
msgstr "O segredo do aplicativo foi renovado com sucesso."
msgid "AuthorizedApplication|Are you sure you want to renew this secret? Any applications using the old secret will no longer be able to authenticate with GitLab."
-msgstr ""
+msgstr "Tem certeza de que deseja renovar este segredo? Quaisquer aplicativos que usam o segredo antigo não poderão mais se autenticar com o GitLab."
msgid "AuthorizedApplication|Are you sure you want to revoke this application?"
msgstr "Tem certeza de que deseja revogar este aplicativo?"
@@ -7155,7 +7256,7 @@ msgid "Badges|This group has no badges, start by creating a new one above."
msgstr ""
msgid "Badges|This project has no badges, start by creating a new one above."
-msgstr ""
+msgstr "Este projeto não possui selos, comece criando um novo acima."
msgid "Badges|You are going to delete this badge. Deleted badges %{strongStart}cannot%{strongEnd} be restored."
msgstr ""
@@ -7539,7 +7640,7 @@ msgid "BillingPlans|Talk to an expert today."
msgstr "Fale hoje com um especialista."
msgid "BillingPlans|Then %{move_link_start}move any projects%{move_link_end} you wish to use with your subscription to that group."
-msgstr ""
+msgstr "Então %{move_link_start}mova quaisquer projetos%{move_link_end} que você deseja usar com sua assinatura para esse grupo."
msgid "BillingPlans|This group uses the plan associated with its parent group."
msgstr "Esse grupo usa o plano associado com seu grupo pai."
@@ -7614,7 +7715,7 @@ msgid "Billings|Free groups are limited to %{number} seats."
msgstr "Grupos gratuitos são limitados a %{number} assentos."
msgid "Billings|Free seats used"
-msgstr ""
+msgstr "Assentos gratuitos usados"
msgid "Billings|Free tier and trial groups can invite a maximum of 20 members per day."
msgstr "Grupos de nível gratuito e de avaliação podem convidar no máximo 20 membros por dia."
@@ -7682,8 +7783,8 @@ msgstr "Ocorreu um erro ao carregar os detalhes da assinatura do GitLab."
msgid "Billing|An error occurred while loading billable members list."
msgstr "Ocorreu um erro ao carregar a lista de membros faturáveis."
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
-msgstr "Ocorreu um erro ao carregar os detalhes do complemento Sugestões de código."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
msgid "Billing|An error occurred while loading pending members list"
msgstr "Ocorreu um erro ao carregar a lista de membros pendentes."
@@ -7697,15 +7798,18 @@ msgstr "Aguardando cadastro de membro"
msgid "Billing|Cannot remove user"
msgstr "Não é possível remover usuário"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr "Membros diretos"
msgid "Billing|Enter at least three characters to search."
msgstr "Digite pelo menos três caracteres para pesquisar."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr "Explorar planos pagos"
@@ -7723,6 +7827,9 @@ msgstr[1] "Grupos no nível Gratuito são limitados a %d assentos"
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "Membros que foram convidados por meio de um convite de grupo, não podem ser removidos. Você pode remover o grupo inteiro, ou pedir ao Proprietário do grupo convidado para remover o membro."
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr "Nenhum usuário para exibir"
@@ -7735,6 +7842,12 @@ msgstr "Convite de projeto"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "Remover usuário %{username} da sua assinatura"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr "Ver aprovações pendentes"
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "Você está prestes a remover o usuário %{username} de sua assinatura. Se você continuar, o usuário será removido do %{namespace} grupo e de todos os seus subgrupos e projetos. Esta ação não pode ser desfeita."
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr "Seu grupo mudou recentemente para usar o plano Gratuito. %{over_limit_message} Você pode liberar espaço para novos membros removendo aqueles que não precisam mais de acesso ou alternando-os para exceder o limite. Para obter um número ilimitado de membros, você pode %{link_start}atualizar%{link_end} para um nível pago."
@@ -7806,6 +7922,9 @@ msgstr[1] "Bloqueado por %d issues"
msgid "Blocked issue"
msgstr "Issue bloqueada"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr "Bloqueando"
@@ -7839,9 +7958,6 @@ msgstr "Nenhum resultado correspondente"
msgid "BoardNewEpic|Search groups"
msgstr "Pesquisar grupos"
-msgid "BoardNewEpic|Select a group"
-msgstr "Selecione um grupo"
-
msgid "BoardNewIssue|No matching results"
msgstr "Nenhum resultado correspondente"
@@ -7929,9 +8045,6 @@ msgstr "Selecionar etiquetas"
msgid "BoardScope|Select milestone"
msgstr "Selecionar marco"
-msgid "BoardScope|Select weight"
-msgstr "Selecionar peso"
-
msgid "BoardScope|Started"
msgstr "Iniciado"
@@ -8165,7 +8278,7 @@ msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab
msgstr "A ramificação %{branch_name} foi criada. Para configurar implantação automática, escolha um modelo de GitLab CI Yaml e comente suas mudanças. %{link_to_autodeploy_doc}"
msgid "Branch Rules"
-msgstr ""
+msgstr "Regras de ramificação"
msgid "Branch already exists"
msgstr ""
@@ -8342,7 +8455,7 @@ msgid "BranchRules|Users"
msgstr "Usuários"
msgid "BranchRules|View details"
-msgstr ""
+msgstr "Ver detalhes"
msgid "BranchRules|default"
msgstr "padrão"
@@ -9001,16 +9114,16 @@ msgid "CICD|Limit"
msgstr "Limite"
msgid "CICD|Limit access %{italicStart}from%{italicEnd} this project (Deprecated)"
-msgstr ""
+msgstr "Limitar o acesso %{italicStart}do%{italicEnd} projeto (Obsoleto)"
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
-msgstr ""
+msgstr "Limitar o acesso %{italicStart}para%{italicEnd} esse projeto"
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
+msgstr "Evitar que os tokens de trabalho CI/CD deste projeto sejam usados para acessar outros projetos, a menos que o outro projeto seja adicionado à lista de permissões. É um risco de segurança desabilitar esse recurso, porque projetos não autorizados podem tentar recuperar um token ativo e acessar a API. %{linkStart}Saiba mais%{linkEnd}."
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
+msgstr "Impedir o acesso a este projeto de outros tokens de trabalho CI/CD do projeto, a menos que o outro projeto seja adicionado à lista de permissões. É um risco de segurança desabilitar esse recurso, porque projetos não autorizados podem tentar recuperar um token ativo e acessar a API. %{linkStart}Saiba mais.%{linkEnd}"
msgid "CICD|The %{boldStart}Limit CI_JOB_TOKEN%{boldEnd} scope is deprecated and will be removed the 17.0 milestone. Configure the %{boldStart}CI_JOB_TOKEN%{boldEnd} allowlist instead. %{linkStart}How do I do this?%{linkEnd}"
msgstr "O escopo %{boldStart}Limit CI_JOB_TOKEN%{boldEnd} está depreciação e será removido no marco 17.0. Em vez disso, configure a lista de permissões %{boldStart}CI_JOB_TOKEN%{boldEnd} . %{linkStart}Como faço isso?%{linkEnd}"
@@ -9102,8 +9215,8 @@ msgstr "O subdomínio %{code_open}.campfirenow.com%{code_close}"
msgid "Can be manually deployed to"
msgstr "Pode ser implantado manualmente para"
-msgid "Can create groups:"
-msgstr "Pode criar grupos:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr "Não é possível excluir a chave primária"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr "Mudanças:"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr "Verifique suas imagens do Docker quanto a vulnerabilidades conhecidas."
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Verificando disponibilidade de %{text}…"
@@ -9637,8 +9756,8 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] "%{quantity} de pacote de armazenamento"
msgstr[1] "%{quantity} de pacotes de armazenamento"
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "plano %{selectedPlanText}"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9710,7 +9829,7 @@ msgid "Checkout|Credit card form failed to load: %{message}"
msgstr "Falha ao carregar o formulário de cartão de crédito: %{message}"
msgid "Checkout|Discount"
-msgstr ""
+msgstr "Desconto"
msgid "Checkout|Edit"
msgstr "Editar"
@@ -9749,7 +9868,7 @@ msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use) or more."
msgstr "Deve ser %{minimumNumberOfUsers} (seus assentos em uso) ou mais."
msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use, plus all over limit members) or more. To buy fewer seats, remove members from the group."
-msgstr ""
+msgstr "Deve ser %{minimumNumberOfUsers} (seus assentos em uso, mais todos os membros acima do limite) ou mais. Para comprar menos assentos, remova membros do grupo."
msgid "Checkout|Must be 1 or more. Cannot be a decimal."
msgstr "Deve ser 1 ou mais. Não pode ser um decimal."
@@ -9782,10 +9901,10 @@ msgid "Checkout|Select"
msgstr "Selecionar"
msgid "Checkout|Select a country"
-msgstr ""
+msgstr "Selecione um país"
msgid "Checkout|Select a state"
-msgstr ""
+msgstr "Selecione um estado"
msgid "Checkout|Something went wrong while loading price details."
msgstr ""
@@ -9892,6 +10011,9 @@ msgstr "Escolha um modelo..."
msgid "Choose a type..."
msgstr "Escolha um tipo..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Escolher arquivo…"
@@ -9902,7 +10024,7 @@ msgid "Choose the top-level group for your repository imports."
msgstr "Escolha o grupo principal para importar seus repositórios."
msgid "Choose visibility level, enable/disable project features and their permissions, disable email notifications, and show default emoji reactions."
-msgstr ""
+msgstr "Escolha o nível de visibilidade, ative/desative os recursos do projeto e suas permissões, desative as notificações por e-mail e mostre reações emoji padrão."
msgid "Choose what content you want to see on a group’s overview page."
msgstr "Escolha o conteúdo que você deseja ver na página de visão geral de um grupo."
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr "Cancelar"
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "Não é possível usar a variável mascarada com o valor atual"
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr "Ambientes"
@@ -10153,9 +10275,6 @@ msgstr "Remover entradas"
msgid "CiVariables|Remove variable"
msgstr "Remover variável"
-msgid "CiVariables|Remove variable row"
-msgstr "Remover a variável"
-
msgid "CiVariables|Run job"
msgstr "Executar tarefa"
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr "Este %{entity} tem %{currentVariableCount} variáveis de CI/CD definidas. O número máximo de variáveis por %{entity} é %{maxVariableLimit}. Para adicionar novas variáveis, você deve reduzir o número de variáveis definidas."
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Tipo"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Valor"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr "Variável será mascarada nos registros de tarefa. Requer valores para atender aos requisitos de expressão regular."
@@ -10198,9 +10329,6 @@ msgstr "Variáveis armazenam informações, como senhas e chaves secretas, que v
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (Todos os ambientes)"
-
msgid "CiVariable|All environments"
msgstr "Todos os ambientes"
@@ -10359,6 +10487,9 @@ msgstr "Clientes"
msgid "Clientside DSN"
msgstr "DSN do lado do cliente"
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Clonar"
@@ -10474,13 +10605,13 @@ msgid "Cloud Storage"
msgstr "Armazenamento em nuvem"
msgid "CloudSeed|AI / ML"
-msgstr ""
+msgstr "IA / ML"
msgid "CloudSeed|All"
msgstr "Todos"
msgid "CloudSeed|AlloyDB for Postgres"
-msgstr ""
+msgstr "AlloyDB para Postgres"
msgid "CloudSeed|Available database services through which instances may be created"
msgstr "Serviços de banco de dados disponíveis através dos quais as instâncias podem ser criadas"
@@ -10489,31 +10620,31 @@ msgid "CloudSeed|Cancel"
msgstr "Cancelar"
msgid "CloudSeed|Cloud Firestore"
-msgstr ""
+msgstr "Cloud Firestore"
msgid "CloudSeed|Cloud SQL for MySQL"
-msgstr ""
+msgstr "Cloud SQL para MySQL"
msgid "CloudSeed|Cloud SQL for Postgres"
-msgstr ""
+msgstr "Cloud SQL para Postgres"
msgid "CloudSeed|Cloud SQL for SQL Server"
-msgstr ""
+msgstr "Cloud SQL para SQL Server"
msgid "CloudSeed|Cloud SQL instance creation request successful. Expected resolution time is ~5 minutes."
msgstr ""
msgid "CloudSeed|Cloud SQL instances are fully managed, relational PostgreSQL databases. Google handles replication, patch management, and database management to ensure availability and performance."
-msgstr ""
+msgstr "Cloud SQL são bancos de dados PostgreSQL relacionais totalmente gerenciados. O Google lida com replicação, gerenciamento de patches e gerenciamento de banco de dados para garantir disponibilidade e desempenho."
msgid "CloudSeed|CloudSQL Instance"
-msgstr ""
+msgstr "Instância do CloudSQL"
msgid "CloudSeed|Configuration"
msgstr "Configuração"
msgid "CloudSeed|Configure via Merge Request"
-msgstr ""
+msgstr "Configurar via solicitação de mesclagem"
msgid "CloudSeed|Create MySQL Instance"
msgstr "Criar instância do MySQL"
@@ -10531,10 +10662,10 @@ msgid "CloudSeed|Create instance"
msgstr "Criar instância"
msgid "CloudSeed|Database instance is generated within the selected Google Cloud project"
-msgstr ""
+msgstr "A instância do banco de dados é gerada dentro do projeto Google Cloud selecionado"
msgid "CloudSeed|Database instances associated with this project"
-msgstr ""
+msgstr "Instâncias de banco de dados associadas a este projeto"
msgid "CloudSeed|Database version"
msgstr "Versão do banco de dados"
@@ -10555,7 +10686,7 @@ msgid "CloudSeed|Description"
msgstr "Descrição"
msgid "CloudSeed|Determines memory and virtual cores available to your instance"
-msgstr ""
+msgstr "Determina memória e núcleos virtuais disponíveis para sua instância"
msgid "CloudSeed|Enhance security by storing database variables in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
@@ -10564,22 +10695,22 @@ msgid "CloudSeed|Environment"
msgstr "Ambiente"
msgid "CloudSeed|Flexible, scalable NoSQL cloud database for client- and server-side development"
-msgstr ""
+msgstr "Banco de dados em nuvem NoSQL flexível e escalável para desenvolvimento do lado do cliente e do servidor"
msgid "CloudSeed|Fully managed PostgreSQL-compatible service for high-demand workloads"
-msgstr ""
+msgstr "Serviço compatível com PostgreSQL totalmente gerenciado para cargas de trabalho de alta demanda"
msgid "CloudSeed|Fully managed relational database service for MySQL"
-msgstr ""
+msgstr "Serviço de banco de dados relacional totalmente gerenciado para MySQL"
msgid "CloudSeed|Fully managed relational database service for PostgreSQL"
-msgstr ""
+msgstr "Serviço de banco de dados relacional totalmente gerenciado para PostgreSQL"
msgid "CloudSeed|Fully managed relational database service for SQL Server"
-msgstr ""
+msgstr "Serviço de banco de dados relacional totalmente gerenciado para SQL Server"
msgid "CloudSeed|Generated database instance is linked to the selected branch or tag"
-msgstr ""
+msgstr "A instância de banco de dados gerada está vinculada à ramificação ou tag selecionada"
msgid "CloudSeed|Google Cloud Error - %{message}"
msgstr ""
@@ -10591,7 +10722,7 @@ msgid "CloudSeed|Google Cloud project"
msgstr ""
msgid "CloudSeed|Google Cloud's AI tools are armed with the best of Google's research and technology to help developers focus exclusively on solving problems that matter"
-msgstr ""
+msgstr "As ferramentas de IA do Google Cloud estão equipadas com o melhor da pesquisa e tecnologia do Google para ajudar os desenvolvedores a se concentrarem exclusivamente na solução de problemas importantes"
msgid "CloudSeed|I accept Google Cloud pricing and responsibilities involved with managing database instances"
msgstr ""
@@ -10603,7 +10734,7 @@ msgid "CloudSeed|Language AI"
msgstr ""
msgid "CloudSeed|Learn more about pricing for %{cloudsqlPricingStart}Cloud SQL%{cloudsqlPricingEnd}, %{alloydbPricingStart}Alloy DB%{alloydbPricingEnd}, %{memorystorePricingStart}Memorystore%{memorystorePricingEnd} and %{firestorePricingStart}Firestore%{firestorePricingEnd}."
-msgstr ""
+msgstr "Saiba mais sobre preços para %{cloudsqlPricingStart}Cloud SQL%{cloudsqlPricingEnd}, %{alloydbPricingStart}Alloy DB%{alloydbPricingEnd}, %{memorystorePricingStart}Memorystore%{memorystorePricingEnd} e %{firestorePricingStart}Firestore%{firestorePricingEnd}."
msgid "CloudSeed|Machine type"
msgstr "Tipo de máquina"
@@ -10636,7 +10767,7 @@ msgid "CloudSeed|Services"
msgstr "Serviços"
msgid "CloudSeed|There are no instances to display."
-msgstr ""
+msgstr "Não há instâncias para exibir."
msgid "CloudSeed|Translation AI"
msgstr ""
@@ -10645,7 +10776,7 @@ msgid "CloudSeed|Version"
msgstr "Versão"
msgid "CloudSeed|Vision AI"
-msgstr ""
+msgstr "Vision AI"
msgid "Cluster"
msgstr "Cluster"
@@ -10656,15 +10787,9 @@ msgstr "Saúde do cluster"
msgid "Cluster cache cleared."
msgstr "Cache do cluster limpo."
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr "Nível de cluster"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr "É necessário especificar o tipo de cluster para Stages::ClusterEndpointInserter"
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr "%{linkStart}Veja a documentação%{linkEnd} para instalação avançada. Certifique-se de ter seu token de acesso disponível."
@@ -10955,6 +11080,9 @@ msgstr "Este agente não tem tokens"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "Para excluir o agente, digite %{name} para confirmar:"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr "Ver todos os %{number} agentes"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "Ver todos os %{number} agentes"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "Adoraríamos saber mais sobre sua experiência com o GitLab Agent."
@@ -11402,9 +11533,6 @@ msgstr "Revisão de código"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "O Code Review Analytics exibe uma tabela de solicitações de mesclagem abertas consideradas em revisão de código. Atualmente não há solicitações de mesclagem em revisão para este projeto e/ou filtros."
-msgid "Code Suggestions add-on"
-msgstr "Complemento Sugestões de Código"
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11448,7 +11576,7 @@ msgid "CodeOwners|Code owners"
msgstr "Proprietários de código"
msgid "CodeOwners|Code owners are users and groups that can approve specific file changes."
-msgstr ""
+msgstr "Proprietários de código são usuários e grupos que podem aprovar alterações específicas de arquivos."
msgid "CodeOwners|Hide all"
msgstr "Ocultar tudo"
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr "Ativar sugestões de código para usuários desta instância. %{link_start}O que são sugestões de código?%{link_end}"
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr "Digite o novo token de acesso pessoal"
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
-msgstr "No GitLab.com, crie um token. Este token é necessário para usar sugestões de código em sua instância autogerenciada. %{link_start}Como faço para criar um token?%{link_end}"
-
-msgid "CodeSuggestionsSM|Personal access token"
-msgstr "Token de acesso pessoal"
-
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
-msgstr "%{code_suggestions_link_start}Sugestões de código%{link_end} agora usa serviços de IA de terceiros para fornecer sugestões de maior qualidade. Você pode %{third_party_link_start} desativar serviços de terceiros%{link_end} para o seu grupo, ou desabilitar totalmente as Sugestões de Código %{profile_settings_link_start}em seu perfil de usuário%{link_end}."
-
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
-msgstr "Usamos serviços de IA de terceiros para melhorar as sugestões de código."
-
msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr "%{link_start}O que são sugestões de código?%{link_end}"
msgid "CodeSuggestions|Code Suggestions"
msgstr "Sugestões de código"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
+msgstr ""
+
msgid "CodeSuggestions|Enable Code Suggestions"
msgstr "Ativar sugestões de código"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
+msgstr ""
+
msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgstr "Obtenha sugestões de código enquanto escreve código em seu IDE. %{link_start}Saiba mais%{link_end}."
+
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
+msgstr ""
+
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr "Grupos de usuários são mostrados nos últimos %{months_included} meses
msgid "Collapse"
msgstr "Recolher"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr "Ocultar todos os tópicos"
@@ -11776,7 +11904,7 @@ msgid "Commits"
msgstr "Commits"
msgid "Commits & branches"
-msgstr ""
+msgstr "Commits e ramificações"
msgid "Commits feed"
msgstr "Feed de commits"
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "Ocorreu um erro ao pesquisar a lista de tags/ramificações. Por favor, tente novamente."
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr "Ver solicitação de mesclagem aberta"
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr "Framework de conformidade"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Adicionar framework"
@@ -12033,8 +12161,8 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
-msgstr "Frameworks que foram adicionados aparecerão aqui."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr ""
msgid "ComplianceFrameworks|Invalid format"
msgstr "Formato inválido"
@@ -12249,15 +12377,18 @@ msgstr "Confidencialidade"
msgid "Configuration help"
msgstr "Ajuda na configuração"
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr "Configurar CAPTCHAs, limites de endereço IP e outras medidas anti-spam."
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr "Configure permissões avançadas, armazenamento de arquivos grandes, autenticação de dois fatores e configurações de relacionamento com o cliente."
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr "Falha na conexão"
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "Contatar suporte"
@@ -13014,6 +13151,9 @@ msgstr "Adicionado design %{targetLink} em %{resourceParentLink}."
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr "Solicitação de mesclagem aprovada %{targetLink} em %{resourceParentLink}."
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr "Projeto criado em %{resourceParentLink}."
@@ -13059,9 +13223,18 @@ msgstr "Página da wiki criada %{targetLink} em %{resourceParentLink}."
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr "Iniciou o projeto %{resourceParentLink}."
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr "Criar versão"
msgid "Create requirement"
msgstr "Criar requisito"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr "Criar nova conta de serviço"
@@ -14073,9 +14258,6 @@ msgstr "A organização foi adicionada."
msgid "Crm|Organization has been updated."
msgstr "A organização foi atualizada."
-msgid "Cron Timezone"
-msgstr "Fuso horário do cron"
-
msgid "Cron time zone"
msgstr "Fuso horário cron"
@@ -14414,9 +14596,6 @@ msgstr "Tempo para restaurar o serviço"
msgid "CycleAnalytics|Total time"
msgstr "Tempo total"
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "filtro de seleção de grupo"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr "não permitido para o determinado evento de início"
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr "Tempo para restaurar o serviço (mediana dos dias)"
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr "Mínimo = 0 (sem tempo limite habilitado), Máximo = 2880 minutos"
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "Mínimo = 1 segundo, Máximo = 3600 segundos"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr "Monitora todas as solicitações HTTP enviadas ao destino para encontrar possíveis vulnerabilidades."
@@ -15377,7 +15565,7 @@ msgid "DefaultBranchProtection|Both developers and maintainers can push new comm
msgstr "Tanto os desenvolvedores e mantenedores podem enviar novos commits, forçar push ou excluir a ramificação."
msgid "DefaultBranchProtection|Developers can push the initial commit to a repository, but none afterward. Maintainers can always push. No one can force push."
-msgstr ""
+msgstr "Os desenvolvedores podem enviar o commit inicial para um repositório, mas nenhum depois. Os mantenedores sempre podem fazere o push. Ninguém pode forçar o push."
msgid "DefaultBranchProtection|Developers cannot push new commits, but are allowed to accept merge requests to the branch. Maintainers can push to the branch."
msgstr "Os desenvolvedores não podem enviar novos commits, mas podem aceitar solicitações de mesclagem para a ramificação. Os mantenedores podem fazer push para a ramificação."
@@ -15389,7 +15577,7 @@ msgid "DefaultBranchProtection|Fully protected"
msgstr "Totalmente protegido"
msgid "DefaultBranchProtection|Fully protected after initial push"
-msgstr ""
+msgstr "Totalmente protegido após o push inicial"
msgid "DefaultBranchProtection|Not protected"
msgstr "Não protegido"
@@ -15409,9 +15597,6 @@ msgstr "Defina um padrão personalizado utilizando a sintaxe do cron"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "Defina os ambientes na(s) fase(s) de implantação em %{code_open}.gitlab-ci.yml%{code_close} para acompanhar as implantações aqui."
-
msgid "Define how approval rules are applied to merge requests."
msgstr "Defina como as regras de aprovação são aplicadas às solicitações de mesclagem."
@@ -15534,9 +15719,6 @@ msgstr "Excluir etiqueta: %{labelName}"
msgid "Delete pipeline"
msgstr "Excluir pipeline"
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr "Excluir projeto"
@@ -15757,6 +15939,9 @@ msgstr "Localização e caminho de dependência"
msgid "Dependencies|Packager"
msgstr "Empacotador"
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr "Projetos"
@@ -15775,6 +15960,9 @@ msgstr "O caminho de dependência do componente é baseado no arquivo de bloquei
msgid "Dependencies|There may be multiple paths"
msgstr "Pode haver vários caminhos"
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "Alternar lista de vulnerabilidades"
@@ -15958,6 +16146,12 @@ msgstr "Fuso horário"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} outros"
+msgid "DeployKeys|Add new deploy key"
+msgstr "Adicionar nova chave de implantação"
+
+msgid "DeployKeys|Add new key"
+msgstr "Adicionar nova chave"
+
msgid "DeployKeys|Current project"
msgstr "Projeto Atual"
@@ -15985,8 +16179,8 @@ msgstr "Conceder permissões de escrita a esta chave"
msgid "DeployKeys|Loading deploy keys"
msgstr "Carregando chaves de implantação"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "Nenhuma chave de implantação encontrada. Crie uma com o formulário acima."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr "Nenhuma chave de implantação encontrada, comece adicionando uma nova acima."
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "Chaves de implantação acessíveis de forma privada"
@@ -16000,8 +16194,8 @@ msgstr "Chaves de implantação acessíveis publicamente"
msgid "DeployKeys|Read access only"
msgstr "Apenas acesso de leitura"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "Tokens de implantação ativos (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr "Tokens de implantação ativos"
msgid "DeployTokens|Allows read and write access to registry images."
msgstr "Permite acesso de leitura e gravação às imagens de registro."
@@ -16024,6 +16218,9 @@ msgstr "Permite acesso somente-leitura ao repositório."
msgid "DeployTokens|Allows write access to registry images."
msgstr "Permite acesso de leitura às imagens de registro."
+msgid "DeployTokens|Cancel"
+msgstr "Cancelar"
+
msgid "DeployTokens|Copy deploy token"
msgstr "Copiar token de implantação"
@@ -16084,7 +16281,7 @@ msgstr "Escopos"
msgid "DeployTokens|Scopes (select at least one)"
msgstr "Escopos (selecione pelo menos um)"
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr "Este %{entity_type} não tem nenhum tokem de implantação ativa."
msgid "DeployTokens|This action cannot be undone."
@@ -16102,12 +16299,12 @@ msgstr "Nome de usuário"
msgid "DeployTokens|Username (optional)"
msgstr "Nome de usuário (opcional)"
-msgid "DeployTokens|Your New Deploy Token"
-msgstr "Seu novo token de implantação"
-
msgid "DeployTokens|Your new Deploy Token username"
msgstr "Seu novo nome de usuário do token de implantação"
+msgid "DeployTokens|Your new deploy token"
+msgstr "Seu novo token de implantação"
+
msgid "DeployTokens|Your new group deploy token has been created."
msgstr "Seu novo token de inplantação de grupo foi criado."
@@ -16189,6 +16386,12 @@ msgstr "Aprovado por você %{time}"
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr "A aprovação irá executar a tarefa manual a partir da implantação #%{deploymentIid}. Rejeitar irá falhar na tarefa manual."
+msgid "DeploymentApproval|Deployment approved"
+msgstr "Implantação aprovada"
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr "Implantação rejeitada"
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr "Nível de implantação: %{tier}"
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "Cancelado"
@@ -16275,6 +16475,24 @@ msgstr "ID da implantação"
msgid "Deployment|Failed"
msgstr "Falhado"
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr "Última implantação"
@@ -16290,15 +16508,18 @@ msgstr "Pulado"
msgid "Deployment|Success"
msgstr "Sucesso"
-msgid "Deployment|This deployment was created using the API"
-msgstr "Esta implantação foi criada usando a API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
-msgid "Deployment|Unavailable"
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
msgstr ""
+msgid "Deployment|Unavailable"
+msgstr "Indisponível"
+
msgid "Deployment|Unknown"
msgstr ""
@@ -16357,7 +16578,7 @@ msgid "Descriptive label"
msgstr "Etiqueta descritiva"
msgid "Deselect all"
-msgstr ""
+msgstr "Desmarcar todos"
msgid "Design"
msgstr "Design"
@@ -16365,12 +16586,6 @@ msgstr "Design"
msgid "Design Management files and data"
msgstr "Projeto de gerenciamento de arquivos e dados"
-msgid "Design repositories"
-msgstr "Repositórios de design"
-
-msgid "Design repository"
-msgstr "Repositório de design"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} de %{designs_count}"
@@ -17565,9 +17780,6 @@ msgstr "E-mail enviado"
msgid "Email the pipeline status to a list of recipients."
msgstr "Envie o status do pipeline para uma lista de e-mails."
-msgid "Email updates (optional)"
-msgstr "Atualizações via e-mail (opcional)"
-
msgid "Email:"
msgstr "E-mail:"
@@ -17610,6 +17822,9 @@ msgstr "%{emails}, %{andMore} será notificado do seu comentário."
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "e %{moreCount} mais"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "E-mails"
@@ -17748,9 +17963,6 @@ msgstr "Ativar executores de grupo"
msgid "Enable header and footer in emails"
msgstr "Ativar cabeçalho e rodapé em e-mails"
-msgid "Enable in-product marketing emails"
-msgstr "Ativar e-mails de marketing no produto"
-
msgid "Enable incident management inbound alert limit"
msgstr "Ativar limite de alerta de entrada de gerenciamento de incidentes"
@@ -17772,7 +17984,7 @@ msgstr "Ative apenas para aplicativos confidenciais usados exclusivamente por um
msgid "Enable or disable version check and Service Ping."
msgstr "Ativar ou desativar a verificação de versão e o serviço de ping."
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr "Forçar Autenticação de dois fatores para todos os logins de usuários
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,8 +18209,8 @@ msgstr "Ambiente"
msgid "Environment scope"
msgstr "Escopo de ambiente"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr "As variáveis de ambiente nesta instância do GitLab são configuradas para serem %{link_start}protegidas%{link_end} por padrão."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr ""
msgid "Environment:"
msgstr "Ambiente:"
@@ -18147,12 +18356,18 @@ msgstr "Introdução aos ambientes"
msgid "Environments|GitLab agent"
msgstr "GitLab agent"
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Tarefa"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr "Saiba mais sobre como parar ambientes"
@@ -18198,6 +18413,12 @@ msgstr "Reverter ambiente %{name}?"
msgid "Environments|Search by environment name"
msgstr "Pesquisar pelo nome do ambiente"
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr "Selecionar agente"
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr "Em breve"
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr "Os métodos de entrada existentes podem ser removidos"
msgid "Expand"
msgstr "Expandir"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Expandir tudo"
@@ -19337,6 +19570,9 @@ msgstr "https://exemplo.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr "Filtre por casos de teste que estão arquivados no momento."
msgid "Filter by test cases that are currently open."
msgstr "Filtre por casos de teste que estão abertos no momento."
-msgid "Filter by user"
-msgstr "Filtrar por usuário"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr "Filtrar por resultados..."
msgid "Filter users"
msgstr "Filtrar usuários"
-msgid "Filter..."
-msgstr "Filtro..."
-
msgid "Finalizing"
msgstr "Finalizando"
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "Alternativamente, você pode atualizar para o GitLab Premium ou GitLab Ultimate:"
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "Explorar planos pagos"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "Explorar planos pagos:"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr "Gerenciar membros"
-
-msgid "FreeUserCap|Manage members:"
-msgstr "Gerenciar membros:"
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr "Para obter mais membros %{trial_link_start}inicie uma avaliação %{trial_link_end} ou %{upgrade_link_start}atualize%{upgrade_link_end} para GitLab Premium ou GitLab Ultimate."
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr "Para obter mais membros, inicie uma avaliação:"
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr "Você atingiu seu limite de membros!"
-
msgid "Freeze end"
msgstr "Fim do congelamento"
@@ -20754,7 +20957,7 @@ msgid "Geo|Last event ID from primary"
msgstr "Último ID de evento do primário"
msgid "Geo|Last event ID processed"
-msgstr ""
+msgstr "Último ID de evento processado"
msgid "Geo|Last repository check run"
msgstr "Última verificação de repositório executada"
@@ -21113,6 +21316,12 @@ msgstr "Obter gratuitamente uma instância de revisão"
msgid "Get a support subscription"
msgstr "Obtenha uma assinatura de suporte"
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Começar"
@@ -21288,7 +21497,7 @@ msgid "GitLab documentation"
msgstr "Documentação do GitLab"
msgid "GitLab events trigger webhooks. Use the request details of a webhook to help troubleshoot problems. %{link_start}How do I troubleshoot?%{link_end}"
-msgstr ""
+msgstr "Os eventos do GitLab acionam webhooks. Use os detalhes da solicitação de um webhook para ajudar a solucionar problemas. %{link_start}Como faço para solucionar problemas?%{link_end}"
msgid "GitLab export"
msgstr "Exportação do GitLab"
@@ -21440,6 +21649,9 @@ msgstr "Não verificado"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Atualizando a configuração de suas páginas..."
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr "Usar domínio único"
@@ -21455,6 +21667,9 @@ msgstr "Quando ativado, um domínio único é gerado para acessar as páginas."
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr "Quando ativado, todas as tentativas de visitar seu site através de HTTP são redirecionadas automaticamente para HTTPS usando uma resposta com o código de status 301. Requer um certificado válido para todos os domínios. %{docs_link_start}Saiba mais.%{link_end}"
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr "Ao usar Pages sob o domínio geral de uma instância do GitLab (%{pages_host}), você não pode usar HTTPS com subdomínios de subdomínios. Se seu namespace ou nome de grupo contiver um ponto, ele não funcionará. Esta é uma limitação do protocolo HTTP sobre TLS. As páginas HTTP funcionam se você não redirecionar HTTP para HTTPS. %{docs_link_start}Saiba mais.%{link_end}"
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr "Servidores Gitaly"
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,8 +21805,8 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr "Para usar o Gitpod você deve primeiro ativar o recurso na seção de integrações de suas %{linkStart}preferências de usuário%{linkEnd}."
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
-msgstr ""
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr "Para usar a integração, cada usuário também deve habilitar o Gitpod em sua conta do GitLab. %{help_link_start}Como faço para ativar-lo?%{help_link_end}"
msgid "Gitpod|https://gitpod.example.com"
msgstr ""
@@ -21614,6 +21823,9 @@ msgstr "Acesso concedido %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr "%{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr "Fechar"
msgid "GlobalSearch|Fetching aggregations error."
msgstr "Erro ao buscar agregações."
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "Grupo"
@@ -21716,9 +21934,6 @@ msgstr "Pesquisa"
msgid "GlobalSearch|Search GitLab"
msgstr "Pesquisar no GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "Pesquisar por projetos, issues, etc."
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "Digite e pressione a tecla Enter para enviar a pesquisa."
@@ -21771,13 +21989,13 @@ msgid "GlobalSearch|in %{scope}"
msgstr "em %{scope}"
msgid "GlobalShortcuts|Copied reference to clipboard."
-msgstr ""
+msgstr "Referência copiada para a área de transferência."
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr ""
msgid "GlobalShortcuts|Unable to copy the reference at this time."
-msgstr ""
+msgstr "Não é possível copiar a referência neste momento."
msgid "GlobalShortcuts|Unable to copy the source branch name at this time."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr "Revogar autorizações"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr "Arraste seu arquivo de chave aqui ou %{linkStart}clique para enviar%{linkEnd}."
@@ -22004,8 +22228,8 @@ msgstr "Google Play"
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr "Deixe em branco para usar sua chave de conta de serviço atual."
-msgid "GooglePlay|Service account key (.json)"
-msgstr "Chave da conta de serviço (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
+msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
msgstr "Carregue uma nova chave de conta de serviço (substitua %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr "Avatar do grupo"
msgid "Group by"
msgstr "Agrupar por"
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "Descrição do grupo (opcional)"
@@ -22181,9 +22408,6 @@ msgstr "Nome do grupo (sua organização)"
msgid "Group navigation"
msgstr "Navegação do grupo"
-msgid "Group overview"
-msgstr "Visão geral do grupo"
-
msgid "Group overview content"
msgstr "Conteúdo da visão geral do grupo"
@@ -22515,10 +22739,10 @@ msgid "GroupSelect|Select a group"
msgstr "Selecionar grupos"
msgid "GroupSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave empty for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{project_sharing_docs_link_start}project sharing%{link_end} and %{group_sharing_docs_link_start}group sharing%{link_end}."
-msgstr ""
+msgstr "Após a instância atingir o limite de usuários, qualquer usuário adicionado ou que solicite acesso deve ser aprovado por um administrador. Deixe em branco para um limite de usuários ilimitado. Se você alterar o limite de usuários para ilimitado, deverá reativar %{project_sharing_docs_link_start}compartilhamento de projeto%{link_end} e %{group_sharing_docs_link_start}compartilhamento de grupo%{link_end}."
msgid "GroupSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave empty for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{project_sharing_docs_link_start}project sharing%{link_end} and %{group_sharing_docs_link_start}group sharing%{link_end}. Increasing the user cap does not automatically approve pending users."
-msgstr ""
+msgstr "Após a instância atingir o limite de usuários, qualquer usuário adicionado ou que solicite acesso deve ser aprovado por um administrador. Deixe em branco para um limite de usuários ilimitado. Se você alterar o limite de usuários para ilimitado, deverá reativar %{project_sharing_docs_link_start}compartilhamento de projeto%{link_end} e %{group_sharing_docs_link_start}compartilhamento de grupo%{link_end}. Aumentar o limite de usuários não aprova automaticamente os usuários pendentes."
msgid "GroupSettings|Analytics"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr "Frameworks de conformidade"
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,8 +22972,8 @@ msgstr "Esse recurso requer um navegador com suporte a localStorage"
msgid "GroupsDropdown|Toggle edit mode"
msgstr "Alternar modo de edição"
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "Um grupo é uma coleção de vários projetos."
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
msgid "GroupsEmptyState|Create new project"
msgstr "Criar novo projeto"
@@ -22760,8 +22984,8 @@ msgstr "Criar novo subgrupo"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Se você organizar seus projetos num grupo, será como uma pasta."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
msgid "GroupsEmptyState|No archived projects."
msgstr "Nenhum projeto arquivado."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "Você pode gerenciar permissões de membros e acesso do seu grupo para cada projeto no grupo."
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "Você não tem as permissões necessárias para criar um subgrupo ou projeto neste grupo. Entre em contato com um proprietário deste grupo para criar um novo subgrupo ou projeto."
@@ -23202,6 +23423,9 @@ msgstr "Ajude a traduzir o GitLab para seu idioma"
msgid "Help translate to your language"
msgstr "Ajude a traduzir para o seu idioma"
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr "Eu quero armazenar meu código"
msgid "I want to use GitLab CI with my existing repository"
msgstr "Euquero usar o GitLab CI com meu repositório existente"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr "Verificar forma de pagamento"
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr "Verificar sua identidade"
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr "Detalhes da importação do GitHub"
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr "O repositório não pôde ser importado."
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr "Não há um repositório de Git válido neste URL. Se seu repositório HTTP não for acessível publicamente, verifique suas credenciais."
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr "Melhore o suporte ao cliente com a Central de serviços"
@@ -24170,381 +24409,72 @@ msgstr "Em uso"
msgid "InProductMarketing|%{organization_name} logo"
msgstr "Logotipo de %{organization_name}"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...e você pode obter uma avaliação gratuita do GitLab Ultimate"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr "Teste de segurança avançado"
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr "Blog"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr "Construindo para iOS? Estamos protegendo você."
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "Crie seu primeiro projeto!"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "Siga nossos passos"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "Avaliação gratuita de 30 dias"
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr "Prepare-se para construir para iOS"
-msgid "InProductMarketing|Get started today"
-msgstr "Comece hoje mesmo"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr "Comece hoje com uma avaliação de 30 dias do GitLab Ultimate, sem necessidade de cartão de crédito."
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr "Primeiros passos com GitLab CI/CD"
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr "Conceitos básicos de Git"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr "GitHub Enterprise para o GitLab"
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr "Importe seu projeto e código do GitHub, Bitbucket e outros"
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr "Melhore a qualidade do código e simplifique as revisões"
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "Convide seus colegas e comece a enviar o código mais rapidamente."
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "Convide seus colegas hoje mesmo"
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "Convide sua equipe em menos de 60 segundos"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "Convide sua equipe agora"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr "Saiba como construir para iOS"
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr "Reduza o risco de segurança e conformidade"
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "Comece uma avaliação do GitLab Ultimate hoje em menos de um minuto, sem necessidade de cartão de crédito."
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr "Iniciar um teste autogerenciado"
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "Comece uma avaliação gratuita do GitLab Ultimate – sem necessidade de cartão de crédito"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "Inicie uma avaliação"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "Comece por %{performance_link}"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "Comece importando seus projetos"
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "Comece com uma avaliação gratuita do GitLab Ultimate"
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "Comece sua avaliação agora!"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr "Comece sua avaliação hoje para experimentar o sucesso de um único aplicativo e descubra todos os recursos do GitLab Ultimate gratuitamente!"
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr "Este é o e-mail %{current_series} de %{total_series} da série %{track} . Para desativar e-mails de notificação enviados por sua instância local do GitLab, entre em contato com seu administrador ou %{unsubscribe_link}."
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr "Para desativar esses e-mails de integração, %{unsubscribe_link}."
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "Experimente o GitLab Ultimate gratuitamente"
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "Experimente você mesmo"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr "Assista a construção do iOS em ação."
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr "criar um projeto"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "como é fácil começar"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "guia de início rápido"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr "cancelar inscrição"
-msgid "InProductMarketing|update your preferences"
-msgstr "atualize suas preferências"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "você pode %{unsubscribe_link} a qualquer momento."
@@ -25049,6 +24928,16 @@ msgstr "Em linha"
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr "Insira as chaves do host manualmente"
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr "Intervalo"
-msgid "Interval Pattern"
-msgstr "Padrão de intervalo"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr "Código de dois fatores inválido."
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr "não atribuído"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type} criado %{created_at} por "
-
msgid "IssuableStatus|Closed"
msgstr "Fechada"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Fechada (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "Criado %{created_at} por"
-
msgid "IssuableStatus|duplicated"
msgstr "duplicada"
@@ -26127,29 +26004,49 @@ msgstr "Issues com nenhum épico atribuído"
msgid "Issues, merge requests, pushes, and comments."
msgstr "Issues, solicitações de mesclagem, pushes e comentários."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "Depois que você começa a criar issues para seus projetos, podemos começar a acompanhar e exibir métricas para elas"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr "Issues criadas"
msgid "IssuesAnalytics|Issues created per month"
msgstr "Issues criadas por mês"
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "Últimos 12 meses"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Desculpe, mas o seu filtro não produziu resultados"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "Não há issues para os projetos no seu grupo"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "Para ampliar sua pesquisa, altere ou remova filtros na barra de filtros acima"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr "Total:"
@@ -26196,6 +26093,9 @@ msgstr "Itálico (%{modifierKey}I)"
msgid "Italic text"
msgstr "Texto em itálico"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr "Iteração"
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26794,7 +26697,7 @@ msgid "Job Failed #%{build_id}"
msgstr "Tarefa falhou nº %{build_id}"
msgid "Job artifacts"
-msgstr ""
+msgstr "Artefatos de tarefa"
msgid "Job has been erased"
msgstr "A tarefa foi apagada"
@@ -27001,7 +26904,7 @@ msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}"
msgstr ""
msgid "Job|%{searchLength} results found for %{searchTerm}"
-msgstr ""
+msgstr "%{searchLength} resultados encontrados para %{searchTerm}"
msgid "Job|Are you sure you want to erase this job log and artifacts?"
msgstr "Tem certeza de que deseja apagar este registro de tarefa e artefatos?"
@@ -27030,6 +26933,9 @@ msgstr "Duração"
msgid "Job|Erase job log and artifacts"
msgstr "Apagar registro de tarefa e artefatos"
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27061,7 +26967,7 @@ msgid "Job|No job log"
msgstr ""
msgid "Job|No search results found"
-msgstr ""
+msgstr "Nenhum resultado da pesquisa encontrado"
msgid "Job|Passed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr "Repetir"
msgid "Job|Run again"
msgstr "Executar novamente"
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr "Executando"
@@ -27177,9 +27086,6 @@ msgstr "Entrar em um projeto"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr "Entrou em %{user_created_time}"
@@ -27442,9 +27348,6 @@ msgstr "Última atividade"
msgid "Last Name"
msgstr "Sobrenome"
-msgid "Last Pipeline"
-msgstr "Último Pipeline"
-
msgid "Last Seen"
msgstr "Visto pela última vez"
@@ -27541,6 +27444,9 @@ msgstr "Você fez o push para"
msgid "LastPushEvent|at"
msgstr "em"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "Últimas modificações"
@@ -28054,7 +27960,7 @@ msgid "Link"
msgstr ""
msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
-msgstr ""
+msgstr "Vincule %{issuableType}s juntos para mostrar que eles estão relacionados ou que um está bloqueando os outros."
msgid "Link %{issuableType}s together to show that they're related."
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr "Bloquear arquivo?"
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr "Bloquear inscrições para sincronização LDAP"
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr "Bloqueio não encontrado"
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28549,7 +28461,7 @@ msgid "Markdown enabled."
msgstr "Markdown ativado."
msgid "Markdown is supported"
-msgstr ""
+msgstr "Markdown é suportado"
msgid "Markdown supported."
msgstr "Markdown suportado."
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr "Notificações de Mattermost"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr "Adicionar ao Mattermost"
@@ -28671,6 +28589,9 @@ msgstr "Preencha a palavra que funciona melhor para sua equipe."
msgid "MattermostService|Install"
msgstr "Instalar"
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr "URL de requisição"
@@ -28683,6 +28604,9 @@ msgstr "Ãcone de resposta"
msgid "MattermostService|Response username"
msgstr "Nome de usuário de resposta"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr "Sugestões:"
@@ -28989,6 +28913,102 @@ msgstr "%{member_name} convidou você para participar do GitLab"
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr "Mensagem do commit mesclado"
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr "Detalhes da mesclagem"
@@ -29299,7 +29322,7 @@ msgid "Merge request reports"
msgstr "Relatórios de solicitação de mesclagem"
msgid "Merge request status"
-msgstr ""
+msgstr "Status da solicitação de mesclagem"
msgid "Merge request summaries"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr "Métricas e perfis"
msgid "Metrics:"
msgstr "Métricas:"
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr "Criar métricas"
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30384,7 +30407,7 @@ msgid "My awesome group"
msgstr "Meu grupo incrível"
msgid "My comment templates"
-msgstr ""
+msgstr "Meus modelos de comentários"
msgid "My company or team"
msgstr "Minha empresa ou equipe"
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr "Analisar"
msgid "Navigation|Build"
msgstr "Construção"
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr "Código"
@@ -30769,15 +30795,18 @@ msgstr "Grupos que você visita frequentemente aparecerão aqui."
msgid "Navigation|Leave admin mode"
msgstr "Sair do modo admin"
-msgid "Navigation|Main navigation"
-msgstr "Navegação principal"
-
msgid "Navigation|Manage"
msgstr "Gerenciar"
+msgid "Navigation|Merge requests settings"
+msgstr ""
+
msgid "Navigation|Monitor"
msgstr "Monitor"
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr "Nenhuma correspondência de grupo encontrada"
@@ -30796,12 +30825,18 @@ msgstr "Fixado"
msgid "Navigation|Plan"
msgstr "Plano"
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr "Projetos"
msgid "Navigation|Projects you visit often will appear here."
msgstr "Os projetos que você visita frequentemente aparecerão aqui."
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr "Recuperar resultados de pesquisa"
@@ -30820,6 +30855,12 @@ msgstr "Ocorreu um erro ao obter os resultados da pesquisa."
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr "Ver todos os meus grupos"
+
+msgid "Navigation|View all my projects"
+msgstr "Ver todos os meus projetos"
+
msgid "Navigation|View all your groups"
msgstr "Ver todos os seus grupos"
@@ -31044,9 +31085,6 @@ msgstr "Nova resposta para a issue #%{issue_iid}:"
msgid "New runners registration token has been generated!"
msgstr "Um novo token de registro de executores foi gerado!"
-msgid "New schedule"
-msgstr "Novo agendamento"
-
msgid "New snippet"
msgstr "Novo snippet"
@@ -31254,6 +31292,9 @@ msgstr "Sem iteração"
msgid "No label"
msgstr "Nenhuma etiqueta"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "Sem etiquetas com esse nome ou descrição"
@@ -31278,6 +31319,12 @@ msgstr "Nenhum resultado correspondente"
msgid "No matching results for \"%{query}\""
msgstr "Nenhum resultado correspondente para \"%{query}\""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr "Nenhum membro encontrado"
@@ -31296,12 +31343,15 @@ msgstr "Nenhum marco"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
-msgstr "Sem outras etiquetas com esse nome ou descrição"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
msgstr ""
+msgid "No other labels with such name or description"
+msgstr "Sem outras etiquetas com esse nome ou descrição"
+
msgid "No parent group"
msgstr "Nenhum grupo acima"
@@ -31356,9 +31406,6 @@ msgstr "Nenhum resultado encontrado."
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "Nenhum agendamento"
-
msgid "No service accounts"
msgstr "Nenhuma conta de serviço"
@@ -31410,6 +31457,12 @@ msgstr "Nenhum evento de webhook"
msgid "No webhooks enabled. Select trigger events above."
msgstr "Nenhum webhooks ativado. Selecione os eventos de gatilho acima."
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr "Acessível apenas por %{membersPageLinkStart}membros do projeto%{members
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr "Inclua apenas novos recursos no seu nível de assinatura atual."
@@ -32807,24 +32860,60 @@ msgstr "Opções"
msgid "Ordered list"
msgstr "Lista ordenada"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "Organizações"
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr "Ocorreu um erro ao carregar os projetos. Atualize a página para tentar novamente."
+msgid "Organization|Copy organization ID"
+msgstr "Copiar ID da organização"
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr "Publico - A organização pode ser acessada sem nenhuma autenticação."
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr "Páginas"
msgid "Pages Domain"
msgstr "Domínio de Pages"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr "Primeiro"
@@ -33685,7 +33777,10 @@ msgstr "Caminho"
msgid "Path:"
msgstr "Caminho:"
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33950,7 +34045,7 @@ msgid "Pipeline ran in fork of project"
msgstr "O pipeline foi executado na ramificação do projeto"
msgid "Pipeline schedules"
-msgstr ""
+msgstr "Agendamentos de pipeline"
msgid "Pipeline status emails"
msgstr "E-mails de status do pipeline"
@@ -34091,7 +34186,7 @@ msgid "PipelineEditor|The CI/CD configuration is continuously validated. Errors
msgstr ""
msgid "PipelineEditor|The full configuration view is displayed when the CI/CD configuration file has valid syntax."
-msgstr ""
+msgstr "A exibição de configuração completa é exibida quando o arquivo de configuração de CI/CD tem sintaxe válida."
msgid "PipelineEditor|The pipeline visualization is displayed when the CI/CD configuration file has valid syntax."
msgstr ""
@@ -34130,10 +34225,7 @@ msgid "PipelineScheduleIntervalPattern|Custom (%{linkStart}Learn more%{linkEnd}.
msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
-msgstr ""
-
-msgid "PipelineSchedules|Activated"
-msgstr "Ativado"
+msgstr "Um pipeline agendado inicia automaticamente em intervalos regulares, como diariamente ou semanalmente. O pipeline: "
msgid "PipelineSchedules|Active"
msgstr "Ativo"
@@ -34142,28 +34234,28 @@ msgid "PipelineSchedules|All"
msgstr "Todos"
msgid "PipelineSchedules|An error occurred while creating the pipeline schedule."
-msgstr ""
+msgstr "Ocorreu um erro ao criar o agendamento do pipeline."
msgid "PipelineSchedules|An error occurred while trying to fetch the pipeline schedule."
-msgstr ""
+msgstr "Ocorreu um erro ao tentar obter o agendamento do pipeline."
msgid "PipelineSchedules|An error occurred while updating the pipeline schedule."
-msgstr ""
+msgstr "Ocorreu um erro ao atualizar o agendamento do pipeline."
msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
msgstr "Tem certeza de que deseja excluir este agendamento de pipeline?"
msgid "PipelineSchedules|Can have custom CI/CD variables."
-msgstr ""
+msgstr "Pode ter variáveis CI/CD personalizadas."
msgid "PipelineSchedules|Create a new pipeline schedule"
-msgstr ""
+msgstr "Criar um novo agendamento de pipeline"
msgid "PipelineSchedules|Create pipeline schedule"
msgstr "Criar agendamento de pipeline"
msgid "PipelineSchedules|Cron timezone"
-msgstr ""
+msgstr "Fuso horário do cron"
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr "Excluir agendamento de pipeline"
@@ -34178,13 +34270,13 @@ msgid "PipelineSchedules|Inactive"
msgstr "Inativo"
msgid "PipelineSchedules|Interval Pattern"
-msgstr ""
+msgstr "Padrão de intervalo"
msgid "PipelineSchedules|Last Pipeline"
msgstr "Último pipeline"
msgid "PipelineSchedules|Learn more in the %{linkStart}scheduled pipelines documentation.%{linkEnd}"
-msgstr ""
+msgstr "Saiba mais na documentação de %{linkStart}pipelines agendados.%{linkEnd}\n"
msgid "PipelineSchedules|New schedule"
msgstr "Novo agendamento"
@@ -34193,22 +34285,22 @@ msgid "PipelineSchedules|Next Run"
msgstr "Próxima Execução"
msgid "PipelineSchedules|No pipeline schedules"
-msgstr ""
+msgstr "Sem agendamentos de pipeline"
msgid "PipelineSchedules|None"
msgstr "Nenhum"
msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?"
-msgstr ""
+msgstr "Apenas o proprietário de um agendamento do pipeline pode fazer alterações nele. Deseja se apropriar desse agendamento?"
msgid "PipelineSchedules|Owner"
msgstr "Proprietário"
msgid "PipelineSchedules|Pipeline schedule successfully deleted."
-msgstr ""
+msgstr "Agendamento de pipeline excluído com sucesso."
msgid "PipelineSchedules|Pipeline schedules"
-msgstr ""
+msgstr "Agendamentos de pipeline"
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Digite uma descrição curta para esta pipeline"
@@ -34217,10 +34309,10 @@ msgid "PipelineSchedules|Run pipeline schedule"
msgstr "Executar agendamento de pipeline"
msgid "PipelineSchedules|Runs for a specific branch or tag."
-msgstr ""
+msgstr "Executa para uma ramificação ou tag específica."
msgid "PipelineSchedules|Runs with the same project permissions as the schedule owner."
-msgstr ""
+msgstr "Executa com as mesmas permissões de projeto que o proprietário do agendamento."
msgid "PipelineSchedules|Successfully scheduled a pipeline to run. Go to the %{linkStart}Pipelines page%{linkEnd} for details. "
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Variáveis"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34424,7 +34510,7 @@ msgid "Pipelines|Could not load artifacts."
msgstr "Não foi possível carregar os artefatos"
msgid "Pipelines|Could not load full configuration content"
-msgstr ""
+msgstr "Não foi possível carregar o conteúdo completo da configuração"
msgid "Pipelines|Description"
msgstr "Descrição"
@@ -34445,10 +34531,10 @@ msgid "Pipelines|Follow these instructions to install GitLab Runner on macOS."
msgstr ""
msgid "Pipelines|Full configuration"
-msgstr ""
+msgstr "Configuração completa"
msgid "Pipelines|Full configuration is view only"
-msgstr ""
+msgstr "A configuração completa é apenas para visualização"
msgid "Pipelines|Get familiar with GitLab CI syntax by setting up a simple pipeline running a \"Hello world\" script to see how it runs, explore how CI/CD works."
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr "Criado"
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr "Para ver as tarefas restantes, acesse a aba %{boldStart}Tarefas%{boldEnd
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr "Gatilho"
-
msgid "Pipeline|Variables"
msgstr "Variáveis"
@@ -35174,7 +35260,7 @@ msgid "Port"
msgstr "Porta"
msgid "Possible to override in each project."
-msgstr ""
+msgstr "Possível substituir em cada projeto."
msgid "Postman collection"
msgstr ""
@@ -35288,7 +35374,7 @@ msgid "Preferences|Configure how dates and times display for you."
msgstr "Configure como as datas e horas são exibidas para você."
msgid "Preferences|Content will be a maximum of 1280 pixels wide."
-msgstr ""
+msgstr "Conteúdo terá no máximo 1280 pixels de largura."
msgid "Preferences|Content will span %{percentage} of the page width."
msgstr "Conteúdo abrangerá %{percentage} da largura da página."
@@ -35353,9 +35439,6 @@ msgstr "Largura do layout"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "Deve ser um número entre %{min} e %{max}"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr "Nota: Você tem a nova navegação ativada, então apenas o tema Escuro altera significativamente a aparência do GitLab."
-
msgid "Preferences|Preview"
msgstr "Pré-visualizar"
@@ -35467,6 +35550,9 @@ msgstr "Discussão anterior não resolvida"
msgid "Primary Action"
msgstr "Ação primária"
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr "Voltar aos painéis"
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr "Criar uma visualização"
@@ -35618,7 +35698,7 @@ msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr ""
msgid "ProductAnalytics|Cube API key"
-msgstr ""
+msgstr "Chave da API do Cube"
msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr "Para mais informações, consulte os %{linkStart} documentos%{linkEnd}."
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr "Voltar"
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,9 +35787,12 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
-msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
+msgid "ProductAnalytics|Snowplow configurator connection string"
msgstr ""
+msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
+msgstr "A cadeia de conexão para sua instância do configurador do Snowplow."
+
msgid "ProductAnalytics|The host to send all tracking events to"
msgstr ""
@@ -35734,11 +35814,8 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
-msgstr ""
+msgstr "Usado para recuperar dados do painel da instância do Cubo."
msgid "ProductAnalytics|User Sessions"
msgstr ""
@@ -35876,7 +35953,7 @@ msgid "Profiles|Add new email"
msgstr "Adicionar novo e-mail"
msgid "Profiles|Add new mirror repository"
-msgstr ""
+msgstr "Adicionar novo repositório espelho"
msgid "Profiles|An error occurred while updating your username, please try again."
msgstr "Ocorreu um erro ao atualizar seu nome de usuário, por favor, tente novamente."
@@ -35968,8 +36045,8 @@ msgstr "Não exibir informações pessoais relacionadas à atividade em seu perf
msgid "Profiles|Edit Profile"
msgstr "Editar perfil"
-msgid "Profiles|Email"
-msgstr "E-mail"
+msgid "Profiles|Email address"
+msgstr ""
msgid "Profiles|Email addresses"
msgstr "Endereços de e-mail"
@@ -36403,9 +36480,6 @@ msgstr "Projeto ou grupo"
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr "Visão geral do projeto"
-
msgid "Project path"
msgstr "Caminho do projeto"
@@ -36842,7 +36916,7 @@ msgid "ProjectSettings|Enable \"Delete source branch\" option by default"
msgstr "Ativar a opção \"Excluir ramificação de origem\" por padrão"
msgid "ProjectSettings|Enable email notifications"
-msgstr ""
+msgstr "Ativar notificações por e-mail"
msgid "ProjectSettings|Enable merge trains"
msgstr "Ativar merge train"
@@ -36851,7 +36925,7 @@ msgid "ProjectSettings|Enable merged results pipelines"
msgstr "Ativar pipelines de resultados mesclados"
msgid "ProjectSettings|Enable sending email notifications for this project"
-msgstr ""
+msgstr "Ativar o envio de notificações por e-mail para este projeto"
msgid "ProjectSettings|Enable suggested reviewers"
msgstr "Ativar revisores sugeridos"
@@ -36895,6 +36969,12 @@ msgstr "Feature flags"
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "Ferramenta flexível para desenvolver ideias e planejar as tarefas nesse projeto."
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr "Forks"
@@ -37030,6 +37110,9 @@ msgstr "Público"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr "Publicar, armazenar e visualizar pacotes em um projeto."
+msgid "ProjectSettings|Relative path:"
+msgstr "Caminho relativo:"
+
msgid "ProjectSettings|Releases"
msgstr "Versões"
@@ -37067,7 +37150,7 @@ msgid "ProjectSettings|Select a project"
msgstr "Selecione um projeto"
msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
-msgstr "Selecione a ramificação padrão para este projeto e configure o modelo para nomes de ramificações."
+msgstr "Selecionar a ramificação padrão para este projeto e configure o modelo para nomes de ramificações."
msgid "ProjectSettings|Select the project containing Analytics Dashboards configuration files."
msgstr "Selecione o projeto que contém os arquivos de configuração dos painéis analíticos."
@@ -37102,6 +37185,9 @@ msgstr "Squashing nunca é executado e a caixa de seleção está oculta."
msgid "ProjectSettings|Status checks must succeed"
msgstr "As verificações de status devem ser bem-sucedidas"
+msgid "ProjectSettings|Storage name:"
+msgstr "Nome do armazenamento:"
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37361,7 +37447,7 @@ msgid "Projects help you organize your work. They contain your file repository,
msgstr ""
msgid "Projects in this group can use Git LFS"
-msgstr ""
+msgstr "Projetos neste grupo podem usar Git LFS"
msgid "Projects shared with %{group_name}"
msgstr "Projetos compartilhados com %{group_name}"
@@ -37862,7 +37948,7 @@ msgid "Protected paths"
msgstr "Caminhos protegidos"
msgid "Protected tags"
-msgstr ""
+msgstr "Tags protegidas"
msgid "ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported."
msgstr "%{wildcards_link_start}Caracteres curinga%{wildcards_link_end} como %{code_tag_start}*-stable%{code_tag_end} ou %{code_tag_start}production/*%{code_tag_end} são suportados."
@@ -37921,6 +38007,12 @@ msgstr "Aprovação do proprietário do código"
msgid "ProtectedBranch|Create wildcard"
msgstr "Criar curinga"
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37970,7 +38062,7 @@ msgid "ProtectedBranch|Tag"
msgstr ""
msgid "ProtectedBranch|There are currently no protected branches, to protect a branch start by creating a new one above."
-msgstr ""
+msgstr "Atualmente não há ramificações protegidas, para proteger uma ramificação comece criando uma acima."
msgid "ProtectedBranch|Toggle allowed to force push"
msgstr "Alternar para forçar push"
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr "O que são ramificações protegidas?"
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,12 +38140,15 @@ msgstr "Excluir regra de implantação"
msgid "ProtectedEnvironments|Edit"
msgstr "Editar"
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
-msgstr ""
-
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr "Proteger um ambiente"
+
+msgid "ProtectedEnvironments|Protected environments"
+msgstr "Ambientes protegidos"
+
msgid "ProtectedEnvironments|Remove approval rule"
msgstr "Remover regra de aprovação"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr "Salvar"
+msgid "ProtectedEnvironments|Select users"
+msgstr "Selecionar usuários"
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr "Usuários"
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} poderá ser editado por desenvolvedores. Tem certeza disso?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr "Selecionar grupos"
-msgid "ProtectedEnvironment|Select users"
-msgstr "Selecionar usuários"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38166,7 +38264,7 @@ msgid "ProtectedTags|Unprotect tag"
msgstr ""
msgid "ProtectedTags|default"
-msgstr ""
+msgstr "padrão"
msgid "ProtectedTag|By default, protected tags restrict who can modify the tag."
msgstr "Por padrão, tags protegidas restringem quem pode modificar a tag."
@@ -38207,9 +38305,6 @@ msgstr "Instruções de provisão"
msgid "Provisioned by:"
msgstr "Provisionado por:"
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr "Público"
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr "Receber notificações sobre sua própria atividade"
-msgid "Receive product marketing emails"
-msgstr "Receber e-mails de marketing de produtos"
-
msgid "Recent"
msgstr "Recente"
@@ -38713,34 +38805,10 @@ msgstr "Enviar e-mails para usuários"
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr "Ativar minutos de computação gratuitos"
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr "Para manter o GitLab livre de spam e abuso, pedimos que você verifique sua identidade com um método de pagamento válido, como cartão de débito ou crédito. Até então, você não pode usar minutos de computação gratuitos para criar seu aplicativo."
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr "Remover prioridade"
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr "Remover revisor"
@@ -39090,6 +39155,9 @@ msgstr "Remover o e-mail secundário"
msgid "Remove spent time"
msgstr "Remover tempo gasto"
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr "Remover estimativa de tempo"
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr "Remover usuário"
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr "Remover usuário do grupo"
@@ -39381,12 +39446,6 @@ msgstr "Por que você está reportando este usuário?"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Denunciado em %{timeAgo} por %{reportedBy}"
-msgid "Reported by"
-msgstr "Reportado por"
-
-msgid "Reported by %{reporter}"
-msgstr "Reportado por %{reporter}"
-
msgid "Reporter"
msgstr "Relator"
@@ -39693,9 +39752,6 @@ msgstr "Recálculo de uso do repositório iniciado"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "Selecionar"
-
msgid "Request"
msgstr "Requisição"
@@ -39718,7 +39774,7 @@ msgid "Request review from"
msgstr "Solicitar revisão de"
msgid "Request time"
-msgstr ""
+msgstr "Hora da solicitação"
msgid "Request to link SAML account must be authorized"
msgstr ""
@@ -40042,7 +40098,7 @@ msgid "Review time"
msgstr "Tempo de revisão"
msgid "Review time is the amount of time since the first comment in a merge request."
-msgstr ""
+msgstr "O tempo de revisão é a quantidade de tempo desde o primeiro comentário em uma solicitação de mesclagem."
msgid "Reviewer"
msgid_plural "%d Reviewers"
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr "Membros do %{type} podem registrar executores"
msgid "Runners|Minor version upgrades are available."
msgstr "Atualizações de versão secundária estão disponíveis."
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr "Tags múltiplas devem ser separadas por vírgula. Por exemplo, %{example}."
@@ -40799,7 +40861,7 @@ msgid "Runners|Running"
msgstr "Executando"
msgid "Runners|Running Jobs"
-msgstr ""
+msgstr "Tarefas em execução"
msgid "Runners|Runs untagged jobs"
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr "Selecione projetos para atribuir a este executor"
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr "O tempo que leva para um executor de instância selecionar uma tarefa. A
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr "Para permitir que %{strongOpen}%{group_name}%{strongClose} gerencie sua
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "O SSO da sua organização foi conectado à sua conta do GitLab"
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr "Token SCIM"
@@ -41225,9 +41293,6 @@ msgstr "Salvar nota interna"
msgid "Save password"
msgstr "Salvar senha"
-msgid "Save pipeline schedule"
-msgstr "Salvar agendamento da pipeline"
-
msgid "Saving"
msgstr "Salvando"
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,11 +41431,14 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
-msgstr ""
+msgid "ScanResultPolicy|Attribute is:"
+msgstr "O atributo é:"
+
+msgid "ScanResultPolicy|Attribute:"
+msgstr "Atributo:"
-msgid "ScanResultPolicy|Choose an option"
-msgstr "Escolha uma opção"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
+msgstr "Os atributos são aplicados automaticamente pelos verificadores"
msgid "ScanResultPolicy|Choose criteria type"
msgstr "Escolha o tipo de critério"
@@ -41384,6 +41452,24 @@ msgstr "Variáveis de CI personalizadas"
msgid "ScanResultPolicy|Except"
msgstr "Exceto"
+msgid "ScanResultPolicy|False positive"
+msgstr "Falso positivo"
+
+msgid "ScanResultPolicy|Fix available"
+msgstr "Correção disponível"
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr "Correção disponível é aplicável apenas ao contêiner e verificação de dependência"
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr "É"
+
+msgid "ScanResultPolicy|Is not"
+msgstr "Não é"
+
msgid "ScanResultPolicy|License is:"
msgstr "Licença é:"
@@ -41396,8 +41482,8 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
-msgstr "Nova severidade"
+msgid "ScanResultPolicy|New attribute"
+msgstr "Novo atributo"
msgid "ScanResultPolicy|New status"
msgstr "Novo status"
@@ -41408,8 +41494,8 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
-msgstr ""
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
+msgstr "Apenas 2 critérios de atributo são permitidos"
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
msgstr ""
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr "Selecione um tipo de verificação antes de adicionar critérios"
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41481,7 +41582,7 @@ msgid "Scanner profile not found for given parameters"
msgstr ""
msgid "Schedule a new pipeline"
-msgstr "Agendar nova pipeline"
+msgstr "Agendar novo pipeline"
msgid "Schedule-based escalation rules must have a schedule in the same project as the policy"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr "Pesquisar um grupo"
msgid "Search an environment spec"
msgstr "Pesquisar uma especificação de ambiente"
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "Pesquisar responsável"
@@ -41630,15 +41734,12 @@ msgstr "Pesquisar marcos"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
-msgstr "Pesquisar ou filtrar resultados..."
-
msgid "Search or filter results…"
msgstr "Pesquisar ou filtrar resultados…"
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr "Pesquisar na página"
@@ -41865,6 +41966,9 @@ msgstr "Configuração de segurança"
msgid "Security dashboard"
msgstr "Painel de segurança"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41995,7 +42099,7 @@ msgid "SecurityConfiguration|Security training"
msgstr "Treinamento de segurança"
msgid "SecurityConfiguration|Simulate breach and attack scenarios against your running application by attempting to detect and exploit known vulnerabilities."
-msgstr ""
+msgstr "Simule cenários de violação e ataque contra seu aplicativo em execução, tentando detectar e explorar vulnerabilidades conhecidas."
msgid "SecurityConfiguration|Something went wrong. Please refresh the page, or try again later."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr "e "
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr "ou "
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr "E verificações a serem realizadas:"
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr "Ativado"
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr "Forçar segurança para este projeto. %{linkStart}Mais informações.%{linkEnd}"
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr "Falha ao carregar imagens."
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr "Grupos"
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,14 +42619,20 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr "ramificação"
msgid "SecurityOrchestration|branches"
msgstr "ramificações"
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
-msgstr "pelo agente chamado %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
+msgstr ""
msgid "SecurityOrchestration|group level branch input"
msgstr ""
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr "Adicionar comentário e descartar"
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "Adicionar ou remover projetos para monitorar na área de segurança. Projetos incluídos nessa lista terão seus resultados exibidos no painel de segurança e relatório de vulnerabilidade."
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr "Configurar teste de segurança"
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr "Criar issue"
@@ -42647,9 +42787,15 @@ msgstr "Detecção"
msgid "SecurityReports|Development vulnerabilities"
msgstr "Vulnerabilidades de desenvolvimento"
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "Dispensar vulnerabilidade"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "Dispensar '%{vulnerabilityName}'"
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr "O relatório expirou"
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr "Salvar comentário"
-
msgid "SecurityReports|Scan details"
msgstr "Detalhes da verificação"
@@ -42844,8 +42990,8 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr "Enviar vulnerabilidade"
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
-msgstr "O relatório de vulnerabilidade mostra resultados de verificações bem-sucedidas na ramificação padrão do seu projeto, registros de vulnerabilidade adicionados manualmente e vulnerabilidades encontradas na verificação de ambientes operacionais. %{linkStart}Saiba mais.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
msgstr ""
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr "Enviar notificação por e-mail"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "Envie e-mails para ajudar a orientar novos usuários no processo de integração."
-
msgid "Send emails to users upon account deactivation."
msgstr "Envie e-mails aos usuários após a desativação da conta."
@@ -43264,6 +43407,9 @@ msgstr "As chaves de contas de serviço autorizam o GitLab a implantar seu proje
msgid "Service Desk"
msgstr "Central de serviços"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr "Não é possível criar um e-mail personalizado"
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43307,7 +43465,7 @@ msgid "ServiceDesk|Copy Service Desk email address"
msgstr ""
msgid "ServiceDesk|Custom email address"
-msgstr ""
+msgstr "Endereço de e-mail personalizado"
msgid "ServiceDesk|Custom email address could not be verified."
msgstr "Endereço de e-mail personalizado não pôde ser verificado."
@@ -43321,9 +43479,15 @@ msgstr "A verificação do endereço de e-mail personalizado já foi processada
msgid "ServiceDesk|Custom email already exists"
msgstr "E-mail personalizado já existe"
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr "E-mail personalizado não existe"
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,47 +43497,80 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr "Ativar central de Serviços"
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr "Para obter ajuda na configuração da central de serviços para sua instância, entre em contato com um administrador."
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr "issues criadas a partir da central de serviços aparecerão aqui. Cada comentário torna-se da conversa por e-mail"
+msgid "ServiceDesk|Keep custom email"
+msgstr "Manter e-mail personalizado"
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr "Parâmetros ausentes"
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr "Por favor, compartilhe seus comentários sobre este recurso no %{linkStart} issue de feedback%{linkEnd}"
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
-msgid "ServiceDesk|SMTP password"
+msgid "ServiceDesk|SMTP host issue"
msgstr ""
+msgid "ServiceDesk|SMTP password"
+msgstr "Senha SMTP"
+
msgid "ServiceDesk|SMTP password is required and must be at least 8 characters long."
-msgstr ""
+msgstr "A senha SMTP é necessária e deve ter pelo menos 8 caracteres."
msgid "ServiceDesk|SMTP port"
-msgstr ""
+msgstr "Porta SMTP"
msgid "ServiceDesk|SMTP port is required and must be a port number larger than 0."
-msgstr ""
+msgstr "A porta SMTP é necessária e deve ser um número de porta maior que 0."
msgid "ServiceDesk|SMTP username"
-msgstr ""
+msgstr "Nome de usuário SMTP"
msgid "ServiceDesk|SMTP username is required."
-msgstr ""
+msgstr "O nome de usuário SMTP é obrigatório."
msgid "ServiceDesk|Save and test connection"
-msgstr ""
+msgstr "Salvar e testar a conexão"
msgid "ServiceDesk|Saved custom email address and started verification."
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr "Configuração da Central de serviços ausente"
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr "Configuração da Central de serviços ou objeto de verificação ausente"
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr "As credenciais fornecidas (nome de usuário e senha) foram rejeitadas pelo servidor SMTP."
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr "O e-mail recebido não continha o token de verificação que foi enviado para o seu endereço de e-mail."
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr "Para Ativar a central de serviços nesta instância, um administrador de instância deve primeiro configurar o e-mail de entrada."
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr "Use a central de serviços para conectar com seus usuários e oferecer suporte ao cliente por e-mail dentro do GitLab"
msgid "ServiceDesk|User cannot manage project."
msgstr "O usuário não pode gerenciar o projeto."
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr "Seus usuários podem enviar e-mails para este endereço:"
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr "Duração da sessão (minutos)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr "Não foi possível verificar o usuário. Ocorreu um erro ao carregar o desafio de verificação do usuário. Atualize para tentar novamente."
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr "Define a estimativa de tempo como %{time_estimate}."
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr "Definir %{epic_ref} como épico pai."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr "Alguém entrou na sua conta %{host} de um novo local"
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Alguém, esperamos que você, solicitou a redefinição da senha da sua conta do GitLab em %{link_to_gitlab}."
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "Alguma coisa deu errado"
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr "Algo deu errado ao obter os comentários mais recentes."
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr "Carregar nova licença"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr "Adicionar lugares"
@@ -45653,6 +45901,9 @@ msgstr "Desativado com sucesso"
msgid "Successfully deleted WebAuthn device."
msgstr "Dispositivo WebAuthn excluído com sucesso."
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "E-mail removido com sucesso."
@@ -45671,6 +45922,9 @@ msgstr "Desbanido com sucesso"
msgid "Successfully unblocked"
msgstr "Desbloqueado com sucesso"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr "Desbloqueado com sucesso"
@@ -46229,7 +46483,7 @@ msgid "TagsPage|Create tag"
msgstr "Criar tag"
msgid "TagsPage|Delete protected tag"
-msgstr ""
+msgstr "Excluir tag protegida"
msgid "TagsPage|Delete tag"
msgstr "Apagar tag"
@@ -46295,7 +46549,7 @@ msgid "TagsPage|Use git tag command to add a new one:"
msgstr "Use o comando \"git tag\" para adiciona uma nova tag:"
msgid "TagsPage|Yes, delete protected tag"
-msgstr ""
+msgstr "Sim, excluir tag protegida"
msgid "TagsPage|Yes, delete tag"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr "Destino"
@@ -46344,8 +46601,14 @@ msgstr ""
msgid "Target branch"
msgstr "Ramificação de destino"
-msgid "Target branch or tag"
-msgstr "Ramificação ou tag de destino"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
+msgstr ""
msgid "Target branch: %{target_branch}"
msgstr "Ramificações de destino: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr "O YAML analisado é muito grande"
-
msgid "The password for the Jenkins server."
msgstr "A senha para o servidor Jenkins."
@@ -47301,7 +47561,7 @@ msgid "The start date must be earlier than the end date."
msgstr "A data de início deve ser anterior à data de término."
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
-msgstr ""
+msgstr "O assunto será usado como título da nova edição e a mensagem será a descrição. %{quickActionsLinkStart}Ações rápidas%{quickActionsLinkEnd} e estilo com %{markdownLinkStart}Markdown%{markdownLinkEnd} são suportados."
msgid "The tag name can't be changed for an existing release."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr "Atualmente, não há repositórios espelhados."
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "Existem conflitos de merge"
@@ -47372,9 +47635,6 @@ msgstr "Não há chaves SSH com acesso à sua conta."
msgid "There are no Spam Logs"
msgstr "Não há registros de spam"
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Essa solicitação de mesclagem está bloqueado."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,11 +48505,11 @@ msgstr "Este pipeline faz uso de uma configuração de CI/CD predefinida habilit
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
-msgstr "Este pipeline foi disparando por um agendamento."
+msgid "This pipeline was created by a schedule."
+msgstr ""
msgid "This process deletes the project repository and all related resources."
msgstr "Esse processo exclui o repositório do projeto e todos os recursos relacionados."
@@ -48252,7 +48524,7 @@ msgid "This project does not belong to a group and cannot make use of group runn
msgstr "Este projeto não pertence a um grupo e não pode usar executores de grupo."
msgid "This project does not have %{service_desk_link_start}Service Desk%{service_desk_link_end} enabled, so the user who created the issue will no longer receive email notifications about new activity."
-msgstr ""
+msgstr "Este projeto não tem a %{service_desk_link_start}Central de serviços%{service_desk_link_end} ativada, portanto, o usuário que criou a issue não receberá mais notificações por e-mail sobre novas atividades."
msgid "This project does not have a wiki homepage yet"
msgstr "Este projeto ainda não tem uma página inicial na wiki"
@@ -48360,7 +48632,7 @@ msgid "This user has an unconfirmed email address. You may force a confirmation.
msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
-msgstr ""
+msgstr "Este usuário não tem %{accessTokenTypePlural} ativo."
msgid "This user has no identities"
msgstr "Esse usuário não tem identidades"
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,8 +48784,8 @@ msgstr "Fuso horário"
msgid "TimeTrackingEstimated|Est"
msgstr "Est"
-msgid "TimeTrackingReport|From"
-msgstr "De"
+msgid "TimeTrackingReport|From the start of"
+msgstr ""
msgid "TimeTrackingReport|Run report"
msgstr "Executar relatório"
@@ -48533,8 +48805,8 @@ msgstr "Resumo"
msgid "TimeTrackingReport|Time spent"
msgstr "Tempo gasto"
-msgid "TimeTrackingReport|To"
-msgstr "Para"
+msgid "TimeTrackingReport|To the end of"
+msgstr ""
msgid "TimeTrackingReport|Total time spent: "
msgstr "Tempo total gasto: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48987,7 +49259,7 @@ msgid "To set up this integration:"
msgstr ""
msgid "To specify the notification level per project of a group you belong to, visit the project page and change the notification level there."
-msgstr ""
+msgstr "Para especificar o nível de notificação por projeto de um grupo ao qual você pertence, visite a página do projeto e altere o nível de notificação lá."
msgid "To start using GitLab Enterprise Edition, upload the %{codeOpen}.gitlab-license%{codeClose} file or enter the license key you have received from GitLab Inc."
msgstr ""
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "Amanhã"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr "Total"
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr "Rastreamento"
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49370,7 +49654,7 @@ msgid "Tracing|Failed to enable tracing."
msgstr ""
msgid "Tracing|Failed to load page."
-msgstr ""
+msgstr "Falha ao carregar a página."
msgid "Tracing|Failed to load trace details."
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49550,10 +49846,10 @@ msgid "Trials|Looking to do more with GitLab?"
msgstr ""
msgid "Trials|Upgrade your plan for more security features"
-msgstr ""
+msgstr "Atualize seu plano para obter mais recursos de segurança"
msgid "Trials|With GitLab Ultimate you can detect and address vulnerabilities in your application."
-msgstr ""
+msgstr "Com o GitLab Ultimate, você pode detectar e solucionar vulnerabilidades em seu aplicativo."
msgid "Trials|You can apply your trial to a new group or an existing group."
msgstr "Você pode aplicar sua avaliação a um novo grupo ou a um grupo existente."
@@ -49564,7 +49860,7 @@ msgstr[0] "Você tem %{daysRemaining} dias restantes no GitLab %{planName}!"
msgstr[1] "Você tem %{daysRemaining} dias restantes no GitLab %{planName}!"
msgid "Trials|Your 30-day trial has ended"
-msgstr ""
+msgstr "Sua avaliação de 30 dias terminou"
msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
msgstr "Sua avaliação termina em %{boldStart}%{trialEndDate}%{boldEnd}. Esperamos que você esteja gostando dos recursos do GitLab %{planName}.Para manter esses recursos após o término da avaliação, você precisará comprar uma assinatura. (Você também pode escolher o GitLab Premium se ele atender às suas necessidades.)"
@@ -49654,13 +49950,13 @@ msgid "Try grouping with different labels"
msgstr "Tente agrupar com etiquetas diferentes"
msgid "Try out **styling** _your_ content right here or read the [direction](%{directionUrl})."
-msgstr ""
+msgstr "Experimente o **estilo** em _seu_ conteúdo aqui ou leia a [instrução](%{directionUrl})."
msgid "Try out GitLab Pipelines"
msgstr ""
msgid "Try the rich text editor now"
-msgstr ""
+msgstr "Experimente o editor de texto com formatação agora"
msgid "Try the troubleshooting steps here."
msgstr "Tente as etapas de solução de problemas aqui."
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "O USUÃRIO SERÃ BLOQUEADO! Tem certeza?"
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr "Não foi possível carregar a página"
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr "Não foi possível analisar JSON"
@@ -49911,9 +50207,6 @@ msgstr "Não é possível atualizar este épico neste momento."
msgid "Unable to update this issue at this time."
msgstr "Não é possível atualizar esta issue neste momento."
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr "Desaprovar uma solicitação de mesclagem"
@@ -49992,6 +50285,9 @@ msgstr "Infelizmente, sua mensagem de e-mail para o GitLab não pôde ser proces
msgid "Unhappy?"
msgstr "Infeliz?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr "Compre minutos de computação adicionais"
msgid "UsageQuota|Buy storage"
msgstr "Comprar armazenamento"
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr "Pacotes de código e imagens de contêiner."
@@ -50388,12 +50687,12 @@ msgstr "Registro de contêiner"
msgid "UsageQuota|Dependency proxy"
msgstr "Proxy de dependência"
-msgid "UsageQuota|Filter chart by month"
-msgstr "Filtrar gráfico por mês"
-
msgid "UsageQuota|Filter charts by year"
msgstr "Filtrar gráficos por ano"
+msgid "UsageQuota|Filter projects data by month"
+msgstr "Filtrar dados de projetos por mês"
+
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
msgstr "Para obter mais informações sobre limites de armazenamento, consulte nosso %{faq_link_start}FAQ%{link_end}."
@@ -50434,11 +50733,14 @@ msgid "UsageQuota|Namespace entities"
msgstr ""
msgid "UsageQuota|Namespace overview"
-msgstr ""
+msgstr "Visão geral do espaço de nome"
msgid "UsageQuota|Namespace storage used"
msgstr "Armazenamento de espaço de nome usado"
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr "Nenhum dado de uso de computação disponível."
@@ -50458,7 +50760,7 @@ msgid "UsageQuota|Precise calculation of Container Registry storage size is dela
msgstr ""
msgid "UsageQuota|Projects under this namespace have %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
-msgstr ""
+msgstr "Projetos sob este espaço de nome têm %{planLimit} de armazenamento. %{linkStart}Como os limites são aplicados?%{linkEnd}"
msgid "UsageQuota|Recalculate repository usage"
msgstr "Recalcular o uso do repositório"
@@ -50488,7 +50790,7 @@ msgid "UsageQuota|Storage"
msgstr "Armazenamento"
msgid "UsageQuota|Storage per project included in %{planName} subscription"
-msgstr ""
+msgstr "Armazenamento por projeto incluído na assinatura %{planName}"
msgid "UsageQuota|Storage type"
msgstr "Tipo de armazenamento"
@@ -50505,15 +50807,15 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr "O gráfico e a tabela abaixo mostram o uso para %{month} de %{year}"
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr "A tabela abaixo mostra o uso desde %{usageSince}"
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr ""
@@ -50725,7 +51027,7 @@ msgid "Use template"
msgstr "Utilizar modelo"
msgid "Use the %{strongStart}Test%{strongEnd} option above to create an event."
-msgstr ""
+msgstr "Use a opção %{strongStart}Teste%{strongEnd} acima para criar um evento."
msgid "Use the Apple App Store Connect integration to easily connect to the Apple App Store with Fastlane in CI/CD pipelines."
msgstr "Use a integração da Apple App Store Connect para se conectar facilmente à Apple App Store com Fastlane em pipelines de CI/CD."
@@ -50740,7 +51042,7 @@ msgid "Use the link below to confirm your email address."
msgstr ""
msgid "Use the new rich text editor to see your text and tables fully formatted as you type. No need to remember any formatting syntax, or switch between preview and editing modes!"
-msgstr ""
+msgstr "Use o novo editor de texto com formatação para ver seu texto e tabelas totalmente formatados enquanto você digita. Não há necessidade de lembrar qualquer sintaxe de formatação ou alternar entre os modos de visualização e edição!"
msgid "Use the public cloud instance URL (%{kroki_public_url}) or %{install_link_start}install Kroki%{install_link_end} on your own infrastructure and use your own instance URL."
msgstr ""
@@ -50778,13 +51080,13 @@ msgid "Used by more than 100,000 organizations, GitLab is the most popular solut
msgstr ""
msgid "Used for account notifications if a %{openingTag}group-specific email address%{closingTag} is not set."
-msgstr ""
+msgstr "Usado para notificações de conta se um endereço de e-mail%{closingTag} específico do grupo %{openingTag}não estiver definido."
msgid "Used for avatar detection. You can change it in your %{openingTag}profile settings%{closingTag}."
-msgstr ""
+msgstr "Usado para detecção de avatar. Você pode alterá-lo em suas %{openingTag}configurações de perfil%{closingTag}."
msgid "Used for web based operations, such as edits and merges."
-msgstr ""
+msgstr "Usado para operações baseadas na web, como edições e mesclagens."
msgid "Used programming language"
msgstr "Linguajem de programação usada"
@@ -51185,6 +51487,9 @@ msgstr "Nome de usuário está disponível."
msgid "Username or email"
msgstr "Nome de usuário ou e-mail"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Nome de usuário:"
@@ -51748,7 +52053,7 @@ msgid "View the latest successful deployment to this environment"
msgstr ""
msgid "View trigger token usage examples"
-msgstr ""
+msgstr "Ver exemplos de uso de token de gatilho"
msgid "View usage details"
msgstr "Ver detalhes de uso"
@@ -51888,6 +52193,9 @@ msgstr "Detalhes"
msgid "VulnerabilityExport|Detected At"
msgstr "Detectado em"
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr "Nome do grupo"
@@ -51915,17 +52223,20 @@ msgstr "Ferramenta"
msgid "VulnerabilityExport|Vulnerability"
msgstr "Vulnerabilidade"
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Confirmado%{statusEnd} %{timeago} por %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Dispensado%{statusEnd} %{timeago} por %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Resolvido%{statusEnd} %{timeago} por %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr ""
@@ -52167,6 +52478,9 @@ msgstr "Arquivo:"
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr "Ocultar prompt"
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr "Ocorreu um erro inesperado. %{linkStart}Por favor tente novamente%{linkEnd}."
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr "AVISO:"
@@ -52387,7 +52701,7 @@ msgid "We heard back from your device. You have been authenticated."
msgstr ""
msgid "We invite you to %{featureLinkStart}request a feature%{featureLinkEnd}, %{bugLinkStart}report a bug%{bugLinkEnd} or %{feedbackLinkStart}share feedback%{feedbackLinkEnd}"
-msgstr ""
+msgstr "Convidamos você a %{featureLinkStart}solicitar um recurso%{featureLinkEnd}, %{bugLinkStart}relatar um erro%{bugLinkEnd} ou %{feedbackLinkStart}compartilhar feedback%{feedbackLinkEnd}"
msgid "We recommend a work email address."
msgstr ""
@@ -52414,7 +52728,7 @@ msgid "We want to let you know %{username} has exceeded the Git rate limit due t
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
-msgstr ""
+msgstr "Notificaremos %{inviter} que você recusou o convite para ingressar no GitLab. Você deixará de receber lembretes."
msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
msgstr ""
@@ -52570,7 +52884,7 @@ msgid "Webhooks|A wiki page is created or updated."
msgstr "Uma página de wiki é criada ou atualizada."
msgid "Webhooks|An emoji is awarded or revoked. %{help_link}?"
-msgstr ""
+msgstr "Um emoji é concedido ou revogado. %{help_link}?"
msgid "Webhooks|An issue is created, updated, closed, or reopened."
msgstr "Uma issue é criada, atualizada, fechada ou reaberta."
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr "Eventos de versões"
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr "Verificação SSL"
@@ -52749,15 +53069,6 @@ msgstr "Bem-vindo a uma nova experiência de navegação"
msgid "Welcome, %{name}!"
msgstr "Bem-vindo, %{name}!"
-msgid "What are group audit events?"
-msgstr "O que são eventos de auditoria em grupo?"
-
-msgid "What are instance audit events?"
-msgstr "O que são eventos de auditoria de instância?"
-
-msgid "What are project audit events?"
-msgstr "O que são eventos de auditoria de projetos?"
-
msgid "What are some examples?"
msgstr "Quais são alguns exemplos?"
@@ -52858,7 +53169,7 @@ msgid "Which API requests are affected?"
msgstr ""
msgid "Which emoji events trigger webhooks"
-msgstr ""
+msgstr "Quais eventos de emoji ativam webhooks"
msgid "While it's rare to have no vulnerabilities, it can happen. In any event, we ask that you please double check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr "Criar %{workItemType}"
-msgid "WorkItem|Create objective"
-msgstr "Criar objetivo"
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr "Data de vencimento"
msgid "WorkItem|Existing task"
msgstr "Tarefa existente"
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr "Somente histórico"
@@ -53246,14 +53557,20 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr "Vincule itens de trabalho para mostrar que eles estão relacionados ou que um está bloqueando outros."
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr "Marcar como concluído"
msgid "WorkItem|Milestone"
msgstr "Marco"
-msgid "WorkItem|New objective"
-msgstr "Novo objetivo"
+msgid "WorkItem|New %{workItemType}"
+msgstr ""
msgid "WorkItem|New task"
msgstr "Nova tarefa"
@@ -53289,7 +53606,7 @@ msgid "WorkItem|Objective"
msgstr "Objetivo"
msgid "WorkItem|Only project members with at least the Reporter role, the author, and assignees can view or be notified about this %{workItemType}."
-msgstr ""
+msgstr "WorkItem|Apenas membros do projeto com pelo menos a função Relator, o autor e os responsáveis podem visualizar ou ser notificados sobre isso %{workItemType}"
msgid "WorkItem|Open"
msgstr "Abrir"
@@ -53396,9 +53713,6 @@ msgstr "Caso de teste"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,8 +53743,8 @@ msgstr ""
msgid "Workspaces"
msgstr "Espaços de trabalho"
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
-msgstr "Um espaço de trabalho é um ambiente de sandbox virtual para seu código no GitLab. Você pode criar um espaço de trabalho para um projeto público."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
+msgstr ""
msgid "Workspaces|Cancel"
msgstr "Cancelar"
@@ -53528,9 +53842,6 @@ msgstr "Estado desconhecido"
msgid "Workspaces|Workspaces"
msgstr "Espaços de trabalho"
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr "Você pode criar um espaço de trabalho apenas para projetos públicos."
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr "Você não pode criar um espaço de trabalho para este projeto"
@@ -53574,7 +53885,7 @@ msgid "Write your release notes or drag your files here…"
msgstr "Escreva suas notas de lançamento ou arraste seus arquivos aqui…"
msgid "Writing just got easier"
-msgstr ""
+msgstr "A escrita acabou de ficar mais fácil"
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53843,7 +54160,7 @@ msgid "You can invite another group to %{project_name}."
msgstr ""
msgid "You can modify this job's CI/CD variables before running it again."
-msgstr ""
+msgstr "Você pode modificar as variáveis CI/CD deste trabalho antes de executá-lo novamente."
msgid "You can move around the graph by using the arrow keys."
msgstr "Você pode mover o gráfico usando as setas do teclado."
@@ -53993,13 +54310,10 @@ msgid "You don't have any active chat names."
msgstr "Você não tem nenhum nome de bate-papo ativo."
msgid "You don't have any applications."
-msgstr ""
+msgstr "Você não tem nenhum aplicativo."
msgid "You don't have any authorized applications."
-msgstr ""
-
-msgid "You don't have any deployments right now."
-msgstr "Você não tem implantações nesse momento."
+msgstr "Você não tem nenhum aplicativo autorizado."
msgid "You don't have any open merge requests"
msgstr "Você não tem nenhuma solicitação de mesclagem em aberto"
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "Seus aplicativos autorizados"
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr "Seu navegador não suporta WebAuthn. Por favor, use um navegador compatível, por exemplo, Chrome (67+) ou Firefox (60+)."
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr "Seu projeto não está mais recebendo os benefícios do GitLab Ultimate a partir de 01/07/2022. Conforme notificado anteriormente no aplicativo, os projetos públicos de código aberto no nível Gratuito podem se inscrever no GitLab for Open Source Program para receber os benefícios do GitLab Ultimate. Consulte o %{faq_link_start}FAQ%{link_end} para obter mais detalhes."
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr "permitido falhar"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54869,7 +55183,7 @@ msgid "at least the Reporter role"
msgstr ""
msgid "at least the Reporter role, the author, and assignees"
-msgstr ""
+msgstr "pelo menos a função de Relator, o autor e os responsáveis"
msgid "attach a new file"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr "não pode ser alterado quando atribuído a um épico"
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr "criado por"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr "por exemplo %{token}"
msgid "eg party_tanuki"
msgstr "por exemplo, party_tanuki"
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] "arquivos"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -55976,7 +56299,7 @@ msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Select %{boldStart}Mark as
msgstr "%{boldStart}Mesclagem bloqueada:%{boldEnd} Selecione %{boldStart}Marca como pronta%{boldEnd} para removê-lo do status do Rascunho."
msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} Users who can write to the source or target branches can resolve the conflicts."
-msgstr ""
+msgstr "%{boldStart}Mesclagem bloqueada:%{boldEnd} Os usuários que podem gravar nas ramificações de origem ou destino podem resolver os conflitos."
msgid "mrWidget|%{boldStart}Merge blocked:%{boldEnd} a Jira issue key must be mentioned in the title or description."
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr "deve ser especificado"
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr "não deve ser um proprietário do namespace"
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr "meu-grupo-incrível"
@@ -56429,6 +56761,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, e %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr "%{slash_command} adiciona ou subtrai o tempo já gasto."
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr "nome da tag"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr "total deve ser menor ou igual a %{size}"
msgid "triggered"
msgstr "disparado"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr "configurações de autenticação de dois fatores"
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "versão %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/pt_PT/gitlab.po b/locale/pt_PT/gitlab.po
index 9d398e0817e..ed19ac5ed3c 100644
--- a/locale/pt_PT/gitlab.po
+++ b/locale/pt_PT/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: pt-PT\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " ou "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} indisponível"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr "%{verb} %{time_spent_value} tempo passado."
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr "+ mais %{count}"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ mais %{moreCount}"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Aceitar convite"
@@ -2444,6 +2494,9 @@ msgstr "Grupos"
msgid "AccessDropdown|Roles"
msgstr "Funções"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "Utilizadores"
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr "Adicionar à revisão"
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr "Ocorreu um erro ao pré-visualizar o blob"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr "Ocorreu um erro ao buscar as cores das etiquetas."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "Ocorreu um erro ao atualizar aprovadores"
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr "Tens a certeza de que desejas apagar este dispositivo? Esta ação não
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Tens a certeza de que desejas apagar este agendamento de pipeline?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "A verificar a disponibilidade de %{text}…"
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr "Escolhe um modelo..."
msgid "Choose a type..."
msgstr "Escolhe um tipo..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Escolher um ficheiro…"
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "Não podes usar a Variável Mascarada com o valor atual"
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr "Remover linha da variável"
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Tipo"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Valor"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (Todos os ambientes)"
-
msgid "CiVariable|All environments"
msgstr "Todos os ambientes"
@@ -10359,6 +10487,9 @@ msgstr "Clientes"
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Clone"
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
+msgstr ""
+
+msgid "IssuesAnalytics|Closed"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,12 +31343,15 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
-msgstr "Nenhumas outras etiquetas com tal nome ou descrição"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
msgstr ""
+msgid "No other labels with such name or description"
+msgstr "Nenhumas outras etiquetas com tal nome ou descrição"
+
msgid "No parent group"
msgstr ""
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr "Receber notificações sobre a tua própria atividade"
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr "Pesquisar objetivos"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr "Não tens nenhumas implantações por enquanto."
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr "permissão para falhar"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "versão %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po
index c8fc8578791..50930b8b596 100644
--- a/locale/ro_RO/gitlab.po
+++ b/locale/ro_RO/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ro\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 15:58\n"
+"PO-Revision-Date: 2023-09-12 12:31\n"
msgid " %{start} to %{end}"
msgstr " de la %{start} până la %{end}"
@@ -46,6 +46,12 @@ msgstr " și "
msgid " and %{sliced}"
msgstr " și %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid " or "
msgstr " sau "
@@ -766,9 +772,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr "%{count} greutate totală"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} nu a putut fi găsită."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} zile până când etichetele sunt înlăturate automat"
@@ -814,8 +817,8 @@ msgstr "%{edit_in_new_fork_notice} Încercați să încărcați din nou un fiși
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr "%{enable_service_ping_link_start}Activați%{link_end} sau %{generate_manually_link_start}generați%{link_end} serviciul Ping pentru a previzualiza și descărca payload-ul datelor de utilizare a serviciului."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr ""
msgid "%{extra} more downstream pipelines"
msgstr "%{extra} alte pipeline-uri în aval"
@@ -892,6 +895,12 @@ msgstr "%{issuesSize} cu o limită de %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Ce este nou%{italic_end} este inactiv și nu poate fi vizualizat."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} probleme cu o limită de %{maxIssueCount}"
@@ -967,6 +976,9 @@ msgstr "%{labelStart}Răspuns nemodificat:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} indisponibil"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1435,11 +1447,11 @@ msgstr "%{verb} %{time_spent_value} de timp petrecut."
msgid "%{verb} this %{noun} as a draft."
msgstr "%{verb} acest %{noun} ca fiind un draft."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} vă permit să trimiteți notificări către aplicațiile web ca răspuns la evenimente dintr-un grup sau proiect."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} vă permit să trimiteți notificări către aplicațiile web ca răspuns la evenimente dintr-un grup sau proiect. Vă recomandăm să folosiți o %{integrations_link_start}integrare%{link_end} în locul unui webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr "Opțiuni de %{widget}"
@@ -1546,6 +1558,9 @@ msgstr "+ %{amount} mai mult"
msgid "+ %{count} more"
msgstr "+ %{count} mai mult"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} mai mult"
@@ -2041,15 +2056,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2089,12 +2113,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2116,6 +2158,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2131,6 +2176,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2143,6 +2191,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2155,9 +2206,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2362,9 +2410,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2479,6 +2524,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2536,6 +2584,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Acceptați invitația"
@@ -2587,6 +2638,9 @@ msgstr "Grupuri"
msgid "AccessDropdown|Roles"
msgstr "Roluri"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "Utilizatori"
@@ -2767,6 +2821,9 @@ msgstr "Confirmare"
msgid "Action"
msgstr "Acțiune"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3079,6 +3136,9 @@ msgstr "Adăugare sugestie la lot"
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "Adăugați text la pagina de autentificare. Markdown activat."
@@ -3103,6 +3163,9 @@ msgstr "Adăugați la revizuire"
msgid "Add to tree"
msgstr "Adăugați la arbore"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr "Adăugați subiecte la proiecte pentru a-i ajuta utilizatorii să le găsească."
@@ -3130,8 +3193,8 @@ msgstr "Adăugare/înlăturare"
msgid "AddMember|Invite email is invalid"
msgstr "E-mailul de invitație nu este valid"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "Limita de invitații de %{daily_invites} pe zi a fost depășită"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "Invitațiile nu pot fi în alb"
@@ -3970,8 +4033,8 @@ msgstr "Blocarea utilizatorului are următoarele efecte:"
msgid "AdminUsers|Bot"
msgstr "Bot"
-msgid "AdminUsers|Can create group"
-msgstr "Poate crea un grup"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "Nu puteți să vă conectați sau să accesați informațiile despre instanță"
@@ -4594,6 +4657,9 @@ msgstr "Titlul este un câmp obligatoriu pentru alertele din GitLab. ÃŽn cazul Ã
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr "Pentru integrare, se generează un URL webhook È™i o cheie de autorizare. După ce salvaÈ›i integrarea, ambele sunt vizibile în fila „Vizualizare acredităriâ€."
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr "Adăugare nouă integrare"
@@ -5032,9 +5098,6 @@ msgstr "A apărut o eroare în timpul preluării cheilor publice de implementare
msgid "An error occurred previewing the blob"
msgstr "A apărut o eroare de previzualizare a blob-ului"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr "A survenit o eroare la încărcarea provocării de verificare a utilizatorului. Actualizați pentru a încerca din nou."
-
msgid "An error occurred when updating the title"
msgstr "A apărut o eroare la actualizarea titlului"
@@ -5125,6 +5188,9 @@ msgstr "A apărut o eroare în timpul preluării problemelor."
msgid "An error occurred while fetching label colors."
msgstr "A apărut o eroare în timpul preluării culorilor etichetelor."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr "A apărut o eroare în timpul preluării participanților"
@@ -5311,6 +5377,9 @@ msgstr[2] "A apărut o eroare în timpul salvării setărilor"
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "S-a produs o eroare în timpul salvării setărilor. Încercați să le salvați din nou."
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "S-a produs o eroare la declanșarea jobului."
@@ -5326,6 +5395,12 @@ msgstr "A apărut o eroare în timpul încercării de a rula un nou pipeline pen
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr "A apărut o eroare la încercarea de a dezactiva urmărirea acestui utilizator, vă rugăm să încercați din nou."
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "A apărut o eroare în timp ce se actualizau aprobatorii"
@@ -5437,6 +5512,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5482,15 +5560,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5512,6 +5593,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5527,6 +5614,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5569,24 +5659,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6355,9 +6451,6 @@ msgstr "SunteÈ›i sigur că doriÈ›i să È™tergeÈ›i acest dispozitiv? Această acÈ
msgid "Are you sure you want to delete this label?"
msgstr "Sunteți sigur că doriți să ștergeți această etichetă?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Sunteți sigur că doriți să ștergeți acest program al pipeline-ului?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "Sunteți sigur că doriți să ștergeți acest pipeline? În acest fel, toate cache-urile de conducte vor expira și se vor șterge toate obiectele conexe, cum ar fi build-urile, jurnalele, artefactele și declanșatoarele. Această acțiune nu poate fi anulată."
@@ -6439,8 +6532,8 @@ msgstr "Sunteți sigur că doriți să resetați tokenul de înregistrare?"
msgid "Are you sure you want to retry this migration?"
msgstr "Sunteți sigur că doriți să reîncercați această migrare?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "Sunteți sigur că doriți să revocați acest %{accessTokenType}? Această acțiune nu poate fi anulată."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
msgstr ""
@@ -6589,6 +6682,9 @@ msgstr "Listă de ramuri, separate prin virgulă, care urmează să fie inspecta
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr "Token de acces personal al utilizatorului. Utilizatorul trebuie să aibă acces la activitatea respectivă. Toate comentariile sunt atribuite acestui utilizator."
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "Întrebați din nou mai târziu"
@@ -6802,6 +6898,9 @@ msgstr "Un antet cu acest nume există deja."
msgid "AuditStreams|Active"
msgstr "Activ"
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr "Adăugați un punct final HTTP pentru a gestiona jurnalele de audit în sistemele terților."
@@ -6919,6 +7018,9 @@ msgstr "Acestea ar putea include informații sensibile. Asigurați-vă că aveț
msgid "AuditStreams|This is great for keeping everything one place."
msgstr "Acest lucru este excelent pentru a păstra totul într-un singur loc."
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "Valoare"
@@ -7846,7 +7948,7 @@ msgstr "A apărut o eroare în timpul încărcării detaliilor abonamentului Git
msgid "Billing|An error occurred while loading billable members list."
msgstr "A apărut o eroare la încărcarea listei membrilor facturabili."
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7861,15 +7963,18 @@ msgstr "Se așteaptă înscrierea unui membru"
msgid "Billing|Cannot remove user"
msgstr "Nu se poate înlătura utilizatorul"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr "Membri direcți"
msgid "Billing|Enter at least three characters to search."
msgstr "Introduceți cel puțin trei caractere pentru a căuta."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr "Explorați planurile plătite"
@@ -7888,6 +7993,9 @@ msgstr[2] "Grupurile din nivelul gratuit sunt limitate la %d de seat-uri"
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "Membrii care au fost invitați printr-o invitație de grup nu pot fi înlăturați. Puteți fie să înlăturați întregul grup, fie să solicitați unui proprietar al grupului invitat să înlăture membrul."
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr "Niciun utilizator de afișat."
@@ -7900,6 +8008,12 @@ msgstr "Invitație la proiect"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "Înlăturați utilizatorul %{username} din abonament"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7927,6 +8041,9 @@ msgstr "Vizualizați aprobările în așteptare"
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "Sunteți pe cale să înlăturați utilizatorul %{username} din abonament. Dacă veți continua, utilizatorul va fi înlăturat din grupul %{namespace} și din toate subgrupurile și proiectele acestuia. Această acțiune nu poate fi anulată."
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr "Recent, grupul dvs. a retrogradat la planul gratuit. %{over_limit_message} Puteți elibera spațiu pentru noii membri, înlăturându-i pe cei care nu mai au nevoie de acces sau trecându-i la peste-limită. %{link_start}Actualizați%{link_end} la un nivel plătit pentru a profita de un număr nelimitat de membri."
@@ -7972,6 +8089,9 @@ msgstr[2] "Blocat de %d de probleme"
msgid "Blocked issue"
msgstr "Problemă blocată"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr "Blocare"
@@ -8005,9 +8125,6 @@ msgstr "Nicio potrivire de rezultate"
msgid "BoardNewEpic|Search groups"
msgstr "Căutați grupuri"
-msgid "BoardNewEpic|Select a group"
-msgstr "Selectați un grup"
-
msgid "BoardNewIssue|No matching results"
msgstr "Nu există rezultate care să se potrivească"
@@ -8095,9 +8212,6 @@ msgstr "Selectați etichete"
msgid "BoardScope|Select milestone"
msgstr "Selectați obiectivul"
-msgid "BoardScope|Select weight"
-msgstr "Selectați greutate"
-
msgid "BoardScope|Started"
msgstr "Începută"
@@ -9175,7 +9289,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9271,8 +9385,8 @@ msgstr "Subdomeniul %{code_open}.campfirenow.com%{code_close}."
msgid "Can be manually deployed to"
msgstr "Poate fi desfășurat manual la"
-msgid "Can create groups:"
-msgstr "Poate crea grupuri:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr "Nu se poate șterge formarea primară"
@@ -9658,6 +9772,9 @@ msgstr "Schimbările aduse titlului nu au fost salvate"
msgid "Changes:"
msgstr "Modificări:"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr "Modificarea oricărei setări de aici necesită o repornire a aplicației"
@@ -9748,6 +9865,9 @@ msgstr "Verificați imaginile dvs. Docker pentru vulnerabilități cunoscute."
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Verificarea disponibilității %{text}…"
@@ -9808,8 +9928,8 @@ msgstr[0] "%{quantity} pachet de stocare"
msgstr[1] "%{quantity} pachete de stocare"
msgstr[2] "%{quantity} de pachete de stocare"
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "Planul %{selectedPlanText}"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -10063,6 +10183,9 @@ msgstr "Alegeți un șablon…"
msgid "Choose a type..."
msgstr "Alegeți un tip…"
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Alegeți fișierul…"
@@ -10264,15 +10387,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "Nu se poate utiliza Variabilă mascată cu valoarea curentă"
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr "Medii"
@@ -10324,9 +10447,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr "Înlăturați variabila"
-msgid "CiVariables|Remove variable row"
-msgstr "Înlăturați rândul variabil"
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10348,12 +10468,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Tipul"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Valoare"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10369,9 +10501,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (Toate mediile)"
-
msgid "CiVariable|All environments"
msgstr "Toate mediile"
@@ -10531,6 +10660,9 @@ msgstr "Clienți"
msgid "Clientside DSN"
msgstr "DSN pe partea clientului"
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Clonare"
@@ -10828,15 +10960,9 @@ msgstr "Sănătatea Clusterului"
msgid "Cluster cache cleared."
msgstr "Cache-ul clusterului a fost curățat."
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr "Clusterul este necesar pentru Stagii::ClusterEndpointInserter"
-
msgid "Cluster level"
msgstr "Nivelul clusterului"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr "Tipul de cluster trebuie să fie specificat pentru Stagii::ClusterEndpointInserter"
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr "%{linkStart}Consultați documentația%{linkEnd} pentru instalarea avansată. Asigurați-vă că aveți la dispoziție tokenul de acces."
@@ -11128,6 +11254,9 @@ msgstr "Acest agent nu are tokenuri"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "Pentru a șterge agentul, tastați %{name} pentru a confirma:"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr "Pentru a revoca tokenul, tastați %{name} pentru a confirma:"
@@ -11152,6 +11281,9 @@ msgstr "Vedeți toți cei %{number} (de) agenți"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "Vedeți toate cele %{number} (de) clustere"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "Ne-ar plăcea să aflăm mai multe despre experiența d-voastră cu agentul GitLab."
@@ -11575,9 +11707,6 @@ msgstr "Revizuirea codului"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "Analiza revizuirii codului afișează un tabel cu merge request-uri deschise considerate a fi în curs de revizuire a codului. În prezent, nu există merge request-uri în revizuire pentru acest proiect și/sau filtre."
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11647,31 +11776,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11743,6 +11869,9 @@ msgstr "Cohortele de utilizatori sunt prezentate pentru ultimele %{months_includ
msgid "Collapse"
msgstr "Restrângeți"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr "Restrângeți toate subiectele"
@@ -12103,9 +12232,6 @@ msgstr "A apărut o eroare la încărcarea listei de ramuri/etichete. Vă rugăm
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "A apărut o eroare în timpul căutării în lista de ramuri/etichete. Vă rugăm să încercați din nou."
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "A apărut o eroare în timp ce se actualiza lista de ramuri/etichete. Vă rugăm să încercați din nou"
-
msgid "CompareRevisions|View open merge request"
msgstr "Vizualizați merge request-ul deschis"
@@ -12151,6 +12277,9 @@ msgstr ""
msgid "Compliance framework"
msgstr "Framework de conformitate"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Adăugare framework"
@@ -12208,8 +12337,8 @@ msgstr "Eroare la preluarea datelor framework-urilor de conformitate. Vă rugăm
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
-msgstr "Framework-urile care au fost adăugate vor apărea aici."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr ""
msgid "ComplianceFrameworks|Invalid format"
msgstr "Format invalid"
@@ -12424,15 +12553,18 @@ msgstr "Confidențialitate"
msgid "Configuration help"
msgstr "Ajutor pentru configurare"
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "Configurați meniul și conținutul %{italic_start}Ce este nou%{italic_end}."
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
-msgstr "Configurați %{link} pentru a urmări evenimentele. %{link_start}Aflați mai multe.%{link_end}"
-
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr "Configurați %{repository_checks_link_start}controalele de repozitoriu%{link_end} și %{housekeeping_link_start}curățenia%{link_end} în repozitorii."
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr "Configurați CAPTCHAs, limite de adrese IP și alte măsuri anti-spam."
@@ -12496,6 +12628,9 @@ msgstr "Configurați permisiunile avansate, Large File Storage, autentificarea c
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr "Configurați permisiunile avansate, Large File Storage, autentificarea cu doi factori și setările privind relațiile cu clienții."
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12667,6 +12802,9 @@ msgstr "Eșec de conectare"
msgid "Consistency guarantee method"
msgstr "Metoda de garantare a consistenței"
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "Contactați asistența"
@@ -13192,6 +13330,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13225,6 +13366,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13237,9 +13402,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13327,6 +13501,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13873,6 +14056,9 @@ msgstr "Creați versiunea"
msgid "Create requirement"
msgstr "Creați o cerință"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr "Creați un cont de servicii"
@@ -14251,9 +14437,6 @@ msgstr "Organizația a fost adăugată."
msgid "Crm|Organization has been updated."
msgstr "Organizația a fost actualizată."
-msgid "Cron Timezone"
-msgstr "Fusul orar Cron"
-
msgid "Cron time zone"
msgstr "Fusul orar Cron"
@@ -14593,9 +14776,6 @@ msgstr "Timpul pentru restabilirea serviciului"
msgid "CycleAnalytics|Total time"
msgstr "Timpul total"
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "filtrul derulant de grup"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr "nepermis pentru evenimentul de start dat"
@@ -14773,6 +14953,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14863,6 +15046,9 @@ msgstr "Timpul de restabilire a serviciului ( zile medii)"
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15085,6 +15271,9 @@ msgstr "Minim = 0 (nu este activat niciun timeout), Maxim = 2880 de minute"
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "Minim = 1 secundă, Maxim = 3600 de secunde"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr "Monitorizează toate solicitările HTTP trimise către țintă pentru a găsi potențiale vulnerabilități."
@@ -15592,9 +15781,6 @@ msgstr "Definiți un model personalizat cu sintaxa cron"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr "Definiți reguli personalizate pentru ceea ce constituie spam, independent de Akismet"
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "Definiți mediile în etapa/etapele de desfășurare din %{code_open}.gitlab-ci.yml%{code_close} pentru a urmări desfășurările aici."
-
msgid "Define how approval rules are applied to merge requests."
msgstr "Definiți modul în care se aplică regulile de aprobare la merge request-uri."
@@ -15718,9 +15904,6 @@ msgstr "Ștergeți eticheta: %{labelName}"
msgid "Delete pipeline"
msgstr "Ștergeți pipeline-ul"
-msgid "Delete pipeline schedule"
-msgstr "Ștergeți programul de pipeline"
-
msgid "Delete project"
msgstr "Ștergeți proiectul"
@@ -15946,6 +16129,9 @@ msgstr "Locație și calea dependenței"
msgid "Dependencies|Packager"
msgstr "Manager de pachete"
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15964,6 +16150,9 @@ msgstr "Calea dependenței componentei se bazează pe fișierul de blocare. Pot
msgid "Dependencies|There may be multiple paths"
msgstr "Pot exista mai multe căi"
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "Comută lista vulnerabilităților"
@@ -16150,6 +16339,12 @@ msgstr "Fusul orar"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} altele"
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr "Proiectul actual"
@@ -16177,8 +16372,8 @@ msgstr "Acordați permisiuni în scriere pentru această cheie"
msgid "DeployKeys|Loading deploy keys"
msgstr "Încărcarea cheilor de implementare"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "Nu s-au găsit chei de implementare. Creați una cu ajutorul formularului de mai sus"
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "Chei de implementare accesibile în mod privat"
@@ -16192,8 +16387,8 @@ msgstr "Chei de implementare accesibile public"
msgid "DeployKeys|Read access only"
msgstr "Acces numai în citire"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "Tokenuri de implementare active (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
msgstr "Permite accesul în citire și scriere la imaginile de registru."
@@ -16216,6 +16411,9 @@ msgstr "Permite accesul numai în citire la repozitoriu."
msgid "DeployTokens|Allows write access to registry images."
msgstr "Permite accesul în scriere la imaginile din registru."
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr "Copiați tokenul de implementare"
@@ -16276,8 +16474,8 @@ msgstr "Scopuri"
msgid "DeployTokens|Scopes (select at least one)"
msgstr "Domenii (selectați cel puțin unul)"
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
-msgstr "Acest tip de %{entity_type} nu are Token de implementare active."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
+msgstr ""
msgid "DeployTokens|This action cannot be undone."
msgstr "Această acțiune nu poate fi anulată."
@@ -16294,12 +16492,12 @@ msgstr "Nume de utilizator"
msgid "DeployTokens|Username (optional)"
msgstr "Nume de utilizator (opțional)"
-msgid "DeployTokens|Your New Deploy Token"
-msgstr "Noul dvs. token de implementare"
-
msgid "DeployTokens|Your new Deploy Token username"
msgstr "Noul dvs. nume de utilizator al Tokenului de implementare"
+msgid "DeployTokens|Your new deploy token"
+msgstr ""
+
msgid "DeployTokens|Your new group deploy token has been created."
msgstr "Noul dvs. token de implementare de grup a fost creat."
@@ -16381,6 +16579,12 @@ msgstr "Aprobat de d-voastră %{time}"
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr "Aprobarea va executa jobul manual din implementarea #%{deploymentIid}. Respingerea va eșua jobul manual."
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr "Nivel de implementare: %{tier}"
@@ -16453,9 +16657,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "Anulat"
@@ -16468,6 +16669,24 @@ msgstr "ID de implementare"
msgid "Deployment|Failed"
msgstr "Eșuat"
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr "Ultima implementare"
@@ -16483,12 +16702,15 @@ msgstr "Sărit"
msgid "Deployment|Success"
msgstr "Succes"
-msgid "Deployment|This deployment was created using the API"
-msgstr "Această implementare a fost creată utilizând API-ul"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr ""
msgid "Deployment|Triggerer"
msgstr "Declanșator"
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16558,12 +16780,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr "Fișierele și datele de Management al designului"
-msgid "Design repositories"
-msgstr "Repozitorii de design"
-
-msgid "Design repository"
-msgstr "Repozitoriu de design"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} din %{designs_count}"
@@ -17764,9 +17980,6 @@ msgstr "E-mail trimis"
msgid "Email the pipeline status to a list of recipients."
msgstr "Trimiteți prin e-mail starea pipeline-ului către o listă de destinatari."
-msgid "Email updates (optional)"
-msgstr "Actualizări prin e-mail (opțional)"
-
msgid "Email:"
msgstr "E-mail:"
@@ -17809,6 +18022,9 @@ msgstr "%{emails}, %{andMore} vor fi notificați cu privire la comentariul dumne
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "și %{moreCount} alții"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "E-mailuri"
@@ -17947,9 +18163,6 @@ msgstr "Activați executorii de grup"
msgid "Enable header and footer in emails"
msgstr "Activați antetul și subsolul în e-mailuri"
-msgid "Enable in-product marketing emails"
-msgstr "Activați e-mailurile de marketing în produs"
-
msgid "Enable incident management inbound alert limit"
msgstr "Activați limita de alertă de intrare pentru gestionarea incidentelor"
@@ -17971,8 +18184,8 @@ msgstr "Activați această opțiune numai pentru aplicațiile confidențiale uti
msgid "Enable or disable version check and Service Ping."
msgstr "Activați sau dezactivați verificarea versiunii și serviciul Ping."
-msgid "Enable rate limiting for POST requests to the specified paths"
-msgstr "Activați limitarea ratei pentru solicitările POST spre căile specificate"
+msgid "Enable rate limiting for requests to the specified paths"
+msgstr ""
msgid "Enable reCAPTCHA"
msgstr "Activați reCAPTCHA"
@@ -18085,9 +18298,6 @@ msgstr "Impuneți autentificarea cu doi factori pentru toate autentificările ut
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr "Îmbunătățiți securitatea prin stocarea cheilor conturilor de servicii în administratorii de secrete - aflați mai multe despre %{docLinkStart}managementul secretului cu GitLab%{docLinkEnd}"
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr "Asigurați-vă că %{linkStart}mediul dvs. face parte din etapa de implementare%{linkEnd} a pipeline-ului dvs. CI pentru a urmări implementările în clusterul dvs."
@@ -18199,8 +18409,8 @@ msgstr "Mediul"
msgid "Environment scope"
msgstr "Domeniul mediului"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr "Variabilele de mediu din această instanță GitLab sunt configurate implicit să fie %{link_start}protejate%{link_end}."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr ""
msgid "Environment:"
msgstr "Mediu"
@@ -18346,12 +18556,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Joburi"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr "Aflați mai multe despre oprirea mediilor"
@@ -18397,6 +18613,12 @@ msgstr "Mediul de revenire %{name}?"
msgid "Environments|Search by environment name"
msgstr "Căutare după numele mediului"
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18433,6 +18655,9 @@ msgstr "Această acțiune va %{docsStart}încerca din nou cea mai recentă imple
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr "Această acțiune va %{docsStart}readuce acest mediu%{docsEnd} la o implementare anterioară reușită pentru commit-ul %{commitId}. Sunteți sigur că doriți să continuați?"
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr "Viitoare"
@@ -18535,6 +18760,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19291,6 +19522,9 @@ msgstr "Metodele de autentificare existente pot fi înlăturate"
msgid "Expand"
msgstr "Extindeți"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Extindeți tot"
@@ -19537,6 +19771,9 @@ msgstr "https://example.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20197,9 +20434,6 @@ msgstr "Filtrați după cazurile de testare care sunt arhivate în prezent."
msgid "Filter by test cases that are currently open."
msgstr "Filtrați după cazurile de testare care sunt deschise în prezent."
-msgid "Filter by user"
-msgstr "Filtrați după utilizator"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr "Parametrii de filtrare nu sunt valabili. Asigurați-vă că data de sfârșit este ulterioară datei de început."
@@ -20224,9 +20458,6 @@ msgstr "Filtrarea rezultatelor..."
msgid "Filter users"
msgstr "Filtrați utilizatorii"
-msgid "Filter..."
-msgstr "Filtrare..."
-
msgid "Finalizing"
msgstr ""
@@ -20596,33 +20827,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "O altă opțiune este de a face upgrade la GitLab Premium sau GitLab Ultimate:"
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "Explorați planurile plătite"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "Explorați planurile plătite:"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr "Gestionați membrii"
-
-msgid "FreeUserCap|Manage members:"
-msgstr "Gestionați membrii:"
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr "Pentru a obține mai mulți membri, %{trial_link_start}începeți o perioadă de încercare%{trial_link_end} sau %{upgrade_link_start}faceți upgrade%{upgrade_link_end} la GitLab Premium sau GitLab Ultimate."
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr "Pentru a obține mai mulți membri, începeți o perioadă de încercare:"
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr "Ați atins limita de membri!"
-
msgid "Freeze end"
msgstr "Înghețul se termină"
@@ -21319,6 +21523,12 @@ msgstr "Obțineți o revizuire gratuită a instanței"
msgid "Get a support subscription"
msgstr "Obțineți un abonament de asistență"
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Începeți"
@@ -21646,6 +21856,9 @@ msgstr "Neconfirmat"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "Actualizarea configurației Pages..."
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21661,6 +21874,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr "Când este activată, toate încercările de a vă vizita site-ul web prin HTTP sunt redirecționate automat către HTTPS utilizând un răspuns cu codul de stare 301. Necesită un certificat valid pentru toate domeniile. %{docs_link_start}Aflați mai multe.%{link_end}"
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr "Când utilizați Pages sub domeniul general al unei instanțe GitLab (%{pages_host}), nu puteți utiliza HTTPS cu subdomeniile unor subdomenii. Dacă spațiul de nume sau numele de grup al dvs. conține un punct, nu funcționează. Aceasta este o limitare a protocolului HTTP Over TLS. Paginile HTTP funcționează dacă nu redirecționați HTTP to HTTPS. %{docs_link_start}Aflați mai multe.%{link_end}"
@@ -21676,12 +21892,6 @@ msgstr "Proiectul dvs. a fost configurat pentru Pages. Acum trebuie să aÈ™teptÄ
msgid "Gitaly Servers"
msgstr "Servere Gitaly"
-msgid "Gitaly relative path:"
-msgstr "Calea relativă Gitaly:"
-
-msgid "Gitaly storage name:"
-msgstr "Numele stocării Gitaly:"
-
msgid "Gitaly timeouts"
msgstr "Timeout-uri Gitaly"
@@ -21802,8 +22012,8 @@ msgstr "URL-ul instanței dvs. Gitpod configurate pentru a vă citi proiectele G
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr "Pentru a utiliza Gitpod, trebuie mai întâi să activați caracteristica în secțiunea „Integrări†din %{linkStart}preferințele utilizatorului%{linkEnd}."
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
-msgstr "Pentru a utiliza integrarea, fiecare utilizator trebuie de asemenea să activeze Gitpod pe contul său GitLab. %{link_start}Cum să-l activez?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr ""
msgid "Gitpod|https://gitpod.example.com"
msgstr "https://gitpod.example.com"
@@ -21820,6 +22030,9 @@ msgstr "Accesul acordat %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr "Epica dată este deja legată de această epică."
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21841,6 +22054,9 @@ msgstr "%{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr "%{count} (de) rezultate implicite furnizate. Utilizați tastele săgeată sus și jos pentru a naviga în lista de rezultate ale căutării."
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21853,6 +22069,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21922,9 +22141,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr "Căutați în GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "Căutați proiecte, probleme etc."
@@ -21955,6 +22171,9 @@ msgstr "A apărut o eroare la preluarea sugestiilor de autocompletare a căutăr
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "Tastați și apăsați tasta Enter pentru a trimite căutarea."
@@ -22195,6 +22414,12 @@ msgstr "Revocarea autorizațiilor"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "Revocarea autorizațiilor acordate către GitLab. Acest lucru nu invalidează conturile de servicii."
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22210,7 +22435,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22321,6 +22546,9 @@ msgstr "Avatarul grupului"
msgid "Group by"
msgstr "Grupați după"
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "Descrierea grupului (opțional)"
@@ -22387,9 +22615,6 @@ msgstr "Numele grupului (organizația dvs.)"
msgid "Group navigation"
msgstr "Navigare în grup"
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr "Conținutul general al grupului"
@@ -22765,7 +22990,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr "Framework-uri de conformitate"
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22954,8 +23179,8 @@ msgstr "Această caracteristică necesită un browser care suportă localStorage
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "Un grup este o colecție de mai multe proiecte."
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
msgid "GroupsEmptyState|Create new project"
msgstr "Creați un nou proiect"
@@ -22966,8 +23191,8 @@ msgstr "Creați un nou subgrup"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "Grupurile sunt cel mai bun mod de a gestiona mai multe proiecte și membri."
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Dacă vă organizați proiectele în cadrul unui grup, acesta funcționează ca un dosar."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
msgid "GroupsEmptyState|No archived projects."
msgstr ""
@@ -22984,9 +23209,6 @@ msgstr "Nu există subgrupuri sau proiecte."
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "Proiectele sunt locul în care vă puteți stoca propriul cod, puteți accesa problemele, wiki și alte caracteristici ale Gitlab."
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "Puteți gestiona permisiunile și accesul membrilor grupului dvs. la fiecare proiect din grup."
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "Nu aveți permisiunile necesare pentru a crea un subgrup sau un proiect în acest grup. Vă rugăm să contactați un proprietar al acestui grup pentru a crea un nou subgrup sau proiect."
@@ -23410,6 +23632,9 @@ msgstr "Ajutați la traducerea GitLab în limba dvs."
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr "Ajută la împiedicarea atacurilor prin forță brută de către boți."
@@ -23674,9 +23899,6 @@ msgstr "Doresc să-mi stochez codul"
msgid "I want to use GitLab CI with my existing repository"
msgstr "Vreau să folosesc GitLab CI cu repozitoriul meu existent"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "Aș dori să primesc actualizări despre GitLab prin e-mail"
-
msgid "I'm signing up for GitLab because:"
msgstr "Mă înscriu la GitLab pentru că:"
@@ -23716,6 +23938,12 @@ msgstr "Această opțiune este dezactivată deoarece nu aveți permisiunea de a
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr "Această opțiune este dezactivată deoarece nu aveți permisiuni de scriere pentru ramura curentă."
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "INFO: Cheia dvs. SSH a expirat. Vă rugăm să generați o cheie nouă."
@@ -23899,6 +24127,12 @@ msgstr "Metodă de verificare prin plată"
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr "Verificați-vă identitatea"
@@ -24313,7 +24547,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24340,6 +24574,12 @@ msgstr "Repozitoriul nu a putut fi importat."
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr "Nu există un repozitoriu Git valid la această adresă URL. Dacă depozitul HTTP nu este accesibil publicului, verificați-vă acreditările."
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr "Îmbunătățiți asistența pentru clienți cu Service Desk"
@@ -24382,381 +24622,72 @@ msgstr "ÃŽn uz"
msgid "InProductMarketing|%{organization_name} logo"
msgstr "logoul %{organization_name}"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr "%{strong_start}Securitatea avansată a aplicațiilor%{strong_end} — inclusiv scanarea SAST, DAST, testarea FUZZ, scanarea dependențelor, conformitatea licenței, detectarea secretelor"
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr "%{strong_start}Managementul portofoliului la nivelul întregii companii%{strong_end} — incluzând epice multi-nivel, etichete cu scop exclusiv"
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr "%{strong_start}Perspective la nivel executiv%{strong_end} — inclusiv rapoarte de productivitate, tipuri de sarcini, zile până la finalizare, fluxuri de valoare"
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr "%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr "%{strong_start}Roluri multiple de aprobare%{strong_end} — inclusiv proprietarii de coduri și aprobările de îmbinare necesare"
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr "*GitLab*, substantiv: un sinonim pentru echipe eficiente"
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...și puteți obține o versiune de încercare gratuită a GitLab Ultimate"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr "3 moduri de a aprofunda GitLab CI/CD"
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr "De fapt, GitLab face echipa să funcționeze (mai bine)"
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr "Și în cele din urmă %{deploy_link} o aplicație Python."
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "Executorii dvs. sunt pregătiți?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr "Scanări de securitate automatizate direct în GitLab"
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "Deveniți un erou DevOps"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr "Consolidați-vă securitatea"
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "Cod mai bun în mai puțin timp"
-
msgid "InProductMarketing|Blog"
msgstr "Blog"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr "Construiți pentru iOS? Avem tot ce vă trebuie."
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr "Prin activarea proprietarilor de coduri și necesitatea aprobărilor de îmbinare, persoana potrivită va revizui MR-ul potrivit. Acest lucru este avantajos pentru ambele părți: un cod mai curat și un proces de revizuire mai eficient."
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr "Proprietarii de coduri și aprobările de îmbinare necesare fac parte din nivelurile plătite ale GitLab. Puteți începe o perioadă de încercare gratuită de 30 de zile a GitLab Ultimate și puteți activa aceste funcții în mai puțin de 5 minute, fără a fi nevoie de un card de credit."
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr "Creați un executor CI personalizat în doar câteva clicuri"
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr "Creați un executor personalizat"
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "Creați un proiect în GitLab în 5 minute"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "Creați-vă primul proiect!"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr "Livrați produse mai bune, mai repede"
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr "Știați că echipele care utilizează GitLab sunt mult mai eficiente?"
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr "Dați-i drumul și creați un proiect și un repo"
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr "Aveți un coechipier care ar fi perfect pentru această sarcină?"
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr "Extindeți-vă parcursul DevOps cu o perioadă de încercare gratuită GitLab"
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "Explorați GitLab CI/CD"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "Explorați opțiunile"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr "Descoperiți potențialul GitLab CI/CD"
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr "Simțiți nevoia de viteză?"
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr "Aflați cum se comportă cu adevărat echipele dvs."
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "Urmați etapele noastre"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "Perioada de încercare gratuită de 30 de zile"
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr "Începeți rapid cu CI/CD folosind propriul nostru %{quick_start_link}. Începeți cu un executor disponibil și apoi creați un fișier CI .yml – este chiar atât de simplu."
-
-msgid "InProductMarketing|Get our import guides"
-msgstr "Obțineți ghidurile noastre de import"
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr "Pregătiți-vă să construiți pentru iOS"
-msgid "InProductMarketing|Get started today"
-msgstr "Începeți astăzi"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr "Începeți astăzi cu o perioadă de încercare GitLab Ultimate de 30 de zile, fără a fi nevoie de un card de credit."
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr "Demarați cu GitLab CI/CD"
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr "Faceți cunoștință cu GitLab CI/CD"
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr "Configurați-vă echipa pe GitLab"
-
-msgid "InProductMarketing|Git basics"
-msgstr "Noțiuni de bază Git"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr "Proiecte GitHub Enterprise către GitLab"
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr "GitLab oferă testarea statică a securității aplicațiilor (SAST), testarea dinamică a securității aplicațiilor (DAST), scanarea containerelor și scanarea dependențelor pentru a vă ajuta să livrați aplicații sigure, împreună cu conformitatea licenței."
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr "CI/CD a GitLab face dezvoltarea de software mai ușoară. Nu ne credeți? Iată trei moduri în care o puteți testa rapid (și satisfăcător):"
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr "Nivelurile premium ale GitLab sunt concepute pentru a vă face pe dvs., echipa și aplicația dvs. mai eficienți și mai siguri cu caracteristici care includ, dar fără a se limita la:"
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "Acordați-ne un minut..."
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr "Mergeți mai departe cu GitLab"
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr "Goldman Sachs a trecut de la 1 versiune la fiecare două săptămâni la mii de versiuni pe zi"
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr "Aveți o altă instanță pe care ați dori să o importați? Aici este %{import_link} nostru."
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr "Iată ce trebuie să știți"
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr "Cum (și de ce) replicarea are sens"
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr "Cât timp ne ia să închidem problemele/MR-urile în funcție de tipuri, cum ar fi solicitări de funcții, erori, datorii tehnice, securitate?"
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr "Câte zile îi ia echipei noastre pentru a finaliza diverse sarcini?"
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr "Cum să construiți și să testați mai repede"
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr "Dacă nu doriți să primiți e-mailuri de marketing direct de la GitLab, %{marketing_preference_link}."
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr "Dacă nu mai doriți să primiți e-mailuri de marketing de la noi,"
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr "Importați-vă proiectul și codul din GitHub, Bitbucket și altele"
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr "Îmbunătățiți securitatea aplicațiilor cu o perioadă de încercare de 30 de zile"
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr "Îmbunătățiți calitatea codului și eficientizați revizuirile"
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr "Creșteți eficiența operațională"
-msgid "InProductMarketing|Invite them to help out."
-msgstr "Invitați-i să vă ajute."
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "Invitați-vă colegii și începeți să expediați codul mai repede."
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "Invitați-vă colegii să se alăture în mai puțin de un minut"
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "Invitați-vă colegii astăzi"
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "Invitați-vă echipa în mai puțin de 60 de secunde"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "Invitați-vă echipa acum"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr "Invitați-vă echipa astăzi pentru a construi împreună cod mai bun (și procese)"
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr "Totul este în statistici"
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr "De asemenea, este posibil să folosiți pur și simplu %{external_repo_link} pentru a profita de CI/CD de la GitLab."
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr "Lansați GitLab CI/CD în 20 de minute sau mai puțin"
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr "Învățați cum să dezvoltați pentru iOS"
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr "Faceți schimbarea? Importarea proiectelor dvs. în GitLab este mai ușoară decât credeți. Deplasați %{github_link} sau importați ceva %{bitbucket_link}."
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr "Stăpâniți arta importului!"
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr "Treceți la crearea cu ușurință a unui site web Pages %{ci_template_link}"
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr "Proprietari multipli, fluxuri de lucru confuze? Vă oferim o soluție"
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr "Aveți nevoie de o alternativă la import?"
-
msgid "InProductMarketing|No credit card required."
msgstr "Nu este nevoie de card de credit."
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr "Instrumentul nostru reunește toate aceste lucruri"
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr "Dezvoltare rapidă, simplificată"
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr "Securitate integrată în ciclul de viață al dezvoltării dumneavoastră"
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr "Uneori, nu sunteți pregătit pentru o tranziție completă la un nou instrument. Dacă nu sunteți pregătit să vă angajați complet, %{mirroring_link} vă oferă o modalitate sigură de a încerca GitLab în paralel cu instrumentul dvs. actual."
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr "Creați un executor de scalare automată în GitLab"
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "Începeți astăzi o versiune de încercare GitLab Ultimate în mai puțin de un minut, fără a fi nevoie de un card de credit."
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr "Începeți o versiune de încercare autogestionată"
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "Începeți o perioadă de încercare gratuită a GitLab Ultimate – nu este nevoie de card de credit"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "Începeți o perioadă de încercare"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "Începeți cu %{performance_link}"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "Începeți cu importul proiectelor dumneavoastră"
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "Începeți cu o perioadă de testare gratuită GitLab Ultimate"
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "Începeți perioada de încercare acum!"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr "Începeți perioada dvs. de încercare astăzi pentru a experimenta succesul unei singure aplicații și pentru a descoperi gratuit toate caracteristicile GitLab Ultimate!"
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr "Nu vă mai întrebați și folosiți GitLab pentru a răspunde la întrebări precum:"
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr "Simplificați revizuirea codului, aflați dintr-o privire cine nu este disponibil, comunicați prin comentarii sau prin e-mail și integrați cu Slack pentru ca toată lumea să fie pe aceeași pagină."
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr "Faceți primii pași cu GitLab"
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr "Duceți managementul codului sursă la nivelul următor"
-
msgid "InProductMarketing|Team members collaborating"
msgstr "Membrii echipei care colaborează"
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr "Lucrați în echipă în GitLab pentru o mai mare eficiență"
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr "Munca în echipă face visul să funcționeze"
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr "Testați, creați, desfășurați"
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr "Asta este tot ce este nevoie pentru a începe cu GitLab, dar dacă sunteți nou în lucrul cu Git, consultați %{basics_link} pentru sfaturi și trucuri utile pentru început."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr "Acesta este e-mailul %{current_series} din %{total_series} în seria %{track}."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr "Acesta este e-mailul %{current_series} din %{total_series} din seria de %{track}. Pentru a dezactiva e-mailurile de notificare trimise de instanța GitLab locală, fie contactați administratorul dvs., fie %{unsubscribe_link}."
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr "Ticketmaster și-a redus timpul de dezvoltare CI de 15 ori"
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr "V-ați săturat să vă luptați cu lanțuri de instrumente disparate, cu silozuri de informații și cu procese ineficiente? CI/CD de la GitLab este dezvoltat pe o platformă DevOps cu management al codului sursă, planificare, monitorizare și multe altele gata de utilizare. Aflați %{ci_link}."
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr "Pentru a renunța la aceste e-mailuri de onboarding, %{unsubscribe_link}."
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr "Pentru a înțelege și a obține cele mai bune rezultate din GitLab, începeți de la zero, începând cu %{project_link}. În GitLab, repozitoriile fac parte dintr-un proiect, așa că, după ce ați creat proiectul, puteți merge mai departe la %{repo_link}."
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "Încercați GitLab Ultimate gratuit"
-
-msgid "InProductMarketing|Try it out"
-msgstr "Încercați-l"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "Încercați-l și dumneavoastră"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr "Transformați colegii în colaboratori"
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr "Înțelegeți replicarea unui repozitoriu"
-
-msgid "InProductMarketing|Understand your project options"
-msgstr "Înțelegeți opțiunile proiectului dumneavoastră."
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr "Utilizați GitLab CI/CD"
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr "Utilizați șablonul nostru AWS cloudformation pentru a vă instala executorii în doar câteva clicuri!"
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr "Utilizat de peste 100.000 de organizații din întreaga lume:"
@@ -24772,66 +24703,15 @@ msgstr "Vreți să găzduiți GitLab pe serverele dumneavoastră?"
msgid "InProductMarketing|Watch iOS building in action."
msgstr "Urmăriți dezvoltarea iOS în acțiune."
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr "Știm un lucru sau două despre eficiență și nu vrem să păstrăm acest lucru pentru noi. Înscrieți-vă pentru o versiune de încercare gratuită a GitLab Ultimate, iar echipele dvs. îl vor folosi din prima zi."
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr "Cum arată cronologia fluxului nostru de valori, de la produs la dezvoltare, revizuire și producție?"
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr "Când echipa dvs. este pe GitLab, aceste răspunsuri sunt la un clic distanță."
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr "Lucrul în GitLab = mai eficient"
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr "Echipele dvs. pot fi mai eficiente"
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "ghid cuprinzător"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "conectați un repozitoriu extern"
-
-msgid "InProductMarketing|create a project"
-msgstr "creați un proiect"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "din Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "accesați about.gitlab.com"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "cât de ușor este să începeți"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "ghid de pornire rapidă"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "replicarea repozitoriului"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "configurați un repo"
-
-msgid "InProductMarketing|test and deploy"
-msgstr "testați și desfășurați"
-
-msgid "InProductMarketing|testing browser performance"
-msgstr "testarea performanței browserului"
-
msgid "InProductMarketing|unsubscribe"
msgstr "dezabonați-vă"
-msgid "InProductMarketing|update your preferences"
-msgstr "actualizați-vă preferințele"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr "folosind un șablon CI/CD"
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "vă puteți %{unsubscribe_link} în orice moment."
@@ -25261,6 +25141,18 @@ msgstr "Inline"
msgid "Inline math"
msgstr "Matematică inline"
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Input host keys manually"
msgstr "Introduceți manual cheile gazdei"
@@ -25618,6 +25510,9 @@ msgstr "Problemele ZenTao se afișează aici atunci când creați probleme în p
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr "nu poate depăși %{recipients_limit}"
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr "IntelliJ IDEA (HTTPS)"
@@ -25654,15 +25549,9 @@ msgstr "Utilizatorii interni nu pot fi dezactivați"
msgid "Interval"
msgstr "Interval"
-msgid "Interval Pattern"
-msgstr "Model de intervale"
-
msgid "Introducing Your DevOps Reports"
msgstr "Prezentarea rapoartelor dvs. DevOps"
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25744,9 +25633,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr "Cod cu doi factori invalid."
-msgid "Invalid yaml"
-msgstr "Yaml nevalid"
-
msgid "Invalidated"
msgstr "Invalidat"
@@ -26080,18 +25966,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr "neatribuit"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type} creat(ă) la %{created_at} de "
-
msgid "IssuableStatus|Closed"
msgstr "Închis(ă)"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Închis(ă) (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "Creat(ă) la %{created_at} de"
-
msgid "IssuableStatus|duplicated"
msgstr "duplicat"
@@ -26341,29 +26221,50 @@ msgstr "Probleme fără nicio epică atribuită"
msgid "Issues, merge requests, pushes, and comments."
msgstr "Probleme, merge request-uri, evenimente push și comentarii."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "După ce începeți să creați probleme pentru proiectele dvs., putem începe să urmărim și să afișăm metrici pentru acestea"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Avg/Lună:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr "Probleme create"
msgid "IssuesAnalytics|Issues created per month"
msgstr "Probleme create pe lună"
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "Ultimele 12 luni"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Ne pare rău, filtrul dvs. nu a produs niciun rezultat"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "Nu există probleme pentru proiectele din grupul dumneavoastră"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "Pentru a vă lărgi căutarea, modificați sau înlăturați filtrele din bara de filtrare de mai sus"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr "Total:"
@@ -26410,6 +26311,9 @@ msgstr ""
msgid "Italic text"
msgstr "Text italic"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr "iterație"
@@ -26746,6 +26650,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27244,6 +27151,9 @@ msgstr "Durata"
msgid "Job|Erase job log and artifacts"
msgstr "Ștergeți jurnalul jobului și artefactele"
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr "Eșuat"
@@ -27295,6 +27205,9 @@ msgstr "Reîncercați"
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr "Rulează"
@@ -27391,9 +27304,6 @@ msgstr "Alăturați-vă unui proiect"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr "Alăturați-vă echipei dvs. pe GitLab și contribuiți la un proiect existent"
-msgid "Joined %{time_ago}"
-msgstr "S-a alăturat %{time_ago}"
-
msgid "Joined %{user_created_time}"
msgstr "S-a înscris la %{user_created_time}"
@@ -27658,9 +27568,6 @@ msgstr "Ultima activitate"
msgid "Last Name"
msgstr "Numele de familie"
-msgid "Last Pipeline"
-msgstr "Ultimul pipeline"
-
msgid "Last Seen"
msgstr "Văzut(ă) ultima dată"
@@ -27757,6 +27664,9 @@ msgstr "Ați împins la"
msgid "LastPushEvent|at"
msgstr "la"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "Ultimele modificări"
@@ -28465,6 +28375,9 @@ msgstr ""
msgid "Lock File?"
msgstr "Blocați fișierul?"
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr "Blocați abonamentele la sincronizarea LDAP"
@@ -28474,6 +28387,9 @@ msgstr ""
msgid "Lock not found"
msgstr "Blocajul nu a fost găsit"
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28879,6 +28795,12 @@ msgstr "URL-ul Mattermost:"
msgid "Mattermost notifications"
msgstr "Notificări Mattermost"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr "Adăugare la Mattermost"
@@ -28894,6 +28816,9 @@ msgstr "Completați cuvântul care se potrivește cel mai bine echipei dumneavoa
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr "URL de solicitare"
@@ -28906,6 +28831,9 @@ msgstr "Pictograma de răspuns"
msgid "MattermostService|Response username"
msgstr "Nume de utilizator de răspuns"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr "Sugestii:"
@@ -29212,6 +29140,102 @@ msgstr "%{member_name} v-a invitat să vă alăturați la GitLab"
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr "Invitație de aderare la %{project_or_group} %{project_or_group_name}"
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29473,6 +29497,9 @@ msgstr "Mesajul commit-ului de îmbinare"
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr "Detalii de îmbinare"
@@ -29905,9 +29932,6 @@ msgstr "Metrici și profilare"
msgid "Metrics:"
msgstr "Metrici:"
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr "nu poate fi anterioară datei de starting_at"
-
msgid "Metrics|Create metric"
msgstr "Creați o metrică"
@@ -30004,6 +30028,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30886,10 +30913,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30967,6 +30994,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30997,15 +31027,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31024,12 +31057,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31048,6 +31087,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31273,9 +31318,6 @@ msgstr "Răspuns nou pentru problema #%{issue_iid}:"
msgid "New runners registration token has been generated!"
msgstr "A fost generat un nou token de înregistrare a executorilor!"
-msgid "New schedule"
-msgstr "Program nou"
-
msgid "New snippet"
msgstr "Fragment de cod nou"
@@ -31483,6 +31525,9 @@ msgstr "Nicio iterație"
msgid "No label"
msgstr "Nicio etichetă"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "Nicio etichetă cu un astfel de nume sau descriere"
@@ -31507,6 +31552,12 @@ msgstr "Nicio potrivire de rezultate"
msgid "No matching results for \"%{query}\""
msgstr "Nicio potrivire de rezultate pentru „%{query}â€"
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr "Nu s-au găsit membri"
@@ -31525,12 +31576,15 @@ msgstr "Niciun obiectiv"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
+msgstr ""
+
msgid "No other labels with such name or description"
msgstr "Nicio altă etichetă cu un astfel de nume sau descriere"
-msgid "No panels matching properties %{opts}"
-msgstr "Niciun panou nu se potrivește cu proprietățile %{opts}"
-
msgid "No parent group"
msgstr "Niciun grup părinte"
@@ -31585,9 +31639,6 @@ msgstr ""
msgid "No runner executable"
msgstr "Niciun executor disponibil"
-msgid "No schedules"
-msgstr "Nicio programare"
-
msgid "No service accounts"
msgstr "Nu există conturi de servicii"
@@ -31639,6 +31690,12 @@ msgstr "Niciun eveniment webhook"
msgid "No webhooks enabled. Select trigger events above."
msgstr "Niciun webhooks activat. Selectați evenimentele de declanșare de mai sus."
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] "Nu vă faceți griji, puteți utiliza în continuare toate caracteristicile %{strong}%{plan_name}%{strong_close} pentru acum. Aveți la dispoziție %{remaining_days} zi pentru a vă reînnoi abonamentul."
@@ -32851,6 +32908,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr "Unul sau mai multe dintre tokenurile dvs. de acces personal vor expira în %{days_to_expire} zile sau mai puțin:"
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr "Numai membrii din %{workspaceType} cu %{permissions} pot vizualiza sau pot fi notificați despre acest/această %{issuableType}."
@@ -32878,9 +32938,6 @@ msgstr "Accesibil numai %{membersPageLinkStart}membrilor proiectului%{membersPag
msgid "Only active projects show up in the search and on the dashboard."
msgstr "Numai proiectele active apar în căutări și în tabloul de bord."
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr "Are efect numai atunci când este activată stocarea remote. Setați la 0 pentru nicio limită de mărime."
-
msgid "Only include features new to your current subscription tier."
msgstr "Includeți numai caracteristici noi pentru nivelul actual de abonament."
@@ -33043,24 +33100,60 @@ msgstr "Opțiuni"
msgid "Ordered list"
msgstr "Lista ordonată"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "Organizații"
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr "Membru orfan"
@@ -33775,6 +33868,9 @@ msgstr "Pages"
msgid "Pages Domain"
msgstr "Domeniul Pages"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr "Prima"
@@ -33922,8 +34018,11 @@ msgstr "Cale"
msgid "Path:"
msgstr "Cale:"
-msgid "Paths to protect with rate limiting"
-msgstr "Căile care trebuie protejate cu limitarea ratei"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
+msgstr ""
msgid "Pause"
msgstr "Pauză"
@@ -34369,9 +34468,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "Activat"
-
msgid "PipelineSchedules|Active"
msgstr "Activ"
@@ -34486,12 +34582,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Variabile"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr "Asumați-vă proprietatea de a edita"
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34942,6 +35032,9 @@ msgstr "Nu s-a putut recupera starea pipeline-ului. Pentru pașii de depanare, c
msgid "Pipeline|Created"
msgstr "Creată"
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr "Se creează pipeline-ul."
@@ -35065,9 +35158,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr "Autorul declanșatorului"
-msgid "Pipeline|Triggerer"
-msgstr "Declanșator"
-
msgid "Pipeline|Variables"
msgstr "Variabile"
@@ -35590,9 +35680,6 @@ msgstr "Lățimea aspectului"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "Trebuie să fie un număr între %{min} și %{max}."
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr "Previzualizare"
@@ -35704,6 +35791,9 @@ msgstr "Discuție anterioară nerezolvată"
msgid "Primary Action"
msgstr "Acțiune primară"
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35827,9 +35917,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35845,9 +35932,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35884,9 +35968,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35947,6 +36028,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35971,9 +36055,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36205,7 +36286,7 @@ msgstr "Nu afișați în profilul dvs. informații personale legate de propria a
msgid "Profiles|Edit Profile"
msgstr "Editare profil"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36640,9 +36721,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr "Ordinea proiectelor nu va fi salvată, deoarece nu este disponibilă stocarea locală."
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr "Calea proiectului"
@@ -37132,6 +37210,12 @@ msgstr "Feature Flags"
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "Instrument flexibil pentru dezvoltarea în colaborare a ideilor și planificarea activității în cadrul acestui proiect."
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr "Forkuri"
@@ -37267,6 +37351,9 @@ msgstr "Public"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr "Versiuni"
@@ -37339,6 +37426,9 @@ msgstr "Squashing-ul nu se efectuează niciodată, iar caseta de selectare este
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38158,6 +38248,12 @@ msgstr "Aprobarea proprietarului de cod"
msgid "ProtectedBranch|Create wildcard"
msgstr "Creați wildcard"
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38230,7 +38326,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr "Ce sunt ramurile protejate?"
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38287,10 +38383,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38302,6 +38401,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38320,6 +38422,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} va putea fi editat de dezvoltatori. Sunteți sigur?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr "Toate mediile specificate cu nivelurile de implementare de mai jos sunt protejate de un grup părinte. %{link_start}Aflați mai multe%{link_end}."
@@ -38377,9 +38482,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr "Selectați grupurile"
-msgid "ProtectedEnvironment|Select users"
-msgstr "Alegeți utilizatorii"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38446,9 +38548,6 @@ msgstr "Instrucțiuni de furnizare"
msgid "Provisioned by:"
msgstr "Furnizat de:"
-msgid "Proxy support for this API is not available currently"
-msgstr "Suportul proxy pentru acest API nu este disponibil în prezent"
-
msgid "Public"
msgstr "Public"
@@ -38809,9 +38908,6 @@ msgstr "Primiți notificări cu privire la rapoartele de abuz prin e-mail."
msgid "Receive notifications about your own activity"
msgstr "Primiți notificări despre propria activitate"
-msgid "Receive product marketing emails"
-msgstr "Primiți e-mailuri de marketing pentru produse"
-
msgid "Recent"
msgstr "Recent"
@@ -38953,36 +39049,12 @@ msgstr "trimiteți e-mailuri către utilizatori"
msgid "RegistrationFeatures|use this feature"
msgstr "utilizați această funcție"
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr "Sunteți sigur că doriți să săriți peste această etapă?"
-
-msgid "RegistrationVerification|Enable free compute minutes"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr "GitLab nu vă va debita cardul, acesta va fi folosit doar pentru validare."
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr "Pipeline-urile care utilizează executori partajați GitLab vor eșua până când nu vă validați contul."
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr "Săriți peste aceasta deocamdată."
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
+msgid "Registries enqueued to be reverified"
msgstr ""
-msgid "RegistrationVerification|Validate account"
-msgstr "Validați contul"
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr "Verificați-vă identitatea"
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr "Da, aș vrea să sar peste"
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
-msgstr "Puteți oricând să vă verificați contul ulterior."
-
msgid "Registry entry enqueued to be resynced"
msgstr ""
@@ -39316,9 +39388,6 @@ msgstr ""
msgid "Remove priority"
msgstr "Înlăturați prioritatea"
-msgid "Remove report"
-msgstr "Înlăturați raportul"
-
msgid "Remove reviewer"
msgstr "Înlăturați recenzentul"
@@ -39331,6 +39400,9 @@ msgstr "Înlăturați e-mailul secundar"
msgid "Remove spent time"
msgstr "Înlăturați timpul petrecut"
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr "Înlăturați estimarea timpului"
@@ -39340,9 +39412,6 @@ msgstr "Înlăturați avatarul subiectului"
msgid "Remove user"
msgstr "Înlăturați utilizatorul"
-msgid "Remove user & report"
-msgstr "Înlăturați utilizatorul și raportați-l"
-
msgid "Remove user from group"
msgstr "Înlăturați utilizatorul din grup"
@@ -39622,12 +39691,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Raportat(ă) %{timeAgo} de %{reportedBy}"
-msgid "Reported by"
-msgstr "Raportat de"
-
-msgid "Reported by %{reporter}"
-msgstr "Raportat de %{reporter}"
-
msgid "Reporter"
msgstr "Reporter"
@@ -39940,9 +40003,6 @@ msgstr "Recalcularea utilizării repozitoriului a început"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr "Repozitoriu: %{counter_repositories} / Wikis: %{counter_wikis} / Artefacte de construcție: %{counter_build_artifacts} / Artefacte de pipeline: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Fragmente de cod: %{counter_snippets} / Pachete: %{counter_packages} / Încărcări: %{counter_uploads}"
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "Selectați"
-
msgid "Request"
msgstr "Solicitare"
@@ -40360,6 +40420,9 @@ msgstr ""
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr "Numele regulii este deja luat."
@@ -40795,6 +40858,9 @@ msgstr "Membrii cu rol de %{type} pot înregistra executori"
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41083,7 +41149,7 @@ msgstr "Selectați proiectele pe care să le atribuiți acestui executor"
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41167,6 +41233,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41377,6 +41446,9 @@ msgstr "Pentru a permite ca %{strongOpen}%{group_name}%{strongClose} să vă adm
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "Autentificarea unică (SSO) a organizației dvs. a fost conectată la contul dvs. GitLab"
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41485,9 +41557,6 @@ msgstr "Salvați nota internă"
msgid "Save password"
msgstr "Salvați parola"
-msgid "Save pipeline schedule"
-msgstr "Salvați programul de pipeline"
-
msgid "Saving"
msgstr "Se salvează"
@@ -41500,7 +41569,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41626,10 +41695,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41644,6 +41716,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41656,7 +41746,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41668,7 +41758,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41680,6 +41770,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41707,9 +41803,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41821,6 +41926,9 @@ msgstr "Căutați un grup"
msgid "Search an environment spec"
msgstr "Căutați o specificație de mediu"
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "Căutați responsabili"
@@ -41890,15 +41998,12 @@ msgstr "Căutați obiective"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
-msgstr "Căutați sau filtrați rezultatele…"
-
msgid "Search or filter results…"
msgstr "Căutați sau filtrați rezultatele…"
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr "Pagina de căutare"
@@ -42136,6 +42241,9 @@ msgstr ""
msgid "Security dashboard"
msgstr "Tabloul de bord de securitate"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr "O aprobare de merge request este necesară atunci când scade gradul de coverage de teste."
@@ -42292,6 +42400,12 @@ msgstr " și "
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr " sau "
@@ -42301,7 +42415,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr "%{agent} pentru %{namespaces}"
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42358,6 +42478,9 @@ msgstr "A apărut o eroare la preluarea politicilor privind rezultatele scanări
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr "Sunteți sigur că doriți să ștergeți această politică? Această acțiune nu poate fi anulată."
@@ -42430,7 +42553,7 @@ msgstr "Activat"
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr "Impuneți securitatea pentru acest proiect. %{linkStart}Mai multe informații.%{linkEnd}"
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42442,12 +42565,18 @@ msgstr "Încărcarea agenților de cluster a eșuat."
msgid "SecurityOrchestration|Failed to load images."
msgstr "Nu s-a reușit încărcarea imaginilor."
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr "Dacă un scaner găsește o vulnerabilitate critică nou detectată într-un merge request deschis care vizează ramura principală, atunci solicitați două aprobări din partea oricărui membru al securității aplicației."
@@ -42715,6 +42844,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr "Vizualizați proiectul de politică"
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42727,13 +42859,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42763,13 +42895,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr "ramură"
msgid "SecurityOrchestration|branches"
msgstr "ramuri"
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42778,6 +42916,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42847,9 +42991,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "Adăugați sau eliminați proiecte de monitorizat în zona de securitate. Proiectele incluse în această listă vor avea rezultatele lor afișate în tabloul de bord de securitate și în raportul de vulnerabilitate."
@@ -42904,6 +43045,9 @@ msgstr "Comentariu editat la „%{vulnerabilityName}â€"
msgid "SecurityReports|Configure security testing"
msgstr "Configurați testarea securității"
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42919,9 +43063,15 @@ msgstr "Detecție"
msgid "SecurityReports|Development vulnerabilities"
msgstr "Vulnerabilități de dezvoltare"
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "Respingeți vulnerabilitatea"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "„%{vulnerabilityName}†a fost respinsă"
@@ -42952,6 +43102,9 @@ msgstr "Descărcați URL-urile scanate"
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr "Fie că nu aveți permisiunea de a vizualiza acest tablou de bord, fie tabloul de bord nu a fost configurat. Vă rugăm să verificați setările de permisiune cu administratorul dvs. sau verificați configurațiile tabloului de bord pentru a continua."
@@ -43069,9 +43222,6 @@ msgstr "Raportul a expirat"
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr "Rezultatele arată vulnerabilitățile introduse de merge request, în plus față de vulnerabilitățile existente din ultimul pipeline de succes din ramura implicită a proiectului dumneavoastră."
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr "Detalii de scanare"
@@ -43117,8 +43267,8 @@ msgstr "Încă se detectează"
msgid "SecurityReports|Submit vulnerability"
msgstr "Trimiteți vulnerabilitatea"
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
-msgstr "Raportul de vulnerabilitate prezintă rezultatele scanărilor reușite pe ramura implicită a proiectului dvs., înregistrările de vulnerabilități adăugate manual și vulnerabilitățile găsite în urma scanării mediilor operaționale. %{linkStart}Aflați mai multe.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
msgstr "Următoarele rapoarte de securitate conțin una sau mai multe detectări de vulnerabilitate care nu au putut fi analizate și nu au fost înregistrate. Pentru a investiga un raport, descărcați artefactele din ieșirea jobului. Asigurați-vă că raportul de securitate este conform cu schema %{helpPageLinkStart}JSON relevantă%{helpPageLinkEnd}."
@@ -43465,9 +43615,6 @@ msgstr "Trimiteți e-mailuri în format multipart (HTML și text simplu). Debifa
msgid "Send email notification"
msgstr "Trimiteți o notificare prin e-mail"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "Trimiteți e-mailuri pentru a ajuta la ghidarea noilor utilizatori prin procesul de onboarding."
-
msgid "Send emails to users upon account deactivation."
msgstr "Trimiteți e-mailuri utilizatorilor la dezactivarea contului."
@@ -43537,6 +43684,9 @@ msgstr "Cheile conturilor de servicii autorizează GitLab să implementeze proie
msgid "Service Desk"
msgstr "Service Desk"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr "Service Desk permite oamenilor să creeze probleme în instanța d-voastră GitLab fără propriul lor cont de utilizator. Acesta oferă o adresă de e-mail unică pentru ca utilizatorii finali să creeze probleme într-un proiect. Răspunsurile pot fi trimise fie prin interfața GitLab, fie prin e-mail. Utilizatorii finali văd discuțiile doar prin e-mail."
@@ -43561,12 +43711,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43594,9 +43756,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43606,27 +43774,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr "Activați Service Desk"
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr "Pentru a obține ajutor la configurarea Service Desk pentru instanța dvs., vă rugăm să contactați un administrator."
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr "Problemele create din e-mailurile Service Desk vor apărea aici. Fiecare comentariu devine parte a conversației din e-mail."
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43666,15 +43867,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr "Pentru a activa Service Desk pe această instanță, un administrator de instanță trebuie mai întâi să configureze e-mailul de intrare."
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr "Folosiți Service Desk pentru a vă conecta cu utilizatorii dvs. și pentru a oferi asistență clienților prin e-mail chiar în GitLab"
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr "Utilizatorii dvs. pot trimite e-mailuri la această adresă:"
@@ -43702,6 +43933,9 @@ msgstr "ID-ul sesiunii"
msgid "Session duration (minutes)"
msgstr "Durata sesiunii (minute)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "Setați %{epic_ref} ca epică părinte."
@@ -43822,6 +44056,9 @@ msgstr "Setați estimarea de timp la %{time_estimate}."
msgid "Set to 0 for no size limit."
msgstr "Setați la 0 pentru nicio limită de mărime."
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43900,6 +44137,9 @@ msgstr "Starea dvs. se resetează la %{date}."
msgid "Sets %{epic_ref} as parent epic."
msgstr "Setați %{epic_ref} ca epică părinte."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr "Setează starea de sănătate la %{health_status}."
@@ -44737,6 +44977,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Cineva, sperăm că dvs., a solicitat resetarea parolei pentru contul dvs. GitLab pe %{link_to_gitlab}."
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "Ceva nu a mers bine"
@@ -44830,9 +45073,6 @@ msgstr "Ceva nu a mers bine în timpul preluării modificărilor descrierii. Vă
msgid "Something went wrong while fetching details"
msgstr "Ceva nu a mers bine în timpul preluării detaliilor"
-msgid "Something went wrong while fetching latest comments."
-msgstr "Ceva nu a mers bine în timpul preluării ultimelor comentarii."
-
msgid "Something went wrong while fetching projects"
msgstr "Ceva nu a mers bine în timpul preluării proiectelor"
@@ -45781,6 +46021,18 @@ msgstr "Exportați fișierul de utilizare a licenței"
msgid "SubscriptionBanner|Upload new license"
msgstr "Încărcați noua licență"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr "Adăugați seat-uri"
@@ -45928,6 +46180,9 @@ msgstr "Dezactivat cu succes"
msgid "Successfully deleted WebAuthn device."
msgstr "Dispozitivul WebAuthn a fost înlăturat cu succes."
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "E-mail eliminat cu succes."
@@ -45946,6 +46201,9 @@ msgstr "Eliminarea excluderii a avut succes"
msgid "Successfully unblocked"
msgstr "Deblocat cu succes"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr "Deblocat cu succes"
@@ -46609,6 +46867,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr "Țintă"
@@ -46621,8 +46882,14 @@ msgstr "Calea de destinație"
msgid "Target branch"
msgstr "Ramura țintă"
-msgid "Target branch or tag"
-msgstr "Ramura sau eticheta țintă"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
+msgstr ""
msgid "Target branch: %{target_branch}"
msgstr ""
@@ -47461,9 +47728,6 @@ msgstr "Pagina nu a putut fi afișată deoarece a expirat."
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr "Epica părinte este confidențială și poate conține numai epice și probleme confidențiale."
-msgid "The parsed YAML is too big"
-msgstr "YAML-ul analizat este prea mare"
-
msgid "The password for the Jenkins server."
msgstr "Parola pentru serverul Jenkins."
@@ -47638,6 +47902,9 @@ msgstr "Vulnerabilitatea nu mai este detectată. Verificați dacă vulnerabilita
msgid "There are currently no mirrored repositories."
msgstr "În prezent, nu există repozitorii replicate."
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "Există conflicte de îmbinare"
@@ -47656,9 +47923,6 @@ msgstr "Nu există chei SSH cu acces la contul dumneavoastră."
msgid "There are no Spam Logs"
msgstr "Nu există jurnale de spam"
-msgid "There are no abuse reports!"
-msgstr "Nu există rapoarte de abuz!"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47908,6 +48172,9 @@ msgstr "A apărut o eroare la preluarea etichetelor de top pentru grupul selecta
msgid "There was an error fetching the variables."
msgstr "A apărut o eroare la preluarea variabilelor."
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr "A apărut o eroare la preluarea etapelor de analiză a fluxului de valori."
@@ -47992,6 +48259,9 @@ msgstr "A apărut o eroare cu reCAPTCHA. Vă rugăm să rezolvați din nou reCAP
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr "Aceste date influențează modul în care apar epicele dvs. în foaia de parcurs. Stabiliți o dată fixă sau una moștenită din obiectivele atribuite problemelor din această epică."
@@ -48496,9 +48766,15 @@ msgstr "Acest merge request este de la un proiect privat la un proiect intern."
msgid "This merge request is from an internal project to a public project."
msgstr "Acest merge request este de la un proiect intern la un proiect public."
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Acest merge request este blocat."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr "Acest merge request a fost îmbinat. Pentru a aplica această sugestie, editați direct acest fișier."
@@ -48517,11 +48793,11 @@ msgstr "Acest pipeline utilizează o configurație predefinită CI/CD activată
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
-msgstr "Acest pipeline a fost declanșat de o programare."
+msgid "This pipeline was created by a schedule."
+msgstr ""
msgid "This process deletes the project repository and all related resources."
msgstr "Acest proces șterge repozitoriul proiectului și toate resursele aferente."
@@ -48670,7 +48946,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48796,7 +49072,7 @@ msgstr "Fusul orar"
msgid "TimeTrackingEstimated|Est"
msgstr "Est"
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48817,7 +49093,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49243,7 +49519,7 @@ msgstr "Pentru a vă reactiva contul, conectați-vă la GitLab la %{gitlab_url}.
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49525,6 +49801,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "Mâine"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr "Prea multe spații de nume activate. Gestionați-le prin consolă sau prin API."
@@ -49606,6 +49885,9 @@ msgstr "Total"
msgid "Total Score"
msgstr "Scor total"
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr "Total nuclee (CPU)"
@@ -49636,9 +49918,15 @@ msgstr "1000+"
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr "Urmărire"
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49711,6 +49999,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50077,9 +50377,6 @@ msgstr "URL-ul sau ID-ul solicitării"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr "UTILIZATORUL %{user_name} VA FI ÎNLĂTURAT! Sunteți sigur?"
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "UTILIZATOR %{user} VA FI ÎNLĂTURAT! Sunteți sigur?"
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "UTILIZATORUL VA FI BLOCAT! Sunteți sigur?"
@@ -50167,6 +50464,9 @@ msgstr "Imposibil de încărcat widget-ul Merge-Request-ului. Încercați să re
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr "JSON nu poate fi analizat"
@@ -50200,9 +50500,6 @@ msgstr "Nu se poate actualiza această epică în acest moment."
msgid "Unable to update this issue at this time."
msgstr "Nu se poate actualiza această problemă în acest moment."
-msgid "Unable to verify the user"
-msgstr "Nu se poate verifica utilizatorul"
-
msgid "Unapprove a merge request"
msgstr "Dezaprobați un merge request"
@@ -50281,6 +50578,9 @@ msgstr "Din păcate, mesajul dvs. de e-mail către GitLab nu a putut fi procesat
msgid "Unhappy?"
msgstr "Nemulțumit(ă)?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50656,6 +50956,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr "Cumpărați spațiu de stocare"
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr "Pachete de cod și imagini de containere."
@@ -50677,10 +50980,10 @@ msgstr "Registrul de containere"
msgid "UsageQuota|Dependency proxy"
msgstr "Proxy de dependență"
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50728,6 +51031,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr "Stocarea spațiului de nume utilizată"
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50794,15 +51100,15 @@ msgstr "Grupul %{strong_start}%{context_name}%{strong_end} va fi afectat de aces
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr "Proiectul %{strong_start}%{context_name}%{strong_end} va fi afectat de acest lucru. "
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr ""
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr "Spațiul de nume utilizează în prezent %{strong_start}%{used_storage}%{strong_end} de spațiul de stocare al spațiului de nume. Vizualizați și gestionați utilizarea din %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Aflați mai multe%{link_end} despre cum să reduceți spațiul de stocare"
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr ""
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr ""
@@ -51475,6 +51781,9 @@ msgstr "Numele de utilizator este disponibil."
msgid "Username or email"
msgstr "Nume de utilizator sau e-mail"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Nume de utilizator:"
@@ -52180,6 +52489,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52207,17 +52519,20 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Confirmat%{statusEnd} %{timeago} de %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "%{statusStart}Detectat%{statusEnd} %{timeago} în pipeline-ul %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Respins%{statusEnd} %{timeago} de %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "%{statusStart}Rezolvat%{statusEnd} %{timeago} de %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr "(opțional) Includeți soluția la vulnerabilitate, dacă este disponibilă."
@@ -52459,6 +52774,9 @@ msgstr "Fișier:"
msgid "Vulnerability|GitLab Security Report"
msgstr "Raport de securitate GitLab"
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52573,10 +52891,7 @@ msgstr "Scanerul a determinat că această vulnerabilitate este un fals pozitiv.
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr "Răspunsul nemodificat este răspunsul original care nu a suferit nicio mutație la solicitare."
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52612,6 +52927,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr "AVERTISMENT:"
@@ -52939,6 +53257,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr "Evenimente de lansări"
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr "Verificarea SSL"
@@ -53041,15 +53365,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr "Bine ați venit, %{name}!"
-msgid "What are group audit events?"
-msgstr "Ce sunt evenimentele de audit de grup?"
-
-msgid "What are instance audit events?"
-msgstr "Ce sunt evenimentele de audit de instanță?"
-
-msgid "What are project audit events?"
-msgstr "Ce sunt evenimentele de audit de proiect?"
-
msgid "What are some examples?"
msgstr "Care sunt câteva exemple?"
@@ -53407,6 +53722,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53500,9 +53821,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr "Creați elementul de lucru"
@@ -53521,9 +53839,6 @@ msgstr "Data scadenței"
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53542,13 +53857,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr "Obiectiv"
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53692,9 +54013,6 @@ msgstr "Caz de testare"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr "Acest element de lucru este indisponibil. Fie nu există, fie nu aveți permisiunea de a-l vizualiza."
@@ -53725,7 +54043,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53824,9 +54142,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54088,6 +54403,9 @@ msgstr "Puteți crea un nou token de acces personal vizitând %{link}"
msgid "You can create a new SSH key by visiting %{link}"
msgstr "Puteți crea o nouă cheie SSH vizitând %{link}"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr "Puteți crea unul nou sau le puteți verifica în setările pentru %{pat_link_start}tokenurile de acces personal%{pat_link_end}."
@@ -54097,6 +54415,9 @@ msgstr "Puteți să creați una nouă sau să le verificați în setările %{ssh
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr "Puteți să creați una nouă sau să le verificați în setările cheilor SSH %{ssh_key_link}."
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr "Puteți să creați unul nou sau să le verificați în setările tokenurilor de acces personal %{pat_link}."
@@ -54295,9 +54616,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr "Nu aveți nicio implementare în acest moment."
-
msgid "You don't have any open merge requests"
msgstr "Nu aveți niciun merge request deschis"
@@ -54796,9 +55114,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "Aplicațiile dvs. autorizate"
-msgid "Your browser does not support iFrames"
-msgstr "Browserul dvs. nu acceptă iFrames"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr "Browserul dvs. nu acceptă WebAuthn. Vă rugăm să utilizați un browser compatibil, de exemplu Chrome (67+) sau Firefox (60+)."
@@ -54919,9 +55234,6 @@ msgstr "Tokenurile dvs. de acces personal vor expira în %{days_to_expire} zile
msgid "Your profile"
msgstr "Profilul d-voastră"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr "Proiectul dvs. nu mai primește beneficii GitLab Ultimate începând cu 2022-07-01. După cum a fost notificat în aplicație anterior, proiectele publice cu sursă deschisă de pe nivelul Gratuit se pot aplica la programul GitLab for Open Source pentru a primi beneficiile GitLab Ultimate. Consultați %{faq_link_start}FAQ%{link_end} pentru mai multe detalii."
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "Limita proiectelor dvs. este de %{limit} (de) proiecte! Vă rugăm să contactați administratorul dvs. pentru a o mări"
@@ -54946,6 +55258,9 @@ msgstr "Cerințele dvs. sunt importate. După terminare, veți primi un e-mail d
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr "Cerințele dvs. vor fi importate în fundal. După terminare, veți primi un e-mail de confirmare."
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr "Căutarea dvs. nu a găsit niciun commit."
@@ -55117,6 +55432,9 @@ msgstr ""
msgid "allowed to fail"
msgstr "permis să eșueze"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr "deja interzis din spațiul de nume"
@@ -55228,6 +55546,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr "nu poate fi setat pentru această resursă"
@@ -55756,6 +56077,9 @@ msgstr ""
msgid "created by"
msgstr "creat(ă) de"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr "zilnic"
@@ -55825,6 +56149,9 @@ msgstr "ex. %{token}"
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr "elementul nu este o ierarhie"
@@ -55912,9 +56239,6 @@ msgstr[2] "de fișiere"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "constatarea nu este găsită sau este deja atașată unei vulnerabilități"
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56182,6 +56506,9 @@ msgstr "este prea mare"
msgid "jigsaw is not defined"
msgstr "jigsaw nu este definit"
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr "analizator personalizat kuromoji"
@@ -56662,6 +56989,9 @@ msgstr "trebuie să fie în interiorul rețelei fork."
msgid "must be less than the limit of %{tag_limit} tags"
msgstr "trebuie să fie mai mic(ă) decât limita de %{tag_limit} (de) etichete"
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr "trebuie să fie setat pentru un spațiu de nume de proiect"
@@ -56671,6 +57001,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr "trebuie să fie unic(ă) prin statut și timp scurs în cadrul unei politici"
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56698,6 +57031,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr "nu trebuie să conțină combinații de cuvinte și litere utilizate în mod obișnuit"
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr "grupul-meu-formidabil"
@@ -56755,6 +57091,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item} și %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57064,6 +57403,9 @@ msgstr "%{slash_command} adaugă sau scade timpul deja petrecut."
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "a început o discuție pe %{design_link}"
@@ -57106,6 +57448,9 @@ msgstr "numele etichetei"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr "stările terraform"
@@ -57154,9 +57499,6 @@ msgstr "totalul trebuie să fie mai mic sau egal cu %{size}"
msgid "triggered"
msgstr "declanșat"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr "setări de autentificare cu doi factori"
@@ -57214,6 +57556,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "versiunea %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "prin %{closed_via}"
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index 5f95e6bfb06..0d8317ac912 100644
--- a/locale/ru/gitlab.po
+++ b/locale/ru/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ru\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr " %{start} по %{end}"
@@ -47,6 +47,13 @@ msgstr " и "
msgid " and %{sliced}"
msgstr " и %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr " или "
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} не может быть найден."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} дней до автоматичеÑкого ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ‚ÐµÐ³Ð¾Ð²"
@@ -910,7 +914,7 @@ msgstr "%{edit_in_new_fork_notice} Попробуйте загрузить фаÐ
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -988,6 +992,12 @@ msgstr "%{issuesSize} Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸ÐµÐ¼ %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "Раздел %{italic_start}Что нового%{italic_end} неактивен и недоÑтупен Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1063,6 +1073,9 @@ msgstr "%{labelStart}Ðемодифицированный ответ:%{labelEnd}
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} недоÑтупно"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,11 +1564,11 @@ msgstr "%{verb} %{time_spent_value} потраченного времени."
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} позволÑÑŽÑ‚ отправлÑÑ‚ÑŒ ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð²ÐµÐ±-приложениÑм в ответ на ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð² группе или проекте."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} позволÑÑŽÑ‚ отправлÑÑ‚ÑŒ ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð²ÐµÐ±-приложениÑм в ответ на ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð² группе или проекте. Мы рекомендуем иÑпользовать %{integrations_link_start}интеграции%{link_end} вмеÑто веб-обработчиков."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr ""
@@ -1663,6 +1676,9 @@ msgstr "+%{amount} ещё"
msgid "+ %{count} more"
msgstr "+ ещё %{count}"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ ещё %{moreCount}"
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "ПринÑÑ‚ÑŒ приглашение"
@@ -2730,6 +2782,9 @@ msgstr "Группы"
msgid "AccessDropdown|Roles"
msgstr "Роли"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "Пользователи"
@@ -2910,6 +2965,9 @@ msgstr ""
msgid "Action"
msgstr "ДейÑтвие"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3222,6 +3280,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3246,6 +3307,9 @@ msgstr "Добавить к рецензированию"
msgid "Add to tree"
msgstr "Добавить к дереву"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr "ДобавлÑйте теги в проекты, чтобы пользователÑм было легче их найти."
@@ -3273,7 +3337,7 @@ msgstr "Добавить/удалить"
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4113,7 +4177,7 @@ msgstr "Блокировка Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð¼ÐµÐµÑ‚ ÑледующÐ
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4737,6 +4801,9 @@ msgstr "Заголовок — обÑзательное поле Ð´Ð»Ñ Ð¾Ð¿Ð¾Ð²
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr "Ð”Ð»Ñ Ð¸Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ð¸ генерируетÑÑ URL-Ð°Ð´Ñ€ÐµÑ Ð²ÐµÐ±-обработчика и ключ авторизации. ПоÑле ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ð¸ оба Ñлемента видны во вкладке «ПроÑмотр учётных данных»."
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr "Добавить новую интеграцию"
@@ -5175,9 +5242,6 @@ msgstr "Произошла ошибка при получении публичн
msgid "An error occurred previewing the blob"
msgstr "Произошла ошибка при предварительном проÑмотре объекта"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr "Произошла ошибка при обновлении заголовка"
@@ -5268,6 +5332,9 @@ msgstr "Произошла ошибка при получении задач."
msgid "An error occurred while fetching label colors."
msgstr "Произошла ошибка при получении цветов меток."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr "Произошла ошибка при получении учаÑтников"
@@ -5455,6 +5522,9 @@ msgstr[3] "Произошла ошибка при Ñохранении параÐ
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "Произошла ошибка при запуÑке заданиÑ."
@@ -5470,6 +5540,12 @@ msgstr "Произошла ошибка при попытке запуÑтить
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "Произошла ошибка при обновлении утверждающих"
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr "Ð’Ñ‹ уверены, что хотите удалить Ñто уÑÑ‚Ñ€Ð
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Ð’Ñ‹ уверены, что вы хотите удалить Ñто раÑпиÑание Ñборочной линии?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6595,7 +6689,7 @@ msgstr "Ð’Ñ‹ уверены, что хотите ÑброÑить Ñтот тоÐ
msgid "Are you sure you want to retry this migration?"
msgstr "Ð’Ñ‹ уверены, что хотите попробовать повторить Ñту миграцию?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6750,6 +6844,9 @@ msgstr "СпиÑок разделённых запÑтыми веток, котÐ
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr "ПерÑональный ключ доÑтупа пользователÑ. Пользователь должен иметь доÑтуп к задаче. Ð’Ñе комментарии — от имени Ñтого пользователÑ."
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "СпроÑите Ñнова позже"
@@ -6966,6 +7063,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr "Ðевозможно удалить пользователÑ"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr "Введите минимум три Ñимвола Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr "Обзор платных планов"
@@ -8053,6 +8159,9 @@ msgstr[3] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "УчаÑтники, приглашённые Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ группового приглашениÑ, не могут быть удалены. Ð’Ñ‹ можете либо удалить вÑÑŽ группу, либо попроÑить владельца приглашённой группы удалить учаÑтника."
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr "Ðет пользователей Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ."
@@ -8065,6 +8174,12 @@ msgstr "Приглашение в проект"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "Удалить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %{username} из вашей подпиÑки"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ удалить %{username} из вашей подпиÑки. ЕÑли вы продолжите, пользователь будет удалён из группы %{namespace} и вÑех её подгрупп и проектов. ДейÑтвие не может быть отменено."
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] "Заблокировано %d обÑуждениÑми"
msgid "Blocked issue"
msgstr "Заблокированное обÑуждение"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr "Блокировка"
@@ -8171,9 +8292,6 @@ msgstr "Ðичего не найдено"
msgid "BoardNewEpic|Search groups"
msgstr "ПоиÑк групп"
-msgid "BoardNewEpic|Select a group"
-msgstr "Выберите группу"
-
msgid "BoardNewIssue|No matching results"
msgstr "Ðет подходÑщих результатов"
@@ -8261,9 +8379,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,8 +9555,8 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr "Может быть развернуто вручную в"
-msgid "Can create groups:"
-msgstr "Может Ñоздавать группы:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr ""
@@ -9827,6 +9942,9 @@ msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² заголовке не были ÑохраненÑ
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr "Проверьте ваши образы Docker на наличие из
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Проверка доÑтупноÑти %{text} ..."
@@ -9979,8 +10100,8 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "план %{selectedPlanText}"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr "Выберите шаблон..."
msgid "Choose a type..."
msgstr "Выберите тип..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Выберите файл…"
@@ -10435,15 +10559,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "Ðевозможно иÑпользовать маÑкируемую переменную Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ значением"
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr "ОкружениÑ"
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr "Удалить переменную"
-msgid "CiVariables|Remove variable row"
-msgstr "Удалить Ñтроку переменных"
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Тип"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "Значение"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (Ð’Ñе Ñреды)"
-
msgid "CiVariable|All environments"
msgstr "Ð’Ñе Ñреды"
@@ -10703,6 +10833,9 @@ msgstr "Клиенты"
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Клонировать"
@@ -11000,15 +11133,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr "КÑш клаÑтера очищен."
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11301,6 +11428,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11325,6 +11455,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11748,9 +11881,6 @@ msgstr "Ревью кода"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "Ðналитика Ð ÐµÑ†ÐµÐ½Ð·Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶Ð°ÐµÑ‚ ÑпиÑок открытых запроÑов на ÑлиÑние, которые находÑÑ‚ÑÑ Ð½Ð° Ñтадии проверки кода. Ð’ наÑтоÑщее Ð²Ñ€ÐµÐ¼Ñ Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ проекта и/или фильтров отÑутÑтвуют рецензируемые запроÑÑ‹ на ÑлиÑние."
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr ""
msgid "Collapse"
msgstr "Свернуть"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr "Ошибка при загрузке ÑпиÑка веток/тегов.
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "Ошибка при поиÑке ÑпиÑка веток/тегов. ПожалуйÑта, попробуйте ещё раз."
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "Ошибка при обновлении ÑпиÑка веток/тегов. ПожалуйÑта, попробуйте ещё раз."
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12383,7 +12513,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12599,13 +12729,16 @@ msgstr "КонфиденциальноÑÑ‚ÑŒ"
msgid "Configuration help"
msgstr ""
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "ÐаÑтроить меню и Ñодержимое раздела %{italic_start}Что нового%{italic_end}."
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
-msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
msgstr ""
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
@@ -12671,6 +12804,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr "Ошибка подключениÑ"
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr "Создать релиз"
msgid "Create requirement"
msgstr "Создать требование"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14429,9 +14616,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "ЧаÑовой поÑÑ Cron"
-
msgid "Cron time zone"
msgstr "ЧаÑовой поÑÑ Cron"
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "Групповой выпадающий фильтр"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr "Определить наÑтраиваемый шаблон Ñ Ñинт
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "Укажите Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ Ð½Ð° Ñтапе(ах) Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð² %{code_open}.gitlab-ci.yml%{code_close} Ð´Ð»Ñ Ð¾Ñ‚ÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð·Ð´ÐµÑÑŒ."
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr "Удалить метку: %{labelName}"
msgid "Delete pipeline"
msgstr "Удалить Ñборочную линию"
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr "Удалить проект"
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr "Упаковщик"
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16342,6 +16532,12 @@ msgstr "ЧаÑовой поÑÑ"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} других"
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr "Текущий проект"
@@ -16369,8 +16565,8 @@ msgstr "ПредоÑтавить права на запиÑÑŒ Ñтому клюÑ
msgid "DeployKeys|Loading deploy keys"
msgstr "Загрузка ключей развертываниÑ"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "Ðе найдено ключей развертываниÑ. Создайте первый Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ данной формы."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "Приватные ключи развертываниÑ"
@@ -16384,8 +16580,8 @@ msgstr "Публичные ключи развертываниÑ"
msgid "DeployKeys|Read access only"
msgstr "ДоÑтуп только на чтение"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "Ðктивные токены Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
msgstr ""
@@ -16408,6 +16604,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr "Копировать токен развёртываниÑ"
@@ -16468,8 +16667,8 @@ msgstr "ОблаÑти"
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
-msgstr "%{entity_type} не имеет токенов развертываниÑ."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
+msgstr ""
msgid "DeployTokens|This action cannot be undone."
msgstr "Это дейÑтвие Ð½ÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ."
@@ -16486,10 +16685,10 @@ msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16661,6 +16863,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16676,12 +16896,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
-msgstr "Это развёртывание было Ñоздано Ñ Ð¸Ñпользованием API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr "Данные и файлы ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½Ð°Ð¼Ð¸"
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} из %{designs_count}"
@@ -17963,9 +18180,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr "Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð°:"
@@ -18008,6 +18222,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "ÐдреÑа Ñл. почты"
@@ -18146,9 +18363,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr "УбедитеÑÑŒ, что ваша Ñреда %{linkStart}ÑвлÑетÑÑ Ñ‡Ð°Ñтью Ñтапа развёртываниÑ%{linkEnd} Ñборочной линии CI Ð´Ð»Ñ Ð¾Ñ‚ÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ñ€Ð°Ð·Ð²Ñ‘Ñ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð² ваш клаÑтер."
@@ -18398,7 +18609,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18545,12 +18756,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Задание"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18596,6 +18813,12 @@ msgstr "Откатить окружение %{name}?"
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr ""
msgid "Expand"
msgstr "Развернуть"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Развернуть вÑе"
@@ -19737,6 +19972,9 @@ msgstr ""
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr "Фильтр по пользователю"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr "Фильтр..."
-
msgid "Finalizing"
msgstr ""
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "Обзор платных планов"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "Обзор платных планов"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21852,6 +22063,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr "Серверы Gitaly"
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22008,7 +22219,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr "ДоÑтуп предоÑтавлен %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr "Ð”Ð°Ð½Ð½Ð°Ñ Ñ†ÐµÐ»ÑŒ уже ÑвÑзана Ñ Ñтой целью."
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22128,9 +22348,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr "ПоиÑк в GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22527,6 +22753,9 @@ msgstr "Ðватар группы"
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "ОпиÑание группы (необÑзательно)"
@@ -22593,9 +22822,6 @@ msgstr "Ðазвание группы (вашей организации)"
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr "Содержание обзора группы"
@@ -22971,7 +23197,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23160,8 +23386,8 @@ msgstr "Эта функциональноÑÑ‚ÑŒ требует поддержкÐ
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "Группа - Ñто набор из неÑкольких проектов."
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
msgid "GroupsEmptyState|Create new project"
msgstr ""
@@ -23172,8 +23398,8 @@ msgstr "Создать новую подгруппу"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "При размещении проектов в группе, группа выполнÑет функции папки."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
msgid "GroupsEmptyState|No archived projects."
msgstr ""
@@ -23190,9 +23416,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "Ð’Ñ‹ можете управлÑÑ‚ÑŒ правами и доÑтупом учаÑтников вашей группы к каждому проекту в группе."
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23618,6 +23841,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23883,9 +24109,6 @@ msgstr "Я хочу хранить Ñвой код"
msgid "I want to use GitLab CI with my existing repository"
msgstr "Я хочу иÑпользовать GitLab CI Ñ Ð¼Ð¾Ð¸Ð¼ ÑущеÑтвующим репозиторием"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23925,6 +24148,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "ИÐФОРМÐЦИЯ: Срок дейÑÑ‚Ð²Ð¸Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ SSH-ключа иÑтёк. ПожалуйÑта, Ñоздайте новый."
@@ -24108,6 +24337,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24984,66 +24916,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr "обновите наÑтройки"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25867,15 +25765,9 @@ msgstr "Внутренние пользователи не могут быть Ð
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "Шаблон интервала"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26294,18 +26183,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr "убрал(а) ответÑтвенного"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr "Закрыто"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Закрыто (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26555,28 +26438,50 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr "ОбÑуждениÑ, запроÑÑ‹ на ÑлиÑниÑ, отправки изменений и комментарии."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "ПоÑле того как вы начнёте Ñоздавать обÑÑƒÐ¶Ð´ÐµÐ½Ð¸Ñ Ð² Ñвоих проектах, мы Ñможем начать отÑлеживание и отображение метрик Ð´Ð»Ñ Ð½Ð¸Ñ…"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "ПоÑледние 12 меÑÑцев"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr "ИтерациÑ"
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27458,6 +27369,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27509,6 +27423,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27605,9 +27522,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr "ПоÑледнÑÑ Ð¡Ð±Ð¾Ñ€Ð¾Ñ‡Ð½Ð°Ñ Ð›Ð¸Ð½Ð¸Ñ"
-
msgid "Last Seen"
msgstr ""
@@ -27973,6 +27884,9 @@ msgstr "Вы отправили в"
msgid "LastPushEvent|at"
msgstr "в"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "ПоÑледние изменениÑ"
@@ -28688,6 +28602,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr "Блокировка членÑтва в Ñинхронизации LDAP"
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr "Блокировка не найдена"
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29117,6 +29043,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29129,6 +29058,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29435,6 +29367,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr "Ðапишите комментарий к коммиту запроÑа
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr "Метрики и профилирование"
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr "Создать метрику"
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31225,15 +31259,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31252,12 +31289,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31276,6 +31319,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr "Ðовый региÑтрационный токен обработчика заданий Ñгенерирован!"
-msgid "New schedule"
-msgstr "Ðовое раÑпиÑание"
-
msgid "New snippet"
msgstr "Ðовый Ñниппет"
@@ -31712,6 +31758,9 @@ msgstr "Ðет итераций"
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "Ðет меток Ñ Ñ‚Ð°ÐºÐ¸Ð¼ наименованием или опиÑанием"
@@ -31736,6 +31785,12 @@ msgstr "Ðет результатов"
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,12 +31809,15 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
-msgstr "Ðет других меток Ñ Ñ‚Ð°ÐºÐ¸Ð¼ наименованием или опиÑанием"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
msgstr ""
+msgid "No other labels with such name or description"
+msgstr "Ðет других меток Ñ Ñ‚Ð°ÐºÐ¸Ð¼ наименованием или опиÑанием"
+
msgid "No parent group"
msgstr ""
@@ -31814,9 +31872,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "Ðет раÑпиÑаний"
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33087,6 +33148,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33279,24 +33340,60 @@ msgstr "ÐаÑтройки"
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34012,6 +34109,9 @@ msgstr "Страницы"
msgid "Pages Domain"
msgstr "Домен Pages"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34159,7 +34259,10 @@ msgstr "Путь"
msgid "Path:"
msgstr "Путь:"
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34606,9 +34709,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "Ðктивировано"
-
msgid "PipelineSchedules|Active"
msgstr "Ðктивно"
@@ -34723,12 +34823,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Переменные"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35179,6 +35273,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr "Переменные"
@@ -35827,9 +35921,6 @@ msgstr "Ширина макета"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "Должно быть чиÑлом между %{min} и %{max}"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35941,6 +36032,9 @@ msgstr "ÐŸÑ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ Ð½ÐµÐ·Ð°Ð²ÐµÑ€ÑˆÑ‘Ð½Ð½Ð°Ñ Ð´Ð¸ÑкуÑÑиÑ"
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr "Изменить профиль"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36877,9 +36962,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "Гибкий инÑтрумент Ð´Ð»Ñ ÑовмеÑтной разработки идей и Ð¿Ð»Ð°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ в Ñтом проекте."
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr "ОтветвлениÑ"
@@ -37504,6 +37592,9 @@ msgstr "ПубличнаÑ"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37576,6 +37667,9 @@ msgstr "Сжатие никогда не выполнÑетÑÑ, а флажок
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38395,6 +38489,12 @@ msgstr "Одобрение владельцем кода"
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} будет доÑтупно Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ°Ð¼Ð¸. Ð’Ñ‹ уверены?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr "Выбрать пользователей"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr "Публичный"
@@ -39048,9 +39151,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr "Получать ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾ Ñвоей деÑтельноÑти"
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr "ПоÑледние"
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr "Удалить потраченное времÑ"
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr "Удалить оценку времени"
@@ -39581,9 +39657,6 @@ msgstr "Удалить логотип тега"
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr "Удалить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð· группы"
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Сообщил %{reportedBy} %{timeAgo}"
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40187,9 +40254,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr "Сохранить пароль"
-msgid "Save pipeline schedule"
-msgstr "Сохранить раÑпиÑание Ñборочной лини"
-
msgid "Saving"
msgstr ""
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "ИÑкать ответÑтвенных"
@@ -42150,13 +42262,10 @@ msgstr "ПоиÑк Ñтапов"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42407,6 +42516,9 @@ msgstr ""
msgid "Security dashboard"
msgstr "Панель безопаÑноÑти"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr "Служба поддержки"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr "ПродолжительноÑÑ‚ÑŒ ÑеÑÑии (в минутах)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "УÑтановить %{epic_ref} в качеÑтве родительÑкой цели."
@@ -44095,6 +44333,9 @@ msgstr "Задать оценку времени в %{time_estimate}."
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr "Ваш ÑÑ‚Ð°Ñ‚ÑƒÑ ÑброÑитÑÑ %{date}."
msgid "Sets %{epic_ref} as parent epic."
msgstr "УÑтанавливает %{epic_ref} как родительÑкую цель."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr "Что-то пошло не так при получении поÑледних комментариев."
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr "Добавить меÑта"
@@ -46203,6 +46459,9 @@ msgstr "УÑпешно деактивирован"
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "ÐÐ´Ñ€ÐµÑ Ñлектронной почты уÑпешно удален."
@@ -46221,6 +46480,9 @@ msgstr "УÑпешно разбанен"
msgid "Successfully unblocked"
msgstr "УÑпешно разблокировано"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr "УÑпешно разблокировано"
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46898,7 +47163,13 @@ msgstr ""
msgid "Target branch"
msgstr "Ð¦ÐµÐ»ÐµÐ²Ð°Ñ Ð²ÐµÑ‚ÐºÐ°"
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47940,9 +48211,6 @@ msgstr "Ðет ключей SSH Ñ Ð´Ð¾Ñтупом к вашей учетной
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr "Ðет Ñообщений о нарушениÑÑ…!"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr "Произошла ошибка при извлечении переменных."
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr "Произошла ошибка при получении Ñтапов аналитики потока значений."
@@ -48276,6 +48547,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние заблокирован."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,10 +49081,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48954,7 +49234,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,7 +49360,7 @@ msgstr "ЧаÑовой поÑÑ"
msgid "TimeTrackingEstimated|Est"
msgstr "Оцен."
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49101,7 +49381,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "Завтра"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr "Ð’Ñего"
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr "ТраÑÑировка"
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr "Ðевозможно обновить Ñто обÑуждение в данный момент."
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr "К Ñожалению, ваше пиÑьмо в GitLab не может Ð
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50966,10 +51273,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51083,13 +51393,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51765,6 +52075,9 @@ msgstr ""
msgid "Username or email"
msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ email"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ:"
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53333,15 +53661,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53817,9 +54139,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr "Ðа текущий момент у Ð²Ð°Ñ Ð½ÐµÑ‚ развёртываний."
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "Ваш лимит проектов - %{limit} проектов! ПожалуйÑта, ÑвÑжитеÑÑŒ Ñ Ð²Ð°ÑˆÐ¸Ð¼ админиÑтратором, чтобы увеличить его"
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr "По вашему запроÑу не найдено ни одного коммита."
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56141,6 +56469,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr "Ñлемент не ÑвлÑетÑÑ Ð¸ÐµÑ€Ð°Ñ€Ñ…Ð¸ÐµÐ¹"
@@ -56229,9 +56560,6 @@ msgstr[3] "файлов"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr "Ñлишком большой"
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, и %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57398,6 +57741,9 @@ msgstr ""
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "начата диÑкуÑÑÐ¸Ñ Ð¿Ð¾ %{design_link}"
@@ -57440,6 +57786,9 @@ msgstr "название тега"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57488,9 +57837,6 @@ msgstr ""
msgid "triggered"
msgstr "запущено"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "верÑÐ¸Ñ %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "через %{closed_via}"
diff --git a/locale/si_LK/gitlab.po b/locale/si_LK/gitlab.po
index 863ebee61e7..12f2b15a943 100644
--- a/locale/si_LK/gitlab.po
+++ b/locale/si_LK/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: si-LK\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr " %{start} සිට %{end}"
@@ -45,6 +45,11 @@ msgstr " සහ "
msgid " and %{sliced}"
msgstr " සහ %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " à·„à· "
@@ -279,8 +284,8 @@ msgstr[1] "සමූහ %d"
msgid "%d group found"
msgid_plural "%d groups found"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "සමූහ %d ක් හමු විය"
+msgstr[1] "සමූහ %d ක් හමු විය"
msgid "%d hour"
msgid_plural "%d hours"
@@ -618,8 +623,8 @@ msgstr "ගොනු %{count}ක් ස්පර්à·à¶ºà·’"
msgid "%{count} group"
msgid_plural "%{count} groups"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "සමූහ %{count}"
+msgstr[1] "සමූහ %{count}"
msgid "%{count} issue"
msgid_plural "%{count} issues"
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} සොය෠ගà·à¶±à·“මට නොහà·à¶šà·’යි."
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr "%{edit_in_new_fork_notice} යළි ගොනුවක් උඩුගà
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@සමà·à¶œà¶¸.ලංකà·"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -785,7 +787,7 @@ msgid "%{issuable_class_name} doesn't exist or you don't have permission to add
msgstr ""
msgid "%{issuable}(s) already assigned"
-msgstr ""
+msgstr "%{issuable} දà·à¶±à¶§à¶¸à¶­à·Š පවර෠ඇත"
msgid "%{issueType} actions"
msgstr "ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œ %{issueType}"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr "%{labelStart}අසංà·à·à¶°à·’ත ප්â€à¶»à¶­à·’චà·à¶»à¶º:%{l
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} නොතිබේ"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1112,10 +1123,10 @@ msgid "%{spanStart}in%{spanEnd} %{errorFn}"
msgstr ""
msgid "%{startDate} – %{dueDate}"
-msgstr ""
+msgstr "%{startDate} – %{dueDate}"
msgid "%{startDate} – No due date"
-msgstr ""
+msgstr "%{startDate} – නියමිත දිනයක් නà·à¶­"
msgid "%{start} to %{end}"
msgstr "%{start} සිට %{end}"
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1415,7 +1426,7 @@ msgid "(revoked)"
msgstr "(අහà·à·ƒà·’යි)"
msgid "(this user)"
-msgstr "(මෙම පරිà·à·“ලකයà·)"
+msgstr "(මෙම පරිà·à·Šâ€à¶»à·“ලකයà·)"
msgid "(we need your current password to confirm your changes)"
msgstr "(ඔබගේ වෙනස්කම් තහවුරුවට අපට වත්මන් මුරපදය අවà·à·Šâ€à¶ºà¶ºà·’)"
@@ -1429,6 +1440,9 @@ msgstr "තවත් + %{amount}"
msgid "+ %{count} more"
msgstr "තවත් + %{count}"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "තවත් + %{moreCount}"
@@ -1465,7 +1479,7 @@ msgid "- %{policy_name} (notifying after %{elapsed_time} minutes unless %{status
msgstr ""
msgid "- Add or remove a user."
-msgstr "- පුද්ගලයෙක් එක් හ෠ඉවතලන්න."
+msgstr "- යමෙක් එක් හ෠ඉවත් කරන්න."
msgid "- Available to run jobs."
msgstr ""
@@ -1482,7 +1496,7 @@ msgstr[0] "- සිදුවීම"
msgstr[1] "- සිදුවීම්"
msgid "- Go to the Activity page for %{project_name}."
-msgstr ""
+msgstr "- %{project_name} සඳහ෠ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š පිටුවට යන්න."
msgid "- List the visible events for %{project_name} using the Events API %{events_api_link}."
msgstr ""
@@ -1498,8 +1512,8 @@ msgstr "- තà·à¶»à¶±à·Šà¶± -"
msgid "- User"
msgid_plural "- Users"
-msgstr[0] "- පරිà·à·“ලක"
-msgstr[1] "- පරිà·à·“ලකයින්"
+msgstr[0] "- පරිà·à·Šâ€à¶»à·“ලකයà·"
+msgstr[1] "- පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "- View the last_activity_at attribute for %{project_name} using the Project API %{projects_api_link}."
msgstr ""
@@ -1758,7 +1772,7 @@ msgid "A confidential work item cannot have a parent that already has non-confid
msgstr ""
msgid "A deleted user"
-msgstr "මකà·à¶¯à·à¶¸à·– පරිà·à·“ලකයෙකි"
+msgstr "මකà·à¶¯à·à¶¸à·– පරිà·à·Šâ€à¶»à·“ලකයෙකි"
msgid "A different reason"
msgstr "වෙනස් හේතුවක්"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2310,7 +2354,7 @@ msgid "AbuseReport|Go to profile"
msgstr ""
msgid "AbuseReport|Groups"
-msgstr ""
+msgstr "සමූහ"
msgid "AbuseReport|Last login"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2382,7 +2429,7 @@ msgid "AbuseReport|Something else"
msgstr ""
msgid "AbuseReport|Spam"
-msgstr ""
+msgstr "අයà·à¶ à·’ත"
msgid "AbuseReport|Tier"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "ආරà·à¶°à¶±à·à·€ පිළිගන්න"
@@ -2444,8 +2494,11 @@ msgstr "සමූහ"
msgid "AccessDropdown|Roles"
msgstr "භූමිකà·"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
-msgstr "පරිà·à·“ලකයින්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "AccessTokens|Access Tokens"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr "ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2664,10 +2720,10 @@ msgid "Active project access tokens"
msgstr ""
msgid "Activity"
-msgstr "ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸"
+msgstr "ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š"
msgid "Activity|An error occurred while retrieving activity. Reload the page to try again."
-msgstr ""
+msgstr "ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š ගà·à¶±à·“මේදී දà·à·‚යක් මතු විය. පිටුව නà·à·€à¶­ පූරණය කර බලන්න."
msgid "Add"
msgstr "එකතු"
@@ -2898,7 +2954,7 @@ msgid "Add new webhook"
msgstr ""
msgid "Add or remove a user."
-msgstr "පුද්ගලයෙක් එක්/ඉවත් කරන්න."
+msgstr "යමෙක් එක් හ෠ඉවත් කරන්න."
msgid "Add or remove previously merged commits"
msgstr ""
@@ -2928,7 +2984,7 @@ msgid "Add request manually"
msgstr "ඉල්ලීම අතින් යොදන්න"
msgid "Add start and due date"
-msgstr ""
+msgstr "ආරම්භක හ෠නියමිත දිනය යොදන්න"
msgid "Add suggestion to batch"
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr "එකතු/ඉවතට"
msgid "AddMember|Invite email is invalid"
msgstr "ආරà·à¶°à¶±à· තà·à¶´à·‘ල වලංගු නොවේ"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3126,7 +3188,7 @@ msgid "AdminArea|%{billable_users_link_start}Learn more%{billable_users_link_end
msgstr ""
msgid "AdminArea|Active users"
-msgstr "සක්â€à¶»à·’ය පරිà·à·“ලකයින්"
+msgstr "සක්â€à¶»à·’ය පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "AdminArea|All users created in the instance, including users who are not %{billable_users_link_start}billable users%{billable_users_link_end}."
msgstr ""
@@ -3135,7 +3197,7 @@ msgid "AdminArea|Are you sure?"
msgstr ""
msgid "AdminArea|Blocked users"
-msgstr "අවහිර කළ පරිà·à·“ලකයින්"
+msgstr "අවහිර කළ පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "AdminArea|Bots"
msgstr "ස්වයංක්â€à¶»à¶¸à¶½à·šà¶›"
@@ -3207,7 +3269,7 @@ msgid "AdminArea|New project"
msgstr "නව ව්â€à¶ºà·à¶´à·˜à¶­à·’ය"
msgid "AdminArea|New user"
-msgstr "නව පරිà·à·“ලක"
+msgstr "නව පරිà·à·Šâ€à¶»à·“ලක"
msgid "AdminArea|No applications found"
msgstr "යෙදුම් හමු නොවිණි"
@@ -3237,7 +3299,7 @@ msgid "AdminArea|Total Non-Billable users"
msgstr ""
msgid "AdminArea|Total users"
-msgstr "මුළු පරිà·à·“ලකයින්"
+msgstr "මුළු පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "AdminArea|Totals"
msgstr ""
@@ -3246,10 +3308,10 @@ msgid "AdminArea|Updated %{last_update_time}"
msgstr ""
msgid "AdminArea|Users"
-msgstr "පරිà·à·“ලකයින්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "AdminArea|Users statistics"
-msgstr "පරිà·à·“ලක සංඛ්â€à¶ºà·à¶½à·šà¶›à¶±"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක සංඛ්â€à¶ºà·à¶½à·šà¶›à¶±"
msgid "AdminArea|Users with highest role"
msgstr "ඉහළම භූමිකà·à·€à¶šà·Š සහිත පුද්ගලයින්"
@@ -3258,7 +3320,7 @@ msgid "AdminArea|Users with highest role guest and with a %{strongOpen}Custom Ro
msgstr ""
msgid "AdminArea|Users without a Group and Project"
-msgstr "සමූහයක් හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් නà·à¶­à·’ පරිà·à·“ලකයින්"
+msgstr "සමූහයක් හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් නà·à¶­à·’ පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "AdminArea|View latest groups"
msgstr "නවතම සමූහ බලන්න"
@@ -3267,7 +3329,7 @@ msgid "AdminArea|View latest projects"
msgstr "නවතම ව්â€à¶ºà·à¶´à·˜à¶­à·’ බලන්න"
msgid "AdminArea|View latest users"
-msgstr "නවතම පරිà·à·“ලකයින් බලන්න"
+msgstr "නවතම පරිà·à·Šâ€à¶»à·“ලකයින් බලන්න"
msgid "AdminArea|Yes, proceed"
msgstr ""
@@ -3294,10 +3356,10 @@ msgid "AdminEmail|Body is required."
msgstr ""
msgid "AdminEmail|Loading groups and projects."
-msgstr ""
+msgstr "සමූහ සහ ව්â€à¶ºà·à¶´à·˜à¶­à·’ පූරණය වෙමින්."
msgid "AdminEmail|No groups or projects found."
-msgstr ""
+msgstr "සමූහ හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’ හමු නොවිණි."
msgid "AdminEmail|Recipient group or project"
msgstr ""
@@ -3699,7 +3761,7 @@ msgid "AdminStatistics|Merge requests"
msgstr "ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම්"
msgid "AdminStatistics|Milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶±"
msgid "AdminStatistics|Notes"
msgstr "සටහන්"
@@ -3827,8 +3889,8 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
-msgstr "සමූහයක් සෑදිය à·„à·à¶šà·’ය"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr ""
@@ -3843,7 +3905,7 @@ msgid "AdminUsers|Compute quota"
msgstr ""
msgid "AdminUsers|Confirm user"
-msgstr "පරිà·à·“ලක තහවුරුව"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක තහවුරුව"
msgid "AdminUsers|Confirm user %{username}?"
msgstr ""
@@ -3864,16 +3926,16 @@ msgid "AdminUsers|Deactivating a user has the following effects:"
msgstr ""
msgid "AdminUsers|Delete User %{username} and contributions?"
-msgstr "පරිà·à·“ලක %{username} සහ දà·à¶ºà¶šà¶­à·Šà·€ මකන්නද?"
+msgstr "%{username} පරිà·à·Šâ€à¶»à·“ලකය෠සහ දà·à¶ºà¶šà¶­à·Šâ€à·€ මකන්නද?"
msgid "AdminUsers|Delete User %{username}?"
-msgstr "පරිà·à·“ලක %{username} මකන්නද?"
+msgstr "%{username} පරිà·à·Šâ€à¶»à·“ලකය෠මකන්නද?"
msgid "AdminUsers|Delete user"
msgstr "පරිà·à·“ලකය෠මකන්න"
msgid "AdminUsers|Delete user and contributions"
-msgstr "පරිà·à·“ලක සහ දà·à¶ºà¶šà¶­à·Šâ€à·€ මකන්න"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකය෠සහ දà·à¶ºà¶šà¶­à·Šâ€à·€ මකන්න"
msgid "AdminUsers|Export permissions as CSV (max 100,000 users)"
msgstr "CSV ලෙස අවසර නිර්යà·à¶­à¶º (උපරිම පුද්ගලයින් 100,000)"
@@ -3906,7 +3968,7 @@ msgid "AdminUsers|LDAP Blocked"
msgstr ""
msgid "AdminUsers|Learn more about %{link_start}banned users.%{link_end}"
-msgstr "%{link_start}තහනම් කළ පරිà·à·“ලකයින්%{link_end} ගà·à¶± තව දà·à¶±à¶œà¶±à·Šà¶±."
+msgstr "%{link_start}තහනම් කළ පරිà·à·Šâ€à¶»à·“ලකයින්%{link_end} ගà·à¶± තව දà·à¶±à¶œà¶±à·Šà¶±."
msgid "AdminUsers|Limits"
msgstr "සීමà·"
@@ -3924,10 +3986,10 @@ msgid "AdminUsers|Manage (accept/reject) pending user sign ups"
msgstr ""
msgid "AdminUsers|New user"
-msgstr "නව පරිà·à·“ලක"
+msgstr "නව පරිà·à·Šâ€à¶»à·“ලක"
msgid "AdminUsers|No users found"
-msgstr "පරිà·à·“ලකයින් හමු නොවිණි"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින් හමු නොවිණි"
msgid "AdminUsers|Owned groups will be left"
msgstr ""
@@ -3942,7 +4004,7 @@ msgid "AdminUsers|Personal projects, group and user history will be left intact"
msgstr ""
msgid "AdminUsers|Private profile"
-msgstr ""
+msgstr "පෞද්ගලික පà·à¶­à·’කඩකි"
msgid "AdminUsers|Projects, issues, merge requests, and comments of this user are hidden from other users."
msgstr ""
@@ -3966,7 +4028,7 @@ msgid "AdminUsers|Rejected users:"
msgstr ""
msgid "AdminUsers|Reset link will be generated and sent to the user. User will be forced to set the password on first sign in."
-msgstr "යළි à·ƒà·à¶šà·ƒà·“මේ සබà·à¶³à·’ය උත්පà·à¶¯à¶±à¶º කර පරිà·à·“ලකය෠වෙත යවනු ලà·à¶¶à·š. පළමු පිවිසුමේදී මුරපදය à·ƒà·à¶šà·ƒà·“මට පරිà·à·“ලකයà·à¶§ බල කෙරෙනු ඇත."
+msgstr "යළි à·ƒà·à¶šà·ƒà·“මේ සබà·à¶³à·’ය උත්පà·à¶¯à¶±à¶º කර පරිà·à·Šâ€à¶»à·“ලකය෠වෙත යවනු ලà·à¶¶à·š. පළමු පිවිසුමේදී මුරපදය à·ƒà·à¶šà·ƒà·“මට පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ බල කෙරෙනු ඇත."
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
@@ -3975,7 +4037,7 @@ msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
-msgstr "පරිà·à·“ලකයින් සොයන්න"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින් සොයන්න"
msgid "AdminUsers|Send email to users"
msgstr "පුද්ගලයින්ට වි-තà·à¶´à·à¶½à·Š යවන්න"
@@ -3993,25 +4055,25 @@ msgid "AdminUsers|The user can't access git repositories."
msgstr ""
msgid "AdminUsers|The user can't log in."
-msgstr "පරිà·à·“ලකයà·à¶§ පිවිසීමට නොහà·à¶šà·’ය."
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ පිවිසීමට නොහà·à¶šà·’ය."
msgid "AdminUsers|The user has unlimited access to all groups, projects, users, and features."
-msgstr "පරිà·à·“ලකයà·à¶§ සියළුම සමූහ, ව්â€à¶ºà·à¶´à·˜à¶­à·’, පරිà·à·“ලකයින් සහ විà·à·šà·‚à·à¶‚ග වෙත අසීමිත ප්â€à¶»à·€à·šà·à¶ºà¶šà·Š ඇත."
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ සියළුම සමූහ, ව්â€à¶ºà·à¶´à·˜à¶­à·’, පරිà·à·“ලකයින් සහ විà·à·šà·‚à·à¶‚ග වෙත අසීමිත ප්â€à¶»à·€à·šà·à¶ºà¶šà·Š ඇත."
msgid "AdminUsers|The user will be logged out"
-msgstr "පරිà·à·“ලකය෠නික්මෙනු ඇත"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකය෠නික්මෙනු ඇත"
msgid "AdminUsers|The user will not be able to access git repositories"
-msgstr "පරිà·à·“ලකයà·à¶§ ගිට් කà·à·‚්ඨ වෙත ප්â€à¶»à·€à·šà· වීමට නොහà·à¶šà·’ වේ"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ ගිට් කà·à·‚්ඨ වෙත ප්â€à¶»à·€à·šà· වීමට නොහà·à¶šà·’ වේ"
msgid "AdminUsers|The user will not be able to access the API"
-msgstr "පරිà·à·“ලකයà·à¶§ යෙ.ක්â€à¶».මු. වෙත ප්â€à¶»à·€à·šà· වීමට නොහà·à¶šà·’ වේ"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ යෙ.ක්â€à¶».මු. වෙත ප්â€à¶»à·€à·šà· වීමට නොහà·à¶šà·’ වේ"
msgid "AdminUsers|The user will not be able to use slash commands"
-msgstr "පරිà·à·“ලකයà·à¶§ ස්ලෑෂ් විධà·à¶± භà·à·€à·’ත෠කිරීමට නොහà·à¶šà·’ වේ"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ ස්ලෑෂ් විධà·à¶± භà·à·€à·’ත෠කිරීමට නොහà·à¶šà·’ වේ"
msgid "AdminUsers|The user will not receive any notifications"
-msgstr "පරිà·à·“ලකයà·à¶§ කිසිදු දà·à¶±à·”ම්දීමක් නොලà·à¶¶à·™à¶±à·” ඇත"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ කිසිදු දà·à¶±à·”ම්දීමක් නොලà·à¶¶à·™à¶±à·” ඇත"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "තහවුරු කිරීමට, %{projectName} ලියන්න"
@@ -4035,7 +4097,7 @@ msgid "AdminUsers|Unlock user %{username}?"
msgstr ""
msgid "AdminUsers|User administration"
-msgstr "පරිà·à·“ලක පරිපà·à¶½à¶±à¶º"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක පරිපà·à¶½à¶±à¶º"
msgid "AdminUsers|User will not be able to access git repositories"
msgstr ""
@@ -4044,13 +4106,13 @@ msgid "AdminUsers|User will not be able to login"
msgstr ""
msgid "AdminUsers|Users"
-msgstr "පරිà·à·“ලකයින්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "AdminUsers|Users can still be invited to your instance and/or add themselves if permitted based on your settings. They will not have access to your instance, nor count towards your subscribed seat count until you %{approve_link}."
msgstr ""
msgid "AdminUsers|Validate user account"
-msgstr "පරිà·à·“ලක ගිණුම වලංගුකරණය"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක ගිණුම වලංගුකරණය"
msgid "AdminUsers|View pending member requests"
msgstr ""
@@ -4104,7 +4166,7 @@ msgid "AdminUsers|You cannot remove your own administrator access."
msgstr ""
msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
-msgstr ""
+msgstr "ඔබ මෙම පරිà·à·Šâ€à¶»à·“ලකයà·à¶œà·š ගිණුම මà·à¶šà·“මට පෙර අයිති සමූහ පà·à·€à¶»à·’ය හ෠මක෠දà·à¶¸à·’ය යුතුය"
msgid "AdminUsers|Your GitLab instance has reached the maximum allowed %{user_doc_link} set by an instance admin."
msgstr ""
@@ -4185,7 +4247,7 @@ msgid "Admin|Quarterly reconciliation will occur on %{qrtlyDate}"
msgstr ""
msgid "Admin|Settings"
-msgstr ""
+msgstr "à·ƒà·à¶šà·ƒà·”ම්"
msgid "Admin|Spam Logs"
msgstr ""
@@ -4293,7 +4355,7 @@ msgid "AlertManagement|Acknowledged"
msgstr ""
msgid "AlertManagement|Activity feed"
-msgstr ""
+msgstr "ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š සංග්â€à¶»à·„ය"
msgid "AlertManagement|Alert"
msgstr "ඇඟවීම"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr "නව අනුකලනයක් යොදන්න"
@@ -4698,7 +4763,7 @@ msgid "All users must accept the Terms of Service and Privacy Policy to access G
msgstr ""
msgid "All users must have a name."
-msgstr "සියළුම පරිà·à·“ලකයින්ට නමක් තිබිය යුතුය."
+msgstr "සියළුම පරිà·à·Šâ€à¶»à·“ලකයින්ට නමක් තිබිය යුතුය."
msgid "All users with matching cards"
msgstr ""
@@ -4716,7 +4781,7 @@ msgid "Allow commits from members who can merge to the target branch. %{link_sta
msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
-msgstr ""
+msgstr "සමූහයේ හිමිකරුවන්ට LDAP ආà·à·Šâ€à¶»à·’ත à·ƒà·à¶šà·ƒà·”ම් කළමනà·à¶šà¶»à¶«à¶ºà¶§ ඉඩ දෙන්න"
msgid "Allow job retries even if the deployment job is outdated."
msgstr ""
@@ -4734,10 +4799,10 @@ msgid "Allow only the selected protocols to be used for Git access."
msgstr "ගිට් ප්â€à¶»à·€à·šà·à¶ºà¶§ තේරූ කෙටුම්පත් පමණක් භà·à·€à·’තයට ඉඩදෙන්න."
msgid "Allow owners to manage default branch protection per group."
-msgstr ""
+msgstr "හිමිකරුවන්ට එක් එක් සමූහයේ පෙරනිමි à·à·à¶›à· රà·à¶šà·€à¶»à¶«à¶º කළමනà·à¶šà¶»à¶«à¶ºà¶§ ඉඩ දෙන්න."
msgid "Allow owners to manually add users outside of LDAP"
-msgstr ""
+msgstr "LDAP වලින් පිටත පරිà·à·Šâ€à¶»à·“ලකයින් අතින් එක් කිරීමට හිමිකරුවන්ට ඉඩ දෙන්න"
msgid "Allow password authentication for Git over HTTP(S)"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] "à·ƒà·à¶šà·ƒà·”ම් සුරà·à¶šà·“මේදී දà·à·‚යකà
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "ඔබගේ à·ƒà·à¶šà·ƒà·”ම් සුරà·à¶šà·“මේදී දà·à·‚යක් ඇති විය. යළි සුරà·à¶šà·“මට බලන්න."
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,20 +5414,23 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
msgid "Analytics|Dashboards are created by editing the groups dashboard files."
-msgstr ""
+msgstr "සමූහවල උපකරණ පුවරු ගොනු සංස්කරණයෙන් උපකරණ පුවරු à·ƒà·à¶¯à¶ºà·’."
msgid "Analytics|Dashboards are created by editing the projects dashboard files."
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,9 +5468,12 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
-msgid "Analytics|Language"
+msgid "Analytics|Invalid visualization configuration"
msgstr ""
+msgid "Analytics|Language"
+msgstr "භà·à·‚à·à·€"
+
msgid "Analytics|Line Chart"
msgstr ""
@@ -5407,7 +5496,7 @@ msgid "Analytics|OS Version"
msgstr ""
msgid "Analytics|Page Language"
-msgstr ""
+msgstr "පිටුවේ භà·à·‚à·à·€"
msgid "Analytics|Page Path"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -5530,7 +5625,7 @@ msgid "Any %{header}"
msgstr "ඕනෑම %{header}"
msgid "Any Author"
-msgstr "ඕනෑම කතෘ"
+msgstr "සියළුම කතුවරු"
msgid "Any Milestone"
msgstr ""
@@ -5566,16 +5661,16 @@ msgid "Append the comment with %{tableflip}"
msgstr ""
msgid "AppleAppStore|Drag your Private Key file here or %{linkStart}click to upload%{linkEnd}."
-msgstr ""
+msgstr "ඔබගේ බලපත්â€à¶»à¶ºà·š ගොනුව මෙතà·à¶±à¶§ අදින්න à·„à· %{linkStart}උඩුගත කිරීමට%{linkEnd} ඔබන්න."
msgid "AppleAppStore|Drop your Private Key file to start the upload."
-msgstr ""
+msgstr "උඩුගත කිරීම ඇරඹීමට ඔබගේ බලපත්â€à¶»à¶ºà·š ගොනුව මෙතà·à¶±à¶§ දමන්න ."
msgid "AppleAppStore|Error: You are trying to upload something other than a Private Key file."
-msgstr ""
+msgstr "දà·à·‚යකි: ඔබ පෞද්. යතුරේ ගොනුව වෙනුවට වෙනත් දෙයක් උඩුගත කිරීමට උත්සà·à·„ කරයි."
msgid "AppleAppStore|Leave empty to use your current Private Key."
-msgstr ""
+msgstr "ඔබගේ වත්මන් පෞද්. යතුර භà·à·€à·’තයට හිස්ව තබන්න."
msgid "AppleAppStore|Only set variables on protected branches and tags"
msgstr ""
@@ -5590,10 +5685,10 @@ msgid "AppleAppStore|The Apple App Store Connect Key ID."
msgstr ""
msgid "AppleAppStore|The Apple App Store Connect Private Key (.p8)"
-msgstr ""
+msgstr "ඇපල් යෙදුම් ගබඩà·à·€à¶§ සබඳින පෞද්. යතුර (.p8)"
msgid "AppleAppStore|Upload a new Apple App Store Connect Private Key (replace %{currentFileName})"
-msgstr ""
+msgstr "ඇපල් යෙදුම් ගබඩà·à·€à¶§ සබඳින නව පෞද්. යතුරක් උඩුගත කරන්න (%{currentFileName} ප්â€à¶»à¶­à·’ස්ථà·à¶´à¶±à¶º වේ)"
msgid "AppleAppStore|Use GitLab to build and release an app in the Apple App Store."
msgstr ""
@@ -5658,7 +5753,7 @@ msgstr[0] ""
msgstr[1] ""
msgid "ApplicationSettings|Approve users"
-msgstr "පුද්ගලයින් අනුමතය"
+msgstr "පුද්ගලයින්ට අනුමà·à¶­à·’ය"
msgid "ApplicationSettings|Approve users in the pending approval status?"
msgstr ""
@@ -5940,10 +6035,10 @@ msgid "ApprovalRule|Rule name"
msgstr "නීතියේ නම"
msgid "ApprovalRule|Search in"
-msgstr ""
+msgstr "මෙහි සොයන්න:"
msgid "ApprovalRule|Search users or groups"
-msgstr ""
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින් හ෠සමූහ සොයන්න"
msgid "ApprovalRule|Select eligible approvers by expertise or files changed."
msgstr ""
@@ -5955,7 +6050,7 @@ msgid "ApprovalRule|Try for free"
msgstr "නොමිලේ උත්සà·à·„යට"
msgid "ApprovalRule|all groups"
-msgstr ""
+msgstr "සියළුම සමූහ"
msgid "ApprovalRule|day(s)"
msgstr ""
@@ -5964,7 +6059,7 @@ msgid "ApprovalRule|month(s)"
msgstr ""
msgid "ApprovalRule|project groups"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ සමූහ"
msgid "ApprovalRule|week(s)"
msgstr ""
@@ -6012,7 +6107,7 @@ msgid "ApprovalSettings|This setting is configured at the instance level and can
msgstr ""
msgid "ApprovalSettings|This setting is configured in %{groupName} and can only be changed in the group settings by an administrator or group owner."
-msgstr ""
+msgstr "මෙම à·ƒà·à¶šà·ƒà·”ම %{groupName} à·„à·’ වින්â€à¶ºà·à·ƒà¶œà¶­ කර ඇති අතර පරිපà·à¶½à¶šà¶ºà·™à¶šà·”ට හ෠සමූහයේ හිමිකරුවෙකුට පමණක් සමූහයේ à·ƒà·à¶šà·ƒà·”ම් හරහ෠වෙනස් කිරීමට à·„à·à¶šà·’ය."
msgid "ApprovalSettings|When a commit is added:"
msgstr ""
@@ -6048,7 +6143,7 @@ msgid "Approvals|Section: %section"
msgstr ""
msgid "Approvals|The number of people who need to approve this is more than those who are allowed to. Please ask the project owner to update %{securityPolicy}."
-msgstr ""
+msgstr "මෙය අනුමත කළ යුතු පුද්ගලයින් ඉඩ දී ඇති අයට වඩ෠සිටියි. කරුණà·à¶šà¶» %{securityPolicy}යà·à·€à¶­à·Šà¶šà·à¶½ කරන ලෙස ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ හිමිකරුට පවසන්න."
msgid "Approvals|Verify the number of %{linkStart}eligible security approvers%{linkEnd} matches the required approvers for the security policy."
msgstr ""
@@ -6105,7 +6200,7 @@ msgid "Approvers"
msgstr "අනුමතකරුවà·"
msgid "Approvers from private group(s) not shown"
-msgstr ""
+msgstr "පෞද්ගලික සමූහවල අනුමතකරුවන් නොපෙන්වයි"
msgid "Apr"
msgstr "බක්"
@@ -6200,9 +6295,6 @@ msgstr "ඔබට මෙම උපà·à¶‚ගය මà·à¶šà·“මට වුවමà¶
msgid "Are you sure you want to delete this label?"
msgstr "ඔබට මෙම නම්පත මà·à¶šà·“මට වුවමන෠ද?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,8 +6375,8 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "ඔබට මෙම %{accessTokenType} අහà·à·ƒà·’ කිරීමට වුවමන෠ද? මෙම ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º අප්â€à¶»à¶­à·’වර්ත්â€à¶ºà¶ºà·’."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
msgstr ""
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "පසුව අසන්න"
@@ -6435,7 +6530,7 @@ msgid "Ask someone with write access to resolve it."
msgstr ""
msgid "Ask your group owner to set up a group runner."
-msgstr ""
+msgstr "කණ්ඩà·à¶ºà¶¸à·Š ධà·à·€à¶šà¶ºà·™à¶šà·” පිහිටුවීමට ඔබේ කණ්ඩà·à¶ºà¶¸à·Š හිමිකරුගෙන් ඉල්ල෠සිටින්න."
msgid "Assertion consumer service URL"
msgstr ""
@@ -6483,7 +6578,7 @@ msgid "Assign to me"
msgstr "මට පවරන්න"
msgid "Assign yourself"
-msgstr ""
+msgstr "ඔබට පවරà·à¶œà¶±à·Šà¶±"
msgid "Assigned"
msgstr "පà·à·€à¶»à·”ණු"
@@ -6586,7 +6681,7 @@ msgid "AuditLogs|Action"
msgstr "ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º"
msgid "AuditLogs|Author"
-msgstr "කතෘ"
+msgstr "කර්තෘ"
msgid "AuditLogs|Date"
msgstr "දිනය"
@@ -6598,7 +6693,7 @@ msgid "AuditLogs|Failed to find %{type}. Please try again."
msgstr "%{type} සොය෠ගà·à¶±à·“මට අසමත් විය. පසුව බලන්න."
msgid "AuditLogs|Group Events"
-msgstr ""
+msgstr "සමූහයේ සිදුවීම්"
msgid "AuditLogs|IP Address"
msgstr "අ.ජà·.කෙ. ලිපිනය"
@@ -6616,7 +6711,7 @@ msgid "AuditLogs|Object"
msgstr "වස්තුව"
msgid "AuditLogs|Project Events"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ සිදුවීම්"
msgid "AuditLogs|Target"
msgstr "ඉලක්කය"
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6720,7 +6818,7 @@ msgid "AuditStreams|No header created yet."
msgstr ""
msgid "AuditStreams|Private key"
-msgstr ""
+msgstr "පෞද්ගලික යතුර"
msgid "AuditStreams|Project ID"
msgstr ""
@@ -6732,7 +6830,7 @@ msgid "AuditStreams|Save external stream destination"
msgstr ""
msgid "AuditStreams|Select events"
-msgstr ""
+msgstr "සිදුවීම් තà·à¶»à¶±à·Šà¶±"
msgid "AuditStreams|Setup streaming for audit events"
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "අගය"
@@ -6762,7 +6863,7 @@ msgid "AuditStreams|Verification token"
msgstr ""
msgid "AuditStreams|audit-events"
-msgstr ""
+msgstr "විගණන-සිදුවීම්"
msgid "AuditStreams|ex: 1000"
msgstr ""
@@ -6843,10 +6944,10 @@ msgid "Authentication via WebAuthn device failed."
msgstr ""
msgid "Author"
-msgstr "කතෘ"
+msgstr "කර්තෘ"
msgid "Author: %{author_name}"
-msgstr "කතෘ: %{author_name}"
+msgstr "කර්තෘ: %{author_name}"
msgid "Authored %{timeago}"
msgstr ""
@@ -6900,7 +7001,7 @@ msgid "AuthorizedApplication|There was an error trying to renew the application
msgstr ""
msgid "Authors: %{authors}"
-msgstr "කතෘ: %{authors}"
+msgstr "කතුවරු: %{authors}"
msgid "Auto DevOps"
msgstr ""
@@ -7152,7 +7253,7 @@ msgid "Badges|The badge was deleted."
msgstr "චිහ්නය මක෠දà·à¶¸à·’ණි."
msgid "Badges|This group has no badges, start by creating a new one above."
-msgstr ""
+msgstr "මෙම සමූහයේ චිහ්න නà·à¶­, ඉහත අළුතින් සෑදීමට à·„à·à¶šà·’ය."
msgid "Badges|This project has no badges, start by creating a new one above."
msgstr ""
@@ -7446,7 +7547,7 @@ msgid "BillingPlans|Free"
msgstr "නොමිලේ"
msgid "BillingPlans|Free forever features for individual users"
-msgstr "තනි පරිà·à·“ලකයින්ට à·ƒà·à¶¸à¶¯à· නොමිලේ විà·à·šà·‚à·à¶‚ග"
+msgstr "තනි පරිà·à·Šâ€à¶»à·“ලකයින්ට à·ƒà·à¶¸à¶¯à· නොමිලේ විà·à·šà·‚à·à¶‚ග"
msgid "BillingPlans|Free guest users"
msgstr ""
@@ -7503,7 +7604,7 @@ msgid "BillingPlans|Pricing page"
msgstr "මිලකරණ පිටුව"
msgid "BillingPlans|Priority support"
-msgstr ""
+msgstr "ප්â€à¶»à¶¸à·”ඛ සහà·à¶º"
msgid "BillingPlans|Ready to explore the value of the paid features today? Start a trial, no credit card required."
msgstr "ගෙවන විà·à·šà·‚à·à¶‚ගවල වටිනà·à¶šà¶¸ ගවේà·à¶±à¶º කිරීමට අද සූදà·à¶±à¶¸à·Šà¶¯? නà·à·„à·à·ƒà·”මක් අරඹන්න, ණය පතක් අවà·à·Šâ€à¶º නොවේ."
@@ -7569,7 +7670,7 @@ msgid "BillingPlans|While GitLab is ending availability of the Bronze plan, you
msgstr ""
msgid "BillingPlans|You don't have any groups. You'll need to %{create_group_link_start}create one%{create_group_link_end} and %{move_link_start}move your projects to it%{move_link_end}."
-msgstr ""
+msgstr "ඔබ සතුව සමූහ නà·à¶­. %{create_group_link_start}නව සමූහයක්%{create_group_link_end} à·ƒà·à¶¯à· %{move_link_start}ඔබගේ ව්â€à¶ºà·à¶´à·˜à¶­à·’ එයට ගෙන ය෠යුතුය%{move_link_end}."
msgid "BillingPlans|Your GitLab.com %{plan} trial will %{strong_open}expire after %{expiration_date}%{strong_close}. You can retain access to the %{plan} features by upgrading below."
msgstr ""
@@ -7617,7 +7718,7 @@ msgid "Billings|Free seats used"
msgstr ""
msgid "Billings|Free tier and trial groups can invite a maximum of 20 members per day."
-msgstr ""
+msgstr "නොමිලේ à·ƒà·à¶½à·ƒà·”ම සහ නà·à·„ුසුම යටතේ තිබෙන සමූහ වෙත දවසකට උපරිම à·ƒà·à¶¸à·à¶¢à·’කයින් 20 දෙනෙකුට ආරà·à¶°à¶±à· කිරීමට à·„à·à¶šà·’ය."
msgid "Billings|In a seat"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr "සෘජු à·ƒà·à¶¸à·à¶¢à·’කත්ව"
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr "ගෙවන à·ƒà·à¶½à·ƒà·”ම් ගවේà·à¶±à¶º"
@@ -7717,10 +7821,13 @@ msgstr ""
msgid "Billing|Groups in the Free tier are limited to %d seat"
msgid_plural "Billing|Groups in the Free tier are limited to %d seats"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "නොමිලේ à·ƒà·à¶½à·ƒà·”මට යටත් සමූහ ආසන %d කට සීම෠වේ"
+msgstr[1] "නොමිලේ à·ƒà·à¶½à·ƒà·”මට යටත් සමූහ ආසන %d කට සීම෠වේ"
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
+msgstr "ආරà·à¶°à¶±à¶ºà¶šà·’න් සමූහයට පà·à¶¸à·’ණි à·ƒà·à¶¸à·à¶¢à·’කයින් ඉවත් කිරීමට නොහà·à¶šà·’ය. ඔබට සමස්ත සමූහය ඉවත් කිරීමට à·„à·à¶šà·’ය à·„à· à·ƒà·à¶¸à·à¶¢à·’කය෠ඉවත් කිරීමට ආරà·à¶°à·’ත සමූහයේ හිමිකරුවෙකුගෙන් අසන්න."
+
+msgid "Billing|No seats available"
msgstr ""
msgid "Billing|No users to display."
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7742,7 +7855,7 @@ msgid "Billing|Subscription start"
msgstr ""
msgid "Billing|To ensure all members can access the group when your trial ends, you can upgrade to a paid tier."
-msgstr ""
+msgstr "ඔබගේ නà·à·„à·à·ƒà·”ම අවසන් වූ පසු සියළුම à·ƒà·à¶¸à·à¶¢à·’කයින්ට සමූහය වෙත තවදුරටත් ප්â€à¶»à·€à·šà· වීමට ගෙවන à·ƒà·à¶½à·ƒà·”මකට උත්à·à·Šâ€à¶»à·šà¶«à·’ කිරීමට à·„à·à¶šà·’ය."
msgid "Billing|Toggle seat details"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "BoardNewEpic|Search groups"
msgstr "සමූහ සෙà·à¶ºà¶±à·Šà¶±"
-msgid "BoardNewEpic|Select a group"
-msgstr "සමූහයක් තà·à¶»à¶±à·Šà¶±"
-
msgid "BoardNewIssue|No matching results"
msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
@@ -7861,7 +7977,7 @@ msgid "BoardScope|An error occurred while getting iterations. Please try again."
msgstr ""
msgid "BoardScope|An error occurred while getting milestones, please try again."
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± ලබ෠ගà·à¶±à·“මේදී දà·à·‚යක් සිදු විය, නà·à·€à¶­ උත්සà·à·„ කරන්න."
msgid "BoardScope|An error occurred while searching for labels, please try again."
msgstr ""
@@ -7915,7 +8031,7 @@ msgid "BoardScope|Search iterations"
msgstr ""
msgid "BoardScope|Search milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± සොයන්න"
msgid "BoardScope|Select assignee"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr "නම්පත් තà·à¶»à¶±à·Šà¶±"
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr "ඇරඹිණි"
@@ -8010,7 +8123,7 @@ msgid "Boards|An error occurred while fetching list's information. Please try ag
msgstr ""
msgid "Boards|An error occurred while fetching milestones. Please try again."
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± ලබ෠ගà·à¶±à·“මේදී දà·à·‚යක් සිදු විය, නà·à·€à¶­ උත්සà·à·„ කරන්න."
msgid "Boards|An error occurred while fetching recent boards. Please try again."
msgstr ""
@@ -8276,13 +8389,13 @@ msgid "BranchRules|Does not allow force push"
msgstr ""
msgid "BranchRules|Does not require approval from code owners"
-msgstr ""
+msgstr "කේත හිමිකරුවන්ගේ අනුමà·à¶­à·’ය වුවමන෠නà·à¶­"
msgid "BranchRules|From users with push access."
msgstr ""
msgid "BranchRules|Groups"
-msgstr ""
+msgstr "සමූහ"
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
@@ -8300,7 +8413,7 @@ msgid "BranchRules|No data to display"
msgstr ""
msgid "BranchRules|No matching results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "BranchRules|Protect branch"
msgstr ""
@@ -8312,16 +8425,16 @@ msgid "BranchRules|Reject code pushes that change files listed in the CODEOWNERS
msgstr ""
msgid "BranchRules|Require approval from code owners."
-msgstr ""
+msgstr "කේත හිමිකරුවන්ගේ අනුමà·à¶­à·’ය වුවමනà·à¶º"
msgid "BranchRules|Required approvals (%{total})"
msgstr ""
msgid "BranchRules|Requires CODEOWNERS approval"
-msgstr ""
+msgstr "කේත හිමිකරුවන්ගේ අනුමà·à¶­à·’ය වුවමනà·à¶º"
msgid "BranchRules|Requires approval from code owners"
-msgstr ""
+msgstr "කේත හිමිකරුවන්ගේ අනුමà·à¶­à·’ය වුවමනà·à¶º"
msgid "BranchRules|Roles"
msgstr ""
@@ -8549,7 +8662,7 @@ msgid "BroadcastMessages|Indigo"
msgstr ""
msgid "BroadcastMessages|Leave blank to target all group and project pages."
-msgstr ""
+msgstr "සියළුම සමූහ හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’ පිටු ඉලක්ක කිරීමට හිස්ව තබන්න."
msgid "BroadcastMessages|Light"
msgstr ""
@@ -8789,7 +8902,7 @@ msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
msgid "BulkImport|Your imported groups and projects will appear here."
-msgstr ""
+msgstr "ඔබ ආයà·à¶­ කළ සමූහ මෙහි දිස්වනු ඇත."
msgid "BulkImport|Your imported projects will appear here."
msgstr ""
@@ -8846,7 +8959,7 @@ msgid "By authenticating with an account tied to an Enterprise e-mail address, i
msgstr ""
msgid "By default, all projects and groups use the global notifications setting."
-msgstr ""
+msgstr "පෙරනිමි පරිදි සියළුම ව්â€à¶ºà·à¶´à·˜à¶­à·’ සහ සමූහ ගà·à¶½à·“ය දà·à¶±à·”ම්දීමේ à·ƒà·à¶šà·ƒà·”ම භà·à·€à·’ත෠කරයි."
msgid "By month"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,8 +9215,8 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
-msgstr "සමූහ සෑදිය à·„à·à¶šà·’ය:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr ""
@@ -9316,7 +9429,7 @@ msgid "CascadingSettings|This setting has been enforced by an instance admin."
msgstr ""
msgid "CascadingSettings|This setting has been enforced by an owner of %{link}."
-msgstr ""
+msgstr "%{link} හිමිකරුවෙක් මෙම à·ƒà·à¶šà·ƒà·”ම බලà·à¶­à·Šà¶¸à¶š කර ඇත."
msgid "CascadingSettings|cannot be changed because it is locked by an ancestor"
msgstr ""
@@ -9489,6 +9602,9 @@ msgstr "මà·à¶­à·˜à¶šà·à·€à·š වෙනස්කම් සුරà·à¶šà·“ න
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr "මෙහි ඕනෑම à·ƒà·à¶šà·ƒà·”මක් වෙනස් කිරීමට යෙදුම යළි ඇරඹිය යුතුය"
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,8 +9756,8 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] "ආචයන ඇසුරුම් %{quantity}"
msgstr[1] "ආචයන ඇසුරුම් %{quantity}"
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText} à·ƒà·à¶½à·ƒà·”ම"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9767,7 +9886,7 @@ msgid "Checkout|Network Error: %{message}"
msgstr ""
msgid "Checkout|Number of users"
-msgstr "පරිà·à·“ලකයින් ගණන"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින් ගණන"
msgid "Checkout|Payment method"
msgstr "ගෙවීමේ ක්â€à¶»à¶¸à¶º"
@@ -9824,7 +9943,7 @@ msgid "Checkout|Total storage: %{quantity} GB"
msgstr ""
msgid "Checkout|Users"
-msgstr "පරිà·à·“ලකයින්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "Checkout|You'll create your new group after checkout"
msgstr ""
@@ -9892,6 +10011,9 @@ msgstr "අච්චුවක් තà·à¶»à¶±à·Šà¶±..."
msgid "Choose a type..."
msgstr "වර්ගයක් තà·à¶»à¶±à·Šà¶±..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "ගොනුව තà·à¶»à¶±à·Šà¶±â€¦"
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr "පරිසර"
@@ -10118,7 +10240,7 @@ msgid "CiVariables|File"
msgstr ""
msgid "CiVariables|Group"
-msgstr ""
+msgstr "සමූහය"
msgid "CiVariables|Input variable key"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "වර්ගය"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "අගය"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (සියළු පරිසර)"
-
msgid "CiVariable|All environments"
msgstr "සියළු පරිසර"
@@ -10276,7 +10404,7 @@ msgid "Clear chart filters"
msgstr ""
msgid "Clear due date"
-msgstr ""
+msgstr "නියමිත දිනය මකන්න"
msgid "Clear health status"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10883,8 +11008,8 @@ msgstr ""
msgid "ClusterAgents|No activity occurred in the past day"
msgid_plural "ClusterAgents|No activity occurred in the past %d days"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "පසුගිය දවසේ කිසිදු ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à¶šà·Š සිදු වී නà·à¶­"
+msgstr[1] "පසුගිය දවස් %d දී කිසිදු ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à¶šà·Š සිදු වී නà·à¶­"
msgid "ClusterAgents|No agent access token"
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr "කේත සමà·à¶½à·à¶ à¶±à¶º"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11418,7 +11546,7 @@ msgid "Code coverage statistics for %{ref} %{start_date} - %{end_date}"
msgstr ""
msgid "Code owner approval is required"
-msgstr ""
+msgstr "කේත හිමිකරුගේ අනුමà·à¶­à·’ය වුවමනà·à¶º"
msgid "Code review"
msgstr "කේත සමà·à¶½à·à¶ à¶±à¶º"
@@ -11439,28 +11567,28 @@ msgid "CodeNavigation|No references found"
msgstr ""
msgid "CodeOwners|An error occurred while loading code owners."
-msgstr ""
+msgstr "කේත හිමිකරුවන් පූරණයේදී දà·à·‚යක් සිදු විය."
msgid "CodeOwners|Assign users and groups as approvers for specific file changes."
-msgstr ""
+msgstr "නිà·à·Šà¶ à·’ත ගොනු වෙනස්කම් සඳහ෠අනුමතකරුවන් ලෙස පරිà·à·Šâ€à¶»à·“ලකයින් සහ සමූහ යොදන්න."
msgid "CodeOwners|Code owners"
-msgstr ""
+msgstr "කේත හිමිකරුවන්"
msgid "CodeOwners|Code owners are users and groups that can approve specific file changes."
-msgstr ""
+msgstr "කේත හිමිකරුවන් යනු නිà·à·Šà¶ à·’ත ගොනු වෙනස්කම් අනුමත කරන පරිà·à·Šâ€à¶»à·“ලකයින් සහ සමූහ වේ."
msgid "CodeOwners|Hide all"
-msgstr ""
+msgstr "සියල්ල සඟවන්න"
msgid "CodeOwners|Learn more."
-msgstr ""
+msgstr "තව දà·à¶±à¶œà¶±à·Šà¶±"
msgid "CodeOwners|Show all"
-msgstr ""
+msgstr "සියල්ල පෙන්වන්න"
msgid "CodeOwner|Pattern"
-msgstr ""
+msgstr "රටà·à·€"
msgid "CodeSuggestionsSM|By enabling this feature, you agree to the %{terms_link_start}GitLab Testing Agreement%{link_end} and acknowledge that GitLab will send data from the instance, including personal data, to our %{ai_docs_link_start}AI providers%{link_end} to provide this feature."
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11516,10 +11641,10 @@ msgstr[0] ""
msgstr[1] ""
msgid "CodeownersValidation|Entries with spaces"
-msgstr ""
+msgstr "හිස්තà·à¶±à·Š සහිත නිවේà·à·’ත"
msgid "CodeownersValidation|Hide errors"
-msgstr ""
+msgstr "දà·à·‚ සඟවන්න"
msgid "CodeownersValidation|How are errors handled?"
msgstr ""
@@ -11537,7 +11662,7 @@ msgid "CodeownersValidation|Missing section name"
msgstr ""
msgid "CodeownersValidation|Show errors"
-msgstr ""
+msgstr "දà·à·‚ පෙන්වන්න"
msgid "CodeownersValidation|Syntax is valid."
msgstr ""
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr "හකුළන්න"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11585,7 +11713,7 @@ msgid "Collapse merge details"
msgstr ""
msgid "Collapse milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± හකුළන්න"
msgid "Collapse replies"
msgstr "පිළිතුරු හකුළන්න"
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr "වින්â€à¶ºà·à·ƒà¶ºà¶§ උපකà·à¶»"
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr "සිදුවීම් ලුහුබà·à¶³à·“මට %{snowplow_link_start}ස්නà·à¶´à·Šà¶½à·%{snowplow_link_end} වින්â€à¶ºà·à·ƒà¶œà¶­ කරන්න. %{help_link_start}තව දà·à¶±à¶œà¶±à·Šà¶±.%{help_link_end}"
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -12781,7 +12918,7 @@ msgid "ContainerRegistry|Something went wrong while updating the cleanup policy.
msgstr ""
msgid "ContainerRegistry|Sorry, your filter produced no results."
-msgstr ""
+msgstr "ඔබගේ පෙරීමට කිසිදු ප්â€à¶»à¶­à·’ඵලයක් නà·à¶­"
msgid "ContainerRegistry|Tag successfully marked for deletion."
msgstr ""
@@ -12847,7 +12984,7 @@ msgid "ContainerRegistry|This project's cleanup policy for tags is not enabled."
msgstr ""
msgid "ContainerRegistry|To widen your search, change or remove the filters above."
-msgstr ""
+msgstr "ඔබගේ සෙවීම පුළුල් කිරීමට, ඉහත පෙරහන් වෙනස් හ෠ඉවත් කරන්න."
msgid "ContainerRegistry|We are having trouble connecting to the Container Registry. Please try refreshing the page. If this error persists, please review %{docLinkStart}the troubleshooting documentation%{docLinkEnd}."
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13069,7 +13242,7 @@ msgid "ContributionEvent|Left project %{resourceParentLink}."
msgstr ""
msgid "ContributionEvent|Made a private contribution."
-msgstr ""
+msgstr "පෞද්. දà·à¶ºà¶šà¶­à·Šâ€à·€à¶ºà¶šà·Š ලබ෠දී ඇත."
msgid "ContributionEvent|Opened Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13441,13 +13623,13 @@ msgid "Could not load usage counts. Please refresh the page to try again."
msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
-msgstr ""
+msgstr "%{group} වෙතින් %{user} ඉවත් කිරීමට නොහà·à¶šà·’ විය. සමූහයේ අන්තිම හිමිකරු ඉවත් කිරීමට නොහà·à¶šà·’ය."
msgid "Could not remove the trigger."
msgstr ""
msgid "Could not restore the group"
-msgstr ""
+msgstr "සමූහය ප්â€à¶»à¶­à·Šâ€à¶ºà¶»à·Šà¶´à¶«à¶ºà¶§ නොහà·à¶šà·’ විය"
msgid "Could not retrieve the list of branches. Use the YAML editor mode, or refresh this page later. To view the list of branches, go to %{boldStart}Code - Branches%{boldEnd}"
msgstr ""
@@ -13534,7 +13716,7 @@ msgid "Create a cluster"
msgstr ""
msgid "Create a group"
-msgstr ""
+msgstr "සමූහයක් à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "Create a merge request"
msgstr ""
@@ -13612,7 +13794,7 @@ msgid "Create from"
msgstr ""
msgid "Create group"
-msgstr ""
+msgstr "සමූහය à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "Create group label"
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr "සේව෠ගිණුමක් à·ƒà·à¶¯à¶±à·Šà¶±"
@@ -13720,7 +13905,7 @@ msgid "Create your first page"
msgstr ""
msgid "Create your group"
-msgstr ""
+msgstr "ඔබගේ සමූහය à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "Create, update, or delete a merge request."
msgstr ""
@@ -13732,10 +13917,10 @@ msgid "CreateGitTag|Set tag message"
msgstr ""
msgid "CreateGroup|You don’t have permission to create a subgroup in this group."
-msgstr ""
+msgstr "මෙම සමූහයේ උප සමූහයක් සෑදීමට ඔබට අවසර නà·à¶­."
msgid "CreateGroup|You don’t have permission to create groups."
-msgstr ""
+msgstr "ඔබට සමූහ සෑදීමට අවසර නà·à¶­."
msgid "CreateTag|Tag"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr "සංවිධà·à¶±à¶º යà·à·€à¶­à·Šà¶šà·à¶½ කර ඇත."
msgid "Crm|Organization has been updated."
msgstr "සංවිධà·à¶±à¶º යà·à·€à¶­à·Šà¶šà·à¶½ කර ඇත."
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14143,13 +14325,13 @@ msgid "CurrentUser|Start an Ultimate trial"
msgstr ""
msgid "CurrentUser|Switch to GitLab Next"
-msgstr ""
+msgstr "ගිට්ලà·à¶¶à·Š නෙක්â€à·ƒà·Šà¶§à·Š බලන්න"
msgid "Currently unable to fetch data for this pipeline."
msgstr ""
msgid "Custom (%{language})"
-msgstr ""
+msgstr "අභිරුචි (%{language})"
msgid "Custom Attributes"
msgstr ""
@@ -14182,7 +14364,7 @@ msgid "Custom project templates"
msgstr ""
msgid "Custom project templates have not been set up for groups that you are a member of. They are enabled from a group’s settings page. Contact your group’s Owner or Maintainer to setup custom project templates."
-msgstr ""
+msgstr "ඔබට à·ƒà·à¶¸à·à¶¢à·’කත්â€à·€à¶º තිබෙන සමූහ සඳහ෠අභිරුචි ව්â€à¶ºà·à¶´à·˜à¶­à·’ අච්චු පිහිටුව෠නà·à¶­. ඒව෠සමූහයේ à·ƒà·à¶šà·ƒà·”ම් පිටුවෙන් සබල කරයි. අභිරුචි ව්â€à¶ºà·à¶´à·˜à¶­à·’ අච්චු පිහිටුවීමට ඔබගේ සමූහයේ හිමිකරු හ෠නඩත්තුකරු අමතන්න."
msgid "Custom range"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14731,7 +14916,7 @@ msgid "Dashboard|%{firstProject}, %{rest}, and %{secondProject}"
msgstr ""
msgid "Dashboard|Unable to add %{invalidProjects}. This dashboard is available for public projects, and private projects in groups with a Premium plan."
-msgstr ""
+msgstr "%{invalidProjects} එක් කිරීමට නොහà·à¶šà·’ය. මෙම උපකරණ පුවරුව ප්â€à¶»à·ƒà·’ද්ධ ව්â€à¶ºà·à¶´à·˜à¶­à·’ සහ ආධික්â€à¶º à·ƒà·à¶½à·ƒà·”මක් සහිත සමූහවල පෞද්ගලික ව්â€à¶ºà·à¶´à·˜à¶­à·’ සඳහ෠තිබේ."
msgid "DastConfig|Customize DAST settings to suit your requirements. Configuration changes made here override those provided by GitLab and are excluded from updates. For details of more advanced configuration options, see the %{docsLinkStart}GitLab DAST documentation%{docsLinkEnd}."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15052,7 +15240,7 @@ msgid "DastProfiles|URLs to skip during the authenticated scan."
msgstr ""
msgid "DastProfiles|Username"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º"
msgid "DastProfiles|Username form field"
msgstr ""
@@ -15353,7 +15541,7 @@ msgid "Default first day of the week in calendars and date pickers."
msgstr ""
msgid "Default language"
-msgstr ""
+msgstr "පෙරනිමි භà·à·‚à·à·€"
msgid "Default language for users who are not logged in."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15671,7 +15853,7 @@ msgid "DeletionSettings|Only administrators can delete projects."
msgstr ""
msgid "DeletionSettings|Owners and administrators can delete projects."
-msgstr ""
+msgstr "හිමිකරුවන්ට සහ පරිපà·à¶½à¶šà¶ºà·’න්ට ව්â€à¶ºà·à¶´à·˜à¶­à·’ මà·à¶šà·“මට à·„à·à¶šà·’ය."
msgid "DeletionSettings|Period that deleted groups and projects will remain restorable for. Personal projects are always deleted immediately."
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,11 +16179,11 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
-msgstr ""
+msgstr "පෞද්ගලිකව ප්â€à¶»à·€à·šà· විය à·„à·à¶šà·’ යෙදවීමේ යතුරු"
msgid "DeployKeys|Project usage"
msgstr ""
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16097,15 +16294,15 @@ msgid "DeployTokens|Use this token as a password. Save it. This password can %{i
msgstr ""
msgid "DeployTokens|Username"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º"
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16360,17 +16581,11 @@ msgid "Deselect all"
msgstr ""
msgid "Design"
-msgstr ""
+msgstr "නිර්මà·à¶«"
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -16443,7 +16658,7 @@ msgid "DesignManagement|Design description"
msgstr ""
msgid "DesignManagement|Designs"
-msgstr ""
+msgstr "නිර්මà·à¶«"
msgid "DesignManagement|Discard changes"
msgstr ""
@@ -16521,7 +16736,7 @@ msgid "DesignManagement|Your designs are being copied and are on their way… Pl
msgstr ""
msgid "Designs"
-msgstr ""
+msgstr "නිර්මà·à¶«"
msgid "Destroy"
msgstr ""
@@ -16608,10 +16823,10 @@ msgid "DevopsAdoption|At least one pipeline successfully run"
msgstr ""
msgid "DevopsAdoption|Code owners"
-msgstr ""
+msgstr "කේත හිමිකරුවන්"
msgid "DevopsAdoption|Code owners enabled for at least one project"
-msgstr ""
+msgstr "කේත හිමිකරුවන් අවම à·€à·à¶ºà·™à¶±à·Š එක් ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් සඳහ෠සබල කර ඇත"
msgid "DevopsAdoption|Confirm remove Group"
msgstr ""
@@ -16638,10 +16853,10 @@ msgid "DevopsAdoption|DevOps adoption tracks the use of key features across your
msgstr ""
msgid "DevopsAdoption|Edit groups"
-msgstr ""
+msgstr "සමූහ සංස්කරණය"
msgid "DevopsAdoption|Edit subgroups"
-msgstr ""
+msgstr "උප සමූහ සංස්කරණය"
msgid "DevopsAdoption|Feature adoption is based on usage in the previous calendar month. Data is updated at the beginning of each month. Last updated: %{timestamp}."
msgstr ""
@@ -16677,10 +16892,10 @@ msgid "DevopsAdoption|Pipelines"
msgstr ""
msgid "DevopsAdoption|Remove Group"
-msgstr ""
+msgstr "සමූහය ඉවත් කරන්න"
msgid "DevopsAdoption|Remove Group from the table."
-msgstr ""
+msgstr "වගුවෙන් සමූහය ඉවත් කරන්න."
msgid "DevopsAdoption|Runner configured for project/group"
msgstr ""
@@ -16884,7 +17099,7 @@ msgid "Disabled"
msgstr ""
msgid "Disabled by %{parent} owner"
-msgstr ""
+msgstr "%{parent} හිමිකරු විසින් අබල කර ඇත"
msgid "Disabled mirrors can only be enabled by instance owners. It is recommended that you delete them."
msgstr ""
@@ -16996,7 +17211,7 @@ msgid "Display as:"
msgstr ""
msgid "Display milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± පෙන්වන්න"
msgid "Display name"
msgstr ""
@@ -17026,7 +17241,7 @@ msgid "Dockerfile"
msgstr "ඩෝකර්ගොනුව"
msgid "Documentation"
-msgstr ""
+msgstr "ප්â€à¶»à¶½à·šà¶›à¶±à¶º"
msgid "Documentation for popular identity providers"
msgstr ""
@@ -17071,7 +17286,7 @@ msgid "DomainVerification|Enter your domain"
msgstr ""
msgid "DomainVerification|Failed to verify domain ownership"
-msgstr ""
+msgstr "වසමේ අයිතිය සත්â€à¶ºà·à¶´à¶±à¶ºà¶§ අසමත් විය"
msgid "DomainVerification|How do I configure a domain?"
msgstr ""
@@ -17086,25 +17301,25 @@ msgid "DomainVerification|New Domain"
msgstr ""
msgid "DomainVerification|No domains configured. Create a domain in a project in this group hierarchy."
-msgstr ""
+msgstr "වසම් කිසිවක් වින්â€à¶ºà·à·ƒà¶œà¶­ කර නà·à¶­. මෙම සමූහයේ ව්â€à¶ºà·à¶´à·˜à¶­à·’යකට වසමක් à·ƒà·à¶¯à¶±à·Šà¶±."
msgid "DomainVerification|Remove certificate"
msgstr ""
msgid "DomainVerification|Successfully verified domain ownership"
-msgstr ""
+msgstr "වසමේ අයිතිය à·ƒà·à¶»à·Šà¶®à¶šà·€ සත්â€à¶ºà·à¶´à¶±à¶º විය"
msgid "DomainVerification|The following domains are configured for projects in this group. Users with email addresses that match a verified domain do not need to confirm their account."
msgstr ""
msgid "DomainVerification|To verify ownership of your domain, add the above key to a TXT record within your DNS configuration within seven days. %{link_to_help}"
-msgstr ""
+msgstr "ඔබගේ වසමේ අයිතිය සත්â€à¶ºà·à¶´à¶±à¶ºà¶§, ඉහත යතුර දවස් හතක් ඇතුළත ඔබගේ à·€.නà·.ප. වින්â€à¶ºà·à·ƒà¶ºà¶§ TXT à·€à·à¶»à·Šà¶­à·à·€à¶šà·Š ලෙස එක් කරන්න. %{link_to_help}"
msgid "Domains"
msgstr ""
msgid "Don't have a group?"
-msgstr ""
+msgstr "සමූහයක් නà·à¶¯à·Šà¶¯?"
msgid "Don't have an account yet?"
msgstr "තවම ගිණුමක් නà·à¶¯à·Šà¶¯?"
@@ -17113,7 +17328,7 @@ msgid "Don't include description in commit message"
msgstr ""
msgid "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'."
-msgstr ""
+msgstr "GPG යතුරේ පෞද්ගලික කොටස අලවන්න එපà·. '-----BEGIN PGP PUBLIC KEY BLOCK-----' යනුවෙන් ආරම්භ වන ප්â€à¶»à·ƒà·’ද්ධ කොටස අලවන්න."
msgid "Don't send service data"
msgstr ""
@@ -17248,10 +17463,10 @@ msgid "DropdownWidget|You don't have permission to view this %{issuableAttribute
msgstr ""
msgid "Due Date"
-msgstr ""
+msgstr "නියමිත දිනය"
msgid "Due date"
-msgstr ""
+msgstr "නියමිත දිනය"
msgid "Due to inactivity, the %{project_link} project is scheduled to be deleted on %{b_open}%{deletion_date}%{b_close}. To unschedule the deletion of %{project_link}, perform some activity on it. For example:"
msgstr ""
@@ -17410,7 +17625,7 @@ msgid "Edit group application"
msgstr ""
msgid "Edit group: %{group_name}"
-msgstr ""
+msgstr "සමූහය සංස්කරණය: %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr ""
@@ -17458,7 +17673,7 @@ msgid "Edit topic: %{topic_name}"
msgstr ""
msgid "Edit user: %{user_name}"
-msgstr "පරිà·à·“ලක සංස්කරණය: %{user_name}"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක සංස්කරණය: %{user_name}"
msgid "Edit video description"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "වි-තà·à¶´à·à¶½à·Š"
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -17992,7 +18201,7 @@ msgid "EnterpriseUsers|The user does not match the \"Enterprise User\" definitio
msgstr ""
msgid "EnterpriseUsers|The user is already an enterprise user of the group"
-msgstr ""
+msgstr "පරිà·à·Šâ€à¶»à·“ලකය෠දà·à¶±à¶§à¶¸à¶­à·Š සමූහයේ ව්â€à¶ºà·€à·ƒà·à¶º පරිà·à·Šâ€à¶»à·“ලකයෙකි"
msgid "Environment"
msgstr "පරිසරය"
@@ -18000,7 +18209,7 @@ msgstr "පරිසරය"
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr "පරිසරයේ නම යටතේ සොයන්න"
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18883,7 +19113,7 @@ msgid "EventFilterBy|Filter by wiki"
msgstr ""
msgid "Events"
-msgstr ""
+msgstr "සිදුවීම්"
msgid "Events API"
msgstr "සිදුවීම් යෙ.ක්â€à¶».මු."
@@ -19005,7 +19235,7 @@ msgid "Everyone can contribute"
msgstr "à·ƒà·à¶¸à¶§ දà·à¶ºà¶š වීමට à·„à·à¶šà·’ය"
msgid "Everything on your to-do list is marked as done."
-msgstr ""
+msgstr "ඔබගේ කළ-යුතු ලà·à¶ºà·’ස්තුවේ සියල්ල අහවර බව යොද෠ඇත."
msgid "Everything you need to create a GitLab Pages site using Bridgetown"
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19116,7 +19349,7 @@ msgid "Expand merge details"
msgstr ""
msgid "Expand milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± විහිදන්න"
msgid "Expand settings section"
msgstr ""
@@ -19203,7 +19436,7 @@ msgid "Export commit custody report"
msgstr ""
msgid "Export group"
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­ කරන්න"
msgid "Export issues"
msgstr ""
@@ -19293,7 +19526,7 @@ msgid "ExternalAuthorization|External classification policy authorization."
msgstr ""
msgid "ExternalAuthorization|Passphrase required to decrypt the private key. Encrypted when stored."
-msgstr ""
+msgstr "පෞද්ගලික යතුර විසංකේතනයට මුරවà·à¶šà·’ය වුවමනà·à¶º. සංකේතිතව ගබඩ෠කරයි."
msgid "ExternalAuthorization|Period GitLab waits for a response from the external service. If there is no response, access is denied. Default: 0.5 seconds."
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19396,7 +19632,7 @@ msgid "Failed to cancel auto stop because you do not have permission to update t
msgstr ""
msgid "Failed to change the owner"
-msgstr ""
+msgstr "අයිතිකරු වෙනස් කිරීමට අසමත් විය"
msgid "Failed to check related branches."
msgstr ""
@@ -19510,10 +19746,10 @@ msgid "Failed to load labels. Please try again."
msgstr ""
msgid "Failed to load milestones."
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± පූරණයට අසමත් විය."
msgid "Failed to load milestones. Please try again."
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± පූරණයට අසමත් විය. නà·à·€à¶­ උත්සà·à·„ කරන්න."
msgid "Failed to load projects"
msgstr ""
@@ -19570,7 +19806,7 @@ msgid "Failed to remove timelog"
msgstr ""
msgid "Failed to remove user identity."
-msgstr "පරිà·à·“ලක අනන්â€à¶ºà¶­à·à·€à¶º ඉවත් කිරීමට අසමත් විය."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක අනන්â€à¶ºà¶­à·à·€à¶º ඉවත් කිරීමට අසමත් විය."
msgid "Failed to remove user key."
msgstr ""
@@ -19833,7 +20069,7 @@ msgid "FeatureFlags|Try again in a few moments or contact your support team."
msgstr ""
msgid "FeatureFlags|User IDs"
-msgstr "පරිà·à·“ලක à·„à·à¶³à·”."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·„à·à¶³à·”."
msgid "FeatureFlags|User List"
msgstr ""
@@ -19860,7 +20096,7 @@ msgid "FeatureFlag|Type"
msgstr ""
msgid "FeatureFlag|User IDs"
-msgstr "පරිà·à·“ලක à·„à·à¶³à·”."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·„à·à¶³à·”."
msgid "FeatureFlag|User List"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr "පරිà·à·Šâ€à¶»à·“ලකය෠අනුව පෙරන්න"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20175,16 +20405,16 @@ msgid "For a faster browsing experience, some files are collapsed by default."
msgstr ""
msgid "For additional information, review your %{link_to} or contact your %{project_or_group} owner."
-msgstr ""
+msgstr "අතිරේක තොරතුරු සඳහ෠ඔබගේ %{link_to} සමà·à¶½à·à¶ à¶±à¶º කරන්න à·„à· %{project_or_group} හිමිකරු අමතන්න."
msgid "For additional information, review your %{link_to} or contact your group owner."
-msgstr ""
+msgstr "අතිරේක තොරතුරු සඳහ෠ඔබගේ %{link_to} සමà·à¶½à·à¶ à¶±à¶º කරන්න හ෠සමූහයේ හිමිකරු අමතන්න."
msgid "For additional information, review your %{project_or_group} membership: %{url} or contact your %{project_or_group} owner."
-msgstr ""
+msgstr "අතිරේක තොරතුරු සඳහ෠ඔබගේ %{project_or_group} à·ƒà·à¶¸à·à¶¢à·’කත්â€à·€à¶º සමà·à¶½à·à¶ à¶±à¶º කරන්න: %{url} à·„à· %{project_or_group} හිමිකරු අමතන්න."
msgid "For additional information, review your group membership: %{link_to} or contact your group owner."
-msgstr ""
+msgstr "අතිරේක තොරතුරු සඳහ෠ඔබගේ සමූහයේ à·ƒà·à¶¸à·à¶¢à·’කත්â€à·€à¶º සමà·à¶½à·à¶ à¶±à¶º කරන්න: %{link_to} හ෠සමූහයේ හිමිකරු අමතන්න."
msgid "For each job, clone the repository."
msgstr ""
@@ -20256,7 +20486,7 @@ msgid "ForkProject|Cancel"
msgstr ""
msgid "ForkProject|Create a group"
-msgstr ""
+msgstr "සමූහයක් à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "ForkProject|Fork project"
msgstr ""
@@ -20274,7 +20504,7 @@ msgid "ForkProject|Please select a visibility level"
msgstr ""
msgid "ForkProject|Private"
-msgstr ""
+msgstr "පෞද්ගලික"
msgid "ForkProject|Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group."
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20513,7 +20716,7 @@ msgid "Generate root cause analysis"
msgstr ""
msgid "Generate site and private keys at"
-msgstr ""
+msgstr "මෙයින් අඩවියේ සහ පෞද්. යතුරු උත්පà·à¶¯à¶±à¶º කරගන්න"
msgid "Generated with JSON data"
msgstr ""
@@ -20553,8 +20756,8 @@ msgstr ""
msgid "Geo|%d group selected"
msgid_plural "Geo|%d groups selected"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "සමූහ %d ක් තà·à¶»à· ඇත"
+msgstr[1] "සමූහ %d ක් තà·à¶»à· ඇත"
msgid "Geo|%d shard selected"
msgid_plural "Geo|%d shards selected"
@@ -20727,7 +20930,7 @@ msgid "Geo|Go to the primary site"
msgstr ""
msgid "Geo|Groups to synchronize"
-msgstr ""
+msgstr "සමමුහූර්තයට සමූහ"
msgid "Geo|Healthy"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21285,7 +21494,7 @@ msgid "GitLab detected an attempt to sign in to your %{host} account using an in
msgstr ""
msgid "GitLab documentation"
-msgstr ""
+msgstr "ගිට්ලà·à¶¶à·Š ප්â€à¶»à¶½à·šà¶›à¶±à¶º"
msgid "GitLab events trigger webhooks. Use the request details of a webhook to help troubleshoot problems. %{link_start}How do I troubleshoot?%{link_end}"
msgstr ""
@@ -21297,7 +21506,7 @@ msgid "GitLab for Jira Cloud"
msgstr ""
msgid "GitLab group: %{source_link}"
-msgstr ""
+msgstr "ගිට්ලà·à¶¶à·Š සමූහය: %{source_link}"
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
msgstr ""
@@ -21336,7 +21545,7 @@ msgid "GitLab single sign-on URL"
msgstr ""
msgid "GitLab username"
-msgstr "ගිට්ලà·à¶¶à·Š පරිà·à·“ලක නà·à¶¸à¶º"
+msgstr "ගිට්ලà·à¶¶à·Š පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º"
msgid "GitLab uses %{linkStart}Sidekiq%{linkEnd} to process background jobs"
msgstr ""
@@ -21357,7 +21566,7 @@ msgid "GitLabPagesDomains|Retry"
msgstr ""
msgid "GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}."
-msgstr ""
+msgstr "%{domain} සත්â€à¶ºà·à¶´à¶±à¶º කර නà·à¶­. අයිතිය සත්â€à¶ºà·à¶´à¶±à¶º කරන ආකà·à¶»à¶º දà·à¶± ගà·à¶±à·“මට, ඔබගේ %{link_start}වසමේ විස්තර%{link_end} බලන්න."
msgid "GitLabPages|Access Control is enabled for this Pages website; only authorized users will be able to access it. To make your website publicly available, navigate to your project's %{strong_start}Settings &gt; General &gt; Visibility%{strong_end} and select %{strong_start}Everyone%{strong_end} in pages section. Read the %{link_start}documentation%{link_end} for more information."
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "ඔබගේ පිටු වින්â€à¶ºà·à·ƒà¶º යà·à·€à¶­à·Šà¶šà·à¶½ වෙමින්..."
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,21 +21847,27 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
msgid "GlobalSearch|Archived"
-msgstr ""
+msgstr "සංරක්â€à·‚ිත"
msgid "GlobalSearch|Close"
-msgstr ""
+msgstr "වස෠දà·à¶¸à·–"
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
-msgid "GlobalSearch|Group"
+msgid "GlobalSearch|Filters"
msgstr ""
+msgid "GlobalSearch|Group"
+msgstr "සමූහය"
+
msgid "GlobalSearch|Groups"
msgstr "සමූහ"
@@ -21669,25 +21887,25 @@ msgid "GlobalSearch|Issues assigned to me"
msgstr ""
msgid "GlobalSearch|Labels"
-msgstr ""
+msgstr "නම්පත්"
msgid "GlobalSearch|Language"
-msgstr ""
+msgstr "භà·à·‚à·à·€"
msgid "GlobalSearch|Merge requests I've created"
-msgstr ""
+msgstr "මම සෑදූ ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම්"
msgid "GlobalSearch|Merge requests assigned to me"
-msgstr ""
+msgstr "මට පවරන ලද ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම්"
msgid "GlobalSearch|Merge requests that I'm a reviewer"
-msgstr ""
+msgstr "මට සමà·à¶½à·à¶ à¶±à¶ºà¶§ තිබෙන ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම්"
msgid "GlobalSearch|No labels found"
-msgstr ""
+msgstr "නම්පත් හමු නොවිණි"
msgid "GlobalSearch|Places"
-msgstr ""
+msgstr "පෙදෙස්"
msgid "GlobalSearch|Project"
msgstr ""
@@ -21711,19 +21929,16 @@ msgid "GlobalSearch|Results updated. %{count} results available. Use the up and
msgstr ""
msgid "GlobalSearch|Search"
-msgstr ""
+msgstr "සොයන්න"
msgid "GlobalSearch|Search GitLab"
msgstr "ගිට්ලà·à¶¶à·Š à·„à·’ සොයන්න"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
msgid "GlobalSearch|Search labels"
-msgstr ""
+msgstr "නම්පත් සොයන්න"
msgid "GlobalSearch|Search results are loading"
msgstr ""
@@ -21732,7 +21947,7 @@ msgid "GlobalSearch|Settings"
msgstr "à·ƒà·à¶šà·ƒà·”ම්"
msgid "GlobalSearch|Show more"
-msgstr ""
+msgstr "තව පෙන්වන්න"
msgid "GlobalSearch|Showing top %{maxItems}"
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21900,7 +22118,7 @@ msgid "Go to the 'Admin area &gt; Sign-up restrictions', and check the 'Domain d
msgstr ""
msgid "Go to the activity feed"
-msgstr ""
+msgstr "ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š සංග්â€à¶»à·„යට යන්න"
msgid "Go to the group’s 'Settings &gt; General' page, and check 'Restrict membership by email domain'."
msgstr ""
@@ -21909,7 +22127,7 @@ msgid "Go to the milestone list"
msgstr ""
msgid "Go to the project's activity feed"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š සංග්â€à¶»à·„යට යන්න"
msgid "Go to the project's overview page"
msgstr ""
@@ -21918,13 +22136,13 @@ msgid "Go to wiki"
msgstr ""
msgid "Go to your To-Do list"
-msgstr ""
+msgstr "කළ-යුතු ලà·à¶ºà·’ස්තුවට යන්න"
msgid "Go to your fork"
msgstr ""
msgid "Go to your groups"
-msgstr ""
+msgstr "ඔබගේ සමූහ වෙත යන්න"
msgid "Go to your issues"
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22056,7 +22280,7 @@ msgid "Grid"
msgstr ""
msgid "Group"
-msgstr ""
+msgstr "සමූහය"
msgid "Group %{group_name} and its Mattermost team were successfully created."
msgstr ""
@@ -22083,7 +22307,7 @@ msgid "Group Access Tokens"
msgstr ""
msgid "Group Git LFS status:"
-msgstr ""
+msgstr "සමූහයේ ගිට් LFS තත්â€à·€à¶º:"
msgid "Group Hooks"
msgstr ""
@@ -22095,7 +22319,7 @@ msgid "Group SAML must be enabled to test"
msgstr ""
msgid "Group URL"
-msgstr ""
+msgstr "සමූහයේ ඒ.ස.නි."
msgid "Group access token creation is disabled in this group."
msgstr ""
@@ -22104,88 +22328,88 @@ msgid "Group application: %{name}"
msgstr ""
msgid "Group applications"
-msgstr ""
+msgstr "සමූහයේ යෙදුම්"
msgid "Group audit events"
-msgstr ""
+msgstr "සමූහයේ විගණන සිදුවීම්"
msgid "Group avatar"
-msgstr ""
+msgstr "සමූහයේ ප්â€à¶»à¶­à·’ිරූපය"
msgid "Group by"
msgstr ""
-msgid "Group description (optional)"
+msgid "Group by:"
msgstr ""
+msgid "Group description (optional)"
+msgstr "සමූහයේ විස්තරය (විකල්පයකි)"
+
msgid "Group export could not be started."
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­à¶ºà¶§ නොහà·à¶šà·’ විය."
msgid "Group export download requests"
-msgstr ""
+msgstr "සමූහයේ නිර්යà·à¶­ බà·à¶œà·à¶±à·“මේ ඉල්ලීම්"
msgid "Group export error"
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­ දà·à·‚යකි"
msgid "Group export link has expired. Please generate a new export from your group settings."
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­ සබà·à¶³à·’ය ඉකුත් වී ඇත. ඔබගේ සමූහයේ à·ƒà·à¶šà·ƒà·”ම් හරහ෠නව නිර්යà·à¶­à¶ºà¶šà·Š උත්පà·à¶¯à¶±à¶º කරන්න."
msgid "Group export requests"
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­ ඉල්ලීම්"
msgid "Group export started. A download link will be sent by email and made available on this page."
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­à¶º ඇරඹිණි. බà·à¶œà·à¶±à·“මේ සබà·à¶³à·’යක් වි-තà·à¶´à·‘ලෙන් එවන අතර මෙම පිටුවෙහි ද තිබෙනු ඇත."
msgid "Group has been already marked for deletion"
-msgstr ""
+msgstr "සමූහය දà·à¶±à¶§à¶¸à¶­à·Š මà·à¶šà·“මට ලකුණු කර ඇත"
msgid "Group has not been marked for deletion"
-msgstr ""
+msgstr "සමූහය මà·à¶šà·“මට ලකුණු කර නà·à¶­"
msgid "Group import could not be scheduled"
msgstr ""
msgid "Group import requests"
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­ ඉල්ලීම්"
msgid "Group info:"
-msgstr ""
+msgstr "සමූහයේ තොරතුරු:"
msgid "Group information"
-msgstr ""
+msgstr "සමූහයේ තොරතුරු"
msgid "Group jobs by"
msgstr ""
msgid "Group members"
-msgstr ""
+msgstr "සමූහයේ à·ƒà·à¶¸à·à¶¢à·’කයින්"
msgid "Group membership expiration date changed"
-msgstr ""
+msgstr "සමූහයේ à·ƒà·à¶¸à·à¶¢à·’කත්â€à·€à¶º ඉකුත් වන දිනය වෙනස් විය"
msgid "Group membership expiration date removed"
-msgstr ""
+msgstr "සමූහයේ à·ƒà·à¶¸à·à¶¢à·’කත්â€à·€à¶º ඉකුත් වන දිනය ඉවත් කෙරිණි"
msgid "Group mention in private"
-msgstr ""
+msgstr "පෞද්ගලිකව සමූහය à·ƒà·à¶³à·„ුම"
msgid "Group mention in public"
msgstr ""
msgid "Group milestone"
-msgstr ""
+msgstr "සමූහයේ සන්ධිස්ථà·à¶±"
msgid "Group name (your organization)"
msgstr "සමූහයේ නම (ඔබගේ සංවිධà·à¶±à¶º)"
msgid "Group navigation"
-msgstr ""
-
-msgid "Group overview"
-msgstr ""
+msgstr "සමූහයේ යà·à¶­à·Šâ€à¶»à¶«à¶º"
msgid "Group overview content"
-msgstr ""
+msgstr "සමූහයේ විà·à·Šà¶½à·šà·‚ණ අන්තර්ගතය"
msgid "Group path is already taken. We've suggested one that is available."
msgstr ""
@@ -22200,22 +22424,22 @@ msgid "Group project URLs are prefixed with the group namespace"
msgstr ""
msgid "Group requires separate account"
-msgstr ""
+msgstr "සමූහයට වෙනම ගිණුමක් වුවමනà·à¶º"
msgid "Group runners"
-msgstr ""
+msgstr "සමූහයේ ධà·à·€à¶š"
msgid "Group runners can be managed with the %{link}."
-msgstr ""
+msgstr "%{link} සමඟ සමූහයේ ධà·à·€à¶š කළමනà·à¶šà¶»à¶«à¶ºà¶§ à·„à·à¶šà·’ය."
msgid "Group variables (inherited)"
msgstr ""
msgid "Group was exported"
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­ විය"
msgid "Group was successfully updated."
-msgstr ""
+msgstr "සමූහය à·ƒà·à¶»à·Šà¶®à¶šà·€ යà·à·€à¶­à·Šà¶šà·à¶½ කෙරිණි."
msgid "Group wikis"
msgstr ""
@@ -22224,7 +22448,7 @@ msgid "Group-level wiki is disabled."
msgstr ""
msgid "Group: %{group_name}"
-msgstr ""
+msgstr "සමූහය: %{group_name}"
msgid "GroupActivityMetrics|Issues created"
msgstr ""
@@ -22236,13 +22460,13 @@ msgid "GroupActivityMetrics|Merge requests created"
msgstr ""
msgid "GroupActivityMetrics|Recent activity"
-msgstr ""
+msgstr "මෑත ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š"
msgid "GroupImport|Failed to import group: %{error}"
msgstr ""
msgid "GroupImport|Group '%{group_name}' is being imported."
-msgstr ""
+msgstr "'%{group_name}' සමූහය අයà·à¶­ වෙමින් පවතී."
msgid "GroupImport|Group could not be imported: %{errors}"
msgstr ""
@@ -22251,22 +22475,22 @@ msgid "GroupImport|Please wait while we import the group for you. Refresh at wil
msgstr ""
msgid "GroupImport|The group was successfully imported."
-msgstr ""
+msgstr "සමූහය à·ƒà·à¶»à·Šà¶®à¶šà·€ ආයà·à¶­ විය."
msgid "GroupImport|Unable to process group import file"
msgstr ""
msgid "GroupPage|Copy group ID"
-msgstr ""
+msgstr "සමූහයේ à·„à·à¶³à·”. පිටපතක්"
msgid "GroupPage|Group ID: %{group_id}"
-msgstr ""
+msgstr "සමූහයේ à·„à·à¶³à·”.: %{group_id}"
msgid "GroupRoadmap|%{dateWord} – No end date"
msgstr ""
msgid "GroupRoadmap|%{startDateInWords} – %{endDateInWords}"
-msgstr ""
+msgstr "%{startDateInWords} – %{endDateInWords}"
msgid "GroupRoadmap|Loading epics"
msgstr ""
@@ -22275,16 +22499,16 @@ msgid "GroupRoadmap|New epic"
msgstr ""
msgid "GroupRoadmap|No start and end date"
-msgstr ""
+msgstr "ආරම්භක හ෠අවසà·à¶± දිනයක් නà·à¶­"
msgid "GroupRoadmap|No start date – %{dateWord}"
-msgstr ""
+msgstr "ආරම්භක දිනයක් නà·à¶­ – %{dateWord}"
msgid "GroupRoadmap|Something went wrong while fetching epics"
msgstr ""
msgid "GroupRoadmap|Something went wrong while fetching milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± ලබ෠ගà·à¶±à·“මේදී යමක් à·€à·à¶»à¶¯à·“ ඇත"
msgid "GroupRoadmap|Sorry, no epics matched your search"
msgstr ""
@@ -22293,10 +22517,10 @@ msgid "GroupRoadmap|The roadmap shows the progress of your epics along a timelin
msgstr ""
msgid "GroupRoadmap|This quarter"
-msgstr ""
+msgstr "මෙම කà·à¶»à·Šà¶­à·”à·€"
msgid "GroupRoadmap|This year"
-msgstr ""
+msgstr "මෙම වසර"
msgid "GroupRoadmap|To make your epics appear in the roadmap, add start or due dates to them."
msgstr ""
@@ -22350,7 +22574,7 @@ msgid "GroupSAML|Certificate fingerprint"
msgstr ""
msgid "GroupSAML|Configuration"
-msgstr ""
+msgstr "වින්â€à¶ºà·à·ƒà¶º"
msgid "GroupSAML|Copy SAML Response XML"
msgstr ""
@@ -22392,7 +22616,7 @@ msgid "GroupSAML|Manage your group’s membership while adding another level of
msgstr ""
msgid "GroupSAML|Members"
-msgstr ""
+msgstr "à·ƒà·à¶¸à·à¶¢à·’කයින්"
msgid "GroupSAML|Members will be forwarded here when signing in to your group. Get this from your identity provider, where it can also be called \"SSO Service Location\", \"SAML Token Issuance Endpoint\", or \"SAML 2.0/W-Federation URL\"."
msgstr ""
@@ -22425,7 +22649,7 @@ msgid "GroupSAML|SAML Group Name"
msgstr ""
msgid "GroupSAML|SAML Group Name: %{saml_group_name}"
-msgstr ""
+msgstr "SAML සමූහයේ නම: %{saml_group_name}"
msgid "GroupSAML|SAML Name ID and email address do not match your user account. Contact an administrator."
msgstr ""
@@ -22506,13 +22730,13 @@ msgid "GroupSelect|An error occurred fetching the groups. Please refresh the pag
msgstr ""
msgid "GroupSelect|No matching results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "GroupSelect|Search groups"
msgstr "සමූහ සොයන්න"
msgid "GroupSelect|Select a group"
-msgstr ""
+msgstr "සමූහයක් තà·à¶»à¶±à·Šà¶±"
msgid "GroupSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave empty for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{project_sharing_docs_link_start}project sharing%{link_end} and %{group_sharing_docs_link_start}group sharing%{link_end}."
msgstr ""
@@ -22521,10 +22745,10 @@ msgid "GroupSettings|After the instance reaches the user cap, any user who is ad
msgstr ""
msgid "GroupSettings|Analytics"
-msgstr ""
+msgstr "විà·à·Šà¶½à·šà·‚"
msgid "GroupSettings|Analytics Dashboards"
-msgstr ""
+msgstr "විà·à·Šà¶½à·šà·‚ පුවරුව"
msgid "GroupSettings|Applied to all subgroups unless overridden by a group owner. Groups already added to the project lose access."
msgstr ""
@@ -22536,7 +22760,7 @@ msgid "GroupSettings|Available only on the top-level group. Applies to all subgr
msgstr ""
msgid "GroupSettings|Badges"
-msgstr ""
+msgstr "චිහ්න"
msgid "GroupSettings|Be careful. Changing a group's parent can have unintended side effects. %{learn_more_link_start}Learn more.%{learn_more_link_end}"
msgstr ""
@@ -22545,7 +22769,7 @@ msgid "GroupSettings|Cannot update the path because there are projects under thi
msgstr ""
msgid "GroupSettings|Change group URL"
-msgstr ""
+msgstr "සමූහයේ ඒ.ස.නි. වෙනස් කරන්න"
msgid "GroupSettings|Changing a group's URL can have unintended side effects."
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22581,13 +22805,13 @@ msgid "GroupSettings|Default to Auto DevOps pipeline for all projects within thi
msgstr ""
msgid "GroupSettings|Email notifications are disabled"
-msgstr ""
+msgstr "වි-තà·à¶´à·à¶½à·Š දà·à¶±à·”ම්දීම් අක්â€à¶»à·’යයි"
msgid "GroupSettings|Enable overview background aggregation for Value Streams Dashboard"
msgstr ""
msgid "GroupSettings|Export group"
-msgstr ""
+msgstr "සමූහය නිර්යà·à¶­ කරන්න"
msgid "GroupSettings|Git abuse rate limit"
msgstr ""
@@ -22644,7 +22868,7 @@ msgid "GroupSettings|Select the project containing Analytics Dashboards configur
msgstr ""
msgid "GroupSettings|Select the project containing the %{code_start}.gitlab/insights.yml%{code_end} file"
-msgstr ""
+msgstr "%{code_start}.gitlab/insights.yml%{code_end} ගොනුව අඩංගු ව්â€à¶ºà·à¶´à·˜à¶­à·’ය තà·à¶»à¶±à·Šà¶±"
msgid "GroupSettings|Select the project containing your custom Insights file."
msgstr ""
@@ -22683,7 +22907,7 @@ msgid "GroupSettings|Value Streams Dashboard"
msgstr ""
msgid "GroupSettings|What are badges?"
-msgstr ""
+msgstr "චිහ්න යනු මොනවà·à¶¯?"
msgid "GroupSettings|What is Analytics Dashboards?"
msgstr ""
@@ -22692,7 +22916,7 @@ msgid "GroupSettings|What is Insights?"
msgstr ""
msgid "GroupSettings|You must have the Owner role in the target group"
-msgstr ""
+msgstr "ඉලක්කගත සමූහයේ හිමිකà·à¶» භූමිකà·à·€ ඔබ සතු විය යුතුය"
msgid "GroupSettings|You will need to update your local repositories to point to the new location."
msgstr ""
@@ -22713,10 +22937,10 @@ msgid "Groups"
msgstr "සමූහ"
msgid "Groups (%{count})"
-msgstr ""
+msgstr "සමූහ (%{count})"
msgid "Groups and projects"
-msgstr ""
+msgstr "සමූහ හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’"
msgid "Groups are a great way to organize projects and people."
msgstr ""
@@ -22731,7 +22955,7 @@ msgid "GroupsDropdown|Groups you visit often will appear here"
msgstr "ඔබ නිතර ගොඩවදින සමූහ මෙහි දිස්වේ"
msgid "GroupsDropdown|Loading groups"
-msgstr ""
+msgstr "සමූහ පූරණය වෙමින්"
msgid "GroupsDropdown|Search your groups"
msgstr "ඔබගේ සමූහ සොයන්න"
@@ -22740,7 +22964,7 @@ msgid "GroupsDropdown|Something went wrong on our end."
msgstr ""
msgid "GroupsDropdown|Sorry, no groups matched your search"
-msgstr ""
+msgstr "ඔබගේ සෙවුමට සමූහ කිසිවක් නොගà·à·…පෙයි"
msgid "GroupsDropdown|This feature requires browser localStorage support"
msgstr ""
@@ -22748,8 +22972,8 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr ""
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr "සමූහයක් යනු ව්â€à¶ºà·à¶´à·˜à¶­à·’ කිහිපයක එකතුවකි."
msgid "GroupsEmptyState|Create new project"
msgstr "නව ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් à·ƒà·à¶¯à¶±à·Šà¶±"
@@ -22760,17 +22984,17 @@ msgstr "නව උප සමූහයක් à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "බොහ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’ සහ à·ƒà·à¶¸à·à¶¢à·’කයින් කළමනà·à¶šà¶»à¶«à¶ºà¶§ හොඳම ක්â€à¶»à¶¸à¶º සමූහ වේ."
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr ""
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr "සමූහයක් යටතේ ඔබගේ ව්â€à¶ºà·à¶´à·˜à¶­à·’ සංවිධà·à¶±à¶º කරන්නේ නම්, එය බහà·à¶½à·”මක් පරිදි ක්â€à¶»à·’ය෠කරයි. ඔබගේ සමූහයේ à·ƒà·à¶¸à·à¶¢à·’කයින්ගේ අවසර කළමනà·à¶šà¶»à¶«à¶ºà¶§ මෙන්ම එක් එක් ව්â€à¶ºà·à¶´à·˜à¶­à·’යට තිබෙන ප්â€à¶»à·€à·šà·à¶º ද à·ƒà·à¶šà·ƒà·“මට à·„à·à¶šà·’ය."
msgid "GroupsEmptyState|No archived projects."
-msgstr ""
+msgstr "සංරක්â€à·‚ිත ව්â€à¶ºà·à¶´à·˜à¶­à·’ නà·à¶­."
msgid "GroupsEmptyState|No groups found"
-msgstr ""
+msgstr "සමූහ හමු නොවිණි"
msgid "GroupsEmptyState|No shared projects."
-msgstr ""
+msgstr "බෙදà·à¶œà¶­à·Š ව්â€à¶ºà·à¶´à·˜à¶­à·’ නà·à¶­."
msgid "GroupsEmptyState|No subgroups or projects."
msgstr "උප සමූහ හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’ නà·à¶­."
@@ -22778,9 +23002,6 @@ msgstr "උප සමූහ හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’ නà·à¶­."
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "මෙම සමූහය තුළ උප සමූහයක් හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් සෑදීමට ඔබට අවà·à·Šâ€à¶º අවසර නà·à¶­. නව උප සමූහයක් හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් සෑදීමට මෙම සමූහයේ හිමිකරුවෙකු අමතන්න."
@@ -22800,10 +23021,10 @@ msgid "GroupsNew|Create a token with %{code_start}api%{code_end} and %{code_star
msgstr ""
msgid "GroupsNew|Create group"
-msgstr ""
+msgstr "සමූහයක් à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "GroupsNew|Create new group"
-msgstr ""
+msgstr "නව සමූහයක් à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "GroupsNew|Create subgroup"
msgstr "උප සමූහයක් à·ƒà·à¶¯à¶±à·Šà¶±"
@@ -22815,7 +23036,7 @@ msgid "GroupsNew|GitLab source instance URL"
msgstr ""
msgid "GroupsNew|Groups"
-msgstr ""
+msgstr "සමූහ"
msgid "GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}."
msgstr ""
@@ -22824,7 +23045,7 @@ msgid "GroupsNew|Import a group and related data from another GitLab instance."
msgstr ""
msgid "GroupsNew|Import group"
-msgstr ""
+msgstr "සමූහය ආයà·à¶­ කරන්න"
msgid "GroupsNew|Import groups by direct transfer"
msgstr ""
@@ -22833,10 +23054,10 @@ msgid "GroupsNew|Importing groups by direct transfer is currently disabled."
msgstr ""
msgid "GroupsNew|New group"
-msgstr ""
+msgstr "නව සමූහයක්"
msgid "GroupsNew|New subgroup"
-msgstr ""
+msgstr "නව උප සමූහයක්"
msgid "GroupsNew|Not all group items are migrated. %{docs_link_start}What items are migrated%{docs_link_end}?"
msgstr ""
@@ -22872,34 +23093,34 @@ msgid "GroupsNew|You can also %{linkStart}import an existing group%{linkEnd}."
msgstr ""
msgid "GroupsNew|e.g. h8d3f016698e..."
-msgstr ""
+msgstr "උදà·.: h8d3f016698e..."
msgid "GroupsTree|Are you sure you want to leave the \"%{fullName}\" group?"
-msgstr ""
+msgstr "ඔබට \"%{fullName}\" සමූහය à·„à·à¶» යà·à¶¸à¶§ වුවමන෠ද?"
msgid "GroupsTree|Delete"
-msgstr ""
+msgstr "මකන්න"
msgid "GroupsTree|Edit"
-msgstr ""
+msgstr "සංස්කරණය"
msgid "GroupsTree|Failed to leave the group. Please make sure you are not the only owner."
-msgstr ""
+msgstr "සමූහය à·„à·à¶» යà·à¶¸à¶§ අසමත් විය. ඔබ ඉතිරිව සිටින එකම හිමිකරු නොවන බවට වග බල෠ගන්න."
msgid "GroupsTree|Leave group"
-msgstr ""
+msgstr "සමූහය à·„à·à¶»à¶ºà¶±à·Šà¶±"
msgid "GroupsTree|Loading groups"
-msgstr ""
+msgstr "සමූහ පූරණය වෙමින්"
msgid "GroupsTree|Options"
-msgstr ""
+msgstr "විකල්ප"
msgid "GroupsTree|Search by name"
msgstr "නම අනුව සොයන්න"
msgid "Groups|Avatar will be removed. Are you sure?"
-msgstr ""
+msgstr "ප්â€à¶»à¶­à·’රූපය ඉවත් කෙරෙනු ඇත. ඔබට විà·à·Šà·€à·à·ƒà¶¯?"
msgid "Groups|Changing group URL can have unintended side effects."
msgstr ""
@@ -22908,7 +23129,7 @@ msgid "Groups|Checking group URL availability..."
msgstr ""
msgid "Groups|Create and add README"
-msgstr ""
+msgstr "මෙයකියවන්න à·ƒà·à¶¯à· යොදන්න"
msgid "Groups|Creating README"
msgstr ""
@@ -22917,22 +23138,22 @@ msgid "Groups|Enter a descriptive name for your group."
msgstr ""
msgid "Groups|Group ID"
-msgstr ""
+msgstr "සමූහයේ à·„à·à¶³à·”."
msgid "Groups|Group README"
-msgstr ""
+msgstr "සමූහයේ මෙයකියවන්න"
msgid "Groups|Group URL"
-msgstr ""
+msgstr "සමූහයේ ඒ.ස.නි."
msgid "Groups|Group avatar"
-msgstr ""
+msgstr "සමූහයේ ප්â€à¶»à¶­à·’රූපය"
msgid "Groups|Group description (optional)"
-msgstr ""
+msgstr "සමූහයේ සවිස්තරය (විකල්පයකි)"
msgid "Groups|Group name"
-msgstr ""
+msgstr "සමූහයේ නම"
msgid "Groups|Group path is available."
msgstr ""
@@ -22941,7 +23162,7 @@ msgid "Groups|Group path is unavailable. Path has been replaced with a suggested
msgstr ""
msgid "Groups|Learn more about subgroups"
-msgstr ""
+msgstr "උප සමූහ ගà·à¶± තව දà·à¶±à¶œà¶±à·Šà¶±"
msgid "Groups|Members, projects, trials, and paid subscriptions are tied to a specific top-level group. If you are already a member of a top-level group, you can create a subgroup so your new work is part of your existing top-level group. Do you want to create a subgroup instead?"
msgstr ""
@@ -22950,16 +23171,16 @@ msgid "Groups|Must start with letter, digit, emoji, or underscore. Can also cont
msgstr ""
msgid "Groups|Remove avatar"
-msgstr ""
+msgstr "ප්â€à¶»à¶­à·’රූපය ඉවත් කරන්න"
msgid "Groups|Save changes"
-msgstr ""
+msgstr "වෙනස්කම් සුරකින්න"
msgid "Groups|Subgroup URL"
-msgstr ""
+msgstr "උප සමූහයේ ඒ.ස.නි."
msgid "Groups|Subgroup name"
-msgstr ""
+msgstr "උපසමූහයේ නම"
msgid "Groups|Subgroup slug"
msgstr ""
@@ -23077,7 +23298,7 @@ msgid "HarborRegistry|Something went wrong while fetching the tags."
msgstr ""
msgid "HarborRegistry|Sorry, your filter produced no results."
-msgstr ""
+msgstr "ඔබගේ පෙරීමට කිසිදු ප්â€à¶»à¶­à·’ඵලයක් නà·à¶­"
msgid "HarborRegistry|Tag"
msgstr ""
@@ -23092,7 +23313,7 @@ msgid "HarborRegistry|This image has no artifacts"
msgstr ""
msgid "HarborRegistry|To widen your search, change or remove the filters above."
-msgstr ""
+msgstr "ඔබගේ සෙවීම පුළුල් කිරීමට, ඉහත පෙරහන් වෙනස් හ෠ඉවත් කරන්න."
msgid "HarborRegistry|We are having trouble connecting to the Harbor Registry. Please try refreshing the page. If this error persists, please review %{docLinkStart}the documentation%{docLinkEnd}."
msgstr ""
@@ -23200,6 +23421,9 @@ msgid "Help translate GitLab into your language"
msgstr ""
msgid "Help translate to your language"
+msgstr "ඔබගේ භà·à·‚à·à·€à¶§ පරිවර්තනයට සහà·à¶º වන්න"
+
+msgid "Helpful"
msgstr ""
msgid "Helps prevent bots from brute-force attacks."
@@ -23281,7 +23505,7 @@ msgid "Hide shared projects"
msgstr ""
msgid "Hide sidebar"
-msgstr ""
+msgstr "පà·à¶­à·’ තීරුව වසන්න"
msgid "Hide thread"
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr "මම ගිට්ලà·à¶¶à·Š වෙත ලියà·à¶´à¶¯à·’ංචි වන්නේ:"
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23914,13 +24147,13 @@ msgid "Import from Jira"
msgstr ""
msgid "Import group"
-msgstr ""
+msgstr "සමූහය ආයà·à¶­ කරන්න"
msgid "Import group from file"
-msgstr ""
+msgstr "ගොනුවකින් සමූහයක් ආයà·à¶­ කරන්න"
msgid "Import groups"
-msgstr ""
+msgstr "සමූහ ආයà·à¶­ කරන්න"
msgid "Import history"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24156,7 +24395,7 @@ msgid "In the background, we're attempting to connect you again."
msgstr ""
msgid "In this group"
-msgstr ""
+msgstr "මෙම සමූහයෙහි"
msgid "In this page you will find information about the settings that are used in your current instance."
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "ගිට්ලà·à¶¶à·Š CI/CD ගවේà·à¶±à¶º"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "විකල්ප ගවේà·à¶±à¶º"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr "ගිට්ලà·à¶¶à·Š CI/CD à·„à·’ බලය ගවේà·à¶±à¶º"
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "about.gitlab.com වෙත යන්න"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24756,7 +24635,7 @@ msgid "IncidentManagement|Triggered"
msgstr ""
msgid "IncidentManagement|Unassigned"
-msgstr ""
+msgstr "පවර෠නà·à¶­"
msgid "IncidentManagement|Unknown"
msgstr ""
@@ -24909,7 +24788,7 @@ msgid "Incident|Timeline text..."
msgstr "කà·à¶½à¶»à·šà¶›à· පà·à¶¨à¶º..."
msgid "Include author name in notification email body"
-msgstr ""
+msgstr "දà·à¶±à·”ම්දීමේ වි-තà·à¶´à·‘ලට කර්තෘගේ නම ඇතුළත් කරන්න"
msgid "Include description in commit message"
msgstr ""
@@ -24921,7 +24800,7 @@ msgid "Include the name of the author of the issue, merge request or comment in
msgstr ""
msgid "Include the username in the URL if required: %{code_open}https://username@gitlab.company.com/group/project.git%{code_close}."
-msgstr ""
+msgstr "ඒ.à·ƒ.නි. සඳහ෠වුවමන෠නම් පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º ඇතුළත් කරන්න: %{code_open}https://username@gitlab.company.com/group/project.git%{code_close}."
msgid "Includes LFS objects. It can be overridden per group, or per project. Set to 0 for no limit."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25379,7 +25268,7 @@ msgid "Integrations|Trigger"
msgstr ""
msgid "Integrations|Unable to post to %{channel_list}, please add the GitLab Slack app to any private Slack channels"
-msgstr ""
+msgstr "%{channel_list} වෙත පළ කිරීමට නොහà·à¶šà·’ය, කරුණà·à¶šà¶» ගිට්ලà·à¶¶à·Š ස්ලà·à¶šà·Š යෙදුම ඕනෑම පෞද්ගලික ස්ලà·à¶šà·Š නà·à¶½à·’කà·à·€à¶šà¶§ එක් කරන්න"
msgid "Integrations|Use custom settings"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr "IntelliJ IDEA (HTTPS)"
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25676,10 +25559,10 @@ msgid "InviteMembersModal|Review the invite errors and try again:"
msgstr ""
msgid "InviteMembersModal|Search for a group to invite"
-msgstr ""
+msgstr "ආරà·à¶°à¶±à¶ºà¶§ සමූහයක් සොයන්න"
msgid "InviteMembersModal|Select a group to invite"
-msgstr ""
+msgstr "ආරà·à¶°à¶±à¶ºà¶§ සමූහයක් තà·à¶»à¶±à·Šà¶±"
msgid "InviteMembersModal|Select a role"
msgstr ""
@@ -25708,7 +25591,7 @@ msgid "InviteMembersModal|To assign issues to a new team member, you need a proj
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
-msgstr ""
+msgstr "තවත් à·ƒà·à¶¸à·à¶¢à·’කයින්ට ඉඩ දීම සඳහ෠සමූහයේ හිමිකරුවෙකුට %{trialLinkStart}නà·à·„à·à·ƒà·”මක් ඇරඹීමට à·„à·à¶šà·’ය%{trialLinkEnd} හ෠ගෙවන à·ƒà·à¶½à·ƒà·”මකට %{upgradeLinkStart}උත්à·à·Šâ€à¶»à·šà¶«à·’ කිරීමට%{upgradeLinkEnd} à·„à·à¶šà·’ය."
msgid "InviteMembersModal|To invite new users to this top-level group, you must remove existing users. You can still add existing users from the top-level group, including any subgroups and projects."
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25990,7 +25867,7 @@ msgid "IssueAnalytics|Created by"
msgstr ""
msgid "IssueAnalytics|Due date"
-msgstr ""
+msgstr "නියමිත දිනය"
msgid "IssueAnalytics|Failed to load issues. Please try again."
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr "ඔබගේ පෙරීමට කිසිදු ප්â€à¶»à¶­à·’ඵලයක් නà·à¶­"
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26284,7 +26184,7 @@ msgid "Iterations|Done"
msgstr "අහවරයි"
msgid "Iterations|Due date"
-msgstr ""
+msgstr "නියමිත දිනය"
msgid "Iterations|Duration"
msgstr ""
@@ -26518,22 +26418,25 @@ msgid "JiraConnect|Jira Connect Proxy URL"
msgstr ""
msgid "JiraConnect|Link groups"
-msgstr ""
+msgstr "සමූහ සබඳින්න"
msgid "JiraConnect|Linked groups"
-msgstr ""
+msgstr "සබà·à¶³à·’ සමූහ"
msgid "JiraConnect|New branch was successfully created."
msgstr ""
msgid "JiraConnect|No groups found."
-msgstr ""
+msgstr "සමූහයක් හමු නොවිණි"
msgid "JiraConnect|No linked groups"
-msgstr ""
+msgstr "සබà·à¶³à·’ සමූහ නà·à¶­"
+
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr "ඔබගේ සමූහ නොපෙනේද? ඔබට ප්â€à¶»à·€à·šà·à¶º තිබෙන සමූහ පමණක් මෙහි දිස්වෙයි."
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
-msgstr ""
+msgstr "ඔබගේ සමූහ නොපෙනේද? ඔබට අවම à·€à·à¶ºà·™à¶±à·Š නඩත්තු කිරීමේ භූමිකà·à·€ තිබෙන සමූහ පමණක් මෙහි දිස්වෙයි."
msgid "JiraConnect|Setting up this integration is only possible if you're a GitLab administrator."
msgstr ""
@@ -26545,10 +26448,10 @@ msgid "JiraConnect|Sign in to GitLab to get started."
msgstr ""
msgid "JiraConnect|Sign in to GitLab to link groups."
-msgstr ""
+msgstr "සමූහ සබà·à¶³à·“මට ගිට්ලà·à¶¶à·Š වෙත පිවිසෙන්න."
msgid "JiraConnect|Sign in to link groups"
-msgstr ""
+msgstr "සමූහ සබà·à¶³à·“මට ගිට්ලà·à¶¶à·Š වෙත පිවිසෙන්න"
msgid "JiraConnect|Tell us what you think!"
msgstr ""
@@ -26569,7 +26472,7 @@ msgid "JiraConnect|You can now close this window and return to Jira."
msgstr ""
msgid "JiraConnect|You don't have permission to create branches for this project. Select a different project or contact the project owner for access. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
+msgstr "මෙම ව්â€à¶ºà·à¶´à·˜à¶­à·’ය සඳහ෠à·à·à¶›à· සෑදීමට ඔබට අවසර නà·à¶­. වෙනත් ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් තà·à¶»à¶±à·Šà¶± හ෠ප්â€à¶»à·€à·šà·à¶º සඳහ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ හිමිකරු අමතන්න. %{linkStart}තව දà·à¶±à¶œà¶±à·Šà¶±.%{linkEnd}"
msgid "JiraConnect|You must use a %{linkStart}supported browser%{linkEnd} to use the GitLab for Jira app."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27301,7 +27207,7 @@ msgid "LDAP Synchronization"
msgstr ""
msgid "LDAP group settings"
-msgstr ""
+msgstr "LDAP සමූහයේ à·ƒà·à¶šà·ƒà·”ම්"
msgid "LDAP settings"
msgstr ""
@@ -27411,10 +27317,10 @@ msgid "Label|Assignee"
msgstr ""
msgid "Language"
-msgstr ""
+msgstr "භà·à·‚à·à·€"
msgid "Language type"
-msgstr ""
+msgstr "භà·à·‚෠වර්ගය"
msgid "Large File Storage"
msgstr ""
@@ -27437,14 +27343,11 @@ msgid "Last Accessed On"
msgstr ""
msgid "Last Activity"
-msgstr ""
+msgstr "අවසà·à¶± ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸"
msgid "Last Name"
msgstr "අග නම"
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -27572,7 +27478,7 @@ msgid "Learn More"
msgstr ""
msgid "Learn More."
-msgstr ""
+msgstr "තව දà·à¶±à¶œà¶±à·Šà¶±"
msgid "Learn about signing commits"
msgstr ""
@@ -27623,7 +27529,7 @@ msgid "Learn more about group-level project templates"
msgstr ""
msgid "Learn more about groups."
-msgstr ""
+msgstr "සමූහ ගà·à¶± තව දà·à¶±à¶œà¶±à·Šà¶±."
msgid "Learn more about issues."
msgstr ""
@@ -27650,7 +27556,7 @@ msgid "Learn more in the"
msgstr ""
msgid "Learn more."
-msgstr ""
+msgstr "තව දà·à¶±à¶œà¶±à·Šà¶±"
msgid "Learn more: %{url}"
msgstr ""
@@ -27668,7 +27574,7 @@ msgid "LearnGitLab|Add code"
msgstr ""
msgid "LearnGitLab|Add code owners"
-msgstr ""
+msgstr "කේත හිමිකරුවන් යොදන්න"
msgid "LearnGitLab|Analyze your application for vulnerabilities with DAST"
msgstr ""
@@ -27794,7 +27700,7 @@ msgid "Leave feedback."
msgstr ""
msgid "Leave group"
-msgstr ""
+msgstr "සමූහය à·„à·à¶»à¶ºà¶±à·Šà¶±"
msgid "Leave project"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28396,7 +28308,7 @@ msgid "Mailgun HTTP webhook signing key"
msgstr ""
msgid "Mailgun events"
-msgstr ""
+msgstr "මේල්ගන් සිදුවීම්"
msgid "Main menu"
msgstr "ප්â€à¶»à¶°à·à¶± වට්ටà·à¶»à·”à·€"
@@ -28420,7 +28332,7 @@ msgid "Make everyone on your team more productive regardless of their location.
msgstr ""
msgid "Make new users' profiles private by default"
-msgstr ""
+msgstr "පෙරනිමි පරිදි නව පරිà·à·Šâ€à¶»à·“ලකයින්ගේ පà·à¶­à·’කඩ පෞද්ගලිකව තබන්න"
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -28456,7 +28368,7 @@ msgid "Manage git repositories with fine-grained access controls that keep your
msgstr ""
msgid "Manage group labels"
-msgstr ""
+msgstr "සමූහයේ නම්පත් කළමනà·à¶šà¶»à¶«à¶º"
msgid "Manage labels"
msgstr ""
@@ -28465,7 +28377,7 @@ msgid "Manage members"
msgstr ""
msgid "Manage milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± කළමනà·à¶šà¶»à¶«à¶º"
msgid "Manage project labels"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28690,7 +28614,7 @@ msgid "MattermostService|Use this service to perform common tasks in your projec
msgstr ""
msgid "Max 100,000 events"
-msgstr ""
+msgstr "උපරිම සිදුවීම් 100,000"
msgid "Max Value"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29048,7 +29068,7 @@ msgid "Membership"
msgstr ""
msgid "Members|%{group} by %{createdBy}"
-msgstr ""
+msgstr "%{group} සෑදුවේ %{createdBy}"
msgid "Members|%{time} by %{user}"
msgstr ""
@@ -29060,13 +29080,13 @@ msgid "Members|2FA"
msgstr ""
msgid "Members|A group must have at least one owner. To leave this group, assign a new owner."
-msgstr ""
+msgstr "සමූහයකට අවම à·€à·à¶ºà·™à¶±à·Š එක් හිමිකරුවෙකු සිටිය යුතුය. නව හිමිකරුවෙක්ට පà·à·€à¶»à·“මෙන් මෙම සමූහය à·„à·à¶» යà·à¶¸à¶§ à·„à·à¶šà·’ය."
msgid "Members|A group must have at least one owner. To remove the member, assign a new owner."
-msgstr ""
+msgstr "සමූහයකට අවම à·€à·à¶ºà·™à¶±à·Š එක් හිමිකරුවෙකු සිටිය යුතුය. නව හිමිකරුවෙක්ට පà·à·€à¶»à·“මෙන් à·ƒà·à¶¸à·à¶¢à·’කය෠ඉවත් කිරීමට à·„à·à¶šà·’ය."
msgid "Members|A personal project's owner cannot be removed."
-msgstr ""
+msgstr "පෞද්ගලික ව්â€à¶ºà·à¶´à·˜à¶­à·’යක හිමිකරු ඉවත් කිරීමට නොහà·à¶šà·’ය."
msgid "Members|Access granted"
msgstr ""
@@ -29096,10 +29116,10 @@ msgid "Members|Are you sure you want to leave \"%{source}\"?"
msgstr ""
msgid "Members|Are you sure you want to remove \"%{groupName}\"?"
-msgstr ""
+msgstr "ඔබට \"%{groupName}\" ඉවත් කිරීමට වුවමන෠ද?"
msgid "Members|Are you sure you want to remove %{userName} from \"%{group}\"?"
-msgstr ""
+msgstr "\"%{group}\" වෙතින් %{userName} ඉවත් කිරීමට වුවමන෠ද?"
msgid "Members|Are you sure you want to remove this orphaned member from \"%{group}\"?"
msgstr ""
@@ -29141,7 +29161,7 @@ msgid "Members|Expiration date updated successfully."
msgstr ""
msgid "Members|Filter groups"
-msgstr ""
+msgstr "සමූහ පෙරන්න"
msgid "Members|Filter members"
msgstr ""
@@ -29162,10 +29182,10 @@ msgid "Members|Membership"
msgstr ""
msgid "Members|Remove \"%{groupName}\""
-msgstr ""
+msgstr "\"%{groupName}\" ඉවත් කරන්න"
msgid "Members|Remove group"
-msgstr ""
+msgstr "සමූහය à·„à·à¶»à¶ºà¶±à·Šà¶±"
msgid "Members|Revert to LDAP group sync settings"
msgstr ""
@@ -29186,7 +29206,7 @@ msgid "Members|User created"
msgstr ""
msgid "Members|You cannot remove yourself from a personal project."
-msgstr ""
+msgstr "පෞද්ගලික ව්â€à¶ºà·à¶´à·˜à¶­à·’යකින් ඔබව ඉවත් කර ගà·à¶±à·“මට නොහà·à¶šà·’ය."
msgid "Member|Deny access"
msgstr ""
@@ -29247,11 +29267,14 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
msgid "Merge events"
-msgstr ""
+msgstr "ඒකà·à¶¶à¶¯à·Šà¶° සිදුවීම්"
msgid "Merge immediately"
msgstr ""
@@ -29290,7 +29313,7 @@ msgid "Merge request dependencies"
msgstr ""
msgid "Merge request events"
-msgstr ""
+msgstr "ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම් සිදුවීම්"
msgid "Merge request not merged"
msgstr ""
@@ -29365,7 +29388,7 @@ msgid "MergeChecks|Skipped pipelines are considered successful"
msgstr ""
msgid "MergeChecks|This setting is configured in group %{groupName} and can only be changed in the group settings by an administrator or group owner."
-msgstr ""
+msgstr "මෙම à·ƒà·à¶šà·ƒà·”ම %{groupName} සමූහයේ වින්â€à¶ºà·à·ƒà¶œà¶­ කර ඇති අතර පරිපà·à¶½à¶šà¶ºà·™à¶šà·”ට හ෠සමූහයේ හිමිකරුවෙකුට පමණක් සමූහයේ à·ƒà·à¶šà·ƒà·”ම් හරහ෠වෙනස් කිරීමට à·„à·à¶šà·’ය."
msgid "MergeConflict|Commit to source branch"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -29808,34 +29831,34 @@ msgid "Milestone actions"
msgstr ""
msgid "Milestone due date"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶±à¶ºà¶§ නියමිත දිනය"
msgid "Milestone id(s) not found: %{milestones}"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± à·„à·à¶³à·”. හමු නොවිණි: %{milestones}"
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone(s) not found: %{milestones}"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶±(ය) හමු නොවිණි: %{milestones}"
msgid "MilestoneCombobox|An error occurred while searching for milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± සෙවීමේදී දà·à·‚යක් සිදු විය"
msgid "MilestoneCombobox|Group milestones"
-msgstr ""
+msgstr "සමූහයේ සන්ධිස්ථà·à¶±"
msgid "MilestoneCombobox|Milestone"
msgstr "සන්ධිස්ථà·à¶±à¶º"
msgid "MilestoneCombobox|No matching results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "MilestoneCombobox|No milestone"
msgstr ""
msgid "MilestoneCombobox|Project milestones"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ සන්ධිස්ථà·à¶±"
msgid "MilestoneCombobox|Search Milestones"
msgstr "සන්ධිස්ථà·à¶± සොයන්න"
@@ -29850,28 +29873,28 @@ msgid "MilestonePage|Milestone ID: %{milestone_id}"
msgstr ""
msgid "MilestoneSidebar|Closed:"
-msgstr ""
+msgstr "වස෠ඇත:"
msgid "MilestoneSidebar|Copy reference"
-msgstr ""
+msgstr "සමුද්දේà·à¶ºà·š පිටපතක්"
msgid "MilestoneSidebar|Due date"
-msgstr ""
+msgstr "නියමිත දිනය"
msgid "MilestoneSidebar|Edit"
-msgstr ""
+msgstr "සංස්කරණය"
msgid "MilestoneSidebar|From"
-msgstr ""
+msgstr "වෙතින්"
msgid "MilestoneSidebar|Issues"
msgstr ""
msgid "MilestoneSidebar|Merge requests"
-msgstr ""
+msgstr "ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම"
msgid "MilestoneSidebar|Merged:"
-msgstr ""
+msgstr "ඒකà·à¶¶à¶¯à·Šà¶°à·’ත:"
msgid "MilestoneSidebar|New Issue"
msgstr ""
@@ -29880,43 +29903,43 @@ msgid "MilestoneSidebar|New issue"
msgstr ""
msgid "MilestoneSidebar|No due date"
-msgstr ""
+msgstr "නියමිත දිනයක් නà·à¶­"
msgid "MilestoneSidebar|No start date"
-msgstr ""
+msgstr "ආරම්භක දිනයක් නà·à¶­"
msgid "MilestoneSidebar|None"
-msgstr ""
+msgstr "කිසිවක් නà·à¶­"
msgid "MilestoneSidebar|Open:"
-msgstr ""
+msgstr "විවෘත:"
msgid "MilestoneSidebar|Reference:"
-msgstr ""
+msgstr "සමුද්දේà·à¶º:"
msgid "MilestoneSidebar|Start date"
-msgstr ""
+msgstr "ආරම්භක දිනය"
msgid "MilestoneSidebar|Toggle sidebar"
msgstr ""
msgid "MilestoneSidebar|Until"
-msgstr ""
+msgstr "මෙතෙක්"
msgid "MilestoneSidebar|complete"
-msgstr ""
+msgstr "සම්පූර්ණයි"
msgid "Milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶±"
msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle} and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}. Once deleted, it cannot be undone or recovered."
-msgstr ""
+msgstr "ඔබ %{milestoneTitle} සන්ධිස්ථà·à¶±à¶º සදහටම මක෠දම෠එය %{issuesWithCount} සහ %{mergeRequestsWithCount} වෙතින් ඉවත් කිරීමට à·ƒà·à¶»à·ƒà·™à¶ºà·’. මෙය අප්â€à¶»à¶­à·’වර්ත්â€à¶º අතර ප්â€à¶»à¶­à·’à·ƒà·à¶°à¶±à¶ºà¶§ ද නොහà·à¶šà·’ය."
msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle}. This milestone is not currently used in any issues or merge requests."
msgstr ""
msgid "Milestones|Close Milestone"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶±à¶º වසන්න"
msgid "Milestones|Completed Issues (closed)"
msgstr ""
@@ -29925,19 +29948,19 @@ msgid "Milestones|Create a milestone to better track your issues and merge reque
msgstr ""
msgid "Milestones|Delete milestone"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶±à¶º මකන්න"
msgid "Milestones|Delete milestone %{milestoneTitle}?"
-msgstr ""
+msgstr "%{milestoneTitle} සන්ධිස්ථà·à¶±à¶º මකන්නද?"
msgid "Milestones|Failed to delete milestone %{milestoneTitle}"
-msgstr ""
+msgstr "%{milestoneTitle} සන්ධිස්ථà·à¶±à¶º මà·à¶šà·“මට අසමත් විය"
msgid "Milestones|Group Milestone"
-msgstr ""
+msgstr "සමූහයේ සන්ධිස්ථà·à¶±"
msgid "Milestones|Milestone %{milestoneTitle} was not found"
-msgstr ""
+msgstr "%{milestoneTitle} සන්ධිස්ථà·à¶±à¶º හමු නොවිණි"
msgid "Milestones|Ongoing Issues (open and assigned)"
msgstr ""
@@ -29946,7 +29969,7 @@ msgid "Milestones|Organize issues and merge requests into a cohesive group, and
msgstr ""
msgid "Milestones|Project Milestone"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ සන්ධිස්ථà·à¶±à¶º"
msgid "Milestones|Promote %{milestoneTitle} to group milestone?"
msgstr ""
@@ -29961,16 +29984,16 @@ msgid "Milestones|Promoting %{milestoneTitle} will make it available for all pro
msgstr ""
msgid "Milestones|Reopen Milestone"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶±à¶º යළි අරින්න"
msgid "Milestones|There are no closed milestones"
-msgstr ""
+msgstr "වස෠දà·à¶¸à·– සන්ධිස්ථà·à¶± නà·à¶­"
msgid "Milestones|There are no open milestones"
-msgstr ""
+msgstr "විවෘත සන්ධිස්ථà·à¶± නà·à¶­"
msgid "Milestones|This action cannot be reversed."
-msgstr ""
+msgstr "මෙම ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º අප්â€à¶»à¶­à·’වර්ත්â€à¶ºà¶ºà·’."
msgid "Milestones|Unstarted Issues (open and unassigned)"
msgstr ""
@@ -30273,7 +30296,7 @@ msgid "Most relevant"
msgstr ""
msgid "Most starred"
-msgstr ""
+msgstr "බොහ෠තරුයෙදූ"
msgid "Move"
msgstr ""
@@ -30336,10 +30359,10 @@ msgid "MrDeploymentActions|Stop environment"
msgstr ""
msgid "MrList|Assigned to %{name}"
-msgstr ""
+msgstr "%{name} වෙත පවර෠ඇත"
msgid "MrList|Review requested from %{name}"
-msgstr ""
+msgstr "%{name}ගේ සමà·à¶½à·à¶ à¶±à¶ºà¶šà·Š ඉල්ල෠ඇත"
msgid "MrSurvey|By continuing, you acknowledge that responses will be used to improve GitLab and in accordance with the %{linkStart}GitLab Privacy Policy%{linkEnd}."
msgstr ""
@@ -30381,7 +30404,7 @@ msgid "Must be 90 days or more."
msgstr ""
msgid "My awesome group"
-msgstr ""
+msgstr "මà·à¶œà·š විස්මිත සමූහය"
msgid "My comment templates"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30752,35 +30778,38 @@ msgid "Navigation|Enter admin mode"
msgstr ""
msgid "Navigation|Explore"
-msgstr ""
+msgstr "ගවේà·à¶±à¶º"
msgid "Navigation|Frequently visited groups"
-msgstr ""
+msgstr "නිතර ගොඩවà·à¶¯à·”ණු සමූහ"
msgid "Navigation|Frequently visited projects"
-msgstr ""
+msgstr "නිතර ගොඩවà·à¶¯à·”ණු ව්â€à¶ºà·à¶´à·˜à¶­à·’"
msgid "Navigation|Groups"
-msgstr ""
+msgstr "සමූහ"
msgid "Navigation|Groups you visit often will appear here."
-msgstr ""
+msgstr "ඔබ නිතර ගොඩවදින සමූහ මෙහි දිස්වනු ඇත."
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
-msgid "Navigation|No group matches found"
+msgid "Navigation|Monitor settings"
msgstr ""
+msgid "Navigation|No group matches found"
+msgstr "ගà·à·…පෙන සමූහ හමු නොවිණි"
+
msgid "Navigation|No project matches found"
msgstr ""
@@ -30796,23 +30825,29 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
+msgstr "ඔබ නිතර ගොඩවදින ව්â€à¶ºà·à¶´à·˜à¶­à·’ මෙහි දිස්වනු ඇත."
+
+msgid "Navigation|Repository settings"
msgstr ""
msgid "Navigation|Retrieving search results"
msgstr ""
msgid "Navigation|Search your projects or groups"
-msgstr ""
+msgstr "ඔබගේ ව්â€à¶ºà·à¶´à·˜à¶­à·’ හ෠සමූහ සොයන්න"
msgid "Navigation|Secure"
msgstr ""
msgid "Navigation|Switch context"
-msgstr ""
+msgstr "සන්දර්භය මà·à¶»à·”à·€"
msgid "Navigation|There was an error fetching search results."
msgstr ""
@@ -30820,17 +30855,23 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr "මà·à¶œà·š සියළුම සමූහ පෙන්වන්න"
+
+msgid "Navigation|View all my projects"
+msgstr "මà·à¶œà·š සියළුම ව්â€à¶ºà·à¶´à·˜à¶­à·’ පෙන්වන්න"
+
msgid "Navigation|View all your groups"
-msgstr ""
+msgstr "ඔබගේ සියළුම සමූහ බලන්න"
msgid "Navigation|View all your projects"
-msgstr ""
+msgstr "ඔබගේ සියළුම ව්â€à¶ºà·à¶´à·˜à¶­à·’ බලන්න"
msgid "Navigation|Your pinned items appear here."
msgstr ""
msgid "Navigation|Your work"
-msgstr "ඔබගේ à·€à·à¶©à¶º"
+msgstr "ඔබගේ à·€à·à¶©"
msgid "Nav|Help"
msgstr "උදව්"
@@ -30973,7 +31014,7 @@ msgid "New group"
msgstr "නව සමූහය"
msgid "New group name"
-msgstr ""
+msgstr "නව සමූහයේ නම"
msgid "New health check access token has been generated!"
msgstr ""
@@ -31044,14 +31085,11 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
msgid "New subgroup"
-msgstr ""
+msgstr "නව උප සමූහය"
msgid "New tag"
msgstr ""
@@ -31081,7 +31119,7 @@ msgid "Next commit"
msgstr ""
msgid "Next design"
-msgstr ""
+msgstr "ඊළඟ නිර්මà·à¶«à¶º"
msgid "Next file in diff"
msgstr ""
@@ -31117,7 +31155,7 @@ msgid "No Google Cloud projects - You need at least one Google Cloud project"
msgstr ""
msgid "No Matching Results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "No Milestone"
msgstr ""
@@ -31132,7 +31170,7 @@ msgid "No access"
msgstr ""
msgid "No activities found"
-msgstr ""
+msgstr "ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š හමු නොවිණි"
msgid "No approvers"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31273,9 +31314,15 @@ msgid "No matching labels"
msgstr ""
msgid "No matching results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "No matching results for \"%{query}\""
+msgstr "\"%{query}\" සඳහ෠ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
+
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
msgstr ""
msgid "No members found"
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31333,7 +31383,7 @@ msgid "No public deploy keys"
msgstr ""
msgid "No public groups"
-msgstr ""
+msgstr "ප්â€à¶»à·ƒà·’ද්ධ සමූහ නà·à¶­"
msgid "No ref selected"
msgstr ""
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31384,7 +31431,7 @@ msgid "No starrers matched your search"
msgstr ""
msgid "No start date – %{dueDate}"
-msgstr ""
+msgstr "ආරම්භක දිනයක් නà·à¶­ – %{dueDate}"
msgid "No suggestions found"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -31422,7 +31475,7 @@ msgid "No. of commits"
msgstr ""
msgid "Nobody has starred this repository yet"
-msgstr ""
+msgstr "කිසිවෙක් තවමත් මෙම කà·à·‚්ඨයට තරු යොද෠නà·à¶­"
msgid "Node was successfully created."
msgstr ""
@@ -31479,7 +31532,7 @@ msgid "Not available"
msgstr ""
msgid "Not available for private projects"
-msgstr ""
+msgstr "පෞද්ගලික ව්â€à¶ºà·à¶´à·˜à¶­à·’ සඳහ෠නොතිබේ"
msgid "Not available for protected branches"
msgstr ""
@@ -31587,7 +31640,7 @@ msgid "Nothing to preview."
msgstr ""
msgid "Notification events"
-msgstr ""
+msgstr "දà·à¶±à·”ම්දීමේ සිදුවීම්"
msgid "Notification setting - %{notification_title}"
msgstr ""
@@ -31697,7 +31750,7 @@ msgid "Notifications"
msgstr "දà·à¶±à·”ම්දීම්"
msgid "Notifications have been disabled by the project or group owner"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ හ෠සමූහයේ හිමිකරු දà·à¶±à·”ම්දීම් අබල කර ඇත"
msgid "Notifications off"
msgstr "දà·à¶±à·”ම්දීම් අක්â€à¶»à·’යයි"
@@ -32117,7 +32170,7 @@ msgid "Number of employees"
msgstr ""
msgid "Number of events"
-msgstr ""
+msgstr "සිදුවීම් ගණන"
msgid "Number of files touched"
msgstr ""
@@ -32485,7 +32538,7 @@ msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulne
msgstr ""
msgid "OnDemandScans|Only project owners and maintainers can select runner tags."
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ හිමිකරුවන්ට සහ නඩත්තුකරුවන්ට පමණක් ධà·à·€à¶š අනන්â€à¶ºà¶± තේරීමට à·„à·à¶šà·’ය."
msgid "OnDemandScans|Pre-scan verification for %{profile_name} completed with"
msgstr ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "සංවිධà·à¶±"
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -32919,13 +33008,13 @@ msgid "Owned by:"
msgstr ""
msgid "Owner"
-msgstr ""
+msgstr "හිමිකරු"
msgid "Owners and administrators"
msgstr "හිමිකරුවන් හ෠පරිපà·à¶½à¶šà¶ºà·’න්"
msgid "Owners can modify this selection."
-msgstr ""
+msgstr "හිමිකරුවන්ට මෙම තේරීම වෙනස් කිරීමට à·„à·à¶šà·’ය."
msgid "PQL|An error occurred while sending hand raise lead."
msgstr ""
@@ -33003,7 +33092,7 @@ msgid "Package type must be Maven"
msgstr ""
msgid "Package type must be NPM"
-msgstr ""
+msgstr "ඇසුරුමේ වර්ගය NPM විය යුතුය"
msgid "Package type must be NuGet"
msgstr ""
@@ -33012,7 +33101,7 @@ msgid "Package type must be PyPi"
msgstr ""
msgid "Package type must be RPM"
-msgstr ""
+msgstr "ඇසුරුමේ වර්ගය NPM විය යුතුය"
msgid "Package type must be RubyGems"
msgstr ""
@@ -33386,7 +33475,7 @@ msgid "PackageRegistry|Show Conan commands"
msgstr ""
msgid "PackageRegistry|Show NPM commands"
-msgstr ""
+msgstr "NPM විධà·à¶± පෙන්වන්න"
msgid "PackageRegistry|Show Nuget commands"
msgstr ""
@@ -33422,7 +33511,7 @@ msgid "PackageRegistry|Something went wrong while fetching the package metadata.
msgstr ""
msgid "PackageRegistry|Sorry, your filter produced no results"
-msgstr ""
+msgstr "ඔබගේ පෙරීමට කිසිදු ප්â€à¶»à¶­à·’ඵලයක් නà·à¶­"
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
@@ -33455,7 +33544,7 @@ msgid "PackageRegistry|This NuGet package has no dependencies."
msgstr ""
msgid "PackageRegistry|To widen your search, change or remove the filters above."
-msgstr ""
+msgstr "ඔබගේ සෙවීම පුළුල් කිරීමට, ඉහත පෙරහන් වෙනස් හ෠ඉවත් කරන්න."
msgid "PackageRegistry|Unable to fetch package version information."
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33827,7 +33922,7 @@ msgid "Permalink"
msgstr ""
msgid "Permanently remove group"
-msgstr ""
+msgstr "සමූහයක් සදහටම ඉවත් කරන්න"
msgid "Permissions"
msgstr ""
@@ -33836,7 +33931,7 @@ msgid "Permissions Help"
msgstr ""
msgid "Permissions and group features"
-msgstr ""
+msgstr "අවසර සහ සමූහ විà·à·šà·‚à·à¶‚ග"
msgid "Permissions and project features"
msgstr ""
@@ -33860,7 +33955,7 @@ msgid "Personal projects limit:"
msgstr ""
msgid "PersonalProject|Learn to move a project to a group"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් සමූහයකට ගෙනයà·à¶¸à¶§ දà·à¶± ගන්න"
msgid "PersonalProject|Some GitLab features, including the ability to upgrade to a paid plan or start a free trial, are only available for groups and projects inside groups. %{projectName} is a personal project, so none of this is available. We recommend you move your project to a group to unlock GitLab's full potential."
msgstr ""
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34202,7 +34294,7 @@ msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes
msgstr ""
msgid "PipelineSchedules|Owner"
-msgstr ""
+msgstr "හිමිකරු"
msgid "PipelineSchedules|Pipeline schedule successfully deleted."
msgstr ""
@@ -34226,10 +34318,10 @@ msgid "PipelineSchedules|Successfully scheduled a pipeline to run. Go to the %{l
msgstr ""
msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
-msgstr ""
+msgstr "%{owner}ගෙන් à·ƒà·à¶»à·Šà¶®à¶šà·€ අයිතිය ලබ෠ගà·à¶±à·’ණි."
msgid "PipelineSchedules|Take ownership"
-msgstr ""
+msgstr "අයිතිකරු වන්න"
msgid "PipelineSchedules|Take ownership of pipeline schedule"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34505,7 +34591,7 @@ msgid "Pipelines|Not building for iOS or not what you're looking for? %{linkStar
msgstr ""
msgid "Pipelines|Owner"
-msgstr ""
+msgstr "හිමිකරු"
msgid "Pipelines|Pipeline Editor"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35075,7 +35161,7 @@ msgid "Please select a country / region"
msgstr ""
msgid "Please select a group"
-msgstr ""
+msgstr "සමූහයක් තà·à¶»à¶±à·Šà¶±"
msgid "Please select a valid target branch"
msgstr ""
@@ -35303,7 +35389,7 @@ msgid "Preferences|Customize the behavior of the system layout and default views
msgstr ""
msgid "Preferences|Customize the color of GitLab."
-msgstr ""
+msgstr "ගිට්ලà·à¶¶à·Š පà·à¶§ අභිරුචිකරණය."
msgid "Preferences|Customize the colors of removed and added lines in diffs."
msgstr ""
@@ -35353,14 +35439,11 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr "පෙරදසුන"
msgid "Preferences|Project overview content"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ දළ විà·à·Šà¶½à·šà·‚ණ අන්තර්ගතය"
msgid "Preferences|Render whitespace characters in the Web IDE"
msgstr ""
@@ -35456,7 +35539,7 @@ msgid "Previous commit"
msgstr ""
msgid "Previous design"
-msgstr ""
+msgstr "කලින් නිර්මà·à¶«à¶º"
msgid "Previous file in diff"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35486,28 +35572,28 @@ msgid "Prioritized labels"
msgstr ""
msgid "Priority"
-msgstr ""
+msgstr "ප්â€à¶»à¶¸à·”ඛත්â€à·€à¶º"
msgid "Private"
-msgstr ""
+msgstr "පෞද්ගලික"
msgid "Private - Guest users are not allowed to view detailed release information like title and source code."
-msgstr ""
+msgstr "පෞද්ගලික - ආගන්තුක පරිà·à·Šâ€à¶»à·“ලකයින්ට සිරà·à·ƒà·’ සහ මූලà·à·à·Šâ€à¶» කේත à·€à·à¶±à·’ සවිස්තරà·à¶­à·Šà¶¸à¶š නිකුතු තොරතුරු බà·à¶½à·“මට ඉඩ නොදේ."
msgid "Private - Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group."
-msgstr ""
+msgstr "පෞද්ගලික - ව්â€à¶ºà·à¶´à·˜à¶­à·’ය වෙත ප්â€à¶»à·€à·šà·à¶º එක් එක් පරිà·à·Šâ€à¶»à·“ලකයින්ට ප්â€à¶»à¶¯à·à¶±à¶º කළ යුතුය. මෙම ව්â€à¶ºà·à¶´à·˜à¶­à·’ය සමූහයක කොටසක් නම්, සමූහයේ à·ƒà·à¶¸à·à¶¢à·’කයින්ට ප්â€à¶»à·€à·šà·à¶º ප්â€à¶»à¶¯à·à¶±à¶º වේ."
msgid "Private - The group and its projects can only be viewed by members."
-msgstr ""
+msgstr "පෞද්ගලික - à·ƒà·à¶¸à·à¶¢à·’කයින්ට පමණක් සමූහය හ෠එහි ව්â€à¶ºà·à¶´à·˜à¶­à·’ දà·à¶šà·“මට à·„à·à¶šà·’ය."
msgid "Private group(s)"
-msgstr ""
+msgstr "පෞද්ගලික සමූහ"
msgid "Private profile"
msgstr "පෞද්ගලික පà·à¶­à·’කඩ"
msgid "Private profile:"
-msgstr ""
+msgstr "පෞද්ගලික පà·à¶­à·’කඩ:"
msgid "Private projects can be created in your personal namespace with:"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35630,7 +35710,7 @@ msgid "ProductAnalytics|Event Type"
msgstr ""
msgid "ProductAnalytics|Events"
-msgstr ""
+msgstr "සිදුවීම්"
msgid "ProductAnalytics|Events grouped by %{granularity}"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35846,7 +35923,7 @@ msgid "Profiles|%{provider} Active"
msgstr ""
msgid "Profiles|@username"
-msgstr "@පරිà·à·“ලකනà·à¶¸à¶º"
+msgstr "@පරිà·à·Šâ€à¶»à·“ලකනà·à¶¸à¶º"
msgid "Profiles|Account could not be deleted. GitLab was unable to verify your identity."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr "ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š ආà·à·Šâ€à¶»à·’ත පෞදà
msgid "Profiles|Edit Profile"
msgstr "පà·à¶­à·’කඩ සංස්කරණය"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36014,7 +36091,7 @@ msgid "Profiles|If after setting a password, the option to delete your account i
msgstr ""
msgid "Profiles|Include private contributions on your profile"
-msgstr ""
+msgstr "මà·à¶œà·š පà·à¶­à·’කඩෙහි පෞද්ගලික දà·à¶ºà¶šà¶­à·Šâ€à·€ ද පෙන්වන්න"
msgid "Profiles|Incoming email token was successfully reset"
msgstr ""
@@ -36050,7 +36127,7 @@ msgid "Profiles|Location"
msgstr "ස්ථà·à¶±à¶º"
msgid "Profiles|Made a private contribution"
-msgstr ""
+msgstr "පෞද්. දà·à¶ºà¶šà¶­à·Šâ€à·€à¶ºà¶šà·Š ලබ෠දී ඇත"
msgid "Profiles|Main settings"
msgstr "ප්â€à¶»à¶°à·à¶± à·ƒà·à¶šà·ƒà·”ම්"
@@ -36173,16 +36250,16 @@ msgid "Profiles|Usage type"
msgstr "භà·à·€à·’ත වර්ගය"
msgid "Profiles|Use a private email - %{email}"
-msgstr ""
+msgstr "පෞද්. වි-තà·à¶´à·‘ලක් යොදà·à¶œà¶±à·Šà¶± - %{email}"
msgid "Profiles|User ID"
-msgstr "පරිà·à·“ලක à·„à·à¶³à·”."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·„à·à¶³à·”."
msgid "Profiles|Username change failed - %{message}"
msgstr ""
msgid "Profiles|Username successfully changed"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ වෙනස් කෙරිණි"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ වෙනස් කෙරිණි"
msgid "Profiles|Using emoji in names seems fun, but please try to set a status message instead"
msgstr ""
@@ -36212,13 +36289,13 @@ msgid "Profiles|You must accept the Terms of Service in order to perform this ac
msgstr ""
msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
-msgstr ""
+msgstr "ඔබගේ ගිණුම මà·à¶šà·“මට පෙර ඔබට අයිති සමූහ පà·à·€à¶»à·’ය යුතුය හ෠මක෠දà·à¶¸à·’ය යුතුය."
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
-msgstr ""
+msgstr "ඔබගේ ගිණුම මà·à¶šà·“මට පෙර මෙම සමූහවල අයිතිය පà·à·€à¶»à·’ය යුතුය හ෠මක෠දà·à¶¸à·’ය යුතුය."
msgid "Profiles|Your Discord user ID. %{external_accounts_link_start}Learn more.%{external_accounts_link_end}"
-msgstr ""
+msgstr "ඔබගේ ඩිස්කà·à¶©à·Š à·„à·à¶³à·”. %{external_accounts_link_start}තව දà·à¶±à¶œà¶±à·Šà¶±.%{external_accounts_link_end}"
msgid "Profiles|Your LinkedIn profile name from linkedin.com/in/profilename"
msgstr "linkedin.com/in/profilename වෙතින් පà·à¶­à·’කඩ නà·à¶¸à¶º"
@@ -36242,7 +36319,7 @@ msgid "Profiles|https://website.com"
msgstr "https://අඩවිය.ලංකà·"
msgid "Profiles|username"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º"
msgid "Profiles|your account"
msgstr ""
@@ -36275,7 +36352,7 @@ msgid "Project \"%{name}\" is no longer available. Select another project to con
msgstr ""
msgid "Project %{code_open}%{source_project}%{code_close} has more restricted access settings than %{code_open}%{target_project}%{code_close}. To avoid exposing private changes, make sure you're submitting changes to the correct project."
-msgstr ""
+msgstr "%{code_open}%{target_project}%{code_close} ව්â€à¶ºà·à¶´à·˜à¶­à·’යට වඩ෠සීම෠කළ ප්â€à¶»à·€à·šà· à·ƒà·à¶šà·ƒà·”ම් %{code_open}%{source_project}%{code_close} à·„à·’ ඇත. පෞද්ගලික වෙනස්කම් හෙළි නොවීමට, ඔබ නිවà·à¶»à¶¯à·’ ව්â€à¶ºà·à¶´à·˜à¶­à·’යට වෙනස්කම් යොමු කරන බවට වග බල෠ගන්න."
msgid "Project %{project_repo} could not be found"
msgstr ""
@@ -36332,7 +36409,7 @@ msgid "Project and wiki repositories"
msgstr ""
msgid "Project audit events"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ විගණන සිදුවීම්"
msgid "Project avatar"
msgstr ""
@@ -36398,14 +36475,11 @@ msgid "Project navigation"
msgstr ""
msgid "Project or Group"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් හ෠සමූහයක්"
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36482,10 +36556,10 @@ msgid "ProjectLastActivity|Never"
msgstr ""
msgid "ProjectList|Starred"
-msgstr ""
+msgstr "තරු යෙදූ"
msgid "ProjectList|Yours"
-msgstr ""
+msgstr "ඔබගේ"
msgid "ProjectOverview|Create new fork"
msgstr ""
@@ -36605,7 +36679,7 @@ msgid "ProjectQualitySummary|Violations found"
msgstr ""
msgid "ProjectSelect|No matching results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "ProjectSelect|Search for project"
msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් සඳහ෠සොයන්න"
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37016,7 +37096,7 @@ msgid "ProjectSettings|Prevents direct linking to potentially sensitive media fi
msgstr ""
msgid "ProjectSettings|Private"
-msgstr ""
+msgstr "පෞද්ගලික"
msgid "ProjectSettings|Product analytics"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37151,7 +37237,7 @@ msgid "ProjectSettings|Topics"
msgstr ""
msgid "ProjectSettings|Topics are publicly visible even on private projects. Do not include sensitive information in topic names. %{linkStart}Learn more%{linkEnd}."
-msgstr ""
+msgstr "පෞද්ගලික ව්â€à¶ºà·à¶´à·˜à¶­à·’වල පව෠මà·à¶­à·˜à¶šà· ප්â€à¶»à·ƒà·’ද්ධියේ දිස්වේ. මà·à¶­à·˜à¶šà·à·€à¶½ නම් සඳහ෠සංවේදී තොරතුරු ඇතුළත් නොකරන්න. %{linkStart}තව දà·à¶±à¶œà¶±à·Šà¶±%{linkEnd}."
msgid "ProjectSettings|Track machine learning model experiments and artifacts."
msgstr ""
@@ -37322,7 +37408,7 @@ msgid "ProjectTransfer|An error occurred fetching the transfer locations, please
msgstr ""
msgid "ProjectView|Activity"
-msgstr ""
+msgstr "ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š"
msgid "ProjectView|Files and Readme (default)"
msgstr "ගොනු හ෠මෙයකියවන්න (පෙරනිමි)"
@@ -37361,10 +37447,10 @@ msgid "Projects help you organize your work. They contain your file repository,
msgstr ""
msgid "Projects in this group can use Git LFS"
-msgstr ""
+msgstr "මෙම සමූහයේ ව්â€à¶ºà·à¶´à·˜à¶­à·’ වලට ගිට් LFS භà·à·€à·’ත෠කිරීමට à·„à·à¶šà·’ය"
msgid "Projects shared with %{group_name}"
-msgstr ""
+msgstr "%{group_name} සමඟ බෙදà·à¶œà¶­à·Š ව්â€à¶ºà·à¶´à·˜à¶­à·’"
msgid "Projects to index"
msgstr ""
@@ -37454,7 +37540,7 @@ msgid "ProjectsNew|Enable Static Application Security Testing (SAST)"
msgstr ""
msgid "ProjectsNew|Group name"
-msgstr ""
+msgstr "සමූහයේ නම"
msgid "ProjectsNew|Import"
msgstr "ආයà·à¶­à¶º"
@@ -37697,10 +37783,10 @@ msgid "Promotions|Configure Service Desk"
msgstr ""
msgid "Promotions|Contact an owner of group %{namespace_name} to upgrade the plan."
-msgstr ""
+msgstr "à·ƒà·à¶½à·ƒà·”ම උත්à·à·Šâ€à¶»à·šà¶«à·’ කිරීමට %{namespace_name} සමූහයේ හිමිකරුවෙකු අමතන්න."
msgid "Promotions|Contact owner %{link_start}%{owner_name}%{link_end} to upgrade the plan."
-msgstr ""
+msgstr "à·ƒà·à¶½à·ƒà·”ම උත්à·à·Šâ€à¶»à·šà¶«à·’ කිරීමට %{link_start}%{owner_name}%{link_end} හිමිකරු අමතන්න."
msgid "Promotions|Contact your Administrator to upgrade your license."
msgstr ""
@@ -37916,11 +38002,17 @@ msgid "ProtectedBranch|By default, protected branches restrict who can modify th
msgstr ""
msgid "ProtectedBranch|Code owner approval"
-msgstr ""
+msgstr "කේත හිමිකරුගේ අනුමà·à¶­à·’ය"
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37958,7 +38050,7 @@ msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOW
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
-msgstr ""
+msgstr "කේත හිමිකරුවන්ගේ අනුමà·à¶­à·’ය වුවමනà·à¶º:"
msgid "ProtectedBranch|Search protected tags"
msgstr "රක්â€à·‚ිත අනන්â€à¶ºà¶± සොයන්න"
@@ -37976,7 +38068,7 @@ msgid "ProtectedBranch|Toggle allowed to force push"
msgstr ""
msgid "ProtectedBranch|Toggle code owner approval"
-msgstr ""
+msgstr "කේත හිමිකරුගේ අනුමà·à¶­à·’ය සබල කරන්න"
msgid "ProtectedBranch|Unprotect"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr "සමූහ තà·à¶»à¶±à·Šà¶±"
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38313,7 +38408,7 @@ msgid "Push commits to the source branch or add previously merged commits to rev
msgstr ""
msgid "Push events"
-msgstr ""
+msgstr "තල්ලු සිදුවීම්"
msgid "Push project from command line"
msgstr ""
@@ -38430,7 +38525,7 @@ msgid "PushoverService|Get real-time notifications on your device."
msgstr ""
msgid "PushoverService|High priority"
-msgstr ""
+msgstr "ඉහළ ප්â€à¶»à¶¸à·”ඛත්â€à·€à¶º"
msgid "PushoverService|Leave blank for all active devices."
msgstr ""
@@ -38439,13 +38534,13 @@ msgid "PushoverService|Leave blank to use your current user key."
msgstr ""
msgid "PushoverService|Low priority"
-msgstr ""
+msgstr "අඩු ප්â€à¶»à¶¸à·”ඛත්â€à·€à¶º"
msgid "PushoverService|Lowest priority"
-msgstr ""
+msgstr "අවම ප්â€à¶»à¶¸à·”ඛත්â€à·€à¶º"
msgid "PushoverService|Normal priority"
-msgstr ""
+msgstr "à·ƒà·à¶¸à·à¶±à·Šâ€à¶º ප්â€à¶»à¶¸à·”ඛත්â€à·€à¶º"
msgid "PushoverService|See project %{project_full_name}"
msgstr ""
@@ -38517,10 +38612,10 @@ msgid "Re-import without projects"
msgstr ""
msgid "Re-request review"
-msgstr ""
+msgstr "යළි සමà·à¶½à·à¶ à¶±à¶ºà¶§ ඉල්ලන්න"
msgid "Read documentation"
-msgstr ""
+msgstr "ප්â€à¶»à¶½à·šà¶›à¶±à¶º කියවන්න"
msgid "Read more"
msgstr ""
@@ -38535,7 +38630,7 @@ msgid "Read the documentation before applying changes."
msgstr ""
msgid "Read their documentation."
-msgstr ""
+msgstr "එම ප්â€à¶»à¶½à·šà¶›à¶±à¶º කියවන්න."
msgid "Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project."
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr "මෑත"
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39001,7 +39069,7 @@ msgid "Remove description history"
msgstr ""
msgid "Remove due date"
-msgstr ""
+msgstr "නියමිත දිනය ඉවත් කරන්න"
msgid "Remove epic reference"
msgstr ""
@@ -39022,7 +39090,7 @@ msgid "Remove from epic"
msgstr ""
msgid "Remove group"
-msgstr ""
+msgstr "සමූහය ඉවත් කරන්න"
msgid "Remove header logo"
msgstr ""
@@ -39073,10 +39141,7 @@ msgid "Remove phone verification exemption"
msgstr ""
msgid "Remove priority"
-msgstr ""
-
-msgid "Remove report"
-msgstr ""
+msgstr "ප්â€à¶»à¶¸à·”ඛත්â€à·€à¶º ඉවත් කරන්න"
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,11 +39167,8 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
-msgstr ""
+msgstr "සමූහයෙන් පරිà·à·Šâ€à¶»à·“ලකය෠ඉවත් කරන්න"
msgid "Remove user from project"
msgstr ""
@@ -39136,7 +39201,7 @@ msgid "Removed an issue from an epic."
msgstr ""
msgid "Removed group can not be restored!"
-msgstr ""
+msgstr "ඉවත් කළ සමූහයක් ප්â€à¶»à¶­à·Šâ€à¶ºà¶»à·Šà¶´à¶«à¶ºà¶§ නොහà·à¶šà·’ය!"
msgid "Removed link with %{issue_ref}."
msgstr ""
@@ -39148,7 +39213,7 @@ msgid "Removed spent time."
msgstr ""
msgid "Removed the due date."
-msgstr ""
+msgstr "නියමිත දිනය ඉවත් කෙරිණි."
msgid "Removed time estimate."
msgstr ""
@@ -39157,10 +39222,10 @@ msgid "Removed upload with id %{id}"
msgstr ""
msgid "RemovedProjects|No projects pending deletion found"
-msgstr ""
+msgstr "මà·à¶šà·“මට තිබෙන ව්â€à¶ºà·à¶´à·˜à¶­à·’ කිසිවක් හමු නොවිණි"
msgid "RemovedProjects|Projects that are pending deletion that you have access to are listed here."
-msgstr ""
+msgstr "ඔබට ප්â€à¶»à·€à·šà·à¶º සහිත මà·à¶šà·“මට නියමිත ව්â€à¶ºà·à¶´à·˜à¶­à·’ මෙහි දිස් වේ."
msgid "Removes %{assignee_text} %{assignee_references}."
msgstr ""
@@ -39196,7 +39261,7 @@ msgid "Removes spent time."
msgstr ""
msgid "Removes the due date."
-msgstr ""
+msgstr "නියමිත දිනය ඉවත් කරයි."
msgid "Removes time estimate."
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr "ඉල්ලීම"
@@ -39715,7 +39771,7 @@ msgid "Request details"
msgstr ""
msgid "Request review from"
-msgstr ""
+msgstr "සමà·à¶½à·à¶ à¶±à¶ºà¶šà·Š ඉල්ලන්න"
msgid "Request time"
msgstr ""
@@ -39733,7 +39789,7 @@ msgid "Requested design version does not exist."
msgstr ""
msgid "Requested review"
-msgstr ""
+msgstr "සමà·à¶½à·à¶ à¶±à¶ºà¶šà·Š ඉල්ල෠ඇත"
msgid "Requested states are invalid"
msgstr ""
@@ -40056,7 +40112,7 @@ msgid "Reviewing"
msgstr ""
msgid "Reviewing (merge request !%{mergeRequestId})"
-msgstr ""
+msgstr "සමà·à¶½à·à¶ à¶±à¶º කරමින් (%{mergeRequestId} ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම!)"
msgid "Revoke"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40167,7 +40226,7 @@ msgid "Runner was successfully updated."
msgstr ""
msgid "RunnerTags|No matching results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "RunnerTags|No tags exist"
msgstr ""
@@ -40241,7 +40300,7 @@ msgid "Runners|Active runners"
msgstr ""
msgid "Runners|Add notes such as the runner owner or what it should be used for."
-msgstr ""
+msgstr "ධà·à·€à¶šà¶ºà·š අයිතිකරු හ෠එය භà·à·€à·’ත෠කළ යුතු අවස්ථ෠වà·à¶±à·’ සටහන් යොදන්න."
msgid "Runners|Add tags for the types of jobs the runner processes to ensure that the runner only runs jobs that you intend it to. %{helpLinkStart}Learn more.%{helpLinkEnd}"
msgstr ""
@@ -40295,7 +40354,7 @@ msgid "Runners|Assigned Group"
msgstr "පà·à·€à¶»à·”ණු සමූහය"
msgid "Runners|Assigned Projects (%{projectCount})"
-msgstr ""
+msgstr "පවරන ලද ව්â€à¶ºà·à¶´à·˜à¶­à·’ (%{projectCount})"
msgid "Runners|Assigned project runners"
msgstr ""
@@ -40465,7 +40524,7 @@ msgid "Runners|Go to runners page"
msgstr ""
msgid "Runners|Group"
-msgstr ""
+msgstr "සමූහය"
msgid "Runners|Group area › Runners"
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40618,7 +40680,7 @@ msgid "Runners|Operating systems"
msgstr ""
msgid "Runners|Owner"
-msgstr ""
+msgstr "හිමිකරු"
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41052,7 +41117,7 @@ msgid "Runners|active"
msgstr ""
msgid "Runners|group"
-msgstr ""
+msgstr "සමූහය"
msgid "Runners|paused"
msgstr ""
@@ -41079,16 +41144,16 @@ msgid "SAML SSO"
msgstr ""
msgid "SAML SSO for %{group_name}"
-msgstr ""
+msgstr "%{group_name} සඳහ෠SAML SSO"
msgid "SAML discovery tokens"
msgstr ""
msgid "SAML for %{group_name}"
-msgstr ""
+msgstr "%{group_name} සඳහ෠SAML"
msgid "SAML group membership settings"
-msgstr ""
+msgstr "SAML සමූහ à·ƒà·à¶¸à·à¶¢à·’කත්â€à·€ à·ƒà·à¶šà·ƒà·”ම්"
msgid "SAML single sign-on"
msgstr ""
@@ -41097,7 +41162,7 @@ msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to %{groupName}"
-msgstr ""
+msgstr "%{groupName} වෙත පිවිසෙන්න"
msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr "මුරපදය සුරකින්න"
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr "සමූහයක් සොයන්න"
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,15 +41734,12 @@ msgstr "සන්ධිස්ථà·à¶± සොයන්න"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
-msgstr "ප්â€à¶»à¶­à·’ඵල සොයන්න හ෠පෙරන්න..."
-
msgid "Search or filter results…"
msgstr "සොයන්න හ෠ප්â€à¶»à¶­à·’ඵල පෙරන්න…"
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr "පිටුව සොයන්න"
@@ -41661,7 +41762,7 @@ msgid "Search requirements"
msgstr "අවà·à·Šâ€à¶ºà¶­à· සොයන්න"
msgid "Search results"
-msgstr ""
+msgstr "සෙවුම් ප්â€à¶»à¶­à·’ඵල"
msgid "Search settings"
msgstr "à·ƒà·à¶šà·ƒà·”ම් සොයන්න"
@@ -41673,10 +41774,10 @@ msgid "Search your projects"
msgstr "ඔබගේ ව්â€à¶ºà·à¶´à·˜à¶­à·’ සොයන්න"
msgid "Search your%{visibility}projects"
-msgstr ""
+msgstr "ඔබගේ %{visibility} ව්â€à¶ºà·à¶´à·˜à¶­à·’ සොයන්න"
msgid "Search%{visibility}projects"
-msgstr ""
+msgstr "%{visibility} ව්â€à¶ºà·à¶´à·˜à¶­à·’ සොයන්න"
msgid "SearchCodeResults|of %{link_to_project}"
msgstr ""
@@ -41761,7 +41862,7 @@ msgid "SearchToken|Assignee"
msgstr ""
msgid "SearchToken|Reviewer"
-msgstr ""
+msgstr "සමà·à¶½à·à¶ à¶š"
msgid "Searching by both author and message is currently not supported."
msgstr ""
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr "ආරක්â€à·‚ණ උපකරණ පුවරුව"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41890,7 +41994,7 @@ msgid "SecurityConfiguration|Available with Ultimate"
msgstr ""
msgid "SecurityConfiguration|BAS"
-msgstr ""
+msgstr "BAS"
msgid "SecurityConfiguration|Breach and Attack Simulation (BAS)"
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42369,7 +42494,7 @@ msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
msgid "SecurityOrchestration|Sorry, your filter produced no results."
-msgstr ""
+msgstr "ඔබගේ පෙරීමට කිසිදු ප්â€à¶»à¶­à·’ඵලයක් නà·à¶­"
msgid "SecurityOrchestration|Source"
msgstr ""
@@ -42399,7 +42524,7 @@ msgid "SecurityOrchestration|This %{namespaceType} is not linked to a security p
msgstr ""
msgid "SecurityOrchestration|This group"
-msgstr ""
+msgstr "මෙම සමූහය"
msgid "SecurityOrchestration|This is a group-level policy"
msgstr "මෙය සමූහ මට්ටමේ ප්â€à¶»à¶­à·’පත්තියකි"
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42750,7 +42899,7 @@ msgid "SecurityReports|Monitor vulnerabilities in your project"
msgstr ""
msgid "SecurityReports|Monitored projects"
-msgstr ""
+msgstr "නිරීක්â€à·‚ිත ව්â€à¶ºà·à¶´à·˜à¶­à·’"
msgid "SecurityReports|More info"
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42833,7 +42979,7 @@ msgid "SecurityReports|Sometimes a scanner can't determine a finding's severity.
msgstr ""
msgid "SecurityReports|Sorry, your filter produced no results"
-msgstr ""
+msgstr "ඔබගේ පෙරීමට කිසිදු ප්â€à¶»à¶­à·’ඵලයක් නà·à¶­"
msgid "SecurityReports|Status"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -42902,7 +43048,7 @@ msgid "SecurityReports|This selection is required."
msgstr ""
msgid "SecurityReports|To widen your search, change or remove filters above"
-msgstr ""
+msgstr "ඔබගේ සෙවීම පුළුල් කිරීමට, ඉහත පෙරහන් වෙනස් හ෠ඉවත් කරන්න."
msgid "SecurityReports|Tool"
msgstr ""
@@ -42974,7 +43120,7 @@ msgid "Select Profile"
msgstr ""
msgid "Select a LDAP group"
-msgstr ""
+msgstr "LDAP සමූහයක් තà·à¶»à¶±à·Šà¶±"
msgid "Select a branch"
msgstr ""
@@ -42998,7 +43144,7 @@ msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll
msgstr ""
msgid "Select a group"
-msgstr ""
+msgstr "සමූහයක් තà·à¶»à¶±à·Šà¶±"
msgid "Select a label"
msgstr ""
@@ -43058,16 +43204,16 @@ msgid "Select default branch"
msgstr ""
msgid "Select due date"
-msgstr ""
+msgstr "නියමිත දිනය තà·à¶»à¶±à·Šà¶±"
msgid "Select epic"
msgstr ""
msgid "Select group"
-msgstr ""
+msgstr "සමූහයක් තà·à¶»à¶±à·Šà¶±"
msgid "Select group or project"
-msgstr ""
+msgstr "සමූහයක් හ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් තà·à¶»à¶±à·Šà¶±"
msgid "Select health status"
msgstr ""
@@ -43091,7 +43237,7 @@ msgid "Select milestone"
msgstr ""
msgid "Select private project"
-msgstr ""
+msgstr "පෞද්. ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් තà·à¶»à¶±à·Šà¶±"
msgid "Select project"
msgstr ""
@@ -43136,7 +43282,7 @@ msgid "Select strategy activation method"
msgstr ""
msgid "Select subgroup"
-msgstr ""
+msgstr "උප සමූහයක් තà·à¶»à¶±à·Šà¶±"
msgid "Select subscription"
msgstr ""
@@ -43181,7 +43327,7 @@ msgid "Send"
msgstr ""
msgid "Send a single email notification to Owners and Maintainers for new alerts."
-msgstr ""
+msgstr "නව ඇඟවීම් සඳහ෠හිමිකරුවන් සහ නඩත්තුකරුවන් වෙත තනි වි-තà·à¶´à·à¶½à·Š දà·à¶±à·”ම්දීමක් යවන්න."
msgid "Send email"
msgstr ""
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43445,7 +43675,7 @@ msgid "Set any rate limit to %{code_open}0%{code_close} to disable the limit."
msgstr ""
msgid "Set due date"
-msgstr ""
+msgstr "නියමිත දිනය සකසන්න"
msgid "Set health status"
msgstr "සෞඛ්â€à¶º තත්â€à·€à¶º සකසන්න"
@@ -43508,7 +43738,7 @@ msgid "Set the default expiration time for job artifacts in all projects. Set to
msgstr ""
msgid "Set the due date to %{due_date}."
-msgstr ""
+msgstr "%{due_date} ට නියමිත දිනය සකසන්න."
msgid "Set the iteration to %{iteration_reference}."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -43634,7 +43870,7 @@ msgid "Sets target branch to %{branch_name}."
msgstr ""
msgid "Sets the due date to %{due_date}."
-msgstr ""
+msgstr "%{due_date} ට නියමිත දිනය සකසයි."
msgid "Sets the iteration to %{iteration_reference}."
msgstr ""
@@ -43753,7 +43989,7 @@ msgid "Short name"
msgstr ""
msgid "Should these changes be private?"
-msgstr ""
+msgstr "මෙම වෙනස්කම් පෞද්ගලික විය යුතුද?"
msgid "Should you ever lose your phone or access to your one time password secret, each of these recovery codes can be used one time each to regain access to your account. Please save them in a safe place, or you %{boldStart}will%{boldEnd} lose access to your account."
msgstr ""
@@ -43780,7 +44016,7 @@ msgid "Show all issues."
msgstr ""
msgid "Show all milestones"
-msgstr ""
+msgstr "සියළුම සන්ධිස්ථà·à¶± පෙන්වන්න"
msgid "Show all test cases."
msgstr ""
@@ -43825,7 +44061,7 @@ msgid "Show full blame"
msgstr ""
msgid "Show group milestones"
-msgstr ""
+msgstr "සමූහයේ සන්ධිස්ථà·à¶± පෙන්වන්න"
msgid "Show labels"
msgstr ""
@@ -43852,13 +44088,13 @@ msgid "Show password"
msgstr ""
msgid "Show project milestones"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ සන්ධිස්ථà·à¶± පෙන්වන්න"
msgid "Show sidebar"
-msgstr ""
+msgstr "පà·à¶­à·’ තීරුව පෙන්වන්න"
msgid "Show sub-group milestones"
-msgstr ""
+msgstr "උප සමූහවල සන්ධිස්ථà·à¶± පෙන්වන්න"
msgid "Show the Closed list"
msgstr ""
@@ -44364,7 +44600,7 @@ msgid "SnippetsEmptyState|Code snippets"
msgstr ""
msgid "SnippetsEmptyState|Documentation"
-msgstr ""
+msgstr "ප්â€à¶»à¶½à·šà¶›à¶±à¶º"
msgid "SnippetsEmptyState|New snippet"
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr "යමෙක් ඔබගේ %{host} ගිණුමට නව ස්ථ
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "යමෙක්, බොහà·à·€à·’ට ඔබ, %{link_to_gitlab} à·„à·’ ඔබගේ ගිට්ලà·à¶¶à·Š ගිණුමේ මුරපදය යළි පිහිටුවීමට ඉල්ල෠ඇත."
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr "සවිස්තරයෙහි වෙනස්කම් ගà·à¶±à·“à
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr "නවතම අදහස් ගà·à¶±à·“මේදී යම් දෙයක් à·€à·à¶»à¶¯à·“ ඇත."
-
msgid "Something went wrong while fetching projects"
msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ ගà·à¶±à·“මේදී යම් දෙයක් à·€à·à¶»à¶¯à·“ ඇත"
@@ -44676,19 +44912,19 @@ msgid "Sorry, you have exceeded the maximum browsable page number. Please use th
msgstr ""
msgid "Sorry, your filter produced no results"
-msgstr ""
+msgstr "ඔබගේ පෙරීමට කිසිදු ප්â€à¶»à¶­à·’ඵලයක් නà·à¶­"
msgid "Sort by"
msgstr ""
msgid "Sort direction"
-msgstr ""
+msgstr "පෙළගà·à·ƒà·“මේ දිà·à·à¶±à¶­à·’ය"
msgid "Sort direction: Ascending"
-msgstr ""
+msgstr "පෙළගà·à·ƒà·“මේ දිà·à·à¶±à¶­à·’ය: ආරà·à·„ණ"
msgid "Sort direction: Descending"
-msgstr ""
+msgstr "පෙළගà·à·ƒà·“මේ දිà·à·à¶±à¶­à·’ය: අවරà·à·„ණ"
msgid "Sort or filter"
msgstr ""
@@ -44709,7 +44945,7 @@ msgid "SortOptions|Created date"
msgstr "සෑදූ දිනය"
msgid "SortOptions|Due date"
-msgstr ""
+msgstr "නියමිත දිනය"
msgid "SortOptions|Due later"
msgstr ""
@@ -44733,7 +44969,7 @@ msgid "SortOptions|Last Contact"
msgstr ""
msgid "SortOptions|Last created"
-msgstr ""
+msgstr "අන්තිමට සෑදූ"
msgid "SortOptions|Latest version"
msgstr ""
@@ -44757,7 +44993,7 @@ msgid "SortOptions|Merged recently"
msgstr "මෑතදී ඒකà·à¶¶à¶¯à·Šà¶°à·’ත"
msgid "SortOptions|Milestone due date"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶±à¶ºà¶§ නියමිත දිනය"
msgid "SortOptions|Milestone due later"
msgstr ""
@@ -44784,7 +45020,7 @@ msgid "SortOptions|Name, descending"
msgstr "නම, අවරà·à·„ණ"
msgid "SortOptions|Oldest created"
-msgstr ""
+msgstr "මුලින්ම සෑදූ"
msgid "SortOptions|Oldest last activity"
msgstr "පරණම අවසà·à¶± ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸"
@@ -44793,7 +45029,7 @@ msgid "SortOptions|Oldest sign in"
msgstr ""
msgid "SortOptions|Oldest starred"
-msgstr ""
+msgstr "පරණම තරුයෙදූ"
msgid "SortOptions|Oldest updated"
msgstr ""
@@ -44817,7 +45053,7 @@ msgid "SortOptions|Recent sign in"
msgstr "මෑත ඇතුළු වීම"
msgid "SortOptions|Recently starred"
-msgstr ""
+msgstr "මෑතදී තරු යෙදූ"
msgid "SortOptions|Size"
msgstr "ප්â€à¶»à¶¸à·à¶«à¶º"
@@ -44826,7 +45062,7 @@ msgid "SortOptions|Sort by:"
msgstr ""
msgid "SortOptions|Sort direction"
-msgstr ""
+msgstr "පෙළගà·à·ƒà·“මේ දිà·à·à¶±à¶­à·’ය"
msgid "SortOptions|Stars"
msgstr "තරු"
@@ -45054,16 +45290,16 @@ msgid "Starred Projects"
msgstr "තරු යෙදූ ව්â€à¶ºà·à¶´à·˜à¶­à·’"
msgid "Starred Projects' Activity"
-msgstr ""
+msgstr "තරු යෙදූ ව්â€à¶ºà·à¶´à·˜à¶­à·’වල ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š"
msgid "Starred projects"
msgstr "තරු යෙදූ ව්â€à¶ºà·à¶´à·˜à¶­à·’"
msgid "StarredProjectsEmptyState|Visit a project page and press on a star icon. Then, you can find the project on this page."
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යක පිටුවට ගොස් තරු නිරූපකය ඔබන්න. එවිට, මෙම පිටුවෙහි ව්â€à¶ºà·à¶´à·˜à¶­à·’ය දිස් වනු ඇත."
msgid "StarredProjectsEmptyState|You don't have starred projects yet."
-msgstr ""
+msgstr "ඔබ සතුව තරු යෙදූ ව්â€à¶ºà·à¶´à·˜à¶­à·’ නà·à¶­."
msgid "Starrers"
msgstr ""
@@ -45099,7 +45335,7 @@ msgid "Start another thread"
msgstr ""
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
-msgstr ""
+msgstr "සමූහයක් තේරීමෙන් එහි ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම් ගවේà·à¶±à¶º අරඹන්න. ව්â€à¶ºà·à¶´à·˜à¶­à·’, නම්පත්, සන්ධිස්ථà·à¶± සහ කතුවරුන් අනුව පෙරීමට ද à·„à·à¶šà·’ය."
msgid "Start cleanup"
msgstr ""
@@ -45387,10 +45623,10 @@ msgid "Subgroup milestone"
msgstr ""
msgid "Subgroup navigation"
-msgstr "උප සමූහය යà·à¶­à·Šâ€à¶»à¶«à¶º"
+msgstr "උප සමූහයේ යà·à¶­à·Šâ€à¶»à¶«à¶º"
msgid "SubgroupCreationLevel|Roles allowed to create subgroups"
-msgstr ""
+msgstr "උප සමූහ සෑදීමට à·„à·à¶šà·’ භූමිකà·"
msgid "SubgroupCreationlevel|Allowed to create subgroups"
msgstr "උපසමූහ සෑදීමට ඉඩ ඇත"
@@ -45506,6 +45742,18 @@ msgstr "බලපත්â€à¶ºà¶» භà·à·€à·’ත ගොනුව බà·à¶œà¶±à·Š
msgid "SubscriptionBanner|Upload new license"
msgstr "නව බලපත්â€à¶»à¶º යොදන්න"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr "ආසන එක්කරන්න"
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "වි-තà·à¶´à·‘ල ඉවත් කෙරිණි."
@@ -45671,6 +45922,9 @@ msgstr "තහනම ඉවත් කෙරිණි"
msgid "Successfully unblocked"
msgstr "අනවහිර කෙරිණි"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr "අගුළු à·„à·à¶»à·’ණි"
@@ -45879,7 +46133,7 @@ msgid "SuperSonics|Licensed to"
msgstr ""
msgid "SuperSonics|Maximum users"
-msgstr "උපරිම පරිà·à·“ලකයින්"
+msgstr "උපරිම පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "SuperSonics|Offline license"
msgstr "මà·à¶»à·Šà¶œà¶…පගත බලපත්â€à¶»à¶º"
@@ -46043,7 +46297,7 @@ msgid "Switch branch/tag"
msgstr "à·à·à¶›à·à·€/අනන්â€à¶ºà¶±à¶º මà·à¶»à·”à·€"
msgid "Switch to GitLab Next"
-msgstr "ගිට්ලà·à¶¶à·Š නෙක්â€à·ƒà·Šà¶§à·Š මà·à¶»à·”à·€"
+msgstr "ගිට්ලà·à¶¶à·Š නෙක්â€à·ƒà·Šà¶§à·Š බලන්න"
msgid "Switch to plain text editing"
msgstr ""
@@ -46280,7 +46534,7 @@ msgid "TagsPage|Repository has no tags yet."
msgstr "කà·à·‚්ඨයෙහි තවම අනන්â€à¶ºà¶± නà·à¶­."
msgid "TagsPage|Sorry, your filter produced no results."
-msgstr ""
+msgstr "ඔබගේ පෙරීමට කිසිදු ප්â€à¶»à¶­à·’ඵලයක් නà·à¶­"
msgid "TagsPage|Tags"
msgstr "අනන්â€à¶ºà¶±"
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,8 +46601,14 @@ msgstr "ඉලක්කගත මà·à¶»à·Šà¶œà¶º"
msgid "Target branch"
msgstr "ඉලක්කගත à·à·à¶›à·à·€"
-msgid "Target branch or tag"
-msgstr "ඉලක්කගත à·à·à¶›à·à·€/අනන්â€à¶ºà¶±à¶º"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
+msgstr ""
msgid "Target branch: %{target_branch}"
msgstr ""
@@ -46529,7 +46792,7 @@ msgid "Terraform|Download JSON"
msgstr "JSON බà·à¶œà¶±à·Šà¶±"
msgid "Terraform|Explore documentation"
-msgstr ""
+msgstr "ප්â€à¶»à¶½à·šà¶›à¶±à¶º ගවේà·à¶±à¶º"
msgid "Terraform|Failed to load Terraform reports"
msgstr ""
@@ -46595,7 +46858,7 @@ msgid "Terraform|To remove the State file and its versions, type %{name} to conf
msgstr ""
msgid "Terraform|Unknown User"
-msgstr "නොදන්න෠පරිà·à·“ලකයෙකි"
+msgstr "නොදන්න෠පරිà·à·Šâ€à¶»à·“ලකයෙකි"
msgid "Terraform|Unlock"
msgstr "අගුළු à·„à·à¶»à·“ම"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr "ජෙන්කින්ස් සේවà·à¶¯à·à¶ºà¶šà¶º සඳහ෠මුරපදය."
@@ -47319,10 +47579,10 @@ msgid "The uploaded file was invalid. Supported file extensions are %{extensions
msgstr ""
msgid "The user is being deleted."
-msgstr "පරිà·à·“ලකය෠මක෠දà·à¶¸à·™à¶¸à·’න්."
+msgstr "පරිà·à·Šâ€à¶»à·“ලකය෠මක෠දà·à¶¸à·™à¶¸à·’න්."
msgid "The user map has been saved. Continue by selecting the projects you want to import."
-msgstr "පරිà·à·“ලක සිතියම සුරà·à¶šà·’ණි. ඔබට ආයà·à¶­ කිරීමට අවà·à·Šâ€à¶º ව්â€à¶ºà·à¶´à·˜à¶­à·’ තේරීමෙන් ඉදිරියට යන්න."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක සිතියම සුරà·à¶šà·’ණි. ඔබට ආයà·à¶­ කිරීමට අවà·à·Šâ€à¶º ව්â€à¶ºà·à¶´à·˜à¶­à·’ තේරීමෙන් ඉදිරියට යන්න."
msgid "The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below."
msgstr ""
@@ -47334,7 +47594,7 @@ msgid "The user you are trying to deactivate has been active in the past %{minim
msgstr ""
msgid "The username for the Jenkins server."
-msgstr "ජෙන්කින්ස් සේවà·à¶¯à·à¶ºà¶šà¶º සඳහ෠පරිà·à·“ලක නà·à¶¸à¶º."
+msgstr "ජෙන්කින්ස් සේවà·à¶¯à·à¶ºà¶šà¶º සඳහ෠පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º."
msgid "The value of the provided variable exceeds the %{count} character limit"
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "ඒකà·à¶¶à¶¯à·Šà¶° à¶à¶§à·Šà¶§à¶± තිබේ"
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr "අයà·à¶ à·’ත සටහන් නà·à¶­"
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47517,7 +47777,7 @@ msgid "There was a problem fetching linked pipelines."
msgstr ""
msgid "There was a problem fetching milestones."
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± ලබ෠ගà·à¶±à·“මේ ගà·à¶§à·…ුවක් මතු විය."
msgid "There was a problem fetching project branches."
msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ à·à·à¶›à· ගà·à¶±à·“මේ දී ගà·à¶§à¶½à·”වකි."
@@ -47526,7 +47786,7 @@ msgid "There was a problem fetching project tags."
msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ අනන්â€à¶ºà¶± ගà·à¶±à·“මේ දී ගà·à¶§à¶½à·”වකි."
msgid "There was a problem fetching project users."
-msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ පරිà·à·“ලකයින් ගà·à¶±à·“මේ දී ගà·à¶§à¶½à·”වකි."
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ පරිà·à·Šâ€à¶»à·“ලකයින් ගà·à¶±à·“මේ දී ගà·à¶§à¶½à·”වකි."
msgid "There was a problem fetching recent groups."
msgstr "මෑත සමූහ ගà·à¶±à·“මේ දී ගà·à¶§à¶½à·”වකි."
@@ -47556,7 +47816,7 @@ msgid "There was a problem fetching the projects"
msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ ගà·à¶±à·“මේ දී ගà·à¶§à¶½à·”වකි"
msgid "There was a problem fetching users."
-msgstr "පරිà·à·“ලකයින් ගà·à¶±à·“මේ දී ගà·à¶§à¶½à·”වකි."
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින් ගà·à¶±à·“මේ දී ගà·à¶§à¶½à·”වකි."
msgid "There was a problem handling the pipeline data."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47643,7 +47906,7 @@ msgid "There was an error loading related feature flags"
msgstr ""
msgid "There was an error loading users activity calendar."
-msgstr "පරිà·à·“ලක ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š දිනදසුන පූරණය කිරීමේදී දà·à·‚යකි."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š දිනදසුන පූරණය කිරීමේදී දà·à·‚යකි."
msgid "There was an error parsing the data for this graph."
msgstr ""
@@ -47655,7 +47918,7 @@ msgid "There was an error retrieving LDAP groups. Please try again."
msgstr ""
msgid "There was an error retrieving the Jira users."
-msgstr "ජිර෠පරිà·à·“ලකයින් ලබ෠ගà·à¶±à·“මේ දà·à·‚යකි."
+msgstr "ජිර෠පරිà·à·Šâ€à¶»à·“ලකයින් ලබ෠ගà·à¶±à·“මේ දà·à·‚යකි."
msgid "There was an error running the job. Please try again."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr "අභියà·à¶œà¶ºà·™à·„à·’ දà·à·‚යක් මතු විය. à
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47898,7 +48164,7 @@ msgid "This directory"
msgstr "මෙම නà·à¶¸à·à·€à¶½à·’ය"
msgid "This domain is not verified. You will need to verify ownership before access is enabled."
-msgstr ""
+msgstr "මෙම වසම සත්â€à¶ºà·à¶´à¶±à¶º කර නà·à¶­. ප්â€à¶»à·€à·šà·à¶º සබල කිරීමට පෙර අයිතිය සත්â€à¶ºà·à¶´à¶±à¶ºà¶§ වුවමන෠විය à·„à·à¶šà·’ය."
msgid "This email address does not look right, are you sure you typed it correctly?"
msgstr ""
@@ -47985,7 +48251,7 @@ msgid "This group cannot be invited to a project inside a group with enforced SS
msgstr ""
msgid "This group does not have any group runners yet."
-msgstr ""
+msgstr "මෙම සමූහයේ තවමත් සමූහ ධà·à·€à¶š නà·à¶­."
msgid "This group has been scheduled for permanent removal on %{date}"
msgstr ""
@@ -47994,7 +48260,7 @@ msgid "This group has no active access tokens."
msgstr ""
msgid "This group has no projects yet"
-msgstr ""
+msgstr "මෙම සමූහයේ තවමත් ව්â€à¶ºà·à¶´à·˜à¶­à·’ නà·à¶­"
msgid "This group is linked to a subscription"
msgstr ""
@@ -48021,7 +48287,7 @@ msgid "This is a \"Ghost User\", created to hold all issues authored by users th
msgstr ""
msgid "This is a Jira user."
-msgstr "මේ ජිර෠පරිà·à·“ලකයෙකි."
+msgstr "මේ ජිර෠පරිà·à·Šâ€à¶»à·“ලකයෙකි."
msgid "This is a child pipeline within the parent pipeline"
msgstr ""
@@ -48204,17 +48470,23 @@ msgid "This merge request is closed. To apply this suggestion, edit this file di
msgstr ""
msgid "This merge request is from a private project to a public project."
-msgstr ""
+msgstr "මෙම ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම පෞද්ගලික ව්â€à¶ºà·à¶´à·˜à¶­à·’යකින් ප්â€à¶»à·ƒà·’ද්ධ ව්â€à¶ºà·à¶´à·˜à¶­à·’යකට වේ."
msgid "This merge request is from a private project to an internal project."
-msgstr ""
+msgstr "මෙම ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම පෞද්ගලික ව්â€à¶ºà·à¶´à·˜à¶­à·’යකින් අභ්â€à¶ºà¶±à·Šà¶­à¶» ව්â€à¶ºà·à¶´à·˜à¶­à·’යකට වේ."
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම අගුළු ල෠ඇත."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr "ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම ඒකà·à¶¶à¶¯à·Šà¶°à¶ºà·’. මෙම යà·à¶¢à¶±à·à·€ යෙදීමට, ගොනුව සෘජුව සංස්කරණය කරන්න."
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48423,7 +48695,7 @@ msgid "TierBadgePopover|Enhance team productivity"
msgstr ""
msgid "TierBadgePopover|Explore paid plans"
-msgstr ""
+msgstr "ගෙවන à·ƒà·à¶½à·ƒà·”ම් ගවේà·à¶±à¶º"
msgid "TierBadgePopover|Start a free trial"
msgstr ""
@@ -48512,7 +48784,7 @@ msgstr "වේල෠කලà·à¶´à¶º"
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48624,13 +48896,13 @@ msgid "Timeago|%s weeks ago"
msgstr "සති %s කට පෙර"
msgid "Timeago|%s weeks remaining"
-msgstr ""
+msgstr "සති %s ක් ඉතිරිය"
msgid "Timeago|%s years ago"
-msgstr "අවුරුදු %s කට පෙර"
+msgstr "වසර %s කට පෙර"
msgid "Timeago|%s years remaining"
-msgstr "අවුරුදු %s ක් ඉතිරිය"
+msgstr "වසර %s ක් ඉතිරිය"
msgid "Timeago|1 day ago"
msgstr "දවසකට පෙර"
@@ -48663,52 +48935,52 @@ msgid "Timeago|1 week remaining"
msgstr "සතියක් ඉතිරිය"
msgid "Timeago|1 year ago"
-msgstr "අවුරුද්දකට පෙර"
+msgstr "වසරකට පෙර"
msgid "Timeago|1 year remaining"
-msgstr "අවුරුද්දක් ඉතිරිය"
+msgstr "වසරක් ඉතිරිය"
msgid "Timeago|Past due"
msgstr ""
msgid "Timeago|in %s days"
-msgstr ""
+msgstr "දවස් %s කින්"
msgid "Timeago|in %s hours"
-msgstr ""
+msgstr "පà·à¶º %s කින්"
msgid "Timeago|in %s minutes"
-msgstr ""
+msgstr "විනà·à¶©à·’ %s කින්"
msgid "Timeago|in %s months"
-msgstr ""
+msgstr "මà·à·ƒ %s කින්"
msgid "Timeago|in %s seconds"
-msgstr ""
+msgstr "තත්පර %s කින්"
msgid "Timeago|in %s weeks"
-msgstr ""
+msgstr "සති %s කින්"
msgid "Timeago|in %s years"
-msgstr ""
+msgstr "වසර %s කින්"
msgid "Timeago|in 1 day"
-msgstr ""
+msgstr "දවසකින්"
msgid "Timeago|in 1 hour"
-msgstr ""
+msgstr "පà·à¶ºà¶šà·’න්"
msgid "Timeago|in 1 minute"
-msgstr ""
+msgstr "විනà·à¶©à·’යකින්"
msgid "Timeago|in 1 month"
-msgstr ""
+msgstr "මà·à·ƒà¶ºà¶šà·’න්"
msgid "Timeago|in 1 week"
-msgstr ""
+msgstr "සතියකින්"
msgid "Timeago|in 1 year"
-msgstr ""
+msgstr "වසරකින්"
msgid "Timeago|just now"
msgstr "මේ දà·à¶±à·Š"
@@ -48753,13 +49025,13 @@ msgid "Time|A"
msgstr ""
msgid "Time|AM"
-msgstr ""
+msgstr "පෙ.ව."
msgid "Time|P"
msgstr ""
msgid "Time|PM"
-msgstr ""
+msgstr "ප.ව."
msgid "Time|a"
msgstr ""
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48975,7 +49247,7 @@ msgid "To see this project's operational details, %{linkStart}upgrade its group
msgstr ""
msgid "To see this project's operational details, contact an owner of group %{groupName} to upgrade the plan. You can also remove the project from the dashboard."
-msgstr ""
+msgstr "මෙම ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ මෙහෙයුම් විස්තර බà·à¶½à·“ම සඳහ෠සà·à¶½à·ƒà·”ම උත්à·à·Šâ€à¶»à·šà¶«à·’ කිරීමට %{groupName} සමූහයේ හිමිකරුවෙකු අමතන්න. ඔබට උපකරණ පුවරුවෙන් ව්â€à¶ºà·à¶´à·˜à¶­à·’ය ඉවත් කිරීමට ද à·„à·à¶šà·’ය."
msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:"
msgstr ""
@@ -49020,16 +49292,16 @@ msgid "To view usage, refresh this page in a few minutes."
msgstr ""
msgid "To widen your search, change or remove filters above"
-msgstr ""
+msgstr "ඔබගේ සෙවීම පුළුල් කිරීමට, ඉහත පෙරහන් වෙනස් හ෠ඉවත් කරන්න."
msgid "To widen your search, change or remove filters above."
-msgstr ""
+msgstr "ඔබගේ සෙවීම පුළුල් කිරීමට, ඉහත පෙරහන් වෙනස් හ෠ඉවත් කරන්න."
msgid "To-Do List"
msgstr "කළ-යුතු ලේඛනය"
msgid "To-Do list"
-msgstr ""
+msgstr "කළ-යුතු ලේඛනය"
msgid "To-do item successfully marked as done."
msgstr ""
@@ -49047,7 +49319,7 @@ msgid "Todos|Alert"
msgstr ""
msgid "Todos|Any Action"
-msgstr ""
+msgstr "ඕනෑම ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶ºà¶šà·Š"
msgid "Todos|Any Type"
msgstr ""
@@ -49056,7 +49328,7 @@ msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{op
msgstr ""
msgid "Todos|Assigned"
-msgstr ""
+msgstr "පà·à·€à¶»à·”ණු"
msgid "Todos|Could not merge"
msgstr ""
@@ -49065,13 +49337,13 @@ msgid "Todos|Design"
msgstr ""
msgid "Todos|Due %{due_date}"
-msgstr ""
+msgstr "%{due_date} ට නියමිතය"
msgid "Todos|Epic"
msgstr ""
msgid "Todos|Filter by author"
-msgstr "කතෘට අනුව පෙරන්න"
+msgstr "කර්තෘ අනුව පෙරන්න"
msgid "Todos|Filter by group"
msgstr "සමූහය අනුව පෙරන්න"
@@ -49083,13 +49355,13 @@ msgid "Todos|Give yourself a pat on the back!"
msgstr ""
msgid "Todos|Good job! Looks like you don't have anything left on your To-Do List"
-msgstr ""
+msgstr "කදිමයි! ඔබගේ කළ-යුතු ලà·à¶ºà·’ස්තුවේ කිසිවක් ඉතිරි වී නà·à¶­à·’ බව පෙනෙයි"
msgid "Todos|Henceforth, you shall be known as \"To-Do Destroyer\""
msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
-msgstr ""
+msgstr "හිස් කළ-යුතු ලà·à¶ºà·’ස්තුවක් ලස්සනයි නේද?"
msgid "Todos|Issue"
msgstr ""
@@ -49104,13 +49376,13 @@ msgid "Todos|Member access requested"
msgstr ""
msgid "Todos|Mentioned"
-msgstr ""
+msgstr "à·ƒà·à¶³à·„ුම්"
msgid "Todos|Merge request"
msgstr ""
msgid "Todos|Nothing is on your to-do list. Nice work!"
-msgstr ""
+msgstr "ඔබගේ කළ-යුතු ලà·à¶ºà·’ස්තුවේ කිසිවක් නà·à¶­. කදිමයි!"
msgid "Todos|Nothing left to do. High five!"
msgstr ""
@@ -49122,7 +49394,7 @@ msgid "Todos|Removed from Merge Train"
msgstr ""
msgid "Todos|Review requested"
-msgstr ""
+msgstr "සමà·à¶½à·à¶ à¶±à¶ºà¶šà·Š ඉල්ලූ"
msgid "Todos|The pipeline failed"
msgstr ""
@@ -49137,10 +49409,10 @@ msgid "Todos|You're all done!"
msgstr "සියල්ල අහවරයි!"
msgid "Todos|Your To-Do List shows what to work on next"
-msgstr ""
+msgstr "ඔබගේ කළ-යුතු ලà·à¶ºà·’ස්තුවේ ඊළඟ කà·à¶»à·Šà¶ºà¶±à·Š පෙන්වයි"
msgid "Todos|added a to-do item"
-msgstr ""
+msgstr "කළ-යුතු අථකයක් එක් කර ඇත"
msgid "Todos|has requested access to %{what} %{which}"
msgstr ""
@@ -49149,10 +49421,10 @@ msgid "Todos|mentioned %{who}"
msgstr ""
msgid "Todos|requested a review"
-msgstr ""
+msgstr "සමà·à¶½à·à¶ à¶±à¶ºà¶šà·Š ඉල්ල෠ඇත"
msgid "Todos|reviewed your merge request"
-msgstr ""
+msgstr "ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම සමà·à¶½à·à¶ à¶±à¶º කර ඇත"
msgid "Todos|set %{who} as an approver"
msgstr ""
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "හෙට"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49245,7 +49520,7 @@ msgid "Too many projects enabled. Manage them through the console or the API."
msgstr ""
msgid "Too many references. Quick actions are limited to at most %{max_count} user references"
-msgstr ""
+msgstr "සමුද්දේ෠බොහà·à¶º. ඉක්මන් ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œ ආසන්නව පරිà·à·Šâ€à¶»à·“ලක සමුද්දේ෠%{max_count} කට සීම෠වේ"
msgid "Too many results to display. Edit your search or add a filter."
msgstr ""
@@ -49295,7 +49570,7 @@ msgstr[0] ""
msgstr[1] ""
msgid "TopicSelect|No matching results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "TopicSelect|Search topics"
msgstr "මà·à¶­à·˜à¶šà· සොයන්න"
@@ -49318,6 +49593,9 @@ msgstr "මුළු"
msgid "Total Score"
msgstr "මුළු ලකුණු"
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49331,7 +49609,7 @@ msgid "Total test time for all commits/merges"
msgstr ""
msgid "Total users"
-msgstr "මුළු පරිà·à·“ලකයින්"
+msgstr "මුළු පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "Total weight"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr "1000+"
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49442,7 +49738,7 @@ msgid "Track important events in your GitLab instance."
msgstr ""
msgid "Track important events in your group."
-msgstr ""
+msgstr "ඔබගේ සමූහයේ à·€à·à¶¯à¶œà¶­à·Š සිදුවීම් ලුහුබඳින්න."
msgid "Track important events in your project."
msgstr ""
@@ -49541,7 +49837,7 @@ msgid "Trials|Compare all plans"
msgstr "සියළු à·ƒà·à¶½à·ƒà·”ම් සසඳන්න"
msgid "Trials|Create a new group to start your GitLab Ultimate trial."
-msgstr ""
+msgstr "ඔබගේ ගිට්ලà·à¶¶à·Š අල්ටිමේට් නà·à·„à·à·ƒà·”ම ඇරඹීමට නව සමූහයක් à·ƒà·à¶¯à¶±à·Šà¶±."
msgid "Trials|Day %{daysUsed}/%{duration}"
msgstr "දවස් %{daysUsed}/%{duration}"
@@ -49556,7 +49852,7 @@ msgid "Trials|With GitLab Ultimate you can detect and address vulnerabilities in
msgstr ""
msgid "Trials|You can apply your trial to a new group or an existing group."
-msgstr ""
+msgstr "ඔබගේ නà·à·„à·à·ƒà·”ම නව සමූහයකට හ෠පවතින සමූහයකට යෙදීමට à·„à·à¶šà·’ය."
msgid "Trials|You've got %{daysRemaining} day remaining on GitLab %{planName}!"
msgid_plural "Trials|You've got %{daysRemaining} days remaining on GitLab %{planName}!"
@@ -49786,13 +50082,10 @@ msgid "URL or request ID"
msgstr "ඒ.à·ƒ.නි. / ඉල්ලීම් à·„à·à¶³à·”."
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
-msgstr "පරිà·à·“ලක %{user_name} ඉවත් කරනු ලà·à¶¶à·š! ඔබට විà·à·Šà·€à·à·ƒà¶¯?"
-
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "පරිà·à·“ලක %{user} ඉවත් කරනු ලà·à¶¶à·š! ඔබට විà·à·Šà·€à·à·ƒà¶¯?"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක %{user_name} ඉවත් කරනු ලà·à¶¶à·š! ඔබට විà·à·Šà·€à·à·ƒà¶¯?"
msgid "USER WILL BE BLOCKED! Are you sure?"
-msgstr "පරිà·à·“ලකය෠අවහිර කරනු ඇත! ඔබට විà·à·Šà·€à·à·ƒà¶¯?"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකය෠අවහිර කරනු ඇත! ඔබට විà·à·Šà·€à·à·ƒà¶¯?"
msgid "UTC"
msgstr "UTC"
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49897,7 +50193,7 @@ msgid "Unable to schedule a pipeline to run immediately"
msgstr ""
msgid "Unable to sign you in to the group with SAML due to \"%{reason}\""
-msgstr ""
+msgstr "\"%{reason}\" හේතුවෙන් SAML මගින් සමූහයට පිවිසීමට නොහà·à¶šà·’ විය"
msgid "Unable to suggest a path. Please refresh and try again."
msgstr "මà·à¶»à·Šà¶œà¶ºà¶šà·Š යà·à¶¢à¶±à· කළ නොහà·à¶šà·’ය. නà·à·€à·”ම් කර බලන්න."
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr "පුද්ගලය෠තහවුරු කළ නොහà·à¶šà·’ය"
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49933,7 +50226,7 @@ msgid "Unassign from commenting user"
msgstr ""
msgid "Unassigned"
-msgstr ""
+msgstr "පවර෠නà·à¶­"
msgid "Unauthenticated API rate limit period in seconds"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr "අසතුටුයිද?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50020,7 +50316,7 @@ msgid "Unknown response text"
msgstr "නොදන්න෠ප්â€à¶»à¶­à·’චà·à¶» පෙළ"
msgid "Unknown user"
-msgstr "නොදන්න෠පරිà·à·“ලකයෙකි"
+msgstr "නොදන්න෠පරිà·à·Šâ€à¶»à·“ලකයෙකි"
msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
msgstr ""
@@ -50182,7 +50478,7 @@ msgid "Update approvers"
msgstr "අනුමතකරුවන් යà·à·€à¶­à·Šà¶šà·à¶½à¶º"
msgid "Update failed"
-msgstr "යà·à·€à¶­à·Šà¶šà·à¶½à¶º අසමත්!"
+msgstr "යà·à·€à¶­à·Šà¶šà·à¶½ නොවිණි!"
msgid "Update it"
msgstr "එය යà·à·€à¶­à·Šà¶šà·à¶½ කරන්න"
@@ -50191,7 +50487,7 @@ msgid "Update now"
msgstr "දà·à¶±à·Š යà·à·€à¶­à·Šà¶šà·à¶½ කරන්න"
msgid "Update username"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º යà·à·€à¶­à·Šà¶šà·à¶½ කරන්න"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º යà·à·€à¶­à·Šà¶šà·à¶½ කරන්න"
msgid "Update variable"
msgstr ""
@@ -50227,7 +50523,7 @@ msgid "UpdateProject|Could not set the default branch. Do you have a branch name
msgstr ""
msgid "UpdateProject|Learn more."
-msgstr ""
+msgstr "තව දà·à¶±à¶œà¶±à·Šà¶±"
msgid "UpdateProject|New visibility level not allowed!"
msgstr ""
@@ -50290,7 +50586,7 @@ msgid "Upload a certificate for your domain with all intermediates"
msgstr ""
msgid "Upload a private key for your certificate"
-msgstr ""
+msgstr "ඔබගේ සහතිකය සඳහ෠පෞද්. යතුරක් උඩුගත කරන්න"
msgid "Upload could not be deleted."
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr "ආචයනය මිලදී ගන්න"
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr "පරà·à¶ºà¶­à·Šà¶­ ප්â€à¶»à¶­à·’යුක්තය"
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -50665,7 +50967,7 @@ msgid "UsageTrends|Total projects & groups"
msgstr "මුළු ව්â€à¶ºà·à¶´à·˜à¶­à·’ හ෠සමූහ"
msgid "UsageTrends|Users"
-msgstr "පරිà·à·“ලකයින්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "Use %{code_start}::%{code_end} to create a %{link_start}scoped label set%{link_end} (eg. %{code_start}priority::1%{code_end})"
msgstr ""
@@ -50793,7 +51095,7 @@ msgid "Used to help configure your identity provider"
msgstr ""
msgid "User"
-msgstr "පරිà·à·“ලක"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක"
msgid "User %{current_user_username} has started impersonating %{username}"
msgstr ""
@@ -50811,19 +51113,19 @@ msgid "User %{user} was removed from %{group}."
msgstr ""
msgid "User ID"
-msgstr "පරිà·à·“ලක à·„à·à¶³à·”."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·„à·à¶³à·”."
msgid "User OAuth applications"
msgstr ""
msgid "User Settings"
-msgstr "පරිà·à·“ලක à·ƒà·à¶šà·ƒà·”ම්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·ƒà·à¶šà·ƒà·”ම්"
msgid "User Status"
msgstr ""
msgid "User and IP rate limits"
-msgstr "පරිà·à·“ලක හ෠අ.ජà·.කෙ. අනුපà·à¶­ සීමà·"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක හ෠අ.ජà·.කෙ. අනුපà·à¶­ සීමà·"
msgid "User cap"
msgstr ""
@@ -50850,13 +51152,13 @@ msgid "User has already been deactivated"
msgstr ""
msgid "User identity was successfully created."
-msgstr "පරිà·à·“ලකයà·à¶œà·š අනන්â€à¶ºà¶­à·à·€à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ සෑදිණි."
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶œà·š අනන්â€à¶ºà¶­à·à·€à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ සෑදිණි."
msgid "User identity was successfully removed."
-msgstr "පරිà·à·“ලකයà·à¶œà·š අනන්â€à¶ºà¶­à·à·€à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ ඉවත් කෙරිණි."
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶œà·š අනන්â€à¶ºà¶­à·à·€à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ ඉවත් කෙරිණි."
msgid "User identity was successfully updated."
-msgstr "පරිà·à·“ලකයà·à¶œà·š අනන්â€à¶ºà¶­à·à·€à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ යà·à·€à¶­à·Šà¶šà·à¶½ කෙරිණි."
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶œà·š අනන්â€à¶ºà¶­à·à·€à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ යà·à·€à¶­à·Šà¶šà·à¶½ කෙරිණි."
msgid "User is blocked"
msgstr ""
@@ -50865,16 +51167,16 @@ msgid "User is not allowed to resolve thread"
msgstr ""
msgid "User key"
-msgstr "පරිà·à·“ලක යතුර"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක යතුර"
msgid "User key was successfully removed."
-msgstr "පරිà·à·“ලකයà·à¶œà·š යතුර à·ƒà·à¶»à·Šà¶®à¶šà·€ ඉවත් කෙරිණි."
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයà·à¶œà·š යතුර à·ƒà·à¶»à·Šà¶®à¶šà·€ ඉවත් කෙරිණි."
msgid "User list %{name} will be removed. Are you sure?"
msgstr ""
msgid "User map"
-msgstr "පරිà·à·“ලක සිතියම"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක සිතියම"
msgid "User pipeline minutes were successfully reset."
msgstr ""
@@ -50883,7 +51185,7 @@ msgid "User restrictions"
msgstr ""
msgid "User settings"
-msgstr "පරිà·à·“ලක à·ƒà·à¶šà·ƒà·”ම්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·ƒà·à¶šà·ƒà·”ම්"
msgid "User was successfully banned."
msgstr ""
@@ -50910,16 +51212,16 @@ msgid "User-based escalation rules must have a user with access to the project"
msgstr ""
msgid "UserAvailability|%{author}%{badgeStart}Busy%{badgeEnd}"
-msgstr ""
+msgstr "%{author}%{badgeStart}කà·à¶»à·Šà¶ºà¶¶à·„ුලයි%{badgeEnd}"
msgid "UserLists|Add"
msgstr "එකතු"
msgid "UserLists|Add Users"
-msgstr "පරිà·à·“ලකයින් එක්කරන්න"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින් එක්කරන්න"
msgid "UserLists|Add users"
-msgstr "පරිà·à·“ලකයින් එක්කරන්න"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින් එක්කරන්න"
msgid "UserLists|Cancel"
msgstr "අවලංගු කරන්න"
@@ -50964,16 +51266,16 @@ msgid "UserLists|Save"
msgstr "සුරකින්න"
msgid "UserLists|There are no users"
-msgstr "පරිà·à·“ලකයින් නà·à¶­"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින් නà·à¶­"
msgid "UserLists|There was an error fetching the user lists."
msgstr ""
msgid "UserLists|User ID"
-msgstr "පරිà·à·“ලක à·„à·à¶³à·”."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·„à·à¶³à·”."
msgid "UserLists|User IDs"
-msgstr "පරිà·à·“ලක à·„à·à¶³à·”."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·„à·à¶³à·”."
msgid "UserLists|User Lists"
msgstr "පුද්ගල ලේඛන"
@@ -51009,19 +51311,19 @@ msgid "UserProfile|An error occurred loading the personal projects. Please refre
msgstr ""
msgid "UserProfile|Blocked user"
-msgstr "අවහිර කළ පරිà·à·“ලක"
+msgstr "අවහිර කළ පරිà·à·Šâ€à¶»à·“ලක"
msgid "UserProfile|Bot activity"
msgstr "ස්වයංක්â€à¶»à¶¸à¶½à·šà¶›à¶ºà·š ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸"
msgid "UserProfile|Busy"
-msgstr ""
+msgstr "කà·à¶»à·Šà¶ºà¶¶à·„ුලයි"
msgid "UserProfile|Contributed projects"
msgstr "දà·à¶ºà¶š වූ ව්â€à¶ºà·à¶´à·˜à¶­à·’"
msgid "UserProfile|Copy user ID"
-msgstr "පරිà·à·“ලක à·„à·à¶³à·”. පිටපතක්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·„à·à¶³à·”. පිටපතක්"
msgid "UserProfile|Copy user ID: %{id}"
msgstr ""
@@ -51096,37 +51398,37 @@ msgid "UserProfile|This user doesn't have any followers"
msgstr ""
msgid "UserProfile|This user doesn't have any followers."
-msgstr "මෙම පරිà·à·“ලකයà·à¶§ අනුගà·à¶¸à·’කයින් නà·à¶­."
+msgstr "මෙම පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ අනුගà·à¶¸à·’කයින් නà·à¶­."
msgid "UserProfile|This user doesn't have any snippets"
msgstr ""
msgid "UserProfile|This user has a private profile"
-msgstr "මෙම පරිà·à·“ලකයà·à¶§ පුද්ගලික පà·à¶­à·’කඩක් ඇත"
+msgstr "මෙම පරිà·à·Šâ€à¶»à·“ලකයà·à¶§ පුද්ගලික පà·à¶­à·’කඩක් ඇත"
msgid "UserProfile|This user hasn't contributed to any projects"
-msgstr "මෙම පරිà·à·“ලකය෠කිසිදු ව්â€à¶ºà·à¶´à·˜à¶­à·’යකට දà·à¶ºà¶š වී නà·à¶­"
+msgstr "මෙම පරිà·à·Šâ€à¶»à·“ලකය෠කිසිදු ව්â€à¶ºà·à¶´à·˜à¶­à·’යකට දà·à¶ºà¶š වී නà·à¶­"
msgid "UserProfile|This user hasn't starred any projects"
msgstr "මෙම පුද්ගලය෠කිසිදු ව්â€à¶ºà·à¶´à·˜à¶­à·’යකට තරු යොද෠නà·à¶­"
msgid "UserProfile|This user is blocked"
-msgstr "මෙම පරිà·à·“ලකය෠අවහිර කර ඇත"
+msgstr "මෙම පරිà·à·Šâ€à¶»à·“ලකය෠අවහිර කර ඇත"
msgid "UserProfile|This user isn't following other users"
msgstr ""
msgid "UserProfile|This user isn't following other users."
-msgstr "මෙම පුද්ගලය෠වෙනත් පරිà·à·“ලකයින් අනුගමනය නොකරයි."
+msgstr "මෙම පුද්ගලය෠වෙනත් පරිà·à·Šâ€à¶»à·“ලකයින් අනුගමනය නොකරයි."
msgid "UserProfile|Unconfirmed user"
-msgstr "තහවුරු නොකළ පරිà·à·“ලක"
+msgstr "තහවුරු නොකළ පරිà·à·Šâ€à¶»à·“ලක"
msgid "UserProfile|User ID copied to clipboard"
msgstr ""
msgid "UserProfile|User ID: %{id}"
-msgstr "පරිà·à·“ලක à·„à·à¶³à·”.: %{id}"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක à·„à·à¶³à·”.: %{id}"
msgid "UserProfile|User profile navigation"
msgstr ""
@@ -51141,7 +51443,7 @@ msgid "UserProfile|You are not following other users"
msgstr ""
msgid "UserProfile|You are not following other users."
-msgstr "ඔබ වෙනත් පරිà·à·“ලකයින් අනුගමනය නොකරයි."
+msgstr "ඔබ වෙනත් පරිà·à·Šâ€à¶»à·“ලකයින් අනුගමනය නොකරයි."
msgid "UserProfile|You can create a group for several dependent projects."
msgstr ""
@@ -51159,7 +51461,7 @@ msgid "UserProfile|You haven't created any snippets."
msgstr ""
msgid "UserProfile|Your projects can be available publicly, internally, or privately, at your choice."
-msgstr ""
+msgstr "ඔබගේ අභිමතය පරිදි ප්â€à¶»à·ƒà·’ද්ධියේ, අභ්â€à¶ºà¶±à·Šà¶­à¶»à·€ හ෠පුද්ගලිකව ඔබගේ ව්â€à¶ºà·à¶´à·˜à¶­à·’ තබ෠ගà·à¶±à·“මට à·„à·à¶šà·’ය."
msgid "UserProfile|at"
msgstr ""
@@ -51171,28 +51473,31 @@ msgid "UserProfile|updated %{updated}"
msgstr ""
msgid "Username"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º"
msgid "Username (optional)"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º (විකල්ප)"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º (විකල්ප)"
msgid "Username is already taken."
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º ගෙන ඇත."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º ගෙන ඇත."
msgid "Username is available."
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º තිබේ."
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º තිබේ."
msgid "Username or email"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º හ෠වි-තà·à¶´à·‘ල"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º හ෠වි-තà·à¶´à·‘ල"
+
+msgid "Username or primary email"
+msgstr ""
msgid "Username:"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º:"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º:"
msgid "Username: %{username}"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º: %{username}"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º: %{username}"
msgid "Users"
-msgstr "පරිà·à·’ලකයින්"
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "Users API rate limit"
msgstr ""
@@ -51210,13 +51515,13 @@ msgid "Users can request access (if visibility is public or internal)"
msgstr ""
msgid "Users can select 'Remember me' on sign-in to keep their session active beyond the session duration. %{link_start}Learn more.%{link_end}"
-msgstr ""
+msgstr "පරිà·à·Šâ€à¶»à·“ලකයින්ට ඔවුන්ගේ à·€à·à¶» සම්මත කà·à¶½à¶ºà·™à¶±à·Š ඔබ්බට සක්â€à¶»à·’යව තබ෠ගà·à¶±à·“මට පිවිසීමේදී 'මතක තබ෠ගන්න' තේරීමට à·„à·à¶šà·’ය. %{link_start}තව දà·à¶±à¶œà¶±à·Šà¶±.%{link_end}"
msgid "Users cannot be added to projects in this group"
-msgstr ""
+msgstr "මෙම සමූහයේ ව්â€à¶ºà·à¶´à·˜à¶­à·’ වෙත පරිà·à·Šâ€à¶»à·“ලකයින් එක් කිරීමට නොහà·à¶šà·’ය"
msgid "Users in License"
-msgstr "බලපත්â€à¶»à¶ºà·™à·„à·’ පරිà·à·“ලකයින්"
+msgstr "බලපත්â€à¶»à¶ºà·™à·„à·’ පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
@@ -51228,7 +51533,7 @@ msgid "Users requesting access to"
msgstr ""
msgid "Users to exclude from the rate limit"
-msgstr "අනුපà·à¶­ සීමà·à·€à·™à¶±à·Š බà·à·„à·à¶» කිරීමට පරිà·à·“ලකයින්"
+msgstr "අනුපà·à¶­ සීමà·à·€à·™à¶±à·Š බà·à·„à·à¶» කිරීමට පරිà·à·Šâ€à¶»à·“ලකයින්"
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
@@ -51237,16 +51542,16 @@ msgid "UsersSelect|%{name} + %{length} more"
msgstr "%{name} + තවත් %{length}"
msgid "UsersSelect|Any User"
-msgstr "ඕනෑම පරිà·à·“ලකයෙකු"
+msgstr "ඕනෑම පරිà·à·Šâ€à¶»à·“ලකයෙකු"
msgid "UsersSelect|Assignee"
msgstr ""
msgid "UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}"
-msgstr ""
+msgstr "පවර෠නà·à¶­ - %{openingTag} ඔබට පවර෠ගන්න %{closingTag}"
msgid "UsersSelect|Unassigned"
-msgstr ""
+msgstr "පවර෠නà·à¶­"
msgid "User|Data Analyst"
msgstr ""
@@ -51704,7 +52009,7 @@ msgid "View members"
msgstr ""
msgid "View milestones"
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± බලන්න"
msgid "View on %{url}"
msgstr "%{url} හි බලන්න"
@@ -51754,7 +52059,7 @@ msgid "View usage details"
msgstr "භà·à·€à·’ත විස්තර බලන්න"
msgid "View users statistics"
-msgstr "පරිà·à·“ලක සංඛ්â€à¶ºà·à¶½à·šà¶›à¶± බලන්න"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක සංඛ්â€à¶ºà·à¶½à·šà¶›à¶± බලන්න"
msgid "Viewed"
msgstr ""
@@ -51787,7 +52092,7 @@ msgid "VisibilityLevel|Internal"
msgstr ""
msgid "VisibilityLevel|Private"
-msgstr ""
+msgstr "පෞද්ගලික"
msgid "VisibilityLevel|Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group."
msgstr ""
@@ -51888,9 +52193,12 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
-msgid "VulnerabilityExport|Group Name"
+msgid "VulnerabilityExport|Full Path"
msgstr ""
+msgid "VulnerabilityExport|Group Name"
+msgstr "සමූහයේ නම"
+
msgid "VulnerabilityExport|Location"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52021,7 +52332,7 @@ msgid "VulnerabilityManagement|Something went wrong while trying to unlink the i
msgstr ""
msgid "VulnerabilityManagement|Something went wrong, could not get user."
-msgstr "යම් දෙයක් à·€à·à¶»à¶¯à·“ ඇත, පරිà·à·“ලකය෠ගà·à¶±à·“මට නොහà·à¶šà·’ විය."
+msgstr "යම් දෙයක් à·€à·à¶»à¶¯à·“ ඇත, පරිà·à·Šâ€à¶»à·“ලකය෠ගà·à¶±à·“මට නොහà·à¶šà·’ විය."
msgid "VulnerabilityManagement|Something went wrong, could not update vulnerability state."
msgstr ""
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr "ගිට්ලà·à¶¶à·Š ආරක්â€à·‚ණ à·€à·à¶»à·Šà¶­à·à·€"
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr "නිකුතු සිදුවීම්"
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr "SSL සත්â€à¶ºà·à¶´à¶±à¶º"
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr "ආයුබà·à·€à¶±à·Š, %{name}!"
-msgid "What are group audit events?"
-msgstr "සමූහ විගණන සිදුවීම් යනු මොනවà·à¶¯?"
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ විගණන සිදුවීම් යනු මොනවà·à¶¯?"
-
msgid "What are some examples?"
msgstr ""
@@ -53104,7 +53415,7 @@ msgid "Work Item type with id %{id} was not found"
msgstr ""
msgid "Work in progress (open and unassigned)"
-msgstr ""
+msgstr "à·€à·à¶© කෙරෙමින් පවතී (විවෘත හ෠පවර෠නà·à¶­)"
msgid "Work in progress limit"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53149,7 +53466,7 @@ msgid "WorkItem|Add assignees"
msgstr ""
msgid "WorkItem|Add due date"
-msgstr ""
+msgstr "නියමිත දිනයක් යොදන්න"
msgid "WorkItem|Add start date"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53220,14 +53534,11 @@ msgid "WorkItem|Discard changes"
msgstr ""
msgid "WorkItem|Due date"
-msgstr ""
+msgstr "නියමිත දිනය"
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr "සන්ධිස්ථà·à¶±à¶º"
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53262,7 +53579,7 @@ msgid "WorkItem|No iteration"
msgstr ""
msgid "WorkItem|No matching results"
-msgstr ""
+msgstr "ගà·à·…පෙන ප්â€à¶»à¶­à·’ඵල නà·à¶­"
msgid "WorkItem|No milestone"
msgstr "සන්ධිස්ථà·à¶± නà·à¶­"
@@ -53352,7 +53669,7 @@ msgid "WorkItem|Something went wrong while copying the %{workItemType} reference
msgstr ""
msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
-msgstr ""
+msgstr "සන්ධිස්ථà·à¶± ලබ෠ගà·à¶±à·“මේදී යමක් à·€à·à¶»à¶¯à·“ ඇත. නà·à·€à¶­ උත්සà·à·„ කරන්න."
msgid "WorkItem|Something went wrong while fetching work item award emojis. Please try again."
msgstr ""
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53427,79 +53741,79 @@ msgid "WorkItem|You're only seeing %{boldStart}other activity%{boldEnd} in the f
msgstr ""
msgid "Workspaces"
-msgstr ""
+msgstr "à·€à·à¶©à¶¶à·’ම්"
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
-msgstr ""
+msgstr "අවලංගු"
msgid "Workspaces|Could not load workspaces"
-msgstr ""
+msgstr "à·€à·à¶©à¶¶à·’ම් පූරණයට නොහà·à¶šà·’ විය"
msgid "Workspaces|Could not retrieve cluster agents for this project"
msgstr ""
msgid "Workspaces|Create workspace"
-msgstr ""
+msgstr "à·€à·à¶©à¶¶à·’ම à·ƒà·à¶¯à¶±à·Šà¶±"
msgid "Workspaces|Creating"
-msgstr ""
+msgstr "සෑදෙමින්"
msgid "Workspaces|Develop anywhere"
msgstr ""
msgid "Workspaces|Error"
-msgstr ""
+msgstr "දà·à·‚යකි"
msgid "Workspaces|Failed"
-msgstr ""
+msgstr "අසමත් විය"
msgid "Workspaces|Failed to create workspace"
-msgstr ""
+msgstr "à·€à·à¶©à¶¶à·’ම සෑදීමට අසමත් විය"
msgid "Workspaces|Failed to update workspace"
-msgstr ""
+msgstr "à·€à·à¶©à¶¶à·’ම යà·à·€à¶­à·Šà¶šà·à¶½ කිරීමට අසමත් විය"
msgid "Workspaces|GitLab Workspaces is a powerful collaborative platform that provides a comprehensive set of tools for software development teams to manage their entire development lifecycle."
msgstr ""
msgid "Workspaces|New workspace"
-msgstr ""
+msgstr "නව à·€à·à¶©à¶¶à·’ම"
msgid "Workspaces|Restart"
-msgstr ""
+msgstr "යළි අරඹන්න"
msgid "Workspaces|Restarting"
-msgstr ""
+msgstr "යළි ඇරඹෙමින්"
msgid "Workspaces|Running"
-msgstr ""
+msgstr "ධà·à·€à¶±à¶º වෙමින්"
msgid "Workspaces|Select cluster agent"
msgstr ""
msgid "Workspaces|Select default editor"
-msgstr ""
+msgstr "පෙරනිමි සංස්කරකය තà·à¶»à¶±à·Šà¶±"
msgid "Workspaces|Select project"
-msgstr ""
+msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් තà·à¶»à¶±à·Šà¶±"
msgid "Workspaces|Start"
-msgstr ""
+msgstr "අරඹන්න"
msgid "Workspaces|Starting"
-msgstr ""
+msgstr "ඇරඹෙමින්"
msgid "Workspaces|Stop"
-msgstr ""
+msgstr "නවතන්න"
msgid "Workspaces|Stopped"
-msgstr ""
+msgstr "නà·à·€à¶­à·“ ඇත"
msgid "Workspaces|Stopping"
-msgstr ""
+msgstr "නà·à·€à¶­à·™à¶¸à·’න්"
msgid "Workspaces|Terminate"
msgstr ""
@@ -53523,19 +53837,16 @@ msgid "Workspaces|Unable to load current Workspaces. Please try again or contact
msgstr ""
msgid "Workspaces|Unknown state"
-msgstr ""
+msgstr "නොදන්න෠තත්â€à·€à¶ºà¶šà·’"
msgid "Workspaces|Workspaces"
-msgstr ""
-
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
+msgstr "à·€à·à¶©à¶¶à·’ම්"
msgid "Workspaces|You can't create a workspace for this project"
-msgstr ""
+msgstr "මෙම ව්â€à¶ºà·à¶´à·˜à¶­à·’ය සඳහ෠ඔබට à·€à·à¶©à¶¶à·’මක් සෑදීමට නොහà·à¶šà·’ිය"
msgid "Workspaces|Your workspaces"
-msgstr ""
+msgstr "ඔබගේ à·€à·à¶©à¶¶à·’ම්"
msgid "Would you like to create a new branch?"
msgstr "ඔබ නව à·à·à¶›à·à·€à¶šà·Š සෑදීමට කà·à¶¸à¶­à·’ද?"
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr "%{link} වෙත පිවිසීමෙන් නව SSH යතුරක් සෑදීමට à·„à·à¶šà·’ය"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr "ඔබට නව එකක් සෑදීමට හ෠ඔබගේ %{s
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr "ඔබට නව එකක් සෑදීමට හ෠ඔබගේ SSH යතුරු à·ƒà·à¶šà·ƒà·”ම් %{ssh_key_link} තුළ පරීක්â€à·‚෠කළ à·„à·à¶šà·’ය."
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53948,7 +54265,7 @@ msgid "You currently have no custom domains."
msgstr ""
msgid "You do not belong to any groups yet."
-msgstr ""
+msgstr "ඔබ කිසිදු සමූහයකට අයත් නà·à¶­."
msgid "You do not belong to any projects yet."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr "ඔබ සතුව විවෘත ඒකà·à¶¶à¶¯à·Šà¶° ඉල්ලීම් නà·à¶­"
@@ -54008,7 +54322,7 @@ msgid "You don't have any recent searches"
msgstr "ඔබ සතුව මෑත සෙවීම් නà·à¶­"
msgid "You don't have permission to approve this deployment. Contact the project or group owner for help."
-msgstr ""
+msgstr "ඔබට මෙම යෙදවීම අනුමà·à¶­à·’යට අවසර නà·à¶­. උදව් සඳහ෠ව්â€à¶ºà·à¶´à·˜à¶­à·’යේ හ෠සමූහයේ හිමිකරු අමතන්න."
msgid "You don't have permission to view this epic"
msgstr ""
@@ -54354,7 +54668,7 @@ msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{nam
msgstr ""
msgid "Your Activity"
-msgstr ""
+msgstr "ඔබගේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š"
msgid "Your CI/CD configuration syntax is invalid. Select the Validate tab for more details."
msgstr ""
@@ -54489,7 +54803,7 @@ msgid "Your action succeeded."
msgstr "ඔබගේ ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º à·ƒà·à¶»à·Šà¶®à¶šà¶ºà·’."
msgid "Your activity"
-msgstr ""
+msgstr "ඔබගේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š"
msgid "Your applications"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "ඔබගේ බලයලත් යෙදුම්"
-msgid "Your browser does not support iFrames"
-msgstr "ඔබගේ අතිරික්සුව අයිෆ්රේම්ස් සඳහ෠සහය නොදක්වයි"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr "ඔබගේ පà·à¶­à·’කඩ"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "ඔබගේ ව්â€à¶ºà·à¶´à·˜à¶­à·’ සීමà·à·€ %{limit} කි! එය à·€à·à¶©à·’ කිරීමට ඔබගේ පරිපà·à¶½à¶š අමතන්න"
@@ -54646,6 +54954,9 @@ msgstr "ඔබගේ අවà·à·Šâ€à¶ºà¶­à· ආයà·à¶­ වෙමින්. à
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr "ඔබගේ අවà·à·Šâ€à¶ºà¶­à· පසුබිමින් ආයà·à¶­ කෙරේ. අවසන් වූ පසු, තහවුරු කිරීමේ වි-තà·à¶´à·‘ලක් ලà·à¶¶à·™à¶±à·” ඇත."
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54682,10 +54993,10 @@ msgid "Your update failed. You must upload a file with the same file name when d
msgstr ""
msgid "Your username is %{username}."
-msgstr "ඔබගේ පරිà·à·“ලක නà·à¶¸à¶º %{username}."
+msgstr "ඔබගේ පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º %{username}."
msgid "Your work"
-msgstr "ඔබගේ à·€à·à¶©à¶º"
+msgstr "ඔබගේ à·€à·à¶©"
msgid "Your work items are being imported. Once finished, you'll receive a confirmation email."
msgstr ""
@@ -54697,10 +55008,10 @@ msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao,
msgstr ""
msgid "ZenTaoIntegration|This is a ZenTao user."
-msgstr "මේ සෙන්ටà·à¶• පරිà·à·“ලකයෙකි."
+msgstr "මේ සෙන්ටà·à¶• පරිà·à·Šâ€à¶»à·“ලකයෙකි."
msgid "ZenTaoIntegration|ZenTao user"
-msgstr "සෙන්ටà·à¶• පරිà·à·“ලකයà·"
+msgstr "සෙන්ටà·à¶• පරිà·à·Šâ€à¶»à·“ලකයà·"
msgid "ZentaoIntegration|An error occurred while requesting data from the ZenTao service."
msgstr "සෙන්ටà·à¶• සේවයෙන් දත්ත ඉල්ලීමේදී දà·à·‚යක් සිදු විය."
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54854,7 +55168,7 @@ msgid "artifacts"
msgstr ""
msgid "assign yourself"
-msgstr ""
+msgstr "ඔබට පවරà·à¶œà¶±à·Šà¶±"
msgid "assigned"
msgstr "පà·à·€à¶»à·”ණු"
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr "මෙම සම්පතට à·ƒà·à¶šà·ƒà·“මට නොහà·à¶šà·’ය"
@@ -55364,7 +55681,7 @@ msgid "closed"
msgstr "වස෠ඇත"
msgid "closed %{timeago}"
-msgstr ""
+msgstr "%{timeago} වස෠ඇත"
msgid "closed issue"
msgid_plural "closed issues"
@@ -55416,7 +55733,7 @@ msgid "contribute to this project."
msgstr "මෙම ව්â€à¶ºà·à¶´à·˜à¶­à·’යට දà·à¶ºà¶š වන්න."
msgid "could not read private key, is the passphrase correct?"
-msgstr ""
+msgstr "පෞද්. යතුර කියවීමට නොහà·à¶šà·’ විය, මුරවà·à¶šà·’ය නිවà·à¶»à¶¯à·’ ද?"
msgid "created"
msgstr "සෑදිණි"
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr "උදà·. %{token}"
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] "ගොනු"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55678,7 +55998,7 @@ msgid "https://your-bitbucket-server"
msgstr "https://ඔබගේ-බිට්බකට්-සේවà·à¶¯à·à¶ºà¶šà¶º"
msgid "i18n|%{language} (%{percent_translated}%% translated)"
-msgstr ""
+msgstr "%{language} (%{percent_translated}%% ක් පරිවර්තනය වී ඇත)"
msgid "if"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr "එය ඉත෠විà·à·à¶½à¶ºà·’"
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr "කුරුමà·à¶¢à·’ අභිරුචි විà·à·Šà¶½à·šà·‚කය"
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,8 +56701,11 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
-msgstr "මà·à¶œà·š-සමූහය"
+msgstr "මà·à¶œà·š-විස්මිත-සමූහය"
msgid "my-channel"
msgstr "මà·à¶œà·š-නà·à¶½à·’කà·à·€"
@@ -56429,6 +56761,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, සහ %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56517,7 +56852,7 @@ msgid "private"
msgstr "පෞද්ගලික"
msgid "private key does not match certificate."
-msgstr ""
+msgstr "පෞද්. යතුර සහතිකයට නොගà·à·…පෙයි."
msgid "processing"
msgstr "à·ƒà·à¶šà·ƒà·™à¶¸à·’න්"
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "%{design_link} à·„à·’ à·ƒà·à¶šà¶ à·Šà¶¡à·à·€à¶šà·Š ආරම්භ කළà·"
@@ -56772,6 +57110,9 @@ msgstr "අනන්â€à¶ºà¶±à¶ºà·š නම"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56853,13 +57191,13 @@ msgstr[0] ""
msgstr[1] ""
msgid "user avatar"
-msgstr "පරිà·à·“ලක ප්â€à¶»à¶­à·’රූපය"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක ප්â€à¶»à¶­à·’රූපය"
msgid "user namespace cannot be the parent of another namespace"
msgstr ""
msgid "username"
-msgstr "පරිà·à·“ලක නà·à¶¸à¶º"
+msgstr "පරිà·à·Šâ€à¶»à·“ලක නà·à¶¸à¶º"
msgid "v%{version} published %{timeAgo}"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "අනුවà·à¶¯à¶º %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "%{closed_via} හරහà·"
diff --git a/locale/sk_SK/gitlab.po b/locale/sk_SK/gitlab.po
index f1c5ed66363..fdfd5dea804 100644
--- a/locale/sk_SK/gitlab.po
+++ b/locale/sk_SK/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: sk\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -47,6 +47,13 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr ""
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -910,7 +914,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -988,6 +992,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1063,6 +1073,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,10 +1564,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1663,6 +1676,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2730,6 +2782,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2910,6 +2965,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3222,6 +3280,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3246,6 +3307,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3273,7 +3337,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4113,7 +4177,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4737,6 +4801,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5175,9 +5242,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5268,6 +5332,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5455,6 +5522,9 @@ msgstr[3] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5470,6 +5540,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6595,7 +6689,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6750,6 +6844,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6966,6 +7063,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8053,6 +8159,9 @@ msgstr[3] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8065,6 +8174,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8171,9 +8292,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8261,9 +8379,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,7 +9555,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9827,6 +9942,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9979,7 +10100,7 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10435,15 +10559,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10703,6 +10833,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11000,15 +11133,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11301,6 +11428,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11325,6 +11455,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11748,9 +11881,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12383,7 +12513,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12599,15 +12729,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12671,6 +12804,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14429,9 +14616,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16342,6 +16532,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16369,7 +16565,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16384,7 +16580,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16408,6 +16604,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16468,7 +16667,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16486,10 +16685,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16661,6 +16863,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16676,12 +16896,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17963,9 +18180,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18008,6 +18222,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18146,9 +18363,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18398,7 +18609,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18545,12 +18756,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18596,6 +18813,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19737,6 +19972,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21852,6 +22063,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22008,7 +22219,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22128,9 +22348,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22527,6 +22753,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22593,9 +22822,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22971,7 +23197,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23160,7 +23386,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23172,7 +23398,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23190,9 +23416,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23618,6 +23841,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23883,9 +24109,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23925,6 +24148,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24108,6 +24337,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24984,66 +24916,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25867,15 +25765,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26294,18 +26183,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26555,10 +26438,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26567,16 +26462,26 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27458,6 +27369,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27509,6 +27423,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27605,9 +27522,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27973,6 +27884,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28688,6 +28602,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29117,6 +29043,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29129,6 +29058,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29435,6 +29367,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31225,15 +31259,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31252,12 +31289,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31276,6 +31319,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31712,6 +31758,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31736,6 +31785,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,10 +31809,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31814,9 +31872,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33087,6 +33148,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33279,24 +33340,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34012,6 +34109,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34159,7 +34259,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34606,9 +34709,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34723,12 +34823,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35179,6 +35273,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35827,9 +35921,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35941,6 +36032,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36877,9 +36962,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37504,6 +37592,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37576,6 +37667,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38395,6 +38489,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39048,9 +39151,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39581,9 +39657,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40187,9 +40254,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42150,13 +42262,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results..."
-msgstr ""
-
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42407,6 +42516,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44095,6 +44333,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46203,6 +46459,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46221,6 +46480,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46898,7 +47163,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47940,9 +48211,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48276,6 +48547,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,10 +49081,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48954,7 +49234,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,7 +49360,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49101,7 +49381,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50966,10 +51273,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51083,13 +51393,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51765,6 +52075,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53333,15 +53661,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53817,9 +54139,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56141,6 +56469,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56229,9 +56560,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57398,6 +57741,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57440,6 +57786,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57488,9 +57837,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/sl_SI/gitlab.po b/locale/sl_SI/gitlab.po
index c7dca790254..61cb40316ef 100644
--- a/locale/sl_SI/gitlab.po
+++ b/locale/sl_SI/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: sl\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -47,6 +47,13 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr ""
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -910,7 +914,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -988,6 +992,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -1063,6 +1073,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,10 +1564,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1663,6 +1676,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2730,6 +2782,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2910,6 +2965,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3222,6 +3280,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3246,6 +3307,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3273,7 +3337,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -4113,7 +4177,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4737,6 +4801,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5175,9 +5242,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5268,6 +5332,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5455,6 +5522,9 @@ msgstr[3] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5470,6 +5540,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6595,7 +6689,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6750,6 +6844,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6966,6 +7063,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -8053,6 +8159,9 @@ msgstr[3] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -8065,6 +8174,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8171,9 +8292,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8261,9 +8379,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,7 +9555,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9827,6 +9942,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9979,7 +10100,7 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10435,15 +10559,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10703,6 +10833,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -11000,15 +11133,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11301,6 +11428,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11325,6 +11455,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11748,9 +11881,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12383,7 +12513,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12599,15 +12729,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12671,6 +12804,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14429,9 +14616,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16342,6 +16532,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16369,7 +16565,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16384,7 +16580,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16408,6 +16604,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16468,7 +16667,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16486,10 +16685,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16661,6 +16863,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16676,12 +16896,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17963,9 +18180,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -18008,6 +18222,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -18146,9 +18363,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18398,7 +18609,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18545,12 +18756,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18596,6 +18813,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19737,6 +19972,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21852,6 +22063,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -22008,7 +22219,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -22128,9 +22348,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22527,6 +22753,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22593,9 +22822,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22971,7 +23197,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -23160,7 +23386,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -23172,7 +23398,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -23190,9 +23416,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23618,6 +23841,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23883,9 +24109,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23925,6 +24148,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -24108,6 +24337,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24984,66 +24916,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25867,15 +25765,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26294,18 +26183,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26555,10 +26438,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26567,16 +26462,26 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27458,6 +27369,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27509,6 +27423,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27605,9 +27522,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27973,6 +27884,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28688,6 +28602,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -29117,6 +29043,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -29129,6 +29058,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29435,6 +29367,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -31225,15 +31259,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31252,12 +31289,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31276,6 +31319,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31712,6 +31758,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31736,6 +31785,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,10 +31809,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
+
+msgid "No options found"
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31814,9 +31872,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -33087,6 +33148,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33279,24 +33340,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -34012,6 +34109,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -34159,7 +34259,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34606,9 +34709,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34723,12 +34823,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -35179,6 +35273,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35827,9 +35921,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35941,6 +36032,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36877,9 +36962,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37504,6 +37592,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37576,6 +37667,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38395,6 +38489,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -39048,9 +39151,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39581,9 +39657,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -40187,9 +40254,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -42150,13 +42262,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results..."
-msgstr ""
-
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42407,6 +42516,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -44095,6 +44333,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46203,6 +46459,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -46221,6 +46480,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46898,7 +47163,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47940,9 +48211,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48276,6 +48547,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,10 +49081,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48954,7 +49234,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,7 +49360,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -49101,7 +49381,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50966,10 +51273,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51083,13 +51393,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51765,6 +52075,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53333,15 +53661,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53817,9 +54139,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -56141,6 +56469,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -56229,9 +56560,6 @@ msgstr[3] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57398,6 +57741,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57440,6 +57786,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57488,9 +57837,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po
index fd3711611a1..55a6313a741 100644
--- a/locale/sq_AL/gitlab.po
+++ b/locale/sq_AL/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: sq\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/sr_CS/gitlab.po b/locale/sr_CS/gitlab.po
index 6f2d585ad41..25abe63f22c 100644
--- a/locale/sr_CS/gitlab.po
+++ b/locale/sr_CS/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: sr-CS\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -46,6 +46,12 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid " or "
msgstr ""
@@ -766,9 +772,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -814,7 +817,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -892,6 +895,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -967,6 +976,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1435,10 +1447,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1546,6 +1558,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2041,15 +2056,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2089,12 +2113,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2116,6 +2158,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2131,6 +2176,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2143,6 +2191,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2155,9 +2206,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2362,9 +2410,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2479,6 +2524,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2536,6 +2584,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2587,6 +2638,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2767,6 +2821,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3079,6 +3136,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3103,6 +3163,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3130,7 +3193,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3970,7 +4033,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4594,6 +4657,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5032,9 +5098,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5125,6 +5188,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5311,6 +5377,9 @@ msgstr[2] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5326,6 +5395,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5437,6 +5512,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5482,15 +5560,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5512,6 +5593,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5527,6 +5614,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5569,24 +5659,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6355,9 +6451,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6439,7 +6532,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6589,6 +6682,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6802,6 +6898,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6919,6 +7018,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7846,7 +7948,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7861,15 +7963,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7888,6 +7993,9 @@ msgstr[2] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7900,6 +8008,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7927,6 +8041,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7972,6 +8089,9 @@ msgstr[2] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8005,9 +8125,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8095,9 +8212,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9175,7 +9289,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9271,7 +9385,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9658,6 +9772,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9748,6 +9865,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9808,7 +9928,7 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10063,6 +10183,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10264,15 +10387,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10324,9 +10447,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10348,12 +10468,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10369,9 +10501,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10531,6 +10660,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10828,15 +10960,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11128,6 +11254,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11152,6 +11281,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11575,9 +11707,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11647,31 +11776,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11743,6 +11869,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12103,9 +12232,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12151,6 +12277,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12208,7 +12337,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12424,15 +12553,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12496,6 +12628,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12667,6 +12802,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13192,6 +13330,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13225,6 +13366,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13237,9 +13402,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13327,6 +13501,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13873,6 +14056,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14251,9 +14437,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14593,9 +14776,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14773,6 +14953,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14863,6 +15046,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15085,6 +15271,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15592,9 +15781,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15718,9 +15904,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15946,6 +16129,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15964,6 +16150,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16150,6 +16339,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16177,7 +16372,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16192,7 +16387,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16216,6 +16411,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16276,7 +16474,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16294,10 +16492,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16381,6 +16579,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16453,9 +16657,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16468,6 +16669,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16483,12 +16702,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16558,12 +16780,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17764,9 +17980,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17809,6 +18022,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17947,9 +18163,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17971,7 +18184,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18085,9 +18298,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18199,7 +18409,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18346,12 +18556,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18397,6 +18613,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18433,6 +18655,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18535,6 +18760,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19291,6 +19522,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19537,6 +19771,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20197,9 +20434,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20224,9 +20458,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20596,33 +20827,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21319,6 +21523,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21646,6 +21856,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21661,6 +21874,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21676,12 +21892,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21802,7 +22012,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21820,6 +22030,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21841,6 +22054,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21853,6 +22069,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21922,9 +22141,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21955,6 +22171,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22195,6 +22414,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22210,7 +22435,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22321,6 +22546,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22387,9 +22615,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22765,7 +22990,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22954,7 +23179,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22966,7 +23191,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22984,9 +23209,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23410,6 +23632,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23674,9 +23899,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23716,6 +23938,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23899,6 +24127,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24313,7 +24547,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24340,6 +24574,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24382,381 +24622,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24772,66 +24703,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25261,6 +25141,18 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25618,6 +25510,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25654,15 +25549,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25744,9 +25633,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26080,18 +25966,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26341,10 +26221,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26353,16 +26245,25 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26410,6 +26311,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26746,6 +26650,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27244,6 +27151,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27295,6 +27205,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27391,9 +27304,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27658,9 +27568,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27757,6 +27664,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28465,6 +28375,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28474,6 +28387,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28879,6 +28795,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28894,6 +28816,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28906,6 +28831,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29212,6 +29140,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29473,6 +29497,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29905,9 +29932,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30004,6 +30028,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30886,10 +30913,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30967,6 +30994,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30997,15 +31027,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31024,12 +31057,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31048,6 +31087,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31273,9 +31318,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31483,6 +31525,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31507,6 +31552,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31525,10 +31576,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31585,9 +31639,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31639,6 +31690,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32851,6 +32908,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32878,9 +32938,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33043,24 +33100,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33775,6 +33868,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33922,7 +34018,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34369,9 +34468,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34486,12 +34582,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34942,6 +35032,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35065,9 +35158,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35590,9 +35680,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35704,6 +35791,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35827,9 +35917,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35845,9 +35932,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35884,9 +35968,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35947,6 +36028,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35971,9 +36055,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36205,7 +36286,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36640,9 +36721,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37132,6 +37210,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37267,6 +37351,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37339,6 +37426,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38158,6 +38248,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38230,7 +38326,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38287,10 +38383,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38302,6 +38401,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38320,6 +38422,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38377,9 +38482,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38446,9 +38548,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38809,9 +38908,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38953,34 +39049,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39316,9 +39388,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39331,6 +39400,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39340,9 +39412,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39622,12 +39691,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39940,9 +40003,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40360,6 +40420,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40795,6 +40858,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41083,7 +41149,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41167,6 +41233,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41377,6 +41446,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41485,9 +41557,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41500,7 +41569,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41626,10 +41695,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41644,6 +41716,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41656,7 +41746,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41668,7 +41758,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41680,6 +41770,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41707,9 +41803,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41821,6 +41926,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41890,13 +41998,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42136,6 +42241,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42292,6 +42400,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42301,7 +42415,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42358,6 +42478,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42430,7 +42553,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42442,12 +42565,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42715,6 +42844,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42727,13 +42859,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42763,13 +42895,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42778,6 +42916,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42847,9 +42991,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42904,6 +43045,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42919,9 +43063,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42952,6 +43102,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43069,9 +43222,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43117,7 +43267,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43465,9 +43615,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43537,6 +43684,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43561,12 +43711,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43594,9 +43756,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43606,27 +43774,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43666,15 +43867,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43702,6 +43933,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43822,6 +44056,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43900,6 +44137,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44737,6 +44977,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44830,9 +45073,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45781,6 +46021,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45928,6 +46180,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45946,6 +46201,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46609,6 +46867,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46621,7 +46882,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47461,9 +47728,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47638,6 +47902,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47656,9 +47923,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47908,6 +48172,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47992,6 +48259,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48496,9 +48766,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48517,10 +48793,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48670,7 +48946,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48796,7 +49072,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48817,7 +49093,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49243,7 +49519,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49525,6 +49801,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49606,6 +49885,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49636,9 +49918,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49711,6 +49999,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50077,9 +50377,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50167,6 +50464,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50200,9 +50500,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50281,6 +50578,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50656,6 +50956,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50677,10 +50980,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50728,6 +51031,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50794,13 +51100,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51475,6 +51781,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52180,6 +52489,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52207,16 +52519,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52459,6 +52774,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52573,10 +52891,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52612,6 +52927,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52939,6 +53257,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53041,15 +53365,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53407,6 +53722,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53500,9 +53821,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53521,9 +53839,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53542,13 +53857,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53692,9 +54013,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53725,7 +54043,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53824,9 +54142,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54088,6 +54403,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54097,6 +54415,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54295,9 +54616,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54796,9 +55114,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54919,9 +55234,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54946,6 +55258,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55117,6 +55432,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55228,6 +55546,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55756,6 +56077,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55825,6 +56149,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55912,9 +56239,6 @@ msgstr[2] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56182,6 +56506,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56662,6 +56989,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56671,6 +57001,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56698,6 +57031,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56755,6 +57091,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57064,6 +57403,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57106,6 +57448,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57154,9 +57499,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57214,6 +57556,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/sr_SP/gitlab.po b/locale/sr_SP/gitlab.po
index 555dbc91010..30143328c46 100644
--- a/locale/sr_SP/gitlab.po
+++ b/locale/sr_SP/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: sr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -46,6 +46,12 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid " or "
msgstr ""
@@ -766,9 +772,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -814,7 +817,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -892,6 +895,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -967,6 +976,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1435,10 +1447,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1546,6 +1558,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -2041,15 +2056,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2089,12 +2113,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2116,6 +2158,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2131,6 +2176,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2143,6 +2191,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2155,9 +2206,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2362,9 +2410,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2479,6 +2524,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2536,6 +2584,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2587,6 +2638,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2767,6 +2821,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -3079,6 +3136,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -3103,6 +3163,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -3130,7 +3193,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3970,7 +4033,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4594,6 +4657,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -5032,9 +5098,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -5125,6 +5188,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5311,6 +5377,9 @@ msgstr[2] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5326,6 +5395,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5437,6 +5512,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5482,15 +5560,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5512,6 +5593,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5527,6 +5614,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5569,24 +5659,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6355,9 +6451,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6439,7 +6532,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6589,6 +6682,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6802,6 +6898,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6919,6 +7018,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7846,7 +7948,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7861,15 +7963,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7888,6 +7993,9 @@ msgstr[2] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7900,6 +8008,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7927,6 +8041,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7972,6 +8089,9 @@ msgstr[2] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -8005,9 +8125,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -8095,9 +8212,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9175,7 +9289,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9271,7 +9385,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9658,6 +9772,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9748,6 +9865,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9808,7 +9928,7 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -10063,6 +10183,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10264,15 +10387,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10324,9 +10447,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10348,12 +10468,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10369,9 +10501,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10531,6 +10660,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10828,15 +10960,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -11128,6 +11254,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -11152,6 +11281,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11575,9 +11707,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11647,31 +11776,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11743,6 +11869,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -12103,9 +12232,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -12151,6 +12277,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12208,7 +12337,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12424,15 +12553,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12496,6 +12628,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12667,6 +12802,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13192,6 +13330,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13225,6 +13366,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13237,9 +13402,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13327,6 +13501,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13873,6 +14056,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14251,9 +14437,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14593,9 +14776,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14773,6 +14953,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14863,6 +15046,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15085,6 +15271,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15592,9 +15781,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15718,9 +15904,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15946,6 +16129,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15964,6 +16150,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -16150,6 +16339,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -16177,7 +16372,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16192,7 +16387,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16216,6 +16411,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16276,7 +16474,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16294,10 +16492,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16381,6 +16579,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16453,9 +16657,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16468,6 +16669,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16483,12 +16702,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16558,12 +16780,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17764,9 +17980,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17809,6 +18022,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17947,9 +18163,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17971,7 +18184,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18085,9 +18298,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18199,7 +18409,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18346,12 +18556,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18397,6 +18613,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18433,6 +18655,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18535,6 +18760,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19291,6 +19522,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19537,6 +19771,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20197,9 +20434,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20224,9 +20458,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20596,33 +20827,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21319,6 +21523,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21646,6 +21856,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21661,6 +21874,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21676,12 +21892,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21802,7 +22012,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21820,6 +22030,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21841,6 +22054,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21853,6 +22069,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21922,9 +22141,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21955,6 +22171,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -22195,6 +22414,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22210,7 +22435,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22321,6 +22546,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22387,9 +22615,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22765,7 +22990,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22954,7 +23179,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22966,7 +23191,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22984,9 +23209,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23410,6 +23632,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23674,9 +23899,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23716,6 +23938,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23899,6 +24127,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24313,7 +24547,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24340,6 +24574,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24382,381 +24622,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24772,66 +24703,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25261,6 +25141,18 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25618,6 +25510,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25654,15 +25549,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25744,9 +25633,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -26080,18 +25966,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26341,10 +26221,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26353,16 +26245,25 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26410,6 +26311,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26746,6 +26650,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27244,6 +27151,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27295,6 +27205,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27391,9 +27304,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27658,9 +27568,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27757,6 +27664,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28465,6 +28375,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28474,6 +28387,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28879,6 +28795,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28894,6 +28816,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28906,6 +28831,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -29212,6 +29140,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29473,6 +29497,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29905,9 +29932,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -30004,6 +30028,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30886,10 +30913,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30967,6 +30994,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30997,15 +31027,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -31024,12 +31057,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -31048,6 +31087,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31273,9 +31318,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31483,6 +31525,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31507,6 +31552,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31525,10 +31576,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31585,9 +31639,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31639,6 +31690,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32851,6 +32908,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32878,9 +32938,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -33043,24 +33100,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33775,6 +33868,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33922,7 +34018,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34369,9 +34468,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34486,12 +34582,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34942,6 +35032,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35065,9 +35158,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35590,9 +35680,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35704,6 +35791,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35827,9 +35917,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35845,9 +35932,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35884,9 +35968,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35947,6 +36028,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35971,9 +36055,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36205,7 +36286,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36640,9 +36721,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -37132,6 +37210,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37267,6 +37351,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37339,6 +37426,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -38158,6 +38248,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38230,7 +38326,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38287,10 +38383,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38302,6 +38401,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38320,6 +38422,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38377,9 +38482,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38446,9 +38548,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38809,9 +38908,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38953,34 +39049,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39316,9 +39388,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39331,6 +39400,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39340,9 +39412,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39622,12 +39691,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39940,9 +40003,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40360,6 +40420,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40795,6 +40858,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -41083,7 +41149,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41167,6 +41233,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41377,6 +41446,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41485,9 +41557,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41500,7 +41569,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41626,10 +41695,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41644,6 +41716,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41656,7 +41746,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41668,7 +41758,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41680,6 +41770,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41707,9 +41803,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41821,6 +41926,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41890,13 +41998,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -42136,6 +42241,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42292,6 +42400,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42301,7 +42415,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42358,6 +42478,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42430,7 +42553,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42442,12 +42565,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42715,6 +42844,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42727,13 +42859,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42763,13 +42895,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42778,6 +42916,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42847,9 +42991,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42904,6 +43045,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42919,9 +43063,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42952,6 +43102,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43069,9 +43222,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43117,7 +43267,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43465,9 +43615,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43537,6 +43684,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43561,12 +43711,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43594,9 +43756,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43606,27 +43774,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43666,15 +43867,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43702,6 +43933,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43822,6 +44056,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43900,6 +44137,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44737,6 +44977,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44830,9 +45073,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45781,6 +46021,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45928,6 +46180,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45946,6 +46201,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46609,6 +46867,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46621,7 +46882,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47461,9 +47728,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47638,6 +47902,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47656,9 +47923,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47908,6 +48172,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47992,6 +48259,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48496,9 +48766,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48517,10 +48793,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48670,7 +48946,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48796,7 +49072,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48817,7 +49093,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49243,7 +49519,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49525,6 +49801,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49606,6 +49885,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49636,9 +49918,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49711,6 +49999,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50077,9 +50377,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50167,6 +50464,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50200,9 +50500,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50281,6 +50578,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50656,6 +50956,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50677,10 +50980,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50728,6 +51031,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50794,13 +51100,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51475,6 +51781,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -52180,6 +52489,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52207,16 +52519,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52459,6 +52774,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52573,10 +52891,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52612,6 +52927,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52939,6 +53257,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -53041,15 +53365,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53407,6 +53722,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53500,9 +53821,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53521,9 +53839,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53542,13 +53857,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53692,9 +54013,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53725,7 +54043,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53824,9 +54142,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54088,6 +54403,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54097,6 +54415,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54295,9 +54616,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54796,9 +55114,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54919,9 +55234,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54946,6 +55258,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55117,6 +55432,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55228,6 +55546,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55756,6 +56077,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55825,6 +56149,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55912,9 +56239,6 @@ msgstr[2] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56182,6 +56506,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56662,6 +56989,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56671,6 +57001,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56698,6 +57031,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56755,6 +57091,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57064,6 +57403,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -57106,6 +57448,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -57154,9 +57499,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57214,6 +57556,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/sv_SE/gitlab.po b/locale/sv_SE/gitlab.po
index 2b445cdfcd6..abd7a262c37 100644
--- a/locale/sv_SE/gitlab.po
+++ b/locale/sv_SE/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: sv-SE\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr "%{start} till %{end}"
@@ -45,6 +45,11 @@ msgstr " och "
msgid " and %{sliced}"
msgstr " och %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " eller "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} kunde inte hittas."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} dagar tills taggar tas bort automatiskt"
@@ -718,7 +720,7 @@ msgstr "%{edit_in_new_fork_notice} Försök att ladda upp filen igen."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@foretag.se"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr "%{issuesSize} med en gräns på %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Nyheter%{italic_end} är inaktivt och kan inte visas."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} ärenden med en gräns på %{maxIssueCount}"
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Godkänn inbjudan"
@@ -2444,6 +2494,9 @@ msgstr "Grupper"
msgid "AccessDropdown|Roles"
msgstr "Roller"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "Användare"
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr "Åtgärd"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr "Redigera"
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr "Konfidentialitet"
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr "Gruppavatar"
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr "Tidszon"
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "Imorgon"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr "Totalt"
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr "Totalt antal kärnor (CPU)"
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr "Missnöjd?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr "Användarnamn är tillgängligt."
msgid "Username or email"
msgstr "Användarnamn eller e-postadress"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Användarnamn:"
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr "Välkommen, %{name}!"
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr "Din profil"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr "skapad av"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] "filer"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr "den är för stor"
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr "inställningar för tvåfaktorsautentisering"
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "version %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "via %{closed_via}"
diff --git a/locale/sw_KE/gitlab.po b/locale/sw_KE/gitlab.po
index 62d7d55fb92..5e28ea84a04 100644
--- a/locale/sw_KE/gitlab.po
+++ b/locale/sw_KE/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: sw\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/ta_IN/gitlab.po b/locale/ta_IN/gitlab.po
index 35ca472ecb4..b5aaf1988b3 100644
--- a/locale/ta_IN/gitlab.po
+++ b/locale/ta_IN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ta\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/th_TH/gitlab.po b/locale/th_TH/gitlab.po
index 5e6a0a8192a..bafb88919d2 100644
--- a/locale/th_TH/gitlab.po
+++ b/locale/th_TH/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: th\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -44,6 +44,10 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+
msgid " or "
msgstr ""
@@ -574,9 +578,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -622,7 +623,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -700,6 +701,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -775,6 +782,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1203,10 +1213,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1312,6 +1322,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1755,15 +1768,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1803,12 +1825,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1830,6 +1870,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1845,6 +1888,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -1857,6 +1903,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -1869,9 +1918,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2076,9 +2122,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2193,6 +2236,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2250,6 +2296,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2301,6 +2350,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2481,6 +2533,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2793,6 +2848,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2817,6 +2875,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2844,7 +2905,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3684,7 +3745,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4308,6 +4369,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4746,9 +4810,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4839,6 +4900,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5023,6 +5087,9 @@ msgstr[0] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5038,6 +5105,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5147,6 +5220,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5192,15 +5268,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5222,6 +5301,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5237,6 +5322,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5279,24 +5367,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6045,9 +6139,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6127,7 +6218,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6267,6 +6358,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6474,6 +6568,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6591,6 +6688,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7518,7 +7618,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7533,15 +7633,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7558,6 +7661,9 @@ msgstr[0] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7570,6 +7676,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7597,6 +7709,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7640,6 +7755,9 @@ msgstr[0] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7673,9 +7791,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7763,9 +7878,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -8837,7 +8949,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -8933,7 +9045,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9320,6 +9432,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9410,6 +9525,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9466,7 +9584,7 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -9922,15 +10043,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -9982,9 +10103,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10006,12 +10124,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10027,9 +10157,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10187,6 +10314,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10484,15 +10614,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10782,6 +10906,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10806,6 +10933,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11229,9 +11359,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11301,31 +11428,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11753,9 +11880,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11801,6 +11925,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11858,7 +11985,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12074,15 +12201,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12146,6 +12276,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12317,6 +12450,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -12836,6 +12972,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -12869,6 +13008,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -12881,9 +13044,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -12971,6 +13143,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13517,6 +13698,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -13895,9 +14079,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14235,9 +14416,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14411,6 +14589,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14501,6 +14682,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14723,6 +14907,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15226,9 +15413,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15350,9 +15534,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15568,6 +15749,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15586,6 +15770,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15766,6 +15953,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15793,7 +15986,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -15808,7 +16001,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -15832,6 +16025,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -15892,7 +16088,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -15910,10 +16106,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -15997,6 +16193,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16067,9 +16269,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16082,6 +16281,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16097,12 +16314,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16172,12 +16392,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17366,9 +17580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17411,6 +17622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17549,9 +17763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17573,7 +17784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17687,9 +17898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -17801,7 +18009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -17948,12 +18156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -17999,6 +18213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18035,6 +18255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18137,6 +18360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18891,6 +19120,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19137,6 +19369,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19791,9 +20026,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -19818,9 +20050,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20188,33 +20417,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20907,6 +21109,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21234,6 +21442,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21249,6 +21460,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21264,12 +21478,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21390,7 +21598,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21429,6 +21640,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21441,6 +21655,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21510,9 +21727,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21543,6 +21757,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21783,6 +22000,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -21798,7 +22021,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -21975,9 +22201,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22353,7 +22576,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22542,7 +22765,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22554,7 +22777,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22572,9 +22795,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -22994,6 +23214,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23256,9 +23479,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23298,6 +23518,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23481,6 +23707,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23889,7 +24121,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -23916,6 +24148,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -23958,381 +24196,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24348,66 +24277,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24837,6 +24715,14 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25192,6 +25078,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25228,15 +25117,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25318,9 +25201,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25652,18 +25532,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25913,10 +25787,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -25925,16 +25811,23 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -25982,6 +25875,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26318,6 +26214,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26816,6 +26715,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -26867,6 +26769,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -26963,9 +26868,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27226,9 +27128,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27325,6 +27224,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28019,6 +27921,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28028,6 +27933,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28433,6 +28341,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28448,6 +28362,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28460,6 +28377,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28766,6 +28686,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29021,6 +29037,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29453,9 +29472,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29552,6 +29568,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30430,10 +30449,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30511,6 +30530,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30541,15 +30563,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30568,12 +30593,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30592,6 +30623,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -30815,9 +30852,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31025,6 +31059,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31049,6 +31086,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31067,10 +31110,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31127,9 +31173,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31181,6 +31224,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32379,6 +32428,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32406,9 +32458,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32571,24 +32620,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33301,6 +33386,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33448,7 +33536,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33895,9 +33986,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34012,12 +34100,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34468,6 +34550,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34591,9 +34676,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35116,9 +35198,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35230,6 +35309,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35353,9 +35435,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35371,9 +35450,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35410,9 +35486,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35473,6 +35546,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35497,9 +35573,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35731,7 +35804,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36166,9 +36239,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36658,6 +36728,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -36793,6 +36869,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -36865,6 +36944,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37684,6 +37766,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37756,7 +37844,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -37809,10 +37897,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -37824,6 +37915,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -37842,6 +37936,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -37899,9 +37996,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -37968,9 +38062,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38331,9 +38422,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38473,34 +38561,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38834,9 +38898,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -38849,6 +38910,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -38858,9 +38922,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39140,12 +39201,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39446,9 +39501,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -39858,6 +39910,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40283,6 +40338,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40567,7 +40625,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40649,6 +40707,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40857,6 +40918,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -40965,9 +41029,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -40980,7 +41041,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41106,10 +41167,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41124,6 +41188,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41136,7 +41218,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41148,7 +41230,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41160,6 +41242,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41187,9 +41275,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41301,6 +41398,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41370,13 +41470,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41594,6 +41691,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41750,6 +41850,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -41759,7 +41865,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -41888,7 +42003,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -41900,12 +42015,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42171,6 +42292,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42183,13 +42307,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42219,13 +42343,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42234,6 +42364,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42303,9 +42439,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42360,6 +42493,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42375,9 +42511,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42408,6 +42550,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42525,9 +42670,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42571,7 +42713,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -42919,9 +43061,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -42991,6 +43130,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43015,12 +43157,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43048,9 +43202,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43060,27 +43220,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43120,15 +43313,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43156,6 +43379,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43276,6 +43502,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43354,6 +43583,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44187,6 +44419,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44280,9 +44515,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45231,6 +45463,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45378,6 +45622,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45396,6 +45643,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46055,6 +46305,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46067,7 +46320,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47070,6 +47326,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47088,9 +47347,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47340,6 +47596,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47424,6 +47683,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47928,9 +48190,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -47949,10 +48217,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48102,7 +48370,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48228,7 +48496,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48249,7 +48517,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48669,7 +48937,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48951,6 +49219,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49030,6 +49301,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49060,9 +49334,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49135,6 +49415,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49499,9 +49791,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49589,6 +49878,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49622,9 +49914,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49703,6 +49992,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50078,6 +50370,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50099,10 +50394,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50150,6 +50445,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50216,13 +50514,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -50895,6 +51193,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51596,6 +51897,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51623,16 +51927,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -51875,6 +52182,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -51989,10 +52299,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52028,6 +52335,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52355,6 +52665,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52457,15 +52773,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -52817,6 +53124,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -52908,9 +53221,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -52929,9 +53239,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -52950,13 +53257,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53100,9 +53413,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53133,7 +53443,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53232,9 +53542,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53494,6 +53801,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53503,6 +53813,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53701,9 +54014,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54319,9 +54626,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54346,6 +54650,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54513,6 +54820,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54620,6 +54930,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55128,6 +55441,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55193,6 +55509,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55278,9 +55597,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55540,6 +55856,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56010,6 +56329,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56019,6 +56341,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56046,6 +56371,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56103,6 +56431,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56396,6 +56727,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56438,6 +56772,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56486,9 +56823,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56544,6 +56878,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po
index 0cec39ea1b5..b8d1a443d18 100644
--- a/locale/tr_TR/gitlab.po
+++ b/locale/tr_TR/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: tr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr " ve "
msgid " and %{sliced}"
msgstr " ve %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr " veya "
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} bulunamadı."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} gün sonra etiketler otomatik olarak kaldırılacak"
@@ -718,7 +720,7 @@ msgstr "%{edit_in_new_fork_notice} Tekrar bir dosya yüklemeyi deneyin."
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@sirket.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} kullanılamaz"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr "%{verb} %{time_spent_value} zaman harcandı."
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr "%{amount} tane daha"
msgid "+ %{count} more"
msgstr "+ %{count} daha"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} daha fazla"
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "Daveti kabul et"
@@ -2444,6 +2494,9 @@ msgstr "Gruplar"
msgid "AccessDropdown|Roles"
msgstr "Roller"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "Kullanıcılar"
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr "Yığına bir öneri ekleyin."
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr "Ä°ncelemeye ekle"
msgid "Add to tree"
msgstr "AÄŸaca ekle"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr "Ekle/kaldır"
msgid "AddMember|Invite email is invalid"
msgstr "Davet e-postası geçersiz"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr "Kullanıcıyı engelleme aşağıdaki etkilere sahiptir:"
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr "Blob datanın öngösteriminde, bir hata meydana geldi"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr "Sorunlar alınırken bir hata oluştu."
msgid "An error occurred while fetching label colors."
msgstr "Etiket renkleri alınırken bir hata oluştu."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "Ä°ÅŸ tetiklenirken bir hata oluÅŸtu."
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "Onaylama sırasında güncelleme yapılırken bir hata oluştu"
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr "Bu cihazı silmek istediğinizden emin misiniz? Bu işlem geri alınamaz
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Bu iş hattı planını silmek istediğinizden emin misiniz?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr "Engellenen sorun"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "%{text} varlığı kontrol ediliyor…"
@@ -9637,8 +9756,8 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText} planı"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr "Bir şablon seç..."
msgid "Choose a type..."
msgstr "Bir tür seç..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Dosya seçin…"
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr "Ortamlar"
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr "Değişken satırı kaldırın"
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Tür"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "DeÄŸer"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (Tüm ortamlar)"
-
msgid "CiVariable|All environments"
msgstr "Tüm ortamlar"
@@ -10359,6 +10487,9 @@ msgstr "Ä°stemciler"
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Klonla"
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr "Kod Ä°ncelemesi"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
-msgstr ""
-
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr "Daralt"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr "Gizlilik"
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr "Bağlantı başarısız"
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "Destek ile iletişime geçin"
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr "Gereksinim oluÅŸtur"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "Cron Zaman Dilimi"
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "Güvenlik açığı listesini aç/kapat"
@@ -15958,6 +16146,12 @@ msgstr "Saat dilimi"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} diÄŸer"
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr "Mevcut proje"
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr "Dağıtım anahtarları yükleniyor"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr "Genel olarak erişilebilen dağıtım anahtarları"
msgid "DeployKeys|Read access only"
msgstr "Sadece okuma eriÅŸimi"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr "Dağıtıcı belirtecini kopyala"
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr "Kullanıcı adı"
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
-msgstr "Bu dağıtım, API kullanılarak oluşturuldu"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr "Tasarım Yönetimi dosya ve verileri"
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr "E-posta gönderildi"
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "E-postalar"
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr "E-postalarda üstbilgi ve altbilgiyi etkinleştir"
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "Ä°ÅŸ"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr "GeniÅŸlet"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Tümünü genişlet"
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr "Kullanıcıya göre filtrele"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr "Sonuçları filtrele..."
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr "Süzgeç..."
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr "Ücretsiz bir örnek incelemesi alın"
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Başlayın"
@@ -21440,6 +21649,9 @@ msgstr "Doğrulanmadı"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr "Gitaly Sunucuları"
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr "%{time_ago} eriÅŸim verildi"
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr "GitLab'da ara"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr "Grup profil resmi"
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "Grup açıklaması (isteğe bağlı)"
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr "Gruba genel bakış içeriği"
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr "Bu özellik tarayıcıda yerel depolama desteği gerektiriyor"
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,8 +22984,8 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Eğer projelerinizi bir grup altında düzenlerseniz, bir klasör gibi çalışır."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
msgid "GroupsEmptyState|No archived projects."
msgstr ""
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "GitLab'da 5 dakikada bir proje oluÅŸturun"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "Aralık Deseni"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr "Geçersiz iki adımlı doğrulama kodu."
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr "Kapatıldı"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Kapatıldı (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,29 +26004,49 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr "Sorunlar, birleÅŸtirme istekleri, itmeler ve yorumlar."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr ""
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Ortalama/Ay:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "Son 12 ay"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Üzgünüz, süzgeciniz sonuç üretmedi"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "Grubunuzdaki projeler için hiç sorun yok"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "Aramanızı genişletmek için yukarıdaki süzgeç çubuğundaki süzgeçleri değiştirin veya kaldırın"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr "%{time_ago} katıldı"
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr "Son İş Hattı"
-
msgid "Last Seen"
msgstr "Son Görülme"
@@ -27541,6 +27444,9 @@ msgstr "Şuna yolladınız:"
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr "Kilit bulunamadı"
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr "Birleştirme işlemi mesajı"
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr "Metrik oluÅŸtur"
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr "Yeni zamanlama"
-
msgid "New snippet"
msgstr "Yeni parçacık"
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "Zamanlama bulunamadı"
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr "Seçenekler"
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr "Sayfalar"
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr "Yol"
msgid "Path:"
msgstr "Yol:"
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "EtkinleÅŸtirildi"
-
msgid "PipelineSchedules|Active"
msgstr "Etkin"
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr "Düzen genişliği"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "%{min} ile %{max} arasında bir sayı olmalıdır"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr "Önceki çözülmemiş tartışma"
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr "Profili Düzenle"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr "Proje yolu"
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr "Çatallar"
@@ -37030,6 +37110,9 @@ msgstr "Herkese açık"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} geliştiriciler için yazılabilir olacak. Emin misiniz?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr "Genel"
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr "Kendi etkinliğiniz ile ilgili bildirim alın"
-msgid "Receive product marketing emails"
-msgstr "Ürün pazarlama e-postalarını al"
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "%{reportedBy} tarafından %{timeAgo} bildirildi"
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr "Åžifreyi kaydet"
-msgid "Save pipeline schedule"
-msgstr "İş hattı takvimini kaydet"
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr "Ortam özelliklerini ara"
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,15 +41734,12 @@ msgstr "Dönüm noktalarını ara"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
-msgstr "Ara veya sonuçları filtrele..."
-
msgid "Search or filter results…"
msgstr "Sonuçları ara ya da filtrele…"
+msgid "Search or go to…"
+msgstr ""
+
msgid "Search page"
msgstr ""
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr "Güvenlik gösterge panosu"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr "Servis Masası"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr "Oturum süresi (dakika)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr "%{epic_ref} epiğini üst epik olarak ayarlar."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "E-posta başarıyla kaldırıldı."
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr "Başarıyla kilit kaldırıldı"
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr "Hedef Yol"
msgid "Target branch"
msgstr "Hedef dal"
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Bu birleÅŸtirme isteÄŸi kilitlendi."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr "Saat dilimi"
msgid "TimeTrackingEstimated|Est"
msgstr "Tah"
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "Yarın"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr "Bu epik şu anda güncellenemiyor."
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr "Kullanıcı adı ya da e-posta"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,17 +52223,20 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{user} tarafından %{timeago} %{statusStart}onaylandı%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "%{pipelineLink} iş hattında %{timeago} %{statusStart}algılandı%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
-msgstr "%{user} tarafından %{timeago} %{statusStart}reddedildi%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "%{user} tarafından %{timeago} %{statusStart}çözümlendi%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr ""
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr "Şu anda herhangi bir dağıtımınız yok."
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "Yetkili uygulamalarınız"
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr "Profiliniz"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] "dosya"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr "etiket adı"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr "tetiklendi"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr "sürüm %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "%{closed_via} aracılığıyla"
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index 97bc754868b..4dd9580c623 100644
--- a/locale/uk/gitlab.po
+++ b/locale/uk/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: uk\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:01\n"
+"PO-Revision-Date: 2023-09-12 12:33\n"
msgid " %{start} to %{end}"
msgstr " %{start} до %{end}"
@@ -47,6 +47,13 @@ msgstr " Ñ– "
msgid " and %{sliced}"
msgstr " Ñ– %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid " or "
msgstr " або "
@@ -862,9 +869,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr "%{count} загальна вага"
-msgid "%{dashboard_path} could not be found."
-msgstr "%{dashboard_path} не знайдено."
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} днів до того, Ñк теги будуть видалені автоматично"
@@ -890,7 +894,7 @@ msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start} Що таке Двофакторна автентифікаціÑ?%{docs_link_end}"
msgid "%{duration}, queued for %{queuedDuration} seconds"
-msgstr ""
+msgstr "%{duration}, у черзі %{queuedDuration} Ñекунди"
msgid "%{duration}ms"
msgstr "%{duration}мÑ"
@@ -910,8 +914,8 @@ msgstr "%{edit_in_new_fork_notice} Спробуйте завантажити Ñ„Ð
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr "%{enable_service_ping_link_start}Увімкнути%{link_end} або %{generate_manually_link_start}згенерувати%{link_end} ÑервіÑний пінг Ð´Ð»Ñ Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½ÑŒÐ¾Ð³Ð¾ переглÑду Ñ– Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… про викориÑÑ‚Ð°Ð½Ð½Ñ ÑервіÑу."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr ""
msgid "%{extra} more downstream pipelines"
msgstr "Ще %{extra} наÑтупних конвеєрів"
@@ -988,6 +992,12 @@ msgstr "%{issuesSize} з обмеженнÑм %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}Що нового%{italic_end} неактивний Ñ– не може бути переглÑнутий."
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} задач з обмеженнÑм %{maxIssueCount}"
@@ -1063,6 +1073,9 @@ msgstr "%{labelStart}Ðезмінена відповідь:%{labelEnd} %{headers
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} недоÑтупний"
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1551,11 +1564,11 @@ msgstr "%{verb} %{time_spent_value} витрачено чаÑу."
msgid "%{verb} this %{noun} as a draft."
msgstr "%{verb} цей %{noun} Ñк чернетку."
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} надає можливіÑÑ‚ÑŒ надÑилати ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð½Ð° веб-заÑтоÑунки у відповідь на події у групі або в проєкті."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "За допомогою %{webhooks_link_start}%{webhook_type}%{link_end} можна надÑилати ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð´Ð¾ вебзаÑтоÑунків у відповідь на події в групі або проєкті. Ми рекомендуємо викориÑтовувати %{integrations_link_start}інтеграцію%{link_end}, а не вебхук."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr ""
msgid "%{widget} options"
msgstr "%{widget} опції"
@@ -1663,6 +1676,9 @@ msgstr "+ %{amount} більше"
msgid "+ %{count} more"
msgstr "+ ще %{count}"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ ще %{moreCount}"
@@ -2092,7 +2108,7 @@ msgid "A new personal access token has been created"
msgstr "Ðовий перÑональний токен доÑтупу було згенеровано"
msgid "A new personal access token, named %{code_start}%{token_name}%{code_end}, has been created."
-msgstr ""
+msgstr "Створено новий токен доÑтупу з ім'Ñм %{code_start}%{token_name}%{code_end}."
msgid "A new personal access token, named %{token_name}, has been created."
msgstr "Ðовий перÑональний токен доÑтупу, названий %{token_name}, був Ñтворений."
@@ -2184,15 +2200,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -2232,12 +2257,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -2259,6 +2302,9 @@ msgstr "ÐадіÑлати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð² чат."
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -2274,6 +2320,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2286,6 +2335,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2298,9 +2350,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2505,9 +2554,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2518,7 +2564,7 @@ msgid "AbuseReport|Actions"
msgstr ""
msgid "AbuseReport|Activity"
-msgstr ""
+msgstr "ÐктивніÑÑ‚ÑŒ"
msgid "AbuseReport|Admin profile"
msgstr ""
@@ -2622,6 +2668,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2679,6 +2728,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "ПрийнÑти запрошеннÑ"
@@ -2730,6 +2782,9 @@ msgstr "Групи"
msgid "AccessDropdown|Roles"
msgstr "Ролі"
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr "КориÑтувачі"
@@ -2910,6 +2965,9 @@ msgstr "Підтвердити"
msgid "Action"
msgstr "ДіÑ"
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2938,10 +2996,10 @@ msgid "Active chat names (%{count})"
msgstr "Ðктивні імена чата %{count})"
msgid "Active group access tokens"
-msgstr ""
+msgstr "Ðктивні токени доÑтупу до групи"
msgid "Active personal access tokens"
-msgstr ""
+msgstr "Ðктивні перÑональні токени доÑтупу"
msgid "Active pipeline trigger tokens"
msgstr ""
@@ -3178,7 +3236,7 @@ msgid "Add new pipeline trigger token"
msgstr ""
msgid "Add new token"
-msgstr ""
+msgstr "Додати новий токен"
msgid "Add new webhook"
msgstr ""
@@ -3205,7 +3263,7 @@ msgid "Add projects"
msgstr "Додати проєкти"
msgid "Add protected branch"
-msgstr ""
+msgstr "Додати захищену гілку"
msgid "Add reaction"
msgstr "Додати реакцію"
@@ -3222,6 +3280,9 @@ msgstr "Додати пропозицію до пакета"
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "Додати текÑÑ‚ до Ñторінки входу. Markdown увімкнено."
@@ -3246,6 +3307,9 @@ msgstr "Додати до перевірки"
msgid "Add to tree"
msgstr "Додати до дерева"
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr "Додайте теми до проєктів, щоб допомогти кориÑтувачам Ñ—Ñ… знайти."
@@ -3273,8 +3337,8 @@ msgstr "Додати/видалити"
msgid "AddMember|Invite email is invalid"
msgstr "ÐдреÑа електронної пошти Ð´Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð½ÐµÐ´Ñ–Ð¹Ñна"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "Перевищено ліміт запрошень: %{daily_invites} на день"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð½Ðµ може бути пуÑтим"
@@ -3781,7 +3845,7 @@ msgid "AdminSettings|Maximum duration of a session for Git operations when 2FA i
msgstr "МакÑимальна триваліÑÑ‚ÑŒ ÑеÑÑ–Ñ— Ð´Ð»Ñ Git операцій, коли 2FA увімкнена."
msgid "AdminSettings|Maximum includes"
-msgstr ""
+msgstr "МакÑимальна кількіÑÑ‚ÑŒ включень"
msgid "AdminSettings|Maximum number of DAG dependencies that a job can have"
msgstr "МакÑимальна кількіÑÑ‚ÑŒ залежноÑтей DAG, Ñкі може мати завданнÑ"
@@ -3931,7 +3995,7 @@ msgid "AdminSettings|The latest artifacts for all jobs in the most recent succes
msgstr "ОÑтанні артефакти Ð´Ð»Ñ Ð²ÑÑ–Ñ… завдань у оÑтанніх уÑпішних конвеєрах у кожному проєкті зберігаютьÑÑ Ñ‚Ð° не мають терміну дії."
msgid "AdminSettings|The maximum number of included files per pipeline."
-msgstr ""
+msgstr "МакÑимальна кількіÑÑ‚ÑŒ включених файлів у конвеєр."
msgid "AdminSettings|The template for the required pipeline configuration can be one of the GitLab-provided templates, or a custom template added to an instance template repository. %{link_start}How do I create an instance template repository?%{link_end}"
msgstr "Шаблон Ð´Ð»Ñ Ð½ÐµÐ¾Ð±Ñ…Ñ–Ð´Ð½Ð¾Ñ— конфігурації конвеєра може бути одним із шаблонів, наданих GitLab, або інший шаблон доданий до репозиторію шаблонів інÑтанÑу. %{link_start}Як Ñтворити шаблон інÑтанÑу?%{link_end}"
@@ -4113,8 +4177,8 @@ msgstr "Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача має наÑтупні на
msgid "AdminUsers|Bot"
msgstr "Бот"
-msgid "AdminUsers|Can create group"
-msgstr "Може Ñтворювати групи"
+msgid "AdminUsers|Can create top level group"
+msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "Ðе вдаєтьÑÑ Ð²Ð²Ñ–Ð¹Ñ‚Ð¸ або отримати доÑтуп до інформації"
@@ -4737,6 +4801,9 @@ msgstr "Заголовок - це обов'Ñзкове поле Ð´Ð»Ñ Ð¿Ð¾Ð¿Ðµ
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr "Додати нову інтеграцію"
@@ -5175,9 +5242,6 @@ msgstr "Помилка при отриманні публічних ключів
msgid "An error occurred previewing the blob"
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½ÑŒÐ¾Ð³Ð¾ переглÑду об'єкта"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr "ВідбулаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ°"
@@ -5268,6 +5332,9 @@ msgstr "Помилка при отриманні задач."
msgid "An error occurred while fetching label colors."
msgstr "Помилка при отриманні кольорів міток."
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr "Під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñників ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°"
@@ -5455,6 +5522,9 @@ msgstr[3] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при збереженні ваших параметрів. Спробуйте зберегти Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð½Ð¾Ð²Ñƒ."
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr "Помилка при запуÑку завданнÑ."
@@ -5470,6 +5540,12 @@ msgstr "Помилка при запуÑку нового конвеєру длÑ
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr "Помилка при оновленні затверджуючих оÑіб"
@@ -5582,6 +5658,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5627,15 +5706,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5657,6 +5739,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr "Редагувати"
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5672,6 +5760,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5706,7 +5797,7 @@ msgid "Analytics|Page Title"
msgstr ""
msgid "Analytics|Pages"
-msgstr ""
+msgstr "Сторінки"
msgid "Analytics|Referer"
msgstr ""
@@ -5714,24 +5805,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6510,9 +6607,6 @@ msgstr "Ви впевнені, що хочете видалити цей приÑ
msgid "Are you sure you want to delete this label?"
msgstr "Ви впевнені, що хочете видалити цю мітку?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "Ви впевнені, що хочете видалити цей розклад Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð°?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "Ви впевнені, що хочете видалити цей конвеєр? Це призведе до Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії вÑÑ–Ñ… кешів конвеєра та Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð²ÑÑ–Ñ… пов'Ñзаних об'єктів, таких Ñк ÑкладаннÑ, журнали, артефакти та тригери. Ð¦Ñ Ð´Ñ–Ñ Ð½Ðµ може бути ÑкаÑована."
@@ -6595,8 +6689,8 @@ msgstr "Ви впевнені, що хочете Ñкинути реєÑтрац
msgid "Are you sure you want to retry this migration?"
msgstr "Ви впевнені, що хочете повторити перенеÑеннÑ?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "Ви впевнені, що бажаєте видалити цей %{accessTokenType}? Ð¦Ñ Ð´Ñ–Ñ Ð½Ðµ може бути ÑкаÑована."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
msgstr ""
@@ -6750,6 +6844,9 @@ msgstr "СпиÑок гілок, розділених комами, Ð´Ð»Ñ Ð°Ð²Ñ
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr "Запитати пізніше"
@@ -6966,6 +7063,9 @@ msgstr "Заголовок з таким іменем вже Ñ–Ñнує."
msgid "AuditStreams|Active"
msgstr "Ðктивний"
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -7083,6 +7183,9 @@ msgstr "Це може включати конфіденційну інформа
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr "ЗначеннÑ"
@@ -7654,7 +7757,7 @@ msgid "BetaBadge|Is supported by a commercially reasonable effort."
msgstr ""
msgid "BetaBadge|May be unstable."
-msgstr ""
+msgstr "Може бути неÑтабільним."
msgid "BetaBadge|Should not cause data loss."
msgstr ""
@@ -8010,7 +8113,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -8025,15 +8128,18 @@ msgstr "ÐžÑ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑ”Ñтрації учаÑника"
msgid "Billing|Cannot remove user"
msgstr "Ðеможливо видалити кориÑтувача"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr "ПрÑме членÑтво"
msgid "Billing|Enter at least three characters to search."
msgstr "Введіть щонайменше три Ñимволи Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ."
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr "ОзнайомтеÑÑ Ð· платними планами"
@@ -8053,6 +8159,9 @@ msgstr[3] "Групи на рівні «Безкоштовні» обмеженÑ
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "УчаÑники, Ñкі були запрошені за допомогою Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð´Ð¾ групи, не можуть бути видалені. Ви можете або видалити вÑÑŽ групу, або попроÑити влаÑника групи видалити учаÑника."
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr "Ðемає кориÑтувачів Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ."
@@ -8065,6 +8174,12 @@ msgstr "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð´Ð¾ проєкту"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "Видалити кориÑтувача %{username} з вашої підпиÑки"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -8092,6 +8207,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ кориÑтувача %{username} з вашої підпиÑки. Якщо ви продовжите, кориÑтувача буде видалено з групи %{namespace} та вÑÑ–Ñ… Ñ—Ñ— підгруп та проєктів. Цю дію не можна буде відмінити."
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -8138,6 +8256,9 @@ msgstr[3] "Заблоковано %d задачами"
msgid "Blocked issue"
msgstr "Заблокована задача"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr "БлокуваннÑ"
@@ -8171,9 +8292,6 @@ msgstr "Ðемає відповідних результатів"
msgid "BoardNewEpic|Search groups"
msgstr "Пошук груп"
-msgid "BoardNewEpic|Select a group"
-msgstr "Виберіть групу"
-
msgid "BoardNewIssue|No matching results"
msgstr "Ðемає відповідних результатів"
@@ -8261,9 +8379,6 @@ msgstr "Вибрати мітку"
msgid "BoardScope|Select milestone"
msgstr "Вибрати етап"
-msgid "BoardScope|Select weight"
-msgstr "Обрати вагу"
-
msgid "BoardScope|Started"
msgstr "Розпочато"
@@ -9344,7 +9459,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9440,8 +9555,8 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr "Можна вручну розгорнути на"
-msgid "Can create groups:"
-msgstr "Може Ñтворити групи:"
+msgid "Can create top level groups:"
+msgstr ""
msgid "Can not delete primary training"
msgstr ""
@@ -9827,6 +9942,9 @@ msgstr "Зміни в заголовку не збережені"
msgid "Changes:"
msgstr "Зміни:"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9917,6 +10035,9 @@ msgstr "Перевірте Ñвої образи Docker на наÑвніÑÑ‚ÑŒ
msgid "Check your sign-up restrictions"
msgstr "Перевірте Ñвої Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð° реєÑтрацію"
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr "Перевірка доÑтупноÑÑ‚Ñ– %{text}…"
@@ -9979,8 +10100,8 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText} план"
+msgid "Checkout|%{selectedPlanText}"
+msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -10234,6 +10355,9 @@ msgstr "Виберіть тему-шаблон..."
msgid "Choose a type..."
msgstr "Виберіть тип..."
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr "Виберіть файл…"
@@ -10244,7 +10368,7 @@ msgid "Choose the top-level group for your repository imports."
msgstr "Оберіть групу найвищого Ñ€Ñ–Ð²Ð½Ñ Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ репозиторіїв."
msgid "Choose visibility level, enable/disable project features and their permissions, disable email notifications, and show default emoji reactions."
-msgstr ""
+msgstr "Оберіть рівень видимоÑÑ‚Ñ–, увімкніть/вимкніть можливоÑÑ‚Ñ– проєкту та Ñ—Ñ… дозволи, вимкніть електронні ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñ‚Ð° покажіть типові реакції з емодзі."
msgid "Choose what content you want to see on a group’s overview page."
msgstr "Вибрати вміÑÑ‚ оглÑдової Ñторінки групи."
@@ -10406,7 +10530,7 @@ msgid "CiStatusText|preparing"
msgstr "підготовка"
msgid "CiStatusText|scheduled"
-msgstr ""
+msgstr "заплановано"
msgid "CiStatusText|skipped"
msgstr "пропущено"
@@ -10415,35 +10539,35 @@ msgid "CiStatusText|waiting"
msgstr "очікуваннÑ"
msgid "CiStatusText|warning"
-msgstr ""
+msgstr "попередженнÑ"
msgid "CiStatus|running"
msgstr "виконуєтьÑÑ"
msgid "CiVariables|Add Variable"
-msgstr ""
+msgstr "Додати змінну"
msgid "CiVariables|Add variable"
-msgstr ""
+msgstr "Додати змінну"
msgid "CiVariables|Attributes"
msgstr "Ðтрибути"
msgid "CiVariables|CI/CD Variables"
-msgstr ""
+msgstr "Змінні CI/CD"
msgid "CiVariables|Cancel"
msgstr "СкаÑувати"
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "Ðеможливо викориÑтовувати приховану змінну із поточним значеннÑм"
-
msgid "CiVariables|Delete variable"
-msgstr ""
+msgstr "Видалити змінну"
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr "Редагувати змінну"
+
msgid "CiVariables|Environments"
msgstr "Середовища"
@@ -10472,7 +10596,7 @@ msgid "CiVariables|Key"
msgstr "Ключ"
msgid "CiVariables|Mask variable"
-msgstr ""
+msgstr "МаÑкувати змінну"
msgid "CiVariables|Masked"
msgstr "Приховано"
@@ -10484,7 +10608,7 @@ msgid "CiVariables|Maximum number of variables reached."
msgstr "ДоÑÑгнута макÑимальна кількіÑÑ‚ÑŒ змінних."
msgid "CiVariables|Protect variable"
-msgstr ""
+msgstr "ЗахиÑтити змінну"
msgid "CiVariables|Protected"
msgstr "Захищений"
@@ -10495,9 +10619,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr "Видалити змінну"
-msgid "CiVariables|Remove variable row"
-msgstr "Видалити Ñ€Ñдок змінних"
-
msgid "CiVariables|Run job"
msgstr "Виконати завданнÑ"
@@ -10519,12 +10640,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "Тип"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "ЗначеннÑ"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10540,9 +10673,6 @@ msgstr "Змінні зберігають інформацію, наприкла
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr "* (Ð’ÑÑ– Ñередовища)"
-
msgid "CiVariable|All environments"
msgstr "Ð’ÑÑ– Ñередовища"
@@ -10703,6 +10833,9 @@ msgstr "Клієнти"
msgid "Clientside DSN"
msgstr "КлієнтÑький DSN"
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr "Клонувати"
@@ -10743,7 +10876,7 @@ msgid "Close"
msgstr "Закрити"
msgid "Close %{issuableType}"
-msgstr ""
+msgstr "Закрити %{issuableType}"
msgid "Close %{issueType}"
msgstr "Закрити %{issueType}"
@@ -10755,7 +10888,7 @@ msgid "Close %{tabname}"
msgstr "Закрити %{tabname}"
msgid "Close %{workItemType}"
-msgstr ""
+msgstr "Закрити %{workItemType}"
msgid "Close design"
msgstr "Закрити дизайн"
@@ -11000,15 +11133,9 @@ msgstr "Стан клаÑтера"
msgid "Cluster cache cleared."
msgstr "Кеш клаÑтера очищено."
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr "Ðеобхідний клаÑтер Ð´Ð»Ñ Stages::ClusterEndpointInserter "
-
msgid "Cluster level"
msgstr "Рівень клаÑтера"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr "%{linkStart}ОзнайомтеÑÑ Ð· документацією%{linkEnd} Ð´Ð»Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¾Ð³Ð¾ вÑтановленнÑ. ПереконайтеÑÑ, що у Ð²Ð°Ñ Ñ” токен доÑтупу."
@@ -11055,7 +11182,7 @@ msgid "ClusterAgents|Agent %{strongStart}disconnected%{strongEnd}"
msgstr "Ðгент %{strongStart}відключений%{strongEnd}"
msgid "ClusterAgents|Agent ID #%{agentId}"
-msgstr ""
+msgstr "Ідентифікатор агента #%{agentId}"
msgid "ClusterAgents|Agent access token:"
msgstr "Токен доÑтупу агента:"
@@ -11301,6 +11428,9 @@ msgstr "Цей агент не має токенів"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "Щоб видалити агента, введіть %{name} Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ:"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr "Щоб відкликати токен, введіть %{name} Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ:"
@@ -11325,6 +11455,9 @@ msgstr "ПереглÑнути вÑÑ– %{number} агентів"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "ПереглÑнути вÑÑ– %{number} клаÑтери"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "Ми хотіли б дізнатиÑÑŒ більше про ваш доÑвід з GitLab Agent."
@@ -11748,9 +11881,6 @@ msgstr "Перевірка коду"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "Ðналітика перевірки коду відображає таблицю відкритих запитів на злиттÑ, Ñкі знаходÑÑ‚ÑŒÑÑ Ð½Ð° Ñтадії перевірки коду. Ðаразі Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту та/або фільтрів немає запитів на злиттÑ, що перевірÑÑŽÑ‚ÑŒÑÑ."
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11820,31 +11950,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgstr "%{link_start}Що таке пропозиції коду?%{link_end}"
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
-msgstr ""
+msgid "CodeSuggestions|Code Suggestions"
+msgstr "Пропозиції коду"
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
-msgstr "%{link_start}Що таке пропозиції коду?%{link_end}"
-
-msgid "CodeSuggestions|Code Suggestions"
-msgstr "Пропозиції коду"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11917,6 +12044,9 @@ msgstr "Когорти кориÑтувачів показано за оÑтан
msgid "Collapse"
msgstr "Згорнути"
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr "Згорнути вÑÑ– теми"
@@ -11987,7 +12117,7 @@ msgid "CommandPalette|Global Commands"
msgstr ""
msgid "CommandPalette|Pages"
-msgstr ""
+msgstr "Сторінки"
msgid "CommandPalette|Project files"
msgstr ""
@@ -12278,9 +12408,6 @@ msgstr "Під Ñ‡Ð°Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÑпиÑку гілок/тегіÐ
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "Під Ñ‡Ð°Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ ÑпиÑку гілок/тегів ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. Будь лаÑка, Ñпробуйте ще раз."
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "Під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑпиÑку гілок/тегів ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. Будь лаÑка, Ñпробуйте ще раз."
-
msgid "CompareRevisions|View open merge request"
msgstr "ПереглÑнути відкритий запит на злиттÑ"
@@ -12326,6 +12453,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr "Додати фреймворк"
@@ -12383,8 +12513,8 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
-msgstr "Додані фреймворки будуть з'ÑвлÑтиÑÑŒ тут."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr ""
msgid "ComplianceFrameworks|Invalid format"
msgstr "ÐедійÑний формат"
@@ -12599,15 +12729,18 @@ msgstr "КонфіденційніÑÑ‚ÑŒ"
msgid "Configuration help"
msgstr "Довідка по конфігурації"
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "Ðалаштувати %{italic_start}Що нового%{italic_end} меню та вміÑÑ‚."
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
-msgstr "Ðалаштувати %{link} Ð´Ð»Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð´Ñ–Ð¹. %{link_start}ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ.%{link_end}"
-
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr "Ðалаштувати %{repository_checks_link_start}перевірки репозиторіїв:%{link_end} та %{housekeeping_link_start}очищеннÑ%{link_end} в репозиторіÑÑ…."
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ CAPTCHA, Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ IP-Ð°Ð´Ñ€ÐµÑ Ñ‚Ð° інших антиÑпам-заходів."
@@ -12671,6 +12804,9 @@ msgstr "Ðалаштуйте розширені дозволи, Ñховище Ð
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr "Ðалаштуйте додаткові права, Ñховище великих файлів, двофакторну автентифікацію та Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ з клієнтами."
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12842,6 +12978,9 @@ msgstr "Помилка з’єднаннÑ"
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "ЗвернутиÑÑ Ð´Ð¾ Ñлужби підтримки"
@@ -12874,10 +13013,10 @@ msgstr "Будь лаÑка, перейдіть до %{linkStart}налаштуÐ
msgid "ContainerRegistry|%{count} Image repository"
msgid_plural "ContainerRegistry|%{count} Image repositories"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "%{count} репозиторій образів"
+msgstr[1] "%{count} репозиторію образів"
+msgstr[2] "%{count} репозиторіїв образів"
+msgstr[3] "%{count} репозиторіїв образів"
msgid "ContainerRegistry|%{count} tag"
msgid_plural "ContainerRegistry|%{count} tags"
@@ -12920,7 +13059,7 @@ msgid "ContainerRegistry|Cleanup is disabled for this project"
msgstr "ÐžÑ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
msgid "ContainerRegistry|Cleanup is not scheduled."
-msgstr ""
+msgstr "ÐžÑ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð½Ðµ заплановано."
msgid "ContainerRegistry|Cleanup is ongoing"
msgstr "ÐžÑ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ñ‚Ñ€Ð¸Ð²Ð°Ñ”"
@@ -12986,7 +13125,7 @@ msgid "ContainerRegistry|Delete tag"
msgstr "Видалити тег"
msgid "ContainerRegistry|Deleting the image repository will delete all images and tags inside. This action cannot be undone. Please type the following to confirm: %{code}"
-msgstr ""
+msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–ÑŽ образів призведе до Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð²ÑÑ–Ñ… образів Ñ– тегів, що міÑÑ‚ÑÑ‚ÑŒÑÑ Ð² ньому. Ð¦Ñ Ð´Ñ–Ñ Ð½Ðµ може бути ÑкаÑована. Будь лаÑка, введіть наÑтупне Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ: %{code}"
msgid "ContainerRegistry|Digest: %{imageId}"
msgstr "ДайджеÑÑ‚: %{imageId}"
@@ -13092,13 +13231,13 @@ msgid "ContainerRegistry|Run cleanup:"
msgstr "Виконати очищеннÑ:"
msgid "ContainerRegistry|Save storage space by automatically deleting tags from the container registry and keeping the ones you want. %{linkStart}How does cleanup work?%{linkEnd}"
-msgstr ""
+msgstr "Зекономте міÑце в Ñховищі, автоматично видалÑючи теги з реєÑтру контейнерів Ñ– залишаючи лише Ñ‚Ñ–, Ñкі вам потрібні. %{linkStart}Як працює очищеннÑ?%{linkEnd}"
msgid "ContainerRegistry|Set cleanup rules"
msgstr "Ð’Ñтановити правила очищеннÑ"
msgid "ContainerRegistry|Set rules to automatically remove unused packages to save storage space."
-msgstr ""
+msgstr "Ð’Ñтановіть правила Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ²Ð¸ÐºÐ¾Ñ€Ð¸Ñтаних пакетів, щоб заощадити міÑце у Ñховищі."
msgid "ContainerRegistry|Set up cleanup"
msgstr ""
@@ -13146,7 +13285,7 @@ msgid "ContainerRegistry|Tags successfully marked for deletion."
msgstr "Теги уÑпішно позначені Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ."
msgid "ContainerRegistry|Tags that match %{strongStart}any of%{strongEnd} these rules are %{strongStart}kept%{strongEnd}, even if they match a removal rule below. The %{strongStart}latest%{strongEnd} tag is always kept."
-msgstr ""
+msgstr "Теги що відповідають %{strongStart}будь-Ñкому%{strongEnd} з цих правил %{strongStart}залишаютьÑÑ%{strongEnd}, навіть Ñкщо вони відповідають правилу уÑÑƒÐ½ÐµÐ½Ð½Ñ Ð½Ð¸Ð¶Ñ‡Ðµ. %{strongStart}оÑтанній%{strongEnd} з тегів завжди залишаєтьÑÑ."
msgid "ContainerRegistry|Tags that match these rules are %{strongStart}removed%{strongEnd}, unless a rule above says to keep them."
msgstr "Теги, Ñкі відповідають цим правилам, %{strongStart}видалÑÑŽÑ‚ÑŒÑÑ%{strongEnd}, Ñкщо вище правило не передбачає Ñ—Ñ… збереженнÑ."
@@ -13230,7 +13369,7 @@ msgid "Contains only whitespace changes."
msgstr ""
msgid "Content"
-msgstr ""
+msgstr "ВміÑÑ‚"
msgid "Content parsed with %{link}."
msgstr "ВміÑÑ‚ аналізуєтьÑÑ Ð·Ð° допомогою %{link}."
@@ -13344,7 +13483,7 @@ msgid "ContributionAnalytics|Opened MRs"
msgstr ""
msgid "ContributionAnalytics|Opened issues"
-msgstr ""
+msgstr "Відкриті задачі"
msgid "ContributionAnalytics|Pushed"
msgstr ""
@@ -13370,6 +13509,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13403,6 +13545,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr "Прокоментували запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{noteableLink} у %{resourceParentLink}."
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13415,9 +13581,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13505,6 +13680,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -14051,6 +14235,9 @@ msgstr "Створити реліз"
msgid "Create requirement"
msgstr "Створити вимогу"
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr "Створити ÑервіÑний обліковий запиÑ"
@@ -14429,9 +14616,6 @@ msgstr "Організацію було додано."
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "ЧаÑовий поÑÑ Cron"
-
msgid "Cron time zone"
msgstr "ЧаÑовий поÑÑ Cron"
@@ -14772,9 +14956,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr "Загальний чаÑ"
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "випадаючий фільтр груп"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr "не дозволена Ð´Ð»Ñ Ð´Ð°Ð½Ð¾Ñ— початкової події"
@@ -14954,6 +15135,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -15044,6 +15228,9 @@ msgstr "Ð§Ð°Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑервіÑу (Ñереднє чиÑло
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -15266,6 +15453,9 @@ msgstr "Мінімум = 0 (тайм-аут не ввімкнено), МакÑи
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "Мінімум = 1 Ñекунда, МакÑимум = 3600 Ñекунд"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15775,9 +15965,6 @@ msgstr "Визначте влаÑний шаблон за допомогою ÑÐ
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr "Визначити влаÑні правила Ð´Ð»Ñ Ñпаму, незалежного від Akismet"
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "Визначте Ñередовища на Ñтадії Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð² %{code_open}.gitlab-ci.yml%{code_close} Ð´Ð»Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½ÑŒ."
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15902,9 +16089,6 @@ msgstr "Видалити мітку: %{labelName}"
msgid "Delete pipeline"
msgstr "Видалити конвеєр"
-msgid "Delete pipeline schedule"
-msgstr "Видалити розклад конвеєра"
-
msgid "Delete project"
msgstr "Видалити проєкт"
@@ -16135,6 +16319,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr "Пакувальник"
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -16153,6 +16340,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "Увімкнути/вимкнути ÑпиÑок вразливоÑтей"
@@ -16342,6 +16532,12 @@ msgstr "ЧаÑовий поÑÑ"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} інших"
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr "Поточний проєкт"
@@ -16369,8 +16565,8 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð»ÑŽÑ‡Ñ–Ð² розгортаннÑ"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "Ðе знайдено ключів розгортаннÑ. Створюйте Ñ—Ñ… за допомогою форми вище."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "Приватні ключі розгортаннÑ"
@@ -16384,8 +16580,8 @@ msgstr "Публічні ключі розгортаннÑ"
msgid "DeployKeys|Read access only"
msgstr "ДоÑтуп тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "Ðктивні токени Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
msgstr "ДозволÑÑ” читати та запиÑувати доÑтуп до образів реєÑтру."
@@ -16408,6 +16604,9 @@ msgstr "ДозволÑÑ” доÑтуп лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð´Ð¾ реп
msgid "DeployTokens|Allows write access to registry images."
msgstr "ДозволÑÑ” запиÑувати образи реєÑтру."
+msgid "DeployTokens|Cancel"
+msgstr "СкаÑувати"
+
msgid "DeployTokens|Copy deploy token"
msgstr "Скопіювати токен розгортаннÑ"
@@ -16468,7 +16667,7 @@ msgstr "ОблаÑÑ‚ÑŒ дії"
msgid "DeployTokens|Scopes (select at least one)"
msgstr "Межі (вибрати хоча б одну)"
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16486,12 +16685,12 @@ msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
msgid "DeployTokens|Username (optional)"
msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача (необов'Ñзково)"
-msgid "DeployTokens|Your New Deploy Token"
-msgstr "Ваш новий токен розгортаннÑ"
-
msgid "DeployTokens|Your new Deploy Token username"
msgstr "Ваше нове ім'Ñ Ð´Ð»Ñ Ñ‚Ð¾ÐºÐµÐ½Ñƒ розгортаннÑ"
+msgid "DeployTokens|Your new deploy token"
+msgstr ""
+
msgid "DeployTokens|Your new group deploy token has been created."
msgstr ""
@@ -16520,10 +16719,10 @@ msgid "Deployment Frequency"
msgstr "ЧаÑтота РозгортаннÑ"
msgid "Deployment Target|%{linkStart}How to provision or deploy to Kubernetes clusters from GitLab?%{linkEnd}"
-msgstr ""
+msgstr "%{linkStart}Як налаштовувати або розгортати на клаÑтерах Kubernetes з GitLab?%{linkEnd}"
msgid "Deployment Target|Project deployment target (optional)"
-msgstr ""
+msgstr "Ціль Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ (необов'Ñзково)"
msgid "Deployment Target|Select the deployment target"
msgstr ""
@@ -16573,6 +16772,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16646,9 +16851,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "СкаÑовано"
@@ -16661,6 +16863,24 @@ msgstr "ID розгортаннÑ"
msgid "Deployment|Failed"
msgstr "Ðевдало"
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr "ОÑтанній розгорнутий"
@@ -16676,12 +16896,15 @@ msgstr "Пропущено"
msgid "Deployment|Success"
msgstr "УÑпішно"
-msgid "Deployment|This deployment was created using the API"
-msgstr "Це Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð±ÑƒÐ»Ð¾ Ñтворено через API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16751,12 +16974,6 @@ msgstr "Дизайн"
msgid "Design Management files and data"
msgstr "Файли та дані ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ Ð´Ð¸Ð·Ð°Ð¹Ð½Ð¾Ð¼"
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design} з %{designs_count}"
@@ -17323,7 +17540,7 @@ msgid "Discover|GitLab will perform static and dynamic tests on the code of your
msgstr ""
msgid "Discover|Security capabilities, integrated into your development lifecycle"
-msgstr ""
+msgstr "МожливоÑÑ‚Ñ– безпеки, інтегровані у ваш життєвий цикл розробки"
msgid "Discover|See the other features of the %{linkStart}ultimate plan%{linkEnd}"
msgstr "ПереглÑньте інші функції %{linkStart}ultimate плану%{linkEnd}"
@@ -17778,7 +17995,7 @@ msgid "Edit comment"
msgstr "Редагувати коментар"
msgid "Edit comment template"
-msgstr ""
+msgstr "Редагувати шаблон коментарÑ"
msgid "Edit commit message"
msgstr "Редагувати Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ"
@@ -17838,7 +18055,7 @@ msgid "Edit sidebar"
msgstr "Редагувати бічну панель"
msgid "Edit single file"
-msgstr ""
+msgstr "Редагувати один файл"
msgid "Edit table"
msgstr "Редагувати таблицю"
@@ -17874,7 +18091,7 @@ msgid "Edit your search filter and try again."
msgstr ""
msgid "Edit, lint, and visualize your pipeline."
-msgstr ""
+msgstr "Редагуйте, виокремлюйте та візуалізуйте конвеєр."
msgid "Edited"
msgstr "Відредаговано"
@@ -17963,9 +18180,6 @@ msgstr "ЛиÑта відправлено"
msgid "Email the pipeline status to a list of recipients."
msgstr "ВідправлÑти ÑÑ‚Ð°Ñ‚ÑƒÑ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð° по електронній пошті ÑпиÑок одержувачів."
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr "Електронна пошта:"
@@ -18008,6 +18222,9 @@ msgstr "%{emails}, %{andMore} отримає ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ ваш
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "і ще %{moreCount}"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr "ÐдреÑи електронної пошти"
@@ -18146,9 +18363,6 @@ msgstr "Увімкнути групові раннери"
msgid "Enable header and footer in emails"
msgstr "Увімкнути заголовок та футер в електронних лиÑтах"
-msgid "Enable in-product marketing emails"
-msgstr "Увімкніть внутрішні маркетингові розÑилки"
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -18170,7 +18384,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr "Увімкніть або вимкніть перевірку верÑій та СервіÑний пінг."
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -18284,9 +18498,6 @@ msgstr "ЗаÑтоÑовувати двофакторну автентифіка
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr "ПереконайтеÑÑ Ð² тому, що %{linkStart}Ñередовище приÑутнє в Ñтадії розгортаннÑ%{linkEnd} вашого CI конвеєра Ð´Ð»Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½ÑŒ на ваш клаÑтер."
@@ -18398,8 +18609,8 @@ msgstr "Середовище"
msgid "Environment scope"
msgstr "ОбÑÑг Ñередовища"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr "Змінні Ñередовища на цьому інÑтанÑÑ– GitLab за замовчуваннÑм налаштовані на %{link_start} захищено%{link_end}."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr "Змінні Ñередовища в цьому інÑтанÑÑ– GitLab налаштовані на %{help_link_start}, захищені%{help_link_end} за замовчуваннÑм."
msgid "Environment:"
msgstr "Середовище:"
@@ -18545,12 +18756,18 @@ msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Ñередовища"
msgid "Environments|GitLab agent"
msgstr "GitLab агент"
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr "ЗавданнÑ"
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про зупинку Ñередовищ"
@@ -18596,6 +18813,12 @@ msgstr "Відкотити Ñередовище %{name}?"
msgid "Environments|Search by environment name"
msgstr "Пошук за назвою Ñередовища"
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr "Виберіть агента"
@@ -18632,6 +18855,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr "Майбутнє"
@@ -18734,6 +18960,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19230,7 +19462,7 @@ msgid "EscalationStatus|Acknowledged"
msgstr ""
msgid "EscalationStatus|Resolved"
-msgstr ""
+msgstr "Вирішено"
msgid "EscalationStatus|Triggered"
msgstr ""
@@ -19491,6 +19723,9 @@ msgstr "ІÑнуючі методи входу можуть бути видалÐ
msgid "Expand"
msgstr "Розгорнути"
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr "Розгорнути вÑе"
@@ -19737,6 +19972,9 @@ msgstr "https://example.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -20400,9 +20638,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr "Сортувати по кориÑтувачах"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20427,9 +20662,6 @@ msgstr "Фільтрувати результати..."
msgid "Filter users"
msgstr "Фільтр кориÑтувачів"
-msgid "Filter..."
-msgstr "Фільтр..."
-
msgid "Finalizing"
msgstr "Завершуємо"
@@ -20800,33 +21032,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "Крім того, ви можете перейти на GitLab Premium або GitLab Ultimate:"
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "ОглÑд платних планів"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "ОглÑд платних планів:"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr "Ð£Ð¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ ÑƒÑ‡Ð°Ñниками"
-
-msgid "FreeUserCap|Manage members:"
-msgstr "Ð£Ð¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ ÑƒÑ‡Ð°Ñниками:"
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr "Щоб отримати більше учаÑників пробної верÑÑ–Ñ—:"
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr "Ви доÑÑгли ліміту учаÑників!"
-
msgid "Freeze end"
msgstr ""
@@ -21525,6 +21730,12 @@ msgstr "Отримайте безкоштовну оцінку інÑтанÑа"
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr "Почати"
@@ -21852,6 +22063,9 @@ msgstr "Ðепідтверджено"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ— ваших Ñторінок..."
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21867,6 +22081,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr "Якщо ввімкнено, уÑÑ– Ñпроби відвідати ваш вебÑайт через HTTP автоматично перенаправлÑÑŽÑ‚ÑŒÑÑ Ð½Ð° HTTPS за допомогою відповіді з кодом ÑтатуÑу 301. Потрібний дійÑний Ñертифікат Ð´Ð»Ñ Ð²ÑÑ–Ñ… доменів. %{docs_link_start}ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ.%{link_end}"
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21882,12 +22099,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr "Сервери Gitaly"
-msgid "Gitaly relative path:"
-msgstr "ВідноÑний шлÑÑ… Gitaly:"
-
-msgid "Gitaly storage name:"
-msgstr "Ðазва Ñховища Gitaly:"
-
msgid "Gitaly timeouts"
msgstr "Ð§Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Gitaly"
@@ -22008,8 +22219,8 @@ msgstr "URL-адреÑа вашого інÑтанÑа Gitpod, налаштовÐ
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr "Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Gitpod, Ñпочатку ви повинні увімкнути у розділі інтеграцій функцію ваших %{linkStart}налаштувань кориÑтувача%{linkEnd}."
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
-msgstr "Щоб викориÑтовувати інтеграцію, кожен кориÑтувач повинен також увімкнути Gitpod у Ñвоєму обліковому запиÑÑ– GitLab. %{link_start}Як увімкнути?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr ""
msgid "Gitpod|https://gitpod.example.com"
msgstr "https://gitpod.example.com"
@@ -22026,6 +22237,9 @@ msgstr "Ðадано доÑтуп %{time_ago}"
msgid "Given epic is already related to this epic."
msgstr "Даний епік уже пов’Ñзаний із цим епіком."
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -22047,6 +22261,9 @@ msgstr "%{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr "%{count} надано результати за замовчуваннÑм. ВикориÑтовуйте верхні та нижні клавіші зі Ñтрілками, щоб перейти до ÑпиÑку результатів пошуку."
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -22059,6 +22276,9 @@ msgstr "Закрити"
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "Група"
@@ -22099,7 +22319,7 @@ msgid "GlobalSearch|No labels found"
msgstr ""
msgid "GlobalSearch|Places"
-msgstr ""
+msgstr "МіÑцÑ"
msgid "GlobalSearch|Project"
msgstr "Проєкт"
@@ -22128,9 +22348,6 @@ msgstr "Пошук"
msgid "GlobalSearch|Search GitLab"
msgstr "Пошук в GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr "Пошук в GitLab %{kbdOpen}/%{kbdClose}"
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "Пошук проєктів, задач і т.д."
@@ -22161,6 +22378,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "Введіть та натиÑніть клавішу Enter Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ."
@@ -22401,6 +22621,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22416,7 +22642,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22510,7 +22736,7 @@ msgid "Group URL"
msgstr "URL-адреÑа групи"
msgid "Group access token creation is disabled in this group."
-msgstr ""
+msgstr "У цій групі відключено ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð¾ÐºÐµÐ½Ñ–Ð² групового доÑтупу."
msgid "Group application: %{name}"
msgstr "ЗаÑтоÑунок групи: %{name}"
@@ -22527,6 +22753,9 @@ msgstr "Ðватар групи"
msgid "Group by"
msgstr "Групувати за"
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr "ÐžÐ¿Ð¸Ñ Ð³Ñ€ÑƒÐ¿Ð¸ (необов'Ñзково)"
@@ -22593,9 +22822,6 @@ msgstr "Ðазва групи (ваша організаціÑ)"
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr "ОглÑд групи"
-
msgid "Group overview content"
msgstr "ВміÑÑ‚ оглÑдової Ñторінки групи"
@@ -22971,8 +23197,8 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr "Фреймворки відповідноÑÑ‚Ñ–"
-msgid "GroupSettings|Configure analytics features for this group"
-msgstr "Ðалаштувати функції аналітики Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— групи"
+msgid "GroupSettings|Configure analytics features for this group."
+msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
msgstr ""
@@ -23160,8 +23386,8 @@ msgstr "Ð¦Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±ÑƒÑ” підтримки localStorage вÐ
msgid "GroupsDropdown|Toggle edit mode"
msgstr "Перемикач режиму редагуваннÑ"
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "Група — набір із декількох проєктів."
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr ""
msgid "GroupsEmptyState|Create new project"
msgstr "Створити новий проєкт"
@@ -23172,8 +23398,8 @@ msgstr "Створити нову підгрупу"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "Групи — це найкращий ÑпоÑіб керувати кількома проєктами та учаÑниками."
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Ð Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð² у групі Ñхоже на Ñ€Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð² папці."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr ""
msgid "GroupsEmptyState|No archived projects."
msgstr "Ðемає архівованих проєктів."
@@ -23190,9 +23416,6 @@ msgstr "Ðемає підгруп чи проєктів."
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "Проєкти – це міÑце, де ви можете зберігати Ñвій код, задачі, вікі та інші функцій Gitlab."
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "Ви можете керувати правами доÑтупу членів групи мати доÑтуп до кожного проєкту в ній."
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” необхідних прав Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´Ð³Ñ€ÑƒÐ¿Ð¸ або проєкту в цій групі. Будь лаÑка, зв’ÑжітьÑÑ Ð· влаÑником цієї групи, щоб Ñтворити нову підгрупу або проєкт."
@@ -23454,10 +23677,10 @@ msgstr[3] "%d артефактів"
msgid "HarborRegistry|%{count} Image repository"
msgid_plural "HarborRegistry|%{count} Image repositories"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "%{count} репозиторій образів"
+msgstr[1] "%{count} репозиторію образів"
+msgstr[2] "%{count} репозиторіїв образів"
+msgstr[3] "%{count} репозиторіїв образів"
msgid "HarborRegistry|-- artifacts"
msgstr "- артефакти"
@@ -23618,6 +23841,9 @@ msgstr "Допоможіть переклаÑти GitLab на вашу мову"
msgid "Help translate to your language"
msgstr "Допоможіть переклаÑти вашою мовою"
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr "Допомагає запобігти брутфорÑ-атакам від ботів."
@@ -23883,9 +24109,6 @@ msgstr "Я хочу зберегти Ñвій код"
msgid "I want to use GitLab CI with my existing repository"
msgstr "Я хочу викориÑтовувати GitLab CI зі Ñвоїм Ñ–Ñнуючим репозиторієм"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "Я хотів би отримувати Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ GitLab електронною поштою"
-
msgid "I'm signing up for GitLab because:"
msgstr "Я реєÑтруюÑÑ Ð² GitLab, тому що:"
@@ -23925,6 +24148,12 @@ msgstr "Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð°, тому що ви не можете Ñ
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr "Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð°, тому що ви не маєте дозволу на Ð·Ð°Ð¿Ð¸Ñ Ð² поточну гілку."
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "ІÐФОРМÐЦІЯ: Термін дії вашого ключа SSH закінчивÑÑ. Згенеруйте новий ключ."
@@ -24108,6 +24337,12 @@ msgstr "Підтвердьте ÑпоÑіб оплати"
msgid "IdentityVerification|Verify phone number"
msgstr "Підтвердити номер телефону"
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr "Підтвердити Ñвою оÑобу"
@@ -24525,7 +24760,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24552,6 +24787,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr "За цією URL-адреÑою немає дійÑного репозиторію Git. Якщо ваш репозиторій HTTP не Ñ” загальнодоÑтупним, перевірте Ñвої облікові дані."
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24594,381 +24835,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr "%{organization_name} логотип"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr "%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, Сан-ФранциÑко, ÐšÐ°Ð»Ñ–Ñ„Ð¾Ñ€Ð½Ñ–Ñ 94104, СШÐ"
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...Ñ– ви можете отримати безкоштовну пробну верÑÑ–ÑŽ GitLab Ultimate"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr "3 ÑпоÑоби перейти до GitLab CI/CD"
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr "ÐаÑправді GitLab змушує команду працювати (краще)"
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr "І нарешті, %{deploy_link} заÑтоÑунок Ð´Ð»Ñ Python."
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "Чи готові ваші раннери?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr "Ðвтоматичні ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ безпоÑередньо в GitLab"
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "Будь героєм DevOps"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "Кращий код за менший чаÑ"
-
msgid "InProductMarketing|Blog"
msgstr "Блог"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr "Створити влаÑного раннер"
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "Створити проєкт у GitLab за 5 хвилин"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "Створити Ñвій перший проєкт!"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr "Чи знаєте ви, що команди, Ñкі викориÑтовують GitLab, набагато ефективніші?"
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr "Створити проєкт і репо"
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "ОзнайомтеÑÑ Ð· GitLab CI/CD"
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr "Швидко розпочніть роботу з CI/CD, викориÑтовуючи наш %{quick_start_link}. Почніть з доÑтупного раннера, а потім Ñтворіть файл CI .yml – це дійÑно так проÑто."
-
-msgid "InProductMarketing|Get our import guides"
-msgstr "Отримайте наші поÑібники з імпорту"
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr "ОзнайомтеÑÑ Ð· GitLab CI/CD"
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr "ОÑнови Git"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr "GitHub Enterprise Ð´Ð»Ñ GitLab"
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr "GitLab забезпечує теÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¾ÑŽ Ñтатичного заÑтоÑунку (SAST), динамічне теÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ заÑтоÑунків (DAST), ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ñ–Ð², Ñ– ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð»ÐµÐ¶Ð½Ð¾Ñтей Ð´Ð»Ñ Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÑ‡Ð½Ð¸Ñ… заÑтоÑунків разом з відповідніÑÑ‚ÑŽ ліцензії."
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr "GitLab's CI/CD Ñпрощує розробку програмного забезпеченнÑ. Ðе вірите нам? ОÑÑŒ вам три ÑпоÑоби Ð´Ð»Ñ ÑˆÐ²Ð¸Ð´ÐºÐ¾Ð³Ð¾ (Ñ– приємного) теÑÑ‚-драйву:"
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr "Преміум рівні GitLab призначені Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб ви, ваша команда та ваш заÑтоÑунок були ефективнішими та безпечнішими за допомогою функцій, але не обмежені:"
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "Дайте нам одну хвилину..."
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr "Працюйте далі з GitLab"
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr "Goldman Sachs почав з однієї збірки кожні два тижні Ñ– дійшов до тиÑÑч збірок на день"
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr "ОÑÑŒ, що вам потрібно знати"
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr "Як (Ñ– чому) Ð²Ñ–Ð´Ð´Ð·ÐµÑ€ÐºÐ°Ð»ÐµÐ½Ð½Ñ Ð¼Ð°Ñ” значеннÑ"
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr "Скільки чаÑу нам потрібно, щоб закрити задачі/запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð° такими типами, Ñк запити функцій, помилки, технічний борг, безпека?"
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr "Скільки днів необхідно нашій команді Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñ€Ñ–Ð·Ð½Ð¾Ð¼Ð°Ð½Ñ–Ñ‚Ð½Ð¸Ñ… завдань?"
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr "Як Ñтворювати та теÑтувати швидше"
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr "Якщо ви не хочете отримувати маркетингові Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð±ÐµÐ·Ð¿Ð¾Ñередньо від GitLab, %{marketing_preference_link}."
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr "Якщо ви більше не хочете отримувати від Ð½Ð°Ñ Ð¼Ð°Ñ€ÐºÐµÑ‚Ð¸Ð½Ð³Ð¾Ð²Ñ– повідомленнÑ,"
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr "Імпортуйте Ñвій проєкт та код з GitHub, Bitbucket та інших"
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr "Покращте ÑкіÑÑ‚ÑŒ коду та ÑпроÑÑ‚Ñ–Ñ‚ÑŒ перевірки"
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr "Підвищуйте операційну ефективніÑÑ‚ÑŒ"
-msgid "InProductMarketing|Invite them to help out."
-msgstr "ЗапроÑÑ–Ñ‚ÑŒ Ñ—Ñ… допомогти."
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "ЗапроÑÑ–Ñ‚ÑŒ Ñвоїх колег та почніть надÑилати код швидше."
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "ЗапроÑÑ–Ñ‚ÑŒ Ñвоїх колег приєднатиÑÑ Ð¼ÐµÐ½Ñˆ ніж за одну хвилину"
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "ЗапроÑÑ–Ñ‚ÑŒ Ñвоїх колег Ñьогодні"
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "ЗапроÑÑ–Ñ‚ÑŒ Ñвою команду менш ніж за 60 Ñекунд"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "ЗапроÑити Ñвою команду зараз"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr "ЗапроÑÑ–Ñ‚ÑŒ Ñвою команду Ñьогодні, щоб разом Ñтворити кращий код (Ñ– процеÑи)"
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr "Ð’Ñе це Ñ” в ÑтатиÑтиці"
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr "Також можливо проÑто %{external_repo_link}, щоб ÑкориÑтатиÑÑ GitLab CI/CD."
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr "ЗапуÑтити GitLab CI/CD через 20 хвилин або менше"
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr "Перемикаєте? Імпортувати проєкти в GitLab проÑтіше, ніж ви думаєте. ПереміÑÑ‚Ñ–Ñ‚ÑŒ %{github_link} або імпортуйте щоÑÑŒ %{bitbucket_link}."
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr "Опануйте миÑтецтво імпорту!"
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr "Перейдіть до проÑтого ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð²ÐµÐ±-Ñайту Pages %{ci_template_link}"
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr "Вам потрібна альтернатива імпорту?"
-
msgid "InProductMarketing|No credit card required."
msgstr "Кредитна картка непотрібна."
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr "Ðаш інÑтрумент об'єднує вÑе"
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr "Швидка розробка, Ñпрощена"
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr "Безпека, що інтегрована у ваш життєвий цикл розробки"
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "Розпочніть пробну верÑÑ–ÑŽ GitLab Ultimate Ñьогодні менш ніж за одну хвилину, кредитна картка не потрібна."
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "Розпочніть безплатну пробну верÑÑ–ÑŽ GitLab Ultimate - кредитна картка не потрібна"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "Розпочати пробну верÑÑ–ÑŽ"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "Розпочніть з %{performance_link}"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "Розпочніть з імпорту ваших проєктів"
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "Розпочніть з безкоштовної пробної верÑÑ–Ñ— GitLab Ultimate"
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "Розпочніть Ñвою пробну верÑÑ–ÑŽ зараз!"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr "Ðе дивуйтеÑÑ Ñ– викориÑтовуйте GitLab, щоб відповіÑти на такі запитаннÑ:"
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr "Оптимізуйте переглÑд коду, дізнавайтеÑÑ Ð· першого поглÑду, хто недоÑтупний, ÑпілкуйтеÑÑ Ð² коментарÑÑ… або електронною поштою та інтегруйтеÑÑ Ð·Ñ– Slack, щоб уÑÑ– були на одній Ñторінці."
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr "Зробіть перші кроки з GitLab"
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr "Виведіть ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ñ…Ñ–Ð´Ð½Ð¸Ð¼ кодом на новий рівень"
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr "Об’єднайтеÑÑ Ð² GitLab Ð´Ð»Ñ Ð¿Ñ–Ð´Ð²Ð¸Ñ‰ÐµÐ½Ð½Ñ ÐµÑ„ÐµÐºÑ‚Ð¸Ð²Ð½Ð¾ÑÑ‚Ñ–"
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr "ТеÑтуйте, Ñтворюйте, розгортайте"
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr "Це вÑе, що потрібно, щоб почати роботу з GitLab, але Ñкщо ви новачок у роботі з Git, переглÑньте наш %{basics_link}, щоб отримати кориÑні поради та підказки Ð´Ð»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr "Це електронна пошта %{current_series} %{total_series} в %{track} поÑлідовноÑÑ‚Ñ–."
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб відмовитиÑÑ Ð²Ñ–Ð´ цих ознайомчих лиÑтів, %{unsubscribe_link}."
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб зрозуміти та отримати макÑимальну кориÑÑ‚ÑŒ від роботи з GitLab, розпочніть з початку та %{project_link}. Репозиторії Ñ” чаÑтиною проєкту в GitLab, тож піÑÐ»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñвого проєкту, ви можете працювати далі та %{repo_link}."
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "Спробувати верÑÑ–ÑŽ GitLab Ultimate безкоштовно"
-
-msgid "InProductMarketing|Try it out"
-msgstr "Спробуйте!"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "Спробуйте Ñамі!"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr "ВикориÑтовувати GitLab CI/CD"
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr "СкориÑтайтеÑÑ Ð½Ð°ÑˆÐ¸Ð¼ шаблоном AWS cloudformation Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку ваших раннерів лише кількома кліками!"
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr "ВикориÑтовуєтьÑÑ Ð¿Ð¾Ð½Ð°Ð´ 100 000 організаціÑми з уÑього Ñвіту:"
@@ -24984,66 +24916,15 @@ msgstr "Бажаєте розміÑтити GitLab на Ñвоїх ÑерверÐ
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr "Ми дещо знаємо про ефективніÑÑ‚ÑŒ Ñ– хочемо цим поділитиÑÑ. ПідпишітьÑÑ Ð½Ð° безкоштовну пробну верÑÑ–ÑŽ GitLab Ultimate, Ñ– ваші команди кориÑтуватимутьÑÑ Ð½ÐµÑŽ з першого днÑ."
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr "Як виглÑдає чаÑова шкала нашого потоку значень від розробки продукту до його Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ñ‚Ð° ÑтвореннÑ?"
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr "Коли ваша команда перебуває в GitLab, ці відповіді можна знайти одним кліком."
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr "Робота в GitLab = більша ефективніÑÑ‚ÑŒ"
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr "Ваші команди можуть працювати ефективніше"
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "детальне поÑÑненнÑ"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "підключіть зовнішній репозиторій"
-
-msgid "InProductMarketing|create a project"
-msgstr "Створити проєкт"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "від Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "перейдіть на about.gitlab.com"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "Ñк легко почати"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "коротка інÑÑ‚Ñ€ÑƒÐºÑ†Ñ–Ñ Ð· початку роботи"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "Ð²Ñ–Ð´Ð´Ð·ÐµÑ€ÐºÐ°Ð»ÐµÐ½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–ÑŽ"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "налаштувати репо"
-
-msgid "InProductMarketing|test and deploy"
-msgstr "теÑтуйте та розгортайте"
-
-msgid "InProductMarketing|testing browser performance"
-msgstr "теÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð´ÑƒÐºÑ‚Ð¸Ð²Ð½Ð¾ÑÑ‚Ñ– браузера"
-
msgid "InProductMarketing|unsubscribe"
msgstr "відпиÑатиÑÑ"
-msgid "InProductMarketing|update your preferences"
-msgstr "оновіть Ñвої налаштуваннÑ"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr "викориÑтовуючи шаблон CI/CD"
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "ви можете %{unsubscribe_link} у будь-Ñкий чаÑ."
@@ -25162,7 +25043,7 @@ msgid "IncidentManagement|Severity"
msgstr "Рівень"
msgid "IncidentManagement|Status"
-msgstr ""
+msgstr "СтатуÑ"
msgid "IncidentManagement|Stops paging"
msgstr ""
@@ -25473,6 +25354,20 @@ msgstr "Вбудований"
msgid "Inline math"
msgstr "Вбудована математика"
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Input host keys manually"
msgstr "Введіть ключі хоÑта вручну"
@@ -25637,7 +25532,7 @@ msgid "Integrations|All projects inheriting these settings will also be reset."
msgstr ""
msgid "Integrations|An application called %{integration_name} is requesting access to your GitLab account. This application was created by GitLab Inc."
-msgstr ""
+msgstr "Програма під назвою %{integration_name} запитує доÑтуп до вашого облікового запиÑу GitLab. Ð¦Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð° була Ñтворена GitLab Inc."
msgid "Integrations|An error occurred while loading projects using custom settings."
msgstr ""
@@ -25646,7 +25541,7 @@ msgid "Integrations|An event will be triggered when one of the following items h
msgstr ""
msgid "Integrations|Authorize %{integration_name} (%{user}) to use your account?"
-msgstr ""
+msgstr "Ðвторизувати %{integration_name} (%{user}) Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ облікового запиÑу?"
msgid "Integrations|Branches for which notifications are to be sent"
msgstr ""
@@ -25831,6 +25726,9 @@ msgstr "Задачі ZenTao відображаютьÑÑ Ñ‚ÑƒÑ‚, коли ви Ñ
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr "Ðе може перевищувати %{recipients_limit}"
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr "IntelliJ IDEA (HTTPS)"
@@ -25867,15 +25765,9 @@ msgstr "Внутрішні кориÑтувачі не можуть бути дÐ
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "Шаблон інтервалу"
-
msgid "Introducing Your DevOps Reports"
msgstr "ПредÑтавлÑємо ваші DevOps звіти"
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25957,9 +25849,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr "ÐедійÑний двофакторний код підтвердженнÑ."
-msgid "Invalid yaml"
-msgstr "ÐедійÑний yaml"
-
msgid "Invalidated"
msgstr "Визнано недійÑним"
@@ -26294,18 +26183,12 @@ msgstr "вирішено вÑÑ– теми"
msgid "IssuableEvents|unassigned"
msgstr "непризначено"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type} Ñтворено %{created_at} кориÑтувачем "
-
msgid "IssuableStatus|Closed"
msgstr "Закрито"
msgid "IssuableStatus|Closed (%{link})"
msgstr "Закрито (%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "Ñтворено %{created_at}"
-
msgid "IssuableStatus|duplicated"
msgstr "продубльовано"
@@ -26555,29 +26438,51 @@ msgstr "Задачі без призначеного епіку"
msgid "Issues, merge requests, pushes, and comments."
msgstr "Задачі, запити на злиттÑ, Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð´Ñƒ Ñ– коментарі."
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "ПіÑÐ»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð´Ð°Ñ‡ Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… проєктів, ми зможемо почати відÑтежувати Ñ– відображати метрики Ð´Ð»Ñ Ð½Ð¸Ñ…"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Ð’ Ñередньому за міÑÑць:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr ""
+
msgid "IssuesAnalytics|Issues created"
msgstr "Створені задачі"
msgid "IssuesAnalytics|Issues created per month"
msgstr "Створені задачі за міÑÑць"
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "ОÑтанні 12 міÑÑців"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr ""
+
+msgid "IssuesAnalytics|Opened"
+msgstr ""
+
+msgid "IssuesAnalytics|Overview"
+msgstr ""
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Ðа жаль, немає результатів, Ñкі відповідають фільтру"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "Ðемає задач Ð´Ð»Ñ Ð²ÑÑ–Ñ… проєктів у групі"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "Щоб розширити пошук, будь лаÑка, змініть або видаліть фільтр вище"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr "Ð’Ñього:"
@@ -26595,7 +26500,7 @@ msgid "Issues|Test cases can not be moved."
msgstr ""
msgid "Issues|There was an error while moving the issues."
-msgstr ""
+msgstr "Помилка при переміщенні задач."
msgid "Issue|Title"
msgstr "Ðазва"
@@ -26624,6 +26529,9 @@ msgstr ""
msgid "Italic text"
msgstr "ТекÑÑ‚ курÑивом"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr "ІтераціÑ"
@@ -26960,6 +26868,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27417,7 +27328,7 @@ msgid "Jobs|You're about to retry a job that failed because it attempted to depl
msgstr ""
msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id}"
-msgstr ""
+msgstr "%{boldStart}Конвеєр%{boldEnd} %{id}"
msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source}"
msgstr "ЗавданнÑ%{boldStart}Конвеєр%{boldEnd} %{id} Ð´Ð»Ñ %{mrId} з %{source}"
@@ -27426,7 +27337,7 @@ msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into
msgstr "ЗавданнÑ%{boldStart}Конвеєр%{boldEnd} %{id} Ð´Ð»Ñ %{mrId} з %{source} на %{target}"
msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}"
-msgstr ""
+msgstr "Job|%{boldStart}Конвеєр%{boldEnd} %{id} Ð´Ð»Ñ %{ref}"
msgid "Job|%{searchLength} results found for %{searchTerm}"
msgstr "%{searchLength} результатів знайдено Ð´Ð»Ñ %{searchTerm}"
@@ -27458,6 +27369,9 @@ msgstr "ТриваліÑÑ‚ÑŒ"
msgid "Job|Erase job log and artifacts"
msgstr "Стерти лог завдань та артефакти"
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr "Ðевдало"
@@ -27509,6 +27423,9 @@ msgstr "Повторити"
msgid "Job|Run again"
msgstr "ЗапуÑтити знову"
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr "ВиконуєтьÑÑ"
@@ -27605,9 +27522,6 @@ msgstr "ДолучитиÑÑ Ð´Ð¾ проєкту"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27874,9 +27788,6 @@ msgstr "ОÑÑ‚Ð°Ð½Ð½Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ñ–ÑÑ‚ÑŒ"
msgid "Last Name"
msgstr "Прізвище"
-msgid "Last Pipeline"
-msgstr "ОÑтанній Конвеєр"
-
msgid "Last Seen"
msgstr "ВоÑтаннє переглÑнуте"
@@ -27973,6 +27884,9 @@ msgstr "Ви відправили зміни до"
msgid "LastPushEvent|at"
msgstr "в"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr "ОÑтанні зміни"
@@ -28688,6 +28602,9 @@ msgstr "Заблокувати %{issuableType}"
msgid "Lock File?"
msgstr "Заблокувати файл?"
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr "ЗафікÑувати належноÑÑ‚Ñ– (до груп) через LDAP Ñинхронізацію"
@@ -28697,6 +28614,9 @@ msgstr ""
msgid "Lock not found"
msgstr "Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ðµ знайдено"
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ"
@@ -28899,7 +28819,7 @@ msgid "Manage branch rules"
msgstr ""
msgid "Manage git repositories with fine-grained access controls that keep your code secure."
-msgstr ""
+msgstr "Керуйте git-репозиторіÑми за допомогою ретельно продуманих заÑобів контролю доÑтупу, Ñкі захищають ваш код."
msgid "Manage group labels"
msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ñ–Ñ‚ÐºÐ°Ð¼Ð¸ групи"
@@ -28995,7 +28915,7 @@ msgid "Markdown enabled."
msgstr "Markdown активовано."
msgid "Markdown is supported"
-msgstr ""
+msgstr "Markdown підтримуєтьÑÑ"
msgid "Markdown supported."
msgstr "ПідтримуєтьÑÑ Markdown."
@@ -29102,6 +29022,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr "Додати в Mattermost"
@@ -29117,6 +29043,9 @@ msgstr "Вкажіть Ñлово, Ñке найбільше підходить
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr "URL-адреÑа Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ"
@@ -29129,6 +29058,9 @@ msgstr "Піктограма Ð´Ð»Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ñ–"
msgid "MattermostService|Response username"
msgstr "Ð†Ð¼â€™Ñ ÐºÐ¾Ñ€Ð¸Ñтувача Ð´Ð»Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ñ–"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr "Пропозиції:"
@@ -29435,6 +29367,102 @@ msgstr "%{member_name} запроÑив Ð²Ð°Ñ Ð¿Ñ€Ð¸Ñ”Ð´Ð½Ð°Ñ‚Ð¸ÑÑ Ð´Ð¾ GitLa
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ñ”Ð´Ð½Ð°Ñ‚Ð¸ÑÑ Ð´Ð¾ %{project_or_group} %{project_or_group_name}"
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29699,6 +29727,9 @@ msgstr "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ-злиттÑ"
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr "Деталі об’єднаннÑ"
@@ -29892,10 +29923,10 @@ msgid "MergeRequests|Create issue to resolve thread"
msgstr "Створити задачу, щоб вирішити обговореннÑ"
msgid "MergeRequests|Drafts cannot be merged until marked ready."
-msgstr ""
+msgstr "Чернетки не можна об'єднувати, доки не буде позначено Готово."
msgid "MergeRequests|Mark as draft"
-msgstr ""
+msgstr "Позначити Ñк чернетка"
msgid "MergeRequests|Merge request cherry-pick failed"
msgstr ""
@@ -30131,9 +30162,6 @@ msgstr "Метрики та профілюваннÑ"
msgid "Metrics:"
msgstr "Метрики:"
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr "Створити метрику"
@@ -30230,6 +30258,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30607,7 +30638,7 @@ msgid "MlExperimentTracking|Model candidate details"
msgstr ""
msgid "MlExperimentTracking|Model experiments"
-msgstr ""
+msgstr "Модель екÑпериментів."
msgid "MlExperimentTracking|Model registry"
msgstr ""
@@ -30631,10 +30662,10 @@ msgid "MlExperimentTracking|Parameters"
msgstr "Параметри"
msgid "MlExperimentTracking|Status"
-msgstr ""
+msgstr "СтатуÑ"
msgid "MlExperimentTracking|Triggered by"
-msgstr ""
+msgstr "Ініційовано"
msgid "Modal updated"
msgstr ""
@@ -30646,7 +30677,7 @@ msgid "Modal|Close"
msgstr "Закрити"
msgid "Model experiments"
-msgstr ""
+msgstr "Модель екÑпериментів."
msgid "ModelRegistry|Model registry"
msgstr ""
@@ -30838,7 +30869,7 @@ msgid "My awesome group"
msgstr ""
msgid "My comment templates"
-msgstr ""
+msgstr "Мої шаблони коментарів"
msgid "My company or team"
msgstr "ÐœÐ¾Ñ ÐºÐ¾Ð¼Ð¿Ð°Ð½Ñ–Ñ Ð°Ð±Ð¾ команда"
@@ -31114,10 +31145,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -31195,6 +31226,9 @@ msgstr "Ðналіз"
msgid "Navigation|Build"
msgstr "Збірка"
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr "Код"
@@ -31225,15 +31259,18 @@ msgstr "Тут з'ÑвлÑÑ‚ÑŒÑÑ Ð³Ñ€ÑƒÐ¿Ð¸, Ñкі ви чаÑто відві
msgid "Navigation|Leave admin mode"
msgstr "Вийти з режиму адмініÑтратора"
-msgid "Navigation|Main navigation"
-msgstr "ОÑновна навігаціÑ"
-
msgid "Navigation|Manage"
msgstr "УправліннÑ"
+msgid "Navigation|Merge requests settings"
+msgstr ""
+
msgid "Navigation|Monitor"
msgstr "Моніторинг"
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr "Жодної групи не знайдено"
@@ -31252,12 +31289,18 @@ msgstr "Закріплено"
msgid "Navigation|Plan"
msgstr "План"
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr "Проєкти"
msgid "Navigation|Projects you visit often will appear here."
msgstr "Тут з'ÑвлÑÑ‚ÑŒÑÑ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ð¸, Ñкі ви чаÑто відвідуєте."
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr "ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ñ–Ð² пошуку"
@@ -31276,6 +31319,12 @@ msgstr "Помилка при отриманні результатів пошу
msgid "Navigation|Unpin item"
msgstr "Відкріпити елемент"
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr "ПереглÑнути вÑÑ– ваші групи"
@@ -31502,9 +31551,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr "Згенеровано новий реєÑтраційний токен раннерів!"
-msgid "New schedule"
-msgstr "Ðовий Розклад"
-
msgid "New snippet"
msgstr "Ðовий Ñніпет"
@@ -31712,6 +31758,9 @@ msgstr "Ðемає ітерації"
msgid "No label"
msgstr "Без мітки"
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr "Ðемає міток з таким іменем або опиÑом"
@@ -31736,6 +31785,12 @@ msgstr "Ðемає відповідних результатів"
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31754,12 +31809,15 @@ msgstr "Етап відÑутній"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
-msgstr "Ðемає інших міток з таким іменем або опиÑом"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
msgstr ""
+msgid "No other labels with such name or description"
+msgstr "Ðемає інших міток з таким іменем або опиÑом"
+
msgid "No parent group"
msgstr "Ðемає батьківÑької групи"
@@ -31814,9 +31872,6 @@ msgstr "Результатів не знайдено."
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "Ðемає розкладів"
-
msgid "No service accounts"
msgstr ""
@@ -31868,6 +31923,12 @@ msgstr "Ðемає подій вебхука"
msgid "No webhooks enabled. Select trigger events above."
msgstr "Веб-хуки не увімкнено. Виберіть тригерні події вище."
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32411,7 +32472,7 @@ msgid "Notify|Pipeline %{pipeline_name_or_id} has passed!"
msgstr "Конвеєр %{pipeline_name_or_id} уÑпішно виконано!"
msgid "Notify|Pipeline has been fixed and %{pipeline_name_or_id} has passed!"
-msgstr "Конвеєр було виправлено Ñ– %{pipeline_name_or_id} уÑпішно виконано!"
+msgstr "Конвеєр %{pipeline_name_or_id} був виправлений та уÑпішно виконаний!"
msgid "Notify|Please check that your service provider supports email subaddressing and that you have set up email forwarding correctly."
msgstr ""
@@ -33087,6 +33148,9 @@ msgstr "Один чи кілька ваших перÑональних токеÐ
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr "Термін дії одного або декількох ваших токенів оÑобиÑтого доÑтупу закінчитьÑÑ Ñ‡ÐµÑ€ÐµÐ· %{days_to_expire} днів або раніше:"
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -33114,9 +33178,6 @@ msgstr "ДоÑтупно лише Ð´Ð»Ñ %{membersPageLinkStart}учаÑникі
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr "Ефективно тільки при увімкненому віддаленому Ñховищі. Ð’Ñтановіть 0 Ð´Ð»Ñ Ð½ÐµÐ¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð¾Ð³Ð¾ розміру."
-
msgid "Only include features new to your current subscription tier."
msgstr "Додавати лише нові функції Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ поточного Ñ€Ñ–Ð²Ð½Ñ Ð¿Ñ–Ð´Ð¿Ð¸Ñки."
@@ -33279,24 +33340,60 @@ msgstr "Параметри"
msgid "Ordered list"
msgstr "УпорÑдкований ÑпиÑок"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "ОрганізаціÑ"
-msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
msgstr ""
+msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgstr "Помилка при завантаженні груп. Будь лаÑка, оновіть Ñторінку, щоб Ñпробувати ще раз."
+
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33911,10 +34008,10 @@ msgid "PackageRegistry|There are no packages yet"
msgstr "Пакетів ще немає"
msgid "PackageRegistry|There are security risks if packages are deleted while request forwarding is enabled. %{docLinkStart}What are the risks?%{docLinkEnd}"
-msgstr ""
+msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÑ–Ð² при увімкненому переÑиланні запитів може Ñтановити загрозу безпеці. %{docLinkStart}Які ризики?%{docLinkEnd}"
msgid "PackageRegistry|There are security risks if packages are deleted while request forwarding is enabled. %{docs_link_start}What are the risks?%{docs_link_end}"
-msgstr ""
+msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ð°ÐºÑƒÐ½ÐºÑ–Ð² при увімкненому перенаправленні запитів може призвеÑти до ризиків Ð´Ð»Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸. %{docs_link_start}Які ризики?%{docs_link_end}"
msgid "PackageRegistry|There was a problem fetching the details for this package."
msgstr "Виникла проблема при отриманні інформації про цей пакет."
@@ -34012,6 +34109,9 @@ msgstr "Сторінки"
msgid "Pages Domain"
msgstr "Домен Pages"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr "Перша"
@@ -34159,7 +34259,10 @@ msgstr "ШлÑÑ…"
msgid "Path:"
msgstr "ШлÑÑ…:"
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34214,7 +34317,7 @@ msgid "Perform advanced options such as changing path, transferring, exporting,
msgstr "Виконуйте такі розширені операції, Ñк зміна шлÑху, перенеÑеннÑ, екÑпорт чи Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸."
msgid "Perform code reviews and enhance collaboration with merge requests."
-msgstr ""
+msgstr "Виконуйте перевірку коду та покращуйте Ñпівпрацю за допомогою запитів на злиттÑ."
msgid "Perform common operations on GitLab project"
msgstr "Виконати звичайні операції на проєкті GitLab"
@@ -34601,14 +34704,11 @@ msgid "PipelineGraph|What is a downstream pipeline?"
msgstr ""
msgid "PipelineScheduleIntervalPattern|Custom (%{linkStart}Learn more%{linkEnd}.)"
-msgstr ""
+msgstr "ВлаÑний (%{linkStart}дізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{linkEnd}.)"
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr "Запланований конвеєр автоматично починаєтьÑÑ Ð· регулÑрних інтервалів, Ñк Ñ‰Ð¾Ð´Ð½Ñ Ð°Ð±Ð¾ щотижнÑ. Конвеєр: "
-msgid "PipelineSchedules|Activated"
-msgstr "Ðктивовано"
-
msgid "PipelineSchedules|Active"
msgstr "Ðктивні"
@@ -34652,7 +34752,7 @@ msgid "PipelineSchedules|Inactive"
msgstr "Ðеактивні"
msgid "PipelineSchedules|Interval Pattern"
-msgstr ""
+msgstr "Інтервальний шаблон"
msgid "PipelineSchedules|Last Pipeline"
msgstr "ОÑтанній Конвеєр"
@@ -34694,7 +34794,7 @@ msgid "PipelineSchedules|Runs for a specific branch or tag."
msgstr "Виконує Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ñ— гілки або тегу."
msgid "PipelineSchedules|Runs with the same project permissions as the schedule owner."
-msgstr ""
+msgstr "ЗапуÑкаєтьÑÑ Ð· тими ж правами доÑтупу до проєкту, що й у влаÑника розкладу."
msgid "PipelineSchedules|Successfully scheduled a pipeline to run. Go to the %{linkStart}Pipelines page%{linkEnd} for details. "
msgstr "УÑпішно заплановано конвеєр Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку. Перейдіть на Ñторінку %{linkStart}Конвеєрів%{linkEnd} Ð´Ð»Ñ Ð´ÐµÑ‚Ð°Ð»ÐµÐ¹. "
@@ -34723,12 +34823,6 @@ msgstr "Виникла проблема з запуÑком розкладу кÐ
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "Змінні"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr "Стати влаÑником Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ"
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34868,7 +34962,7 @@ msgid "Pipelines|Build with confidence"
msgstr "Виконуйте збірки із впевненіÑÑ‚ÑŽ"
msgid "Pipelines|Building for iOS?"
-msgstr ""
+msgstr "Розробка Ð´Ð»Ñ iOS?"
msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
msgstr ""
@@ -34958,7 +35052,7 @@ msgid "Pipelines|Let's get that runner set up! %{emojiStart}tada%{emojiEnd}"
msgstr ""
msgid "Pipelines|Lint"
-msgstr ""
+msgstr "Перевірка конфігурації (Lint)"
msgid "Pipelines|Loading Pipelines"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð²"
@@ -35069,10 +35163,10 @@ msgid "Pipelines|Token"
msgstr "Токен"
msgid "Pipelines|Total amount of compute minutes used for the pipeline"
-msgstr ""
+msgstr "Загальна кількіÑÑ‚ÑŒ обчиÑлювальних хвилин, викориÑтаних Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð°"
msgid "Pipelines|Total number of jobs for the pipeline"
-msgstr ""
+msgstr "Загальна кількіÑÑ‚ÑŒ завдань Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð°"
msgid "Pipelines|Trigger user has insufficient permissions to project"
msgstr ""
@@ -35084,7 +35178,7 @@ msgid "Pipelines|Try test template"
msgstr "Спробуйте теÑтовий шаблон"
msgid "Pipelines|Unable to create pipeline"
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ñтворити конвеєр"
msgid "Pipelines|Unable to validate CI/CD configuration. See the %{linkStart}GitLab CI/CD troubleshooting guide%{linkEnd} for more details."
msgstr ""
@@ -35135,7 +35229,7 @@ msgid "Pipelines|error"
msgstr "помилка"
msgid "Pipelines|finished"
-msgstr ""
+msgstr "завершено"
msgid "Pipelines|invalid"
msgstr "недійÑний"
@@ -35179,6 +35273,9 @@ msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ ÑÑ‚Ð°Ñ‚ÑƒÑ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð°. Дл
msgid "Pipeline|Created"
msgstr "Створено"
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -35302,9 +35399,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr "Ðвтор тригера"
-msgid "Pipeline|Triggerer"
-msgstr "Запущено"
-
msgid "Pipeline|Variables"
msgstr "Змінні"
@@ -35324,7 +35418,7 @@ msgid "Pipeline|for"
msgstr "ДлÑ"
msgid "Pipeline|merge request"
-msgstr ""
+msgstr "запит на злиттÑ"
msgid "Pipeline|merge train"
msgstr ""
@@ -35827,9 +35921,6 @@ msgstr "Ширина макета"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "Повинно бути чиÑлом від %{min} до %{max}"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr "Примітка: ви ввімкнули нову навігацію, тому лише темний режим Ñ–Ñтотно змінює зовнішній виглÑд GitLab."
-
msgid "Preferences|Preview"
msgstr "Попередній переглÑд"
@@ -35941,6 +36032,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -36032,7 +36126,7 @@ msgid "ProductAnalytics|All Features"
msgstr ""
msgid "ProductAnalytics|All Pages"
-msgstr ""
+msgstr "Ð’ÑÑ– Ñторінки"
msgid "ProductAnalytics|All Sessions Compared"
msgstr ""
@@ -36064,9 +36158,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -36082,9 +36173,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -36121,9 +36209,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr "ПовернутиÑÑ Ð½Ð°Ð·Ð°Ð´"
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -36184,6 +36269,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -36208,9 +36296,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -36442,7 +36527,7 @@ msgstr "Ðе показувати у моєму профілі оÑобиÑту
msgid "Profiles|Edit Profile"
msgstr "Редагувати профіль"
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36797,7 +36882,7 @@ msgid "Project URL"
msgstr "URL-адреÑа проєкту"
msgid "Project access token creation is disabled in this group."
-msgstr ""
+msgstr "У цій групі відключено ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð¾ÐºÐµÐ½Ñ–Ð² доÑтупу до проєкту."
msgid "Project already deleted"
msgstr "Проєкт уже було видалено"
@@ -36877,9 +36962,6 @@ msgstr "Проєкт або Група"
msgid "Project order will not be saved as local storage is not available."
msgstr "ПорÑдок проєктів не буде збережено, тому що локальне Ñховище недоÑтупне."
-msgid "Project overview"
-msgstr "ОглÑд проєкту"
-
msgid "Project path"
msgstr "ШлÑÑ… до проєкту"
@@ -37235,7 +37317,7 @@ msgid "ProjectSettings|Allow anyone to pull from Package Registry"
msgstr "Дозволити будь-кому отримувати дані з реєÑтру пакетів"
msgid "ProjectSettings|Always show thumbs-up and thumbs-down emoji buttons on issues, merge requests, and snippets."
-msgstr ""
+msgstr "Завжди показувати кнопки емодзі \"подобаєтьÑÑ\" Ñ– \"не подобаєтьÑÑ\" на задачах, запитах на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° Ñніпетах."
msgid "ProjectSettings|Analytics"
msgstr "Ðналітика"
@@ -37316,7 +37398,7 @@ msgid "ProjectSettings|Enable \"Delete source branch\" option by default"
msgstr "Увімкнути параметр \"Видалити початкову гілку\" за замовчуваннÑм"
msgid "ProjectSettings|Enable email notifications"
-msgstr ""
+msgstr "Увімкнути ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾ÑŽ поштою"
msgid "ProjectSettings|Enable merge trains"
msgstr ""
@@ -37325,7 +37407,7 @@ msgid "ProjectSettings|Enable merged results pipelines"
msgstr ""
msgid "ProjectSettings|Enable sending email notifications for this project"
-msgstr ""
+msgstr "Увімкнути надÑÐ¸Ð»Ð°Ð½Ð½Ñ Ñповіщень на електронну пошту Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
msgid "ProjectSettings|Enable suggested reviewers"
msgstr ""
@@ -37369,6 +37451,12 @@ msgstr "Перемикачі функцій"
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "Гнучкий інÑтрумент Ð´Ð»Ñ Ñпільної розробки ідей та Ð¿Ð»Ð°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ в цьому проєкті."
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr "Форки"
@@ -37379,7 +37467,7 @@ msgid "ProjectSettings|Global"
msgstr "Глобальні"
msgid "ProjectSettings|Highlight the usage of hidden unicode characters. These have innocent uses for right-to-left languages, but can also be used in potential exploits."
-msgstr ""
+msgstr "ПідÑвічувати викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸Ñ…Ð¾Ð²Ð°Ð½Ð¸Ñ… Ñимволів Unicode. Вони мають невинне викориÑÑ‚Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¼Ð¾Ð², Ñкі пишутьÑÑ Ñправа наліво, але також можуть викориÑтовуватиÑÑ Ð´Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¸Ñ… атак."
msgid "ProjectSettings|Housekeeping, export, archive, change path, transfer, and delete."
msgstr "ОчищеннÑ, екÑпорт, архівуваннÑ, зміна шлÑху, перенеÑÐµÐ½Ð½Ñ Ñ‚Ð° видаленнÑ."
@@ -37454,7 +37542,7 @@ msgid "ProjectSettings|Merging is only allowed when the source branch is up-to-d
msgstr "Ð—Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÐµÐ½Ð¾ лише тоді, коли гілка-джерело Ñ” актуальною Ð´Ð»Ñ Ñ†Ñ–Ð»ÑŒÐ¾Ð²Ð¾Ñ— гілки."
msgid "ProjectSettings|Model experiments"
-msgstr ""
+msgstr "Модель екÑпериментів."
msgid "ProjectSettings|Monitor"
msgstr "Моніторинг"
@@ -37466,7 +37554,7 @@ msgid "ProjectSettings|No merge commits are created."
msgstr "Коміти Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð½Ðµ ÑтворюютьÑÑ."
msgid "ProjectSettings|Note: The container registry is always visible when a project is public and the container registry is set to '%{access_level_description}'"
-msgstr ""
+msgstr "Примітка: РеєÑÑ‚Ñ€ контейнерів завжди видно, коли проєкт Ñ” публічним Ñ– реєÑÑ‚Ñ€ контейнерів вÑтановлено на рівень доÑтупу '%{access_level_description}'."
msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
msgstr "До цього репозиторію можуть бути переміщені лише Ñ‚Ñ– коміти, Ñкі міÑÑ‚ÑÑ‚ÑŒ елемент %{code_block_start}Signed-off-by:%{code_block_end}."
@@ -37504,6 +37592,9 @@ msgstr "Публічний"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr "ПублікаціÑ, Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ñ‚Ð° переглÑд пакетів у проєкті."
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr "Релізи"
@@ -37535,7 +37626,7 @@ msgid "ProjectSettings|Security and Compliance"
msgstr "Безпека та відповідніÑÑ‚ÑŒ"
msgid "ProjectSettings|Security and compliance for this project."
-msgstr ""
+msgstr "Безпека та відповідніÑÑ‚ÑŒ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту."
msgid "ProjectSettings|Select a project"
msgstr ""
@@ -37550,10 +37641,10 @@ msgid "ProjectSettings|Set the default behavior of this option in merge requests
msgstr ""
msgid "ProjectSettings|Share code with others outside the project."
-msgstr ""
+msgstr "ПоділітьÑÑ ÐºÐ¾Ð´Ð¾Ð¼ з іншими оÑобами поза межами проєкту."
msgid "ProjectSettings|Show default emoji reactions"
-msgstr ""
+msgstr "Показати типові реакції з емодзі."
msgid "ProjectSettings|Show link to create or view a merge request when pushing from the command line"
msgstr "Показувати поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‡Ð¸ переглÑду запиту на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð¿Ñ€Ð¸ відправці із командного Ñ€Ñдка"
@@ -37576,6 +37667,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37664,7 +37758,7 @@ msgid "ProjectSettings|Visibility options for this fork are limited by the curre
msgstr "Параметри видимоÑÑ‚Ñ– Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ форка обмежені поточною видиміÑÑ‚ÑŽ вихідного проєкту."
msgid "ProjectSettings|Warn about Potentially Unwanted Characters"
-msgstr ""
+msgstr "Попереджувати про можливо небажані Ñимволи."
msgid "ProjectSettings|What are badges?"
msgstr "Що таке значки?"
@@ -37688,7 +37782,7 @@ msgid "ProjectSettings|Wiki"
msgstr "Вікі"
msgid "ProjectSettings|With GitLab Pages you can host your static websites on GitLab. GitLab Pages uses a caching mechanism for efficiency. Your changes may not take effect until that cache is invalidated, which usually takes less than a minute."
-msgstr ""
+msgstr "За допомогою GitLab Pages ви можете розміщувати Ñвої Ñтатичні вебÑайт на GitLab. GitLab Pages викориÑтовує механізм ÐºÐµÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¿Ñ–Ð´Ð²Ð¸Ñ‰ÐµÐ½Ð½Ñ ÐµÑ„ÐµÐºÑ‚Ð¸Ð²Ð½Ð¾ÑÑ‚Ñ–. Ваші зміни можуть не негайно відображатиÑÑ, поки не буде ÑкаÑований кеш, що, Ñк правило, зазвичай займає менше ніж хвилину."
msgid "ProjectSettings|You need to %{linkStart}set up product analytics%{linkEnd} before your application can be instrumented."
msgstr ""
@@ -37961,7 +38055,7 @@ msgid "ProjectsNew|Pick a group or namespace where you want to create this proje
msgstr ""
msgid "ProjectsNew|Project Configuration"
-msgstr ""
+msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
msgstr "ÐžÐ¿Ð¸Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ %{tag_start}(необов’Ñзково)%{tag_end}"
@@ -38395,6 +38489,12 @@ msgstr "Ð—Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ð»Ð°Ñника коду"
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -38467,7 +38567,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38526,10 +38626,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr "Редагувати"
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38541,6 +38644,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38559,6 +38665,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} буде доÑупне Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу Ð´Ð»Ñ Ñ€Ð¾Ð·Ñ€Ð¾Ð±Ð½Ð¸ÐºÑ–Ð². Ви впевнені?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38616,9 +38725,6 @@ msgstr "Виберіть Ñередовище"
msgid "ProtectedEnvironment|Select groups"
msgstr "Виберіть групи"
-msgid "ProtectedEnvironment|Select users"
-msgstr "Виберіть кориÑтувачів"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38685,9 +38791,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr "Публічний"
@@ -39004,7 +39107,7 @@ msgid "Read more"
msgstr "Докладніше"
msgid "Read more about GitLab at %{link_to_promo}."
-msgstr ""
+msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про GitLab на %{link_to_promo}."
msgid "Read more about the %{changes_link_start}changes%{link_end}, the %{vision_link_start}vision%{link_end}, and the %{design_link_start}design%{link_end}."
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про %{changes_link_start}зміни%{link_end}, %{vision_link_start}баченнÑ%{link_end} та %{design_link_start}дизайн%{link_end}."
@@ -39048,9 +39151,6 @@ msgstr "Отримуйте ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ повідомленнÑ
msgid "Receive notifications about your own activity"
msgstr "Отримувати ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ влаÑну активніÑÑ‚ÑŒ"
-msgid "Receive product marketing emails"
-msgstr "Отримуйте маркетингові розÑилки на електронну пошту"
-
msgid "Recent"
msgstr "ОÑтанні"
@@ -39193,34 +39293,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39557,9 +39633,6 @@ msgstr ""
msgid "Remove priority"
msgstr "Видалити пріоритет"
-msgid "Remove report"
-msgstr "Видалити звіт"
-
msgid "Remove reviewer"
msgstr "Видалити оглÑдача"
@@ -39572,6 +39645,9 @@ msgstr ""
msgid "Remove spent time"
msgstr "Видалити витрачений чаÑ"
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr "Видалити запланований чаÑ"
@@ -39581,9 +39657,6 @@ msgstr ""
msgid "Remove user"
msgstr "Видалити кориÑтувача"
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr "Видалити кориÑтувача з групи"
@@ -39863,12 +39936,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Повідомлено %{timeAgo} кориÑтувачем %{reportedBy}"
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr "Репортер"
@@ -40187,9 +40254,6 @@ msgstr "Розпочато перерахунок викориÑÑ‚Ð°Ð½Ð½Ñ ÑÑ…Ð
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "Вибрати"
-
msgid "Request"
msgstr "Запит"
@@ -40611,6 +40675,9 @@ msgstr ""
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -41051,6 +41118,9 @@ msgstr "УчаÑники %{type} можуть зареєÑтрувати ранÐ
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr "Декілька тегів мають бути розділені комою. Ðаприклад, %{example}."
@@ -41341,7 +41411,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr "Виберіть потрібний вам раннер, а потім виберіть ємніÑÑ‚ÑŒ Ð´Ð»Ñ Ð½ÑŒÐ¾Ð³Ð¾ в конÑолі AWS CloudFormation."
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -41426,6 +41496,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41637,6 +41710,9 @@ msgstr "Щоб дозволити %{strongOpen}%{group_name}%{strongClose} кеÑ
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr "Токен SCIM"
@@ -41745,9 +41821,6 @@ msgstr ""
msgid "Save password"
msgstr "Зберегти пароль"
-msgid "Save pipeline schedule"
-msgstr "Зберегти розклад конвеєра"
-
msgid "Saving"
msgstr "ЗбереженнÑ"
@@ -41760,7 +41833,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41886,10 +41959,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41904,6 +41980,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41916,7 +42010,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41928,7 +42022,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41940,6 +42034,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41967,9 +42067,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -42081,6 +42190,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr "Пошук Ñпецифікації Ñередовища"
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr "Пошук виконавців"
@@ -42150,15 +42262,12 @@ msgstr "Пошук етапів"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
-msgstr "Шукати чи фільтрувати результати..."
-
msgid "Search or filter results…"
msgstr "Шукати чи фільтрувати результати…"
+msgid "Search or go to…"
+msgstr "Знайдіть або перейдіть до…"
+
msgid "Search page"
msgstr "Сторінка пошуку"
@@ -42399,7 +42508,7 @@ msgid "Security and Compliance"
msgstr "Безпека та відповідніÑÑ‚ÑŒ"
msgid "Security capabilities"
-msgstr ""
+msgstr "МожливоÑÑ‚Ñ– безпеки"
msgid "Security configuration"
msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸"
@@ -42407,6 +42516,9 @@ msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸"
msgid "Security dashboard"
msgstr "Панель безпеки"
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42450,7 +42562,7 @@ msgid "SecurityConfiguration|Configure %{feature}"
msgstr ""
msgid "SecurityConfiguration|Configure with a merge request"
-msgstr ""
+msgstr "Ðалаштуйте за допомогою запиту на злиттÑ"
msgid "SecurityConfiguration|Copy code and open .gitlab-ci.yml file"
msgstr ""
@@ -42563,6 +42675,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42572,7 +42690,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42629,6 +42753,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42701,7 +42828,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42713,12 +42840,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ образи."
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42987,6 +43120,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42999,13 +43135,13 @@ msgstr "Вік вразливоÑÑ‚Ñ– менше ніж %{vulnerabilityAge}."
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -43035,13 +43171,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr "гілка"
msgid "SecurityOrchestration|branches"
msgstr "гілки"
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -43050,6 +43192,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -43119,9 +43267,6 @@ msgstr "Додати коментар (обов'Ñзково)"
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -43176,6 +43321,9 @@ msgstr "Коментар відредаговано в \"%{vulnerabilityName}\""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -43191,9 +43339,15 @@ msgstr "ВиÑвленнÑ"
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "Відхилити вразливіÑÑ‚ÑŒ"
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "Відхилено \"%{vulnerabilityName}\""
@@ -43224,6 +43378,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -43341,9 +43498,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -43390,7 +43544,7 @@ msgstr "Ð’Ñе ще виÑвлено"
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43738,9 +43892,6 @@ msgstr "ÐадÑилайте електронну пошту в багатоко
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "ÐадÑилати електронні лиÑти, щоб допомогти новим кориÑтувачам пройти Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð°Ð´Ð°Ð¿Ñ‚Ð°Ñ†Ñ–Ñ—."
-
msgid "Send emails to users upon account deactivation."
msgstr "ÐадÑилати електронні лиÑти кориÑтувачам піÑÐ»Ñ Ð´ÐµÐ°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ñ–Ñ— облікового запиÑу."
@@ -43810,6 +43961,9 @@ msgstr ""
msgid "Service Desk"
msgstr "Служба підтримки"
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43834,12 +43988,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43867,9 +44033,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43879,27 +44051,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43939,15 +44144,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43975,6 +44210,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr "ТриваліÑÑ‚ÑŒ ÑеÑÑ–Ñ— (у хвилинах)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "Ð’Ñтановити %{epic_ref} Ñк батьківÑький епік."
@@ -44095,6 +44333,9 @@ msgstr "Ð’Ñтановити запланований Ñ‡Ð°Ñ %{time_estimate}."
msgid "Set to 0 for no size limit."
msgstr "Ð’Ñтановіть Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ 0 Ð´Ð»Ñ Ð²Ñ–Ð´ÑутноÑÑ‚Ñ– ліміту розміру."
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -44173,6 +44414,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr "Ð’Ñтановлює %{epic_ref} Ñк батьківÑький епік."
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -45012,6 +45256,9 @@ msgstr "ХтоÑÑŒ увійшов у ваш обліковий Ð·Ð°Ð¿Ð¸Ñ %{host
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "ЩоÑÑŒ пішло не так"
@@ -45105,9 +45352,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr "Помилка при отриманні оÑтанніх коментарів."
-
msgid "Something went wrong while fetching projects"
msgstr "Помилка при отриманні проєктів"
@@ -46056,6 +46300,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr "Завантажити нову ліцензію"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -46203,6 +46459,9 @@ msgstr "УÑпішно деактивовано"
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "УÑпішно видалено адреÑу електронної пошти."
@@ -46221,6 +46480,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr "УÑпішно розблоковано"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr "УÑпішно розблоковано"
@@ -46886,6 +47148,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr "Ціль"
@@ -46898,8 +47163,14 @@ msgstr "Цільовий шлÑÑ…"
msgid "Target branch"
msgstr "Цільова гілка"
-msgid "Target branch or tag"
-msgstr "Цільова гілка або тег"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
+msgstr ""
msgid "Target branch: %{target_branch}"
msgstr ""
@@ -47745,9 +48016,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47922,6 +48190,9 @@ msgstr "ВразливіÑÑ‚ÑŒ більше не виÑвлÑєтьÑÑ. ПерÐ
msgid "There are currently no mirrored repositories."
msgstr "Ðаразі немає віддзеркалених репозиторіїв."
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr "Ñ–Ñнують конфлікти при злитті"
@@ -47940,9 +48211,6 @@ msgstr "Ðемає SSH ключів, що мають доÑтуп до вашоÐ
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr "Повідомлень про Ð·Ð»Ð¾Ð²Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ð½ÐµÐ¼Ð°Ñ”!"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -48192,6 +48460,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -48276,6 +48547,9 @@ msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° з reCAPTCHA. Будь лаÑка, проÐ
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48780,9 +49054,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr "Цей запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾."
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48801,14 +49081,14 @@ msgstr "Цей конвеєр викориÑтовує попередньо ви
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
-msgstr "Цей конвеєр був ініційований розкладом."
+msgid "This pipeline was created by a schedule."
+msgstr ""
msgid "This process deletes the project repository and all related resources."
-msgstr ""
+msgstr "Цей Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð²Ð¸Ð´Ð°Ð»ÑÑ” репозиторій проєкту Ñ– вÑÑ– пов'Ñзані з ним реÑурÑи."
msgid "This project can be restored until %{date}."
msgstr ""
@@ -48832,7 +49112,7 @@ msgid "This project is %{strongStart}NOT%{strongEnd} a fork, and has the followi
msgstr ""
msgid "This project is %{strongStart}NOT%{strongEnd} a fork. This process deletes the project repository and all related resources."
-msgstr ""
+msgstr "Цей проєкт %{strongStart}ÐЕ%{strongEnd} форк. Цей Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚ÑŒ репозиторій проєкту та вÑÑ– пов'Ñзані реÑурÑи."
msgid "This project is archived and cannot be commented on."
msgstr "Цей проєкт заархівовано і його не можна коментувати."
@@ -48954,7 +49234,7 @@ msgstr "Цей кориÑтувач Ñ” автором цього %{workItemType}
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -49080,8 +49360,8 @@ msgstr "ЧаÑовий поÑÑ"
msgid "TimeTrackingEstimated|Est"
msgstr "Запланований чаÑ"
-msgid "TimeTrackingReport|From"
-msgstr "Від"
+msgid "TimeTrackingReport|From the start of"
+msgstr ""
msgid "TimeTrackingReport|Run report"
msgstr ""
@@ -49101,7 +49381,7 @@ msgstr "ПідÑумок"
msgid "TimeTrackingReport|Time spent"
msgstr "Витрачений чаÑ"
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -49530,7 +49810,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49812,6 +50092,9 @@ msgstr ""
msgid "Tomorrow"
msgstr "Завтра"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49894,6 +50177,9 @@ msgstr "Ð’Ñього"
msgid "Total Score"
msgstr "Загальний рахунок"
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr "Ð’Ñього Ñдер (ЦП)"
@@ -49924,9 +50210,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr "ВідÑтеженнÑ"
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49999,6 +50291,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -50366,9 +50670,6 @@ msgstr "URL або ідентифікатор запиту"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -50456,6 +50757,9 @@ msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ віджет запиту нÐ
msgid "Unable to load the page"
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ Ñторінку"
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -50489,9 +50793,6 @@ msgstr "Ðеможливо оновити цей епік в даний моме
msgid "Unable to update this issue at this time."
msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ цю задачу зараз."
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -50570,6 +50871,9 @@ msgstr "Ðа жаль, ваше Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ—
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50817,7 +51121,7 @@ msgid "UpdateProject|Prune"
msgstr ""
msgid "UpdateProject|Prune unreachable objects"
-msgstr ""
+msgstr "Очищати недоÑÑжні об'єкти"
msgid "UpdateProject|Pruning unreachable objects can lead to repository corruption."
msgstr ""
@@ -50945,6 +51249,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr "Пакети коду та образи контейнерів."
@@ -50966,10 +51273,10 @@ msgstr "РеєÑÑ‚Ñ€ контейнерів"
msgid "UsageQuota|Dependency proxy"
msgstr "ПрокÑÑ– залежноÑтей"
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -51017,6 +51324,9 @@ msgstr "ОглÑд проÑтору імен"
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -51051,7 +51361,7 @@ msgid "UsageQuota|Shared bits of code and text."
msgstr "Спільні фрагменти коду та текÑту."
msgid "UsageQuota|Shared runner duration"
-msgstr ""
+msgstr "ТриваліÑÑ‚ÑŒ загальних раннерів"
msgid "UsageQuota|Something went wrong while fetching pipeline statistics"
msgstr ""
@@ -51083,15 +51393,15 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr ""
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr "ПроÑÑ‚Ñ–Ñ€ імен наразі викориÑтовує %{strong_start}%{used_storage}%{strong_end} пам’ÑÑ‚Ñ– проÑтору імен. ПереглÑдайте та керуйте Ñвоїм викориÑтаннÑм із %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{link_end} про те, Ñк зменшити пам’ÑÑ‚ÑŒ."
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr ""
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr ""
@@ -51355,7 +51665,7 @@ msgid "Used by members to sign in to your group in GitLab"
msgstr "ВикориÑтовуєтьÑÑ ÑƒÑ‡Ð°Ñниками Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ñƒ у вашу групу в GitLab"
msgid "Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises."
-msgstr ""
+msgstr "ВикориÑтовуєтьÑÑ Ð¿Ð¾Ð½Ð°Ð´ 100 000 організацій, GitLab Ñ” найбільш популÑрним рішеннÑм ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ git репозиторіÑми."
msgid "Used for account notifications if a %{openingTag}group-specific email address%{closingTag} is not set."
msgstr ""
@@ -51765,6 +52075,9 @@ msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача доÑтупне."
msgid "Username or email"
msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача або електронна пошта"
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача:"
@@ -52069,7 +52382,7 @@ msgid "Variable"
msgstr "Змінна"
msgid "Variable (default)"
-msgstr ""
+msgstr "Змінна (за замовчуваннÑм)"
msgid "Variable name '%{variable}' must not start with '%{prefix}'"
msgstr ""
@@ -52472,6 +52785,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -52491,7 +52807,7 @@ msgid "VulnerabilityExport|Severity"
msgstr ""
msgid "VulnerabilityExport|Status"
-msgstr ""
+msgstr "СтатуÑ"
msgid "VulnerabilityExport|Tool"
msgstr ""
@@ -52499,16 +52815,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "%{statusStart}ВиÑвлено%{statusEnd} %{timeago} в конвеєрі %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52751,6 +53070,9 @@ msgstr "Файл:"
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52865,10 +53187,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52904,6 +53223,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr "ПОПЕРЕДЖЕÐÐЯ:"
@@ -52938,7 +53260,7 @@ msgid "We also use email for avatar detection if no avatar is uploaded."
msgstr "Ми також викориÑтовуємо електронну пошту Ð´Ð»Ñ Ð²Ð¸ÑÐ²Ð»ÐµÐ½Ð½Ñ Ð°Ð²Ð°Ñ‚Ð°Ñ€Ð°, Ñкщо аватара не завантажено."
msgid "We are currently unable to fetch data for the pipeline header."
-msgstr ""
+msgstr "Ðаразі ми не можемо отримати дані Ð´Ð»Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ° конвеєра."
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -53231,6 +53553,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr "Перевірка SSL"
@@ -53333,15 +53661,6 @@ msgstr "ЛаÑкаво проÑимо до нового доÑвіду навіÐ
msgid "Welcome, %{name}!"
msgstr "ЛаÑкаво проÑимо, %{name}!"
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr "Які є приклади?"
@@ -53595,7 +53914,7 @@ msgid "WikiPage|Commit message"
msgstr "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñƒ"
msgid "WikiPage|Content"
-msgstr ""
+msgstr "ВміÑÑ‚"
msgid "WikiPage|Create %{pageTitle}"
msgstr "Створити %{pageTitle}"
@@ -53702,6 +54021,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr "%{count} більше виконавців"
@@ -53796,9 +54121,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr "Створити %{workItemType}"
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr "Створити робочий елемент"
@@ -53817,9 +54139,6 @@ msgstr "Запланована дата завершеннÑ"
msgid "WorkItem|Existing task"
msgstr "ІÑнуюче підзавданнÑ"
-msgid "WorkItem|Health status"
-msgstr "Стан здоров'Ñ"
-
msgid "WorkItem|History only"
msgstr "Лише Ñ–ÑторіÑ"
@@ -53838,13 +54157,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr "Етап"
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53988,9 +54313,6 @@ msgstr "ТеÑтовий кейÑ"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr "Ð¦Ñ %{workItemType} Ñ” конфіденційною Ñ– має бути видимою лише Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників команди з принаймні доÑтупом Репортер"
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ñ” конфіденційним Ñ– повинно бути видимим лише Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників команди з доÑтупом не нижче Ñ€Ñ–Ð²Ð½Ñ Ñ€ÐµÐ¿Ð¾Ñ€Ñ‚ÐµÑ€Ð°"
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr "Робочий елемент недоÑтупний. Він не Ñ–Ñнує, або у Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” дозволу на його переглÑд."
@@ -54021,7 +54343,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -54120,9 +54442,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -54212,10 +54531,10 @@ msgstr[2] ""
msgstr[3] ""
msgid "You are about to delete this forked project containing:"
-msgstr ""
+msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ цей форк, що міÑтить цей проєкт, що міÑтить:"
msgid "You are about to delete this project containing:"
-msgstr ""
+msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ цей проєкт, що міÑтить:"
msgid "You are about to incur additional charges"
msgstr ""
@@ -54362,7 +54681,7 @@ msgid "You can always edit this later"
msgstr "Ви завжди можете відредагувати це пізніше"
msgid "You can check it in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
-msgstr ""
+msgstr "Ви можете перевірити це в %{pat_link_start}параметрах оÑобиÑтих токенів доÑтупу%{pat_link_end}."
msgid "You can check it in your in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54385,6 +54704,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -54394,6 +54716,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -54476,7 +54801,7 @@ msgid "You can specify notification level per group or per project."
msgstr "Ви можете вказати рівень Ñповіщень на рівні групи або проєкту."
msgid "You can still use and manage existing tokens. %{link_start}Learn more.%{link_end}"
-msgstr ""
+msgstr "Ви вÑе ще можете викориÑтовувати Ñ–Ñнуючі токени та керувати ними. %{link_start}ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ.%{link_end}"
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
@@ -54592,9 +54917,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr "Ðаразі у Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” ніÑких розгортань."
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54885,13 +55207,13 @@ msgid "You're receiving this email because of your account on %{host}."
msgstr "Ви отримали цей електронний лиÑÑ‚, оÑкільки ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð¸Ð¹ на %{host}."
msgid "You're receiving this email because of your account on %{host}. %{manage_label_subscriptions_link_start}Manage label subscriptions%{manage_label_subscriptions_link_end} &middot; %{help_link_start}Help%{help_link_end}"
-msgstr "Ви отримуєте цей лиÑÑ‚ через ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° %{host}. %{manage_label_subscriptions_link_start}Керувати підпиÑками на мітки%{manage_label_subscriptions_link_end} &middot; %{help_link_start}Допомога%{help_link_end}\n"
+msgstr "Ви отримали цей лиÑÑ‚ через ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° %{host}. %{manage_label_subscriptions_link_start}ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ–Ð´Ð¿Ð¸Ñками на мітки%{manage_label_subscriptions_link_end} &middot; %{help_link_start}Допомога%{help_link_end}"
msgid "You're receiving this email because of your account on %{host}. %{manage_notifications_link_start}Manage all notifications%{manage_notifications_link_end} &middot; %{help_link_start}Help%{help_link_end}"
-msgstr "Ви отримуєте цей лиÑÑ‚ через ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° %{host}. %{manage_notifications_link_start}Керувати вÑіма ÑповіщеннÑми%{manage_notifications_link_end} &middot; %{help_link_start}Допомога%{help_link_end}"
+msgstr "Ви отримали цей електронний лиÑÑ‚ через ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° %{host}. %{manage_notifications_link_start}Керуйте вÑіма ÑповіщеннÑми%{manage_notifications_link_end} &middot; %{help_link_start}Довідка%{help_link_end}"
msgid "You're receiving this email because of your account on %{host}. %{unsubscribe_link_start}Unsubscribe%{unsubscribe_link_end} from this thread &middot; %{manage_notifications_link_start}Manage all notifications%{manage_notifications_link_end} &middot; %{help_link_start}Help%{help_link_end}"
-msgstr "Ви отримуєте цей лиÑÑ‚ через ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° %{host}. %{unsubscribe_link_start}ВідпиÑатиÑÑ%{unsubscribe_link_end} від цієї теми &middot; %{manage_notifications_link_start}Керувати вÑіма ÑповіщеннÑми%{manage_notifications_link_end} &middot; %{help_link_start}Допомога%{help_link_end}"
+msgstr "Ви отримали цей електронний лиÑÑ‚ через ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° %{host}. %{unsubscribe_link_start}ВідпиÑатиÑÑ%{unsubscribe_link_end} від цієї гілки &middot; %{manage_notifications_link_start}Керуйте вÑіма ÑповіщеннÑми%{manage_notifications_link_end} &middot; %{help_link_start}Довідка%{help_link_end}"
msgid "You're receiving this email because of your activity on %{host}."
msgstr "Ви отримали цей електронний лиÑÑ‚ через Ñвою активніÑÑ‚ÑŒ на %{host}."
@@ -55095,9 +55417,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr "Ваші авторизовані заÑтоÑунки"
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -55196,10 +55515,10 @@ msgid "Your name"
msgstr "Ваше ім'Ñ"
msgid "Your new %{accessTokenType}"
-msgstr ""
+msgstr "Ваш новий %{accessTokenType}"
msgid "Your new %{accessTokenType} has been created."
-msgstr ""
+msgstr "Ваш новий %{accessTokenType} Ñтворено."
msgid "Your new comment"
msgstr ""
@@ -55219,9 +55538,6 @@ msgstr ""
msgid "Your profile"
msgstr "Ваш профіль"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr "Ваш проєкт більше не отримує переваги GitLab Ultimate з 2022-07-01. Як повідомлÑлоÑÑ Ñ€Ð°Ð½Ñ–ÑˆÐµ в заÑтоÑунку, публічні проєкти з відкритим вихідним кодом на безкоштовному рівні можуть подати заÑвку на учаÑÑ‚ÑŒ у програмі GitLab Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¾Ð³Ð¾ вихідного коду, щоб отримати переваги GitLab Ultimate. Будь лаÑка, звернітьÑÑ Ð´Ð¾ %{faq_link_start}FAQ%{link_end} Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ детальної інформації."
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "Ваш ліміт проєктів Ñкладає %{limit}! Будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтратора, щоб його збільшити"
@@ -55246,6 +55562,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -55419,6 +55738,9 @@ msgstr ""
msgid "allowed to fail"
msgstr "невдача дозволена"
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -55532,6 +55854,9 @@ msgstr "не можна змінити на %{new_type}"
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55992,10 +56317,10 @@ msgstr "закрито %{timeago}"
msgid "closed issue"
msgid_plural "closed issues"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "закрита задача"
+msgstr[1] "закриті задачі"
+msgstr[2] "закритих задач"
+msgstr[3] "закритих задач"
msgid "comment"
msgstr "коментар"
@@ -56070,6 +56395,9 @@ msgstr ""
msgid "created by"
msgstr "Ñтворено"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr "щоднÑ"
@@ -56141,6 +56469,9 @@ msgstr "напр. %{token}"
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr "елемент відÑутній в ієрархії"
@@ -56229,9 +56560,6 @@ msgstr[3] "файлів"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "знахідку втрачено або вже закріплено за вразливіÑÑ‚ÑŽ"
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -56503,6 +56831,9 @@ msgstr "те, що він занадто великий"
msgid "jigsaw is not defined"
msgstr "jigsaw не визначено"
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56988,6 +57319,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56997,6 +57331,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -57024,6 +57361,9 @@ msgstr "не може бути влаÑником проÑтору імен"
msgid "must not contain commonly used combinations of words and letters"
msgstr "не повинно міÑтити загальновживаних Ñполучень Ñлів Ñ– букв"
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -57081,6 +57421,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, Ñ– %{lastItem}"
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -57092,10 +57435,10 @@ msgstr ""
msgid "open issue"
msgid_plural "open issues"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "відкрита задача"
+msgstr[1] "відкриті задачі"
+msgstr[2] "відкритих задач"
+msgstr[3] "відкритих задач"
msgid "or"
msgstr "або"
@@ -57398,6 +57741,9 @@ msgstr "%{slash_command} додає або віднімає чаÑ."
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr "розпочато Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ %{design_link}"
@@ -57440,6 +57786,9 @@ msgstr "назва тегу"
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr "Ñтани terraform"
@@ -57488,9 +57837,6 @@ msgstr "загальна Ñума повинна бути меншою або Ñ€
msgid "triggered"
msgstr "запущено"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -57549,6 +57895,9 @@ msgstr "верÑÑ–Ñ %{report_version} Ð´Ð»Ñ Ð·Ð²Ñ–Ñ‚Ñƒ типу %{report_type}
msgid "version %{versionIndex}"
msgstr "верÑÑ–Ñ %{versionIndex}"
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr "через %{closed_via}"
diff --git a/locale/ur_PK/gitlab.po b/locale/ur_PK/gitlab.po
index 72cec1182e1..ff3ed05847d 100644
--- a/locale/ur_PK/gitlab.po
+++ b/locale/ur_PK/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: ur-PK\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/uz_UZ/gitlab.po b/locale/uz_UZ/gitlab.po
index 48f07a9a914..b0ce139a0d6 100644
--- a/locale/uz_UZ/gitlab.po
+++ b/locale/uz_UZ/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: uz\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:04\n"
+"PO-Revision-Date: 2023-09-12 12:36\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -45,6 +45,11 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid " or "
msgstr ""
@@ -670,9 +675,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -718,7 +720,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -796,6 +798,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -871,6 +879,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1319,10 +1330,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1429,6 +1440,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1898,15 +1912,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1946,12 +1969,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1973,6 +2014,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1988,6 +2032,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -2000,6 +2047,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -2012,9 +2062,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2219,9 +2266,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2336,6 +2380,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2393,6 +2440,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2444,6 +2494,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2624,6 +2677,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2936,6 +2992,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2960,6 +3019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2987,7 +3049,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3827,7 +3889,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4451,6 +4513,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4889,9 +4954,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4982,6 +5044,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5167,6 +5232,9 @@ msgstr[1] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5182,6 +5250,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5292,6 +5366,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5337,15 +5414,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5367,6 +5447,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5382,6 +5468,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5424,24 +5513,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6200,9 +6295,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6283,7 +6375,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6428,6 +6520,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6638,6 +6733,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6755,6 +6853,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7682,7 +7783,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7697,15 +7798,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7723,6 +7827,9 @@ msgstr[1] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7735,6 +7842,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7762,6 +7875,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7806,6 +7922,9 @@ msgstr[1] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7839,9 +7958,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7929,9 +8045,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -9006,7 +9119,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -9102,7 +9215,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9489,6 +9602,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9579,6 +9695,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9637,7 +9756,7 @@ msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
msgstr[1] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9892,6 +10011,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -10093,15 +10215,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -10153,9 +10275,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10177,12 +10296,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10198,9 +10329,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10359,6 +10487,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10656,15 +10787,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10955,6 +11080,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10979,6 +11107,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11402,9 +11533,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11474,31 +11602,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11569,6 +11694,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11928,9 +12056,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11976,6 +12101,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -12033,7 +12161,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12249,15 +12377,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12321,6 +12452,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12492,6 +12626,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -13014,6 +13151,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -13047,6 +13187,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -13059,9 +13223,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -13149,6 +13322,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13695,6 +13877,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -14073,9 +14258,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14414,9 +14596,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14592,6 +14771,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14682,6 +14864,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14904,6 +15089,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15409,9 +15597,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15534,9 +15719,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15757,6 +15939,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15775,6 +15960,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15958,6 +16146,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15985,7 +16179,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -16000,7 +16194,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -16024,6 +16218,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -16084,7 +16281,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -16102,10 +16299,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -16189,6 +16386,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16260,9 +16463,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16275,6 +16475,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16290,12 +16508,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16365,12 +16586,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17565,9 +17780,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17610,6 +17822,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17748,9 +17963,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17772,7 +17984,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17886,9 +18098,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -18000,7 +18209,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -18147,12 +18356,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -18198,6 +18413,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18234,6 +18455,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18336,6 +18560,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -19091,6 +19321,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19337,6 +19570,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19994,9 +20230,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -20021,9 +20254,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20392,33 +20622,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -21113,6 +21316,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21440,6 +21649,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21455,6 +21667,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21470,12 +21685,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21596,7 +21805,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21614,6 +21823,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21635,6 +21847,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21647,6 +21862,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21716,9 +21934,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21749,6 +21964,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21989,6 +22207,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -22004,7 +22228,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -22115,6 +22339,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -22181,9 +22408,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22559,7 +22783,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22748,7 +22972,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22760,7 +22984,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22778,9 +23002,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -23202,6 +23423,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23465,9 +23689,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23507,6 +23728,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23690,6 +23917,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -24101,7 +24334,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -24128,6 +24361,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -24170,381 +24409,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24560,66 +24490,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -25049,6 +24928,16 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25405,6 +25294,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25441,15 +25333,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25531,9 +25417,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25866,18 +25749,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -26127,10 +26004,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -26139,16 +26028,24 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -26196,6 +26093,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26532,6 +26432,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -27030,6 +26933,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -27081,6 +26987,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -27177,9 +27086,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27442,9 +27348,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27541,6 +27444,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28242,6 +28148,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28251,6 +28160,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28656,6 +28568,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28671,6 +28589,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28683,6 +28604,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28989,6 +28913,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29247,6 +29267,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29679,9 +29702,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29778,6 +29798,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30658,10 +30681,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30739,6 +30762,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30769,15 +30795,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30796,12 +30825,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30820,6 +30855,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -31044,9 +31085,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31254,6 +31292,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31278,6 +31319,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31296,10 +31343,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31356,9 +31406,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31410,6 +31457,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32615,6 +32668,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32642,9 +32698,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32807,24 +32860,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33538,6 +33627,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33685,7 +33777,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -34132,9 +34227,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34249,12 +34341,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34705,6 +34791,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34828,9 +34917,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35353,9 +35439,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35467,6 +35550,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35590,9 +35676,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35608,9 +35691,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35647,9 +35727,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35710,6 +35787,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35734,9 +35814,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35968,7 +36045,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36403,9 +36480,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36895,6 +36969,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -37030,6 +37110,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -37102,6 +37185,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37921,6 +38007,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37993,7 +38085,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -38048,10 +38140,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -38063,6 +38158,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -38081,6 +38179,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -38138,9 +38239,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -38207,9 +38305,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38570,9 +38665,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38713,34 +38805,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -39075,9 +39143,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -39090,6 +39155,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -39099,9 +39167,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39381,12 +39446,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39693,9 +39752,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -40109,6 +40165,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40539,6 +40598,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40825,7 +40887,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40908,6 +40970,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -41117,6 +41182,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -41225,9 +41293,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -41240,7 +41305,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41366,10 +41431,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41384,6 +41452,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41396,7 +41482,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41408,7 +41494,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41420,6 +41506,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41447,9 +41539,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41561,6 +41662,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41630,13 +41734,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41865,6 +41966,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -42021,6 +42125,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -42030,7 +42140,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -42087,6 +42203,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -42159,7 +42278,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -42171,12 +42290,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42443,6 +42568,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42455,13 +42583,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42491,13 +42619,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42506,6 +42640,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42575,9 +42715,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42632,6 +42769,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42647,9 +42787,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42680,6 +42826,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42797,9 +42946,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42844,7 +42990,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -43192,9 +43338,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -43264,6 +43407,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43288,12 +43434,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43321,9 +43479,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43333,27 +43497,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43393,15 +43590,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43429,6 +43656,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43549,6 +43779,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43627,6 +43860,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44462,6 +44698,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44555,9 +44794,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45506,6 +45742,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45653,6 +45901,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45671,6 +45922,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46332,6 +46586,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46344,7 +46601,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -47177,9 +47440,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47354,6 +47614,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47372,9 +47635,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47624,6 +47884,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47708,6 +47971,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -48212,9 +48478,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -48233,10 +48505,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48386,7 +48658,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48512,7 +48784,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48533,7 +48805,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48956,7 +49228,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -49238,6 +49510,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49318,6 +49593,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49348,9 +49626,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49423,6 +49707,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49788,9 +50084,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49878,6 +50171,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49911,9 +50207,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49992,6 +50285,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50367,6 +50663,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50388,10 +50687,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50439,6 +50738,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50505,13 +50807,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -51185,6 +51487,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51888,6 +52193,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51915,16 +52223,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -52167,6 +52478,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -52281,10 +52595,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52320,6 +52631,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52647,6 +52961,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52749,15 +53069,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -53112,6 +53423,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -53204,9 +53521,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -53225,9 +53539,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -53246,13 +53557,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53396,9 +53713,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53429,7 +53743,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53528,9 +53842,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53791,6 +54102,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53800,6 +54114,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53998,9 +54315,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54497,9 +54811,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54619,9 +54930,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54646,6 +54954,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54815,6 +55126,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54924,6 +55238,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55442,6 +55759,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55509,6 +55829,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55595,9 +55918,6 @@ msgstr[1] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55861,6 +56181,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56336,6 +56659,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56345,6 +56671,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56372,6 +56701,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56429,6 +56761,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56730,6 +57065,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56772,6 +57110,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56820,9 +57161,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56879,6 +57217,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/vi_VN/gitlab.po b/locale/vi_VN/gitlab.po
index 2818027504c..38f5a78cc6a 100644
--- a/locale/vi_VN/gitlab.po
+++ b/locale/vi_VN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: vi\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -44,6 +44,10 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+
msgid " or "
msgstr ""
@@ -574,9 +578,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -622,7 +623,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -700,6 +701,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -775,6 +782,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1203,10 +1213,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1312,6 +1322,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr ""
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr ""
@@ -1755,15 +1768,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1803,12 +1825,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1830,6 +1870,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1845,6 +1888,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -1857,6 +1903,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -1869,9 +1918,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2076,9 +2122,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2193,6 +2236,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2250,6 +2296,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2301,6 +2350,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2481,6 +2533,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2793,6 +2848,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2817,6 +2875,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2844,7 +2905,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3684,7 +3745,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4308,6 +4369,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4746,9 +4810,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4839,6 +4900,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5023,6 +5087,9 @@ msgstr[0] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5038,6 +5105,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5147,6 +5220,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5192,15 +5268,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5222,6 +5301,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5237,6 +5322,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5279,24 +5367,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6045,9 +6139,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6127,7 +6218,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6267,6 +6358,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6474,6 +6568,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6591,6 +6688,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7518,7 +7618,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7533,15 +7633,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7558,6 +7661,9 @@ msgstr[0] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7570,6 +7676,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7597,6 +7709,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7640,6 +7755,9 @@ msgstr[0] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7673,9 +7791,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7763,9 +7878,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -8837,7 +8949,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -8933,7 +9045,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9320,6 +9432,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9410,6 +9525,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9466,7 +9584,7 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -9922,15 +10043,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -9982,9 +10103,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10006,12 +10124,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10027,9 +10157,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10187,6 +10314,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10484,15 +10614,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10782,6 +10906,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10806,6 +10933,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11229,9 +11359,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11301,31 +11428,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11753,9 +11880,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11801,6 +11925,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11858,7 +11985,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12074,15 +12201,18 @@ msgstr ""
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12146,6 +12276,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12317,6 +12450,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -12836,6 +12972,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -12869,6 +13008,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -12881,9 +13044,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -12971,6 +13143,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13517,6 +13698,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -13895,9 +14079,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr ""
-
msgid "Cron time zone"
msgstr ""
@@ -14235,9 +14416,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14411,6 +14589,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14501,6 +14682,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14723,6 +14907,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15226,9 +15413,6 @@ msgstr ""
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15350,9 +15534,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15568,6 +15749,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15586,6 +15770,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15766,6 +15953,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15793,7 +15986,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -15808,7 +16001,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -15832,6 +16025,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -15892,7 +16088,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -15910,10 +16106,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -15997,6 +16193,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16067,9 +16269,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16082,6 +16281,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16097,12 +16314,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16172,12 +16392,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17366,9 +17580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17411,6 +17622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17549,9 +17763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17573,7 +17784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17687,9 +17898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -17801,7 +18009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -17948,12 +18156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -17999,6 +18213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18035,6 +18255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18137,6 +18360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18891,6 +19120,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19137,6 +19369,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19791,9 +20026,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -19818,9 +20050,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20188,33 +20417,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20907,6 +21109,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21234,6 +21442,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21249,6 +21460,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21264,12 +21478,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21390,7 +21598,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21429,6 +21640,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21441,6 +21655,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21510,9 +21727,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21543,6 +21757,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21783,6 +22000,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -21798,7 +22021,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -21975,9 +22201,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22353,7 +22576,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22542,7 +22765,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22554,7 +22777,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22572,9 +22795,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -22994,6 +23214,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23256,9 +23479,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23298,6 +23518,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23481,6 +23707,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23889,7 +24121,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -23916,6 +24148,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -23958,381 +24196,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24348,66 +24277,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24837,6 +24715,14 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25192,6 +25078,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25228,15 +25117,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr ""
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25318,9 +25201,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25652,18 +25532,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25913,10 +25787,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr ""
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -25925,16 +25811,23 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -25982,6 +25875,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26318,6 +26214,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26816,6 +26715,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -26867,6 +26769,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -26963,9 +26868,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27226,9 +27128,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr ""
-
msgid "Last Seen"
msgstr ""
@@ -27325,6 +27224,9 @@ msgstr ""
msgid "LastPushEvent|at"
msgstr ""
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28019,6 +27921,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28028,6 +27933,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28433,6 +28341,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28448,6 +28362,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28460,6 +28377,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28766,6 +28686,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29021,6 +29037,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29453,9 +29472,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29552,6 +29568,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30430,10 +30449,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30511,6 +30530,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30541,15 +30563,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30568,12 +30593,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30592,6 +30623,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -30815,9 +30852,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr ""
-
msgid "New snippet"
msgstr ""
@@ -31025,6 +31059,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31049,6 +31086,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31067,10 +31110,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31127,9 +31173,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr ""
-
msgid "No service accounts"
msgstr ""
@@ -31181,6 +31224,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32379,6 +32428,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32406,9 +32458,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32571,24 +32620,60 @@ msgstr ""
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33301,6 +33386,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33448,7 +33536,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33895,9 +33986,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr ""
-
msgid "PipelineSchedules|Active"
msgstr ""
@@ -34012,12 +34100,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr ""
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34468,6 +34550,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34591,9 +34676,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35116,9 +35198,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35230,6 +35309,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35353,9 +35435,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35371,9 +35450,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35410,9 +35486,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35473,6 +35546,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35497,9 +35573,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35731,7 +35804,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36166,9 +36239,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36658,6 +36728,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -36793,6 +36869,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -36865,6 +36944,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37684,6 +37766,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37756,7 +37844,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -37809,10 +37897,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -37824,6 +37915,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -37842,6 +37936,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -37899,9 +37996,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -37968,9 +38062,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38331,9 +38422,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38473,34 +38561,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr ""
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38834,9 +38898,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -38849,6 +38910,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -38858,9 +38922,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39140,12 +39201,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39446,9 +39501,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -39858,6 +39910,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40283,6 +40338,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40567,7 +40625,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40649,6 +40707,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40857,6 +40918,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -40965,9 +41029,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr ""
-
msgid "Saving"
msgstr ""
@@ -40980,7 +41041,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41106,10 +41167,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attribute:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41124,6 +41188,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41136,7 +41218,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41148,7 +41230,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41160,6 +41242,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41187,9 +41275,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41301,6 +41398,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41370,13 +41470,10 @@ msgstr ""
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41594,6 +41691,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41750,6 +41850,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -41759,7 +41865,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -41888,7 +42003,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -41900,12 +42015,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42171,6 +42292,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42183,13 +42307,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42219,13 +42343,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42234,6 +42364,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42303,9 +42439,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42360,6 +42493,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42375,9 +42511,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42408,6 +42550,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42525,9 +42670,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42571,7 +42713,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -42919,9 +43061,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -42991,6 +43130,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43015,12 +43157,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43048,9 +43202,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43060,27 +43220,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43120,15 +43313,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43156,6 +43379,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43276,6 +43502,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43354,6 +43583,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44187,6 +44419,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44280,9 +44515,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45231,6 +45463,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45378,6 +45622,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45396,6 +45643,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46055,6 +46305,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46067,7 +46320,13 @@ msgstr ""
msgid "Target branch"
msgstr ""
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47070,6 +47326,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47088,9 +47347,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47340,6 +47596,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47424,6 +47683,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47928,9 +48190,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -47949,10 +48217,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48102,7 +48370,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48228,7 +48496,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48249,7 +48517,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48669,7 +48937,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48951,6 +49219,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49030,6 +49301,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49060,9 +49334,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49135,6 +49415,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49499,9 +49791,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49589,6 +49878,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49622,9 +49914,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49703,6 +49992,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50078,6 +50370,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50099,10 +50394,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50150,6 +50445,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50216,13 +50514,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -50895,6 +51193,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51596,6 +51897,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51623,16 +51927,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -51875,6 +52182,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -51989,10 +52299,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52028,6 +52335,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52355,6 +52665,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52457,15 +52773,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -52817,6 +53124,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -52908,9 +53221,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -52929,9 +53239,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -52950,13 +53257,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53100,9 +53413,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53133,7 +53443,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53232,9 +53542,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53494,6 +53801,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53503,6 +53813,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53701,9 +54014,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54319,9 +54626,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54346,6 +54650,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54513,6 +54820,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54620,6 +54930,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55128,6 +55441,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55193,6 +55509,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55278,9 +55597,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55540,6 +55856,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56010,6 +56329,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56019,6 +56341,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56046,6 +56371,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56103,6 +56431,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56396,6 +56727,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56438,6 +56772,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56486,9 +56823,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56544,6 +56878,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index e16fc194189..d853c8138f9 100644
--- a/locale/zh_CN/gitlab.po
+++ b/locale/zh_CN/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: zh-CN\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr "从%{start}到%{end}"
@@ -44,6 +44,10 @@ msgstr "和"
msgid " and %{sliced}"
msgstr "和%{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] " 除了这些分支:"
+
msgid " or "
msgstr " 或者"
@@ -78,7 +82,7 @@ msgid "##### ERROR ##### You have used %{usage_percentage} of the storage quota
msgstr "##### 错误 ##### 您已使用 %{namespace_name} 的存储é…é¢çš„ %{usage_percentage} ( %{size_limit} çš„ %{current_size} ) 。 %{namespace_name} 现在为åªè¯»çŠ¶æ€ã€‚ 此命å空间下的项目已被é”定,æ“作将å—到é™åˆ¶ã€‚ 如果需è¦ç®¡ç†å­˜å‚¨ï¼Œæˆ–è´­ä¹°é¢å¤–存储空间,请å‚阅 %{manage_storage_url}。è¦äº†è§£æ›´å¤šå…³äºŽé™åˆ¶æ“作的信æ¯ï¼Œè¯·å‚阅 %{restricted_actions_url}"
msgid "##### WARNING ##### You have used %{usage_percentage} of the storage quota for %{namespace_name} (%{current_size} of %{size_limit}). If %{namespace_name} exceeds the storage quota, all projects in the namespace will be locked and actions will be restricted. To manage storage, or purchase additional storage, see %{manage_storage_url}. To learn more about restricted actions, see %{restricted_actions_url}"
-msgstr ""
+msgstr "##### 警告 ##### 您已使用 %{namespace_name} 存储空间的 %{usage_percentage} ( %{size_limit} 中的 %{current_size} ) 。如果 %{namespace_name} 超过储存é…é¢é™åˆ¶ï¼Œè¯¥å‘½å空间中的所有项目都将被é”定,您的æ“作将会å—到é™åˆ¶ã€‚管ç†å‚¨å­˜é…é¢æˆ–è´­ä¹°é¢å¤–存储空间,请å‚阅 %{manage_storage_url} 。了解更多关于æ“作é™åˆ¶çš„ä¿¡æ¯ï¼Œè¯·å‚阅 %{restricted_actions_url}。"
msgid "#%{issueIid} (closed)"
msgstr "#%{issueIid}(已关闭)"
@@ -574,9 +578,6 @@ msgstr "%{count} 个标签"
msgid "%{count} total weight"
msgstr "总æƒé‡%{count}"
-msgid "%{dashboard_path} could not be found."
-msgstr "未找到%{dashboard_path}。"
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days}天,直到标签被自动删除"
@@ -622,8 +623,8 @@ msgstr "%{edit_in_new_fork_notice} å†æ¬¡å°è¯•ä¸Šä¼ æ–‡ä»¶ã€‚"
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr "%{enable_service_ping_link_start}å¯ç”¨%{link_end} 或 %{generate_manually_link_start}生æˆ%{link_end} æœåŠ¡Ping 以预览和下载æœåŠ¡ä½¿ç”¨æ•°æ®æœ‰æ•ˆè½½è·ã€‚"
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr "%{enable_service_ping_link_start}å¯ç”¨%{enable_service_ping_link_end} 或 %{generate_manually_link_start}生æˆ%{generate_manually_link_end} æœåŠ¡ Ping 以预览和下载æœåŠ¡ä½¿ç”¨æ•°æ®æœ‰æ•ˆè´Ÿè½½ã€‚"
msgid "%{extra} more downstream pipelines"
msgstr "å¦å¤– %{extra} 个下游æµæ°´çº¿"
@@ -700,6 +701,12 @@ msgstr "%{issuesSize}个,上é™ä¸º%{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}新增功能%{italic_end} 处于未激活状æ€ä¸”无法查看。"
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr "由于æƒé™ä¸è¶³è€Œæ— æ³•åˆ é™¤ %{item_ids} "
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr "由于未链接而无法删除 %{item_ids}"
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount}个议题,上é™ä¸º%{maxIssueCount}"
@@ -775,6 +782,9 @@ msgstr "%{labelStart}未修改的å“应:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message}ä¸å¯ç”¨"
+msgid "%{label_name} is locked and was not removed"
+msgstr "%{label_name} å·²é”定且未被删除"
+
msgid "%{label_name} was removed"
msgstr "已删除 %{label_name}"
@@ -1203,11 +1213,11 @@ msgstr "%{verb} 耗时 %{time_spent_value}"
msgid "%{verb} this %{noun} as a draft."
msgstr "%{verb} æ­¤ %{noun} 作为è‰ç¨¿ã€‚"
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end}å…许您针对æŸä¸ªç¾¤ç»„或项目中的事件å‘é€é€šçŸ¥åˆ°web应用程åºã€‚"
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} ä½¿æ‚¨èƒ½å¤Ÿå‘ Web 应用程åºå‘é€é€šçŸ¥ä»¥å“应群组或项目中的事件。"
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end}å…许您针对æŸä¸ªç¾¤ç»„或项目中的事件å‘é€é€šçŸ¥åˆ°web应用程åºã€‚ 如需使用webhook, 我们推è优先使用已有%{integrations_link_start}集æˆ%{link_end}。"
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} ä½¿æ‚¨èƒ½å¤Ÿå‘ Web 应用程åºå‘é€é€šçŸ¥ä»¥å“应群组或项目中的事件。我们建议优先使用 %{integrations_link_start}集æˆ%{integrations_link_end} 而ä¸æ˜¯ Webhook。"
msgid "%{widget} options"
msgstr "%{widget} 选项"
@@ -1312,6 +1322,9 @@ msgstr "+ 其余 %{amount} 项"
msgid "+ %{count} more"
msgstr "+ 其余%{count}项"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr "+ %{hiddenBranchesLength} 更多"
+
msgid "+ %{moreCount} more"
msgstr "+ 其余%{moreCount}项"
@@ -1609,7 +1622,7 @@ msgid "A complete DevOps platform"
msgstr "一个完整的DevOpså¹³å°"
msgid "A confidential issue must have only confidential children. Make any child items confidential and try again."
-msgstr ""
+msgstr "ç§å¯†è®®é¢˜å¿…é¡»åªæœ‰ç§å¯†å­çº§ã€‚将所有å­é¡¹ç›®è®¾ç½®ä¸ºç§å¯†ï¼Œç„¶åŽé‡è¯•ã€‚"
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr "ç§å¯†å·¥ä½œé¡¹ä¸èƒ½è¢«åŒ…å«åœ¨å·²å«æœ‰éžç§å¯†å­é¡¹çš„父项中。"
@@ -1750,20 +1763,29 @@ msgid "AI| %{link_start}What are Experiment features?%{link_end}"
msgstr "%{link_start}什么是实验功能?%{link_end}"
msgid "AI|%{tool} is %{transition} an answer"
-msgstr ""
+msgstr "%{tool} 是一个 %{transition} 答案"
msgid "AI|AI generated explanations will appear here."
msgstr "AI 生æˆçš„解释将显示在这里。"
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr " %{linkStart}实验性功能%{linkEnd} 是正在开å‘的功能。还未准备好用于生产环境。我们鼓励用户试用实验性功能并æä¾›å馈。实验性功能:%{bullets}"
+
msgid "AI|Apply AI-generated description"
msgstr "应用 AI 生æˆçš„æè¿°"
+msgid "AI|Ask GitLab Duo"
+msgstr "询问æžç‹GitLab Duo"
+
msgid "AI|Ask a question"
msgstr "æé—®"
msgid "AI|Autocomplete"
msgstr "自动补全"
+msgid "AI|Can be removed at any time"
+msgstr "å¯ä»¥éšæ—¶ç§»é™¤"
+
msgid "AI|Close the Code Explanation"
msgstr "关闭代ç è§£é‡Š"
@@ -1786,7 +1808,7 @@ msgid "AI|Experiment features"
msgstr "实验功能"
msgid "AI|Explain the code from %{filePath} in human understandable language presented in Markdown format. In the response add neither original code snippet nor any title. `%{text}`. If it is not programming code, say `The selected text is not code. I am afraid this feature is for explaining code only. Would you like to ask a different question about the selected text?` and wait for another question."
-msgstr ""
+msgstr "用人类å¯ä»¥ç†è§£çš„语言以 Markdown æ ¼å¼è§£é‡Š %{filePath} 的代ç ã€‚在å“应中既ä¸æ·»åŠ åŽŸå§‹ä»£ç ç‰‡æ®µä¹Ÿä¸æ·»åŠ ä»»ä½•æ ‡é¢˜ã€‚`%{text}`。如果ä¸æ˜¯ç¼–程代ç ï¼Œä¾‹å¦‚ “所选文本ä¸æ˜¯ä»£ç ã€‚æ怕此功能仅用于解释代ç ã€‚您想就所选文本æ出其他问题å—?“ 然åŽç­‰å¾…å¦ä¸€ä¸ªé—®é¢˜ã€‚"
msgid "AI|Explain your rating (optional)"
msgstr "解释您的评分(å¯é€‰ï¼‰"
@@ -1801,14 +1823,32 @@ msgid "AI|Generate issue description"
msgstr "生æˆè®®é¢˜æè¿°"
msgid "AI|GitLab Duo"
+msgstr "æžç‹GitLab Duo"
+
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
msgstr ""
+msgid "AI|Has no support and might not be documented"
+msgstr "无支æŒï¼Œä¸”å¯èƒ½ä¸ä¼šè¢«è®°å½•"
+
msgid "AI|Helpful"
msgstr "有帮助"
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr "我ä¸çŸ¥é“我能帮上什么忙。 请给予更好的指示ï¼"
+msgid "AI|May be unstable"
+msgstr "å¯èƒ½ä¸ç¨³å®š"
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr "å¯èƒ½ä¼šæä¾›ä¸ä»£è¡¨æˆ‘们观点的ä¸å½“回应。请勿输入个人数æ®ã€‚"
@@ -1830,6 +1870,9 @@ msgstr "å‘é€èŠå¤©æ¶ˆæ¯ã€‚"
msgid "AI|Something went wrong. Please try again later"
msgstr "出错了。请ç¨åŽå†è¯•"
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr "找ä¸åˆ°å®¹å™¨å…ƒç´ ï¼Œåœæ­¢ AI Genie。"
@@ -1845,6 +1888,9 @@ msgstr "这些功能å¯èƒ½ä¼šå¯¼è‡´æ€§èƒ½å’Œç¨³å®šæ€§é—®é¢˜ï¼›è¿™äº›é—®é¢˜å¯èƒ½
msgid "AI|Third-party AI services"
msgstr "第三方 AI æœåŠ¡"
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr "没有帮助"
@@ -1857,6 +1903,9 @@ msgstr "使用第三方 AI æœåŠ¡"
msgid "AI|What does the selected code mean?"
msgstr "选中的代ç æ˜¯ä»€ä¹ˆæ„æ€ï¼Ÿ"
+msgid "AI|What's an Experiment?"
+msgstr "什么是实验?"
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr "写一个简短的æ述,让 AI 填写细节。"
@@ -1869,9 +1918,6 @@ msgstr "错误"
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr "您ä¸èƒ½å°†æ­¤è¾“出的任何部分å¤åˆ¶åˆ° %{gitlabOrg} 或 %{gitlabCom} 群组中的议题ã€è¯„论ã€æºä»£ç ã€æ交消æ¯ã€åˆå¹¶è¯·æ±‚或任何其他用户界é¢ä¸­ã€‚"
-msgid "AI|You can ask AI for more information."
-msgstr "您å¯ä»¥å‘ AI 询问更多信æ¯ã€‚"
-
msgid "AI|finding"
msgstr "å‘现"
@@ -2076,9 +2122,6 @@ msgstr "未找到报告"
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr "为 %{category} %{reportLinkStart}报告%{reportLinkEnd}于 %{timeAgo}。"
-msgid "AbuseReport|Abuse reports"
-msgstr "滥用报告"
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr "未确认的滥用"
@@ -2193,6 +2236,9 @@ msgstr "攻击性或辱骂性内容"
msgid "AbuseReport|Other"
msgstr "其他"
+msgid "AbuseReport|Past abuse reports"
+msgstr "过去的滥用报告"
+
msgid "AbuseReport|Personal information or credentials"
msgstr "个人信æ¯æˆ–凭æ®"
@@ -2250,6 +2296,9 @@ msgstr "验è¯"
msgid "AbuseReport|View screenshot"
msgstr "查看截图"
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "接å—邀请"
@@ -2301,6 +2350,9 @@ msgstr "群组"
msgid "AccessDropdown|Roles"
msgstr "角色"
+msgid "AccessDropdown|Select"
+msgstr "选择"
+
msgid "AccessDropdown|Users"
msgstr "用户"
@@ -2481,6 +2533,9 @@ msgstr "确认"
msgid "Action"
msgstr "æ“作"
+msgid "Action '%{action}' in registries is not supported."
+msgstr "ä¸æ”¯æŒé•œåƒåº“中的 '%{action}' æ“作。"
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr "ä¸æ”¯æŒä»“库 %{registry_id} æ¡ç›®ä¸­çš„ “%{action}†æ“作。"
@@ -2515,7 +2570,7 @@ msgid "Active personal access tokens"
msgstr "有效的个人访问令牌"
msgid "Active pipeline trigger tokens"
-msgstr ""
+msgstr "活动的æµæ°´çº¿è§¦å‘令牌"
msgid "Active project access tokens"
msgstr "有效的项目访问令牌"
@@ -2743,10 +2798,10 @@ msgid "Add new key"
msgstr "添加新密钥"
msgid "Add new pipeline subscription"
-msgstr ""
+msgstr "添加新的æµæ°´çº¿è®¢é˜…"
msgid "Add new pipeline trigger token"
-msgstr ""
+msgstr "添加æµæ°´çº¿è§¦å‘令牌"
msgid "Add new token"
msgstr "添加新令牌"
@@ -2776,7 +2831,7 @@ msgid "Add projects"
msgstr "添加项目"
msgid "Add protected branch"
-msgstr ""
+msgstr "添加å—ä¿æŠ¤åˆ†æ”¯"
msgid "Add reaction"
msgstr "添加回应"
@@ -2793,6 +2848,9 @@ msgstr "将建议加入批é‡å¤„ç†"
msgid "Add tag"
msgstr "添加标签"
+msgid "Add target branch rule"
+msgstr "添加目标分支规则"
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "将文本添加到登录页é¢ã€‚Markdownå·²å¯ç”¨ã€‚"
@@ -2817,6 +2875,9 @@ msgstr "添加到评审"
msgid "Add to tree"
msgstr "添加到树"
+msgid "Add token"
+msgstr "添加令牌"
+
msgid "Add topics to projects to help users find them."
msgstr "将主题添加到项目以帮助用户找到它们。"
@@ -2844,8 +2905,8 @@ msgstr "添加/删除"
msgid "AddMember|Invite email is invalid"
msgstr "邀请邮件无效"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "æ¯å¤©é™åˆ¶%{daily_invites}次邀请"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "邀请ä¸èƒ½ä¸ºç©º"
@@ -3463,7 +3524,7 @@ msgid "AdminSettings|Set a CI/CD template as the required pipeline configuration
msgstr "å°†CI/CD模æ¿è®¾ç½®ä¸ºå®žä¾‹ä¸­æ‰€æœ‰é¡¹ç›®æ‰€éœ€çš„æµæ°´çº¿é…置。当æµæ°´çº¿è¿è¡Œæ—¶ï¼Œé¡¹ç›®CI/CDé…ç½®åˆå¹¶åˆ°æ‰€éœ€çš„æµæ°´çº¿é…置中。%{link_start}什么是必需的æµæ°´çº¿é…ç½®?%{link_end}"
msgid "AdminSettings|Set options for cost factors of forks"
-msgstr "设置派生项目的æˆæœ¬å› ç´ çš„选项"
+msgstr "设置派生项目的消耗系数的选项"
msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered group runners."
msgstr "设置新注册的群组 runners 认è¯ä»¤ç‰Œçš„过期时间。"
@@ -3511,7 +3572,7 @@ msgid "AdminSettings|There are Advanced Search migrations pending that require i
msgstr "有需è¦æš‚åœç´¢å¼•çš„高级æœç´¢è¿ç§»å¾…处ç†ã€‚索引必须ä¿æŒæš‚åœï¼Œç›´åˆ°å®Œæˆè¿ç§»ã€‚"
msgid "AdminSettings|This cost factor will be applied to the storage consumed by forks."
-msgstr "æ­¤æˆæœ¬å› ç´ å°†åº”用于派生项目消耗的存储。"
+msgstr "此消耗系数将应用于派生项目消耗的存储。"
msgid "AdminSettings|This limit cannot be disabled. Set to 0 to block all DAG dependencies."
msgstr "æ­¤é™åˆ¶æ— æ³•ç¦ç”¨ã€‚设置为 0 以阻止所有 DAG ä¾èµ–项。"
@@ -3684,8 +3745,8 @@ msgstr "ç¦ç”¨ç”¨æˆ·å…·æœ‰ä»¥ä¸‹æ•ˆæžœï¼š"
msgid "AdminUsers|Bot"
msgstr "Bot"
-msgid "AdminUsers|Can create group"
-msgstr "å¯ä»¥åˆ›å»ºç¾¤ç»„"
+msgid "AdminUsers|Can create top level group"
+msgstr "å¯ä»¥åˆ›å»ºé¡¶çº§ç¾¤ç»„"
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "无法登录或访问实例信æ¯"
@@ -4308,6 +4369,9 @@ msgstr "标题为在 GitLab中警报的必填字段。如果您指定的负载å­
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr "集æˆç”ŸæˆWebhook URL 和授æƒå¯†é’¥ã€‚您ä¿å­˜é›†æˆåŽï¼Œä¸¤è€…都在“查看凭æ®â€é€‰é¡¹å¡ä¸‹å¯è§ã€‚"
+msgid "AlertSettings|Active alerts"
+msgstr "激活的警报"
+
msgid "AlertSettings|Add new integration"
msgstr "添加新的集æˆ"
@@ -4746,9 +4810,6 @@ msgstr "获å–公共部署密钥时出错。请é‡è¯•ã€‚"
msgid "An error occurred previewing the blob"
msgstr "预览 blob 时出错"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr "加载用户验è¯æŒ‘战时å‘生错误。刷新请å†æ¬¡é‡è¯•ã€‚"
-
msgid "An error occurred when updating the title"
msgstr "更新标题时出现错误"
@@ -4839,6 +4900,9 @@ msgstr "获å–议题时å‘生错误。"
msgid "An error occurred while fetching label colors."
msgstr "获å–标记颜色时出错。"
+msgid "An error occurred while fetching labels, please try again."
+msgstr "获å–标记时出错,请é‡è¯•ã€‚"
+
msgid "An error occurred while fetching participants"
msgstr "获å–å‚与者时出现错误"
@@ -5023,6 +5087,9 @@ msgstr[0] "ä¿å­˜è®¾ç½®æ—¶å‘生错误。"
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "ä¿å­˜æ‚¨çš„设置时å‘生错误。请å°è¯•å†æ¬¡ä¿å­˜ã€‚"
+msgid "An error occurred while searching for labels, please try again."
+msgstr "æœç´¢æ ‡è®°æ—¶å‡ºé”™ï¼Œè¯·é‡è¯•ã€‚"
+
msgid "An error occurred while triggering the job."
msgstr "触å‘作业时å‘生错误。"
@@ -5038,6 +5105,12 @@ msgstr "å°è¯•ä¸ºæ­¤åˆå¹¶è¯·æ±‚è¿è¡Œæ–°æµæ°´çº¿æ—¶å‘生错误。"
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr "试图å–消关注这个用户时出错,请é‡è¯•ã€‚"
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr "æ›´æ–°é•œåƒåº“时出错:'%{error_message}'。"
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr "æ›´æ–°é•œåƒåº“时出错:'%{error_message}'。"
+
msgid "An error occurred while updating approvers"
msgstr "更新核准人时å‘生错误"
@@ -5147,6 +5220,9 @@ msgstr "分æžè®¾ç½®"
msgid "Analytics|A visualization with that name already exists."
msgstr "已存在使用该å称的å¯è§†åŒ–分æžã€‚"
+msgid "Analytics|Add a visualization"
+msgstr "添加å¯è§†åŒ–"
+
msgid "Analytics|Add visualizations"
msgstr "添加å¯è§†åŒ–"
@@ -5192,15 +5268,18 @@ msgstr "é…置仪表盘项目"
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr "创建仪表盘 %{dashboardSlug}"
+msgid "Analytics|Create your dashboard"
+msgstr "创建仪表盘"
+
msgid "Analytics|Custom dashboards"
msgstr "自定义仪表盘"
-msgid "Analytics|Dashboard Title"
-msgstr "仪表盘标题"
-
msgid "Analytics|Dashboard not found"
msgstr "未找到仪表盘"
+msgid "Analytics|Dashboard title"
+msgstr "仪表盘标题"
+
msgid "Analytics|Dashboard was saved successfully"
msgstr "仪表盘ä¿å­˜æˆåŠŸ"
@@ -5222,6 +5301,12 @@ msgstr "日期和时间以 UTC 时区显示"
msgid "Analytics|Edit"
msgstr "编辑"
+msgid "Analytics|Edit your dashboard"
+msgstr "编辑仪表盘"
+
+msgid "Analytics|Enter a dashboard title"
+msgstr "输入仪表盘标题"
+
msgid "Analytics|Enter a visualization name"
msgstr "输入å¯è§†åŒ–分æžå称"
@@ -5237,6 +5322,9 @@ msgstr "抓å–æ•°æ®å¤±è´¥"
msgid "Analytics|Host"
msgstr "主机"
+msgid "Analytics|Invalid visualization configuration"
+msgstr "å¯è§†åŒ–é…置无效"
+
msgid "Analytics|Language"
msgstr "语言"
@@ -5279,24 +5367,30 @@ msgstr "Referer"
msgid "Analytics|Resulting Data"
msgstr "结果数æ®"
-msgid "Analytics|Save"
-msgstr "ä¿å­˜"
-
msgid "Analytics|Save and add to Dashboard"
msgstr "ä¿å­˜å¹¶æ·»åŠ åˆ°ä»ªè¡¨ç›˜"
msgid "Analytics|Save new visualization"
msgstr "ä¿å­˜æ–°çš„å¯è§†åŒ–分æž"
+msgid "Analytics|Save your dashboard"
+msgstr "ä¿å­˜ä»ªè¡¨ç›˜"
+
msgid "Analytics|Select a measurement"
msgstr "选择一ç§åº¦é‡"
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr "从侧边æ ä¸­é€‰æ‹©ä¸€ä¸ªå¯è§†åŒ–å³å¯å¼€å§‹ã€‚"
+
msgid "Analytics|Select a visualization type"
msgstr "选择å¯è§†åŒ–分æžç±»åž‹"
msgid "Analytics|Single Statistic"
msgstr "å•ä¸€ç»Ÿè®¡"
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr "您的é¢æ¿å¯è§†åŒ–é…置有问题。请å‚阅 %{linkStart}故障排除文档%{linkEnd}。"
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr "连接到数æ®æºæ—¶å‡ºé”™ã€‚请å‚阅%{linkStart}故障排除文档%{linkEnd}。"
@@ -6045,9 +6139,6 @@ msgstr "您确定è¦åˆ é™¤æ­¤è®¾å¤‡å—?此æ“作无法撤销。"
msgid "Are you sure you want to delete this label?"
msgstr "您确定è¦åˆ é™¤æ­¤æ ‡è®°å—?"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "确定è¦åˆ é™¤æ­¤æµæ°´çº¿è®¡åˆ’å—?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "确定è¦åˆ é™¤è¿™æ¡æµæ°´çº¿å—? 删除æ“作将使所有æµæ°´çº¿ç¼“存过期,并删除所有相关的对象,如构建ã€æ—¥å¿—ã€äº§ç‰©å’Œè§¦å‘器。 æ­¤æ“作ä¸å¯é€†ã€‚"
@@ -6127,8 +6218,8 @@ msgstr "确定è¦é‡ç½®æ³¨å†Œä»¤ç‰Œå—?"
msgid "Are you sure you want to retry this migration?"
msgstr "确定è¦é‡è¯•æ­¤è¿ç§»å—?"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "您确定è¦æ’¤é”€%{accessTokenType}嘛?此æ“作ä¸èƒ½æ’¤é”€ã€‚"
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr "您确定è¦æ’¤é”€ %{accessTokenType} “%{tokenName}â€å—?此æ“作ä¸å¯é€†ã€‚"
msgid "Are you sure you want to revoke this SSH key?"
msgstr "您确定è¦æ’¤é”€æ­¤ SSH 密钥å—?"
@@ -6267,6 +6358,9 @@ msgstr "将自动检查以逗å·åˆ†éš”的分支列表。留空则包å«æ‰€æœ‰åˆ†
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr "用户的个人访问令牌。用户必须å¯ä»¥è®¿é—®ä»»åŠ¡ã€‚所有评论都归于此用户。"
+msgid "Ask a maintainer to check the import status for more details."
+msgstr "如果您想了解更多详情,请è”系仓库维护者检查导入状æ€ã€‚"
+
msgid "Ask again later"
msgstr "ç¨åŽå†é—®"
@@ -6474,6 +6568,9 @@ msgstr "æ­¤å称的 header 已存在。"
msgid "AuditStreams|Active"
msgstr "有效"
+msgid "AuditStreams|Add a new private key"
+msgstr "添加一个新的ç§é’¥"
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr "添加一个 HTTP 端点æ¥ç®¡ç†ç¬¬ä¸‰æ–¹ç³»ç»Ÿä¸­çš„审计日志。"
@@ -6591,6 +6688,9 @@ msgstr "å¯èƒ½åŒ…括æ•æ„Ÿä¿¡æ¯ï¼Œè¯·ç¡®ä¿æ‚¨ä¿¡ä»»ç›®çš„地端点。"
msgid "AuditStreams|This is great for keeping everything one place."
msgstr "éžå¸¸é€‚åˆå°†æ‰€æœ‰æ•°æ®ä¿å­˜åœ¨ä¸€ä¸ªåœ°æ–¹ã€‚"
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr "使用 Google Cloud 控制å°ä»¥æŸ¥çœ‹ç§é’¥ã€‚è‹¥è¦æ›´æ”¹ç§é’¥ï¼Œè¯·ä½¿ç”¨æ–°çš„ç§é’¥è¿›è¡Œæ›¿æ¢ã€‚"
+
msgid "AuditStreams|Value"
msgstr "值"
@@ -7162,7 +7262,7 @@ msgid "BetaBadge|Is supported by a commercially reasonable effort."
msgstr "尽力æä¾›åˆç†çš„商业支æŒã€‚"
msgid "BetaBadge|May be unstable."
-msgstr ""
+msgstr "å¯èƒ½ä¸ç¨³å®š"
msgid "BetaBadge|Should not cause data loss."
msgstr "ä¸åº”导致数æ®ä¸¢å¤±ã€‚"
@@ -7518,8 +7618,8 @@ msgstr "加载订阅信æ¯æ—¶å‘生错误。"
msgid "Billing|An error occurred while loading billable members list."
msgstr "加载计费æˆå‘˜åˆ—表时å‘生错误。"
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
-msgstr "加载代ç å»ºè®®æ’件的详细信æ¯æ—¶å‡ºé”™ã€‚"
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "加载代ç å»ºè®®é™„加组件的详细信æ¯æ—¶å‘生错误。如果问题ä»ç„¶å­˜åœ¨ï¼Œè¯· %{supportLinkStart}è”系支æŒäººå‘˜%{supportLinkEnd}。"
msgid "Billing|An error occurred while loading pending members list"
msgstr "加载待处ç†æˆå‘˜åˆ—表时出错"
@@ -7533,15 +7633,18 @@ msgstr "等待æˆå‘˜æ³¨å†Œ"
msgid "Billing|Cannot remove user"
msgstr "无法删除用户"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr "已分é…代ç å»ºè®®æ’件"
-
msgid "Billing|Direct memberships"
msgstr "直接æˆå‘˜"
msgid "Billing|Enter at least three characters to search."
msgstr "请至少输入三个字符æ‰å¯æœç´¢ã€‚"
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr "分é…代ç å»ºè®®æ’件时出错"
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr "å–消分é…代ç å»ºè®®é™„加组件时出错"
+
msgid "Billing|Explore paid plans"
msgstr "æµè§ˆä»˜è´¹æ–¹æ¡ˆ"
@@ -7558,6 +7661,9 @@ msgstr[0] "å…è´¹ç‰ˆä¸­çš„ç¾¤ç»„ä»…é™ %d 个席ä½"
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "无法删除通过群组邀请而邀请的æˆå‘˜ã€‚您å¯ä»¥ç§»é™¤æ•´ä¸ªç¾¤ç»„,也å¯ä»¥è¦æ±‚å—邀群组的所有者移除æˆå‘˜ã€‚"
+msgid "Billing|No seats available"
+msgstr "æ— å¯ç”¨å¸­ä½"
+
msgid "Billing|No users to display."
msgstr "无用户å¯æ˜¾ç¤ºã€‚"
@@ -7570,6 +7676,12 @@ msgstr "项目邀请"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "从您的订阅中删除用户 %{username}"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "将附加组件分é…给该æˆå‘˜æ—¶å‡ºçŽ°é—®é¢˜ã€‚如果问题ä»ç„¶å­˜åœ¨ï¼Œè¯· %{supportLinkStart}è”系支æŒäººå‘˜%{supportLinkEnd}。"
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "å–消分é…该æˆå‘˜çš„附加组件时出现问题。如果问题ä»ç„¶å­˜åœ¨ï¼Œè¯· %{supportLinkStart}è”系支æŒäººå‘˜%{supportLinkEnd}。"
+
msgid "Billing|Subscription end"
msgstr "订阅结æŸ"
@@ -7597,6 +7709,9 @@ msgstr "查看待审批"
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "您将è¦ä»Žè®¢é˜…中删除用户%{username}。如果继续,该用户将从 %{namespace} 群组åŠå…¶æ‰€æœ‰å­ç»„和项目中删除。此æ“作无法撤消。"
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr "您已分é…所有å¯ç”¨çš„代ç å»ºè®®é™„加席ä½ã€‚如果您想购买更多å席,请 %{salesLinkStart}è”系销售人员%{salesLinkEnd}。"
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr "您的群组最近更改为使用å…费版。%{over_limit_message}您å¯ä»¥é€šè¿‡åˆ é™¤ä¸å†éœ€è¦è®¿é—®æƒé™çš„æˆå‘˜ï¼Œæˆ–将其切æ¢ä¸ºè¶…é™çŠ¶æ€ï¼Œæ¥ä¸ºæ–°æˆå‘˜é‡Šæ”¾å¸­ä½ã€‚è¦èŽ·å¾—æ— é™æ•°é‡çš„会员,您å¯ä»¥%{link_start}å‡çº§%{link_end}到付费版。"
@@ -7640,6 +7755,9 @@ msgstr[0] "被%d个议题阻塞"
msgid "Blocked issue"
msgstr "å—阻的议题"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr "已阻止的工作项目在当å‰è®¢é˜…级别ä¸å¯ç”¨"
+
msgid "Blocking"
msgstr "阻塞"
@@ -7673,9 +7791,6 @@ msgstr "没有匹é…结果"
msgid "BoardNewEpic|Search groups"
msgstr "æœç´¢ç¾¤ç»„"
-msgid "BoardNewEpic|Select a group"
-msgstr "选择一个群组"
-
msgid "BoardNewIssue|No matching results"
msgstr "没有匹é…结果"
@@ -7763,9 +7878,6 @@ msgstr "选择标记"
msgid "BoardScope|Select milestone"
msgstr "选择里程碑"
-msgid "BoardScope|Select weight"
-msgstr "选择æƒé‡"
-
msgid "BoardScope|Started"
msgstr "已开始"
@@ -8381,7 +8493,7 @@ msgid "BroadcastMessages|Indigo"
msgstr "é›è“色"
msgid "BroadcastMessages|Leave blank to target all group and project pages."
-msgstr ""
+msgstr "留空以é”定所有群组和项目页é¢ã€‚"
msgid "BroadcastMessages|Light"
msgstr "浅色"
@@ -8411,16 +8523,16 @@ msgid "BroadcastMessages|Notification"
msgstr "通知"
msgid "BroadcastMessages|One or more roles is required."
-msgstr ""
+msgstr "需è¦ä¸€ä¸ªæˆ–多个角色。"
msgid "BroadcastMessages|Paths can contain wildcards, like */welcome."
-msgstr ""
+msgstr "路径å¯ä»¥åŒ…å«é€šé…符,例如 */welcome。"
msgid "BroadcastMessages|Red"
msgstr "红色"
msgid "BroadcastMessages|Select at least one role."
-msgstr ""
+msgstr "选择至少一个角色。"
msgid "BroadcastMessages|Show only to users who have specific roles on groups/project pages"
msgstr "ä»…å‘在群组/项目页é¢ä¸Šå…·æœ‰ç‰¹å®šè§’色的用户显示"
@@ -8837,8 +8949,8 @@ msgstr "é™åˆ¶%{italicStart}从%{italicEnd}此项目访问(已废弃)"
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr "é™åˆ¶%{italicStart}访问到%{italicEnd}此项目(已废弃)"
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
-msgstr "阻止此项目中的 CI/CD 作业令牌被用于访问其他项目,除éžå°†å…¶ä»–项目添加到白åå•ä¸­ã€‚ç¦ç”¨æ­¤åŠŸèƒ½å­˜åœ¨å®‰å…¨é£Žé™©ï¼Œå› ä¸ºæœªç»æŽˆæƒçš„项目å¯èƒ½ä¼šå°è¯•æ£€ç´¢æœ‰æ•ˆä»¤ç‰Œå¹¶è®¿é—® API。%{linkStart}了解更多。%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
+msgstr "防止此项目中的 CI/CD 作业令牌被用于访问其他项目,除éžå°†å…¶ä»–项目添加到白åå•ä¸­ã€‚ç¦ç”¨æ­¤åŠŸèƒ½å­˜åœ¨å®‰å…¨é£Žé™©ï¼Œå› ä¸ºæœªç»æŽˆæƒçš„项目å¯èƒ½ä¼šå°è¯•æ£€ç´¢æ´»åŠ¨ä»¤ç‰Œå¹¶è®¿é—® API。%{linkStart}了解更多%{linkEnd}。"
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
msgstr "阻止从其他项目 CI/CD 作业令牌访问此项目,除éžå°†å…¶ä»–项目添加到白åå•ä¸­ã€‚ç¦ç”¨æ­¤åŠŸèƒ½å­˜åœ¨å®‰å…¨é£Žé™©ï¼Œå› ä¸ºæœªç»æŽˆæƒçš„项目å¯èƒ½ä¼šå°è¯•æ£€ç´¢æœ‰æ•ˆä»¤ç‰Œå¹¶è®¿é—® API。%{linkStart}了解更多。%{linkEnd}"
@@ -8933,8 +9045,8 @@ msgstr "%{code_open}.campfirenow.com%{code_close} å­åŸŸå。"
msgid "Can be manually deployed to"
msgstr "å¯ä»¥æ‰‹åŠ¨éƒ¨ç½²åˆ°"
-msgid "Can create groups:"
-msgstr "å¯ä»¥åˆ›å»ºç¾¤ç»„:"
+msgid "Can create top level groups:"
+msgstr "å¯ä»¥åˆ›å»ºé¡¶çº§ç¾¤ç»„:"
msgid "Can not delete primary training"
msgstr "ä¸èƒ½åˆ é™¤åˆçº§åŸ¹è®­"
@@ -9320,6 +9432,9 @@ msgstr "标题更改尚未ä¿å­˜"
msgid "Changes:"
msgstr "å˜æ›´ï¼š"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr "更改下方的任何设置都ä¸éœ€è¦é‡å¯åº”用。"
+
msgid "Changing any setting here requires an application restart"
msgstr "更改此处的任何设置都需è¦é‡æ–°å¯åŠ¨åº”用程åº"
@@ -9410,6 +9525,9 @@ msgstr "检查您的Dockeré•œåƒæ˜¯å¦å­˜åœ¨å·²çŸ¥æ¼æ´ž."
msgid "Check your sign-up restrictions"
msgstr "检查您的注册é™åˆ¶"
+msgid "Checkin reminder has been enabled."
+msgstr "Checkin æ醒已å¯ç”¨ã€‚"
+
msgid "Checking %{text} availability…"
msgstr "正在检查%{text}çš„å¯ç”¨æ€§..."
@@ -9466,8 +9584,8 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] "%{quantity} 个存储包"
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText}计划"
+msgid "Checkout|%{selectedPlanText}"
+msgstr "%{selectedPlanText}"
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr "选择模æ¿..."
msgid "Choose a type..."
msgstr "选择类型..."
+msgid "Choose an option"
+msgstr "选择一个选项"
+
msgid "Choose file…"
msgstr "选择文件…"
@@ -9755,7 +9876,7 @@ msgid "CiCatalog|About this project"
msgstr "关于此项目"
msgid "CiCatalog|Back to the CI/CD Catalog"
-msgstr ""
+msgstr "返回 CI/CD 目录"
msgid "CiCatalog|CI/CD Catalog"
msgstr "CI/CD 目录"
@@ -9764,7 +9885,7 @@ msgid "CiCatalog|CI/CD Catalog resource"
msgstr "CI/CD 目录资æº"
msgid "CiCatalog|Component ID not found, or you do not have permission to access component."
-msgstr ""
+msgstr "未找到组件 ID,或者您没有æƒé™è®¿é—®ç»„件。"
msgid "CiCatalog|Create a pipeline component repository and make reusing pipeline configurations faster and easier."
msgstr "创建一个æµæ°´çº¿ç»„件仓库,并使æµæ°´çº¿é…置更快,更容易。"
@@ -9785,7 +9906,7 @@ msgid "CiCatalog|Mark project as a CI/CD Catalog resource. %{linkStart}What is t
msgstr "将项目标记为 CI/CD 目录资æºã€‚%{linkStart}什么是 CI/CD 目录?%{linkEnd}"
msgid "CiCatalog|No component available"
-msgstr ""
+msgstr "æ— å¯ç”¨ç»„件"
msgid "CiCatalog|No release available"
msgstr "æ— å¯ç”¨å‘布"
@@ -9922,15 +10043,15 @@ msgstr "CI/CD å˜é‡"
msgid "CiVariables|Cancel"
msgstr "å–消"
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "当å‰å€¼æ— æ³•ä½¿ç”¨éšè—å˜é‡"
-
msgid "CiVariables|Delete variable"
msgstr "删除å˜é‡"
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr "您è¦åˆ é™¤å˜é‡ %{key} å—?"
+msgid "CiVariables|Edit Variable"
+msgstr "编辑å˜é‡"
+
msgid "CiVariables|Environments"
msgstr "环境"
@@ -9982,9 +10103,6 @@ msgstr "删除输入"
msgid "CiVariables|Remove variable"
msgstr "删除å˜é‡"
-msgid "CiVariables|Remove variable row"
-msgstr "删除å˜é‡è¡Œ"
-
msgid "CiVariables|Run job"
msgstr "è¿è¡Œä½œä¸š"
@@ -10006,12 +10124,24 @@ msgstr "获å–继承的 CI å˜é‡æ—¶å‡ºé”™ã€‚"
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr "æ­¤ %{entity} 有 %{currentVariableCount} 个定义的 CI/CD å˜é‡ã€‚æ¯ä¸ª %{entity} 的最大å˜é‡æ•°æ˜¯ %{maxVariableLimit}。è¦æ·»åŠ æ–°å˜é‡ï¼Œæ‚¨å¿…é¡»å‡å°‘定义å˜é‡çš„æ•°é‡ã€‚"
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "类型"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "值"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr "å˜é‡å°†åœ¨ä½œä¸šæ—¥å¿—中被éšè—。需è¦å€¼æ»¡è¶³æ­£åˆ™è¡¨è¾¾å¼è¦æ±‚。"
@@ -10027,9 +10157,6 @@ msgstr "å˜é‡å­˜å‚¨æ‚¨å¯ä»¥åœ¨ä½œä¸šè„šæœ¬ä¸­ä½¿ç”¨çš„ä¿¡æ¯ï¼Œå¦‚密ç å’Œå¯†
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr "您已达到å¯ç”¨å˜é‡çš„最大数é‡ã€‚è¦æ·»åŠ æ–°å˜é‡ï¼Œæ‚¨å¿…é¡»å‡å°‘定义å˜é‡çš„æ•°é‡ã€‚"
-msgid "CiVariable|* (All environments)"
-msgstr "* (所有环境)"
-
msgid "CiVariable|All environments"
msgstr "所有环境"
@@ -10040,7 +10167,7 @@ msgid "CiVariable|Define a CI/CD variable in the UI"
msgstr "在 UI 中定义一个 CI/CD å˜é‡"
msgid "CiVariable|GitLab CI/CD supports OpenID Connect (OIDC) to give your build and deployment jobs access to cloud credentials and services. %{linkStart}How do I configure OIDC for my cloud provider?%{linkEnd}"
-msgstr ""
+msgstr "æžç‹GitLab CI/CD æ”¯æŒ OpenID 连接 (OIDC),以使您的构建和部署作业能够访问云凭è¯å’ŒæœåŠ¡ã€‚%{linkStart}如何为我的云æ供商é…ç½® OIDC?%{linkEnd}"
msgid "CiVariable|Maximum of %{limit} environments listed. For more environments, enter a search query."
msgstr "最多列出 %{limit} 个环境。如需查看更多环境,请输入æœç´¢æŸ¥è¯¢ã€‚"
@@ -10052,7 +10179,7 @@ msgid "CiVariable|Search environments"
msgstr "æœç´¢çŽ¯å¢ƒ"
msgid "CiVariable|Use OIDC to securely connect to cloud services"
-msgstr ""
+msgstr "使用 OIDC 安全地连接到云æœåŠ¡"
msgid "CiVariable|Variable %{key} has been deleted."
msgstr "已删除å˜é‡ %{key}。"
@@ -10187,6 +10314,9 @@ msgstr "客户端"
msgid "Clientside DSN"
msgstr "客户端DSN"
+msgid "Clientside traces sample rate"
+msgstr "客户端跟踪采样率"
+
msgid "Clone"
msgstr "克隆"
@@ -10484,15 +10614,9 @@ msgstr "集群å¥åº·"
msgid "Cluster cache cleared."
msgstr "群集缓存已清除。"
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr "Stages::ClusterEndpointInserter需è¦é›†ç¾¤"
-
msgid "Cluster level"
msgstr "集群级别"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr "必须为 Stages::ClusterEndpointInserter 指定集群类型"
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr "%{linkStart}查看高级安装文档%{linkEnd} 。请确ä¿æ‚¨æœ‰å¯ç”¨çš„访问令牌。"
@@ -10782,6 +10906,9 @@ msgstr "此代ç†æ²¡æœ‰ä»¤ç‰Œ"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "è¦åˆ é™¤ä»£ç†ï¼Œè¯·è¾“å…¥ %{name} 进行确认:"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr "è¦ç®¡ç†æ›´å¤šä»£ç†ï¼Œ%{linkStart}请使用 Terraform%{linkEnd}。"
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr "è¦åˆ é™¤ä»£ç†ï¼Œè¯·è¾“å…¥ %{name} 进行确认:"
@@ -10806,6 +10933,9 @@ msgstr "查看所有 %{number} 个代ç†"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "查看所有 %{number} 个集群"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr "ClusterAgents|我们在 UI ä¸Šä»…æ”¯æŒ 100 个代ç†ã€‚"
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "我们想è¦äº†è§£ä½ å¯¹ GitLab Agent 的想法。"
@@ -11229,9 +11359,6 @@ msgstr "代ç è¯„审"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "代ç è¯„审分æžæ˜¾ç¤ºäº†ä¸€ä¸ªå¤„于代ç è¯„审阶段的开放åˆå¹¶è¯·æ±‚列表。 当å‰æ²¡æœ‰æ­¤é¡¹ç›®å’Œ/或筛选器的åˆå¹¶è¯·æ±‚。"
-msgid "Code Suggestions add-on"
-msgstr "代ç å»ºè®®æ’件"
-
msgid "Code Suggestions add-on status"
msgstr "代ç å»ºè®®æ’件状æ€"
@@ -11301,33 +11428,30 @@ msgstr "为此实例å¯ç”¨ä»£ç å»ºè®® %{beta}"
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr "为此实例的用户å¯ç”¨ä»£ç å»ºè®®ã€‚%{link_start}什么是代ç å»ºè®®ï¼Ÿ%{link_end}"
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr "输入新的个人访问令牌"
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
-msgstr "在 SaaS 上创建一个令牌。在您的ç§æœ‰åŒ–部署版实例上使用代ç å»ºè®®éœ€è¦æ­¤ä»¤ç‰Œã€‚ %{link_start}如何创建令牌?%{link_end}"
-
-msgid "CodeSuggestionsSM|Personal access token"
-msgstr "个人访问令牌"
-
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
-msgstr "%{code_suggestions_link_start}代ç å»ºè®®%{link_end}现在使用第三方 AI æœåŠ¡æ¥æ供更高质é‡çš„建议。您å¯ä»¥%{third_party_link_start}为您的群组ç¦ç”¨ç¬¬ä¸‰æ–¹æœåŠ¡%{link_end} ,或者在%{profile_settings_link_start}您的用户é…置文件%{link_end}中完全ç¦ç”¨ä»£ç å»ºè®®ã€‚"
-
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
-msgstr "我们使用第三方 AI æœåŠ¡æ¥æ”¹è¿›ä»£ç å»ºè®®ã€‚"
-
msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr "%{link_start}什么是代ç å»ºè®®ï¼Ÿ%{link_end}"
msgid "CodeSuggestions|Code Suggestions"
msgstr "代ç å»ºè®®"
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
+msgstr ""
+
msgid "CodeSuggestions|Enable Code Suggestions"
msgstr "å¯ç”¨ä»£ç å»ºè®®"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
+msgstr ""
+
msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr "在 IDE 中编写代ç æ—¶èŽ·å–代ç å»ºè®®ã€‚%{link_start}了解更多%{link_end}。"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
+msgstr "介ç»ä»£ç å»ºè®®æ’件"
+
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
+msgstr ""
+
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
msgstr "此群组中的项目å¯ä»¥ä½¿ç”¨ä»£ç å»ºè®®"
@@ -11395,6 +11519,9 @@ msgstr "用户人群显示过去%{months_included}个月内的状况。åªæœ‰æ´»
msgid "Collapse"
msgstr "收起"
+msgid "Collapse AI-generated summary"
+msgstr "æŠ˜å  AI 生æˆçš„摘è¦"
+
msgid "Collapse all threads"
msgstr "折å æ‰€æœ‰ä¸»é¢˜"
@@ -11753,9 +11880,6 @@ msgstr "加载分支/标签列表时å‘生错误。请é‡è¯•ã€‚"
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "æœç´¢åˆ†æ”¯/标签列表时å‘生错误。请é‡è¯•ã€‚"
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "更新分支/标签列表时å‘生错误。请é‡è¯•ã€‚"
-
msgid "CompareRevisions|View open merge request"
msgstr "查看开放的åˆå¹¶è¯·æ±‚"
@@ -11801,6 +11925,9 @@ msgstr "åˆè§„中心"
msgid "Compliance framework"
msgstr "åˆè§„框架"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr "åˆè§„框架|主动åˆè§„框架"
+
msgid "ComplianceFrameworks|Add framework"
msgstr "添加框架"
@@ -11858,8 +11985,8 @@ msgstr "获å–åˆè§„框架数æ®æ—¶å‡ºé”™ã€‚请刷新页é¢æˆ–å°è¯•å…¶å®ƒçš„框
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr "设置默认åˆè§„框架时出错"
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
-msgstr "已添加的框架将出现在此处。"
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr "已添加的框架将出现在此处,首先在上é¢åˆ›å»ºä¸€ä¸ªæ–°æ¡†æž¶ã€‚"
msgid "ComplianceFrameworks|Invalid format"
msgstr "无效格å¼"
@@ -12074,15 +12201,18 @@ msgstr "ç§å¯†æ€§"
msgid "Configuration help"
msgstr "é…置帮助"
+msgid "Configure"
+msgstr ""
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "é…ç½® %{italic_start}新增功能%{italic_end} 抽屉和内容。"
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
-msgstr "é…ç½® %{link} æ¥è·Ÿè¸ªäº‹ä»¶ã€‚ %{link_start}了解更多信æ¯ã€‚%{link_end}"
-
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr "在仓库上é…ç½® %{repository_checks_link_start}仓库检查%{link_end} å’Œ %{housekeeping_link_start}例行维护%{link_end}。"
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr "é…ç½® %{snowplow_link_start}Snowplow%{snowplow_link_end} æ¥è·Ÿè¸ªäº‹ä»¶ã€‚ %{help_link_start}了解更多。%{help_link_end}"
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr "é…ç½® CAPTCHAã€IP 地å€é™åˆ¶å’Œå…¶ä»–å垃圾邮件措施。"
@@ -12146,6 +12276,9 @@ msgstr "é…置高级æƒé™ã€å¤§æ–‡ä»¶å­˜å‚¨ã€åŒé‡èº«ä»½éªŒè¯å’Œ CI/CD 设ç½
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr "调整高级æƒé™ã€å¤§æ–‡ä»¶å­˜å‚¨ã€åŒé‡è®¤è¯å’Œå®¢æˆ·å…³ç³»è®¾ç½®ã€‚"
+msgid "Configure checkin reminder frequency"
+msgstr "é…ç½® checkin æ醒频率"
+
msgid "Configure custom rules for Jira issue key matching"
msgstr "为 Jira 议题密钥匹é…é…置自定义规则"
@@ -12317,6 +12450,9 @@ msgstr "连接失败"
msgid "Consistency guarantee method"
msgstr "一致性ä¿éšœæ–¹æ³•"
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "è”系支æŒ"
@@ -12333,7 +12469,7 @@ msgid "Container Scanning"
msgstr "容器扫æ"
msgid "Container must be a group."
-msgstr ""
+msgstr "容器必须是一个组。"
msgid "Container must be a project or a group."
msgstr "容器必须是一个项目或一个群组。"
@@ -12443,7 +12579,7 @@ msgid "ContainerRegistry|Created %{time}"
msgstr "创建于 %{time}"
msgid "ContainerRegistry|Delete image repository"
-msgstr ""
+msgstr "删除镜åƒä»“库"
msgid "ContainerRegistry|Delete image repository?"
msgstr "删除镜åƒä»“库?"
@@ -12612,7 +12748,7 @@ msgid "ContainerRegistry|Tags successfully marked for deletion."
msgstr "标签已æˆåŠŸè®¾ç½®ä¸ºå¾…删除。"
msgid "ContainerRegistry|Tags that match %{strongStart}any of%{strongEnd} these rules are %{strongStart}kept%{strongEnd}, even if they match a removal rule below. The %{strongStart}latest%{strongEnd} tag is always kept."
-msgstr ""
+msgstr "ç¬¦åˆ %{strongStart}任何 %{strongEnd}这些规则的标签将被 %{strongStart}ä¿ç•™ %{strongEnd},å³ä½¿å®ƒä»¬åŒ¹é…以下删除规则。始终ä¿ç•™ %{strongStart}最新 %{strongEnd}的标签。"
msgid "ContainerRegistry|Tags that match these rules are %{strongStart}removed%{strongEnd}, unless a rule above says to keep them."
msgstr "匹é…这些规则的标签将被%{strongStart}移除%{strongEnd},除éžä»¥ä¸Šä»»ä¸€è§„则è¦æ±‚ä¿ç•™å®ƒä»¬ã€‚"
@@ -12836,6 +12972,9 @@ msgstr "已在 %{resourceParentLink} 中添加设计 %{targetLink}。"
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr "已批准 %{resourceParentLink} 中的åˆå¹¶è¯·æ±‚ %{targetLink}。"
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr "存档 %{resourceParentLink} 中的设计。"
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr "已在 %{resourceParentLink} 中关闭å²è¯— %{targetLink}。"
@@ -12869,6 +13008,30 @@ msgstr "已在 %{resourceParentLink} 中关闭任务 %{targetLink}。"
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr "已在 %{resourceParentLink} 中关闭测试用例 %{targetLink}。"
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr "评论了 %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr "在 %{resourceParentLink} 中评论了å²è¯— %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr "对 %{resourceParentLink} 中的æ交 %{noteableLink} 进行了评论。"
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr "评论了 %{resourceParentLink} 中的设计 %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr "评论了 %{resourceParentLink} 中的议题 %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr "评论了 %{resourceParentLink} 中的åˆå¹¶è¯·æ±‚ %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr "评论了 %{resourceParentLink}中的代ç ç‰‡æ®µ %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr "评论了代ç ç‰‡æ®µ %{noteableLink}。"
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr "已创建项目 %{resourceParentLink}。"
@@ -12881,9 +13044,18 @@ msgstr "已在 %{resourceParentLink} 中创建 wiki é¡µé¢ %{targetLink}。"
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr "已删除 %{resourceParentLink} 中的分支 %{refLink}。"
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr "删除了 %{resourceParentLink} 中的里程碑。"
+
+msgid "ContributionEvent|Deleted resource."
+msgstr "已删除的资æºã€‚"
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr "已删除 %{resourceParentLink} 中的标签 %{refLink}。"
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr "删除了 %{resourceParentLink} 中的 Wiki 页é¢ã€‚ "
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr "已加入项目 %{resourceParentLink}。"
@@ -12939,37 +13111,46 @@ msgid "ContributionEvent|Removed due to membership expiration from %{resourcePar
msgstr "由于会员资格到期,已从 %{resourceParentLink} 中删除。"
msgid "ContributionEvent|Reopened Epic %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“å¼€å²è¯— %{targetLink}。"
msgid "ContributionEvent|Reopened incident %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“开事件 %{targetLink}。"
msgid "ContributionEvent|Reopened issue %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“开议题 %{targetLink}。"
msgid "ContributionEvent|Reopened key result %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“开关键结果 %{targetLink}。"
msgid "ContributionEvent|Reopened merge request %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“å¼€åˆå¹¶è¯·æ±‚ %{targetLink}。"
msgid "ContributionEvent|Reopened milestone %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“开里程碑 %{targetLink}。"
msgid "ContributionEvent|Reopened objective %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“开目标 %{targetLink}。"
msgid "ContributionEvent|Reopened requirement %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“å¼€è¦æ±‚ %{targetLink}。"
msgid "ContributionEvent|Reopened resource."
-msgstr ""
+msgstr "é‡æ–°æ‰“开资æºã€‚"
msgid "ContributionEvent|Reopened task %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“开任务 %{targetLink}。"
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "已在 %{resourceParentLink} 中é‡æ–°æ‰“开测试用例 %{targetLink}。"
+
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr "更新了 %{resourceParentLink} 中的设计 %{targetLink}。"
+
+msgid "ContributionEvent|Updated resource."
+msgstr "更新了资æºã€‚"
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr "更新了 %{resourceParentLink} 中的 Wiki 页 %{targetLink}。"
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr "…和 %{count} 次更多的æ交。%{linkStart}比较%{linkEnd}。"
@@ -13191,10 +13372,10 @@ msgid "CorpusManagement|Total Size: %{totalSize}"
msgstr "总大å°ï¼š %{totalSize}"
msgid "Cost Factor Settings"
-msgstr "æˆæœ¬å› ç´ è®¾ç½®"
+msgstr "消耗系数设置"
msgid "Cost factor for forks of projects"
-msgstr "派生项目的æˆæœ¬å› ç´ "
+msgstr "派生项目的消耗系数"
msgid "Could not access the Wiki Repository at this time."
msgstr "ç›®å‰æ— æ³•è®¿é—® Wiki 仓库。"
@@ -13503,7 +13684,7 @@ msgid "Create phone verification exemption"
msgstr "创建电è¯éªŒè¯è±å…"
msgid "Create pipeline trigger token"
-msgstr ""
+msgstr "创建æµæ°´çº¿è§¦å‘令牌"
msgid "Create project"
msgstr "新建项目"
@@ -13517,6 +13698,9 @@ msgstr "创建å‘布"
msgid "Create requirement"
msgstr "创建需求"
+msgid "Create rules for target branches in merge requests."
+msgstr "为åˆå¹¶è¯·æ±‚中的目标分支创建规则。"
+
msgid "Create service account"
msgstr "创建æœåŠ¡å¸æˆ·"
@@ -13895,9 +14079,6 @@ msgstr "已添加组织"
msgid "Crm|Organization has been updated."
msgstr "组织已更新。"
-msgid "Cron Timezone"
-msgstr "Cron 时区"
-
msgid "Cron time zone"
msgstr "Cron时区"
@@ -14235,9 +14416,6 @@ msgstr "æ¢å¤æœåŠ¡çš„时间"
msgid "CycleAnalytics|Total time"
msgstr "总时间"
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "群组下拉列表筛选器"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr "ä¸é€‚用于给定的开始事件"
@@ -14411,6 +14589,9 @@ msgstr "中"
msgid "DORA4Metrics|Merge request throughput"
msgstr "åˆå¹¶è¯·æ±‚åžåé‡"
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr "%{name} 的指标比较"
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr "%{name} 群组的指标比较"
@@ -14501,6 +14682,9 @@ msgstr "æ¢å¤æœåŠ¡çš„时间(中ä½å¤©æ•°ï¼‰"
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr "为了帮助我们改进显示预测功能,请在 %{linkStart}这个议题%{linkEnd} 中å馈您的体验。"
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr "为了帮助我们改进价值æµç®¡ç†ä»ªè¡¨ç›˜ï¼Œè¯·åœ¨ %{linkStart}调查表%{linkEnd} 中å馈您的体验。"
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr "å‘生影å“用户的æœåŠ¡äº‹æ•…或缺陷时,æ¢å¤æœåŠ¡éœ€è¦ä¸è¶…过 1 天。"
@@ -14723,6 +14907,9 @@ msgstr "æœ€å° = 0 (无超时),最大 = 2880 分钟"
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "æœ€å° = 1秒,最大 = 3600秒"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr "修改 URL 将清除之å‰è¾“入的附加请求标头和密ç å­—段的任何值。"
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr "监控å‘é€åˆ°ç›®æ ‡çš„所有 HTTP 请求æ¥æŸ¥æ‰¾æ½œåœ¨æ¼æ´žã€‚"
@@ -15010,7 +15197,7 @@ msgid "Data type"
msgstr "æ•°æ®ç±»åž‹"
msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but this version of GitLab requires PostgreSQL %{pg_version_minimum}. Please upgrade your environment to a supported PostgreSQL version. See %{pg_requirements_url} for details."
-msgstr ""
+msgstr "æ•°æ®åº““%{database_name}â€æ­£åœ¨ä½¿ç”¨ PostgreSQL %{pg_version_current},但此版本的æžç‹GitLab éœ€è¦ PostgreSQL %{pg_version_minimum}。请将您的环境å‡çº§åˆ°å—支æŒçš„ PostgreSQL ç‰ˆæœ¬ã€‚è¯¦è§ %{pg_requirements_url}。"
msgid "Database update failed"
msgstr "æ•°æ®åº“更新失败"
@@ -15226,9 +15413,6 @@ msgstr "使用 Cron 语法定义自定义模å¼"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr "定义独立于Akismet的垃圾邮件自定义规则"
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "在%{code_open}.gitlab-ci.yml%{code_close}的部署阶段中定义环境æ¥è·Ÿè¸ªéƒ¨ç½²ã€‚"
-
msgid "Define how approval rules are applied to merge requests."
msgstr "定义审核规则如何应用于åˆå¹¶è¯·æ±‚。"
@@ -15318,7 +15502,7 @@ msgid "Delete corpus"
msgstr "删除语料库"
msgid "Delete custom emoji"
-msgstr ""
+msgstr "删除自定义表情"
msgid "Delete deploy key"
msgstr "删除部署密钥"
@@ -15350,9 +15534,6 @@ msgstr "删除标记:%{labelName}"
msgid "Delete pipeline"
msgstr "删除æµæ°´çº¿"
-msgid "Delete pipeline schedule"
-msgstr "删除æµæ°´çº¿è®¡åˆ’"
-
msgid "Delete project"
msgstr "删除项目"
@@ -15568,6 +15749,9 @@ msgstr "ä½ç½®å’Œä¾èµ–项路径"
msgid "Dependencies|Packager"
msgstr "包管ç†å·¥å…·"
+msgid "Dependencies|Project list unavailable"
+msgstr "项目列表ä¸å¯ç”¨"
+
msgid "Dependencies|Projects"
msgstr "项目"
@@ -15586,6 +15770,9 @@ msgstr "组件ä¾èµ–路径基于é”定文件。有å¯èƒ½æœ‰å¤šä¸ªè·¯å¾„。在这
msgid "Dependencies|There may be multiple paths"
msgstr "å¯èƒ½æœ‰å¤šä¸ªè·¯å¾„"
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr "该群组的数é‡è¶…过了最大å­ç»„æ•° 600 çš„é™åˆ¶ã€‚ç›®å‰æˆ‘们无法准确显示项目列表。请访问å­ç»„ä¾èµ–项列表以查看此信æ¯ï¼Œæˆ–å‚阅 %{linkStart}ä¾èµ–项列表帮助 %{linkEnd} 页以了解更多信æ¯ã€‚"
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "切æ¢æ¼æ´žåˆ—表"
@@ -15766,6 +15953,12 @@ msgstr "时区"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} 其他"
+msgid "DeployKeys|Add new deploy key"
+msgstr "添加新的部署密钥"
+
+msgid "DeployKeys|Add new key"
+msgstr "添加新密钥"
+
msgid "DeployKeys|Current project"
msgstr "当å‰é¡¹ç›®"
@@ -15793,8 +15986,8 @@ msgstr "授予此密钥写入æƒé™"
msgid "DeployKeys|Loading deploy keys"
msgstr "加载部署密钥"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "没有找到部署密钥。请使用上é¢çš„表å•åˆ›å»ºéƒ¨ç½²å¯†é’¥ã€‚"
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr "未找到部署密钥,首先在上é¢æ·»åŠ ä¸€ä¸ªæ–°å¯†é’¥ã€‚"
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "ç§æœ‰è®¿é—®çš„部署密钥"
@@ -15808,8 +16001,8 @@ msgstr "公开访问的部署密钥"
msgid "DeployKeys|Read access only"
msgstr "åªè¯»æƒé™"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "å¯ç”¨éƒ¨ç½²ä»¤ç‰Œï¼ˆ%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr "已激活部署令牌"
msgid "DeployTokens|Allows read and write access to registry images."
msgstr "å…许对容器镜åƒåº“进行读写访问。"
@@ -15832,6 +16025,9 @@ msgstr "å…许以åªè¯»æƒé™è®¿é—®ä»£ç ä»“库。"
msgid "DeployTokens|Allows write access to registry images."
msgstr "å…许写入仓库镜åƒã€‚"
+msgid "DeployTokens|Cancel"
+msgstr "å–消"
+
msgid "DeployTokens|Copy deploy token"
msgstr "å¤åˆ¶éƒ¨ç½²ä»¤ç‰Œ"
@@ -15892,8 +16088,8 @@ msgstr "有效范围"
msgid "DeployTokens|Scopes (select at least one)"
msgstr "范围(至少选择一个)"
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
-msgstr "该%{entity_type}æ— å¯ç”¨çš„部署令牌。"
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
+msgstr "此 %{entity_type} 没有已激活的部署令牌。"
msgid "DeployTokens|This action cannot be undone."
msgstr "æ­¤æ“作无法撤消。"
@@ -15910,12 +16106,12 @@ msgstr "用户å"
msgid "DeployTokens|Username (optional)"
msgstr "用户å (å¯é€‰)"
-msgid "DeployTokens|Your New Deploy Token"
-msgstr "您的新部署令牌"
-
msgid "DeployTokens|Your new Deploy Token username"
msgstr "您的新部署令牌用户å"
+msgid "DeployTokens|Your new deploy token"
+msgstr "您的新部署令牌"
+
msgid "DeployTokens|Your new group deploy token has been created."
msgstr "您的新群租部署令牌已创建。"
@@ -15997,6 +16193,12 @@ msgstr "由您批准于 %{time}"
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr "批准将从部署 #%{deploymentIid}è¿è¡Œæ‰‹åŠ¨ä½œä¸šã€‚æ‹’ç»å°†ä½¿æ‰‹åŠ¨ä½œä¸šå¤±è´¥ã€‚"
+msgid "DeploymentApproval|Deployment approved"
+msgstr "部署已批准"
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr "部署被拒ç»"
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr "部署等级: %{tier}"
@@ -16067,9 +16269,6 @@ msgstr "在 %{code_open}.gitlab-ci.yml%{code_close} 的部署阶段中定义环å
msgid "Deployments|You don't have any deployments right now."
msgstr "您现在没有任何部署。"
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "å·²å–消"
@@ -16082,6 +16281,24 @@ msgstr "部署 ID"
msgid "Deployment|Failed"
msgstr "失败"
+msgid "Deployment|Flux sync failed"
+msgstr "Flux åŒæ­¥å¤±è´¥"
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr "Flux åŒæ­¥å·²æˆåŠŸåè°ƒ"
+
+msgid "Deployment|Flux sync reconciling"
+msgstr "Flux åŒæ­¥åè°ƒ"
+
+msgid "Deployment|Flux sync stalled"
+msgstr "Flux åŒæ­¥åœæ­¢"
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr "Flux åŒæ­¥çŠ¶æ€ä¸å¯ç”¨"
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr "Flux åŒæ­¥çŠ¶æ€æœªçŸ¥"
+
msgid "Deployment|Latest Deployed"
msgstr "最近一次部署"
@@ -16097,12 +16314,15 @@ msgstr "已跳过"
msgid "Deployment|Success"
msgstr "æˆåŠŸ"
-msgid "Deployment|This deployment was created using the API"
-msgstr "此部署使用API创建"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr "åŒæ­¥çŠ¶æ€æœªçŸ¥ã€‚%{linkStart}如何为我的部署é…ç½® Flux?%{linkEnd}"
msgid "Deployment|Triggerer"
msgstr "触å‘器"
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr "无法检测状æ€ã€‚%{linkStart}如何检测状æ€ï¼Ÿ%{linkEnd}"
+
msgid "Deployment|Unavailable"
msgstr "ä¸å¯ç”¨"
@@ -16172,12 +16392,6 @@ msgstr "设计"
msgid "Design Management files and data"
msgstr "设计管ç†æ–‡ä»¶å’Œæ•°æ®"
-msgid "Design repositories"
-msgstr "设计仓库"
-
-msgid "Design repository"
-msgstr "设计仓库"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design}/%{designs_count}"
@@ -17366,9 +17580,6 @@ msgstr "邮件已å‘é€"
msgid "Email the pipeline status to a list of recipients."
msgstr "å°†æµæ°´çº¿çŠ¶æ€å‘é€åˆ°æ”¶ä»¶äººåˆ—表。"
-msgid "Email updates (optional)"
-msgstr "电å­é‚®ä»¶æ›´æ–°(å¯é€‰)"
-
msgid "Email:"
msgstr "电å­é‚®ä»¶ï¼š"
@@ -17411,6 +17622,9 @@ msgstr "%{emails},%{andMore} 将收到您的评论通知。"
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "还有 %{moreCount} 个"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr "将您的电å­é‚®ä»¶æ›´æ–°ä¸ºæœ‰æ•ˆçš„永久地å€ã€‚如果您使用临时电å­é‚®ä»¶ï¼Œç¨åŽå°†æ— æ³•ç™»å½•ã€‚"
+
msgid "Emails"
msgstr "电å­é‚®ä»¶"
@@ -17549,9 +17763,6 @@ msgstr "å¯ç”¨ç¾¤ç»„Runner"
msgid "Enable header and footer in emails"
msgstr "在电å­é‚®ä»¶ä¸­å¯ç”¨é¡µçœ‰å’Œé¡µè„š"
-msgid "Enable in-product marketing emails"
-msgstr "接收产å“è¥é”€ç”µå­é‚®ä»¶"
-
msgid "Enable incident management inbound alert limit"
msgstr "å¯ç”¨äº‹ä»¶ç®¡ç†å…¥ç«™è­¦æŠ¥é™åˆ¶"
@@ -17573,8 +17784,8 @@ msgstr "请仅对å¯å®‰å…¨å­˜å‚¨å®¢æˆ·ç«¯ secret çš„å¯ä¿¡ä»»åŽç«¯æœåŠ¡å™¨ä¸“ç
msgid "Enable or disable version check and Service Ping."
msgstr "å¯ç”¨æˆ–ç¦ç”¨ç‰ˆæœ¬æ£€æŸ¥å’ŒæœåŠ¡Ping。"
-msgid "Enable rate limiting for POST requests to the specified paths"
-msgstr "为指定路径的 POST 请求å¯ç”¨é€ŸçŽ‡é™åˆ¶"
+msgid "Enable rate limiting for requests to the specified paths"
+msgstr "å¯ç”¨å¯¹æŒ‡å®šè·¯å¾„请求的速率é™åˆ¶"
msgid "Enable reCAPTCHA"
msgstr "å¯ç”¨ reCAPTCHA"
@@ -17667,7 +17878,7 @@ msgid "End time"
msgstr "结æŸæ—¶é—´"
msgid "Endpoint name '%{endpoint}' of component '%{component}' must not start with '%{prefix}'"
-msgstr ""
+msgstr "组件“%{component}â€çš„端点å称“%{endpoint}â€ä¸å¾—以“%{prefix}â€å¼€å¤´"
msgid "Ends"
msgstr "结æŸ"
@@ -17687,9 +17898,6 @@ msgstr "对所有用户登录强制执行åŒé‡è®¤è¯ã€‚"
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr "通过将æœåŠ¡å¸æˆ·å¯†é’¥å­˜å‚¨åœ¨ secret 管ç†å™¨ä¸­æ¥å¢žå¼ºå®‰å…¨æ€§ - 了解更多关于 %{docLinkStart}使用 GitLab%{docLinkEnd} 进行 secret 管ç†çš„ä¿¡æ¯"
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr "如需跟踪到群集的部署,请确ä¿æ‚¨çš„%{linkStart}环境包å«äºŽCIæµæ°´çº¿çš„部署阶段%{linkEnd}。"
@@ -17801,8 +18009,8 @@ msgstr "环境"
msgid "Environment scope"
msgstr "环境范围"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr "æ­¤GitLab实例上的环境å˜é‡è¢«é»˜è®¤é…置为%{link_start}å—ä¿æŠ¤%{link_end}."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr "æ­¤æžç‹GitLab 实例上的环境å˜é‡è¢«é…置为默认%{help_link_start}å—ä¿æŠ¤%{help_link_end}。"
msgid "Environment:"
msgstr "环境:"
@@ -17948,12 +18156,18 @@ msgstr "环境入门"
msgid "Environments|GitLab agent"
msgstr "GitLab 代ç†"
+msgid "Environments|HelmReleases"
+msgstr "HelmReleases"
+
msgid "Environments|Job"
msgstr "作业"
msgid "Environments|Kubernetes namespace (optional)"
msgstr "Kubernetes 命å空间(å¯é€‰ï¼‰"
+msgid "Environments|Kustomizations"
+msgstr "Kustomizations"
+
msgid "Environments|Learn more about stopping environments"
msgstr "了解更多关于如何终止环境的信æ¯"
@@ -17999,6 +18213,12 @@ msgstr "回滚环境 %{name}?"
msgid "Environments|Search by environment name"
msgstr "按环境å称æœç´¢"
+msgid "Environments|Select Flux resource"
+msgstr "选择 Flux 资æº"
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr "选择 Flux 资æºï¼ˆå¯é€‰ï¼‰"
+
msgid "Environments|Select agent"
msgstr "选择代ç†"
@@ -18035,6 +18255,9 @@ msgstr "æ­¤æ“作将%{docsStart}é‡è¯•å¸¦æœ‰æ交 %{commitId} 的最新部署%{
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr "æ­¤æ“作将%{docsStart}将此环境%{docsEnd}回滚到先å‰æˆåŠŸéƒ¨ç½²çš„æ交 %{commitId}。您确定è¦ç»§ç»­å—?"
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr "无法从此环境访问以下资æºã€‚请检查您对以下内容的授æƒï¼Œç„¶åŽé‡è¯•ï¼š"
+
msgid "Environments|Upcoming"
msgstr "å³å°†æŽ¨å‡º"
@@ -18137,6 +18360,12 @@ msgstr "åŒæ­¥çŠ¶æ€"
msgid "Environment|There was an error connecting to the cluster agent."
msgstr "连接到集群代ç†æ—¶å‡ºé”™ã€‚"
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr "èŽ·å– %{resourceType} 时出错。"
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr "未ç»æŽˆæƒä»Žæ­¤çŽ¯å¢ƒè®¿é—® %{resourceType}。"
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr "æ— æƒä»Žæ­¤çŽ¯å¢ƒè®¿é—®é›†ç¾¤ä»£ç†ã€‚检查您的身份验è¯å¹¶é‡è¯•ã€‚"
@@ -18891,6 +19120,9 @@ msgstr "现有的登录方法å¯èƒ½ä¼šè¢«åˆ é™¤"
msgid "Expand"
msgstr "展开"
+msgid "Expand AI-generated summary"
+msgstr "展开 AI 生æˆçš„摘è¦"
+
msgid "Expand all"
msgstr "展开全部"
@@ -19137,6 +19369,9 @@ msgstr "https://example.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr "失败"
@@ -19224,13 +19459,13 @@ msgid "Failed to create resources"
msgstr "创建资æºå¤±è´¥"
msgid "Failed to create target branch rule"
-msgstr ""
+msgstr "创建目标分支规则失败"
msgid "Failed to create wiki"
msgstr "创建Wiki失败"
msgid "Failed to delete custom emoji. Please try again."
-msgstr ""
+msgstr "删除自定义表情失败,请é‡è¯•ã€‚"
msgid "Failed to deploy to"
msgstr "无法部署到"
@@ -19791,9 +20026,6 @@ msgstr "按当å‰å·²å½’档的测试用例筛选。"
msgid "Filter by test cases that are currently open."
msgstr "按当å‰å¼€æ”¾çš„测试用例进行过滤。"
-msgid "Filter by user"
-msgstr "按用户筛选"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr "筛选å‚数无效。请确ä¿ç»“æŸæ—¥æœŸåœ¨å¼€å§‹æ—¥æœŸä¹‹åŽã€‚"
@@ -19818,9 +20050,6 @@ msgstr "筛选结果..."
msgid "Filter users"
msgstr "过滤用户"
-msgid "Filter..."
-msgstr "筛选..."
-
msgid "Finalizing"
msgstr "正在完æˆ"
@@ -20017,7 +20246,7 @@ msgid "For more information, see the File Hooks documentation."
msgstr "欲了解更多信æ¯ï¼Œè¯·å‚阅文件钩å­æ–‡æ¡£ã€‚"
msgid "For the GitLab Team to keep your subscription data up to date, this is a reminder to report your license usage on a monthly basis, or at the cadence set in your agreement with GitLab. This allows us to simplify the billing process for overages and renewals. To report your usage data, export your license usage file and email it to %{renewal_service_email}. If you need an updated license, GitLab will send the license to the email address registered in the %{customers_dot}, and you can upload this license to your instance."
-msgstr ""
+msgstr "为了让您的订阅数æ®ä¿æŒæœ€æ–°ï¼Œæžç‹GitLab 团队æ醒您æ¯æœˆæŠ¥å‘Šæ‚¨çš„许å¯è¯ä½¿ç”¨æƒ…况,或者按照您与æžç‹GitLab çš„å议中设置的频率进行报告。这使我们能够简化超é¢å’Œç»­è®¢çš„计费æµç¨‹ã€‚è¦æŠ¥å‘Šæ‚¨çš„使用数æ®ï¼Œè¯·å¯¼å‡ºæ‚¨çš„许å¯ä½¿ç”¨æƒ…况文件并通过电å­é‚®ä»¶å°†å…¶å‘é€åˆ° %{renewal_service_email}。如果您需è¦æ›´æ–°çš„许å¯è¯ï¼Œæžç‹GitLab 将把许å¯è¯å‘é€åˆ°åœ¨ %{customers_dot} 中注册的电å­é‚®ä»¶åœ°å€ï¼Œæ‚¨å¯ä»¥å°†æ­¤è®¸å¯è¯ä¸Šä¼ åˆ°æ‚¨çš„实例。"
msgid "For the next few releases, you can go to your avatar at any time to turn the new navigation on and off."
msgstr "对于今åŽå‡ ä¸ªç‰ˆæœ¬ï¼Œæ‚¨å¯ä»¥éšæ—¶ç‚¹å‡»æ‚¨çš„头åƒï¼Œç„¶åŽæ‰“开或关闭新导航æ ã€‚"
@@ -20188,33 +20417,6 @@ msgstr "å…费顶级群组近期将é™åˆ¶ä¸ºæœ€å¤š %{free_users_limit} 个用户
msgid "Free trial will expire in %{days}"
msgstr "å…费试用将在 %{days} 天åŽåˆ°æœŸ"
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "或者,您å¯ä»¥å‡çº§åˆ°ä¸“业版或旗舰版:"
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "探索付费计划"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "探索付费计划:"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr "æ ¹æ®æˆ‘们在 %{date_time} è¿è¡Œçš„检查,您似乎已达到 “%{namespace_name}†的 %{free_user_limit} 个æˆå‘˜çš„é™åˆ¶ã€‚您ä¸èƒ½å†æ·»åŠ æˆå‘˜ï¼Œä½†å¯ä»¥ç®¡ç†çŽ°æœ‰æˆå‘˜ï¼Œä¾‹å¦‚,删除ä¸æ´»è·ƒçš„æˆå‘˜å¹¶ç”¨æ–°æˆå‘˜æ›¿æ¢ä»–们。"
-
-msgid "FreeUserCap|Manage members"
-msgstr "管ç†æˆå‘˜"
-
-msgid "FreeUserCap|Manage members:"
-msgstr "管ç†æˆå‘˜ï¼š"
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr "è¦èŽ·å¾—更多æˆå‘˜ï¼Œ%{trial_link_start}开始试用 %{trial_link_end}或%{upgrade_link_start}å‡çº§%{upgrade_link_end}到专业版或旗舰版。"
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr "è¦èŽ·å¾—更多æˆå‘˜ï¼Œè¯·å¼€å§‹è¯•ç”¨ï¼š"
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr "您已达到æˆå‘˜é™åˆ¶ï¼"
-
msgid "Freeze end"
msgstr "冻结结æŸ"
@@ -20907,6 +21109,12 @@ msgstr "获得å…费的实例评估"
msgid "Get a support subscription"
msgstr "获å–支æŒè®¢é˜…"
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr "获å–更多关于故障排除æµæ°´çº¿çš„ä¿¡æ¯"
+
msgid "Get started"
msgstr "马上开始"
@@ -21234,6 +21442,9 @@ msgstr "未验è¯"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "正在更新您的页é¢é…ç½®..."
+msgid "GitLabPages|Use multiple versions"
+msgstr "使用多个版本"
+
msgid "GitLabPages|Use unique domain"
msgstr "使用唯一域å"
@@ -21249,6 +21460,9 @@ msgstr "å¯ç”¨åŽï¼Œä¼šç”Ÿæˆä¸€ä¸ªå”¯ä¸€çš„域åæ¥è®¿é—®é¡µé¢ã€‚"
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr "å¯ç”¨åŽï¼Œæ‰€æœ‰é€šè¿‡HTTP的访问å°è¯•éƒ½ä¼šè‡ªåŠ¨é‡å®šå‘到HTTPS,使用状æ€ä»£ç 301。 需è¦å¯¹æ‰€æœ‰åŸŸå有效的è¯ä¹¦ã€‚%{docs_link_start}了解更多信æ¯ã€‚%{link_end}"
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr "å¯ç”¨åŽï¼Œæ‚¨å¯ä»¥åˆ›å»ºå¤šä¸ªé¡µé¢ç«™ç‚¹çš„版本。"
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr "当在 GitLab 实例 (%{pages_host})的一般域å下使用 Pages 时,您ä¸èƒ½ä½¿ç”¨ HTTPS 与å­åŸŸçš„å­åŸŸå。 如果您的命å空间或群组å称包å«ä¸€ä¸ªç‚¹ï¼Œè¯¥å称无效。这是一个 HTTP On TLS å议的é™åˆ¶ã€‚ 如果您ä¸å°† HTTP é‡å®šå‘到 HTTPS ,HTTP 页é¢å¯ä»¥æ­£å¸¸å·¥ä½œã€‚ %{docs_link_start}了解更多信æ¯ã€‚%{link_end}"
@@ -21264,12 +21478,6 @@ msgstr "您的项目已为 Pages é…置。现在我们必须等待æµæ°´çº¿ç¬¬ä¸
msgid "Gitaly Servers"
msgstr "GitalyæœåŠ¡å™¨"
-msgid "Gitaly relative path:"
-msgstr "Gitaly相对路径:"
-
-msgid "Gitaly storage name:"
-msgstr "Gitaly存储å称:"
-
msgid "Gitaly timeouts"
msgstr "Gitaly 超时"
@@ -21390,8 +21598,8 @@ msgstr "é…ç½®ä¸ºè¯»å– GitLab 项目的 Gitpod 实例的 URL,例如 https://g
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr "è¦ä½¿ç”¨ Gitpod,您必须首先在您的%{linkStart}用户å好设置%{linkEnd}的集æˆéƒ¨åˆ†ä¸­å¯ç”¨è¯¥åŠŸèƒ½ã€‚"
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
-msgstr "è¦ä½¿ç”¨é›†æˆï¼Œæ¯ä¸ªç”¨æˆ·è¿˜å¿…须在其 GitLab è´¦å·ä¸Šå¯ç”¨ Gitpod。 %{link_start}如何å¯ç”¨å®ƒï¼Ÿ%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr "è¦ä½¿ç”¨é›†æˆï¼Œæ¯ä¸ªç”¨æˆ·è¿˜å¿…须在其æžç‹GitLab 账户上å¯ç”¨ Gitpod。%{help_link_start}如何å¯ç”¨å®ƒï¼Ÿ%{help_link_end}"
msgid "Gitpod|https://gitpod.example.com"
msgstr "https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr "%{time_ago}授æƒè®¿é—®"
msgid "Given epic is already related to this epic."
msgstr "给定å²è¯—å·²ç»ä¸Žæ­¤å²è¯—å…³è”。"
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr "给定的输入未在包å«çš„é…置文件的 `spec` 部分中定义"
+
msgid "Global SAML group membership lock"
msgstr "全局 SAML 组æˆå‘˜èº«ä»½é”定"
@@ -21429,6 +21640,9 @@ msgstr "%{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr "æä¾› %{count} 个默认结果,使用上下箭头键导航æœç´¢ç»“果列表。"
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr "å·²å¯ç”¨%{link_start}精确代ç æœç´¢ï¼ˆç”± Zoekt æ供)%{link_end}"
+
msgid "GlobalSearch|Aggregations load error."
msgstr "èšåˆåŠ è½½é”™è¯¯ã€‚"
@@ -21441,6 +21655,9 @@ msgstr "关闭"
msgid "GlobalSearch|Fetching aggregations error."
msgstr "获å–èšåˆé”™è¯¯ã€‚"
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "群组"
@@ -21510,9 +21727,6 @@ msgstr "æœç´¢"
msgid "GlobalSearch|Search GitLab"
msgstr "æœç´¢ GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr "æœç´¢ GitLab %{kbdOpen}/%{kbdClose}"
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "æœç´¢é¡¹ç›®ã€è®®é¢˜ç­‰ã€‚"
@@ -21543,6 +21757,9 @@ msgstr "获å–æœç´¢è‡ªåŠ¨å®Œæˆå»ºè®®æ—¶å‡ºé”™ã€‚"
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr "获å–“语法选项â€æ–‡æ¡£æ—¶å‡ºé”™ã€‚"
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr "输入 %{kbdOpen}/%{kbdClose} 进行æœç´¢"
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "输入并按回车键æ交æœç´¢ã€‚"
@@ -21565,13 +21782,13 @@ msgid "GlobalSearch|in %{scope}"
msgstr "在%{scope}中"
msgid "GlobalShortcuts|Copied reference to clipboard."
-msgstr ""
+msgstr "已将å‚考å¤åˆ¶åˆ°å‰ªè´´æ¿ä¸­ã€‚"
msgid "GlobalShortcuts|Copied source branch name to clipboard."
msgstr "å·²å¤åˆ¶æºåˆ†æ”¯å称到剪贴æ¿ã€‚"
msgid "GlobalShortcuts|Unable to copy the reference at this time."
-msgstr ""
+msgstr "无法å¤åˆ¶å‚考。"
msgid "GlobalShortcuts|Unable to copy the source branch name at this time."
msgstr "无法å¤åˆ¶æºåˆ†æ”¯å称。"
@@ -21783,6 +22000,12 @@ msgstr "撤销授æƒ"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "撤销授予 GitLab 的授æƒï¼Œä¸ä¼šä½¿æœåŠ¡å¸æˆ·å¤±æ•ˆã€‚"
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr "仅在å—ä¿æŠ¤çš„分支和标签上设置å˜é‡"
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr "ä»…é™å—ä¿æŠ¤çš„分支和标签"
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr "将您的密钥文件拖动到此处,或%{linkStart}点击上传%{linkEnd}"
@@ -21798,8 +22021,8 @@ msgstr "Google Play"
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr "留空则使用您当å‰çš„æœåŠ¡å¸æˆ·å¯†é’¥ã€‚"
-msgid "GooglePlay|Service account key (.json)"
-msgstr "æœåŠ¡å¸æˆ·å¯†é’¥ï¼ˆ.json)"
+msgid "GooglePlay|Service account key (.JSON)"
+msgstr "æœåŠ¡è´¦æˆ·å¯†é’¥ (.JSON)"
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
msgstr "上传新的æœåŠ¡å¸æˆ·å¯†é’¥ï¼ˆæ›¿æ¢ %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr "群组头åƒ"
msgid "Group by"
msgstr "分组方å¼"
+msgid "Group by:"
+msgstr "分组方å¼ï¼š"
+
msgid "Group description (optional)"
msgstr "群组æ述(å¯é€‰ï¼‰"
@@ -21975,9 +22201,6 @@ msgstr "群组å称(您的组织)"
msgid "Group navigation"
msgstr "群组导航"
-msgid "Group overview"
-msgstr "群组概览"
-
msgid "Group overview content"
msgstr "群组概述内容"
@@ -22309,7 +22532,7 @@ msgid "GroupSelect|Select a group"
msgstr "选择一个群组"
msgid "GroupSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave empty for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{project_sharing_docs_link_start}project sharing%{link_end} and %{group_sharing_docs_link_start}group sharing%{link_end}."
-msgstr ""
+msgstr "当实例达到用户上é™åŽï¼Œä»»ä½•æ–°å¢žçš„用户或请求访问的用户都需è¦ç”±ç®¡ç†å‘˜æ‰¹å‡†ã€‚è‹¥è¦æ— é™åˆ¶ç”¨æˆ·ä¸Šé™ï¼Œè¯·ç•™ç©ºè¯¥å€¼ã€‚ 如果您将用户上é™æ”¹ä¸ºæ— é™åˆ¶ï¼Œæ‚¨å¿…é¡»é‡æ–°å¯ç”¨%{project_sharing_docs_link_start}项目分享%{link_end}å’Œ%{group_sharing_docs_link_start}群组分享%{link_end}。"
msgid "GroupSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave empty for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{project_sharing_docs_link_start}project sharing%{link_end} and %{group_sharing_docs_link_start}group sharing%{link_end}. Increasing the user cap does not automatically approve pending users."
msgstr "当执行个体达到用户上é™åŽï¼Œä»»ä½•æ–°å¢žçš„用户或请求访问的用户都需è¦ç”±ç®¡ç†å‘˜è¿›è¡Œå®¡æ ¸æ‰èƒ½æ‰¹å‡†ã€‚ è‹¥è¦æ— é™åˆ¶ç”¨æˆ·ä¸Šé™ï¼Œè¯·ç•™ç©ºè¯¥æ ä½ã€‚ 如果您将用户上é™æ”¹ä¸ºæ— é™åˆ¶ï¼Œæ‚¨å¿…é¡»é‡æ–°å¯ç”¨é¡¹ç›®åˆ†äº«å’Œç¾¤ç»„分享。 详细资讯请å‚考 %{project_sharing_docs_link_start}项目分享%{link_end} å’Œ %{group_sharing_docs_link_start}群组分享%{link_end}。增加用户上é™ä¸ä¼šè‡ªåŠ¨æ‰¹å‡†å¾…定的用户。"
@@ -22353,8 +22576,8 @@ msgstr "选择此群组中项目的åˆå¹¶è¯·æ±‚检查。此设置会覆盖此群
msgid "GroupSettings|Compliance frameworks"
msgstr "åˆè§„框架"
-msgid "GroupSettings|Configure analytics features for this group"
-msgstr "é…置此群组的分æžåŠŸèƒ½"
+msgid "GroupSettings|Configure analytics features for this group."
+msgstr "为此群组é…置分æžåŠŸèƒ½ã€‚"
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
msgstr "é…ç½®åˆè§„框架以æ供给此群组中的项目。%{linkStart}什么是åˆè§„框架?%{linkEnd}"
@@ -22542,8 +22765,8 @@ msgstr "此功能需è¦æµè§ˆå™¨æœ¬åœ°å­˜å‚¨æ”¯æŒ"
msgid "GroupsDropdown|Toggle edit mode"
msgstr "切æ¢ç¼–辑模å¼"
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "群组是几个项目的集åˆã€‚"
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr "群组是多个项目的集åˆ"
msgid "GroupsEmptyState|Create new project"
msgstr "创建新项目"
@@ -22554,8 +22777,8 @@ msgstr "创建新的å­ç»„"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "群组是管ç†å¤šä¸ªé¡¹ç›®å’Œæˆå‘˜çš„最佳方å¼ã€‚"
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "如果您在一个群组下组织项目,它的工作方å¼å°±åƒä¸€ä¸ªæ–‡ä»¶å¤¹ã€‚"
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr "如果您将项目组织在一个群组下,它的工作方å¼å°±åƒä¸€ä¸ªæ–‡ä»¶å¤¹ã€‚您å¯ä»¥ç®¡ç†ç¾¤ç»„æˆå‘˜çš„æƒé™ä»¥åŠå¯¹ç¾¤ç»„中æ¯ä¸ªé¡¹ç›®çš„访问。"
msgid "GroupsEmptyState|No archived projects."
msgstr "没有归档的项目。"
@@ -22572,9 +22795,6 @@ msgstr "没有å­ç»„或项目。"
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "项目是您用æ¥å­˜å‚¨æ‚¨çš„代ç ã€è®¿é—®è®®é¢˜ã€wiki 和其它功能的地方。"
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "您å¯ä»¥ç®¡ç†ç¾¤ç»„æˆå‘˜çš„æƒé™å¹¶è®¿é—®ç¾¤ç»„中的æ¯ä¸ªé¡¹ç›®ã€‚"
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "您没有在该群组中创建å­ç»„或项目的必è¦æƒé™ã€‚请è”系该群组的所有者æ¥åˆ›å»ºæ–°çš„å­ç»„或项目。"
@@ -22591,7 +22811,7 @@ msgid "GroupsNew|Connect instance"
msgstr "连接实例"
msgid "GroupsNew|Create a token with %{code_start}api%{code_end} and %{code_start}read_repository%{code_end} scopes in the %{pat_link_start}user settings%{pat_link_end} of the source GitLab instance. For %{short_living_link_start}security reasons%{short_living_link_end}, set a short expiration date for the token. Keep in mind that large migrations take more time."
-msgstr ""
+msgstr "在æºæžç‹GitLab 实例的 %{pat_link_start}用户设置%{pat_link_end} 中创建一个具有 %{code_start}api%{code_end} å’Œ %{code_start}read_repository%{code_end} 作用域的令牌。出于 %{short_living_link_start}安全原因%{short_living_link_end},为令牌设置一个较短的到期日期。请注æ„,大型è¿ç§»éœ€è¦æ›´å¤šæ—¶é—´ã€‚"
msgid "GroupsNew|Create group"
msgstr "创建群组"
@@ -22994,6 +23214,9 @@ msgstr "帮助将 GitLab 翻译æˆæ‚¨çš„语言"
msgid "Help translate to your language"
msgstr "帮助我们翻译æˆæ‚¨çš„语言"
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr "有助于防止机器人暴力攻击。"
@@ -23256,9 +23479,6 @@ msgstr "我想存储我的代ç "
msgid "I want to use GitLab CI with my existing repository"
msgstr "我想在我的现有仓库上使用GitLab CI"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "我希望通过电å­é‚®ä»¶æŽ¥æ”¶GitLabçš„æ›´æ–°"
-
msgid "I'm signing up for GitLab because:"
msgstr "我注册GitLab是因为:"
@@ -23298,6 +23518,12 @@ msgstr "此选项被ç¦ç”¨ï¼Œå› ä¸ºæ‚¨ä¸å…许在此项目中创建åˆå¹¶è¯·æ±‚
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr "此选项被ç¦ç”¨ï¼Œå› ä¸ºæ‚¨æ²¡æœ‰å½“å‰åˆ†æ”¯çš„写入æƒé™ã€‚"
+msgid "IDs with errors: %{error_messages}."
+msgstr "有错误的 ID:%{error_messages}。"
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr "é‡è¦æ示:仅将此设置用于éžå¸¸ä¸¥æ ¼çš„审计目的。å¯ç”¨åŽï¼Œä»»ä½•äººéƒ½æ— æ³•åœ¨åˆå¹¶åŽä»Žä»»ä½•åˆå¹¶è¯·æ±‚中移除标记。此外,任何人都无法关闭此设置或删除此标记。"
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "ä¿¡æ¯ï¼šæ‚¨çš„SSH密钥已过期。请生æˆä¸€ä¸ªæ–°å¯†é’¥ã€‚"
@@ -23481,6 +23707,12 @@ msgstr "验è¯ä»˜æ¬¾æ–¹å¼"
msgid "IdentityVerification|Verify phone number"
msgstr "验è¯ç”µè¯å·ç "
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr "改为使用信用å¡éªŒè¯ï¼Ÿ"
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr "改为使用电è¯å·ç éªŒè¯ï¼Ÿ"
+
msgid "IdentityVerification|Verify your identity"
msgstr "验è¯æ‚¨çš„身份"
@@ -23889,8 +24121,8 @@ msgstr "获å–导入详细信æ¯æ—¶å‡ºé”™ã€‚"
msgid "Import|GitHub import details"
msgstr "GitHub 导入详情"
-msgid "Import|Maximum decompressed size (MiB)"
-msgstr "最大解压大å°ï¼ˆMiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
+msgstr "从导入归档的最大压缩文件大å°(MiB)"
msgid "Import|Maximum import remote file size (MB)"
msgstr "最大导入远端文件大å°ï¼ˆMB)"
@@ -23916,6 +24148,12 @@ msgstr "仓库无法导入。"
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr "在此 URL 上没有有效的 Git 仓库。如果您的 HTTP 仓库ä¸èƒ½å…¬å¼€è®¿é—®ï¼Œè¯·éªŒè¯æ‚¨çš„凭æ®ã€‚"
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr "解压归档文件的超时时间(秒)"
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr "解压归档文件超时。"
+
msgid "Improve customer support with Service Desk"
msgstr "通过æœåŠ¡å°æ”¹å–„客户支æŒ"
@@ -23958,381 +24196,72 @@ msgstr "正在使用"
msgid "InProductMarketing|%{organization_name} logo"
msgstr "%{organization_name} 标志"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr "%{strong_start}高级应用程åºå®‰å…¨%{strong_end} — 包括 SASTã€DAST 扫æã€FUZZ 测试ã€ä¾èµ–性扫æã€è®¸å¯è¯åˆè§„性ã€ç§˜å¯†æ£€æµ‹"
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr "%{strong_start}å…¬å¸èŒƒå›´å†…的组åˆç®¡ç†%{strong_end} — 包括多级å²è¯—ã€èŒƒå›´æ ‡è®°"
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr "%{strong_start}高管级洞察%{strong_end} — 包括生产力报告ã€ä»»åŠ¡ç±»åž‹ã€å®Œæˆå¤©æ•°ã€ä»·å€¼æµ"
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr "%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr "%{strong_start}多个批准角色%{strong_end} — 包括代ç æ‰€æœ‰è€…和所需的åˆå¹¶æ‰¹å‡†"
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr "*GitLab*,åè¯ï¼šé«˜æ•ˆå›¢é˜Ÿçš„åŒä¹‰è¯"
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...您å¯ä»¥èŽ·å¾—旗舰版的å…费试用"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr "深入了解 GitLab CI/CD çš„ 3 ç§æ–¹æ³•"
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr "实际上,GitLab 使团队能够工作更好"
-
msgid "InProductMarketing|Advanced security testing"
msgstr "高级安全测试"
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr "æœ€åŽ %{deploy_link} 一个 Python 应用程åºã€‚"
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "您的Runner准备好了å—?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr "直接在 GitLab 中自动进行安全扫æ"
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "æˆä¸ºDevOps英雄"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr "增强您的安全性"
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "用更少的时间编写更好的代ç "
-
msgid "InProductMarketing|Blog"
msgstr "åšå®¢"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr "为 iOS 构建?我们会为您æä¾›ä¿éšœã€‚"
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr "通过å¯ç”¨ä»£ç æ‰€æœ‰è€…和所需的åˆå¹¶æ‰¹å‡†ï¼Œåˆé€‚的人将审查åˆé€‚çš„ MR。这是åŒèµ¢çš„:更干净的代ç å’Œæ›´æœ‰æ•ˆçš„审查过程。"
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr "代ç æ‰€æœ‰è€…和所需的åˆå¹¶æ‰¹å‡†æ˜¯ GitLab 付费版的一部分。您å¯ä»¥å¼€å§‹å…费试用 GitLab 旗舰版 30 天,并在 5 分钟内å¯ç”¨è¿™äº›åŠŸèƒ½ï¼Œæ— éœ€ä¿¡ç”¨å¡ã€‚"
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr "åªéœ€å•å‡»å‡ ä¸‹å³å¯åˆ›å»ºè‡ªå®šä¹‰ CI Runner"
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr "创建自定义Runner"
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "在5分钟内在 GitLab 中创建一个项目"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "创建您的第一个项目ï¼"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr "更快地交付更好的产å“"
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr "您知é“使用 GitLab 的团队效率更高å—?"
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr "深入并创建一个项目和仓库"
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr "您有一ä½é€‚åˆæ­¤ä»»åŠ¡çš„团队æˆå‘˜å—?"
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr "通过å…费的 GitLab 试用扩展您的 DevOps 之旅"
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "探索GitLab CI/CD"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "探索选项"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr "探索 GitLab CI/CD 的力é‡"
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr "感觉需è¦é€Ÿåº¦å—?"
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr "了解您的团队的实际情况"
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "è·Ÿéšæˆ‘们的步骤"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "30 天å…费试用"
msgid "InProductMarketing|Free guest users"
msgstr "å…费访客用户"
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr "用我们的%{quick_start_link}快速开始使用 CI/CD。从一个å¯ç”¨çš„è¿è¡Œå™¨å¼€å§‹ï¼Œç„¶åŽåˆ›å»ºä¸€ä¸ª CI .yml 文件——这真的很容易。"
-
-msgid "InProductMarketing|Get our import guides"
-msgstr "获å–导入指å—"
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr "设置为 iOS 构建"
-msgid "InProductMarketing|Get started today"
-msgstr "ç«‹å³å¼€å§‹"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr "ç«‹å³å¼€å§‹ä¸ºæœŸ 30 天的 GitLab 旗舰版 试用,无需信用å¡ã€‚"
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr "开始使用 GitLab CI/CD"
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr "了解GitLab CI/CD"
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr "在 GitLab 上建立您的团队"
-
-msgid "InProductMarketing|Git basics"
-msgstr "Git 基础知识"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr "GitHub ä¼ä¸šé¡¹ç›®åˆ° GitLab"
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr "GitLab æä¾›é™æ€åº”用程åºå®‰å…¨æµ‹è¯•ï¼ˆSAST)ã€åŠ¨æ€åº”用程åºå®‰å…¨æµ‹è¯•ï¼ˆDAST)ã€å®¹å™¨æ‰«æå’Œä¾èµ–扫æ以帮助您æ供安全的应用程åºä»¥åŠéµå®ˆè®¸å¯å议。"
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr "GitLab çš„ CI/CD 使软件开å‘更容易。ä¸ç›¸ä¿¡æˆ‘们?您å¯ä»¥é€šè¿‡ä»¥ä¸‹ä¸‰ç§æ–¹å¼è¿›è¡Œå¿«é€Ÿï¼ˆä¸”令人满æ„)的测试驱动:"
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr "专业版是为了使您ã€æ‚¨çš„团队和您的应用程åºæ›´æœ‰æ•ˆçŽ‡å’Œæ›´å®‰å…¨è€Œè®¾è®¡ï¼Œå¹¶ä¸”包括但ä¸é™äºŽï¼š"
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "给我们一分钟..."
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr "用 GitLab 走得更远"
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr "Goldman Sachs 从æ¯ä¸¤å‘¨ä¸€æ¬¡æž„建到æ¯å¤©æ•°åƒæ¬¡æž„建"
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr "è¦å¯¼å…¥ä¸åŒçš„实例å—?这是我们的 %{import_link}。"
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr "这是你需è¦çŸ¥é“çš„"
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr "é•œåƒå¦‚何(以åŠä¸ºä»€ä¹ˆï¼‰æœ‰æ„义"
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr "关闭功能请求ã€bugã€æŠ€æœ¯å€ºåŠ¡ã€å®‰å…¨æ€§ç­‰ç±»åž‹çš„议题/MR 需è¦å¤šé•¿æ—¶é—´ï¼Ÿ"
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr "我们的团队完æˆå„ç§ä»»åŠ¡éœ€è¦å¤šå°‘天?"
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr "如何更快地构建和测试"
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr "如果您ä¸æƒ³ç›´æŽ¥æŽ¥æ”¶æˆ‘们的è¥é”€ç”µå­é‚®ä»¶ï¼Œåˆ™ %{marketing_preference_link}."
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr "如果您ä¸å†å¸Œæœ›æ”¶åˆ°æˆ‘们的è¥é”€ç”µå­é‚®ä»¶ï¼Œ"
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr "从 GitHubã€Bitbucket 等导入您的项目和代ç "
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr "通过 30 天试用æ高应用安全性"
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr "æ高代ç è´¨é‡å¹¶ç®€åŒ–审查"
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr "æ高è¿è¥æ•ˆçŽ‡"
-msgid "InProductMarketing|Invite them to help out."
-msgstr "邀请他们æ供帮助。"
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr "æ— é™åˆ¶é‚€è¯·åŒäº‹"
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "邀请您的åŒäº‹å¹¶å¼€å§‹æ›´å¿«åœ°å‘é€ä»£ç ã€‚"
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "ä¸åˆ°ä¸€åˆ†é’Ÿé‚€è¯·æ‚¨çš„åŒäº‹åŠ å…¥"
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "ç«‹å³é‚€è¯·æ‚¨çš„åŒäº‹"
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "60 秒内邀请您的团队"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "ç«‹å³é‚€è¯·æ‚¨çš„团队"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr "ç«‹å³é‚€è¯·æ‚¨çš„团队一起构建更好的代ç ï¼ˆå’Œæµç¨‹ï¼‰"
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr "一切尽在统计中"
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr "为了利用 GitLab çš„ CI/CD,也å¯ä»¥ç®€å•åœ°è®¾ç½®ä¸º %{external_repo_link}"
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr "在 20 分钟或更短的时间内å¯åŠ¨ GitLab CI/CD"
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr "了解如何为 iOS 构建"
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr "进行转æ¢ï¼Ÿå°†é¡¹ç›®å¯¼å…¥ GitLab 比您想象的è¦å®¹æ˜“,移动 %{github_link},或者导入一些东西 %{bitbucket_link}。"
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr "掌æ¡å¯¼å…¥çš„艺术ï¼"
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr "继续轻æ¾åˆ›å»º Pages 网站 %{ci_template_link}"
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr "多个所有者,混乱的工作æµï¼Ÿæˆ‘们已为您æä¾›ä¿éšœ"
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr "需è¦æ›¿ä»£å¯¼å…¥çš„方法å—?"
-
msgid "InProductMarketing|No credit card required."
msgstr "ä¸éœ€è¦ä¿¡ç”¨å¡ã€‚"
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr "我们的工具将所有东西整åˆåœ¨ä¸€èµ·"
-
msgid "InProductMarketing|Portfolio management"
msgstr "组åˆç®¡ç†"
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr "快速开å‘,简化"
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr "é™ä½Žå®‰å…¨ä¸Žåˆè§„风险"
msgid "InProductMarketing|Security risk mitigation"
msgstr "é™ä½Žå®‰å…¨é£Žé™©"
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr "集æˆåˆ°æ‚¨çš„å¼€å‘生命周期中的安全性"
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr "有时您还没有准备好完全过渡到新工具。如果您还没有准备好完全æ交, %{mirroring_link} 为您æ供了一ç§ä¸Žå½“å‰å·¥å…·å¹¶è¡Œè¯•ç”¨ GitLab 的安全方法。"
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr "在 GitLab 中å¯åŠ¨è‡ªåŠ¨ç¼©æ”¾Runner"
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "ç«‹å³åœ¨ä¸åˆ°ä¸€åˆ†é’Ÿçš„时间内开始 GitLab Ultimate 试用,无需信用å¡ã€‚"
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr "开始试用"
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "开始å…费试用旗舰版 - 无需信用å¡"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "开始试用"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "从%{performance_link}开始"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "从导入您的项目开始"
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "开始å…费试用 GitLab Ultimate"
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "现在就开始试用ï¼"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr "å³åˆ»å¼€å§‹è¯•ç”¨ï¼Œä½“验å•ä¸ªåº”用的æˆåŠŸï¼Œå¹¶å…è´¹å‘现GitLab Ultimate的所有功能。"
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr "åœæ­¢ç–‘惑,使用GitLab回答以下问题:"
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr "简化代ç å®¡æ ¸ï¼Œä¸€ç›®äº†ç„¶åœ°çŸ¥é“è°ä¸å¯ç”¨ï¼Œåœ¨è¯„论或电å­é‚®ä»¶ä¸­æ²Ÿé€šï¼Œå¹¶ä¸ŽSlackæ•´åˆï¼Œè®©æ¯ä¸ªäººéƒ½åœ¨åŒä¸€é¡µé¢ä¸Šã€‚"
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr "使用GitLab的第一步"
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr "让您的æºä»£ç ç®¡ç†æ›´ä¸Šä¸€å±‚楼"
-
msgid "InProductMarketing|Team members collaborating"
msgstr "团队æˆå‘˜è¿›è¡Œå作"
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr "在 GitLab 中组队以æ高效率"
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr "团队åˆä½œæˆå°±æ¢¦æƒ³"
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr "测试,创建,部署"
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr "这就是开始使用 GitLab 所需的全部内容,但是如果您ä¸ç†Ÿæ‚‰ Git,请查看我们的 %{basics_link} 以获å–有用的入门æ示和技巧。"
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr "这是 %{track} 系列中的第 %{current_series} å°ç”µå­é‚®ä»¶ï¼Œå…± %{total_series} å°"
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr "这是 %{track} 系列中的第 %{current_series} å°ç”µå­é‚®ä»¶ï¼Œå…± %{total_series} å°ã€‚è¦ç¦ç”¨æœ¬åœ° GitLab 实例å‘é€çš„通知电å­é‚®ä»¶ï¼Œè¯·è”系您的管ç†å‘˜æˆ– %{unsubscribe_link}。"
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr "Ticketmaster å°† CI 构建时间缩短了 15 å€"
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr "厌倦了与ä¸åŒçš„工具链ã€ä¿¡æ¯å­¤å²›å’Œä½Žæ•ˆæµç¨‹çš„æ斗? GitLab çš„ CI/CD 建立在 DevOps å¹³å°ä¸Šï¼Œå…·æœ‰æºä»£ç ç®¡ç†ã€è§„划ã€ç›‘控等功能。å‚阅 %{ci_link}。"
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr "选择退出Onboarding邮件,%{unsubscribe_link}。"
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr "è¦äº†è§£å¹¶å……分利用GitLab,请从头开始,从%{project_link}开始。在GitLab中,仓库是项目的一部分,所以在您创建了您的项目之åŽï¼Œæ‚¨å¯ä»¥ç»§ç»­æ‰§è¡Œ%{repo_link}。"
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "å…费试用 GitLab 旗舰版"
-
-msgid "InProductMarketing|Try it out"
-msgstr "å°è¯•ä¸€ä¸‹"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "å°è¯•ä¸€ä¸‹"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr "å°†åŒäº‹å˜æˆåˆä½œè€…"
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr "了解仓库镜åƒ"
-
-msgid "InProductMarketing|Understand your project options"
-msgstr "了解您的项目选项"
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr "使用 GitLab CI/CD"
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr "使用我们的AWS cloudformation模æ¿ï¼Œåªéœ€ç‚¹å‡»å‡ ä¸‹ï¼Œå³å¯è®©æ‚¨çš„ runner 加速ï¼"
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr "å…¨çƒè¶…过10万个组织使用:"
@@ -24348,66 +24277,15 @@ msgstr "想在您的æœåŠ¡å™¨ä¸Šæ‰˜ç®¡ GitLab?"
msgid "InProductMarketing|Watch iOS building in action."
msgstr "观看 iOS 构建实践。"
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr "我们知é“一些关于效率的事情,我们想分享给大家。注册GitLab Ultimateçš„å…费试用版,您的团队将从第一天开始使用它。"
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr "从产å“到开å‘,å†åˆ°å®¡æŸ¥å’Œç”Ÿäº§ï¼Œæˆ‘们的价值æµæ—¶é—´è¡¨æ˜¯ä»€ä¹ˆæ ·çš„?"
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr "当您的团队在 GitLab 上时,åªéœ€å•å‡»ä¸€ä¸‹å³å¯èŽ·å¾—这些答案。"
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr "在 GitLab 中工作 = 更高效"
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr "您的团队å¯ä»¥æ›´å…·æ•ˆçŽ‡"
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "综åˆæŒ‡å—"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "连接外部仓库"
-
-msgid "InProductMarketing|create a project"
-msgstr "创建一个项目"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "从 Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "转到about.gitlab.cn"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "如何轻æ¾åœ°å¼€å§‹"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "快速开始指å—"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "仓库镜åƒ"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "设置 repo"
-
-msgid "InProductMarketing|test and deploy"
-msgstr "测试和部署"
-
-msgid "InProductMarketing|testing browser performance"
-msgstr "测试æµè§ˆå™¨æ€§èƒ½ã€‚"
-
msgid "InProductMarketing|unsubscribe"
msgstr "å–消订阅"
-msgid "InProductMarketing|update your preferences"
-msgstr "更新您的å好"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr "使用 CI/CD 模æ¿"
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "您å¯ä»¥éšæ—¶%{unsubscribe_link}。"
@@ -24837,6 +24715,14 @@ msgstr "内è”"
msgid "Inline math"
msgstr "内è”æ•°å­¦"
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] "检测到 %d 个代ç è´¨é‡ç»“æžœ"
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] "检测到 %d 个 SAST 结果"
+
msgid "Input host keys manually"
msgstr "手动输入主机密钥"
@@ -25192,6 +25078,9 @@ msgstr "当您在禅é“中创建项目的议题时,禅é“议题会显示在此
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr "ä¸èƒ½è¶…过 %{recipients_limit}"
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr "è¦å‘é€é€šçŸ¥çš„分支"
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr "IntelliJ IDEA (HTTPS)"
@@ -25228,15 +25117,9 @@ msgstr "ä¸èƒ½åœç”¨å†…部用户"
msgid "Interval"
msgstr "é—´éš”"
-msgid "Interval Pattern"
-msgstr "循环周期"
-
msgid "Introducing Your DevOps Reports"
msgstr "介ç»æ‚¨çš„ DevOps 报告"
-msgid "Introducing the Code Suggestions add-on"
-msgstr "引入代ç å»ºè®®æ’件"
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr "无效的 “schemaVersion†“%{schema_version}â€"
@@ -25318,9 +25201,6 @@ msgstr "无效标签"
msgid "Invalid two-factor code."
msgstr "无效的åŒé‡è®¤è¯ç ã€‚"
-msgid "Invalid yaml"
-msgstr "无效的yaml"
-
msgid "Invalidated"
msgstr "无效"
@@ -25484,7 +25364,7 @@ msgid "InviteMembersModal|Something went wrong"
msgstr "出现错误"
msgid "InviteMembersModal|The following %{errorMembersLength} out of %{totalMembersCount} members could not be added"
-msgstr ""
+msgstr "无法添加 %{totalMembersCount} 个æˆå‘˜ä¸­çš„以下 %{errorMembersLength} 个"
msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
@@ -25652,18 +25532,12 @@ msgstr "已解决所有主题"
msgid "IssuableEvents|unassigned"
msgstr "未分é…"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type} 创建于 %{created_at} "
-
msgid "IssuableStatus|Closed"
msgstr "已关闭"
msgid "IssuableStatus|Closed (%{link})"
msgstr "关闭(%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "创建于 %{created_at}"
-
msgid "IssuableStatus|duplicated"
msgstr "é‡å¤"
@@ -25913,29 +25787,48 @@ msgstr "未分é…å²è¯—的议题"
msgid "Issues, merge requests, pushes, and comments."
msgstr "议题,åˆå¹¶è¯·æ±‚,推é€åŠè¯„论。"
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "在您为项目创建议题åŽï¼Œæˆ‘们就会开始跟踪并显示它们的指标"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "月å‡ï¼š"
+msgid "IssuesAnalytics|Closed"
+msgstr "已关闭:"
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr "为您群组中的项目创建议题以跟踪和查看项目指标。"
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr "加载图表失败。请é‡è¯•ã€‚"
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr "开始议题分æž"
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr "打开的议题 vs 关闭的议题"
+
msgid "IssuesAnalytics|Issues created"
msgstr "议题已创建"
msgid "IssuesAnalytics|Issues created per month"
msgstr "æ¯æœˆåˆ›å»ºçš„议题"
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "最近12个月"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr "过去 12 个月 (%{chartDateRange})"
+
+msgid "IssuesAnalytics|Opened"
+msgstr "已打开"
+
+msgid "IssuesAnalytics|Overview"
+msgstr "概览"
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "对ä¸èµ·ï¼Œæ— ç¬¦åˆç­›é€‰å™¨çš„结果"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "群组中的项目无任何议题"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "è¦æ‰©å¤§æœç´¢èŒƒå›´ï¼Œè¯·æ›´æ”¹æˆ–删除上é¢çš„筛选æ¡ä»¶"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr "è¦æ‰©å¤§æœç´¢èŒƒå›´ï¼Œè¯·æ›´æ”¹æˆ–删除上é¢è¿‡æ»¤æ ä¸­çš„过滤器。"
msgid "IssuesAnalytics|Total:"
msgstr "总计:"
@@ -25982,6 +25875,9 @@ msgstr "斜体(%{modifierKey}I)"
msgid "Italic text"
msgstr "斜体文字"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr "无法添加 ID 为 %{id} 的项目。您无æƒæ‰§è¡Œæ­¤æ“作。"
+
msgid "Iteration"
msgstr "迭代"
@@ -26318,6 +26214,9 @@ msgstr "未找到群组。"
msgid "JiraConnect|No linked groups"
msgstr "没有关è”的群组"
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr "没有看到您的群组?此处仅显示您有æƒè®¿é—®çš„群组。"
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr "看ä¸åˆ°æ‚¨çš„群组?åªæœ‰æ‚¨åœ¨å…¶ä¸­å…·æœ‰ç»´æŠ¤è€…角色的群组,æ‰ä¼šæ˜¾ç¤ºåœ¨è¿™é‡Œã€‚"
@@ -26816,6 +26715,9 @@ msgstr "时长"
msgid "Job|Erase job log and artifacts"
msgstr "擦除作业日志和产物"
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr "失败"
@@ -26867,6 +26769,9 @@ msgstr "é‡è¯•"
msgid "Job|Run again"
msgstr "å†æ¬¡è¿è¡Œ"
+msgid "Job|Runner type"
+msgstr "Runner 类型"
+
msgid "Job|Running"
msgstr "正在è¿è¡Œ"
@@ -26963,9 +26868,6 @@ msgstr "加入项目"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr "加入您的 GitLab 团队,并为现有项目åšå‡ºè´¡çŒ®"
-msgid "Joined %{time_ago}"
-msgstr "加入于%{time_ago}"
-
msgid "Joined %{user_created_time}"
msgstr "加入于%{user_created_time}"
@@ -27226,9 +27128,6 @@ msgstr "最近活动"
msgid "Last Name"
msgstr "姓"
-msgid "Last Pipeline"
-msgstr "最新æµæ°´çº¿"
-
msgid "Last Seen"
msgstr "最åŽå‡ºçŽ°"
@@ -27325,6 +27224,9 @@ msgstr "您推é€äº†"
msgid "LastPushEvent|at"
msgstr "于"
+msgid "Latest AI-generated summary"
+msgstr "AI 生æˆçš„最新摘è¦"
+
msgid "Latest changes"
msgstr "最新更改"
@@ -27386,7 +27288,7 @@ msgid "Learn more about Needs relationships"
msgstr "了解更多关于Needs关系的信æ¯"
msgid "Learn more about Service Desk"
-msgstr ""
+msgstr "了解æœåŠ¡å°çš„更多内容"
msgid "Learn more about Web Terminal"
msgstr "了解更多关于 Web 终端"
@@ -28019,6 +27921,9 @@ msgstr "é”定 %{issuableType}"
msgid "Lock File?"
msgstr "é”定文件?"
+msgid "Lock label after a merge request is merged"
+msgstr "åˆå¹¶è¯·æ±‚åˆå¹¶åŽé”定标记"
+
msgid "Lock memberships to LDAP synchronization"
msgstr "é”定æˆå‘˜èº«ä»½åˆ°LDAPåŒæ­¥"
@@ -28028,6 +27933,9 @@ msgstr "é”定æˆå‘˜èº«ä»½åˆ° SAML 群组关è”åŒæ­¥"
msgid "Lock not found"
msgstr "未找到é”"
+msgid "Lock on merge"
+msgstr "åˆå¹¶æ—¶é”定"
+
msgid "Lock status"
msgstr "é”定状æ€"
@@ -28326,7 +28234,7 @@ msgid "Markdown enabled."
msgstr "Markdownå·²å¯ç”¨ã€‚"
msgid "Markdown is supported"
-msgstr ""
+msgstr "æ”¯æŒ Markdown"
msgid "Markdown supported."
msgstr "æ”¯æŒ Markdown。"
@@ -28433,6 +28341,12 @@ msgstr "Mattermost URL:"
msgid "Mattermost notifications"
msgstr "Mattermost 通知"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr "使用以下选项在您的 Mattermost 团队%{link_start}添加 Slash 命令 %{icon}%{link_end} 。"
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr "在您的 Mattermost 安装上%{link_start}å¯ç”¨è‡ªå®šä¹‰ Slash 命令 %{icon}%{link_end}。"
+
msgid "MattermostService|Add to Mattermost"
msgstr "添加到Mattermost"
@@ -28448,6 +28362,9 @@ msgstr "填入最适åˆä½ çš„团队的文字。"
msgid "MattermostService|Install"
msgstr "安装"
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr "将令牌粘贴到 %{strong_start}令牌%{strong_end} 字段中。"
+
msgid "MattermostService|Request URL"
msgstr "请求网å€"
@@ -28460,6 +28377,9 @@ msgstr "å“应图标"
msgid "MattermostService|Response username"
msgstr "å“应用户å"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr "选择 %{strong_start}有效的%{strong_end} å¤é€‰æ¡†ï¼Œç„¶åŽé€‰æ‹© %{strong_start}ä¿å­˜æ›´æ”¹%{strong_end} 以开始在 Mattermost 中使用æžç‹GitLabï¼"
+
msgid "MattermostService|Suggestions:"
msgstr "建议:"
@@ -28766,6 +28686,102 @@ msgstr "%{member_name}邀请您使用GitLab"
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr "邀请加入%{project_or_group}%{project_or_group_name}"
+msgid "MemberRoles|Actions"
+msgstr "动作"
+
+msgid "MemberRoles|Add new role"
+msgstr "添加新角色"
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr "管ç†æ¼æ´ž"
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr "å…许管ç†å‘˜è®¿é—®æ¼æ´žæŠ¥å‘Šã€‚必须选择“读å–æ¼æ´žâ€æ‰èƒ½ç”Ÿæ•ˆã€‚"
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr "å…许åªè¯»è®¿é—®æºä»£ç ã€‚"
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr "å…许åªè¯»è®¿é—®æ¼æ´žæŠ¥å‘Šã€‚"
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr "您确定è¦åˆ é™¤æ­¤è§’色å—?"
+
+msgid "MemberRoles|Base role"
+msgstr "基本角色"
+
+msgid "MemberRoles|Base role to use as template"
+msgstr "用作模æ¿çš„基本角色"
+
+msgid "MemberRoles|Create new role"
+msgstr "创建新角色"
+
+msgid "MemberRoles|Custom roles"
+msgstr "自定义角色"
+
+msgid "MemberRoles|Delete role"
+msgstr "删除角色"
+
+msgid "MemberRoles|Description"
+msgstr "æè¿°"
+
+msgid "MemberRoles|Enter a short name."
+msgstr "请输入一个简短的å称。"
+
+msgid "MemberRoles|Failed to create role."
+msgstr "创建角色失败。"
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr "删除角色失败。"
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr "获å–角色失败。"
+
+msgid "MemberRoles|ID"
+msgstr "ID"
+
+msgid "MemberRoles|Incident manager"
+msgstr "事件管ç†å™¨"
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr "请确ä¿è¯¥ç¾¤ç»„有旗舰版的许å¯è¯ã€‚"
+
+msgid "MemberRoles|Name"
+msgstr "å称"
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr "此群组没有自定义角色"
+
+msgid "MemberRoles|Permissions"
+msgstr "æƒé™"
+
+msgid "MemberRoles|Read code"
+msgstr "读å–代ç "
+
+msgid "MemberRoles|Read vulnerability"
+msgstr "读å–æ¼æ´ž"
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr "移除自定义角色也会从群组中移除具有此自定义角色的所有æˆå‘˜ã€‚如果您决定删除一个自定义角色,您必须将这些用户é‡æ–°æ·»åŠ åˆ°ç¾¤ç»„中。"
+
+msgid "MemberRoles|Role name"
+msgstr "角色å称"
+
+msgid "MemberRoles|Role successfully created."
+msgstr "角色创建æˆåŠŸã€‚"
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr "角色删除æˆåŠŸã€‚"
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr "选择è¦æ·»åŠ æƒé™çš„标准角色。"
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr "è¦æ·»åŠ æ–°è§’色,请选择一个群组,然åŽæ·»åŠ æ–°è§’色。"
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr "å¿…é¡»å¯ç”¨ %{requirement} æ‰èƒ½å¯ç”¨ %{permission}。"
@@ -29021,6 +29037,9 @@ msgstr "åˆå¹¶æ交消æ¯"
msgid "Merge conflicts"
msgstr "åˆå¹¶å†²çª"
+msgid "Merge date & time could not be determined"
+msgstr "åˆå¹¶æ—¥æœŸå’Œæ—¶é—´æ— æ³•ç¡®å®š"
+
msgid "Merge details"
msgstr "åˆå¹¶è¯¦æƒ…"
@@ -29453,9 +29472,6 @@ msgstr "指标与分æž"
msgid "Metrics:"
msgstr "指标:"
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr "ä¸èƒ½åœ¨ starting_at 时间之å‰"
-
msgid "Metrics|Create metric"
msgstr "创建指标"
@@ -29552,6 +29568,9 @@ msgstr "Microsoft Azure 集æˆè®¾ç½®æ— æ³•ä¿å­˜ã€‚%{errors}"
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr "Microsoft Azure 集æˆè®¾ç½®å·²æˆåŠŸæ›´æ–°ã€‚"
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr "当 SAML å“应包å«è¶…é¢å£°æ˜Žæ—¶ï¼Œä»Ž Microsoft Azure åŒæ­¥ç¾¤ç»„æˆå‘˜èº«ä»½ã€‚"
+
msgid "Microsoft|Tenant ID"
msgstr "租户 ID"
@@ -30226,7 +30245,7 @@ msgid "Namespace:"
msgstr "命å空间:"
msgid "NamespaceLimits|%{date} %{linkStart}%{username}%{linkEnd} changed the limit to %{limit}"
-msgstr ""
+msgstr "%{date} %{linkStart}%{username}%{linkEnd} å°†é™åˆ¶æ›´æ”¹ä¸º %{limit}"
msgid "NamespaceLimits|Add minimum free storage amount (in MiB) that will be used to enforce storage usage for namespaces on free plan. To remove the limit, set the value to 0 and click \"Update limit\" button."
msgstr "添加最å°å…费存储é‡ï¼ˆä»¥ MiB 为å•ä½ï¼‰ï¼Œç”¨äºŽå¼ºåˆ¶å…费计划中命å空间的存储使用。è¦åˆ é™¤é™åˆ¶ï¼Œè¯·å°†å€¼è®¾ç½®ä¸º 0,然åŽå•å‡»â€œæ›´æ–°é™åˆ¶â€æŒ‰é’®ã€‚"
@@ -30430,12 +30449,12 @@ msgstr "哪些æ“作å—到é™åˆ¶ï¼Ÿ"
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr "您已使用 %{name_with_link} 储存空间的 %{used_storage_percentage}(总计 %{limit},已使用 %{current_size})"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
+msgstr "您已使用 %{namespace_name} 的存储é…é¢çš„ %{used_storage_percentage}"
+
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr "您已使用 %{name} 储存空间的 %{used_storage_percentage}(总计 %{limit},已使用%{current_size})"
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
-msgstr "您已使用 %{namespace_name} 的存储é…é¢çš„ %{used_storage_percentage}%%"
-
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
msgstr "需è¦å®¡æ ¸çš„用户必须由群组所有者审核。了解更多关于%{user_caps_link_start}用户上é™%{link_end}å’Œ%{users_pending_approval_link_start}用户等待批准%{link_end}çš„ä¿¡æ¯ã€‚"
@@ -30511,6 +30530,9 @@ msgstr "分æž"
msgid "Navigation|Build"
msgstr "构建"
+msgid "Navigation|CI/CD settings"
+msgstr "CI/CD 设置"
+
msgid "Navigation|Code"
msgstr "代ç "
@@ -30541,15 +30563,18 @@ msgstr "您ç»å¸¸è®¿é—®çš„群组将出现在这里。"
msgid "Navigation|Leave admin mode"
msgstr "离开管ç†å‘˜æ¨¡å¼"
-msgid "Navigation|Main navigation"
-msgstr "主导航"
-
msgid "Navigation|Manage"
msgstr "管ç†"
+msgid "Navigation|Merge requests settings"
+msgstr "åˆå¹¶è¯·æ±‚设置"
+
msgid "Navigation|Monitor"
msgstr "监控"
+msgid "Navigation|Monitor settings"
+msgstr "监控设置"
+
msgid "Navigation|No group matches found"
msgstr "未找到匹é…的群组"
@@ -30568,12 +30593,18 @@ msgstr "已钉选"
msgid "Navigation|Plan"
msgstr "计划"
+msgid "Navigation|Primary"
+msgstr "主导航"
+
msgid "Navigation|Projects"
msgstr "项目"
msgid "Navigation|Projects you visit often will appear here."
msgstr "您ç»å¸¸è®¿é—®çš„项目将出现在这里。"
+msgid "Navigation|Repository settings"
+msgstr "仓库设置"
+
msgid "Navigation|Retrieving search results"
msgstr "获å–æœç´¢ç»“æžœ"
@@ -30592,6 +30623,12 @@ msgstr "获å–æœç´¢ç»“果时出错。"
msgid "Navigation|Unpin item"
msgstr "å–消钉选事项"
+msgid "Navigation|View all my groups"
+msgstr "查看我的所有群组"
+
+msgid "Navigation|View all my projects"
+msgstr "查看我的所有项目"
+
msgid "Navigation|View all your groups"
msgstr "查看您的所有群组"
@@ -30815,9 +30852,6 @@ msgstr "议题#%{issue_iid}的新回å¤ï¼š"
msgid "New runners registration token has been generated!"
msgstr "已生æˆæ–°çš„Runner注册令牌ï¼"
-msgid "New schedule"
-msgstr "新建计划"
-
msgid "New snippet"
msgstr "新建代ç ç‰‡æ®µ"
@@ -31025,6 +31059,9 @@ msgstr "无迭代"
msgid "No label"
msgstr "无标记"
+msgid "No labels found"
+msgstr "未找到标记"
+
msgid "No labels with such name or description"
msgstr "没有具有此类å称或æ述的标记"
@@ -31049,6 +31086,12 @@ msgstr "没有匹é…的结果"
msgid "No matching results for \"%{query}\""
msgstr "没有与“%{query}â€åŒ¹é…的结果"
+msgid "No matching work item found."
+msgstr "找ä¸åˆ°åŒ¹é…的工作项。"
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr "找ä¸åˆ°åŒ¹é…的工作项。请确ä¿æ‚¨æ·»åŠ çš„是有效 ID 并且您有æƒè®¿é—®è¯¥é¡¹ç›®ã€‚"
+
msgid "No members found"
msgstr "未找到æˆå‘˜"
@@ -31067,12 +31110,15 @@ msgstr "无里程碑"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr "仅能åŒæ—¶æ›´æ–°ä¸è¶…过 %{max_issues} 个议题"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr "åŒæ—¶ä¿®æ”¹çš„工作项ä¸å¾—超过 %{max_work_items}。"
+
+msgid "No options found"
+msgstr "未找到选项"
+
msgid "No other labels with such name or description"
msgstr "没有其他具有此类å称或æ述的标记"
-msgid "No panels matching properties %{opts}"
-msgstr "没有与属性匹é…çš„é¢æ¿%{opts}"
-
msgid "No parent group"
msgstr "父群组ä¸å­˜åœ¨"
@@ -31127,9 +31173,6 @@ msgstr "未找到结果。"
msgid "No runner executable"
msgstr "æ— runnerå¯æ‰§è¡Œæ–‡ä»¶"
-msgid "No schedules"
-msgstr "无计划"
-
msgid "No service accounts"
msgstr "没有æœåŠ¡å¸æˆ·"
@@ -31181,6 +31224,12 @@ msgstr "没有 webhook 事件"
msgid "No webhooks enabled. Select trigger events above."
msgstr "未å¯ç”¨ webhook。选择上é¢çš„触å‘事件。"
+msgid "No work item IDs provided."
+msgstr "未æ供工作项 ID。"
+
+msgid "No work item found."
+msgstr "未找到工作项"
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] "ä¸ç”¨æ‹…心,您现在ä»ç„¶å¯ä»¥ä½¿ç”¨æ‰€æœ‰ %{strong}%{plan_name}%{strong_close} 功能。您有 %{remaining_days} 天æ¥ç»­è®¢æ‚¨çš„订阅。"
@@ -32379,6 +32428,9 @@ msgstr "一个或多个个人访问令牌已过期。"
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr "您的一个或多个个人访问令牌将在 %{days_to_expire} 天或更短的时间内到期:"
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr "您的一个或多个资æºè®¿é—®ä»¤ç‰Œå°†åœ¨%{days_to_expire} 天或更短的时间内过期。"
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr "åªæœ‰å…·æœ‰%{permissions}æƒé™çš„%{workspaceType}æˆå‘˜ï¼Œå¯ä»¥æŸ¥çœ‹æˆ–收到关于这个%{issuableType}的通知。"
@@ -32406,9 +32458,6 @@ msgstr "åªæœ‰%{membersPageLinkStart}项目æˆå‘˜%{membersPageLinkEnd}å¯ä»¥è®¿é
msgid "Only active projects show up in the search and on the dashboard."
msgstr "仅活动的项目显示在æœç´¢å’Œä»ªè¡¨æ¿ä¸Šã€‚"
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr "仅在å¯ç”¨è¿œç¨‹å­˜å‚¨æ—¶æœ‰æ•ˆã€‚设置为 0 表示没有大å°é™åˆ¶ã€‚"
-
msgid "Only include features new to your current subscription tier."
msgstr "仅包括您当å‰è®¢é˜…级别的新功能。"
@@ -32571,24 +32620,60 @@ msgstr "æ“作"
msgid "Ordered list"
msgstr "有åºåˆ—表"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "组织"
-msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
msgstr ""
+msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
+msgstr "加载群组时å‘生错误。请刷新页é¢å¹¶é‡è¯•ã€‚"
+
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr "加载项目时出错。请刷新页é¢å†è¯•ä¸€æ¬¡ã€‚"
+msgid "Organization|Copy organization ID"
+msgstr "å¤åˆ¶ç»„织 ID"
+
+msgid "Organization|Frequently visited groups"
+msgstr "ç»å¸¸è®¿é—®çš„群组"
+
+msgid "Organization|Frequently visited projects"
+msgstr "ç»å¸¸è®¿é—®çš„项目"
+
+msgid "Organization|New organization"
+msgstr "新建组织"
+
+msgid "Organization|Org ID"
+msgstr "组织 ID"
+
msgid "Organization|Organization navigation"
msgstr "组织导航"
msgid "Organization|Organization overview"
msgstr "组织概览"
+msgid "Organization|Organizations"
+msgstr "组织|组织"
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr "公开 - 无需身份验è¯å³å¯è®¿é—®è¯¥ç»„织。"
+
msgid "Organization|Search or filter list"
msgstr "æœç´¢æˆ–过滤列表"
+msgid "Organization|View all"
+msgstr "查看全部"
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr "孤儿æˆå‘˜"
@@ -33301,6 +33386,9 @@ msgstr "Pages"
msgid "Pages Domain"
msgstr "Pages域å"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr "è¯ä¹¦å¯†é’¥å¤ªé•¿ã€‚(最大为 %d 字节)"
+
msgid "Pagination|First"
msgstr "首页"
@@ -33448,8 +33536,11 @@ msgstr "路径"
msgid "Path:"
msgstr "路径:"
-msgid "Paths to protect with rate limiting"
-msgstr "使用速率é™åˆ¶ä¿æŠ¤çš„路径"
+msgid "Paths with rate limiting for GET requests"
+msgstr "对 GET 请求进行速率é™åˆ¶çš„路径"
+
+msgid "Paths with rate limiting for POST requests"
+msgstr "对 POST 请求进行速率é™åˆ¶çš„路径"
msgid "Pause"
msgstr "æš‚åœ"
@@ -33725,7 +33816,7 @@ msgid "Pipeline subscriptions trigger a new pipeline on the default branch of th
msgstr "当订阅项目 %{default_branch_docs} 上的新标签æˆåŠŸå®Œæˆæµæ°´çº¿æ—¶ï¼Œæµæ°´çº¿è®¢é˜…会在此项目的默认分支上触å‘æ–°æµæ°´çº¿ã€‚"
msgid "Pipeline trigger tokens"
-msgstr ""
+msgstr "æµæ°´çº¿è§¦å‘令牌"
msgid "Pipeline triggers"
msgstr "æµæ°´çº¿è§¦å‘器"
@@ -33895,9 +33986,6 @@ msgstr "自定义(%{linkStart}了解详情%{linkEnd})"
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr "计划æµæ°´çº¿ä¼šå®šæœŸè‡ªåŠ¨å¯åŠ¨ï¼Œä¾‹å¦‚æ¯å¤©æˆ–æ¯å‘¨ã€‚æµæ°´çº¿ï¼š "
-msgid "PipelineSchedules|Activated"
-msgstr "是å¦å¯ç”¨"
-
msgid "PipelineSchedules|Active"
msgstr "å·²å¯ç”¨"
@@ -34012,12 +34100,6 @@ msgstr "è¿è¡Œæµæ°´çº¿è®¡åˆ’时出错。"
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr "获å–æµæ°´çº¿è®¡åˆ’的所有æƒæ—¶å‡ºé”™ã€‚"
-msgid "PipelineSchedules|Variables"
-msgstr "å˜é‡"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr "å–得所有æƒä»¥è¿›è¡Œç¼–辑"
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34468,6 +34550,9 @@ msgstr "无法获å–æµæ°´çº¿çŠ¶æ€ã€‚有关故障排除步骤,请å‚阅%{link
msgid "Pipeline|Created"
msgstr "已创建"
+msgid "Pipeline|Created by"
+msgstr "创建人"
+
msgid "Pipeline|Creating pipeline."
msgstr "正在创建æµæ°´çº¿ã€‚"
@@ -34520,7 +34605,7 @@ msgid "Pipeline|Raw text search is not currently supported. Please use the avail
msgstr "ç›®å‰ä¸æ”¯æŒåŽŸå§‹æ–‡æœ¬æœç´¢ã€‚请使用å¯ç”¨çš„æœç´¢ä»¤ç‰Œã€‚"
msgid "Pipeline|Run again"
-msgstr ""
+msgstr "é‡æ–°è¿è¡Œ"
msgid "Pipeline|Run for branch name or tag"
msgstr "为分支å称或标签è¿è¡Œ"
@@ -34591,9 +34676,6 @@ msgstr "è¦æŸ¥çœ‹å‰©ä½™ä½œä¸šï¼Œè¯·è½¬åˆ° %{boldStart}作业%{boldEnd} 选项å¡
msgid "Pipeline|Trigger author"
msgstr "触å‘者"
-msgid "Pipeline|Triggerer"
-msgstr "触å‘者"
-
msgid "Pipeline|Variables"
msgstr "å˜é‡"
@@ -35116,9 +35198,6 @@ msgstr "布局宽度"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "必须为%{min}到%{max}之间的数字"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr "注æ„:您å¯ç”¨äº†æ–°çš„导航,因此åªæœ‰æ·±è‰²æ¨¡å¼ä¸»é¢˜ä¼šæ˜¾è‘—改å˜å¤–观。"
-
msgid "Preferences|Preview"
msgstr "预览"
@@ -35230,8 +35309,11 @@ msgstr "上一次未解决的讨论"
msgid "Primary Action"
msgstr "主è¦æ“作"
+msgid "Primary navigation sidebar"
+msgstr "主导航侧边æ "
+
msgid "Print as PDF"
-msgstr ""
+msgstr "以 PDF å½¢å¼æ‰“å°"
msgid "Print codes"
msgstr "打å°ä»£ç "
@@ -35276,7 +35358,7 @@ msgid "Private projects can be created in your personal namespace with:"
msgstr "ç§æœ‰é¡¹ç›®å¯ä»¥åœ¨ä¸ªäººå称空间中创建:"
msgid "Private projects compute cost factor"
-msgstr "ç§æœ‰é¡¹ç›®è®¡ç®—æˆæœ¬å› ç´ "
+msgstr "ç§æœ‰é¡¹ç›®è®¡ç®—消耗系数"
msgid "Problem with %{name} command: %{message}."
msgstr "%{name} 命令出错: %{message}。"
@@ -35353,9 +35435,6 @@ msgstr "返回仪表盘"
msgid "ProductAnalytics|Click Events"
msgstr "点击事件"
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr "将所有事件相互比较"
@@ -35371,9 +35450,6 @@ msgstr "比较所有功能的功能使用情况"
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr "比较所有页é¢çš„页é¢æµè§ˆé‡"
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr "创建å¯è§†åŒ–"
@@ -35381,7 +35457,7 @@ msgid "ProductAnalytics|Creating your product analytics instance..."
msgstr "正在创建产å“分æžå®žä¾‹..."
msgid "ProductAnalytics|Cube API key"
-msgstr ""
+msgstr "Cube API 密钥"
msgid "ProductAnalytics|Details on how to configure product analytics to collect data."
msgstr "如何é…置产å“分æžæ¥æ”¶é›†æ•°æ®çš„详情。"
@@ -35410,9 +35486,6 @@ msgstr "有关更多信æ¯ï¼Œè¯·å‚阅%{linkStart}文档%{linkEnd}。"
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr "è¦è®©äº§å“分æžä»ªè¡¨ç›˜å¼€å§‹å‘您显示一些数æ®ï¼Œæ‚¨éœ€è¦å°†åˆ†æžè·Ÿè¸ªä»£ç æ·»åŠ åˆ°æ‚¨çš„项目中。"
-msgid "ProductAnalytics|Go back"
-msgstr "返回"
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr "一个用户有多少会è¯"
@@ -35473,8 +35546,11 @@ msgstr "设置产å“分æž"
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr "设置跟踪您的产å“表现,并优化产å“和开å‘æµç¨‹ã€‚"
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr "Snowplow é…置器连接字符串"
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
-msgstr ""
+msgstr "Snowplow é…置器实例的连接字符串。"
msgid "ProductAnalytics|The host to send all tracking events to"
msgstr "è¦å‘é€æ‰€æœ‰è·Ÿè¸ªäº‹ä»¶çš„主机"
@@ -35497,11 +35573,8 @@ msgstr "跟踪特定功能"
msgid "ProductAnalytics|Unique Users"
msgstr "独立用户数"
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
-msgstr ""
+msgstr "用于从 Cube 实例检索仪表盘数æ®ã€‚"
msgid "ProductAnalytics|User Sessions"
msgstr "用户会è¯"
@@ -35731,8 +35804,8 @@ msgstr "ä¸è¦åœ¨æ‚¨çš„个人资料中显示与活动相关的个人信æ¯ã€‚"
msgid "Profiles|Edit Profile"
msgstr "编辑个人资料"
-msgid "Profiles|Email"
-msgstr "电å­é‚®ä»¶"
+msgid "Profiles|Email address"
+msgstr "电å­é‚®ä»¶åœ°å€"
msgid "Profiles|Email addresses"
msgstr "电å­é‚®ä»¶åœ°å€"
@@ -36166,9 +36239,6 @@ msgstr "项目或群组"
msgid "Project order will not be saved as local storage is not available."
msgstr "由于本地存储ä¸å¯ç”¨ï¼Œå› æ­¤ä¸ä¼šä¿å­˜é¡¹ç›®é¡ºåºã€‚"
-msgid "Project overview"
-msgstr "项目概览"
-
msgid "Project path"
msgstr "项目路径"
@@ -36658,6 +36728,12 @@ msgstr "功能标志"
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "用于在此项目中å作开å‘想法和计划工作的çµæ´»å·¥å…·ã€‚"
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr "对于 Gitaly,数æ®åœ¨å­˜å‚¨ä¸Šçš„ä½ç½®ã€‚对于 Gitaly Cluster,虚拟存储上的数æ®ä½ç½®ã€‚"
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr "对于 Gitaly,存储仓库的存储的å称。对于 Gitaly Cluster,存储仓库的虚拟存储的å称。"
+
msgid "ProjectSettings|Forks"
msgstr "派生"
@@ -36793,6 +36869,9 @@ msgstr "公开"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr "在项目中å‘布ã€å­˜å‚¨å’ŒæŸ¥çœ‹è½¯ä»¶åŒ…。"
+msgid "ProjectSettings|Relative path:"
+msgstr "相对路径:"
+
msgid "ProjectSettings|Releases"
msgstr "å‘布"
@@ -36865,6 +36944,9 @@ msgstr "永远ä¸ä¼šæ‰§è¡ŒåŽ‹ç¼©ï¼Œå¹¶ä¸”该å¤é€‰æ¡†æ˜¯éšè—的。"
msgid "ProjectSettings|Status checks must succeed"
msgstr "状æ€æ£€æŸ¥å¿…é¡»æˆåŠŸ"
+msgid "ProjectSettings|Storage name:"
+msgstr "存储å称:"
+
msgid "ProjectSettings|Store custom configuration files."
msgstr "存储自定义é…置文件。"
@@ -37684,6 +37766,12 @@ msgstr "代ç æ‰€æœ‰è€…批准"
msgid "ProtectedBranch|Create wildcard"
msgstr "创建通é…符"
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr "直接推é€åˆ°åˆ†æ”¯æ—¶ä¸é€‚用于用户 **å…许推é€** 。å¯é€‰éƒ¨åˆ†æœªæ‰§è¡Œã€‚"
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr "å‘å—ä¿æŠ¤åˆ†æ”¯æŽˆäºˆåˆå¹¶æƒé™è¿˜å¯ä»¥æå‡æŸäº› CI/CD 功能的æƒé™ã€‚"
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr "继承的 - å¯ä»¥åœ¨ç¾¤ç»„级别更改此设置"
@@ -37733,7 +37821,7 @@ msgid "ProtectedBranch|Tag"
msgstr "标签"
msgid "ProtectedBranch|There are currently no protected branches, to protect a branch start by creating a new one above."
-msgstr ""
+msgstr "当å‰æ²¡æœ‰å—ä¿æŠ¤çš„分支,您å¯ä»¥åœ¨ä¸Šé¢æ–°å»ºä¸€ä¸ªæ¥ä¿æŠ¤åˆ†æ”¯ã€‚"
msgid "ProtectedBranch|Toggle allowed to force push"
msgstr "切æ¢å…许强制推é€"
@@ -37756,8 +37844,8 @@ msgstr "查看作为分支规则的å—ä¿æŠ¤åˆ†æ”¯"
msgid "ProtectedBranch|What are protected branches?"
msgstr "什么是å—ä¿æŠ¤çš„分支?"
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
-msgstr "直接推é€åˆ°åˆ†æ”¯æ—¶ã€‚ä¸é€‚用于**å…许推é€**的用户。å¯é€‰éƒ¨åˆ†ä¸å¼ºåˆ¶æŽ¨é€ã€‚"
+msgid "ProtectedBranch|What are the security implications?"
+msgstr "有哪些安全éšæ‚£ï¼Ÿ"
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
msgstr "您åªèƒ½æ·»åŠ å…±äº«æ­¤é¡¹ç›®çš„群组。%{learn_more_link}"
@@ -37809,12 +37897,15 @@ msgstr "删除部署人规则"
msgid "ProtectedEnvironments|Edit"
msgstr "编辑"
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
-msgstr "å—ä¿æŠ¤çš„环境(%{protectedEnvironmentsCount})"
-
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr "批准数é‡å¿…须介于 1 到 5 之间"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr "ä¿æŠ¤çŽ¯å¢ƒ"
+
+msgid "ProtectedEnvironments|Protected environments"
+msgstr "å—ä¿æŠ¤çš„环境"
+
msgid "ProtectedEnvironments|Remove approval rule"
msgstr "删除批准规则"
@@ -37824,6 +37915,9 @@ msgstr "需è¦çš„批准次数"
msgid "ProtectedEnvironments|Save"
msgstr "ä¿å­˜"
+msgid "ProtectedEnvironments|Select users"
+msgstr "选择用户"
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr "设置哪些群组ã€è®¿é—®çº§åˆ«æˆ–用户需è¦æ‰¹å‡†ã€‚"
@@ -37842,6 +37936,9 @@ msgstr "用户"
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} 将对开å‘人员å¯å†™ã€‚确定继续å—?"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr "添加新的å—ä¿æŠ¤çŽ¯å¢ƒ"
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr "指定了以下部署级别的所有环境å‡å—父组ä¿æŠ¤ã€‚%{link_start}了解更多%{link_end}。"
@@ -37899,9 +37996,6 @@ msgstr "选择环境"
msgid "ProtectedEnvironment|Select groups"
msgstr "选择群组"
-msgid "ProtectedEnvironment|Select users"
-msgstr "选择用户"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr "当å‰æ²¡æœ‰å—ä¿æŠ¤çš„环境。"
@@ -37968,9 +38062,6 @@ msgstr "æ供说明"
msgid "Provisioned by:"
msgstr "æ供者:"
-msgid "Proxy support for this API is not available currently"
-msgstr "æ­¤APIç›®å‰ä¸æ”¯æŒä½¿ç”¨ä»£ç†"
-
msgid "Public"
msgstr "公开"
@@ -37993,7 +38084,7 @@ msgid "Public projects are an easy way to allow everyone to have read-only acces
msgstr "公开项目是使æ¯ä¸ªäººéƒ½èƒ½å¤Ÿåªè¯»è®¿é—®çš„一ç§ç®€å•æ–¹å¼ã€‚"
msgid "Public projects compute cost factor"
-msgstr "公开项目计算æˆæœ¬å› ç´ "
+msgstr "公开项目计算消耗系数"
msgid "Publish to status page"
msgstr "å‘布到状æ€é¡µ"
@@ -38041,7 +38132,7 @@ msgid "Purchase|An error occurred with your purchase because your group is curre
msgstr "您的购买å‘生错误,因为您的群组目å‰å·²å…³è”到过期的订阅。%{supportLinkStart}创建工å•%{supportLinkEnd},我们的支æŒå›¢é˜Ÿå°†å助工作。"
msgid "Purchase|An error occurred with your purchase. We detected a %{customersPortalLinkStart}Customers Portal%{customersPortalLinkEnd} account that matches your email address, but it has not been linked to your GitLab.com account. Follow the %{linkCustomersPortalHelpLinkStart}instructions to link your Customers Portal account%{linkCustomersPortalHelpLinkEnd}, and retry the purchase. If the problem persists, %{supportLinkStart}contact support%{supportLinkEnd}."
-msgstr ""
+msgstr "è´­ä¹°æ—¶å‘生错误。我们检测到一个与您的电å­é‚®ä»¶åœ°å€åŒ¹é…çš„ %{customersPortalLinkStart}æžç‹è®¢å•ç®¡ç†ä¸­å¿ƒ%{customersPortalLinkEnd} 账户,但它尚未链接到您的 JiHuLab.com 账户。按照 %{linkCustomersPortalHelpLinkStart}说明关è”您的æžç‹è®¢å•ç®¡ç†ä¸­å¿ƒè´¦æˆ·%{linkCustomersPortalHelpLinkEnd},然åŽé‡æ–°è´­ä¹°ã€‚如果问题ä»ç„¶å­˜åœ¨ï¼Œ%{supportLinkStart}请è”系支æŒäººå‘˜%{supportLinkEnd}。"
msgid "Purchase|Your card was declined due to insufficient funds. Make sure you have sufficient funds, then retry the purchase or use a different card. If the problem persists, %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr "您的å¡å› èµ„金ä¸è¶³è€Œè¢«æ‹’ç»ã€‚ç¡®ä¿æ‚¨æœ‰è¶³å¤Ÿçš„资金,然åŽé‡è¯•è´­ä¹°æˆ–使用ä¸åŒçš„å¡ã€‚如果问题ä»ç„¶å­˜åœ¨ï¼Œè¯· %{supportLinkStart}è”系支æŒäººå‘˜%{supportLinkEnd}。"
@@ -38331,9 +38422,6 @@ msgstr "通过电å­é‚®ä»¶æŽ¥æ”¶æ»¥ç”¨æŠ¥å‘Šé€šçŸ¥ã€‚"
msgid "Receive notifications about your own activity"
msgstr "接收关于您自己活动的通知"
-msgid "Receive product marketing emails"
-msgstr "接收产å“è¥é”€ç”µå­é‚®ä»¶"
-
msgid "Recent"
msgstr "最近"
@@ -38473,35 +38561,11 @@ msgstr "å‘用户å‘é€ç”µå­é‚®ä»¶"
msgid "RegistrationFeatures|use this feature"
msgstr "使用此功能"
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr "您确定è¦è·³è¿‡è¿™ä¸€æ­¥å—?"
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr "å¯ç”¨å…费计算分钟数"
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr "GitLab ä¸ä¼šä»Žæ‚¨çš„å¡ä¸­æ‰£æ¬¾ï¼Œå®ƒåªä¼šç”¨äºŽéªŒè¯ã€‚"
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr "使用 GitLab 共享 runner çš„æµæ°´çº¿å°†å¤±è´¥ï¼Œç›´åˆ°æ‚¨éªŒè¯æ‚¨çš„å¸æˆ·ã€‚"
+msgid "Registries enqueued to be resynced"
+msgstr "é•œåƒåº“排队以é‡æ–°åŒæ­¥"
-msgid "RegistrationVerification|Skip this for now"
-msgstr "暂时跳过"
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr "为了防止 GitLab å…å—垃圾邮件和滥用,我们è¦æ±‚您使用有效的付款方å¼ï¼ˆä¾‹å¦‚借记å¡æˆ–信用å¡ï¼‰æ¥éªŒè¯æ‚¨çš„身份。在此之å‰ï¼Œæ‚¨æ— æ³•ä½¿ç”¨å…费计算分钟数æ¥æž„建您的应用程åºã€‚"
-
-msgid "RegistrationVerification|Validate account"
-msgstr "验è¯å¸æˆ·"
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr "验è¯æ‚¨çš„身份"
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr "是的,我想跳过"
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
-msgstr "您å¯ä»¥ç¨åŽéªŒè¯æ‚¨çš„å¸æˆ·ã€‚"
+msgid "Registries enqueued to be reverified"
+msgstr "é•œåƒåº“排队以é‡æ–°éªŒè¯"
msgid "Registry entry enqueued to be resynced"
msgstr "仓库æ¡ç›®æŽ’队等待é‡æ–°åŒæ­¥"
@@ -38834,9 +38898,6 @@ msgstr "删除电è¯éªŒè¯è±å…"
msgid "Remove priority"
msgstr "删除优先级"
-msgid "Remove report"
-msgstr "删除报告"
-
msgid "Remove reviewer"
msgstr "删除审核者"
@@ -38849,6 +38910,9 @@ msgstr "删除次è¦ç”µå­é‚®ä»¶"
msgid "Remove spent time"
msgstr "删除消耗时间"
+msgid "Remove summary"
+msgstr "删除摘è¦"
+
msgid "Remove time estimate"
msgstr "删除时间估计"
@@ -38858,9 +38922,6 @@ msgstr "删除主题头åƒ"
msgid "Remove user"
msgstr "删除用户"
-msgid "Remove user & report"
-msgstr "删除用户和报告"
-
msgid "Remove user from group"
msgstr "从群组中删除用户"
@@ -39140,12 +39201,6 @@ msgstr "您为什么è¦ä¸¾æŠ¥è¿™ä¸ªç”¨æˆ·ï¼Ÿ"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "由%{reportedBy}报告于%{timeAgo}"
-msgid "Reported by"
-msgstr "报告人"
-
-msgid "Reported by %{reporter}"
-msgstr "由%{reporter}报告"
-
msgid "Reporter"
msgstr "报告者"
@@ -39446,9 +39501,6 @@ msgstr "已开始é‡æ–°è®¡ç®—仓库使用情况"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr "仓库: %{counter_repositories} / Wikis: %{counter_wikis} / 构建产物: %{counter_build_artifacts} / æµæ°´çº¿äº§ç‰©ï¼š%{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / 代ç ç‰‡æ®µ: %{counter_snippets} / 软件包: %{counter_packages} / 上传文件: %{counter_uploads}"
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "选择"
-
msgid "Request"
msgstr "请求"
@@ -39853,11 +39905,14 @@ msgid "Root cause analysis"
msgstr "根本原因分æž"
msgid "Root cause analysis is a feature that analyzes your logs to determine why a job may have failed and the potential ways to fix it. To generate this analysis, we may share information in your job logs with %{linkStart}Third-Party AI providers%{linkEnd}. Before initiating this analysis, please do not include in your logs any information that could impact the security or privacy of your account."
-msgstr ""
+msgstr "根因分æžæ˜¯ä¸€é¡¹åŠŸèƒ½ï¼Œå¯åˆ†æžæ‚¨çš„日志以确定作业å¯èƒ½å¤±è´¥çš„原因åŠè§£å†³è¯¥é—®é¢˜çš„潜在方法。为了生æˆæ­¤åˆ†æžï¼Œæˆ‘们å¯èƒ½ä¼šä¸Ž %{linkStart}第三方 AI æ供商%{linkEnd} 共享您的作业日志中的信æ¯ã€‚在开始此分æžä¹‹å‰ï¼Œè¯·ä¸è¦åœ¨æ‚¨çš„日志中包å«ä»»ä½•å¯èƒ½å½±å“您账户的安全或éšç§çš„ä¿¡æ¯ã€‚"
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr "规则å称"
+
msgid "Rule name is already taken."
msgstr "规则å称已被使用。"
@@ -40283,6 +40338,9 @@ msgstr "%{type}çš„æˆå‘˜å¯ä»¥æ³¨å†ŒRunner"
msgid "Runners|Minor version upgrades are available."
msgstr "次è¦ç‰ˆæœ¬å‡çº§çŽ°åœ¨å¯ç”¨ã€‚"
+msgid "Runners|Most recent failures"
+msgstr "最近的失败记录"
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr "多个标签必须用逗å·åˆ†éš”。例如,%{example}。"
@@ -40567,8 +40625,8 @@ msgstr "选择è¦åˆ†é…给此 runner 的项目"
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr "选择您喜欢的 runner,然åŽåœ¨ AWS CloudFormation 控制å°ä¸­é€‰æ‹© runner 的容é‡ã€‚"
-msgid "Runners|Shared runners are disabled in the group settings"
-msgstr "在群组设置中ç¦ç”¨å…±äº« runners"
+msgid "Runners|Shared runners are disabled in the group settings."
+msgstr "在群组设置中ç¦ç”¨å…±äº« Runner"
msgid "Runners|Shared runners are disabled."
msgstr "共享 runners å·²ç¦ç”¨ã€‚"
@@ -40649,6 +40707,9 @@ msgstr "实例 runner 选中作业所需的时间。等待 runner 的作业处äº
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr "使用此é…置的æ¯ä¸ª runner 的唯一 ID。"
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr "您的实例 Runner 最近没有失败。如果 Runner 失败,错误消æ¯å°†åœ¨è¿™é‡Œæ˜¾ç¤ºã€‚"
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr "现在没有è¿è¡Œä½œä¸šçš„ runners。当å¯ç”¨çš„ runners 选中作业时,显示在此处。"
@@ -40852,11 +40913,14 @@ msgid "SAML|To access %{groupName}, you must sign in using single sign-on throug
msgstr "è¦è®¿é—® %{groupName},您必须通过外部登录页é¢ä½¿ç”¨å•ç‚¹ç™»å½•è¿›è¡Œç™»å½•ã€‚"
msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
-msgstr ""
+msgstr "è¦åœ¨æ‚¨ä½¿ç”¨å•ç‚¹ç™»å½•æˆåŠŸç™»å½•åŽå…许 %{strongOpen}%{group_name}%{strongClose} 管ç†æ‚¨çš„æžç‹GitLab 账户 %{strongOpen}%{username}%{strongClose} (%{email}),请选择 %{strongOpen}授æƒ%{strongClose}。"
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "您的组织的 SSO 已连接到您的 GitLab å¸æˆ·"
+msgid "SBOMs last updated"
+msgstr "SBOM 最åŽæ›´æ–°"
+
msgid "SCIM|SCIM Token"
msgstr "SCIM 令牌"
@@ -40965,9 +41029,6 @@ msgstr "ä¿å­˜å†…部备注"
msgid "Save password"
msgstr "ä¿å­˜å¯†ç "
-msgid "Save pipeline schedule"
-msgstr "ä¿å­˜æµæ°´çº¿è®¡åˆ’"
-
msgid "Saving"
msgstr "ä¿å­˜ä¸­"
@@ -40980,11 +41041,11 @@ msgstr "%{hostname} 的时区"
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr "%{period} %{days} 于 %{time} %{timezoneLabel} %{timezone}"
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
-msgstr ""
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
+msgstr "%{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period} çš„ %{rules} æ“作"
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
-msgstr ""
+msgstr "æ¯æ¬¡æµæ°´çº¿è¿è¡Œ %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} 时为 %{rules}"
msgid "ScanExecutionPolicy|A runner will be selected automatically from those available."
msgstr "系统将从å¯ç”¨çš„ runners 中自动选择一个 runner。"
@@ -41106,11 +41167,14 @@ msgstr "时间æ¡ä»¶åªèƒ½æ·»åŠ åˆ°åŽŸå·²å­˜åœ¨çš„æ¼æ´ž"
msgid "ScanResultPolicy|Age is:"
msgstr "时间:"
-msgid "ScanResultPolicy|Block users from unprotecting branches"
-msgstr ""
+msgid "ScanResultPolicy|Attribute is:"
+msgstr "属性是:"
-msgid "ScanResultPolicy|Choose an option"
-msgstr "选择一个选项"
+msgid "ScanResultPolicy|Attribute:"
+msgstr "属性:"
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
+msgstr "属性由扫æ工具自动应用"
msgid "ScanResultPolicy|Choose criteria type"
msgstr "选择æ¡ä»¶ç±»åž‹"
@@ -41124,6 +41188,24 @@ msgstr "自定义的 CI å˜é‡"
msgid "ScanResultPolicy|Except"
msgstr "除外"
+msgid "ScanResultPolicy|False positive"
+msgstr "误报"
+
+msgid "ScanResultPolicy|Fix available"
+msgstr "å¯ç”¨ä¿®å¤"
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr "å¯ç”¨çš„ä¿®å¤ä»…适用于容器和ä¾èµ–项扫æ"
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr "如果选择,以下选项将覆盖 %{linkStart}项目设置%{linkEnd} ,但仅影å“策略中选择的分支。"
+
+msgid "ScanResultPolicy|Is"
+msgstr "是"
+
+msgid "ScanResultPolicy|Is not"
+msgstr "ä¸æ˜¯"
+
msgid "ScanResultPolicy|License is:"
msgstr "许å¯è¯æ˜¯ï¼š"
@@ -41136,8 +41218,8 @@ msgstr "匹é…"
msgid "ScanResultPolicy|New age"
msgstr "新时间"
-msgid "ScanResultPolicy|New severity"
-msgstr "新建严é‡çº§åˆ«"
+msgid "ScanResultPolicy|New attribute"
+msgstr "新建属性"
msgid "ScanResultPolicy|New status"
msgstr "新建状æ€"
@@ -41148,18 +41230,24 @@ msgstr "新检测到"
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr "åªå…许 1 个时间æ¡ä»¶"
-msgid "ScanResultPolicy|Only 1 severity is allowed"
-msgstr "åªå…许有 1 个严é‡æ€§"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
+msgstr "ä»…å…许 2 个属性标准"
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
msgstr "åªå…许 2 个状æ€æ¡ä»¶"
msgid "ScanResultPolicy|Override project approval settings"
-msgstr ""
+msgstr "覆盖项目审批设置"
msgid "ScanResultPolicy|Pre-existing"
msgstr "预先存在"
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr "防止分支ä¿æŠ¤ä¿®æ”¹"
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr "å—ä¿æŠ¤çš„分支设置"
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr "添加æ¡ä»¶å‰é€‰æ‹©æ‰«æ类型"
@@ -41187,9 +41275,18 @@ msgstr "当 %{scanType} %{scanners} 在 %{branches} %{branchExceptions} è¿è¡Œï¼
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr "当针对 %{branches} %{branchExceptions} 的开放åˆå¹¶è¯·æ±‚中的 %{scanType} 和许å¯è¯åŒ¹é…以下所有æ¡ä»¶æ—¶ï¼š"
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr "当 %{scanType} 处于通过 %{commitType} æŒ‡å‘ %{branches} %{branchExceptions} 的打开状æ€æ—¶"
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr "当 %{scanners} 在 %{branches} %{branchExceptions} 分支的开放åˆå¹¶è¯·æ±‚中,找到指定的扫æ器æ¡ä»¶å¹¶åŒ¹é…以下æ¡ä»¶çš„ %{boldDescription}"
+msgid "ScanResultPolicy|any commits"
+msgstr "任何æ交"
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr "任何未签åæ交"
+
msgid "ScanResultPolicy|license status"
msgstr "许å¯è¯çŠ¶æ€"
@@ -41301,6 +41398,9 @@ msgstr "æœç´¢ç¾¤ç»„"
msgid "Search an environment spec"
msgstr "æœç´¢çŽ¯å¢ƒè§„则"
+msgid "Search artifacts"
+msgstr "æœç´¢äº§ç‰©"
+
msgid "Search assignees"
msgstr "æœç´¢æŒ‡æ´¾äºº"
@@ -41370,15 +41470,12 @@ msgstr "æœç´¢é‡Œç¨‹ç¢‘"
msgid "Search or filter commits"
msgstr "æœç´¢æˆ–过滤æ交"
-msgid "Search or filter results"
-msgstr "æœç´¢æˆ–过滤结果"
-
-msgid "Search or filter results..."
-msgstr "æœç´¢æˆ–筛选结果......"
-
msgid "Search or filter results…"
msgstr "æœç´¢æˆ–筛选结果…"
+msgid "Search or go to…"
+msgstr "æœç´¢æˆ–转到…"
+
msgid "Search page"
msgstr "æœç´¢é¡µ"
@@ -41594,6 +41691,9 @@ msgstr "安全é…ç½®"
msgid "Security dashboard"
msgstr "安全仪表盘"
+msgid "Security reports last updated"
+msgstr "最新更新的安全报告"
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr "当测试覆盖率下é™æ—¶éœ€è¦åˆå¹¶è¯·æ±‚批准。"
@@ -41750,6 +41850,12 @@ msgstr "和 "
msgid "SecurityOrchestration| and all the following apply:"
msgstr "以下所有内容å‡é€‚用:"
+msgid "SecurityOrchestration| for any commits"
+msgstr "对于任何æ交"
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr "对于未签åæ交"
+
msgid "SecurityOrchestration| or "
msgstr "或 "
@@ -41759,8 +41865,14 @@ msgstr "是 %{licenseState} 并且是"
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr "%{namespaces} 使用的 %{agent}"
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
-msgstr "%{branches} 上的 %{cadence}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr "%{branchName}"
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr "%{branchName}(在 %{codeStart}%{fullPath}%{codeEnd} 中)"
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
+msgstr "%{cadence} 于 %{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
msgstr "%{licenses} 和 %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr "获å–扫æ结果策略时出错。"
msgid "SecurityOrchestration|And scans to be performed:"
msgstr "è¦æ‰§è¡Œçš„扫æ:"
+msgid "SecurityOrchestration|Any merge request"
+msgstr "任何åˆå¹¶è¯·æ±‚"
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr "确定è¦åˆ é™¤æ­¤ç­–ç•¥å—?此æ“作无法撤消。"
@@ -41888,8 +42003,8 @@ msgstr "å¯ç”¨"
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr "强制此项目的安全性。 %{linkStart}更多信æ¯ã€‚%{linkEnd}"
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
-msgstr "æ¯æ¬¡æµæ°´çº¿åœ¨ %{branches} è¿è¡Œæ—¶"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
+msgstr "æ¯æ¬¡æµæ°´çº¿è¿è¡Œ %{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|Exceptions"
msgstr "异常"
@@ -41900,12 +42015,18 @@ msgstr "加载集群代ç†å¤±è´¥ã€‚"
msgid "SecurityOrchestration|Failed to load images."
msgstr "加载镜åƒå¤±è´¥ã€‚"
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr "对于 %{branches}%{commitType}%{branchExceptionsString}上的任何åˆå¹¶è¯·æ±‚"
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr "对于大型群组,对原已存在的åˆå¹¶è¯·æ±‚应用策略å˜æ›´å¯èƒ½ä¼šæœ‰å¾ˆå¤§çš„延迟。策略å˜æ›´é€šå¸¸å¯¹äºŽæ–°åˆ›å»ºçš„åˆå¹¶è¯·æ±‚,几乎立å³åº”用。"
msgid "SecurityOrchestration|Groups"
msgstr "群组"
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr "éšè—é¢å¤–的分支"
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr "如果任何扫æ器在针对主分支的开放åˆå¹¶è¯·æ±‚中å‘现新检测的严é‡æ¼æ´žï¼Œç„¶åŽéœ€è¦ä»»ä½• App security æˆå‘˜çš„两次批准。"
@@ -42171,6 +42292,9 @@ msgstr "使用扫æ结果策略创建规则,在åˆå¹¶åˆå¹¶è¯·æ±‚之å‰æ£€æŸ¥
msgid "SecurityOrchestration|View policy project"
msgstr "查看策略项目"
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr "æ¼æ´ž %{vulnerabilityStates}"
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr "æ¼æ´žä¸º %{vulnerabilityStates}。"
@@ -42183,14 +42307,14 @@ msgstr "æ¼æ´žæ—¶é—´å°äºŽ %{vulnerabilityAge}。"
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr "æ¼æ´žæ—¶é—´éœ€è¦å…ˆå‰å­˜åœ¨æ¼æ´žçŠ¶æ€ï¼ˆå·²æ£€æµ‹ã€å·²ç¡®è®¤ã€å·²è§£å†³æˆ–已忽略)"
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
-msgstr "当 %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} 在 %{targeting}%{branches}%{criteriaApply} 的开放åˆå¹¶è¯·æ±‚中"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
+msgstr "当 %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} 在 %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply} 的开放åˆå¹¶è¯·æ±‚中"
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr "当许å¯è¯æ‰«æ器在 %{targeting}%{branches} 的开放åˆå¹¶è¯·æ±‚中找到除 %{licenses}%{detection} 之外的任何许å¯è¯æ—¶ã€‚"
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "当许å¯è¯æ‰«æ器在 %{targeting}%{branches}%{branchExceptionsString} 的开放åˆå¹¶è¯·æ±‚中找到除 %{licenses}%{detection} 之外的任何许å¯è¯æ—¶ã€‚"
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr "当许å¯è¯æ‰«æ器在 %{targeting}%{branches} 的开放åˆå¹¶è¯·æ±‚ä¸­æ‰¾åˆ°åŒ¹é… %{licenses}%{detection} 的任何许å¯è¯æ—¶ã€‚"
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "当许å¯è¯æ‰«æ器在 %{targeting}%{branches}%{branchExceptionsString} 的开放åˆå¹¶è¯·æ±‚ä¸­æ‰¾åˆ°åŒ¹é… %{licenses}%{detection} 的任何许å¯è¯æ—¶ã€‚"
msgid "SecurityOrchestration|With the following customized CI variables:"
msgstr "使用以下自定义 CI å˜é‡ï¼š"
@@ -42219,14 +42343,20 @@ msgstr "任何å—ä¿æŠ¤çš„分支"
msgid "SecurityOrchestration|any security scanner finds"
msgstr "任何安全扫æ器å‘现"
+msgid "SecurityOrchestration|are false positives"
+msgstr "误报"
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr "ä¸æ˜¯è¯¯æŠ¥"
+
msgid "SecurityOrchestration|branch"
msgstr "分支"
msgid "SecurityOrchestration|branches"
msgstr "分支"
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
-msgstr "在å为 %{agents} %{cadence} 的代ç†ä¸Šæ‰§è¡Œ"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
+msgstr "在å为 %{agents} %{cadence}%{branchExceptionsString} 的代ç†ä¸Šæ‰§è¡Œ"
msgid "SecurityOrchestration|group level branch input"
msgstr "群组级分支输入"
@@ -42234,6 +42364,12 @@ msgstr "群组级分支输入"
msgid "SecurityOrchestration|group level branch selector"
msgstr "群组级分支选择器"
+msgid "SecurityOrchestration|have a fix available"
+msgstr "有å¯ç”¨çš„ä¿®å¤"
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr "没有å¯ç”¨çš„ä¿®å¤"
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr "超过 %{allowed}"
@@ -42303,9 +42439,6 @@ msgstr "添加评论(必填)"
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr "为忽略添加评论或原因"
-msgid "SecurityReports|Add comment & dismiss"
-msgstr "添加评论并关闭"
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "添加或删除安全区内的项目。 此列表中项目的扫æ结果将显示在安全仪表盘和æ¼æ´žæŠ¥å‘Šä¸­ã€‚"
@@ -42360,6 +42493,9 @@ msgstr "在'%{vulnerabilityName}' 上的评论已编辑"
msgid "SecurityReports|Configure security testing"
msgstr "é…置安全测试"
+msgid "SecurityReports|Confirm dismissal"
+msgstr "确认忽略"
+
msgid "SecurityReports|Create Issue"
msgstr "创建议题"
@@ -42375,9 +42511,15 @@ msgstr "检测"
msgid "SecurityReports|Development vulnerabilities"
msgstr "å¼€å‘æ¼æ´ž"
+msgid "SecurityReports|Dismiss as"
+msgstr "忽略为"
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "忽略æ¼æ´ž"
+msgid "SecurityReports|Dismissal comment"
+msgstr "忽略评论"
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "已忽略的'%{vulnerabilityName}'"
@@ -42408,6 +42550,9 @@ msgstr "下载扫æçš„ URL"
msgid "SecurityReports|Download the patch to apply it manually"
msgstr "下载补ä¸æ‰‹åŠ¨åº”用"
+msgid "SecurityReports|Edit dismissal"
+msgstr "编辑忽略"
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr "您无æƒæŸ¥çœ‹æ­¤ä»ªè¡¨ç›˜æˆ–尚未设置仪表盘。请å‘管ç†å‘˜æŸ¥è¯¢æ‚¨çš„æƒé™è®¾ç½®ï¼Œæˆ–检查仪表盘é…置并继续。"
@@ -42525,9 +42670,6 @@ msgstr "报告已过期"
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr "结果显示åˆå¹¶è¯·æ±‚引入的æ¼æ´žï¼Œæ­¤å¤–还有从您项目的默认分支中最新æˆåŠŸæµæ°´çº¿ä¸­å­˜åœ¨çš„æ¼æ´žã€‚"
-msgid "SecurityReports|Save comment"
-msgstr "ä¿å­˜è¯„论"
-
msgid "SecurityReports|Scan details"
msgstr "扫æ详情"
@@ -42571,8 +42713,8 @@ msgstr "ä»ç„¶æ£€æµ‹åˆ°"
msgid "SecurityReports|Submit vulnerability"
msgstr "æ交æ¼æ´ž"
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
-msgstr "æ¼æ´žæŠ¥å‘Šæ˜¾ç¤ºå¯¹é¡¹ç›®é»˜è®¤åˆ†æ”¯çš„æˆåŠŸæ‰«æ结果,手动添加的æ¼æ´žè®°å½•ä»¥åŠä»Žæ‰«ææ“作环境中å‘现的æ¼æ´žã€‚ %{linkStart}了解更多。%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
+msgstr "æ¼æ´žæŠ¥å‘Šæ˜¾ç¤ºå¯¹é¡¹ç›®é»˜è®¤åˆ†æ”¯çš„æˆåŠŸæ‰«æ结果,手动添加的æ¼æ´žè®°å½•ä»¥åŠä»Žæ‰«ææ“作环境中å‘现的æ¼æ´žã€‚%{linkStart}了解更多。%{linkEnd}"
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
msgstr "安全报告包å«ä¸€ä¸ªæˆ–多个无法解æžä¸”未记录的æ¼æ´žå‘现。è¦è°ƒæŸ¥ä¸€ä¸ªæŠ¥å‘Šï¼Œä¸‹è½½ä½œä¸šè¾“出中的产物。确ä¿åˆ›å»ºçš„安全报告都符åˆç›¸å…³çš„ %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}。"
@@ -42919,9 +43061,6 @@ msgstr "以多部分格å¼ï¼ˆHTML 和纯文本)å‘é€ç”µå­é‚®ä»¶ã€‚å–消选ä
msgid "Send email notification"
msgstr "å‘é€ç”µå­é‚®ä»¶é€šçŸ¥"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "å‘é€ç”µå­é‚®ä»¶ä»¥å¸®åŠ©æŒ‡å¯¼æ–°ç”¨æˆ·å®Œæˆæ–°äººæµç¨‹ã€‚"
-
msgid "Send emails to users upon account deactivation."
msgstr "å¸æˆ·åœç”¨åŽå‘用户å‘é€ç”µå­é‚®ä»¶ã€‚"
@@ -42991,6 +43130,9 @@ msgstr "æœåŠ¡å¸æˆ·å¯†é’¥æŽˆæƒ GitLab 部署您的 Google Cloud 项目"
msgid "Service Desk"
msgstr "æœåŠ¡å°"
+msgid "Service Desk Ticket"
+msgstr "æœåŠ¡å°å·¥å•"
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr "æœåŠ¡å°å…许人们在没有自己的用户账å·çš„情况下在您的 GitLab 实例中创建议题。它为最终用户在项目中创建议题æ供了一个唯一的电å­é‚®ä»¶åœ°å€ã€‚回å¤å¯ä»¥é€šè¿‡ GitLab ç•Œé¢æˆ–通过电å­é‚®ä»¶å‘é€ã€‚最终用户åªèƒ½é€šè¿‡ç”µå­é‚®ä»¶æŸ¥çœ‹ä¸»é¢˜ã€‚"
@@ -43015,26 +43157,38 @@ msgstr "用户没有æƒé™åœ¨æ­¤å‘½å空间中创建æœåŠ¡å¸æˆ·ã€‚"
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr "用户没有æƒé™åˆ›å»ºæœåŠ¡å¸æˆ·ã€‚"
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr "%{customEmail} 与 SMTP 主机 %{smtpAddress} %{badgeStart}已验è¯%{badgeEnd}"
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr "无法与指定主机建立连接或出现 SSL 问题。"
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr "验è¯ç”µå­é‚®ä»¶å·²å‘é€åˆ°æ‚¨çš„自定义电å­é‚®ä»¶åœ°å€çš„å­åœ°å€ã€‚å¯èƒ½éœ€è¦ 30 分钟。å±å¹•ä¼šè‡ªåŠ¨åˆ·æ–°ã€‚"
+
msgid "ServiceDesk|Cannot create custom email"
msgstr "无法创建自定义电å­é‚®ä»¶"
msgid "ServiceDesk|Cannot update custom email"
msgstr "无法更新自定义电å­é‚®ä»¶"
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr "检查您的转å‘设置并确ä¿åŽŸå§‹ç”µå­é‚®ä»¶å‘件人ä¿ç•™åœ¨â€œå‘件人â€æ ‡å¤´ä¸­ã€‚"
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
-msgstr ""
+msgstr "使用 TLS 时的常用端å£ä¸º 587, ä¸ä½¿ç”¨æ—¶ä¸º 25。"
msgid "ServiceDesk|Configure a custom email address"
msgstr "é…置自定义电å­é‚®ä»¶åœ°å€"
msgid "ServiceDesk|Connect a custom email address your customers can use to create Service Desk issues. Forward all emails from your custom email address to the Service Desk email address of this project. GitLab will send Service Desk emails from the custom address on your behalf using your SMTP credentials."
-msgstr ""
+msgstr "连接客户å¯ä»¥ç”¨æ¥åˆ›å»ºæœåŠ¡å°é—®é¢˜çš„自定义电å­é‚®ä»¶åœ°å€ã€‚ 将所有邮件从您的自定义电å­é‚®ä»¶åœ°å€è½¬å‘到此项目的æœåŠ¡å°ç”µå­é‚®ä»¶åœ°å€ã€‚æžç‹GitLab 将使用您的 SMTP 凭æ®ï¼Œä»£è¡¨æ‚¨ä»Žè‡ªå®šä¹‰åœ°å€å‘é€æœåŠ¡å°ç”µå­é‚®ä»¶ã€‚"
msgid "ServiceDesk|Copy Service Desk email address"
-msgstr ""
+msgstr "å¤åˆ¶æœåŠ¡å°ç”µå­çš„邮件地å€"
msgid "ServiceDesk|Custom email address"
-msgstr ""
+msgstr "自定义电å­é‚®ä»¶åœ°å€"
msgid "ServiceDesk|Custom email address could not be verified."
msgstr "无法验è¯è‡ªå®šä¹‰ç”µå­é‚®ä»¶åœ°å€ã€‚"
@@ -43048,26 +43202,50 @@ msgstr "自定义电å­é‚®ä»¶åœ°å€éªŒè¯å·²å¤„ç†ä½†å¤±è´¥ã€‚"
msgid "ServiceDesk|Custom email already exists"
msgstr "自定义电å­é‚®ä»¶å·²å­˜åœ¨"
+msgid "ServiceDesk|Custom email disabled."
+msgstr "å·²ç¦ç”¨è‡ªå®šä¹‰ç”µå­é‚®ä»¶ã€‚"
+
msgid "ServiceDesk|Custom email does not exist"
msgstr "自定义电å­é‚®ä»¶ä¸å­˜åœ¨"
+msgid "ServiceDesk|Custom email enabled."
+msgstr "å·²å¯ç”¨è‡ªå®šä¹‰ç”µå­é‚®ä»¶ã€‚"
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
-msgstr ""
+msgstr "自定义电å­é‚®ä»¶æ˜¯å¿…需的并且必须是一个有效的电å­é‚®ä»¶åœ°å€ã€‚"
msgid "ServiceDesk|Email address your customers can use to send support requests. It must support sub-addressing."
-msgstr ""
+msgstr "您的客户å¯ä»¥ç”¨æ¥å‘é€æ”¯æŒè¯·æ±‚的电å­é‚®ä»¶åœ°å€ã€‚它必须支æŒå­åœ°å€ã€‚"
msgid "ServiceDesk|Enable Service Desk"
msgstr "å¯ç”¨æœåŠ¡å°"
+msgid "ServiceDesk|Enable custom email address"
+msgstr "å¯ç”¨è‡ªå®šä¹‰ç”µå­é‚®ä»¶åœ°å€"
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr "有关为您的实例设置æœåŠ¡å°çš„帮助,请è”系管ç†å‘˜ã€‚"
+msgid "ServiceDesk|Incorrect From header"
+msgstr "å‘件人标头ä¸æ­£ç¡®"
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr "验è¯ä»¤ç‰Œä¸æ­£ç¡®"
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr "凭æ®æ— æ•ˆ"
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr "从æœåŠ¡å°ç”µå­é‚®ä»¶åˆ›å»ºçš„议题将显示在此处,æ¯æ¡è¯„论都æˆä¸ºç”µå­é‚®ä»¶å¯¹è¯çš„一部分。"
+msgid "ServiceDesk|Keep custom email"
+msgstr "ä¿ç•™è‡ªå®šä¹‰ç”µå­é‚®ä»¶"
+
msgid "ServiceDesk|Minimum 8 characters long."
-msgstr ""
+msgstr "至少 8 个字符长。"
+
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr "或é‡ç½®å¹¶å°†æ–°çš„自定义电å­é‚®ä»¶åœ°å€è¿žæŽ¥åˆ°æ­¤æœåŠ¡å°ã€‚"
msgid "ServiceDesk|Parameters missing"
msgstr "缺少å‚æ•°"
@@ -43075,38 +43253,53 @@ msgstr "缺少å‚æ•°"
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr "请在%{linkStart}å馈议题%{linkEnd}中分享您对此功能的å馈"
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr "请é‡è¯•ã€‚检查电å­é‚®ä»¶è½¬å‘设置和凭æ®ï¼Œç„¶åŽé‡æ–°å¯åŠ¨éªŒè¯ã€‚"
+
+msgid "ServiceDesk|Reset custom email"
+msgstr "é‡ç½®è‡ªå®šä¹‰ç”µå­é‚®ä»¶"
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr "é‡ç½®è‡ªå®šä¹‰ç”µå­é‚®ä»¶åœ°å€å¹¶åˆ é™¤å‡­æ®"
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr "é‡ç½®è‡ªå®šä¹‰ç”µå­é‚®ä»¶åœ°å€ã€‚"
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
-msgstr ""
+msgstr "SMTP 地å€æ˜¯å¿…需的并且必须是å¯è§£æžçš„。"
msgid "ServiceDesk|SMTP host"
-msgstr ""
+msgstr "SMTP 主机"
+
+msgid "ServiceDesk|SMTP host issue"
+msgstr "SMTP 主机问题"
msgid "ServiceDesk|SMTP password"
-msgstr ""
+msgstr "SMTP 密ç "
msgid "ServiceDesk|SMTP password is required and must be at least 8 characters long."
-msgstr ""
+msgstr "SMTP 密ç æ˜¯å¿…需的,且长度必须至少为 8 个字符。"
msgid "ServiceDesk|SMTP port"
-msgstr ""
+msgstr "SMTP 端å£"
msgid "ServiceDesk|SMTP port is required and must be a port number larger than 0."
-msgstr ""
+msgstr "SMTP 端å£æ˜¯å¿…需的,并且端å£å·å¿…须大于 0 。"
msgid "ServiceDesk|SMTP username"
-msgstr ""
+msgstr "SMTP 用户å"
msgid "ServiceDesk|SMTP username is required."
-msgstr ""
+msgstr "SMTP 用户å是必需的。"
msgid "ServiceDesk|Save and test connection"
-msgstr ""
+msgstr "ä¿å­˜å¹¶æµ‹è¯•è¿žæŽ¥"
msgid "ServiceDesk|Saved custom email address and started verification."
-msgstr ""
+msgstr "å·²ä¿å­˜è‡ªå®šä¹‰ç”µå­é‚®ä»¶åœ°å€å¹¶å¼€å§‹éªŒè¯ã€‚"
msgid "ServiceDesk|Service Desk email address to forward emails to"
-msgstr ""
+msgstr "æœåŠ¡å°ç”µå­é‚®ä»¶åœ°å€ï¼Œç”¨äºŽè½¬å‘电å­é‚®ä»¶"
msgid "ServiceDesk|Service Desk is not enabled"
msgstr "æœåŠ¡å°æœªå¯ç”¨"
@@ -43120,15 +43313,45 @@ msgstr "缺少æœåŠ¡å°è®¾ç½®"
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr "缺少æœåŠ¡å°è®¾ç½®æˆ–验è¯å¯¹è±¡"
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr "给定的凭æ®ï¼ˆç”¨æˆ·å和密ç ï¼‰è¢« SMTP æœåŠ¡å™¨æ‹’ç»ã€‚"
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr "收到的电å­é‚®ä»¶æ²¡æœ‰åŒ…å«å‘é€åˆ°æ‚¨çš„电å­é‚®ä»¶åœ°å€çš„验è¯ä»¤ç‰Œã€‚"
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr "未åŠæ—¶æ”¶åˆ°éªŒè¯é‚®ä»¶ã€‚验è¯ç”µå­é‚®ä»¶åº”当在 30 分钟内出现在您实例的æœåŠ¡å°ä¸­ã€‚ç¡®ä¿æ‚¨å·²æ­£ç¡®è®¾ç½®ç”µå­é‚®ä»¶è½¬å‘。"
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr "è¦åœ¨æ­¤å®žä¾‹ä¸Šå¯ç”¨æœåŠ¡å°ï¼Œå®žä¾‹ç®¡ç†å‘˜å¿…须首先设置接收电å­é‚®ä»¶åœ°å€ã€‚"
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr "è¦ä¸ºæ­¤æœåŠ¡å°ä½¿ç”¨è‡ªå®šä¹‰ç”µå­é‚®ä»¶åœ°å€ï¼Œæ‚¨éœ€è¦å†æ¬¡é…置并验è¯ç”µå­é‚®ä»¶åœ°å€ã€‚"
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr "使用 Service Desk 与您的用户è”系并在 GitLab 内通过电å­é‚®ä»¶æ供客户支æŒ"
msgid "ServiceDesk|User cannot manage project."
msgstr "用户无法管ç†é¡¹ç›®ã€‚"
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr "未在规定时间内收到验è¯ç”µå­é‚®ä»¶"
+
+msgid "ServiceDesk|Verification failed"
+msgstr "验è¯å¤±è´¥"
+
+msgid "ServiceDesk|Verification started"
+msgstr "验è¯å·²å¼€å§‹"
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr "使用 SMTP 主机 %{smtpAddress}éªŒè¯ %{customEmail}:"
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr "å¯ç”¨åŽï¼Œå°†ä½¿ç”¨æ供的凭æ®å‘é€æœåŠ¡å°ç”µå­é‚®ä»¶ã€‚"
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr "您å³å°† %{strongStart}ç¦ç”¨è‡ªå®šä¹‰ç”µå­é‚®ä»¶åœ°å€%{strongEnd} %{customEmail} %{strongStart}并删除其凭æ®%{strongEnd}。"
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr "您的用户å¯ä»¥å‘以下地å€å‘é€ç”µå­é‚®ä»¶ï¼š"
@@ -43156,6 +43379,9 @@ msgstr "ä¼šè¯ ID"
msgid "Session duration (minutes)"
msgstr "会è¯æŒç»­æ—¶é—´(分钟)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr "无法验è¯ç”¨æˆ·ã€‚加载用户验è¯æŒ‘战时å‘生错误。请刷新å†æ¬¡é‡è¯•ã€‚"
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "å°†%{epic_ref}设置为父å²è¯—。"
@@ -43276,6 +43502,9 @@ msgstr "将时间估计设置为%{time_estimate}。"
msgid "Set to 0 for no size limit."
msgstr "设置为 0 表示没有大å°é™åˆ¶ã€‚"
+msgid "Set to 0 to disable timeout."
+msgstr "设置为 0 以ç¦ç”¨è¶…时。"
+
msgid "Set to auto-merge"
msgstr "设置为自动åˆå¹¶"
@@ -43354,6 +43583,9 @@ msgstr "您的状æ€åœ¨ %{date} æ—¶é‡ç½®ã€‚"
msgid "Sets %{epic_ref} as parent epic."
msgstr "å°†%{epic_ref}设置为父å²è¯—。"
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr "å°† checkin æ醒频率设置为 %{frequency}。"
+
msgid "Sets health status to %{health_status}."
msgstr "å°†å¥åº·çŠ¶æ€è®¾ç½®ä¸º %{health_status}。"
@@ -44187,6 +44419,9 @@ msgstr "有人从新ä½ç½®ç™»å½•åˆ°æ‚¨çš„ %{host} å¸æˆ·"
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "有人(希望是您)è¦æ±‚在 %{link_to_gitlab} 上é‡ç½®æ‚¨çš„ GitLab è´¦å·çš„密ç ã€‚"
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "出错了"
@@ -44280,9 +44515,6 @@ msgstr "获å–æè¿°å˜æ›´æ—¶å‡ºé”™äº†ï¼Œè¯·ç¨åŽé‡è¯•ã€‚"
msgid "Something went wrong while fetching details"
msgstr "获å–详细信æ¯æ—¶å‡ºé”™"
-msgid "Something went wrong while fetching latest comments."
-msgstr "获å–最新评论时出错。"
-
msgid "Something went wrong while fetching projects"
msgstr "获å–项目时出错。"
@@ -44614,7 +44846,7 @@ msgid "Source is not available"
msgstr "æºä¸å¯ç”¨"
msgid "Source project"
-msgstr ""
+msgstr "æºé¡¹ç›®"
msgid "Source project cannot be found."
msgstr "找ä¸åˆ°æºé¡¹ç›®ã€‚"
@@ -44947,7 +45179,7 @@ msgid "StatusCheck|Apply this status check to all branches or a specific protect
msgstr "将此状æ€æ£€æŸ¥åº”用于所有分支或特定的å—ä¿æŠ¤åˆ†æ”¯ã€‚"
msgid "StatusCheck|Check for a status response in merge requests. %{linkStart}Learn more%{linkEnd}."
-msgstr ""
+msgstr "在åˆå¹¶è¯·æ±‚中检查状æ€å“应。%{linkStart}了解更多%{linkEnd}。"
msgid "StatusCheck|Examples: QA, Security."
msgstr "示例:QAã€å®‰å…¨ã€‚"
@@ -45208,7 +45440,7 @@ msgid "Subscription deletion failed."
msgstr "订阅删除失败。"
msgid "Subscription for %{subscription} will be removed. Do you want to continue?"
-msgstr ""
+msgstr "%{subscription} 的订阅将被移除。您想è¦ç»§ç»­å—?"
msgid "Subscription service outage"
msgstr "订阅æœåŠ¡ä¸­æ–­"
@@ -45231,6 +45463,18 @@ msgstr "导出许å¯è¯ä½¿ç”¨æ–‡ä»¶"
msgid "SubscriptionBanner|Upload new license"
msgstr "上传新许å¯è¯"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr "如果您想增加席ä½ã€å‡çº§æ‚¨çš„计划或购买é¢å¤–产å“,请è”系您的æžç‹GitLab 销售代表。"
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr "这是由æžç‹GitLab 销售团队管ç†çš„自定义订阅"
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr "è¦æ›´æ”¹åªè¯»è®¢é˜…或购买其他产å“,请è”系您的 GitLab åˆä½œä¼™ä¼´ã€‚"
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr "您的订阅为åªè¯»æ¨¡å¼"
+
msgid "SubscriptionTable|Add seats"
msgstr "添加席ä½"
@@ -45378,6 +45622,9 @@ msgstr "å·²æˆåŠŸå†»ç»“"
msgid "Successfully deleted WebAuthn device."
msgstr "å·²æˆåŠŸåˆ é™¤WebAuthn设备。"
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr "æˆåŠŸé“¾æŽ¥ ID:%{item_ids}。"
+
msgid "Successfully removed email."
msgstr "æˆåŠŸåˆ é™¤ç”µå­é‚®ä»¶ã€‚"
@@ -45396,6 +45643,9 @@ msgstr "æˆåŠŸè§£ç¦"
msgid "Successfully unblocked"
msgstr "æˆåŠŸè§£é™¤ç¦ç”¨"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr "æˆåŠŸå–消链接 ID:%{item_ids}。"
+
msgid "Successfully unlocked"
msgstr "æˆåŠŸè§£é™¤ç¦ç”¨"
@@ -45692,7 +45942,7 @@ msgid "SuperSonics|You have added a license that activates on %{date}. Please se
msgstr "您已ç»æ·»åŠ äº†æ¿€æ´»äºŽ %{date} 的许å¯è¯ã€‚详情请查看下é¢çš„订阅历å²è¡¨ã€‚"
msgid "SuperSonics|You have applied a true-up for %{trueUpQuantity} %{trueUpQuantityUsers} but you need one for %{expectedTrueUpQuantity} %{expectedTrueUpQuantityUsers}. To pay for seat overages, contact your sales representative. For further assistance, contact %{licenseSupportLinkStart}GitLab support%{licenseSupportLinkEnd}."
-msgstr ""
+msgstr "您已ç»åº”用了 %{trueUpQuantity} %{trueUpQuantityUsers} çš„æ ¡å‡†ï¼Œä½†æ‚¨éœ€è¦ %{expectedTrueUpQuantity} %{expectedTrueUpQuantityUsers}的校准。 è‹¥è¦æ”¯ä»˜è¶…é¢çš„席ä½è´¹ç”¨ï¼Œè¯·è”系您的销售代表。如需进一步帮助,请è”ç³» %{licenseSupportLinkStart}æžç‹GitLab 支æŒäººå‘˜%{licenseSupportLinkEnd}。"
msgid "SuperSonics|You have successfully added a license that activates on %{date}. Please see the subscription history table below for more details."
msgstr "您已æˆåŠŸæ·»åŠ åœ¨ %{date} 激活的许å¯è¯ã€‚有关更多详细信æ¯ï¼Œè¯·å‚阅下é¢çš„订阅历å²è¡¨ã€‚"
@@ -46055,6 +46305,9 @@ msgstr "与 GitLab Duo Chat 通信时出错。请ç¨åŽå†è¯•ã€‚"
msgid "TanukiBot|What is a fork?"
msgstr "什么是派生?"
+msgid "Targe branch"
+msgstr "目标分支"
+
msgid "Target"
msgstr "目标"
@@ -46067,8 +46320,14 @@ msgstr "目标路径"
msgid "Target branch"
msgstr "目标分支"
-msgid "Target branch or tag"
-msgstr "目标分支或标签"
+msgid "Target branch rule"
+msgstr "目标分支规则"
+
+msgid "Target branch rule created."
+msgstr "目标分支规则已创建。"
+
+msgid "Target branch rules"
+msgstr "目标分支规则"
msgid "Target branch: %{target_branch}"
msgstr "目标分支:%{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr "页é¢å·²è¶…时,无法显示。"
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr "父å²è¯—是ç§å¯†çš„,åªèƒ½åŒ…å«ç§å¯†å²è¯—和议题"
-msgid "The parsed YAML is too big"
-msgstr "解æžçš„ YAML 文件过大"
-
msgid "The password for the Jenkins server."
msgstr "Jenkins æœåŠ¡å™¨çš„密ç ã€‚"
@@ -47070,6 +47326,9 @@ msgstr "æ¼æ´žå·²ä¸å†è¢«æ£€æµ‹åˆ°ã€‚请在更改其状æ€å‰ç¡®ä¿æ¼æ´žå·²ä¿®
msgid "There are currently no mirrored repositories."
msgstr "ç›®å‰æ²¡æœ‰é•œåƒçš„仓库。"
+msgid "There are currently no target branch rules"
+msgstr "当å‰æ²¡æœ‰ç›®æ ‡åˆ†æ”¯è§„则"
+
msgid "There are merge conflicts"
msgstr "存在åˆå¹¶å†²çª"
@@ -47088,9 +47347,6 @@ msgstr "没有å¯è®¿é—®æ‚¨å¸æˆ·çš„SSH密钥。"
msgid "There are no Spam Logs"
msgstr "没有垃圾邮件日志"
-msgid "There are no abuse reports!"
-msgstr "没有滥用报告ï¼"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr "给定的 `represent_as` å‚数没有批准规则。请改用有效的用户/群组/角色å称。"
@@ -47263,7 +47519,7 @@ msgid "There was a problem fetching the latest pipeline status."
msgstr "获å–最新æµæ°´çº¿çŠ¶æ€æ—¶å‡ºçŽ°é—®é¢˜ã€‚"
msgid "There was a problem fetching the pipeline stage."
-msgstr ""
+msgstr "获å–æµæ°´çº¿é˜¶æ®µæ—¶å‡ºçŽ°é—®é¢˜ã€‚"
msgid "There was a problem fetching the pipeline stages."
msgstr "获å–æµæ°´çº¿é˜¶æ®µæ—¶å‡ºçŽ°é—®é¢˜ã€‚"
@@ -47340,6 +47596,9 @@ msgstr "获å–选中群组的顶级标记时出错"
msgid "There was an error fetching the variables."
msgstr "获å–å˜é‡æ—¶å‡ºé”™ã€‚"
+msgid "There was an error fetching this merge request's pipelines."
+msgstr "获å–æ­¤åˆå¹¶è¯·æ±‚çš„æµæ°´çº¿æ—¶å‡ºé”™ã€‚"
+
msgid "There was an error fetching value stream analytics stages."
msgstr "获å–值æµåˆ†æžé˜¶æ®µæ—¶å‡ºé”™ã€‚"
@@ -47424,11 +47683,14 @@ msgstr "reCAPTCHA 验è¯é”™è¯¯ã€‚请å†æ¬¡éªŒè¯ reCAPTCHA。"
msgid "There was an summarizing your pending comments."
msgstr "有一份您的待处ç†è¯„论的摘è¦ã€‚"
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr "这些分支已ç»æœ‰ä¸€ä¸ªå¼€æ”¾çš„åˆå¹¶è¯·æ±‚:%{link_to_mr}。选择ä¸åŒçš„æºæˆ–目标分支。"
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr "这些日期会影å“您的å²è¯—在路线图中的显示方å¼ã€‚设置一个固定日期或从分é…给此å²è¯—中议题的里程碑继承的日期。"
msgid "These examples show common methods of triggering a pipeline with a pipeline trigger token. The URL and ID for this project is prefilled."
-msgstr ""
+msgstr "这些示例展示了使用æµæ°´çº¿è§¦å‘令牌触å‘æµæ°´çº¿çš„常用方法。该项目的 URL å’Œ ID 已预先填写。"
msgid "These existing issues have a similar title. It might be better to comment there instead of creating another similar issue."
msgstr "这些现有的议题具有类似的标题。在那里评论å¯èƒ½æ›´å¥½ï¼Œè€Œä¸æ˜¯åˆ›å»ºå¦ä¸€ä¸ªç±»ä¼¼çš„问题。"
@@ -47928,9 +48190,15 @@ msgstr "æ­¤åˆå¹¶è¯·æ±‚是从ç§æœ‰é¡¹ç›®åˆ°å†…部项目。"
msgid "This merge request is from an internal project to a public project."
msgstr "æ­¤åˆå¹¶è¯·æ±‚是从内部项目到公开项目。"
+msgid "This merge request is hidden because its author has been banned"
+msgstr "æ­¤åˆå¹¶è¯·æ±‚被éšè—,因为其作者已被ç¦æ­¢"
+
msgid "This merge request is locked."
msgstr "æ­¤åˆå¹¶è¯·æ±‚å·²é”定。"
+msgid "This merge request is locked. Only project members can comment."
+msgstr "该åˆå¹¶è¯·æ±‚已被é”定。åªæœ‰é¡¹ç›®æˆå‘˜æ‰èƒ½å‘表评论。"
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr "åˆå¹¶è¯·æ±‚å·²åˆå¹¶ã€‚è¦åº”用此建议,请直接编辑此文件。"
@@ -47949,11 +48217,11 @@ msgstr "æ­¤æµæ°´çº¿ä½¿ç”¨äº† %{strongStart}Auto DevOps 预先定义的并已å¯
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr "æ­¤æµæ°´çº¿ä½¿ç”¨ç”± Auto DevOps å¯ç”¨çš„预定义 CI/CD é…置。"
-msgid "This pipeline was triggered by a schedule"
-msgstr "æ­¤æµæ°´çº¿æ˜¯ç”±è®¡åˆ’触å‘çš„"
+msgid "This pipeline was created by a schedule"
+msgstr "æ­¤æµæ°´çº¿æ˜¯ç”±å®šæ—¶è®¡åˆ’创建的"
-msgid "This pipeline was triggered by a schedule."
-msgstr "æ­¤æµæ°´çº¿æ˜¯ç”±å®šæ—¶è®¡åˆ’触å‘çš„."
+msgid "This pipeline was created by a schedule."
+msgstr "æ­¤æµæ°´çº¿æ˜¯ç”±å®šæ—¶è®¡åˆ’创建的。"
msgid "This process deletes the project repository and all related resources."
msgstr "æ­¤æµç¨‹å°†åˆ é™¤é¡¹ç›®ä»“库和所有相关资æºã€‚"
@@ -48102,8 +48370,8 @@ msgstr "此用户是此%{workItemType}的作者。"
msgid "This variable value does not meet the masking requirements."
msgstr "æ­¤å˜é‡å€¼ä¸ç¬¦åˆéšè—è¦æ±‚。"
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
-msgstr "该æ¼æ´žå·²è‡ªåŠ¨è§£å†³ï¼Œå› ä¸ºå…¶æ¼æ´žç±»åž‹å·²åœ¨æ­¤é¡¹ç›®ä¸­ç¦ç”¨æˆ–已从 GitLab 的默认规则集中删除。"
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
+msgstr "该æ¼æ´žå·²è‡ªåŠ¨è§£å†³ï¼Œå› ä¸ºå…¶æ¼æ´žç±»åž‹å·²åœ¨æ­¤é¡¹ç›®ä¸­ç¦ç”¨æˆ–已从æžç‹GitLab 的默认规则集中删除。有关 SAST 规则更改的详细信æ¯ï¼Œè¯·å‚阅 https://docs.gitlab.cn/jh/user/application_security/sast/rules#important-rule-changes。"
msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr "这会使您注册的应用程åºå’Œ WebAuthn 设备无效。"
@@ -48228,7 +48496,7 @@ msgstr "时区"
msgid "TimeTrackingEstimated|Est"
msgstr "预计"
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr "从"
msgid "TimeTrackingReport|Run report"
@@ -48249,8 +48517,8 @@ msgstr "摘è¦"
msgid "TimeTrackingReport|Time spent"
msgstr "时间花费"
-msgid "TimeTrackingReport|To"
-msgstr "到"
+msgid "TimeTrackingReport|To the end of"
+msgstr "至"
msgid "TimeTrackingReport|Total time spent: "
msgstr "总时间花费:"
@@ -48669,8 +48937,8 @@ msgstr "è¦é‡æ–°æ¿€æ´»æ‚¨çš„å¸æˆ·ï¼Œè¯·åœ¨ %{gitlab_url}登录 GitLab。"
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr "è¦ç§»é™¤%{link_start}åªè¯»%{link_end}状æ€å¹¶é‡æ–°èŽ·å¾—写入æƒé™ï¼Œè¯·è®©æ‚¨çš„顶级群组所有者将您的顶级群组中的用户数é‡å‡å°‘到 %{free_limit} 个用户或更少,或者å‡çº§åˆ°æ²¡æœ‰ç”¨æˆ·é™åˆ¶çš„付费级别。"
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
-msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr "è¦ç§»é™¤ %{link_start}åªè¯»%{link_end} 状æ€å¹¶é‡æ–°èŽ·å¾—写入访问æƒé™ï¼Œæ‚¨å¯ä»¥å°†é¡¶çº§ç¾¤ç»„中的用户数é‡å‡å°‘到 %{free_limit} 或更少。您还å¯ä»¥å‡çº§åˆ°æ²¡æœ‰ç”¨æˆ·é™åˆ¶çš„付费级别。如果您需è¦æ›´å¤šæ—¶é—´ï¼Œå¯ä»¥å¼€å§‹ 30 天å…费试用,其中包å«æ— é™ç”¨æˆ·ã€‚"
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
msgstr "è¦å°†ç”µè¯éªŒè¯æ›¿æ¢ä¸ºä¿¡ç”¨å¡éªŒè¯ï¼Œè¯·ä½¿ç”¨ä¸‹é¢çš„按钮创建电è¯éªŒè¯è±å…。"
@@ -48951,6 +49219,9 @@ msgstr "此个人访问令牌已在被检测到时自动撤销。在将此æ¼æ´ž
msgid "Tomorrow"
msgstr "明日"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr "å¯ç”¨äº†å¤ªå¤šçš„命å空间,通过控制å°æˆ–API管ç†å®ƒä»¬ã€‚"
@@ -49030,6 +49301,9 @@ msgstr "全部"
msgid "Total Score"
msgstr "总分"
+msgid "Total Spans"
+msgstr "总跨度"
+
msgid "Total cores (CPUs)"
msgstr "总核心(CPU)"
@@ -49060,9 +49334,15 @@ msgstr "1000+"
msgid "Trace Details"
msgstr "跟踪详情"
+msgid "Trace Start"
+msgstr "跟踪开始"
+
msgid "Tracing"
msgstr "跟踪"
+msgid "Tracing|%{ms} ms"
+msgstr "%{ms} 毫秒"
+
msgid "Tracing|Check again"
msgstr "å†æ¬¡æŸ¥çœ‹"
@@ -49073,7 +49353,7 @@ msgid "Tracing|Duration"
msgstr "æŒç»­æ—¶é—´"
msgid "Tracing|Duration (ms)"
-msgstr ""
+msgstr "æŒç»­æ—¶é—´ (毫秒)"
msgid "Tracing|Enable"
msgstr "å¯ç”¨"
@@ -49130,11 +49410,23 @@ msgid "Tracing|Operation"
msgstr "è¿ç»´"
msgid "Tracing|Period"
-msgstr ""
+msgstr "周期"
msgid "Tracing|Service"
msgstr "æœåŠ¡"
+msgid "Tracing|Span Details"
+msgstr "Span 详细信æ¯"
+
+msgid "Tracing|Span ID"
+msgstr "Span ID"
+
+msgid "Tracing|Status Code"
+msgstr "状æ€ç "
+
+msgid "Tracing|Toggle children spans"
+msgstr "切æ¢å­ Span"
+
msgid "Tracing|Trace ID"
msgstr "跟踪 ID"
@@ -49365,7 +49657,7 @@ msgid "Try grouping with different labels"
msgstr "å°è¯•ä½¿ç”¨ä¸åŒçš„标记分组"
msgid "Try out **styling** _your_ content right here or read the [direction](%{directionUrl})."
-msgstr ""
+msgstr "å°è¯•åœ¨æ­¤å¤„对_您的_内容进行**æ ·å¼**设置或阅读 [direction](%{directionUrl})。"
msgid "Try out GitLab Pipelines"
msgstr "试用 GitLab æµæ°´çº¿"
@@ -49499,9 +49791,6 @@ msgstr "URL或请求ID"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr "用户 %{user_name} 将被删除ï¼æ‚¨ç¡®å®šå—?"
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "用户 %{user} 将被删除ï¼ä½ ç¡®å®šå—?"
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "用户将被ç¦ç”¨ï¼ä½ ç¡®å®šå—?"
@@ -49589,6 +49878,9 @@ msgstr "无法加载åˆå¹¶è¯·æ±‚部件。请å°è¯•é‡æ–°åŠ è½½é¡µé¢ã€‚"
msgid "Unable to load the page"
msgstr "无法载入页é¢"
+msgid "Unable to load user list. Reload the page and try again."
+msgstr "未能加载用户列表,刷新页é¢ä»¥é‡è¯•ã€‚"
+
msgid "Unable to parse JSON"
msgstr "æ— æ³•è§£æž JSON"
@@ -49622,9 +49914,6 @@ msgstr "当å‰æ— æ³•æ›´æ–°æ­¤ å²è¯—。"
msgid "Unable to update this issue at this time."
msgstr "当å‰æ— æ³•æ›´æ–°è¿™ä¸ªè®®é¢˜ã€‚"
-msgid "Unable to verify the user"
-msgstr "无法验è¯ç”¨æˆ·"
-
msgid "Unapprove a merge request"
msgstr "å–消批准åˆå¹¶è¯·æ±‚"
@@ -49703,6 +49992,9 @@ msgstr "很é—憾,您å‘é€ç»™GitLab的电å­é‚®ä»¶æ— æ³•å¤„ç†ã€‚"
msgid "Unhappy?"
msgstr "ä¸å–œæ¬¢ï¼Ÿ"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr "天"
@@ -50078,6 +50370,9 @@ msgstr "è´­ä¹°é¢å¤–的计算分钟数"
msgid "UsageQuota|Buy storage"
msgstr "购买存储"
+msgid "UsageQuota|Code Suggestions"
+msgstr "代ç å»ºè®®"
+
msgid "UsageQuota|Code packages and container images."
msgstr "代ç åŒ…和容器镜åƒã€‚"
@@ -50099,12 +50394,12 @@ msgstr "容器镜åƒåº“"
msgid "UsageQuota|Dependency proxy"
msgstr "ä¾èµ–代ç†"
-msgid "UsageQuota|Filter chart by month"
-msgstr "按月筛选图表"
-
msgid "UsageQuota|Filter charts by year"
msgstr "按年筛选图表"
+msgid "UsageQuota|Filter projects data by month"
+msgstr "按月过滤项目数æ®"
+
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
msgstr "关于存储é™åˆ¶çš„更多信æ¯ï¼Œè¯·å‚阅我们的 %{faq_link_start}常è§é—®é¢˜%{link_end}。"
@@ -50112,10 +50407,10 @@ msgid "UsageQuota|Git repository."
msgstr "Git仓库。"
msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker Images."
-msgstr "存储 Docker é•œåƒçš„ Gitlab-integrated Docker Container Registry。"
+msgstr "æžç‹GitLab 集æˆçš„存储 Docker é•œåƒçš„ Docker 容器镜åƒåº“"
msgid "UsageQuota|Group settings %{gt} Usage quotas"
-msgstr ""
+msgstr "群组设置 %{gt} 使用é¢åº¦"
msgid "UsageQuota|Included in %{planName} subscription"
msgstr "包å«åœ¨ %{planName} 订阅中"
@@ -50150,6 +50445,9 @@ msgstr "命å空间概览"
msgid "UsageQuota|Namespace storage used"
msgstr "已使用的命å空间存储"
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr "命å空间总存储表示所有项目ã€å®¹å™¨é•œåƒåº“å’Œä¾èµ–代ç†æ¶ˆè€—的存储总和。"
+
msgid "UsageQuota|No compute usage data available."
msgstr "没有å¯ç”¨çš„计算å•ä½ä½¿ç”¨æ•°æ®ã€‚"
@@ -50199,7 +50497,7 @@ msgid "UsageQuota|Storage"
msgstr "存储"
msgid "UsageQuota|Storage per project included in %{planName} subscription"
-msgstr ""
+msgstr "%{planName} 订阅中包å«çš„æ¯ä¸ªé¡¹ç›®çš„存储空间"
msgid "UsageQuota|Storage type"
msgstr "存储类型"
@@ -50216,15 +50514,15 @@ msgstr "%{strong_start}%{context_name}%{strong_end} 群组将å—此影å“。"
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr "%{strong_start}%{context_name}%{strong_end} 项目将å—此影å“。"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr "以下图表和表格显示了 %{month} %{year}的使用情况"
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
-msgstr ""
+msgstr "命å空间目å‰æ­£åœ¨ä½¿ç”¨ %{strong_start}%{used_storage}%{strong_end} 的命å空间储存区,群组所有者å¯ä»¥æŸ¥çœ‹å‘½å空间储存状况,并且å¯ä»Ž %{strong_start}%{usage_quotas_nav_instruction}%{strong_end} 购买更多的储存空间。 %{docs_link_start}如何管ç†æˆ‘的储存空间%{link_end}?"
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr "命å空间当å‰æ­£åœ¨ä½¿ç”¨ %{strong_start}%{used_storage}%{strong_end} 的命å空间存储。从 %{strong_start}%{usage_quotas_nav_instruction}%{strong_end} 查看和管ç†æ‚¨çš„使用情况。%{docs_link_start}了解更多%{link_end}有关如何å‡å°‘存储空间的信æ¯ã€‚"
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr "下表显示 %{usageSince} 以æ¥çš„使用情况"
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr "此命å空间拥有 %{planLimit} 的存储空间。%{linkStart}如何应用é™åˆ¶ï¼Ÿ%{linkEnd}"
@@ -50283,7 +50581,7 @@ msgid "UsageQuota|Usage of resources across your projects"
msgstr "您的项目中资æºä½¿ç”¨æƒ…况"
msgid "UsageQuota|User settings %{gt} Usage quotas"
-msgstr ""
+msgstr "用户设置 %{gt} 使用é…é¢"
msgid "UsageQuota|Wiki content."
msgstr "Wiki 内容。"
@@ -50895,6 +51193,9 @@ msgstr "用户åå¯ç”¨ã€‚"
msgid "Username or email"
msgstr "用户å或邮箱"
+msgid "Username or primary email"
+msgstr "用户å或主è¦ç”µå­é‚®ä»¶"
+
msgid "Username:"
msgstr "用户å:"
@@ -51022,25 +51323,25 @@ msgid "Validations failed."
msgstr "验è¯å¤±è´¥ã€‚"
msgid "Validation|can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"
-msgstr ""
+msgstr "åªèƒ½åŒ…å«å°å†™å­—æ¯ã€æ•°å­—ã€â€œ_†和 “-â€ã€‚必须以字æ¯å¼€å¤´ï¼Œä¸èƒ½ä»¥ “-†或 “_†结尾"
msgid "Validation|groupId parameter is invalid"
-msgstr ""
+msgstr "groupId å‚数无效"
msgid "Validation|must belong to the same project"
-msgstr ""
+msgstr "必须属于åŒä¸€ä¸ªé¡¹ç›®"
msgid "Validation|parameters are invalid"
-msgstr ""
+msgstr "å‚数无效"
msgid "Validation|percentage must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "percentage 必须是 0 到 100 ä¹‹é—´çš„å­—ç¬¦ä¸²ï¼ˆå« 0 å’Œ 100)"
msgid "Validation|rollout must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "rollout 必须是 0 到 100 ä¹‹é—´çš„å­—ç¬¦ä¸²ï¼ˆå« 0 å’Œ 100)"
msgid "Validation|strategy name is invalid"
-msgstr ""
+msgstr "ç­–ç•¥å称无效"
msgid "Value"
msgstr "值"
@@ -51244,7 +51545,7 @@ msgid "VerificationReminder|You’ll now be able to take advantage of free compu
msgstr "您现在å¯ä»¥ä½¿ç”¨å…±äº« runners çš„å…费计算分钟数。"
msgid "Verifications status"
-msgstr ""
+msgstr "验è¯çŠ¶æ€"
msgid "Verified"
msgstr "已验è¯"
@@ -51456,7 +51757,7 @@ msgid "View the latest successful deployment to this environment"
msgstr "查看此环境最新æˆåŠŸéƒ¨ç½²"
msgid "View trigger token usage examples"
-msgstr ""
+msgstr "查看触å‘令牌用法示例"
msgid "View usage details"
msgstr "查看使用详情"
@@ -51596,6 +51897,9 @@ msgstr "详情"
msgid "VulnerabilityExport|Detected At"
msgstr "检测时间"
+msgid "VulnerabilityExport|Full Path"
+msgstr "完整路径"
+
msgid "VulnerabilityExport|Group Name"
msgstr "群组å称"
@@ -51623,17 +51927,20 @@ msgstr "工具"
msgid "VulnerabilityExport|Vulnerability"
msgstr "æ¼æ´ž"
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
msgstr "由%{user}%{statusStart}确认%{statusEnd}于%{timeago}"
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "ç”±æµæ°´çº¿%{pipelineLink}于%{timeago}%{statusStart}检测出%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr "在æµæ°´çº¿ %{pipelineLink} 中,于%{timeago} %{statusStart}检测到%{statusEnd} "
+
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
+msgstr "由 %{user} 于 %{timeago} %{statusStart}忽略%{statusEnd}"
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
-msgstr "由%{user}于%{timeago}%{statusStart}忽略%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr "由 %{user} 于 %{timeago} 因 %{dismissalReason}%{statusStart}忽略%{statusEnd}"
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "由%{user}于%{timeago}%{statusStart}解决%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr "由 %{user} 于 %{timeago} %{statusStart}解决%{statusEnd}"
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr "(å¯é€‰ï¼‰åŒ…括æ¼æ´žçš„解决方案(如果有)。"
@@ -51768,7 +52075,7 @@ msgid "VulnerabilityStatusTypes|Resolved"
msgstr "已解决"
msgid "Vulnerability|%{file} was not found in commit %{ref}"
-msgstr ""
+msgstr "在æ交 %{ref} 中未找到 %{file}"
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (版本 %{scannerVersion})"
@@ -51875,6 +52182,9 @@ msgstr "文件:"
msgid "Vulnerability|GitLab Security Report"
msgstr "GitLab 安全报告"
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr "æžç‹GitLab 已在 AI æ示的代ç ç‰‡æ®µä¸­è¯†åˆ«å‡ºæ•æ„Ÿå­—符串,表明å¯èƒ½å­˜åœ¨æ³„露的 secret。请在使用“解释此æ¼æ´žâ€åŠŸèƒ½ä¹‹å‰æ£€æŸ¥æ‚¨çš„代ç ã€‚如果您ä»å¸Œæœ›ç»§ç»­å¹¶å°† %{linkStart}代ç %{linkEnd} å‘é€ç»™ AI,请å•å‡»ä¸‹é¢çš„å¤é€‰æ¡†ã€‚"
+
msgid "Vulnerability|Hide prompt"
msgstr "éšè—æ示"
@@ -51972,7 +52282,7 @@ msgid "Vulnerability|Show prompt"
msgstr "显示æ示"
msgid "Vulnerability|Something went wrong while trying to get the source file."
-msgstr ""
+msgstr "å°è¯•èŽ·å–æºæ–‡ä»¶æ—¶å‡ºé”™ã€‚"
msgid "Vulnerability|Stacktrace snippet:"
msgstr "堆栈跟踪片段:"
@@ -51989,11 +52299,8 @@ msgstr "扫æ器确定此æ¼æ´žä¸ºè¯¯æŠ¥ã€‚在更改其状æ€ä¹‹å‰éªŒè¯è¯„ä¼°
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr "未修改的å“应是原始å“应没有对请求进行çªå˜çš„å“应"
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr "å‘生æ„外错误。 %{linkStart}请é‡è¯•%{linkEnd}。"
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
-msgstr "这是一项使用 AI 解释æ¼æ´žå¹¶æ供建议的实验性功能。在我们继续改进时,请谨慎使用此功能。请在 %{linkStart}此议题%{linkEnd}中æ供您的å馈和想法。"
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgstr "这是一项使用 AI 解释æ¼æ´žå¹¶æ供建议的测试版功能。在我们继续改进时,请谨慎使用此功能。请在 %{linkStart}此议题%{linkEnd}中æ供您的å馈和想法。"
msgid "Vulnerability|Tool"
msgstr "工具"
@@ -52028,6 +52335,9 @@ msgstr "æ¼æ´žç±»åˆ«ï¼š"
msgid "Vulnerability|Vulnerable method:"
msgstr "æ¼æ´žæ–¹æ³•ï¼š"
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr "警告:检测到å¯èƒ½çš„ secret"
+
msgid "WARNING:"
msgstr "警告:"
@@ -52355,6 +52665,12 @@ msgstr "支æŒä¾‹å¦‚ %{REGEX_CODE} 的正则表达å¼ã€‚"
msgid "Webhooks|Releases events"
msgstr "å‘布事件"
+msgid "Webhooks|Response body is empty"
+msgstr "å“应体为空"
+
+msgid "Webhooks|Response headers data is empty"
+msgstr "å“应标头数æ®ä¸ºç©º"
+
msgid "Webhooks|SSL verification"
msgstr "SSL验è¯"
@@ -52457,15 +52773,6 @@ msgstr "欢迎使用全新的导航æ "
msgid "Welcome, %{name}!"
msgstr "欢迎, %{name}ï¼"
-msgid "What are group audit events?"
-msgstr "什么是群组审计事件?"
-
-msgid "What are instance audit events?"
-msgstr "什么是实例审计事件?"
-
-msgid "What are project audit events?"
-msgstr "什么是项目审计事件?"
-
msgid "What are some examples?"
msgstr "有哪些示例?"
@@ -52817,6 +53124,12 @@ msgstr "进行中(WIP)é™åˆ¶"
msgid "Work item promoted successfully."
msgstr "工作项æˆåŠŸå‡çº§ã€‚"
+msgid "Work items are already linked"
+msgstr "工作项目已ç»è¢«é“¾æŽ¥"
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr "此工作项目将超过链接项目的最大数é‡ã€‚"
+
msgid "WorkItem|%{count} more assignees"
msgstr "%{count} 个更多的指派人"
@@ -52908,9 +53221,6 @@ msgstr "å¤åˆ¶ %{workItemType} 电å­é‚®ä»¶åœ°å€"
msgid "WorkItem|Create %{workItemType}"
msgstr "创建 %{workItemType}"
-msgid "WorkItem|Create objective"
-msgstr "创建目标"
-
msgid "WorkItem|Create work item"
msgstr "创建工作项"
@@ -52929,9 +53239,6 @@ msgstr "截止日期"
msgid "WorkItem|Existing task"
msgstr "现有任务"
-msgid "WorkItem|Health status"
-msgstr "å¥åº·çŠ¶å†µ"
-
msgid "WorkItem|History only"
msgstr "仅历å²è®°å½•"
@@ -52950,14 +53257,20 @@ msgstr "关键结果"
msgid "WorkItem|Key result"
msgstr "关键结果"
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr "将工作项目链接在一起,表明它们是相关的,或其中一个阻塞了其它的。"
+
+msgid "WorkItem|Linked Items"
+msgstr "链接的项目"
+
msgid "WorkItem|Mark as done"
msgstr "标记为完æˆ"
msgid "WorkItem|Milestone"
msgstr "里程碑"
-msgid "WorkItem|New objective"
-msgstr "新建目标"
+msgid "WorkItem|New %{workItemType}"
+msgstr "新建 %{workItemType}"
msgid "WorkItem|New task"
msgstr "新建任务"
@@ -53100,9 +53413,6 @@ msgstr "测试用例"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr "æ­¤%{workItemType}是ä¿å¯†çš„,åªèƒ½æ˜¾ç¤ºç»™æ‹¥æœ‰è‡³å°‘报告者访问æƒé™çš„团队æˆå‘˜ã€‚"
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr "该对象是ä¿å¯†çš„,åªå¯¹è‡³å°‘拥有报告者æƒé™çš„团队æˆå‘˜å¯è§"
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr "此工作项ä¸å¯ç”¨ã€‚它å¯èƒ½ä¸å­˜åœ¨ï¼Œæˆ–者您没有查看它的æƒé™ã€‚"
@@ -53133,8 +53443,8 @@ msgstr "您åªèƒ½åœ¨ä¿¡æ¯æµä¸­çœ‹åˆ°%{boldStart}其他活动%{boldEnd} 。è¦æ
msgid "Workspaces"
msgstr "工作区"
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
-msgstr "工作区是建立您代ç çš„虚拟沙盒环境。 您å¯ä»¥å…¬å¼€é¡¹ç›®åˆ›å»ºä¸€ä¸ªå·¥ä½œåŒºã€‚"
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
+msgstr "工作区是您在æžç‹GitLab 中的代ç çš„虚拟沙盒环境。"
msgid "Workspaces|Cancel"
msgstr "å–消"
@@ -53232,9 +53542,6 @@ msgstr "未知状æ€"
msgid "Workspaces|Workspaces"
msgstr "工作区"
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr "您åªèƒ½ä¸ºå…¬å¼€é¡¹ç›®åˆ›å»ºå·¥ä½œåŒºã€‚"
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr "您无法为此项目创建工作区"
@@ -53494,6 +53801,9 @@ msgstr "您å¯ä»¥é€šè¿‡è®¿é—®%{link}创建一个新的个人访问令牌"
msgid "You can create a new SSH key by visiting %{link}"
msgstr "您å¯ä»¥é€šè¿‡è®¿é—®%{link}创建一个新的SSH密钥"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr "您å¯ä»¥åˆ›å»ºä¸€ä¸ªæ–°çš„访问令牌或在您的 %{link_start}访问令牌%{link_end} 设置中检查。"
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr "您å¯ä»¥åœ¨æ‚¨çš„ %{pat_link_start}个人访问令牌%{pat_link_end} 设置中创建一个新的或检查它们。"
@@ -53503,6 +53813,9 @@ msgstr "您å¯ä»¥åœ¨æ‚¨çš„ %{ssh_key_link_start}SSH 密钥%{ssh_key_link_end} è®
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr "您å¯ä»¥åœ¨æ‚¨çš„ SSH 密钥设置 %{ssh_key_link} 中创建一个新的密钥或检查它们。"
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr "您å¯ä»¥åˆ›å»ºä¸€ä¸ªæ–°çš„访问令牌或在访问令牌设置中检查:%{target_url}"
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr "您å¯ä»¥åœ¨æ‚¨çš„个人访问令牌设置%{pat_link}中创建一个新的令牌或检查它们。"
@@ -53701,9 +54014,6 @@ msgstr "您没有任何应用。"
msgid "You don't have any authorized applications."
msgstr "您没有任何授æƒçš„应用。"
-msgid "You don't have any deployments right now."
-msgstr "您现在没有任何部署。"
-
msgid "You don't have any open merge requests"
msgstr "您没有任何开å¯çš„åˆå¹¶è¯·æ±‚"
@@ -53775,7 +54085,7 @@ msgid "You have insufficient permissions to create a Todo for this alert"
msgstr "您没有足够的æƒé™ä¸ºè¿™ä¸ªè­¦æŠ¥åˆ›å»ºå¾…办事项"
msgid "You have insufficient permissions to create a target branch rule"
-msgstr ""
+msgstr "您没有足够的æƒé™åˆ›å»ºç›®æ ‡åˆ†æ”¯è§„则"
msgid "You have insufficient permissions to create an HTTP integration for this project"
msgstr "您没有足够的æƒé™ä¸ºæ­¤é¡¹ç›®åˆ›å»ºHTTP集æˆ"
@@ -53859,7 +54169,7 @@ msgid "You must confirm your email within %{cut_off_days} days of signing up. If
msgstr "æ‚¨å¿…é¡»åœ¨æ³¨å†ŒåŽ %{cut_off_days} 天内确认您的电å­é‚®ä»¶ã€‚如果您未在此时间范围内确认您的电å­é‚®ä»¶ï¼Œæ‚¨çš„账户将被删除,并且您将需è¦é‡æ–°æ³¨å†Œ GitLab。"
msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
-msgstr ""
+msgstr "å¯ç”¨è°ƒè¯•è·Ÿè¸ªæ—¶ï¼Œæ‚¨å¿…须在关è”项目中具有开å‘人员或更高æƒé™æ‰èƒ½æŸ¥çœ‹ä½œä¸šæ—¥å¿—。è¦ç¦ç”¨è°ƒè¯•è·Ÿè¸ªï¼Œè¯·åœ¨æµæ°´çº¿é…置或 CI/CD 设置中将“CI_DEBUG_TRACEâ€å’Œâ€œCI_DEBUG_SERVICESâ€å˜é‡è®¾ç½®ä¸ºâ€œfalseâ€ã€‚如果您必须查看此作业日志,则此项目维护者或所有者必须将您添加到具有开å‘人员æƒé™æˆ–更高æƒé™çš„项目中。"
msgid "You must have maintainer access to force delete a lock"
msgstr "必须拥有维护者æƒé™æ‰èƒ½å¼ºåˆ¶åˆ é™¤é”"
@@ -54085,7 +54395,7 @@ msgid "Your DevOps Reports give an overview of how you are using GitLab from a f
msgstr "您的 DevOps 报告从功能角度概述了您如何使用 GitLab。使用它们æ¥æŸ¥çœ‹æ‚¨ä¸Žå…¶ä»–组织的比较情况,以åŠæ‚¨çš„团队之间的比较情况。"
msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. To ensure that your group does not become read-only, you should contact a user with the Owner role for this group to upgrade to a paid tier, or manage your usage. For more information about the upcoming usage limits, see our %{faq_link_start}FAQ%{link_end}."
-msgstr ""
+msgstr "您的å…费顶级群组 %{group_name} 拥有超过 %{free_users_limit} 个用户,使用超过 %{free_storage_limit} çš„æ•°æ®ã€‚对å…费顶级群组应用使用é™åˆ¶åŽï¼Œè¯¥ç¾¤ç»„中的项目将处于 %{read_only_link_start}åªè¯»çŠ¶æ€%{link_end}。为确ä¿æ‚¨çš„群组ä¸ä¼šå˜æˆåªè¯»ï¼Œæ‚¨åº”该è”系具有该群组所有者角色的用户以å‡çº§åˆ°ä»˜è´¹çº§ï¼Œæˆ–管ç†æ‚¨çš„使用情况。有关å³å°†åˆ°æ¥çš„使用é™åˆ¶çš„更多信æ¯ï¼Œè¯·å‚阅我们的 %{faq_link_start}常è§é—®é¢˜è§£ç­”%{link_end}。"
msgid "Your Free top-level group, %{group_name}, has more than %{free_users_limit} users and uses more than %{free_storage_limit} of data. After usage limits are applied to Free top-level groups, projects in this group will be in a %{read_only_link_start}read-only state%{link_end}. You should reduce the number of users or upgrade to a paid tier %{strong_start}before%{strong_end} you manage your storage usage. Otherwise, your Free top-level group will become read-only immediately because the 5-user limit applies. For more information, see our %{faq_link_start}FAQ%{link_end}.%{br_tag}%{br_tag}To minimize the impact of storage limits to Free top-level groups, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price for %{offer_availability_link_start}qualifying top-level groups%{link_end} when you purchase a new, one year subscription of GitLab Premium SaaS. This offer is valid until 2023-10-31."
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr "您的应用"
msgid "Your authorized applications"
msgstr "您已授æƒçš„应用"
-msgid "Your browser does not support iFrames"
-msgstr "您的æµè§ˆå™¨ä¸æ”¯æŒ iFrame"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr "您的æµè§ˆå™¨ä¸æ”¯æŒWebAuthn。请使用支æŒçš„æµè§ˆå™¨ï¼Œå¦‚Chrome(67+)或Firefox(60+)。"
@@ -54319,9 +54626,6 @@ msgstr "您的个人访问令牌将在 %{days_to_expire} 天或更短的时间å†
msgid "Your profile"
msgstr "个人资料"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "您的被é™åˆ¶ä¸ºæœ€å¤§ %{limit} 个项目ï¼è¯·ä¸Žæ‚¨çš„管ç†å‘˜è”系以增加它"
@@ -54346,6 +54650,9 @@ msgstr "您的需求正在导入。导入完æˆæ—¶æ‚¨å°†æ”¶åˆ°ä¸€å°ç¡®è®¤ç”µå­
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr "您的需求将在åŽå°å¯¼å…¥ã€‚完æˆåŽï¼Œæ‚¨å°†æ”¶åˆ°ä¸€å°ç¡®è®¤ç”µå­é‚®ä»¶ã€‚"
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr "您的资æºè®¿é—®ä»¤ç‰Œå°†åœ¨ %{days_to_expire} 天或更短的时间内到期"
+
msgid "Your search didn't match any commits."
msgstr "您的æœç´¢æ²¡æœ‰åŒ¹é…任何æ交。"
@@ -54513,6 +54820,9 @@ msgstr "所有å—ä¿æŠ¤çš„分支"
msgid "allowed to fail"
msgstr "å…许失败"
+msgid "already assigned to an epic"
+msgstr "已分é…到å²è¯—中"
+
msgid "already banned from namespace"
msgstr "已在命å空间中å°ç¦"
@@ -54620,6 +54930,9 @@ msgstr "ä¸èƒ½æ”¹æˆ %{new_type}"
msgid "can not be changed when assigned to an epic"
msgstr "分é…ç»™å²è¯—时无法更改"
+msgid "can not be set for template labels"
+msgstr "无法为模æ¿æ ‡è®°è®¾ç½®"
+
msgid "can not be set for this resource"
msgstr "无法为此资æºè®¾ç½®"
@@ -55128,6 +55441,9 @@ msgstr "由 %{author} 通过 %{email} 创建于 %{timeAgo}"
msgid "created by"
msgstr "创建人:"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr "为æ交 %{linkStart}%{shortId}%{linkEnd}创建了æµæ°´çº¿"
+
msgid "daily"
msgstr "æ¯æ—¥"
@@ -55193,6 +55509,9 @@ msgstr "例如, %{token}"
msgid "eg party_tanuki"
msgstr "例如 party_tanuki"
+msgid "eg. dev/*"
+msgstr "eg. dev/*"
+
msgid "element is not a hierarchy"
msgstr "此元素并éžç¾¤ç»„层级"
@@ -55278,9 +55597,6 @@ msgstr[0] "文件"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "结果无法找到或已与æ¼æ´žå…³è”。"
-msgid "for Workspace is required to be public"
-msgstr "对于è¦æ±‚公开的工作区"
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr "对于必须具有关è”çš„ RemoteDevelopmentAgentConfig 的工作区"
@@ -55540,6 +55856,9 @@ msgstr "它太大了"
msgid "jigsaw is not defined"
msgstr "拼图未定义"
+msgid "key result"
+msgstr "关键结果"
+
msgid "kuromoji custom analyzer"
msgstr "kuromoji自定义分æžå™¨"
@@ -55975,7 +56294,7 @@ msgid "must be a valid syntax highlighting theme ID"
msgstr "必须是有效的语法高亮主题 ID"
msgid "must be a value between 0 and 1"
-msgstr ""
+msgstr "必须为 0 到 1 之间的值"
msgid "must be after start"
msgstr "必须在开始之åŽ"
@@ -56010,6 +56329,9 @@ msgstr "必须在派生(fork)网络内"
msgid "must be less than the limit of %{tag_limit} tags"
msgstr "å¿…é¡»å°äºŽ %{tag_limit} 个标签的数é‡é™åˆ¶"
+msgid "must be owned by the user's enterprise group"
+msgstr "必须属于用户所属ä¼ä¸šé›†å›¢"
+
msgid "must be set for a project namespace"
msgstr "必须为项目命å空间设置"
@@ -56019,6 +56341,9 @@ msgstr "必须指定"
msgid "must be unique by status and elapsed time within a policy"
msgstr "必须在策略中的状æ€å’Œç»è¿‡æ—¶é—´ä¸Šæ˜¯å”¯ä¸€çš„"
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr "必须是唯一的。该 CA 已为å¦ä¸€ä¸ªå‘½å空间é…置。"
+
msgid "must belong to same project of its requirement object."
msgstr "必须属于需求对象所在的åŒä¸€é¡¹ç›®ã€‚"
@@ -56046,6 +56371,9 @@ msgstr "ä¸èƒ½æ˜¯å‘½å空间的所有者"
msgid "must not contain commonly used combinations of words and letters"
msgstr "ä¸èƒ½åŒ…å«å¸¸ç”¨çš„å•è¯å’Œå­—æ¯ç»„åˆ"
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr "å¿…é¡»åªåŒ…å«å­—æ¯ã€æ•°å­—ã€æ­£æ–œæ ï¼Œä¸‹åˆ’线ã€è¿žå­—符或å¥å·"
+
msgid "my-awesome-group"
msgstr "my-awesome-group"
@@ -56103,6 +56431,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item},和 %{lastItem}"
+msgid "objective"
+msgstr "目标"
+
msgid "on or after"
msgstr "ä¸æ—©äºŽ"
@@ -56396,6 +56727,9 @@ msgstr "%{slash_command} 增加或å‡å°‘å·²ç»èŠ±è´¹çš„时间。"
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr "å·²å¯åŠ¨"
+
msgid "started a discussion on %{design_link}"
msgstr "开始讨论%{design_link}"
@@ -56438,6 +56772,9 @@ msgstr "标签å称"
msgid "targeting "
msgstr "目标为"
+msgid "task"
+msgstr "任务"
+
msgid "terraform states"
msgstr "terraform 状æ€"
@@ -56486,9 +56823,6 @@ msgstr "总数必须å°äºŽæˆ–等于 %{size}"
msgid "triggered"
msgstr "已触å‘"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr "æ交 %{linkStart}%{shortId}%{linkEnd} 触å‘了æµæ°´çº¿"
-
msgid "two-factor authentication settings"
msgstr "åŒé‡è®¤è¯è®¾ç½®"
@@ -56544,6 +56878,9 @@ msgstr "%{report_type} 报告类型的 %{report_version} 版本已弃用;但æ˜
msgid "version %{versionIndex}"
msgstr "版本 %{versionIndex}"
+msgid "via"
+msgstr "通过"
+
msgid "via %{closed_via}"
msgstr "通过%{closed_via}"
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index 8251b133481..540e3149141 100644
--- a/locale/zh_HK/gitlab.po
+++ b/locale/zh_HK/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: zh-HK\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:03\n"
+"PO-Revision-Date: 2023-09-12 12:35\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -44,6 +44,10 @@ msgstr ""
msgid " and %{sliced}"
msgstr ""
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] ""
+
msgid " or "
msgstr "或"
@@ -574,9 +578,6 @@ msgstr ""
msgid "%{count} total weight"
msgstr ""
-msgid "%{dashboard_path} could not be found."
-msgstr ""
-
msgid "%{days} days until tags are automatically removed"
msgstr ""
@@ -622,7 +623,7 @@ msgstr ""
msgid "%{emailPrefix}@company.com"
msgstr ""
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
msgstr ""
msgid "%{extra} more downstream pipelines"
@@ -700,6 +701,12 @@ msgstr ""
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr ""
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr ""
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr ""
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr ""
@@ -775,6 +782,9 @@ msgstr ""
msgid "%{label_for_message} unavailable"
msgstr ""
+msgid "%{label_name} is locked and was not removed"
+msgstr ""
+
msgid "%{label_name} was removed"
msgstr ""
@@ -1203,10 +1213,10 @@ msgstr ""
msgid "%{verb} this %{noun} as a draft."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
msgstr ""
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
msgstr ""
msgid "%{widget} options"
@@ -1312,6 +1322,9 @@ msgstr ""
msgid "+ %{count} more"
msgstr "+ %{count} 以上"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr ""
+
msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} 更多"
@@ -1755,15 +1768,24 @@ msgstr ""
msgid "AI|AI generated explanations will appear here."
msgstr ""
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr ""
+
msgid "AI|Apply AI-generated description"
msgstr ""
+msgid "AI|Ask GitLab Duo"
+msgstr ""
+
msgid "AI|Ask a question"
msgstr ""
msgid "AI|Autocomplete"
msgstr ""
+msgid "AI|Can be removed at any time"
+msgstr ""
+
msgid "AI|Close the Code Explanation"
msgstr ""
@@ -1803,12 +1825,30 @@ msgstr ""
msgid "AI|GitLab Duo"
msgstr ""
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr ""
+
msgid "AI|Helpful"
msgstr ""
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr ""
+msgid "AI|May be unstable"
+msgstr ""
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr ""
@@ -1830,6 +1870,9 @@ msgstr ""
msgid "AI|Something went wrong. Please try again later"
msgstr ""
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr ""
@@ -1845,6 +1888,9 @@ msgstr ""
msgid "AI|Third-party AI services"
msgstr ""
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr ""
@@ -1857,6 +1903,9 @@ msgstr ""
msgid "AI|What does the selected code mean?"
msgstr ""
+msgid "AI|What's an Experiment?"
+msgstr ""
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr ""
@@ -1869,9 +1918,6 @@ msgstr ""
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr ""
-msgid "AI|You can ask AI for more information."
-msgstr ""
-
msgid "AI|finding"
msgstr ""
@@ -2076,9 +2122,6 @@ msgstr ""
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr ""
-msgid "AbuseReport|Abuse reports"
-msgstr ""
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr ""
@@ -2193,6 +2236,9 @@ msgstr ""
msgid "AbuseReport|Other"
msgstr ""
+msgid "AbuseReport|Past abuse reports"
+msgstr ""
+
msgid "AbuseReport|Personal information or credentials"
msgstr ""
@@ -2250,6 +2296,9 @@ msgstr ""
msgid "AbuseReport|View screenshot"
msgstr ""
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr ""
@@ -2301,6 +2350,9 @@ msgstr ""
msgid "AccessDropdown|Roles"
msgstr ""
+msgid "AccessDropdown|Select"
+msgstr ""
+
msgid "AccessDropdown|Users"
msgstr ""
@@ -2481,6 +2533,9 @@ msgstr ""
msgid "Action"
msgstr ""
+msgid "Action '%{action}' in registries is not supported."
+msgstr ""
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr ""
@@ -2793,6 +2848,9 @@ msgstr ""
msgid "Add tag"
msgstr ""
+msgid "Add target branch rule"
+msgstr ""
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr ""
@@ -2817,6 +2875,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add token"
+msgstr ""
+
msgid "Add topics to projects to help users find them."
msgstr ""
@@ -2844,7 +2905,7 @@ msgstr ""
msgid "AddMember|Invite email is invalid"
msgstr ""
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
msgstr ""
msgid "AddMember|Invites cannot be blank"
@@ -3684,7 +3745,7 @@ msgstr ""
msgid "AdminUsers|Bot"
msgstr ""
-msgid "AdminUsers|Can create group"
+msgid "AdminUsers|Can create top level group"
msgstr ""
msgid "AdminUsers|Cannot sign in or access instance information"
@@ -4308,6 +4369,9 @@ msgstr ""
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr ""
+msgid "AlertSettings|Active alerts"
+msgstr ""
+
msgid "AlertSettings|Add new integration"
msgstr ""
@@ -4746,9 +4810,6 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr "é è¦½ blob 檔案時發生錯誤"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr ""
-
msgid "An error occurred when updating the title"
msgstr ""
@@ -4839,6 +4900,9 @@ msgstr ""
msgid "An error occurred while fetching label colors."
msgstr ""
+msgid "An error occurred while fetching labels, please try again."
+msgstr ""
+
msgid "An error occurred while fetching participants"
msgstr ""
@@ -5023,6 +5087,9 @@ msgstr[0] ""
msgid "An error occurred while saving your settings. Try saving them again."
msgstr ""
+msgid "An error occurred while searching for labels, please try again."
+msgstr ""
+
msgid "An error occurred while triggering the job."
msgstr ""
@@ -5038,6 +5105,12 @@ msgstr ""
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr ""
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr ""
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr ""
+
msgid "An error occurred while updating approvers"
msgstr ""
@@ -5147,6 +5220,9 @@ msgstr ""
msgid "Analytics|A visualization with that name already exists."
msgstr ""
+msgid "Analytics|Add a visualization"
+msgstr ""
+
msgid "Analytics|Add visualizations"
msgstr ""
@@ -5192,15 +5268,18 @@ msgstr ""
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr ""
-msgid "Analytics|Custom dashboards"
+msgid "Analytics|Create your dashboard"
msgstr ""
-msgid "Analytics|Dashboard Title"
+msgid "Analytics|Custom dashboards"
msgstr ""
msgid "Analytics|Dashboard not found"
msgstr ""
+msgid "Analytics|Dashboard title"
+msgstr ""
+
msgid "Analytics|Dashboard was saved successfully"
msgstr ""
@@ -5222,6 +5301,12 @@ msgstr ""
msgid "Analytics|Edit"
msgstr ""
+msgid "Analytics|Edit your dashboard"
+msgstr ""
+
+msgid "Analytics|Enter a dashboard title"
+msgstr ""
+
msgid "Analytics|Enter a visualization name"
msgstr ""
@@ -5237,6 +5322,9 @@ msgstr ""
msgid "Analytics|Host"
msgstr ""
+msgid "Analytics|Invalid visualization configuration"
+msgstr ""
+
msgid "Analytics|Language"
msgstr ""
@@ -5279,24 +5367,30 @@ msgstr ""
msgid "Analytics|Resulting Data"
msgstr ""
-msgid "Analytics|Save"
-msgstr ""
-
msgid "Analytics|Save and add to Dashboard"
msgstr ""
msgid "Analytics|Save new visualization"
msgstr ""
+msgid "Analytics|Save your dashboard"
+msgstr ""
+
msgid "Analytics|Select a measurement"
msgstr ""
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr ""
+
msgid "Analytics|Select a visualization type"
msgstr ""
msgid "Analytics|Single Statistic"
msgstr ""
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr ""
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr ""
@@ -6045,9 +6139,6 @@ msgstr ""
msgid "Are you sure you want to delete this label?"
msgstr ""
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "確定è¦åˆªé™¤æ­¤æµæ°´ç·šè¨ˆåŠƒå—Žï¼Ÿ"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr ""
@@ -6127,7 +6218,7 @@ msgstr ""
msgid "Are you sure you want to retry this migration?"
msgstr ""
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this SSH key?"
@@ -6267,6 +6358,9 @@ msgstr ""
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr ""
+msgid "Ask a maintainer to check the import status for more details."
+msgstr ""
+
msgid "Ask again later"
msgstr ""
@@ -6474,6 +6568,9 @@ msgstr ""
msgid "AuditStreams|Active"
msgstr ""
+msgid "AuditStreams|Add a new private key"
+msgstr ""
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr ""
@@ -6591,6 +6688,9 @@ msgstr ""
msgid "AuditStreams|This is great for keeping everything one place."
msgstr ""
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr ""
+
msgid "AuditStreams|Value"
msgstr ""
@@ -7518,7 +7618,7 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list."
msgstr ""
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
msgstr ""
msgid "Billing|An error occurred while loading pending members list"
@@ -7533,15 +7633,18 @@ msgstr ""
msgid "Billing|Cannot remove user"
msgstr ""
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr ""
-
msgid "Billing|Direct memberships"
msgstr ""
msgid "Billing|Enter at least three characters to search."
msgstr ""
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr ""
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr ""
+
msgid "Billing|Explore paid plans"
msgstr ""
@@ -7558,6 +7661,9 @@ msgstr[0] ""
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr ""
+msgid "Billing|No seats available"
+msgstr ""
+
msgid "Billing|No users to display."
msgstr ""
@@ -7570,6 +7676,12 @@ msgstr ""
msgid "Billing|Remove user %{username} from your subscription"
msgstr ""
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr ""
+
msgid "Billing|Subscription end"
msgstr ""
@@ -7597,6 +7709,9 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr ""
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
@@ -7640,6 +7755,9 @@ msgstr[0] ""
msgid "Blocked issue"
msgstr ""
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr ""
+
msgid "Blocking"
msgstr ""
@@ -7673,9 +7791,6 @@ msgstr ""
msgid "BoardNewEpic|Search groups"
msgstr ""
-msgid "BoardNewEpic|Select a group"
-msgstr ""
-
msgid "BoardNewIssue|No matching results"
msgstr ""
@@ -7763,9 +7878,6 @@ msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
-msgid "BoardScope|Select weight"
-msgstr ""
-
msgid "BoardScope|Started"
msgstr ""
@@ -8837,7 +8949,7 @@ msgstr ""
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr ""
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
@@ -8933,7 +9045,7 @@ msgstr ""
msgid "Can be manually deployed to"
msgstr ""
-msgid "Can create groups:"
+msgid "Can create top level groups:"
msgstr ""
msgid "Can not delete primary training"
@@ -9320,6 +9432,9 @@ msgstr ""
msgid "Changes:"
msgstr ""
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr ""
+
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -9410,6 +9525,9 @@ msgstr ""
msgid "Check your sign-up restrictions"
msgstr ""
+msgid "Checkin reminder has been enabled."
+msgstr ""
+
msgid "Checking %{text} availability…"
msgstr ""
@@ -9466,7 +9584,7 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] ""
-msgid "Checkout|%{selectedPlanText} plan"
+msgid "Checkout|%{selectedPlanText}"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr ""
msgid "Choose a type..."
msgstr ""
+msgid "Choose an option"
+msgstr ""
+
msgid "Choose file…"
msgstr ""
@@ -9922,15 +10043,15 @@ msgstr ""
msgid "CiVariables|Cancel"
msgstr ""
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
-
msgid "CiVariables|Delete variable"
msgstr ""
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr ""
+msgid "CiVariables|Edit Variable"
+msgstr ""
+
msgid "CiVariables|Environments"
msgstr ""
@@ -9982,9 +10103,6 @@ msgstr ""
msgid "CiVariables|Remove variable"
msgstr ""
-msgid "CiVariables|Remove variable row"
-msgstr ""
-
msgid "CiVariables|Run job"
msgstr ""
@@ -10006,12 +10124,24 @@ msgstr ""
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr ""
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr ""
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr ""
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr ""
@@ -10027,9 +10157,6 @@ msgstr ""
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr ""
-msgid "CiVariable|* (All environments)"
-msgstr ""
-
msgid "CiVariable|All environments"
msgstr ""
@@ -10187,6 +10314,9 @@ msgstr ""
msgid "Clientside DSN"
msgstr ""
+msgid "Clientside traces sample rate"
+msgstr ""
+
msgid "Clone"
msgstr ""
@@ -10484,15 +10614,9 @@ msgstr ""
msgid "Cluster cache cleared."
msgstr ""
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "Cluster level"
msgstr ""
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr ""
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr ""
@@ -10782,6 +10906,9 @@ msgstr ""
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr ""
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr ""
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr ""
@@ -10806,6 +10933,9 @@ msgstr ""
msgid "ClusterAgents|View all %{number} clusters"
msgstr ""
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr ""
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr ""
@@ -11229,9 +11359,6 @@ msgstr ""
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
-msgid "Code Suggestions add-on"
-msgstr ""
-
msgid "Code Suggestions add-on status"
msgstr ""
@@ -11301,31 +11428,28 @@ msgstr ""
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr ""
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
+msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr ""
-msgid "CodeSuggestionsSM|Personal access token"
+msgid "CodeSuggestions|Code Suggestions"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
msgstr ""
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
+msgid "CodeSuggestions|Enable Code Suggestions"
msgstr ""
-msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
msgstr ""
-msgid "CodeSuggestions|Code Suggestions"
+msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr ""
-msgid "CodeSuggestions|Enable Code Suggestions"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
msgstr ""
-msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
msgstr ""
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
@@ -11395,6 +11519,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse AI-generated summary"
+msgstr ""
+
msgid "Collapse all threads"
msgstr ""
@@ -11753,9 +11880,6 @@ msgstr ""
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr ""
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr ""
-
msgid "CompareRevisions|View open merge request"
msgstr ""
@@ -11801,6 +11925,9 @@ msgstr ""
msgid "Compliance framework"
msgstr ""
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr ""
+
msgid "ComplianceFrameworks|Add framework"
msgstr ""
@@ -11858,7 +11985,7 @@ msgstr ""
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr ""
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
msgstr ""
msgid "ComplianceFrameworks|Invalid format"
@@ -12074,15 +12201,18 @@ msgstr "隱密的"
msgid "Configuration help"
msgstr ""
-msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
+msgid "Configure"
msgstr ""
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
+msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr ""
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr ""
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr ""
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr ""
@@ -12146,6 +12276,9 @@ msgstr ""
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr ""
+msgid "Configure checkin reminder frequency"
+msgstr ""
+
msgid "Configure custom rules for Jira issue key matching"
msgstr ""
@@ -12317,6 +12450,9 @@ msgstr ""
msgid "Consistency guarantee method"
msgstr ""
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr ""
@@ -12836,6 +12972,9 @@ msgstr ""
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr ""
@@ -12869,6 +13008,30 @@ msgstr ""
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr ""
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr ""
@@ -12881,9 +13044,18 @@ msgstr ""
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Deleted resource."
+msgstr ""
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr ""
@@ -12971,6 +13143,15 @@ msgstr ""
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
msgstr ""
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
+msgid "ContributionEvent|Updated resource."
+msgstr ""
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr ""
+
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr ""
@@ -13517,6 +13698,9 @@ msgstr ""
msgid "Create requirement"
msgstr ""
+msgid "Create rules for target branches in merge requests."
+msgstr ""
+
msgid "Create service account"
msgstr ""
@@ -13895,9 +14079,6 @@ msgstr ""
msgid "Crm|Organization has been updated."
msgstr ""
-msgid "Cron Timezone"
-msgstr "Cron 時å€"
-
msgid "Cron time zone"
msgstr ""
@@ -14235,9 +14416,6 @@ msgstr ""
msgid "CycleAnalytics|Total time"
msgstr ""
-msgid "CycleAnalytics|group dropdown filter"
-msgstr ""
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr ""
@@ -14411,6 +14589,9 @@ msgstr ""
msgid "DORA4Metrics|Merge request throughput"
msgstr ""
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr ""
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr ""
@@ -14501,6 +14682,9 @@ msgstr ""
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr ""
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr ""
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr ""
@@ -14723,6 +14907,9 @@ msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr ""
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr ""
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr ""
@@ -15226,9 +15413,6 @@ msgstr "使用 Cron 語法定義自定義模å¼"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr ""
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr ""
-
msgid "Define how approval rules are applied to merge requests."
msgstr ""
@@ -15350,9 +15534,6 @@ msgstr ""
msgid "Delete pipeline"
msgstr ""
-msgid "Delete pipeline schedule"
-msgstr ""
-
msgid "Delete project"
msgstr ""
@@ -15568,6 +15749,9 @@ msgstr ""
msgid "Dependencies|Packager"
msgstr ""
+msgid "Dependencies|Project list unavailable"
+msgstr ""
+
msgid "Dependencies|Projects"
msgstr ""
@@ -15586,6 +15770,9 @@ msgstr ""
msgid "Dependencies|There may be multiple paths"
msgstr ""
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr ""
+
msgid "Dependencies|Toggle vulnerability list"
msgstr ""
@@ -15766,6 +15953,12 @@ msgstr ""
msgid "DeployKeys|+%{count} others"
msgstr ""
+msgid "DeployKeys|Add new deploy key"
+msgstr ""
+
+msgid "DeployKeys|Add new key"
+msgstr ""
+
msgid "DeployKeys|Current project"
msgstr ""
@@ -15793,7 +15986,7 @@ msgstr ""
msgid "DeployKeys|Loading deploy keys"
msgstr ""
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
msgstr ""
msgid "DeployKeys|Privately accessible deploy keys"
@@ -15808,7 +16001,7 @@ msgstr ""
msgid "DeployKeys|Read access only"
msgstr ""
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
msgstr ""
msgid "DeployTokens|Allows read and write access to registry images."
@@ -15832,6 +16025,9 @@ msgstr ""
msgid "DeployTokens|Allows write access to registry images."
msgstr ""
+msgid "DeployTokens|Cancel"
+msgstr ""
+
msgid "DeployTokens|Copy deploy token"
msgstr ""
@@ -15892,7 +16088,7 @@ msgstr ""
msgid "DeployTokens|Scopes (select at least one)"
msgstr ""
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
@@ -15910,10 +16106,10 @@ msgstr ""
msgid "DeployTokens|Username (optional)"
msgstr ""
-msgid "DeployTokens|Your New Deploy Token"
+msgid "DeployTokens|Your new Deploy Token username"
msgstr ""
-msgid "DeployTokens|Your new Deploy Token username"
+msgid "DeployTokens|Your new deploy token"
msgstr ""
msgid "DeployTokens|Your new group deploy token has been created."
@@ -15997,6 +16193,12 @@ msgstr ""
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr ""
+msgid "DeploymentApproval|Deployment approved"
+msgstr ""
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr ""
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr ""
@@ -16067,9 +16269,6 @@ msgstr ""
msgid "Deployments|You don't have any deployments right now."
msgstr ""
-msgid "Deployment|API"
-msgstr ""
-
msgid "Deployment|Cancelled"
msgstr ""
@@ -16082,6 +16281,24 @@ msgstr ""
msgid "Deployment|Failed"
msgstr ""
+msgid "Deployment|Flux sync failed"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr ""
+
+msgid "Deployment|Flux sync reconciling"
+msgstr ""
+
+msgid "Deployment|Flux sync stalled"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr ""
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr ""
+
msgid "Deployment|Latest Deployed"
msgstr ""
@@ -16097,12 +16314,15 @@ msgstr ""
msgid "Deployment|Success"
msgstr ""
-msgid "Deployment|This deployment was created using the API"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
msgstr ""
msgid "Deployment|Triggerer"
msgstr ""
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr ""
+
msgid "Deployment|Unavailable"
msgstr ""
@@ -16172,12 +16392,6 @@ msgstr ""
msgid "Design Management files and data"
msgstr ""
-msgid "Design repositories"
-msgstr ""
-
-msgid "Design repository"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -17366,9 +17580,6 @@ msgstr ""
msgid "Email the pipeline status to a list of recipients."
msgstr ""
-msgid "Email updates (optional)"
-msgstr ""
-
msgid "Email:"
msgstr ""
@@ -17411,6 +17622,9 @@ msgstr ""
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr ""
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr ""
+
msgid "Emails"
msgstr ""
@@ -17549,9 +17763,6 @@ msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
-msgid "Enable in-product marketing emails"
-msgstr ""
-
msgid "Enable incident management inbound alert limit"
msgstr ""
@@ -17573,7 +17784,7 @@ msgstr ""
msgid "Enable or disable version check and Service Ping."
msgstr ""
-msgid "Enable rate limiting for POST requests to the specified paths"
+msgid "Enable rate limiting for requests to the specified paths"
msgstr ""
msgid "Enable reCAPTCHA"
@@ -17687,9 +17898,6 @@ msgstr ""
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr ""
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr ""
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr ""
@@ -17801,7 +18009,7 @@ msgstr ""
msgid "Environment scope"
msgstr ""
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
msgstr ""
msgid "Environment:"
@@ -17948,12 +18156,18 @@ msgstr ""
msgid "Environments|GitLab agent"
msgstr ""
+msgid "Environments|HelmReleases"
+msgstr ""
+
msgid "Environments|Job"
msgstr ""
msgid "Environments|Kubernetes namespace (optional)"
msgstr ""
+msgid "Environments|Kustomizations"
+msgstr ""
+
msgid "Environments|Learn more about stopping environments"
msgstr ""
@@ -17999,6 +18213,12 @@ msgstr ""
msgid "Environments|Search by environment name"
msgstr ""
+msgid "Environments|Select Flux resource"
+msgstr ""
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr ""
+
msgid "Environments|Select agent"
msgstr ""
@@ -18035,6 +18255,9 @@ msgstr ""
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr ""
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr ""
+
msgid "Environments|Upcoming"
msgstr ""
@@ -18137,6 +18360,12 @@ msgstr ""
msgid "Environment|There was an error connecting to the cluster agent."
msgstr ""
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr ""
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr ""
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr ""
@@ -18891,6 +19120,9 @@ msgstr ""
msgid "Expand"
msgstr ""
+msgid "Expand AI-generated summary"
+msgstr ""
+
msgid "Expand all"
msgstr ""
@@ -19137,6 +19369,9 @@ msgstr ""
msgid "Facebook"
msgstr ""
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr ""
@@ -19791,9 +20026,6 @@ msgstr ""
msgid "Filter by test cases that are currently open."
msgstr ""
-msgid "Filter by user"
-msgstr ""
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
@@ -19818,9 +20050,6 @@ msgstr ""
msgid "Filter users"
msgstr ""
-msgid "Filter..."
-msgstr ""
-
msgid "Finalizing"
msgstr ""
@@ -20188,33 +20417,6 @@ msgstr ""
msgid "Free trial will expire in %{days}"
msgstr ""
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr ""
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr ""
-
-msgid "FreeUserCap|Manage members"
-msgstr ""
-
-msgid "FreeUserCap|Manage members:"
-msgstr ""
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr ""
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
-
msgid "Freeze end"
msgstr ""
@@ -20907,6 +21109,12 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
+msgid "Get free trial"
+msgstr ""
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr ""
+
msgid "Get started"
msgstr ""
@@ -21234,6 +21442,9 @@ msgstr ""
msgid "GitLabPages|Updating your Pages configuration..."
msgstr ""
+msgid "GitLabPages|Use multiple versions"
+msgstr ""
+
msgid "GitLabPages|Use unique domain"
msgstr ""
@@ -21249,6 +21460,9 @@ msgstr ""
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr ""
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr ""
@@ -21264,12 +21478,6 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
-msgid "Gitaly relative path:"
-msgstr ""
-
-msgid "Gitaly storage name:"
-msgstr ""
-
msgid "Gitaly timeouts"
msgstr ""
@@ -21390,7 +21598,7 @@ msgstr ""
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr ""
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
msgstr ""
msgid "Gitpod|https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr ""
+
msgid "Global SAML group membership lock"
msgstr ""
@@ -21429,6 +21640,9 @@ msgstr ""
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr ""
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr ""
+
msgid "GlobalSearch|Aggregations load error."
msgstr ""
@@ -21441,6 +21655,9 @@ msgstr ""
msgid "GlobalSearch|Fetching aggregations error."
msgstr ""
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr ""
@@ -21510,9 +21727,6 @@ msgstr ""
msgid "GlobalSearch|Search GitLab"
msgstr ""
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr ""
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr ""
@@ -21543,6 +21757,9 @@ msgstr ""
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr ""
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr ""
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr ""
@@ -21783,6 +22000,12 @@ msgstr ""
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr ""
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr ""
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr ""
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
@@ -21798,7 +22021,7 @@ msgstr ""
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr ""
-msgid "GooglePlay|Service account key (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
msgstr ""
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr ""
msgid "Group by"
msgstr ""
+msgid "Group by:"
+msgstr ""
+
msgid "Group description (optional)"
msgstr ""
@@ -21975,9 +22201,6 @@ msgstr ""
msgid "Group navigation"
msgstr ""
-msgid "Group overview"
-msgstr ""
-
msgid "Group overview content"
msgstr ""
@@ -22353,7 +22576,7 @@ msgstr ""
msgid "GroupSettings|Compliance frameworks"
msgstr ""
-msgid "GroupSettings|Configure analytics features for this group"
+msgid "GroupSettings|Configure analytics features for this group."
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
@@ -22542,7 +22765,7 @@ msgstr ""
msgid "GroupsDropdown|Toggle edit mode"
msgstr ""
-msgid "GroupsEmptyState|A group is a collection of several projects."
+msgid "GroupsEmptyState|A group is a collection of several projects"
msgstr ""
msgid "GroupsEmptyState|Create new project"
@@ -22554,7 +22777,7 @@ msgstr ""
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr ""
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
msgstr ""
msgid "GroupsEmptyState|No archived projects."
@@ -22572,9 +22795,6 @@ msgstr ""
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr ""
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr ""
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
@@ -22994,6 +23214,9 @@ msgstr ""
msgid "Help translate to your language"
msgstr ""
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr ""
@@ -23256,9 +23479,6 @@ msgstr ""
msgid "I want to use GitLab CI with my existing repository"
msgstr ""
-msgid "I'd like to receive updates about GitLab via email"
-msgstr ""
-
msgid "I'm signing up for GitLab because:"
msgstr ""
@@ -23298,6 +23518,12 @@ msgstr ""
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr ""
+msgid "IDs with errors: %{error_messages}."
+msgstr ""
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr ""
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr ""
@@ -23481,6 +23707,12 @@ msgstr ""
msgid "IdentityVerification|Verify phone number"
msgstr ""
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr ""
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr ""
+
msgid "IdentityVerification|Verify your identity"
msgstr ""
@@ -23889,7 +24121,7 @@ msgstr ""
msgid "Import|GitHub import details"
msgstr ""
-msgid "Import|Maximum decompressed size (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
msgstr ""
msgid "Import|Maximum import remote file size (MB)"
@@ -23916,6 +24148,12 @@ msgstr ""
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr ""
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr ""
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr ""
+
msgid "Improve customer support with Service Desk"
msgstr ""
@@ -23958,381 +24196,72 @@ msgstr ""
msgid "InProductMarketing|%{organization_name} logo"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr ""
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr ""
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr ""
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr ""
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr ""
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr ""
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr ""
-
msgid "InProductMarketing|Advanced security testing"
msgstr ""
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr ""
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr ""
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr ""
-
-msgid "InProductMarketing|Beef up your security"
-msgstr ""
-
-msgid "InProductMarketing|Better code in less time"
-msgstr ""
-
msgid "InProductMarketing|Blog"
msgstr ""
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr ""
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr ""
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr ""
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr ""
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
-
-msgid "InProductMarketing|Create your first project!"
-msgstr ""
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr ""
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr ""
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr ""
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr ""
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr ""
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Explore the options"
-msgstr ""
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr ""
-
msgid "InProductMarketing|Facebook"
msgstr ""
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr ""
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr ""
-
-msgid "InProductMarketing|Follow our steps"
-msgstr ""
-
msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Free guest users"
msgstr ""
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr ""
-
-msgid "InProductMarketing|Get our import guides"
-msgstr ""
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr ""
-msgid "InProductMarketing|Get started today"
-msgstr ""
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr ""
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Git basics"
-msgstr ""
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr ""
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr ""
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr ""
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr ""
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr ""
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr ""
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr ""
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr ""
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr ""
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr ""
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr ""
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr ""
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr ""
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr ""
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr ""
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr ""
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr ""
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr ""
-msgid "InProductMarketing|Invite them to help out."
-msgstr ""
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr ""
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr ""
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team now"
-msgstr ""
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr ""
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr ""
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr ""
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr ""
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr ""
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr ""
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr ""
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr ""
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr ""
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
-
msgid "InProductMarketing|No credit card required."
msgstr ""
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr ""
-
msgid "InProductMarketing|Portfolio management"
msgstr ""
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr ""
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr ""
msgid "InProductMarketing|Security risk mitigation"
msgstr ""
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr ""
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr ""
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr ""
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr ""
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr ""
-
-msgid "InProductMarketing|Start a trial"
-msgstr ""
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr ""
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr ""
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr ""
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr ""
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr ""
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr ""
-
msgid "InProductMarketing|Team members collaborating"
msgstr ""
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr ""
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr ""
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr ""
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr ""
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr ""
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr ""
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr ""
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr ""
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr ""
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr ""
-
-msgid "InProductMarketing|Try it out"
-msgstr ""
-
-msgid "InProductMarketing|Try it yourself"
-msgstr ""
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr ""
-
msgid "InProductMarketing|Twitter"
msgstr ""
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|Understand your project options"
-msgstr ""
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr ""
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr ""
@@ -24348,66 +24277,15 @@ msgstr ""
msgid "InProductMarketing|Watch iOS building in action."
msgstr ""
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr ""
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr ""
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr ""
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr ""
-
msgid "InProductMarketing|YouTube"
msgstr ""
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr ""
-
-msgid "InProductMarketing|connect an external repository"
-msgstr ""
-
-msgid "InProductMarketing|create a project"
-msgstr ""
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr ""
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr ""
-msgid "InProductMarketing|how easy it is to get started"
-msgstr ""
-
-msgid "InProductMarketing|quick start guide"
-msgstr ""
-
-msgid "InProductMarketing|repository mirroring"
-msgstr ""
-
-msgid "InProductMarketing|set up a repo"
-msgstr ""
-
-msgid "InProductMarketing|test and deploy"
-msgstr ""
-
-msgid "InProductMarketing|testing browser performance"
-msgstr ""
-
msgid "InProductMarketing|unsubscribe"
msgstr ""
-msgid "InProductMarketing|update your preferences"
-msgstr ""
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr ""
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr ""
@@ -24837,6 +24715,14 @@ msgstr ""
msgid "Inline math"
msgstr ""
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] ""
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] ""
+
msgid "Input host keys manually"
msgstr ""
@@ -25192,6 +25078,9 @@ msgstr ""
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr ""
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr ""
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr ""
@@ -25228,15 +25117,9 @@ msgstr ""
msgid "Interval"
msgstr ""
-msgid "Interval Pattern"
-msgstr "循環週期"
-
msgid "Introducing Your DevOps Reports"
msgstr ""
-msgid "Introducing the Code Suggestions add-on"
-msgstr ""
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr ""
@@ -25318,9 +25201,6 @@ msgstr ""
msgid "Invalid two-factor code."
msgstr ""
-msgid "Invalid yaml"
-msgstr ""
-
msgid "Invalidated"
msgstr ""
@@ -25652,18 +25532,12 @@ msgstr ""
msgid "IssuableEvents|unassigned"
msgstr ""
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr ""
-
msgid "IssuableStatus|Closed"
msgstr ""
msgid "IssuableStatus|Closed (%{link})"
msgstr ""
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
-
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -25913,10 +25787,22 @@ msgstr ""
msgid "Issues, merge requests, pushes, and comments."
msgstr "è­°é¡Œã€åˆä½µè«‹æ±‚ã€æŽ¨é€åŠç•™è¨€ã€‚"
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
+msgid "IssuesAnalytics|Avg/Month:"
msgstr ""
-msgid "IssuesAnalytics|Avg/Month:"
+msgid "IssuesAnalytics|Closed"
+msgstr ""
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr ""
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr ""
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr ""
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
msgstr ""
msgid "IssuesAnalytics|Issues created"
@@ -25925,16 +25811,23 @@ msgstr ""
msgid "IssuesAnalytics|Issues created per month"
msgstr ""
-msgid "IssuesAnalytics|Last 12 months"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
msgstr ""
-msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgid "IssuesAnalytics|Opened"
msgstr ""
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
+msgid "IssuesAnalytics|Overview"
msgstr ""
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
+msgid "IssuesAnalytics|Sorry, your filter produced no results"
+msgstr ""
+
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] ""
+
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
msgstr ""
msgid "IssuesAnalytics|Total:"
@@ -25982,6 +25875,9 @@ msgstr ""
msgid "Italic text"
msgstr ""
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr ""
+
msgid "Iteration"
msgstr ""
@@ -26318,6 +26214,9 @@ msgstr ""
msgid "JiraConnect|No linked groups"
msgstr ""
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr ""
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr ""
@@ -26816,6 +26715,9 @@ msgstr ""
msgid "Job|Erase job log and artifacts"
msgstr ""
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr ""
@@ -26867,6 +26769,9 @@ msgstr ""
msgid "Job|Run again"
msgstr ""
+msgid "Job|Runner type"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -26963,9 +26868,6 @@ msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
-msgid "Joined %{time_ago}"
-msgstr ""
-
msgid "Joined %{user_created_time}"
msgstr ""
@@ -27226,9 +27128,6 @@ msgstr ""
msgid "Last Name"
msgstr ""
-msgid "Last Pipeline"
-msgstr "最新æµæ°´ç·š"
-
msgid "Last Seen"
msgstr ""
@@ -27325,6 +27224,9 @@ msgstr "您推é€äº†"
msgid "LastPushEvent|at"
msgstr "在"
+msgid "Latest AI-generated summary"
+msgstr ""
+
msgid "Latest changes"
msgstr ""
@@ -28019,6 +27921,9 @@ msgstr ""
msgid "Lock File?"
msgstr ""
+msgid "Lock label after a merge request is merged"
+msgstr ""
+
msgid "Lock memberships to LDAP synchronization"
msgstr ""
@@ -28028,6 +27933,9 @@ msgstr ""
msgid "Lock not found"
msgstr ""
+msgid "Lock on merge"
+msgstr ""
+
msgid "Lock status"
msgstr ""
@@ -28433,6 +28341,12 @@ msgstr ""
msgid "Mattermost notifications"
msgstr ""
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr ""
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr ""
+
msgid "MattermostService|Add to Mattermost"
msgstr ""
@@ -28448,6 +28362,9 @@ msgstr ""
msgid "MattermostService|Install"
msgstr ""
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr ""
+
msgid "MattermostService|Request URL"
msgstr ""
@@ -28460,6 +28377,9 @@ msgstr ""
msgid "MattermostService|Response username"
msgstr ""
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr ""
+
msgid "MattermostService|Suggestions:"
msgstr ""
@@ -28766,6 +28686,102 @@ msgstr ""
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr ""
+msgid "MemberRoles|Actions"
+msgstr ""
+
+msgid "MemberRoles|Add new role"
+msgstr ""
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr ""
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr ""
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr ""
+
+msgid "MemberRoles|Base role"
+msgstr ""
+
+msgid "MemberRoles|Base role to use as template"
+msgstr ""
+
+msgid "MemberRoles|Create new role"
+msgstr ""
+
+msgid "MemberRoles|Custom roles"
+msgstr ""
+
+msgid "MemberRoles|Delete role"
+msgstr ""
+
+msgid "MemberRoles|Description"
+msgstr ""
+
+msgid "MemberRoles|Enter a short name."
+msgstr ""
+
+msgid "MemberRoles|Failed to create role."
+msgstr ""
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr ""
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr ""
+
+msgid "MemberRoles|ID"
+msgstr ""
+
+msgid "MemberRoles|Incident manager"
+msgstr ""
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr ""
+
+msgid "MemberRoles|Name"
+msgstr ""
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr ""
+
+msgid "MemberRoles|Permissions"
+msgstr ""
+
+msgid "MemberRoles|Read code"
+msgstr ""
+
+msgid "MemberRoles|Read vulnerability"
+msgstr ""
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr ""
+
+msgid "MemberRoles|Role name"
+msgstr ""
+
+msgid "MemberRoles|Role successfully created."
+msgstr ""
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr ""
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr ""
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr ""
@@ -29021,6 +29037,9 @@ msgstr ""
msgid "Merge conflicts"
msgstr ""
+msgid "Merge date & time could not be determined"
+msgstr ""
+
msgid "Merge details"
msgstr ""
@@ -29453,9 +29472,6 @@ msgstr ""
msgid "Metrics:"
msgstr ""
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr ""
-
msgid "Metrics|Create metric"
msgstr ""
@@ -29552,6 +29568,9 @@ msgstr ""
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr ""
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr ""
+
msgid "Microsoft|Tenant ID"
msgstr ""
@@ -30430,10 +30449,10 @@ msgstr ""
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
msgstr ""
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr ""
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
@@ -30511,6 +30530,9 @@ msgstr ""
msgid "Navigation|Build"
msgstr ""
+msgid "Navigation|CI/CD settings"
+msgstr ""
+
msgid "Navigation|Code"
msgstr ""
@@ -30541,15 +30563,18 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
-msgid "Navigation|Main navigation"
+msgid "Navigation|Manage"
msgstr ""
-msgid "Navigation|Manage"
+msgid "Navigation|Merge requests settings"
msgstr ""
msgid "Navigation|Monitor"
msgstr ""
+msgid "Navigation|Monitor settings"
+msgstr ""
+
msgid "Navigation|No group matches found"
msgstr ""
@@ -30568,12 +30593,18 @@ msgstr ""
msgid "Navigation|Plan"
msgstr ""
+msgid "Navigation|Primary"
+msgstr ""
+
msgid "Navigation|Projects"
msgstr ""
msgid "Navigation|Projects you visit often will appear here."
msgstr ""
+msgid "Navigation|Repository settings"
+msgstr ""
+
msgid "Navigation|Retrieving search results"
msgstr ""
@@ -30592,6 +30623,12 @@ msgstr ""
msgid "Navigation|Unpin item"
msgstr ""
+msgid "Navigation|View all my groups"
+msgstr ""
+
+msgid "Navigation|View all my projects"
+msgstr ""
+
msgid "Navigation|View all your groups"
msgstr ""
@@ -30815,9 +30852,6 @@ msgstr ""
msgid "New runners registration token has been generated!"
msgstr ""
-msgid "New schedule"
-msgstr "新增计划"
-
msgid "New snippet"
msgstr "新代碼片段"
@@ -31025,6 +31059,9 @@ msgstr ""
msgid "No label"
msgstr ""
+msgid "No labels found"
+msgstr ""
+
msgid "No labels with such name or description"
msgstr ""
@@ -31049,6 +31086,12 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No matching work item found."
+msgstr ""
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr ""
+
msgid "No members found"
msgstr ""
@@ -31067,10 +31110,13 @@ msgstr ""
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr ""
-msgid "No other labels with such name or description"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
msgstr ""
-msgid "No panels matching properties %{opts}"
+msgid "No options found"
+msgstr ""
+
+msgid "No other labels with such name or description"
msgstr ""
msgid "No parent group"
@@ -31127,9 +31173,6 @@ msgstr ""
msgid "No runner executable"
msgstr ""
-msgid "No schedules"
-msgstr "沒有計劃"
-
msgid "No service accounts"
msgstr ""
@@ -31181,6 +31224,12 @@ msgstr ""
msgid "No webhooks enabled. Select trigger events above."
msgstr ""
+msgid "No work item IDs provided."
+msgstr ""
+
+msgid "No work item found."
+msgstr ""
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] ""
@@ -32379,6 +32428,9 @@ msgstr ""
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr ""
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr ""
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr ""
@@ -32406,9 +32458,6 @@ msgstr ""
msgid "Only active projects show up in the search and on the dashboard."
msgstr ""
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
-
msgid "Only include features new to your current subscription tier."
msgstr ""
@@ -32571,24 +32620,60 @@ msgstr "æ“作"
msgid "Ordered list"
msgstr ""
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr ""
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr ""
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
+msgid "Organization|Copy organization ID"
+msgstr ""
+
+msgid "Organization|Frequently visited groups"
+msgstr ""
+
+msgid "Organization|Frequently visited projects"
+msgstr ""
+
+msgid "Organization|New organization"
+msgstr ""
+
+msgid "Organization|Org ID"
+msgstr ""
+
msgid "Organization|Organization navigation"
msgstr ""
msgid "Organization|Organization overview"
msgstr ""
+msgid "Organization|Organizations"
+msgstr ""
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr ""
+
msgid "Organization|Search or filter list"
msgstr ""
+msgid "Organization|View all"
+msgstr ""
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr ""
@@ -33301,6 +33386,9 @@ msgstr ""
msgid "Pages Domain"
msgstr ""
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr ""
+
msgid "Pagination|First"
msgstr ""
@@ -33448,7 +33536,10 @@ msgstr ""
msgid "Path:"
msgstr ""
-msgid "Paths to protect with rate limiting"
+msgid "Paths with rate limiting for GET requests"
+msgstr ""
+
+msgid "Paths with rate limiting for POST requests"
msgstr ""
msgid "Pause"
@@ -33895,9 +33986,6 @@ msgstr ""
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr ""
-msgid "PipelineSchedules|Activated"
-msgstr "是å¦å•Ÿç”¨"
-
msgid "PipelineSchedules|Active"
msgstr "已啟用"
@@ -34012,12 +34100,6 @@ msgstr ""
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
-msgid "PipelineSchedules|Variables"
-msgstr "變é‡"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr ""
-
msgid "PipelineSource|API"
msgstr ""
@@ -34468,6 +34550,9 @@ msgstr ""
msgid "Pipeline|Created"
msgstr ""
+msgid "Pipeline|Created by"
+msgstr ""
+
msgid "Pipeline|Creating pipeline."
msgstr ""
@@ -34591,9 +34676,6 @@ msgstr ""
msgid "Pipeline|Trigger author"
msgstr ""
-msgid "Pipeline|Triggerer"
-msgstr ""
-
msgid "Pipeline|Variables"
msgstr ""
@@ -35116,9 +35198,6 @@ msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr ""
-
msgid "Preferences|Preview"
msgstr ""
@@ -35230,6 +35309,9 @@ msgstr ""
msgid "Primary Action"
msgstr ""
+msgid "Primary navigation sidebar"
+msgstr ""
+
msgid "Print as PDF"
msgstr ""
@@ -35353,9 +35435,6 @@ msgstr ""
msgid "ProductAnalytics|Click Events"
msgstr ""
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr ""
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr ""
@@ -35371,9 +35450,6 @@ msgstr ""
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr ""
-msgid "ProductAnalytics|Connection string"
-msgstr ""
-
msgid "ProductAnalytics|Create a visualization"
msgstr ""
@@ -35410,9 +35486,6 @@ msgstr ""
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr ""
-msgid "ProductAnalytics|Go back"
-msgstr ""
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr ""
@@ -35473,6 +35546,9 @@ msgstr ""
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr ""
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr ""
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr ""
@@ -35497,9 +35573,6 @@ msgstr ""
msgid "ProductAnalytics|Unique Users"
msgstr ""
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr ""
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr ""
@@ -35731,7 +35804,7 @@ msgstr ""
msgid "Profiles|Edit Profile"
msgstr ""
-msgid "Profiles|Email"
+msgid "Profiles|Email address"
msgstr ""
msgid "Profiles|Email addresses"
@@ -36166,9 +36239,6 @@ msgstr ""
msgid "Project order will not be saved as local storage is not available."
msgstr ""
-msgid "Project overview"
-msgstr ""
-
msgid "Project path"
msgstr ""
@@ -36658,6 +36728,12 @@ msgstr ""
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr ""
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr ""
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr ""
+
msgid "ProjectSettings|Forks"
msgstr ""
@@ -36793,6 +36869,9 @@ msgstr ""
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr ""
+msgid "ProjectSettings|Relative path:"
+msgstr ""
+
msgid "ProjectSettings|Releases"
msgstr ""
@@ -36865,6 +36944,9 @@ msgstr ""
msgid "ProjectSettings|Status checks must succeed"
msgstr ""
+msgid "ProjectSettings|Storage name:"
+msgstr ""
+
msgid "ProjectSettings|Store custom configuration files."
msgstr ""
@@ -37684,6 +37766,12 @@ msgstr ""
msgid "ProtectedBranch|Create wildcard"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr ""
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr ""
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr ""
@@ -37756,7 +37844,7 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
+msgid "ProtectedBranch|What are the security implications?"
msgstr ""
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
@@ -37809,10 +37897,13 @@ msgstr ""
msgid "ProtectedEnvironments|Edit"
msgstr ""
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
+msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr ""
-msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr ""
+
+msgid "ProtectedEnvironments|Protected environments"
msgstr ""
msgid "ProtectedEnvironments|Remove approval rule"
@@ -37824,6 +37915,9 @@ msgstr ""
msgid "ProtectedEnvironments|Save"
msgstr ""
+msgid "ProtectedEnvironments|Select users"
+msgstr ""
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr ""
@@ -37842,6 +37936,9 @@ msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr ""
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr ""
@@ -37899,9 +37996,6 @@ msgstr ""
msgid "ProtectedEnvironment|Select groups"
msgstr ""
-msgid "ProtectedEnvironment|Select users"
-msgstr ""
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr ""
@@ -37968,9 +38062,6 @@ msgstr ""
msgid "Provisioned by:"
msgstr ""
-msgid "Proxy support for this API is not available currently"
-msgstr ""
-
msgid "Public"
msgstr ""
@@ -38331,9 +38422,6 @@ msgstr ""
msgid "Receive notifications about your own activity"
msgstr ""
-msgid "Receive product marketing emails"
-msgstr ""
-
msgid "Recent"
msgstr ""
@@ -38473,34 +38561,10 @@ msgstr ""
msgid "RegistrationFeatures|use this feature"
msgstr ""
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr ""
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr ""
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr ""
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
+msgid "Registries enqueued to be resynced"
msgstr ""
-msgid "RegistrationVerification|Skip this for now"
-msgstr ""
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr ""
-
-msgid "RegistrationVerification|Validate account"
-msgstr ""
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr ""
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr ""
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
+msgid "Registries enqueued to be reverified"
msgstr ""
msgid "Registry entry enqueued to be resynced"
@@ -38834,9 +38898,6 @@ msgstr ""
msgid "Remove priority"
msgstr ""
-msgid "Remove report"
-msgstr ""
-
msgid "Remove reviewer"
msgstr ""
@@ -38849,6 +38910,9 @@ msgstr ""
msgid "Remove spent time"
msgstr ""
+msgid "Remove summary"
+msgstr ""
+
msgid "Remove time estimate"
msgstr ""
@@ -38858,9 +38922,6 @@ msgstr ""
msgid "Remove user"
msgstr ""
-msgid "Remove user & report"
-msgstr ""
-
msgid "Remove user from group"
msgstr ""
@@ -39140,12 +39201,6 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
-msgid "Reported by"
-msgstr ""
-
-msgid "Reported by %{reporter}"
-msgstr ""
-
msgid "Reporter"
msgstr ""
@@ -39446,9 +39501,6 @@ msgstr ""
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr ""
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
-
msgid "Request"
msgstr ""
@@ -39858,6 +39910,9 @@ msgstr ""
msgid "Ruby"
msgstr ""
+msgid "Rule name"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -40283,6 +40338,9 @@ msgstr ""
msgid "Runners|Minor version upgrades are available."
msgstr ""
+msgid "Runners|Most recent failures"
+msgstr ""
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr ""
@@ -40567,7 +40625,7 @@ msgstr ""
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr ""
-msgid "Runners|Shared runners are disabled in the group settings"
+msgid "Runners|Shared runners are disabled in the group settings."
msgstr ""
msgid "Runners|Shared runners are disabled."
@@ -40649,6 +40707,9 @@ msgstr ""
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr ""
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr ""
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr ""
@@ -40857,6 +40918,9 @@ msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
+msgid "SBOMs last updated"
+msgstr ""
+
msgid "SCIM|SCIM Token"
msgstr ""
@@ -40965,9 +41029,6 @@ msgstr ""
msgid "Save password"
msgstr ""
-msgid "Save pipeline schedule"
-msgstr "ä¿å­˜æµæ°´ç·šè¨ˆåŠƒ"
-
msgid "Saving"
msgstr ""
@@ -40980,7 +41041,7 @@ msgstr ""
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr ""
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
msgstr ""
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
@@ -41106,10 +41167,13 @@ msgstr ""
msgid "ScanResultPolicy|Age is:"
msgstr ""
-msgid "ScanResultPolicy|Block users from unprotecting branches"
+msgid "ScanResultPolicy|Attribute is:"
msgstr ""
-msgid "ScanResultPolicy|Choose an option"
+msgid "ScanResultPolicy|Attribute:"
+msgstr ""
+
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
msgstr ""
msgid "ScanResultPolicy|Choose criteria type"
@@ -41124,6 +41188,24 @@ msgstr ""
msgid "ScanResultPolicy|Except"
msgstr ""
+msgid "ScanResultPolicy|False positive"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available"
+msgstr ""
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr ""
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr ""
+
+msgid "ScanResultPolicy|Is"
+msgstr ""
+
+msgid "ScanResultPolicy|Is not"
+msgstr ""
+
msgid "ScanResultPolicy|License is:"
msgstr ""
@@ -41136,7 +41218,7 @@ msgstr ""
msgid "ScanResultPolicy|New age"
msgstr ""
-msgid "ScanResultPolicy|New severity"
+msgid "ScanResultPolicy|New attribute"
msgstr ""
msgid "ScanResultPolicy|New status"
@@ -41148,7 +41230,7 @@ msgstr ""
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr ""
-msgid "ScanResultPolicy|Only 1 severity is allowed"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
msgstr ""
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
@@ -41160,6 +41242,12 @@ msgstr ""
msgid "ScanResultPolicy|Pre-existing"
msgstr ""
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr ""
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr ""
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr ""
@@ -41187,9 +41275,18 @@ msgstr ""
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr ""
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr ""
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr ""
+msgid "ScanResultPolicy|any commits"
+msgstr ""
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr ""
+
msgid "ScanResultPolicy|license status"
msgstr ""
@@ -41301,6 +41398,9 @@ msgstr ""
msgid "Search an environment spec"
msgstr ""
+msgid "Search artifacts"
+msgstr ""
+
msgid "Search assignees"
msgstr ""
@@ -41370,13 +41470,10 @@ msgstr "æœå°‹é‡Œç¨‹ç¢‘"
msgid "Search or filter commits"
msgstr ""
-msgid "Search or filter results"
-msgstr ""
-
-msgid "Search or filter results..."
+msgid "Search or filter results…"
msgstr ""
-msgid "Search or filter results…"
+msgid "Search or go to…"
msgstr ""
msgid "Search page"
@@ -41594,6 +41691,9 @@ msgstr ""
msgid "Security dashboard"
msgstr ""
+msgid "Security reports last updated"
+msgstr ""
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr ""
@@ -41750,6 +41850,12 @@ msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
+msgid "SecurityOrchestration| for any commits"
+msgstr ""
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr ""
+
msgid "SecurityOrchestration| or "
msgstr ""
@@ -41759,7 +41865,13 @@ msgstr ""
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
+msgid "SecurityOrchestration|%{branchName}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr ""
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr ""
msgid "SecurityOrchestration|And scans to be performed:"
msgstr ""
+msgid "SecurityOrchestration|Any merge request"
+msgstr ""
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@@ -41888,7 +42003,7 @@ msgstr ""
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr ""
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|Exceptions"
@@ -41900,12 +42015,18 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load images."
msgstr ""
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr ""
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr ""
msgid "SecurityOrchestration|Groups"
msgstr ""
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
@@ -42171,6 +42292,9 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr ""
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
@@ -42183,13 +42307,13 @@ msgstr ""
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr ""
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|With the following customized CI variables:"
@@ -42219,13 +42343,19 @@ msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
+msgid "SecurityOrchestration|are false positives"
+msgstr ""
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr ""
+
msgid "SecurityOrchestration|branch"
msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
msgstr ""
msgid "SecurityOrchestration|group level branch input"
@@ -42234,6 +42364,12 @@ msgstr ""
msgid "SecurityOrchestration|group level branch selector"
msgstr ""
+msgid "SecurityOrchestration|have a fix available"
+msgstr ""
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr ""
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr ""
@@ -42303,9 +42439,6 @@ msgstr ""
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr ""
-msgid "SecurityReports|Add comment & dismiss"
-msgstr ""
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr ""
@@ -42360,6 +42493,9 @@ msgstr ""
msgid "SecurityReports|Configure security testing"
msgstr ""
+msgid "SecurityReports|Confirm dismissal"
+msgstr ""
+
msgid "SecurityReports|Create Issue"
msgstr ""
@@ -42375,9 +42511,15 @@ msgstr ""
msgid "SecurityReports|Development vulnerabilities"
msgstr ""
+msgid "SecurityReports|Dismiss as"
+msgstr ""
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr ""
+msgid "SecurityReports|Dismissal comment"
+msgstr ""
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr ""
@@ -42408,6 +42550,9 @@ msgstr ""
msgid "SecurityReports|Download the patch to apply it manually"
msgstr ""
+msgid "SecurityReports|Edit dismissal"
+msgstr ""
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr ""
@@ -42525,9 +42670,6 @@ msgstr ""
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
-msgid "SecurityReports|Save comment"
-msgstr ""
-
msgid "SecurityReports|Scan details"
msgstr ""
@@ -42571,7 +42713,7 @@ msgstr ""
msgid "SecurityReports|Submit vulnerability"
msgstr ""
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
msgstr ""
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
@@ -42919,9 +43061,6 @@ msgstr ""
msgid "Send email notification"
msgstr ""
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr ""
-
msgid "Send emails to users upon account deactivation."
msgstr ""
@@ -42991,6 +43130,9 @@ msgstr ""
msgid "Service Desk"
msgstr ""
+msgid "Service Desk Ticket"
+msgstr ""
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr ""
@@ -43015,12 +43157,24 @@ msgstr ""
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr ""
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr ""
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr ""
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr ""
+
msgid "ServiceDesk|Cannot create custom email"
msgstr ""
msgid "ServiceDesk|Cannot update custom email"
msgstr ""
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr ""
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr ""
@@ -43048,9 +43202,15 @@ msgstr ""
msgid "ServiceDesk|Custom email already exists"
msgstr ""
+msgid "ServiceDesk|Custom email disabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email does not exist"
msgstr ""
+msgid "ServiceDesk|Custom email enabled."
+msgstr ""
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr ""
@@ -43060,27 +43220,60 @@ msgstr ""
msgid "ServiceDesk|Enable Service Desk"
msgstr ""
+msgid "ServiceDesk|Enable custom email address"
+msgstr ""
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
+msgid "ServiceDesk|Incorrect From header"
+msgstr ""
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr ""
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr ""
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr ""
+msgid "ServiceDesk|Keep custom email"
+msgstr ""
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr ""
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr ""
+
msgid "ServiceDesk|Parameters missing"
msgstr ""
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr ""
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr ""
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr ""
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr ""
msgid "ServiceDesk|SMTP host"
msgstr ""
+msgid "ServiceDesk|SMTP host issue"
+msgstr ""
+
msgid "ServiceDesk|SMTP password"
msgstr ""
@@ -43120,15 +43313,45 @@ msgstr ""
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr ""
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr ""
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr ""
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr ""
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr ""
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr ""
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr ""
msgid "ServiceDesk|User cannot manage project."
msgstr ""
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr ""
+
+msgid "ServiceDesk|Verification failed"
+msgstr ""
+
+msgid "ServiceDesk|Verification started"
+msgstr ""
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr ""
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr ""
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr ""
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr ""
@@ -43156,6 +43379,9 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr ""
+
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -43276,6 +43502,9 @@ msgstr ""
msgid "Set to 0 for no size limit."
msgstr ""
+msgid "Set to 0 to disable timeout."
+msgstr ""
+
msgid "Set to auto-merge"
msgstr ""
@@ -43354,6 +43583,9 @@ msgstr ""
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr ""
+
msgid "Sets health status to %{health_status}."
msgstr ""
@@ -44187,6 +44419,9 @@ msgstr ""
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr ""
@@ -44280,9 +44515,6 @@ msgstr ""
msgid "Something went wrong while fetching details"
msgstr ""
-msgid "Something went wrong while fetching latest comments."
-msgstr ""
-
msgid "Something went wrong while fetching projects"
msgstr ""
@@ -45231,6 +45463,18 @@ msgstr ""
msgid "SubscriptionBanner|Upload new license"
msgstr ""
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr ""
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr ""
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr ""
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr ""
+
msgid "SubscriptionTable|Add seats"
msgstr ""
@@ -45378,6 +45622,9 @@ msgstr ""
msgid "Successfully deleted WebAuthn device."
msgstr ""
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -45396,6 +45643,9 @@ msgstr ""
msgid "Successfully unblocked"
msgstr ""
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr ""
+
msgid "Successfully unlocked"
msgstr ""
@@ -46055,6 +46305,9 @@ msgstr ""
msgid "TanukiBot|What is a fork?"
msgstr ""
+msgid "Targe branch"
+msgstr ""
+
msgid "Target"
msgstr ""
@@ -46067,7 +46320,13 @@ msgstr ""
msgid "Target branch"
msgstr "目標分支"
-msgid "Target branch or tag"
+msgid "Target branch rule"
+msgstr ""
+
+msgid "Target branch rule created."
+msgstr ""
+
+msgid "Target branch rules"
msgstr ""
msgid "Target branch: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr ""
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr ""
-msgid "The parsed YAML is too big"
-msgstr ""
-
msgid "The password for the Jenkins server."
msgstr ""
@@ -47070,6 +47326,9 @@ msgstr ""
msgid "There are currently no mirrored repositories."
msgstr ""
+msgid "There are currently no target branch rules"
+msgstr ""
+
msgid "There are merge conflicts"
msgstr ""
@@ -47088,9 +47347,6 @@ msgstr ""
msgid "There are no Spam Logs"
msgstr ""
-msgid "There are no abuse reports!"
-msgstr ""
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr ""
@@ -47340,6 +47596,9 @@ msgstr ""
msgid "There was an error fetching the variables."
msgstr ""
+msgid "There was an error fetching this merge request's pipelines."
+msgstr ""
+
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -47424,6 +47683,9 @@ msgstr ""
msgid "There was an summarizing your pending comments."
msgstr ""
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr ""
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr ""
@@ -47928,9 +48190,15 @@ msgstr ""
msgid "This merge request is from an internal project to a public project."
msgstr ""
+msgid "This merge request is hidden because its author has been banned"
+msgstr ""
+
msgid "This merge request is locked."
msgstr ""
+msgid "This merge request is locked. Only project members can comment."
+msgstr ""
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr ""
@@ -47949,10 +48217,10 @@ msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr ""
-msgid "This pipeline was triggered by a schedule"
+msgid "This pipeline was created by a schedule"
msgstr ""
-msgid "This pipeline was triggered by a schedule."
+msgid "This pipeline was created by a schedule."
msgstr ""
msgid "This process deletes the project repository and all related resources."
@@ -48102,7 +48370,7 @@ msgstr ""
msgid "This variable value does not meet the masking requirements."
msgstr ""
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
msgstr ""
msgid "This will invalidate your registered applications and WebAuthn devices."
@@ -48228,7 +48496,7 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr "é ä¼°"
-msgid "TimeTrackingReport|From"
+msgid "TimeTrackingReport|From the start of"
msgstr ""
msgid "TimeTrackingReport|Run report"
@@ -48249,7 +48517,7 @@ msgstr ""
msgid "TimeTrackingReport|Time spent"
msgstr ""
-msgid "TimeTrackingReport|To"
+msgid "TimeTrackingReport|To the end of"
msgstr ""
msgid "TimeTrackingReport|Total time spent: "
@@ -48669,7 +48937,7 @@ msgstr ""
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr ""
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
msgstr ""
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
@@ -48951,6 +49219,9 @@ msgstr ""
msgid "Tomorrow"
msgstr ""
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr ""
@@ -49030,6 +49301,9 @@ msgstr ""
msgid "Total Score"
msgstr ""
+msgid "Total Spans"
+msgstr ""
+
msgid "Total cores (CPUs)"
msgstr ""
@@ -49060,9 +49334,15 @@ msgstr ""
msgid "Trace Details"
msgstr ""
+msgid "Trace Start"
+msgstr ""
+
msgid "Tracing"
msgstr ""
+msgid "Tracing|%{ms} ms"
+msgstr ""
+
msgid "Tracing|Check again"
msgstr ""
@@ -49135,6 +49415,18 @@ msgstr ""
msgid "Tracing|Service"
msgstr ""
+msgid "Tracing|Span Details"
+msgstr ""
+
+msgid "Tracing|Span ID"
+msgstr ""
+
+msgid "Tracing|Status Code"
+msgstr ""
+
+msgid "Tracing|Toggle children spans"
+msgstr ""
+
msgid "Tracing|Trace ID"
msgstr ""
@@ -49499,9 +49791,6 @@ msgstr ""
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr ""
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
@@ -49589,6 +49878,9 @@ msgstr ""
msgid "Unable to load the page"
msgstr ""
+msgid "Unable to load user list. Reload the page and try again."
+msgstr ""
+
msgid "Unable to parse JSON"
msgstr ""
@@ -49622,9 +49914,6 @@ msgstr ""
msgid "Unable to update this issue at this time."
msgstr ""
-msgid "Unable to verify the user"
-msgstr ""
-
msgid "Unapprove a merge request"
msgstr ""
@@ -49703,6 +49992,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr ""
@@ -50078,6 +50370,9 @@ msgstr ""
msgid "UsageQuota|Buy storage"
msgstr ""
+msgid "UsageQuota|Code Suggestions"
+msgstr ""
+
msgid "UsageQuota|Code packages and container images."
msgstr ""
@@ -50099,10 +50394,10 @@ msgstr ""
msgid "UsageQuota|Dependency proxy"
msgstr ""
-msgid "UsageQuota|Filter chart by month"
+msgid "UsageQuota|Filter charts by year"
msgstr ""
-msgid "UsageQuota|Filter charts by year"
+msgid "UsageQuota|Filter projects data by month"
msgstr ""
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
@@ -50150,6 +50445,9 @@ msgstr ""
msgid "UsageQuota|Namespace storage used"
msgstr ""
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr ""
+
msgid "UsageQuota|No compute usage data available."
msgstr ""
@@ -50216,13 +50514,13 @@ msgstr ""
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
msgstr ""
-msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr ""
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr ""
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
@@ -50895,6 +51193,9 @@ msgstr ""
msgid "Username or email"
msgstr ""
+msgid "Username or primary email"
+msgstr ""
+
msgid "Username:"
msgstr ""
@@ -51596,6 +51897,9 @@ msgstr ""
msgid "VulnerabilityExport|Detected At"
msgstr ""
+msgid "VulnerabilityExport|Full Path"
+msgstr ""
+
msgid "VulnerabilityExport|Group Name"
msgstr ""
@@ -51623,16 +51927,19 @@ msgstr ""
msgid "VulnerabilityExport|Vulnerability"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
msgstr ""
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
@@ -51875,6 +52182,9 @@ msgstr ""
msgid "Vulnerability|GitLab Security Report"
msgstr ""
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr ""
+
msgid "Vulnerability|Hide prompt"
msgstr ""
@@ -51989,10 +52299,7 @@ msgstr ""
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr ""
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr ""
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "Vulnerability|Tool"
@@ -52028,6 +52335,9 @@ msgstr ""
msgid "Vulnerability|Vulnerable method:"
msgstr ""
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr ""
+
msgid "WARNING:"
msgstr ""
@@ -52355,6 +52665,12 @@ msgstr ""
msgid "Webhooks|Releases events"
msgstr ""
+msgid "Webhooks|Response body is empty"
+msgstr ""
+
+msgid "Webhooks|Response headers data is empty"
+msgstr ""
+
msgid "Webhooks|SSL verification"
msgstr ""
@@ -52457,15 +52773,6 @@ msgstr ""
msgid "Welcome, %{name}!"
msgstr ""
-msgid "What are group audit events?"
-msgstr ""
-
-msgid "What are instance audit events?"
-msgstr ""
-
-msgid "What are project audit events?"
-msgstr ""
-
msgid "What are some examples?"
msgstr ""
@@ -52817,6 +53124,12 @@ msgstr ""
msgid "Work item promoted successfully."
msgstr ""
+msgid "Work items are already linked"
+msgstr ""
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr ""
+
msgid "WorkItem|%{count} more assignees"
msgstr ""
@@ -52908,9 +53221,6 @@ msgstr ""
msgid "WorkItem|Create %{workItemType}"
msgstr ""
-msgid "WorkItem|Create objective"
-msgstr ""
-
msgid "WorkItem|Create work item"
msgstr ""
@@ -52929,9 +53239,6 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
-msgid "WorkItem|Health status"
-msgstr ""
-
msgid "WorkItem|History only"
msgstr ""
@@ -52950,13 +53257,19 @@ msgstr ""
msgid "WorkItem|Key result"
msgstr ""
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "WorkItem|Linked Items"
+msgstr ""
+
msgid "WorkItem|Mark as done"
msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
-msgid "WorkItem|New objective"
+msgid "WorkItem|New %{workItemType}"
msgstr ""
msgid "WorkItem|New task"
@@ -53100,9 +53413,6 @@ msgstr ""
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr ""
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr ""
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr ""
@@ -53133,7 +53443,7 @@ msgstr ""
msgid "Workspaces"
msgstr ""
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
msgstr ""
msgid "Workspaces|Cancel"
@@ -53232,9 +53542,6 @@ msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr ""
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr ""
@@ -53494,6 +53801,9 @@ msgstr ""
msgid "You can create a new SSH key by visiting %{link}"
msgstr ""
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr ""
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -53503,6 +53813,9 @@ msgstr ""
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr ""
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr ""
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr ""
@@ -53701,9 +54014,6 @@ msgstr ""
msgid "You don't have any authorized applications."
msgstr ""
-msgid "You don't have any deployments right now."
-msgstr ""
-
msgid "You don't have any open merge requests"
msgstr ""
@@ -54198,9 +54508,6 @@ msgstr ""
msgid "Your authorized applications"
msgstr ""
-msgid "Your browser does not support iFrames"
-msgstr ""
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr ""
@@ -54319,9 +54626,6 @@ msgstr ""
msgid "Your profile"
msgstr ""
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr ""
@@ -54346,6 +54650,9 @@ msgstr ""
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr ""
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr ""
+
msgid "Your search didn't match any commits."
msgstr ""
@@ -54513,6 +54820,9 @@ msgstr ""
msgid "allowed to fail"
msgstr ""
+msgid "already assigned to an epic"
+msgstr ""
+
msgid "already banned from namespace"
msgstr ""
@@ -54620,6 +54930,9 @@ msgstr ""
msgid "can not be changed when assigned to an epic"
msgstr ""
+msgid "can not be set for template labels"
+msgstr ""
+
msgid "can not be set for this resource"
msgstr ""
@@ -55128,6 +55441,9 @@ msgstr ""
msgid "created by"
msgstr ""
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr ""
+
msgid "daily"
msgstr ""
@@ -55193,6 +55509,9 @@ msgstr ""
msgid "eg party_tanuki"
msgstr ""
+msgid "eg. dev/*"
+msgstr ""
+
msgid "element is not a hierarchy"
msgstr ""
@@ -55278,9 +55597,6 @@ msgstr[0] ""
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
-msgid "for Workspace is required to be public"
-msgstr ""
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr ""
@@ -55540,6 +55856,9 @@ msgstr ""
msgid "jigsaw is not defined"
msgstr ""
+msgid "key result"
+msgstr ""
+
msgid "kuromoji custom analyzer"
msgstr ""
@@ -56010,6 +56329,9 @@ msgstr ""
msgid "must be less than the limit of %{tag_limit} tags"
msgstr ""
+msgid "must be owned by the user's enterprise group"
+msgstr ""
+
msgid "must be set for a project namespace"
msgstr ""
@@ -56019,6 +56341,9 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr ""
+
msgid "must belong to same project of its requirement object."
msgstr ""
@@ -56046,6 +56371,9 @@ msgstr ""
msgid "must not contain commonly used combinations of words and letters"
msgstr ""
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
@@ -56103,6 +56431,9 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
+msgid "objective"
+msgstr ""
+
msgid "on or after"
msgstr ""
@@ -56396,6 +56727,9 @@ msgstr ""
msgid "ssh:"
msgstr ""
+msgid "started"
+msgstr ""
+
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -56438,6 +56772,9 @@ msgstr ""
msgid "targeting "
msgstr ""
+msgid "task"
+msgstr ""
+
msgid "terraform states"
msgstr ""
@@ -56486,9 +56823,6 @@ msgstr ""
msgid "triggered"
msgstr ""
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr ""
-
msgid "two-factor authentication settings"
msgstr ""
@@ -56544,6 +56878,9 @@ msgstr ""
msgid "version %{versionIndex}"
msgstr ""
+msgid "via"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index 9ca3d0788da..e18af8c4a33 100644
--- a/locale/zh_TW/gitlab.po
+++ b/locale/zh_TW/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: zh-TW\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2023-08-11 16:02\n"
+"PO-Revision-Date: 2023-09-12 12:34\n"
msgid " %{start} to %{end}"
msgstr " %{start} 到 %{end}"
@@ -44,6 +44,10 @@ msgstr "和"
msgid " and %{sliced}"
msgstr " 和 %{sliced}"
+msgid " except branch:"
+msgid_plural " except branches:"
+msgstr[0] "除外分支:"
+
msgid " or "
msgstr " 或 "
@@ -574,9 +578,6 @@ msgstr "%{count} 個標籤"
msgid "%{count} total weight"
msgstr "ç¸½æ¬Šé‡ %{count}"
-msgid "%{dashboard_path} could not be found."
-msgstr "找ä¸åˆ° %{dashboard_path}。"
-
msgid "%{days} days until tags are automatically removed"
msgstr "%{days}天,直到標籤被自動刪除"
@@ -622,8 +623,8 @@ msgstr "%{edit_in_new_fork_notice} è«‹å†æ¬¡å˜—試上傳檔案。"
msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
-msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr "%{enable_service_ping_link_start}啟用%{link_end} 或 %{generate_manually_link_start}產生%{link_end} Service Ping 以é è¦½å’Œä¸‹è¼‰æ‰€ä½¿ç”¨æœå‹™çš„有效負載資料。"
+msgid "%{enable_service_ping_link_start}Enable%{enable_service_ping_link_end} or %{generate_manually_link_start}generate%{generate_manually_link_end} Service Ping to preview and download service usage data payload."
+msgstr "%{enable_service_ping_link_start}啟用%{enable_service_ping_link_end} 或 %{generate_manually_link_start}產生%{generate_manually_link_end} Service Ping 以é è¦½å’Œä¸‹è¼‰æ‰€ä½¿ç”¨æœå‹™çš„有效負載資料。"
msgid "%{extra} more downstream pipelines"
msgstr "還有 %{extra} 個下游æµæ°´ç·š"
@@ -700,6 +701,12 @@ msgstr "%{issuesSize} 上é™ç‚º %{maxIssueCount}"
msgid "%{italic_start}What's new%{italic_end} is inactive and cannot be viewed."
msgstr "%{italic_start}新增功能%{italic_end} 處於éžæ´»å‹•ç‹€æ…‹ï¼Œç„¡æ³•æŸ¥çœ‹ã€‚"
+msgid "%{item_ids} could not be removed due to insufficient permissions"
+msgstr "由於權é™ä¸è¶³è€Œç„¡æ³•åˆªé™¤ %{item_ids} "
+
+msgid "%{item_ids} could not be removed due to not being linked"
+msgstr "由於未éˆçµè€Œç„¡æ³•åˆªé™¤ %{item_ids} "
+
msgid "%{itemsCount} issues with a limit of %{maxIssueCount}"
msgstr "%{itemsCount} 個議題,上é™ç‚º %{maxIssueCount} 個"
@@ -775,6 +782,9 @@ msgstr "%{labelStart}未更改的回應:%{labelEnd} %{headers}"
msgid "%{label_for_message} unavailable"
msgstr "%{label_for_message} 無法使用"
+msgid "%{label_name} is locked and was not removed"
+msgstr "%{label_name} 已鎖定且未被移除"
+
msgid "%{label_name} was removed"
msgstr "%{label_name} 已移除"
@@ -1203,11 +1213,11 @@ msgstr "%{verb} 耗時 %{time_spent_value}"
msgid "%{verb} this %{noun} as a draft."
msgstr "%{verb} 該 %{noun} 為è‰ç¨¿ã€‚"
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end}å…許您在群組或專案中發é€é€šçŸ¥è‡³ web 應用程å¼ä½œç‚ºäº‹ä»¶çš„回應。"
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} å¯ä»¥è®“您在群組或專案中的事件發生時,å‘網é æ‡‰ç”¨ç¨‹å¼ç™¼é€é€šçŸ¥ã€‚"
-msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr "%{webhooks_link_start}%{webhook_type}%{link_end}å…許您在群組或專案中發é€é€šçŸ¥è‡³ web 應用程å¼ä½œç‚ºäº‹ä»¶çš„回應。比起 webhook ,我們建議你使用%{integrations_link_start}æ•´åˆ%{link_end}。"
+msgid "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{integrations_link_end} in preference to a webhook."
+msgstr "%{webhooks_link_start}%{webhook_type}%{webhooks_link_end} å¯ä»¥åœ¨ç¾¤çµ„或專案中的事件發生時,將通知發é€åˆ°ç¶²è·¯æ‡‰ç”¨ç¨‹å¼ã€‚我們建議使用 %{integrations_link_start}æ•´åˆ%{integrations_link_end},而ä¸æ˜¯ä½¿ç”¨ Webhook。"
msgid "%{widget} options"
msgstr "%{widget} é¸é …"
@@ -1312,6 +1322,9 @@ msgstr "+ 其餘 %{amount} 項"
msgid "+ %{count} more"
msgstr "+ 其餘 %{count} 項"
+msgid "+ %{hiddenBranchesLength} more"
+msgstr "+ 更多的 %{hiddenBranchesLength}"
+
msgid "+ %{moreCount} more"
msgstr "+ 其餘 %{moreCount} 項"
@@ -1755,15 +1768,24 @@ msgstr "%{tool} 是一個 %{transition} 解答"
msgid "AI|AI generated explanations will appear here."
msgstr "AI生æˆçš„說明將顯示在這裡。"
+msgid "AI|An %{linkStart}Experiment%{linkEnd} is a feature that's in the process of being developed. It's not production-ready. We encourage users to try Experimental features and provide feedback. An Experiment: %{bullets}"
+msgstr "%{linkStart}實驗%{linkEnd} 是一項正在開發的功能,它還沒有åšå¥½ç”Ÿç”¢æº–備。我們鼓勵使用嘗試實驗性功能並æ供回饋。實驗: %{bullets}"
+
msgid "AI|Apply AI-generated description"
msgstr "套用 AI 生æˆçš„æè¿°"
+msgid "AI|Ask GitLab Duo"
+msgstr "è©¢å• GitLab Duo"
+
msgid "AI|Ask a question"
msgstr "å•ä¸€å€‹å•é¡Œ"
msgid "AI|Autocomplete"
msgstr "自動完æˆ"
+msgid "AI|Can be removed at any time"
+msgstr "å¯ä»¥éš¨æ™‚移除"
+
msgid "AI|Close the Code Explanation"
msgstr "關閉程å¼ç¢¼èªªæ˜Ž"
@@ -1803,12 +1825,30 @@ msgstr "AI產生å•é¡Œæè¿°"
msgid "AI|GitLab Duo"
msgstr "GitLab Duo"
+msgid "AI|Give feedback on AI content"
+msgstr ""
+
+msgid "AI|Give feedback to improve this answer."
+msgstr ""
+
+msgid "AI|Has no support and might not be documented"
+msgstr "沒有支æ´ï¼Œä¸”å¯èƒ½æ²’有文件記錄"
+
msgid "AI|Helpful"
msgstr "有幫助"
+msgid "AI|How could the content be improved?"
+msgstr ""
+
+msgid "AI|How was the AI content?"
+msgstr ""
+
msgid "AI|I don't see how I can help. Please give better instructions!"
msgstr "我ä¸çŸ¥é“我能幫上什麼忙。請給我更好的指令ï¼"
+msgid "AI|May be unstable"
+msgstr "å¯èƒ½ä¸ç©©å®š"
+
msgid "AI|May provide inappropriate responses not representative of GitLab's views. Do not input personal data."
msgstr "AI生æˆçš„回答å¯èƒ½ä¸ä¸€å®šä»£è¡¨GitLab的觀點,有時å¯èƒ½æœƒæä¾›ä¸é©ç•¶çš„回應。在與AI模型互動時,請勿輸入個人æ•æ„Ÿä¿¡æ¯ã€‚"
@@ -1830,6 +1870,9 @@ msgstr "發é€èŠå¤©æ¶ˆæ¯ã€‚"
msgid "AI|Something went wrong. Please try again later"
msgstr "發生錯誤,請ç¨å¾Œå†è©¦"
+msgid "AI|Thank you for your feedback."
+msgstr ""
+
msgid "AI|The container element wasn't found, stopping AI Genie."
msgstr "未找到容器元素,AI Genie åœæ­¢é‹ä½œã€‚"
@@ -1845,6 +1888,9 @@ msgstr "這些功能å¯èƒ½æœƒå°Žè‡´æ€§èƒ½å’Œç©©å®šæ€§å•é¡Œï¼Œä¸¦ä¸”å¯èƒ½æœƒéš¨
msgid "AI|Third-party AI services"
msgstr "第三方人工智慧æœå‹™"
+msgid "AI|To help improve the quality of the content, send your feedback to GitLab team members."
+msgstr ""
+
msgid "AI|Unhelpful"
msgstr "沒有幫助"
@@ -1857,6 +1903,9 @@ msgstr "使用第三方人工智慧æœå‹™"
msgid "AI|What does the selected code mean?"
msgstr "所é¸çš„程å¼ç¢¼æ˜¯ä»€éº¼æ„æ€ï¼Ÿ"
+msgid "AI|What's an Experiment?"
+msgstr "什麼是實驗?"
+
msgid "AI|Write a brief description and have AI fill in the details."
msgstr "寫一個簡短的æ述,讓 AI 填寫細節。"
@@ -1869,9 +1918,6 @@ msgstr "錯誤"
msgid "AI|You are not allowed to copy any part of this output into issues, comments, GitLab source code, commit messages, merge requests or any other user interface in the %{gitlabOrg} or %{gitlabCom} groups."
msgstr "您ä¸å¾—將此輸出的任何部分複製到議題ã€è©•è«–ã€GitLab原始碼ã€æ交訊æ¯ã€åˆä½µè«‹æ±‚或任何在%{gitlabOrg}或%{gitlabCom}群組內其他使用者界é¢ä¸­ã€‚"
-msgid "AI|You can ask AI for more information."
-msgstr "您å¯ä»¥å‘ AI è©¢å•æ›´å¤šè³‡è¨Šã€‚"
-
msgid "AI|finding"
msgstr "尋找"
@@ -2076,9 +2122,6 @@ msgstr "未找到報告"
msgid "AbuseReport|%{reportLinkStart}Reported%{reportLinkEnd} for %{category} %{timeAgo}."
msgstr "%{reportLinkStart}在%{timeAgo}被報告%{reportLinkEnd}為%{category}。"
-msgid "AbuseReport|Abuse reports"
-msgstr "濫用報告"
-
msgid "AbuseReport|Abuse unconfirmed"
msgstr "未經證實的濫用"
@@ -2193,6 +2236,9 @@ msgstr "攻擊或辱罵性內容"
msgid "AbuseReport|Other"
msgstr "其他"
+msgid "AbuseReport|Past abuse reports"
+msgstr "éŽåŽ»çš„濫用報告"
+
msgid "AbuseReport|Personal information or credentials"
msgstr "個人資訊æ¯æˆ–憑證"
@@ -2250,6 +2296,9 @@ msgstr "é©—è­‰"
msgid "AbuseReport|View screenshot"
msgstr "查看截圖"
+msgid "Abusive or offensive"
+msgstr ""
+
msgid "Accept invitation"
msgstr "接å—邀請"
@@ -2301,6 +2350,9 @@ msgstr "群組"
msgid "AccessDropdown|Roles"
msgstr "角色"
+msgid "AccessDropdown|Select"
+msgstr "é¸å–"
+
msgid "AccessDropdown|Users"
msgstr "使用者"
@@ -2481,6 +2533,9 @@ msgstr "確èª"
msgid "Action"
msgstr "動作"
+msgid "Action '%{action}' in registries is not supported."
+msgstr "ä¸æ”¯æŒè¨»å†Šè¡¨ä¸­çš„ '%{action}' æ“作。"
+
msgid "Action '%{action}' in registry %{registry_id} entry is not supported."
msgstr "ä¸æ”¯æ´è¨»å†Šè¡¨ %{registry_id} æ¢ç›®ä¸­çš„ “%{action}†æ“作。"
@@ -2793,6 +2848,9 @@ msgstr "批次添加建議"
msgid "Add tag"
msgstr "新增標籤"
+msgid "Add target branch rule"
+msgstr "增加目標分支è¦å‰‡"
+
msgid "Add text to the sign-in page. Markdown enabled."
msgstr "加入文字到登入é é¢ã€‚Markdown 已啟用。"
@@ -2817,6 +2875,9 @@ msgstr "加入待審閱"
msgid "Add to tree"
msgstr "加入到樹"
+msgid "Add token"
+msgstr "新增令牌"
+
msgid "Add topics to projects to help users find them."
msgstr "加入主題到專案以幫助使用者尋找。"
@@ -2844,8 +2905,8 @@ msgstr "新增/移除"
msgid "AddMember|Invite email is invalid"
msgstr "邀請的電å­éƒµä»¶åœ°å€ç„¡æ•ˆ"
-msgid "AddMember|Invite limit of %{daily_invites} per day exceeded"
-msgstr "超éŽæ¯å¤©é‚€è«‹ %{daily_invites} 次的é™åˆ¶"
+msgid "AddMember|Invite limit of %{daily_invites} per day exceeded."
+msgstr ""
msgid "AddMember|Invites cannot be blank"
msgstr "邀請ä¸å¯ç‚ºç©º"
@@ -3684,8 +3745,8 @@ msgstr "å°éŽ–使用者具有以下效果:"
msgid "AdminUsers|Bot"
msgstr "機器人"
-msgid "AdminUsers|Can create group"
-msgstr "å¯ä»¥å»ºç«‹ç¾¤çµ„"
+msgid "AdminUsers|Can create top level group"
+msgstr "å¯ä»¥å»ºç«‹æœ€ä¸Šå±¤ç¾¤çµ„"
msgid "AdminUsers|Cannot sign in or access instance information"
msgstr "無法登入或存å–執行個體資訊"
@@ -4308,6 +4369,9 @@ msgstr "標題是 GitLab 中警示的必填字段。如果您指定的有效è£è
msgid "AlertSettings|A webhook URL and authorization key is generated for the integration. After you save the integration, both are visible under the “View credentials†tab."
msgstr "為整åˆç”¢ç”Ÿä¸€å€‹ webhook URL 和授權金鑰。ä¿å­˜æ•´åˆå¾Œï¼Œå…©è€…都在“查看憑據â€é¸é …å¡ä¸‹å¯è¦‹ã€‚"
+msgid "AlertSettings|Active alerts"
+msgstr "啟用中的警報"
+
msgid "AlertSettings|Add new integration"
msgstr "新增新的整åˆ"
@@ -4746,9 +4810,6 @@ msgstr "ç²å–公共部署金鑰時出錯。請å†è©¦ä¸€æ¬¡ã€‚"
msgid "An error occurred previewing the blob"
msgstr "é è¦½ blob 時發生錯誤"
-msgid "An error occurred when loading the user verification challenge. Refresh to try again."
-msgstr "加載使用者驗證質詢時發生錯誤。請é‡æ–°æ•´ç†é é¢ï¼Œå†è©¦ä¸€æ¬¡ã€‚"
-
msgid "An error occurred when updating the title"
msgstr "更新標題時發生錯誤"
@@ -4839,6 +4900,9 @@ msgstr "抓å–議題時發生錯誤。"
msgid "An error occurred while fetching label colors."
msgstr "抓å–標記é¡è‰²æ™‚發生錯誤。"
+msgid "An error occurred while fetching labels, please try again."
+msgstr "æ“·å–標籤時發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚"
+
msgid "An error occurred while fetching participants"
msgstr "ç²å–åƒèˆ‡è€…時發生錯誤"
@@ -5023,6 +5087,9 @@ msgstr[0] "儲存設定時發生錯誤"
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "儲存您的設定時發生錯誤。試著å†æ¬¡å„²å­˜æ‚¨çš„設定。"
+msgid "An error occurred while searching for labels, please try again."
+msgstr "æœå°‹æ¨™ç±¤æ™‚發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚"
+
msgid "An error occurred while triggering the job."
msgstr "觸發作業時發生錯誤。"
@@ -5038,6 +5105,12 @@ msgstr "嘗試執行此åˆä½µè«‹æ±‚çš„æ–°æµæ°´ç·šæ™‚發生錯誤。"
msgid "An error occurred while trying to unfollow this user, please try again."
msgstr "嘗試å–消關注此使用者發生錯誤,請é‡è©¦ã€‚"
+msgid "An error occurred while trying to update the registries: '%{error_message}'."
+msgstr "嘗試更新註冊表時發生錯誤: “%{error_message}â€ã€‚"
+
+msgid "An error occurred while trying to update the registry: '%{error_message}'."
+msgstr "嘗試更新註冊表時發生錯誤: '%{error_message}'。"
+
msgid "An error occurred while updating approvers"
msgstr "更新核准者時發生錯誤"
@@ -5147,6 +5220,9 @@ msgstr "分æžè¨­å®š"
msgid "Analytics|A visualization with that name already exists."
msgstr "分æžå…·æœ‰è©²å稱的å¯è¦–化已存在。"
+msgid "Analytics|Add a visualization"
+msgstr "增加視覺化"
+
msgid "Analytics|Add visualizations"
msgstr "增加視覺化"
@@ -5192,15 +5268,18 @@ msgstr "é…置儀表æ¿å°ˆæ¡ˆ"
msgid "Analytics|Create dashboard %{dashboardSlug}"
msgstr "分æžå»ºç«‹å„€è¡¨æ¿ %{dashboardSlug}"
+msgid "Analytics|Create your dashboard"
+msgstr "建立您的儀表æ¿"
+
msgid "Analytics|Custom dashboards"
msgstr "客製儀表æ¿"
-msgid "Analytics|Dashboard Title"
-msgstr "儀表æ¿æ¨™é¡Œ"
-
msgid "Analytics|Dashboard not found"
msgstr "未找到儀表æ¿"
+msgid "Analytics|Dashboard title"
+msgstr "儀表æ¿æ¨™é¡Œ"
+
msgid "Analytics|Dashboard was saved successfully"
msgstr "儀表æ¿å·²æˆåŠŸå„²å­˜"
@@ -5222,6 +5301,12 @@ msgstr "分æžæ—¥æœŸå’Œæ™‚間以 UTC 時å€é¡¯ç¤º"
msgid "Analytics|Edit"
msgstr "編輯"
+msgid "Analytics|Edit your dashboard"
+msgstr "編輯您的儀表æ¿"
+
+msgid "Analytics|Enter a dashboard title"
+msgstr "輸入儀表æ¿æ¨™é¡Œ"
+
msgid "Analytics|Enter a visualization name"
msgstr "分æžè¼¸å…¥å¯è¦–化å稱"
@@ -5237,6 +5322,9 @@ msgstr "讀å–資料失敗"
msgid "Analytics|Host"
msgstr "主機"
+msgid "Analytics|Invalid visualization configuration"
+msgstr "無效的視覺化設定"
+
msgid "Analytics|Language"
msgstr "語言"
@@ -5279,24 +5367,30 @@ msgstr "推薦人"
msgid "Analytics|Resulting Data"
msgstr "çµæžœè³‡æ–™"
-msgid "Analytics|Save"
-msgstr "儲存"
-
msgid "Analytics|Save and add to Dashboard"
msgstr "分æžä¿å­˜ä¸¦å¢žåŠ åˆ°å„€è¡¨æ¿"
msgid "Analytics|Save new visualization"
msgstr "分æžä¿å­˜æ–°çš„å¯è¦–化"
+msgid "Analytics|Save your dashboard"
+msgstr "儲存您的儀表æ¿"
+
msgid "Analytics|Select a measurement"
msgstr "分æžé¸æ“‡æ¸¬é‡"
+msgid "Analytics|Select a visualization from the sidebar to get started."
+msgstr "從å´é‚Šæ¬„é¸æ“‡ä¸€å€‹è¦–覺化開始。"
+
msgid "Analytics|Select a visualization type"
msgstr "分æžé¸æ“‡å¯è¦–化類型"
msgid "Analytics|Single Statistic"
msgstr "單一統計"
+msgid "Analytics|Something is wrong with your panel visualization configuration. See %{linkStart}troubleshooting documentation%{linkEnd}."
+msgstr "您的é¢æ¿è¦–覺化設定似乎有點å•é¡Œã€‚請見%{linkStart}疑難排解文件%{linkEnd}。"
+
msgid "Analytics|Something went wrong while connecting to your data source. See %{linkStart}troubleshooting documentation%{linkEnd}."
msgstr "在連接到您的資料æºæ™‚發生了å•é¡Œã€‚è«‹åƒé–±%{linkStart}疑難排解文件%{linkEnd}。"
@@ -6045,9 +6139,6 @@ msgstr "您確定è¦åˆªé™¤æ­¤è£ç½®å—Žï¼Ÿæ­¤å‹•ä½œç„¡æ³•å¾©åŽŸã€‚"
msgid "Are you sure you want to delete this label?"
msgstr "您確定è¦åˆªé™¤é€™å€‹æ¨™ç±¤å—Žï¼Ÿ"
-msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr "確定è¦åˆªé™¤æ­¤æµæ°´ç·šæŽ’程嗎?"
-
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
msgstr "您確定刪除這個æµæ°´ç·šå—Žï¼Ÿé€™éº¼åšæœƒå°‡æ‰€æœ‰æµæ°´ç·šå¿«å–設æˆéŽæœŸï¼Œä¸¦åˆªé™¤æ‰€æœ‰ç›¸é—œç‰©ä»¶ï¼Œä¾‹å¦‚組建ã€æ—¥èªŒã€ç”¢ç‰©åŠè§¸ç™¼å™¨ã€‚這個動作ä¸èƒ½å¾©åŽŸã€‚"
@@ -6127,8 +6218,8 @@ msgstr "您確定è¦é‡è¨­è¨»å†Šæ†‘證嗎?"
msgid "Are you sure you want to retry this migration?"
msgstr "您確定è¦é‡è©¦é€™å€‹ç§»è½‰å—Žï¼Ÿ"
-msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
-msgstr "您確定è¦æ’¤æ¶ˆæ­¤ %{accessTokenType} 嗎?此æ“作無法復原。"
+msgid "Are you sure you want to revoke the %{accessTokenType} \"%{tokenName}\"? This action cannot be undone."
+msgstr "您確定您想è¦æ’¤éŠ· %{accessTokenType}「%{tokenName}ã€å—Žï¼Ÿæ­¤å‹•ä½œä¸å¯é€†ã€‚"
msgid "Are you sure you want to revoke this SSH key?"
msgstr "您確定è¦æ’¤éŠ·æ­¤ SSH 密鑰嗎?"
@@ -6267,6 +6358,9 @@ msgstr "è¦è‡ªå‹•æª¢æŸ¥çš„以逗號分隔的分支列表。留空以包括所有
msgid "AsanaService|User Personal Access Token. User must have access to the task. All comments are attributed to this user."
msgstr "使用者個人存å–令牌。使用者必須æ“有存å–任務的權é™ã€‚將會以使用者的身分進行所有留言。"
+msgid "Ask a maintainer to check the import status for more details."
+msgstr "è¦æ±‚維護者檢查匯入狀態以å–得更多詳細資訊。"
+
msgid "Ask again later"
msgstr "ç¨å¾Œå†å•"
@@ -6474,6 +6568,9 @@ msgstr "已存在åŒå稱的標頭。"
msgid "AuditStreams|Active"
msgstr "活動"
+msgid "AuditStreams|Add a new private key"
+msgstr "新增ç§é‘°"
+
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
msgstr "新增一個 HTTP 端點來管ç†ç¬¬ä¸‰æ–¹ç³»çµ±ä¸­çš„紀錄。"
@@ -6591,6 +6688,9 @@ msgstr "這å¯èƒ½åŒ…括æ•æ„Ÿä¿¡æ¯ï¼Œè«‹ç¢ºèªæ‚¨ä¿¡ä»»è©²ç›®çš„地端點。"
msgid "AuditStreams|This is great for keeping everything one place."
msgstr "這éžå¸¸é©åˆå°‡æ‰€æœ‰å…§å®¹ä¿å­˜åœ¨ä¸€å€‹åœ°æ–¹ã€‚"
+msgid "AuditStreams|Use the Google Cloud console to view the private key. To change the private key, replace it with a new private key."
+msgstr "使用 Google Cloud 控制å°æª¢è¦–ç§é‘°ã€‚è¦è®Šæ›´ç§é‘°ï¼Œè«‹ä½¿ç”¨æ–°çš„ç§é‘°å–代。"
+
msgid "AuditStreams|Value"
msgstr "價值"
@@ -7518,8 +7618,8 @@ msgstr "載入 GitLab 訂閱詳細資訊時發生錯誤。"
msgid "Billing|An error occurred while loading billable members list."
msgstr "載入計費æˆå“¡åˆ—表時發生錯誤。"
-msgid "Billing|An error occurred while loading details for the Code Suggestions add-on."
-msgstr "載入程å¼ç¢¼å»ºè­°é™„加元件的詳細訊æ¯æ™‚發生錯誤。"
+msgid "Billing|An error occurred while loading details for the Code Suggestions add-on. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "載入程å¼ç¢¼å»ºè­°é™„加元件的詳細訊æ¯æ™‚發生錯誤,如果å•é¡Œä»ç„¶å­˜åœ¨ï¼Œè«‹ %{supportLinkStart}è¯ç¹«æ”¯æ´äººå“¡%{supportLinkEnd}。"
msgid "Billing|An error occurred while loading pending members list"
msgstr "加載待定æˆå“¡æ¸…單時發生錯誤"
@@ -7533,15 +7633,18 @@ msgstr "等待會員註冊"
msgid "Billing|Cannot remove user"
msgstr "無法移除使用者"
-msgid "Billing|Code Suggestions add-on assigned"
-msgstr "已指派的程å¼ç¢¼å»ºè­°é™„加元件"
-
msgid "Billing|Direct memberships"
msgstr "直接會員"
msgid "Billing|Enter at least three characters to search."
msgstr "請輸入最少 3 個字元來æœå°‹ã€‚"
+msgid "Billing|Error assigning Code Suggestions add-on"
+msgstr "指派程å¼ç¢¼å»ºè­°é™„加元件時錯誤"
+
+msgid "Billing|Error un-assigning Code Suggestions add-on"
+msgstr "å–消指派程å¼ç¢¼å»ºè­°é™„加元件時錯誤"
+
msgid "Billing|Explore paid plans"
msgstr "ç€è¦½ä»˜è²»è¨ˆåŠƒ"
@@ -7558,6 +7661,9 @@ msgstr[0] "å…費版中的群組åªèƒ½æœ‰ %d 個æˆå“¡ã€‚"
msgid "Billing|Members who were invited via a group invitation cannot be removed. You can either remove the entire group, or ask an Owner of the invited group to remove the member."
msgstr "無法移除通éŽç¾¤çµ„邀請的被邀請æˆå“¡ã€‚您å¯ä»¥ç§»é™¤æ•´å€‹ç¾¤çµ„,也å¯ä»¥è¦æ±‚å—邀群組的所有者移除æˆå“¡ã€‚"
+msgid "Billing|No seats available"
+msgstr "沒有å¯ç”¨çš„席次"
+
msgid "Billing|No users to display."
msgstr "沒有å¯é¡¯ç¤ºçš„使用者。"
@@ -7570,6 +7676,12 @@ msgstr "專案邀請"
msgid "Billing|Remove user %{username} from your subscription"
msgstr "從您的訂閱中移除使用者 %{username}"
+msgid "Billing|Something went wrong when assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "將附加元件指派給該æˆå“¡æ™‚發生å•é¡Œï¼Œå¦‚æžœå•é¡Œä»ç„¶å­˜åœ¨ï¼Œè«‹ %{supportLinkStart}è¯ç¹«æ”¯æ´äººå“¡%{supportLinkEnd}。"
+
+msgid "Billing|Something went wrong when un-assigning the add-on to this member. If the problem persists, please %{supportLinkStart}contact support%{supportLinkEnd}."
+msgstr "å–消指派該æˆå“¡çš„附加元件時發生å•é¡Œï¼Œå¦‚æžœå•é¡Œä»ç„¶å­˜åœ¨ï¼Œè«‹ %{supportLinkStart}è¯ç¹«æ”¯æ´äººå“¡%{supportLinkEnd}。"
+
msgid "Billing|Subscription end"
msgstr "訂閱çµæŸ"
@@ -7597,6 +7709,9 @@ msgstr "檢視等待中的核准"
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr "您將è¦å¾žè¨‚閱中移除使用者%{username}。如果繼續,該使用者將從 %{namespace} 群組åŠå…¶æ‰€æœ‰å­çµ„和項目中刪除。此æ“作無法撤消。"
+msgid "Billing|You have assigned all available Code Suggestions add-on seats. Please %{salesLinkStart}contact sales%{salesLinkEnd} if you would like to purchase more seats."
+msgstr "您已指派所有å¯ç”¨çš„程å¼ç¢¼å»ºè­°é™„加元件席次,如果您想購買更多席次,請 %{salesLinkStart}è¯ç¹«éŠ·å”®%{salesLinkEnd}。"
+
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr "您的群組最近更改為使用å…費計劃。 %{over_limit_message} 您å¯ä»¥é€šéŽåˆªé™¤ä¸å†éœ€è¦è¨ªå•æ¬Šé™çš„æˆå“¡æˆ–將其切æ›ç‚ºè¶…é™ä¾†ç‚ºæ–°æˆå“¡é‡‹æ”¾ç©ºé–“。è¦ç²å¾—ç„¡é™æ•¸é‡çš„會員,您å¯ä»¥ %{link_start}å‡ç´š%{link_end} 到付費等級。"
@@ -7640,6 +7755,9 @@ msgstr[0] "被 %d 個議題å°éŽ–"
msgid "Blocked issue"
msgstr "被å°éŽ–çš„è­°é¡Œ"
+msgid "Blocked work items are not available for the current subscription tier"
+msgstr "被å°éŽ–的工作項ä¸é©ç”¨æ–¼ç•¶å‰è¨‚閱層級"
+
msgid "Blocking"
msgstr "å°éŽ–中"
@@ -7673,9 +7791,6 @@ msgstr "沒有符åˆçš„çµæžœ"
msgid "BoardNewEpic|Search groups"
msgstr "æœå°‹ç¾¤çµ„"
-msgid "BoardNewEpic|Select a group"
-msgstr "é¸æ“‡ä¸€å€‹ç¾¤çµ„"
-
msgid "BoardNewIssue|No matching results"
msgstr "沒有符åˆçš„çµæžœ"
@@ -7763,9 +7878,6 @@ msgstr "é¸å–標籤"
msgid "BoardScope|Select milestone"
msgstr "é¸å–里程碑"
-msgid "BoardScope|Select weight"
-msgstr "é¸å–權é‡"
-
msgid "BoardScope|Started"
msgstr "開始"
@@ -8381,7 +8493,7 @@ msgid "BroadcastMessages|Indigo"
msgstr "é›è—"
msgid "BroadcastMessages|Leave blank to target all group and project pages."
-msgstr ""
+msgstr "留空則é‡å°æ‰€æœ‰ç¾¤çµ„和專案é é¢ã€‚"
msgid "BroadcastMessages|Light"
msgstr "淺色"
@@ -8411,16 +8523,16 @@ msgid "BroadcastMessages|Notification"
msgstr "通知"
msgid "BroadcastMessages|One or more roles is required."
-msgstr ""
+msgstr "需è¦ä¸€å€‹æˆ–多個角色。"
msgid "BroadcastMessages|Paths can contain wildcards, like */welcome."
-msgstr ""
+msgstr "路徑å¯ä»¥åŒ…å«è¬ç”¨å­—元,如 */welcome。"
msgid "BroadcastMessages|Red"
msgstr "紅色"
msgid "BroadcastMessages|Select at least one role."
-msgstr ""
+msgstr "至少é¸æ“‡ä¸€å€‹è§’色。"
msgid "BroadcastMessages|Show only to users who have specific roles on groups/project pages"
msgstr "僅在群組/專案é é¢ä¸Šå…·æœ‰ç‰¹å®šè§’色的使用者顯示"
@@ -8837,8 +8949,8 @@ msgstr "é™åˆ¶ %{italicStart} 從 %{italicEnd} 該專案存å–(已棄用)"
msgid "CICD|Limit access %{italicStart}to%{italicEnd} this project"
msgstr "é™åˆ¶ %{italicStart} å° %{italicEnd} 該專案的存å–"
-msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
-msgstr "除éžå°‡å…¶ä»–專案加入到å…許清單中,å¦å‰‡ç¦æ­¢ä½¿ç”¨æ­¤å°ˆæ¡ˆçš„ CI/CD 工作令牌存å–其他專案。ç¦ç”¨æ­¤åŠŸèƒ½æœƒå¸¶ä¾†å®‰å…¨é¢¨éšªï¼Œå› ç‚ºæœªç¶“授權的專案å¯èƒ½æœƒå˜—試å–å¾—æœ‰æ•ˆçš„ä»¤ç‰Œä¸¦å­˜å– API。%{linkStart}了解更多。%{linkEnd}"
+msgid "CICD|Prevent CI/CD job tokens from this project from being used to access other projects unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more%{linkEnd}."
+msgstr "除éžå°‡å…¶ä»–專案加入到å…許清單中,å¦å‰‡ç¦æ­¢ä½¿ç”¨æ­¤å°ˆæ¡ˆçš„ CI/CD 作業令牌來存å–其他專案。ç¦ç”¨æ­¤åŠŸèƒ½å°‡å¸¶ä¾†å®‰å…¨é¢¨éšªï¼Œå› ç‚ºæœªç¶“授權的專案å¯èƒ½æœƒå˜—試擷å–æœ‰æ•ˆçš„ä»¤ç‰Œä¸¦å­˜å– API,%{linkStart}了解更多%{linkEnd}。"
msgid "CICD|Prevent access to this project from other project CI/CD job tokens, unless the other project is added to the allowlist. It is a security risk to disable this feature, because unauthorized projects might attempt to retrieve an active token and access the API. %{linkStart}Learn more.%{linkEnd}"
msgstr "除éžå°‡å…¶ä»–專案加入到å…許清單中,å¦å‰‡ç¦æ­¢å…¶ä»–專案的CI/CD作業令牌存å–此專案。ç¦ç”¨æ­¤åŠŸèƒ½æœƒå­˜åœ¨å®‰å…¨é¢¨éšªï¼Œå› ç‚ºæœªç¶“授權的專案å¯èƒ½æœƒå˜—試å–得有效的令牌並存å–API。%{linkStart}了解更多%{linkEnd}。"
@@ -8933,8 +9045,8 @@ msgstr "%{code_open}.campfirenow.com%{code_close} å­åŸŸå。"
msgid "Can be manually deployed to"
msgstr "å¯ä»¥æ‰‹å‹•éƒ¨ç½²åˆ°"
-msgid "Can create groups:"
-msgstr "å¯ä»¥å‰µå»ºç¾¤çµ„:"
+msgid "Can create top level groups:"
+msgstr "å¯ä»¥å»ºç«‹æœ€ä¸Šå±¤ç¾¤çµ„:"
msgid "Can not delete primary training"
msgstr "ä¸èƒ½åˆªé™¤åˆç´šåŸ¹è¨“"
@@ -9320,6 +9432,9 @@ msgstr "標題變更尚未儲存"
msgid "Changes:"
msgstr "變更:"
+msgid "Changing any setting bellow doesn't require an application restart"
+msgstr "更改以下任何設置都ä¸éœ€è¦æ‡‰ç”¨ç¨‹å¼é‡æ–°å•Ÿå‹•"
+
msgid "Changing any setting here requires an application restart"
msgstr "更改此處的任何設定都需è¦é‡æ–°å•Ÿå‹•æ‡‰ç”¨ç¨‹å¼"
@@ -9410,6 +9525,9 @@ msgstr "檢查您的Docker 映åƒæª”是å¦å­˜åœ¨å·²çŸ¥æ¼æ´žã€‚"
msgid "Check your sign-up restrictions"
msgstr "檢查您的註冊é™åˆ¶"
+msgid "Checkin reminder has been enabled."
+msgstr "簽到æ醒已啟用。"
+
msgid "Checking %{text} availability…"
msgstr "正在檢查%{text}çš„å¯ç”¨æ€§..."
@@ -9466,8 +9584,8 @@ msgid "Checkout|%{quantity} storage pack"
msgid_plural "Checkout|%{quantity} storage packs"
msgstr[0] "%{quantity} 個儲存空間包"
-msgid "Checkout|%{selectedPlanText} plan"
-msgstr "%{selectedPlanText} 計劃"
+msgid "Checkout|%{selectedPlanText}"
+msgstr "%{selectedPlanText}"
msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -9721,6 +9839,9 @@ msgstr "é¸æ“‡æ¨¡æ¿â€¦"
msgid "Choose a type..."
msgstr "é¸æ“‡é¡žåž‹..."
+msgid "Choose an option"
+msgstr "é¸æ“‡ä¸€å€‹é¸é …"
+
msgid "Choose file…"
msgstr "é¸æ“‡æ–‡ä»¶â€¦"
@@ -9755,7 +9876,7 @@ msgid "CiCatalog|About this project"
msgstr "關於這個專案"
msgid "CiCatalog|Back to the CI/CD Catalog"
-msgstr ""
+msgstr "返回 CI/CD 目錄"
msgid "CiCatalog|CI/CD Catalog"
msgstr "CI/CD 目錄"
@@ -9764,7 +9885,7 @@ msgid "CiCatalog|CI/CD Catalog resource"
msgstr "CD 目錄資æº"
msgid "CiCatalog|Component ID not found, or you do not have permission to access component."
-msgstr ""
+msgstr "未找到元件ID,或您無權存å–該元件。"
msgid "CiCatalog|Create a pipeline component repository and make reusing pipeline configurations faster and easier."
msgstr "建立æµæ°´ç·šå…ƒä»¶ç‰ˆæœ¬åº«ï¼Œä½¿é‡è¤‡ä½¿ç”¨æµæ°´ç·šé…置更快更簡單。"
@@ -9785,7 +9906,7 @@ msgid "CiCatalog|Mark project as a CI/CD Catalog resource. %{linkStart}What is t
msgstr "將專案標示為 CI/CD 目錄資æºï¼Œ%{linkStart}什麼是 CI/CD 目錄?%{linkEnd}"
msgid "CiCatalog|No component available"
-msgstr ""
+msgstr "沒有å¯ç”¨çš„元件"
msgid "CiCatalog|No release available"
msgstr "沒有å¯ç”¨çš„發布版本"
@@ -9922,15 +10043,15 @@ msgstr "CI/CD 變數"
msgid "CiVariables|Cancel"
msgstr "å–消"
-msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr "ç›®å‰æ•¸å€¼ç„¡æ³•ä½¿ç”¨è®Šæ•¸é®ç½©"
-
msgid "CiVariables|Delete variable"
msgstr "刪除變數"
msgid "CiVariables|Do you want to delete the variable %{key}?"
msgstr "您è¦åˆªé™¤ %{key} 變數嗎?"
+msgid "CiVariables|Edit Variable"
+msgstr "編輯變數"
+
msgid "CiVariables|Environments"
msgstr "環境"
@@ -9982,9 +10103,6 @@ msgstr "清除輸入"
msgid "CiVariables|Remove variable"
msgstr "移除變數"
-msgid "CiVariables|Remove variable row"
-msgstr "移除變數行"
-
msgid "CiVariables|Run job"
msgstr "執行作業"
@@ -10006,12 +10124,24 @@ msgstr "讀å–繼承的 CI 變數時出ç¾éŒ¯èª¤ã€‚"
msgid "CiVariables|This %{entity} has %{currentVariableCount} defined CI/CD variables. The maximum number of variables per %{entity} is %{maxVariableLimit}. To add new variables, you must reduce the number of defined variables."
msgstr "該 %{entity} 具有 %{currentVariableCount} 已定義的 CI/CD 變數,æ¯å€‹ %{entity} 的最大變數數é‡ç‚º %{maxVariableLimit},è¦å¢žåŠ æ–°çš„變數,您必須先減少已定義變數的數é‡ã€‚"
+msgid "CiVariables|This variable value does not meet the masking requirements."
+msgstr ""
+
msgid "CiVariables|Type"
msgstr "é¡žåž‹"
+msgid "CiVariables|Unselect \"Expand variable reference\" if you want to use the variable value as a raw string."
+msgstr ""
+
msgid "CiVariables|Value"
msgstr "值"
+msgid "CiVariables|Value might contain a variable reference"
+msgstr ""
+
+msgid "CiVariables|Variable value will be evaluated as raw string."
+msgstr ""
+
msgid "CiVariables|Variable will be masked in job logs. Requires values to meet regular expression requirements."
msgstr "變數將在作業紀錄中被é®è”½ã€‚需è¦å€¼ä¾†æ»¿è¶³æ­£è¦è¡¨ç¤ºå¼è¦æ±‚。"
@@ -10027,9 +10157,6 @@ msgstr "變數儲存您å¯ä»¥åœ¨ä½œæ¥­è…³æœ¬ä¸­ä½¿ç”¨çš„資訊,例如密碼和
msgid "CiVariables|You have reached the maximum number of variables available. To add new variables, you must reduce the number of defined variables."
msgstr "您已é”到å¯ä½¿ç”¨è®Šæ•¸çš„最大數é‡ï¼Œè¦å¢žåŠ æ–°çš„變數,您必須先減少已定義變數的數é‡ã€‚"
-msgid "CiVariable|* (All environments)"
-msgstr "* (所有環境)"
-
msgid "CiVariable|All environments"
msgstr "所有環境"
@@ -10187,6 +10314,9 @@ msgstr "客戶端"
msgid "Clientside DSN"
msgstr "客戶端 DSN"
+msgid "Clientside traces sample rate"
+msgstr "客戶端追踪採樣率"
+
msgid "Clone"
msgstr "克隆 (Clone) "
@@ -10484,15 +10614,9 @@ msgstr "å¢é›†å¥åº·"
msgid "Cluster cache cleared."
msgstr "å¢é›†å¿«å–已清除。"
-msgid "Cluster is required for Stages::ClusterEndpointInserter"
-msgstr "Stages::ClusterEndpointInserter需è¦å¢é›†"
-
msgid "Cluster level"
msgstr "å¢é›†ç´šåˆ¥"
-msgid "Cluster type must be specified for Stages::ClusterEndpointInserter"
-msgstr "必須為 Stages::ClusterEndpointInserter 指定å¢é›†é¡žåž‹"
-
msgid "ClusterAgents|%{linkStart}View the documentation%{linkEnd} for advanced installation. Ensure you have your access token available."
msgstr "%{linkStart}查看高級安è£æ–‡æª”%{linkEnd} 。請確ä¿æ‚¨æœ‰å¯ç”¨çš„訪å•ä»¤ç‰Œã€‚"
@@ -10782,6 +10906,9 @@ msgstr "ClusterAgents|此代ç†äººæ²’有令牌"
msgid "ClusterAgents|To delete the agent, type %{name} to confirm:"
msgstr "ClusterAgents|è¦åˆªé™¤ä»£ç†äººï¼Œè«‹éµå…¥ %{name} 進行確èªï¼š"
+msgid "ClusterAgents|To manage more agents, %{linkStart}use Terraform%{linkEnd}."
+msgstr "è¦ç®¡ç†æ›´å¤šä»£ç†ï¼Œ %{linkStart}使用 Terraform%{linkEnd}。"
+
msgid "ClusterAgents|To revoke the token, type %{name} to confirm:"
msgstr "è¦æ’¤å›žæ†‘證,請輸入 %{name} 進行確èªï¼š"
@@ -10806,6 +10933,9 @@ msgstr "ClusterAgent|檢視全部 %{number} 個代ç†äºº"
msgid "ClusterAgents|View all %{number} clusters"
msgstr "ClusterAgents|檢視全部 %{number} 個å¢é›†"
+msgid "ClusterAgents|We only support 100 agents on the UI."
+msgstr "我們在 UI ä¸Šåƒ…æ”¯æ´ 100 個代ç†ã€‚"
+
msgid "ClusterAgents|We would love to learn more about your experience with the GitLab Agent."
msgstr "ClusterAgents|我們很想了解更多關於您使用 GitLab 代ç†çš„體驗。"
@@ -11229,9 +11359,6 @@ msgstr "程å¼ç¢¼å¯©æŸ¥"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "程å¼ç¢¼å¯©æŸ¥åˆ†æžé¡¯ç¤ºäº†ä¸€å€‹è™•æ–¼é–‹å•Ÿåˆä½µè«‹æ±‚階段的程å¼ç¢¼å¯©æŸ¥åˆ—表。 當å‰æ²’有此專案和/或篩é¸å™¨çš„åˆä½µè«‹æ±‚。"
-msgid "Code Suggestions add-on"
-msgstr "程å¼ç¢¼å»ºè­°æ’件"
-
msgid "Code Suggestions add-on status"
msgstr "程å¼å»ºè­°æ’件狀態"
@@ -11301,33 +11428,30 @@ msgstr "程å¼ç¢¼å»ºè­°SM為此實例啟用程å¼ç¢¼ç¢¼å»ºè­° %{beta}"
msgid "CodeSuggestionsSM|Enable Code Suggestions for users of this instance. %{link_start}What are Code Suggestions?%{link_end}"
msgstr "程å¼ç¢¼å»ºè­°SM為此實例的用戶啟用程å¼ç¢¼å»ºè­°ã€‚ %{link_start}什麼是程å¼ç¢¼å»ºè­°ï¼Ÿ%{link_end}"
-msgid "CodeSuggestionsSM|Enter new personal access token"
-msgstr "輸入新的個人存å–令牌"
-
-msgid "CodeSuggestionsSM|On GitLab.com, create a token. This token is required to use Code Suggestions on your self-managed instance. %{link_start}How do I create a token?%{link_end}"
-msgstr "程å¼ç¢¼å»ºè­°SM在 GitLab.com 上建立一個令牌。在您的自我管ç†å¯¦ä¾‹ä¸Šä½¿ç”¨ç¨‹å¼ç¢¼å»ºè­°éœ€è¦æ­¤ä»¤ç‰Œã€‚ %{link_start}如何建立令牌?%{link_end}"
-
-msgid "CodeSuggestionsSM|Personal access token"
-msgstr "個人存å–令牌"
-
-msgid "CodeSuggestionsThirdPartyAlert|%{code_suggestions_link_start}Code Suggestions%{link_end} now uses third-party AI services to provide higher quality suggestions. You can %{third_party_link_start}disable third-party services%{link_end} for your group, or disable Code Suggestions entirely in %{profile_settings_link_start}your user profile%{link_end}."
-msgstr "%{code_suggestions_link_start}Code Suggestions(程å¼ç¢¼å»ºè­°ï¼‰%{link_end} ç¾åœ¨ä½¿ç”¨ç¬¬ä¸‰æ–¹ AI æœå‹™æ供更高å“質的建議。您å¯ä»¥åœ¨æ‚¨çš„群組中 %{third_party_link_start}ç¦ç”¨ç¬¬ä¸‰æ–¹æœå‹™%{link_end},或在 %{profile_settings_link_start}您的使用者設定檔%{link_end} 中完全åœç”¨ Code Suggestions。"
-
-msgid "CodeSuggestionsThirdPartyAlert|We use third-party AI services to improve Code Suggestions."
-msgstr "我們使用第三方 AI æœå‹™ä¾†æ”¹é€²ç¨‹å¼ç¢¼å»ºè­°åŠŸèƒ½ã€‚"
-
msgid "CodeSuggestions|%{link_start}What are code suggestions?%{link_end}"
msgstr "%{link_start}什麼是程å¼ç¢¼å»ºè­°ï¼Ÿ%{link_end}"
msgid "CodeSuggestions|Code Suggestions"
msgstr "程å¼ç¢¼å»ºè­° "
+msgid "CodeSuggestions|Code Suggestions add-on assigned"
+msgstr ""
+
msgid "CodeSuggestions|Enable Code Suggestions"
msgstr "啟用程å¼ç¢¼å»ºè­°"
+msgid "CodeSuggestions|Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing."
+msgstr ""
+
msgid "CodeSuggestions|Get code suggestions as you write code in your IDE. %{link_start}Learn more%{link_end}."
msgstr "在您的整åˆé–‹ç™¼ç’°å¢ƒä¸­ç·¨å¯«ç¨‹å¼ç¢¼æ™‚,å¯ä»¥ç²å¾—程å¼ç¢¼å»ºè­°ã€‚%{link_start}了解更多%{link_end}。"
+msgid "CodeSuggestions|Introducing the Code Suggestions add-on"
+msgstr "導入程å¼ç¢¼å»ºè­°æ“´å……功能"
+
+msgid "CodeSuggestions|Introducing the Code&nbsp;Suggestions add&#8209;on"
+msgstr ""
+
msgid "CodeSuggestions|Projects in this group can use Code Suggestions"
msgstr "該群組中的專案å¯ä»¥ä½¿ç”¨ç¨‹å¼ç¢¼å»ºè­°"
@@ -11395,6 +11519,9 @@ msgstr "使用者世代表顯示éŽåŽ»%{months_included}個月內的狀æ³ã€‚åª
msgid "Collapse"
msgstr "收疊"
+msgid "Collapse AI-generated summary"
+msgstr "折疊 AI 產生的摘è¦"
+
msgid "Collapse all threads"
msgstr "收疊所有主題"
@@ -11753,9 +11880,6 @@ msgstr "比較修訂|載入分支/標籤列表時發生錯誤。請é‡è©¦ã€‚"
msgid "CompareRevisions|There was an error while searching the branch/tag list. Please try again."
msgstr "比較修訂|æœå°‹åˆ†æ”¯/標籤列表時發生錯誤。請é‡è©¦ã€‚"
-msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again."
-msgstr "比較修訂|更新分支/標籤列表時發生錯誤。請é‡è©¦ã€‚"
-
msgid "CompareRevisions|View open merge request"
msgstr "檢視開啟的åˆä½µè«‹æ±‚"
@@ -11801,6 +11925,9 @@ msgstr "åˆè¦ä¸­å¿ƒ"
msgid "Compliance framework"
msgstr "åˆè¦æ¡†æž¶"
+msgid "ComplianceFrameworks|Active compliance frameworks"
+msgstr "主動åˆè¦æ¡†æž¶"
+
msgid "ComplianceFrameworks|Add framework"
msgstr "添加框架"
@@ -11858,8 +11985,8 @@ msgstr "å–å¾—åˆè¦æ¡†æž¶è³‡æ–™éŒ¯èª¤ï¼Œè«‹é‡æ–°è¼‰å…¥é é¢æˆ–嘗試其它的
msgid "ComplianceFrameworks|Error setting the default compliance frameworks"
msgstr "é è¨­åˆè¦æ€§æ¡†æž¶è¨­å®šéŒ¯èª¤"
-msgid "ComplianceFrameworks|Frameworks that have been added will appear here."
-msgstr "已添加的框架將出ç¾åœ¨æ­¤è™•ã€‚"
+msgid "ComplianceFrameworks|Frameworks that have been added will appear here, start by creating a new one above."
+msgstr "已加入的框架將出ç¾åœ¨æ­¤è™•ï¼Œè«‹å…ˆåœ¨ä¸Šé¢å»ºç«‹ä¸€å€‹æ–°æ¡†æž¶ã€‚"
msgid "ComplianceFrameworks|Invalid format"
msgstr "無效格å¼"
@@ -12074,15 +12201,18 @@ msgstr "機密性"
msgid "Configuration help"
msgstr "組態å”助說明"
+msgid "Configure"
+msgstr "é…ç½®"
+
msgid "Configure %{italic_start}What's new%{italic_end} drawer and content."
msgstr "設定 %{italic_start}What's new%{italic_end} 內容。"
-msgid "Configure %{link} to track events. %{link_start}Learn more.%{link_end}"
-msgstr "設定 %{link} 跟蹤事件,%{link_start}瞭解更多信æ¯ã€‚%{link_end}"
-
msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and %{housekeeping_link_start}housekeeping%{link_end} on repositories."
msgstr "在版本庫上設定 %{repository_checks_link_start}版本庫檢查%{link_end} 和 %{housekeeping_link_start}例行維護%{link_end}。"
+msgid "Configure %{snowplow_link_start}Snowplow%{snowplow_link_end} to track events. %{help_link_start}Learn more.%{help_link_end}"
+msgstr "é…ç½® %{snowplow_link_start} Snowplow %{snowplow_link_end} 來跟踪事件,%{help_link_start}了解更多。%{help_link_end}"
+
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
msgstr "設定 CAPTCHAã€IP 地å€é™åˆ¶å’Œå…¶ä»–å垃圾郵件措施。"
@@ -12146,6 +12276,9 @@ msgstr "é…置進階權é™ã€å¤§åž‹æ–‡ä»¶å­˜å„²ã€é›™å› å­èªè­‰å’ŒCI/CD設定ã
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
msgstr "設定進階權é™ã€å¤§æ–‡ä»¶å­˜å„²ã€é›™å› å­èªè­‰å’Œå®¢æˆ¶é—œä¿‚設定。"
+msgid "Configure checkin reminder frequency"
+msgstr "設置簽到æ醒頻率"
+
msgid "Configure custom rules for Jira issue key matching"
msgstr "為 Jira è­°é¡ŒéµåŒ¹é…設定自定義è¦å‰‡"
@@ -12317,6 +12450,9 @@ msgstr "連線失敗"
msgid "Consistency guarantee method"
msgstr "一致性ä¿éšœæ–¹æ³•"
+msgid "Contact sales"
+msgstr ""
+
msgid "Contact support"
msgstr "è¯ç¹«æ”¯æ´"
@@ -12836,6 +12972,9 @@ msgstr "在 %{resourceParentLink} 中新增了 %{targetLink} 設計。"
msgid "ContributionEvent|Approved merge request %{targetLink} in %{resourceParentLink}."
msgstr "已核准 %{resourceParentLink} 中的 %{targetLink} åˆä½µè«‹æ±‚。"
+msgid "ContributionEvent|Archived design in %{resourceParentLink}."
+msgstr "在 %{resourceParentLink} çš„å·²å°å­˜è¨­è¨ˆã€‚"
+
msgid "ContributionEvent|Closed Epic %{targetLink} in %{resourceParentLink}."
msgstr "在 %{resourceParentLink} 中關閉了 %{targetLink} å²è©©ã€‚"
@@ -12869,6 +13008,30 @@ msgstr "在 %{resourceParentLink} 中關閉了 %{targetLink} 任務。"
msgid "ContributionEvent|Closed test case %{targetLink} in %{resourceParentLink}."
msgstr "在 %{resourceParentLink} 中關閉了 %{targetLink} 測試案例。"
+msgid "ContributionEvent|Commented on %{noteableLink}."
+msgstr "評論了 %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on Epic %{noteableLink} in %{resourceParentLink}."
+msgstr "在 %{resourceParentLink} 中評論了 Epic %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on commit %{noteableLink} in %{resourceParentLink}."
+msgstr "å° %{resourceParentLink}中的æ交 %{noteableLink} 進行了評論。"
+
+msgid "ContributionEvent|Commented on design %{noteableLink} in %{resourceParentLink}."
+msgstr "在%{resourceParentLink}中å°è¨­è¨ˆ%{noteableLink}發表了評論。"
+
+msgid "ContributionEvent|Commented on issue %{noteableLink} in %{resourceParentLink}."
+msgstr "在 %{resourceParentLink}中評論了議題 %{noteableLink}。"
+
+msgid "ContributionEvent|Commented on merge request %{noteableLink} in %{resourceParentLink}."
+msgstr "å° %{resourceParentLink}中的åˆä½µè«‹æ±‚ %{noteableLink} 進行了評論。"
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink} in %{resourceParentLink}."
+msgstr "å° %{resourceParentLink}中的片段 %{noteableLink} 進行了評論。"
+
+msgid "ContributionEvent|Commented on snippet %{noteableLink}."
+msgstr "評論了代碼片段 %{noteableLink}。"
+
msgid "ContributionEvent|Created project %{resourceParentLink}."
msgstr "已建立 %{resourceParentLink} 專案。"
@@ -12881,9 +13044,18 @@ msgstr "已在 %{resourceParentLink} 中建立 %{targetLink} wiki é é¢ 。"
msgid "ContributionEvent|Deleted branch %{refLink} in %{resourceParentLink}."
msgstr "刪除了 %{resourceParentLink} 中的 %{refLink} 分支。"
+msgid "ContributionEvent|Deleted milestone in %{resourceParentLink}."
+msgstr "在 %{resourceParentLink} 中的已刪除里程碑。"
+
+msgid "ContributionEvent|Deleted resource."
+msgstr "已刪除資æºã€‚"
+
msgid "ContributionEvent|Deleted tag %{refLink} in %{resourceParentLink}."
msgstr "已刪除 %{resourceParentLink} 中的 %{refLink} 標籤。"
+msgid "ContributionEvent|Deleted wiki page in %{resourceParentLink}."
+msgstr "在 %{resourceParentLink} 中的已刪除 wiki é é¢ã€‚"
+
msgid "ContributionEvent|Joined project %{resourceParentLink}."
msgstr "已加入專案 %{resourceParentLink}。"
@@ -12939,37 +13111,46 @@ msgid "ContributionEvent|Removed due to membership expiration from %{resourcePar
msgstr "因為æˆå“¡è³‡æ ¼éŽæœŸè€Œè¢«å¾ž %{resourceParentLink} 移除。"
msgid "ContributionEvent|Reopened Epic %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿäº†å²è©© %{targetLink}。"
msgid "ContributionEvent|Reopened incident %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿäº†äº‹æ•… %{targetLink}。"
msgid "ContributionEvent|Reopened issue %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿäº†è­°é¡Œ %{targetLink} 。"
msgid "ContributionEvent|Reopened key result %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿé—œéµçµæžœ %{targetLink}。"
msgid "ContributionEvent|Reopened merge request %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿåˆä½µè«‹æ±‚ %{targetLink}。"
msgid "ContributionEvent|Reopened milestone %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿé‡Œç¨‹ç¢‘ %{targetLink}。"
msgid "ContributionEvent|Reopened objective %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿç›®æ¨™ %{targetLink}。"
msgid "ContributionEvent|Reopened requirement %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿéœ€æ±‚ %{targetLink}。"
msgid "ContributionEvent|Reopened resource."
-msgstr ""
+msgstr "é‡æ–°é–‹å•Ÿè³‡æºã€‚"
msgid "ContributionEvent|Reopened task %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿä»»å‹™ %{targetLink}。"
msgid "ContributionEvent|Reopened test case %{targetLink} in %{resourceParentLink}."
-msgstr ""
+msgstr "在 %{resourceParentLink}中é‡æ–°é–‹å•Ÿæ¸¬è©¦ç”¨ä¾‹ %{targetLink}。"
+
+msgid "ContributionEvent|Updated design %{targetLink} in %{resourceParentLink}."
+msgstr "已更新%{resourceParentLink}中的%{targetLink}設計。"
+
+msgid "ContributionEvent|Updated resource."
+msgstr "已更新的資æºã€‚"
+
+msgid "ContributionEvent|Updated wiki page %{targetLink} in %{resourceParentLink}."
+msgstr "在%{resourceParentLink}中更新了維基é é¢%{targetLink}。"
msgid "ContributionEvent|…and %{count} more commits. %{linkStart}Compare%{linkEnd}."
msgstr "…和%{count}更多æ交,%{linkStart}比較%{linkEnd}。"
@@ -13517,6 +13698,9 @@ msgstr "建立發布版本"
msgid "Create requirement"
msgstr "建立需求"
+msgid "Create rules for target branches in merge requests."
+msgstr "在åˆä½µè«‹æ±‚中為目標分支創建è¦å‰‡ã€‚"
+
msgid "Create service account"
msgstr "建立æœå‹™å¸³è™Ÿ"
@@ -13895,9 +14079,6 @@ msgstr "已增加組織"
msgid "Crm|Organization has been updated."
msgstr "組織已更新。"
-msgid "Cron Timezone"
-msgstr "Cron 時å€"
-
msgid "Cron time zone"
msgstr "Cron 時å€"
@@ -14235,9 +14416,6 @@ msgstr "是時候æ¢å¾©æœå‹™äº†"
msgid "CycleAnalytics|Total time"
msgstr "總時間"
-msgid "CycleAnalytics|group dropdown filter"
-msgstr "群組下拉é¸å–®éŽæ¿¾å™¨"
-
msgid "CycleAnalytics|not allowed for the given start event"
msgstr "ä¸é©ç”¨æ–¼çµ¦å®šçš„開始事件"
@@ -14411,6 +14589,9 @@ msgstr "中"
msgid "DORA4Metrics|Merge request throughput"
msgstr "åˆä½µè«‹æ±‚的通éŽé‡"
+msgid "DORA4Metrics|Metrics comparison for %{name}"
+msgstr "%{name} 的指標比較"
+
msgid "DORA4Metrics|Metrics comparison for %{name} group"
msgstr "%{name} 群組的指標比較"
@@ -14501,6 +14682,9 @@ msgstr "æœå‹™æ¢å¾©æ™‚間(中ä½å¤©æ•¸ï¼‰"
msgid "DORA4Metrics|To help us improve the Show forecast feature, please share feedback about your experience in %{linkStart}this issue%{linkEnd}."
msgstr "為了幫助我們改進“顯示é æ¸¬â€åŠŸèƒ½ï¼Œè«‹åœ¨%{linkStart}æ­¤å•é¡Œ%{linkEnd}中分享您的æ„見。"
+msgid "DORA4Metrics|To help us improve the Value Stream Management Dashboard, please share feedback about your experience in this %{linkStart}survey%{linkEnd}."
+msgstr "為了幫助我們改進價值æµç®¡ç†å„€è¡¨æ¿ï¼Œè«‹åˆ†äº«æ‚¨åœ¨æ­¤ %{linkStart}調查%{linkEnd} 中的經驗å饋。"
+
msgid "DORA4Metrics|Took 1 day or less to restore service when a service incident or a defect that impacts users occurs."
msgstr "發生影響使用者的æœå‹™äº‹ä»¶æˆ–ç¼ºé™·æ™‚ï¼Œéœ€è¦ 1 天或更短的時間來æ¢å¾©æœå‹™ã€‚"
@@ -14723,6 +14907,9 @@ msgstr "最å°å€¼ = 0(未啟用超時),最大值 = 2880 分é˜"
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
msgstr "最å°å€¼ = 1 秒,最大值 = 3600 秒"
+msgid "DastProfiles|Modifying the URL will clear any previously entered values for the additional request headers and password fields."
+msgstr "修改 URL 將會清除先å‰ç‚ºå…¶ä»–請求標頭與密碼欄ä½è¼¸å…¥çš„任何值。"
+
msgid "DastProfiles|Monitors all HTTP requests sent to the target to find potential vulnerabilities."
msgstr "監控發é€åˆ°ç›®æ¨™çš„所有 HTTP 請求以發ç¾æ½›åœ¨æ¼æ´žã€‚"
@@ -15226,9 +15413,6 @@ msgstr "使用 Cron 語法定義自訂模å¼"
msgid "Define custom rules for what constitutes spam, independent of Akismet"
msgstr "é‡å°Akismet定義構æˆåžƒåœ¾éƒµä»¶çš„自訂è¦å‰‡"
-msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here."
-msgstr "在%{code_open}.githab-ci.yml%{code_close}的部署階段中定義環境來追蹤部署。"
-
msgid "Define how approval rules are applied to merge requests."
msgstr "定義如何將核准è¦å‰‡å¥—用於åˆä½µè«‹æ±‚。"
@@ -15350,9 +15534,6 @@ msgstr "刪除標記:%{labelName}"
msgid "Delete pipeline"
msgstr "刪除æµæ°´ç·š"
-msgid "Delete pipeline schedule"
-msgstr "刪除æµæ°´ç·š (pipeline) 排程"
-
msgid "Delete project"
msgstr "刪除專案"
@@ -15568,6 +15749,9 @@ msgstr "ä½ç½®å’Œä¾è³´è·¯å¾‘"
msgid "Dependencies|Packager"
msgstr "å°è£å·¥å…·"
+msgid "Dependencies|Project list unavailable"
+msgstr "專案清單ä¸å¯ç”¨"
+
msgid "Dependencies|Projects"
msgstr "專案"
@@ -15586,6 +15770,9 @@ msgstr "元件ä¾è³´è·¯å¾‘基於鎖定文件,å¯èƒ½æœ‰å¤šå€‹è·¯å¾‘。在這些
msgid "Dependencies|There may be multiple paths"
msgstr "å¯èƒ½æœ‰å¤šå€‹è·¯å¾‘"
+msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
+msgstr "æ­¤ç¾¤çµ„çš„ä¸‹å±¤ç¾¤çµ„æ•¸è¶…éŽ 600 個的上é™ã€‚ç›®å‰æˆ‘們無法準確顯示專案清單。請存å–å­ç¾¤çµ„ä¾è³´é—œä¿‚清單以檢視此資訊,或åƒé–±%{linkStart}ä¾è³´é—œä¿‚清單說明%{linkEnd}é é¢ä»¥å–得更多資訊。"
+
msgid "Dependencies|Toggle vulnerability list"
msgstr "切æ›æ¼æ´žæ¸…å–®"
@@ -15766,6 +15953,12 @@ msgstr "時å€"
msgid "DeployKeys|+%{count} others"
msgstr "+%{count} 其他"
+msgid "DeployKeys|Add new deploy key"
+msgstr "新增部署密鑰"
+
+msgid "DeployKeys|Add new key"
+msgstr "新增密鑰"
+
msgid "DeployKeys|Current project"
msgstr "ç›®å‰å°ˆæ¡ˆ"
@@ -15793,8 +15986,8 @@ msgstr "授予此金鑰的寫入權é™"
msgid "DeployKeys|Loading deploy keys"
msgstr "載入部署金鑰"
-msgid "DeployKeys|No deploy keys found. Create one with the form above."
-msgstr "沒有找到部署金鑰。請使用上é¢çš„表單建立部署金鑰。"
+msgid "DeployKeys|No deploy keys found, start by adding a new one above."
+msgstr "未發ç¾éƒ¨ç½²å¯†é‘°ï¼Œè«‹å…ˆåœ¨ä¸Šé¢åŠ å…¥ä¸€å€‹æ–°å¯†é‘°ã€‚"
msgid "DeployKeys|Privately accessible deploy keys"
msgstr "ç§æœ‰å­˜å–的部署金鑰"
@@ -15808,8 +16001,8 @@ msgstr "公開存å–的部署金鑰"
msgid "DeployKeys|Read access only"
msgstr "唯讀權é™"
-msgid "DeployTokens|Active Deploy Tokens (%{active_tokens})"
-msgstr "啟用部署令牌(%{active_tokens})"
+msgid "DeployTokens|Active deploy tokens"
+msgstr "啟用部署令牌"
msgid "DeployTokens|Allows read and write access to registry images."
msgstr "å…許å°è¨»å†Šè¡¨æ˜ åƒé€²è¡Œè®€å¯«å­˜å–。"
@@ -15832,6 +16025,9 @@ msgstr "å…許以唯讀權é™è®€å–該版本庫。"
msgid "DeployTokens|Allows write access to registry images."
msgstr "å…許寫入該映åƒè¨»å†Šåº«ã€‚"
+msgid "DeployTokens|Cancel"
+msgstr "å–消"
+
msgid "DeployTokens|Copy deploy token"
msgstr "複製部署令牌"
@@ -15892,8 +16088,8 @@ msgstr "有效範åœ"
msgid "DeployTokens|Scopes (select at least one)"
msgstr "ç¯„åœ (至少é¸æ“‡ä¸€é …)"
-msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
-msgstr "此 %{entity_type} 沒有啟用的部署令牌。"
+msgid "DeployTokens|This %{entity_type} has no active deploy tokens."
+msgstr "此 %{entity_type} 沒有活動部署令牌。"
msgid "DeployTokens|This action cannot be undone."
msgstr "該動作作無法復原。"
@@ -15910,12 +16106,12 @@ msgstr "使用者å稱"
msgid "DeployTokens|Username (optional)"
msgstr "使用者å稱 (å¯é¸)"
-msgid "DeployTokens|Your New Deploy Token"
-msgstr "您的新部署令牌"
-
msgid "DeployTokens|Your new Deploy Token username"
msgstr "您的新部署令牌使用者å稱"
+msgid "DeployTokens|Your new deploy token"
+msgstr "您的新部署令牌"
+
msgid "DeployTokens|Your new group deploy token has been created."
msgstr "您的新群組佈署令牌已經建立。"
@@ -15997,6 +16193,12 @@ msgstr "您已在 %{time} 核准"
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
msgstr "核准將從部署#%{deploymentIid}執行手動作業,拒絕將使手動作業失敗。"
+msgid "DeploymentApproval|Deployment approved"
+msgstr "部署已核准"
+
+msgid "DeploymentApproval|Deployment rejected"
+msgstr "部署被拒絕"
+
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr "部署層: %{tier}"
@@ -16067,9 +16269,6 @@ msgstr "在%{code_open}.githab-ci.yml%{code_close}的部署階段中定義環境
msgid "Deployments|You don't have any deployments right now."
msgstr "您ç¾åœ¨æ²’有任何部署。"
-msgid "Deployment|API"
-msgstr "API"
-
msgid "Deployment|Cancelled"
msgstr "å·²å–消"
@@ -16082,6 +16281,24 @@ msgstr "部署 ID"
msgid "Deployment|Failed"
msgstr "失敗"
+msgid "Deployment|Flux sync failed"
+msgstr "Flux åŒæ­¥å¤±æ•—"
+
+msgid "Deployment|Flux sync reconciled successfully"
+msgstr "Flux å·²æˆåŠŸåŒæ­¥å”調"
+
+msgid "Deployment|Flux sync reconciling"
+msgstr "Flux åŒæ­¥å”調"
+
+msgid "Deployment|Flux sync stalled"
+msgstr "Flux åŒæ­¥åœæ»¯"
+
+msgid "Deployment|Flux sync status is unavailable"
+msgstr "Flux åŒæ­¥ç‹€æ…‹ä¸å¯ç”¨"
+
+msgid "Deployment|Flux sync status is unknown"
+msgstr "Flux åŒæ­¥ç‹€æ…‹æœªçŸ¥"
+
msgid "Deployment|Latest Deployed"
msgstr "最新部署"
@@ -16097,12 +16314,15 @@ msgstr "已略éŽ"
msgid "Deployment|Success"
msgstr "æˆåŠŸ"
-msgid "Deployment|This deployment was created using the API"
-msgstr "此部署使用API建立"
+msgid "Deployment|Sync status is unknown. %{linkStart}How do I configure Flux for my deployment?%{linkEnd}"
+msgstr "åŒæ­¥ç‹€æ…‹æœªçŸ¥ï¼Œ %{linkStart}如何為我的部署é…ç½® Flux?%{linkEnd}"
msgid "Deployment|Triggerer"
msgstr "觸發器"
+msgid "Deployment|Unable to detect state. %{linkStart}How are states detected?%{linkEnd}"
+msgstr "無法檢測狀態, %{linkStart}如何檢測狀態?%{linkEnd}"
+
msgid "Deployment|Unavailable"
msgstr "ä¸å¯ç”¨"
@@ -16172,12 +16392,6 @@ msgstr "設計"
msgid "Design Management files and data"
msgstr "設計管ç†æ–‡ä»¶å’Œè³‡æ–™"
-msgid "Design repositories"
-msgstr "設計版本庫"
-
-msgid "Design repository"
-msgstr "設計版本庫"
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr "%{current_design}/%{designs_count}"
@@ -17366,9 +17580,6 @@ msgstr "é›»å­éƒµä»¶å·²å‚³é€"
msgid "Email the pipeline status to a list of recipients."
msgstr "å°‡æµæ°´ç·šç‹€æ…‹é€éŽé›»å­éƒµä»¶ç™¼é€çµ¦æ¸…單上的收件人。"
-msgid "Email updates (optional)"
-msgstr "發é€é›»å­éƒµä»¶æ›´æ–°ï¼ˆå¯é¸ï¼‰"
-
msgid "Email:"
msgstr "é›»å­éƒµä»¶ï¼š"
@@ -17411,6 +17622,9 @@ msgstr "%{emails}, %{andMore} 將收到您的留言通知。"
msgid "EmailParticipantsWarning|and %{moreCount} more"
msgstr "é›»å­éƒµä»¶åƒèˆ‡è€…警告|還有 %{moreCount} 個"
+msgid "EmailVerification|Update your email to a valid permanent address. If you use a temporary email, you won't be able to sign in later."
+msgstr "請更新您的電å­éƒµä»¶åœ°å€ç‚ºæœ‰æ•ˆçš„永久地å€ï¼Œå¦‚果您使用臨時郵件地å€ï¼Œæ‚¨ä¹‹å¾Œå°‡ç„¡æ³•å†ç™»éŒ„。"
+
msgid "Emails"
msgstr "é›»å­éƒµä»¶"
@@ -17549,9 +17763,6 @@ msgstr "啟用群組執行器"
msgid "Enable header and footer in emails"
msgstr "在電å­éƒµä»¶ä¸­å•Ÿç”¨é é¦–å’Œé å°¾"
-msgid "Enable in-product marketing emails"
-msgstr "接收產å“營銷電å­éƒµä»¶"
-
msgid "Enable incident management inbound alert limit"
msgstr "啟用事件管ç†è­¦å ±é™åˆ¶"
@@ -17573,8 +17784,8 @@ msgstr "僅å°å¯å®‰å…¨å­˜å„²å®¢æˆ¶ç«¯æ©Ÿå¯†çš„å—信任後端æœå‹™å™¨å°ˆç”¨çš„
msgid "Enable or disable version check and Service Ping."
msgstr "啟用或ç¦ç”¨ç‰ˆæœ¬æª¢æŸ¥å’ŒService Ping。"
-msgid "Enable rate limiting for POST requests to the specified paths"
-msgstr "為指定路徑的 POST 請求啟用速率é™åˆ¶"
+msgid "Enable rate limiting for requests to the specified paths"
+msgstr "為指定路徑的請求啟用速率é™åˆ¶"
msgid "Enable reCAPTCHA"
msgstr "啟用 reCAPTCHA"
@@ -17687,9 +17898,6 @@ msgstr "å°æ‰€æœ‰ä½¿ç”¨è€…登入強制執行雙因å­èªè­‰ã€‚"
msgid "Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}"
msgstr "通éŽå°‡æœå‹™å¸³è™Ÿé‡‘鑰存儲在 secret 管ç†å™¨ä¸­ä¾†å¢žå¼·å®‰å…¨æ€§ - 瞭解更多關於 %{docLinkStart}使用 GitLab%{docLinkEnd} 進行 secret 管ç†çš„訊æ¯"
-msgid "Enhance your coding experience with intelligent recommendations. %{linkStart}Code Suggestions%{linkEnd} uses generative AI to suggest code while you're developing. Not available for users with the Guest role."
-msgstr "é€éŽæ™ºèƒ½å»ºè­°ï¼Œæå‡æ‚¨çš„程å¼ç¢¼æ’°å¯«é«”驗。 %{linkStart}程å¼ç¢¼å»ºè­°%{linkEnd} 使用生æˆå¼äººå·¥æ™ºæ…§ï¼Œåœ¨æ‚¨é–‹ç™¼æ™‚æ供程å¼ç¢¼æ’°å¯«å»ºè­°ã€‚此功能ä¸é©ç”¨æ–¼è¨ªå®¢è§’色的使用者。"
-
msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd} of your CI pipeline to track deployments to your cluster."
msgstr "如需追蹤到å¢é›†çš„部署,請確ä¿æ‚¨çš„%{linkStart}環境包å«æ–¼CIæµæ°´ç·šçš„部署階段%{linkEnd}。"
@@ -17801,8 +18009,8 @@ msgstr "環境"
msgid "Environment scope"
msgstr "環境範åœ"
-msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr "æ­¤GitLab執行個體上的環境變é‡è¢«é è¨­é…置為%{link_start}å—ä¿è­·%{link_end}."
+msgid "Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default."
+msgstr "é è¨­æƒ…æ³ä¸‹ï¼Œæ­¤ GitLab 執行個體上的環境變數設定為 %{help_link_start}protected%{help_link_end}。"
msgid "Environment:"
msgstr "環境:"
@@ -17948,12 +18156,18 @@ msgstr "開始使用環境"
msgid "Environments|GitLab agent"
msgstr "GitLab 代ç†"
+msgid "Environments|HelmReleases"
+msgstr "HelmReleases"
+
msgid "Environments|Job"
msgstr "作業"
msgid "Environments|Kubernetes namespace (optional)"
msgstr "環境Kubernetes 命å空間(å¯é¸ï¼‰"
+msgid "Environments|Kustomizations"
+msgstr "定制"
+
msgid "Environments|Learn more about stopping environments"
msgstr "了解更多關於如何終止環境的訊æ¯"
@@ -17999,6 +18213,12 @@ msgstr "還原 %{name} 環境?"
msgid "Environments|Search by environment name"
msgstr "ä¾ç’°å¢ƒå稱查詢"
+msgid "Environments|Select Flux resource"
+msgstr "é¸å– Flux 資æº"
+
+msgid "Environments|Select Flux resource (optional)"
+msgstr "é¸å– Flux 資æºï¼ˆå¯é¸ï¼‰"
+
msgid "Environments|Select agent"
msgstr "é¸æ“‡ä»£ç†"
@@ -18035,6 +18255,9 @@ msgstr "這動作將在該環境 %{docsStart} é‡è©¦æœ€æ–°éƒ¨ç½² %{docsEnd} çš„
msgid "Environments|This action will %{docsStart}roll back this environment%{docsEnd} to a previously successful deployment for commit %{commitId}. Are you sure you want to continue?"
msgstr "這動作將 %{docsStart}該環境回退%{docsEnd}到先å‰æˆåŠŸéƒ¨ç½²çš„ %{commitId} æ交。您確定è¦ç¹¼çºŒå—Žï¼Ÿ"
+msgid "Environments|Unable to access the following resources from this environment. Check your authorization on the following and try again:"
+msgstr "無法從此環境存å–以下資æºï¼Œè«‹æª¢æŸ¥æ‚¨å°ä»¥ä¸‹è³‡æºçš„授權並é‡è©¦ï¼š"
+
msgid "Environments|Upcoming"
msgstr "å³å°‡åˆ°ä¾†"
@@ -18137,6 +18360,12 @@ msgstr "åŒæ­¥ç‹€æ…‹"
msgid "Environment|There was an error connecting to the cluster agent."
msgstr "環境連接到å¢é›†ä»£ç†æ™‚出錯。"
+msgid "Environment|There was an error fetching %{resourceType}."
+msgstr "æ“·å– %{resourceType} 時發生錯誤。"
+
+msgid "Environment|Unauthorized to access %{resourceType} from this environment."
+msgstr "æœªç¶“æŽˆæ¬Šå¾žæ­¤ç’°å¢ƒå­˜å– %{resourceType}。"
+
msgid "Environment|Unauthorized to access the cluster agent from this environment. Check your authentication and try again."
msgstr "環境無權é™å¾žæ­¤ç’°å¢ƒå­˜å–å¢é›†ä»£ç†ã€‚檢查您的身份驗證並é‡è©¦ã€‚"
@@ -18891,6 +19120,9 @@ msgstr "ç¾æœ‰çš„登入方法å¯èƒ½æœƒè¢«ç§»é™¤"
msgid "Expand"
msgstr "展開"
+msgid "Expand AI-generated summary"
+msgstr "展開 AI 產生的摘è¦"
+
msgid "Expand all"
msgstr "展開全部"
@@ -19137,6 +19369,9 @@ msgstr "https://example.com/xxx/wiki/..."
msgid "Facebook"
msgstr "Facebook"
+msgid "Factually incorrect"
+msgstr ""
+
msgid "Fail"
msgstr "失敗"
@@ -19791,9 +20026,6 @@ msgstr "ä¾ç•¶å‰å·²æ­¸æª”的測試用例éŽæ¿¾ã€‚"
msgid "Filter by test cases that are currently open."
msgstr "ä¾ç•¶å‰é–‹æ”¾çš„測試用例進行éŽæ¿¾ã€‚"
-msgid "Filter by user"
-msgstr "ä¾ä½¿ç”¨è€…éŽæ¿¾"
-
msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr "éŽæ¿¾åƒæ•¸ç„¡æ•ˆã€‚確ä¿çµæŸæ—¥æœŸæ™šæ–¼é–‹å§‹æ—¥æœŸã€‚"
@@ -19818,9 +20050,6 @@ msgstr "éŽæ¿¾çµæžœ..."
msgid "Filter users"
msgstr "éŽæ¿¾ä½¿ç”¨è€…"
-msgid "Filter..."
-msgstr "éŽæ¿¾..."
-
msgid "Finalizing"
msgstr "正在完æˆ"
@@ -20188,33 +20417,6 @@ msgstr "å…費的最上層群組將很快會被é™åˆ¶ç‚º%{free_users_limit}個ä½
msgid "Free trial will expire in %{days}"
msgstr "å…費試用期將在 %{days} 天後到期"
-msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr "或者,您å¯ä»¥å‡ç´šåˆ° GitLab Premium 或 GitLab Ultimate:"
-
-msgid "FreeUserCap|Explore paid plans"
-msgstr "探查付費計劃"
-
-msgid "FreeUserCap|Explore paid plans:"
-msgstr "探查付費計劃:"
-
-msgid "FreeUserCap|It looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\", according to the check we ran on %{date_time}. You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
-msgstr "根據我們在 %{date_time} 執行的檢查,您似乎已é”到“%{namespace_name}†的%{free_user_limit} æˆå“¡é™åˆ¶ã€‚您無法å†å¢žåŠ ï¼Œä½†æ‚¨å¯ä»¥ç®¡ç†ç¾æœ‰æˆå“¡ï¼Œä¾‹å¦‚,通éŽåˆªé™¤ä¸æ´»èºçš„æˆå“¡ä¸¦ç”¨æ–°æˆå“¡æ›¿æ›ä»–們。"
-
-msgid "FreeUserCap|Manage members"
-msgstr "æˆå“¡ç®¡ç†"
-
-msgid "FreeUserCap|Manage members:"
-msgstr "æˆå“¡ç®¡ç†:"
-
-msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
-msgstr "è¦å–得更多æˆå“¡ï¼Œå¯ä»¥%{trial_link_start} 開始試用 %{trial_link_end} 或 %{upgrade_link_start}å‡ç´š%{upgrade_link_end} 到 GitLab Premium 或 GitLab Ultimate。"
-
-msgid "FreeUserCap|To get more members start a trial:"
-msgstr "開始試用以å–得更多æˆå“¡æ•¸ï¼š"
-
-msgid "FreeUserCap|You've reached your member limit!"
-msgstr "您已經é”到您的æˆå“¡äººæ•¸ä¸Šé™ï¼"
-
msgid "Freeze end"
msgstr "çµæŸå‡çµ"
@@ -20907,6 +21109,12 @@ msgstr "ç²å¾—å…費的實體評估"
msgid "Get a support subscription"
msgstr "å–得支æ´è¨‚é–±"
+msgid "Get free trial"
+msgstr "å–å¾—å…費試用"
+
+msgid "Get more information about troubleshooting pipelines"
+msgstr "å–得關於æµæ°´ç·šæ•…障排除的更多資訊"
+
msgid "Get started"
msgstr "開始使用"
@@ -21234,6 +21442,9 @@ msgstr "未驗證"
msgid "GitLabPages|Updating your Pages configuration..."
msgstr "正在更新您的é é¢é…ç½®..."
+msgid "GitLabPages|Use multiple versions"
+msgstr "使用多é‡ç‰ˆæœ¬"
+
msgid "GitLabPages|Use unique domain"
msgstr "使用唯一網域"
@@ -21249,6 +21460,9 @@ msgstr "啟用後,將生æˆä¸€å€‹å”¯ä¸€çš„網域來存å–é é¢ã€‚"
msgid "GitLabPages|When enabled, all attempts to visit your website through HTTP are automatically redirected to HTTPS using a response with status code 301. Requires a valid certificate for all domains. %{docs_link_start}Learn more.%{link_end}"
msgstr "啟用後,所有通éŽHTTPçš„å­˜å–嘗試都會自動é‡å®šå‘到HTTPS,使用狀態代碼301。 需è¦å°æ‰€æœ‰åŸŸå有效的證書。%{docs_link_start}瞭解更多訊æ¯ã€‚%{link_end}"
+msgid "GitLabPages|When enabled, you can create multiple versions of your pages site."
+msgstr "啟用後,您å¯ä»¥å»ºç«‹é é¢ç¶²ç«™çš„多個版本。"
+
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with subdomains of subdomains. If your namespace or groupname contains a dot, it does not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages work if you don't redirect HTTP to HTTPS. %{docs_link_start}Learn more.%{link_end}"
msgstr "當在 GitLab 執行個體 (%{pages_host})的一般域å下使用 Pages 時,您ä¸èƒ½ä½¿ç”¨ HTTPS 與å­åŸŸçš„å­åŸŸå。 如果您的命å空間或群組å稱包å«ä¸€å€‹é»žï¼Œè©²å稱無效。這是一個 HTTP On TLS å”è­°çš„é™åˆ¶ã€‚ 如果您ä¸å°‡ HTTP é‡å®šå‘到 HTTPS ,HTTP é é¢å¯ä»¥æ­£å¸¸å·¥ä½œã€‚ %{docs_link_start}瞭解更多訊æ¯ã€‚%{link_end}"
@@ -21264,12 +21478,6 @@ msgstr "您的專案已é‡å° Pages 進行了設定,ç¾åœ¨æˆ‘們必須等待æµ
msgid "Gitaly Servers"
msgstr "Gitaly伺æœå™¨"
-msgid "Gitaly relative path:"
-msgstr "Gitaly 相å°è·¯å¾‘:"
-
-msgid "Gitaly storage name:"
-msgstr "Gitaly 存儲å稱:"
-
msgid "Gitaly timeouts"
msgstr "Gitaly 逾時"
@@ -21390,8 +21598,8 @@ msgstr "é…ç½®ç‚ºè®€å– GitLab 專案的 Gitpod 執行個體的 URL,例如 htt
msgid "Gitpod|To use Gitpod you must first enable the feature in the integrations section of your %{linkStart}user preferences%{linkEnd}."
msgstr "è¦ä½¿ç”¨ Gitpod,您必須首先在您的%{linkStart}使用者å好設置%{linkEnd}çš„æ•´åˆéƒ¨åˆ†ä¸­å•Ÿç”¨è©²åŠŸèƒ½ã€‚"
-msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{link_start}How do I enable it?%{link_end} "
-msgstr "è¦ä½¿ç”¨æ•´åˆï¼Œæ¯å€‹ä½¿ç”¨è€…還必須在其 GitLab 賬號上啟用 Gitpod。 %{link_start}如何啟用它?%{link_end} "
+msgid "Gitpod|To use the integration, each user must also enable Gitpod on their GitLab account. %{help_link_start}How do I enable it?%{help_link_end}"
+msgstr "è¦ä½¿ç”¨æ•´åˆï¼Œæ¯å€‹ä½¿ç”¨è€…還必須在其 GitLab 帳號上啟用 Gitpod,%{help_link_start}如何啟用它?%{help_link_end}"
msgid "Gitpod|https://gitpod.example.com"
msgstr "https://gitpod.example.com"
@@ -21408,6 +21616,9 @@ msgstr "%{time_ago}授權存å–"
msgid "Given epic is already related to this epic."
msgstr "給定å²è©© (epic) 已經與此å²è©© (epic) é—œè¯ã€‚"
+msgid "Given inputs not defined in the `spec` section of the included configuration file"
+msgstr "輸入未包å«åœ¨é…置文件中的“specâ€å®šç¾©éƒ¨ä»½"
+
msgid "Global SAML group membership lock"
msgstr "全域 SAML 群組æˆå“¡éŽ–定"
@@ -21429,6 +21640,9 @@ msgstr "%{search} %{description} %{scope}"
msgid "GlobalSearch|%{count} default results provided. Use the up and down arrow keys to navigate search results list."
msgstr "æä¾› %{count} 個é è¨­çµæžœï¼Œä½¿ç”¨ä¸Šä¸‹ç®­é ­éµå°Žèˆªæœå°‹çµæžœåˆ—表。"
+msgid "GlobalSearch|%{link_start}Exact code search (powered by Zoekt)%{link_end} is enabled"
+msgstr "%{link_start}精確程å¼ç¢¼æœå°‹ï¼ˆç”± Zoekt æ供支æŒï¼‰%{link_end} 已啟用"
+
msgid "GlobalSearch|Aggregations load error."
msgstr "èšåˆè¼‰å…¥éŒ¯èª¤ã€‚"
@@ -21441,6 +21655,9 @@ msgstr "關閉"
msgid "GlobalSearch|Fetching aggregations error."
msgstr "GlobalSearchæ“·å–èšåˆéŒ¯èª¤ã€‚"
+msgid "GlobalSearch|Filters"
+msgstr ""
+
msgid "GlobalSearch|Group"
msgstr "群組"
@@ -21510,9 +21727,6 @@ msgstr "æœå°‹"
msgid "GlobalSearch|Search GitLab"
msgstr "æœå°‹ GitLab"
-msgid "GlobalSearch|Search GitLab %{kbdOpen}/%{kbdClose}"
-msgstr "æœå°‹ GitLab %{kbdOpen}/%{kbdClose}"
-
msgid "GlobalSearch|Search for projects, issues, etc."
msgstr "æœå°‹å°ˆæ¡ˆã€è­°é¡Œç­‰ã€‚"
@@ -21543,6 +21757,9 @@ msgstr "å–å¾—æœå°‹è‡ªå‹•å®Œæˆå»ºè­°æ™‚發生錯誤。"
msgid "GlobalSearch|There was an error fetching the \"Syntax Options\" document."
msgstr "æ“·å–「語法é¸é …ã€æ–‡ä»¶æ™‚發生錯誤。"
+msgid "GlobalSearch|Type %{kbdOpen}/%{kbdClose} to search"
+msgstr "輸入 %{kbdOpen}/%{kbdClose} 進行æœå°‹"
+
msgid "GlobalSearch|Type and press the enter key to submit search."
msgstr "輸入並按回車éµæ交æœå°‹ã€‚"
@@ -21783,6 +22000,12 @@ msgstr "撤銷授權"
msgid "GoogleCloud|Revoke authorizations granted to GitLab. This does not invalidate service accounts."
msgstr "撤銷授予 GitLab 的授權,ä¸æœƒä½¿æœå‹™å¸³è™Ÿå¤±æ•ˆã€‚"
+msgid "GooglePlayStore|Only set variables on protected branches and tags"
+msgstr "僅在å—ä¿è­·çš„分支和標籤上設定變數"
+
+msgid "GooglePlayStore|Protected branches and tags only"
+msgstr "僅é™å—ä¿è­·çš„分支和標籤"
+
msgid "GooglePlay|Drag your key file here or %{linkStart}click to upload%{linkEnd}."
msgstr "將您的密鑰文件拖到此處或 %{linkStart}點擊上傳%{linkEnd}。"
@@ -21798,8 +22021,8 @@ msgstr "Google Play"
msgid "GooglePlay|Leave empty to use your current service account key."
msgstr "留空以使用您當å‰çš„æœå‹™å¸³æˆ¶å¯†é‘°ã€‚"
-msgid "GooglePlay|Service account key (.json)"
-msgstr "æœå‹™å¸³è™Ÿå¯†é‘° (.json)"
+msgid "GooglePlay|Service account key (.JSON)"
+msgstr "æœå‹™å¸³è™Ÿé‡‘é‘° (.JSON)"
msgid "GooglePlay|Upload a new service account key (replace %{currentFileName})"
msgstr "上傳新的æœå‹™å¸³è™Ÿå¯†é‘°ï¼ˆå–代 %{currentFileName})"
@@ -21909,6 +22132,9 @@ msgstr "群組大頭貼"
msgid "Group by"
msgstr "根據...分組"
+msgid "Group by:"
+msgstr "分組ä¾æ“šï¼š"
+
msgid "Group description (optional)"
msgstr "群組æ述(å¯é¸ï¼‰"
@@ -21975,9 +22201,6 @@ msgstr "群組å稱(您的組織)"
msgid "Group navigation"
msgstr "群組導航"
-msgid "Group overview"
-msgstr "群組總覽"
-
msgid "Group overview content"
msgstr "群組概述內容"
@@ -22353,8 +22576,8 @@ msgstr "é¸æ“‡è©²ç¾¤çµ„中專案的åˆä½µè«‹æ±‚檢查,該設定會覆蓋在該
msgid "GroupSettings|Compliance frameworks"
msgstr "åˆè¦æ¡†æž¶"
-msgid "GroupSettings|Configure analytics features for this group"
-msgstr "為該群組é…置分æžåŠŸèƒ½"
+msgid "GroupSettings|Configure analytics features for this group."
+msgstr "為此群組é…置分æžåŠŸèƒ½ã€‚"
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
msgstr "é…ç½®åˆè¦æ€§æ¡†æž¶ä»¥ä½¿å…¶å¯ç”¨æ–¼è©²ç¾¤çµ„中的專案。 %{linkStart}什麼是åˆè¦æ¡†æž¶ï¼Ÿ%{linkEnd}"
@@ -22542,8 +22765,8 @@ msgstr "此功能需è¦ç€è¦½å™¨æœ¬æ©Ÿå„²å­˜æ”¯æ´"
msgid "GroupsDropdown|Toggle edit mode"
msgstr "切æ›ç·¨è¼¯æ¨¡å¼"
-msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "群組是幾個專案的集åˆã€‚"
+msgid "GroupsEmptyState|A group is a collection of several projects"
+msgstr "群組是多個專案的集åˆ"
msgid "GroupsEmptyState|Create new project"
msgstr "新建專案"
@@ -22554,8 +22777,8 @@ msgstr "新建å­ç¾¤çµ„"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
msgstr "群組是管ç†å°ˆæ¡ˆå’Œæˆå“¡çš„最好方å¼ã€‚"
-msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "如果您在一個群組下組織專案,它的工作方å¼å°±åƒä¸€å€‹æ–‡ä»¶å¤¾ã€‚"
+msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group."
+msgstr "如果您將專案組織在一個群組下,它的工作方å¼å°±åƒä¸€å€‹æ–‡ä»¶å¤¾ã€‚您å¯ä»¥ç®¡ç†ç¾¤çµ„æˆå“¡çš„權é™ä»¥åŠå°ç¾¤çµ„中æ¯å€‹å°ˆæ¡ˆçš„å­˜å–。"
msgid "GroupsEmptyState|No archived projects."
msgstr "ç„¡å·²å°å­˜çš„專案。"
@@ -22572,9 +22795,6 @@ msgstr "沒有å­ç¾¤çµ„或專案"
msgid "GroupsEmptyState|Projects are where you can store your code, access issues, wiki, and other features of Gitlab."
msgstr "專案是您儲存您的程å¼ç¢¼ã€å­˜å–è­°é¡Œã€wiki 和其它GitLab 功能的地方。"
-msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "您å¯ä»¥ç®¡ç†ç¾¤çµ„æˆå“¡çš„權é™ä¸¦å­˜å–群組中的æ¯å€‹å°ˆæ¡ˆã€‚"
-
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr "您沒有在該群組中建立å­ç¾¤çµ„或專案所需è¦çš„權é™ã€‚è«‹è¯çµ¡è©²ç¾¤çµ„çš„æ“有者來建立新的å­ç¾¤çµ„或專案。"
@@ -22994,6 +23214,9 @@ msgstr "幫助將 GitLab 翻譯æˆæ‚¨çš„語言"
msgid "Help translate to your language"
msgstr "å”助翻譯為您的語言"
+msgid "Helpful"
+msgstr ""
+
msgid "Helps prevent bots from brute-force attacks."
msgstr "å”助防止機器人暴力攻擊。"
@@ -23256,9 +23479,6 @@ msgstr "我想儲存我的程å¼ç¢¼ç¢¼"
msgid "I want to use GitLab CI with my existing repository"
msgstr "我想在我的ç¾æœ‰ç‰ˆæœ¬åº«ä¸Šä½¿ç”¨GitLab CI"
-msgid "I'd like to receive updates about GitLab via email"
-msgstr "我希望通éŽé›»å­éƒµä»¶æŽ¥æ”¶GitLabçš„æ›´æ–°"
-
msgid "I'm signing up for GitLab because:"
msgstr "我註冊GitLab是因為:"
@@ -23298,6 +23518,12 @@ msgstr "æ­¤é¸é …被ç¦ç”¨ï¼Œå› ç‚ºæ‚¨ä¸å…許在此專案中建立åˆä½µè«‹æ±‚
msgid "IDE|This option is disabled because you don't have write permissions for the current branch."
msgstr "æ­¤é¸é …被ç¦ç”¨ï¼Œå› ç‚ºæ‚¨æ²’有當å‰åˆ†æ”¯çš„寫入權é™ã€‚"
+msgid "IDs with errors: %{error_messages}."
+msgstr "有錯誤的 ID: %{error_messages}。"
+
+msgid "IMPORTANT: Use this setting only for VERY strict auditing purposes. When turned on, nobody will be able to remove the label from any merge requests after they are merged. In addition, nobody will be able to turn off this setting or delete this label."
+msgstr "é‡è¦ï¼šåƒ…在éžå¸¸åš´æ ¼çš„審計目的下使用此設定,開啟後,任何人在åˆä½µè«‹æ±‚åˆä½µå¾Œå°‡ç„¡æ³•åˆªé™¤æ¨™è¨˜ã€‚此外,任何人都無法關閉此設定或刪除此標記。"
+
msgid "INFO: Your SSH key has expired. Please generate a new key."
msgstr "訊æ¯ï¼šæ‚¨çš„SSH金鑰已éŽæœŸã€‚請生æˆä¸€å€‹æ–°é‡‘鑰。"
@@ -23481,6 +23707,12 @@ msgstr "確èªæ‚¨çš„付款方å¼"
msgid "IdentityVerification|Verify phone number"
msgstr "驗證電話號碼"
+msgid "IdentityVerification|Verify with a credit card instead?"
+msgstr "改為使用信用å¡é©—證?"
+
+msgid "IdentityVerification|Verify with a phone number instead?"
+msgstr "改為使用電話號碼驗證?"
+
msgid "IdentityVerification|Verify your identity"
msgstr "驗證您的身份"
@@ -23889,8 +24121,8 @@ msgstr "讀å–匯匯入詳細訊æ¯æ™‚發生錯誤。"
msgid "Import|GitHub import details"
msgstr "GitHub 匯入細節"
-msgid "Import|Maximum decompressed size (MiB)"
-msgstr "æœ€å¤§è§£å£“å¤§å° (MiB)"
+msgid "Import|Maximum decompressed file size for archives from imports (MiB)"
+msgstr "åŒ¯å…¥å­˜æª”çš„æœ€å¤§è§£å£“ç¸®æª”æ¡ˆå¤§å° (MiB)"
msgid "Import|Maximum import remote file size (MB)"
msgstr "最大é ç«¯æ–‡ä»¶åŒ¯å…¥å¤§å° (MB)"
@@ -23916,6 +24148,12 @@ msgstr "無法匯入版本庫。"
msgid "Import|There is not a valid Git repository at this URL. If your HTTP repository is not publicly accessible, verify your credentials."
msgstr "在此 URL 上沒有有效的 Git 倉庫。如果您的 HTTP 倉庫ä¸èƒ½å…¬é–‹å­˜å–,請驗證您的憑據。"
+msgid "Import|Timeout for decompressing archived files (seconds)"
+msgstr "解壓縮存檔文件的逾時時間(秒)"
+
+msgid "Import|Timeout for decompressing archived files."
+msgstr "解壓縮存檔文件的逾時。"
+
msgid "Improve customer support with Service Desk"
msgstr "通éŽæœå‹™å°æ”¹å–„客戶支æ´"
@@ -23958,381 +24196,72 @@ msgstr "使用中"
msgid "InProductMarketing|%{organization_name} logo"
msgstr "%{organization_name} 標誌"
-msgid "InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection"
-msgstr "%{strong_start}進階應用程å¼å®‰å…¨%{strong_end} — 包括 SASTã€DAST 掃æã€FUZZ 測試ã€ä¾è³´æ€§æŽƒæã€è¨±å¯è­‰åˆè¦æ€§ã€ç§˜å¯†æª¢æ¸¬"
-
-msgid "InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels"
-msgstr "%{strong_start}å…¬å¸ç¯„åœå…§çš„組åˆç®¡ç†%{strong_end} — 包括多層級å²è©© (epics) ã€ç¯„åœæ¨™ç±¤"
-
-msgid "InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream"
-msgstr "%{strong_start}執行級別的見解%{strong_end} — 包括生產力報告ã€ä»»å‹™é¡žåž‹ã€å®Œæˆå¤©æ•¸ã€åƒ¹å€¼æµ"
-
msgid "InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
msgstr "%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA"
-msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
-msgstr "%{strong_start}多個核准角色%{strong_end} — 包括代碼所有者和所需的åˆä½µæ ¸å‡†"
-
-msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
-msgstr "*GitLab*,å詞:高效團隊的åŒç¾©è©ž"
-
-msgid "InProductMarketing|...and you can get a free trial of GitLab Ultimate"
-msgstr "...您å¯ä»¥ç²å¾—旗艦版的å…費試用"
-
-msgid "InProductMarketing|3 ways to dive into GitLab CI/CD"
-msgstr "深入瞭解 GitLab CI/CD 的 3 種方法"
-
-msgid "InProductMarketing|Actually, GitLab makes the team work (better)"
-msgstr "實際上,GitLab 使團隊能夠工作更好"
-
msgid "InProductMarketing|Advanced security testing"
msgstr "進階安全測試"
-msgid "InProductMarketing|And finally %{deploy_link} a Python application."
-msgstr "最後 %{deploy_link} 一個 Python 應用程å¼ã€‚"
-
-msgid "InProductMarketing|Are your runners ready?"
-msgstr "InProductMarketing|您的執行器就緒了嗎?"
-
-msgid "InProductMarketing|Automated security scans directly within GitLab"
-msgstr "直接在 GitLab 中自動進行安全掃æ"
-
-msgid "InProductMarketing|Be a DevOps hero"
-msgstr "æˆç‚ºDevOps英雄"
-
-msgid "InProductMarketing|Beef up your security"
-msgstr "增強您的安全性"
-
-msgid "InProductMarketing|Better code in less time"
-msgstr "用更少的時間編寫更好的程å¼ç¢¼"
-
msgid "InProductMarketing|Blog"
msgstr "部è½æ ¼"
msgid "InProductMarketing|Building for iOS? We've got you covered."
msgstr "為 iOS 構建? 我們為您æä¾›ä¿éšœ"
-msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
-msgstr "通éŽå•Ÿç”¨ä»£ç¢¼æ‰€æœ‰è€…和所需的åˆä½µæ ¸å‡†ï¼Œåˆé©çš„人將審查åˆé©çš„ MR。這是雙è´çš„:更乾淨的代碼和更有效的審查éŽç¨‹ã€‚"
-
-msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
-msgstr "程å¼æ‰€æœ‰è€…和所需的åˆä½µæ ¸å‡†æ˜¯ GitLab 付費版的一部分。您å¯ä»¥é–‹å§‹å…費試用 GitLab 旗艦版 30 天,並在 5 分é˜å…§å•Ÿç”¨é€™äº›åŠŸèƒ½ï¼Œç„¡éœ€ä¿¡ç”¨å¡ã€‚"
-
-msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
-msgstr "InProductMarketing|åªéœ€é»žæ“Šå¹¾ä¸‹å³å¯å»ºç«‹è‡ªè¨‚ CI 執行器"
-
-msgid "InProductMarketing|Create a custom runner"
-msgstr "InProductMarketing|建立自訂執行器"
-
-msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr "5分é˜å…§åœ¨ GitLab 中建立一個專案"
-
-msgid "InProductMarketing|Create your first project!"
-msgstr "建立您的第一個專案ï¼"
-
msgid "InProductMarketing|Deliver Better Products Faster"
msgstr "更快地交付更好的產å“"
-msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
-msgstr "您知é“使用 GitLab 的團隊效率更高嗎?"
-
-msgid "InProductMarketing|Dig in and create a project and a repo"
-msgstr "深入並建立一個專案和版本庫"
-
-msgid "InProductMarketing|Do you have a teammate who would be perfect for this task?"
-msgstr "您有一ä½é©åˆæ­¤ä»»å‹™çš„團隊æˆå“¡å—Žï¼Ÿ"
-
-msgid "InProductMarketing|Expand your DevOps journey with a free GitLab trial"
-msgstr "通éŽå…費的 GitLab 試用擴展您的 DevOps 之旅"
-
-msgid "InProductMarketing|Explore GitLab CI/CD"
-msgstr "探索 GitLab CI/CD"
-
-msgid "InProductMarketing|Explore the options"
-msgstr "ç€è¦½é¸é …"
-
-msgid "InProductMarketing|Explore the power of GitLab CI/CD"
-msgstr "探索 GitLab CI/CD 的力é‡"
-
msgid "InProductMarketing|Facebook"
msgstr "Facebook"
-msgid "InProductMarketing|Feel the need for speed?"
-msgstr "感覺需è¦é€Ÿåº¦å—Žï¼Ÿ"
-
-msgid "InProductMarketing|Find out how your teams are really doing"
-msgstr "瞭解您的團隊的實際情æ³"
-
-msgid "InProductMarketing|Follow our steps"
-msgstr "跟隨我們的步驟"
-
msgid "InProductMarketing|Free 30-day trial"
msgstr "30 天å…費試用"
msgid "InProductMarketing|Free guest users"
msgstr "å…費訪客使用者"
-msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr "用我們的%{quick_start_link}快速開始使用 CI/CD。從一個å¯ç”¨çš„é‹è¡Œå™¨é–‹å§‹ï¼Œç„¶å¾Œå»ºç«‹ä¸€å€‹ CI .yml 文件——這真的很容易。"
-
-msgid "InProductMarketing|Get our import guides"
-msgstr "å–得匯入指å—"
-
msgid "InProductMarketing|Get set up to build for iOS"
msgstr "為iOS構建進行設置"
-msgid "InProductMarketing|Get started today"
-msgstr "ç«‹å³é–‹å§‹"
-
-msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial, no credit card required."
-msgstr "ç«‹å³é–‹å§‹ç‚ºæœŸ 30 天的 GitLab 旗艦版 試用,無需信用å¡ã€‚"
-
-msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr "開始使用 GitLab CI/CD"
-
-msgid "InProductMarketing|Get to know GitLab CI/CD"
-msgstr "瞭解GitLab CI/CD"
-
-msgid "InProductMarketing|Get your team set up on GitLab"
-msgstr "在 GitLab 上建立您的團隊"
-
-msgid "InProductMarketing|Git basics"
-msgstr "Git 基礎知識"
-
-msgid "InProductMarketing|GitHub Enterprise projects to GitLab"
-msgstr "GitHub ä¼æ¥­å°ˆæ¡ˆåˆ° GitLab"
-
-msgid "InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance."
-msgstr "GitLab æä¾›éœæ…‹æ‡‰ç”¨ç¨‹å¼å®‰å…¨æ¸¬è©¦ï¼ˆSAST)ã€å‹•æ…‹æ‡‰ç”¨ç¨‹å¼å®‰å…¨æ¸¬è©¦ï¼ˆDAST)ã€å®¹å™¨æŽƒæå’Œä¾è³´æŽƒæ以幫助您æ供安全的應用程å¼ä»¥åŠéµå®ˆè¨±å¯å”議。"
-
-msgid "InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"
-msgstr "GitLab çš„ CI/CD 使軟件開發更容易。ä¸ç›¸ä¿¡æˆ‘們?您å¯ä»¥é€šéŽä»¥ä¸‹ä¸‰ç¨®æ–¹å¼é€²è¡Œå¿«é€Ÿï¼ˆä¸”令人滿æ„)的測試驅動:"
-
-msgid "InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"
-msgstr "專業版是為了使您ã€æ‚¨çš„團隊和您的應用程å¼æ›´æœ‰æ•ˆçŽ‡å’Œæ›´å®‰å…¨è€Œè¨­è¨ˆï¼Œä¸¦ä¸”包括但ä¸é™æ–¼ï¼š"
-
-msgid "InProductMarketing|Give us one minute..."
-msgstr "給我們一分é˜..."
-
-msgid "InProductMarketing|Go farther with GitLab"
-msgstr "用 GitLab èµ°å¾—æ›´é "
-
-msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
-msgstr "Goldman Sachs 從æ¯å…©é€±ä¸€æ¬¡æ§‹å»ºåˆ°æ¯å¤©æ•¸åƒæ¬¡æ§‹å»º"
-
-msgid "InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}."
-msgstr "è¦åŒ¯å…¥ä¸åŒçš„執行個體嗎?這是我們的 %{import_link}。"
-
-msgid "InProductMarketing|Here's what you need to know"
-msgstr "這是你需è¦çŸ¥é“çš„"
-
-msgid "InProductMarketing|How (and why) mirroring makes sense"
-msgstr "如何(以åŠç‚ºä»€éº¼ï¼‰è®“é¡åƒè®Šçš„有æ„義"
-
-msgid "InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?"
-msgstr "關閉功能請求ã€bugã€æŠ€è¡“債務ã€å®‰å…¨æ€§ç­‰é¡žåž‹çš„è­°é¡Œ/MR 需è¦å¤šé•·æ™‚間?"
-
-msgid "InProductMarketing|How many days does it take our team to complete various tasks?"
-msgstr "我們的團隊完æˆå„種任務需è¦å¤šå°‘天?"
-
-msgid "InProductMarketing|How to build and test faster"
-msgstr "如何更快地構建和測試"
-
msgid "InProductMarketing|If you don't want to receive marketing emails directly from GitLab, %{marketing_preference_link}."
msgstr "如果您ä¸æƒ³ç›´æŽ¥æŽ¥æ”¶æˆ‘們的營銷電å­éƒµä»¶ï¼Œå‰‡ %{marketing_preference_link}."
msgid "InProductMarketing|If you no longer wish to receive marketing emails from us,"
msgstr "如果您ä¸å†å¸Œæœ›æ”¶åˆ°æˆ‘們的營銷電å­éƒµä»¶ï¼Œ"
-msgid "InProductMarketing|Import your project and code from GitHub, Bitbucket and others"
-msgstr "從 GitHubã€Bitbucket 等匯入您的專案和代碼"
-
-msgid "InProductMarketing|Improve app security with a 30-day trial"
-msgstr "é€šéŽ 30 天試用æ高應用安全性"
-
-msgid "InProductMarketing|Improve code quality and streamline reviews"
-msgstr "æ高程å¼ç¢¼è³ªé‡ä¸¦ç°¡åŒ–審查"
-
msgid "InProductMarketing|Increase Operational Efficiencies"
msgstr "æ高é‹ç‡Ÿæ•ˆçŽ‡"
-msgid "InProductMarketing|Invite them to help out."
-msgstr "邀請他們æ供幫助。"
-
msgid "InProductMarketing|Invite unlimited colleagues"
msgstr "ç„¡é™åˆ¶é‚€è«‹åŒäº‹"
-msgid "InProductMarketing|Invite your colleagues and start shipping code faster."
-msgstr "邀請您的åŒäº‹ä¸¦é–‹å§‹æ›´å¿«åœ°ç™¼å¸ƒç¨‹å¼ç¢¼ã€‚"
-
-msgid "InProductMarketing|Invite your colleagues to join in less than one minute"
-msgstr "ä¸åˆ°ä¸€åˆ†é˜é‚€è«‹æ‚¨çš„åŒäº‹åŠ å…¥"
-
-msgid "InProductMarketing|Invite your colleagues today"
-msgstr "ç«‹å³é‚€è«‹æ‚¨çš„åŒäº‹"
-
-msgid "InProductMarketing|Invite your team in less than 60 seconds"
-msgstr "60 秒內邀請您的團隊"
-
-msgid "InProductMarketing|Invite your team now"
-msgstr "ç«‹å³é‚€è«‹æ‚¨çš„團隊"
-
-msgid "InProductMarketing|Invite your team today to build better code (and processes) together"
-msgstr "ç«‹å³é‚€è«‹æ‚¨çš„團隊一起構建更好的代碼(和æµç¨‹ï¼‰"
-
-msgid "InProductMarketing|It's all in the stats"
-msgstr "一切盡在統計中"
-
-msgid "InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD."
-msgstr "為了利用 GitLab çš„ CI/CD,也å¯ä»¥ç°¡å–®åœ°è¨­å®šç‚º %{external_repo_link}"
-
-msgid "InProductMarketing|Launch GitLab CI/CD in 20 minutes or less"
-msgstr "在 20 分é˜æˆ–更短的時間內啟動 GitLab CI/CD"
-
msgid "InProductMarketing|Learn how to build for iOS"
msgstr "學習如何為iOS構建"
-msgid "InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}."
-msgstr "進行轉æ›ï¼Ÿå°‡å°ˆæ¡ˆåŒ¯å…¥ GitLab 比您想åƒçš„è¦å®¹æ˜“,移動 %{github_link},或者匯入一些æ±è¥¿ %{bitbucket_link}。"
-
-msgid "InProductMarketing|Master the art of importing!"
-msgstr "掌æ¡åŒ¯å…¥çš„è—è¡“ï¼"
-
-msgid "InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}"
-msgstr "繼續輕鬆建立 Pages 網站 %{ci_template_link}"
-
-msgid "InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"
-msgstr "多個所有者,混亂的工作æµï¼Ÿæˆ‘們已為您æä¾›ä¿éšœ"
-
-msgid "InProductMarketing|Need an alternative to importing?"
-msgstr "需è¦æ›¿ä»£åŒ¯å…¥çš„方法嗎?"
-
msgid "InProductMarketing|No credit card required."
msgstr "ä¸éœ€è¦ä¿¡ç”¨å¡ã€‚"
-msgid "InProductMarketing|Our tool brings all the things together"
-msgstr "我們的工具將所有æ±è¥¿æ•´åˆåœ¨ä¸€èµ·"
-
msgid "InProductMarketing|Portfolio management"
msgstr "投資組åˆç®¡ç†"
-msgid "InProductMarketing|Rapid development, simplified"
-msgstr "快速開發,簡化"
-
msgid "InProductMarketing|Reduce Security and Compliance Risk"
msgstr "é™ä½Žå®‰å…¨èˆ‡åˆè¦é¢¨éšª"
msgid "InProductMarketing|Security risk mitigation"
msgstr "é™ä½Žå®‰å…¨é¢¨éšª"
-msgid "InProductMarketing|Security that's integrated into your development lifecycle"
-msgstr "æ•´åˆåˆ°æ‚¨çš„開發生命週期中的安全性"
-
-msgid "InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool."
-msgstr "有時您還沒有準備好完全éŽæ¸¡åˆ°æ–°å·¥å…·ã€‚如果您還沒有準備好完全æ交, %{mirroring_link} 為您æ供了一種與當å‰å·¥å…·ä¸¦è¡Œè©¦ç”¨ GitLab 的安全方法。"
-
-msgid "InProductMarketing|Spin up an autoscaling runner in GitLab"
-msgstr "InProductMarketing|在 GitLab 中啟動自動縮放執行器"
-
-msgid "InProductMarketing|Start a GitLab Ultimate trial today in less than one minute, no credit card required."
-msgstr "ç«‹å³åœ¨ä¸åˆ°ä¸€åˆ†é˜çš„時間內開始 GitLab Ultimate 試用,無需信用å¡ã€‚"
-
msgid "InProductMarketing|Start a Self-Managed trial"
msgstr "開始試用"
-msgid "InProductMarketing|Start a free trial of GitLab Ultimate – no credit card required"
-msgstr "開始å…費試用旗艦版 - 無需信用å¡"
-
-msgid "InProductMarketing|Start a trial"
-msgstr "開始試用"
-
-msgid "InProductMarketing|Start by %{performance_link}"
-msgstr "從%{performance_link}開始"
-
-msgid "InProductMarketing|Start by importing your projects"
-msgstr "從匯入您的專案開始"
-
-msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
-msgstr "開始å…費試用 GitLab Ultimate"
-
-msgid "InProductMarketing|Start your trial now!"
-msgstr "ç¾åœ¨å°±é–‹å§‹è©¦ç”¨ï¼"
-
-msgid "InProductMarketing|Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!"
-msgstr "å³åˆ»é–‹å§‹è©¦ç”¨ï¼Œé«”驗單個應用的æˆåŠŸï¼Œä¸¦å…費發ç¾GitLab Ultimate的所有功能。"
-
-msgid "InProductMarketing|Stop wondering and use GitLab to answer questions like:"
-msgstr "åœæ­¢ç–‘惑,使用GitLab回答以下å•é¡Œï¼š"
-
-msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
-msgstr "簡化代碼審核,一目瞭然地知é“誰ä¸å¯ç”¨ï¼Œåœ¨è©•è«–或電å­éƒµä»¶ä¸­æºé€šï¼Œä¸¦èˆ‡Slackæ•´åˆï¼Œè®“æ¯å€‹äººéƒ½åœ¨åŒä¸€é é¢ä¸Šã€‚"
-
-msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr "使用GitLab的第一步"
-
-msgid "InProductMarketing|Take your source code management to the next level"
-msgstr "讓您的æºä»£ç¢¼ç®¡ç†æ›´ä¸Šä¸€å±¤æ¨“"
-
msgid "InProductMarketing|Team members collaborating"
msgstr "團隊æˆå“¡åˆä½œ"
-msgid "InProductMarketing|Team up in GitLab for greater efficiency"
-msgstr "在 GitLab 中組隊以æ高效率"
-
-msgid "InProductMarketing|Team work makes the dream work"
-msgstr "團隊åˆä½œæˆå°±å¤¢æƒ³"
-
-msgid "InProductMarketing|Test, create, deploy"
-msgstr "測試,建立,部署"
-
-msgid "InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started."
-msgstr "這就是開始使用 GitLab 所需的全部內容,但是如果您ä¸ç†Ÿæ‚‰ Git,請查看我們的 %{basics_link} 以å–得有用的入門æ示和技巧。"
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series."
-msgstr "這是 %{track} 系列中的第 %{current_series} å°é›»å­éƒµä»¶ï¼Œå…± %{total_series} å°"
-
-msgid "InProductMarketing|This is email %{current_series} of %{total_series} in the %{track} series. To disable notification emails sent by your local GitLab instance, either contact your administrator or %{unsubscribe_link}."
-msgstr "這是 %{track} 系列中的第 %{current_series} å°é›»å­éƒµä»¶ï¼Œå…± %{total_series} å°ã€‚è¦ç¦ç”¨æœ¬åœ° GitLab 執行個體發é€çš„通知電å­éƒµä»¶ï¼Œè«‹è¯ç¹«æ‚¨çš„管ç†å“¡æˆ– %{unsubscribe_link}。"
-
-msgid "InProductMarketing|Ticketmaster decreased their CI build time by 15X"
-msgstr "Ticketmaster å°‡ CI 構建時間縮短了 15 å€"
-
-msgid "InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}."
-msgstr "厭倦了與ä¸åŒçš„工具éˆã€è¨Šæ¯å­¤å³¶å’Œä½Žæ•ˆæµç¨‹çš„æ鬥? GitLab çš„ CI/CD 建立在 DevOps å¹³å°ä¸Šï¼Œå…·æœ‰æºä»£ç¢¼ç®¡ç†ã€è¦åŠƒã€ç›£æŽ§ç­‰åŠŸèƒ½ã€‚åƒé–± %{ci_link}。"
-
msgid "InProductMarketing|To opt out of these onboarding emails, %{unsubscribe_link}."
msgstr "é¸æ“‡é€€å‡ºOnboarding郵件,%{unsubscribe_link}。"
-msgid "InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}."
-msgstr "è¦çž­è§£ä¸¦å……分利用GitLab,請從頭開始,從%{project_link}開始。在GitLab中,版本庫是專案的一部分,所以在您建立了您的專案之後,您å¯ä»¥ç¹¼çºŒåŸ·è¡Œ%{repo_link}。"
-
-msgid "InProductMarketing|Try GitLab Ultimate for free"
-msgstr "å…費試用 GitLab 旗艦版"
-
-msgid "InProductMarketing|Try it out"
-msgstr "嘗試一下"
-
-msgid "InProductMarketing|Try it yourself"
-msgstr "親自嘗試一下"
-
-msgid "InProductMarketing|Turn coworkers into collaborators"
-msgstr "å°‡åŒäº‹è®Šæˆåˆä½œè€…"
-
msgid "InProductMarketing|Twitter"
msgstr "Twitter"
-msgid "InProductMarketing|Understand repository mirroring"
-msgstr "瞭解版本庫é¡åƒ"
-
-msgid "InProductMarketing|Understand your project options"
-msgstr "瞭解您的專案é¸é …"
-
-msgid "InProductMarketing|Use GitLab CI/CD"
-msgstr "使用 GitLab CI/CD"
-
-msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr "InProductMarketing|使用我們的 AWS cloudformation 範本,åªéœ€é»žæ“Šå¹¾ä¸‹å³å¯å•Ÿå‹•æ‚¨çš„執行器ï¼"
-
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr "å…¨çƒè¶…éŽ10è¬å€‹çµ„織使用:"
@@ -24348,66 +24277,15 @@ msgstr "想在您的æœå‹™å™¨ä¸Šè¨—管 GitLab?"
msgid "InProductMarketing|Watch iOS building in action."
msgstr "觀看é‹è¡Œä¸­çš„ iOS 構建。"
-msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
-msgstr "我們知é“一些關於效率的事情,我們想分享給大家。註冊GitLab Ultimateçš„å…費試用版,您的團隊將從第一天開始使用它。"
-
-msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
-msgstr "從產å“到開發,å†åˆ°å¯©æŸ¥å’Œç”Ÿç”¢ï¼Œæˆ‘們的價值æµæ™‚間表是什麼樣的?"
-
-msgid "InProductMarketing|When your team is on GitLab these answers are a click away."
-msgstr "當您的團隊在 GitLab 上時,åªéœ€å–®æ“Šä¸€ä¸‹å³å¯ç²å¾—這些答案。"
-
-msgid "InProductMarketing|Working in GitLab = more efficient"
-msgstr "在 GitLab 中工作 = 更高效"
-
msgid "InProductMarketing|YouTube"
msgstr "YouTube"
-msgid "InProductMarketing|Your teams can be more efficient"
-msgstr "您的團隊å¯ä»¥æ›´å…·æ•ˆçŽ‡"
-
-msgid "InProductMarketing|comprehensive guide"
-msgstr "綜åˆå°Žå¼•"
-
-msgid "InProductMarketing|connect an external repository"
-msgstr "連接外部版本庫"
-
-msgid "InProductMarketing|create a project"
-msgstr "建立一個專案"
-
-msgid "InProductMarketing|from Bitbucket"
-msgstr "從 Bitbucket"
-
msgid "InProductMarketing|go to about.gitlab.com"
msgstr "å‰å¾€about.gitlab.cn"
-msgid "InProductMarketing|how easy it is to get started"
-msgstr "如何輕鬆地開始"
-
-msgid "InProductMarketing|quick start guide"
-msgstr "快速開始指引"
-
-msgid "InProductMarketing|repository mirroring"
-msgstr "版本庫é¡åƒ"
-
-msgid "InProductMarketing|set up a repo"
-msgstr "設定 repo"
-
-msgid "InProductMarketing|test and deploy"
-msgstr "測試和部署"
-
-msgid "InProductMarketing|testing browser performance"
-msgstr "測試ç€è¦½å™¨æ€§èƒ½ã€‚"
-
msgid "InProductMarketing|unsubscribe"
msgstr "å–消訂閱"
-msgid "InProductMarketing|update your preferences"
-msgstr "更新您的å好設定"
-
-msgid "InProductMarketing|using a CI/CD template"
-msgstr "使用 CI/CD 範本"
-
msgid "InProductMarketing|you may %{unsubscribe_link} at any time."
msgstr "您å¯ä»¥éš¨æ™‚%{unsubscribe_link}。"
@@ -24837,6 +24715,14 @@ msgstr "å…§è¯"
msgid "Inline math"
msgstr "å…§è¯æ•¸å­¸"
+msgid "InlineFindings|1 Code Quality finding detected"
+msgid_plural "InlineFindings|%d Code Quality findings detected"
+msgstr[0] "檢測到 %d 程å¼ç¢¼è³ªé‡å•é¡Œ"
+
+msgid "InlineFindings|1 SAST finding detected"
+msgid_plural "InlineFindings|%d SAST findings detected"
+msgstr[0] "檢測到 %d SAST çµæžœ"
+
msgid "Input host keys manually"
msgstr "手動輸入主機金鑰"
@@ -25192,6 +25078,9 @@ msgstr "當您在ZenTao中建立專案的議題時,禪é“議題會顯示在此
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr "ä¸èƒ½è¶…éŽ %{recipients_limit}"
+msgid "Integration|Branches for which notifications are to be sent"
+msgstr "è¦ç™¼é€é€šçŸ¥çš„分支"
+
msgid "IntelliJ IDEA (HTTPS)"
msgstr "IntelliJ IDEA (HTTPS)"
@@ -25228,15 +25117,9 @@ msgstr "ä¸èƒ½åœç”¨å…§éƒ¨ä½¿ç”¨è€…"
msgid "Interval"
msgstr "é–“éš”"
-msgid "Interval Pattern"
-msgstr "循環週期"
-
msgid "Introducing Your DevOps Reports"
msgstr "介紹您的 DevOps 報告"
-msgid "Introducing the Code Suggestions add-on"
-msgstr "導入程å¼ç¢¼å»ºè­°é™„加元件"
-
msgid "Invalid 'schemaVersion' '%{schema_version}'"
msgstr "無效的 “schemaVersion†“%{schema_version}â€"
@@ -25318,9 +25201,6 @@ msgstr "無效的標籤"
msgid "Invalid two-factor code."
msgstr "無效的雙é‡èªè­‰ç¢¼ã€‚"
-msgid "Invalid yaml"
-msgstr "無效的yaml"
-
msgid "Invalidated"
msgstr "無效"
@@ -25652,18 +25532,12 @@ msgstr "已解決所有線程"
msgid "IssuableEvents|unassigned"
msgstr "未指派"
-msgid "IssuableStatus|%{wi_type} created %{created_at} by "
-msgstr "%{wi_type} 創建者 %{created_at}"
-
msgid "IssuableStatus|Closed"
msgstr "已關閉"
msgid "IssuableStatus|Closed (%{link})"
msgstr "關閉(%{link})"
-msgid "IssuableStatus|Created %{created_at} by"
-msgstr "創建者 %{created_at}"
-
msgid "IssuableStatus|duplicated"
msgstr "é‡è¤‡"
@@ -25913,29 +25787,48 @@ msgstr "未分é…å²è©© (epic) çš„è­°é¡Œ"
msgid "Issues, merge requests, pushes, and comments."
msgstr "議題,åˆä½µè«‹æ±‚,推é€åŠç•™è¨€ã€‚"
-msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "在您為專案建立議題後,我們就會開始追蹤並顯示它們的指標"
-
msgid "IssuesAnalytics|Avg/Month:"
msgstr "月å‡ï¼š"
+msgid "IssuesAnalytics|Closed"
+msgstr "已關閉"
+
+msgid "IssuesAnalytics|Create issues for projects in your group to track and see metrics for them."
+msgstr "為群組中的專案建立議題以追蹤與檢視它們的指標。"
+
+msgid "IssuesAnalytics|Failed to load chart. Please try again."
+msgstr "無法載入圖表,請å†è©¦ä¸€æ¬¡ã€‚"
+
+msgid "IssuesAnalytics|Get started with issue analytics"
+msgstr "議題分æžå…¥é–€"
+
+msgid "IssuesAnalytics|Issues Opened vs Closed"
+msgstr "已開啟與已關閉的議題"
+
msgid "IssuesAnalytics|Issues created"
msgstr "議題已建立"
msgid "IssuesAnalytics|Issues created per month"
msgstr "æ¯æœˆå»ºç«‹çš„è­°é¡Œ"
-msgid "IssuesAnalytics|Last 12 months"
-msgstr "最近12個月"
+msgid "IssuesAnalytics|Last 12 months (%{chartDateRange})"
+msgstr "éŽåŽ»12個月(%{chartDateRange})"
+
+msgid "IssuesAnalytics|Opened"
+msgstr "已開啟"
+
+msgid "IssuesAnalytics|Overview"
+msgstr "概述"
msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "抱歉,無符åˆéŽæ¿¾å™¨çš„çµæžœ"
-msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "群組中的專案無任何議題"
+msgid "IssuesAnalytics|This month (%{chartDateRange})"
+msgid_plural "IssuesAnalytics|Last %{monthsCount} months (%{chartDateRange})"
+msgstr[0] "éŽåŽ» %{monthsCount} 個月 (%{chartDateRange})"
-msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
-msgstr "è¦æ“´å¤§æœå°‹ç¯„åœï¼Œè«‹è®Šæ›´æˆ–刪除上é¢çš„éŽæ¿¾æ¢ä»¶"
+msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above."
+msgstr "è¦åœ¨ä¸Šé¢çš„篩é¸æ¢ä»¶ä¸­æ“´å¤§æœç´¢ç¯„åœï¼Œæ›´æ”¹æˆ–刪除篩é¸æ¢ä»¶ã€‚"
msgid "IssuesAnalytics|Total:"
msgstr "總計:"
@@ -25982,6 +25875,9 @@ msgstr "斜體 (%{modifierKey}I)"
msgid "Italic text"
msgstr "斜體文字"
+msgid "Item with ID: %{id} cannot be added. You don't have permission to perform this action."
+msgstr "無法加入 ID 為 %{id} 的項目,您無權執行此æ“作。"
+
msgid "Iteration"
msgstr "迭代"
@@ -26318,6 +26214,9 @@ msgstr "未找到群組。"
msgid "JiraConnect|No linked groups"
msgstr "沒有已éˆçµç¾¤çµ„"
+msgid "JiraConnect|Not seeing your groups? Only groups you have access to appear here."
+msgstr "找ä¸åˆ°æ‚¨çš„群組?åªæœ‰æ‚¨æœ‰æ¬Šé™çš„群組會顯示在這裡。"
+
msgid "JiraConnect|Not seeing your groups? Only groups you have at least the Maintainer role for appear here."
msgstr "看ä¸åˆ°æ‚¨çš„群組?åªæœ‰æ‚¨æ“有至少 Maintainer 角色的群組會出ç¾åœ¨é€™è£¡ã€‚"
@@ -26816,6 +26715,9 @@ msgstr "期間"
msgid "Job|Erase job log and artifacts"
msgstr "擦除作業日誌和產物"
+msgid "Job|External links"
+msgstr ""
+
msgid "Job|Failed"
msgstr "失敗"
@@ -26867,6 +26769,9 @@ msgstr "é‡è©¦"
msgid "Job|Run again"
msgstr "å†æ¬¡åŸ·è¡Œ"
+msgid "Job|Runner type"
+msgstr "執行器類型"
+
msgid "Job|Running"
msgstr "執行中"
@@ -26963,9 +26868,6 @@ msgstr "加入專案"
msgid "Join your team on GitLab and contribute to an existing project"
msgstr "加入您的 GitLab 團隊,並為ç¾æœ‰å°ˆæ¡ˆåšå‡ºè²¢ç»"
-msgid "Joined %{time_ago}"
-msgstr "於 %{time_ago} 加入"
-
msgid "Joined %{user_created_time}"
msgstr "於 %{user_created_time} 加入"
@@ -27226,9 +27128,6 @@ msgstr "最近活動"
msgid "Last Name"
msgstr "姓"
-msgid "Last Pipeline"
-msgstr "最新æµæ°´ç·š"
-
msgid "Last Seen"
msgstr "最後出ç¾"
@@ -27325,6 +27224,9 @@ msgstr "您推é€äº†"
msgid "LastPushEvent|at"
msgstr "æ–¼"
+msgid "Latest AI-generated summary"
+msgstr "最新的 AI 產生摘è¦"
+
msgid "Latest changes"
msgstr "最新變更"
@@ -28019,6 +27921,9 @@ msgstr "鎖定 %{issuableType}"
msgid "Lock File?"
msgstr "鎖定文件?"
+msgid "Lock label after a merge request is merged"
+msgstr "åˆä½µè«‹æ±‚åˆä½µå¾ŒéŽ–定標記"
+
msgid "Lock memberships to LDAP synchronization"
msgstr "鎖定æˆå“¡èº«ä»½åˆ°LDAPåŒæ­¥"
@@ -28028,6 +27933,9 @@ msgstr "鎖定會員資格到 SAML 群組éˆçµåŒæ­¥"
msgid "Lock not found"
msgstr "未找到鎖"
+msgid "Lock on merge"
+msgstr "鎖定åˆä½µ"
+
msgid "Lock status"
msgstr "鎖定狀態"
@@ -28433,6 +28341,12 @@ msgstr "Mattermost URL:"
msgid "Mattermost notifications"
msgstr "Mattermost 通知"
+msgid "MattermostService|%{link_start}Add a slash command %{icon}%{link_end} in your Mattermost team with the options listed below."
+msgstr "%{link_start}在您的 Mattermost 團隊中加入斜線命令 %{icon}%{link_end} ,並使用下é¢åˆ—出的é¸é …。"
+
+msgid "MattermostService|%{link_start}Enable custom slash commands %{icon}%{link_end} on your Mattermost installation."
+msgstr "在您的 Mattermost 安è£ä¸­%{link_start}啟用自訂斜線命令%{icon}%{link_end}。"
+
msgid "MattermostService|Add to Mattermost"
msgstr "加入到Mattermost"
@@ -28448,6 +28362,9 @@ msgstr "填入最é©åˆä½ çš„團隊的文字。"
msgid "MattermostService|Install"
msgstr "安è£"
+msgid "MattermostService|Paste the token into the %{strong_start}Token%{strong_end} field."
+msgstr "將令牌粘貼到 %{strong_start}令牌%{strong_end} 欄ä½ä¸­ã€‚"
+
msgid "MattermostService|Request URL"
msgstr "請求網å€"
@@ -28460,6 +28377,9 @@ msgstr "響應圖示"
msgid "MattermostService|Response username"
msgstr "響應使用者å稱"
+msgid "MattermostService|Select the %{strong_start}Active%{strong_end} check box, then select %{strong_start}Save changes%{strong_end} to start using GitLab inside Mattermost!"
+msgstr "é¸æ“‡ %{strong_start}Active%{strong_end} æ ¸å–方塊,然後é¸æ“‡ %{strong_start}儲存變更%{strong_end} 以開始在 Mattermost 內使用 GitLabï¼"
+
msgid "MattermostService|Suggestions:"
msgstr "建議:"
@@ -28766,6 +28686,102 @@ msgstr "%{member_name}邀請您使用GitLab"
msgid "MemberInviteEmail|Invitation to join the %{project_or_group} %{project_or_group_name}"
msgstr "邀請加入 %{project_or_group} %{project_or_group_name}"
+msgid "MemberRoles|Actions"
+msgstr "動作"
+
+msgid "MemberRoles|Add new role"
+msgstr "新增角色"
+
+msgid "MemberRoles|Admin vulnerability"
+msgstr "管ç†å“¡æ¼æ´ž"
+
+msgid "MemberRoles|Allows admin access to the vulnerability reports. 'Read vulnerability' must be selected in order to take effect."
+msgstr "å…許管ç†å“¡å­˜å–æ¼æ´žå ±å‘Šã€‚å¿…é ˆé¸å–「讀å–æ¼æ´žã€æ‰æœƒç”Ÿæ•ˆã€‚"
+
+msgid "MemberRoles|Allows read-only access to the source code."
+msgstr "å…許唯讀存å–原始碼。"
+
+msgid "MemberRoles|Allows read-only access to the vulnerability reports."
+msgstr "å…許唯讀存å–æ¼æ´žå ±å‘Šã€‚"
+
+msgid "MemberRoles|Are you sure you want to delete this role?"
+msgstr "您確定è¦åˆªé™¤æ­¤è§’色嗎?"
+
+msgid "MemberRoles|Base role"
+msgstr "基礎角色"
+
+msgid "MemberRoles|Base role to use as template"
+msgstr "用作模æ¿çš„基礎角色"
+
+msgid "MemberRoles|Create new role"
+msgstr "建立新角色"
+
+msgid "MemberRoles|Custom roles"
+msgstr "自訂角色"
+
+msgid "MemberRoles|Delete role"
+msgstr "刪除角色"
+
+msgid "MemberRoles|Description"
+msgstr "æè¿°"
+
+msgid "MemberRoles|Enter a short name."
+msgstr "輸入短å稱。"
+
+msgid "MemberRoles|Failed to create role."
+msgstr "建立角色失敗。"
+
+msgid "MemberRoles|Failed to delete the role."
+msgstr "刪除角色失敗。"
+
+msgid "MemberRoles|Failed to fetch roles."
+msgstr "æ“·å–角色失敗。"
+
+msgid "MemberRoles|ID"
+msgstr "ID"
+
+msgid "MemberRoles|Incident manager"
+msgstr "事件管ç†å“¡"
+
+msgid "MemberRoles|Make sure the group has an Ultimate license."
+msgstr "確ä¿ç¾¤çµ„æ“有 Ultimate 授權。"
+
+msgid "MemberRoles|Name"
+msgstr "å稱"
+
+msgid "MemberRoles|No custom roles for this group"
+msgstr "此群組無自訂角色"
+
+msgid "MemberRoles|Permissions"
+msgstr "權é™"
+
+msgid "MemberRoles|Read code"
+msgstr "讀å–程å¼ç¢¼"
+
+msgid "MemberRoles|Read vulnerability"
+msgstr "讀å–æ¼æ´ž"
+
+msgid "MemberRoles|Removing a custom role also removes all members with this custom role from the group. If you decide to delete a custom role, you must re-add these users to the group."
+msgstr "移除自訂角色也會從群組中移除具有此自訂角色的所有æˆå“¡ã€‚若您決定刪除自訂角色,則必須將這些使用者é‡æ–°æ–°å¢žåˆ°ç¾¤çµ„中。"
+
+msgid "MemberRoles|Role name"
+msgstr "角色å稱"
+
+msgid "MemberRoles|Role successfully created."
+msgstr "å·²æˆåŠŸå»ºç«‹è§’色。"
+
+msgid "MemberRoles|Role successfully deleted."
+msgstr "å·²æˆåŠŸåˆªé™¤è§’色。"
+
+msgid "MemberRoles|Select a standard role to add permissions."
+msgstr "é¸å–標準角色以新增權é™ã€‚"
+
+msgid "MemberRoles|To add a new role select 'Add new role'."
+msgstr ""
+
+msgid "MemberRoles|To add a new role select a group and then 'Add new role'."
+msgstr "è¦æ–°å¢žè§’色,請é¸å–一個群組,然後é¸å–「新增角色ã€ã€‚"
+
msgid "MemberRole|%{requirement} has to be enabled in order to enable %{permission}."
msgstr "必須先啟用%{requirement} æ‰èƒ½å•Ÿç”¨ %{permission}。"
@@ -29021,6 +29037,9 @@ msgstr "åˆä½µæ交消æ¯"
msgid "Merge conflicts"
msgstr "åˆä½µè¡çª"
+msgid "Merge date & time could not be determined"
+msgstr "無法確定åˆä½µæ—¥æœŸå’Œæ™‚é–“"
+
msgid "Merge details"
msgstr "åˆä½µè©³æƒ…"
@@ -29453,9 +29472,6 @@ msgstr "指標與分æž"
msgid "Metrics:"
msgstr "指標:"
-msgid "MetricsDashboardAnnotation|can't be before starting_at time"
-msgstr "ä¸èƒ½åœ¨ starting_at 時間之å‰"
-
msgid "Metrics|Create metric"
msgstr "建立指標"
@@ -29552,6 +29568,9 @@ msgstr "Microsoft Azure æ•´åˆè¨­å®šå„²å­˜å¤±æ•—。 %{errors}"
msgid "Microsoft|Microsoft Azure integration settings were successfully updated."
msgstr "Microsoft Azure æ•´åˆè¨­å®šå·²æˆåŠŸæ›´æ–°ã€‚"
+msgid "Microsoft|Sync group memberships from Microsoft Azure when SAML response includes an overage claim."
+msgstr "當 SAML 回應中包å«è¶…é¡è²æ˜Žæ™‚,從 Microsoft Azure åŒæ­¥ç¾¤çµ„æˆå“¡èº«ä»½ã€‚"
+
msgid "Microsoft|Tenant ID"
msgstr "租戶 ID"
@@ -30430,12 +30449,12 @@ msgstr "哪些æ“作會å—é™åˆ¶ï¼Ÿ"
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name_with_link} (%{current_size} of %{limit})."
msgstr "您已使用 %{used_storage_percentage} çš„ %{limit} 儲存é…é¡ä¸­çš„ %{name_with_link} (%{current_size})。"
+msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{namespace_name}"
+msgstr "您已使用了 %{namespace_name} %{used_storage_percentage} 的儲存é¡åº¦ "
+
msgid "NamespaceStorage|You have used %{used_storage_percentage} of the storage quota for %{name} (%{current_size} of %{limit})."
msgstr "您已使用 %{used_storage_percentage} çš„ %{limit} 儲存é…é¡ä¸­çš„ %{name} (%{current_size})。"
-msgid "NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}"
-msgstr "您已使用 %{used_storage_percentage}%% çš„ %{namespace_name} 儲存é…é¡ã€‚"
-
msgid "NamespaceUserCap|Pending users must be reviewed and approved by a group owner. Learn more about %{user_caps_link_start}user caps%{link_end} and %{users_pending_approval_link_start}users pending approval%{link_end}."
msgstr "需è¦å¯©æ ¸çš„使用者必須由群組所有者審核。了解更多關於%{user_caps_link_start}使用者上é™%{link_end}å’Œ%{users_pending_approval_link_start}使用者等待核准%{link_end}的訊æ¯ã€‚"
@@ -30511,6 +30530,9 @@ msgstr "分æž"
msgid "Navigation|Build"
msgstr "建置"
+msgid "Navigation|CI/CD settings"
+msgstr "CI/CD 設定"
+
msgid "Navigation|Code"
msgstr "原始碼"
@@ -30541,15 +30563,18 @@ msgstr "您經常訪å•çš„群組會顯示在這裡。"
msgid "Navigation|Leave admin mode"
msgstr "離開管ç†å“¡æ¨¡å¼"
-msgid "Navigation|Main navigation"
-msgstr "主導覽"
-
msgid "Navigation|Manage"
msgstr "管ç†"
+msgid "Navigation|Merge requests settings"
+msgstr "åˆä½µè«‹æ±‚設定"
+
msgid "Navigation|Monitor"
msgstr "監控"
+msgid "Navigation|Monitor settings"
+msgstr "監控設定"
+
msgid "Navigation|No group matches found"
msgstr "未找到相符的群組"
@@ -30568,12 +30593,18 @@ msgstr "已釘é¸"
msgid "Navigation|Plan"
msgstr "計劃"
+msgid "Navigation|Primary"
+msgstr "主è¦"
+
msgid "Navigation|Projects"
msgstr "專案"
msgid "Navigation|Projects you visit often will appear here."
msgstr "您經常訪å•çš„專案會顯示在這裡。"
+msgid "Navigation|Repository settings"
+msgstr "版本庫設定"
+
msgid "Navigation|Retrieving search results"
msgstr "尋找查詢çµæžœ"
@@ -30592,6 +30623,12 @@ msgstr "å–å¾—æœå°‹çµæžœæ™‚發生錯誤。"
msgid "Navigation|Unpin item"
msgstr "å–消釘é¸é …ç›®"
+msgid "Navigation|View all my groups"
+msgstr "查看我所有的群組"
+
+msgid "Navigation|View all my projects"
+msgstr "查看我所有的專案"
+
msgid "Navigation|View all your groups"
msgstr "查看您的所有群組"
@@ -30815,9 +30852,6 @@ msgstr "議題#%{issue_iid}的新回復:"
msgid "New runners registration token has been generated!"
msgstr "已生æˆæ–°çš„執行器(Runner)註冊令牌ï¼"
-msgid "New schedule"
-msgstr "新增排程"
-
msgid "New snippet"
msgstr "新增程å¼ç¢¼ç‰‡æ®µ"
@@ -31025,6 +31059,9 @@ msgstr "無迭代"
msgid "No label"
msgstr "無標記"
+msgid "No labels found"
+msgstr "未找到標記"
+
msgid "No labels with such name or description"
msgstr "沒有具有此類å稱或æ述的標記"
@@ -31049,6 +31086,12 @@ msgstr "沒有符åˆçš„çµæžœ"
msgid "No matching results for \"%{query}\""
msgstr "沒有與\"%{query}\"符åˆçš„çµæžœ"
+msgid "No matching work item found."
+msgstr "找ä¸åˆ°ç¬¦åˆçš„工作項。"
+
+msgid "No matching work item found. Make sure you are adding a valid ID and you have access to the item."
+msgstr "找ä¸åˆ°ç›¸ç¬¦çš„工作項目,請確ä¿æ‚¨æ­£åœ¨åŠ å…¥çš„ ID 有效,並且您有存å–該項目的權é™ã€‚"
+
msgid "No members found"
msgstr "未找到æˆå“¡"
@@ -31067,12 +31110,15 @@ msgstr "無里程碑"
msgid "No more than %{max_issues} issues can be updated at the same time"
msgstr "ä¸èƒ½åŒæ™‚é–“æ›´æ–°è¶…éŽ %{max_issues} 個å•é¡Œ"
+msgid "No more than %{max_work_items} work items can be modified at the same time."
+msgstr "åŒä¸€æ™‚間最多åªèƒ½ä¿®æ”¹ %{max_work_items} 個工作項目。"
+
+msgid "No options found"
+msgstr "未找到é¸é …"
+
msgid "No other labels with such name or description"
msgstr "沒有其他具有此類å稱或æ述的標記"
-msgid "No panels matching properties %{opts}"
-msgstr "沒有與屬性相符的é¢æ¿%{opts}"
-
msgid "No parent group"
msgstr "父群組ä¸å­˜åœ¨"
@@ -31127,9 +31173,6 @@ msgstr "æœå°‹ä¸åˆ°è³‡æ–™"
msgid "No runner executable"
msgstr "沒有執行器å¯åŸ·è¡Œæ–‡ä»¶"
-msgid "No schedules"
-msgstr "沒有排程"
-
msgid "No service accounts"
msgstr "沒有æœå‹™å¸³è™Ÿ"
@@ -31181,6 +31224,12 @@ msgstr "沒有 webhook 事件"
msgid "No webhooks enabled. Select trigger events above."
msgstr "未啟用 webhook。é¸æ“‡ä¸Šé¢çš„觸發事件。"
+msgid "No work item IDs provided."
+msgstr "未æ供工作項目編號。"
+
+msgid "No work item found."
+msgstr "未找到工作項。"
+
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
msgstr[0] "ä¸ç”¨æ“”心,您ç¾åœ¨ä»ç„¶å¯ä»¥ä½¿ç”¨æ‰€æœ‰ %{strong}%{plan_name}%{strong_close} 功能。您有 %{remaining_days} 天來續訂您的訂閱。"
@@ -32379,6 +32428,9 @@ msgstr "您的一個或多個個人存å–令牌已éŽæœŸã€‚"
msgid "One or more of your personal access tokens will expire in %{days_to_expire} days or less:"
msgstr "您的一個或多個個人存å–令牌將在 %{days_to_expire} 天或更短的時間內到期:"
+msgid "One or more of your resource access tokens will expire in %{days_to_expire} or less:"
+msgstr "一個或多個您的資æºå­˜å–令牌將在 %{days_to_expire} 天或更少時間內éŽæœŸï¼š"
+
msgid "Only %{workspaceType} members with %{permissions} can view or be notified about this %{issuableType}."
msgstr "僅具有 %{permissions} çš„ %{workspaceType} æˆå“¡å¯ä»¥æŸ¥çœ‹æˆ–收到有關此 %{issuableType} 的通知。"
@@ -32406,9 +32458,6 @@ msgstr "僅 %{membersPageLinkStart} 專案æˆå“¡ %{membersPageLinkEnd} å¯ä»¥å­˜
msgid "Only active projects show up in the search and on the dashboard."
msgstr "僅啟用的專案顯示在æœå°‹å’Œå„€è¡¨æ¿ä¸Šã€‚"
-msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr "僅在啟用é ç¨‹å„²å­˜æ™‚有效。設定為 0 表示沒有大å°é™åˆ¶ã€‚"
-
msgid "Only include features new to your current subscription tier."
msgstr "僅包括您當å‰è¨‚閱級別的新功能。"
@@ -32571,24 +32620,60 @@ msgstr "é¸é …"
msgid "Ordered list"
msgstr "項目清單"
+msgid "Organization"
+msgstr ""
+
msgid "Organizations"
msgstr "組織"
+msgid "Organization|A group is a collection of several projects. If you organize your projects under a group, it works like a folder."
+msgstr ""
+
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
msgstr "載入群組時發生錯誤。請é‡æ–°æ•´ç†é é¢ä¸¦é‡è©¦ã€‚"
msgid "Organization|An error occurred loading the projects. Please refresh the page to try again."
msgstr "組織載入專案時發生錯誤。請刷新é é¢é‡è©¦ã€‚"
+msgid "Organization|Copy organization ID"
+msgstr "複製組織 ID"
+
+msgid "Organization|Frequently visited groups"
+msgstr "經常訪å•çš„群組"
+
+msgid "Organization|Frequently visited projects"
+msgstr "經常訪å•çš„專案"
+
+msgid "Organization|New organization"
+msgstr "新組織"
+
+msgid "Organization|Org ID"
+msgstr "組織 ID"
+
msgid "Organization|Organization navigation"
msgstr "組織組織導航"
msgid "Organization|Organization overview"
msgstr "組織總覽"
+msgid "Organization|Organizations"
+msgstr "組織"
+
+msgid "Organization|Public - The organization can be accessed without any authentication."
+msgstr "公開 - 無需任何驗證å³å¯å­˜å–該組織。"
+
msgid "Organization|Search or filter list"
msgstr "查詢或éŽæ¿¾æ¸…å–®"
+msgid "Organization|View all"
+msgstr "查看全部"
+
+msgid "Organization|You don't have any groups yet."
+msgstr ""
+
+msgid "Organization|You don't have any projects yet."
+msgstr ""
+
msgid "Orphaned member"
msgstr "孤兒æˆå“¡"
@@ -33301,6 +33386,9 @@ msgstr "Pages"
msgid "Pages Domain"
msgstr "Pages網域"
+msgid "PagesDomain|Certificate Key is too long. (Max %d bytes)"
+msgstr "憑證密鑰太長。(最大 %d 個字元)"
+
msgid "Pagination|First"
msgstr "首é "
@@ -33448,8 +33536,11 @@ msgstr "路徑"
msgid "Path:"
msgstr "路徑:"
-msgid "Paths to protect with rate limiting"
-msgstr "使用速率é™åˆ¶ä¿è­·çš„路徑"
+msgid "Paths with rate limiting for GET requests"
+msgstr "å° GET 請求進行速率é™åˆ¶çš„路徑"
+
+msgid "Paths with rate limiting for POST requests"
+msgstr "å° POST 請求進行速率é™åˆ¶çš„路徑"
msgid "Pause"
msgstr "æš«åœ"
@@ -33895,9 +33986,6 @@ msgstr "自訂(%{linkStart}了解更多%{linkEnd}。)"
msgid "PipelineSchedules|A scheduled pipeline starts automatically at regular intervals, like daily or weekly. The pipeline: "
msgstr "排定的æµæ°´ç·šæœƒå®šæœŸè‡ªå‹•å•Ÿå‹•ï¼Œä¾‹å¦‚æ¯å¤©æˆ–æ¯é€±ã€‚æµæ°´ç·šï¼š "
-msgid "PipelineSchedules|Activated"
-msgstr "是å¦å•Ÿç”¨"
-
msgid "PipelineSchedules|Active"
msgstr "已啟用"
@@ -34012,12 +34100,6 @@ msgstr "執行æµæ°´ç·šæŽ’程時出ç¾å•é¡Œã€‚"
msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr "å–å¾—æµæ°´ç·šæŽ’程所有權時發生å•é¡Œã€‚"
-msgid "PipelineSchedules|Variables"
-msgstr "變數"
-
-msgid "PipelineSchedule|Take ownership to edit"
-msgstr "å–得所有權進行編輯"
-
msgid "PipelineSource|API"
msgstr "API"
@@ -34468,6 +34550,9 @@ msgstr "無法å–å¾—æµæ°´ç·šç‹€æ…‹ã€‚有關故障排除步驟,請åƒé–±%{link
msgid "Pipeline|Created"
msgstr "已建立"
+msgid "Pipeline|Created by"
+msgstr "建立由"
+
msgid "Pipeline|Creating pipeline."
msgstr "正在建立æµæ°´ç·šã€‚"
@@ -34591,9 +34676,6 @@ msgstr "è¦æŸ¥çœ‹å‰©é¤˜ä½œæ¥­ï¼Œè«‹ç§»è‡³ %{boldStart}Jobs%{boldEnd} é ç°½ã€‚"
msgid "Pipeline|Trigger author"
msgstr "觸發者"
-msgid "Pipeline|Triggerer"
-msgstr "觸發者"
-
msgid "Pipeline|Variables"
msgstr "變數"
@@ -35116,9 +35198,6 @@ msgstr "佈局寬度"
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr "必須為%{min}到%{max}之間的數字"
-msgid "Preferences|Note: You have the new navigation enabled, so only Dark Mode theme significantly changes GitLab's appearance."
-msgstr "注æ„:您已啟用新的導航,因此僅暗黑模å¼ä¸»é¡Œæœƒé¡¯è‘—改變 GitLab 的外觀。"
-
msgid "Preferences|Preview"
msgstr "é è¦½"
@@ -35230,6 +35309,9 @@ msgstr "上一次未解決的討論"
msgid "Primary Action"
msgstr "主è¦æ“作"
+msgid "Primary navigation sidebar"
+msgstr "主è¦å°Žèˆªå´é‚Šæ¬„"
+
msgid "Print as PDF"
msgstr "列å°ç‚º PDF"
@@ -35353,9 +35435,6 @@ msgstr "返回儀表æ¿"
msgid "ProductAnalytics|Click Events"
msgstr "點擊事件"
-msgid "ProductAnalytics|Clickhouse URL"
-msgstr "Clickhouse URL"
-
msgid "ProductAnalytics|Compares all events against each other"
msgstr "將所有事件互相比較"
@@ -35371,9 +35450,6 @@ msgstr "比較所有功能的功能使用情æ³"
msgid "ProductAnalytics|Compares page views of all pages against each other"
msgstr "比較所有é é¢çš„ç€è¦½é‡"
-msgid "ProductAnalytics|Connection string"
-msgstr "連線字串"
-
msgid "ProductAnalytics|Create a visualization"
msgstr "建立視覺化"
@@ -35410,9 +35486,6 @@ msgstr "更多資訊請åƒé–± %{linkStart}文件%{linkEnd}。"
msgid "ProductAnalytics|For the product analytics dashboard to start showing you some data, you need to add the analytics tracking code to your project."
msgstr "è¦è®“產å“分æžå„€è¡¨æ¿é–‹å§‹é¡¯ç¤ºä¸€äº›è³‡æ–™ï¼Œæ‚¨éœ€è¦å°‡åˆ†æžè·Ÿè¸ªç¨‹å¼ç¢¼åŠ å…¥åˆ°å°ˆæ¡ˆä¸­ã€‚"
-msgid "ProductAnalytics|Go back"
-msgstr "返回"
-
msgid "ProductAnalytics|How many sessions a user has"
msgstr "一個使用者有多少會話"
@@ -35473,6 +35546,9 @@ msgstr "設定產å“分æž"
msgid "ProductAnalytics|Set up to track how your product is performing and optimize your product and development processes."
msgstr "設置以追蹤您的產å“表ç¾ï¼Œä¸¦å„ªåŒ–產å“和開發æµç¨‹ã€‚"
+msgid "ProductAnalytics|Snowplow configurator connection string"
+msgstr "Snowplow é…置連çµå­—串"
+
msgid "ProductAnalytics|The connection string for your Snowplow configurator instance."
msgstr "Snowplow 設定器站å°çš„連線字串。"
@@ -35497,9 +35573,6 @@ msgstr "追蹤特定功能"
msgid "ProductAnalytics|Unique Users"
msgstr "ç¨ç«‹ä½¿ç”¨è€…"
-msgid "ProductAnalytics|Used to connect Snowplow to the Clickhouse instance."
-msgstr "用來將 Snowplow 連çµåˆ° Clickhouse ç«™å°ã€‚"
-
msgid "ProductAnalytics|Used to retrieve dashboard data from the Cube instance."
msgstr "用來從 Cube ç«™å°ä¸­æ“·å–儀表æ¿è³‡æ–™ã€‚"
@@ -35731,8 +35804,8 @@ msgstr "ä¸è¦åœ¨å€‹äººæª”案上顯示與活動相關的ç§äººè³‡è¨Š."
msgid "Profiles|Edit Profile"
msgstr "編輯個人資料"
-msgid "Profiles|Email"
-msgstr "é›»å­éƒµä»¶"
+msgid "Profiles|Email address"
+msgstr "é›»å­éƒµä»¶åœ°å€"
msgid "Profiles|Email addresses"
msgstr "é›»å­éƒµä»¶åœ°å€"
@@ -36166,9 +36239,6 @@ msgstr "專案或群組"
msgid "Project order will not be saved as local storage is not available."
msgstr "由於本機儲存ä¸å¯ç”¨ï¼Œå› æ­¤ä¸æœƒå„²å­˜å°ˆæ¡ˆé †åºã€‚"
-msgid "Project overview"
-msgstr "專案總覽"
-
msgid "Project path"
msgstr "專案路徑"
@@ -36658,6 +36728,12 @@ msgstr "特性標籤"
msgid "ProjectSettings|Flexible tool to collaboratively develop ideas and plan work in this project."
msgstr "用於在此專案中å”作開發想法和計劃工作的éˆæ´»å·¥å…·ã€‚"
+msgid "ProjectSettings|For Gitaly, location of data on the storage. For Gitaly Cluster, location of data on the virtual storage."
+msgstr "å°æ–¼ Gitaly,資料在儲存上的ä½ç½®ã€‚å°æ–¼ Gitaly å¢é›†ï¼Œè³‡æ–™åœ¨è™›æ“¬å„²å­˜ä¸Šçš„ä½ç½®ã€‚"
+
+msgid "ProjectSettings|For Gitaly, name of the storage that stores the repository. For Gitaly Cluster, name of the virtual storage that stores the repository."
+msgstr "å°æ–¼ Gitaly,版本庫儲存的å稱。å°æ–¼ Gitaly å¢é›†ï¼Œç‰ˆæœ¬åº«å„²å­˜çš„虛擬儲存å稱。"
+
msgid "ProjectSettings|Forks"
msgstr "分å‰ï¼ˆFork)"
@@ -36793,6 +36869,9 @@ msgstr "公開的"
msgid "ProjectSettings|Publish, store, and view packages in a project."
msgstr "在專案內發布ã€å„²å­˜å’ŒæŸ¥çœ‹è»Ÿé«”包。"
+msgid "ProjectSettings|Relative path:"
+msgstr "相å°è·¯å¾‘:"
+
msgid "ProjectSettings|Releases"
msgstr "發布"
@@ -36865,6 +36944,9 @@ msgstr "æ°¸é ä¸æœƒåŸ·è¡Œå£“縮 (Squash) ,且該複é¸æ¡†æ˜¯éš±è—的。"
msgid "ProjectSettings|Status checks must succeed"
msgstr "狀態檢查必須æˆåŠŸ"
+msgid "ProjectSettings|Storage name:"
+msgstr "儲存å稱:"
+
msgid "ProjectSettings|Store custom configuration files."
msgstr "儲存自定義組態文件。"
@@ -37684,6 +37766,12 @@ msgstr "程å¼ç¢¼æ‰€æœ‰è€…核准"
msgid "ProtectedBranch|Create wildcard"
msgstr "建立è¬ç”¨å­—å…ƒ"
+msgid "ProtectedBranch|Does not apply to users **Allowed to push** when pushing directly to the branch. Optional sections are not enforced."
+msgstr "當直接推é€åˆ°åˆ†æ”¯æ™‚,無法套用使用者**å…許推é€**,é¸æ“‡æ€§éƒ¨åˆ†ä¸å—強制執行。"
+
+msgid "ProtectedBranch|Giving merge rights to a protected branch also gives elevated permissions for certain CI/CD features."
+msgstr "å°‡ä¿è­·åˆ†æ”¯æŽˆäºˆåˆä½µæ¬Šé™ä¹Ÿæœƒæå‡æŸäº›CI/CD功能的權é™ã€‚"
+
msgid "ProtectedBranch|Inherited - This setting can be changed at the group level"
msgstr "繼承 - 該設定å¯ä»¥åœ¨ç¾¤çµ„級別變更"
@@ -37756,8 +37844,8 @@ msgstr "å°‡å—ä¿è­·çš„分支視為分支è¦å‰‡æŸ¥çœ‹"
msgid "ProtectedBranch|What are protected branches?"
msgstr "什麼是å—ä¿è­·çš„分支?"
-msgid "ProtectedBranch|When pushing directly to the branch. Does not apply to users **Allowed to push**. Optional sections are not enforced."
-msgstr "當直接推é€åˆ°åˆ†æ”¯æ™‚,ä¸é©ç”¨æ–¼**å…許推é€**的使用者,é¸å¡«çš„部分ä¸å¼·åˆ¶åŸ·è¡Œã€‚"
+msgid "ProtectedBranch|What are the security implications?"
+msgstr "有哪些安全隱患?"
msgid "ProtectedBranch|You can add only groups that have this project shared. %{learn_more_link}"
msgstr "您åªèƒ½å¢žåŠ å…±äº«æ­¤å°ˆæ¡ˆçš„群組。 %{learn_more_link}"
@@ -37809,12 +37897,15 @@ msgstr "刪除部署者è¦å‰‡"
msgid "ProtectedEnvironments|Edit"
msgstr "編輯"
-msgid "ProtectedEnvironments|List of protected environments (%{protectedEnvironmentsCount})"
-msgstr "å—ä¿è­·çš„環境清單 (%{protectedEnvironmentsCount})"
-
msgid "ProtectedEnvironments|Number of approvals must be between 1 and 5"
msgstr "批准數é‡å¿…須介於 1 至 5 之間"
+msgid "ProtectedEnvironments|Protect an environment"
+msgstr "ä¿è­·ç’°å¢ƒ"
+
+msgid "ProtectedEnvironments|Protected environments"
+msgstr "å—ä¿è­·çš„環境"
+
msgid "ProtectedEnvironments|Remove approval rule"
msgstr "移除核准è¦å‰‡"
@@ -37824,6 +37915,9 @@ msgstr "需è¦çš„核准數"
msgid "ProtectedEnvironments|Save"
msgstr "儲存"
+msgid "ProtectedEnvironments|Select users"
+msgstr "é¸å–使用者"
+
msgid "ProtectedEnvironments|Set which groups, access levels or users are required to approve."
msgstr "設定哪些群組ã€å­˜å–等級或使用者需è¦æ‰¹å‡†ã€‚"
@@ -37842,6 +37936,9 @@ msgstr "使用者"
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr "%{environment_name} å°‡å°é–‹ç™¼äººå“¡å¯å¯«å…¥ï¼Œç¢ºå®šç¹¼çºŒå—Žï¼Ÿ"
+msgid "ProtectedEnvironment|Add new protected environment"
+msgstr "新增å—ä¿è­·çš„環境"
+
msgid "ProtectedEnvironment|All environments specified with the deployment tiers below are protected by a parent group. %{link_start}Learn More%{link_end}."
msgstr "使用以下部署層級所指定的所有環境å‡å—父群組的ä¿è­·ï¼Œ%{link_start}了解更多%{link_end}。"
@@ -37899,9 +37996,6 @@ msgstr "é¸å–環境"
msgid "ProtectedEnvironment|Select groups"
msgstr "é¸æ“‡ç¾¤çµ„"
-msgid "ProtectedEnvironment|Select users"
-msgstr "é¸æ“‡ä½¿ç”¨è€…"
-
msgid "ProtectedEnvironment|There are currently no protected environments."
msgstr "ç›®å‰æ²’有å—ä¿è­·çš„環境。"
@@ -37968,9 +38062,6 @@ msgstr "æ供說明"
msgid "Provisioned by:"
msgstr "æ供者:"
-msgid "Proxy support for this API is not available currently"
-msgstr "æ­¤APIç›®å‰ä¸æ”¯æ´ä½¿ç”¨ä»£ç†"
-
msgid "Public"
msgstr "公開"
@@ -38331,9 +38422,6 @@ msgstr "通éŽé›»å­éƒµä»¶æŽ¥æ”¶æ¿«ç”¨å ±å‘Šé€šçŸ¥ã€‚"
msgid "Receive notifications about your own activity"
msgstr "接收關於您自己活動的通知"
-msgid "Receive product marketing emails"
-msgstr "接收產å“營銷電å­éƒµä»¶"
-
msgid "Recent"
msgstr "最近"
@@ -38473,35 +38561,11 @@ msgstr "å‘使用者發é€é›»å­éƒµä»¶"
msgid "RegistrationFeatures|use this feature"
msgstr "使用此功能"
-msgid "RegistrationVerification|Are you sure you want to skip this step?"
-msgstr "您確定è¦è·³éŽé€™ä¸€æ­¥å—Žï¼Ÿ"
-
-msgid "RegistrationVerification|Enable free compute minutes"
-msgstr "啟用å…費計算分é˜æ•¸"
-
-msgid "RegistrationVerification|GitLab will not charge your card, it will only be used for validation."
-msgstr "GitLab ä¸æœƒå¾žæ‚¨çš„å¡ä¸­æ‰£æ¬¾ï¼Œå®ƒåªæœƒç”¨æ–¼é©—證。"
-
-msgid "RegistrationVerification|Pipelines using shared GitLab runners will fail until you validate your account."
-msgstr "請先驗證您的帳號,å¦å‰‡ç„¡æ³•ä½¿ç”¨å…±äº« GitLab 執行器的æµæ°´ç·šã€‚"
-
-msgid "RegistrationVerification|Skip this for now"
-msgstr "暫時跳éŽ"
-
-msgid "RegistrationVerification|To keep GitLab spam and abuse free we ask that you verify your identity with a valid payment method, such as a debit or credit card. Until then, you can't use free compute minutes to build your application."
-msgstr "為了ä¿æŒGitLabå…å—垃圾郵件和濫用å¨è„…,我們è¦æ±‚您使用有效的付款方å¼ï¼ˆä¾‹å¦‚借記å¡æˆ–信用å¡ï¼‰ä¾†é©—證您的身份。在那之å‰ï¼Œæ‚¨ç„¡æ³•ä½¿ç”¨å…費計算分é˜ä¾†å»ºç«‹æ‚¨çš„應用程å¼ã€‚"
+msgid "Registries enqueued to be resynced"
+msgstr "註冊表已排隊等待é‡æ–°åŒæ­¥"
-msgid "RegistrationVerification|Validate account"
-msgstr "驗證帳號"
-
-msgid "RegistrationVerification|Verify your identity"
-msgstr "驗證您的身份"
-
-msgid "RegistrationVerification|Yes, I'd like to skip"
-msgstr "是的,我想跳éŽ"
-
-msgid "RegistrationVerification|You can alway verify your account at a later time."
-msgstr "您å¯ä»¥ç¨å¾Œé©—證您的帳號。"
+msgid "Registries enqueued to be reverified"
+msgstr "註冊表已排隊等待é‡æ–°é©—è­‰"
msgid "Registry entry enqueued to be resynced"
msgstr "註冊表æ¢ç›®å·²æŽ’入佇列等待é‡æ–°åŒæ­¥"
@@ -38834,9 +38898,6 @@ msgstr "å–消電話驗證è±å…"
msgid "Remove priority"
msgstr "移除優先級別"
-msgid "Remove report"
-msgstr "移除報告"
-
msgid "Remove reviewer"
msgstr "移除審核者"
@@ -38849,6 +38910,9 @@ msgstr "移除次è¦é›»å­éƒµä»¶"
msgid "Remove spent time"
msgstr "移除消耗時間"
+msgid "Remove summary"
+msgstr "移除摘è¦"
+
msgid "Remove time estimate"
msgstr "移除時間估計"
@@ -38858,9 +38922,6 @@ msgstr "移除主題頭åƒ"
msgid "Remove user"
msgstr "移除使用者"
-msgid "Remove user & report"
-msgstr "移除使用者和報告"
-
msgid "Remove user from group"
msgstr "從群組中移除使用者"
@@ -39140,12 +39201,6 @@ msgstr "您為何回報此使用者?"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "由%{reportedBy}報告於%{timeAgo}"
-msgid "Reported by"
-msgstr "報告人"
-
-msgid "Reported by %{reporter}"
-msgstr "由%{reporter}報告"
-
msgid "Reporter"
msgstr "報告者"
@@ -39446,9 +39501,6 @@ msgstr "已開始é‡æ–°è¨ˆç®—版本庫使用情æ³"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}"
msgstr "版本庫: %{counter_repositories} / Wikis: %{counter_wikis} / 構建產物: %{counter_build_artifacts} / æµæ°´ç·šç”¢ç‰©ï¼š%{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / 程å¼ç¢¼ç‰‡æ®µ: %{counter_snippets} / 軟體包: %{counter_packages} / 上傳文件: %{counter_uploads}"
-msgid "RepositorySettingsAccessLevel|Select"
-msgstr "é¸æ“‡"
-
msgid "Request"
msgstr "請求"
@@ -39858,6 +39910,9 @@ msgstr "根本原因分æžæ˜¯ä¸€é …功能,å¯åˆ†æžæ‚¨çš„日誌以確定作業
msgid "Ruby"
msgstr "Ruby"
+msgid "Rule name"
+msgstr "è¦å‰‡å稱"
+
msgid "Rule name is already taken."
msgstr "è¦å‰‡å稱已被使用。"
@@ -40283,6 +40338,9 @@ msgstr "%{type}的會員å¯ä»¥è¨»å†ŠåŸ·è¡Œå™¨"
msgid "Runners|Minor version upgrades are available."
msgstr "å·²æ供次è¦ç‰ˆæœ¬å‡ç´šã€‚"
+msgid "Runners|Most recent failures"
+msgstr "最近的失敗"
+
msgid "Runners|Multiple tags must be separated by a comma. For example, %{example}."
msgstr "多個標籤必須用逗號分隔,例如,%{example}。"
@@ -40567,8 +40625,8 @@ msgstr "é¸æ“‡è¦æŒ‡æ´¾çµ¦è©²åŸ·è¡Œå™¨(runner)的專案"
msgid "Runners|Select your preferred runner, then choose the capacity for the runner in the AWS CloudFormation console."
msgstr "在此處é¸æ“‡æ‚¨çš„å好執行器,然後在 AWS CloudFormation 主控å°ä¸­é¸æ“‡åŸ·è¡Œå™¨çš„容é‡ã€‚"
-msgid "Runners|Shared runners are disabled in the group settings"
-msgstr "共享執行器在群組設置中被ç¦ç”¨"
+msgid "Runners|Shared runners are disabled in the group settings."
+msgstr "共享執行器在群組設定中被ç¦ç”¨ã€‚"
msgid "Runners|Shared runners are disabled."
msgstr "共享的執行器已ç¦ç”¨ã€‚"
@@ -40649,6 +40707,9 @@ msgstr "一個執行個體執行器接收作業的時間,等待執行器的作
msgid "Runners|The unique ID for each runner that uses this configuration."
msgstr "æ¯å€‹ä½¿ç”¨æ­¤é…置的執行器 (Runner) 都有唯一的 ID。"
+msgid "Runners|There are no recent runner failures for your instance runners. Error messages will populate here if runners fail."
+msgstr "沒有最近的執行個體執行器失敗記錄,如果執行器失敗,錯誤訊æ¯å°‡åœ¨æ­¤é¡¯ç¤ºã€‚"
+
msgid "Runners|There are no runners running jobs right now. Active runners will populate here as they pick up jobs."
msgstr "ç›®å‰æ²’有é‹è¡Œä»»å‹™çš„執行器,當執行器撿å–任務時,啟用的執行器會顯示在此處。"
@@ -40857,6 +40918,9 @@ msgstr "è¦åœ¨æ‚¨ä½¿ç”¨å–®é»žç™»å…¥æˆåŠŸç™»å…¥å¾Œå…許 %{strongOpen}%{group_na
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "您組織的 SSO 已連接到您的 GitLab 帳號"
+msgid "SBOMs last updated"
+msgstr "最後更新的 SBOM "
+
msgid "SCIM|SCIM Token"
msgstr "SCIM 憑證"
@@ -40965,9 +41029,6 @@ msgstr "ä¿å­˜å…§éƒ¨è¨»é‡‹"
msgid "Save password"
msgstr "儲存密碼"
-msgid "Save pipeline schedule"
-msgstr "儲存æµæ°´ç·šæŽ’程"
-
msgid "Saving"
msgstr "儲存中"
@@ -40980,8 +41041,8 @@ msgstr "%{hostname}的時å€"
msgid "ScanExecutionPolicy|%{period} %{days} at %{time} %{timezoneLabel} %{timezone}"
msgstr "%{period} %{days} 在 %{time} %{timezoneLabel} %{timezone}"
-msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period}"
-msgstr "%{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces} %{period} 的 %{rules} 動作"
+msgid "ScanExecutionPolicy|%{rules} actions for %{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}"
+msgstr "%{scopes} %{branches} %{agents} %{branchExceptions} %{namespaces} %{period}çš„%{rules} æ“作"
msgid "ScanExecutionPolicy|%{rules} every time a pipeline runs for %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces}"
msgstr "æ¯æ¬¡æµæ°´ç·šåŸ·è¡Œæ™‚,å°æ–¼ %{scopes} %{branches} %{branchExceptions} %{agents} %{namespaces},都會éµå¾ª %{rules}。"
@@ -41106,11 +41167,14 @@ msgstr "年齡標準僅é©ç”¨æ–¼ç¾æœ‰æ¼æ´ž"
msgid "ScanResultPolicy|Age is:"
msgstr "年齡為:"
-msgid "ScanResultPolicy|Block users from unprotecting branches"
-msgstr "阻止使用者存å–未ä¿è­·çš„分支"
+msgid "ScanResultPolicy|Attribute is:"
+msgstr "屬性為:"
+
+msgid "ScanResultPolicy|Attribute:"
+msgstr "屬性:"
-msgid "ScanResultPolicy|Choose an option"
-msgstr "é¸æ“‡é¸é …"
+msgid "ScanResultPolicy|Attributes are automatically applied by the scanners"
+msgstr "屬性由掃æ器自動套用"
msgid "ScanResultPolicy|Choose criteria type"
msgstr "é¸æ“‡æ¢ä»¶é¡žåž‹"
@@ -41124,6 +41188,24 @@ msgstr "自定義 CI 變數"
msgid "ScanResultPolicy|Except"
msgstr "除外"
+msgid "ScanResultPolicy|False positive"
+msgstr "誤報"
+
+msgid "ScanResultPolicy|Fix available"
+msgstr "å¯ç”¨çš„修復"
+
+msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning"
+msgstr "å¯ç”¨çš„修復僅é©ç”¨æ–¼å®¹å™¨å’Œä¾è³´é …掃æ"
+
+msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy."
+msgstr "è‹¥é¸å–,以下é¸é …將會覆寫%{linkStart}專案設定%{linkEnd},但僅影響政策中é¸å–的分支。"
+
+msgid "ScanResultPolicy|Is"
+msgstr "是"
+
+msgid "ScanResultPolicy|Is not"
+msgstr "ä¸æ˜¯"
+
msgid "ScanResultPolicy|License is:"
msgstr "許å¯è­‰ç‚º:"
@@ -41136,8 +41218,8 @@ msgstr "符åˆ"
msgid "ScanResultPolicy|New age"
msgstr "新年齡為:"
-msgid "ScanResultPolicy|New severity"
-msgstr "æ–°åš´é‡æ€§"
+msgid "ScanResultPolicy|New attribute"
+msgstr "新屬性"
msgid "ScanResultPolicy|New status"
msgstr "新狀態"
@@ -41148,8 +41230,8 @@ msgstr "新檢測到"
msgid "ScanResultPolicy|Only 1 age criteria is allowed"
msgstr "僅å…許1個年齡標準"
-msgid "ScanResultPolicy|Only 1 severity is allowed"
-msgstr "僅å…許1個年齡標準"
+msgid "ScanResultPolicy|Only 2 attribute criteria are allowed"
+msgstr "僅å…許 2 個屬性標準"
msgid "ScanResultPolicy|Only 2 status criteria are allowed"
msgstr "僅å…許2個狀態標準"
@@ -41160,6 +41242,12 @@ msgstr "覆寫專案審核設定"
msgid "ScanResultPolicy|Pre-existing"
msgstr "é å…ˆå­˜åœ¨"
+msgid "ScanResultPolicy|Prevent branch protection modification"
+msgstr "防止修改分支ä¿è­·"
+
+msgid "ScanResultPolicy|Protected branch settings"
+msgstr "å—ä¿è­·çš„分支設定"
+
msgid "ScanResultPolicy|Select a scan type before adding criteria"
msgstr "在增加æ¢ä»¶ä¹‹å‰é¸æ“‡æŽƒæé¡žåž‹"
@@ -41187,9 +41275,18 @@ msgstr "當%{scanType} %{scanners}é‹è¡Œåœ¨%{branches} %{branchExceptions}上時
msgid "ScanResultPolicy|When %{scanType} in an open merge request targeting %{branches} %{branchExceptions} and the licenses match all of the following criteria:"
msgstr "當在一個開啟的åˆä½µè«‹æ±‚中,掃æ類型為 %{scanType},目標為 %{branches} %{branchExceptions},且所有的許å¯è­‰ç¬¦åˆä»¥ä¸‹æ¨™æº–時:"
+msgid "ScanResultPolicy|When %{scanType} in an open that targets %{branches} %{branchExceptions} with %{commitType}"
+msgstr "當 %{scanType} 在開啟一個é‡å°ä½¿ç”¨ %{commitType} çš„ %{branches} %{branchExceptions} 時"
+
msgid "ScanResultPolicy|When %{scanners} find scanner specified conditions in an open merge request targeting the %{branches} %{branchExceptions} and match %{boldDescription} of the following criteria"
msgstr "當%{scanners}在é‡å°%{branches} %{branchExceptions} 的開放åˆä½µè«‹æ±‚中找到指定的掃æ器æ¢ä»¶ï¼Œä¸¦ç¬¦åˆä»¥ä¸‹æ¨™æº–çš„ %{boldDescription}時"
+msgid "ScanResultPolicy|any commits"
+msgstr "任何æ交"
+
+msgid "ScanResultPolicy|any unsigned commits"
+msgstr "任何未簽åçš„æ交"
+
msgid "ScanResultPolicy|license status"
msgstr "許å¯è­‰ç‹€æ…‹"
@@ -41301,6 +41398,9 @@ msgstr "æœå°‹ç¾¤çµ„"
msgid "Search an environment spec"
msgstr "æœå°‹ç’°å¢ƒè¦ç¯„"
+msgid "Search artifacts"
+msgstr "æœå°‹å·¥ä»¶ç”¢ç‰©"
+
msgid "Search assignees"
msgstr "æœå°‹æŒ‡æ´¾äºº"
@@ -41370,15 +41470,12 @@ msgstr "æœå°‹é‡Œç¨‹ç¢‘"
msgid "Search or filter commits"
msgstr "æœå°‹æˆ–篩é¸æ交"
-msgid "Search or filter results"
-msgstr "查詢或篩é¸çµæžœ"
-
-msgid "Search or filter results..."
-msgstr "æœå°‹æˆ–éŽæ¿¾çµæžœ......"
-
msgid "Search or filter results…"
msgstr "æœå°‹æˆ–éŽæ¿¾çµæžœâ€¦"
+msgid "Search or go to…"
+msgstr "æœå°‹æˆ–å‰å¾€â€¦â€¦"
+
msgid "Search page"
msgstr "æœå°‹é é¢"
@@ -41594,6 +41691,9 @@ msgstr "安全é…ç½®"
msgid "Security dashboard"
msgstr "安全儀表æ¿"
+msgid "Security reports last updated"
+msgstr "最後更新的安全報告"
+
msgid "SecurityApprovals|A merge request approval is required when test coverage declines."
msgstr "當測試覆蓋率下é™æ™‚需è¦åˆä½µè«‹æ±‚核准。"
@@ -41750,6 +41850,12 @@ msgstr "和"
msgid "SecurityOrchestration| and all the following apply:"
msgstr "與以下所有內容å‡é©ç”¨ï¼š"
+msgid "SecurityOrchestration| for any commits"
+msgstr "為任何æ交"
+
+msgid "SecurityOrchestration| for unsigned commits"
+msgstr "為未簽署的æ交"
+
msgid "SecurityOrchestration| or "
msgstr "或 "
@@ -41759,8 +41865,14 @@ msgstr "那是 %{licenseState} 並且是"
msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr "%{agent} 用於 %{namespaces}"
-msgid "SecurityOrchestration|%{cadence} on %{branches}"
-msgstr "在 %{branches} 上的 %{cadence} "
+msgid "SecurityOrchestration|%{branchName}"
+msgstr "%{branchName}"
+
+msgid "SecurityOrchestration|%{branchName} (in %{codeStart}%{fullPath}%{codeEnd})"
+msgstr "%{branchName} (在 %{codeStart}%{fullPath}%{codeEnd} 中)"
+
+msgid "SecurityOrchestration|%{cadence} on %{branches}%{branchExceptionsString}"
+msgstr "%{cadence} 在 %{branches}%{branchExceptionsString}"
msgid "SecurityOrchestration|%{licenses} and %{lastLicense}"
msgstr "%{licenses} 和 %{lastLicense}"
@@ -41816,6 +41928,9 @@ msgstr "讀å–掃æçµæžœæ”¿ç­–時發生錯誤"
msgid "SecurityOrchestration|And scans to be performed:"
msgstr "è¦åŸ·è¡Œçš„掃æ"
+msgid "SecurityOrchestration|Any merge request"
+msgstr "任何åˆä½µè«‹æ±‚"
+
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr "您確定è¦åˆªé™¤æ­¤æ”¿ç­–嗎? æ­¤æ“作無法撤消。"
@@ -41888,8 +42003,8 @@ msgstr "已啟用"
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
msgstr "強制執行此專案的安全性。 %{linkStart}更多訊æ¯ã€‚%{linkEnd}"
-msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}"
-msgstr "在 %{branches} 上æ¯æ¬¡åŸ·è¡Œçš„æµæ°´ç·š"
+msgid "SecurityOrchestration|Every time a pipeline runs for %{branches}%{branchExceptionsString}"
+msgstr "æ¯æ¬¡æ°´ç·šé‹è¡Œæ™‚,都會é©ç”¨æ–¼ %{branches}%{branchExceptionsString} "
msgid "SecurityOrchestration|Exceptions"
msgstr "異常"
@@ -41900,12 +42015,18 @@ msgstr "載入å¢é›†ä»£ç†å¤±æ•—。"
msgid "SecurityOrchestration|Failed to load images."
msgstr "無法載入圖åƒã€‚"
+msgid "SecurityOrchestration|For any merge request on %{branches}%{commitType}%{branchExceptionsString}"
+msgstr "為 %{branches}%{commitType}%{branchExceptionsString} 上的任何åˆä½µè«‹æ±‚"
+
msgid "SecurityOrchestration|For large groups, there may be a significant delay in applying policy changes to pre-existing merge requests. Policy changes typically apply almost immediately for newly created merge requests."
msgstr "å°æ–¼å¤§åž‹ç¾¤çµ„,將政策更改套用於é å…ˆå­˜åœ¨çš„åˆä½µè«‹æ±‚å¯èƒ½æœƒæœ‰æ˜Žé¡¯çš„延é²ï¼›ç­–略更改通常幾乎立å³é©ç”¨æ–¼æ–°å»ºç«‹çš„åˆä½µè«‹æ±‚。"
msgid "SecurityOrchestration|Groups"
msgstr "群組"
+msgid "SecurityOrchestration|Hide extra branches"
+msgstr "éš±è—é¡å¤–的分支"
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr "如果任何掃æ器在é‡å°ä¸»åˆ†æ”¯çš„開放åˆä½µè«‹æ±‚中發ç¾æ–°æª¢æ¸¬çš„åš´é‡æ¼æ´žï¼Œå‰‡éœ€è¦å–得應用程å¼å®‰å…¨çš„任何æˆå“¡çš„兩次核准。"
@@ -42171,6 +42292,9 @@ msgstr "使用掃æçµæžœæ”¿ç­–建立è¦å‰‡ï¼Œåœ¨åˆä½µåˆä½µè«‹æ±‚之å‰æª¢æŸ¥
msgid "SecurityOrchestration|View policy project"
msgstr "查看政策專案"
+msgid "SecurityOrchestration|Vulnerabilities %{vulnerabilityStates}."
+msgstr "æ¼æ´ž %{vulnerabilityStates}。"
+
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr "æ¼æ´žç‚º %{vulnerabilityStates}。"
@@ -42183,14 +42307,14 @@ msgstr "æ¼æ´žå¹´é½¡å°æ–¼ %{vulnerabilityAge}。"
msgid "SecurityOrchestration|Vulnerability age requires previously existing vulnerability states (detected, confirmed, resolved, or dismissed)"
msgstr "æ¼æ´žçš„年齡需è¦å…ˆå‰å­˜åœ¨çš„æ¼æ´žç‹€æ…‹ï¼ˆå·²æª¢æ¸¬ã€å·²ç¢ºèªã€å·²è§£æ±ºæˆ–已解除)"
-msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{criteriaApply}"
-msgstr "當 %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} 在一個é‡å° %{targeting}%{branches}%{criteriaApply} é–‹å•Ÿçš„åˆä½µè«‹æ±‚中"
+msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply}"
+msgstr "當 %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} 在一個é‡å° %{targeting}%{branches}%{branchExceptionsString}%{criteriaApply} é–‹å•Ÿçš„åˆä½µè«‹æ±‚中"
-msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr "當許å¯è­‰æŽƒæ器在é‡å° %{targeting}%{branches} é–‹å•Ÿçš„åˆä½µè«‹æ±‚中找到除了%{licenses}%{detection} 之外的任何許å¯è­‰æ™‚。"
+msgid "SecurityOrchestration|When license scanner finds any license except %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "當授權æ¢æ¬¾æŽƒæ器在é‡å° %{targeting}%{branches}%{branchExceptionsString} é–‹å•Ÿçš„åˆä½µè«‹æ±‚中找到除了 %{licenses}%{detection} 之外的任何授權æ¢æ¬¾æ™‚。"
-msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}."
-msgstr "當許å¯è­‰æŽƒæ器在開啟的åˆä½µè«‹æ±‚中發ç¾ä»»ä½•ç¬¦åˆ %{licenses}%{detection} 的許å¯è­‰æ™‚,它會將其套用於 %{targeting}%{branches}。"
+msgid "SecurityOrchestration|When license scanner finds any license matching %{licenses}%{detection} in an open merge request %{targeting}%{branches}%{branchExceptionsString}"
+msgstr "當授權æ¢æ¬¾æŽƒæ器在é‡å° %{targeting}%{branches}%{branchExceptionsString} é–‹å•Ÿçš„åˆä½µè«‹æ±‚中找到與 %{licenses}%{detection} 相符的任何授權æ¢æ¬¾æ™‚。"
msgid "SecurityOrchestration|With the following customized CI variables:"
msgstr "安全編輯使用以下自定義 CI 變é‡ï¼š"
@@ -42219,14 +42343,20 @@ msgstr "任何å—ä¿è­·çš„分支"
msgid "SecurityOrchestration|any security scanner finds"
msgstr "任何安全性掃æ器發ç¾"
+msgid "SecurityOrchestration|are false positives"
+msgstr "誤報"
+
+msgid "SecurityOrchestration|are not false positives"
+msgstr "éžèª¤å ±"
+
msgid "SecurityOrchestration|branch"
msgstr "分支"
msgid "SecurityOrchestration|branches"
msgstr "分支"
-msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}"
-msgstr "ç”±å為 %{agents} 的代ç†æ¯ %{cadence} 執行一次"
+msgid "SecurityOrchestration|by the agent named %{agents} %{cadence}%{branchExceptionsString}"
+msgstr "ç”±å為 %{agents} %{cadence}%{branchExceptionsString} 的代ç†åŸ·è¡Œ"
msgid "SecurityOrchestration|group level branch input"
msgstr "群組級別分支輸入"
@@ -42234,6 +42364,12 @@ msgstr "群組級別分支輸入"
msgid "SecurityOrchestration|group level branch selector"
msgstr "群組級別分支é¸æ“‡å™¨"
+msgid "SecurityOrchestration|have a fix available"
+msgstr "有å¯ç”¨çš„修復方案"
+
+msgid "SecurityOrchestration|have no fix available"
+msgstr "沒有å¯ç”¨çš„修復方案"
+
msgid "SecurityOrchestration|more than %{allowed}"
msgstr "è¶…éŽ %{allowed}"
@@ -42303,9 +42439,6 @@ msgstr "發表評論(必填)"
msgid "SecurityReports|Add a comment or reason for dismissal"
msgstr "新增評論或解除原因"
-msgid "SecurityReports|Add comment & dismiss"
-msgstr "增加評論並關閉"
-
msgid "SecurityReports|Add or remove projects to monitor in the security area. Projects included in this list will have their results displayed in the security dashboard and vulnerability report."
msgstr "加入或刪除安全å€å…§çš„專案。 此列表中專案的掃æçµæžœå°‡é¡¯ç¤ºåœ¨å®‰å…¨å„€è¡¨æ¿å’Œæ¼æ´žå ±å‘Šä¸­ã€‚"
@@ -42360,6 +42493,9 @@ msgstr "在'%{vulnerabilityName}' 上的留言已編輯"
msgid "SecurityReports|Configure security testing"
msgstr "設定安全測試"
+msgid "SecurityReports|Confirm dismissal"
+msgstr "確èªå¿½ç•¥"
+
msgid "SecurityReports|Create Issue"
msgstr "建立議題"
@@ -42375,9 +42511,15 @@ msgstr "檢測"
msgid "SecurityReports|Development vulnerabilities"
msgstr "開發æ¼æ´ž"
+msgid "SecurityReports|Dismiss as"
+msgstr "忽略為"
+
msgid "SecurityReports|Dismiss vulnerability"
msgstr "忽略æ¼æ´ž"
+msgid "SecurityReports|Dismissal comment"
+msgstr "忽略評論"
+
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
msgstr "已忽略的'%{vulnerabilityName}'"
@@ -42408,6 +42550,9 @@ msgstr "下載掃æçš„ URL"
msgid "SecurityReports|Download the patch to apply it manually"
msgstr "下載修補程å¼ä¸¦æ‰‹å‹•å¥—用"
+msgid "SecurityReports|Edit dismissal"
+msgstr "編輯忽略"
+
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
msgstr "您無權查看此儀表æ¿æˆ–尚未設定儀表æ¿ã€‚è«‹å‘管ç†å“¡æŸ¥è©¢æ‚¨çš„權é™è¨­å®šï¼Œæˆ–檢查儀表æ¿è¨­å®šä¸¦ç¹¼çºŒã€‚"
@@ -42525,9 +42670,6 @@ msgstr "報告已éŽæœŸ"
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr "çµæžœé¡¯ç¤ºåˆä½µè«‹æ±‚引入的æ¼æ´žï¼Œä»¥åŠå°ˆæ¡ˆé è¨­åˆ†æ”¯ä¸­æœ€æ–°æˆåŠŸæµæ°´ç·šä¸­çš„ç¾æœ‰æ¼æ´žã€‚"
-msgid "SecurityReports|Save comment"
-msgstr "儲存評論"
-
msgid "SecurityReports|Scan details"
msgstr "掃æ詳情"
@@ -42571,8 +42713,8 @@ msgstr "ä»ç„¶æª¢æ¸¬åˆ°"
msgid "SecurityReports|Submit vulnerability"
msgstr "æ交æ¼æ´ž"
-msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
-msgstr "æ¼æ´žå ±å‘Šé¡¯ç¤ºå°å°ˆæ¡ˆé è¨­åˆ†æ”¯çš„æˆåŠŸæŽƒæçµæžœã€æ‰‹å‹•æ·»åŠ çš„æ¼æ´žè¨˜éŒ„以åŠå¾žæŽƒææ“作環境中發ç¾çš„æ¼æ´žã€‚ %{linkStart}了解更多。%{linkEnd}"
+msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more%{linkEnd}."
+msgstr "æ¼æ´žå ±å‘Šé¡¯ç¤ºå°å°ˆæ¡ˆé è¨­åˆ†æ”¯çš„æˆåŠŸæŽƒæçµæžœã€æ‰‹å‹•æ–°å¢žçš„æ¼æ´žç´€éŒ„以åŠå¾žæŽƒæ作業環境中發ç¾çš„æ¼æ´žã€‚%{linkStart}å–得更多資訊%{linkEnd}。"
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
msgstr "安全報告包å«ä¸€å€‹æˆ–多個無法解æžä¸”未記錄的æ¼æ´žç™¼ç¾ã€‚查看報告,請下載該作業項的產出物,確ä¿å»ºç«‹çš„安全報告都符åˆç›¸é—œçš„ %{helpPageLinkStart}JSON 綱è¦%{helpPageLinkEnd}。"
@@ -42919,9 +43061,6 @@ msgstr "以 multipart æ ¼å¼ï¼ˆHTML 和純文字)發é€é›»å­éƒµä»¶ã€‚å–消å‹
msgid "Send email notification"
msgstr "發é€é›»å­éƒµä»¶é€šçŸ¥"
-msgid "Send emails to help guide new users through the onboarding process."
-msgstr "發é€é›»å­éƒµä»¶ä»¥å¹«åŠ©æŒ‡å°Žæ–°ä½¿ç”¨è€…完æˆæ–°äººæµç¨‹ã€‚"
-
msgid "Send emails to users upon account deactivation."
msgstr "帳號åœç”¨å¾Œå‘使用者發é€é›»å­éƒµä»¶ã€‚"
@@ -42991,6 +43130,9 @@ msgstr "æœå‹™å¸³è™Ÿé‡‘鑰授權 GitLab 部署您的 Google Cloud 專案"
msgid "Service Desk"
msgstr "æœå‹™è‡º"
+msgid "Service Desk Ticket"
+msgstr "æœå‹™å°å·¥å–®"
+
msgid "Service Desk allows people to create issues in your GitLab instance without their own user account. It provides a unique email address for end users to create issues in a project. Replies can be sent either through the GitLab interface or by email. End users only see threads through email."
msgstr "æœå‹™è‡º(Service Desk)å…許人們在沒有自己的使用者帳號的情æ³ä¸‹åœ¨æ‚¨çš„ GitLab 執行個體中建立議題。它為最終使用者在專案中建立議題æ供了唯一的電å­éƒµä»¶åœ°å€ã€‚ å¯ä»¥é€šéŽ GitLab ç•Œé¢æˆ–é›»å­éƒµä»¶ç™¼é€å›žå¾©ã€‚ 最終使用者åªèƒ½é€šéŽé›»å­éƒµä»¶æŸ¥çœ‹è­°é¡Œã€‚"
@@ -43015,12 +43157,24 @@ msgstr "使用者沒有權é™åœ¨æ­¤å‘½å空間中建立æœå‹™å¸³è™Ÿã€‚"
msgid "ServiceAccount|User does not have permission to create a service account."
msgstr "使用者沒有權é™å»ºç«‹æœå‹™å¸³è™Ÿã€‚"
+msgid "ServiceDesk|%{customEmail} with SMTP host %{smtpAddress} is %{badgeStart}verified%{badgeEnd}"
+msgstr "%{customEmail} 與 SMTP 主機 %{smtpAddress} 已驗證 %{badgeStart}%{badgeEnd}"
+
+msgid "ServiceDesk|A connection to the specified host could not be made or an SSL issue occurred."
+msgstr "無法與指定主機建立連接或發生 SSL å•é¡Œã€‚"
+
+msgid "ServiceDesk|A verification email has been sent to a sub-address of your custom email address. This can take up to 30 minutes. The screen refreshes automatically."
+msgstr "å·²å‘您自訂電å­éƒµä»¶åœ°å€çš„å­åœ°å€ç™¼é€äº†ä¸€å°é©—證郵件,這å¯èƒ½éœ€è¦æœ€å¤š30分é˜çš„時間,螢幕將自動刷新。"
+
msgid "ServiceDesk|Cannot create custom email"
msgstr "無法建立自定義電å­éƒµä»¶"
msgid "ServiceDesk|Cannot update custom email"
msgstr "æœå‹™å°ç„¡æ³•æ›´æ–°è‡ªå®šç¾©é›»å­éƒµä»¶"
+msgid "ServiceDesk|Check your forwarding settings and make sure the original email sender remains in the From header."
+msgstr "檢查您的轉發設定並確ä¿åŽŸå§‹é›»å­éƒµä»¶ç™¼ä»¶äººä¿ç•™åœ¨â€œç™¼ä»¶äººâ€æ¨™é ­ä¸­ã€‚"
+
msgid "ServiceDesk|Common ports are 587 when using TLS, and 25 when not."
msgstr "在使用TLS時,常見的端å£æ˜¯587,而ä¸ä½¿ç”¨TLS時則是25。"
@@ -43048,9 +43202,15 @@ msgstr "自定義電å­éƒµä»¶åœ°å€é©—證已處ç†ä½†å¤±æ•—。"
msgid "ServiceDesk|Custom email already exists"
msgstr "自定義電å­éƒµä»¶å·²ç¶“存在"
+msgid "ServiceDesk|Custom email disabled."
+msgstr "自定義電å­éƒµä»¶å·²åœç”¨ã€‚"
+
msgid "ServiceDesk|Custom email does not exist"
msgstr "自定義電å­éƒµä»¶ä¸å­˜åœ¨"
+msgid "ServiceDesk|Custom email enabled."
+msgstr "自定義電å­éƒµä»¶å·²å•Ÿç”¨ã€‚"
+
msgid "ServiceDesk|Custom email is required and must be a valid email address."
msgstr "自訂電å­éƒµä»¶ç‚ºå¿…填,且必須是有效的電å­éƒµä»¶åœ°å€ã€‚"
@@ -43060,27 +43220,60 @@ msgstr "您的客戶å¯ç”¨æ–¼å¯„é€æ”¯æ´è«‹æ±‚çš„é›»å­éƒµä»¶åœ°å€ã€‚其必須
msgid "ServiceDesk|Enable Service Desk"
msgstr "啟用æœå‹™å°"
+msgid "ServiceDesk|Enable custom email address"
+msgstr "啟用自定義電å­éƒµä»¶åœ°å€"
+
msgid "ServiceDesk|For help setting up the Service Desk for your instance, please contact an administrator."
msgstr "有關為您的執行個體設定æœå‹™å°çš„幫助,請è¯çµ¡ç®¡ç†å“¡ã€‚"
+msgid "ServiceDesk|Incorrect From header"
+msgstr "發件人標題ä¸æ­£ç¢º"
+
+msgid "ServiceDesk|Incorrect verification token"
+msgstr "驗證令牌ä¸æ­£ç¢º"
+
+msgid "ServiceDesk|Invalid credentials"
+msgstr "憑證無效"
+
msgid "ServiceDesk|Issues created from Service Desk emails will appear here. Each comment becomes part of the email conversation."
msgstr "從æœå‹™å°é›»å­éƒµä»¶å»ºç«‹çš„議題將顯示在此處,æ¯æ¢ç•™è¨€éƒ½æˆç‚ºé›»å­éƒµä»¶å°è©±çš„一部分。"
+msgid "ServiceDesk|Keep custom email"
+msgstr "ä¿ç•™è‡ªå®šç¾©é›»å­éƒµä»¶"
+
msgid "ServiceDesk|Minimum 8 characters long."
msgstr "最少 8 個字元長度。"
+msgid "ServiceDesk|Or reset and connect a new custom email address to this Service Desk."
+msgstr "或é‡è¨­ä¸¦é€£çµæ–°çš„自訂電å­éƒµä»¶åœ°å€åˆ°æ­¤æœå‹™å°ã€‚"
+
msgid "ServiceDesk|Parameters missing"
msgstr "缺少åƒæ•¸"
msgid "ServiceDesk|Please share your feedback on this feature in the %{linkStart}feedback issue%{linkEnd}"
msgstr "請在 %{linkStart}議題回饋%{linkEnd} 中分享您å°æ­¤åŠŸèƒ½çš„回饋"
+msgid "ServiceDesk|Please try again. Check email forwarding settings and credentials, and then restart verification."
+msgstr "è«‹å†è©¦ä¸€æ¬¡ã€‚檢查電å­éƒµä»¶è½‰å¯„設定與憑證,然後é‡æ–°å•Ÿå‹•æ†‘證。"
+
+msgid "ServiceDesk|Reset custom email"
+msgstr "é‡è¨­è‡ªå®šç¾©é›»å­éƒµä»¶"
+
+msgid "ServiceDesk|Reset custom email address and delete credentials"
+msgstr "é‡è¨­è‡ªå®šç¾©é›»å­éƒµä»¶åœ°å€ä¸¦åˆªé™¤æ†‘è­‰"
+
+msgid "ServiceDesk|Reset custom email address."
+msgstr "é‡è¨­è‡ªå®šç¾©é›»å­éƒµä»¶åœ°å€ã€‚"
+
msgid "ServiceDesk|SMTP address is required and must be resolvable."
msgstr "SMTP 地å€æ˜¯å¿…需的並且必須是å¯è§£æžçš„。"
msgid "ServiceDesk|SMTP host"
msgstr "SMTP 主機"
+msgid "ServiceDesk|SMTP host issue"
+msgstr "SMTP 主機å•é¡Œ"
+
msgid "ServiceDesk|SMTP password"
msgstr "SMTP 密碼"
@@ -43120,15 +43313,45 @@ msgstr "缺少æœå‹™å°è¨­å®š"
msgid "ServiceDesk|Service Desk setting or verification object missing"
msgstr "缺少æœå‹™å°è¨­å®šæˆ–é©—è­‰å°è±¡"
+msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server."
+msgstr "指定的憑證(使用者å稱與密碼)被 SMTP 伺æœå™¨æ‹’絕。"
+
+msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address."
+msgstr "收到的電å­éƒµä»¶ä¸åŒ…å«å¯„é€åˆ°æ‚¨é›»å­éƒµä»¶åœ°å€çš„驗證權æ–。"
+
+msgid "ServiceDesk|The verification email wasn't received in time. There is a 30 minutes timeframe for verification emails to appear in your instance's Service Desk. Make sure that you have set up email forwarding correctly."
+msgstr "未åŠæ™‚收到電å­éƒµä»¶ã€‚驗證電å­éƒµä»¶å°‡åœ¨30分é˜å…§å‡ºç¾åœ¨æ‚¨æœå‹™å¯¦é«”çš„æœå‹™å°ä¸­ã€‚確ä¿æ‚¨å·²æ­£ç¢ºè¨­å®šé›»å­éƒµä»¶è½‰å¯„。"
+
msgid "ServiceDesk|To enable Service Desk on this instance, an instance administrator must first set up incoming email."
msgstr "è¦åœ¨æ­¤åŸ·è¡Œå€‹é«”上啟用æœå‹™å°ï¼ŒåŸ·è¡Œå€‹é«”管ç†å“¡å¿…須首先設定接收電å­éƒµä»¶åœ°å€ã€‚"
+msgid "ServiceDesk|To use a custom email address for this Service Desk, you'll need to configure and verify an email address again."
+msgstr "è¦åœ¨é€™å€‹æœå‹™å°ä¸­ä½¿ç”¨è‡ªè¨‚çš„é›»å­éƒµä»¶åœ°å€ï¼Œæ‚¨éœ€è¦é‡æ–°è¨­å®šå’Œé©—證一個電å­éƒµä»¶åœ°å€ã€‚"
+
msgid "ServiceDesk|Use Service Desk to connect with your users and offer customer support through email right inside GitLab"
msgstr "使用 Service Desk 與您的使用者è¯çµ¡ä¸¦åœ¨ GitLab 內通éŽé›»å­éƒµä»¶æ供客戶支æ´"
msgid "ServiceDesk|User cannot manage project."
msgstr "使用者無法管ç†å°ˆæ¡ˆã€‚"
+msgid "ServiceDesk|Verification email not received within timeframe"
+msgstr "未在時間範åœå…§æ”¶åˆ°é©—證電å­éƒµä»¶ï¼š"
+
+msgid "ServiceDesk|Verification failed"
+msgstr "驗證失敗"
+
+msgid "ServiceDesk|Verification started"
+msgstr "驗證已開始"
+
+msgid "ServiceDesk|Verify %{customEmail} with SMTP host %{smtpAddress}:"
+msgstr "使用 SMTP 主機 %{smtpAddress} 驗證 %{customEmail}:"
+
+msgid "ServiceDesk|When enabled, Service Desk emails will be sent using the provided credentials."
+msgstr "啟用後,將使用æ供的憑證寄é€æœå‹™å°é›»å­éƒµä»¶ã€‚"
+
+msgid "ServiceDesk|You are about to %{strongStart}disable the custom email address%{strongEnd} %{customEmail} %{strongStart}and delete its credentials%{strongEnd}."
+msgstr "您å³å°‡ %{strongStart}ç¦ç”¨è‡ªå®šç¾©é›»å­éƒµä»¶åœ°å€%{strongEnd} %{customEmail} %{strongStart}並刪除其憑證%{strongEnd}。"
+
msgid "ServiceDesk|Your users can send emails to this address:"
msgstr "您的使用者å¯ä»¥å‘以下地å€ç™¼é€é›»å­éƒµä»¶ï¼š"
@@ -43156,6 +43379,9 @@ msgstr "會話 ID"
msgid "Session duration (minutes)"
msgstr "會話(session)æŒçºŒæ™‚é–“(分é˜)"
+msgid "Session|Unable to verify the user. An error occurred when loading the user verification challenge. Refresh to try again."
+msgstr "無法驗證使用者,載入使用者驗證質詢時發生錯誤,請é‡æ–°æ•´ç†é‡è©¦ã€‚"
+
msgid "Set %{epic_ref} as the parent epic."
msgstr "å°‡%{epic_ref}設定為父å²è©© (epic) 。"
@@ -43276,6 +43502,9 @@ msgstr "將時間估計設定為%{time_estimate}。"
msgid "Set to 0 for no size limit."
msgstr "設定為 0 表示沒有大å°é™åˆ¶ã€‚"
+msgid "Set to 0 to disable timeout."
+msgstr "設定為 0 來åœç”¨é€¾æ™‚。"
+
msgid "Set to auto-merge"
msgstr "設置為自動åˆä½µ"
@@ -43354,6 +43583,9 @@ msgstr "您的狀態在 %{date} 時é‡è¨­ã€‚"
msgid "Sets %{epic_ref} as parent epic."
msgstr "å°‡%{epic_ref}設定為父å²è©© (epic) 。"
+msgid "Sets checkin reminder frequency to %{frequency}."
+msgstr "設置簽到æ醒頻率為 %{frequency}。"
+
msgid "Sets health status to %{health_status}."
msgstr "å°‡å¥åº·ç‹€æ…‹è¨­å®šç‚º %{health_status}。"
@@ -44187,6 +44419,9 @@ msgstr "有人從新ä½ç½®ç™»å…¥åˆ°æ‚¨çš„ %{host} 帳號"
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "有人(希望是您)è¦æ±‚在 %{link_to_gitlab} 上é‡è¨­æ‚¨çš„ GitLab 帳號的密碼。"
+msgid "Something else"
+msgstr ""
+
msgid "Something went wrong"
msgstr "發生錯誤了"
@@ -44280,9 +44515,6 @@ msgstr "å–å¾—æ述變更時發生錯誤了,請ç¨å¾Œé‡è©¦ã€‚"
msgid "Something went wrong while fetching details"
msgstr "å–得詳細訊æ¯æ™‚發生錯誤"
-msgid "Something went wrong while fetching latest comments."
-msgstr "å–得最新留言時發生錯誤。"
-
msgid "Something went wrong while fetching projects"
msgstr "å–得專案時發生錯誤。"
@@ -45231,6 +45463,18 @@ msgstr "匯出授權許å¯ä½¿ç”¨æ–‡ä»¶"
msgid "SubscriptionBanner|Upload new license"
msgstr "上傳新授權"
+msgid "SubscriptionMangement|If you'd like to add more seats, upgrade your plan, or purchase additional products, contact your GitLab sales representative."
+msgstr "若您想新增更多席次ã€å‡ç´šæ‚¨çš„方案或購買其他產å“,請è¯çµ¡æ‚¨çš„ GitLab 業務代表。"
+
+msgid "SubscriptionMangement|This is a custom subscription managed by the GitLab Sales team"
+msgstr "這是由 GitLab 銷售團隊管ç†çš„自訂訂閱"
+
+msgid "SubscriptionMangement|To make changes to a read-only subscription or purchase additional products, contact your GitLab Partner."
+msgstr "è¦è®Šæ›´å”¯è®€è¨‚閱或購買其他產å“,請è¯çµ¡æ‚¨çš„ GitLab åˆä½œå¤¥ä¼´ã€‚"
+
+msgid "SubscriptionMangement|Your subscription is in read-only mode"
+msgstr "您的訂閱處於唯讀模å¼"
+
msgid "SubscriptionTable|Add seats"
msgstr "加入席次"
@@ -45378,6 +45622,9 @@ msgstr "å·²æˆåŠŸå‡çµ"
msgid "Successfully deleted WebAuthn device."
msgstr "å·²æˆåŠŸåˆªé™¤WebAuthn設備。"
+msgid "Successfully linked ID(s): %{item_ids}."
+msgstr "æˆåŠŸéˆçµ ID: %{item_ids}。"
+
msgid "Successfully removed email."
msgstr "æˆåŠŸåˆªé™¤é›»å­éƒµä»¶ã€‚"
@@ -45396,6 +45643,9 @@ msgstr "å·²æˆåŠŸè§£ç¦"
msgid "Successfully unblocked"
msgstr "å·²æˆåŠŸè§£é™¤å°éŽ–"
+msgid "Successfully unlinked IDs: %{item_ids}."
+msgstr "æˆåŠŸå–消éˆçµ ID: %{item_ids}。"
+
msgid "Successfully unlocked"
msgstr "å·²æˆåŠŸè§£é™¤éŽ–定"
@@ -46055,6 +46305,9 @@ msgstr "與GitLab Duo Chat通訊時發生錯誤,請ç¨å¾Œå†è©¦ã€‚"
msgid "TanukiBot|What is a fork?"
msgstr "什麼是分å‰ï¼Ÿ"
+msgid "Targe branch"
+msgstr "目標分支"
+
msgid "Target"
msgstr "目標"
@@ -46067,8 +46320,14 @@ msgstr "目標路徑"
msgid "Target branch"
msgstr "目標分支"
-msgid "Target branch or tag"
-msgstr "目標分支或標籤"
+msgid "Target branch rule"
+msgstr "目標分支è¦å‰‡"
+
+msgid "Target branch rule created."
+msgstr "目標分支è¦å‰‡å·²å»ºç«‹ã€‚"
+
+msgid "Target branch rules"
+msgstr "目標分支è¦å‰‡"
msgid "Target branch: %{target_branch}"
msgstr "目標分支: %{target_branch}"
@@ -46893,9 +47152,6 @@ msgstr "é é¢å·²é€¾æ™‚,無法顯示。"
msgid "The parent epic is confidential and can only contain confidential epics and issues"
msgstr "父å²è©© (epic) 是機密的,åªèƒ½åŒ…å«æ©Ÿå¯†å²è©© (epics) 和議題"
-msgid "The parsed YAML is too big"
-msgstr "被解æžçš„ YAML 文件太大"
-
msgid "The password for the Jenkins server."
msgstr "Jenkins 伺æœå™¨çš„密碼。"
@@ -47070,6 +47326,9 @@ msgstr "æ¼æ´žå·²ä¸å†è¢«æª¢æ¸¬åˆ°ã€‚請於更改其狀態å‰ç¢ºä¿æ¼æ´žå·²ä¿®
msgid "There are currently no mirrored repositories."
msgstr "當å‰æ²’有已é¡åƒçš„版本庫。"
+msgid "There are currently no target branch rules"
+msgstr "ç›®å‰æ²’有目標分支è¦å‰‡"
+
msgid "There are merge conflicts"
msgstr "存在åˆä½µè¡çª"
@@ -47088,9 +47347,6 @@ msgstr "沒有å¯å­˜å–您帳號的SSH金鑰。"
msgid "There are no Spam Logs"
msgstr "沒有垃圾郵件日誌"
-msgid "There are no abuse reports!"
-msgstr "沒有濫用報告ï¼"
-
msgid "There are no approval rules for the given `represent_as` parameter. Use a valid User/Group/Role name instead."
msgstr "指定的 `represent_as` çš„åƒæ•¸æ²’有批准è¦å‰‡ï¼Œè«‹æ”¹ç”¨æœ‰æ•ˆçš„使用者/群組/角色å稱。"
@@ -47340,6 +47596,9 @@ msgstr "å–å¾—é¸ä¸­ç¾¤çµ„的頂級標記時發生錯誤"
msgid "There was an error fetching the variables."
msgstr "å–得變數時發生錯誤。"
+msgid "There was an error fetching this merge request's pipelines."
+msgstr "æ“·å–æ­¤åˆä½µè«‹æ±‚çš„æµæ°´ç·šæ™‚發生錯誤。"
+
msgid "There was an error fetching value stream analytics stages."
msgstr "å–得價值æµåˆ†æžéšŽæ®µæ™‚發生錯誤。"
@@ -47424,6 +47683,9 @@ msgstr "reCAPTCHA 驗證錯誤。請å†æ¬¡é©—è­‰ reCAPTCHA。"
msgid "There was an summarizing your pending comments."
msgstr "有一個總çµæ‚¨å¾…處ç†çš„æ„見。"
+msgid "These branches already have an open merge request: %{link_to_mr}. Select a different source or target branch."
+msgstr "這些分支已有開放的åˆä½µè«‹æ±‚:%{link_to_mr}。é¸å–ä¸åŒçš„來æºæˆ–目標分支。"
+
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr "這些日期會影響您的å²è©© (epics) 在路線圖中的顯示方å¼ã€‚設定一個固定日期或從分é…給此å²è©© (epic) 中議題的里程碑繼承的日期。"
@@ -47928,9 +48190,15 @@ msgstr "該åˆä½µè«‹æ±‚是從ç§æœ‰å°ˆæ¡ˆåˆ°å…§éƒ¨å°ˆæ¡ˆã€‚"
msgid "This merge request is from an internal project to a public project."
msgstr "該åˆä½µè«‹æ±‚是從內部專案到公開專案。"
+msgid "This merge request is hidden because its author has been banned"
+msgstr "æ­¤åˆä½µè«‹æ±‚已隱è—,因為其作者已被å°éŽ–"
+
msgid "This merge request is locked."
msgstr "該åˆä½µè«‹æ±‚已鎖定。"
+msgid "This merge request is locked. Only project members can comment."
+msgstr "æ­¤åˆä½µè«‹æ±‚已鎖定。僅專案æˆå“¡å¯ä»¥é€²è¡Œè©•è«–。"
+
msgid "This merge request was merged. To apply this suggestion, edit this file directly."
msgstr "åˆä½µè«‹æ±‚å·²åˆä½µã€‚è¦æ‡‰ç”¨æ­¤å»ºè­°ï¼Œè«‹ç›´æŽ¥ç·¨è¼¯æ­¤æ–‡ä»¶ã€‚"
@@ -47949,11 +48217,11 @@ msgstr "該æµæ°´ç·šä½¿ç”¨äº† %{strongStart}Auto DevOps%{strongEnd}é å…ˆå®šç¾©ä
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by Auto DevOps."
msgstr "æ­¤æµæ°´ç·šä½¿ç”¨ç”± Auto DevOps 啟用的é å®šç¾© CI/CD é…置。"
-msgid "This pipeline was triggered by a schedule"
-msgstr "該æµæ°´ç·šç”±æŽ’程觸發"
+msgid "This pipeline was created by a schedule"
+msgstr "該æµæ°´ç·šç”±æŽ’程建立"
-msgid "This pipeline was triggered by a schedule."
-msgstr "該æµæ°´ç·šæ˜¯ç”±æŽ’程觸發的."
+msgid "This pipeline was created by a schedule."
+msgstr "該æµæ°´ç·šç”±æŽ’程建立。"
msgid "This process deletes the project repository and all related resources."
msgstr "該æµç¨‹å°‡åˆªé™¤å°ˆæ¡ˆç‰ˆæœ¬åº«å’Œæ‰€æœ‰ç›¸é—œè³‡æºã€‚"
@@ -48102,8 +48370,8 @@ msgstr "該使用者是此 %{workItemType} 的作者。"
msgid "This variable value does not meet the masking requirements."
msgstr "此變數的值ä¸ç¬¦åˆé®ç½©è¦æ±‚。"
-msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset."
-msgstr "æ­¤æ¼æ´žå·²è‡ªå‹•è§£æ±ºï¼Œå› ç‚ºå…¶æ¼æ´žé¡žåž‹å·²åœ¨æ­¤å°ˆæ¡ˆä¸­åœç”¨æˆ–已從 GitLab çš„é è¨­è¦å‰‡é›†ä¸­ç§»é™¤ã€‚"
+msgid "This vulnerability was automatically resolved because its vulnerability type was disabled in this project or removed from GitLab's default ruleset. For details about SAST rule changes, see https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes."
+msgstr "æ­¤æ¼æ´žå·²è‡ªå‹•è§£æ±ºï¼Œå› ç‚ºå…¶æ¼æ´žé¡žåž‹å·²åœ¨æ­¤å°ˆæ¡ˆä¸­åœç”¨ï¼Œæˆ–已從 GitLab çš„é è¨­è¦å‰‡é›†ä¸­ç§»é™¤ã€‚關於 SAST è¦å‰‡è®Šæ›´çš„詳細資訊,請åƒé–± https://docs.gitlab.com/ee/user/application_security/sast/rules#important-rule-changes。"
msgid "This will invalidate your registered applications and WebAuthn devices."
msgstr "這將使您註冊的應用程å¼å’Œ WebAuthn 設備無效。"
@@ -48228,8 +48496,8 @@ msgstr "時å€"
msgid "TimeTrackingEstimated|Est"
msgstr "é ä¼°"
-msgid "TimeTrackingReport|From"
-msgstr "從"
+msgid "TimeTrackingReport|From the start of"
+msgstr "從開始"
msgid "TimeTrackingReport|Run report"
msgstr "執行報告"
@@ -48249,8 +48517,8 @@ msgstr "摘è¦"
msgid "TimeTrackingReport|Time spent"
msgstr "花費的時間"
-msgid "TimeTrackingReport|To"
-msgstr "至"
+msgid "TimeTrackingReport|To the end of"
+msgstr "到çµæŸ"
msgid "TimeTrackingReport|Total time spent: "
msgstr "總花費時間"
@@ -48669,8 +48937,8 @@ msgstr "è¦é‡æ–°å•Ÿç”¨æ‚¨çš„帳號,請在 %{gitlab_url}登入 GitLab。"
msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your top-level group owner(s) to reduce the number of users in your top-level group to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
msgstr "è¦ç§»é™¤ %{link_start}read-only%{link_end} 狀態並é‡æ–°å–得寫入權é™ï¼Œè«‹è¦æ±‚您的頂級群組æ“有者將您頂級群組中的使用者數é‡æ¸›å°‘到 %{free_limit} 使用者或更少,或者å‡ç´šåˆ°æ²’有使用者é™åˆ¶çš„付費級別。"
-msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users. To minimize the impact to operations, for a limited time, GitLab is offering a %{promotion_link_start}one-time 70 percent discount%{link_end} off the list price at time of purchase for a new, one year subscription of GitLab Premium SaaS to %{offer_availability_link_start}qualifying top-level groups%{link_end}. The offer is valid until %{offer_date}."
-msgstr "è¦è§£é™¤%{link_start}唯讀%{link_end}狀態並æ¢å¾©å¯«å…¥æ¬Šé™ï¼Œæ‚¨å¯ä»¥å°‡æœ€ä¸Šå±¤ç¾¤çµ„中的使用者數é‡æ¸›å°‘至 %{free_limit} 個或更少,您也å¯ä»¥å‡ç´šåˆ°ä»˜è²»æ–¹æ¡ˆï¼Œé€™äº›æ–¹æ¡ˆä¸æœƒæœ‰ä½¿ç”¨è€…é™åˆ¶ã€‚如果您需è¦é¡å¤–的時間,您å¯ä»¥é–‹å§‹äº«å—å…費的 30 天試用期,其中包括無é™åˆ¶çš„使用者數é‡ã€‚為了é™ä½Žå°ç‡Ÿé‹çš„影響,在有é™çš„時間內,GitLab æä¾›%{promotion_link_start}一次性 70%% 折扣%{link_end},å¯ç”¨æ–¼æ–°è³¼è²· GitLab Premium SaaS 一年的訂閱方案,é©ç”¨æ–¼%{offer_availability_link_start}符åˆè³‡æ ¼çš„最上層群組%{link_end},此優惠有效期至 %{offer_date}。"
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your top-level group to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr "è¦åˆªé™¤ %{link_start}唯讀%{link_end} 狀態並é‡æ–°å–得寫入的存å–權é™ï¼Œæ‚¨å¯ä»¥å°‡æœ€ä¸Šå±¤ç¾¤çµ„中的使用ç½æ•¸é‡æ¸›å°‘到 %{free_limit} 或更少,您還å¯ä»¥å‡ç´šåˆ°æ²’有使用者é™åˆ¶çš„付費級別,如果您需è¦æ›´å¤šæ™‚間,å¯ä»¥é–‹å§‹ 30 天å…費試用,其中包å«ç„¡é™çš„使用者。"
msgid "To replace phone verification with credit card verification, create a phone verification exemption using the button below."
msgstr "將電話驗證替æ›ç‚ºä¿¡ç”¨å¡é©—證,請使用下é¢çš„按鈕建立電話驗證è±å…。"
@@ -48951,6 +49219,9 @@ msgstr "此個人存å–令牌已在被åµæ¸¬åˆ°æ™‚自動撤銷。在將此æ¼æ´ž
msgid "Tomorrow"
msgstr "明日"
+msgid "Too long"
+msgstr ""
+
msgid "Too many namespaces enabled. Manage them through the console or the API."
msgstr "啟用了太多的命å空間,通éŽæŽ§åˆ¶å°æˆ–API管ç†å®ƒå€‘。"
@@ -49030,6 +49301,9 @@ msgstr "全部"
msgid "Total Score"
msgstr "總分"
+msgid "Total Spans"
+msgstr "總跨度"
+
msgid "Total cores (CPUs)"
msgstr "總核心數目 (CPUs)"
@@ -49060,9 +49334,15 @@ msgstr "1000+"
msgid "Trace Details"
msgstr "追蹤詳細資訊"
+msgid "Trace Start"
+msgstr "追蹤開始"
+
msgid "Tracing"
msgstr "跟蹤"
+msgid "Tracing|%{ms} ms"
+msgstr "%{ms}毫秒"
+
msgid "Tracing|Check again"
msgstr "å†æ¬¡æª¢æŸ¥"
@@ -49135,6 +49415,18 @@ msgstr "週期"
msgid "Tracing|Service"
msgstr "æœå‹™"
+msgid "Tracing|Span Details"
+msgstr "跨度詳情"
+
+msgid "Tracing|Span ID"
+msgstr "跨度 ID"
+
+msgid "Tracing|Status Code"
+msgstr "狀態碼"
+
+msgid "Tracing|Toggle children spans"
+msgstr "切æ›å­è·¨åº¦"
+
msgid "Tracing|Trace ID"
msgstr "追踪 ID"
@@ -49499,9 +49791,6 @@ msgstr "URL或請求ID"
msgid "USER %{user_name} WILL BE REMOVED! Are you sure?"
msgstr "使用者 %{user_name} 將被刪除ï¼æ‚¨ç¢ºå®šå—Žï¼Ÿ"
-msgid "USER %{user} WILL BE REMOVED! Are you sure?"
-msgstr "使用者 %{user} 將被刪除ï¼æ‚¨ç¢ºå®šå—Žï¼Ÿ"
-
msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr "使用者將被ç¦ç”¨ï¼æ‚¨ç¢ºå®šå—Žï¼Ÿ"
@@ -49589,6 +49878,9 @@ msgstr "無法載入åˆä½µè«‹æ±‚部件。請嘗試é‡æ–°è¼‰å…¥é é¢ã€‚"
msgid "Unable to load the page"
msgstr "無法載入é é¢"
+msgid "Unable to load user list. Reload the page and try again."
+msgstr "無法載入使用者清單。é‡æ–°è¼‰å…¥é é¢ä¸¦å†è©¦ä¸€æ¬¡ã€‚"
+
msgid "Unable to parse JSON"
msgstr "ç„¡æ³•è§£æž JSON"
@@ -49622,9 +49914,6 @@ msgstr "ç›®å‰ç„¡æ³•æ›´æ–°è©²å²è©© (epic) 。"
msgid "Unable to update this issue at this time."
msgstr "ç›®å‰ç„¡æ³•æ›´æ–°è©²è­°é¡Œã€‚"
-msgid "Unable to verify the user"
-msgstr "無法驗證使用者"
-
msgid "Unapprove a merge request"
msgstr "å–消核准åˆä½µè«‹æ±‚"
@@ -49703,6 +49992,9 @@ msgstr "很éºæ†¾ï¼Œæ‚¨ç™¼é€çµ¦GitLabçš„é›»å­éƒµä»¶ç„¡æ³•è™•ç†ã€‚"
msgid "Unhappy?"
msgstr "ä¸æ»¿æ„?"
+msgid "Unhelpful or irrelevant"
+msgstr ""
+
msgid "Units|d"
msgstr "天"
@@ -50078,6 +50370,9 @@ msgstr "購買é¡å¤–的計算分é˜æ•¸"
msgid "UsageQuota|Buy storage"
msgstr "購買儲存"
+msgid "UsageQuota|Code Suggestions"
+msgstr "程å¼ç¢¼å»ºè­°"
+
msgid "UsageQuota|Code packages and container images."
msgstr "軟體包和容器映åƒã€‚"
@@ -50099,12 +50394,12 @@ msgstr "容器註冊表"
msgid "UsageQuota|Dependency proxy"
msgstr "ä¾è³´ä»£ç†"
-msgid "UsageQuota|Filter chart by month"
-msgstr "按月篩é¸åœ–表"
-
msgid "UsageQuota|Filter charts by year"
msgstr "按年篩é¸åœ–表"
+msgid "UsageQuota|Filter projects data by month"
+msgstr "按月éŽæ¿¾å°ˆæ¡ˆè³‡æ–™"
+
msgid "UsageQuota|For more information about storage limits, see our %{faq_link_start}FAQ%{link_end}."
msgstr "有關儲存é™åˆ¶çš„更多訊æ¯ï¼Œè«‹åƒé–±æˆ‘們的 %{faq_link_start}FAQ%{link_end}。"
@@ -50150,6 +50445,9 @@ msgstr "命å空間概覽"
msgid "UsageQuota|Namespace storage used"
msgstr "已使用的命å空間儲存"
+msgid "UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy."
+msgstr "命å空間總儲存表示所有專案ã€å®¹å™¨è¨»å†Šè¡¨å’Œä¾è³´ä»£ç†æ‰€æ¶ˆè€—的儲存總和。"
+
msgid "UsageQuota|No compute usage data available."
msgstr "ç›®å‰æ²’有計算使用é‡çš„資料å¯ç”¨"
@@ -50216,15 +50514,15 @@ msgstr "%{strong_start}%{context_name}%{strong_end} 群組將å—此影響。"
msgid "UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. "
msgstr "%{strong_start}%{context_name}%{strong_end} 專案將å—此影響。"
+msgid "UsageQuota|The chart and the table below show usage for %{month} %{year}"
+msgstr "以下圖表和表格顯示了 %{year} å¹´ %{month} 月的使用情æ³"
+
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. Group owners can view namespace storage usage and purchase more from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}How can I manage my storage%{link_end}?"
msgstr "命å空間目å‰æ­£åœ¨ä½¿ç”¨ %{strong_start}%{used_storage}%{strong_end} 的命å空間儲存å€ï¼Œç¾¤çµ„所有者å¯ä»¥æŸ¥çœ‹å‘½å空間儲存狀æ³ï¼Œå…·ä¸”從 %{strong_start}%{usage_quotas_nav_instruction}%{strong_end} 的購買更多的儲存空間。 %{docs_link_start}如何管ç†æˆ‘的儲存空間%{link_end}?"
msgid "UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. View and manage your usage from %{strong_start}%{usage_quotas_nav_instruction}%{strong_end}. %{docs_link_start}Learn more%{link_end} about how to reduce your storage."
msgstr "該命å空間目å‰æ­£åœ¨ä½¿ç”¨ %{strong_start}%{used_storage}%{strong_end} 的命å空間儲存。從 %{strong_start}%{usage_quotas_nav_instruction}%{strong_end} 查看和管ç†æ‚¨çš„使用情æ³ã€‚ %{docs_link_start}了解更多%{link_end}關於如何減少您的儲存空間。"
-msgid "UsageQuota|The table below shows usage since %{usageSince}"
-msgstr "下方表格顯示自 %{usageSince} 以來的使用情æ³"
-
msgid "UsageQuota|This namespace has %{planLimit} of storage. %{linkStart}How are limits applied?%{linkEnd}"
msgstr "這個命å空間有 %{planLimit} 的儲存空間。%{linkStart}如何套用é™åˆ¶ï¼Ÿ%{linkEnd}"
@@ -50895,6 +51193,9 @@ msgstr "使用者å稱å¯ç”¨ã€‚"
msgid "Username or email"
msgstr "使用者å稱或信箱"
+msgid "Username or primary email"
+msgstr "使用者å稱或主è¦é›»å­éƒµä»¶åœ°å€"
+
msgid "Username:"
msgstr "使用者å稱"
@@ -51022,25 +51323,25 @@ msgid "Validations failed."
msgstr "驗證失敗。"
msgid "Validation|can contain only lowercase letters, digits, '_' and '-'. Must start with a letter, and cannot end with '-' or '_'"
-msgstr ""
+msgstr "åªèƒ½åŒ…å«å°å¯«å­—æ¯ã€æ•¸å­—ã€â€œ_â€å’Œâ€œ-â€ï¼Œå¿…須以字æ¯é–‹é ­ï¼Œä¸èƒ½ä»¥â€œ-â€æˆ–“_â€çµå°¾"
msgid "Validation|groupId parameter is invalid"
-msgstr ""
+msgstr "groupIdåƒæ•¸ç„¡æ•ˆ"
msgid "Validation|must belong to the same project"
-msgstr ""
+msgstr "必須屬於åŒä¸€å€‹å°ˆæ¡ˆ"
msgid "Validation|parameters are invalid"
-msgstr ""
+msgstr "åƒæ•¸ç„¡æ•ˆ"
msgid "Validation|percentage must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "百分比必須是 0 到 100 ä¹‹é–“çš„å­—ä¸²ï¼ˆå« 0 å’Œ 100)"
msgid "Validation|rollout must be a string between 0 and 100 inclusive"
-msgstr ""
+msgstr "rollout 必須是一個介於0到100之間(包括0和100)的字串"
msgid "Validation|strategy name is invalid"
-msgstr ""
+msgstr "ç­–ç•¥å稱無效"
msgid "Value"
msgstr "值"
@@ -51596,6 +51897,9 @@ msgstr "詳細資訊"
msgid "VulnerabilityExport|Detected At"
msgstr "檢測時間"
+msgid "VulnerabilityExport|Full Path"
+msgstr "完整路徑"
+
msgid "VulnerabilityExport|Group Name"
msgstr "群組å稱"
@@ -51623,17 +51927,20 @@ msgstr "工具"
msgid "VulnerabilityExport|Vulnerability"
msgstr "æ¼æ´ž"
-msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
-msgstr "ç”±%{user}%{statusStart}確èª%{statusEnd}æ–¼%{timeago}"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{statusStart}已確èª%{statusEnd} · %{timeago} × %{user}"
-msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
-msgstr "ç”±æµæ°´ç·š%{pipelineLink}æ–¼%{timeago}%{statusStart}檢測出%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} · %{timeago} in pipeline %{pipelineLink}"
+msgstr "%{statusStart}在æµæ°´ç·š%{pipelineLink}中檢測到%{statusEnd} · %{timeago}"
-msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} · %{timeago} by %{user}"
msgstr "由%{user}於%{timeago}%{statusStart}忽略%{statusEnd}"
-msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
-msgstr "由%{user}於%{timeago}%{statusStart}解決%{statusEnd}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd}: %{dismissalReason} · %{timeago} by %{user}"
+msgstr "%{statusStart}已忽略%{statusEnd}:%{dismissalReason},由 %{user} 於 %{timeago}"
+
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} · %{timeago} by %{user}"
+msgstr "%{statusStart}已解決%{statusEnd},由 %{user} 於 %{timeago}"
msgid "VulnerabilityManagement|(optional) Include the solution to the vulnerability if available."
msgstr "(å¯é¸ï¼‰åŒ…括æ¼æ´žçš„解決方案(如果有)。"
@@ -51768,7 +52075,7 @@ msgid "VulnerabilityStatusTypes|Resolved"
msgstr "已解決"
msgid "Vulnerability|%{file} was not found in commit %{ref}"
-msgstr ""
+msgstr "在 %{ref} æ交中未找到 %{file}"
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (版本 %{scannerVersion})"
@@ -51875,6 +52182,9 @@ msgstr "檔案:"
msgid "Vulnerability|GitLab Security Report"
msgstr "GitLab 安全報告"
+msgid "Vulnerability|GitLab has identified sensitive strings in the code snippet for the AI prompt, indicating a possible leaked secret. Please review your code before utilizing the Explain This Vulnerability feature. If you still wish to proceed and send the %{linkStart}code%{linkEnd} to the AI, click the checkbox below."
+msgstr "GitLab 已經辨識出 AI æ示的程å¼ç¢¼ç‰‡æ®µä¸­çš„æ•æ„Ÿå­—串,å¯èƒ½è¡¨ç¤ºæœ‰æ´©æ¼çš„機密,在使用「解釋此æ¼æ´žã€åŠŸèƒ½ä¹‹å‰ï¼Œè«‹æª¢æŸ¥æ‚¨çš„程å¼ç¢¼ã€‚如果您ä»ç„¶å¸Œæœ›ç¹¼çºŒä¸¦å°‡ç¨‹å¼ç¢¼%{linkStart}傳é€%{linkEnd}給 AI,請點é¸ä¸‹æ–¹çš„æ ¸å–方塊。"
+
msgid "Vulnerability|Hide prompt"
msgstr "éš±è—æ示"
@@ -51972,7 +52282,7 @@ msgid "Vulnerability|Show prompt"
msgstr "顯示æ示"
msgid "Vulnerability|Something went wrong while trying to get the source file."
-msgstr ""
+msgstr "嘗試å–得來æºæ–‡ä»¶æ™‚發生å•é¡Œã€‚"
msgid "Vulnerability|Stacktrace snippet:"
msgstr "堆疊追蹤片段:"
@@ -51989,11 +52299,8 @@ msgstr "掃瞄器確定此æ¼æ´žç‚ºèª¤å ±ã€‚在更改其狀態之å‰é©—證評估
msgid "Vulnerability|The unmodified response is the original response that had no mutations done to the request"
msgstr "未修改的回應是未å°è«‹æ±‚進行任何更改的原始回應"
-msgid "Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}."
-msgstr "發生未é æœŸçš„錯誤,%{linkStart}è«‹é‡è©¦%{linkEnd}。"
-
-msgid "Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
-msgstr "這是一個使用人工智慧來解釋æ¼æ´žä¸¦æ供建議的實驗性功能,由於我們æŒçºŒæ”¹é€²ï¼Œè«‹è¬¹æ…Žä½¿ç”¨æ­¤åŠŸèƒ½ã€‚請在%{linkStart}此議題%{linkEnd}中æ供您的回饋和想法。"
+msgid "Vulnerability|This is a beta feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}."
+msgstr "這是一個使用人工智慧來解釋æ¼æ´žä¸¦æ供建議的測試功能。我們會æŒçºŒæ”¹é€²ï¼Œè«‹è¬¹æ…Žä½¿ç”¨æ­¤åŠŸèƒ½ã€‚請在%{linkStart}此議題%{linkEnd}中æ供您的回饋與想法。"
msgid "Vulnerability|Tool"
msgstr "工具"
@@ -52028,6 +52335,9 @@ msgstr "æ¼æ´žé¡žåˆ¥ï¼š"
msgid "Vulnerability|Vulnerable method:"
msgstr "æ¼æ´žæ–¹æ³•ï¼š"
+msgid "Vulnerability|Warning: possible secrets detected"
+msgstr "警告:å¯èƒ½ç™¼ç¾æ©Ÿå¯†è³‡è¨Š"
+
msgid "WARNING:"
msgstr "警告:"
@@ -52355,6 +52665,12 @@ msgstr "æ”¯æ´ %{REGEX_CODE} 等正è¦è¡¨ç¤ºå¼ã€‚"
msgid "Webhooks|Releases events"
msgstr "發布事件"
+msgid "Webhooks|Response body is empty"
+msgstr "回應內容為空"
+
+msgid "Webhooks|Response headers data is empty"
+msgstr "回應標頭資料為空"
+
msgid "Webhooks|SSL verification"
msgstr "SSLé©—è­‰"
@@ -52457,15 +52773,6 @@ msgstr "歡迎使用全新的導航體驗"
msgid "Welcome, %{name}!"
msgstr "歡迎, %{name}ï¼"
-msgid "What are group audit events?"
-msgstr "什麼是群組審查事件?"
-
-msgid "What are instance audit events?"
-msgstr "什麼是執行個體審查事件?"
-
-msgid "What are project audit events?"
-msgstr "什麼是專案審查事件?"
-
msgid "What are some examples?"
msgstr "有哪些範例?"
@@ -52817,6 +53124,12 @@ msgstr "WIP é™åˆ¶"
msgid "Work item promoted successfully."
msgstr "工作項目å‡ç´šæˆåŠŸã€‚"
+msgid "Work items are already linked"
+msgstr "工作項已éˆçµ"
+
+msgid "WorkItems|This work item would exceed the maximum number of linked items."
+msgstr "這個工作項目將超éŽæœ€å¤§é€£çµé …目數é‡ã€‚"
+
msgid "WorkItem|%{count} more assignees"
msgstr "åŠå…¶ä»– %{count} å指派人"
@@ -52908,9 +53221,6 @@ msgstr "複製 %{workItemType} é›»å­éƒµä»¶"
msgid "WorkItem|Create %{workItemType}"
msgstr "建立 %{workItemType}"
-msgid "WorkItem|Create objective"
-msgstr "建立目標"
-
msgid "WorkItem|Create work item"
msgstr "建立工作項"
@@ -52929,9 +53239,6 @@ msgstr "截止日期"
msgid "WorkItem|Existing task"
msgstr "ç¾æœ‰ä»»å‹™"
-msgid "WorkItem|Health status"
-msgstr "å¥åº·ç‹€æ…‹"
-
msgid "WorkItem|History only"
msgstr "僅é™æ­·å²è¨˜éŒ„"
@@ -52950,14 +53257,20 @@ msgstr "é—œéµçµæžœ"
msgid "WorkItem|Key result"
msgstr "é—œéµçµæžœ"
+msgid "WorkItem|Link work items together to show that they're related or that one is blocking others."
+msgstr "將工作項目連çµåœ¨ä¸€èµ·ä»¥è¡¨ç¤ºå®ƒå€‘有相關,或是其中一個正在阻擋其他的。"
+
+msgid "WorkItem|Linked Items"
+msgstr "已連çµçš„é …ç›®"
+
msgid "WorkItem|Mark as done"
msgstr "標記為完æˆ"
msgid "WorkItem|Milestone"
msgstr "里程碑"
-msgid "WorkItem|New objective"
-msgstr "新增目標"
+msgid "WorkItem|New %{workItemType}"
+msgstr "æ–° %{workItemType}"
msgid "WorkItem|New task"
msgstr "新增任務"
@@ -53100,9 +53413,6 @@ msgstr "測試案例"
msgid "WorkItem|This %{workItemType} is confidential and should only be visible to team members with at least Reporter access"
msgstr "æ­¤ %{workItemType} 是機密的,åªèƒ½é¡¯ç¤ºçµ¦æ“有至少「報告人ã€å­˜å–權é™çš„團隊æˆå“¡ã€‚"
-msgid "WorkItem|This objective is confidential and should only be visible to team members with at least Reporter access"
-msgstr "此目標是機密的,åªèƒ½é¡¯ç¤ºçµ¦æ“有至少「報告人ã€å­˜å–權é™çš„團隊æˆå“¡ã€‚"
-
msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
msgstr "該工作項目無法使用,å¯èƒ½ç‚ºä¸å­˜åœ¨æˆ–您無權查看它。"
@@ -53133,8 +53443,8 @@ msgstr "您åªèƒ½åœ¨é é¢ä¸Šçœ‹åˆ° %{boldStart}其他活動%{boldEnd},è¦ç™¼è
msgid "Workspaces"
msgstr "工作å€"
-msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab. You can create a workspace for a public project."
-msgstr "工作å€æ˜¯ GitLab 中程å¼ç¢¼çš„虛擬沙箱環境,您å¯ä»¥ç‚ºå…¬é–‹çš„專案創建工作å€ã€‚"
+msgid "Workspaces|A workspace is a virtual sandbox environment for your code in GitLab."
+msgstr "工作å€æ˜¯GitLab中用於程å¼ç¢¼çš„虛擬沙箱環境。"
msgid "Workspaces|Cancel"
msgstr "å–消"
@@ -53232,9 +53542,6 @@ msgstr "未知狀態"
msgid "Workspaces|Workspaces"
msgstr "工作å€"
-msgid "Workspaces|You can create a workspace for public projects only."
-msgstr "您åªèƒ½ç‚ºå…¬é–‹å°ˆæ¡ˆå»ºç«‹å·¥ä½œå€ã€‚"
-
msgid "Workspaces|You can't create a workspace for this project"
msgstr "您無法為此專案建立工作å€"
@@ -53494,6 +53801,9 @@ msgstr "您å¯ä»¥é€šéŽå­˜å–%{link}建立一個新的個人存å–令牌"
msgid "You can create a new SSH key by visiting %{link}"
msgstr "您å¯ä»¥é€šéŽå­˜å–%{link}建立一個新的SSH金鑰"
+msgid "You can create a new one or check them in your %{link_start}access tokens%{link_end} settings."
+msgstr "您å¯ä»¥å‰µå»ºä¸€å€‹æ–°çš„,或在您的%{link_start}å­˜å–令牌%{link_end}設定中檢查它們。"
+
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr "您å¯ä»¥åœ¨æ‚¨çš„ %{pat_link_start}個人存å–令牌%{pat_link_end} 設定中建立一個新的或檢查它們。"
@@ -53503,6 +53813,9 @@ msgstr "您å¯ä»¥åœ¨æ‚¨çš„ %{ssh_key_link_start}SSH 金鑰%{ssh_key_link_end} è¨
msgid "You can create a new one or check them in your SSH keys settings %{ssh_key_link}."
msgstr "您å¯ä»¥åœ¨æ‚¨çš„ SSH 金鑰設定 %{ssh_key_link} 中建立一個新的金鑰或檢查它們。"
+msgid "You can create a new one or check them in your access token settings: %{target_url}"
+msgstr "您å¯ä»¥å‰µå»ºä¸€å€‹æ–°çš„,或在您的存å–令牌設置中檢查它們:%{target_url}"
+
msgid "You can create a new one or check them in your personal access tokens settings %{pat_link}."
msgstr "您å¯ä»¥åœ¨æ‚¨çš„個人存å–令牌設定%{pat_link}中建立一個新的令牌或檢查它們。"
@@ -53701,9 +54014,6 @@ msgstr "您尚未æ“有任何應用程å¼"
msgid "You don't have any authorized applications."
msgstr "您尚未æ“有任何已授權的應用程å¼"
-msgid "You don't have any deployments right now."
-msgstr "您ç¾åœ¨æ²’有任何部署。"
-
msgid "You don't have any open merge requests"
msgstr "您沒有任何開啟的åˆä½µè«‹æ±‚"
@@ -54198,9 +54508,6 @@ msgstr "您的應用程å¼"
msgid "Your authorized applications"
msgstr "您已授權的應用"
-msgid "Your browser does not support iFrames"
-msgstr "您的ç€è¦½å™¨ä¸æ”¯æ´ iFrame"
-
msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
msgstr "您的ç€è¦½å™¨ä¸æ”¯æ´WebAuthn。請使用支æ´çš„ç€è¦½å™¨ï¼Œå¦‚Chrome(67+)或Firefox(60+)。"
@@ -54319,9 +54626,6 @@ msgstr "您的個人存å–令牌將在 %{days_to_expire} 天或更短的時間å…
msgid "Your profile"
msgstr "個人資料"
-msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr "自 2022 å¹´ 7 月 1 日起,您的專案將ä¸å†ç²å¾— GitLab Ultimate ç¦åˆ©ã€‚正如之å‰åœ¨æ‡‰ç”¨ç¨‹å¼å…§çš„通知,å…費層級的公共開æºå°ˆæ¡ˆå¯ä»¥ç”³è«‹ GitLab é–‹æºè¨ˆåŠƒä»¥ç²å¾— GitLab Ultimate ç¦åˆ©ã€‚è«‹åƒé–± %{faq_link_start}FAQ%{link_end} 了解更多詳情。"
-
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "您的專案é™åˆ¶ç‚º %{limit} 個專案ï¼è«‹èˆ‡æ‚¨çš„管ç†å“¡è¯çµ¡ä»¥å¢žåŠ å®ƒ"
@@ -54346,6 +54650,9 @@ msgstr "您的需求正在匯入。匯入完æˆæ™‚您將收到一å°ç¢ºèªé›»å­
msgid "Your requirements will be imported in the background. After it's finished, you'll get a confirmation email."
msgstr "您的需求將在背景匯入。完æˆå¾Œï¼Œæ‚¨å°‡æ”¶åˆ°ä¸€å°ç¢ºèªé›»å­éƒµä»¶ã€‚"
+msgid "Your resource access tokens will expire in %{days_to_expire} or less"
+msgstr "您的資æºå­˜å–令牌將在 %{days_to_expire} 天內或更短時間內éŽæœŸ"
+
msgid "Your search didn't match any commits."
msgstr "您的æœå°‹æ²’有符åˆä»»ä½•æ交。"
@@ -54513,6 +54820,9 @@ msgstr "所有å—ä¿è­·çš„分支"
msgid "allowed to fail"
msgstr "å…許失敗"
+msgid "already assigned to an epic"
+msgstr "已經分é…給一個å²è©©"
+
msgid "already banned from namespace"
msgstr "已被命å空間å°éŽ–"
@@ -54620,6 +54930,9 @@ msgstr "無法變更為 %{new_type}"
msgid "can not be changed when assigned to an epic"
msgstr "當指派給 epic 時無法更改。"
+msgid "can not be set for template labels"
+msgstr "無法為模æ¿æ¨™è¨˜é€²è¡Œè¨­å®š"
+
msgid "can not be set for this resource"
msgstr "無法設定該資æº"
@@ -55128,6 +55441,9 @@ msgstr " ç”± %{email} é€šéŽ %{author} 在 %{timeAgo} 建立"
msgid "created by"
msgstr "建立者:"
+msgid "created pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
+msgstr "建立了æ交 %{linkStart}%{shortId}%{linkEnd} çš„æµæ°´ç·š"
+
msgid "daily"
msgstr "日常"
@@ -55193,6 +55509,9 @@ msgstr "例如,%{token}"
msgid "eg party_tanuki"
msgstr "例如 party_tanuki"
+msgid "eg. dev/*"
+msgstr "例如. dev/*"
+
msgid "element is not a hierarchy"
msgstr "此元素並éžç¾¤çµ„層級"
@@ -55278,9 +55597,6 @@ msgstr[0] "文件"
msgid "finding is not found or is already attached to a vulnerability"
msgstr "çµæžœç„¡æ³•æ‰¾åˆ°æˆ–已與æ¼æ´žé—œè¯ã€‚"
-msgid "for Workspace is required to be public"
-msgstr "工作å€å¿…須設置為公開"
-
msgid "for Workspace must have an associated RemoteDevelopmentAgentConfig"
msgstr "工作å€å¿…須有關è¯çš„ RemoteDevelopmentAgentConfig"
@@ -55540,6 +55856,9 @@ msgstr "它太大了"
msgid "jigsaw is not defined"
msgstr "jigsaw 未定義"
+msgid "key result"
+msgstr "é—œéµçµæžœ"
+
msgid "kuromoji custom analyzer"
msgstr "kuromoji 自訂分æžå™¨"
@@ -56010,6 +56329,9 @@ msgstr "必須在分å‰ï¼ˆfork)網路內"
msgid "must be less than the limit of %{tag_limit} tags"
msgstr "å¿…é ˆå°æ–¼ %{tag_limit} 個標籤的數é‡é™åˆ¶"
+msgid "must be owned by the user's enterprise group"
+msgstr "必須屬於使用者ä¼æ¥­ç¾¤çµ„"
+
msgid "must be set for a project namespace"
msgstr "必須為專案命å空間設定"
@@ -56019,6 +56341,9 @@ msgstr "必須指定"
msgid "must be unique by status and elapsed time within a policy"
msgstr "必須在政策中的狀態和經éŽæ™‚間上是唯一的"
+msgid "must be unique. This CA has already been configured for another namespace."
+msgstr "必須是唯一的。已為å¦ä¸€å€‹å‘½å空間設定此 CA。"
+
msgid "must belong to same project of its requirement object."
msgstr "必須屬於其需求å°è±¡çš„åŒä¸€å°ˆæ¡ˆã€‚"
@@ -56046,6 +56371,9 @@ msgstr "ä¸èƒ½æ˜¯å‘½å空間的æ“有者"
msgid "must not contain commonly used combinations of words and letters"
msgstr "ä¸å¾—包å«å¸¸ç”¨çš„單字與字æ¯çµ„åˆ"
+msgid "must only contain letters, digits, forward-slash, underscore, hyphen or period"
+msgstr "å¿…é ˆåªåŒ…å«å­—æ¯ã€æ•¸å­—ã€æ­£æ–œç·šã€åº•ç·šã€é€£å­—符或å¥è™Ÿ"
+
msgid "my-awesome-group"
msgstr "我的群組"
@@ -56103,6 +56431,9 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item},和 %{lastItem}"
+msgid "objective"
+msgstr "目標 "
+
msgid "on or after"
msgstr "在或之後"
@@ -56396,6 +56727,9 @@ msgstr "%{slash_command} 增加或減少已經花費的時間。"
msgid "ssh:"
msgstr "ssh:"
+msgid "started"
+msgstr "已開始"
+
msgid "started a discussion on %{design_link}"
msgstr "開始討論%{design_link}"
@@ -56438,6 +56772,9 @@ msgstr "標籤å稱"
msgid "targeting "
msgstr "目標"
+msgid "task"
+msgstr "任務"
+
msgid "terraform states"
msgstr "terraform 狀態"
@@ -56486,9 +56823,6 @@ msgstr "總值必須å°æ–¼æˆ–等於 %{size}"
msgid "triggered"
msgstr "已觸發"
-msgid "triggered pipeline for commit %{linkStart}%{shortId}%{linkEnd}"
-msgstr "觸發了æ交 %{linkStart}%{shortId}%{linkEnd} çš„æµæ°´ç·š"
-
msgid "two-factor authentication settings"
msgstr "雙因å­èªè­‰è¨­å®š"
@@ -56544,6 +56878,9 @@ msgstr " %{report_type} 報告類型的 %{report_version} 版本已棄用;但æ
msgid "version %{versionIndex}"
msgstr "版本 %{versionIndex}"
+msgid "via"
+msgstr "經由"
+
msgid "via %{closed_via}"
msgstr "é€éŽ%{closed_via}"
diff --git a/package.json b/package.json
index 4f71c67a734..e9e20d439e6 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
"markdownlint": "markdownlint --config .markdownlint.yml",
"markdownlint:no-trailing-spaces": "markdownlint --config doc/.markdownlint/markdownlint-no-trailing-spaces.yml",
"markdownlint:no-trailing-spaces:fix": "yarn run markdownlint:no-trailing-spaces --fix",
+ "preinstall": "node ./scripts/frontend/preinstall.mjs",
"postinstall": "node ./scripts/frontend/postinstall.js",
"storybook:install": "yarn --cwd ./storybook install",
"storybook:build": "yarn --cwd ./storybook build --quiet",
@@ -51,17 +52,18 @@
"@apollo/client": "^3.5.10",
"@babel/core": "^7.18.5",
"@babel/preset-env": "^7.18.2",
- "@cubejs-client/core": "^0.33.47",
- "@cubejs-client/vue": "^0.33.47",
+ "@cubejs-client/core": "^0.33.55",
+ "@cubejs-client/vue": "^0.33.55",
"@floating-ui/dom": "^1.2.9",
+ "@gitlab/application-sdk-browser": "^0.2.8",
"@gitlab/at.js": "1.5.7",
- "@gitlab/cluster-client": "^1.2.0",
+ "@gitlab/cluster-client": "^1.3.0",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/fonts": "^1.3.0",
- "@gitlab/svgs": "3.59.0",
- "@gitlab/ui": "65.0.1",
+ "@gitlab/svgs": "3.63.0",
+ "@gitlab/ui": "66.4.0",
"@gitlab/visual-review-tools": "1.7.3",
- "@gitlab/web-ide": "0.0.1-dev-20230821141730",
+ "@gitlab/web-ide": "0.0.1-dev-20230915130935",
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
"@popperjs/core": "^2.11.2",
"@rails/actioncable": "7.0.6",
@@ -124,7 +126,7 @@
"clipboard": "^2.0.8",
"compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1",
- "core-js": "^3.32.0",
+ "core-js": "^3.32.2",
"cron-validator": "^1.1.1",
"cronstrue": "^1.122.0",
"cropper": "^2.3.0",
@@ -136,7 +138,7 @@
"deckar01-task_list": "^2.3.1",
"dexie": "^3.2.3",
"diff": "^3.4.0",
- "dompurify": "^2.4.5",
+ "dompurify": "^3.0.5",
"dropzone": "^4.2.0",
"editorconfig": "^0.15.3",
"emoji-regex": "^10.0.0",
@@ -146,7 +148,7 @@
"gettext-parser": "^6.0.0",
"graphql": "^15.7.2",
"graphql-tag": "^2.11.0",
- "gridstack": "^8.4.0",
+ "gridstack": "^9.2.0",
"highlight.js": "^11.8.0",
"immer": "^9.0.15",
"ipaddr.js": "^1.9.1",
@@ -165,7 +167,7 @@
"marked-bidi": "^1.0.3",
"mathjax": "3",
"mdurl": "^1.0.1",
- "mermaid": "10.1.0",
+ "mermaid": "10.3.1",
"micromatch": "^4.0.5",
"minimatch": "^3.0.4",
"monaco-editor": "^0.30.1",
@@ -179,9 +181,9 @@
"pikaday": "^1.8.0",
"popper.js": "^1.16.1",
"portal-vue": "^2.1.7",
- "postcss": "8.4.14",
+ "postcss": "8.4.28",
"print-js": "^1.6.0",
- "prosemirror-markdown": "1.11.1",
+ "prosemirror-markdown": "1.11.2",
"raphael": "^2.2.7",
"raw-loader": "^4.0.2",
"rehype-raw": "^6.1.1",
@@ -191,8 +193,8 @@
"remark-rehype": "^10.1.0",
"scrollparent": "^2.0.1",
"semver": "^7.3.4",
+ "sentrybrowser": "npm:@sentry/browser@7.66.0",
"sentrybrowser5": "npm:@sentry/browser@5.30.0",
- "sentrybrowser7": "npm:@sentry/browser@^7.21.1",
"sortablejs": "^1.10.2",
"string-hash": "1.1.3",
"style-loader": "^2.0.0",
@@ -210,7 +212,7 @@
"visibilityjs": "^1.2.4",
"vue": "2.7.14",
"vue-apollo": "^3.0.7",
- "vue-loader": "15.10.1",
+ "vue-loader": "15.10.2",
"vue-observe-visibility": "^1.0.0",
"vue-resize": "^1.0.1",
"vue-router": "3.6.5",
@@ -222,8 +224,8 @@
"vuex-vue3": "npm:vuex@4.0.0",
"web-streams-polyfill": "^3.2.1",
"web-vitals": "^0.2.4",
- "webpack": "^4.46.0",
- "webpack-bundle-analyzer": "^4.9.0",
+ "webpack": "^4.47.0",
+ "webpack-bundle-analyzer": "^4.9.1",
"webpack-cli": "^4.10.0",
"webpack-stats-plugin": "^0.3.1",
"worker-loader": "^2.0.0",
@@ -232,11 +234,14 @@
},
"devDependencies": {
"@gitlab/eslint-plugin": "19.0.1",
- "@gitlab/stylelint-config": "4.1.0",
+ "@gitlab/stylelint-config": "5.0.0",
"@graphql-eslint/eslint-plugin": "3.20.1",
+ "@originjs/vite-plugin-commonjs": "^1.0.3",
+ "@rollup/plugin-graphql": "^2.0.3",
"@testing-library/dom": "^7.16.2",
"@types/jest": "^28.1.3",
"@types/lodash": "^4.14.197",
+ "@vitejs/plugin-vue2": "^1.1.2",
"@vue/compat": "^3.2.47",
"@vue/compiler-sfc": "^3.2.47",
"@vue/test-utils": "1.3.6",
@@ -245,16 +250,17 @@
"@vue/vue3-jest": "^29.2.3",
"ajv": "^8.10.0",
"ajv-formats": "^2.1.1",
+ "autoprefixer": "^10.4.8",
"axios-mock-adapter": "^1.15.0",
"babel-jest": "^28.1.3",
"chalk": "^2.4.1",
"cheerio": "^1.0.0-rc.9",
"commander": "^2.20.3",
"custom-jquery-matchers": "^2.1.0",
- "eslint": "8.46.0",
+ "eslint": "8.49.0",
"eslint-import-resolver-jest": "3.0.2",
- "eslint-import-resolver-webpack": "0.13.4",
- "eslint-plugin-import": "^2.28.0",
+ "eslint-import-resolver-webpack": "0.13.7",
+ "eslint-plugin-import": "^2.28.1",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-unsanitized": "^4.0.2",
"fake-indexeddb": "^4.0.1",
@@ -281,11 +287,14 @@
"purgecss": "^4.0.3",
"purgecss-from-html": "^4.0.3",
"sass": "^1.49.9",
- "stylelint": "^14.9.1",
+ "stylelint": "^15.10.2",
"swagger-cli": "^4.0.4",
"timezone-mock": "^1.0.8",
+ "vite": "^4.4.9",
+ "vite-plugin-ruby": "^3.2.2",
+ "vite-svg-loader": "^3.6.0",
"vue-loader-vue3": "npm:vue-loader@17",
- "vue-test-utils-compat": "0.0.13",
+ "vue-test-utils-compat": "0.0.14",
"vuex-mock-store": "^0.1.0",
"webpack-dev-server": "4.15.1",
"xhr-mock": "^2.5.1",
diff --git a/patches/@vue+compiler-core+3.2.47.dev.patch b/patches/@vue+compiler-core+3.2.47.dev.patch
new file mode 100644
index 00000000000..4ac4266d27f
--- /dev/null
+++ b/patches/@vue+compiler-core+3.2.47.dev.patch
@@ -0,0 +1,35 @@
+diff --git a/node_modules/@vue/compiler-core/dist/compiler-core.cjs.js b/node_modules/@vue/compiler-core/dist/compiler-core.cjs.js
+index f6afe09..842766d 100644
+--- a/node_modules/@vue/compiler-core/dist/compiler-core.cjs.js
++++ b/node_modules/@vue/compiler-core/dist/compiler-core.cjs.js
+@@ -980,6 +980,8 @@ function parseChildren(context, mode, ancestors) {
+ const node = nodes[i];
+ if (node.type === 2 /* NodeTypes.TEXT */) {
+ if (!context.inPre) {
++ const isInTextTemplate = parent && parent.tag === 'template' && !nodes.some(n => n && n.tag);
++
+ if (!/[^\t\r\n\f ]/.test(node.content)) {
+ const prev = nodes[i - 1];
+ const next = nodes[i + 1];
+@@ -988,8 +990,8 @@ function parseChildren(context, mode, ancestors) {
+ // - (condense mode) the whitespace is between twos comments, or:
+ // - (condense mode) the whitespace is between comment and element, or:
+ // - (condense mode) the whitespace is between two elements AND contains newline
+- if (!prev ||
+- !next ||
++ if ((!prev && !isInTextTemplate) ||
++ (!next && !isInTextTemplate) ||
+ (shouldCondense &&
+ ((prev.type === 3 /* NodeTypes.COMMENT */ &&
+ next.type === 3 /* NodeTypes.COMMENT */) ||
+@@ -1005,7 +1007,9 @@ function parseChildren(context, mode, ancestors) {
+ }
+ else {
+ // Otherwise, the whitespace is condensed into a single space
+- node.content = ' ';
++ if (!isInTextTemplate) {
++ node.content = ' ';
++ }
+ }
+ }
+ else if (shouldCondense) {
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 00000000000..a47ef4f9528
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ plugins: {
+ autoprefixer: {},
+ },
+};
diff --git a/public/404.html b/public/404.html
index 48b803a7bff..847476683e0 100644
--- a/public/404.html
+++ b/public/404.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
+ <meta content="width=device-width, initial-scale=1" name="viewport">
<title>The page you're looking for could not be found (404)</title>
<style>
body {
diff --git a/public/422.html b/public/422.html
index f7d12a2abca..aaea6fe4f5e 100644
--- a/public/422.html
+++ b/public/422.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
+ <meta content="width=device-width, initial-scale=1" name="viewport">
<title>The change you requested was rejected (422)</title>
<style>
body {
diff --git a/public/500.html b/public/500.html
index 9c04a3db339..56af1654ed7 100644
--- a/public/500.html
+++ b/public/500.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
+ <meta content="width=device-width, initial-scale=1" name="viewport">
<title>Something went wrong (500)</title>
<style>
body {
diff --git a/public/502.html b/public/502.html
index 8d6a95f1b1d..237fbff313f 100644
--- a/public/502.html
+++ b/public/502.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
+ <meta content="width=device-width, initial-scale=1" name="viewport">
<title>GitLab is not responding (502)</title>
<style>
body {
diff --git a/public/503.html b/public/503.html
index 5c29808b4a1..2f09c7a15e1 100644
--- a/public/503.html
+++ b/public/503.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
+ <meta content="width=device-width, initial-scale=1" name="viewport">
<title>GitLab is not responding (503)</title>
<style>
body {
diff --git a/public/deploy.html b/public/deploy.html
index e463b62520c..f9433ce9407 100644
--- a/public/deploy.html
+++ b/public/deploy.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
+ <meta content="width=device-width, initial-scale=1" name="viewport">
<meta name="refresh" content="60">
<meta name="retry-after" content="100">
<meta name="robots" content="noindex, nofollow, noarchive, nostore">
diff --git a/qa/Gemfile b/qa/Gemfile
index 8ad40ec12c2..f1103f472c8 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -2,7 +2,7 @@
source 'https://rubygems.org'
-gem 'gitlab-qa', '~> 12', '>= 12.2.1', require: 'gitlab/qa'
+gem 'gitlab-qa', '~> 12', '>= 12.4.1', require: 'gitlab/qa'
gem 'gitlab_quality-test_tooling', '~> 0.9.3', require: false
gem 'gitlab-utils', path: '../gems/gitlab-utils'
gem 'activesupport', '~> 7.0.5.1' # This should stay in sync with the root's Gemfile
@@ -20,11 +20,11 @@ gem 'rspec_junit_formatter', '~> 0.6.0'
gem 'faker', '~> 3.2'
gem 'knapsack', '~> 4.0'
gem 'parallel_tests', '~> 4.2', '>= 4.2.1'
-gem 'rotp', '~> 6.2.2'
+gem 'rotp', '~> 6.3.0'
gem 'parallel', '~> 1.23'
gem 'rainbow', '~> 3.1.1'
gem 'rspec-parameterized', '~> 1.0.0'
-gem 'octokit', '~> 7.0.0'
+gem 'octokit', '~> 7.1.0'
gem "faraday-retry", "~> 2.2"
gem 'zeitwerk', '~> 2.6', '>= 2.6.8'
gem 'influxdb-client', '~> 2.9'
@@ -44,7 +44,7 @@ gem 'nokogiri', '~> 1.15', '>= 1.15.4'
gem 'deprecation_toolkit', '~> 2.0.3', require: false
-gem 'factory_bot', '~> 6.2.1'
+gem 'factory_bot', '~> 6.3.0'
group :development do
gem 'pry-byebug', '~> 3.10.1', platform: :mri
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 67d64684aa1..8994e6df233 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -80,7 +80,7 @@ GEM
unf (>= 0.0.5, < 1.0.0)
erubi (1.12.0)
excon (0.92.4)
- factory_bot (6.2.1)
+ factory_bot (6.3.0)
activesupport (>= 5.0.0)
faker (3.2.0)
i18n (>= 1.8.11, < 2)
@@ -121,7 +121,7 @@ GEM
gitlab (4.19.0)
httparty (~> 0.20)
terminal-table (>= 1.5.1)
- gitlab-qa (12.2.1)
+ gitlab-qa (12.4.1)
activesupport (>= 6.1, < 7.1)
gitlab (~> 4.19)
http (~> 5.0)
@@ -215,7 +215,7 @@ GEM
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
- octokit (7.0.0)
+ octokit (7.1.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
oj (3.13.23)
@@ -260,7 +260,7 @@ GEM
netrc (~> 0.8)
retriable (3.1.2)
rexml (3.2.5)
- rotp (6.2.2)
+ rotp (6.3.0)
rspec (3.12.0)
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
@@ -346,25 +346,25 @@ DEPENDENCIES
chemlab-library-www-gitlab-com (~> 0.1, >= 0.1.1)
confiner (~> 0.4)
deprecation_toolkit (~> 2.0.3)
- factory_bot (~> 6.2.1)
+ factory_bot (~> 6.3.0)
faker (~> 3.2)
faraday-retry (~> 2.2)
fog-core (= 2.1.0)
fog-google (~> 1.19)
- gitlab-qa (~> 12, >= 12.2.1)
+ gitlab-qa (~> 12, >= 12.4.1)
gitlab-utils!
gitlab_quality-test_tooling (~> 0.9.3)
influxdb-client (~> 2.9)
knapsack (~> 4.0)
nokogiri (~> 1.15, >= 1.15.4)
- octokit (~> 7.0.0)
+ octokit (~> 7.1.0)
parallel (~> 1.23)
parallel_tests (~> 4.2, >= 4.2.1)
pry-byebug (~> 3.10.1)
rainbow (~> 3.1.1)
rake (~> 13, >= 13.0.6)
rest-client (~> 2.1.0)
- rotp (~> 6.2.2)
+ rotp (~> 6.3.0)
rspec (~> 3.12)
rspec-parameterized (~> 1.0.0)
rspec-retry (~> 0.6.2)
@@ -377,4 +377,4 @@ DEPENDENCIES
zeitwerk (~> 2.6, >= 2.6.8)
BUNDLED WITH
- 2.4.18
+ 2.4.19
diff --git a/qa/README.md b/qa/README.md
index c1b6794ca60..15af644a4ae 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -95,29 +95,19 @@ By default tests on CI use `info` log level. `debug` level is still available in
First, follow the instructions to [install GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/index.md) as your local GitLab development environment.
-Then, navigate to the QA folder and run the following commands:
+Then, navigate to the QA folder, install the gems, and run the tests via RSpec:
```bash
cd gitlab-development-kit/gitlab/qa
bundle install
-export WEBDRIVER_HEADLESS=false
-export GITLAB_INITIAL_ROOT_PASSWORD={your current root user's password}
-```
-
-Finally, most tests that do not require special setup (or have the `:orchestrated` tag) can be run with the following command:
-
-```bash
bundle exec rspec <path/to/spec.rb>
```
-However, tests that are tagged with the `:orchestrated` tag require special setup. To run these tests, first [re-configure the IP address in GDK](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/run_qa_against_gdk.md#run-qa-tests-against-your-gdk-setup), and then run the following command:
-
-```bash
-bundle exec bin/qa Test::Instance::All {GDK IP ADDRESS}
-```
-
-- Note: If you want to run tests requiring SSH against GDK, you will need to [modify your GDK setup](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/run_qa_against_gdk.md).
-- Note: If this is your first time running GDK, you can use the password pre-set for `root`. [See supported GitLab environment variables](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#supported-gitlab-environment-variables). If you have changed your `root` password, use that when exporting `GITLAB_INITIAL_ROOT_PASSWORD`.
+Note:
+- If you want to run tests requiring SSH against GDK, you will need to [modify your GDK setup](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/run_qa_against_gdk.md).
+- If this is your first time running GDK, you can use the password pre-set for `root`. [See supported GitLab environment variables](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#supported-gitlab-environment-variables). If you have changed your `root` password, export the password as `GITLAB_INITIAL_ROOT_PASSWORD`.
+- By default the tests will run in a headless browser. If you'd like to watch the test exectution, you can export `WEBDRIVER_HEADLESS=false`.
+- Tests that are tagged `:orchestrated` require special setup (e.g., custom GitLab configuration, or additional services such as LDAP). All [orchestrated tests can be run via `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md). There are also [setup instructions](https://docs.gitlab.com/ee/development/testing_guide/end_to_end/running_tests_that_require_special_setup.html) for running some of those tests against GDK or another local GitLab instance.
#### Generic command for a typical GDK installation
@@ -145,7 +135,7 @@ See the section above for situations that might require adjustment to the comman
1. Use the following command to start an instance that you can visit at `http://127.0.0.1`:
```bash
- docker run \
+ docker run \
--hostname 127.0.0.1 \
--publish 80:80 --publish 22:22 \
--name gitlab \
diff --git a/qa/gdk/Dockerfile.gdk b/qa/gdk/Dockerfile.gdk
index 0926883d00f..829ebecd4ee 100644
--- a/qa/gdk/Dockerfile.gdk
+++ b/qa/gdk/Dockerfile.gdk
@@ -1,23 +1,17 @@
-FROM registry.gitlab.com/gitlab-org/gitlab-development-kit/asdf-bootstrapped-verify:main@sha256:14fa752a80df21f840fc48f4be8561bee21b78886ac718652582fdd788d34c32
+FROM registry.gitlab.com/gitlab-org/gitlab-development-kit/asdf-bootstrapped-verify:main@sha256:66bf41314b7f3bb65ec671f3b2f8d59e1d6de9d2dc0b2daf72aa03a950c75549 as base
ENV GITLAB_LICENSE_MODE=test \
GDK_KILL_CONFIRM=true
-# Allow passwordless /etc/hosts update by gdk user
-USER root
-RUN echo "gdk ALL=(ALL) NOPASSWD: /usr/bin/tee -a /etc/hosts" >> /etc/sudoers
-
-USER gdk
-
# Clone GDK at specific sha and bootstrap packages
#
-ARG GDK_SHA=747ab64be815f5c239d5d63209527a42bd838e83
-ARG GEM_CACHE=/home/gdk/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/cache
-RUN --mount=type=cache,target=${GEM_CACHE},uid=1000,gid=1000 \
- set -eux; \
+ARG GDK_SHA=9756ad259ec0ed356f49ed22678e2f13252b3f4f
+RUN set -eux; \
git clone --depth 1 https://gitlab.com/gitlab-org/gitlab-development-kit.git && cd gitlab-development-kit; \
git fetch --depth 1 origin ${GDK_SHA} && git -c advice.detachedHead=false checkout ${GDK_SHA}; \
- mkdir gitlab && make bootstrap
+ mkdir gitlab \
+ && make bootstrap \
+ && sudo apt-get autoclean
WORKDIR /home/gdk/gitlab-development-kit
@@ -25,59 +19,85 @@ COPY --chown=gdk:gdk qa/gdk/gdk.yml ./
# Build gitlab-shell
#
+FROM base as gitlab-shell
+
COPY --chown=gdk:gdk GITLAB_SHELL_VERSION ./gitlab/
-RUN --mount=type=cache,target=${GEM_CACHE},uid=1000,gid=1000 \
- set -eux; \
- make gitlab-shell-setup \
- && cd gitlab-shell && go clean -cache -modcache -r
+RUN make gitlab-shell-setup \
+ && cd gitlab-shell \
+ && go clean -cache -modcache -r \
+ && rm -rf /home/gdk/.asdf/installs/ruby/*/lib/ruby/gems/*/cache
# Build gitlab-workhorse
#
+FROM base as workhorse
+
COPY --chown=gdk:gdk VERSION GITLAB_WORKHORSE_VERSION ./gitlab/
COPY --chown=gdk:gdk workhorse ./gitlab/workhorse
-RUN --mount=type=cache,target=${GEM_CACHE},uid=1000,gid=1000 \
- set -eux; \
- make gitlab-workhorse-setup && mv gitlab/workhorse ./ \
- && cd workhorse && go clean -cache -modcache -r
+RUN make gitlab-workhorse-setup \
+ && cd gitlab/workhorse \
+ && go clean -cache -modcache -r
# Build gitaly
#
+FROM base as gitaly
COPY --chown=gdk:gdk GITALY_SERVER_VERSION ./gitlab/
-RUN --mount=type=cache,target=${GEM_CACHE},uid=1000,gid=1000 \
- set -eux; \
+RUN set -eux; \
make gitaly-setup; \
cd gitaly \
&& go clean -cache -modcache -r \
&& rm -rf _build/cache \
- _build/deps/git/source \
- _build/deps/libgit2/source \
_build/deps \
_build/intermediate
# Install gitlab gem dependencies
#
+FROM base as gitlab-gems
+
COPY --chown=gdk:gdk Gemfile Gemfile.lock ./gitlab/
COPY --chown=gdk:gdk vendor/gems/ ./gitlab/vendor/gems/
COPY --chown=gdk:gdk gems/ ./gitlab/gems/
-RUN --mount=type=cache,target=${GEM_CACHE},uid=1000,gid=1000 \
- make .gitlab-bundle
+RUN make .gitlab-bundle \
+ && cd gitlab \
+ && rm -rf /home/gdk/.asdf/installs/ruby/*/lib/ruby/gems/*/cache
# Install gitlab npm dependencies
#
+FROM base as gitlab-node-modules
+
COPY --chown=gdk:gdk package.json yarn.lock ./gitlab/
COPY --chown=gdk:gdk scripts/frontend/postinstall.js ./gitlab/scripts/frontend/postinstall.js
+COPY --chown=gdk:gdk scripts/frontend/preinstall.mjs ./gitlab/scripts/frontend/preinstall.mjs
RUN make .gitlab-yarn && yarn cache clean
+# Build final image
+#
+FROM base as gdk
+
+# Set global defaults so we can initialize empty git repo
+RUN git config --global init.defaultBranch master \
+ && git config --global user.email "gdk@example.com" \
+ && git config --global user.name "gdk"
+
+# Copy all components from separate docker stages
+COPY --from=gitlab-shell --chown=gdk:gdk /home/gdk/gitlab-development-kit/gitlab-shell ./gitlab-shell/
+COPY --from=gitaly --chown=gdk:gdk /home/gdk/gitlab-development-kit/gitaly ./gitaly/
+COPY --from=workhorse --chown=gdk:gdk /home/gdk/gitlab-development-kit/gitlab/workhorse ./gitlab/workhorse/
+COPY --from=gitlab-gems --chown=gdk:gdk /home/gdk/.asdf/installs/ruby /home/gdk/.asdf/installs/ruby/
+COPY --from=gitlab-node-modules --chown=gdk:gdk /home/gdk/gitlab-development-kit/gitlab/node_modules ./gitlab/node_modules/
+
# Copy code
COPY --chown=gdk:gdk ./ ./gitlab/
COPY --chown=gdk:gdk qa/gdk/entrypoint ../
-# Create missing pids folder and sync compiled workhorse
-RUN mkdir -p gitlab/tmp/pids \
- && rsync -a --remove-source-files workhorse/ gitlab/workhorse/
-
# Set up GDK
-RUN SKIP_WORKHORSE_SETUP=true SKIP_GITLAB_SHELL_SETUP=true SKIP_GITALY_SETUP=true \
+RUN set -eux; \
+ # We need to init git repository within docker build because external .git folder
+ # will always invalidate cache on 'COPY --chown=gdk:gdk ./ ./gitlab/' step and some gdk setup steps require gitlab
+ # to be an actual git repository
+ (cd gitlab && git init . && git add --all && git commit --quiet -m "Init repository") &> /dev/null; \
+ gdk config set gitaly.skip_setup true \
+ && gdk config set workhorse.skip_setup true \
+ && gdk config set gitlab_shell.skip_setup true; \
make redis/redis.conf all \
&& gdk kill
diff --git a/qa/gdk/Dockerfile.gdk.dockerignore b/qa/gdk/Dockerfile.gdk.dockerignore
index 26062339c21..ce7f2ae3d37 100644
--- a/qa/gdk/Dockerfile.gdk.dockerignore
+++ b/qa/gdk/Dockerfile.gdk.dockerignore
@@ -1,3 +1,5 @@
+.go/
+.git/
.bundle/
.gitlab/
.lefthook/
@@ -6,11 +8,12 @@
builds/
changelogs/
danger/
+data/
doc/
-log/*.log
-node_modules/
rubocop/
-tmp/*
+storybook/
+node_modules/
+log/*.log
.eslint*
.gitlab-ci.yml
@@ -27,6 +30,12 @@ tests.yml
*.md
+tmp/*
+!tmp/feature_flags
+!tmp/pids
+!tmp/prometheus_multiproc_dir
+!tmp/sockets
+
db/fixtures/
!db/fixtures/development/01_admin.rb
!db/fixtures/development/02_application_settings.rb
@@ -40,3 +49,13 @@ scripts/
qa/
!qa/gdk
+
+spec/
+!spec/contracts
+!spec/factories
+!spec/support
+
+ee/spec
+!ee/spec/contracts
+!ee/spec/factories
+!ee/spec/support
diff --git a/qa/gdk/entrypoint b/qa/gdk/entrypoint
index 3b86f19b9b2..62403648885 100755
--- a/qa/gdk/entrypoint
+++ b/qa/gdk/entrypoint
@@ -8,14 +8,6 @@ set -e
# from outside the container
echo "$(hostname -i) gdk.test" | sudo tee -a /etc/hosts > /dev/null
-# make sure we don't override existing BUNDLE_PATH which happens on CI where all job variables are also passed in to service
-unset BUNDLE_PATH
-
gdk start
-# /builds folder is present when running as a service on CI
-if [ -d /builds ]; then
- exec "$@" | tee -a /builds/gdk.log
-else
- exec "$@" | tee -a ${HOME}/gitlab-development-kit/gitlab/log/gdk.log
-fi
+exec "$@" | tee -a ${HOME}/gitlab-development-kit/gitlab/log/gdk.log
diff --git a/qa/lib/gitlab/page/group/settings/billing.rb b/qa/lib/gitlab/page/group/settings/billing.rb
index 0d25a012db3..086cb42a778 100644
--- a/qa/lib/gitlab/page/group/settings/billing.rb
+++ b/qa/lib/gitlab/page/group/settings/billing.rb
@@ -11,13 +11,12 @@ module Gitlab
link :upgrade_to_ultimate
# Subscription details
- strong :subscription_header
+ h5 :subscription_header
button :refresh_seats
# Usage
p :seats_in_subscription
p :seats_currently_in_use
- link :see_seats_usage
p :max_seats_used
p :seats_owed
diff --git a/qa/lib/gitlab/page/group/settings/billing.stub.rb b/qa/lib/gitlab/page/group/settings/billing.stub.rb
index c49d744d61f..9aa1a23ec14 100644
--- a/qa/lib/gitlab/page/group/settings/billing.stub.rb
+++ b/qa/lib/gitlab/page/group/settings/billing.stub.rb
@@ -197,30 +197,6 @@ module Gitlab
# This is a stub, used for indexing. The method is dynamically generated.
end
- # @note Defined as +link :see_seats_usage+
- # Clicks +see_seats_usage+
- def see_seats_usage
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::Billing.perform do |billing|
- # expect(billing.see_seats_usage_element).to exist
- # end
- # @return [Watir::Link] The raw +Link+ element
- def see_seats_usage_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::Billing.perform do |billing|
- # expect(billing).to be_see_seats_usage
- # end
- # @return [Boolean] true if the +see_seats_usage+ element is present on the page
- def see_seats_usage?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
# @note Defined as +p :max_seats_used+
# @return [String] The text content or value of +max_seats_used+
def max_seats_used
diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
index cdb0760ad9c..8ae9e8fd25a 100644
--- a/qa/lib/gitlab/page/group/settings/usage_quotas.rb
+++ b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
@@ -6,14 +6,10 @@ module Gitlab
module Settings
class UsageQuotas < Chemlab::Page
# Seats section
- link :seats_tab
div :seats_in_use
p :seats_used
p :seats_owed
table :subscription_users
- div :pending_members_alert
- button :remove_user
- button :view_pending_approvals, text: /View pending approvals/
# Pipelines section
link :pipelines_tab
@@ -27,23 +23,17 @@ module Gitlab
link :purchase_more_storage
div :namespace_usage_total
div :group_usage_message
- div :dependency_proxy_usage
span :dependency_proxy_size
- div :container_registry_usage
- div :project
- div :storage_type_legend
- span :container_registry_size
- div :storage_purchased, 'data-testid': 'storage-purchased'
+ div :storage_purchased
div :storage_purchase_successful_alert, text: /You have successfully purchased a storage/
span :project_repository_size
- span :project_lfs_object_size
- span :project_build_artifact_size
- span :project_packages_size
span :project_wiki_size
span :project_snippets_size
span :project_containers_registry_size
# Pending members
+ button :view_pending_approvals, text: /View pending approvals/
+ div :pending_members_alert
div :pending_members
button :approve_member
button :confirm_member_approval, text: /^OK$/
@@ -62,15 +52,6 @@ module Gitlab
additional_ci_minutes?
end
- # Waits and Checks if storage project data loaded
- #
- # @return [Boolean] True if the alert presents, false if not after 5 second wait
- def project_storage_data_available?
- storage_type_legend_element.wait_until(timeout: 3, &:present?)
- rescue Watir::Wait::TimeoutError
- false
- end
-
# Returns total purchased storage value once it's ready on page
#
# @return [Float] Total purchased storage value in GiB
diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb
index 8099d1cf53a..748c9a82d59 100644
--- a/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb
+++ b/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb
@@ -5,30 +5,6 @@ module Gitlab
module Group
module Settings
module UsageQuotas
- # @note Defined as +link :seats_tab+
- # Clicks +seats_tab+
- def seats_tab
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas.seats_tab_element).to exist
- # end
- # @return [Watir::Link] The raw +Link+ element
- def seats_tab_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas).to be_seats_tab
- # end
- # @return [Boolean] true if the +seats_tab+ element is present on the page
- def seats_tab?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
# @note Defined as +div :seats_in_use+
# @return [String] The text content or value of +seats_in_use+
def seats_in_use
@@ -125,30 +101,6 @@ module Gitlab
# This is a stub, used for indexing. The method is dynamically generated.
end
- # @note Defined as +button :remove_user+
- # Clicks +remove_user+
- def remove_user
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas.remove_user_element).to exist
- # end
- # @return [Watir::Button] The raw +Button+ element
- def remove_user_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas).to be_remove_user
- # end
- # @return [Boolean] true if the +remove_user+ element is present on the page
- def remove_user?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
# @note Defined as +link :pipelines_tab+
# Clicks +pipelines_tab+
def pipelines_tab
@@ -365,30 +317,6 @@ module Gitlab
# This is a stub, used for indexing. The method is dynamically generated.
end
- # @note Defined as +div :dependency_proxy_usage+
- # @return [String] The text content or value of +dependency_proxy_usage+
- def dependency_proxy_usage
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas.dependency_proxy_usage_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def dependency_proxy_usage_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas).to be_dependency_proxy_usage
- # end
- # @return [Boolean] true if the +dependency_proxy_usage+ element is present on the page
- def dependency_proxy_usage?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
# @note Defined as +span :dependency_proxy_size+
# @return [String] The text content or value of +dependency_proxy_size+
def dependency_proxy_size
@@ -413,30 +341,6 @@ module Gitlab
# This is a stub, used for indexing. The method is dynamically generated.
end
- # @note Defined as +div :container_registry_usage+
- # @return [String] The text content or value of +container_registry_usage+
- def container_registry_usage
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas.container_registry_usage_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def container_registry_usage_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas).to be_container_registry_usage
- # end
- # @return [Boolean] true if the +container_registry_usage+ element is present on the page
- def container_registry_usage?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
# @note Defined as +div :project_storage_used+
# @return [String] The text content or value of +project_storage_used+
def project_storage_used
@@ -485,54 +389,6 @@ module Gitlab
# This is a stub, used for indexing. The method is dynamically generated.
end
- # @note Defined as +div :storage_type_legend+
- # @return [String] The text content or value of +storage_type_legend+
- def storage_type_legend
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas.storage_type_legend_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def storage_type_legend_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas).to be_storage_type_legend
- # end
- # @return [Boolean] true if the +storage_type_legend+ element is present on the page
- def storage_type_legend?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +span :container_registry_size+
- # @return [String] The text content or value of +container_registry_size+
- def container_registry_size
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas.container_registry_size_element).to exist
- # end
- # @return [Watir::Span] The raw +Span+ element
- def container_registry_size_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
- # expect(usage_quotas).to be_container_registry_size
- # end
- # @return [Boolean] true if the +container_registry_size+ element is present on the page
- def container_registry_size?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
# @note Defined as +div :storage_purchased+
# @return [String] The text content or value of +storage_purchased+
def storage_purchased
diff --git a/qa/lib/gitlab/page/main/login.rb b/qa/lib/gitlab/page/main/login.rb
deleted file mode 100644
index de05df1a086..00000000000
--- a/qa/lib/gitlab/page/main/login.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Page
- module Main
- class Login < Chemlab::Page
- path '/users/sign_in'
-
- text_field :login_field
- text_field :password_field
- button :sign_in_button
-
- button :accept_terms, text: 'Accept terms'
-
- # password change tab
- text_field :password_confirmation_field
- button :change_password_button
-
- # Sign in using a given username and password
- # @note this will also automatically accept terms if prompted
- # @param [String] username the username to sign in with
- # @param [String] password the password to sign in with
- # @example
- # Page::Main::Login.perform do |login|
- # login.sign_in_as(username: 'username', password: 'password')
- # login.sign_in_as(username: 'username', password: 'password', accept_terms: false)
- # end
- def sign_in_as(username:, password:, accept_terms: true)
- self.login_field = username
- self.password_field = password
-
- sign_in_button
- self.accept_terms if accept_terms && accept_terms?
- end
- end
- end
- end
-end
diff --git a/qa/lib/gitlab/page/main/login.stub.rb b/qa/lib/gitlab/page/main/login.stub.rb
deleted file mode 100644
index a819ca4bcc8..00000000000
--- a/qa/lib/gitlab/page/main/login.stub.rb
+++ /dev/null
@@ -1,183 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Page
- module Main
- module Login
- # @note Defined as +text_field :login_field+
- # @return [String] The text content or value of +login_field+
- def login_field
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # Set the value of login_field
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # login.login_field = 'value'
- # end
- # @param value [String] The value to set.
- def login_field=(value)
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login.login_field_element).to exist
- # end
- # @return [Watir::TextField] The raw +TextField+ element
- def login_field_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login).to be_login_field
- # end
- # @return [Boolean] true if the +login_field+ element is present on the page
- def login_field?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +text_field :password_field+
- # @return [String] The text content or value of +password_field+
- def password_field
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # Set the value of password_field
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # login.password_field = 'value'
- # end
- # @param value [String] The value to set.
- def password_field=(value)
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login.password_field_element).to exist
- # end
- # @return [Watir::TextField] The raw +TextField+ element
- def password_field_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login).to be_password_field
- # end
- # @return [Boolean] true if the +password_field+ element is present on the page
- def password_field?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +button :sign_in_button+
- # Clicks +sign_in_button+
- def sign_in_button
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login.sign_in_button_element).to exist
- # end
- # @return [Watir::Button] The raw +Button+ element
- def sign_in_button_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login).to be_sign_in_button
- # end
- # @return [Boolean] true if the +sign_in_button+ element is present on the page
- def sign_in_button?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +button :accept_terms+
- # Clicks +accept_terms+
- def accept_terms
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login.accept_terms_element).to exist
- # end
- # @return [Watir::Button] The raw +Button+ element
- def accept_terms_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login).to be_accept_terms
- # end
- # @return [Boolean] true if the +accept_terms+ element is present on the page
- def accept_terms?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +text_field :password_confirmation_field+
- # @return [String] The text content or value of +password_confirmation_field+
- def password_confirmation_field
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # Set the value of password_confirmation_field
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # login.password_confirmation_field = 'value'
- # end
- # @param value [String] The value to set.
- def password_confirmation_field=(value)
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login.password_confirmation_field_element).to exist
- # end
- # @return [Watir::TextField] The raw +TextField+ element
- def password_confirmation_field_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login).to be_password_confirmation_field
- # end
- # @return [Boolean] true if the +password_confirmation_field+ element is present on the page
- def password_confirmation_field?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +button :change_password_button+
- # Clicks +change_password_button+
- def change_password_button
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login.change_password_button_element).to exist
- # end
- # @return [Watir::Button] The raw +Button+ element
- def change_password_button_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Main::Login.perform do |login|
- # expect(login).to be_change_password_button
- # end
- # @return [Boolean] true if the +change_password_button+ element is present on the page
- def change_password_button?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
- end
- end
- end
-end
diff --git a/qa/lib/gitlab/page/main/sign_up.rb b/qa/lib/gitlab/page/main/sign_up.rb
index 85d7f482461..d4ae335babd 100644
--- a/qa/lib/gitlab/page/main/sign_up.rb
+++ b/qa/lib/gitlab/page/main/sign_up.rb
@@ -6,16 +6,15 @@ module Gitlab
class SignUp < Chemlab::Page
path '/users/sign_up'
- # TODO: Refactor data-qa-selectors to be more terse
- text_field :first_name, 'data-qa-selector': 'new_user_first_name_field'
- text_field :last_name, 'data-qa-selector': 'new_user_last_name_field'
+ text_field :first_name, 'data-testid': 'new-user-first-name-field'
+ text_field :last_name, 'data-testid': 'new-user-last-name-field'
- text_field :username, 'data-qa-selector': 'new_user_username_field'
+ text_field :username, 'data-testid': 'new-user-username-field'
- text_field :email, 'data-qa-selector': 'new_user_email_field'
- text_field :password, 'data-qa-selector': 'new_user_password_field'
+ text_field :email, 'data-testid': 'new-user-email-field'
+ text_field :password, 'data-testid': 'new-user-password-field'
- button :register, 'data-qa-selector': 'new_user_register_button'
+ button :register, 'data-testid': 'new-user-register-button'
# Register a user
# @param [Resource::User] user the user to register
diff --git a/qa/lib/gitlab/page/subscriptions/new.rb b/qa/lib/gitlab/page/subscriptions/new.rb
index 6e3cb45fd29..95e5028f985 100644
--- a/qa/lib/gitlab/page/subscriptions/new.rb
+++ b/qa/lib/gitlab/page/subscriptions/new.rb
@@ -38,8 +38,8 @@ module Gitlab
button :confirm_purchase, text: /Confirm purchase/
# Order Summary
- div :selected_plan, 'data-testid': 'selected-plan'
- div :order_total, 'data-testid': 'total-amount'
+ div :selected_plan
+ div :total_amount
end
end
end
diff --git a/qa/lib/gitlab/page/subscriptions/new.stub.rb b/qa/lib/gitlab/page/subscriptions/new.stub.rb
index 93680ab95e0..a7f5d689838 100644
--- a/qa/lib/gitlab/page/subscriptions/new.stub.rb
+++ b/qa/lib/gitlab/page/subscriptions/new.stub.rb
@@ -86,6 +86,40 @@ module Gitlab
# This is a stub, used for indexing. The method is dynamically generated.
end
+ # @note Defined as +text_field :quantity+
+ # @return [String] The text content or value of +quantity+
+ def quantity
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # Set the value of quantity
+ # @example
+ # Gitlab::Page::Subscriptions::New.perform do |new|
+ # new.quantity = 'value'
+ # end
+ # @param value [String] The value to set.
+ def quantity=(value)
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Subscriptions::New.perform do |new|
+ # expect(new.quantity_element).to exist
+ # end
+ # @return [Watir::TextField] The raw +TextField+ element
+ def quantity_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Subscriptions::New.perform do |new|
+ # expect(new).to be_quantity
+ # end
+ # @return [Boolean] true if the +quantity+ element is present on the page
+ def quantity?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
# @note Defined as +button :continue_to_billing+
# Clicks +continue_to_billing+
def continue_to_billing
@@ -539,6 +573,54 @@ module Gitlab
def confirm_purchase?
# This is a stub, used for indexing. The method is dynamically generated.
end
+
+ # @note Defined as +div :selected_plan+
+ # @return [String] The text content or value of +selected_plan+
+ def selected_plan
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Subscriptions::New.perform do |new|
+ # expect(new.selected_plan_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def selected_plan_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Subscriptions::New.perform do |new|
+ # expect(new).to be_selected_plan
+ # end
+ # @return [Boolean] true if the +selected_plan+ element is present on the page
+ def selected_plan?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :total_amount+
+ # @return [String] The text content or value of +total_amount+
+ def total_amount
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Subscriptions::New.perform do |new|
+ # expect(new.total_amount_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def total_amount_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Subscriptions::New.perform do |new|
+ # expect(new).to be_total_amount
+ # end
+ # @return [Boolean] true if the +total_amount+ element is present on the page
+ def total_amount?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
end
end
end
diff --git a/qa/perf/ai/Dockerfile.ab b/qa/perf/ai/Dockerfile.ab
new file mode 100644
index 00000000000..72c4681ed47
--- /dev/null
+++ b/qa/perf/ai/Dockerfile.ab
@@ -0,0 +1,7 @@
+FROM alpine:3.18
+
+RUN apk add --no-cache apache2-utils
+
+COPY prompt.json .
+
+ENTRYPOINT [ "/usr/bin/ab" ]
diff --git a/qa/perf/ai/README.md b/qa/perf/ai/README.md
new file mode 100644
index 00000000000..c0fbcf09f0c
--- /dev/null
+++ b/qa/perf/ai/README.md
@@ -0,0 +1,43 @@
+# Performance testing tools for AI features
+
+## Code Suggestions
+
+These tests are based on [examples from testing of the Code Suggestions Model Gateway](https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/issues/77).
+
+### Apache Bench
+
+If you're using a Mac you may already have the [Apache Bench](https://httpd.apache.org/docs/current/programs/ab.html) tool installed:
+
+```shell
+$ which ab
+/usr/sbin/ab
+```
+
+#### Build a Docker image
+
+If you don't already have Apache Bench installed, [`Dockerfile.ab`](Dockerfile.ab) allows you to build a Docker image that you can use to run it.
+
+To build the image, from the `qa/perf/ai` directory run:
+
+```shell
+docker build -t ab -f Dockerfile.ab .
+```
+
+That will create an image named `ab`. When you start a container via `docker run <image>` any arguments that follow will be passed to `ab` inside
+the container. The command in the section below assumes you have Apache Bench installed, but you can use the image you built if you
+add `docker run --rm` in front of the command. For example, instead of `ab -n 1000 ...` use `docker run --rm ab -n 1000 ...`.
+
+### Run tests
+
+WARNING:
+Be mindful of the potential impact before running a performance test. It could disrupt accessibility for other users and could be problematic for our use of third-party services. If you're unsure, consult the relevant teams (those working on the Code Suggestions feature, the [AI-powered:AI Framework](https://about.gitlab.com/handbook/product/categories/#ai-framework-group) group, the [Create:Code Creation](https://about.gitlab.com/handbook/product/categories/#code-creation-group) group, and the [`#g_code_suggestions` Slack channel (internal)](https://gitlab.slack.com/archives/C048Z2DHWGP))
+
+To run performance tests using Apache Bench, execute the following from the `qa/perf/ai` directory:
+
+```shell
+export GITLAB_PAT=<your personal access token>
+export URL=<the code suggestions endpoint to test>
+ab -n 1000 -c 20 -H "Authorization: Bearer $GITLAB_PAT" -T 'application/json' -p prompt.json $URL
+```
+
+For example, if `$URL` were `https://staging.gitlab.com/api/v4/code_suggestions/completions` that command would `POST` 1000 requests, 20 at a time, to the staging Code Suggestions completions endpoint, using the data in [`prompt.json`](prompt.json) as the prompt.
diff --git a/qa/perf/ai/prompt.json b/qa/perf/ai/prompt.json
new file mode 100644
index 00000000000..8668f71f4f5
--- /dev/null
+++ b/qa/perf/ai/prompt.json
@@ -0,0 +1,10 @@
+{
+ "prompt_version": 1,
+ "project_path": "gitlab-org/gitlab",
+ "project_id": 278964,
+ "current_file": {
+ "file_name": "test.py",
+ "content_above_cursor": "import pytest",
+ "content_below_cursor": ""
+ }
+}
diff --git a/qa/qa.rb b/qa/qa.rb
index f0eb7deb205..cfa2c68a3cd 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -59,6 +59,7 @@ module QA
"ssh_keys" => "SSHKeys",
"ecdsa" => "ECDSA",
"ed25519" => "ED25519",
+ "graphql" => "GraphQL",
"rsa" => "RSA",
"ldap" => "LDAP",
"ldap_tls" => "LDAPTLS",
diff --git a/qa/qa/factories/access_tokens.rb b/qa/qa/factories/access_tokens.rb
new file mode 100644
index 00000000000..60fdbb75785
--- /dev/null
+++ b/qa/qa/factories/access_tokens.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ factory :project_access_token, class: 'QA::Resource::ProjectAccessToken'
+ factory :group_access_token, class: 'QA::Resource::GroupAccessToken'
+ end
+end
diff --git a/qa/qa/factories/files.rb b/qa/qa/factories/files.rb
new file mode 100644
index 00000000000..ed21812e291
--- /dev/null
+++ b/qa/qa/factories/files.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ factory :file, class: 'QA::Resource::File'
+ end
+end
diff --git a/qa/qa/factories/jobs.rb b/qa/qa/factories/jobs.rb
new file mode 100644
index 00000000000..7e659df57a1
--- /dev/null
+++ b/qa/qa/factories/jobs.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ # https://docs.gitlab.com/ee/api/jobs.html
+ factory :job, class: 'QA::Resource::Job'
+ end
+end
diff --git a/qa/qa/factories/labels.rb b/qa/qa/factories/labels.rb
new file mode 100644
index 00000000000..e4668fdf784
--- /dev/null
+++ b/qa/qa/factories/labels.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ factory :project_label, class: 'QA::Resource::ProjectLabel'
+ factory :group_label, class: 'QA::Resource::GroupLabel'
+ end
+end
diff --git a/qa/qa/factories/milestones.rb b/qa/qa/factories/milestones.rb
new file mode 100644
index 00000000000..949d2f0346d
--- /dev/null
+++ b/qa/qa/factories/milestones.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ factory :project_milestone, class: 'QA::Resource::ProjectMilestone'
+ factory :group_milestone, class: 'QA::Resource::GroupMilestone'
+ end
+end
diff --git a/qa/qa/factories/pipelines.rb b/qa/qa/factories/pipelines.rb
new file mode 100644
index 00000000000..aa3a48fd034
--- /dev/null
+++ b/qa/qa/factories/pipelines.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ # https://docs.gitlab.com/ee/api/pipelines.html
+ factory :pipeline, class: 'QA::Resource::Pipeline'
+ end
+end
diff --git a/qa/qa/factories/runners.rb b/qa/qa/factories/runners.rb
new file mode 100644
index 00000000000..ed9d60154be
--- /dev/null
+++ b/qa/qa/factories/runners.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ factory :project_runner, class: 'QA::Resource::ProjectRunner'
+ factory :group_runner, class: 'QA::Resource::GroupRunner'
+ end
+end
diff --git a/qa/qa/factories/snippets.rb b/qa/qa/factories/snippets.rb
new file mode 100644
index 00000000000..65a4d260566
--- /dev/null
+++ b/qa/qa/factories/snippets.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ factory :snippet, class: 'QA::Resource::Snippet' do
+ trait :private do
+ visibility { 'Private' }
+ end
+
+ factory :project_snippet, class: 'QA::Resource::ProjectSnippet'
+ end
+ end
+end
diff --git a/qa/qa/factories/users.rb b/qa/qa/factories/users.rb
new file mode 100644
index 00000000000..dd75ec04541
--- /dev/null
+++ b/qa/qa/factories/users.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module QA
+ FactoryBot.define do
+ # https://docs.gitlab.com/ee/api/users.html
+ factory :user, class: 'QA::Resource::User' do
+ trait :admin do
+ admin { true }
+ end
+
+ trait :set_public_email do
+ after(:create, &:set_public_email)
+ end
+
+ trait :hard_delete do
+ hard_delete_on_api_removal { true }
+ end
+ end
+ end
+end
diff --git a/qa/qa/flow/merge_request.rb b/qa/qa/flow/merge_request.rb
index 24abfa9e356..040fd8bdd51 100644
--- a/qa/qa/flow/merge_request.rb
+++ b/qa/qa/flow/merge_request.rb
@@ -22,7 +22,7 @@ module QA
return
end
- Page::Project::Menu.perform(&:click_merge_requests)
+ Page::Project::Menu.perform(&:go_to_merge_requests)
Page::MergeRequest::Index.perform(&:click_new_merge_request)
Page::MergeRequest::New.perform do |merge_request|
merge_request.select_source_branch(source_branch)
diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb
index 3b044f8a051..8fd813a5ddc 100644
--- a/qa/qa/page/admin/menu.rb
+++ b/qa/qa/page/admin/menu.rb
@@ -5,11 +5,8 @@ module QA
module Admin
class Menu < Page::Base
include SubMenus::Common
-
- if QA::Runtime::Env.super_sidebar_enabled?
- prepend Sidebar::Overview
- prepend Sidebar::Settings
- end
+ include Sidebar::Overview
+ include Sidebar::Settings
view 'lib/sidebars/admin/menus/admin_overview_menu.rb' do
element :admin_overview_submenu_content
@@ -23,73 +20,12 @@ module QA
element :admin_monitoring_menu_link
end
- def go_to_preferences_settings
- hover_element(:admin_settings_menu_link) do
- click_element :admin_settings_preferences_link
- end
- end
-
- def go_to_repository_settings
- hover_element(:admin_settings_menu_link) do
- click_element :admin_settings_repository_link
- end
- end
-
- def go_to_integration_settings
- hover_element(:admin_settings_menu_link) do
- click_element :admin_settings_integrations_link
- end
- end
-
- def go_to_general_settings
- hover_element(:admin_settings_menu_link) do
- click_element :admin_settings_general_link
- end
- end
-
- def go_to_metrics_and_profiling_settings
- hover_element(:admin_settings_menu_link) do
- click_element :admin_settings_metrics_and_profiling_link
- end
- end
-
- def go_to_network_settings
- hover_element(:admin_settings_menu_link) do
- click_element :admin_settings_network_link
- end
- end
-
- def go_to_users_overview
- click_element :admin_overview_users_link
- end
-
- def go_to_groups_overview
- click_element :admin_overview_groups_link
- end
-
- def go_to_security_and_compliance
- hover_element(:admin_settings_menu_link) do
- click_element :admin_security_and_compliance_link
- end
- end
-
def go_to_applications
- return click_element(:nav_item_link, submenu_item: 'Applications') if Runtime::Env.super_sidebar_enabled?
-
- click_element(:sidebar_menu_link, menu_item: 'Applications')
+ click_element(:nav_item_link, submenu_item: 'Applications')
end
private
- def hover_element(element)
- within_sidebar do
- scroll_to_element(element)
- find_element(element).hover
-
- yield
- end
- end
-
def within_sidebar(&block)
page.within('.sidebar-top-level-items', &block)
end
diff --git a/qa/qa/page/admin/overview/groups/edit.rb b/qa/qa/page/admin/overview/groups/edit.rb
index 8e4650a1232..c096f1c862e 100644
--- a/qa/qa/page/admin/overview/groups/edit.rb
+++ b/qa/qa/page/admin/overview/groups/edit.rb
@@ -7,11 +7,11 @@ module QA
module Groups
class Edit < QA::Page::Base
view 'app/views/admin/groups/_form.html.haml' do
- element :save_changes_button, required: true
+ element 'save-changes-button', required: true
end
def click_save_changes_button
- click_element :save_changes_button, Groups::Show
+ click_element 'save-changes-button', Groups::Show
end
end
end
diff --git a/qa/qa/page/admin/overview/groups/index.rb b/qa/qa/page/admin/overview/groups/index.rb
index c9417bd01b1..6157e7a5e4d 100644
--- a/qa/qa/page/admin/overview/groups/index.rb
+++ b/qa/qa/page/admin/overview/groups/index.rb
@@ -7,21 +7,21 @@ module QA
module Groups
class Index < QA::Page::Base
view 'app/views/admin/groups/index.html.haml' do
- element :group_search_field, required: true
+ element 'group-search-field', required: true
end
view 'app/views/admin/groups/_group.html.haml' do
- element :group_row_content
- element :group_name_link
+ element 'group-row-content'
+ element 'group-name-link'
end
def search_group(group_name)
- find_element(:group_search_field).set(group_name).send_keys(:return)
+ find_element('group-search-field').set(group_name).send_keys(:return)
end
def click_group(group_name)
- within_element(:group_row_content, text: group_name) do
- click_element(:group_name_link)
+ within_element('group-row-content', text: group_name) do
+ click_element('group-name-link')
end
end
end
diff --git a/qa/qa/page/admin/overview/groups/show.rb b/qa/qa/page/admin/overview/groups/show.rb
index 6744b0c1e70..c7f2760857f 100644
--- a/qa/qa/page/admin/overview/groups/show.rb
+++ b/qa/qa/page/admin/overview/groups/show.rb
@@ -7,11 +7,11 @@ module QA
module Groups
class Show < QA::Page::Base
view 'app/views/admin/groups/show.html.haml' do
- element :edit_group_link, required: true
+ element 'edit-group-link', required: true
end
def click_edit_group_link
- click_element :edit_group_link, Groups::Edit
+ click_element 'edit-group-link', Groups::Edit
end
end
end
diff --git a/qa/qa/page/admin/overview/users/index.rb b/qa/qa/page/admin/overview/users/index.rb
index 6f1134b751a..c444b728f5a 100644
--- a/qa/qa/page/admin/overview/users/index.rb
+++ b/qa/qa/page/admin/overview/users/index.rb
@@ -7,8 +7,8 @@ module QA
module Users
class Index < QA::Page::Base
view 'app/views/admin/users/_users.html.haml' do
- element :user_search_field
- element :pending_approval_tab
+ element 'user-search-field'
+ element 'pending-approval-tab'
end
view 'app/assets/javascripts/admin/users/components/users_table.vue' do
@@ -16,11 +16,11 @@ module QA
end
def search_user(username)
- find_element(:user_search_field).set(username).send_keys(:return)
+ find_element('user-search-field').set(username).send_keys(:return)
end
def click_pending_approval_tab
- click_element :pending_approval_tab
+ click_element 'pending-approval-tab'
end
def click_user(username)
diff --git a/qa/qa/page/admin/overview/users/show.rb b/qa/qa/page/admin/overview/users/show.rb
index 2fde3ac2c6d..1087ef723a5 100644
--- a/qa/qa/page/admin/overview/users/show.rb
+++ b/qa/qa/page/admin/overview/users/show.rb
@@ -7,54 +7,53 @@ module QA
module Users
class Show < QA::Page::Base
view 'app/views/admin/users/_head.html.haml' do
- element :impersonate_user_link
- element :impersonation_tokens_tab
+ element 'impersonate-user-link'
+ element 'impersonation-tokens-tab'
end
view 'app/views/admin/users/show.html.haml' do
- element :user_id_content
+ element 'user-id-content'
end
view 'app/assets/javascripts/admin/users/components/actions/approve.vue' do
- element :approve_user_button
- element :approve_user_confirm_button
+ element 'approve-user-confirm-button'
end
view 'app/assets/javascripts/admin/users/components/user_actions.vue' do
- element :user_actions_dropdown_toggle
+ element 'user-actions-dropdown-toggle'
end
view 'app/helpers/users_helper.rb' do
- element :confirm_user_button
- element :confirm_user_confirm_button
+ element 'confirm-user-button'
+ element 'confirm-user-confirm-button'
end
def open_user_actions_dropdown(user)
- click_element(:user_actions_dropdown_toggle, username: user.username)
+ click_element('user-actions-dropdown-toggle', username: user.username)
end
def go_to_impersonation_tokens(&block)
- navigate_to_tab(:impersonation_tokens_tab)
+ navigate_to_tab('impersonation-tokens-tab')
Users::Components::ImpersonationTokens.perform(&block)
end
def click_impersonate_user
- click_element(:impersonate_user_link)
+ click_element('impersonate-user-link')
end
def user_id
- find_element(:user_id_content).text
+ find_element('user-id-content').text
end
def confirm_user
- click_element :confirm_user_button
- click_element :confirm_user_confirm_button
+ click_element 'confirm-user-button'
+ click_element 'confirm-user-confirm-button'
end
def approve_user(user)
open_user_actions_dropdown(user)
- click_element :approve_user_button
- click_element :approve_user_confirm_button
+ click_element 'approve'
+ click_element 'approve-user-confirm-button'
end
private
diff --git a/qa/qa/page/blame/show.rb b/qa/qa/page/blame/show.rb
index cbe8ef600dc..42fb217d2df 100644
--- a/qa/qa/page/blame/show.rb
+++ b/qa/qa/page/blame/show.rb
@@ -5,7 +5,7 @@ module QA
module Blame
class Show < Page::Base
view 'app/views/projects/blob/_header_content.html.haml' do
- element :file_name_content
+ element 'file-name-content'
end
view 'app/views/projects/blame/show.html.haml' do
@@ -13,11 +13,11 @@ module QA
end
def has_file?(file_name)
- within_element(:file_name_content) { has_text?(file_name) }
+ within_element('file-name-content') { has_text?(file_name) }
end
def has_no_file?(file_name)
- within_element(:file_name_content) do
+ within_element('file-name-content') do
has_no_text?(file_name)
end
end
diff --git a/qa/qa/page/component/access_tokens.rb b/qa/qa/page/component/access_tokens.rb
index 6d7c36065ef..0732e0b8a89 100644
--- a/qa/qa/page/component/access_tokens.rb
+++ b/qa/qa/page/component/access_tokens.rb
@@ -75,7 +75,6 @@ module QA
def created_access_token
within_element(:access_token_section) do
- click_element(:toggle_visibility_button, wait: 30)
find_element(:created_access_token_field).value
end
end
diff --git a/qa/qa/page/component/ci_badge_link.rb b/qa/qa/page/component/ci_badge_link.rb
index 485e363d960..0fddd1cbf12 100644
--- a/qa/qa/page/component/ci_badge_link.rb
+++ b/qa/qa/page/component/ci_badge_link.rb
@@ -32,12 +32,12 @@ module QA
super
base.view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
- element :status_badge_link
+ element 'ci-badge-link'
end
end
def status_badge
- find_element(:status_badge_link).text
+ find_element('ci-badge-link').text
end
def completed?(timeout: 60)
diff --git a/qa/qa/page/component/members/invite_members_modal.rb b/qa/qa/page/component/members/invite_members_modal.rb
index 876c5ba65b6..ae51213b3e2 100644
--- a/qa/qa/page/component/members/invite_members_modal.rb
+++ b/qa/qa/page/component/members/invite_members_modal.rb
@@ -59,10 +59,6 @@ module QA
Support::WaitForRequests.wait_for_requests
- # Needed as a workaround to help avoid race condition with initial search request
- # https://gitlab.com/gitlab-org/gitlab/-/issues/349379
- sleep 2
-
search_and_select(group_name)
set_access_level(access_level)
diff --git a/qa/qa/page/component/members/members_table.rb b/qa/qa/page/component/members/members_table.rb
index 15b0f230341..5add3a0ac7d 100644
--- a/qa/qa/page/component/members/members_table.rb
+++ b/qa/qa/page/component/members/members_table.rb
@@ -35,7 +35,7 @@ module QA
end
base.view 'app/assets/javascripts/members/components/action_buttons/approve_access_request_button.vue' do
- element :approve_access_request_button
+ element 'approve-access-request-button'
end
base.view 'app/assets/javascripts/members/components/members_tabs.vue' do
@@ -69,13 +69,13 @@ module QA
def approve_access_request(username)
within_element(:member_row, text: username) do
- click_element :approve_access_request_button
+ click_element 'approve-access-request-button'
end
end
def deny_access_request(username)
within_element(:member_row, text: username) do
- click_element :delete_member_button
+ click_element 'delete-member-button'
end
confirm_remove_member
diff --git a/qa/qa/page/dashboard/todos.rb b/qa/qa/page/dashboard/todos.rb
index a65bba9ac39..74283f46928 100644
--- a/qa/qa/page/dashboard/todos.rb
+++ b/qa/qa/page/dashboard/todos.rb
@@ -8,14 +8,13 @@ module QA
view 'app/views/dashboard/todos/index.html.haml' do
element :todos_list_container, required: true
- element :group_dropdown
+ element 'group-dropdown'
end
view 'app/views/dashboard/todos/_todo.html.haml' do
- element :todo_item_container
+ element 'todo-item-container'
element :todo_action_name_content
- element :todo_target_title_content
- element :todo_author_name_content
+ element 'todo-author-name-content'
end
view 'app/helpers/dropdowns_helper.rb' do
@@ -24,15 +23,15 @@ module QA
end
def has_todo_list?
- has_element?(:todo_item_container)
+ has_element?('todo-item-container')
end
def has_no_todo_list?
- has_no_element?(:todo_item_container)
+ has_no_element?('todo-item-container')
end
def filter_todos_by_group(group)
- click_element :group_dropdown
+ click_element 'group-dropdown'
fill_element(:dropdown_input_field, group.path)
@@ -43,25 +42,20 @@ module QA
wait_for_requests
end
- def has_latest_todo_with_author?(author:, action:)
- content = { selector: :todo_author_name_content, text: author }
- has_latest_todo_with_content?(action, **content)
+ def click_todo_with_content(content)
+ click_element('todo-item-container', text: content)
end
- def has_latest_todo_with_title?(title:, action:)
- content = { selector: :todo_target_title_content, text: title }
+ def has_latest_todo_with_author?(author:, action:)
+ content = { selector: 'todo-author-name-content', text: author }
has_latest_todo_with_content?(action, **content)
end
- def click_todo_with_content(content)
- click_element(:todo_item_container, text: content)
- end
-
private
def has_latest_todo_with_content?(action, **kwargs)
within_element(:todos_list_container) do
- within_element_by_index(:todo_item_container, 0) do
+ within_element_by_index('todo-item-container', 0) do
has_element?(:todo_action_name_content, text: action) &&
has_element?(kwargs[:selector], text: kwargs[:text])
end
diff --git a/qa/qa/page/group/menu.rb b/qa/qa/page/group/menu.rb
index c8f826b20e7..e9bc1d94032 100644
--- a/qa/qa/page/group/menu.rb
+++ b/qa/qa/page/group/menu.rb
@@ -4,175 +4,14 @@ module QA
module Page
module Group
class Menu < Page::Base
- include QA::Page::SubMenus::Common
-
- if Runtime::Env.super_sidebar_enabled?
- prepend Page::SubMenus::SuperSidebar::Manage
- prepend Page::SubMenus::SuperSidebar::Plan
- prepend Page::SubMenus::SuperSidebar::Settings
- prepend SubMenus::SuperSidebar::Main
- prepend SubMenus::SuperSidebar::Build
- prepend SubMenus::SuperSidebar::Operate
- prepend SubMenus::SuperSidebar::Deploy
- end
-
- def click_group_members_item
- return go_to_members if Runtime::Env.super_sidebar_enabled?
-
- hover_group_information do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Members')
- end
- end
- end
-
- def click_subgroup_members_item
- return go_to_members if Runtime::Env.super_sidebar_enabled?
-
- hover_subgroup_information do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Members')
- end
- end
- end
-
- def click_settings
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'Settings')
- end
- end
-
- def click_group_general_settings_item
- return go_to_general_settings if Runtime::Env.super_sidebar_enabled?
-
- hover_group_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'General')
- end
- end
- end
-
- def go_to_milestones
- hover_issues do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Milestones')
- end
- end
- end
-
- def go_to_runners
- hover_group_ci_cd do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Runners')
- end
- end
- end
-
- def go_to_package_settings
- hover_group_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Packages and registries')
- end
- end
- end
-
- def go_to_group_packages
- return go_to_package_registry if Runtime::Env.super_sidebar_enabled?
-
- hover_group_packages do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Package Registry')
- end
- end
- end
-
- def go_to_group_dependency_proxy
- return go_to_dependency_proxy if Runtime::Env.super_sidebar_enabled?
-
- hover_group_packages do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Dependency Proxy')
- end
- end
- end
-
- def go_to_repository_settings
- hover_group_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Repository')
- end
- end
- end
-
- def go_to_access_token_settings
- hover_group_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Access Tokens')
- end
- end
- end
-
- private
-
- def hover_settings
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Settings')
- find_element(:sidebar_menu_link, menu_item: 'Settings').hover
-
- yield
- end
- end
-
- def hover_issues
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Issues')
- find_element(:sidebar_menu_link, menu_item: 'Issues').hover
-
- yield
- end
- end
-
- def hover_group_information
- within_sidebar do
- find_element(:sidebar_menu_link, menu_item: 'Group information').hover
-
- yield
- end
- end
-
- def hover_subgroup_information
- within_sidebar do
- find_element(:sidebar_menu_link, menu_item: 'Subgroup information').hover
-
- yield
- end
- end
-
- def hover_group_ci_cd
- within_sidebar do
- find_element(:sidebar_menu_link, menu_item: 'CI/CD').hover
-
- yield
- end
- end
-
- def hover_group_packages
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Packages and registries')
- find_element(:sidebar_menu_link, menu_item: 'Packages and registries').hover
-
- yield
- end
- end
-
- def hover_group_settings
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Settings')
- find_element(:sidebar_menu_link, menu_item: 'Settings').hover
-
- yield
- end
- end
+ include Page::SubMenus::Common
+ include Page::SubMenus::Manage
+ include Page::SubMenus::Plan
+ include Page::SubMenus::Settings
+ include SubMenus::Main
+ include SubMenus::Build
+ include SubMenus::Operate
+ include SubMenus::Deploy
end
end
end
diff --git a/qa/qa/page/group/milestone/new.rb b/qa/qa/page/group/milestone/new.rb
index 451117a2163..55b406ed477 100644
--- a/qa/qa/page/group/milestone/new.rb
+++ b/qa/qa/page/group/milestone/new.rb
@@ -7,7 +7,7 @@ module QA
class New < Page::Milestone::New
view 'app/views/groups/milestones/_form.html.haml' do
element :create_milestone_button
- element :milestone_description_field
+ element 'milestone-description-field'
element :milestone_title_field
end
@@ -16,7 +16,7 @@ module QA
end
def set_description(description)
- fill_element(:milestone_description_field, description)
+ fill_element('milestone-description-field', description)
end
def set_title(title)
diff --git a/qa/qa/page/group/runners/index.rb b/qa/qa/page/group/runners/index.rb
new file mode 100644
index 00000000000..5678f5d44dd
--- /dev/null
+++ b/qa/qa/page/group/runners/index.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module Runners
+ class Index < Page::Base
+ view "app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue" do
+ element 'new-group-runner-button'
+ end
+
+ # Returns total count of all runner types
+ #
+ # @return [Integer]
+ def count_all_runners
+ find_element("runner-count-all").text.to_i
+ end
+
+ # Returns total count of group runner types
+ #
+ # @return [Integer]
+ def count_group_runners
+ find_element("runner-count-group").text.to_i
+ end
+
+ # Returns total count of project runner types
+ #
+ # @return [Integer]
+ def count_project_runners
+ find_element("runner-count-project").text.to_i
+ end
+
+ # Returns count of online runners
+ #
+ # @return [Integer]
+ def count_online_runners
+ within_element("runner-stats-online") do
+ find_element("non-animated-value").text.to_i
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/show.rb b/qa/qa/page/group/show.rb
index 1aab6847b4c..0eaab078950 100644
--- a/qa/qa/page/group/show.rb
+++ b/qa/qa/page/group/show.rb
@@ -15,7 +15,7 @@ module QA
view 'app/views/shared/members/_access_request_links.html.haml' do
element :leave_group_link
- element :request_access_link
+ element 'request-access-link'
end
def click_subgroup(name)
@@ -49,7 +49,7 @@ module QA
end
def click_request_access
- click_element :request_access_link
+ click_element 'request-access-link'
end
end
end
diff --git a/qa/qa/page/group/sub_menus/build.rb b/qa/qa/page/group/sub_menus/build.rb
new file mode 100644
index 00000000000..c5ad6b68285
--- /dev/null
+++ b/qa/qa/page/group/sub_menus/build.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module SubMenus
+ module Build
+ extend QA::Page::PageConcern
+
+ def go_to_runners
+ open_build_submenu("Runners")
+ end
+
+ private
+
+ def open_build_submenu(sub_menu)
+ open_submenu("Build", sub_menu)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/sub_menus/deploy.rb b/qa/qa/page/group/sub_menus/deploy.rb
new file mode 100644
index 00000000000..c5a83442bb8
--- /dev/null
+++ b/qa/qa/page/group/sub_menus/deploy.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module SubMenus
+ module Deploy
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.class_eval do
+ include QA::Page::SubMenus::Deploy
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/sub_menus/main.rb b/qa/qa/page/group/sub_menus/main.rb
new file mode 100644
index 00000000000..a9f2e11c532
--- /dev/null
+++ b/qa/qa/page/group/sub_menus/main.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module SubMenus
+ module Main
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.class_eval do
+ include QA::Page::SubMenus::Main
+ end
+ end
+
+ def go_to_group_overview
+ click_element(:nav_item_link, submenu_item: 'group-overview')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/sub_menus/operate.rb b/qa/qa/page/group/sub_menus/operate.rb
new file mode 100644
index 00000000000..f491d60622a
--- /dev/null
+++ b/qa/qa/page/group/sub_menus/operate.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Group
+ module SubMenus
+ module Operate
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.class_eval do
+ include QA::Page::SubMenus::Operate
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/group/sub_menus/super_sidebar/build.rb b/qa/qa/page/group/sub_menus/super_sidebar/build.rb
deleted file mode 100644
index 0b8bf030622..00000000000
--- a/qa/qa/page/group/sub_menus/super_sidebar/build.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Group
- module SubMenus
- module SuperSidebar
- module Build
- extend QA::Page::PageConcern
-
- def go_to_runners
- open_build_submenu("Runners")
- end
-
- private
-
- def open_build_submenu(sub_menu)
- open_submenu("Build", sub_menu)
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/group/sub_menus/super_sidebar/deploy.rb b/qa/qa/page/group/sub_menus/super_sidebar/deploy.rb
deleted file mode 100644
index 4d205898bf6..00000000000
--- a/qa/qa/page/group/sub_menus/super_sidebar/deploy.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Group
- module SubMenus
- module SuperSidebar
- module Deploy
- extend QA::Page::PageConcern
-
- def self.prepended(base)
- super
-
- base.class_eval do
- include QA::Page::SubMenus::SuperSidebar::Deploy
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/group/sub_menus/super_sidebar/main.rb b/qa/qa/page/group/sub_menus/super_sidebar/main.rb
deleted file mode 100644
index 1bc6fa84935..00000000000
--- a/qa/qa/page/group/sub_menus/super_sidebar/main.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Group
- module SubMenus
- module SuperSidebar
- module Main
- extend QA::Page::PageConcern
-
- def self.prepended(base)
- super
-
- base.class_eval do
- include QA::Page::SubMenus::SuperSidebar::Main
- end
- end
-
- def go_to_group_overview
- click_element(:nav_item_link, submenu_item: 'Group overview')
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/group/sub_menus/super_sidebar/operate.rb b/qa/qa/page/group/sub_menus/super_sidebar/operate.rb
deleted file mode 100644
index 640e1e969de..00000000000
--- a/qa/qa/page/group/sub_menus/super_sidebar/operate.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Group
- module SubMenus
- module SuperSidebar
- module Operate
- extend QA::Page::PageConcern
-
- def self.prepended(base)
- super
-
- base.class_eval do
- include QA::Page::SubMenus::SuperSidebar::Operate
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/issuable/new.rb b/qa/qa/page/issuable/new.rb
index 8004875dedb..0306b246e42 100644
--- a/qa/qa/page/issuable/new.rb
+++ b/qa/qa/page/issuable/new.rb
@@ -7,11 +7,11 @@ module QA
include Page::Component::RichTextPopover
view 'app/views/shared/issuable/form/_title.html.haml' do
- element :issuable_form_title_field
+ element 'issuable-form-title-field'
end
view 'app/views/shared/form_elements/_description.html.haml' do
- element :issuable_form_description_field
+ element 'issuable-form-description-field'
end
view 'app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue' do
@@ -35,11 +35,11 @@ module QA
end
def fill_title(title)
- fill_element :issuable_form_title_field, title
+ fill_element('issuable-form-title-field', title)
end
def fill_description(description)
- fill_element :issuable_form_description_field, description
+ fill_element('issuable-form-description-field', description)
end
def choose_milestone(milestone)
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index f5bfeecec10..9bd0e52132f 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -7,57 +7,33 @@ module QA
# We need to check phone_layout? instead of mobile_layout? here
# since tablets have the regular top navigation bar
prepend Mobile::Page::Main::Menu if Runtime::Env.phone_layout?
+ include SubMenus::CreateNewMenu
+ include SubMenus::SuperSidebar::GlobalSearchModal
- if Runtime::Env.super_sidebar_enabled?
- prepend SubMenus::CreateNewMenu
- include SubMenus::SuperSidebar::ContextSwitcher
+ view 'app/assets/javascripts/super_sidebar/components/super_sidebar.vue' do
+ element :navbar, required: true # TODO: rename to sidebar once it's default implementation
end
- if QA::Runtime::Env.super_sidebar_enabled?
- # Define alternative navbar (super sidebar) which does not yet implement all the same elements
- view 'app/assets/javascripts/super_sidebar/components/super_sidebar.vue' do
- element :navbar, required: true # TODO: rename to sidebar once it's default implementation
- end
-
- view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do
- element 'user-dropdown', required: !Runtime::Env.phone_layout?
- element :user_avatar_content, required: !Runtime::Env.phone_layout?
- element :sign_out_link
- element :edit_profile_link
- end
-
- view 'app/assets/javascripts/super_sidebar/components/user_name_group.vue' do
- element :user_profile_link
- end
+ view 'app/assets/javascripts/super_sidebar/components/user_menu.vue' do
+ element 'user-dropdown', required: !Runtime::Env.phone_layout?
+ element :user_avatar_content, required: !Runtime::Env.phone_layout?
+ element :sign_out_link
+ element :edit_profile_link
+ end
- view 'app/assets/javascripts/super_sidebar/components/user_bar.vue' do
- element 'super-sidebar-search-button'
- element 'stop-impersonation-btn'
- element 'issues-shortcut-button', required: !Runtime::Env.phone_layout?
- element 'merge-requests-shortcut-button', required: !Runtime::Env.phone_layout?
- element 'todos-shortcut-button', required: !Runtime::Env.phone_layout?
- end
+ view 'app/assets/javascripts/super_sidebar/components/user_name_group.vue' do
+ element :user_profile_link
+ end
- view 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue' do
- element 'global-search-input'
- end
- else
- view 'app/views/layouts/header/_default.html.haml' do
- element :navbar, required: true
- element :canary_badge_link
- element :user_avatar_content, required: !Runtime::Env.phone_layout?
- element 'user-dropdown', required: !Runtime::Env.phone_layout?
- element 'stop-impersonation-btn'
- element 'issues-shortcut-button', required: !Runtime::Env.phone_layout?
- element 'merge-requests-shortcut-button', required: !Runtime::Env.phone_layout?
- element 'todos-shortcut-button', required: !Runtime::Env.phone_layout?
- end
+ view 'app/assets/javascripts/super_sidebar/components/user_bar.vue' do
+ element 'stop-impersonation-btn'
+ element 'issues-shortcut-button', required: !Runtime::Env.phone_layout?
+ element 'merge-requests-shortcut-button', required: !Runtime::Env.phone_layout?
+ element 'todos-shortcut-button', required: !Runtime::Env.phone_layout?
+ end
- view 'app/views/layouts/header/_current_user_dropdown.html.haml' do
- element :sign_out_link
- element :edit_profile_link
- element :user_profile_link
- end
+ view 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue' do
+ element 'global-search-input'
end
view 'app/assets/javascripts/nav/components/top_nav_app.vue' do
@@ -102,88 +78,31 @@ module QA
end
def go_to_projects
- return click_element(:nav_item_link, submenu_item: 'Projects') if Runtime::Env.super_sidebar_enabled?
-
- click_element(:sidebar_menu_link, menu_item: 'Projects')
+ click_element(:nav_item_link, submenu_item: 'Projects')
end
def go_to_groups
# This needs to be fixed in the tests themselves. Fullfillment tests try to go to groups view from the
# group. Instead of having a global hack, explicit test should navigate to correct view first.
# see: https://gitlab.com/gitlab-org/gitlab/-/issues/403589#note_1383040061
- if Runtime::Env.super_sidebar_enabled?
- go_to_your_work unless has_element?(:nav_item_link, submenu_item: 'Groups', wait: 0)
- click_element(:nav_item_link, submenu_item: 'Groups')
- elsif has_element?(:sidebar_menu_link, menu_item: 'Groups')
- # Use new functionality to visit Groups where possible
- click_element(:sidebar_menu_link, menu_item: 'Groups')
- else
- # Otherwise fallback to previous functionality
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/403589
- # and related issues
- within_groups_menu do
- click_element(:menu_item_link, title: 'View all groups')
- end
- end
+ go_to_your_work unless has_element?(:nav_item_link, submenu_item: 'Groups', wait: 0)
+ click_element(:nav_item_link, submenu_item: 'Groups')
end
def go_to_snippets
- return click_element(:nav_item_link, submenu_item: 'Snippets') if Runtime::Env.super_sidebar_enabled?
-
- click_element(:sidebar_menu_link, menu_item: 'Snippets')
+ click_element(:nav_item_link, submenu_item: 'Snippets')
end
def go_to_workspaces
- return click_element(:nav_item_link, submenu_item: 'Workspaces') if Runtime::Env.super_sidebar_enabled?
-
- click_element(:sidebar_menu_link, menu_item: 'Workspaces')
- end
-
- def go_to_create_project
- click_element('new-menu-toggle')
- click_element(:global_new_project_link)
- end
-
- def go_to_create_group
- click_element('new-menu-toggle')
- click_element(:global_new_group_link)
- end
-
- def go_to_create_snippet
- click_element('new-menu-toggle')
- click_element(:global_new_snippet_link)
+ click_element(:nav_item_link, submenu_item: 'Workspaces')
end
def go_to_menu_dropdown_option(option_name)
- return click_element(option_name) if QA::Runtime::Env.super_sidebar_enabled?
-
- within_top_menu do
- click_element(:navbar_dropdown, title: 'Menu')
- click_element(option_name)
- end
+ click_element(option_name)
end
- # To go to one of the popular pages using the provided shortcut buttons within top menu
- # @param [Symbol] the name of the element (e.g: `:issues_shortcut button`)
- # @example:
- # Menu.perform do |menu|
- # menu.go_to_page_by_shortcut('issues-shortcut-button') #=> Go to Issues page using shortcut button
- # end
- def go_to_page_by_shortcut(button)
- within_top_menu do
- click_element(button)
- end
- end
-
- def go_to_admin_area
- Runtime::Env.super_sidebar_enabled? ? super : click_admin_area
-
- return unless has_text?('Enter admin mode', wait: 1.0)
-
- Admin::NewSession.perform do |new_session|
- new_session.set_password(Runtime::User.admin_password)
- new_session.click_enter_admin_mode
- end
+ def go_to_todos
+ click_element('todos-shortcut-button')
end
def signed_in?
@@ -209,6 +128,8 @@ module QA
end
def sign_out
+ close_global_search_modal_if_shown
+
retry_until do
wait_if_retry_later
@@ -242,11 +163,6 @@ module QA
end
end
- def search_for(term)
- click_element(Runtime::Env.super_sidebar_enabled? ? 'super-sidebar-search-button' : :search_box)
- fill_element('global-search-input', "#{term}\n")
- end
-
def has_personal_area?(wait: Capybara.default_max_wait_time)
has_element?(:user_avatar_content, wait: wait)
end
@@ -255,15 +171,6 @@ module QA
has_no_element?(:user_avatar_content, wait: wait)
end
- def has_admin_area_link?(wait: Capybara.default_max_wait_time)
- return super if Runtime::Env.super_sidebar_enabled?
-
- within_top_menu do
- click_element(:navbar_dropdown, title: 'Menu')
- has_element?(:admin_area_link, wait: wait)
- end
- end
-
def click_stop_impersonation_link
click_element('stop-impersonation-btn')
end
@@ -278,55 +185,15 @@ module QA
has_element?(:canary_badge_link)
end
- def enable_new_navigation
- Runtime::Logger.info("Enabling super sidebar!")
- return Runtime::Logger.info("User is not signed in, skipping") unless has_element?(:navbar, wait: 2)
-
- return Runtime::Logger.info("Super sidebar is already enabled") if has_css?('[data-testid="super-sidebar"]')
-
- within_user_menu { click_element(:new_navigation_toggle) }
- end
-
- def disable_new_navigation
- Runtime::Logger.info("Disabling super sidebar!")
- return Runtime::Logger.info("User is not signed in, skipping") unless has_element?(:navbar, wait: 2)
-
- unless has_css?('[data-testid="super-sidebar"]')
- return Runtime::Logger.info("Super sidebar is already disabled")
- end
-
- within_user_menu { click_element(:new_navigation_toggle) }
- end
-
private
- def within_top_menu(&block)
- within_element(:navbar, &block)
- end
-
def within_user_menu(&block)
- within_top_menu do
+ within_element(:navbar) do
click_element :user_avatar_content unless has_element?(:user_profile_link, wait: 1)
within_element('user-dropdown', &block)
end
end
-
- def within_groups_menu(&block)
- go_to_menu_dropdown_option(:groups_dropdown)
-
- within_element('menu-subview', &block)
- end
-
- def within_projects_menu(&block)
- go_to_menu_dropdown_option(:projects_dropdown)
-
- within_element('menu-subview', &block)
- end
-
- def click_admin_area
- go_to_menu_dropdown_option(:admin_area_link)
- end
end
end
end
diff --git a/qa/qa/page/merge_request/new.rb b/qa/qa/page/merge_request/new.rb
index 90022616674..6a59440fc28 100644
--- a/qa/qa/page/merge_request/new.rb
+++ b/qa/qa/page/merge_request/new.rb
@@ -7,23 +7,23 @@ module QA
include QA::Page::Component::Dropdown
view 'app/views/shared/issuable/_form.html.haml' do
- element :issuable_create_button, required: true
+ element 'issuable-create-button', required: true
end
view 'app/views/projects/merge_requests/creations/_new_compare.html.haml' do
- element :compare_branches_button
+ element 'compare-branches-button'
end
view 'app/assets/javascripts/merge_requests/components/compare_dropdown.vue' do
- element :source_branch_dropdown, ':data-qa-selector="qaSelector"' # rubocop:disable QA/ElementWithPattern
+ element 'source-branch-dropdown', ':data-testid="testid"' # rubocop:disable QA/ElementWithPattern
end
- view 'app/views/projects/merge_requests/_page.html.haml' do
- element :diffs_tab
+ view 'app/views/projects/merge_requests/creations/_new_submit.html.haml' do
+ element 'diffs-tab'
end
view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do
- element :file_name_content
+ element 'file-name-content'
end
def has_secure_description?(scanner_name)
@@ -34,23 +34,23 @@ module QA
end
def click_compare_branches_and_continue
- click_element(:compare_branches_button)
+ click_element('compare-branches-button')
end
def create_merge_request
- click_element(:issuable_create_button, Page::MergeRequest::Show)
+ click_element('issuable-create-button', Page::MergeRequest::Show)
end
def click_diffs_tab
- click_element(:diffs_tab)
+ click_element('diffs-tab')
end
def has_file?(file_name)
- has_element?(:file_name_content, text: file_name)
+ has_element?('file-name-content', text: file_name)
end
def select_source_branch(branch)
- click_element(:source_branch_dropdown)
+ click_element('source-branch-dropdown')
search_and_select(branch)
end
end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 2ff6460b1c8..80541bd9283 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -36,12 +36,15 @@ module QA
end
view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do
- element :file_name_content
element :file_title_container
element :dropdown_button
element :edit_in_ide_button
end
+ view 'app/assets/javascripts/vue_shared/components/file_row.vue' do
+ element 'file-row-name-container'
+ end
+
view 'app/assets/javascripts/diffs/components/diff_row.vue' do
element :diff_comment_button
element :new_diff_line_link
@@ -53,10 +56,10 @@ module QA
end
view 'app/views/projects/merge_requests/_code_dropdown.html.haml' do
- element :mr_code_dropdown
- element :download_email_patches_menu_item
- element :download_plain_diff_menu_item
- element :open_in_web_ide_button
+ element 'mr-code-dropdown'
+ element 'download-email-patches-menu-item'
+ element 'download-plain-diff-menu-item'
+ element 'open-in-web-ide-button'
end
view 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue' do
@@ -124,9 +127,9 @@ module QA
end
view 'app/views/projects/merge_requests/_page.html.haml' do
- element :notes_tab, required: true
- element :commits_tab, required: true
- element :diffs_tab, required: true
+ element 'notes-tab', required: true
+ element 'commits-tab', required: true
+ element 'diffs-tab', required: true
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue' do
@@ -138,6 +141,10 @@ module QA
element :close_button
end
+ view 'app/assets/javascripts/ci/jobs_page/components/job_cells/job_cell.vue' do
+ element 'fork-icon'
+ end
+
def start_review
click_element(:start_review_button)
@@ -190,18 +197,18 @@ module QA
end
def click_discussions_tab
- click_element(:notes_tab)
+ click_element('notes-tab')
wait_for_requests
end
def click_commits_tab
- click_element(:commits_tab)
+ click_element('commits-tab')
end
def click_diffs_tab
# Do not wait for spinner due to https://gitlab.com/gitlab-org/gitlab/-/issues/398584
- click_element(:diffs_tab, skip_finished_loading_check: true)
+ click_element('diffs-tab', skip_finished_loading_check: true)
end
def click_pipeline_link
@@ -222,17 +229,17 @@ module QA
def has_file?(file_name)
open_file_tree
- return true if has_element?(:file_name_content, file_name: file_name)
+ return true if has_element?('file-row-name-container', file_name: file_name)
# Since the file tree uses virtual scrolling, search for file in case it is outside of viewport
search_file_tree(file_name)
- has_element?(:file_name_content, file_name: file_name)
+ has_element?('file-row-name-container', file_name: file_name)
end
def has_no_file?(file_name)
# Since the file tree uses virtual scrolling, search for file to ensure non-existence
search_file_tree(file_name)
- has_no_element?(:file_name_content, file_name: file_name)
+ has_no_element?('file-row-name-container', file_name: file_name)
end
def search_file_tree(file_name)
@@ -277,6 +284,11 @@ module QA
end
def mark_to_squash
+ # Refresh page if commit arrived after loading the MR page
+ wait_until(reload: true, message: 'Wait for MR to be unblocked') do
+ has_no_element?(:head_mismatch_content, wait: 1)
+ end
+
# The squash checkbox is enabled via JS
wait_until(reload: false) do
!find_element(:squash_checkbox, visible: false).disabled?
@@ -395,16 +407,16 @@ module QA
# Click by JS is needed to bypass the Moved MR actions popover
# Change back to regular click_element when moved_mr_sidebar FF is removed
# Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/385460
- click_by_javascript(find_element(:mr_code_dropdown))
- visit_link_in_element(:download_email_patches_menu_item)
+ click_by_javascript(find_element('mr-code-dropdown'))
+ visit_link_in_element('download-email-patches-menu-item')
end
def view_plain_diff
# Click by JS is needed to bypass the Moved MR actions popover
# Change back to regular click_element when moved_mr_sidebar FF is removed
# Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/385460
- click_by_javascript(find_element(:mr_code_dropdown))
- visit_link_in_element(:download_plain_diff_menu_item)
+ click_by_javascript(find_element('mr-code-dropdown'))
+ visit_link_in_element('download-plain-diff-menu-item')
end
def wait_for_merge_request_error_message
@@ -417,8 +429,8 @@ module QA
# Click by JS is needed to bypass the Moved MR actions popover
# Change back to regular click_element when moved_mr_sidebar FF is removed
# Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/385460
- click_by_javascript(find_element(:mr_code_dropdown))
- click_element(:open_in_web_ide_button)
+ click_by_javascript(find_element('mr-code-dropdown'))
+ click_element('open-in-web-ide-button')
page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
wait_for_requests
end
@@ -476,6 +488,10 @@ module QA
def mr_widget_text
find_element(:mr_widget_content).text
end
+
+ def has_fork_icon?
+ has_element?('fork-icon', skip_finished_loading_check: true)
+ end
end
end
end
diff --git a/qa/qa/page/profile/menu.rb b/qa/qa/page/profile/menu.rb
index f9493dbefcc..d3b08944914 100644
--- a/qa/qa/page/profile/menu.rb
+++ b/qa/qa/page/profile/menu.rb
@@ -4,64 +4,26 @@ module QA
module Page
module Profile
class Menu < Page::Base
- prepend QA::Mobile::Page::SubMenus::Common if QA::Runtime::Env.mobile_layout?
- # TODO: integrate back once super sidebar becomes default
- prepend QA::Page::Profile::SuperSidebar::Menu if QA::Runtime::Env.super_sidebar_enabled?
-
- view 'lib/sidebars/user_settings/menus/access_tokens_menu.rb' do
- element :access_token_link
- end
-
- view 'lib/sidebars/user_settings/menus/ssh_keys_menu.rb' do
- element :ssh_keys_link
- end
-
- view 'lib/sidebars/user_settings/menus/emails_menu.rb' do
- element :profile_emails_link
- end
-
- view 'lib/sidebars/user_settings/menus/password_menu.rb' do
- element :profile_password_link
- end
-
- view 'lib/sidebars/user_settings/menus/account_menu.rb' do
- element :profile_account_link
- end
-
- def click_access_tokens
- within_sidebar do
- click_element(:access_token_link)
- end
- end
+ include SubMenus::CreateNewMenu
def click_ssh_keys
- within_sidebar do
- click_element(:ssh_keys_link)
- end
+ click_element(:nav_item_link, submenu_item: 'SSH Keys')
end
def click_account
- within_sidebar do
- click_element(:profile_account_link)
- end
+ click_element(:nav_item_link, submenu_item: 'Account')
end
def click_emails
- within_sidebar do
- click_element(:profile_emails_link)
- end
+ click_element(:nav_item_link, submenu_item: 'Emails')
end
def click_password
- within_sidebar do
- click_element(:profile_password_link)
- end
+ click_element(:nav_item_link, submenu_item: 'Password')
end
- private
-
- def within_sidebar(&block)
- page.within('.sidebar-top-level-items', &block)
+ def click_access_tokens
+ click_element(:nav_item_link, submenu_item: 'Access Tokens')
end
end
end
diff --git a/qa/qa/page/profile/super_sidebar/menu.rb b/qa/qa/page/profile/super_sidebar/menu.rb
deleted file mode 100644
index ade9c47313d..00000000000
--- a/qa/qa/page/profile/super_sidebar/menu.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Profile
- module SuperSidebar
- module Menu
- def click_ssh_keys
- click_element(:nav_item_link, submenu_item: 'SSH Keys')
- end
-
- def click_account
- click_element(:nav_item_link, submenu_item: 'Account')
- end
-
- def click_emails
- click_element(:nav_item_link, submenu_item: 'Emails')
- end
-
- def click_password
- click_element(:nav_item_link, submenu_item: 'Password')
- end
-
- def click_access_tokens
- click_element(:nav_item_link, submenu_item: 'Access Tokens')
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/artifact/show.rb b/qa/qa/page/project/artifact/show.rb
index 5e05eec79f0..42de1bb273f 100644
--- a/qa/qa/page/project/artifact/show.rb
+++ b/qa/qa/page/project/artifact/show.rb
@@ -6,12 +6,12 @@ module QA
module Artifact
class Show < QA::Page::Base
view 'app/views/projects/artifacts/_tree_directory.html.haml' do
- element :directory_name_link
+ element 'directory-name-link'
end
def go_to_directory(name, retry_attempts = 1)
retry_on_exception(max_attempts: retry_attempts, reload: true, sleep_interval: 10) do
- click_element(:directory_name_link, directory_name: name)
+ click_element('directory-name-link', directory_name: name)
end
end
end
diff --git a/qa/qa/page/project/issue/index.rb b/qa/qa/page/project/issue/index.rb
index a4f4f6e3cf1..f3ec160d26e 100644
--- a/qa/qa/page/project/issue/index.rb
+++ b/qa/qa/page/project/issue/index.rb
@@ -6,38 +6,39 @@ module QA
module Issue
class Index < Page::Base
view 'app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue' do
- element :issuable_container
- element :issuable_search_container
+ element 'issuable-container'
+ element 'issuable-search-container'
end
view 'app/assets/javascripts/issuable/components/issue_assignees.vue' do
- element :assignee_link
- element :avatar_counter_content
+ element 'assignee-link'
+ element 'avatar-counter-content'
end
view 'app/assets/javascripts/issuable/components/csv_export_modal.vue' do
- element :export_issuable_modal
+ element 'export-issuable-modal'
+ element 'export-issues-button'
end
view 'app/assets/javascripts/issuable/components/csv_import_export_buttons.vue' do
- element :export_as_csv_button
- element :import_from_jira_link
+ element 'export-as-csv-button'
+ element 'import-from-jira-link'
end
view 'app/assets/javascripts/issues/list/components/issues_list_app.vue' do
- element :issues_list_more_actions_dropdown
+ element 'issues-list-more-actions-dropdown'
end
view 'app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue' do
- element :import_issues_dropdown
+ element 'import-issues-dropdown'
end
view 'app/assets/javascripts/vue_shared/issuable/list/components/issuable_tabs.vue' do
- element :closed_issuables_tab, ':data-qa-selector="`${tab.name}_issuables_tab`"' # rubocop:disable QA/ElementWithPattern
+ element 'closed-issuables-tab', ':data-testid="`${tab.name}-issuables-tab`"' # rubocop:disable QA/ElementWithPattern
end
def avatar_counter
- find_element(:avatar_counter_content)
+ find_element('avatar-counter-content')
end
def click_issue_link(title)
@@ -45,33 +46,33 @@ module QA
end
def click_closed_issues_tab
- click_element(:closed_issuables_tab)
+ click_element('closed-issuables-tab')
end
def click_export_as_csv_button
- click_element(:export_as_csv_button)
+ click_element('export-as-csv-button')
end
def click_export_issues_button
- click_element(:export_issues_button)
+ click_element('export-issues-button')
end
def click_import_from_jira_link
- click_element(:import_from_jira_link)
+ click_element('import-from-jira-link')
end
def click_import_issues_dropdown
# When there are no issues, the image that loads causes the buttons to jump
has_loaded_all_images?
- click_element(:import_issues_dropdown)
+ click_element('import-issues-dropdown')
end
def click_issues_list_more_actions_dropdown
- click_element(:issues_list_more_actions_dropdown)
+ click_element('issues-list-more-actions-dropdown')
end
def export_issues_modal
- find_element(:export_issuable_modal)
+ find_element('export-issuable-modal')
end
def go_to_jira_import_form
@@ -80,15 +81,15 @@ module QA
end
def has_assignee_link_count?(count)
- all_elements(:assignee_link, count: count)
+ all_elements('assignee-link', count: count)
end
def has_issue?(issue)
- has_element? :issuable_container, issuable_title: issue.title
+ has_element? 'issuable-container', issuable_title: issue.title
end
def has_no_issue?(issue)
- has_no_element? :issuable_container, issuable_title: issue.title
+ has_no_element? 'issuable-container', issuable_title: issue.title
end
end
end
diff --git a/qa/qa/page/project/issue/jira_import.rb b/qa/qa/page/project/issue/jira_import.rb
index d3be24464ab..365d5a62b2c 100644
--- a/qa/qa/page/project/issue/jira_import.rb
+++ b/qa/qa/page/project/issue/jira_import.rb
@@ -6,17 +6,17 @@ module QA
module Issue
class JiraImport < Page::Base
view 'app/assets/javascripts/jira_import/components/jira_import_form.vue' do
- element :jira_project_dropdown
- element :jira_issues_import_button
+ element 'jira-project-dropdown'
+ element 'jira-issues-import-button'
end
def select_jira_project(jira_project)
- select_element(:jira_project_dropdown, jira_project)
+ select_element('jira-project-dropdown', jira_project)
end
def select_project_and_import(jira_project)
select_jira_project(jira_project)
- click_element(:jira_issues_import_button)
+ click_element('jira-issues-import-button')
end
end
end
diff --git a/qa/qa/page/project/issue/new.rb b/qa/qa/page/project/issue/new.rb
index 7f52cda7c15..e7347179cff 100644
--- a/qa/qa/page/project/issue/new.rb
+++ b/qa/qa/page/project/issue/new.rb
@@ -6,11 +6,11 @@ module QA
module Issue
class New < Page::Issuable::New
view 'app/views/shared/issuable/_form.html.haml' do
- element :issuable_create_button
+ element 'issuable-create-button'
end
def create_new_issue
- click_element :issuable_create_button, Page::Project::Issue::Show
+ click_element('issuable-create-button', Page::Project::Issue::Show)
end
end
end
diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb
index 41a2986e300..c2c1f6e4b79 100644
--- a/qa/qa/page/project/job/show.rb
+++ b/qa/qa/page/project/job/show.rb
@@ -7,27 +7,28 @@ module QA
class Show < QA::Page::Base
include Component::CiBadgeLink
- view 'app/assets/javascripts/jobs/components/log/log.vue' do
- element :job_log_content
+ view 'app/assets/javascripts/ci/job_details/components/log/log.vue' do
+ element 'job-log-content'
end
- view 'app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue' do
- element :pipeline_path, required: true
+ view 'app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue' do
+ element 'pipeline-path', required: true
end
- view 'app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue' do
- element :retry_button
+ view 'app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue' do
+ element 'retry-button'
end
- view 'app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue' do
- element :browse_artifacts_button
+ view 'app/assets/javascripts/ci/job_details/components/sidebar/artifacts_block.vue' do
+ element 'browse-artifacts-button'
+ element 'artifacts-unlocked-message-content'
+ element 'artifacts-locked-message-content'
end
def successful?(timeout: 60)
raise "Timed out waiting for the build trace to load" unless loaded?
raise "Timed out waiting for the status to be a valid completed state" unless completed?(timeout: timeout)
- job_log = find_element(:job_log_content).text
QA::Runtime::Logger.debug(" \n\n ------- Job log: ------- \n\n #{job_log} \n -------")
passed?
@@ -38,28 +39,27 @@ module QA
result = ''
wait_until(reload: false, max_duration: wait, sleep_interval: 1) do
- result = find_element(:job_log_content).text
-
- result.include?('Job')
+ result = job_log.include?('Job') ? job_log : ''
+ result.present?
end
result
end
def has_browse_button?
- has_element? :browse_artifacts_button
+ has_element?('browse-artifacts-button')
end
def click_browse_button
- click_element :browse_artifacts_button
+ click_element('browse-artifacts-button')
end
def retry!
- click_element :retry_button
+ click_element 'retry-button'
end
- def has_job_log?
- has_element? :job_log_content
+ def has_job_log?(wait: 1)
+ has_element?('job-log-content', wait: wait)
end
def has_status?(status, wait: 30)
@@ -69,20 +69,28 @@ module QA
end
def has_locked_artifact?
- has_element? :artifacts_locked_message_content
+ has_element?('artifacts-locked-message-content')
end
def has_unlocked_artifact?
- has_element? :artifacts_unlocked_message_content
+ has_element?('artifacts-unlocked-message-content')
+ end
+
+ def go_to_pipeline
+ click_element('pipeline-path')
end
private
def loaded?(wait: 60)
wait_until(reload: true, max_duration: wait, sleep_interval: 1) do
- has_element?(:job_log_content, wait: 1)
+ has_job_log?
end
end
+
+ def job_log
+ find_element('job-log-content').text
+ end
end
end
end
diff --git a/qa/qa/page/project/menu.rb b/qa/qa/page/project/menu.rb
index 534a4da8426..5d69909a323 100644
--- a/qa/qa/page/project/menu.rb
+++ b/qa/qa/page/project/menu.rb
@@ -5,83 +5,16 @@ module QA
module Project
class Menu < Page::Base
include SubMenus::Common
- include SubMenus::Project
- include SubMenus::CiCd
- include SubMenus::Issues
- include SubMenus::Deployments
- include SubMenus::Monitor
- include SubMenus::Infrastructure
- include SubMenus::Repository
- include SubMenus::Settings
- include SubMenus::Packages
include SubMenus::CreateNewMenu
-
- if Runtime::Env.super_sidebar_enabled?
- include Page::SubMenus::SuperSidebar::Manage
- include Page::SubMenus::SuperSidebar::Deploy
- include SubMenus::SuperSidebar::Plan
- include SubMenus::SuperSidebar::Settings
- include SubMenus::SuperSidebar::Code
- include SubMenus::SuperSidebar::Build
- include SubMenus::SuperSidebar::Operate
- include SubMenus::SuperSidebar::Monitor
- include SubMenus::SuperSidebar::Main
- end
-
- def click_merge_requests
- return go_to_merge_requests if Runtime::Env.super_sidebar_enabled?
-
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'Merge requests')
- end
- end
-
- def click_wiki
- return go_to_wiki if Runtime::Env.super_sidebar_enabled?
-
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'Wiki')
- end
- end
-
- def click_activity
- return go_to_activity if Runtime::Env.super_sidebar_enabled?
-
- hover_project_information do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Activity')
- end
- end
- end
-
- def click_snippets
- return go_to_snippets if Runtime::Env.super_sidebar_enabled?
-
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'Snippets')
- end
- end
-
- def click_members
- return go_to_members if Runtime::Env.super_sidebar_enabled?
-
- hover_project_information do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Members')
- end
- end
- end
-
- private
-
- def hover_project_information
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Project information')
- find_element(:sidebar_menu_link, menu_item: 'Project information').hover
-
- yield
- end
- end
+ include SubMenus::Plan
+ include SubMenus::Settings
+ include SubMenus::Code
+ include SubMenus::Build
+ include SubMenus::Operate
+ include SubMenus::Monitor
+ include SubMenus::Main
+ include Page::SubMenus::Manage
+ include Page::SubMenus::Deploy
end
end
end
diff --git a/qa/qa/page/project/milestone/new.rb b/qa/qa/page/project/milestone/new.rb
index 98f3a0ef4ab..4df4988e056 100644
--- a/qa/qa/page/project/milestone/new.rb
+++ b/qa/qa/page/project/milestone/new.rb
@@ -7,7 +7,7 @@ module QA
class New < Page::Milestone::New
view 'app/views/projects/milestones/_form.html.haml' do
element :create_milestone_button
- element :milestone_description_field
+ element 'milestone-description-field'
element :milestone_title_field
end
@@ -25,7 +25,7 @@ module QA
end
def set_description(description)
- fill_element :milestone_description_field, description
+ fill_element('milestone-description-field', description)
end
def set_due_date(due_date)
diff --git a/qa/qa/page/project/monitor/alerts/index.rb b/qa/qa/page/project/monitor/alerts/index.rb
index 1738ce170f2..3e4745a0f2f 100644
--- a/qa/qa/page/project/monitor/alerts/index.rb
+++ b/qa/qa/page/project/monitor/alerts/index.rb
@@ -7,7 +7,7 @@ module QA
module Alerts
class Index < Page::Base
view 'app/assets/javascripts/alert_management/components/alert_management_table.vue' do
- element :alert_table_container, required: true
+ element 'alert-table-container', required: true
end
def has_alert_with_title?(title)
diff --git a/qa/qa/page/project/monitor/incidents/index.rb b/qa/qa/page/project/monitor/incidents/index.rb
index 04cb23da389..c192670205d 100644
--- a/qa/qa/page/project/monitor/incidents/index.rb
+++ b/qa/qa/page/project/monitor/incidents/index.rb
@@ -7,20 +7,20 @@ module QA
module Incidents
class Index < Page::Base
view 'app/assets/javascripts/incidents/components/incidents_list.vue' do
- element :create_incident_button
- element :incident_link
+ element 'create-incident-button'
+ element 'incident-link'
end
def create_incident
- click_element :create_incident_button
+ click_element 'create-incident-button'
end
def has_incident?(wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME, title: nil)
- wait_until(max_duration: wait) { has_element?(:incident_link, text: title) }
+ wait_until(max_duration: wait) { has_element?('incident-link', text: title) }
end
def has_no_incident?(title: nil)
- has_no_element?(:incident_link, text: title)
+ has_no_element?('incident-link', text: title)
end
def go_to_tab(tab)
diff --git a/qa/qa/page/project/pipeline/index.rb b/qa/qa/page/project/pipeline/index.rb
index 70ac35eeffe..a1086794b1f 100644
--- a/qa/qa/page/project/pipeline/index.rb
+++ b/qa/qa/page/project/pipeline/index.rb
@@ -5,23 +5,23 @@ module QA
module Project
module Pipeline
class Index < QA::Page::Base
- view 'app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue' do
+ view 'app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue' do
element :pipeline_url_link
end
- view 'app/assets/javascripts/pipelines/components/pipelines_list/pipelines_status_badge.vue' do
+ view 'app/assets/javascripts/ci/pipelines_page/components/pipelines_status_badge.vue' do
element :pipeline_commit_status
end
- view 'app/assets/javascripts/pipelines/components/pipelines_list/pipeline_operations.vue' do
+ view 'app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue' do
element :pipeline_retry_button
end
- view 'app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue' do
+ view 'app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue' do
element :run_pipeline_button
end
- view 'app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue' do
+ view 'app/assets/javascripts/ci/common/pipelines_table.vue' do
element :pipeline_row_container
end
@@ -38,14 +38,16 @@ module QA
wait ||= Support::Repeater::DEFAULT_MAX_WAIT_TIME
finished_status = %w[passed failed canceled skipped manual]
- wait_until(max_duration: wait, reload: reload, sleep_interval: 1) do
+ wait_until(max_duration: wait, reload: reload, sleep_interval: 1, message: "Wait for latest pipeline") do
status ? latest_pipeline_status == status : finished_status.include?(latest_pipeline_status)
end
end
def has_any_pipeline?(wait: nil)
wait ||= Support::Repeater::DEFAULT_MAX_WAIT_TIME
- wait_until(max_duration: wait) { has_element?(:pipeline_row_container) }
+ wait_until(max_duration: wait, message: "Wait for any pipeline") do
+ has_element?(:pipeline_row_container)
+ end
end
def has_no_pipeline?
diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb
index c955b4d933d..db678ab1285 100644
--- a/qa/qa/page/project/pipeline/show.rb
+++ b/qa/qa/page/project/pipeline/show.rb
@@ -7,21 +7,21 @@ module QA
class Show < QA::Page::Base
include Component::CiBadgeLink
- view 'app/assets/javascripts/pipelines/components/pipeline_details_header.vue' do
+ view 'app/assets/javascripts/ci/pipeline_details/header/pipeline_details_header.vue' do
element :pipeline_details_header, required: true
end
- view 'app/assets/javascripts/pipelines/components/graph/graph_component.vue' do
+ view 'app/assets/javascripts/ci/pipeline_details/graph/components/graph_component.vue' do
element :pipeline_graph, /class.*pipeline-graph.*/ # rubocop:disable QA/ElementWithPattern
end
- view 'app/assets/javascripts/pipelines/components/graph/job_item.vue' do
+ view 'app/assets/javascripts/ci/pipeline_details/graph/components/job_item.vue' do
element :job_item_container, required: true
element :job_link, required: true
element :job_action_button
end
- view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
+ view 'app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipeline.vue' do
element :expand_linked_pipeline_button
element :linked_pipeline_container
element :downstream_title_content
@@ -35,7 +35,7 @@ module QA
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end
- view 'app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue' do
+ view 'app/assets/javascripts/ci/pipeline_details/graph/components/job_group_dropdown.vue' do
element :job_dropdown_container
element :jobs_dropdown_menu
end
@@ -149,6 +149,14 @@ module QA
end
end
end
+
+ def has_no_skipped_job_in_group?
+ within_element(:jobs_dropdown_menu) do
+ all_elements(:job_item_container, minimum: 1).all? do
+ has_no_selector?('.ci-status-icon-skipped')
+ end
+ end
+ end
end
end
end
diff --git a/qa/qa/page/project/pipeline_editor/new.rb b/qa/qa/page/project/pipeline_editor/new.rb
deleted file mode 100644
index da3e772b11f..00000000000
--- a/qa/qa/page/project/pipeline_editor/new.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module PipelineEditor
- class New < QA::Page::Base
- view 'app/assets/javascripts/ci/pipeline_editor/components/ui/pipeline_editor_empty_state.vue' do
- element :create_new_ci_button, required: true
- end
-
- def create_new_ci
- click_element(:create_new_ci_button, Page::Project::PipelineEditor::Show)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/pipeline_editor/show.rb b/qa/qa/page/project/pipeline_editor/show.rb
index c70b6e76cfe..41d094d7742 100644
--- a/qa/qa/page/project/pipeline_editor/show.rb
+++ b/qa/qa/page/project/pipeline_editor/show.rb
@@ -5,55 +5,18 @@ module QA
module Project
module PipelineEditor
class Show < QA::Page::Base
- view 'app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue' do
- element :pipeline_editor_app, required: true
- end
-
- view 'app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue' do
- element :branch_selector_button, required: true
- end
-
- view 'app/assets/javascripts/ci/pipeline_editor/components/commit/commit_form.vue' do
- element :source_branch_field, required: true
- end
-
- view 'app/assets/javascripts/ci/pipeline_editor/components/editor/ci_editor_header.vue' do
- element :drawer_toggle, required: true
- element :template_repo_link, required: true
- end
-
view 'app/assets/javascripts/vue_shared/components/source_editor.vue' do
- element :source_editor_container, required: true
- end
-
- view 'app/assets/javascripts/ci/pipeline_editor/components/header/pipeline_status.vue' do
- element :pipeline_id_content
+ element 'source-editor-container', required: true
end
view 'app/assets/javascripts/ci/pipeline_editor/components/commit/commit_form.vue' do
- element :commit_changes_button
- element :new_mr_checkbox
- end
-
- view 'app/assets/javascripts/ci/pipeline_editor/components/header/validation_segment.vue' do
- element :validation_message_content
- end
-
- view 'app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue' do
- element :stage_container
- element :job_container
+ element 'source-branch-field', required: true
+ element 'commit-changes-button'
+ element 'new-mr-checkbox'
end
view 'app/assets/javascripts/ci/pipeline_editor/components/pipeline_editor_tabs.vue' do
- element :file_editor_container
- end
-
- view 'app/assets/javascripts/ci/pipeline_editor/components/popovers/file_tree_popover.vue' do
- element :file_tree_popover
- end
-
- view 'app/assets/javascripts/ci/pipeline_editor/components/validate/ci_validate.vue' do
- element :simulate_pipeline_button
+ element 'file-editor-container', required: true
end
def initialize
@@ -65,115 +28,31 @@ module QA
def dismiss_file_tree_popover
# clicking outside the popover will dismiss it
- click_element(:pipeline_editor_app)
- end
-
- def source_branch_name
- find_element(:source_branch_field).value
- end
-
- def editing_content
- find_element(:source_editor_container).text
+ click_element('source-editor-container')
end
def write_to_editor(text)
- find_element(:source_editor_container).fill_in(with: text)
+ find_element('source-editor-container').fill_in(with: text)
wait_for_requests
end
def submit_changes
- wait_until(reload: false) { !find_element(:commit_changes_button).disabled? }
- click_element(:commit_changes_button)
+ wait_until(reload: false) { !find_element('commit-changes-button').disabled? }
+ click_element('commit-changes-button')
wait_for_requests
end
def set_source_branch(name)
- find_element(:source_branch_field).fill_in(with: name)
- end
-
- def current_branch
- find_element(:branch_selector_button).text
- end
-
- def pipeline_id
- find_element(:pipeline_id_content).text.delete!('#').to_i
- end
-
- def ci_syntax_validate_message
- find_element(:validation_message_content).text
- end
-
- def go_to_visualize_tab
- go_to_tab('Visualize')
- end
-
- def go_to_full_configuration_tab
- go_to_tab('Full configuration')
- end
-
- def go_to_validate_tab
- go_to_tab('Validate')
- end
-
- def has_source_editor?
- has_element?(:source_editor_container)
- end
-
- def has_stage?(name)
- all_elements(:stage_container, minimum: 1).any? { |item| item.text.match(/#{name}/i) }
- end
-
- def has_job?(name)
- all_elements(:job_container, minimum: 1).any? { |item| item.text.match(/#{name}/i) }
- end
-
- def has_no_alert?
- has_no_css?('.gl-alert-body')
- end
-
- def tab_alert_message
- within_element(:file_editor_container) do
- find('.gl-alert-body').text
- end
- end
-
- def tab_alert_title
- within_element(:file_editor_container) do
- find('.gl-alert-title').text
- end
- end
-
- def has_new_mr_checkbox?
- has_element?(:new_mr_checkbox, visible: true)
- end
-
- def has_no_new_mr_checkbox?
- has_no_element?(:new_mr_checkbox, visible: true)
+ find_element('source-branch-field').fill_in(with: name)
end
def select_new_mr_checkbox
- check_element(:new_mr_checkbox, true)
- end
-
- def simulate_pipeline
- click_element(:simulate_pipeline_button)
- end
-
- private
-
- def go_to_tab(name)
- within_element(:file_editor_container) do
- find('.nav-item', text: name).click
- end
-
- wait_for_requests
+ check_element('new-mr-checkbox', true)
end
end
end
end
end
end
-
-QA::Page::Project::PipelineEditor::Show.prepend_mod_with('Page::Project::PipelineEditor::Show', namespace: QA)
diff --git a/qa/qa/page/project/settings/alerts.rb b/qa/qa/page/project/settings/alerts.rb
index 2646e271bd2..988006b8ad3 100644
--- a/qa/qa/page/project/settings/alerts.rb
+++ b/qa/qa/page/project/settings/alerts.rb
@@ -8,23 +8,23 @@ module QA
include ::QA::Page::Component::Dropdown
view 'app/assets/javascripts/alerts_settings/components/alerts_form.vue' do
- element :create_incident_checkbox
- element :incident_templates_dropdown
- element :save_changes_button
- element :enable_email_notification_checkbox
+ element 'create-incident-checkbox'
+ element 'incident-templates-dropdown'
+ element 'save-changes-button'
+ element 'enable-email-notification-checkbox'
end
view 'app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue' do
- element :add_integration_button
+ element 'add-integration-button'
end
view 'app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue' do
- element :integration_type_dropdown
- element :integration_name_field
- element :active_toggle_container
- element :save_and_create_alert_button
- element :test_payload_field
- element :send_test_alert_button
+ element 'integration-type-dropdown'
+ element 'integration-name-field'
+ element 'active-toggle-container'
+ element 'save-and-create-alert-button'
+ element 'test-payload-field'
+ element 'send-test-alert'
end
def go_to_alert_settings
@@ -32,54 +32,54 @@ module QA
end
def enable_incident_for_alert
- check_element(:create_incident_checkbox, true)
+ check_element('create-incident-checkbox', true)
end
def enable_email_notification
- check_element(:enable_email_notification_checkbox, true)
+ check_element('enable-email-notification-checkbox', true)
end
def select_issue_template(template)
- click_element(:incident_templates_dropdown)
- within_element :incident_templates_dropdown do
+ click_element('incident-templates-dropdown')
+ within_element 'incident-templates-dropdown' do
select_item(template)
end
end
def save_alert_settings
- click_element :save_changes_button
+ click_element 'save-changes-button'
end
def has_template?(template)
- within_element :incident_templates_dropdown do
+ within_element 'incident-templates-dropdown' do
has_text?(template)
end
end
def add_new_integration
wait_for_requests
- click_element(:add_integration_button)
+ click_element('add-integration-button')
end
def select_http_endpoint
- click_element(:integration_type_dropdown)
+ click_element('integration-type-dropdown')
find("option[value='HTTP']").click
# Click outside of the list to close it
- click_element(:integration_name_field)
+ click_element('integration-name-field')
end
def select_prometheus
- click_element(:integration_type_dropdown)
+ click_element('integration-type-dropdown')
find("option[value='PROMETHEUS']").click
end
def enter_integration_name(name)
- fill_element(:integration_name_field, name)
+ fill_element('integration-name-field', name)
end
def activate_integration
- within_element(:active_toggle_container) do
+ within_element('active-toggle-container') do
find('.gl-toggle').click
end
@@ -87,15 +87,15 @@ module QA
end
def save_and_create_alert
- click_element(:save_and_create_alert_button)
+ click_element('save-and-create-alert-button')
end
def fill_in_test_payload(payload)
- fill_element(:test_payload_field, payload)
+ fill_element('test-payload-field', payload)
end
def send_test_alert
- click_element(:send_test_alert_button)
+ click_element('send-test-alert')
end
def go_to_view_credentials
diff --git a/qa/qa/page/project/settings/merge_request.rb b/qa/qa/page/project/settings/merge_request.rb
index 3530726feeb..f3d9c763159 100644
--- a/qa/qa/page/project/settings/merge_request.rb
+++ b/qa/qa/page/project/settings/merge_request.rb
@@ -11,11 +11,11 @@ module QA
element :save_merge_request_changes_button
end
- view 'app/views/projects/_merge_request_merge_method_settings.html.haml' do
+ view 'app/views/projects/settings/merge_requests/_merge_request_merge_method_settings.html.haml' do
element :merge_ff_radio
end
- view 'app/views/projects/_merge_request_pipelines_and_threads_options.html.haml' do
+ view 'app/views/projects/settings/merge_requests/_merge_request_pipelines_and_threads_options.html.haml' do
element :only_allow_merge_if_all_discussions_are_resolved_checkbox
end
diff --git a/qa/qa/page/project/settings/mirroring_repositories.rb b/qa/qa/page/project/settings/mirroring_repositories.rb
index 85b413ba880..404f9184290 100644
--- a/qa/qa/page/project/settings/mirroring_repositories.rb
+++ b/qa/qa/page/project/settings/mirroring_repositories.rb
@@ -7,7 +7,8 @@ module QA
class MirroringRepositories < Page::Base
view 'app/views/projects/mirrors/_authentication_method.html.haml' do
element :authentication_method_field
- element :password_field
+ element 'username-field'
+ element 'password-field'
end
view 'app/views/projects/mirrors/_mirror_repos.html.haml' do
@@ -42,8 +43,12 @@ module QA
fill_element :mirror_repository_url_field, value
end
+ def username=(value)
+ fill_element 'username-field', value
+ end
+
def password=(value)
- fill_element :password_field, value
+ fill_element 'password-field', value
end
def mirror_direction=(value)
diff --git a/qa/qa/page/project/settings/monitor.rb b/qa/qa/page/project/settings/monitor.rb
index 8170ae31a13..85791f07a64 100644
--- a/qa/qa/page/project/settings/monitor.rb
+++ b/qa/qa/page/project/settings/monitor.rb
@@ -8,21 +8,21 @@ module QA
include QA::Page::Settings::Common
view 'app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue' do
- element :incidents_settings_content
+ element 'incidents-settings-content'
end
view 'app/views/projects/settings/operations/_alert_management.html.haml' do
- element :alerts_settings_content
+ element 'alerts-settings-content'
end
def expand_incidents(&block)
- expand_content(:incidents_settings_content) do
+ expand_content('incidents-settings-content') do
# Fill in with incidents settings
end
end
def expand_alerts(&block)
- expand_content(:alerts_settings_content) do
+ expand_content('alerts-settings-content') do
Settings::Alerts.perform(&block)
end
end
diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb
index 93522c1deac..aab2c5ed6bd 100644
--- a/qa/qa/page/project/settings/protected_branches.rb
+++ b/qa/qa/page/project/settings/protected_branches.rb
@@ -5,6 +5,8 @@ module QA
module Project
module Settings
class ProtectedBranches < Page::Base
+ include Page::Component::ListboxFilter
+
view 'app/views/protected_branches/shared/_index.html.haml' do
element 'add-protected-branch-button'
end
@@ -14,11 +16,9 @@ module QA
element :protected_branch_dropdown_content
end
- view 'app/views/protected_branches/_create_protected_branch.html.haml' do
- element :select_allowed_to_push_dropdown
- element :allowed_to_push_dropdown_content
- element :select_allowed_to_merge_dropdown
- element :allowed_to_merge_dropdown_content
+ view 'app/assets/javascripts/protected_branches/protected_branch_create.js' do
+ element 'allowed-to-push-dropdown'
+ element 'allowed-to-merge-dropdown'
end
view 'app/views/protected_branches/shared/_create_protected_branch.html.haml' do
@@ -50,19 +50,19 @@ module QA
private
def select_allowed(action, allowed)
- click_element :"select_allowed_to_#{action}_dropdown"
-
- allowed[:roles] = Resource::ProtectedBranch::Roles::NO_ONE unless allowed.key?(:roles)
+ within_element("allowed-to-#{action}-dropdown") do
+ click_element ".js-allowed-to-#{action}"
+ allowed[:roles] = Resource::ProtectedBranch::Roles::NO_ONE unless allowed.key?(:roles)
- within_element(:"allowed_to_#{action}_dropdown_content") do
click_on allowed[:roles][:description]
+
allowed[:users].each { |user| select_name user.username } if allowed.key?(:users)
allowed[:groups].each { |group| select_name group.name } if allowed.key?(:groups)
end
end
def select_name(name)
- fill_element(:dropdown_input_field, name)
+ fill_element('.gl-search-box-by-type-input', name)
click_on name
end
end
diff --git a/qa/qa/page/project/settings/protected_tags.rb b/qa/qa/page/project/settings/protected_tags.rb
index 49fdae5f8a3..5923bc7dc78 100644
--- a/qa/qa/page/project/settings/protected_tags.rb
+++ b/qa/qa/page/project/settings/protected_tags.rb
@@ -11,9 +11,8 @@ module QA
element :tags_dropdown
end
- view 'app/views/projects/protected_tags/_create_protected_tag.html.haml' do
- element :access_levels_content
- element :access_levels_dropdown
+ view 'app/assets/javascripts/protected_tags/protected_tag_create.js' do
+ element :allowed_to_create_dropdown
end
view 'app/views/projects/protected_tags/shared/_create_protected_tag.html.haml' do
@@ -27,13 +26,14 @@ module QA
end
def choose_access_level_role(role)
- return if find_element(:access_levels_dropdown).text == role
+ return if find_element(:allowed_to_create_dropdown).text == role
- click_element :access_levels_dropdown
- within_element(:access_levels_content) do
+ click_element :allowed_to_create_dropdown
+ within_element :allowed_to_create_dropdown do
click_on role
end
- click_element :access_levels_dropdown
+ # confirm selection and remove dropdown
+ click_element :allowed_to_create_dropdown
end
def click_protect_tag_button
diff --git a/qa/qa/page/project/sub_menus/build.rb b/qa/qa/page/project/sub_menus/build.rb
new file mode 100644
index 00000000000..f9827cfdd5e
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/build.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module Build
+ extend QA::Page::PageConcern
+
+ def go_to_pipelines
+ open_build_submenu('Pipelines')
+ end
+
+ def go_to_pipeline_editor
+ open_build_submenu('Pipeline editor')
+ end
+
+ def go_to_jobs
+ open_build_submenu('Jobs')
+ end
+
+ def go_to_schedules
+ open_build_submenu('Pipeline schedules')
+ end
+
+ def go_to_environments
+ open_operations_submenu('Environments')
+ end
+
+ def go_to_feature_flags
+ open_operations_submenu('Feature Flags')
+ end
+
+ def go_to_releases
+ open_operations_submenu('Releases')
+ end
+
+ private
+
+ def open_build_submenu(sub_menu)
+ open_submenu('Build', sub_menu)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/ci_cd.rb b/qa/qa/page/project/sub_menus/ci_cd.rb
deleted file mode 100644
index 3547ea76182..00000000000
--- a/qa/qa/page/project/sub_menus/ci_cd.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module CiCd
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::Project::SubMenus::Common
- end
- end
-
- def go_to_pipelines
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'CI/CD')
- end
- end
-
- def go_to_pipeline_editor
- hover_ci_cd_pipelines do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Editor')
- end
- end
- end
-
- private
-
- def hover_ci_cd_pipelines
- within_sidebar do
- find_element(:sidebar_menu_link, menu_item: 'CI/CD').hover
-
- yield
- end
- end
- end
- end
- end
- end
-end
-
-QA::Page::Project::SubMenus::CiCd.prepend_mod_with('Page::Project::SubMenus::CiCd', namespace: QA)
diff --git a/qa/qa/page/project/sub_menus/code.rb b/qa/qa/page/project/sub_menus/code.rb
new file mode 100644
index 00000000000..81bca9f9dd6
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/code.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module Code
+ extend QA::Page::PageConcern
+
+ def go_to_repository
+ open_code_submenu('Repository')
+ end
+
+ def go_to_repository_commits
+ open_code_submenu('Commits')
+ end
+
+ def go_to_repository_branches
+ open_code_submenu('Branches')
+ end
+
+ def go_to_repository_tags
+ open_code_submenu('Tags')
+ end
+
+ def go_to_snippets
+ open_code_submenu('Snippets')
+ end
+
+ def go_to_graph
+ open_code_submenu('Repository graph')
+ end
+
+ def go_to_compare_revisions
+ open_code_submenu('Compare revisions')
+ end
+
+ def go_to_merge_requests
+ open_code_submenu('Merge requests')
+ end
+
+ private
+
+ def open_code_submenu(sub_menu)
+ open_submenu('Code', sub_menu)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/common.rb b/qa/qa/page/project/sub_menus/common.rb
index 280d28a697d..563bc9257c5 100644
--- a/qa/qa/page/project/sub_menus/common.rb
+++ b/qa/qa/page/project/sub_menus/common.rb
@@ -13,14 +13,6 @@ module QA
base.class_eval do
include QA::Page::SubMenus::Common
- view 'app/views/shared/nav/_sidebar_menu_item.html.haml' do
- element :sidebar_menu_item_link
- end
-
- view 'app/views/shared/nav/_sidebar_menu.html.haml' do
- element :sidebar_menu_link
- end
-
view 'app/views/layouts/nav/_top_bar.html.haml' do
element :toggle_mobile_nav_button
end
diff --git a/qa/qa/page/project/sub_menus/create_new_menu.rb b/qa/qa/page/project/sub_menus/create_new_menu.rb
index cfb91c29d5e..f79478b09d4 100644
--- a/qa/qa/page/project/sub_menus/create_new_menu.rb
+++ b/qa/qa/page/project/sub_menus/create_new_menu.rb
@@ -11,21 +11,12 @@ module QA
super
base.class_eval do
- # TODO: remove this when the super sidebar is enabled by default
- view 'app/helpers/nav/new_dropdown_helper.rb' do
- element :new_issue_link
- end
-
- view 'app/helpers/sidebars_helper.rb' do
- element :create_menu_item
- end
+ include QA::Page::SubMenus::CreateNewMenu
end
end
def go_to_new_issue
within_new_item_menu do
- next click_element(:new_issue_link) unless QA::Runtime::Env.super_sidebar_enabled?
-
click_element(:create_menu_item, create_menu_item: 'new_issue')
end
end
diff --git a/qa/qa/page/project/sub_menus/deploy.rb b/qa/qa/page/project/sub_menus/deploy.rb
new file mode 100644
index 00000000000..df46c3e1639
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/deploy.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module Deploy
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.class_eval do
+ include QA::Page::SubMenus::SuperSidebar::Deploy
+ end
+ end
+
+ def go_to_releases
+ open_deploy_submenu("Releases")
+ end
+
+ def go_to_feature_flags
+ open_deploy_submenu("Feature flags")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/deployments.rb b/qa/qa/page/project/sub_menus/deployments.rb
deleted file mode 100644
index 24243cb2436..00000000000
--- a/qa/qa/page/project/sub_menus/deployments.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module Deployments
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::Project::SubMenus::Common
- end
- end
-
- def go_to_deployments_environments
- hover_deployments do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Environments')
- end
- end
- end
-
- private
-
- def hover_deployments
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Deployments')
- find_element(:sidebar_menu_link, menu_item: 'Deployments').hover
-
- yield
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/infrastructure.rb b/qa/qa/page/project/sub_menus/infrastructure.rb
deleted file mode 100644
index 2c207022c8d..00000000000
--- a/qa/qa/page/project/sub_menus/infrastructure.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module Infrastructure
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::Project::SubMenus::Common
- end
- end
-
- def go_to_infrastructure_kubernetes
- hover_infrastructure do
- within_submenu do
- click_link('Kubernetes clusters')
- end
- end
- end
-
- private
-
- def hover_infrastructure
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Infrastructure')
- find_element(:sidebar_menu_link, menu_item: 'Infrastructure').hover
-
- yield
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/issues.rb b/qa/qa/page/project/sub_menus/issues.rb
deleted file mode 100644
index b5b918e076d..00000000000
--- a/qa/qa/page/project/sub_menus/issues.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module Issues
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::Project::SubMenus::Common
- end
- end
-
- def go_to_issues
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'Issues')
- end
- end
-
- def click_milestones
- within_sidebar do
- click_element(:sidebar_menu_item_link, menu_item: 'Milestones')
- end
- end
-
- def go_to_issue_boards
- hover_issues do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Boards')
- end
- end
- end
-
- def go_to_labels
- hover_issues do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Labels')
- end
- end
- end
-
- def go_to_milestones
- hover_issues do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Milestones')
- end
- end
- end
-
- def go_to_jira_issues
- hover_issues do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Jira issues')
- end
- end
- end
-
- private
-
- def hover_issues
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Issues')
- find_element(:sidebar_menu_link, menu_item: 'Issues').hover
-
- yield
- end
- end
- end
- end
- end
- end
-end
-
-QA::Page::Project::SubMenus::Issues.prepend_mod_with('Page::Project::SubMenus::Issues', namespace: QA)
diff --git a/qa/qa/page/project/sub_menus/main.rb b/qa/qa/page/project/sub_menus/main.rb
new file mode 100644
index 00000000000..a147f28eef0
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/main.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module Main
+ extend QA::Page::PageConcern
+
+ def click_project
+ click_element(:nav_item_link, submenu_item: 'project-overview')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/monitor.rb b/qa/qa/page/project/sub_menus/monitor.rb
index 00774261467..8f601005633 100644
--- a/qa/qa/page/project/sub_menus/monitor.rb
+++ b/qa/qa/page/project/sub_menus/monitor.rb
@@ -7,55 +7,30 @@ module QA
module Monitor
extend QA::Page::PageConcern
- def self.included(base)
- super
+ def go_to_monitor_error_tracking
+ open_monitor_submenu('Error tracking')
+ end
- base.class_eval do
- include QA::Page::Project::SubMenus::Common
- end
+ def go_to_monitor_alerts
+ open_monitor_submenu('Alerts')
end
def go_to_monitor_incidents
- hover_monitor do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Incidents')
- end
- end
+ open_monitor_submenu('Incidents')
end
- def go_to_monitor_alerts
- hover_monitor do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Alerts')
- end
- end
+ def go_to_monitor_escalation_policies
+ open_monitor_submenu('Escalation Policies')
end
def go_to_monitor_on_call_schedules
- hover_monitor do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'On-call Schedules')
- end
- end
- end
-
- def go_to_monitor_escalation_policies
- hover_monitor do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Escalation Policies')
- end
- end
+ open_monitor_submenu('On-call Schedules')
end
private
- def hover_monitor
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Monitor')
- find_element(:sidebar_menu_link, menu_item: 'Monitor').hover
-
- yield
- end
+ def open_monitor_submenu(sub_menu)
+ open_submenu('Monitor', sub_menu)
end
end
end
diff --git a/qa/qa/page/project/sub_menus/operate.rb b/qa/qa/page/project/sub_menus/operate.rb
new file mode 100644
index 00000000000..26f264fa821
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/operate.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module Operate
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.class_eval do
+ include QA::Page::SubMenus::Operate
+ end
+ end
+
+ def go_to_infrastructure_registry
+ open_operate_submenu('Terraform modules')
+ end
+
+ def go_to_kubernetes_clusters
+ open_operate_submenu('Kubernetes clusters')
+ end
+
+ def go_to_terraform
+ open_operate_submenu('Terraform states')
+ end
+
+ private
+
+ def open_operate_submenu(sub_menu)
+ open_submenu('Operate', sub_menu)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/packages.rb b/qa/qa/page/project/sub_menus/packages.rb
deleted file mode 100644
index 9f3446bfd39..00000000000
--- a/qa/qa/page/project/sub_menus/packages.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module Packages
- extend QA::Page::PageConcern
-
- def go_to_package_registry
- hover_registry do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Package Registry')
- end
- end
- end
-
- def go_to_container_registry
- hover_registry do
- within_submenu do
- click_link('Container Registry')
- end
- end
- end
-
- def go_to_infrastructure_registry
- hover_registry do
- within_submenu do
- click_link('Terraform modules')
- end
- end
- end
-
- private
-
- def hover_registry
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Packages and registries')
- find_element(:sidebar_menu_link, menu_item: 'Packages and registries').hover
-
- yield
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/plan.rb b/qa/qa/page/project/sub_menus/plan.rb
new file mode 100644
index 00000000000..a7fe00f3c60
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/plan.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module Plan
+ def self.included(base)
+ super
+
+ base.class_eval do
+ include QA::Page::SubMenus::Plan
+ end
+ end
+
+ def go_to_requirements
+ open_plan_submenu("Requirements")
+ end
+
+ def go_to_jira_issues
+ open_plan_submenu("Jira issues")
+ end
+
+ def go_to_open_jira
+ open_plan_submenu("Open Jira")
+ end
+
+ def go_to_issues
+ open_plan_submenu("Issues")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/project.rb b/qa/qa/page/project/sub_menus/project.rb
deleted file mode 100644
index 89d4ed578ed..00000000000
--- a/qa/qa/page/project/sub_menus/project.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module Project
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::Project::SubMenus::Common
- end
- end
-
- def click_project
- retry_on_exception do
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'Project scope')
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
deleted file mode 100644
index 274dd3a58c8..00000000000
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module Repository
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::Project::SubMenus::Common
- end
- end
-
- def click_repository
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'Repository')
- end
- end
-
- def go_to_repository_branches
- hover_repository do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Branches')
- end
- end
- end
-
- def go_to_repository_tags
- hover_repository do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Tags')
- end
- end
- end
-
- def go_to_repository_contributors
- return go_to_contributor_statistics if Runtime::Env.super_sidebar_enabled?
-
- hover_repository do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Contributor statistics')
- end
- end
- end
-
- private
-
- def hover_repository
- within_sidebar do
- find_element(:sidebar_menu_link, menu_item: 'Repository').hover
-
- yield
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/secure.rb b/qa/qa/page/project/sub_menus/secure.rb
new file mode 100644
index 00000000000..19aa051668c
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/secure.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module Secure
+ extend QA::Page::PageConcern
+
+ def go_to_security_configuration
+ open_secure_submenu('Security configuration')
+ end
+
+ private
+
+ def open_secure_submenu(sub_menu)
+ open_submenu('Secure', sub_menu)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/settings.rb b/qa/qa/page/project/sub_menus/settings.rb
index 2ed4c28afb7..bf6b25062f0 100644
--- a/qa/qa/page/project/sub_menus/settings.rb
+++ b/qa/qa/page/project/sub_menus/settings.rb
@@ -11,89 +11,26 @@ module QA
super
base.class_eval do
- include QA::Page::Project::SubMenus::Common
+ include QA::Page::SubMenus::Settings
end
end
- def go_to_ci_cd_settings
- hover_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'CI/CD')
- end
- end
- end
-
- def go_to_repository_settings
- hover_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Repository')
- end
- end
- end
-
- def go_to_general_settings
- hover_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'General')
- end
- end
- end
-
- def click_settings
- within_sidebar do
- click_element(:sidebar_menu_link, menu_item: 'Settings')
- end
- end
-
- def go_to_integrations_settings
- hover_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Integrations')
- end
- end
- end
-
- def go_to_monitor_settings
- hover_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Monitor')
- end
- end
- end
-
- def go_to_access_token_settings
- hover_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Access Tokens')
- end
- end
+ def go_to_merge_request_settings
+ open_settings_submenu('Merge requests')
end
def go_to_pages_settings
- hover_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Pages')
- end
- end
+ open_settings_submenu('Pages')
end
- def go_to_merge_request_settings
- hover_settings do
- within_submenu do
- click_element(:sidebar_menu_item_link, menu_item: 'Merge requests')
- end
- end
+ def go_to_monitor_settings
+ open_settings_submenu('Monitor')
end
private
- def hover_settings
- within_sidebar do
- scroll_to_element(:sidebar_menu_link, menu_item: 'Settings')
- find_element(:sidebar_menu_link, menu_item: 'Settings').hover
-
- yield
- end
+ def open_settings_submenu(sub_menu)
+ open_submenu('Settings', sub_menu)
end
end
end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/build.rb b/qa/qa/page/project/sub_menus/super_sidebar/build.rb
deleted file mode 100644
index 7d772d9d192..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/build.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Build
- extend QA::Page::PageConcern
-
- def go_to_pipelines
- open_build_submenu('Pipelines')
- end
-
- def go_to_pipeline_editor
- open_build_submenu('Pipeline editor')
- end
-
- def go_to_jobs
- open_build_submenu('Jobs')
- end
-
- def go_to_schedules
- open_build_submenu('Pipeline schedules')
- end
-
- def go_to_environments
- open_operations_submenu('Environments')
- end
-
- def go_to_feature_flags
- open_operations_submenu('Feature Flags')
- end
-
- def go_to_releases
- open_operations_submenu('Releases')
- end
-
- private
-
- def open_build_submenu(sub_menu)
- open_submenu('Build', sub_menu)
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/code.rb b/qa/qa/page/project/sub_menus/super_sidebar/code.rb
deleted file mode 100644
index fae7210e3c8..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/code.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Code
- extend QA::Page::PageConcern
-
- def go_to_repository
- open_code_submenu('Repository')
- end
-
- def go_to_repository_commits
- open_code_submenu('Commits')
- end
-
- def go_to_repository_branches
- open_code_submenu('Branches')
- end
-
- def go_to_repository_tags
- open_code_submenu('Tags')
- end
-
- def go_to_snippets
- open_code_submenu('Snippets')
- end
-
- def go_to_graph
- open_code_submenu('Repository graph')
- end
-
- def go_to_compare_revisions
- open_code_submenu('Compare revisions')
- end
-
- def go_to_merge_requests
- open_code_submenu('Merge requests')
- end
-
- private
-
- def open_code_submenu(sub_menu)
- open_submenu('Code', sub_menu)
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/deploy.rb b/qa/qa/page/project/sub_menus/super_sidebar/deploy.rb
deleted file mode 100644
index f19e18b11d7..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/deploy.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Deploy
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::SubMenus::SuperSidebar::Deploy
- end
- end
-
- def go_to_releases
- open_deploy_submenu("Releases")
- end
-
- def go_to_feature_flags
- open_deploy_submenu("Feature flags")
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/main.rb b/qa/qa/page/project/sub_menus/super_sidebar/main.rb
deleted file mode 100644
index bf2619737ab..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/main.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Main
- extend QA::Page::PageConcern
-
- def click_project
- click_element(:nav_item_link, submenu_item: 'Project overview')
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/monitor.rb b/qa/qa/page/project/sub_menus/super_sidebar/monitor.rb
deleted file mode 100644
index 65ed9dbb4f8..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/monitor.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Monitor
- extend QA::Page::PageConcern
-
- def go_to_monitor_error_tracking
- open_monitor_submenu('Error tracking')
- end
-
- def go_to_monitor_alerts
- open_monitor_submenu('Alerts')
- end
-
- def go_to_monitor_incidents
- open_monitor_submenu('Incidents')
- end
-
- def go_to_monitor_escalation_policies
- open_monitor_submenu('Escalation Policies')
- end
-
- def go_to_monitor_on_call_schedules
- open_monitor_submenu('On-call Schedules')
- end
-
- private
-
- def open_monitor_submenu(sub_menu)
- open_submenu('Monitor', sub_menu)
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/operate.rb b/qa/qa/page/project/sub_menus/super_sidebar/operate.rb
deleted file mode 100644
index 8191f2263ef..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/operate.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Operate
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::SubMenus::SuperSidebar::Operate
- end
- end
-
- def go_to_infrastructure_registry
- open_operate_submenu('Terraform modules')
- end
-
- def go_to_kubernetes_clusters
- open_operate_submenu('Kubernetes clusters')
- end
-
- def go_to_terraform
- open_operate_submenu('Terraform states')
- end
-
- private
-
- def open_operate_submenu(sub_menu)
- open_submenu('Operate', sub_menu)
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/plan.rb b/qa/qa/page/project/sub_menus/super_sidebar/plan.rb
deleted file mode 100644
index fe77789f371..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/plan.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Plan
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::SubMenus::SuperSidebar::Plan
- end
- end
-
- def go_to_requirements
- open_plan_submenu("Requirements")
- end
-
- def go_to_jira_issues
- open_plan_submenu("Jira issues")
- end
-
- def go_to_open_jira
- open_plan_submenu("Open Jira")
- end
-
- def go_to_issues
- open_plan_submenu("Issues")
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/secure.rb b/qa/qa/page/project/sub_menus/super_sidebar/secure.rb
deleted file mode 100644
index ab1717a447a..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/secure.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Secure
- extend QA::Page::PageConcern
-
- def go_to_security_configuration
- open_secure_submenu('Security configuration')
- end
-
- private
-
- def open_secure_submenu(sub_menu)
- open_submenu('Secure', sub_menu)
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/sub_menus/super_sidebar/settings.rb b/qa/qa/page/project/sub_menus/super_sidebar/settings.rb
deleted file mode 100644
index 3aca6cf00af..00000000000
--- a/qa/qa/page/project/sub_menus/super_sidebar/settings.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Project
- module SubMenus
- module SuperSidebar
- module Settings
- extend QA::Page::PageConcern
-
- def self.included(base)
- super
-
- base.class_eval do
- include QA::Page::SubMenus::SuperSidebar::Settings
- end
- end
-
- def go_to_merge_request_settings
- open_settings_submenu('Merge requests')
- end
-
- def go_to_pages_settings
- open_settings_submenu('Pages')
- end
-
- def go_to_monitor_settings
- open_settings_submenu('Monitor')
- end
-
- private
-
- def open_settings_submenu(sub_menu)
- open_submenu('Settings', sub_menu)
- end
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb
index 19802f846d8..16eaa7efba9 100644
--- a/qa/qa/page/project/web_ide/edit.rb
+++ b/qa/qa/page/project/web_ide/edit.rb
@@ -58,7 +58,7 @@ module QA
end
view 'app/assets/javascripts/vue_shared/components/file_row.vue' do
- element :file_name_content
+ element 'file-row-name-container'
element :file_row_container
end
@@ -123,7 +123,7 @@ module QA
def has_file?(file_name)
within_element(:file_list_container) do
- has_element?(:file_name_content, file_name: file_name)
+ has_element?('file-row-name-container', file_name: file_name)
end
end
@@ -289,7 +289,7 @@ module QA
end
def rename_file(file_name, new_file_name)
- click_element(:file_name_content, file_name: file_name)
+ click_element('file-row-name-container', file_name: file_name)
click_element(:dropdown_button)
click_element(:rename_move_button, Page::Component::WebIDE::Modal::CreateNewFile)
fill_element(:file_name_field, new_file_name)
@@ -314,7 +314,7 @@ module QA
end
def delete_file(file_name)
- click_element(:file_name_content, file_name: file_name)
+ click_element('file-row-name-container', file_name: file_name)
click_element(:dropdown_button)
click_element(:delete_button)
end
@@ -326,9 +326,9 @@ module QA
def select_file(file_name)
# wait for the list of files to load
wait_until(reload: true) do
- has_element?(:file_name_content, file_name: file_name)
+ has_element?('file-row-name-container', file_name: file_name)
end
- click_element(:file_name_content, file_name: file_name)
+ click_element('file-row-name-container', file_name: file_name)
end
def link_line(line_number)
diff --git a/qa/qa/page/project/web_ide/vscode.rb b/qa/qa/page/project/web_ide/vscode.rb
index 6a570978dbe..8f257e95f3e 100644
--- a/qa/qa/page/project/web_ide/vscode.rb
+++ b/qa/qa/page/project/web_ide/vscode.rb
@@ -13,6 +13,7 @@ module QA
def has_file_explorer?
page.has_css?('.explorer-folders-view', visible: true)
+ page.has_css?('[aria-label="Files Explorer"]', visible: true)
end
def right_click_file_explorer
@@ -33,11 +34,11 @@ module QA
end
def has_upload_menu_item?
- page.has_css?('[aria-label="Upload..."]', visible: true)
+ page.has_css?('.menu-item-check', visible: true)
end
def click_upload_menu_item
- page.find('[aria-label="Upload..."]').click
+ page.find('[aria-label="Upload..."]', visible: true).click
end
def enter_file_input(file)
@@ -170,11 +171,10 @@ module QA
# We need to execute a script on the iframe to stub out the iframes body.removeChild to add it back in.
page.execute_script("document.body.removeChild = function(){};")
- right_click_file_explorer
- has_upload_menu_item?
-
# Use for stability, WebIDE inside an iframe is finnicky, webdriver sometimes moves too fast
Support::Waiter.wait_until(max_duration: 20, retry_on_exception: true) do
+ right_click_file_explorer
+ has_upload_menu_item?
click_upload_menu_item
enter_file_input(file_path)
end
diff --git a/qa/qa/page/registration/sign_up.rb b/qa/qa/page/registration/sign_up.rb
index 4fedc05c702..ab3f15bb857 100644
--- a/qa/qa/page/registration/sign_up.rb
+++ b/qa/qa/page/registration/sign_up.rb
@@ -5,39 +5,39 @@ module QA
module Registration
class SignUp < Page::Base
view 'app/views/devise/shared/_signup_box.html.haml' do
- element :new_user_first_name_field
- element :new_user_last_name_field
- element :new_user_email_field
- element :new_user_password_field
- element :new_user_register_button
+ element 'new-user-first-name-field'
+ element 'new-user-last-name-field'
+ element 'new-user-email-field'
+ element 'new-user-password-field'
+ element 'new-user-register-button'
end
view 'app/helpers/registrations_helper.rb' do
- element :new_user_username_field
+ element 'new-user-username-field'
end
def fill_new_user_first_name_field(first_name)
- fill_element :new_user_first_name_field, first_name
+ fill_element 'new-user-first-name-field', first_name
end
def fill_new_user_last_name_field(last_name)
- fill_element :new_user_last_name_field, last_name
+ fill_element 'new-user-last-name-field', last_name
end
def fill_new_user_username_field(username)
- fill_element :new_user_username_field, username
+ fill_element 'new-user-username-field', username
end
def fill_new_user_email_field(email)
- fill_element :new_user_email_field, email
+ fill_element 'new-user-email-field', email
end
def fill_new_user_password_field(password)
- fill_element :new_user_password_field, password
+ fill_element 'new-user-password-field', password
end
def click_new_user_register_button
- click_element :new_user_register_button if has_element?(:new_user_register_button)
+ click_element 'new-user-register-button' if has_element?('new-user-register-button')
end
end
end
diff --git a/qa/qa/page/sub_menus/common.rb b/qa/qa/page/sub_menus/common.rb
index 19d07e885c6..dc878674877 100644
--- a/qa/qa/page/sub_menus/common.rb
+++ b/qa/qa/page/sub_menus/common.rb
@@ -4,39 +4,24 @@ module QA
module Page
module SubMenus
module Common
- prepend Mobile::Page::SubMenus::Common if QA::Runtime::Env.mobile_layout?
-
def self.included(base)
super
base.class_eval do
+ prepend Mobile::Page::SubMenus::Common if QA::Runtime::Env.mobile_layout?
+
view 'app/assets/javascripts/super_sidebar/components/super_sidebar.vue' do
element :navbar
end
end
end
- def hover_element(element)
- within_sidebar do
- find_element(element).hover
- yield
- end
- end
-
def within_sidebar(&block)
wait_for_requests
within_element(:navbar, &block)
end
- def within_submenu(element = nil, &block)
- if element
- within_element(element, &block)
- else
- within_submenu_without_element(&block)
- end
- end
-
private
# Opens the new item menu and yields to the block
@@ -48,7 +33,7 @@ module QA
yield
end
- # Implementation for super-sidebar, will replace within_submenu
+ # Open sidebar navigation submenu
#
# @param [String] parent_menu_name
# @param [String] parent_section_id
@@ -64,10 +49,6 @@ module QA
click_element(:nav_item_link, submenu_item: sub_menu)
end
end
-
- def within_submenu_without_element(&block)
- has_css?('.fly-out-list') ? within('.fly-out-list', &block) : yield
- end
end
end
end
diff --git a/qa/qa/page/sub_menus/create_new_menu.rb b/qa/qa/page/sub_menus/create_new_menu.rb
index 1f8641827be..aaf763ac33e 100644
--- a/qa/qa/page/sub_menus/create_new_menu.rb
+++ b/qa/qa/page/sub_menus/create_new_menu.rb
@@ -6,7 +6,7 @@ module QA
module CreateNewMenu
extend QA::Page::PageConcern
- def self.prepended(base)
+ def self.included(base)
super
base.class_eval do
diff --git a/qa/qa/page/sub_menus/deploy.rb b/qa/qa/page/sub_menus/deploy.rb
new file mode 100644
index 00000000000..c930cd6b6df
--- /dev/null
+++ b/qa/qa/page/sub_menus/deploy.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module SubMenus
+ module Deploy
+ extend QA::Page::PageConcern
+
+ def go_to_package_registry
+ open_deploy_submenu("Package Registry")
+ end
+
+ def go_to_container_registry
+ open_deploy_submenu('Container Registry')
+ end
+
+ private
+
+ def open_deploy_submenu(sub_menu)
+ open_submenu("Deploy", sub_menu)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/sub_menus/main.rb b/qa/qa/page/sub_menus/main.rb
new file mode 100644
index 00000000000..c8d7d27d930
--- /dev/null
+++ b/qa/qa/page/sub_menus/main.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module SubMenus
+ module Main
+ extend QA::Page::PageConcern
+
+ def go_to_issues
+ click_element(:nav_item_link, submenu_item: 'Issues')
+ end
+
+ def go_to_merge_requests
+ click_element(:nav_item_link, submenu_item: 'Merge requests')
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/sub_menus/manage.rb b/qa/qa/page/sub_menus/manage.rb
new file mode 100644
index 00000000000..70daf42a8b4
--- /dev/null
+++ b/qa/qa/page/sub_menus/manage.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module SubMenus
+ module Manage
+ extend QA::Page::PageConcern
+
+ def go_to_activity
+ open_manage_submenu('Activity')
+ end
+
+ def go_to_members
+ open_manage_submenu('Members')
+ end
+
+ def go_to_labels
+ open_manage_submenu('Labels')
+ end
+
+ private
+
+ def open_manage_submenu(sub_menu)
+ open_submenu('Manage', sub_menu)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/sub_menus/operate.rb b/qa/qa/page/sub_menus/operate.rb
new file mode 100644
index 00000000000..cbbf275d3d1
--- /dev/null
+++ b/qa/qa/page/sub_menus/operate.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module SubMenus
+ module Operate
+ extend QA::Page::PageConcern
+
+ def go_to_dependency_proxy
+ open_operate_submenu('Dependency Proxy')
+ end
+
+ private
+
+ def open_operate_submenu(sub_menu)
+ open_submenu('Operate', sub_menu)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/sub_menus/plan.rb b/qa/qa/page/sub_menus/plan.rb
new file mode 100644
index 00000000000..d0a4c9c7d2e
--- /dev/null
+++ b/qa/qa/page/sub_menus/plan.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module SubMenus
+ module Plan
+ extend QA::Page::PageConcern
+
+ def go_to_issue_boards
+ open_plan_submenu("Issue boards")
+ end
+
+ def go_to_service_desk
+ open_plan_submenu("Service Desk")
+ end
+
+ def go_to_wiki
+ open_plan_submenu("Wiki")
+ end
+
+ def go_to_milestones
+ open_plan_submenu('Milestones')
+ end
+
+ private
+
+ def open_plan_submenu(sub_menu)
+ open_submenu("Plan", sub_menu)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/sub_menus/settings.rb b/qa/qa/page/sub_menus/settings.rb
new file mode 100644
index 00000000000..ba5ca8f8960
--- /dev/null
+++ b/qa/qa/page/sub_menus/settings.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module SubMenus
+ module Settings
+ extend QA::Page::PageConcern
+
+ def go_to_general_settings
+ open_settings_submenu('General')
+ end
+
+ def go_to_integrations_settings
+ open_settings_submenu('Integrations')
+ end
+
+ def go_to_webhooks_settings
+ open_settings_submenu('Webhooks')
+ end
+
+ def go_to_access_token_settings
+ open_settings_submenu('Access Tokens')
+ end
+
+ def go_to_repository_settings
+ open_settings_submenu('Repository')
+ end
+
+ def go_to_ci_cd_settings
+ open_settings_submenu('CI/CD')
+ end
+
+ def go_to_package_settings
+ open_settings_submenu('Packages and registries')
+ end
+
+ private
+
+ def open_settings_submenu(sub_menu)
+ open_submenu('Settings', sub_menu)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb b/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb
deleted file mode 100644
index af06438782d..00000000000
--- a/qa/qa/page/sub_menus/super_sidebar/context_switcher.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module SubMenus
- module SuperSidebar
- module ContextSwitcher
- extend QA::Page::PageConcern
-
- def self.prepended(base)
- super
-
- base.class_eval do
- view 'app/assets/javascripts/super_sidebar/components/context_switcher_toggle.vue' do
- element 'context-switcher'
- end
-
- view 'app/assets/javascripts/super_sidebar/components/context_switcher.vue' do
- element 'context-navigation'
- end
- end
- end
-
- def go_to_your_work
- go_to_context("Your work")
- end
-
- def go_to_explore
- go_to_context("Explore")
- end
-
- def go_to_admin_area
- go_to_context("Admin Area")
- end
-
- def has_admin_area_link?(wait: Capybara.default_max_wait_time)
- open_context_switcher
-
- has_element?(:nav_item_link, submenu_item: "Admin Area", wait: wait)
- end
-
- private
-
- def go_to_context(sub_menu)
- open_context_switcher
- click_element(:nav_item_link, submenu_item: sub_menu)
- end
-
- def open_context_switcher
- click_element('context-switcher') unless has_element?('context-navigation', wait: 0)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/sub_menus/super_sidebar/deploy.rb b/qa/qa/page/sub_menus/super_sidebar/deploy.rb
deleted file mode 100644
index 30e41b82c79..00000000000
--- a/qa/qa/page/sub_menus/super_sidebar/deploy.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module SubMenus
- module SuperSidebar
- module Deploy
- extend QA::Page::PageConcern
-
- def go_to_package_registry
- open_deploy_submenu("Package Registry")
- end
-
- def go_to_container_registry
- open_deploy_submenu('Container Registry')
- end
-
- private
-
- def open_deploy_submenu(sub_menu)
- open_submenu("Deploy", sub_menu)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/sub_menus/super_sidebar/global_search_modal.rb b/qa/qa/page/sub_menus/super_sidebar/global_search_modal.rb
new file mode 100644
index 00000000000..293c628cd7e
--- /dev/null
+++ b/qa/qa/page/sub_menus/super_sidebar/global_search_modal.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+# rubocop:disable Search/NamespacedClass
+module QA
+ module Page
+ module SubMenus
+ module SuperSidebar
+ module GlobalSearchModal
+ extend QA::Page::PageConcern
+
+ def self.prepended(base)
+ super
+
+ base.class_eval do
+ view 'app/assets/javascripts/super_sidebar/components/global_search/' \
+ 'components/global_search_default_places.vue' do
+ element :_, "'data-qa-places-item': title" # rubocop:disable QA/ElementWithPattern
+ element 'places-item-link'
+ end
+
+ view 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue' do
+ element 'global-search-input'
+ end
+
+ view 'app/assets/javascripts/super_sidebar/components/user_bar.vue' do
+ element 'super-sidebar-search-button'
+ end
+ end
+ end
+
+ def go_to_your_work
+ go_to_places_item("Your work")
+ end
+
+ def go_to_explore
+ go_to_places_item("Explore")
+ end
+
+ def go_to_admin_area
+ go_to_places_item("Admin Area")
+
+ return unless has_text?('Enter admin mode', wait: 1.0)
+
+ Admin::NewSession.perform do |new_session|
+ new_session.set_password(Runtime::User.admin_password)
+ new_session.click_enter_admin_mode
+ end
+ end
+
+ def has_admin_area_link?(wait: Capybara.default_max_wait_time)
+ open_global_search_modal
+
+ has_element?('places-item-link', places_item: "Admin Area", wait: wait)
+ end
+
+ def search_for(term)
+ click_element('super-sidebar-search-button')
+ fill_element('global-search-input', "#{term}\n")
+ end
+
+ def close_global_search_modal_if_shown
+ find_element('global-search-input').send_keys(:escape) if has_element?('global-search-input', wait: 1)
+ end
+
+ private
+
+ def go_to_places_item(places_item)
+ open_global_search_modal
+ click_element('places-item-link', places_item: places_item)
+ end
+
+ def open_global_search_modal
+ click_element('super-sidebar-search-button')
+ end
+ end
+ end
+ end
+ end
+end
+# rubocop:enable Search/NamespacedClass
diff --git a/qa/qa/page/sub_menus/super_sidebar/main.rb b/qa/qa/page/sub_menus/super_sidebar/main.rb
deleted file mode 100644
index aadb24369ea..00000000000
--- a/qa/qa/page/sub_menus/super_sidebar/main.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module SubMenus
- module SuperSidebar
- module Main
- extend QA::Page::PageConcern
-
- def go_to_issues
- click_element(:nav_item_link, submenu_item: 'Issues')
- end
-
- def go_to_merge_requests
- click_element(:nav_item_link, submenu_item: 'Merge requests')
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/sub_menus/super_sidebar/manage.rb b/qa/qa/page/sub_menus/super_sidebar/manage.rb
deleted file mode 100644
index 369171299b2..00000000000
--- a/qa/qa/page/sub_menus/super_sidebar/manage.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module SubMenus
- module SuperSidebar
- module Manage
- extend QA::Page::PageConcern
-
- def go_to_activity
- open_manage_submenu('Activity')
- end
-
- def go_to_members
- open_manage_submenu('Members')
- end
-
- def go_to_labels
- open_manage_submenu('Labels')
- end
-
- private
-
- def open_manage_submenu(sub_menu)
- open_submenu('Manage', sub_menu)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/sub_menus/super_sidebar/operate.rb b/qa/qa/page/sub_menus/super_sidebar/operate.rb
deleted file mode 100644
index 29f23d74307..00000000000
--- a/qa/qa/page/sub_menus/super_sidebar/operate.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module SubMenus
- module SuperSidebar
- module Operate
- extend QA::Page::PageConcern
-
- def go_to_dependency_proxy
- open_operate_submenu('Dependency Proxy')
- end
-
- private
-
- def open_operate_submenu(sub_menu)
- open_submenu('Operate', sub_menu)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/sub_menus/super_sidebar/plan.rb b/qa/qa/page/sub_menus/super_sidebar/plan.rb
deleted file mode 100644
index 839ba89cedb..00000000000
--- a/qa/qa/page/sub_menus/super_sidebar/plan.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module SubMenus
- module SuperSidebar
- module Plan
- extend QA::Page::PageConcern
-
- def go_to_issue_boards
- open_plan_submenu("Issue boards")
- end
-
- def go_to_service_desk
- open_plan_submenu("Service Desk")
- end
-
- def go_to_wiki
- open_plan_submenu("Wiki")
- end
-
- def go_to_milestones
- open_plan_submenu('Milestones')
- end
-
- private
-
- def open_plan_submenu(sub_menu)
- open_submenu("Plan", sub_menu)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/sub_menus/super_sidebar/settings.rb b/qa/qa/page/sub_menus/super_sidebar/settings.rb
deleted file mode 100644
index ff38ab2b043..00000000000
--- a/qa/qa/page/sub_menus/super_sidebar/settings.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module SubMenus
- module SuperSidebar
- module Settings
- extend QA::Page::PageConcern
-
- def go_to_general_settings
- open_settings_submenu('General')
- end
-
- def go_to_integrations_settings
- open_settings_submenu('Integrations')
- end
-
- def go_to_webhooks_settings
- open_settings_submenu('Webhooks')
- end
-
- def go_to_access_token_settings
- open_settings_submenu('Access Tokens')
- end
-
- def go_to_repository_settings
- open_settings_submenu('Repository')
- end
-
- def go_to_ci_cd_settings
- open_settings_submenu('CI/CD')
- end
-
- def go_to_package_settings
- open_settings_submenu('Packages and registries')
- end
-
- private
-
- def open_settings_submenu(sub_menu)
- open_submenu('Settings', sub_menu)
- end
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/user/show.rb b/qa/qa/page/user/show.rb
index 1cfaca2fc57..e5ee943a69d 100644
--- a/qa/qa/page/user/show.rb
+++ b/qa/qa/page/user/show.rb
@@ -4,10 +4,6 @@ module QA
module Page
module User
class Show < Page::Base
- view 'app/views/users/show.html.haml' do
- element :following_tab
- end
-
view 'app/views/users/_follow_user.html.haml' do
element :follow_user_link
end
@@ -25,9 +21,7 @@ module QA
end
def click_following_tab
- return click_element(:nav_item_link, submenu_item: 'Following') if Runtime::Env.super_sidebar_enabled?
-
- click_element(:following_tab)
+ click_element(:nav_item_link, submenu_item: 'Following')
end
def click_user_link(username)
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb
index 5f431103df3..499a9b278e9 100644
--- a/qa/qa/resource/api_fabricator.rb
+++ b/qa/qa/resource/api_fabricator.rb
@@ -231,13 +231,13 @@ module QA
# @example
# wait_for_resource_availability('https://gitlab.com/api/v4/projects/1234')
# @example
- # wait_for_resource_availability(resource_web_url(Resource::Issue.fabricate_via_api!))
+ # wait_for_resource_availability(resource_web_url(create(:issue)))
def wait_for_resource_availability(resource_web_url)
return unless Runtime::Address.valid?(resource_web_url)
Support::Retrier.retry_until(sleep_interval: 3, max_attempts: 5, raise_on_failure: false) do
response_check = get(resource_web_url)
- Runtime::Logger.debug("Resource availability check ... #{response_check.code}")
+ Runtime::Logger.debug("Resource availability check for #{resource_web_url} ... #{response_check.code}")
response_check.code == HTTP_STATUS_OK
end
end
diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb
index 459670add36..fcb901e41f3 100644
--- a/qa/qa/resource/base.rb
+++ b/qa/qa/resource/base.rb
@@ -23,6 +23,13 @@ module QA
new.tap(&prepare_block)
end
+ # All instances of the Resource
+ #
+ # @return [Array<QA::Resource>]
+ def all(api_client = nil, **kwargs)
+ instance(api_client).all(**kwargs)
+ end
+
def fabricate_via_api_unless_fips!
if Runtime::Env.personal_access_tokens_disabled?
fabricate!
@@ -81,6 +88,10 @@ module QA
private
+ def instance(api_client)
+ init { |resource| resource.api_client = api_client || QA::Runtime::API::Client.as_admin }
+ end
+
def do_fabricate!(resource:, prepare_block:)
prepare_block.call(resource) if prepare_block
@@ -163,6 +174,14 @@ module QA
end
end
+ # To be overridden by Resource classes to return a list of all instances of the resource
+ #
+ # @params [Hash] kwargs arguments to be used to query the API to search for resources with a specific criteria
+ # @return [Array]
+ def all(**kwargs)
+ raise NotImplementedError
+ end
+
# Override api reload! and update custom attributes from api_resource
#
api_reload = instance_method(:reload!)
diff --git a/qa/qa/resource/graphql.rb b/qa/qa/resource/graphql.rb
new file mode 100644
index 00000000000..0568551f6b5
--- /dev/null
+++ b/qa/qa/resource/graphql.rb
@@ -0,0 +1,20 @@
+# rubocop:todo Naming/FileName
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ module GraphQL
+ # All GraphQL queries and mutations use the same path, `/graphql`
+ #
+ # @return [String]
+ def api_get_path
+ "/graphql"
+ end
+
+ alias_method :api_post_path, :api_get_path
+ alias_method :api_delete_path, :api_get_path
+ end
+ end
+end
+
+# rubocop:enable Naming/FileName
diff --git a/qa/qa/resource/job.rb b/qa/qa/resource/job.rb
index dc425cc174c..2791e48e295 100644
--- a/qa/qa/resource/job.rb
+++ b/qa/qa/resource/job.rb
@@ -5,7 +5,7 @@ module QA
class Job < Base
attr_accessor :id, :name, :project
- attributes :id, :project
+ attributes :id, :project, :status
def fabricate_via_api!
resource_web_url(api_get)
diff --git a/qa/qa/resource/merge_request_from_fork.rb b/qa/qa/resource/merge_request_from_fork.rb
index 3e849aea862..e80d57a88c9 100644
--- a/qa/qa/resource/merge_request_from_fork.rb
+++ b/qa/qa/resource/merge_request_from_fork.rb
@@ -27,7 +27,9 @@ module QA
Flow::Login.sign_in_unless_signed_in(user: fork.user)
Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform(&:create_merge_request)
- Support::WaitForRequests.wait_for_requests
+ Support::Waiter.wait_until(message: 'Waiting for fork icon to appear') do
+ Page::MergeRequest::Show.perform(&:has_fork_icon?)
+ end
mr_url = current_url
# Sign back in as original user
diff --git a/qa/qa/resource/project_snippet.rb b/qa/qa/resource/project_snippet.rb
index 9a22966efdb..0e546cef8f8 100644
--- a/qa/qa/resource/project_snippet.rb
+++ b/qa/qa/resource/project_snippet.rb
@@ -12,7 +12,7 @@ module QA
def fabricate!
project.visit!
- Page::Project::Menu.perform { |sidebar| sidebar.click_snippets }
+ Page::Project::Menu.perform(&:go_to_snippets)
Page::Project::Snippet::New.perform do |new_snippet|
new_snippet.click_create_first_snippet
diff --git a/qa/qa/resource/snippet.rb b/qa/qa/resource/snippet.rb
index df9843bcfca..1a18235fa93 100644
--- a/qa/qa/resource/snippet.rb
+++ b/qa/qa/resource/snippet.rb
@@ -42,12 +42,6 @@ module QA
@id = Page::Dashboard::Snippet::Show.perform(&:snippet_id)
end
- def fabricate_via_api!
- resource_web_url(api_post)
- rescue ResourceNotFoundError
- super
- end
-
def api_get_path
"/snippets/#{id}"
end
diff --git a/qa/qa/runtime/application_settings.rb b/qa/qa/runtime/application_settings.rb
index 0c88716a01c..58085acd05c 100644
--- a/qa/qa/runtime/application_settings.rb
+++ b/qa/qa/runtime/application_settings.rb
@@ -45,6 +45,20 @@ module QA
set_application_settings(**@original_application_settings.slice(...))
end
+ # Enable the application setting that allows requests from local services to the GitLab instance
+ #
+ # @return [Void]
+ def enable_local_requests
+ set_application_settings(allow_local_requests_from_web_hooks_and_services: true)
+ end
+
+ # Disables the application setting that allows local requests
+ #
+ # @return [Void]
+ def disable_local_requests
+ set_application_settings(allow_local_requests_from_web_hooks_and_services: false)
+ end
+
private
def admin_api_client
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index 7bc4530287c..ce970d02e0a 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -151,6 +151,7 @@ module QA
driver: 'ALL',
server: 'ALL'
}
+
when :safari
if QA::Runtime::Env.remote_mobile_device_name
webdriver_options.platform_name = 'iOS'
@@ -159,9 +160,11 @@ module QA
webdriver_options.add_option('appium:platformVersion', 'latest')
end
when :firefox
- webdriver_options.add_option('acceptInsecureCerts', true) if QA::Runtime::Env.accept_insecure_certs?
+ webdriver_options.accept_insecure_certs = true if QA::Runtime::Env.accept_insecure_certs?
+ webdriver_options.args << "--headless" if QA::Runtime::Env.webdriver_headless?
when :edge
webdriver_options.args << "--window-size=#{DEFAULT_WINDOW_SIZE}"
+ webdriver_options.args << "headless" if QA::Runtime::Env.webdriver_headless?
end
selenium_options = {
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 7c9a6c93335..f88ffd05332 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -667,10 +667,6 @@ module QA
ENV['DEFAULT_CHROME_DOWNLOAD_PATH'] || Dir.tmpdir
end
- def super_sidebar_enabled?
- enabled?(ENV['QA_SUPER_SIDEBAR_ENABLED'], default: true)
- end
-
def require_slack_env!
missing_env = %i[slack_workspace slack_email slack_password].select do |method|
::QA::Runtime::Env.public_send(method).nil?
diff --git a/qa/qa/service/cluster_provider/gcloud.rb b/qa/qa/service/cluster_provider/gcloud.rb
index 28eb902b89e..7993cf4ab4d 100644
--- a/qa/qa/service/cluster_provider/gcloud.rb
+++ b/qa/qa/service/cluster_provider/gcloud.rb
@@ -45,7 +45,7 @@ module QA
end
def install_kubernetes_agent(agent_token:, kas_address:, agent_name: "gitlab-agent")
- shell <<~CMD.tr("\n", ' ')
+ cmd_str = <<~CMD.tr("\n", ' ')
helm repo add gitlab https://charts.gitlab.io &&
helm repo update &&
helm upgrade --install gitlab-agent gitlab/gitlab-agent
@@ -56,6 +56,7 @@ module QA
--set config.kasAddress=#{kas_address}
--set config.kasHeaders="{Cookie: gitlab_canary=#{target_canary?}}"
CMD
+ shell(cmd_str, mask_secrets: [agent_token])
end
def uninstall_kubernetes_agent(agent_name: "gitlab-agent")
@@ -78,7 +79,7 @@ module QA
end
def install_gitlab_workspaces_proxy
- shell <<~CMD.tr("\n", ' ')
+ cmd_str = <<~CMD.tr("\n", ' ')
helm repo add gitlab-workspaces-proxy \
https://gitlab.com/api/v4/projects/gitlab-org%2fremote-development%2fgitlab-workspaces-proxy/packages/helm/devel &&
helm repo update &&
@@ -94,12 +95,14 @@ module QA
--set="auth.signing_key=#{Runtime::Env.workspaces_oauth_signing_key}" \
--set="ingress.host.workspaceDomain=#{Runtime::Env.workspaces_proxy_domain}" \
--set="ingress.host.wildcardDomain=*.#{Runtime::Env.workspaces_proxy_domain}" \
- --set="ingress.tls.workspaceDomainCert=#{Runtime::Env.workspaces_domain_cert}" \
- --set="ingress.tls.workspaceDomainKey=#{Runtime::Env.workspaces_domain_key}" \
- --set="ingress.tls.wildcardDomainCert=#{Runtime::Env.workspaces_wildcard_cert}" \
- --set="ingress.tls.wildcardDomainKey=#{Runtime::Env.workspaces_wildcard_key}" \
+ --set="ingress.tls.workspaceDomainCert=$(cat #{Runtime::Env.workspaces_domain_cert})" \
+ --set="ingress.tls.workspaceDomainKey=$(cat #{Runtime::Env.workspaces_domain_key})" \
+ --set="ingress.tls.wildcardDomainCert=$(cat #{Runtime::Env.workspaces_wildcard_cert})" \
+ --set="ingress.tls.wildcardDomainKey=$(cat #{Runtime::Env.workspaces_wildcard_key})" \
--set="ingress.className=nginx"
CMD
+
+ shell(cmd_str, mask_secrets: [Runtime::Env.workspaces_oauth_app_secret, Runtime::Env.workspaces_oauth_signing_key])
end
def update_dns(load_balancer_ip)
diff --git a/qa/qa/service/docker_run/smocker.rb b/qa/qa/service/docker_run/smocker.rb
index dbc32a22c6e..1f205440f4b 100644
--- a/qa/qa/service/docker_run/smocker.rb
+++ b/qa/qa/service/docker_run/smocker.rb
@@ -4,12 +4,12 @@ module QA
module Service
module DockerRun
class Smocker < Base
- def initialize
+ def initialize(name: 'smocker-server')
@image = 'thiht/smocker:0.17.1'
- @name = 'smocker-server'
+ @name = name
@public_port = 8080
@admin_port = 8081
- super
+ super()
@network_cache = network
end
@@ -38,10 +38,6 @@ module QA
@api = nil
end
- def self.logs
- @container&.logs
- end
-
attr_reader :public_port, :admin_port
def host_name
diff --git a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb
index fc400fbb9c7..d730e1a80d4 100644
--- a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Manage' do
describe 'Group access token', product_group: :authentication_and_authorization do
- let(:group_access_token) { QA::Resource::GroupAccessToken.fabricate_via_api! }
+ let(:group_access_token) { create(:group_access_token) }
let(:api_client) { Runtime::API::Client.new(:gitlab, personal_access_token: group_access_token.token) }
let(:project) do
Resource::Project.fabricate! do |project|
@@ -18,14 +18,10 @@ module QA
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/367064'
) do
expect do
- Resource::File.fabricate_via_api! do |file|
- file.api_client = api_client
- file.project = project
- file.branch = "new_branch_#{SecureRandom.hex(8)}"
- file.commit_message = 'Add new file'
- file.name = "text-#{SecureRandom.hex(8)}.txt"
- file.content = 'New file'
- end
+ create(:file,
+ api_client: api_client,
+ project: project,
+ branch: "new_branch_#{SecureRandom.hex(8)}")
rescue StandardError => e
QA::Runtime::Logger.error("Full failure message: #{e.message}")
raise
@@ -34,7 +30,11 @@ module QA
it(
'can be used to commit via the API',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/367067'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/367067',
+ quarantine: {
+ type: :flaky,
+ issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/396615"
+ }
) do
expect do
Resource::Repository::Commit.fabricate_via_api! do |commit|
diff --git a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
index c13ddb2b746..1c335231515 100644
--- a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
@@ -103,11 +103,11 @@ module QA
def verify_issues_import
issues = imported_project.issues
- issue = Resource::Issue.init do |resource|
- resource.project = imported_project
- resource.iid = issues.first[:iid]
- resource.api_client = user_api_client
- end.reload!
+ issue = build(:issue,
+ project: imported_project,
+ iid: issues.first[:iid],
+ api_client: user_api_client).reload!
+
comments, events = fetch_events_and_comments(issue)
expect(issues.length).to eq(1)
diff --git a/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb
index e9a9f838436..d90a6aea864 100644
--- a/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb
@@ -70,6 +70,16 @@ module QA
"transferred",
"locked",
"unlocked",
+ "deployed",
+ "marked_as_duplicate",
+ "unmarked_as_duplicate",
+ "connected",
+ "disconnected",
+ "moved_columns_in_project",
+ "added_to_project",
+ "removed_from_project",
+ "base_ref_deleted",
+ "converted_to_discussion",
# mentions are supported but they can be reported differently on gitlab's side
# for example mention of issue creation in pr will be reported in the issue on gitlab side
# or referenced in github will still create a 'mentioned in' comment in gitlab
@@ -80,11 +90,7 @@ module QA
let(:api_client) { Runtime::API::Client.as_admin }
- let(:user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.api_client = api_client
- end
- end
+ let(:user) { create(:user, api_client: api_client) }
let(:github_client) do
Octokit::Client.new(
@@ -527,11 +533,7 @@ module QA
logger.debug("= Fetching issue comments =")
Parallel.map(imported_issues, in_threads: Etc.nprocessors) do |issue|
- resource = Resource::Issue.init do |issue_resource|
- issue_resource.project = imported_project
- issue_resource.iid = issue[:iid]
- issue_resource.api_client = api_client
- end
+ resource = build(:issue, project: imported_project, iid: issue[:iid], api_client: api_client)
logger.debug("Fetching events and comments for issue '!#{issue[:iid]}'")
comments = resource.comments(**api_request_params)
diff --git a/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb b/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb
index 783c3a65c7d..280d35854b9 100644
--- a/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/integrations/webhook_events_spec.rb
@@ -53,9 +53,7 @@ module QA
it 'sends an issues and note event',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349723' do
Resource::ProjectWebHook.setup(session: session, issues: true, note: true) do |webhook, smocker|
- issue = Resource::Issue.fabricate_via_api! do |issue_init|
- issue_init.project = webhook.project
- end
+ issue = create(:issue, project: webhook.project)
Resource::ProjectIssueNote.fabricate_via_api! do |note|
note.project = issue.project
@@ -118,9 +116,7 @@ module QA
} do
Resource::ProjectWebHook.setup(fail_mock, session: session, issues: true) do |webhook, smocker|
hook_trigger_times.times do
- Resource::Issue.fabricate_via_api! do |issue_init|
- issue_init.project = webhook.project
- end
+ create(:issue, project: webhook.project)
# using sleep to give rate limiter a chance to activate.
sleep 0.5
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb
index 75203584edd..0f8185a52c5 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb
@@ -13,25 +13,18 @@ module QA
api_client: source_admin_api_client)
end
- let(:imported_subgroup) do
- Resource::Group.init do |group|
- group.api_client = api_client
- group.sandbox = imported_group
- group.path = subgroup.path
- end
- end
+ let(:imported_subgroup) { build(:group, api_client: api_client, sandbox: imported_group, path: subgroup.path) }
before do
- Resource::GroupLabel.fabricate_via_api! do |label|
- label.api_client = source_admin_api_client
- label.group = source_group
- label.title = "source-group-#{SecureRandom.hex(4)}"
- end
- Resource::GroupLabel.fabricate_via_api! do |label|
- label.api_client = source_admin_api_client
- label.group = subgroup
- label.title = "subgroup-#{SecureRandom.hex(4)}"
- end
+ create(:group_label,
+ api_client: source_admin_api_client,
+ group: source_group,
+ title: "source-group-label-#{SecureRandom.hex(4)}")
+
+ create(:group_label,
+ api_client: source_admin_api_client,
+ group: subgroup,
+ title: "source-group-label-#{SecureRandom.hex(4)}")
imported_group # trigger import
end
@@ -53,12 +46,7 @@ module QA
end
context 'with milestones and badges' do
- let(:source_milestone) do
- Resource::GroupMilestone.fabricate_via_api! do |milestone|
- milestone.api_client = source_admin_api_client
- milestone.group = source_group
- end
- end
+ let(:source_milestone) { create(:group_milestone, api_client: source_admin_api_client, group: source_group) }
before do
source_milestone
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
index bff1837f51b..1209d4bfd09 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
@@ -6,11 +6,7 @@ module QA
include_context 'with gitlab project migration'
let!(:source_issue) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.api_client = source_admin_api_client
- issue.project = source_project
- issue.labels = %w[label_one label_two]
- end
+ create(:issue, project: source_project, labels: %w[label_one label_two], api_client: source_admin_api_client)
end
let(:source_issue_comments) do
@@ -23,11 +19,7 @@ module QA
let(:imported_issue) do
issue = imported_issues.first
- Resource::Issue.init do |resource|
- resource.api_client = api_client
- resource.project = imported_projects.first
- resource.iid = issue[:iid]
- end
+ build(:issue, api_client: api_client, project: imported_projects.first, iid: issue[:iid])
end
let(:imported_issue_comments) do
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
index 99f8fb5107e..541f057eba1 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
@@ -331,11 +331,7 @@ module QA
imported_issues = project.issues(auto_paginate: true, attempts: 2)
Parallel.map(imported_issues, in_threads: 6) do |issue|
- resource = Resource::Issue.init do |issue_resource|
- issue_resource.project = project
- issue_resource.iid = issue[:iid]
- issue_resource.api_client = client
- end
+ resource = build(:issue, project: project, iid: issue[:iid], api_client: client)
[issue[:iid], {
url: issue[:web_url],
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
index ed79281b328..f0bedc9f0a4 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
@@ -5,17 +5,10 @@ module QA
describe 'Gitlab migration', product_group: :import_and_integrate do
include_context 'with gitlab project migration'
- let!(:source_member) do
- Resource::User.fabricate_via_api! do |usr|
- usr.api_client = source_admin_api_client
- end.tap(&:set_public_email)
- end
+ let!(:source_member) { create(:user, :set_public_email, api_client: source_admin_api_client) }
let!(:target_member) do
- Resource::User.fabricate_via_api! do |usr|
- usr.api_client = admin_api_client
- usr.email = source_member.email
- end.tap(&:set_public_email)
+ create(:user, :set_public_email, api_client: admin_api_client, email: source_member.email)
end
let(:imported_group_member) do
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
index 307d0493b2a..e393c519e52 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
@@ -8,13 +8,11 @@ module QA
let!(:source_project_with_readme) { true }
let!(:source_mr_reviewer) do
- reviewer = Resource::User.fabricate_via_api! do |usr|
- usr.api_client = source_admin_api_client
- usr.username = "source-reviewer-#{SecureRandom.hex(6)}"
- end
- reviewer.tap do |usr|
- usr.set_public_email
- source_project.add_member(usr, Resource::Members::AccessLevel::MAINTAINER)
+ create(:user,
+ :set_public_email,
+ api_client: source_admin_api_client,
+ username: "source-reviewer-#{SecureRandom.hex(6)}") do |user|
+ source_project.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
end
end
@@ -27,10 +25,7 @@ module QA
end
let!(:mr_reviewer) do
- Resource::User.fabricate_via_api! do |usr|
- usr.api_client = admin_api_client
- usr.email = source_mr_reviewer.email
- end.tap(&:set_public_email)
+ create(:user, :set_public_email, api_client: admin_api_client, email: source_mr_reviewer.email)
end
let!(:source_mr_reviewers) { [source_mr_reviewer.email] }
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
index 100b50abfdb..bde2393d4fa 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
@@ -90,7 +90,11 @@ module QA
it(
'successfully imports repository',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347570'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347570',
+ quarantine: {
+ type: :bug,
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422430'
+ }
) do
expect_project_import_finished_successfully
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
index fcf15b66c11..e7af292ac69 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
@@ -9,13 +9,7 @@ module QA
let!(:tag) { 'v0.0.1' }
let!(:source_project_with_readme) { true }
- let!(:milestone) do
- Resource::ProjectMilestone.fabricate_via_api! do |resource|
- resource.project = source_project
- resource.api_client = source_admin_api_client
- end
- end
-
+ let!(:milestone) { create(:project_milestone, project: source_project, api_client: source_admin_api_client) }
let(:source_release) { comparable_release(source_project.releases.find { |r| r[:tag_name] == tag }) }
let(:imported_release) { comparable_release(imported_releases.find { |r| r[:tag_name] == tag }) }
let(:imported_releases) { imported_project.releases }
diff --git a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
index af0eef290f7..5400d22353a 100644
--- a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
@@ -4,24 +4,17 @@ module QA
RSpec.describe 'Manage' do
describe 'Project access token', product_group: :authentication_and_authorization do
before(:all) do
- @project_access_token = QA::Resource::ProjectAccessToken.fabricate_via_api! do |pat|
- pat.project = create(:project, :with_readme)
- end
-
+ @project_access_token = create(:project_access_token, project: create(:project, :with_readme))
@user_api_client = Runtime::API::Client.new(:gitlab, personal_access_token: @project_access_token.token)
end
context 'for the same project' do
it 'can be used to create a file via the project API', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347858' do
expect do
- Resource::File.fabricate_via_api! do |file|
- file.api_client = @user_api_client
- file.project = @project_access_token.project
- file.branch = "new_branch_#{SecureRandom.hex(8)}"
- file.commit_message = 'Add new file'
- file.name = "text-#{SecureRandom.hex(8)}.txt"
- file.content = 'New file'
- end
+ create(:file,
+ api_client: @user_api_client,
+ project: @project_access_token.project,
+ branch: "new_branch_#{SecureRandom.hex(8)}")
rescue StandardError => e
QA::Runtime::Logger.error("Full failure message: #{e.message}")
raise
@@ -52,14 +45,10 @@ module QA
it 'cannot be used to create a file via the project API', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347860' do
expect do
- Resource::File.fabricate_via_api! do |file|
- file.api_client = @user_api_client
- file.project = @different_project
- file.branch = "new_branch_#{SecureRandom.hex(8)}"
- file.commit_message = 'Add new file'
- file.name = "text-#{SecureRandom.hex(8)}.txt"
- file.content = 'New file'
- end
+ create(:file,
+ api_client: @user_api_client,
+ project: @different_project,
+ branch: "new_branch_#{SecureRandom.hex(8)}")
end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden/)
end
diff --git a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
index d3b702a658c..77e3618e2c7 100644
--- a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Manage', :requires_admin, :skip_live_env, except: { job: %w[review-qa-* gdk-qa-*] } do
describe 'rate limits', :reliable, product_group: :import_and_integrate do
- let(:rate_limited_user) { Resource::User.fabricate_via_api! }
+ let(:rate_limited_user) { create(:user) }
let(:api_client) { Runtime::API::Client.new(:gitlab, user: rate_limited_user) }
let!(:request) { Runtime::API::Request.new(api_client, '/users') }
diff --git a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb
deleted file mode 100644
index 578891b2722..00000000000
--- a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Manage' do
- # TODO: `:reliable` should be added back once https://gitlab.com/gitlab-org/gitlab/-/issues/359278 is resolved
- describe 'User', :requires_admin, product_group: :authentication_and_authorization do
- before(:all) do
- admin_api_client = Runtime::API::Client.as_admin
-
- @user = Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- end
-
- @user_api_client = Runtime::API::Client.new(:gitlab, user: @user)
-
- @sandbox = create(:sandbox, path: "sandbox-for-access-termination-#{SecureRandom.hex(4)}", api_client: admin_api_client)
-
- group = create(:group, path: "group-to-test-access-termination-#{SecureRandom.hex(8)}", sandbox: @sandbox)
-
- @sandbox.add_member(@user)
-
- @project = create(:project, :with_readme, name: 'project-for-user-group-access-termination', group: group)
- end
-
- context 'after parent group membership termination' do
- before do
- @sandbox.remove_member(@user)
- end
-
- it 'is not allowed to push code via the CLI', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347863' do
- QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 2) do
- expect do
- Resource::Repository::Push.fabricate! do |push|
- push.repository_http_uri = @project.repository_http_location.uri
- push.file_name = 'test.txt'
- push.file_content = "# This is a test project named #{@project.name}"
- push.commit_message = 'Add test.txt'
- push.branch_name = "new_branch_#{SecureRandom.hex(8)}"
- push.user = @user
- end
- end.to raise_error(QA::Support::Run::CommandError, /You are not allowed to push code to this project/)
- end
- end
-
- it 'is not allowed to create a file via the API', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347864' do
- QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 2) do
- expect do
- Resource::File.fabricate_via_api! do |file|
- file.api_client = @user_api_client
- file.project = @project
- file.branch = "new_branch_#{SecureRandom.hex(8)}"
- file.commit_message = 'Add new file'
- file.name = 'test.txt'
- file.content = "New file"
- end
- end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden/)
- end
- end
-
- it 'is not allowed to commit via the API', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347865' do
- QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 2) do
- expect do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.api_client = @user_api_client
- commit.project = @project
- commit.branch = "new_branch_#{SecureRandom.hex(8)}"
- commit.start_branch = @project.default_branch
- commit.commit_message = 'Add new file'
- commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
- end
- end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden - You are not allowed to push into this branch/)
- end
- end
- end
-
- after(:all) do
- @sandbox.remove_via_api!
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
index 6935f9de486..ecaa329d800 100644
--- a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
+++ b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
@@ -7,12 +7,8 @@ module QA
include Support::API
describe 'Issue', product_group: :project_management do
- let(:issue) do
- Resource::Issue.fabricate_via_api!
- end
-
+ let(:issue) { create(:issue) }
let(:issue_id) { issue.api_response[:iid] }
-
let(:api_client) { Runtime::API::Client.new(:gitlab) }
before do
diff --git a/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb b/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb
index 9e6e15963c4..019919ec111 100644
--- a/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb
+++ b/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb
@@ -7,12 +7,11 @@ module QA
let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.additional_repository_storage } }
let(:snippet) do
- Resource::Snippet.fabricate_via_api! do |snippet|
- snippet.title = 'Snippet to move storage of'
- snippet.file_name = 'original_file'
- snippet.file_content = 'Original file content'
- snippet.api_client = Runtime::API::Client.as_admin
- end
+ create(:snippet,
+ title: 'Snippet to move storage of',
+ file_name: 'original_file',
+ file_content: 'Original file content',
+ api_client: Runtime::API::Client.as_admin)
end
praefect_manager = Service::PraefectManager.new
diff --git a/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb b/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
index 79974828a2b..ade5d5043dc 100644
--- a/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
@@ -34,10 +34,7 @@ module QA
upstream_project.pipelines.size == 1 && upstream_pipeline.status == 'success'
end
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = upstream_project
- pipeline.variables = [{ key: key, value: value, variable_type: 'env_var' }]
- end
+ create(:pipeline, project: upstream_project, variables: [{ key: key, value: value, variable_type: 'env_var' }])
# Wait for this pipeline to be created
Support::Waiter.wait_until { upstream_project.pipelines.size > 1 }
diff --git a/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb b/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb
index 5b0e0573016..13bc91f2ad4 100644
--- a/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb
@@ -6,11 +6,7 @@ module QA
let!(:admin_api_client) { Runtime::API::Client.as_admin }
let!(:user_api_client) { Runtime::API::Client.new(:gitlab, user: user) }
- let(:user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.api_client = admin_api_client
- end
- end
+ let(:user) { create(:user, api_client: admin_api_client) }
let(:project) { create(:project, name: 'project-for-canceled-schedule') }
diff --git a/qa/qa/specs/features/api/4_verify/file_variable_downstream_pipeline_spec.rb b/qa/qa/specs/features/api/4_verify/file_variable_downstream_pipeline_spec.rb
index 289133b33cc..3d409e40c1f 100644
--- a/qa/qa/specs/features/api/4_verify/file_variable_downstream_pipeline_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/file_variable_downstream_pipeline_spec.rb
@@ -1,19 +1,18 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_security, feature_flag: {
- name: 'ci_prevent_file_var_expansion_downstream_pipeline',
- scope: :project
- } do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_security,
+ feature_flag: { name: 'ci_prevent_file_var_expansion_downstream_pipeline', scope: :project },
+ quarantine: { type: :bug, issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424903' } do
describe 'Pipeline with file variables and downstream pipelines' do
let(:random_string) { Faker::Alphanumeric.alphanumeric(number: 8) }
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
- let!(:project) { create(:project, name: 'upstream-project-with-file-variables') }
+ let!(:upstream_project) { create(:project, name: 'upstream-project-with-file-variables') }
let!(:downstream_project) { create(:project, name: 'downstream-project') }
- let!(:project_runner) do
+ let!(:upstream_project_runner) do
Resource::ProjectRunner.fabricate! do |runner|
- runner.project = project
+ runner.project = upstream_project
runner.name = executor
runner.tags = [executor]
end
@@ -27,15 +26,11 @@ module QA
end
end
- let(:add_ci_file) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.project = project
- commit.commit_message = 'Add .gitlab-ci.yml and child.yml'
- commit.add_files(
- [
- {
- file_path: '.gitlab-ci.yml',
- content: <<~YAML
+ let(:upstream_project_files) do
+ [
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
default:
tags: [#{executor}]
@@ -56,11 +51,11 @@ module QA
strategy: depend
project: #{downstream_project.path_with_namespace}
- YAML
- },
- {
- file_path: 'child.yml',
- content: <<~YAML
+ YAML
+ },
+ {
+ file_path: 'child.yml',
+ content: <<~YAML
default:
tags: [#{executor}]
@@ -75,22 +70,16 @@ module QA
script:
- cat "$MY_FILE_VAR"
- cat "$DOCKER_CA_CERT"
- YAML
- }
- ]
- )
- end
+ YAML
+ }
+ ]
end
- let(:add_downstream_project_ci_file) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.project = downstream_project
- commit.commit_message = 'Add .gitlab-ci.yml'
- commit.add_files(
- [
- {
- file_path: '.gitlab-ci.yml',
- content: <<~YAML
+ let(:downstream_project_file) do
+ [
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
default:
tags: [#{executor}]
@@ -105,91 +94,53 @@ module QA
script:
- cat "$MY_FILE_VAR"
- cat "$DOCKER_CA_CERT"
- YAML
- }
- ]
- )
- end
- end
-
- let(:add_project_file_variables) do
- {
- 'TEST_PROJECT_FILE' => "hello, this is test\n",
- 'DOCKER_CA_CERT' => "This is secret\n"
- }.each do |file_name, content|
- add_file_variable_to_project(project, file_name, content)
- end
- end
-
- let(:upstream_pipeline) do
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = project
- end
- end
-
- def child_pipeline
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = project
- pipeline.id = upstream_pipeline.downstream_pipeline_id(bridge_name: 'trigger_child')
- end
- end
-
- def downstream_project_pipeline
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = downstream_project
- pipeline.id = upstream_pipeline.downstream_pipeline_id(bridge_name: 'trigger_downstream_project')
- end
+ YAML
+ }
+ ]
end
around do |example|
- Runtime::Feature.enable(:ci_prevent_file_var_expansion_downstream_pipeline, project: project)
+ Runtime::Feature.enable(:ci_prevent_file_var_expansion_downstream_pipeline, project: upstream_project)
example.run
- Runtime::Feature.disable(:ci_prevent_file_var_expansion_downstream_pipeline, project: project)
+ Runtime::Feature.disable(:ci_prevent_file_var_expansion_downstream_pipeline, project: upstream_project)
end
before do
- add_project_file_variables
- add_downstream_project_ci_file
- add_ci_file
- upstream_pipeline
- wait_for_pipelines
+ add_file_variables_to_upstream_project
+ add_ci_file(downstream_project, downstream_project_file)
+ add_ci_file(upstream_project, upstream_project_files)
+ Support::Waiter.wait_until(message: 'Wait for first pipeline creation') { upstream_project.pipelines.present? }
+
+ wait_for_pipelines_to_finish
end
after do
- project_runner.remove_via_api!
- downstream_project_runner.remove_via_api!
+ [upstream_project_runner, downstream_project_runner].each(&:remove_via_api!)
end
it(
'creates variable with file path in downstream pipelines and can read file variable content',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/416337'
) do
- child_echo_job = Resource::Job.fabricate_via_api! do |job|
- job.project = project
- job.id = project.job_by_name('child_job_echo')[:id]
- end
+ child_echo_job = create(:job, project: upstream_project,
+ id: upstream_project.job_by_name('child_job_echo')[:id])
- child_cat_job = Resource::Job.fabricate_via_api! do |job|
- job.project = project
- job.id = project.job_by_name('child_job_cat')[:id]
- end
+ child_cat_job = create(:job, project: upstream_project, id: upstream_project.job_by_name('child_job_cat')[:id])
- downstream_project_echo_job = Resource::Job.fabricate_via_api! do |job|
- job.project = downstream_project
- job.id = downstream_project.job_by_name('downstream_job_echo')[:id]
- end
+ downstream_project_echo_job = create(:job,
+ project: downstream_project,
+ id: downstream_project.job_by_name('downstream_job_echo')[:id])
- downstream_project_cat_job = Resource::Job.fabricate_via_api! do |job|
- job.project = downstream_project
- job.id = downstream_project.job_by_name('downstream_job_cat')[:id]
- end
+ downstream_project_cat_job = create(:job,
+ project: downstream_project,
+ id: downstream_project.job_by_name('downstream_job_cat')[:id])
aggregate_failures do
trace = child_echo_job.trace
- expect(trace).to include('run something -f', "#{project.name}.tmp/TEST_PROJECT_FILE")
- expect(trace).to include('docker run --tlscacert=', "#{project.name}.tmp/DOCKER_CA_CERT")
- expect(trace).to include('run --output=', "#{project.name}.tmp/DOCKER_CA_CERT.crt")
- expect(trace).to include('Will read private key from', "#{project.name}.tmp/TEST_PROJECT_FILE")
+ expect(trace).to include('run something -f', "#{upstream_project.name}.tmp/TEST_PROJECT_FILE")
+ expect(trace).to include('docker run --tlscacert=', "#{upstream_project.name}.tmp/DOCKER_CA_CERT")
+ expect(trace).to include('run --output=', "#{upstream_project.name}.tmp/DOCKER_CA_CERT.crt")
+ expect(trace).to include('Will read private key from', "#{upstream_project.name}.tmp/TEST_PROJECT_FILE")
trace = child_cat_job.trace
expect(trace).to have_content('hello, this is test')
@@ -209,23 +160,54 @@ module QA
private
- def add_file_variable_to_project(project, key, value)
- Resource::CiVariable.fabricate_via_api! do |ci_variable|
- ci_variable.project = project
- ci_variable.key = key
- ci_variable.value = value
- ci_variable.variable_type = 'file'
+ def add_file_variables_to_upstream_project
+ {
+ 'TEST_PROJECT_FILE' => "hello, this is test\n",
+ 'DOCKER_CA_CERT' => "This is secret\n"
+ }.each do |file_name, content|
+ Resource::CiVariable.fabricate_via_api! do |ci_variable|
+ ci_variable.project = upstream_project
+ ci_variable.key = file_name
+ ci_variable.value = content
+ ci_variable.variable_type = 'file'
+ end
+ end
+ end
+
+ def add_ci_file(project, files)
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add CI files to project'
+ commit.add_files(files)
end
end
- def wait_for_pipelines
+ def wait_for_pipelines_to_finish
Support::Waiter.wait_until(max_duration: 300, sleep_interval: 10) do
- upstream_pipeline.reload!
upstream_pipeline.status == 'success' &&
child_pipeline.status == 'success' &&
downstream_project_pipeline.status == 'success'
end
end
+
+ # Fetch upstream project's parent pipeline
+ def upstream_pipeline
+ create(:pipeline, project: upstream_project, id: upstream_project.latest_pipeline[:id])
+ end
+
+ # Fetch upstream project's child pipeline
+ def child_pipeline
+ create(:pipeline,
+ project: upstream_project,
+ id: upstream_pipeline.downstream_pipeline_id(bridge_name: 'trigger_child'))
+ end
+
+ # Fetch downstream project's pipeline
+ def downstream_project_pipeline
+ create(:pipeline,
+ project: downstream_project,
+ id: upstream_pipeline.downstream_pipeline_id(bridge_name: 'trigger_downstream_project'))
+ end
end
end
end
diff --git a/qa/qa/specs/features/api/4_verify/file_variable_spec.rb b/qa/qa/specs/features/api/4_verify/file_variable_spec.rb
index d7adc1d8454..1e859d2b5df 100644
--- a/qa/qa/specs/features/api/4_verify/file_variable_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/file_variable_spec.rb
@@ -74,10 +74,7 @@ module QA
'does not expose file variable content with echo',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370791'
) do
- job = Resource::Job.fabricate_via_api! do |job|
- job.project = project
- job.id = project.job_by_name('job_echo')[:id]
- end
+ job = create(:job, project: project, id: project.job_by_name('job_echo')[:id])
aggregate_failures do
trace = job.trace
@@ -92,10 +89,7 @@ module QA
'can read file variable content with cat',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386409'
) do
- job = Resource::Job.fabricate_via_api! do |job|
- job.project = project
- job.id = project.job_by_name('job_cat')[:id]
- end
+ job = job = create(:job, project: project, id: project.job_by_name('job_cat')[:id])
aggregate_failures do
trace = job.trace
@@ -116,9 +110,7 @@ module QA
end
def trigger_pipeline
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = project
- end
+ create(:pipeline, project: project)
end
def wait_for_pipeline
diff --git a/qa/qa/specs/features/api/4_verify/job_downloads_artifacts_spec.rb b/qa/qa/specs/features/api/4_verify/job_downloads_artifacts_spec.rb
new file mode 100644
index 00000000000..d666bcea6e9
--- /dev/null
+++ b/qa/qa/specs/features/api/4_verify/job_downloads_artifacts_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', product_group: :pipeline_security do
+ describe 'Job artifacts' do
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
+ let(:project) { create(:project, name: 'project-for-job-artifacts-fetching') }
+ let(:random_test_string) { Faker::Alphanumeric.alphanumeric(number: 8) }
+ let!(:runner) { create(:project_runner, project: project, name: executor, tags: [executor]) }
+
+ let!(:add_ci_file) do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add CI file for job artifacts test'
+ commit.add_files(
+ [
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ default:
+ tags: ["#{executor}"]
+
+ stages:
+ - build
+ - test
+
+ job_creates_artifacts:
+ stage: build
+ script: mkdir tmp; echo #{random_test_string} > tmp/output.xml
+ artifacts:
+ paths:
+ - tmp
+
+ job_with_default_settings:
+ stage: test
+ script: cat $CI_PROJECT_DIR/tmp/output.xml
+
+ job_with_empty_dependencies:
+ stage: test
+ dependencies: []
+ script: cat $CI_PROJECT_DIR/tmp/output.xml
+ YAML
+ ]
+ )
+ end
+ end
+
+ let(:job_with_default_settings) do
+ create(:job, project: project, id: project.job_by_name('job_with_default_settings')[:id])
+ end
+
+ let(:job_with_empty_dependencies) do
+ create(:job, project: project, id: project.job_by_name('job_with_empty_dependencies')[:id])
+ end
+
+ let(:job_creates_artifacts) do
+ create(:job, project: project, id: project.job_by_name('job_creates_artifacts')[:id])
+ end
+
+ before do
+ # Pipeline is expected to fail here when it finishes because
+ # job_with_empty_dependencies shouldn't be able to read $CI_PROJECT_DIR/tmp/output.xml
+ Support::Waiter.wait_until(message: 'Wait for pipeline to finish') do
+ project.pipelines.present? && project.latest_pipeline[:status] == 'failed'
+ end
+ end
+
+ after do
+ runner.remove_via_api!
+ end
+
+ it 'are not downloaded when dependencies array is set to empty',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/424958' do
+ # If this job fails, the 'failed' status of pipeline is no longer helpful
+ # We should exit the test case here
+ # And might want to see why this job fails for investing purposes
+ expect(job_creates_artifacts.status).to eq('success'),
+ "Expected job to succeed but #{job_creates_artifacts.status} - Trace : \n#{job_creates_artifacts.trace}"
+
+ aggregate_failures 'each job trace' do
+ trace = job_with_default_settings.trace
+ expect(trace).to include('Downloading artifacts from coordinator', random_test_string),
+ 'Job fails to download and open artifact from previous stage as expected.'
+
+ trace = job_with_empty_dependencies.trace
+ expect(trace).to include('cat $CI_PROJECT_DIR/tmp/output.xml', 'No such file or directory'),
+ 'Job downloads and opens artifact from previous stage even though not expected to.'
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb b/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb
index d2b1cbd2c95..446790d84e1 100644
--- a/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb
+++ b/qa/qa/specs/features/api/5_package/container_registry/saas/container_registry_spec.rb
@@ -23,11 +23,7 @@ module QA
end
end
- let!(:project_access_token) do
- QA::Resource::ProjectAccessToken.fabricate_via_api! do |pat|
- pat.project = project
- end
- end
+ let!(:project_access_token) { create(:project_access_token, project: project) }
let(:masked_token) do
use_ci_variable(name: 'PAT', value: project_access_token.token, project: project)
@@ -57,11 +53,9 @@ module QA
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
- docker pull $IMAGE_TAG
- tags:
- - "runner-for-#{project.name}"
test:
- image: dwdraju/alpine-curl-jq:latest
+ image: registry.gitlab.com/gitlab-ci-utils/curl-jq:latest
stage: test
script:
- 'id=$(curl --header "PRIVATE-TOKEN: #{masked_token}" "https://${CI_SERVER_HOST}/api/v4/projects/#{project.id}/registry/repositories" | jq ".[0].id")'
@@ -72,8 +66,6 @@ module QA
- if [ $status_code -ne 200 ]; then exit 1; fi;
- 'status_code=$(curl --head --output /dev/null --write-out "%{http_code}\n" --header "PRIVATE-TOKEN: #{masked_token}" "https://${CI_SERVER_HOST}/api/v4/projects/#{project.id}/registry/repositories/$id/tags/master")'
- if [ $status_code -ne 404 ]; then exit 1; fi;
- tags:
- - "runner-for-#{project.name}"
YAML
end
@@ -96,7 +88,7 @@ module QA
end
Support::Retrier.retry_until(
- max_duration: 10,
+ max_duration: 30,
sleep_interval: 1,
message: "Waiting for pipeline to start"
) do
diff --git a/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb b/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb
index 6f8b6df6658..6284f8b3869 100644
--- a/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb
+++ b/qa/qa/specs/features/api/9_data_stores/user_inherited_access_spec.rb
@@ -12,11 +12,7 @@ module QA
end
context 'when added to parent group' do
- let!(:parent_group_user) do
- Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- end
- end
+ let!(:parent_group_user) { create(:user, api_client: admin_api_client) }
let!(:parent_group_user_api_client) do
Runtime::API::Client.new(:gitlab, user: parent_group_user)
@@ -57,14 +53,10 @@ module QA
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363348'
) do
expect do
- Resource::File.fabricate_via_api! do |file|
- file.api_client = parent_group_user_api_client
- file.project = sub_group_project
- file.branch = "new_branch_#{SecureRandom.hex(8)}"
- file.commit_message = 'Add new file'
- file.name = 'test.txt'
- file.content = "New file"
- end
+ create(:file,
+ api_client: parent_group_user_api_client,
+ project: sub_group_project,
+ branch: "new_branch_#{SecureRandom.hex(8)}")
end.not_to raise_error
end
@@ -98,11 +90,7 @@ module QA
create(:project, :with_readme, name: 'parent-group-project-to-test-user-access', group: parent_group)
end
- let!(:sub_group_user) do
- Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- end
- end
+ let!(:sub_group_user) { create(:user, api_client: admin_api_client) }
let!(:sub_group_user_api_client) do
Runtime::API::Client.new(:gitlab, user: sub_group_user)
@@ -138,14 +126,10 @@ module QA
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/363343'
) do
expect do
- Resource::File.fabricate_via_api! do |file|
- file.api_client = sub_group_user_api_client
- file.project = parent_group_project
- file.branch = "new_branch_#{SecureRandom.hex(8)}"
- file.commit_message = 'Add new file'
- file.name = 'test.txt'
- file.content = "New file"
- end
+ create(:file,
+ api_client: sub_group_user_api_client,
+ project: parent_group_project,
+ branch: "new_branch_#{SecureRandom.hex(8)}")
end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden/)
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
index a2eca6278d0..b576ab75c69 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb
@@ -17,11 +17,10 @@ module QA
end
let(:imported_issue) do
- Resource::Issue.init do |resource|
- resource.project = imported_project
- resource.iid = imported_project.issues.first[:iid]
- resource.api_client = api_client
- end.reload!
+ build(:issue,
+ project: imported_project,
+ iid: imported_project.issues.first[:iid],
+ api_client: api_client).reload!
end
let(:imported_issue_events) do
diff --git a/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb
index 99be4e87251..9e6d79316ac 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/integrations/slash_commands_spec.rb
@@ -55,12 +55,7 @@ module QA
end
context 'with gitlab issue' do
- let!(:issue) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- end
- end
-
+ let!(:issue) { create(:issue, project: project) }
let(:comment) { "Comment #{SecureRandom.hex(6)}" }
it 'displays an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377891' do
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
index f2582d47723..3a1bf2b5fa2 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
@@ -3,17 +3,9 @@
module QA
RSpec.describe 'Manage', :requires_admin, :skip_live_env, :reliable do
describe '2FA', product_group: :authentication_and_authorization do
- let(:owner_user) do
- Resource::User.fabricate_via_api! do |usr|
- usr.api_client = admin_api_client
- end
- end
+ let(:owner_user) { create(:user, api_client: admin_api_client) }
- let(:developer_user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.api_client = admin_api_client
- end
- end
+ let(:developer_user) { create(:user, api_client: admin_api_client) }
let(:sandbox_group) do
Resource::Sandbox.fabricate! do |sandbox_group|
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb
index 9484f15f35d..d533855688d 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb
@@ -3,7 +3,7 @@
module QA
context 'Manage', :reliable, :requires_admin, :skip_live_env, product_group: :authentication_and_authorization do
describe '2FA' do
- let!(:user) { Resource::User.fabricate_via_api! }
+ let!(:user) { create(:user) }
let!(:user_api_client) { Runtime::API::Client.new(:gitlab, user: user) }
let(:address) { QA::Runtime::Scenario.gitlab_address }
let(:uri) { URI.parse(address) }
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
index 89f15759b54..d7f088e08e3 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
@@ -6,12 +6,7 @@ module QA
let(:admin_api_client) { Runtime::API::Client.as_admin }
let(:owner_api_client) { Runtime::API::Client.new(:gitlab, user: owner_user) }
- let!(:owner_user) do
- Resource::User.fabricate_via_api! do |usr|
- usr.username = "owner_user_#{SecureRandom.hex(4)}"
- usr.api_client = admin_api_client
- end
- end
+ let!(:owner_user) { create(:user, username: "owner_user_#{SecureRandom.hex(4)}", api_client: admin_api_client) }
let(:sandbox_group) do
Flow::Login.sign_in(as: owner_user)
@@ -22,30 +17,31 @@ module QA
end
let(:group) do
- create(:group, sandbox: sandbox_group, api_client: owner_api_client, path: "group-with-2fa-#{SecureRandom.hex(8)}")
+ create(:group, sandbox: sandbox_group, api_client: owner_api_client,
+ path: "group-with-2fa-#{SecureRandom.hex(8)}")
end
- let(:developer_user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.username = "developer_user_#{SecureRandom.hex(4)}"
- resource.api_client = admin_api_client
- end
- end
+ let(:developer_user) { create(:user, username: "developer_user_#{SecureRandom.hex(4)}", api_client: admin_api_client) }
- let(:two_fa_expected_text) { /The group settings for.*require you to enable Two-Factor Authentication for your account.*You need to do this before/ }
+ let(:two_fa_expected_text) do
+ /The group settings for.*require you to enable Two-Factor Authentication for your account.*You need to do this before/
+ end
before do
group.add_member(developer_user, Resource::Members::AccessLevel::DEVELOPER)
end
+ after do
+ group.set_require_two_factor_authentication(value: 'false')
+ group.remove_via_api! do |resource|
+ resource.api_client = admin_api_client
+ end
+ developer_user.remove_via_api!
+ end
+
it(
'allows enforcing 2FA via UI and logging in with 2FA',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347931',
- quarantine: {
- type: :bug,
- only: { condition: -> { QA::Runtime::Env.super_sidebar_enabled? } },
- issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/409336'
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347931'
) do
enforce_two_factor_authentication_on_group(group)
@@ -68,21 +64,13 @@ module QA
expect(Page::Main::Menu.perform(&:signed_in?)).to be_truthy
end
- after do
- group.set_require_two_factor_authentication(value: 'false')
- group.remove_via_api! do |resource|
- resource.api_client = admin_api_client
- end
- developer_user.remove_via_api!
- end
-
# We are intentionally using the UI to enforce 2FA to exercise the flow with UI.
# Any future tests should use the API for this purpose.
def enforce_two_factor_authentication_on_group(group)
Flow::Login.while_signed_in(as: owner_user) do
group.visit!
- Page::Group::Menu.perform(&:click_group_general_settings_item)
+ Page::Group::Menu.perform(&:go_to_general_settings)
Page::Group::Settings::General.perform(&:set_require_2fa_enabled)
QA::Support::Retrier.retry_on_exception(reload_page: page) do
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb
index b2aa3166b9d..c7bfe4daa84 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_oauth_and_oidc_with_gitlab_as_idp_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Manage', :skip_live_env, requires_admin: 'creates users and instance OAuth application',
product_group: :authentication_and_authorization do
- let!(:user) { Resource::User.fabricate_via_api! }
+ let!(:user) { create(:user) }
let(:consumer_host) { "http://#{consumer_name}.#{Runtime::Env.running_in_ci? ? 'test' : 'bridge'}" }
let(:instance_oauth_app) do
Resource::InstanceOauthApplication.fabricate! do |application|
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
index 5f31ac412d6..6b22a7f6eec 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
@@ -17,7 +17,12 @@ module QA
RSpec.describe 'Manage', :skip_signup_disabled, :requires_admin, product_group: :authentication_and_authorization do
describe 'while LDAP is enabled', :orchestrated, :ldap_no_tls,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347934' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347934',
+ quarantine: {
+ only: { job: 'airgapped' },
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/414247',
+ type: :investigating
+ } do
before do
# When LDAP is enabled, a previous test might have created a token for the LDAP 'tanuki' user who is not an admin
# So we need to set it to nil in order to create a new token for admin user so that we are able to set_application_settings
@@ -43,7 +48,12 @@ module QA
end
describe 'standard', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347867' do
- context 'when admin approval is not required' do
+ context 'when admin approval is not required',
+ quarantine: {
+ only: { job: 'airgapped' },
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/414247',
+ type: :investigating
+ } do
before(:all) do
set_require_admin_approval_after_user_signup(false)
end
@@ -51,11 +61,7 @@ module QA
it_behaves_like 'registration and login'
context 'when user account is deleted' do
- let(:user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.api_client = admin_api_client
- end
- end
+ let(:user) { create(:user, api_client: admin_api_client) }
before do
# Use the UI instead of API to delete the account since
@@ -101,7 +107,13 @@ module QA
end
end
- context 'when admin approval is required' do
+ context 'when admin approval is required',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347871',
+ quarantine: {
+ only: { job: 'airgapped' },
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/414247',
+ type: :investigating
+ } do
let(:signed_up_waiting_approval_text) do
'You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator.'
end
@@ -125,8 +137,7 @@ module QA
set_require_admin_approval_after_user_signup(false)
end
- it 'allows user login after approval',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347871' do
+ it 'allows user login after approval' do
user # sign up user
expect(page).to have_text(signed_up_waiting_approval_text)
diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb
index ce5d9307769..27ce6565068 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb
@@ -5,12 +5,7 @@ module QA
describe 'Impersonation tokens', :requires_admin, product_group: :authentication_and_authorization do
let(:admin_api_client) { Runtime::API::Client.as_admin }
- let!(:user) do
- Resource::User.fabricate_via_api! do |usr|
- usr.api_client = admin_api_client
- usr.hard_delete_on_api_removal = true
- end
- end
+ let!(:user) { create(:user, :hard_delete, api_client: admin_api_client) }
it(
'can be created and revoked via the UI',
diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/user_access_termination_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/user_access_termination_spec.rb
new file mode 100644
index 00000000000..b67143276e8
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/user/user_access_termination_spec.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Manage' do
+ # TODO: `:reliable` should be added back once https://gitlab.com/gitlab-org/gitlab/-/issues/359278 is resolved
+ describe 'User', :requires_admin, product_group: :authentication_and_authorization do
+ # rubocop:disable RSpec/InstanceVariable
+ before(:all) do
+ admin_api_client = Runtime::API::Client.as_admin
+
+ @user = create(:user, api_client: admin_api_client)
+
+ @user_api_client = Runtime::API::Client.new(:gitlab, user: @user)
+
+ # Use UI to create the top-level group as the `top_level_group_creation_enabled` feature flag
+ # could be disabled on live environments
+ @sandbox = Resource::Sandbox.fabricate! do |sandbox_group|
+ sandbox_group.path = "sandbox-for-access-termination-#{SecureRandom.hex(4)}"
+ end
+
+ group = create(:group, path: "group-to-test-access-termination-#{SecureRandom.hex(8)}", sandbox: @sandbox)
+
+ @sandbox.add_member(@user)
+
+ @project = create(:project, :with_readme, name: 'project-for-user-group-access-termination', group: group)
+ end
+
+ after(:all) do
+ @sandbox.remove_via_api!
+ end
+
+ context 'when parent group membership is terminated' do
+ before do
+ @sandbox.remove_member(@user)
+ end
+
+ it 'is not allowed to push code via the CLI',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347863' do
+ QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 2) do
+ expect do
+ Resource::Repository::Push.fabricate! do |push|
+ push.repository_http_uri = @project.repository_http_location.uri
+ push.file_name = 'test.txt'
+ push.file_content = "# This is a test project named #{@project.name}"
+ push.commit_message = 'Add test.txt'
+ push.branch_name = "new_branch_#{SecureRandom.hex(8)}"
+ push.user = @user
+ end
+ end.to raise_error(QA::Support::Run::CommandError, /You are not allowed to push code to this project/)
+ end
+ end
+
+ it 'is not allowed to create a file via the API',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347864' do
+ QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 2) do
+ expect do
+ create(:file,
+ api_client: @user_api_client,
+ project: @project,
+ branch: "new_branch_#{SecureRandom.hex(8)}")
+ end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden/)
+ end
+ end
+
+ it 'is not allowed to commit via the API',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347865' do
+ QA::Support::Retrier.retry_on_exception(max_attempts: 5, sleep_interval: 2) do
+ expect do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.api_client = @user_api_client
+ commit.project = @project
+ commit.branch = "new_branch_#{SecureRandom.hex(8)}"
+ commit.start_branch = @project.default_branch
+ commit.commit_message = 'Add new file'
+ commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
+ end
+ end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError,
+ /403 Forbidden - You are not allowed to push into this branch/)
+ end
+ end
+ end
+ # rubocop:enable RSpec/InstanceVariable
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb
index 63d30da9ec3..b2cb1cd309f 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/design_management/add_design_content_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Plan', product_group: :product_planning do
describe 'Design Management' do
- let(:issue) { Resource::Issue.fabricate_via_api! }
+ let(:issue) { create(:issue) }
let(:design_filename) { 'banana_sample.gif' }
let(:design) { Runtime::Path.fixture('designs', design_filename) }
let(:annotation) { "This design is great!" }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
index afc7e8202e2..8b6c35ea63d 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
@@ -18,7 +18,7 @@ module QA
it 'is received by a user for project invitation', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347961' do
project.visit!
- Page::Project::Menu.perform(&:click_members)
+ Page::Project::Menu.perform(&:go_to_members)
Page::Project::Members.perform do |member_settings|
member_settings.add_member(user.username)
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
index 5d8f9f7d7b3..d7eb3fb0e47 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
@@ -3,11 +3,10 @@
module QA
RSpec.describe 'Plan', :reliable, product_group: :project_management do
let!(:user) do
- Resource::User.fabricate_via_api! do |user|
- user.name = "QA User <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;"
- user.password = "pw_#{SecureRandom.hex(12)}"
- user.api_client = Runtime::API::Client.as_admin
- end
+ create(:user,
+ name: "QA User <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;",
+ password: "pw_#{SecureRandom.hex(12)}",
+ api_client: Runtime::API::Client.as_admin)
end
let!(:project) { create(:project, name: 'xss-test-for-mentions-project') }
@@ -18,9 +17,7 @@ module QA
project.add_member(user)
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- end.visit!
+ create(:issue, project: project).visit!
end
after do
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
index d446a773809..a1c4f49c58a 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
@@ -5,7 +5,7 @@ module QA
describe 'collapse comments in issue discussions' do
let(:my_first_reply) { 'My first reply' }
let(:one_reply) { '1 reply' }
- let(:issue) { Resource::Issue.fabricate_via_api! }
+ let(:issue) { create(:issue) }
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
index 45c7f307834..67bb4d0bf72 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
@@ -8,11 +8,7 @@ module QA
before do
Flow::Login.sign_in
- 2.times do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- end
- end
+ create_list(:issue, 2, project: project)
project.visit!
Page::Project::Menu.perform(&:go_to_issues)
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
index 8af39cb6a82..83f9573fbf8 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
@@ -6,7 +6,7 @@ module QA
before do
Flow::Login.sign_in
- Resource::Issue.fabricate_via_api!.visit!
+ create(:issue).visit!
end
it 'filters comments and activities in an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347948' do
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
index c85ea5e8a69..f1306949716 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
@@ -8,9 +8,7 @@ module QA
before do
Flow::Login.sign_in
- Resource::Issue.fabricate_via_api! do |issue|
- issue.title = issue_title
- end.project.visit!
+ create(:issue, title: issue_title).project.visit!
end
it 'shows issue suggestions when creating a new issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347995' do
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
index b2dca4fc312..109331630d7 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
@@ -22,7 +22,7 @@ module QA
user
Flow::Login.sign_in_as_admin
project.visit!
- Page::Project::Menu.perform(&:click_members)
+ Page::Project::Menu.perform(&:go_to_members)
Page::Project::Members.perform do |members|
members.add_member(user.username)
end
@@ -36,9 +36,7 @@ module QA
issue.project = project
end.visit!
else
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- end.visit!
+ create(:issue, project: project).visit!
end
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
index d282b0dbbd5..09b0ec25099 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
@@ -15,11 +15,7 @@ module QA
end
it 'update without refresh', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347941' do
- issue = Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- issue.assignee_ids = [user1.id]
- end
-
+ issue = create(:issue, project: project, assignee_ids: [user1.id])
issue.visit!
Page::Project::Issue::Show.perform do |show|
diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb
index c3c2ad68abf..1a03da20355 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb
@@ -12,11 +12,7 @@ module QA
let(:project) { create(:project, name: "project-to-test-milestones-#{SecureRandom.hex(4)}", group: group) }
- let(:issue) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- end
- end
+ let(:issue) { create(:issue, project: project) }
before do
Flow::Login.sign_in
@@ -48,26 +44,14 @@ module QA
end
context 'Group milestone' do
- let(:milestone) do
- Resource::GroupMilestone.fabricate_via_api! do |milestone|
- milestone.group = group
- milestone.start_date = start_date
- milestone.due_date = due_date
- end
- end
+ let(:milestone) { create(:group_milestone, group: group, start_date: start_date, due_date: due_date) }
it_behaves_like 'milestone assigned to existing issue', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347964'
it_behaves_like 'milestone assigned to new issue', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347965'
end
context 'Project milestone' do
- let(:milestone) do
- Resource::ProjectMilestone.fabricate_via_api! do |milestone|
- milestone.project = project
- milestone.start_date = start_date
- milestone.due_date = due_date
- end
- end
+ let(:milestone) { create(:project_milestone, project: project, start_date: start_date, due_date: due_date) }
it_behaves_like 'milestone assigned to existing issue', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347962'
it_behaves_like 'milestone assigned to new issue', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347963'
diff --git a/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb
index 3d4ec8a422e..582270c7940 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/pages/new_static_page_spec.rb
@@ -14,21 +14,17 @@ module QA
describe 'Pages', product_group: :knowledge do
let!(:project) { create(:project, name: 'gitlab-pages-projects', template_name: :plainhtml) }
let(:pipeline) do
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = project
- pipeline.variables = [
+ create(:pipeline,
+ project: project,
+ variables: [
{ key: :CI_PAGES_DOMAIN, value: 'nip.io', variable_type: :env_var },
{ key: :CI_PAGES_URL, value: 'http://127.0.0.1.nip.io', variable_type: :env_var }
- ]
- end
+ ])
end
before do
Flow::Login.sign_in
- Resource::ProjectRunner.fabricate_via_api! do |runner|
- runner.project = project
- runner.executor = :docker
- end
+ create(:project_runner, project: project, executor: :docker)
pipeline.visit!
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb
index 19c9ac6c238..9881b1ad6b8 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/project_wiki/project_based_content_creation_spec.rb
@@ -18,7 +18,7 @@ module QA
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347809' do
project.visit!
- Page::Project::Menu.perform(&:click_wiki)
+ Page::Project::Menu.perform(&:go_to_wiki)
Page::Project::Wiki::Show.perform(&:click_create_your_first_page)
Page::Project::Wiki::Edit.perform do |edit|
diff --git a/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb
index 87a0cf1b310..91e7a7523b0 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb
@@ -4,35 +4,25 @@ module QA
RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Related issues' do
let(:project) { create(:project, name: 'project-to-test-related-issues') }
- let(:issue_1) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- end
- end
-
- let(:issue_2) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- end
- end
+ let(:issues) { create_list(:issue, 2, project: project) }
before do
Flow::Login.sign_in
end
it 'relates and unrelates one issue to/from another', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347994' do
- issue_1.visit!
+ issues.first.visit!
Page::Project::Issue::Show.perform do |show|
max_wait = 60
- show.relate_issue(issue_2)
+ show.relate_issue(issues.last)
- expect(show.related_issuable_item).to have_text(issue_2.title, wait: max_wait)
+ expect(show.related_issuable_item).to have_text(issues.last.title, wait: max_wait)
show.click_remove_related_issue_button
- expect(show).not_to have_text(issue_2.title, wait: max_wait)
+ expect(show).not_to have_text(issues.last.title, wait: max_wait)
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb
index 878c4dea26e..1e84bf34135 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb
@@ -20,7 +20,7 @@ module QA
Runtime::Env.transient_trials.times do |i|
QA::Runtime::Logger.info("Transient bug test action - Trial #{i}")
- Resource::Issue.fabricate_via_api!.visit!
+ create(:issue).visit!
Page::Project::Issue::Show.perform do |issue_page|
issue_page.select_all_activities_filter
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
index 89b43e88bde..8d6f3343e9c 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
@@ -35,14 +35,9 @@ module QA
) do
gitlab_account_user_name = Resource::User.default.reload!.name
- milestone = Resource::ProjectMilestone.fabricate_via_api! do |milestone|
- milestone.project = project
- end
+ milestone = create(:project_milestone, project: project)
- label = Resource::ProjectLabel.fabricate_via_api! do |label|
- label.project = project
- label.title = 'foo::label'
- end
+ label = create(:project_label, project: project, title: 'foo::label')
Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request|
merge_request.title = merge_request_title
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/file/delete_file_via_web_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/file/delete_file_via_web_spec.rb
index 76243066476..1a63b2beae8 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/file/delete_file_via_web_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/file/delete_file_via_web_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do
describe 'File management', product_group: :source_code do
- let(:file) { Resource::File.fabricate_via_api! }
+ let(:file) { create(:file) }
commit_message_for_delete = 'QA Test - Delete file'
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/file/edit_file_via_web_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/file/edit_file_via_web_spec.rb
index 397796b76e5..ac70165f107 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/file/edit_file_via_web_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/file/edit_file_via_web_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create', :reliable do
describe 'File management', product_group: :source_code do
- let(:file) { Resource::File.fabricate_via_api! }
+ let(:file) { create(:file) }
updated_file_content = 'QA Test - Updated file content'
commit_message_for_update = 'QA Test - Update file'
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb
index 5e221d06815..aca5275a289 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/file/file_with_unusual_name_spec.rb
@@ -12,12 +12,10 @@ module QA
context 'when file name starts with a dash and contains hash, semicolon, colon, and question mark' do
it 'renders repository file tree correctly', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347714' do
- Resource::File.fabricate_via_api! do |file|
- file.project = project
- file.commit_message = 'Add new file'
- file.name = "test-folder/#{file_name}"
- file.content = "### Heading\n\n[Example link](https://example.com/)"
- end
+ create(:file,
+ project: project,
+ name: "test-folder/#{file_name}",
+ content: "### Heading\n\n[Example link](https://example.com/)")
project.visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb
index 8c8834b44a0..24ef490b3de 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/license_detection_spec.rb
@@ -19,8 +19,10 @@ module QA
project.visit!
- Page::Project::Show.perform do |show|
- expect(show).to have_license(rendered_license_name)
+ Page::Project::Show.perform do |project|
+ Support::Waiter.wait_until(reload_page: project, message: 'Waiting for licence') do
+ project.has_license?(rendered_license_name)
+ end
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
index 4f45feb1b0a..25a289f4e19 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
@@ -26,6 +26,7 @@ module QA
mirror_settings.repository_url = target_project_uri
mirror_settings.mirror_direction = 'Push'
mirror_settings.authentication_method = 'Password'
+ mirror_settings.username = Runtime::User.username
mirror_settings.password = Runtime::User.password
mirror_settings.mirror_repository
mirror_settings.update(target_project_uri) # rubocop:disable Rails/SaveBang
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
index 4cd371b524d..e430781412d 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
@@ -25,6 +25,7 @@ module QA
mirror_settings.repository_url = target_project_uri
mirror_settings.mirror_direction = 'Push'
mirror_settings.authentication_method = 'Password'
+ mirror_settings.username = Runtime::User.username
mirror_settings.password = Runtime::User.password
mirror_settings.mirror_repository
mirror_settings.update(target_project_uri) # rubocop:disable Rails/SaveBang
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
index 4f2e657fada..309ef82ee29 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/user_views_commit_diff_patch_spec.rb
@@ -5,9 +5,7 @@ module QA
describe 'Commit data', :reliable, product_group: :source_code do
before(:context) do
# Get the user's details to confirm they're included in the email patch
- @user = Resource::User.fabricate_via_api! do |user|
- user.username = Runtime::User.username
- end
+ @user = create(:user, username: Runtime::User.username)
project_push = Resource::Repository::ProjectPush.fabricate! do |push|
push.file_name = 'README.md'
@@ -20,14 +18,13 @@ module QA
# add second file to repo to enable diff from initial commit
@commit_message = 'Add second file'
- Resource::File.fabricate_via_api! do |file|
- file.project = @project
- file.name = 'second'
- file.content = 'second file content'
- file.commit_message = @commit_message
- file.author_name = @user.name
- file.author_email = @user.public_email
- end
+ create(:file,
+ project: @project,
+ name: 'second',
+ content: 'second file content',
+ commit_message: @commit_message,
+ author_name: @user.name,
+ author_email: @user.public_email)
end
def view_commit
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
index fba12d25640..577251b2e7d 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
@@ -4,19 +4,17 @@ module QA
RSpec.describe 'Create', product_group: :source_code do
describe 'Multiple file snippet' do
let(:personal_snippet) do
- Resource::Snippet.fabricate_via_api! do |snippet|
- snippet.title = 'Personal snippet to add file to'
- snippet.file_name = 'Original file name'
- snippet.file_content = 'Original file content'
- end
+ create(:snippet,
+ title: 'Personal snippet to add file to',
+ file_name: 'Original file name',
+ file_content: 'Original file content')
end
let(:project_snippet) do
- Resource::ProjectSnippet.fabricate_via_api! do |snippet|
- snippet.title = 'Project snippet to add file to'
- snippet.file_name = 'Original file name'
- snippet.file_content = 'Original file content'
- end
+ create(:project_snippet,
+ title: 'Project snippet to add file to',
+ file_name: 'Original file name',
+ file_content: 'Original file content')
end
before do
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
index ce4fd6fff4e..667601b7bca 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
@@ -8,29 +8,25 @@ module QA
let(:third_file_content) { 'Third file content' }
let(:personal_snippet) do
- Resource::Snippet.fabricate_via_api! do |snippet|
- snippet.title = 'Personal snippet to copy file contents from'
- snippet.file_name = 'First file name'
- snippet.file_content = first_file_content
-
- snippet.add_files do |files|
- files.append(name: 'Second file name', content: second_file_content)
- files.append(name: 'Third file name', content: third_file_content)
- end
- end
+ create(:snippet,
+ title: 'Personal snippet to copy file contents from',
+ file_name: 'First file name',
+ file_content: first_file_content,
+ files: [
+ { name: 'Second file name', content: second_file_content },
+ { name: 'Third file name', content: third_file_content }
+ ])
end
let(:project_snippet) do
- Resource::ProjectSnippet.fabricate_via_api! do |snippet|
- snippet.title = 'Project snippet to copy file contents from'
- snippet.file_name = 'First file name'
- snippet.file_content = first_file_content
-
- snippet.add_files do |files|
- files.append(name: 'Second file name', content: second_file_content)
- files.append(name: 'Third file name', content: third_file_content)
- end
- end
+ create(:project_snippet,
+ title: 'Project snippet to copy file contents from',
+ file_name: 'First file name',
+ file_content: first_file_content,
+ files: [
+ { name: 'Second file name', content: second_file_content },
+ { name: 'Third file name', content: third_file_content }
+ ])
end
let(:files) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
index 8d8f153dc8e..bc511670e1c 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
@@ -4,27 +4,23 @@ module QA
RSpec.describe 'Create' do
describe 'Multiple file snippet', :reliable, product_group: :source_code do
let(:personal_snippet) do
- Resource::Snippet.fabricate_via_api! do |snippet|
- snippet.title = 'Personal snippet to delete file from'
- snippet.file_name = 'Original file name'
- snippet.file_content = 'Original file content'
-
- snippet.add_files do |files|
- files.append(name: 'Second file name', content: 'Second file content')
- end
- end
+ create(:snippet,
+ title: 'Personal snippet to delete file from',
+ file_name: 'Original file name',
+ file_content: 'Original file content',
+ files: [
+ { name: 'Second file name', content: 'Second file content' }
+ ])
end
let(:project_snippet) do
- Resource::ProjectSnippet.fabricate_via_api! do |snippet|
- snippet.title = 'Project snippet to delete file from'
- snippet.file_name = 'Original file name'
- snippet.file_content = 'Original file content'
-
- snippet.add_files do |files|
- files.append(name: 'Second file name', content: 'Second file content')
- end
- end
+ create(:project_snippet,
+ title: 'Project snippet to delete file from',
+ file_name: 'Original file name',
+ file_content: 'Original file content',
+ files: [
+ { name: 'Second file name', content: 'Second file content' }
+ ])
end
before do
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb
index 6180b9e6585..aa794ebe115 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb
@@ -4,45 +4,34 @@ module QA
RSpec.describe 'Create', product_group: :source_code do
describe 'Snippet index page' do
let(:personal_snippet_with_single_file) do
- Resource::Snippet.fabricate_via_api! do |snippet|
- snippet.title = "Personal snippet with one file-#{SecureRandom.hex(8)}"
- snippet.visibility = 'Public'
- end
+ create(:snippet, title: "Personal snippet with one file-#{SecureRandom.hex(8)}")
end
let(:personal_snippet_with_multiple_files) do
- Resource::Snippet.fabricate_via_api! do |snippet|
- snippet.title = "Personal snippet with multiple files-#{SecureRandom.hex(8)}"
- snippet.visibility = 'Private'
- snippet.file_name = 'First file name'
- snippet.file_content = 'first file content'
-
- snippet.add_files do |files|
- files.append(name: 'Second file name', content: 'second file content')
- files.append(name: 'Third file name', content: 'third file content')
- end
- end
+ create(:snippet,
+ :private,
+ title: "Personal snippet with multiple files-#{SecureRandom.hex(8)}",
+ file_name: 'First file name',
+ file_content: 'first file content',
+ files: [
+ { name: 'Second file name', content: 'second file content' },
+ { name: 'Third file name', content: 'third file content' }
+ ])
end
let(:project_snippet_with_single_file) do
- Resource::ProjectSnippet.fabricate_via_api! do |snippet|
- snippet.title = "Project snippet with one file-#{SecureRandom.hex(8)}"
- snippet.visibility = 'Private'
- end
+ create(:project_snippet, :private, title: "Project snippet with one file-#{SecureRandom.hex(8)}")
end
let(:project_snippet_with_multiple_files) do
- Resource::ProjectSnippet.fabricate_via_api! do |snippet|
- snippet.title = "Project snippet with multiple files-#{SecureRandom.hex(8)}"
- snippet.visibility = 'Public'
- snippet.file_name = 'First file name'
- snippet.file_content = 'first file content'
-
- snippet.add_files do |files|
- files.append(name: 'Second file name', content: 'second file content')
- files.append(name: 'Third file name', content: 'third file content')
- end
- end
+ create(:project_snippet,
+ title: "Project snippet with multiple files-#{SecureRandom.hex(8)}",
+ file_name: 'First file name',
+ file_content: 'first file content',
+ files: [
+ { name: 'Second file name', content: 'second file content' },
+ { name: 'Third file name', content: 'third file content' }
+ ])
end
before do
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb
index d5de93fdee6..8d592e66eea 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_parent_child_pipelines_spec.rb
@@ -313,10 +313,7 @@ module QA
end
def find_job(job_name)
- Resource::Job.fabricate_via_api! do |job|
- job.project = project
- job.id = project.job_by_name(job_name)[:id]
- end
+ create(:job, project: project, id: project.job_by_name(job_name)[:id])
end
def wait_for_pipeline_creation(original_pipeline_count)
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb
index 91e62dfba9b..7ca2b41b972 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_job_artifacts/unlocking_job_artifacts_across_pipelines_spec.rb
@@ -202,10 +202,7 @@ module QA
end
def find_job(job_name)
- Resource::Job.fabricate_via_api! do |job|
- job.project = project
- job.id = project.job_by_name(job_name)[:id]
- end
+ create(:job, project: project, id: project.job_by_name(job_name)[:id])
end
def pipeline_count
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb
index 4ec9360be24..6e6a21f65a2 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb
@@ -62,13 +62,7 @@ module QA
Support::Waiter.wait_until { show.passed? }
end
- job = Resource::Job.fabricate_via_api! do |job|
- job.id = project.job_by_name(pipeline_job_name)[:id]
- job.name = pipeline_job_name
- job.project = project
- end
-
- job.visit!
+ create(:job, id: project.job_by_name(pipeline_job_name)[:id], name: pipeline_job_name, project: project).visit!
Page::Project::Job::Show.perform do |show|
expect(show.output).to have_content(variable_custom_value)
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb
index 52efacfd407..e599f1929d5 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb
@@ -4,13 +4,7 @@ module QA
RSpec.describe 'Verify', :runner, :reliable, product_group: :pipeline_execution do
describe 'Parent-child pipelines independent relationship' do
let!(:project) { create(:project, name: 'pipeline-independent-relationship') }
- let!(:runner) do
- Resource::ProjectRunner.fabricate_via_api! do |runner|
- runner.project = project
- runner.name = project.name
- runner.tags = [project.name]
- end
- end
+ let!(:runner) { create(:project_runner, project: project, name: project.name, tags: [project.name]) }
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb
deleted file mode 100644
index f4847a9ec99..00000000000
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Verify' do
- describe 'Pipeline editor', product_group: :pipeline_authoring do
- let(:project) { create(:project, :with_readme, name: 'pipeline-editor-project') }
-
- before do
- Flow::Login.sign_in
- project.visit!
- Page::Project::Menu.perform(&:go_to_pipeline_editor)
- end
-
- after do
- project&.remove_via_api!
- end
-
- it(
- 'can create merge request',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349130'
- ) do
- Page::Project::PipelineEditor::New.perform(&:create_new_ci)
-
- Page::Project::PipelineEditor::Show.perform do |show|
- # The new MR checkbox is visible after a new branch name is set
- show.set_source_branch(SecureRandom.hex(10))
- expect(show).to have_new_mr_checkbox
-
- show.select_new_mr_checkbox
- show.submit_changes
- end
-
- Page::MergeRequest::New.perform(&:create_merge_request)
-
- Page::MergeRequest::Show.perform do |show|
- expect(show).to have_title('Update .gitlab-ci.yml file')
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
index 019228da130..c5929dd1f49 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
@@ -121,9 +121,7 @@ module QA
def trigger_new_pipeline
original_count = project.pipelines.length
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = project
- end
+ create(:pipeline, project: project)
Support::Waiter.wait_until(sleep_interval: 1) { project.pipelines.length > original_count }
end
@@ -133,10 +131,7 @@ module QA
# If pipeline is held up, likely because there are some jobs that
# doesn't have either "skipped" or "manual" status
def problematic_jobs
- pipeline = Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = project
- pipeline.id = project.latest_pipeline[:id]
- end
+ pipeline = create(:pipeline, project: project, id: project.latest_pipeline[:id])
acceptable_statuses = %w[skipped manual]
pipeline.jobs.select { |job| !(acceptable_statuses.include? job[:status]) }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb
index 5c0e2a9d668..efd60b79ade 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb
@@ -3,15 +3,8 @@
module QA
RSpec.describe 'Verify' do
describe 'Update CI file with pipeline editor', product_group: :pipeline_authoring do
- let(:random_test_string) { SecureRandom.hex(10) }
+ let(:new_branch_name) { SecureRandom.hex(10) }
let(:project) { create(:project, name: 'pipeline-editor-project') }
- let!(:runner) do
- Resource::ProjectRunner.fabricate_via_api! do |runner|
- runner.project = project
- runner.name = random_test_string
- runner.tags = [random_test_string]
- end
- end
let!(:commit) do
Resource::Repository::Commit.fabricate_via_api! do |commit|
@@ -22,10 +15,7 @@ module QA
{
file_path: '.gitlab-ci.yml',
content: <<~YAML
- test_job:
- tags: ['#{random_test_string}']
- script:
- - echo "Simple test!"
+ 'This is to make pipeline fail immediately to save test execution time and resources.'
YAML
}
]
@@ -33,34 +23,48 @@ module QA
end
end
+ let(:new_content) do
+ <<~YAML
+ 'This is to do the exact same thing as the above.'
+ YAML
+ end
+
before do
Flow::Login.sign_in
project.visit!
- Support::Waiter.wait_until { !project.pipelines.empty? && project.pipelines.first[:status] == 'success' }
- Page::Project::Menu.perform(&:go_to_pipeline_editor)
+ Support::Waiter.wait_until(message: 'Wait for first pipeline to be created') { project.pipelines.size == 1 }
+
+ edit_ci_file_content_and_create_merge_request
end
- after do
- [runner, project].each(&:remove_via_api!)
+ it 'creates new pipelines, target branch, and merge request',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349005' do
+ # Verify a new MR is created from the update
+ Page::MergeRequest::Show.perform do |show|
+ expect(show).to have_title('Update .gitlab-ci.yml file')
+ end
+
+ # The target branch is also created and new pipeline respectively
+ aggregate_failures do
+ expect(project).to have_branch(new_branch_name)
+ expect { project.pipelines.size > 1 }.to eventually_be_truthy
+ end
end
- it 'creates new pipeline and target branch', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349005' do
- Page::Project::PipelineEditor::Show.perform do |show|
- show.write_to_editor(random_test_string)
- show.set_source_branch(random_test_string)
- show.submit_changes
+ private
- Support::Waiter.wait_until { project.pipelines.size > 1 }
+ def edit_ci_file_content_and_create_merge_request
+ Page::Project::Menu.perform(&:go_to_pipeline_editor)
+ Support::WaitForRequests.wait_for_requests
- aggregate_failures do
- expect(show.source_branch_name).to eq(random_test_string)
- expect(show.current_branch).to eq(random_test_string)
- expect(show.editing_content).to have_content(random_test_string)
- expect { show.pipeline_id }.to eventually_eq(project.pipelines.pluck(:id).max).within(max_duration: 60, sleep_interval: 3)
- end
+ Page::Project::PipelineEditor::Show.perform do |show|
+ show.write_to_editor(new_content)
+ show.set_source_branch(new_branch_name)
+ show.select_new_mr_checkbox
+ show.submit_changes
end
- expect(project).to have_branch(random_test_string)
+ Page::MergeRequest::New.perform(&:create_merge_request)
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_counts_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_counts_spec.rb
new file mode 100644
index 00000000000..0173f8bd132
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_counts_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', :runner, product_group: :runner do
+ describe 'Runner fleet management' do
+ let(:executor) { "qa-runner-#{Time.now.to_i}" }
+ let(:description) { "test-runner-#{Time.now.to_i}" }
+
+ let!(:runner) do
+ Resource::GroupRunner.fabricate! do |runner|
+ runner.name = executor
+ runner.description = description
+ end
+ end
+
+ after do
+ runner.remove_via_api!
+ end
+
+ it(
+ 'shows group runner counts',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/421256'
+ ) do
+ Flow::Login.sign_in
+
+ runner.group.visit!
+
+ Page::Group::Menu.perform(&:go_to_runners)
+ group_runners = Page::Group::Runners::Index.perform(&:count_group_runners)
+ project_runners = Page::Group::Runners::Index.perform(&:count_project_runners)
+ all_runners = Page::Group::Runners::Index.perform(&:count_all_runners)
+
+ aggregate_failures do
+ expect(group_runners).to eq(1)
+ expect(project_runners).to eq(0)
+ expect(all_runners).to be >= 1
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_status_counts_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_status_counts_spec.rb
new file mode 100644
index 00000000000..66cd996d6e0
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/runner/fleet_management/group_runner_status_counts_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', :runner, product_group: :runner do
+ describe 'Runner fleet management' do
+ let(:executor) { "qa-runner-#{Time.now.to_i}" }
+ let(:description) { "test-runner-#{Time.now.to_i}" }
+
+ let!(:runner) do
+ Resource::GroupRunner.fabricate! do |runner|
+ runner.name = executor
+ runner.description = description
+ end
+ end
+
+ after do
+ runner.remove_via_api!
+ end
+
+ it(
+ 'shows group runner online count',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/421255'
+ ) do
+ Flow::Login.sign_in
+
+ runner.group.visit!
+
+ Page::Group::Menu.perform(&:go_to_runners)
+ online_runners = Page::Group::Runners::Index.perform(&:count_online_runners)
+
+ expect(online_runners).to be >= 1
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb
index da7a6c537b8..a779df82b73 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/testing/endpoint_coverage_spec.rb
@@ -12,13 +12,7 @@ module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_security do
context 'Endpoint Coverage' do
let!(:project) { create(:project, name: 'endpoint-coverage') }
- let!(:runner) do
- Resource::ProjectRunner.fabricate_via_api! do |runner|
- runner.project = project
- runner.name = project.name
- runner.tags = [project.name]
- end
- end
+ let!(:runner) { create(:project_runner, project: project, name: project.name, tags: [project.name]) }
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
deleted file mode 100644
index ee60483d4de..00000000000
--- a/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
- describe 'Code coverage statistics' do
- let(:executor) { "qa-runner-#{Time.now.to_i}" }
- let(:runner) do
- Resource::ProjectRunner.fabricate_via_api! do |runner|
- runner.name = executor
- runner.tags = ['e2e-test']
- end
- end
-
- let(:merge_request) do
- Resource::MergeRequest.fabricate_via_api! do |mr|
- mr.project = runner.project
- mr.file_name = '.gitlab-ci.yml'
- mr.file_content = <<~EOF
- test:
- tags: [e2e-test]
- coverage: '/\\d+\\.\\d+% covered/'
- script:
- - echo '66.67% covered'
- EOF
- end
- end
-
- before do
- Flow::Login.sign_in
- end
-
- after do
- runner.remove_via_api!
- end
-
- it 'creates an MR with code coverage statistics', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348068' do
- merge_request.visit!
-
- Page::MergeRequest::Show.perform do |mr_widget|
- mr_widget.has_pipeline_status?('passed')
- expect(mr_widget).to have_content('Test coverage 66.67%')
- end
- end
- end
- end
-end
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb
index 49d1434035f..28d3ef60bbe 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/container_registry_spec.rb
@@ -70,7 +70,7 @@ module QA
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 200)
- job.click_element(:pipeline_path)
+ job.go_to_pipeline
end
Page::Project::Pipeline::Show.perform do |pipeline|
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb
index 3c656d9ca75..319b63291fd 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/saas/pull_container_registry_image_spec.rb
@@ -10,10 +10,7 @@ module QA
it 'pulls an image from an existing repository',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/412799' do
- project = Resource::Project.init do |project|
- project.path_with_namespace = 'gitlab-qa/container-registry-sanity'
- end.reload!
-
+ project = build(:project, path_with_namespace: 'gitlab-qa/container-registry-sanity').reload!
project.visit!
Page::Project::Menu.perform(&:go_to_pipelines)
diff --git a/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb b/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
index dae0e17746c..6b698d089f6 100644
--- a/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
@@ -142,7 +142,7 @@ module QA
project.group.visit!
- Page::Group::Menu.perform(&:go_to_group_dependency_proxy)
+ Page::Group::Menu.perform(&:go_to_dependency_proxy)
Page::Group::DependencyProxy.perform do |index|
expect(index).to have_blob_count("Contains 1 blobs of images")
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
index 3c43e97e21e..8ad82211f0d 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
@@ -59,7 +59,7 @@ module QA
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 800)
- job.click_element(:pipeline_path)
+ job.go_to_pipeline
end
Page::Project::Pipeline::Show.perform do |pipeline|
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb
index 28037391aeb..88cbe34b858 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb
@@ -101,7 +101,7 @@ module QA
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 800)
- job.click_element(:pipeline_path)
+ job.go_to_pipeline
end
Page::Project::Pipeline::Show.perform do |pipeline|
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb
index 04e020178ee..c6504ed3b18 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb
@@ -163,7 +163,7 @@ module QA
project.group.visit!
- Page::Group::Menu.perform(&:go_to_group_packages)
+ Page::Group::Menu.perform(&:go_to_package_registry)
Page::Project::Packages::Index.perform do |index|
expect(index).to have_package(package.name)
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
index d9a1f1cd4a6..c11f339f5f6 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb
@@ -8,13 +8,7 @@ module QA
let(:runner_name) { "qa-runner-#{SecureRandom.hex(4)}" }
let(:repository_location) { project.repository_ssh_location }
let(:project) { create(:project, name: 'deploy-key-clone-project') }
- let!(:runner) do
- Resource::ProjectRunner.fabricate_via_api! do |resource|
- resource.project = project
- resource.name = runner_name
- resource.tags = [runner_name]
- end
- end
+ let!(:runner) { create(:project_runner, project: project, name: runner_name, tags: [runner_name]) }
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb
index 7e941a135f1..4cadeb4b842 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb
@@ -33,13 +33,11 @@ module QA
end
let(:pipeline) do
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = project
- pipeline.variables =
- optional_jobs.map do |job|
- { key: job, value: '1', variable_type: 'env_var' }
- end
- end
+ create(:pipeline,
+ project: project,
+ variables: optional_jobs.map do |job|
+ { key: job, value: '1', variable_type: 'env_var' }
+ end)
end
before do
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index 8ee77f5c054..46ce7f26a52 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -47,7 +47,7 @@ module QA
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 600)
- job.click_element(:pipeline_path)
+ job.go_to_pipeline
end
Page::Project::Pipeline::Show.perform do |pipeline|
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb
index 85aa12062d5..82bbd37ea79 100644
--- a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb
+++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/email_notification_for_alert_spec.rb
@@ -12,12 +12,7 @@ module QA
let!(:admin_api_client) { Runtime::API::Client.as_admin }
- let!(:user) do
- Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- user.hard_delete_on_api_removal = true
- end
- end
+ let!(:user) { create(:user, :hard_delete, api_client: admin_api_client) }
let(:project) { create(:project, name: 'project-for-alerts', description: 'Project for alerts') }
let(:alert_title) { Faker::Lorem.word }
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb
index 0c977e5259c..8d29681f262 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/group/group_member_access_request_spec.rb
@@ -5,11 +5,7 @@ module QA
describe 'Group member access request' do
let!(:admin_api_client) { Runtime::API::Client.as_admin }
- let!(:user) do
- Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- end
- end
+ let!(:user) { create(:user, api_client: admin_api_client) }
let!(:group) do
create(:group, path: "group-for-access-request-#{SecureRandom.hex(8)}", api_client: admin_api_client)
@@ -23,10 +19,7 @@ module QA
Flow::Login.sign_in_as_admin
- Page::Main::Menu.perform do |menu|
- menu.go_to_page_by_shortcut('todos-shortcut-button')
- end
-
+ Page::Main::Menu.perform(&:go_to_todos)
Page::Dashboard::Todos.perform do |todos|
todos.filter_todos_by_group(group)
end
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb
index 2a1f8a58108..41e6723d300 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/group/transfer_group_spec.rb
@@ -18,7 +18,7 @@ module QA
it 'transfers a subgroup to another group',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347692' do
- Page::Group::Menu.perform(&:click_group_general_settings_item)
+ Page::Group::Menu.perform(&:go_to_general_settings)
Page::Group::Settings::General.perform do |general|
general.transfer_group(sub_group_for_transfer, target_group)
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb
index 7fb970c3f25..41c8bcd53ef 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/add_project_member_spec.rb
@@ -11,7 +11,7 @@ module QA
project = create(:project, name: 'add-member-project')
project.visit!
- Page::Project::Menu.perform(&:click_members)
+ Page::Project::Menu.perform(&:go_to_members)
Page::Project::Members.perform do |members|
members.add_member(user.username)
members.search_member(user.username)
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb
index 2ea96dfef95..c1056f50f3c 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/dashboard_images_spec.rb
@@ -5,12 +5,7 @@ module QA
shared_examples 'loads all images' do |admin|
let(:api_client) { Runtime::API::Client.as_admin }
- let(:user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.admin = admin
- resource.api_client = api_client
- end
- end
+ let(:user) { create(:user, admin: admin, api_client: api_client) }
after do
user.remove_via_api!
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb
index 29e39d48c67..28253c1f1df 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/invite_group_to_project_spec.rb
@@ -5,7 +5,7 @@ module QA
describe 'Invite group', :reliable, product_group: :tenant_scale do
shared_examples 'invites group to project' do
it 'grants group and members correct access level' do
- Page::Project::Menu.perform(&:click_members)
+ Page::Project::Menu.perform(&:go_to_members)
Page::Project::Members.perform do |project_members|
project_members.invite_group(group.path, 'Developer')
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb
index 310b8747584..28d05fd58c0 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/project_owner_permissions_spec.rb
@@ -15,11 +15,7 @@ module QA
shared_examples 'adds user as owner' do |project_type, testcase|
let!(:issue) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.api_client = owner_api_client
- issue.project = project
- issue.title = 'Test Owner Deletes Issue'
- end
+ create(:issue, title: 'Test Owner Deletes Issue', project: project, api_client: owner_api_client)
end
before do
@@ -46,11 +42,7 @@ module QA
shared_examples 'adds user as maintainer' do |testcase|
let!(:issue) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.api_client = owner_api_client
- issue.project = project
- issue.title = 'Test Maintainer Deletes Issue'
- end
+ create(:issue, title: 'Test Maintainer Deletes Issue', project: project, api_client: owner_api_client)
end
before do
@@ -75,11 +67,10 @@ module QA
context 'for personal projects' do
let!(:project) do
- Resource::Project.fabricate_via_api! do |project|
- project.api_client = owner_api_client
- project.name = 'qa-owner-personal-project'
- project.personal_namespace = owner.username
- end
+ create(:project,
+ name: 'qa-owner-personal-project',
+ api_client: owner_api_client,
+ personal_namespace: owner.username)
end
it_behaves_like 'adds user as owner', :personal_project, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/352542'
@@ -88,13 +79,7 @@ module QA
context 'for group projects' do
let!(:group) { create(:group) }
-
- let!(:project) do
- Resource::Project.fabricate_via_api! do |project|
- project.group = group
- project.name = 'qa-owner-group-project'
- end
- end
+ let!(:project) { create(:project, name: 'qa-owner-group-project', group: group) }
it_behaves_like 'adds user as owner', :group_project, 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366436'
it_behaves_like 'adds user as maintainer', 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366435'
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb
index 5cdb88407fb..c5a6e92cb99 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/project/view_project_activity_spec.rb
@@ -15,7 +15,7 @@ module QA
end.project
project.visit!
- Page::Project::Menu.perform(&:click_activity)
+ Page::Project::Menu.perform(&:go_to_activity)
Page::Project::Activity.perform do |activity|
activity.click_push_events
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb
index a119d600667..9ace1a4b4f7 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/follow_user_activity_spec.rb
@@ -7,18 +7,10 @@ module QA
let(:followed_user_api_client) { Runtime::API::Client.new(:gitlab, user: followed_user) }
- let(:followed_user) do
- Resource::User.fabricate_via_api! do |user|
- user.name = "followed_user_#{SecureRandom.hex(8)}"
- user.api_client = admin_api_client
- end
- end
+ let(:followed_user) { create(:user, name: "followed_user_#{SecureRandom.hex(8)}", api_client: admin_api_client) }
let(:following_user) do
- Resource::User.fabricate_via_api! do |user|
- user.name = "following_user_#{SecureRandom.hex(8)}"
- user.api_client = admin_api_client
- end
+ create(:user, name: "following_user_#{SecureRandom.hex(8)}", api_client: admin_api_client)
end
let(:group) do
@@ -30,12 +22,7 @@ module QA
end
let(:project) do
- Resource::Project.fabricate_via_api! do |project|
- project.name = 'project-for-tags'
- project.initialize_with_readme = true
- project.api_client = followed_user_api_client
- project.group = group
- end
+ create(:project, :with_readme, name: 'project-for-tags', api_client: followed_user_api_client, group: group)
end
let(:merge_request) do
@@ -45,12 +32,7 @@ module QA
end
end
- let(:issue) do
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- issue.api_client = followed_user_api_client
- end
- end
+ let(:issue) { create(:issue, project: project, api_client: followed_user_api_client) }
let(:comment) do
Resource::ProjectIssueNote.fabricate_via_api! do |project_issue_note|
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb
index 562bd1b1aa1..46e4a674f99 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/parent_group_access_termination_spec.rb
@@ -5,21 +5,11 @@ module QA
describe 'User', :requires_admin, :reliable, product_group: :tenant_scale do
let(:admin_api_client) { Runtime::API::Client.as_admin }
- let!(:user) do
- Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- end
- end
+ let!(:user) { create(:user, api_client: admin_api_client) }
let!(:group) { create(:group, path: "group-to-test-access-termination-#{SecureRandom.hex(8)}") }
- let!(:project) do
- Resource::Project.fabricate_via_api! do |project|
- project.group = group
- project.name = "project-for-user-access-termination"
- project.initialize_with_readme = true
- end
- end
+ let!(:project) { create(:project, :with_readme, name: 'project-for-user-access-termination', group: group) }
context 'with terminated parent group membership' do
before do
@@ -28,7 +18,7 @@ module QA
Flow::Login.while_signed_in_as_admin do
group.visit!
- Page::Group::Menu.perform(&:click_subgroup_members_item)
+ Page::Group::Menu.perform(&:go_to_members)
Page::Group::Members.perform do |members_page|
members_page.search_member(user.username)
members_page.remove_member(user.username)
diff --git a/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb b/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb
index 8553e1739ce..c0ec71c4488 100644
--- a/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb
+++ b/qa/qa/specs/features/browser_ui/9_data_stores/user/user_inherited_access_spec.rb
@@ -14,22 +14,14 @@ module QA
end
context 'when added to parent group' do
- let!(:parent_group_user) do
- Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- end
- end
+ let!(:parent_group_user) { create(:user, api_client: admin_api_client) }
let!(:parent_group_user_api_client) do
Runtime::API::Client.new(:gitlab, user: parent_group_user)
end
let!(:sub_group_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.group = sub_group
- project.name = "sub-group-project-to-test-user-access"
- project.initialize_with_readme = true
- end
+ create(:project, :with_readme, name: 'sub-group-project-to-test-user-access', group: sub_group)
end
before do
@@ -61,18 +53,10 @@ module QA
context 'when added to sub-group' do
let!(:parent_group_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.group = parent_group
- project.name = "parent-group-project-to-test-user-access"
- project.initialize_with_readme = true
- end
+ create(:project, :with_readme, name: 'parent-group-project-to-test-user-access', group: parent_group)
end
- let!(:sub_group_user) do
- Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- end
- end
+ let!(:sub_group_user) { create(:user, api_client: admin_api_client) }
let!(:sub_group_user_api_client) do
Runtime::API::Client.new(:gitlab, user: sub_group_user)
diff --git a/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb b/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb
index 445586d31ac..f32b9258492 100644
--- a/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb
+++ b/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb
@@ -13,12 +13,7 @@ module QA
create(:group, api_client: api_client, path: "destination-group-for-import-#{SecureRandom.hex(4)}")
end
- let!(:user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.api_client = api_client
- resource.hard_delete_on_api_removal = true
- end
- end
+ let!(:user) { create(:user, :hard_delete, api_client: api_client) }
let!(:user_api_client) { Runtime::API::Client.new(user: user) }
diff --git a/qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb b/qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb
index e702da4ad5b..19d9f9ad94f 100644
--- a/qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb
+++ b/qa/qa/specs/features/shared_contexts/import/gitlab_group_migration_common.rb
@@ -23,10 +23,10 @@ module QA
Runtime::ApplicationSettings.get_application_settings(api_client: source_admin_api_client)[:bulk_import_enabled]
end
let!(:source_admin_user) do
- Resource::User.fabricate_via_api! do |usr|
- usr.api_client = source_admin_api_client
- usr.username = Runtime::Env.admin_username || "root"
- end.tap(&:set_public_email)
+ create(:user,
+ :set_public_email,
+ api_client: source_admin_api_client,
+ username: Runtime::Env.admin_username || 'root')
end
let!(:source_group) do
Resource::Sandbox.fabricate_via_api! do |group|
@@ -43,17 +43,12 @@ module QA
Runtime::ApplicationSettings.get_application_settings(api_client: admin_api_client)[:bulk_import_enabled]
end
let!(:admin_user) do
- Resource::User.fabricate_via_api! do |usr|
- usr.api_client = admin_api_client
- usr.username = Runtime::Env.admin_username || "root"
- end.tap(&:set_public_email)
- end
- let!(:user) do
- Resource::User.fabricate_via_api! do |usr|
- usr.api_client = admin_api_client
- usr.username = "target-user-#{SecureRandom.hex(6)}"
- end
+ create(:user,
+ :set_public_email,
+ api_client: admin_api_client,
+ username: Runtime::Env.admin_username || 'root')
end
+ let!(:user) { create(:user, api_client: admin_api_client, username: "target-user-#{SecureRandom.hex(6)}") }
let!(:api_client) { Runtime::API::Client.new(user: user) }
let!(:target_sandbox) do
Resource::Sandbox.fabricate_via_api! do |group|
diff --git a/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb b/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb
index 900245deca3..823d4eb31e4 100644
--- a/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb
+++ b/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb
@@ -9,11 +9,10 @@ module QA
let(:source_project_with_readme) { false }
let(:source_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.api_client = source_admin_api_client
- project.group = source_group
- project.initialize_with_readme = source_project_with_readme
- end
+ create(:project,
+ api_client: source_admin_api_client,
+ group: source_group,
+ initialize_with_readme: source_project_with_readme)
end
let(:imported_projects) { imported_group.reload!.projects }
diff --git a/qa/qa/specs/features/shared_contexts/merge_train_spec_with_user_prep.rb b/qa/qa/specs/features/shared_contexts/merge_train_spec_with_user_prep.rb
deleted file mode 100644
index 8af5dc5463e..00000000000
--- a/qa/qa/specs/features/shared_contexts/merge_train_spec_with_user_prep.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- RSpec.shared_context 'merge train spec with user prep' do
- let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
- let(:file_name) { Faker::Lorem.word }
- let(:mr_title) { Faker::Lorem.sentence }
- let(:admin_api_client) { Runtime::API::Client.as_admin }
-
- let(:user) do
- Resource::User.fabricate_via_api! do |user|
- user.api_client = admin_api_client
- end
- end
-
- let(:project) do
- Resource::Project.fabricate_via_api! do |project|
- project.name = 'pipeline-for-merge-trains'
- end
- end
-
- let!(:runner) do
- Resource::ProjectRunner.fabricate! do |runner|
- runner.project = project
- runner.name = executor
- runner.tags = [executor]
- end
- end
-
- let!(:project_files) do
- Resource::Repository::Commit.fabricate_via_api! do |commit|
- commit.project = project
- commit.commit_message = 'Add .gitlab-ci.yml'
- commit.add_files(
- [
- {
- file_path: '.gitlab-ci.yml',
- content: <<~YAML
- test_merge_train:
- tags:
- - #{executor}
- script:
- - sleep 10
- - echo 'OK!'
- only:
- - merge_requests
- YAML
- },
- {
- file_path: file_name,
- content: Faker::Lorem.sentence
- }
- ]
- )
- end
- end
-
- before do
- project.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
-
- Flow::Login.sign_in
- project.visit!
- Flow::MergeRequest.enable_merge_trains
-
- Flow::Login.sign_in(as: user)
-
- Resource::MergeRequest.fabricate_via_api! do |merge_request|
- merge_request.title = mr_title
- merge_request.project = project
- merge_request.description = Faker::Lorem.sentence
- merge_request.target_new_branch = false
- merge_request.update_existing_file = true
- merge_request.file_name = file_name
- merge_request.file_content = Faker::Lorem.sentence
- end.visit!
-
- Page::MergeRequest::Show.perform do |show|
- show.has_pipeline_status?('passed')
- show.try_to_merge!
- end
- end
-
- after do
- runner&.remove_via_api!
- user&.remove_via_api!
- end
- end
-end
diff --git a/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb b/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb
index 3905a05633f..21e4d906043 100644
--- a/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb
+++ b/qa/qa/specs/features/shared_contexts/packages_registry_shared_context.rb
@@ -4,20 +4,10 @@ module QA
RSpec.shared_context 'packages registry qa scenario' do
let(:personal_access_token) { Runtime::Env.personal_access_token }
- let(:package_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.name = "#{package_type}_package_project"
- project.initialize_with_readme = true
- project.visibility = :private
- end
- end
+ let(:package_project) { create(:project, :private, :with_readme, name: "packages-#{SecureRandom.hex(8)}") }
let(:client_project) do
- Resource::Project.fabricate_via_api! do |client_project|
- client_project.name = "#{package_type}_client_project"
- client_project.initialize_with_readme = true
- client_project.group = package_project.group
- end
+ create(:project, :with_readme, name: "client-#{SecureRandom.hex(8)}", group: package_project.group)
end
let(:package_project_inbound_job_token_disabled) do
diff --git a/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb
index 9623bcbb7b5..b8637ed652c 100644
--- a/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb
+++ b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb
@@ -2,13 +2,7 @@
module QA
RSpec.shared_context 'sends and resolves test alerts' do
- let(:project) do
- Resource::Project.fabricate_via_api! do |project|
- project.name = 'project-for-alerts'
- project.description = 'Project for alerts'
- end
- end
-
+ let(:project) { create(:project, name: 'project-for-alerts', description: 'Project for alerts') }
let(:resolve_title) { Faker::Lorem.sentence }
let(:unresolve_title) { Faker::Lorem.sentence }
let(:http) { true }
diff --git a/qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb b/qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb
index 69786c55be8..fb91364a1fc 100644
--- a/qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb
+++ b/qa/qa/specs/features/shared_contexts/variable_inheritance_shared_context.rb
@@ -8,27 +8,24 @@ module QA
let(:group) { create(:group, path: "group-for-variable-inheritance-#{random_string}") }
let(:upstream_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.group = group
- project.name = 'upstream-variable-inheritance'
- project.description = 'Project for pipeline with variable defined via UI - Upstream'
- end
+ create(:project,
+ name: 'upstream-variable-inheritance',
+ description: 'Project for pipeline with variable defined via UI - Upstream',
+ group: group)
end
let(:downstream1_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.group = group
- project.name = 'downstream1-variable-inheritance'
- project.description = 'Project for pipeline with variable defined via UI - Downstream'
- end
+ create(:project,
+ name: 'downstream1-variable-inheritance',
+ description: 'Project for pipeline with variable defined via UI - Downstream',
+ group: group)
end
let(:downstream2_project) do
- Resource::Project.fabricate_via_api! do |project|
- project.group = group
- project.name = 'downstream2-variable-inheritance'
- project.description = 'Project for pipeline with variable defined via UI - Downstream'
- end
+ create(:project,
+ name: 'downstream2-variable-inheritance',
+ description: 'Project for pipeline with variable defined via UI - Downstream',
+ group: group)
end
let!(:runner) do
@@ -94,17 +91,11 @@ module QA
end
def upstream_pipeline
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = upstream_project
- pipeline.id = upstream_project.pipelines.first[:id]
- end
+ create(:pipeline, project: upstream_project, id: upstream_project.pipelines.first[:id])
end
def downstream_pipeline(project, bridge_name)
- Resource::Pipeline.fabricate_via_api! do |pipeline|
- pipeline.project = project
- pipeline.id = upstream_pipeline.downstream_pipeline_id(bridge_name: bridge_name)
- end
+ create(:pipeline, project: project, id: upstream_pipeline.downstream_pipeline_id(bridge_name: bridge_name))
end
def upstream_child1_ci_file
diff --git a/qa/qa/specs/features/shared_examples/audit_event_streaming_shared_examples.rb b/qa/qa/specs/features/shared_examples/audit_event_streaming_shared_examples.rb
new file mode 100644
index 00000000000..67a4fd12b96
--- /dev/null
+++ b/qa/qa/specs/features/shared_examples/audit_event_streaming_shared_examples.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.shared_examples 'streamed events' do |event_type, entity_type, testcase|
+ it 'the external server receives the event', testcase: testcase do
+ entity_path # Call to trigger the event before we can check it was received
+ event_record = @mock_service.wait_for_event(event_type, entity_type, entity_path)
+ verify_response = @mock_service.verify
+
+ # Most of the verification is done via `wait_for_event` above
+ # The other two are checks for data that couldn't be added to a mock in advance
+ aggregate_failures do
+ # Smocker treats header values as arrays
+ # Verification tokens are created for us if we don't provide one
+ # https://docs.gitlab.com/ee/administration/audit_event_streaming/#verify-event-authenticity
+ expect(event_record[:headers]).to include(
+ headers.transform_values { |v| [v] }
+ .merge("X-Gitlab-Event-Streaming-Token": [@stream_destination.verification_token])
+ )
+ expect(event_record[:body]).to include(details: a_hash_including(target_details: target_details))
+ expect(verify_response).to be_success,
+ "Failures when verifying events received:\n#{JSON.pretty_generate(verify_response.failures)}"
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/helpers/context_selector.rb b/qa/qa/specs/helpers/context_selector.rb
index 3ef729c4500..aab2a82d90e 100644
--- a/qa/qa/specs/helpers/context_selector.rb
+++ b/qa/qa/specs/helpers/context_selector.rb
@@ -116,12 +116,12 @@ module QA
# @return [String] 'gitlab' or 'jihulab'
def production_domain(tld)
return 'gitlab' unless GitlabEdition.jh?
- return 'gitlab' if tld == 'hk'
+ return 'gitlab' if tld == 'hk' || tld == 'cn'
return 'jihulab' if tld == 'com'
end
def opts_tld
- GitlabEdition.jh? ? '(.com|.hk)' : '(.com|.net)'
+ GitlabEdition.jh? ? '(.com|.hk|.cn)' : '(.com|.net)'
end
def get_tld(host)
diff --git a/qa/qa/support/audit_event_streaming_service.rb b/qa/qa/support/audit_event_streaming_service.rb
new file mode 100644
index 00000000000..03f27f7f3bb
--- /dev/null
+++ b/qa/qa/support/audit_event_streaming_service.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+module QA
+ module Support
+ class AuditEventStreamingService < Vendor::Smocker::SmockerApi
+ def initialize(wait: 10, reset_on_init: true)
+ # We use the time of initialization to limit the results we get from the audit events API
+ @start = DateTime.now.iso8601
+ @smocker_container = Service::DockerRun::Smocker.new
+ @smocker_container.register!
+ @smocker_container.wait_for_running
+
+ super(
+ host: @smocker_container.host_name,
+ public_port: @smocker_container.public_port,
+ admin_port: @smocker_container.admin_port
+ )
+ wait_for_ready(wait: wait)
+ reset if reset_on_init
+ register(mocks)
+ end
+
+ def logs
+ @smocker_container.logs
+ end
+
+ def reset!
+ reset
+ register(mocks)
+ end
+
+ # Remove the Smocker Docker container
+ #
+ # @return [void]
+ def teardown!
+ @smocker_container.remove! if @smocker_container
+ end
+
+ # Wait for the mock service to receive a request with the specified event type
+ #
+ # @param [Symbol] event_type the event to wait for
+ # @param [String] entity_type the entity type of the event
+ # @param [String] entity_path the event entity identifier
+ # @param [Integer] wait the amount of time to wait for the event to be received
+ # @param [Boolean] raise_on_failure raise an error if the event is not received
+ # @return [Hash] the request
+ def wait_for_event(event_type, entity_type, entity_path = nil, wait: 10, raise_on_failure: true)
+ event = Waiter.wait_until(max_duration: wait, sleep_interval: 1, raise_on_failure: false) do
+ history.find do |record|
+ body = record.request[:body]
+ next if body.blank?
+
+ body&.dig(:event_type) == event_type.to_s &&
+ body&.dig(:entity_type) == entity_type &&
+ (!entity_path || body&.dig(:entity_path) == entity_path)
+ end&.request
+ end
+ return event unless event.nil? && raise_on_failure
+
+ # Get the audit events from the API to help troubleshoot failures
+ audit_events = EE::Resource::AuditEvents.all(created_after: @start, entity_type: entity_type)
+
+ raise Repeater::WaitExceededError,
+ "An event with type '#{event_type}'#{" and entity_path '#{entity_path}'" if entity_path} was not received. " \
+ "Event history: #{stringified_history}. " \
+ "Audit events with entity_type '#{entity_type}': #{audit_events}"
+ end
+
+ # Wait for GitLab to start streaming audit events and for the Smocker server to be ready to receive them.
+ #
+ # When we start the mock streaming server it sometimes doesn't start receiving traffic immediately, even
+ # when the smocker API reports that it's ready. In addition, there can be a brief delay after a new streaming
+ # destination is configured before it sends events.
+ def wait_for_streaming_to_start(event_type:, entity_type:)
+ # Create and then remove an SSH key and confirm that the mock streaming server received the event
+ Waiter.wait_until(max_duration: 60, sleep_interval: 5, message: 'Waiting for streaming to start') do
+ yield
+
+ wait_for_event(event_type, entity_type, wait: 2, raise_on_failure: false)
+ end
+ rescue Repeater::WaitExceededError
+ # If there is a failure this will output the logs from the smocker container (at the debug log level)
+ logs
+
+ raise
+ end
+
+ private
+
+ # The configuration for the mocked requests and responses for events that will be verified in this test
+ #
+ # @return [String]
+ def mocks
+ @mocks ||= File.read(EE::Runtime::Path.fixture('audit_event_streaming', 'mocks.yml'))
+ end
+ end
+ end
+end
diff --git a/qa/qa/support/matchers/have_matcher.rb b/qa/qa/support/matchers/have_matcher.rb
index 6fa88ef205b..52650edab5f 100644
--- a/qa/qa/support/matchers/have_matcher.rb
+++ b/qa/qa/support/matchers/have_matcher.rb
@@ -31,6 +31,7 @@ module QA
incident
framework
delete_issue_button
+ skipped_job_in_group
].each do |predicate|
RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs|
match do |page_object|
diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb
index ccc5e04d672..932b1bf7f6b 100644
--- a/qa/qa/support/page/logging.rb
+++ b/qa/qa/support/page/logging.rb
@@ -75,7 +75,7 @@ module QA
super
end
- # @param name [Symbol] name of the data_qa_selector element
+ # @param name [Symbol, String] name of the data_qa_selector or data-testid element
# @param page [Class] a target page class to check existence of (class must inherit from QA::Page::Base)
# @param kwargs [Hash] keyword arguments to pass to Capybara finder
def click_element(name, page = nil, **kwargs)
diff --git a/qa/qa/support/system_logs/sentry.rb b/qa/qa/support/system_logs/sentry.rb
index a1bd53e7d7a..79a5df7b10a 100644
--- a/qa/qa/support/system_logs/sentry.rb
+++ b/qa/qa/support/system_logs/sentry.rb
@@ -5,10 +5,10 @@ module QA
module SystemLogs
class Sentry
BASE_URLS = {
- staging: 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg',
- staging_ref: 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=all',
- pre: 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=all',
- production: 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd'
+ staging: 'https://new-sentry.gitlab.net/organizations/gitlab/issues/?environment=gstg&project=3',
+ staging_ref: 'https://new-sentry.gitlab.net/organizations/gitlab/projects/staging-ref/?project=18',
+ pre: 'https://new-sentry.gitlab.net/organizations/gitlab/issues/?environment=pre&project=3',
+ production: 'https://new-sentry.gitlab.net/organizations/gitlab/issues/?environment=gprd&project=3'
}.freeze
def initialize(env, correlation_id)
diff --git a/qa/qa/tools/delete_projects.rb b/qa/qa/tools/delete_projects.rb
index da46606f286..e11ea90dc90 100644
--- a/qa/qa/tools/delete_projects.rb
+++ b/qa/qa/tools/delete_projects.rb
@@ -3,6 +3,11 @@
# This script deletes all projects directly under a group specified by ENV['TOP_LEVEL_GROUP_NAME']
# Required environment variables: GITLAB_QA_ACCESS_TOKEN and GITLAB_ADDRESS
# Optional environment variable: TOP_LEVEL_GROUP_NAME (defaults to 'gitlab-qa-sandbox-group')
+
+# Optional environment variable: CLEANUP_ALL_QA_SANDBOX_GROUPS (defaults to false)
+# Set CLEANUP_ALL_QA_SANDBOX_GROUPS to true if you would like to delete projects under all
+# 'gitlab-qa-sandbox-group-*' groups. Otherwise, this will fall back to TOP_LEVEL_GROUP_NAME.
+
# Run `rake delete_projects`
module QA
@@ -10,6 +15,7 @@ module QA
class DeleteProjects
include Support::API
include Lib::Project
+ include Lib::Group
def initialize
raise ArgumentError, "Please provide GITLAB_ADDRESS environment variable" unless ENV['GITLAB_ADDRESS']
@@ -22,12 +28,24 @@ module QA
$stdout.puts 'Running...'
# Fetch group's id
- group_id = fetch_group_id
+ if ENV['CLEANUP_ALL_QA_SANDBOX_GROUPS']
+ (1..7).each do |group_number|
+ group_id = fetch_group_id(@api_client, group_number)
+ delete_selected_projects(group_id)
+ end
+
+ else
+ group_id = fetch_group_id(@api_client)
+ delete_selected_projects(group_id)
+ end
+ end
+ private
+
+ def delete_selected_projects(group_id)
projects_head_response = head Runtime::API::Request.new(@api_client, "/groups/#{group_id}/projects", per_page: "100").url
total_project_pages = projects_head_response.headers[:x_total_pages]
- # Do not delete projects that are less than 4 days old (for debugging purposes)
project_ids = fetch_project_ids(group_id, total_project_pages)
$stdout.puts "Number of projects to be deleted: #{project_ids.length}"
@@ -35,20 +53,13 @@ module QA
$stdout.puts "\nDone"
end
- private
-
- def fetch_group_id
- group_name = ENV['TOP_LEVEL_GROUP_NAME'] || "gitlab-qa-sandbox-group-#{Time.now.wday + 1}"
- group_search_response = get Runtime::API::Request.new(@api_client, "/groups/#{group_name}").url
- JSON.parse(group_search_response.body)["id"]
- end
-
def fetch_project_ids(group_id, total_project_pages)
projects_ids = []
total_project_pages.to_i.times do |page_no|
projects_response = get Runtime::API::Request.new(@api_client, "/groups/#{group_id}/projects", page: (page_no + 1).to_s, per_page: "100").url
- projects_ids.concat(JSON.parse(projects_response.body).select { |project| Date.parse(project["created_at"]) < Date.today - 3 }.map { |project| project["id"] })
+ # Do not delete projects that are less than 4 days old (for debugging purposes)
+ projects_ids.concat(JSON.parse(projects_response.body).select { |project| Date.parse(project["created_at"]) < Date.today - 3 }.pluck("id"))
end
projects_ids.uniq
diff --git a/qa/qa/tools/delete_subgroups.rb b/qa/qa/tools/delete_subgroups.rb
index 84166ec0038..35bff409647 100644
--- a/qa/qa/tools/delete_subgroups.rb
+++ b/qa/qa/tools/delete_subgroups.rb
@@ -5,6 +5,10 @@
# Required environment variables: GITLAB_QA_ACCESS_TOKEN and GITLAB_ADDRESS
# Optional environment variable: TOP_LEVEL_GROUP_NAME (defaults to 'gitlab-qa-sandbox-group-<current weekday #>')
+# Optional environment variable: CLEANUP_ALL_QA_SANDBOX_GROUPS (defaults to false)
+# Set CLEANUP_ALL_QA_SANDBOX_GROUPS to true if you would like to delete all subgroups under all
+# 'gitlab-qa-sandbox-group-*' groups. Otherwise, this will fall back to TOP_LEVEL_GROUP_NAME.
+
# Optional environment variable: PERMANENTLY_DELETE (defaults to false)
# Set PERMANENTLY_DELETE to true if you would like to permanently delete subgroups on an environment with
# deletion protection enabled. Otherwise, subgroups will remain available during the retention period specified
@@ -17,6 +21,7 @@ module QA
class DeleteSubgroups
include Support::API
include Ci::Helpers
+ include Lib::Group
def initialize
raise ArgumentError, "Please provide GITLAB_ADDRESS" unless ENV['GITLAB_ADDRESS']
@@ -27,7 +32,21 @@ module QA
end
def run
- group_id = fetch_group_id
+ if ENV['CLEANUP_ALL_QA_SANDBOX_GROUPS']
+ (1..7).each do |group_number|
+ group_id = fetch_group_id(@api_client, group_number)
+ delete_subgroups(group_id)
+ end
+
+ else
+ group_id = fetch_group_id(@api_client)
+ delete_subgroups(group_id)
+ end
+ end
+
+ private
+
+ def delete_subgroups(group_id)
return logger.info('Top level group not found') if group_id.nil?
subgroups = fetch_subgroups(group_id)
@@ -44,16 +63,6 @@ module QA
logger.info('Done')
end
- private
-
- def fetch_group_id
- logger.info("Fetching top level group id...\n")
-
- group_name = ENV['TOP_LEVEL_GROUP_NAME'] || "gitlab-qa-sandbox-group-#{Time.now.wday + 1}"
- group_search_response = get Runtime::API::Request.new(@api_client, "/groups/#{group_name}" ).url
- JSON.parse(group_search_response.body)['id']
- end
-
def fetch_subgroups(group_id)
logger.info("Fetching subgroups...")
@@ -63,7 +72,8 @@ module QA
while page_no.present?
subgroups_response = get Runtime::API::Request.new(@api_client, api_path, page: page_no, per_page: '100').url
- subgroups.concat(JSON.parse(subgroups_response.body))
+ # Do not delete subgroups that are less than 4 days old (for debugging purposes)
+ subgroups.concat(JSON.parse(subgroups_response.body).select { |subgroup| Date.parse(subgroup["created_at"]) < Date.today - 3 })
page_no = subgroups_response.headers[:x_next_page].to_s
end
diff --git a/qa/qa/tools/lib/group.rb b/qa/qa/tools/lib/group.rb
new file mode 100644
index 00000000000..5f154906073
--- /dev/null
+++ b/qa/qa/tools/lib/group.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module QA
+ module Tools
+ module Lib
+ module Group
+ def fetch_group_id(api_client, group_number = nil)
+ group_name = if group_number
+ "gitlab-qa-sandbox-group-#{group_number}"
+ else
+ ENV['TOP_LEVEL_GROUP_NAME'] || "gitlab-qa-sandbox-group-#{Time.now.wday + 1}"
+ end
+
+ group_search_response = get Runtime::API::Request.new(api_client, "/groups/#{group_name}").url
+ JSON.parse(group_search_response.body)["id"]
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/tools/reliable_report.rb b/qa/qa/tools/reliable_report.rb
index fd39b637f83..90ceb0f740a 100644
--- a/qa/qa/tools/reliable_report.rb
+++ b/qa/qa/tools/reliable_report.rb
@@ -91,13 +91,13 @@ module QA
issues
.reject { |issue| issue[:iid] == report_iid }
.each do |issue|
- issue_iid = issue[:iid]
- issue_endpoint = "projects/#{PROJECT_ID}/issues/#{issue_iid}"
+ issue_iid = issue[:iid]
+ issue_endpoint = "projects/#{PROJECT_ID}/issues/#{issue_iid}"
- puts "Closing previous report '#{issue[:web_url]}'"
- api_update(:put, issue_endpoint, state_event: "close")
- api_update(:post, "#{issue_endpoint}/notes", body: "Closed issue in favor of ##{report_iid}")
- end
+ puts "Closing previous report '#{issue[:web_url]}'"
+ api_update(:put, issue_endpoint, state_event: "close")
+ api_update(:post, "#{issue_endpoint}/notes", body: "Closed issue in favor of ##{report_iid}")
+ end
end
# Notify failure
@@ -244,7 +244,10 @@ module QA
headings: headings.map(&:upcase),
markdown: markdown,
rows: specs.map do |k, v|
- [name_column(name: k, file: v[:file], markdown: markdown), *table_params(v.values)]
+ [
+ name_column(name: k, file: v[:file], exceptions_and_job_urls: v[:exceptions_and_job_urls],
+ markdown: markdown), *table_params(v.values)
+ ]
end
)]
end
@@ -312,13 +315,26 @@ module QA
# @param [String] file
# @param [Boolean] markdown
# @return [String]
- def name_column(name:, file:, markdown: false)
- return "**name**: #{name}<br>**file**: #{file}" if markdown
+ def name_column(name:, file:, exceptions_and_job_urls:, markdown: false)
+ return "**name**: #{name}<br>**file**: #{file}#{exceptions_markdown(exceptions_and_job_urls)}" if markdown
wrapped_name = name.length > 150 ? "#{name} ".scan(/.{1,150} /).map(&:strip).join("\n") : name
"name: '#{wrapped_name}'\nfile: #{file.ljust(160)}"
end
+ # Formatted expection with link to job url
+ #
+ # @param [Hash] exceptions_and_job_urls
+ # @return [String]
+ def exceptions_markdown(exceptions_and_job_urls)
+ return '' if exceptions_and_job_urls.empty?
+
+ "<br>**Exceptions**:#{exceptions_and_job_urls.keys.map do |e|
+ "<br>- [`#{e.truncate(250).tr('`', "'")}`](#{exceptions_and_job_urls[e]})"
+ end.join('')}"
+ end
+
+ # rubocop:disable Metrics/AbcSize
# Test executions grouped by name
#
# @param [Boolean] reliable
@@ -329,6 +345,7 @@ module QA
all_runs = query_api.query(query: query(reliable))
all_runs.each_with_object(Hash.new { |hsh, key| hsh[key] = {} }) do |table, result|
records = table.records.sort_by { |record| record.values["_time"] }
+
# skip specs that executed less time than defined by range or stopped executing before report date
# offset 1 day due to how schedulers are configured and first run can be 1 day later
next if (Date.today - Date.parse(records.first.values["_time"])).to_i < (range - 1)
@@ -341,16 +358,26 @@ module QA
runs = records.count
failed = records.count { |r| r.values["status"] == "failed" }
+
failure_rate = (failed.to_f / runs) * 100
+ records_with_exception = records.reject { |r| !r.values["failure_exception"] }
+
+ # Since exception is the key in the below hash, only one instance of an occurrence is kept
+ exceptions_and_job_urls = Hash[*records_with_exception.flat_map do |r|
+ [r.values["failure_exception"], r.values["job_url"]]
+ end]
+
result[stage][name] = {
file: file,
runs: runs,
failed: failed,
+ exceptions_and_job_urls: exceptions_and_job_urls,
failure_rate: failure_rate == 0 ? failure_rate.round(0) : failure_rate.round(2)
}
end
end
+ # rubocop:enable Metrics/AbcSize
# Flux query
#
@@ -363,19 +390,26 @@ module QA
|> filter(fn: (r) => r._measurement == "test-stats")
|> filter(fn: (r) => r.run_type == "staging-full" or
r.run_type == "staging-sanity" or
- r.run_type == "staging-sanity-no-admin" or
r.run_type == "production-full" or
r.run_type == "production-sanity" or
r.run_type == "package-and-qa" or
r.run_type == "nightly"
)
+ |> filter(fn: (r) => r.job_name != "airgapped" and
+ r.job_name != "instance-image-slow-network" and
+ r.job_name != "nplus1-instance-image"
+ )
|> filter(fn: (r) => r.status != "pending" and
r.merge_request == "false" and
r.quarantined == "false" and
r.smoke == "false" and
- r.reliable == "#{reliable}" and
- r._field == "id"
+ r.reliable == "#{reliable}"
+ )
+ |> filter(fn: (r) => r["_field"] == "job_url" or
+ r["_field"] == "failure_exception" or
+ r["_field"] == "id"
)
+ |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value")
|> group(columns: ["name"])
QUERY
end
diff --git a/qa/qa/tools/test_resources_handler.rb b/qa/qa/tools/test_resources_handler.rb
index 5a56f4a62c7..1ce6919fcc6 100644
--- a/qa/qa/tools/test_resources_handler.rb
+++ b/qa/qa/tools/test_resources_handler.rb
@@ -36,7 +36,7 @@ module QA
QA::EE::Resource::GroupIteration
QA::EE::Resource::Settings::Elasticsearch
QA::EE::Resource::VulnerabilityItem
- QA::EE::Resource::ScanResultPolicyProject
+ QA::EE::Resource::SecurityScanPolicyProject
QA::EE::Resource::ScanResultPolicyCommit
QA::EE::Resource::InstanceAuditEventExternalDestination
].freeze
diff --git a/qa/spec/resource/api_fabricator_spec.rb b/qa/spec/resource/api_fabricator_spec.rb
index 96823ea7ada..b0b84d0b202 100644
--- a/qa/spec/resource/api_fabricator_spec.rb
+++ b/qa/spec/resource/api_fabricator_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe QA::Resource::ApiFabricator do
expect(error.to_s).to eql(<<~ERROR.chomp)
Fabrication of FooBarResource using the API failed (400) with `#{raw_post}`.
Correlation Id: foobar
- Sentry Url: https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg&query=correlation_id%3A%22foobar%22
+ Sentry Url: https://new-sentry.gitlab.net/organizations/gitlab/issues/?environment=gstg&project=3&query=correlation_id%3A%22foobar%22
Kibana - Discover Url: https://nonprod-log.gitlab.net/app/discover#/?_a=%28index:%27ed942d00-5186-11ea-ad8a-f3610a492295%27%2Cquery%3A%28language%3Akuery%2Cquery%3A%27json.correlation_id%20%3A%20foobar%27%29%29&_g=%28time%3A%28from%3A%272022-11-13T00:00:00.000Z%27%2Cto%3A%272022-11-14T00:00:00.000Z%27%29%29
Kibana - Dashboard Url: https://nonprod-log.gitlab.net/app/dashboards#/view/b74dc030-6f56-11ed-9af2-6131f0ee4ce6?_g=%28time%3A%28from:%272022-11-13T00:00:00.000Z%27%2Cto%3A%272022-11-14T00:00:00.000Z%27%29%29&_a=%28filters%3A%21%28%28query%3A%28match_phrase%3A%28json.correlation_id%3A%27foobar%27%29%29%29%29%29
ERROR
diff --git a/qa/spec/specs/helpers/context_selector_spec.rb b/qa/spec/specs/helpers/context_selector_spec.rb
index 369ee60d31d..a4573d96523 100644
--- a/qa/spec/specs/helpers/context_selector_spec.rb
+++ b/qa/spec/specs/helpers/context_selector_spec.rb
@@ -30,11 +30,19 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
end
it 'returns true when url has .net' do
+ allow(GitlabEdition).to receive(:jh?).and_return(false)
QA::Runtime::Scenario.define(:gitlab_address, "https://release.gitlab.net")
expect(described_class.context_matches?).to be_truthy
end
+ it 'returns true when url has .cn on jh side' do
+ allow(GitlabEdition).to receive(:jh?).and_return(true)
+ QA::Runtime::Scenario.define(:gitlab_address, "https://release.gitlab.cn")
+
+ expect(described_class.context_matches?).to be_truthy
+ end
+
it 'returns false when url does not have .com' do
QA::Runtime::Scenario.define(:gitlab_address, "https://gitlab.test")
@@ -83,6 +91,9 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
QA::Runtime::Scenario.define(:gitlab_address, "https://gitlab.hk/")
expect(described_class.context_matches?(:production)).to be_truthy
+
+ QA::Runtime::Scenario.define(:gitlab_address, "https://gitlab.cn/")
+ expect(described_class.context_matches?(:production)).to be_truthy
end
it 'matches domain' do
diff --git a/qa/spec/support/system_logs/sentry_spec.rb b/qa/spec/support/system_logs/sentry_spec.rb
index 6821c527b23..9ea6821484a 100644
--- a/qa/spec/support/system_logs/sentry_spec.rb
+++ b/qa/spec/support/system_logs/sentry_spec.rb
@@ -9,19 +9,19 @@ RSpec.describe QA::Support::SystemLogs::Sentry do
subject { described_class.new(env, correlation_id).url }
let(:staging_url) do
- "https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg&query=correlation_id%3A%22#{correlation_id}%22"
+ "https://new-sentry.gitlab.net/organizations/gitlab/issues/?environment=gstg&project=3&query=correlation_id%3A%22#{correlation_id}%22"
end
let(:staging_ref_url) do
- "https://sentry.gitlab.net/gitlab/staging-ref/?environment=all&query=correlation_id%3A%22#{correlation_id}%22"
+ "https://new-sentry.gitlab.net/organizations/gitlab/projects/staging-ref/?project=18&query=correlation_id%3A%22#{correlation_id}%22"
end
let(:pre_url) do
- "https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=all&query=correlation_id%3A%22#{correlation_id}%22"
+ "https://new-sentry.gitlab.net/organizations/gitlab/issues/?environment=pre&project=3&query=correlation_id%3A%22#{correlation_id}%22"
end
let(:production_url) do
- "https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd&query=correlation_id%3A%22#{correlation_id}%22"
+ "https://new-sentry.gitlab.net/organizations/gitlab/issues/?environment=gprd&project=3&query=correlation_id%3A%22#{correlation_id}%22"
end
where(:env, :expected_url) do
diff --git a/qa/spec/tools/reliable_report_spec.rb b/qa/spec/tools/reliable_report_spec.rb
index 9786d247d5e..caef8f89bd5 100644
--- a/qa/spec/tools/reliable_report_spec.rb
+++ b/qa/spec/tools/reliable_report_spec.rb
@@ -40,6 +40,8 @@ describe QA::Tools::ReliableReport do
"status" => "failed",
"file_path" => "some/spec.rb",
"stage" => "create",
+ "failure_exception" => "failure message",
+ "job_url" => "https://job/url",
"_time" => time
}
[
@@ -61,19 +63,26 @@ describe QA::Tools::ReliableReport do
|> filter(fn: (r) => r._measurement == "test-stats")
|> filter(fn: (r) => r.run_type == "staging-full" or
r.run_type == "staging-sanity" or
- r.run_type == "staging-sanity-no-admin" or
r.run_type == "production-full" or
r.run_type == "production-sanity" or
r.run_type == "package-and-qa" or
r.run_type == "nightly"
)
+ |> filter(fn: (r) => r.job_name != "airgapped" and
+ r.job_name != "instance-image-slow-network" and
+ r.job_name != "nplus1-instance-image"
+ )
|> filter(fn: (r) => r.status != "pending" and
r.merge_request == "false" and
r.quarantined == "false" and
r.smoke == "false" and
- r.reliable == "#{reliable}" and
- r._field == "id"
+ r.reliable == "#{reliable}"
+ )
+ |> filter(fn: (r) => r["_field"] == "job_url" or
+ r["_field"] == "failure_exception" or
+ r["_field"] == "id"
)
+ |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value")
|> group(columns: ["name"])
QUERY
end
@@ -106,8 +115,12 @@ describe QA::Tools::ReliableReport do
)
end
- def name_column(spec_name)
- "**name**: #{spec_name}<br>**file**: spec.rb"
+ def name_column(spec_name, exceptions_and_job_urls = {})
+ "**name**: #{spec_name}<br>**file**: spec.rb#{exceptions_markdown(exceptions_and_job_urls)}"
+ end
+
+ def exceptions_markdown(exceptions_and_job_urls)
+ exceptions_and_job_urls.empty? ? '' : "<br>**Exceptions**:<br>- [`failure message`](https://job/url)"
end
before do
@@ -184,7 +197,7 @@ describe QA::Tools::ReliableReport do
Total amount: **1**
- #{markdown_section([['create', 1]], [[name_column('unstable spec'), 3, 2, '66.67%']], 'create', 'unstable')}
+ #{markdown_section([['create', 1]], [[name_column('unstable spec', { 'failure message' => 'https://job/url' }), 3, 2, '66.67%']], 'create', 'unstable')}
TXT
end
diff --git a/rubocop/cop/capybara/testid_finders.rb b/rubocop/cop/capybara/testid_finders.rb
new file mode 100644
index 00000000000..c45af1eb66c
--- /dev/null
+++ b/rubocop/cop/capybara/testid_finders.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'rubocop-rspec'
+
+module RuboCop
+ module Cop
+ module Capybara
+ # Prefer to use data-testid helpers for Capybara
+ #
+ # @example
+ # # bad
+ # find('[data-testid="some-testid"]')
+ # within('[data-testid="some-testid"]')
+ #
+ # # good
+ # find_by_testid('some-testid')
+ # within_testid('some-testid')
+ #
+ class TestidFinders < RuboCop::Cop::Base
+ MSG = 'Prefer to use custom helper method `%{replacement}(%{testid})`.'
+
+ METHOD_MAP = {
+ find: 'find_by_testid',
+ within: 'within_testid'
+ }.freeze
+
+ RESTRICT_ON_SEND = METHOD_MAP.keys.to_set.freeze
+
+ # @!method find_argument(node)
+ def_node_matcher :argument, <<~PATTERN
+ (send _ ${RESTRICT_ON_SEND} (str $_) ...)
+ PATTERN
+
+ def on_send(node)
+ argument(node) do |method, arg|
+ selector = data_testid_selector(arg)
+ next unless selector
+
+ replacement = METHOD_MAP.fetch(method)
+ msg = format(MSG, testid: selector, replacement: replacement)
+
+ add_offense(node, message: msg)
+ end
+ end
+
+ private
+
+ def data_testid_selector(arg)
+ arg[/^\[data-testid=[",'](.+)[",']\]$/, 1]
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/lint/last_keyword_argument.rb b/rubocop/cop/lint/last_keyword_argument.rb
deleted file mode 100644
index f50c25f7924..00000000000
--- a/rubocop/cop/lint/last_keyword_argument.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-# frozen_string_literal: true
-
-module RuboCop
- module Cop
- module Lint
- # This cop only works if there are files from deprecation_toolkit. You can
- # generate these files by:
- #
- # 1. Running specs with RECORD_DEPRECATIONS=1
- # 1. Downloading the complete set of deprecations/ files from a CI
- # pipeline (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47720)
- class LastKeywordArgument < RuboCop::Cop::Base
- extend RuboCop::Cop::AutoCorrector
-
- MSG = 'Using the last argument as keyword parameters is deprecated'
-
- DEPRECATIONS_GLOB = File.expand_path('../../../deprecations/**/*.yml', __dir__)
- KEYWORD_DEPRECATION_STR = 'maybe ** should be added to the call'
-
- def on_send(node)
- return if target_ruby_version >= 3.0
-
- arg = get_last_argument(node)
- return unless arg
-
- return unless known_match?(processed_source.file_path, node.first_line, node.method_name.to_s)
-
- return if arg.children.first.respond_to?(:kwsplat_type?) && arg.children.first&.kwsplat_type?
-
- # parser thinks `a: :b, c: :d` is hash type, it's actually kwargs
- return if arg.hash_type? && !arg.source.match(/\A{/)
-
- add_offense(arg) do |corrector|
- if arg.hash_type?
- kwarg = arg.source.sub(/\A{\s*/, '').sub(/\s*}\z/, '')
- corrector.replace(arg, kwarg)
- elsif arg.splat_type?
- corrector.insert_before(arg, '*')
- else
- corrector.insert_before(arg, '**')
- end
- end
- end
-
- private
-
- def get_last_argument(node)
- return node.arguments[-2] if node.block_argument?
-
- node.arguments.last
- end
-
- def known_match?(file_path, line_number, method_name)
- method_name = 'initialize' if method_name == 'new'
-
- return unless self.class.keyword_warnings[method_name]
-
- file_path_from_root = file_path.sub(File.expand_path('../../..', __dir__), '')
- file_and_line = "#{file_path_from_root}:#{line_number}"
-
- self.class.keyword_warnings[method_name].any? do |warning|
- warning.include?(file_and_line)
- end
- end
-
- def self.keyword_warnings
- @keyword_warnings ||= keywords_list
- end
-
- def self.keywords_list
- hash = Dir.glob(DEPRECATIONS_GLOB).each_with_object({}) do |file, hash|
- hash.merge!(YAML.safe_load(File.read(file)))
- end
-
- hash.values.flatten.each_with_object({}) do |str, results|
- next unless str.include?(KEYWORD_DEPRECATION_STR)
-
- match_data = str.match(/called method `([^\s]+)'/)
- next unless match_data
-
- key = match_data[1]
- results[key] ||= []
- results[key] << str
- end
- end
- end
- end
- end
-end
diff --git a/rubocop/cop/migration/versioned_migration_class.rb b/rubocop/cop/migration/versioned_migration_class.rb
index d078acedb37..6bb676667d5 100644
--- a/rubocop/cop/migration/versioned_migration_class.rb
+++ b/rubocop/cop/migration/versioned_migration_class.rb
@@ -60,6 +60,7 @@ module RuboCop
# Returns true for any parent class of format Gitlab::Database::Migration[version] if version < current_version
def old_version_migration_class?(class_node)
parent_class_node = class_node.parent_class
+ return false if parent_class_node.nil?
return false unless parent_class_node.send_type? && parent_class_node.arguments.last.float_type?
return false unless parent_class_node.children[0].const_name == GITLAB_MIGRATION_CLASS
diff --git a/rubocop/rubocop-ruby27.yml b/rubocop/rubocop-ruby27.yml
deleted file mode 100644
index 29957defeb0..00000000000
--- a/rubocop/rubocop-ruby27.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-# RuboCop configuration adjustments during the transition time from Ruby 2.7 to
-# Ruby 3.0. This configuration should be removed after the transition has been
-# completed.
-
-# These cops are enabled in Ruby 3.0 (rubocop-30.yml).
-Style/MutableConstant:
- Enabled: false
-Style/RedundantFreeze:
- Enabled: false
diff --git a/rubocop/rubocop-ruby30.yml b/rubocop/rubocop-ruby30.yml
deleted file mode 100644
index b984d761b80..00000000000
--- a/rubocop/rubocop-ruby30.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-# RuboCop configuration adjustments during the transition time from Ruby 2.7 to
-# Ruby 3.0.
-#
-# After the transition has been completed:
-# * Move all configuration which enabled or tweaked cops to .rubocop.yml.
-# * Remove all remaining configuration.
-
-# These cops are disabled in Ruby 2.7 (rubocop-27.yml).
-Style/MutableConstant:
- Enabled: true
-Style/RedundantFreeze:
- Enabled: true
-
-# No longer needed because Ruby 3.0 will fail due to kwargs issues.
-Lint/LastKeywordArgument:
- Enabled: false
diff --git a/scripts/build_gdk_image b/scripts/build_gdk_image
index 8b1fdec2d7d..cb1dbd03adb 100755
--- a/scripts/build_gdk_image
+++ b/scripts/build_gdk_image
@@ -8,10 +8,6 @@ REGISTRY="${CI_REGISTRY}/${CI_PROJECT_PATH}"
SHA_TAG="${CI_COMMIT_SHA}"
BRANCH_TAG="${CI_COMMIT_REF_SLUG}"
-# Fetch ruby version based on contents of .ruby-version
-RUBY_VERSION=$(cat .ruby-version)
-RUBY_VERSION_MINOR=$(echo "$RUBY_VERSION" | awk -F. '{$3=0; OFS="."; print $1,$2,$3}')
-
IMAGE="${REGISTRY}/gitlab-qa-gdk"
if [[ -n "${CI}" ]]; then
@@ -20,17 +16,16 @@ else
OUTPUT_OPTION="--load"
fi
-echoinfo "Building GDK image with GDK sha: '${GDK_SHA}'" "yes"
+echoinfo "Building GDK image" "yes"
docker buildx build \
- --cache-to="type=inline" \
- --cache-from="${IMAGE}:${BRANCH_TAG}" \
- --cache-from="${IMAGE}:master" \
+ --cache-to="type=registry,mode=max,image-manifest=true,ref=${IMAGE}/cache:${BRANCH_TAG}" \
+ --cache-from="${IMAGE}/cache:${BRANCH_TAG}" \
+ --cache-from="${IMAGE}/cache:master" \
--file="qa/gdk/Dockerfile.gdk" \
--platform=${ARCH:-amd64} \
--tag="${IMAGE}:${SHA_TAG}" \
--tag="${IMAGE}:${BRANCH_TAG}" \
- --build-arg="GEM_CACHE=/home/gdk/.asdf/installs/ruby/${RUBY_VERSION}/lib/ruby/gems/${RUBY_VERSION_MINOR}/cache" \
${OUTPUT_OPTION} \
.
diff --git a/scripts/decomposition/generate-loose-foreign-key b/scripts/decomposition/generate-loose-foreign-key
index 66781343411..d52fa2b4f3f 100755
--- a/scripts/decomposition/generate-loose-foreign-key
+++ b/scripts/decomposition/generate-loose-foreign-key
@@ -167,8 +167,6 @@ def generate_migration(definition)
FOREIGN_KEY_NAME = "#{definition.name}"
def up
- return unless foreign_key_exists?(:#{definition.from_table}, :#{definition.to_table}, name: FOREIGN_KEY_NAME)
-
with_lock_retries do
remove_foreign_key_if_exists(:#{definition.from_table}, :#{definition.to_table},
name: FOREIGN_KEY_NAME, reverse_lock_order: true)
diff --git a/scripts/frontend/create_jsconfig.js b/scripts/frontend/create_jsconfig.js
index 7e2d0eb02c4..be95c5cb2d3 100755
--- a/scripts/frontend/create_jsconfig.js
+++ b/scripts/frontend/create_jsconfig.js
@@ -30,8 +30,19 @@ async function createJsConfig() {
// eslint-disable-next-line global-require
const webpackConfig = require('../../config/webpack.config');
- const paths = {}; // aliases
- const WEBPACK_ALIAS_EXCEPTIONS = ['jquery$', '@gitlab/svgs/dist/icons.svg'];
+ // Aliases
+ const paths = {
+ // NOTE: Sentry is exposed via a wrapper, which has a limited API.
+ '@sentry/browser': [
+ path.relative(PATH_PROJECT_ROOT, 'app/assets/javascripts/sentry/sentry_browser_wrapper.js'),
+ ],
+ };
+ const WEBPACK_ALIAS_EXCEPTIONS = [
+ 'jquery$',
+ '@gitlab/svgs/dist/icons.svg',
+ '@apollo/client$',
+ '@sentry/browser$',
+ ];
Object.entries(webpackConfig.resolve.alias)
.filter(([key]) => !WEBPACK_ALIAS_EXCEPTIONS.includes(key))
.forEach(([key, value]) => {
@@ -40,6 +51,7 @@ async function createJsConfig() {
paths[alias] = target;
});
+ // JS/TS config. See more: https://www.typescriptlang.org/tsconfig
const jsConfig = {
// As we're introducing jsconfig to the project, as a precaution we add both:
// 'include' and 'exclude' options. This might be simplified in the future.
@@ -52,13 +64,22 @@ async function createJsConfig() {
'ee/app/assets/javascripts',
'spec/frontend',
'ee/spec/frontend',
- 'tmp/tests/frontend/fixtures/',
- 'tmp/tests/frontend/fixtures-ee/',
+ 'tmp/tests/frontend/fixtures',
+ 'tmp/tests/frontend/fixtures-ee',
],
+
+ // Explicitly enable automatic type acquisition
+ // See more: https://www.typescriptlang.org/tsconfig#type-acquisition
+ typeAcquisition: {
+ enable: true,
+ },
+
compilerOptions: {
baseUrl: '.', // Define the project root
checkJs: false, // Disable type checking on JavaScript files
disableSizeLimit: true, // Disable memory size limit for the language server
+ skipLibCheck: true, // Skip type checking all .d.ts files
+ resolveJsonModule: true, // Enable importing .json files
paths, // Aliases
},
};
diff --git a/scripts/frontend/preinstall.mjs b/scripts/frontend/preinstall.mjs
new file mode 100644
index 00000000000..09d980344ea
--- /dev/null
+++ b/scripts/frontend/preinstall.mjs
@@ -0,0 +1,59 @@
+import { dirname, join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { readFile, rm } from 'node:fs/promises';
+
+const ROOT_PATH = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
+const NODE_MODULES = join(ROOT_PATH, 'node_modules');
+const INTEGRITY_FILE = join(NODE_MODULES, '.yarn-integrity');
+const PACKAGE_JSON = join(ROOT_PATH, 'package.json');
+
+function isAliasedDependency(x) {
+ return x.includes('@npm:');
+}
+function serializeAliasedDependencyPatterns(obj) {
+ return Object.entries(obj).map(([key, version]) => `${key}@${version}`);
+}
+
+async function readJSON(file) {
+ return JSON.parse(await readFile(file, { encoding: 'utf-8' }));
+}
+
+async function getPrevTopLevelPatterns() {
+ try {
+ return (await readJSON(INTEGRITY_FILE))?.topLevelPatterns?.filter(isAliasedDependency);
+ } catch {
+ return [];
+ }
+}
+async function getCurrentTopLevelPatterns() {
+ try {
+ const { dependencies, devDependencies } = await readJSON(PACKAGE_JSON);
+
+ return serializeAliasedDependencyPatterns(dependencies)
+ .concat(serializeAliasedDependencyPatterns(devDependencies))
+ .filter(isAliasedDependency);
+ } catch {
+ return [];
+ }
+}
+
+function arraysHaveSameItems(a1, a2) {
+ return JSON.stringify(a1.sort()) === JSON.stringify(a2.sort());
+}
+
+const [prevTopLevelPatterns, currentTopLevelPatterns] = await Promise.all([
+ getPrevTopLevelPatterns(),
+ getCurrentTopLevelPatterns(),
+]);
+
+/**
+ * Yarn seems to have problems at times, if one uses an <alias>@npm:<name>
+ * and those packages are being updated. In case one switches branches the
+ * node_modules folder seems to end up being a corrupted somehow
+ */
+if (!arraysHaveSameItems(prevTopLevelPatterns, currentTopLevelPatterns)) {
+ console.error(
+ '[WARNING] package.json changed significantly. Removing node_modules to be sure there are no problems.',
+ );
+ await rm(NODE_MODULES, { recursive: true, force: true });
+}
diff --git a/scripts/frontend/webpack_dev_server.js b/scripts/frontend/webpack_dev_server.js
index a76e6dc024a..ae73c14b501 100755
--- a/scripts/frontend/webpack_dev_server.js
+++ b/scripts/frontend/webpack_dev_server.js
@@ -30,17 +30,15 @@ if (STATIC_MODE) {
// run webpack through webpack-dev-server, optionally compiling a DLL to reduce memory
else {
- const watch = ['config/webpack.config.js'];
+ const watch = [
+ 'config/webpack.config.js',
+ // ensure we refresh when running yarn install
+ 'node_modules/.yarn-integrity',
+ ];
// if utilizing the vendor DLL, we need to restart the process when dependency changes occur
if (DLL_MODE) {
- watch.push(
- 'config/webpack.vendor.config.js',
- // ensure we refresh when running yarn install
- 'node_modules/.yarn-integrity',
- 'package.json',
- 'yarn.lock',
- );
+ watch.push('config/webpack.vendor.config.js', 'package.json', 'yarn.lock');
}
nodemon({
exec: 'webpack-dev-server --config config/webpack.config.js',
diff --git a/scripts/generate-message-to-run-e2e-pipeline.rb b/scripts/generate-message-to-run-e2e-pipeline.rb
index cfe480ac5c7..ccbaba8a3eb 100755
--- a/scripts/generate-message-to-run-e2e-pipeline.rb
+++ b/scripts/generate-message-to-run-e2e-pipeline.rb
@@ -83,7 +83,7 @@ class GenerateMessageToRunE2ePipeline
Once done, apply the ✅ emoji on this comment.
- For any questions or help, reach out on the internal #quality Slack channel.
+ **Team members only:** for any questions or help, reach out on the internal `#quality` Slack channel.
<!-- Run e2e warning end -->
MARKDOWN
end
diff --git a/scripts/gitaly-test-spawn b/scripts/gitaly-test-spawn
index 9285b561ae0..f3688a6e88e 100755
--- a/scripts/gitaly-test-spawn
+++ b/scripts/gitaly-test-spawn
@@ -10,6 +10,8 @@ class GitalyTestSpawn
include GitalySetup
def run
+ ensure_gitlab_shell_secret!
+
# Run Praefect migrations
setup_praefect
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index e6b63925fc6..6683802c2fe 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -149,7 +149,7 @@ else
if [ -n "${MD_DOC_PATH}" ]
then
# shellcheck disable=2059
- printf "${COLOR_GREEN}INFO: Merged results pipeline detected. Testing only the following files:${COLOR_RESET}\n${MD_DOC_PATH}"
+ printf "${COLOR_GREEN}INFO: Merged results pipeline detected. Testing only the following files:${COLOR_RESET}\n${MD_DOC_PATH}\n"
fi
fi
fi
diff --git a/scripts/lint-docs-redirects.rb b/scripts/lint-docs-redirects.rb
new file mode 100755
index 00000000000..fb4ac19981d
--- /dev/null
+++ b/scripts/lint-docs-redirects.rb
@@ -0,0 +1,203 @@
+#!/usr/bin/env ruby
+
+# frozen_string_literal: true
+
+#
+# https://docs.gitlab.com/ee/development/documentation/redirects.html
+#
+require 'net/http'
+require 'uri'
+require 'json'
+require 'cgi'
+
+class LintDocsRedirect
+ COLOR_CODE_RED = "\e[31m"
+ COLOR_CODE_RESET = "\e[0m"
+ # All the projects we want this script to run
+ PROJECT_PATHS = ['gitlab-org/gitlab',
+ 'gitlab-org/gitlab-runner',
+ 'gitlab-org/omnibus-gitlab',
+ 'gitlab-org/charts/gitlab',
+ 'gitlab-org/cloud-native/gitlab-operator'].freeze
+
+ def execute
+ return unless project_supported?
+
+ abort_unless_merge_request_iid_exists
+
+ check_renamed_deleted_files
+ end
+
+ private
+
+ # Project slug based on project path
+ # Taken from https://gitlab.com/gitlab-org/gitlab/-/blob/daaa5b6f79049e5bb28cdafaa11d3a0a84d64ab3/scripts/trigger-build.rb#L298-313
+ def project_slug
+ case ENV['CI_PROJECT_PATH']
+ when 'gitlab-org/gitlab'
+ 'ee'
+ when 'gitlab-org/gitlab-runner'
+ 'runner'
+ when 'gitlab-org/omnibus-gitlab'
+ 'omnibus'
+ when 'gitlab-org/charts/gitlab'
+ 'charts'
+ when 'gitlab-org/cloud-native/gitlab-operator'
+ 'operator'
+ end
+ end
+
+ def navigation_file
+ @navigation_file ||= begin
+ url = URI('https://gitlab.com/gitlab-org/gitlab-docs/-/raw/main/content/_data/navigation.yaml')
+ response = Net::HTTP.get_response(url)
+
+ raise "Could not download navigation.yaml. Response code: #{response.code}" if response.code != '200'
+
+ # response.body should be memoized in a method, so that it doesn't
+ # need to be downloaded multiple times in one CI job.
+ response.body
+ end
+ end
+
+ ##
+ ## Check if the deleted/renamed file exists in
+ ## https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/content/_data/navigation.yaml.
+ ##
+ ## We need to first convert the Markdown file to HTML. There are two cases:
+ ##
+ ## - A source doc entry with index.md looks like: doc/administration/index.md
+ ## The navigation.yaml equivalent is: ee/administration/
+ ## - A source doc entry without index.md looks like: doc/administration/appearance.md
+ ## The navigation.yaml equivalent is: ee/administration/appearance.html
+ ##
+ def check_for_missing_nav_entry(file)
+ file_sub = file["old_path"].gsub('doc', project_slug).gsub('index.md', '').gsub('.md', '.html')
+
+ result = navigation_file.include?(file_sub)
+ return unless result
+
+ warning(file)
+
+ abort
+ end
+
+ def warning(file)
+ warn <<~WARNING
+ #{COLOR_CODE_RED}✖ ERROR: Missing redirect for a deleted or moved page#{COLOR_CODE_RESET}
+
+ The following file is linked in the global navigation for docs.gitlab.com:
+
+ => #{file['old_path']}
+
+ Unless you add a redirect or remove the page from the global navigation,
+ this change will break pipelines in the 'gitlab/gitlab-docs' project.
+
+ #{rake_command(file)}
+
+ For more information, see:
+ - Create a redirect : https://docs.gitlab.com/ee/development/documentation/redirects.html
+ - Edit the global nav : https://docs.gitlab.com/ee/development/documentation/site_architecture/global_nav.html#add-a-navigation-entry
+ WARNING
+ end
+
+ # Rake task to use depending on the file being deleted or renamed
+ def rake_command(file)
+ # The Rake task is only available for gitlab-org/gitlab
+ return unless project_slug == 'ee'
+
+ if renamed_doc_file?(file)
+ rake = "bundle exec rake \"gitlab:docs:redirect[#{file['old_path']}, #{file['new_path']}]\""
+ msg = "It seems you renamed a page, run the following Rake task locally and commit the changes.\n"
+ elsif deleted_doc_file?(file)
+ rake = "bundle exec rake \"gitlab:docs:redirect[#{file['old_path']}, doc/new/path.md]\""
+ msg = "It seems you deleted a page. Run the following Rake task by replacing\n" \
+ "'doc/new/path.md' with the page to redirect to, and commit the changes.\n"
+ end
+
+ <<~MSG
+ #{msg}
+ #{rake}
+ MSG
+ end
+
+ # GitLab API URL
+ def gitlab_api_url
+ ENV.fetch('CI_API_V4_URL', 'https://gitlab.com/api/v4')
+ end
+
+ # Take the project path from the CI_PROJECT_PATH predefined variable.
+ def url_encoded_project_path
+ project_path = ENV.fetch('CI_PROJECT_PATH', nil)
+ return unless project_path
+
+ CGI.escape(project_path)
+ end
+
+ # Take the merge request ID from the CI_MERGE_REQUEST_IID predefined
+ # variable.
+ def merge_request_iid
+ ENV.fetch('CI_MERGE_REQUEST_IID', nil)
+ end
+
+ def abort_unless_merge_request_iid_exists
+ abort("Error: CI_MERGE_REQUEST_IID environment variable is missing") if merge_request_iid.nil?
+ end
+
+ # Skip if CI_PROJECT_PATH is not in the designated project paths
+ def project_supported?
+ PROJECT_PATHS.include? ENV['CI_PROJECT_PATH']
+ end
+
+ # Fetch the merge request diff JSON object
+ def merge_request_diff
+ @merge_request_diff ||= begin
+ uri = URI.parse(
+ "#{gitlab_api_url}/projects/#{url_encoded_project_path}/merge_requests/#{merge_request_iid}/diffs?per_page=30"
+ )
+ response = Net::HTTP.get_response(uri)
+
+ unless response.code == '200'
+ raise "API call to get MR diffs failed. Response code: #{response.code}. Response message: #{response.message}"
+ end
+
+ JSON.parse(response.body)
+ end
+ end
+
+ def renamed_doc_file?(file)
+ file['renamed_file'] == true && file['old_path'].start_with?('doc')
+ end
+
+ def deleted_doc_file?(file)
+ file['deleted_file'] == true && file['old_path'].start_with?('doc')
+ end
+
+ # Create a list of hashes of the renamed documentation files
+ def check_renamed_deleted_files
+ renamed_files = merge_request_diff.select do |file|
+ renamed_doc_file?(file)
+ end
+
+ deleted_files = merge_request_diff.select do |file|
+ deleted_doc_file?(file)
+ end
+
+ # Merge the two arrays
+ all_files = renamed_files + deleted_files
+
+ return if all_files.empty?
+
+ all_files.each do |file|
+ status = deleted_doc_file?(file) ? 'deleted' : 'renamed'
+ puts "Checking #{status} file..."
+ puts "=> Old_path: #{file['old_path']}"
+ puts "=> New_path: #{file['new_path']}"
+ puts
+
+ check_for_missing_nav_entry(file)
+ end
+ end
+end
+
+LintDocsRedirect.new.execute if $PROGRAM_NAME == __FILE__
diff --git a/scripts/process_custom_semgrep_results.sh b/scripts/process_custom_semgrep_results.sh
index 1fdd8e486f3..0eccef00973 100755
--- a/scripts/process_custom_semgrep_results.sh
+++ b/scripts/process_custom_semgrep_results.sh
@@ -22,7 +22,7 @@ jq -crM '.vulnerabilities |
echo "Resulting file:"
cat findings.txt
-EXISTING_COMMENT_ID=$(curl "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes" \
+EXISTING_COMMENT_ID=$(curl "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes?per_page=100" \
--header "Private-Token: $CUSTOM_SAST_RULES_BOT_PAT" |
jq -crM 'map( select( .author.id == (env.BOT_USER_ID | tonumber) ) | .id ) | first')
diff --git a/scripts/remote_development/run-e2e-tests.sh b/scripts/remote_development/run-e2e-tests.sh
index 63d828d323c..1c1fb07ea53 100755
--- a/scripts/remote_development/run-e2e-tests.sh
+++ b/scripts/remote_development/run-e2e-tests.sh
@@ -7,7 +7,7 @@
# them to be overridden.
#
# For details on how to run this, see the documentation comments at the top of
-# qa/qa/specs/features/ee/browser_ui/3_create/remote_development/create_new_workspace_and_terminate_spec.rb
+# qa/qa/specs/features/ee/browser_ui/3_create/remote_development/with_prerequisite_done/workspace_actions_with_prerequisite_done_spec.rb
DEFAULT_PASSWORD='5iveL!fe'
@@ -28,9 +28,8 @@ echo "TEST_INSTANCE_URL: ${TEST_INSTANCE_URL}"
working_directory="$(git rev-parse --show-toplevel)/qa"
-# TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/397005
-# Remove the '--tag quarantine' from below once this test is removed from quarantine
+# This test is currently quarantined as its only used for local testing, so we have to use the '--tag quarantine'
(cd "$working_directory" && \
bundle && \
bundle exec bin/qa Test::Instance::All "$TEST_INSTANCE_URL" -- \
- --tag quarantine qa/specs/features/ee/browser_ui/3_create/remote_development/without_setup)
+ --tag quarantine qa/specs/features/ee/browser_ui/3_create/remote_development/with_prerequisite_done/workspace_actions_with_prerequisite_done_spec.rb)
diff --git a/scripts/remote_development/run-smoke-test-suite.sh b/scripts/remote_development/run-smoke-test-suite.sh
index 9ab692e6a15..14c50678fba 100755
--- a/scripts/remote_development/run-smoke-test-suite.sh
+++ b/scripts/remote_development/run-smoke-test-suite.sh
@@ -32,7 +32,7 @@ printf "${Color_Off}"
printf "${BBlue}Running Remote Development backend specs${Color_Off}\n\n"
bin/rspec -r spec_helper \
-$(find . -path '**/remote_development/**/*_spec.rb') \
+$(find . -path './**/remote_development/*_spec.rb' | grep -v 'qa/qa') \
ee/spec/graphql/types/query_type_spec.rb \
ee/spec/graphql/types/subscription_type_spec.rb \
ee/spec/requests/api/internal/kubernetes_spec.rb \
diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh
index cab1ac10f35..eefd9ed4993 100644
--- a/scripts/rspec_helpers.sh
+++ b/scripts/rspec_helpers.sh
@@ -166,7 +166,6 @@ function debug_shell_options() {
}
function debug_rspec_variables() {
- echoinfo "SKIP_FLAKY_TESTS_AUTOMATICALLY: ${SKIP_FLAKY_TESTS_AUTOMATICALLY:-}"
echoinfo "RETRY_FAILED_TESTS_IN_NEW_PROCESS: ${RETRY_FAILED_TESTS_IN_NEW_PROCESS:-}"
echoinfo "KNAPSACK_GENERATE_REPORT: ${KNAPSACK_GENERATE_REPORT:-}"
diff --git a/scripts/setup-test-env b/scripts/setup-test-env
index 50bec46b71a..a9d1be7a0ce 100755
--- a/scripts/setup-test-env
+++ b/scripts/setup-test-env
@@ -24,6 +24,7 @@ require_relative '../lib/system_check/helpers'
# Required for config/initializers/1_settings.rb
require 'omniauth'
require 'omniauth-github'
+require 'omniauth-saml'
require 'etc'
require 'gitlab/utils/all'
require 'gitlab/safe_request_store'
diff --git a/scripts/setup/as-if-jh.sh b/scripts/setup/as-if-jh.sh
index ffc3c6582db..6701f12e64c 100755
--- a/scripts/setup/as-if-jh.sh
+++ b/scripts/setup/as-if-jh.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-prepare_jh_branch() {
+set_jh_branch_env_variable() {
set -eu # https://explainshell.com/explain?cmd=set+-eu
JH_BRANCH="$(./scripts/setup/find-jh-branch.rb)"
@@ -9,7 +9,15 @@ prepare_jh_branch() {
echoinfo "JH_BRANCH: ${JH_BRANCH}"
}
-download_jh_path() {
+download_jh_files() {
+ if [ "${JH_BRANCH}" = "main-jh" ]; then
+ download_jh_files_from_api "$@"
+ else
+ download_jh_files_from_git_clone "$@"
+ fi
+}
+
+download_jh_files_from_api() {
set -eu # https://explainshell.com/explain?cmd=set+-eu
for path in "$@"; do
@@ -17,11 +25,50 @@ download_jh_path() {
# shellcheck disable=SC3043
local output="${path}.tar.gz"
- echoinfo "Downloading ${path}"
+ echoinfo "Downloading ${path} via API"
+ # Note: We are limited to 5 downloads/minute on this endpoint.
+ # (see https://docs.gitlab.com/ee/api/repositories.html#get-file-archive)
+ #
+ # If we run this command more than 5 times/minute, we will receive HTTP 429 errors.
+ #
+ # If this problem happens too often, we might want to either download files from
+ # another endpoint, and only download the folders with this endpoint. We could also
+ # do a git clone in all cases.
curl -f --location --output "${output}" --header "Private-Token: ${ADD_JH_FILES_TOKEN}" --get --data-urlencode "sha=${JH_BRANCH}" --data-urlencode "path=${path}" "https://gitlab.com/api/v4/projects/${GITLAB_JH_MIRROR_PROJECT}/repository/archive"
tar -zxf "${output}" --strip-component 1
rm "${output}"
done
}
+
+# The JiHu mirror project is private, so we would need to be authenticated to download files from the API.
+#
+# When being authenticated and downloading files via the API, we are limited to 5 requests per minute
+# (see https://docs.gitlab.com/ee/api/repositories.html#get-file-archive), and we would need to download 6 files
+# (3 archives for two branches). This job can also be run in parallel between many pipelines.
+download_jh_files_from_git_clone() {
+ return_code=0
+ git_merge_status_code=0
+
+ echoinfo "Cloning JH mirror repo to download JH files"
+
+ git config --global user.email "${GITLAB_USER_EMAIL}";
+ git config --global user.name "${GITLAB_USER_NAME}";
+
+ git clone --filter=tree:0 "${JH_MIRROR_REPOSITORY}" gitlab-jh
+ cd gitlab-jh
+ git checkout "${JH_BRANCH}"
+
+ git merge main-jh || git_merge_status_code=$?
+ if [ "${git_merge_status_code}" -ne 0 ]; then
+ git merge --abort || true
+ return_code=3
+ fi
+
+ mv ${JH_FILES_TO_COMMIT} ./..
+ cd ..
+
+ # We explicitly use exit instead of return, otherwise the job would exit with a 1 error code
+ exit "${return_code}"
+}
diff --git a/scripts/trigger-build.rb b/scripts/trigger-build.rb
index 8f509399fd4..98ca8112d62 100755
--- a/scripts/trigger-build.rb
+++ b/scripts/trigger-build.rb
@@ -307,6 +307,8 @@ module Trigger
'omnibus'
when 'gitlab-org/charts/gitlab'
'charts'
+ when 'gitlab-org/cloud-native/gitlab-operator'
+ 'operator'
end
end
diff --git a/spec/components/pajamas/banner_component_spec.rb b/spec/components/pajamas/banner_component_spec.rb
index 6b99b4c1d76..c9d9a9176e8 100644
--- a/spec/components/pajamas/banner_component_spec.rb
+++ b/spec/components/pajamas/banner_component_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Pajamas::BannerComponent, type: :component do
end
it 'renders a close button' do
- expect(page).to have_css "button.gl-banner-close"
+ expect(page).to have_css "button.gl-button.gl-banner-close"
end
describe 'button_text and button_link' do
diff --git a/spec/contracts/consumer/resources/graphql/pipelines.js b/spec/contracts/consumer/resources/graphql/pipelines.js
index 48724e15eb8..201045e011f 100644
--- a/spec/contracts/consumer/resources/graphql/pipelines.js
+++ b/spec/contracts/consumer/resources/graphql/pipelines.js
@@ -5,7 +5,7 @@ import { extractGraphQLQuery } from '../../helpers/graphql_query_extractor';
export async function getPipelineHeaderDataRequest(endpoint) {
const { url } = endpoint;
const query = await extractGraphQLQuery(
- 'app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql',
+ 'app/assets/javascripts/ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql',
);
const graphqlQuery = {
query,
@@ -27,7 +27,7 @@ export async function getPipelineHeaderDataRequest(endpoint) {
export async function deletePipeline(endpoint) {
const { url } = endpoint;
const query = await extractGraphQLQuery(
- 'app/assets/javascripts/pipelines/graphql/mutations/delete_pipeline.mutation.graphql',
+ 'app/assets/javascripts/ci/pipeline_details/graphql/mutations/delete_pipeline.mutation.graphql',
);
const graphqlQuery = {
query,
diff --git a/spec/contracts/consumer/specs/project/pipelines/show.spec.js b/spec/contracts/consumer/specs/project/pipelines/show.spec.js
index 97ad9dbbc9d..d2743b1037f 100644
--- a/spec/contracts/consumer/specs/project/pipelines/show.spec.js
+++ b/spec/contracts/consumer/specs/project/pipelines/show.spec.js
@@ -27,7 +27,7 @@ pactWith(
describe(GET_PIPELINE_HEADER_DATA_PROVIDER_NAME, () => {
beforeEach(async () => {
const query = await extractGraphQLQuery(
- 'app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql',
+ 'app/assets/javascripts/ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql',
);
const graphqlQuery = new GraphQLInteraction()
.given(PipelineHeaderData.scenario.state)
@@ -64,7 +64,7 @@ pactWith(
describe(DELETE_PIPELINE_PROVIDER_NAME, () => {
beforeEach(async () => {
const query = await extractGraphQLQuery(
- 'app/assets/javascripts/pipelines/graphql/mutations/delete_pipeline.mutation.graphql',
+ 'app/assets/javascripts/ci/pipeline_details/graphql/mutations/delete_pipeline.mutation.graphql',
);
const graphqlQuery = new GraphQLInteraction()
.given(DeletePipeline.scenario.state)
diff --git a/spec/controllers/activity_pub/projects/releases_controller_spec.rb b/spec/controllers/activity_pub/projects/releases_controller_spec.rb
new file mode 100644
index 00000000000..8719756b260
--- /dev/null
+++ b/spec/controllers/activity_pub/projects/releases_controller_spec.rb
@@ -0,0 +1,134 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ActivityPub::Projects::ReleasesController, feature_category: :groups_and_projects do
+ include AccessMatchersForController
+
+ let_it_be(:project) { create(:project, :repository, :public) }
+ let_it_be(:private_project) { create(:project, :repository, :private) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:release_1) { create(:release, project: project, released_at: Time.zone.parse('2018-10-18')) }
+ let_it_be(:release_2) { create(:release, project: project, released_at: Time.zone.parse('2019-10-19')) }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ shared_examples 'common access controls' do
+ it 'renders a 200' do
+ get(action, params: params)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ context 'when the project is private' do
+ let(:project) { private_project }
+
+ context 'when user is not logged in' do
+ it 'renders a 404' do
+ get(action, params: params)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when user is a developer' do
+ before do
+ sign_in(developer)
+ end
+
+ it 'still renders a 404' do
+ get(action, params: params)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'when activity_pub feature flag is disabled' do
+ before do
+ stub_feature_flags(activity_pub: false)
+ end
+
+ it 'renders a 404' do
+ get(action, params: params)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when activity_pub_project feature flag is disabled' do
+ before do
+ stub_feature_flags(activity_pub_project: false)
+ end
+
+ it 'renders a 404' do
+ get(action, params: params)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ shared_examples_for 'ActivityPub response' do
+ it 'returns an application/activity+json content_type' do
+ expect(response.media_type).to eq 'application/activity+json'
+ end
+
+ it 'is formated as an ActivityStream document' do
+ expect(json_response['@context']).to eq 'https://www.w3.org/ns/activitystreams'
+ end
+ end
+
+ describe 'GET #index' do
+ before do
+ get(action, params: params)
+ end
+
+ let(:action) { :index }
+ let(:params) { { namespace_id: project.namespace, project_id: project } }
+
+ it_behaves_like 'common access controls'
+ it_behaves_like 'ActivityPub response'
+
+ it "returns the project's releases actor profile data" do
+ expect(json_response['id']).to include project_releases_path(project)
+ end
+ end
+
+ describe 'GET #outbox' do
+ before do
+ get(action, params: params)
+ end
+
+ let(:action) { :outbox }
+ let(:params) { { namespace_id: project.namespace, project_id: project, page: page } }
+
+ context 'with no page parameter' do
+ let(:page) { nil }
+
+ it_behaves_like 'common access controls'
+ it_behaves_like 'ActivityPub response'
+
+ it "returns the project's releases collection index" do
+ expect(json_response['id']).to include outbox_project_releases_path(project)
+ expect(json_response['totalItems']).to eq 2
+ end
+ end
+
+ context 'with a page parameter' do
+ let(:page) { 1 }
+
+ it_behaves_like 'common access controls'
+ it_behaves_like 'ActivityPub response'
+
+ it "returns the project's releases list" do
+ expect(json_response['id']).to include outbox_project_releases_path(project, page: 1)
+
+ names = json_response['orderedItems'].map { |release| release['object']['name'] }
+ expect(names).to match_array([release_2.name, release_1.name])
+ end
+ end
+ end
+end
diff --git a/spec/controllers/admin/jobs_controller_spec.rb b/spec/controllers/admin/jobs_controller_spec.rb
index 2d1482f40d4..c99bb6ff695 100644
--- a/spec/controllers/admin/jobs_controller_spec.rb
+++ b/spec/controllers/admin/jobs_controller_spec.rb
@@ -14,8 +14,6 @@ RSpec.describe Admin::JobsController do
get :index
expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:builds)).to be_a(Kaminari::PaginatableWithoutCount)
- expect(assigns(:builds).count).to be(1)
end
end
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index 399b7c02c52..f83b98d7a51 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -416,7 +416,7 @@ RSpec.describe Admin::UsersController do
context 'for an internal user' do
it 'does not deactivate the user' do
- internal_user = User.alert_bot
+ internal_user = Users::Internal.alert_bot
put :deactivate, params: { id: internal_user.username }
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 58125f3a831..b7ee01ce6b3 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -865,33 +865,6 @@ RSpec.describe ApplicationController, feature_category: :shared do
end
end
- describe '#required_signup_info' do
- controller(described_class) do
- def index; end
- end
-
- let(:user) { create(:user) }
-
- context 'user with required role' do
- before do
- user.set_role_required!
- sign_in(user)
- get :index
- end
-
- it { is_expected.to redirect_to users_sign_up_welcome_path }
- end
-
- context 'user without a required role' do
- before do
- sign_in(user)
- get :index
- end
-
- it { is_expected.not_to redirect_to users_sign_up_welcome_path }
- end
- end
-
describe 'rescue_from Gitlab::Auth::IpBlocked' do
controller(described_class) do
skip_before_action :authenticate_user!
diff --git a/spec/controllers/concerns/onboarding/status_spec.rb b/spec/controllers/concerns/onboarding/status_spec.rb
index b14346dc052..fe7c5ac6346 100644
--- a/spec/controllers/concerns/onboarding/status_spec.rb
+++ b/spec/controllers/concerns/onboarding/status_spec.rb
@@ -75,32 +75,4 @@ RSpec.describe Onboarding::Status, feature_category: :onboarding do
it { is_expected.to eq(last_member_source) }
end
end
-
- describe '#invite_with_tasks_to_be_done?' do
- subject { described_class.new(nil, nil, user).invite_with_tasks_to_be_done? }
-
- context 'when there are tasks_to_be_done with one member' do
- let_it_be(:member) { create(:group_member, user: user, tasks_to_be_done: tasks_to_be_done) }
-
- it { is_expected.to eq(true) }
- end
-
- context 'when there are multiple members and the tasks_to_be_done is on only one of them' do
- before do
- create(:group_member, user: user, tasks_to_be_done: tasks_to_be_done)
- end
-
- it { is_expected.to eq(true) }
- end
-
- context 'when there are no tasks_to_be_done' do
- it { is_expected.to eq(false) }
- end
-
- context 'when there are no members' do
- let_it_be(:user) { build_stubbed(:user) }
-
- it { is_expected.to eq(false) }
- end
- end
end
diff --git a/spec/controllers/concerns/preferred_language_switcher_spec.rb b/spec/controllers/concerns/preferred_language_switcher_spec.rb
index 40d6ac10c37..4ceb6fa312e 100644
--- a/spec/controllers/concerns/preferred_language_switcher_spec.rb
+++ b/spec/controllers/concerns/preferred_language_switcher_spec.rb
@@ -13,13 +13,79 @@ RSpec.describe PreferredLanguageSwitcher, type: :controller do
end
end
+ subject { cookies[:preferred_language] }
+
context 'when first visit' do
+ let(:glm_source) { 'about.gitlab.com' }
+ let(:accept_language_header) { nil }
+
before do
- get :new
+ request.env['HTTP_ACCEPT_LANGUAGE'] = accept_language_header
+
+ get :new, params: { glm_source: glm_source }
end
it 'sets preferred_language to default' do
- expect(cookies[:preferred_language]).to eq Gitlab::CurrentSettings.default_preferred_language
+ expect(subject).to eq Gitlab::CurrentSettings.default_preferred_language
+ end
+
+ context 'when language param is valid' do
+ let(:glm_source) { 'about.gitlab.com/fr-fr/' }
+
+ it 'sets preferred_language accordingly' do
+ expect(subject).to eq 'fr'
+ end
+
+ context 'when language param is invalid' do
+ let(:glm_source) { 'about.gitlab.com/ko-ko/' }
+
+ it 'sets preferred_language to default' do
+ expect(subject).to eq Gitlab::CurrentSettings.default_preferred_language
+ end
+ end
+ end
+
+ context 'when browser preferred language is not english' do
+ context 'with selectable language' do
+ let(:accept_language_header) { 'zh-CN,zh;q=0.8,zh-TW;q=0.7' }
+
+ it 'sets preferred_language accordingly' do
+ expect(subject).to eq 'zh_CN'
+ end
+ end
+
+ context 'with unselectable language' do
+ let(:accept_language_header) { 'nl-NL;q=0.8' }
+
+ it 'sets preferred_language to default' do
+ expect(subject).to eq Gitlab::CurrentSettings.default_preferred_language
+ end
+ end
+
+ context 'with empty string in language header' do
+ let(:accept_language_header) { '' }
+
+ it 'sets preferred_language to default' do
+ expect(subject).to eq Gitlab::CurrentSettings.default_preferred_language
+ end
+ end
+
+ context 'with language header without dashes' do
+ let(:accept_language_header) { 'fr;q=8' }
+
+ it 'sets preferred_language accordingly' do
+ expect(subject).to eq 'fr'
+ end
+ end
+ end
+
+ context 'when language params and language header are both valid' do
+ let(:accept_language_header) { 'zh-CN,zh;q=0.8,zh-TW;q=0.7' }
+ let(:glm_source) { 'about.gitlab.com/fr-fr/' }
+
+ it 'sets preferred_language according to language params' do
+ expect(subject).to eq 'fr'
+ end
end
end
@@ -36,7 +102,7 @@ RSpec.describe PreferredLanguageSwitcher, type: :controller do
let(:user_preferred_language) { 'zh_CN' }
it 'keeps preferred language unchanged' do
- expect(cookies[:preferred_language]).to eq user_preferred_language
+ expect(subject).to eq user_preferred_language
end
end
@@ -44,7 +110,7 @@ RSpec.describe PreferredLanguageSwitcher, type: :controller do
let(:user_preferred_language) { 'xxx' }
it 'sets preferred_language to default' do
- expect(cookies[:preferred_language]).to eq Gitlab::CurrentSettings.default_preferred_language
+ expect(subject).to eq Gitlab::CurrentSettings.default_preferred_language
end
end
end
diff --git a/spec/controllers/confirmations_controller_spec.rb b/spec/controllers/confirmations_controller_spec.rb
index fea43894f1c..cbe0ec5d126 100644
--- a/spec/controllers/confirmations_controller_spec.rb
+++ b/spec/controllers/confirmations_controller_spec.rb
@@ -19,17 +19,6 @@ RSpec.describe ConfirmationsController, feature_category: :system_access do
get :show, params: { confirmation_token: confirmation_token }
end
- context 'when signup info is required' do
- before do
- allow(controller).to receive(:current_user) { user }
- user.set_role_required!
- end
-
- it 'does not redirect' do
- expect(perform_request).not_to redirect_to(users_sign_up_welcome_path)
- end
- end
-
context 'user is already confirmed' do
before do
user.confirm
@@ -137,17 +126,6 @@ RSpec.describe ConfirmationsController, feature_category: :system_access do
stub_feature_flags(identity_verification: false)
end
- context 'when signup info is required' do
- before do
- allow(controller).to receive(:current_user) { user }
- user.set_role_required!
- end
-
- it 'does not redirect' do
- expect(perform_request).not_to redirect_to(users_sign_up_welcome_path)
- end
- end
-
context "when `email_confirmation_setting` is set to `soft`" do
before do
stub_application_setting_enum('email_confirmation_setting', 'soft')
diff --git a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
index 3fb5e08f065..6bb791d2fd4 100644
--- a/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
+++ b/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb
@@ -244,7 +244,7 @@ RSpec.describe Groups::DependencyProxyForContainersController, feature_category:
subject
send_data_type, send_data = workhorse_send_data
- header, url = send_data.values_at('Header', 'Url')
+ header, url = send_data.values_at('Headers', 'Url')
expect(send_data_type).to eq('send-dependency')
expect(header).to eq(
@@ -312,7 +312,7 @@ RSpec.describe Groups::DependencyProxyForContainersController, feature_category:
subject
send_data_type, send_data = workhorse_send_data
- header, url = send_data.values_at('Header', 'Url')
+ header, url = send_data.values_at('Headers', 'Url')
expect(send_data_type).to eq('send-dependency')
expect(header).to eq("Authorization" => ["Bearer abcd1234"])
diff --git a/spec/controllers/groups/labels_controller_spec.rb b/spec/controllers/groups/labels_controller_spec.rb
index f9f1fc21538..3dcf41941bb 100644
--- a/spec/controllers/groups/labels_controller_spec.rb
+++ b/spec/controllers/groups/labels_controller_spec.rb
@@ -3,7 +3,8 @@
require 'spec_helper'
RSpec.describe Groups::LabelsController, feature_category: :team_planning do
- let_it_be(:group) { create(:group) }
+ let_it_be(:root_group) { create(:group) }
+ let_it_be(:group) { create(:group, parent: root_group) }
let_it_be(:user) { create(:user) }
let_it_be(:another_user) { create(:user) }
let_it_be(:project) { create(:project, namespace: group) }
@@ -162,5 +163,50 @@ RSpec.describe Groups::LabelsController, feature_category: :team_planning do
let(:group_request) { put :update, params: { group_id: group.to_param, id: label.to_param, label: { title: 'Test' } } }
let(:sub_group_request) { put :update, params: { group_id: sub_group.to_param, id: label.to_param, label: { title: 'Test' } } }
end
+
+ context 'when updating lock_on_merge' do
+ let_it_be(:params) { { lock_on_merge: true } }
+ let_it_be_with_reload(:label) { create(:group_label, group: group) }
+
+ subject(:update_request) { put :update, params: { group_id: group.to_param, id: label.to_param, label: params } }
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: false)
+ end
+
+ it 'does not allow setting lock_on_merge' do
+ update_request
+
+ expect(response).to redirect_to(group_labels_path)
+ expect(label.reload.lock_on_merge).to be_falsey
+ end
+ end
+
+ shared_examples 'allows setting lock_on_merge' do
+ it do
+ update_request
+
+ expect(response).to redirect_to(group_labels_path)
+ expect(label.reload.lock_on_merge).to be_truthy
+ end
+ end
+
+ context 'when feature flag for group is enabled' do
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: group)
+ end
+
+ it_behaves_like 'allows setting lock_on_merge'
+ end
+
+ context 'when feature flag for ancestor group is enabled' do
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: root_group)
+ end
+
+ it_behaves_like 'allows setting lock_on_merge'
+ end
+ end
end
end
diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb
index 37242bce6bf..a4e55a89f41 100644
--- a/spec/controllers/groups/runners_controller_spec.rb
+++ b/spec/controllers/groups/runners_controller_spec.rb
@@ -3,65 +3,88 @@
require 'spec_helper'
RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
- let_it_be(:user) { create(:user) }
- let_it_be(:group) { create(:group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:namespace_settings) { create(:namespace_settings, runner_registration_enabled: true) }
+ let_it_be(:group) { create(:group, namespace_settings: namespace_settings) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:runner) { create(:ci_runner, :group, groups: [group]) }
let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
let!(:instance_runner) { create(:ci_runner, :instance) }
- let(:params_runner_project) { { group_id: group, id: project_runner } }
- let(:params_runner_instance) { { group_id: group, id: instance_runner } }
- let(:params) { { group_id: group, id: runner } }
-
before do
sign_in(user)
end
describe '#index', :snowplow do
- context 'when user is owner' do
- before do
- group.add_owner(user)
- end
+ subject(:execute_get_request) { get :index, params: { group_id: group } }
- it 'renders show with 200 status code' do
- get :index, params: { group_id: group }
+ shared_examples 'can access the page' do
+ it 'renders index with 200 status code' do
+ execute_get_request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
end
it 'tracks the event' do
- get :index, params: { group_id: group }
+ execute_get_request
expect_snowplow_event(category: described_class.name, action: 'index', user: user, namespace: group)
end
+ end
+
+ shared_examples 'cannot access the page' do
+ it 'renders 404' do
+ execute_get_request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
- it 'assigns variables' do
- get :index, params: { group_id: group }
+ it 'does not track the event' do
+ execute_get_request
- expect(assigns(:group_new_runner_path)).to eq(new_group_runner_path(group))
+ expect_no_snowplow_event
end
end
- context 'when user is not owner' do
+ context 'when the user is a maintainer' do
before do
group.add_maintainer(user)
end
- it 'renders a 404' do
- get :index, params: { group_id: group }
+ include_examples 'can access the page'
- expect(response).to have_gitlab_http_status(:not_found)
+ it 'does not expose runner creation and registration variables' do
+ execute_get_request
+
+ expect(assigns(:group_runner_registration_token)).to be_nil
+ expect(assigns(:group_new_runner_path)).to be_nil
end
+ end
- it 'does not track the event' do
- get :index, params: { group_id: group }
+ context 'when the user is an owner' do
+ before do
+ group.add_owner(user)
+ end
- expect_no_snowplow_event
+ include_examples 'can access the page'
+
+ it 'exposes runner creation and registration variables' do
+ execute_get_request
+
+ expect(assigns(:group_runner_registration_token)).not_to be_nil
+ expect(assigns(:group_new_runner_path)).to eq(new_group_runner_path(group))
end
end
+
+ context 'when user is not maintainer' do
+ before do
+ group.add_developer(user)
+ end
+
+ include_examples 'cannot access the page'
+ end
end
describe '#new' do
@@ -139,9 +162,9 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
end
describe '#show' do
- context 'when user is owner' do
+ context 'when user is maintainer' do
before do
- group.add_owner(user)
+ group.add_maintainer(user)
end
it 'renders show with 200 status code' do
@@ -166,9 +189,9 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
end
end
- context 'when user is not owner' do
+ context 'when user is not maintainer' do
before do
- group.add_maintainer(user)
+ group.add_developer(user)
end
it 'renders a 404' do
@@ -197,20 +220,26 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
group.add_owner(user)
end
- it 'renders edit with 200 status code' do
+ it 'renders 200 for group runner' do
get :edit, params: { group_id: group, id: runner }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:edit)
end
- it 'renders a 404 instance runner' do
+ it 'renders 404 for non-existing runner' do
+ get :edit, params: { group_id: group, id: non_existing_record_id }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'renders 404 for instance runner' do
get :edit, params: { group_id: group, id: instance_runner }
expect(response).to have_gitlab_http_status(:not_found)
end
- it 'renders edit with 200 status code project runner' do
+ it 'renders 200 for project runner' do
get :edit, params: { group_id: group, id: project_runner }
expect(response).to have_gitlab_http_status(:ok)
@@ -218,18 +247,49 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
end
end
- context 'when user is not owner' do
+ context 'when user is maintainer' do
before do
group.add_maintainer(user)
end
- it 'renders a 404' do
+ it 'renders 404 for group runner' do
get :edit, params: { group_id: group, id: runner }
expect(response).to have_gitlab_http_status(:not_found)
end
- it 'renders a 404 project runner' do
+ it 'renders 404 for instance runner' do
+ get :edit, params: { group_id: group, id: instance_runner }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'renders 200 for project runner' do
+ get :edit, params: { group_id: group, id: project_runner }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:edit)
+ end
+ end
+
+ context 'when user is not maintainer' do
+ before do
+ group.add_developer(user)
+ end
+
+ it 'renders 404 for group runner' do
+ get :edit, params: { group_id: group, id: runner }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'renders 404 for instance runner' do
+ get :edit, params: { group_id: group, id: instance_runner }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'renders 404 for project runner' do
get :edit, params: { group_id: group, id: project_runner }
expect(response).to have_gitlab_http_status(:not_found)
@@ -238,83 +298,105 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
end
describe '#update' do
- let!(:runner) { create(:ci_runner, :group, groups: [group]) }
-
- context 'when user is an owner' do
- before do
- group.add_owner(user)
- end
+ let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
+ shared_examples 'updates the runner' do
it 'updates the runner, ticks the queue, and redirects' do
new_desc = runner.description.swapcase
expect do
- post :update, params: params.merge(runner: { description: new_desc })
+ post :update, params: { group_id: group, id: runner, runner: { description: new_desc } }
+ runner.reload
end.to change { runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:found)
expect(runner.reload.description).to eq(new_desc)
end
+ end
- it 'does not update the instance runner' do
- new_desc = instance_runner.description.swapcase
+ shared_examples 'rejects the update' do
+ it 'does not update the runner' do
+ new_desc = runner.description.swapcase
expect do
- post :update, params: params_runner_instance.merge(runner: { description: new_desc })
- end.to not_change { instance_runner.ensure_runner_queue_value }
- .and not_change { instance_runner.description }
+ post :update, params: { group_id: group, id: runner, runner: { description: new_desc } }
+ runner.reload
+ end.to not_change { runner.ensure_runner_queue_value }
+ .and not_change { runner.description }
expect(response).to have_gitlab_http_status(:not_found)
end
+ end
+
+ context 'when user is owner' do
+ before do
+ group.add_owner(user)
+ end
- it 'updates the project runner, ticks the queue, and redirects project runner' do
- new_desc = project_runner.description.swapcase
+ context 'with group runner' do
+ let(:runner) { group_runner }
- expect do
- post :update, params: params_runner_project.merge(runner: { description: new_desc })
- end.to change { project_runner.ensure_runner_queue_value }
+ it_behaves_like 'updates the runner'
+ end
- expect(response).to have_gitlab_http_status(:found)
- expect(project_runner.reload.description).to eq(new_desc)
+ context 'with instance runner' do
+ let(:runner) { instance_runner }
+
+ it_behaves_like 'rejects the update'
+ end
+
+ context 'with project runner' do
+ let(:runner) { project_runner }
+
+ it_behaves_like 'updates the runner'
end
end
- context 'when user is not an owner' do
+ context 'when user is maintainer' do
before do
group.add_maintainer(user)
end
- it 'rejects the update and responds 404' do
- old_desc = runner.description
+ context 'with group runner' do
+ let(:runner) { group_runner }
- expect do
- post :update, params: params.merge(runner: { description: old_desc.swapcase })
- end.not_to change { runner.ensure_runner_queue_value }
+ it_behaves_like 'rejects the update'
+ end
- expect(response).to have_gitlab_http_status(:not_found)
- expect(runner.reload.description).to eq(old_desc)
+ context 'with instance runner' do
+ let(:runner) { instance_runner }
+
+ it_behaves_like 'rejects the update'
end
- it 'rejects the update and responds 404 instance runner' do
- old_desc = instance_runner.description
+ context 'with project runner' do
+ let(:runner) { project_runner }
- expect do
- post :update, params: params_runner_instance.merge(runner: { description: old_desc.swapcase })
- end.not_to change { instance_runner.ensure_runner_queue_value }
+ it_behaves_like 'updates the runner'
+ end
+ end
- expect(response).to have_gitlab_http_status(:not_found)
- expect(instance_runner.reload.description).to eq(old_desc)
+ context 'when user is not maintainer' do
+ before do
+ group.add_developer(user)
end
- it 'rejects the update and responds 404 project runner' do
- old_desc = project_runner.description
+ context 'with group runner' do
+ let(:runner) { group_runner }
- expect do
- post :update, params: params_runner_project.merge(runner: { description: old_desc.swapcase })
- end.not_to change { project_runner.ensure_runner_queue_value }
+ it_behaves_like 'rejects the update'
+ end
- expect(response).to have_gitlab_http_status(:not_found)
- expect(project_runner.reload.description).to eq(old_desc)
+ context 'with instance runner' do
+ let(:runner) { instance_runner }
+
+ it_behaves_like 'rejects the update'
+ end
+
+ context 'with project runner' do
+ let(:runner) { project_runner }
+
+ it_behaves_like 'rejects the update'
end
end
end
diff --git a/spec/controllers/groups/uploads_controller_spec.rb b/spec/controllers/groups/uploads_controller_spec.rb
index 7795fff5541..94bb9c9aa02 100644
--- a/spec/controllers/groups/uploads_controller_spec.rb
+++ b/spec/controllers/groups/uploads_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::UploadsController do
+RSpec.describe Groups::UploadsController, feature_category: :portfolio_management do
include WorkhorseHelpers
let(:model) { create(:group, :public) }
diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb
index f3b21e191c4..b3b7753df61 100644
--- a/spec/controllers/invites_controller_spec.rb
+++ b/spec/controllers/invites_controller_spec.rb
@@ -192,26 +192,6 @@ RSpec.describe InvitesController do
expect(session[:invite_email]).to eq(member.invite_email)
end
- context 'with stored location for user' do
- it 'stores the correct path for user' do
- request
-
- expect(controller.stored_location_for(:user)).to eq(activity_project_path(member.source))
- end
-
- context 'with relative root' do
- before do
- stub_default_url_options(script_name: '/gitlab')
- end
-
- it 'stores the correct path for user' do
- request
-
- expect(controller.stored_location_for(:user)).to eq(activity_project_path(member.source))
- end
- end
- end
-
context 'when it is part of our invite email experiment' do
let(:extra_params) { { invite_type: 'initial_email' } }
diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb
index 5b9fd192ad4..44deeb6c47e 100644
--- a/spec/controllers/oauth/applications_controller_spec.rb
+++ b/spec/controllers/oauth/applications_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Oauth::ApplicationsController do
+RSpec.describe Oauth::ApplicationsController, feature_category: :system_access do
let(:user) { create(:user) }
let(:application) { create(:oauth_application, owner: user) }
@@ -86,10 +86,10 @@ RSpec.describe Oauth::ApplicationsController do
it_behaves_like 'redirects to login page when the user is not signed in'
it_behaves_like 'redirects to 2fa setup page when the user requires it'
- it 'returns the secret in json format' do
+ it 'returns the prefixed secret in json format' do
subject
- expect(json_response['secret']).not_to be_nil
+ expect(json_response['secret']).to match(/gloas-\h{64}/)
end
context 'when renew fails' do
@@ -153,6 +153,15 @@ RSpec.describe Oauth::ApplicationsController do
expect(response).to render_template :show
end
+ context 'the secret' do
+ render_views
+
+ it 'is in the response' do
+ subject
+ expect(response.body).to match(/gloas-\h{64}/)
+ end
+ end
+
it 'redirects back to profile page if OAuth applications are disabled' do
disable_user_oauth
diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb
index 4772c3f3487..cfb512afc91 100644
--- a/spec/controllers/oauth/authorizations_controller_spec.rb
+++ b/spec/controllers/oauth/authorizations_controller_spec.rb
@@ -5,9 +5,15 @@ require 'spec_helper'
RSpec.describe Oauth::AuthorizationsController do
let(:user) { create(:user) }
let(:application_scopes) { 'api read_user' }
+ let(:confidential) { true }
let!(:application) do
- create(:oauth_application, scopes: application_scopes, redirect_uri: 'http://example.com')
+ create(
+ :oauth_application,
+ scopes: application_scopes,
+ redirect_uri: 'http://example.com',
+ confidential: confidential
+ )
end
let(:params) do
@@ -68,12 +74,27 @@ RSpec.describe Oauth::AuthorizationsController do
create(:oauth_access_token, application: application, resource_owner_id: user.id, scopes: scopes)
end
- it 'authorizes the request and shows the user a page that redirects' do
- subject
+ context 'when application is confidential' do
+ let(:confidential) { true }
- expect(request.session['user_return_to']).to be_nil
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template('doorkeeper/authorizations/redirect')
+ it 'authorizes the request and shows the user a page that redirects' do
+ subject
+
+ expect(request.session['user_return_to']).to be_nil
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/redirect')
+ end
+ end
+
+ context 'when application is not confidential' do
+ let(:confidential) { false }
+
+ it 'returns 200 code and renders view' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/new')
+ end
end
end
diff --git a/spec/controllers/profiles/notifications_controller_spec.rb b/spec/controllers/profiles/notifications_controller_spec.rb
index 36ec36fb6f1..22c0a62a6a1 100644
--- a/spec/controllers/profiles/notifications_controller_spec.rb
+++ b/spec/controllers/profiles/notifications_controller_spec.rb
@@ -149,11 +149,10 @@ RSpec.describe Profiles::NotificationsController do
it 'updates only permitted attributes' do
sign_in(user)
- put :update, params: { user: { notification_email: 'new@example.com', email_opted_in: true, notified_of_own_activity: true, admin: true } }
+ put :update, params: { user: { notification_email: 'new@example.com', notified_of_own_activity: true, admin: true } }
user.reload
expect(user.notification_email).to eq('new@example.com')
- expect(user.email_opted_in).to eq(true)
expect(user.notified_of_own_activity).to eq(true)
expect(user.admin).to eq(false)
expect(controller).to set_flash[:notice].to('Notification settings saved')
diff --git a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
index 044ce8f397a..14f3f5c23cd 100644
--- a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
+++ b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
@@ -73,14 +73,14 @@ RSpec.describe Profiles::PersonalAccessTokensController do
get :index
end
- it "only includes details of the active personal access token" do
+ it "only includes details of active personal access tokens" do
active_personal_access_tokens_detail =
::PersonalAccessTokenSerializer.new.represent([active_personal_access_token])
expect(assigns(:active_access_tokens).to_json).to eq(active_personal_access_tokens_detail.to_json)
end
- it "sets PAT name and scopes" do
+ it "builds a PAT with name and scopes from params" do
name = 'My PAT'
scopes = 'api,read_user'
@@ -105,5 +105,57 @@ RSpec.describe Profiles::PersonalAccessTokensController do
expect(json_response.count).to eq(1)
end
+
+ it 'sets available scopes' do
+ expect(assigns(:scopes)).to eq(Gitlab::Auth.available_scopes_for(access_token_user))
+ end
+
+ context 'with feature flag k8s_proxy_pat disabled' do
+ before do
+ stub_feature_flags(k8s_proxy_pat: false)
+ # Impersonation and inactive personal tokens are ignored
+ create(:personal_access_token, :impersonation, user: access_token_user)
+ create(:personal_access_token, :revoked, user: access_token_user)
+ get :index
+ end
+
+ it "only includes details of active personal access tokens" do
+ active_personal_access_tokens_detail =
+ ::PersonalAccessTokenSerializer.new.represent([active_personal_access_token])
+
+ expect(assigns(:active_access_tokens).to_json).to eq(active_personal_access_tokens_detail.to_json)
+ end
+
+ it "builds a PAT with name and scopes from params" do
+ name = 'My PAT'
+ scopes = 'api,read_user'
+
+ get :index, params: { name: name, scopes: scopes }
+
+ expect(assigns(:personal_access_token)).to have_attributes(
+ name: eq(name),
+ scopes: contain_exactly(:api, :read_user)
+ )
+ end
+
+ it 'returns 404 when personal access tokens are disabled' do
+ allow(::Gitlab::CurrentSettings).to receive_messages(personal_access_tokens_disabled?: true)
+
+ get :index
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns tokens for json format' do
+ get :index, params: { format: :json }
+
+ expect(json_response.count).to eq(1)
+ end
+
+ it 'sets available scopes' do
+ expect(assigns(:scopes))
+ .to eq(Gitlab::Auth.available_scopes_for(access_token_user) - [Gitlab::Auth::K8S_PROXY_SCOPE])
+ end
+ end
end
end
diff --git a/spec/controllers/profiles/preferences_controller_spec.rb b/spec/controllers/profiles/preferences_controller_spec.rb
index b4ffe0bc844..aaf169cd42b 100644
--- a/spec/controllers/profiles/preferences_controller_spec.rb
+++ b/spec/controllers/profiles/preferences_controller_spec.rb
@@ -54,6 +54,7 @@ RSpec.describe Profiles::PreferencesController do
preferred_language: 'jp',
tab_width: '5',
project_shortcut_buttons: 'true',
+ keyboard_shortcuts_enabled: 'true',
render_whitespace_in_code: 'true'
}.with_indifferent_access
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
index b1c43a33386..2bcb47f97ab 100644
--- a/spec/controllers/profiles_controller_spec.rb
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -193,20 +193,6 @@ RSpec.describe ProfilesController, :request_store do
.to raise_error(ActionController::ParameterMissing)
end
- context 'with legacy storage' do
- it 'moves dependent projects to new namespace' do
- project = create(:project_empty_repo, :legacy_storage, namespace: namespace)
-
- put :update_username,
- params: { user: { username: new_username } }
-
- user.reload
-
- expect(response).to have_gitlab_http_status(:found)
- expect(gitlab_shell.repository_exists?(project.repository_storage, "#{new_username}/#{project.path}.git")).to be_truthy
- end
- end
-
context 'with hashed storage' do
it 'keeps repository location unchanged on disk' do
project = create(:project_empty_repo, namespace: namespace)
diff --git a/spec/controllers/projects/alerting/notifications_controller_spec.rb b/spec/controllers/projects/alerting/notifications_controller_spec.rb
index 5ce2950f95f..6a8c57e4abd 100644
--- a/spec/controllers/projects/alerting/notifications_controller_spec.rb
+++ b/spec/controllers/projects/alerting/notifications_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::Alerting::NotificationsController do
+RSpec.describe Projects::Alerting::NotificationsController, feature_category: :incident_management do
include HttpBasicAuthHelpers
let_it_be(:project) { create(:project) }
@@ -68,6 +68,31 @@ RSpec.describe Projects::Alerting::NotificationsController do
make_request
end
+ context 'with a corresponding project_alerting_setting' do
+ let_it_be_with_reload(:setting) { create(:project_alerting_setting, :with_http_integration, project: project) }
+ let_it_be_with_reload(:integration) { project.alert_management_http_integrations.last! }
+
+ context 'and a migrated or synced HTTP integration' do
+ it 'extracts and finds the integration' do
+ expect(notify_service).to receive(:execute).with('some token', integration)
+
+ make_request
+ end
+ end
+
+ context 'and no migrated or synced HTTP integration' do
+ before do
+ integration.destroy!
+ end
+
+ it 'does not find an integration' do
+ expect(notify_service).to receive(:execute).with('some token', nil)
+
+ make_request
+ end
+ end
+ end
+
context 'with a corresponding integration' do
context 'with integration parameters specified' do
let_it_be_with_reload(:integration) { create(:alert_management_http_integration, project: project) }
diff --git a/spec/controllers/projects/environments/sample_metrics_controller_spec.rb b/spec/controllers/projects/environments/sample_metrics_controller_spec.rb
deleted file mode 100644
index b266c569edd..00000000000
--- a/spec/controllers/projects/environments/sample_metrics_controller_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::Environments::SampleMetricsController do
- include StubENV
-
- let_it_be(:project) { create(:project) }
- let_it_be(:environment) { create(:environment, project: project) }
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_reporter(user)
- sign_in(user)
- end
-
- describe 'GET #query' do
- context 'when the file is not found' do
- before do
- get :query, params: environment_params
- end
-
- it 'returns a 404' do
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when the sample data is found' do
- before do
- allow_next_instance_of(Metrics::SampleMetricsService) do |service|
- allow(service).to receive(:query).and_return([])
- end
- get :query, params: environment_params
- end
-
- it 'returns JSON with a message and a 200 status code' do
- expect(json_response.keys).to contain_exactly('status', 'data')
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
- end
-
- private
-
- def environment_params(params = {})
- {
- id: environment.id.to_s,
- namespace_id: project.namespace.full_path,
- project_id: project.path,
- identifier: 'sample_metric_query_result',
- start: '2019-12-02T23:31:45.000Z',
- end: '2019-12-03T00:01:45.000Z'
- }.merge(params)
- end
-end
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index 4b091e9221e..c421aee88f8 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -398,7 +398,7 @@ RSpec.describe Projects::EnvironmentsController, feature_category: :continuous_d
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq(
{ 'redirect_url' =>
- project_pipeline_url(project, action.pipeline_id) })
+ project_job_url(project, action) })
end
it 'returns environment url for multiple stop actions' do
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 7b576533ae5..d4f04105605 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -120,11 +120,11 @@ RSpec.describe Projects::IssuesController, :request_store, feature_category: :te
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
end
- it 'redirects to last page when out of bounds on non-html requests' do
+ it 'does not redirect when out of bounds on non-html requests' do
get :index, params: params.merge(page: last_page + 1), format: 'atom'
- expect(response).to have_gitlab_http_status(:redirect)
- expect(response).to redirect_to(action: 'index', format: 'atom', page: last_page, state: 'opened')
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(assigns(:issues).size).to eq(0)
end
end
@@ -1725,7 +1725,7 @@ RSpec.describe Projects::IssuesController, :request_store, feature_category: :te
describe 'GET service_desk' do
let_it_be(:project) { create(:project_empty_repo, :public) }
- let_it_be(:support_bot) { User.support_bot }
+ let_it_be(:support_bot) { Users::Internal.support_bot }
let_it_be(:other_user) { create(:user) }
let_it_be(:service_desk_issue_1) { create(:issue, project: project, author: support_bot) }
let_it_be(:service_desk_issue_2) { create(:issue, project: project, author: support_bot, assignees: [other_user]) }
@@ -1756,7 +1756,7 @@ RSpec.describe Projects::IssuesController, :request_store, feature_category: :te
it 'allows an assignee to be specified by id' do
get_service_desk(assignee_id: other_user.id)
- expect(assigns(:users)).to contain_exactly(other_user, support_bot)
+ expect(assigns(:issues)).to contain_exactly(service_desk_issue_2)
end
end
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index ede26ebd032..9851153bd39 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -47,7 +47,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
it 'has only pending builds' do
expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:builds).first.status).to eq('pending')
end
end
@@ -60,7 +59,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
it 'has only running jobs' do
expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:builds).first.status).to eq('running')
end
end
@@ -73,7 +71,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
it 'has only finished jobs' do
expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:builds).first.status).to eq('success')
end
end
@@ -89,7 +86,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
it 'redirects to the page' do
expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:builds).current_page).to eq(last_page)
end
end
end
@@ -156,6 +152,18 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state, featu
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ context 'when the job is a bridge' do
+ let!(:downstream_pipeline) { create(:ci_pipeline, child_of: pipeline) }
+ let(:job) { downstream_pipeline.source_job }
+
+ it 'redirects to the downstream pipeline page' do
+ get_show(id: job.id)
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(namespace_project_pipeline_path(id: downstream_pipeline.id))
+ end
+ end
end
context 'when requesting JSON' do
diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb
index 74c16621fc5..db8cac8bb4a 100644
--- a/spec/controllers/projects/labels_controller_spec.rb
+++ b/spec/controllers/projects/labels_controller_spec.rb
@@ -297,6 +297,53 @@ RSpec.describe Projects::LabelsController, feature_category: :team_planning do
end
end
+ describe 'PUT #update' do
+ context 'when updating lock_on_merge' do
+ let_it_be(:params) { { lock_on_merge: true } }
+ let_it_be_with_reload(:label) { create(:label, project: project) }
+
+ subject(:update_request) { put :update, params: { namespace_id: project.namespace, project_id: project, id: label.to_param, label: params } }
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: false)
+ end
+
+ it 'does not allow setting lock_on_merge' do
+ update_request
+
+ expect(response).to redirect_to(namespace_project_labels_path)
+ expect(label.reload.lock_on_merge).to be_falsey
+ end
+ end
+
+ shared_examples 'allows setting lock_on_merge' do
+ it do
+ update_request
+
+ expect(response).to redirect_to(namespace_project_labels_path)
+ expect(label.reload.lock_on_merge).to be_truthy
+ end
+ end
+
+ context 'when feature flag is enabled' do
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: project)
+ end
+
+ it_behaves_like 'allows setting lock_on_merge'
+ end
+
+ context 'when feature flag for ancestor group is enabled' do
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: group)
+ end
+
+ it_behaves_like 'allows setting lock_on_merge'
+ end
+ end
+ end
+
describe 'DELETE #destroy' do
context 'when current user has ability to destroy the label' do
before do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 0e3e3f31783..a47bb98770c 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -68,72 +68,6 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :code_review
end
end
- context 'when add_prepared_state_to_mr feature flag on' do
- before do
- stub_feature_flags(add_prepared_state_to_mr: true)
- end
-
- context 'when the merge request is not prepared' do
- before do
- merge_request.update!(prepared_at: nil, created_at: 10.minutes.ago)
- end
-
- it 'prepares the merge request' do
- expect(NewMergeRequestWorker).to receive(:perform_async)
-
- go
- end
-
- context 'when the merge request was created less than 5 minutes ago' do
- it 'does not prepare the merge request again' do
- travel_to(4.minutes.from_now) do
- merge_request.update!(created_at: Time.current - 4.minutes)
-
- expect(NewMergeRequestWorker).not_to receive(:perform_async)
-
- go
- end
- end
- end
-
- context 'when the merge request was created 5 minutes ago' do
- it 'prepares the merge request' do
- travel_to(6.minutes.from_now) do
- merge_request.update!(created_at: Time.current - 6.minutes)
-
- expect(NewMergeRequestWorker).to receive(:perform_async)
-
- go
- end
- end
- end
- end
-
- context 'when the merge request is prepared' do
- before do
- merge_request.update!(prepared_at: Time.current, created_at: 10.minutes.ago)
- end
-
- it 'prepares the merge request' do
- expect(NewMergeRequestWorker).not_to receive(:perform_async)
-
- go
- end
- end
- end
-
- context 'when add_prepared_state_to_mr feature flag is off' do
- before do
- stub_feature_flags(add_prepared_state_to_mr: false)
- end
-
- it 'does not prepare the merge request again' do
- expect(NewMergeRequestWorker).not_to receive(:perform_async)
-
- go
- end
- end
-
describe 'as html' do
it 'sets the endpoint_metadata_url' do
go
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 500fab471ef..35aa01cdfad 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
request.headers['X-Last-Fetched-At'] = microseconds(last_fetched_at)
end
- specify { expect(get(:index, params: request_params)).to have_request_urgency(:medium) }
+ specify { expect(get(:index, params: request_params)).to have_request_urgency(:low) }
it 'sets the correct feature category' do
get :index, params: request_params
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index a5542a2b825..43e7bafc206 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -769,6 +769,33 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
[
{
+ chart_param: 'time-to-restore-service',
+ event: 'p_analytics_ci_cd_time_to_restore_service'
+ },
+ {
+ chart_param: 'change-failure-rate',
+ event: 'p_analytics_ci_cd_change_failure_rate'
+ }
+ ].each do |tab|
+ it_behaves_like 'tracking unique visits', :charts do
+ let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } }
+ let(:target_id) { ['p_analytics_pipelines', tab[:event]] }
+ end
+
+ it_behaves_like 'Snowplow event tracking with RedisHLL context' do
+ subject { get :charts, params: request_params, format: :html }
+
+ let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } }
+ let(:category) { described_class.name }
+ let(:action) { 'perform_analytics_usage_action' }
+ let(:namespace) { project.namespace }
+ let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' }
+ let(:property) { 'p_analytics_pipelines' }
+ end
+ end
+
+ [
+ {
chart_param: '',
event: 'p_analytics_ci_cd_pipelines'
},
@@ -783,14 +810,6 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
{
chart_param: 'lead-time',
event: 'p_analytics_ci_cd_lead_time'
- },
- {
- chart_param: 'time-to-restore-service',
- event: 'p_analytics_ci_cd_time_to_restore_service'
- },
- {
- chart_param: 'change-failure-rate',
- event: 'p_analytics_ci_cd_change_failure_rate'
}
].each do |tab|
it_behaves_like 'tracking unique visits', :charts do
@@ -798,15 +817,12 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
let(:target_id) { ['p_analytics_pipelines', tab[:event]] }
end
- it_behaves_like 'Snowplow event tracking with RedisHLL context' do
+ it_behaves_like 'internal event tracking' do
subject { get :charts, params: request_params, format: :html }
let(:request_params) { { namespace_id: project.namespace, project_id: project, id: pipeline.id, chart: tab[:chart_param] } }
- let(:category) { described_class.name }
- let(:action) { 'perform_analytics_usage_action' }
+ let(:action) { tab[:event] }
let(:namespace) { project.namespace }
- let(:label) { 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly' }
- let(:property) { 'p_analytics_pipelines' }
end
end
end
diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb
deleted file mode 100644
index 3e64631fbf1..00000000000
--- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::Prometheus::AlertsController, feature_category: :incident_management do
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
- let_it_be(:environment) { create(:environment, project: project) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
-
- shared_examples 'unprivileged' do
- before do
- project.add_developer(user)
- end
-
- it 'returns not_found' do
- make_request
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- shared_examples 'project non-specific environment' do |status|
- let(:other) { create(:environment) }
-
- it "returns #{status}" do
- make_request(environment_id: other)
-
- expect(response).to have_gitlab_http_status(status)
- end
-
- if status == :ok
- it 'returns no prometheus alerts' do
- make_request(environment_id: other)
-
- expect(json_response).to be_empty
- end
- end
- end
-
- describe 'POST #notify' do
- let(:alert_1) { build(:alert_management_alert, :prometheus, project: project) }
- let(:alert_2) { build(:alert_management_alert, :prometheus, project: project) }
- let(:service_response) { ServiceResponse.success(http_status: :created) }
- let(:notify_service) { instance_double(Projects::Prometheus::Alerts::NotifyService, execute: service_response) }
-
- before do
- sign_out(user)
-
- expect(Projects::Prometheus::Alerts::NotifyService)
- .to receive(:new)
- .with(project, duck_type(:permitted?))
- .and_return(notify_service)
- end
-
- it 'returns created if notification succeeds' do
- expect(notify_service).to receive(:execute).and_return(service_response)
-
- post :notify, params: project_params, session: { as: :json }
-
- expect(response).to have_gitlab_http_status(:created)
- end
-
- it 'returns unprocessable entity if notification fails' do
- expect(notify_service).to receive(:execute).and_return(
- ServiceResponse.error(message: 'Unprocessable Entity', http_status: :unprocessable_entity)
- )
-
- post :notify, params: project_params, session: { as: :json }
-
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
- end
-
- context 'bearer token' do
- context 'when set' do
- it 'extracts bearer token' do
- request.headers['HTTP_AUTHORIZATION'] = 'Bearer some token'
-
- expect(notify_service).to receive(:execute).with('some token')
-
- post :notify, params: project_params, as: :json
- end
-
- it 'pass nil if cannot extract a non-bearer token' do
- request.headers['HTTP_AUTHORIZATION'] = 'some token'
-
- expect(notify_service).to receive(:execute).with(nil)
-
- post :notify, params: project_params, as: :json
- end
- end
-
- context 'when missing' do
- it 'passes nil' do
- expect(notify_service).to receive(:execute).with(nil)
-
- post :notify, params: project_params, as: :json
- end
- end
- end
- end
-
- def project_params(opts = {})
- opts.reverse_merge(namespace_id: project.namespace, project_id: project)
- end
-end
diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb
index 01635f2e158..9f20856fa68 100644
--- a/spec/controllers/projects/uploads_controller_spec.rb
+++ b/spec/controllers/projects/uploads_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::UploadsController do
+RSpec.describe Projects::UploadsController, feature_category: :team_planning do
include WorkhorseHelpers
let(:model) { create(:project, :public) }
diff --git a/spec/controllers/registrations/welcome_controller_spec.rb b/spec/controllers/registrations/welcome_controller_spec.rb
index 5a3feefc1ba..0bac52c8dca 100644
--- a/spec/controllers/registrations/welcome_controller_spec.rb
+++ b/spec/controllers/registrations/welcome_controller_spec.rb
@@ -12,21 +12,12 @@ RSpec.describe Registrations::WelcomeController, feature_category: :system_acces
it { is_expected.to redirect_to new_user_registration_path }
end
- context 'when role or setup_for_company is not set' do
+ context 'when setup_for_company is not set' do
before do
sign_in(user)
end
it { is_expected.to render_template(:show) }
- end
-
- context 'when role is required and setup_for_company is not set' do
- before do
- user.set_role_required!
- sign_in(user)
- end
-
- it { is_expected.to render_template(:show) }
render_views
@@ -37,7 +28,7 @@ RSpec.describe Registrations::WelcomeController, feature_category: :system_acces
end
end
- context 'when role and setup_for_company is set' do
+ context 'when setup_for_company is set' do
before do
user.update!(setup_for_company: false)
sign_in(user)
@@ -46,15 +37,6 @@ RSpec.describe Registrations::WelcomeController, feature_category: :system_acces
it { is_expected.to redirect_to(dashboard_projects_path) }
end
- context 'when role is set and setup_for_company is not set' do
- before do
- user.update!(role: :software_developer)
- sign_in(user)
- end
-
- it { is_expected.to render_template(:show) }
- end
-
context 'when 2FA is required from group' do
before do
user = create(:user, require_two_factor_authentication_from_group: true)
@@ -131,12 +113,6 @@ RSpec.describe Registrations::WelcomeController, feature_category: :system_acces
expect(subject).to redirect_to(dashboard_projects_path)
end
end
-
- context 'when tasks to be done are assigned' do
- let!(:member1) { create(:group_member, user: user, tasks_to_be_done: %w[ci code]) }
-
- it { is_expected.to redirect_to(issues_dashboard_path(assignee_username: user.username)) }
- end
end
end
end
diff --git a/spec/controllers/repositories/git_http_controller_spec.rb b/spec/controllers/repositories/git_http_controller_spec.rb
index 88af7d1fe45..602c9c0a2ce 100644
--- a/spec/controllers/repositories/git_http_controller_spec.rb
+++ b/spec/controllers/repositories/git_http_controller_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Repositories::GitHttpController, feature_category: :source_code_management do
- let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:project) { create(:project_with_design, :public, :repository) }
let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository) }
let_it_be(:project_snippet) { create(:project_snippet, :public, :repository, project: project) }
@@ -177,4 +177,27 @@ RSpec.describe Repositories::GitHttpController, feature_category: :source_code_m
it_behaves_like 'handles logging git receive pack operation'
end
end
+
+ context 'when repository container is a design_management_repository' do
+ let(:container) { project.design_management_repository }
+ let(:access_checker_class) { Gitlab::GitAccessDesign }
+ let(:repository_path) { "#{container.full_path}.git" }
+ let(:params) { { repository_path: repository_path, service: 'git-upload-pack' } }
+
+ describe 'GET #info_refs' do
+ it 'calls the right access checker class with the right object' do
+ allow(controller).to receive(:verify_workhorse_api!).and_return(true)
+
+ access_double = double
+
+ expect(access_checker_class).to receive(:new)
+ .with(nil, container, 'http', hash_including({ repository_path: repository_path }))
+ .and_return(access_double)
+
+ allow(access_double).to receive(:check).and_return(false)
+
+ get :info_refs, params: params
+ end
+ end
+ end
end
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 57ae1d5a1db..9771141a955 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -41,21 +41,25 @@ RSpec.describe SearchController, feature_category: :global_search do
describe 'rate limit scope' do
it 'uses current_user and search scope' do
%w[projects blobs users issues merge_requests].each do |scope|
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user, scope])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user, scope], users_allowlist: [])
get :show, params: { search: 'hello', scope: scope }
end
end
it 'uses just current_user when no search scope is used' do
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user], users_allowlist: [])
get :show, params: { search: 'hello' }
end
it 'uses just current_user when search scope is abusive' do
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user], users_allowlist: [])
get(:show, params: { search: 'hello', scope: 'hack-the-mainframe' })
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user], users_allowlist: [])
get :show, params: { search: 'hello', scope: 'blobs' * 1000 }
end
end
@@ -298,6 +302,14 @@ RSpec.describe SearchController, feature_category: :global_search do
end
end
+ it_behaves_like 'search request exceeding rate limit', :clean_gitlab_redis_cache do
+ let(:current_user) { user }
+
+ def request
+ get(:show, params: { search: 'foo@bar.com', scope: 'users' })
+ end
+ end
+
it 'increments the custom search sli apdex' do
expect(Gitlab::Metrics::GlobalSearchSlis).to receive(:record_apdex).with(
elapsed: a_kind_of(Numeric),
@@ -370,16 +382,19 @@ RSpec.describe SearchController, feature_category: :global_search do
describe 'rate limit scope' do
it 'uses current_user and search scope' do
%w[projects blobs users issues merge_requests].each do |scope|
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user, scope])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user, scope], users_allowlist: [])
get :count, params: { search: 'hello', scope: scope }
end
end
it 'uses just current_user when search scope is abusive' do
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user], users_allowlist: [])
get :count, params: { search: 'hello', scope: 'hack-the-mainframe' }
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user], users_allowlist: [])
get :count, params: { search: 'hello', scope: 'blobs' * 1000 }
end
end
@@ -432,6 +447,14 @@ RSpec.describe SearchController, feature_category: :global_search do
get(:count, params: { search: 'foo@bar.com', scope: 'users' })
end
end
+
+ it_behaves_like 'search request exceeding rate limit', :clean_gitlab_redis_cache do
+ let(:current_user) { user }
+
+ def request
+ get(:count, params: { search: 'foo@bar.com', scope: 'users' })
+ end
+ end
end
describe 'GET #autocomplete' do
@@ -454,16 +477,19 @@ RSpec.describe SearchController, feature_category: :global_search do
describe 'rate limit scope' do
it 'uses current_user and search scope' do
%w[projects blobs users issues merge_requests].each do |scope|
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user, scope])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user, scope], users_allowlist: [])
get :autocomplete, params: { term: 'hello', scope: scope }
end
end
it 'uses just current_user when search scope is abusive' do
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user], users_allowlist: [])
get :autocomplete, params: { term: 'hello', scope: 'hack-the-mainframe' }
- expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit, scope: [user])
+ expect(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).with(:search_rate_limit,
+ scope: [user], users_allowlist: [])
get :autocomplete, params: { term: 'hello', scope: 'blobs' * 1000 }
end
end
@@ -476,6 +502,14 @@ RSpec.describe SearchController, feature_category: :global_search do
end
end
+ it_behaves_like 'search request exceeding rate limit', :clean_gitlab_redis_cache do
+ let(:current_user) { user }
+
+ def request
+ get(:autocomplete, params: { term: 'foo@bar.com', scope: 'users' })
+ end
+ end
+
it 'can be filtered with params[:filter]' do
get :autocomplete, params: { term: 'setting', filter: 'generic' }
expect(response).to have_gitlab_http_status(:ok)
diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb
index e60cf37aad6..190c00092b6 100644
--- a/spec/controllers/sent_notifications_controller_spec.rb
+++ b/spec/controllers/sent_notifications_controller_spec.rb
@@ -299,7 +299,7 @@ RSpec.describe SentNotificationsController do
end
context 'when support bot is the notification recipient' do
- let(:sent_notification) { create(:sent_notification, project: target_project, noteable: noteable, recipient: User.support_bot) }
+ let(:sent_notification) { create(:sent_notification, project: target_project, noteable: noteable, recipient: Users::Internal.support_bot) }
it 'deletes the external author on the issue' do
expect { unsubscribe }.to change { issue.issue_email_participants.count }.by(-1)
diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
index 8015136d1e0..8ae78c5ee35 100644
--- a/spec/controllers/uploads_controller_spec.rb
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -19,7 +19,7 @@ RSpec.shared_examples 'content publicly cached' do
end
end
-RSpec.describe UploadsController do
+RSpec.describe UploadsController, feature_category: :groups_and_projects do
include WorkhorseHelpers
let!(:user) { create(:user, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
diff --git a/spec/db/avoid_migration_name_collisions_spec.rb b/spec/db/avoid_migration_name_collisions_spec.rb
new file mode 100644
index 00000000000..f5fa3da0c81
--- /dev/null
+++ b/spec/db/avoid_migration_name_collisions_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Avoid Migration Name Collisions', feature_category: :database do
+ subject(:duplicated_migration_class_names) do
+ class_names = migration_files.map { |path| class_name_regex.match(File.read(path))[1] }
+ class_names.select { |class_name| class_names.count(class_name) > 1 }
+ end
+
+ let(:class_name_regex) { /^\s*class\s+:*([A-Z][A-Za-z0-9_]+\S+)/ }
+ let(:migration_files) { Dir['db/migrate/*.rb', 'db/post_migrate/*.rb', 'ee/elastic/migrate/*.rb'] }
+
+ it 'loads all database and search migrations without name collisions' do
+ expect(duplicated_migration_class_names).to be_empty
+ end
+end
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 3c99393b14b..cfd6bbf3094 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe 'Database schema', feature_category: :database do
aws_roles: %w[role_external_id],
boards: %w[milestone_id iteration_id],
broadcast_messages: %w[namespace_id],
- chat_names: %w[chat_id team_id user_id integration_id],
+ chat_names: %w[chat_id team_id user_id],
chat_teams: %w[team_id],
ci_builds: %w[project_id runner_id user_id erased_by_id trigger_request_id partition_id],
ci_namespace_monthly_usages: %w[namespace_id],
@@ -187,6 +187,44 @@ RSpec.describe 'Database schema', feature_category: :database do
expect(ignored_columns).to match_array(ignored_columns - foreign_keys)
end
end
+
+ context 'btree indexes' do
+ it 'only has existing indexes in the ignored duplicate indexes duplicate_indexes.yml' do
+ table_ignored_indexes = (ignored_indexes[table] || {}).to_a.flatten.uniq
+ indexes_by_name = indexes.map(&:name)
+ expect(indexes_by_name).to include(*table_ignored_indexes)
+ end
+
+ it 'does not have any duplicated indexes' do
+ duplicate_indexes = Database::DuplicateIndexes.new(table, indexes).duplicate_indexes
+ expect(duplicate_indexes).to be_an_instance_of Hash
+
+ table_ignored_indexes = ignored_indexes[table] || {}
+
+ # We ignore all the indexes that are explicitly ignored in duplicate_indexes.yml
+ duplicate_indexes.each do |index, matching_indexes|
+ duplicate_indexes[index] = matching_indexes.reject do |matching_index|
+ table_ignored_indexes.fetch(index.name, []).include?(matching_index.name) ||
+ table_ignored_indexes.fetch(matching_index.name, []).include?(index.name)
+ end
+
+ duplicate_indexes.delete(index) if duplicate_indexes[index].empty?
+ end
+
+ if duplicate_indexes.present?
+ btree_index = duplicate_indexes.each_key.first
+ matching_indexes = duplicate_indexes[btree_index]
+
+ error_message = <<~ERROR
+ Duplicate index: #{btree_index.name} with #{matching_indexes.map(&:name)}
+ #{btree_index.name} : #{btree_index.columns.inspect}
+ #{matching_indexes.first.name} : #{matching_indexes.first.columns.inspect}.
+ Consider dropping the indexes #{matching_indexes.map(&:name).join(', ')}
+ ERROR
+ raise error_message
+ end
+ end
+ end
end
end
end
@@ -196,23 +234,18 @@ RSpec.describe 'Database schema', feature_category: :database do
IGNORED_LIMIT_ENUMS = {
'Analytics::CycleAnalytics::Stage' => %w[start_event_identifier end_event_identifier],
'Ci::Bridge' => %w[failure_reason],
- 'Ci::Bridge::Partitioned' => %w[failure_reason],
'Ci::Build' => %w[failure_reason],
- 'Ci::Build::Partitioned' => %w[failure_reason],
'Ci::BuildMetadata' => %w[timeout_source],
'Ci::BuildTraceChunk' => %w[data_store],
'Ci::DailyReportResult' => %w[param_type],
'Ci::JobArtifact' => %w[file_type],
'Ci::Pipeline' => %w[source config_source failure_reason],
'Ci::Processable' => %w[failure_reason],
- 'Ci::Processable::Partitioned' => %w[failure_reason],
'Ci::Runner' => %w[access_level],
'Ci::Stage' => %w[status],
'Clusters::Cluster' => %w[platform_type provider_type],
'CommitStatus' => %w[failure_reason],
- 'CommitStatus::Partitioned' => %w[failure_reason],
'GenericCommitStatus' => %w[failure_reason],
- 'GenericCommitStatus::Partitioned' => %w[failure_reason],
'InternalId' => %w[usage],
'List' => %w[list_type],
'NotificationSetting' => %w[level],
@@ -244,7 +277,6 @@ RSpec.describe 'Database schema', feature_category: :database do
"ApplicationSetting" => %w[repository_storages_weighted],
"AlertManagement::Alert" => %w[payload],
"Ci::BuildMetadata" => %w[config_options config_variables],
- "Ci::BuildMetadata::Partitioned" => %w[config_options config_variables id_tokens runtime_runner_features secrets],
"ExperimentSubject" => %w[context],
"ExperimentUser" => %w[context],
"Geo::Event" => %w[payload],
@@ -409,4 +441,9 @@ RSpec.describe 'Database schema', feature_category: :database do
def ignored_jsonb_columns(model)
IGNORED_JSONB_COLUMNS.fetch(model, [])
end
+
+ def ignored_indexes
+ duplicate_indexes_file_path = "spec/support/helpers/database/duplicate_indexes.yml"
+ @ignored_indexes ||= YAML.load_file(Rails.root.join(duplicate_indexes_file_path)) || {}
+ end
end
diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb
index 461a6390a33..8a65c219f5d 100644
--- a/spec/experiments/application_experiment_spec.rb
+++ b/spec/experiments/application_experiment_spec.rb
@@ -211,7 +211,7 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :experiment
application_experiment.variant(:variant1) {}
application_experiment.variant(:variant2) {}
- expect(application_experiment.assigned.name).to eq('variant2')
+ expect(application_experiment.assigned.name).to eq(:variant2)
end
end
@@ -248,7 +248,7 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :experiment
end
it "caches the variant determined by the variant resolver" do
- expect(application_experiment.assigned.name).to eq('candidate') # we should be in the experiment
+ expect(application_experiment.assigned.name).to eq(:candidate) # we should be in the experiment
application_experiment.run
@@ -263,7 +263,7 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :experiment
# the control.
stub_feature_flags(namespaced_stub: false) # simulate being not rolled out
- expect(application_experiment.assigned.name).to eq('control') # if we ask, it should be control
+ expect(application_experiment.assigned.name).to eq(:control) # if we ask, it should be control
application_experiment.run
@@ -299,29 +299,4 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :experiment
end
end
end
-
- context "with deprecation warnings" do
- before do
- Gitlab::Experiment::Configuration.instance_variable_set(:@__dep_versions, nil) # clear the internal memoization
-
- allow(ActiveSupport::Deprecation).to receive(:new).and_call_original
- end
-
- it "doesn't warn on non dev/test environments" do
- allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
-
- expect { experiment(:example) { |e| e.use {} } }.not_to raise_error
- expect(ActiveSupport::Deprecation).not_to have_received(:new).with(anything, 'Gitlab::Experiment')
- end
-
- it "warns on dev and test environments" do
- allow(Gitlab).to receive(:dev_or_test_env?).and_return(true)
-
- # This will eventually raise an ActiveSupport::Deprecation exception,
- # it's ok to change it when that happens.
- expect { experiment(:example) { |e| e.use {} } }.not_to raise_error
-
- expect(ActiveSupport::Deprecation).to have_received(:new).with(anything, 'Gitlab::Experiment')
- end
- end
end
diff --git a/spec/factories/ci/catalog/resources.rb b/spec/factories/ci/catalog/resources.rb
index 66c2e58cdd9..c663164d449 100644
--- a/spec/factories/ci/catalog/resources.rb
+++ b/spec/factories/ci/catalog/resources.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
FactoryBot.define do
- factory :catalog_resource, class: 'Ci::Catalog::Resource' do
+ factory :ci_catalog_resource, class: 'Ci::Catalog::Resource' do
project factory: :project
end
end
diff --git a/spec/factories/ci/catalog/resources/components.rb b/spec/factories/ci/catalog/resources/components.rb
index 3eeb2f4251a..8feecc695bc 100644
--- a/spec/factories/ci/catalog/resources/components.rb
+++ b/spec/factories/ci/catalog/resources/components.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
FactoryBot.define do
- factory :catalog_resource_component, class: 'Ci::Catalog::Resources::Component' do
- version factory: :catalog_resource_version
+ factory :ci_catalog_resource_component, class: 'Ci::Catalog::Resources::Component' do
+ version factory: :ci_catalog_resource_version
catalog_resource { version.catalog_resource }
project { version.project }
name { catalog_resource.name }
diff --git a/spec/factories/ci/catalog/resources/versions.rb b/spec/factories/ci/catalog/resources/versions.rb
index d5057969273..520708d9d58 100644
--- a/spec/factories/ci/catalog/resources/versions.rb
+++ b/spec/factories/ci/catalog/resources/versions.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
FactoryBot.define do
- factory :catalog_resource_version, class: 'Ci::Catalog::Resources::Version' do
- catalog_resource
+ factory :ci_catalog_resource_version, class: 'Ci::Catalog::Resources::Version' do
+ catalog_resource factory: :ci_catalog_resource
project { catalog_resource.project }
release { association :release, project: project }
end
diff --git a/spec/factories/ci/reports/sbom/metadatum.rb b/spec/factories/ci/reports/sbom/metadatum.rb
new file mode 100644
index 00000000000..f05ace8754f
--- /dev/null
+++ b/spec/factories/ci/reports/sbom/metadatum.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :ci_reports_sbom_metadata, class: '::Gitlab::Ci::Reports::Sbom::Metadata' do
+ transient do
+ vendor { generate(:name) }
+ author_name { generate(:name) }
+ end
+
+ tools do
+ [
+ {
+ vendor: vendor,
+ name: "Gemnasium",
+ version: "2.34.0"
+ }
+ ]
+ end
+ authors do
+ [
+ {
+ name: author_name,
+ email: "support@gitlab.com"
+ }
+ ]
+ end
+ properties do
+ [
+ {
+ name: "gitlab:dependency_scanning:input_file:path",
+ value: "package-lock.json"
+ },
+ {
+ name: "gitlab:dependency_scanning:package_manager:name",
+ value: "npm"
+ }
+ ]
+ end
+
+ skip_create
+
+ initialize_with { new(tools: tools, authors: authors, properties: properties) }
+ end
+end
diff --git a/spec/factories/ci/reports/sbom/reports.rb b/spec/factories/ci/reports/sbom/reports.rb
index 7a076282915..3698b0f17eb 100644
--- a/spec/factories/ci/reports/sbom/reports.rb
+++ b/spec/factories/ci/reports/sbom/reports.rb
@@ -3,6 +3,14 @@
FactoryBot.define do
factory :ci_reports_sbom_report, class: '::Gitlab::Ci::Reports::Sbom::Report' do
transient do
+ sbom_attributes do
+ {
+ bom_format: 'CycloneDX',
+ spec_version: '1.4',
+ serial_number: "urn:uuid:aec33827-20ae-40d0-ae83-18ee846364d2",
+ version: 1
+ }
+ end
num_components { 5 }
components { build_list :ci_reports_sbom_component, num_components }
source { association :ci_reports_sbom_source }
@@ -14,8 +22,18 @@ FactoryBot.define do
end
end
+ trait(:with_metadata) do
+ transient do
+ metadata { association(:ci_reports_sbom_metadata) }
+ end
+
+ after(:build) do |report, options|
+ report.metadata = options.metadata
+ end
+ end
+
after(:build) do |report, options|
- options.components.each { |component| report.add_component(component) }
+ options.components.each { |component| report.add_component(component) } if options.components
report.set_source(options.source)
end
diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb
index 3f17d4d5a97..7d044c4aa92 100644
--- a/spec/factories/issues.rb
+++ b/spec/factories/issues.rb
@@ -65,6 +65,18 @@ FactoryBot.define do
end
end
+ trait :group_level do
+ project { nil }
+ association :namespace, factory: :group
+ association :author, factory: :user
+ end
+
+ trait :user_namespace_level do
+ project { nil }
+ association :namespace, factory: :user_namespace
+ association :author, factory: :user
+ end
+
trait :issue do
association :work_item_type, :default, :issue
end
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 390db24dde8..3b37d6cf8ad 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -56,6 +56,14 @@ FactoryBot.define do
state_id { MergeRequest.available_states[:merged] }
end
+ trait :unprepared do
+ prepared_at { nil }
+ end
+
+ trait :prepared do
+ prepared_at { Time.now }
+ end
+
trait :with_merged_metrics do
merged
diff --git a/spec/factories/metrics/dashboard/annotations.rb b/spec/factories/metrics/dashboard/annotations.rb
deleted file mode 100644
index 50c9ed01fd8..00000000000
--- a/spec/factories/metrics/dashboard/annotations.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :metrics_dashboard_annotation, class: '::Metrics::Dashboard::Annotation' do
- description { "Dashbaord annoation description" }
- dashboard_path { "custom_dashbaord.yml" }
- starting_at { Time.current }
- end
-end
diff --git a/spec/factories/metrics/users_starred_dashboards.rb b/spec/factories/metrics/users_starred_dashboards.rb
deleted file mode 100644
index 06fe7735e9a..00000000000
--- a/spec/factories/metrics/users_starred_dashboards.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :metrics_users_starred_dashboard, class: '::Metrics::UsersStarredDashboard' do
- dashboard_path { "custom_dashboard.yml" }
- user
- project
- end
-end
diff --git a/spec/factories/ml/candidate_params.rb b/spec/factories/ml/candidate_params.rb
index 73cb0c54089..e3af8ab834b 100644
--- a/spec/factories/ml/candidate_params.rb
+++ b/spec/factories/ml/candidate_params.rb
@@ -4,7 +4,7 @@ FactoryBot.define do
factory :ml_candidate_params, class: '::Ml::CandidateParam' do
association :candidate, factory: :ml_candidates
- sequence(:name) { |n| "metric#{n}" }
+ sequence(:name) { |n| "params#{n}" }
sequence(:value) { |n| "value#{n}" }
end
end
diff --git a/spec/factories/ml/candidates.rb b/spec/factories/ml/candidates.rb
index b9a2320138a..9bfb78066bd 100644
--- a/spec/factories/ml/candidates.rb
+++ b/spec/factories/ml/candidates.rb
@@ -7,16 +7,12 @@ FactoryBot.define do
experiment { association :ml_experiments, project_id: project.id }
trait :with_metrics_and_params do
- after(:create) do |candidate|
- candidate.metrics = FactoryBot.create_list(:ml_candidate_metrics, 2, candidate: candidate )
- candidate.params = FactoryBot.create_list(:ml_candidate_params, 2, candidate: candidate )
- end
+ metrics { Array.new(2) { association(:ml_candidate_metrics, candidate: instance) } }
+ params { Array.new(2) { association(:ml_candidate_params, candidate: instance) } }
end
trait :with_metadata do
- after(:create) do |candidate|
- candidate.metadata = FactoryBot.create_list(:ml_candidate_metadata, 2, candidate: candidate )
- end
+ metadata { Array.new(2) { association(:ml_candidate_metadata, candidate: instance) } }
end
trait :with_artifact do
diff --git a/spec/factories/packages/dependency_links.rb b/spec/factories/packages/dependency_links.rb
index 6470cbdc9a6..d28263efe05 100644
--- a/spec/factories/packages/dependency_links.rb
+++ b/spec/factories/packages/dependency_links.rb
@@ -6,15 +6,31 @@ FactoryBot.define do
dependency { association(:packages_dependency) }
dependency_type { :dependencies }
- trait(:with_nuget_metadatum) do
+ trait :with_nuget_metadatum do
after :build do |link|
link.nuget_metadatum = build(:nuget_dependency_link_metadatum)
end
end
- trait(:rubygems) do
+ trait :rubygems do
package { association(:rubygems_package) }
dependency { association(:packages_dependency, :rubygems) }
end
+
+ trait :dependencies do
+ dependency_type { :dependencies }
+ end
+
+ trait :dev_dependencies do
+ dependency_type { :devDependencies }
+ end
+
+ trait :bundle_dependencies do
+ dependency_type { :bundleDependencies }
+ end
+
+ trait :peer_dependencies do
+ dependency_type { :peerDependencies }
+ end
end
end
diff --git a/spec/factories/packages/nuget/symbol.rb b/spec/factories/packages/nuget/symbol.rb
new file mode 100644
index 00000000000..7ab1e026cda
--- /dev/null
+++ b/spec/factories/packages/nuget/symbol.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :nuget_symbol, class: 'Packages::Nuget::Symbol' do
+ package { association(:nuget_package) }
+ file { fixture_file_upload('spec/fixtures/packages/nuget/symbol/package.pdb') }
+ file_path { 'lib/net7.0/package.pdb' }
+ size { 100.bytes }
+ sequence(:signature) { |n| "b91a152048fc4b3883bf3cf73fbc03f#{n}FFFFFFFF" }
+ end
+end
diff --git a/spec/factories/packages/package_protection_rules.rb b/spec/factories/packages/package_protection_rules.rb
new file mode 100644
index 00000000000..3038fb847e7
--- /dev/null
+++ b/spec/factories/packages/package_protection_rules.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :package_protection_rule, class: 'Packages::Protection::Rule' do
+ project
+ package_name_pattern { '@my_scope/my_package' }
+ package_type { :npm }
+ push_protected_up_to_access_level { Gitlab::Access::DEVELOPER }
+ end
+end
diff --git a/spec/factories/packages/packages.rb b/spec/factories/packages/packages.rb
index 132152bf028..caec7580e46 100644
--- a/spec/factories/packages/packages.rb
+++ b/spec/factories/packages/packages.rb
@@ -301,9 +301,9 @@ FactoryBot.define do
end
end
- factory :ml_model_package do
+ factory :ml_model_package, class: 'Packages::MlModel::Package' do
sequence(:name) { |n| "mlmodel-package-#{n}" }
- sequence(:version) { |n| "v1.0.#{n}" }
+ sequence(:version) { |n| "1.0.#{n}" }
package_type { :ml_model }
end
end
diff --git a/spec/factories/pages_domains.rb b/spec/factories/pages_domains.rb
index 2ba5cbb48bf..d91037e803f 100644
--- a/spec/factories/pages_domains.rb
+++ b/spec/factories/pages_domains.rb
@@ -349,6 +349,472 @@ x6zG6WoibsbsJMj70nwseUnPTBQNDP+j61RJjC/r
end
end
+ trait :extra_long_key do
+ certificate do
+ <<~CERT
+ -----BEGIN CERTIFICATE-----
+ MIIRLzCCCRegAwIBAgIULB+G07cadoQD0Sh7NOq6jio5SaowDQYJKoZIhvcNAQEL
+ BQAwJzELMAkGA1UEBhMCZGUxGDAWBgNVBAMMD2xvY2FsaG9zdC5sb2NhbDAeFw0y
+ MzA4MTQxNjIxMzdaFw0yMzA5MTMxNjIxMzdaMCcxCzAJBgNVBAYTAmRlMRgwFgYD
+ VQQDDA9sb2NhbGhvc3QubG9jYWwwgggiMA0GCSqGSIb3DQEBAQUAA4IIDwAwgggK
+ AoIIAQDhfq6cKgjogJYFGRuokm7MAyUHwMBzkprL1wSemGquI2i1DkjzbDHSa2iR
+ qTTiNgr8NHlYXhmqn6Km7T4DNaWBqrWLsYVusGBtKKIl6EbE+dVjV/7iqn1lgUF2
+ RI77S7t6tXYKYwG1CiboUi+Dyz/eJB408KY8ruHkSkuqdMRV6XXkkytU3DRd6FKj
+ mdw8S7A0IcY8I/r8Sj81CifAuI4BkSqrh210o01RwYZVjcXiq5R+qIXbT51H6MRV
+ pSMTPRMQ2yvJ997OTR3UopZWv5WeGc0wyQSqMUBBL82wvpNeOWc5GYLLGx1uilh1
+ zWr+MnCYebaDOfP1a4GnHB2KwCY9RUVw6tAKcLxBMWbcd7JN5ijObkhk3TmPexol
+ XmkB72+5q6cytwgdj1Wc2udg746kkPwkKeOmJt1789Jaqlvn4Emez/g3N2hXO3s9
+ DJZuTY3NXesmraq9oGmlWSZNF5up2sZ4811ci1cMEl9p8GSNpTcMy98ZdXCUhrrS
+ g3fPbaK6abcRx5xhbXqzuI6QExBie+6x9aPPO7VR3ibwdk2rae24f2fnquS6sFLa
+ Oa7Spl0eFdS0nySvlMhII2kB4ZBaa1dzZYsVmJgOMKfBKsh7k1EZPOYcnKAyyiWS
+ RAhzgPIC9TULZtnEJ9RBW6th4gUvA2aa1YM8PPERW+kYXBfNsPOqKkW5mK9FI+9S
+ at/og1vQQHY2GFXy5pyQDlgX6UArdnF6grAOOwZJFhCXg0FMaMFy6FEdohNnCOZm
+ iUNk3JE+FyI50UeA6rR5J/x11+kfwmAxpo5+E7zIpIe5MTCdvCdqk7QklAVbIWK6
+ JLY/nqWj0pyhpGSRPJ0U44/ildZt3+tj5IdyqNnuwQwbLCpVYu4o6qhd2WtctfL1
+ L/fXuR3BuhzULmAzatmzJQd5+ewd1e5gH8aQsHMD0OMXJnKK1zrdj/FmbvvTfT69
+ aelyQvFORCqvTZo/b+zXKF6MRd7OblJoqeRVwjxoQWHv5n+FbfLzqUuy+XDleBTp
+ dXSdkQIK5rII23vKoo25gp6uZ99dqMI5RTUN1h0GLHwkCrIACOF3FMuAuqjugP/9
+ sIZK1fXpNnQ1qmZN17phpRDra/tYdoX3YlLYBs/1W5IIauBPJKpz/TYxa2vlisKz
+ yfvkV5CYqUz2ax2mb5bGHeyYYkbPfF6tV986GhEIZTQRBi10BM5eIU/l1WTJUUqn
+ Ld2RF2T2AiFgaavSqiBIUzj5mpVyVjeDs96yik0oCgx31OUUgqV5oSgwnUJYf/1l
+ 1Z5Yg/VhnENo1NN4HHdPWMPLK18dWvY/Ui3GAL6s/6LCLTWS9+mV1zW2IhDyvapq
+ vuWMmQdfbKKvwsD8gFQtxO09CkWa8JOjTYt7VQaISnl039Y/L3vAwy7q9sE9fbNt
+ BiNKxLeULx6TBumHLbSJPUesqKSkM3Iz10seyXD+dZX3Z5dULV8ME16/lAs5UUPt
+ g4SKGnhoyoxciWRB0YYGq8MW9RceppUkn8sG/zF4xsffvdft4KAMBWbzZKOFsO5S
+ pjKFyLBIg68cXmgyqTrWODS6HaBagiTjrKyI+EUl6riFhHjClWtGRTAmwWiif/jF
+ dav0C4GMrF3jpnfQYmz9mE4G/PgHTvb4gXaOQsHFuxUPmWjOz07Ba0mo8GR492jD
+ 3I9ffIjOA1UBA8tRMBAbBzKavQrX6qy9XKHopXC5vrB5l3zBquX8X0I9CZmjrvZt
+ vdj/7Lu+p6wU7RbFr5C3b+obFZN57qj/uf+7GfrjuZnfrxkxb0LxLAgrirUi6RkW
+ rHJ3aL+dQlGd7vzZKsLmgJv34PtproTfIeFgVq3q2nz3uKBCdBwLQRs0scKvbwSu
+ VresQWQfwoy7viMI2964pDl9KBmt8dsVYm0TGx6AYtB2XhzHnF5wgr82anEswbBp
+ n3fo7wgI9lbmwrwXpS5LgCIvOIcqGtH2izXcqt+45fqazsPDj3b3pEyT6FcqwlLC
+ T/1p9kjUJ//mg8DBTXcyWuVDdtbdGpGJHtKftU0tWr3X84k53HGaJFDdUJWuJp8v
+ 87hZMc2IsgjtJ5gBAvpW23BVZf27VFBTJBZqTt/pWMiEdfyMlZeqnUv7o6TlBEfO
+ BNl6BupT9SYQMahE9GDl/mq+QRN0x9qzncDKlQSKZsiocO3Q8eQheTkQY0TVWTUy
+ 9Wgqj845nGTJfM+w4xto8cbkB61fcKd4u1iiDWeYmnTkKOo5Ny0+47bHVrBiaumU
+ 5JsV/qs32+BZBQKIh/mRK/FE/pxXOX0ouZlM3bq3nuDCd7BwqMstI1zx2eKNAjN9
+ G22ZFs9RteI0JbHndJvGIv72Zo7ERGM7+D6rGDARuolPKcgdKWiBH1bTiGv9WSxo
+ fer6hCPNkGl4Z1Upa/pe85P1DL0Yz4mVJteFd+Tn+oJwEyP8XJp6jQj5kYgMDAuG
+ sGq3STyLwnDPe6R+dkCxmQ6kAuZFBNEuduWFZfQJJGxib1vCjnfAsMK0BqW2jFF7
+ cID0A0upiDjgcjloJ+FYF2VLCXUE6dmtgujlNLhyMWcyKDNzKlNsMVB7swkPLnOK
+ 6MFVYQ9dXI72IpI73LKXoREsOcEyItS2pvDhu9TfGcQLBkVTYWllsuhpmsg9xwYJ
+ ajf4ewKP0Yxa6XbkDlxNtyFbRIu8m6AhoRo3sPBPUIb02Dri4qBId7RVBRe+B8M9
+ NuNE5o88QHA21R2u7S7cr67Zw26HSNGEN+9HGY4Xpy66ijW84wIDAQABo1MwUTAd
+ BgNVHQ4EFgQULhLmAennkk5+BcYJY1cU6OYXFokwHwYDVR0jBBgwFoAULhLmAenn
+ kk5+BcYJY1cU6OYXFokwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+ CAEAphitB4iOhDwsKy21Ut2c3C0/gg/rlyyUhoD1H2BAYdJTlRFdCpoH0F2dXFOh
+ rFfh4U3G8sRYm/TwhP9lJ4/TCdYH7WQBIU0dvMectYd2KWyYkNb8eBh4fC1gLZ5I
+ 5zxAigc242Pjft9NsTgcbDI8+xjtSXc0cwaZTD5kxZyQm1BnONoZvF0/s7dsv+n0
+ kU1tB9n0PlcAphQTq311Vk99HW1SqrA9njQftJr/tbOy2nyHqFjhQxAqr9/CYE3t
+ 6v4itH04n3eHgYDlmi0MqrFtqGobLhRp+zVAVxy7o9+nh0Z9wUikknPapV1GH1Vs
+ TO8fhr9eunXsTHQVP2EK77tJK7pNdfBvwHOq595iCbSFp0TF5sG4zCGZReB0TvtS
+ nROSKwq+jsV4xSGlTnqbf4EIoD4HdrWw7BvLOlz55oPK+Og/w4X0DwR6zx3rCAT8
+ nrDm5ekNBTVlAhbD2g284mZ0G5F+c3lnhbju66RoHvrzyEQ+6avdhUB9BTKzZ7Pj
+ CkRLsTlXtOnO5E5/rX1+mKXRwCNmPdK4vYfPucl/vgdlcpvzJunrQMPlvfM2UKeg
+ z2yyT0rW1sK9IcvlqwApWwPuS1mC1o3WrwzZo0qgDwQSzjQh6UkQPSBTmkM9Fv4I
+ AzGQoWAcXw/QbRpvjEm8H3U60B0fCwPyG7Z7eGjf4am2RYs+viRT/4ewJ22i9imx
+ E5jxIpMLeb0CITI594sRQXbLEsISq9Hvrt4kr5lSfZ9IRRv+AiYjjHQVSMRo641j
+ JExXZRuQgagL6Pg4wElyRR1tAsy1aDdenV0hLJ7eSaQf3Z9Bs4honDv97UUVLbQW
+ hebIGnJEPY4w15hUTKzp6eIz+V2rpG2Jcf2G5UXRWnw+Gai3CyBMJ7NnqvIis8qP
+ OUbGYrbqRWOmrjphOgaX9hvLD7nbK1wXMFE3V7cP5py594qN8vg8EGSpsCATXAk3
+ A8aSW/Kl1jVCn1WVzez+E9bbcTf06eUc1M0X5HI8NH7uhw1ECn/jYA9Q5UJ32SNK
+ 4G14vsPtbtG99nAKy3fbA1Qn3MOu5anA2rl0NNICNEc89Q6fMeyFV8ctwyF7qqYq
+ M439B6R8jzz0ESLZdp7r9f8Ve3TlBvs+42knRBkjUqfNHSf06/wG+AUOmNiGF8jt
+ O2e4mXxLotqIAT5OpNpZIQyZY1Sr4uvp3zsvKOnHU3GBwsB4nhHqRzpRqkK6DIaw
+ TnOC/dOKzWpUy9iNzEGCNaJVWkQBCaFMJb968h2cZQzpj15XhAVlKfhh2KHCoDGt
+ WnEPgchVzBQwvhZra3gP7ynkGxSRYYPzLWt7b6oZSMB/JWyU+2fSqRPAXvUue7Ns
+ peHKPuGETVMR8jTuUghQvQDyTpoH9GZzyNQ2CUOfgAoA5cc9XuI+KGcsQuWqQvLv
+ zpxeHM8d1+vAu8WjnTs0E0MZk7Vi+N5DuhsTT7kP9fyz+rQzgQ7+bcanOgBABIcc
+ dsbTdfJApeFwN874s020M11Q+RwsXm40xDZHTYWe+r2Yq/+kd2N0rM40TS/Zv6KA
+ /1Ag5XC7dq3Uqp0Vk06LzZ7qP8gNiN813/qvN2PW/phq4A/OFtCnEGfom4I2MimB
+ SEpYuPTgiRo//y1tqq5D8994J546LdQ2Y1VmlK/7CYHZN7Sq7yoA0gVZh31QC7Wh
+ huX/bjhpmmehMbE8f0//6jEqvJxA6qV8f2XJNGa8ctE0Tf7kwku0JSPSqW4hMdml
+ udZivHIpgANbYgTVeVR4LFnkZO2tVeNXDj+jaQJ8piyZ4V2HVASTWM/0JieUuQU/
+ btvNFQ0iMRrjVKjgK9OZxo3f5O/CNTrKYQDPMyyJEvs2+oZHwj7T7srlgEm0RmX0
+ PkXsR2kmCnjSdgIrwbW2FB+QS2U/N0jUQfFxfv8s0zor9RyL3PuHjtfYPbr8v0wS
+ 5b81CafxumhOw93DWhwZoyK+IcYrZ904tqmJFraaX9odJ1AzZS+vf1AzlwiVTT1+
+ xN0Thf/WnXzQb9JGQA0Ix005ekZbxbjOa1jQ8kIuZ4qQe+/figpTf8AusvxnwG7N
+ T2iP8qVnd/ovxIDrPJ+nssiolQwDK7ocSk6ZCQLYj3fSCSgGmobY8XFlFrMfW+oM
+ TQG4vWvcLuIrrTcnp5aIl4XyvVuvkJoYZD7AXBng5CoGA1AaJEK1He5i6+OeNHIJ
+ HvNMsUPmHaOdYa2iVU1aJ4DUbO8zydXPPNtI6hMvnvqp5oq7beNX8hXkIPIhO1y3
+ Nc09nzD4nLCHH96GVpCwvWuvlbLGK2fHdj/bP0PVRn1ql4O3AbXD0tEY4nacq7Ex
+ AS5oPtHdosrQrTv0ZG2D+H5x7u02f0hraMubSyjruZ+TA9phgQjXm+D+JrcCrDr/
+ oE1L1uBKnQOT/8AsYh2t2JhuV7Ry0cg6Jt+AQAmLCzaBpxIGYWWNIbjDifn9lZi+
+ lZW9Ny+sWVNa4VzB8V9V9rXGWqDnNag1j87JTmS3NTqsECiaP4QJML/A8zjoI7e8
+ QFwKPChCfZHhKA/yAcY7GX7Gwj/ljMrS6ZvYirH0dI+v00rQ7LFA9REplCVLxpBT
+ iboycHkVNdni8H4xqiMpBYw83bX5B5syLS744+QX2kUkhIO8ILSiOJ+gutbDRDi8
+ Vmi1NgacnawjwRBzfKZd3r2JCZ47n3o9j8kbxQlgdOtY8PmttzQH8jUk22rjyWJs
+ O+Y4I/T3OE9g24Ei+b4kwgBFXaoajzWj+/xKOI+Oy+EUPg0=
+ -----END CERTIFICATE-----
+ CERT
+ end
+
+ key do
+ <<~KEY
+ -----BEGIN PRIVATE KEY-----
+ MIIkRAIBADANBgkqhkiG9w0BAQEFAASCJC4wgiQqAgEAAoIIAQDhfq6cKgjogJYF
+ GRuokm7MAyUHwMBzkprL1wSemGquI2i1DkjzbDHSa2iRqTTiNgr8NHlYXhmqn6Km
+ 7T4DNaWBqrWLsYVusGBtKKIl6EbE+dVjV/7iqn1lgUF2RI77S7t6tXYKYwG1Cibo
+ Ui+Dyz/eJB408KY8ruHkSkuqdMRV6XXkkytU3DRd6FKjmdw8S7A0IcY8I/r8Sj81
+ CifAuI4BkSqrh210o01RwYZVjcXiq5R+qIXbT51H6MRVpSMTPRMQ2yvJ997OTR3U
+ opZWv5WeGc0wyQSqMUBBL82wvpNeOWc5GYLLGx1uilh1zWr+MnCYebaDOfP1a4Gn
+ HB2KwCY9RUVw6tAKcLxBMWbcd7JN5ijObkhk3TmPexolXmkB72+5q6cytwgdj1Wc
+ 2udg746kkPwkKeOmJt1789Jaqlvn4Emez/g3N2hXO3s9DJZuTY3NXesmraq9oGml
+ WSZNF5up2sZ4811ci1cMEl9p8GSNpTcMy98ZdXCUhrrSg3fPbaK6abcRx5xhbXqz
+ uI6QExBie+6x9aPPO7VR3ibwdk2rae24f2fnquS6sFLaOa7Spl0eFdS0nySvlMhI
+ I2kB4ZBaa1dzZYsVmJgOMKfBKsh7k1EZPOYcnKAyyiWSRAhzgPIC9TULZtnEJ9RB
+ W6th4gUvA2aa1YM8PPERW+kYXBfNsPOqKkW5mK9FI+9Sat/og1vQQHY2GFXy5pyQ
+ DlgX6UArdnF6grAOOwZJFhCXg0FMaMFy6FEdohNnCOZmiUNk3JE+FyI50UeA6rR5
+ J/x11+kfwmAxpo5+E7zIpIe5MTCdvCdqk7QklAVbIWK6JLY/nqWj0pyhpGSRPJ0U
+ 44/ildZt3+tj5IdyqNnuwQwbLCpVYu4o6qhd2WtctfL1L/fXuR3BuhzULmAzatmz
+ JQd5+ewd1e5gH8aQsHMD0OMXJnKK1zrdj/FmbvvTfT69aelyQvFORCqvTZo/b+zX
+ KF6MRd7OblJoqeRVwjxoQWHv5n+FbfLzqUuy+XDleBTpdXSdkQIK5rII23vKoo25
+ gp6uZ99dqMI5RTUN1h0GLHwkCrIACOF3FMuAuqjugP/9sIZK1fXpNnQ1qmZN17ph
+ pRDra/tYdoX3YlLYBs/1W5IIauBPJKpz/TYxa2vlisKzyfvkV5CYqUz2ax2mb5bG
+ HeyYYkbPfF6tV986GhEIZTQRBi10BM5eIU/l1WTJUUqnLd2RF2T2AiFgaavSqiBI
+ Uzj5mpVyVjeDs96yik0oCgx31OUUgqV5oSgwnUJYf/1l1Z5Yg/VhnENo1NN4HHdP
+ WMPLK18dWvY/Ui3GAL6s/6LCLTWS9+mV1zW2IhDyvapqvuWMmQdfbKKvwsD8gFQt
+ xO09CkWa8JOjTYt7VQaISnl039Y/L3vAwy7q9sE9fbNtBiNKxLeULx6TBumHLbSJ
+ PUesqKSkM3Iz10seyXD+dZX3Z5dULV8ME16/lAs5UUPtg4SKGnhoyoxciWRB0YYG
+ q8MW9RceppUkn8sG/zF4xsffvdft4KAMBWbzZKOFsO5SpjKFyLBIg68cXmgyqTrW
+ ODS6HaBagiTjrKyI+EUl6riFhHjClWtGRTAmwWiif/jFdav0C4GMrF3jpnfQYmz9
+ mE4G/PgHTvb4gXaOQsHFuxUPmWjOz07Ba0mo8GR492jD3I9ffIjOA1UBA8tRMBAb
+ BzKavQrX6qy9XKHopXC5vrB5l3zBquX8X0I9CZmjrvZtvdj/7Lu+p6wU7RbFr5C3
+ b+obFZN57qj/uf+7GfrjuZnfrxkxb0LxLAgrirUi6RkWrHJ3aL+dQlGd7vzZKsLm
+ gJv34PtproTfIeFgVq3q2nz3uKBCdBwLQRs0scKvbwSuVresQWQfwoy7viMI2964
+ pDl9KBmt8dsVYm0TGx6AYtB2XhzHnF5wgr82anEswbBpn3fo7wgI9lbmwrwXpS5L
+ gCIvOIcqGtH2izXcqt+45fqazsPDj3b3pEyT6FcqwlLCT/1p9kjUJ//mg8DBTXcy
+ WuVDdtbdGpGJHtKftU0tWr3X84k53HGaJFDdUJWuJp8v87hZMc2IsgjtJ5gBAvpW
+ 23BVZf27VFBTJBZqTt/pWMiEdfyMlZeqnUv7o6TlBEfOBNl6BupT9SYQMahE9GDl
+ /mq+QRN0x9qzncDKlQSKZsiocO3Q8eQheTkQY0TVWTUy9Wgqj845nGTJfM+w4xto
+ 8cbkB61fcKd4u1iiDWeYmnTkKOo5Ny0+47bHVrBiaumU5JsV/qs32+BZBQKIh/mR
+ K/FE/pxXOX0ouZlM3bq3nuDCd7BwqMstI1zx2eKNAjN9G22ZFs9RteI0JbHndJvG
+ Iv72Zo7ERGM7+D6rGDARuolPKcgdKWiBH1bTiGv9WSxofer6hCPNkGl4Z1Upa/pe
+ 85P1DL0Yz4mVJteFd+Tn+oJwEyP8XJp6jQj5kYgMDAuGsGq3STyLwnDPe6R+dkCx
+ mQ6kAuZFBNEuduWFZfQJJGxib1vCjnfAsMK0BqW2jFF7cID0A0upiDjgcjloJ+FY
+ F2VLCXUE6dmtgujlNLhyMWcyKDNzKlNsMVB7swkPLnOK6MFVYQ9dXI72IpI73LKX
+ oREsOcEyItS2pvDhu9TfGcQLBkVTYWllsuhpmsg9xwYJajf4ewKP0Yxa6XbkDlxN
+ tyFbRIu8m6AhoRo3sPBPUIb02Dri4qBId7RVBRe+B8M9NuNE5o88QHA21R2u7S7c
+ r67Zw26HSNGEN+9HGY4Xpy66ijW84wIDAQABAoIIAQDcVXF+TCB6NrLf9mGtPLAg
+ jm4PfktOYpD43ne4FAwhbZ3xVCz6Fd000xjRQ3nWE6J2PzvWmdQQgX1oCGbQsgmv
+ gsNz5RkRSCxgXRTbX3RPIiNct+3pQ1fV6A+z5VekuqJNS6Q0j/tqD6pm1W9yIxac
+ E8SkTATTRLqa2/HFc+UoYT9+AkOT3rsYi1q8Wyn0jKx2tA3EVA/5lv7d77daO7se
+ Ut9TzbepAawaV7PQQwB59NfbTwXEfq2bRxkY6ow0Tzgi/1VxOs8t2/JrBBdMWlVy
+ r5lssu7o8cjsKS6eJglPR13SUFgZ57vBeFLpgLer/FNC2aL55JW5V7vPMsy29/wl
+ YFty8y4nFXMNbJ0qjZbfQSbcVqxMSlHlHg81NmP6rSAJV22/Q1MdtyGba9YsRMen
+ i7ekCn5TqqQ+asc/Kjk1gFXPZT0PjwdYPVm1FGilDQijA8My/vzX3zd7hnnDWG8U
+ 8B2Ar6OpOsnqlMVAedF3ClmZGlg7wyInLuK7shROzbz00zk7mUT3egcsNwiuRMJ8
+ yMY6g1/1rU0F2sFHswE/nfjXjz5TAwwOUx4R980YLdDNBd3aQ6qQGhv9SQRg/yuS
+ /lHsAut9RaZGL0qrmAdfoFndBEGA8ZYjKpy9p9ZuLi/LrhePtYbRgW2IE2+J7FTO
+ VE9cuYZLROz03k8MK2hi5yWgPz/0Evon3+4IJT/2LOx4t5QKVYseFjIjHLD9ZD/8
+ d/Z4E9y9evUwUuwRcAJNDAsCIXipMOYuhmbDCBqfIlqVRft+bTyl/jAsNmMcLsWu
+ 77oYqbuP++86SnIIBcWQSvpkzEB4gV4eZqfWZOrjjTwisDe2RjCyLXz7nUPJzklB
+ AUw7RmEHK3APN/iBUI1o84rs1iV/1mNuqqbk52MQGeS2mAl1Vn9Pnndr8aG1kPwj
+ RxduO35FgPRRZTmQNFQ10ArH1c+2HHnadAXrBONDb5/jrv3aX0R5+f59WgfQnrEQ
+ GoJRnLftCCcIY+KzjBFMqlt7tQ+vqMakocolOEyjbb6GMlcCCpySKnW7L6OnnP2H
+ wc9OMI6fn3iqwKroeL7nA8ZzGhGjDkDlE42PMH53/0sS/s9cZM0kAMgwgx7eOpvV
+ G7LZP+zdAwMOptQxf2UAUD5xqZjbfzBlkUmgbZvAycMTOFJocc/+AglcOn8lgtnY
+ AZltXXBUkIXWIzVV8ShWth+DoJ82X2XkxJbidhGKpUZUj05Xq8llxjBXG2KPmnmu
+ yAnkmcvfvv2XQwJd0NuqR+Iyz8K6hd7/JMjQSYQ4z2/kWdEQTOz47y+xi3V9Pzro
+ LypwQvdRAwdNeVhqzcwMeEt4y1nDRtQyrBspxK/9ysWGe1sXzH/P+gDG3CZHv5Kz
+ 9b82pNI8mGuSSzZqKtZtHnysb6bt/h16EnLNZQ3+SxGa6nA8Vk90Un+qPDHye8lh
+ FC0Pdkp1bqWY1Gok+xSWm0jeT+1PKcGNaePxV4/3+NL5AR3hhPRaVg0pbiuFXz71
+ JgWKGkj7eHFxQtineq/F1OxsdYzB66xBNI9f7gB3KCFyVkE5PVebNV82fV080IQ0
+ Cy5yQ6XMU+lxuEFas9ZVb2Z9/mkXpQBOFY+9p9nP0wHdwmS/SeH5TuJnquBh31kt
+ FkDnAQyVAHcLPdKihWnSsNPlFDeY/Vb2bTA8ppPGXZuj8oh+CSDA2P8u3BeUeEcj
+ U3gjD6ottWIpOcqXNHwql9asLuVERGUDd7K9ALsK3DzjRsDFwQMSFaFCtG4v1ZZa
+ WtURi8RmZBUP47///9DkwV46/m0TTP5ax9vxjJLkiZOGlQes98KQ1Oyl9b37cds5
+ gb3SbXz65VWYW3/4+h3GecZ6xynfsfavD0d0fBAJN48YaKb3k/9p6qfw3cxr/A4I
+ Y75m9Au9OXZdgncCT19kpC2uXlXu9XlGXcv/VkNt1p0jMta6A1n6kJvyG/hrjUpH
+ WSYibXEW/qod7za4oYBv+3bjNSSaBqjx5n/1U8lj6xp36ilHhHQ7QkIH3O4RqkPj
+ 5oXKezm2CUqxYJ7Lo84f7cLbHXcG9Qp+wmCy97E/NPlK+8yQZyz0e6i8KtxEocsQ
+ u/xqHlCSi+JCR8vNA0ndsWJzI2/dDF/7Q0pcOvIxNARSmyHADabRBen+FPUEE0AN
+ KWaspqrf78hAqLbCXskUZf0T9S9DDMDHQj9bZs0H48OvCVFFb5TzBndG2kJIOZSg
+ OnzOOELcZBPY/rv9g26Q8CrhGnh4GoEEbNP8imPJ8Kmpd1Vk5auVYD9qfygm21Bw
+ uxj1/O0cdnZfT16X9h0JnwjP9MZ4tlRH4t77uswHuaStRTe/dn/kA9Tn0cox4z3q
+ 6txM4uakB+st4LgMhnDTGvMMD+I3TSaReexr82hOZJUwc95VzW4lWrIEB4Yv69uA
+ Lt/5kbJUY44kAgdORPHLVsFhngHilGyD/3m/XyHUxRiNdj6/CDANtWwYN9089Jky
+ gauvpCOT6D2SJVCx/AZIWmDwNAorXVNC6Rl3aySzIK81aqYejm3D6S774ciOG1HC
+ lbmVPtLr1kh/ZbM+VrnpzIu+svm4hFZA6dhAYnx+50ZJUISX4a9i/vkTNBK0puwz
+ yj64bwKxdoRnT7tzJAmz5pMRn6K69ur2mEvW/4KolJeZp3V8YYmPZPjYMLPdeJDc
+ Lf/t6Ff1WoERTpe6IepnPlKxuSgpn9JDzZ+V3hVnQdu4kHjSheZMXei3Bv0fb/eA
+ /DR1vGi6zCGGyGh7lSaWCQKCBAEA+aiesAPcwyZyjGn7u1c1qBOUtUex+EroyO+D
+ JXgKIUbNvKxNcD7+vWD7mq+uDHEsYeKwcK2ulV5t6pD4HYaHROg+qtaGm9jK1Tbu
+ O9zPyQpOOEG/tqHxasO+fuDiQOO22xwy2+oc1BkpPn+q4yDLrGtV60k5mIEFusdB
+ fDYLQIKBRa5mIrXOJ4+DMumAqXAHeB9rjlll4AyQLHt0n3oRok1GXuL5tQJvt1E2
+ HsU1HPMcwM/cX3xuFDMRNJ0PP9GGFmXGHIrWGqYbsnIIgZHUjbSShAzsk0xK2OKQ
+ S10CXP4VFkB2C94WYu6f4aVKk1ia9DYdDLvzVG5pvx8gmolccCk59cquE0SVZXoq
+ 607tHXspYgCBhJZShrvLvxX8hxbstsoVa4E7AkjWQUMbD/5Kpt1V22F2EHWLIty1
+ UXSTdlNGTntfoS4PEkxQg32kF17x02fpWpvR1gINrZbpVUgWaiISs7XbAYsTukwV
+ BlUka1/yZMrZzB5q8GN2RXyT0bV1U5P1SqiF3M2Y5ffzVP/OTW/+bahnICvIeDlm
+ aXary2SCLFtpQ0UBbmGV35JtgjxPV3LjARYiNv1kpozKD4goX/q45JMmefHIf0NK
+ m90Jbk8ezxyMIYanrQ6rNLK6nUm68+mJdR+okNXuosCWaWG7uAl8yZ+Aw6yY8aRa
+ fBhX5HHY328gCbCPwf6W1gkfmdgTNIq339sIngyNlQAxQwW3DRf38P9U3PniZX6z
+ wqNNqGaE8+9OjHyJzSXCFiYHFuerfVYYmkm3zvuPaya+CLd+xqj2jV4P+GUW/3vJ
+ UNtNM4nUITgws2hNQS+oWEbcFiI7Z3M7JIAI1P2BsWvB6YCP63+p4Ij5Mij7IQso
+ 2B6j5/dohXKzQvSFt+r94bSjYfMGE5F3TGWERwmubGifap0hsEuxLdECdzC8yo6W
+ fie4V7AW+ssBRhyHf/FKUwix358xECRBYa/hm7gLMtGYU/Pt5wuK1APJGVbTizaC
+ y9LSEDkOTqGu/S8waJJkdgkethbMj7Z2uhpBRxlRKWr9I2GvUn+9kYnfuIINB9Iz
+ mMnUeK6L9mhu/+e2+8VSfr3VHASd9+9m4cVWqSEjPxgg91dHl5LkPvnQyj6gu7UC
+ IdIUziFEeEBp+7t7bqhyq+9ofxachn502tWeuureyzscoFrbfKlgb2yXg0K9TQLu
+ UFXGboRE9xS8xI6svAwKgWrjdbUlg+MLTVVLK5oA5srGLuzYc2bqu5KIL2ViWaeI
+ pnvYDWBIBtyqvbYUbb88DFTl35rcufpwXE9SBvWk8FO5pEvtncYDfU8bhdGg3esJ
+ s4uTg2BBb97kViYttyR0YWnWh2B63M+rqb4Kt0v2dGalUmHoTwKCBAEA5zjwfagb
+ Yg7tT4eN5MAvCRzeMKVKSKhPKmXVJWtul3SzcypUj8uB4wIU2HQwRUB6IIW7fbKt
+ 2vfJRCYKYMUtaavltQR1Vp6at5xkswIEeNfxe5vpOk7EiFuE+Im/MVnjvkTyKmYi
+ emO0Sv5reTHaQ0KbE+cgoNO85SHS+XXxm9VCdMbhGiYbhVNPzeIKX8Kwg/wiAP1N
+ hO1WgT/fXtD5/xtGjh6/IKruJ/CtQXvecT7+/QbT7rQ2Xx0YBu2/5W9XRobzIo6K
+ gLyUkRIIvnVC+sfnuFBMtmMT6e2P9FqMe3f9sIyqyJlQdjaBZeGM2S4sDNMZQEAX
+ uOjUK4sG+7KwQxVdNlOolrn1QTKGXIsbRH9cWbn3KM6qC4LkCEthoHB8oY9aC/Lm
+ gux4kJ4KM7cxXuHIDfcp2Zg8Cd2pUuH3U21HSpPkzEXEK0U7G5O8E24KpKfBUco9
+ CE+bReo1OKRgqpVyYiFbtC5xAbwIqd7+WFkEK8rwwMIwB/Yqhl+10T2KsA5vcvz/
+ fhjH4voEc4VWZGjjfyqkHhFTlJFpqaWchBI1EHhNezpIQj86eIGvzbgzZfGHg6I1
+ B+HQo3bqLvO0sO5XKJ/bid1Alm/RC4RfWIqSk6lNzM9yaMiHJ0LUrTf9bjpk30+y
+ nz5wbLpkxNZYP6LE7Zhm+um/TBCMRJ4eW0Oc5rcIEl+Q+h+dMeI6o26Nb3H7gQSf
+ L3L+VqxboT2tXxUKoGwadMqNrsoxHb87xX5E8l10DGdWgSer6bH44bVba7kz8Zny
+ XqNad8ZpBAUzXMbNmzBxe+q1jCcUI7simu7CO0UZgkeJhFY4tUFq07B63YRmP90y
+ fvoGp0MC5m+UlawIrRgq3oNOXhl4b6S6ow4JiDAndGz51KGRQLxZcqP3yBmjXwOb
+ GL2zlnGhoIe56qTuPBibmk50NLjsQIDo4heYG/h1MKa183yo1uwBxJfNFmcDQh/d
+ C27wiAF5fiZvU7yJ7d2EFgvyNOrcMaCq+1Yb4Au3gYTe5qpRNcl1kwFI+1DO87e6
+ rryA67YBDatghqhVuXwRgNqgpq3UcCDkczQPm9Hb+u9/kOz8vF9EwSBthivKpTxL
+ TD0u26vdJ+syiyzTPvHShgyyT5u5Zl1sAjzaCQte+WgsAtojgTrrYUDKDb/IhhQK
+ SzRit+0m/yXo4bAgHFklRdOs1OcIyTA9NzHke7JsCGgErqDTbCI5xqVp7dxAQcwJ
+ ybaX1tkRar66tS7DDsKw9PeHdW9LzUNCm4TGyT0SMbOz8PdVCb1TnbkHIJclLjz2
+ 4llQyPGEsqNWUF7FzNuybWSFl25/EhlT3lMMmH2T4yRA+K4Hc298gxofKgsnHEzh
+ CosyHu+csHDpLQKCBAEAqfQ2AtC+SkM0G45Shdf6eO7LfxTNfJ9SFOenuawcCUcv
+ 607IcK8Rr04EOet6apHoisJNJoe1n41m+hWyMjdQgoIvlxDvFczhV4BLcYkCEnPn
+ h7iKkANyWyHh3nGs1EuwQTzTCo43DdQLFbbHWFMNE9UF6mQwxzad9eaLF8mao1G0
+ OwFcGij1rEywHcqDgdT34LhS+da12W3z/7QTUjVBJ+G/E/0jzCtabcrlMtFBNPHz
+ EvbtqDsGnM2e2thId0NlKn4h/XAuDHojxLiIPdxOfCD+1NIPgr6e/UJOxF8Oqst1
+ A27ibXXEe5jCUlO5jtD0u2bTI8YXAdUgO7Eu+sSjnt8Ry9cr5YX8xdYCvak/FaCw
+ LTz27pF+oKXbL7wB6tyaTF0Jc+PHjeiTol3SYHLV0v494lhYjR/XleX1sPvRHu3V
+ oLuwAANg0y4MaVbwi9Bgg2/rlXkZwbwoH5HqSdoHGD0Vyiz0Z/qLdXkxntv7LPVm
+ B2NoHOJgHkE3VFpYLpx+wGSqySYr6oIzoenHRofVozWoWHIZsfbcQ6ufog/dJ1rG
+ mvenktm4/bGE22vNDKmNwZQ+IJE2vYSGLjMNosEn6x69Gy1pNf54ZNokQjKYpvVJ
+ nehrJK+MGe0wc3FwRH7avAyxPIBOujpId5bvTdHwfnpG7uKcP5iRjX468tuHicZO
+ wtvdTXtagc+UUyRm1M4ZVN1SCxwKo70b7ODyqBON52X3raHD3aJmkn1MViXhSdBw
+ lbbFHDHzhSo9E+LTVK5lOa+QlAe3DzqFCYaYO0rfDNIc9WOhL5FxtH5KL7b6uSkM
+ tYiQ7rEEVmnhCidCz/aBxgzVqCVY3dWtomAe45xXXRPNS0MzkQgA3R/BsE47ekAc
+ cSwCCIR5OxjHuAzGZHmSG2QdeG5rPAjFKpuWWneZZXBBr1Tnfsg43RNwM3VKsrb3
+ DceAmH/3ZguWcywqGnc+aSSlNaELznvdc7znG8+klnJvEaF6FrvaypxTMfnUcqLE
+ sJa0jzq+k5GEvi27MG4Y14R5EnupEIOVksJ4jMuFFH5NSHQ5TluKD1bzNQHAmF8K
+ fLXfSmotUPulCw6jsq0Z9JyOxwcV1ZDvc5Yzau2JmQ+wPYbGsccsmFvClc9zxlcz
+ S0FeZLXecxhM5+rUkh+McqpHVmmx4sDc5jDZbfgsDpMnSPL9uaeHQpPKM/oQWU/F
+ uwXs80nFIUZ5KFzhd1HXtg6rtPtpbscp8fL8MxmcyAK5rPM1rj4wU6QPDHamP4TZ
+ w4IY4YjAI23ZrPNmgW/k7t4j+1MsHfy/SbNVXxkpKwyPd5CQxepMvoWwVv+fbgHq
+ ygNMIbFf0ZsJdv8bwZDWUtc0nxr2JI2buuXdiVWJVQKCBAEA1tsADaOCHnJEbdxG
+ K8OxcURT6twM1MshFQKfNzBHCZG1llRFU4EFZs3uVNxSZmdtlH7wI/M+vfP2H89B
+ YX6XnlPPFY/ZAO5MUkWPBQ/g2/G9QOE1raq30QVJ4DEPampex9UFOgTCEPxI8k7L
+ y0hZypo/xBTHKurV4gy2IHxKUEWwhRaw4T174T3zMBrVDPq6T0qgxk6aE+T+tweF
+ JnQFedn8i99iNpbeylpIhEr3/j9Nbg1ELdFjnKpKQ1X1NNtrO+v2TawqY0nYu50I
+ ZwJLhQDw/0IOpoQWYw8O7z6cv7ZWFBICOHjOXap0PxmBaeYPpLMcCaoE4Rvo27VK
+ feQjCZL2lJ7UT4rorPaoB6Jzagj25aF6W37+X8f24QY653zfMrkkMWo6bHoT5j4U
+ uM2HoOUoomGDj+B4GarRxmSXD/zBfDlFJ9PEX3jrXcq/v0ZHuYzwhHHqmKhwXl0t
+ qz6DXL+WFD1vG1T0SWpSmpbNvYap64+ee192hk9mYIrbRl1rXAFt6mnRd3jLdMxi
+ Cn5iMteMXgRfkFkFU05z4uIzOD469Nz1Eoar0nMyf/vyQrThfd8bz2OQ54wb9Wlw
+ XsSyqJ4we11gARGJDMFGfO86MepCHdf6pVA2vctoW0EsovEeG6lDRoamMncwvLfP
+ H2EVi7xSRX2SY6GE0selr7VF/AQt7e0yIPCQpPtvdIUFfAwkfORrkg2bZdnzINL0
+ KjZHvcytnTgWtWPql/rl/QBQKEoXAyd3yHbV2RnmEzf/TqzZEJZ+AAjPQMWGMTo7
+ JzM18QYC1CwFp+IHZP6DJlij5VfrQGwLMhYLYN9FvpfVDnQ1F1YKNVnzrC3ktNP+
+ A+a3KQU84qtMWouk7Ke6U/O8QfuvO8+TOgpxc/XWJVNfwrk+a7/3ITkWi7zq/ecF
+ C0hTqAguH8W2AYLZVIxpa97diAnonEUZkGW5OVIjCeMwGV/9gM2kJ3O4UQF7nMXS
+ ATjxxduyR0fJjzr2i9mZVrw3ZWk0adI5aK7w+WJWKCbVjA5rpKwIQkv9upULLvxm
+ qi8PeNE/JyZ0lUmSco+gkbjez3YW8vHk+Z5G6YJtrxTPrK3XWA+lNDl8tpE704A1
+ 9vwEcXLrsNfAijOOFY9cjhRNYx7sc+8PB66XBudwiosXYb10g6YsTPqePheli8dg
+ r0Kozd59WBo2GlaBiSxN67VZjMpdx9uZq44Mm8Bx9U8wZLgcYJyDUSCqD7gOC+SU
+ 3J3ynJ2hPzwGdvrz8lnDFC9l22Fb3m9TUr/rewQ5Dt3QrwTZ7JzGPdsEhnv8J1zV
+ s7E3aWNHZf7YI/J+eKKCjWzfk/2T/LbkDvMHNI1x+wAjsSc6wjSu2QtPKh8CKeD5
+ trKU2QKCBAA3IgjiRuX5dCkgoq6T+nqCMy5/vrbMRMCMLfGsOwk9wNQk/NtsuCoP
+ fyFLWPD3RwWv17904oFWiSA+kfCQ8QAlLHJuweCUybbklh+RN8PYHs/llxt0G7Uf
+ sk1VV9XlWINE9x5uxoOQq8+aMFDvWjbq7H1kbJkVWSYJjQgjqk1Afp02FIQ6kWKJ
+ CBKcMT/AvONsFjjyBTUtCGop3ftytEFedw3zlqhn9y6HITTvmjSyZBoPZox+vacI
+ DDArlo5EC/BZf0zpaIgDJccGLJI/eOPqX4VqhX+EWJErVdX0dlLDQcoAlM6lIRer
+ OHHdvyKN5Dvv0eSlgp68jjrLTwEr46DcHrB/W3L5/S23rJ3G6IObvS6SljPYFQHo
+ l/hi3ZGM4wSazjQIfNPk4mlE/fB5jmFWolijGLc89hGhpmyVJ6bqISUowM2OqydV
+ NhK6oZhyd32ebCHp2XQ1CKPdfrEhdsEreLT9E5pMNVptsZ7ptxIhZ9ILuK9fCRC0
+ Mz1bQ8ZX/VgCvb6qcU/7aGZasqDMQopbwz6bVg8FXAy2Vx1vyy+GXyZqBRdi7Lep
+ 6XzspzM5AJ2Bpk2PkMbiCRBnjrxDHpXcokq+J5sTYQug599v6TXqNf0u6QHd3aJK
+ t0NRtiiOtErp8HZ2yWcocwcNnTTdLQ43bJX7jevzQ6KVZwdavMOebHz/XY/HTUzZ
+ taq3/vRx2EWmsBxqpkmu3FOKopkAB38j6ulUjMebamopw0vicLJj5cxjqAcOLrTB
+ 4Wgr0sF/sdlzSCyEyAAoQMPfbBTIXwErJylHEPLYncJG9QrH+GKDWbw5mDW63wYY
+ bHKjLJ62/rkJldyWGTsSMeHmKbt7SZUv3ntcOjeugQubZL2olZwzyAGqUtQ/tnJV
+ rBPuzRddPWA2Jq3ZOfpmLmmAlKX0n/udTNBbK+eBht31DZWZv3thqkp2hlcn70tL
+ jrJcQv9hpqCR3u96Xfqf+Fm2qx3IjhIzhtE6hlGBaDgl1+4Np2kNwwboWtT11Duv
+ kcwZ5dskO3i3KGEESyi3j/qzv6HVWEjq8ex/H23l9QigAN9ikPRdDuSmKPxMgr76
+ CmXc4AtLZA4iiosHgHZ2GxDmlPB+yohBy3AGuemv6sL4EU2C1Z6wDdOUapKJtgSu
+ M++J8FOtBW+yuySCIBCAYGVbjm/dVi3ay2VhMiW7uq1aBMYh8Dg9DppIPJ0KS8dB
+ dsyQz5OTBDRoQ1kT9vMYIRZrjbeCNqQnfkWAIxejT2TXQxPVJf+efVqrotrzOivb
+ AdoggNoChG89dOwEJqDRJ4OX4kvuNuJa1M9kvfdoEc9ToKXXY4m7GSaf4JyGEqe8
+ NtjUPwBEHYJ9bcJ/fgqxWtoc23l/1OfP
+ -----END PRIVATE KEY-----
+ KEY
+ end
+ end
+
+ trait :key_length_8192 do
+ certificate do
+ <<~CERT
+ -----BEGIN CERTIFICATE-----
+ MIIJLzCCBRegAwIBAgIUB6932CbRBXCmSbrDR1L1AeVQsq0wDQYJKoZIhvcNAQEL
+ BQAwJzELMAkGA1UEBhMCZGUxGDAWBgNVBAMMD2xvY2FsaG9zdC5sb2NhbDAeFw0y
+ MzA4MTcxOTA0MDlaFw0yMzA5MTYxOTA0MDlaMCcxCzAJBgNVBAYTAmRlMRgwFgYD
+ VQQDDA9sb2NhbGhvc3QubG9jYWwwggQiMA0GCSqGSIb3DQEBAQUAA4IEDwAwggQK
+ AoIEAQC5qEZ5QBj+nPYQjpbOBwRWIsNJVPgB54ADkjYSfL6kbPyeQsgAP2vU8zWA
+ Z1lIyiV3M5qa7KZ4oK4uin7O3rwho2XoWaaf1Z6ifpNeVl8Favyn/IeVJp+jchtl
+ VyDAEaX0GozOfo5X+xOAQE7twUNSlB8+6YIqxTQf28zB7ks/2w2qrJvXO3cSgQyB
+ 74tTUn/25hwATNlEzSBRdLzoNeK7ZInayLAvxwR5krIm+yjH0EGsI7XZQMLjZOwL
+ 95FrhfBLYODwPam5lAzPB6paeY+oGGkNwGhzECqmHLnXMSlY6lpeUs1vOCjVcE13
+ v5jb+nIwLaBWvpF4fnskgwI5+hiBcfsRuByKH+x5pW7ofCnqAOgkq8m1ErqRIvN8
+ SG54ySlA/+RoPI+G/1/x/AdQtdQxL5X80ZeUjpLGTGy3kPVEQ8feP8Ny3rSklsPt
+ nIMk6fRWgiw2ba2jt500F+FuntCj3PWDZfQ+LBBswuLpQCoB124RobXwFCCfqSd1
+ 8+S8PfGJQ4gDwc4K17lm/WJq/X3mUDmxJLhEIvpZUxi2App7b3KqdCMthOUxUFoa
+ IZiWtbK3h0A10c/Qr29BI3soKxD30dw/DylR42dTGZUX9fdEkPOulVaTXmApnGkv
+ HRomQ2VSJQq8wccceXvte/ZV2duehDk7032LhlNCeosfaJs4L5BXdB+xGfxDzQ65
+ p2xo/nA3k4eJhWhIejzOmJ1zUcsAl9rDUK312hajRh1UFDIr53yYnpAjcxyDYZqv
+ EcuFrjNZKi7zPsZC/17f48hOEHXC5PcFJrm7dvJa2z3+Vswy7IVljVhxu5CQQwk/
+ aIWDAqQXjXYL9L9y8kGspczucVhthOuDKad1Hopy3E5HpaNhXWOLqglWQihjRviG
+ Llt1DU5RnMRJJUp2JW8Ic+SAgtBpS39xFyJRj+gBrcWopdDWr/leTWY6NEKijTRg
+ SzxmvFr9uRlrAExO+FNafeTslYoStTQPysBwNC0HWa3SV04GU/LBRVko6f/ee5WQ
+ aPjGeRiSqBDZBL5HkJ90UMAXrj+2lv+yW16T9upD0H8gv/GpZZIPoZ9fcanSWMz4
+ 1BloOglzUC+AWe/8j6egcpwDbVMbOq51XxP5BkXp/wc2vzxMF8OEMLm6pu6arAup
+ 8JFtFwrS7Cn85iWIppWxNiuSptpBnYdCd+e51uKjigvA+KGyarnPyJOOHynLVwpg
+ hofK8hw0EzDgkQ2ysh9rwqvKtMJdXr9Vi4LGlacnTvO3modvk2B6zv4AsSsR88gP
+ HMTM+Y6J8pJVs8OkY8S/utlOXKrTv3Y1+PRueVWtyVggfvOaXy2UKkAp8e6zBZ6V
+ 5D0BheSOW99ImH63c0AXQ8JV6j1TAgMBAAGjUzBRMB0GA1UdDgQWBBQlK1yjMe+/
+ 2592Ei6EiNHBMnzMMjAfBgNVHSMEGDAWgBQlK1yjMe+/2592Ei6EiNHBMnzMMjAP
+ BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IEAQBYie/7NeBW6jzXhL73
+ qTfubvtpYkNSCSYj5OvunG5sCzHEpWv31yEWbhRxEoLlh4rZxGtsn7hqsa6D4u6U
+ /OXydn8NNPIJH+bOLkn2QLz9Rn8N3YLTAnbjtYIIPDSy2VXMnJAP99eBH/+p+V0V
+ ZIxgSVBNljs34DJsLzOaiDz5js8z/ZPuJbiNjmUOpPxFj2TS7zuVWvpmrei8yGLC
+ PPxe4+LzIRTSgOJAdfyVzgBBD4vjFyPyNi6z2e5t0PrZ2jMJIXtjJQ98CMDEmn+m
+ EYrB3RoSTIGAv1Y3MZfkcOY+SzkqEvb8ojqODX+6axso3Vw1ylVQnGhmOesSVV7Z
+ Fnf2AtaRdjOJD3rhsZw80fjv/PW8NKoS1CdDiylJ0t1GQycSTOs7aCZx0aVc9iDY
+ OAKZU6rBWbWBQx9Nddsll/oeTkRhd3tW3lZH6r8tXweDERQffrHpAv6GiAnqmQKQ
+ s5t8cp8iB7mkCH8YmONdaoR+e5jGwEAVgax1BDedt1Ryz85gG6udAN2xHy9NAxPH
+ z0tRSpcvBztkw5jTSUxT1cVyYt+fDQpB8LX085Vg07bniCZ3oZmq0QO0M3mGrrva
+ FX9VnsakfTJ7lMlaEE7qMfE58S5sLkbXfWG649MFs6lK0e3vkU81iy+DiAA8wA7D
+ t/pswj0DLAQHdrNNvpRTMrl4edHAZawQFMDuTO4EFMYygcYu7s/Q4RMZaoknYbWk
+ 57JMXg5iC4/GcwpMZ33zA/zIuf6TMXAS2p9yjCQOaPhiwWVCa4awtCZl4iVI5Q78
+ yxWN6mLmqH/zHiIBf4rtcwYmSzLyg8rz1FRjBR50BpC3Vt/F80rIe46QgBkyxwT3
+ FhtOJkGAyw6yko0JinA/14KmeJnpf3g0YZig+jhG1omhigms6U18KYdeVy6N/5wf
+ 35ut0cGvXE+Ii4XKRZuVx0UxszaS3aBxLvsQBOOKEBRJljCHimWGPqGYECgvb7BK
+ 20UYkYmxX/l/hYjlmE9/wI7Wozd3ho2PcPfI5kSBHvo8qVg/VouLAq1cxvHPWjz8
+ FOOgukZKnLRnVHz1wqH0HxoQKrW4iGZINHDBVh6R1zgEBWAm1X3xNQ6Sww+xIoUz
+ lYoDi58waKHs6ph82qoPfRtielxdZGLz7JhijQqWG+QYB45d55GG8FC15byH0PTx
+ JOlCjbDbHKShYdcB/UK7nr7fNTWgjsaF7gaLy0GOZS4zDE6/TtDNLC6zrwipcYOm
+ dqd6UrgdkMHccm7qCJpBdD09cTH8sJIgGSEC3YuHvqJ1/bUMaXAF5em2cQBcH+Ng
+ q98r/+7CUPADtb/H+OjIWhW2vLGISMbr7xgWqkETsrh+XZI3QOuz2/n38PZBcwhm
+ O5R7
+ -----END CERTIFICATE-----
+ CERT
+ end
+
+ key do
+ <<~KEY
+ -----BEGIN PRIVATE KEY-----
+ MIISQwIBADANBgkqhkiG9w0BAQEFAASCEi0wghIpAgEAAoIEAQC5qEZ5QBj+nPYQ
+ jpbOBwRWIsNJVPgB54ADkjYSfL6kbPyeQsgAP2vU8zWAZ1lIyiV3M5qa7KZ4oK4u
+ in7O3rwho2XoWaaf1Z6ifpNeVl8Favyn/IeVJp+jchtlVyDAEaX0GozOfo5X+xOA
+ QE7twUNSlB8+6YIqxTQf28zB7ks/2w2qrJvXO3cSgQyB74tTUn/25hwATNlEzSBR
+ dLzoNeK7ZInayLAvxwR5krIm+yjH0EGsI7XZQMLjZOwL95FrhfBLYODwPam5lAzP
+ B6paeY+oGGkNwGhzECqmHLnXMSlY6lpeUs1vOCjVcE13v5jb+nIwLaBWvpF4fnsk
+ gwI5+hiBcfsRuByKH+x5pW7ofCnqAOgkq8m1ErqRIvN8SG54ySlA/+RoPI+G/1/x
+ /AdQtdQxL5X80ZeUjpLGTGy3kPVEQ8feP8Ny3rSklsPtnIMk6fRWgiw2ba2jt500
+ F+FuntCj3PWDZfQ+LBBswuLpQCoB124RobXwFCCfqSd18+S8PfGJQ4gDwc4K17lm
+ /WJq/X3mUDmxJLhEIvpZUxi2App7b3KqdCMthOUxUFoaIZiWtbK3h0A10c/Qr29B
+ I3soKxD30dw/DylR42dTGZUX9fdEkPOulVaTXmApnGkvHRomQ2VSJQq8wccceXvt
+ e/ZV2duehDk7032LhlNCeosfaJs4L5BXdB+xGfxDzQ65p2xo/nA3k4eJhWhIejzO
+ mJ1zUcsAl9rDUK312hajRh1UFDIr53yYnpAjcxyDYZqvEcuFrjNZKi7zPsZC/17f
+ 48hOEHXC5PcFJrm7dvJa2z3+Vswy7IVljVhxu5CQQwk/aIWDAqQXjXYL9L9y8kGs
+ pczucVhthOuDKad1Hopy3E5HpaNhXWOLqglWQihjRviGLlt1DU5RnMRJJUp2JW8I
+ c+SAgtBpS39xFyJRj+gBrcWopdDWr/leTWY6NEKijTRgSzxmvFr9uRlrAExO+FNa
+ feTslYoStTQPysBwNC0HWa3SV04GU/LBRVko6f/ee5WQaPjGeRiSqBDZBL5HkJ90
+ UMAXrj+2lv+yW16T9upD0H8gv/GpZZIPoZ9fcanSWMz41BloOglzUC+AWe/8j6eg
+ cpwDbVMbOq51XxP5BkXp/wc2vzxMF8OEMLm6pu6arAup8JFtFwrS7Cn85iWIppWx
+ NiuSptpBnYdCd+e51uKjigvA+KGyarnPyJOOHynLVwpghofK8hw0EzDgkQ2ysh9r
+ wqvKtMJdXr9Vi4LGlacnTvO3modvk2B6zv4AsSsR88gPHMTM+Y6J8pJVs8OkY8S/
+ utlOXKrTv3Y1+PRueVWtyVggfvOaXy2UKkAp8e6zBZ6V5D0BheSOW99ImH63c0AX
+ Q8JV6j1TAgMBAAECggQAOlfCRco50JGc1hkpFPepijQEcKAOC/MnDHg/G9Itytgh
+ Ds7nsQQ9K79+OarAqRo1ad9Cn5rsuY2tDx0gunvOXTfPB5Rcw2/LGT9zqjq0Q6ya
+ V2QJa3qmwiNSrqcRuKoTH8HUK/QjYUyalTwgUaDhOisoIooZCL3OIpDdKLhs11VM
+ Vy1FD/807RC20IJpozaS1hD8DbAYuwFHPbHUx5hfdwoiNCnLDEibhGTwLUXSS/CL
+ IsBaHjq2w+TsNNqIzWRa3iVEqtqF4ra+y7SZ+TKoTWfWY6bqa/ZRoL/4OsLNPo7u
+ 9SNKQcBBPMm83nvMWpy6k59S+s+KQXZl1lSBN5z7ZHpgLvJPraxYkOXHE7IpLcs5
+ KIT/rzKChKeaIp1UcgqtNyrzKTqW1BKeoRnVZqytUQOmO7vVya6AO2a653jbSqeO
+ QK6DCi8oT2y9h4cew1PuH91qbXRME93Yvg0fH7cy07vVP4Sjm4IXa0ZXLnumd8uu
+ YEYUOazpj6MFrpCFeg5xP/SD4sJdsJSYQ+AutHaSwPTHHH7wlSD00WtGobPxvgaI
+ 3z397AkOSU/58KpMHFhfIEOVjxQvHWJ0MOEoi7f07hv5/asTDhPLXZb1foEiQl7W
+ 5S8y9L68s3beqxqXJB0b0xOm6yhuHOmkYz4IbHQ5Cvh8T+unUVhWA9ckrysdVCs9
+ Kcgs2knAuNpSXGCoDW0zGqXRQg11WaHJ2S0woLyrDfhk14tBwhojZblwN2d8nqsR
+ 3JxM5Dcc5tS722ousXqxiF9DuSA0ekwvp4mljwkw/9mJYpbk1568aE4aavjMZnfb
+ r0RGGwXhbIHG+41j1izxKIS0au8H8BsqEJbJubWxHAVFODdVlAckuRXV4ZzL9Nro
+ MPrJYdwTh8dVcFVtAZQk0cSlWmg7UqbsCZqZ5Kxk4HJhK3xbzF/cNPnY7zL2l3mo
+ 7qYONaRKRdelWZqcB9z+ZuGVMUfMxRhaN9InubRlpqoOTXK22GbmhcIApsXi38GU
+ Z3cgrBrGhG42Tqpp3Ub+goGPw8cnQM9+OItxm0hcL5BJOeC63uqavVemLhs9JM2g
+ 7pkxRPeTagdulHRWEFVTtpt1AN1Am9fivLSEXa6Oz5Fab4b36qOJx9wdCFYC0nh9
+ v/BEBJmlsxuVA+gL0e4tYcxMt67AMdgMyhKzT5A76Jxp3AcJ9QoHZODHkfgIcvAo
+ sCPkBcBNiRZ4EJyrB27fSCxSqqfIGo+ZttZ/K3+g412+2ALfA+TM4LpCmLN441Rb
+ XPa+Gz0ZAroXa+RVO3M4Jr9aJeDRKMSty5wIXavA43L372A+6WuwGKOVqiP1svzV
+ Bs6rhoKhoPsxjIPwFJluH9XMKgBhvWFdf4lLtrGDaQKCAgEA41NZ0VeOW+2D13w2
+ SUF2oq1pbZcloExPN1GKqBf61l/VzmJxrNiEHXm7oQlnX7f6KI9FlpC+Po3U59Wo
+ OhTe6t7eF+e3vvUObBssrbe6dkiwN7deJxq6W4bdddjH1MLBEpNu4qswgC8v17GA
+ hAG001DfYnphicZiRBayP3mgNM1xgnwW4YoyCL7+rBKYnE4HEfhNcgJxDiKBsx2y
+ sR4ARe8RORqaH3AkJh/M7IcsRdrtTEqovaaWGiiF5XRx0xUEj2MtnYaq4j0Cp2jl
+ vPVhZu63kxFmFZbz4G0qmuCp3KzH0JMSWMqM4zFV6ZLi9g5F/6mWCV6RJ2aK9hnD
+ JybaqN1tnriwBx2k1nclfMjTAGunfg8gFT+V9Zwqb9kSOmIaQonbKj9/Zu4OkiWh
+ QGJQKdQ7L0PBb82XyPEaltxrKJRf3rxc2xVjstcaSw75EukRP95jFV0IzYRbgzYX
+ NC/0eojriqR4K3JxlKTAYJTw+0WciCWFqnxD54w77SetUkbnV5kMmc8kDLyBli4a
+ Gtwu0tO7PR9M37hW2/ND1U1PWpV1II5aQNtRf8P/ZMA1A6lFa9R8AyxbCz7om5FH
+ vYjYsW8D+pGfPpFsXlye7kwG7dNx8HrENhUu+j34PqKVpdyNOxzuYOo8PQQDhOmf
+ +DDDqqQA8D4gcifPj1I4wsM9tocCggIBANETZm7i5EDnInSsfj7vVJV4DfxD245e
+ s1ZlqRCd/Jpgc3RbmXdPFTF8N12Q8ls4bXPDKiTiy1Oy4OeZ5+6lgkpRCz2Ptgtj
+ Q1+is9VhPLoXaqRHbZ2Y7F7auN9KcthFt6WYurDNiqXybmZ6X7EDM8uDLFsL+2nk
+ QswBNqJrfTZyvPe4ZUy+WkS3ma2Zo9xujTwV0SHXbzwW/o8pIMWDLR9hxMVUYuXG
+ uEYORT+n0TVDFmUyHxjyR5j1tQ8jyLigcMaR1ysjzMyM2LWY/VZXuVH1OdUr7xYn
+ Kq4q0BtGAWNzOzO8jJjhtPmacVJA1wgI53nik42nE7an4vcinFDJzwqFFdK0abWv
+ XMZ3E36XT/+QY8GZ9Y5fEBOegfS1DyQHoSgqbJONS/cfRe8NSTc1+e7JfeRNUtYD
+ SEk6sham0RXnTHLCOhP59DxX5RWY9oNgIBSXRa5ZS9AOx0PIMx0ZaSBBh2vsAe9j
+ rnOkI8k/X1aqD1wo+t2wR7xFG7jPnnzqNOqbT/FSop6NCZ8eEPGWJi9Sc5Yks85J
+ N6XJwvFdLfY+VvQjqgqbh13mdcosA0JVAzqnEZI6wj02KSqAvm3Bfmfp5qnmE8LY
+ TEEBhYzXcwEkGoQ5Em6/+zhXnoFACdkSgB5yw0UmQDCNE3I94WQ+qQI/7PnoSqHg
+ KTRufnjHrGnVAoICAQDdfcYCyeukOD0AhT8ji0w7XvldVSrND+0TOjj+ZTb7Dy90
+ Qsj9n4zCZ2zgkBgP1GNCh65G8MrcijcKmEusI8+7SuFcq2KGBaFCxgt3S4+7VkGU
+ V+697TXsnfBDta+m5wdVwR8GbcP48YENCR7t//ee+apd+l307r2qF+8fF7N4H0Bc
+ 4ektYgg0K1xablgR25jZ8nQLBMQBALAcxG/qUQ/1E+VVHU1UGmCuYMe7Ik2J1rDl
+ Z80X1CtmW1ty4U1SXKUvzHOSi7cObmGamgNWZEO+FhP5kLdFi+odHmCnvQTkRdj+
+ qX3z048IgnZx+bN4CRo865CLmn+VwzzcYueZyyq749u+Dbc9h62nZTm6ZrXoL/xn
+ P/eDnIvRXpKengM7rYBmmolXlbzdnk/GKDIAWIpA50+vUrYz6D7fA8Rjf2pNhJwQ
+ mrlioWmdxCYTQgh/W2V6NIWYOCiujirYIqjjKWJszeGqGWwY8Q4nxYrHz/co7H+C
+ zAR7w04qWqG9Ba7DfuBDopT7fC9k1XrxyAOZbjWVJ8XE3S16wdKnxlOujgAmg382
+ 9FyN2uOCuIasNPaylYhVcxhNwzcGMwpTIW+kBaUU5NUcnCxruye6nUYhayRJL39R
+ z1xEUcmO+zhYVvO2Qrm9Aghll3SQAswnAbbjDShoqBld+zqD37RFsdgqNC96GwKC
+ AgEAr615eNs1qEOO9DKssf0wOZfzSHFMX0i7sHEjqk7WHnHFEZSWU2YkDLyvWPOe
+ cX/smET5eJ0I9H9t862i8SgpXoDSzRugf9kcl5ODQFzARi2+8eMC/FWu59UpWpaY
+ AZozQfYfiMhtJBudIIbbOUXTk8HY13gt/UBL0FeErN1dDQ9EMXLDy8R23R7ZBsH+
+ qg5Kpp4+aA057mfz5h9M5infFGt2h8jsgN6FoHgFQAOnCvYgL0/6SV/rQV/Uj7Al
+ zN0jZfbNsfYW9Bm1ToIK/S4hDfjca37LGvY2KrrWutQL/qCoskRQb3XYN5PKfK73
+ AE1bE1OLYI9vRR+02qw+ZLPuQIyrVa061etQLYOI4eoK0ldlOxw+9S5zt8iMsi4h
+ VskCZVmgeitUFYY1oTSsvLOiGz87hUZjwGhpqP6k/duV/K2p0xPY8UgqLTo9x/QL
+ z0BKNIMXjfSCe4SvcwkZye28I9psDAb3aUt9HrZhS4zwc0XaOjpE8VpaLJx1Osla
+ BuRVKnzuo3woIMmpuAXvftAHreO+M/8LBt8G30u1flIpeKvRLLt6+gbNq90mRIbP
+ BkGgwPv5C8JLzFtiI9CiMl9P88jahRBKsoJFMKoyqbGvdNn9XfUGxACU+zbEfR5u
+ J/Qfq3YLFmOZtDIWkPvmE/GC2d0VJrhFXdeZR/FAXASLnzECggIAGcuDDxovnC5W
+ fxNR3xAHx7iLlxmAvYMJ8+zul6kPhymyJ5ib36RyhbdV+53sKssC9r2xesOivI1D
+ y4gUafqzEhZfNf3cvedCh5CVqWbAIjasYSSa/ZCqbZW7/wA1Zs4pG8xFXZKdLybo
+ jwDzidZ+NokW7mXZL9TTFqtOm3ShhfGZOMdx8TtAnn2iiemYTHjo3xuRROU3M0xa
+ ADbzpJl6/+pYNOt4VxghHNqcUFdQwqnnnueHCVRwCq3rtxsXPFULUZKF6KhZlu99
+ nmO3zVn85Os7lGa383RZHcu43LwxuXsAMHgay1Def83kwnKda7lKel/eWw7Cdj2v
+ uVr3V27aM1ZKOWYivm3aodlYLrhwcnqczkzAU1uP5PHZhJrUY3okZb/cPFShi4ok
+ ExpntdKzXVXg2zDdB8GyeqZ5ba6zpkoFxBBwMFWgd+PajLFvN7lHEC9BrFg817hT
+ vjPpz7M6hZmLLCkrIPA8lgM2r3AJF0Uu2IgshwTMP4TmLwMPDkDfctp3qWR4EA92
+ DH76UVaDfcfE0WSCh1Znk/2DPxVv8yYVK0elqpM+JiS0xsLvzksTk39rbv7qdy6f
+ 1EoJJFfrfqvrowyGG0f946bb5k2nsNFjKwHexQMpYx35pGbSp1CCOHqzLIS+LjOb
+ c5RerXbZTDEafdHsyGlkhu+nOjYvyGM=
+ -----END PRIVATE KEY-----
+ KEY
+ end
+ end
+
trait :instance_serverless do
wildcard { true }
scope { :instance }
diff --git a/spec/factories/project_alerting_settings.rb b/spec/factories/project_alerting_settings.rb
index 2c8ca7c70a8..ef0beb6b98a 100644
--- a/spec/factories/project_alerting_settings.rb
+++ b/spec/factories/project_alerting_settings.rb
@@ -3,6 +3,24 @@
FactoryBot.define do
factory :project_alerting_setting, class: 'Alerting::ProjectAlertingSetting' do
project
- token { 'access_token_123' }
+ token { SecureRandom.hex }
+
+ # Remove in next required stop after %16.4
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/338838
+ transient do
+ sync_http_integrations { false }
+ end
+
+ trait :with_http_integration do
+ sync_http_integrations { true }
+ end
+
+ # for simplicity, let factory exclude the AlertManagement::HttpIntegration
+ # created in after_commit callback on model
+ after(:create) do |setting, evaluator|
+ next if evaluator.sync_http_integrations
+
+ setting.project.alert_management_http_integrations.last!.destroy!
+ end
end
end
diff --git a/spec/factories/project_authorizations.rb b/spec/factories/project_authorizations.rb
index 1726da55c99..4e4330b37a6 100644
--- a/spec/factories/project_authorizations.rb
+++ b/spec/factories/project_authorizations.rb
@@ -7,7 +7,9 @@ FactoryBot.define do
access_level { Gitlab::Access::REPORTER }
end
- trait :owner do
- access_level { Gitlab::Access::OWNER }
- end
+ trait(:guest) { access_level { Gitlab::Access::GUEST } }
+ trait(:reporter) { access_level { Gitlab::Access::REPORTER } }
+ trait(:developer) { access_level { Gitlab::Access::DEVELOPER } }
+ trait(:maintainer) { access_level { Gitlab::Access::MAINTAINER } }
+ trait(:owner) { access_level { Gitlab::Access::OWNER } }
end
diff --git a/spec/factories/project_metrics_settings.rb b/spec/factories/project_metrics_settings.rb
deleted file mode 100644
index b5c0fd88a6c..00000000000
--- a/spec/factories/project_metrics_settings.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :project_metrics_setting, class: 'ProjectMetricsSetting' do
- project
- external_dashboard_url { 'https://grafana.com' }
- end
-end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 0111083298c..443bca6030c 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -535,7 +535,7 @@ FactoryBot.define do
factory :project_with_design, parent: :project do
after(:create) do |project|
issue = create(:issue, project: project)
- create(:design, project: project, issue: issue)
+ create(:design, :with_file, project: project, issue: issue)
end
end
diff --git a/spec/factories/self_managed_prometheus_alert_event.rb b/spec/factories/self_managed_prometheus_alert_event.rb
deleted file mode 100644
index 3a48aba5f54..00000000000
--- a/spec/factories/self_managed_prometheus_alert_event.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :self_managed_prometheus_alert_event do
- project
- sequence(:payload_key) { |n| "hash payload key #{n}" }
- status { SelfManagedPrometheusAlertEvent.status_value_for(:firing) }
- title { 'alert' }
- query_expression { 'vector(2)' }
- started_at { Time.now }
- end
-end
diff --git a/spec/factories/service_desk/custom_email_verification.rb b/spec/factories/service_desk/custom_email_verification.rb
index a3b72da2e9e..4c3322169fa 100644
--- a/spec/factories/service_desk/custom_email_verification.rb
+++ b/spec/factories/service_desk/custom_email_verification.rb
@@ -11,5 +11,10 @@ FactoryBot.define do
trait :overdue do
triggered_at { (ServiceDesk::CustomEmailVerification::TIMEFRAME + 1).minutes.ago }
end
+
+ trait :finished do
+ state { 'finished' }
+ token { nil }
+ end
end
end
diff --git a/spec/factories/usage_data.rb b/spec/factories/usage_data.rb
index 0e944b90d0c..1084891b07f 100644
--- a/spec/factories/usage_data.rb
+++ b/spec/factories/usage_data.rb
@@ -35,8 +35,8 @@ FactoryBot.define do
create(:custom_issue_tracker_integration, project: projects[2], active: true)
create(:project_error_tracking_setting, project: projects[0])
create(:project_error_tracking_setting, project: projects[1], enabled: false)
- alert_bot_issues = create_list(:incident, 2, project: projects[0], author: User.alert_bot)
- create_list(:incident, 2, project: projects[1], author: User.alert_bot)
+ alert_bot_issues = create_list(:incident, 2, project: projects[0], author: Users::Internal.alert_bot)
+ create_list(:incident, 2, project: projects[1], author: Users::Internal.alert_bot)
issues = create_list(:issue, 4, project: projects[0])
create_list(:prometheus_alert, 2, project: projects[0])
create(:prometheus_alert, project: projects[1])
@@ -62,7 +62,6 @@ FactoryBot.define do
# Alert Issues
create(:alert_management_alert, issue: issues[0], project: projects[0])
create(:alert_management_alert, issue: alert_bot_issues[0], project: projects[0])
- create(:self_managed_prometheus_alert_event, related_issues: [issues[1]], project: projects[0])
# Kubernetes agents
create(:cluster_agent, project: projects[0])
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index 67c857165fc..d61d5cc2d78 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -126,6 +126,10 @@ FactoryBot.define do
end
end
+ trait :no_super_sidebar do
+ use_new_navigation { false }
+ end
+
trait :two_factor_via_webauthn do
transient { registrations_count { 5 } }
diff --git a/spec/factories/users/group_visit.rb b/spec/factories/users/group_visit.rb
new file mode 100644
index 00000000000..a98ee61332a
--- /dev/null
+++ b/spec/factories/users/group_visit.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :group_visit, class: 'Users::GroupVisit' do
+ transient { target_user { association(:user) } }
+ transient { target_group { association(:group) } }
+
+ user_id { target_user.id }
+ entity_id { target_group.id }
+ visited_at { Time.now }
+ end
+end
diff --git a/spec/factories/users/project_visit.rb b/spec/factories/users/project_visit.rb
new file mode 100644
index 00000000000..40ead720061
--- /dev/null
+++ b/spec/factories/users/project_visit.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_visit, class: 'Users::ProjectVisit' do
+ transient { target_user { association(:user) } }
+ transient { target_project { association(:project) } }
+
+ user_id { target_user.id }
+ entity_id { target_project.id }
+ visited_at { Time.now }
+ end
+end
diff --git a/spec/factories/work_items.rb b/spec/factories/work_items.rb
index 4a2186f2fcf..1827f2a590b 100644
--- a/spec/factories/work_items.rb
+++ b/spec/factories/work_items.rb
@@ -26,6 +26,18 @@ FactoryBot.define do
closed_at { Time.now }
end
+ trait :group_level do
+ project { nil }
+ association :namespace, factory: :group
+ association :author, factory: :user
+ end
+
+ trait :user_namespace_level do
+ project { nil }
+ association :namespace, factory: :user_namespace
+ association :author, factory: :user
+ end
+
trait :issue do
association :work_item_type, :default, :issue
end
diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb
index f934736ced9..f1df5c2d6f0 100644
--- a/spec/features/abuse_report_spec.rb
+++ b/spec/features/abuse_report_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
- let_it_be(:abusive_user) { create(:user) }
+ let_it_be(:abusive_user) { create(:user, :no_super_sidebar) }
- let_it_be(:reporter1) { create(:user) }
+ let_it_be(:reporter1) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be(:issue) { create(:issue, project: project, author: abusive_user) }
@@ -57,7 +57,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
describe 'when user_profile_overflow_menu FF turned on' do
context 'when reporting a user profile for abuse' do
- let_it_be(:reporter2) { create(:user) }
+ let_it_be(:reporter2) { create(:user, :no_super_sidebar) }
before do
visit user_path(abusive_user)
@@ -108,7 +108,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
describe 'when user_profile_overflow_menu FF turned off' do
context 'when reporting a user profile for abuse' do
- let_it_be(:reporter2) { create(:user) }
+ let_it_be(:reporter2) { create(:user, :no_super_sidebar) }
before do
stub_feature_flags(user_profile_overflow_menu_vue: false)
diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb
index 18bc851558d..973988560b3 100644
--- a/spec/features/admin/admin_abuse_reports_spec.rb
+++ b/spec/features/admin/admin_abuse_reports_spec.rb
@@ -11,291 +11,195 @@ RSpec.describe "Admin::AbuseReports", :js, feature_category: :insider_threat do
let_it_be(:closed_report) { create(:abuse_report, :closed, user: user, category: 'spam') }
describe 'as an admin' do
+ include FilteredSearchHelpers
+
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
- end
-
- context 'when abuse_reports_list feature flag is enabled' do
- include FilteredSearchHelpers
-
- before do
- visit admin_abuse_reports_path
- end
-
- let(:abuse_report_row_selector) { '[data-testid="abuse-report-row"]' }
-
- it 'only includes open reports by default' do
- expect_displayed_reports_count(2)
-
- expect_report_shown(open_report, open_report2)
-
- within '[data-testid="abuse-reports-filtered-search-bar"]' do
- expect(page).to have_content 'Status = Open'
- end
- end
-
- it 'can be filtered by status, user, reporter, and category', :aggregate_failures do
- # filter by status
- filter %w[Status Closed]
- expect_displayed_reports_count(1)
- expect_report_shown(closed_report)
- expect_report_not_shown(open_report, open_report2)
-
- filter %w[Status Open]
- expect_displayed_reports_count(2)
- expect_report_shown(open_report, open_report2)
- expect_report_not_shown(closed_report)
-
- # filter by user
- filter(['User', open_report2.user.username])
- expect_displayed_reports_count(1)
- expect_report_shown(open_report2)
- expect_report_not_shown(open_report, closed_report)
+ visit admin_abuse_reports_path
+ end
- # filter by reporter
- filter(['Reporter', open_report.reporter.username])
+ let(:abuse_report_row_selector) { '[data-testid="abuse-report-row"]' }
- expect_displayed_reports_count(1)
- expect_report_shown(open_report)
- expect_report_not_shown(open_report2, closed_report)
+ it 'only includes open reports by default' do
+ expect_displayed_reports_count(2)
- # filter by category
- filter(['Category', open_report2.category])
+ expect_report_shown(open_report, open_report2)
- expect_displayed_reports_count(1)
- expect_report_shown(open_report2)
- expect_report_not_shown(open_report, closed_report)
+ within_testid('abuse-reports-filtered-search-bar') do
+ expect(page).to have_content 'Status = Open'
end
+ end
- it 'can be sorted by created_at and updated_at in desc and asc order', :aggregate_failures do
- sort_by 'Created date'
- # created_at desc
- expect(report_rows[0].text).to include(report_text(open_report2))
- expect(report_rows[1].text).to include(report_text(open_report))
-
- # created_at asc
- toggle_sort_direction
-
- expect(report_rows[0].text).to include(report_text(open_report))
- expect(report_rows[1].text).to include(report_text(open_report2))
+ it 'can be filtered by status, user, reporter, and category', :aggregate_failures do
+ # filter by status
+ filter %w[Status Closed]
+ expect_displayed_reports_count(1)
+ expect_report_shown(closed_report)
+ expect_report_not_shown(open_report, open_report2)
- # updated_at asc
- sort_by 'Updated date'
+ filter %w[Status Open]
+ expect_displayed_reports_count(2)
+ expect_report_shown(open_report, open_report2)
+ expect_report_not_shown(closed_report)
- expect(report_rows[0].text).to include(report_text(open_report2))
- expect(report_rows[1].text).to include(report_text(open_report))
+ # filter by user
+ filter(['User', open_report2.user.username])
- # updated_at desc
- toggle_sort_direction
+ expect_displayed_reports_count(1)
+ expect_report_shown(open_report2)
+ expect_report_not_shown(open_report, closed_report)
- expect(report_rows[0].text).to include(report_text(open_report))
- expect(report_rows[1].text).to include(report_text(open_report2))
- end
+ # filter by reporter
+ filter(['Reporter', open_report.reporter.username])
- context 'when multiple reports for the same user are created' do
- let_it_be(:open_report3) { create(:abuse_report, category: 'spam', user: user) }
- let_it_be(:closed_report2) { create(:abuse_report, :closed, user: user, category: 'spam') }
+ expect_displayed_reports_count(1)
+ expect_report_shown(open_report)
+ expect_report_not_shown(open_report2, closed_report)
- it 'aggregates open reports by user & category', :aggregate_failures do
- expect_displayed_reports_count(2)
+ # filter by category
+ filter(['Category', open_report2.category])
- expect_aggregated_report_shown(open_report, 2)
- expect_report_shown(open_report2)
- end
+ expect_displayed_reports_count(1)
+ expect_report_shown(open_report2)
+ expect_report_not_shown(open_report, closed_report)
+ end
- it 'can sort aggregated reports by number_of_reports in desc order only', :aggregate_failures do
- sort_by 'Number of Reports'
+ it 'can be sorted by created_at and updated_at in desc and asc order', :aggregate_failures do
+ sort_by 'Created date'
+ # created_at desc
+ expect(report_rows[0].text).to include(report_text(open_report2))
+ expect(report_rows[1].text).to include(report_text(open_report))
- expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
- expect(report_rows[1].text).to include(report_text(open_report2))
+ # created_at asc
+ toggle_sort_direction
- toggle_sort_direction
+ expect(report_rows[0].text).to include(report_text(open_report))
+ expect(report_rows[1].text).to include(report_text(open_report2))
- expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
- expect(report_rows[1].text).to include(report_text(open_report2))
- end
+ # updated_at asc
+ sort_by 'Updated date'
- it 'can sort aggregated reports by created_at and updated_at in desc and asc order', :aggregate_failures do
- # number_of_reports desc (default)
- expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
- expect(report_rows[1].text).to include(report_text(open_report2))
+ expect(report_rows[0].text).to include(report_text(open_report2))
+ expect(report_rows[1].text).to include(report_text(open_report))
- # created_at desc
- sort_by 'Created date'
+ # updated_at desc
+ toggle_sort_direction
- expect(report_rows[0].text).to include(report_text(open_report2))
- expect(report_rows[1].text).to include(aggregated_report_text(open_report, 2))
-
- # created_at asc
- toggle_sort_direction
+ expect(report_rows[0].text).to include(report_text(open_report))
+ expect(report_rows[1].text).to include(report_text(open_report2))
+ end
- expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
- expect(report_rows[1].text).to include(report_text(open_report2))
+ context 'when multiple reports for the same user are created' do
+ let_it_be(:open_report3) { create(:abuse_report, category: 'spam', user: user) }
+ let_it_be(:closed_report2) { create(:abuse_report, :closed, user: user, category: 'spam') }
- sort_by 'Updated date'
+ it 'aggregates open reports by user & category', :aggregate_failures do
+ expect_displayed_reports_count(2)
- # updated_at asc
- expect(report_rows[0].text).to include(report_text(open_report2))
- expect(report_rows[1].text).to include(aggregated_report_text(open_report, 2))
+ expect_aggregated_report_shown(open_report, 2)
+ expect_report_shown(open_report2)
+ end
- # updated_at desc
- toggle_sort_direction
+ it 'can sort aggregated reports by number_of_reports in desc order only', :aggregate_failures do
+ sort_by 'Number of Reports'
- expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
- expect(report_rows[1].text).to include(report_text(open_report2))
- end
+ expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
+ expect(report_rows[1].text).to include(report_text(open_report2))
- it 'does not aggregate closed reports', :aggregate_failures do
- filter %w[Status Closed]
+ toggle_sort_direction
- expect_displayed_reports_count(2)
- expect_report_shown(closed_report, closed_report2)
- end
+ expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
+ expect(report_rows[1].text).to include(report_text(open_report2))
end
- def report_rows
- page.all(abuse_report_row_selector)
- end
+ it 'can sort aggregated reports by created_at and updated_at in desc and asc order', :aggregate_failures do
+ # number_of_reports desc (default)
+ expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
+ expect(report_rows[1].text).to include(report_text(open_report2))
- def report_text(report)
- "#{report.user.name} reported for #{report.category} by #{report.reporter.name}"
- end
+ # created_at desc
+ sort_by 'Created date'
- def aggregated_report_text(report, count)
- "#{report.user.name} reported for #{report.category} by #{count} users"
- end
+ expect(report_rows[0].text).to include(report_text(open_report2))
+ expect(report_rows[1].text).to include(aggregated_report_text(open_report, 2))
- def expect_report_shown(*reports)
- reports.each do |r|
- expect(page).to have_content(report_text(r))
- end
- end
+ # created_at asc
+ toggle_sort_direction
- def expect_report_not_shown(*reports)
- reports.each do |r|
- expect(page).not_to have_content(report_text(r))
- end
- end
+ expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
+ expect(report_rows[1].text).to include(report_text(open_report2))
- def expect_aggregated_report_shown(*reports, count)
- reports.each do |r|
- expect(page).to have_content(aggregated_report_text(r, count))
- end
- end
+ sort_by 'Updated date'
- def expect_displayed_reports_count(count)
- expect(page).to have_css(abuse_report_row_selector, count: count)
- end
+ # updated_at asc
+ expect(report_rows[0].text).to include(report_text(open_report2))
+ expect(report_rows[1].text).to include(aggregated_report_text(open_report, 2))
- def filter(tokens)
- # remove all existing filters first
- page.find_all('.gl-token-close').each(&:click)
+ # updated_at desc
+ toggle_sort_direction
- select_tokens(*tokens, submit: true, input_text: 'Filter reports')
+ expect(report_rows[0].text).to include(aggregated_report_text(open_report, 2))
+ expect(report_rows[1].text).to include(report_text(open_report2))
end
- def sort_by(sort)
- page.within('.vue-filtered-search-bar-container .sort-dropdown-container') do
- page.find('.gl-dropdown-toggle').click
+ it 'does not aggregate closed reports', :aggregate_failures do
+ filter %w[Status Closed]
- page.within('.dropdown-menu') do
- click_button sort
- wait_for_requests
- end
- end
+ expect_displayed_reports_count(2)
+ expect_report_shown(closed_report, closed_report2)
end
end
- context 'when abuse_reports_list feature flag is disabled' do
- before do
- stub_feature_flags(abuse_reports_list: false)
-
- visit admin_abuse_reports_path
- end
+ def report_rows
+ page.all(abuse_report_row_selector)
+ end
- it 'displays all abuse reports', :aggregate_failures do
- expect_report_shown(open_report)
- expect_report_actions_shown(open_report)
+ def report_text(report)
+ "#{report.user.name} reported for #{report.category} by #{report.reporter.name}"
+ end
- expect_report_shown(open_report2)
- expect_report_actions_shown(open_report2)
+ def aggregated_report_text(report, count)
+ "#{report.user.name} reported for #{report.category} by #{count} users"
+ end
- expect_report_shown(closed_report)
- expect_report_actions_shown(closed_report)
+ def expect_report_shown(*reports)
+ reports.each do |r|
+ expect(page).to have_content(report_text(r))
end
+ end
- context 'when an admin has been reported for abuse' do
- let_it_be(:admin_abuse_report) { create(:abuse_report, user: admin) }
-
- it 'displays the abuse report without actions' do
- expect_report_shown(admin_abuse_report)
- expect_report_actions_not_shown(admin_abuse_report)
- end
+ def expect_report_not_shown(*reports)
+ reports.each do |r|
+ expect(page).not_to have_content(report_text(r))
end
+ end
- context 'when multiple users have been reported for abuse' do
- let(:report_count) { AbuseReport.default_per_page + 3 }
-
- before do
- report_count.times do
- create(:abuse_report, user: create(:user))
- end
- end
-
- context 'in the abuse report view', :aggregate_failures do
- it 'adds pagination' do
- visit admin_abuse_reports_path
-
- expect(page).to have_selector('.pagination')
- expect(page).to have_selector('.pagination .js-pagination-page', count: (report_count.to_f / AbuseReport.default_per_page).ceil)
- end
- end
+ def expect_aggregated_report_shown(*reports, count)
+ reports.each do |r|
+ expect(page).to have_content(aggregated_report_text(r, count))
end
+ end
- context 'when filtering reports' do
- it 'can be filtered by reported-user', :aggregate_failures do
- visit admin_abuse_reports_path
-
- page.within '.filter-form' do
- click_button 'User'
- wait_for_requests
-
- page.within '.dropdown-menu-user' do
- click_link user.name
- end
-
- wait_for_requests
- end
+ def expect_displayed_reports_count(count)
+ expect(page).to have_css(abuse_report_row_selector, count: count)
+ end
- expect_report_shown(open_report)
- expect_report_shown(closed_report)
- end
- end
+ def filter(tokens)
+ # remove all existing filters first
+ page.find_all('.gl-token-close').each(&:click)
- def expect_report_shown(report)
- page.within(:table_row, { "User" => report.user.name, "Reported by" => report.reporter.name }) do
- expect(page).to have_content(report.user.name)
- expect(page).to have_content(report.reporter.name)
- expect(page).to have_content(report.message)
- expect(page).to have_link(report.user.name, href: user_path(report.user))
- end
- end
+ select_tokens(*tokens, submit: true, input_text: 'Filter reports')
+ end
- def expect_report_actions_shown(report)
- page.within(:table_row, { "User" => report.user.name, "Reported by" => report.reporter.name }) do
- expect(page).to have_link('Remove user & report')
- expect(page).to have_link('Block user')
- expect(page).to have_link('Remove user')
- end
- end
+ def sort_by(sort)
+ page.within('.vue-filtered-search-bar-container .sort-dropdown-container') do
+ page.find('.gl-dropdown-toggle').click
- def expect_report_actions_not_shown(report)
- page.within(:table_row, { "User" => report.user.name, "Reported by" => report.reporter.name }) do
- expect(page).not_to have_link('Remove user & report')
- expect(page).not_to have_link('Block user')
- expect(page).not_to have_link('Remove user')
+ page.within('.dropdown-menu') do
+ click_button sort
+ wait_for_requests
end
end
end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index b4f64cbfa7b..a5acba1fe4a 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Admin::Hooks', feature_category: :webhooks do
include Spec::Support::Helpers::ModalHelpers
- let_it_be(:user) { create(:admin) }
+ let_it_be(:user) { create(:admin, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/admin/admin_jobs_spec.rb b/spec/features/admin/admin_jobs_spec.rb
index d46b314c144..b305bec6493 100644
--- a/spec/features/admin/admin_jobs_spec.rb
+++ b/spec/features/admin/admin_jobs_spec.rb
@@ -2,9 +2,8 @@
require 'spec_helper'
-RSpec.describe 'Admin Jobs', feature_category: :continuous_integration do
+RSpec.describe 'Admin Jobs', :js, feature_category: :continuous_integration do
before do
- stub_feature_flags(admin_jobs_vue: false)
admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
@@ -23,12 +22,13 @@ RSpec.describe 'Admin Jobs', feature_category: :continuous_integration do
visit admin_jobs_path
- expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'All')
- expect(page).to have_selector('.row-content-block', text: 'All jobs')
- expect(page.all('.build-link').size).to eq(4)
- expect(page).to have_button 'Stop all jobs'
+ wait_for_requests
- click_button 'Stop all jobs'
+ expect(page).to have_selector('[data-testid="jobs-all-tab"]')
+ expect(page.all('[data-testid="jobs-table-row"]').size).to eq(4)
+ expect(page).to have_button 'Cancel all jobs'
+
+ click_button 'Cancel all jobs'
expect(page).to have_button 'Yes, proceed'
expect(page).to have_content 'Are you sure?'
end
@@ -38,73 +38,11 @@ RSpec.describe 'Admin Jobs', feature_category: :continuous_integration do
it 'shows a message' do
visit admin_jobs_path
- expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'All')
- expect(page).to have_content 'No jobs to show'
- expect(page).not_to have_button 'Stop all jobs'
- end
- end
- end
-
- context 'Pending tab' do
- context 'when have pending jobs' do
- it 'shows pending jobs' do
- build1 = create(:ci_build, pipeline: pipeline, status: :pending)
- build2 = create(:ci_build, pipeline: pipeline, status: :running)
- build3 = create(:ci_build, pipeline: pipeline, status: :success)
- build4 = create(:ci_build, pipeline: pipeline, status: :failed)
-
- visit admin_jobs_path(scope: :pending)
-
- expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Pending')
- expect(page.find('.build-link')).to have_content(build1.id)
- expect(page.find('.build-link')).not_to have_content(build2.id)
- expect(page.find('.build-link')).not_to have_content(build3.id)
- expect(page.find('.build-link')).not_to have_content(build4.id)
- expect(page).to have_button 'Stop all jobs'
- end
- end
-
- context 'when have no jobs pending' do
- it 'shows a message' do
- create(:ci_build, pipeline: pipeline, status: :success)
-
- visit admin_jobs_path(scope: :pending)
-
- expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Pending')
- expect(page).to have_content 'No jobs to show'
- expect(page).not_to have_button 'Stop all jobs'
- end
- end
- end
-
- context 'Running tab' do
- context 'when have running jobs' do
- it 'shows running jobs' do
- build1 = create(:ci_build, pipeline: pipeline, status: :running)
- build2 = create(:ci_build, pipeline: pipeline, status: :success)
- build3 = create(:ci_build, pipeline: pipeline, status: :failed)
- build4 = create(:ci_build, pipeline: pipeline, status: :pending)
-
- visit admin_jobs_path(scope: :running)
-
- expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Running')
- expect(page.find('.build-link')).to have_content(build1.id)
- expect(page.find('.build-link')).not_to have_content(build2.id)
- expect(page.find('.build-link')).not_to have_content(build3.id)
- expect(page.find('.build-link')).not_to have_content(build4.id)
- expect(page).to have_button 'Stop all jobs'
- end
- end
-
- context 'when have no jobs running' do
- it 'shows a message' do
- create(:ci_build, pipeline: pipeline, status: :success)
-
- visit admin_jobs_path(scope: :running)
+ wait_for_requests
- expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Running')
- expect(page).to have_content 'No jobs to show'
- expect(page).not_to have_button 'Stop all jobs'
+ expect(page).to have_selector('[data-testid="jobs-all-tab"]')
+ expect(page).to have_selector('[data-testid="jobs-empty-state"]')
+ expect(page).not_to have_button 'Cancel all jobs'
end
end
end
@@ -116,13 +54,19 @@ RSpec.describe 'Admin Jobs', feature_category: :continuous_integration do
build2 = create(:ci_build, pipeline: pipeline, status: :running)
build3 = create(:ci_build, pipeline: pipeline, status: :success)
- visit admin_jobs_path(scope: :finished)
+ visit admin_jobs_path
+
+ wait_for_requests
+
+ find_by_testid('jobs-finished-tab').click
+
+ wait_for_requests
- expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Finished')
- expect(page.find('.build-link')).not_to have_content(build1.id)
- expect(page.find('.build-link')).not_to have_content(build2.id)
- expect(page.find('.build-link')).to have_content(build3.id)
- expect(page).to have_button 'Stop all jobs'
+ expect(page).to have_selector('[data-testid="jobs-finished-tab"]')
+ expect(find_by_testid('job-id-link')).not_to have_content(build1.id)
+ expect(find_by_testid('job-id-link')).not_to have_content(build2.id)
+ expect(find_by_testid('job-id-link')).to have_content(build3.id)
+ expect(page).to have_button 'Cancel all jobs'
end
end
@@ -130,11 +74,17 @@ RSpec.describe 'Admin Jobs', feature_category: :continuous_integration do
it 'shows a message' do
create(:ci_build, pipeline: pipeline, status: :running)
- visit admin_jobs_path(scope: :finished)
+ visit admin_jobs_path
+
+ wait_for_requests
+
+ find_by_testid('jobs-finished-tab').click
+
+ wait_for_requests
- expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Finished')
+ expect(page).to have_selector('[data-testid="jobs-finished-tab"]')
expect(page).to have_content 'No jobs to show'
- expect(page).to have_button 'Stop all jobs'
+ expect(page).to have_button 'Cancel all jobs'
end
end
end
diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb
index a64d3f241f6..5d9106fea02 100644
--- a/spec/features/admin/admin_mode/logout_spec.rb
+++ b/spec/features/admin/admin_mode/logout_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Admin Mode Logout', :js, feature_category: :system_access do
include UserLoginHelper
include Features::TopNavSpecHelpers
- let(:user) { create(:admin) }
+ let(:user) { create(:admin, :no_super_sidebar) }
before do
# TODO: This used to use gitlab_sign_in, instead of sign_in, but that is buggy. See
diff --git a/spec/features/admin/admin_mode/workers_spec.rb b/spec/features/admin/admin_mode/workers_spec.rb
index 124c43eef9d..2a862c750d7 100644
--- a/spec/features/admin/admin_mode/workers_spec.rb
+++ b/spec/features/admin/admin_mode/workers_spec.rb
@@ -6,8 +6,8 @@ require 'spec_helper'
RSpec.describe 'Admin mode for workers', :request_store, feature_category: :system_access do
include Features::AdminUsersHelpers
- let(:user) { create(:user) }
- let(:user_to_delete) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
+ let(:user_to_delete) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
@@ -22,7 +22,7 @@ RSpec.describe 'Admin mode for workers', :request_store, feature_category: :syst
end
context 'as an admin user' do
- let(:user) { create(:admin) }
+ let(:user) { create(:admin, :no_super_sidebar) }
context 'when admin mode disabled' do
it 'cannot delete user', :js do
diff --git a/spec/features/admin/admin_mode_spec.rb b/spec/features/admin/admin_mode_spec.rb
index 65249fa0235..edfa58567ad 100644
--- a/spec/features/admin/admin_mode_spec.rb
+++ b/spec/features/admin/admin_mode_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Admin mode', :js, feature_category: :shared do
include Features::TopNavSpecHelpers
include StubENV
- let(:admin) { create(:admin) }
+ let(:admin) { create(:admin, :no_super_sidebar) }
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index af6ba318ac6..e0f4473c80c 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -54,6 +54,11 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
let(:runner) { instance_runner }
end
+ it_behaves_like 'shows runner details from list' do
+ let(:runner) { instance_runner }
+ let(:runner_page_path) { admin_runner_path(instance_runner) }
+ end
+
it_behaves_like 'pauses, resumes and deletes a runner' do
let(:runner) { instance_runner }
end
@@ -575,6 +580,8 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do
let(:runner_page_path) { admin_runner_path(project_runner) }
end
+ it_behaves_like 'shows locked field'
+
describe 'breadcrumbs' do
it 'contains the current runner id and token' do
page.within '[data-testid="breadcrumb-links"]' do
diff --git a/spec/features/admin/admin_sees_background_migrations_spec.rb b/spec/features/admin/admin_sees_background_migrations_spec.rb
index 7d4d3deb6d8..7423e74bf3a 100644
--- a/spec/features/admin/admin_sees_background_migrations_spec.rb
+++ b/spec/features/admin/admin_sees_background_migrations_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe "Admin > Admin sees background migrations", feature_category: :database do
include ListboxHelpers
- let_it_be(:admin) { create(:admin) }
+ let_it_be(:admin) { create(:admin, :no_super_sidebar) }
let(:job_class) { Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJob }
let_it_be(:active_migration) { create(:batched_background_migration, :active, table_name: 'active') }
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index b78d6777a1a..e87f47e5234 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
include TermsHelper
include UsageDataHelpers
- let_it_be(:admin) { create(:admin) }
+ let_it_be(:admin) { create(:admin, :no_super_sidebar) }
context 'application setting :admin_mode is enabled', :request_store do
before do
@@ -53,7 +53,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
it 'modify import sources' do
expect(current_settings.import_sources).to be_empty
- page.within('[data-testid="admin-visibility-access-settings"]') do
+ page.within('[data-testid="admin-import-export-settings"]') do
check "Repository by URL"
click_button 'Save changes'
end
@@ -63,7 +63,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
end
it 'change Visibility and Access Controls' do
- page.within('[data-testid="admin-visibility-access-settings"]') do
+ page.within('[data-testid="admin-import-export-settings"]') do
page.within('[data-testid="project-export"]') do
uncheck 'Enabled'
end
@@ -113,7 +113,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
end
it 'change Maximum export size' do
- page.within(find('[data-testid="account-limit"]')) do
+ page.within(find('[data-testid="admin-import-export-settings"]')) do
fill_in 'Maximum export size (MiB)', with: 25
click_button 'Save changes'
end
@@ -123,7 +123,7 @@ RSpec.describe 'Admin updates settings', feature_category: :shared do
end
it 'change Maximum import size' do
- page.within(find('[data-testid="account-limit"]')) do
+ page.within(find('[data-testid="admin-import-export-settings"]')) do
fill_in 'Maximum import size (MiB)', with: 15
click_button 'Save changes'
end
diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/user_spec.rb
index a95fd133133..7dc329e6909 100644
--- a/spec/features/admin/users/user_spec.rb
+++ b/spec/features/admin/users/user_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do
include Features::AdminUsersHelpers
include Spec::Support::Helpers::ModalHelpers
- let_it_be(:user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
- let_it_be(:current_user) { create(:admin) }
+ let_it_be(:user) { create(:omniauth_user, :no_super_sidebar, provider: 'twitter', extern_uid: '123456') }
+ let_it_be(:current_user) { create(:admin, :no_super_sidebar) }
before do
sign_in(current_user)
@@ -145,7 +145,7 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do
end
describe 'Impersonation' do
- let_it_be(:another_user) { create(:user) }
+ let_it_be(:another_user) { create(:user, :no_super_sidebar) }
context 'before impersonating' do
subject { visit admin_user_path(user_to_visit) }
@@ -156,7 +156,7 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do
it 'disables impersonate button' do
subject
- impersonate_btn = find('[data-testid="impersonate_user_link"]')
+ impersonate_btn = find('[data-testid="impersonate-user-link"]')
expect(impersonate_btn).not_to be_nil
expect(impersonate_btn['disabled']).not_to be_nil
@@ -174,7 +174,7 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do
subject
expect(page).to have_content('Impersonate')
- impersonate_btn = find('[data-testid="impersonate_user_link"]')
+ impersonate_btn = find('[data-testid="impersonate-user-link"]')
expect(impersonate_btn['disabled']).to be_nil
end
end
diff --git a/spec/features/admin/users/users_spec.rb b/spec/features/admin/users/users_spec.rb
index 8e80ce5edd9..8ee30c50a7d 100644
--- a/spec/features/admin/users/users_spec.rb
+++ b/spec/features/admin/users/users_spec.rb
@@ -350,7 +350,8 @@ RSpec.describe 'Admin::Users', feature_category: :user_management do
let_it_be(:ghost_user) { create(:user, :ghost) }
it 'does not render actions dropdown' do
- expect(page).not_to have_css("[data-testid='user-actions-#{ghost_user.id}'] [data-testid='dropdown-toggle']")
+ expect(page).not_to have_css(
+ "[data-testid='user-actions-#{ghost_user.id}'] [data-testid='user-actions-dropdown-toggle']")
end
end
@@ -358,7 +359,8 @@ RSpec.describe 'Admin::Users', feature_category: :user_management do
let_it_be(:bot_user) { create(:user, user_type: :alert_bot) }
it 'does not render actions dropdown' do
- expect(page).not_to have_css("[data-testid='user-actions-#{bot_user.id}'] [data-testid='dropdown-toggle']")
+ expect(page).not_to have_css(
+ "[data-testid='user-actions-#{bot_user.id}'] [data-testid='user-actions-dropdown-toggle']")
end
end
end
diff --git a/spec/features/alert_management/alert_details_spec.rb b/spec/features/alert_management/alert_details_spec.rb
index 45fa4d810aa..b377d3a092b 100644
--- a/spec/features/alert_management/alert_details_spec.rb
+++ b/spec/features/alert_management/alert_details_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Alert details', :js, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
- let_it_be(:developer) { create(:user) }
+ let_it_be(:developer) { create(:user, :no_super_sidebar) }
let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered', title: 'Alert') }
before_all do
diff --git a/spec/features/alert_management/alert_management_list_spec.rb b/spec/features/alert_management/alert_management_list_spec.rb
index 6ed3bdec5f5..cc54af249e1 100644
--- a/spec/features/alert_management/alert_management_list_spec.rb
+++ b/spec/features/alert_management/alert_management_list_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Alert Management index', :js, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
- let_it_be(:developer) { create(:user) }
+ let_it_be(:developer) { create(:user, :no_super_sidebar) }
before_all do
project.add_developer(developer)
diff --git a/spec/features/boards/board_filters_spec.rb b/spec/features/boards/board_filters_spec.rb
index 006b7ce45d4..1ee02de9a66 100644
--- a/spec/features/boards/board_filters_spec.rb
+++ b/spec/features/boards/board_filters_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'Issue board filters', :js, feature_category: :team_planning do
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository, group: group) }
let_it_be(:user) { create(:user) }
- let_it_be(:board) { create(:board, project: project) }
let_it_be(:project_label) { create(:label, project: project, title: 'Label') }
let_it_be(:milestone_1) { create(:milestone, project: project, due_date: 3.days.from_now) }
let_it_be(:milestone_2) { create(:milestone, project: project, due_date: Date.tomorrow) }
@@ -21,166 +21,195 @@ RSpec.describe 'Issue board filters', :js, feature_category: :team_planning do
let(:filter_first_suggestion) { find('.gl-filtered-search-suggestion-list').first('.gl-filtered-search-suggestion') }
let(:filter_submit) { find('.gl-search-box-by-click-search-button') }
- before do
- stub_feature_flags(apollo_boards: false)
- project.add_maintainer(user)
- sign_in(user)
+ context 'for a project board' do
+ let_it_be(:board) { create(:board, project: project) }
- visit_project_board
- end
-
- shared_examples 'loads all the users when opened' do
- it 'and submit one as filter', :aggregate_failures do
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
+ before do
+ stub_feature_flags(apollo_boards: false)
+ project.add_maintainer(user)
+ sign_in(user)
+ visit project_board_path(project, board)
wait_for_requests
+ end
- expect_filtered_search_dropdown_results(filter_dropdown, 4)
+ shared_examples 'loads all the users when opened' do
+ it 'and submit one as filter', :aggregate_failures do
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
- click_on user.username
- filter_submit.click
+ wait_for_requests
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
- expect(find('.board-card')).to have_content(issue.title)
- end
- end
+ expect_filtered_search_dropdown_results(filter_dropdown, 3)
- describe 'filters by assignee' do
- before do
- set_filter('assignee')
- end
+ click_on user.username
+ filter_submit.click
- it_behaves_like 'loads all the users when opened', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/351426' do
- let(:issue) { issue_2 }
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
+ expect(find('.board-card')).to have_content(issue.title)
+ end
end
- end
- describe 'filters by author' do
- before do
- set_filter('author')
- end
+ describe 'filters by assignee' do
+ before do
+ set_filter('assignee')
+ end
- it_behaves_like 'loads all the users when opened' do
- let(:issue) { issue_1 }
+ it_behaves_like 'loads all the users when opened', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/351426' do
+ let(:issue) { issue_2 }
+ end
end
- end
- describe 'filters by label' do
- before do
- set_filter('label')
+ describe 'filters by author' do
+ before do
+ set_filter('author')
+ end
+
+ it_behaves_like 'loads all the users when opened' do
+ let(:issue) { issue_1 }
+ end
end
- it 'loads all the labels when opened and submit one as filter', :aggregate_failures do
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
+ describe 'filters by label' do
+ before do
+ set_filter('label')
+ end
- expect_filtered_search_dropdown_results(filter_dropdown, 3)
+ it 'loads all the labels when opened and submit one as filter', :aggregate_failures do
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
- filter_dropdown.click_on project_label.title
- filter_submit.click
+ expect_filtered_search_dropdown_results(filter_dropdown, 3)
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
- expect(find('.board-card')).to have_content(issue_2.title)
- end
- end
+ filter_dropdown.click_on project_label.title
+ filter_submit.click
- describe 'filters by releases' do
- before do
- set_filter('release')
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
+ expect(find('.board-card')).to have_content(issue_2.title)
+ end
end
- it 'loads all the releases when opened and submit one as filter', :aggregate_failures do
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
+ describe 'filters by releases' do
+ before do
+ set_filter('release')
+ end
- expect_filtered_search_dropdown_results(filter_dropdown, 2)
+ it 'loads all the releases when opened and submit one as filter', :aggregate_failures do
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
- click_on release.tag
- filter_submit.click
+ expect_filtered_search_dropdown_results(filter_dropdown, 2)
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
- expect(find('.board-card')).to have_content(issue_1.title)
- end
- end
+ click_on release.tag
+ filter_submit.click
- describe 'filters by confidentiality' do
- before do
- filter_input.click
- filter_input.set("confidential:")
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
+ expect(find('.board-card')).to have_content(issue_1.title)
+ end
end
- it 'loads all the confidentiality options when opened and submit one as filter', :aggregate_failures do
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
+ describe 'filters by confidentiality' do
+ before do
+ filter_input.click
+ filter_input.set("confidential:")
+ end
- expect_filtered_search_dropdown_results(filter_dropdown, 2)
+ it 'loads all the confidentiality options when opened and submit one as filter', :aggregate_failures do
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
- filter_dropdown.click_on 'Yes'
- filter_submit.click
+ expect_filtered_search_dropdown_results(filter_dropdown, 2)
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
- expect(find('.board-card')).to have_content(issue_2.title)
- end
- end
+ filter_dropdown.click_on 'Yes'
+ filter_submit.click
- describe 'filters by milestone' do
- before do
- set_filter('milestone')
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
+ expect(find('.board-card')).to have_content(issue_2.title)
+ end
end
- it 'loads all the milestones when opened and submit one as filter', :aggregate_failures do
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
+ describe 'filters by milestone' do
+ before do
+ set_filter('milestone')
+ end
+
+ it 'loads all the milestones when opened and submit one as filter', :aggregate_failures do
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
- expect_filtered_search_dropdown_results(filter_dropdown, 6)
- expect(filter_dropdown).to have_content('None')
- expect(filter_dropdown).to have_content('Any')
- expect(filter_dropdown).to have_content('Started')
- expect(filter_dropdown).to have_content('Upcoming')
+ expect_filtered_search_dropdown_results(filter_dropdown, 6)
+ expect(filter_dropdown).to have_content('None')
+ expect(filter_dropdown).to have_content('Any')
+ expect(filter_dropdown).to have_content('Started')
+ expect(filter_dropdown).to have_content('Upcoming')
- dropdown_nodes = page.find_all('.gl-filtered-search-suggestion-list > .gl-filtered-search-suggestion')
+ dropdown_nodes = page.find_all('.gl-filtered-search-suggestion-list > .gl-filtered-search-suggestion')
- expect(dropdown_nodes[4]).to have_content(milestone_2.title)
- expect(dropdown_nodes.last).to have_content(milestone_1.title)
+ expect(dropdown_nodes[4]).to have_content(milestone_2.title)
+ expect(dropdown_nodes.last).to have_content(milestone_1.title)
- click_on milestone_1.title
- filter_submit.click
+ click_on milestone_1.title
+ filter_submit.click
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
+ end
end
- end
- describe 'filters by reaction emoji' do
- before do
- set_filter('my-reaction')
+ describe 'filters by reaction emoji' do
+ before do
+ set_filter('my-reaction')
+ end
+
+ it 'loads all the emojis when opened and submit one as filter', :aggregate_failures do
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
+
+ expect_filtered_search_dropdown_results(filter_dropdown, 3)
+
+ click_on 'thumbsup'
+ filter_submit.click
+
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
+ expect(find('.board-card')).to have_content(issue_1.title)
+ end
end
- it 'loads all the emojis when opened and submit one as filter', :aggregate_failures do
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 2)
+ describe 'filters by type' do
+ let_it_be(:incident) { create(:incident, project: project) }
+
+ before do
+ set_filter('type')
+ end
- expect_filtered_search_dropdown_results(filter_dropdown, 3)
+ it 'loads all the types when opened and submit one as filter', :aggregate_failures do
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 3)
- click_on 'thumbsup'
- filter_submit.click
+ expect_filtered_search_dropdown_results(filter_dropdown, 2)
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
- expect(find('.board-card')).to have_content(issue_1.title)
+ click_on 'Incident'
+ filter_submit.click
+
+ expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
+ expect(find('.board-card')).to have_content(incident.title)
+ end
end
end
- describe 'filters by type' do
- let_it_be(:incident) { create(:incident, project: project) }
+ context 'for a group board' do
+ let_it_be(:board) { create(:board, group: group) }
+
+ let_it_be(:child_project_member) { create(:user).tap { |u| project.add_maintainer(u) } }
before do
- set_filter('type')
- end
+ stub_feature_flags(apollo_boards: false)
- it 'loads all the types when opened and submit one as filter', :aggregate_failures do
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 3)
+ group.add_maintainer(user)
+ sign_in(user)
+ end
- expect_filtered_search_dropdown_results(filter_dropdown, 2)
+ context 'when filtering by assignee' do
+ it 'includes descendant project members in autocomplete' do
+ visit group_board_path(group, board)
+ wait_for_requests
- click_on 'Incident'
- filter_submit.click
+ set_filter('assignee')
- expect(find('.board:nth-child(1)')).to have_selector('.board-card', count: 1)
- expect(find('.board-card')).to have_content(incident.title)
+ expect(page).to have_css('.gl-filtered-search-suggestion', text: child_project_member.name)
+ end
end
end
@@ -193,9 +222,4 @@ RSpec.describe 'Issue board filters', :js, feature_category: :team_planning do
def expect_filtered_search_dropdown_results(filter_dropdown, count)
expect(filter_dropdown).to have_selector('.gl-dropdown-item', count: count)
end
-
- def visit_project_board
- visit project_board_path(project, board)
- wait_for_requests
- end
end
diff --git a/spec/features/boards/multiple_boards_spec.rb b/spec/features/boards/multiple_boards_spec.rb
index e9d34c6f87f..9d59d3dd02a 100644
--- a/spec/features/boards/multiple_boards_spec.rb
+++ b/spec/features/boards/multiple_boards_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Multiple Issue Boards', :js, feature_category: :team_planning do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:planning) { create(:label, project: project, name: 'Planning') }
let_it_be(:board) { create(:board, name: 'board1', project: project) }
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 4807b691e4f..358da1e1279 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project issue boards sidebar', :js, feature_category: :team_planning, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/416414' do
+RSpec.describe 'Project issue boards sidebar', :js, feature_category: :team_planning do
include BoardHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index 8ad27b65f11..e22ae4f51fb 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Contributions Calendar', :js, feature_category: :user_profile do
include MobileHelpers
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:contributed_project) { create(:project, :public, :repository) }
let(:issue_note) { create(:note, project: contributed_project) }
diff --git a/spec/features/contextual_sidebar_spec.rb b/spec/features/contextual_sidebar_spec.rb
index 132c8eb7192..ab322f18240 100644
--- a/spec/features/contextual_sidebar_spec.rb
+++ b/spec/features/contextual_sidebar_spec.rb
@@ -4,9 +4,8 @@ require 'spec_helper'
RSpec.describe 'Contextual sidebar', :js, feature_category: :remote_development do
context 'when context is a project' do
- let_it_be(:project) { create(:project) }
-
- let(:user) { project.first_owner }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :repository, namespace: user.namespace) }
before do
sign_in(user)
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index 56272f58e0d..4fe05abd73b 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -60,8 +60,8 @@ RSpec.describe 'Value Stream Analytics', :js, feature_category: :value_stream_ma
# NOTE: in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68595 travel back
# 5 days in time before we create data for these specs, to mitigate some flakiness
# So setting the date range to be the last 2 days should skip past the existing data
- from = 2.days.ago.strftime("%Y-%m-%d")
- to = 1.day.ago.strftime("%Y-%m-%d")
+ from = 2.days.ago.to_date.iso8601
+ to = 1.day.ago.to_date.iso8601
max_items_per_page = 20
around do |example|
diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb
index 60621f57bde..61631d28aa9 100644
--- a/spec/features/dashboard/activity_spec.rb
+++ b/spec/features/dashboard/activity_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Dashboard > Activity', feature_category: :user_profile do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
index c1849cbee83..a00666c2376 100644
--- a/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
+++ b/spec/features/dashboard/group_dashboard_with_external_authorization_service_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'The group dashboard', :js, feature_category: :groups_and_project
include ExternalAuthorizationServiceHelpers
include Features::TopNavSpecHelpers
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in user
diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb
index b077b554773..e1da163cdf5 100644
--- a/spec/features/dashboard/groups_list_spec.rb
+++ b/spec/features/dashboard/groups_list_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Dashboard Groups page', :js, feature_category: :groups_and_projects do
- let(:user) { create :user }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
let(:nested_group) { create(:group, :nested) }
let(:another_group) { create(:group) }
@@ -237,4 +237,15 @@ RSpec.describe 'Dashboard Groups page', :js, feature_category: :groups_and_proje
expect(page).to have_link("Explore groups", href: explore_groups_path)
end
+
+ context 'when there are no groups to display' do
+ before do
+ sign_in(user)
+ visit dashboard_groups_path
+ end
+
+ it 'shows empty state' do
+ expect(page).to have_content(s_('GroupsEmptyState|A group is a collection of several projects'))
+ end
+ end
end
diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb
index 5e6ec007569..501405c5662 100644
--- a/spec/features/dashboard/issuables_counter_spec.rb
+++ b/spec/features/dashboard/issuables_counter_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching, feature_category: :team_planning do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, namespace: user.namespace) }
let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, source_project: project) }
diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb
index 70d9f7e5137..69b32113bba 100644
--- a/spec/features/dashboard/issues_spec.rb
+++ b/spec/features/dashboard/issues_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Dashboard Issues', feature_category: :team_planning do
include FilteredSearchHelpers
- let_it_be(:current_user) { create :user }
+ let_it_be(:current_user) { create(:user, :no_super_sidebar) }
let_it_be(:user) { current_user } # Shared examples depend on this being available
let_it_be(:public_project) { create(:project, :public) }
let_it_be(:project) { create(:project) }
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index 624f3530f81..4bb04f4ff80 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Dashboard Merge Requests', feature_category: :code_review_workfl
include FilteredSearchHelpers
include ProjectForksHelper
- let(:current_user) { create :user }
+ let(:current_user) { create(:user, :no_super_sidebar) }
let(:user) { current_user }
let(:project) { create(:project) }
diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb
index 0dd25ffaa94..38637115246 100644
--- a/spec/features/dashboard/milestones_spec.rb
+++ b/spec/features/dashboard/milestones_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe 'Dashboard > Milestones', feature_category: :team_planning do
end
describe 'as logged-in user' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
let(:project) { create(:project, namespace: user.namespace) }
let!(:milestone) { create(:milestone, project: project) }
@@ -50,7 +50,7 @@ RSpec.describe 'Dashboard > Milestones', feature_category: :team_planning do
end
describe 'with merge requests disabled' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
let(:project) { create(:project, :merge_requests_disabled, namespace: user.namespace) }
let!(:milestone) { create(:milestone, project: project) }
diff --git a/spec/features/dashboard/navbar_spec.rb b/spec/features/dashboard/navbar_spec.rb
index ff0ff899fc2..30e7f2d2e4e 100644
--- a/spec/features/dashboard/navbar_spec.rb
+++ b/spec/features/dashboard/navbar_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe '"Your work" navbar', feature_category: :navigation do
include_context 'dashboard navbar structure'
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
it_behaves_like 'verified navigation bar' do
before do
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 747d09f5d08..e5ad9808f83 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Dashboard Projects', feature_category: :groups_and_projects do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project, reload: true) { create(:project, :repository, creator: build(:user)) } # ensure creator != owner to avoid N+1 false-positive
let_it_be(:project2) { create(:project, :public) }
diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb
index 2e01c1304de..c8013d364e3 100644
--- a/spec/features/dashboard/shortcuts_spec.rb
+++ b/spec/features/dashboard/shortcuts_spec.rb
@@ -50,13 +50,13 @@ RSpec.describe 'Dashboard shortcuts', :js, feature_category: :shared do
context 'logged out' do
before do
+ stub_feature_flags(super_sidebar_logged_out: false)
visit explore_root_path
end
it 'navigate to tabs' do
find('body').send_keys([:shift, 'G'])
- find('.nothing-here-block')
expect(page).to have_content('No public groups')
find('body').send_keys([:shift, 'S'])
diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb
index da985c6dc07..f9284f9479e 100644
--- a/spec/features/dashboard/snippets_spec.rb
+++ b/spec/features/dashboard/snippets_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Dashboard snippets', feature_category: :source_code_management do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
it_behaves_like 'a "Your work" page with sidebar and breadcrumbs', :dashboard_snippets_path, :snippets
diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb
index 9d59126df8d..5642d083673 100644
--- a/spec/features/dashboard/todos/todos_spec.rb
+++ b/spec/features/dashboard/todos/todos_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe 'Dashboard Todos', feature_category: :team_planning do
include DesignManagementTestHelpers
- let_it_be(:user) { create(:user, username: 'john') }
- let_it_be(:user2) { create(:user, username: 'diane') }
- let_it_be(:author) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar, username: 'john') }
+ let_it_be(:user2) { create(:user, :no_super_sidebar, username: 'diane') }
+ let_it_be(:author) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project, due_date: Date.today, title: "Fix bug") }
diff --git a/spec/features/explore/groups_list_spec.rb b/spec/features/explore/groups_list_spec.rb
index 39cd3c80307..91ee6d48a48 100644
--- a/spec/features/explore/groups_list_spec.rb
+++ b/spec/features/explore/groups_list_spec.rb
@@ -4,88 +4,104 @@ require 'spec_helper'
RSpec.describe 'Explore Groups page', :js, feature_category: :groups_and_projects do
let!(:user) { create :user }
- let!(:group) { create(:group) }
- let!(:public_group) { create(:group, :public) }
- let!(:private_group) { create(:group, :private) }
- let!(:empty_project) { create(:project, group: public_group) }
- before do
- group.add_owner(user)
+ context 'when there are groups to show' do
+ let!(:group) { create(:group) }
+ let!(:public_group) { create(:group, :public) }
+ let!(:private_group) { create(:group, :private) }
+ let!(:empty_project) { create(:project, group: public_group) }
- sign_in(user)
+ before do
+ group.add_owner(user)
- visit explore_groups_path
- wait_for_requests
- end
+ sign_in(user)
- it 'shows groups user is member of' do
- expect(page).to have_content(group.full_name)
- expect(page).to have_content(public_group.full_name)
- expect(page).not_to have_content(private_group.full_name)
- end
+ visit explore_groups_path
+ wait_for_requests
+ end
- it 'filters groups' do
- fill_in 'filter', with: group.name
- wait_for_requests
+ it 'shows groups user is member of' do
+ expect(page).to have_content(group.full_name)
+ expect(page).to have_content(public_group.full_name)
+ expect(page).not_to have_content(private_group.full_name)
+ end
- expect(page).to have_content(group.full_name)
- expect(page).not_to have_content(public_group.full_name)
- expect(page).not_to have_content(private_group.full_name)
- end
+ it 'filters groups' do
+ fill_in 'filter', with: group.name
+ wait_for_requests
- it 'resets search when user cleans the input' do
- fill_in 'filter', with: group.name
- wait_for_requests
+ expect(page).to have_content(group.full_name)
+ expect(page).not_to have_content(public_group.full_name)
+ expect(page).not_to have_content(private_group.full_name)
+ end
- expect(page).to have_content(group.full_name)
- expect(page).not_to have_content(public_group.full_name)
+ it 'resets search when user cleans the input' do
+ fill_in 'filter', with: group.name
+ wait_for_requests
- fill_in 'filter', with: ""
- page.find('[name="filter"]').send_keys(:enter)
- wait_for_requests
+ expect(page).to have_content(group.full_name)
+ expect(page).not_to have_content(public_group.full_name)
- expect(page).to have_content(group.full_name)
- expect(page).to have_content(public_group.full_name)
- expect(page).not_to have_content(private_group.full_name)
- expect(page.all('.js-groups-list-holder .groups-list li').length).to eq 2
- end
+ fill_in 'filter', with: ""
+ page.find('[name="filter"]').send_keys(:enter)
+ wait_for_requests
- it 'shows non-archived projects count' do
- # Initially project is not archived
- expect(find('.js-groups-list-holder .groups-list li:first-child .stats .number-projects')).to have_text("1")
+ expect(page).to have_content(group.full_name)
+ expect(page).to have_content(public_group.full_name)
+ expect(page).not_to have_content(private_group.full_name)
+ expect(page.all('.js-groups-list-holder .groups-list li').length).to eq 2
+ end
- # Archive project
- ::Projects::UpdateService.new(empty_project, user, archived: true).execute
- visit explore_groups_path
+ it 'shows non-archived projects count' do
+ # Initially project is not archived
+ expect(find('.js-groups-list-holder .groups-list li:first-child .stats .number-projects')).to have_text("1")
- # Check project count
- expect(find('.js-groups-list-holder .groups-list li:first-child .stats .number-projects')).to have_text("0")
+ # Archive project
+ ::Projects::UpdateService.new(empty_project, user, archived: true).execute
+ visit explore_groups_path
- # Unarchive project
- ::Projects::UpdateService.new(empty_project, user, archived: false).execute
- visit explore_groups_path
+ # Check project count
+ expect(find('.js-groups-list-holder .groups-list li:first-child .stats .number-projects')).to have_text("0")
- # Check project count
- expect(find('.js-groups-list-holder .groups-list li:first-child .stats .number-projects')).to have_text("1")
- end
+ # Unarchive project
+ ::Projects::UpdateService.new(empty_project, user, archived: false).execute
+ visit explore_groups_path
- describe 'landing component' do
- it 'shows a landing component' do
- expect(page).to have_content('Below you will find all the groups that are public.')
+ # Check project count
+ expect(find('.js-groups-list-holder .groups-list li:first-child .stats .number-projects')).to have_text("1")
end
- it 'is dismissable' do
- find('.dismiss-button').click
+ describe 'landing component' do
+ it 'shows a landing component' do
+ expect(page).to have_content('Below you will find all the groups that are public.')
+ end
+
+ it 'is dismissable' do
+ find('.dismiss-button').click
+
+ expect(page).not_to have_content('Below you will find all the groups that are public.')
+ end
- expect(page).not_to have_content('Below you will find all the groups that are public.')
+ it 'does not show persistently once dismissed' do
+ find('.dismiss-button').click
+
+ visit explore_groups_path
+
+ expect(page).not_to have_content('Below you will find all the groups that are public.')
+ end
end
+ end
- it 'does not show persistently once dismissed' do
- find('.dismiss-button').click
+ context 'when there are no groups to show' do
+ before do
+ sign_in(user)
visit explore_groups_path
+ wait_for_requests
+ end
- expect(page).not_to have_content('Below you will find all the groups that are public.')
+ it 'shows empty state' do
+ expect(page).to have_content(_('No public groups'))
end
end
end
diff --git a/spec/features/explore/navbar_spec.rb b/spec/features/explore/navbar_spec.rb
index 8f281abe6a7..853d66ed4d1 100644
--- a/spec/features/explore/navbar_spec.rb
+++ b/spec/features/explore/navbar_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe '"Explore" navbar', feature_category: :navigation do
it_behaves_like 'verified navigation bar' do
before do
+ stub_feature_flags(super_sidebar_logged_out: false)
visit explore_projects_path
end
end
diff --git a/spec/features/explore/user_explores_projects_spec.rb b/spec/features/explore/user_explores_projects_spec.rb
index f259ba6a167..43d464e0c9f 100644
--- a/spec/features/explore/user_explores_projects_spec.rb
+++ b/spec/features/explore/user_explores_projects_spec.rb
@@ -3,6 +3,10 @@
require 'spec_helper'
RSpec.describe 'User explores projects', feature_category: :user_profile do
+ before do
+ stub_feature_flags(super_sidebar_logged_out: false)
+ end
+
describe '"All" tab' do
it_behaves_like 'an "Explore" page with sidebar and breadcrumbs', :explore_projects_path, :projects
end
diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb
index f94f0288f99..dfafacf48e2 100644
--- a/spec/features/global_search_spec.rb
+++ b/spec/features/global_search_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Global search', :js, feature_category: :global_search do
include AfterNextHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
before do
diff --git a/spec/features/groups/container_registry_spec.rb b/spec/features/groups/container_registry_spec.rb
index d68b4ccf8f8..953a8e27547 100644
--- a/spec/features/groups/container_registry_spec.rb
+++ b/spec/features/groups/container_registry_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Container Registry', :js, feature_category: :container_registry do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
diff --git a/spec/features/groups/dependency_proxy_for_containers_spec.rb b/spec/features/groups/dependency_proxy_for_containers_spec.rb
index c0456140291..1e15b97c5aa 100644
--- a/spec/features/groups/dependency_proxy_for_containers_spec.rb
+++ b/spec/features/groups/dependency_proxy_for_containers_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'Group Dependency Proxy for containers', :js, feature_category: :
include DependencyProxyHelpers
include_context 'file upload requests helpers'
+ include_context 'with a server running the dependency proxy'
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
@@ -21,17 +22,6 @@ RSpec.describe 'Group Dependency Proxy for containers', :js, feature_category: :
HTTParty.get(url, headers: headers)
end
- def run_server(handler)
- default_server = Capybara.server
-
- Capybara.server = Capybara.servers[:puma]
- server = Capybara::Server.new(handler)
- server.boot
- server
- ensure
- Capybara.server = default_server
- end
-
let_it_be(:external_server) do
handler = lambda do |env|
if env['REQUEST_PATH'] == '/token'
diff --git a/spec/features/groups/dependency_proxy_spec.rb b/spec/features/groups/dependency_proxy_spec.rb
index 60922f813df..2d4f6d4fbf2 100644
--- a/spec/features/groups/dependency_proxy_spec.rb
+++ b/spec/features/groups/dependency_proxy_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Group Dependency Proxy', feature_category: :dependency_proxy do
- let(:owner) { create(:user) }
- let(:reporter) { create(:user) }
+ let(:owner) { create(:user, :no_super_sidebar) }
+ let(:reporter) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
let(:path) { group_dependency_proxy_path(group) }
let(:settings_path) { group_settings_packages_and_registries_path(group) }
diff --git a/spec/features/groups/group_page_with_external_authorization_service_spec.rb b/spec/features/groups/group_page_with_external_authorization_service_spec.rb
index 5b373aecce8..4cc0fe4171d 100644
--- a/spec/features/groups/group_page_with_external_authorization_service_spec.rb
+++ b/spec/features/groups/group_page_with_external_authorization_service_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'The group page', feature_category: :groups_and_projects do
include ExternalAuthorizationServiceHelpers
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
before do
diff --git a/spec/features/groups/group_runners_spec.rb b/spec/features/groups/group_runners_spec.rb
index e9d2d185e8a..4e5d7c6f8e8 100644
--- a/spec/features/groups/group_runners_spec.rb
+++ b/spec/features/groups/group_runners_spec.rb
@@ -7,182 +7,235 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do
include Spec::Support::Helpers::ModalHelpers
let_it_be(:group_owner) { create(:user) }
+ let_it_be(:group_maintainer) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
before do
group.add_owner(group_owner)
- sign_in(group_owner)
+ group.add_maintainer(group_maintainer)
end
describe "Group runners page", :js do
- context "with no runners" do
+ context 'when logged in as group maintainer' do
before do
- visit group_runners_path(group)
+ sign_in(group_maintainer)
end
- it_behaves_like 'shows no runners registered'
-
- it 'shows tabs with total counts equal to 0' do
- expect(page).to have_link('All 0')
- expect(page).to have_link('Group 0')
- expect(page).to have_link('Project 0')
- end
- end
+ context "with no runners" do
+ before do
+ visit group_runners_path(group)
+ end
- context "with an online group runner" do
- let!(:group_runner) do
- create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now)
- end
+ it_behaves_like 'shows no runners registered'
- before do
- visit group_runners_path(group)
+ it 'shows tabs with total counts equal to 0' do
+ expect(page).to have_link('All 0')
+ expect(page).to have_link('Group 0')
+ expect(page).to have_link('Project 0')
+ end
end
- it_behaves_like 'shows runner in list' do
- let(:runner) { group_runner }
- end
+ context "with an online group runner" do
+ let_it_be(:group_runner) do
+ create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now)
+ end
- it_behaves_like 'pauses, resumes and deletes a runner' do
- let(:runner) { group_runner }
- end
+ before do
+ visit group_runners_path(group)
+ end
- it 'shows an editable group badge' do
- within_runner_row(group_runner.id) do
- expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, group_runner))
+ it_behaves_like 'shows runner in list' do
+ let(:runner) { group_runner }
+ end
- expect(page).to have_selector '.badge', text: s_('Runners|Group')
+ it_behaves_like 'shows runner details from list' do
+ let(:runner) { group_runner }
+ let(:runner_page_path) { group_runner_path(group, group_runner) }
end
- end
- context 'when description does not match' do
- before do
- input_filtered_search_keys('runner-baz')
+ it 'shows a group runner badge' do
+ within_runner_row(group_runner.id) do
+ expect(page).to have_selector '.badge', text: s_('Runners|Group')
+ end
end
- it_behaves_like 'shows no runners found'
+ context 'when description does not match' do
+ before do
+ input_filtered_search_keys('runner-baz')
+ end
+
+ it_behaves_like 'shows no runners found'
- it 'shows no runner' do
- expect(page).not_to have_content 'runner-foo'
+ it 'shows no runner' do
+ expect(page).not_to have_content 'runner-foo'
+ end
end
end
- end
- context "with an online project runner" do
- let!(:project_runner) do
- create(:ci_runner, :project, projects: [project], description: 'runner-bar', contacted_at: Time.zone.now)
- end
+ context "with an online project runner" do
+ let_it_be(:project_runner) do
+ create(:ci_runner, :project, projects: [project], description: 'runner-bar', contacted_at: Time.zone.now)
+ end
- before do
- visit group_runners_path(group)
- end
+ before do
+ visit group_runners_path(group)
+ end
- it_behaves_like 'shows runner in list' do
- let(:runner) { project_runner }
- end
+ it_behaves_like 'shows runner in list' do
+ let(:runner) { project_runner }
+ end
- it_behaves_like 'pauses, resumes and deletes a runner' do
- let(:runner) { project_runner }
+ it_behaves_like 'shows runner details from list' do
+ let(:runner) { project_runner }
+ let(:runner_page_path) { group_runner_path(group, project_runner) }
+ end
+
+ it 'shows a project runner badge' do
+ within_runner_row(project_runner.id) do
+ expect(page).to have_selector '.badge', text: s_('Runners|Project')
+ end
+ end
end
- it 'shows an editable project runner' do
- within_runner_row(project_runner.id) do
- expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, project_runner))
+ context "with an online instance runner" do
+ let_it_be(:instance_runner) do
+ create(:ci_runner, :instance, description: 'runner-baz', contacted_at: Time.zone.now)
+ end
- expect(page).to have_selector '.badge', text: s_('Runners|Project')
+ before do
+ visit group_runners_path(group)
end
- end
- end
- context "with an online instance runner" do
- let!(:instance_runner) do
- create(:ci_runner, :instance, description: 'runner-baz', contacted_at: Time.zone.now)
- end
+ context "when selecting 'Show only inherited'" do
+ before do
+ find("[data-testid='runner-membership-toggle'] button").click
- before do
- visit group_runners_path(group)
- end
+ wait_for_requests
+ end
- context "when selecting 'Show only inherited'" do
- before do
- find("[data-testid='runner-membership-toggle'] button").click
+ it_behaves_like 'shows runner in list' do
+ let(:runner) { instance_runner }
+ end
- wait_for_requests
+ it_behaves_like 'shows runner details from list' do
+ let(:runner) { instance_runner }
+ let(:runner_page_path) { group_runner_path(group, instance_runner) }
+ end
end
+ end
- it_behaves_like 'shows runner in list' do
- let(:runner) { instance_runner }
+ describe 'filtered search' do
+ before do
+ visit group_runners_path(group)
end
- it 'shows runner details page' do
- click_link("##{instance_runner.id} (#{instance_runner.short_sha})")
+ it 'allows user to search by paused and status', :js do
+ focus_filtered_search
- expect(current_url).to include(group_runner_path(group, instance_runner))
- expect(page).to have_content "#{s_('Runners|Description')} runner-baz"
+ page.within(search_bar_selector) do
+ expect(page).to have_link(s_('Runners|Paused'))
+ expect(page).to have_content('Status')
+ end
end
end
- end
- context 'with a multi-project runner' do
- let(:project) { create(:project, group: group) }
- let(:project_2) { create(:project, group: group) }
- let!(:runner) { create(:ci_runner, :project, projects: [project, project_2], description: 'group-runner') }
+ describe 'filter by tag' do
+ let!(:rnr_1) { create(:ci_runner, :group, groups: [group], description: 'runner-blue', tag_list: ['blue']) }
+ let!(:rnr_2) { create(:ci_runner, :group, groups: [group], description: 'runner-red', tag_list: ['red']) }
- it 'user cannot remove the project runner' do
- visit group_runners_path(group)
+ before do
+ visit group_runners_path(group)
+ end
- within_runner_row(runner.id) do
- expect(page).not_to have_button 'Delete runner'
+ it_behaves_like 'filters by tag' do
+ let(:tag) { 'blue' }
+ let(:found_runner) { rnr_1.description }
+ let(:missing_runner) { rnr_2.description }
end
end
end
- context "with multiple runners" do
+ context 'when logged in as group owner' do
before do
- create(:ci_runner, :group, groups: [group], description: 'runner-foo')
- create(:ci_runner, :group, groups: [group], description: 'runner-bar')
-
- visit group_runners_path(group)
+ sign_in(group_owner)
end
- it_behaves_like 'deletes runners in bulk' do
- let(:runner_count) { '2' }
- end
- end
+ context "with an online group runner" do
+ let_it_be(:group_runner) do
+ create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now)
+ end
- describe 'filtered search' do
- before do
- visit group_runners_path(group)
+ before do
+ visit group_runners_path(group)
+ end
+
+ it_behaves_like 'pauses, resumes and deletes a runner' do
+ let(:runner) { group_runner }
+ end
+
+ it 'shows an edit link' do
+ within_runner_row(group_runner.id) do
+ expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, group_runner))
+ end
+ end
end
- it 'allows user to search by paused and status', :js do
- focus_filtered_search
+ context "with an online project runner" do
+ let_it_be(:project_runner) do
+ create(:ci_runner, :project, projects: [project], description: 'runner-bar', contacted_at: Time.zone.now)
+ end
+
+ before do
+ visit group_runners_path(group)
+ end
- page.within(search_bar_selector) do
- expect(page).to have_link(s_('Runners|Paused'))
- expect(page).to have_content('Status')
+ it_behaves_like 'pauses, resumes and deletes a runner' do
+ let(:runner) { project_runner }
+ end
+
+ it 'shows an editable project runner' do
+ within_runner_row(project_runner.id) do
+ expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, project_runner))
+ end
end
end
- end
- describe 'filter by tag' do
- let!(:runner_1) { create(:ci_runner, :group, groups: [group], description: 'runner-blue', tag_list: ['blue']) }
- let!(:runner_2) { create(:ci_runner, :group, groups: [group], description: 'runner-red', tag_list: ['red']) }
+ context 'with a multi-project runner' do
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:project_2) { create(:project, group: group) }
+ let_it_be(:runner) do
+ create(:ci_runner, :project, projects: [project, project_2], description: 'group-runner')
+ end
- before do
- visit group_runners_path(group)
+ it 'owner cannot remove the project runner' do
+ visit group_runners_path(group)
+
+ within_runner_row(runner.id) do
+ expect(page).not_to have_button 'Delete runner'
+ end
+ end
end
- it_behaves_like 'filters by tag' do
- let(:tag) { 'blue' }
- let(:found_runner) { runner_1.description }
- let(:missing_runner) { runner_2.description }
+ context "with multiple runners" do
+ before do
+ create(:ci_runner, :group, groups: [group], description: 'runner-foo')
+ create(:ci_runner, :group, groups: [group], description: 'runner-bar')
+
+ visit group_runners_path(group)
+ end
+
+ it_behaves_like 'deletes runners in bulk' do
+ let(:runner_count) { '2' }
+ end
end
end
end
describe "Group runner create page", :js do
before do
+ sign_in(group_owner)
+
visit new_group_runner_path(group)
end
@@ -196,23 +249,39 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do
create(:ci_runner, :group, groups: [group], description: 'runner-foo')
end
- let_it_be(:group_runner_job) { create(:ci_build, runner: group_runner) }
+ let_it_be(:group_runner_job) { create(:ci_build, runner: group_runner, project: project) }
- before do
- visit group_runner_path(group, group_runner)
- end
+ context 'when logged in as group maintainer' do
+ before do
+ sign_in(group_maintainer)
- it 'user views runner details' do
- expect(page).to have_content "#{s_('Runners|Description')} runner-foo"
+ visit group_runner_path(group, group_runner)
+ end
+
+ it 'user views runner details' do
+ expect(page).to have_content "#{s_('Runners|Description')} runner-foo"
+ end
end
- it_behaves_like 'shows runner jobs tab' do
- let(:job_count) { '1' }
- let(:job) { group_runner_job }
+ context 'when logged in as group owner' do
+ before do
+ sign_in(group_owner)
+
+ visit group_runner_path(group, group_runner)
+ end
+
+ it_behaves_like 'shows runner jobs tab' do
+ let(:job_count) { '1' }
+ let(:job) { group_runner_job }
+ end
end
end
describe "Group runner edit page", :js do
+ before do
+ sign_in(group_owner)
+ end
+
context 'when updating a group runner' do
let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group]) }
@@ -239,6 +308,8 @@ RSpec.describe "Group Runners", feature_category: :runner_fleet do
let(:runner) { project_runner }
let(:runner_page_path) { group_runner_path(group, project_runner) }
end
+
+ it_behaves_like 'shows locked field'
end
end
end
diff --git a/spec/features/groups/labels/create_spec.rb b/spec/features/groups/labels/create_spec.rb
index 5b57e670c1d..8242f422e6e 100644
--- a/spec/features/groups/labels/create_spec.rb
+++ b/spec/features/groups/labels/create_spec.rb
@@ -9,15 +9,17 @@ RSpec.describe 'Create a group label', feature_category: :team_planning do
before do
group.add_owner(user)
sign_in(user)
- visit group_labels_path(group)
+
+ visit new_group_label_path(group)
end
it 'creates a new label' do
- click_link 'New label'
fill_in 'Title', with: 'test-label'
click_button 'Create label'
expect(page).to have_content 'test-label'
expect(page).to have_current_path(group_labels_path(group), ignore_query: true)
end
+
+ it_behaves_like 'lock_on_merge when creating labels'
end
diff --git a/spec/features/groups/labels/edit_spec.rb b/spec/features/groups/labels/edit_spec.rb
index 6e056d35435..70568d4baa2 100644
--- a/spec/features/groups/labels/edit_spec.rb
+++ b/spec/features/groups/labels/edit_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe 'Edit group label', feature_category: :team_planning do
before do
group.add_owner(user)
sign_in(user)
+
visit edit_group_label_path(group, label)
end
@@ -34,4 +35,17 @@ RSpec.describe 'Edit group label', feature_category: :team_planning do
expect(page).to have_content("#{label.title} was removed").and have_no_content("#{label.title}</span>")
end
+
+ describe 'lock_on_merge' do
+ let(:label_unlocked) { create(:group_label, group: group, lock_on_merge: false) }
+ let(:label_locked) { create(:group_label, group: group, lock_on_merge: true) }
+ let(:edit_label_path_unlocked) { edit_group_label_path(group, label_unlocked) }
+ let(:edit_label_path_locked) { edit_group_label_path(group, label_locked) }
+
+ before do
+ visit edit_label_path_unlocked
+ end
+
+ it_behaves_like 'lock_on_merge when editing labels'
+ end
end
diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb
index 138031ffaac..dd64ddcede5 100644
--- a/spec/features/groups/members/manage_members_spec.rb
+++ b/spec/features/groups/members/manage_members_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe 'Groups > Members > Manage members', feature_category: :groups_an
end
end
- it_behaves_like 'inviting members', 'group-members-page' do
+ it_behaves_like 'inviting members', 'group_members_page' do
let_it_be(:entity) { group }
let_it_be(:members_page_path) { group_group_members_path(entity) }
let_it_be(:subentity) { create(:group, parent: group) }
diff --git a/spec/features/groups/members/request_access_spec.rb b/spec/features/groups/members/request_access_spec.rb
index cd0c9bfe3eb..c04b84be90e 100644
--- a/spec/features/groups/members/request_access_spec.rb
+++ b/spec/features/groups/members/request_access_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Groups > Members > Request access', feature_category: :groups_and_projects do
- let(:user) { create(:user) }
- let(:owner) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
+ let(:owner) { create(:user, :no_super_sidebar) }
let(:group) { create(:group, :public) }
let!(:project) { create(:project, :private, namespace: group) }
diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb
index a52e2d95fed..6a38f0c59a8 100644
--- a/spec/features/groups/navbar_spec.rb
+++ b/spec/features/groups/navbar_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'Group navbar', :with_license, feature_category: :navigation do
include_context 'group navbar structure'
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
@@ -18,7 +18,6 @@ RSpec.describe 'Group navbar', :with_license, feature_category: :navigation do
stub_config(dependency_proxy: { enabled: false })
stub_config(registry: { enabled: false })
- stub_feature_flags(harbor_registry_integration: false)
stub_feature_flags(observability_group_tab: false)
stub_group_wikis(false)
group.add_maintainer(user)
@@ -87,8 +86,6 @@ RSpec.describe 'Group navbar', :with_license, feature_category: :navigation do
before do
group.update!(harbor_integration: harbor_integration)
- stub_feature_flags(harbor_registry_integration: true)
-
insert_harbor_registry_nav(_('Package Registry'))
visit group_path(group)
diff --git a/spec/features/groups/new_group_page_spec.rb b/spec/features/groups/new_group_page_spec.rb
index c3731565ddf..e1034f2bb9d 100644
--- a/spec/features/groups/new_group_page_spec.rb
+++ b/spec/features/groups/new_group_page_spec.rb
@@ -39,14 +39,14 @@ RSpec.describe 'New group page', :js, feature_category: :groups_and_projects do
context 'for a new top-level group' do
it 'shows the "Your work" navigation' do
visit new_group_path
- expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: "Your work")
+ expect(page).to have_selector(".super-sidebar", text: "Your work")
end
end
context 'for a new subgroup' do
it 'shows the group navigation of the parent group' do
visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
- expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: parent_group.name)
+ expect(page).to have_selector(".super-sidebar", text: parent_group.name)
end
end
end
diff --git a/spec/features/groups/packages_spec.rb b/spec/features/groups/packages_spec.rb
index ec8215928e4..1d9269501be 100644
--- a/spec/features/groups/packages_spec.rb
+++ b/spec/features/groups/packages_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Group Packages', feature_category: :package_registry do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
diff --git a/spec/features/groups/settings/packages_and_registries_spec.rb b/spec/features/groups/settings/packages_and_registries_spec.rb
index 8ea8dc9219a..fa310722860 100644
--- a/spec/features/groups/settings/packages_and_registries_spec.rb
+++ b/spec/features/groups/settings/packages_and_registries_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Group Package and registry settings', feature_category: :package_registry do
include WaitForRequests
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
let(:sub_group) { create(:group, parent: group) }
diff --git a/spec/features/groups/user_sees_package_sidebar_spec.rb b/spec/features/groups/user_sees_package_sidebar_spec.rb
index 6a91dfb92bf..4efb9ff7608 100644
--- a/spec/features/groups/user_sees_package_sidebar_spec.rb
+++ b/spec/features/groups/user_sees_package_sidebar_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Groups > sidebar', feature_category: :groups_and_projects do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:group) { create(:group) }
before do
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index 67133b1856f..7af58bf460c 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Group', feature_category: :groups_and_projects do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/help_dropdown_spec.rb b/spec/features/help_dropdown_spec.rb
index 5f1d3a5e2b7..08d7dba4d79 100644
--- a/spec/features/help_dropdown_spec.rb
+++ b/spec/features/help_dropdown_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe "Help Dropdown", :js, feature_category: :shared do
- let_it_be(:user) { create(:user) }
- let_it_be(:admin) { create(:admin) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:admin) { create(:admin, :no_super_sidebar) }
before do
stub_application_setting(version_check_enabled: true)
diff --git a/spec/features/ide/user_opens_merge_request_spec.rb b/spec/features/ide/user_opens_merge_request_spec.rb
index dc280133a20..2aa89cadb7d 100644
--- a/spec/features/ide/user_opens_merge_request_spec.rb
+++ b/spec/features/ide/user_opens_merge_request_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe 'IDE merge request', :js, feature_category: :web_ide do
include CookieHelper
- let(:merge_request) { create(:merge_request, :simple, source_project: project) }
- let(:project) { create(:project, :public, :repository) }
- let(:user) { project.first_owner }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :public, :repository, namespace: user.namespace) }
+ let_it_be(:merge_request) { create(:merge_request, :simple, source_project: project) }
before do
stub_feature_flags(vscode_web_ide: false)
diff --git a/spec/features/incidents/incident_details_spec.rb b/spec/features/incidents/incident_details_spec.rb
index d6feb008d47..7e447ae32c0 100644
--- a/spec/features/incidents/incident_details_spec.rb
+++ b/spec/features/incidents/incident_details_spec.rb
@@ -150,6 +150,9 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d
wait_for_requests
sticky_header = find_by_scrolling('[data-testid=issue-sticky-header]')
- expect(sticky_header.find('[data-testid=confidential]')).to be_present
+
+ page.within(sticky_header) do
+ expect(page).to have_text 'Confidential'
+ end
end
end
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index 03ec72980e5..a56df7bdecc 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -4,7 +4,8 @@ require 'spec_helper'
RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_category: :experimentation_expansion do
let_it_be(:owner) { create(:user, name: 'John Doe') }
- let_it_be(:group) { create(:group, name: 'Owned') }
+ # private will ensure we really have access to the group when we land on the activity page
+ let_it_be(:group) { create(:group, :private, name: 'Owned') }
let_it_be(:project) { create(:project, :repository, namespace: group) }
let(:group_invite) { group.group_members.invite.last }
@@ -22,18 +23,6 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
visit user_confirmation_path(confirmation_token: new_user_token)
end
- def fill_in_sign_up_form(new_user, submit_button_text = 'Register')
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
- fill_in 'new_user_password', with: new_user.password
-
- wait_for_all_requests
-
- click_button submit_button_text
- end
-
def fill_in_welcome_form
select 'Software Developer', from: 'user_role'
click_button 'Get started!'
@@ -58,10 +47,10 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
expect(page).to have_content('To accept this invitation, create an account or sign in')
end
- it 'pre-fills the "Username or email" field on the sign in box with the invite_email from the invite' do
+ it 'pre-fills the "Username or primary email" field on the sign in box with the invite_email from the invite' do
click_link 'Sign in'
- expect(find_field('Username or email').value).to eq(group_invite.invite_email)
+ expect(find_field('Username or primary email').value).to eq(group_invite.invite_email)
end
it 'pre-fills the Email field on the sign up box with the invite_email from the invite' do
@@ -70,11 +59,11 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
context 'when invite is sent before account is created;ldap or service sign in for manual acceptance edge case' do
- let(:user) { create(:user, email: 'user@example.com') }
+ let(:user) { create(:user, :no_super_sidebar, email: 'user@example.com') }
context 'when invite clicked and not signed in' do
before do
- visit invite_path(group_invite.raw_invite_token)
+ visit invite_path(group_invite.raw_invite_token, invite_type: Emails::Members::INITIAL_INVITE)
end
it 'sign in, grants access and redirects to group activity page' do
@@ -82,7 +71,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
gitlab_sign_in(user, remember: true, visit: false)
- expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
+ expect_to_be_on_group_activity_page(group)
end
end
@@ -143,6 +132,10 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
end
end
+
+ def expect_to_be_on_group_activity_page(group)
+ expect(page).to have_current_path(activity_group_path(group))
+ end
end
end
end
@@ -195,12 +188,11 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
context 'when the user sign-up using a different email address' do
let(:invite_email) { build_stubbed(:user).email }
- it 'signs up and redirects to the activity page',
- quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/414971' do
+ it 'signs up and redirects to the projects dashboard' do
fill_in_sign_up_form(new_user)
fill_in_welcome_form
- expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
+ expect_to_be_on_projects_dashboard_with_zero_authorized_projects
end
end
end
@@ -232,8 +224,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
end
context 'when the user signs up for an account with the invitation email address' do
- it 'redirects to the most recent membership activity page with all invitations automatically accepted',
- quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/417092' do
+ it 'redirects to the most recent membership activity page with all invitations automatically accepted' do
fill_in_sign_up_form(new_user)
fill_in_welcome_form
@@ -250,13 +241,13 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
stub_feature_flags(identity_verification: false)
end
- it 'signs up and redirects to the group activity page' do
+ it 'signs up and redirects to the projects dashboard' do
fill_in_sign_up_form(new_user)
confirm_email(new_user)
gitlab_sign_in(new_user, remember: true, visit: false)
fill_in_welcome_form
- expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
+ expect_to_be_on_projects_dashboard_with_zero_authorized_projects
end
end
@@ -266,15 +257,22 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures, feature_cate
allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
end
- it 'signs up and redirects to the group activity page' do
+ it 'signs up and redirects to the projects dashboard' do
fill_in_sign_up_form(new_user)
fill_in_welcome_form
- expect(page).to have_current_path(activity_group_path(group), ignore_query: true)
+ expect_to_be_on_projects_dashboard_with_zero_authorized_projects
end
end
end
end
+
+ def expect_to_be_on_projects_dashboard_with_zero_authorized_projects
+ expect(page).to have_current_path(dashboard_projects_path)
+
+ expect(page).to have_content _('Welcome to GitLab')
+ expect(page).to have_content _('Faster releases. Better code. Less pain.')
+ end
end
context 'when accepting an invite without an account' do
diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 0a06a052bc2..0c5b33c2530 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -113,33 +113,5 @@ RSpec.describe 'Dropdown assignee', :js, feature_category: :team_planning do
expect(page).to have_text invited_to_group_group_user.name
expect(page).not_to have_text subsubgroup_user.name
end
-
- context 'when new_graphql_users_autocomplete is disabled' do
- before do
- stub_feature_flags(new_graphql_users_autocomplete: false)
- end
-
- it 'shows inherited, direct, and invited group members but not descendent members', :aggregate_failures do
- visit issues_group_path(subgroup)
-
- select_tokens 'Assignee', '='
-
- expect(page).to have_text group_user.name
- expect(page).to have_text subgroup_user.name
- expect(page).to have_text invited_to_group_group_user.name
- expect(page).not_to have_text subsubgroup_user.name
- expect(page).not_to have_text invited_to_project_group_user.name
-
- visit project_issues_path(subgroup_project)
-
- select_tokens 'Assignee', '='
-
- expect(page).to have_text group_user.name
- expect(page).to have_text subgroup_user.name
- expect(page).to have_text invited_to_project_group_user.name
- expect(page).to have_text invited_to_group_group_user.name
- expect(page).not_to have_text subsubgroup_user.name
- end
- end
end
end
diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb
index 3031b20eb7c..e51c82081ff 100644
--- a/spec/features/issues/filtered_search/visual_tokens_spec.rb
+++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe 'Visual tokens', :js, feature_category: :team_planning do
include FilteredSearchHelpers
let_it_be(:project) { create(:project) }
- let_it_be(:user) { create(:user, name: 'administrator', username: 'root') }
- let_it_be(:user_rock) { create(:user, name: 'The Rock', username: 'rock') }
+ let_it_be(:user) { create(:user, :no_super_sidebar, name: 'administrator', username: 'root') }
+ let_it_be(:user_rock) { create(:user, :no_super_sidebar, name: 'The Rock', username: 'rock') }
let_it_be(:milestone_nine) { create(:milestone, title: '9.0', project: project) }
let_it_be(:milestone_ten) { create(:milestone, title: '10.0', project: project) }
let_it_be(:label) { create(:label, project: project, title: 'abc') }
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 5f7a4f26a98..ed2c712feb1 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -8,14 +8,13 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
include ContentEditorHelpers
let_it_be(:project) { create(:project, :repository) }
- let_it_be(:user) { create(:user) }
- let_it_be(:user2) { create(:user) }
- let_it_be(:guest) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:user2) { create(:user, :no_super_sidebar) }
+ let_it_be(:guest) { create(:user, :no_super_sidebar) }
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:label) { create(:label, project: project) }
let_it_be(:label2) { create(:label, project: project) }
let_it_be(:issue) { create(:issue, project: project, assignees: [user], milestone: milestone) }
- let_it_be(:issue2) { create(:issue, project: project, assignees: [user], milestone: milestone) }
let_it_be(:confidential_issue) { create(:issue, project: project, assignees: [user], milestone: milestone, confidential: true) }
let(:current_user) { user }
@@ -666,69 +665,59 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do
end
end
- describe 'inline edit' do
- context 'within issue 1' do
- before do
- visit project_issue_path(project, issue)
- wait_for_requests
- end
+ describe 'editing an issue by hotkey' do
+ let_it_be(:issue2) { create(:issue, project: project) }
- it 'opens inline edit form with shortcut' do
- find('body').send_keys('e')
+ before do
+ visit project_issue_path(project, issue2)
+ end
- expect(page).to have_selector('.detail-page-description form')
- end
+ it 'opens inline edit form with shortcut' do
+ find('body').send_keys('e')
- describe 'when user has made no changes' do
- it 'let user leave the page without warnings' do
- expected_content = 'Issue created'
- expect(page).to have_content(expected_content)
+ expect(page).to have_selector('.detail-page-description form')
+ end
- find('body').send_keys('e')
+ context 'when user has made no changes' do
+ it 'let user leave the page without warnings' do
+ expected_content = 'Issue created'
+ expect(page).to have_content(expected_content)
- click_link 'Boards'
+ find('body').send_keys('e')
- expect(page).not_to have_content(expected_content)
- end
- end
+ click_link 'Boards'
- describe 'when user has made changes' do
- it 'shows a warning and can stay on page', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/397683' do
- content = 'new issue content'
+ expect(page).not_to have_content(expected_content)
+ end
+ end
- find('body').send_keys('e')
- fill_in 'issue-description', with: content
+ context 'when user has made changes' do
+ it 'shows a warning and can stay on page' do
+ content = 'new issue content'
- click_link 'Boards'
+ find('body').send_keys('e')
+ fill_in 'issue-description', with: content
+ click_link 'Boards' do
page.driver.browser.switch_to.alert.dismiss
-
- click_button 'Save changes'
- wait_for_requests
-
- expect(page).to have_content(content)
end
- end
- end
- context 'within issue 2' do
- before do
- visit project_issue_path(project, issue2)
+ click_button 'Save changes'
wait_for_requests
- end
- describe 'when user has made changes' do
- it 'shows a warning and can leave page', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410497' do
- content = 'new issue content'
- find('body').send_keys('e')
- fill_in 'issue-description', with: content
+ expect(page).to have_content(content)
+ end
- click_link 'Boards'
+ it 'shows a warning and can leave page' do
+ content = 'new issue content'
+ find('body').send_keys('e')
+ fill_in 'issue-description', with: content
+ click_link 'Boards' do
page.driver.browser.switch_to.alert.accept
-
- expect(page).not_to have_content(content)
end
+
+ expect(page).not_to have_content(content)
end
end
end
diff --git a/spec/features/issues/issue_state_spec.rb b/spec/features/issues/issue_state_spec.rb
index 758dafccb86..2a8b33183bb 100644
--- a/spec/features/issues/issue_state_spec.rb
+++ b/spec/features/issues/issue_state_spec.rb
@@ -3,53 +3,71 @@
require 'spec_helper'
RSpec.describe 'issue state', :js, feature_category: :team_planning do
- let_it_be(:project) { create(:project) }
+ include CookieHelper
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
let_it_be(:user) { create(:user) }
before do
project.add_developer(user)
sign_in(user)
+ set_cookie('new-actions-popover-viewed', 'true')
end
shared_examples 'issue closed' do |selector|
it 'can close an issue' do
- wait_for_requests
+ expect(page).to have_selector('[data-testid="issue-state-badge"]')
- expect(find('.status-box')).to have_content 'Open'
+ expect(find('[data-testid="issue-state-badge"]')).to have_content 'Open'
within selector do
click_button 'Close issue'
wait_for_requests
end
- expect(find('.status-box')).to have_content 'Closed'
+ expect(find('[data-testid="issue-state-badge"]')).to have_content 'Closed'
end
end
shared_examples 'issue reopened' do |selector|
it 'can reopen an issue' do
- wait_for_requests
+ expect(page).to have_selector('[data-testid="issue-state-badge"]')
- expect(find('.status-box')).to have_content 'Closed'
+ expect(find('[data-testid="issue-state-badge"]')).to have_content 'Closed'
within selector do
click_button 'Reopen issue'
wait_for_requests
end
- expect(find('.status-box')).to have_content 'Open'
+ expect(find('[data-testid="issue-state-badge"]')).to have_content 'Open'
end
end
- describe 'when open', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/297348' do
+ describe 'when open' do
context 'when clicking the top `Close issue` button', :aggregate_failures do
- let(:open_issue) { create(:issue, project: project) }
+ context 'when move_close_into_dropdown FF is disabled' do
+ let(:open_issue) { create(:issue, project: project) }
- before do
- visit project_issue_path(project, open_issue)
+ before do
+ stub_feature_flags(move_close_into_dropdown: false)
+ visit project_issue_path(project, open_issue)
+ end
+
+ it_behaves_like 'issue closed', '.detail-page-header-actions'
end
- it_behaves_like 'issue closed', '.detail-page-header'
+ context 'when move_close_into_dropdown FF is enabled' do
+ let(:open_issue) { create(:issue, project: project) }
+
+ before do
+ visit project_issue_path(project, open_issue)
+ find('#new-actions-header-dropdown > button').click
+ end
+
+ it_behaves_like 'issue closed', '.dropdown-menu-right'
+ end
end
context 'when clicking the bottom `Close issue` button', :aggregate_failures do
@@ -63,15 +81,29 @@ RSpec.describe 'issue state', :js, feature_category: :team_planning do
end
end
- describe 'when closed', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/297201' do
+ describe 'when closed' do
context 'when clicking the top `Reopen issue` button', :aggregate_failures do
- let(:closed_issue) { create(:issue, project: project, state: 'closed') }
+ context 'when move_close_into_dropdown FF is disabled' do
+ let(:closed_issue) { create(:issue, project: project, state: 'closed', author: user) }
- before do
- visit project_issue_path(project, closed_issue)
+ before do
+ stub_feature_flags(move_close_into_dropdown: false)
+ visit project_issue_path(project, closed_issue)
+ end
+
+ it_behaves_like 'issue reopened', '.detail-page-header-actions'
end
- it_behaves_like 'issue reopened', '.detail-page-header'
+ context 'when move_close_into_dropdown FF is enabled' do
+ let(:closed_issue) { create(:issue, project: project, state: 'closed', author: user) }
+
+ before do
+ visit project_issue_path(project, closed_issue)
+ find('#new-actions-header-dropdown > button').click
+ end
+
+ it_behaves_like 'issue reopened', '.dropdown-menu-right'
+ end
end
context 'when clicking the bottom `Reopen issue` button', :aggregate_failures do
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index 4512e88ae72..a6ed0b52e7d 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -103,7 +103,7 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning
let(:namespace) { create(:namespace) }
let(:regular_project) { create(:project, title: project_title, service_desk_enabled: false) }
let(:service_desk_project) { build(:project, :private, namespace: namespace, service_desk_enabled: true) }
- let(:service_desk_issue) { create(:issue, project: service_desk_project, author: ::User.support_bot) }
+ let(:service_desk_issue) { create(:issue, project: service_desk_project, author: ::Users::Internal.support_bot) }
before do
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true)
diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb
index a390dca6822..293b6c53eb5 100644
--- a/spec/features/issues/note_polling_spec.rb
+++ b/spec/features/issues/note_polling_spec.rb
@@ -19,22 +19,6 @@ RSpec.describe 'Issue notes polling', :js, feature_category: :team_planning do
expect(page).to have_selector("#note_#{note.id}", text: 'Looks good!')
end
-
- context 'when action_cable_notes is disabled' do
- before do
- stub_feature_flags(action_cable_notes: false)
- end
-
- it 'displays the new comment' do
- visit project_issue_path(project, issue)
- close_rich_text_promo_popover_if_present
-
- note = create(:note, noteable: issue, project: project, note: 'Looks good!')
- wait_for_requests
-
- expect(page).to have_selector("#note_#{note.id}", text: 'Looks good!')
- end
- end
end
describe 'updates' do
diff --git a/spec/features/issues/service_desk_spec.rb b/spec/features/issues/service_desk_spec.rb
index 1b99c8b39d3..120b4ddb6e1 100644
--- a/spec/features/issues/service_desk_spec.rb
+++ b/spec/features/issues/service_desk_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'Service Desk Issue Tracker', :js, feature_category: :service_desk do
let(:project) { create(:project, :private, service_desk_enabled: true) }
- let_it_be(:user) { create(:user) }
- let_it_be(:support_bot) { User.support_bot }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:support_bot) { Users::Internal.support_bot }
before do
# The following two conditions equate to Gitlab::ServiceDesk.supported == true
@@ -252,7 +252,7 @@ RSpec.describe 'Service Desk Issue Tracker', :js, feature_category: :service_des
end
it 'shows service_desk_reply_to in issues list' do
- expect(page).to have_text('by GitLab Support Bot')
+ expect(page).to have_text('by service.desk@example.com via GitLab Support Bot')
end
end
end
diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb
index 2c537cefa5e..c503c18be8d 100644
--- a/spec/features/issues/todo_spec.rb
+++ b/spec/features/issues/todo_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Manually create a todo item from issue', :js, feature_category: :team_planning do
let!(:project) { create(:project) }
let!(:issue) { create(:issue, project: project) }
- let!(:user) { create(:user) }
+ let!(:user) { create(:user, :no_super_sidebar) }
before do
project.add_maintainer(user)
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index 76b07d903bc..857cb1f39a2 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe "User creates issue", feature_category: :team_planning do
sign_out(:user)
end
- it "redirects to signin then back to new issue after signin", :js, quarantine: 'https://gitlab.com/gitlab-org/quality/engineering-productivity/master-broken-incidents/-/issues/1486' do
+ it "redirects to signin then back to new issue after signin", :js do
create(:issue, project: project)
visit project_issues_path(project)
diff --git a/spec/features/issues/user_sees_live_update_spec.rb b/spec/features/issues/user_sees_live_update_spec.rb
index 860603ad546..0822542ca02 100644
--- a/spec/features/issues/user_sees_live_update_spec.rb
+++ b/spec/features/issues/user_sees_live_update_spec.rb
@@ -19,34 +19,32 @@ RSpec.describe 'Issues > User sees live update', :js, feature_category: :team_pl
expect(page).to have_text("new title")
issue.update!(title: "updated title")
-
wait_for_requests
+
expect(page).to have_text("updated title")
end
end
describe 'confidential issue#show' do
- it 'shows confidential sibebar information as confidential and can be turned off', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/254644' do
+ it 'shows confidential sidebar information as confidential and can be turned off' do
issue = create(:issue, :confidential, project: project)
visit project_issue_path(project, issue)
- expect(page).to have_css('.issuable-note-warning')
- expect(find('.issuable-sidebar-item.confidentiality')).to have_css('.is-active')
- expect(find('.issuable-sidebar-item.confidentiality')).not_to have_css('.not-active')
-
- find('.confidential-edit').click
- expect(page).to have_css('.sidebar-item-warning-message')
+ expect(page).to have_text('This is a confidential issue. People without permission will never get a notification.')
- within('.sidebar-item-warning-message') do
- find('[data-testid="confidential-toggle"]').click
+ within '.block.confidentiality' do
+ click_button 'Edit'
end
- wait_for_requests
+ expect(page).to have_text('You are going to turn off the confidentiality. This means everyone will be able to see and leave a comment on this issue.')
+
+ click_button 'Turn off'
visit project_issue_path(project, issue)
- expect(page).not_to have_css('.is-active')
+ expect(page).not_to have_css('.gl-badge', text: 'Confidential')
+ expect(page).not_to have_text('This is a confidential issue. People without permission will never get a notification.')
end
end
end
diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb
index dc149ccc698..c15716243ae 100644
--- a/spec/features/issues/user_uses_quick_actions_spec.rb
+++ b/spec/features/issues/user_uses_quick_actions_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'Issues > User uses quick actions', :js, feature_category: :team_
context "issuable common quick actions" do
let(:new_url_opts) { {} }
- let(:maintainer) { create(:user) }
+ let(:maintainer) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :public) }
let!(:label_bug) { create(:label, project: project, title: 'bug') }
let!(:label_feature) { create(:label, project: project, title: 'feature') }
@@ -26,7 +26,7 @@ RSpec.describe 'Issues > User uses quick actions', :js, feature_category: :team_
end
describe 'issue-only commands' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :public, :repository) }
let(:issue) { create(:issue, project: project, due_date: Date.new(2016, 8, 28)) }
diff --git a/spec/features/jira_connect/branches_spec.rb b/spec/features/jira_connect/branches_spec.rb
index 25dc14a1dc9..ae1dd551c47 100644
--- a/spec/features/jira_connect/branches_spec.rb
+++ b/spec/features/jira_connect/branches_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'Create GitLab branches from Jira', :js, feature_category: :integrations do
include ListboxHelpers
- let_it_be(:alice) { create(:user, name: 'Alice') }
- let_it_be(:bob) { create(:user, name: 'Bob') }
+ let_it_be(:alice) { create(:user, :no_super_sidebar, name: 'Alice') }
+ let_it_be(:bob) { create(:user, :no_super_sidebar, name: 'Bob') }
let_it_be(:project1) { create(:project, :repository, namespace: alice.namespace, title: 'foo') }
let_it_be(:project2) { create(:project, :repository, namespace: alice.namespace, title: 'bar') }
diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index eb79d6e64f3..0cb712622f2 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Labels Hierarchy', :js, feature_category: :team_planning do
include FilteredSearchHelpers
include ContentEditorHelpers
- let!(:user) { create(:user) }
+ let!(:user) { create(:user, :no_super_sidebar) }
let!(:grandparent) { create(:group) }
let!(:parent) { create(:group, parent: grandparent) }
let!(:child) { create(:group, parent: parent) }
diff --git a/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb b/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb
index 446f6a470de..fea4841c5ea 100644
--- a/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb
+++ b/spec/features/merge_request/user_closes_reopens_merge_request_state_spec.rb
@@ -2,8 +2,7 @@
require 'spec_helper'
-RSpec.describe 'User closes/reopens a merge request', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/297500',
- feature_category: :code_review_workflow do
+RSpec.describe 'User closes/reopens a merge request', :js, feature_category: :code_review_workflow do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
@@ -13,89 +12,67 @@ RSpec.describe 'User closes/reopens a merge request', :js, quarantine: 'https://
end
describe 'when open' do
- context 'when clicking the top `Close merge request` link', :aggregate_failures do
- let(:open_merge_request) { create(:merge_request, source_project: project, target_project: project) }
+ let(:open_merge_request) { create(:merge_request, source_project: project, target_project: project) }
- before do
- visit merge_request_path(open_merge_request)
- end
+ before do
+ visit merge_request_path(open_merge_request)
+ end
- it 'can close a merge request' do
- expect(find('.status-box')).to have_content 'Open'
+ context 'when clicking the top `Close merge request` button', :aggregate_failures do
+ it 'closes the merge request' do
+ expect(page).to have_css('.gl-badge', text: 'Open')
within '.detail-page-header' do
- click_button 'Toggle dropdown'
- click_link 'Close merge request'
+ click_button 'Merge request actions'
+ click_button 'Close merge request'
end
- wait_for_requests
-
- expect(find('.status-box')).to have_content 'Closed'
+ expect(page).to have_css('.gl-badge', text: 'Closed')
end
end
context 'when clicking the bottom `Close merge request` button', :aggregate_failures do
- let(:open_merge_request) { create(:merge_request, source_project: project, target_project: project) }
-
- before do
- visit merge_request_path(open_merge_request)
- end
-
- it 'can close a merge request' do
- expect(find('.status-box')).to have_content 'Open'
+ it 'closes the merge request' do
+ expect(page).to have_css('.gl-badge', text: 'Open')
within '.timeline-content-form' do
click_button 'Close merge request'
-
- # Clicking the bottom `Close merge request` button does not yet update
- # the header status so for now we'll check that the button text changes
- expect(page).not_to have_button 'Close merge request'
- expect(page).to have_button 'Reopen merge request'
end
+
+ expect(page).to have_css('.gl-badge', text: 'Closed')
end
end
end
describe 'when closed' do
- context 'when clicking the top `Reopen merge request` link', :aggregate_failures do
- let(:closed_merge_request) { create(:merge_request, source_project: project, target_project: project, state: 'closed') }
+ let(:closed_merge_request) { create(:merge_request, source_project: project, target_project: project, state: 'closed') }
- before do
- visit merge_request_path(closed_merge_request)
- end
+ before do
+ visit merge_request_path(closed_merge_request)
+ end
- it 'can reopen a merge request' do
- expect(find('.status-box')).to have_content 'Closed'
+ context 'when clicking the top `Reopen merge request` button', :aggregate_failures do
+ it 'reopens the merge request' do
+ expect(page).to have_css('.gl-badge', text: 'Closed')
within '.detail-page-header' do
- click_button 'Toggle dropdown'
- click_link 'Reopen merge request'
+ click_button 'Merge request actions'
+ click_button 'Reopen merge request'
end
- wait_for_requests
-
- expect(find('.status-box')).to have_content 'Open'
+ expect(page).to have_css('.gl-badge', text: 'Open')
end
end
context 'when clicking the bottom `Reopen merge request` button', :aggregate_failures do
- let(:closed_merge_request) { create(:merge_request, source_project: project, target_project: project, state: 'closed') }
-
- before do
- visit merge_request_path(closed_merge_request)
- end
-
- it 'can reopen a merge request' do
- expect(find('.status-box')).to have_content 'Closed'
+ it 'reopens the merge request' do
+ expect(page).to have_css('.gl-badge', text: 'Closed')
within '.timeline-content-form' do
click_button 'Reopen merge request'
-
- # Clicking the bottom `Reopen merge request` button does not yet update
- # the header status so for now we'll check that the button text changes
- expect(page).not_to have_button 'Reopen merge request'
- expect(page).to have_button 'Close merge request'
end
+
+ expect(page).to have_css('.gl-badge', text: 'Open')
end
end
end
diff --git a/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb b/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
index a96ec1f68aa..df39fe492c1 100644
--- a/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
+++ b/spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb
@@ -48,7 +48,8 @@ RSpec.describe 'Batch diffs', :js, feature_category: :code_review_workflow do
context 'when user visits a URL with a link directly to to a discussion' do
context 'which is in the first batched page of diffs' do
- it 'scrolls to the correct discussion' do
+ it 'scrolls to the correct discussion',
+ quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410029' } do
page.within get_first_diff do
click_link('just now')
end
diff --git a/spec/features/merge_request/user_merges_merge_request_spec.rb b/spec/features/merge_request/user_merges_merge_request_spec.rb
index 402405e1fb6..aee42784d05 100644
--- a/spec/features/merge_request/user_merges_merge_request_spec.rb
+++ b/spec/features/merge_request/user_merges_merge_request_spec.rb
@@ -5,7 +5,7 @@ require "spec_helper"
RSpec.describe "User merges a merge request", :js, feature_category: :code_review_workflow do
include ContentEditorHelpers
- let(:user) { project.first_owner }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
@@ -24,7 +24,7 @@ RSpec.describe "User merges a merge request", :js, feature_category: :code_revie
end
context 'sidebar merge requests counter' do
- let(:project) { create(:project, :public, :repository) }
+ let_it_be(:project) { create(:project, :public, :repository, namespace: user.namespace) }
let!(:merge_request) { create(:merge_request, source_project: project) }
it 'decrements the open MR count', :sidekiq_inline do
diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
deleted file mode 100644
index ebec8a6d2ea..00000000000
--- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
+++ /dev/null
@@ -1,150 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Merge request > User merges when pipeline succeeds', :js, feature_category: :code_review_workflow do
- let(:project) { create(:project, :public, :repository) }
- let(:user) { project.creator }
- let(:merge_request) do
- create(
- :merge_request_with_diffs,
- source_project: project,
- author: user,
- title: 'Bug NS-04',
- merge_params: { force_remove_source_branch: '1' }
- )
- end
-
- let(:pipeline) do
- create(
- :ci_pipeline,
- project: project,
- sha: merge_request.diff_head_sha,
- ref: merge_request.source_branch,
- head_pipeline_of: merge_request
- )
- end
-
- before do
- project.add_maintainer(user)
- end
-
- context 'when there is active pipeline for merge request' do
- before do
- create(:ci_build, pipeline: pipeline)
- stub_feature_flags(auto_merge_labels_mr_widget: true)
-
- sign_in(user)
- visit project_merge_request_path(project, merge_request)
- end
-
- describe 'enabling Merge when pipeline succeeds' do
- shared_examples 'Set to auto-merge activator' do
- it 'activates the Merge when pipeline succeeds feature', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410055' do
- click_button "Set to auto-merge"
-
- expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds"
- expect(page).to have_content "Source branch will not be deleted"
- expect(page).to have_selector ".js-cancel-auto-merge"
- visit project_merge_request_path(project, merge_request) # Needed to refresh the page
- expect(page).to have_content /enabled an automatic merge when the pipeline for \h{8} succeeds/i
- end
- end
-
- context "when enabled immediately" do
- it_behaves_like 'Set to auto-merge activator'
- end
-
- context 'when enabled after it was previously canceled' do
- before do
- click_button "Set to auto-merge"
-
- wait_for_requests
-
- click_button "Cancel auto-merge"
-
- wait_for_requests
-
- expect(page).to have_content 'Set to auto-merge'
- end
-
- it_behaves_like 'Set to auto-merge activator'
- end
-
- context 'when it was enabled and then canceled' do
- let(:merge_request) do
- create(
- :merge_request_with_diffs,
- :merge_when_pipeline_succeeds,
- source_project: project,
- title: 'Bug NS-04',
- author: user,
- merge_user: user
- )
- end
-
- before do
- merge_request.merge_params['force_remove_source_branch'] = '0'
- merge_request.save!
- click_button "Cancel auto-merge"
- end
-
- it_behaves_like 'Set to auto-merge activator'
- end
- end
- end
-
- context 'when merge when pipeline succeeds is enabled' do
- let(:merge_request) do
- create(
- :merge_request_with_diffs,
- :simple,
- :merge_when_pipeline_succeeds,
- source_project: project,
- author: user,
- merge_user: user,
- title: 'MepMep'
- )
- end
-
- let!(:build) do
- create(:ci_build, pipeline: pipeline)
- end
-
- before do
- stub_feature_flags(auto_merge_labels_mr_widget: true)
- sign_in user
- visit project_merge_request_path(project, merge_request)
- end
-
- it 'allows to cancel the automatic merge', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410494' do
- click_button "Cancel auto-merge"
-
- expect(page).to have_button "Set to auto-merge"
-
- refresh
-
- expect(page).to have_content "canceled the automatic merge"
- end
- end
-
- context 'when pipeline is not active' do
- it 'does not allow to enable merge when pipeline succeeds' do
- stub_feature_flags(auto_merge_labels_mr_widget: false)
-
- visit project_merge_request_path(project, merge_request)
-
- expect(page).not_to have_link 'Merge when pipeline succeeds'
- end
- end
-
- context 'when pipeline is not active and auto_merge_labels_mr_widget on' do
- it 'does not allow to enable merge when pipeline succeeds' do
- stub_feature_flags(auto_merge_labels_mr_widget: true)
-
- visit project_merge_request_path(project, merge_request)
-
- expect(page).not_to have_link 'Set to auto-merge'
- end
- end
-end
diff --git a/spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb b/spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb
index 63f03ae64e0..c12816b6521 100644
--- a/spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb
+++ b/spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb
@@ -6,17 +6,16 @@ RSpec.describe 'Merge request > User opens checkout branch modal', :js, feature_
include ProjectForksHelper
include CookieHelper
- let(:project) { create(:project, :public, :repository) }
- let(:user) { project.creator }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :public, :repository, namespace: user.namespace) }
before do
- project.add_maintainer(user)
sign_in(user)
set_cookie('new-actions-popover-viewed', 'true')
end
describe 'for fork' do
- let(:author) { create(:user) }
+ let(:author) { create(:user, :no_super_sidebar) }
let(:source_project) { fork_project(project, author, repository: true) }
let(:merge_request) do
diff --git a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
index 21c62b0d0d8..e55ecd2a531 100644
--- a/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
+++ b/spec/features/merge_request/user_sees_check_out_branch_modal_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe 'Merge request > User sees check out branch modal', :js, feature_category: :code_review_workflow do
include CookieHelper
- let(:project) { create(:project, :public, :repository) }
- let(:user) { project.creator }
- let(:merge_request) { create(:merge_request, source_project: project) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :public, :repository, creator: user) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
let(:modal_window_title) { 'Check out, review, and resolve locally' }
before do
diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
index d237faba663..dd1119c5648 100644
--- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
@@ -119,37 +119,6 @@ RSpec.describe 'Merge request > User sees deployment widget', :js, feature_categ
end
before do
- stub_feature_flags(review_apps_redeploy_mr_widget: false)
- build.success!
- deployment.update!(on_stop: manual.name)
- visit project_merge_request_path(project, merge_request)
- wait_for_requests
- end
-
- it 'does start build when stop button clicked' do
- accept_gl_confirm(button_text: 'Stop environment') do
- find('.js-stop-env').click
- end
-
- expect(page).to have_content('close_app')
- end
-
- context 'for reporter' do
- let(:role) { :reporter }
-
- it 'does not show stop button' do
- expect(page).not_to have_selector('.js-stop-env')
- end
- end
- end
-
- context 'with stop action with the review_apps_redeploy_mr_widget feature flag turned on' do
- let(:manual) do
- create(:ci_build, :manual, pipeline: pipeline, name: 'close_app', environment: environment.name)
- end
-
- before do
- stub_feature_flags(review_apps_redeploy_mr_widget: true)
build.success!
deployment.update!(on_stop: manual.name)
visit project_merge_request_path(project, merge_request)
@@ -173,9 +142,8 @@ RSpec.describe 'Merge request > User sees deployment widget', :js, feature_categ
end
end
- context 'with redeploy action and with the review_apps_redeploy_mr_widget feature flag turned on' do
+ context 'with redeploy action' do
before do
- stub_feature_flags(review_apps_redeploy_mr_widget: true)
build.success!
environment.update!(state: 'stopped')
visit project_merge_request_path(project, merge_request)
diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
index add8e9f30de..e052d06c158 100644
--- a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
@@ -48,60 +48,29 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
end
# rubocop:enable RSpec/AvoidConditionalStatements
- context 'when a user created a merge request in the parent project' do
- let!(:merge_request) do
- create(
- :merge_request,
- source_project: project,
- target_project: project,
- source_branch: 'feature',
- target_branch: 'master'
- )
- end
-
- let!(:push_pipeline) do
- Ci::CreatePipelineService.new(project, user, ref: 'feature')
- .execute(:push)
- .payload
- end
-
- let!(:detached_merge_request_pipeline) do
- Ci::CreatePipelineService.new(project, user, ref: 'feature')
- .execute(:merge_request_event, merge_request: merge_request)
- .payload
- end
-
+ context 'with feature flag `mr_pipelines_graphql turned off`' do
before do
- visit project_merge_request_path(project, merge_request)
-
- page.within('.merge-request-tabs') do
- click_link('Pipelines')
- end
- end
-
- it 'sees branch pipelines and detached merge request pipelines in correct order' do
- page.within('.ci-table') do
- expect(page).to have_selector('[data-testid="ci-badge-created"]', count: 2)
- expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{detached_merge_request_pipeline.id}")
- end
+ stub_feature_flags(mr_pipelines_graphql: false)
end
- it 'sees the latest detached merge request pipeline as the head pipeline', :sidekiq_might_not_need_inline do
- click_link "Overview"
-
- page.within('.ci-widget-content') do
- expect(page).to have_content("##{detached_merge_request_pipeline.id}")
+ context 'when a user created a merge request in the parent project' do
+ let!(:merge_request) do
+ create(
+ :merge_request,
+ source_project: project,
+ target_project: project,
+ source_branch: 'feature',
+ target_branch: 'master'
+ )
end
- end
- context 'when a user updated a merge request in the parent project', :sidekiq_might_not_need_inline do
- let!(:push_pipeline_2) do
+ let!(:push_pipeline) do
Ci::CreatePipelineService.new(project, user, ref: 'feature')
.execute(:push)
.payload
end
- let!(:detached_merge_request_pipeline_2) do
+ let!(:detached_merge_request_pipeline) do
Ci::CreatePipelineService.new(project, user, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request)
.payload
@@ -117,192 +86,184 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
- expect(page).to have_selector('[data-testid="ci-badge-pending"]', count: 4)
-
- expect(all('[data-testid="pipeline-url-link"]')[0])
- .to have_content("##{detached_merge_request_pipeline_2.id}")
-
- expect(all('[data-testid="pipeline-url-link"]')[1])
- .to have_content("##{detached_merge_request_pipeline.id}")
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'created', count: 2)
+ expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{detached_merge_request_pipeline.id}")
+ end
+ end
- expect(all('[data-testid="pipeline-url-link"]')[2])
- .to have_content("##{push_pipeline_2.id}")
+ it 'sees the latest detached merge request pipeline as the head pipeline', :sidekiq_might_not_need_inline do
+ click_link "Overview"
- expect(all('[data-testid="pipeline-url-link"]')[3])
- .to have_content("##{push_pipeline.id}")
+ page.within('.ci-widget-content') do
+ expect(page).to have_content("##{detached_merge_request_pipeline.id}")
end
end
- it 'sees detached tag for detached merge request pipelines' do
- page.within('.ci-table') do
- expect(all('.pipeline-tags')[0])
- .to have_content(expected_detached_mr_tag)
+ context 'when a user updated a merge request in the parent project', :sidekiq_might_not_need_inline do
+ let!(:push_pipeline_2) do
+ Ci::CreatePipelineService.new(project, user, ref: 'feature')
+ .execute(:push)
+ .payload
+ end
- expect(all('.pipeline-tags')[1])
- .to have_content(expected_detached_mr_tag)
+ let!(:detached_merge_request_pipeline_2) do
+ Ci::CreatePipelineService.new(project, user, ref: 'feature')
+ .execute(:merge_request_event, merge_request: merge_request)
+ .payload
+ end
- expect(all('.pipeline-tags')[2])
- .not_to have_content(expected_detached_mr_tag)
+ before do
+ visit project_merge_request_path(project, merge_request)
- expect(all('.pipeline-tags')[3])
- .not_to have_content(expected_detached_mr_tag)
+ page.within('.merge-request-tabs') do
+ click_link('Pipelines')
+ end
end
- end
- it 'sees the latest detached merge request pipeline as the head pipeline' do
- click_link 'Overview'
+ it 'sees branch pipelines and detached merge request pipelines in correct order' do
+ page.within('.ci-table') do
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'pending', count: 4)
- page.within('.ci-widget-content') do
- expect(page).to have_content("##{detached_merge_request_pipeline_2.id}")
+ expect(all('[data-testid="pipeline-url-link"]')[0])
+ .to have_content("##{detached_merge_request_pipeline_2.id}")
+
+ expect(all('[data-testid="pipeline-url-link"]')[1])
+ .to have_content("##{detached_merge_request_pipeline.id}")
+
+ expect(all('[data-testid="pipeline-url-link"]')[2])
+ .to have_content("##{push_pipeline_2.id}")
+
+ expect(all('[data-testid="pipeline-url-link"]')[3])
+ .to have_content("##{push_pipeline.id}")
+ end
end
- end
- end
- context 'when a user created a merge request in the parent project' do
- before do
- visit project_merge_request_path(project, merge_request)
+ it 'sees detached tag for detached merge request pipelines' do
+ page.within('.ci-table') do
+ expect(all('.pipeline-tags')[0])
+ .to have_content(expected_detached_mr_tag)
- page.within('.merge-request-tabs') do
- click_link('Pipelines')
+ expect(all('.pipeline-tags')[1])
+ .to have_content(expected_detached_mr_tag)
+
+ expect(all('.pipeline-tags')[2])
+ .not_to have_content(expected_detached_mr_tag)
+
+ expect(all('.pipeline-tags')[3])
+ .not_to have_content(expected_detached_mr_tag)
+ end
end
- end
- context 'when a user merges a merge request in the parent project', :sidekiq_might_not_need_inline do
- before do
+ it 'sees the latest detached merge request pipeline as the head pipeline' do
click_link 'Overview'
- click_button 'Set to auto-merge'
- wait_for_requests
+ page.within('.ci-widget-content') do
+ expect(page).to have_content("##{detached_merge_request_pipeline_2.id}")
+ end
end
+ end
- context 'when detached merge request pipeline is pending' do
- it 'waits the head pipeline' do
- expect(page).to have_content mr_widget_title
- expect(page).to have_button('Cancel auto-merge')
+ context 'when a user created a merge request in the parent project' do
+ before do
+ visit project_merge_request_path(project, merge_request)
+
+ page.within('.merge-request-tabs') do
+ click_link('Pipelines')
end
end
- context 'when branch pipeline succeeds' do
+ context 'when a user merges a merge request in the parent project', :sidekiq_might_not_need_inline do
before do
click_link 'Overview'
- push_pipeline.reload.succeed!
+ click_button 'Set to auto-merge'
wait_for_requests
end
- it 'waits the head pipeline' do
- expect(page).to have_content mr_widget_title
- expect(page).to have_button('Cancel auto-merge')
+ context 'when detached merge request pipeline is pending' do
+ it 'waits the head pipeline' do
+ expect(page).to have_content mr_widget_title
+ expect(page).to have_button('Cancel auto-merge')
+ end
end
- end
- end
- end
- context 'when there are no `merge_requests` keyword in .gitlab-ci.yml' do
- let(:config) do
- {
- build: {
- script: 'build'
- },
- test: {
- script: 'test'
- },
- deploy: {
- script: 'deploy'
- }
- }
- end
-
- it 'sees a branch pipeline in pipeline tab' do
- page.within('.ci-table') do
- expect(page).to have_selector('[data-testid="ci-badge-created"]', count: 1)
- expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{push_pipeline.id}")
- end
- end
+ context 'when branch pipeline succeeds' do
+ before do
+ click_link 'Overview'
+ push_pipeline.reload.succeed!
- it 'sees the latest branch pipeline as the head pipeline', :sidekiq_might_not_need_inline do
- click_link 'Overview'
+ wait_for_requests
+ end
- page.within('.ci-widget-content') do
- expect(page).to have_content("##{push_pipeline.id}")
+ it 'waits the head pipeline' do
+ expect(page).to have_content mr_widget_title
+ expect(page).to have_button('Cancel auto-merge')
+ end
+ end
end
end
- end
- end
-
- context 'when a user created a merge request from a forked project to the parent project', :sidekiq_might_not_need_inline do
- let(:merge_request) do
- create(
- :merge_request,
- source_project: forked_project,
- target_project: project,
- source_branch: 'feature',
- target_branch: 'master'
- )
- end
-
- let!(:push_pipeline) do
- Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
- .execute(:push)
- .payload
- end
-
- let!(:detached_merge_request_pipeline) do
- Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
- .execute(:merge_request_event, merge_request: merge_request)
- .payload
- end
- let(:forked_project) { fork_project(project, user2, repository: true) }
- let(:user2) { create(:user) }
-
- before do
- forked_project.add_maintainer(user2)
-
- stub_feature_flags(auto_merge_labels_mr_widget: false)
+ context 'when there are no `merge_requests` keyword in .gitlab-ci.yml' do
+ let(:config) do
+ {
+ build: {
+ script: 'build'
+ },
+ test: {
+ script: 'test'
+ },
+ deploy: {
+ script: 'deploy'
+ }
+ }
+ end
- visit project_merge_request_path(project, merge_request)
+ it 'sees a branch pipeline in pipeline tab' do
+ page.within('.ci-table') do
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'created', count: 1)
+ expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{push_pipeline.id}")
+ end
+ end
- page.within('.merge-request-tabs') do
- click_link('Pipelines')
- end
- end
+ it 'sees the latest branch pipeline as the head pipeline', :sidekiq_might_not_need_inline do
+ click_link 'Overview'
- it 'sees branch pipelines and detached merge request pipelines in correct order' do
- page.within('.ci-table') do
- expect(page).to have_selector('[data-testid="ci-badge-pending"]', count: 2)
- expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{detached_merge_request_pipeline.id}")
+ page.within('.ci-widget-content') do
+ expect(page).to have_content("##{push_pipeline.id}")
+ end
+ end
end
end
- it 'sees the latest detached merge request pipeline as the head pipeline' do
- click_link "Overview"
-
- page.within('.ci-widget-content') do
- expect(page).to have_content("##{detached_merge_request_pipeline.id}")
+ context 'when a user created a merge request from a forked project to the parent project', :sidekiq_might_not_need_inline do
+ let(:merge_request) do
+ create(
+ :merge_request,
+ source_project: forked_project,
+ target_project: project,
+ source_branch: 'feature',
+ target_branch: 'master'
+ )
end
- end
- it 'sees pipeline list in forked project' do
- visit project_pipelines_path(forked_project)
-
- expect(page).to have_selector('[data-testid="ci-badge-pending"]', count: 2)
- end
-
- context 'when a user updated a merge request from a forked project to the parent project' do
- let!(:push_pipeline_2) do
+ let!(:push_pipeline) do
Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
.execute(:push)
.payload
end
- let!(:detached_merge_request_pipeline_2) do
+ let!(:detached_merge_request_pipeline) do
Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
.execute(:merge_request_event, merge_request: merge_request)
.payload
end
+ let(:forked_project) { fork_project(project, user2, repository: true) }
+ let(:user2) { create(:user) }
+
before do
+ forked_project.add_maintainer(user2)
+
visit project_merge_request_path(project, merge_request)
page.within('.merge-request-tabs') do
@@ -312,35 +273,8 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
- expect(page).to have_selector('[data-testid="ci-badge-pending"]', count: 4)
-
- expect(all('[data-testid="pipeline-url-link"]')[0])
- .to have_content("##{detached_merge_request_pipeline_2.id}")
-
- expect(all('[data-testid="pipeline-url-link"]')[1])
- .to have_content("##{detached_merge_request_pipeline.id}")
-
- expect(all('[data-testid="pipeline-url-link"]')[2])
- .to have_content("##{push_pipeline_2.id}")
-
- expect(all('[data-testid="pipeline-url-link"]')[3])
- .to have_content("##{push_pipeline.id}")
- end
- end
-
- it 'sees detached tag for detached merge request pipelines' do
- page.within('.ci-table') do
- expect(all('.pipeline-tags')[0])
- .to have_content(expected_detached_mr_tag)
-
- expect(all('.pipeline-tags')[1])
- .to have_content(expected_detached_mr_tag)
-
- expect(all('.pipeline-tags')[2])
- .not_to have_content(expected_detached_mr_tag)
-
- expect(all('.pipeline-tags')[3])
- .not_to have_content(expected_detached_mr_tag)
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'pending', count: 2)
+ expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{detached_merge_request_pipeline.id}")
end
end
@@ -348,88 +282,158 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
click_link "Overview"
page.within('.ci-widget-content') do
- expect(page).to have_content("##{detached_merge_request_pipeline_2.id}")
+ expect(page).to have_content("##{detached_merge_request_pipeline.id}")
end
end
it 'sees pipeline list in forked project' do
visit project_pipelines_path(forked_project)
- expect(page).to have_selector('[data-testid="ci-badge-pending"]', count: 4)
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'pending', count: 2)
end
- end
- context 'when the latest pipeline is running in the parent project' do
- before do
- create(:ci_pipeline,
- source: :merge_request_event,
- project: project,
- ref: 'feature',
- sha: merge_request.diff_head_sha,
- user: user,
- merge_request: merge_request,
- status: :running)
- merge_request.update_head_pipeline
- end
+ context 'when a user updated a merge request from a forked project to the parent project' do
+ let!(:push_pipeline_2) do
+ Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
+ .execute(:push)
+ .payload
+ end
+
+ let!(:detached_merge_request_pipeline_2) do
+ Ci::CreatePipelineService.new(forked_project, user2, ref: 'feature')
+ .execute(:merge_request_event, merge_request: merge_request)
+ .payload
+ end
- context 'when the previous pipeline failed in the fork project' do
before do
- detached_merge_request_pipeline.reload.drop!
+ visit project_merge_request_path(project, merge_request)
+
+ page.within('.merge-request-tabs') do
+ click_link('Pipelines')
+ end
end
- context 'when the parent project enables pipeline must succeed' do
- before do
- project.update!(only_allow_merge_if_pipeline_succeeds: true)
+ it 'sees branch pipelines and detached merge request pipelines in correct order' do
+ page.within('.ci-table') do
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'pending', count: 4)
+
+ expect(all('[data-testid="pipeline-url-link"]')[0])
+ .to have_content("##{detached_merge_request_pipeline_2.id}")
+
+ expect(all('[data-testid="pipeline-url-link"]')[1])
+ .to have_content("##{detached_merge_request_pipeline.id}")
+
+ expect(all('[data-testid="pipeline-url-link"]')[2])
+ .to have_content("##{push_pipeline_2.id}")
+
+ expect(all('[data-testid="pipeline-url-link"]')[3])
+ .to have_content("##{push_pipeline.id}")
end
+ end
+
+ it 'sees detached tag for detached merge request pipelines' do
+ page.within('.ci-table') do
+ expect(all('.pipeline-tags')[0])
+ .to have_content(expected_detached_mr_tag)
+
+ expect(all('.pipeline-tags')[1])
+ .to have_content(expected_detached_mr_tag)
- it 'shows Set to auto-merge button' do
- visit project_merge_request_path(project, merge_request)
+ expect(all('.pipeline-tags')[2])
+ .not_to have_content(expected_detached_mr_tag)
- expect(page).to have_button('Set to auto-merge')
+ expect(all('.pipeline-tags')[3])
+ .not_to have_content(expected_detached_mr_tag)
end
end
- end
- end
- context 'when a user merges a merge request from a forked project to the parent project' do
- before do
- click_link("Overview")
+ it 'sees the latest detached merge request pipeline as the head pipeline' do
+ click_link "Overview"
- click_button 'Set to auto-merge'
+ page.within('.ci-widget-content') do
+ expect(page).to have_content("##{detached_merge_request_pipeline_2.id}")
+ end
+ end
- wait_for_requests
- end
+ it 'sees pipeline list in forked project' do
+ visit project_pipelines_path(forked_project)
- context 'when detached merge request pipeline is pending' do
- it 'waits the head pipeline' do
- expect(page).to have_content mr_widget_title
- expect(page).to have_button('Cancel auto-merge')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'pending', count: 4)
end
end
- context 'when detached merge request pipeline succeeds' do
+ context 'when the latest pipeline is running in the parent project' do
before do
- detached_merge_request_pipeline.reload.succeed!
-
- refresh
+ create(:ci_pipeline,
+ source: :merge_request_event,
+ project: project,
+ ref: 'feature',
+ sha: merge_request.diff_head_sha,
+ user: user,
+ merge_request: merge_request,
+ status: :running)
+ merge_request.update_head_pipeline
end
- it 'merges the merge request' do
- expect(page).to have_content('Merged by')
- expect(page).to have_button('Revert')
+ context 'when the previous pipeline failed in the fork project' do
+ before do
+ detached_merge_request_pipeline.reload.drop!
+ end
+
+ context 'when the parent project enables pipeline must succeed' do
+ before do
+ project.update!(only_allow_merge_if_pipeline_succeeds: true)
+ end
+
+ it 'shows Set to auto-merge button' do
+ visit project_merge_request_path(project, merge_request)
+
+ expect(page).to have_button('Set to auto-merge')
+ end
+ end
end
end
- context 'when branch pipeline succeeds' do
+ context 'when a user merges a merge request from a forked project to the parent project' do
before do
- push_pipeline.reload.succeed!
+ click_link("Overview")
+
+ click_button 'Set to auto-merge'
wait_for_requests
end
- it 'waits the head pipeline' do
- expect(page).to have_content mr_widget_title
- expect(page).to have_button('Cancel auto-merge')
+ context 'when detached merge request pipeline is pending' do
+ it 'waits the head pipeline' do
+ expect(page).to have_content mr_widget_title
+ expect(page).to have_button('Cancel auto-merge')
+ end
+ end
+
+ context 'when detached merge request pipeline succeeds' do
+ before do
+ detached_merge_request_pipeline.reload.succeed!
+
+ wait_for_requests
+ end
+
+ it 'merges the merge request' do
+ expect(page).to have_content('Merged by')
+ expect(page).to have_button('Revert')
+ end
+ end
+
+ context 'when branch pipeline succeeds' do
+ before do
+ push_pipeline.reload.succeed!
+
+ wait_for_requests
+ end
+
+ it 'waits the head pipeline' do
+ expect(page).to have_content mr_widget_title
+ expect(page).to have_button('Cancel auto-merge')
+ end
end
end
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 75df93d1a6c..1db09790e1c 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -646,7 +646,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
click_expand_button
within('[data-testid="widget-extension-collapsed-section"]') do
- click_link 'addTest'
+ click_button 'View details'
end
end
@@ -693,7 +693,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
click_expand_button
within('[data-testid="widget-extension-collapsed-section"]') do
- click_link 'Test#sum when a is 1 and b is 3 returns summary'
+ click_button 'View details'
end
end
@@ -741,7 +741,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
click_expand_button
within('[data-testid="widget-extension-collapsed-section"]') do
- click_link 'addTest'
+ click_button 'View details'
end
end
@@ -788,7 +788,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
click_expand_button
within('[data-testid="widget-extension-collapsed-section"]') do
- click_link 'addTest'
+ click_button 'View details'
end
end
@@ -834,7 +834,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
click_expand_button
within('[data-testid="widget-extension-collapsed-section"]') do
- click_link 'Test#sum when a is 4 and b is 4 returns summary'
+ click_button 'View details'
end
end
@@ -881,7 +881,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
click_expand_button
within('[data-testid="widget-extension-collapsed-section"]') do
- click_link 'addTest'
+ click_button 'View details'
end
end
@@ -958,4 +958,21 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
end
end
end
+
+ context 'views MR when pipeline has code coverage enabled' do
+ let!(:pipeline) { create(:ci_pipeline, status: 'success', project: project, ref: merge_request.source_branch) }
+ let!(:build) { create(:ci_build, :success, :coverage, pipeline: pipeline) }
+
+ before do
+ merge_request.update!(head_pipeline: pipeline)
+
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'shows the coverage' do
+ within '.ci-widget' do
+ expect(find_by_testid('pipeline-coverage')).to have_content('Test coverage 99.90% ')
+ end
+ end
+ end
end
diff --git a/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb
index 5801e8a1a11..77cd116ecc9 100644
--- a/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb
+++ b/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb
@@ -30,15 +30,33 @@ RSpec.describe 'Merge request > User sees pipelines from forked project', :js,
before do
create(:ci_build, pipeline: pipeline, name: 'rspec')
create(:ci_build, pipeline: pipeline, name: 'spinach')
-
sign_in(user)
- visit project_merge_request_path(target_project, merge_request)
end
- it 'user visits a pipelines page', :sidekiq_might_not_need_inline do
- page.within('.merge-request-tabs') { click_link 'Pipelines' }
+ context 'with feature flag `mr_pipelines_graphql` turned off' do
+ before do
+ stub_feature_flags(mr_pipelines_graphql: false)
+ visit project_merge_request_path(target_project, merge_request)
+ end
+
+ it 'user visits a pipelines page', :sidekiq_might_not_need_inline do
+ page.within('.merge-request-tabs') { click_link 'Pipelines' }
+
+ page.within('.ci-table') do
+ expect(page).to have_content(pipeline.id)
+ end
+ end
+ end
+
+ context 'with feature flag `mr_pipelines_graphql` turned on' do
+ before do
+ stub_feature_flags(mr_pipelines_graphql: true)
+ visit project_merge_request_path(target_project, merge_request)
+ end
+
+ it 'user visits a pipelines page', :sidekiq_might_not_need_inline do
+ page.within('.merge-request-tabs') { click_link 'Pipelines' }
- page.within('.ci-table') do
expect(page).to have_content(pipeline.id)
end
end
diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb
index 5ce919fe2e6..bb3890f5242 100644
--- a/spec/features/merge_request/user_sees_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_pipelines_spec.rb
@@ -3,285 +3,291 @@
require 'spec_helper'
RSpec.describe 'Merge request > User sees pipelines', :js, feature_category: :code_review_workflow do
- describe 'pipeline tab' do
- let(:merge_request) { create(:merge_request) }
- let(:project) { merge_request.target_project }
- let(:user) { project.creator }
-
+ context 'with feature flag `mr_pipelines_graphql turned off`' do
before do
- project.add_maintainer(user)
- sign_in(user)
+ stub_feature_flags(mr_pipelines_graphql: false)
end
- context 'with pipelines' do
- let!(:pipeline) do
- create(
- :ci_pipeline,
- :success,
- project: merge_request.source_project,
- ref: merge_request.source_branch,
- sha: merge_request.diff_head_sha
- )
- end
-
- let!(:manual_job) { create(:ci_build, :manual, name: 'job1', stage: 'deploy', pipeline: pipeline) }
-
- let!(:job) { create(:ci_build, :success, name: 'job2', stage: 'test', pipeline: pipeline) }
+ describe 'pipeline tab' do
+ let(:merge_request) { create(:merge_request) }
+ let(:project) { merge_request.target_project }
+ let(:user) { project.creator }
before do
- merge_request.update_attribute(:head_pipeline_id, pipeline.id)
+ project.add_maintainer(user)
+ sign_in(user)
end
- it 'pipelines table displays correctly' do
- visit project_merge_request_path(project, merge_request)
-
- expect(page.find('.ci-widget')).to have_content('passed')
-
- page.within('.merge-request-tabs') do
- click_link('Pipelines')
+ context 'with pipelines' do
+ let!(:pipeline) do
+ create(
+ :ci_pipeline,
+ :success,
+ project: merge_request.source_project,
+ ref: merge_request.source_branch,
+ sha: merge_request.diff_head_sha
+ )
end
- wait_for_requests
+ let!(:manual_job) { create(:ci_build, :manual, name: 'job1', stage: 'deploy', pipeline: pipeline) }
- page.within(find('[data-testid="pipeline-table-row"]', match: :first)) do
- expect(page).to have_selector('[data-testid="ci-badge-passed"]')
- expect(page).to have_content(pipeline.id)
- expect(page).to have_content('API')
- expect(page).to have_css('[data-testid="pipeline-mini-graph"]')
- expect(page).to have_css('[data-testid="pipelines-manual-actions-dropdown"]')
- expect(page).to have_css('[data-testid="pipeline-multi-actions-dropdown"]')
- end
- end
+ let!(:job) { create(:ci_build, :success, name: 'job2', stage: 'test', pipeline: pipeline) }
- context 'with a detached merge request pipeline' do
- let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
+ before do
+ merge_request.update_attribute(:head_pipeline_id, pipeline.id)
+ end
- it 'displays the "Run pipeline" button' do
+ it 'pipelines table displays correctly' do
visit project_merge_request_path(project, merge_request)
+ expect(page.find('.ci-widget')).to have_content('passed')
+
page.within('.merge-request-tabs') do
click_link('Pipelines')
end
wait_for_requests
- expect(page.find('[data-testid="run_pipeline_button"]')).to have_text('Run pipeline')
+ page.within(find('[data-testid="pipeline-table-row"]', match: :first)) do
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'passed')
+ expect(page).to have_content(pipeline.id)
+ expect(page).to have_content('API')
+ expect(page).to have_css('[data-testid="pipeline-mini-graph"]')
+ expect(page).to have_css('[data-testid="pipelines-manual-actions-dropdown"]')
+ expect(page).to have_css('[data-testid="pipeline-multi-actions-dropdown"]')
+ end
end
- end
- context 'with a merged results pipeline' do
- let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) }
+ context 'with a detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
- it 'displays the "Run pipeline" button' do
- visit project_merge_request_path(project, merge_request)
+ it 'displays the "Run pipeline" button' do
+ visit project_merge_request_path(project, merge_request)
- page.within('.merge-request-tabs') do
- click_link('Pipelines')
- end
+ page.within('.merge-request-tabs') do
+ click_link('Pipelines')
+ end
- wait_for_requests
+ wait_for_requests
- expect(page.find('[data-testid="run_pipeline_button"]')).to have_text('Run pipeline')
+ expect(page.find('[data-testid="run_pipeline_button"]')).to have_text('Run pipeline')
+ end
end
- end
- end
- context 'without pipelines' do
- before do
- visit project_merge_request_path(project, merge_request)
- end
+ context 'with a merged results pipeline' do
+ let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) }
+
+ it 'displays the "Run pipeline" button' do
+ visit project_merge_request_path(project, merge_request)
+
+ page.within('.merge-request-tabs') do
+ click_link('Pipelines')
+ end
+
+ wait_for_requests
- it 'user visits merge request page' do
- page.within('.merge-request-tabs') do
- expect(page).to have_link('Pipelines')
+ expect(page.find('[data-testid="run_pipeline_button"]')).to have_text('Run pipeline')
+ end
end
end
- it 'shows empty state with run pipeline button' do
- page.within('.merge-request-tabs') do
- click_link('Pipelines')
+ context 'without pipelines' do
+ before do
+ visit project_merge_request_path(project, merge_request)
end
- expect(page).to have_content('There are currently no pipelines.')
- expect(page.find('[data-testid="run_pipeline_button"]')).to have_text('Run pipeline')
- end
- end
- end
+ it 'user visits merge request page' do
+ page.within('.merge-request-tabs') do
+ expect(page).to have_link('Pipelines')
+ end
+ end
- describe 'fork MRs in parent project', :sidekiq_inline do
- include ProjectForksHelper
-
- let_it_be(:parent_project) { create(:project, :public, :repository) }
- let_it_be(:forked_project) { fork_project(parent_project, developer_in_fork, repository: true, target_project: create(:project, :public, :repository)) }
- let_it_be(:developer_in_parent) { create(:user) }
- let_it_be(:developer_in_fork) { create(:user) }
- let_it_be(:reporter_in_parent_and_developer_in_fork) { create(:user) }
-
- let(:merge_request) do
- create(
- :merge_request,
- :with_detached_merge_request_pipeline,
- source_project: forked_project,
- source_branch: 'feature',
- target_project: parent_project,
- target_branch: 'master'
- )
- end
+ it 'shows empty state with run pipeline button' do
+ page.within('.merge-request-tabs') do
+ click_link('Pipelines')
+ end
- let(:config) do
- { test: { script: 'test', rules: [{ if: '$CI_MERGE_REQUEST_ID' }] } }
+ expect(page).to have_content('There are currently no pipelines.')
+ expect(page.find('[data-testid="run_pipeline_button"]')).to have_text('Run pipeline')
+ end
+ end
end
- before_all do
- parent_project.add_developer(developer_in_parent)
- parent_project.add_reporter(reporter_in_parent_and_developer_in_fork)
- forked_project.add_developer(developer_in_fork)
- forked_project.add_developer(reporter_in_parent_and_developer_in_fork)
- end
+ describe 'fork MRs in parent project', :sidekiq_inline do
+ include ProjectForksHelper
- before do
- stub_ci_pipeline_yaml_file(YAML.dump(config))
- sign_in(actor)
- end
+ let_it_be(:parent_project) { create(:project, :public, :repository) }
+ let_it_be(:forked_project) { fork_project(parent_project, developer_in_fork, repository: true, target_project: create(:project, :public, :repository)) }
+ let_it_be(:developer_in_parent) { create(:user) }
+ let_it_be(:developer_in_fork) { create(:user) }
+ let_it_be(:reporter_in_parent_and_developer_in_fork) { create(:user) }
- after do
- parent_project.all_pipelines.delete_all
- forked_project.all_pipelines.delete_all
- end
+ let(:merge_request) do
+ create(
+ :merge_request,
+ :with_detached_merge_request_pipeline,
+ source_project: forked_project,
+ source_branch: 'feature',
+ target_project: parent_project,
+ target_branch: 'master'
+ )
+ end
- context 'when actor is a developer in parent project' do
- let(:actor) { developer_in_parent }
+ let(:config) do
+ { test: { script: 'test', rules: [{ if: '$CI_MERGE_REQUEST_ID' }] } }
+ end
- it 'creates a pipeline in the parent project when user proceeds with the warning' do
- visit project_merge_request_path(parent_project, merge_request)
+ before_all do
+ parent_project.add_developer(developer_in_parent)
+ parent_project.add_reporter(reporter_in_parent_and_developer_in_fork)
+ forked_project.add_developer(developer_in_fork)
+ forked_project.add_developer(reporter_in_parent_and_developer_in_fork)
+ end
- create_merge_request_pipeline
- act_on_security_warning(action: 'Run pipeline')
+ before do
+ stub_ci_pipeline_yaml_file(YAML.dump(config))
+ sign_in(actor)
+ end
- check_pipeline(expected_project: parent_project)
- check_head_pipeline(expected_project: parent_project)
+ after do
+ parent_project.all_pipelines.delete_all
+ forked_project.all_pipelines.delete_all
end
- it 'does not create a pipeline in the parent project when user cancels the action', :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state do
- visit project_merge_request_path(parent_project, merge_request)
+ context 'when actor is a developer in parent project' do
+ let(:actor) { developer_in_parent }
- create_merge_request_pipeline
- act_on_security_warning(action: 'Cancel')
+ it 'creates a pipeline in the parent project when user proceeds with the warning' do
+ visit project_merge_request_path(parent_project, merge_request)
- check_no_new_pipeline_created
- end
- end
+ create_merge_request_pipeline
+ act_on_security_warning(action: 'Run pipeline')
- context 'when actor is a developer in fork project' do
- let(:actor) { developer_in_fork }
+ check_pipeline(expected_project: parent_project)
+ check_head_pipeline(expected_project: parent_project)
+ end
- it 'creates a pipeline in the fork project' do
- visit project_merge_request_path(parent_project, merge_request)
+ it 'does not create a pipeline in the parent project when user cancels the action', :clean_gitlab_redis_cache, :clean_gitlab_redis_shared_state do
+ visit project_merge_request_path(parent_project, merge_request)
- create_merge_request_pipeline
+ create_merge_request_pipeline
+ act_on_security_warning(action: 'Cancel')
- check_pipeline(expected_project: forked_project)
- check_head_pipeline(expected_project: forked_project)
+ check_no_new_pipeline_created
+ end
end
- end
- context 'when actor is a reporter in parent project and a developer in fork project' do
- let(:actor) { reporter_in_parent_and_developer_in_fork }
+ context 'when actor is a developer in fork project' do
+ let(:actor) { developer_in_fork }
- it 'creates a pipeline in the fork project' do
- visit project_merge_request_path(parent_project, merge_request)
+ it 'creates a pipeline in the fork project' do
+ visit project_merge_request_path(parent_project, merge_request)
- create_merge_request_pipeline
+ create_merge_request_pipeline
- check_pipeline(expected_project: forked_project)
- check_head_pipeline(expected_project: forked_project)
+ check_pipeline(expected_project: forked_project)
+ check_head_pipeline(expected_project: forked_project)
+ end
end
- end
- def create_merge_request_pipeline
- page.within('.merge-request-tabs') { click_link('Pipelines') }
- click_on('Run pipeline')
- end
+ context 'when actor is a reporter in parent project and a developer in fork project' do
+ let(:actor) { reporter_in_parent_and_developer_in_fork }
- def check_pipeline(expected_project:)
- page.within('.ci-table') do
- expect(page).to have_selector('[data-testid="pipeline-table-row"]', count: 4)
+ it 'creates a pipeline in the fork project' do
+ visit project_merge_request_path(parent_project, merge_request)
- page.within(first('[data-testid="pipeline-table-row"]')) do
- page.within('.pipeline-tags') do
- expect(page.find('[data-testid="pipeline-url-link"]')[:href]).to include(expected_project.full_path)
- expect(page).to have_content('merge request')
- end
- page.within('.pipeline-triggerer') do
- expect(page).to have_link(href: user_path(actor))
+ create_merge_request_pipeline
+
+ check_pipeline(expected_project: forked_project)
+ check_head_pipeline(expected_project: forked_project)
+ end
+ end
+
+ def create_merge_request_pipeline
+ page.within('.merge-request-tabs') { click_link('Pipelines') }
+ click_on('Run pipeline')
+ end
+
+ def check_pipeline(expected_project:)
+ page.within('.ci-table') do
+ expect(page).to have_selector('[data-testid="pipeline-table-row"]', count: 4)
+
+ page.within(first('[data-testid="pipeline-table-row"]')) do
+ page.within('.pipeline-tags') do
+ expect(page.find('[data-testid="pipeline-url-link"]')[:href]).to include(expected_project.full_path)
+ expect(page).to have_content('merge request')
+ end
+ page.within('.pipeline-triggerer') do
+ expect(page).to have_link(href: user_path(actor))
+ end
end
end
end
- end
- def check_head_pipeline(expected_project:)
- page.within('.merge-request-tabs') { click_link('Overview') }
+ def check_head_pipeline(expected_project:)
+ page.within('.merge-request-tabs') { click_link('Overview') }
- page.within('.ci-widget-content') do
- expect(page.find('.pipeline-id')[:href]).to include(expected_project.full_path)
+ page.within('.ci-widget-content') do
+ expect(page.find('.pipeline-id')[:href]).to include(expected_project.full_path)
+ end
end
- end
- def act_on_security_warning(action:)
- page.within('#create-pipeline-for-fork-merge-request-modal') do
- expect(page).to have_content('Are you sure you want to run this pipeline?')
- click_button(action)
+ def act_on_security_warning(action:)
+ page.within('#create-pipeline-for-fork-merge-request-modal') do
+ expect(page).to have_content('Are you sure you want to run this pipeline?')
+ click_button(action)
+ end
end
- end
- def check_no_new_pipeline_created
- page.within('.ci-table') do
- expect(page).to have_selector('[data-testid="pipeline-table-row"]', count: 2)
+ def check_no_new_pipeline_created
+ page.within('.ci-table') do
+ expect(page).to have_selector('[data-testid="pipeline-table-row"]', count: 2)
+ end
end
end
- end
-
- describe 'race condition' do
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
- let(:build_push_data) { { ref: 'feature', checkout_sha: TestEnv::BRANCH_SHA['feature'] } }
- let(:merge_request_params) do
- { "source_branch" => "feature", "source_project_id" => project.id,
- "target_branch" => "master", "target_project_id" => project.id, "title" => "A" }
- end
+ describe 'race condition' do
+ let(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+ let(:build_push_data) { { ref: 'feature', checkout_sha: TestEnv::BRANCH_SHA['feature'] } }
- before do
- project.add_maintainer(user)
- sign_in user
- end
+ let(:merge_request_params) do
+ { "source_branch" => "feature", "source_project_id" => project.id,
+ "target_branch" => "master", "target_project_id" => project.id, "title" => "A" }
+ end
- context 'when pipeline and merge request were created simultaneously', :delete do
before do
- stub_ci_pipeline_to_return_yaml_file
+ project.add_maintainer(user)
+ sign_in user
+ end
+
+ context 'when pipeline and merge request were created simultaneously', :delete do
+ before do
+ stub_ci_pipeline_to_return_yaml_file
- threads = []
+ threads = []
- threads << Thread.new do
- Sidekiq::Worker.skipping_transaction_check do
- @merge_request = MergeRequests::CreateService.new(project: project, current_user: user, params: merge_request_params).execute
+ threads << Thread.new do
+ Sidekiq::Worker.skipping_transaction_check do
+ @merge_request = MergeRequests::CreateService.new(project: project, current_user: user, params: merge_request_params).execute
+ end
end
- end
- threads << Thread.new do
- Sidekiq::Worker.skipping_transaction_check do
- @pipeline = Ci::CreatePipelineService.new(project, user, build_push_data).execute(:push).payload
+ threads << Thread.new do
+ Sidekiq::Worker.skipping_transaction_check do
+ @pipeline = Ci::CreatePipelineService.new(project, user, build_push_data).execute(:push).payload
+ end
end
- end
- threads.each { |thr| thr.join }
- end
+ threads.each { |thr| thr.join }
+ end
- it 'user sees pipeline in merge request widget', :sidekiq_might_not_need_inline do
- visit project_merge_request_path(project, @merge_request)
+ it 'user sees pipeline in merge request widget', :sidekiq_might_not_need_inline do
+ visit project_merge_request_path(project, @merge_request)
- expect(page.find(".ci-widget")).to have_content(TestEnv::BRANCH_SHA['feature'])
- expect(page.find(".ci-widget")).to have_content("##{@pipeline.id}")
+ expect(page.find(".ci-widget")).to have_content(TestEnv::BRANCH_SHA['feature'])
+ expect(page.find(".ci-widget")).to have_content("##{@pipeline.id}")
+ end
end
end
end
diff --git a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
index e3be99254dc..16578af238d 100644
--- a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
+++ b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe 'Merge request > User selects branches for new MR', :js, feature_
include ListboxHelpers
include CookieHelper
- let(:project) { create(:project, :public, :repository) }
- let(:user) { project.creator }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :public, :repository, namespace: user.namespace) }
def select_source_branch(branch_name)
find('.js-source-branch', match: :first).click
@@ -16,7 +16,6 @@ RSpec.describe 'Merge request > User selects branches for new MR', :js, feature_
end
before do
- project.add_maintainer(user)
sign_in(user)
set_cookie('new-actions-popover-viewed', 'true')
end
diff --git a/spec/features/merge_request/user_sets_to_auto_merge_spec.rb b/spec/features/merge_request/user_sets_to_auto_merge_spec.rb
new file mode 100644
index 00000000000..4dc0c03aedc
--- /dev/null
+++ b/spec/features/merge_request/user_sets_to_auto_merge_spec.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > User sets to auto-merge', :js, feature_category: :code_review_workflow do
+ include ContentEditorHelpers
+
+ let(:project) { create(:project, :public, :repository) }
+ let(:user) { project.creator }
+ let(:merge_request) do
+ create(
+ :merge_request_with_diffs,
+ source_project: project,
+ author: user,
+ title: 'Bug NS-04',
+ merge_params: { force_remove_source_branch: '1' }
+ )
+ end
+
+ let(:pipeline) do
+ create(
+ :ci_pipeline,
+ project: project,
+ sha: merge_request.diff_head_sha,
+ ref: merge_request.source_branch,
+ head_pipeline_of: merge_request
+ )
+ end
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ context 'when there is active pipeline for merge request' do
+ before do
+ create(:ci_build, pipeline: pipeline)
+
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ describe 'setting to auto-merge when pipeline succeeds' do
+ shared_examples 'Set to auto-merge activator' do
+ it 'activates auto-merge feature', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410055' do
+ close_rich_text_promo_popover_if_present
+ expect(page).to have_content 'Set to auto-merge'
+ click_button "Set to auto-merge"
+ wait_for_requests
+
+ expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds"
+ expect(page).to have_content "Source branch will not be deleted"
+ expect(page).to have_selector ".js-cancel-auto-merge"
+ expect(page).to have_content(/enabled an automatic merge when the pipeline for \h{8} succeeds/i)
+ end
+ end
+
+ context "when enabled immediately" do
+ it_behaves_like 'Set to auto-merge activator'
+ end
+
+ context 'when enabled after it was previously canceled' do
+ before do
+ close_rich_text_promo_popover_if_present
+ click_button "Set to auto-merge"
+
+ wait_for_requests
+
+ click_button "Cancel auto-merge"
+
+ wait_for_requests
+ end
+
+ it_behaves_like 'Set to auto-merge activator'
+ end
+
+ context 'when it is enabled and then canceled' do
+ let(:merge_request) do
+ create(
+ :merge_request_with_diffs,
+ :merge_when_pipeline_succeeds,
+ source_project: project,
+ title: 'Bug NS-04',
+ author: user,
+ merge_user: user
+ )
+ end
+
+ before do
+ merge_request.merge_params['force_remove_source_branch'] = '0'
+ merge_request.save!
+ click_button "Cancel auto-merge"
+ end
+
+ it_behaves_like 'Set to auto-merge activator'
+ end
+ end
+ end
+
+ context 'when there is an active pipeline' do
+ let(:merge_request) do
+ create(
+ :merge_request_with_diffs,
+ :simple,
+ :merge_when_pipeline_succeeds,
+ source_project: project,
+ author: user,
+ merge_user: user,
+ title: 'MepMep'
+ )
+ end
+
+ let!(:build) do
+ create(:ci_build, pipeline: pipeline)
+ end
+
+ before do
+ sign_in user
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'allows to cancel the auto-merge', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/410055' do
+ close_rich_text_promo_popover_if_present
+
+ click_button "Cancel auto-merge"
+
+ expect(page).to have_button "Set to auto-merge"
+
+ refresh
+
+ expect(page).to have_content "canceled the automatic merge"
+ end
+ end
+
+ context 'when there is no active pipeline' do
+ before do
+ sign_in user
+ visit project_merge_request_path(project, merge_request.reload)
+ end
+
+ it 'does not allow to set to auto-merge' do
+ expect(page).not_to have_link 'Set to auto-merge'
+ end
+ end
+end
diff --git a/spec/features/merge_request/user_uses_quick_actions_spec.rb b/spec/features/merge_request/user_uses_quick_actions_spec.rb
index 1c63f5b56b0..b2cc25f1c34 100644
--- a/spec/features/merge_request/user_uses_quick_actions_spec.rb
+++ b/spec/features/merge_request/user_uses_quick_actions_spec.rb
@@ -11,15 +11,9 @@ RSpec.describe 'Merge request > User uses quick actions', :js, :use_clean_rails_
feature_category: :code_review_workflow do
include Features::NotesHelpers
- let(:project) { create(:project, :public, :repository) }
- let(:user) { project.creator }
- let(:guest) { create(:user) }
- let(:merge_request) { create(:merge_request, source_project: project) }
- let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
-
context "issuable common quick actions" do
let!(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } }
- let(:maintainer) { create(:user) }
+ let(:maintainer) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :public, :repository) }
let!(:label_bug) { create(:label, project: project, title: 'bug') }
let!(:label_feature) { create(:label, project: project, title: 'feature') }
@@ -32,7 +26,8 @@ RSpec.describe 'Merge request > User uses quick actions', :js, :use_clean_rails_
end
describe 'merge-request-only commands' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
+ let(:guest) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
diff --git a/spec/features/monitor_sidebar_link_spec.rb b/spec/features/monitor_sidebar_link_spec.rb
index 6e464cb8752..1d39f749ca7 100644
--- a/spec/features/monitor_sidebar_link_spec.rb
+++ b/spec/features/monitor_sidebar_link_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures, feature_category: :shared do
let_it_be_with_reload(:project) { create(:project, :internal, :repository) }
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let(:role) { nil }
diff --git a/spec/features/nav/pinned_nav_items_spec.rb b/spec/features/nav/pinned_nav_items_spec.rb
index cf53e0a322a..1a3ac973ed4 100644
--- a/spec/features/nav/pinned_nav_items_spec.rb
+++ b/spec/features/nav/pinned_nav_items_spec.rb
@@ -168,17 +168,19 @@ RSpec.describe 'Navigation menu item pinning', :js, feature_category: :navigatio
private
- def add_pin(menu_item_title)
- menu_item = find("[data-testid=\"nav-item-link\"]", text: menu_item_title)
- menu_item.hover
- menu_item.find("[data-testid=\"thumbtack-icon\"]").click
+ def add_pin(nav_item_title)
+ nav_item = find("[data-testid=\"nav-item\"]", text: nav_item_title)
+ nav_item.hover
+ pin_button = nav_item.find("[data-testid=\"nav-item-pin\"]")
+ pin_button.click
wait_for_requests
end
- def remove_pin(menu_item_title)
- menu_item = find("[data-testid=\"nav-item-link\"]", text: menu_item_title)
- menu_item.hover
- menu_item.find("[data-testid=\"thumbtack-solid-icon\"]").click
+ def remove_pin(nav_item_title)
+ nav_item = find("[data-testid=\"nav-item\"]", text: nav_item_title)
+ nav_item.hover
+ unpin_button = nav_item.find("[data-testid=\"nav-item-unpin\"]")
+ unpin_button.click
wait_for_requests
end
diff --git a/spec/features/nav/top_nav_responsive_spec.rb b/spec/features/nav/top_nav_responsive_spec.rb
index ff8132dc087..2a07742c91e 100644
--- a/spec/features/nav/top_nav_responsive_spec.rb
+++ b/spec/features/nav/top_nav_responsive_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
include MobileHelpers
include Features::InviteMembersModalHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/nav/top_nav_spec.rb b/spec/features/nav/top_nav_spec.rb
index ccbf4646273..bf91897eb26 100644
--- a/spec/features/nav/top_nav_spec.rb
+++ b/spec/features/nav/top_nav_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'top nav responsive', :js, feature_category: :navigation do
include Features::InviteMembersModalHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb
index ca20a1cd81b..b65416ee618 100644
--- a/spec/features/oauth_login_spec.rb
+++ b/spec/features/oauth_login_spec.rb
@@ -136,7 +136,7 @@ RSpec.describe 'OAuth Login', :allow_forgery_protection, feature_category: :syst
# record as the host / port depends on whether or not the spec uses
# JS.
let(:application) do
- create(:oauth_application, scopes: 'api', redirect_uri: redirect_uri, confidential: false)
+ create(:oauth_application, scopes: 'api', redirect_uri: redirect_uri, confidential: true)
end
let(:params) do
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index a756c524cbb..697ad4c87f7 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'User edit profile', feature_category: :user_profile do
include Features::NotesHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
stub_feature_flags(edit_user_profile_vue: false)
@@ -478,7 +478,7 @@ RSpec.describe 'User edit profile', feature_category: :user_profile do
end
context 'Remove status button' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
user.status = UserStatus.new(message: 'Eating bread', emoji: 'stuffed_flatbread')
diff --git a/spec/features/profiles/user_visits_notifications_tab_spec.rb b/spec/features/profiles/user_visits_notifications_tab_spec.rb
index 7d858e3c92c..3af8dadcde0 100644
--- a/spec/features/profiles/user_visits_notifications_tab_spec.rb
+++ b/spec/features/profiles/user_visits_notifications_tab_spec.rb
@@ -12,14 +12,6 @@ RSpec.describe 'User visits the notifications tab', :js, feature_category: :user
visit(profile_notifications_path)
end
- it 'turns on the receive product marketing emails setting' do
- expect(page).to have_content('Notifications')
-
- expect do
- check 'Receive product marketing emails'
- end.to change { user.reload.email_opted_in }.to(true)
- end
-
it 'changes the project notifications setting' do
expect(page).to have_content('Notifications')
diff --git a/spec/features/profiles/user_visits_profile_account_page_spec.rb b/spec/features/profiles/user_visits_profile_account_page_spec.rb
index 8ff9cbc242e..8569cefd1f4 100644
--- a/spec/features/profiles/user_visits_profile_account_page_spec.rb
+++ b/spec/features/profiles/user_visits_profile_account_page_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User visits the profile account page', feature_category: :user_profile do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb
index ac0ed91468c..f92b8e2e751 100644
--- a/spec/features/profiles/user_visits_profile_authentication_log_spec.rb
+++ b/spec/features/profiles/user_visits_profile_authentication_log_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User visits the authentication log', feature_category: :user_profile do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
context 'when user signed in' do
before do
diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
index d690589b893..033711f699e 100644
--- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
+++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'User visits the profile preferences page', :js, feature_category: :user_profile do
include ListboxHelpers
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/profiles/user_visits_profile_spec.rb b/spec/features/profiles/user_visits_profile_spec.rb
index 14fc6ed33b3..821c3d5ef2b 100644
--- a/spec/features/profiles/user_visits_profile_spec.rb
+++ b/spec/features/profiles/user_visits_profile_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User visits their profile', feature_category: :user_profile do
- let_it_be_with_refind(:user) { create(:user) }
+ let_it_be_with_refind(:user) { create(:user, :no_super_sidebar) }
before do
stub_feature_flags(profile_tabs_vue: false)
diff --git a/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb b/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb
index 547e47ead77..728fe1a3172 100644
--- a/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb
+++ b/spec/features/profiles/user_visits_profile_ssh_keys_page_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User visits the profile SSH keys page', feature_category: :user_profile do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/projects/active_tabs_spec.rb b/spec/features/projects/active_tabs_spec.rb
index 594c2b442aa..973a1e76679 100644
--- a/spec/features/projects/active_tabs_spec.rb
+++ b/spec/features/projects/active_tabs_spec.rb
@@ -3,9 +3,8 @@
require 'spec_helper'
RSpec.describe 'Project active tab', feature_category: :groups_and_projects do
- let_it_be(:project) { create(:project, :repository, :with_namespace_settings) }
-
- let(:user) { project.first_owner }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :repository, :with_namespace_settings, namespace: user.namespace) }
before do
sign_in(user)
diff --git a/spec/features/projects/branches/user_creates_branch_spec.rb b/spec/features/projects/branches/user_creates_branch_spec.rb
index 8d636dacb75..eafb75d75ac 100644
--- a/spec/features/projects/branches/user_creates_branch_spec.rb
+++ b/spec/features/projects/branches/user_creates_branch_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'User creates branch', :js, feature_category: :groups_and_project
include Features::BranchesHelpers
let_it_be(:group) { create(:group, :public) }
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
shared_examples 'creates new branch' do
specify do
diff --git a/spec/features/projects/ci/editor_spec.rb b/spec/features/projects/ci/editor_spec.rb
index b09aa91f4ab..adaa5e48967 100644
--- a/spec/features/projects/ci/editor_spec.rb
+++ b/spec/features/projects/ci/editor_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe 'Pipeline Editor', :js, feature_category: :pipeline_composition d
it 'renders the empty page', :aggregate_failures do
expect(page).to have_content 'Optimize your workflow with CI/CD Pipelines'
- expect(page).to have_selector '[data-testid="create_new_ci_button"]'
+ expect(page).to have_selector '[data-testid="create-new-ci-button"]'
end
context 'when clicking on the create new CI button' do
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index eadcc0e62c4..b16f43a16b6 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Gcp Cluster', :js, feature_category: :deployment_management do
include GoogleApi::CloudPlatformHelpers
let(:project) { create(:project) }
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
project.add_maintainer(user)
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index 6da8eea687e..1393cc6db15 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'User Cluster', :js, feature_category: :deployment_management do
include GoogleApi::CloudPlatformHelpers
let(:project) { create(:project) }
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
project.add_maintainer(user)
diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb
index d40f929d0b2..e075cc86319 100644
--- a/spec/features/projects/clusters_spec.rb
+++ b/spec/features/projects/clusters_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Clusters', :js, feature_category: :groups_and_projects do
include GoogleApi::CloudPlatformHelpers
let(:project) { create(:project) }
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
project.add_maintainer(user)
diff --git a/spec/features/projects/commit/user_sees_pipelines_tab_spec.rb b/spec/features/projects/commit/user_sees_pipelines_tab_spec.rb
index e44364c7f2d..bc5d468c97a 100644
--- a/spec/features/projects/commit/user_sees_pipelines_tab_spec.rb
+++ b/spec/features/projects/commit/user_sees_pipelines_tab_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe 'Commit > Pipelines tab', :js, feature_category: :source_code_man
wait_for_requests
page.within('[data-testid="pipeline-table-row"]') do
- expect(page).to have_selector('[data-testid="ci-badge-passed"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'passed')
expect(page).to have_content(pipeline.id)
expect(page).to have_content('API')
expect(page).to have_css('[data-testid="pipeline-mini-graph"]')
diff --git a/spec/features/projects/confluence/user_views_confluence_page_spec.rb b/spec/features/projects/confluence/user_views_confluence_page_spec.rb
index c1ce6ea4536..216bea74c09 100644
--- a/spec/features/projects/confluence/user_views_confluence_page_spec.rb
+++ b/spec/features/projects/confluence/user_views_confluence_page_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User views the Confluence page', feature_category: :integrations do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :public) }
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index 11ea72b87a2..3abe3ce1396 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -10,24 +10,19 @@ RSpec.describe 'Environment', feature_category: :groups_and_projects do
before do
sign_in(user)
project.add_role(user, role)
- stub_feature_flags(environment_details_vue: false)
end
def auto_stop_button_selector
%q{button[title="Prevent environment from auto-stopping"]}
end
- describe 'environment details page vue' do
+ describe 'environment details page', :js do
let_it_be(:environment) { create(:environment, project: project) }
let!(:permissions) {}
let!(:deployment) {}
let!(:action) {}
let!(:cluster) {}
- before do
- stub_feature_flags(environment_details_vue: true)
- end
-
context 'with auto-stop' do
let_it_be(:environment) { create(:environment, :will_auto_stop, name: 'staging', project: project) }
@@ -35,122 +30,16 @@ RSpec.describe 'Environment', feature_category: :groups_and_projects do
visit_environment(environment)
end
- it 'shows auto stop info', :js do
- expect(page).to have_content('Auto stops')
- end
-
- it 'shows auto stop button', :js do
- expect(page).to have_selector(auto_stop_button_selector)
- expect(page.find(auto_stop_button_selector).find(:xpath, '..')['action']).to have_content(cancel_auto_stop_project_environment_path(environment.project, environment))
- end
-
- it 'allows user to cancel auto stop', :js do
- page.find(auto_stop_button_selector).click
- wait_for_all_requests
- expect(page).to have_content('Auto stop successfully canceled.')
- expect(page).not_to have_selector(auto_stop_button_selector)
- end
- end
-
- context 'without deployments' do
- before do
- visit_environment(environment)
- end
-
- it 'does not show deployments', :js do
- expect(page).to have_content('You don\'t have any deployments right now.')
- end
- end
-
- context 'with deployments' do
- before do
- visit_environment(environment)
- end
-
- context 'when there is a successful deployment' do
- let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, :success, pipeline: pipeline) }
-
- let(:deployment) do
- create(:deployment, :success, environment: environment, deployable: build)
- end
-
- it 'does show deployments', :js do
- wait_for_requests
- expect(page).to have_link("#{build.name} (##{build.id})")
- end
- end
-
- context 'when there is a failed deployment' do
- let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, pipeline: pipeline) }
-
- let(:deployment) do
- create(:deployment, :failed, environment: environment, deployable: build)
- end
-
- it 'does show deployments', :js do
- wait_for_requests
- expect(page).to have_link("#{build.name} (##{build.id})")
- end
- end
-
- context 'with related deployable present' do
- let_it_be(:previous_pipeline) { create(:ci_pipeline, project: project) }
-
- let_it_be(:previous_build) do
- create(:ci_build, :success, pipeline: previous_pipeline, environment: environment.name)
- end
-
- let_it_be(:previous_deployment) do
- create(:deployment, :success, environment: environment, deployable: previous_build)
- end
-
- let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
- let_it_be(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) }
-
- let_it_be(:deployment) do
- create(:deployment, :success, environment: environment, deployable: build)
- end
-
- before do
- visit_environment(environment)
- end
-
- it 'shows deployment information and buttons', :js do
- wait_for_requests
- expect(page).to have_button('Re-deploy to environment')
- expect(page).to have_button('Rollback environment')
- expect(page).to have_link("#{build.name} (##{build.id})")
- end
- end
- end
- end
-
- describe 'environment details page' do
- let_it_be(:environment) { create(:environment, project: project) }
- let!(:permissions) {}
- let!(:deployment) {}
- let!(:action) {}
- let!(:cluster) {}
-
- context 'with auto-stop' do
- let!(:environment) { create(:environment, :will_auto_stop, name: 'staging', project: project) }
-
- before do
- visit_environment(environment)
- end
-
- it 'shows auto stop info', :js do
+ it 'shows auto stop info' do
expect(page).to have_content('Auto stops')
end
- it 'shows auto stop button', :js do
+ it 'shows auto stop button' do
expect(page).to have_selector(auto_stop_button_selector)
expect(page.find(auto_stop_button_selector).find(:xpath, '..')['action']).to have_content(cancel_auto_stop_project_environment_path(environment.project, environment))
end
- it 'allows user to cancel auto stop', :js do
+ it 'allows user to cancel auto stop' do
page.find(auto_stop_button_selector).click
wait_for_all_requests
expect(page).to have_content('Auto stop successfully canceled.')
@@ -208,10 +97,6 @@ RSpec.describe 'Environment', feature_category: :groups_and_projects do
it 'does show deployments' do
expect(page).to have_link("#{build.name} (##{build.id})")
end
-
- it 'shows a tooltip on the job name' do
- expect(page).to have_css("[title=\"#{build.name} (##{build.id})\"].has-tooltip")
- end
end
context 'when there is a failed deployment' do
@@ -227,26 +112,6 @@ RSpec.describe 'Environment', feature_category: :groups_and_projects do
end
end
- context 'with many deployments' do
- let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, pipeline: pipeline) }
-
- let!(:second) { create(:deployment, environment: environment, deployable: build, status: :success, finished_at: Time.current) }
- let!(:first) { create(:deployment, environment: environment, deployable: build, status: :running) }
- let!(:last) { create(:deployment, environment: environment, deployable: build, status: :success, finished_at: 2.days.ago) }
- let!(:third) { create(:deployment, environment: environment, deployable: build, status: :canceled, finished_at: 1.day.ago) }
-
- before do
- visit_environment(environment)
- end
-
- it 'shows all of them in ordered way' do
- ids = find_all('[data-testid="deployment-id"]').map { |e| e.text }
- expected_ordered_ids = [first, second, third, last].map { |d| "##{d.iid}" }
- expect(ids).to eq(expected_ordered_ids)
- end
- end
-
context 'with upcoming deployments' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
@@ -265,7 +130,7 @@ RSpec.describe 'Environment', feature_category: :groups_and_projects do
# See https://gitlab.com/gitlab-org/gitlab/-/issues/350618 for more information.
it 'shows upcoming deployments in unordered way' do
displayed_ids = find_all('[data-testid="deployment-id"]').map { |e| e.text }
- internal_ids = [runnind_deployment_1, runnind_deployment_2, success_without_finished_at].map { |d| "##{d.iid}" }
+ internal_ids = [runnind_deployment_1, runnind_deployment_2, success_without_finished_at].map { |d| d.iid.to_s }
expect(displayed_ids).to match_array(internal_ids)
end
end
@@ -309,20 +174,19 @@ RSpec.describe 'Environment', feature_category: :groups_and_projects do
end
it 'does show a play button' do
- expect(page).to have_link(action.name)
+ expect(page).to have_button(action.name, visible: :all)
end
- it 'does allow to play manual action', :js do
+ it 'does allow to play manual action' do
expect(action).to be_manual
- find('button.dropdown').click
+ click_button('Deploy to...')
- expect { click_link(action.name) }
+ expect { click_button(action.name) }
.not_to change { Ci::Pipeline.count }
wait_for_all_requests
- expect(page).to have_content(action.name)
expect(action.reload).to be_pending
end
end
@@ -347,38 +211,6 @@ RSpec.describe 'Environment', feature_category: :groups_and_projects do
end
end
- context 'with terminal' do
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let!(:cluster) do
- create(:cluster, :project, :provided_by_gcp, projects: [project])
- end
-
- context 'for project maintainer' do
- let(:role) { :maintainer }
-
- context 'web terminal', :js do
- before do
- # Stub #terminals as it causes js-enabled feature specs to
- # render the page incorrectly
- #
- # In EE we have to stub EE::Environment since it overwrites
- # the "terminals" method.
- allow_next_instance_of(Gitlab.ee? ? EE::Environment : Environment) do |instance|
- allow(instance).to receive(:terminals) { nil }
- end
-
- visit terminal_project_environment_path(project, environment)
- end
-
- it 'displays a web terminal' do
- expect(page).to have_selector('#terminal')
- expect(page).to have_link(nil, href: environment.external_url)
- end
- end
- end
- end
- end
-
context 'when environment is available' do
context 'with stop action' do
let(:build) { create(:ci_build, :success, pipeline: pipeline, environment: environment.name) }
@@ -446,6 +278,8 @@ RSpec.describe 'Environment', feature_category: :groups_and_projects do
visit folder_project_environments_path(project, id: 'staging-1.0')
end
+ wait_for_requests
+
expect(reqs.first.status_code).to eq(200)
expect(page).to have_content('Environments / staging-1.0')
end
diff --git a/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb
index 4af5c91479a..127610cf4db 100644
--- a/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb
+++ b/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb
@@ -7,13 +7,14 @@ RSpec.describe 'User creates feature flag', :js do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
+ let!(:environment) { create(:environment, :production, project: project) }
before do
project.add_developer(user)
sign_in(user)
end
- it 'user creates a flag enabled for user ids' do
+ it 'user creates a flag enabled for user ids with existing environment' do
visit(new_project_feature_flag_path(project))
set_feature_flag_info('test_feature', 'Test feature')
within_strategy_row(1) do
@@ -29,6 +30,22 @@ RSpec.describe 'User creates feature flag', :js do
expect(page).to have_text('test_feature')
end
+ it 'user creates a flag enabled for user ids with non-existing environment' do
+ visit(new_project_feature_flag_path(project))
+ set_feature_flag_info('test_feature', 'Test feature')
+ within_strategy_row(1) do
+ select 'User IDs', from: 'Type'
+ fill_in 'User IDs', with: 'user1, user2'
+ environment_plus_button.click
+ environment_search_input.set('foo-bar')
+ environment_search_create_button.first.click
+ end
+ click_button 'Create feature flag'
+
+ expect_user_to_see_feature_flags_index_page
+ expect(page).to have_text('test_feature')
+ end
+
it 'user creates a flag with default environment scopes' do
visit(new_project_feature_flag_path(project))
set_feature_flag_info('test_flag', 'Test flag')
@@ -74,14 +91,18 @@ RSpec.describe 'User creates feature flag', :js do
end
def environment_plus_button
- find('.js-new-environments-dropdown')
+ find('[data-testid=new-environments-dropdown]')
end
def environment_search_input
- find('.js-new-environments-dropdown input')
+ find('[data-testid=new-environments-dropdown] input')
end
def environment_search_results
- all('.js-new-environments-dropdown button.dropdown-item')
+ all('[data-testid=new-environments-dropdown] li')
+ end
+
+ def environment_search_create_button
+ all('[data-testid=new-environments-dropdown] button')
end
end
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index b798524b9c4..8f66b722ead 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -3,10 +3,10 @@
require 'spec_helper'
RSpec.describe 'Edit Project Settings', feature_category: :groups_and_projects do
- let(:member) { create(:user) }
+ let(:member) { create(:user, :no_super_sidebar) }
let!(:project) { create(:project, :public, :repository) }
let!(:issue) { create(:issue, project: project) }
- let(:non_member) { create(:user) }
+ let(:non_member) { create(:user, :no_super_sidebar) }
describe 'project features visibility selectors', :js do
before do
diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
index 95e96159744..595aad0144b 100644
--- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb
+++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > Project owner creates a license file', :js, feature_category: :groups_and_projects do
- let(:project) { create(:project, :repository) }
- let(:project_maintainer) { project.first_owner }
+ let_it_be(:project_maintainer) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :repository, namespace: project_maintainer.namespace) }
before do
project.repository.delete_file(project_maintainer, 'LICENSE',
diff --git a/spec/features/projects/files/user_find_file_spec.rb b/spec/features/projects/files/user_find_file_spec.rb
index 5406726eb6e..005a870bea0 100644
--- a/spec/features/projects/files/user_find_file_spec.rb
+++ b/spec/features/projects/files/user_find_file_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'User find project file', feature_category: :groups_and_projects do
include ListboxHelpers
- let(:user) { create :user }
+ let(:user) { create :user, :no_super_sidebar }
let(:project) { create :project, :repository }
before do
diff --git a/spec/features/projects/files/user_searches_for_files_spec.rb b/spec/features/projects/files/user_searches_for_files_spec.rb
index 25456593fc4..627912df408 100644
--- a/spec/features/projects/files/user_searches_for_files_spec.rb
+++ b/spec/features/projects/files/user_searches_for_files_spec.rb
@@ -3,7 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User searches for files', feature_category: :groups_and_projects do
- let(:user) { project.first_owner }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :repository, namespace: user.namespace) }
before do
sign_in(user)
@@ -11,7 +12,7 @@ RSpec.describe 'Projects > Files > User searches for files', feature_category: :
describe 'project main screen' do
context 'when project is empty' do
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project, namespace: user.namespace) }
before do
visit project_path(project)
@@ -25,10 +26,7 @@ RSpec.describe 'Projects > Files > User searches for files', feature_category: :
end
context 'when project is not empty' do
- let(:project) { create(:project, :repository) }
-
before do
- project.add_developer(user)
visit project_path(project)
end
@@ -39,10 +37,7 @@ RSpec.describe 'Projects > Files > User searches for files', feature_category: :
end
describe 'project tree screen' do
- let(:project) { create(:project, :repository) }
-
before do
- project.add_developer(user)
visit project_tree_path(project, project.default_branch)
end
diff --git a/spec/features/projects/forks/fork_list_spec.rb b/spec/features/projects/forks/fork_list_spec.rb
index 966147637f5..86e4e03259e 100644
--- a/spec/features/projects/forks/fork_list_spec.rb
+++ b/spec/features/projects/forks/fork_list_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'listing forks of a project', feature_category: :groups_and_proje
let(:source) { create(:project, :public, :repository) }
let!(:fork) { fork_project(source, nil, repository: true) }
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
source.add_maintainer(user)
diff --git a/spec/features/projects/graph_spec.rb b/spec/features/projects/graph_spec.rb
index 16a3686215f..9b0803e4b0c 100644
--- a/spec/features/projects/graph_spec.rb
+++ b/spec/features/projects/graph_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Project Graph', :js, feature_category: :groups_and_projects do
- let(:user) { create :user }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :repository, namespace: user.namespace) }
let(:branch_name) { 'master' }
diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb
index ad2fccc14bf..bda45da0fa5 100644
--- a/spec/features/projects/import_export/export_file_spec.rb
+++ b/spec/features/projects/import_export/export_file_spec.rb
@@ -38,6 +38,10 @@ RSpec.describe 'Import/Export - project export integration test', :js, feature_c
context 'admin user' do
before do
sign_in(user)
+
+ # Now that we export project in batches we produce more queries than before
+ # needing to increase the default threshold
+ allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(200)
end
it 'exports a project successfully', :sidekiq_inline do
diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb
index 77f95827d88..afcf0e660f7 100644
--- a/spec/features/projects/jobs/user_browses_jobs_spec.rb
+++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe 'User browses jobs', feature_category: :groups_and_projects do
wait_for_requests
- expect(page).to have_selector('[data-testid="ci-badge-canceled"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'canceled')
expect(page).not_to have_selector('[data-testid="jobs-table-error-alert"]')
end
end
@@ -93,7 +93,7 @@ RSpec.describe 'User browses jobs', feature_category: :groups_and_projects do
wait_for_requests
- expect(page).to have_selector('[data-testid="ci-badge-pending"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'pending')
end
end
@@ -133,7 +133,7 @@ RSpec.describe 'User browses jobs', feature_category: :groups_and_projects do
wait_for_requests
- expect(page).to have_selector('[data-testid="ci-badge-pending"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'pending')
end
it 'unschedules a job successfully' do
@@ -141,7 +141,7 @@ RSpec.describe 'User browses jobs', feature_category: :groups_and_projects do
wait_for_requests
- expect(page).to have_selector('[data-testid="ci-badge-manual"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'manual')
end
end
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index c203e644280..1bee4cc5081 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :grou
wait_for_requests
- expect(page).to have_css('[data-testid="ci-badge-passed"]', text: 'passed')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'passed')
end
it 'shows commit`s data', :js do
@@ -93,7 +93,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :grou
visit project_job_path(project, job)
within '.js-pipeline-info' do
- expect(page).to have_content("Pipeline ##{pipeline.id} for #{pipeline.ref}")
+ expect(page).to have_content("Pipeline ##{pipeline.id} #{pipeline.status} for #{pipeline.ref}")
end
end
@@ -239,7 +239,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :grou
href = new_project_issue_path(project, options)
- page.within('.build-sidebar') do
+ page.within('aside.right-sidebar') do
expect(find('[data-testid="job-new-issue"]')['href']).to include(href)
end
end
@@ -1051,7 +1051,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :grou
it 'retries the job' do
find('[data-testid="retry-button-modal"]').click
- within '[data-testid="ci-header-content"]' do
+ within '[data-testid="job-header-content"]' do
expect(page).to have_content('pending')
end
end
diff --git a/spec/features/projects/labels/user_creates_labels_spec.rb b/spec/features/projects/labels/user_creates_labels_spec.rb
index 46729048fe7..6e52963bee2 100644
--- a/spec/features/projects/labels/user_creates_labels_spec.rb
+++ b/spec/features/projects/labels/user_creates_labels_spec.rb
@@ -63,6 +63,8 @@ RSpec.describe "User creates labels", feature_category: :team_planning do
end
end
end
+
+ it_behaves_like "lock_on_merge when creating labels"
end
context "in another project" do
diff --git a/spec/features/projects/labels/user_edits_labels_spec.rb b/spec/features/projects/labels/user_edits_labels_spec.rb
index bf1182cfddd..059edea2109 100644
--- a/spec/features/projects/labels/user_edits_labels_spec.rb
+++ b/spec/features/projects/labels/user_edits_labels_spec.rb
@@ -13,16 +13,16 @@ RSpec.describe "User edits labels", feature_category: :team_planning do
project.add_maintainer(user)
sign_in(user)
- visit(edit_project_label_path(project, label))
+ visit edit_project_label_path(project, label)
end
- it "updates label's title" do
- new_title = "fix"
+ it 'update label with new title' do
+ new_title = 'fix'
- fill_in("Title", with: new_title)
- click_button("Save changes")
+ fill_in('Title', with: new_title)
+ click_button('Save changes')
- page.within(".other-labels .manage-labels-list") do
+ page.within('.other-labels .manage-labels-list') do
expect(page).to have_content(new_title).and have_no_content(label.title)
end
end
@@ -38,4 +38,17 @@ RSpec.describe "User edits labels", feature_category: :team_planning do
expect(page).to have_content("#{label.title} was removed").and have_no_content("#{label.title}</span>")
end
+
+ describe 'lock_on_merge' do
+ let_it_be_with_reload(:label_unlocked) { create(:label, project: project, lock_on_merge: false) }
+ let_it_be(:label_locked) { create(:label, project: project, lock_on_merge: true) }
+ let_it_be(:edit_label_path_unlocked) { edit_project_label_path(project, label_unlocked) }
+ let_it_be(:edit_label_path_locked) { edit_project_label_path(project, label_locked) }
+
+ before do
+ visit edit_label_path_unlocked
+ end
+
+ it_behaves_like 'lock_on_merge when editing labels'
+ end
end
diff --git a/spec/features/projects/members/manage_members_spec.rb b/spec/features/projects/members/manage_members_spec.rb
index 0e3ac5ff3ac..76b2a73e170 100644
--- a/spec/features/projects/members/manage_members_spec.rb
+++ b/spec/features/projects/members/manage_members_spec.rb
@@ -173,7 +173,7 @@ RSpec.describe 'Projects > Members > Manage members', :js, feature_category: :on
end
end
- it_behaves_like 'inviting members', 'project-members-page' do
+ it_behaves_like 'inviting members', 'project_members_page' do
let_it_be(:entity) { project }
let_it_be(:members_page_path) { project_project_members_path(entity) }
let_it_be(:subentity) { project }
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
index 9af36b4b2a9..d1e58ba91f0 100644
--- a/spec/features/projects/members/user_requests_access_spec.rb
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'Projects > Members > User requests access', :js, feature_category: :groups_and_projects do
include Spec::Support::Helpers::ModalHelpers
- let_it_be(:user) { create(:user) }
- let_it_be(:maintainer) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:maintainer) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, :public, :repository) }
let(:owner) { project.first_owner }
diff --git a/spec/features/projects/milestones/user_interacts_with_labels_spec.rb b/spec/features/projects/milestones/user_interacts_with_labels_spec.rb
index 36dfee7811d..3742c9f19d8 100644
--- a/spec/features/projects/milestones/user_interacts_with_labels_spec.rb
+++ b/spec/features/projects/milestones/user_interacts_with_labels_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User interacts with labels', feature_category: :team_planning do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, namespace: user.namespace) }
let(:milestone) { create(:milestone, project: project, title: 'v2.2', description: '# Description header') }
let(:issue1) { create(:issue, project: project, title: 'Bugfix1', milestone: milestone) }
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb
index b6645e9b710..e967c1be3bc 100644
--- a/spec/features/projects/navbar_spec.rb
+++ b/spec/features/projects/navbar_spec.rb
@@ -8,15 +8,13 @@ RSpec.describe 'Project navbar', :with_license, feature_category: :groups_and_pr
include_context 'project navbar structure'
- let_it_be(:project) { create(:project, :repository) }
-
- let(:user) { project.first_owner }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :repository, namespace: user.namespace) }
before do
sign_in(user)
stub_config(registry: { enabled: false })
- stub_feature_flags(harbor_registry_integration: false)
stub_feature_flags(ml_experiment_tracking: false)
insert_package_nav(_('Deployments'))
insert_infrastructure_registry_nav
@@ -88,8 +86,6 @@ RSpec.describe 'Project navbar', :with_license, feature_category: :groups_and_pr
let_it_be(:harbor_integration) { create(:harbor_integration, project: project) }
before do
- stub_feature_flags(harbor_registry_integration: true)
-
insert_harbor_registry_nav(_('Terraform modules'))
visit project_path(project)
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index 6e6d9ff4af9..926fea24e14 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'New project', :js, feature_category: :groups_and_projects do
end
context 'as a user' do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
@@ -76,7 +76,7 @@ RSpec.describe 'New project', :js, feature_category: :groups_and_projects do
end
context 'as an admin' do
- let(:user) { create(:admin) }
+ let(:user) { create(:admin, :no_super_sidebar) }
shared_examples '"New project" page' do
before do
@@ -566,14 +566,14 @@ RSpec.describe 'New project', :js, feature_category: :groups_and_projects do
let(:provider) { :bitbucket }
context 'as a user' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:oauth_config_instructions) { 'To enable importing projects from Bitbucket, ask your GitLab administrator to configure OAuth integration' }
it_behaves_like 'has instructions to enable OAuth'
end
context 'as an admin', :do_not_mock_admin_mode_setting do
- let(:user) { create(:admin) }
+ let(:user) { create(:admin, :no_super_sidebar) }
let(:oauth_config_instructions) { 'To enable importing projects from Bitbucket, as administrator you need to configure OAuth integration' }
it_behaves_like 'has instructions to enable OAuth'
@@ -581,7 +581,7 @@ RSpec.describe 'New project', :js, feature_category: :groups_and_projects do
end
describe 'sidebar' do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:parent_group) { create(:group) }
before do
@@ -616,14 +616,14 @@ RSpec.describe 'New project', :js, feature_category: :groups_and_projects do
context 'for a new top-level project' do
it 'shows the "Your work" navigation' do
visit new_project_path
- expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: "Your work")
+ expect(page).to have_selector(".super-sidebar", text: "Your work")
end
end
context 'for a new group project' do
it 'shows the group sidebar of the parent group' do
visit new_project_path(namespace_id: parent_group.id)
- expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: parent_group.name)
+ expect(page).to have_selector(".super-sidebar", text: parent_group.name)
end
end
end
diff --git a/spec/features/projects/pages/user_edits_settings_spec.rb b/spec/features/projects/pages/user_edits_settings_spec.rb
index eec9f2befb6..8350214bf99 100644
--- a/spec/features/projects/pages/user_edits_settings_spec.rb
+++ b/spec/features/projects/pages/user_edits_settings_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe 'Pages edits pages settings', :js, feature_category: :pages do
include Spec::Support::Helpers::ModalHelpers
let_it_be_with_reload(:project) { create(:project, :pages_published, pages_https_only: false) }
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index 358c55376d4..322d25ed052 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -12,389 +12,301 @@ RSpec.describe 'Pipeline Schedules', :js, feature_category: :groups_and_projects
let!(:user) { create(:user) }
let!(:maintainer) { create(:user) }
- context 'with pipeline_schedules_vue feature flag turned off' do
+ context 'logged in as the pipeline schedule owner' do
before do
- stub_feature_flags(pipeline_schedules_vue: false)
+ project.add_developer(user)
+ pipeline_schedule.update!(owner: user)
+ gitlab_sign_in(user)
end
- context 'logged in as the pipeline schedule owner' do
+ describe 'GET /projects/pipeline_schedules' do
before do
- project.add_developer(user)
- pipeline_schedule.update!(owner: user)
- gitlab_sign_in(user)
+ visit_pipelines_schedules
end
- describe 'GET /projects/pipeline_schedules' do
- before do
- visit_pipelines_schedules
- end
-
- it 'edits the pipeline' do
- page.within('.pipeline-schedule-table-row') do
- click_link 'Edit'
- end
+ it 'edits the pipeline' do
+ page.find('[data-testid="edit-pipeline-schedule-btn"]').click
- expect(page).to have_content('Edit Pipeline Schedule')
- end
+ expect(page).to have_content(s_('PipelineSchedules|Edit pipeline schedule'))
end
+ end
- describe 'PATCH /projects/pipelines_schedules/:id/edit' do
- before do
- edit_pipeline_schedule
- end
-
- it 'displays existing properties' do
- description = find_field('schedule_description').value
- expect(description).to eq('pipeline schedule')
- expect(page).to have_button('master')
- expect(page).to have_button('Select timezone')
- end
+ describe 'PATCH /projects/pipelines_schedules/:id/edit' do
+ before do
+ edit_pipeline_schedule
+ end
- it 'edits the scheduled pipeline' do
- fill_in 'schedule_description', with: 'my brand new description'
+ it 'displays existing properties' do
+ description = find_field('schedule-description').value
+ expect(description).to eq('pipeline schedule')
+ expect(page).to have_button('master')
+ expect(page).to have_button(_('Select timezone'))
+ end
- save_pipeline_schedule
+ it 'edits the scheduled pipeline' do
+ fill_in 'schedule-description', with: 'my brand new description'
- expect(page).to have_content('my brand new description')
- end
+ save_pipeline_schedule
- context 'when ref is nil' do
- before do
- pipeline_schedule.update_attribute(:ref, nil)
- edit_pipeline_schedule
- end
+ expect(page).to have_content('my brand new description')
+ end
- it 'shows the pipeline schedule with default ref' do
- page.within('[data-testid="schedule-target-ref"]') do
- expect(first('.gl-button-text').text).to eq('master')
- end
- end
+ context 'when ref is nil' do
+ before do
+ pipeline_schedule.update_attribute(:ref, nil)
+ edit_pipeline_schedule
end
- context 'when ref is empty' do
- before do
- pipeline_schedule.update_attribute(:ref, '')
- edit_pipeline_schedule
- end
-
- it 'shows the pipeline schedule with default ref' do
- page.within('[data-testid="schedule-target-ref"]') do
- expect(first('.gl-button-text').text).to eq('master')
- end
+ it 'shows the pipeline schedule with default ref' do
+ page.within('#schedule-target-branch-tag') do
+ expect(first('.gl-button-text').text).to eq('master')
end
end
end
- end
-
- context 'logged in as a project maintainer' do
- before do
- project.add_maintainer(user)
- gitlab_sign_in(user)
- end
- describe 'GET /projects/pipeline_schedules' do
+ context 'when ref is empty' do
before do
- visit_pipelines_schedules
+ pipeline_schedule.update_attribute(:ref, '')
+ edit_pipeline_schedule
end
- describe 'The view' do
- it 'displays the required information description' do
- page.within('.pipeline-schedule-table-row') do
- expect(page).to have_content('pipeline schedule')
- expect(find("[data-testid='next-run-cell'] time")['title'])
- .to include(pipeline_schedule.real_next_run.strftime('%b %-d, %Y'))
- expect(page).to have_link('master')
- expect(page).to have_link("##{pipeline.id}")
- end
- end
-
- it 'creates a new scheduled pipeline' do
- click_link 'New schedule'
-
- expect(page).to have_content('Schedule a new pipeline')
- end
-
- it 'changes ownership of the pipeline' do
- click_button 'Take ownership'
-
- page.within('#pipeline-take-ownership-modal') do
- click_link 'Take ownership'
- end
-
- page.within('.pipeline-schedule-table-row') do
- expect(page).not_to have_content('No owner')
- expect(page).to have_link('Sidney Jones')
- end
- end
-
- it 'deletes the pipeline' do
- click_link 'Delete'
-
- accept_gl_confirm(button_text: 'Delete pipeline schedule')
-
- expect(page).not_to have_css(".pipeline-schedule-table-row")
+ it 'shows the pipeline schedule with default ref' do
+ page.within('#schedule-target-branch-tag') do
+ expect(first('.gl-button-text').text).to eq('master')
end
end
+ end
+ end
+ end
- context 'when ref is nil' do
- before do
- pipeline_schedule.update_attribute(:ref, nil)
- visit_pipelines_schedules
- end
-
- it 'shows a list of the pipeline schedules with empty ref column' do
- expect(first('.branch-name-cell').text).to eq('')
- end
- end
+ context 'logged in as a project maintainer' do
+ before do
+ project.add_maintainer(user)
+ pipeline_schedule.update!(owner: maintainer)
+ gitlab_sign_in(user)
+ end
- context 'when ref is empty' do
- before do
- pipeline_schedule.update_attribute(:ref, '')
- visit_pipelines_schedules
- end
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
- it 'shows a list of the pipeline schedules with empty ref column' do
- expect(first('.branch-name-cell').text).to eq('')
- end
- end
+ wait_for_requests
end
- describe 'POST /projects/pipeline_schedules/new' do
- before do
- visit_new_pipeline_schedule
- end
-
- it 'sets defaults for timezone and target branch' do
- expect(page).to have_button('master')
- expect(page).to have_button('Select timezone')
+ describe 'The view' do
+ it 'displays the required information description' do
+ page.within('[data-testid="pipeline-schedule-table-row"]') do
+ expect(page).to have_content('pipeline schedule')
+ expect(find('[data-testid="next-run-cell"] time')['title'])
+ .to include(pipeline_schedule.real_next_run.strftime('%b %-d, %Y'))
+ expect(page).to have_link('master')
+ expect(find("[data-testid='last-pipeline-status'] a")['href']).to include(pipeline.id.to_s)
+ end
end
it 'creates a new scheduled pipeline' do
- fill_in_schedule_form
- save_pipeline_schedule
+ click_link 'New schedule'
- expect(page).to have_content('my fancy description')
+ expect(page).to have_content('Schedule a new pipeline')
end
- it 'prevents an invalid form from being submitted' do
- save_pipeline_schedule
+ it 'changes ownership of the pipeline' do
+ find("[data-testid='take-ownership-pipeline-schedule-btn']").click
- expect(page).to have_content('This field is required')
- end
- end
+ page.within('#pipeline-take-ownership-modal') do
+ click_button s_('PipelineSchedules|Take ownership')
- context 'when user creates a new pipeline schedule with variables' do
- before do
- visit_pipelines_schedules
- click_link 'New schedule'
- fill_in_schedule_form
- all('[name="schedule[variables_attributes][][key]"]')[0].set('AAA')
- all('[name="schedule[variables_attributes][][secret_value]"]')[0].set('AAA123')
- all('[name="schedule[variables_attributes][][key]"]')[1].set('BBB')
- all('[name="schedule[variables_attributes][][secret_value]"]')[1].set('BBB123')
- save_pipeline_schedule
- end
+ wait_for_requests
+ end
- it 'user sees the new variable in edit window', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/397040' do
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- page.within('.ci-variable-list') do
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('AAA')
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('AAA123')
- expect(find(".ci-variable-row:nth-child(2) .js-ci-variable-input-key").value).to eq('BBB')
- expect(find(".ci-variable-row:nth-child(2) .js-ci-variable-input-value", visible: false).value).to eq('BBB123')
+ page.within('[data-testid="pipeline-schedule-table-row"]') do
+ expect(page).not_to have_content('No owner')
+ expect(page).to have_link('Sidney Jones')
end
end
- end
- context 'when user edits a variable of a pipeline schedule' do
- before do
- create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
- create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
+ it 'deletes the pipeline' do
+ page.within('[data-testid="pipeline-schedule-table-row"]') do
+ click_button s_('PipelineSchedules|Delete pipeline schedule')
end
- visit_pipelines_schedules
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- find('.js-ci-variable-list-section .js-secret-value-reveal-button').click
- first('.js-ci-variable-input-key').set('foo')
- first('.js-ci-variable-input-value').set('bar')
- click_button 'Save pipeline schedule'
- end
+ accept_gl_confirm(button_text: s_('PipelineSchedules|Delete pipeline schedule'))
- it 'user sees the updated variable in edit window' do
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- page.within('.ci-variable-list') do
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('foo')
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('bar')
- end
+ expect(page).not_to have_css('[data-testid="pipeline-schedule-table-row"]')
end
end
- context 'when user removes a variable of a pipeline schedule' do
+ context 'when ref is nil' do
before do
- create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
- create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
- end
-
+ pipeline_schedule.update_attribute(:ref, nil)
visit_pipelines_schedules
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- find('.ci-variable-list .ci-variable-row-remove-button').click
- click_button 'Save pipeline schedule'
+ wait_for_requests
end
- it 'user does not see the removed variable in edit window' do
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- page.within('.ci-variable-list') do
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('')
- expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('')
+ it 'shows a list of the pipeline schedules with empty ref column' do
+ target = find('[data-testid="pipeline-schedule-target"]')
+
+ page.within('[data-testid="pipeline-schedule-table-row"]') do
+ expect(target.text).to eq(s_('PipelineSchedules|None'))
end
end
end
- context 'when active is true and next_run_at is NULL' do
+ context 'when ref is empty' do
before do
- create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
- pipeline_schedule.update_attribute(:next_run_at, nil) # Consequently next_run_at will be nil
- end
+ pipeline_schedule.update_attribute(:ref, '')
+ visit_pipelines_schedules
+ wait_for_requests
end
- it 'user edit and recover the problematic pipeline schedule' do
- visit_pipelines_schedules
- find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
- fill_in 'schedule_cron', with: '* 1 2 3 4'
- click_button 'Save pipeline schedule'
+ it 'shows a list of the pipeline schedules with empty ref column' do
+ target = find('[data-testid="pipeline-schedule-target"]')
- page.within('.pipeline-schedule-table-row:nth-child(1)') do
- expect(page).to have_css("[data-testid='next-run-cell'] time")
- end
+ expect(target.text).to eq(s_('PipelineSchedules|None'))
end
end
end
- context 'logged in as non-member' do
+ describe 'POST /projects/pipeline_schedules/new' do
before do
- gitlab_sign_in(user)
+ visit_new_pipeline_schedule
end
- describe 'GET /projects/pipeline_schedules' do
- before do
- visit_pipelines_schedules
- end
+ it 'sets defaults for timezone and target branch' do
+ expect(page).to have_button('master')
+ expect(page).to have_button('Select timezone')
+ end
- describe 'The view' do
- it 'does not show create schedule button' do
- expect(page).not_to have_link('New schedule')
- end
- end
+ it 'creates a new scheduled pipeline' do
+ fill_in_schedule_form
+ create_pipeline_schedule
+
+ expect(page).to have_content('my fancy description')
end
- end
- context 'not logged in' do
- describe 'GET /projects/pipeline_schedules' do
- before do
- visit_pipelines_schedules
- end
+ it 'prevents an invalid form from being submitted' do
+ create_pipeline_schedule
- describe 'The view' do
- it 'does not show create schedule button' do
- expect(page).not_to have_link('New schedule')
- end
- end
+ expect(page).to have_content("Cron timezone can't be blank")
end
end
- end
- context 'with pipeline_schedules_vue feature flag turned on' do
- context 'logged in as a project maintainer' do
+ context 'when user creates a new pipeline schedule with variables' do
before do
- project.add_maintainer(maintainer)
- pipeline_schedule.update!(owner: user)
- gitlab_sign_in(maintainer)
+ visit_pipelines_schedules
+ click_link 'New schedule'
+ fill_in_schedule_form
+ all('[name="schedule[variables_attributes][][key]"]')[0].set('AAA')
+ all('[name="schedule[variables_attributes][][secret_value]"]')[0].set('AAA123')
+ all('[name="schedule[variables_attributes][][key]"]')[1].set('BBB')
+ all('[name="schedule[variables_attributes][][secret_value]"]')[1].set('BBB123')
+ create_pipeline_schedule
end
- describe 'GET /projects/pipeline_schedules' do
- before do
- visit_pipelines_schedules
-
- wait_for_requests
+ it 'user sees the new variable in edit window', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/397040' do
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ page.within('.ci-variable-list') do
+ expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-key").value).to eq('AAA')
+ expect(find(".ci-variable-row:nth-child(1) .js-ci-variable-input-value", visible: false).value).to eq('AAA123')
+ expect(find(".ci-variable-row:nth-child(2) .js-ci-variable-input-key").value).to eq('BBB')
+ expect(find(".ci-variable-row:nth-child(2) .js-ci-variable-input-value", visible: false).value).to eq('BBB123')
end
+ end
+ end
- describe 'The view' do
- it 'displays the required information description' do
- page.within('[data-testid="pipeline-schedule-table-row"]') do
- expect(page).to have_content('pipeline schedule')
- expect(find("[data-testid='next-run-cell'] time")['title'])
- .to include(pipeline_schedule.real_next_run.strftime('%b %-d, %Y'))
- expect(page).to have_link('master')
- expect(find("[data-testid='last-pipeline-status'] a")['href']).to include(pipeline.id.to_s)
- end
- end
-
- it 'changes ownership of the pipeline' do
- click_button 'Take ownership'
+ context 'when user edits a variable of a pipeline schedule' do
+ before do
+ create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
+ create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
+ end
- page.within('#pipeline-take-ownership-modal') do
- click_button 'Take ownership'
+ visit_pipelines_schedules
+ first('[data-testid="edit-pipeline-schedule-btn"]').click
+ click_button _('Reveal values')
+ first('[data-testid="pipeline-form-ci-variable-key"]').set('foo')
+ first('[data-testid="pipeline-form-ci-variable-value"]').set('bar')
+ save_pipeline_schedule
+ end
- wait_for_requests
- end
+ it 'user sees the updated variable' do
+ first('[data-testid="edit-pipeline-schedule-btn"]').click
- page.within('[data-testid="pipeline-schedule-table-row"]') do
- expect(page).not_to have_content('No owner')
- expect(page).to have_link('Sidney Jones')
- end
- end
+ expect(first('[data-testid="pipeline-form-ci-variable-key"]').value).to eq('foo')
+ expect(first('[data-testid="pipeline-form-ci-variable-value"]').value).to eq('')
- it 'runs the pipeline' do
- click_button 'Run pipeline schedule'
+ click_button _('Reveal values')
- wait_for_requests
+ expect(first('[data-testid="pipeline-form-ci-variable-value"]').value).to eq('bar')
+ end
+ end
- expect(page).to have_content("Successfully scheduled a pipeline to run. Go to the Pipelines page for details.")
- end
+ context 'when user removes a variable of a pipeline schedule' do
+ before do
+ create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
+ create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
+ end
- it 'deletes the pipeline' do
- click_button 'Delete pipeline schedule'
+ visit_pipelines_schedules
+ first('[data-testid="edit-pipeline-schedule-btn"]').click
+ find('[data-testid="remove-ci-variable-row"]').click
+ save_pipeline_schedule
+ end
- accept_gl_confirm(button_text: 'Delete pipeline schedule')
+ it 'user does not see the removed variable in edit window' do
+ first('[data-testid="edit-pipeline-schedule-btn"]').click
- expect(page).not_to have_css('[data-testid="pipeline-schedule-table-row"]')
- end
- end
+ expect(first('[data-testid="pipeline-form-ci-variable-key"]').value).to eq('')
+ expect(first('[data-testid="pipeline-form-ci-variable-value"]').value).to eq('')
end
end
- context 'logged in as non-member' do
+ context 'when active is true and next_run_at is NULL' do
before do
- gitlab_sign_in(user)
+ create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
+ pipeline_schedule.update_attribute(:next_run_at, nil) # Consequently next_run_at will be nil
+ end
end
- describe 'GET /projects/pipeline_schedules' do
- before do
- visit_pipelines_schedules
+ it 'user edit and recover the problematic pipeline schedule' do
+ visit_pipelines_schedules
+ first('[data-testid="edit-pipeline-schedule-btn"]').click
+ fill_in 'schedule_cron', with: '* 1 2 3 4'
+ save_pipeline_schedule
- wait_for_requests
- end
-
- describe 'The view' do
- it 'does not show create schedule button' do
- expect(page).not_to have_link('New schedule')
- end
+ page.within(first('[data-testid="pipeline-schedule-table-row"]')) do
+ expect(page).to have_css("[data-testid='next-run-cell'] time")
end
end
end
+ end
- context 'not logged in' do
- describe 'GET /projects/pipeline_schedules' do
- before do
- visit_pipelines_schedules
+ context 'logged in as non-member' do
+ before do
+ gitlab_sign_in(user)
+ end
- wait_for_requests
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
+ end
+
+ describe 'The view' do
+ it 'does not show create schedule button' do
+ expect(page).not_to have_link('New schedule')
end
+ end
+ end
+ end
- describe 'The view' do
- it 'does not show create schedule button' do
- expect(page).not_to have_link('New schedule')
- end
+ context 'not logged in' do
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
+ end
+
+ describe 'The view' do
+ it 'does not show create schedule button' do
+ expect(page).not_to have_link('New schedule')
end
end
end
@@ -413,7 +325,7 @@ RSpec.describe 'Pipeline Schedules', :js, feature_category: :groups_and_projects
end
def select_timezone
- find('[data-testid="schedule-timezone"] .gl-new-dropdown-toggle').click
+ find('#schedule-timezone .gl-new-dropdown-toggle').click
find("li", text: "Arizona").click
end
@@ -421,12 +333,16 @@ RSpec.describe 'Pipeline Schedules', :js, feature_category: :groups_and_projects
click_button 'master'
end
+ def create_pipeline_schedule
+ click_button s_('PipelineSchedules|Create pipeline schedule')
+ end
+
def save_pipeline_schedule
- click_button 'Save pipeline schedule'
+ click_button s_('PipelineSchedules|Edit pipeline schedule')
end
def fill_in_schedule_form
- fill_in 'schedule_description', with: 'my fancy description'
+ fill_in 'schedule-description', with: 'my fancy description'
fill_in 'schedule_cron', with: '* 1 2 3 4'
select_timezone
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index bb49fb734d7..2fc8345fb47 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -224,7 +224,7 @@ RSpec.describe 'Pipeline', :js, feature_category: :groups_and_projects do
expect(page).not_to have_content('Retry job')
within('[data-testid="pipeline-details-header"]') do
- expect(page).to have_selector('[data-testid="ci-badge-running"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'running')
end
end
end
@@ -278,7 +278,7 @@ RSpec.describe 'Pipeline', :js, feature_category: :groups_and_projects do
expect(page).not_to have_content('Retry job')
within('[data-testid="pipeline-details-header"]') do
- expect(page).to have_selector('[data-testid="ci-badge-running"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'running')
end
end
@@ -312,7 +312,7 @@ RSpec.describe 'Pipeline', :js, feature_category: :groups_and_projects do
expect(page).not_to have_content('Play job')
within('[data-testid="pipeline-details-header"]') do
- expect(page).to have_selector('[data-testid="ci-badge-running"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'running')
end
end
end
@@ -537,7 +537,7 @@ RSpec.describe 'Pipeline', :js, feature_category: :groups_and_projects do
it 'shows running status in pipeline header', :sidekiq_might_not_need_inline do
within('[data-testid="pipeline-details-header"]') do
- expect(page).to have_selector('[data-testid="ci-badge-running"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'running')
end
end
end
@@ -843,12 +843,10 @@ RSpec.describe 'Pipeline', :js, feature_category: :groups_and_projects do
end
it 'displays the PipelineSchedule in an inactive state' do
- stub_feature_flags(pipeline_schedules_vue: false)
-
visit project_pipeline_schedules_path(project)
page.click_link('Inactive')
- expect(page).to have_selector('table.ci-table > tbody > tr > td', text: 'blocked user schedule')
+ expect(page).to have_selector('[data-testid="pipeline-schedule-description"]', text: 'blocked user schedule')
end
it 'does not create a new Pipeline', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408215' do
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 26fcd8ca3ca..c1aa2c35337 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
let(:expected_detached_mr_tag) { 'merge request' }
context 'when user is logged in' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
@@ -115,7 +115,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
it 'indicates that pipeline can be canceled' do
expect(page).to have_selector('.js-pipelines-cancel-button')
- expect(page).to have_selector('[data-testid="ci-badge-running"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'running')
end
context 'when canceling' do
@@ -127,7 +127,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
it 'indicated that pipelines was canceled', :sidekiq_might_not_need_inline do
expect(page).not_to have_selector('.js-pipelines-cancel-button')
- expect(page).to have_selector('[data-testid="ci-badge-canceled"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'canceled')
end
end
end
@@ -144,7 +144,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
it 'indicates that pipeline can be retried' do
expect(page).to have_selector('.js-pipelines-retry-button')
- expect(page).to have_selector('[data-testid="ci-badge-failed"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'failed')
end
context 'when retrying' do
@@ -155,7 +155,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
it 'shows running pipeline that is not retryable' do
expect(page).not_to have_selector('.js-pipelines-retry-button')
- expect(page).to have_selector('[data-testid="ci-badge-running"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'running')
end
end
end
@@ -396,7 +396,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
end
it 'shows the pipeline as preparing' do
- expect(page).to have_selector('[data-testid="ci-badge-preparing"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'preparing')
end
end
@@ -417,7 +417,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
end
it 'has pipeline running' do
- expect(page).to have_selector('[data-testid="ci-badge-running"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'running')
end
context 'when canceling' do
@@ -428,7 +428,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
it 'indicates that pipeline was canceled', :sidekiq_might_not_need_inline do
expect(page).not_to have_selector('.js-pipelines-cancel-button')
- expect(page).to have_selector('[data-testid="ci-badge-canceled"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'canceled')
end
end
end
@@ -450,7 +450,7 @@ RSpec.describe 'Pipelines', :js, feature_category: :continuous_integration do
end
it 'has failed pipeline', :sidekiq_might_not_need_inline do
- expect(page).to have_selector('[data-testid="ci-badge-failed"]')
+ expect(page).to have_selector('[data-testid="ci-badge-link"]', text: 'failed')
end
end
end
diff --git a/spec/features/projects/settings/monitor_settings_spec.rb b/spec/features/projects/settings/monitor_settings_spec.rb
index b46451f4255..c2914c020e3 100644
--- a/spec/features/projects/settings/monitor_settings_spec.rb
+++ b/spec/features/projects/settings/monitor_settings_spec.rb
@@ -5,9 +5,8 @@ require 'spec_helper'
RSpec.describe 'Projects > Settings > For a forked project', :js, feature_category: :groups_and_projects do
include ListboxHelpers
- let_it_be(:project) { create(:project, :repository, create_templates: :issue) }
-
- let(:user) { project.first_owner }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :repository, create_templates: :issue, namespace: user.namespace) }
before do
sign_in(user)
diff --git a/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb b/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
index 1ab88ec0fff..ee54065fdf8 100644
--- a/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
+++ b/spec/features/projects/settings/registry_settings_cleanup_tags_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Project > Settings > Packages and registries > Container registry tag expiration policy',
feature_category: :groups_and_projects do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project, reload: true) { create(:project, namespace: user.namespace) }
let(:container_registry_enabled) { true }
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index 9df82e447aa..7f0367f47f7 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Project > Settings > Packages and registries > Container registry tag expiration policy',
feature_category: :groups_and_projects do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project, reload: true) { create(:project, namespace: user.namespace) }
let(:container_registry_enabled) { true }
diff --git a/spec/features/projects/settings/service_desk_setting_spec.rb b/spec/features/projects/settings/service_desk_setting_spec.rb
index d068cb219f1..5cc2e2d3c05 100644
--- a/spec/features/projects/settings/service_desk_setting_spec.rb
+++ b/spec/features/projects/settings/service_desk_setting_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache, feature_c
wait_for_requests
project.reload
- expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_custom_address)
+ expect(find('[data-testid="incoming-email"]').value).to eq(project.service_desk_alias_address)
page.within '#js-service-desk' do
fill_in('service-desk-project-suffix', with: 'foo')
diff --git a/spec/features/projects/show/user_sees_collaboration_links_spec.rb b/spec/features/projects/show/user_sees_collaboration_links_spec.rb
index ee017336acc..626d4de7baf 100644
--- a/spec/features/projects/show/user_sees_collaboration_links_spec.rb
+++ b/spec/features/projects/show/user_sees_collaboration_links_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Projects > Show > Collaboration links', :js, feature_category: :
using RSpec::Parameterized::TableSyntax
let_it_be(:project) { create(:project, :repository, :public) }
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/projects/user_sees_sidebar_spec.rb b/spec/features/projects/user_sees_sidebar_spec.rb
index 5a744be5d81..22d00e9a351 100644
--- a/spec/features/projects/user_sees_sidebar_spec.rb
+++ b/spec/features/projects/user_sees_sidebar_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Projects > User sees sidebar', feature_category: :groups_and_projects do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :private, public_builds: false, namespace: user.namespace) }
# NOTE: See documented behaviour https://design.gitlab.com/regions/navigation#contextual-navigation
@@ -182,7 +182,7 @@ RSpec.describe 'Projects > User sees sidebar', feature_category: :groups_and_pro
end
context 'as guest' do
- let(:guest) { create(:user) }
+ let(:guest) { create(:user, :no_super_sidebar) }
let!(:issue) { create(:issue, :opened, project: project, author: guest) }
before do
diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb
index 77f753b92eb..b7b2093d78a 100644
--- a/spec/features/projects/user_uses_shortcuts_spec.rb
+++ b/spec/features/projects/user_uses_shortcuts_spec.rb
@@ -3,9 +3,8 @@
require 'spec_helper'
RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_projects do
- let_it_be(:project) { create(:project, :repository) }
-
- let(:user) { project.first_owner }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:project) { create(:project, :repository, namespace: user.namespace) }
before do
sign_in(user)
@@ -15,58 +14,6 @@ RSpec.describe 'User uses shortcuts', :js, feature_category: :groups_and_project
wait_for_requests
end
- context 'disabling shortcuts' do
- before do
- page.evaluate_script("localStorage.removeItem('shortcutsDisabled')")
- end
-
- it 'can disable shortcuts from help menu' do
- open_modal_shortcut_keys
- click_toggle_button
- close_modal
-
- open_modal_shortcut_keys
-
- expect(page).not_to have_selector('[data-testid="modal-shortcuts"]')
-
- page.refresh
- open_modal_shortcut_keys
-
- # after reload, shortcuts modal doesn't exist at all until we add it
- expect(page).not_to have_selector('[data-testid="modal-shortcuts"]')
- end
-
- it 're-enables shortcuts' do
- open_modal_shortcut_keys
- click_toggle_button
- close_modal
-
- open_modal_from_help_menu
- click_toggle_button
- close_modal
-
- open_modal_shortcut_keys
- expect(find('[data-testid="modal-shortcuts"]')).to be_visible
- end
-
- def open_modal_shortcut_keys
- find('body').native.send_key('?')
- end
-
- def open_modal_from_help_menu
- find('.header-help-dropdown-toggle').click
- find('button', text: 'Keyboard shortcuts').click
- end
-
- def click_toggle_button
- find('.js-toggle-shortcuts .gl-toggle').click
- end
-
- def close_modal
- find('.modal button[aria-label="Close"]').click
- end
- end
-
context 'when navigating to the Project pages' do
it 'redirects to the project overview page' do
visit project_issues_path(project)
diff --git a/spec/features/projects/wikis_spec.rb b/spec/features/projects/wikis_spec.rb
index 5d950da6674..63714954c0c 100644
--- a/spec/features/projects/wikis_spec.rb
+++ b/spec/features/projects/wikis_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
RSpec.describe 'Project wikis', :js, feature_category: :wiki do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let(:wiki) { create(:project_wiki, user: user, project: project) }
let(:project) { create(:project, namespace: user.namespace, creator: user) }
diff --git a/spec/features/projects/work_items/work_item_spec.rb b/spec/features/projects/work_items/work_item_spec.rb
index 618d3e2efd0..a1f5466f5bf 100644
--- a/spec/features/projects/work_items/work_item_spec.rb
+++ b/spec/features/projects/work_items/work_item_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'Work item', :js, feature_category: :team_planning do
- let_it_be_with_reload(:user) { create(:user) }
- let_it_be_with_reload(:user2) { create(:user, name: 'John') }
+ let_it_be_with_reload(:user) { create(:user, :no_super_sidebar) }
+ let_it_be_with_reload(:user2) { create(:user, :no_super_sidebar, name: 'John') }
let_it_be(:project) { create(:project, :public) }
let_it_be(:work_item) { create(:work_item, project: project) }
@@ -39,6 +39,44 @@ RSpec.describe 'Work item', :js, feature_category: :team_planning do
expect(page).to have_selector('[data-testid="work-item-actions-dropdown"]')
end
+ it 'reassigns to another user',
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/413074' do
+ find('[data-testid="work-item-assignees-input"]').fill_in(with: user.username)
+ wait_for_requests
+
+ send_keys(:enter)
+ find("body").click
+ wait_for_requests
+
+ find('[data-testid="work-item-assignees-input"]').fill_in(with: user2.username)
+ wait_for_requests
+
+ send_keys(:enter)
+ find("body").click
+ wait_for_requests
+
+ expect(work_item.reload.assignees).to include(user2)
+ end
+
+ it 'updates the assignee in real-time' do
+ Capybara::Session.new(:other_session)
+
+ using_session :other_session do
+ visit work_items_path
+ expect(work_item.reload.assignees).not_to include(user)
+ end
+
+ find('[data-testid="work-item-assignees-input"]').hover
+ find('[data-testid="assign-self"]').click
+ wait_for_requests
+
+ expect(work_item.reload.assignees).to include(user)
+
+ using_session :other_session do
+ expect(work_item.reload.assignees).to include(user)
+ end
+ end
+
it_behaves_like 'work items title'
it_behaves_like 'work items toggle status button'
it_behaves_like 'work items assignees'
@@ -90,5 +128,11 @@ RSpec.describe 'Work item', :js, feature_category: :team_planning do
expect(page).to have_selector('[data-testid="award-button"].disabled')
end
end
+
+ it 'assignees input field is disabled' do
+ within('[data-testid="work-item-assignees-input"]') do
+ expect(page).to have_field(type: 'text', disabled: true)
+ end
+ end
end
end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index d28fafaac45..7ca9395f669 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
include MobileHelpers
describe 'template' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in user
@@ -78,7 +78,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
end
describe 'shows tip about push to create git command' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in user
@@ -214,7 +214,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
end
describe 'showing information about source of a project fork', :js do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:base_project) { create(:project, :public, :repository) }
let(:forked_project) { fork_project(base_project, user, repository: true) }
@@ -265,7 +265,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
end
describe 'when the project repository is disabled', :js do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :repository_disabled, :repository, namespace: user.namespace) }
before do
@@ -282,7 +282,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
end
describe 'removal', :js do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, namespace: user.namespace) }
before do
@@ -307,7 +307,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
end
describe 'tree view (default view is set to Files)', :js do
- let(:user) { create(:user, project_view: 'files') }
+ let(:user) { create(:user, :no_super_sidebar, project_view: 'files') }
let(:project) { create(:forked_project_with_submodules) }
before do
@@ -379,7 +379,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
end
describe 'activity view' do
- let(:user) { create(:user, project_view: 'activity') }
+ let(:user) { create(:user, :no_super_sidebar, project_view: 'activity') }
let(:project) { create(:project, :repository) }
before do
@@ -410,7 +410,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
end
describe 'edit' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :public) }
let(:path) { edit_project_path(project) }
@@ -425,7 +425,7 @@ RSpec.describe 'Project', feature_category: :groups_and_projects do
describe 'view for a user without an access to a repo' do
let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
it 'does not contain default branch information in its content' do
default_branch = 'merge-commit-analyze-side-branch'
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 3c63ec82778..091c318459b 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -9,396 +9,387 @@ RSpec.describe 'Runners', feature_category: :runner_fleet do
sign_in(user)
end
- context 'when project_runners_vue_ui is disabled' do
- before do
- stub_feature_flags(project_runners_vue_ui: false)
- end
+ context 'with user as project maintainer' do
+ let_it_be(:project) { create(:project).tap { |project| project.add_maintainer(user) } }
- context 'with user as project maintainer' do
- let_it_be(:project) { create(:project).tap { |project| project.add_maintainer(user) } }
+ context 'when user views runners page', :js do
+ before do
+ visit project_runners_path(project)
+ end
- context 'when user views runners page', :js do
- before do
- visit project_runners_path(project)
- end
+ it 'user can see a link with instructions on how to install GitLab Runner' do
+ expect(page).to have_link(s_('Runners|New project runner'), href: new_project_runner_path(project))
+ end
- it 'user can see a link with instructions on how to install GitLab Runner' do
- expect(page).to have_link(s_('Runners|New project runner'), href: new_project_runner_path(project))
- end
+ it_behaves_like "shows and resets runner registration token" do
+ let(:dropdown_text) { s_('Runners|Register a project runner') }
+ let(:registration_token) { project.runners_token }
+ end
+ end
- it_behaves_like "shows and resets runner registration token" do
- let(:dropdown_text) { s_('Runners|Register a project runner') }
- let(:registration_token) { project.runners_token }
- end
+ context 'when user views new runner page', :js do
+ before do
+ visit new_project_runner_path(project)
end
- context 'when user views new runner page', :js do
- before do
- visit new_project_runner_path(project)
- end
+ it_behaves_like 'creates runner and shows register page' do
+ let(:register_path_pattern) { register_project_runner_path(project, '.*') }
+ end
- it_behaves_like 'creates runner and shows register page' do
- let(:register_path_pattern) { register_project_runner_path(project, '.*') }
- end
+ it_behaves_like 'shows locked field'
+ end
+ end
- it 'shows the locked field' do
- expect(page).to have_selector('input[type="checkbox"][name="locked"]')
- expect(page).to have_content(_('Lock to current projects'))
- end
- end
+ context 'when a project has enabled shared_runners' do
+ let_it_be(:project) { create(:project) }
+
+ before do
+ project.add_maintainer(user)
end
- context 'when a project has enabled shared_runners' do
- let_it_be(:project) { create(:project) }
+ context 'when a project_type runner is activated on the project' do
+ let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project]) }
- before do
- project.add_maintainer(user)
- end
+ it 'user sees the project runner' do
+ visit project_runners_path(project)
- context 'when a project_type runner is activated on the project' do
- let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project]) }
+ within '[data-testid="assigned_project_runners"]' do
+ expect(page).to have_content(project_runner.display_name)
+ end
- it 'user sees the project runner' do
- visit project_runners_path(project)
+ click_on project_runner.short_sha
- within '[data-testid="assigned_project_runners"]' do
- expect(page).to have_content(project_runner.display_name)
- end
+ expect(page).to have_content(project_runner.platform)
+ end
- click_on project_runner.short_sha
+ it 'user can pause and resume the project runner' do
+ visit project_runners_path(project)
- expect(page).to have_content(project_runner.platform)
+ within '[data-testid="assigned_project_runners"]' do
+ expect(page).to have_link('Pause')
end
- it 'user can pause and resume the project runner' do
- visit project_runners_path(project)
+ click_on 'Pause'
- within '[data-testid="assigned_project_runners"]' do
- expect(page).to have_link('Pause')
- end
+ within '[data-testid="assigned_project_runners"]' do
+ expect(page).to have_link('Resume')
+ end
- click_on 'Pause'
+ click_on 'Resume'
- within '[data-testid="assigned_project_runners"]' do
- expect(page).to have_link('Resume')
- end
+ within '[data-testid="assigned_project_runners"]' do
+ expect(page).to have_link('Pause')
+ end
+ end
- click_on 'Resume'
+ it 'user removes an activated project runner if this is last project for that runners' do
+ visit project_runners_path(project)
- within '[data-testid="assigned_project_runners"]' do
- expect(page).to have_link('Pause')
- end
+ within '[data-testid="assigned_project_runners"]' do
+ click_on 'Remove runner'
end
- it 'user removes an activated project runner if this is last project for that runners' do
- visit project_runners_path(project)
+ expect(page).not_to have_content(project_runner.display_name)
+ end
- within '[data-testid="assigned_project_runners"]' do
- click_on 'Remove runner'
- end
+ it 'user edits the runner to be protected' do
+ visit project_runners_path(project)
+
+ within '[data-testid="assigned_project_runners"]' do
+ first('[data-testid="edit-runner-link"]').click
+ end
+
+ expect(page.find_field('runner[access_level]')).not_to be_checked
+
+ check 'runner_access_level'
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Protected Yes'
+ end
- expect(page).not_to have_content(project_runner.display_name)
+ context 'when a runner has a tag' do
+ before do
+ project_runner.update!(tag_list: ['tag'])
end
- it 'user edits the runner to be protected' do
+ it 'user edits runner not to run untagged jobs' do
visit project_runners_path(project)
within '[data-testid="assigned_project_runners"]' do
first('[data-testid="edit-runner-link"]').click
end
- expect(page.find_field('runner[access_level]')).not_to be_checked
+ expect(page.find_field('runner[run_untagged]')).to be_checked
- check 'runner_access_level'
+ uncheck 'runner_run_untagged'
click_button 'Save changes'
- expect(page).to have_content 'Protected Yes'
+ expect(page).to have_content 'Can run untagged jobs No'
end
+ end
- context 'when a runner has a tag' do
- before do
- project_runner.update!(tag_list: ['tag'])
- end
-
- it 'user edits runner not to run untagged jobs' do
- visit project_runners_path(project)
-
- within '[data-testid="assigned_project_runners"]' do
- first('[data-testid="edit-runner-link"]').click
- end
-
- expect(page.find_field('runner[run_untagged]')).to be_checked
+ context 'when a shared runner is activated on the project' do
+ let!(:shared_runner) { create(:ci_runner, :instance) }
- uncheck 'runner_run_untagged'
- click_button 'Save changes'
+ it 'user sees CI/CD setting page' do
+ visit project_runners_path(project)
- expect(page).to have_content 'Can run untagged jobs No'
+ within '[data-testid="available-shared-runners"]' do
+ expect(page).to have_content(shared_runner.display_name)
end
end
- context 'when a shared runner is activated on the project' do
- let!(:shared_runner) { create(:ci_runner, :instance) }
+ context 'when multiple shared runners are configured' do
+ let_it_be(:shared_runner_2) { create(:ci_runner, :instance) }
- it 'user sees CI/CD setting page' do
+ it 'shows the runner count' do
visit project_runners_path(project)
within '[data-testid="available-shared-runners"]' do
- expect(page).to have_content(shared_runner.display_name)
+ expect(page).to have_content format(_('Available shared runners: %{count}'), { count: 2 })
end
end
- context 'when multiple shared runners are configured' do
- let_it_be(:shared_runner_2) { create(:ci_runner, :instance) }
+ it 'adds pagination to the shared runner list' do
+ stub_const('Projects::Settings::CiCdController::NUMBER_OF_RUNNERS_PER_PAGE', 1)
- it 'shows the runner count' do
- visit project_runners_path(project)
+ visit project_runners_path(project)
- within '[data-testid="available-shared-runners"]' do
- expect(page).to have_content format(_('Available shared runners: %{count}'), { count: 2 })
- end
+ within '[data-testid="available-shared-runners"]' do
+ expect(find('.pagination')).not_to be_nil
end
+ end
+ end
+ end
- it 'adds pagination to the shared runner list' do
- stub_const('Projects::Settings::CiCdController::NUMBER_OF_RUNNERS_PER_PAGE', 1)
+ context 'when multiple project runners are configured' do
+ let!(:project_runner_2) { create(:ci_runner, :project, projects: [project]) }
- visit project_runners_path(project)
+ it 'adds pagination to the runner list' do
+ stub_const('Projects::Settings::CiCdController::NUMBER_OF_RUNNERS_PER_PAGE', 1)
- within '[data-testid="available-shared-runners"]' do
- expect(find('.pagination')).not_to be_nil
- end
- end
- end
+ visit project_runners_path(project)
+
+ expect(find('.pagination')).not_to be_nil
end
+ end
+ end
- context 'when multiple project runners are configured' do
- let!(:project_runner_2) { create(:ci_runner, :project, projects: [project]) }
+ context 'when a project runner exists in another project' do
+ let(:another_project) { create(:project) }
+ let!(:project_runner) { create(:ci_runner, :project, projects: [another_project]) }
- it 'adds pagination to the runner list' do
- stub_const('Projects::Settings::CiCdController::NUMBER_OF_RUNNERS_PER_PAGE', 1)
+ before do
+ another_project.add_maintainer(user)
+ end
- visit project_runners_path(project)
+ it 'user enables and disables a project runner' do
+ visit project_runners_path(project)
- expect(find('.pagination')).not_to be_nil
- end
+ within '[data-testid="available_project_runners"]' do
+ click_on 'Enable for this project'
+ end
+
+ expect(page.find('[data-testid="assigned_project_runners"]')).to have_content(project_runner.display_name)
+
+ within '[data-testid="assigned_project_runners"]' do
+ click_on 'Disable for this project'
end
+
+ expect(page.find('[data-testid="available_project_runners"]')).to have_content(project_runner.display_name)
end
+ end
- context 'when a project runner exists in another project' do
- let(:another_project) { create(:project) }
- let!(:project_runner) { create(:ci_runner, :project, projects: [another_project]) }
+ context 'shared runner text' do
+ context 'when application settings have shared_runners_text' do
+ let(:shared_runners_text) { 'custom **shared** runners description' }
+ let(:shared_runners_html) { 'custom shared runners description' }
before do
- another_project.add_maintainer(user)
+ stub_application_setting(shared_runners_text: shared_runners_text)
end
- it 'user enables and disables a project runner' do
+ it 'user sees shared runners description' do
visit project_runners_path(project)
- within '[data-testid="available_project_runners"]' do
- click_on 'Enable for this project'
+ page.within("[data-testid='shared-runners-description']") do
+ expect(page).not_to have_content('The same shared runner executes code from multiple projects')
+ expect(page).to have_content(shared_runners_html)
end
-
- expect(page.find('[data-testid="assigned_project_runners"]')).to have_content(project_runner.display_name)
-
- within '[data-testid="assigned_project_runners"]' do
- click_on 'Disable for this project'
- end
-
- expect(page.find('[data-testid="available_project_runners"]')).to have_content(project_runner.display_name)
end
end
- context 'shared runner text' do
- context 'when application settings have shared_runners_text' do
- let(:shared_runners_text) { 'custom **shared** runners description' }
- let(:shared_runners_html) { 'custom shared runners description' }
+ context 'when application settings have an unsafe link in shared_runners_text' do
+ let(:shared_runners_text) { '<a href="javascript:alert(\'xss\')">link</a>' }
- before do
- stub_application_setting(shared_runners_text: shared_runners_text)
- end
+ before do
+ stub_application_setting(shared_runners_text: shared_runners_text)
+ end
- it 'user sees shared runners description' do
- visit project_runners_path(project)
+ it 'user sees no link' do
+ visit project_runners_path(project)
- page.within("[data-testid='shared-runners-description']") do
- expect(page).not_to have_content('The same shared runner executes code from multiple projects')
- expect(page).to have_content(shared_runners_html)
- end
+ page.within("[data-testid='shared-runners-description']") do
+ expect(page).to have_content('link')
+ expect(page).not_to have_link('link')
end
end
+ end
- context 'when application settings have an unsafe link in shared_runners_text' do
- let(:shared_runners_text) { '<a href="javascript:alert(\'xss\')">link</a>' }
+ context 'when application settings have an unsafe image in shared_runners_text' do
+ let(:shared_runners_text) { '<img src="404.png" onerror="alert(\'xss\')"/>' }
- before do
- stub_application_setting(shared_runners_text: shared_runners_text)
- end
+ before do
+ stub_application_setting(shared_runners_text: shared_runners_text)
+ end
- it 'user sees no link' do
- visit project_runners_path(project)
+ it 'user sees image safely' do
+ visit project_runners_path(project)
- page.within("[data-testid='shared-runners-description']") do
- expect(page).to have_content('link')
- expect(page).not_to have_link('link')
- end
+ page.within("[data-testid='shared-runners-description']") do
+ expect(page).to have_css('img')
+ expect(page).not_to have_css('img[onerror]')
end
end
+ end
+ end
+ end
- context 'when application settings have an unsafe image in shared_runners_text' do
- let(:shared_runners_text) { '<img src="404.png" onerror="alert(\'xss\')"/>' }
+ context 'enable shared runners in project settings', :js do
+ before do
+ project.add_maintainer(user)
- before do
- stub_application_setting(shared_runners_text: shared_runners_text)
- end
+ visit project_runners_path(project)
+ end
- it 'user sees image safely' do
- visit project_runners_path(project)
+ context 'when a project has enabled shared_runners' do
+ let(:project) { create(:project, shared_runners_enabled: true) }
- page.within("[data-testid='shared-runners-description']") do
- expect(page).to have_css('img')
- expect(page).not_to have_css('img[onerror]')
- end
- end
- end
+ it 'shared runners toggle is on' do
+ expect(page).to have_selector('[data-testid="toggle-shared-runners"]')
+ expect(page).to have_selector('[data-testid="toggle-shared-runners"] .is-checked')
end
end
- context 'enable shared runners in project settings', :js do
- before do
- project.add_maintainer(user)
+ context 'when a project has disabled shared_runners' do
+ let(:project) { create(:project, shared_runners_enabled: false) }
- visit project_runners_path(project)
+ it 'shared runners toggle is off' do
+ expect(page).not_to have_selector('[data-testid="toggle-shared-runners"] .is-checked')
end
+ end
+ end
- context 'when a project has enabled shared_runners' do
- let(:project) { create(:project, shared_runners_enabled: true) }
+ context 'group runners in project settings' do
+ before do
+ project.add_maintainer(user)
+ end
- it 'shared runners toggle is on' do
- expect(page).to have_selector('[data-testid="toggle-shared-runners"]')
- expect(page).to have_selector('[data-testid="toggle-shared-runners"] .is-checked')
- end
+ let_it_be(:group) { create :group }
+ let_it_be(:project) { create :project, group: group }
+
+ context 'as project and group maintainer' do
+ before do
+ group.add_maintainer(user)
end
- context 'when a project has disabled shared_runners' do
- let(:project) { create(:project, shared_runners_enabled: false) }
+ context 'project with a group but no group runner' do
+ it 'group runners are not available' do
+ visit project_runners_path(project)
- it 'shared runners toggle is off' do
- expect(page).not_to have_selector('[data-testid="toggle-shared-runners"] .is-checked')
+ expect(page).not_to have_content 'To register them, go to the group\'s Runners page.'
+ expect(page).to have_content 'Ask your group owner to set up a group runner'
end
end
end
- context 'group runners in project settings' do
+ context 'as project maintainer and group owner' do
before do
- project.add_maintainer(user)
+ group.add_owner(user)
end
- let_it_be(:group) { create :group }
- let_it_be(:project) { create :project, group: group }
+ context 'project with a group but no group runner' do
+ it 'group runners are available' do
+ visit project_runners_path(project)
- context 'as project and group maintainer' do
- before do
- group.add_maintainer(user)
+ expect(page).to have_content 'This group does not have any group runners yet.'
+
+ expect(page).to have_content 'To register them, go to the group\'s Runners page.'
+ expect(page).not_to have_content 'Ask your group owner to set up a group runner'
end
+ end
+ end
- context 'project with a group but no group runner' do
- it 'group runners are not available' do
- visit project_runners_path(project)
+ context 'as project maintainer' do
+ context 'project without a group' do
+ let(:project) { create :project }
- expect(page).not_to have_content 'To register them, go to the group\'s Runners page.'
- expect(page).to have_content 'Ask your group owner to set up a group runner'
- end
+ it 'group runners are not available' do
+ visit project_runners_path(project)
+
+ expect(page).to have_content 'This project does not belong to a group and cannot make use of group runners.'
end
end
- context 'as project maintainer and group owner' do
- before do
- group.add_owner(user)
- end
+ context 'with group project' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
context 'project with a group but no group runner' do
- it 'group runners are available' do
+ it 'group runners are not available' do
visit project_runners_path(project)
expect(page).to have_content 'This group does not have any group runners yet.'
- expect(page).to have_content 'To register them, go to the group\'s Runners page.'
- expect(page).not_to have_content 'Ask your group owner to set up a group runner'
+ expect(page).not_to have_content 'To register them, go to the group\'s Runners page.'
+ expect(page).to have_content 'Ask your group owner to set up a group runner.'
end
end
- end
- context 'as project maintainer' do
- context 'project without a group' do
- let(:project) { create :project }
+ context 'project with a group and a group runner' do
+ let_it_be(:group_runner) do
+ create(:ci_runner, :group, groups: [group], description: 'group-runner')
+ end
- it 'group runners are not available' do
+ it 'group runners are available' do
visit project_runners_path(project)
- expect(page).to have_content 'This project does not belong to a group and cannot make use of group runners.'
+ expect(page).to have_content 'Available group runners: 1'
+ expect(page).to have_content 'group-runner'
end
- end
- context 'with group project' do
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, group: group) }
+ it 'group runners may be disabled for a project' do
+ visit project_runners_path(project)
- context 'project with a group but no group runner' do
- it 'group runners are not available' do
- visit project_runners_path(project)
+ click_on 'Disable group runners'
- expect(page).to have_content 'This group does not have any group runners yet.'
+ expect(page).to have_content 'Enable group runners'
+ expect(project.reload.group_runners_enabled).to be false
- expect(page).not_to have_content 'To register them, go to the group\'s Runners page.'
- expect(page).to have_content 'Ask your group owner to set up a group runner.'
- end
- end
+ click_on 'Enable group runners'
- context 'project with a group and a group runner' do
- let_it_be(:group_runner) do
- create(:ci_runner, :group, groups: [group], description: 'group-runner')
- end
+ expect(page).to have_content 'Disable group runners'
+ expect(project.reload.group_runners_enabled).to be true
+ end
- it 'group runners are available' do
- visit project_runners_path(project)
+ context 'when multiple group runners are configured' do
+ let_it_be(:group_runner_2) { create(:ci_runner, :group, groups: [group]) }
- expect(page).to have_content 'Available group runners: 1'
- expect(page).to have_content 'group-runner'
- end
-
- it 'group runners may be disabled for a project' do
+ it 'shows the runner count' do
visit project_runners_path(project)
- click_on 'Disable group runners'
-
- expect(page).to have_content 'Enable group runners'
- expect(project.reload.group_runners_enabled).to be false
-
- click_on 'Enable group runners'
-
- expect(page).to have_content 'Disable group runners'
- expect(project.reload.group_runners_enabled).to be true
- end
-
- context 'when multiple group runners are configured' do
- let_it_be(:group_runner_2) { create(:ci_runner, :group, groups: [group]) }
-
- it 'shows the runner count' do
- visit project_runners_path(project)
-
- within '[data-testid="group-runners"]' do
- expect(page).to have_content format(_('Available group runners: %{runners}'), { runners: 2 })
- end
+ within '[data-testid="group-runners"]' do
+ expect(page).to have_content format(_('Available group runners: %{runners}'), { runners: 2 })
end
+ end
- it 'adds pagination to the group runner list' do
- stub_const('Projects::Settings::CiCdController::NUMBER_OF_RUNNERS_PER_PAGE', 1)
+ it 'adds pagination to the group runner list' do
+ stub_const('Projects::Settings::CiCdController::NUMBER_OF_RUNNERS_PER_PAGE', 1)
- visit project_runners_path(project)
+ visit project_runners_path(project)
- within '[data-testid="group-runners"]' do
- expect(find('.pagination')).not_to be_nil
- end
+ within '[data-testid="group-runners"]' do
+ expect(find('.pagination')).not_to be_nil
end
end
end
diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb
index 976324a5032..d2847203669 100644
--- a/spec/features/search/user_searches_for_code_spec.rb
+++ b/spec/features/search/user_searches_for_code_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'User searches for code', :js, :disable_rate_limiter, feature_cat
using RSpec::Parameterized::TableSyntax
include ListboxHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be_with_reload(:project) { create(:project, :repository, namespace: user.namespace) }
context 'when signed in' do
diff --git a/spec/features/search/user_searches_for_comments_spec.rb b/spec/features/search/user_searches_for_comments_spec.rb
index f7af1797c71..f47e692c652 100644
--- a/spec/features/search/user_searches_for_comments_spec.rb
+++ b/spec/features/search/user_searches_for_comments_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'User searches for comments', :js, :disable_rate_limiter, feature_category: :global_search do
let_it_be(:project) { create(:project, :repository) }
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
project.add_reporter(user)
diff --git a/spec/features/search/user_searches_for_commits_spec.rb b/spec/features/search/user_searches_for_commits_spec.rb
index 724daf9277d..140d8763813 100644
--- a/spec/features/search/user_searches_for_commits_spec.rb
+++ b/spec/features/search/user_searches_for_commits_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User searches for commits', :js, :clean_gitlab_redis_rate_limiting, feature_category: :global_search do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, :repository) }
let(:sha) { '6d394385cf567f80a8fd85055db1ab4c5295806f' }
diff --git a/spec/features/search/user_searches_for_issues_spec.rb b/spec/features/search/user_searches_for_issues_spec.rb
index 9451e337db1..d816b393cce 100644
--- a/spec/features/search/user_searches_for_issues_spec.rb
+++ b/spec/features/search/user_searches_for_issues_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User searches for issues', :js, :clean_gitlab_redis_rate_limiting, feature_category: :global_search do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
let!(:issue1) { create(:issue, title: 'issue Foo', project: project, created_at: 1.hour.ago) }
diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb
index d7b52d9e07a..61af5e86eea 100644
--- a/spec/features/search/user_searches_for_merge_requests_spec.rb
+++ b/spec/features/search/user_searches_for_merge_requests_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User searches for merge requests', :js, :clean_gitlab_redis_rate_limiting, feature_category: :global_search do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
let_it_be(:merge_request1) { create(:merge_request, title: 'Merge Request Foo', source_project: project, target_project: project, created_at: 1.hour.ago) }
let_it_be(:merge_request2) { create(:merge_request, :simple, title: 'Merge Request Bar', source_project: project, target_project: project) }
diff --git a/spec/features/search/user_searches_for_milestones_spec.rb b/spec/features/search/user_searches_for_milestones_spec.rb
index 7ca7958f61b..ad62c8eb3da 100644
--- a/spec/features/search/user_searches_for_milestones_spec.rb
+++ b/spec/features/search/user_searches_for_milestones_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'User searches for milestones', :js, :clean_gitlab_redis_rate_limiting,
feature_category: :global_search do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
let_it_be(:milestone1) { create(:milestone, title: 'Foo', project: project) }
let_it_be(:milestone2) { create(:milestone, title: 'Bar', project: project) }
diff --git a/spec/features/search/user_searches_for_projects_spec.rb b/spec/features/search/user_searches_for_projects_spec.rb
index 48a94161927..51e5ad85e2b 100644
--- a/spec/features/search/user_searches_for_projects_spec.rb
+++ b/spec/features/search/user_searches_for_projects_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'User searches for projects', :js, :disable_rate_limiter, feature
context 'when signed out' do
context 'when block_anonymous_global_searches is disabled' do
before do
- stub_feature_flags(block_anonymous_global_searches: false)
+ stub_feature_flags(block_anonymous_global_searches: false, super_sidebar_logged_out: false)
end
include_examples 'top right search form'
diff --git a/spec/features/search/user_searches_for_users_spec.rb b/spec/features/search/user_searches_for_users_spec.rb
index e0a07c5103d..b52f6aeba68 100644
--- a/spec/features/search/user_searches_for_users_spec.rb
+++ b/spec/features/search/user_searches_for_users_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'User searches for users', :js, :clean_gitlab_redis_rate_limiting, feature_category: :global_search do
- let_it_be(:user1) { create(:user, username: 'gob_bluth', name: 'Gob Bluth') }
- let_it_be(:user2) { create(:user, username: 'michael_bluth', name: 'Michael Bluth') }
- let_it_be(:user3) { create(:user, username: 'gob_2018', name: 'George Oscar Bluth') }
+ let_it_be(:user1) { create(:user, :no_super_sidebar, username: 'gob_bluth', name: 'Gob Bluth') }
+ let_it_be(:user2) { create(:user, :no_super_sidebar, username: 'michael_bluth', name: 'Michael Bluth') }
+ let_it_be(:user3) { create(:user, :no_super_sidebar, username: 'gob_2018', name: 'George Oscar Bluth') }
before do
sign_in(user1)
diff --git a/spec/features/search/user_searches_for_wiki_pages_spec.rb b/spec/features/search/user_searches_for_wiki_pages_spec.rb
index 65f262075f9..a5b63243d0b 100644
--- a/spec/features/search/user_searches_for_wiki_pages_spec.rb
+++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'User searches for wiki pages', :js, :clean_gitlab_redis_rate_limiting,
feature_category: :global_search do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) }
let_it_be(:wiki_page) do
create(:wiki_page, wiki: project.wiki, title: 'directory/title', content: 'Some Wiki content')
diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb
index 71d0f8d6d7f..3f2a71b63dc 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe 'User uses header search field', :js, :disable_rate_limiter, feat
include FilteredSearchHelpers
let_it_be(:project) { create(:project, :repository) }
- let_it_be(:reporter) { create(:user) }
- let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user, :no_super_sidebar) }
+ let_it_be(:developer) { create(:user, :no_super_sidebar) }
let(:user) { reporter }
diff --git a/spec/features/sentry_js_spec.rb b/spec/features/sentry_js_spec.rb
index d3880011914..0cf32864b1e 100644
--- a/spec/features/sentry_js_spec.rb
+++ b/spec/features/sentry_js_spec.rb
@@ -41,6 +41,7 @@ RSpec.describe 'Sentry', feature_category: :error_tracking do
it 'loads sentry if sentry settings are enabled', :js do
allow(Gitlab::CurrentSettings).to receive(:sentry_enabled).and_return(true)
+ allow(Gitlab::CurrentSettings).to receive(:sentry_clientside_dsn).and_return('https://mockdsn@example.com/1')
visit new_user_session_path
diff --git a/spec/features/signed_commits_spec.rb b/spec/features/signed_commits_spec.rb
index 0268c8ad0d4..08d2d0575eb 100644
--- a/spec/features/signed_commits_spec.rb
+++ b/spec/features/signed_commits_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe 'GPG signed commits', feature_category: :source_code_management do
- let(:project) { create(:project, :public, :repository) }
+RSpec.describe 'GPG signed commits', :js, feature_category: :source_code_management do
+ let_it_be(:project) { create(:project, :public, :repository) }
it 'changes from unverified to verified when the user changes their email to match the gpg key', :sidekiq_might_not_need_inline do
ref = GpgHelpers::SIGNED_AND_AUTHORED_SHA
@@ -47,7 +47,7 @@ RSpec.describe 'GPG signed commits', feature_category: :source_code_management d
expect(page).to have_selector('.gl-badge', text: 'Verified')
end
- context 'shows popover badges', :js do
+ context 'shows popover badges' do
let(:user_1) do
create :user, email: GpgHelpers::User1.emails.first, username: 'nannie.bernhard', name: 'Nannie Bernhard'
end
@@ -163,7 +163,7 @@ RSpec.describe 'GPG signed commits', feature_category: :source_code_management d
end
end
- context 'view signed commit on the tree view', :js do
+ context 'view signed commit on the tree view' do
shared_examples 'a commit with a signature' do
before do
visit project_tree_path(project, 'signed-commits')
diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb
index afb53c563de..7a07299a14f 100644
--- a/spec/features/snippets/search_snippets_spec.rb
+++ b/spec/features/snippets/search_snippets_spec.rb
@@ -4,10 +4,11 @@ require 'spec_helper'
RSpec.describe 'Search Snippets', :js, feature_category: :global_search do
it 'user searches for snippets by title' do
+ user = create(:user, :no_super_sidebar)
public_snippet = create(:personal_snippet, :public, title: 'Beginning and Middle')
- private_snippet = create(:personal_snippet, :private, title: 'Middle and End')
+ private_snippet = create(:personal_snippet, :private, title: 'Middle and End', author: user)
- sign_in private_snippet.author
+ sign_in user
visit dashboard_snippets_path
submit_search('Middle')
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
index 2673ad5e1d7..bbb120edb80 100644
--- a/spec/features/snippets/show_spec.rb
+++ b/spec/features/snippets/show_spec.rb
@@ -3,9 +3,13 @@
require 'spec_helper'
RSpec.describe 'Snippet', :js, feature_category: :source_code_management do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: user) }
+ before do
+ stub_feature_flags(super_sidebar_logged_out: false)
+ end
+
it_behaves_like 'show and render proper snippet blob' do
let(:anchor) { nil }
@@ -36,7 +40,7 @@ RSpec.describe 'Snippet', :js, feature_category: :source_code_management do
end
context 'when authenticated as a different user' do
- let_it_be(:different_user) { create(:user) }
+ let_it_be(:different_user) { create(:user, :no_super_sidebar) }
before do
sign_in(different_user)
diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb
index 090d854081a..341cc150a64 100644
--- a/spec/features/snippets/user_creates_snippet_spec.rb
+++ b/spec/features/snippets/user_creates_snippet_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'User creates snippet', :js, feature_category: :source_code_manag
include DropzoneHelper
include Features::SnippetSpecHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
let(:title) { 'My Snippet Title' }
let(:file_content) { 'Hello World!' }
@@ -130,7 +130,7 @@ RSpec.describe 'User creates snippet', :js, feature_category: :source_code_manag
expect(page).not_to have_content(files_validation_message)
end
- it 'previews a snippet with file', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/408203' do
+ it 'previews a snippet with file' do
# Click placeholder first to expand full description field
snippet_fill_in_description('My Snippet')
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
@@ -145,7 +145,11 @@ RSpec.describe 'User creates snippet', :js, feature_category: :source_code_manag
# Adds a cache buster for checking if the image exists as Selenium is now handling the cached requests
# not anymore as requests when they come straight from memory cache.
# accept_confirm is needed because of https://gitlab.com/gitlab-org/gitlab/-/issues/262102
- reqs = inspect_requests { accept_confirm { visit("#{link}?ran=#{SecureRandom.base64(20)}") } }
+ reqs = inspect_requests do
+ visit("#{link}?ran=#{SecureRandom.base64(20)}") do
+ page.driver.browser.switch_to.alert.accept
+ end
+ end
expect(reqs.first.status_code).to eq(200)
end
end
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index beadeab1736..24d63cadf00 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe 'Task Lists', :js, feature_category: :team_planning do
include Warden::Test::Helpers
let_it_be(:project) { create(:project, :public, :repository) }
- let_it_be(:user) { create(:user) }
- let_it_be(:user2) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:user2) { create(:user, :no_super_sidebar) }
let(:markdown) do
<<-MARKDOWN.strip_heredoc
diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb
index 77ef3df97f6..b78efa65888 100644
--- a/spec/features/unsubscribe_links_spec.rb
+++ b/spec/features/unsubscribe_links_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe 'Unsubscribe links', :sidekiq_inline, feature_category: :shared d
include Warden::Test::Helpers
let_it_be(:project) { create(:project, :public) }
- let_it_be(:author) { create(:user).tap { |u| project.add_reporter(u) } }
- let_it_be(:recipient) { create(:user) }
+ let_it_be(:author) { create(:user, :no_super_sidebar).tap { |u| project.add_reporter(u) } }
+ let_it_be(:recipient) { create(:user, :no_super_sidebar) }
let(:params) { { title: 'A bug!', description: 'Fix it!', assignee_ids: [recipient.id] } }
let(:issue) { Issues::CreateService.new(container: project, current_user: author, params: params).execute[:issue] }
@@ -22,6 +22,10 @@ RSpec.describe 'Unsubscribe links', :sidekiq_inline, feature_category: :shared d
end
context 'when logged out' do
+ before do
+ stub_feature_flags(super_sidebar_logged_out: false)
+ end
+
context 'when visiting the link from the body' do
it 'shows the unsubscribe confirmation page and redirects to root path when confirming' do
visit body_link
diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
index cd181f73473..5de544e866e 100644
--- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'User uploads avatar to profile', feature_category: :user_profile do
- let!(:user) { create(:user) }
+ let!(:user) { create(:user, :no_super_sidebar) }
let(:avatar_file_path) { Rails.root.join('spec', 'fixtures', 'dk.png') }
shared_examples 'upload avatar' do
diff --git a/spec/features/usage_stats_consent_spec.rb b/spec/features/usage_stats_consent_spec.rb
index c446fe1531b..92f7a944007 100644
--- a/spec/features/usage_stats_consent_spec.rb
+++ b/spec/features/usage_stats_consent_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Usage stats consent', feature_category: :service_ping do
context 'when signed in' do
- let(:user) { create(:admin, created_at: 8.days.ago) }
+ let(:user) { create(:admin, :no_super_sidebar, created_at: 8.days.ago) }
let(:message) { 'To help improve GitLab, we would like to periodically collect usage information.' }
before do
diff --git a/spec/features/users/active_sessions_spec.rb b/spec/features/users/active_sessions_spec.rb
index 53a4c8a91e9..663d2283dbd 100644
--- a/spec/features/users/active_sessions_spec.rb
+++ b/spec/features/users/active_sessions_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Active user sessions', :clean_gitlab_redis_sessions, feature_category: :system_access do
it 'successful login adds a new active user login' do
- user = create(:user)
+ user = create(:user, :no_super_sidebar)
now = Time.zone.parse('2018-03-12 09:06')
travel_to(now) do
@@ -31,7 +31,7 @@ RSpec.describe 'Active user sessions', :clean_gitlab_redis_sessions, feature_cat
end
it 'successful login cleans up obsolete entries' do
- user = create(:user)
+ user = create(:user, :no_super_sidebar)
Gitlab::Redis::Sessions.with do |redis|
redis.sadd?("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
@@ -45,7 +45,7 @@ RSpec.describe 'Active user sessions', :clean_gitlab_redis_sessions, feature_cat
end
it 'sessionless login does not clean up obsolete entries' do
- user = create(:user)
+ user = create(:user, :no_super_sidebar)
personal_access_token = create(:personal_access_token, user: user)
Gitlab::Redis::Sessions.with do |redis|
@@ -61,7 +61,7 @@ RSpec.describe 'Active user sessions', :clean_gitlab_redis_sessions, feature_cat
end
it 'logout deletes the active user login' do
- user = create(:user)
+ user = create(:user, :no_super_sidebar)
gitlab_sign_in(user)
expect(page).to have_current_path root_path, ignore_query: true
diff --git a/spec/features/users/anonymous_sessions_spec.rb b/spec/features/users/anonymous_sessions_spec.rb
index 83473964d6b..368f272ba23 100644
--- a/spec/features/users/anonymous_sessions_spec.rb
+++ b/spec/features/users/anonymous_sessions_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe 'Session TTLs', :clean_gitlab_redis_shared_state, feature_categor
end
it 'increases the TTL when the login succeeds' do
- user = create(:user)
+ user = create(:user, :no_super_sidebar)
gitlab_sign_in(user)
expect(page).to have_content(user.name)
diff --git a/spec/features/users/email_verification_on_login_spec.rb b/spec/features/users/email_verification_on_login_spec.rb
index 7675de28f86..d83040efd72 100644
--- a/spec/features/users/email_verification_on_login_spec.rb
+++ b/spec/features/users/email_verification_on_login_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting, :js, feature_category: :system_access do
include EmailHelpers
- let_it_be_with_reload(:user) { create(:user) }
- let_it_be(:another_user) { create(:user) }
+ let_it_be_with_reload(:user) { create(:user, :no_super_sidebar) }
+ let_it_be(:another_user) { create(:user, :no_super_sidebar) }
let_it_be(:new_email) { build_stubbed(:user).email }
let(:require_email_verification_enabled) { user }
@@ -220,7 +220,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting,
shared_examples 'no email verification required when 2fa enabled or ff disabled' do
context 'when 2FA is enabled' do
- let_it_be(:user) { create(:user, :two_factor) }
+ let_it_be(:user) { create(:user, :no_super_sidebar, :two_factor) }
it_behaves_like 'no email verification required', two_factor_auth: true
end
@@ -234,8 +234,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting,
describe 'when failing to login the maximum allowed number of times' do
before do
- # See comment in RequireEmailVerification::MAXIMUM_ATTEMPTS on why this is divided by 2
- (RequireEmailVerification::MAXIMUM_ATTEMPTS / 2).times do
+ RequireEmailVerification::MAXIMUM_ATTEMPTS.times do
gitlab_sign_in(user, password: 'wrong_password')
end
end
@@ -345,7 +344,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting,
before do
perform_enqueued_jobs do
- (User.maximum_attempts / 2).times do
+ User.maximum_attempts.times do
gitlab_sign_in(user, password: 'wrong_password')
end
end
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 047590fb3aa..c07e419be1f 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
expect(authentication_metrics)
.to increment(:user_authenticated_counter)
- user = create(:user)
+ user = create(:user, :no_super_sidebar)
expect(user.reset_password_token).to be_nil
@@ -43,7 +43,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
# This behavior is dependent on there only being one user
User.delete_all
- user = create(:admin, password_automatically_set: true)
+ user = create(:admin, :no_super_sidebar, password_automatically_set: true)
visit root_path
expect(page).to have_current_path edit_user_password_path, ignore_query: true
@@ -77,7 +77,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
.and increment(:user_unauthenticated_counter)
.and increment(:user_session_destroyed_counter).twice
- user = create(:user, :blocked)
+ user = create(:user, :no_super_sidebar, :blocked)
gitlab_sign_in(user)
@@ -90,14 +90,14 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
.and increment(:user_unauthenticated_counter)
.and increment(:user_session_destroyed_counter).twice
- user = create(:user, :blocked)
+ user = create(:user, :no_super_sidebar, :blocked)
expect { gitlab_sign_in(user) }.not_to change { user.reload.sign_in_count }
end
end
describe 'with an unconfirmed email address' do
- let!(:user) { create(:user, confirmed_at: nil) }
+ let!(:user) { create(:user, :no_super_sidebar, confirmed_at: nil) }
let(:grace_period) { 2.days }
let(:alert_title) { 'Please confirm your email address' }
let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
@@ -141,7 +141,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'when resending the confirmation email' do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
it 'redirects to the "almost there" page' do
visit new_user_confirmation_path
@@ -154,7 +154,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
describe 'with a disallowed password' do
- let(:user) { create(:user, :disallowed_password) }
+ let(:user) { create(:user, :no_super_sidebar, :disallowed_password) }
before do
expect(authentication_metrics)
@@ -180,7 +180,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
.to increment(:user_unauthenticated_counter)
.and increment(:user_password_invalid_counter)
- gitlab_sign_in(User.ghost)
+ gitlab_sign_in(Users::Internal.ghost)
expect(page).to have_content('Invalid login or password.')
end
@@ -190,8 +190,8 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
.to increment(:user_unauthenticated_counter)
.and increment(:user_password_invalid_counter)
- expect { gitlab_sign_in(User.ghost) }
- .not_to change { User.ghost.reload.sign_in_count }
+ expect { gitlab_sign_in(Users::Internal.ghost) }
+ .not_to change { Users::Internal.ghost.reload.sign_in_count }
end
end
@@ -286,6 +286,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
enter_code(code, only_two_factor_webauthn_enabled: only_two_factor_webauthn_enabled)
expect(page).to have_content('Invalid two-factor code.')
+ expect(user.reload.failed_attempts).to eq(1)
end
end
end
@@ -294,7 +295,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
# Freeze time to prevent failures when time between code being entered and
# validated greater than otp_allowed_drift
context 'with valid username/password', :freeze_time do
- let(:user) { create(:user, :two_factor) }
+ let(:user) { create(:user, :no_super_sidebar, :two_factor) }
before do
gitlab_sign_in(user, remember: true)
@@ -371,13 +372,13 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'when user with TOTP enabled' do
- let(:user) { create(:user, :two_factor) }
+ let(:user) { create(:user, :no_super_sidebar, :two_factor) }
include_examples 'can login with recovery codes'
end
context 'when user with only Webauthn enabled' do
- let(:user) { create(:user, :two_factor_via_webauthn, registrations_count: 1) }
+ let(:user) { create(:user, :no_super_sidebar, :two_factor_via_webauthn, registrations_count: 1) }
include_examples 'can login with recovery codes', only_two_factor_webauthn_enabled: true
end
@@ -468,6 +469,12 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
describe 'without two-factor authentication' do
+ it 'renders sign in text for providers' do
+ visit new_user_session_path
+
+ expect(page).to have_content(_('or sign in with'))
+ end
+
it 'displays the remember me checkbox' do
visit new_user_session_path
@@ -487,7 +494,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'with correct username and password' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
it 'allows basic login' do
expect(authentication_metrics)
@@ -576,8 +583,8 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
end
- context 'with invalid username and password' do
- let(:user) { create(:user) }
+ context 'with correct username and invalid password' do
+ let(:user) { create(:user, :no_super_sidebar) }
it 'blocks invalid login' do
expect(authentication_metrics)
@@ -588,12 +595,13 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
expect_single_session_with_short_ttl
expect(page).to have_content('Invalid login or password.')
+ expect(user.reload.failed_attempts).to eq(1)
end
end
end
describe 'with required two-factor authentication enabled' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
# TODO: otp_grace_period_started_at
@@ -631,7 +639,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'after the grace period' do
- let(:user) { create(:user, otp_grace_period_started_at: 9999.hours.ago) }
+ let(:user) { create(:user, :no_super_sidebar, otp_grace_period_started_at: 9999.hours.ago) }
it 'redirects to two-factor configuration page' do
expect(authentication_metrics)
@@ -720,7 +728,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'after the grace period' do
- let(:user) { create(:user, otp_grace_period_started_at: 9999.hours.ago) }
+ let(:user) { create(:user, :no_super_sidebar, otp_grace_period_started_at: 9999.hours.ago) }
it 'redirects to two-factor configuration page' do
expect(authentication_metrics)
@@ -911,7 +919,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'when terms are enforced', :js do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
enforce_terms
@@ -1082,7 +1090,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions, feature_category: :system_
end
context 'when sending confirmation email and not yet confirmed' do
- let!(:user) { create(:user, confirmed_at: nil) }
+ let!(:user) { create(:user, :no_super_sidebar, confirmed_at: nil) }
let(:grace_period) { 2.days }
let(:alert_title) { 'Please confirm your email address' }
let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
diff --git a/spec/features/users/logout_spec.rb b/spec/features/users/logout_spec.rb
index c9839247e7d..d0e5be8dca3 100644
--- a/spec/features/users/logout_spec.rb
+++ b/spec/features/users/logout_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Logout/Sign out', :js, feature_category: :system_access do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/users/overview_spec.rb b/spec/features/users/overview_spec.rb
index fdd0c38a718..d1ff60b6069 100644
--- a/spec/features/users/overview_spec.rb
+++ b/spec/features/users/overview_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Overview tab on a user profile', :js, feature_category: :user_profile do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
let(:contributed_project) { create(:project, :public, :repository) }
def push_code_contribution
diff --git a/spec/features/users/rss_spec.rb b/spec/features/users/rss_spec.rb
index 2db58ce04a1..99451ac472d 100644
--- a/spec/features/users/rss_spec.rb
+++ b/spec/features/users/rss_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe 'User RSS', feature_category: :user_profile do
- let(:user) { create(:user) }
- let(:path) { user_path(create(:user)) }
+ let(:user) { create(:user, :no_super_sidebar) }
+ let(:path) { user_path(create(:user, :no_super_sidebar)) }
describe 'with "user_profile_overflow_menu_vue" feature flag off' do
before do
@@ -22,6 +22,7 @@ RSpec.describe 'User RSS', feature_category: :user_profile do
context 'when signed out' do
before do
+ stub_feature_flags(super_sidebar_logged_out: false)
visit path
end
@@ -45,6 +46,7 @@ RSpec.describe 'User RSS', feature_category: :user_profile do
context 'when signed out' do
before do
+ stub_feature_flags(super_sidebar_logged_out: false)
visit path
end
diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb
index f8653b22377..522eb12f507 100644
--- a/spec/features/users/show_spec.rb
+++ b/spec/features/users/show_spec.rb
@@ -7,6 +7,10 @@ RSpec.describe 'User page', feature_category: :user_profile do
let_it_be(:user) { create(:user, bio: '<b>Lorem</b> <i>ipsum</i> dolor sit <a href="https://example.com">amet</a>') }
+ before do
+ stub_feature_flags(super_sidebar_logged_out: false)
+ end
+
subject(:visit_profile) { visit(user_path(user)) }
context 'with "user_profile_overflow_menu_vue" feature flag enabled', :js do
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index 450b9fa46b1..111c0cce1b1 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -234,7 +234,7 @@ RSpec.describe 'Signup', :js, feature_category: :user_profile do
confirm_email
- expect(find_field('Username or email').value).to eq(new_user.email)
+ expect(find_field('Username or primary email').value).to eq(new_user.email)
end
end
@@ -332,7 +332,6 @@ RSpec.describe 'Signup', :js, feature_category: :user_profile do
click_button 'Register'
expect(page).to have_current_path(users_sign_up_welcome_path), ignore_query: true
- visit new_project_path
select 'Software Developer', from: 'user_role'
click_button 'Get started!'
@@ -341,7 +340,7 @@ RSpec.describe 'Signup', :js, feature_category: :user_profile do
expect(created_user.software_developer_role?).to be_truthy
expect(created_user.setup_for_company).to be_nil
- expect(page).to have_current_path(new_project_path)
+ expect(page).to have_current_path(dashboard_projects_path)
end
it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
@@ -388,7 +387,7 @@ RSpec.describe 'Signup', :js, feature_category: :user_profile do
end
end
- it 'redirects to step 2 of the signup process, sets the role and redirects back' do
+ it 'allows visiting of a page after initial registration' do
visit new_user_registration_path
fill_in_signup_form
@@ -397,15 +396,6 @@ RSpec.describe 'Signup', :js, feature_category: :user_profile do
visit new_project_path
- expect(page).to have_current_path(users_sign_up_welcome_path)
-
- select 'Software Developer', from: 'user_role'
- click_button 'Get started!'
-
- created_user = User.find_by_username(new_user.username)
-
- expect(created_user.software_developer_role?).to be_truthy
- expect(created_user.setup_for_company).to be_nil
expect(page).to have_current_path(new_project_path)
end
diff --git a/spec/features/users/snippets_spec.rb b/spec/features/users/snippets_spec.rb
index 2876351be37..98ac9fa5f92 100644
--- a/spec/features/users/snippets_spec.rb
+++ b/spec/features/users/snippets_spec.rb
@@ -4,10 +4,10 @@ require 'spec_helper'
RSpec.describe 'Snippets tab on a user profile', :js, feature_category: :source_code_management do
context 'when the user has snippets' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
- stub_feature_flags(profile_tabs_vue: false)
+ stub_feature_flags(profile_tabs_vue: false, super_sidebar_logged_out: false)
end
context 'pagination' do
@@ -30,7 +30,7 @@ RSpec.describe 'Snippets tab on a user profile', :js, feature_category: :source_
let!(:other_snippet) { create(:snippet, :public) }
it 'contains only internal and public snippets of a user when a user is logged in' do
- sign_in(create(:user))
+ sign_in(create(:user, :no_super_sidebar))
visit user_path(user)
page.within('.user-profile-nav') { click_link 'Snippets' }
wait_for_requests
diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb
index cf62ccaf999..3495af3ae85 100644
--- a/spec/features/users/terms_spec.rb
+++ b/spec/features/users/terms_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe 'Users > Terms', :js, feature_category: :user_profile do
end
context 'when user is a project bot' do
- let(:project_bot) { create(:user, :project_bot) }
+ let(:project_bot) { create(:user, :no_super_sidebar, :project_bot) }
before do
enforce_terms
@@ -42,7 +42,7 @@ RSpec.describe 'Users > Terms', :js, feature_category: :user_profile do
end
context 'when user is a service account' do
- let(:service_account) { create(:user, :service_account) }
+ let(:service_account) { create(:user, :no_super_sidebar, :service_account) }
before do
enforce_terms
@@ -57,7 +57,7 @@ RSpec.describe 'Users > Terms', :js, feature_category: :user_profile do
end
context 'when signed in' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
sign_in(user)
diff --git a/spec/features/users/user_browses_projects_on_user_page_spec.rb b/spec/features/users/user_browses_projects_on_user_page_spec.rb
index 8bdc09f3f87..5e047192e7b 100644
--- a/spec/features/users/user_browses_projects_on_user_page_spec.rb
+++ b/spec/features/users/user_browses_projects_on_user_page_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Users > User browses projects on user page', :js, feature_category: :groups_and_projects do
- let!(:user) { create :user }
+ let!(:user) { create(:user, :no_super_sidebar) }
let!(:private_project) do
create :project, :private, name: 'private', namespace: user.namespace do |project|
project.add_maintainer(user)
@@ -29,7 +29,7 @@ RSpec.describe 'Users > User browses projects on user page', :js, feature_catego
end
before do
- stub_feature_flags(profile_tabs_vue: false)
+ stub_feature_flags(profile_tabs_vue: false, super_sidebar_logged_out: false)
end
it 'hides loading spinner after load', :js do
@@ -87,7 +87,7 @@ RSpec.describe 'Users > User browses projects on user page', :js, feature_catego
end
context 'when signed in as another user' do
- let(:another_user) { create :user }
+ let(:another_user) { create(:user, :no_super_sidebar) }
before do
sign_in(another_user)
diff --git a/spec/features/webauthn_spec.rb b/spec/features/webauthn_spec.rb
index 5c42facfa8b..52e2b375187 100644
--- a/spec/features/webauthn_spec.rb
+++ b/spec/features/webauthn_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
# TODO: it_behaves_like 'hardware device for 2fa', 'WebAuthn'
describe 'registration' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
gitlab_sign_in(user)
@@ -58,7 +58,8 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
gitlab_sign_out
# Second user
- user = gitlab_sign_in(:user)
+ user = create(:user, :no_super_sidebar)
+ gitlab_sign_in(user)
visit profile_account_path
enable_two_factor_authentication
webauthn_device_registration(webauthn_device: webauthn_device, name: 'My other device', password: user.password)
@@ -125,7 +126,7 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
it_behaves_like 'hardware device for 2fa', 'WebAuthn'
describe 'registration' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
gitlab_sign_in(user)
@@ -160,7 +161,8 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
gitlab_sign_out
# Second user
- user = gitlab_sign_in(:user)
+ user = create(:user, :no_super_sidebar)
+ gitlab_sign_in(user)
user.update_attribute(:otp_required_for_login, true)
visit profile_account_path
manage_two_factor_authentication
@@ -225,7 +227,7 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
describe 'authentication' do
let(:otp_required_for_login) { true }
- let(:user) { create(:user, webauthn_xid: WebAuthn.generate_user_id, otp_required_for_login: otp_required_for_login) }
+ let(:user) { create(:user, :no_super_sidebar, webauthn_xid: WebAuthn.generate_user_id, otp_required_for_login: otp_required_for_login) }
let!(:webauthn_device) do
add_webauthn_device(app_id, user)
end
@@ -254,7 +256,7 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
describe 'when a given WebAuthn device has already been registered by another user' do
describe 'but not the current user' do
- let(:other_user) { create(:user, webauthn_xid: WebAuthn.generate_user_id, otp_required_for_login: otp_required_for_login) }
+ let(:other_user) { create(:user, :no_super_sidebar, webauthn_xid: WebAuthn.generate_user_id, otp_required_for_login: otp_required_for_login) }
it 'does not allow logging in with that particular device' do
# Register other user with a different WebAuthn device
@@ -275,7 +277,8 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
it "allows logging in with that particular device" do
pending("support for passing credential options in FakeClient")
# Register current user with the same WebAuthn device
- current_user = gitlab_sign_in(:user)
+ current_user = create(:user, :no_super_sidebar)
+ gitlab_sign_in(current_user)
visit profile_account_path
manage_two_factor_authentication
register_webauthn_device(webauthn_device)
diff --git a/spec/features/whats_new_spec.rb b/spec/features/whats_new_spec.rb
index 3668d90f2e9..c8bcf5f6ef0 100644
--- a/spec/features/whats_new_spec.rb
+++ b/spec/features/whats_new_spec.rb
@@ -3,9 +3,13 @@
require "spec_helper"
RSpec.describe "renders a `whats new` dropdown item", feature_category: :onboarding do
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
context 'when not logged in' do
+ before do
+ stub_feature_flags(super_sidebar_logged_out: false)
+ end
+
it 'and on SaaS it renders', :saas do
visit user_path(user)
diff --git a/spec/finders/abuse_reports_finder_spec.rb b/spec/finders/abuse_reports_finder_spec.rb
index 0b641d0cb08..c3cf84d082f 100644
--- a/spec/finders/abuse_reports_finder_spec.rb
+++ b/spec/finders/abuse_reports_finder_spec.rb
@@ -17,17 +17,21 @@ RSpec.describe AbuseReportsFinder, feature_category: :insider_threat do
create(:abuse_report, :closed, category: 'phishing', user: user_2, reporter: reporter_2, id: 2)
end
- let(:params) { {} }
-
subject(:finder) { described_class.new(params).execute }
describe '#execute' do
- context 'when params is empty' do
+ shared_examples 'returns all abuse reports' do
it 'returns all abuse reports' do
expect(finder).to match_array([abuse_report_1, abuse_report_2])
end
end
+ context 'when params is empty' do
+ let(:params) { {} }
+
+ it_behaves_like 'returns all abuse reports'
+ end
+
shared_examples 'returns filtered reports' do |filter_field|
it "returns abuse reports filtered by #{filter_field}_id" do
expect(finder).to match_array(filtered_reports)
@@ -41,9 +45,7 @@ RSpec.describe AbuseReportsFinder, feature_category: :insider_threat do
.and_return(nil)
end
- it 'returns all abuse reports' do
- expect(finder).to match_array([abuse_report_1, abuse_report_2])
- end
+ it_behaves_like 'returns all abuse reports'
end
end
@@ -169,39 +171,5 @@ RSpec.describe AbuseReportsFinder, feature_category: :insider_threat do
end
end
end
-
- context 'when legacy view is enabled' do
- before do
- stub_feature_flags(abuse_reports_list: false)
- end
-
- context 'when params is empty' do
- it 'returns all abuse reports' do
- expect(subject).to match_array([abuse_report_1, abuse_report_2])
- end
- end
-
- context 'when params[:user_id] is present' do
- let(:params) { { user_id: user_1 } }
-
- it 'returns abuse reports for the specified user' do
- expect(subject).to match_array([abuse_report_1])
- end
- end
-
- context 'when sorting' do
- it 'returns reports sorted by id in descending order' do
- expect(subject).to match_array([abuse_report_2, abuse_report_1])
- end
- end
-
- context 'when any of the new filters are present such as params[:status]' do
- let(:params) { { status: 'open' } }
-
- it 'returns all abuse reports' do
- expect(subject).to match_array([abuse_report_1, abuse_report_2])
- end
- end
- end
end
end
diff --git a/spec/finders/ci/jobs_finder_spec.rb b/spec/finders/ci/jobs_finder_spec.rb
index 0b3777a2fe8..57046baafab 100644
--- a/spec/finders/ci/jobs_finder_spec.rb
+++ b/spec/finders/ci/jobs_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobsFinder, '#execute' do
+RSpec.describe Ci::JobsFinder, '#execute', feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }
let_it_be(:project) { create(:project, :private, public_builds: false) }
@@ -13,8 +13,8 @@ RSpec.describe Ci::JobsFinder, '#execute' do
let(:params) { {} }
- context 'no project' do
- subject { described_class.new(current_user: current_user, params: params).execute }
+ context 'when project, pipeline, and runner are blank' do
+ subject(:finder_execute) { described_class.new(current_user: current_user, params: params).execute }
context 'with admin' do
let(:current_user) { admin }
@@ -34,43 +34,139 @@ RSpec.describe Ci::JobsFinder, '#execute' do
end
end
- context 'with normal user' do
- let(:current_user) { user }
+ context 'with admin and admin mode enabled', :enable_admin_mode do
+ let(:current_user) { admin }
- it { is_expected.to be_empty }
- end
+ context 'with param `scope`' do
+ using RSpec::Parameterized::TableSyntax
- context 'without user' do
- let(:current_user) { nil }
+ where(:scope, :expected_jobs) do
+ 'pending' | lazy { [pending_job] }
+ 'running' | lazy { [running_job] }
+ 'finished' | lazy { [successful_job] }
+ %w[running success] | lazy { [running_job, successful_job] }
+ end
- it { is_expected.to be_empty }
- end
+ with_them do
+ let(:params) { { scope: scope } }
- context 'with scope', :enable_admin_mode do
- let(:current_user) { admin }
- let(:jobs) { [pending_job, running_job, successful_job] }
+ it { is_expected.to match_array(expected_jobs) }
+ end
+ end
- using RSpec::Parameterized::TableSyntax
+ context 'with param `runner_type`' do
+ let_it_be(:job_with_group_runner) { create(:ci_build, :success, runner: create(:ci_runner, :group)) }
+ let_it_be(:job_with_instance_runner) { create(:ci_build, :success, runner: create(:ci_runner, :instance)) }
+ let_it_be(:job_with_project_runner) { create(:ci_build, :success, runner: create(:ci_runner, :project)) }
+
+ context 'with feature flag :admin_jobs_filter_runner_type enabled' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:runner_type, :expected_jobs) do
+ 'group_type' | lazy { [job_with_group_runner] }
+ 'instance_type' | lazy { [job_with_instance_runner] }
+ 'project_type' | lazy { [job_with_project_runner] }
+ %w[instance_type project_type] | lazy { [job_with_instance_runner, job_with_project_runner] }
+ end
+
+ with_them do
+ let(:params) { { runner_type: runner_type } }
+ it { is_expected.to match_array(expected_jobs) }
+ end
+ end
- where(:scope, :expected_jobs) do
- 'pending' | lazy { [pending_job] }
- 'running' | lazy { [running_job] }
- 'finished' | lazy { [successful_job] }
- %w[running success] | lazy { [running_job, successful_job] }
+ context 'with feature flag :admin_jobs_filter_runner_type disabled' do
+ let(:params) { { runner_type: 'instance_type' } }
+ let(:expected_jobs) do
+ [
+ job_with_group_runner,
+ job_with_instance_runner,
+ job_with_project_runner,
+ pending_job,
+ running_job,
+ successful_job
+ ]
+ end
+
+ before do
+ stub_feature_flags(admin_jobs_filter_runner_type: false)
+ end
+
+ it { is_expected.to match_array(expected_jobs) }
+ end
end
- with_them do
- let(:params) { { scope: scope } }
+ context "with params" do
+ let_it_be(:job_with_running_status_and_group_runner) do
+ create(:ci_build, :running, runner: create(:ci_runner, :group))
+ end
+
+ let_it_be(:job_with_instance_runner) { create(:ci_build, :success, runner: create(:ci_runner, :instance)) }
+ let_it_be(:job_with_project_runner) { create(:ci_build, :success, runner: create(:ci_runner, :project)) }
+
+ context 'with feature flag :admin_jobs_filter_runner_type enabled' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:param_runner_type, :param_scope, :expected_jobs) do
+ 'group_type' | 'running' | lazy { [job_with_running_status_and_group_runner] }
+ %w[instance_type project_type] | 'finished' | lazy { [job_with_instance_runner, job_with_project_runner] }
+ %w[instance_type project_type] | 'pending' | lazy { [] }
+ end
+
+ with_them do
+ let(:params) { { runner_type: param_runner_type, scope: param_scope } }
+
+ it { is_expected.to match_array(expected_jobs) }
+ end
+ end
- it { is_expected.to match_array(expected_jobs) }
+ context 'with feature flag :admin_jobs_filter_runner_type disabled' do
+ before do
+ stub_feature_flags(admin_jobs_filter_runner_type: false)
+ end
+
+ using RSpec::Parameterized::TableSyntax
+
+ where(:param_runner_type, :param_scope, :expected_jobs) do
+ 'group_type' | 'running' | lazy do
+ [job_with_running_status_and_group_runner, running_job]
+ end
+ %w[instance_type project_type] | 'finished' | lazy do
+ [
+ job_with_instance_runner,
+ job_with_project_runner,
+ successful_job
+ ]
+ end
+ %w[instance_type project_type] | 'pending' | lazy { [pending_job] }
+ end
+
+ with_them do
+ let(:params) { { runner_type: param_runner_type, scope: param_scope } }
+
+ it { is_expected.to match_array(expected_jobs) }
+ end
+ end
end
end
+
+ context 'with user not being project member' do
+ let(:current_user) { user }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'without user' do
+ let(:current_user) { nil }
+
+ it { is_expected.to be_empty }
+ end
end
- context 'a project is present' do
+ context 'when project is present' do
subject { described_class.new(current_user: user, project: project, params: params).execute }
- context 'user has access to the project' do
+ context 'with user being project maintainer' do
before do
project.add_maintainer(user)
end
@@ -78,9 +174,47 @@ RSpec.describe Ci::JobsFinder, '#execute' do
it 'returns jobs for the specified project' do
expect(subject).to match_array([successful_job])
end
+
+ context 'when artifacts are present for some jobs' do
+ let_it_be(:job_with_artifacts) { create(:ci_build, :success, pipeline: pipeline, name: 'test') }
+ let_it_be(:artifact) { create(:ci_job_artifact, job: job_with_artifacts) }
+
+ context 'when with_artifacts is true' do
+ let(:params) { { with_artifacts: true } }
+
+ it 'returns only jobs with artifacts' do
+ expect(subject).to match_array([job_with_artifacts])
+ end
+ end
+
+ context 'when with_artifacts is false' do
+ let(:params) { { with_artifacts: false } }
+
+ it 'returns all jobs' do
+ expect(subject).to match_array([successful_job, job_with_artifacts])
+ end
+ end
+
+ context "with param `scope" do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:param_scope, :expected_jobs) do
+ 'success' | lazy { [successful_job, job_with_artifacts] }
+ '[success pending]' | lazy { [successful_job, job_with_artifacts] }
+ 'pending' | lazy { [] }
+ nil | lazy { [successful_job, job_with_artifacts] }
+ end
+
+ with_them do
+ let(:params) { { with_artifacts: false, scope: param_scope } }
+
+ it { is_expected.to match_array(expected_jobs) }
+ end
+ end
+ end
end
- context 'user has no access to project builds' do
+ context 'with user being project guest' do
before do
project.add_guest(user)
end
@@ -99,79 +233,80 @@ RSpec.describe Ci::JobsFinder, '#execute' do
end
end
- context 'when artifacts are present for some jobs' do
- let_it_be(:job_with_artifacts) { create(:ci_build, :success, pipeline: pipeline, name: 'test') }
- let_it_be(:artifact) { create(:ci_job_artifact, job: job_with_artifacts) }
-
- subject { described_class.new(current_user: user, project: project, params: params).execute }
-
- before do
- project.add_maintainer(user)
- end
-
- context 'when with_artifacts is true' do
- let(:params) { { with_artifacts: true } }
+ context 'when pipeline is present' do
+ subject { described_class.new(current_user: user, pipeline: pipeline, params: params).execute }
- it 'returns only jobs with artifacts' do
- expect(subject).to match_array([job_with_artifacts])
+ context 'with user being project maintainer' do
+ before_all do
+ project.add_maintainer(user)
+ successful_job.update!(retried: true)
end
- end
- context 'when with_artifacts is false' do
- let(:params) { { with_artifacts: false } }
+ let_it_be(:job_4) { create(:ci_build, :success, pipeline: pipeline, name: 'build') }
- it 'returns all jobs' do
- expect(subject).to match_array([successful_job, job_with_artifacts])
+ it 'does not return retried jobs by default' do
+ expect(subject).to match_array([job_4])
end
- end
- end
-
- context 'when pipeline is present' do
- before_all do
- project.add_maintainer(user)
- successful_job.update!(retried: true)
- end
-
- let_it_be(:job_4) { create(:ci_build, :success, pipeline: pipeline, name: 'build') }
- subject { described_class.new(current_user: user, pipeline: pipeline, params: params).execute }
+ context 'when include_retried is false' do
+ let(:params) { { include_retried: false } }
- it 'does not return retried jobs by default' do
- expect(subject).to match_array([job_4])
- end
+ it 'does not return retried jobs' do
+ expect(subject).to match_array([job_4])
+ end
+ end
- context 'when include_retried is false' do
- let(:params) { { include_retried: false } }
+ context 'when include_retried is true' do
+ let(:params) { { include_retried: true } }
- it 'does not return retried jobs' do
- expect(subject).to match_array([job_4])
+ it 'returns retried jobs' do
+ expect(subject).to match_array([successful_job, job_4])
+ end
end
end
- context 'when include_retried is true' do
- let(:params) { { include_retried: true } }
+ context 'without user' do
+ let(:user) { nil }
- it 'returns retried jobs' do
- expect(subject).to match_array([successful_job, job_4])
+ it 'returns no jobs' do
+ expect(subject).to be_empty
end
end
end
- context 'a runner is present' do
+ context 'when runner is present' do
let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
let_it_be(:job_4) { create(:ci_build, :success, runner: runner) }
- subject { described_class.new(current_user: user, runner: runner, params: params).execute }
+ subject(:execute) { described_class.new(current_user: user, runner: runner, params: params).execute }
- context 'user has access to the runner', :enable_admin_mode do
+ context 'when current user is an admin' do
let(:user) { admin }
- it 'returns jobs for the specified project' do
- expect(subject).to match_array([job_4])
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it 'returns jobs for the specified project' do
+ expect(subject).to contain_exactly job_4
+ end
+
+ context 'with params' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:param_runner_type, :param_scope, :expected_jobs) do
+ 'project_type' | 'success' | lazy { [job_4] }
+ 'instance_type' | nil | lazy { [] }
+ nil | 'pending' | lazy { [] }
+ end
+
+ with_them do
+ let(:params) { { runner_type: param_runner_type, scope: param_scope } }
+
+ it { is_expected.to match_array(expected_jobs) }
+ end
+ end
end
end
- context 'user has no access to project builds' do
+ context 'with user being project guest' do
let_it_be(:guest) { create(:user) }
let(:user) { guest }
diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb
index e57ad5bc76d..5d249ddb391 100644
--- a/spec/finders/ci/runners_finder_spec.rb
+++ b/spec/finders/ci/runners_finder_spec.rb
@@ -222,12 +222,14 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
end
shared_examples 'executes as normal user' do
- it 'returns no runners' do
+ it 'raises Gitlab::Access::AccessDeniedError' do
user = create :user
create :ci_runner, active: true
create :ci_runner, active: false
- expect(described_class.new(current_user: user, params: {}).execute).to be_empty
+ expect do
+ described_class.new(current_user: user, params: {}).execute
+ end.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
@@ -250,12 +252,14 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
end
context 'when user is nil' do
- it 'returns no runners' do
+ it 'raises Gitlab::Access::AccessDeniedError' do
user = nil
create :ci_runner, active: true
create :ci_runner, active: false
- expect(described_class.new(current_user: user, params: {}).execute).to be_empty
+ expect do
+ described_class.new(current_user: user, params: {}).execute
+ end.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end
@@ -306,154 +310,162 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
shared_examples 'membership equal to :descendants' do
it 'returns all descendant runners' do
- expect(subject).to eq([runner_project_7, runner_project_6, runner_project_5,
- runner_project_4, runner_project_3, runner_project_2,
- runner_project_1, runner_sub_group_4, runner_sub_group_3,
- runner_sub_group_2, runner_sub_group_1, runner_group])
+ is_expected.to contain_exactly(
+ runner_project_7, runner_project_6, runner_project_5,
+ runner_project_4, runner_project_3, runner_project_2,
+ runner_project_1, runner_sub_group_4, runner_sub_group_3,
+ runner_sub_group_2, runner_sub_group_1, runner_group)
end
end
- context 'with user as group owner' do
- before do
- group.add_owner(user)
+ context 'with user is group maintainer or owner' do
+ where(:user_role) do
+ [GroupMember::OWNER, GroupMember::MAINTAINER]
end
- context 'with :group as target group' do
- let(:target_group) { group }
-
- context 'passing no membership params' do
- it_behaves_like 'membership equal to :descendants'
+ with_them do
+ before do
+ group.add_member(user, user_role)
end
- context 'with :descendants membership' do
- let(:membership) { :descendants }
+ context 'with :group as target group' do
+ let(:target_group) { group }
- it_behaves_like 'membership equal to :descendants'
- end
+ context 'passing no membership params' do
+ it_behaves_like 'membership equal to :descendants'
+ end
- context 'with :direct membership' do
- let(:membership) { :direct }
+ context 'with :descendants membership' do
+ let(:membership) { :descendants }
- it 'returns runners belonging to group' do
- expect(subject).to eq([runner_group])
+ it_behaves_like 'membership equal to :descendants'
end
- end
- context 'with :all_available membership' do
- let(:membership) { :all_available }
+ context 'with :direct membership' do
+ let(:membership) { :direct }
- it 'returns runners available to group' do
- expect(subject).to match_array([runner_project_7, runner_project_6, runner_project_5,
- runner_project_4, runner_project_3, runner_project_2,
- runner_project_1, runner_sub_group_4, runner_sub_group_3,
- runner_sub_group_2, runner_sub_group_1, runner_group, runner_instance])
+ it 'returns runners belonging to group' do
+ is_expected.to contain_exactly(runner_group)
+ end
end
- end
- context 'with unknown membership' do
- let(:membership) { :unsupported }
+ context 'with :all_available membership' do
+ let(:membership) { :all_available }
- it 'raises an error' do
- expect { subject }.to raise_error(ArgumentError, 'Invalid membership filter')
+ it 'returns runners available to group' do
+ is_expected.to contain_exactly(
+ runner_project_7, runner_project_6, runner_project_5,
+ runner_project_4, runner_project_3, runner_project_2,
+ runner_project_1, runner_sub_group_4, runner_sub_group_3,
+ runner_sub_group_2, runner_sub_group_1, runner_group, runner_instance)
+ end
end
- end
- context 'with nil group' do
- let(:target_group) { nil }
+ context 'with unknown membership' do
+ let(:membership) { :unsupported }
- it 'returns no runners' do
- # Query should run against all runners, however since user is not admin, query returns no results
- expect(subject).to eq([])
+ it 'raises an error' do
+ expect { subject }.to raise_error(ArgumentError, 'Invalid membership filter')
+ end
end
- end
- context 'with sort param' do
- let(:extra_params) { { sort: 'contacted_asc' } }
+ context 'with nil group' do
+ let(:target_group) { nil }
- it 'sorts by specified attribute' do
- expect(subject).to eq([runner_group, runner_sub_group_1, runner_sub_group_2,
- runner_sub_group_3, runner_sub_group_4, runner_project_1,
- runner_project_2, runner_project_3, runner_project_4,
- runner_project_5, runner_project_6, runner_project_7])
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ # Query should run against all runners, however since user is not admin, we raise an error
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
+ end
end
- end
- context 'filtering' do
- context 'by search term' do
- let(:extra_params) { { search: 'runner_project_search' } }
+ context 'with sort param' do
+ let(:extra_params) { { sort: 'contacted_asc' } }
- it 'returns correct runner' do
- expect(subject).to match_array([runner_project_3])
+ it 'sorts by specified attribute' do
+ expect(subject).to eq([runner_group, runner_sub_group_1, runner_sub_group_2,
+ runner_sub_group_3, runner_sub_group_4, runner_project_1,
+ runner_project_2, runner_project_3, runner_project_4,
+ runner_project_5, runner_project_6, runner_project_7])
end
end
- context 'by active status' do
- let(:extra_params) { { active: false } }
+ context 'filtering' do
+ context 'by search term' do
+ let(:extra_params) { { search: 'runner_project_search' } }
- it 'returns correct runner' do
- expect(subject).to match_array([runner_sub_group_1])
+ it 'returns correct runner' do
+ expect(subject).to match_array([runner_project_3])
+ end
end
- end
- context 'by status' do
- let(:extra_params) { { status_status: 'paused' } }
+ context 'by active status' do
+ let(:extra_params) { { active: false } }
- it 'returns correct runner' do
- expect(subject).to match_array([runner_sub_group_1])
+ it 'returns correct runner' do
+ expect(subject).to match_array([runner_sub_group_1])
+ end
end
- end
- context 'by tag_name' do
- let(:extra_params) { { tag_name: %w[runner_tag] } }
+ context 'by status' do
+ let(:extra_params) { { status_status: 'paused' } }
- it 'returns correct runner' do
- expect(subject).to match_array([runner_project_5])
+ it 'returns correct runner' do
+ expect(subject).to match_array([runner_sub_group_1])
+ end
end
- end
- context 'by runner type' do
- let(:extra_params) { { type_type: 'project_type' } }
+ context 'by tag_name' do
+ let(:extra_params) { { tag_name: %w[runner_tag] } }
- it 'returns correct runners' do
- expect(subject).to eq([runner_project_7, runner_project_6,
- runner_project_5, runner_project_4,
- runner_project_3, runner_project_2, runner_project_1])
+ it 'returns correct runner' do
+ expect(subject).to match_array([runner_project_5])
+ end
+ end
+
+ context 'by runner type' do
+ let(:extra_params) { { type_type: 'project_type' } }
+
+ it 'returns correct runners' do
+ expect(subject).to eq([runner_project_7, runner_project_6,
+ runner_project_5, runner_project_4,
+ runner_project_3, runner_project_2, runner_project_1])
+ end
end
end
end
end
end
- context 'when user is not group owner' do
- where(:user_permission) do
- [:maintainer, :developer, :reporter, :guest]
+ context 'when user is group developer or below' do
+ where(:user_role) do
+ [GroupMember::DEVELOPER, GroupMember::REPORTER, GroupMember::GUEST]
end
with_them do
before do
- create(:group_member, user_permission, group: sub_group_1, user: user)
+ group.add_member(user, user_role)
end
context 'with :sub_group_1 as target group' do
let(:target_group) { sub_group_1 }
- it 'returns no runners' do
- is_expected.to be_empty
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'with :group as target group' do
let(:target_group) { group }
- it 'returns no runners' do
- is_expected.to be_empty
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
context 'with :all_available membership' do
let(:membership) { :all_available }
- it 'returns no runners' do
- expect(subject).to be_empty
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end
@@ -461,35 +473,31 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
end
context 'when user has no access' do
- it 'returns no runners' do
- expect(subject).to be_empty
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'when user is nil' do
- let_it_be(:user) { nil }
+ let(:user) { nil }
- it 'returns no runners' do
- expect(subject).to be_empty
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end
describe '#sort_key' do
- subject { described_class.new(current_user: user, params: params.merge(group: group)).sort_key }
+ subject(:sort_key) { described_class.new(current_user: user, params: params.merge(group: group)).sort_key }
context 'without params' do
- it 'returns created_at_desc' do
- expect(subject).to eq('created_at_desc')
- end
+ it { is_expected.to eq('created_at_desc') }
end
context 'with params' do
let(:extra_params) { { sort: 'contacted_asc' } }
- it 'returns contacted_asc' do
- expect(subject).to eq('contacted_asc')
- end
+ it { is_expected.to eq('contacted_asc') }
end
end
end
@@ -504,7 +512,7 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
let(:params) { { project: project }.merge(extra_params).reject { |_, v| v.nil? } }
describe '#execute' do
- subject { described_class.new(current_user: user, params: params).execute }
+ subject(:execute) { described_class.new(current_user: user, params: params).execute }
context 'with user as project admin' do
before do
@@ -515,7 +523,7 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
let_it_be(:runner_project) { create(:ci_runner, :project, contacted_at: 7.minutes.ago, projects: [project]) }
it 'returns runners available to project' do
- expect(subject).to match_array([runner_project])
+ is_expected.to match_array([runner_project])
end
end
@@ -524,7 +532,7 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
let_it_be(:runner_group) { create(:ci_runner, :group, contacted_at: 12.minutes.ago, groups: [group]) }
it 'returns runners available to project' do
- expect(subject).to match_array([runner_instance, runner_group])
+ is_expected.to match_array([runner_instance, runner_group])
end
end
@@ -610,24 +618,24 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
project.add_developer(user)
end
- it 'returns no runners' do
- expect(subject).to be_empty
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'when user is nil' do
let_it_be(:user) { nil }
- it 'returns no runners' do
- expect(subject).to be_empty
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'with nil project_full_path' do
let(:project_full_path) { nil }
- it 'returns no runners' do
- expect(subject).to be_empty
+ it 'raises Gitlab::Access::AccessDeniedError' do
+ expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end
diff --git a/spec/finders/ci/triggers_finder_spec.rb b/spec/finders/ci/triggers_finder_spec.rb
new file mode 100644
index 00000000000..2df79e8f023
--- /dev/null
+++ b/spec/finders/ci/triggers_finder_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::TriggersFinder, feature_category: :continuous_integration do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:trigger) { create(:ci_trigger, project: project) }
+
+ subject { described_class.new(current_user, project).execute }
+
+ describe "#execute" do
+ context 'when the current user is authorized' do
+ before_all do
+ project.add_owner(current_user)
+ end
+
+ it 'returns list of trigger tokens' do
+ expect(subject).to contain_exactly(trigger)
+ end
+ end
+
+ context 'when the current user is not authorized' do
+ it 'does not return trigger tokens' do
+ expect(subject).to be_blank
+ end
+ end
+ end
+end
diff --git a/spec/finders/deployments_finder_spec.rb b/spec/finders/deployments_finder_spec.rb
index 5a803ee2a0d..807a7ca8e26 100644
--- a/spec/finders/deployments_finder_spec.rb
+++ b/spec/finders/deployments_finder_spec.rb
@@ -280,6 +280,22 @@ RSpec.describe DeploymentsFinder, feature_category: :deployment_management do
it { is_expected.to match_array([deployment_2]) }
end
end
+
+ context 'with mixed deployable types' do
+ let!(:deployment_1) do
+ create(:deployment, :success, project: project, deployable: create(:ci_build))
+ end
+
+ let!(:deployment_2) do
+ create(:deployment, :success, project: project, deployable: create(:ci_bridge))
+ end
+
+ let(:params) { { **base_params, status: 'success' } }
+
+ it 'successfuly fetches deployments' do
+ is_expected.to contain_exactly(deployment_1, deployment_2)
+ end
+ end
end
context 'at group scope' do
diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb
index 18473a5e70b..b8a5be44241 100644
--- a/spec/finders/group_members_finder_spec.rb
+++ b/spec/finders/group_members_finder_spec.rb
@@ -288,4 +288,39 @@ RSpec.describe GroupMembersFinder, '#execute', feature_category: :groups_and_pro
end
end
end
+
+ context 'filter by non-invite' do
+ let_it_be(:member) { group.add_maintainer(user1) }
+ let_it_be(:invited_member) do
+ create(:group_member, :invited, { user: user2, group: group })
+ end
+
+ context 'params is not passed in' do
+ subject { described_class.new(group, user1).execute }
+
+ it 'does not filter members by invite' do
+ expect(subject).to match_array([member, invited_member])
+ end
+ end
+
+ context 'params is passed in' do
+ subject { described_class.new(group, user1, params: { non_invite: non_invite_param }).execute }
+
+ context 'filtering is set to false' do
+ let(:non_invite_param) { false }
+
+ it 'does not filter members by invite' do
+ expect(subject).to match_array([member, invited_member])
+ end
+ end
+
+ context 'filtering is set to true' do
+ let(:non_invite_param) { true }
+
+ it 'filters members by invite' do
+ expect(subject).to match_array([member])
+ end
+ end
+ end
+ end
end
diff --git a/spec/finders/groups/accepting_group_transfers_finder_spec.rb b/spec/finders/groups/accepting_group_transfers_finder_spec.rb
index 18407dd0196..5c78ec3124b 100644
--- a/spec/finders/groups/accepting_group_transfers_finder_spec.rb
+++ b/spec/finders/groups/accepting_group_transfers_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Groups::AcceptingGroupTransfersFinder do
+RSpec.describe Groups::AcceptingGroupTransfersFinder, feature_category: :groups_and_projects do
let_it_be(:current_user) { create(:user) }
let_it_be(:great_grandparent_group) do
@@ -119,6 +119,25 @@ RSpec.describe Groups::AcceptingGroupTransfersFinder do
expect(result).to contain_exactly(great_grandparent_group)
end
end
+
+ context 'on searching with multiple matches' do
+ let(:params) { { search: 'great-grandparent-group' } }
+ let(:other_groups) { [] }
+
+ before do
+ 2.times do
+ # app/finders/group/base.rb adds an ORDER BY path, so create a group with 1 in the front.
+ group = create(:group, parent: great_grandparent_group, path: "1-#{SecureRandom.hex}")
+ group.add_owner(current_user)
+ other_groups << group
+ end
+ end
+
+ it 'prioritizes exact matches first' do
+ expect(result.first).to eq(great_grandparent_group)
+ expect(result[1..]).to match_array(other_groups)
+ end
+ end
end
end
end
diff --git a/spec/finders/organizations/groups_finder_spec.rb b/spec/finders/organizations/groups_finder_spec.rb
new file mode 100644
index 00000000000..08c5604149b
--- /dev/null
+++ b/spec/finders/organizations/groups_finder_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Organizations::GroupsFinder, feature_category: :cell do
+ let_it_be(:organization_user) { create(:organization_user) }
+ let_it_be(:organization) { organization_user.organization }
+ let_it_be(:user) { organization_user.user }
+ let_it_be(:public_group) { create(:group, name: 'public-group', organization: organization) }
+ let_it_be(:other_group) { create(:group, name: 'other-group', organization: organization) }
+ let_it_be(:outside_organization_group) { create(:group) }
+ let_it_be(:private_group) do
+ create(:group, :private, name: 'private-group', organization: organization)
+ end
+
+ let_it_be(:no_access_group_in_org) do
+ create(:group, :private, name: 'no-access', organization: organization)
+ end
+
+ let(:current_user) { user }
+ let(:params) { {} }
+ let(:finder) { described_class.new(organization: organization, current_user: current_user, params: params) }
+
+ before_all do
+ private_group.add_developer(user)
+ public_group.add_developer(user)
+ other_group.add_developer(user)
+ outside_organization_group.add_developer(user)
+ end
+
+ subject(:result) { finder.execute.to_a }
+
+ describe '#execute' do
+ context 'when user is not authorized to read the organization' do
+ let(:current_user) { create(:user) }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when organization is nil' do
+ let(:organization) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when user is authorized to read the organization' do
+ it 'return all accessible groups' do
+ expect(result).to contain_exactly(public_group, private_group, other_group)
+ end
+
+ context 'when search param is passed' do
+ let(:params) { { search: 'the' } }
+
+ it 'filters the groups by search' do
+ expect(result).to contain_exactly(other_group)
+ end
+ end
+
+ context 'when sort param is not passed' do
+ it 'return groups sorted by name in ascending order by default' do
+ expect(result).to eq([other_group, private_group, public_group])
+ end
+ end
+
+ context 'when sort param is passed' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:field, :direction, :sorted_groups) do
+ 'name' | 'asc' | lazy { [other_group, private_group, public_group] }
+ 'name' | 'desc' | lazy { [public_group, private_group, other_group] }
+ 'path' | 'asc' | lazy { [other_group, private_group, public_group] }
+ 'path' | 'desc' | lazy { [public_group, private_group, other_group] }
+ end
+
+ with_them do
+ let(:params) { { sort: { field: field, direction: direction } } }
+ it 'sorts the groups' do
+ expect(result).to eq(sorted_groups)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/finders/organizations/organization_users_finder_spec.rb b/spec/finders/organizations/organization_users_finder_spec.rb
new file mode 100644
index 00000000000..d7fba372e40
--- /dev/null
+++ b/spec/finders/organizations/organization_users_finder_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Organizations::OrganizationUsersFinder, feature_category: :cell do
+ let_it_be(:organization) { create(:organization) }
+ let_it_be(:organization_user_1) { create(:organization_user, organization: organization) }
+ let_it_be(:organization_user_2) { create(:organization_user, organization: organization) }
+ let_it_be(:other_organization_user) { create(:organization_user) }
+
+ let(:current_user) { organization_user_1.user }
+ let(:finder) { described_class.new(organization: organization, current_user: current_user) }
+
+ subject(:result) { finder.execute.to_a }
+
+ describe '#execute' do
+ context 'when user is not authorized to read the organization' do
+ let(:current_user) { create(:user) }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when organization is nil' do
+ let(:organization) { nil }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when user is authorized to read the organization' do
+ it 'returns all organization users' do
+ expect(result).to contain_exactly(organization_user_1, organization_user_2)
+ end
+ end
+ end
+end
diff --git a/spec/finders/packages/npm/packages_for_user_finder_spec.rb b/spec/finders/packages/npm/packages_for_user_finder_spec.rb
new file mode 100644
index 00000000000..e2dc21e1008
--- /dev/null
+++ b/spec/finders/packages/npm/packages_for_user_finder_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Packages::Npm::PackagesForUserFinder, feature_category: :package_registry do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:project2) { create(:project, group: group) }
+ let_it_be(:package) { create(:npm_package, project: project) }
+ let_it_be(:package_name) { package.name }
+ let_it_be(:package_with_diff_name) { create(:npm_package, project: project) }
+ let_it_be(:package_with_diff_project) { create(:npm_package, name: package_name, project: project2) }
+ let_it_be(:maven_package) { create(:maven_package, name: package_name, project: project) }
+
+ let(:finder) { described_class.new(user, project_or_group, package_name: package_name) }
+
+ describe '#execute' do
+ subject { finder.execute }
+
+ shared_examples 'searches for packages' do
+ it { is_expected.to contain_exactly(package) }
+ end
+
+ context 'with a project' do
+ let(:project_or_group) { project }
+
+ it_behaves_like 'searches for packages'
+ end
+
+ context 'with a group' do
+ let(:project_or_group) { group }
+
+ before_all do
+ project.add_reporter(user)
+ end
+
+ it_behaves_like 'searches for packages'
+ end
+ end
+end
diff --git a/spec/finders/packages/nuget/package_finder_spec.rb b/spec/finders/packages/nuget/package_finder_spec.rb
index 792e543e424..8230d132d75 100644
--- a/spec/finders/packages/nuget/package_finder_spec.rb
+++ b/spec/finders/packages/nuget/package_finder_spec.rb
@@ -114,16 +114,6 @@ RSpec.describe Packages::Nuget::PackageFinder, feature_category: :package_regist
it_behaves_like 'calling with_nuget_version_or_normalized_version scope', with_normalized: true
end
-
- context 'when nuget_normalized_version feature flag is disabled' do
- let(:package_version) { '2.0.0+abc' }
-
- before do
- stub_feature_flags(nuget_normalized_version: false)
- end
-
- it_behaves_like 'calling with_nuget_version_or_normalized_version scope', with_normalized: false
- end
end
context 'with a project' do
diff --git a/spec/fixtures/api/schemas/entities/codequality_degradation.json b/spec/fixtures/api/schemas/entities/codequality_degradation.json
index ac772873daf..ac1a556e33c 100644
--- a/spec/fixtures/api/schemas/entities/codequality_degradation.json
+++ b/spec/fixtures/api/schemas/entities/codequality_degradation.json
@@ -10,6 +10,9 @@
"description": {
"type": "string"
},
+ "fingerprint": {
+ "type": "string"
+ },
"severity": {
"type": "string"
},
diff --git a/spec/fixtures/api/schemas/job/job.json b/spec/fixtures/api/schemas/job/job.json
index f3d5e9b038a..34668f309a6 100644
--- a/spec/fixtures/api/schemas/job/job.json
+++ b/spec/fixtures/api/schemas/job/job.json
@@ -5,7 +5,6 @@
"id",
"name",
"started",
- "build_path",
"playable",
"created_at",
"updated_at",
diff --git a/spec/fixtures/api/schemas/ml/search_runs.json b/spec/fixtures/api/schemas/ml/search_runs.json
new file mode 100644
index 00000000000..c1db2c9f15c
--- /dev/null
+++ b/spec/fixtures/api/schemas/ml/search_runs.json
@@ -0,0 +1,82 @@
+{
+ "type": "object",
+ "required": [
+ "runs",
+ "next_page_token"
+ ],
+ "properties": {
+ "runs": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "info",
+ "data"
+ ],
+ "properties": {
+ "info": {
+ "type": "object",
+ "required": [
+ "run_id",
+ "run_uuid",
+ "user_id",
+ "experiment_id",
+ "status",
+ "start_time",
+ "artifact_uri",
+ "lifecycle_stage"
+ ],
+ "optional": [
+ "end_time"
+ ],
+ "properties": {
+ "run_id": {
+ "type": "string"
+ },
+ "run_uuid": {
+ "type": "string"
+ },
+ "experiment_id": {
+ "type": "string"
+ },
+ "artifact_uri": {
+ "type": "string"
+ },
+ "start_time": {
+ "type": "integer"
+ },
+ "end_time": {
+ "type": "integer"
+ },
+ "user_id": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "RUNNING",
+ "SCHEDULED",
+ "FINISHED",
+ "FAILED",
+ "KILLED"
+ ]
+ },
+ "lifecycle_stage": {
+ "type": "string",
+ "enum": [
+ "active"
+ ]
+ }
+ }
+ },
+ "data": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "next_page_token": {
+ "type": "string"
+ }
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/integration.json b/spec/fixtures/api/schemas/public_api/v4/integration.json
index 8902196a2c4..2b16e44eb85 100644
--- a/spec/fixtures/api/schemas/public_api/v4/integration.json
+++ b/spec/fixtures/api/schemas/public_api/v4/integration.json
@@ -65,6 +65,9 @@
},
"comment_on_event_enabled": {
"type": "boolean"
+ },
+ "vulnerability_events": {
+ "type": "boolean"
}
},
"additionalProperties": false
diff --git a/spec/fixtures/api/schemas/public_api/v4/operations/strategy.json b/spec/fixtures/api/schemas/public_api/v4/operations/strategy.json
index f572b1a4f9b..a72260af145 100644
--- a/spec/fixtures/api/schemas/public_api/v4/operations/strategy.json
+++ b/spec/fixtures/api/schemas/public_api/v4/operations/strategy.json
@@ -8,7 +8,8 @@
"id": { "type": "integer" },
"name": { "type": "string" },
"parameters": { "type": "object" },
- "scopes": { "type": "array", "items": { "$ref": "scope.json" } }
+ "scopes": { "type": "array", "items": { "$ref": "scope.json" } },
+ "user_list": { "type": ["object", "null"], "$ref": "user_list.json" }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/public_api/v4/operations/user_list.json b/spec/fixtures/api/schemas/public_api/v4/operations/user_list.json
new file mode 100644
index 00000000000..6a9f977e37d
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/operations/user_list.json
@@ -0,0 +1,16 @@
+{
+ "type": ["object", "null"],
+ "required": [
+ "id",
+ "iid",
+ "name",
+ "user_xids"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "iid": { "type": "integer" },
+ "name": { "type": "string" },
+ "user_xids": { "type": "string" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/status/ci_detailed_status.json b/spec/fixtures/api/schemas/status/ci_detailed_status.json
index 8d0f1e4a6af..0d9e4975858 100644
--- a/spec/fixtures/api/schemas/status/ci_detailed_status.json
+++ b/spec/fixtures/api/schemas/status/ci_detailed_status.json
@@ -17,7 +17,7 @@
"group": { "type": "string" },
"tooltip": { "type": "string" },
"has_details": { "type": "boolean" },
- "details_path": { "type": "string" },
+ "details_path": { "oneOf": [{ "type": "null" }, {"type": "string" }] },
"favicon": { "type": "string" },
"illustration": { "$ref": "illustration.json" },
"action": { "$ref": "action.json" }
diff --git a/spec/fixtures/ci_secure_files/sample.p12 b/spec/fixtures/ci_secure_files/sample.p12
index c74df26a8d4..84c7bf6a2f5 100644
--- a/spec/fixtures/ci_secure_files/sample.p12
+++ b/spec/fixtures/ci_secure_files/sample.p12
Binary files differ
diff --git a/spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event.yml b/spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event.yml
index 1c1ad65796c..6c3a0ef5ed6 100644
--- a/spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event.yml
+++ b/spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event.yml
@@ -1,6 +1,6 @@
---
description:
-category: Groups::EmailCampaignsController
+category: Projects::Pipelines::EmailCampaignsController
action: click
label_description:
property_description:
@@ -13,12 +13,12 @@ identifiers:
product_section:
product_stage:
product_group:
-milestone: "13.11"
+milestone: '13.11'
introduced_by_url:
distributions:
-- ce
-- ee
+ - ce
+ - ee
tiers:
-- free
-- premium
-- ultimate
+ - free
+ - premium
+ - ultimate
diff --git a/spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event_ee.yml b/spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event_ee.yml
index 174468028b8..3381c73f23e 100644
--- a/spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event_ee.yml
+++ b/spec/fixtures/lib/generators/gitlab/snowplow_event_definition_generator/sample_event_ee.yml
@@ -1,6 +1,6 @@
---
description:
-category: Groups::EmailCampaignsController
+category: Projects::Pipelines::EmailCampaignsController
action: click
label_description:
property_description:
@@ -13,10 +13,10 @@ identifiers:
product_section:
product_stage:
product_group:
-milestone: "13.11"
+milestone: '13.11'
introduced_by_url:
distributions:
-- ee
+ - ee
tiers:
-#- premium
-- ultimate
+ #- premium
+ - ultimate
diff --git a/spec/fixtures/packages/nuget/symbol/package.pdb b/spec/fixtures/packages/nuget/symbol/package.pdb
new file mode 100644
index 00000000000..dc82bf418a2
--- /dev/null
+++ b/spec/fixtures/packages/nuget/symbol/package.pdb
Binary files differ
diff --git a/spec/fixtures/security_reports/master/gl-common-scanning-report.json b/spec/fixtures/security_reports/master/gl-common-scanning-report.json
index 4c494963a79..31a86d3a8ae 100644
--- a/spec/fixtures/security_reports/master/gl-common-scanning-report.json
+++ b/spec/fixtures/security_reports/master/gl-common-scanning-report.json
@@ -1,11 +1,11 @@
{
"vulnerabilities": [
{
+ "id": "vulnerability-1",
"category": "dependency_scanning",
"name": "Vulnerability for remediation testing 1",
"message": "This vulnerability should have ONE remediation",
"description": "",
- "cve": "CVE-2137",
"severity": "High",
"solution": "Upgrade to latest version.",
"scanner": {
@@ -43,11 +43,11 @@
}
},
{
+ "id": "vulnerability-2",
"category": "dependency_scanning",
"name": "Vulnerability for remediation testing 2",
"message": "This vulnerability should have ONE remediation",
"description": "",
- "cve": "CVE-2138",
"severity": "High",
"solution": "Upgrade to latest version.",
"scanner": {
@@ -85,11 +85,11 @@
}
},
{
+ "id": "vulnerability-3",
"category": "dependency_scanning",
"name": "Vulnerability for remediation testing 3",
"message": "Remediation for this vulnerability should remediate CVE-2140 as well",
"description": "",
- "cve": "CVE-2139",
"severity": "High",
"solution": "Upgrade to latest version.",
"scanner": {
@@ -127,11 +127,11 @@
}
},
{
+ "id": "vulnerability-4",
"category": "dependency_scanning",
"name": "Vulnerability for remediation testing 4",
"message": "Remediation for this vulnerability should remediate CVE-2139 as well",
"description": "",
- "cve": "CVE-2140",
"severity": "High",
"solution": "Upgrade to latest version.",
"scanner": {
@@ -169,11 +169,11 @@
}
},
{
+ "id": "vulnerability-5",
"category": "dependency_scanning",
"name": "Vulnerabilities in libxml2",
"message": "Vulnerabilities in libxml2 in nokogiri",
"description": "",
- "cve": "CVE-1020",
"severity": "High",
"solution": "Upgrade to latest version.",
"scanner": {
@@ -281,12 +281,11 @@
}
},
{
- "id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d3",
+ "id": "vulnerability-6",
"category": "dependency_scanning",
"name": "Regular Expression Denial of Service",
"message": "Regular Expression Denial of Service in debug",
"description": "",
- "cve": "CVE-1030",
"severity": "Unknown",
"solution": "Upgrade to latest versions.",
"scanner": {
@@ -387,6 +386,7 @@
]
},
{
+ "id": "vulnerability-7",
"category": "dependency_scanning",
"name": "Authentication bypass via incorrect DOM traversal and canonicalization",
"message": "Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js",
@@ -421,47 +421,46 @@
{
"fixes": [
{
- "cve": "CVE-2137"
+ "id": "vulnerability-1"
}
],
- "summary": "this remediates CVE-2137",
+ "summary": "this remediates the first vulnerability",
"diff": "dG90YWxseSBsZWdpdCBkaWZm"
},
{
"fixes": [
{
- "cve": "CVE-2138"
+ "id": "vulnerability-2"
}
],
- "summary": "this remediates CVE-2138",
+ "summary": "this remediates the second vulnerability",
"diff": "dG90YWxseSBsZWdpdCBkaWZm"
},
{
"fixes": [
{
- "cve": "CVE-2139"
+ "id": "vulnerability-3"
},
{
- "cve": "CVE-2140"
+ "id": "vulnerability-4"
}
],
- "summary": "this remediates CVE-2139 and CVE-2140",
+ "summary": "this remediates the third and fourth vulnerability",
"diff": "dG90YWxseSBsZWdpdGltYXRlIGRpZmYsIDEwLzEwIHdvdWxkIGFwcGx5"
},
{
"fixes": [
{
- "cve": "CVE-1020"
+ "id": "vulnerability-5"
}
],
- "summary": "this fixes CVE-1020",
+ "summary": "this fixes the fifth vulnerability",
"diff": "dG90YWxseSBsZWdpdGltYXRlIGRpZmYsIDEwLzEwIHdvdWxkIGFwcGx5"
},
{
"fixes": [
{
- "cve": "CVE",
- "id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d3"
+ "id": "vulnerability-6"
}
],
"summary": "this fixes CVE",
@@ -470,22 +469,11 @@
{
"fixes": [
{
- "cve": "CVE",
- "id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d3"
+ "id": "vulnerability-6"
}
],
"summary": "this fixed CVE",
"diff": "dG90YWxseSBsZWdpdGltYXRlIGRpZmYsIDEwLzEwIHdvdWxkIGFwcGx5"
- },
- {
- "fixes": [
- {
- "id": "2134",
- "cve": "CVE-1"
- }
- ],
- "summary": "this fixes CVE-1",
- "diff": "dG90YWxseSBsZWdpdGltYXRlIGRpZmYsIDEwLzEwIHdvdWxkIGFwcGx5"
}
],
"dependency_files": [],
diff --git a/spec/frontend/__helpers__/clean_html_element_serializer.js b/spec/frontend/__helpers__/clean_html_element_serializer.js
new file mode 100644
index 00000000000..d787f5126ec
--- /dev/null
+++ b/spec/frontend/__helpers__/clean_html_element_serializer.js
@@ -0,0 +1,142 @@
+// slot-scope attribute is a result of Vue.js 3 stubs being serialized in slot context, drop it
+// modelModifiers are result of Vue.js 3 model modifiers handling and should not be in snapshot
+const ATTRIBUTES_TO_REMOVE = ['slot-scope', 'modelmodifiers'];
+// Taken from https://github.com/vuejs/vue/blob/72aed6a149b94b5b929fb47370a7a6d4cb7491c5/src/platforms/web/util/attrs.ts#L37-L44
+const BOOLEAN_ATTRIBUTES = new Set(
+ (
+ 'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' +
+ 'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' +
+ 'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' +
+ 'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' +
+ 'required,reversed,scoped,seamless,selected,sortable,' +
+ 'truespeed,typemustmatch,visible'
+ ).split(','),
+);
+
+function sortClassesAlphabetically(node) {
+ // Make classes render in alphabetical order for both Vue2 and Vue3
+ if (node.hasAttribute('class')) {
+ const classes = node.getAttribute('class');
+ if (classes === '') {
+ node.removeAttribute('class');
+ } else {
+ node.setAttribute('class', Array.from(node.classList).sort().join(' '));
+ }
+ }
+}
+
+const TRANSITION_VALUES_TO_REMOVE = [
+ { attributeName: 'css', defaultValue: 'true' },
+ { attributeName: 'persisted', defaultValue: 'true' },
+];
+function removeInternalPropsLeakingToTransitionStub(node) {
+ TRANSITION_VALUES_TO_REMOVE.forEach((hash) => {
+ if (node.getAttribute(hash.attributeName) === hash.defaultValue) {
+ node.removeAttribute(hash.attributeName);
+ }
+ });
+}
+
+function normalizeText(node) {
+ const newText = node.textContent.trim();
+ const textWithoutNewLines = newText.replace(/\n/g, '');
+ const textWithoutDeepSpace = textWithoutNewLines.replace(/(?<=\S)\s+/g, ' ');
+ // eslint-disable-next-line no-param-reassign
+ node.textContent = textWithoutDeepSpace;
+}
+
+const visited = new WeakSet();
+
+// Lovingly borrowed from https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace#whitespace_helper_functions
+function isAllWhitespace(node) {
+ return !/[^\t\n\r ]/.test(node.textContent);
+}
+
+function isIgnorable(node) {
+ return (
+ node.nodeType === Node.COMMENT_NODE || // A comment node
+ (node.nodeType === Node.TEXT_NODE && isAllWhitespace(node))
+ ); // a text node, all ws
+}
+
+const REFERENCE_ATTRIBUTES = ['aria-controls', 'aria-labelledby', 'for'];
+function updateIdTags(root) {
+ const elementsWithIds = [...(root.id ? [root] : []), ...root.querySelectorAll('[id]')];
+
+ const referenceSelector = REFERENCE_ATTRIBUTES.map((attr) => `[${attr}]`).join(',');
+ const elementsWithReference = [
+ ...(root.matches(referenceSelector) ? [root] : []),
+ ...root.querySelectorAll(REFERENCE_ATTRIBUTES.map((attr) => `[${attr}]`).join(',')),
+ ];
+
+ elementsWithReference.forEach((el) => {
+ REFERENCE_ATTRIBUTES.filter((attr) => el.getAttribute(attr)).forEach((target) => {
+ const index = elementsWithIds.findIndex((t) => t.id === el.getAttribute(target));
+ if (index !== -1) {
+ el.setAttribute(target, `reference-${index}`);
+ }
+ });
+ });
+
+ elementsWithIds.forEach((el, index) => {
+ el.setAttribute('id', `reference-${index}`);
+ });
+}
+
+export function test(received) {
+ return received instanceof Element && !visited.has(received);
+}
+
+export function serialize(received, config, indentation, depth, refs, printer) {
+ // Explicitly set empty string values of img.src to `null` as Vue3 does
+ // We need to do this before `clone`, otherwise src prop diff will be lost
+ received.querySelectorAll('img').forEach((img) => img.setAttribute('src', img.src || null));
+
+ const clone = received.cloneNode(true);
+
+ updateIdTags(clone);
+ visited.add(clone);
+
+ const iterator = document.createNodeIterator(
+ clone,
+ // eslint-disable-next-line no-bitwise
+ NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,
+ );
+ const ignorableNodes = [];
+
+ for (let currentNode = iterator.nextNode(); currentNode; currentNode = iterator.nextNode()) {
+ if (isIgnorable(currentNode)) {
+ ignorableNodes.push(currentNode);
+ } else {
+ if (currentNode instanceof Element) {
+ ATTRIBUTES_TO_REMOVE.forEach((attr) => currentNode.removeAttribute(attr));
+
+ if (!currentNode.tagName.includes('-')) {
+ // We want to normalize boolean attributes rendering only on native tags
+ BOOLEAN_ATTRIBUTES.forEach((attr) => {
+ if (currentNode.hasAttribute(attr) && currentNode.getAttribute(attr) === attr) {
+ currentNode.setAttribute(attr, '');
+ }
+ });
+ }
+
+ sortClassesAlphabetically(currentNode);
+
+ if (currentNode.tagName === 'TRANSITION-STUB') {
+ removeInternalPropsLeakingToTransitionStub(currentNode);
+ }
+ }
+
+ if (currentNode.nodeType === Node.TEXT_NODE) {
+ normalizeText(currentNode);
+ }
+
+ currentNode.normalize();
+ visited.add(currentNode);
+ }
+ }
+
+ ignorableNodes.forEach((x) => x.remove());
+
+ return printer(clone, config, indentation, depth, refs);
+}
diff --git a/spec/frontend/__helpers__/dom_shims/get_client_rects.js b/spec/frontend/__helpers__/dom_shims/get_client_rects.js
index 7ba60dd7936..0ec3525f0ef 100644
--- a/spec/frontend/__helpers__/dom_shims/get_client_rects.js
+++ b/spec/frontend/__helpers__/dom_shims/get_client_rects.js
@@ -1,7 +1,8 @@
function hasHiddenStyle(node) {
if (!node.style) {
return false;
- } else if (node.style.display === 'none' || node.style.visibility === 'hidden') {
+ }
+ if (node.style.display === 'none' || node.style.visibility === 'hidden') {
return true;
}
diff --git a/spec/frontend/__helpers__/html_string_serializer.js b/spec/frontend/__helpers__/html_string_serializer.js
new file mode 100644
index 00000000000..99f4acd0e97
--- /dev/null
+++ b/spec/frontend/__helpers__/html_string_serializer.js
@@ -0,0 +1,11 @@
+export function test(received) {
+ return received && typeof received === 'string' && received.startsWith('<');
+}
+
+export function serialize(received, config, indentation, depth, refs, printer) {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(received, 'text/html');
+ const el = doc.body.firstElementChild;
+
+ return printer(el, config, indentation, depth, refs);
+}
diff --git a/spec/frontend/__helpers__/vue_test_utils_helper.js b/spec/frontend/__helpers__/vue_test_utils_helper.js
index c144a256dce..20a79fc4d2f 100644
--- a/spec/frontend/__helpers__/vue_test_utils_helper.js
+++ b/spec/frontend/__helpers__/vue_test_utils_helper.js
@@ -1,6 +1,13 @@
import * as testingLibrary from '@testing-library/dom';
-import { createWrapper, WrapperArray, ErrorWrapper, mount, shallowMount } from '@vue/test-utils';
-import { isArray, upperFirst } from 'lodash';
+import {
+ createWrapper,
+ Wrapper, // eslint-disable-line no-unused-vars
+ ErrorWrapper,
+ mount,
+ shallowMount,
+ WrapperArray,
+} from '@vue/test-utils';
+import { compose } from 'lodash/fp';
const vNodeContainsText = (vnode, text) =>
(vnode.text && vnode.text.includes(text)) ||
@@ -14,7 +21,7 @@ const vNodeContainsText = (vnode, text) =>
*
* @param {HTMLElement} element
* @param {Object} options
- * @returns VTU wrapper
+ * @returns {Wrapper} VTU wrapper
*/
const createWrapperFromElement = (element, options) =>
// eslint-disable-next-line no-underscore-dangle
@@ -52,19 +59,84 @@ export const waitForMutation = (store, expectedMutationType) =>
});
});
+/**
+ * Query function type
+ * @callback FindFunction
+ * @param text
+ * @returns {Wrapper}
+ */
+
+/**
+ * Query all function type
+ * @callback FindAllFunction
+ * @param text
+ * @returns {WrapperArray}
+ */
+
+/**
+ * Query find with options functions type
+ * @callback FindWithOptionsFunction
+ * @param text
+ * @param options
+ * @returns {Wrapper}
+ */
+
+/**
+ * Query find all with options functions type
+ * @callback FindAllWithOptionsFunction
+ * @param text
+ * @param options
+ * @returns {WrapperArray}
+ */
+
+/**
+ * Extended Wrapper queries
+ * @typedef { {
+ * findByTestId: FindFunction,
+ * findAllByTestId: FindAllFunction,
+ * findComponentByTestId: FindFunction,
+ * findAllComponentsByTestId: FindAllFunction,
+ * findByRole: FindWithOptionsFunction,
+ * findAllByRole: FindAllWithOptionsFunction,
+ * findByLabelText: FindWithOptionsFunction,
+ * findAllByLabelText: FindAllWithOptionsFunction,
+ * findByPlaceholderText: FindWithOptionsFunction,
+ * findAllByPlaceholderText: FindAllWithOptionsFunction,
+ * findByText: FindWithOptionsFunction,
+ * findAllByText: FindAllWithOptionsFunction,
+ * findByDisplayValue: FindWithOptionsFunction,
+ * findAllByDisplayValue: FindAllWithOptionsFunction,
+ * findByAltText: FindWithOptionsFunction,
+ * findAllByAltText: FindAllWithOptionsFunction,
+ * findByTitle: FindWithOptionsFunction,
+ * findAllByTitle: FindAllWithOptionsFunction
+ * } } ExtendedQueries
+ */
+
+/**
+ * Extended Wrapper
+ * @typedef {(Wrapper & ExtendedQueries)} ExtendedWrapper
+ */
+
+/**
+ * Creates a Wrapper {@link https://v1.test-utils.vuejs.org/api/wrapper/} with
+ * Additional Queries {@link https://testing-library.com/docs/queries/about}.
+ * @param { Wrapper } wrapper
+ * @returns { ExtendedWrapper }
+ */
export const extendedWrapper = (wrapper) => {
// https://testing-library.com/docs/queries/about
const AVAILABLE_QUERIES = [
- 'byRole',
- 'byLabelText',
- 'byPlaceholderText',
- 'byText',
- 'byDisplayValue',
- 'byAltText',
- 'byTitle',
+ 'ByRole',
+ 'ByLabelText',
+ 'ByPlaceholderText',
+ 'ByText',
+ 'ByDisplayValue',
+ 'ByAltText',
+ 'ByTitle',
];
- if (isArray(wrapper) || !wrapper?.find) {
+ if (Array.isArray(wrapper) || !wrapper?.find) {
// eslint-disable-next-line no-console
console.warn(
'[vue-test-utils-helper]: you are trying to extend an object that is not a VueWrapper.',
@@ -74,11 +146,13 @@ export const extendedWrapper = (wrapper) => {
return Object.defineProperties(wrapper, {
findByTestId: {
+ /** @this { Wrapper } */
value(id) {
return this.find(`[data-testid="${id}"]`);
},
},
findAllByTestId: {
+ /** @this { Wrapper } */
value(id) {
return this.findAll(`[data-testid="${id}"]`);
},
@@ -88,6 +162,7 @@ export const extendedWrapper = (wrapper) => {
* with CSS selectors: https://v1.test-utils.vuejs.org/api/wrapper/#findcomponent
*/
findComponentByTestId: {
+ /** @this { Wrapper } */
value(id) {
return this.findComponent(`[data-testid="${id}"]`);
},
@@ -97,6 +172,7 @@ export const extendedWrapper = (wrapper) => {
* with CSS selectors: https://v1.test-utils.vuejs.org/api/wrapper/#findallcomponents
*/
findAllComponentsByTestId: {
+ /** @this { Wrapper } */
value(id) {
return this.findAllComponents(`[data-testid="${id}"]`);
},
@@ -105,13 +181,10 @@ export const extendedWrapper = (wrapper) => {
...AVAILABLE_QUERIES.reduce((accumulator, query) => {
return {
...accumulator,
- [`find${upperFirst(query)}`]: {
+ [`find${query}`]: {
+ /** @this { Wrapper } */
value(text, options = {}) {
- const elements = testingLibrary[`queryAll${upperFirst(query)}`](
- wrapper.element,
- text,
- options,
- );
+ const elements = testingLibrary[`queryAll${query}`](this.element, text, options);
// Element not found, return an `ErrorWrapper`
if (!elements.length) {
@@ -126,13 +199,10 @@ export const extendedWrapper = (wrapper) => {
...AVAILABLE_QUERIES.reduce((accumulator, query) => {
return {
...accumulator,
- [`findAll${upperFirst(query)}`]: {
+ [`findAll${query}`]: {
+ /** @this { Wrapper } */
value(text, options = {}) {
- const elements = testingLibrary[`queryAll${upperFirst(query)}`](
- wrapper.element,
- text,
- options,
- );
+ const elements = testingLibrary[`queryAll${query}`](this.element, text, options);
const wrappers = elements.map((element) => {
const elementWrapper = createWrapperFromElement(element, this.options);
@@ -152,6 +222,5 @@ export const extendedWrapper = (wrapper) => {
});
};
-export const shallowMountExtended = (...args) => extendedWrapper(shallowMount(...args));
-
-export const mountExtended = (...args) => extendedWrapper(mount(...args));
+export const shallowMountExtended = compose(extendedWrapper, shallowMount);
+export const mountExtended = compose(extendedWrapper, mount);
diff --git a/spec/frontend/__helpers__/vue_test_utils_helper_spec.js b/spec/frontend/__helpers__/vue_test_utils_helper_spec.js
index 2f69a2348d9..c137561154d 100644
--- a/spec/frontend/__helpers__/vue_test_utils_helper_spec.js
+++ b/spec/frontend/__helpers__/vue_test_utils_helper_spec.js
@@ -374,34 +374,34 @@ describe('Vue test utils helpers', () => {
});
});
- describe.each`
- mountExtendedFunction | expectedMountFunction
- ${shallowMountExtended} | ${'shallowMount'}
- ${mountExtended} | ${'mount'}
- `('$mountExtendedFunction', ({ mountExtendedFunction, expectedMountFunction }) => {
- const FakeComponent = jest.fn();
- const options = {
- propsData: {
- foo: 'bar',
- },
- };
-
- beforeEach(() => {
- const mockWrapper = { find: jest.fn() };
- jest.spyOn(vtu, expectedMountFunction).mockImplementation(() => mockWrapper);
+ describe('mount extended functions', () => {
+ // eslint-disable-next-line vue/one-component-per-file
+ const FakeChildComponent = Vue.component('FakeChildComponent', {
+ template: '<div>Bar <div data-testid="fake-id"/></div>',
});
- it(`calls \`${expectedMountFunction}\` with passed arguments`, () => {
- mountExtendedFunction(FakeComponent, options);
-
- expect(vtu[expectedMountFunction]).toHaveBeenCalledWith(FakeComponent, options);
+ // eslint-disable-next-line vue/one-component-per-file
+ const FakeComponent = Vue.component('FakeComponent', {
+ components: {
+ FakeChildComponent,
+ },
+ template: '<div>Foo <fake-child-component data-testid="fake-id" /></div>',
});
- it('returns extended wrapper', () => {
- const result = mountExtendedFunction(FakeComponent, options);
+ describe('mountExtended', () => {
+ it('mounts component and provides extended queries', () => {
+ const wrapper = mountExtended(FakeComponent);
+ expect(wrapper.text()).toBe('Foo Bar');
+ expect(wrapper.findAllByTestId('fake-id').length).toBe(2);
+ });
+ });
- expect(result).toHaveProperty('find');
- expect(result).toHaveProperty('findByTestId');
+ describe('shallowMountExtended', () => {
+ it('shallow mounts component and provides extended queries', () => {
+ const wrapper = shallowMountExtended(FakeComponent);
+ expect(wrapper.text()).toBe('Foo');
+ expect(wrapper.findAllByTestId('fake-id').length).toBe(1);
+ });
});
});
});
diff --git a/spec/frontend/access_tokens/components/access_token_table_app_spec.js b/spec/frontend/access_tokens/components/access_token_table_app_spec.js
index 5236f38dc35..ae767f8b3f5 100644
--- a/spec/frontend/access_tokens/components/access_token_table_app_spec.js
+++ b/spec/frontend/access_tokens/components/access_token_table_app_spec.js
@@ -157,9 +157,9 @@ describe('~/access_tokens/components/access_token_table_app', () => {
href: '/-/profile/personal_access_tokens/1/revoke',
'data-confirm': sprintf(
__(
- 'Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone.',
+ 'Are you sure you want to revoke the %{accessTokenType} "%{tokenName}"? This action cannot be undone.',
),
- { accessTokenType },
+ { accessTokenType, tokenName: 'a' },
),
});
expect(button.props('category')).toBe('tertiary');
diff --git a/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap b/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
index ddeab3e3b62..fca17f948f8 100644
--- a/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
+++ b/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
@@ -24,7 +24,6 @@ exports[`AddContextCommitsModal renders modal with 2 tabs 1`] = `
<gl-tab-stub
titlelinkclass=""
>
-
<div
class="gl-mt-3"
>
@@ -38,7 +37,6 @@ exports[`AddContextCommitsModal renders modal with 2 tabs 1`] = `
searchtextoptionlabel="Search for this text"
value=""
/>
-
<review-tab-container-stub
commits=""
emptylisttext="Your search didn't match any commits. Try a different query."
@@ -46,11 +44,9 @@ exports[`AddContextCommitsModal renders modal with 2 tabs 1`] = `
/>
</div>
</gl-tab-stub>
-
<gl-tab-stub
titlelinkclass=""
>
-
<review-tab-container-stub
commits=""
emptylisttext="Commits you select appear here. Go to the first tab and select commits to add to this merge request."
diff --git a/spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js b/spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js
index e519684bbc5..4340699a7ed 100644
--- a/spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js
+++ b/spec/frontend/admin/abuse_report/components/abuse_report_app_spec.js
@@ -1,28 +1,46 @@
-import { shallowMount } from '@vue/test-utils';
import { GlAlert } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import AbuseReportApp from '~/admin/abuse_report/components/abuse_report_app.vue';
import ReportHeader from '~/admin/abuse_report/components/report_header.vue';
import UserDetails from '~/admin/abuse_report/components/user_details.vue';
+import ReportDetails from '~/admin/abuse_report/components/report_details.vue';
import ReportedContent from '~/admin/abuse_report/components/reported_content.vue';
-import HistoryItems from '~/admin/abuse_report/components/history_items.vue';
+import ActivityEventsList from '~/admin/abuse_report/components/activity_events_list.vue';
+import ActivityHistoryItem from '~/admin/abuse_report/components/activity_history_item.vue';
import { SUCCESS_ALERT } from '~/admin/abuse_report/constants';
import { mockAbuseReport } from '../mock_data';
describe('AbuseReportApp', () => {
let wrapper;
+ const { similarOpenReports } = mockAbuseReport.user;
+
const findAlert = () => wrapper.findComponent(GlAlert);
const findReportHeader = () => wrapper.findComponent(ReportHeader);
const findUserDetails = () => wrapper.findComponent(UserDetails);
- const findReportedContent = () => wrapper.findComponent(ReportedContent);
- const findHistoryItems = () => wrapper.findComponent(HistoryItems);
- const createComponent = (props = {}) => {
- wrapper = shallowMount(AbuseReportApp, {
+ const findReportedContent = () => wrapper.findByTestId('reported-content');
+ const findReportedContentForSimilarReports = () =>
+ wrapper.findAllByTestId('reported-content-similar-open-reports');
+ const firstReportedContentForSimilarReports = () =>
+ findReportedContentForSimilarReports().at(0).findComponent(ReportedContent);
+
+ const findActivityList = () => wrapper.findComponent(ActivityEventsList);
+ const findActivityItem = () => wrapper.findByTestId('activity');
+ const findActivityForSimilarReports = () =>
+ wrapper.findAllByTestId('activity-similar-open-reports');
+ const firstActivityForSimilarReports = () =>
+ findActivityForSimilarReports().at(0).findComponent(ActivityHistoryItem);
+
+ const findReportDetails = () => wrapper.findComponent(ReportDetails);
+
+ const createComponent = (props = {}, provide = {}) => {
+ wrapper = shallowMountExtended(AbuseReportApp, {
propsData: {
abuseReport: mockAbuseReport,
...props,
},
+ provide,
});
};
@@ -64,7 +82,7 @@ describe('AbuseReportApp', () => {
});
});
- describe('ReportHeader', () => {
+ describe('Report header', () => {
it('renders ReportHeader', () => {
expect(findReportHeader().props('user')).toBe(mockAbuseReport.user);
expect(findReportHeader().props('report')).toBe(mockAbuseReport.report);
@@ -83,7 +101,7 @@ describe('AbuseReportApp', () => {
});
});
- describe('UserDetails', () => {
+ describe('User Details', () => {
it('renders UserDetails', () => {
expect(findUserDetails().props('user')).toBe(mockAbuseReport.user);
});
@@ -101,13 +119,47 @@ describe('AbuseReportApp', () => {
});
});
- it('renders ReportedContent', () => {
- expect(findReportedContent().props('report')).toBe(mockAbuseReport.report);
- expect(findReportedContent().props('reporter')).toBe(mockAbuseReport.reporter);
+ describe('Reported Content', () => {
+ it('renders ReportedContent', () => {
+ expect(findReportedContent().props('report')).toBe(mockAbuseReport.report);
+ });
+
+ it('renders similar abuse reports', () => {
+ expect(findReportedContentForSimilarReports()).toHaveLength(similarOpenReports.length);
+ expect(firstReportedContentForSimilarReports().props('report')).toBe(similarOpenReports[0]);
+ });
});
- it('renders HistoryItems', () => {
- expect(findHistoryItems().props('report')).toBe(mockAbuseReport.report);
- expect(findHistoryItems().props('reporter')).toBe(mockAbuseReport.reporter);
+ describe('ReportDetails', () => {
+ describe('when abuseReportLabels feature flag is enabled', () => {
+ it('renders ReportDetails', () => {
+ createComponent({}, { glFeatures: { abuseReportLabels: true } });
+
+ expect(findReportDetails().props('reportId')).toBe(mockAbuseReport.report.globalId);
+ });
+ });
+
+ describe('when abuseReportLabels feature flag is disabled', () => {
+ it('does not render ReportDetails', () => {
+ createComponent({}, { glFeatures: { abuseReportLabels: false } });
+
+ expect(findReportDetails().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('Activity', () => {
+ it('renders the activity events list', () => {
+ expect(findActivityList().exists()).toBe(true);
+ });
+
+ it('renders activity item for abuse report', () => {
+ expect(findActivityItem().props('report')).toBe(mockAbuseReport.report);
+ });
+
+ it('renders activity items for similar abuse reports', () => {
+ expect(findActivityForSimilarReports()).toHaveLength(similarOpenReports.length);
+ expect(firstActivityForSimilarReports().props('report')).toBe(similarOpenReports[0]);
+ });
});
});
diff --git a/spec/frontend/admin/abuse_report/components/activity_events_list_spec.js b/spec/frontend/admin/abuse_report/components/activity_events_list_spec.js
new file mode 100644
index 00000000000..cd1120d2db4
--- /dev/null
+++ b/spec/frontend/admin/abuse_report/components/activity_events_list_spec.js
@@ -0,0 +1,30 @@
+import { shallowMount } from '@vue/test-utils';
+import ActivityEventsList from '~/admin/abuse_report/components/activity_events_list.vue';
+
+describe('ActivityEventsList', () => {
+ let wrapper;
+
+ const mockSlotContent = 'Test slot content';
+
+ const findActivityEventsList = () => wrapper.findComponent(ActivityEventsList);
+
+ const createComponent = () => {
+ wrapper = shallowMount(ActivityEventsList, {
+ slots: {
+ 'history-items': mockSlotContent,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders activity title', () => {
+ expect(findActivityEventsList().text()).toContain('Activity');
+ });
+
+ it('renders history-items slot', () => {
+ expect(findActivityEventsList().text()).toContain(mockSlotContent);
+ });
+});
diff --git a/spec/frontend/admin/abuse_report/components/activity_history_item_spec.js b/spec/frontend/admin/abuse_report/components/activity_history_item_spec.js
new file mode 100644
index 00000000000..3f430b0143e
--- /dev/null
+++ b/spec/frontend/admin/abuse_report/components/activity_history_item_spec.js
@@ -0,0 +1,64 @@
+import { GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { sprintf } from '~/locale';
+import AcitivityHistoryItem from '~/admin/abuse_report/components/activity_history_item.vue';
+import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import { mockAbuseReport } from '../mock_data';
+
+describe('AcitivityHistoryItem', () => {
+ let wrapper;
+
+ const { report } = mockAbuseReport;
+
+ const findHistoryItem = () => wrapper.findComponent(HistoryItem);
+ const findTimeAgo = () => wrapper.findComponent(TimeAgoTooltip);
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(AcitivityHistoryItem, {
+ propsData: {
+ report,
+ ...props,
+ },
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the icon', () => {
+ expect(findHistoryItem().props('icon')).toBe('warning');
+ });
+
+ describe('rendering the title', () => {
+ it('renders the reporters name and the category', () => {
+ const title = sprintf('Reported by %{name} for %{category}.', {
+ name: report.reporter.name,
+ category: report.category,
+ });
+ expect(findHistoryItem().text()).toContain(title);
+ });
+
+ describe('when the reporter is not defined', () => {
+ beforeEach(() => {
+ createComponent({ report: { ...report, reporter: undefined } });
+ });
+
+ it('renders the `No user found` as the reporters name and the category', () => {
+ const title = sprintf('Reported by %{name} for %{category}.', {
+ name: 'No user found',
+ category: report.category,
+ });
+ expect(findHistoryItem().text()).toContain(title);
+ });
+ });
+ });
+
+ it('renders the time-ago tooltip', () => {
+ expect(findTimeAgo().props('time')).toBe(report.reportedAt);
+ });
+});
diff --git a/spec/frontend/admin/abuse_report/components/history_items_spec.js b/spec/frontend/admin/abuse_report/components/history_items_spec.js
deleted file mode 100644
index 86e994fdc57..00000000000
--- a/spec/frontend/admin/abuse_report/components/history_items_spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { GlSprintf } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { sprintf } from '~/locale';
-import HistoryItems from '~/admin/abuse_report/components/history_items.vue';
-import HistoryItem from '~/vue_shared/components/registry/history_item.vue';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import { HISTORY_ITEMS_I18N } from '~/admin/abuse_report/constants';
-import { mockAbuseReport } from '../mock_data';
-
-describe('HistoryItems', () => {
- let wrapper;
-
- const { report, reporter } = mockAbuseReport;
-
- const findHistoryItem = () => wrapper.findComponent(HistoryItem);
- const findTimeAgo = () => wrapper.findComponent(TimeAgoTooltip);
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(HistoryItems, {
- propsData: {
- report,
- reporter,
- ...props,
- },
- stubs: {
- GlSprintf,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('renders the icon', () => {
- expect(findHistoryItem().props('icon')).toBe('warning');
- });
-
- describe('rendering the title', () => {
- it('renders the reporters name and the category', () => {
- const title = sprintf(HISTORY_ITEMS_I18N.reportedByForCategory, {
- name: reporter.name,
- category: report.category,
- });
- expect(findHistoryItem().text()).toContain(title);
- });
-
- describe('when the reporter is not defined', () => {
- beforeEach(() => {
- createComponent({ reporter: undefined });
- });
-
- it('renders the `No user found` as the reporters name and the category', () => {
- const title = sprintf(HISTORY_ITEMS_I18N.reportedByForCategory, {
- name: HISTORY_ITEMS_I18N.deletedReporter,
- category: report.category,
- });
- expect(findHistoryItem().text()).toContain(title);
- });
- });
- });
-
- it('renders the time-ago tooltip', () => {
- expect(findTimeAgo().props('time')).toBe(report.reportedAt);
- });
-});
diff --git a/spec/frontend/admin/abuse_report/components/labels_select_spec.js b/spec/frontend/admin/abuse_report/components/labels_select_spec.js
new file mode 100644
index 00000000000..a22dcc18e10
--- /dev/null
+++ b/spec/frontend/admin/abuse_report/components/labels_select_spec.js
@@ -0,0 +1,297 @@
+import MockAdapter from 'axios-mock-adapter';
+import { GlButton, GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK, HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
+import LabelsSelect from '~/admin/abuse_report/components/labels_select.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component';
+import labelsQuery from '~/admin/abuse_report/components/graphql/abuse_report_labels.query.graphql';
+import DropdownWidget from '~/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue';
+import DropdownValue from '~/sidebar/components/labels/labels_select_widget/dropdown_value.vue';
+import DropdownHeader from '~/sidebar/components/labels/labels_select_widget/dropdown_header.vue';
+import DropdownContentsCreateView from '~/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue';
+import DropdownFooter from '~/sidebar/components/labels/labels_select_widget/dropdown_footer.vue';
+import { createAlert } from '~/alert';
+import { mockLabelsQueryResponse, mockLabel1, mockLabel2 } from '../mock_data';
+
+jest.mock('~/alert');
+
+Vue.use(VueApollo);
+
+describe('Labels select component', () => {
+ let mock;
+ let wrapper;
+ let fakeApollo;
+
+ const selectedText = () => wrapper.findByTestId('selected-labels').text();
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findEditButton = () => wrapper.findComponent(GlButton);
+ const findDropdown = () => wrapper.findComponent(DropdownWidget);
+ const findDropdownHeader = () => wrapper.findComponent(DropdownHeader);
+ const findDropdownValue = () => wrapper.findComponent(DropdownValue);
+ const findCreateView = () => wrapper.findComponent(DropdownContentsCreateView);
+ const findDropdownFooter = () => wrapper.findComponent(DropdownFooter);
+
+ const labelsQueryHandlerSuccess = jest.fn().mockResolvedValue(mockLabelsQueryResponse);
+ const labelsQueryHandlerFailure = jest.fn().mockRejectedValue(new Error());
+
+ const updatePath = '/admin/abuse_reports/1';
+ const listPath = '/admin/abuse_reports';
+
+ async function openLabelsDropdown() {
+ findEditButton().vm.$emit('click');
+ await waitForPromises();
+ }
+
+ const selectLabel = (label) => {
+ findDropdown().vm.$emit('set-option', label);
+ nextTick();
+ };
+
+ const createComponent = ({ props = {}, labelsQueryHandler = labelsQueryHandlerSuccess } = {}) => {
+ fakeApollo = createMockApollo([[labelsQuery, labelsQueryHandler]]);
+ wrapper = shallowMountExtended(LabelsSelect, {
+ apolloProvider: fakeApollo,
+ propsData: {
+ report: { labels: [] },
+ canEdit: true,
+ ...props,
+ },
+ provide: {
+ updatePath,
+ listPath,
+ },
+ stubs: {
+ GlDropdown,
+ GlDropdownItem,
+ DropdownWidget: stubComponent(DropdownWidget, {
+ template: RENDER_ALL_SLOTS_TEMPLATE,
+ methods: { showDropdown: jest.fn() },
+ }),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ fakeApollo = null;
+ mock.restore();
+ });
+
+ describe('initial load', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays loading icon', () => {
+ expect(findLoadingIcon().exists()).toEqual(true);
+ });
+
+ it('disables edit button', () => {
+ expect(findEditButton().props('disabled')).toEqual(true);
+ });
+
+ describe('after initial load', () => {
+ beforeEach(() => {
+ wrapper.setProps({ report: { labels: [mockLabel1] } });
+ });
+
+ it('does not display loading icon', () => {
+ expect(findLoadingIcon().exists()).toEqual(false);
+ });
+
+ it('enables edit button', () => {
+ expect(findEditButton().props('disabled')).toEqual(false);
+ });
+
+ it('renders fetched DropdownValue with the correct props', () => {
+ const component = findDropdownValue();
+ expect(component.isVisible()).toBe(true);
+ expect(component.props('selectedLabels')).toEqual([mockLabel1]);
+ expect(component.props('labelsFilterBasePath')).toBe(listPath);
+ });
+ });
+ });
+
+ describe('when there are no selected labels', () => {
+ it('displays "None"', () => {
+ createComponent();
+
+ expect(selectedText()).toContain('None');
+ });
+ });
+
+ describe('when there are selected labels', () => {
+ beforeEach(() => {
+ createComponent({ props: { report: { labels: [mockLabel1, mockLabel2] } } });
+
+ mock.onPut(updatePath).reply(HTTP_STATUS_OK, {});
+ jest.spyOn(axios, 'put');
+ });
+
+ it('renders selected labels in DropdownValue', () => {
+ expect(findDropdownValue().isVisible()).toBe(true);
+ expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel1, mockLabel2]);
+ });
+
+ it('selected labels can be removed', async () => {
+ findDropdownValue().vm.$emit('onLabelRemove', mockLabel1.id);
+ await nextTick();
+
+ expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel2]);
+ expect(axios.put).toHaveBeenCalledWith(updatePath, {
+ label_ids: [mockLabel2.id],
+ });
+ });
+ });
+
+ describe('when not editing', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('does not trigger abuse report labels query', () => {
+ expect(labelsQueryHandlerSuccess).not.toHaveBeenCalled();
+ });
+
+ it('does not render the dropdown', () => {
+ expect(findDropdown().isVisible()).toBe(false);
+ });
+ });
+
+ describe('when editing', () => {
+ beforeEach(async () => {
+ createComponent();
+ await openLabelsDropdown();
+ });
+
+ it('triggers abuse report labels query', () => {
+ expect(labelsQueryHandlerSuccess).toHaveBeenCalledTimes(1);
+ });
+
+ it('renders dropdown with fetched labels', () => {
+ expect(findDropdown().isVisible()).toBe(true);
+ expect(findDropdown().props('options')).toEqual([mockLabel1, mockLabel2]);
+ });
+
+ it('selects/deselects a label', async () => {
+ await selectLabel(mockLabel1);
+
+ expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel1]);
+
+ await selectLabel(mockLabel1);
+
+ expect(selectedText()).toContain('None');
+ });
+
+ it('triggers abuse report labels query when search term is set', async () => {
+ findDropdown().vm.$emit('set-search', 'Dos');
+ await waitForPromises();
+
+ expect(labelsQueryHandlerSuccess).toHaveBeenCalledTimes(2);
+ expect(labelsQueryHandlerSuccess).toHaveBeenCalledWith({ searchTerm: 'Dos' });
+ });
+
+ it('does not render DropdownContentsCreateView', () => {
+ expect(findCreateView().exists()).toBe(false);
+ });
+
+ it('renders DropdownFooter', () => {
+ expect(findDropdownFooter().props('footerCreateLabelTitle')).toEqual('Create label');
+ expect(findDropdownFooter().props('footerManageLabelTitle')).toEqual('');
+ });
+
+ describe('when DropdownHeader emits `toggleDropdownContentsCreateView` event', () => {
+ beforeEach(() => {
+ findDropdownHeader().vm.$emit('toggleDropdownContentsCreateView');
+ });
+
+ it('renders DropdownContentsCreateView and removes DropdownFooter', () => {
+ expect(findCreateView().props('workspaceType')).toEqual('abuseReport');
+ expect(findDropdownFooter().exists()).toBe(false);
+ });
+
+ describe('when DropdownContentsCreateView emits `hideCreateView` event', () => {
+ it('removes itself', async () => {
+ findCreateView().vm.$emit('hideCreateView');
+ await nextTick();
+
+ expect(findCreateView().exists()).toBe(false);
+ });
+ });
+
+ describe('when DropdownContentsCreateView emits `labelCreated` event', () => {
+ it('selects created label', async () => {
+ findCreateView().vm.$emit('labelCreated', mockLabel1);
+ await nextTick();
+
+ expect(findDropdownValue().props('selectedLabels')).toEqual([mockLabel1]);
+ });
+ });
+ });
+
+ describe('when DropdownFooter emits `toggleDropdownContentsCreateView` event', () => {
+ it('renders DropdownContentsCreateView', async () => {
+ findDropdownFooter().vm.$emit('toggleDropdownContentsCreateView');
+ await nextTick();
+
+ expect(findCreateView().props('workspaceType')).toEqual('abuseReport');
+ });
+ });
+ });
+
+ describe('after edit', () => {
+ const setup = async (response) => {
+ mock.onPut(updatePath).reply(response, {});
+ jest.spyOn(axios, 'put');
+
+ createComponent();
+ await openLabelsDropdown();
+ await selectLabel(mockLabel1);
+
+ findDropdown().vm.$emit('hide');
+ };
+
+ describe('successful save', () => {
+ it('saves', async () => {
+ await setup(HTTP_STATUS_OK);
+
+ expect(axios.put).toHaveBeenCalledWith(updatePath, {
+ label_ids: [mockLabel1.id],
+ });
+ });
+ });
+
+ describe('unsuccessful save', () => {
+ it('creates an alert', async () => {
+ await setup(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while updating labels.',
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+ });
+ });
+
+ describe('failed abuse report labels query', () => {
+ it('creates an alert', async () => {
+ createComponent({ labelsQueryHandler: labelsQueryHandlerFailure });
+ await openLabelsDropdown();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while searching for labels, please try again.',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/abuse_report/components/report_actions_spec.js b/spec/frontend/admin/abuse_report/components/report_actions_spec.js
index 6dd6d0e55c5..0e20630db14 100644
--- a/spec/frontend/admin/abuse_report/components/report_actions_spec.js
+++ b/spec/frontend/admin/abuse_report/components/report_actions_spec.js
@@ -191,31 +191,4 @@ describe('ReportActions', () => {
);
});
});
-
- describe('when moderateUserPath is not present', () => {
- it('sends the request to updatePath', async () => {
- jest.spyOn(axios, 'put');
- axiosMock.onPut(report.updatePath).replyOnce(HTTP_STATUS_OK, {});
-
- const reportWithoutModerateUserPath = { ...report };
- delete reportWithoutModerateUserPath.moderateUserPath;
-
- createComponent({ report: reportWithoutModerateUserPath });
-
- clickActionsButton();
-
- await nextTick();
-
- selectAction(params.user_action);
- selectReason(params.reason);
-
- await nextTick();
-
- submitForm();
-
- await waitForPromises();
-
- expect(axios.put).toHaveBeenCalledWith(report.updatePath, expect.any(Object));
- });
- });
});
diff --git a/spec/frontend/admin/abuse_report/components/report_details_spec.js b/spec/frontend/admin/abuse_report/components/report_details_spec.js
new file mode 100644
index 00000000000..a5c43dcb82b
--- /dev/null
+++ b/spec/frontend/admin/abuse_report/components/report_details_spec.js
@@ -0,0 +1,74 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import LabelsSelect from '~/admin/abuse_report/components/labels_select.vue';
+import ReportDetails from '~/admin/abuse_report/components/report_details.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import abuseReportQuery from '~/admin/abuse_report/components/graphql/abuse_report.query.graphql';
+import { createAlert } from '~/alert';
+import { mockAbuseReport, mockLabel1, mockReportQueryResponse } from '../mock_data';
+
+jest.mock('~/alert');
+
+Vue.use(VueApollo);
+
+describe('Report Details', () => {
+ let wrapper;
+ let fakeApollo;
+
+ const findLabelsSelect = () => wrapper.findComponent(LabelsSelect);
+
+ const abuseReportQueryHandlerSuccess = jest.fn().mockResolvedValue(mockReportQueryResponse);
+ const abuseReportQueryHandlerFailure = jest.fn().mockRejectedValue(new Error());
+
+ const createComponent = ({ abuseReportQueryHandler = abuseReportQueryHandlerSuccess } = {}) => {
+ fakeApollo = createMockApollo([[abuseReportQuery, abuseReportQueryHandler]]);
+ wrapper = shallowMount(ReportDetails, {
+ apolloProvider: fakeApollo,
+ propsData: {
+ reportId: mockAbuseReport.report.globalId,
+ },
+ });
+ };
+
+ afterEach(() => {
+ fakeApollo = null;
+ });
+
+ describe('successful abuse report query', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('triggers abuse report query', async () => {
+ await waitForPromises();
+
+ expect(abuseReportQueryHandlerSuccess).toHaveBeenCalledWith({
+ id: mockAbuseReport.report.globalId,
+ });
+ });
+
+ it('renders LabelsSelect with the fetched report', async () => {
+ expect(findLabelsSelect().props('report').labels).toEqual([]);
+
+ await waitForPromises();
+
+ expect(findLabelsSelect().props('report').labels).toEqual([mockLabel1]);
+ });
+ });
+
+ describe('failed abuse report query', () => {
+ beforeEach(async () => {
+ createComponent({ abuseReportQueryHandler: abuseReportQueryHandlerFailure });
+
+ await waitForPromises();
+ });
+
+ it('creates an alert', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while fetching labels, please try again.',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/abuse_report/components/report_header_spec.js b/spec/frontend/admin/abuse_report/components/report_header_spec.js
index f22f3af091f..6ec380f0387 100644
--- a/spec/frontend/admin/abuse_report/components/report_header_spec.js
+++ b/spec/frontend/admin/abuse_report/components/report_header_spec.js
@@ -54,37 +54,30 @@ describe('ReportHeader', () => {
});
describe.each`
- status | text | variant | className | badgeIcon
- ${STATUS_OPEN} | ${REPORT_HEADER_I18N[STATUS_OPEN]} | ${'success'} | ${'issuable-status-badge-open'} | ${'issues'}
- ${STATUS_CLOSED} | ${REPORT_HEADER_I18N[STATUS_CLOSED]} | ${'info'} | ${'issuable-status-badge-closed'} | ${'issue-closed'}
- `(
- 'rendering the report $status status badge',
- ({ status, text, variant, className, badgeIcon }) => {
- beforeEach(() => {
- createComponent({ report: { ...report, status } });
- });
-
- it(`indicates the ${status} status`, () => {
- expect(findBadge().text()).toBe(text);
- });
-
- it(`with the ${variant} variant`, () => {
- expect(findBadge().props('variant')).toBe(variant);
- });
-
- it(`with the text '${text}' as 'aria-label'`, () => {
- expect(findBadge().attributes('aria-label')).toBe(text);
- });
-
- it(`contains the ${className} class`, () => {
- expect(findBadge().element.classList).toContain(className);
- });
-
- it(`has an icon with the ${badgeIcon} name`, () => {
- expect(findIcon().props('name')).toBe(badgeIcon);
- });
- },
- );
+ status | text | variant | badgeIcon
+ ${STATUS_OPEN} | ${REPORT_HEADER_I18N[STATUS_OPEN]} | ${'success'} | ${'issues'}
+ ${STATUS_CLOSED} | ${REPORT_HEADER_I18N[STATUS_CLOSED]} | ${'info'} | ${'issue-closed'}
+ `('rendering the report $status status badge', ({ status, text, variant, badgeIcon }) => {
+ beforeEach(() => {
+ createComponent({ report: { ...report, status } });
+ });
+
+ it(`indicates the ${status} status`, () => {
+ expect(findBadge().text()).toBe(text);
+ });
+
+ it(`with the ${variant} variant`, () => {
+ expect(findBadge().props('variant')).toBe(variant);
+ });
+
+ it(`with the text '${text}' as 'aria-label'`, () => {
+ expect(findBadge().attributes('aria-label')).toBe(text);
+ });
+
+ it(`has an icon with the ${badgeIcon} name`, () => {
+ expect(findIcon().props('name')).toBe(badgeIcon);
+ });
+ });
it('renders the actions', () => {
const actionsComponent = findActions();
diff --git a/spec/frontend/admin/abuse_report/components/reported_content_spec.js b/spec/frontend/admin/abuse_report/components/reported_content_spec.js
index 9fc49f08f8c..2f16f5a7af2 100644
--- a/spec/frontend/admin/abuse_report/components/reported_content_spec.js
+++ b/spec/frontend/admin/abuse_report/components/reported_content_spec.js
@@ -14,7 +14,7 @@ const modalId = 'abuse-report-screenshot-modal';
describe('ReportedContent', () => {
let wrapper;
- const { report, reporter } = { ...mockAbuseReport };
+ const { report } = { ...mockAbuseReport };
const findScreenshotButton = () => wrapper.findByTestId('screenshot-button');
const findReportUrlButton = () => wrapper.findByTestId('report-url-button');
@@ -32,7 +32,6 @@ describe('ReportedContent', () => {
wrapper = shallowMountExtended(ReportedContent, {
propsData: {
report,
- reporter,
...props,
},
stubs: {
@@ -167,18 +166,18 @@ describe('ReportedContent', () => {
describe('rendering the card footer', () => {
it('renders the reporters avatar', () => {
- expect(findAvatar().props('src')).toBe(reporter.avatarUrl);
+ expect(findAvatar().props('src')).toBe(report.reporter.avatarUrl);
});
it('renders the users name', () => {
- expect(findCardFooter().text()).toContain(reporter.name);
+ expect(findCardFooter().text()).toContain(report.reporter.name);
});
it('renders a link to the users profile page', () => {
const link = findProfileLink();
- expect(link.attributes('href')).toBe(reporter.path);
- expect(link.text()).toBe(`@${reporter.username}`);
+ expect(link.attributes('href')).toBe(report.reporter.path);
+ expect(link.text()).toBe(`@${report.reporter.username}`);
});
it('renders the time-ago tooltip', () => {
diff --git a/spec/frontend/admin/abuse_report/components/user_details_spec.js b/spec/frontend/admin/abuse_report/components/user_details_spec.js
index ca499fbaa6e..f3d8d5bb610 100644
--- a/spec/frontend/admin/abuse_report/components/user_details_spec.js
+++ b/spec/frontend/admin/abuse_report/components/user_details_spec.js
@@ -18,7 +18,7 @@ describe('UserDetails', () => {
const findLinkFor = (attribute) => findLinkIn(findUserDetail(attribute));
const findTimeIn = (component) => component.findComponent(TimeAgoTooltip).props('time');
const findTimeFor = (attribute) => findTimeIn(findUserDetail(attribute));
- const findOtherReport = (index) => wrapper.findByTestId(`other-report-${index}`);
+ const findPastReport = (index) => wrapper.findByTestId(`past-report-${index}`);
const createComponent = (props = {}) => {
wrapper = shallowMountExtended(UserDetails, {
@@ -38,8 +38,8 @@ describe('UserDetails', () => {
describe('createdAt', () => {
it('renders the users createdAt with the correct label', () => {
- expect(findUserDetailLabel('createdAt')).toBe(USER_DETAILS_I18N.createdAt);
- expect(findTimeFor('createdAt')).toBe(user.createdAt);
+ expect(findUserDetailLabel('created-at')).toBe(USER_DETAILS_I18N.createdAt);
+ expect(findTimeFor('created-at')).toBe(user.createdAt);
});
});
@@ -67,32 +67,34 @@ describe('UserDetails', () => {
describe('creditCard', () => {
it('renders the correct label', () => {
- expect(findUserDetailLabel('creditCard')).toBe(USER_DETAILS_I18N.creditCard);
+ expect(findUserDetailLabel('credit-card-verification')).toBe(USER_DETAILS_I18N.creditCard);
});
it('renders the users name', () => {
- expect(findUserDetail('creditCard').text()).toContain(
+ expect(findUserDetail('credit-card-verification').text()).toContain(
sprintf(USER_DETAILS_I18N.registeredWith, { ...user.creditCard }),
);
- expect(findUserDetail('creditCard').text()).toContain(user.creditCard.name);
+ expect(findUserDetail('credit-card-verification').text()).toContain(user.creditCard.name);
});
describe('similar credit cards', () => {
it('renders the number of similar records', () => {
- expect(findUserDetail('creditCard').text()).toContain(
+ expect(findUserDetail('credit-card-verification').text()).toContain(
sprintf('Card matches %{similarRecordsCount} accounts', { ...user.creditCard }),
);
});
it('renders a link to the matching cards', () => {
- expect(findLinkFor('creditCard').attributes('href')).toBe(user.creditCard.cardMatchesLink);
+ expect(findLinkFor('credit-card-verification').attributes('href')).toBe(
+ user.creditCard.cardMatchesLink,
+ );
- expect(findLinkFor('creditCard').text()).toBe(
+ expect(findLinkFor('credit-card-verification').text()).toBe(
sprintf('%{similarRecordsCount} accounts', { ...user.creditCard }),
);
- expect(findLinkFor('creditCard').text()).toContain(
+ expect(findLinkFor('credit-card-verification').text()).toContain(
user.creditCard.similarRecordsCount.toString(),
);
});
@@ -105,13 +107,13 @@ describe('UserDetails', () => {
});
it('does not render the number of similar records', () => {
- expect(findUserDetail('creditCard').text()).not.toContain(
+ expect(findUserDetail('credit-card-verification').text()).not.toContain(
sprintf('Card matches %{similarRecordsCount} accounts', { ...user.creditCard }),
);
});
it('does not render a link to the matching cards', () => {
- expect(findLinkFor('creditCard').exists()).toBe(false);
+ expect(findLinkFor('credit-card-verification').exists()).toBe(false);
});
});
});
@@ -124,55 +126,55 @@ describe('UserDetails', () => {
});
it('does not render the users creditCard', () => {
- expect(findUserDetail('creditCard').exists()).toBe(false);
+ expect(findUserDetail('credit-card-verification').exists()).toBe(false);
});
});
});
describe('otherReports', () => {
it('renders the correct label', () => {
- expect(findUserDetailLabel('otherReports')).toBe(USER_DETAILS_I18N.otherReports);
+ expect(findUserDetailLabel('past-closed-reports')).toBe(USER_DETAILS_I18N.pastReports);
});
- describe.each(user.otherReports)('renders a line for report %#', (otherReport) => {
- const index = user.otherReports.indexOf(otherReport);
+ describe.each(user.pastClosedReports)('renders a line for report %#', (pastReport) => {
+ const index = user.pastClosedReports.indexOf(pastReport);
it('renders the category', () => {
- expect(findOtherReport(index).text()).toContain(
- sprintf('Reported for %{category}', { ...otherReport }),
+ expect(findPastReport(index).text()).toContain(
+ sprintf('Reported for %{category}', { ...pastReport }),
);
});
it('renders a link to the report', () => {
- expect(findLinkIn(findOtherReport(index)).attributes('href')).toBe(otherReport.reportPath);
+ expect(findLinkIn(findPastReport(index)).attributes('href')).toBe(pastReport.reportPath);
});
it('renders the time it was created', () => {
- expect(findTimeIn(findOtherReport(index))).toBe(otherReport.createdAt);
+ expect(findTimeIn(findPastReport(index))).toBe(pastReport.createdAt);
});
});
describe('when the users otherReports is empty', () => {
beforeEach(() => {
createComponent({
- user: { ...user, otherReports: [] },
+ user: { ...user, pastClosedReports: [] },
});
});
it('does not render the users otherReports', () => {
- expect(findUserDetail('otherReports').exists()).toBe(false);
+ expect(findUserDetail('past-closed-reports').exists()).toBe(false);
});
});
});
describe('normalLocation', () => {
it('renders the correct label', () => {
- expect(findUserDetailLabel('normalLocation')).toBe(USER_DETAILS_I18N.normalLocation);
+ expect(findUserDetailLabel('normal-location')).toBe(USER_DETAILS_I18N.normalLocation);
});
describe('when the users mostUsedIp is blank', () => {
it('renders the users lastSignInIp', () => {
- expect(findUserDetailValue('normalLocation')).toBe(user.lastSignInIp);
+ expect(findUserDetailValue('normal-location')).toBe(user.lastSignInIp);
});
});
@@ -186,23 +188,25 @@ describe('UserDetails', () => {
});
it('renders the users mostUsedIp', () => {
- expect(findUserDetailValue('normalLocation')).toBe(mostUsedIp);
+ expect(findUserDetailValue('normal-location')).toBe(mostUsedIp);
});
});
});
describe('lastSignInIp', () => {
it('renders the users lastSignInIp with the correct label', () => {
- expect(findUserDetailLabel('lastSignInIp')).toBe(USER_DETAILS_I18N.lastSignInIp);
- expect(findUserDetailValue('lastSignInIp')).toBe(user.lastSignInIp);
+ expect(findUserDetailLabel('last-sign-in-ip')).toBe(USER_DETAILS_I18N.lastSignInIp);
+ expect(findUserDetailValue('last-sign-in-ip')).toBe(user.lastSignInIp);
});
});
it.each(['snippets', 'groups', 'notes'])(
'renders the users %s with the correct label',
(attribute) => {
- expect(findUserDetailLabel(attribute)).toBe(USER_DETAILS_I18N[attribute]);
- expect(findUserDetailValue(attribute)).toBe(
+ const testId = `user-${attribute}-count`;
+
+ expect(findUserDetailLabel(testId)).toBe(USER_DETAILS_I18N[attribute]);
+ expect(findUserDetailValue(testId)).toBe(
USER_DETAILS_I18N[`${attribute}Count`](user[`${attribute}Count`]),
);
},
diff --git a/spec/frontend/admin/abuse_report/mock_data.js b/spec/frontend/admin/abuse_report/mock_data.js
index 8ff0c7d507a..ee61eabfa66 100644
--- a/spec/frontend/admin/abuse_report/mock_data.js
+++ b/spec/frontend/admin/abuse_report/mock_data.js
@@ -15,7 +15,7 @@ export const mockAbuseReport = {
similarRecordsCount: 2,
cardMatchesLink: '/admin/users/spamuser417/card_match',
},
- otherReports: [
+ pastClosedReports: [
{
category: 'offensive',
createdAt: '2023-02-28T10:09:54.982Z',
@@ -32,14 +32,27 @@ export const mockAbuseReport = {
snippetsCount: 0,
groupsCount: 0,
notesCount: 6,
- },
- reporter: {
- username: 'reporter',
- name: 'R Porter',
- avatarUrl: 'https://www.gravatar.com/avatar/a2579caffc69ea5d7606f9dd9d8504ba?s=80&d=identicon',
- path: '/reporter',
+ similarOpenReports: [
+ {
+ status: 'open',
+ message: 'This is obvious spam',
+ reportedAt: '2023-03-29T09:39:50.502Z',
+ category: 'spam',
+ type: 'issue',
+ content: '',
+ screenshot: null,
+ reporter: {
+ username: 'reporter 2',
+ name: 'Another Reporter',
+ avatarUrl: 'https://www.gravatar.com/avatar/anotherreporter',
+ path: '/reporter-2',
+ },
+ updatePath: '/admin/abuse_reports/28',
+ },
+ ],
},
report: {
+ globalId: 'gid://gitlab/AbuseReport/1',
status: 'open',
message: 'This is obvious spam',
reportedAt: '2023-03-29T09:39:50.502Z',
@@ -52,5 +65,66 @@ export const mockAbuseReport = {
'/uploads/-/system/abuse_report/screenshot/27/Screenshot_2023-03-30_at_16.56.37.png',
updatePath: '/admin/abuse_reports/27',
moderateUserPath: '/admin/abuse_reports/27/moderate_user',
+ reporter: {
+ username: 'reporter',
+ name: 'R Porter',
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/a2579caffc69ea5d7606f9dd9d8504ba?s=80&d=identicon',
+ path: '/reporter',
+ },
+ },
+};
+
+export const mockLabel1 = {
+ id: 'gid://gitlab/Admin::AbuseReportLabel/1',
+ title: 'Uno',
+ color: '#F0AD4E',
+ textColor: '#FFFFFF',
+ description: null,
+};
+
+export const mockLabel2 = {
+ id: 'gid://gitlab/Admin::AbuseReportLabel/2',
+ title: 'Dos',
+ color: '#F0AD4E',
+ textColor: '#FFFFFF',
+ description: null,
+};
+
+export const mockLabelsQueryResponse = {
+ data: {
+ labels: {
+ nodes: [mockLabel1, mockLabel2],
+ __typename: 'LabelConnection',
+ },
+ },
+};
+
+export const mockReportQueryResponse = {
+ data: {
+ abuseReport: {
+ labels: {
+ nodes: [mockLabel1],
+ __typename: 'LabelConnection',
+ },
+ __typename: 'AbuseReport',
+ },
+ },
+};
+
+export const mockCreateLabelResponse = {
+ data: {
+ labelCreate: {
+ label: {
+ id: 'gid://gitlab/Admin::AbuseReportLabel/1',
+ color: '#ed9121',
+ description: null,
+ title: 'abuse report label',
+ textColor: '#FFFFFF',
+ __typename: 'Label',
+ },
+ errors: [],
+ __typename: 'AbuseReportLabelCreatePayload',
+ },
},
};
diff --git a/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js b/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js
index 8482faccca0..7f915dbacb1 100644
--- a/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js
+++ b/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js
@@ -1,3 +1,4 @@
+import { GlLabel } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import setWindowLocation from 'helpers/set_window_location_helper';
import AbuseReportRow from '~/admin/abuse_reports/components/abuse_report_row.vue';
@@ -13,6 +14,7 @@ describe('AbuseReportRow', () => {
const findListItem = () => wrapper.findComponent(ListItem);
const findAbuseCategory = () => wrapper.findComponent(AbuseCategory);
+ const findLabels = () => wrapper.findAllComponents(GlLabel);
const findAbuseReportTitle = () => wrapper.findByTestId('abuse-report-title');
const findDisplayedDate = () => wrapper.findByTestId('abuse-report-date');
@@ -95,6 +97,18 @@ describe('AbuseReportRow', () => {
expect(findAbuseCategory().exists()).toBe(true);
});
+ it('renders labels', () => {
+ const labels = findLabels();
+ expect(labels).toHaveLength(2);
+
+ const { color, title } = mockAbuseReports[0].labels[0];
+ expect(labels.at(0).props()).toMatchObject({
+ backgroundColor: color,
+ title,
+ target: `${window.location.href}?${encodeURIComponent('label_name[]')}=${title}`,
+ });
+ });
+
describe('aggregated report', () => {
const mockAggregatedAbuseReport = mockAbuseReports[1];
const { reportedUser, category, count } = mockAggregatedAbuseReport;
diff --git a/spec/frontend/admin/abuse_reports/mock_data.js b/spec/frontend/admin/abuse_reports/mock_data.js
index 33a28a21cca..3101321d02d 100644
--- a/spec/frontend/admin/abuse_reports/mock_data.js
+++ b/spec/frontend/admin/abuse_reports/mock_data.js
@@ -1,3 +1,5 @@
+import { mockLabel1, mockLabel2 } from '../abuse_report/mock_data';
+
export const mockAbuseReports = [
{
category: 'spam',
@@ -7,6 +9,7 @@ export const mockAbuseReports = [
reportedUser: { name: 'Mr. Abuser' },
reportPath: '/admin/abuse_reports/1',
count: 1,
+ labels: [mockLabel1, mockLabel2],
},
{
category: 'phishing',
diff --git a/spec/frontend/admin/applications/components/__snapshots__/delete_application_spec.js.snap b/spec/frontend/admin/applications/components/__snapshots__/delete_application_spec.js.snap
index 459a113b6d1..7f068cf9ee9 100644
--- a/spec/frontend/admin/applications/components/__snapshots__/delete_application_spec.js.snap
+++ b/spec/frontend/admin/applications/components/__snapshots__/delete_application_spec.js.snap
@@ -10,7 +10,6 @@ exports[`DeleteApplication the modal component form matches the snapshot 1`] = `
type="hidden"
value="delete"
/>
-
<input
name="authenticity_token"
type="hidden"
diff --git a/spec/frontend/admin/topics/components/__snapshots__/remove_avatar_spec.js.snap b/spec/frontend/admin/topics/components/__snapshots__/remove_avatar_spec.js.snap
index 00f742c3614..e0fca2590e7 100644
--- a/spec/frontend/admin/topics/components/__snapshots__/remove_avatar_spec.js.snap
+++ b/spec/frontend/admin/topics/components/__snapshots__/remove_avatar_spec.js.snap
@@ -10,7 +10,6 @@ exports[`RemoveAvatar the modal component form matches the snapshot 1`] = `
type="hidden"
value="delete"
/>
-
<input
name="authenticity_token"
type="hidden"
diff --git a/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap b/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap
index 4237685e45c..d8157c6ff20 100644
--- a/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap
+++ b/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap
@@ -1,3 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`AssociationsListItem renders interpolated message in a \`li\` element 1`] = `"<li><strong>5</strong> groups</li>"`;
+exports[`AssociationsListItem renders interpolated message in a \`li\` element 1`] = `
+<li>
+ <strong>
+ 5
+ </strong>
+ groups
+</li>
+`;
diff --git a/spec/frontend/admin/users/components/modals/__snapshots__/delete_user_modal_spec.js.snap b/spec/frontend/admin/users/components/modals/__snapshots__/delete_user_modal_spec.js.snap
index 265569ac0e3..7f853f13363 100644
--- a/spec/frontend/admin/users/components/modals/__snapshots__/delete_user_modal_spec.js.snap
+++ b/spec/frontend/admin/users/components/modals/__snapshots__/delete_user_modal_spec.js.snap
@@ -10,13 +10,11 @@ exports[`Delete user modal renders modal with form included 1`] = `
type="hidden"
value="delete"
/>
-
<input
name="authenticity_token"
type="hidden"
value="csrf"
/>
-
<gl-form-input-stub
autocomplete="off"
autofocus=""
diff --git a/spec/frontend/admin/users/components/user_actions_spec.js b/spec/frontend/admin/users/components/user_actions_spec.js
index 69755c6142a..b44986ea7de 100644
--- a/spec/frontend/admin/users/components/user_actions_spec.js
+++ b/spec/frontend/admin/users/components/user_actions_spec.js
@@ -18,7 +18,7 @@ describe('AdminUserActions component', () => {
const findUserActions = (id) => wrapper.findByTestId(`user-actions-${id}`);
const findEditButton = (id = user.id) => findUserActions(id).find('[data-testid="edit"]');
const findActionsDropdown = (id = user.id) =>
- findUserActions(id).find('[data-testid="dropdown-toggle"]');
+ findUserActions(id).find('[data-testid="user-actions-dropdown-toggle"]');
const findDisclosureGroup = () => wrapper.findComponent(GlDisclosureDropdownGroup);
const initComponent = ({ actions = [], showButtonLabels } = {}) => {
diff --git a/spec/frontend/alerts_settings/components/__snapshots__/alerts_form_spec.js.snap b/spec/frontend/alerts_settings/components/__snapshots__/alerts_form_spec.js.snap
index 80d3676ffee..84156d6daf3 100644
--- a/spec/frontend/alerts_settings/components/__snapshots__/alerts_form_spec.js.snap
+++ b/spec/frontend/alerts_settings/components/__snapshots__/alerts_form_spec.js.snap
@@ -7,7 +7,6 @@ exports[`Alert integration settings form default state should match the default
message="Action to take when receiving an alert. %{docsLink}"
/>
</p>
-
<form>
<gl-form-group-stub
class="gl-pl-0"
@@ -16,15 +15,14 @@ exports[`Alert integration settings form default state should match the default
>
<gl-form-checkbox-stub
checked="true"
- data-qa-selector="create_incident_checkbox"
- id="2"
+ data-testid="create-incident-checkbox"
+ id="reference-0"
>
<span>
Create an incident. Incidents are created for each alert triggered.
</span>
</gl-form-checkbox-stub>
</gl-form-group-stub>
-
<gl-form-group-stub
class="col-8 col-md-9 gl-px-6"
label-for="alert-integration-settings-issue-template"
@@ -34,11 +32,9 @@ exports[`Alert integration settings form default state should match the default
>
<label
class="gl-display-inline-flex"
- for="alert-integration-settings-issue-template"
+ for="reference-1"
>
-
Incident template (optional).
-
<gl-link-stub
href="/help/user/project/description_templates#create-an-issue-template"
target="_blank"
@@ -50,14 +46,13 @@ exports[`Alert integration settings form default state should match the default
</span>
</gl-link-stub>
</label>
-
<gl-collapsible-listbox-stub
block="true"
category="primary"
- data-qa-selector="incident_templates_dropdown"
+ data-testid="incident-templates-dropdown"
headertext=""
icon=""
- id="alert-integration-settings-issue-template"
+ id="reference-1"
items="[object Object]"
noresultstext="No results found"
placement="left"
@@ -71,50 +66,45 @@ exports[`Alert integration settings form default state should match the default
variant="default"
/>
</gl-form-group-stub>
-
<gl-form-group-stub
- class="gl-pl-0 gl-mb-5"
+ class="gl-mb-5 gl-pl-0"
labeldescription=""
optionaltext="(optional)"
>
<gl-form-checkbox-stub
- data-qa-selector="enable_email_notification_checkbox"
- id="3"
+ data-testid="enable-email-notification-checkbox"
+ id="reference-2"
>
<span>
Send a single email notification to Owners and Maintainers for new alerts.
</span>
</gl-form-checkbox-stub>
</gl-form-group-stub>
-
<gl-form-group-stub
- class="gl-pl-0 gl-mb-5"
+ class="gl-mb-5 gl-pl-0"
labeldescription=""
optionaltext="(optional)"
>
<gl-form-checkbox-stub
checked="true"
- id="4"
+ id="reference-3"
>
<span>
Automatically close associated incident when a recovery alert notification resolves an alert
</span>
</gl-form-checkbox-stub>
</gl-form-group-stub>
-
<gl-button-stub
buttontextclasses=""
category="primary"
class="js-no-auto-disable"
- data-qa-selector="save_changes_button"
+ data-testid="save-changes-button"
icon=""
size="medium"
type="submit"
variant="confirm"
>
-
Save changes
-
</gl-button-stub>
</form>
</div>
diff --git a/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
index a16a03a2fc5..e01dde8f62c 100644
--- a/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
+++ b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
@@ -57,7 +57,7 @@ describe('AlertsSettingsWrapper', () => {
const findIntegrationsList = () => wrapper.findComponent(IntegrationsList);
const findLoader = () => findIntegrationsList().findComponent(GlLoadingIcon);
const findIntegrations = () => findIntegrationsList().findAll('table tbody tr');
- const findAddIntegrationBtn = () => wrapper.findByTestId('add-integration-btn');
+ const findAddIntegrationBtn = () => wrapper.findByTestId('add-integration-button');
const findAlertsSettingsForm = () => wrapper.findComponent(AlertsSettingsForm);
const findAlert = () => wrapper.findComponent(GlAlert);
diff --git a/spec/frontend/analytics/cycle_analytics/components/__snapshots__/total_time_spec.js.snap b/spec/frontend/analytics/cycle_analytics/components/__snapshots__/total_time_spec.js.snap
index 92927ef16ec..5f712ba41f4 100644
--- a/spec/frontend/analytics/cycle_analytics/components/__snapshots__/total_time_spec.js.snap
+++ b/spec/frontend/analytics/cycle_analytics/components/__snapshots__/total_time_spec.js.snap
@@ -1,28 +1,52 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`TotalTime with a blank object should render -- 1`] = `"<span> -- </span>"`;
+exports[`TotalTime with a blank object should render -- 1`] = `
+<span>
+ --
+</span>
+`;
exports[`TotalTime with a valid time object with {"days": 3, "mins": 47, "seconds": 3} 1`] = `
-"<span>
- 3 <span>days</span></span>"
+<span>
+ 3
+ <span>
+ days
+ </span>
+</span>
`;
exports[`TotalTime with a valid time object with {"hours": 7, "mins": 20, "seconds": 10} 1`] = `
-"<span>
- 7 <span>hrs</span></span>"
+<span>
+ 7
+ <span>
+ hrs
+ </span>
+</span>
`;
exports[`TotalTime with a valid time object with {"hours": 23, "mins": 10} 1`] = `
-"<span>
- 23 <span>hrs</span></span>"
+<span>
+ 23
+ <span>
+ hrs
+ </span>
+</span>
`;
exports[`TotalTime with a valid time object with {"mins": 47, "seconds": 3} 1`] = `
-"<span>
- 47 <span>mins</span></span>"
+<span>
+ 47
+ <span>
+ mins
+ </span>
+</span>
`;
exports[`TotalTime with a valid time object with {"seconds": 35} 1`] = `
-"<span>
- 35 <span>s</span></span>"
+<span>
+ 35
+ <span>
+ s
+ </span>
+</span>
`;
diff --git a/spec/frontend/api/application_settings_api_spec.js b/spec/frontend/api/application_settings_api_spec.js
new file mode 100644
index 00000000000..92a6a159913
--- /dev/null
+++ b/spec/frontend/api/application_settings_api_spec.js
@@ -0,0 +1,45 @@
+import MockAdapter from 'axios-mock-adapter';
+import * as applicationSettingsApi from '~/api/application_settings_api';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+
+describe('~/api/application_settings_api.js', () => {
+ const MOCK_SETTINGS_RES = { test_setting: 'foo' };
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ window.gon = { api_version: 'v7' };
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('getApplicationSettings', () => {
+ it('fetches application settings', () => {
+ const expectedUrl = '/api/v7/application/settings';
+ jest.spyOn(axios, 'get');
+ mock.onGet(expectedUrl).reply(HTTP_STATUS_OK, MOCK_SETTINGS_RES);
+
+ return applicationSettingsApi.getApplicationSettings().then(({ data }) => {
+ expect(data).toEqual(MOCK_SETTINGS_RES);
+ expect(axios.get).toHaveBeenCalledWith(expectedUrl);
+ });
+ });
+ });
+
+ describe('updateApplicationSettings', () => {
+ it('updates application settings', () => {
+ const expectedUrl = '/api/v7/application/settings';
+ const MOCK_REQ = { another_setting: 'bar' };
+ jest.spyOn(axios, 'put');
+ mock.onPut(expectedUrl).reply(HTTP_STATUS_OK, MOCK_SETTINGS_RES);
+
+ return applicationSettingsApi.updateApplicationSettings(MOCK_REQ).then(({ data }) => {
+ expect(data).toEqual(MOCK_SETTINGS_RES);
+ expect(axios.put).toHaveBeenCalledWith(expectedUrl, MOCK_REQ);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/artifacts_settings/components/__snapshots__/keep_latest_artifact_checkbox_spec.js.snap b/spec/frontend/artifacts_settings/components/__snapshots__/keep_latest_artifact_checkbox_spec.js.snap
index 58aee76e381..1456830b0eb 100644
--- a/spec/frontend/artifacts_settings/components/__snapshots__/keep_latest_artifact_checkbox_spec.js.snap
+++ b/spec/frontend/artifacts_settings/components/__snapshots__/keep_latest_artifact_checkbox_spec.js.snap
@@ -2,63 +2,45 @@
exports[`Keep latest artifact toggle when application keep latest artifact setting is enabled sets correct setting value in toggle with query result 1`] = `
<div>
- <!---->
-
<div
- class="gl-toggle-wrapper gl-display-flex gl-mb-0 flex-grow-1 gl-flex-direction-column"
+ class="gl-display-flex gl-flex-direction-column gl-mb-0 gl-toggle-wrapper"
data-testid="toggle-wrapper"
>
<span
- class="gl-toggle-label-container gl-mb-3"
+ class="gl-flex-shrink-0 gl-mb-3 gl-toggle-label"
+ data-testid="toggle-label"
+ id="reference-0"
+ >
+ Keep artifacts from most recent successful jobs
+ </span>
+ <button
+ aria-checked="true"
+ aria-describedby="toggle-help-2"
+ aria-labelledby="reference-0"
+ class="gl-flex-shrink-0 gl-toggle is-checked"
+ role="switch"
+ type="button"
>
<span
- class="gl-toggle-label"
- data-testid="toggle-label"
- id="toggle-label-4"
+ class="toggle-icon"
>
- Keep artifacts from most recent successful jobs
+ <gl-icon-stub
+ name="mobile-issue-close"
+ size="16"
+ />
</span>
-
- <!---->
- </span>
-
+ </button>
<span
- class="gl-toggle-switch-container"
+ class="gl-help-label"
+ data-testid="toggle-help"
+ id="reference-1"
>
- <!---->
-
- <button
- aria-checked="true"
- aria-describedby="toggle-help-2"
- aria-labelledby="toggle-label-4"
- class="gl-flex-shrink-0 gl-toggle is-checked"
- role="switch"
- type="button"
- >
- <span
- class="toggle-icon"
- >
- <gl-icon-stub
- name="mobile-issue-close"
- size="16"
- />
- </span>
- </button>
-
- <span
- class="gl-help-label"
- data-testid="toggle-help"
- id="toggle-help-2"
- >
-
The latest artifacts created by jobs in the most recent successful pipeline will be stored.
-
- <gl-link-stub
- href="/help/ci/pipelines/job_artifacts"
- >
- Learn more.
- </gl-link-stub>
- </span>
+ <gl-link-stub
+ href="/help/ci/pipelines/job_artifacts"
+ >
+ Learn more.
+ </gl-link-stub>
</span>
</div>
</div>
diff --git a/spec/frontend/avatar_helper_spec.js b/spec/frontend/avatar_helper_spec.js
deleted file mode 100644
index 91bf8e28774..00000000000
--- a/spec/frontend/avatar_helper_spec.js
+++ /dev/null
@@ -1,110 +0,0 @@
-import { TEST_HOST } from 'spec/test_constants';
-import {
- DEFAULT_SIZE_CLASS,
- IDENTICON_BG_COUNT,
- renderAvatar,
- renderIdenticon,
- getIdenticonBackgroundClass,
- getIdenticonTitle,
-} from '~/helpers/avatar_helper';
-import { getFirstCharacterCapitalized } from '~/lib/utils/text_utility';
-
-function matchAll(str) {
- return new RegExp(`^${str}$`);
-}
-
-describe('avatar_helper', () => {
- describe('getIdenticonBackgroundClass', () => {
- it('returns identicon bg class from id that is a number', () => {
- expect(getIdenticonBackgroundClass(1)).toEqual('bg2');
- });
-
- it('returns identicon bg class from id that is a string', () => {
- expect(getIdenticonBackgroundClass('1')).toEqual('bg2');
- });
-
- it('returns identicon bg class from id that is a GraphQL string id', () => {
- expect(getIdenticonBackgroundClass('gid://gitlab/Project/1')).toEqual('bg2');
- });
-
- it('returns identicon bg class from unparsable string', () => {
- expect(getIdenticonBackgroundClass('gid://gitlab/')).toEqual('bg1');
- });
-
- it(`wraps around if id is bigger than ${IDENTICON_BG_COUNT}`, () => {
- expect(getIdenticonBackgroundClass(IDENTICON_BG_COUNT + 4)).toEqual('bg5');
- expect(getIdenticonBackgroundClass(IDENTICON_BG_COUNT * 5 + 6)).toEqual('bg7');
- });
- });
-
- describe('getIdenticonTitle', () => {
- it('returns identicon title from name', () => {
- expect(getIdenticonTitle('Lorem')).toEqual('L');
- expect(getIdenticonTitle('dolar-sit-amit')).toEqual('D');
- expect(getIdenticonTitle('%-with-special-chars')).toEqual('%');
- });
-
- it('returns space if name is falsey', () => {
- expect(getIdenticonTitle('')).toEqual(' ');
- expect(getIdenticonTitle(null)).toEqual(' ');
- });
- });
-
- describe('renderIdenticon', () => {
- it('renders with the first letter as title and bg based on id', () => {
- const entity = {
- id: IDENTICON_BG_COUNT + 3,
- name: 'Xavior',
- };
- const options = {
- sizeClass: 's32',
- };
-
- const result = renderIdenticon(entity, options);
-
- expect(result).toHaveClass(`identicon ${options.sizeClass} bg4`);
- expect(result).toHaveText(matchAll(getFirstCharacterCapitalized(entity.name)));
- });
-
- it('renders with defaults, if no options are given', () => {
- const entity = {
- id: 1,
- name: 'tanuki',
- };
-
- const result = renderIdenticon(entity);
-
- expect(result).toHaveClass(`identicon ${DEFAULT_SIZE_CLASS} bg2`);
- expect(result).toHaveText(matchAll(getFirstCharacterCapitalized(entity.name)));
- });
- });
-
- describe('renderAvatar', () => {
- it('renders an image with the avatarUrl', () => {
- const avatarUrl = `${TEST_HOST}/not-real-assets/test.png`;
-
- const result = renderAvatar({
- avatar_url: avatarUrl,
- });
-
- expect(result).toBeMatchedBy('img');
- expect(result).toHaveAttr('src', avatarUrl);
- expect(result).toHaveClass(DEFAULT_SIZE_CLASS);
- });
-
- it('renders an identicon if no avatarUrl', () => {
- const entity = {
- id: 1,
- name: 'walrus',
- };
- const options = {
- sizeClass: 's16',
- };
-
- const result = renderAvatar(entity, options);
-
- expect(result).toHaveClass(`identicon ${options.sizeClass} bg2`);
- expect(result).toHaveText(matchAll(getFirstCharacterCapitalized(entity.name)));
- });
- });
-});
diff --git a/spec/frontend/behaviors/markdown/paste_markdown_table_spec.js b/spec/frontend/behaviors/markdown/paste_markdown_table_spec.js
index 7044618fd9e..154347b08b5 100644
--- a/spec/frontend/behaviors/markdown/paste_markdown_table_spec.js
+++ b/spec/frontend/behaviors/markdown/paste_markdown_table_spec.js
@@ -77,7 +77,8 @@ describe('PasteMarkdownTable', () => {
data.getData = jest.fn().mockImplementation((type) => {
if (type === 'text/html') {
return '<table><tr><td>First</td><td>Last</td><tr><td>John</td><td>Doe</td><tr><td>Jane</td><td>Doe</td></table>';
- } else if (type === 'text/plain') {
+ }
+ if (type === 'text/plain') {
return 'First\tLast\nJohn\tDoe\nJane\tDoe';
}
@@ -102,7 +103,8 @@ describe('PasteMarkdownTable', () => {
data.getData = jest.fn().mockImplementation((type) => {
if (type === 'text/html') {
return '<table><tr><td>First</td><td>Last</td><tr><td>John</td><td>Doe</td><tr><td>Jane</td><td>/td></table>';
- } else if (type === 'text/plain') {
+ }
+ if (type === 'text/plain') {
return 'First\tLast\nJohn\tDoe\nJane';
}
diff --git a/spec/frontend/blob/components/__snapshots__/blob_edit_header_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_edit_header_spec.js.snap
index 1733c4d4bb4..bd7485e9d80 100644
--- a/spec/frontend/blob/components/__snapshots__/blob_edit_header_spec.js.snap
+++ b/spec/frontend/blob/components/__snapshots__/blob_edit_header_spec.js.snap
@@ -2,10 +2,10 @@
exports[`Blob Header Editing rendering matches the snapshot 1`] = `
<div
- class="js-file-title file-title-flex-parent"
+ class="file-title-flex-parent js-file-title"
>
<div
- class="gl-display-flex gl-align-items-center gl-w-full"
+ class="gl-align-items-center gl-display-flex gl-w-full"
>
<gl-form-input-stub
class="form-control js-snippet-file-name"
@@ -14,8 +14,6 @@ exports[`Blob Header Editing rendering matches the snapshot 1`] = `
type="text"
value="foo.md"
/>
-
- <!---->
</div>
</div>
`;
diff --git a/spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap
index 4ae55f34e4c..292a0da2bfe 100644
--- a/spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap
+++ b/spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap
@@ -2,9 +2,8 @@
exports[`Blob Header Filepath rendering matches the snapshot 1`] = `
<div
- class="file-header-content d-flex align-items-center lh-100"
+ class="align-items-center d-flex file-header-content lh-100"
>
-
<file-icon-stub
aria-hidden="true"
cssclasses="gl-mr-3"
@@ -12,14 +11,12 @@ exports[`Blob Header Filepath rendering matches the snapshot 1`] = `
filename="foo/bar/dummy.md"
size="16"
/>
-
<strong
- class="file-title-name mr-1 js-blob-header-filepath"
+ class="file-title-name js-blob-header-filepath mr-1"
data-qa-selector="file_title_content"
>
foo/bar/dummy.md
</strong>
-
<clipboard-button-stub
category="tertiary"
cssclass="gl-mr-2"
@@ -30,13 +27,10 @@ exports[`Blob Header Filepath rendering matches the snapshot 1`] = `
tooltipplacement="top"
variant="default"
/>
-
<small
class="gl-mr-3"
>
a lot
</small>
-
- <!---->
</div>
`;
diff --git a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
deleted file mode 100644
index b430dc15557..00000000000
--- a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
+++ /dev/null
@@ -1,34 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Blob Header Default Actions rendering matches the snapshot 1`] = `
-<div
- class="js-file-title file-title-flex-parent"
->
- <div
- class="gl-display-flex"
- >
- <table-of-contents-stub
- class="gl-pr-2"
- />
-
- <blob-filepath-stub
- blob="[object Object]"
- showpath="true"
- />
- </div>
-
- <div
- class="gl-display-flex gl-flex-wrap file-actions"
- >
- <viewer-switcher-stub
- docicon="document"
- value="simple"
- />
-
- <default-actions-stub
- activeviewer="simple"
- rawpath="https://testing.com/flightjs/flight/snippets/51/raw"
- />
- </div>
-</div>
-`;
diff --git a/spec/frontend/blob/components/blob_header_spec.js b/spec/frontend/blob/components/blob_header_spec.js
index 47e09bb38bc..922d6a0211b 100644
--- a/spec/frontend/blob/components/blob_header_spec.js
+++ b/spec/frontend/blob/components/blob_header_spec.js
@@ -1,4 +1,6 @@
+import Vue from 'vue';
import { shallowMount, mount } from '@vue/test-utils';
+import VueApollo from 'vue-apollo';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import BlobHeader from '~/blob/components/blob_header.vue';
import DefaultActions from '~/blob/components/blob_header_default_actions.vue';
@@ -10,8 +12,14 @@ import {
SIMPLE_BLOB_VIEWER_TITLE,
} from '~/blob/components/constants';
import TableContents from '~/blob/components/table_contents.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import WebIdeLink from 'ee_else_ce/vue_shared/components/web_ide_link.vue';
+import userInfoQuery from '~/blob/queries/user_info.query.graphql';
+import applicationInfoQuery from '~/blob/queries/application_info.query.graphql';
+import { Blob, userInfoMock, applicationInfoMock } from './mock_data';
-import { Blob } from './mock_data';
+Vue.use(VueApollo);
describe('Blob Header Default Actions', () => {
let wrapper;
@@ -26,14 +34,29 @@ describe('Blob Header Default Actions', () => {
const findBlobFilePath = () => wrapper.findComponent(BlobFilepath);
const findRichTextEditorBtn = () => wrapper.findByLabelText(RICH_BLOB_VIEWER_TITLE);
const findSimpleTextEditorBtn = () => wrapper.findByLabelText(SIMPLE_BLOB_VIEWER_TITLE);
+ const findWebIdeLink = () => wrapper.findComponent(WebIdeLink);
- function createComponent({
+ async function createComponent({
blobProps = {},
options = {},
propsData = {},
mountFn = shallowMount,
} = {}) {
+ const userInfoMockResolver = jest.fn().mockResolvedValue({
+ data: { ...userInfoMock },
+ });
+
+ const applicationInfoMockResolver = jest.fn().mockResolvedValue({
+ data: { ...applicationInfoMock },
+ });
+
+ const fakeApollo = createMockApollo([
+ [userInfoQuery, userInfoMockResolver],
+ [applicationInfoQuery, applicationInfoMockResolver],
+ ]);
+
wrapper = mountFn(BlobHeader, {
+ apolloProvider: fakeApollo,
provide: {
...defaultProvide,
},
@@ -43,12 +66,40 @@ describe('Blob Header Default Actions', () => {
},
...options,
});
+
+ await waitForPromises();
}
describe('rendering', () => {
- it('matches the snapshot', () => {
- createComponent();
- expect(wrapper.element).toMatchSnapshot();
+ describe('WebIdeLink component', () => {
+ it('renders the WebIdeLink component with the correct props', async () => {
+ const { ideEditPath, editBlobPath, gitpodBlobUrl, pipelineEditorPath } = Blob;
+ const showForkSuggestion = false;
+ await createComponent({ propsData: { showForkSuggestion } });
+
+ expect(findWebIdeLink().props()).toMatchObject({
+ showEditButton: true,
+ editUrl: editBlobPath,
+ webIdeUrl: ideEditPath,
+ needsToFork: showForkSuggestion,
+ showPipelineEditorButton: Boolean(pipelineEditorPath),
+ pipelineEditorUrl: pipelineEditorPath,
+ gitpodUrl: gitpodBlobUrl,
+ showGitpodButton: applicationInfoMock.gitpodEnabled,
+ gitpodEnabled: userInfoMock.currentUser.gitpodEnabled,
+ userPreferencesGitpodPath: userInfoMock.currentUser.preferencesGitpodPath,
+ userProfileEnableGitpodPath: userInfoMock.currentUser.profileEnableGitpodPath,
+ });
+ });
+
+ it.each([[{ archived: true }], [{ editBlobPath: null }]])(
+ 'does not render the WebIdeLink component when blob is archived or does not have an edit path',
+ (blobProps) => {
+ createComponent({ blobProps });
+
+ expect(findWebIdeLink().exists()).toBe(false);
+ },
+ );
});
describe('default render', () => {
diff --git a/spec/frontend/blob/components/mock_data.js b/spec/frontend/blob/components/mock_data.js
index 6ecf5091591..7ed526fba97 100644
--- a/spec/frontend/blob/components/mock_data.js
+++ b/spec/frontend/blob/components/mock_data.js
@@ -30,6 +30,10 @@ export const Blob = {
richViewer: {
...RichViewerMock,
},
+ ideEditPath: 'ide/edit',
+ editBlobPath: 'edit/blob',
+ gitpodBlobUrl: 'gitpod/blob/url',
+ pipelineEditorPath: 'pipeline/editor/path',
};
export const BinaryBlob = {
@@ -60,3 +64,14 @@ export const SimpleBlobContentMock = {
export const mockEnvironmentName = 'my.testing.environment';
export const mockEnvironmentPath = 'https://my.testing.environment';
+
+export const userInfoMock = {
+ currentUser: {
+ id: '123',
+ gitpodEnabled: true,
+ preferencesGitpodPath: '/-/profile/preferences#user_gitpod_enabled',
+ profileEnableGitpodPath: '/-/profile?user%5Bgitpod_enabled%5D=true',
+ },
+};
+
+export const applicationInfoMock = { gitpodEnabled: true };
diff --git a/spec/frontend/blob/line_highlighter_spec.js b/spec/frontend/blob/line_highlighter_spec.js
index de39a8f688a..c7a86d6230a 100644
--- a/spec/frontend/blob/line_highlighter_spec.js
+++ b/spec/frontend/blob/line_highlighter_spec.js
@@ -72,6 +72,15 @@ describe('LineHighlighter', () => {
expect(utils.scrollToElement).toHaveBeenCalledWith('#L5', expect.anything());
});
+ it('does not scroll to the first highlighted line when disableScroll is `true`', () => {
+ jest.spyOn(utils, 'scrollToElement');
+ const highlighter = new LineHighlighter();
+ const scrollEnabled = false;
+ highlighter.highlightHash('#L5-25', scrollEnabled);
+
+ expect(utils.scrollToElement).not.toHaveBeenCalled();
+ });
+
it('discards click events', () => {
const clickSpy = jest.fn();
diff --git a/spec/frontend/blob/openapi/index_spec.js b/spec/frontend/blob/openapi/index_spec.js
index 95e86398ab8..c96a021550d 100644
--- a/spec/frontend/blob/openapi/index_spec.js
+++ b/spec/frontend/blob/openapi/index_spec.js
@@ -4,16 +4,16 @@ import { TEST_HOST } from 'helpers/test_constants';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import renderOpenApi from '~/blob/openapi';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import setWindowLocation from 'helpers/set_window_location_helper';
describe('OpenAPI blob viewer', () => {
const id = 'js-openapi-viewer';
const mockEndpoint = 'some/endpoint';
let mock;
- beforeEach(async () => {
+ beforeEach(() => {
setHTMLFixture(`<div id="${id}" data-endpoint="${mockEndpoint}"></div>`);
mock = new MockAdapter(axios).onGet().reply(HTTP_STATUS_OK);
- await renderOpenApi();
});
afterEach(() => {
@@ -21,9 +21,28 @@ describe('OpenAPI blob viewer', () => {
mock.restore();
});
- it('initializes SwaggerUI with the correct configuration', () => {
- expect(document.body.innerHTML).toContain(
- `<iframe src="${TEST_HOST}/-/sandbox/swagger" sandbox="allow-scripts allow-popups allow-forms" frameborder="0" width="100%" height="1000"></iframe>`,
- );
+ describe('without config options', () => {
+ beforeEach(async () => {
+ await renderOpenApi();
+ });
+
+ it('initializes SwaggerUI without config options', () => {
+ expect(document.body.innerHTML).toContain(
+ `<iframe src="${TEST_HOST}/-/sandbox/swagger" sandbox="allow-scripts allow-popups allow-forms" frameborder="0" width="100%" height="1000"></iframe>`,
+ );
+ });
+ });
+
+ describe('with config options', () => {
+ beforeEach(async () => {
+ setWindowLocation('?displayOperationId=true');
+ await renderOpenApi();
+ });
+
+ it('initializes SwaggerUI with the correct config options', () => {
+ expect(document.body.innerHTML).toContain(
+ `<iframe src="${TEST_HOST}/-/sandbox/swagger?displayOperationId=true" sandbox="allow-scripts allow-popups allow-forms" frameborder="0" width="100%" height="1000"></iframe>`,
+ );
+ });
});
});
diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js
index 1740676161f..95b5712bab0 100644
--- a/spec/frontend/boards/board_card_inner_spec.js
+++ b/spec/frontend/boards/board_card_inner_spec.js
@@ -91,6 +91,7 @@ describe('Board card component', () => {
rootPath: '/',
scopedLabelsAvailable: false,
isEpicBoard,
+ allowSubEpics: isEpicBoard,
issuableType: TYPE_ISSUE,
isGroupBoard,
isApolloBoard: false,
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js
index 167efb94fcc..f0d40af94fe 100644
--- a/spec/frontend/boards/components/board_card_spec.js
+++ b/spec/frontend/boards/components/board_card_spec.js
@@ -72,6 +72,7 @@ describe('Board card', () => {
issuableType: 'issue',
isGroupBoard: true,
disabled: false,
+ allowSubEpics: false,
isApolloBoard: false,
...provide,
},
diff --git a/spec/frontend/boards/components/boards_selector_spec.js b/spec/frontend/boards/components/boards_selector_spec.js
index b17a5589c07..fa18b47cf54 100644
--- a/spec/frontend/boards/components/boards_selector_spec.js
+++ b/spec/frontend/boards/components/boards_selector_spec.js
@@ -87,6 +87,7 @@ describe('BoardsSelector', () => {
isGroupBoard = false,
isProjectBoard = false,
provide = {},
+ props = {},
} = {}) => {
fakeApollo = createMockApollo([
[projectBoardsQuery, projectBoardsQueryHandler],
@@ -100,6 +101,7 @@ describe('BoardsSelector', () => {
apolloProvider: fakeApollo,
propsData: {
throttleDuration,
+ ...props,
},
attachTo: document.body,
provide: {
@@ -307,4 +309,14 @@ describe('BoardsSelector', () => {
});
});
});
+
+ describe('Apollo boards', () => {
+ it('displays loading state of dropdown while current board is being fetched', () => {
+ createComponent({
+ props: { isCurrentBoardLoading: true },
+ provide: { isApolloBoard: true },
+ });
+ expect(findDropdown().props('loading')).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/boards/components/issue_board_filtered_search_spec.js b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
index 5b5b68d5dbe..16ad54f0854 100644
--- a/spec/frontend/boards/components/issue_board_filtered_search_spec.js
+++ b/spec/frontend/boards/components/issue_board_filtered_search_spec.js
@@ -61,12 +61,7 @@ describe('IssueBoardFilter', () => {
({ isSignedIn }) => {
createComponent({ isSignedIn });
- const tokens = mockTokens(
- fetchLabelsSpy,
- fetchUsersSpy,
- wrapper.vm.fetchMilestones,
- isSignedIn,
- );
+ const tokens = mockTokens(fetchLabelsSpy, fetchUsersSpy, isSignedIn);
expect(findBoardsFilteredSearch().props('tokens')).toEqual(orderBy(tokens, ['title']));
},
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js
index 1b526e6fbec..f354067e226 100644
--- a/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_title_spec.js
@@ -8,6 +8,7 @@ import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.v
import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
import { createStore } from '~/boards/stores';
import issueSetTitleMutation from '~/boards/graphql/issue_set_title.mutation.graphql';
+import * as cacheUpdates from '~/boards/graphql/cache_updates';
import updateEpicTitleMutation from '~/sidebar/queries/update_epic_title.mutation.graphql';
import { updateIssueTitleResponse, updateEpicTitleResponse } from '../../mock_data';
@@ -40,6 +41,10 @@ describe('BoardSidebarTitle', () => {
.fn()
.mockResolvedValue(updateEpicTitleResponse);
+ beforeEach(() => {
+ cacheUpdates.setError = jest.fn();
+ });
+
afterEach(() => {
localStorage.clear();
store = null;
@@ -207,8 +212,7 @@ describe('BoardSidebarTitle', () => {
it('collapses sidebar and renders former item title', () => {
expect(findCollapsed().isVisible()).toBe(true);
expect(findTitle().text()).toContain(TEST_ISSUE_B.title);
- expect(storeDispatch).toHaveBeenCalledWith(
- 'setError',
+ expect(cacheUpdates.setError).toHaveBeenCalledWith(
expect.objectContaining({ message: 'An error occurred when updating the title' }),
);
});
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 8f57a6eb7da..dfcdb4c05d0 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -827,7 +827,7 @@ export const mockConfidentialToken = {
],
};
-export const mockTokens = (fetchLabels, fetchUsers, fetchMilestones, isSignedIn) => [
+export const mockTokens = (fetchLabels, fetchUsers, isSignedIn) => [
{
icon: 'user',
title: TOKEN_TITLE_ASSIGNEE,
@@ -870,7 +870,8 @@ export const mockTokens = (fetchLabels, fetchUsers, fetchMilestones, isSignedIn)
shouldSkipSort: true,
token: MilestoneToken,
unique: true,
- fetchMilestones,
+ fullPath: 'gitlab-org',
+ isProject: false,
},
{
icon: 'issues',
diff --git a/spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap b/spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap
index 4da56a865d5..ee8031f2475 100644
--- a/spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap
+++ b/spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap
@@ -16,102 +16,82 @@ exports[`Delete merged branches component Delete merged branches confirmation mo
toggletext=""
variant="default"
>
-
<ul
aria-labelledby="dropdown-toggle-btn-25"
class="gl-new-dropdown-contents"
data-testid="disclosure-content"
- id="disclosure-26"
+ id="reference-0"
tabindex="-1"
>
<gl-disclosure-dropdown-item-stub
item="[object Object]"
/>
</ul>
-
</gl-base-dropdown-stub>
-
<b-button-stub
- class="gl-display-block gl-md-display-none! gl-button btn-danger-secondary"
+ class="btn-danger-secondary gl-button gl-display-block gl-md-display-none!"
data-testid="delete-merged-branches-button"
size="md"
tag="button"
type="button"
variant="danger"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- Delete merged branches
-
+ Delete merged branches
</span>
</b-button-stub>
-
<div>
<form
action="/namespace/project/-/merged_branches"
method="post"
>
<p>
- You are about to
+ You are about to
<strong>
delete all branches
</strong>
- that were merged into
+ that were merged into
<code>
master
</code>
.
</p>
-
<p>
-
This may include merged branches that are not visible on the current screen.
-
</p>
-
<p>
-
A branch won't be deleted if it is protected or associated with an open merge request.
-
</p>
-
<p>
- This bulk action is
+ This bulk action is
<strong>
permanent and cannot be undone or recovered
</strong>
.
</p>
-
<p>
- Plese type the following to confirm:
+ Plese type the following to confirm:
<code>
delete
</code>
- .
+ .
<b-form-input-stub
aria-labelledby="input-label"
autocomplete="off"
- class="gl-form-input gl-mt-2 gl-form-input-sm"
+ class="gl-form-input gl-form-input-sm gl-mt-2"
debounce="0"
formatter="[Function]"
type="text"
value=""
/>
</p>
-
<input
name="_method"
type="hidden"
value="delete"
/>
-
<input
name="authenticity_token"
type="hidden"
@@ -119,7 +99,7 @@ exports[`Delete merged branches component Delete merged branches confirmation mo
/>
</form>
<div
- class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap gl-m-0 gl-mr-3"
+ class="gl-display-flex gl-flex-direction-row gl-flex-wrap gl-justify-content-end gl-m-0 gl-mr-3"
>
<b-button-stub
class="gl-button"
@@ -129,19 +109,12 @@ exports[`Delete merged branches component Delete merged branches confirmation mo
type="button"
variant="default"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
Cancel
-
</span>
</b-button-stub>
-
<b-button-stub
class="gl-button"
data-testid="delete-merged-branches-confirmation-button"
@@ -151,10 +124,6 @@ exports[`Delete merged branches component Delete merged branches confirmation mo
type="button"
variant="danger"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
diff --git a/spec/frontend/branches/components/__snapshots__/divergence_graph_spec.js.snap b/spec/frontend/branches/components/__snapshots__/divergence_graph_spec.js.snap
index 2afca66b0c1..81a57653f61 100644
--- a/spec/frontend/branches/components/__snapshots__/divergence_graph_spec.js.snap
+++ b/spec/frontend/branches/components/__snapshots__/divergence_graph_spec.js.snap
@@ -2,7 +2,7 @@
exports[`Branch divergence graph component renders ahead and behind count 1`] = `
<div
- class="divergence-graph px-2 d-none d-md-block"
+ class="d-md-block d-none divergence-graph px-2"
title="10 commits behind main, 10 commits ahead"
>
<graph-bar-stub
@@ -10,11 +10,9 @@ exports[`Branch divergence graph component renders ahead and behind count 1`] =
maxcommits="100"
position="left"
/>
-
<div
- class="graph-separator float-left mt-1"
+ class="float-left graph-separator mt-1"
/>
-
<graph-bar-stub
count="10"
maxcommits="100"
@@ -25,7 +23,7 @@ exports[`Branch divergence graph component renders ahead and behind count 1`] =
exports[`Branch divergence graph component renders distance count 1`] = `
<div
- class="divergence-graph px-2 d-none d-md-block"
+ class="d-md-block d-none divergence-graph px-2"
title="More than 900 commits different with main"
>
<graph-bar-stub
diff --git a/spec/frontend/ci/admin/jobs_table/admin_job_table_app_spec.js b/spec/frontend/ci/admin/jobs_table/admin_job_table_app_spec.js
new file mode 100644
index 00000000000..d14b78d2f4d
--- /dev/null
+++ b/spec/frontend/ci/admin/jobs_table/admin_job_table_app_spec.js
@@ -0,0 +1,445 @@
+import { GlLoadingIcon, GlEmptyState, GlAlert, GlIntersectionObserver } from '@gitlab/ui';
+import { mount, shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import JobsTableTabs from '~/ci/jobs_page/components/jobs_table_tabs.vue';
+import JobsSkeletonLoader from '~/ci/admin/jobs_table/components/jobs_skeleton_loader.vue';
+import getAllJobsQuery from '~/ci/admin/jobs_table/graphql/queries/get_all_jobs.query.graphql';
+import getAllJobsCount from '~/ci/admin/jobs_table/graphql/queries/get_all_jobs_count.query.graphql';
+import getCancelableJobsQuery from '~/ci/admin/jobs_table/graphql/queries/get_cancelable_jobs_count.query.graphql';
+import AdminJobsTableApp from '~/ci/admin/jobs_table/admin_jobs_table_app.vue';
+import CancelJobs from '~/ci/admin/jobs_table/components/cancel_jobs.vue';
+import JobsTable from '~/ci/jobs_page/components/jobs_table.vue';
+import { createAlert } from '~/alert';
+import { TEST_HOST } from 'spec/test_constants';
+import JobsFilteredSearch from '~/ci/common/private/jobs_filtered_search/app.vue';
+import * as urlUtils from '~/lib/utils/url_utility';
+import {
+ JOBS_FETCH_ERROR_MSG,
+ CANCELABLE_JOBS_ERROR_MSG,
+ LOADING_ARIA_LABEL,
+ RAW_TEXT_WARNING_ADMIN,
+ JOBS_COUNT_ERROR_MESSAGE,
+} from '~/ci/admin/jobs_table/constants';
+import { TOKEN_TYPE_JOBS_RUNNER_TYPE } from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ mockAllJobsResponsePaginated,
+ mockCancelableJobsCountResponse,
+ mockAllJobsResponseEmpty,
+ statuses,
+ mockFailedSearchToken,
+ mockAllJobsCountResponse,
+} from 'jest/ci/jobs_mock_data';
+
+Vue.use(VueApollo);
+
+jest.mock('~/alert');
+
+describe('Job table app', () => {
+ let wrapper;
+
+ const successHandler = jest.fn().mockResolvedValue(mockAllJobsResponsePaginated);
+ const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+ const cancelHandler = jest.fn().mockResolvedValue(mockCancelableJobsCountResponse);
+ const emptyHandler = jest.fn().mockResolvedValue(mockAllJobsResponseEmpty);
+ const countSuccessHandler = jest.fn().mockResolvedValue(mockAllJobsCountResponse);
+
+ const findSkeletonLoader = () => wrapper.findComponent(JobsSkeletonLoader);
+ const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
+ const findTable = () => wrapper.findComponent(JobsTable);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findTabs = () => wrapper.findComponent(JobsTableTabs);
+ const findCancelJobsButton = () => wrapper.findComponent(CancelJobs);
+ const findFilteredSearch = () => wrapper.findComponent(JobsFilteredSearch);
+
+ const mockSearchTokenRunnerType = {
+ type: TOKEN_TYPE_JOBS_RUNNER_TYPE,
+ value: { data: 'INSTANCE_TYPE', operator: '=' },
+ };
+
+ const triggerInfiniteScroll = () =>
+ wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
+
+ const createMockApolloProvider = (handler, cancelableHandler, countHandler) => {
+ const requestHandlers = [
+ [getAllJobsQuery, handler],
+ [getCancelableJobsQuery, cancelableHandler],
+ [getAllJobsCount, countHandler],
+ ];
+
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = ({
+ handler = successHandler,
+ cancelableHandler = cancelHandler,
+ countHandler = countSuccessHandler,
+ mountFn = shallowMount,
+ data = {},
+ provideOptions = {},
+ } = {}) => {
+ wrapper = mountFn(AdminJobsTableApp, {
+ data() {
+ return {
+ ...data,
+ };
+ },
+ provide: {
+ jobStatuses: statuses,
+ glFeatures: { adminJobsFilterRunnerType: true },
+ ...provideOptions,
+ },
+ apolloProvider: createMockApolloProvider(handler, cancelableHandler, countHandler),
+ });
+ };
+
+ describe('loading state', () => {
+ it('should display skeleton loader when loading', () => {
+ createComponent();
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ expect(findTable().exists()).toBe(false);
+ expect(findLoadingSpinner().exists()).toBe(false);
+ });
+
+ it('when switching tabs only the skeleton loader should show', () => {
+ createComponent();
+
+ findTabs().vm.$emit('fetchJobsByStatus', null);
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ expect(findLoadingSpinner().exists()).toBe(false);
+ });
+ });
+
+ describe('loaded state', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('should display the jobs table with data', () => {
+ expect(findTable().exists()).toBe(true);
+ expect(findSkeletonLoader().exists()).toBe(false);
+ expect(findLoadingSpinner().exists()).toBe(false);
+ });
+
+ it('should refetch jobs query on fetchJobsByStatus event', async () => {
+ expect(successHandler).toHaveBeenCalledTimes(1);
+
+ await findTabs().vm.$emit('fetchJobsByStatus');
+
+ expect(successHandler).toHaveBeenCalledTimes(2);
+ });
+
+ it('avoids refetch jobs query when scope has not changed', async () => {
+ expect(successHandler).toHaveBeenCalledTimes(1);
+
+ await findTabs().vm.$emit('fetchJobsByStatus', null);
+
+ expect(successHandler).toHaveBeenCalledTimes(1);
+ });
+
+ it('should refetch jobs count query when the amount jobs and count do not match', async () => {
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+
+ // after applying filter a new count is fetched
+ findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(successHandler).toHaveBeenCalledTimes(2);
+
+ // tab is switched to `finished`, no count
+ await findTabs().vm.$emit('fetchJobsByStatus', ['FAILED', 'SUCCESS', 'CANCELED']);
+
+ // tab is switched back to `all`, the old filter count has to be overwritten with new count
+ await findTabs().vm.$emit('fetchJobsByStatus', null);
+
+ expect(successHandler).toHaveBeenCalledTimes(4);
+ });
+
+ describe('when infinite scrolling is triggered', () => {
+ it('does not display a skeleton loader', () => {
+ triggerInfiniteScroll();
+
+ expect(findSkeletonLoader().exists()).toBe(false);
+ });
+
+ it('handles infinite scrolling by calling fetch more', async () => {
+ triggerInfiniteScroll();
+
+ await nextTick();
+
+ const pageSize = 50;
+
+ expect(findLoadingSpinner().exists()).toBe(true);
+ expect(findLoadingSpinner().attributes('aria-label')).toBe(LOADING_ARIA_LABEL);
+
+ await waitForPromises();
+
+ expect(findLoadingSpinner().exists()).toBe(false);
+
+ expect(successHandler).toHaveBeenLastCalledWith({
+ first: pageSize,
+ after: mockAllJobsResponsePaginated.data.jobs.pageInfo.endCursor,
+ });
+ });
+ });
+ });
+
+ describe('empty state', () => {
+ it('should display empty state if there are no jobs and tab scope is null', async () => {
+ createComponent({ handler: emptyHandler, mountFn: mount });
+
+ await waitForPromises();
+
+ expect(findEmptyState().exists()).toBe(true);
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('should not display empty state if there are jobs and tab scope is not null', async () => {
+ createComponent({ handler: successHandler, mountFn: mount });
+
+ await waitForPromises();
+
+ expect(findEmptyState().exists()).toBe(false);
+ expect(findTable().exists()).toBe(true);
+ });
+ });
+
+ describe('error state', () => {
+ it('should show an alert if there is an error fetching the jobs data', async () => {
+ createComponent({ handler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe(JOBS_FETCH_ERROR_MSG);
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('should show an alert if there is an error fetching the jobs count data', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe(JOBS_COUNT_ERROR_MESSAGE);
+ });
+
+ it('should show an alert if there is an error fetching the cancelable jobs data', async () => {
+ createComponent({ handler: successHandler, cancelableHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe(CANCELABLE_JOBS_ERROR_MSG);
+ });
+
+ it('jobs table should still load if count query fails', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('jobs table should still load if cancel query fails', async () => {
+ createComponent({ handler: successHandler, cancelableHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('jobs count should be zero if count query fails', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findTabs().props('allJobsCount')).toBe(0);
+ });
+
+ it('cancel button should be hidden if query fails', async () => {
+ createComponent({ handler: successHandler, cancelableHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findCancelJobsButton().exists()).toBe(false);
+ });
+ });
+
+ describe('cancel jobs button', () => {
+ it('should display cancel all jobs button', async () => {
+ createComponent({ cancelableHandler: cancelHandler, mountFn: mount });
+
+ await waitForPromises();
+
+ expect(findCancelJobsButton().exists()).toBe(true);
+ });
+
+ it('should not display cancel all jobs button', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findCancelJobsButton().exists()).toBe(false);
+ });
+ });
+
+ describe('filtered search', () => {
+ it('should display filtered search', () => {
+ createComponent();
+
+ expect(findFilteredSearch().exists()).toBe(true);
+ });
+
+ // this test should be updated once BE supports tab and filtered search filtering
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/356210
+ it.each`
+ scope | shouldDisplay
+ ${null} | ${true}
+ ${['FAILED', 'SUCCESS', 'CANCELED']} | ${false}
+ `(
+ 'with tab scope $scope the filtered search displays $shouldDisplay',
+ async ({ scope, shouldDisplay }) => {
+ createComponent();
+
+ await waitForPromises();
+
+ await findTabs().vm.$emit('fetchJobsByStatus', scope);
+
+ expect(findFilteredSearch().exists()).toBe(shouldDisplay);
+ },
+ );
+
+ describe.each`
+ searchTokens | expectedQueryParams
+ ${[]} | ${{ runnerTypes: null, statuses: null }}
+ ${[mockFailedSearchToken]} | ${{ runnerTypes: null, statuses: 'FAILED' }}
+ ${[mockFailedSearchToken, mockSearchTokenRunnerType]} | ${{ runnerTypes: 'INSTANCE_TYPE', statuses: 'FAILED' }}
+ `('when filtering jobs by searchTokens', ({ searchTokens, expectedQueryParams }) => {
+ it(`refetches jobs query including filters ${JSON.stringify(
+ expectedQueryParams,
+ )}`, async () => {
+ createComponent();
+
+ expect(successHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', searchTokens);
+
+ expect(successHandler).toHaveBeenCalledTimes(2);
+ expect(successHandler).toHaveBeenNthCalledWith(2, { first: 50, ...expectedQueryParams });
+ });
+
+ it(`refetches jobs count query including filters ${JSON.stringify(
+ expectedQueryParams,
+ )}`, async () => {
+ createComponent();
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', searchTokens);
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(2);
+ expect(countSuccessHandler).toHaveBeenNthCalledWith(2, expectedQueryParams);
+ });
+ });
+
+ it('shows raw text warning when user inputs raw text', async () => {
+ const expectedWarning = {
+ message: RAW_TEXT_WARNING_ADMIN,
+ type: 'warning',
+ };
+
+ createComponent();
+
+ expect(successHandler).toHaveBeenCalledTimes(1);
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', ['raw text']);
+
+ expect(createAlert).toHaveBeenCalledWith(expectedWarning);
+ expect(successHandler).toHaveBeenCalledTimes(1);
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+ });
+
+ it('updates URL query string when filtering jobs by status', async () => {
+ createComponent();
+
+ jest.spyOn(urlUtils, 'updateHistory');
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(urlUtils.updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/?statuses=FAILED`,
+ });
+ });
+
+ it('resets query param after clearing tokens', () => {
+ createComponent();
+
+ jest.spyOn(urlUtils, 'updateHistory');
+
+ findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(successHandler).toHaveBeenCalledWith({
+ first: 50,
+ statuses: 'FAILED',
+ runnerTypes: null,
+ });
+ expect(urlUtils.updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/?statuses=FAILED`,
+ });
+
+ findFilteredSearch().vm.$emit('filterJobsBySearch', []);
+
+ expect(urlUtils.updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/`,
+ });
+
+ expect(successHandler).toHaveBeenCalledWith({
+ first: 50,
+ statuses: null,
+ runnerTypes: null,
+ });
+ });
+
+ describe('when feature flag `adminJobsFilterRunnerType` is disabled', () => {
+ const provideOptions = { glFeatures: { adminJobsFilterRunnerType: false } };
+
+ describe.each`
+ searchTokens | expectedQueryParams
+ ${[]} | ${{ statuses: null }}
+ ${[mockFailedSearchToken]} | ${{ statuses: 'FAILED' }}
+ ${[mockFailedSearchToken, mockSearchTokenRunnerType]} | ${{ statuses: 'FAILED' }}
+ `('when filtering jobs by searchTokens', ({ searchTokens, expectedQueryParams }) => {
+ it(`refetches jobs query including filters ${JSON.stringify(
+ expectedQueryParams,
+ )}`, async () => {
+ createComponent({ provideOptions });
+
+ expect(successHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', searchTokens);
+
+ expect(successHandler).toHaveBeenCalledTimes(2);
+ expect(successHandler).toHaveBeenNthCalledWith(2, { first: 50, ...expectedQueryParams });
+ });
+
+ it(`refetches jobs count query including filters ${JSON.stringify(
+ expectedQueryParams,
+ )}`, async () => {
+ createComponent({ provideOptions });
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', searchTokens);
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(2);
+ expect(countSuccessHandler).toHaveBeenNthCalledWith(2, expectedQueryParams);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/admin/jobs_table/components/cancel_jobs_modal_spec.js b/spec/frontend/ci/admin/jobs_table/components/cancel_jobs_modal_spec.js
new file mode 100644
index 00000000000..c3d1d0266f4
--- /dev/null
+++ b/spec/frontend/ci/admin/jobs_table/components/cancel_jobs_modal_spec.js
@@ -0,0 +1,66 @@
+import { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
+import { TEST_HOST } from 'helpers/test_constants';
+import axios from '~/lib/utils/axios_utils';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import CancelJobsModal from '~/ci/admin/jobs_table/components/cancel_jobs_modal.vue';
+import { setVueErrorHandler } from '../../../../__helpers__/set_vue_error_handler';
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ redirectTo: jest.fn(),
+}));
+
+describe('Cancel jobs modal', () => {
+ const props = {
+ url: `${TEST_HOST}/cancel_jobs_modal.vue/cancelAll`,
+ modalId: 'cancel-jobs-modal',
+ };
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = mount(CancelJobsModal, { propsData: props });
+ });
+
+ describe('on submit', () => {
+ it('cancels jobs and redirects to overview page', async () => {
+ const responseURL = `${TEST_HOST}/cancel_jobs_modal.vue/jobs`;
+ // TODO: We can't use axios-mock-adapter because our current version
+ // does not support responseURL
+ //
+ // see https://gitlab.com/gitlab-org/gitlab/-/issues/375308 for details
+ jest.spyOn(axios, 'post').mockImplementation((url) => {
+ expect(url).toBe(props.url);
+ return Promise.resolve({
+ request: {
+ responseURL,
+ },
+ });
+ });
+
+ wrapper.findComponent(GlModal).vm.$emit('primary');
+ await nextTick();
+
+ expect(redirectTo).toHaveBeenCalledWith(responseURL); // eslint-disable-line import/no-deprecated
+ });
+
+ it('displays error if canceling jobs failed', async () => {
+ const dummyError = new Error('canceling jobs failed');
+ // TODO: We can't use axios-mock-adapter because our current version
+ // does not support responseURL
+ //
+ // see https://gitlab.com/gitlab-org/gitlab/-/issues/375308 for details
+ jest.spyOn(axios, 'post').mockImplementation((url) => {
+ expect(url).toBe(props.url);
+ return Promise.reject(dummyError);
+ });
+
+ setVueErrorHandler({ instance: wrapper.vm, handler: () => {} }); // silencing thrown error
+ wrapper.findComponent(GlModal).vm.$emit('primary');
+ await nextTick();
+
+ expect(redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
+ });
+ });
+});
diff --git a/spec/frontend/ci/admin/jobs_table/components/cancel_jobs_spec.js b/spec/frontend/ci/admin/jobs_table/components/cancel_jobs_spec.js
new file mode 100644
index 00000000000..2884e4ed521
--- /dev/null
+++ b/spec/frontend/ci/admin/jobs_table/components/cancel_jobs_spec.js
@@ -0,0 +1,54 @@
+import { GlButton } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { TEST_HOST } from 'helpers/test_constants';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import CancelJobs from '~/ci/admin/jobs_table/components/cancel_jobs.vue';
+import CancelJobsModal from '~/ci/admin/jobs_table/components/cancel_jobs_modal.vue';
+import { CANCEL_JOBS_MODAL_ID, CANCEL_BUTTON_TOOLTIP } from '~/ci/admin/jobs_table/constants';
+
+describe('CancelJobs component', () => {
+ let wrapper;
+
+ const findCancelJobs = () => wrapper.findComponent(CancelJobs);
+ const findButton = () => wrapper.findComponent(GlButton);
+ const findModal = () => wrapper.findComponent(CancelJobsModal);
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMountExtended(CancelJobs, {
+ directives: {
+ GlModal: createMockDirective('gl-modal'),
+ GlTooltip: createMockDirective('gl-tooltip'),
+ },
+ propsData: {
+ url: `${TEST_HOST}/cancel_jobs_modal.vue/cancelAll`,
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('has correct inputs', () => {
+ expect(findCancelJobs().props().url).toBe(`${TEST_HOST}/cancel_jobs_modal.vue/cancelAll`);
+ });
+
+ it('has correct button variant', () => {
+ expect(findButton().props().variant).toBe('danger');
+ });
+
+ it('checks that button and modal are connected', () => {
+ const buttonModalDirective = getBinding(findButton().element, 'gl-modal');
+ const modalId = findModal().props('modalId');
+
+ expect(buttonModalDirective.value).toBe(CANCEL_JOBS_MODAL_ID);
+ expect(modalId).toBe(CANCEL_JOBS_MODAL_ID);
+ });
+
+ it('checks that tooltip is displayed', () => {
+ const buttonTooltipDirective = getBinding(findButton().element, 'gl-tooltip');
+
+ expect(buttonTooltipDirective.value).toBe(CANCEL_BUTTON_TOOLTIP);
+ });
+});
diff --git a/spec/frontend/ci/admin/jobs_table/components/cells/project_cell_spec.js b/spec/frontend/ci/admin/jobs_table/components/cells/project_cell_spec.js
new file mode 100644
index 00000000000..3e391e74394
--- /dev/null
+++ b/spec/frontend/ci/admin/jobs_table/components/cells/project_cell_spec.js
@@ -0,0 +1,32 @@
+import { GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import ProjectCell from '~/ci/admin/jobs_table/components/cells/project_cell.vue';
+import { mockAllJobsNodes } from 'jest/ci/jobs_mock_data';
+
+const mockJob = mockAllJobsNodes[0];
+
+describe('Project cell', () => {
+ let wrapper;
+
+ const findProjectLink = () => wrapper.findComponent(GlLink);
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(ProjectCell, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ describe('Project Link', () => {
+ beforeEach(() => {
+ createComponent({ job: mockJob });
+ });
+
+ it('shows and links to the project', () => {
+ expect(findProjectLink().exists()).toBe(true);
+ expect(findProjectLink().text()).toBe(mockJob.pipeline.project.fullPath);
+ expect(findProjectLink().attributes('href')).toBe(mockJob.pipeline.project.webUrl);
+ });
+ });
+});
diff --git a/spec/frontend/ci/admin/jobs_table/components/cells/runner_cell_spec.js b/spec/frontend/ci/admin/jobs_table/components/cells/runner_cell_spec.js
new file mode 100644
index 00000000000..2f1dae71572
--- /dev/null
+++ b/spec/frontend/ci/admin/jobs_table/components/cells/runner_cell_spec.js
@@ -0,0 +1,64 @@
+import { GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RunnerCell from '~/ci/admin/jobs_table/components/cells/runner_cell.vue';
+import { RUNNER_EMPTY_TEXT } from '~/ci/admin/jobs_table/constants';
+import { allRunnersData } from 'jest/ci/runner/mock_data';
+
+const mockRunner = allRunnersData.data.runners.nodes[0];
+
+const mockJobWithRunner = {
+ id: 'gid://gitlab/Ci::Build/2264',
+ runner: mockRunner,
+};
+
+const mockJobWithoutRunner = {
+ id: 'gid://gitlab/Ci::Build/2265',
+};
+
+describe('Runner Cell', () => {
+ let wrapper;
+
+ const findRunnerLink = () => wrapper.findComponent(GlLink);
+ const findEmptyRunner = () => wrapper.find('[data-testid="empty-runner-text"]');
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(RunnerCell, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ describe('Runner Link', () => {
+ describe('Job with runner', () => {
+ beforeEach(() => {
+ createComponent({ job: mockJobWithRunner });
+ });
+
+ it('shows and links to the runner', () => {
+ expect(findRunnerLink().exists()).toBe(true);
+ expect(findRunnerLink().text()).toBe(mockRunner.description);
+ expect(findRunnerLink().attributes('href')).toBe(mockRunner.adminUrl);
+ });
+
+ it('hides the empty runner text', () => {
+ expect(findEmptyRunner().exists()).toBe(false);
+ });
+ });
+
+ describe('Job without runner', () => {
+ beforeEach(() => {
+ createComponent({ job: mockJobWithoutRunner });
+ });
+
+ it('shows default `empty` text', () => {
+ expect(findEmptyRunner().exists()).toBe(true);
+ expect(findEmptyRunner().text()).toBe(RUNNER_EMPTY_TEXT);
+ });
+
+ it('hides the runner link', () => {
+ expect(findRunnerLink().exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/admin/jobs_table/components/jobs_skeleton_loader_spec.js b/spec/frontend/ci/admin/jobs_table/components/jobs_skeleton_loader_spec.js
new file mode 100644
index 00000000000..0d2f5f58121
--- /dev/null
+++ b/spec/frontend/ci/admin/jobs_table/components/jobs_skeleton_loader_spec.js
@@ -0,0 +1,28 @@
+import { GlSkeletonLoader } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import JobsSkeletonLoader from '~/ci/admin/jobs_table/components/jobs_skeleton_loader.vue';
+
+describe('jobs_skeleton_loader.vue', () => {
+ let wrapper;
+
+ const findGlSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+
+ const WIDTH = '1248';
+ const HEIGHT = '73';
+
+ beforeEach(() => {
+ wrapper = shallowMount(JobsSkeletonLoader);
+ });
+
+ it('renders a GlSkeletonLoader', () => {
+ expect(findGlSkeletonLoader().exists()).toBe(true);
+ });
+
+ it('has correct width', () => {
+ expect(findGlSkeletonLoader().attributes('width')).toBe(WIDTH);
+ });
+
+ it('has correct height', () => {
+ expect(findGlSkeletonLoader().attributes('height')).toBe(HEIGHT);
+ });
+});
diff --git a/spec/frontend/ci/admin/jobs_table/graphql/cache_config_spec.js b/spec/frontend/ci/admin/jobs_table/graphql/cache_config_spec.js
new file mode 100644
index 00000000000..36fbbafac44
--- /dev/null
+++ b/spec/frontend/ci/admin/jobs_table/graphql/cache_config_spec.js
@@ -0,0 +1,106 @@
+import cacheConfig from '~/ci/admin/jobs_table/graphql/cache_config';
+import {
+ CIJobConnectionExistingCache,
+ CIJobConnectionIncomingCache,
+ CIJobConnectionIncomingCacheRunningStatus,
+} from 'jest/ci/jobs_mock_data';
+
+const firstLoadArgs = { first: 3, statuses: 'PENDING' };
+const runningArgs = { first: 3, statuses: 'RUNNING' };
+
+describe('jobs/components/table/graphql/cache_config', () => {
+ describe('when fetching data with the same statuses', () => {
+ it('should contain cache nodes and a status when merging caches on first load', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
+ args: firstLoadArgs,
+ });
+
+ expect(res.nodes).toHaveLength(CIJobConnectionIncomingCache.nodes.length);
+ expect(res.statuses).toBe('PENDING');
+ });
+
+ it('should add to existing caches when merging caches after first load', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ CIJobConnectionIncomingCache,
+ {
+ args: firstLoadArgs,
+ },
+ );
+
+ expect(res.nodes).toHaveLength(
+ CIJobConnectionIncomingCache.nodes.length + CIJobConnectionExistingCache.nodes.length,
+ );
+ });
+
+ it('should not add to existing cache if the incoming elements are the same', () => {
+ // simulate that this is the last page
+ const finalExistingCache = {
+ ...CIJobConnectionExistingCache,
+ pageInfo: {
+ hasNextPage: false,
+ },
+ };
+
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ finalExistingCache,
+ {
+ args: firstLoadArgs,
+ },
+ );
+
+ expect(res.nodes).toHaveLength(CIJobConnectionExistingCache.nodes.length);
+ });
+
+ it('should contain the pageInfo key as part of the result', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
+ args: firstLoadArgs,
+ });
+
+ expect(res.pageInfo).toEqual(
+ expect.objectContaining({
+ __typename: 'PageInfo',
+ endCursor: 'eyJpZCI6IjIwNTEifQ',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'eyJpZCI6IjIxNzMifQ',
+ }),
+ );
+ });
+ });
+
+ describe('when fetching data with different statuses', () => {
+ it('should reset cache when a cache already exists', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ CIJobConnectionIncomingCacheRunningStatus,
+ {
+ args: runningArgs,
+ },
+ );
+
+ expect(res.nodes).not.toEqual(CIJobConnectionExistingCache.nodes);
+ expect(res.nodes).toHaveLength(CIJobConnectionIncomingCacheRunningStatus.nodes.length);
+ });
+ });
+
+ describe('when incoming data has no nodes', () => {
+ it('should return existing cache', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ { __typename: 'CiJobConnection', count: 500 },
+ {
+ args: { statuses: 'SUCCESS' },
+ },
+ );
+
+ const expectedResponse = {
+ ...CIJobConnectionExistingCache,
+ statuses: 'SUCCESS',
+ };
+
+ expect(res).toEqual(expectedResponse);
+ });
+ });
+});
diff --git a/spec/frontend/ci/artifacts/components/feedback_banner_spec.js b/spec/frontend/ci/artifacts/components/feedback_banner_spec.js
deleted file mode 100644
index 53e0fdac6f6..00000000000
--- a/spec/frontend/ci/artifacts/components/feedback_banner_spec.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import { GlBanner } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import FeedbackBanner from '~/ci/artifacts/components/feedback_banner.vue';
-import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
-import {
- I18N_FEEDBACK_BANNER_TITLE,
- I18N_FEEDBACK_BANNER_BUTTON,
- FEEDBACK_URL,
-} from '~/ci/artifacts/constants';
-
-const mockBannerImagePath = 'banner/image/path';
-
-describe('Artifacts management feedback banner', () => {
- let wrapper;
- let userCalloutDismissSpy;
-
- const findBanner = () => wrapper.findComponent(GlBanner);
-
- const createComponent = ({ shouldShowCallout = true } = {}) => {
- userCalloutDismissSpy = jest.fn();
-
- wrapper = shallowMount(FeedbackBanner, {
- provide: {
- artifactsManagementFeedbackImagePath: mockBannerImagePath,
- },
- stubs: {
- UserCalloutDismisser: makeMockUserCalloutDismisser({
- dismiss: userCalloutDismissSpy,
- shouldShowCallout,
- }),
- },
- });
- };
-
- it('is displayed with the correct props', () => {
- createComponent();
-
- expect(findBanner().props()).toMatchObject({
- title: I18N_FEEDBACK_BANNER_TITLE,
- buttonText: I18N_FEEDBACK_BANNER_BUTTON,
- buttonLink: FEEDBACK_URL,
- svgPath: mockBannerImagePath,
- });
- });
-
- it('dismisses the callout when closed', () => {
- createComponent();
-
- findBanner().vm.$emit('close');
-
- expect(userCalloutDismissSpy).toHaveBeenCalled();
- });
-
- it('is not displayed once it has been dismissed', () => {
- createComponent({ shouldShowCallout: false });
-
- expect(findBanner().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js b/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js
index e062140246b..1cbb1a714c9 100644
--- a/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js
+++ b/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js
@@ -13,7 +13,6 @@ import getJobArtifactsResponse from 'test_fixtures/graphql/ci/artifacts/graphql/
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import waitForPromises from 'helpers/wait_for_promises';
import JobArtifactsTable from '~/ci/artifacts/components/job_artifacts_table.vue';
-import FeedbackBanner from '~/ci/artifacts/components/feedback_banner.vue';
import ArtifactsTableRowDetails from '~/ci/artifacts/components/artifacts_table_row_details.vue';
import ArtifactDeleteModal from '~/ci/artifacts/components/artifact_delete_modal.vue';
import ArtifactsBulkDelete from '~/ci/artifacts/components/artifacts_bulk_delete.vue';
@@ -46,8 +45,6 @@ describe('JobArtifactsTable component', () => {
const mockToastShow = jest.fn();
- const findBanner = () => wrapper.findComponent(FeedbackBanner);
-
const findLoadingState = () => wrapper.findComponent(GlLoadingIcon);
const findTable = () => wrapper.findComponent(GlTable);
const findDetailsRows = () => wrapper.findAllComponents(ArtifactsTableRowDetails);
@@ -162,7 +159,6 @@ describe('JobArtifactsTable component', () => {
projectPath: 'project/path',
projectId,
canDestroyArtifacts,
- artifactsManagementFeedbackImagePath: 'banner/image/path',
},
mocks: {
$toast: {
@@ -175,12 +171,6 @@ describe('JobArtifactsTable component', () => {
});
};
- it('renders feedback banner', () => {
- createComponent();
-
- expect(findBanner().exists()).toBe(true);
- });
-
it('when loading, shows a loading state', () => {
createComponent();
@@ -373,6 +363,7 @@ describe('JobArtifactsTable component', () => {
it('is disabled when job has no metadata.gz', async () => {
const jobWithoutMetadata = {
...job,
+ hasArtifacts: true,
artifacts: { nodes: [archiveArtifact] },
};
@@ -389,6 +380,7 @@ describe('JobArtifactsTable component', () => {
it('is disabled when job has no artifacts', async () => {
const jobWithoutArtifacts = {
...job,
+ hasArtifacts: false,
artifacts: { nodes: [] },
};
diff --git a/spec/frontend/ci/ci_variable_list/ci_variable_list/ci_variable_list_spec.js b/spec/frontend/ci/ci_variable_list/ci_variable_list/ci_variable_list_spec.js
deleted file mode 100644
index 8990a70d4ef..00000000000
--- a/spec/frontend/ci/ci_variable_list/ci_variable_list/ci_variable_list_spec.js
+++ /dev/null
@@ -1,161 +0,0 @@
-import $ from 'jquery';
-import htmlPipelineSchedulesEdit from 'test_fixtures/pipeline_schedules/edit.html';
-import htmlPipelineSchedulesEditWithVariables from 'test_fixtures/pipeline_schedules/edit_with_variables.html';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import VariableList from '~/ci/ci_variable_list/ci_variable_list';
-
-const HIDE_CLASS = 'hide';
-
-describe('VariableList', () => {
- let $wrapper;
- let variableList;
-
- describe('with only key/value inputs', () => {
- describe('with no variables', () => {
- beforeEach(() => {
- setHTMLFixture(htmlPipelineSchedulesEdit);
- $wrapper = $('.js-ci-variable-list-section');
-
- variableList = new VariableList({
- container: $wrapper,
- formField: 'schedule',
- });
- variableList.init();
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- it('should remove the row when clicking the remove button', () => {
- $wrapper.find('.js-row-remove-button').trigger('click');
-
- expect($wrapper.find('.js-row').length).toBe(0);
- });
-
- it('should add another row when editing the last rows key input', () => {
- const $row = $wrapper.find('.js-row');
- $row.find('.js-ci-variable-input-key').val('foo').trigger('input');
-
- expect($wrapper.find('.js-row').length).toBe(2);
-
- // Check for the correct default in the new row
- const $keyInput = $wrapper.find('.js-row:last-child').find('.js-ci-variable-input-key');
-
- expect($keyInput.val()).toBe('');
- });
-
- it('should add another row when editing the last rows value textarea', () => {
- const $row = $wrapper.find('.js-row');
- $row.find('.js-ci-variable-input-value').val('foo').trigger('input');
-
- expect($wrapper.find('.js-row').length).toBe(2);
-
- // Check for the correct default in the new row
- const $valueInput = $wrapper.find('.js-row:last-child').find('.js-ci-variable-input-key');
-
- expect($valueInput.val()).toBe('');
- });
-
- it('should remove empty row after blurring', () => {
- const $row = $wrapper.find('.js-row');
- $row.find('.js-ci-variable-input-key').val('foo').trigger('input');
-
- expect($wrapper.find('.js-row').length).toBe(2);
-
- $row.find('.js-ci-variable-input-key').val('').trigger('input').trigger('blur');
-
- expect($wrapper.find('.js-row').length).toBe(1);
- });
- });
-
- describe('with persisted variables', () => {
- beforeEach(() => {
- setHTMLFixture(htmlPipelineSchedulesEditWithVariables);
- $wrapper = $('.js-ci-variable-list-section');
-
- variableList = new VariableList({
- container: $wrapper,
- formField: 'schedule',
- });
- variableList.init();
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- it('should have "Reveal values" button initially when there are already variables', () => {
- expect($wrapper.find('.js-secret-value-reveal-button').text()).toBe('Reveal values');
- });
-
- it('should reveal hidden values', () => {
- const $row = $wrapper.find('.js-row:first-child');
- const $inputValue = $row.find('.js-ci-variable-input-value');
- const $placeholder = $row.find('.js-secret-value-placeholder');
-
- expect($placeholder.hasClass(HIDE_CLASS)).toBe(false);
- expect($inputValue.hasClass(HIDE_CLASS)).toBe(true);
-
- // Reveal values
- $wrapper.find('.js-secret-value-reveal-button').click();
-
- expect($placeholder.hasClass(HIDE_CLASS)).toBe(true);
- expect($inputValue.hasClass(HIDE_CLASS)).toBe(false);
- });
- });
- });
-
- describe('toggleEnableRow method', () => {
- beforeEach(() => {
- setHTMLFixture(htmlPipelineSchedulesEditWithVariables);
- $wrapper = $('.js-ci-variable-list-section');
-
- variableList = new VariableList({
- container: $wrapper,
- formField: 'variables',
- });
- variableList.init();
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- it('should disable all key inputs', () => {
- expect($wrapper.find('.js-ci-variable-input-key:not([disabled])').length).toBe(3);
-
- variableList.toggleEnableRow(false);
-
- expect($wrapper.find('.js-ci-variable-input-key[disabled]').length).toBe(3);
- });
-
- it('should disable all remove buttons', () => {
- expect($wrapper.find('.js-row-remove-button:not([disabled])').length).toBe(3);
-
- variableList.toggleEnableRow(false);
-
- expect($wrapper.find('.js-row-remove-button[disabled]').length).toBe(3);
- });
-
- it('should enable all remove buttons', () => {
- variableList.toggleEnableRow(false);
-
- expect($wrapper.find('.js-row-remove-button[disabled]').length).toBe(3);
-
- variableList.toggleEnableRow(true);
-
- expect($wrapper.find('.js-row-remove-button:not([disabled])').length).toBe(3);
- });
-
- it('should enable all key inputs', () => {
- variableList.toggleEnableRow(false);
-
- expect($wrapper.find('.js-ci-variable-input-key[disabled]').length).toBe(3);
-
- variableList.toggleEnableRow(true);
-
- expect($wrapper.find('.js-ci-variable-input-key:not([disabled])').length).toBe(3);
- });
- });
-});
diff --git a/spec/frontend/ci/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js b/spec/frontend/ci/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js
deleted file mode 100644
index 3ef5427f288..00000000000
--- a/spec/frontend/ci/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import $ from 'jquery';
-import htmlPipelineSchedulesEdit from 'test_fixtures/pipeline_schedules/edit.html';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import setupNativeFormVariableList from '~/ci/ci_variable_list/native_form_variable_list';
-
-describe('NativeFormVariableList', () => {
- let $wrapper;
-
- beforeEach(() => {
- setHTMLFixture(htmlPipelineSchedulesEdit);
- $wrapper = $('.js-ci-variable-list-section');
-
- setupNativeFormVariableList({
- container: $wrapper,
- formField: 'schedule',
- });
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- describe('onFormSubmit', () => {
- it('should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)', () => {
- const $row = $wrapper.find('.js-row');
-
- expect($row.find('.js-ci-variable-input-key').attr('name')).toBe(
- 'schedule[variables_attributes][][key]',
- );
-
- expect($row.find('.js-ci-variable-input-value').attr('name')).toBe(
- 'schedule[variables_attributes][][secret_value]',
- );
-
- $wrapper.closest('form').trigger('trigger-submit');
-
- expect($row.find('.js-ci-variable-input-key').attr('name')).toBe('');
- expect($row.find('.js-ci-variable-input-value').attr('name')).toBe('');
- });
- });
-});
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
index 762c9611dac..ab5d914a6a1 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
@@ -1,42 +1,90 @@
-import { GlDrawer, GlFormSelect } from '@gitlab/ui';
+import { GlDrawer, GlFormCombobox, GlFormInput, GlFormSelect } from '@gitlab/ui';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import CiEnvironmentsDropdown from '~/ci/ci_variable_list/components/ci_environments_dropdown.vue';
import CiVariableDrawer from '~/ci/ci_variable_list/components/ci_variable_drawer.vue';
+import { awsTokenList } from '~/ci/ci_variable_list/components/ci_variable_autocomplete_tokens';
import {
ADD_VARIABLE_ACTION,
+ DRAWER_EVENT_LABEL,
+ EDIT_VARIABLE_ACTION,
+ EVENT_ACTION,
variableOptions,
+ projectString,
variableTypes,
} from '~/ci/ci_variable_list/constants';
+import { mockTracking } from 'helpers/tracking_helper';
+import { mockVariablesWithScopes } from '../mocks';
describe('CI Variable Drawer', () => {
let wrapper;
+ let trackingSpy;
+
+ const mockProjectVariable = mockVariablesWithScopes(projectString)[0];
+ const mockProjectVariableFileType = mockVariablesWithScopes(projectString)[1];
+ const mockEnvScope = 'staging';
+ const mockEnvironments = ['*', 'dev', 'staging', 'production'];
+
+ // matches strings that contain at least 8 consecutive characters consisting of only
+ // letters (both uppercase and lowercase), digits, or the specified special characters
+ const maskableRegex = '^[a-zA-Z0-9_+=/@:.~-]{8,}$';
+
+ // matches strings that consist of at least 8 or more non-whitespace characters
+ const maskableRawRegex = '^\\S{8,}$';
const defaultProps = {
areEnvironmentsLoading: false,
- hasEnvScopeQuery: true,
+ areScopedVariablesAvailable: true,
+ environments: mockEnvironments,
+ hideEnvironmentScope: false,
+ selectedVariable: {},
mode: ADD_VARIABLE_ACTION,
};
- const createComponent = ({ mountFn = shallowMountExtended, props = {} } = {}) => {
+ const defaultProvide = {
+ isProtectedByDefault: true,
+ environmentScopeLink: '/help/environments',
+ maskableRawRegex,
+ maskableRegex,
+ };
+
+ const createComponent = ({
+ mountFn = shallowMountExtended,
+ props = {},
+ provide = {},
+ stubs = {},
+ } = {}) => {
wrapper = mountFn(CiVariableDrawer, {
propsData: {
...defaultProps,
...props,
},
provide: {
- environmentScopeLink: '/help/environments',
+ ...defaultProvide,
+ ...provide,
},
+ stubs,
});
};
+ const findConfirmBtn = () => wrapper.findByTestId('ci-variable-confirm-btn');
+ const findDisabledEnvironmentScopeDropdown = () => wrapper.findComponent(GlFormInput);
const findDrawer = () => wrapper.findComponent(GlDrawer);
+ const findEnvironmentScopeDropdown = () => wrapper.findComponent(CiEnvironmentsDropdown);
+ const findExpandedCheckbox = () => wrapper.findByTestId('ci-variable-expanded-checkbox');
+ const findKeyField = () => wrapper.findComponent(GlFormCombobox);
+ const findMaskedCheckbox = () => wrapper.findByTestId('ci-variable-masked-checkbox');
+ const findProtectedCheckbox = () => wrapper.findByTestId('ci-variable-protected-checkbox');
+ const findValueField = () => wrapper.findByTestId('ci-variable-value');
+ const findValueLabel = () => wrapper.findByTestId('ci-variable-value-label');
+ const findTitle = () => findDrawer().find('h2');
const findTypeDropdown = () => wrapper.findComponent(GlFormSelect);
describe('validations', () => {
- beforeEach(() => {
- createComponent({ mountFn: mountExtended });
- });
-
describe('type dropdown', () => {
+ beforeEach(() => {
+ createComponent({ mountFn: mountExtended });
+ });
+
it('adds each type option as a dropdown item', () => {
expect(findTypeDropdown().findAll('option')).toHaveLength(variableOptions.length);
@@ -50,20 +98,288 @@ describe('CI Variable Drawer', () => {
variableTypes.envType,
);
});
+
+ it('renders the selected variable type', () => {
+ createComponent({
+ mountFn: mountExtended,
+ props: {
+ areEnvironmentsLoading: true,
+ selectedVariable: mockProjectVariableFileType,
+ },
+ });
+
+ expect(findTypeDropdown().element.value).toBe(variableTypes.fileType);
+ });
+ });
+
+ describe('environment scope dropdown', () => {
+ it('passes correct props to the dropdown', () => {
+ createComponent({
+ props: {
+ areEnvironmentsLoading: true,
+ selectedVariable: { ...mockProjectVariable, environmentScope: mockEnvScope },
+ },
+ stubs: { CiEnvironmentsDropdown },
+ });
+
+ expect(findEnvironmentScopeDropdown().props()).toMatchObject({
+ areEnvironmentsLoading: true,
+ environments: mockEnvironments,
+ selectedEnvironmentScope: mockEnvScope,
+ });
+ });
+
+ it('hides environment scope dropdown when hideEnvironmentScope is true', () => {
+ createComponent({
+ props: { hideEnvironmentScope: true },
+ stubs: { CiEnvironmentsDropdown },
+ });
+
+ expect(findEnvironmentScopeDropdown().exists()).toBe(false);
+ });
+
+ it('disables the environment scope dropdown when areScopedVariablesAvailable is false', () => {
+ createComponent({
+ mountFn: mountExtended,
+ props: { areScopedVariablesAvailable: false },
+ });
+
+ expect(findEnvironmentScopeDropdown().exists()).toBe(false);
+ expect(findDisabledEnvironmentScopeDropdown().attributes('readonly')).toBe('readonly');
+ });
+ });
+
+ describe('protected flag', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('is true by default when isProtectedByDefault is true', () => {
+ expect(findProtectedCheckbox().attributes('checked')).toBeDefined();
+ });
+
+ it('is not checked when isProtectedByDefault is false', () => {
+ createComponent({ provide: { isProtectedByDefault: false } });
+
+ expect(findProtectedCheckbox().attributes('checked')).toBeUndefined();
+ });
+
+ it('inherits value of selected variable when editing', () => {
+ createComponent({
+ props: {
+ selectedVariable: mockProjectVariableFileType,
+ mode: EDIT_VARIABLE_ACTION,
+ },
+ });
+
+ expect(findProtectedCheckbox().attributes('checked')).toBeUndefined();
+ });
+ });
+
+ describe('masked flag', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('is false by default', () => {
+ expect(findMaskedCheckbox().attributes('checked')).toBeUndefined();
+ });
+
+ it('inherits value of selected variable when editing', () => {
+ createComponent({
+ props: {
+ selectedVariable: mockProjectVariableFileType,
+ mode: EDIT_VARIABLE_ACTION,
+ },
+ });
+
+ expect(findMaskedCheckbox().attributes('checked')).toBeDefined();
+ });
+ });
+
+ describe('expanded flag', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('is true by default when adding a variable', () => {
+ expect(findExpandedCheckbox().attributes('checked')).toBeDefined();
+ });
+
+ it('inherits value of selected variable when editing', () => {
+ createComponent({
+ props: {
+ selectedVariable: mockProjectVariableFileType,
+ mode: EDIT_VARIABLE_ACTION,
+ },
+ });
+
+ expect(findExpandedCheckbox().attributes('checked')).toBeUndefined();
+ });
+
+ it("sets the variable's raw value", async () => {
+ await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
+ await findExpandedCheckbox().vm.$emit('change');
+ await findConfirmBtn().vm.$emit('click');
+
+ const sentRawValue = wrapper.emitted('add-variable')[0][0].raw;
+ expect(sentRawValue).toBe(!defaultProps.raw);
+ });
+
+ it('shows help text when variable is not expanded (will be evaluated as raw)', async () => {
+ expect(findExpandedCheckbox().attributes('checked')).toBeDefined();
+ expect(findDrawer().text()).not.toContain(
+ 'Variable value will be evaluated as raw string.',
+ );
+
+ await findExpandedCheckbox().vm.$emit('change');
+
+ expect(findExpandedCheckbox().attributes('checked')).toBeUndefined();
+ expect(findDrawer().text()).toContain('Variable value will be evaluated as raw string.');
+ });
+
+ it('shows help text when variable is expanded and contains the $ character', async () => {
+ expect(findDrawer().text()).not.toContain(
+ 'Unselect "Expand variable reference" if you want to use the variable value as a raw string.',
+ );
+
+ await findValueField().vm.$emit('input', '$NEW_VALUE');
+
+ expect(findDrawer().text()).toContain(
+ 'Unselect "Expand variable reference" if you want to use the variable value as a raw string.',
+ );
+ });
+ });
+
+ describe('key', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('prompts AWS tokens as options', () => {
+ expect(findKeyField().props('tokenList')).toBe(awsTokenList);
+ });
+
+ it('cannot submit with empty key', async () => {
+ expect(findConfirmBtn().attributes('disabled')).toBeDefined();
+
+ await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
+
+ expect(findConfirmBtn().attributes('disabled')).toBeUndefined();
+ });
+ });
+
+ describe('value', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('can submit empty value', async () => {
+ await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
+
+ // value is empty by default
+ expect(findConfirmBtn().attributes('disabled')).toBeUndefined();
+ });
+
+ describe.each`
+ value | canSubmit | trackingErrorProperty
+ ${'secretValue'} | ${true} | ${null}
+ ${'~v@lid:symbols.'} | ${true} | ${null}
+ ${'short'} | ${false} | ${null}
+ ${'multiline\nvalue'} | ${false} | ${'\n'}
+ ${'dollar$ign'} | ${false} | ${'$'}
+ ${'unsupported|char'} | ${false} | ${'|'}
+ `('masking requirements', ({ value, canSubmit, trackingErrorProperty }) => {
+ beforeEach(async () => {
+ createComponent();
+
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
+ await findValueField().vm.$emit('input', value);
+ await findMaskedCheckbox().vm.$emit('input', true);
+ });
+
+ it(`${
+ canSubmit ? 'can submit' : 'shows validation errors and disables submit button'
+ } when value is '${value}'`, () => {
+ if (canSubmit) {
+ expect(findValueLabel().attributes('invalid-feedback')).toBe('');
+ expect(findConfirmBtn().attributes('disabled')).toBeUndefined();
+ } else {
+ expect(findValueLabel().attributes('invalid-feedback')).toBe(
+ 'This variable value does not meet the masking requirements.',
+ );
+ expect(findConfirmBtn().attributes('disabled')).toBeDefined();
+ }
+ });
+
+ it(`${
+ trackingErrorProperty ? 'sends the correct' : 'does not send the'
+ } variable validation tracking event when value is '${value}'`, () => {
+ const trackingEventSent = trackingErrorProperty ? 1 : 0;
+ expect(trackingSpy).toHaveBeenCalledTimes(trackingEventSent);
+
+ if (trackingErrorProperty) {
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTION, {
+ label: DRAWER_EVENT_LABEL,
+ property: trackingErrorProperty,
+ });
+ }
+ });
+ });
+
+ it('only sends the tracking event once', async () => {
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ await findKeyField().vm.$emit('input', 'NEW_VARIABLE');
+ await findMaskedCheckbox().vm.$emit('input', true);
+
+ expect(trackingSpy).toHaveBeenCalledTimes(0);
+
+ await findValueField().vm.$emit('input', 'unsupported|char');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+
+ await findValueField().vm.$emit('input', 'dollar$ign');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ });
});
});
describe('drawer events', () => {
- beforeEach(() => {
+ it('emits `close-form` when closing the drawer', async () => {
createComponent();
- });
- it('emits `close-form` when closing the drawer', async () => {
expect(wrapper.emitted('close-form')).toBeUndefined();
await findDrawer().vm.$emit('close');
expect(wrapper.emitted('close-form')).toHaveLength(1);
});
+
+ describe('when adding a variable', () => {
+ beforeEach(() => {
+ createComponent({ stubs: { GlDrawer } });
+ });
+
+ it('title and confirm button renders the correct text', () => {
+ expect(findTitle().text()).toBe('Add Variable');
+ expect(findConfirmBtn().text()).toBe('Add Variable');
+ });
+ });
+
+ describe('when editing a variable', () => {
+ beforeEach(() => {
+ createComponent({
+ props: { mode: EDIT_VARIABLE_ACTION },
+ stubs: { GlDrawer },
+ });
+ });
+
+ it('title and confirm button renders the correct text', () => {
+ expect(findTitle().text()).toBe('Edit Variable');
+ expect(findConfirmBtn().text()).toBe('Edit Variable');
+ });
+ });
});
});
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
index f5737c61eea..79dd638e2bd 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_settings_spec.js
@@ -77,6 +77,21 @@ describe('Ci variable table', () => {
selectedVariable: {},
});
});
+
+ it('passes props down correctly to the ci drawer', async () => {
+ createComponent({ featureFlags: { ciVariableDrawer: true } });
+
+ await findCiVariableTable().vm.$emit('set-selected-variable');
+
+ expect(findCiVariableDrawer().props()).toEqual({
+ areEnvironmentsLoading: defaultProps.areEnvironmentsLoading,
+ areScopedVariablesAvailable: defaultProps.areScopedVariablesAvailable,
+ environments: defaultProps.environments,
+ hideEnvironmentScope: defaultProps.hideEnvironmentScope,
+ mode: ADD_VARIABLE_ACTION,
+ selectedVariable: {},
+ });
+ });
});
describe.each`
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js
index 39c03a41660..de24c389511 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_table_spec.js
@@ -105,9 +105,8 @@ describe('Ci variable table', () => {
index | text
${0} | ${'Key (Click to sort descending)'}
${1} | ${'Value'}
- ${2} | ${'Attributes'}
- ${3} | ${'Environments'}
- ${4} | ${'Actions'}
+ ${2} | ${'Environments'}
+ ${3} | ${'Actions'}
`('renders the $text column', ({ index, text }) => {
expect(findTableColumnText(index)).toEqual(text);
});
diff --git a/spec/frontend/ci/common/pipelines_table_spec.js b/spec/frontend/ci/common/pipelines_table_spec.js
new file mode 100644
index 00000000000..26dd1a2fcc5
--- /dev/null
+++ b/spec/frontend/ci/common/pipelines_table_spec.js
@@ -0,0 +1,280 @@
+import '~/commons';
+import { GlTableLite } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import fixture from 'test_fixtures/pipelines/pipelines.json';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import PipelineFailedJobsWidget from '~/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue';
+import PipelineOperations from '~/ci/pipelines_page/components/pipeline_operations.vue';
+import PipelineTriggerer from '~/ci/pipelines_page/components/pipeline_triggerer.vue';
+import PipelineUrl from '~/ci/pipelines_page/components/pipeline_url.vue';
+import PipelinesTable from '~/ci/common/pipelines_table.vue';
+import PipelinesTimeago from '~/ci/pipelines_page/components/time_ago.vue';
+import {
+ PipelineKeyOptions,
+ BUTTON_TOOLTIP_RETRY,
+ BUTTON_TOOLTIP_CANCEL,
+ TRACKING_CATEGORIES,
+} from '~/ci/constants';
+
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+
+jest.mock('~/ci/event_hub');
+
+describe('Pipelines Table', () => {
+ let pipeline;
+ let wrapper;
+ let trackingSpy;
+
+ const defaultProvide = {
+ glFeatures: {},
+ withFailedJobsDetails: false,
+ };
+
+ const provideWithDetails = {
+ glFeatures: {
+ ciJobFailuresInMr: true,
+ },
+ withFailedJobsDetails: true,
+ };
+
+ const defaultProps = {
+ pipelines: [],
+ viewType: 'root',
+ pipelineKeyOption: PipelineKeyOptions[0],
+ };
+
+ const createMockPipeline = () => {
+ // Clone fixture as it could be modified by tests
+ const { pipelines } = JSON.parse(JSON.stringify(fixture));
+ return pipelines.find((p) => p.user !== null && p.commit !== null);
+ };
+
+ const createComponent = (props = {}, provide = {}) => {
+ wrapper = extendedWrapper(
+ mount(PipelinesTable, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ stubs: ['PipelineFailedJobsWidget'],
+ }),
+ );
+ };
+
+ const findGlTableLite = () => wrapper.findComponent(GlTableLite);
+ const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
+ const findPipelineInfo = () => wrapper.findComponent(PipelineUrl);
+ const findTriggerer = () => wrapper.findComponent(PipelineTriggerer);
+ const findLegacyPipelineMiniGraph = () => wrapper.findComponent(LegacyPipelineMiniGraph);
+ const findTimeAgo = () => wrapper.findComponent(PipelinesTimeago);
+ const findActions = () => wrapper.findComponent(PipelineOperations);
+
+ const findPipelineFailureWidget = () => wrapper.findComponent(PipelineFailedJobsWidget);
+ const findTableRows = () => wrapper.findAllByTestId('pipeline-table-row');
+ const findStatusTh = () => wrapper.findByTestId('status-th');
+ const findPipelineTh = () => wrapper.findByTestId('pipeline-th');
+ const findStagesTh = () => wrapper.findByTestId('stages-th');
+ const findActionsTh = () => wrapper.findByTestId('actions-th');
+ const findRetryBtn = () => wrapper.findByTestId('pipelines-retry-button');
+ const findCancelBtn = () => wrapper.findByTestId('pipelines-cancel-button');
+
+ beforeEach(() => {
+ pipeline = createMockPipeline();
+ });
+
+ describe('Pipelines Table', () => {
+ beforeEach(() => {
+ createComponent({ pipelines: [pipeline], viewType: 'root' });
+ });
+
+ it('displays table', () => {
+ expect(findGlTableLite().exists()).toBe(true);
+ });
+
+ it('should render table head with correct columns', () => {
+ expect(findStatusTh().text()).toBe('Status');
+ expect(findPipelineTh().text()).toBe('Pipeline');
+ expect(findStagesTh().text()).toBe('Stages');
+ expect(findActionsTh().text()).toBe('Actions');
+ });
+
+ it('should display a table row', () => {
+ expect(findTableRows()).toHaveLength(1);
+ });
+
+ describe('status cell', () => {
+ it('should render a status badge', () => {
+ expect(findCiBadgeLink().exists()).toBe(true);
+ });
+ });
+
+ describe('pipeline cell', () => {
+ it('should render pipeline information', () => {
+ expect(findPipelineInfo().exists()).toBe(true);
+ });
+
+ it('should display the pipeline id', () => {
+ expect(findPipelineInfo().text()).toContain(`#${pipeline.id}`);
+ });
+ });
+
+ describe('stages cell', () => {
+ it('should render pipeline mini graph', () => {
+ expect(findLegacyPipelineMiniGraph().exists()).toBe(true);
+ });
+
+ it('should render the right number of stages', () => {
+ const stagesLength = pipeline.details.stages.length;
+ expect(findLegacyPipelineMiniGraph().props('stages').length).toBe(stagesLength);
+ });
+
+ it('should render the latest downstream pipelines only', () => {
+ // component receives two downstream pipelines. one of them is already outdated
+ // because we retried the trigger job, so the mini pipeline graph will only
+ // render the newly created downstream pipeline instead
+ expect(pipeline.triggered).toHaveLength(2);
+ expect(findLegacyPipelineMiniGraph().props('downstreamPipelines')).toHaveLength(1);
+ });
+
+ describe('when pipeline does not have stages', () => {
+ beforeEach(() => {
+ pipeline = createMockPipeline();
+ pipeline.details.stages = [];
+
+ createComponent({ pipelines: [pipeline] });
+ });
+
+ it('stages are not rendered', () => {
+ expect(findLegacyPipelineMiniGraph().props('stages')).toHaveLength(0);
+ });
+ });
+ });
+
+ describe('duration cell', () => {
+ it('should render duration information', () => {
+ expect(findTimeAgo().exists()).toBe(true);
+ });
+ });
+
+ describe('operations cell', () => {
+ it('should render pipeline operations', () => {
+ expect(findActions().exists()).toBe(true);
+ });
+
+ it('should render retry action tooltip', () => {
+ expect(findRetryBtn().attributes('title')).toBe(BUTTON_TOOLTIP_RETRY);
+ });
+
+ it('should render cancel action tooltip', () => {
+ expect(findCancelBtn().attributes('title')).toBe(BUTTON_TOOLTIP_CANCEL);
+ });
+ });
+
+ describe('triggerer cell', () => {
+ it('should render the pipeline triggerer', () => {
+ expect(findTriggerer().exists()).toBe(true);
+ });
+ });
+
+ describe('failed jobs details', () => {
+ describe('row', () => {
+ describe('when the FF is disabled', () => {
+ beforeEach(() => {
+ createComponent({ pipelines: [pipeline] });
+ });
+
+ it('does not render', () => {
+ expect(findTableRows()).toHaveLength(1);
+ expect(findPipelineFailureWidget().exists()).toBe(false);
+ });
+ });
+
+ describe('when the FF is enabled', () => {
+ describe('and `withFailedJobsDetails` value is provided', () => {
+ beforeEach(() => {
+ createComponent({ pipelines: [pipeline] }, provideWithDetails);
+ });
+
+ it('renders', () => {
+ expect(findTableRows()).toHaveLength(2);
+ expect(findPipelineFailureWidget().exists()).toBe(true);
+ });
+
+ it('passes the expected props', () => {
+ expect(findPipelineFailureWidget().props()).toStrictEqual({
+ failedJobsCount: pipeline.failed_builds.length,
+ isPipelineActive: pipeline.active,
+ pipelineIid: pipeline.iid,
+ pipelinePath: pipeline.path,
+ // Make sure the forward slash was removed
+ projectPath: 'frontend-fixtures/pipelines-project',
+ });
+ });
+ });
+
+ describe('and `withFailedJobsDetails` value is not provided', () => {
+ beforeEach(() => {
+ createComponent(
+ { pipelines: [pipeline] },
+ { glFeatures: { ciJobFailuresInMr: true } },
+ );
+ });
+
+ it('does not render', () => {
+ expect(findTableRows()).toHaveLength(1);
+ expect(findPipelineFailureWidget().exists()).toBe(false);
+ });
+ });
+ });
+ });
+ });
+
+ describe('tracking', () => {
+ beforeEach(() => {
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks status badge click', () => {
+ findCiBadgeLink().vm.$emit('ciStatusBadgeClick');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_ci_status_badge', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+
+ it('tracks retry pipeline button click', () => {
+ findRetryBtn().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_retry_button', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+
+ it('tracks cancel pipeline button click', () => {
+ findCancelBtn().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_cancel_button', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+
+ it('tracks pipeline mini graph stage click', () => {
+ findLegacyPipelineMiniGraph().vm.$emit('miniGraphStageClick');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_minigraph', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/common/private/job_links_layer_spec.js b/spec/frontend/ci/common/private/job_links_layer_spec.js
new file mode 100644
index 00000000000..c2defc8d770
--- /dev/null
+++ b/spec/frontend/ci/common/private/job_links_layer_spec.js
@@ -0,0 +1,85 @@
+import { shallowMount } from '@vue/test-utils';
+import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
+import LinksInner from '~/ci/pipeline_details/graph/components/links_inner.vue';
+import LinksLayer from '~/ci/common/private/job_links_layer.vue';
+
+import { generateResponse } from 'jest/ci/pipeline_details/graph/mock_data';
+
+describe('links layer component', () => {
+ let wrapper;
+
+ const findLinksInner = () => wrapper.findComponent(LinksInner);
+
+ const pipeline = generateResponse(mockPipelineResponse, 'root/fungi-xoxo');
+ const containerId = `pipeline-links-container-${pipeline.id}`;
+ const slotContent = "<div>Ceci n'est pas un graphique</div>";
+
+ const defaultProps = {
+ containerId,
+ containerMeasurements: { width: 400, height: 400 },
+ pipelineId: pipeline.id,
+ pipelineData: pipeline.stages,
+ showLinks: false,
+ };
+
+ const createComponent = ({ mountFn = shallowMount, props = {} } = {}) => {
+ wrapper = mountFn(LinksLayer, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ slots: {
+ default: slotContent,
+ },
+ stubs: {
+ 'links-inner': true,
+ },
+ });
+ };
+
+ describe('with show links off', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the default slot', () => {
+ expect(wrapper.html()).toContain(slotContent);
+ });
+
+ it('does not render inner links component', () => {
+ expect(findLinksInner().exists()).toBe(false);
+ });
+ });
+
+ describe('with show links on', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ showLinks: true,
+ },
+ });
+ });
+
+ it('renders the default slot', () => {
+ expect(wrapper.html()).toContain(slotContent);
+ });
+
+ it('renders the inner links component', () => {
+ expect(findLinksInner().exists()).toBe(true);
+ });
+ });
+
+ describe('with width or height measurement at 0', () => {
+ beforeEach(() => {
+ createComponent({ props: { containerMeasurements: { width: 0, height: 100 } } });
+ });
+
+ it('renders the default slot', () => {
+ expect(wrapper.html()).toContain(slotContent);
+ });
+
+ it('does not render the inner links component', () => {
+ expect(findLinksInner().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/common/private/jobs_filtered_search/jobs_filtered_search_spec.js b/spec/frontend/ci/common/private/jobs_filtered_search/jobs_filtered_search_spec.js
new file mode 100644
index 00000000000..079738557a4
--- /dev/null
+++ b/spec/frontend/ci/common/private/jobs_filtered_search/jobs_filtered_search_spec.js
@@ -0,0 +1,123 @@
+import { GlFilteredSearch } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import {
+ OPERATORS_IS,
+ TOKEN_TITLE_STATUS,
+ TOKEN_TYPE_STATUS,
+ TOKEN_TYPE_JOBS_RUNNER_TYPE,
+ TOKEN_TITLE_JOBS_RUNNER_TYPE,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import JobsFilteredSearch from '~/ci/common/private/jobs_filtered_search/app.vue';
+import { mockFailedSearchToken } from 'jest/ci/jobs_mock_data';
+
+describe('Jobs filtered search', () => {
+ let wrapper;
+
+ const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
+ const getSearchToken = (type) =>
+ findFilteredSearch()
+ .props('availableTokens')
+ .find((token) => token.type === type);
+
+ const findStatusToken = () => getSearchToken('status');
+ const findRunnerTypeToken = () => getSearchToken('jobs-runner-type');
+
+ const createComponent = (props, provideOptions = {}) => {
+ wrapper = shallowMount(JobsFilteredSearch, {
+ propsData: {
+ ...props,
+ },
+ provide: {
+ glFeatures: { adminJobsFilterRunnerType: true },
+ ...provideOptions,
+ },
+ });
+ };
+
+ it('displays filtered search', () => {
+ createComponent();
+
+ expect(findFilteredSearch().exists()).toBe(true);
+ });
+
+ it('displays status token', () => {
+ createComponent();
+
+ expect(findStatusToken()).toMatchObject({
+ type: TOKEN_TYPE_STATUS,
+ icon: 'status',
+ title: TOKEN_TITLE_STATUS,
+ unique: true,
+ operators: OPERATORS_IS,
+ });
+ });
+
+ it('displays token for runner type', () => {
+ createComponent();
+
+ expect(findRunnerTypeToken()).toMatchObject({
+ type: TOKEN_TYPE_JOBS_RUNNER_TYPE,
+ title: TOKEN_TITLE_JOBS_RUNNER_TYPE,
+ operators: OPERATORS_IS,
+ });
+ });
+
+ it('emits filter token to parent component', () => {
+ createComponent();
+
+ findFilteredSearch().vm.$emit('submit', mockFailedSearchToken);
+
+ expect(wrapper.emitted('filterJobsBySearch')).toEqual([[mockFailedSearchToken]]);
+ });
+
+ it('filtered search value is empty array when no query string is passed', () => {
+ createComponent();
+
+ expect(findFilteredSearch().props('value')).toEqual([]);
+ });
+
+ describe('with query string passed', () => {
+ it('filtered search returns correct data shape', () => {
+ const tokenStatusesValue = 'SUCCESS';
+ const tokenRunnerTypesValue = 'INSTANCE_VALUE';
+
+ createComponent({
+ queryString: { statuses: tokenStatusesValue, runnerTypes: tokenRunnerTypesValue },
+ });
+
+ expect(findFilteredSearch().props('value')).toEqual([
+ { type: TOKEN_TYPE_STATUS, value: { data: tokenStatusesValue, operator: '=' } },
+ {
+ type: TOKEN_TYPE_JOBS_RUNNER_TYPE,
+ value: { data: tokenRunnerTypesValue, operator: '=' },
+ },
+ ]);
+ });
+ });
+
+ describe('when feature flag `adminJobsFilterRunnerType` is disabled', () => {
+ const provideOptions = { glFeatures: { adminJobsFilterRunnerType: false } };
+
+ it('does not display token for runner type', () => {
+ createComponent(null, provideOptions);
+
+ expect(findRunnerTypeToken()).toBeUndefined();
+ });
+
+ describe('with query string passed', () => {
+ it('filtered search returns only data shape for search token `status` and not for search token `jobs runner type`', () => {
+ const tokenStatusesValue = 'SUCCESS';
+ const tokenRunnerTypesValue = 'INSTANCE_VALUE';
+
+ createComponent(
+ { queryString: { statuses: tokenStatusesValue, runnerTypes: tokenRunnerTypesValue } },
+ provideOptions,
+ );
+
+ expect(findFilteredSearch().props('value')).toEqual([
+ { type: TOKEN_TYPE_STATUS, value: { data: tokenStatusesValue, operator: '=' } },
+ ]);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/common/private/jobs_filtered_search/tokens/job_status_token_spec.js b/spec/frontend/ci/common/private/jobs_filtered_search/tokens/job_status_token_spec.js
new file mode 100644
index 00000000000..78a1963d939
--- /dev/null
+++ b/spec/frontend/ci/common/private/jobs_filtered_search/tokens/job_status_token_spec.js
@@ -0,0 +1,58 @@
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { stubComponent } from 'helpers/stub_component';
+import JobStatusToken from '~/ci/common/private/jobs_filtered_search/tokens/job_status_token.vue';
+import {
+ TOKEN_TITLE_STATUS,
+ TOKEN_TYPE_STATUS,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+
+describe('Job Status Token', () => {
+ let wrapper;
+
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
+ const findAllFilteredSearchSuggestions = () =>
+ wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const findAllGlIcons = () => wrapper.findAllComponents(GlIcon);
+
+ const defaultProps = {
+ config: {
+ type: TOKEN_TYPE_STATUS,
+ icon: 'status',
+ title: TOKEN_TITLE_STATUS,
+ unique: true,
+ },
+ value: {
+ data: '',
+ },
+ cursorPosition: 'start',
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMount(JobStatusToken, {
+ propsData: {
+ ...defaultProps,
+ },
+ stubs: {
+ GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
+ template: `<div><slot name="suggestions"></slot></div>`,
+ }),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('passes config correctly', () => {
+ expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
+ });
+
+ it('renders all job statuses available', () => {
+ const expectedLength = 11;
+
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(expectedLength);
+ expect(findAllGlIcons()).toHaveLength(expectedLength);
+ });
+});
diff --git a/spec/frontend/ci/common/private/jobs_filtered_search/utils_spec.js b/spec/frontend/ci/common/private/jobs_filtered_search/utils_spec.js
new file mode 100644
index 00000000000..8f6d2368bf4
--- /dev/null
+++ b/spec/frontend/ci/common/private/jobs_filtered_search/utils_spec.js
@@ -0,0 +1,22 @@
+import { validateQueryString } from '~/ci/common/private/jobs_filtered_search/utils';
+
+describe('Filtered search utils', () => {
+ describe('validateQueryString', () => {
+ it.each`
+ queryStringObject | expected
+ ${{ statuses: 'SUCCESS' }} | ${{ statuses: 'SUCCESS' }}
+ ${{ statuses: 'failed' }} | ${{ statuses: 'FAILED' }}
+ ${{ runnerTypes: 'instance_type' }} | ${{ runnerTypes: 'INSTANCE_TYPE' }}
+ ${{ runnerTypes: 'wrong_runner_type' }} | ${null}
+ ${{ statuses: 'SUCCESS', runnerTypes: 'instance_type' }} | ${{ statuses: 'SUCCESS', runnerTypes: 'INSTANCE_TYPE' }}
+ ${{ wrong: 'SUCCESS' }} | ${null}
+ ${{ statuses: 'wrong' }} | ${null}
+ ${{ wrong: 'wrong' }} | ${null}
+ `(
+ 'when provided $queryStringObject, the expected result is $expected',
+ ({ queryStringObject, expected }) => {
+ expect(validateQueryString(queryStringObject)).toEqual(expected);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/empty_state_spec.js b/spec/frontend/ci/job_details/components/empty_state_spec.js
new file mode 100644
index 00000000000..992ed88e81b
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/empty_state_spec.js
@@ -0,0 +1,140 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import EmptyState from '~/ci/job_details/components/empty_state.vue';
+import ManualVariablesForm from '~/ci/job_details/components/manual_variables_form.vue';
+import { mockFullPath, mockId } from '../mock_data';
+
+describe('Empty State', () => {
+ let wrapper;
+
+ const defaultProps = {
+ illustrationPath: 'illustrations/pending_job_empty.svg',
+ illustrationSizeClass: 'svg-430',
+ jobId: mockId,
+ title: 'This job has not started yet',
+ playable: false,
+ isRetryable: true,
+ };
+
+ const createWrapper = (props) => {
+ wrapper = shallowMountExtended(EmptyState, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: {
+ projectPath: mockFullPath,
+ },
+ });
+ };
+
+ const content = 'This job is in pending state and is waiting to be picked by a runner';
+
+ const findEmptyStateImage = () => wrapper.find('img');
+ const findTitle = () => wrapper.findByTestId('job-empty-state-title');
+ const findContent = () => wrapper.findByTestId('job-empty-state-content');
+ const findAction = () => wrapper.findByTestId('job-empty-state-action');
+ const findManualVarsForm = () => wrapper.findComponent(ManualVariablesForm);
+
+ describe('renders image and title', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('renders empty state image', () => {
+ expect(findEmptyStateImage().exists()).toBe(true);
+ });
+
+ it('renders provided title', () => {
+ expect(findTitle().text().trim()).toBe(defaultProps.title);
+ });
+ });
+
+ describe('with content', () => {
+ beforeEach(() => {
+ createWrapper({ content });
+ });
+
+ it('renders content', () => {
+ expect(findContent().text().trim()).toBe(content);
+ });
+ });
+
+ describe('without content', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('does not render content', () => {
+ expect(findContent().exists()).toBe(false);
+ });
+ });
+
+ describe('with action', () => {
+ beforeEach(() => {
+ createWrapper({
+ action: {
+ path: 'runner',
+ button_title: 'Check runner',
+ method: 'post',
+ },
+ });
+ });
+
+ it('renders action', () => {
+ expect(findAction().attributes('href')).toBe('runner');
+ });
+ });
+
+ describe('without action', () => {
+ beforeEach(() => {
+ createWrapper({
+ action: null,
+ });
+ });
+
+ it('does not render action', () => {
+ expect(findAction().exists()).toBe(false);
+ });
+
+ it('does not render manual variables form', () => {
+ expect(findManualVarsForm().exists()).toBe(false);
+ });
+ });
+
+ describe('with playable action and not scheduled job', () => {
+ beforeEach(() => {
+ createWrapper({
+ content,
+ playable: true,
+ scheduled: false,
+ action: {
+ path: 'runner',
+ button_title: 'Check runner',
+ method: 'post',
+ },
+ });
+ });
+
+ it('renders manual variables form', () => {
+ expect(findManualVarsForm().exists()).toBe(true);
+ });
+
+ it('does not render the empty state action', () => {
+ expect(findAction().exists()).toBe(false);
+ });
+ });
+
+ describe('with playable action and scheduled job', () => {
+ beforeEach(() => {
+ createWrapper({
+ playable: true,
+ scheduled: true,
+ content,
+ });
+ });
+
+ it('does not render manual variables form', () => {
+ expect(findManualVarsForm().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/environments_block_spec.js b/spec/frontend/ci/job_details/components/environments_block_spec.js
new file mode 100644
index 00000000000..56ae6b44e9a
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/environments_block_spec.js
@@ -0,0 +1,260 @@
+import { mount } from '@vue/test-utils';
+import EnvironmentsBlock from '~/ci/job_details/components/environments_block.vue';
+
+const TEST_CLUSTER_NAME = 'test_cluster';
+const TEST_CLUSTER_PATH = 'path/to/test_cluster';
+const TEST_KUBERNETES_NAMESPACE = 'this-is-a-kubernetes-namespace';
+
+describe('Environments block', () => {
+ let wrapper;
+
+ const status = {
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed',
+ };
+
+ const environment = {
+ environment_path: '/environment',
+ name: 'environment',
+ };
+
+ const lastDeployment = { iid: 'deployment', deployable: { build_path: 'bar' } };
+
+ const createEnvironmentWithLastDeployment = () => ({
+ ...environment,
+ last_deployment: { ...lastDeployment },
+ });
+
+ const createDeploymentWithCluster = () => ({ name: TEST_CLUSTER_NAME, path: TEST_CLUSTER_PATH });
+
+ const createDeploymentWithClusterAndKubernetesNamespace = () => ({
+ name: TEST_CLUSTER_NAME,
+ path: TEST_CLUSTER_PATH,
+ kubernetes_namespace: TEST_KUBERNETES_NAMESPACE,
+ });
+
+ const createComponent = (deploymentStatus = {}, deploymentCluster = {}) => {
+ wrapper = mount(EnvironmentsBlock, {
+ propsData: {
+ deploymentStatus,
+ deploymentCluster,
+ iconStatus: status,
+ },
+ });
+ };
+
+ const findText = () => wrapper.findComponent(EnvironmentsBlock).text();
+ const findJobDeploymentLink = () => wrapper.find('[data-testid="job-deployment-link"]');
+ const findEnvironmentLink = () => wrapper.find('[data-testid="job-environment-link"]');
+ const findClusterLink = () => wrapper.find('[data-testid="job-cluster-link"]');
+
+ describe('with last deployment', () => {
+ it('renders info for most recent deployment', () => {
+ createComponent({
+ status: 'last',
+ environment,
+ });
+
+ expect(findText()).toBe('This job is deployed to environment.');
+ });
+
+ describe('when there is a cluster', () => {
+ it('renders info with cluster', () => {
+ createComponent(
+ {
+ status: 'last',
+ environment: createEnvironmentWithLastDeployment(),
+ },
+ createDeploymentWithCluster(),
+ );
+
+ expect(findText()).toBe(
+ `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME}.`,
+ );
+ });
+
+ describe('when there is a kubernetes namespace', () => {
+ it('renders info with cluster', () => {
+ createComponent(
+ {
+ status: 'last',
+ environment: createEnvironmentWithLastDeployment(),
+ },
+ createDeploymentWithClusterAndKubernetesNamespace(),
+ );
+
+ expect(findText()).toBe(
+ `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME} and namespace ${TEST_KUBERNETES_NAMESPACE}.`,
+ );
+ });
+ });
+ });
+ });
+
+ describe('with out of date deployment', () => {
+ describe('with last deployment', () => {
+ it('renders info for out date and most recent', () => {
+ createComponent({
+ status: 'out_of_date',
+ environment: createEnvironmentWithLastDeployment(),
+ });
+
+ expect(findText()).toBe(
+ 'This job is an out-of-date deployment to environment. View the most recent deployment.',
+ );
+
+ expect(findJobDeploymentLink().attributes('href')).toBe('bar');
+ });
+
+ describe('when there is a cluster', () => {
+ it('renders info with cluster', () => {
+ createComponent(
+ {
+ status: 'out_of_date',
+ environment: createEnvironmentWithLastDeployment(),
+ },
+ createDeploymentWithCluster(),
+ );
+
+ expect(findText()).toBe(
+ `This job is an out-of-date deployment to environment using cluster ${TEST_CLUSTER_NAME}. View the most recent deployment.`,
+ );
+ });
+
+ describe('when there is a kubernetes namespace', () => {
+ it('renders info with cluster', () => {
+ createComponent(
+ {
+ status: 'out_of_date',
+ environment: createEnvironmentWithLastDeployment(),
+ },
+ createDeploymentWithClusterAndKubernetesNamespace(),
+ );
+
+ expect(findText()).toBe(
+ `This job is an out-of-date deployment to environment using cluster ${TEST_CLUSTER_NAME} and namespace ${TEST_KUBERNETES_NAMESPACE}. View the most recent deployment.`,
+ );
+ });
+ });
+ });
+ });
+
+ describe('without last deployment', () => {
+ it('renders info about out of date deployment', () => {
+ createComponent({
+ status: 'out_of_date',
+ environment,
+ });
+
+ expect(findText()).toBe('This job is an out-of-date deployment to environment.');
+ });
+ });
+ });
+
+ describe('with failed deployment', () => {
+ it('renders info about failed deployment', () => {
+ createComponent({
+ status: 'failed',
+ environment,
+ });
+
+ expect(findText()).toBe('The deployment of this job to environment did not succeed.');
+ });
+ });
+
+ describe('creating deployment', () => {
+ describe('with last deployment', () => {
+ it('renders info about creating deployment and overriding latest deployment', () => {
+ createComponent({
+ status: 'creating',
+ environment: createEnvironmentWithLastDeployment(),
+ });
+
+ expect(findText()).toBe(
+ 'This job is creating a deployment to environment. This will overwrite the latest deployment.',
+ );
+
+ expect(findEnvironmentLink().attributes('href')).toBe(environment.environment_path);
+
+ expect(findJobDeploymentLink().attributes('href')).toBe('bar');
+
+ expect(findClusterLink().exists()).toBe(false);
+ });
+ });
+
+ describe('without last deployment', () => {
+ it('renders info about deployment being created', () => {
+ createComponent({
+ status: 'creating',
+ environment,
+ });
+
+ expect(findText()).toBe('This job is creating a deployment to environment.');
+ });
+
+ describe('when there is a cluster', () => {
+ it('inclues information about the cluster', () => {
+ createComponent(
+ {
+ status: 'creating',
+ environment,
+ },
+ createDeploymentWithCluster(),
+ );
+
+ expect(findText()).toBe(
+ `This job is creating a deployment to environment using cluster ${TEST_CLUSTER_NAME}.`,
+ );
+ });
+ });
+ });
+
+ describe('without environment', () => {
+ it('does not render environment link', () => {
+ createComponent({
+ status: 'creating',
+ environment: null,
+ });
+
+ expect(findEnvironmentLink().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('with a cluster', () => {
+ it('renders the cluster link', () => {
+ createComponent(
+ {
+ status: 'last',
+ environment: createEnvironmentWithLastDeployment(),
+ },
+ createDeploymentWithCluster(),
+ );
+
+ expect(findText()).toBe(
+ `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME}.`,
+ );
+
+ expect(findClusterLink().attributes('href')).toBe(TEST_CLUSTER_PATH);
+ });
+
+ describe('when the cluster is missing the path', () => {
+ it('renders the name without a link', () => {
+ createComponent(
+ {
+ status: 'last',
+ environment: createEnvironmentWithLastDeployment(),
+ },
+ { name: 'the-cluster' },
+ );
+
+ expect(findText()).toContain('using cluster the-cluster.');
+
+ expect(findClusterLink().exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/erased_block_spec.js b/spec/frontend/ci/job_details/components/erased_block_spec.js
new file mode 100644
index 00000000000..7eb856f97f1
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/erased_block_spec.js
@@ -0,0 +1,59 @@
+import { GlLink } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import ErasedBlock from '~/ci/job_details/components/erased_block.vue';
+import { getTimeago } from '~/lib/utils/datetime_utility';
+
+describe('Erased block', () => {
+ let wrapper;
+
+ const erasedAt = '2016-11-07T11:11:16.525Z';
+ const timeago = getTimeago();
+ const formattedDate = timeago.format(erasedAt);
+
+ const findLink = () => wrapper.findComponent(GlLink);
+
+ const createComponent = (props) => {
+ wrapper = mount(ErasedBlock, {
+ propsData: props,
+ });
+ };
+
+ describe('with job erased by user', () => {
+ beforeEach(() => {
+ createComponent({
+ user: {
+ username: 'root',
+ web_url: 'gitlab.com/root',
+ },
+ erasedAt,
+ });
+ });
+
+ it('renders username and link', () => {
+ expect(findLink().attributes('href')).toEqual('gitlab.com/root');
+
+ expect(wrapper.text().trim()).toContain('Job has been erased by');
+ expect(wrapper.text().trim()).toContain('root');
+ });
+
+ it('renders erasedAt', () => {
+ expect(wrapper.text().trim()).toContain(formattedDate);
+ });
+ });
+
+ describe('with erased job', () => {
+ beforeEach(() => {
+ createComponent({
+ erasedAt,
+ });
+ });
+
+ it('renders username and link', () => {
+ expect(wrapper.text().trim()).toContain('Job has been erased');
+ });
+
+ it('renders erasedAt', () => {
+ expect(wrapper.text().trim()).toContain(formattedDate);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/job_header_spec.js b/spec/frontend/ci/job_details/components/job_header_spec.js
new file mode 100644
index 00000000000..6fc55732353
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/job_header_spec.js
@@ -0,0 +1,154 @@
+import { GlButton, GlAvatarLink, GlTooltip } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import JobHeader from '~/ci/job_details/components/job_header.vue';
+import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+describe('Header CI Component', () => {
+ let wrapper;
+
+ const defaultProps = {
+ status: {
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ details_path: 'path',
+ },
+ name: 'Job build_job',
+ time: '2017-05-08T14:57:39.781Z',
+ user: {
+ id: 1234,
+ web_url: 'path',
+ name: 'Foo',
+ username: 'foobar',
+ email: 'foo@bar.com',
+ avatar_url: 'link',
+ },
+ shouldRenderTriggeredLabel: true,
+ };
+
+ const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
+ const findTimeAgo = () => wrapper.findComponent(TimeagoTooltip);
+ const findUserLink = () => wrapper.findComponent(GlAvatarLink);
+ const findSidebarToggleBtn = () => wrapper.findComponent(GlButton);
+ const findStatusTooltip = () => wrapper.findComponent(GlTooltip);
+ const findActionButtons = () => wrapper.findByTestId('job-header-action-buttons');
+ const findJobName = () => wrapper.findByTestId('job-name');
+
+ const createComponent = (props, slots) => {
+ wrapper = extendedWrapper(
+ shallowMount(JobHeader, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ ...slots,
+ }),
+ );
+ };
+
+ describe('render', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should render status badge', () => {
+ expect(findCiBadgeLink().exists()).toBe(true);
+ });
+
+ it('should render timeago date', () => {
+ expect(findTimeAgo().exists()).toBe(true);
+ });
+
+ it('should render sidebar toggle button', () => {
+ expect(findSidebarToggleBtn().exists()).toBe(true);
+ });
+
+ it('should not render header action buttons when slot is empty', () => {
+ expect(findActionButtons().exists()).toBe(false);
+ });
+ });
+
+ describe('user avatar', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('contains the username', () => {
+ expect(findUserLink().text()).toContain(defaultProps.user.username);
+ });
+
+ it('has the correct HTML attributes', () => {
+ expect(findUserLink().attributes()).toMatchObject({
+ 'data-user-id': defaultProps.user.id.toString(),
+ 'data-username': defaultProps.user.username,
+ 'data-name': defaultProps.user.name,
+ href: defaultProps.user.web_url,
+ });
+ });
+
+ describe('when the user has a status', () => {
+ const STATUS_MESSAGE = 'Working on exciting features...';
+
+ beforeEach(() => {
+ createComponent({
+ user: { ...defaultProps.user, status: { message: STATUS_MESSAGE } },
+ });
+ });
+
+ it('renders a tooltip', () => {
+ expect(findStatusTooltip().text()).toBe(STATUS_MESSAGE);
+ });
+ });
+
+ describe('with data from GraphQL', () => {
+ const userId = 1;
+
+ beforeEach(() => {
+ createComponent({
+ user: { ...defaultProps.user, id: `gid://gitlab/User/${1}` },
+ });
+ });
+
+ it('has the correct user id', () => {
+ expect(findUserLink().attributes('data-user-id')).toBe(userId.toString());
+ });
+ });
+
+ describe('with data from REST', () => {
+ it('has the correct user id', () => {
+ expect(findUserLink().attributes('data-user-id')).toBe(defaultProps.user.id.toString());
+ });
+ });
+ });
+
+ describe('job name', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should render the job name', () => {
+ expect(findJobName().text()).toBe('Job build_job');
+ });
+ });
+
+ describe('slot', () => {
+ it('should render header action buttons', () => {
+ createComponent({}, { slots: { default: 'Test Actions' } });
+
+ expect(findActionButtons().exists()).toBe(true);
+ expect(findActionButtons().text()).toBe('Test Actions');
+ });
+ });
+
+ describe('shouldRenderTriggeredLabel', () => {
+ it('should render created keyword when the shouldRenderTriggeredLabel is false', () => {
+ createComponent({ shouldRenderTriggeredLabel: false });
+
+ expect(wrapper.text()).toContain('created');
+ expect(wrapper.text()).not.toContain('started');
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/job_log_controllers_spec.js b/spec/frontend/ci/job_details/components/job_log_controllers_spec.js
new file mode 100644
index 00000000000..84c664aca34
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/job_log_controllers_spec.js
@@ -0,0 +1,321 @@
+import { GlSearchBoxByClick } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import JobLogControllers from '~/ci/job_details/components/job_log_controllers.vue';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
+import { backoffMockImplementation } from 'helpers/backoff_helper';
+import * as commonUtils from '~/lib/utils/common_utils';
+import { mockJobLog } from 'jest/ci/jobs_mock_data';
+
+const mockToastShow = jest.fn();
+
+describe('Job log controllers', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation);
+ });
+
+ afterEach(() => {
+ commonUtils.backOff.mockReset();
+ });
+
+ const defaultProps = {
+ rawPath: '/raw',
+ size: 511952,
+ isScrollTopDisabled: false,
+ isScrollBottomDisabled: false,
+ isScrollingDown: true,
+ isJobLogSizeVisible: true,
+ isComplete: true,
+ jobLog: mockJobLog,
+ };
+
+ const createWrapper = (props, { jobLogJumpToFailures = false } = {}) => {
+ wrapper = mount(JobLogControllers, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: {
+ glFeatures: {
+ jobLogJumpToFailures,
+ },
+ },
+ data() {
+ return {
+ searchTerm: '82',
+ };
+ },
+ mocks: {
+ $toast: {
+ show: mockToastShow,
+ },
+ },
+ });
+ };
+
+ const findTruncatedInfo = () => wrapper.find('[data-testid="log-truncated-info"]');
+ const findRawLink = () => wrapper.find('[data-testid="raw-link"]');
+ const findRawLinkController = () => wrapper.find('[data-testid="job-raw-link-controller"]');
+ const findScrollTop = () => wrapper.find('[data-testid="job-controller-scroll-top"]');
+ const findScrollBottom = () => wrapper.find('[data-testid="job-controller-scroll-bottom"]');
+ const findJobLogSearch = () => wrapper.findComponent(GlSearchBoxByClick);
+ const findSearchHelp = () => wrapper.findComponent(HelpPopover);
+ const findScrollFailure = () => wrapper.find('[data-testid="job-controller-scroll-to-failure"]');
+
+ describe('Truncate information', () => {
+ describe('with isJobLogSizeVisible', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('renders size information', () => {
+ expect(findTruncatedInfo().text()).toMatch('499.95 KiB');
+ });
+
+ it('renders link to raw job log', () => {
+ expect(findRawLink().attributes('href')).toBe(defaultProps.rawPath);
+ });
+ });
+ });
+
+ describe('links section', () => {
+ describe('with raw job log path', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('renders raw job log link', () => {
+ expect(findRawLinkController().attributes('href')).toBe(defaultProps.rawPath);
+ });
+ });
+
+ describe('without raw job log path', () => {
+ beforeEach(() => {
+ createWrapper({
+ rawPath: null,
+ });
+ });
+
+ it('does not render raw job log link', () => {
+ expect(findRawLinkController().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('scroll buttons', () => {
+ describe('scroll top button', () => {
+ describe('when user can scroll top', () => {
+ beforeEach(() => {
+ createWrapper({
+ isScrollTopDisabled: false,
+ });
+ });
+
+ it('emits scrollJobLogTop event on click', async () => {
+ await findScrollTop().trigger('click');
+
+ expect(wrapper.emitted().scrollJobLogTop).toHaveLength(1);
+ });
+ });
+
+ describe('when user can not scroll top', () => {
+ beforeEach(() => {
+ createWrapper({
+ isScrollTopDisabled: true,
+ isScrollBottomDisabled: false,
+ isScrollingDown: false,
+ });
+ });
+
+ it('renders disabled scroll top button', () => {
+ expect(findScrollTop().attributes('disabled')).toBeDefined();
+ });
+
+ it('does not emit scrollJobLogTop event on click', async () => {
+ await findScrollTop().trigger('click');
+
+ expect(wrapper.emitted().scrollJobLogTop).toBeUndefined();
+ });
+ });
+ });
+
+ describe('scroll bottom button', () => {
+ describe('when user can scroll bottom', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('emits scrollJobLogBottom event on click', async () => {
+ await findScrollBottom().trigger('click');
+
+ expect(wrapper.emitted().scrollJobLogBottom).toHaveLength(1);
+ });
+ });
+
+ describe('when user can not scroll bottom', () => {
+ beforeEach(() => {
+ createWrapper({
+ isScrollTopDisabled: false,
+ isScrollBottomDisabled: true,
+ isScrollingDown: false,
+ });
+ });
+
+ it('renders disabled scroll bottom button', () => {
+ expect(findScrollBottom().attributes('disabled')).toEqual('disabled');
+ });
+
+ it('does not emit scrollJobLogBottom event on click', async () => {
+ await findScrollBottom().trigger('click');
+
+ expect(wrapper.emitted().scrollJobLogBottom).toBeUndefined();
+ });
+ });
+
+ describe('while isScrollingDown is true', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('renders animate class for the scroll down button', () => {
+ expect(findScrollBottom().classes()).toContain('animate');
+ });
+ });
+
+ describe('while isScrollingDown is false', () => {
+ beforeEach(() => {
+ createWrapper({
+ isScrollTopDisabled: true,
+ isScrollBottomDisabled: false,
+ isScrollingDown: false,
+ });
+ });
+
+ it('does not render animate class for the scroll down button', () => {
+ expect(findScrollBottom().classes()).not.toContain('animate');
+ });
+ });
+ });
+
+ describe('scroll to failure button', () => {
+ describe('with feature flag disabled', () => {
+ it('does not display button', () => {
+ createWrapper();
+
+ expect(findScrollFailure().exists()).toBe(false);
+ });
+ });
+
+ describe('with red text failures on the page', () => {
+ let firstFailure;
+ let secondFailure;
+
+ beforeEach(() => {
+ jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce(['mock-element']);
+
+ createWrapper({}, { jobLogJumpToFailures: true });
+
+ firstFailure = document.createElement('div');
+ firstFailure.className = 'term-fg-l-red';
+ document.body.appendChild(firstFailure);
+
+ secondFailure = document.createElement('div');
+ secondFailure.className = 'term-fg-l-red';
+ document.body.appendChild(secondFailure);
+ });
+
+ afterEach(() => {
+ if (firstFailure) {
+ firstFailure.remove();
+ firstFailure = null;
+ }
+
+ if (secondFailure) {
+ secondFailure.remove();
+ secondFailure = null;
+ }
+ });
+
+ it('is enabled', () => {
+ expect(findScrollFailure().props('disabled')).toBe(false);
+ });
+
+ it('scrolls to each failure', async () => {
+ jest.spyOn(firstFailure, 'scrollIntoView');
+
+ await findScrollFailure().trigger('click');
+
+ expect(firstFailure.scrollIntoView).toHaveBeenCalled();
+
+ await findScrollFailure().trigger('click');
+
+ expect(secondFailure.scrollIntoView).toHaveBeenCalled();
+
+ await findScrollFailure().trigger('click');
+
+ expect(firstFailure.scrollIntoView).toHaveBeenCalled();
+ });
+ });
+
+ describe('with no red text failures on the page', () => {
+ beforeEach(() => {
+ jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce([]);
+
+ createWrapper({}, { jobLogJumpToFailures: true });
+ });
+
+ it('is disabled', () => {
+ expect(findScrollFailure().props('disabled')).toBe(true);
+ });
+ });
+
+ describe('when the job log is not complete', () => {
+ beforeEach(() => {
+ jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce(['mock-element']);
+
+ createWrapper({ isComplete: false }, { jobLogJumpToFailures: true });
+ });
+
+ it('is enabled', () => {
+ expect(findScrollFailure().props('disabled')).toBe(false);
+ });
+ });
+
+ describe('on error', () => {
+ beforeEach(() => {
+ jest.spyOn(commonUtils, 'backOff').mockRejectedValueOnce();
+
+ createWrapper({}, { jobLogJumpToFailures: true });
+ });
+
+ it('stays disabled', () => {
+ expect(findScrollFailure().props('disabled')).toBe(true);
+ });
+ });
+ });
+ });
+
+ describe('Job log search', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('displays job log search', () => {
+ expect(findJobLogSearch().exists()).toBe(true);
+ expect(findSearchHelp().exists()).toBe(true);
+ });
+
+ it('emits search results', () => {
+ findJobLogSearch().vm.$emit('submit');
+
+ expect(wrapper.emitted('searchResults')).toHaveLength(1);
+ });
+
+ it('clears search results', () => {
+ findJobLogSearch().vm.$emit('clear');
+
+ expect(wrapper.emitted('searchResults')).toEqual([[[]]]);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/log/collapsible_section_spec.js b/spec/frontend/ci/job_details/components/log/collapsible_section_spec.js
new file mode 100644
index 00000000000..e3d5c448338
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/log/collapsible_section_spec.js
@@ -0,0 +1,95 @@
+import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import CollapsibleSection from '~/ci/job_details/components/log/collapsible_section.vue';
+import LogLineHeader from '~/ci/job_details/components/log/line_header.vue';
+import { collapsibleSectionClosed, collapsibleSectionOpened } from './mock_data';
+
+describe('Job Log Collapsible Section', () => {
+ let wrapper;
+
+ const jobLogEndpoint = 'jobs/335';
+
+ const findCollapsibleLine = () => wrapper.find('.collapsible-line');
+ const findCollapsibleLineSvg = () => wrapper.find('.collapsible-line svg');
+ const findLogLineHeader = () => wrapper.findComponent(LogLineHeader);
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(CollapsibleSection, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ describe('with closed section', () => {
+ beforeEach(() => {
+ createComponent({
+ section: collapsibleSectionClosed,
+ jobLogEndpoint,
+ });
+ });
+
+ it('renders clickable header line', () => {
+ expect(findCollapsibleLine().attributes('role')).toBe('button');
+ });
+
+ it('renders an icon with the closed state', () => {
+ expect(findCollapsibleLineSvg().attributes('data-testid')).toBe('chevron-lg-right-icon');
+ });
+ });
+
+ describe('with opened section', () => {
+ beforeEach(() => {
+ createComponent({
+ section: collapsibleSectionOpened,
+ jobLogEndpoint,
+ });
+ });
+
+ it('renders clickable header line', () => {
+ expect(findCollapsibleLine().attributes('role')).toBe('button');
+ });
+
+ it('renders an icon with the open state', () => {
+ expect(findCollapsibleLineSvg().attributes('data-testid')).toBe('chevron-lg-down-icon');
+ });
+
+ it('renders collapsible lines content', () => {
+ expect(wrapper.findAll('.js-line').length).toEqual(collapsibleSectionOpened.lines.length);
+ });
+ });
+
+ it('emits onClickCollapsibleLine on click', async () => {
+ createComponent({
+ section: collapsibleSectionOpened,
+ jobLogEndpoint,
+ });
+
+ findCollapsibleLine().trigger('click');
+
+ await nextTick();
+ expect(wrapper.emitted('onClickCollapsibleLine').length).toBe(1);
+ });
+
+ describe('with search results', () => {
+ it('passes isHighlighted prop correctly', () => {
+ const mockSearchResults = [
+ {
+ content: [{ text: 'foo' }],
+ lineNumber: 1,
+ offset: 5,
+ section: 'prepare-script',
+ section_header: true,
+ },
+ ];
+
+ createComponent({
+ section: collapsibleSectionOpened,
+ jobLogEndpoint,
+ searchResults: mockSearchResults,
+ });
+
+ expect(findLogLineHeader().props('isHighlighted')).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/log/duration_badge_spec.js b/spec/frontend/ci/job_details/components/log/duration_badge_spec.js
new file mode 100644
index 00000000000..0d5f60cefd1
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/log/duration_badge_spec.js
@@ -0,0 +1,26 @@
+import { shallowMount } from '@vue/test-utils';
+import DurationBadge from '~/ci/job_details/components/log/duration_badge.vue';
+
+describe('Job Log Duration Badge', () => {
+ let wrapper;
+
+ const data = {
+ duration: '00:30:01',
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(DurationBadge, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent(data);
+ });
+
+ it('renders provided duration', () => {
+ expect(wrapper.text()).toBe(data.duration);
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/log/line_header_spec.js b/spec/frontend/ci/job_details/components/log/line_header_spec.js
new file mode 100644
index 00000000000..7d1b05346f2
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/log/line_header_spec.js
@@ -0,0 +1,133 @@
+import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import DurationBadge from '~/ci/job_details/components/log/duration_badge.vue';
+import LineHeader from '~/ci/job_details/components/log/line_header.vue';
+import LineNumber from '~/ci/job_details/components/log/line_number.vue';
+
+describe('Job Log Header Line', () => {
+ let wrapper;
+
+ const defaultProps = {
+ line: {
+ content: [
+ {
+ text: 'Running with gitlab-runner 12.1.0 (de7731dd)',
+ style: 'term-fg-l-green',
+ },
+ ],
+ lineNumber: 76,
+ },
+ isClosed: true,
+ path: '/jashkenas/underscore/-/jobs/335',
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = mount(LineHeader, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ describe('line', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the line number component', () => {
+ expect(wrapper.findComponent(LineNumber).exists()).toBe(true);
+ });
+
+ it('renders a span the provided text', () => {
+ expect(wrapper.find('span').text()).toBe(defaultProps.line.content[0].text);
+ });
+
+ it('renders the provided style as a class attribute', () => {
+ expect(wrapper.find('span').classes()).toContain(defaultProps.line.content[0].style);
+ });
+ });
+
+ describe('when isCloses is true', () => {
+ beforeEach(() => {
+ createComponent({ ...defaultProps, isClosed: true });
+ });
+
+ it('sets icon name to be chevron-lg-right', () => {
+ expect(wrapper.vm.iconName).toEqual('chevron-lg-right');
+ });
+ });
+
+ describe('when isCloses is false', () => {
+ beforeEach(() => {
+ createComponent({ ...defaultProps, isClosed: false });
+ });
+
+ it('sets icon name to be chevron-lg-down', () => {
+ expect(wrapper.vm.iconName).toEqual('chevron-lg-down');
+ });
+ });
+
+ describe('on click', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('emits toggleLine event', async () => {
+ wrapper.trigger('click');
+
+ await nextTick();
+ expect(wrapper.emitted().toggleLine.length).toBe(1);
+ });
+ });
+
+ describe('with duration', () => {
+ beforeEach(() => {
+ createComponent({ ...defaultProps, duration: '00:10' });
+ });
+
+ it('renders the duration badge', () => {
+ expect(wrapper.findComponent(DurationBadge).exists()).toBe(true);
+ });
+ });
+
+ describe('line highlighting', () => {
+ describe('with hash', () => {
+ beforeEach(() => {
+ setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353#L77`);
+
+ createComponent();
+ });
+
+ it('highlights line', () => {
+ expect(wrapper.classes()).toContain('gl-bg-gray-700');
+ });
+ });
+
+ describe('without hash', () => {
+ beforeEach(() => {
+ setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353`);
+
+ createComponent();
+ });
+
+ it('does not highlight line', () => {
+ expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
+ });
+ });
+
+ describe('search results', () => {
+ it('highlights the job log lines', () => {
+ createComponent({ ...defaultProps, isHighlighted: true });
+
+ expect(wrapper.classes()).toContain('gl-bg-gray-700');
+ });
+
+ it('does not highlight the job log lines', () => {
+ createComponent();
+
+ expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/log/line_number_spec.js b/spec/frontend/ci/job_details/components/log/line_number_spec.js
new file mode 100644
index 00000000000..d5c1d0fd985
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/log/line_number_spec.js
@@ -0,0 +1,35 @@
+import { shallowMount } from '@vue/test-utils';
+import LineNumber from '~/ci/job_details/components/log/line_number.vue';
+
+describe('Job Log Line Number', () => {
+ let wrapper;
+
+ const data = {
+ lineNumber: 0,
+ path: '/jashkenas/underscore/-/jobs/335',
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(LineNumber, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent(data);
+ });
+
+ it('renders incremented lineNunber by 1', () => {
+ expect(wrapper.text()).toBe('1');
+ });
+
+ it('renders link with lineNumber as an ID', () => {
+ expect(wrapper.attributes().id).toBe('L1');
+ });
+
+ it('links to the provided path with line number as anchor', () => {
+ expect(wrapper.attributes().href).toBe(`${data.path}#L1`);
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/log/line_spec.js b/spec/frontend/ci/job_details/components/log/line_spec.js
new file mode 100644
index 00000000000..b6f3a2b68df
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/log/line_spec.js
@@ -0,0 +1,256 @@
+import { shallowMount } from '@vue/test-utils';
+import Line from '~/ci/job_details/components/log/line.vue';
+import LineNumber from '~/ci/job_details/components/log/line_number.vue';
+import setWindowLocation from 'helpers/set_window_location_helper';
+
+const httpUrl = 'http://example.com';
+const httpsUrl = 'https://example.com';
+const queryUrl = 'https://example.com?param=val';
+
+const mockProps = ({ text = 'Running with gitlab-runner 12.1.0 (de7731dd)' } = {}) => ({
+ line: {
+ content: [
+ {
+ text,
+ style: 'term-fg-l-green',
+ },
+ ],
+ lineNumber: 0,
+ },
+ path: '/jashkenas/underscore/-/jobs/335',
+});
+
+describe('Job Log Line', () => {
+ let wrapper;
+ let data;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(Line, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findLine = () => wrapper.find('span');
+ const findLink = () => findLine().find('a');
+ const findLinks = () => findLine().findAll('a');
+ const findLinkAttributeByIndex = (i) => findLinks().at(i).attributes();
+
+ beforeEach(() => {
+ data = mockProps();
+ createComponent(data);
+ });
+
+ it('renders the line number component', () => {
+ expect(wrapper.findComponent(LineNumber).exists()).toBe(true);
+ });
+
+ it('renders a span the provided text', () => {
+ expect(findLine().text()).toBe(data.line.content[0].text);
+ });
+
+ it('renders the provided style as a class attribute', () => {
+ expect(findLine().classes()).toContain(data.line.content[0].style);
+ });
+
+ describe('job urls as links', () => {
+ it('renders an http link', () => {
+ createComponent(mockProps({ text: httpUrl }));
+
+ expect(findLink().text()).toBe(httpUrl);
+ expect(findLink().attributes().href).toBe(httpUrl);
+ });
+
+ it('renders an https link', () => {
+ createComponent(mockProps({ text: httpsUrl }));
+
+ expect(findLink().text()).toBe(httpsUrl);
+ expect(findLink().attributes().href).toBe(httpsUrl);
+ });
+
+ it('renders a link with rel nofollow and noopener', () => {
+ createComponent(mockProps({ text: httpsUrl }));
+
+ expect(findLink().attributes().rel).toBe('nofollow noopener noreferrer');
+ });
+
+ it('renders a link with corresponding styles', () => {
+ createComponent(mockProps({ text: httpsUrl }));
+
+ expect(findLink().classes()).toEqual(['gl-reset-color!', 'gl-text-decoration-underline']);
+ });
+
+ it('renders links with queries, surrounded by questions marks', () => {
+ createComponent(mockProps({ text: `Did you see my url ${queryUrl}??` }));
+
+ expect(findLine().text()).toBe('Did you see my url https://example.com?param=val??');
+ expect(findLinkAttributeByIndex(0).href).toBe(queryUrl);
+ });
+
+ it('renders links with queries, surrounded by exclamation marks', () => {
+ createComponent(mockProps({ text: `No! The ${queryUrl}!?` }));
+
+ expect(findLine().text()).toBe('No! The https://example.com?param=val!?');
+ expect(findLinkAttributeByIndex(0).href).toBe(queryUrl);
+ });
+
+ it('renders links that have brackets `[]` in their parameters', () => {
+ const url = `${httpUrl}?label_name[]=frontend`;
+
+ createComponent(mockProps({ text: url }));
+
+ expect(findLine().text()).toBe(url);
+ expect(findLinks().at(0).text()).toBe(url);
+ expect(findLinks().at(0).attributes('href')).toBe(url);
+ });
+
+ it('renders multiple links surrounded by text', () => {
+ createComponent(
+ mockProps({ text: `Well, my HTTP url: ${httpUrl} and my HTTPS url: ${httpsUrl}` }),
+ );
+ expect(findLine().text()).toBe(
+ 'Well, my HTTP url: http://example.com and my HTTPS url: https://example.com',
+ );
+
+ expect(findLinks()).toHaveLength(2);
+
+ expect(findLinkAttributeByIndex(0).href).toBe(httpUrl);
+ expect(findLinkAttributeByIndex(1).href).toBe(httpsUrl);
+ });
+
+ it('renders multiple links surrounded by text, with other symbols', () => {
+ createComponent(
+ mockProps({ text: `${httpUrl}, ${httpUrl}: ${httpsUrl}; ${httpsUrl}. ${httpsUrl}...` }),
+ );
+ expect(findLine().text()).toBe(
+ 'http://example.com, http://example.com: https://example.com; https://example.com. https://example.com...',
+ );
+
+ expect(findLinks()).toHaveLength(5);
+
+ expect(findLinkAttributeByIndex(0).href).toBe(httpUrl);
+ expect(findLinkAttributeByIndex(1).href).toBe(httpUrl);
+ expect(findLinkAttributeByIndex(2).href).toBe(httpsUrl);
+ expect(findLinkAttributeByIndex(3).href).toBe(httpsUrl);
+ expect(findLinkAttributeByIndex(4).href).toBe(httpsUrl);
+ });
+
+ it('renders multiple links surrounded by brackets', () => {
+ createComponent(mockProps({ text: `(${httpUrl}) <${httpUrl}> {${httpsUrl}}` }));
+ expect(findLine().text()).toBe(
+ '(http://example.com) <http://example.com> {https://example.com}',
+ );
+
+ const links = findLinks();
+
+ expect(links).toHaveLength(3);
+
+ expect(links.at(0).text()).toBe(httpUrl);
+ expect(links.at(0).attributes('href')).toBe(httpUrl);
+
+ expect(links.at(1).text()).toBe(httpUrl);
+ expect(links.at(1).attributes('href')).toBe(httpUrl);
+
+ expect(links.at(2).text()).toBe(httpsUrl);
+ expect(links.at(2).attributes('href')).toBe(httpsUrl);
+ });
+
+ it('renders text with symbols in it', () => {
+ const text = 'apt-get update < /dev/null > /dev/null';
+ createComponent(mockProps({ text }));
+
+ expect(findLine().text()).toBe(text);
+ });
+
+ const jshref = 'javascript:doEvil();'; // eslint-disable-line no-script-url
+
+ it.each`
+ type | text
+ ${'html link'} | ${'<a href="#">linked</a>'}
+ ${'html script'} | ${'<script>doEvil();</script>'}
+ ${'html strong'} | ${'<strong>highlighted</strong>'}
+ ${'js'} | ${jshref}
+ ${'file'} | ${'file:///a-file'}
+ ${'ftp'} | ${'ftp://example.com/file'}
+ ${'email'} | ${'email@example.com'}
+ ${'no scheme'} | ${'example.com/page'}
+ `('does not render a $type link', ({ text }) => {
+ createComponent(mockProps({ text }));
+ expect(findLink().exists()).toBe(false);
+ });
+ });
+
+ describe('job log search', () => {
+ it('applies highlight class to search result elements', () => {
+ createComponent({
+ line: {
+ offset: 1560,
+ content: [{ text: '82.71' }],
+ section: 'step-script',
+ lineNumber: 21,
+ },
+ path: '/root/ci-project/-/jobs/1089',
+ isHighlighted: true,
+ });
+
+ expect(wrapper.classes()).toContain('gl-bg-gray-700');
+ });
+
+ it('does not apply highlight class to search result elements', () => {
+ createComponent({
+ line: {
+ offset: 1560,
+ content: [{ text: 'docker' }],
+ section: 'step-script',
+ lineNumber: 29,
+ },
+ path: '/root/ci-project/-/jobs/1089',
+ });
+
+ expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
+ });
+ });
+
+ describe('job log hash highlighting', () => {
+ describe('with hash', () => {
+ beforeEach(() => {
+ setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353#L77`);
+ });
+
+ it('applies highlight class to job log line', () => {
+ createComponent({
+ line: {
+ offset: 24526,
+ content: [{ text: 'job log content' }],
+ section: 'custom-section',
+ lineNumber: 76,
+ },
+ path: '/root/ci-project/-/jobs/6353',
+ });
+
+ expect(wrapper.classes()).toContain('gl-bg-gray-700');
+ });
+ });
+
+ describe('without hash', () => {
+ beforeEach(() => {
+ setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353`);
+ });
+
+ it('does not apply highlight class to job log line', () => {
+ createComponent({
+ line: {
+ offset: 24500,
+ content: [{ text: 'line' }],
+ section: 'custom-section',
+ lineNumber: 10,
+ },
+ path: '/root/ci-project/-/jobs/6353',
+ });
+
+ expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/log/log_spec.js b/spec/frontend/ci/job_details/components/log/log_spec.js
new file mode 100644
index 00000000000..cc1621b87d6
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/log/log_spec.js
@@ -0,0 +1,162 @@
+import { mount } from '@vue/test-utils';
+import Vue from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import waitForPromises from 'helpers/wait_for_promises';
+import { scrollToElement } from '~/lib/utils/common_utils';
+import Log from '~/ci/job_details/components/log/log.vue';
+import LogLineHeader from '~/ci/job_details/components/log/line_header.vue';
+import { logLinesParser } from '~/ci/job_details/store/utils';
+import { jobLog } from './mock_data';
+
+jest.mock('~/lib/utils/common_utils', () => ({
+ ...jest.requireActual('~/lib/utils/common_utils'),
+ scrollToElement: jest.fn(),
+}));
+
+describe('Job Log', () => {
+ let wrapper;
+ let actions;
+ let state;
+ let store;
+ let toggleCollapsibleLineMock;
+
+ Vue.use(Vuex);
+
+ const createComponent = (props) => {
+ wrapper = mount(Log, {
+ propsData: {
+ ...props,
+ },
+ store,
+ });
+ };
+
+ beforeEach(() => {
+ toggleCollapsibleLineMock = jest.fn();
+ actions = {
+ toggleCollapsibleLine: toggleCollapsibleLineMock,
+ };
+
+ state = {
+ jobLog: logLinesParser(jobLog),
+ jobLogEndpoint: 'jobs/id',
+ };
+
+ store = new Vuex.Store({
+ actions,
+ state,
+ });
+ });
+
+ const findCollapsibleLine = () => wrapper.findComponent(LogLineHeader);
+ const findAllCollapsibleLines = () => wrapper.findAllComponents(LogLineHeader);
+
+ describe('line numbers', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders a line number for each open line', () => {
+ expect(wrapper.find('#L1').text()).toBe('1');
+ expect(wrapper.find('#L2').text()).toBe('2');
+ expect(wrapper.find('#L3').text()).toBe('3');
+ });
+
+ it('links to the provided path and correct line number', () => {
+ expect(wrapper.find('#L1').attributes('href')).toBe(`${state.jobLogEndpoint}#L1`);
+ });
+ });
+
+ describe('collapsible sections', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders a clickable header section', () => {
+ expect(findCollapsibleLine().attributes('role')).toBe('button');
+ });
+
+ it('renders an icon with the open state', () => {
+ expect(findCollapsibleLine().find('[data-testid="chevron-lg-down-icon"]').exists()).toBe(
+ true,
+ );
+ });
+
+ describe('on click header section', () => {
+ it('calls toggleCollapsibleLine', () => {
+ findCollapsibleLine().trigger('click');
+
+ expect(toggleCollapsibleLineMock).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('anchor scrolling', () => {
+ afterEach(() => {
+ window.location.hash = '';
+ });
+
+ describe('when hash is not present', () => {
+ it('does not scroll to line number', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.find('#L6').exists()).toBe(false);
+ expect(scrollToElement).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when hash is present', () => {
+ beforeEach(() => {
+ window.location.hash = '#L6';
+ });
+
+ it('scrolls to line number', async () => {
+ createComponent();
+
+ state.jobLog = logLinesParser(jobLog, [], '#L6');
+ await waitForPromises();
+
+ expect(scrollToElement).toHaveBeenCalledTimes(1);
+
+ state.jobLog = logLinesParser(jobLog, [], '#L7');
+ await waitForPromises();
+
+ expect(scrollToElement).toHaveBeenCalledTimes(1);
+ });
+
+ it('line number within collapsed section is visible', () => {
+ state.jobLog = logLinesParser(jobLog, [], '#L6');
+
+ createComponent();
+
+ expect(wrapper.find('#L6').exists()).toBe(true);
+ });
+ });
+
+ describe('with search results', () => {
+ it('passes isHighlighted prop correctly', () => {
+ const mockSearchResults = [
+ {
+ offset: 1002,
+ content: [
+ {
+ text: 'Using Docker executor with image dev.gitlab.org3',
+ },
+ ],
+ section: 'prepare-executor',
+ section_header: true,
+ lineNumber: 2,
+ },
+ ];
+
+ createComponent({ searchResults: mockSearchResults });
+
+ expect(findAllCollapsibleLines().at(0).props('isHighlighted')).toBe(true);
+ expect(findAllCollapsibleLines().at(1).props('isHighlighted')).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/jobs/components/log/mock_data.js b/spec/frontend/ci/job_details/components/log/mock_data.js
index fa51b92a044..fa51b92a044 100644
--- a/spec/frontend/jobs/components/log/mock_data.js
+++ b/spec/frontend/ci/job_details/components/log/mock_data.js
diff --git a/spec/frontend/ci/job_details/components/manual_variables_form_spec.js b/spec/frontend/ci/job_details/components/manual_variables_form_spec.js
new file mode 100644
index 00000000000..3391cafb4fc
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/manual_variables_form_spec.js
@@ -0,0 +1,364 @@
+import { GlSprintf, GlLink } from '@gitlab/ui';
+import { createLocalVue } from '@vue/test-utils';
+import VueApollo from 'vue-apollo';
+import { nextTick } from 'vue';
+import { createAlert } from '~/alert';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { TYPENAME_CI_BUILD } from '~/graphql_shared/constants';
+import { JOB_GRAPHQL_ERRORS } from '~/ci/constants';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import waitForPromises from 'helpers/wait_for_promises';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import ManualVariablesForm from '~/ci/job_details/components/manual_variables_form.vue';
+import getJobQuery from '~/ci/job_details/graphql/queries/get_job.query.graphql';
+import playJobMutation from '~/ci/job_details/graphql/mutations/job_play_with_variables.mutation.graphql';
+import retryJobMutation from '~/ci/job_details/graphql/mutations/job_retry_with_variables.mutation.graphql';
+
+import {
+ mockFullPath,
+ mockId,
+ mockJobResponse,
+ mockJobWithVariablesResponse,
+ mockJobPlayMutationData,
+ mockJobRetryMutationData,
+} from '../mock_data';
+
+const localVue = createLocalVue();
+jest.mock('~/alert');
+localVue.use(VueApollo);
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ redirectTo: jest.fn(),
+}));
+
+const defaultProvide = {
+ projectPath: mockFullPath,
+};
+
+describe('Manual Variables Form', () => {
+ let wrapper;
+ let mockApollo;
+ let requestHandlers;
+
+ const getJobQueryResponseHandlerWithVariables = jest.fn().mockResolvedValue(mockJobResponse);
+ const playJobMutationHandler = jest.fn().mockResolvedValue({});
+ const retryJobMutationHandler = jest.fn().mockResolvedValue({});
+
+ const defaultHandlers = {
+ getJobQueryResponseHandlerWithVariables,
+ playJobMutationHandler,
+ retryJobMutationHandler,
+ };
+
+ const createComponent = ({ props = {}, handlers = defaultHandlers } = {}) => {
+ requestHandlers = handlers;
+
+ mockApollo = createMockApollo([
+ [getJobQuery, handlers.getJobQueryResponseHandlerWithVariables],
+ [playJobMutation, handlers.playJobMutationHandler],
+ [retryJobMutation, handlers.retryJobMutationHandler],
+ ]);
+
+ const options = {
+ localVue,
+ apolloProvider: mockApollo,
+ };
+
+ wrapper = mountExtended(ManualVariablesForm, {
+ propsData: {
+ jobId: mockId,
+ isRetryable: false,
+ ...props,
+ },
+ provide: {
+ ...defaultProvide,
+ },
+ ...options,
+ });
+
+ return waitForPromises();
+ };
+
+ const findHelpText = () => wrapper.findComponent(GlSprintf);
+ const findHelpLink = () => wrapper.findComponent(GlLink);
+ const findCancelBtn = () => wrapper.findByTestId('cancel-btn');
+ const findRunBtn = () => wrapper.findByTestId('run-manual-job-btn');
+ const findDeleteVarBtn = () => wrapper.findByTestId('delete-variable-btn');
+ const findAllDeleteVarBtns = () => wrapper.findAllByTestId('delete-variable-btn');
+ const findDeleteVarBtnPlaceholder = () => wrapper.findByTestId('delete-variable-btn-placeholder');
+ const findCiVariableKey = () => wrapper.findByTestId('ci-variable-key');
+ const findAllCiVariableKeys = () => wrapper.findAllByTestId('ci-variable-key');
+ const findCiVariableValue = () => wrapper.findByTestId('ci-variable-value');
+ const findAllVariables = () => wrapper.findAllByTestId('ci-variable-row');
+
+ const setCiVariableKey = () => {
+ findCiVariableKey().setValue('new key');
+ findCiVariableKey().vm.$emit('change');
+ nextTick();
+ };
+
+ const setCiVariableKeyByPosition = (position, value) => {
+ findAllCiVariableKeys().at(position).setValue(value);
+ findAllCiVariableKeys().at(position).vm.$emit('change');
+ nextTick();
+ };
+
+ afterEach(() => {
+ createAlert.mockClear();
+ });
+
+ describe('when page renders', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
+ it('renders help text with provided link', () => {
+ expect(findHelpText().exists()).toBe(true);
+ expect(findHelpLink().attributes('href')).toBe(
+ '/help/ci/variables/index#add-a-cicd-variable-to-a-project',
+ );
+ });
+ });
+
+ describe('when query is unsuccessful', () => {
+ beforeEach(async () => {
+ await createComponent({
+ handlers: {
+ getJobQueryResponseHandlerWithVariables: jest.fn().mockRejectedValue({}),
+ },
+ });
+ });
+
+ it('shows an alert with error', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText,
+ });
+ });
+ });
+
+ describe('when job has not been retried', () => {
+ beforeEach(async () => {
+ await createComponent({
+ handlers: {
+ getJobQueryResponseHandlerWithVariables: jest
+ .fn()
+ .mockResolvedValue(mockJobWithVariablesResponse),
+ },
+ });
+ });
+
+ it('does not render the cancel button', () => {
+ expect(findCancelBtn().exists()).toBe(false);
+ expect(findRunBtn().exists()).toBe(true);
+ });
+ });
+
+ describe('when job has variables', () => {
+ beforeEach(async () => {
+ await createComponent({
+ handlers: {
+ getJobQueryResponseHandlerWithVariables: jest
+ .fn()
+ .mockResolvedValue(mockJobWithVariablesResponse),
+ },
+ });
+ });
+
+ it('sets manual job variables', () => {
+ const queryKey = mockJobWithVariablesResponse.data.project.job.manualVariables.nodes[0].key;
+ const queryValue =
+ mockJobWithVariablesResponse.data.project.job.manualVariables.nodes[0].value;
+
+ expect(findCiVariableKey().element.value).toBe(queryKey);
+ expect(findCiVariableValue().element.value).toBe(queryValue);
+ });
+ });
+
+ describe('when play mutation fires', () => {
+ beforeEach(async () => {
+ await createComponent({
+ handlers: {
+ playJobMutationHandler: jest.fn().mockResolvedValue(mockJobPlayMutationData),
+ },
+ });
+ });
+
+ it('passes variables in correct format', async () => {
+ await setCiVariableKey();
+
+ await findCiVariableValue().setValue('new value');
+
+ await findRunBtn().vm.$emit('click');
+
+ expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledTimes(1);
+ expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledWith({
+ id: convertToGraphQLId(TYPENAME_CI_BUILD, mockId),
+ variables: [
+ {
+ key: 'new key',
+ value: 'new value',
+ },
+ ],
+ });
+ });
+
+ it('redirects to job properly after job is run', async () => {
+ findRunBtn().vm.$emit('click');
+ await waitForPromises();
+
+ expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledTimes(1);
+ expect(redirectTo).toHaveBeenCalledWith(mockJobPlayMutationData.data.jobPlay.job.webPath); // eslint-disable-line import/no-deprecated
+ });
+ });
+
+ describe('when play mutation is unsuccessful', () => {
+ beforeEach(async () => {
+ await createComponent({
+ handlers: {
+ playJobMutationHandler: jest.fn().mockRejectedValue({}),
+ },
+ });
+ });
+
+ it('shows an alert with error', async () => {
+ findRunBtn().vm.$emit('click');
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText,
+ });
+ });
+ });
+
+ describe('when job is retryable', () => {
+ beforeEach(async () => {
+ await createComponent({
+ props: { isRetryable: true },
+ handlers: {
+ retryJobMutationHandler: jest.fn().mockResolvedValue(mockJobRetryMutationData),
+ },
+ });
+ });
+
+ it('renders cancel button', () => {
+ expect(findCancelBtn().exists()).toBe(true);
+ });
+
+ it('redirects to job properly after rerun', async () => {
+ findRunBtn().vm.$emit('click');
+ await waitForPromises();
+
+ expect(requestHandlers.retryJobMutationHandler).toHaveBeenCalledTimes(1);
+ expect(redirectTo).toHaveBeenCalledWith(mockJobRetryMutationData.data.jobRetry.job.webPath); // eslint-disable-line import/no-deprecated
+ });
+ });
+
+ describe('when retry mutation is unsuccessful', () => {
+ beforeEach(async () => {
+ await createComponent({
+ props: { isRetryable: true },
+ handlers: {
+ retryJobMutationHandler: jest.fn().mockRejectedValue({}),
+ },
+ });
+ });
+
+ it('shows an alert with error', async () => {
+ findRunBtn().vm.$emit('click');
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText,
+ });
+ });
+ });
+
+ describe('updating variables in UI', () => {
+ beforeEach(async () => {
+ await createComponent({
+ handlers: {
+ getJobQueryResponseHandlerWithVariables: jest.fn().mockResolvedValue(mockJobResponse),
+ },
+ });
+ });
+
+ it('creates a new variable when user enters a new key value', async () => {
+ expect(findAllVariables()).toHaveLength(1);
+
+ await setCiVariableKey();
+
+ expect(findAllVariables()).toHaveLength(2);
+ });
+
+ it('does not create extra empty variables', async () => {
+ expect(findAllVariables()).toHaveLength(1);
+
+ await setCiVariableKey();
+
+ expect(findAllVariables()).toHaveLength(2);
+
+ await setCiVariableKey();
+
+ expect(findAllVariables()).toHaveLength(2);
+ });
+
+ it('removes the correct variable row', async () => {
+ const variableKeyNameOne = 'key-one';
+ const variableKeyNameThree = 'key-three';
+
+ await setCiVariableKeyByPosition(0, variableKeyNameOne);
+
+ await setCiVariableKeyByPosition(1, 'key-two');
+
+ await setCiVariableKeyByPosition(2, variableKeyNameThree);
+
+ expect(findAllVariables()).toHaveLength(4);
+
+ await findAllDeleteVarBtns().at(1).trigger('click');
+
+ expect(findAllVariables()).toHaveLength(3);
+
+ expect(findAllCiVariableKeys().at(0).element.value).toBe(variableKeyNameOne);
+ expect(findAllCiVariableKeys().at(1).element.value).toBe(variableKeyNameThree);
+ expect(findAllCiVariableKeys().at(2).element.value).toBe('');
+ });
+
+ it('delete variable button should only show when there is more than one variable', async () => {
+ expect(findDeleteVarBtn().exists()).toBe(false);
+
+ await setCiVariableKey();
+
+ expect(findDeleteVarBtn().exists()).toBe(true);
+ });
+ });
+
+ describe('variable delete button placeholder', () => {
+ beforeEach(async () => {
+ await createComponent({
+ handlers: {
+ getJobQueryResponseHandlerWithVariables: jest.fn().mockResolvedValue(mockJobResponse),
+ },
+ });
+ });
+
+ it('delete variable button placeholder should only exist when a user cannot remove', () => {
+ expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
+ });
+
+ it('does not show the placeholder button', () => {
+ expect(findDeleteVarBtnPlaceholder().classes('gl-opacity-0')).toBe(true);
+ });
+
+ it('placeholder button will not delete the row on click', async () => {
+ expect(findAllCiVariableKeys()).toHaveLength(1);
+ expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
+
+ await findDeleteVarBtnPlaceholder().trigger('click');
+
+ expect(findAllCiVariableKeys()).toHaveLength(1);
+ expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/artifacts_block_spec.js b/spec/frontend/ci/job_details/components/sidebar/artifacts_block_spec.js
new file mode 100644
index 00000000000..1d61bf3243f
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/artifacts_block_spec.js
@@ -0,0 +1,193 @@
+import { GlPopover } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { trimText } from 'helpers/text_helper';
+import ArtifactsBlock from '~/ci/job_details/components/sidebar/artifacts_block.vue';
+import { getTimeago } from '~/lib/utils/datetime_utility';
+
+describe('Artifacts block', () => {
+ let wrapper;
+
+ const createWrapper = (propsData) =>
+ mountExtended(ArtifactsBlock, {
+ propsData: {
+ helpUrl: 'help-url',
+ ...propsData,
+ },
+ });
+
+ const findArtifactRemoveElt = () => wrapper.findByTestId('artifacts-remove-timeline');
+ const findJobLockedElt = () => wrapper.findByTestId('artifacts-locked-message-content');
+ const findKeepBtn = () => wrapper.findByTestId('keep-artifacts');
+ const findDownloadBtn = () => wrapper.findByTestId('download-artifacts');
+ const findBrowseBtn = () => wrapper.findByTestId('browse-artifacts-button');
+ const findArtifactsHelpLink = () => wrapper.findByTestId('artifacts-help-link');
+ const findPopover = () => wrapper.findComponent(GlPopover);
+
+ const expireAt = '2018-08-14T09:38:49.157Z';
+ const timeago = getTimeago();
+ const formattedDate = timeago.format(expireAt);
+ const lockedText =
+ 'These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available.';
+
+ const expiredArtifact = {
+ expire_at: expireAt,
+ expired: true,
+ locked: false,
+ };
+
+ const nonExpiredArtifact = {
+ download_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/download',
+ browse_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/browse',
+ keep_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/keep',
+ expire_at: expireAt,
+ expired: false,
+ locked: false,
+ };
+
+ const lockedExpiredArtifact = {
+ ...expiredArtifact,
+ download_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/download',
+ browse_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/browse',
+ expired: true,
+ locked: true,
+ };
+
+ const lockedNonExpiredArtifact = {
+ ...nonExpiredArtifact,
+ keep_path: undefined,
+ locked: true,
+ };
+
+ describe('with expired artifacts that are not locked', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({
+ artifact: expiredArtifact,
+ });
+ });
+
+ it('renders expired artifact date and info', () => {
+ expect(trimText(findArtifactRemoveElt().text())).toBe(
+ `The artifacts were removed ${formattedDate}`,
+ );
+
+ expect(
+ findArtifactRemoveElt()
+ .find('[data-testid="artifact-expired-help-link"]')
+ .attributes('href'),
+ ).toBe('help-url');
+ });
+
+ it('does not show the keep button', () => {
+ expect(findKeepBtn().exists()).toBe(false);
+ });
+
+ it('does not show the download button', () => {
+ expect(findDownloadBtn().exists()).toBe(false);
+ });
+
+ it('does not show the browse button', () => {
+ expect(findBrowseBtn().exists()).toBe(false);
+ });
+ });
+
+ describe('with artifacts that will expire', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({
+ artifact: nonExpiredArtifact,
+ });
+ });
+
+ it('renders will expire artifact date and info', () => {
+ expect(trimText(findArtifactRemoveElt().text())).toBe(
+ `The artifacts will be removed ${formattedDate}`,
+ );
+
+ expect(
+ findArtifactRemoveElt()
+ .find('[data-testid="artifact-expired-help-link"]')
+ .attributes('href'),
+ ).toBe('help-url');
+ });
+
+ it('renders the keep button', () => {
+ expect(findKeepBtn().exists()).toBe(true);
+ });
+
+ it('renders the download button', () => {
+ expect(findDownloadBtn().exists()).toBe(true);
+ });
+
+ it('renders the browse button', () => {
+ expect(findBrowseBtn().exists()).toBe(true);
+ });
+ });
+
+ describe('with expired locked artifacts', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({
+ artifact: lockedExpiredArtifact,
+ });
+ });
+
+ it('renders the information that the artefacts are locked', () => {
+ expect(findArtifactRemoveElt().exists()).toBe(false);
+ expect(trimText(findJobLockedElt().text())).toBe(lockedText);
+ });
+
+ it('does not render the keep button', () => {
+ expect(findKeepBtn().exists()).toBe(false);
+ });
+
+ it('renders the download button', () => {
+ expect(findDownloadBtn().exists()).toBe(true);
+ });
+
+ it('renders the browse button', () => {
+ expect(findBrowseBtn().exists()).toBe(true);
+ });
+ });
+
+ describe('with non expired locked artifacts', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({
+ artifact: lockedNonExpiredArtifact,
+ });
+ });
+
+ it('renders the information that the artefacts are locked', () => {
+ expect(findArtifactRemoveElt().exists()).toBe(false);
+ expect(trimText(findJobLockedElt().text())).toBe(lockedText);
+ });
+
+ it('does not render the keep button', () => {
+ expect(findKeepBtn().exists()).toBe(false);
+ });
+
+ it('renders the download button', () => {
+ expect(findDownloadBtn().exists()).toBe(true);
+ });
+
+ it('renders the browse button', () => {
+ expect(findBrowseBtn().exists()).toBe(true);
+ });
+ });
+
+ describe('artifacts help text', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({
+ artifact: lockedNonExpiredArtifact,
+ });
+ });
+
+ it('displays help text', () => {
+ const expectedHelpText =
+ 'Job artifacts are files that are configured to be uploaded when a job finishes execution. Artifacts could be compiled files, unit tests or scanning reports, or any other files generated by a job.';
+
+ expect(findPopover().text()).toBe(expectedHelpText);
+ });
+
+ it('links to artifacts help page', () => {
+ expect(findArtifactsHelpLink().attributes('href')).toBe('/help/ci/jobs/job_artifacts');
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/commit_block_spec.js b/spec/frontend/ci/job_details/components/sidebar/commit_block_spec.js
new file mode 100644
index 00000000000..e9a848bcd11
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/commit_block_spec.js
@@ -0,0 +1,66 @@
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import CommitBlock from '~/ci/job_details/components/sidebar/commit_block.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+describe('Commit block', () => {
+ let wrapper;
+
+ const commit = {
+ short_id: '1f0fb84f',
+ id: '1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
+ commit_path: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
+ title: 'Update README.md',
+ };
+
+ const mergeRequest = {
+ iid: '!21244',
+ path: 'merge_requests/21244',
+ };
+
+ const findCommitSha = () => wrapper.findByTestId('commit-sha');
+ const findLinkSha = () => wrapper.findByTestId('link-commit');
+
+ const mountComponent = (props) => {
+ wrapper = extendedWrapper(
+ shallowMount(CommitBlock, {
+ propsData: {
+ commit,
+ ...props,
+ },
+ }),
+ );
+ };
+
+ describe('without merge request', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('renders pipeline short sha link', () => {
+ expect(findCommitSha().attributes('href')).toBe(commit.commit_path);
+ expect(findCommitSha().text()).toBe(commit.short_id);
+ });
+
+ it('renders clipboard button', () => {
+ expect(wrapper.findComponent(ClipboardButton).attributes('text')).toBe(commit.id);
+ });
+
+ it('renders git commit title', () => {
+ expect(wrapper.text()).toContain(commit.title);
+ });
+
+ it('does not render merge request', () => {
+ expect(findLinkSha().exists()).toBe(false);
+ });
+ });
+
+ describe('with merge request', () => {
+ it('renders merge request link and reference', () => {
+ mountComponent({ mergeRequest });
+
+ expect(findLinkSha().attributes('href')).toBe(mergeRequest.path);
+ expect(findLinkSha().text()).toBe(`!${mergeRequest.iid}`);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/external_links_block_spec.js b/spec/frontend/ci/job_details/components/sidebar/external_links_block_spec.js
new file mode 100644
index 00000000000..1f2c448f1c6
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/external_links_block_spec.js
@@ -0,0 +1,49 @@
+import { GlLink } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import ExternalLinksBlock from '~/ci/job_details/components/sidebar/external_links_block.vue';
+
+describe('External links block', () => {
+ let wrapper;
+
+ const createWrapper = (propsData) => {
+ wrapper = mountExtended(ExternalLinksBlock, {
+ propsData: {
+ ...propsData,
+ },
+ });
+ };
+
+ const findAllLinks = () => wrapper.findAllComponents(GlLink);
+ const findLink = () => findAllLinks().at(0);
+
+ it('renders a list of links', () => {
+ createWrapper({
+ externalLinks: [
+ {
+ label: 'URL 1',
+ url: 'https://url1.example.com/',
+ },
+ {
+ label: 'URL 2',
+ url: 'https://url2.example.com/',
+ },
+ ],
+ });
+
+ expect(findAllLinks()).toHaveLength(2);
+ });
+
+ it('renders a link', () => {
+ createWrapper({
+ externalLinks: [
+ {
+ label: 'Example URL',
+ url: 'https://example.com/',
+ },
+ ],
+ });
+
+ expect(findLink().text()).toBe('Example URL');
+ expect(findLink().attributes('href')).toBe('https://example.com/');
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/job_container_item_spec.js b/spec/frontend/ci/job_details/components/sidebar/job_container_item_spec.js
new file mode 100644
index 00000000000..0eabaefd5de
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/job_container_item_spec.js
@@ -0,0 +1,87 @@
+import { GlIcon, GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import delayedJobFixture from 'test_fixtures/jobs/delayed.json';
+import JobContainerItem from '~/ci/job_details/components/sidebar/job_container_item.vue';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import job from 'jest/ci/jobs_mock_data';
+
+describe('JobContainerItem', () => {
+ let wrapper;
+
+ const findCiIcon = () => wrapper.findComponent(CiIcon);
+ const findGlIcon = () => wrapper.findComponent(GlIcon);
+
+ function createComponent(jobData = {}, props = { isActive: false, retried: false }) {
+ wrapper = shallowMount(JobContainerItem, {
+ propsData: {
+ job: {
+ ...jobData,
+ retried: props.retried,
+ },
+ isActive: props.isActive,
+ },
+ });
+ }
+
+ describe('when a job is not active and not retried', () => {
+ beforeEach(() => {
+ createComponent(job);
+ });
+
+ it('displays a status icon', () => {
+ expect(findCiIcon().props('status')).toBe(job.status);
+ });
+
+ it('displays the job name', () => {
+ expect(wrapper.text()).toContain(job.name);
+ });
+
+ it('displays a link to the job', () => {
+ const link = wrapper.findComponent(GlLink);
+
+ expect(link.attributes('href')).toBe(job.status.details_path);
+ });
+ });
+
+ describe('when a job is active', () => {
+ beforeEach(() => {
+ createComponent(job, { isActive: true });
+ });
+
+ it('displays an arrow sprite icon', () => {
+ expect(findGlIcon().props('name')).toBe('arrow-right');
+ });
+ });
+
+ describe('when a job is retried', () => {
+ beforeEach(() => {
+ createComponent(job, { isActive: false, retried: true });
+ });
+
+ it('displays a retry icon', () => {
+ expect(findGlIcon().props('name')).toBe('retry');
+ });
+ });
+
+ describe('for a delayed job', () => {
+ beforeEach(() => {
+ const remainingMilliseconds = 1337000;
+ jest
+ .spyOn(Date, 'now')
+ .mockImplementation(
+ () => new Date(delayedJobFixture.scheduled_at).getTime() - remainingMilliseconds,
+ );
+
+ createComponent(delayedJobFixture);
+ });
+
+ it('displays remaining time in tooltip', async () => {
+ await nextTick();
+
+ const link = wrapper.findComponent(GlLink);
+
+ expect(link.attributes('title')).toMatch('delayed job - delayed manual action (00:22:17)');
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/job_retry_forward_deployment_modal_spec.js b/spec/frontend/ci/job_details/components/sidebar/job_retry_forward_deployment_modal_spec.js
new file mode 100644
index 00000000000..075bccd57cc
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/job_retry_forward_deployment_modal_spec.js
@@ -0,0 +1,68 @@
+import { GlLink, GlModal } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import JobRetryForwardDeploymentModal from '~/ci/job_details/components/sidebar/job_retry_forward_deployment_modal.vue';
+import createStore from '~/ci/job_details/store';
+import job from 'jest/ci/jobs_mock_data';
+
+describe('Job Retry Forward Deployment Modal', () => {
+ let store;
+ let wrapper;
+
+ const retryOutdatedJobDocsUrl = 'url-to-docs';
+ const findLink = () => wrapper.findComponent(GlLink);
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const createWrapper = ({ props = {}, provide = {}, stubs = {} } = {}) => {
+ store = createStore();
+ wrapper = shallowMount(JobRetryForwardDeploymentModal, {
+ propsData: {
+ modalId: 'modal-id',
+ href: job.retry_path,
+ ...props,
+ },
+ provide,
+ store,
+ stubs,
+ });
+ };
+
+ beforeEach(createWrapper);
+
+ describe('Modal configuration', () => {
+ it('should display the correct messages', () => {
+ const modal = findModal();
+ expect(modal.attributes('title')).toMatch('Are you sure you want to retry this job?');
+ expect(modal.text()).toMatch(
+ "You're about to retry a job that failed because it attempted to deploy code that is older than the latest deployment. Retrying this job could result in overwriting the environment with the older source code.",
+ );
+ expect(modal.text()).toMatch('Are you sure you want to proceed?');
+ });
+ });
+
+ describe('Modal docs help link', () => {
+ it('should not display an info link when none is provided', () => {
+ createWrapper();
+
+ expect(findLink().exists()).toBe(false);
+ });
+
+ it('should display an info link when one is provided', () => {
+ createWrapper({ provide: { retryOutdatedJobDocsUrl } });
+
+ expect(findLink().attributes('href')).toBe(retryOutdatedJobDocsUrl);
+ expect(findLink().text()).toMatch('More information');
+ });
+ });
+
+ describe('Modal actions', () => {
+ beforeEach(createWrapper);
+
+ it('should correctly configure the primary action', () => {
+ expect(findModal().props('actionPrimary').attributes).toMatchObject({
+ 'data-method': 'post',
+ href: job.retry_path,
+ variant: 'danger',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/job_sidebar_retry_button_spec.js b/spec/frontend/ci/job_details/components/sidebar/job_sidebar_retry_button_spec.js
new file mode 100644
index 00000000000..8fdf6b72ee1
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/job_sidebar_retry_button_spec.js
@@ -0,0 +1,64 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import JobsSidebarRetryButton from '~/ci/job_details/components/sidebar/job_sidebar_retry_button.vue';
+import createStore from '~/ci/job_details/store';
+import job from 'jest/ci/jobs_mock_data';
+
+describe('Job Sidebar Retry Button', () => {
+ let store;
+ let wrapper;
+
+ const forwardDeploymentFailure = 'forward_deployment_failure';
+ const findRetryButton = () => wrapper.findByTestId('retry-job-button');
+ const findRetryLink = () => wrapper.findByTestId('retry-job-link');
+
+ const createWrapper = ({ props = {} } = {}) => {
+ store = createStore();
+ wrapper = shallowMountExtended(JobsSidebarRetryButton, {
+ propsData: {
+ href: job.retry_path,
+ isManualJob: false,
+ modalId: 'modal-id',
+ ...props,
+ },
+ store,
+ });
+ };
+
+ beforeEach(createWrapper);
+
+ it.each([
+ [null, false, true],
+ ['unmet_prerequisites', false, true],
+ [forwardDeploymentFailure, true, false],
+ ])(
+ 'when error is: %s, should render button: %s | should render link: %s',
+ async (failureReason, buttonExists, linkExists) => {
+ await store.dispatch('receiveJobSuccess', { ...job, failure_reason: failureReason });
+
+ expect(findRetryButton().exists()).toBe(buttonExists);
+ expect(findRetryLink().exists()).toBe(linkExists);
+ },
+ );
+
+ describe('Button', () => {
+ it('should have the correct configuration', async () => {
+ await store.dispatch('receiveJobSuccess', { failure_reason: forwardDeploymentFailure });
+
+ expect(findRetryButton().attributes()).toMatchObject({
+ category: 'primary',
+ variant: 'confirm',
+ icon: 'retry',
+ });
+ });
+ });
+
+ describe('Link', () => {
+ it('should have the correct configuration', () => {
+ expect(findRetryLink().attributes()).toMatchObject({
+ 'data-method': 'post',
+ href: job.retry_path,
+ icon: 'retry',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/jobs_container_spec.js b/spec/frontend/ci/job_details/components/sidebar/jobs_container_spec.js
new file mode 100644
index 00000000000..b2b675199ed
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/jobs_container_spec.js
@@ -0,0 +1,143 @@
+import { GlLink } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import JobsContainer from '~/ci/job_details/components/sidebar/jobs_container.vue';
+
+describe('Jobs List block', () => {
+ let wrapper;
+
+ const retried = {
+ status: {
+ details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
+ group: 'success',
+ has_details: true,
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed',
+ },
+ id: 233432756,
+ tooltip: 'build - passed',
+ retried: true,
+ };
+
+ const active = {
+ name: 'test',
+ status: {
+ details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
+ group: 'success',
+ has_details: true,
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed',
+ },
+ id: 2322756,
+ tooltip: 'build - passed',
+ active: true,
+ };
+
+ const job = {
+ name: 'build',
+ status: {
+ details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
+ group: 'success',
+ has_details: true,
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed',
+ },
+ id: 232153,
+ tooltip: 'build - passed',
+ };
+
+ const findAllJobs = () => wrapper.findAllComponents(GlLink);
+ const findJob = () => findAllJobs().at(0);
+
+ const findArrowIcon = () => wrapper.findByTestId('arrow-right-icon');
+ const findRetryIcon = () => wrapper.findByTestId('retry-icon');
+
+ const createComponent = (props) => {
+ wrapper = extendedWrapper(
+ mount(JobsContainer, {
+ propsData: {
+ ...props,
+ },
+ }),
+ );
+ };
+
+ it('renders a list of jobs', () => {
+ createComponent({
+ jobs: [job, retried, active],
+ jobId: 12313,
+ });
+
+ expect(findAllJobs()).toHaveLength(3);
+ });
+
+ it('renders the arrow right icon when job id matches `jobId`', () => {
+ createComponent({
+ jobs: [active],
+ jobId: active.id,
+ });
+
+ expect(findArrowIcon().exists()).toBe(true);
+ });
+
+ it('does not render the arrow right icon when the job is not active', () => {
+ createComponent({
+ jobs: [job],
+ jobId: active.id,
+ });
+
+ expect(findArrowIcon().exists()).toBe(false);
+ });
+
+ it('renders the job name when present', () => {
+ createComponent({
+ jobs: [job],
+ jobId: active.id,
+ });
+
+ expect(findJob().text()).toBe(job.name);
+ expect(findJob().text()).not.toContain(job.id.toString());
+ });
+
+ it('renders job id when job name is not available', () => {
+ createComponent({
+ jobs: [retried],
+ jobId: active.id,
+ });
+
+ expect(findJob().text()).toBe(retried.id.toString());
+ });
+
+ it('links to the job page', () => {
+ createComponent({
+ jobs: [job],
+ jobId: active.id,
+ });
+
+ expect(findJob().attributes('href')).toBe(job.status.details_path);
+ });
+
+ it('renders retry icon when job was retried', () => {
+ createComponent({
+ jobs: [retried],
+ jobId: active.id,
+ });
+
+ expect(findRetryIcon().exists()).toBe(true);
+ });
+
+ it('does not render retry icon when job was not retried', () => {
+ createComponent({
+ jobs: [job],
+ jobId: active.id,
+ });
+
+ expect(findRetryIcon().exists()).toBe(false);
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/sidebar_detail_row_spec.js b/spec/frontend/ci/job_details/components/sidebar/sidebar_detail_row_spec.js
new file mode 100644
index 00000000000..52c886e3c88
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/sidebar_detail_row_spec.js
@@ -0,0 +1,68 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import SidebarDetailRow from '~/ci/job_details/components/sidebar/sidebar_detail_row.vue';
+import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
+
+describe('Sidebar detail row', () => {
+ let wrapper;
+
+ const title = 'this is the title';
+ const value = 'this is the value';
+ const helpUrl = `${DOCS_URL}/runner/register/index.html`;
+ const path = 'path/to/value';
+
+ const findHelpLink = () => wrapper.findByTestId('job-sidebar-help-link');
+ const findValueLink = () => wrapper.findByTestId('job-sidebar-value-link');
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(SidebarDetailRow, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ describe('with title/value and without helpUrl/path', () => {
+ beforeEach(() => {
+ createComponent({ title, value });
+ });
+
+ it('should render the provided title and value', () => {
+ expect(wrapper.text()).toBe(`${title}: ${value}`);
+ });
+
+ it('should not render the help link', () => {
+ expect(findHelpLink().exists()).toBe(false);
+ });
+
+ it('should not render the value link', () => {
+ expect(findValueLink().exists()).toBe(false);
+ });
+ });
+
+ describe('when helpUrl provided', () => {
+ beforeEach(() => {
+ createComponent({
+ helpUrl,
+ title,
+ value,
+ });
+ });
+
+ it('should render the help link', () => {
+ expect(findHelpLink().exists()).toBe(true);
+ expect(findHelpLink().attributes('href')).toBe(helpUrl);
+ });
+ });
+
+ describe('when path is provided', () => {
+ it('should render link to value', () => {
+ createComponent({
+ path,
+ title,
+ value,
+ });
+
+ expect(findValueLink().attributes('href')).toBe(path);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js b/spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js
new file mode 100644
index 00000000000..1063bec6f3b
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/sidebar_header_spec.js
@@ -0,0 +1,101 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import SidebarHeader from '~/ci/job_details/components/sidebar/sidebar_header.vue';
+import JobRetryButton from '~/ci/job_details/components/sidebar/job_sidebar_retry_button.vue';
+import getJobQuery from '~/ci/job_details/graphql/queries/get_job.query.graphql';
+import { mockFullPath, mockId, mockJobResponse } from '../../mock_data';
+
+Vue.use(VueApollo);
+
+const defaultProvide = {
+ projectPath: mockFullPath,
+};
+
+describe('Sidebar Header', () => {
+ let wrapper;
+
+ const createComponent = ({ options = {}, props = {}, restJob = {} } = {}) => {
+ wrapper = shallowMountExtended(SidebarHeader, {
+ propsData: {
+ ...props,
+ jobId: mockId,
+ restJob,
+ },
+ provide: {
+ ...defaultProvide,
+ },
+ ...options,
+ });
+ };
+
+ const createComponentWithApollo = ({ props = {}, restJob = {} } = {}) => {
+ const getJobQueryResponse = jest.fn().mockResolvedValue(mockJobResponse);
+
+ const requestHandlers = [[getJobQuery, getJobQueryResponse]];
+
+ const apolloProvider = createMockApollo(requestHandlers);
+
+ const options = {
+ apolloProvider,
+ };
+
+ createComponent({
+ props,
+ restJob,
+ options,
+ });
+
+ return waitForPromises();
+ };
+
+ const findCancelButton = () => wrapper.findByTestId('cancel-button');
+ const findEraseButton = () => wrapper.findByTestId('job-log-erase-link');
+ const findNewIssueButton = () => wrapper.findByTestId('job-new-issue');
+ const findTerminalLink = () => wrapper.findByTestId('terminal-link');
+ const findJobName = () => wrapper.findByTestId('job-name');
+ const findRetryButton = () => wrapper.findComponent(JobRetryButton);
+
+ describe('when rendering contents', () => {
+ it('renders the correct job name', async () => {
+ await createComponentWithApollo();
+ expect(findJobName().text()).toBe(mockJobResponse.data.project.job.name);
+ });
+
+ it('does not render buttons with no paths', async () => {
+ await createComponentWithApollo();
+ expect(findCancelButton().exists()).toBe(false);
+ expect(findEraseButton().exists()).toBe(false);
+ expect(findRetryButton().exists()).toBe(false);
+ expect(findNewIssueButton().exists()).toBe(false);
+ expect(findTerminalLink().exists()).toBe(false);
+ });
+
+ it('renders a retry button with a path', async () => {
+ await createComponentWithApollo({ restJob: { retry_path: 'retry/path' } });
+ expect(findRetryButton().exists()).toBe(true);
+ });
+
+ it('renders a cancel button with a path', async () => {
+ await createComponentWithApollo({ restJob: { cancel_path: 'cancel/path' } });
+ expect(findCancelButton().exists()).toBe(true);
+ });
+
+ it('renders an erase button with a path', async () => {
+ await createComponentWithApollo({ restJob: { erase_path: 'erase/path' } });
+ expect(findEraseButton().exists()).toBe(true);
+ });
+
+ it('should render link to new issue', async () => {
+ await createComponentWithApollo({ restJob: { new_issue_path: 'new/issue/path' } });
+ expect(findNewIssueButton().attributes('href')).toBe('new/issue/path');
+ });
+
+ it('should render terminal link', async () => {
+ await createComponentWithApollo({ restJob: { terminal_path: 'terminal/path' } });
+ expect(findTerminalLink().attributes('href')).toBe('terminal/path');
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js b/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js
new file mode 100644
index 00000000000..e188d99b8b1
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js
@@ -0,0 +1,134 @@
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import DetailRow from '~/ci/job_details/components/sidebar/sidebar_detail_row.vue';
+import SidebarJobDetailsContainer from '~/ci/job_details/components/sidebar/sidebar_job_details_container.vue';
+import createStore from '~/ci/job_details/store';
+import job from 'jest/ci/jobs_mock_data';
+
+describe('Job Sidebar Details Container', () => {
+ let store;
+ let wrapper;
+
+ const findJobTimeout = () => wrapper.findByTestId('job-timeout');
+ const findJobTags = () => wrapper.findByTestId('job-tags');
+ const findAllDetailsRow = () => wrapper.findAllComponents(DetailRow);
+
+ const createWrapper = ({ props = {} } = {}) => {
+ store = createStore();
+ wrapper = extendedWrapper(
+ shallowMount(SidebarJobDetailsContainer, {
+ propsData: props,
+ store,
+ stubs: {
+ DetailRow,
+ },
+ }),
+ );
+ };
+
+ describe('when no details are available', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('should render an empty container', () => {
+ expect(wrapper.html()).toBe('');
+ });
+
+ it.each(['duration', 'erased_at', 'finished_at', 'queued_at', 'runner', 'coverage'])(
+ 'should not render %s details when missing',
+ async (detail) => {
+ await store.dispatch('receiveJobSuccess', { [detail]: undefined });
+
+ expect(findAllDetailsRow()).toHaveLength(0);
+ },
+ );
+ });
+
+ describe('when some of the details are available', () => {
+ beforeEach(createWrapper);
+
+ it.each([
+ ['duration', 'Elapsed time: 6 seconds'],
+ ['erased_at', 'Erased: 3 weeks ago'],
+ ['finished_at', 'Finished: 3 weeks ago'],
+ ['queued_duration', 'Queued: 9 seconds'],
+ ['id', 'Job ID: #4757'],
+ ['runner', 'Runner: #1 (ABCDEFGH) local ci runner'],
+ ['coverage', 'Coverage: 20%'],
+ ])('uses %s to render job-%s', async (detail, value) => {
+ await store.dispatch('receiveJobSuccess', { [detail]: job[detail] });
+ const detailsRow = findAllDetailsRow();
+
+ expect(detailsRow).toHaveLength(1);
+ expect(detailsRow.at(0).text()).toBe(value);
+ });
+
+ it('only renders tags', async () => {
+ const { tags } = job;
+ await store.dispatch('receiveJobSuccess', { tags });
+ const tagsComponent = findJobTags();
+
+ expect(tagsComponent.text()).toBe('Tags: tag');
+ });
+ });
+
+ describe('when all the info are available', () => {
+ it('renders all the details components', async () => {
+ createWrapper();
+ await store.dispatch('receiveJobSuccess', job);
+
+ expect(findAllDetailsRow()).toHaveLength(8);
+ });
+
+ describe('duration row', () => {
+ it('renders all the details components', async () => {
+ createWrapper();
+ await store.dispatch('receiveJobSuccess', job);
+
+ expect(findAllDetailsRow().at(0).text()).toBe('Duration: 6 seconds');
+ });
+ });
+ });
+
+ describe('timeout', () => {
+ const {
+ metadata: { timeout_human_readable, timeout_source },
+ } = job;
+
+ beforeEach(createWrapper);
+
+ it('does not render if metadata is empty', async () => {
+ const metadata = {};
+ await store.dispatch('receiveJobSuccess', { metadata });
+ const detailsRow = findAllDetailsRow();
+
+ expect(wrapper.html()).toBe('');
+ expect(detailsRow.exists()).toBe(false);
+ });
+
+ it('uses metadata to render timeout', async () => {
+ const metadata = { timeout_human_readable };
+ await store.dispatch('receiveJobSuccess', { metadata });
+ const detailsRow = findAllDetailsRow();
+
+ expect(detailsRow).toHaveLength(1);
+ expect(detailsRow.at(0).text()).toBe('Timeout: 1m 40s');
+ });
+
+ it('uses metadata to render timeout and the source', async () => {
+ const metadata = { timeout_human_readable, timeout_source };
+ await store.dispatch('receiveJobSuccess', { metadata });
+ const detailsRow = findAllDetailsRow();
+
+ expect(detailsRow.at(0).text()).toBe('Timeout: 1m 40s (from runner)');
+ });
+
+ it('should not render when no time is provided', async () => {
+ const metadata = { timeout_source };
+ await store.dispatch('receiveJobSuccess', { metadata });
+
+ expect(findJobTimeout().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/sidebar_spec.js b/spec/frontend/ci/job_details/components/sidebar/sidebar_spec.js
new file mode 100644
index 00000000000..88e1f41b270
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/sidebar_spec.js
@@ -0,0 +1,222 @@
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import ArtifactsBlock from '~/ci/job_details/components/sidebar/artifacts_block.vue';
+import ExternalLinksBlock from '~/ci/job_details/components/sidebar/external_links_block.vue';
+import JobRetryForwardDeploymentModal from '~/ci/job_details/components/sidebar/job_retry_forward_deployment_modal.vue';
+import JobsContainer from '~/ci/job_details/components/sidebar/jobs_container.vue';
+import Sidebar from '~/ci/job_details/components/sidebar/sidebar.vue';
+import StagesDropdown from '~/ci/job_details/components/sidebar/stages_dropdown.vue';
+import createStore from '~/ci/job_details/store';
+import job, { jobsInStage } from 'jest/ci/jobs_mock_data';
+
+describe('Sidebar details block', () => {
+ let mock;
+ let store;
+ let wrapper;
+
+ const forwardDeploymentFailure = 'forward_deployment_failure';
+ const findModal = () => wrapper.findComponent(JobRetryForwardDeploymentModal);
+ const findArtifactsBlock = () => wrapper.findComponent(ArtifactsBlock);
+ const findExternalLinksBlock = () => wrapper.findComponent(ExternalLinksBlock);
+ const findJobStagesDropdown = () => wrapper.findComponent(StagesDropdown);
+ const findJobsContainer = () => wrapper.findComponent(JobsContainer);
+
+ const createWrapper = (props) => {
+ store = createStore();
+
+ store.state.job = job;
+
+ wrapper = extendedWrapper(
+ shallowMount(Sidebar, {
+ propsData: {
+ ...props,
+ },
+
+ store,
+ }),
+ );
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet().reply(HTTP_STATUS_OK, {
+ name: job.stage,
+ });
+ });
+
+ describe('forward deployment failure', () => {
+ describe('when the relevant data is missing', () => {
+ it.each`
+ retryPath | failureReason
+ ${null} | ${null}
+ ${''} | ${''}
+ ${job.retry_path} | ${''}
+ ${''} | ${forwardDeploymentFailure}
+ ${job.retry_path} | ${'unmet_prerequisites'}
+ `(
+ 'should not render the modal when path and failure are $retryPath, $failureReason',
+ async ({ retryPath, failureReason }) => {
+ createWrapper();
+ await store.dispatch('receiveJobSuccess', {
+ ...job,
+ failure_reason: failureReason,
+ retry_path: retryPath,
+ });
+ expect(findModal().exists()).toBe(false);
+ },
+ );
+ });
+
+ describe('when there is the relevant error', () => {
+ beforeEach(() => {
+ createWrapper();
+ return store.dispatch('receiveJobSuccess', {
+ ...job,
+ failure_reason: forwardDeploymentFailure,
+ });
+ });
+
+ it('should render the modal', () => {
+ expect(findModal().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('stages dropdown', () => {
+ beforeEach(() => {
+ createWrapper();
+ return store.dispatch('receiveJobSuccess', job);
+ });
+
+ describe('with stages', () => {
+ it('renders value provided as selectedStage as selected', () => {
+ expect(findJobStagesDropdown().props('selectedStage')).toBe(job.stage);
+ });
+ });
+
+ describe('without jobs for stages', () => {
+ it('does not render jobs container', () => {
+ expect(findJobsContainer().exists()).toBe(false);
+ });
+ });
+
+ describe('with jobs for stages', () => {
+ beforeEach(() => {
+ return store.dispatch('receiveJobsForStageSuccess', jobsInStage.latest_statuses);
+ });
+
+ it('renders list of jobs', () => {
+ expect(findJobsContainer().exists()).toBe(true);
+ });
+ });
+
+ describe('when job data changes', () => {
+ const stageArg = job.pipeline.details.stages.find((stage) => stage.name === job.stage);
+
+ beforeEach(() => {
+ jest.spyOn(store, 'dispatch');
+ });
+
+ describe('and the job stage is currently selected', () => {
+ describe('when the status changed', () => {
+ it('refetch the jobs list for the stage', async () => {
+ await store.dispatch('receiveJobSuccess', { ...job, status: 'new' });
+
+ expect(store.dispatch).toHaveBeenNthCalledWith(2, 'fetchJobsForStage', { ...stageArg });
+ });
+ });
+
+ describe('when the status did not change', () => {
+ it('does not refetch the jobs list for the stage', async () => {
+ await store.dispatch('receiveJobSuccess', { ...job });
+
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+ expect(store.dispatch).toHaveBeenNthCalledWith(1, 'receiveJobSuccess', {
+ ...job,
+ });
+ });
+ });
+ });
+
+ describe('and the job stage is not currently selected', () => {
+ it('does not refetch the jobs list for the stage', async () => {
+ // Setting stage to `random` on the job means that we are looking
+ // at `build` stage currently, but the job we are seeing in the logs
+ // belong to `random`, so we shouldn't have to refetch
+ await store.dispatch('receiveJobSuccess', { ...job, stage: 'random' });
+
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+ expect(store.dispatch).toHaveBeenNthCalledWith(1, 'receiveJobSuccess', {
+ ...job,
+ stage: 'random',
+ });
+ });
+ });
+ });
+ });
+
+ describe('artifacts', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('artifacts are not shown if there are no properties other than locked', () => {
+ expect(findArtifactsBlock().exists()).toBe(false);
+ });
+
+ it('artifacts are shown if present', async () => {
+ store.state.job.artifact = {
+ download_path: '/root/ci-project/-/jobs/1960/artifacts/download',
+ browse_path: '/root/ci-project/-/jobs/1960/artifacts/browse',
+ keep_path: '/root/ci-project/-/jobs/1960/artifacts/keep',
+ expire_at: '2021-03-23T17:57:11.211Z',
+ expired: false,
+ locked: false,
+ };
+
+ await nextTick();
+
+ expect(findArtifactsBlock().exists()).toBe(true);
+ });
+ });
+
+ describe('external links', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('external links block is not shown if there are no external links', () => {
+ expect(findExternalLinksBlock().exists()).toBe(false);
+ });
+
+ it('external links block is shown if there are external links', async () => {
+ store.state.job.annotations = [
+ {
+ name: 'external_links',
+ data: [
+ {
+ external_link: {
+ label: 'URL 1',
+ url: 'https://url1.example.com/',
+ },
+ },
+ {
+ external_link: {
+ label: 'URL 2',
+ url: 'https://url2.example.com/',
+ },
+ },
+ ],
+ },
+ ];
+
+ await nextTick();
+
+ expect(findExternalLinksBlock().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/stages_dropdown_spec.js b/spec/frontend/ci/job_details/components/sidebar/stages_dropdown_spec.js
new file mode 100644
index 00000000000..e007896c81e
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/stages_dropdown_spec.js
@@ -0,0 +1,192 @@
+import { GlDisclosureDropdown, GlLink, GlSprintf } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { Mousetrap } from '~/lib/mousetrap';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import StagesDropdown from '~/ci/job_details/components/sidebar/stages_dropdown.vue';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import * as copyToClipboard from '~/behaviors/copy_to_clipboard';
+import {
+ mockPipelineWithoutRef,
+ mockPipelineWithoutMR,
+ mockPipelineWithAttachedMR,
+ mockPipelineDetached,
+} from 'jest/ci/jobs_mock_data';
+
+describe('Stages Dropdown', () => {
+ let wrapper;
+
+ const findStatus = () => wrapper.findComponent(CiBadgeLink);
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const findSelectedStageText = () => findDropdown().props('toggleText');
+
+ const findPipelineInfoText = () => wrapper.findByTestId('pipeline-info').text();
+
+ const createComponent = (props) => {
+ wrapper = extendedWrapper(
+ shallowMount(StagesDropdown, {
+ propsData: {
+ stages: [],
+ selectedStage: 'deploy',
+ ...props,
+ },
+ stubs: {
+ GlSprintf,
+ GlLink,
+ },
+ }),
+ );
+ };
+
+ describe('without a merge request pipeline', () => {
+ beforeEach(() => {
+ createComponent({
+ pipeline: mockPipelineWithoutMR,
+ stages: [{ name: 'build' }, { name: 'test' }],
+ });
+ });
+
+ it('renders pipeline status', () => {
+ expect(findStatus().props('status')).toBe(mockPipelineWithoutMR.details.status);
+ expect(findStatus().props('size')).toBe('sm');
+ });
+
+ it('renders dropdown with stages', () => {
+ expect(findDropdown().props('items')).toEqual([
+ expect.objectContaining({ text: 'build' }),
+ expect.objectContaining({ text: 'test' }),
+ ]);
+ });
+
+ it('renders selected stage', () => {
+ expect(findSelectedStageText()).toBe('deploy');
+ });
+ });
+
+ describe('pipelineInfo', () => {
+ const allElements = [
+ 'pipeline-path',
+ 'mr-link',
+ 'source-ref-link',
+ 'copy-source-ref-link',
+ 'source-branch-link',
+ 'copy-source-branch-link',
+ 'target-branch-link',
+ 'copy-target-branch-link',
+ ];
+ describe.each([
+ [
+ 'does not have a ref',
+ {
+ pipeline: mockPipelineWithoutRef,
+ text: `Pipeline #${mockPipelineWithoutRef.id}`,
+ foundElements: [
+ { testId: 'pipeline-path', props: [{ href: mockPipelineWithoutRef.path }] },
+ ],
+ },
+ ],
+ [
+ 'hasRef but not triggered by MR',
+ {
+ pipeline: mockPipelineWithoutMR,
+ text: `Pipeline #${mockPipelineWithoutMR.id} for ${mockPipelineWithoutMR.ref.name}`,
+ foundElements: [
+ { testId: 'pipeline-path', props: [{ href: mockPipelineWithoutMR.path }] },
+ { testId: 'source-ref-link', props: [{ href: mockPipelineWithoutMR.ref.path }] },
+ { testId: 'copy-source-ref-link', props: [{ text: mockPipelineWithoutMR.ref.name }] },
+ ],
+ },
+ ],
+ [
+ 'hasRef and MR but not MR pipeline',
+ {
+ pipeline: mockPipelineDetached,
+ text: `Pipeline #${mockPipelineDetached.id} for !${mockPipelineDetached.merge_request.iid} with ${mockPipelineDetached.merge_request.source_branch}`,
+ foundElements: [
+ { testId: 'pipeline-path', props: [{ href: mockPipelineDetached.path }] },
+ { testId: 'mr-link', props: [{ href: mockPipelineDetached.merge_request.path }] },
+ {
+ testId: 'source-branch-link',
+ props: [{ href: mockPipelineDetached.merge_request.source_branch_path }],
+ },
+ {
+ testId: 'copy-source-branch-link',
+ props: [{ text: mockPipelineDetached.merge_request.source_branch }],
+ },
+ ],
+ },
+ ],
+ [
+ 'hasRef and MR and MR pipeline',
+ {
+ pipeline: mockPipelineWithAttachedMR,
+ text: `Pipeline #${mockPipelineWithAttachedMR.id} for !${mockPipelineWithAttachedMR.merge_request.iid} with ${mockPipelineWithAttachedMR.merge_request.source_branch} into ${mockPipelineWithAttachedMR.merge_request.target_branch}`,
+ foundElements: [
+ { testId: 'pipeline-path', props: [{ href: mockPipelineWithAttachedMR.path }] },
+ { testId: 'mr-link', props: [{ href: mockPipelineWithAttachedMR.merge_request.path }] },
+ {
+ testId: 'source-branch-link',
+ props: [{ href: mockPipelineWithAttachedMR.merge_request.source_branch_path }],
+ },
+ {
+ testId: 'copy-source-branch-link',
+ props: [{ text: mockPipelineWithAttachedMR.merge_request.source_branch }],
+ },
+ {
+ testId: 'target-branch-link',
+ props: [{ href: mockPipelineWithAttachedMR.merge_request.target_branch_path }],
+ },
+ {
+ testId: 'copy-target-branch-link',
+ props: [{ text: mockPipelineWithAttachedMR.merge_request.target_branch }],
+ },
+ ],
+ },
+ ],
+ ])('%s', (_, { pipeline, text, foundElements }) => {
+ beforeEach(() => {
+ createComponent({
+ pipeline,
+ });
+ });
+
+ it('should render the text', () => {
+ expect(findPipelineInfoText()).toMatchInterpolatedText(text);
+ });
+
+ it('should find components with props', () => {
+ foundElements.forEach((element) => {
+ element.props.forEach((prop) => {
+ const key = Object.keys(prop)[0];
+ expect(wrapper.findByTestId(element.testId).attributes(key)).toBe(prop[key]);
+ });
+ });
+ });
+
+ it('should not find components', () => {
+ const foundTestIds = foundElements.map((element) => element.testId);
+ allElements
+ .filter((testId) => !foundTestIds.includes(testId))
+ .forEach((testId) => {
+ expect(wrapper.findByTestId(testId).exists()).toBe(false);
+ });
+ });
+ });
+ });
+
+ describe('mousetrap', () => {
+ it.each([
+ ['copy-source-ref-link', mockPipelineWithoutMR],
+ ['copy-source-branch-link', mockPipelineWithAttachedMR],
+ ])(
+ 'calls clickCopyToClipboardButton with `%s` button when `b` is pressed',
+ (button, pipeline) => {
+ const copyToClipboardMock = jest.spyOn(copyToClipboard, 'clickCopyToClipboardButton');
+ createComponent({ pipeline });
+
+ Mousetrap.trigger('b');
+
+ expect(copyToClipboardMock).toHaveBeenCalledWith(wrapper.findByTestId(button).element);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/sidebar/trigger_block_spec.js b/spec/frontend/ci/job_details/components/sidebar/trigger_block_spec.js
new file mode 100644
index 00000000000..f2b00c42d53
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/sidebar/trigger_block_spec.js
@@ -0,0 +1,81 @@
+import { GlButton, GlTableLite } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import TriggerBlock from '~/ci/job_details/components/sidebar/trigger_block.vue';
+
+describe('Trigger block', () => {
+ let wrapper;
+
+ const findRevealButton = () => wrapper.findComponent(GlButton);
+ const findVariableTable = () => wrapper.findComponent(GlTableLite);
+ const findShortToken = () => wrapper.find('[data-testid="trigger-short-token"]');
+ const findVariableValue = (index) =>
+ wrapper.findAll('[data-testid="trigger-build-value"]').at(index);
+ const findVariableKey = (index) => wrapper.findAll('[data-testid="trigger-build-key"]').at(index);
+
+ const createComponent = (props) => {
+ wrapper = mount(TriggerBlock, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ describe('with short token and no variables', () => {
+ it('renders short token', () => {
+ createComponent({
+ trigger: {
+ short_token: '0a666b2',
+ variables: [],
+ },
+ });
+
+ expect(findShortToken().text()).toContain('0a666b2');
+ });
+ });
+
+ describe('without variables or short token', () => {
+ beforeEach(() => {
+ createComponent({ trigger: { variables: [] } });
+ });
+
+ it('does not render short token', () => {
+ expect(findShortToken().exists()).toBe(false);
+ });
+
+ it('does not render variables', () => {
+ expect(findRevealButton().exists()).toBe(false);
+ expect(findVariableTable().exists()).toBe(false);
+ });
+ });
+
+ describe('with variables', () => {
+ describe('hide/reveal variables', () => {
+ it('should toggle variables on click', async () => {
+ const hiddenValue = '••••••';
+ const gcsVar = { key: 'UPLOAD_TO_GCS', value: 'false', public: false };
+ const s3Var = { key: 'UPLOAD_TO_S3', value: 'true', public: false };
+
+ createComponent({
+ trigger: {
+ variables: [gcsVar, s3Var],
+ },
+ });
+
+ expect(findRevealButton().text()).toBe('Reveal values');
+
+ expect(findVariableValue(0).text()).toBe(hiddenValue);
+ expect(findVariableValue(1).text()).toBe(hiddenValue);
+
+ expect(findVariableKey(0).text()).toBe(gcsVar.key);
+ expect(findVariableKey(1).text()).toBe(s3Var.key);
+
+ await findRevealButton().trigger('click');
+
+ expect(findRevealButton().text()).toBe('Hide values');
+
+ expect(findVariableValue(0).text()).toBe(gcsVar.value);
+ expect(findVariableValue(1).text()).toBe(s3Var.value);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/stuck_block_spec.js b/spec/frontend/ci/job_details/components/stuck_block_spec.js
new file mode 100644
index 00000000000..ec3b2d45a68
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/stuck_block_spec.js
@@ -0,0 +1,94 @@
+import { GlBadge, GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import StuckBlock from '~/ci/job_details/components/stuck_block.vue';
+
+describe('Stuck Block Job component', () => {
+ let wrapper;
+
+ const createWrapper = (props) => {
+ wrapper = shallowMount(StuckBlock, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const tags = ['docker', 'gitlab-org'];
+
+ const findStuckNoActiveRunners = () =>
+ wrapper.find('[data-testid="job-stuck-no-active-runners"]');
+ const findStuckNoRunners = () => wrapper.find('[data-testid="job-stuck-no-runners"]');
+ const findStuckWithTags = () => wrapper.find('[data-testid="job-stuck-with-tags"]');
+ const findRunnerPathLink = () => wrapper.findComponent(GlLink);
+ const findAllBadges = () => wrapper.findAllComponents(GlBadge);
+
+ describe('with no runners for project', () => {
+ beforeEach(() => {
+ createWrapper({
+ hasOfflineRunnersForProject: true,
+ runnersPath: '/root/project/runners#js-runners-settings',
+ });
+ });
+
+ it('renders only information about project not having runners', () => {
+ expect(findStuckNoRunners().exists()).toBe(true);
+ expect(findStuckWithTags().exists()).toBe(false);
+ expect(findStuckNoActiveRunners().exists()).toBe(false);
+ });
+
+ it('renders link to runners page', () => {
+ expect(findRunnerPathLink().attributes('href')).toBe(
+ '/root/project/runners#js-runners-settings',
+ );
+ });
+ });
+
+ describe('with tags', () => {
+ beforeEach(() => {
+ createWrapper({
+ hasOfflineRunnersForProject: false,
+ tags,
+ runnersPath: '/root/project/runners#js-runners-settings',
+ });
+ });
+
+ it('renders information about the tags not being set', () => {
+ expect(findStuckWithTags().exists()).toBe(true);
+ expect(findStuckNoActiveRunners().exists()).toBe(false);
+ expect(findStuckNoRunners().exists()).toBe(false);
+ });
+
+ it('renders tags', () => {
+ findAllBadges().wrappers.forEach((badgeElt, index) => {
+ return expect(badgeElt.text()).toBe(tags[index]);
+ });
+ });
+
+ it('renders link to runners page', () => {
+ expect(findRunnerPathLink().attributes('href')).toBe(
+ '/root/project/runners#js-runners-settings',
+ );
+ });
+ });
+
+ describe('without active runners', () => {
+ beforeEach(() => {
+ createWrapper({
+ hasOfflineRunnersForProject: false,
+ runnersPath: '/root/project/runners#js-runners-settings',
+ });
+ });
+
+ it('renders information about project not having runners', () => {
+ expect(findStuckNoActiveRunners().exists()).toBe(true);
+ expect(findStuckNoRunners().exists()).toBe(false);
+ expect(findStuckWithTags().exists()).toBe(false);
+ });
+
+ it('renders link to runners page', () => {
+ expect(findRunnerPathLink().attributes('href')).toBe(
+ '/root/project/runners#js-runners-settings',
+ );
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/components/unmet_prerequisites_block_spec.js b/spec/frontend/ci/job_details/components/unmet_prerequisites_block_spec.js
new file mode 100644
index 00000000000..08966743901
--- /dev/null
+++ b/spec/frontend/ci/job_details/components/unmet_prerequisites_block_spec.js
@@ -0,0 +1,37 @@
+import { GlAlert, GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import UnmetPrerequisitesBlock from '~/ci/job_details/components/unmet_prerequisites_block.vue';
+
+describe('Unmet Prerequisites Block Job component', () => {
+ let wrapper;
+ const helpPath = '/user/project/clusters/index.html#troubleshooting-failed-deployment-jobs';
+
+ const createComponent = () => {
+ wrapper = shallowMount(UnmetPrerequisitesBlock, {
+ propsData: {
+ helpPath,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders an alert with the correct message', () => {
+ const container = wrapper.findComponent(GlAlert);
+ const alertMessage =
+ 'This job failed because the necessary resources were not successfully created.';
+
+ expect(container).not.toBeNull();
+ expect(container.text()).toContain(alertMessage);
+ });
+
+ it('renders link to help page', () => {
+ const helpLink = wrapper.findComponent(GlLink);
+
+ expect(helpLink).not.toBeNull();
+ expect(helpLink.text()).toContain('More information');
+ expect(helpLink.attributes().href).toEqual(helpPath);
+ });
+});
diff --git a/spec/frontend/ci/job_details/job_app_spec.js b/spec/frontend/ci/job_details/job_app_spec.js
new file mode 100644
index 00000000000..c2d91771495
--- /dev/null
+++ b/spec/frontend/ci/job_details/job_app_spec.js
@@ -0,0 +1,343 @@
+import Vue, { nextTick } from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import { GlLoadingIcon } from '@gitlab/ui';
+import MockAdapter from 'axios-mock-adapter';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { TEST_HOST } from 'helpers/test_constants';
+import EmptyState from '~/ci/job_details/components/empty_state.vue';
+import EnvironmentsBlock from '~/ci/job_details/components/environments_block.vue';
+import ErasedBlock from '~/ci/job_details/components/erased_block.vue';
+import JobApp from '~/ci/job_details/job_app.vue';
+import JobLog from '~/ci/job_details/components/log/log.vue';
+import JobLogTopBar from 'ee_else_ce/ci/job_details/components/job_log_controllers.vue';
+import Sidebar from '~/ci/job_details/components/sidebar/sidebar.vue';
+import StuckBlock from '~/ci/job_details/components/stuck_block.vue';
+import UnmetPrerequisitesBlock from '~/ci/job_details/components/unmet_prerequisites_block.vue';
+import createStore from '~/ci/job_details/store';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import { MANUAL_STATUS } from '~/ci/constants';
+import job from 'jest/ci/jobs_mock_data';
+import { mockPendingJobData } from './mock_data';
+
+describe('Job App', () => {
+ Vue.use(Vuex);
+
+ let store;
+ let wrapper;
+ let mock;
+
+ const initSettings = {
+ endpoint: `${TEST_HOST}jobs/123.json`,
+ pagePath: `${TEST_HOST}jobs/123`,
+ logState:
+ 'eyJvZmZzZXQiOjE3NDUxLCJuX29wZW5fdGFncyI6MCwiZmdfY29sb3IiOm51bGwsImJnX2NvbG9yIjpudWxsLCJzdHlsZV9tYXNrIjowfQ%3D%3D',
+ };
+
+ const props = {
+ artifactHelpUrl: 'help/artifact',
+ deploymentHelpUrl: 'help/deployment',
+ runnerSettingsUrl: 'settings/ci-cd/runners',
+ terminalPath: 'jobs/123/terminal',
+ projectPath: 'user-name/project-name',
+ subscriptionsMoreMinutesUrl: 'https://customers.gitlab.com/buy_pipeline_minutes',
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(JobApp, {
+ propsData: { ...props },
+ store,
+ });
+ };
+
+ const setupAndMount = async ({ jobData = {}, jobLogData = {} } = {}) => {
+ mock.onGet(initSettings.endpoint).replyOnce(HTTP_STATUS_OK, { ...job, ...jobData });
+ mock.onGet(`${initSettings.pagePath}/trace.json`).reply(HTTP_STATUS_OK, jobLogData);
+
+ const asyncInit = store.dispatch('init', initSettings);
+
+ createComponent();
+
+ await asyncInit;
+ jest.runOnlyPendingTimers();
+ await axios.waitForAll();
+ await nextTick();
+ };
+
+ const findLoadingComponent = () => wrapper.findComponent(GlLoadingIcon);
+ const findSidebar = () => wrapper.findComponent(Sidebar);
+ const findStuckBlockComponent = () => wrapper.findComponent(StuckBlock);
+ const findFailedJobComponent = () => wrapper.findComponent(UnmetPrerequisitesBlock);
+ const findEnvironmentsBlockComponent = () => wrapper.findComponent(EnvironmentsBlock);
+ const findErasedBlock = () => wrapper.findComponent(ErasedBlock);
+ const findEmptyState = () => wrapper.findComponent(EmptyState);
+ const findJobLog = () => wrapper.findComponent(JobLog);
+ const findJobLogTopBar = () => wrapper.findComponent(JobLogTopBar);
+
+ const findJobContent = () => wrapper.findByTestId('job-content');
+ const findArchivedJob = () => wrapper.findByTestId('archived-job');
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ store = createStore();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
+ wrapper.destroy();
+ });
+
+ describe('while loading', () => {
+ beforeEach(() => {
+ store.state.isLoading = true;
+ createComponent();
+ });
+
+ it('renders loading icon', () => {
+ expect(findLoadingComponent().exists()).toBe(true);
+ expect(findSidebar().exists()).toBe(false);
+ expect(findJobContent().exists()).toBe(false);
+ });
+ });
+
+ describe('with successful request', () => {
+ describe('Header section', () => {
+ describe('job callout message', () => {
+ it('should not render the reason when reason is absent', () =>
+ setupAndMount().then(() => {
+ expect(wrapper.vm.shouldRenderCalloutMessage).toBe(false);
+ }));
+
+ it('should render the reason when reason is present', () =>
+ setupAndMount({
+ jobData: {
+ callout_message: 'There is an unkown failure, please try again',
+ },
+ }).then(() => {
+ expect(wrapper.vm.shouldRenderCalloutMessage).toBe(true);
+ }));
+ });
+ });
+
+ describe('stuck block', () => {
+ describe('without active runners available', () => {
+ it('renders stuck block when there are no runners', () =>
+ setupAndMount({
+ jobData: {
+ status: {
+ group: 'pending',
+ icon: 'status_pending',
+ label: 'pending',
+ text: 'pending',
+ details_path: 'path',
+ },
+ stuck: true,
+ runners: {
+ available: false,
+ online: false,
+ },
+ tags: [],
+ },
+ }).then(() => {
+ expect(findStuckBlockComponent().exists()).toBe(true);
+ }));
+ });
+
+ it('does not render stuck block when there are runners', () =>
+ setupAndMount({
+ jobData: {
+ runners: { available: true },
+ },
+ }).then(() => {
+ expect(findStuckBlockComponent().exists()).toBe(false);
+ }));
+ });
+
+ describe('unmet prerequisites block', () => {
+ it('renders unmet prerequisites block when there is an unmet prerequisites failure', () =>
+ setupAndMount({
+ jobData: {
+ status: {
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ details_path: 'path',
+ illustration: {
+ content: 'Retry this job in order to create the necessary resources.',
+ image: 'path',
+ size: 'svg-430',
+ title: 'Failed to create resources',
+ },
+ },
+ failure_reason: 'unmet_prerequisites',
+ has_trace: false,
+ runners: {
+ available: true,
+ },
+ tags: [],
+ },
+ }).then(() => {
+ expect(findFailedJobComponent().exists()).toBe(true);
+ }));
+ });
+
+ describe('environments block', () => {
+ it('renders environment block when job has environment', () =>
+ setupAndMount({
+ jobData: {
+ deployment_status: {
+ environment: {
+ environment_path: '/path',
+ name: 'foo',
+ },
+ },
+ },
+ }).then(() => {
+ expect(findEnvironmentsBlockComponent().exists()).toBe(true);
+ }));
+
+ it('does not render environment block when job has environment', () =>
+ setupAndMount().then(() => {
+ expect(findEnvironmentsBlockComponent().exists()).toBe(false);
+ }));
+ });
+
+ describe('erased block', () => {
+ it('renders erased block when `erased` is true', () =>
+ setupAndMount({
+ jobData: {
+ erased_by: {
+ username: 'root',
+ web_url: 'gitlab.com/root',
+ },
+ erased_at: '2016-11-07T11:11:16.525Z',
+ },
+ }).then(() => {
+ expect(findErasedBlock().exists()).toBe(true);
+ }));
+
+ it('does not render erased block when `erased` is false', () =>
+ setupAndMount({
+ jobData: {
+ erased_at: null,
+ },
+ }).then(() => {
+ expect(findErasedBlock().exists()).toBe(false);
+ }));
+ });
+
+ describe('empty states block', () => {
+ it('renders empty state when job does not have log and is not running', () =>
+ setupAndMount({
+ jobData: {
+ has_trace: false,
+ status: {
+ group: 'pending',
+ icon: 'status_pending',
+ label: 'pending',
+ text: 'pending',
+ details_path: 'path',
+ illustration: {
+ image: 'path',
+ size: '340',
+ title: 'Empty State',
+ content: 'This is an empty state',
+ },
+ action: {
+ button_title: 'Retry job',
+ method: 'post',
+ path: '/path',
+ },
+ },
+ },
+ }).then(() => {
+ expect(findEmptyState().exists()).toBe(true);
+ }));
+
+ it('does not render empty state when job does not have log but it is running', () =>
+ setupAndMount({
+ jobData: {
+ has_trace: false,
+ status: {
+ group: 'running',
+ icon: 'status_running',
+ label: 'running',
+ text: 'running',
+ details_path: 'path',
+ },
+ },
+ }).then(() => {
+ expect(findEmptyState().exists()).toBe(false);
+ }));
+
+ it('does not render empty state when job has log but it is not running', () =>
+ setupAndMount({ jobData: { has_trace: true } }).then(() => {
+ expect(findEmptyState().exists()).toBe(false);
+ }));
+ });
+
+ describe('sidebar', () => {
+ it('renders sidebar', async () => {
+ await setupAndMount();
+
+ expect(findSidebar().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('archived job', () => {
+ beforeEach(() => setupAndMount({ jobData: { archived: true } }));
+
+ it('renders warning about job being archived', () => {
+ expect(findArchivedJob().exists()).toBe(true);
+ });
+ });
+
+ describe('non-archived job', () => {
+ beforeEach(() => setupAndMount());
+
+ it('does not warning about job being archived', () => {
+ expect(findArchivedJob().exists()).toBe(false);
+ });
+ });
+
+ describe('job log', () => {
+ beforeEach(() => setupAndMount());
+
+ it('should render job log header', () => {
+ expect(findJobLogTopBar().exists()).toBe(true);
+ });
+
+ it('should render job log', () => {
+ expect(findJobLog().exists()).toBe(true);
+ });
+ });
+
+ describe('job log polling', () => {
+ beforeEach(() => {
+ jest.spyOn(store, 'dispatch');
+ });
+
+ it('should poll job log by default', async () => {
+ await setupAndMount({
+ jobData: mockPendingJobData,
+ });
+
+ expect(store.dispatch).toHaveBeenCalledWith('fetchJobLog');
+ });
+
+ it('should NOT poll job log for manual variables form empty state', async () => {
+ const manualPendingJobData = mockPendingJobData;
+ manualPendingJobData.status.group = MANUAL_STATUS;
+
+ await setupAndMount({
+ jobData: manualPendingJobData,
+ });
+
+ expect(store.dispatch).not.toHaveBeenCalledWith('fetchJobLog');
+ });
+ });
+});
diff --git a/spec/frontend/jobs/components/job/mock_data.js b/spec/frontend/ci/job_details/mock_data.js
index fb3a361c9c9..fb3a361c9c9 100644
--- a/spec/frontend/jobs/components/job/mock_data.js
+++ b/spec/frontend/ci/job_details/mock_data.js
diff --git a/spec/frontend/ci/job_details/store/actions_spec.js b/spec/frontend/ci/job_details/store/actions_spec.js
new file mode 100644
index 00000000000..bb5c1fe32bd
--- /dev/null
+++ b/spec/frontend/ci/job_details/store/actions_spec.js
@@ -0,0 +1,502 @@
+import MockAdapter from 'axios-mock-adapter';
+import { TEST_HOST } from 'helpers/test_constants';
+import testAction from 'helpers/vuex_action_helper';
+import {
+ setJobEndpoint,
+ setJobLogOptions,
+ clearEtagPoll,
+ stopPolling,
+ requestJob,
+ fetchJob,
+ receiveJobSuccess,
+ receiveJobError,
+ scrollTop,
+ scrollBottom,
+ requestJobLog,
+ fetchJobLog,
+ startPollingJobLog,
+ stopPollingJobLog,
+ receiveJobLogSuccess,
+ receiveJobLogError,
+ toggleCollapsibleLine,
+ requestJobsForStage,
+ fetchJobsForStage,
+ receiveJobsForStageSuccess,
+ receiveJobsForStageError,
+ hideSidebar,
+ showSidebar,
+ toggleSidebar,
+} from '~/ci/job_details/store/actions';
+import * as types from '~/ci/job_details/store/mutation_types';
+import state from '~/ci/job_details/store/state';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+
+describe('Job State actions', () => {
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = state();
+ });
+
+ describe('setJobEndpoint', () => {
+ it('should commit SET_JOB_ENDPOINT mutation', () => {
+ return testAction(
+ setJobEndpoint,
+ 'job/872324.json',
+ mockedState,
+ [{ type: types.SET_JOB_ENDPOINT, payload: 'job/872324.json' }],
+ [],
+ );
+ });
+ });
+
+ describe('setJobLogOptions', () => {
+ it('should commit SET_JOB_LOG_OPTIONS mutation', () => {
+ return testAction(
+ setJobLogOptions,
+ { pagePath: 'job/872324/trace.json' },
+ mockedState,
+ [{ type: types.SET_JOB_LOG_OPTIONS, payload: { pagePath: 'job/872324/trace.json' } }],
+ [],
+ );
+ });
+ });
+
+ describe('hideSidebar', () => {
+ it('should commit HIDE_SIDEBAR mutation', () => {
+ return testAction(hideSidebar, null, mockedState, [{ type: types.HIDE_SIDEBAR }], []);
+ });
+ });
+
+ describe('showSidebar', () => {
+ it('should commit SHOW_SIDEBAR mutation', () => {
+ return testAction(showSidebar, null, mockedState, [{ type: types.SHOW_SIDEBAR }], []);
+ });
+ });
+
+ describe('toggleSidebar', () => {
+ describe('when isSidebarOpen is true', () => {
+ it('should dispatch hideSidebar', () => {
+ return testAction(toggleSidebar, null, mockedState, [], [{ type: 'hideSidebar' }]);
+ });
+ });
+
+ describe('when isSidebarOpen is false', () => {
+ it('should dispatch showSidebar', () => {
+ mockedState.isSidebarOpen = false;
+
+ return testAction(toggleSidebar, null, mockedState, [], [{ type: 'showSidebar' }]);
+ });
+ });
+ });
+
+ describe('requestJob', () => {
+ it('should commit REQUEST_JOB mutation', () => {
+ return testAction(requestJob, null, mockedState, [{ type: types.REQUEST_JOB }], []);
+ });
+ });
+
+ describe('fetchJob', () => {
+ let mock;
+
+ beforeEach(() => {
+ mockedState.jobEndpoint = `${TEST_HOST}/endpoint.json`;
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ stopPolling();
+ clearEtagPoll();
+ });
+
+ describe('success', () => {
+ it('dispatches requestJob and receiveJobSuccess', () => {
+ mock
+ .onGet(`${TEST_HOST}/endpoint.json`)
+ .replyOnce(HTTP_STATUS_OK, { id: 121212, name: 'karma' });
+
+ return testAction(
+ fetchJob,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestJob',
+ },
+ {
+ payload: { id: 121212, name: 'karma' },
+ type: 'receiveJobSuccess',
+ },
+ ],
+ );
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onGet(`${TEST_HOST}/endpoint.json`).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ });
+
+ it('dispatches requestJob and receiveJobError', () => {
+ return testAction(
+ fetchJob,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestJob',
+ },
+ {
+ type: 'receiveJobError',
+ },
+ ],
+ );
+ });
+ });
+ });
+
+ describe('receiveJobSuccess', () => {
+ it('should commit RECEIVE_JOB_SUCCESS mutation', () => {
+ return testAction(
+ receiveJobSuccess,
+ { id: 121232132 },
+ mockedState,
+ [{ type: types.RECEIVE_JOB_SUCCESS, payload: { id: 121232132 } }],
+ [],
+ );
+ });
+ });
+
+ describe('receiveJobError', () => {
+ it('should commit RECEIVE_JOB_ERROR mutation', () => {
+ return testAction(
+ receiveJobError,
+ null,
+ mockedState,
+ [{ type: types.RECEIVE_JOB_ERROR }],
+ [],
+ );
+ });
+ });
+
+ describe('scrollTop', () => {
+ it('should dispatch toggleScrollButtons action', () => {
+ return testAction(scrollTop, null, mockedState, [], [{ type: 'toggleScrollButtons' }]);
+ });
+ });
+
+ describe('scrollBottom', () => {
+ it('should dispatch toggleScrollButtons action', () => {
+ return testAction(scrollBottom, null, mockedState, [], [{ type: 'toggleScrollButtons' }]);
+ });
+ });
+
+ describe('requestJobLog', () => {
+ it('should commit REQUEST_JOB_LOG mutation', () => {
+ return testAction(requestJobLog, null, mockedState, [{ type: types.REQUEST_JOB_LOG }], []);
+ });
+ });
+
+ describe('fetchJobLog', () => {
+ let mock;
+
+ beforeEach(() => {
+ mockedState.jobLogEndpoint = `${TEST_HOST}/endpoint`;
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ stopPolling();
+ clearEtagPoll();
+ });
+
+ describe('success', () => {
+ it('dispatches requestJobLog, receiveJobLogSuccess and stopPollingJobLog when job is complete', () => {
+ mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, {
+ html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
+ complete: true,
+ });
+
+ return testAction(
+ fetchJobLog,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'toggleScrollisInBottom',
+ payload: true,
+ },
+ {
+ payload: {
+ html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
+ complete: true,
+ },
+ type: 'receiveJobLogSuccess',
+ },
+ {
+ type: 'stopPollingJobLog',
+ },
+ ],
+ );
+ });
+
+ describe('when job is incomplete', () => {
+ let jobLogPayload;
+
+ beforeEach(() => {
+ jobLogPayload = {
+ html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
+ complete: false,
+ };
+
+ mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, jobLogPayload);
+ });
+
+ it('dispatches startPollingJobLog', () => {
+ return testAction(
+ fetchJobLog,
+ null,
+ mockedState,
+ [],
+ [
+ { type: 'toggleScrollisInBottom', payload: true },
+ { type: 'receiveJobLogSuccess', payload: jobLogPayload },
+ { type: 'startPollingJobLog' },
+ ],
+ );
+ });
+
+ it('does not dispatch startPollingJobLog when timeout is non-empty', () => {
+ mockedState.jobLogTimeout = 1;
+
+ return testAction(
+ fetchJobLog,
+ null,
+ mockedState,
+ [],
+ [
+ { type: 'toggleScrollisInBottom', payload: true },
+ { type: 'receiveJobLogSuccess', payload: jobLogPayload },
+ ],
+ );
+ });
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onGet(`${TEST_HOST}/endpoint/trace.json`).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ });
+
+ it('dispatches requestJobLog and receiveJobLogError', () => {
+ return testAction(
+ fetchJobLog,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'receiveJobLogError',
+ },
+ ],
+ );
+ });
+ });
+ });
+
+ describe('startPollingJobLog', () => {
+ let dispatch;
+ let commit;
+
+ beforeEach(() => {
+ dispatch = jest.fn();
+ commit = jest.fn();
+
+ startPollingJobLog({ dispatch, commit });
+ });
+
+ afterEach(() => {
+ jest.clearAllTimers();
+ });
+
+ it('should save the timeout id but not call fetchJobLog', () => {
+ expect(commit).toHaveBeenCalledWith(types.SET_JOB_LOG_TIMEOUT, expect.any(Number));
+ expect(commit.mock.calls[0][1]).toBeGreaterThan(0);
+
+ expect(dispatch).not.toHaveBeenCalledWith('fetchJobLog');
+ });
+
+ describe('after timeout has passed', () => {
+ beforeEach(() => {
+ jest.advanceTimersByTime(4000);
+ });
+
+ it('should clear the timeout id and fetchJobLog', () => {
+ expect(commit).toHaveBeenCalledWith(types.SET_JOB_LOG_TIMEOUT, 0);
+ expect(dispatch).toHaveBeenCalledWith('fetchJobLog');
+ });
+ });
+ });
+
+ describe('stopPollingJobLog', () => {
+ let origTimeout;
+
+ beforeEach(() => {
+ // Can't use spyOn(window, 'clearTimeout') because this caused unrelated specs to timeout
+ // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23838#note_280277727
+ origTimeout = window.clearTimeout;
+ window.clearTimeout = jest.fn();
+ });
+
+ afterEach(() => {
+ window.clearTimeout = origTimeout;
+ });
+
+ it('should commit STOP_POLLING_JOB_LOG mutation', async () => {
+ const jobLogTimeout = 7;
+
+ await testAction(
+ stopPollingJobLog,
+ null,
+ { ...mockedState, jobLogTimeout },
+ [{ type: types.SET_JOB_LOG_TIMEOUT, payload: 0 }, { type: types.STOP_POLLING_JOB_LOG }],
+ [],
+ );
+ expect(window.clearTimeout).toHaveBeenCalledWith(jobLogTimeout);
+ });
+ });
+
+ describe('receiveJobLogSuccess', () => {
+ it('should commit RECEIVE_JOB_LOG_SUCCESS mutation', () => {
+ return testAction(
+ receiveJobLogSuccess,
+ 'hello world',
+ mockedState,
+ [{ type: types.RECEIVE_JOB_LOG_SUCCESS, payload: 'hello world' }],
+ [],
+ );
+ });
+ });
+
+ describe('receiveJobLogError', () => {
+ it('should commit stop polling job log', () => {
+ return testAction(receiveJobLogError, null, mockedState, [], [{ type: 'stopPollingJobLog' }]);
+ });
+ });
+
+ describe('toggleCollapsibleLine', () => {
+ it('should commit TOGGLE_COLLAPSIBLE_LINE mutation', () => {
+ return testAction(
+ toggleCollapsibleLine,
+ { isClosed: true },
+ mockedState,
+ [{ type: types.TOGGLE_COLLAPSIBLE_LINE, payload: { isClosed: true } }],
+ [],
+ );
+ });
+ });
+
+ describe('requestJobsForStage', () => {
+ it('should commit REQUEST_JOBS_FOR_STAGE mutation', () => {
+ return testAction(
+ requestJobsForStage,
+ { name: 'deploy' },
+ mockedState,
+ [{ type: types.REQUEST_JOBS_FOR_STAGE, payload: { name: 'deploy' } }],
+ [],
+ );
+ });
+ });
+
+ describe('fetchJobsForStage', () => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('success', () => {
+ it('dispatches requestJobsForStage and receiveJobsForStageSuccess', () => {
+ mock.onGet(`${TEST_HOST}/jobs.json`).replyOnce(HTTP_STATUS_OK, {
+ latest_statuses: [{ id: 121212, name: 'build' }],
+ retried: [],
+ });
+
+ return testAction(
+ fetchJobsForStage,
+ { dropdown_path: `${TEST_HOST}/jobs.json` },
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestJobsForStage',
+ payload: { dropdown_path: `${TEST_HOST}/jobs.json` },
+ },
+ {
+ payload: [{ id: 121212, name: 'build' }],
+ type: 'receiveJobsForStageSuccess',
+ },
+ ],
+ );
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onGet(`${TEST_HOST}/jobs.json`).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ });
+
+ it('dispatches requestJobsForStage and receiveJobsForStageError', () => {
+ return testAction(
+ fetchJobsForStage,
+ { dropdown_path: `${TEST_HOST}/jobs.json` },
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestJobsForStage',
+ payload: { dropdown_path: `${TEST_HOST}/jobs.json` },
+ },
+ {
+ type: 'receiveJobsForStageError',
+ },
+ ],
+ );
+ });
+ });
+ });
+
+ describe('receiveJobsForStageSuccess', () => {
+ it('should commit RECEIVE_JOBS_FOR_STAGE_SUCCESS mutation', () => {
+ return testAction(
+ receiveJobsForStageSuccess,
+ [{ id: 121212, name: 'karma' }],
+ mockedState,
+ [{ type: types.RECEIVE_JOBS_FOR_STAGE_SUCCESS, payload: [{ id: 121212, name: 'karma' }] }],
+ [],
+ );
+ });
+ });
+
+ describe('receiveJobsForStageError', () => {
+ it('should commit RECEIVE_JOBS_FOR_STAGE_ERROR mutation', () => {
+ return testAction(
+ receiveJobsForStageError,
+ null,
+ mockedState,
+ [{ type: types.RECEIVE_JOBS_FOR_STAGE_ERROR }],
+ [],
+ );
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/store/getters_spec.js b/spec/frontend/ci/job_details/store/getters_spec.js
new file mode 100644
index 00000000000..dfa5f9d4781
--- /dev/null
+++ b/spec/frontend/ci/job_details/store/getters_spec.js
@@ -0,0 +1,245 @@
+import * as getters from '~/ci/job_details/store/getters';
+import state from '~/ci/job_details/store/state';
+
+describe('Job Store Getters', () => {
+ let localState;
+
+ beforeEach(() => {
+ localState = state();
+ });
+
+ describe('headerTime', () => {
+ describe('when the job has started key', () => {
+ it('returns started_at value', () => {
+ const started = '2018-08-31T16:20:49.023Z';
+ const startedAt = '2018-08-31T16:20:49.023Z';
+ localState.job.started_at = startedAt;
+ localState.job.started = started;
+
+ expect(getters.headerTime(localState)).toEqual(startedAt);
+ });
+ });
+
+ describe('when the job does not have started key', () => {
+ it('returns created_at value', () => {
+ const created = '2018-08-31T16:20:49.023Z';
+ localState.job.created_at = created;
+
+ expect(getters.headerTime(localState)).toEqual(created);
+ });
+ });
+ });
+
+ describe('shouldRenderCalloutMessage', () => {
+ describe('with status and callout message', () => {
+ it('returns true', () => {
+ localState.job.callout_message = 'Callout message';
+ localState.job.status = { icon: 'passed' };
+
+ expect(getters.shouldRenderCalloutMessage(localState)).toEqual(true);
+ });
+ });
+
+ describe('without status & with callout message', () => {
+ it('returns false', () => {
+ localState.job.callout_message = 'Callout message';
+
+ expect(getters.shouldRenderCalloutMessage(localState)).toEqual(false);
+ });
+ });
+
+ describe('with status & without callout message', () => {
+ it('returns false', () => {
+ localState.job.status = { icon: 'passed' };
+
+ expect(getters.shouldRenderCalloutMessage(localState)).toEqual(false);
+ });
+ });
+ });
+
+ describe('shouldRenderTriggeredLabel', () => {
+ describe('when started equals null', () => {
+ it('returns false', () => {
+ localState.job.started_at = null;
+
+ expect(getters.shouldRenderTriggeredLabel(localState)).toEqual(false);
+ });
+ });
+
+ describe('when started equals string', () => {
+ it('returns true', () => {
+ localState.job.started_at = '2018-08-31T16:20:49.023Z';
+
+ expect(getters.shouldRenderTriggeredLabel(localState)).toEqual(true);
+ });
+ });
+ });
+
+ describe('hasEnvironment', () => {
+ describe('without `deployment_status`', () => {
+ it('returns false', () => {
+ expect(getters.hasEnvironment(localState)).toEqual(false);
+ });
+ });
+
+ describe('with an empty object for `deployment_status`', () => {
+ it('returns false', () => {
+ localState.job.deployment_status = {};
+
+ expect(getters.hasEnvironment(localState)).toEqual(false);
+ });
+ });
+
+ describe('when `deployment_status` is defined and not empty', () => {
+ it('returns true', () => {
+ localState.job.deployment_status = {
+ status: 'creating',
+ environment: {
+ last_deployment: {},
+ },
+ };
+
+ expect(getters.hasEnvironment(localState)).toEqual(true);
+ });
+ });
+ });
+
+ describe('hasJobLog', () => {
+ describe('when has_trace is true', () => {
+ it('returns true', () => {
+ localState.job.has_trace = true;
+ localState.job.status = {};
+
+ expect(getters.hasJobLog(localState)).toEqual(true);
+ });
+ });
+
+ describe('when job is running', () => {
+ it('returns true', () => {
+ localState.job.has_trace = false;
+ localState.job.status = { group: 'running' };
+
+ expect(getters.hasJobLog(localState)).toEqual(true);
+ });
+ });
+
+ describe('when has_trace is false and job is not running', () => {
+ it('returns false', () => {
+ localState.job.has_trace = false;
+ localState.job.status = { group: 'pending' };
+
+ expect(getters.hasJobLog(localState)).toEqual(false);
+ });
+ });
+ });
+
+ describe('emptyStateIllustration', () => {
+ describe('with defined illustration', () => {
+ it('returns the state illustration object', () => {
+ localState.job.status = {
+ illustration: {
+ path: 'foo',
+ },
+ };
+
+ expect(getters.emptyStateIllustration(localState)).toEqual({ path: 'foo' });
+ });
+ });
+
+ describe('when illustration is not defined', () => {
+ it('returns an empty object', () => {
+ expect(getters.emptyStateIllustration(localState)).toEqual({});
+ });
+ });
+ });
+
+ describe('shouldRenderSharedRunnerLimitWarning', () => {
+ describe('without runners information', () => {
+ it('returns false', () => {
+ expect(getters.shouldRenderSharedRunnerLimitWarning(localState)).toEqual(false);
+ });
+ });
+
+ describe('with runners information', () => {
+ describe('when used quota is less than limit', () => {
+ it('returns false', () => {
+ localState.job.runners = {
+ quota: {
+ used: 33,
+ limit: 2000,
+ },
+ available: true,
+ online: true,
+ };
+
+ expect(getters.shouldRenderSharedRunnerLimitWarning(localState)).toEqual(false);
+ });
+ });
+
+ describe('when used quota is equal to limit', () => {
+ it('returns true', () => {
+ localState.job.runners = {
+ quota: {
+ used: 2000,
+ limit: 2000,
+ },
+ available: true,
+ online: true,
+ };
+
+ expect(getters.shouldRenderSharedRunnerLimitWarning(localState)).toEqual(true);
+ });
+ });
+
+ describe('when used quota is bigger than limit', () => {
+ it('returns true', () => {
+ localState.job.runners = {
+ quota: {
+ used: 2002,
+ limit: 2000,
+ },
+ available: true,
+ online: true,
+ };
+
+ expect(getters.shouldRenderSharedRunnerLimitWarning(localState)).toEqual(true);
+ });
+ });
+ });
+ });
+
+ describe('hasOfflineRunnersForProject', () => {
+ describe('with available and offline runners', () => {
+ it('returns true', () => {
+ localState.job.runners = {
+ available: true,
+ online: false,
+ };
+
+ expect(getters.hasOfflineRunnersForProject(localState)).toEqual(true);
+ });
+ });
+
+ describe('with non available runners', () => {
+ it('returns false', () => {
+ localState.job.runners = {
+ available: false,
+ online: false,
+ };
+
+ expect(getters.hasOfflineRunnersForProject(localState)).toEqual(false);
+ });
+ });
+
+ describe('with online runners', () => {
+ it('returns false', () => {
+ localState.job.runners = {
+ available: false,
+ online: true,
+ };
+
+ expect(getters.hasOfflineRunnersForProject(localState)).toEqual(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/store/helpers.js b/spec/frontend/ci/job_details/store/helpers.js
new file mode 100644
index 00000000000..6b186e094e7
--- /dev/null
+++ b/spec/frontend/ci/job_details/store/helpers.js
@@ -0,0 +1,5 @@
+import state from '~/ci/job_details/store/state';
+
+export const resetStore = (store) => {
+ store.replaceState(state());
+};
diff --git a/spec/frontend/ci/job_details/store/mutations_spec.js b/spec/frontend/ci/job_details/store/mutations_spec.js
new file mode 100644
index 00000000000..0835c534fb9
--- /dev/null
+++ b/spec/frontend/ci/job_details/store/mutations_spec.js
@@ -0,0 +1,269 @@
+import * as types from '~/ci/job_details/store/mutation_types';
+import mutations from '~/ci/job_details/store/mutations';
+import state from '~/ci/job_details/store/state';
+
+describe('Jobs Store Mutations', () => {
+ let stateCopy;
+
+ const html =
+ 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- : Writing /builds/ab89e95b0fa0b9272ea0c797b76908f24d36992630e9325273a4ce3.png<br>I';
+
+ beforeEach(() => {
+ stateCopy = state();
+ });
+
+ describe('SET_JOB_ENDPOINT', () => {
+ it('should set jobEndpoint', () => {
+ mutations[types.SET_JOB_ENDPOINT](stateCopy, 'job/21312321.json');
+
+ expect(stateCopy.jobEndpoint).toEqual('job/21312321.json');
+ });
+ });
+
+ describe('HIDE_SIDEBAR', () => {
+ it('should set isSidebarOpen to false', () => {
+ mutations[types.HIDE_SIDEBAR](stateCopy);
+
+ expect(stateCopy.isSidebarOpen).toEqual(false);
+ });
+ });
+
+ describe('SHOW_SIDEBAR', () => {
+ it('should set isSidebarOpen to true', () => {
+ mutations[types.SHOW_SIDEBAR](stateCopy);
+
+ expect(stateCopy.isSidebarOpen).toEqual(true);
+ });
+ });
+
+ describe('RECEIVE_JOB_LOG_SUCCESS', () => {
+ describe('when job log has state', () => {
+ it('sets jobLogState', () => {
+ const stateLog =
+ 'eyJvZmZzZXQiOjczNDQ1MSwibl9vcGVuX3RhZ3MiOjAsImZnX2NvbG9yIjpudWxsLCJiZ19jb2xvciI6bnVsbCwic3R5bGVfbWFzayI6MH0=';
+ mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
+ state: stateLog,
+ });
+
+ expect(stateCopy.jobLogState).toEqual(stateLog);
+ });
+ });
+
+ describe('when jobLogSize is smaller than the total size', () => {
+ it('sets isJobLogSizeVisible to true', () => {
+ mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, { total: 51184600, size: 1231 });
+
+ expect(stateCopy.isJobLogSizeVisible).toEqual(true);
+ });
+ });
+
+ describe('when jobLogSize is bigger than the total size', () => {
+ it('sets isJobLogSizeVisible to false', () => {
+ const copy = { ...stateCopy, jobLogSize: 5118460, size: 2321312 };
+
+ mutations[types.RECEIVE_JOB_LOG_SUCCESS](copy, { total: 511846 });
+
+ expect(copy.isJobLogSizeVisible).toEqual(false);
+ });
+ });
+
+ it('sets job log size and isJobLogComplete', () => {
+ mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
+ append: true,
+ html,
+ size: 511846,
+ complete: true,
+ lines: [],
+ });
+
+ expect(stateCopy.jobLogSize).toEqual(511846);
+ expect(stateCopy.isJobLogComplete).toEqual(true);
+ });
+
+ describe('with new job log', () => {
+ describe('log.lines', () => {
+ describe('when append is true', () => {
+ it('sets the parsed log', () => {
+ mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
+ append: true,
+ size: 511846,
+ complete: true,
+ lines: [
+ {
+ offset: 1,
+ content: [{ text: 'Running with gitlab-runner 11.12.1 (5a147c92)' }],
+ },
+ ],
+ });
+
+ expect(stateCopy.jobLog).toEqual([
+ {
+ offset: 1,
+ content: [{ text: 'Running with gitlab-runner 11.12.1 (5a147c92)' }],
+ lineNumber: 0,
+ },
+ ]);
+ });
+ });
+
+ describe('when it is defined', () => {
+ it('sets the parsed log', () => {
+ mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
+ append: false,
+ size: 511846,
+ complete: true,
+ lines: [
+ { offset: 0, content: [{ text: 'Running with gitlab-runner 11.11.1 (5a147c92)' }] },
+ ],
+ });
+
+ expect(stateCopy.jobLog).toEqual([
+ {
+ offset: 0,
+ content: [{ text: 'Running with gitlab-runner 11.11.1 (5a147c92)' }],
+ lineNumber: 0,
+ },
+ ]);
+ });
+ });
+
+ describe('when it is null', () => {
+ it('sets the default value', () => {
+ mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
+ append: true,
+ html,
+ size: 511846,
+ complete: false,
+ lines: null,
+ });
+
+ expect(stateCopy.jobLog).toEqual([]);
+ });
+ });
+ });
+ });
+ });
+
+ describe('SET_JOB_LOG_TIMEOUT', () => {
+ it('sets the jobLogTimeout id', () => {
+ const id = 7;
+
+ expect(stateCopy.jobLogTimeout).not.toEqual(id);
+
+ mutations[types.SET_JOB_LOG_TIMEOUT](stateCopy, id);
+
+ expect(stateCopy.jobLogTimeout).toEqual(id);
+ });
+ });
+
+ describe('STOP_POLLING_JOB_LOG', () => {
+ it('sets isJobLogComplete to true', () => {
+ mutations[types.STOP_POLLING_JOB_LOG](stateCopy);
+
+ expect(stateCopy.isJobLogComplete).toEqual(true);
+ });
+ });
+
+ describe('TOGGLE_COLLAPSIBLE_LINE', () => {
+ it('toggles the `isClosed` property of the provided object', () => {
+ const section = { isClosed: true };
+ mutations[types.TOGGLE_COLLAPSIBLE_LINE](stateCopy, section);
+ expect(section.isClosed).toEqual(false);
+ });
+ });
+
+ describe('REQUEST_JOB', () => {
+ it('sets isLoading to true', () => {
+ mutations[types.REQUEST_JOB](stateCopy);
+
+ expect(stateCopy.isLoading).toEqual(true);
+ });
+ });
+
+ describe('RECEIVE_JOB_SUCCESS', () => {
+ it('sets is loading to false', () => {
+ mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321 });
+
+ expect(stateCopy.isLoading).toEqual(false);
+ });
+
+ it('sets hasError to false', () => {
+ mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321 });
+
+ expect(stateCopy.hasError).toEqual(false);
+ });
+
+ it('sets job data', () => {
+ mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321 });
+
+ expect(stateCopy.job).toEqual({ id: 1312321 });
+ });
+
+ it('sets selectedStage when the selectedStage is empty', () => {
+ expect(stateCopy.selectedStage).toEqual('');
+ mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321, stage: 'deploy' });
+
+ expect(stateCopy.selectedStage).toEqual('deploy');
+ });
+
+ it('does not set selectedStage when the selectedStage is not More', () => {
+ stateCopy.selectedStage = 'notify';
+
+ expect(stateCopy.selectedStage).toEqual('notify');
+ mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321, stage: 'deploy' });
+
+ expect(stateCopy.selectedStage).toEqual('notify');
+ });
+ });
+
+ describe('RECEIVE_JOB_ERROR', () => {
+ it('resets job data', () => {
+ mutations[types.RECEIVE_JOB_ERROR](stateCopy);
+
+ expect(stateCopy.isLoading).toEqual(false);
+ expect(stateCopy.job).toEqual({});
+ });
+ });
+
+ describe('REQUEST_JOBS_FOR_STAGE', () => {
+ it('sets isLoadingJobs to true', () => {
+ mutations[types.REQUEST_JOBS_FOR_STAGE](stateCopy, { name: 'deploy' });
+
+ expect(stateCopy.isLoadingJobs).toEqual(true);
+ });
+
+ it('sets selectedStage', () => {
+ mutations[types.REQUEST_JOBS_FOR_STAGE](stateCopy, { name: 'deploy' });
+
+ expect(stateCopy.selectedStage).toEqual('deploy');
+ });
+ });
+
+ describe('RECEIVE_JOBS_FOR_STAGE_SUCCESS', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_JOBS_FOR_STAGE_SUCCESS](stateCopy, [{ name: 'karma' }]);
+ });
+
+ it('sets isLoadingJobs to false', () => {
+ expect(stateCopy.isLoadingJobs).toEqual(false);
+ });
+
+ it('sets jobs', () => {
+ expect(stateCopy.jobs).toEqual([{ name: 'karma' }]);
+ });
+ });
+
+ describe('RECEIVE_JOBS_FOR_STAGE_ERROR', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_JOBS_FOR_STAGE_ERROR](stateCopy);
+ });
+
+ it('sets isLoadingJobs to false', () => {
+ expect(stateCopy.isLoadingJobs).toEqual(false);
+ });
+
+ it('resets jobs', () => {
+ expect(stateCopy.jobs).toEqual([]);
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/store/utils_spec.js b/spec/frontend/ci/job_details/store/utils_spec.js
new file mode 100644
index 00000000000..4ffba35761e
--- /dev/null
+++ b/spec/frontend/ci/job_details/store/utils_spec.js
@@ -0,0 +1,510 @@
+import {
+ logLinesParser,
+ updateIncrementalJobLog,
+ parseHeaderLine,
+ parseLine,
+ addDurationToHeader,
+ isCollapsibleSection,
+ findOffsetAndRemove,
+ getIncrementalLineNumber,
+} from '~/ci/job_details/store/utils';
+import {
+ utilsMockData,
+ originalTrace,
+ regularIncremental,
+ regularIncrementalRepeated,
+ headerTrace,
+ headerTraceIncremental,
+ collapsibleTrace,
+ collapsibleTraceIncremental,
+} from '../components/log/mock_data';
+
+describe('Jobs Store Utils', () => {
+ describe('parseHeaderLine', () => {
+ it('returns a new object with the header keys and the provided line parsed', () => {
+ const headerLine = { content: [{ text: 'foo' }] };
+ const parsedHeaderLine = parseHeaderLine(headerLine, 2);
+
+ expect(parsedHeaderLine).toEqual({
+ isClosed: false,
+ isHeader: true,
+ line: {
+ ...headerLine,
+ lineNumber: 2,
+ },
+ lines: [],
+ });
+ });
+
+ it('pre-closes a section when specified in options', () => {
+ const headerLine = { content: [{ text: 'foo' }], section_options: { collapsed: 'true' } };
+
+ const parsedHeaderLine = parseHeaderLine(headerLine, 2);
+
+ expect(parsedHeaderLine.isClosed).toBe(true);
+ });
+
+ it('expands all pre-closed sections if hash is present', () => {
+ const headerLine = { content: [{ text: 'foo' }], section_options: { collapsed: 'true' } };
+
+ const parsedHeaderLine = parseHeaderLine(headerLine, 2, '#L33');
+
+ expect(parsedHeaderLine.isClosed).toBe(false);
+ });
+ });
+
+ describe('parseLine', () => {
+ it('returns a new object with the lineNumber key added to the provided line object', () => {
+ const line = { content: [{ text: 'foo' }] };
+ const parsed = parseLine(line, 1);
+ expect(parsed.content).toEqual(line.content);
+ expect(parsed.lineNumber).toEqual(1);
+ });
+ });
+
+ describe('addDurationToHeader', () => {
+ const duration = {
+ offset: 106,
+ content: [],
+ section: 'prepare-script',
+ section_duration: '00:03',
+ };
+
+ it('adds the section duration to the correct header', () => {
+ const parsed = [
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ section: 'prepare-script',
+ content: [{ text: 'foo' }],
+ },
+ lines: [],
+ },
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ section: 'foo-bar',
+ content: [{ text: 'foo' }],
+ },
+ lines: [],
+ },
+ ];
+
+ addDurationToHeader(parsed, duration);
+
+ expect(parsed[0].line.section_duration).toEqual(duration.section_duration);
+ expect(parsed[1].line.section_duration).toEqual(undefined);
+ });
+
+ it('does not add the section duration when the headers do not match', () => {
+ const parsed = [
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ section: 'bar-foo',
+ content: [{ text: 'foo' }],
+ },
+ lines: [],
+ },
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ section: 'foo-bar',
+ content: [{ text: 'foo' }],
+ },
+ lines: [],
+ },
+ ];
+ addDurationToHeader(parsed, duration);
+
+ expect(parsed[0].line.section_duration).toEqual(undefined);
+ expect(parsed[1].line.section_duration).toEqual(undefined);
+ });
+
+ it('does not add when content has no headers', () => {
+ const parsed = [
+ {
+ section: 'bar-foo',
+ content: [{ text: 'foo' }],
+ lineNumber: 1,
+ },
+ {
+ section: 'foo-bar',
+ content: [{ text: 'foo' }],
+ lineNumber: 2,
+ },
+ ];
+
+ addDurationToHeader(parsed, duration);
+
+ expect(parsed[0].line).toEqual(undefined);
+ expect(parsed[1].line).toEqual(undefined);
+ });
+ });
+
+ describe('isCollapsibleSection', () => {
+ const header = {
+ isHeader: true,
+ line: {
+ section: 'foo',
+ },
+ };
+ const line = {
+ lineNumber: 1,
+ section: 'foo',
+ content: [],
+ };
+
+ it('returns true when line belongs to the last section', () => {
+ expect(isCollapsibleSection([header], header, { section: 'foo', content: [] })).toEqual(true);
+ });
+
+ it('returns false when last line was not an header', () => {
+ expect(isCollapsibleSection([line], line, { section: 'bar' })).toEqual(false);
+ });
+
+ it('returns false when accumulator is empty', () => {
+ expect(isCollapsibleSection([], { isHeader: true }, { section: 'bar' })).toEqual(false);
+ });
+
+ it('returns false when section_duration is defined', () => {
+ expect(isCollapsibleSection([header], header, { section_duration: '10:00' })).toEqual(false);
+ });
+
+ it('returns false when `section` is not a match', () => {
+ expect(isCollapsibleSection([header], header, { section: 'bar' })).toEqual(false);
+ });
+
+ it('returns false when no parameters are provided', () => {
+ expect(isCollapsibleSection()).toEqual(false);
+ });
+ });
+ describe('logLinesParser', () => {
+ let result;
+
+ beforeEach(() => {
+ result = logLinesParser(utilsMockData);
+ });
+
+ describe('regular line', () => {
+ it('adds a lineNumber property with correct index', () => {
+ expect(result[0].lineNumber).toEqual(0);
+ expect(result[1].line.lineNumber).toEqual(1);
+ });
+ });
+
+ describe('collapsible section', () => {
+ it('adds a `isClosed` property', () => {
+ expect(result[1].isClosed).toEqual(false);
+ });
+
+ it('adds a `isHeader` property', () => {
+ expect(result[1].isHeader).toEqual(true);
+ });
+
+ it('creates a lines array property with the content of the collapsible section', () => {
+ expect(result[1].lines.length).toEqual(2);
+ expect(result[1].lines[0].content).toEqual(utilsMockData[2].content);
+ expect(result[1].lines[1].content).toEqual(utilsMockData[3].content);
+ });
+ });
+
+ describe('section duration', () => {
+ it('adds the section information to the header section', () => {
+ expect(result[1].line.section_duration).toEqual(utilsMockData[4].section_duration);
+ });
+
+ it('does not add section duration as a line', () => {
+ expect(result[1].lines.includes(utilsMockData[4])).toEqual(false);
+ });
+ });
+ });
+
+ describe('findOffsetAndRemove', () => {
+ describe('when last item is header', () => {
+ const existingLog = [
+ {
+ isHeader: true,
+ isClosed: false,
+ line: { content: [{ text: 'bar' }], offset: 10, lineNumber: 1 },
+ },
+ ];
+
+ describe('and matches the offset', () => {
+ it('returns an array with the item removed', () => {
+ const newData = [{ offset: 10, content: [{ text: 'foobar' }] }];
+ const result = findOffsetAndRemove(newData, existingLog);
+
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('and does not match the offset', () => {
+ it('returns the provided existing log', () => {
+ const newData = [{ offset: 110, content: [{ text: 'foobar' }] }];
+ const result = findOffsetAndRemove(newData, existingLog);
+
+ expect(result).toEqual(existingLog);
+ });
+ });
+ });
+
+ describe('when last item is a regular line', () => {
+ const existingLog = [{ content: [{ text: 'bar' }], offset: 10, lineNumber: 1 }];
+
+ describe('and matches the offset', () => {
+ it('returns an array with the item removed', () => {
+ const newData = [{ offset: 10, content: [{ text: 'foobar' }] }];
+ const result = findOffsetAndRemove(newData, existingLog);
+
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('and does not match the fofset', () => {
+ it('returns the provided old log', () => {
+ const newData = [{ offset: 101, content: [{ text: 'foobar' }] }];
+ const result = findOffsetAndRemove(newData, existingLog);
+
+ expect(result).toEqual(existingLog);
+ });
+ });
+ });
+
+ describe('when last item is nested', () => {
+ const existingLog = [
+ {
+ isHeader: true,
+ isClosed: false,
+ lines: [{ offset: 101, content: [{ text: 'foobar' }], lineNumber: 2 }],
+ line: {
+ offset: 10,
+ lineNumber: 1,
+ section_duration: '10:00',
+ },
+ },
+ ];
+
+ describe('and matches the offset', () => {
+ it('returns an array with the last nested line item removed', () => {
+ const newData = [{ offset: 101, content: [{ text: 'foobar' }] }];
+
+ const result = findOffsetAndRemove(newData, existingLog);
+ expect(result[0].lines).toEqual([]);
+ });
+ });
+
+ describe('and does not match the offset', () => {
+ it('returns the provided old log', () => {
+ const newData = [{ offset: 120, content: [{ text: 'foobar' }] }];
+
+ const result = findOffsetAndRemove(newData, existingLog);
+ expect(result).toEqual(existingLog);
+ });
+ });
+ });
+
+ describe('when no data is provided', () => {
+ it('returns an empty array', () => {
+ const result = findOffsetAndRemove();
+ expect(result).toEqual([]);
+ });
+ });
+ });
+
+ describe('getIncrementalLineNumber', () => {
+ describe('when last line is 0', () => {
+ it('returns 1', () => {
+ const log = [
+ {
+ content: [],
+ lineNumber: 0,
+ },
+ ];
+
+ expect(getIncrementalLineNumber(log)).toEqual(1);
+ });
+ });
+
+ describe('with unnested line', () => {
+ it('returns the lineNumber of the last item in the array', () => {
+ const log = [
+ {
+ content: [],
+ lineNumber: 10,
+ },
+ {
+ content: [],
+ lineNumber: 101,
+ },
+ ];
+
+ expect(getIncrementalLineNumber(log)).toEqual(102);
+ });
+ });
+
+ describe('when last line is the header section', () => {
+ it('returns the lineNumber of the last item in the array', () => {
+ const log = [
+ {
+ content: [],
+ lineNumber: 10,
+ },
+ {
+ isHeader: true,
+ line: {
+ lineNumber: 101,
+ content: [],
+ },
+ lines: [],
+ },
+ ];
+
+ expect(getIncrementalLineNumber(log)).toEqual(102);
+ });
+ });
+
+ describe('when last line is a nested line', () => {
+ it('returns the lineNumber of the last item in the nested array', () => {
+ const log = [
+ {
+ content: [],
+ lineNumber: 10,
+ },
+ {
+ isHeader: true,
+ line: {
+ lineNumber: 101,
+ content: [],
+ },
+ lines: [
+ {
+ lineNumber: 102,
+ content: [],
+ },
+ { lineNumber: 103, content: [] },
+ ],
+ },
+ ];
+
+ expect(getIncrementalLineNumber(log)).toEqual(104);
+ });
+ });
+ });
+
+ describe('updateIncrementalJobLog', () => {
+ describe('without repeated section', () => {
+ it('concats and parses both arrays', () => {
+ const oldLog = logLinesParser(originalTrace);
+ const result = updateIncrementalJobLog(regularIncremental, oldLog);
+
+ expect(result).toEqual([
+ {
+ offset: 1,
+ content: [
+ {
+ text: 'Downloading',
+ },
+ ],
+ lineNumber: 0,
+ },
+ {
+ offset: 2,
+ content: [
+ {
+ text: 'log line',
+ },
+ ],
+ lineNumber: 1,
+ },
+ ]);
+ });
+ });
+
+ describe('with regular line repeated offset', () => {
+ it('updates the last line and formats with the incremental part', () => {
+ const oldLog = logLinesParser(originalTrace);
+ const result = updateIncrementalJobLog(regularIncrementalRepeated, oldLog);
+
+ expect(result).toEqual([
+ {
+ offset: 1,
+ content: [
+ {
+ text: 'log line',
+ },
+ ],
+ lineNumber: 0,
+ },
+ ]);
+ });
+ });
+
+ describe('with header line repeated', () => {
+ it('updates the header line and formats with the incremental part', () => {
+ const oldLog = logLinesParser(headerTrace);
+ const result = updateIncrementalJobLog(headerTraceIncremental, oldLog);
+
+ expect(result).toEqual([
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ offset: 1,
+ section_header: true,
+ content: [
+ {
+ text: 'updated log line',
+ },
+ ],
+ section: 'section',
+ lineNumber: 0,
+ },
+ lines: [],
+ },
+ ]);
+ });
+ });
+
+ describe('with collapsible line repeated', () => {
+ it('updates the collapsible line and formats with the incremental part', () => {
+ const oldLog = logLinesParser(collapsibleTrace);
+ const result = updateIncrementalJobLog(collapsibleTraceIncremental, oldLog);
+
+ expect(result).toEqual([
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ offset: 1,
+ section_header: true,
+ content: [
+ {
+ text: 'log line',
+ },
+ ],
+ section: 'section',
+ lineNumber: 0,
+ },
+ lines: [
+ {
+ offset: 2,
+ content: [
+ {
+ text: 'updated log line',
+ },
+ ],
+ section: 'section',
+ lineNumber: 1,
+ },
+ ],
+ },
+ ]);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/job_details/utils_spec.js b/spec/frontend/ci/job_details/utils_spec.js
new file mode 100644
index 00000000000..7b5a97f3939
--- /dev/null
+++ b/spec/frontend/ci/job_details/utils_spec.js
@@ -0,0 +1,265 @@
+import { compactJobLog, filterAnnotations } from '~/ci/job_details/utils';
+import { mockJobLog } from 'jest/ci/jobs_mock_data';
+
+describe('Job utils', () => {
+ describe('compactJobLog', () => {
+ it('compacts job log correctly', () => {
+ const expectedResults = [
+ {
+ content: [
+ {
+ text: 'Running with gitlab-runner 15.0.0 (febb2a09)',
+ },
+ ],
+ lineNumber: 0,
+ offset: 0,
+ },
+ {
+ content: [
+ {
+ text: ' on colima-docker EwM9WzgD',
+ },
+ ],
+ lineNumber: 1,
+ offset: 54,
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-cyan term-bold',
+ text: 'Resolving secrets',
+ },
+ ],
+ lineNumber: 2,
+ offset: 91,
+ section: 'resolve-secrets',
+ section_duration: '00:00',
+ section_header: true,
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-cyan term-bold',
+ text: 'Preparing the "docker" executor',
+ },
+ ],
+ lineNumber: 4,
+ offset: 218,
+ section: 'prepare-executor',
+ section_duration: '00:01',
+ section_header: true,
+ },
+ {
+ content: [
+ {
+ text: 'Using Docker executor with image ruby:2.7 ...',
+ },
+ ],
+ lineNumber: 5,
+ offset: 317,
+ section: 'prepare-executor',
+ },
+ {
+ content: [
+ {
+ text: 'Pulling docker image ruby:2.7 ...',
+ },
+ ],
+ lineNumber: 6,
+ offset: 372,
+ section: 'prepare-executor',
+ },
+ {
+ content: [
+ {
+ text:
+ 'Using docker image sha256:55106bf6ba7f452c38d01ea760affc6ceb67d4b60068ffadab98d1b7b007668c for ruby:2.7 with digest ruby@sha256:23d08a4bae1a12ee3fce017f83204fcf9a02243443e4a516e65e5ff73810a449 ...',
+ },
+ ],
+ lineNumber: 7,
+ offset: 415,
+ section: 'prepare-executor',
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-cyan term-bold',
+ text: 'Preparing environment',
+ },
+ ],
+ lineNumber: 9,
+ offset: 665,
+ section: 'prepare-script',
+ section_duration: '00:01',
+ section_header: true,
+ },
+ {
+ content: [
+ {
+ text: 'Running on runner-ewm9wzgd-project-20-concurrent-0 via 8ea689ec6969...',
+ },
+ ],
+ lineNumber: 10,
+ offset: 752,
+ section: 'prepare-script',
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-cyan term-bold',
+ text: 'Getting source from Git repository',
+ },
+ ],
+ lineNumber: 12,
+ offset: 865,
+ section: 'get-sources',
+ section_duration: '00:01',
+ section_header: true,
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-green term-bold',
+ text: 'Fetching changes with git depth set to 20...',
+ },
+ ],
+ lineNumber: 13,
+ offset: 962,
+ section: 'get-sources',
+ },
+ {
+ content: [
+ {
+ text: 'Reinitialized existing Git repository in /builds/root/ci-project/.git/',
+ },
+ ],
+ lineNumber: 14,
+ offset: 1019,
+ section: 'get-sources',
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-green term-bold',
+ text: 'Checking out e0f63d76 as main...',
+ },
+ ],
+ lineNumber: 15,
+ offset: 1090,
+ section: 'get-sources',
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-green term-bold',
+ text: 'Skipping Git submodules setup',
+ },
+ ],
+ lineNumber: 16,
+ offset: 1136,
+ section: 'get-sources',
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-cyan term-bold',
+ text: 'Executing "step_script" stage of the job script',
+ },
+ ],
+ lineNumber: 18,
+ offset: 1217,
+ section: 'step-script',
+ section_duration: '00:00',
+ section_header: true,
+ },
+ {
+ content: [
+ {
+ text:
+ 'Using docker image sha256:55106bf6ba7f452c38d01ea760affc6ceb67d4b60068ffadab98d1b7b007668c for ruby:2.7 with digest ruby@sha256:23d08a4bae1a12ee3fce017f83204fcf9a02243443e4a516e65e5ff73810a449 ...',
+ },
+ ],
+ lineNumber: 19,
+ offset: 1327,
+ section: 'step-script',
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-green term-bold',
+ text: '$ echo "82.71"',
+ },
+ ],
+ lineNumber: 20,
+ offset: 1533,
+ section: 'step-script',
+ },
+ {
+ content: [
+ {
+ text: '82.71',
+ },
+ ],
+ lineNumber: 21,
+ offset: 1560,
+ section: 'step-script',
+ },
+ {
+ content: [
+ {
+ style: 'term-fg-l-green term-bold',
+ text: 'Job succeeded',
+ },
+ ],
+ lineNumber: 23,
+ offset: 1605,
+ },
+ ];
+
+ expect(compactJobLog(mockJobLog)).toStrictEqual(expectedResults);
+ });
+ });
+
+ describe('filterAnnotations', () => {
+ it('filters annotations by type', () => {
+ const data = [
+ {
+ name: 'b',
+ data: [
+ {
+ dummy: {},
+ },
+ {
+ external_link: {
+ label: 'URL 2',
+ url: 'https://url2.example.com/',
+ },
+ },
+ ],
+ },
+ {
+ name: 'a',
+ data: [
+ {
+ external_link: {
+ label: 'URL 1',
+ url: 'https://url1.example.com/',
+ },
+ },
+ ],
+ },
+ ];
+
+ expect(filterAnnotations(data, 'external_link')).toEqual([
+ {
+ label: 'URL 1',
+ url: 'https://url1.example.com/',
+ },
+ {
+ label: 'URL 2',
+ url: 'https://url2.example.com/',
+ },
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/ci/jobs_mock_data.js b/spec/frontend/ci/jobs_mock_data.js
new file mode 100644
index 00000000000..c428de3b9d8
--- /dev/null
+++ b/spec/frontend/ci/jobs_mock_data.js
@@ -0,0 +1,1629 @@
+import mockJobsCount from 'test_fixtures/graphql/jobs/get_jobs_count.query.graphql.json';
+import mockAllJobsCount from 'test_fixtures/graphql/jobs/get_all_jobs_count.query.graphql.json';
+import mockJobsEmpty from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.empty.json';
+import mockAllJobsEmpty from 'test_fixtures/graphql/jobs/get_all_jobs.query.graphql.empty.json';
+import mockJobsPaginated from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.paginated.json';
+import mockAllJobsPaginated from 'test_fixtures/graphql/jobs/get_all_jobs.query.graphql.paginated.json';
+import mockJobs from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.json';
+import mockAllJobs from 'test_fixtures/graphql/jobs/get_all_jobs.query.graphql.json';
+import mockJobsAsGuest from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.as_guest.json';
+import mockCancelableJobsCount from 'test_fixtures/graphql/jobs/get_cancelable_jobs_count.query.graphql.json';
+import { TEST_HOST } from 'spec/test_constants';
+import { TOKEN_TYPE_STATUS } from '~/vue_shared/components/filtered_search_bar/constants';
+
+const threeWeeksAgo = new Date();
+threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
+
+// Fixtures generated at spec/frontend/fixtures/jobs.rb
+export const mockJobsResponsePaginated = mockJobsPaginated;
+export const mockAllJobsResponsePaginated = mockAllJobsPaginated;
+export const mockJobsResponseEmpty = mockJobsEmpty;
+export const mockAllJobsResponseEmpty = mockAllJobsEmpty;
+export const mockJobsNodes = mockJobs.data.project.jobs.nodes;
+export const mockAllJobsNodes = mockAllJobs.data.jobs.nodes;
+export const mockJobsNodesAsGuest = mockJobsAsGuest.data.project.jobs.nodes;
+export const mockJobsCountResponse = mockJobsCount;
+export const mockAllJobsCountResponse = mockAllJobsCount;
+export const mockCancelableJobsCountResponse = mockCancelableJobsCount;
+
+export const stages = [
+ {
+ name: 'build',
+ title: 'build: running',
+ groups: [
+ {
+ name: 'build:linux',
+ size: 1,
+ status: {
+ icon: 'status_pending',
+ text: 'pending',
+ label: 'pending',
+ group: 'pending',
+ tooltip: 'pending',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
+ illustration: {
+ image: 'illustrations/pending_job_empty.svg',
+ size: 'svg-430',
+ title: 'This job has not started yet',
+ content: 'This job is in pending state and is waiting to be picked by a runner',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 1180,
+ name: 'build:linux',
+ started: false,
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
+ cancel_path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
+ playable: false,
+ created_at: '2018-09-28T11:09:57.229Z',
+ updated_at: '2018-09-28T11:09:57.503Z',
+ status: {
+ icon: 'status_pending',
+ text: 'pending',
+ label: 'pending',
+ group: 'pending',
+ tooltip: 'pending',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
+ illustration: {
+ image: 'illustrations/pending_job_empty.svg',
+ size: 'svg-430',
+ title: 'This job has not started yet',
+ content: 'This job is in pending state and is waiting to be picked by a runner',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ {
+ name: 'build:osx',
+ size: 1,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/444',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 444,
+ name: 'build:osx',
+ started: '2018-05-18T05:32:20.655Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/444',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.364Z',
+ updated_at: '2018-05-18T15:32:54.364Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/444',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ ],
+ status: {
+ icon: 'status_running',
+ text: 'running',
+ label: 'running',
+ group: 'running',
+ tooltip: 'running',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/pipelines/27#build',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_running-9c635b2419a8e1ec991c993061b89cc5aefc0743bb238ecd0c381e7741a70e8c.png',
+ },
+ path: '/gitlab-org/gitlab-shell/pipelines/27#build',
+ dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=build',
+ },
+ {
+ name: 'test',
+ title: 'test: passed with warnings',
+ groups: [
+ {
+ name: 'jenkins',
+ size: 1,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: null,
+ group: 'success',
+ tooltip: null,
+ has_details: false,
+ details_path: null,
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ jobs: [
+ {
+ id: 459,
+ name: 'jenkins',
+ started: '2018-05-18T09:32:20.658Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/459',
+ playable: false,
+ created_at: '2018-05-18T15:32:55.330Z',
+ updated_at: '2018-05-18T15:32:55.330Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: null,
+ group: 'success',
+ tooltip: null,
+ has_details: false,
+ details_path: null,
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ },
+ ],
+ },
+ {
+ name: 'rspec:linux',
+ size: 3,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: false,
+ details_path: null,
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ jobs: [
+ {
+ id: 445,
+ name: 'rspec:linux 0 3',
+ started: '2018-05-18T07:32:20.655Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/445',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/445/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.425Z',
+ updated_at: '2018-05-18T15:32:54.425Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/445',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/445/retry',
+ method: 'post',
+ },
+ },
+ },
+ {
+ id: 446,
+ name: 'rspec:linux 1 3',
+ started: '2018-05-18T07:32:20.655Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/446',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/446/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.506Z',
+ updated_at: '2018-05-18T15:32:54.506Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/446',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/446/retry',
+ method: 'post',
+ },
+ },
+ },
+ {
+ id: 447,
+ name: 'rspec:linux 2 3',
+ started: '2018-05-18T07:32:20.656Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/447',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/447/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.572Z',
+ updated_at: '2018-05-18T15:32:54.572Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/447',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/447/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ {
+ name: 'rspec:osx',
+ size: 1,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/452',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/452/retry',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 452,
+ name: 'rspec:osx',
+ started: '2018-05-18T07:32:20.657Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/452',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/452/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.920Z',
+ updated_at: '2018-05-18T15:32:54.920Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/452',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/452/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ {
+ name: 'rspec:windows',
+ size: 3,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: false,
+ details_path: null,
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ jobs: [
+ {
+ id: 448,
+ name: 'rspec:windows 0 3',
+ started: '2018-05-18T07:32:20.656Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/448',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/448/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.639Z',
+ updated_at: '2018-05-18T15:32:54.639Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/448',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/448/retry',
+ method: 'post',
+ },
+ },
+ },
+ {
+ id: 449,
+ name: 'rspec:windows 1 3',
+ started: '2018-05-18T07:32:20.656Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/449',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/449/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.703Z',
+ updated_at: '2018-05-18T15:32:54.703Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/449',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/449/retry',
+ method: 'post',
+ },
+ },
+ },
+ {
+ id: 451,
+ name: 'rspec:windows 2 3',
+ started: '2018-05-18T07:32:20.657Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/451',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/451/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.853Z',
+ updated_at: '2018-05-18T15:32:54.853Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/451',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/451/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ {
+ name: 'spinach:linux',
+ size: 1,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/453',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/453/retry',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 453,
+ name: 'spinach:linux',
+ started: '2018-05-18T07:32:20.657Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/453',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/453/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.993Z',
+ updated_at: '2018-05-18T15:32:54.993Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/453',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/453/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ {
+ name: 'spinach:osx',
+ size: 1,
+ status: {
+ icon: 'status_warning',
+ text: 'failed',
+ label: 'failed (allowed to fail)',
+ group: 'failed-with-warnings',
+ tooltip: 'failed - (unknown failure) (allowed to fail)',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/454',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 454,
+ name: 'spinach:osx',
+ started: '2018-05-18T07:32:20.657Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/454',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:55.053Z',
+ updated_at: '2018-05-18T15:32:55.053Z',
+ status: {
+ icon: 'status_warning',
+ text: 'failed',
+ label: 'failed (allowed to fail)',
+ group: 'failed-with-warnings',
+ tooltip: 'failed - (unknown failure) (allowed to fail)',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/454',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
+ method: 'post',
+ },
+ },
+ callout_message: 'There is an unknown failure, please try again',
+ recoverable: true,
+ },
+ ],
+ },
+ ],
+ status: {
+ icon: 'status_warning',
+ text: 'passed',
+ label: 'passed with warnings',
+ group: 'success-with-warnings',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/pipelines/27#test',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ path: '/gitlab-org/gitlab-shell/pipelines/27#test',
+ dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=test',
+ },
+ {
+ name: 'deploy',
+ title: 'deploy: running',
+ groups: [
+ {
+ name: 'production',
+ size: 1,
+ status: {
+ icon: 'status_created',
+ text: 'created',
+ label: 'created',
+ group: 'created',
+ tooltip: 'created',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/457',
+ illustration: {
+ image: 'illustrations/job_not_triggered.svg',
+ size: 'svg-306',
+ title: 'This job has not been triggered yet',
+ content:
+ 'This job depends on upstream jobs that need to succeed in order for this job to be triggered',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/gitlab-org/gitlab-shell/-/jobs/457/cancel',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 457,
+ name: 'production',
+ started: false,
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/457',
+ cancel_path: '/gitlab-org/gitlab-shell/-/jobs/457/cancel',
+ playable: false,
+ created_at: '2018-05-18T15:32:55.259Z',
+ updated_at: '2018-09-28T11:09:57.454Z',
+ status: {
+ icon: 'status_created',
+ text: 'created',
+ label: 'created',
+ group: 'created',
+ tooltip: 'created',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/457',
+ illustration: {
+ image: 'illustrations/job_not_triggered.svg',
+ size: 'svg-306',
+ title: 'This job has not been triggered yet',
+ content:
+ 'This job depends on upstream jobs that need to succeed in order for this job to be triggered',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/gitlab-org/gitlab-shell/-/jobs/457/cancel',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ {
+ name: 'staging',
+ size: 1,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/455',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/455/retry',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 455,
+ name: 'staging',
+ started: '2018-05-18T09:32:20.658Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/455',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/455/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:55.119Z',
+ updated_at: '2018-05-18T15:32:55.119Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/455',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/455/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ {
+ name: 'stop staging',
+ size: 1,
+ status: {
+ icon: 'status_created',
+ text: 'created',
+ label: 'created',
+ group: 'created',
+ tooltip: 'created',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/456',
+ illustration: {
+ image: 'illustrations/job_not_triggered.svg',
+ size: 'svg-306',
+ title: 'This job has not been triggered yet',
+ content:
+ 'This job depends on upstream jobs that need to succeed in order for this job to be triggered',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/gitlab-org/gitlab-shell/-/jobs/456/cancel',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 456,
+ name: 'stop staging',
+ started: false,
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/456',
+ cancel_path: '/gitlab-org/gitlab-shell/-/jobs/456/cancel',
+ playable: false,
+ created_at: '2018-05-18T15:32:55.205Z',
+ updated_at: '2018-09-28T11:09:57.396Z',
+ status: {
+ icon: 'status_created',
+ text: 'created',
+ label: 'created',
+ group: 'created',
+ tooltip: 'created',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/456',
+ illustration: {
+ image: 'illustrations/job_not_triggered.svg',
+ size: 'svg-306',
+ title: 'This job has not been triggered yet',
+ content:
+ 'This job depends on upstream jobs that need to succeed in order for this job to be triggered',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/gitlab-org/gitlab-shell/-/jobs/456/cancel',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ ],
+ status: {
+ icon: 'status_running',
+ text: 'running',
+ label: 'running',
+ group: 'running',
+ tooltip: 'running',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/pipelines/27#deploy',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_running-9c635b2419a8e1ec991c993061b89cc5aefc0743bb238ecd0c381e7741a70e8c.png',
+ },
+ path: '/gitlab-org/gitlab-shell/pipelines/27#deploy',
+ dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=deploy',
+ },
+ {
+ name: 'notify',
+ title: 'notify: manual action',
+ groups: [
+ {
+ name: 'slack',
+ size: 1,
+ status: {
+ icon: 'status_manual',
+ text: 'manual',
+ label: 'manual play action',
+ group: 'manual',
+ tooltip: 'manual action',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/458',
+ illustration: {
+ image: 'illustrations/manual_action.svg',
+ size: 'svg-394',
+ title: 'This job requires a manual action',
+ content:
+ 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
+ action: {
+ icon: 'play',
+ title: 'Play',
+ path: '/gitlab-org/gitlab-shell/-/jobs/458/play',
+ method: 'post',
+ },
+ },
+ jobs: [
+ {
+ id: 458,
+ name: 'slack',
+ started: null,
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/458',
+ play_path: '/gitlab-org/gitlab-shell/-/jobs/458/play',
+ playable: true,
+ created_at: '2018-05-18T15:32:55.303Z',
+ updated_at: '2018-05-18T15:34:08.535Z',
+ status: {
+ icon: 'status_manual',
+ text: 'manual',
+ label: 'manual play action',
+ group: 'manual',
+ tooltip: 'manual action',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/458',
+ illustration: {
+ image: 'illustrations/manual_action.svg',
+ size: 'svg-394',
+ title: 'This job requires a manual action',
+ content:
+ 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
+ action: {
+ icon: 'play',
+ title: 'Play',
+ path: '/gitlab-org/gitlab-shell/-/jobs/458/play',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ },
+ ],
+ status: {
+ icon: 'status_manual',
+ text: 'manual',
+ label: 'manual action',
+ group: 'manual',
+ tooltip: 'manual action',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/pipelines/27#notify',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
+ },
+ path: '/gitlab-org/gitlab-shell/pipelines/27#notify',
+ dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=notify',
+ },
+];
+
+export const statuses = {
+ success: 'SUCCESS',
+ failed: 'FAILED',
+ canceled: 'CANCELED',
+ pending: 'PENDING',
+ running: 'RUNNING',
+};
+
+export default {
+ id: 4757,
+ artifact: {
+ locked: false,
+ },
+ name: 'test',
+ stage: 'build',
+ build_path: '/root/ci-mock/-/jobs/4757',
+ retry_path: '/root/ci-mock/-/jobs/4757/retry',
+ cancel_path: '/root/ci-mock/-/jobs/4757/cancel',
+ new_issue_path: '/root/ci-mock/issues/new',
+ playable: false,
+ complete: true,
+ created_at: threeWeeksAgo.toISOString(),
+ updated_at: threeWeeksAgo.toISOString(),
+ finished_at: threeWeeksAgo.toISOString(),
+ queued_duration: 9.54,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ has_details: true,
+ details_path: `${TEST_HOST}/root/ci-mock/-/jobs/4757`,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/root/ci-mock/-/jobs/4757/retry',
+ method: 'post',
+ },
+ },
+ coverage: 20,
+ erased_at: threeWeeksAgo.toISOString(),
+ erased: false,
+ duration: 6.785563,
+ tags: ['tag'],
+ user: {
+ name: 'Root',
+ username: 'root',
+ id: 1,
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3000/root',
+ },
+ erase_path: '/root/ci-mock/-/jobs/4757/erase',
+ artifacts: [null],
+ annotations: [],
+ runner: {
+ id: 1,
+ short_sha: 'ABCDEFGH',
+ description: 'local ci runner',
+ edit_path: '/root/ci-mock/runners/1/edit',
+ },
+ pipeline: {
+ id: 140,
+ user: {
+ name: 'Root',
+ username: 'root',
+ id: 1,
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3000/root',
+ },
+ active: false,
+ coverage: null,
+ source: 'unknown',
+ created_at: '2017-05-24T09:59:58.634Z',
+ updated_at: '2017-06-01T17:32:00.062Z',
+ path: '/root/ci-mock/pipelines/140',
+ flags: {
+ latest: true,
+ stuck: false,
+ yaml_errors: false,
+ retryable: false,
+ cancelable: false,
+ },
+ details: {
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ has_details: true,
+ details_path: '/root/ci-mock/pipelines/140',
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png',
+ },
+ duration: 6,
+ finished_at: '2017-06-01T17:32:00.042Z',
+ stages: [
+ {
+ dropdown_path: '/jashkenas/underscore/pipelines/16/stage.json?stage=build',
+ name: 'build',
+ path: '/jashkenas/underscore/pipelines/16#build',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ },
+ title: 'build: passed',
+ },
+ {
+ dropdown_path: '/jashkenas/underscore/pipelines/16/stage.json?stage=test',
+ name: 'test',
+ path: '/jashkenas/underscore/pipelines/16#test',
+ status: {
+ icon: 'status_warning',
+ text: 'passed',
+ label: 'passed with warnings',
+ group: 'success-with-warnings',
+ },
+ title: 'test: passed with warnings',
+ },
+ ],
+ },
+ ref: {
+ name: 'abc',
+ path: '/root/ci-mock/commits/abc',
+ tag: false,
+ branch: true,
+ },
+ commit: {
+ id: 'c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
+ short_id: 'c5864777',
+ title: 'Add new file',
+ created_at: '2017-05-24T10:59:52.000+01:00',
+ parent_ids: ['798e5f902592192afaba73f4668ae30e56eae492'],
+ message: 'Add new file',
+ author_name: 'Root',
+ author_email: 'admin@example.com',
+ authored_date: '2017-05-24T10:59:52.000+01:00',
+ committer_name: 'Root',
+ committer_email: 'admin@example.com',
+ committed_date: '2017-05-24T10:59:52.000+01:00',
+ author: {
+ name: 'Root',
+ username: 'root',
+ id: 1,
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3000/root',
+ },
+ author_gravatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ commit_url:
+ 'http://localhost:3000/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
+ commit_path: '/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
+ },
+ },
+ metadata: {
+ timeout_human_readable: '1m 40s',
+ timeout_source: 'runner',
+ },
+ merge_request: {
+ iid: 2,
+ path: '/root/ci-mock/merge_requests/2',
+ },
+ raw_path: '/root/ci-mock/builds/4757/raw',
+ has_trace: true,
+};
+
+export const failedJobStatus = {
+ icon: 'status_warning',
+ text: 'failed',
+ label: 'failed (allowed to fail)',
+ group: 'failed-with-warnings',
+ tooltip: 'failed - (unknown failure) (allowed to fail)',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/454',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
+ method: 'post',
+ },
+};
+
+export const jobsInStage = {
+ name: 'build',
+ title: 'build: running',
+ latest_statuses: [
+ {
+ id: 1180,
+ name: 'build:linux',
+ started: false,
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
+ cancel_path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
+ playable: false,
+ created_at: '2018-09-28T11:09:57.229Z',
+ updated_at: '2018-09-28T11:09:57.503Z',
+ status: {
+ icon: 'status_pending',
+ text: 'pending',
+ label: 'pending',
+ group: 'pending',
+ tooltip: 'pending',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
+ illustration: {
+ image: 'illustrations/pending_job_empty.svg',
+ size: 'svg-430',
+ title: 'This job has not started yet',
+ content: 'This job is in pending state and is waiting to be picked by a runner',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
+ method: 'post',
+ },
+ },
+ },
+ {
+ id: 444,
+ name: 'build:osx',
+ started: '2018-05-18T05:32:20.655Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/444',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.364Z',
+ updated_at: '2018-05-18T15:32:54.364Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/444',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ retried: [
+ {
+ id: 443,
+ name: 'build:linux',
+ started: '2018-05-18T06:32:20.655Z',
+ build_path: '/gitlab-org/gitlab-shell/-/jobs/443',
+ retry_path: '/gitlab-org/gitlab-shell/-/jobs/443/retry',
+ playable: false,
+ created_at: '2018-05-18T15:32:54.296Z',
+ updated_at: '2018-05-18T15:32:54.296Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed (retried)',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/443',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/443/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ status: {
+ icon: 'status_running',
+ text: 'running',
+ label: 'running',
+ group: 'running',
+ tooltip: 'running',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/pipelines/27#build',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_running-9c635b2419a8e1ec991c993061b89cc5aefc0743bb238ecd0c381e7741a70e8c.png',
+ },
+ path: '/gitlab-org/gitlab-shell/pipelines/27#build',
+ dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=build',
+};
+
+export const mockPipelineWithoutMR = {
+ id: 28029444,
+ details: {
+ status: {
+ details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
+ group: 'success',
+ has_details: true,
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed',
+ },
+ },
+ path: 'pipeline/28029444',
+ ref: {
+ name: 'test-branch',
+ },
+};
+
+export const mockPipelineWithoutRef = {
+ ...mockPipelineWithoutMR,
+ ref: null,
+};
+
+export const mockPipelineWithAttachedMR = {
+ id: 28029444,
+ details: {
+ status: {
+ details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
+ group: 'success',
+ has_details: true,
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed',
+ },
+ },
+ path: 'pipeline/28029444',
+ flags: {
+ merge_request_pipeline: true,
+ detached_merge_request_pipeline: false,
+ },
+ merge_request: {
+ iid: 1234,
+ path: '/root/detached-merge-request-pipelines/-/merge_requests/1',
+ title: 'Update README.md',
+ source_branch: 'feature-1234',
+ source_branch_path: '/root/detached-merge-request-pipelines/branches/feature-1234',
+ target_branch: 'main',
+ target_branch_path: '/root/detached-merge-request-pipelines/branches/main',
+ },
+ ref: {
+ name: 'test-branch',
+ },
+};
+
+export const mockPipelineDetached = {
+ id: 28029444,
+ details: {
+ status: {
+ details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
+ group: 'success',
+ has_details: true,
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed',
+ },
+ },
+ path: 'pipeline/28029444',
+ flags: {
+ merge_request_pipeline: false,
+ detached_merge_request_pipeline: true,
+ },
+ merge_request: {
+ iid: 1234,
+ path: '/root/detached-merge-request-pipelines/-/merge_requests/1',
+ title: 'Update README.md',
+ source_branch: 'feature-1234',
+ source_branch_path: '/root/detached-merge-request-pipelines/branches/feature-1234',
+ target_branch: 'main',
+ target_branch_path: '/root/detached-merge-request-pipelines/branches/main',
+ },
+ ref: {
+ name: 'test-branch',
+ },
+};
+
+export const CIJobConnectionIncomingCache = {
+ __typename: 'CiJobConnection',
+ pageInfo: {
+ __typename: 'PageInfo',
+ endCursor: 'eyJpZCI6IjIwNTEifQ',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'eyJpZCI6IjIxNzMifQ',
+ },
+ nodes: [
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2057' },
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2056' },
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2051' },
+ ],
+};
+
+export const CIJobConnectionIncomingCacheRunningStatus = {
+ __typename: 'CiJobConnection',
+ pageInfo: {
+ __typename: 'PageInfo',
+ endCursor: 'eyJpZCI6IjIwNTEifQ',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'eyJpZCI6IjIxNzMifQ',
+ },
+ nodes: [
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2000' },
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2001' },
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2002' },
+ ],
+};
+
+export const CIJobConnectionExistingCache = {
+ pageInfo: {
+ __typename: 'PageInfo',
+ endCursor: 'eyJpZCI6IjIwNTEifQ',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'eyJpZCI6IjIxNzMifQ',
+ },
+ nodes: [
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2100' },
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2101' },
+ { __ref: 'CiJob:gid://gitlab/Ci::Build/2102' },
+ ],
+ statuses: 'PENDING',
+};
+
+export const mockFailedSearchToken = {
+ type: TOKEN_TYPE_STATUS,
+ value: { data: 'FAILED', operator: '=' },
+};
+
+export const retryMutationResponse = {
+ data: {
+ jobRetry: {
+ job: {
+ __typename: 'CiJob',
+ id: '"gid://gitlab/Ci::Build/1985"',
+ detailedStatus: {
+ detailsPath: '/root/project/-/jobs/1985',
+ id: 'pending-1985-1985',
+ __typename: 'DetailedStatus',
+ },
+ },
+ errors: [],
+ __typename: 'JobRetryPayload',
+ },
+ },
+};
+
+export const playMutationResponse = {
+ data: {
+ jobPlay: {
+ job: {
+ __typename: 'CiJob',
+ id: '"gid://gitlab/Ci::Build/1986"',
+ detailedStatus: {
+ detailsPath: '/root/project/-/jobs/1986',
+ id: 'pending-1986-1986',
+ __typename: 'DetailedStatus',
+ },
+ },
+ errors: [],
+ __typename: 'JobRetryPayload',
+ },
+ },
+};
+
+export const cancelMutationResponse = {
+ data: {
+ jobCancel: {
+ job: {
+ __typename: 'CiJob',
+ id: '"gid://gitlab/Ci::Build/1987"',
+ detailedStatus: {
+ detailsPath: '/root/project/-/jobs/1987',
+ id: 'pending-1987-1987',
+ __typename: 'DetailedStatus',
+ },
+ },
+ errors: [],
+ __typename: 'JobRetryPayload',
+ },
+ },
+};
+
+export const unscheduleMutationResponse = {
+ data: {
+ jobUnschedule: {
+ job: {
+ __typename: 'CiJob',
+ id: '"gid://gitlab/Ci::Build/1988"',
+ detailedStatus: {
+ detailsPath: '/root/project/-/jobs/1988',
+ id: 'pending-1988-1988',
+ __typename: 'DetailedStatus',
+ },
+ },
+ errors: [],
+ __typename: 'JobRetryPayload',
+ },
+ },
+};
+
+export const mockJobLog = [
+ { offset: 0, content: [{ text: 'Running with gitlab-runner 15.0.0 (febb2a09)' }], lineNumber: 0 },
+ { offset: 54, content: [{ text: ' on colima-docker EwM9WzgD' }], lineNumber: 1 },
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ offset: 91,
+ content: [{ text: 'Resolving secrets', style: 'term-fg-l-cyan term-bold' }],
+ section: 'resolve-secrets',
+ section_header: true,
+ lineNumber: 2,
+ section_duration: '00:00',
+ },
+ lines: [],
+ },
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ offset: 218,
+ content: [{ text: 'Preparing the "docker" executor', style: 'term-fg-l-cyan term-bold' }],
+ section: 'prepare-executor',
+ section_header: true,
+ lineNumber: 4,
+ section_duration: '00:01',
+ },
+ lines: [
+ {
+ offset: 317,
+ content: [{ text: 'Using Docker executor with image ruby:2.7 ...' }],
+ section: 'prepare-executor',
+ lineNumber: 5,
+ },
+ {
+ offset: 372,
+ content: [{ text: 'Pulling docker image ruby:2.7 ...' }],
+ section: 'prepare-executor',
+ lineNumber: 6,
+ },
+ {
+ offset: 415,
+ content: [
+ {
+ text:
+ 'Using docker image sha256:55106bf6ba7f452c38d01ea760affc6ceb67d4b60068ffadab98d1b7b007668c for ruby:2.7 with digest ruby@sha256:23d08a4bae1a12ee3fce017f83204fcf9a02243443e4a516e65e5ff73810a449 ...',
+ },
+ ],
+ section: 'prepare-executor',
+ lineNumber: 7,
+ },
+ ],
+ },
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ offset: 665,
+ content: [{ text: 'Preparing environment', style: 'term-fg-l-cyan term-bold' }],
+ section: 'prepare-script',
+ section_header: true,
+ lineNumber: 9,
+ section_duration: '00:01',
+ },
+ lines: [
+ {
+ offset: 752,
+ content: [
+ { text: 'Running on runner-ewm9wzgd-project-20-concurrent-0 via 8ea689ec6969...' },
+ ],
+ section: 'prepare-script',
+ lineNumber: 10,
+ },
+ ],
+ },
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ offset: 865,
+ content: [{ text: 'Getting source from Git repository', style: 'term-fg-l-cyan term-bold' }],
+ section: 'get-sources',
+ section_header: true,
+ lineNumber: 12,
+ section_duration: '00:01',
+ },
+ lines: [
+ {
+ offset: 962,
+ content: [
+ {
+ text: 'Fetching changes with git depth set to 20...',
+ style: 'term-fg-l-green term-bold',
+ },
+ ],
+ section: 'get-sources',
+ lineNumber: 13,
+ },
+ {
+ offset: 1019,
+ content: [
+ { text: 'Reinitialized existing Git repository in /builds/root/ci-project/.git/' },
+ ],
+ section: 'get-sources',
+ lineNumber: 14,
+ },
+ {
+ offset: 1090,
+ content: [{ text: 'Checking out e0f63d76 as main...', style: 'term-fg-l-green term-bold' }],
+ section: 'get-sources',
+ lineNumber: 15,
+ },
+ {
+ offset: 1136,
+ content: [{ text: 'Skipping Git submodules setup', style: 'term-fg-l-green term-bold' }],
+ section: 'get-sources',
+ lineNumber: 16,
+ },
+ ],
+ },
+ {
+ isClosed: false,
+ isHeader: true,
+ line: {
+ offset: 1217,
+ content: [
+ {
+ text: 'Executing "step_script" stage of the job script',
+ style: 'term-fg-l-cyan term-bold',
+ },
+ ],
+ section: 'step-script',
+ section_header: true,
+ lineNumber: 18,
+ section_duration: '00:00',
+ },
+ lines: [
+ {
+ offset: 1327,
+ content: [
+ {
+ text:
+ 'Using docker image sha256:55106bf6ba7f452c38d01ea760affc6ceb67d4b60068ffadab98d1b7b007668c for ruby:2.7 with digest ruby@sha256:23d08a4bae1a12ee3fce017f83204fcf9a02243443e4a516e65e5ff73810a449 ...',
+ },
+ ],
+ section: 'step-script',
+ lineNumber: 19,
+ },
+ {
+ offset: 1533,
+ content: [{ text: '$ echo "82.71"', style: 'term-fg-l-green term-bold' }],
+ section: 'step-script',
+ lineNumber: 20,
+ },
+ { offset: 1560, content: [{ text: '82.71' }], section: 'step-script', lineNumber: 21 },
+ ],
+ },
+ {
+ offset: 1605,
+ content: [{ text: 'Job succeeded', style: 'term-fg-l-green term-bold' }],
+ lineNumber: 23,
+ },
+];
diff --git a/spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js b/spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js
new file mode 100644
index 00000000000..1ffd680118e
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/components/job_cells/actions_cell_spec.js
@@ -0,0 +1,240 @@
+import { GlModal } from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import ActionsCell from '~/ci/jobs_page/components/job_cells/actions_cell.vue';
+import eventHub from '~/ci/jobs_page/event_hub';
+import JobPlayMutation from '~/ci/jobs_page/graphql/mutations/job_play.mutation.graphql';
+import JobRetryMutation from '~/ci/jobs_page/graphql/mutations/job_retry.mutation.graphql';
+import JobUnscheduleMutation from '~/ci/jobs_page/graphql/mutations/job_unschedule.mutation.graphql';
+import JobCancelMutation from '~/ci/jobs_page/graphql/mutations/job_cancel.mutation.graphql';
+import {
+ mockJobsNodes,
+ mockJobsNodesAsGuest,
+ playMutationResponse,
+ retryMutationResponse,
+ unscheduleMutationResponse,
+ cancelMutationResponse,
+} from 'jest/ci/jobs_mock_data';
+
+jest.mock('~/lib/utils/url_utility');
+
+Vue.use(VueApollo);
+
+describe('Job actions cell', () => {
+ let wrapper;
+
+ const findMockJob = (jobName, nodes = mockJobsNodes) => {
+ const job = nodes.find(({ name }) => name === jobName);
+ expect(job).toBeDefined(); // ensure job is present
+ return job;
+ };
+
+ const mockJob = findMockJob('build');
+ const cancelableJob = findMockJob('cancelable');
+ const playableJob = findMockJob('playable');
+ const retryableJob = findMockJob('retryable');
+ const failedJob = findMockJob('failed');
+ const scheduledJob = findMockJob('scheduled');
+ const jobWithArtifact = findMockJob('with_artifact');
+ const cannotPlayJob = findMockJob('playable', mockJobsNodesAsGuest);
+ const cannotRetryJob = findMockJob('retryable', mockJobsNodesAsGuest);
+ const cannotPlayScheduledJob = findMockJob('scheduled', mockJobsNodesAsGuest);
+
+ const findRetryButton = () => wrapper.findByTestId('retry');
+ const findPlayButton = () => wrapper.findByTestId('play');
+ const findCancelButton = () => wrapper.findByTestId('cancel-button');
+ const findDownloadArtifactsButton = () => wrapper.findByTestId('download-artifacts');
+ const findCountdownButton = () => wrapper.findByTestId('countdown');
+ const findPlayScheduledJobButton = () => wrapper.findByTestId('play-scheduled');
+ const findUnscheduleButton = () => wrapper.findByTestId('unschedule');
+
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const playMutationHandler = jest.fn().mockResolvedValue(playMutationResponse);
+ const retryMutationHandler = jest.fn().mockResolvedValue(retryMutationResponse);
+ const unscheduleMutationHandler = jest.fn().mockResolvedValue(unscheduleMutationResponse);
+ const cancelMutationHandler = jest.fn().mockResolvedValue(cancelMutationResponse);
+
+ const $toast = {
+ show: jest.fn(),
+ };
+
+ const createMockApolloProvider = (requestHandlers) => {
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = (job, requestHandlers, props = {}) => {
+ wrapper = shallowMountExtended(ActionsCell, {
+ propsData: {
+ job,
+ ...props,
+ },
+ apolloProvider: createMockApolloProvider(requestHandlers),
+ mocks: {
+ $toast,
+ },
+ });
+ };
+
+ it('displays the artifacts download button with correct link', () => {
+ createComponent(jobWithArtifact);
+
+ expect(findDownloadArtifactsButton().attributes('href')).toBe(
+ jobWithArtifact.artifacts.nodes[0].downloadPath,
+ );
+ });
+
+ it('does not display an artifacts download button', () => {
+ createComponent(mockJob);
+
+ expect(findDownloadArtifactsButton().exists()).toBe(false);
+ });
+
+ it.each`
+ button | action | jobType
+ ${findPlayButton} | ${'play'} | ${cannotPlayJob}
+ ${findRetryButton} | ${'retry'} | ${cannotRetryJob}
+ ${findPlayScheduledJobButton} | ${'play scheduled'} | ${cannotPlayScheduledJob}
+ `('does not display the $action button if user cannot update build', ({ button, jobType }) => {
+ createComponent(jobType);
+
+ expect(button().exists()).toBe(false);
+ });
+
+ it.each`
+ button | action | jobType
+ ${findPlayButton} | ${'play'} | ${playableJob}
+ ${findRetryButton} | ${'retry'} | ${retryableJob}
+ ${findDownloadArtifactsButton} | ${'download artifacts'} | ${jobWithArtifact}
+ ${findCancelButton} | ${'cancel'} | ${cancelableJob}
+ `('displays the $action button', ({ button, jobType }) => {
+ createComponent(jobType);
+
+ expect(button().exists()).toBe(true);
+ });
+
+ it.each`
+ button | action | jobType | mutationFile | handler | jobId
+ ${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${playableJob.id}
+ ${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${retryableJob.id}
+ ${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler} | ${cancelableJob.id}
+ `('performs the $action mutation', ({ button, jobType, mutationFile, handler, jobId }) => {
+ createComponent(jobType, [[mutationFile, handler]]);
+
+ button().vm.$emit('click');
+
+ expect(handler).toHaveBeenCalledWith({ id: jobId });
+ });
+
+ it.each`
+ button | action | jobType | mutationFile | handler
+ ${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob} | ${JobUnscheduleMutation} | ${unscheduleMutationHandler}
+ ${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler}
+ `(
+ 'the mutation action $action emits the jobActionPerformed event',
+ async ({ button, jobType, mutationFile, handler }) => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+
+ createComponent(jobType, [[mutationFile, handler]]);
+
+ button().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('jobActionPerformed');
+ expect(redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
+ },
+ );
+
+ it.each`
+ button | action | jobType | mutationFile | handler | redirectLink
+ ${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${'/root/project/-/jobs/1986'}
+ ${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${'/root/project/-/jobs/1985'}
+ `(
+ 'the mutation action $action redirects to the job',
+ async ({ button, jobType, mutationFile, handler, redirectLink }) => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+
+ createComponent(jobType, [[mutationFile, handler]]);
+
+ button().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(redirectTo).toHaveBeenCalledWith(redirectLink); // eslint-disable-line import/no-deprecated
+ expect(eventHub.$emit).not.toHaveBeenCalled();
+ },
+ );
+
+ it.each`
+ button | action | jobType
+ ${findPlayButton} | ${'play'} | ${playableJob}
+ ${findRetryButton} | ${'retry'} | ${retryableJob}
+ ${findCancelButton} | ${'cancel'} | ${cancelableJob}
+ ${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob}
+ `('disables the $action button after first request', async ({ button, jobType }) => {
+ createComponent(jobType);
+
+ expect(button().props('disabled')).toBe(false);
+
+ button().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(button().props('disabled')).toBe(true);
+ });
+
+ describe('Retry button title', () => {
+ it('displays retry title when job has failed and is retryable', () => {
+ createComponent(failedJob);
+
+ expect(findRetryButton().attributes('title')).toBe('Retry');
+ });
+
+ it('displays run again title when job has passed and is retryable', () => {
+ createComponent(retryableJob);
+
+ expect(findRetryButton().attributes('title')).toBe('Run again');
+ });
+ });
+
+ describe('Scheduled Jobs', () => {
+ const today = () => new Date('2021-08-31');
+
+ beforeEach(() => {
+ jest.spyOn(Date, 'now').mockImplementation(today);
+ });
+
+ it('displays the countdown, play and unschedule buttons', () => {
+ createComponent(scheduledJob);
+
+ expect(findCountdownButton().exists()).toBe(true);
+ expect(findPlayScheduledJobButton().exists()).toBe(true);
+ expect(findUnscheduleButton().exists()).toBe(true);
+ });
+
+ it('unschedules a job', () => {
+ createComponent(scheduledJob, [[JobUnscheduleMutation, unscheduleMutationHandler]]);
+
+ findUnscheduleButton().vm.$emit('click');
+
+ expect(unscheduleMutationHandler).toHaveBeenCalledWith({
+ id: scheduledJob.id,
+ });
+ });
+
+ it('shows the play job confirmation modal', async () => {
+ createComponent(scheduledJob);
+
+ findPlayScheduledJobButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(findModal().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/jobs_page/components/job_cells/duration_cell_spec.js b/spec/frontend/ci/jobs_page/components/job_cells/duration_cell_spec.js
new file mode 100644
index 00000000000..21f14ba0c98
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/components/job_cells/duration_cell_spec.js
@@ -0,0 +1,77 @@
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import DurationCell from '~/ci/jobs_page/components/job_cells/duration_cell.vue';
+
+describe('Duration Cell', () => {
+ let wrapper;
+
+ const findJobDuration = () => wrapper.findByTestId('job-duration');
+ const findJobFinishedTime = () => wrapper.findByTestId('job-finished-time');
+ const findDurationIcon = () => wrapper.findByTestId('duration-icon');
+ const findFinishedTimeIcon = () => wrapper.findByTestId('finished-time-icon');
+
+ const createComponent = (props) => {
+ wrapper = extendedWrapper(
+ shallowMount(DurationCell, {
+ propsData: {
+ job: {
+ ...props,
+ },
+ },
+ }),
+ );
+ };
+
+ it('does not display duration or finished time when no properties are present', () => {
+ createComponent();
+
+ expect(findJobDuration().exists()).toBe(false);
+ expect(findJobFinishedTime().exists()).toBe(false);
+ });
+
+ it('displays duration and finished time when both properties are present', () => {
+ const props = {
+ duration: 7,
+ finishedAt: '2021-04-26T13:37:52Z',
+ };
+
+ createComponent(props);
+
+ expect(findJobDuration().exists()).toBe(true);
+ expect(findJobFinishedTime().exists()).toBe(true);
+ });
+
+ it('displays only the duration of the job when the duration property is present', () => {
+ const props = {
+ duration: 7,
+ };
+
+ createComponent(props);
+
+ expect(findJobDuration().exists()).toBe(true);
+ expect(findJobFinishedTime().exists()).toBe(false);
+ });
+
+ it('displays only the finished time of the job when the finshedAt property is present', () => {
+ const props = {
+ finishedAt: '2021-04-26T13:37:52Z',
+ };
+
+ createComponent(props);
+
+ expect(findJobFinishedTime().exists()).toBe(true);
+ expect(findJobDuration().exists()).toBe(false);
+ });
+
+ it('displays icons for finished time and duration', () => {
+ const props = {
+ duration: 7,
+ finishedAt: '2021-04-26T13:37:52Z',
+ };
+
+ createComponent(props);
+
+ expect(findFinishedTimeIcon().props('name')).toBe('calendar');
+ expect(findDurationIcon().props('name')).toBe('timer');
+ });
+});
diff --git a/spec/frontend/ci/jobs_page/components/job_cells/job_cell_spec.js b/spec/frontend/ci/jobs_page/components/job_cells/job_cell_spec.js
new file mode 100644
index 00000000000..cb8f6ed8f9b
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/components/job_cells/job_cell_spec.js
@@ -0,0 +1,142 @@
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import JobCell from '~/ci/jobs_page/components/job_cells/job_cell.vue';
+import { mockJobsNodes, mockJobsNodesAsGuest } from 'jest/ci/jobs_mock_data';
+
+describe('Job Cell', () => {
+ let wrapper;
+
+ const findMockJob = (jobName, nodes = mockJobsNodes) => {
+ const job = nodes.find(({ name }) => name === jobName);
+ expect(job).toBeDefined(); // ensure job is present
+ return job;
+ };
+
+ const mockJob = findMockJob('build');
+ const jobCreatedByTag = findMockJob('created_by_tag');
+ const pendingJob = findMockJob('pending');
+ const jobAsGuest = findMockJob('build', mockJobsNodesAsGuest);
+
+ const findJobIdLink = () => wrapper.findByTestId('job-id-link');
+ const findJobIdNoLink = () => wrapper.findByTestId('job-id-limited-access');
+ const findJobRef = () => wrapper.findByTestId('job-ref');
+ const findJobSha = () => wrapper.findByTestId('job-sha');
+ const findLabelIcon = () => wrapper.findByTestId('label-icon');
+ const findForkIcon = () => wrapper.findByTestId('fork-icon');
+ const findStuckIcon = () => wrapper.findByTestId('stuck-icon');
+ const findAllTagBadges = () => wrapper.findAllByTestId('job-tag-badge');
+
+ const findBadgeById = (id) => wrapper.findByTestId(id);
+
+ const createComponent = (job = mockJob) => {
+ wrapper = extendedWrapper(
+ shallowMount(JobCell, {
+ propsData: {
+ job,
+ },
+ }),
+ );
+ };
+
+ describe('Job Id', () => {
+ it('displays the job id and links to the job', () => {
+ createComponent();
+
+ const expectedJobId = `#${getIdFromGraphQLId(mockJob.id)}`;
+
+ expect(findJobIdLink().text()).toBe(expectedJobId);
+ expect(findJobIdLink().attributes('href')).toBe(mockJob.detailedStatus.detailsPath);
+ expect(findJobIdNoLink().exists()).toBe(false);
+ });
+
+ it('display the job id with no link', () => {
+ createComponent(jobAsGuest);
+
+ const expectedJobId = `#${getIdFromGraphQLId(jobAsGuest.id)}`;
+
+ expect(findJobIdNoLink().text()).toBe(expectedJobId);
+ expect(findJobIdNoLink().exists()).toBe(true);
+ expect(findJobIdLink().exists()).toBe(false);
+ });
+ });
+
+ describe('Ref of the job', () => {
+ it('displays the ref name and links to the ref', () => {
+ createComponent();
+
+ expect(findJobRef().text()).toBe(mockJob.refName);
+ expect(findJobRef().attributes('href')).toBe(mockJob.refPath);
+ });
+
+ it('displays fork icon when job is not created by tag', () => {
+ createComponent();
+
+ expect(findForkIcon().exists()).toBe(true);
+ expect(findLabelIcon().exists()).toBe(false);
+ });
+
+ it('displays label icon when job is created by a tag', () => {
+ createComponent(jobCreatedByTag);
+
+ expect(findLabelIcon().exists()).toBe(true);
+ expect(findForkIcon().exists()).toBe(false);
+ });
+ });
+
+ describe('Commit of the job', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays the sha and links to the commit', () => {
+ expect(findJobSha().text()).toBe(mockJob.shortSha);
+ expect(findJobSha().attributes('href')).toBe(mockJob.commitPath);
+ });
+ });
+
+ describe('Job badges', () => {
+ it('displays tags of the job', () => {
+ const mockJobWithTags = {
+ tags: ['tag-1', 'tag-2', 'tag-3'],
+ };
+
+ createComponent(mockJobWithTags);
+
+ expect(findAllTagBadges()).toHaveLength(mockJobWithTags.tags.length);
+ });
+
+ it.each`
+ testId | text
+ ${'manual-job-badge'} | ${'manual'}
+ ${'triggered-job-badge'} | ${'triggered'}
+ ${'fail-job-badge'} | ${'allowed to fail'}
+ ${'delayed-job-badge'} | ${'delayed'}
+ `('displays the static $text badge', ({ testId, text }) => {
+ createComponent({
+ manualJob: true,
+ triggered: true,
+ allowFailure: true,
+ scheduledAt: '2021-03-09T14:58:50+00:00',
+ });
+
+ expect(findBadgeById(testId).exists()).toBe(true);
+ expect(findBadgeById(testId).text()).toBe(text);
+ });
+ });
+
+ describe('Job icons', () => {
+ it('stuck icon is not shown if job is not stuck', () => {
+ createComponent();
+
+ expect(findStuckIcon().exists()).toBe(false);
+ });
+
+ it('stuck icon is shown if job is pending', () => {
+ createComponent(pendingJob);
+
+ expect(findStuckIcon().exists()).toBe(true);
+ expect(findStuckIcon().attributes('name')).toBe('warning');
+ });
+ });
+});
diff --git a/spec/frontend/ci/jobs_page/components/job_cells/pipeline_cell_spec.js b/spec/frontend/ci/jobs_page/components/job_cells/pipeline_cell_spec.js
new file mode 100644
index 00000000000..6b212846897
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/components/job_cells/pipeline_cell_spec.js
@@ -0,0 +1,78 @@
+import { GlAvatar } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import PipelineCell from '~/ci/jobs_page/components/job_cells/pipeline_cell.vue';
+
+const mockJobWithoutUser = {
+ id: 'gid://gitlab/Ci::Build/2264',
+ pipeline: {
+ id: 'gid://gitlab/Ci::Pipeline/460',
+ path: '/root/ci-project/-/pipelines/460',
+ },
+};
+
+const mockJobWithUser = {
+ id: 'gid://gitlab/Ci::Build/2264',
+ pipeline: {
+ id: 'gid://gitlab/Ci::Pipeline/460',
+ path: '/root/ci-project/-/pipelines/460',
+ user: {
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ webPath: '/root',
+ },
+ },
+};
+
+describe('Pipeline Cell', () => {
+ let wrapper;
+
+ const findPipelineId = () => wrapper.findByTestId('pipeline-id');
+ const findPipelineUserLink = () => wrapper.findByTestId('pipeline-user-link');
+ const findUserAvatar = () => wrapper.findComponent(GlAvatar);
+
+ const createComponent = (props = mockJobWithUser) => {
+ wrapper = extendedWrapper(
+ shallowMount(PipelineCell, {
+ propsData: {
+ job: props,
+ },
+ }),
+ );
+ };
+
+ describe('Pipeline Id', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays the pipeline id and links to the pipeline', () => {
+ const expectedPipelineId = `#${getIdFromGraphQLId(mockJobWithUser.pipeline.id)}`;
+
+ expect(findPipelineId().text()).toBe(expectedPipelineId);
+ expect(findPipelineId().attributes('href')).toBe(mockJobWithUser.pipeline.path);
+ });
+ });
+
+ describe('Pipeline created by', () => {
+ const apiWrapperText = 'API';
+
+ it('shows and links to the pipeline user', () => {
+ createComponent();
+
+ expect(findPipelineUserLink().exists()).toBe(true);
+ expect(findPipelineUserLink().attributes('href')).toBe(mockJobWithUser.pipeline.user.webPath);
+ expect(findUserAvatar().attributes('src')).toBe(mockJobWithUser.pipeline.user.avatarUrl);
+ expect(wrapper.text()).not.toContain(apiWrapperText);
+ });
+
+ it('shows pipeline was created by the API', () => {
+ createComponent(mockJobWithoutUser);
+
+ expect(findPipelineUserLink().exists()).toBe(false);
+ expect(findUserAvatar().exists()).toBe(false);
+ expect(wrapper.text()).toContain(apiWrapperText);
+ });
+ });
+});
diff --git a/spec/frontend/ci/jobs_page/components/jobs_table_empty_state_spec.js b/spec/frontend/ci/jobs_page/components/jobs_table_empty_state_spec.js
new file mode 100644
index 00000000000..f4893c4077f
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/components/jobs_table_empty_state_spec.js
@@ -0,0 +1,37 @@
+import { GlEmptyState } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import JobsTableEmptyState from '~/ci/jobs_page/components/jobs_table_empty_state.vue';
+
+describe('Jobs table empty state', () => {
+ let wrapper;
+
+ const pipelineEditorPath = '/root/project/-/ci/editor';
+ const emptyStateSvgPath = 'assets/jobs-empty-state.svg';
+
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+
+ const createComponent = () => {
+ wrapper = shallowMount(JobsTableEmptyState, {
+ provide: {
+ pipelineEditorPath,
+ emptyStateSvgPath,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays empty state', () => {
+ expect(findEmptyState().exists()).toBe(true);
+ });
+
+ it('links to the pipeline editor', () => {
+ expect(findEmptyState().props('primaryButtonLink')).toBe(pipelineEditorPath);
+ });
+
+ it('shows an empty state image', () => {
+ expect(findEmptyState().props('svgPath')).toBe(emptyStateSvgPath);
+ });
+});
diff --git a/spec/frontend/ci/jobs_page/components/jobs_table_spec.js b/spec/frontend/ci/jobs_page/components/jobs_table_spec.js
new file mode 100644
index 00000000000..3adb95bf371
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/components/jobs_table_spec.js
@@ -0,0 +1,107 @@
+import { GlTable } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import JobsTable from '~/ci/jobs_page/components/jobs_table.vue';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import { DEFAULT_FIELDS_ADMIN } from '~/ci/admin/jobs_table/constants';
+import ProjectCell from '~/ci/admin/jobs_table/components/cells/project_cell.vue';
+import RunnerCell from '~/ci/admin/jobs_table/components/cells/runner_cell.vue';
+import { mockJobsNodes, mockAllJobsNodes } from 'jest/ci/jobs_mock_data';
+
+describe('Jobs Table', () => {
+ let wrapper;
+
+ const findTable = () => wrapper.findComponent(GlTable);
+ const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
+ const findTableRows = () => wrapper.findAllByTestId('jobs-table-row');
+ const findJobStage = () => wrapper.findByTestId('job-stage-name');
+ const findJobName = () => wrapper.findByTestId('job-name');
+ const findJobProject = () => wrapper.findComponent(ProjectCell);
+ const findJobRunner = () => wrapper.findComponent(RunnerCell);
+ const findAllCoverageJobs = () => wrapper.findAllByTestId('job-coverage');
+
+ const createComponent = (props = {}) => {
+ wrapper = extendedWrapper(
+ mount(JobsTable, {
+ propsData: {
+ ...props,
+ },
+ }),
+ );
+ };
+
+ describe('jobs table', () => {
+ beforeEach(() => {
+ createComponent({ jobs: mockJobsNodes });
+ });
+
+ it('displays the jobs table', () => {
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('displays correct number of job rows', () => {
+ expect(findTableRows()).toHaveLength(mockJobsNodes.length);
+ });
+
+ it('displays job status', () => {
+ expect(findCiBadgeLink().exists()).toBe(true);
+ });
+
+ it('displays the job stage and name', () => {
+ const [firstJob] = mockJobsNodes;
+
+ expect(findJobStage().text()).toBe(firstJob.stage.name);
+ expect(findJobName().text()).toBe(firstJob.name);
+ });
+
+ it('displays the coverage for only jobs that have coverage', () => {
+ const jobsThatHaveCoverage = mockJobsNodes.filter((job) => job.coverage !== null);
+
+ jobsThatHaveCoverage.forEach((job, index) => {
+ expect(findAllCoverageJobs().at(index).text()).toBe(`${job.coverage}%`);
+ });
+ expect(findAllCoverageJobs()).toHaveLength(jobsThatHaveCoverage.length);
+ });
+
+ describe('when stage of a job is missing', () => {
+ it('shows no stage', () => {
+ const stagelessJob = { ...mockJobsNodes[0], stage: null };
+ createComponent({ jobs: [stagelessJob] });
+
+ expect(findJobStage().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('regular user', () => {
+ beforeEach(() => {
+ createComponent({ jobs: mockJobsNodes });
+ });
+
+ it('hides the job runner', () => {
+ expect(findJobRunner().exists()).toBe(false);
+ });
+
+ it('hides the job project link', () => {
+ expect(findJobProject().exists()).toBe(false);
+ });
+ });
+
+ describe('admin mode', () => {
+ beforeEach(() => {
+ createComponent({ jobs: mockAllJobsNodes, tableFields: DEFAULT_FIELDS_ADMIN, admin: true });
+ });
+
+ it('displays the runner cell', () => {
+ expect(findJobRunner().exists()).toBe(true);
+ });
+
+ it('displays the project cell', () => {
+ expect(findJobProject().exists()).toBe(true);
+ });
+
+ it('displays correct number of job rows', () => {
+ expect(findTableRows()).toHaveLength(mockAllJobsNodes.length);
+ });
+ });
+});
diff --git a/spec/frontend/ci/jobs_page/components/jobs_table_tabs_spec.js b/spec/frontend/ci/jobs_page/components/jobs_table_tabs_spec.js
new file mode 100644
index 00000000000..c36f3841890
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/components/jobs_table_tabs_spec.js
@@ -0,0 +1,81 @@
+import { GlTab } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import { trimText } from 'helpers/text_helper';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import JobsTableTabs from '~/ci/jobs_page/components/jobs_table_tabs.vue';
+import CancelJobs from '~/ci/admin/jobs_table/components/cancel_jobs.vue';
+
+describe('Jobs Table Tabs', () => {
+ let wrapper;
+
+ const defaultProps = {
+ allJobsCount: 286,
+ loading: false,
+ };
+
+ const adminProps = {
+ ...defaultProps,
+ showCancelAllJobsButton: true,
+ };
+
+ const statuses = {
+ success: 'SUCCESS',
+ failed: 'FAILED',
+ canceled: 'CANCELED',
+ };
+
+ const findAllTab = () => wrapper.findByTestId('jobs-all-tab');
+ const findFinishedTab = () => wrapper.findByTestId('jobs-finished-tab');
+ const findCancelJobsButton = () => wrapper.findAllComponents(CancelJobs);
+
+ const triggerTabChange = (index) => wrapper.findAllComponents(GlTab).at(index).vm.$emit('click');
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = extendedWrapper(
+ mount(JobsTableTabs, {
+ provide: {
+ jobStatuses: {
+ ...statuses,
+ },
+ },
+ propsData: {
+ ...props,
+ },
+ }),
+ );
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays All tab with count', () => {
+ expect(trimText(findAllTab().text())).toBe(`All ${defaultProps.allJobsCount}`);
+ });
+
+ it('displays Finished tab with no count', () => {
+ expect(findFinishedTab().text()).toBe('Finished');
+ });
+
+ it.each`
+ tabIndex | expectedScope
+ ${0} | ${null}
+ ${1} | ${[statuses.success, statuses.failed, statuses.canceled]}
+ `('emits fetchJobsByStatus with $expectedScope on tab change', ({ tabIndex, expectedScope }) => {
+ triggerTabChange(tabIndex);
+
+ expect(wrapper.emitted()).toEqual({ fetchJobsByStatus: [[expectedScope]] });
+ });
+
+ it('does not displays cancel all jobs button', () => {
+ expect(findCancelJobsButton().exists()).toBe(false);
+ });
+
+ describe('admin mode', () => {
+ it('displays cancel all jobs button', () => {
+ createComponent(adminProps);
+
+ expect(findCancelJobsButton().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/jobs_page/graphql/cache_config_spec.js b/spec/frontend/ci/jobs_page/graphql/cache_config_spec.js
new file mode 100644
index 00000000000..cfbd77f4154
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/graphql/cache_config_spec.js
@@ -0,0 +1,106 @@
+import cacheConfig from '~/ci/jobs_page/graphql/cache_config';
+import {
+ CIJobConnectionExistingCache,
+ CIJobConnectionIncomingCache,
+ CIJobConnectionIncomingCacheRunningStatus,
+} from 'jest/ci/jobs_mock_data';
+
+const firstLoadArgs = { first: 3, statuses: 'PENDING' };
+const runningArgs = { first: 3, statuses: 'RUNNING' };
+
+describe('jobs/components/table/graphql/cache_config', () => {
+ describe('when fetching data with the same statuses', () => {
+ it('should contain cache nodes and a status when merging caches on first load', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
+ args: firstLoadArgs,
+ });
+
+ expect(res.nodes).toHaveLength(CIJobConnectionIncomingCache.nodes.length);
+ expect(res.statuses).toBe('PENDING');
+ });
+
+ it('should add to existing caches when merging caches after first load', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ CIJobConnectionIncomingCache,
+ {
+ args: firstLoadArgs,
+ },
+ );
+
+ expect(res.nodes).toHaveLength(
+ CIJobConnectionIncomingCache.nodes.length + CIJobConnectionExistingCache.nodes.length,
+ );
+ });
+
+ it('should not add to existing cache if the incoming elements are the same', () => {
+ // simulate that this is the last page
+ const finalExistingCache = {
+ ...CIJobConnectionExistingCache,
+ pageInfo: {
+ hasNextPage: false,
+ },
+ };
+
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ finalExistingCache,
+ {
+ args: firstLoadArgs,
+ },
+ );
+
+ expect(res.nodes).toHaveLength(CIJobConnectionExistingCache.nodes.length);
+ });
+
+ it('should contain the pageInfo key as part of the result', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
+ args: firstLoadArgs,
+ });
+
+ expect(res.pageInfo).toEqual(
+ expect.objectContaining({
+ __typename: 'PageInfo',
+ endCursor: 'eyJpZCI6IjIwNTEifQ',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'eyJpZCI6IjIxNzMifQ',
+ }),
+ );
+ });
+ });
+
+ describe('when fetching data with different statuses', () => {
+ it('should reset cache when a cache already exists', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ CIJobConnectionIncomingCacheRunningStatus,
+ {
+ args: runningArgs,
+ },
+ );
+
+ expect(res.nodes).not.toEqual(CIJobConnectionExistingCache.nodes);
+ expect(res.nodes).toHaveLength(CIJobConnectionIncomingCacheRunningStatus.nodes.length);
+ });
+ });
+
+ describe('when incoming data has no nodes', () => {
+ it('should return existing cache', () => {
+ const res = cacheConfig.typePolicies.CiJobConnection.merge(
+ CIJobConnectionExistingCache,
+ { __typename: 'CiJobConnection', count: 500 },
+ {
+ args: { statuses: 'SUCCESS' },
+ },
+ );
+
+ const expectedResponse = {
+ ...CIJobConnectionExistingCache,
+ statuses: 'SUCCESS',
+ };
+
+ expect(res).toEqual(expectedResponse);
+ });
+ });
+});
diff --git a/spec/frontend/ci/jobs_page/job_page_app_spec.js b/spec/frontend/ci/jobs_page/job_page_app_spec.js
new file mode 100644
index 00000000000..77443c9d490
--- /dev/null
+++ b/spec/frontend/ci/jobs_page/job_page_app_spec.js
@@ -0,0 +1,338 @@
+import { GlAlert, GlEmptyState, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
+import { mount, shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { s__ } from '~/locale';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { TEST_HOST } from 'spec/test_constants';
+import { createAlert } from '~/alert';
+import getJobsQuery from '~/ci/jobs_page/graphql/queries/get_jobs.query.graphql';
+import getJobsCountQuery from '~/ci/jobs_page/graphql/queries/get_jobs_count.query.graphql';
+import JobsTable from '~/ci/jobs_page/components/jobs_table.vue';
+import JobsTableApp from '~/ci/jobs_page/jobs_page_app.vue';
+import JobsTableTabs from '~/ci/jobs_page/components/jobs_table_tabs.vue';
+import JobsFilteredSearch from '~/ci/common/private/jobs_filtered_search/app.vue';
+import JobsSkeletonLoader from '~/ci/admin/jobs_table/components/jobs_skeleton_loader.vue';
+import * as urlUtils from '~/lib/utils/url_utility';
+import {
+ mockJobsResponsePaginated,
+ mockJobsResponseEmpty,
+ mockFailedSearchToken,
+ mockJobsCountResponse,
+} from 'jest/ci/jobs_mock_data';
+
+const projectPath = 'gitlab-org/gitlab';
+Vue.use(VueApollo);
+
+jest.mock('~/alert');
+
+describe('Job table app', () => {
+ let wrapper;
+
+ const successHandler = jest.fn().mockResolvedValue(mockJobsResponsePaginated);
+ const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+ const emptyHandler = jest.fn().mockResolvedValue(mockJobsResponseEmpty);
+
+ const countSuccessHandler = jest.fn().mockResolvedValue(mockJobsCountResponse);
+
+ const findSkeletonLoader = () => wrapper.findComponent(JobsSkeletonLoader);
+ const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
+ const findTable = () => wrapper.findComponent(JobsTable);
+ const findTabs = () => wrapper.findComponent(JobsTableTabs);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findFilteredSearch = () => wrapper.findComponent(JobsFilteredSearch);
+
+ const triggerInfiniteScroll = () =>
+ wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
+
+ const createMockApolloProvider = (handler, countHandler) => {
+ const requestHandlers = [
+ [getJobsQuery, handler],
+ [getJobsCountQuery, countHandler],
+ ];
+
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = ({
+ handler = successHandler,
+ countHandler = countSuccessHandler,
+ mountFn = shallowMount,
+ } = {}) => {
+ wrapper = mountFn(JobsTableApp, {
+ provide: {
+ fullPath: projectPath,
+ },
+ apolloProvider: createMockApolloProvider(handler, countHandler),
+ });
+ };
+
+ describe('loading state', () => {
+ it('should display skeleton loader when loading', () => {
+ createComponent();
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ expect(findTable().exists()).toBe(false);
+ expect(findLoadingSpinner().exists()).toBe(false);
+ });
+
+ it('when switching tabs only the skeleton loader should show', () => {
+ createComponent();
+
+ findTabs().vm.$emit('fetchJobsByStatus', null);
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ expect(findLoadingSpinner().exists()).toBe(false);
+ });
+ });
+
+ describe('loaded state', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('should display the jobs table with data', () => {
+ expect(findTable().exists()).toBe(true);
+ expect(findSkeletonLoader().exists()).toBe(false);
+ expect(findLoadingSpinner().exists()).toBe(false);
+ });
+
+ it('should refetch jobs query on fetchJobsByStatus event', async () => {
+ expect(successHandler).toHaveBeenCalledTimes(1);
+
+ await findTabs().vm.$emit('fetchJobsByStatus');
+
+ expect(successHandler).toHaveBeenCalledTimes(2);
+ });
+
+ it('avoids refetch jobs query when scope has not changed', async () => {
+ expect(successHandler).toHaveBeenCalledTimes(1);
+
+ await findTabs().vm.$emit('fetchJobsByStatus', null);
+
+ expect(successHandler).toHaveBeenCalledTimes(1);
+ });
+
+ it('should refetch jobs count query when the amount jobs and count do not match', async () => {
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+
+ // after applying filter a new count is fetched
+ findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(2);
+
+ // tab is switched to `finished`, no count
+ await findTabs().vm.$emit('fetchJobsByStatus', ['FAILED', 'SUCCESS', 'CANCELED']);
+
+ // tab is switched back to `all`, the old filter count has to be overwritten with new count
+ await findTabs().vm.$emit('fetchJobsByStatus', null);
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(3);
+ });
+
+ describe('when infinite scrolling is triggered', () => {
+ it('does not display a skeleton loader', () => {
+ triggerInfiniteScroll();
+
+ expect(findSkeletonLoader().exists()).toBe(false);
+ });
+
+ it('handles infinite scrolling by calling fetch more', async () => {
+ triggerInfiniteScroll();
+
+ await nextTick();
+
+ const pageSize = 30;
+
+ expect(findLoadingSpinner().exists()).toBe(true);
+
+ await waitForPromises();
+
+ expect(findLoadingSpinner().exists()).toBe(false);
+
+ expect(successHandler).toHaveBeenLastCalledWith({
+ first: pageSize,
+ fullPath: projectPath,
+ after: mockJobsResponsePaginated.data.project.jobs.pageInfo.endCursor,
+ });
+ });
+ });
+ });
+
+ describe('error state', () => {
+ it('should show an alert if there is an error fetching the jobs data', async () => {
+ createComponent({ handler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe('There was an error fetching the jobs for your project.');
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('should show an alert if there is an error fetching the jobs count data', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe(
+ 'There was an error fetching the number of jobs for your project.',
+ );
+ });
+
+ it('jobs table should still load if count query fails', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('jobs count should be zero if count query fails', async () => {
+ createComponent({ handler: successHandler, countHandler: failedHandler });
+
+ await waitForPromises();
+
+ expect(findTabs().props('allJobsCount')).toBe(0);
+ });
+ });
+
+ describe('empty state', () => {
+ it('should display empty state if there are no jobs and tab scope is null', async () => {
+ createComponent({ handler: emptyHandler, mountFn: mount });
+
+ await waitForPromises();
+
+ expect(findEmptyState().exists()).toBe(true);
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('should not display empty state if there are jobs and tab scope is not null', async () => {
+ createComponent({ handler: successHandler, mountFn: mount });
+
+ await waitForPromises();
+
+ expect(findEmptyState().exists()).toBe(false);
+ expect(findTable().exists()).toBe(true);
+ });
+ });
+
+ describe('filtered search', () => {
+ it('should display filtered search', () => {
+ createComponent();
+
+ expect(findFilteredSearch().exists()).toBe(true);
+ });
+
+ // this test should be updated once BE supports tab and filtered search filtering
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/356210
+ it.each`
+ scope | shouldDisplay
+ ${null} | ${true}
+ ${['FAILED', 'SUCCESS', 'CANCELED']} | ${false}
+ `(
+ 'with tab scope $scope the filtered search displays $shouldDisplay',
+ async ({ scope, shouldDisplay }) => {
+ createComponent();
+
+ await waitForPromises();
+
+ await findTabs().vm.$emit('fetchJobsByStatus', scope);
+
+ expect(findFilteredSearch().exists()).toBe(shouldDisplay);
+ },
+ );
+
+ it('refetches jobs query when filtering', async () => {
+ createComponent();
+
+ expect(successHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(successHandler).toHaveBeenCalledTimes(2);
+ });
+
+ it('refetches jobs count query when filtering', async () => {
+ createComponent();
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(2);
+ });
+
+ it('shows raw text warning when user inputs raw text', async () => {
+ const expectedWarning = {
+ message: s__(
+ 'Jobs|Raw text search is not currently supported for the jobs filtered search feature. Please use the available search tokens.',
+ ),
+ type: 'warning',
+ };
+
+ createComponent();
+
+ expect(successHandler).toHaveBeenCalledTimes(1);
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', ['raw text']);
+
+ expect(createAlert).toHaveBeenCalledWith(expectedWarning);
+ expect(successHandler).toHaveBeenCalledTimes(1);
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+ });
+
+ it('updates URL query string when filtering jobs by status', async () => {
+ createComponent();
+
+ jest.spyOn(urlUtils, 'updateHistory');
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(urlUtils.updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/?statuses=FAILED`,
+ });
+ });
+
+ it('resets query param after clearing tokens', () => {
+ createComponent();
+
+ jest.spyOn(urlUtils, 'updateHistory');
+
+ findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+
+ expect(successHandler).toHaveBeenCalledWith({
+ first: 30,
+ fullPath: 'gitlab-org/gitlab',
+ statuses: 'FAILED',
+ });
+ expect(countSuccessHandler).toHaveBeenCalledWith({
+ fullPath: 'gitlab-org/gitlab',
+ statuses: 'FAILED',
+ });
+ expect(urlUtils.updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/?statuses=FAILED`,
+ });
+
+ findFilteredSearch().vm.$emit('filterJobsBySearch', []);
+
+ expect(urlUtils.updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/`,
+ });
+
+ expect(successHandler).toHaveBeenCalledWith({
+ first: 30,
+ fullPath: 'gitlab-org/gitlab',
+ statuses: null,
+ });
+ expect(countSuccessHandler).toHaveBeenCalledWith({
+ fullPath: 'gitlab-org/gitlab',
+ statuses: null,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/merge_requests/components/pipelines_table_wrapper_spec.js b/spec/frontend/ci/merge_requests/components/pipelines_table_wrapper_spec.js
new file mode 100644
index 00000000000..df9bf2a4235
--- /dev/null
+++ b/spec/frontend/ci/merge_requests/components/pipelines_table_wrapper_spec.js
@@ -0,0 +1,117 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+
+import { createAlert } from '~/alert';
+import PipelinesTableWrapper from '~/ci/merge_requests/components/pipelines_table_wrapper.vue';
+import getMergeRequestsPipelines from '~/ci/merge_requests/graphql/queries/get_merge_request_pipelines.query.graphql';
+
+import { mergeRequestPipelinesResponse } from '../mock_data';
+
+Vue.use(VueApollo);
+
+jest.mock('~/alert');
+
+const pipelinesLength = mergeRequestPipelinesResponse.data.project.mergeRequest.pipelines.count;
+
+let wrapper;
+let mergeRequestPipelinesRequest;
+let apolloMock;
+
+const defaultProvide = {
+ graphqlPath: '/api/graphql/',
+ mergeRequestId: 1,
+ targetProjectFullPath: '/group/project',
+};
+
+const createComponent = () => {
+ const handlers = [[getMergeRequestsPipelines, mergeRequestPipelinesRequest]];
+
+ apolloMock = createMockApollo(handlers);
+
+ wrapper = shallowMount(PipelinesTableWrapper, {
+ apolloProvider: apolloMock,
+ provide: {
+ ...defaultProvide,
+ },
+ });
+
+ return waitForPromises();
+};
+
+const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+const findPipelineList = () => wrapper.findAll('li');
+
+beforeEach(() => {
+ mergeRequestPipelinesRequest = jest.fn();
+ mergeRequestPipelinesRequest.mockResolvedValue(mergeRequestPipelinesResponse);
+});
+afterEach(() => {
+ apolloMock = null;
+ createAlert.mockClear();
+});
+
+describe('PipelinesTableWrapper component', () => {
+ describe('When queries are loading', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('does not render the pipeline list', () => {
+ expect(findPipelineList()).toHaveLength(0);
+ });
+ });
+
+ describe('When there is an error fetching pipelines', () => {
+ beforeEach(async () => {
+ mergeRequestPipelinesRequest.mockRejectedValueOnce({ error: 'API error message' });
+ await createComponent();
+ });
+ it('shows an error message', () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
+ message: "There was an error fetching this merge request's pipelines.",
+ });
+ });
+ });
+
+ describe('When queries have loaded', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
+ it('does not render the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('renders a pipeline list', () => {
+ expect(findPipelineList()).toHaveLength(pipelinesLength);
+ });
+ });
+
+ describe('polling', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
+ it('polls every 10 seconds', () => {
+ expect(mergeRequestPipelinesRequest).toHaveBeenCalledTimes(1);
+
+ jest.advanceTimersByTime(5000);
+
+ expect(mergeRequestPipelinesRequest).toHaveBeenCalledTimes(1);
+
+ jest.advanceTimersByTime(5000);
+
+ expect(mergeRequestPipelinesRequest).toHaveBeenCalledTimes(2);
+ });
+ });
+});
diff --git a/spec/frontend/ci/merge_requests/mock_data.js b/spec/frontend/ci/merge_requests/mock_data.js
new file mode 100644
index 00000000000..1d8fdb88aa3
--- /dev/null
+++ b/spec/frontend/ci/merge_requests/mock_data.js
@@ -0,0 +1,30 @@
+const createMergeRequestPipelines = (count = 30) => {
+ const pipelines = [];
+
+ for (let i = 0; i < count; i += 1) {
+ pipelines.push({
+ id: i,
+ iid: i + 10,
+ path: `/project/pipelines/${i}`,
+ });
+ }
+
+ return {
+ count,
+ nodes: pipelines,
+ };
+};
+
+export const mergeRequestPipelinesResponse = {
+ data: {
+ project: {
+ __typename: 'Project',
+ id: 'gid://gitlab/Project/1',
+ mergeRequest: {
+ __typename: 'MergeRequest',
+ id: 'gid://gitlab/MergeRequest/1',
+ pipelines: createMergeRequestPipelines(),
+ },
+ },
+ },
+};
diff --git a/spec/frontend/ci/mixins/delayed_job_mixin_spec.js b/spec/frontend/ci/mixins/delayed_job_mixin_spec.js
new file mode 100644
index 00000000000..a1dab55bd07
--- /dev/null
+++ b/spec/frontend/ci/mixins/delayed_job_mixin_spec.js
@@ -0,0 +1,119 @@
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import delayedJobFixture from 'test_fixtures/jobs/delayed.json';
+import delayedJobMixin from '~/ci/mixins/delayed_job_mixin';
+
+describe('DelayedJobMixin', () => {
+ let wrapper;
+ const dummyComponent = {
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ },
+ mixins: [delayedJobMixin],
+ template: '<div>{{remainingTime}}</div>',
+ };
+
+ describe('if job is empty object', () => {
+ beforeEach(() => {
+ wrapper = shallowMount(dummyComponent, {
+ propsData: {
+ job: {},
+ },
+ });
+ });
+
+ it('sets remaining time to 00:00:00', () => {
+ expect(wrapper.text()).toBe('00:00:00');
+ });
+
+ it('does not update remaining time after mounting', async () => {
+ await nextTick();
+
+ expect(wrapper.text()).toBe('00:00:00');
+ });
+ });
+
+ describe('in REST component', () => {
+ describe('if job is delayed job', () => {
+ let remainingTimeInMilliseconds = 42000;
+
+ beforeEach(async () => {
+ jest
+ .spyOn(Date, 'now')
+ .mockImplementation(
+ () => new Date(delayedJobFixture.scheduled_at).getTime() - remainingTimeInMilliseconds,
+ );
+
+ wrapper = shallowMount(dummyComponent, {
+ propsData: {
+ job: delayedJobFixture,
+ },
+ });
+
+ await nextTick();
+ });
+
+ it('sets remaining time', () => {
+ expect(wrapper.text()).toBe('00:00:42');
+ });
+
+ it('updates remaining time', async () => {
+ remainingTimeInMilliseconds = 41000;
+ jest.advanceTimersByTime(1000);
+
+ await nextTick();
+ expect(wrapper.text()).toBe('00:00:41');
+ });
+ });
+ });
+
+ describe('in GraphQL component', () => {
+ const mockGraphQlJob = {
+ name: 'build_b',
+ scheduledAt: new Date(delayedJobFixture.scheduled_at),
+ status: {
+ icon: 'status_success',
+ tooltip: 'passed',
+ hasDetails: true,
+ detailsPath: '/root/abcd-dag/-/jobs/1515',
+ group: 'success',
+ action: null,
+ },
+ };
+
+ describe('if job is delayed job', () => {
+ let remainingTimeInMilliseconds = 42000;
+
+ beforeEach(async () => {
+ jest
+ .spyOn(Date, 'now')
+ .mockImplementation(
+ () => mockGraphQlJob.scheduledAt.getTime() - remainingTimeInMilliseconds,
+ );
+
+ wrapper = shallowMount(dummyComponent, {
+ propsData: {
+ job: mockGraphQlJob,
+ },
+ });
+
+ await nextTick();
+ });
+
+ it('sets remaining time', () => {
+ expect(wrapper.text()).toBe('00:00:42');
+ });
+
+ it('updates remaining time', async () => {
+ remainingTimeInMilliseconds = 41000;
+ jest.advanceTimersByTime(1000);
+
+ await nextTick();
+ expect(wrapper.text()).toBe('00:00:41');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/dag/components/__snapshots__/dag_graph_spec.js.snap b/spec/frontend/ci/pipeline_details/dag/components/__snapshots__/dag_graph_spec.js.snap
new file mode 100644
index 00000000000..624c89a237c
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/dag/components/__snapshots__/dag_graph_spec.js.snap
@@ -0,0 +1,743 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`The DAG graph in the basic case renders the graph svg 1`] = `
+<svg
+ height="540"
+ viewBox="0,0,1000,540"
+ width="1000"
+>
+ <g
+ fill="none"
+ stroke-opacity="0.8"
+ >
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-0"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-1"
+ x1="116"
+ x2="361.3333333333333"
+ >
+ <stop
+ offset="0%"
+ stop-color="#e17223"
+ />
+ <stop
+ offset="100%"
+ stop-color="#83ab4a"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-2"
+ >
+ <path
+ d="
+ M100, 129
+ V158
+ H377.3333333333333
+ V100
+ H100
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip63)"
+ d="M108,129L190,129L190,129L369.3333333333333,129"
+ stroke="url(#dag-grad53)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-3"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-4"
+ x1="377.3333333333333"
+ x2="622.6666666666666"
+ >
+ <stop
+ offset="0%"
+ stop-color="#83ab4a"
+ />
+ <stop
+ offset="100%"
+ stop-color="#6f3500"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-5"
+ >
+ <path
+ d="
+ M361.3333333333333, 129.0000000000002
+ V158.0000000000002
+ H638.6666666666666
+ V100
+ H361.3333333333333
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip64)"
+ d="M369.3333333333333,129L509.3333333333333,129L509.3333333333333,129.0000000000002L630.6666666666666,129.0000000000002"
+ stroke="url(#dag-grad54)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-6"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-7"
+ x1="116"
+ x2="622.6666666666666"
+ >
+ <stop
+ offset="0%"
+ stop-color="#5772ff"
+ />
+ <stop
+ offset="100%"
+ stop-color="#6f3500"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-8"
+ >
+ <path
+ d="
+ M100, 187.0000000000002
+ V241.00000000000003
+ H638.6666666666666
+ V158.0000000000002
+ H100
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip65)"
+ d="M108,212.00000000000003L306,212.00000000000003L306,187.0000000000002L630.6666666666666,187.0000000000002"
+ stroke="url(#dag-grad55)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-9"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-10"
+ x1="116"
+ x2="361.3333333333333"
+ >
+ <stop
+ offset="0%"
+ stop-color="#b24800"
+ />
+ <stop
+ offset="100%"
+ stop-color="#006887"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-11"
+ >
+ <path
+ d="
+ M100, 269.9999999999998
+ V324
+ H377.3333333333333
+ V240.99999999999977
+ H100
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip66)"
+ d="M108,295L338.93333333333334,295L338.93333333333334,269.9999999999998L369.3333333333333,269.9999999999998"
+ stroke="url(#dag-grad56)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-12"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-13"
+ x1="116"
+ x2="361.3333333333333"
+ >
+ <stop
+ offset="0%"
+ stop-color="#25d2d2"
+ />
+ <stop
+ offset="100%"
+ stop-color="#487900"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-14"
+ >
+ <path
+ d="
+ M100, 352.99999999999994
+ V407.00000000000006
+ H377.3333333333333
+ V323.99999999999994
+ H100
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip67)"
+ d="M108,378.00000000000006L144.66666666666669,378.00000000000006L144.66666666666669,352.99999999999994L369.3333333333333,352.99999999999994"
+ stroke="url(#dag-grad57)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-15"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-16"
+ x1="377.3333333333333"
+ x2="622.6666666666666"
+ >
+ <stop
+ offset="0%"
+ stop-color="#006887"
+ />
+ <stop
+ offset="100%"
+ stop-color="#d84280"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-17"
+ >
+ <path
+ d="
+ M361.3333333333333, 270.0000000000001
+ V299.0000000000001
+ H638.6666666666666
+ V240.99999999999977
+ H361.3333333333333
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip68)"
+ d="M369.3333333333333,269.9999999999998L464,269.9999999999998L464,270.0000000000001L630.6666666666666,270.0000000000001"
+ stroke="url(#dag-grad58)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-18"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-19"
+ x1="377.3333333333333"
+ x2="622.6666666666666"
+ >
+ <stop
+ offset="0%"
+ stop-color="#487900"
+ />
+ <stop
+ offset="100%"
+ stop-color="#d84280"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-20"
+ >
+ <path
+ d="
+ M361.3333333333333, 328.0000000000001
+ V381.99999999999994
+ H638.6666666666666
+ V299.0000000000001
+ H361.3333333333333
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip69)"
+ d="M369.3333333333333,352.99999999999994L522,352.99999999999994L522,328.0000000000001L630.6666666666666,328.0000000000001"
+ stroke="url(#dag-grad59)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-21"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-22"
+ x1="377.3333333333333"
+ x2="622.6666666666666"
+ >
+ <stop
+ offset="0%"
+ stop-color="#487900"
+ />
+ <stop
+ offset="100%"
+ stop-color="#3547de"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-23"
+ >
+ <path
+ d="
+ M361.3333333333333, 411
+ V440
+ H638.6666666666666
+ V381.99999999999994
+ H361.3333333333333
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip70)"
+ d="M369.3333333333333,410.99999999999994L580,410.99999999999994L580,411L630.6666666666666,411"
+ stroke="url(#dag-grad60)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-24"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-25"
+ x1="638.6666666666666"
+ x2="884"
+ >
+ <stop
+ offset="0%"
+ stop-color="#d84280"
+ />
+ <stop
+ offset="100%"
+ stop-color="#006887"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-26"
+ >
+ <path
+ d="
+ M622.6666666666666, 270.1890725105691
+ V299.1890725105691
+ H900
+ V241.0000000000001
+ H622.6666666666666
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip71)"
+ d="M630.6666666666666,270.0000000000001L861.6,270.0000000000001L861.6,270.1890725105691L892,270.1890725105691"
+ stroke="url(#dag-grad61)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ <g
+ class="dag-link gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke-opacity gl-transition-timing-function-ease"
+ id="reference-27"
+ >
+ <lineargradient
+ gradientUnits="userSpaceOnUse"
+ id="reference-28"
+ x1="638.6666666666666"
+ x2="884"
+ >
+ <stop
+ offset="0%"
+ stop-color="#3547de"
+ />
+ <stop
+ offset="100%"
+ stop-color="#275600"
+ />
+ </lineargradient>
+ <clippath
+ id="reference-29"
+ >
+ <path
+ d="
+ M622.6666666666666, 411
+ V440
+ H900
+ V382
+ H622.6666666666666
+ Z
+ "
+ />
+ </clippath>
+ <path
+ clip-path="url(#dag-clip72)"
+ d="M630.6666666666666,411L679.9999999999999,411L679.9999999999999,411L892,411"
+ stroke="url(#dag-grad62)"
+ stroke-width="56"
+ style="stroke-linejoin: round;"
+ />
+ </g>
+ </g>
+ <g>
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-30"
+ stroke="#e17223"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="108"
+ x2="108"
+ y1="104"
+ y2="154.00000000000003"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-31"
+ stroke="#83ab4a"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="369"
+ x2="369"
+ y1="104"
+ y2="154"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-32"
+ stroke="#5772ff"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="108"
+ x2="108"
+ y1="187.00000000000003"
+ y2="237.00000000000003"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-33"
+ stroke="#b24800"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="108"
+ x2="108"
+ y1="270"
+ y2="320.00000000000006"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-34"
+ stroke="#25d2d2"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="108"
+ x2="108"
+ y1="353.00000000000006"
+ y2="403.0000000000001"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-35"
+ stroke="#6f3500"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="630"
+ x2="630"
+ y1="104.0000000000002"
+ y2="212.00000000000009"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-36"
+ stroke="#006887"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="369"
+ x2="369"
+ y1="244.99999999999977"
+ y2="294.99999999999994"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-37"
+ stroke="#487900"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="369"
+ x2="369"
+ y1="327.99999999999994"
+ y2="436"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-38"
+ stroke="#d84280"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="630"
+ x2="630"
+ y1="245.00000000000009"
+ y2="353"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-39"
+ stroke="#3547de"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="630"
+ x2="630"
+ y1="386"
+ y2="436"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-40"
+ stroke="#006887"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="892"
+ x2="892"
+ y1="245.18907251056908"
+ y2="295.1890725105691"
+ />
+ <line
+ class="dag-node gl-cursor-pointer gl-transition-duration-slow gl-transition-property-stroke gl-transition-timing-function-ease"
+ id="reference-41"
+ stroke="#275600"
+ stroke-linecap="round"
+ stroke-width="16"
+ x1="892"
+ x2="892"
+ y1="386"
+ y2="436"
+ />
+ </g>
+ <g
+ class="gl-font-sm"
+ >
+ <foreignobject
+ class="gl-overflow-visible"
+ height="58.00000000000003px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="8"
+ y="100"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 58.00000000000003px; text-align: right;"
+ >
+ build_a
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="25px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="369.3333333333333"
+ y="75"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 25px; text-align: left;"
+ >
+ test_a
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="58px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="8"
+ y="183.00000000000003"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 58px; text-align: right;"
+ >
+ test_b
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="58.00000000000006px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="8"
+ y="266"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 58.00000000000006px; text-align: right;"
+ >
+ post_test_a
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="58.00000000000006px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="8"
+ y="349.00000000000006"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 58.00000000000006px; text-align: right;"
+ >
+ post_test_b
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="25px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="630.6666666666666"
+ y="75.0000000000002"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 25px; text-align: right;"
+ >
+ post_test_c
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="25px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="369.3333333333333"
+ y="215.99999999999977"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 25px; text-align: left;"
+ >
+ staging_a
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="25px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="369.3333333333333"
+ y="298.99999999999994"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 25px; text-align: left;"
+ >
+ staging_b
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="25px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="630.6666666666666"
+ y="216.00000000000009"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 25px; text-align: right;"
+ >
+ canary_a
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="25px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="630.6666666666666"
+ y="357"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 25px; text-align: right;"
+ >
+ canary_c
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="58px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="908"
+ y="241.18907251056908"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 58px; text-align: left;"
+ >
+ production_a
+ </div>
+ </foreignobject>
+ <foreignobject
+ class="gl-overflow-visible"
+ height="58px"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
+ width="84"
+ x="908"
+ y="382"
+ >
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break gl-pointer-events-none"
+ style="height: 58px; text-align: left;"
+ >
+ production_d
+ </div>
+ </foreignobject>
+ </g>
+</svg>
+`;
diff --git a/spec/frontend/ci/pipeline_details/dag/components/dag_annotations_spec.js b/spec/frontend/ci/pipeline_details/dag/components/dag_annotations_spec.js
new file mode 100644
index 00000000000..d1c338e50c6
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/dag/components/dag_annotations_spec.js
@@ -0,0 +1,98 @@
+import { GlButton } from '@gitlab/ui';
+import { shallowMount, mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import DagAnnotations from '~/ci/pipeline_details/dag/components/dag_annotations.vue';
+import { singleNote, multiNote } from '../mock_data';
+
+describe('The DAG annotations', () => {
+ let wrapper;
+
+ const getColorBlock = () => wrapper.find('[data-testid="dag-color-block"]');
+ const getAllColorBlocks = () => wrapper.findAll('[data-testid="dag-color-block"]');
+ const getTextBlock = () => wrapper.find('[data-testid="dag-note-text"]');
+ const getAllTextBlocks = () => wrapper.findAll('[data-testid="dag-note-text"]');
+ const getToggleButton = () => wrapper.findComponent(GlButton);
+
+ const createComponent = (propsData = {}, method = shallowMount) => {
+ wrapper = method(DagAnnotations, {
+ propsData,
+ data() {
+ return {
+ showList: true,
+ };
+ },
+ });
+ };
+
+ describe('when there is one annotation', () => {
+ const currentNote = singleNote['dag-link103'];
+
+ beforeEach(() => {
+ createComponent({ annotations: singleNote });
+ });
+
+ it('displays the color block', () => {
+ expect(getColorBlock().exists()).toBe(true);
+ });
+
+ it('displays the text block', () => {
+ expect(getTextBlock().exists()).toBe(true);
+ expect(getTextBlock().text()).toBe(`${currentNote.source.name} → ${currentNote.target.name}`);
+ });
+
+ it('does not display the list toggle link', () => {
+ expect(getToggleButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when there are multiple annoataions', () => {
+ beforeEach(() => {
+ createComponent({ annotations: multiNote });
+ });
+
+ it('displays a color block for each link', () => {
+ expect(getAllColorBlocks().length).toBe(Object.keys(multiNote).length);
+ });
+
+ it('displays a text block for each link', () => {
+ expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length);
+
+ Object.values(multiNote).forEach((item, idx) => {
+ expect(getAllTextBlocks().at(idx).text()).toBe(`${item.source.name} → ${item.target.name}`);
+ });
+ });
+
+ it('displays the list toggle link', () => {
+ expect(getToggleButton().exists()).toBe(true);
+ expect(getToggleButton().text()).toBe('Hide list');
+ });
+ });
+
+ describe('the list toggle', () => {
+ beforeEach(() => {
+ createComponent({ annotations: multiNote }, mount);
+ });
+
+ describe('clicking hide', () => {
+ it('hides listed items and changes text to show', async () => {
+ expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length);
+ expect(getToggleButton().text()).toBe('Hide list');
+ getToggleButton().trigger('click');
+ await nextTick();
+ expect(getAllTextBlocks().length).toBe(0);
+ expect(getToggleButton().text()).toBe('Show list');
+ });
+ });
+
+ describe('clicking show', () => {
+ it('shows listed items and changes text to hide', async () => {
+ getToggleButton().trigger('click');
+ getToggleButton().trigger('click');
+
+ await nextTick();
+ expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length);
+ expect(getToggleButton().text()).toBe('Hide list');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/dag/components/dag_graph_spec.js b/spec/frontend/ci/pipeline_details/dag/components/dag_graph_spec.js
new file mode 100644
index 00000000000..aff83c00e79
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/dag/components/dag_graph_spec.js
@@ -0,0 +1,209 @@
+import { shallowMount } from '@vue/test-utils';
+import { IS_HIGHLIGHTED, LINK_SELECTOR, NODE_SELECTOR } from '~/ci/pipeline_details/dag/constants';
+import DagGraph from '~/ci/pipeline_details/dag/components/dag_graph.vue';
+import { createSankey } from '~/ci/pipeline_details/dag/utils/drawing_utils';
+import { highlightIn, highlightOut } from '~/ci/pipeline_details/dag/utils/interactions';
+import { removeOrphanNodes } from '~/ci/pipeline_details/utils/parsing_utils';
+import { parsedData } from '../mock_data';
+
+describe('The DAG graph', () => {
+ let wrapper;
+
+ const getGraph = () => wrapper.find('.dag-graph-container > svg');
+ const getAllLinks = () => wrapper.findAll(`.${LINK_SELECTOR}`);
+ const getAllNodes = () => wrapper.findAll(`.${NODE_SELECTOR}`);
+ const getAllLabels = () => wrapper.findAll('foreignObject');
+
+ const createComponent = (propsData = {}) => {
+ if (wrapper?.destroy) {
+ wrapper.destroy();
+ }
+
+ wrapper = shallowMount(DagGraph, {
+ attachTo: document.body,
+ propsData,
+ data() {
+ return {
+ color: () => {},
+ width: 0,
+ height: 0,
+ };
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent({ graphData: parsedData });
+ });
+
+ describe('in the basic case', () => {
+ beforeEach(() => {
+ /*
+ The graph uses random to offset links. To keep the snapshot consistent,
+ we mock Math.random. Wheeeee!
+ */
+ const randomNumber = jest.spyOn(global.Math, 'random');
+ randomNumber.mockImplementation(() => 0.2);
+ createComponent({ graphData: parsedData });
+ });
+
+ it('renders the graph svg', () => {
+ expect(getGraph().exists()).toBe(true);
+ expect(getGraph().html()).toMatchSnapshot();
+ });
+ });
+
+ describe('links', () => {
+ it('renders the expected number of links', () => {
+ expect(getAllLinks()).toHaveLength(parsedData.links.length);
+ });
+
+ it('renders the expected number of gradients', () => {
+ expect(wrapper.findAll('linearGradient')).toHaveLength(parsedData.links.length);
+ });
+
+ it('renders the expected number of clip paths', () => {
+ expect(wrapper.findAll('clipPath')).toHaveLength(parsedData.links.length);
+ });
+ });
+
+ describe('nodes and labels', () => {
+ const sankeyNodes = createSankey()(parsedData).nodes;
+ const processedNodes = removeOrphanNodes(sankeyNodes);
+
+ describe('nodes', () => {
+ it('renders the expected number of nodes', () => {
+ expect(getAllNodes()).toHaveLength(processedNodes.length);
+ });
+ });
+
+ describe('labels', () => {
+ it('renders the expected number of labels as foreignObjects', () => {
+ expect(getAllLabels()).toHaveLength(processedNodes.length);
+ });
+
+ it('renders the title as text', () => {
+ expect(getAllLabels().at(0).text()).toBe(parsedData.nodes[0].name);
+ });
+ });
+ });
+
+ describe('interactions', () => {
+ const strokeOpacity = (opacity) => `stroke-opacity: ${opacity};`;
+ const baseOpacity = () => wrapper.vm.$options.viewOptions.baseOpacity;
+
+ describe('links', () => {
+ const liveLink = () => getAllLinks().at(4);
+ const otherLink = () => getAllLinks().at(1);
+
+ describe('on hover', () => {
+ it('sets the link opacity to baseOpacity and background links to 0.2', () => {
+ liveLink().trigger('mouseover');
+ expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
+ expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
+ });
+
+ it('reverts the styles on mouseout', () => {
+ liveLink().trigger('mouseover');
+ liveLink().trigger('mouseout');
+ expect(liveLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
+ expect(otherLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
+ });
+ });
+
+ describe('on click', () => {
+ describe('toggles link liveness', () => {
+ it('turns link on', () => {
+ liveLink().trigger('click');
+ expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
+ expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
+ });
+
+ it('turns link off on second click', () => {
+ liveLink().trigger('click');
+ liveLink().trigger('click');
+ expect(liveLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
+ expect(otherLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
+ });
+ });
+
+ it('the link remains live even after mouseout', () => {
+ liveLink().trigger('click');
+ liveLink().trigger('mouseout');
+ expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
+ expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
+ });
+
+ it('preserves state when multiple links are toggled on and off', () => {
+ const anotherLiveLink = () => getAllLinks().at(2);
+
+ liveLink().trigger('click');
+ anotherLiveLink().trigger('click');
+ expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
+ expect(anotherLiveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
+ expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
+
+ anotherLiveLink().trigger('click');
+ expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
+ expect(anotherLiveLink().attributes('style')).toBe(strokeOpacity(highlightOut));
+ expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
+
+ liveLink().trigger('click');
+ expect(liveLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
+ expect(anotherLiveLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
+ expect(otherLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
+ });
+ });
+ });
+
+ describe('nodes', () => {
+ const liveNode = () => getAllNodes().at(10);
+ const anotherLiveNode = () => getAllNodes().at(5);
+ const nodesNotHighlighted = () => getAllNodes().filter((n) => !n.classes(IS_HIGHLIGHTED));
+ const linksNotHighlighted = () => getAllLinks().filter((n) => !n.classes(IS_HIGHLIGHTED));
+ const nodesHighlighted = () => getAllNodes().filter((n) => n.classes(IS_HIGHLIGHTED));
+ const linksHighlighted = () => getAllLinks().filter((n) => n.classes(IS_HIGHLIGHTED));
+
+ describe('on click', () => {
+ it('highlights the clicked node and predecessors', () => {
+ liveNode().trigger('click');
+
+ expect(nodesNotHighlighted().length < getAllNodes().length).toBe(true);
+ expect(linksNotHighlighted().length < getAllLinks().length).toBe(true);
+
+ linksHighlighted().wrappers.forEach((link) => {
+ expect(link.attributes('style')).toBe(strokeOpacity(highlightIn));
+ });
+
+ nodesHighlighted().wrappers.forEach((node) => {
+ expect(node.attributes('stroke')).not.toBe('#f2f2f2');
+ });
+
+ linksNotHighlighted().wrappers.forEach((link) => {
+ expect(link.attributes('style')).toBe(strokeOpacity(highlightOut));
+ });
+
+ nodesNotHighlighted().wrappers.forEach((node) => {
+ expect(node.attributes('stroke')).toBe('#f2f2f2');
+ });
+ });
+
+ it('toggles path off on second click', () => {
+ liveNode().trigger('click');
+ liveNode().trigger('click');
+
+ expect(nodesNotHighlighted().length).toBe(getAllNodes().length);
+ expect(linksNotHighlighted().length).toBe(getAllLinks().length);
+ });
+
+ it('preserves state when multiple nodes are toggled on and off', () => {
+ anotherLiveNode().trigger('click');
+ liveNode().trigger('click');
+ anotherLiveNode().trigger('click');
+ expect(nodesNotHighlighted().length < getAllNodes().length).toBe(true);
+ expect(linksNotHighlighted().length < getAllLinks().length).toBe(true);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/dag/dag_spec.js b/spec/frontend/ci/pipeline_details/dag/dag_spec.js
new file mode 100644
index 00000000000..de9490be607
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/dag/dag_spec.js
@@ -0,0 +1,168 @@
+import { GlAlert, GlEmptyState } from '@gitlab/ui';
+import { mount, shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from '~/ci/pipeline_details/dag/constants';
+import Dag from '~/ci/pipeline_details/dag/dag.vue';
+import DagAnnotations from '~/ci/pipeline_details/dag/components/dag_annotations.vue';
+import DagGraph from '~/ci/pipeline_details/dag/components/dag_graph.vue';
+
+import { PARSE_FAILURE, UNSUPPORTED_DATA } from '~/ci/pipeline_details/constants';
+import {
+ mockParsedGraphQLNodes,
+ tooSmallGraph,
+ unparseableGraph,
+ graphWithoutDependencies,
+ singleNote,
+ multiNote,
+} from './mock_data';
+
+describe('Pipeline DAG graph wrapper', () => {
+ let wrapper;
+ const getAlert = () => wrapper.findComponent(GlAlert);
+ const getAllAlerts = () => wrapper.findAllComponents(GlAlert);
+ const getGraph = () => wrapper.findComponent(DagGraph);
+ const getNotes = () => wrapper.findComponent(DagAnnotations);
+ const getErrorText = (type) => wrapper.vm.$options.errorTexts[type];
+ const getEmptyState = () => wrapper.findComponent(GlEmptyState);
+
+ const createComponent = ({
+ graphData = mockParsedGraphQLNodes,
+ provideOverride = {},
+ method = shallowMount,
+ } = {}) => {
+ wrapper = method(Dag, {
+ provide: {
+ pipelineProjectPath: 'root/abc-dag',
+ pipelineIid: '1',
+ emptySvgPath: '/my-svg',
+ dagDocPath: '/my-doc',
+ ...provideOverride,
+ },
+ data() {
+ return {
+ graphData,
+ showFailureAlert: false,
+ };
+ },
+ });
+ };
+
+ describe('when a query argument is undefined', () => {
+ beforeEach(() => {
+ createComponent({
+ provideOverride: { pipelineProjectPath: undefined },
+ graphData: null,
+ });
+ });
+
+ it('does not render the graph', () => {
+ expect(getGraph().exists()).toBe(false);
+ });
+
+ it('does not render the empty state', () => {
+ expect(getEmptyState().exists()).toBe(false);
+ });
+ });
+
+ describe('when all query variables are defined', () => {
+ describe('but the parse fails', () => {
+ beforeEach(() => {
+ createComponent({
+ graphData: unparseableGraph,
+ });
+ });
+
+ it('shows the PARSE_FAILURE alert and not the graph', () => {
+ expect(getAlert().exists()).toBe(true);
+ expect(getAlert().text()).toBe(getErrorText(PARSE_FAILURE));
+ expect(getGraph().exists()).toBe(false);
+ });
+
+ it('does not render the empty state', () => {
+ expect(getEmptyState().exists()).toBe(false);
+ });
+ });
+
+ describe('parse succeeds', () => {
+ beforeEach(() => {
+ createComponent({ method: mount });
+ });
+
+ it('shows the graph', () => {
+ expect(getGraph().exists()).toBe(true);
+ });
+
+ it('does not render the empty state', () => {
+ expect(getEmptyState().exists()).toBe(false);
+ });
+ });
+
+ describe('parse succeeds, but the resulting graph is too small', () => {
+ beforeEach(() => {
+ createComponent({
+ graphData: tooSmallGraph,
+ });
+ });
+
+ it('shows the UNSUPPORTED_DATA alert and not the graph', () => {
+ expect(getAlert().exists()).toBe(true);
+ expect(getAlert().text()).toBe(getErrorText(UNSUPPORTED_DATA));
+ expect(getGraph().exists()).toBe(false);
+ });
+
+ it('does not show the empty dag graph state', () => {
+ expect(getEmptyState().exists()).toBe(false);
+ });
+ });
+
+ describe('the returned data is empty', () => {
+ beforeEach(() => {
+ createComponent({
+ method: mount,
+ graphData: graphWithoutDependencies,
+ });
+ });
+
+ it('does not render an error alert or the graph', () => {
+ expect(getAllAlerts().length).toBe(0);
+ expect(getGraph().exists()).toBe(false);
+ });
+
+ it('shows the empty dag graph state', () => {
+ expect(getEmptyState().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('annotations', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('toggles on link mouseover and mouseout', async () => {
+ const currentNote = singleNote['dag-link103'];
+
+ expect(getNotes().exists()).toBe(false);
+
+ getGraph().vm.$emit('update-annotation', { type: ADD_NOTE, data: currentNote });
+ await nextTick();
+ expect(getNotes().exists()).toBe(true);
+
+ getGraph().vm.$emit('update-annotation', { type: REMOVE_NOTE, data: currentNote });
+ await nextTick();
+ expect(getNotes().exists()).toBe(false);
+ });
+
+ it('toggles on node and link click', async () => {
+ expect(getNotes().exists()).toBe(false);
+
+ getGraph().vm.$emit('update-annotation', { type: REPLACE_NOTES, data: multiNote });
+ await nextTick();
+ expect(getNotes().exists()).toBe(true);
+
+ getGraph().vm.$emit('update-annotation', { type: REPLACE_NOTES, data: {} });
+ await nextTick();
+ expect(getNotes().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/pipelines/components/dag/mock_data.js b/spec/frontend/ci/pipeline_details/dag/mock_data.js
index f27e7cf3d6b..f27e7cf3d6b 100644
--- a/spec/frontend/pipelines/components/dag/mock_data.js
+++ b/spec/frontend/ci/pipeline_details/dag/mock_data.js
diff --git a/spec/frontend/ci/pipeline_details/dag/utils/drawing_utils_spec.js b/spec/frontend/ci/pipeline_details/dag/utils/drawing_utils_spec.js
new file mode 100644
index 00000000000..aea8e894bd4
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/dag/utils/drawing_utils_spec.js
@@ -0,0 +1,57 @@
+import { createSankey } from '~/ci/pipeline_details/dag/utils/drawing_utils';
+import { parseData } from '~/ci/pipeline_details/utils/parsing_utils';
+import { mockParsedGraphQLNodes } from '../mock_data';
+
+describe('DAG visualization drawing utilities', () => {
+ const parsed = parseData(mockParsedGraphQLNodes);
+
+ const layoutSettings = {
+ width: 200,
+ height: 200,
+ nodeWidth: 10,
+ nodePadding: 20,
+ paddingForLabels: 100,
+ };
+
+ const sankeyLayout = createSankey(layoutSettings)(parsed);
+
+ describe('createSankey', () => {
+ it('returns a nodes data structure with expected d3-added properties', () => {
+ const exampleNode = sankeyLayout.nodes[0];
+ expect(exampleNode).toHaveProperty('sourceLinks');
+ expect(exampleNode).toHaveProperty('targetLinks');
+ expect(exampleNode).toHaveProperty('depth');
+ expect(exampleNode).toHaveProperty('layer');
+ expect(exampleNode).toHaveProperty('x0');
+ expect(exampleNode).toHaveProperty('x1');
+ expect(exampleNode).toHaveProperty('y0');
+ expect(exampleNode).toHaveProperty('y1');
+ });
+
+ it('returns a links data structure with expected d3-added properties', () => {
+ const exampleLink = sankeyLayout.links[0];
+ expect(exampleLink).toHaveProperty('source');
+ expect(exampleLink).toHaveProperty('target');
+ expect(exampleLink).toHaveProperty('width');
+ expect(exampleLink).toHaveProperty('y0');
+ expect(exampleLink).toHaveProperty('y1');
+ });
+
+ describe('data structure integrity', () => {
+ const newObject = { name: 'bad-actor' };
+
+ beforeEach(() => {
+ sankeyLayout.nodes.unshift(newObject);
+ });
+
+ it('sankey does not propagate changes back to the original', () => {
+ expect(sankeyLayout.nodes[0]).toBe(newObject);
+ expect(parsed.nodes[0]).not.toBe(newObject);
+ });
+
+ afterEach(() => {
+ sankeyLayout.nodes.shift();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/__snapshots__/links_inner_spec.js.snap b/spec/frontend/ci/pipeline_details/graph/components/__snapshots__/links_inner_spec.js.snap
new file mode 100644
index 00000000000..b31c0e59a33
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/__snapshots__/links_inner_spec.js.snap
@@ -0,0 +1,110 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Links Inner component with a large number of needs matches snapshot and has expected path 1`] = `
+<div
+ class="gl-display-flex gl-relative"
+ totalgroups="10"
+>
+ <svg
+ class="gl-absolute gl-pointer-events-none"
+ height="445px"
+ id="reference-0"
+ viewBox="0,0,1019,445"
+ width="1019px"
+ >
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M202,118C52,118,52,138,102,138"
+ stroke-width="2"
+ />
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M202,118C62,118,62,148,112,148"
+ stroke-width="2"
+ />
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M222,138C72,138,72,158,122,158"
+ stroke-width="2"
+ />
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M212,128C82,128,82,168,132,168"
+ stroke-width="2"
+ />
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M232,148C92,148,92,178,142,178"
+ stroke-width="2"
+ />
+ </svg>
+</div>
+`;
+
+exports[`Links Inner component with a parallel need matches snapshot and has expected path 1`] = `
+<div
+ class="gl-display-flex gl-relative"
+ totalgroups="10"
+>
+ <svg
+ class="gl-absolute gl-pointer-events-none"
+ height="445px"
+ id="reference-0"
+ viewBox="0,0,1019,445"
+ width="1019px"
+ >
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M192,108C32,108,32,118,82,118"
+ stroke-width="2"
+ />
+ </svg>
+</div>
+`;
+
+exports[`Links Inner component with one need matches snapshot and has expected path 1`] = `
+<div
+ class="gl-display-flex gl-relative"
+ totalgroups="10"
+>
+ <svg
+ class="gl-absolute gl-pointer-events-none"
+ height="445px"
+ id="reference-0"
+ viewBox="0,0,1019,445"
+ width="1019px"
+ >
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M202,118C52,118,52,138,102,138"
+ stroke-width="2"
+ />
+ </svg>
+</div>
+`;
+
+exports[`Links Inner component with same stage needs matches snapshot and has expected path 1`] = `
+<div
+ class="gl-display-flex gl-relative"
+ totalgroups="10"
+>
+ <svg
+ class="gl-absolute gl-pointer-events-none"
+ height="445px"
+ id="reference-0"
+ viewBox="0,0,1019,445"
+ width="1019px"
+ >
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M192,108C32,108,32,118,82,118"
+ stroke-width="2"
+ />
+ <path
+ class="gl-fill-transparent gl-stroke-gray-200 gl-transition-duration-slow gl-transition-timing-function-ease"
+ d="M202,118C42,118,42,128,92,128"
+ stroke-width="2"
+ />
+ </svg>
+</div>
+`;
diff --git a/spec/frontend/ci/pipeline_details/graph/components/action_component_spec.js b/spec/frontend/ci/pipeline_details/graph/components/action_component_spec.js
new file mode 100644
index 00000000000..9e177156d0e
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/action_component_spec.js
@@ -0,0 +1,116 @@
+import { GlButton } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import { nextTick } from 'vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import ActionComponent from '~/ci/common/private/job_action_component.vue';
+
+describe('pipeline graph action component', () => {
+ let wrapper;
+ let mock;
+ const findButton = () => wrapper.findComponent(GlButton);
+ const findTooltipWrapper = () => wrapper.find('[data-testid="ci-action-icon-tooltip-wrapper"]');
+
+ const defaultProps = {
+ tooltipText: 'bar',
+ link: 'foo',
+ actionIcon: 'cancel',
+ };
+
+ const createComponent = ({ props } = {}) => {
+ wrapper = mount(ActionComponent, {
+ propsData: { ...defaultProps, ...props },
+ });
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ mock.onPost('foo.json').reply(HTTP_STATUS_OK);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('render', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should render the provided title as a bootstrap tooltip', () => {
+ expect(findTooltipWrapper().attributes('title')).toBe('bar');
+ });
+
+ it('should update bootstrap tooltip when title changes', async () => {
+ wrapper.setProps({ tooltipText: 'changed' });
+
+ await nextTick();
+ expect(findTooltipWrapper().attributes('title')).toBe('changed');
+ });
+
+ it('should render an svg', () => {
+ expect(wrapper.find('.ci-action-icon-wrapper').exists()).toBe(true);
+ expect(wrapper.find('svg').exists()).toBe(true);
+ });
+ });
+
+ describe('on click', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('emits `pipelineActionRequestComplete` after a successful request', async () => {
+ findButton().trigger('click');
+
+ await waitForPromises();
+
+ expect(wrapper.emitted().pipelineActionRequestComplete).toHaveLength(1);
+ });
+
+ it('renders a loading icon while waiting for request', async () => {
+ findButton().trigger('click');
+
+ await nextTick();
+ expect(wrapper.find('.js-action-icon-loading').exists()).toBe(true);
+ });
+ });
+
+ describe('when has a confirmation modal', () => {
+ beforeEach(() => {
+ createComponent({ props: { withConfirmationModal: true, shouldTriggerClick: false } });
+ });
+
+ describe('and a first click is initiated', () => {
+ beforeEach(async () => {
+ findButton().trigger('click');
+
+ await waitForPromises();
+ });
+
+ it('emits `showActionConfirmationModal` event', () => {
+ expect(wrapper.emitted().showActionConfirmationModal).toHaveLength(1);
+ });
+
+ it('does not emit `pipelineActionRequestComplete` event', () => {
+ expect(wrapper.emitted().pipelineActionRequestComplete).toBeUndefined();
+ });
+ });
+
+ describe('and the `shouldTriggerClick` value becomes true', () => {
+ beforeEach(async () => {
+ await wrapper.setProps({ shouldTriggerClick: true });
+ });
+
+ it('does not emit `showActionConfirmationModal` event', () => {
+ expect(wrapper.emitted().showActionConfirmationModal).toBeUndefined();
+ });
+
+ it('emits `actionButtonClicked` event', () => {
+ expect(wrapper.emitted().actionButtonClicked).toHaveLength(1);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/graph_component_spec.js b/spec/frontend/ci/pipeline_details/graph/components/graph_component_spec.js
new file mode 100644
index 00000000000..a98e79c69fe
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/graph_component_spec.js
@@ -0,0 +1,182 @@
+import { shallowMount } from '@vue/test-utils';
+import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { LAYER_VIEW, STAGE_VIEW } from '~/ci/pipeline_details/graph/constants';
+import PipelineGraph from '~/ci/pipeline_details/graph/components/graph_component.vue';
+import JobItem from '~/ci/pipeline_details/graph/components/job_item.vue';
+import LinkedPipelinesColumn from '~/ci/pipeline_details/graph/components/linked_pipelines_column.vue';
+import StageColumnComponent from '~/ci/pipeline_details/graph/components/stage_column_component.vue';
+import { calculatePipelineLayersInfo } from '~/ci/pipeline_details/graph/utils';
+import LinksLayer from '~/ci/common/private/job_links_layer.vue';
+
+import { generateResponse, pipelineWithUpstreamDownstream } from '../mock_data';
+
+describe('graph component', () => {
+ let wrapper;
+
+ const findDownstreamColumn = () => wrapper.findByTestId('downstream-pipelines');
+ const findLinkedColumns = () => wrapper.findAllComponents(LinkedPipelinesColumn);
+ const findLinksLayer = () => wrapper.findComponent(LinksLayer);
+ const findStageColumns = () => wrapper.findAllComponents(StageColumnComponent);
+ const findStageNameInJob = () => wrapper.findByTestId('stage-name-in-job');
+
+ const defaultProps = {
+ pipeline: generateResponse(mockPipelineResponse, 'root/fungi-xoxo'),
+ showLinks: false,
+ viewType: STAGE_VIEW,
+ configPaths: {
+ metricsPath: '',
+ graphqlResourceEtag: 'this/is/a/path',
+ },
+ };
+
+ const defaultData = {
+ measurements: {
+ width: 800,
+ height: 800,
+ },
+ };
+
+ const createComponent = ({
+ data = {},
+ mountFn = shallowMount,
+ props = {},
+ stubOverride = {},
+ } = {}) => {
+ wrapper = mountFn(PipelineGraph, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ data() {
+ return {
+ ...defaultData,
+ ...data,
+ };
+ },
+ stubs: {
+ 'links-inner': true,
+ 'linked-pipeline': true,
+ 'job-item': true,
+ 'job-group-dropdown': true,
+ ...stubOverride,
+ },
+ });
+ };
+
+ describe('with data', () => {
+ beforeEach(() => {
+ createComponent({ mountFn: mountExtended });
+ });
+
+ it('renders the main columns in the graph', () => {
+ expect(findStageColumns()).toHaveLength(defaultProps.pipeline.stages.length);
+ });
+
+ it('renders the links layer', () => {
+ expect(findLinksLayer().exists()).toBe(true);
+ });
+
+ it('does not display stage name on the job in default (stage) mode', () => {
+ expect(findStageNameInJob().exists()).toBe(false);
+ });
+
+ describe('when column requests a refresh', () => {
+ beforeEach(() => {
+ findStageColumns().at(0).vm.$emit('refreshPipelineGraph');
+ });
+
+ it('refreshPipelineGraph is emitted', () => {
+ expect(wrapper.emitted().refreshPipelineGraph).toHaveLength(1);
+ });
+ });
+
+ describe('when column request an update to the retry confirmation modal', () => {
+ beforeEach(() => {
+ findStageColumns().at(0).vm.$emit('setSkipRetryModal');
+ });
+
+ it('setSkipRetryModal is emitted', () => {
+ expect(wrapper.emitted().setSkipRetryModal).toHaveLength(1);
+ });
+ });
+
+ describe('when links are present', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mountExtended,
+ stubOverride: { 'job-item': false },
+ data: { hoveredJobName: 'test_a' },
+ });
+ findLinksLayer().vm.$emit('highlightedJobsChange', ['test_c', 'build_c']);
+ });
+
+ it('dims unrelated jobs', () => {
+ const unrelatedJob = wrapper.findComponent(JobItem);
+ expect(findLinksLayer().emitted().highlightedJobsChange).toHaveLength(1);
+ expect(unrelatedJob.classes('gl-opacity-3')).toBe(true);
+ });
+ });
+ });
+
+ describe('when linked pipelines are not present', () => {
+ beforeEach(() => {
+ createComponent({ mountFn: mountExtended });
+ });
+
+ it('should not render a linked pipelines column', () => {
+ expect(findLinkedColumns()).toHaveLength(0);
+ });
+ });
+
+ describe('when linked pipelines are present', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mountExtended,
+ props: { pipeline: pipelineWithUpstreamDownstream(mockPipelineResponse) },
+ });
+ });
+
+ it('should render linked pipelines columns', () => {
+ expect(findLinkedColumns()).toHaveLength(2);
+ });
+ });
+
+ describe('in layers mode', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mountExtended,
+ stubOverride: {
+ 'job-item': false,
+ 'job-group-dropdown': false,
+ },
+ props: {
+ viewType: LAYER_VIEW,
+ computedPipelineInfo: calculatePipelineLayersInfo(defaultProps.pipeline, 'layer', ''),
+ },
+ });
+ });
+
+ it('displays the stage name on the job', () => {
+ expect(findStageNameInJob().exists()).toBe(true);
+ });
+ });
+
+ describe('downstream pipelines', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mountExtended,
+ props: {
+ pipeline: pipelineWithUpstreamDownstream(mockPipelineResponse),
+ },
+ });
+ });
+
+ it('filters pipelines spawned from the same trigger job', () => {
+ // The mock data has one downstream with `retried: true and one
+ // with retried false. We filter the `retried: true` out so we
+ // should only pass one downstream
+ expect(findDownstreamColumn().props().linkedPipelines).toHaveLength(1);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/graph_view_selector_spec.js b/spec/frontend/ci/pipeline_details/graph/components/graph_view_selector_spec.js
new file mode 100644
index 00000000000..bf98995de9c
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/graph_view_selector_spec.js
@@ -0,0 +1,217 @@
+import { GlAlert, GlButton, GlButtonGroup, GlLoadingIcon } from '@gitlab/ui';
+import { mount, shallowMount } from '@vue/test-utils';
+import { LAYER_VIEW, STAGE_VIEW } from '~/ci/pipeline_details/graph/constants';
+import GraphViewSelector from '~/ci/pipeline_details/graph/components/graph_view_selector.vue';
+
+describe('the graph view selector component', () => {
+ let wrapper;
+
+ const findDependenciesToggle = () => wrapper.find('[data-testid="show-links-toggle"]');
+ const findViewTypeSelector = () => wrapper.findComponent(GlButtonGroup);
+ const findStageViewButton = () => findViewTypeSelector().findAllComponents(GlButton).at(0);
+ const findLayerViewButton = () => findViewTypeSelector().findAllComponents(GlButton).at(1);
+ const findSwitcherLoader = () => wrapper.find('[data-testid="switcher-loading-state"]');
+ const findToggleLoader = () => findDependenciesToggle().findComponent(GlLoadingIcon);
+ const findHoverTip = () => wrapper.findComponent(GlAlert);
+
+ const defaultProps = {
+ showLinks: false,
+ tipPreviouslyDismissed: false,
+ type: STAGE_VIEW,
+ };
+
+ const defaultData = {
+ hoverTipDismissed: false,
+ isToggleLoading: false,
+ isSwitcherLoading: false,
+ showLinksActive: false,
+ };
+
+ const createComponent = ({ data = {}, mountFn = shallowMount, props = {} } = {}) => {
+ wrapper = mountFn(GraphViewSelector, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ data() {
+ return {
+ ...defaultData,
+ ...data,
+ };
+ },
+ });
+ };
+
+ describe('when showing stage view', () => {
+ beforeEach(() => {
+ createComponent({ mountFn: mount });
+ });
+
+ it('shows the Stage view button as selected', () => {
+ expect(findStageViewButton().classes('selected')).toBe(true);
+ });
+
+ it('shows the Job dependencies view button not selected', () => {
+ expect(findLayerViewButton().exists()).toBe(true);
+ expect(findLayerViewButton().classes('selected')).toBe(false);
+ });
+
+ it('does not show the Job dependencies (links) toggle', () => {
+ expect(findDependenciesToggle().exists()).toBe(false);
+ });
+ });
+
+ describe('when showing Job dependencies view', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mount,
+ props: {
+ type: LAYER_VIEW,
+ },
+ });
+ });
+
+ it('shows the Job dependencies view as selected', () => {
+ expect(findLayerViewButton().classes('selected')).toBe(true);
+ });
+
+ it('shows the Stage button as not selected', () => {
+ expect(findStageViewButton().exists()).toBe(true);
+ expect(findStageViewButton().classes('selected')).toBe(false);
+ });
+
+ it('shows the Job dependencies (links) toggle', () => {
+ expect(findDependenciesToggle().exists()).toBe(true);
+ });
+ });
+
+ describe('events', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mount,
+ props: {
+ type: LAYER_VIEW,
+ },
+ });
+ });
+
+ it('shows loading state and emits updateViewType when view type toggled', async () => {
+ expect(wrapper.emitted().updateViewType).toBeUndefined();
+ expect(findSwitcherLoader().exists()).toBe(false);
+
+ await findStageViewButton().trigger('click');
+ /*
+ Loading happens before the event is emitted or timers are run.
+ Then we run the timer because the event is emitted in setInterval
+ which is what gives the loader a chace to show up.
+ */
+ expect(findSwitcherLoader().exists()).toBe(true);
+ jest.runOnlyPendingTimers();
+
+ expect(wrapper.emitted().updateViewType).toHaveLength(1);
+ expect(wrapper.emitted().updateViewType).toEqual([[STAGE_VIEW]]);
+ });
+
+ it('shows loading state and emits updateShowLinks when show links toggle is clicked', async () => {
+ expect(wrapper.emitted().updateShowLinksState).toBeUndefined();
+ expect(findToggleLoader().exists()).toBe(false);
+
+ await findDependenciesToggle().vm.$emit('change', true);
+ /*
+ Loading happens before the event is emitted or timers are run.
+ Then we run the timer because the event is emitted in setInterval
+ which is what gives the loader a chace to show up.
+ */
+ expect(findToggleLoader().exists()).toBe(true);
+ jest.runOnlyPendingTimers();
+
+ expect(wrapper.emitted().updateShowLinksState).toHaveLength(1);
+ expect(wrapper.emitted().updateShowLinksState).toEqual([[true]]);
+ });
+
+ it('does not emit an event if the click occurs on the currently selected view button', async () => {
+ expect(wrapper.emitted().updateShowLinksState).toBeUndefined();
+
+ await findLayerViewButton().trigger('click');
+
+ expect(wrapper.emitted().updateShowLinksState).toBeUndefined();
+ });
+ });
+
+ describe('hover tip callout', () => {
+ describe('when links are live and it has not been previously dismissed', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ showLinks: true,
+ type: LAYER_VIEW,
+ },
+ data: {
+ showLinksActive: true,
+ },
+ mountFn: mount,
+ });
+ });
+
+ it('is displayed', () => {
+ expect(findHoverTip().exists()).toBe(true);
+ expect(findHoverTip().text()).toBe(wrapper.vm.$options.i18n.hoverTipText);
+ });
+
+ it('emits dismissHoverTip event when the tip is dismissed', async () => {
+ expect(wrapper.emitted().dismissHoverTip).toBeUndefined();
+ await findHoverTip().find('button').trigger('click');
+ expect(wrapper.emitted().dismissHoverTip).toHaveLength(1);
+ });
+
+ it('is displayed at first then hidden on swith to STAGE_VIEW then displayed on switch to LAYER_VIEW', async () => {
+ expect(findHoverTip().exists()).toBe(true);
+ expect(findHoverTip().text()).toBe(wrapper.vm.$options.i18n.hoverTipText);
+
+ await findStageViewButton().trigger('click');
+ expect(findHoverTip().exists()).toBe(false);
+
+ await findLayerViewButton().trigger('click');
+ expect(findHoverTip().exists()).toBe(true);
+ expect(findHoverTip().text()).toBe(wrapper.vm.$options.i18n.hoverTipText);
+ });
+ });
+
+ describe('when links are live and it has been previously dismissed', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ showLinks: true,
+ tipPreviouslyDismissed: true,
+ type: LAYER_VIEW,
+ },
+ data: {
+ showLinksActive: true,
+ },
+ });
+ });
+
+ it('is not displayed', () => {
+ expect(findHoverTip().exists()).toBe(false);
+ });
+ });
+
+ describe('when links are not live', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ showLinks: true,
+ type: LAYER_VIEW,
+ },
+ data: {
+ showLinksActive: false,
+ },
+ });
+ });
+
+ it('is not displayed', () => {
+ expect(findHoverTip().exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/job_group_dropdown_spec.js b/spec/frontend/ci/pipeline_details/graph/components/job_group_dropdown_spec.js
new file mode 100644
index 00000000000..d5a1cfffe68
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/job_group_dropdown_spec.js
@@ -0,0 +1,84 @@
+import { shallowMount, mount } from '@vue/test-utils';
+import JobGroupDropdown from '~/ci/pipeline_details/graph/components/job_group_dropdown.vue';
+
+describe('job group dropdown component', () => {
+ const group = {
+ jobs: [
+ {
+ id: 4256,
+ name: '<img src=x onerror=alert(document.domain)>',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ tooltip: 'passed',
+ group: 'success',
+ details_path: '/root/ci-mock/builds/4256',
+ has_details: true,
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/root/ci-mock/builds/4256/retry',
+ method: 'post',
+ },
+ },
+ },
+ {
+ id: 4299,
+ name: 'test',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ tooltip: 'passed',
+ group: 'success',
+ details_path: '/root/ci-mock/builds/4299',
+ has_details: true,
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/root/ci-mock/builds/4299/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ name: 'rspec:linux',
+ size: 2,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ tooltip: 'passed',
+ group: 'success',
+ details_path: '/root/ci-mock/builds/4256',
+ has_details: true,
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/root/ci-mock/builds/4256/retry',
+ method: 'post',
+ },
+ },
+ };
+
+ let wrapper;
+ const findButton = () => wrapper.find('button');
+
+ const createComponent = ({ mountFn = shallowMount }) => {
+ wrapper = mountFn(JobGroupDropdown, { propsData: { group } });
+ };
+
+ beforeEach(() => {
+ createComponent({ mountFn: mount });
+ });
+
+ it('renders button with group name and size', () => {
+ expect(findButton().text()).toContain(group.name);
+ expect(findButton().text()).toContain(group.size.toString());
+ });
+
+ it('renders dropdown with jobs', () => {
+ expect(wrapper.findAll('.scrollable-menu>ul>li').length).toBe(group.jobs.length);
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/job_item_spec.js b/spec/frontend/ci/pipeline_details/graph/components/job_item_spec.js
new file mode 100644
index 00000000000..107f0df5c02
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/job_item_spec.js
@@ -0,0 +1,492 @@
+import MockAdapter from 'axios-mock-adapter';
+import Vue, { nextTick } from 'vue';
+import { GlBadge, GlModal, GlToast } from '@gitlab/ui';
+import JobItem from '~/ci/pipeline_details/graph/components/job_item.vue';
+import axios from '~/lib/utils/axios_utils';
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+import ActionComponent from '~/ci/common/private/job_action_component.vue';
+
+import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import {
+ delayedJob,
+ mockJob,
+ mockJobWithoutDetails,
+ mockJobWithUnauthorizedAction,
+ mockFailedJob,
+ triggerJob,
+ triggerJobWithRetryAction,
+} from '../mock_data';
+
+describe('pipeline graph job item', () => {
+ useLocalStorageSpy();
+ Vue.use(GlToast);
+
+ let wrapper;
+ let mockAxios;
+
+ const findJobWithoutLink = () => wrapper.findByTestId('job-without-link');
+ const findJobWithLink = () => wrapper.findByTestId('job-with-link');
+ const findActionVueComponent = () => wrapper.findComponent(ActionComponent);
+ const findActionComponent = () => wrapper.findByTestId('ci-action-component');
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const findJobLink = () => wrapper.findByTestId('job-with-link');
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const clickOnModalPrimaryBtn = () => findModal().vm.$emit('primary');
+ const clickOnModalCancelBtn = () => findModal().vm.$emit('hide');
+ const clickOnModalCloseBtn = () => findModal().vm.$emit('close');
+
+ const myCustomClass1 = 'my-class-1';
+ const myCustomClass2 = 'my-class-2';
+
+ const defaultProps = {
+ job: mockJob,
+ };
+
+ const createWrapper = ({ props, data, mountFn = mountExtended, mocks = {} } = {}) => {
+ wrapper = mountFn(JobItem, {
+ data() {
+ return {
+ ...data,
+ };
+ },
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ mocks: {
+ ...mocks,
+ },
+ });
+ };
+
+ const triggerActiveClass = 'gl-shadow-x0-y0-b3-s1-blue-500';
+
+ beforeEach(() => {
+ mockAxios = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ describe('name with link', () => {
+ it('should render the job name and status with a link', async () => {
+ createWrapper();
+
+ await nextTick();
+ const link = findJobLink();
+
+ expect(link.attributes('href')).toBe(mockJob.status.detailsPath);
+
+ expect(link.attributes('title')).toBe(`${mockJob.name} - ${mockJob.status.label}`);
+
+ expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
+
+ expect(wrapper.text()).toBe(mockJob.name);
+ });
+ });
+
+ describe('name without link', () => {
+ beforeEach(() => {
+ createWrapper({
+ props: {
+ job: mockJobWithoutDetails,
+ cssClassJobName: 'css-class-job-name',
+ jobHovered: 'test',
+ },
+ });
+ });
+
+ it('should render status and name', () => {
+ expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
+ expect(findJobLink().exists()).toBe(false);
+
+ expect(wrapper.text()).toBe(mockJobWithoutDetails.name);
+ });
+
+ it('should apply hover class and provided class name', () => {
+ expect(findJobWithoutLink().classes()).toContain('css-class-job-name');
+ });
+ });
+
+ describe('action icon', () => {
+ it('should render the action icon', () => {
+ createWrapper();
+
+ const actionComponent = findActionComponent();
+
+ expect(actionComponent.exists()).toBe(true);
+ expect(actionComponent.props('actionIcon')).toBe('retry');
+ expect(actionComponent.attributes('disabled')).toBeUndefined();
+ });
+
+ it('should render disabled action icon when user cannot run the action', () => {
+ createWrapper({
+ props: {
+ job: mockJobWithUnauthorizedAction,
+ },
+ });
+
+ const actionComponent = findActionComponent();
+
+ expect(actionComponent.exists()).toBe(true);
+ expect(actionComponent.props('actionIcon')).toBe('stop');
+ expect(actionComponent.attributes('disabled')).toBeDefined();
+ });
+
+ it('action icon tooltip text when job has passed but can be ran again', () => {
+ createWrapper({ props: { job: mockJob } });
+
+ expect(findActionComponent().props('tooltipText')).toBe('Run again');
+ });
+
+ it('action icon tooltip text when job has failed and can be retried', () => {
+ createWrapper({ props: { job: mockFailedJob } });
+
+ expect(findActionComponent().props('tooltipText')).toBe('Retry');
+ });
+ });
+
+ describe('job style', () => {
+ beforeEach(() => {
+ createWrapper({
+ props: {
+ job: mockJob,
+ cssClassJobName: 'css-class-job-name',
+ },
+ });
+ });
+
+ it('should render provided class name', () => {
+ expect(findJobLink().classes()).toContain('css-class-job-name');
+ });
+
+ it('does not show a badge on the job item', () => {
+ expect(findBadge().exists()).toBe(false);
+ });
+
+ it('does not apply the trigger job class', () => {
+ expect(findJobWithLink().classes()).not.toContain('gl-rounded-lg');
+ });
+ });
+
+ describe('status label', () => {
+ it('should not render status label when it is not provided', () => {
+ createWrapper({
+ props: {
+ job: {
+ id: 4258,
+ name: 'test',
+ status: {
+ icon: 'status_success',
+ },
+ },
+ },
+ });
+
+ expect(findJobWithoutLink().attributes('title')).toBe('test');
+ });
+
+ it('should not render status label when it is provided', () => {
+ createWrapper({
+ props: {
+ job: {
+ id: 4259,
+ name: 'test',
+ status: {
+ icon: 'status_success',
+ label: 'success',
+ tooltip: 'success',
+ },
+ },
+ },
+ });
+
+ expect(findJobWithoutLink().attributes('title')).toBe('test - success');
+ });
+ });
+
+ describe('for delayed job', () => {
+ it('displays remaining time in tooltip', () => {
+ createWrapper({
+ props: {
+ job: delayedJob,
+ },
+ });
+
+ expect(findJobWithLink().attributes('title')).toBe(
+ `delayed job - delayed manual action (00:00:00)`,
+ );
+ });
+ });
+
+ describe('trigger job', () => {
+ describe('card', () => {
+ beforeEach(() => {
+ createWrapper({
+ props: {
+ job: triggerJob,
+ },
+ });
+ });
+
+ it('shows a badge on the job item', () => {
+ expect(findBadge().exists()).toBe(true);
+ expect(findBadge().text()).toBe('Trigger job');
+ });
+
+ it('applies a rounded corner style instead of the usual pill shape', () => {
+ expect(findJobWithoutLink().classes()).toContain('gl-rounded-lg');
+ });
+ });
+
+ describe('when retrying', () => {
+ const mockToastShow = jest.fn();
+
+ beforeEach(async () => {
+ createWrapper({
+ mountFn: shallowMountExtended,
+ props: {
+ skipRetryModal: true,
+ job: triggerJobWithRetryAction,
+ },
+ mocks: {
+ $toast: {
+ show: mockToastShow,
+ },
+ },
+ });
+
+ await findActionVueComponent().vm.$emit('pipelineActionRequestComplete');
+ await nextTick();
+ });
+
+ it('shows a toast message that the downstream is being created', () => {
+ expect(mockToastShow).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('highlighting', () => {
+ it.each`
+ job | jobName | expanded | link
+ ${mockJob} | ${mockJob.name} | ${true} | ${true}
+ ${mockJobWithoutDetails} | ${mockJobWithoutDetails.name} | ${true} | ${false}
+ `(
+ `trigger job should stay highlighted when downstream is expanded`,
+ ({ job, jobName, expanded, link }) => {
+ createWrapper({
+ props: {
+ job,
+ pipelineExpanded: { jobName, expanded },
+ },
+ });
+ const findJobEl = link ? findJobWithLink : findJobWithoutLink;
+
+ expect(findJobEl().classes()).toContain(triggerActiveClass);
+ },
+ );
+
+ it.each`
+ job | jobName | expanded | link
+ ${mockJob} | ${mockJob.name} | ${false} | ${true}
+ ${mockJobWithoutDetails} | ${mockJobWithoutDetails.name} | ${false} | ${false}
+ `(
+ `trigger job should not be highlighted when downstream is not expanded`,
+ ({ job, jobName, expanded, link }) => {
+ createWrapper({
+ props: {
+ job,
+ pipelineExpanded: { jobName, expanded },
+ },
+ });
+ const findJobEl = link ? findJobWithLink : findJobWithoutLink;
+
+ expect(findJobEl().classes()).not.toContain(triggerActiveClass);
+ },
+ );
+ });
+ });
+
+ describe('job classes', () => {
+ it('job class is shown', () => {
+ createWrapper({
+ props: {
+ job: mockJob,
+ cssClassJobName: 'my-class',
+ },
+ });
+
+ const jobLinkEl = findJobLink();
+
+ expect(jobLinkEl.classes()).toContain('my-class');
+
+ expect(jobLinkEl.classes()).not.toContain(triggerActiveClass);
+ });
+
+ it('job class is shown, along with hover', () => {
+ createWrapper({
+ props: {
+ job: mockJob,
+ cssClassJobName: 'my-class',
+ sourceJobHovered: mockJob.name,
+ },
+ });
+
+ const jobLinkEl = findJobLink();
+
+ expect(jobLinkEl.classes()).toContain('my-class');
+ expect(jobLinkEl.classes()).toContain(triggerActiveClass);
+ });
+
+ it('multiple job classes are shown', () => {
+ createWrapper({
+ props: {
+ job: mockJob,
+ cssClassJobName: [myCustomClass1, myCustomClass2],
+ },
+ });
+
+ const jobLinkEl = findJobLink();
+
+ expect(jobLinkEl.classes()).toContain(myCustomClass1);
+ expect(jobLinkEl.classes()).toContain(myCustomClass2);
+
+ expect(jobLinkEl.classes()).not.toContain(triggerActiveClass);
+ });
+
+ it('multiple job classes are shown conditionally', () => {
+ createWrapper({
+ props: {
+ job: mockJob,
+ cssClassJobName: { [myCustomClass1]: true, [myCustomClass2]: true },
+ },
+ });
+
+ const jobLinkEl = findJobLink();
+
+ expect(jobLinkEl.classes()).toContain(myCustomClass1);
+ expect(jobLinkEl.classes()).toContain(myCustomClass2);
+
+ expect(jobLinkEl.classes()).not.toContain(triggerActiveClass);
+ });
+
+ it('multiple job classes are shown, along with a hover', () => {
+ createWrapper({
+ props: {
+ job: mockJob,
+ cssClassJobName: [myCustomClass1, myCustomClass2],
+ sourceJobHovered: mockJob.name,
+ },
+ });
+
+ const jobLinkEl = findJobLink();
+
+ expect(jobLinkEl.classes()).toContain(myCustomClass1);
+ expect(jobLinkEl.classes()).toContain(myCustomClass2);
+ expect(jobLinkEl.classes()).toContain(triggerActiveClass);
+ });
+ });
+
+ describe('confirmation modal', () => {
+ describe('when clicking on the action component', () => {
+ it.each`
+ skipRetryModal | exists | visibilityText
+ ${false} | ${true} | ${'shows'}
+ ${true} | ${false} | ${'hides'}
+ `(
+ '$visibilityText the modal when `skipRetryModal` is $skipRetryModal',
+ async ({ exists, skipRetryModal }) => {
+ createWrapper({
+ props: {
+ skipRetryModal,
+ job: triggerJobWithRetryAction,
+ },
+ });
+ await findActionComponent().trigger('click');
+
+ expect(findModal().exists()).toBe(exists);
+ },
+ );
+ });
+
+ describe('when showing the modal', () => {
+ it.each`
+ buttonName | shouldTriggerActionClick | actionBtn
+ ${'primary'} | ${true} | ${clickOnModalPrimaryBtn}
+ ${'cancel'} | ${false} | ${clickOnModalCancelBtn}
+ ${'close'} | ${false} | ${clickOnModalCloseBtn}
+ `(
+ 'clicking on $buttonName will pass down shouldTriggerActionClick as $shouldTriggerActionClick to the action component',
+ async ({ shouldTriggerActionClick, actionBtn }) => {
+ createWrapper({
+ props: {
+ skipRetryModal: false,
+ job: triggerJobWithRetryAction,
+ },
+ });
+ await findActionComponent().trigger('click');
+
+ await actionBtn();
+
+ expect(findActionComponent().props().shouldTriggerClick).toBe(shouldTriggerActionClick);
+ },
+ );
+ });
+
+ describe('when not checking the "do not show this again" checkbox', () => {
+ it.each`
+ actionName | actionBtn
+ ${'closing'} | ${clickOnModalCloseBtn}
+ ${'cancelling'} | ${clickOnModalCancelBtn}
+ ${'confirming'} | ${clickOnModalPrimaryBtn}
+ `(
+ 'does not emit any event and will not modify localstorage on $actionName',
+ async ({ actionBtn }) => {
+ createWrapper({
+ props: {
+ skipRetryModal: false,
+ job: triggerJobWithRetryAction,
+ },
+ });
+ await findActionComponent().trigger('click');
+ await actionBtn();
+
+ expect(wrapper.emitted().setSkipRetryModal).toBeUndefined();
+ expect(localStorage.setItem).not.toHaveBeenCalled();
+ },
+ );
+ });
+
+ describe('when checking the "do not show this again" checkbox', () => {
+ it.each`
+ actionName | actionBtn
+ ${'closing'} | ${clickOnModalCloseBtn}
+ ${'cancelling'} | ${clickOnModalCancelBtn}
+ ${'confirming'} | ${clickOnModalPrimaryBtn}
+ `(
+ 'emits "setSkipRetryModal" and set local storage key on $actionName the modal',
+ async ({ actionBtn }) => {
+ // We are passing the checkbox as a slot to the GlModal.
+ // The way GlModal is mounted, we can neither click on the box
+ // or emit an event directly. We therefore set the data property
+ // as it would be if the box was checked.
+ createWrapper({
+ data: {
+ currentSkipModalValue: true,
+ },
+ props: {
+ skipRetryModal: false,
+ job: triggerJobWithRetryAction,
+ },
+ });
+ await findActionComponent().trigger('click');
+ await actionBtn();
+
+ expect(wrapper.emitted().setSkipRetryModal).toHaveLength(1);
+ expect(localStorage.setItem).toHaveBeenCalledWith('skip_retry_modal', 'true');
+ },
+ );
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/job_name_component_spec.js b/spec/frontend/ci/pipeline_details/graph/components/job_name_component_spec.js
new file mode 100644
index 00000000000..ca201aee648
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/job_name_component_spec.js
@@ -0,0 +1,30 @@
+import { mount } from '@vue/test-utils';
+import jobNameComponent from '~/ci/common/private/job_name_component.vue';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+
+describe('job name component', () => {
+ let wrapper;
+
+ const propsData = {
+ name: 'foo',
+ status: {
+ icon: 'status_success',
+ group: 'success',
+ },
+ };
+
+ beforeEach(() => {
+ wrapper = mount(jobNameComponent, {
+ propsData,
+ });
+ });
+
+ it('should render the provided name', () => {
+ expect(wrapper.text()).toBe(propsData.name);
+ });
+
+ it('should render an icon with the provided status', () => {
+ expect(wrapper.findComponent(CiIcon).exists()).toBe(true);
+ expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/linked_pipeline_spec.js b/spec/frontend/ci/pipeline_details/graph/components/linked_pipeline_spec.js
new file mode 100644
index 00000000000..5541b0db54a
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/linked_pipeline_spec.js
@@ -0,0 +1,464 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlButton, GlLoadingIcon, GlTooltip } from '@gitlab/ui';
+import { createWrapper } from '@vue/test-utils';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
+import { ACTION_FAILURE, UPSTREAM, DOWNSTREAM } from '~/ci/pipeline_details/graph/constants';
+import LinkedPipelineComponent from '~/ci/pipeline_details/graph/components/linked_pipeline.vue';
+import CancelPipelineMutation from '~/ci/pipeline_details/graphql/mutations/cancel_pipeline.mutation.graphql';
+import RetryPipelineMutation from '~/ci/pipeline_details/graphql/mutations/retry_pipeline.mutation.graphql';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import mockPipeline from './linked_pipelines_mock_data';
+
+describe('Linked pipeline', () => {
+ let wrapper;
+ let requestHandlers;
+
+ const downstreamProps = {
+ pipeline: {
+ ...mockPipeline,
+ multiproject: false,
+ },
+ columnTitle: 'Downstream',
+ type: DOWNSTREAM,
+ expanded: false,
+ isLoading: false,
+ };
+
+ const upstreamProps = {
+ ...downstreamProps,
+ columnTitle: 'Upstream',
+ type: UPSTREAM,
+ };
+
+ const findButton = () => wrapper.findComponent(GlButton);
+ const findCancelButton = () => wrapper.findByLabelText('Cancel downstream pipeline');
+ const findCardTooltip = () => wrapper.findComponent(GlTooltip);
+ const findDownstreamPipelineTitle = () => wrapper.findByTestId('downstream-title');
+ const findExpandButton = () => wrapper.findByTestId('expand-pipeline-button');
+ const findLinkedPipeline = () => wrapper.findComponent({ ref: 'linkedPipeline' });
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findPipelineLabel = () => wrapper.findByTestId('downstream-pipeline-label');
+ const findPipelineLink = () => wrapper.findByTestId('pipelineLink');
+ const findRetryButton = () => wrapper.findByLabelText('Retry downstream pipeline');
+
+ const defaultHandlers = {
+ cancelPipeline: jest.fn().mockResolvedValue({ data: { pipelineCancel: { errors: [] } } }),
+ retryPipeline: jest.fn().mockResolvedValue({ data: { pipelineRetry: { errors: [] } } }),
+ };
+
+ const createMockApolloProvider = (handlers) => {
+ Vue.use(VueApollo);
+
+ requestHandlers = handlers;
+ return createMockApollo([
+ [CancelPipelineMutation, requestHandlers.cancelPipeline],
+ [RetryPipelineMutation, requestHandlers.retryPipeline],
+ ]);
+ };
+
+ const createComponent = ({ propsData, handlers = defaultHandlers }) => {
+ const mockApollo = createMockApolloProvider(handlers);
+
+ wrapper = mountExtended(LinkedPipelineComponent, {
+ propsData,
+ apolloProvider: mockApollo,
+ });
+ };
+
+ describe('rendered output', () => {
+ const props = {
+ pipeline: mockPipeline,
+ columnTitle: 'Downstream',
+ type: DOWNSTREAM,
+ expanded: false,
+ isLoading: false,
+ };
+
+ beforeEach(() => {
+ createComponent({ propsData: props });
+ });
+
+ it('should render the project name', () => {
+ expect(wrapper.text()).toContain(props.pipeline.project.name);
+ });
+
+ it('should render an svg within the status container', () => {
+ const pipelineStatusElement = wrapper.findComponent(CiIcon);
+
+ expect(pipelineStatusElement.find('svg').exists()).toBe(true);
+ });
+
+ it('should render the pipeline status icon svg', () => {
+ expect(wrapper.find('.ci-status-icon-success svg').exists()).toBe(true);
+ });
+
+ it('should have a ci-status child component', () => {
+ expect(wrapper.findComponent(CiIcon).exists()).toBe(true);
+ });
+
+ it('should render the pipeline id', () => {
+ expect(wrapper.text()).toContain(`#${props.pipeline.id}`);
+ });
+
+ it('adds the card tooltip text to the DOM', () => {
+ expect(findCardTooltip().exists()).toBe(true);
+
+ expect(findCardTooltip().text()).toContain(mockPipeline.project.name);
+ expect(findCardTooltip().text()).toContain(mockPipeline.status.label);
+ expect(findCardTooltip().text()).toContain(mockPipeline.sourceJob.name);
+ expect(findCardTooltip().text()).toContain(mockPipeline.id.toString());
+ });
+
+ it('should display multi-project label when pipeline project id is not the same as triggered pipeline project id', () => {
+ expect(findPipelineLabel().text()).toBe('Multi-project');
+ });
+ });
+
+ describe('upstream pipelines', () => {
+ beforeEach(() => {
+ createComponent({ propsData: upstreamProps });
+ });
+
+ it('should display parent label when pipeline project id is the same as triggered_by pipeline project id', () => {
+ expect(findPipelineLabel().exists()).toBe(true);
+ });
+
+ it('upstream pipeline should contain the correct link', () => {
+ expect(findPipelineLink().attributes('href')).toBe(upstreamProps.pipeline.path);
+ });
+
+ it('applies the reverse-row css class to the card', () => {
+ expect(findLinkedPipeline().classes()).toContain('gl-flex-direction-row-reverse');
+ expect(findLinkedPipeline().classes()).not.toContain('gl-flex-direction-row');
+ });
+ });
+
+ describe('downstream pipelines', () => {
+ describe('styling', () => {
+ beforeEach(() => {
+ createComponent({ propsData: downstreamProps });
+ });
+
+ it('parent/child label container should exist', () => {
+ expect(findPipelineLabel().exists()).toBe(true);
+ });
+
+ it('should display child label when pipeline project id is the same as triggered pipeline project id', () => {
+ expect(findPipelineLabel().exists()).toBe(true);
+ });
+
+ it('should have the name of the trigger job on the card when it is a child pipeline', () => {
+ expect(findDownstreamPipelineTitle().text()).toBe(mockPipeline.sourceJob.name);
+ });
+
+ it('downstream pipeline should contain the correct link', () => {
+ expect(findPipelineLink().attributes('href')).toBe(downstreamProps.pipeline.path);
+ });
+
+ it('applies the flex-row css class to the card', () => {
+ expect(findLinkedPipeline().classes()).toContain('gl-flex-direction-row');
+ expect(findLinkedPipeline().classes()).not.toContain('gl-flex-direction-row-reverse');
+ });
+ });
+
+ describe('action button', () => {
+ describe('with permissions', () => {
+ describe('on an upstream', () => {
+ describe('when retryable', () => {
+ beforeEach(() => {
+ const retryablePipeline = {
+ ...upstreamProps,
+ pipeline: { ...mockPipeline, retryable: true },
+ };
+
+ createComponent({ propsData: retryablePipeline });
+ });
+
+ it('does not show the retry or cancel button', () => {
+ expect(findCancelButton().exists()).toBe(false);
+ expect(findRetryButton().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('on a downstream', () => {
+ const retryablePipeline = {
+ ...downstreamProps,
+ pipeline: { ...mockPipeline, retryable: true },
+ };
+
+ describe('when retryable', () => {
+ beforeEach(() => {
+ createComponent({ propsData: retryablePipeline });
+ });
+
+ it('shows only the retry button', () => {
+ expect(findCancelButton().exists()).toBe(false);
+ expect(findRetryButton().exists()).toBe(true);
+ });
+
+ it.each`
+ findElement | name
+ ${findRetryButton} | ${'retry button'}
+ ${findExpandButton} | ${'expand button'}
+ `('hides the card tooltip when $name is hovered', async ({ findElement }) => {
+ expect(findCardTooltip().exists()).toBe(true);
+
+ await findElement().trigger('mouseover');
+
+ expect(findCardTooltip().exists()).toBe(false);
+ });
+
+ describe('and the retry button is clicked', () => {
+ describe('on success', () => {
+ beforeEach(async () => {
+ await findRetryButton().trigger('click');
+ });
+
+ it('calls the retry mutation', () => {
+ expect(requestHandlers.retryPipeline).toHaveBeenCalledTimes(1);
+ expect(requestHandlers.retryPipeline).toHaveBeenCalledWith({
+ id: 'gid://gitlab/Ci::Pipeline/195',
+ });
+ });
+
+ it('emits the refreshPipelineGraph event', async () => {
+ await waitForPromises();
+ expect(wrapper.emitted('refreshPipelineGraph')).toHaveLength(1);
+ });
+ });
+
+ describe('on failure', () => {
+ beforeEach(async () => {
+ createComponent({
+ propsData: retryablePipeline,
+ handlers: {
+ retryPipeline: jest.fn().mockRejectedValue({ errors: [] }),
+ cancelPipeline: jest.fn().mockRejectedValue({ errors: [] }),
+ },
+ });
+
+ await findRetryButton().trigger('click');
+ });
+
+ it('emits an error event', async () => {
+ await waitForPromises();
+ expect(wrapper.emitted('error')).toEqual([[{ type: ACTION_FAILURE }]]);
+ });
+ });
+ });
+ });
+
+ describe('when cancelable', () => {
+ const cancelablePipeline = {
+ ...downstreamProps,
+ pipeline: { ...mockPipeline, cancelable: true },
+ };
+
+ beforeEach(() => {
+ createComponent({ propsData: cancelablePipeline });
+ });
+
+ it('shows only the cancel button', () => {
+ expect(findCancelButton().exists()).toBe(true);
+ expect(findRetryButton().exists()).toBe(false);
+ });
+
+ it.each`
+ findElement | name
+ ${findCancelButton} | ${'cancel button'}
+ ${findExpandButton} | ${'expand button'}
+ `('hides the card tooltip when $name is hovered', async ({ findElement }) => {
+ expect(findCardTooltip().exists()).toBe(true);
+
+ await findElement().trigger('mouseover');
+
+ expect(findCardTooltip().exists()).toBe(false);
+ });
+
+ describe('and the cancel button is clicked', () => {
+ describe('on success', () => {
+ beforeEach(async () => {
+ await findCancelButton().trigger('click');
+ });
+
+ it('calls the cancel mutation', () => {
+ expect(requestHandlers.cancelPipeline).toHaveBeenCalledTimes(1);
+ expect(requestHandlers.cancelPipeline).toHaveBeenCalledWith({
+ id: 'gid://gitlab/Ci::Pipeline/195',
+ });
+ });
+ it('emits the refreshPipelineGraph event', async () => {
+ await waitForPromises();
+ expect(wrapper.emitted('refreshPipelineGraph')).toHaveLength(1);
+ });
+ });
+
+ describe('on failure', () => {
+ beforeEach(async () => {
+ createComponent({
+ propsData: cancelablePipeline,
+ handlers: {
+ retryPipeline: jest.fn().mockRejectedValue({ errors: [] }),
+ cancelPipeline: jest.fn().mockRejectedValue({ errors: [] }),
+ },
+ });
+
+ await findCancelButton().trigger('click');
+ });
+
+ it('emits an error event', async () => {
+ await waitForPromises();
+ expect(wrapper.emitted('error')).toEqual([[{ type: ACTION_FAILURE }]]);
+ });
+ });
+ });
+ });
+
+ describe('when both cancellable and retryable', () => {
+ beforeEach(() => {
+ const pipelineWithTwoActions = {
+ ...downstreamProps,
+ pipeline: { ...mockPipeline, cancelable: true, retryable: true },
+ };
+
+ createComponent({ propsData: pipelineWithTwoActions });
+ });
+
+ it('only shows the cancel button', () => {
+ expect(findRetryButton().exists()).toBe(false);
+ expect(findCancelButton().exists()).toBe(true);
+ });
+ });
+ });
+ });
+
+ describe('without permissions', () => {
+ beforeEach(() => {
+ const pipelineWithTwoActions = {
+ ...downstreamProps,
+ pipeline: {
+ ...mockPipeline,
+ cancelable: true,
+ retryable: true,
+ userPermissions: { updatePipeline: false },
+ },
+ };
+
+ createComponent({ propsData: pipelineWithTwoActions });
+ });
+
+ it('does not show any action button', () => {
+ expect(findRetryButton().exists()).toBe(false);
+ expect(findCancelButton().exists()).toBe(false);
+ });
+ });
+ });
+ });
+
+ describe('expand button', () => {
+ it.each`
+ pipelineType | chevronPosition | buttonBorderClasses | expanded
+ ${downstreamProps} | ${'chevron-lg-right'} | ${'gl-border-l-0!'} | ${false}
+ ${downstreamProps} | ${'chevron-lg-left'} | ${'gl-border-l-0!'} | ${true}
+ ${upstreamProps} | ${'chevron-lg-left'} | ${'gl-border-r-0!'} | ${false}
+ ${upstreamProps} | ${'chevron-lg-right'} | ${'gl-border-r-0!'} | ${true}
+ `(
+ '$pipelineType.columnTitle pipeline button icon should be $chevronPosition with $buttonBorderClasses if expanded state is $expanded',
+ ({ pipelineType, chevronPosition, buttonBorderClasses, expanded }) => {
+ createComponent({ propsData: { ...pipelineType, expanded } });
+ expect(findExpandButton().props('icon')).toBe(chevronPosition);
+ expect(findExpandButton().classes()).toContain(buttonBorderClasses);
+ },
+ );
+
+ describe('shadow border', () => {
+ beforeEach(() => {
+ createComponent({ propsData: downstreamProps });
+ });
+
+ it.each`
+ activateEventName | deactivateEventName
+ ${'mouseover'} | ${'mouseout'}
+ ${'focus'} | ${'blur'}
+ `(
+ 'applies the class on $activateEventName and removes it on $deactivateEventName',
+ async ({ activateEventName, deactivateEventName }) => {
+ const shadowClass = 'gl-shadow-none!';
+
+ expect(findExpandButton().classes()).toContain(shadowClass);
+
+ await findExpandButton().vm.$emit(activateEventName);
+ expect(findExpandButton().classes()).not.toContain(shadowClass);
+
+ await findExpandButton().vm.$emit(deactivateEventName);
+ expect(findExpandButton().classes()).toContain(shadowClass);
+ },
+ );
+ });
+ });
+
+ describe('when isLoading is true', () => {
+ const props = {
+ pipeline: mockPipeline,
+ columnTitle: 'Downstream',
+ type: DOWNSTREAM,
+ expanded: false,
+ isLoading: true,
+ };
+
+ beforeEach(() => {
+ createComponent({ propsData: props });
+ });
+
+ it('loading icon is visible', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('on click/hover', () => {
+ const props = {
+ pipeline: mockPipeline,
+ columnTitle: 'Downstream',
+ type: DOWNSTREAM,
+ expanded: false,
+ isLoading: false,
+ };
+
+ beforeEach(() => {
+ createComponent({ propsData: props });
+ });
+
+ it('emits `pipelineClicked` event', () => {
+ findButton().trigger('click');
+
+ expect(wrapper.emitted('pipelineClicked')).toHaveLength(1);
+ });
+
+ it(`should emit ${BV_HIDE_TOOLTIP} to close the tooltip`, async () => {
+ const root = createWrapper(wrapper.vm.$root);
+ await findButton().vm.$emit('click');
+
+ expect(root.emitted(BV_HIDE_TOOLTIP)).toHaveLength(1);
+ });
+
+ it('should emit downstreamHovered with job name on mouseover', () => {
+ findLinkedPipeline().trigger('mouseover');
+ expect(wrapper.emitted('downstreamHovered')).toStrictEqual([['test_c']]);
+ });
+
+ it('should emit downstreamHovered with empty string on mouseleave', () => {
+ findLinkedPipeline().trigger('mouseleave');
+ expect(wrapper.emitted('downstreamHovered')).toStrictEqual([['']]);
+ });
+
+ it('should emit pipelineExpanded with job name and expanded state on click', () => {
+ findExpandButton().trigger('click');
+ expect(wrapper.emitted('pipelineExpandToggle')).toStrictEqual([['test_c', true]]);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/linked_pipelines_column_spec.js b/spec/frontend/ci/pipeline_details/graph/components/linked_pipelines_column_spec.js
new file mode 100644
index 00000000000..30f05baceab
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/linked_pipelines_column_spec.js
@@ -0,0 +1,214 @@
+import { mount, shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
+import {
+ DOWNSTREAM,
+ UPSTREAM,
+ LAYER_VIEW,
+ STAGE_VIEW,
+} from '~/ci/pipeline_details/graph/constants';
+import PipelineGraph from '~/ci/pipeline_details/graph/components/graph_component.vue';
+import LinkedPipeline from '~/ci/pipeline_details/graph/components/linked_pipeline.vue';
+import LinkedPipelinesColumn from '~/ci/pipeline_details/graph/components/linked_pipelines_column.vue';
+import * as parsingUtils from '~/ci/pipeline_details/utils/parsing_utils';
+import { LOAD_FAILURE } from '~/ci/pipeline_details/constants';
+
+import { pipelineWithUpstreamDownstream, wrappedPipelineReturn } from '../mock_data';
+
+const processedPipeline = pipelineWithUpstreamDownstream(mockPipelineResponse);
+
+describe('Linked Pipelines Column', () => {
+ const defaultProps = {
+ columnTitle: 'Downstream',
+ linkedPipelines: processedPipeline.downstream,
+ showLinks: false,
+ type: DOWNSTREAM,
+ viewType: STAGE_VIEW,
+ configPaths: {
+ metricsPath: '',
+ graphqlResourceEtag: 'this/is/a/path',
+ },
+ };
+
+ let wrapper;
+ const findLinkedColumnTitle = () => wrapper.find('[data-testid="linked-column-title"]');
+ const findLinkedPipelineElements = () => wrapper.findAllComponents(LinkedPipeline);
+ const findPipelineGraph = () => wrapper.findComponent(PipelineGraph);
+ const findExpandButton = () => wrapper.find('[data-testid="expand-pipeline-button"]');
+
+ Vue.use(VueApollo);
+
+ const createComponent = ({ apolloProvider, mountFn = shallowMount, props = {} } = {}) => {
+ wrapper = mountFn(LinkedPipelinesColumn, {
+ apolloProvider,
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ const createComponentWithApollo = ({
+ mountFn = shallowMount,
+ getPipelineDetailsHandler = jest.fn().mockResolvedValue(wrappedPipelineReturn),
+ props = {},
+ } = {}) => {
+ const requestHandlers = [[getPipelineDetails, getPipelineDetailsHandler]];
+
+ const apolloProvider = createMockApollo(requestHandlers);
+ createComponent({ apolloProvider, mountFn, props });
+ };
+
+ describe('it renders correctly', () => {
+ beforeEach(() => {
+ createComponentWithApollo();
+ });
+
+ it('renders the pipeline title', () => {
+ expect(findLinkedColumnTitle().text()).toBe(defaultProps.columnTitle);
+ });
+
+ it('renders the correct number of linked pipelines', () => {
+ expect(findLinkedPipelineElements()).toHaveLength(defaultProps.linkedPipelines.length);
+ });
+ });
+
+ describe('click action', () => {
+ const clickExpandButton = async () => {
+ await findExpandButton().trigger('click');
+ await waitForPromises();
+ };
+
+ describe('layer type rendering', () => {
+ let layersFn;
+
+ beforeEach(() => {
+ layersFn = jest.spyOn(parsingUtils, 'listByLayers');
+ createComponentWithApollo({ mountFn: mount });
+ });
+
+ it('calls listByLayers only once no matter how many times view is switched', async () => {
+ expect(layersFn).not.toHaveBeenCalled();
+ await clickExpandButton();
+ await wrapper.setProps({ viewType: LAYER_VIEW });
+ await nextTick();
+ expect(layersFn).toHaveBeenCalledTimes(1);
+ await wrapper.setProps({ viewType: STAGE_VIEW });
+ await wrapper.setProps({ viewType: LAYER_VIEW });
+ await wrapper.setProps({ viewType: STAGE_VIEW });
+ expect(layersFn).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when graph does not use needs', () => {
+ beforeEach(() => {
+ const nonNeedsResponse = { ...wrappedPipelineReturn };
+ nonNeedsResponse.data.project.pipeline.usesNeeds = false;
+
+ createComponentWithApollo({
+ props: {
+ viewType: LAYER_VIEW,
+ },
+ getPipelineDetailsHandler: jest.fn().mockResolvedValue(nonNeedsResponse),
+ mountFn: mount,
+ });
+ });
+
+ it('shows the stage view, even when the main graph view type is layers', async () => {
+ await clickExpandButton();
+ expect(findPipelineGraph().props('viewType')).toBe(STAGE_VIEW);
+ });
+ });
+
+ describe('downstream', () => {
+ describe('when successful', () => {
+ beforeEach(() => {
+ createComponentWithApollo({ mountFn: mount });
+ });
+
+ it('toggles the pipeline visibility', async () => {
+ expect(findPipelineGraph().exists()).toBe(false);
+ await clickExpandButton();
+ expect(findPipelineGraph().exists()).toBe(true);
+ await clickExpandButton();
+ expect(findPipelineGraph().exists()).toBe(false);
+ });
+ });
+
+ describe('on error', () => {
+ beforeEach(() => {
+ createComponentWithApollo({
+ mountFn: mount,
+ getPipelineDetailsHandler: jest.fn().mockRejectedValue(new Error('GraphQL error')),
+ });
+ });
+
+ it('emits the error', async () => {
+ await clickExpandButton();
+ expect(wrapper.emitted().error).toEqual([[{ type: LOAD_FAILURE, skipSentry: true }]]);
+ });
+
+ it('does not show the pipeline', async () => {
+ expect(findPipelineGraph().exists()).toBe(false);
+ await clickExpandButton();
+ expect(findPipelineGraph().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('upstream', () => {
+ const upstreamProps = {
+ columnTitle: 'Upstream',
+ /*
+ Because the IDs need to match to work, rather
+ than make new mock data, we are representing
+ the upstream pipeline with the downstream data.
+ */
+ linkedPipelines: processedPipeline.downstream,
+ type: UPSTREAM,
+ };
+
+ describe('when successful', () => {
+ beforeEach(() => {
+ createComponentWithApollo({
+ mountFn: mount,
+ props: upstreamProps,
+ });
+ });
+
+ it('toggles the pipeline visibility', async () => {
+ expect(findPipelineGraph().exists()).toBe(false);
+ await clickExpandButton();
+ expect(findPipelineGraph().exists()).toBe(true);
+ await clickExpandButton();
+ expect(findPipelineGraph().exists()).toBe(false);
+ });
+ });
+
+ describe('on error', () => {
+ beforeEach(() => {
+ createComponentWithApollo({
+ mountFn: mount,
+ getPipelineDetailsHandler: jest.fn().mockRejectedValue(new Error('GraphQL error')),
+ props: upstreamProps,
+ });
+ });
+
+ it('emits the error', async () => {
+ await clickExpandButton();
+ expect(wrapper.emitted().error).toEqual([[{ type: LOAD_FAILURE, skipSentry: true }]]);
+ });
+
+ it('does not show the pipeline', async () => {
+ expect(findPipelineGraph().exists()).toBe(false);
+ await clickExpandButton();
+ expect(findPipelineGraph().exists()).toBe(false);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/pipelines/graph/linked_pipelines_mock_data.js b/spec/frontend/ci/pipeline_details/graph/components/linked_pipelines_mock_data.js
index f7f5738e46d..f7f5738e46d 100644
--- a/spec/frontend/pipelines/graph/linked_pipelines_mock_data.js
+++ b/spec/frontend/ci/pipeline_details/graph/components/linked_pipelines_mock_data.js
diff --git a/spec/frontend/ci/pipeline_details/graph/components/links_inner_spec.js b/spec/frontend/ci/pipeline_details/graph/components/links_inner_spec.js
new file mode 100644
index 00000000000..655b2ac74ac
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/links_inner_spec.js
@@ -0,0 +1,223 @@
+import { shallowMount } from '@vue/test-utils';
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import LinksInner from '~/ci/pipeline_details/graph/components/links_inner.vue';
+import { parseData } from '~/ci/pipeline_details/utils/parsing_utils';
+import { createJobsHash } from '~/ci/pipeline_details/utils';
+import {
+ jobRect,
+ largePipelineData,
+ parallelNeedData,
+ pipelineData,
+ pipelineDataWithNoNeeds,
+ rootRect,
+ sameStageNeeds,
+} from 'jest/ci/pipeline_editor/components/graph/mock_data';
+
+describe('Links Inner component', () => {
+ const containerId = 'pipeline-graph-container';
+ const defaultProps = {
+ containerId,
+ containerMeasurements: { width: 1019, height: 445 },
+ pipelineId: 1,
+ pipelineData: [],
+ totalGroups: 10,
+ };
+
+ let wrapper;
+
+ const createComponent = (props) => {
+ const currentPipelineData = props?.pipelineData || defaultProps.pipelineData;
+ wrapper = shallowMount(LinksInner, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ linksData: parseData(currentPipelineData.flatMap(({ groups }) => groups)).links,
+ },
+ });
+ };
+
+ const findLinkSvg = () => wrapper.find('#link-svg');
+ const findAllLinksPath = () => findLinkSvg().findAll('path');
+
+ // We create fixture so that each job has an empty div that represent
+ // the JobPill in the DOM. Each `JobPill` would have different coordinates,
+ // so we increment their coordinates on each iteration to simulate different positions.
+ const setHTMLFixtureLocal = ({ stages }) => {
+ const jobs = createJobsHash(stages);
+ const arrayOfJobs = Object.keys(jobs);
+
+ const linksHtmlElements = arrayOfJobs.map((job) => {
+ return `<div id=${job}-${defaultProps.pipelineId} />`;
+ });
+
+ setHTMLFixture(`<div id="${containerId}">${linksHtmlElements.join(' ')}</div>`);
+
+ // We are mocking the clientRect data of each job and the container ID.
+ jest
+ .spyOn(document.getElementById(containerId), 'getBoundingClientRect')
+ .mockImplementation(() => rootRect);
+
+ arrayOfJobs.forEach((job, index) => {
+ jest
+ .spyOn(
+ document.getElementById(`${job}-${defaultProps.pipelineId}`),
+ 'getBoundingClientRect',
+ )
+ .mockImplementation(() => {
+ const newValue = 10 * index;
+ const { left, right, top, bottom, x, y } = jobRect;
+ return {
+ ...jobRect,
+ left: left + newValue,
+ right: right + newValue,
+ top: top + newValue,
+ bottom: bottom + newValue,
+ x: x + newValue,
+ y: y + newValue,
+ };
+ });
+ });
+ };
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ describe('basic SVG creation', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders an SVG of the right size', () => {
+ expect(findLinkSvg().exists()).toBe(true);
+ expect(findLinkSvg().attributes('width')).toBe(
+ `${defaultProps.containerMeasurements.width}px`,
+ );
+ expect(findLinkSvg().attributes('height')).toBe(
+ `${defaultProps.containerMeasurements.height}px`,
+ );
+ });
+ });
+
+ describe('no pipeline data', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the component', () => {
+ expect(findLinkSvg().exists()).toBe(true);
+ expect(findAllLinksPath()).toHaveLength(0);
+ });
+ });
+
+ describe('pipeline data with no needs', () => {
+ beforeEach(() => {
+ createComponent({ pipelineData: pipelineDataWithNoNeeds.stages });
+ });
+
+ it('renders no links', () => {
+ expect(findLinkSvg().exists()).toBe(true);
+ expect(findAllLinksPath()).toHaveLength(0);
+ });
+ });
+
+ describe('with one need', () => {
+ beforeEach(() => {
+ setHTMLFixtureLocal(pipelineData);
+ createComponent({ pipelineData: pipelineData.stages });
+ });
+
+ it('renders one link', () => {
+ expect(findAllLinksPath()).toHaveLength(1);
+ });
+
+ it('path does not contain NaN values', () => {
+ expect(wrapper.html()).not.toContain('NaN');
+ });
+
+ it('matches snapshot and has expected path', () => {
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+
+ describe('with a parallel need', () => {
+ beforeEach(() => {
+ setHTMLFixtureLocal(parallelNeedData);
+ createComponent({ pipelineData: parallelNeedData.stages });
+ });
+
+ it('renders only one link for all the same parallel jobs', () => {
+ expect(findAllLinksPath()).toHaveLength(1);
+ });
+
+ it('path does not contain NaN values', () => {
+ expect(wrapper.html()).not.toContain('NaN');
+ });
+
+ it('matches snapshot and has expected path', () => {
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+
+ describe('with same stage needs', () => {
+ beforeEach(() => {
+ setHTMLFixtureLocal(sameStageNeeds);
+ createComponent({ pipelineData: sameStageNeeds.stages });
+ });
+
+ it('renders the correct number of links', () => {
+ expect(findAllLinksPath()).toHaveLength(2);
+ });
+
+ it('path does not contain NaN values', () => {
+ expect(wrapper.html()).not.toContain('NaN');
+ });
+
+ it('matches snapshot and has expected path', () => {
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+
+ describe('with a large number of needs', () => {
+ beforeEach(() => {
+ setHTMLFixtureLocal(largePipelineData);
+ createComponent({ pipelineData: largePipelineData.stages });
+ });
+
+ it('renders the correct number of links', () => {
+ expect(findAllLinksPath()).toHaveLength(5);
+ });
+
+ it('path does not contain NaN values', () => {
+ expect(wrapper.html()).not.toContain('NaN');
+ });
+
+ it('matches snapshot and has expected path', () => {
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+
+ describe('interactions', () => {
+ beforeEach(() => {
+ setHTMLFixtureLocal(largePipelineData);
+ createComponent({ pipelineData: largePipelineData.stages });
+ });
+
+ it('highlight needs on hover', async () => {
+ const firstLink = findAllLinksPath().at(0);
+
+ const defaultColorClass = 'gl-stroke-gray-200';
+ const hoverColorClass = 'gl-stroke-blue-400';
+
+ expect(firstLink.classes(defaultColorClass)).toBe(true);
+ expect(firstLink.classes(hoverColorClass)).toBe(false);
+
+ // Because there is a watcher, we need to set the props after the component
+ // has mounted.
+ await wrapper.setProps({ highlightedJob: 'test_1' });
+
+ expect(firstLink.classes(defaultColorClass)).toBe(false);
+ expect(firstLink.classes(hoverColorClass)).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/components/stage_column_component_spec.js b/spec/frontend/ci/pipeline_details/graph/components/stage_column_component_spec.js
new file mode 100644
index 00000000000..cc79205ec41
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/components/stage_column_component_spec.js
@@ -0,0 +1,228 @@
+import { mount, shallowMount } from '@vue/test-utils';
+import JobItem from '~/ci/pipeline_details/graph/components/job_item.vue';
+import StageColumnComponent from '~/ci/pipeline_details/graph/components/stage_column_component.vue';
+import ActionComponent from '~/ci/common/private/job_action_component.vue';
+
+const mockJob = {
+ id: 4250,
+ name: 'test',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ details_path: '/root/ci-mock/builds/4250',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/root/ci-mock/builds/4250/retry',
+ method: 'post',
+ },
+ },
+};
+
+const mockGroups = Array(4)
+ .fill(0)
+ .map((item, idx) => {
+ return { ...mockJob, jobs: [mockJob], id: idx, name: `fish-${idx}` };
+ });
+
+const defaultProps = {
+ name: 'Fish',
+ groups: mockGroups,
+ pipelineId: 159,
+ userPermissions: {
+ updatePipeline: true,
+ },
+};
+
+describe('stage column component', () => {
+ let wrapper;
+
+ const findStageColumnTitle = () => wrapper.find('[data-testid="stage-column-title"]');
+ const findStageColumnGroup = () => wrapper.find('[data-testid="stage-column-group"]');
+ const findAllStageColumnGroups = () => wrapper.findAll('[data-testid="stage-column-group"]');
+ const findJobItem = () => wrapper.findComponent(JobItem);
+ const findActionComponent = () => wrapper.findComponent(ActionComponent);
+
+ const createComponent = ({ method = shallowMount, props = {} } = {}) => {
+ wrapper = method(StageColumnComponent, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ describe('when mounted', () => {
+ beforeEach(() => {
+ createComponent({ method: mount });
+ });
+
+ it('should render provided title', () => {
+ expect(findStageColumnTitle().text()).toBe(defaultProps.name);
+ });
+
+ it('should render the provided groups', () => {
+ expect(findAllStageColumnGroups().length).toBe(mockGroups.length);
+ });
+
+ it('should emit updateMeasurements event on mount', () => {
+ expect(wrapper.emitted().updateMeasurements).toHaveLength(1);
+ });
+ });
+
+ describe('when job notifies action is complete', () => {
+ beforeEach(() => {
+ createComponent({
+ method: mount,
+ props: {
+ groups: [
+ {
+ title: 'Fish',
+ size: 1,
+ jobs: [mockJob],
+ },
+ ],
+ },
+ });
+ findJobItem().vm.$emit('pipelineActionRequestComplete');
+ });
+
+ it('emits refreshPipelineGraph', () => {
+ expect(wrapper.emitted().refreshPipelineGraph).toHaveLength(1);
+ });
+ });
+
+ describe('job', () => {
+ describe('text handling', () => {
+ beforeEach(() => {
+ createComponent({
+ method: mount,
+ props: {
+ groups: [
+ {
+ ...mockJob,
+ name: '<img src=x onerror=alert(document.domain)>',
+ jobs: [
+ {
+ id: 4259,
+ name: '<img src=x onerror=alert(document.domain)>',
+ status: {
+ icon: 'status_success',
+ label: 'success',
+ tooltip: '<img src=x onerror=alert(document.domain)>',
+ },
+ },
+ ],
+ },
+ ],
+ name: 'test <img src=x onerror=alert(document.domain)>',
+ },
+ });
+ });
+
+ it('escapes name', () => {
+ expect(findStageColumnTitle().html()).toContain(
+ 'test &lt;img src=x onerror=alert(document.domain)&gt;',
+ );
+ });
+
+ it('escapes id', () => {
+ expect(findStageColumnGroup().attributes('id')).toBe(
+ 'ci-badge-&lt;img src=x onerror=alert(document.domain)&gt;',
+ );
+ });
+ });
+
+ describe('interactions', () => {
+ beforeEach(() => {
+ createComponent({ method: mount });
+ });
+
+ it('emits jobHovered event on mouseenter and mouseleave', async () => {
+ await findStageColumnGroup().trigger('mouseenter');
+ expect(wrapper.emitted().jobHover).toEqual([[defaultProps.groups[0].name]]);
+ await findStageColumnGroup().trigger('mouseleave');
+ expect(wrapper.emitted().jobHover).toEqual([[defaultProps.groups[0].name], ['']]);
+ });
+ });
+ });
+
+ describe('with action', () => {
+ const defaults = {
+ groups: [
+ {
+ id: 4259,
+ name: '<img src=x onerror=alert(document.domain)>',
+ status: {
+ icon: 'status_success',
+ label: 'success',
+ tooltip: '<img src=x onerror=alert(document.domain)>',
+ },
+ jobs: [mockJob],
+ },
+ ],
+ title: 'test',
+ hasTriggeredBy: false,
+ action: {
+ icon: 'play',
+ title: 'Play all',
+ path: 'action',
+ },
+ };
+
+ it('renders action button if permissions are permitted', () => {
+ createComponent({
+ method: mount,
+ props: {
+ ...defaults,
+ },
+ });
+
+ expect(findActionComponent().exists()).toBe(true);
+ });
+
+ it('does not render action button if permissions are not permitted', () => {
+ createComponent({
+ method: mount,
+ props: {
+ ...defaults,
+ userPermissions: {
+ updatePipeline: false,
+ },
+ },
+ });
+
+ expect(findActionComponent().exists()).toBe(false);
+ });
+ });
+
+ describe('without action', () => {
+ beforeEach(() => {
+ createComponent({
+ method: mount,
+ props: {
+ groups: [
+ {
+ id: 4259,
+ name: '<img src=x onerror=alert(document.domain)>',
+ status: {
+ icon: 'status_success',
+ label: 'success',
+ tooltip: '<img src=x onerror=alert(document.domain)>',
+ },
+ jobs: [mockJob],
+ },
+ ],
+ title: 'test',
+ hasTriggeredBy: false,
+ },
+ });
+ });
+
+ it('does not render action button', () => {
+ expect(findActionComponent().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/graph_component_wrapper_spec.js b/spec/frontend/ci/pipeline_details/graph/graph_component_wrapper_spec.js
new file mode 100644
index 00000000000..372ed2a4e1c
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/graph_component_wrapper_spec.js
@@ -0,0 +1,603 @@
+import { GlAlert, GlButton, GlButtonGroup, GlLoadingIcon, GlToggle } from '@gitlab/ui';
+import MockAdapter from 'axios-mock-adapter';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { stubPerformanceWebAPI } from 'helpers/performance';
+import waitForPromises from 'helpers/wait_for_promises';
+import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
+import getUserCallouts from '~/graphql_shared/queries/get_user_callouts.query.graphql';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import {
+ PIPELINES_DETAIL_LINK_DURATION,
+ PIPELINES_DETAIL_LINKS_TOTAL,
+ PIPELINES_DETAIL_LINKS_JOB_RATIO,
+} from '~/performance/constants';
+import * as perfUtils from '~/performance/utils';
+import {
+ ACTION_FAILURE,
+ LAYER_VIEW,
+ STAGE_VIEW,
+ VIEW_TYPE_KEY,
+} from '~/ci/pipeline_details/graph/constants';
+import PipelineGraph from '~/ci/pipeline_details/graph/components/graph_component.vue';
+import PipelineGraphWrapper from '~/ci/pipeline_details/graph/graph_component_wrapper.vue';
+import GraphViewSelector from '~/ci/pipeline_details/graph/components/graph_view_selector.vue';
+import * as Api from '~/ci/pipeline_details/graph/api_utils';
+import LinksLayer from '~/ci/common/private/job_links_layer.vue';
+import * as parsingUtils from '~/ci/pipeline_details/utils/parsing_utils';
+import getPipelineHeaderData from '~/ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql';
+import * as sentryUtils from '~/ci/utils';
+import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
+import { mockRunningPipelineHeaderData } from '../mock_data';
+import {
+ mapCallouts,
+ mockCalloutsResponse,
+ mockPipelineResponseWithTooManyJobs,
+} from './mock_data';
+
+const defaultProvide = {
+ graphqlResourceEtag: 'frog/amphibirama/etag/',
+ metricsPath: '',
+ pipelineProjectPath: 'frog/amphibirama',
+ pipelineIid: '22',
+};
+
+describe('Pipeline graph wrapper', () => {
+ Vue.use(VueApollo);
+ useLocalStorageSpy();
+
+ let wrapper;
+ let requestHandlers;
+ let pipelineDetailsHandler;
+
+ const findAlert = () => wrapper.findByTestId('error-alert');
+ const findJobCountWarning = () => wrapper.findByTestId('job-count-warning');
+ const findDependenciesToggle = () => wrapper.findByTestId('show-links-toggle');
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findLinksLayer = () => wrapper.findComponent(LinksLayer);
+ const findGraph = () => wrapper.findComponent(PipelineGraph);
+ const findStageColumnTitle = () => wrapper.findByTestId('stage-column-title');
+ const findViewSelector = () => wrapper.findComponent(GraphViewSelector);
+ const findViewSelectorToggle = () => findViewSelector().findComponent(GlToggle);
+ const findViewSelectorTrip = () => findViewSelector().findComponent(GlAlert);
+ const getLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
+
+ const createComponent = ({
+ apolloProvider,
+ data = {},
+ provide = {},
+ mountFn = shallowMountExtended,
+ } = {}) => {
+ wrapper = mountFn(PipelineGraphWrapper, {
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ apolloProvider,
+ data() {
+ return {
+ ...data,
+ };
+ },
+ });
+ };
+
+ const createComponentWithApollo = ({
+ calloutsList = [],
+ data = {},
+ mountFn = shallowMountExtended,
+ provide = {},
+ } = {}) => {
+ const callouts = mapCallouts(calloutsList);
+
+ requestHandlers = {
+ getUserCalloutsHandler: jest.fn().mockResolvedValue(mockCalloutsResponse(callouts)),
+ getPipelineHeaderDataHandler: jest.fn().mockResolvedValue(mockRunningPipelineHeaderData),
+ getPipelineDetailsHandler: pipelineDetailsHandler,
+ };
+
+ const handlers = [
+ [getPipelineHeaderData, requestHandlers.getPipelineHeaderDataHandler],
+ [getPipelineDetails, requestHandlers.getPipelineDetailsHandler],
+ [getUserCallouts, requestHandlers.getUserCalloutsHandler],
+ ];
+
+ const apolloProvider = createMockApollo(handlers);
+ createComponent({ apolloProvider, data, provide, mountFn });
+ };
+
+ beforeEach(() => {
+ pipelineDetailsHandler = jest.fn();
+ pipelineDetailsHandler.mockResolvedValue(mockPipelineResponse);
+ });
+
+ describe('when data is loading', () => {
+ beforeEach(() => {
+ createComponentWithApollo();
+ });
+
+ it('displays the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('does not display the alert', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('does not display the graph', () => {
+ expect(findGraph().exists()).toBe(false);
+ });
+
+ it('skips querying headerPipeline', () => {
+ expect(wrapper.vm.$apollo.queries.headerPipeline.skip).toBe(true);
+ });
+ });
+
+ describe('when data has loaded', () => {
+ beforeEach(async () => {
+ createComponentWithApollo();
+ await waitForPromises();
+ });
+
+ it('does not display the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('does not display the alert', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('displays the graph', () => {
+ expect(findGraph().exists()).toBe(true);
+ });
+
+ it('passes the etag resource and metrics path to the graph', () => {
+ expect(findGraph().props('configPaths')).toMatchObject({
+ graphqlResourceEtag: defaultProvide.graphqlResourceEtag,
+ metricsPath: defaultProvide.metricsPath,
+ });
+ });
+ });
+
+ describe('when a stage has 100 jobs or more', () => {
+ beforeEach(async () => {
+ pipelineDetailsHandler.mockResolvedValue(mockPipelineResponseWithTooManyJobs);
+ createComponentWithApollo();
+ await waitForPromises();
+ });
+
+ it('show a warning alert', () => {
+ expect(findJobCountWarning().exists()).toBe(true);
+ expect(findJobCountWarning().props().title).toBe(
+ 'Only the first 100 jobs per stage are displayed',
+ );
+ });
+ });
+
+ describe('when there is an error', () => {
+ beforeEach(async () => {
+ pipelineDetailsHandler.mockRejectedValue(new Error('GraphQL error'));
+ createComponentWithApollo();
+ await waitForPromises();
+ });
+
+ it('does not display the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('displays the alert', () => {
+ expect(findAlert().exists()).toBe(true);
+ });
+
+ it('does not display the graph', () => {
+ expect(findGraph().exists()).toBe(false);
+ });
+ });
+
+ describe('when there is no pipeline iid available', () => {
+ beforeEach(async () => {
+ createComponentWithApollo({
+ provide: {
+ pipelineIid: '',
+ },
+ });
+ await waitForPromises();
+ });
+
+ it('does not display the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('displays the no iid alert', () => {
+ expect(findAlert().exists()).toBe(true);
+ expect(findAlert().text()).toBe(
+ 'The data in this pipeline is too old to be rendered as a graph. Please check the Jobs tab to access historical data.',
+ );
+ });
+
+ it('does not display the graph', () => {
+ expect(findGraph().exists()).toBe(false);
+ });
+ });
+
+ describe('events', () => {
+ beforeEach(async () => {
+ createComponentWithApollo();
+ await waitForPromises();
+ });
+ describe('when receiving `setSkipRetryModal` event', () => {
+ it('passes down `skipRetryModal` value as true', async () => {
+ expect(findGraph().props('skipRetryModal')).toBe(false);
+
+ await findGraph().vm.$emit('setSkipRetryModal');
+
+ expect(findGraph().props('skipRetryModal')).toBe(true);
+ });
+ });
+ });
+
+ describe('when there is an error with an action in the graph', () => {
+ beforeEach(async () => {
+ createComponentWithApollo();
+ await waitForPromises();
+ await findGraph().vm.$emit('error', { type: ACTION_FAILURE });
+ });
+
+ it('does not display the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('displays the action error alert', () => {
+ expect(findAlert().exists()).toBe(true);
+ expect(findAlert().text()).toBe('An error occurred while performing this action.');
+ });
+
+ it('displays the graph', () => {
+ expect(findGraph().exists()).toBe(true);
+ });
+ });
+
+ describe('when refresh action is emitted', () => {
+ beforeEach(async () => {
+ createComponentWithApollo();
+ await waitForPromises();
+ findGraph().vm.$emit('refreshPipelineGraph');
+ });
+
+ it('calls refetch', () => {
+ expect(requestHandlers.getPipelineHeaderDataHandler).toHaveBeenCalledWith({
+ fullPath: 'frog/amphibirama',
+ iid: '22',
+ });
+ expect(requestHandlers.getPipelineDetailsHandler).toHaveBeenCalledTimes(2);
+ expect(requestHandlers.getUserCalloutsHandler).toHaveBeenCalledWith({});
+ });
+ });
+
+ describe('when query times out', () => {
+ const advanceApolloTimers = async () => {
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+ };
+
+ beforeEach(async () => {
+ const errorData = {
+ data: {
+ project: {
+ pipelines: null,
+ },
+ },
+ errors: [{ message: 'timeout' }],
+ };
+
+ pipelineDetailsHandler
+ .mockResolvedValueOnce(errorData)
+ .mockResolvedValueOnce(mockPipelineResponse)
+ .mockResolvedValueOnce(errorData);
+
+ createComponentWithApollo();
+ await waitForPromises();
+ });
+
+ it('shows correct errors and does not overwrite populated data when data is empty', async () => {
+ /* fails at first, shows error, no data yet */
+ expect(findAlert().exists()).toBe(true);
+ expect(findGraph().exists()).toBe(false);
+
+ /* succeeds, clears error, shows graph */
+ await advanceApolloTimers();
+ expect(findAlert().exists()).toBe(false);
+ expect(findGraph().exists()).toBe(true);
+
+ /* fails again, alert returns but data persists */
+ await advanceApolloTimers();
+ expect(findAlert().exists()).toBe(true);
+ expect(findGraph().exists()).toBe(true);
+ });
+ });
+
+ describe('view dropdown', () => {
+ describe('default', () => {
+ let layersFn;
+ beforeEach(async () => {
+ layersFn = jest.spyOn(parsingUtils, 'listByLayers');
+ createComponentWithApollo({
+ mountFn: mountExtended,
+ });
+
+ await waitForPromises();
+ });
+
+ it('appears when pipeline uses needs', () => {
+ expect(findViewSelector().exists()).toBe(true);
+ });
+
+ it('switches between views', async () => {
+ expect(findStageColumnTitle().text()).toBe('deploy');
+
+ await findViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
+
+ expect(findStageColumnTitle().text()).toBe('');
+ });
+
+ it('saves the view type to local storage', async () => {
+ await findViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
+ expect(localStorage.setItem.mock.calls).toEqual([[VIEW_TYPE_KEY, LAYER_VIEW]]);
+ });
+
+ it('calls listByLayers only once no matter how many times view is switched', async () => {
+ expect(layersFn).not.toHaveBeenCalled();
+ await findViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
+ expect(layersFn).toHaveBeenCalledTimes(1);
+ await findViewSelector().vm.$emit('updateViewType', STAGE_VIEW);
+ await findViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
+ await findViewSelector().vm.$emit('updateViewType', STAGE_VIEW);
+ expect(layersFn).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when layers view is selected', () => {
+ beforeEach(async () => {
+ createComponentWithApollo({
+ data: {
+ currentViewType: LAYER_VIEW,
+ },
+ mountFn: mountExtended,
+ });
+
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+ });
+
+ it('sets showLinks to true', async () => {
+ /* This spec uses .props for performance reasons. */
+ expect(findLinksLayer().exists()).toBe(true);
+ expect(findLinksLayer().props('showLinks')).toBe(false);
+ expect(findViewSelector().props('type')).toBe(LAYER_VIEW);
+ await findDependenciesToggle().vm.$emit('change', true);
+
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+ expect(wrapper.findComponent(LinksLayer).props('showLinks')).toBe(true);
+ });
+ });
+
+ describe('when layers view is selected, and links are active', () => {
+ beforeEach(async () => {
+ createComponentWithApollo({
+ data: {
+ currentViewType: LAYER_VIEW,
+ showLinks: true,
+ },
+ mountFn: mountExtended,
+ });
+
+ await waitForPromises();
+ });
+
+ it('shows the hover tip in the view selector', async () => {
+ await findViewSelectorToggle().vm.$emit('change', true);
+ expect(findViewSelectorTrip().exists()).toBe(true);
+ });
+ });
+
+ describe('when hover tip would otherwise show, but it has been previously dismissed', () => {
+ beforeEach(async () => {
+ createComponentWithApollo({
+ data: {
+ currentViewType: LAYER_VIEW,
+ showLinks: true,
+ },
+ mountFn: mountExtended,
+ calloutsList: ['pipeline_needs_hover_tip'.toUpperCase()],
+ });
+
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+ });
+
+ it('does not show the hover tip', async () => {
+ await findViewSelectorToggle().vm.$emit('change', true);
+ expect(findViewSelectorTrip().exists()).toBe(false);
+ });
+ });
+
+ describe('when feature flag is on and local storage is set', () => {
+ beforeEach(async () => {
+ localStorage.setItem(VIEW_TYPE_KEY, LAYER_VIEW);
+
+ createComponentWithApollo({
+ mountFn: mountExtended,
+ });
+
+ await waitForPromises();
+ });
+
+ afterEach(() => {
+ localStorage.clear();
+ });
+
+ it('sets the asString prop on the LocalStorageSync component', () => {
+ expect(getLocalStorageSync().props('asString')).toBe(true);
+ });
+
+ it('reads the view type from localStorage when available', () => {
+ const viewSelectorNeedsSegment = wrapper
+ .findComponent(GlButtonGroup)
+ .findAllComponents(GlButton)
+ .at(1);
+ expect(viewSelectorNeedsSegment.classes()).toContain('selected');
+ });
+ });
+
+ describe('when feature flag is on and local storage is set, but the graph does not use needs', () => {
+ beforeEach(async () => {
+ const nonNeedsResponse = { ...mockPipelineResponse };
+ nonNeedsResponse.data.project.pipeline.usesNeeds = false;
+
+ localStorage.setItem(VIEW_TYPE_KEY, LAYER_VIEW);
+
+ pipelineDetailsHandler.mockResolvedValue(nonNeedsResponse);
+ createComponentWithApollo({
+ mountFn: mountExtended,
+ });
+
+ await waitForPromises();
+ });
+
+ afterEach(() => {
+ localStorage.clear();
+ });
+
+ it('still passes stage type to graph', () => {
+ expect(findGraph().props('viewType')).toBe(STAGE_VIEW);
+ });
+ });
+
+ describe('when feature flag is on but pipeline does not use needs', () => {
+ beforeEach(async () => {
+ const nonNeedsResponse = { ...mockPipelineResponse };
+ nonNeedsResponse.data.project.pipeline.usesNeeds = false;
+
+ pipelineDetailsHandler.mockResolvedValue(nonNeedsResponse);
+ createComponentWithApollo({
+ mountFn: mountExtended,
+ });
+
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+ });
+
+ it('does not appear when pipeline does not use needs', () => {
+ expect(findViewSelector().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('performance metrics', () => {
+ const metricsPath = '/root/project/-/ci/prometheus_metrics/histograms.json';
+ let markAndMeasure;
+ let reportToSentry;
+ let reportPerformance;
+ let mock;
+
+ beforeEach(() => {
+ jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => cb());
+ markAndMeasure = jest.spyOn(perfUtils, 'performanceMarkAndMeasure');
+ reportToSentry = jest.spyOn(sentryUtils, 'reportToSentry');
+ reportPerformance = jest.spyOn(Api, 'reportPerformance');
+ });
+
+ describe('with no metrics path', () => {
+ beforeEach(async () => {
+ createComponentWithApollo();
+ await waitForPromises();
+ });
+
+ it('is not called', () => {
+ expect(markAndMeasure).not.toHaveBeenCalled();
+ expect(reportToSentry).not.toHaveBeenCalled();
+ expect(reportPerformance).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('with metrics path', () => {
+ const duration = 500;
+ const numLinks = 3;
+ const totalGroups = 7;
+ const metricsData = {
+ histograms: [
+ { name: PIPELINES_DETAIL_LINK_DURATION, value: duration / 1000 },
+ { name: PIPELINES_DETAIL_LINKS_TOTAL, value: numLinks },
+ {
+ name: PIPELINES_DETAIL_LINKS_JOB_RATIO,
+ value: numLinks / totalGroups,
+ },
+ ],
+ };
+
+ describe('when no duration is obtained', () => {
+ beforeEach(async () => {
+ stubPerformanceWebAPI();
+
+ createComponentWithApollo({
+ provide: {
+ metricsPath,
+ glFeatures: {
+ pipelineGraphLayersView: true,
+ },
+ },
+ data: {
+ currentViewType: LAYER_VIEW,
+ },
+ });
+
+ await waitForPromises();
+ });
+
+ it('attempts to collect metrics', () => {
+ expect(markAndMeasure).toHaveBeenCalled();
+ expect(reportPerformance).not.toHaveBeenCalled();
+ expect(reportToSentry).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('with duration and no error', () => {
+ beforeEach(async () => {
+ mock = new MockAdapter(axios);
+ mock.onPost(metricsPath).reply(HTTP_STATUS_OK, {});
+
+ jest.spyOn(window.performance, 'getEntriesByName').mockImplementation(() => {
+ return [{ duration }];
+ });
+
+ createComponentWithApollo({
+ provide: {
+ metricsPath,
+ },
+ data: {
+ currentViewType: LAYER_VIEW,
+ },
+ });
+ await waitForPromises();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('calls reportPerformance with expected arguments', () => {
+ expect(markAndMeasure).toHaveBeenCalled();
+ expect(reportPerformance).toHaveBeenCalled();
+ expect(reportPerformance).toHaveBeenCalledWith(metricsPath, metricsData);
+ expect(reportToSentry).not.toHaveBeenCalled();
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/graph/mock_data.js b/spec/frontend/ci/pipeline_details/graph/mock_data.js
new file mode 100644
index 00000000000..a880a9cf4b0
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/graph/mock_data.js
@@ -0,0 +1,383 @@
+import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
+import { unwrapPipelineData } from '~/ci/pipeline_details/graph/utils';
+import { BUILD_KIND, BRIDGE_KIND, RETRY_ACTION_TITLE } from '~/ci/pipeline_details/graph/constants';
+
+// We mock this instead of using fixtures for performance reason.
+const mockPipelineResponseCopy = JSON.parse(JSON.stringify(mockPipelineResponse));
+const groups = new Array(100).fill({
+ ...mockPipelineResponse.data.project.pipeline.stages.nodes[0].groups.nodes[0],
+});
+mockPipelineResponseCopy.data.project.pipeline.stages.nodes[0].groups.nodes = groups;
+export const mockPipelineResponseWithTooManyJobs = mockPipelineResponseCopy;
+
+export const downstream = {
+ nodes: [
+ {
+ id: 175,
+ iid: '31',
+ path: '/root/elemenohpee/-/pipelines/175',
+ retryable: true,
+ cancelable: false,
+ userPermissions: {
+ updatePipeline: true,
+ },
+ status: {
+ id: '70',
+ group: 'success',
+ label: 'passed',
+ icon: 'status_success',
+ __typename: 'DetailedStatus',
+ },
+ sourceJob: {
+ name: 'test_c',
+ id: '71',
+ retried: false,
+ __typename: 'CiJob',
+ },
+ project: {
+ id: 'gid://gitlab/Project/25',
+ name: 'elemenohpee',
+ fullPath: 'root/elemenohpee',
+ __typename: 'Project',
+ },
+ __typename: 'Pipeline',
+ multiproject: true,
+ },
+ {
+ id: 181,
+ iid: '27',
+ path: '/root/abcd-dag/-/pipelines/181',
+ retryable: true,
+ cancelable: false,
+ userPermissions: {
+ updatePipeline: true,
+ },
+ status: {
+ id: '72',
+ group: 'success',
+ label: 'passed',
+ icon: 'status_success',
+ __typename: 'DetailedStatus',
+ },
+ sourceJob: {
+ id: '73',
+ name: 'test_d',
+ retried: true,
+ __typename: 'CiJob',
+ },
+ project: {
+ id: 'gid://gitlab/Project/23',
+ name: 'abcd-dag',
+ fullPath: 'root/abcd-dag',
+ __typename: 'Project',
+ },
+ __typename: 'Pipeline',
+ multiproject: false,
+ },
+ ],
+};
+
+export const upstream = {
+ id: 161,
+ iid: '24',
+ path: '/root/abcd-dag/-/pipelines/161',
+ retryable: true,
+ cancelable: false,
+ userPermissions: {
+ updatePipeline: true,
+ },
+ status: {
+ id: '74',
+ group: 'success',
+ label: 'passed',
+ icon: 'status_success',
+ __typename: 'DetailedStatus',
+ },
+ sourceJob: null,
+ project: {
+ id: 'gid://gitlab/Project/23',
+ name: 'abcd-dag',
+ fullPath: 'root/abcd-dag',
+ __typename: 'Project',
+ },
+ __typename: 'Pipeline',
+ multiproject: true,
+};
+
+export const wrappedPipelineReturn = {
+ data: {
+ project: {
+ __typename: 'Project',
+ id: '75',
+ pipeline: {
+ __typename: 'Pipeline',
+ id: 'gid://gitlab/Ci::Pipeline/175',
+ iid: '38',
+ complete: true,
+ usesNeeds: true,
+ userPermissions: {
+ __typename: 'PipelinePermissions',
+ updatePipeline: true,
+ },
+ downstream: {
+ retryable: true,
+ cancelable: false,
+ userPermissions: {
+ updatePipeline: true,
+ },
+ __typename: 'PipelineConnection',
+ nodes: [],
+ },
+ upstream: {
+ id: 'gid://gitlab/Ci::Pipeline/174',
+ iid: '37',
+ path: '/root/elemenohpee/-/pipelines/174',
+ retryable: true,
+ cancelable: false,
+ userPermissions: {
+ updatePipeline: true,
+ },
+ __typename: 'Pipeline',
+ status: {
+ __typename: 'DetailedStatus',
+ id: '77',
+ group: 'success',
+ label: 'passed',
+ icon: 'status_success',
+ },
+ sourceJob: {
+ name: 'test_c',
+ id: '78',
+ retried: false,
+ __typename: 'CiJob',
+ },
+ project: {
+ id: 'gid://gitlab/Project/25',
+ name: 'elemenohpee',
+ fullPath: 'root/elemenohpee',
+ __typename: 'Project',
+ },
+ },
+ stages: {
+ __typename: 'CiStageConnection',
+ nodes: [
+ {
+ name: 'build',
+ __typename: 'CiStage',
+ id: '79',
+ status: {
+ action: null,
+ id: '80',
+ __typename: 'DetailedStatus',
+ },
+ groups: {
+ __typename: 'CiGroupConnection',
+ nodes: [
+ {
+ __typename: 'CiGroup',
+ id: '81',
+ status: {
+ __typename: 'DetailedStatus',
+ id: '82',
+ label: 'passed',
+ group: 'success',
+ icon: 'status_success',
+ },
+ name: 'build_n',
+ size: 1,
+ jobs: {
+ __typename: 'CiJobConnection',
+ nodes: [
+ {
+ __typename: 'CiJob',
+ id: '83',
+ kind: BUILD_KIND,
+ name: 'build_n',
+ scheduledAt: null,
+ needs: {
+ __typename: 'CiBuildNeedConnection',
+ nodes: [],
+ },
+ previousStageJobsOrNeeds: {
+ __typename: 'CiJobConnection',
+ nodes: [],
+ },
+ status: {
+ __typename: 'DetailedStatus',
+ id: '84',
+ icon: 'status_success',
+ tooltip: 'passed',
+ label: 'passed',
+ hasDetails: true,
+ detailsPath: '/root/elemenohpee/-/jobs/1662',
+ group: 'success',
+ action: {
+ __typename: 'StatusAction',
+ id: '85',
+ buttonTitle: 'Retry this job',
+ icon: 'retry',
+ path: '/root/elemenohpee/-/jobs/1662/retry',
+ title: 'Retry',
+ },
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+};
+
+export const generateResponse = (raw, mockPath) => unwrapPipelineData(mockPath, raw.data);
+
+export const pipelineWithUpstreamDownstream = (base) => {
+ const pip = { ...base };
+ pip.data.project.pipeline.downstream = downstream;
+ pip.data.project.pipeline.upstream = upstream;
+
+ return generateResponse(pip, 'root/abcd-dag');
+};
+
+export const mapCallouts = (callouts) =>
+ callouts.map((callout) => {
+ return { featureName: callout, __typename: 'UserCallout' };
+ });
+
+export const mockCalloutsResponse = (mappedCallouts) => ({
+ data: {
+ currentUser: {
+ id: 45,
+ __typename: 'User',
+ callouts: {
+ id: 5,
+ __typename: 'UserCalloutConnection',
+ nodes: mappedCallouts,
+ },
+ },
+ },
+});
+
+export const delayedJob = {
+ __typename: 'CiJob',
+ kind: BUILD_KIND,
+ name: 'delayed job',
+ scheduledAt: '2015-07-03T10:01:00.000Z',
+ needs: [],
+ status: {
+ __typename: 'DetailedStatus',
+ icon: 'status_scheduled',
+ tooltip: 'delayed manual action (%{remainingTime})',
+ hasDetails: true,
+ detailsPath: '/root/kinder-pipe/-/jobs/5339',
+ group: 'scheduled',
+ action: {
+ __typename: 'StatusAction',
+ icon: 'time-out',
+ title: 'Unschedule',
+ path: '/frontend-fixtures/builds-project/-/jobs/142/unschedule',
+ buttonTitle: 'Unschedule job',
+ },
+ },
+};
+
+export const mockJob = {
+ id: 4256,
+ name: 'test',
+ kind: BUILD_KIND,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ tooltip: 'passed',
+ group: 'success',
+ detailsPath: '/root/ci-mock/builds/4256',
+ hasDetails: true,
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/root/ci-mock/builds/4256/retry',
+ method: 'post',
+ },
+ },
+};
+
+export const mockJobWithoutDetails = {
+ id: 4257,
+ name: 'job_without_details',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ detailsPath: '/root/ci-mock/builds/4257',
+ hasDetails: false,
+ },
+};
+
+export const mockJobWithUnauthorizedAction = {
+ id: 4258,
+ name: 'stop-environment',
+ status: {
+ icon: 'status_manual',
+ label: 'manual stop action (not allowed)',
+ tooltip: 'manual action',
+ group: 'manual',
+ detailsPath: '/root/ci-mock/builds/4258',
+ hasDetails: true,
+ action: null,
+ },
+};
+
+export const triggerJob = {
+ id: 4259,
+ name: 'trigger',
+ kind: BRIDGE_KIND,
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ action: null,
+ },
+};
+
+export const triggerJobWithRetryAction = {
+ ...triggerJob,
+ status: {
+ ...triggerJob.status,
+ action: {
+ icon: 'retry',
+ title: RETRY_ACTION_TITLE,
+ path: '/root/ci-mock/builds/4259/retry',
+ method: 'post',
+ },
+ },
+};
+
+export const mockFailedJob = {
+ id: 3999,
+ name: 'failed job',
+ kind: BUILD_KIND,
+ status: {
+ id: 'failed-3999-3999',
+ icon: 'status_failed',
+ tooltip: 'failed - (stuck or timeout failure)',
+ hasDetails: true,
+ detailsPath: '/root/ci-project/-/jobs/3999',
+ group: 'failed',
+ label: 'failed',
+ action: {
+ id: 'Ci::BuildPresenter-failed-3999',
+ buttonTitle: 'Retry this job',
+ icon: 'retry',
+ path: '/root/ci-project/-/jobs/3999/retry',
+ title: 'Retry',
+ },
+ },
+};
diff --git a/spec/frontend/ci/pipeline_details/header/pipeline_details_header_spec.js b/spec/frontend/ci/pipeline_details/header/pipeline_details_header_spec.js
new file mode 100644
index 00000000000..6e13658a773
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/header/pipeline_details_header_spec.js
@@ -0,0 +1,452 @@
+import { GlAlert, GlBadge, GlLoadingIcon, GlModal, GlSprintf } from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import PipelineDetailsHeader from '~/ci/pipeline_details/header/pipeline_details_header.vue';
+import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL } from '~/ci/constants';
+import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
+import cancelPipelineMutation from '~/ci/pipeline_details/graphql/mutations/cancel_pipeline.mutation.graphql';
+import deletePipelineMutation from '~/ci/pipeline_details/graphql/mutations/delete_pipeline.mutation.graphql';
+import retryPipelineMutation from '~/ci/pipeline_details/graphql/mutations/retry_pipeline.mutation.graphql';
+import getPipelineDetailsQuery from '~/ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql';
+import {
+ pipelineHeaderSuccess,
+ pipelineHeaderRunning,
+ pipelineHeaderRunningWithDuration,
+ pipelineHeaderFailed,
+ pipelineRetryMutationResponseSuccess,
+ pipelineCancelMutationResponseSuccess,
+ pipelineDeleteMutationResponseSuccess,
+ pipelineRetryMutationResponseFailed,
+ pipelineCancelMutationResponseFailed,
+ pipelineDeleteMutationResponseFailed,
+} from '../mock_data';
+
+Vue.use(VueApollo);
+
+describe('Pipeline details header', () => {
+ let wrapper;
+ let glModalDirective;
+
+ const successHandler = jest.fn().mockResolvedValue(pipelineHeaderSuccess);
+ const runningHandler = jest.fn().mockResolvedValue(pipelineHeaderRunning);
+ const runningHandlerWithDuration = jest.fn().mockResolvedValue(pipelineHeaderRunningWithDuration);
+ const failedHandler = jest.fn().mockResolvedValue(pipelineHeaderFailed);
+
+ const retryMutationHandlerSuccess = jest
+ .fn()
+ .mockResolvedValue(pipelineRetryMutationResponseSuccess);
+ const cancelMutationHandlerSuccess = jest
+ .fn()
+ .mockResolvedValue(pipelineCancelMutationResponseSuccess);
+ const deleteMutationHandlerSuccess = jest
+ .fn()
+ .mockResolvedValue(pipelineDeleteMutationResponseSuccess);
+ const retryMutationHandlerFailed = jest
+ .fn()
+ .mockResolvedValue(pipelineRetryMutationResponseFailed);
+ const cancelMutationHandlerFailed = jest
+ .fn()
+ .mockResolvedValue(pipelineCancelMutationResponseFailed);
+ const deleteMutationHandlerFailed = jest
+ .fn()
+ .mockResolvedValue(pipelineDeleteMutationResponseFailed);
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findStatus = () => wrapper.findComponent(CiBadgeLink);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findAllBadges = () => wrapper.findAllComponents(GlBadge);
+ const findDeleteModal = () => wrapper.findComponent(GlModal);
+ const findCreatedTimeAgo = () => wrapper.findByTestId('pipeline-created-time-ago');
+ const findFinishedTimeAgo = () => wrapper.findByTestId('pipeline-finished-time-ago');
+ const findPipelineName = () => wrapper.findByTestId('pipeline-name');
+ const findCommitTitle = () => wrapper.findByTestId('pipeline-commit-title');
+ const findTotalJobs = () => wrapper.findByTestId('total-jobs');
+ const findComputeMinutes = () => wrapper.findByTestId('compute-minutes');
+ const findCommitLink = () => wrapper.findByTestId('commit-link');
+ const findPipelineRunningText = () => wrapper.findByTestId('pipeline-running-text').text();
+ const findPipelineRefText = () => wrapper.findByTestId('pipeline-ref-text').text();
+ const findRetryButton = () => wrapper.findByTestId('retry-pipeline');
+ const findCancelButton = () => wrapper.findByTestId('cancel-pipeline');
+ const findDeleteButton = () => wrapper.findByTestId('delete-pipeline');
+ const findPipelineUserLink = () => wrapper.findByTestId('pipeline-user-link');
+ const findPipelineDuration = () => wrapper.findByTestId('pipeline-duration-text');
+
+ const defaultHandlers = [[getPipelineDetailsQuery, successHandler]];
+
+ const defaultProvideOptions = {
+ pipelineIid: 1,
+ paths: {
+ pipelinesPath: '/namespace/my-project/-/pipelines',
+ fullProject: '/namespace/my-project',
+ triggeredByPath: '',
+ },
+ };
+
+ const defaultProps = {
+ name: 'Ruby 3.0 master branch pipeline',
+ totalJobs: '50',
+ computeMinutes: '0.65',
+ yamlErrors: 'errors',
+ failureReason: 'pipeline failed',
+ badges: {
+ schedule: true,
+ child: false,
+ latest: true,
+ mergeTrainPipeline: false,
+ invalid: false,
+ failed: false,
+ autoDevops: false,
+ detached: false,
+ stuck: false,
+ },
+ refText:
+ 'Related merge request <a class="mr-iid" href="/root/ci-project/-/merge_requests/1">!1</a> to merge <a class="ref-name" href="/root/ci-project/-/commits/test">test</a>',
+ };
+
+ const createMockApolloProvider = (handlers) => {
+ return createMockApollo(handlers);
+ };
+
+ const createComponent = (handlers = defaultHandlers, props = defaultProps) => {
+ glModalDirective = jest.fn();
+
+ wrapper = shallowMountExtended(PipelineDetailsHeader, {
+ provide: {
+ ...defaultProvideOptions,
+ },
+ propsData: {
+ ...props,
+ },
+ directives: {
+ glModal: {
+ bind(_, { value }) {
+ glModalDirective(value);
+ },
+ },
+ },
+ stubs: { GlSprintf },
+ apolloProvider: createMockApolloProvider(handlers),
+ });
+ };
+
+ describe('loading state', () => {
+ it('shows a loading state while graphQL is fetching initial data', () => {
+ createComponent();
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('defaults', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('does not display loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('displays pipeline status', () => {
+ expect(findStatus().exists()).toBe(true);
+ });
+
+ it('displays pipeline name', () => {
+ expect(findPipelineName().text()).toBe(defaultProps.name);
+ });
+
+ it('displays total jobs', () => {
+ expect(findTotalJobs().text()).toBe('50 Jobs');
+ });
+
+ it('has link to commit', () => {
+ const {
+ data: {
+ project: { pipeline },
+ },
+ } = pipelineHeaderSuccess;
+
+ expect(findCommitLink().attributes('href')).toBe(pipeline.commit.webPath);
+ });
+
+ it('displays correct badges', () => {
+ expect(findAllBadges()).toHaveLength(2);
+ expect(wrapper.findByText('latest').exists()).toBe(true);
+ expect(wrapper.findByText('Scheduled').exists()).toBe(true);
+ });
+
+ it('displays ref text', () => {
+ expect(findPipelineRefText()).toBe('Related merge request !1 to merge test');
+ });
+
+ it('displays pipeline user link with required user popover attributes', () => {
+ const {
+ data: {
+ project: {
+ pipeline: { user },
+ },
+ },
+ } = pipelineHeaderSuccess;
+
+ const userId = getIdFromGraphQLId(user.id).toString();
+
+ expect(findPipelineUserLink().classes()).toContain('js-user-link');
+ expect(findPipelineUserLink().attributes('data-user-id')).toBe(userId);
+ expect(findPipelineUserLink().attributes('data-username')).toBe(user.username);
+ expect(findPipelineUserLink().attributes('href')).toBe(user.webUrl);
+ });
+ });
+
+ describe('without pipeline name', () => {
+ it('displays commit title', async () => {
+ createComponent(defaultHandlers, { ...defaultProps, name: '' });
+
+ await waitForPromises();
+
+ const expectedTitle = pipelineHeaderSuccess.data.project.pipeline.commit.title;
+
+ expect(findPipelineName().exists()).toBe(false);
+ expect(findCommitTitle().text()).toBe(expectedTitle);
+ });
+ });
+
+ describe('finished pipeline', () => {
+ it('displays compute minutes when not zero', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findComputeMinutes().text()).toBe('0.65');
+ });
+
+ it('does not display compute minutes when zero', async () => {
+ createComponent(defaultHandlers, { ...defaultProps, computeMinutes: '0.0' });
+
+ await waitForPromises();
+
+ expect(findComputeMinutes().exists()).toBe(false);
+ });
+
+ it('does not display created time ago', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findCreatedTimeAgo().exists()).toBe(false);
+ });
+
+ it('displays finished time ago', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findFinishedTimeAgo().exists()).toBe(true);
+ });
+
+ it('displays pipeline duartion text', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findPipelineDuration().text()).toBe(
+ '120 minutes 10 seconds, queued for 3,600 seconds',
+ );
+ });
+ });
+
+ describe('running pipeline', () => {
+ beforeEach(async () => {
+ createComponent([[getPipelineDetailsQuery, runningHandler]]);
+
+ await waitForPromises();
+ });
+
+ it('does not display compute minutes', () => {
+ expect(findComputeMinutes().exists()).toBe(false);
+ });
+
+ it('does not display finished time ago', () => {
+ expect(findFinishedTimeAgo().exists()).toBe(false);
+ });
+
+ it('does not display pipeline duration text', () => {
+ expect(findPipelineDuration().exists()).toBe(false);
+ });
+
+ it('displays pipeline running text', () => {
+ expect(findPipelineRunningText()).toBe('In progress, queued for 3,600 seconds');
+ });
+
+ it('displays created time ago', () => {
+ expect(findCreatedTimeAgo().exists()).toBe(true);
+ });
+ });
+
+ describe('running pipeline with duration', () => {
+ beforeEach(async () => {
+ createComponent([[getPipelineDetailsQuery, runningHandlerWithDuration]]);
+
+ await waitForPromises();
+ });
+
+ it('does not display pipeline duration text', () => {
+ expect(findPipelineDuration().exists()).toBe(false);
+ });
+ });
+
+ describe('actions', () => {
+ describe('retry action', () => {
+ beforeEach(async () => {
+ createComponent([
+ [getPipelineDetailsQuery, failedHandler],
+ [retryPipelineMutation, retryMutationHandlerSuccess],
+ ]);
+
+ await waitForPromises();
+ });
+
+ it('should call retryPipeline Mutation with pipeline id', () => {
+ findRetryButton().vm.$emit('click');
+
+ expect(retryMutationHandlerSuccess).toHaveBeenCalledWith({
+ id: pipelineHeaderFailed.data.project.pipeline.id,
+ });
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('should render retry action tooltip', () => {
+ expect(findRetryButton().attributes('title')).toBe(BUTTON_TOOLTIP_RETRY);
+ });
+ });
+
+ describe('retry action failed', () => {
+ beforeEach(async () => {
+ createComponent([
+ [getPipelineDetailsQuery, failedHandler],
+ [retryPipelineMutation, retryMutationHandlerFailed],
+ ]);
+
+ await waitForPromises();
+ });
+
+ it('should display error message on failure', async () => {
+ findRetryButton().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(findAlert().exists()).toBe(true);
+ });
+
+ it('retry button loading state should reset on error', async () => {
+ findRetryButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(findRetryButton().props('loading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findRetryButton().props('loading')).toBe(false);
+ });
+ });
+
+ describe('cancel action', () => {
+ it('should call cancelPipeline Mutation with pipeline id', async () => {
+ createComponent([
+ [getPipelineDetailsQuery, runningHandler],
+ [cancelPipelineMutation, cancelMutationHandlerSuccess],
+ ]);
+
+ await waitForPromises();
+
+ findCancelButton().vm.$emit('click');
+
+ expect(cancelMutationHandlerSuccess).toHaveBeenCalledWith({
+ id: pipelineHeaderRunning.data.project.pipeline.id,
+ });
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('should render cancel action tooltip', async () => {
+ createComponent([
+ [getPipelineDetailsQuery, runningHandler],
+ [cancelPipelineMutation, cancelMutationHandlerSuccess],
+ ]);
+
+ await waitForPromises();
+
+ expect(findCancelButton().attributes('title')).toBe(BUTTON_TOOLTIP_CANCEL);
+ });
+
+ it('should display error message on failure', async () => {
+ createComponent([
+ [getPipelineDetailsQuery, runningHandler],
+ [cancelPipelineMutation, cancelMutationHandlerFailed],
+ ]);
+
+ await waitForPromises();
+
+ findCancelButton().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(findAlert().exists()).toBe(true);
+ });
+ });
+
+ describe('delete action', () => {
+ it('displays delete modal when clicking on delete and does not call the delete action', async () => {
+ createComponent([
+ [getPipelineDetailsQuery, successHandler],
+ [deletePipelineMutation, deleteMutationHandlerSuccess],
+ ]);
+
+ await waitForPromises();
+
+ findDeleteButton().vm.$emit('click');
+
+ const modalId = 'pipeline-delete-modal';
+
+ expect(findDeleteModal().props('modalId')).toBe(modalId);
+ expect(glModalDirective).toHaveBeenCalledWith(modalId);
+ expect(deleteMutationHandlerSuccess).not.toHaveBeenCalled();
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('should call deletePipeline Mutation with pipeline id when modal is submitted', async () => {
+ createComponent([
+ [getPipelineDetailsQuery, successHandler],
+ [deletePipelineMutation, deleteMutationHandlerSuccess],
+ ]);
+
+ await waitForPromises();
+
+ findDeleteModal().vm.$emit('primary');
+
+ expect(deleteMutationHandlerSuccess).toHaveBeenCalledWith({
+ id: pipelineHeaderSuccess.data.project.pipeline.id,
+ });
+ });
+
+ it('should display error message on failure', async () => {
+ createComponent([
+ [getPipelineDetailsQuery, successHandler],
+ [deletePipelineMutation, deleteMutationHandlerFailed],
+ ]);
+
+ await waitForPromises();
+
+ findDeleteModal().vm.$emit('primary');
+
+ await waitForPromises();
+
+ expect(findAlert().exists()).toBe(true);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/jobs/components/failed_jobs_table_spec.js b/spec/frontend/ci/pipeline_details/jobs/components/failed_jobs_table_spec.js
new file mode 100644
index 00000000000..7110a35ad4e
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/jobs/components/failed_jobs_table_spec.js
@@ -0,0 +1,141 @@
+import { GlButton, GlLink, GlTableLite } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { createAlert } from '~/alert';
+import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import FailedJobsTable from '~/ci/pipeline_details/jobs/components/failed_jobs_table.vue';
+import RetryFailedJobMutation from '~/ci/pipeline_details/jobs/graphql/mutations/retry_failed_job.mutation.graphql';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+import {
+ successRetryMutationResponse,
+ failedRetryMutationResponse,
+ mockFailedJobsData,
+ mockFailedJobsDataNoPermission,
+} from '../../mock_data';
+
+jest.mock('~/alert');
+jest.mock('~/lib/utils/url_utility');
+
+Vue.use(VueApollo);
+
+describe('Failed Jobs Table', () => {
+ let wrapper;
+
+ const successRetryMutationHandler = jest.fn().mockResolvedValue(successRetryMutationResponse);
+ const failedRetryMutationHandler = jest.fn().mockResolvedValue(failedRetryMutationResponse);
+
+ const findJobsTable = () => wrapper.findComponent(GlTableLite);
+ const findRetryButton = () => wrapper.findComponent(GlButton);
+ const findJobLink = () => wrapper.findComponent(GlLink);
+ const findJobLog = () => wrapper.findByTestId('job-log');
+ const findSummary = (index) => wrapper.findAllByTestId('job-trace-summary').at(index);
+ const findFirstFailureMessage = () => wrapper.findAllByTestId('job-failure-message').at(0);
+
+ const createMockApolloProvider = (resolver) => {
+ const requestHandlers = [[RetryFailedJobMutation, resolver]];
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = (resolver, failedJobsData = mockFailedJobsData) => {
+ wrapper = mountExtended(FailedJobsTable, {
+ propsData: {
+ failedJobs: failedJobsData,
+ },
+ apolloProvider: createMockApolloProvider(resolver),
+ });
+ };
+
+ it('displays the failed jobs table', () => {
+ createComponent();
+
+ expect(findJobsTable().exists()).toBe(true);
+ });
+
+ it('displays failed job summary', () => {
+ createComponent();
+
+ expect(findSummary(0).text()).toBe('Html Summary');
+ });
+
+ it('displays no job log when no trace', () => {
+ createComponent();
+
+ expect(findSummary(1).text()).toBe('No job log');
+ });
+
+ it('displays failure reason', () => {
+ createComponent();
+
+ expect(findFirstFailureMessage().text()).toBe('Job failed');
+ });
+
+ it('calls the retry failed job mutation and tracks the click', () => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
+ createComponent(successRetryMutationHandler);
+
+ findRetryButton().trigger('click');
+
+ expect(successRetryMutationHandler).toHaveBeenCalledWith({
+ id: mockFailedJobsData[0].id,
+ });
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_retry', {
+ label: TRACKING_CATEGORIES.failed,
+ });
+
+ unmockTracking();
+ });
+
+ it('redirects to the new job after the mutation', async () => {
+ const {
+ data: {
+ jobRetry: { job },
+ },
+ } = successRetryMutationResponse;
+
+ createComponent(successRetryMutationHandler);
+
+ findRetryButton().trigger('click');
+
+ await waitForPromises();
+
+ expect(redirectTo).toHaveBeenCalledWith(job.detailedStatus.detailsPath); // eslint-disable-line import/no-deprecated
+ });
+
+ it('shows error message if the retry failed job mutation fails', async () => {
+ createComponent(failedRetryMutationHandler);
+
+ findRetryButton().trigger('click');
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'There was a problem retrying the failed job.',
+ });
+ });
+
+ it('hides the job log and retry button if a user does not have permission', () => {
+ createComponent([[]], mockFailedJobsDataNoPermission);
+
+ expect(findJobLog().exists()).toBe(false);
+ expect(findRetryButton().exists()).toBe(false);
+ });
+
+ it('displays the job log and retry button if a user has permission', () => {
+ createComponent();
+
+ expect(findJobLog().exists()).toBe(true);
+ expect(findRetryButton().exists()).toBe(true);
+ });
+
+ it('job name links to the correct job', () => {
+ createComponent();
+
+ expect(findJobLink().attributes('href')).toBe(mockFailedJobsData[0].detailedStatus.detailsPath);
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/jobs/failed_jobs_app_spec.js b/spec/frontend/ci/pipeline_details/jobs/failed_jobs_app_spec.js
new file mode 100644
index 00000000000..17b43aa422b
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/jobs/failed_jobs_app_spec.js
@@ -0,0 +1,80 @@
+import { GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/alert';
+import FailedJobsApp from '~/ci/pipeline_details/jobs/failed_jobs_app.vue';
+import FailedJobsTable from '~/ci/pipeline_details/jobs/components/failed_jobs_table.vue';
+import GetFailedJobsQuery from '~/ci/pipeline_details/jobs/graphql/queries/get_failed_jobs.query.graphql';
+import { mockFailedJobsQueryResponse } from 'jest/ci/pipeline_details/mock_data';
+
+Vue.use(VueApollo);
+
+jest.mock('~/alert');
+
+describe('Failed Jobs App', () => {
+ let wrapper;
+ let resolverSpy;
+
+ const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
+ const findJobsTable = () => wrapper.findComponent(FailedJobsTable);
+
+ const createMockApolloProvider = (resolver) => {
+ const requestHandlers = [[GetFailedJobsQuery, resolver]];
+
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = (resolver) => {
+ wrapper = shallowMount(FailedJobsApp, {
+ provide: {
+ fullPath: 'root/ci-project',
+ pipelineIid: 1,
+ },
+ apolloProvider: createMockApolloProvider(resolver),
+ });
+ };
+
+ beforeEach(() => {
+ resolverSpy = jest.fn().mockResolvedValue(mockFailedJobsQueryResponse);
+ });
+
+ describe('loading spinner', () => {
+ it('displays loading spinner when fetching failed jobs', () => {
+ createComponent(resolverSpy);
+
+ expect(findLoadingSpinner().exists()).toBe(true);
+ });
+
+ it('hides loading spinner after the failed jobs have been fetched', async () => {
+ createComponent(resolverSpy);
+
+ await waitForPromises();
+
+ expect(findLoadingSpinner().exists()).toBe(false);
+ });
+ });
+
+ it('displays the failed jobs table', async () => {
+ createComponent(resolverSpy);
+
+ await waitForPromises();
+
+ expect(findJobsTable().exists()).toBe(true);
+ expect(createAlert).not.toHaveBeenCalled();
+ });
+
+ it('handles query fetch error correctly', async () => {
+ resolverSpy = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+
+ createComponent(resolverSpy);
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'There was a problem fetching the failed jobs.',
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/jobs/jobs_app_spec.js b/spec/frontend/ci/pipeline_details/jobs/jobs_app_spec.js
new file mode 100644
index 00000000000..4a3a901502e
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/jobs/jobs_app_spec.js
@@ -0,0 +1,127 @@
+import { GlIntersectionObserver, GlSkeletonLoader, GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/alert';
+import JobsApp from '~/ci/pipeline_details/jobs/jobs_app.vue';
+import JobsTable from '~/ci/jobs_page/components/jobs_table.vue';
+import getPipelineJobsQuery from '~/ci/pipeline_details/jobs/graphql/queries/get_pipeline_jobs.query.graphql';
+import { mockPipelineJobsQueryResponse } from '../mock_data';
+
+Vue.use(VueApollo);
+
+jest.mock('~/alert');
+
+describe('Jobs app', () => {
+ let wrapper;
+ let resolverSpy;
+
+ const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+ const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
+ const findJobsTable = () => wrapper.findComponent(JobsTable);
+
+ const triggerInfiniteScroll = () =>
+ wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
+
+ const createMockApolloProvider = (resolver) => {
+ const requestHandlers = [[getPipelineJobsQuery, resolver]];
+
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = (resolver) => {
+ wrapper = shallowMount(JobsApp, {
+ provide: {
+ projectPath: 'root/ci-project',
+ pipelineIid: 1,
+ },
+ apolloProvider: createMockApolloProvider(resolver),
+ });
+ };
+
+ beforeEach(() => {
+ resolverSpy = jest.fn().mockResolvedValue(mockPipelineJobsQueryResponse);
+ });
+
+ describe('loading spinner', () => {
+ const setup = async () => {
+ createComponent(resolverSpy);
+
+ await waitForPromises();
+
+ triggerInfiniteScroll();
+ };
+
+ it('displays loading spinner when fetching more jobs', async () => {
+ await setup();
+
+ expect(findLoadingSpinner().exists()).toBe(true);
+ expect(findSkeletonLoader().exists()).toBe(false);
+ });
+
+ it('hides loading spinner after jobs have been fetched', async () => {
+ await setup();
+ await waitForPromises();
+
+ expect(findLoadingSpinner().exists()).toBe(false);
+ expect(findSkeletonLoader().exists()).toBe(false);
+ });
+ });
+
+ it('displays the skeleton loader', () => {
+ createComponent(resolverSpy);
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ expect(findJobsTable().exists()).toBe(false);
+ });
+
+ it('displays the jobs table', async () => {
+ createComponent(resolverSpy);
+
+ await waitForPromises();
+
+ expect(findJobsTable().exists()).toBe(true);
+ expect(findSkeletonLoader().exists()).toBe(false);
+ expect(createAlert).not.toHaveBeenCalled();
+ });
+
+ it('handles job fetch error correctly', async () => {
+ resolverSpy = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+
+ createComponent(resolverSpy);
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while fetching the pipelines jobs.',
+ });
+ });
+
+ it('handles infinite scrolling by calling fetchMore', async () => {
+ createComponent(resolverSpy);
+ await waitForPromises();
+
+ triggerInfiniteScroll();
+ await waitForPromises();
+
+ expect(resolverSpy).toHaveBeenCalledWith({
+ after: 'eyJpZCI6Ijg0NyJ9',
+ fullPath: 'root/ci-project',
+ iid: 1,
+ });
+ });
+
+ it('does not display skeleton loader again after fetchMore', async () => {
+ createComponent(resolverSpy);
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ await waitForPromises();
+
+ triggerInfiniteScroll();
+ await waitForPromises();
+
+ expect(findSkeletonLoader().exists()).toBe(false);
+ });
+});
diff --git a/spec/frontend/pipelines/linked_pipelines_mock.json b/spec/frontend/ci/pipeline_details/linked_pipelines_mock.json
index a68283032d2..a68283032d2 100644
--- a/spec/frontend/pipelines/linked_pipelines_mock.json
+++ b/spec/frontend/ci/pipeline_details/linked_pipelines_mock.json
diff --git a/spec/frontend/ci/pipeline_details/mock_data.js b/spec/frontend/ci/pipeline_details/mock_data.js
new file mode 100644
index 00000000000..e32d0a0df47
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/mock_data.js
@@ -0,0 +1,1277 @@
+import pipelineHeaderSuccess from 'test_fixtures/graphql/pipelines/pipeline_header_success.json';
+import pipelineHeaderRunning from 'test_fixtures/graphql/pipelines/pipeline_header_running.json';
+import pipelineHeaderRunningWithDuration from 'test_fixtures/graphql/pipelines/pipeline_header_running_with_duration.json';
+import pipelineHeaderFailed from 'test_fixtures/graphql/pipelines/pipeline_header_failed.json';
+
+const PIPELINE_RUNNING = 'RUNNING';
+const PIPELINE_CANCELED = 'CANCELED';
+const PIPELINE_FAILED = 'FAILED';
+
+const threeWeeksAgo = new Date();
+threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
+
+export {
+ pipelineHeaderSuccess,
+ pipelineHeaderRunning,
+ pipelineHeaderRunningWithDuration,
+ pipelineHeaderFailed,
+};
+
+export const pipelineRetryMutationResponseSuccess = {
+ data: { pipelineRetry: { errors: [] } },
+};
+
+export const pipelineRetryMutationResponseFailed = {
+ data: { pipelineRetry: { errors: ['error'] } },
+};
+
+export const pipelineCancelMutationResponseSuccess = {
+ data: { pipelineCancel: { errors: [] } },
+};
+
+export const pipelineCancelMutationResponseFailed = {
+ data: { pipelineCancel: { errors: ['error'] } },
+};
+
+export const pipelineDeleteMutationResponseSuccess = {
+ data: { pipelineDestroy: { errors: [] } },
+};
+
+export const pipelineDeleteMutationResponseFailed = {
+ data: { pipelineDestroy: { errors: ['error'] } },
+};
+
+export const mockPipelineHeader = {
+ detailedStatus: {},
+ id: 123,
+ userPermissions: {
+ destroyPipeline: true,
+ updatePipeline: true,
+ },
+ createdAt: threeWeeksAgo.toISOString(),
+ user: {
+ id: 'user-1',
+ name: 'Foo',
+ username: 'foobar',
+ email: 'foo@bar.com',
+ avatarUrl: 'link',
+ },
+};
+
+export const mockFailedPipelineHeader = {
+ ...mockPipelineHeader,
+ status: PIPELINE_FAILED,
+ retryable: true,
+ cancelable: false,
+ detailedStatus: {
+ id: 'status-1',
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ detailsPath: 'path',
+ },
+};
+
+export const mockFailedPipelineNoPermissions = {
+ id: 123,
+ userPermissions: {
+ destroyPipeline: false,
+ updatePipeline: false,
+ },
+ createdAt: threeWeeksAgo.toISOString(),
+ user: {
+ id: 'user-1',
+ name: 'Foo',
+ username: 'foobar',
+ email: 'foo@bar.com',
+ avatarUrl: 'link',
+ },
+ status: PIPELINE_RUNNING,
+ retryable: true,
+ cancelable: false,
+ detailedStatus: {
+ id: 'status-1',
+ group: 'running',
+ icon: 'status_running',
+ label: 'running',
+ text: 'running',
+ detailsPath: 'path',
+ },
+};
+
+export const mockRunningPipelineHeader = {
+ ...mockPipelineHeader,
+ status: PIPELINE_RUNNING,
+ retryable: false,
+ cancelable: true,
+ detailedStatus: {
+ id: 'status-1',
+ group: 'running',
+ icon: 'status_running',
+ label: 'running',
+ text: 'running',
+ detailsPath: 'path',
+ },
+};
+
+export const mockRunningPipelineNoPermissions = {
+ id: 123,
+ userPermissions: {
+ destroyPipeline: false,
+ updatePipeline: false,
+ },
+ createdAt: threeWeeksAgo.toISOString(),
+ user: {
+ id: 'user-1',
+ name: 'Foo',
+ username: 'foobar',
+ email: 'foo@bar.com',
+ avatarUrl: 'link',
+ },
+ status: PIPELINE_RUNNING,
+ retryable: false,
+ cancelable: true,
+ detailedStatus: {
+ id: 'status-1',
+ group: 'running',
+ icon: 'status_running',
+ label: 'running',
+ text: 'running',
+ detailsPath: 'path',
+ },
+};
+
+export const mockCancelledPipelineHeader = {
+ ...mockPipelineHeader,
+ status: PIPELINE_CANCELED,
+ retryable: true,
+ cancelable: false,
+ detailedStatus: {
+ id: 'status-1',
+ group: 'cancelled',
+ icon: 'status_cancelled',
+ label: 'cancelled',
+ text: 'cancelled',
+ detailsPath: 'path',
+ },
+};
+
+export const mockSuccessfulPipelineHeader = {
+ ...mockPipelineHeader,
+ status: 'SUCCESS',
+ retryable: false,
+ cancelable: false,
+ detailedStatus: {
+ id: 'status-1',
+ group: 'success',
+ icon: 'status_success',
+ label: 'success',
+ text: 'success',
+ detailsPath: 'path',
+ },
+};
+
+export const mockRunningPipelineHeaderData = {
+ data: {
+ project: {
+ id: '1',
+ pipeline: {
+ ...mockRunningPipelineHeader,
+ iid: '28',
+ user: {
+ id: 'user-1',
+ name: 'Foo',
+ username: 'foobar',
+ webPath: '/foo',
+ webUrl: '/foo',
+ email: 'foo@bar.com',
+ avatarUrl: 'link',
+ status: null,
+ __typename: 'UserCore',
+ },
+ __typename: 'Pipeline',
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
+export const users = [
+ {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/root',
+ },
+ {
+ id: 10,
+ name: 'Angel Spinka',
+ username: 'shalonda',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/709df1b65ad06764ee2b0edf1b49fc27?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/shalonda',
+ },
+ {
+ id: 11,
+ name: 'Art Davis',
+ username: 'deja.green',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/bb56834c061522760e7a6dd7d431a306?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/deja.green',
+ },
+ {
+ id: 32,
+ name: 'Arnold Mante',
+ username: 'reported_user_10',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/ab558033a82466d7905179e837d7723a?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/reported_user_10',
+ },
+ {
+ id: 38,
+ name: 'Cher Wintheiser',
+ username: 'reported_user_16',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/2640356e8b5bc4314133090994ed162b?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/reported_user_16',
+ },
+ {
+ id: 39,
+ name: 'Bethel Wolf',
+ username: 'reported_user_17',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/4b948694fadba4b01e4acfc06b065e8e?s=80\u0026d=identicon',
+ web_url: 'http://192.168.1.22:3000/reported_user_17',
+ },
+];
+
+export const branches = [
+ {
+ name: 'branch-1',
+ commit: {
+ id: '21fb056cc47dcf706670e6de635b1b326490ebdc',
+ short_id: '21fb056c',
+ created_at: '2020-05-07T10:58:28.000-04:00',
+ parent_ids: null,
+ title: 'Add new file',
+ message: 'Add new file',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2020-05-07T10:58:28.000-04:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2020-05-07T10:58:28.000-04:00',
+ web_url:
+ 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/21fb056cc47dcf706670e6de635b1b326490ebdc',
+ },
+ merged: false,
+ protected: false,
+ developers_can_push: false,
+ developers_can_merge: false,
+ can_push: true,
+ default: false,
+ web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-1',
+ },
+ {
+ name: 'branch-10',
+ commit: {
+ id: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ short_id: '66673b07',
+ created_at: '2020-03-16T11:04:46.000-04:00',
+ parent_ids: null,
+ title: 'Update .gitlab-ci.yml',
+ message: 'Update .gitlab-ci.yml',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2020-03-16T11:04:46.000-04:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2020-03-16T11:04:46.000-04:00',
+ web_url:
+ 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
+ },
+ merged: false,
+ protected: false,
+ developers_can_push: false,
+ developers_can_merge: false,
+ can_push: true,
+ default: false,
+ web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-10',
+ },
+ {
+ name: 'branch-11',
+ commit: {
+ id: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ short_id: '66673b07',
+ created_at: '2020-03-16T11:04:46.000-04:00',
+ parent_ids: null,
+ title: 'Update .gitlab-ci.yml',
+ message: 'Update .gitlab-ci.yml',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2020-03-16T11:04:46.000-04:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2020-03-16T11:04:46.000-04:00',
+ web_url:
+ 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
+ },
+ merged: false,
+ protected: false,
+ developers_can_push: false,
+ developers_can_merge: false,
+ can_push: true,
+ default: false,
+ web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-11',
+ },
+];
+
+export const tags = [
+ {
+ name: 'tag-3',
+ message: '',
+ target: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ commit: {
+ id: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ short_id: '66673b07',
+ created_at: '2020-03-16T11:04:46.000-04:00',
+ parent_ids: ['def28bf679235071140180495f25b657e2203587'],
+ title: 'Update .gitlab-ci.yml',
+ message: 'Update .gitlab-ci.yml',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2020-03-16T11:04:46.000-04:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2020-03-16T11:04:46.000-04:00',
+ web_url:
+ 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
+ },
+ release: null,
+ protected: false,
+ },
+ {
+ name: 'tag-2',
+ message: '',
+ target: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ commit: {
+ id: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ short_id: '66673b07',
+ created_at: '2020-03-16T11:04:46.000-04:00',
+ parent_ids: ['def28bf679235071140180495f25b657e2203587'],
+ title: 'Update .gitlab-ci.yml',
+ message: 'Update .gitlab-ci.yml',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2020-03-16T11:04:46.000-04:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2020-03-16T11:04:46.000-04:00',
+ web_url:
+ 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
+ },
+ release: null,
+ protected: false,
+ },
+ {
+ name: 'tag-1',
+ message: '',
+ target: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ commit: {
+ id: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ short_id: '66673b07',
+ created_at: '2020-03-16T11:04:46.000-04:00',
+ parent_ids: ['def28bf679235071140180495f25b657e2203587'],
+ title: 'Update .gitlab-ci.yml',
+ message: 'Update .gitlab-ci.yml',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2020-03-16T11:04:46.000-04:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2020-03-16T11:04:46.000-04:00',
+ web_url:
+ 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
+ },
+ release: null,
+ protected: false,
+ },
+ {
+ name: 'main-tag',
+ message: '',
+ target: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ commit: {
+ id: '66673b07efef254dab7d537f0433a40e61cf84fe',
+ short_id: '66673b07',
+ created_at: '2020-03-16T11:04:46.000-04:00',
+ parent_ids: ['def28bf679235071140180495f25b657e2203587'],
+ title: 'Update .gitlab-ci.yml',
+ message: 'Update .gitlab-ci.yml',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2020-03-16T11:04:46.000-04:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2020-03-16T11:04:46.000-04:00',
+ web_url:
+ 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
+ },
+ release: null,
+ protected: false,
+ },
+];
+
+export const mockSearch = [
+ { type: 'username', value: { data: 'root', operator: '=' } },
+ { type: 'ref', value: { data: 'main', operator: '=' } },
+ { type: 'status', value: { data: 'pending', operator: '=' } },
+];
+
+export const mockBranchesAfterMap = ['branch-1', 'branch-10', 'branch-11'];
+
+export const mockTagsAfterMap = ['tag-3', 'tag-2', 'tag-1', 'main-tag'];
+
+export const mockPipelineJobsQueryResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/20',
+ __typename: 'Project',
+ pipeline: {
+ id: 'gid://gitlab/Ci::Pipeline/224',
+ __typename: 'Pipeline',
+ jobs: {
+ __typename: 'CiJobConnection',
+ pageInfo: {
+ endCursor: 'eyJpZCI6Ijg0NyJ9',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'eyJpZCI6IjYyMCJ9',
+ __typename: 'PageInfo',
+ },
+ nodes: [
+ {
+ artifacts: {
+ nodes: [
+ {
+ downloadPath: '/root/ci-project/-/jobs/620/artifacts/download?file_type=trace',
+ fileType: 'TRACE',
+ __typename: 'CiJobArtifact',
+ },
+ ],
+ __typename: 'CiJobArtifactConnection',
+ },
+ allowFailure: false,
+ status: 'SUCCESS',
+ scheduledAt: null,
+ manualJob: false,
+ triggered: null,
+ createdByTag: false,
+ detailedStatus: {
+ id: 'success-620-620',
+ detailsPath: '/root/ci-project/-/jobs/620',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed (retried)',
+ action: null,
+ __typename: 'DetailedStatus',
+ },
+ id: 'gid://gitlab/Ci::Build/620',
+ refName: 'main',
+ refPath: '/root/ci-project/-/commits/main',
+ tags: [],
+ shortSha: '5acce24b',
+ commitPath: '/root/ci-project/-/commit/5acce24b3737d4f0d649ad0a26ae1903a2b35f5e',
+ stage: { id: 'gid://gitlab/Ci::Stage/148', name: 'test', __typename: 'CiStage' },
+ name: 'coverage_job',
+ duration: 4,
+ finishedAt: '2021-12-06T14:13:49Z',
+ coverage: 82.71,
+ retryable: false,
+ playable: false,
+ cancelable: false,
+ active: false,
+ stuck: false,
+ userPermissions: {
+ readBuild: true,
+ readJobArtifacts: true,
+ updateBuild: true,
+ __typename: 'JobPermissions',
+ },
+ __typename: 'CiJob',
+ },
+ {
+ artifacts: {
+ nodes: [
+ {
+ downloadPath: '/root/ci-project/-/jobs/619/artifacts/download?file_type=trace',
+ fileType: 'TRACE',
+ __typename: 'CiJobArtifact',
+ },
+ ],
+ __typename: 'CiJobArtifactConnection',
+ },
+ allowFailure: false,
+ status: 'SUCCESS',
+ scheduledAt: null,
+ manualJob: false,
+ triggered: null,
+ createdByTag: false,
+ detailedStatus: {
+ id: 'success-619-619',
+ detailsPath: '/root/ci-project/-/jobs/619',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ text: 'passed',
+ tooltip: 'passed (retried)',
+ action: null,
+ __typename: 'DetailedStatus',
+ },
+ id: 'gid://gitlab/Ci::Build/619',
+ refName: 'main',
+ refPath: '/root/ci-project/-/commits/main',
+ tags: [],
+ shortSha: '5acce24b',
+ commitPath: '/root/ci-project/-/commit/5acce24b3737d4f0d649ad0a26ae1903a2b35f5e',
+ stage: { id: 'gid://gitlab/Ci::Stage/148', name: 'test', __typename: 'CiStage' },
+ name: 'test_job_two',
+ duration: 4,
+ finishedAt: '2021-12-06T14:13:44Z',
+ coverage: null,
+ retryable: false,
+ playable: false,
+ cancelable: false,
+ active: false,
+ stuck: false,
+ userPermissions: {
+ readBuild: true,
+ readJobArtifacts: true,
+ updateBuild: true,
+ __typename: 'JobPermissions',
+ },
+ __typename: 'CiJob',
+ },
+ ],
+ },
+ },
+ },
+ },
+};
+
+export const mockPipeline = (projectPath) => {
+ return {
+ pipeline: {
+ id: 1,
+ user: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url: '',
+ web_url: 'http://0.0.0.0:3000/root',
+ show_status: false,
+ path: '/root',
+ },
+ active: false,
+ source: 'merge_request_event',
+ created_at: '2021-10-19T21:17:38.698Z',
+ updated_at: '2021-10-21T18:00:42.758Z',
+ path: 'foo',
+ flags: {},
+ merge_request: {
+ iid: 1,
+ path: `/${projectPath}/1`,
+ title: 'commit',
+ source_branch: 'test-commit-name',
+ source_branch_path: `/${projectPath}`,
+ target_branch: 'main',
+ target_branch_path: `/${projectPath}/-/commit/main`,
+ },
+ ref: {
+ name: 'refs/merge-requests/1/head',
+ path: `/${projectPath}/-/commits/refs/merge-requests/1/head`,
+ tag: false,
+ branch: false,
+ merge_request: true,
+ },
+ commit: {
+ id: 'fd6df5b3229e213c97d308844a6f3e7fd71e8f8c',
+ short_id: 'fd6df5b3',
+ created_at: '2021-10-19T21:17:12.000+00:00',
+ parent_ids: ['7147906b84306e83cb3fec6582a25390b75713c6'],
+ title: 'Commit',
+ message: 'Commit',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2021-10-19T21:17:12.000+00:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2021-10-19T21:17:12.000+00:00',
+ trailers: {},
+ web_url: '',
+ author: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url: '',
+ web_url: '',
+ show_status: false,
+ path: '/root',
+ },
+ author_gravatar_url: '',
+ commit_url: `/${projectPath}/fd6df5b3229e213c97d308844a6f3e7fd71e8f8c`,
+ commit_path: `/${projectPath}/commit/fd6df5b3229e213c97d308844a6f3e7fd71e8f8c`,
+ },
+ project: {
+ full_path: `/${projectPath}`,
+ },
+ triggered_by: null,
+ triggered: [],
+ },
+ pipelineScheduleUrl: 'foo',
+ pipelineKey: 'id',
+ viewType: 'root',
+ };
+};
+
+export const mockPipelineTag = () => {
+ return {
+ pipeline: {
+ id: 311,
+ iid: 37,
+ user: {
+ id: 1,
+ username: 'root',
+ name: 'Administrator',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ web_url: 'http://gdk.test:3000/root',
+ show_status: false,
+ path: '/root',
+ },
+ active: false,
+ source: 'push',
+ name: 'Build pipeline',
+ created_at: '2022-02-02T15:39:04.012Z',
+ updated_at: '2022-02-02T15:40:59.573Z',
+ path: '/root/mr-widgets/-/pipelines/311',
+ flags: {
+ stuck: false,
+ auto_devops: false,
+ merge_request: false,
+ yaml_errors: false,
+ retryable: true,
+ cancelable: false,
+ failure_reason: false,
+ detached_merge_request_pipeline: false,
+ merge_request_pipeline: false,
+ merge_train_pipeline: false,
+ latest: true,
+ },
+ details: {
+ status: {
+ icon: 'status_warning',
+ text: 'passed',
+ label: 'passed with warnings',
+ group: 'success-with-warnings',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/311',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ stages: [
+ {
+ name: 'accessibility',
+ title: 'accessibility: passed',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/311#accessibility',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ path: '/root/mr-widgets/-/pipelines/311#accessibility',
+ dropdown_path: '/root/mr-widgets/-/pipelines/311/stage.json?stage=accessibility',
+ },
+ {
+ name: 'validate',
+ title: 'validate: passed with warnings',
+ status: {
+ icon: 'status_warning',
+ text: 'passed',
+ label: 'passed with warnings',
+ group: 'success-with-warnings',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/311#validate',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ path: '/root/mr-widgets/-/pipelines/311#validate',
+ dropdown_path: '/root/mr-widgets/-/pipelines/311/stage.json?stage=validate',
+ },
+ {
+ name: 'test',
+ title: 'test: passed',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/311#test',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ path: '/root/mr-widgets/-/pipelines/311#test',
+ dropdown_path: '/root/mr-widgets/-/pipelines/311/stage.json?stage=test',
+ },
+ {
+ name: 'build',
+ title: 'build: passed',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/311#build',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ path: '/root/mr-widgets/-/pipelines/311#build',
+ dropdown_path: '/root/mr-widgets/-/pipelines/311/stage.json?stage=build',
+ },
+ ],
+ duration: 93,
+ finished_at: '2022-02-02T15:40:59.384Z',
+ event_type_name: 'Pipeline',
+ manual_actions: [],
+ scheduled_actions: [],
+ },
+ ref: {
+ name: 'test',
+ path: '/root/mr-widgets/-/commits/test',
+ tag: true,
+ branch: false,
+ merge_request: false,
+ },
+ commit: {
+ id: '9b92b4f730d1611bd9a086ca221ae206d5da1e59',
+ short_id: '9b92b4f7',
+ created_at: '2022-01-13T13:59:03.000+00:00',
+ parent_ids: ['0ba763634114e207dc72c65c8e9459556b1204fb'],
+ title: 'Update hello_world.js',
+ message: 'Update hello_world.js',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2022-01-13T13:59:03.000+00:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2022-01-13T13:59:03.000+00:00',
+ trailers: {},
+ web_url:
+ 'http://gdk.test:3000/root/mr-widgets/-/commit/9b92b4f730d1611bd9a086ca221ae206d5da1e59',
+ author: {
+ id: 1,
+ username: 'root',
+ name: 'Administrator',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ web_url: 'http://gdk.test:3000/root',
+ show_status: false,
+ path: '/root',
+ },
+ author_gravatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ commit_url:
+ 'http://gdk.test:3000/root/mr-widgets/-/commit/9b92b4f730d1611bd9a086ca221ae206d5da1e59',
+ commit_path: '/root/mr-widgets/-/commit/9b92b4f730d1611bd9a086ca221ae206d5da1e59',
+ },
+ retry_path: '/root/mr-widgets/-/pipelines/311/retry',
+ delete_path: '/root/mr-widgets/-/pipelines/311',
+ failed_builds: [
+ {
+ id: 1696,
+ name: 'fmt',
+ started: '2022-02-02T15:39:45.192Z',
+ complete: true,
+ archived: false,
+ build_path: '/root/mr-widgets/-/jobs/1696',
+ retry_path: '/root/mr-widgets/-/jobs/1696/retry',
+ playable: false,
+ scheduled: false,
+ created_at: '2022-02-02T15:39:04.136Z',
+ updated_at: '2022-02-02T15:39:57.969Z',
+ status: {
+ icon: 'status_warning',
+ text: 'failed',
+ label: 'failed (allowed to fail)',
+ group: 'failed-with-warnings',
+ tooltip: 'failed - (script failure) (allowed to fail)',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/jobs/1696',
+ illustration: {
+ image:
+ '/assets/illustrations/skipped-job_empty-29a8a37d8a61d1b6f68cf3484f9024e53cd6eb95e28eae3554f8011a1146bf27.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/root/mr-widgets/-/jobs/1696/retry',
+ method: 'post',
+ button_title: 'Retry this job',
+ },
+ },
+ recoverable: false,
+ },
+ ],
+ project: {
+ id: 23,
+ name: 'mr-widgets',
+ full_path: '/root/mr-widgets',
+ full_name: 'Administrator / mr-widgets',
+ },
+ triggered_by: null,
+ triggered: [],
+ },
+ pipelineScheduleUrl: 'foo',
+ pipelineKey: 'id',
+ viewType: 'root',
+ };
+};
+
+export const mockPipelineBranch = () => {
+ return {
+ pipeline: {
+ id: 268,
+ iid: 34,
+ user: {
+ id: 1,
+ username: 'root',
+ name: 'Administrator',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ web_url: 'http://gdk.test:3000/root',
+ show_status: false,
+ path: '/root',
+ },
+ active: false,
+ source: 'push',
+ name: 'Build pipeline',
+ created_at: '2022-01-14T17:40:27.866Z',
+ updated_at: '2022-01-14T18:02:35.850Z',
+ path: '/root/mr-widgets/-/pipelines/268',
+ flags: {
+ stuck: false,
+ auto_devops: false,
+ merge_request: false,
+ yaml_errors: false,
+ retryable: true,
+ cancelable: false,
+ failure_reason: false,
+ detached_merge_request_pipeline: false,
+ merge_request_pipeline: false,
+ merge_train_pipeline: false,
+ latest: true,
+ },
+ details: {
+ status: {
+ icon: 'status_warning',
+ text: 'passed',
+ label: 'passed with warnings',
+ group: 'success-with-warnings',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/268',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ stages: [
+ {
+ name: 'validate',
+ title: 'validate: passed with warnings',
+ status: {
+ icon: 'status_warning',
+ text: 'passed',
+ label: 'passed with warnings',
+ group: 'success-with-warnings',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/268#validate',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ path: '/root/mr-widgets/-/pipelines/268#validate',
+ dropdown_path: '/root/mr-widgets/-/pipelines/268/stage.json?stage=validate',
+ },
+ {
+ name: 'test',
+ title: 'test: passed',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/268#test',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ path: '/root/mr-widgets/-/pipelines/268#test',
+ dropdown_path: '/root/mr-widgets/-/pipelines/268/stage.json?stage=test',
+ },
+ {
+ name: 'build',
+ title: 'build: passed',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/pipelines/268#build',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
+ },
+ path: '/root/mr-widgets/-/pipelines/268#build',
+ dropdown_path: '/root/mr-widgets/-/pipelines/268/stage.json?stage=build',
+ },
+ ],
+ duration: 75,
+ finished_at: '2022-01-14T18:02:35.842Z',
+ event_type_name: 'Pipeline',
+ manual_actions: [],
+ scheduled_actions: [],
+ },
+ ref: {
+ name: 'update-ci',
+ path: '/root/mr-widgets/-/commits/update-ci',
+ tag: false,
+ branch: true,
+ merge_request: false,
+ },
+ commit: {
+ id: '96aef9ecec5752c09371c1ade5fc77860aafc863',
+ short_id: '96aef9ec',
+ created_at: '2022-01-14T17:40:26.000+00:00',
+ parent_ids: ['06860257572d4cf84b73806250b78169050aed83'],
+ title: 'Update main.tf',
+ message: 'Update main.tf',
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2022-01-14T17:40:26.000+00:00',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2022-01-14T17:40:26.000+00:00',
+ trailers: {},
+ web_url:
+ 'http://gdk.test:3000/root/mr-widgets/-/commit/96aef9ecec5752c09371c1ade5fc77860aafc863',
+ author: {
+ id: 1,
+ username: 'root',
+ name: 'Administrator',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ web_url: 'http://gdk.test:3000/root',
+ show_status: false,
+ path: '/root',
+ },
+ author_gravatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ commit_url:
+ 'http://gdk.test:3000/root/mr-widgets/-/commit/96aef9ecec5752c09371c1ade5fc77860aafc863',
+ commit_path: '/root/mr-widgets/-/commit/96aef9ecec5752c09371c1ade5fc77860aafc863',
+ },
+ retry_path: '/root/mr-widgets/-/pipelines/268/retry',
+ delete_path: '/root/mr-widgets/-/pipelines/268',
+ failed_builds: [
+ {
+ id: 1260,
+ name: 'fmt',
+ started: '2022-01-14T17:40:36.435Z',
+ complete: true,
+ archived: false,
+ build_path: '/root/mr-widgets/-/jobs/1260',
+ retry_path: '/root/mr-widgets/-/jobs/1260/retry',
+ playable: false,
+ scheduled: false,
+ created_at: '2022-01-14T17:40:27.879Z',
+ updated_at: '2022-01-14T17:40:42.129Z',
+ status: {
+ icon: 'status_warning',
+ text: 'failed',
+ label: 'failed (allowed to fail)',
+ group: 'failed-with-warnings',
+ tooltip: 'failed - (script failure) (allowed to fail)',
+ has_details: true,
+ details_path: '/root/mr-widgets/-/jobs/1260',
+ illustration: {
+ image:
+ '/assets/illustrations/skipped-job_empty-29a8a37d8a61d1b6f68cf3484f9024e53cd6eb95e28eae3554f8011a1146bf27.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/root/mr-widgets/-/jobs/1260/retry',
+ method: 'post',
+ button_title: 'Retry this job',
+ },
+ },
+ recoverable: false,
+ },
+ ],
+ project: {
+ id: 23,
+ name: 'mr-widgets',
+ full_path: '/root/mr-widgets',
+ full_name: 'Administrator / mr-widgets',
+ },
+ triggered_by: null,
+ triggered: [],
+ },
+ pipelineScheduleUrl: 'foo',
+ pipelineKey: 'id',
+ viewType: 'root',
+ };
+};
+
+export const mockFailedJobsQueryResponse = {
+ data: {
+ project: {
+ __typename: 'Project',
+ id: 'gid://gitlab/Project/20',
+ pipeline: {
+ __typename: 'Pipeline',
+ id: 'gid://gitlab/Ci::Pipeline/300',
+ jobs: {
+ __typename: 'CiJobConnection',
+ nodes: [
+ {
+ __typename: 'CiJob',
+ status: 'FAILED',
+ detailedStatus: {
+ __typename: 'DetailedStatus',
+ id: 'failed-1848-1848',
+ detailsPath: '/root/ci-project/-/jobs/1848',
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ tooltip: 'failed - (script failure)',
+ action: {
+ __typename: 'StatusAction',
+ id: 'Ci::Build-failed-1848',
+ buttonTitle: 'Retry this job',
+ icon: 'retry',
+ method: 'post',
+ path: '/root/ci-project/-/jobs/1848/retry',
+ title: 'Retry',
+ },
+ },
+ id: 'gid://gitlab/Ci::Build/1848',
+ stage: {
+ __typename: 'CiStage',
+ id: 'gid://gitlab/Ci::Stage/358',
+ name: 'build',
+ },
+ name: 'wait_job',
+ retryable: true,
+ userPermissions: {
+ __typename: 'JobPermissions',
+ readBuild: true,
+ updateBuild: true,
+ },
+ trace: {
+ htmlSummary: '<span>Html Summary</span>',
+ },
+ failureMessage: 'Failed',
+ },
+ {
+ __typename: 'CiJob',
+ status: 'FAILED',
+ detailedStatus: {
+ __typename: 'DetailedStatus',
+ id: 'failed-1710-1710',
+ detailsPath: '/root/ci-project/-/jobs/1710',
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ tooltip: 'failed - (script failure) (retried)',
+ action: null,
+ },
+ id: 'gid://gitlab/Ci::Build/1710',
+ stage: {
+ __typename: 'CiStage',
+ id: 'gid://gitlab/Ci::Stage/358',
+ name: 'build',
+ },
+ name: 'wait_job',
+ retryable: false,
+ userPermissions: {
+ __typename: 'JobPermissions',
+ readBuild: true,
+ updateBuild: true,
+ },
+ trace: null,
+ failureMessage: 'Failed',
+ },
+ ],
+ },
+ },
+ },
+ },
+};
+
+export const mockFailedJobsData = [
+ {
+ __typename: 'CiJob',
+ status: 'FAILED',
+ detailedStatus: {
+ __typename: 'DetailedStatus',
+ id: 'failed-1848-1848',
+ detailsPath: '/root/ci-project/-/jobs/1848',
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ tooltip: 'failed - (script failure)',
+ action: {
+ __typename: 'StatusAction',
+ id: 'Ci::Build-failed-1848',
+ buttonTitle: 'Retry this job',
+ icon: 'retry',
+ method: 'post',
+ path: '/root/ci-project/-/jobs/1848/retry',
+ title: 'Retry',
+ },
+ },
+ id: 'gid://gitlab/Ci::Build/1848',
+ stage: {
+ __typename: 'CiStage',
+ id: 'gid://gitlab/Ci::Stage/358',
+ name: 'build',
+ },
+ name: 'wait_job',
+ retryable: true,
+ userPermissions: {
+ __typename: 'JobPermissions',
+ readBuild: true,
+ updateBuild: true,
+ },
+ trace: {
+ htmlSummary: '<span>Html Summary</span>',
+ },
+ failureMessage: 'Job failed',
+ _showDetails: true,
+ },
+ {
+ __typename: 'CiJob',
+ status: 'FAILED',
+ detailedStatus: {
+ __typename: 'DetailedStatus',
+ id: 'failed-1710-1710',
+ detailsPath: '/root/ci-project/-/jobs/1710',
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ tooltip: 'failed - (script failure) (retried)',
+ action: null,
+ },
+ id: 'gid://gitlab/Ci::Build/1710',
+ stage: {
+ __typename: 'CiStage',
+ id: 'gid://gitlab/Ci::Stage/358',
+ name: 'build',
+ },
+ name: 'wait_job',
+ retryable: false,
+ userPermissions: {
+ __typename: 'JobPermissions',
+ readBuild: true,
+ updateBuild: true,
+ },
+ trace: null,
+ failureMessage: 'Job failed',
+ _showDetails: true,
+ },
+];
+
+export const mockFailedJobsDataNoPermission = [
+ {
+ ...mockFailedJobsData[0],
+ userPermissions: { __typename: 'JobPermissions', readBuild: false, updateBuild: false },
+ },
+];
+
+export const successRetryMutationResponse = {
+ data: {
+ jobRetry: {
+ job: {
+ __typename: 'CiJob',
+ id: '"gid://gitlab/Ci::Build/1985"',
+ detailedStatus: {
+ detailsPath: '/root/project/-/jobs/1985',
+ id: 'pending-1985-1985',
+ __typename: 'DetailedStatus',
+ },
+ },
+ errors: [],
+ __typename: 'JobRetryPayload',
+ },
+ },
+};
+
+export const failedRetryMutationResponse = {
+ data: {
+ jobRetry: {
+ job: {},
+ errors: ['New Error'],
+ __typename: 'JobRetryPayload',
+ },
+ },
+};
diff --git a/spec/frontend/ci/pipeline_details/pipeline_tabs_spec.js b/spec/frontend/ci/pipeline_details/pipeline_tabs_spec.js
new file mode 100644
index 00000000000..8d67cdef05c
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/pipeline_tabs_spec.js
@@ -0,0 +1,63 @@
+import { createAppOptions } from '~/ci/pipeline_details/pipeline_tabs';
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ removeParams: () => 'gitlab.com',
+ joinPaths: () => {},
+ setUrlFragment: () => {},
+}));
+
+jest.mock('~/ci/pipeline_details/utils', () => ({
+ getPipelineDefaultTab: () => '',
+}));
+
+describe('~/ci/pipeline_details/pipeline_tabs.js', () => {
+ describe('createAppOptions', () => {
+ const SELECTOR = 'SELECTOR';
+
+ let el;
+
+ const createElement = () => {
+ el = document.createElement('div');
+ el.id = SELECTOR;
+ el.dataset.canGenerateCodequalityReports = 'true';
+ el.dataset.codequalityReportDownloadPath = 'codequalityReportDownloadPath';
+ el.dataset.downloadablePathForReportType = 'downloadablePathForReportType';
+ el.dataset.exposeSecurityDashboard = 'true';
+ el.dataset.exposeLicenseScanningData = 'true';
+ el.dataset.failedJobsCount = 1;
+ el.dataset.graphqlResourceEtag = 'graphqlResourceEtag';
+ el.dataset.pipelineIid = '123';
+ el.dataset.pipelineProjectPath = 'pipelineProjectPath';
+
+ document.body.appendChild(el);
+ };
+
+ afterEach(() => {
+ el = null;
+ });
+
+ it("extracts the properties from the element's dataset", () => {
+ createElement();
+ const options = createAppOptions(`#${SELECTOR}`, null);
+
+ expect(options).toMatchObject({
+ el,
+ provide: {
+ canGenerateCodequalityReports: true,
+ codequalityReportDownloadPath: 'codequalityReportDownloadPath',
+ downloadablePathForReportType: 'downloadablePathForReportType',
+ exposeSecurityDashboard: true,
+ exposeLicenseScanningData: true,
+ failedJobsCount: '1',
+ graphqlResourceEtag: 'graphqlResourceEtag',
+ pipelineIid: '123',
+ pipelineProjectPath: 'pipelineProjectPath',
+ },
+ });
+ });
+
+ it('returns `null` if el does not exist', () => {
+ expect(createAppOptions('foo', null)).toBe(null);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/pipelines_store_spec.js b/spec/frontend/ci/pipeline_details/pipelines_store_spec.js
new file mode 100644
index 00000000000..43e605f4306
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/pipelines_store_spec.js
@@ -0,0 +1,80 @@
+import PipelineStore from '~/ci/pipeline_details/stores/pipelines_store';
+
+describe('Pipelines Store', () => {
+ let store;
+
+ beforeEach(() => {
+ store = new PipelineStore();
+ });
+
+ it('should be initialized with an empty state', () => {
+ expect(store.state.pipelines).toEqual([]);
+ expect(store.state.count).toEqual({});
+ expect(store.state.pageInfo).toEqual({});
+ });
+
+ describe('storePipelines', () => {
+ it('should use the default parameter if none is provided', () => {
+ store.storePipelines();
+
+ expect(store.state.pipelines).toEqual([]);
+ });
+
+ it('should store the provided array', () => {
+ const array = [
+ { id: 1, status: 'running' },
+ { id: 2, status: 'success' },
+ ];
+ store.storePipelines(array);
+
+ expect(store.state.pipelines).toEqual(array);
+ });
+ });
+
+ describe('storeCount', () => {
+ it('should use the default parameter if none is provided', () => {
+ store.storeCount();
+
+ expect(store.state.count).toEqual({});
+ });
+
+ it('should store the provided count', () => {
+ const count = { all: 20, finished: 10 };
+ store.storeCount(count);
+
+ expect(store.state.count).toEqual(count);
+ });
+ });
+
+ describe('storePagination', () => {
+ it('should use the default parameter if none is provided', () => {
+ store.storePagination();
+
+ expect(store.state.pageInfo).toEqual({});
+ });
+
+ it('should store pagination information normalized and parsed', () => {
+ const pagination = {
+ 'X-nExt-pAge': '2',
+ 'X-page': '1',
+ 'X-Per-Page': '1',
+ 'X-Prev-Page': '2',
+ 'X-TOTAL': '37',
+ 'X-Total-Pages': '2',
+ };
+
+ const expectedResult = {
+ perPage: 1,
+ page: 1,
+ total: 37,
+ totalPages: 2,
+ nextPage: 2,
+ previousPage: 2,
+ };
+
+ store.storePagination(pagination);
+
+ expect(store.state.pageInfo).toEqual(expectedResult);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/tabs/pipeline_tabs_spec.js b/spec/frontend/ci/pipeline_details/tabs/pipeline_tabs_spec.js
new file mode 100644
index 00000000000..0f1835b7ec8
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/tabs/pipeline_tabs_spec.js
@@ -0,0 +1,114 @@
+import { GlTab } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import PipelineTabs from '~/ci/pipeline_details/tabs/pipeline_tabs.vue';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+
+describe('The Pipeline Tabs', () => {
+ let wrapper;
+ let trackingSpy;
+
+ const $router = { push: jest.fn() };
+
+ const findDagTab = () => wrapper.findByTestId('dag-tab');
+ const findFailedJobsTab = () => wrapper.findByTestId('failed-jobs-tab');
+ const findJobsTab = () => wrapper.findByTestId('jobs-tab');
+ const findPipelineTab = () => wrapper.findByTestId('pipeline-tab');
+ const findTestsTab = () => wrapper.findByTestId('tests-tab');
+
+ const findFailedJobsBadge = () => wrapper.findByTestId('failed-builds-counter');
+ const findJobsBadge = () => wrapper.findByTestId('builds-counter');
+ const findTestsBadge = () => wrapper.findByTestId('tests-counter');
+
+ const defaultProvide = {
+ defaultTabValue: '',
+ failedJobsCount: 1,
+ totalJobCount: 10,
+ testsCount: 123,
+ };
+
+ const createComponent = (provide = {}) => {
+ wrapper = shallowMountExtended(PipelineTabs, {
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ stubs: {
+ GlTab,
+ RouterView: true,
+ },
+ mocks: {
+ $router,
+ },
+ });
+ };
+
+ describe('Tabs', () => {
+ it.each`
+ tabName | tabComponent
+ ${'Pipeline'} | ${findPipelineTab}
+ ${'Dag'} | ${findDagTab}
+ ${'Jobs'} | ${findJobsTab}
+ ${'Failed Jobs'} | ${findFailedJobsTab}
+ ${'Tests'} | ${findTestsTab}
+ `('shows $tabName tab', ({ tabComponent }) => {
+ createComponent();
+
+ expect(tabComponent().exists()).toBe(true);
+ });
+
+ describe('with no failed jobs', () => {
+ beforeEach(() => {
+ createComponent({ failedJobsCount: 0 });
+ });
+
+ it('hides the failed jobs tab', () => {
+ expect(findFailedJobsTab().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('Tabs badges', () => {
+ it.each`
+ tabName | badgeComponent | badgeText
+ ${'Jobs'} | ${findJobsBadge} | ${String(defaultProvide.totalJobCount)}
+ ${'Failed Jobs'} | ${findFailedJobsBadge} | ${String(defaultProvide.failedJobsCount)}
+ ${'Tests'} | ${findTestsBadge} | ${String(defaultProvide.testsCount)}
+ `('shows badge for $tabName with the correct text', ({ badgeComponent, badgeText }) => {
+ createComponent();
+
+ expect(badgeComponent().exists()).toBe(true);
+ expect(badgeComponent().text()).toBe(badgeText);
+ });
+ });
+
+ describe('Tab tracking', () => {
+ beforeEach(() => {
+ createComponent();
+
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks failed jobs tab click', () => {
+ findFailedJobsTab().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', {
+ label: TRACKING_CATEGORIES.failed,
+ });
+ });
+
+ it('tracks tests tab click', () => {
+ findTestsTab().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', {
+ label: TRACKING_CATEGORIES.tests,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/empty_state_spec.js b/spec/frontend/ci/pipeline_details/test_reports/empty_state_spec.js
new file mode 100644
index 00000000000..ed1d6bc7d37
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/empty_state_spec.js
@@ -0,0 +1,45 @@
+import { GlEmptyState } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import EmptyState, { i18n } from '~/ci/pipeline_details/test_reports/empty_state.vue';
+
+describe('Test report empty state', () => {
+ let wrapper;
+
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+
+ const createComponent = ({ hasTestReport = true } = {}) => {
+ wrapper = shallowMount(EmptyState, {
+ provide: {
+ emptyStateImagePath: '/image/path',
+ hasTestReport,
+ },
+ stubs: {
+ GlEmptyState,
+ },
+ });
+ };
+
+ describe('when pipeline has a test report', () => {
+ it('should render empty test report message', () => {
+ createComponent();
+
+ expect(findEmptyState().props()).toMatchObject({
+ primaryButtonText: i18n.noTestsButton,
+ description: i18n.noTestsDescription,
+ title: i18n.noTestsTitle,
+ });
+ });
+ });
+
+ describe('when pipeline does not have a test report', () => {
+ it('should render no test report message', () => {
+ createComponent({ hasTestReport: false });
+
+ expect(findEmptyState().props()).toMatchObject({
+ primaryButtonText: i18n.noReportsButton,
+ description: i18n.noReportsDescription,
+ title: i18n.noReportsTitle,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/mock_data.js b/spec/frontend/ci/pipeline_details/test_reports/mock_data.js
new file mode 100644
index 00000000000..7c9f9287c86
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/mock_data.js
@@ -0,0 +1,31 @@
+import { TestStatus } from '~/ci/pipeline_details/constants';
+
+export default [
+ {
+ classname: 'spec.test_spec',
+ file: 'spec/trace_spec.rb',
+ execution_time: 0,
+ name: 'Test#skipped text',
+ stack_trace: null,
+ status: TestStatus.SKIPPED,
+ system_output: null,
+ },
+ {
+ classname: 'spec.test_spec',
+ file: 'spec/trace_spec.rb',
+ execution_time: 0,
+ name: 'Test#error text',
+ stack_trace: null,
+ status: TestStatus.ERROR,
+ system_output: null,
+ },
+ {
+ classname: 'spec.test_spec',
+ file: 'spec/trace_spec.rb',
+ execution_time: 0,
+ name: 'Test#unknown text',
+ stack_trace: null,
+ status: TestStatus.UNKNOWN,
+ system_output: null,
+ },
+];
diff --git a/spec/frontend/ci/pipeline_details/test_reports/stores/actions_spec.js b/spec/frontend/ci/pipeline_details/test_reports/stores/actions_spec.js
new file mode 100644
index 00000000000..6636a7f1ed6
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/stores/actions_spec.js
@@ -0,0 +1,149 @@
+import MockAdapter from 'axios-mock-adapter';
+import testReports from 'test_fixtures/pipelines/test_report.json';
+import { TEST_HOST } from 'helpers/test_constants';
+import testAction from 'helpers/vuex_action_helper';
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import * as actions from '~/ci/pipeline_details/stores/test_reports/actions';
+import * as types from '~/ci/pipeline_details/stores/test_reports/mutation_types';
+
+jest.mock('~/alert');
+
+describe('Actions TestReports Store', () => {
+ let mock;
+ let state;
+
+ const summary = { total_count: 1 };
+
+ const suiteEndpoint = `${TEST_HOST}/tests/suite.json`;
+ const summaryEndpoint = `${TEST_HOST}/test_reports/summary.json`;
+ const defaultState = {
+ suiteEndpoint,
+ summaryEndpoint,
+ testReports: {},
+ selectedSuite: null,
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ state = { ...defaultState };
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('fetch report summary', () => {
+ beforeEach(() => {
+ mock.onGet(summaryEndpoint).replyOnce(HTTP_STATUS_OK, summary, {});
+ });
+
+ it('sets testReports and shows tests', () => {
+ return testAction(
+ actions.fetchSummary,
+ null,
+ state,
+ [{ type: types.SET_SUMMARY, payload: summary }],
+ [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
+ );
+ });
+
+ it('should create alert on API error', async () => {
+ await testAction(
+ actions.fetchSummary,
+ null,
+ { summaryEndpoint: null },
+ [],
+ [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
+ );
+ expect(createAlert).toHaveBeenCalled();
+ });
+ });
+
+ describe('fetch test suite', () => {
+ beforeEach(() => {
+ const buildIds = [1];
+ testReports.test_suites[0].build_ids = buildIds;
+ mock
+ .onGet(suiteEndpoint, { params: { build_ids: buildIds } })
+ .replyOnce(HTTP_STATUS_OK, testReports.test_suites[0], {});
+ });
+
+ it('sets test suite and shows tests', () => {
+ const suite = testReports.test_suites[0];
+ const index = 0;
+
+ return testAction(
+ actions.fetchTestSuite,
+ index,
+ { ...state, testReports },
+ [{ type: types.SET_SUITE, payload: { suite, index } }],
+ [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
+ );
+ });
+
+ it('should call SET_SUITE_ERROR on error', () => {
+ const index = 0;
+
+ return testAction(
+ actions.fetchTestSuite,
+ index,
+ { ...state, testReports, suiteEndpoint: null },
+ [{ type: types.SET_SUITE_ERROR, payload: expect.any(Error) }],
+ [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
+ );
+ });
+
+ describe('when we already have the suite data', () => {
+ it('should not fetch suite', () => {
+ const index = 0;
+ testReports.test_suites[0].hasFullSuite = true;
+
+ return testAction(actions.fetchTestSuite, index, { ...state, testReports }, [], []);
+ });
+ });
+ });
+
+ describe('set selected suite index', () => {
+ it('sets selectedSuiteIndex', () => {
+ const selectedSuiteIndex = 0;
+
+ return testAction(
+ actions.setSelectedSuiteIndex,
+ selectedSuiteIndex,
+ { ...state, hasFullReport: true },
+ [{ type: types.SET_SELECTED_SUITE_INDEX, payload: selectedSuiteIndex }],
+ [],
+ );
+ });
+ });
+
+ describe('remove selected suite index', () => {
+ it('sets selectedSuiteIndex to null', () => {
+ return testAction(
+ actions.removeSelectedSuiteIndex,
+ {},
+ state,
+ [{ type: types.SET_SELECTED_SUITE_INDEX, payload: null }],
+ [],
+ );
+ });
+ });
+
+ describe('toggles loading', () => {
+ it('sets isLoading to true', () => {
+ return testAction(actions.toggleLoading, {}, state, [{ type: types.TOGGLE_LOADING }], []);
+ });
+
+ it('toggles isLoading to false', () => {
+ return testAction(
+ actions.toggleLoading,
+ {},
+ { ...state, isLoading: true },
+ [{ type: types.TOGGLE_LOADING }],
+ [],
+ );
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/stores/getters_spec.js b/spec/frontend/ci/pipeline_details/test_reports/stores/getters_spec.js
new file mode 100644
index 00000000000..e52e9a07ae0
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/stores/getters_spec.js
@@ -0,0 +1,171 @@
+import testReports from 'test_fixtures/pipelines/test_report.json';
+import * as getters from '~/ci/pipeline_details/stores/test_reports/getters';
+import {
+ iconForTestStatus,
+ formatFilePath,
+ formattedTime,
+} from '~/ci/pipeline_details/stores/test_reports/utils';
+
+describe('Getters TestReports Store', () => {
+ let state;
+
+ const defaultState = {
+ blobPath: '/test/blob/path',
+ testReports,
+ selectedSuiteIndex: 0,
+ pageInfo: {
+ page: 1,
+ perPage: 2,
+ },
+ };
+
+ const emptyState = {
+ blobPath: '',
+ testReports: {},
+ selectedSuite: null,
+ pageInfo: {
+ page: 1,
+ perPage: 2,
+ },
+ };
+
+ beforeEach(() => {
+ state = {
+ testReports,
+ };
+ });
+
+ const setupState = (testState = defaultState) => {
+ state = testState;
+ };
+
+ describe('getTestSuites', () => {
+ it('should return the test suites', () => {
+ setupState();
+
+ const suites = getters.getTestSuites(state);
+ const expected = testReports.test_suites.map((x) => ({
+ ...x,
+ formattedTime: formattedTime(x.total_time),
+ }));
+
+ expect(suites).toEqual(expected);
+ });
+
+ it('should return an empty array when testReports is empty', () => {
+ setupState(emptyState);
+
+ expect(getters.getTestSuites(state)).toEqual([]);
+ });
+ });
+
+ describe('getSelectedSuite', () => {
+ it('should return the selected suite', () => {
+ setupState();
+
+ const selectedSuite = getters.getSelectedSuite(state);
+ const expected = testReports.test_suites[state.selectedSuiteIndex];
+
+ expect(selectedSuite).toEqual(expected);
+ });
+ });
+
+ describe('getSuiteTests', () => {
+ it('should return the current page of test cases inside the suite', () => {
+ setupState();
+
+ const cases = getters.getSuiteTests(state);
+ const expected = testReports.test_suites[0].test_cases
+ .map((x) => ({
+ ...x,
+ filePath: `${state.blobPath}/${formatFilePath(x.file)}`,
+ formattedTime: formattedTime(x.execution_time),
+ icon: iconForTestStatus(x.status),
+ }))
+ .slice(0, state.pageInfo.perPage);
+
+ expect(cases).toEqual(expected);
+ });
+
+ it('should return an empty array when testReports is empty', () => {
+ setupState(emptyState);
+
+ expect(getters.getSuiteTests(state)).toEqual([]);
+ });
+
+ describe('when a test case classname property is null', () => {
+ it('should return an empty string value for the classname property', () => {
+ const testCases = testReports.test_suites[0].test_cases;
+ setupState({
+ ...defaultState,
+ testReports: {
+ ...testReports,
+ test_suites: [
+ {
+ test_cases: testCases.map((testCase) => ({
+ ...testCase,
+ classname: null,
+ })),
+ },
+ ],
+ },
+ });
+
+ const expected = testCases
+ .map((x) => ({
+ ...x,
+ classname: '',
+ filePath: `${state.blobPath}/${formatFilePath(x.file)}`,
+ formattedTime: formattedTime(x.execution_time),
+ icon: iconForTestStatus(x.status),
+ }))
+ .slice(0, state.pageInfo.perPage);
+
+ expect(getters.getSuiteTests(state)).toEqual(expected);
+ });
+ });
+
+ describe('when a test case name property is null', () => {
+ it('should return an empty string value for the name property', () => {
+ const testCases = testReports.test_suites[0].test_cases;
+ setupState({
+ ...defaultState,
+ testReports: {
+ ...testReports,
+ test_suites: [
+ {
+ test_cases: testCases.map((testCase) => ({
+ ...testCase,
+ name: null,
+ })),
+ },
+ ],
+ },
+ });
+
+ const expected = testCases
+ .map((x) => ({
+ ...x,
+ name: '',
+ filePath: `${state.blobPath}/${formatFilePath(x.file)}`,
+ formattedTime: formattedTime(x.execution_time),
+ icon: iconForTestStatus(x.status),
+ }))
+ .slice(0, state.pageInfo.perPage);
+
+ expect(getters.getSuiteTests(state)).toEqual(expected);
+ });
+ });
+ });
+
+ describe('getSuiteTestCount', () => {
+ it('should return the total number of test cases', () => {
+ setupState();
+
+ const testCount = getters.getSuiteTestCount(state);
+ const expected = testReports.test_suites[0].test_cases.length;
+
+ expect(testCount).toEqual(expected);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/stores/mutations_spec.js b/spec/frontend/ci/pipeline_details/test_reports/stores/mutations_spec.js
new file mode 100644
index 00000000000..d58515dcc6d
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/stores/mutations_spec.js
@@ -0,0 +1,114 @@
+import testReports from 'test_fixtures/pipelines/test_report.json';
+import * as types from '~/ci/pipeline_details/stores/test_reports/mutation_types';
+import mutations from '~/ci/pipeline_details/stores/test_reports/mutations';
+import { createAlert } from '~/alert';
+
+jest.mock('~/alert');
+
+describe('Mutations TestReports Store', () => {
+ let mockState;
+
+ const defaultState = {
+ endpoint: '',
+ testReports: {},
+ selectedSuite: null,
+ isLoading: false,
+ pageInfo: {
+ page: 1,
+ perPage: 2,
+ },
+ };
+
+ beforeEach(() => {
+ mockState = { ...defaultState };
+ });
+
+ describe('set page', () => {
+ it('should set the current page to display', () => {
+ const pageToDisplay = 3;
+ mutations[types.SET_PAGE](mockState, pageToDisplay);
+
+ expect(mockState.pageInfo.page).toEqual(pageToDisplay);
+ });
+ });
+
+ describe('set suite', () => {
+ it('should set the suite at the given index', () => {
+ mockState.testReports = testReports;
+ const suite = { name: 'test_suite' };
+ const index = 0;
+ const expectedState = { ...mockState };
+ expectedState.testReports.test_suites[index] = { suite, hasFullSuite: true };
+ mutations[types.SET_SUITE](mockState, { suite, index });
+
+ expect(mockState.testReports.test_suites[index]).toEqual(
+ expectedState.testReports.test_suites[index],
+ );
+ });
+ });
+
+ describe('set suite error', () => {
+ it('should set the error message in state if provided', () => {
+ const message = 'Test report artifacts not found';
+
+ mutations[types.SET_SUITE_ERROR](mockState, {
+ response: { data: { errors: message } },
+ });
+
+ expect(mockState.errorMessage).toBe(message);
+ });
+
+ it('should show an alert otherwise', () => {
+ mutations[types.SET_SUITE_ERROR](mockState, {});
+
+ expect(createAlert).toHaveBeenCalled();
+ });
+ });
+
+ describe('set selected suite index', () => {
+ it('should set selectedSuiteIndex', () => {
+ const selectedSuiteIndex = 0;
+ mutations[types.SET_SELECTED_SUITE_INDEX](mockState, selectedSuiteIndex);
+
+ expect(mockState.selectedSuiteIndex).toEqual(selectedSuiteIndex);
+ });
+ });
+
+ describe('set summary', () => {
+ it('should set summary', () => {
+ const summary = {
+ total: { time: 0, count: 10, success: 1, failed: 2, skipped: 3, error: 4 },
+ };
+ const expectedSummary = {
+ ...summary,
+ total_time: 0,
+ total_count: 10,
+ success_count: 1,
+ failed_count: 2,
+ skipped_count: 3,
+ error_count: 4,
+ };
+ mutations[types.SET_SUMMARY](mockState, summary);
+
+ expect(mockState.testReports).toEqual(expectedSummary);
+ });
+ });
+
+ describe('toggle loading', () => {
+ it('should set to true', () => {
+ const expectedState = { ...mockState, isLoading: true };
+ mutations[types.TOGGLE_LOADING](mockState);
+
+ expect(mockState.isLoading).toEqual(expectedState.isLoading);
+ });
+
+ it('should toggle back to false', () => {
+ const expectedState = { ...mockState, isLoading: false };
+ mockState.isLoading = true;
+
+ mutations[types.TOGGLE_LOADING](mockState);
+
+ expect(mockState.isLoading).toEqual(expectedState.isLoading);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/stores/utils_spec.js b/spec/frontend/ci/pipeline_details/test_reports/stores/utils_spec.js
new file mode 100644
index 00000000000..c0ffc2b34fb
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/stores/utils_spec.js
@@ -0,0 +1,40 @@
+import { formatFilePath, formattedTime } from '~/ci/pipeline_details/stores/test_reports/utils';
+
+describe('Test reports utils', () => {
+ describe('formatFilePath', () => {
+ it.each`
+ file | expected
+ ${'./test.js'} | ${'test.js'}
+ ${'/test.js'} | ${'test.js'}
+ ${'.//////////////test.js'} | ${'test.js'}
+ ${'test.js'} | ${'test.js'}
+ ${'mock/path./test.js'} | ${'mock/path./test.js'}
+ ${'./mock/path./test.js'} | ${'mock/path./test.js'}
+ `('should format $file to be $expected', ({ file, expected }) => {
+ expect(formatFilePath(file)).toBe(expected);
+ });
+ });
+
+ describe('formattedTime', () => {
+ describe('when time is smaller than a second', () => {
+ it('should return time in milliseconds fixed to 2 decimals', () => {
+ const result = formattedTime(0.4815162342);
+ expect(result).toBe('481.52ms');
+ });
+ });
+
+ describe('when time is equal to a second', () => {
+ it('should return time in seconds fixed to 2 decimals', () => {
+ const result = formattedTime(1);
+ expect(result).toBe('1.00s');
+ });
+ });
+
+ describe('when time is greater than a second', () => {
+ it('should return time in seconds fixed to 2 decimals', () => {
+ const result = formattedTime(4.815162342);
+ expect(result).toBe('4.82s');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/test_case_details_spec.js b/spec/frontend/ci/pipeline_details/test_reports/test_case_details_spec.js
new file mode 100644
index 00000000000..0f651b9d456
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/test_case_details_spec.js
@@ -0,0 +1,149 @@
+import { GlModal, GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import TestCaseDetails from '~/ci/pipeline_details/test_reports/test_case_details.vue';
+import CodeBlock from '~/vue_shared/components/code_block.vue';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
+
+describe('Test case details', () => {
+ let wrapper;
+ const defaultTestCase = {
+ classname: 'spec.test_spec',
+ name: 'Test#something cool',
+ file: '~/index.js',
+ filePath: '/src/javascripts/index.js',
+ formattedTime: '10.04ms',
+ recent_failures: {
+ count: 2,
+ base_branch: 'main',
+ },
+ system_output: 'Line 42 is broken',
+ };
+
+ const findCopyFileBtn = () => wrapper.findComponent(ModalCopyButton);
+ const findModal = () => wrapper.findComponent(GlModal);
+ const findName = () => wrapper.findByTestId('test-case-name');
+ const findFile = () => wrapper.findByTestId('test-case-file');
+ const findFileLink = () => wrapper.findComponent(GlLink);
+ const findDuration = () => wrapper.findByTestId('test-case-duration');
+ const findRecentFailures = () => wrapper.findByTestId('test-case-recent-failures');
+ const findAttachmentUrl = () => wrapper.findByTestId('test-case-attachment-url');
+ const findSystemOutput = () => wrapper.findByTestId('test-case-trace');
+
+ const createComponent = (testCase = {}) => {
+ wrapper = extendedWrapper(
+ shallowMount(TestCaseDetails, {
+ propsData: {
+ modalId: 'my-modal',
+ testCase: {
+ ...defaultTestCase,
+ ...testCase,
+ },
+ },
+ stubs: { CodeBlock, GlModal },
+ }),
+ );
+ };
+
+ describe('required details', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the test case classname as modal title', () => {
+ expect(findModal().props('title')).toBe(defaultTestCase.classname);
+ });
+
+ it('renders the test case name', () => {
+ expect(findName().text()).toBe(defaultTestCase.name);
+ });
+
+ it('renders the test case file', () => {
+ expect(findFile().text()).toBe(defaultTestCase.file);
+ expect(findFileLink().attributes('href')).toBe(defaultTestCase.filePath);
+ });
+
+ it('renders copy button for test case file', () => {
+ expect(findCopyFileBtn().attributes('text')).toBe(defaultTestCase.file);
+ });
+
+ it('renders the test case duration', () => {
+ expect(findDuration().text()).toBe(defaultTestCase.formattedTime);
+ });
+ });
+
+ describe('when test case has execution time instead of formatted time', () => {
+ beforeEach(() => {
+ createComponent({ ...defaultTestCase, formattedTime: null, execution_time: 17 });
+ });
+
+ it('renders the test case duration', () => {
+ expect(findDuration().text()).toBe('17 s');
+ });
+ });
+
+ describe('when test case has recent failures', () => {
+ describe('has only 1 recent failure', () => {
+ it('renders the recent failure', () => {
+ createComponent({ recent_failures: { ...defaultTestCase.recent_failures, count: 1 } });
+
+ expect(findRecentFailures().text()).toContain(
+ `Failed 1 time in ${defaultTestCase.recent_failures.base_branch} in the last 14 days`,
+ );
+ });
+ });
+
+ describe('has more than 1 recent failure', () => {
+ it('renders the recent failures', () => {
+ createComponent();
+
+ expect(findRecentFailures().text()).toContain(
+ `Failed ${defaultTestCase.recent_failures.count} times in ${defaultTestCase.recent_failures.base_branch} in the last 14 days`,
+ );
+ });
+ });
+ });
+
+ describe('when test case does not have recent failures', () => {
+ it('does not render the recent failures', () => {
+ createComponent({ recent_failures: null });
+
+ expect(findRecentFailures().exists()).toBe(false);
+ });
+ });
+
+ describe('when test case has attachment URL', () => {
+ it('renders the attachment URL as a link', () => {
+ const expectedUrl = '/my/path.jpg';
+ createComponent({ attachment_url: expectedUrl });
+ const attachmentUrl = findAttachmentUrl();
+
+ expect(attachmentUrl.exists()).toBe(true);
+ expect(attachmentUrl.attributes('href')).toBe(expectedUrl);
+ });
+ });
+
+ describe('when test case does not have attachment URL', () => {
+ it('does not render the attachment URL', () => {
+ createComponent({ attachment_url: null });
+
+ expect(findAttachmentUrl().exists()).toBe(false);
+ });
+ });
+
+ describe('when test case has system output', () => {
+ it('renders the test case system output', () => {
+ createComponent();
+
+ expect(findSystemOutput().text()).toContain(defaultTestCase.system_output);
+ });
+ });
+
+ describe('when test case does not have system output', () => {
+ it('does not render the test case system output', () => {
+ createComponent({ system_output: null });
+
+ expect(findSystemOutput().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/test_reports_spec.js b/spec/frontend/ci/pipeline_details/test_reports/test_reports_spec.js
new file mode 100644
index 00000000000..8ff060026da
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/test_reports_spec.js
@@ -0,0 +1,125 @@
+import { GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import testReports from 'test_fixtures/pipelines/test_report.json';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import EmptyState from '~/ci/pipeline_details/test_reports/empty_state.vue';
+import TestReports from '~/ci/pipeline_details/test_reports/test_reports.vue';
+import TestSummary from '~/ci/pipeline_details/test_reports/test_summary.vue';
+import TestSummaryTable from '~/ci/pipeline_details/test_reports/test_summary_table.vue';
+import * as getters from '~/ci/pipeline_details/stores/test_reports/getters';
+
+Vue.use(Vuex);
+
+describe('Test reports app', () => {
+ let wrapper;
+ let store;
+
+ const loadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
+ const testsDetail = () => wrapper.findByTestId('tests-detail');
+ const emptyState = () => wrapper.findComponent(EmptyState);
+ const testSummary = () => wrapper.findComponent(TestSummary);
+ const testSummaryTable = () => wrapper.findComponent(TestSummaryTable);
+
+ const actionSpies = {
+ fetchTestSuite: jest.fn(),
+ fetchSummary: jest.fn(),
+ setSelectedSuiteIndex: jest.fn(),
+ removeSelectedSuiteIndex: jest.fn(),
+ };
+
+ const createComponent = ({ state = {} } = {}) => {
+ store = new Vuex.Store({
+ modules: {
+ testReports: {
+ namespaced: true,
+ state: {
+ isLoading: false,
+ selectedSuiteIndex: null,
+ testReports,
+ ...state,
+ },
+ actions: actionSpies,
+ getters,
+ },
+ },
+ });
+
+ jest.spyOn(store, 'registerModule').mockReturnValue(null);
+
+ wrapper = extendedWrapper(
+ shallowMount(TestReports, {
+ provide: {
+ blobPath: '/blob/path',
+ summaryEndpoint: '/summary.json',
+ suiteEndpoint: '/suite.json',
+ },
+ store,
+ }),
+ );
+ };
+
+ describe('when component is created', () => {
+ it('should call fetchSummary when pipeline has test report', () => {
+ createComponent();
+
+ expect(actionSpies.fetchSummary).toHaveBeenCalled();
+ });
+ });
+
+ describe('when loading', () => {
+ beforeEach(() => createComponent({ state: { isLoading: true } }));
+
+ it('shows the loading spinner', () => {
+ expect(emptyState().exists()).toBe(false);
+ expect(testsDetail().exists()).toBe(false);
+ expect(loadingSpinner().exists()).toBe(true);
+ });
+ });
+
+ describe('when the api returns no data', () => {
+ it('displays empty state component', () => {
+ createComponent({ state: { testReports: {} } });
+
+ expect(emptyState().exists()).toBe(true);
+ });
+ });
+
+ describe('when the api returns data', () => {
+ beforeEach(() => createComponent());
+
+ it('sets testReports and shows tests', () => {
+ expect(wrapper.vm.testReports).toEqual(expect.any(Object));
+ expect(wrapper.vm.showTests).toBe(true);
+ });
+
+ it('shows tests details', () => {
+ expect(testsDetail().exists()).toBe(true);
+ });
+ });
+
+ describe('when a suite is clicked', () => {
+ beforeEach(() => {
+ createComponent({ state: { hasFullReport: true } });
+ testSummaryTable().vm.$emit('row-click', 0);
+ });
+
+ it('should call setSelectedSuiteIndex and fetchTestSuite', () => {
+ expect(actionSpies.setSelectedSuiteIndex).toHaveBeenCalled();
+ expect(actionSpies.fetchTestSuite).toHaveBeenCalled();
+ });
+ });
+
+ describe('when clicking back to summary', () => {
+ beforeEach(() => {
+ createComponent({ state: { selectedSuiteIndex: 0 } });
+ testSummary().vm.$emit('on-back-click');
+ });
+
+ it('should call removeSelectedSuiteIndex', () => {
+ expect(actionSpies.removeSelectedSuiteIndex).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/test_suite_table_spec.js b/spec/frontend/ci/pipeline_details/test_reports/test_suite_table_spec.js
new file mode 100644
index 00000000000..5bdea6bbcbf
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/test_suite_table_spec.js
@@ -0,0 +1,169 @@
+import { GlButton, GlFriendlyWrap, GlLink, GlPagination, GlEmptyState } from '@gitlab/ui';
+import Vue from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import testReports from 'test_fixtures/pipelines/test_report.json';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import SuiteTable, { i18n } from '~/ci/pipeline_details/test_reports/test_suite_table.vue';
+import { TestStatus } from '~/ci/pipeline_details/constants';
+import * as getters from '~/ci/pipeline_details/stores/test_reports/getters';
+import { formatFilePath } from '~/ci/pipeline_details/stores/test_reports/utils';
+import { ARTIFACTS_EXPIRED_ERROR_MESSAGE } from '~/ci/pipeline_details/stores/test_reports/constants';
+import skippedTestCases from './mock_data';
+
+Vue.use(Vuex);
+
+describe('Test reports suite table', () => {
+ let wrapper;
+ let store;
+
+ const {
+ test_suites: [testSuite],
+ } = testReports;
+
+ testSuite.test_cases = [...testSuite.test_cases, ...skippedTestCases];
+ const testCases = testSuite.test_cases;
+ const blobPath = '/test/blob/path';
+
+ const noCasesMessage = () => wrapper.findByTestId('no-test-cases');
+ const artifactsExpiredMessage = () => wrapper.findByTestId('artifacts-expired');
+ const artifactsExpiredEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const allCaseRows = () => wrapper.findAllByTestId('test-case-row');
+ const findCaseRowAtIndex = (index) => wrapper.findAllByTestId('test-case-row').at(index);
+ const findLinkForRow = (row) => row.findComponent(GlLink);
+ const findIconForRow = (row, status) => row.find(`.ci-status-icon-${status}`);
+
+ const createComponent = ({ suite = testSuite, perPage = 20, errorMessage } = {}) => {
+ store = new Vuex.Store({
+ modules: {
+ testReports: {
+ namespaced: true,
+ state: {
+ blobPath,
+ testReports: {
+ test_suites: [suite],
+ },
+ selectedSuiteIndex: 0,
+ pageInfo: {
+ page: 1,
+ perPage,
+ },
+ errorMessage,
+ },
+ getters,
+ },
+ },
+ });
+
+ wrapper = shallowMountExtended(SuiteTable, {
+ provide: {
+ blobPath: '/blob/path',
+ summaryEndpoint: '/summary.json',
+ suiteEndpoint: '/suite.json',
+ },
+ store,
+ stubs: { GlFriendlyWrap },
+ });
+ };
+
+ it('should render a message when there are no test cases', () => {
+ createComponent({ suite: [] });
+
+ expect(noCasesMessage().exists()).toBe(true);
+ expect(artifactsExpiredMessage().exists()).toBe(false);
+ });
+
+ it('should render an empty state when artifacts have expired', () => {
+ createComponent({ suite: [], errorMessage: ARTIFACTS_EXPIRED_ERROR_MESSAGE });
+ const emptyState = artifactsExpiredEmptyState();
+
+ expect(noCasesMessage().exists()).toBe(false);
+ expect(artifactsExpiredMessage().exists()).toBe(true);
+
+ expect(emptyState.exists()).toBe(true);
+ expect(emptyState.props('title')).toBe(i18n.expiredArtifactsTitle);
+ });
+
+ describe('when a test suite is supplied', () => {
+ beforeEach(() => createComponent());
+
+ it('renders the correct number of rows', () => {
+ expect(allCaseRows()).toHaveLength(testCases.length);
+ });
+
+ it.each([
+ TestStatus.ERROR,
+ TestStatus.FAILED,
+ TestStatus.SKIPPED,
+ TestStatus.SUCCESS,
+ 'unknown',
+ ])('renders the correct icon for test case with %s status', (status) => {
+ const test = testCases.findIndex((x) => x.status === status);
+ const row = findCaseRowAtIndex(test);
+
+ expect(findIconForRow(row, status).exists()).toBe(true);
+ });
+
+ it('renders the file name for the test with a copy button', () => {
+ const { file } = testCases[0];
+ const relativeFile = formatFilePath(file);
+ const filePath = `${blobPath}/${relativeFile}`;
+ const row = findCaseRowAtIndex(0);
+ const fileLink = findLinkForRow(row);
+ const button = row.findComponent(GlButton);
+
+ expect(fileLink.attributes('href')).toBe(filePath);
+ expect(row.text()).toContain(file);
+ expect(button.exists()).toBe(true);
+ expect(button.attributes('data-clipboard-text')).toBe(file);
+ });
+ });
+
+ describe('when a test suite has more test cases than the pagination size', () => {
+ const perPage = 2;
+
+ beforeEach(() => {
+ createComponent({ testSuite, perPage });
+ });
+
+ it('renders one page of test cases', () => {
+ expect(allCaseRows().length).toBe(perPage);
+ });
+
+ it('renders a pagination component', () => {
+ expect(wrapper.findComponent(GlPagination).exists()).toBe(true);
+ });
+ });
+
+ describe('when a test case classname property is null', () => {
+ it('still renders all test cases', () => {
+ createComponent({
+ testSuite: {
+ ...testSuite,
+ test_cases: testSuite.test_cases.map((testCase) => ({
+ ...testCase,
+ classname: null,
+ })),
+ },
+ });
+
+ expect(allCaseRows()).toHaveLength(testCases.length);
+ });
+ });
+
+ describe('when a test case name property is null', () => {
+ it('still renders all test cases', () => {
+ createComponent({
+ testSuite: {
+ ...testSuite,
+ test_cases: testSuite.test_cases.map((testCase) => ({
+ ...testCase,
+ name: null,
+ })),
+ },
+ });
+
+ expect(allCaseRows()).toHaveLength(testCases.length);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/test_summary_spec.js b/spec/frontend/ci/pipeline_details/test_reports/test_summary_spec.js
new file mode 100644
index 00000000000..f9182d52c8a
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/test_summary_spec.js
@@ -0,0 +1,106 @@
+import { mount } from '@vue/test-utils';
+import testReports from 'test_fixtures/pipelines/test_report.json';
+import Summary from '~/ci/pipeline_details/test_reports/test_summary.vue';
+import { formattedTime } from '~/ci/pipeline_details/stores/test_reports/utils';
+
+describe('Test reports summary', () => {
+ let wrapper;
+
+ const {
+ test_suites: [testSuite],
+ } = testReports;
+
+ const backButton = () => wrapper.find('.js-back-button');
+ const totalTests = () => wrapper.find('.js-total-tests');
+ const failedTests = () => wrapper.find('.js-failed-tests');
+ const erroredTests = () => wrapper.find('.js-errored-tests');
+ const successRate = () => wrapper.find('.js-success-rate');
+ const duration = () => wrapper.find('.js-duration');
+
+ const defaultProps = {
+ report: testSuite,
+ showBack: false,
+ };
+
+ const createComponent = (props) => {
+ wrapper = mount(Summary, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ describe('should not render', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('a back button by default', () => {
+ expect(backButton().exists()).toBe(false);
+ });
+ });
+
+ describe('should render', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('a back button and emit on-back-click event', () => {
+ createComponent({
+ showBack: true,
+ });
+
+ expect(backButton().exists()).toBe(true);
+ });
+ });
+
+ describe('when a report is supplied', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays the correct total', () => {
+ expect(totalTests().text()).toBe('4 tests');
+ });
+
+ it('displays the correct failure count', () => {
+ expect(failedTests().text()).toBe('2 failures');
+ });
+
+ it('displays the correct error count', () => {
+ expect(erroredTests().text()).toBe('0 errors');
+ });
+
+ it('calculates and displays percentages correctly', () => {
+ expect(successRate().text()).toBe('50% success rate');
+ });
+
+ it('displays the correctly formatted duration', () => {
+ expect(duration().text()).toBe(formattedTime(testSuite.total_time));
+ });
+ });
+
+ describe('success percentage calculation', () => {
+ it.each`
+ name | successCount | totalCount | skippedCount | result
+ ${'displays 0 when there are no tests'} | ${0} | ${0} | ${0} | ${'0'}
+ ${'displays whole number when possible'} | ${10} | ${50} | ${0} | ${'20'}
+ ${'excludes skipped tests from total'} | ${10} | ${50} | ${5} | ${'22.22'}
+ ${'rounds to 0.01'} | ${1} | ${16604} | ${0} | ${'0.01'}
+ ${'correctly rounds to 50'} | ${8302} | ${16604} | ${0} | ${'50'}
+ ${'rounds down for large close numbers'} | ${16603} | ${16604} | ${0} | ${'99.99'}
+ ${'correctly displays 100'} | ${16604} | ${16604} | ${0} | ${'100'}
+ `('$name', ({ successCount, totalCount, skippedCount, result }) => {
+ createComponent({
+ report: {
+ success_count: successCount,
+ skipped_count: skippedCount,
+ total_count: totalCount,
+ },
+ });
+
+ expect(successRate().text()).toBe(`${result}% success rate`);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/test_reports/test_summary_table_spec.js b/spec/frontend/ci/pipeline_details/test_reports/test_summary_table_spec.js
new file mode 100644
index 00000000000..bb62fbcb32c
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/test_reports/test_summary_table_spec.js
@@ -0,0 +1,100 @@
+import { mount } from '@vue/test-utils';
+import Vue from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import testReports from 'test_fixtures/pipelines/test_report.json';
+import SummaryTable from '~/ci/pipeline_details/test_reports/test_summary_table.vue';
+import * as getters from '~/ci/pipeline_details/stores/test_reports/getters';
+
+Vue.use(Vuex);
+
+describe('Test reports summary table', () => {
+ let wrapper;
+ let store;
+
+ const allSuitesRows = () => wrapper.findAll('.js-suite-row');
+ const noSuitesToShow = () => wrapper.find('.js-no-tests-suites');
+
+ const defaultProps = {
+ testReports,
+ };
+
+ const createComponent = (reports = null) => {
+ store = new Vuex.Store({
+ modules: {
+ testReports: {
+ namespaced: true,
+ state: {
+ testReports: reports || testReports,
+ },
+ getters,
+ },
+ },
+ });
+
+ wrapper = mount(SummaryTable, {
+ provide: {
+ blobPath: '/blob/path',
+ summaryEndpoint: '/summary.json',
+ suiteEndpoint: '/suite.json',
+ },
+ propsData: defaultProps,
+ store,
+ });
+ };
+
+ describe('when test reports are supplied', () => {
+ beforeEach(() => createComponent());
+ const findErrorIcon = () => wrapper.findComponent({ ref: 'suiteErrorIcon' });
+
+ it('renders the correct number of rows', () => {
+ expect(noSuitesToShow().exists()).toBe(false);
+ expect(allSuitesRows().length).toBe(testReports.test_suites.length);
+ });
+
+ describe('when there is a suite error', () => {
+ beforeEach(() => {
+ createComponent({
+ test_suites: [
+ {
+ ...testReports.test_suites[0],
+ suite_error: 'Suite Error',
+ },
+ ],
+ });
+ });
+
+ it('renders error icon', () => {
+ expect(findErrorIcon().exists()).toBe(true);
+ expect(findErrorIcon().attributes('title')).toEqual('Suite Error');
+ });
+ });
+
+ describe('when there is not a suite error', () => {
+ beforeEach(() => {
+ createComponent({
+ test_suites: [
+ {
+ ...testReports.test_suites[0],
+ suite_error: null,
+ },
+ ],
+ });
+ });
+
+ it('does not render error icon', () => {
+ expect(findErrorIcon().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('when there are no test suites', () => {
+ beforeEach(() => {
+ createComponent({ test_suites: [] });
+ });
+
+ it('displays the no suites to show message', () => {
+ expect(noSuitesToShow().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/utils/index_spec.js b/spec/frontend/ci/pipeline_details/utils/index_spec.js
new file mode 100644
index 00000000000..61230cb52e6
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/utils/index_spec.js
@@ -0,0 +1,201 @@
+import {
+ createJobsHash,
+ generateJobNeedsDict,
+ getPipelineDefaultTab,
+} from '~/ci/pipeline_details/utils';
+import { validPipelineTabNames, pipelineTabName } from '~/ci/pipeline_details/constants';
+
+describe('utils functions', () => {
+ const jobName1 = 'build_1';
+ const jobName2 = 'build_2';
+ const jobName3 = 'test_1';
+ const jobName4 = 'deploy_1';
+ const job1 = { name: jobName1, script: 'echo hello', stage: 'build' };
+ const job2 = { name: jobName2, script: 'echo build', stage: 'build' };
+ const job3 = {
+ name: jobName3,
+ script: 'echo test',
+ stage: 'test',
+ needs: [jobName1, jobName2],
+ };
+ const job4 = {
+ name: jobName4,
+ script: 'echo deploy',
+ stage: 'deploy',
+ needs: [jobName3],
+ };
+ const userDefinedStage = 'myStage';
+
+ const pipelineGraphData = {
+ stages: [
+ {
+ name: userDefinedStage,
+ groups: [],
+ },
+ {
+ name: job4.stage,
+ groups: [
+ {
+ name: jobName4,
+ jobs: [{ ...job4 }],
+ },
+ ],
+ },
+ {
+ name: job1.stage,
+ groups: [
+ {
+ name: jobName1,
+ jobs: [{ ...job1 }],
+ },
+ {
+ name: jobName2,
+ jobs: [{ ...job2 }],
+ },
+ ],
+ },
+ {
+ name: job3.stage,
+ groups: [
+ {
+ name: jobName3,
+ jobs: [{ ...job3 }],
+ },
+ ],
+ },
+ ],
+ };
+
+ describe('createJobsHash', () => {
+ it('returns an empty object if there are no jobs received as argument', () => {
+ expect(createJobsHash([])).toEqual({});
+ });
+
+ it('returns a hash with the jobname as key and all its data as value', () => {
+ const jobs = {
+ [jobName1]: { jobs: [job1], name: jobName1, needs: [] },
+ [jobName2]: { jobs: [job2], name: jobName2, needs: [] },
+ [jobName3]: { jobs: [job3], name: jobName3, needs: job3.needs },
+ [jobName4]: { jobs: [job4], name: jobName4, needs: job4.needs },
+ };
+
+ expect(createJobsHash(pipelineGraphData.stages)).toEqual(jobs);
+ });
+ });
+
+ describe('generateJobNeedsDict', () => {
+ it('generates an empty object if it receives no jobs', () => {
+ expect(generateJobNeedsDict({})).toEqual({});
+ });
+
+ it('generates a dict with empty needs if there are no dependencies', () => {
+ const smallGraph = {
+ [jobName1]: job1,
+ [jobName2]: job2,
+ };
+
+ expect(generateJobNeedsDict(smallGraph)).toEqual({
+ [jobName1]: [],
+ [jobName2]: [],
+ });
+ });
+
+ it('generates a dict where key is the a job and its value is an array of all its needs', () => {
+ const jobsWithNeeds = {
+ [jobName1]: job1,
+ [jobName2]: job2,
+ [jobName3]: job3,
+ [jobName4]: job4,
+ };
+
+ expect(generateJobNeedsDict(jobsWithNeeds)).toEqual({
+ [jobName1]: [],
+ [jobName2]: [],
+ [jobName3]: [jobName1, jobName2],
+ [jobName4]: [jobName3, jobName1, jobName2],
+ });
+ });
+
+ it('removes needs which are not in the data', () => {
+ const inexistantJobName = 'job5';
+ const jobsWithNeeds = {
+ [jobName1]: job1,
+ [jobName2]: job2,
+ [jobName3]: job3,
+ [jobName4]: {
+ name: jobName4,
+ script: 'echo deploy',
+ stage: 'deploy',
+ needs: [inexistantJobName],
+ },
+ };
+
+ expect(generateJobNeedsDict(jobsWithNeeds)).toEqual({
+ [jobName1]: [],
+ [jobName2]: [],
+ [jobName3]: [jobName1, jobName2],
+ [jobName4]: [],
+ });
+ });
+
+ it('handles parallel jobs by adding the group name as a need', () => {
+ const size = 3;
+ const jobOptimize1 = 'optimize_1';
+ const jobPrepareA = 'prepare_a';
+ const jobPrepareA1 = `${jobPrepareA} 1/${size}`;
+ const jobPrepareA2 = `${jobPrepareA} 2/${size}`;
+ const jobPrepareA3 = `${jobPrepareA} 3/${size}`;
+
+ const jobsParallel = {
+ [jobOptimize1]: {
+ jobs: [job1],
+ name: [jobOptimize1],
+ needs: [jobPrepareA1, jobPrepareA2, jobPrepareA3],
+ },
+ [jobPrepareA]: { jobs: [], name: jobPrepareA, needs: [], size },
+ [jobPrepareA1]: { jobs: [], name: jobPrepareA, needs: [], size },
+ [jobPrepareA2]: { jobs: [], name: jobPrepareA, needs: [], size },
+ [jobPrepareA3]: { jobs: [], name: jobPrepareA, needs: [], size },
+ };
+
+ expect(generateJobNeedsDict(jobsParallel)).toEqual({
+ [jobOptimize1]: [
+ jobPrepareA1,
+ // This is the important part, the `jobPrepareA` group name has been
+ // added to our list of needs.
+ jobPrepareA,
+ jobPrepareA2,
+ jobPrepareA3,
+ ],
+ [jobPrepareA]: [],
+ [jobPrepareA1]: [],
+ [jobPrepareA2]: [],
+ [jobPrepareA3]: [],
+ });
+ });
+ });
+
+ describe('getPipelineDefaultTab', () => {
+ const baseUrl = 'http://gitlab.com/user/multi-projects-small/-/pipelines/332/';
+ it('returns pipeline tab name if there is only the base url', () => {
+ expect(getPipelineDefaultTab(baseUrl)).toBe(pipelineTabName);
+ });
+
+ it('returns null if there was no valid last url part', () => {
+ expect(getPipelineDefaultTab(`${baseUrl}something`)).toBe(null);
+ });
+
+ it('returns the correct tab name if present', () => {
+ validPipelineTabNames.forEach((tabName) => {
+ expect(getPipelineDefaultTab(`${baseUrl}${tabName}`)).toBe(tabName);
+ });
+ });
+
+ it('returns the right value even with query params', () => {
+ const [tabName] = validPipelineTabNames;
+ expect(getPipelineDefaultTab(`${baseUrl}${tabName}?query="something"&query2="else"`)).toBe(
+ tabName,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/utils/parsing_utils_spec.js b/spec/frontend/ci/pipeline_details/utils/parsing_utils_spec.js
new file mode 100644
index 00000000000..9390f076d3d
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/utils/parsing_utils_spec.js
@@ -0,0 +1,191 @@
+import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
+import { createSankey } from '~/ci/pipeline_details/dag/utils/drawing_utils';
+import {
+ makeLinksFromNodes,
+ filterByAncestors,
+ generateColumnsFromLayersListBare,
+ keepLatestDownstreamPipelines,
+ listByLayers,
+ parseData,
+ removeOrphanNodes,
+ getMaxNodes,
+} from '~/ci/pipeline_details/utils/parsing_utils';
+import { createNodeDict } from '~/ci/pipeline_details/utils';
+
+import { mockDownstreamPipelinesRest } from '../../../vue_merge_request_widget/mock_data';
+import { mockDownstreamPipelinesGraphql } from '../../../commit/mock_data';
+import { mockParsedGraphQLNodes, missingJob } from '../dag/mock_data';
+import { generateResponse } from '../graph/mock_data';
+
+describe('DAG visualization parsing utilities', () => {
+ const nodeDict = createNodeDict(mockParsedGraphQLNodes);
+ const unfilteredLinks = makeLinksFromNodes(mockParsedGraphQLNodes, nodeDict);
+ const parsed = parseData(mockParsedGraphQLNodes);
+
+ describe('makeLinksFromNodes', () => {
+ it('returns the expected link structure', () => {
+ expect(unfilteredLinks[0]).toHaveProperty('source', 'build_a');
+ expect(unfilteredLinks[0]).toHaveProperty('target', 'test_a');
+ expect(unfilteredLinks[0]).toHaveProperty('value', 10);
+ });
+
+ it('does not generate a link for non-existing jobs', () => {
+ const sources = unfilteredLinks.map(({ source }) => source);
+
+ expect(sources.includes(missingJob)).toBe(false);
+ });
+ });
+
+ describe('filterByAncestors', () => {
+ const allLinks = [
+ { source: 'job1', target: 'job4' },
+ { source: 'job1', target: 'job2' },
+ { source: 'job2', target: 'job4' },
+ ];
+
+ const dedupedLinks = [
+ { source: 'job1', target: 'job2' },
+ { source: 'job2', target: 'job4' },
+ ];
+
+ const nodeLookup = {
+ job1: {
+ name: 'job1',
+ },
+ job2: {
+ name: 'job2',
+ needs: ['job1'],
+ },
+ job4: {
+ name: 'job4',
+ needs: ['job1', 'job2'],
+ category: 'build',
+ },
+ };
+
+ it('dedupes links', () => {
+ expect(filterByAncestors(allLinks, nodeLookup)).toMatchObject(dedupedLinks);
+ });
+ });
+
+ describe('parseData parent function', () => {
+ it('returns an object containing a list of nodes and links', () => {
+ // an array of nodes exist and the values are defined
+ expect(parsed).toHaveProperty('nodes');
+ expect(Array.isArray(parsed.nodes)).toBe(true);
+ expect(parsed.nodes.filter(Boolean)).not.toHaveLength(0);
+
+ // an array of links exist and the values are defined
+ expect(parsed).toHaveProperty('links');
+ expect(Array.isArray(parsed.links)).toBe(true);
+ expect(parsed.links.filter(Boolean)).not.toHaveLength(0);
+ });
+ });
+
+ describe('removeOrphanNodes', () => {
+ it('removes sankey nodes that have no needs and are not needed', () => {
+ const layoutSettings = {
+ width: 200,
+ height: 200,
+ nodeWidth: 10,
+ nodePadding: 20,
+ paddingForLabels: 100,
+ };
+
+ const sankeyLayout = createSankey(layoutSettings)(parsed);
+ const cleanedNodes = removeOrphanNodes(sankeyLayout.nodes);
+ /*
+ These lengths are determined by the mock data.
+ If the data changes, the numbers may also change.
+ */
+ expect(parsed.nodes).toHaveLength(mockParsedGraphQLNodes.length);
+ expect(cleanedNodes).toHaveLength(12);
+ });
+ });
+
+ describe('getMaxNodes', () => {
+ it('returns the number of nodes in the most populous generation', () => {
+ const layerNodes = [
+ { layer: 0 },
+ { layer: 0 },
+ { layer: 1 },
+ { layer: 1 },
+ { layer: 0 },
+ { layer: 3 },
+ { layer: 2 },
+ { layer: 4 },
+ { layer: 1 },
+ { layer: 3 },
+ { layer: 4 },
+ ];
+ expect(getMaxNodes(layerNodes)).toBe(3);
+ });
+ });
+
+ describe('generateColumnsFromLayersList', () => {
+ const pipeline = generateResponse(mockPipelineResponse, 'root/fungi-xoxo');
+ const { pipelineLayers } = listByLayers(pipeline);
+ const columns = generateColumnsFromLayersListBare(pipeline, pipelineLayers);
+
+ it('returns stage-like objects with default name, id, and status', () => {
+ columns.forEach((col, idx) => {
+ expect(col).toMatchObject({
+ name: '',
+ status: { action: null },
+ id: `layer-${idx}`,
+ });
+ });
+ });
+
+ it('creates groups that match the list created in listByLayers', () => {
+ columns.forEach((col, idx) => {
+ const groupNames = col.groups.map(({ name }) => name);
+ expect(groupNames).toEqual(pipelineLayers[idx]);
+ });
+ });
+
+ it('looks up the correct group object', () => {
+ columns.forEach((col) => {
+ col.groups.forEach((group) => {
+ const groupStage = pipeline.stages.find((el) => el.name === group.stageName);
+ const groupObject = groupStage.groups.find((el) => el.name === group.name);
+ expect(group).toBe(groupObject);
+ });
+ });
+ });
+ });
+});
+
+describe('linked pipeline utilities', () => {
+ describe('keepLatestDownstreamPipelines', () => {
+ it('filters data from GraphQL', () => {
+ const downstream = mockDownstreamPipelinesGraphql().nodes;
+ const latestDownstream = keepLatestDownstreamPipelines(downstream);
+
+ expect(downstream).toHaveLength(3);
+ expect(latestDownstream).toHaveLength(1);
+ });
+
+ it('filters data from REST', () => {
+ const downstream = mockDownstreamPipelinesRest();
+ const latestDownstream = keepLatestDownstreamPipelines(downstream);
+
+ expect(downstream).toHaveLength(2);
+ expect(latestDownstream).toHaveLength(1);
+ });
+
+ it('returns downstream pipelines if sourceJob.retried is null', () => {
+ const downstream = mockDownstreamPipelinesGraphql({ includeSourceJobRetried: false }).nodes;
+ const latestDownstream = keepLatestDownstreamPipelines(downstream);
+
+ expect(latestDownstream).toHaveLength(downstream.length);
+ });
+
+ it('returns downstream pipelines if source_job.retried is null', () => {
+ const downstream = mockDownstreamPipelinesRest({ includeSourceJobRetried: false });
+ const latestDownstream = keepLatestDownstreamPipelines(downstream);
+
+ expect(latestDownstream).toHaveLength(downstream.length);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_details/utils/unwrapping_utils_spec.js b/spec/frontend/ci/pipeline_details/utils/unwrapping_utils_spec.js
new file mode 100644
index 00000000000..99ee2eff1e4
--- /dev/null
+++ b/spec/frontend/ci/pipeline_details/utils/unwrapping_utils_spec.js
@@ -0,0 +1,127 @@
+import {
+ unwrapGroups,
+ unwrapNodesWithName,
+ unwrapStagesWithNeeds,
+} from '~/ci/pipeline_details/utils/unwrapping_utils';
+
+const groupsArray = [
+ {
+ name: 'build_a',
+ size: 1,
+ status: {
+ label: 'passed',
+ group: 'success',
+ icon: 'status_success',
+ },
+ },
+ {
+ name: 'bob_the_build',
+ size: 1,
+ status: {
+ label: 'passed',
+ group: 'success',
+ icon: 'status_success',
+ },
+ },
+];
+
+const basicStageInfo = {
+ name: 'center_stage',
+ status: {
+ action: null,
+ },
+};
+
+const stagesAndGroups = [
+ {
+ ...basicStageInfo,
+ groups: {
+ nodes: groupsArray,
+ },
+ },
+];
+
+const needArray = [
+ {
+ name: 'build_b',
+ },
+];
+
+const elephantArray = [
+ {
+ name: 'build_b',
+ elephant: 'gray',
+ },
+];
+
+const baseJobs = {
+ name: 'test_d',
+ status: {
+ icon: 'status_success',
+ tooltip: null,
+ hasDetails: true,
+ detailsPath: '/root/abcd-dag/-/pipelines/162',
+ group: 'success',
+ action: null,
+ },
+};
+
+const jobArrayWithNeeds = [
+ {
+ ...baseJobs,
+ needs: {
+ nodes: needArray,
+ },
+ },
+];
+
+const jobArrayWithElephant = [
+ {
+ ...baseJobs,
+ needs: {
+ nodes: elephantArray,
+ },
+ },
+];
+
+const completeMock = [
+ {
+ ...basicStageInfo,
+ groups: {
+ nodes: groupsArray.map((group) => ({ ...group, jobs: { nodes: jobArrayWithNeeds } })),
+ },
+ },
+];
+
+describe('Shared pipeline unwrapping utils', () => {
+ describe('unwrapGroups', () => {
+ it('takes stages without nodes and returns the unwrapped groups', () => {
+ expect(unwrapGroups(stagesAndGroups)[0].node.groups).toEqual(groupsArray);
+ });
+
+ it('keeps other stage properties intact', () => {
+ expect(unwrapGroups(stagesAndGroups)[0].node).toMatchObject(basicStageInfo);
+ });
+ });
+
+ describe('unwrapNodesWithName', () => {
+ it('works with no field argument', () => {
+ expect(unwrapNodesWithName(jobArrayWithNeeds, 'needs')[0].needs).toEqual([needArray[0].name]);
+ });
+
+ it('works with custom field argument', () => {
+ expect(unwrapNodesWithName(jobArrayWithElephant, 'needs', 'elephant')[0].needs).toEqual([
+ elephantArray[0].elephant,
+ ]);
+ });
+ });
+
+ describe('unwrapStagesWithNeeds', () => {
+ it('removes nodes from groups, jobs, and needs', () => {
+ const firstProcessedGroup = unwrapStagesWithNeeds(completeMock)[0].groups[0];
+ expect(firstProcessedGroup).toMatchObject(groupsArray[0]);
+ expect(firstProcessedGroup.jobs[0]).toMatchObject(baseJobs);
+ expect(firstProcessedGroup.jobs[0].needs[0]).toBe(needArray[0].name);
+ });
+ });
+});
diff --git a/spec/frontend/pipelines/pipeline_graph/mock_data.js b/spec/frontend/ci/pipeline_editor/components/graph/mock_data.js
index db77e0a0573..db77e0a0573 100644
--- a/spec/frontend/pipelines/pipeline_graph/mock_data.js
+++ b/spec/frontend/ci/pipeline_editor/components/graph/mock_data.js
diff --git a/spec/frontend/ci/pipeline_editor/components/graph/pipeline_graph_spec.js b/spec/frontend/ci/pipeline_editor/components/graph/pipeline_graph_spec.js
new file mode 100644
index 00000000000..95edfb01cf0
--- /dev/null
+++ b/spec/frontend/ci/pipeline_editor/components/graph/pipeline_graph_spec.js
@@ -0,0 +1,100 @@
+import { GlAlert } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { setHTMLFixture } from 'helpers/fixtures';
+import { CI_CONFIG_STATUS_VALID } from '~/ci/pipeline_editor/constants';
+import LinksInner from '~/ci/pipeline_details/graph/components/links_inner.vue';
+import LinksLayer from '~/ci/common/private/job_links_layer.vue';
+import JobPill from '~/ci/pipeline_editor/components/graph/job_pill.vue';
+import PipelineGraph from '~/ci/pipeline_editor/components/graph/pipeline_graph.vue';
+import StageName from '~/ci/pipeline_editor/components/graph/stage_name.vue';
+import { pipelineData, singleStageData } from './mock_data';
+
+describe('pipeline graph component', () => {
+ const defaultProps = { pipelineData };
+ let wrapper;
+
+ const containerId = 'pipeline-graph-container-0';
+ setHTMLFixture(`<div id="${containerId}"></div>`);
+
+ const createComponent = (props = defaultProps) => {
+ return shallowMount(PipelineGraph, {
+ propsData: {
+ ...props,
+ },
+ stubs: { LinksLayer, LinksInner },
+ data() {
+ return {
+ measurements: {
+ width: 1000,
+ height: 1000,
+ },
+ };
+ },
+ });
+ };
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findAllJobPills = () => wrapper.findAllComponents(JobPill);
+ const findAllStageNames = () => wrapper.findAllComponents(StageName);
+ const findLinksLayer = () => wrapper.findComponent(LinksLayer);
+ const findPipelineGraph = () => wrapper.find('[data-testid="graph-container"]');
+
+ describe('with `VALID` status', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ pipelineData: {
+ status: CI_CONFIG_STATUS_VALID,
+ stages: [{ name: 'hello', groups: [] }],
+ },
+ });
+ });
+
+ it('renders the graph with no status error', () => {
+ expect(findAlert().exists()).toBe(false);
+ expect(findPipelineGraph().exists()).toBe(true);
+ expect(findLinksLayer().exists()).toBe(true);
+ });
+ });
+
+ describe('with only one stage', () => {
+ beforeEach(() => {
+ wrapper = createComponent({ pipelineData: singleStageData });
+ });
+
+ it('renders the right number of stage titles', () => {
+ const expectedStagesLength = singleStageData.stages.length;
+
+ expect(findAllStageNames()).toHaveLength(expectedStagesLength);
+ });
+
+ it('renders the right number of job pills', () => {
+ // We count the number of jobs in the mock data
+ const expectedJobsLength = singleStageData.stages.reduce((acc, val) => {
+ return acc + val.groups.length;
+ }, 0);
+
+ expect(findAllJobPills()).toHaveLength(expectedJobsLength);
+ });
+ });
+
+ describe('with multiple stages and jobs', () => {
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ it('renders the right number of stage titles', () => {
+ const expectedStagesLength = pipelineData.stages.length;
+
+ expect(findAllStageNames()).toHaveLength(expectedStagesLength);
+ });
+
+ it('renders the right number of job pills', () => {
+ // We count the number of jobs in the mock data
+ const expectedJobsLength = pipelineData.stages.reduce((acc, val) => {
+ return acc + val.groups.length;
+ }, 0);
+
+ expect(findAllJobPills()).toHaveLength(expectedJobsLength);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_header_spec.js b/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_header_spec.js
index a651664851e..655bfe538c6 100644
--- a/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_header_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_header_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { GlCard } from '@gitlab/ui';
import PipelineEditorHeader from '~/ci/pipeline_editor/components/header/pipeline_editor_header.vue';
import PipelineStatus from '~/ci/pipeline_editor/components/header/pipeline_status.vue';
import ValidationSegment from '~/ci/pipeline_editor/components/header/validation_segment.vue';
@@ -20,6 +21,9 @@ describe('Pipeline editor header', () => {
isNewCiConfigFile: false,
...props,
},
+ stubs: {
+ GlCard,
+ },
});
};
diff --git a/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js b/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
index f5e0b65d615..4ec1dd4b605 100644
--- a/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/header/pipeline_editor_mini_graph_spec.js
@@ -4,8 +4,8 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import PipelineEditorMiniGraph from '~/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
-import getLinkedPipelinesQuery from '~/pipelines/graphql/queries/get_linked_pipelines.query.graphql';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import getLinkedPipelinesQuery from '~/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql';
import { PIPELINE_FAILURE } from '~/ci/pipeline_editor/constants';
import { mockLinkedPipelines, mockProjectFullPath, mockProjectPipeline } from '../../mock_data';
diff --git a/spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js b/spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js
index 3bbe14adb88..1a2ed60a6f4 100644
--- a/spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/header/pipeline_status_spec.js
@@ -6,8 +6,9 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import PipelineStatus, { i18n } from '~/ci/pipeline_editor/components/header/pipeline_status.vue';
import getPipelineQuery from '~/ci/pipeline_editor/graphql/queries/pipeline.query.graphql';
-import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
+import PipelineMiniGraph from '~/ci/pipeline_mini_graph/pipeline_mini_graph.vue';
import PipelineEditorMiniGraph from '~/ci/pipeline_editor/components/header/pipeline_editor_mini_graph.vue';
+import getPipelineEtag from '~/ci/pipeline_editor/graphql/queries/client/pipeline_etag.query.graphql';
import { mockCommitSha, mockProjectPipeline, mockProjectFullPath } from '../../mock_data';
Vue.use(VueApollo);
@@ -21,6 +22,16 @@ describe('Pipeline Status', () => {
const handlers = [[getPipelineQuery, mockPipelineQuery]];
mockApollo = createMockApollo(handlers);
+ mockApollo.clients.defaultClient.cache.writeQuery({
+ query: getPipelineEtag,
+ data: {
+ etags: {
+ __typename: 'EtagValues',
+ pipeline: 'pipelines/1',
+ },
+ },
+ });
+
wrapper = shallowMount(PipelineStatus, {
apolloProvider: mockApollo,
propsData: {
diff --git a/spec/frontend/ci/pipeline_editor/components/pipeline_editor_tabs_spec.js b/spec/frontend/ci/pipeline_editor/components/pipeline_editor_tabs_spec.js
index 77252a5c0b6..69e91f11309 100644
--- a/spec/frontend/ci/pipeline_editor/components/pipeline_editor_tabs_spec.js
+++ b/spec/frontend/ci/pipeline_editor/components/pipeline_editor_tabs_spec.js
@@ -19,7 +19,7 @@ import {
VALIDATE_TAB,
VALIDATE_TAB_BADGE_DISMISSED_KEY,
} from '~/ci/pipeline_editor/constants';
-import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
+import PipelineGraph from '~/ci/pipeline_editor/components/graph/pipeline_graph.vue';
import getBlobContent from '~/ci/pipeline_editor/graphql/queries/blob_content.query.graphql';
import {
mockBlobContentQueryResponse,
diff --git a/spec/frontend/ci/pipeline_editor/mock_data.js b/spec/frontend/ci/pipeline_editor/mock_data.js
index 007abde939f..e08c35f1555 100644
--- a/spec/frontend/ci/pipeline_editor/mock_data.js
+++ b/spec/frontend/ci/pipeline_editor/mock_data.js
@@ -1,5 +1,5 @@
import { CI_CONFIG_STATUS_INVALID, CI_CONFIG_STATUS_VALID } from '~/ci/pipeline_editor/constants';
-import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
+import { unwrapStagesWithNeeds } from '~/ci/pipeline_details/utils/unwrapping_utils';
import { DOCS_URL_IN_EE_DIR } from 'jh_else_ce/lib/utils/url_utility';
export const commonOptions = {
diff --git a/spec/frontend/ci/pipeline_mini_graph/job_item_spec.js b/spec/frontend/ci/pipeline_mini_graph/job_item_spec.js
new file mode 100644
index 00000000000..9c14e75caa4
--- /dev/null
+++ b/spec/frontend/ci/pipeline_mini_graph/job_item_spec.js
@@ -0,0 +1,29 @@
+import { shallowMount } from '@vue/test-utils';
+import JobItem from '~/ci/pipeline_mini_graph/job_item.vue';
+
+describe('JobItem', () => {
+ let wrapper;
+
+ const defaultProps = {
+ job: { id: '3' },
+ };
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMount(JobItem, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ describe('when mounted', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the received HTML', () => {
+ expect(wrapper.html()).toContain(defaultProps.job.id);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_mini_graph/legacy_pipeline_mini_graph_spec.js b/spec/frontend/ci/pipeline_mini_graph/legacy_pipeline_mini_graph_spec.js
new file mode 100644
index 00000000000..916f3053153
--- /dev/null
+++ b/spec/frontend/ci/pipeline_mini_graph/legacy_pipeline_mini_graph_spec.js
@@ -0,0 +1,122 @@
+import { mount } from '@vue/test-utils';
+import { pipelines } from 'test_fixtures/pipelines/pipelines.json';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import PipelineStages from '~/ci/pipeline_mini_graph/pipeline_stages.vue';
+import mockLinkedPipelines from './linked_pipelines_mock_data';
+
+const mockStages = pipelines[0].details.stages;
+
+describe('Legacy Pipeline Mini Graph', () => {
+ let wrapper;
+
+ const findLegacyPipelineMiniGraph = () => wrapper.findComponent(LegacyPipelineMiniGraph);
+ const findPipelineStages = () => wrapper.findComponent(PipelineStages);
+
+ const findLinkedPipelineUpstream = () =>
+ wrapper.findComponent('[data-testid="pipeline-mini-graph-upstream"]');
+ const findLinkedPipelineDownstream = () =>
+ wrapper.findComponent('[data-testid="pipeline-mini-graph-downstream"]');
+ const findDownstreamArrowIcon = () => wrapper.find('[data-testid="downstream-arrow-icon"]');
+ const findUpstreamArrowIcon = () => wrapper.find('[data-testid="upstream-arrow-icon"]');
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(LegacyPipelineMiniGraph, {
+ propsData: {
+ stages: mockStages,
+ ...props,
+ },
+ });
+ };
+
+ describe('rendered state without upstream or downstream pipelines', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should render the pipeline stages', () => {
+ expect(findPipelineStages().exists()).toBe(true);
+ });
+
+ it('should have the correct props', () => {
+ expect(findLegacyPipelineMiniGraph().props()).toMatchObject({
+ downstreamPipelines: [],
+ isMergeTrain: false,
+ pipelinePath: '',
+ stages: expect.any(Array),
+ updateDropdown: false,
+ upstreamPipeline: undefined,
+ });
+ });
+
+ it('should have no linked pipelines', () => {
+ expect(findLinkedPipelineDownstream().exists()).toBe(false);
+ expect(findLinkedPipelineUpstream().exists()).toBe(false);
+ });
+
+ it('should not render arrow icons', () => {
+ expect(findUpstreamArrowIcon().exists()).toBe(false);
+ expect(findDownstreamArrowIcon().exists()).toBe(false);
+ });
+ });
+
+ describe('rendered state with upstream pipeline', () => {
+ beforeEach(() => {
+ createComponent({
+ upstreamPipeline: mockLinkedPipelines.triggered_by,
+ });
+ });
+
+ it('should have the correct props', () => {
+ expect(findLegacyPipelineMiniGraph().props()).toMatchObject({
+ downstreamPipelines: [],
+ isMergeTrain: false,
+ pipelinePath: '',
+ stages: expect.any(Array),
+ updateDropdown: false,
+ upstreamPipeline: expect.any(Object),
+ });
+ });
+
+ it('should render the upstream linked pipelines mini list only', () => {
+ expect(findLinkedPipelineUpstream().exists()).toBe(true);
+ expect(findLinkedPipelineDownstream().exists()).toBe(false);
+ });
+
+ it('should render an upstream arrow icon only', () => {
+ expect(findDownstreamArrowIcon().exists()).toBe(false);
+ expect(findUpstreamArrowIcon().exists()).toBe(true);
+ expect(findUpstreamArrowIcon().props('name')).toBe('long-arrow');
+ });
+ });
+
+ describe('rendered state with downstream pipelines', () => {
+ beforeEach(() => {
+ createComponent({
+ downstreamPipelines: mockLinkedPipelines.triggered,
+ pipelinePath: 'my/pipeline/path',
+ });
+ });
+
+ it('should have the correct props', () => {
+ expect(findLegacyPipelineMiniGraph().props()).toMatchObject({
+ downstreamPipelines: expect.any(Array),
+ isMergeTrain: false,
+ pipelinePath: 'my/pipeline/path',
+ stages: expect.any(Array),
+ updateDropdown: false,
+ upstreamPipeline: undefined,
+ });
+ });
+
+ it('should render the downstream linked pipelines mini list only', () => {
+ expect(findLinkedPipelineDownstream().exists()).toBe(true);
+ expect(findLinkedPipelineUpstream().exists()).toBe(false);
+ });
+
+ it('should render a downstream arrow icon only', () => {
+ expect(findUpstreamArrowIcon().exists()).toBe(false);
+ expect(findDownstreamArrowIcon().exists()).toBe(true);
+ expect(findDownstreamArrowIcon().props('name')).toBe('long-arrow');
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_mini_graph/legacy_pipeline_stage_spec.js b/spec/frontend/ci/pipeline_mini_graph/legacy_pipeline_stage_spec.js
new file mode 100644
index 00000000000..30a0b868c5f
--- /dev/null
+++ b/spec/frontend/ci/pipeline_mini_graph/legacy_pipeline_stage_spec.js
@@ -0,0 +1,247 @@
+import { GlDropdown } from '@gitlab/ui';
+import { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import LegacyPipelineStage from '~/ci/pipeline_mini_graph/legacy_pipeline_stage.vue';
+import eventHub from '~/ci/event_hub';
+import waitForPromises from 'helpers/wait_for_promises';
+import { stageReply } from './mock_data';
+
+const dropdownPath = 'path.json';
+
+describe('Pipelines stage component', () => {
+ let wrapper;
+ let mock;
+ let glTooltipDirectiveMock;
+
+ const createComponent = (props = {}) => {
+ glTooltipDirectiveMock = jest.fn();
+ wrapper = mount(LegacyPipelineStage, {
+ attachTo: document.body,
+ directives: {
+ GlTooltip: glTooltipDirectiveMock,
+ },
+ propsData: {
+ stage: {
+ status: {
+ group: 'success',
+ icon: 'status_success',
+ title: 'success',
+ },
+ dropdown_path: dropdownPath,
+ },
+ updateDropdown: false,
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ jest.spyOn(eventHub, '$emit');
+ });
+
+ afterEach(() => {
+ eventHub.$emit.mockRestore();
+ mock.restore();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
+ wrapper.destroy();
+ });
+
+ const findCiActionBtn = () => wrapper.find('.js-ci-action');
+ const findCiIcon = () => wrapper.findComponent(CiIcon);
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownToggle = () => wrapper.find('button.dropdown-toggle');
+ const findDropdownMenu = () =>
+ wrapper.find('[data-testid="mini-pipeline-graph-dropdown-menu-list"]');
+ const findDropdownMenuTitle = () =>
+ wrapper.find('[data-testid="pipeline-stage-dropdown-menu-title"]');
+ const findMergeTrainWarning = () => wrapper.find('[data-testid="warning-message-merge-trains"]');
+ const findLoadingState = () => wrapper.find('[data-testid="pipeline-stage-loading-state"]');
+
+ const openStageDropdown = async () => {
+ await findDropdownToggle().trigger('click');
+ await waitForPromises();
+ await nextTick();
+ };
+
+ describe('loading state', () => {
+ beforeEach(async () => {
+ createComponent({ updateDropdown: true });
+
+ mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
+
+ await openStageDropdown();
+ });
+
+ it('displays loading state while jobs are being fetched', async () => {
+ jest.runOnlyPendingTimers();
+ await nextTick();
+
+ expect(findLoadingState().exists()).toBe(true);
+ expect(findLoadingState().text()).toBe(LegacyPipelineStage.i18n.loadingText);
+ });
+
+ it('does not display loading state after jobs have been fetched', async () => {
+ await waitForPromises();
+
+ expect(findLoadingState().exists()).toBe(false);
+ });
+ });
+
+ describe('default appearance', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('sets up the tooltip to not have a show delay animation', () => {
+ expect(glTooltipDirectiveMock.mock.calls[0][1].modifiers.ds0).toBe(true);
+ });
+
+ it('renders a dropdown with the status icon', () => {
+ expect(findDropdown().exists()).toBe(true);
+ expect(findDropdownToggle().exists()).toBe(true);
+ expect(findCiIcon().exists()).toBe(true);
+ });
+
+ it('renders a borderless ci-icon', () => {
+ expect(findCiIcon().exists()).toBe(true);
+ expect(findCiIcon().props('isBorderless')).toBe(true);
+ expect(findCiIcon().classes('borderless')).toBe(true);
+ });
+
+ it('renders a ci-icon with a custom border class', () => {
+ expect(findCiIcon().exists()).toBe(true);
+ expect(findCiIcon().classes('gl-border')).toBe(true);
+ });
+ });
+
+ describe('when user opens dropdown and stage request is successful', () => {
+ beforeEach(async () => {
+ mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
+ createComponent();
+
+ await openStageDropdown();
+ await jest.runAllTimers();
+ await axios.waitForAll();
+ });
+
+ it('renders the received data and emits the correct events', () => {
+ expect(findDropdownMenu().text()).toContain(stageReply.latest_statuses[0].name);
+ expect(findDropdownMenuTitle().text()).toContain(stageReply.name);
+ expect(eventHub.$emit).toHaveBeenCalledWith('clickedDropdown');
+ expect(wrapper.emitted('miniGraphStageClick')).toEqual([[]]);
+ });
+
+ it('refreshes when updateDropdown is set to true', async () => {
+ expect(mock.history.get).toHaveLength(1);
+
+ wrapper.setProps({ updateDropdown: true });
+ await axios.waitForAll();
+
+ expect(mock.history.get).toHaveLength(2);
+ });
+ });
+
+ describe('when user opens dropdown and stage request fails', () => {
+ it('should close the dropdown', async () => {
+ mock.onGet(dropdownPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ createComponent();
+
+ await openStageDropdown();
+ await axios.waitForAll();
+ await waitForPromises();
+
+ expect(findDropdown().classes('show')).toBe(false);
+ });
+ });
+
+ describe('update endpoint correctly', () => {
+ beforeEach(async () => {
+ const copyStage = { ...stageReply };
+ copyStage.latest_statuses[0].name = 'this is the updated content';
+ mock.onGet('bar.json').reply(HTTP_STATUS_OK, copyStage);
+ createComponent({
+ stage: {
+ status: {
+ group: 'running',
+ icon: 'status_running',
+ title: 'running',
+ },
+ dropdown_path: 'bar.json',
+ },
+ });
+ await axios.waitForAll();
+ });
+
+ it('should update the stage to request the new endpoint provided', async () => {
+ await openStageDropdown();
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+
+ expect(findDropdownMenu().text()).toContain('this is the updated content');
+ });
+ });
+
+ describe('job update in dropdown', () => {
+ beforeEach(async () => {
+ mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
+ mock.onPost(`${stageReply.latest_statuses[0].status.action.path}.json`).reply(HTTP_STATUS_OK);
+
+ createComponent();
+ await waitForPromises();
+ await nextTick();
+ });
+
+ const clickCiAction = async () => {
+ await openStageDropdown();
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+
+ await findCiActionBtn().trigger('click');
+ };
+
+ it('keeps dropdown open when job item action is clicked', async () => {
+ await clickCiAction();
+ await waitForPromises();
+
+ expect(findDropdown().classes('show')).toBe(true);
+ });
+ });
+
+ describe('With merge trains enabled', () => {
+ it('shows a warning on the dropdown', async () => {
+ mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
+ createComponent({
+ isMergeTrain: true,
+ });
+
+ await openStageDropdown();
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+
+ const warning = findMergeTrainWarning();
+
+ expect(warning.text()).toBe('Merge train pipeline jobs can not be retried');
+ });
+ });
+
+ describe('With merge trains disabled', () => {
+ beforeEach(async () => {
+ mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
+ createComponent();
+
+ await openStageDropdown();
+ await axios.waitForAll();
+ });
+
+ it('does not show a warning on the dropdown', () => {
+ const warning = findMergeTrainWarning();
+
+ expect(warning.exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_mini_graph/linked_pipelines_mini_list_spec.js b/spec/frontend/ci/pipeline_mini_graph/linked_pipelines_mini_list_spec.js
new file mode 100644
index 00000000000..0396029cdaf
--- /dev/null
+++ b/spec/frontend/ci/pipeline_mini_graph/linked_pipelines_mini_list_spec.js
@@ -0,0 +1,166 @@
+import { mount } from '@vue/test-utils';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import LinkedPipelinesMiniList from '~/ci/pipeline_mini_graph/linked_pipelines_mini_list.vue';
+import mockData from './linked_pipelines_mock_data';
+
+describe('Linked pipeline mini list', () => {
+ let wrapper;
+
+ const findCiIcon = () => wrapper.findComponent(CiIcon);
+ const findCiIcons = () => wrapper.findAllComponents(CiIcon);
+ const findLinkedPipelineCounter = () => wrapper.find('[data-testid="linked-pipeline-counter"]');
+ const findLinkedPipelineMiniItem = () =>
+ wrapper.find('[data-testid="linked-pipeline-mini-item"]');
+ const findLinkedPipelineMiniItems = () =>
+ wrapper.findAll('[data-testid="linked-pipeline-mini-item"]');
+ const findLinkedPipelineMiniList = () => wrapper.findComponent(LinkedPipelinesMiniList);
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(LinkedPipelinesMiniList, {
+ directives: {
+ GlTooltip: createMockDirective('gl-tooltip'),
+ },
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ describe('when passed an upstream pipeline as prop', () => {
+ beforeEach(() => {
+ createComponent({
+ triggeredBy: [mockData.triggered_by],
+ });
+ });
+
+ it('should render one linked pipeline item', () => {
+ expect(findLinkedPipelineMiniItem().exists()).toBe(true);
+ });
+
+ it('should render a linked pipeline with the correct href', () => {
+ expect(findLinkedPipelineMiniItem().exists()).toBe(true);
+
+ expect(findLinkedPipelineMiniItem().attributes('href')).toBe(
+ '/gitlab-org/gitlab-foss/-/pipelines/129',
+ );
+ });
+
+ it('should render one ci status icon', () => {
+ expect(findCiIcon().exists()).toBe(true);
+ });
+
+ it('should render a borderless ci-icon', () => {
+ expect(findCiIcon().exists()).toBe(true);
+
+ expect(findCiIcon().props('isBorderless')).toBe(true);
+ expect(findCiIcon().classes('borderless')).toBe(true);
+ });
+
+ it('should render a ci-icon with a custom border class', () => {
+ expect(findCiIcon().exists()).toBe(true);
+
+ expect(findCiIcon().classes('gl-border')).toBe(true);
+ });
+
+ it('should render the correct ci status icon', () => {
+ expect(findCiIcon().classes('ci-status-icon-running')).toBe(true);
+ });
+
+ it('should have an activated tooltip', () => {
+ expect(findLinkedPipelineMiniItem().exists()).toBe(true);
+ const tooltip = getBinding(findLinkedPipelineMiniItem().element, 'gl-tooltip');
+
+ expect(tooltip.value.title).toBe('GitLabCE - running');
+ });
+
+ it('should correctly set is-upstream', () => {
+ expect(findLinkedPipelineMiniList().exists()).toBe(true);
+
+ expect(findLinkedPipelineMiniList().classes('is-upstream')).toBe(true);
+ });
+
+ it('should correctly compute shouldRenderCounter', () => {
+ expect(findLinkedPipelineMiniList().vm.shouldRenderCounter).toBe(false);
+ });
+
+ it('should not render the pipeline counter', () => {
+ expect(findLinkedPipelineCounter().exists()).toBe(false);
+ });
+ });
+
+ describe('when passed downstream pipelines as props', () => {
+ beforeEach(() => {
+ createComponent({
+ triggered: mockData.triggered,
+ pipelinePath: 'my/pipeline/path',
+ });
+ });
+
+ it('should render three linked pipeline items', () => {
+ expect(findLinkedPipelineMiniItems().exists()).toBe(true);
+ expect(findLinkedPipelineMiniItems().length).toBe(3);
+ });
+
+ it('should render three ci status icons', () => {
+ expect(findCiIcons().exists()).toBe(true);
+ expect(findCiIcons().length).toBe(3);
+ });
+
+ it('should render the correct ci status icon', () => {
+ expect(findCiIcon().classes('ci-status-icon-running')).toBe(true);
+ });
+
+ it('should have an activated tooltip', () => {
+ expect(findLinkedPipelineMiniItem().exists()).toBe(true);
+ const tooltip = getBinding(findLinkedPipelineMiniItem().element, 'gl-tooltip');
+
+ expect(tooltip.value.title).toBe('GitLabCE - running');
+ });
+
+ it('should correctly set is-downstream', () => {
+ expect(findLinkedPipelineMiniList().exists()).toBe(true);
+
+ expect(findLinkedPipelineMiniList().classes('is-downstream')).toBe(true);
+ });
+
+ it('should render a borderless ci-icon', () => {
+ expect(findCiIcon().exists()).toBe(true);
+
+ expect(findCiIcon().props('isBorderless')).toBe(true);
+ expect(findCiIcon().classes('borderless')).toBe(true);
+ });
+
+ it('should render a ci-icon with a custom border class', () => {
+ expect(findCiIcon().exists()).toBe(true);
+
+ expect(findCiIcon().classes('gl-border')).toBe(true);
+ });
+
+ it('should render the pipeline counter', () => {
+ expect(findLinkedPipelineCounter().exists()).toBe(true);
+ });
+
+ it('should correctly compute shouldRenderCounter', () => {
+ expect(findLinkedPipelineMiniList().vm.shouldRenderCounter).toBe(true);
+ });
+
+ it('should correctly trim linkedPipelines', () => {
+ expect(findLinkedPipelineMiniList().props('triggered').length).toBe(6);
+ expect(findLinkedPipelineMiniList().vm.linkedPipelinesTrimmed.length).toBe(3);
+ });
+
+ it('should set the correct pipeline path', () => {
+ expect(findLinkedPipelineCounter().exists()).toBe(true);
+
+ expect(findLinkedPipelineCounter().attributes('href')).toBe('my/pipeline/path');
+ });
+
+ it('should render the correct counterTooltipText', () => {
+ expect(findLinkedPipelineCounter().exists()).toBe(true);
+ const tooltip = getBinding(findLinkedPipelineCounter().element, 'gl-tooltip');
+
+ expect(tooltip.value.title).toBe(findLinkedPipelineMiniList().vm.counterTooltipText);
+ });
+ });
+});
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/linked_pipelines_mock_data.js b/spec/frontend/ci/pipeline_mini_graph/linked_pipelines_mock_data.js
index 117c7f2ae52..117c7f2ae52 100644
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/linked_pipelines_mock_data.js
+++ b/spec/frontend/ci/pipeline_mini_graph/linked_pipelines_mock_data.js
diff --git a/spec/frontend/ci/pipeline_mini_graph/mock_data.js b/spec/frontend/ci/pipeline_mini_graph/mock_data.js
new file mode 100644
index 00000000000..231375b40dd
--- /dev/null
+++ b/spec/frontend/ci/pipeline_mini_graph/mock_data.js
@@ -0,0 +1,252 @@
+export const mockDownstreamPipelinesGraphql = ({ includeSourceJobRetried = true } = {}) => ({
+ nodes: [
+ {
+ id: 'gid://gitlab/Ci::Pipeline/612',
+ path: '/root/job-log-sections/-/pipelines/612',
+ project: {
+ id: 'gid://gitlab/Project/21',
+ name: 'job-log-sections',
+ __typename: 'Project',
+ },
+ detailedStatus: {
+ id: 'success-612-612',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ sourceJob: {
+ id: 'gid://gitlab/Ci::Bridge/532',
+ retried: includeSourceJobRetried ? false : null,
+ },
+ __typename: 'Pipeline',
+ },
+ {
+ id: 'gid://gitlab/Ci::Pipeline/611',
+ path: '/root/job-log-sections/-/pipelines/611',
+ project: {
+ id: 'gid://gitlab/Project/21',
+ name: 'job-log-sections',
+ __typename: 'Project',
+ },
+ detailedStatus: {
+ id: 'success-611-611',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ sourceJob: {
+ id: 'gid://gitlab/Ci::Bridge/531',
+ retried: includeSourceJobRetried ? true : null,
+ },
+ __typename: 'Pipeline',
+ },
+ {
+ id: 'gid://gitlab/Ci::Pipeline/609',
+ path: '/root/job-log-sections/-/pipelines/609',
+ project: {
+ id: 'gid://gitlab/Project/21',
+ name: 'job-log-sections',
+ __typename: 'Project',
+ },
+ detailedStatus: {
+ id: 'success-609-609',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ sourceJob: {
+ id: 'gid://gitlab/Ci::Bridge/530',
+ retried: includeSourceJobRetried ? true : null,
+ },
+ __typename: 'Pipeline',
+ },
+ ],
+ __typename: 'PipelineConnection',
+});
+
+const upstream = {
+ id: 'gid://gitlab/Ci::Pipeline/610',
+ path: '/root/trigger-downstream/-/pipelines/610',
+ project: {
+ id: 'gid://gitlab/Project/21',
+ name: 'trigger-downstream',
+ __typename: 'Project',
+ },
+ detailedStatus: {
+ id: 'success-610-610',
+ group: 'success',
+ icon: 'status_success',
+ label: 'passed',
+ __typename: 'DetailedStatus',
+ },
+ __typename: 'Pipeline',
+};
+
+export const mockPipelineStagesQueryResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/20',
+ pipeline: {
+ id: 'gid://gitlab/Ci::Pipeline/320',
+ stages: {
+ nodes: [
+ {
+ __typename: 'CiStage',
+ id: 'gid://gitlab/Ci::Stage/409',
+ name: 'build',
+ detailedStatus: {
+ __typename: 'DetailedStatus',
+ id: 'success-409-409',
+ icon: 'status_success',
+ group: 'success',
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+};
+
+export const mockPipelineStatusResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/20',
+ pipeline: {
+ id: 'gid://gitlab/Ci::Pipeline/320',
+ detailedStatus: {
+ id: 'pending-320-320',
+ detailsPath: '/root/ci-project/-/pipelines/320',
+ icon: 'status_pending',
+ group: 'pending',
+ __typename: 'DetailedStatus',
+ },
+ __typename: 'Pipeline',
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
+export const mockUpstreamDownstreamQueryResponse = {
+ data: {
+ project: {
+ id: '1',
+ pipeline: {
+ id: 'pipeline-1',
+ path: '/root/ci-project/-/pipelines/790',
+ downstream: mockDownstreamPipelinesGraphql(),
+ upstream,
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
+export const linkedPipelinesFetchError = 'There was a problem fetching linked pipelines.';
+export const stagesFetchError = 'There was a problem fetching the pipeline stages.';
+
+export const stageReply = {
+ name: 'deploy',
+ title: 'deploy: running',
+ latest_statuses: [
+ {
+ id: 928,
+ name: 'stop staging',
+ started: false,
+ build_path: '/twitter/flight/-/jobs/928',
+ cancel_path: '/twitter/flight/-/jobs/928/cancel',
+ playable: false,
+ created_at: '2018-04-04T20:02:02.728Z',
+ updated_at: '2018-04-04T20:02:02.766Z',
+ status: {
+ icon: 'status_pending',
+ text: 'pending',
+ label: 'pending',
+ group: 'pending',
+ tooltip: 'pending',
+ has_details: true,
+ details_path: '/twitter/flight/-/jobs/928',
+ favicon:
+ '/assets/ci_favicons/dev/favicon_status_pending-db32e1faf94b9f89530ac519790920d1f18ea8f6af6cd2e0a26cd6840cacf101.ico',
+ action: {
+ icon: 'cancel',
+ title: 'Cancel',
+ path: '/twitter/flight/-/jobs/928/cancel',
+ method: 'post',
+ },
+ },
+ },
+ {
+ id: 926,
+ name: 'production',
+ started: false,
+ build_path: '/twitter/flight/-/jobs/926',
+ retry_path: '/twitter/flight/-/jobs/926/retry',
+ play_path: '/twitter/flight/-/jobs/926/play',
+ playable: true,
+ created_at: '2018-04-04T20:00:57.202Z',
+ updated_at: '2018-04-04T20:11:13.110Z',
+ status: {
+ icon: 'status_canceled',
+ text: 'canceled',
+ label: 'manual play action',
+ group: 'canceled',
+ tooltip: 'canceled',
+ has_details: true,
+ details_path: '/twitter/flight/-/jobs/926',
+ favicon:
+ '/assets/ci_favicons/dev/favicon_status_canceled-5491840b9b6feafba0bc599cbd49ee9580321dc809683856cf1b0d51532b1af6.ico',
+ action: {
+ icon: 'play',
+ title: 'Play',
+ path: '/twitter/flight/-/jobs/926/play',
+ method: 'post',
+ },
+ },
+ },
+ {
+ id: 217,
+ name: 'staging',
+ started: '2018-03-07T08:41:46.234Z',
+ build_path: '/twitter/flight/-/jobs/217',
+ retry_path: '/twitter/flight/-/jobs/217/retry',
+ playable: false,
+ created_at: '2018-03-07T14:41:58.093Z',
+ updated_at: '2018-03-07T14:41:58.093Z',
+ status: {
+ icon: 'status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ tooltip: 'passed',
+ has_details: true,
+ details_path: '/twitter/flight/-/jobs/217',
+ favicon:
+ '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/twitter/flight/-/jobs/217/retry',
+ method: 'post',
+ },
+ },
+ },
+ ],
+ status: {
+ icon: 'status_running',
+ text: 'running',
+ label: 'running',
+ group: 'running',
+ tooltip: 'running',
+ has_details: true,
+ details_path: '/twitter/flight/pipelines/13#deploy',
+ favicon:
+ '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
+ },
+ path: '/twitter/flight/pipelines/13#deploy',
+ dropdown_path: '/twitter/flight/pipelines/13/stage.json?stage=deploy',
+};
diff --git a/spec/frontend/ci/pipeline_mini_graph/pipeline_mini_graph_spec.js b/spec/frontend/ci/pipeline_mini_graph/pipeline_mini_graph_spec.js
new file mode 100644
index 00000000000..6833726a297
--- /dev/null
+++ b/spec/frontend/ci/pipeline_mini_graph/pipeline_mini_graph_spec.js
@@ -0,0 +1,123 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlLoadingIcon } from '@gitlab/ui';
+
+import { createAlert } from '~/alert';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import createMockApollo from 'helpers/mock_apollo_helper';
+
+import getLinkedPipelinesQuery from '~/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql';
+import getPipelineStagesQuery from '~/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stages.query.graphql';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import PipelineMiniGraph from '~/ci/pipeline_mini_graph/pipeline_mini_graph.vue';
+import * as sharedGraphQlUtils from '~/graphql_shared/utils';
+
+import {
+ linkedPipelinesFetchError,
+ stagesFetchError,
+ mockPipelineStagesQueryResponse,
+ mockUpstreamDownstreamQueryResponse,
+} from './mock_data';
+
+Vue.use(VueApollo);
+jest.mock('~/alert');
+
+describe('PipelineMiniGraph', () => {
+ let wrapper;
+ let linkedPipelinesResponse;
+ let pipelineStagesResponse;
+
+ const fullPath = 'gitlab-org/gitlab';
+ const iid = '315';
+ const pipelineEtag = '/api/graphql:pipelines/id/315';
+
+ const createComponent = ({
+ pipelineStagesHandler = pipelineStagesResponse,
+ linkedPipelinesHandler = linkedPipelinesResponse,
+ } = {}) => {
+ const handlers = [
+ [getLinkedPipelinesQuery, linkedPipelinesHandler],
+ [getPipelineStagesQuery, pipelineStagesHandler],
+ ];
+ const mockApollo = createMockApollo(handlers);
+
+ wrapper = shallowMountExtended(PipelineMiniGraph, {
+ propsData: {
+ fullPath,
+ iid,
+ pipelineEtag,
+ },
+ apolloProvider: mockApollo,
+ });
+
+ return waitForPromises();
+ };
+
+ const findLegacyPipelineMiniGraph = () => wrapper.findComponent(LegacyPipelineMiniGraph);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+
+ beforeEach(() => {
+ linkedPipelinesResponse = jest.fn().mockResolvedValue(mockUpstreamDownstreamQueryResponse);
+ pipelineStagesResponse = jest.fn().mockResolvedValue(mockPipelineStagesQueryResponse);
+ });
+
+ describe('when initial queries are loading', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('shows a loading icon and no mini graph', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ expect(findLegacyPipelineMiniGraph().exists()).toBe(false);
+ });
+ });
+
+ describe('when queries have loaded', () => {
+ it('does not show a loading icon', async () => {
+ await createComponent();
+
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('renders the Pipeline Mini Graph', async () => {
+ await createComponent();
+
+ expect(findLegacyPipelineMiniGraph().exists()).toBe(true);
+ });
+
+ it('fires the queries', async () => {
+ await createComponent();
+
+ expect(linkedPipelinesResponse).toHaveBeenCalledWith({ iid, fullPath });
+ expect(pipelineStagesResponse).toHaveBeenCalledWith({ iid, fullPath });
+ });
+ });
+
+ describe('polling', () => {
+ it('toggles query polling with visibility check', async () => {
+ jest.spyOn(sharedGraphQlUtils, 'toggleQueryPollingByVisibility');
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(sharedGraphQlUtils.toggleQueryPollingByVisibility).toHaveBeenCalledTimes(2);
+ });
+ });
+
+ describe('when pipeline queries are unsuccessful', () => {
+ const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+ it.each`
+ query | handlerName | errorMessage
+ ${'pipeline stages'} | ${'pipelineStagesHandler'} | ${stagesFetchError}
+ ${'linked pipelines'} | ${'linkedPipelinesHandler'} | ${linkedPipelinesFetchError}
+ `('throws an error for the $query query', async ({ errorMessage, handlerName }) => {
+ await createComponent({ [handlerName]: failedHandler });
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({ message: errorMessage });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_mini_graph/pipeline_stage_spec.js b/spec/frontend/ci/pipeline_mini_graph/pipeline_stage_spec.js
new file mode 100644
index 00000000000..96966bcbb84
--- /dev/null
+++ b/spec/frontend/ci/pipeline_mini_graph/pipeline_stage_spec.js
@@ -0,0 +1,46 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import createMockApollo from 'helpers/mock_apollo_helper';
+
+import getPipelineStageQuery from '~/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stage.query.graphql';
+import PipelineStage from '~/ci/pipeline_mini_graph/pipeline_stage.vue';
+
+Vue.use(VueApollo);
+
+describe('PipelineStage', () => {
+ let wrapper;
+ let pipelineStageResponse;
+
+ const defaultProps = {
+ pipelineEtag: '/etag',
+ stageId: '1',
+ };
+
+ const createComponent = ({ pipelineStageHandler = pipelineStageResponse } = {}) => {
+ const handlers = [[getPipelineStageQuery, pipelineStageHandler]];
+ const mockApollo = createMockApollo(handlers);
+
+ wrapper = shallowMountExtended(PipelineStage, {
+ propsData: {
+ ...defaultProps,
+ },
+ apolloProvider: mockApollo,
+ });
+
+ return waitForPromises();
+ };
+
+ const findPipelineStage = () => wrapper.findComponent(PipelineStage);
+
+ describe('when mounted', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders job item', () => {
+ expect(findPipelineStage().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_mini_graph/pipeline_stages_spec.js b/spec/frontend/ci/pipeline_mini_graph/pipeline_stages_spec.js
new file mode 100644
index 00000000000..bbd39c6fcd9
--- /dev/null
+++ b/spec/frontend/ci/pipeline_mini_graph/pipeline_stages_spec.js
@@ -0,0 +1,63 @@
+import { shallowMount } from '@vue/test-utils';
+import { pipelines } from 'test_fixtures/pipelines/pipelines.json';
+import LegacyPipelineStage from '~/ci/pipeline_mini_graph/legacy_pipeline_stage.vue';
+import PipelineStages from '~/ci/pipeline_mini_graph/pipeline_stages.vue';
+
+const mockStages = pipelines[0].details.stages;
+
+describe('Pipeline Stages', () => {
+ let wrapper;
+
+ const findLegacyPipelineStages = () => wrapper.findAllComponents(LegacyPipelineStage);
+ const findPipelineStagesAt = (i) => findLegacyPipelineStages().at(i);
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(PipelineStages, {
+ propsData: {
+ stages: mockStages,
+ ...props,
+ },
+ });
+ };
+
+ it('renders stages', () => {
+ createComponent();
+
+ expect(findLegacyPipelineStages()).toHaveLength(mockStages.length);
+ });
+
+ it('does not fail when stages are empty', () => {
+ createComponent({ stages: [] });
+
+ expect(wrapper.exists()).toBe(true);
+ expect(findLegacyPipelineStages()).toHaveLength(0);
+ });
+
+ it('update dropdown is false by default', () => {
+ createComponent();
+
+ expect(findPipelineStagesAt(0).props('updateDropdown')).toBe(false);
+ expect(findPipelineStagesAt(1).props('updateDropdown')).toBe(false);
+ });
+
+ it('update dropdown is set to true', () => {
+ createComponent({ updateDropdown: true });
+
+ expect(findPipelineStagesAt(0).props('updateDropdown')).toBe(true);
+ expect(findPipelineStagesAt(1).props('updateDropdown')).toBe(true);
+ });
+
+ it('is merge train is false by default', () => {
+ createComponent();
+
+ expect(findPipelineStagesAt(0).props('isMergeTrain')).toBe(false);
+ expect(findPipelineStagesAt(1).props('isMergeTrain')).toBe(false);
+ });
+
+ it('is merge train is set to true', () => {
+ createComponent({ isMergeTrain: true });
+
+ expect(findPipelineStagesAt(0).props('isMergeTrain')).toBe(true);
+ expect(findPipelineStagesAt(1).props('isMergeTrain')).toBe(true);
+ });
+});
diff --git a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js
index 79a0cfa0dc9..33cf24c9ed1 100644
--- a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js
@@ -97,6 +97,7 @@ describe('Pipeline schedules form', () => {
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
// Variables
const findVariableRows = () => wrapper.findAllByTestId('ci-variable-row');
+ const findVariableTypes = () => wrapper.findAllByTestId('pipeline-form-ci-variable-type');
const findKeyInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-key');
const findValueInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-value');
const findHiddenValueInputs = () =>
@@ -182,6 +183,16 @@ describe('Pipeline schedules form', () => {
mock.restore();
});
+ it('changes variable type', async () => {
+ expect(findVariableTypes().at(0).props('selected')).toBe('ENV_VAR');
+
+ findVariableTypes().at(0).vm.$emit('select', 'FILE');
+
+ await nextTick();
+
+ expect(findVariableTypes().at(0).props('selected')).toBe('FILE');
+ });
+
it('creates blank variable on input change event', async () => {
expect(findVariableRows()).toHaveLength(1);
diff --git a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js
index 5cc3829efbd..70b4c7a5224 100644
--- a/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js
@@ -1,5 +1,6 @@
import { GlIcon, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import { s__ } from '~/locale';
import PipelineScheduleTarget from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue';
import { mockPipelineScheduleNodes } from '../../../mock_data';
@@ -20,18 +21,35 @@ describe('Pipeline schedule target', () => {
const findIcon = () => wrapper.findComponent(GlIcon);
const findLink = () => wrapper.findComponent(GlLink);
+ const findTarget = () => wrapper.findComponent('[data-testid="pipeline-schedule-target"]');
- beforeEach(() => {
- createComponent();
- });
+ describe('with ref', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays icon', () => {
+ expect(findIcon().exists()).toBe(true);
+ expect(findIcon().props('name')).toBe('fork');
+ });
- it('displays icon', () => {
- expect(findIcon().exists()).toBe(true);
- expect(findIcon().props('name')).toBe('fork');
+ it('displays ref link', () => {
+ expect(findLink().attributes('href')).toBe(defaultProps.schedule.refPath);
+ expect(findLink().text()).toBe(defaultProps.schedule.refForDisplay);
+ });
});
- it('displays ref link', () => {
- expect(findLink().attributes('href')).toBe(defaultProps.schedule.refPath);
- expect(findLink().text()).toBe(defaultProps.schedule.refForDisplay);
+ describe('without refPath', () => {
+ beforeEach(() => {
+ createComponent({
+ schedule: { ...mockPipelineScheduleNodes[0], refPath: null, refForDisplay: null },
+ });
+ });
+
+ it('displays none for the target', () => {
+ expect(findIcon().exists()).toBe(false);
+ expect(findLink().exists()).toBe(false);
+ expect(findTarget().text()).toBe(s__('PipelineSchedules|None'));
+ });
});
});
diff --git a/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js
deleted file mode 100644
index e4ff9a0545b..00000000000
--- a/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { GlModal } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import TakeOwnershipModalLegacy from '~/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue';
-
-describe('Take ownership modal', () => {
- let wrapper;
- const url = `/root/job-log-tester/-/pipeline_schedules/3/take_ownership`;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMountExtended(TakeOwnershipModalLegacy, {
- propsData: {
- ownershipUrl: url,
- ...props,
- },
- });
- };
-
- const findModal = () => wrapper.findComponent(GlModal);
-
- beforeEach(() => {
- createComponent();
- });
-
- it('has a primary action set to a url and a post data-method', () => {
- const actionPrimary = findModal().props('actionPrimary');
-
- expect(actionPrimary.attributes).toEqual(
- expect.objectContaining({
- category: 'primary',
- variant: 'confirm',
- href: url,
- 'data-method': 'post',
- }),
- );
- });
-
- it('shows a take ownership message', () => {
- expect(findModal().text()).toBe(
- 'Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?',
- );
- });
-});
diff --git a/spec/frontend/ci/pipeline_schedules/mock_data.js b/spec/frontend/ci/pipeline_schedules/mock_data.js
index 8d4e0f1bea6..711b120c61e 100644
--- a/spec/frontend/ci/pipeline_schedules/mock_data.js
+++ b/spec/frontend/ci/pipeline_schedules/mock_data.js
@@ -1,8 +1,8 @@
// Fixture located at spec/frontend/fixtures/pipeline_schedules.rb
+import mockGetSinglePipelineScheduleGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.single.json';
import mockGetPipelineSchedulesGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.json';
import mockGetPipelineSchedulesAsGuestGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.as_guest.json';
import mockGetPipelineSchedulesTakeOwnershipGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.take_ownership.json';
-import mockGetSinglePipelineScheduleGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.single.json';
const {
data: {
diff --git a/spec/frontend/ci/pipelines_page/components/empty_state/ci_templates_spec.js b/spec/frontend/ci/pipelines_page/components/empty_state/ci_templates_spec.js
new file mode 100644
index 00000000000..980a8be24ea
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/empty_state/ci_templates_spec.js
@@ -0,0 +1,107 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import CiTemplates from '~/ci/pipelines_page/components/empty_state/ci_templates.vue';
+
+const pipelineEditorPath = '/-/ci/editor';
+const suggestedCiTemplates = [
+ { name: 'Android', logo: '/assets/illustrations/logos/android.svg' },
+ { name: 'Bash', logo: '/assets/illustrations/logos/bash.svg' },
+ { name: 'C++', logo: '/assets/illustrations/logos/c_plus_plus.svg' },
+];
+
+describe('CI Templates', () => {
+ let wrapper;
+ let trackingSpy;
+
+ const createWrapper = (propsData = {}) => {
+ wrapper = shallowMountExtended(CiTemplates, {
+ provide: {
+ pipelineEditorPath,
+ suggestedCiTemplates,
+ },
+ propsData,
+ });
+ };
+
+ const findTemplateDescription = () => wrapper.findByTestId('template-description');
+ const findTemplateLink = () => wrapper.findByTestId('template-link');
+ const findTemplateNames = () => wrapper.findAllByTestId('template-name');
+ const findTemplateName = () => wrapper.findByTestId('template-name');
+ const findTemplateLogo = () => wrapper.findByTestId('template-logo');
+
+ describe('renders template list', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ it('renders all suggested templates', () => {
+ expect(findTemplateNames().length).toBe(3);
+ expect(wrapper.text()).toContain('Android', 'Bash', 'C++');
+ });
+
+ it('has the correct template name', () => {
+ expect(findTemplateName().text()).toBe('Android');
+ });
+
+ it('links to the correct template', () => {
+ expect(findTemplateLink().attributes('href')).toBe(
+ pipelineEditorPath.concat('?template=Android'),
+ );
+ });
+
+ it('has the link button enabled', () => {
+ expect(findTemplateLink().props('disabled')).toBe(false);
+ });
+
+ it('has the description of the template', () => {
+ expect(findTemplateDescription().text()).toBe(
+ 'Continuous integration and deployment template to test and deploy your Android project.',
+ );
+ });
+
+ it('has the right logo of the template', () => {
+ expect(findTemplateLogo().attributes('src')).toBe('/assets/illustrations/logos/android.svg');
+ });
+ });
+
+ describe('filtering the templates', () => {
+ beforeEach(() => {
+ createWrapper({ filterTemplates: ['Bash'] });
+ });
+
+ it('renders only the filtered templates', () => {
+ expect(findTemplateNames()).toHaveLength(1);
+ expect(findTemplateName().text()).toBe('Bash');
+ });
+ });
+
+ describe('disabling the templates', () => {
+ beforeEach(() => {
+ createWrapper({ disabled: true });
+ });
+
+ it('has the link button disabled', () => {
+ expect(findTemplateLink().props('disabled')).toBe(true);
+ });
+ });
+
+ describe('tracking', () => {
+ beforeEach(() => {
+ createWrapper();
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('sends an event when template is clicked', () => {
+ findTemplateLink().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'template_clicked', {
+ label: 'Android',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/empty_state/ios_templates_spec.js b/spec/frontend/ci/pipelines_page/components/empty_state/ios_templates_spec.js
new file mode 100644
index 00000000000..8620d41886e
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/empty_state/ios_templates_spec.js
@@ -0,0 +1,133 @@
+import '~/commons';
+import { nextTick } from 'vue';
+import { GlPopover, GlButton } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
+import IosTemplates from '~/ci/pipelines_page/components/empty_state/ios_templates.vue';
+import CiTemplates from '~/ci/pipelines_page/components/empty_state/ci_templates.vue';
+
+const pipelineEditorPath = '/-/ci/editor';
+const registrationToken = 'SECRET_TOKEN';
+const iOSTemplateName = 'iOS-Fastlane';
+
+describe('iOS Templates', () => {
+ let wrapper;
+
+ const createWrapper = (providedPropsData = {}) => {
+ return shallowMountExtended(IosTemplates, {
+ provide: {
+ pipelineEditorPath,
+ iosRunnersAvailable: true,
+ ...providedPropsData,
+ },
+ propsData: {
+ registrationToken,
+ },
+ stubs: {
+ GlButton,
+ },
+ });
+ };
+
+ const findIosTemplate = () => wrapper.findComponent(CiTemplates);
+ const findRunnerInstructionsModal = () => wrapper.findComponent(RunnerInstructionsModal);
+ const findRunnerInstructionsPopover = () => wrapper.findComponent(GlPopover);
+ const findRunnerSetupTodoEmoji = () => wrapper.findByTestId('runner-setup-marked-todo');
+ const findRunnerSetupCompletedEmoji = () => wrapper.findByTestId('runner-setup-marked-completed');
+ const findSetupRunnerLink = () => wrapper.findByText('Set up a runner');
+ const configurePipelineLink = () => wrapper.findByTestId('configure-pipeline-link');
+
+ describe('when ios runners are not available', () => {
+ beforeEach(() => {
+ wrapper = createWrapper({ iosRunnersAvailable: false });
+ });
+
+ describe('the runner setup section', () => {
+ it('marks the section as todo', () => {
+ expect(findRunnerSetupTodoEmoji().isVisible()).toBe(true);
+ expect(findRunnerSetupCompletedEmoji().isVisible()).toBe(false);
+ });
+
+ it('renders the setup runner link', () => {
+ expect(findSetupRunnerLink().exists()).toBe(true);
+ });
+
+ it('renders the runner instructions modal with a popover once clicked', async () => {
+ findSetupRunnerLink().element.parentElement.click();
+
+ await nextTick();
+
+ expect(findRunnerInstructionsModal().exists()).toBe(true);
+ expect(findRunnerInstructionsModal().props('registrationToken')).toBe(registrationToken);
+ expect(findRunnerInstructionsModal().props('defaultPlatformName')).toBe('osx');
+
+ findRunnerInstructionsModal().vm.$emit('shown');
+
+ await nextTick();
+
+ expect(findRunnerInstructionsPopover().exists()).toBe(true);
+ });
+ });
+
+ describe('the configure pipeline section', () => {
+ it('has a disabled link button', () => {
+ expect(configurePipelineLink().props('disabled')).toBe(true);
+ });
+ });
+
+ describe('the ios-Fastlane template', () => {
+ it('renders the template', () => {
+ expect(findIosTemplate().props('filterTemplates')).toStrictEqual([iOSTemplateName]);
+ });
+
+ it('has a disabled link button', () => {
+ expect(findIosTemplate().props('disabled')).toBe(true);
+ });
+ });
+ });
+
+ describe('when ios runners are available', () => {
+ beforeEach(() => {
+ wrapper = createWrapper();
+ });
+
+ describe('the runner setup section', () => {
+ it('marks the section as completed', () => {
+ expect(findRunnerSetupTodoEmoji().isVisible()).toBe(false);
+ expect(findRunnerSetupCompletedEmoji().isVisible()).toBe(true);
+ });
+
+ it('does not render the setup runner link', () => {
+ expect(findSetupRunnerLink().exists()).toBe(false);
+ });
+ });
+
+ describe('the configure pipeline section', () => {
+ it('has an enabled link button', () => {
+ expect(configurePipelineLink().props('disabled')).toBe(false);
+ });
+
+ it('links to the pipeline editor with the right template', () => {
+ expect(configurePipelineLink().attributes('href')).toBe(
+ `${pipelineEditorPath}?template=${iOSTemplateName}`,
+ );
+ });
+ });
+
+ describe('the ios-Fastlane template', () => {
+ it('renders the template', () => {
+ expect(findIosTemplate().props('filterTemplates')).toStrictEqual([iOSTemplateName]);
+ });
+
+ it('has an enabled link button', () => {
+ expect(findIosTemplate().props('disabled')).toBe(false);
+ });
+
+ it('links to the pipeline editor with the right template', () => {
+ expect(configurePipelineLink().attributes('href')).toBe(
+ `${pipelineEditorPath}?template=${iOSTemplateName}`,
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/empty_state/no_ci_empty_state_spec.js b/spec/frontend/ci/pipelines_page/components/empty_state/no_ci_empty_state_spec.js
new file mode 100644
index 00000000000..0c42723f753
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/empty_state/no_ci_empty_state_spec.js
@@ -0,0 +1,87 @@
+import '~/commons';
+import { shallowMount } from '@vue/test-utils';
+import { GlEmptyState } from '@gitlab/ui';
+import { stubExperiments } from 'helpers/experimentation_helper';
+import EmptyState from '~/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue';
+import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
+import PipelinesCiTemplates from '~/ci/pipelines_page/components/empty_state/pipelines_ci_templates.vue';
+import IosTemplates from '~/ci/pipelines_page/components/empty_state/ios_templates.vue';
+
+describe('Pipelines Empty State', () => {
+ let wrapper;
+
+ const findIllustration = () => wrapper.find('img');
+ const findButton = () => wrapper.find('a');
+ const pipelinesCiTemplates = () => wrapper.findComponent(PipelinesCiTemplates);
+ const iosTemplates = () => wrapper.findComponent(IosTemplates);
+
+ const createWrapper = (props = {}) => {
+ wrapper = shallowMount(EmptyState, {
+ provide: {
+ pipelineEditorPath: '',
+ suggestedCiTemplates: [],
+ anyRunnersAvailable: true,
+ ciRunnerSettingsPath: '',
+ },
+ propsData: {
+ emptyStateSvgPath: 'foo.svg',
+ canSetCi: true,
+ ...props,
+ },
+ stubs: {
+ GlEmptyState,
+ GitlabExperiment,
+ },
+ });
+ };
+
+ describe('when user can configure CI', () => {
+ describe('when the ios_specific_templates experiment is active', () => {
+ beforeEach(() => {
+ stubExperiments({ ios_specific_templates: 'candidate' });
+ createWrapper();
+ });
+
+ it('should render the iOS templates', () => {
+ expect(iosTemplates().exists()).toBe(true);
+ });
+
+ it('should not render the CI/CD templates', () => {
+ expect(pipelinesCiTemplates().exists()).toBe(false);
+ });
+ });
+
+ describe('when the ios_specific_templates experiment is inactive', () => {
+ beforeEach(() => {
+ stubExperiments({ ios_specific_templates: 'control' });
+ createWrapper();
+ });
+
+ it('should render the CI/CD templates', () => {
+ expect(pipelinesCiTemplates().exists()).toBe(true);
+ });
+
+ it('should not render the iOS templates', () => {
+ expect(iosTemplates().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('when user cannot configure CI', () => {
+ beforeEach(() => {
+ createWrapper({ canSetCi: false });
+ });
+
+ it('should render empty state SVG', () => {
+ expect(findIllustration().attributes('src')).toBe('foo.svg');
+ });
+
+ it('should render empty state header', () => {
+ expect(wrapper.text()).toBe('This project is not currently set up to run pipelines.');
+ });
+
+ it('should not render a link', () => {
+ expect(findButton().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/empty_state/pipelines_ci_templates_spec.js b/spec/frontend/ci/pipelines_page/components/empty_state/pipelines_ci_templates_spec.js
new file mode 100644
index 00000000000..fbef4aa08eb
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/empty_state/pipelines_ci_templates_spec.js
@@ -0,0 +1,58 @@
+import '~/commons';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import PipelinesCiTemplates from '~/ci/pipelines_page/components/empty_state/pipelines_ci_templates.vue';
+import CiTemplates from '~/ci/pipelines_page/components/empty_state/ci_templates.vue';
+
+const pipelineEditorPath = '/-/ci/editor';
+
+describe('Pipelines CI Templates', () => {
+ let wrapper;
+ let trackingSpy;
+
+ const createWrapper = (propsData = {}, stubs = {}) => {
+ return shallowMountExtended(PipelinesCiTemplates, {
+ provide: {
+ pipelineEditorPath,
+ ...propsData,
+ },
+ stubs,
+ });
+ };
+
+ const findTestTemplateLink = () => wrapper.findByTestId('test-template-link');
+ const findCiTemplates = () => wrapper.findComponent(CiTemplates);
+
+ describe('templates', () => {
+ beforeEach(() => {
+ wrapper = createWrapper();
+ });
+
+ it('renders test template and Ci templates', () => {
+ expect(findTestTemplateLink().attributes('href')).toBe(
+ pipelineEditorPath.concat('?template=Getting-Started'),
+ );
+ expect(findCiTemplates().exists()).toBe(true);
+ });
+ });
+
+ describe('tracking', () => {
+ beforeEach(() => {
+ wrapper = createWrapper();
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('sends an event when Getting-Started template is clicked', () => {
+ findTestTemplateLink().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'template_clicked', {
+ label: 'Getting-Started',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/failure_widget/failed_job_details_spec.js b/spec/frontend/ci/pipelines_page/components/failure_widget/failed_job_details_spec.js
new file mode 100644
index 00000000000..6967a369338
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/failure_widget/failed_job_details_spec.js
@@ -0,0 +1,254 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlIcon, GlLink } from '@gitlab/ui';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/alert';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import FailedJobDetails from '~/ci/pipelines_page/components/failure_widget/failed_job_details.vue';
+import RetryMrFailedJobMutation from '~/ci/merge_requests/graphql/mutations/retry_mr_failed_job.mutation.graphql';
+import { BRIDGE_KIND } from '~/ci/pipeline_details/graph/constants';
+import { job } from './mock';
+
+Vue.use(VueApollo);
+jest.mock('~/alert');
+
+const createFakeEvent = () => ({ stopPropagation: jest.fn() });
+
+describe('FailedJobDetails component', () => {
+ let wrapper;
+ let mockRetryResponse;
+
+ const retrySuccessResponse = {
+ data: {
+ jobRetry: {
+ errors: [],
+ },
+ },
+ };
+
+ const defaultProps = {
+ job,
+ };
+
+ const createComponent = ({ props = {} } = {}) => {
+ const handlers = [[RetryMrFailedJobMutation, mockRetryResponse]];
+
+ wrapper = shallowMountExtended(FailedJobDetails, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ apolloProvider: createMockApollo(handlers),
+ });
+ };
+
+ const findArrowIcon = () => wrapper.findComponent(GlIcon);
+ const findJobId = () => wrapper.findComponent(GlLink);
+ const findJobLog = () => wrapper.findByTestId('job-log');
+ const findJobName = () => wrapper.findByText(defaultProps.job.name);
+ const findRetryButton = () => wrapper.findByLabelText('Retry');
+ const findRow = () => wrapper.findByTestId('widget-row');
+ const findStageName = () => wrapper.findByText(defaultProps.job.stage.name);
+
+ beforeEach(() => {
+ mockRetryResponse = jest.fn();
+ mockRetryResponse.mockResolvedValue(retrySuccessResponse);
+ });
+
+ describe('ui', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the job name', () => {
+ expect(findJobName().exists()).toBe(true);
+ });
+
+ it('renders the stage name', () => {
+ expect(findStageName().exists()).toBe(true);
+ });
+
+ it('renders the job id as a link', () => {
+ const jobId = getIdFromGraphQLId(defaultProps.job.id);
+
+ expect(findJobId().exists()).toBe(true);
+ expect(findJobId().text()).toContain(String(jobId));
+ });
+
+ it('does not renders the job lob', () => {
+ expect(findJobLog().exists()).toBe(false);
+ });
+ });
+
+ describe('Retry action', () => {
+ describe('when the job is not retryable', () => {
+ beforeEach(() => {
+ createComponent({ props: { job: { ...job, retryable: false } } });
+ });
+
+ it('disables the retry button', () => {
+ expect(findRetryButton().props().disabled).toBe(true);
+ });
+ });
+
+ describe('when the job is a bridge', () => {
+ beforeEach(() => {
+ createComponent({ props: { job: { ...job, kind: BRIDGE_KIND } } });
+ });
+
+ it('disables the retry button', () => {
+ expect(findRetryButton().props().disabled).toBe(true);
+ });
+ });
+
+ describe('when the job is retryable', () => {
+ describe('and user has permission to update the build', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('enables the retry button', () => {
+ expect(findRetryButton().props().disabled).toBe(false);
+ });
+
+ describe('when clicking on the retry button', () => {
+ it('passes the loading state to the button', async () => {
+ await findRetryButton().vm.$emit('click', createFakeEvent());
+
+ expect(findRetryButton().props().loading).toBe(true);
+ });
+
+ describe('and it succeeds', () => {
+ beforeEach(async () => {
+ findRetryButton().vm.$emit('click', createFakeEvent());
+ await waitForPromises();
+ });
+
+ it('is no longer loading', () => {
+ expect(findRetryButton().props().loading).toBe(false);
+ });
+
+ it('calls the retry mutation', () => {
+ expect(mockRetryResponse).toHaveBeenCalled();
+ expect(mockRetryResponse).toHaveBeenCalledWith({
+ id: job.id,
+ });
+ });
+
+ it('emits the `retried-job` event', () => {
+ expect(wrapper.emitted('job-retried')).toStrictEqual([[job.name]]);
+ });
+ });
+
+ describe('and it fails', () => {
+ const customErrorMsg = 'Custom error message from API';
+
+ beforeEach(async () => {
+ mockRetryResponse.mockResolvedValue({
+ data: { jobRetry: { errors: [customErrorMsg] } },
+ });
+ findRetryButton().vm.$emit('click', createFakeEvent());
+
+ await waitForPromises();
+ });
+
+ it('shows an error message', () => {
+ expect(createAlert).toHaveBeenCalledWith({ message: customErrorMsg });
+ });
+
+ it('does not emits the `refetch-jobs` event', () => {
+ expect(wrapper.emitted('refetch-jobs')).toBeUndefined();
+ });
+ });
+ });
+ });
+
+ describe('and user does not have permission to update the build', () => {
+ beforeEach(() => {
+ createComponent({
+ props: { job: { ...job, retryable: true, userPermissions: { updateBuild: false } } },
+ });
+ });
+
+ it('disables the retry button', () => {
+ expect(findRetryButton().props().disabled).toBe(true);
+ });
+ });
+ });
+ });
+
+ describe('Job log', () => {
+ describe('without permissions', () => {
+ beforeEach(async () => {
+ createComponent({ props: { job: { ...job, userPermissions: { readBuild: false } } } });
+ await findRow().trigger('click');
+ });
+
+ it('does not renders the received html of the job log', () => {
+ expect(findJobLog().html()).not.toContain(defaultProps.job.trace.htmlSummary);
+ });
+
+ it('shows a permission error message', () => {
+ expect(findJobLog().text()).toBe("You do not have permission to read this job's log.");
+ });
+ });
+
+ describe('with permissions', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ describe('when clicking on the row', () => {
+ beforeEach(async () => {
+ await findRow().trigger('click');
+ });
+
+ describe('while collapsed', () => {
+ it('expands the job log', () => {
+ expect(findJobLog().exists()).toBe(true);
+ });
+
+ it('renders the down arrow', () => {
+ expect(findArrowIcon().props().name).toBe('chevron-down');
+ });
+
+ it('renders the received html of the job log', () => {
+ expect(findJobLog().html()).toContain(defaultProps.job.trace.htmlSummary);
+ });
+ });
+
+ describe('while expanded', () => {
+ it('collapes the job log', async () => {
+ expect(findJobLog().exists()).toBe(true);
+
+ await findRow().trigger('click');
+
+ expect(findJobLog().exists()).toBe(false);
+ });
+
+ it('renders the right arrow', async () => {
+ expect(findArrowIcon().props().name).toBe('chevron-down');
+
+ await findRow().trigger('click');
+
+ expect(findArrowIcon().props().name).toBe('chevron-right');
+ });
+ });
+ });
+
+ describe('when clicking on a link element within the row', () => {
+ it('does not expands/collapse the job log', async () => {
+ expect(findJobLog().exists()).toBe(false);
+ expect(findArrowIcon().props().name).toBe('chevron-right');
+
+ await findJobId().vm.$emit('click');
+
+ expect(findJobLog().exists()).toBe(false);
+ expect(findArrowIcon().props().name).toBe('chevron-right');
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/failure_widget/failed_jobs_list_spec.js b/spec/frontend/ci/pipelines_page/components/failure_widget/failed_jobs_list_spec.js
new file mode 100644
index 00000000000..af075b02b64
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/failure_widget/failed_jobs_list_spec.js
@@ -0,0 +1,279 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+
+import { GlLoadingIcon, GlToast } from '@gitlab/ui';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/alert';
+import FailedJobsList from '~/ci/pipelines_page/components/failure_widget/failed_jobs_list.vue';
+import FailedJobDetails from '~/ci/pipelines_page/components/failure_widget/failed_job_details.vue';
+import * as utils from '~/ci/pipelines_page/components/failure_widget/utils';
+import getPipelineFailedJobs from '~/ci/pipelines_page/graphql/queries/get_pipeline_failed_jobs.query.graphql';
+import { failedJobsMock, failedJobsMock2, failedJobsMockEmpty, activeFailedJobsMock } from './mock';
+
+Vue.use(VueApollo);
+Vue.use(GlToast);
+
+jest.mock('~/alert');
+
+describe('FailedJobsList component', () => {
+ let wrapper;
+ let mockFailedJobsResponse;
+ const showToast = jest.fn();
+
+ const defaultProps = {
+ failedJobsCount: 0,
+ graphqlResourceEtag: 'api/graphql',
+ isPipelineActive: false,
+ pipelineIid: 1,
+ projectPath: 'namespace/project/',
+ };
+
+ const defaultProvide = {
+ graphqlPath: 'api/graphql',
+ };
+
+ const createComponent = ({ props = {}, provide } = {}) => {
+ const handlers = [[getPipelineFailedJobs, mockFailedJobsResponse]];
+ const mockApollo = createMockApollo(handlers);
+
+ wrapper = shallowMountExtended(FailedJobsList, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ apolloProvider: mockApollo,
+ mocks: {
+ $toast: {
+ show: showToast,
+ },
+ },
+ });
+ };
+
+ const findAllHeaders = () => wrapper.findAllByTestId('header');
+ const findFailedJobRows = () => wrapper.findAllComponents(FailedJobDetails);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findNoFailedJobsText = () => wrapper.findByText('No failed jobs in this pipeline 🎉');
+
+ beforeEach(() => {
+ mockFailedJobsResponse = jest.fn();
+ });
+
+ describe('on mount', () => {
+ beforeEach(() => {
+ mockFailedJobsResponse.mockResolvedValue(failedJobsMock);
+ createComponent();
+ });
+
+ it('fires the graphql query', () => {
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
+ expect(mockFailedJobsResponse).toHaveBeenCalledWith({
+ fullPath: defaultProps.projectPath,
+ pipelineIid: defaultProps.pipelineIid,
+ });
+ });
+ });
+
+ describe('when loading failed jobs', () => {
+ beforeEach(() => {
+ mockFailedJobsResponse.mockResolvedValue(failedJobsMock);
+ createComponent();
+ });
+
+ it('shows a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('when failed jobs have loaded', () => {
+ beforeEach(async () => {
+ mockFailedJobsResponse.mockResolvedValue(failedJobsMock);
+ jest.spyOn(utils, 'sortJobsByStatus');
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('does not renders a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('renders table column', () => {
+ expect(findAllHeaders()).toHaveLength(3);
+ });
+
+ it('shows the list of failed jobs', () => {
+ expect(findFailedJobRows()).toHaveLength(
+ failedJobsMock.data.project.pipeline.jobs.nodes.length,
+ );
+ });
+
+ it('does not renders the empty state', () => {
+ expect(findNoFailedJobsText().exists()).toBe(false);
+ });
+
+ it('calls sortJobsByStatus', () => {
+ expect(utils.sortJobsByStatus).toHaveBeenCalledWith(
+ failedJobsMock.data.project.pipeline.jobs.nodes,
+ );
+ });
+ });
+
+ describe('when there are no failed jobs', () => {
+ beforeEach(async () => {
+ mockFailedJobsResponse.mockResolvedValue(failedJobsMockEmpty);
+ jest.spyOn(utils, 'sortJobsByStatus');
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('renders the empty state', () => {
+ expect(findNoFailedJobsText().exists()).toBe(true);
+ });
+ });
+
+ describe('polling', () => {
+ it.each`
+ isGraphqlActive | text
+ ${true} | ${'polls'}
+ ${false} | ${'does not poll'}
+ `(`$text when isGraphqlActive: $isGraphqlActive`, async ({ isGraphqlActive }) => {
+ const defaultCount = 2;
+ const newCount = 1;
+
+ const expectedCount = isGraphqlActive ? newCount : defaultCount;
+ const expectedCallCount = isGraphqlActive ? 2 : 1;
+ const mockResponse = isGraphqlActive ? activeFailedJobsMock : failedJobsMock;
+
+ // Second result is to simulate polling with a different response
+ mockFailedJobsResponse.mockResolvedValueOnce(mockResponse);
+ mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock2);
+
+ createComponent();
+ await waitForPromises();
+
+ // Initially, we get the first response which is always the default
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
+ expect(findFailedJobRows()).toHaveLength(defaultCount);
+
+ jest.advanceTimersByTime(10000);
+ await waitForPromises();
+
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(expectedCallCount);
+ expect(findFailedJobRows()).toHaveLength(expectedCount);
+ });
+ });
+
+ describe('when a REST action occurs', () => {
+ beforeEach(() => {
+ // Second result is to simulate polling with a different response
+ mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock);
+ mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock2);
+ });
+
+ it.each([true, false])('triggers a refetch of the jobs count', async (isPipelineActive) => {
+ const defaultCount = 2;
+ const newCount = 1;
+
+ createComponent({ props: { isPipelineActive } });
+ await waitForPromises();
+
+ // Initially, we get the first response which is always the default
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
+ expect(findFailedJobRows()).toHaveLength(defaultCount);
+
+ wrapper.setProps({ isPipelineActive: !isPipelineActive });
+ await waitForPromises();
+
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(2);
+ expect(findFailedJobRows()).toHaveLength(newCount);
+ });
+ });
+
+ describe('When the job count changes from REST', () => {
+ beforeEach(() => {
+ mockFailedJobsResponse.mockResolvedValue(failedJobsMockEmpty);
+
+ createComponent();
+ });
+
+ describe('and the count is the same', () => {
+ it('does not re-fetch the query', async () => {
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
+
+ await wrapper.setProps({ failedJobsCount: 0 });
+
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('and the count is different', () => {
+ it('re-fetches the query', async () => {
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
+
+ await wrapper.setProps({ failedJobsCount: 10 });
+
+ expect(mockFailedJobsResponse).toHaveBeenCalledTimes(2);
+ });
+ });
+ });
+
+ describe('when an error occurs loading jobs', () => {
+ const errorMessage = "We couldn't fetch jobs for you because you are not qualified";
+
+ beforeEach(async () => {
+ mockFailedJobsResponse.mockRejectedValue({ message: errorMessage });
+
+ createComponent();
+
+ await waitForPromises();
+ });
+ it('does not renders a loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('calls create Alert with the error message and danger variant', () => {
+ expect(createAlert).toHaveBeenCalledWith({ message: errorMessage, variant: 'danger' });
+ });
+ });
+
+ describe('when `refetch-jobs` job is fired from the widget', () => {
+ beforeEach(async () => {
+ mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock);
+ mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock2);
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('refetches all failed jobs', async () => {
+ expect(findFailedJobRows()).not.toHaveLength(
+ failedJobsMock2.data.project.pipeline.jobs.nodes.length,
+ );
+
+ await findFailedJobRows().at(0).vm.$emit('job-retried', 'job-name');
+ await waitForPromises();
+
+ expect(findFailedJobRows()).toHaveLength(
+ failedJobsMock2.data.project.pipeline.jobs.nodes.length,
+ );
+ });
+
+ it('shows a toast message', async () => {
+ await findFailedJobRows().at(0).vm.$emit('job-retried', 'job-name');
+ await waitForPromises();
+
+ expect(showToast).toHaveBeenCalledWith('job-name job is being retried');
+ });
+ });
+});
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/mock.js b/spec/frontend/ci/pipelines_page/components/failure_widget/mock.js
index 318d787a984..318d787a984 100644
--- a/spec/frontend/pipelines/components/pipelines_list/failure_widget/mock.js
+++ b/spec/frontend/ci/pipelines_page/components/failure_widget/mock.js
diff --git a/spec/frontend/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget_spec.js b/spec/frontend/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget_spec.js
new file mode 100644
index 00000000000..e52b62feb23
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget_spec.js
@@ -0,0 +1,139 @@
+import { GlButton, GlCard, GlIcon, GlPopover } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import PipelineFailedJobsWidget from '~/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue';
+import FailedJobsList from '~/ci/pipelines_page/components/failure_widget/failed_jobs_list.vue';
+
+jest.mock('~/alert');
+
+describe('PipelineFailedJobsWidget component', () => {
+ let wrapper;
+
+ const defaultProps = {
+ failedJobsCount: 4,
+ isPipelineActive: false,
+ pipelineIid: 1,
+ pipelinePath: '/pipelines/1',
+ projectPath: 'namespace/project/',
+ };
+
+ const defaultProvide = {
+ fullPath: 'namespace/project/',
+ };
+
+ const createComponent = ({ props = {}, provide = {} } = {}) => {
+ wrapper = shallowMountExtended(PipelineFailedJobsWidget, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ stubs: { GlCard },
+ });
+ };
+
+ const findFailedJobsCard = () => wrapper.findByTestId('failed-jobs-card');
+ const findFailedJobsButton = () => wrapper.findComponent(GlButton);
+ const findFailedJobsList = () => wrapper.findAllComponents(FailedJobsList);
+ const findInfoIcon = () => wrapper.findComponent(GlIcon);
+ const findInfoPopover = () => wrapper.findComponent(GlPopover);
+
+ describe('when there are no failed jobs', () => {
+ beforeEach(() => {
+ createComponent({ props: { failedJobsCount: 0 } });
+ });
+
+ it('renders the show failed jobs button with a count of 0', () => {
+ expect(findFailedJobsButton().exists()).toBe(true);
+ expect(findFailedJobsButton().text()).toBe('Failed jobs (0)');
+ });
+ });
+
+ describe('when there are failed jobs', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the show failed jobs button with correct count', () => {
+ expect(findFailedJobsButton().exists()).toBe(true);
+ expect(findFailedJobsButton().text()).toBe(`Failed jobs (${defaultProps.failedJobsCount})`);
+ });
+
+ it('renders the info icon', () => {
+ expect(findInfoIcon().exists()).toBe(true);
+ });
+
+ it('renders the info popover', () => {
+ expect(findInfoPopover().exists()).toBe(true);
+ });
+
+ it('does not render the failed jobs widget', () => {
+ expect(findFailedJobsList().exists()).toBe(false);
+ });
+ });
+
+ describe('when the job button is clicked', () => {
+ beforeEach(async () => {
+ createComponent();
+ await findFailedJobsButton().vm.$emit('click');
+ });
+
+ it('renders the failed jobs widget', () => {
+ expect(findFailedJobsList().exists()).toBe(true);
+ });
+
+ it('removes the CSS border classes', () => {
+ expect(findFailedJobsCard().attributes('class')).not.toContain(
+ 'gl-border-white gl-hover-border-gray-100',
+ );
+ });
+ });
+
+ describe('when the job details are not expanded', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('has the CSS border classes', () => {
+ expect(findFailedJobsCard().attributes('class')).toContain(
+ 'gl-border-white gl-hover-border-gray-100',
+ );
+ });
+ });
+
+ describe('when the job count changes', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ describe('from the prop', () => {
+ it('updates the job count', async () => {
+ const newJobCount = 12;
+
+ expect(findFailedJobsButton().text()).toContain(String(defaultProps.failedJobsCount));
+
+ await wrapper.setProps({ failedJobsCount: newJobCount });
+
+ expect(findFailedJobsButton().text()).toContain(String(newJobCount));
+ });
+ });
+
+ describe('from the event', () => {
+ beforeEach(async () => {
+ await findFailedJobsButton().vm.$emit('click');
+ });
+
+ it('updates the job count', async () => {
+ const newJobCount = 12;
+
+ expect(findFailedJobsButton().text()).toContain(String(defaultProps.failedJobsCount));
+
+ await findFailedJobsList().at(0).vm.$emit('failed-jobs-count', newJobCount);
+
+ expect(findFailedJobsButton().text()).toContain(String(newJobCount));
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/failure_widget/utils_spec.js b/spec/frontend/ci/pipelines_page/components/failure_widget/utils_spec.js
new file mode 100644
index 00000000000..5755cd846ac
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/failure_widget/utils_spec.js
@@ -0,0 +1,55 @@
+import { isFailedJob, sortJobsByStatus } from '~/ci/pipelines_page/components/failure_widget/utils';
+
+describe('isFailedJob', () => {
+ describe('when the job argument is undefined', () => {
+ it('returns false', () => {
+ expect(isFailedJob()).toBe(false);
+ });
+ });
+
+ describe('when the job is of status `failed`', () => {
+ it('returns false', () => {
+ expect(isFailedJob({ detailedStatus: { group: 'success' } })).toBe(false);
+ });
+ });
+
+ describe('when the job status is `failed`', () => {
+ it('returns true', () => {
+ expect(isFailedJob({ detailedStatus: { group: 'failed' } })).toBe(true);
+ });
+ });
+});
+
+describe('sortJobsByStatus', () => {
+ describe('when the arg is undefined', () => {
+ it('returns an empty array', () => {
+ expect(sortJobsByStatus()).toEqual([]);
+ });
+ });
+
+ describe('when receiving an empty array', () => {
+ it('returns an empty array', () => {
+ expect(sortJobsByStatus([])).toEqual([]);
+ });
+ });
+
+ describe('when reciving a list of jobs', () => {
+ const jobArr = [
+ { detailedStatus: { group: 'failed' } },
+ { detailedStatus: { group: 'allowed_to_fail' } },
+ { detailedStatus: { group: 'failed' } },
+ { detailedStatus: { group: 'success' } },
+ ];
+
+ const expectedResult = [
+ { detailedStatus: { group: 'failed' } },
+ { detailedStatus: { group: 'failed' } },
+ { detailedStatus: { group: 'allowed_to_fail' } },
+ { detailedStatus: { group: 'success' } },
+ ];
+
+ it('sorts failed jobs first', () => {
+ expect(sortJobsByStatus(jobArr)).toEqual(expectedResult);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/nav_controls_spec.js b/spec/frontend/ci/pipelines_page/components/nav_controls_spec.js
new file mode 100644
index 00000000000..f4858ac27ea
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/nav_controls_spec.js
@@ -0,0 +1,80 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import NavControls from '~/ci/pipelines_page/components/nav_controls.vue';
+
+describe('Pipelines Nav Controls', () => {
+ let wrapper;
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(NavControls, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findRunPipelineButton = () => wrapper.findByTestId('run-pipeline-button');
+ const findCiLintButton = () => wrapper.findByTestId('ci-lint-button');
+ const findClearCacheButton = () => wrapper.findByTestId('clear-cache-button');
+
+ it('should render link to create a new pipeline', () => {
+ const mockData = {
+ newPipelinePath: 'foo',
+ ciLintPath: 'foo',
+ resetCachePath: 'foo',
+ };
+
+ createComponent(mockData);
+
+ const runPipelineButton = findRunPipelineButton();
+ expect(runPipelineButton.text()).toContain('Run pipeline');
+ expect(runPipelineButton.attributes('href')).toBe(mockData.newPipelinePath);
+ });
+
+ it('should not render link to create pipeline if no path is provided', () => {
+ const mockData = {
+ helpPagePath: 'foo',
+ ciLintPath: 'foo',
+ resetCachePath: 'foo',
+ };
+
+ createComponent(mockData);
+
+ expect(findRunPipelineButton().exists()).toBe(false);
+ });
+
+ it('should render link for CI lint', () => {
+ const mockData = {
+ newPipelinePath: 'foo',
+ helpPagePath: 'foo',
+ ciLintPath: 'foo',
+ resetCachePath: 'foo',
+ };
+
+ createComponent(mockData);
+ const ciLintButton = findCiLintButton();
+
+ expect(ciLintButton.text()).toContain('CI lint');
+ expect(ciLintButton.attributes('href')).toBe(mockData.ciLintPath);
+ });
+
+ describe('Reset Runners Cache', () => {
+ beforeEach(() => {
+ const mockData = {
+ newPipelinePath: 'foo',
+ ciLintPath: 'foo',
+ resetCachePath: 'foo',
+ };
+ createComponent(mockData);
+ });
+
+ it('should render button for resetting runner caches', () => {
+ expect(findClearCacheButton().text()).toContain('Clear runner caches');
+ });
+
+ it('should emit postAction event when reset runner cache button is clicked', () => {
+ findClearCacheButton().vm.$emit('click');
+
+ expect(wrapper.emitted('resetRunnersCache')).toEqual([['foo']]);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipeline_labels_spec.js b/spec/frontend/ci/pipelines_page/components/pipeline_labels_spec.js
new file mode 100644
index 00000000000..b5c9a3030e0
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipeline_labels_spec.js
@@ -0,0 +1,164 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { trimText } from 'helpers/text_helper';
+import PipelineLabelsComponent from '~/ci/pipelines_page/components/pipeline_labels.vue';
+import { mockPipeline } from 'jest/ci/pipeline_details/mock_data';
+
+const projectPath = 'test/test';
+
+describe('Pipeline label component', () => {
+ let wrapper;
+
+ const findScheduledTag = () => wrapper.findByTestId('pipeline-url-scheduled');
+ const findLatestTag = () => wrapper.findByTestId('pipeline-url-latest');
+ const findYamlTag = () => wrapper.findByTestId('pipeline-url-yaml');
+ const findStuckTag = () => wrapper.findByTestId('pipeline-url-stuck');
+ const findAutoDevopsTag = () => wrapper.findByTestId('pipeline-url-autodevops');
+ const findAutoDevopsTagLink = () => wrapper.findByTestId('pipeline-url-autodevops-link');
+ const findDetachedTag = () => wrapper.findByTestId('pipeline-url-detached');
+ const findFailureTag = () => wrapper.findByTestId('pipeline-url-failure');
+ const findForkTag = () => wrapper.findByTestId('pipeline-url-fork');
+ const findTrainTag = () => wrapper.findByTestId('pipeline-url-train');
+
+ const defaultProps = mockPipeline(projectPath);
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(PipelineLabelsComponent, {
+ propsData: { ...defaultProps, ...props },
+ provide: {
+ targetProjectFullPath: projectPath,
+ },
+ });
+ };
+
+ it('should not render tags when flags are not set', () => {
+ createComponent();
+
+ expect(findStuckTag().exists()).toBe(false);
+ expect(findLatestTag().exists()).toBe(false);
+ expect(findYamlTag().exists()).toBe(false);
+ expect(findAutoDevopsTag().exists()).toBe(false);
+ expect(findFailureTag().exists()).toBe(false);
+ expect(findScheduledTag().exists()).toBe(false);
+ expect(findForkTag().exists()).toBe(false);
+ expect(findTrainTag().exists()).toBe(false);
+ });
+
+ it('should render the stuck tag when flag is provided', () => {
+ const stuckPipeline = defaultProps.pipeline;
+ stuckPipeline.flags.stuck = true;
+
+ createComponent({
+ ...stuckPipeline.pipeline,
+ });
+
+ expect(findStuckTag().text()).toContain('stuck');
+ });
+
+ it('should render latest tag when flag is provided', () => {
+ const latestPipeline = defaultProps.pipeline;
+ latestPipeline.flags.latest = true;
+
+ createComponent({
+ ...latestPipeline,
+ });
+
+ expect(findLatestTag().text()).toContain('latest');
+ });
+
+ it('should render a yaml badge when it is invalid', () => {
+ const yamlPipeline = defaultProps.pipeline;
+ yamlPipeline.flags.yaml_errors = true;
+
+ createComponent({
+ ...yamlPipeline,
+ });
+
+ expect(findYamlTag().text()).toContain('yaml invalid');
+ });
+
+ it('should render an autodevops badge when flag is provided', () => {
+ const autoDevopsPipeline = defaultProps.pipeline;
+ autoDevopsPipeline.flags.auto_devops = true;
+
+ createComponent({
+ ...autoDevopsPipeline,
+ });
+
+ expect(trimText(findAutoDevopsTag().text())).toBe('Auto DevOps');
+
+ expect(findAutoDevopsTagLink().attributes()).toMatchObject({
+ href: '/help/topics/autodevops/index.md',
+ target: '_blank',
+ });
+ });
+
+ it('should render a detached badge when flag is provided', () => {
+ const detachedMRPipeline = defaultProps.pipeline;
+ detachedMRPipeline.flags.detached_merge_request_pipeline = true;
+
+ createComponent({
+ ...detachedMRPipeline,
+ });
+
+ expect(findDetachedTag().text()).toBe('merge request');
+ });
+
+ it('should render error badge when pipeline has a failure reason set', () => {
+ const failedPipeline = defaultProps.pipeline;
+ failedPipeline.flags.failure_reason = true;
+ failedPipeline.failure_reason = 'some reason';
+
+ createComponent({
+ ...failedPipeline,
+ });
+
+ expect(findFailureTag().text()).toContain('error');
+ expect(findFailureTag().attributes('title')).toContain('some reason');
+ });
+
+ it('should render scheduled badge when pipeline was triggered by a schedule', () => {
+ const scheduledPipeline = defaultProps.pipeline;
+ scheduledPipeline.source = 'schedule';
+
+ createComponent({
+ ...scheduledPipeline,
+ });
+
+ expect(findScheduledTag().exists()).toBe(true);
+ expect(findScheduledTag().text()).toContain('Scheduled');
+ });
+
+ it('should render the fork badge when the pipeline was run in a fork', () => {
+ const forkedPipeline = defaultProps.pipeline;
+ forkedPipeline.project.full_path = '/test/forked';
+
+ createComponent({
+ ...forkedPipeline,
+ });
+
+ expect(findForkTag().exists()).toBe(true);
+ expect(findForkTag().text()).toBe('fork');
+ });
+
+ it('should render the train badge when the pipeline is a merge train pipeline', () => {
+ const mergeTrainPipeline = defaultProps.pipeline;
+ mergeTrainPipeline.flags.merge_train_pipeline = true;
+
+ createComponent({
+ ...mergeTrainPipeline,
+ });
+
+ expect(findTrainTag().text()).toBe('merge train');
+ });
+
+ it('should not render the train badge when the pipeline is not a merge train pipeline', () => {
+ const mergeTrainPipeline = defaultProps.pipeline;
+ mergeTrainPipeline.flags.merge_train_pipeline = false;
+
+ createComponent({
+ ...mergeTrainPipeline,
+ });
+
+ expect(findTrainTag().exists()).toBe(false);
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipeline_multi_actions_spec.js b/spec/frontend/ci/pipelines_page/components/pipeline_multi_actions_spec.js
new file mode 100644
index 00000000000..7ae21db8815
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipeline_multi_actions_spec.js
@@ -0,0 +1,316 @@
+import { nextTick } from 'vue';
+import {
+ GlAlert,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlSprintf,
+ GlLoadingIcon,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { stubComponent } from 'helpers/stub_component';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import PipelineMultiActions, {
+ i18n,
+} from '~/ci/pipelines_page/components/pipeline_multi_actions.vue';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+
+describe('Pipeline Multi Actions Dropdown', () => {
+ let wrapper;
+ let mockAxios;
+
+ const artifacts = [
+ {
+ name: 'job my-artifact',
+ path: '/download/path',
+ },
+ {
+ name: 'job-2 my-artifact-2',
+ path: '/download/path-two',
+ },
+ ];
+ const newArtifacts = [
+ {
+ name: 'job-3 my-new-artifact',
+ path: '/new/download/path',
+ },
+ {
+ name: 'job-4 my-new-artifact-2',
+ path: '/new/download/path-two',
+ },
+ {
+ name: 'job-5 my-new-artifact-3',
+ path: '/new/download/path-three',
+ },
+ ];
+ const artifactItemTestId = 'artifact-item';
+ const artifactsEndpointPlaceholder = ':pipeline_artifacts_id';
+ const artifactsEndpoint = `endpoint/${artifactsEndpointPlaceholder}/artifacts.json`;
+ const pipelineId = 108;
+
+ const createComponent = () => {
+ wrapper = extendedWrapper(
+ shallowMount(PipelineMultiActions, {
+ provide: {
+ artifactsEndpoint,
+ artifactsEndpointPlaceholder,
+ },
+ propsData: {
+ pipelineId,
+ },
+ stubs: {
+ GlAlert,
+ GlSprintf,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlSearchBoxByType: stubComponent(GlSearchBoxByType),
+ },
+ }),
+ );
+ };
+
+ const findAlert = () => wrapper.findByTestId('artifacts-fetch-error');
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findFirstArtifactItem = () => wrapper.findByTestId(artifactItemTestId);
+ const findAllArtifactItemsData = () =>
+ findDropdown()
+ .props('items')
+ .map(({ text, href }) => ({
+ name: text,
+ path: href,
+ }));
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findEmptyMessage = () => wrapper.findByTestId('artifacts-empty-message');
+ const findWarning = () => wrapper.findByTestId('artifacts-fetch-warning');
+ const changePipelineId = (newId) => wrapper.setProps({ pipelineId: newId });
+
+ beforeEach(() => {
+ mockAxios = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ it('should render the dropdown', () => {
+ createComponent();
+
+ expect(findDropdown().exists()).toBe(true);
+ });
+
+ describe('Artifacts', () => {
+ const endpoint = artifactsEndpoint.replace(artifactsEndpointPlaceholder, pipelineId);
+
+ describe('while loading artifacts', () => {
+ beforeEach(() => {
+ mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_OK, { artifacts });
+ });
+
+ it('should render a loading spinner and no empty message', async () => {
+ createComponent();
+
+ findDropdown().vm.$emit('shown');
+ await nextTick();
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ expect(findEmptyMessage().exists()).toBe(false);
+ });
+ });
+
+ describe('artifacts loaded successfully', () => {
+ describe('artifacts exist', () => {
+ beforeEach(async () => {
+ mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_OK, { artifacts });
+
+ createComponent();
+
+ findDropdown().vm.$emit('shown');
+ await waitForPromises();
+ });
+
+ it('should fetch artifacts and show search box on dropdown click', () => {
+ expect(mockAxios.history.get).toHaveLength(1);
+ expect(findSearchBox().exists()).toBe(true);
+ });
+
+ it('should focus the search box when opened with artifacts', () => {
+ findDropdown().vm.$emit('shown');
+
+ expect(findSearchBox().attributes('autofocus')).not.toBe(undefined);
+ });
+
+ it('should clear searchQuery when dropdown is closed', async () => {
+ findDropdown().vm.$emit('shown');
+ findSearchBox().vm.$emit('input', 'job-2');
+ await waitForPromises();
+
+ expect(findSearchBox().vm.value).toBe('job-2');
+
+ findDropdown().vm.$emit('hidden');
+ await waitForPromises();
+
+ expect(findSearchBox().vm.value).toBe('');
+ });
+
+ it('should render all the provided artifacts when search query is empty', async () => {
+ findSearchBox().vm.$emit('input', '');
+ await waitForPromises();
+
+ expect(findAllArtifactItemsData()).toEqual(
+ artifacts.map(({ name, path }) => ({ name, path })),
+ );
+ expect(findEmptyMessage().exists()).toBe(false);
+ });
+
+ it('should render filtered artifacts when search query is not empty', async () => {
+ findSearchBox().vm.$emit('input', 'job-2');
+ await waitForPromises();
+
+ expect(findAllArtifactItemsData()).toEqual([
+ {
+ name: 'job-2 my-artifact-2',
+ path: '/download/path-two',
+ },
+ ]);
+ expect(findEmptyMessage().exists()).toBe(false);
+ });
+
+ it('should render the correct artifact name and path', () => {
+ expect(findFirstArtifactItem().attributes('href')).toBe(artifacts[0].path);
+ expect(findFirstArtifactItem().text()).toBe(artifacts[0].name);
+ });
+
+ describe('when opened again with new artifacts', () => {
+ describe('with a successful refetch', () => {
+ beforeEach(async () => {
+ mockAxios.resetHistory();
+ mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_OK, { artifacts: newArtifacts });
+
+ findDropdown().vm.$emit('shown');
+ await nextTick();
+ });
+
+ it('should hide list and render a loading spinner on dropdown click', () => {
+ expect(findAllArtifactItemsData()).toHaveLength(0);
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('should not render warning or empty message while loading', () => {
+ expect(findEmptyMessage().exists()).toBe(false);
+ expect(findWarning().exists()).toBe(false);
+ });
+
+ it('should render the correct new list', async () => {
+ await waitForPromises();
+
+ expect(findAllArtifactItemsData()).toEqual(newArtifacts);
+ });
+ });
+
+ describe('with a failing refetch', () => {
+ beforeEach(async () => {
+ mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+
+ findDropdown().vm.$emit('shown');
+ await waitForPromises();
+ });
+
+ it('should render warning', () => {
+ expect(findWarning().text()).toBe(i18n.artifactsFetchWarningMessage);
+ });
+
+ it('should render old list', () => {
+ expect(findAllArtifactItemsData()).toEqual(artifacts);
+ });
+ });
+ });
+
+ describe('pipeline id has changed', () => {
+ const newEndpoint = artifactsEndpoint.replace(
+ artifactsEndpointPlaceholder,
+ pipelineId + 1,
+ );
+
+ beforeEach(() => {
+ changePipelineId(pipelineId + 1);
+ });
+
+ describe('followed by a failing request', () => {
+ beforeEach(async () => {
+ mockAxios.onGet(newEndpoint).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+
+ findDropdown().vm.$emit('shown');
+ await waitForPromises();
+ });
+
+ it('should render error message and no warning', () => {
+ expect(findWarning().exists()).toBe(false);
+ expect(findAlert().text()).toBe(i18n.artifactsFetchErrorMessage);
+ });
+
+ it('should clear list', () => {
+ expect(findAllArtifactItemsData()).toHaveLength(0);
+ });
+ });
+ });
+ });
+
+ describe('artifacts list is empty', () => {
+ beforeEach(() => {
+ mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_OK, { artifacts: [] });
+ });
+
+ it('should render empty message and no search box when no artifacts are found', async () => {
+ createComponent();
+
+ findDropdown().vm.$emit('shown');
+ await waitForPromises();
+
+ expect(findEmptyMessage().exists()).toBe(true);
+ expect(findSearchBox().exists()).toBe(false);
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('with a failing request', () => {
+ beforeEach(() => {
+ mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+ });
+
+ it('should render an error message', async () => {
+ createComponent();
+ findDropdown().vm.$emit('shown');
+ await waitForPromises();
+
+ const error = findAlert();
+ expect(error.exists()).toBe(true);
+ expect(error.text()).toBe(i18n.artifactsFetchErrorMessage);
+ });
+ });
+ });
+
+ describe('tracking', () => {
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks artifacts dropdown click', () => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
+ createComponent();
+
+ findDropdown().vm.$emit('shown');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_artifacts_dropdown', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js b/spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js
new file mode 100644
index 00000000000..d2eab64b317
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js
@@ -0,0 +1,77 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import PipelinesManualActions from '~/ci/pipelines_page/components/pipelines_manual_actions.vue';
+import PipelineMultiActions from '~/ci/pipelines_page/components/pipeline_multi_actions.vue';
+import PipelineOperations from '~/ci/pipelines_page/components/pipeline_operations.vue';
+import eventHub from '~/ci/event_hub';
+
+describe('Pipeline operations', () => {
+ let wrapper;
+
+ const defaultProps = {
+ pipeline: {
+ id: 329,
+ iid: 234,
+ details: {
+ has_manual_actions: true,
+ has_scheduled_actions: false,
+ },
+ flags: {
+ retryable: true,
+ cancelable: true,
+ },
+ cancel_path: '/root/ci-project/-/pipelines/329/cancel',
+ retry_path: '/root/ci-project/-/pipelines/329/retry',
+ },
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = shallowMountExtended(PipelineOperations, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findManualActions = () => wrapper.findComponent(PipelinesManualActions);
+ const findMultiActions = () => wrapper.findComponent(PipelineMultiActions);
+ const findRetryBtn = () => wrapper.findByTestId('pipelines-retry-button');
+ const findCancelBtn = () => wrapper.findByTestId('pipelines-cancel-button');
+
+ it('should display pipeline manual actions', () => {
+ createComponent();
+
+ expect(findManualActions().exists()).toBe(true);
+ });
+
+ it('should display pipeline multi actions', () => {
+ createComponent();
+
+ expect(findMultiActions().exists()).toBe(true);
+ });
+
+ describe('events', () => {
+ beforeEach(() => {
+ createComponent();
+
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+ });
+
+ it('should emit retryPipeline event', () => {
+ findRetryBtn().vm.$emit('click');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith(
+ 'retryPipeline',
+ defaultProps.pipeline.retry_path,
+ );
+ });
+
+ it('should emit openConfirmationModal event', () => {
+ findCancelBtn().vm.$emit('click');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('openConfirmationModal', {
+ pipeline: defaultProps.pipeline,
+ endpoint: defaultProps.pipeline.cancel_path,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js b/spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js
new file mode 100644
index 00000000000..4d78a923542
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js
@@ -0,0 +1,27 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlSprintf } from '@gitlab/ui';
+import { mockPipelineHeader } from 'jest/ci/pipeline_details/mock_data';
+import PipelineStopModal from '~/ci/pipelines_page/components/pipeline_stop_modal.vue';
+
+describe('PipelineStopModal', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = shallowMount(PipelineStopModal, {
+ propsData: {
+ pipeline: mockPipelineHeader,
+ },
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should render "stop pipeline" warning', () => {
+ expect(wrapper.text()).toMatch(`You’re about to stop pipeline #${mockPipelineHeader.id}.`);
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipeline_triggerer_spec.js b/spec/frontend/ci/pipelines_page/components/pipeline_triggerer_spec.js
new file mode 100644
index 00000000000..cb04171f031
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipeline_triggerer_spec.js
@@ -0,0 +1,76 @@
+import { GlAvatar, GlAvatarLink } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import pipelineTriggerer from '~/ci/pipelines_page/components/pipeline_triggerer.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+
+describe('Pipelines Triggerer', () => {
+ let wrapper;
+
+ const mockData = {
+ pipeline: {
+ user: {
+ name: 'foo',
+ avatar_url: '/avatar',
+ path: '/path',
+ },
+ },
+ };
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(pipelineTriggerer, {
+ propsData: {
+ ...props,
+ },
+ directives: {
+ GlTooltip: createMockDirective('gl-tooltip'),
+ },
+ });
+ };
+
+ const findAvatarLink = () => wrapper.findComponent(GlAvatarLink);
+ const findAvatar = () => wrapper.findComponent(GlAvatar);
+ const findTriggerer = () => wrapper.findByText('API');
+
+ describe('when user was a triggerer', () => {
+ beforeEach(() => {
+ createComponent(mockData);
+ });
+
+ it('should render pipeline triggerer table cell', () => {
+ expect(wrapper.find('[data-testid="pipeline-triggerer"]').exists()).toBe(true);
+ });
+
+ it('should render only user avatar', () => {
+ expect(findAvatarLink().exists()).toBe(true);
+ expect(findTriggerer().exists()).toBe(false);
+ });
+
+ it('should set correct props on avatar link component', () => {
+ expect(findAvatarLink().attributes()).toMatchObject({
+ title: mockData.pipeline.user.name,
+ href: mockData.pipeline.user.path,
+ });
+ });
+
+ it('should add tooltip to avatar link', () => {
+ const tooltip = getBinding(findAvatarLink().element, 'gl-tooltip');
+
+ expect(tooltip).toBeDefined();
+ });
+
+ it('should set correct props on avatar component', () => {
+ expect(findAvatar().attributes().src).toBe(mockData.pipeline.user.avatar_url);
+ });
+ });
+
+ describe('when API was a triggerer', () => {
+ beforeEach(() => {
+ createComponent({ pipeline: {} });
+ });
+
+ it('should render label only', () => {
+ expect(findAvatarLink().exists()).toBe(false);
+ expect(findTriggerer().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipeline_url_spec.js b/spec/frontend/ci/pipelines_page/components/pipeline_url_spec.js
new file mode 100644
index 00000000000..0ee22dda826
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipeline_url_spec.js
@@ -0,0 +1,188 @@
+import { merge } from 'lodash';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import PipelineUrlComponent from '~/ci/pipelines_page/components/pipeline_url.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+import {
+ mockPipeline,
+ mockPipelineBranch,
+ mockPipelineTag,
+} from 'jest/ci/pipeline_details/mock_data';
+
+const projectPath = 'test/test';
+
+describe('Pipeline Url Component', () => {
+ let wrapper;
+ let trackingSpy;
+
+ const findTableCell = () => wrapper.findByTestId('pipeline-url-table-cell');
+ const findPipelineUrlLink = () => wrapper.findByTestId('pipeline-url-link');
+ const findRefName = () => wrapper.findByTestId('merge-request-ref');
+ const findCommitShortSha = () => wrapper.findByTestId('commit-short-sha');
+ const findCommitIcon = () => wrapper.findByTestId('commit-icon');
+ const findCommitIconType = () => wrapper.findByTestId('commit-icon-type');
+ const findCommitRefName = () => wrapper.findByTestId('commit-ref-name');
+
+ const findCommitTitleContainer = () => wrapper.findByTestId('commit-title-container');
+ const findPipelineNameContainer = () => wrapper.findByTestId('pipeline-name-container');
+ const findCommitTitle = (commitWrapper) => commitWrapper.find('[data-testid="commit-title"]');
+
+ const defaultProps = { ...mockPipeline(projectPath), refClass: 'gl-text-black' };
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(PipelineUrlComponent, {
+ propsData: { ...defaultProps, ...props },
+ provide: {
+ targetProjectFullPath: projectPath,
+ },
+ });
+ };
+
+ it('should render pipeline url table cell', () => {
+ createComponent();
+
+ expect(findTableCell().exists()).toBe(true);
+ });
+
+ it('should render a link the provided path and id', () => {
+ createComponent();
+
+ expect(findPipelineUrlLink().attributes('href')).toBe('foo');
+
+ expect(findPipelineUrlLink().text()).toBe('#1');
+ });
+
+ it('should render the pipeline name instead of commit title', () => {
+ createComponent(merge(mockPipeline(projectPath), { pipeline: { name: 'Build pipeline' } }));
+
+ expect(findCommitTitleContainer().exists()).toBe(false);
+ expect(findPipelineNameContainer().exists()).toBe(true);
+ expect(findRefName().exists()).toBe(true);
+ expect(findCommitShortSha().exists()).toBe(true);
+ });
+
+ it('should render the commit title when pipeline has no name', () => {
+ createComponent();
+
+ const commitWrapper = findCommitTitleContainer();
+
+ expect(findCommitTitle(commitWrapper).exists()).toBe(true);
+ expect(findRefName().exists()).toBe(true);
+ expect(findCommitShortSha().exists()).toBe(true);
+ expect(findPipelineNameContainer().exists()).toBe(false);
+ });
+
+ it('should pass the refClass prop to merge request link', () => {
+ createComponent();
+
+ expect(findRefName().classes()).toContain(defaultProps.refClass);
+ });
+
+ it('should pass the refClass prop to the commit ref name link', () => {
+ createComponent(mockPipelineBranch());
+
+ expect(findCommitRefName().classes()).toContain(defaultProps.refClass);
+ });
+
+ describe('commit user avatar', () => {
+ it('renders when commit author exists', () => {
+ const pipelineBranch = mockPipelineBranch();
+ const { avatar_url: imgSrc, name, path } = pipelineBranch.pipeline.commit.author;
+ createComponent(pipelineBranch);
+
+ const component = wrapper.findComponent(UserAvatarLink);
+ expect(component.exists()).toBe(true);
+ expect(component.props()).toMatchObject({
+ imgSize: 16,
+ imgSrc,
+ imgAlt: name,
+ linkHref: path,
+ tooltipText: name,
+ });
+ });
+
+ it('does not render when commit author does not exist', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(UserAvatarLink).exists()).toBe(false);
+ });
+ });
+
+ it('should render commit icon tooltip', () => {
+ createComponent();
+
+ expect(findCommitIcon().attributes('title')).toBe('Commit');
+ });
+
+ it.each`
+ pipeline | expectedTitle
+ ${mockPipelineTag()} | ${'Tag'}
+ ${mockPipelineBranch()} | ${'Branch'}
+ ${mockPipeline()} | ${'Merge Request'}
+ `('should render tooltip $expectedTitle for commit icon type', ({ pipeline, expectedTitle }) => {
+ createComponent(pipeline);
+
+ expect(findCommitIconType().attributes('title')).toBe(expectedTitle);
+ });
+
+ describe('tracking', () => {
+ beforeEach(() => {
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks pipeline id click', () => {
+ createComponent();
+
+ findPipelineUrlLink().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_pipeline_id', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+
+ it('tracks merge request ref click', () => {
+ createComponent();
+
+ findRefName().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_mr_ref', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+
+ it('tracks commit ref name click', () => {
+ createComponent(mockPipelineBranch());
+
+ findCommitRefName().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_name', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+
+ it('tracks commit title click', () => {
+ createComponent(merge(mockPipelineBranch(), { pipeline: { name: null } }));
+
+ findCommitTitle(findCommitTitleContainer()).vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_title', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+
+ it('tracks commit short sha click', () => {
+ createComponent(mockPipelineBranch());
+
+ findCommitShortSha().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_sha', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipelines_artifacts_spec.js b/spec/frontend/ci/pipelines_page/components/pipelines_artifacts_spec.js
new file mode 100644
index 00000000000..557403b3de9
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipelines_artifacts_spec.js
@@ -0,0 +1,64 @@
+import {
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlDisclosureDropdownGroup,
+ GlSprintf,
+} from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import PipelineArtifacts from '~/ci/pipelines_page/components/pipelines_artifacts.vue';
+
+describe('Pipelines Artifacts dropdown', () => {
+ let wrapper;
+
+ const artifacts = [
+ {
+ name: 'job my-artifact',
+ path: '/download/path',
+ },
+ {
+ name: 'job-2 my-artifact-2',
+ path: '/download/path-two',
+ },
+ ];
+ const pipelineId = 108;
+
+ const createComponent = ({ mockArtifacts = artifacts } = {}) => {
+ wrapper = shallowMount(PipelineArtifacts, {
+ propsData: {
+ pipelineId,
+ artifacts: mockArtifacts,
+ },
+ stubs: {
+ GlSprintf,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlDisclosureDropdownGroup,
+ },
+ });
+ };
+
+ const findGlDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const findFirstGlDropdownItem = () => wrapper.findComponent(GlDisclosureDropdownItem);
+
+ it('should render a dropdown with all the provided artifacts', () => {
+ createComponent();
+
+ const [{ items }] = findGlDropdown().props('items');
+ expect(items).toHaveLength(artifacts.length);
+ });
+
+ it('should render a link with the provided path', () => {
+ createComponent();
+
+ expect(findFirstGlDropdownItem().props('item').href).toBe(artifacts[0].path);
+ expect(findFirstGlDropdownItem().text()).toBe(artifacts[0].name);
+ });
+
+ describe('with no artifacts', () => {
+ it('should not render the dropdown', () => {
+ createComponent({ mockArtifacts: [] });
+
+ expect(findGlDropdown().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipelines_filtered_search_spec.js b/spec/frontend/ci/pipelines_page/components/pipelines_filtered_search_spec.js
new file mode 100644
index 00000000000..4cd85b86e31
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipelines_filtered_search_spec.js
@@ -0,0 +1,199 @@
+import { GlFilteredSearch } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import { nextTick } from 'vue';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import Api from '~/api';
+import axios from '~/lib/utils/axios_utils';
+import PipelinesFilteredSearch from '~/ci/pipelines_page/components/pipelines_filtered_search.vue';
+import {
+ FILTERED_SEARCH_TERM,
+ OPERATORS_IS,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+import { users, mockSearch, branches, tags } from 'jest/ci/pipeline_details/mock_data';
+
+describe('Pipelines filtered search', () => {
+ let wrapper;
+ let mock;
+
+ const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
+ const getSearchToken = (type) =>
+ findFilteredSearch()
+ .props('availableTokens')
+ .find((token) => token.type === type);
+ const findBranchToken = () => getSearchToken('ref');
+ const findTagToken = () => getSearchToken('tag');
+ const findUserToken = () => getSearchToken('username');
+ const findStatusToken = () => getSearchToken('status');
+ const findSourceToken = () => getSearchToken('source');
+
+ const createComponent = (params = {}) => {
+ wrapper = mount(PipelinesFilteredSearch, {
+ propsData: {
+ projectId: '21',
+ defaultBranchName: 'main',
+ params,
+ },
+ attachTo: document.body,
+ });
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
+ jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
+ jest.spyOn(Api, 'tags').mockResolvedValue({ data: tags });
+
+ createComponent();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('displays UI elements', () => {
+ expect(findFilteredSearch().exists()).toBe(true);
+ });
+
+ it('displays search tokens', () => {
+ expect(findUserToken()).toMatchObject({
+ type: 'username',
+ icon: 'user',
+ title: 'Trigger author',
+ unique: true,
+ projectId: '21',
+ operators: OPERATORS_IS,
+ });
+
+ expect(findBranchToken()).toMatchObject({
+ type: 'ref',
+ icon: 'branch',
+ title: 'Branch name',
+ unique: true,
+ projectId: '21',
+ defaultBranchName: 'main',
+ operators: OPERATORS_IS,
+ });
+
+ expect(findSourceToken()).toMatchObject({
+ type: 'source',
+ icon: 'trigger-source',
+ title: 'Source',
+ unique: true,
+ operators: OPERATORS_IS,
+ });
+
+ expect(findStatusToken()).toMatchObject({
+ type: 'status',
+ icon: 'status',
+ title: 'Status',
+ unique: true,
+ operators: OPERATORS_IS,
+ });
+
+ expect(findTagToken()).toMatchObject({
+ type: 'tag',
+ icon: 'tag',
+ title: 'Tag name',
+ unique: true,
+ operators: OPERATORS_IS,
+ });
+ });
+
+ it('emits filterPipelines on submit with correct filter', () => {
+ findFilteredSearch().vm.$emit('submit', mockSearch);
+
+ expect(wrapper.emitted('filterPipelines')).toHaveLength(1);
+ expect(wrapper.emitted('filterPipelines')[0]).toEqual([mockSearch]);
+ });
+
+ it('disables tag name token when branch name token is active', async () => {
+ findFilteredSearch().vm.$emit('input', [
+ { type: 'ref', value: { data: 'branch-1', operator: '=' } },
+ { type: FILTERED_SEARCH_TERM, value: { data: '' } },
+ ]);
+
+ await nextTick();
+ expect(findBranchToken().disabled).toBe(false);
+ expect(findTagToken().disabled).toBe(true);
+ });
+
+ it('disables branch name token when tag name token is active', async () => {
+ findFilteredSearch().vm.$emit('input', [
+ { type: 'tag', value: { data: 'tag-1', operator: '=' } },
+ { type: FILTERED_SEARCH_TERM, value: { data: '' } },
+ ]);
+
+ await nextTick();
+ expect(findBranchToken().disabled).toBe(true);
+ expect(findTagToken().disabled).toBe(false);
+ });
+
+ it('resets tokens disabled state on clear', async () => {
+ findFilteredSearch().vm.$emit('clearInput');
+
+ await nextTick();
+ expect(findBranchToken().disabled).toBe(false);
+ expect(findTagToken().disabled).toBe(false);
+ });
+
+ it('resets tokens disabled state when clearing tokens by backspace', async () => {
+ findFilteredSearch().vm.$emit('input', [{ type: FILTERED_SEARCH_TERM, value: { data: '' } }]);
+
+ await nextTick();
+ expect(findBranchToken().disabled).toBe(false);
+ expect(findTagToken().disabled).toBe(false);
+ });
+
+ describe('Url query params', () => {
+ const params = {
+ username: 'deja.green',
+ ref: 'main',
+ };
+
+ beforeEach(() => {
+ createComponent(params);
+ });
+
+ it('sets default value if url query params', () => {
+ const expectedValueProp = [
+ {
+ type: 'username',
+ value: {
+ data: params.username,
+ operator: '=',
+ },
+ },
+ {
+ type: 'ref',
+ value: {
+ data: params.ref,
+ operator: '=',
+ },
+ },
+ { type: FILTERED_SEARCH_TERM, value: { data: '' } },
+ ];
+
+ expect(findFilteredSearch().props('value')).toMatchObject(expectedValueProp);
+ expect(findFilteredSearch().props('value')).toHaveLength(expectedValueProp.length);
+ });
+ });
+
+ describe('tracking', () => {
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks filtered search click', () => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
+ findFilteredSearch().vm.$emit('submit', mockSearch);
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_filtered_search', {
+ label: TRACKING_CATEGORIES.search,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/pipelines_manual_actions_spec.js b/spec/frontend/ci/pipelines_page/components/pipelines_manual_actions_spec.js
new file mode 100644
index 00000000000..a24e136f1ff
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/pipelines_manual_actions_spec.js
@@ -0,0 +1,216 @@
+import { GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import MockAdapter from 'axios-mock-adapter';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import mockPipelineActionsQueryResponse from 'test_fixtures/graphql/pipelines/get_pipeline_actions.query.graphql.json';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/alert';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
+import PipelinesManualActions from '~/ci/pipelines_page/components/pipelines_manual_actions.vue';
+import getPipelineActionsQuery from '~/ci/pipelines_page/graphql/queries/get_pipeline_actions.query.graphql';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
+import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
+
+Vue.use(VueApollo);
+
+jest.mock('~/alert');
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
+
+describe('Pipeline manual actions', () => {
+ let wrapper;
+ let mock;
+
+ const queryHandler = jest.fn().mockResolvedValue(mockPipelineActionsQueryResponse);
+ const {
+ data: {
+ project: {
+ pipeline: {
+ jobs: { nodes },
+ },
+ },
+ },
+ } = mockPipelineActionsQueryResponse;
+
+ const mockPath = nodes[2].playPath;
+
+ const createComponent = (limit = 50) => {
+ wrapper = shallowMountExtended(PipelinesManualActions, {
+ provide: {
+ fullPath: 'root/ci-project',
+ manualActionsLimit: limit,
+ },
+ propsData: {
+ iid: 100,
+ },
+ stubs: {
+ GlDropdown,
+ },
+ apolloProvider: createMockApollo([[getPipelineActionsQuery, queryHandler]]),
+ });
+ };
+
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findAllCountdowns = () => wrapper.findAllComponents(GlCountdown);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findLimitMessage = () => wrapper.findByTestId('limit-reached-msg');
+
+ it('skips calling query on mount', () => {
+ createComponent();
+
+ expect(queryHandler).not.toHaveBeenCalled();
+ });
+
+ describe('loading', () => {
+ beforeEach(() => {
+ createComponent();
+
+ findDropdown().vm.$emit('shown');
+ });
+
+ it('display loading state while actions are being fetched', () => {
+ expect(findAllDropdownItems().at(0).text()).toBe('Loading...');
+ expect(findLoadingIcon().exists()).toBe(true);
+ expect(findAllDropdownItems()).toHaveLength(1);
+ });
+ });
+
+ describe('loaded', () => {
+ beforeEach(async () => {
+ mock = new MockAdapter(axios);
+
+ createComponent();
+
+ findDropdown().vm.$emit('shown');
+
+ await waitForPromises();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ confirmAction.mockReset();
+ });
+
+ it('displays dropdown with the provided actions', () => {
+ expect(findAllDropdownItems()).toHaveLength(3);
+ });
+
+ it("displays a disabled action when it's not playable", () => {
+ expect(findAllDropdownItems().at(0).attributes('disabled')).toBeDefined();
+ });
+
+ describe('on action click', () => {
+ it('makes a request and toggles the loading state', async () => {
+ mock.onPost(mockPath).reply(HTTP_STATUS_OK);
+
+ findAllDropdownItems().at(1).vm.$emit('click');
+
+ await nextTick();
+
+ expect(findDropdown().props('loading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findDropdown().props('loading')).toBe(false);
+ });
+
+ it('makes a failed request and toggles the loading state', async () => {
+ mock.onPost(mockPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+
+ findAllDropdownItems().at(1).vm.$emit('click');
+
+ await nextTick();
+
+ expect(findDropdown().props('loading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findDropdown().props('loading')).toBe(false);
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('tracking', () => {
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks manual actions click', () => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
+ findDropdown().vm.$emit('shown');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_manual_actions', {
+ label: TRACKING_CATEGORIES.table,
+ });
+ });
+ });
+
+ describe('scheduled jobs', () => {
+ beforeEach(() => {
+ jest
+ .spyOn(Date, 'now')
+ .mockImplementation(() => new Date('2063-04-04T00:42:00Z').getTime());
+ });
+
+ it('makes post request after confirming', async () => {
+ mock.onPost(mockPath).reply(HTTP_STATUS_OK);
+
+ confirmAction.mockResolvedValueOnce(true);
+
+ findAllDropdownItems().at(2).vm.$emit('click');
+
+ expect(confirmAction).toHaveBeenCalled();
+
+ await waitForPromises();
+
+ expect(mock.history.post).toHaveLength(1);
+ });
+
+ it('does not make post request if confirmation is cancelled', async () => {
+ mock.onPost(mockPath).reply(HTTP_STATUS_OK);
+
+ confirmAction.mockResolvedValueOnce(false);
+
+ findAllDropdownItems().at(2).vm.$emit('click');
+
+ expect(confirmAction).toHaveBeenCalled();
+
+ await waitForPromises();
+
+ expect(mock.history.post).toHaveLength(0);
+ });
+
+ it('displays the remaining time in the dropdown', () => {
+ expect(findAllCountdowns().at(0).props('endDateString')).toBe(nodes[2].scheduledAt);
+ });
+ });
+ });
+
+ describe('limit message', () => {
+ it('limit message does not show', async () => {
+ createComponent();
+
+ findDropdown().vm.$emit('shown');
+
+ await waitForPromises();
+
+ expect(findLimitMessage().exists()).toBe(false);
+ });
+
+ it('limit message does show', async () => {
+ createComponent(3);
+
+ findDropdown().vm.$emit('shown');
+
+ await waitForPromises();
+
+ expect(findLimitMessage().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/components/time_ago_spec.js b/spec/frontend/ci/pipelines_page/components/time_ago_spec.js
new file mode 100644
index 00000000000..f7203f8d1b4
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/components/time_ago_spec.js
@@ -0,0 +1,85 @@
+import { GlIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import TimeAgo from '~/ci/pipelines_page/components/time_ago.vue';
+
+describe('Timeago component', () => {
+ let wrapper;
+
+ const defaultProps = { duration: 0, finished_at: '' };
+
+ const createComponent = (props = defaultProps, extraProps) => {
+ wrapper = extendedWrapper(
+ shallowMount(TimeAgo, {
+ propsData: {
+ pipeline: {
+ details: {
+ ...props,
+ },
+ },
+ ...extraProps,
+ },
+ data() {
+ return {
+ iconTimerSvg: `<svg></svg>`,
+ };
+ },
+ }),
+ );
+ };
+
+ const duration = () => wrapper.find('.duration');
+ const finishedAt = () => wrapper.find('.finished-at');
+ const findCalendarIcon = () => wrapper.findByTestId('calendar-icon');
+
+ describe('with duration', () => {
+ beforeEach(() => {
+ createComponent({ duration: 10, finished_at: '' });
+ });
+
+ it('should render duration and timer svg', () => {
+ const icon = duration().findComponent(GlIcon);
+
+ expect(duration().exists()).toBe(true);
+ expect(icon.props('name')).toBe('timer');
+ });
+ });
+
+ describe('without duration', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should not render duration and timer svg', () => {
+ expect(duration().exists()).toBe(false);
+ });
+ });
+
+ describe('with finishedTime', () => {
+ it('should render time', () => {
+ createComponent({ duration: 0, finished_at: '2017-04-26T12:40:23.277Z' });
+
+ const time = finishedAt().find('time');
+
+ expect(finishedAt().exists()).toBe(true);
+ expect(time.exists()).toBe(true);
+ });
+
+ it('should display calendar icon', () => {
+ createComponent({ duration: 0, finished_at: '2017-04-26T12:40:23.277Z' });
+
+ expect(findCalendarIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('without finishedTime', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should not render time and calendar icon', () => {
+ expect(finishedAt().exists()).toBe(false);
+ expect(findCalendarIcon().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/pipelines_spec.js b/spec/frontend/ci/pipelines_page/pipelines_spec.js
new file mode 100644
index 00000000000..5d1f431e57c
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/pipelines_spec.js
@@ -0,0 +1,851 @@
+import '~/commons';
+import {
+ GlButton,
+ GlEmptyState,
+ GlFilteredSearch,
+ GlLoadingIcon,
+ GlPagination,
+ GlCollapsibleListbox,
+} from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
+import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import { chunk } from 'lodash';
+import { nextTick } from 'vue';
+import mockPipelinesResponse from 'test_fixtures/pipelines/pipelines.json';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import { TEST_HOST } from 'helpers/test_constants';
+import { mockTracking } from 'helpers/tracking_helper';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import Api from '~/api';
+import { createAlert, VARIANT_WARNING } from '~/alert';
+import setSortPreferenceMutation from '~/issues/list/queries/set_sort_preference.mutation.graphql';
+import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import NavigationControls from '~/ci/pipelines_page/components/nav_controls.vue';
+import PipelinesComponent from '~/ci/pipelines_page/pipelines.vue';
+import PipelinesCiTemplates from '~/ci/pipelines_page/components/empty_state/pipelines_ci_templates.vue';
+import PipelinesTableComponent from '~/ci/common/pipelines_table.vue';
+import { RAW_TEXT_WARNING, TRACKING_CATEGORIES } from '~/ci/constants';
+import Store from '~/ci/pipeline_details/stores/pipelines_store';
+import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
+import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
+import {
+ setIdTypePreferenceMutationResponse,
+ setIdTypePreferenceMutationResponseWithErrors,
+} from 'jest/issues/list/mock_data';
+
+import { stageReply } from 'jest/ci/pipeline_mini_graph/mock_data';
+import { users, mockSearch, branches } from '../pipeline_details/mock_data';
+
+jest.mock('@sentry/browser');
+jest.mock('~/alert');
+
+const mockProjectPath = 'twitter/flight';
+const mockProjectId = '21';
+const mockDefaultBranchName = 'main';
+const mockPipelinesEndpoint = `/${mockProjectPath}/pipelines.json`;
+const mockPipelinesIds = mockPipelinesResponse.pipelines.map(({ id }) => id);
+const mockPipelineWithStages = mockPipelinesResponse.pipelines.find(
+ (p) => p.details.stages && p.details.stages.length,
+);
+
+describe('Pipelines', () => {
+ let wrapper;
+ let mockApollo;
+ let mock;
+ let trackingSpy;
+
+ const paths = {
+ emptyStateSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
+ errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
+ noPipelinesSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
+ ciLintPath: '/ci/lint',
+ resetCachePath: `${mockProjectPath}/settings/ci_cd/reset_cache`,
+ newPipelinePath: `${mockProjectPath}/pipelines/new`,
+
+ ciRunnerSettingsPath: `${mockProjectPath}/-/settings/ci_cd#js-runners-settings`,
+ };
+
+ const noPermissions = {
+ emptyStateSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
+ errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
+ noPipelinesSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
+ };
+
+ const defaultProps = {
+ hasGitlabCi: true,
+ canCreatePipeline: true,
+ ...paths,
+ };
+
+ const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findNavigationTabs = () => wrapper.findComponent(NavigationTabs);
+ const findNavigationControls = () => wrapper.findComponent(NavigationControls);
+ const findPipelinesTable = () => wrapper.findComponent(PipelinesTableComponent);
+ const findTablePagination = () => wrapper.findComponent(TablePagination);
+ const findPipelineKeyCollapsibleBoxVue = () => wrapper.findComponent(GlCollapsibleListbox);
+
+ const findTab = (tab) => wrapper.findByTestId(`pipelines-tab-${tab}`);
+ const findPipelineKeyCollapsibleBox = () => wrapper.findByTestId('pipeline-key-collapsible-box');
+ const findRunPipelineButton = () => wrapper.findByTestId('run-pipeline-button');
+ const findCiLintButton = () => wrapper.findByTestId('ci-lint-button');
+ const findCleanCacheButton = () => wrapper.findByTestId('clear-cache-button');
+ const findStagesDropdownToggle = () =>
+ wrapper.find('[data-testid="mini-pipeline-graph-dropdown"] .dropdown-toggle');
+ const findPipelineUrlLinks = () => wrapper.findAll('[data-testid="pipeline-url-link"]');
+
+ const createComponent = (props = defaultProps) => {
+ const { mutationMock, ...restProps } = props;
+ mockApollo = createMockApollo([[setSortPreferenceMutation, mutationMock]]);
+
+ wrapper = extendedWrapper(
+ mount(PipelinesComponent, {
+ provide: {
+ pipelineEditorPath: '',
+ suggestedCiTemplates: [],
+ ciRunnerSettingsPath: paths.ciRunnerSettingsPath,
+ anyRunnersAvailable: true,
+ },
+ propsData: {
+ store: new Store(),
+ projectId: mockProjectId,
+ defaultBranchName: mockDefaultBranchName,
+ endpoint: mockPipelinesEndpoint,
+ params: {},
+ ...restProps,
+ },
+ apolloProvider: mockApollo,
+ }),
+ );
+ };
+
+ beforeEach(() => {
+ setWindowLocation(TEST_HOST);
+ });
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ jest.spyOn(window.history, 'pushState');
+ jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
+ jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
+ });
+
+ afterEach(() => {
+ mock.reset();
+ mockApollo = null;
+ window.history.pushState.mockReset();
+ });
+
+ describe('when pipelines are not yet loaded', () => {
+ beforeEach(async () => {
+ createComponent();
+ await nextTick();
+ });
+
+ it('shows loading state when the app is loading', () => {
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ });
+
+ it('does not display tabs when the first request has not yet been made', () => {
+ expect(findNavigationTabs().exists()).toBe(false);
+ });
+
+ it('does not display buttons', () => {
+ expect(findNavigationControls().exists()).toBe(false);
+ });
+ });
+
+ describe('when there are pipelines in the project', () => {
+ beforeEach(() => {
+ mock
+ .onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
+ .reply(HTTP_STATUS_OK, mockPipelinesResponse);
+ });
+
+ describe('when user has no permissions', () => {
+ beforeEach(async () => {
+ createComponent({ hasGitlabCi: true, canCreatePipeline: false, ...noPermissions });
+ await waitForPromises();
+ });
+
+ it('renders "All" tab with count different from "0"', () => {
+ expect(findTab('all').text()).toMatchInterpolatedText('All 3');
+ });
+
+ it('does not render buttons', () => {
+ expect(findNavigationControls().exists()).toBe(false);
+
+ expect(findRunPipelineButton().exists()).toBe(false);
+ expect(findCiLintButton().exists()).toBe(false);
+ expect(findCleanCacheButton().exists()).toBe(false);
+ });
+
+ it('renders pipelines in a table', () => {
+ expect(findPipelinesTable().exists()).toBe(true);
+
+ expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
+ expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
+ expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
+ });
+ });
+
+ describe('when user has permissions', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('should set up navigation tabs', () => {
+ expect(findNavigationTabs().props('tabs')).toEqual([
+ { name: 'All', scope: 'all', count: '3', isActive: true },
+ { name: 'Finished', scope: 'finished', count: undefined, isActive: false },
+ { name: 'Branches', scope: 'branches', isActive: false },
+ { name: 'Tags', scope: 'tags', isActive: false },
+ ]);
+ });
+
+ it('renders "All" tab with count different from "0"', () => {
+ expect(findTab('all').text()).toMatchInterpolatedText('All 3');
+ });
+
+ it('should render other navigation tabs', () => {
+ expect(findTab('finished').text()).toBe('Finished');
+ expect(findTab('branches').text()).toBe('Branches');
+ expect(findTab('tags').text()).toBe('Tags');
+ });
+
+ it('shows navigation controls', () => {
+ expect(findNavigationControls().exists()).toBe(true);
+ });
+
+ it('renders Run pipeline link', () => {
+ expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
+ });
+
+ it('renders CI lint link', () => {
+ expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
+ });
+
+ it('renders Clear runner cache button', () => {
+ expect(findCleanCacheButton().text()).toBe('Clear runner caches');
+ });
+
+ it('renders pipelines in a table', () => {
+ expect(findPipelinesTable().exists()).toBe(true);
+
+ expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
+ expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
+ expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
+ });
+
+ describe('when user goes to a tab', () => {
+ const goToTab = (tab) => {
+ findNavigationTabs().vm.$emit('onChangeTab', tab);
+ };
+
+ describe('when the scope in the tab has pipelines', () => {
+ const mockFinishedPipeline = mockPipelinesResponse.pipelines[0];
+
+ beforeEach(async () => {
+ mock
+ .onGet(mockPipelinesEndpoint, { params: { scope: 'finished', page: '1' } })
+ .reply(HTTP_STATUS_OK, {
+ pipelines: [mockFinishedPipeline],
+ count: mockPipelinesResponse.count,
+ });
+
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
+ goToTab('finished');
+
+ await waitForPromises();
+ });
+
+ it('should filter pipelines', () => {
+ expect(findPipelinesTable().exists()).toBe(true);
+
+ expect(findPipelineUrlLinks()).toHaveLength(1);
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFinishedPipeline.id}`);
+ });
+
+ it('should update browser bar', () => {
+ expect(window.history.pushState).toHaveBeenCalledTimes(1);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?scope=finished&page=1`,
+ );
+ });
+
+ it.each(['all', 'finished', 'branches', 'tags'])('tracks %p tab click', async (scope) => {
+ goToTab(scope);
+
+ await waitForPromises();
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_filter_tabs', {
+ label: TRACKING_CATEGORIES.tabs,
+ property: scope,
+ });
+ });
+ });
+
+ describe('when the scope in the tab is empty', () => {
+ beforeEach(async () => {
+ mock
+ .onGet(mockPipelinesEndpoint, { params: { scope: 'branches', page: '1' } })
+ .reply(HTTP_STATUS_OK, {
+ pipelines: [],
+ count: mockPipelinesResponse.count,
+ });
+
+ goToTab('branches');
+
+ await waitForPromises();
+ });
+
+ it('should filter pipelines', () => {
+ expect(findEmptyState().text()).toBe('There are currently no pipelines.');
+ });
+
+ it('should update browser bar', () => {
+ expect(window.history.pushState).toHaveBeenCalledTimes(1);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?scope=branches&page=1`,
+ );
+ });
+ });
+ });
+
+ describe('when user triggers a filtered search', () => {
+ const mockFilteredPipeline = mockPipelinesResponse.pipelines[1];
+
+ let expectedParams;
+
+ beforeEach(async () => {
+ expectedParams = {
+ page: '1',
+ scope: 'all',
+ username: 'root',
+ ref: 'main',
+ status: 'pending',
+ };
+
+ mock
+ .onGet(mockPipelinesEndpoint, {
+ params: expectedParams,
+ })
+ .replyOnce(HTTP_STATUS_OK, {
+ pipelines: [mockFilteredPipeline],
+ count: mockPipelinesResponse.count,
+ });
+
+ findFilteredSearch().vm.$emit('submit', mockSearch);
+
+ await waitForPromises();
+ });
+
+ it('requests data with query params on filter submit', () => {
+ expect(mock.history.get[1].params).toEqual(expectedParams);
+ });
+
+ it('renders filtered pipelines', () => {
+ expect(findPipelineUrlLinks()).toHaveLength(1);
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFilteredPipeline.id}`);
+ });
+
+ it('should update browser bar', () => {
+ expect(window.history.pushState).toHaveBeenCalledTimes(1);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?page=1&scope=all&username=root&ref=main&status=pending`,
+ );
+ });
+ });
+
+ describe('when user changes Show Pipeline ID to Show Pipeline IID', () => {
+ const mockFilteredPipeline = mockPipelinesResponse.pipelines[0];
+
+ beforeEach(() => {
+ gon.current_user_id = 1;
+ });
+
+ it('should change the text to Show Pipeline IID', async () => {
+ expect(findPipelineKeyCollapsibleBox().exists()).toBe(true);
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFilteredPipeline.id}`);
+ findPipelineKeyCollapsibleBoxVue().vm.$emit('select', 'iid');
+
+ await waitForPromises();
+
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFilteredPipeline.iid}`);
+ });
+
+ it('calls mutation to save idType preference', () => {
+ const mutationMock = jest.fn().mockResolvedValue(setIdTypePreferenceMutationResponse);
+ createComponent({ ...defaultProps, mutationMock });
+
+ findPipelineKeyCollapsibleBoxVue().vm.$emit('select', 'iid');
+
+ expect(mutationMock).toHaveBeenCalledWith({ input: { visibilityPipelineIdType: 'IID' } });
+ });
+
+ it('captures error when mutation response has errors', async () => {
+ const mutationMock = jest
+ .fn()
+ .mockResolvedValue(setIdTypePreferenceMutationResponseWithErrors);
+ createComponent({ ...defaultProps, mutationMock });
+
+ findPipelineKeyCollapsibleBoxVue().vm.$emit('select', 'iid');
+ await waitForPromises();
+
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error('oh no!'));
+ });
+ });
+
+ describe('when user triggers a filtered search with raw text', () => {
+ beforeEach(async () => {
+ findFilteredSearch().vm.$emit('submit', ['rawText']);
+
+ await waitForPromises();
+ });
+
+ it('requests data with query params on filter submit', () => {
+ expect(mock.history.get[1].params).toEqual({ page: '1', scope: 'all' });
+ });
+
+ it('displays a warning message if raw text search is used', () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
+ message: RAW_TEXT_WARNING,
+ variant: VARIANT_WARNING,
+ });
+ });
+
+ it('should update browser bar', () => {
+ expect(window.history.pushState).toHaveBeenCalledTimes(1);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?page=1&scope=all`,
+ );
+ });
+ });
+ });
+ });
+
+ describe('when there are multiple pages of pipelines', () => {
+ const mockPageSize = 2;
+ const mockPageHeaders = ({ page = 1 } = {}) => {
+ return {
+ 'X-PER-PAGE': `${mockPageSize}`,
+ 'X-PREV-PAGE': `${page - 1}`,
+ 'X-PAGE': `${page}`,
+ 'X-NEXT-PAGE': `${page + 1}`,
+ };
+ };
+ const [firstPage, secondPage] = chunk(mockPipelinesResponse.pipelines, mockPageSize);
+
+ const goToPage = (page) => {
+ findTablePagination().findComponent(GlPagination).vm.$emit('input', page);
+ };
+
+ beforeEach(async () => {
+ mock.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } }).reply(
+ HTTP_STATUS_OK,
+ {
+ pipelines: firstPage,
+ count: mockPipelinesResponse.count,
+ },
+ mockPageHeaders({ page: 1 }),
+ );
+ mock.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '2' } }).reply(
+ HTTP_STATUS_OK,
+ {
+ pipelines: secondPage,
+ count: mockPipelinesResponse.count,
+ },
+ mockPageHeaders({ page: 2 }),
+ );
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('shows the first page of pipelines', () => {
+ expect(findPipelineUrlLinks()).toHaveLength(firstPage.length);
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${firstPage[0].id}`);
+ expect(findPipelineUrlLinks().at(1).text()).toBe(`#${firstPage[1].id}`);
+ });
+
+ it('should not update browser bar', () => {
+ expect(window.history.pushState).not.toHaveBeenCalled();
+ });
+
+ describe('when user goes to next page', () => {
+ beforeEach(async () => {
+ goToPage(2);
+ await waitForPromises();
+ });
+
+ it('should update page and keep scope the same scope', () => {
+ expect(findPipelineUrlLinks()).toHaveLength(secondPage.length);
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${secondPage[0].id}`);
+ });
+
+ it('should update browser bar', () => {
+ expect(window.history.pushState).toHaveBeenCalledTimes(1);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?page=2&scope=all`,
+ );
+ });
+
+ it('should reset page to 1 when filtering pipelines', () => {
+ expect(window.history.pushState).toHaveBeenCalledTimes(1);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?page=2&scope=all`,
+ );
+
+ findFilteredSearch().vm.$emit('submit', [
+ { type: 'status', value: { data: 'success', operator: '=' } },
+ ]);
+
+ expect(window.history.pushState).toHaveBeenCalledTimes(2);
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.anything(),
+ `${window.location.pathname}?page=1&scope=all&status=success`,
+ );
+ });
+ });
+ });
+
+ describe('when pipelines can be polled', () => {
+ beforeEach(() => {
+ const emptyResponse = {
+ pipelines: [],
+ count: { all: '0' },
+ };
+
+ // Mock no pipelines in the first attempt
+ mock
+ .onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
+ .replyOnce(HTTP_STATUS_OK, emptyResponse, {
+ 'POLL-INTERVAL': 100,
+ });
+ // Mock pipelines in the next attempt
+ mock
+ .onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
+ .reply(HTTP_STATUS_OK, mockPipelinesResponse, {
+ 'POLL-INTERVAL': 100,
+ });
+ });
+
+ describe('data is loaded for the first time', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('shows tabs', () => {
+ expect(findNavigationTabs().exists()).toBe(true);
+ });
+
+ it('should update page and keep scope the same scope', () => {
+ expect(findPipelineUrlLinks()).toHaveLength(0);
+ });
+
+ describe('data is loaded for a second time', () => {
+ beforeEach(async () => {
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+ });
+
+ it('shows tabs', () => {
+ expect(findNavigationTabs().exists()).toBe(true);
+ });
+
+ it('is loading after a time', () => {
+ expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
+ expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
+ expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
+ expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
+ });
+ });
+ });
+ });
+
+ describe('when no pipelines exist', () => {
+ beforeEach(() => {
+ mock
+ .onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
+ .reply(HTTP_STATUS_OK, {
+ pipelines: [],
+ count: { all: '0' },
+ });
+ });
+
+ describe('when CI is enabled and user has permissions', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('renders tab with count of "0"', () => {
+ expect(findNavigationTabs().exists()).toBe(true);
+ expect(findTab('all').text()).toMatchInterpolatedText('All 0');
+ });
+
+ it('renders Run pipeline link', () => {
+ expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
+ });
+
+ it('renders CI lint link', () => {
+ expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
+ });
+
+ it('renders Clear runner cache button', () => {
+ expect(findCleanCacheButton().text()).toBe('Clear runner caches');
+ });
+
+ it('renders empty state', () => {
+ expect(findEmptyState().text()).toBe('There are currently no pipelines.');
+ });
+
+ it('renders filtered search', () => {
+ expect(findFilteredSearch().exists()).toBe(true);
+ });
+
+ it('renders the pipeline key collapsible box', () => {
+ expect(findPipelineKeyCollapsibleBox().exists()).toBe(true);
+ });
+
+ it('renders tab empty state finished scope', async () => {
+ mock
+ .onGet(mockPipelinesEndpoint, { params: { scope: 'finished', page: '1' } })
+ .reply(HTTP_STATUS_OK, {
+ pipelines: [],
+ count: { all: '0' },
+ });
+
+ findNavigationTabs().vm.$emit('onChangeTab', 'finished');
+
+ await waitForPromises();
+
+ expect(findEmptyState().text()).toBe('There are currently no finished pipelines.');
+ });
+ });
+
+ describe('when CI is not enabled and user has permissions', () => {
+ beforeEach(async () => {
+ createComponent({ hasGitlabCi: false, canCreatePipeline: true, ...paths });
+ await waitForPromises();
+ });
+
+ it('renders the CI/CD templates', () => {
+ expect(wrapper.findComponent(PipelinesCiTemplates).exists()).toBe(true);
+ });
+
+ it('does not render filtered search', () => {
+ expect(findFilteredSearch().exists()).toBe(false);
+ });
+
+ it('does not render the pipeline key dropdown', () => {
+ expect(findPipelineKeyCollapsibleBox().exists()).toBe(false);
+ });
+
+ it('does not render tabs nor buttons', () => {
+ expect(findNavigationTabs().exists()).toBe(false);
+ expect(findTab('all').exists()).toBe(false);
+ expect(findRunPipelineButton().exists()).toBe(false);
+ expect(findCiLintButton().exists()).toBe(false);
+ expect(findCleanCacheButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when CI is not enabled and user has no permissions', () => {
+ beforeEach(async () => {
+ createComponent({ hasGitlabCi: false, canCreatePipeline: false, ...noPermissions });
+ await waitForPromises();
+ });
+
+ it('renders empty state without button to set CI', () => {
+ expect(findEmptyState().text()).toBe(
+ 'This project is not currently set up to run pipelines.',
+ );
+
+ expect(findEmptyState().findComponent(GlButton).exists()).toBe(false);
+ });
+
+ it('does not render tabs or buttons', () => {
+ expect(findTab('all').exists()).toBe(false);
+ expect(findRunPipelineButton().exists()).toBe(false);
+ expect(findCiLintButton().exists()).toBe(false);
+ expect(findCleanCacheButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when CI is enabled and user has no permissions', () => {
+ beforeEach(() => {
+ createComponent({ hasGitlabCi: true, canCreatePipeline: false, ...noPermissions });
+
+ return waitForPromises();
+ });
+
+ it('renders tab with count of "0"', () => {
+ expect(findTab('all').text()).toMatchInterpolatedText('All 0');
+ });
+
+ it('does not render buttons', () => {
+ expect(findRunPipelineButton().exists()).toBe(false);
+ expect(findCiLintButton().exists()).toBe(false);
+ expect(findCleanCacheButton().exists()).toBe(false);
+ });
+
+ it('renders empty state', () => {
+ expect(findEmptyState().text()).toBe('There are currently no pipelines.');
+ });
+ });
+ });
+
+ describe('when a pipeline with stages exists', () => {
+ describe('updates results when a staged is clicked', () => {
+ let stopMock;
+ let restartMock;
+ let cancelMock;
+
+ beforeEach(() => {
+ mock.onGet(mockPipelinesEndpoint, { scope: 'all', page: '1' }).reply(
+ HTTP_STATUS_OK,
+ {
+ pipelines: [mockPipelineWithStages],
+ count: { all: '1' },
+ },
+ {
+ 'POLL-INTERVAL': 100,
+ },
+ );
+
+ mock
+ .onGet(mockPipelineWithStages.details.stages[0].dropdown_path)
+ .reply(HTTP_STATUS_OK, stageReply);
+
+ createComponent();
+
+ stopMock = jest.spyOn(window, 'clearTimeout');
+ restartMock = jest.spyOn(axios, 'get');
+ });
+
+ describe('when a request is being made', () => {
+ beforeEach(async () => {
+ mock.onGet(mockPipelinesEndpoint).reply(HTTP_STATUS_OK, mockPipelinesResponse);
+
+ await waitForPromises();
+ });
+
+ it('stops polling, cancels the request, & restarts polling', async () => {
+ // Mock init a polling cycle
+ wrapper.vm.poll.options.notificationCallback(true);
+
+ await findStagesDropdownToggle().trigger('click');
+ jest.runOnlyPendingTimers();
+
+ // cancelMock is getting overwritten in pipelines_service.js#L29
+ // so we have to spy on it again here
+ cancelMock = jest.spyOn(axios.CancelToken, 'source');
+
+ await waitForPromises();
+
+ expect(cancelMock).toHaveBeenCalled();
+ expect(stopMock).toHaveBeenCalled();
+ expect(restartMock).toHaveBeenCalledWith(
+ `${mockPipelinesResponse.pipelines[0].path}/stage.json?stage=build`,
+ );
+ });
+
+ it('stops polling & restarts polling', async () => {
+ await findStagesDropdownToggle().trigger('click');
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+
+ expect(cancelMock).not.toHaveBeenCalled();
+ expect(stopMock).toHaveBeenCalled();
+ expect(restartMock).toHaveBeenCalledWith(
+ `${mockPipelinesResponse.pipelines[0].path}/stage.json?stage=build`,
+ );
+ });
+ });
+ });
+ });
+
+ describe('when pipelines cannot be loaded', () => {
+ beforeEach(() => {
+ mock.onGet(mockPipelinesEndpoint).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, {});
+ });
+
+ describe('when user has no permissions', () => {
+ beforeEach(async () => {
+ createComponent({ hasGitlabCi: false, canCreatePipeline: true, ...noPermissions });
+
+ await waitForPromises();
+ });
+
+ it('renders tabs', () => {
+ expect(findNavigationTabs().exists()).toBe(true);
+ expect(findTab('all').text()).toBe('All');
+ });
+
+ it('does not render buttons', () => {
+ expect(findRunPipelineButton().exists()).toBe(false);
+ expect(findCiLintButton().exists()).toBe(false);
+ expect(findCleanCacheButton().exists()).toBe(false);
+ });
+
+ it('shows error state', () => {
+ expect(findEmptyState().props('title')).toBe('There was an error fetching the pipelines.');
+ expect(findEmptyState().props('description')).toBe(
+ 'Try again in a few moments or contact your support team.',
+ );
+ });
+ });
+
+ describe('when user has permissions', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('renders tabs', () => {
+ expect(findTab('all').text()).toBe('All');
+ });
+
+ it('renders buttons', () => {
+ expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
+
+ expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
+ expect(findCleanCacheButton().text()).toBe('Clear runner caches');
+ });
+
+ it('shows error state', () => {
+ expect(findEmptyState().props('title')).toBe('There was an error fetching the pipelines.');
+ expect(findEmptyState().props('description')).toBe(
+ 'Try again in a few moments or contact your support team.',
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/tokens/pipeline_branch_name_token_spec.js b/spec/frontend/ci/pipelines_page/tokens/pipeline_branch_name_token_spec.js
new file mode 100644
index 00000000000..ea615d85c4b
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/tokens/pipeline_branch_name_token_spec.js
@@ -0,0 +1,142 @@
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
+import { nextTick } from 'vue';
+import { shallowMount } from '@vue/test-utils';
+import waitForPromises from 'helpers/wait_for_promises';
+import Api from '~/api';
+import PipelineBranchNameToken from '~/ci/pipelines_page/tokens/pipeline_branch_name_token.vue';
+import { branches, mockBranchesAfterMap } from 'jest/ci/pipeline_details/mock_data';
+
+describe('Pipeline Branch Name Token', () => {
+ let wrapper;
+
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
+ const findAllFilteredSearchSuggestions = () =>
+ wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const getBranchSuggestions = () =>
+ findAllFilteredSearchSuggestions().wrappers.map((w) => w.text());
+
+ const stubs = {
+ GlFilteredSearchToken: {
+ template: `<div><slot name="suggestions"></slot></div>`,
+ },
+ };
+
+ const defaultProps = {
+ config: {
+ type: 'ref',
+ icon: 'branch',
+ title: 'Branch name',
+ unique: true,
+ projectId: '21',
+ defaultBranchName: null,
+ disabled: false,
+ },
+ value: {
+ data: '',
+ },
+ cursorPosition: 'start',
+ };
+
+ const optionsWithDefaultBranchName = (options) => {
+ return {
+ propsData: {
+ ...defaultProps,
+ config: {
+ ...defaultProps.config,
+ defaultBranchName: 'main',
+ },
+ },
+ ...options,
+ };
+ };
+
+ const createComponent = (options, data) => {
+ wrapper = shallowMount(PipelineBranchNameToken, {
+ propsData: {
+ ...defaultProps,
+ },
+ data() {
+ return {
+ ...data,
+ };
+ },
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
+
+ createComponent();
+ });
+
+ it('passes config correctly', () => {
+ expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
+ });
+
+ it('fetches and sets project branches', () => {
+ expect(Api.branches).toHaveBeenCalled();
+
+ expect(wrapper.vm.branches).toEqual(mockBranchesAfterMap);
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ describe('displays loading icon correctly', () => {
+ it('shows loading icon', () => {
+ createComponent({ stubs }, { loading: true });
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('does not show loading icon', () => {
+ createComponent({ stubs }, { loading: false });
+
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+ });
+
+ describe('shows branches correctly', () => {
+ it('renders all branches', () => {
+ createComponent({ stubs }, { branches, loading: false });
+
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(branches.length);
+ });
+
+ it('renders only the branch searched for', () => {
+ const mockBranches = ['main'];
+ createComponent({ stubs }, { branches: mockBranches, loading: false });
+
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(mockBranches.length);
+ });
+
+ it('shows the default branch first if no branch was searched for', async () => {
+ const mockBranches = [{ name: 'branch-1' }];
+ jest.spyOn(Api, 'branches').mockResolvedValue({ data: mockBranches });
+
+ createComponent(optionsWithDefaultBranchName({ stubs }), { loading: false });
+ await nextTick();
+ expect(getBranchSuggestions()).toEqual(['main', 'branch-1']);
+ });
+
+ it('does not show the default branch if a search term was provided', async () => {
+ const mockBranches = [{ name: 'branch-1' }];
+ jest.spyOn(Api, 'branches').mockResolvedValue({ data: mockBranches });
+
+ createComponent(optionsWithDefaultBranchName(), { loading: false });
+
+ findFilteredSearchToken().vm.$emit('input', { data: 'branch-1' });
+ await waitForPromises();
+ expect(getBranchSuggestions()).toEqual(['branch-1']);
+ });
+
+ it('shows the default branch only once if it appears in the results', async () => {
+ const mockBranches = [{ name: 'main' }];
+ jest.spyOn(Api, 'branches').mockResolvedValue({ data: mockBranches });
+
+ createComponent(optionsWithDefaultBranchName({ stubs }), { loading: false });
+ await nextTick();
+ expect(getBranchSuggestions()).toEqual(['main']);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/tokens/pipeline_source_token_spec.js b/spec/frontend/ci/pipelines_page/tokens/pipeline_source_token_spec.js
new file mode 100644
index 00000000000..0ea2b641b33
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/tokens/pipeline_source_token_spec.js
@@ -0,0 +1,53 @@
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { PIPELINE_SOURCES } from 'ee_else_ce/ci/pipelines_page/tokens/constants';
+import { stubComponent } from 'helpers/stub_component';
+import PipelineSourceToken from '~/ci/pipelines_page/tokens/pipeline_source_token.vue';
+
+describe('Pipeline Source Token', () => {
+ let wrapper;
+
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
+ const findAllFilteredSearchSuggestions = () =>
+ wrapper.findAllComponents(GlFilteredSearchSuggestion);
+
+ const defaultProps = {
+ config: {
+ type: 'source',
+ icon: 'trigger-source',
+ title: 'Source',
+ unique: true,
+ },
+ value: {
+ data: '',
+ },
+ cursorPosition: 'start',
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMount(PipelineSourceToken, {
+ propsData: {
+ ...defaultProps,
+ },
+ stubs: {
+ GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
+ template: `<div><slot name="suggestions"></slot></div>`,
+ }),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('passes config correctly', () => {
+ expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
+ });
+
+ describe('shows sources correctly', () => {
+ it('renders all pipeline sources available', () => {
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(PIPELINE_SOURCES.length);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/tokens/pipeline_status_token_spec.js b/spec/frontend/ci/pipelines_page/tokens/pipeline_status_token_spec.js
new file mode 100644
index 00000000000..b8f98666438
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/tokens/pipeline_status_token_spec.js
@@ -0,0 +1,58 @@
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { stubComponent } from 'helpers/stub_component';
+import PipelineStatusToken from '~/ci/pipelines_page/tokens/pipeline_status_token.vue';
+import {
+ TOKEN_TITLE_STATUS,
+ TOKEN_TYPE_STATUS,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+
+describe('Pipeline Status Token', () => {
+ let wrapper;
+
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
+ const findAllFilteredSearchSuggestions = () =>
+ wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const findAllGlIcons = () => wrapper.findAllComponents(GlIcon);
+
+ const defaultProps = {
+ config: {
+ type: TOKEN_TYPE_STATUS,
+ icon: 'status',
+ title: TOKEN_TITLE_STATUS,
+ unique: true,
+ },
+ value: {
+ data: '',
+ },
+ cursorPosition: 'start',
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMount(PipelineStatusToken, {
+ propsData: {
+ ...defaultProps,
+ },
+ stubs: {
+ GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
+ template: `<div><slot name="suggestions"></slot></div>`,
+ }),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('passes config correctly', () => {
+ expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
+ });
+
+ describe('shows statuses correctly', () => {
+ it('renders all pipeline statuses available', () => {
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(wrapper.vm.statuses.length);
+ expect(findAllGlIcons()).toHaveLength(wrapper.vm.statuses.length);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/tokens/pipeline_tag_name_token_spec.js b/spec/frontend/ci/pipelines_page/tokens/pipeline_tag_name_token_spec.js
new file mode 100644
index 00000000000..d23d9f07df3
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/tokens/pipeline_tag_name_token_spec.js
@@ -0,0 +1,95 @@
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Api from '~/api';
+import PipelineTagNameToken from '~/ci/pipelines_page/tokens/pipeline_tag_name_token.vue';
+import { tags, mockTagsAfterMap } from 'jest/ci/pipeline_details/mock_data';
+
+describe('Pipeline Branch Name Token', () => {
+ let wrapper;
+
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
+ const findAllFilteredSearchSuggestions = () =>
+ wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+
+ const stubs = {
+ GlFilteredSearchToken: {
+ template: `<div><slot name="suggestions"></slot></div>`,
+ },
+ };
+
+ const defaultProps = {
+ config: {
+ type: 'tag',
+ icon: 'tag',
+ title: 'Tag name',
+ unique: true,
+ projectId: '21',
+ disabled: false,
+ },
+ value: {
+ data: '',
+ },
+ cursorPosition: 'start',
+ };
+
+ const createComponent = (options, data) => {
+ wrapper = shallowMount(PipelineTagNameToken, {
+ propsData: {
+ ...defaultProps,
+ },
+ data() {
+ return {
+ ...data,
+ };
+ },
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ jest.spyOn(Api, 'tags').mockResolvedValue({ data: tags });
+
+ createComponent();
+ });
+
+ it('passes config correctly', () => {
+ expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
+ });
+
+ it('fetches and sets project tags', () => {
+ expect(Api.tags).toHaveBeenCalled();
+
+ expect(wrapper.vm.tags).toEqual(mockTagsAfterMap);
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ describe('displays loading icon correctly', () => {
+ it('shows loading icon', () => {
+ createComponent({ stubs }, { loading: true });
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('does not show loading icon', () => {
+ createComponent({ stubs }, { loading: false });
+
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+ });
+
+ describe('shows tags correctly', () => {
+ it('renders all tags', () => {
+ createComponent({ stubs }, { tags, loading: false });
+
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(tags.length);
+ });
+
+ it('renders only the tag searched for', () => {
+ const mockTags = ['main-tag'];
+ createComponent({ stubs }, { tags: mockTags, loading: false });
+
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(mockTags.length);
+ });
+ });
+});
diff --git a/spec/frontend/ci/pipelines_page/tokens/pipeline_trigger_author_token_spec.js b/spec/frontend/ci/pipelines_page/tokens/pipeline_trigger_author_token_spec.js
new file mode 100644
index 00000000000..eccb90b0c94
--- /dev/null
+++ b/spec/frontend/ci/pipelines_page/tokens/pipeline_trigger_author_token_spec.js
@@ -0,0 +1,99 @@
+import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { stubComponent } from 'helpers/stub_component';
+import Api from '~/api';
+import PipelineTriggerAuthorToken from '~/ci/pipelines_page/tokens/pipeline_trigger_author_token.vue';
+import { users } from 'jest/ci/pipeline_details/mock_data';
+
+describe('Pipeline Trigger Author Token', () => {
+ let wrapper;
+
+ const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
+ const findAllFilteredSearchSuggestions = () =>
+ wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+
+ const defaultProps = {
+ config: {
+ type: 'username',
+ icon: 'user',
+ title: 'Trigger author',
+ dataType: 'username',
+ unique: true,
+ triggerAuthors: users,
+ },
+ value: {
+ data: '',
+ },
+ cursorPosition: 'start',
+ };
+
+ const createComponent = (data) => {
+ wrapper = shallowMount(PipelineTriggerAuthorToken, {
+ propsData: {
+ ...defaultProps,
+ },
+ data() {
+ return {
+ ...data,
+ };
+ },
+ stubs: {
+ GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
+ template: `<div><slot name="suggestions"></slot></div>`,
+ }),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
+
+ createComponent();
+ });
+
+ it('passes config correctly', () => {
+ expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
+ });
+
+ it('fetches and sets project users', () => {
+ expect(Api.projectUsers).toHaveBeenCalled();
+
+ expect(wrapper.vm.users).toEqual(users);
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ describe('displays loading icon correctly', () => {
+ it('shows loading icon', () => {
+ createComponent({ loading: true });
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('does not show loading icon', () => {
+ createComponent({ loading: false });
+
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+ });
+
+ describe('shows trigger authors correctly', () => {
+ beforeEach(() => {});
+
+ it('renders all trigger authors', () => {
+ createComponent({ users, loading: false });
+
+ // should have length of all users plus the static 'Any' option
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(users.length + 1);
+ });
+
+ it('renders only the trigger author searched for', () => {
+ createComponent({
+ users: [{ name: 'Arnold', username: 'admin', state: 'active', avatar_url: 'avatar-link' }],
+ loading: false,
+ });
+
+ expect(findAllFilteredSearchSuggestions()).toHaveLength(2);
+ });
+ });
+});
diff --git a/spec/frontend/ci/reports/components/__snapshots__/issue_status_icon_spec.js.snap b/spec/frontend/ci/reports/components/__snapshots__/issue_status_icon_spec.js.snap
index b5a4cb42463..2de634a6209 100644
--- a/spec/frontend/ci/reports/components/__snapshots__/issue_status_icon_spec.js.snap
+++ b/spec/frontend/ci/reports/components/__snapshots__/issue_status_icon_spec.js.snap
@@ -2,10 +2,9 @@
exports[`IssueStatusIcon renders "failed" state correctly 1`] = `
<div
- class="report-block-list-icon failed"
+ class="failed report-block-list-icon"
>
<gl-icon-stub
- data-qa-selector="status_failed_icon"
name="status_failed_borderless"
size="24"
/>
@@ -14,10 +13,9 @@ exports[`IssueStatusIcon renders "failed" state correctly 1`] = `
exports[`IssueStatusIcon renders "neutral" state correctly 1`] = `
<div
- class="report-block-list-icon neutral"
+ class="neutral report-block-list-icon"
>
<gl-icon-stub
- data-qa-selector="status_neutral_icon"
name="dash"
size="24"
/>
@@ -29,7 +27,6 @@ exports[`IssueStatusIcon renders "success" state correctly 1`] = `
class="report-block-list-icon success"
>
<gl-icon-stub
- data-qa-selector="status_success_icon"
name="status_success_borderless"
size="24"
/>
diff --git a/spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js b/spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js
index ad20d7682ed..bc77b7b89dd 100644
--- a/spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js
+++ b/spec/frontend/ci/runner/components/cells/runner_summary_cell_spec.js
@@ -13,7 +13,6 @@ import {
INSTANCE_TYPE,
I18N_INSTANCE_TYPE,
PROJECT_TYPE,
- I18N_NO_DESCRIPTION,
I18N_CREATED_AT_LABEL,
I18N_CREATED_AT_BY_LABEL,
} from '~/ci/runner/constants';
@@ -102,15 +101,6 @@ describe('RunnerTypeCell', () => {
it('Displays the runner description', () => {
expect(wrapper.text()).toContain(mockRunner.description);
- expect(wrapper.findByText(I18N_NO_DESCRIPTION).exists()).toBe(false);
- });
-
- it('Displays "No description" for missing runner description', () => {
- createComponent({
- runner: { description: null },
- });
-
- expect(wrapper.findByText(I18N_NO_DESCRIPTION).classes()).toContain('gl-text-secondary');
});
it('Displays last contact', () => {
diff --git a/spec/frontend/ci/runner/components/runner_create_form_spec.js b/spec/frontend/ci/runner/components/runner_create_form_spec.js
index c452e32b0e4..3c5f8c4d6a9 100644
--- a/spec/frontend/ci/runner/components/runner_create_form_spec.js
+++ b/spec/frontend/ci/runner/components/runner_create_form_spec.js
@@ -61,6 +61,7 @@ describe('RunnerCreateForm', () => {
createComponent();
expect(findRunnerFormFields().props('value')).toEqual(defaultRunnerModel);
+ expect(findRunnerFormFields().props('runnerType')).toEqual(INSTANCE_TYPE);
});
it('shows a submit button', () => {
diff --git a/spec/frontend/ci/runner/components/runner_form_fields_spec.js b/spec/frontend/ci/runner/components/runner_form_fields_spec.js
index 93be4d9d35e..7e39a6b72f9 100644
--- a/spec/frontend/ci/runner/components/runner_form_fields_spec.js
+++ b/spec/frontend/ci/runner/components/runner_form_fields_spec.js
@@ -132,8 +132,8 @@ describe('RunnerFormFields', () => {
it('when runner is of project type, locked checkbox can be checked', async () => {
createComponent({
+ runnerType: PROJECT_TYPE,
value: {
- runnerType: PROJECT_TYPE,
locked: false,
},
});
@@ -144,7 +144,6 @@ describe('RunnerFormFields', () => {
expect(wrapper.emitted('input').at(-1)).toEqual([
{
- runnerType: PROJECT_TYPE,
locked: true,
},
]);
diff --git a/spec/frontend/ci/runner/components/runner_managers_table_spec.js b/spec/frontend/ci/runner/components/runner_managers_table_spec.js
index cde6ee6eea0..d5782e21a2f 100644
--- a/spec/frontend/ci/runner/components/runner_managers_table_spec.js
+++ b/spec/frontend/ci/runner/components/runner_managers_table_spec.js
@@ -60,8 +60,8 @@ describe('RunnerJobs', () => {
it('shows status', () => {
createComponent();
- expect(findCellText({ field: 'status', i: 0 })).toBe(s__('Runners|Online'));
- expect(findCellText({ field: 'status', i: 1 })).toBe(s__('Runners|Online'));
+ expect(findCellText({ field: 'status', i: 0 })).toContain(s__('Runners|Online'));
+ expect(findCellText({ field: 'status', i: 0 })).toContain(s__('Runners|Idle'));
});
it('shows version', () => {
diff --git a/spec/frontend/ci/runner/components/runner_update_form_spec.js b/spec/frontend/ci/runner/components/runner_update_form_spec.js
index 5851078a8d3..2ba1c31fe52 100644
--- a/spec/frontend/ci/runner/components/runner_update_form_spec.js
+++ b/spec/frontend/ci/runner/components/runner_update_form_spec.js
@@ -15,6 +15,7 @@ import RunnerUpdateForm from '~/ci/runner/components/runner_update_form.vue';
import runnerUpdateMutation from '~/ci/runner/graphql/edit/runner_update.mutation.graphql';
import { captureException } from '~/ci/runner/sentry_utils';
import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_alert_to_local_storage';
+import { INSTANCE_TYPE } from '~/ci/runner/constants';
import { runnerFormData } from '../mock_data';
jest.mock('~/ci/runner/local_storage_alert/save_alert_to_local_storage');
@@ -119,6 +120,7 @@ describe('RunnerUpdateForm', () => {
it('shows runner fields', () => {
expect(findRunnerFormFields().props('value')).toEqual(runnerToModel(mockRunner));
+ expect(findRunnerFormFields().props('runnerType')).toEqual(INSTANCE_TYPE);
});
it('form has not been submitted', () => {
diff --git a/spec/frontend/ci_secure_files/components/metadata/__snapshots__/modal_spec.js.snap b/spec/frontend/ci_secure_files/components/metadata/__snapshots__/modal_spec.js.snap
index 79194c20ff5..d0c1987829f 100644
--- a/spec/frontend/ci_secure_files/components/metadata/__snapshots__/modal_spec.js.snap
+++ b/spec/frontend/ci_secure_files/components/metadata/__snapshots__/modal_spec.js.snap
@@ -13,22 +13,16 @@ exports[`Secure File Metadata Modal when a .cer file is supplied matches cer the
<div
data-testid="slot-default"
>
-
<table
aria-busy=""
aria-colcount="2"
- class="table b-table gl-table"
+ class="b-table gl-table table"
role="table"
>
- <!---->
- <!---->
<thead
- class=""
role="rowgroup"
>
- <!---->
<tr
- class=""
role="row"
>
<th
@@ -56,14 +50,11 @@ exports[`Secure File Metadata Modal when a .cer file is supplied matches cer the
<tbody
role="rowgroup"
>
- <!---->
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -72,21 +63,16 @@ exports[`Secure File Metadata Modal when a .cer file is supplied matches cer the
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- Apple Distribution: Team Name (ABC123XYZ)
-
+ Apple Distribution: Team Name (ABC123XYZ)
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -95,21 +81,16 @@ exports[`Secure File Metadata Modal when a .cer file is supplied matches cer the
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- 33669367788748363528491290218354043267
-
+ 33669367788748363528491290218354043267
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -118,21 +99,16 @@ exports[`Secure File Metadata Modal when a .cer file is supplied matches cer the
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- Team Name (ABC123XYZ)
-
+ Team Name (ABC123XYZ)
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -141,21 +117,16 @@ exports[`Secure File Metadata Modal when a .cer file is supplied matches cer the
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- Apple Worldwide Developer Relations Certification Authority - G3
-
+ Apple Worldwide Developer Relations Certification Authority - G3
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -164,18 +135,12 @@ exports[`Secure File Metadata Modal when a .cer file is supplied matches cer the
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- April 26, 2023 at 7:20:39 PM GMT
-
+ April 26, 2023 at 7:20:39 PM GMT
</td>
</tr>
- <!---->
- <!---->
</tbody>
- <!---->
</table>
</div>
</div>
@@ -194,22 +159,16 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
<div
data-testid="slot-default"
>
-
<table
aria-busy=""
aria-colcount="2"
- class="table b-table gl-table"
+ class="b-table gl-table table"
role="table"
>
- <!---->
- <!---->
<thead
- class=""
role="rowgroup"
>
- <!---->
<tr
- class=""
role="row"
>
<th
@@ -237,14 +196,11 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
<tbody
role="rowgroup"
>
- <!---->
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -253,21 +209,16 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- 6b9fcce1-b9a9-4b37-b2ce-ec4da2044abf
-
+ 6b9fcce1-b9a9-4b37-b2ce-ec4da2044abf
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -276,21 +227,16 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- iOS
-
+ iOS
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -299,21 +245,16 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- Team Name (ABC123XYZ)
-
+ Team Name (ABC123XYZ)
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -322,21 +263,16 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- iOS Demo - match Development com.gitlab.ios-demo
-
+ iOS Demo - match Development com.gitlab.ios-demo
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -345,21 +281,16 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- 33669367788748363528491290218354043267
-
+ 33669367788748363528491290218354043267
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
<strong>
@@ -368,18 +299,12 @@ exports[`Secure File Metadata Modal when a .mobileprovision file is supplied mat
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
-
- August 1, 2023 at 11:15:13 PM GMT
-
+ August 1, 2023 at 11:15:13 PM GMT
</td>
</tr>
- <!---->
- <!---->
</tbody>
- <!---->
</table>
</div>
</div>
diff --git a/spec/frontend/clusters/components/__snapshots__/new_cluster_spec.js.snap b/spec/frontend/clusters/components/__snapshots__/new_cluster_spec.js.snap
index 21ffda8578a..f90acb5cb22 100644
--- a/spec/frontend/clusters/components/__snapshots__/new_cluster_spec.js.snap
+++ b/spec/frontend/clusters/components/__snapshots__/new_cluster_spec.js.snap
@@ -1,9 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NewCluster renders the cluster component correctly 1`] = `
-"<div class=\\"gl-pt-4\\">
- <h4>Enter your Kubernetes cluster certificate details</h4>
- <p>Enter details about your cluster. <b-link-stub href=\\"/help/user/project/clusters/add_existing_cluster\\" class=\\"gl-link\\">How do I use a certificate to connect to my cluster?</b-link-stub>
+<div
+ class="gl-pt-4"
+>
+ <h4>
+ Enter your Kubernetes cluster certificate details
+ </h4>
+ <p>
+ Enter details about your cluster.
+ <b-link-stub
+ class="gl-link"
+ href="/help/user/project/clusters/add_existing_cluster"
+ >
+ How do I use a certificate to connect to my cluster?
+ </b-link-stub>
</p>
-</div>"
+</div>
`;
diff --git a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
index 67b0ecdf7eb..b5fc3247165 100644
--- a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
+++ b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
@@ -5,42 +5,27 @@ exports[`Remove cluster confirmation modal renders buttons with modal included 1
class="gl-display-flex"
>
<button
- class="btn gl-mr-3 btn-danger btn-md gl-button"
+ class="btn btn-danger btn-md gl-button gl-mr-3"
data-testid="remove-integration-and-resources-button"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- Remove integration and resources
-
+ Remove integration and resources
</span>
</button>
-
<button
- class="btn btn-danger btn-md gl-button btn-danger-secondary"
+ class="btn btn-danger btn-danger-secondary btn-md gl-button"
data-testid="remove-integration-button"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- Remove integration
-
+ Remove integration
</span>
</button>
-
- <!---->
</div>
`;
@@ -49,63 +34,44 @@ exports[`Remove cluster confirmation modal two buttons open modal with "cleanup"
class="gl-display-flex"
>
<button
- class="btn gl-mr-3 btn-danger btn-md gl-button"
+ class="btn btn-danger btn-md gl-button gl-mr-3"
data-testid="remove-integration-and-resources-button"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- Remove integration and resources
-
+ Remove integration and resources
</span>
</button>
-
<button
- class="btn btn-danger btn-md gl-button btn-danger-secondary"
+ class="btn btn-danger btn-danger-secondary btn-md gl-button"
data-testid="remove-integration-button"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- Remove integration
-
+ Remove integration
</span>
</button>
-
<div
kind="danger"
>
<p>
You are about to remove your cluster integration and all GitLab-created resources associated with this cluster.
</p>
-
<div>
-
This will permanently delete the following resources:
-
<ul>
<li>
Any project namespaces
</li>
-
<li>
<code>
clusterroles
</code>
</li>
-
<li>
<code>
clusterrolebindings
@@ -113,15 +79,13 @@ exports[`Remove cluster confirmation modal two buttons open modal with "cleanup"
</li>
</ul>
</div>
-
<strong>
- To remove your integration and resources, type
+ To remove your integration and resources, type
<code>
my-test-cluster
</code>
- to confirm:
+ to confirm:
</strong>
-
<form
action="clusterPath"
class="gl-mb-5"
@@ -132,27 +96,23 @@ exports[`Remove cluster confirmation modal two buttons open modal with "cleanup"
type="hidden"
value="delete"
/>
-
<input
name="authenticity_token"
type="hidden"
/>
-
<input
name="cleanup"
type="hidden"
value="true"
/>
-
<input
autocomplete="off"
- class="gl-form-input form-control"
- id="__BVID__14"
+ class="form-control gl-form-input"
+ id="reference-0"
name="confirm_cluster_name_input"
type="text"
/>
</form>
-
<span>
If you do not wish to delete all associated GitLab resources, you can simply remove the integration.
</span>
@@ -165,58 +125,40 @@ exports[`Remove cluster confirmation modal two buttons open modal without "clean
class="gl-display-flex"
>
<button
- class="btn gl-mr-3 btn-danger btn-md gl-button"
+ class="btn btn-danger btn-md gl-button gl-mr-3"
data-testid="remove-integration-and-resources-button"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- Remove integration and resources
-
+ Remove integration and resources
</span>
</button>
-
<button
- class="btn btn-danger btn-md gl-button btn-danger-secondary"
+ class="btn btn-danger btn-danger-secondary btn-md gl-button"
data-testid="remove-integration-button"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- Remove integration
-
+ Remove integration
</span>
</button>
-
<div
kind="danger"
>
<p>
You are about to remove your cluster integration.
</p>
-
- <!---->
-
<strong>
- To remove your integration, type
+ To remove your integration, type
<code>
my-test-cluster
</code>
- to confirm:
+ to confirm:
</strong>
-
<form
action="clusterPath"
class="gl-mb-5"
@@ -227,28 +169,23 @@ exports[`Remove cluster confirmation modal two buttons open modal without "clean
type="hidden"
value="delete"
/>
-
<input
name="authenticity_token"
type="hidden"
/>
-
<input
name="cleanup"
type="hidden"
value="true"
/>
-
<input
autocomplete="off"
- class="gl-form-input form-control"
- id="__BVID__21"
+ class="form-control gl-form-input"
+ id="reference-0"
name="confirm_cluster_name_input"
type="text"
/>
</form>
-
- <!---->
</div>
</div>
`;
diff --git a/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap b/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
index 36d2c2cabc5..1c2bdd2f8bc 100644
--- a/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
+++ b/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
@@ -2,14 +2,13 @@
exports[`Code navigation popover component renders popover 1`] = `
<div
- class="popover code-navigation-popover popover-font-size-normal gl-popover bs-popover-bottom show"
+ class="bs-popover-bottom code-navigation-popover gl-popover popover popover-font-size-normal show"
style="left: 0px; top: 0px;"
>
<div
class="arrow"
style="left: 0px;"
/>
-
<gl-tabs-stub
contentclass="gl-py-0"
navclass="gl-hidden"
@@ -21,13 +20,11 @@ exports[`Code navigation popover component renders popover 1`] = `
titlelinkclass=""
>
<div
- class="overflow-auto code-navigation-popover-container"
+ class="code-navigation-popover-container overflow-auto"
>
- <div
- class=""
- >
+ <div>
<pre
- class="border-0 bg-transparent m-0 code highlight text-wrap"
+ class="bg-transparent border-0 code highlight m-0 text-wrap"
>
<span
class="line"
@@ -39,9 +36,8 @@ exports[`Code navigation popover component renders popover 1`] = `
function
</span>
<span>
- main() {
+ main() {
</span>
-
<br />
</span>
<span
@@ -51,15 +47,13 @@ exports[`Code navigation popover component renders popover 1`] = `
<span>
}
</span>
-
<br />
</span>
</pre>
</div>
</div>
-
<div
- class="popover-body border-top"
+ class="border-top popover-body"
>
<gl-button-stub
buttontextclasses=""
@@ -72,25 +66,19 @@ exports[`Code navigation popover component renders popover 1`] = `
target="_blank"
variant="default"
>
-
Go to definition
-
</gl-button-stub>
</div>
</gl-tab-stub>
-
<gl-tab-stub
class="py-2"
data-testid="references-tab"
titlelinkclass=""
>
-
<p
class="gl-my-4 gl-px-4"
>
-
No references found
-
</p>
</gl-tab-stub>
</gl-tabs-stub>
diff --git a/spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap b/spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap
index 60c87aa10eb..24b2677f497 100644
--- a/spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap
+++ b/spec/frontend/comment_templates/components/__snapshots__/list_item_spec.js.snap
@@ -13,23 +13,20 @@ exports[`Comment templates list item component renders list item 1`] = `
>
test
</h6>
-
<div
class="gl-ml-auto"
>
<div
- class="gl-new-dropdown gl-disclosure-dropdown"
+ class="gl-disclosure-dropdown gl-new-dropdown"
>
<button
- aria-controls="base-dropdown-7"
- aria-labelledby="actions-toggle-3"
- class="btn btn-default btn-md gl-button btn-default-tertiary gl-new-dropdown-toggle gl-new-dropdown-icon-only gl-new-dropdown-toggle-no-caret"
+ aria-controls="reference-1"
+ aria-labelledby="reference-0"
+ class="btn btn-default btn-default-tertiary btn-md gl-button gl-new-dropdown-icon-only gl-new-dropdown-toggle gl-new-dropdown-toggle-no-caret"
data-testid="base-dropdown-toggle"
- id="actions-toggle-3"
+ id="reference-0"
type="button"
>
- <!---->
-
<svg
aria-hidden="true"
class="gl-button-icon gl-icon s16"
@@ -40,36 +37,29 @@ exports[`Comment templates list item component renders list item 1`] = `
href="file-mock#ellipsis_v"
/>
</svg>
-
<span
class="gl-button-text"
>
<span
class="gl-new-dropdown-button-text gl-sr-only"
>
-
- Comment template actions
-
+ Comment template actions
</span>
-
- <!---->
</span>
</button>
-
<div
class="gl-new-dropdown-panel gl-w-31!"
data-testid="base-dropdown-menu"
- id="base-dropdown-7"
+ id="reference-1"
>
<div
class="gl-new-dropdown-inner"
>
-
<ul
- aria-labelledby="actions-toggle-3"
+ aria-labelledby="reference-0"
class="gl-new-dropdown-contents"
data-testid="disclosure-content"
- id="disclosure-4"
+ id="reference-2"
tabindex="-1"
>
<li
@@ -86,9 +76,7 @@ exports[`Comment templates list item component renders list item 1`] = `
<span
class="gl-new-dropdown-item-text-wrapper"
>
-
- Edit
-
+ Edit
</span>
</button>
</li>
@@ -106,36 +94,25 @@ exports[`Comment templates list item component renders list item 1`] = `
<span
class="gl-new-dropdown-item-text-wrapper"
>
-
- Delete
-
+ Delete
</span>
</button>
</li>
</ul>
-
</div>
</div>
</div>
-
<div
class="gl-tooltip"
>
-
Comment template actions
-
</div>
</div>
</div>
-
<div
- class="gl-font-monospace gl-white-space-pre-line gl-font-sm gl-mt-n5"
+ class="gl-font-monospace gl-font-sm gl-mt-n5 gl-white-space-pre-line"
>
-
/assign_reviewer
-
</div>
-
- <!---->
</li>
`;
diff --git a/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js b/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
index 3b3e5098857..891cd0a6b83 100644
--- a/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
+++ b/spec/frontend/commit/commit_box_pipeline_mini_graph_spec.js
@@ -7,11 +7,11 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import CommitBoxPipelineMiniGraph from '~/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import PipelineMiniGraph from '~/ci/pipeline_mini_graph/pipeline_mini_graph.vue';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
import { COMMIT_BOX_POLL_INTERVAL } from '~/projects/commit_box/info/constants';
-import getLinkedPipelinesQuery from '~/pipelines/graphql/queries/get_linked_pipelines.query.graphql';
-import getPipelineStagesQuery from '~/pipelines/graphql/queries/get_pipeline_stages.query.graphql';
+import getLinkedPipelinesQuery from '~/ci/pipeline_details/graphql/queries/get_linked_pipelines.query.graphql';
+import getPipelineStagesQuery from '~/ci/pipeline_mini_graph/graphql/queries/get_pipeline_stages.query.graphql';
import * as sharedGraphQlUtils from '~/graphql_shared/utils';
import {
mockDownstreamQueryResponse,
diff --git a/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js b/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js
new file mode 100644
index 00000000000..4af292e3588
--- /dev/null
+++ b/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js
@@ -0,0 +1,362 @@
+import { GlLoadingIcon, GlModal, GlTableLite } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import { nextTick } from 'vue';
+import fixture from 'test_fixtures/pipelines/pipelines.json';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { stubComponent } from 'helpers/stub_component';
+import waitForPromises from 'helpers/wait_for_promises';
+import Api from '~/api';
+import LegacyPipelinesTableWraper from '~/commit/pipelines/legacy_pipelines_table_wrapper.vue';
+import {
+ HTTP_STATUS_BAD_REQUEST,
+ HTTP_STATUS_INTERNAL_SERVER_ERROR,
+ HTTP_STATUS_OK,
+ HTTP_STATUS_UNAUTHORIZED,
+} from '~/lib/utils/http_status';
+import { createAlert } from '~/alert';
+import { TOAST_MESSAGE } from '~/ci/pipeline_details/constants';
+import axios from '~/lib/utils/axios_utils';
+
+const $toast = {
+ show: jest.fn(),
+};
+
+jest.mock('~/alert');
+
+describe('Pipelines table in Commits and Merge requests', () => {
+ let wrapper;
+ let pipeline;
+ let mock;
+ const showMock = jest.fn();
+
+ const findRunPipelineBtn = () => wrapper.findByTestId('run_pipeline_button');
+ const findRunPipelineBtnMobile = () => wrapper.findByTestId('run_pipeline_button_mobile');
+ const findLoadingState = () => wrapper.findComponent(GlLoadingIcon);
+ const findErrorEmptyState = () => wrapper.findByTestId('pipeline-error-empty-state');
+ const findEmptyState = () => wrapper.findByTestId('pipeline-empty-state');
+ const findTable = () => wrapper.findComponent(GlTableLite);
+ const findTableRows = () => wrapper.findAllByTestId('pipeline-table-row');
+ const findModal = () => wrapper.findComponent(GlModal);
+ const findMrPipelinesDocsLink = () => wrapper.findByTestId('mr-pipelines-docs-link');
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = extendedWrapper(
+ mount(LegacyPipelinesTableWraper, {
+ propsData: {
+ endpoint: 'endpoint.json',
+ emptyStateSvgPath: 'foo',
+ errorStateSvgPath: 'foo',
+ ...props,
+ },
+ mocks: {
+ $toast,
+ },
+ stubs: {
+ GlModal: stubComponent(GlModal, {
+ template: '<div />',
+ methods: { show: showMock },
+ }),
+ },
+ }),
+ );
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ const { pipelines } = fixture;
+
+ pipeline = pipelines.find((p) => p.user !== null && p.commit !== null);
+ });
+
+ describe('successful request', () => {
+ describe('without pipelines', () => {
+ beforeEach(async () => {
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, []);
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('should render the empty state', () => {
+ expect(findTableRows()).toHaveLength(0);
+ expect(findLoadingState().exists()).toBe(false);
+ expect(findErrorEmptyState().exists()).toBe(false);
+ expect(findEmptyState().exists()).toBe(true);
+ });
+
+ it('should render correct empty state content', () => {
+ expect(findRunPipelineBtn().exists()).toBe(true);
+ expect(findMrPipelinesDocsLink().attributes('href')).toBe(
+ '/help/ci/pipelines/merge_request_pipelines.md#prerequisites',
+ );
+ expect(findEmptyState().text()).toContain(
+ 'To run a merge request pipeline, the jobs in the CI/CD configuration file must be configured to run in merge request pipelines.',
+ );
+ });
+ });
+
+ describe('with pagination', () => {
+ beforeEach(async () => {
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipeline], {
+ 'X-TOTAL': 10,
+ 'X-PER-PAGE': 2,
+ 'X-PAGE': 1,
+ 'X-TOTAL-PAGES': 5,
+ 'X-NEXT-PAGE': 2,
+ 'X-PREV-PAGE': 2,
+ });
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('should make an API request when using pagination', async () => {
+ expect(mock.history.get).toHaveLength(1);
+ expect(mock.history.get[0].params.page).toBe('1');
+
+ wrapper.find('.next-page-item').trigger('click');
+
+ await waitForPromises();
+
+ expect(mock.history.get).toHaveLength(2);
+ expect(mock.history.get[1].params.page).toBe('2');
+ });
+ });
+
+ describe('with pipelines', () => {
+ beforeEach(async () => {
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipeline], { 'x-total': 10 });
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('should render a table with the received pipelines', () => {
+ expect(findTable().exists()).toBe(true);
+ expect(findTableRows()).toHaveLength(1);
+ expect(findLoadingState().exists()).toBe(false);
+ expect(findErrorEmptyState().exists()).toBe(false);
+ });
+
+ describe('pipeline badge counts', () => {
+ it('should receive update-pipelines-count event', () => {
+ const element = document.createElement('div');
+ document.body.appendChild(element);
+
+ return new Promise((resolve) => {
+ element.addEventListener('update-pipelines-count', (event) => {
+ expect(event.detail.pipelineCount).toEqual(10);
+ resolve();
+ });
+
+ createComponent();
+
+ element.appendChild(wrapper.vm.$el);
+ });
+ });
+ });
+ });
+ });
+
+ describe('run pipeline button', () => {
+ let pipelineCopy;
+
+ beforeEach(() => {
+ pipelineCopy = { ...pipeline };
+ });
+
+ describe('when latest pipeline has detached flag', () => {
+ it('renders the run pipeline button', async () => {
+ pipelineCopy.flags.detached_merge_request_pipeline = true;
+ pipelineCopy.flags.merge_request_pipeline = true;
+
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findRunPipelineBtn().exists()).toBe(true);
+ expect(findRunPipelineBtnMobile().exists()).toBe(true);
+ });
+ });
+
+ describe('when latest pipeline does not have detached flag', () => {
+ it('does not render the run pipeline button', async () => {
+ pipelineCopy.flags.detached_merge_request_pipeline = false;
+ pipelineCopy.flags.merge_request_pipeline = false;
+
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
+
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findRunPipelineBtn().exists()).toBe(false);
+ expect(findRunPipelineBtnMobile().exists()).toBe(false);
+ });
+ });
+
+ describe('on click', () => {
+ beforeEach(async () => {
+ pipelineCopy.flags.detached_merge_request_pipeline = true;
+
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
+
+ createComponent({
+ props: {
+ canRunPipeline: true,
+ projectId: '5',
+ mergeRequestId: 3,
+ },
+ });
+
+ await waitForPromises();
+ });
+ describe('success', () => {
+ beforeEach(() => {
+ jest.spyOn(Api, 'postMergeRequestPipeline').mockResolvedValue();
+ });
+ it('displays a toast message during pipeline creation', async () => {
+ await findRunPipelineBtn().trigger('click');
+
+ expect($toast.show).toHaveBeenCalledWith(TOAST_MESSAGE);
+ });
+
+ it('on desktop, shows a loading button', async () => {
+ await findRunPipelineBtn().trigger('click');
+
+ expect(findRunPipelineBtn().props('loading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findRunPipelineBtn().props('loading')).toBe(false);
+ });
+
+ it('on mobile, shows a loading button', async () => {
+ await findRunPipelineBtnMobile().trigger('click');
+
+ expect(findRunPipelineBtn().props('loading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findRunPipelineBtn().props('disabled')).toBe(false);
+ expect(findRunPipelineBtn().props('loading')).toBe(false);
+ });
+ });
+
+ describe('failure', () => {
+ const permissionsMsg = 'You do not have permission to run a pipeline on this branch.';
+ const defaultMsg =
+ 'An error occurred while trying to run a new pipeline for this merge request.';
+
+ it.each`
+ status | message
+ ${HTTP_STATUS_BAD_REQUEST} | ${defaultMsg}
+ ${HTTP_STATUS_UNAUTHORIZED} | ${permissionsMsg}
+ ${HTTP_STATUS_INTERNAL_SERVER_ERROR} | ${defaultMsg}
+ `('displays permissions error message', async ({ status, message }) => {
+ const response = { response: { status } };
+
+ jest.spyOn(Api, 'postMergeRequestPipeline').mockRejectedValue(response);
+
+ await findRunPipelineBtn().trigger('click');
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message,
+ primaryButton: {
+ text: 'Learn more',
+ link: '/help/ci/pipelines/merge_request_pipelines.md',
+ },
+ });
+ });
+ });
+ });
+
+ describe('on click for fork merge request', () => {
+ beforeEach(async () => {
+ pipelineCopy.flags.detached_merge_request_pipeline = true;
+
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
+
+ createComponent({
+ props: {
+ projectId: '5',
+ mergeRequestId: 3,
+ canCreatePipelineInTargetProject: true,
+ sourceProjectFullPath: 'test/parent-project',
+ targetProjectFullPath: 'test/fork-project',
+ },
+ });
+
+ jest.spyOn(Api, 'postMergeRequestPipeline').mockResolvedValue();
+
+ await waitForPromises();
+ });
+
+ it('on desktop, shows a security warning modal', async () => {
+ await findRunPipelineBtn().trigger('click');
+
+ await nextTick();
+
+ expect(findModal()).not.toBeNull();
+ });
+
+ it('on mobile, shows a security warning modal', async () => {
+ await findRunPipelineBtnMobile().trigger('click');
+
+ expect(findModal()).not.toBeNull();
+ });
+ });
+
+ describe('when no pipelines were created on a forked merge request', () => {
+ beforeEach(async () => {
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, []);
+
+ createComponent({
+ props: {
+ projectId: '5',
+ mergeRequestId: 3,
+ canCreatePipelineInTargetProject: true,
+ sourceProjectFullPath: 'test/parent-project',
+ targetProjectFullPath: 'test/fork-project',
+ },
+ });
+
+ await waitForPromises();
+ });
+
+ it('should show security modal from empty state run pipeline button', () => {
+ expect(findEmptyState().exists()).toBe(true);
+ expect(findModal().exists()).toBe(true);
+
+ findRunPipelineBtn().trigger('click');
+
+ expect(showMock).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('unsuccessfull request', () => {
+ beforeEach(async () => {
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, []);
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('should render error state', () => {
+ expect(findErrorEmptyState().text()).toBe(
+ 'There was an error fetching the pipelines. Try again in a few moments or contact your support team.',
+ );
+ });
+ });
+});
diff --git a/spec/frontend/commit/pipelines/pipelines_table_spec.js b/spec/frontend/commit/pipelines/pipelines_table_spec.js
deleted file mode 100644
index 009ec68ddcf..00000000000
--- a/spec/frontend/commit/pipelines/pipelines_table_spec.js
+++ /dev/null
@@ -1,362 +0,0 @@
-import { GlLoadingIcon, GlModal, GlTableLite } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
-import fixture from 'test_fixtures/pipelines/pipelines.json';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { stubComponent } from 'helpers/stub_component';
-import waitForPromises from 'helpers/wait_for_promises';
-import Api from '~/api';
-import PipelinesTable from '~/commit/pipelines/pipelines_table.vue';
-import {
- HTTP_STATUS_BAD_REQUEST,
- HTTP_STATUS_INTERNAL_SERVER_ERROR,
- HTTP_STATUS_OK,
- HTTP_STATUS_UNAUTHORIZED,
-} from '~/lib/utils/http_status';
-import { createAlert } from '~/alert';
-import { TOAST_MESSAGE } from '~/pipelines/constants';
-import axios from '~/lib/utils/axios_utils';
-
-const $toast = {
- show: jest.fn(),
-};
-
-jest.mock('~/alert');
-
-describe('Pipelines table in Commits and Merge requests', () => {
- let wrapper;
- let pipeline;
- let mock;
- const showMock = jest.fn();
-
- const findRunPipelineBtn = () => wrapper.findByTestId('run_pipeline_button');
- const findRunPipelineBtnMobile = () => wrapper.findByTestId('run_pipeline_button_mobile');
- const findLoadingState = () => wrapper.findComponent(GlLoadingIcon);
- const findErrorEmptyState = () => wrapper.findByTestId('pipeline-error-empty-state');
- const findEmptyState = () => wrapper.findByTestId('pipeline-empty-state');
- const findTable = () => wrapper.findComponent(GlTableLite);
- const findTableRows = () => wrapper.findAllByTestId('pipeline-table-row');
- const findModal = () => wrapper.findComponent(GlModal);
- const findMrPipelinesDocsLink = () => wrapper.findByTestId('mr-pipelines-docs-link');
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = extendedWrapper(
- mount(PipelinesTable, {
- propsData: {
- endpoint: 'endpoint.json',
- emptyStateSvgPath: 'foo',
- errorStateSvgPath: 'foo',
- ...props,
- },
- mocks: {
- $toast,
- },
- stubs: {
- GlModal: stubComponent(GlModal, {
- template: '<div />',
- methods: { show: showMock },
- }),
- },
- }),
- );
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- const { pipelines } = fixture;
-
- pipeline = pipelines.find((p) => p.user !== null && p.commit !== null);
- });
-
- describe('successful request', () => {
- describe('without pipelines', () => {
- beforeEach(async () => {
- mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, []);
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('should render the empty state', () => {
- expect(findTableRows()).toHaveLength(0);
- expect(findLoadingState().exists()).toBe(false);
- expect(findErrorEmptyState().exists()).toBe(false);
- expect(findEmptyState().exists()).toBe(true);
- });
-
- it('should render correct empty state content', () => {
- expect(findRunPipelineBtn().exists()).toBe(true);
- expect(findMrPipelinesDocsLink().attributes('href')).toBe(
- '/help/ci/pipelines/merge_request_pipelines.md#prerequisites',
- );
- expect(findEmptyState().text()).toContain(
- 'To run a merge request pipeline, the jobs in the CI/CD configuration file must be configured to run in merge request pipelines.',
- );
- });
- });
-
- describe('with pagination', () => {
- beforeEach(async () => {
- mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipeline], {
- 'X-TOTAL': 10,
- 'X-PER-PAGE': 2,
- 'X-PAGE': 1,
- 'X-TOTAL-PAGES': 5,
- 'X-NEXT-PAGE': 2,
- 'X-PREV-PAGE': 2,
- });
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('should make an API request when using pagination', async () => {
- expect(mock.history.get).toHaveLength(1);
- expect(mock.history.get[0].params.page).toBe('1');
-
- wrapper.find('.next-page-item').trigger('click');
-
- await waitForPromises();
-
- expect(mock.history.get).toHaveLength(2);
- expect(mock.history.get[1].params.page).toBe('2');
- });
- });
-
- describe('with pipelines', () => {
- beforeEach(async () => {
- mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipeline], { 'x-total': 10 });
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('should render a table with the received pipelines', () => {
- expect(findTable().exists()).toBe(true);
- expect(findTableRows()).toHaveLength(1);
- expect(findLoadingState().exists()).toBe(false);
- expect(findErrorEmptyState().exists()).toBe(false);
- });
-
- describe('pipeline badge counts', () => {
- it('should receive update-pipelines-count event', () => {
- const element = document.createElement('div');
- document.body.appendChild(element);
-
- return new Promise((resolve) => {
- element.addEventListener('update-pipelines-count', (event) => {
- expect(event.detail.pipelineCount).toEqual(10);
- resolve();
- });
-
- createComponent();
-
- element.appendChild(wrapper.vm.$el);
- });
- });
- });
- });
- });
-
- describe('run pipeline button', () => {
- let pipelineCopy;
-
- beforeEach(() => {
- pipelineCopy = { ...pipeline };
- });
-
- describe('when latest pipeline has detached flag', () => {
- it('renders the run pipeline button', async () => {
- pipelineCopy.flags.detached_merge_request_pipeline = true;
- pipelineCopy.flags.merge_request_pipeline = true;
-
- mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
-
- createComponent();
-
- await waitForPromises();
-
- expect(findRunPipelineBtn().exists()).toBe(true);
- expect(findRunPipelineBtnMobile().exists()).toBe(true);
- });
- });
-
- describe('when latest pipeline does not have detached flag', () => {
- it('does not render the run pipeline button', async () => {
- pipelineCopy.flags.detached_merge_request_pipeline = false;
- pipelineCopy.flags.merge_request_pipeline = false;
-
- mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
-
- createComponent();
-
- await waitForPromises();
-
- expect(findRunPipelineBtn().exists()).toBe(false);
- expect(findRunPipelineBtnMobile().exists()).toBe(false);
- });
- });
-
- describe('on click', () => {
- beforeEach(async () => {
- pipelineCopy.flags.detached_merge_request_pipeline = true;
-
- mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
-
- createComponent({
- props: {
- canRunPipeline: true,
- projectId: '5',
- mergeRequestId: 3,
- },
- });
-
- await waitForPromises();
- });
- describe('success', () => {
- beforeEach(() => {
- jest.spyOn(Api, 'postMergeRequestPipeline').mockResolvedValue();
- });
- it('displays a toast message during pipeline creation', async () => {
- await findRunPipelineBtn().trigger('click');
-
- expect($toast.show).toHaveBeenCalledWith(TOAST_MESSAGE);
- });
-
- it('on desktop, shows a loading button', async () => {
- await findRunPipelineBtn().trigger('click');
-
- expect(findRunPipelineBtn().props('loading')).toBe(true);
-
- await waitForPromises();
-
- expect(findRunPipelineBtn().props('loading')).toBe(false);
- });
-
- it('on mobile, shows a loading button', async () => {
- await findRunPipelineBtnMobile().trigger('click');
-
- expect(findRunPipelineBtn().props('loading')).toBe(true);
-
- await waitForPromises();
-
- expect(findRunPipelineBtn().props('disabled')).toBe(false);
- expect(findRunPipelineBtn().props('loading')).toBe(false);
- });
- });
-
- describe('failure', () => {
- const permissionsMsg = 'You do not have permission to run a pipeline on this branch.';
- const defaultMsg =
- 'An error occurred while trying to run a new pipeline for this merge request.';
-
- it.each`
- status | message
- ${HTTP_STATUS_BAD_REQUEST} | ${defaultMsg}
- ${HTTP_STATUS_UNAUTHORIZED} | ${permissionsMsg}
- ${HTTP_STATUS_INTERNAL_SERVER_ERROR} | ${defaultMsg}
- `('displays permissions error message', async ({ status, message }) => {
- const response = { response: { status } };
-
- jest.spyOn(Api, 'postMergeRequestPipeline').mockRejectedValue(response);
-
- await findRunPipelineBtn().trigger('click');
-
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message,
- primaryButton: {
- text: 'Learn more',
- link: '/help/ci/pipelines/merge_request_pipelines.md',
- },
- });
- });
- });
- });
-
- describe('on click for fork merge request', () => {
- beforeEach(async () => {
- pipelineCopy.flags.detached_merge_request_pipeline = true;
-
- mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipelineCopy]);
-
- createComponent({
- props: {
- projectId: '5',
- mergeRequestId: 3,
- canCreatePipelineInTargetProject: true,
- sourceProjectFullPath: 'test/parent-project',
- targetProjectFullPath: 'test/fork-project',
- },
- });
-
- jest.spyOn(Api, 'postMergeRequestPipeline').mockResolvedValue();
-
- await waitForPromises();
- });
-
- it('on desktop, shows a security warning modal', async () => {
- await findRunPipelineBtn().trigger('click');
-
- await nextTick();
-
- expect(findModal()).not.toBeNull();
- });
-
- it('on mobile, shows a security warning modal', async () => {
- await findRunPipelineBtnMobile().trigger('click');
-
- expect(findModal()).not.toBeNull();
- });
- });
-
- describe('when no pipelines were created on a forked merge request', () => {
- beforeEach(async () => {
- mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, []);
-
- createComponent({
- props: {
- projectId: '5',
- mergeRequestId: 3,
- canCreatePipelineInTargetProject: true,
- sourceProjectFullPath: 'test/parent-project',
- targetProjectFullPath: 'test/fork-project',
- },
- });
-
- await waitForPromises();
- });
-
- it('should show security modal from empty state run pipeline button', () => {
- expect(findEmptyState().exists()).toBe(true);
- expect(findModal().exists()).toBe(true);
-
- findRunPipelineBtn().trigger('click');
-
- expect(showMock).toHaveBeenCalled();
- });
- });
- });
-
- describe('unsuccessfull request', () => {
- beforeEach(async () => {
- mock.onGet('endpoint.json').reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, []);
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('should render error state', () => {
- expect(findErrorEmptyState().text()).toBe(
- 'There was an error fetching the pipelines. Try again in a few moments or contact your support team.',
- );
- });
- });
-});
diff --git a/spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap b/spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap
index d9f161b47b1..b17987dad89 100644
--- a/spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap
+++ b/spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap
@@ -7,17 +7,13 @@ exports[`Confidential merge request project form group component renders empty s
<label>
Project
</label>
-
<div>
- <!---->
-
<p
- class="gl-text-gray-600 gl-mt-1 gl-mb-0"
+ class="gl-mb-0 gl-mt-1 gl-text-gray-600"
>
-
- No forks are available to you.
+ No forks are available to you.
<br />
- To protect this issue's confidentiality,
+ To protect this issue's confidentiality,
<a
class="help-link"
href="https://test.com"
@@ -25,9 +21,9 @@ exports[`Confidential merge request project form group component renders empty s
>
fork this project
</a>
- and set the fork's visibility to private.
+ and set the fork's visibility to private.
<gl-link-stub
- class="gl-w-auto gl-p-0 gl-display-inline-block gl-bg-transparent"
+ class="gl-bg-transparent gl-display-inline-block gl-p-0 gl-w-auto"
href="/help"
target="_blank"
>
@@ -36,7 +32,6 @@ exports[`Confidential merge request project form group component renders empty s
>
Read more
</span>
-
<gl-icon-stub
name="question-o"
size="16"
@@ -54,21 +49,17 @@ exports[`Confidential merge request project form group component renders fork dr
<label>
Project
</label>
-
<div>
<dropdown-stub
projects="[object Object],[object Object]"
selectedproject="[object Object]"
/>
-
<p
- class="gl-text-gray-600 gl-mt-1 gl-mb-0"
+ class="gl-mb-0 gl-mt-1 gl-text-gray-600"
>
-
- To protect this issue's confidentiality, a private fork of this project was selected.
-
+ To protect this issue's confidentiality, a private fork of this project was selected.
<gl-link-stub
- class="gl-w-auto gl-p-0 gl-display-inline-block gl-bg-transparent"
+ class="gl-bg-transparent gl-display-inline-block gl-p-0 gl-w-auto"
href="/help"
target="_blank"
>
@@ -77,7 +68,6 @@ exports[`Confidential merge request project form group component renders fork dr
>
Read more
</span>
-
<gl-icon-stub
name="question-o"
size="16"
diff --git a/spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap b/spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap
index a328f79e4e7..a708f7d5f47 100644
--- a/spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap
+++ b/spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap
@@ -1,9 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`content_editor/components/toolbar_button displays tertiary, medium button with a provided label and icon 1`] = `
-"<b-button-stub size=\\"sm\\" tag=\\"button\\" type=\\"button\\" variant=\\"default\\" aria-label=\\"Bold\\" title=\\"Bold\\" class=\\"gl-mr-3 gl-button btn-default-tertiary btn-icon\\">
- <!---->
- <gl-icon-stub name=\\"bold\\" size=\\"16\\" class=\\"gl-button-icon\\"></gl-icon-stub>
- <!---->
-</b-button-stub>"
+<b-button-stub
+ aria-label="Bold"
+ class="btn-default-tertiary btn-icon gl-button gl-mr-3"
+ size="sm"
+ tag="button"
+ title="Bold"
+ type="button"
+ variant="default"
+>
+ <gl-icon-stub
+ class="gl-button-icon"
+ name="bold"
+ size="16"
+ />
+</b-button-stub>
`;
diff --git a/spec/frontend/content_editor/components/wrappers/__snapshots__/table_of_contents_spec.js.snap b/spec/frontend/content_editor/components/wrappers/__snapshots__/table_of_contents_spec.js.snap
index a9d42769789..e058f05fec4 100644
--- a/spec/frontend/content_editor/components/wrappers/__snapshots__/table_of_contents_spec.js.snap
+++ b/spec/frontend/content_editor/components/wrappers/__snapshots__/table_of_contents_spec.js.snap
@@ -2,23 +2,18 @@
exports[`content/components/wrappers/table_of_contents collects all headings and renders a nested list of headings 1`] = `
<div
- class="table-of-contents gl-border-1 gl-border-solid gl-border-gray-100 gl-mb-5 gl-p-4!"
+ class="gl-border-1 gl-border-gray-100 gl-border-solid gl-mb-5 gl-p-4! table-of-contents"
data-testid="table-of-contents"
>
-
Table of contents
-
<li
dir="auto"
>
<a
href="#"
>
-
- Heading 1
-
+ Heading 1
</a>
-
<ul
dir="auto"
>
@@ -28,11 +23,8 @@ exports[`content/components/wrappers/table_of_contents collects all headings and
<a
href="#"
>
-
- Heading 1.1
-
+ Heading 1.1
</a>
-
<ul
dir="auto"
>
@@ -42,12 +34,8 @@ exports[`content/components/wrappers/table_of_contents collects all headings and
<a
href="#"
>
-
- Heading 1.1.1
-
+ Heading 1.1.1
</a>
-
- <!---->
</li>
</ul>
</li>
@@ -57,11 +45,8 @@ exports[`content/components/wrappers/table_of_contents collects all headings and
<a
href="#"
>
-
- Heading 1.2
-
+ Heading 1.2
</a>
-
<ul
dir="auto"
>
@@ -71,12 +56,8 @@ exports[`content/components/wrappers/table_of_contents collects all headings and
<a
href="#"
>
-
- Heading 1.2.1
-
+ Heading 1.2.1
</a>
-
- <!---->
</li>
</ul>
</li>
@@ -86,12 +67,8 @@ exports[`content/components/wrappers/table_of_contents collects all headings and
<a
href="#"
>
-
- Heading 1.3
-
+ Heading 1.3
</a>
-
- <!---->
</li>
<li
dir="auto"
@@ -99,11 +76,8 @@ exports[`content/components/wrappers/table_of_contents collects all headings and
<a
href="#"
>
-
- Heading 1.4
-
+ Heading 1.4
</a>
-
<ul
dir="auto"
>
@@ -113,12 +87,8 @@ exports[`content/components/wrappers/table_of_contents collects all headings and
<a
href="#"
>
-
- Heading 1.4.1
-
+ Heading 1.4.1
</a>
-
- <!---->
</li>
</ul>
</li>
@@ -130,12 +100,8 @@ exports[`content/components/wrappers/table_of_contents collects all headings and
<a
href="#"
>
-
- Heading 2
-
+ Heading 2
</a>
-
- <!---->
</li>
</div>
`;
diff --git a/spec/frontend/content_editor/components/wrappers/code_block_spec.js b/spec/frontend/content_editor/components/wrappers/code_block_spec.js
index e802681dfc6..0093393eceb 100644
--- a/spec/frontend/content_editor/components/wrappers/code_block_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/code_block_spec.js
@@ -11,6 +11,9 @@ import CodeBlockWrapper from '~/content_editor/components/wrappers/code_block.vu
import codeBlockLanguageLoader from '~/content_editor/services/code_block_language_loader';
import { emitEditorEvent, createTestEditor, mockChainedCommands } from '../../test_utils';
+// Disabled due to eslint reporting errors for inline snapshots
+/* eslint-disable no-irregular-whitespace */
+
const SAMPLE_README_CONTENT = `# Sample README
This is a sample README.
@@ -212,12 +215,20 @@ describe('content/components/wrappers/code_block', () => {
it('shows a code suggestion block', () => {
expect(findCodeSuggestionBoxText()).toContain('Suggested change From line 5 to 5');
- expect(findCodeDeleted()).toMatchInlineSnapshot(
- `"<code data-line-number=\\"5\\">## Usage\u200b</code>"`,
- );
- expect(findCodeAdded()).toMatchInlineSnapshot(
- `"<code data-line-number=\\"5\\">\u200b</code>"`,
- );
+ expect(findCodeDeleted()).toMatchInlineSnapshot(`
+ <code
+ data-line-number="5"
+ >
+ ## Usage​
+ </code>
+ `);
+ expect(findCodeAdded()).toMatchInlineSnapshot(`
+ <code
+ data-line-number="5"
+ >
+ ​
+ </code>
+ `);
});
describe('decrement line start button', () => {
@@ -232,9 +243,11 @@ describe('content/components/wrappers/code_block', () => {
expect(findCodeSuggestionBoxText()).toContain('Suggested change From line 4 to 5');
expect(findCodeDeleted()).toMatchInlineSnapshot(`
- "<code data-line-number=\\"4\\">\u200b
+ <code
+ data-line-number="4"
+ >
+ ​
</code>
- <code data-line-number=\\"5\\">## Usage\u200b</code>"
`);
});
@@ -248,15 +261,11 @@ describe('content/components/wrappers/code_block', () => {
expect(findCodeSuggestionBoxText()).toContain('Suggested change From line 1 to 5');
expect(findCodeDeleted()).toMatchInlineSnapshot(`
- "<code data-line-number=\\"1\\"># Sample README\u200b
- </code>
- <code data-line-number=\\"2\\">\u200b
- </code>
- <code data-line-number=\\"3\\">This is a sample README.\u200b
- </code>
- <code data-line-number=\\"4\\">\u200b
+ <code
+ data-line-number="1"
+ >
+ # Sample README​
</code>
- <code data-line-number=\\"5\\">## Usage\u200b</code>"
`);
expect(button.attributes('disabled')).toBe('disabled');
@@ -291,9 +300,11 @@ describe('content/components/wrappers/code_block', () => {
expect(findCodeSuggestionBoxText()).toContain('Suggested change From line 4 to 5');
expect(findCodeDeleted()).toMatchInlineSnapshot(`
- "<code data-line-number=\\"4\\">\u200b
+ <code
+ data-line-number="4"
+ >
+ ​
</code>
- <code data-line-number=\\"5\\">## Usage\u200b</code>"
`);
});
});
@@ -326,9 +337,11 @@ describe('content/components/wrappers/code_block', () => {
expect(findCodeSuggestionBoxText()).toContain('Suggested change From line 5 to 6');
expect(findCodeDeleted()).toMatchInlineSnapshot(`
- "<code data-line-number=\\"5\\">## Usage\u200b
+ <code
+ data-line-number="5"
+ >
+ ## Usage​
</code>
- <code data-line-number=\\"6\\">\u200b</code>"
`);
});
});
@@ -345,9 +358,11 @@ describe('content/components/wrappers/code_block', () => {
expect(findCodeSuggestionBoxText()).toContain('Suggested change From line 5 to 6');
expect(findCodeDeleted()).toMatchInlineSnapshot(`
- "<code data-line-number=\\"5\\">## Usage\u200b
+ <code
+ data-line-number="5"
+ >
+ ## Usage​
</code>
- <code data-line-number=\\"6\\">\u200b</code>"
`);
});
@@ -361,15 +376,11 @@ describe('content/components/wrappers/code_block', () => {
expect(findCodeSuggestionBoxText()).toContain('Suggested change From line 5 to 9');
expect(findCodeDeleted()).toMatchInlineSnapshot(`
- "<code data-line-number=\\"5\\">## Usage\u200b
- </code>
- <code data-line-number=\\"6\\">\u200b
- </code>
- <code data-line-number=\\"7\\">\`\`\`yaml\u200b
- </code>
- <code data-line-number=\\"8\\">foo: bar\u200b
+ <code
+ data-line-number="5"
+ >
+ ## Usage​
</code>
- <code data-line-number=\\"9\\">\`\`\`\u200b</code>"
`);
expect(button.attributes('disabled')).toBe('disabled');
diff --git a/spec/frontend/content_editor/services/markdown_serializer_spec.js b/spec/frontend/content_editor/services/markdown_serializer_spec.js
index 7be8114902a..3eb00f69345 100644
--- a/spec/frontend/content_editor/services/markdown_serializer_spec.js
+++ b/spec/frontend/content_editor/services/markdown_serializer_spec.js
@@ -175,7 +175,7 @@ describe('markdownSerializer', () => {
inlineDiff({ type: 'deletion' }, '-10 lines'),
),
),
- ).toBe('{+\\+30 lines+}{-\\-10 lines-}');
+ ).toBe('{++30 lines+}{--10 lines-}');
});
it('correctly serializes highlight', () => {
diff --git a/spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js b/spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js
index 4be4aa50dfc..50b12244a55 100644
--- a/spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js
+++ b/spec/frontend/contribution_events/components/contribution_event/contribution_event_created_spec.js
@@ -23,15 +23,15 @@ describe('ContributionEventCreated', () => {
};
describe.each`
- event | expectedMessage | expectedIconName | expectedIconClass
- ${eventProjectCreated()} | ${'Created project %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
- ${eventMilestoneCreated()} | ${'Opened milestone %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
- ${eventIssueCreated()} | ${'Opened issue %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
- ${eventMergeRequestCreated()} | ${'Opened merge request %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
- ${eventWikiPageCreated()} | ${'Created wiki page %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
- ${eventDesignCreated()} | ${'Added design %{targetLink} in %{resourceParentLink}.'} | ${'upload'} | ${null}
- ${{ resource_parent: { type: 'unsupported type' } }} | ${'Created resource.'} | ${'status_open'} | ${'gl-text-green-500'}
- ${{ target: { type: 'unsupported type' } }} | ${'Created resource.'} | ${'status_open'} | ${'gl-text-green-500'}
+ event | expectedMessage | expectedIconName | expectedIconClass
+ ${eventProjectCreated()} | ${'Created project %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventMilestoneCreated()} | ${'Opened milestone %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventIssueCreated()} | ${'Opened issue %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventMergeRequestCreated()} | ${'Opened merge request %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventWikiPageCreated()} | ${'Created wiki page %{targetLink} in %{resourceParentLink}.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${eventDesignCreated()} | ${'Added design %{targetLink} in %{resourceParentLink}.'} | ${'upload'} | ${null}
+ ${{ resource_parent: { type: 'unsupported type' }, target: { type: null } }} | ${'Created resource.'} | ${'status_open'} | ${'gl-text-green-500'}
+ ${{ target: { type: 'unsupported type' } }} | ${'Created resource.'} | ${'status_open'} | ${'gl-text-green-500'}
`(
'when event target type is $event.target.type',
({ event, expectedMessage, expectedIconName, expectedIconClass }) => {
diff --git a/spec/frontend/contribution_events/components/contribution_event/contribution_event_destroyed_spec.js b/spec/frontend/contribution_events/components/contribution_event/contribution_event_destroyed_spec.js
new file mode 100644
index 00000000000..b296b75ce0a
--- /dev/null
+++ b/spec/frontend/contribution_events/components/contribution_event/contribution_event_destroyed_spec.js
@@ -0,0 +1,32 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ContributionEventDestroyed from '~/contribution_events/components/contribution_event/contribution_event_destroyed.vue';
+import ContributionEventBase from '~/contribution_events/components/contribution_event/contribution_event_base.vue';
+import { eventDesignDestroyed, eventWikiPageDestroyed, eventMilestoneDestroyed } from '../../utils';
+
+describe('ContributionEventDestroyed', () => {
+ let wrapper;
+
+ const createComponent = ({ propsData }) => {
+ wrapper = shallowMountExtended(ContributionEventDestroyed, {
+ propsData,
+ });
+ };
+
+ describe.each`
+ event | expectedMessage | iconName
+ ${eventDesignDestroyed()} | ${'Archived design in %{resourceParentLink}.'} | ${'archive'}
+ ${eventWikiPageDestroyed()} | ${'Deleted wiki page in %{resourceParentLink}.'} | ${'remove'}
+ ${eventMilestoneDestroyed()} | ${'Deleted milestone in %{resourceParentLink}.'} | ${'remove'}
+ ${{ target: { type: 'unsupported type' } }} | ${'Deleted resource.'} | ${'remove'}
+ `('when event target type is $event.target.type', ({ event, expectedMessage, iconName }) => {
+ it('renders `ContributionEventBase` with correct props', () => {
+ createComponent({ propsData: { event } });
+
+ expect(wrapper.findComponent(ContributionEventBase).props()).toMatchObject({
+ event,
+ message: expectedMessage,
+ iconName,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/contribution_events/components/contribution_event/contribution_event_updated_spec.js b/spec/frontend/contribution_events/components/contribution_event/contribution_event_updated_spec.js
new file mode 100644
index 00000000000..e8e25b24dc9
--- /dev/null
+++ b/spec/frontend/contribution_events/components/contribution_event/contribution_event_updated_spec.js
@@ -0,0 +1,31 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ContributionEventUpdated from '~/contribution_events/components/contribution_event/contribution_event_updated.vue';
+import ContributionEventBase from '~/contribution_events/components/contribution_event/contribution_event_base.vue';
+import { eventDesignUpdated, eventWikiPageUpdated } from '../../utils';
+
+describe('ContributionEventUpdated', () => {
+ let wrapper;
+
+ const createComponent = ({ propsData }) => {
+ wrapper = shallowMountExtended(ContributionEventUpdated, {
+ propsData,
+ });
+ };
+
+ describe.each`
+ event | expectedMessage
+ ${eventDesignUpdated()} | ${'Updated design %{targetLink} in %{resourceParentLink}.'}
+ ${eventWikiPageUpdated()} | ${'Updated wiki page %{targetLink} in %{resourceParentLink}.'}
+ ${{ target: { type: 'unsupported type' } }} | ${'Updated resource.'}
+ `('when event target type is $event.target.type', ({ event, expectedMessage }) => {
+ it('renders `ContributionEventBase` with correct props', () => {
+ createComponent({ propsData: { event } });
+
+ expect(wrapper.findComponent(ContributionEventBase).props()).toMatchObject({
+ event,
+ message: expectedMessage,
+ iconName: 'pencil',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/contribution_events/components/contribution_events_spec.js b/spec/frontend/contribution_events/components/contribution_events_spec.js
index 7493d248e2b..dc460a698bd 100644
--- a/spec/frontend/contribution_events/components/contribution_events_spec.js
+++ b/spec/frontend/contribution_events/components/contribution_events_spec.js
@@ -11,6 +11,8 @@ import ContributionEventCreated from '~/contribution_events/components/contribut
import ContributionEventClosed from '~/contribution_events/components/contribution_event/contribution_event_closed.vue';
import ContributionEventReopened from '~/contribution_events/components/contribution_event/contribution_event_reopened.vue';
import ContributionEventCommented from '~/contribution_events/components/contribution_event/contribution_event_commented.vue';
+import ContributionEventUpdated from '~/contribution_events/components/contribution_event/contribution_event_updated.vue';
+import ContributionEventDestroyed from '~/contribution_events/components/contribution_event/contribution_event_destroyed.vue';
import {
eventApproved,
eventExpired,
@@ -23,6 +25,8 @@ import {
eventClosed,
eventReopened,
eventCommented,
+ eventUpdated,
+ eventDestroyed,
} from '../utils';
describe('ContributionEvents', () => {
@@ -43,6 +47,8 @@ describe('ContributionEvents', () => {
eventClosed(),
eventReopened(),
eventCommented(),
+ eventUpdated(),
+ eventDestroyed(),
],
},
});
@@ -61,6 +67,8 @@ describe('ContributionEvents', () => {
${ContributionEventClosed} | ${eventClosed()}
${ContributionEventReopened} | ${eventReopened()}
${ContributionEventCommented} | ${eventCommented()}
+ ${ContributionEventUpdated} | ${eventUpdated()}
+ ${ContributionEventDestroyed} | ${eventDestroyed()}
`(
'renders `$expectedComponent.name` component and passes expected event',
({ expectedComponent, expectedEvent }) => {
diff --git a/spec/frontend/contribution_events/components/target_link_spec.js b/spec/frontend/contribution_events/components/target_link_spec.js
index 40650b3585c..968a9d3bd3d 100644
--- a/spec/frontend/contribution_events/components/target_link_spec.js
+++ b/spec/frontend/contribution_events/components/target_link_spec.js
@@ -49,7 +49,7 @@ describe('TargetLink', () => {
});
});
- describe('when target is not defined', () => {
+ describe('when target type is not defined', () => {
beforeEach(() => {
createComponent({ propsData: { event: eventJoined() } });
});
diff --git a/spec/frontend/contribution_events/utils.js b/spec/frontend/contribution_events/utils.js
index 8b34506c6ac..f91a4dd800b 100644
--- a/spec/frontend/contribution_events/utils.js
+++ b/spec/frontend/contribution_events/utils.js
@@ -10,6 +10,8 @@ import {
EVENT_TYPE_CLOSED,
EVENT_TYPE_REOPENED,
EVENT_TYPE_COMMENTED,
+ EVENT_TYPE_UPDATED,
+ EVENT_TYPE_DESTROYED,
PUSH_EVENT_REF_TYPE_BRANCH,
PUSH_EVENT_REF_TYPE_TAG,
EVENT_TYPE_CREATED,
@@ -32,22 +34,12 @@ import {
COMMIT_NOTEABLE_TYPE,
} from '~/notes/constants';
+// Private finders
const findEventByAction = (action) => () => events.find((event) => event.action === action);
const findEventByActionAndTargetType = (action, targetType) => () =>
events.find((event) => event.action === action && event.target?.type === targetType);
const findEventByActionAndIssueType = (action, issueType) => () =>
events.find((event) => event.action === action && event.target.issue_type === issueType);
-
-export const eventApproved = findEventByAction(EVENT_TYPE_APPROVED);
-
-export const eventExpired = findEventByAction(EVENT_TYPE_EXPIRED);
-
-export const eventJoined = findEventByAction(EVENT_TYPE_JOINED);
-
-export const eventLeft = findEventByAction(EVENT_TYPE_LEFT);
-
-export const eventMerged = findEventByAction(EVENT_TYPE_MERGED);
-
const findPushEvent = ({
isNew = false,
isRemoved = false,
@@ -62,6 +54,45 @@ const findPushEvent = ({
ref.type === refType &&
commit.count === commitCount,
);
+const findEventByActionAndNoteableType = (action, noteableType) => () =>
+ events.find((event) => event.action === action && event.noteable?.type === noteableType);
+const findCommentedSnippet = (resourceParentType) => () =>
+ events.find(
+ (event) =>
+ event.action === EVENT_TYPE_COMMENTED &&
+ event.noteable?.type === SNIPPET_NOTEABLE_TYPE &&
+ event.resource_parent?.type === resourceParentType,
+ );
+const findUpdatedEvent = (targetType) =>
+ findEventByActionAndTargetType(EVENT_TYPE_UPDATED, targetType);
+const findDestroyedEvent = (targetType) =>
+ findEventByActionAndTargetType(EVENT_TYPE_DESTROYED, targetType);
+
+// Finders that are used by EE
+export const findCreatedEvent = (targetType) =>
+ findEventByActionAndTargetType(EVENT_TYPE_CREATED, targetType);
+export const findWorkItemCreatedEvent = (issueType) =>
+ findEventByActionAndIssueType(EVENT_TYPE_CREATED, issueType);
+export const findClosedEvent = (targetType) =>
+ findEventByActionAndTargetType(EVENT_TYPE_CREATED, targetType);
+export const findWorkItemClosedEvent = (issueType) =>
+ findEventByActionAndIssueType(EVENT_TYPE_CLOSED, issueType);
+export const findReopenedEvent = (targetType) =>
+ findEventByActionAndTargetType(EVENT_TYPE_REOPENED, targetType);
+export const findWorkItemReopenedEvent = (issueType) =>
+ findEventByActionAndIssueType(EVENT_TYPE_REOPENED, issueType);
+export const findCommentedEvent = (noteableType) =>
+ findEventByActionAndNoteableType(EVENT_TYPE_COMMENTED, noteableType);
+
+export const eventApproved = findEventByAction(EVENT_TYPE_APPROVED);
+
+export const eventExpired = findEventByAction(EVENT_TYPE_EXPIRED);
+
+export const eventJoined = findEventByAction(EVENT_TYPE_JOINED);
+
+export const eventLeft = findEventByAction(EVENT_TYPE_LEFT);
+
+export const eventMerged = findEventByAction(EVENT_TYPE_MERGED);
export const eventPushedNewBranch = findPushEvent({ isNew: true });
export const eventPushedNewTag = findPushEvent({ isNew: true, refType: PUSH_EVENT_REF_TYPE_TAG });
@@ -77,13 +108,7 @@ export const eventBulkPushedBranch = findPushEvent({ commitCount: 5 });
export const eventPrivate = () => ({ ...events[0], action: EVENT_TYPE_PRIVATE });
export const eventCreated = findEventByAction(EVENT_TYPE_CREATED);
-
-export const findCreatedEvent = (targetType) =>
- findEventByActionAndTargetType(EVENT_TYPE_CREATED, targetType);
-export const findWorkItemCreatedEvent = (issueType) =>
- findEventByActionAndIssueType(EVENT_TYPE_CREATED, issueType);
-
-export const eventProjectCreated = findCreatedEvent(undefined);
+export const eventProjectCreated = findCreatedEvent(null);
export const eventMilestoneCreated = findCreatedEvent(TARGET_TYPE_MILESTONE);
export const eventIssueCreated = findCreatedEvent(TARGET_TYPE_ISSUE);
export const eventMergeRequestCreated = findCreatedEvent(TARGET_TYPE_MERGE_REQUEST);
@@ -93,12 +118,6 @@ export const eventTaskCreated = findWorkItemCreatedEvent(WORK_ITEM_ISSUE_TYPE_TA
export const eventIncidentCreated = findWorkItemCreatedEvent(WORK_ITEM_ISSUE_TYPE_INCIDENT);
export const eventClosed = findEventByAction(EVENT_TYPE_CLOSED);
-
-export const findClosedEvent = (targetType) =>
- findEventByActionAndTargetType(EVENT_TYPE_CREATED, targetType);
-export const findWorkItemClosedEvent = (issueType) =>
- findEventByActionAndIssueType(EVENT_TYPE_CLOSED, issueType);
-
export const eventMilestoneClosed = findClosedEvent(TARGET_TYPE_MILESTONE);
export const eventIssueClosed = findClosedEvent(TARGET_TYPE_ISSUE);
export const eventMergeRequestClosed = findClosedEvent(TARGET_TYPE_MERGE_REQUEST);
@@ -108,12 +127,6 @@ export const eventTaskClosed = findWorkItemClosedEvent(WORK_ITEM_ISSUE_TYPE_TASK
export const eventIncidentClosed = findWorkItemClosedEvent(WORK_ITEM_ISSUE_TYPE_INCIDENT);
export const eventReopened = findEventByAction(EVENT_TYPE_REOPENED);
-
-export const findReopenedEvent = (targetType) =>
- findEventByActionAndTargetType(EVENT_TYPE_REOPENED, targetType);
-export const findWorkItemReopenedEvent = (issueType) =>
- findEventByActionAndIssueType(EVENT_TYPE_REOPENED, issueType);
-
export const eventMilestoneReopened = findReopenedEvent(TARGET_TYPE_MILESTONE);
export const eventMergeRequestReopened = findReopenedEvent(TARGET_TYPE_MERGE_REQUEST);
export const eventWikiPageReopened = findReopenedEvent(TARGET_TYPE_WIKI);
@@ -123,19 +136,6 @@ export const eventTaskReopened = findWorkItemReopenedEvent(WORK_ITEM_ISSUE_TYPE_
export const eventIncidentReopened = findWorkItemReopenedEvent(WORK_ITEM_ISSUE_TYPE_INCIDENT);
export const eventCommented = findEventByAction(EVENT_TYPE_COMMENTED);
-
-const findEventByActionAndNoteableType = (action, noteableType) => () =>
- events.find((event) => event.action === action && event.noteable?.type === noteableType);
-export const findCommentedEvent = (noteableType) =>
- findEventByActionAndNoteableType(EVENT_TYPE_COMMENTED, noteableType);
-export const findCommentedSnippet = (resourceParentType) => () =>
- events.find(
- (event) =>
- event.action === EVENT_TYPE_COMMENTED &&
- event.noteable?.type === SNIPPET_NOTEABLE_TYPE &&
- event.resource_parent?.type === resourceParentType,
- );
-
export const eventCommentedIssue = findCommentedEvent(ISSUE_NOTEABLE_TYPE);
export const eventCommentedMergeRequest = findCommentedEvent(MERGE_REQUEST_NOTEABLE_TYPE);
export const eventCommentedSnippet = findCommentedEvent(SNIPPET_NOTEABLE_TYPE);
@@ -153,3 +153,12 @@ export const eventCommentedCommit = () => ({
first_line_in_markdown: '\u003cp\u003eMy title 9\u003c/p\u003e',
},
});
+
+export const eventUpdated = findEventByAction(EVENT_TYPE_UPDATED);
+export const eventDesignUpdated = findUpdatedEvent(TARGET_TYPE_DESIGN);
+export const eventWikiPageUpdated = findUpdatedEvent(TARGET_TYPE_WIKI);
+
+export const eventDestroyed = findEventByAction(EVENT_TYPE_DESTROYED);
+export const eventDesignDestroyed = findDestroyedEvent(TARGET_TYPE_DESIGN);
+export const eventWikiPageDestroyed = findDestroyedEvent(TARGET_TYPE_WIKI);
+export const eventMilestoneDestroyed = findDestroyedEvent(TARGET_TYPE_MILESTONE);
diff --git a/spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap b/spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap
index 5cfb4702be7..8b76a627c1e 100644
--- a/spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap
+++ b/spec/frontend/contributors/component/__snapshots__/contributors_spec.js.snap
@@ -3,7 +3,7 @@
exports[`Contributors charts should render charts and a RefSelector when loading completed and there is chart data 1`] = `
<div>
<div
- class="gl-border-b gl-border-gray-100 gl-mb-6 gl-bg-gray-10 gl-p-5"
+ class="gl-bg-gray-10 gl-border-b gl-border-gray-100 gl-mb-6 gl-p-5"
>
<div
class="gl-display-flex"
@@ -20,26 +20,19 @@ exports[`Contributors charts should render charts and a RefSelector when loading
value="main"
/>
</div>
-
<a
class="btn btn-default btn-md gl-button"
data-testid="history-button"
href="some/path"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
History
-
</span>
</a>
</div>
</div>
-
<div
data-testid="contributors-charts"
>
@@ -48,11 +41,9 @@ exports[`Contributors charts should render charts and a RefSelector when loading
>
Commits to main
</h4>
-
<span>
Excluding merge commits. Limited to 6,000 commits.
</span>
-
<glareachart-stub
annotations=""
class="gl-mb-5"
@@ -70,27 +61,22 @@ exports[`Contributors charts should render charts and a RefSelector when loading
thresholds=""
width="auto"
/>
-
<div
class="row"
>
<div
- class="col-lg-6 col-12 gl-my-5"
+ class="col-12 col-lg-6 gl-my-5"
>
<h4
class="gl-mb-2 gl-mt-0"
>
John
</h4>
-
<p
class="gl-mb-3"
>
-
- 2 commits (jawnnypoo@gmail.com)
-
+ 2 commits (jawnnypoo@gmail.com)
</p>
-
<glareachart-stub
annotations=""
data="[object Object]"
diff --git a/spec/frontend/custom_emoji/components/__snapshots__/list_spec.js.snap b/spec/frontend/custom_emoji/components/__snapshots__/list_spec.js.snap
index 4e87d4d8192..c69547deb1c 100644
--- a/spec/frontend/custom_emoji/components/__snapshots__/list_spec.js.snap
+++ b/spec/frontend/custom_emoji/components/__snapshots__/list_spec.js.snap
@@ -3,14 +3,11 @@
exports[`Custom emoji settings list component renders table of custom emoji 1`] = `
<div>
<div
- class="tabs gl-tabs"
+ class="gl-tabs tabs"
>
- <!---->
- <div
- class=""
- >
+ <div>
<ul
- class="nav gl-tabs-nav"
+ class="gl-tabs-nav nav"
role="tablist"
>
<div
@@ -23,22 +20,12 @@ exports[`Custom emoji settings list component renders table of custom emoji 1`]
href="/new"
to="/new"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- New custom emoji
-
+ New custom emoji
</span>
</a>
-
- <!---->
-
- <!---->
</div>
<div
class="gl-actions-tabs-end"
@@ -50,30 +37,19 @@ exports[`Custom emoji settings list component renders table of custom emoji 1`]
href="/new"
to="/new"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
-
- New custom emoji
-
+ New custom emoji
</span>
</a>
-
- <!---->
-
- <!---->
</div>
</ul>
</div>
<div
- class="tab-content gl-pt-0 gl-tab-content"
+ class="gl-pt-0 gl-tab-content tab-content"
>
<transition-stub
- css="true"
enteractiveclass=""
enterclass=""
entertoclass="show"
@@ -89,14 +65,12 @@ exports[`Custom emoji settings list component renders table of custom emoji 1`]
role="tabpanel"
style="display: none;"
>
-
<table
aria-busy=""
aria-colcount="4"
- class="table b-table gl-table gl-table-layout-fixed"
+ class="b-table gl-table gl-table-layout-fixed table"
role="table"
>
- <!---->
<colgroup>
<col
style="width: 70px;"
@@ -110,12 +84,9 @@ exports[`Custom emoji settings list component renders table of custom emoji 1`]
/>
</colgroup>
<thead
- class=""
role="rowgroup"
>
- <!---->
<tr
- class=""
role="row"
>
<th
@@ -162,9 +133,7 @@ exports[`Custom emoji settings list component renders table of custom emoji 1`]
<tbody
role="rowgroup"
>
- <!---->
<tr
- class=""
role="row"
>
<td
@@ -180,7 +149,7 @@ exports[`Custom emoji settings list component renders table of custom emoji 1`]
</td>
<td
aria-colindex="2"
- class="gl-vertical-align-middle! gl-font-monospace"
+ class="gl-font-monospace gl-vertical-align-middle!"
role="cell"
>
<strong
@@ -194,26 +163,17 @@ exports[`Custom emoji settings list component renders table of custom emoji 1`]
class="gl-vertical-align-middle!"
role="cell"
>
-
- created-at
-
+ created-at
</td>
<td
aria-colindex="4"
- class=""
role="cell"
/>
</tr>
- <!---->
- <!---->
</tbody>
- <!---->
</table>
-
- <!---->
</div>
</transition-stub>
- <!---->
</div>
</div>
</div>
diff --git a/spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap b/spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap
index 560533891c9..8560b80ac9c 100644
--- a/spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap
+++ b/spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap
@@ -2,17 +2,16 @@
exports[`Design management design presentation component currentCommentForm is equal to current annotation position when isAnnotating is true 1`] = `
<div
- class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
+ class="gl-h-full gl-p-5 gl-relative gl-w-full overflow-auto"
>
<div
- class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
+ class="gl-align-items-center gl-display-flex gl-h-full gl-relative gl-w-full"
>
<design-image-stub
image="test.jpg"
name="test"
scale="1"
/>
-
<design-overlay-stub
currentcommentform="[object Object]"
dimensions="[object Object]"
@@ -25,17 +24,16 @@ exports[`Design management design presentation component currentCommentForm is e
exports[`Design management design presentation component currentCommentForm is null when isAnnotating is false 1`] = `
<div
- class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
+ class="gl-h-full gl-p-5 gl-relative gl-w-full overflow-auto"
>
<div
- class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
+ class="gl-align-items-center gl-display-flex gl-h-full gl-relative gl-w-full"
>
<design-image-stub
image="test.jpg"
name="test"
scale="1"
/>
-
<design-overlay-stub
dimensions="[object Object]"
notes=""
@@ -47,17 +45,16 @@ exports[`Design management design presentation component currentCommentForm is n
exports[`Design management design presentation component currentCommentForm is null when isAnnotating is true but annotation position is falsey 1`] = `
<div
- class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
+ class="gl-h-full gl-p-5 gl-relative gl-w-full overflow-auto"
>
<div
- class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
+ class="gl-align-items-center gl-display-flex gl-h-full gl-relative gl-w-full"
>
<design-image-stub
image="test.jpg"
name="test"
scale="1"
/>
-
<design-overlay-stub
dimensions="[object Object]"
notes=""
@@ -69,31 +66,26 @@ exports[`Design management design presentation component currentCommentForm is n
exports[`Design management design presentation component renders empty state when no image provided 1`] = `
<div
- class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
+ class="gl-h-full gl-p-5 gl-relative gl-w-full overflow-auto"
>
<div
- class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
- >
- <!---->
-
- <!---->
- </div>
+ class="gl-align-items-center gl-display-flex gl-h-full gl-relative gl-w-full"
+ />
</div>
`;
exports[`Design management design presentation component renders image and overlay when image provided 1`] = `
<div
- class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
+ class="gl-h-full gl-p-5 gl-relative gl-w-full overflow-auto"
>
<div
- class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
+ class="gl-align-items-center gl-display-flex gl-h-full gl-relative gl-w-full"
>
<design-image-stub
image="test.jpg"
name="test"
scale="1"
/>
-
<design-overlay-stub
dimensions="[object Object]"
notes=""
diff --git a/spec/frontend/design_management/components/__snapshots__/image_spec.js.snap b/spec/frontend/design_management/components/__snapshots__/image_spec.js.snap
index 1f4e579f075..573ad5f872f 100644
--- a/spec/frontend/design_management/components/__snapshots__/image_spec.js.snap
+++ b/spec/frontend/design_management/components/__snapshots__/image_spec.js.snap
@@ -4,11 +4,9 @@ exports[`Design management large image component renders SVG with proper height
<div
class="gl-mx-auto gl-my-auto js-design-image"
>
- <!---->
-
<img
alt="test"
- class="mh-100 img-fluid"
+ class="img-fluid mh-100"
src="mockImage.svg"
/>
</div>
@@ -18,11 +16,9 @@ exports[`Design management large image component renders image 1`] = `
<div
class="gl-mx-auto gl-my-auto js-design-image"
>
- <!---->
-
<img
alt="test"
- class="mh-100 img-fluid"
+ class="img-fluid mh-100"
src="test.jpg"
/>
</div>
@@ -33,12 +29,10 @@ exports[`Design management large image component renders loading state 1`] = `
class="gl-mx-auto gl-my-auto js-design-image"
isloading="true"
>
- <!---->
-
<img
alt=""
- class="mh-100 img-fluid"
- src=""
+ class="img-fluid mh-100"
+ src="null"
/>
</div>
`;
@@ -55,8 +49,6 @@ exports[`Design management large image component sets correct classes and styles
<div
class="gl-mx-auto gl-my-auto js-design-image"
>
- <!---->
-
<img
alt="test"
class="mh-100"
@@ -70,8 +62,6 @@ exports[`Design management large image component zoom sets image style when zoom
<div
class="gl-mx-auto gl-my-auto js-design-image"
>
- <!---->
-
<img
alt="test"
class="mh-100"
diff --git a/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_signed_out_spec.js.snap b/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_signed_out_spec.js.snap
index ab37cb90bd3..8bc9bce7e80 100644
--- a/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_signed_out_spec.js.snap
+++ b/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_signed_out_spec.js.snap
@@ -4,19 +4,19 @@ exports[`DesignNoteSignedOut renders message containing register and sign-in lin
<div
class="disabled-comment text-center"
>
- Please
+ Please
<gl-link-stub
href="/users/sign_up?redirect_to_referer=yes"
>
register
</gl-link-stub>
- or
+ or
<gl-link-stub
href="/users/sign_in?redirect_to_referer=yes"
>
sign in
</gl-link-stub>
- to reply.
+ to reply.
</div>
`;
@@ -24,18 +24,18 @@ exports[`DesignNoteSignedOut renders message containing register and sign-in lin
<div
class="disabled-comment text-center"
>
- Please
+ Please
<gl-link-stub
href="/users/sign_up?redirect_to_referer=yes"
>
register
</gl-link-stub>
- or
+ or
<gl-link-stub
href="/users/sign_in?redirect_to_referer=yes"
>
sign in
</gl-link-stub>
- to start a new discussion.
+ to start a new discussion.
</div>
`;
diff --git a/spec/frontend/design_management/components/design_notes/__snapshots__/design_reply_form_spec.js.snap b/spec/frontend/design_management/components/design_notes/__snapshots__/design_reply_form_spec.js.snap
index 4dc8eaea174..206187c3530 100644
--- a/spec/frontend/design_management/components/design_notes/__snapshots__/design_reply_form_spec.js.snap
+++ b/spec/frontend/design_management/components/design_notes/__snapshots__/design_reply_form_spec.js.snap
@@ -1,17 +1,33 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Design reply form component renders button text as "Comment" when creating a comment 1`] = `
-"<button data-track-action=\\"click_button\\" data-qa-selector=\\"save_comment_button\\" type=\\"submit\\" disabled=\\"disabled\\" class=\\"btn gl-mr-3 gl-w-auto! btn-confirm btn-md disabled gl-button\\">
- <!---->
- <!----> <span class=\\"gl-button-text\\">
- Comment
- </span></button>"
+<button
+ class="btn btn-confirm btn-md disabled gl-button gl-mr-3 gl-w-auto!"
+ data-qa-selector="save_comment_button"
+ data-track-action="click_button"
+ disabled=""
+ type="submit"
+>
+ <span
+ class="gl-button-text"
+ >
+ Comment
+ </span>
+</button>
`;
exports[`Design reply form component renders button text as "Save comment" when creating a comment 1`] = `
-"<button data-track-action=\\"click_button\\" data-qa-selector=\\"save_comment_button\\" type=\\"submit\\" disabled=\\"disabled\\" class=\\"btn gl-mr-3 gl-w-auto! btn-confirm btn-md disabled gl-button\\">
- <!---->
- <!----> <span class=\\"gl-button-text\\">
- Save comment
- </span></button>"
+<button
+ class="btn btn-confirm btn-md disabled gl-button gl-mr-3 gl-w-auto!"
+ data-qa-selector="save_comment_button"
+ data-track-action="click_button"
+ disabled=""
+ type="submit"
+>
+ <span
+ class="gl-button-text"
+ >
+ Save comment
+ </span>
+</button>
`;
diff --git a/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap b/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
index 0bbb44bb517..53359b02b4c 100644
--- a/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
+++ b/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
@@ -9,36 +9,27 @@ exports[`Design management list item component when item appears in view after i
`;
exports[`Design management list item component with notes renders item with multiple comments 1`] = `
-<router-link-stub
- ariacurrentvalue="page"
- class="card gl-cursor-pointer text-plain js-design-list-item design-list-item gl-mb-0"
- event="click"
- tag="a"
- to="[object Object]"
+<a
+ class="card design-list-item gl-cursor-pointer gl-mb-0 js-design-list-item text-plain"
>
<div
- class="card-body gl-p-0 gl-display-flex gl-align-items-center gl-justify-content-center gl-overflow-hidden gl-relative gl-rounded-top-base"
+ class="card-body gl-align-items-center gl-display-flex gl-justify-content-center gl-overflow-hidden gl-p-0 gl-relative gl-rounded-top-base"
>
- <!---->
-
<gl-intersection-observer-stub
class="gl-flex-grow-1"
>
- <!---->
-
<img
alt="test"
- class="gl-display-block gl-mx-auto gl-max-w-full gl-max-h-full gl-w-auto design-img"
+ class="design-img gl-display-block gl-max-h-full gl-max-w-full gl-mx-auto gl-w-auto"
data-qa-filename="test"
data-qa-selector="design_image"
data-testid="design-img-1"
- src=""
+ src="null"
/>
</gl-intersection-observer-stub>
</div>
-
<div
- class="card-footer gl-display-flex gl-w-full gl-bg-white gl-py-3 gl-px-4"
+ class="card-footer gl-bg-white gl-display-flex gl-px-4 gl-py-3 gl-w-full"
>
<div
class="gl-display-flex gl-flex-direction-column str-truncated-100"
@@ -51,12 +42,10 @@ exports[`Design management list item component with notes renders item with mult
>
test
</span>
-
<span
class="str-truncated-100"
>
-
- Updated
+ Updated
<timeago-stub
cssclass=""
datetimeformat="DATE_WITH_TIME_FORMAT"
@@ -65,60 +54,47 @@ exports[`Design management list item component with notes renders item with mult
/>
</span>
</div>
-
<div
- class="gl-ml-auto gl-display-flex gl-align-items-center gl-text-gray-500"
+ class="gl-align-items-center gl-display-flex gl-ml-auto gl-text-gray-500"
>
<gl-icon-stub
class="gl-ml-2"
name="comments"
size="16"
/>
-
<span
aria-label="2 comments"
class="gl-ml-2"
>
-
2
-
</span>
</div>
</div>
-</router-link-stub>
+</a>
`;
exports[`Design management list item component with notes renders item with single comment 1`] = `
-<router-link-stub
- ariacurrentvalue="page"
- class="card gl-cursor-pointer text-plain js-design-list-item design-list-item gl-mb-0"
- event="click"
- tag="a"
- to="[object Object]"
+<a
+ class="card design-list-item gl-cursor-pointer gl-mb-0 js-design-list-item text-plain"
>
<div
- class="card-body gl-p-0 gl-display-flex gl-align-items-center gl-justify-content-center gl-overflow-hidden gl-relative gl-rounded-top-base"
+ class="card-body gl-align-items-center gl-display-flex gl-justify-content-center gl-overflow-hidden gl-p-0 gl-relative gl-rounded-top-base"
>
- <!---->
-
<gl-intersection-observer-stub
class="gl-flex-grow-1"
>
- <!---->
-
<img
alt="test"
- class="gl-display-block gl-mx-auto gl-max-w-full gl-max-h-full gl-w-auto design-img"
+ class="design-img gl-display-block gl-max-h-full gl-max-w-full gl-mx-auto gl-w-auto"
data-qa-filename="test"
data-qa-selector="design_image"
data-testid="design-img-1"
- src=""
+ src="null"
/>
</gl-intersection-observer-stub>
</div>
-
<div
- class="card-footer gl-display-flex gl-w-full gl-bg-white gl-py-3 gl-px-4"
+ class="card-footer gl-bg-white gl-display-flex gl-px-4 gl-py-3 gl-w-full"
>
<div
class="gl-display-flex gl-flex-direction-column str-truncated-100"
@@ -131,12 +107,10 @@ exports[`Design management list item component with notes renders item with sing
>
test
</span>
-
<span
class="str-truncated-100"
>
-
- Updated
+ Updated
<timeago-stub
cssclass=""
datetimeformat="DATE_WITH_TIME_FORMAT"
@@ -145,25 +119,21 @@ exports[`Design management list item component with notes renders item with sing
/>
</span>
</div>
-
<div
- class="gl-ml-auto gl-display-flex gl-align-items-center gl-text-gray-500"
+ class="gl-align-items-center gl-display-flex gl-ml-auto gl-text-gray-500"
>
<gl-icon-stub
class="gl-ml-2"
name="comments"
size="16"
/>
-
<span
aria-label="1 comment"
class="gl-ml-2"
>
-
1
-
</span>
</div>
</div>
-</router-link-stub>
+</a>
`;
diff --git a/spec/frontend/design_management/components/list/item_spec.js b/spec/frontend/design_management/components/list/item_spec.js
index 4a0ad5a045b..14e8a5579ba 100644
--- a/spec/frontend/design_management/components/list/item_spec.js
+++ b/spec/frontend/design_management/components/list/item_spec.js
@@ -1,5 +1,5 @@
import { GlIcon, GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { shallowMount, RouterLinkStub } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueRouter from 'vue-router';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
@@ -49,7 +49,7 @@ describe('Design management list item component', () => {
imageLoading,
};
},
- stubs: ['router-link'],
+ stubs: { RouterLink: RouterLinkStub },
}),
);
}
diff --git a/spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap
index 3c4aa0f4d3c..cf8aac22f67 100644
--- a/spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap
@@ -2,14 +2,14 @@
exports[`Design management toolbar component renders design and updated data 1`] = `
<header
- class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-bg-white gl-py-4 gl-pl-4 js-design-header"
+ class="gl-align-items-center gl-bg-white gl-display-flex gl-justify-content-space-between gl-pl-4 gl-py-4 js-design-header"
>
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
>
<a
aria-label="Go back to designs"
- class="gl-mr-5 gl-display-flex gl-align-items-center gl-justify-content-center text-plain"
+ class="gl-align-items-center gl-display-flex gl-justify-content-center gl-mr-5 text-plain"
data-testid="close-design"
>
<gl-icon-stub
@@ -17,16 +17,14 @@ exports[`Design management toolbar component renders design and updated data 1`]
size="16"
/>
</a>
-
<div
- class="gl-overflow-hidden gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex gl-overflow-hidden"
>
<h2
- class="gl-m-0 str-truncated-100 gl-font-base"
+ class="gl-font-base gl-m-0 str-truncated-100"
>
test.jpg
</h2>
-
<small
class="gl-text-gray-500"
>
@@ -34,12 +32,10 @@ exports[`Design management toolbar component renders design and updated data 1`]
</small>
</div>
</div>
-
<design-navigation-stub
- class="gl-ml-auto gl-flex-shrink-0"
- id="1"
+ class="gl-flex-shrink-0 gl-ml-auto"
+ id="reference-0"
/>
-
<gl-button-stub
aria-label="Download design"
buttontextclasses=""
@@ -50,7 +46,6 @@ exports[`Design management toolbar component renders design and updated data 1`]
title="Download design"
variant="default"
/>
-
<delete-button-stub
buttoncategory="secondary"
buttonclass=""
diff --git a/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap b/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
index 191bcc2d484..e6a74c49d50 100644
--- a/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
+++ b/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
@@ -12,15 +12,12 @@ exports[`Design management upload button component renders inverted upload desig
title="Adding a design with the same filename replaces the file in a new version."
variant="confirm"
>
-
Upload designs
-
</gl-button-stub>
-
<input
accept="image/*"
class="gl-display-none"
- multiple="multiple"
+ multiple=""
name="design_file"
type="file"
/>
@@ -37,15 +34,12 @@ exports[`Design management upload button component renders upload design button
title="Adding a design with the same filename replaces the file in a new version."
variant="confirm"
>
-
Upload designs
-
</gl-button-stub>
-
<input
accept="image/*"
class="gl-display-none"
- multiple="multiple"
+ multiple=""
name="design_file"
type="file"
/>
diff --git a/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
index f0615f61059..224e35e9f5e 100644
--- a/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
@@ -2,86 +2,70 @@
exports[`Design management design index page renders design index 1`] = `
<div
- class="design-detail js-design-detail fixed-top gl-w-full gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
+ class="design-detail fixed-top gl-display-flex gl-flex-direction-column gl-justify-content-center gl-lg-flex-direction-row gl-w-full js-design-detail"
>
<div
- class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
+ class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-overflow-hidden gl-relative"
>
<div
iid="1"
project-path="project-path"
/>
-
- <!---->
-
<design-presentation-stub
discussions="[object Object],[object Object]"
image="test.jpg"
imagename="test.jpg"
scale="1"
/>
-
<div
- class="design-scaler-wrapper gl-absolute gl-mb-6 gl-display-flex gl-justify-content-center gl-align-items-center"
+ class="design-scaler-wrapper gl-absolute gl-align-items-center gl-display-flex gl-justify-content-center gl-mb-6"
>
<design-scaler-stub
maxscale="2"
/>
</div>
</div>
-
<div
- class="image-notes gl-pt-0"
+ class="gl-pt-0 image-notes"
>
<div
- class="gl-py-4 gl-mb-4 gl-display-flex gl-justify-content-space-between gl-align-items-center gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
+ class="gl-align-items-center gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-display-flex gl-justify-content-space-between gl-mb-4 gl-py-4"
>
<span>
To Do
</span>
-
<design-todo-button-stub
design="[object Object]"
/>
</div>
-
<h2
class="gl-font-weight-bold gl-mt-0"
>
-
- My precious issue
-
+ My precious issue
</h2>
-
<a
- class="gl-text-gray-400 gl-text-decoration-none gl-mb-6 gl-display-block"
+ class="gl-display-block gl-mb-6 gl-text-decoration-none gl-text-gray-400"
href="full-issue-url"
>
ull-issue-path
</a>
-
<description-form-stub
design="[object Object]"
designvariables="[object Object]"
markdownpreviewpath="/project-path/preview_markdown?target_type=Issue"
/>
-
<participants-stub
class="gl-mb-4"
lazy="true"
numberoflessparticipants="8"
participants="[object Object]"
/>
-
- <!---->
-
<design-note-signed-out-stub
class="gl-mb-4"
isadddiscussion="true"
registerpath=""
signinpath=""
/>
-
<design-discussion-stub
data-testid="unresolved-discussion"
designid="gid::/gitlab/Design/1"
@@ -92,7 +76,6 @@ exports[`Design management design index page renders design index 1`] = `
registerpath=""
signinpath=""
/>
-
<gl-accordion-stub
class="gl-mb-5"
headerlevel="3"
@@ -113,23 +96,21 @@ exports[`Design management design index page renders design index 1`] = `
/>
</gl-accordion-item-stub>
</gl-accordion-stub>
-
</div>
</div>
`;
exports[`Design management design index page with error GlAlert is rendered in correct position with correct content 1`] = `
<div
- class="design-detail js-design-detail fixed-top gl-w-full gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
+ class="design-detail fixed-top gl-display-flex gl-flex-direction-column gl-justify-content-center gl-lg-flex-direction-row gl-w-full js-design-detail"
>
<div
- class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
+ class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-overflow-hidden gl-relative"
>
<div
iid="1"
project-path="project-path"
/>
-
<div
class="gl-p-5"
>
@@ -144,82 +125,64 @@ exports[`Design management design index page with error GlAlert is rendered in c
title=""
variant="danger"
>
-
woops
-
</gl-alert-stub>
</div>
-
<design-presentation-stub
discussions=""
image="test.jpg"
imagename="test.jpg"
scale="1"
/>
-
<div
- class="design-scaler-wrapper gl-absolute gl-mb-6 gl-display-flex gl-justify-content-center gl-align-items-center"
+ class="design-scaler-wrapper gl-absolute gl-align-items-center gl-display-flex gl-justify-content-center gl-mb-6"
>
<design-scaler-stub
maxscale="2"
/>
</div>
</div>
-
<div
- class="image-notes gl-pt-0"
+ class="gl-pt-0 image-notes"
>
<div
- class="gl-py-4 gl-mb-4 gl-display-flex gl-justify-content-space-between gl-align-items-center gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
+ class="gl-align-items-center gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-display-flex gl-justify-content-space-between gl-mb-4 gl-py-4"
>
<span>
To Do
</span>
-
<design-todo-button-stub
design="[object Object]"
/>
</div>
-
<h2
class="gl-font-weight-bold gl-mt-0"
>
-
- My precious issue
-
+ My precious issue
</h2>
-
<a
- class="gl-text-gray-400 gl-text-decoration-none gl-mb-6 gl-display-block"
+ class="gl-display-block gl-mb-6 gl-text-decoration-none gl-text-gray-400"
href="full-issue-url"
>
ull-issue-path
</a>
-
<description-form-stub
design="[object Object]"
designvariables="[object Object]"
markdownpreviewpath="/project-path/preview_markdown?target_type=Issue"
/>
-
<participants-stub
class="gl-mb-4"
lazy="true"
numberoflessparticipants="8"
participants="[object Object]"
/>
-
- <!---->
-
<design-note-signed-out-stub
class="gl-mb-4"
isadddiscussion="true"
registerpath=""
signinpath=""
/>
-
- <!---->
-
</div>
</div>
`;
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index c1f0966f9c6..e10aad6214c 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -11,7 +11,7 @@ import CommitWidget from '~/diffs/components/commit_widget.vue';
import CompareVersions from '~/diffs/components/compare_versions.vue';
import DiffFile from '~/diffs/components/diff_file.vue';
import NoChanges from '~/diffs/components/no_changes.vue';
-import findingsDrawer from '~/diffs/components/shared/findings_drawer.vue';
+import FindingsDrawer from '~/diffs/components/shared/findings_drawer.vue';
import DiffsFileTree from '~/diffs/components/diffs_file_tree.vue';
import CollapsedFilesWarning from '~/diffs/components/collapsed_files_warning.vue';
@@ -251,6 +251,11 @@ describe('diffs/components/app', () => {
await nextTick();
expect(store.state.diffs.currentDiffFileId).toBe('ABC');
});
+
+ it('renders findings-drawer', () => {
+ createComponent();
+ expect(wrapper.findComponent(FindingsDrawer).exists()).toBe(true);
+ });
});
it('marks current diff file based on currently highlighted row', async () => {
@@ -755,20 +760,4 @@ describe('diffs/components/app', () => {
);
});
});
-
- describe('findings-drawer', () => {
- it('does not render findings-drawer when codeQualityInlineDrawer flag is off', () => {
- createComponent();
- expect(wrapper.findComponent(findingsDrawer).exists()).toBe(false);
- });
-
- it('does render findings-drawer when codeQualityInlineDrawer flag is on', () => {
- createComponent({}, () => {}, {
- glFeatures: {
- codeQualityInlineDrawer: true,
- },
- });
- expect(wrapper.findComponent(findingsDrawer).exists()).toBe(true);
- });
- });
});
diff --git a/spec/frontend/diffs/components/diff_inline_findings_item_spec.js b/spec/frontend/diffs/components/diff_inline_findings_item_spec.js
index 72d96d3435f..cda3273d51e 100644
--- a/spec/frontend/diffs/components/diff_inline_findings_item_spec.js
+++ b/spec/frontend/diffs/components/diff_inline_findings_item_spec.js
@@ -1,4 +1,4 @@
-import { GlIcon, GlLink } from '@gitlab/ui';
+import { GlIcon } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DiffInlineFindingsItem from '~/diffs/components/diff_inline_findings_item.vue';
import { SEVERITY_CLASSES, SEVERITY_ICONS } from '~/ci/reports/codequality_report/constants';
@@ -8,19 +8,13 @@ let wrapper;
const [codeQualityFinding] = multipleFindingsArrCodeQualityScale;
const findIcon = () => wrapper.findComponent(GlIcon);
-const findButton = () => wrapper.findComponent(GlLink);
const findDescriptionPlainText = () => wrapper.findByTestId('description-plain-text');
-const findDescriptionLinkSection = () => wrapper.findByTestId('description-button-section');
describe('DiffCodeQuality', () => {
- const createWrapper = ({ glFeatures = {}, link = true } = {}) => {
+ const createWrapper = () => {
return shallowMountExtended(DiffInlineFindingsItem, {
propsData: {
finding: codeQualityFinding,
- link,
- },
- provide: {
- glFeatures,
},
});
};
@@ -36,42 +30,9 @@ describe('DiffCodeQuality', () => {
});
});
- describe('with codeQualityInlineDrawer flag false', () => {
- it('should render severity + description in plain text', () => {
- wrapper = createWrapper({
- glFeatures: {
- codeQualityInlineDrawer: false,
- },
- });
- expect(findDescriptionPlainText().text()).toContain(codeQualityFinding.severity);
- expect(findDescriptionPlainText().text()).toContain(codeQualityFinding.description);
- });
- });
-
- describe('with codeQualityInlineDrawer flag true', () => {
- const [{ description, severity }] = multipleFindingsArrCodeQualityScale;
- const renderedText = `${severity} - ${description}`;
- it('when link prop is true, should render gl-link', () => {
- wrapper = createWrapper({
- glFeatures: {
- codeQualityInlineDrawer: true,
- },
- });
-
- expect(findButton().exists()).toBe(true);
- expect(findButton().text()).toBe(renderedText);
- });
-
- it('when link prop is false, should not render gl-link', () => {
- wrapper = createWrapper({
- glFeatures: {
- codeQualityInlineDrawer: true,
- },
- link: false,
- });
-
- expect(findButton().exists()).toBe(false);
- expect(findDescriptionLinkSection().text()).toBe(renderedText);
- });
+ it('should render severity + description in plain text', () => {
+ wrapper = createWrapper();
+ expect(findDescriptionPlainText().text()).toContain(codeQualityFinding.severity);
+ expect(findDescriptionPlainText().text()).toContain(codeQualityFinding.description);
});
});
diff --git a/spec/frontend/diffs/components/diff_inline_findings_spec.js b/spec/frontend/diffs/components/diff_inline_findings_spec.js
index 65b2abe7dd5..f654a2e2d4f 100644
--- a/spec/frontend/diffs/components/diff_inline_findings_spec.js
+++ b/spec/frontend/diffs/components/diff_inline_findings_spec.js
@@ -2,7 +2,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DiffInlineFindings from '~/diffs/components/diff_inline_findings.vue';
import DiffInlineFindingsItem from '~/diffs/components/diff_inline_findings_item.vue';
import { NEW_CODE_QUALITY_FINDINGS } from '~/diffs/i18n';
-import { multipleCodeQualityNoSast } from '../mock_data/inline_findings';
+import { multipleFindingsArrCodeQualityScale } from '../mock_data/inline_findings';
let wrapper;
const heading = () => wrapper.findByTestId('diff-inline-findings-heading');
@@ -13,7 +13,7 @@ describe('DiffInlineFindings', () => {
return shallowMountExtended(DiffInlineFindings, {
propsData: {
title: NEW_CODE_QUALITY_FINDINGS,
- findings: multipleCodeQualityNoSast.codeQuality,
+ findings: multipleFindingsArrCodeQualityScale,
},
});
};
@@ -25,7 +25,7 @@ describe('DiffInlineFindings', () => {
it('renders the correct number of DiffInlineFindingsItem components with correct props', () => {
wrapper = createWrapper();
- expect(diffInlineFindingsItems()).toHaveLength(multipleCodeQualityNoSast.codeQuality.length);
+ expect(diffInlineFindingsItems()).toHaveLength(multipleFindingsArrCodeQualityScale.length);
expect(diffInlineFindingsItems().wrappers[0].props('finding')).toEqual(
wrapper.props('findings')[0],
);
diff --git a/spec/frontend/diffs/components/diff_row_spec.js b/spec/frontend/diffs/components/diff_row_spec.js
index 8a67d7b152c..30510958704 100644
--- a/spec/frontend/diffs/components/diff_row_spec.js
+++ b/spec/frontend/diffs/components/diff_row_spec.js
@@ -71,7 +71,8 @@ describe('DiffRow', () => {
const hits = coverageFileData[file]?.[line];
if (hits) {
return { text: `Test coverage: ${hits} hits`, class: 'coverage' };
- } else if (hits === 0) {
+ }
+ if (hits === 0) {
return { text: 'No test coverage', class: 'no-coverage' };
}
diff --git a/spec/frontend/diffs/components/inline_findings_spec.js b/spec/frontend/diffs/components/inline_findings_spec.js
index 71cc6ae49fd..102287a23b6 100644
--- a/spec/frontend/diffs/components/inline_findings_spec.js
+++ b/spec/frontend/diffs/components/inline_findings_spec.js
@@ -2,7 +2,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
import InlineFindings from '~/diffs/components/inline_findings.vue';
import DiffInlineFindings from '~/diffs/components/diff_inline_findings.vue';
import { NEW_CODE_QUALITY_FINDINGS } from '~/diffs/i18n';
-import { threeCodeQualityFindingsRaw } from '../mock_data/inline_findings';
+import { threeCodeQualityFindings } from '../mock_data/inline_findings';
let wrapper;
@@ -12,7 +12,7 @@ describe('InlineFindings', () => {
const createWrapper = () => {
return mountExtended(InlineFindings, {
propsData: {
- codeQuality: threeCodeQualityFindingsRaw,
+ codeQuality: threeCodeQualityFindings,
},
});
};
@@ -28,6 +28,6 @@ describe('InlineFindings', () => {
it('renders diff inline findings component with correct props for codequality array', () => {
wrapper = createWrapper();
expect(diffInlineFindings().props('title')).toBe(NEW_CODE_QUALITY_FINDINGS);
- expect(diffInlineFindings().props('findings')).toBe(threeCodeQualityFindingsRaw);
+ expect(diffInlineFindings().props('findings')).toBe(threeCodeQualityFindings);
});
});
diff --git a/spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap b/spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap
index 51bd8f380ee..afa2a7d9678 100644
--- a/spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap
+++ b/spec/frontend/diffs/components/shared/__snapshots__/findings_drawer_spec.js.snap
@@ -9,15 +9,13 @@ exports[`FindingsDrawer matches the snapshot 1`] = `
zindex="252"
>
<h2
- class="gl-font-size-h2 gl-mt-0 gl-mb-0"
+ class="gl-font-size-h2 gl-mb-0 gl-mt-0"
data-testid="findings-drawer-heading"
>
-
- Unused method argument - \`c\`. If it's necessary, use \`_\` or \`_c\` as an argument name to indicate that it won't be used.
-
+ Unused method argument - \`c\`. If it's necessary, use \`_\` or \`_c\` as an argument name to indicate that it won't be used.
</h2>
<ul
- class="gl-list-style-none gl-border-b-initial gl-mb-0 gl-pb-0!"
+ class="gl-border-b-initial gl-list-style-none gl-mb-0 gl-pb-0!"
>
<li
class="gl-mb-4"
@@ -28,19 +26,14 @@ exports[`FindingsDrawer matches the snapshot 1`] = `
>
Severity:
</span>
-
<gl-icon-stub
- class="inline-findings-severity-icon gl-text-orange-300"
+ class="gl-text-orange-300 inline-findings-severity-icon"
data-testid="findings-drawer-severity-icon"
name="severity-low"
size="12"
/>
-
-
- minor
-
+ minor
</li>
-
<li
class="gl-mb-4"
data-testid="findings-drawer-engine"
@@ -50,11 +43,8 @@ exports[`FindingsDrawer matches the snapshot 1`] = `
>
Engine:
</span>
-
- testengine name
-
+ testengine name
</li>
-
<li
class="gl-mb-4"
data-testid="findings-drawer-category"
@@ -64,21 +54,17 @@ exports[`FindingsDrawer matches the snapshot 1`] = `
>
Category:
</span>
-
- testcategory 1
-
+ testcategory 1
</li>
-
<li
class="gl-mb-4"
data-testid="findings-drawer-other-locations"
>
<span
- class="gl-font-weight-bold gl-mb-3 gl-display-block"
+ class="gl-display-block gl-font-weight-bold gl-mb-3"
>
Other locations:
</span>
-
<ul
class="gl-pl-6"
>
@@ -115,7 +101,6 @@ exports[`FindingsDrawer matches the snapshot 1`] = `
</ul>
</li>
</ul>
-
<span
class="drawer-body gl-display-block gl-px-3 gl-py-0!"
data-testid="findings-drawer-body"
diff --git a/spec/frontend/diffs/mock_data/inline_findings.js b/spec/frontend/diffs/mock_data/inline_findings.js
index 85fb48b86d5..ae1ae909238 100644
--- a/spec/frontend/diffs/mock_data/inline_findings.js
+++ b/spec/frontend/diffs/mock_data/inline_findings.js
@@ -4,6 +4,7 @@ export const multipleFindingsArrCodeQualityScale = [
description: 'mocked minor Issue',
line: 2,
scale: 'codeQuality',
+ text: 'mocked minor Issue',
},
{
severity: 'major',
@@ -43,6 +44,7 @@ export const multipleFindingsArrSastScale = [
description: 'mocked low Issue',
line: 2,
scale: 'sast',
+ text: 'mocked low Issue',
},
{
severity: 'medium',
@@ -76,48 +78,6 @@ export const multipleFindingsArrSastScale = [
},
];
-export const multipleCodeQualityNoSast = {
- codeQuality: multipleFindingsArrCodeQualityScale,
- sast: [],
-};
-
-export const multipleSastNoCodeQuality = {
- codeQuality: [],
- sast: multipleFindingsArrSastScale,
-};
-
-export const fiveCodeQualityFindings = {
- filePath: 'index.js',
- codequality: multipleFindingsArrCodeQualityScale.slice(0, 5),
-};
-
-export const threeCodeQualityFindings = {
- filePath: 'index.js',
- codequality: multipleFindingsArrCodeQualityScale.slice(0, 3),
-};
-export const threeCodeQualityFindingsRaw = [multipleFindingsArrCodeQualityScale.slice(0, 3)];
-
-export const singularCodeQualityFinding = {
- filePath: 'index.js',
- codequality: [multipleFindingsArrCodeQualityScale[0]],
-};
-
-export const singularFindingSast = {
- filePath: 'index.js',
- sast: [multipleFindingsArrSastScale[0]],
-};
-
-export const threeSastFindings = {
- filePath: 'index.js',
- sast: multipleFindingsArrSastScale.slice(0, 3),
-};
-
-export const oneCodeQualityTwoSastFindings = {
- filePath: 'index.js',
- sast: multipleFindingsArrSastScale.slice(0, 2),
- codequality: [multipleFindingsArrCodeQualityScale[0]],
-};
-
export const diffCodeQuality = {
diffFile: { file_hash: '123' },
diffLines: [
@@ -151,3 +111,19 @@ export const diffCodeQuality = {
},
],
};
+
+export const singularCodeQualityFinding = [multipleFindingsArrCodeQualityScale[0]];
+export const singularSastFinding = [multipleFindingsArrSastScale[0]];
+export const twoSastFindings = multipleFindingsArrSastScale.slice(0, 2);
+export const fiveCodeQualityFindings = multipleFindingsArrCodeQualityScale.slice(0, 5);
+export const threeCodeQualityFindings = multipleFindingsArrCodeQualityScale.slice(0, 3);
+
+export const filePath = 'testPath';
+export const scale = 'exampleScale';
+
+export const dropdownIcon = {
+ id: 'noise.rb-2',
+ key: 'mockedkey',
+ name: 'severity-medium',
+ class: 'gl-text-orange-400',
+};
diff --git a/spec/frontend/drawio/drawio_editor_spec.js b/spec/frontend/drawio/drawio_editor_spec.js
index 5a77b9d4689..0b863edc13b 100644
--- a/spec/frontend/drawio/drawio_editor_spec.js
+++ b/spec/frontend/drawio/drawio_editor_spec.js
@@ -5,6 +5,7 @@ import {
DRAWIO_IFRAME_TIMEOUT,
DIAGRAM_MAX_SIZE,
} from '~/drawio/constants';
+import { base64EncodeUnicode } from '~/lib/utils/text_utility';
import { createAlert, VARIANT_SUCCESS } from '~/alert';
const DRAWIO_EDITOR_URL =
@@ -19,8 +20,8 @@ describe('drawio/drawio_editor', () => {
let editorFacade;
let drawioIFrameReceivedMessages;
const diagramURL = `${window.location.origin}/uploads/diagram.drawio.svg`;
- const testSvg = '<svg></svg>';
- const testEncodedSvg = `data:image/svg+xml;base64,${btoa(testSvg)}`;
+ const testSvg = '<svg>😀</svg>';
+ const testEncodedSvg = `data:image/svg+xml;base64,${base64EncodeUnicode(testSvg)}`;
const filename = 'diagram.drawio.svg';
const findDrawioIframe = () => document.getElementById(DRAWIO_FRAME_ID);
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/include.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/include.yml
index 909911debf1..3076105ffde 100644
--- a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/include.yml
+++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/include.yml
@@ -33,6 +33,17 @@ include:
rules:
- exists:
- file.md
+ - local: builds.yml
+ rules:
+ - if: $INCLUDE_BUILDS == "true"
+ changes:
+ - 'test.yml'
+ - local: builds.yml
+ rules:
+ - changes:
+ paths:
+ - 'test.yml'
+ compare_to: 'master'
# valid trigger:include
trigger:include accepts project and file properties:
diff --git a/spec/frontend/emoji/index_spec.js b/spec/frontend/emoji/index_spec.js
index 1b948cce73a..1a12bd303f1 100644
--- a/spec/frontend/emoji/index_spec.js
+++ b/spec/frontend/emoji/index_spec.js
@@ -134,9 +134,11 @@ describe('emoji', () => {
const emojiKey = 'bomb';
const markup = glEmojiTag(emojiKey);
- expect(trimText(markup)).toMatchInlineSnapshot(
- `"<gl-emoji data-name=\\"bomb\\"></gl-emoji>"`,
- );
+ expect(trimText(markup)).toMatchInlineSnapshot(`
+ <gl-emoji
+ data-name="bomb"
+ />
+ `);
});
it('bomb emoji with sprite fallback readiness', () => {
@@ -144,9 +146,12 @@ describe('emoji', () => {
const markup = glEmojiTag(emojiKey, {
sprite: true,
});
- expect(trimText(markup)).toMatchInlineSnapshot(
- `"<gl-emoji data-fallback-sprite-class=\\"emoji-bomb\\" data-name=\\"bomb\\"></gl-emoji>"`,
- );
+ expect(trimText(markup)).toMatchInlineSnapshot(`
+ <gl-emoji
+ data-fallback-sprite-class="emoji-bomb"
+ data-name="bomb"
+ />
+ `);
});
});
diff --git a/spec/frontend/environments/edit_environment_spec.js b/spec/frontend/environments/edit_environment_spec.js
index b55bbb34c65..9989c946800 100644
--- a/spec/frontend/environments/edit_environment_spec.js
+++ b/spec/frontend/environments/edit_environment_spec.js
@@ -7,7 +7,6 @@ import EditEnvironment from '~/environments/components/edit_environment.vue';
import { createAlert } from '~/alert';
import { visitUrl } from '~/lib/utils/url_utility';
import getEnvironment from '~/environments/graphql/queries/environment.query.graphql';
-import getEnvironmentWithFluxResource from '~/environments/graphql/queries/environment_with_flux_resource.query.graphql';
import updateEnvironment from '~/environments/graphql/mutations/update_environment.mutation.graphql';
import { __ } from '~/locale';
import createMockApollo from '../__helpers__/mock_apollo_helper';
@@ -44,9 +43,6 @@ describe('~/environments/components/edit.vue', () => {
let wrapper;
const getEnvironmentQuery = jest.fn().mockResolvedValue({ data: resolvedEnvironment });
- const getEnvironmentWithFluxResourceQuery = jest
- .fn()
- .mockResolvedValue({ data: resolvedEnvironment });
const updateEnvironmentSuccess = jest
.fn()
@@ -60,24 +56,17 @@ describe('~/environments/components/edit.vue', () => {
const mocks = [
[getEnvironment, getEnvironmentQuery],
- [getEnvironmentWithFluxResource, getEnvironmentWithFluxResourceQuery],
[updateEnvironment, mutationHandler],
];
return createMockApollo(mocks);
};
- const createWrapperWithApollo = async ({
- mutationHandler = updateEnvironmentSuccess,
- fluxResourceForEnvironment = false,
- } = {}) => {
+ const createWrapperWithApollo = async ({ mutationHandler = updateEnvironmentSuccess } = {}) => {
wrapper = mountExtended(EditEnvironment, {
propsData: { environment: {} },
provide: {
...provide,
- glFeatures: {
- fluxResourceForEnvironment,
- },
},
apolloProvider: createMockApolloProvider(mutationHandler),
});
@@ -170,11 +159,4 @@ describe('~/environments/components/edit.vue', () => {
});
});
});
-
- describe('when `fluxResourceForEnvironment` is enabled', () => {
- it('calls the `getEnvironmentWithFluxResource` query', () => {
- createWrapperWithApollo({ fluxResourceForEnvironment: true });
- expect(getEnvironmentWithFluxResourceQuery).toHaveBeenCalled();
- });
- });
});
diff --git a/spec/frontend/environments/environment_form_spec.js b/spec/frontend/environments/environment_form_spec.js
index 1b80b596db7..22dd7437d82 100644
--- a/spec/frontend/environments/environment_form_spec.js
+++ b/spec/frontend/environments/environment_form_spec.js
@@ -53,11 +53,7 @@ describe('~/environments/components/form.vue', () => {
},
});
- const createWrapperWithApollo = ({
- propsData = {},
- fluxResourceForEnvironment = false,
- queryResult = null,
- } = {}) => {
+ const createWrapperWithApollo = ({ propsData = {}, queryResult = null } = {}) => {
Vue.use(VueApollo);
const requestHandlers = [
@@ -83,9 +79,6 @@ describe('~/environments/components/form.vue', () => {
return mountExtended(EnvironmentForm, {
provide: {
...PROVIDE,
- glFeatures: {
- fluxResourceForEnvironment,
- },
},
propsData: {
...DEFAULT_PROPS,
@@ -422,39 +415,30 @@ describe('~/environments/components/form.vue', () => {
});
describe('flux resource selector', () => {
- it("doesn't render if `fluxResourceForEnvironment` feature flag is disabled", () => {
+ beforeEach(() => {
wrapper = createWrapperWithApollo();
+ });
+
+ it("doesn't render flux resource selector by default", () => {
expect(findFluxResourceSelector().exists()).toBe(false);
});
- describe('when `fluxResourceForEnvironment` feature flag is enabled', () => {
- beforeEach(() => {
- wrapper = createWrapperWithApollo({
- fluxResourceForEnvironment: true,
- });
+ describe('when the agent was selected', () => {
+ beforeEach(async () => {
+ await selectAgent();
});
- it("doesn't render flux resource selector by default", () => {
+ it("doesn't render flux resource selector", () => {
expect(findFluxResourceSelector().exists()).toBe(false);
});
- describe('when the agent was selected', () => {
- beforeEach(async () => {
- await selectAgent();
- });
-
- it("doesn't render flux resource selector", () => {
- expect(findFluxResourceSelector().exists()).toBe(false);
- });
-
- it('renders the flux resource selector when the namespace is selected', async () => {
- await findNamespaceSelector().vm.$emit('select', 'agent');
+ it('renders the flux resource selector when the namespace is selected', async () => {
+ await findNamespaceSelector().vm.$emit('select', 'agent');
- expect(findFluxResourceSelector().props()).toEqual({
- namespace: 'agent',
- fluxResourcePath: '',
- configuration,
- });
+ expect(findFluxResourceSelector().props()).toEqual({
+ namespace: 'agent',
+ fluxResourcePath: '',
+ configuration,
});
});
});
@@ -522,7 +506,6 @@ describe('~/environments/components/form.vue', () => {
beforeEach(() => {
wrapper = createWrapperWithApollo({
propsData: { environment: environmentWithAgentAndNamespace },
- fluxResourceForEnvironment: true,
});
});
diff --git a/spec/frontend/environments/new_environment_item_spec.js b/spec/frontend/environments/new_environment_item_spec.js
index bfcc4f4ebb6..7ee31bf2c62 100644
--- a/spec/frontend/environments/new_environment_item_spec.js
+++ b/spec/frontend/environments/new_environment_item_spec.js
@@ -13,7 +13,6 @@ import Deployment from '~/environments/components/deployment.vue';
import DeployBoardWrapper from '~/environments/components/deploy_board_wrapper.vue';
import KubernetesOverview from '~/environments/components/kubernetes_overview.vue';
import getEnvironmentClusterAgent from '~/environments/graphql/queries/environment_cluster_agent.query.graphql';
-import getEnvironmentClusterAgentWithFluxResource from '~/environments/graphql/queries/environment_cluster_agent_with_flux_resource.query.graphql';
import {
resolvedEnvironment,
rolloutStatus,
@@ -27,7 +26,6 @@ Vue.use(VueApollo);
describe('~/environments/components/new_environment_item.vue', () => {
let wrapper;
let queryResponseHandler;
- let queryWithFluxResourceResponseHandler;
const projectPath = '/1';
@@ -39,27 +37,14 @@ describe('~/environments/components/new_environment_item.vue', () => {
environment: {
id: '1',
kubernetesNamespace: 'default',
+ fluxResourcePath: fluxResourcePathMock,
clusterAgent,
},
},
},
};
queryResponseHandler = jest.fn().mockResolvedValue(response);
- queryWithFluxResourceResponseHandler = jest.fn().mockResolvedValue({
- data: {
- project: {
- id: response.data.project.id,
- environment: {
- ...response.data.project.environment,
- fluxResourcePath: fluxResourcePathMock,
- },
- },
- },
- });
- return createMockApollo([
- [getEnvironmentClusterAgent, queryResponseHandler],
- [getEnvironmentClusterAgentWithFluxResource, queryWithFluxResourceResponseHandler],
- ]);
+ return createMockApollo([[getEnvironmentClusterAgent, queryResponseHandler]]);
};
const createWrapper = ({ propsData = {}, provideData = {}, apolloProvider } = {}) =>
@@ -554,25 +539,6 @@ describe('~/environments/components/new_environment_item.vue', () => {
});
});
- it('should request agent data with Flux resource when `fluxResourceForEnvironment` feature flag is enabled', async () => {
- wrapper = createWrapper({
- propsData: { environment: resolvedEnvironment },
- provideData: {
- glFeatures: {
- fluxResourceForEnvironment: true,
- },
- },
- apolloProvider: createApolloProvider(agent),
- });
-
- await expandCollapsedSection();
-
- expect(queryWithFluxResourceResponseHandler).toHaveBeenCalledWith({
- environmentName: resolvedEnvironment.name,
- projectFullPath: projectPath,
- });
- });
-
it('should render if the environment has an agent associated', async () => {
wrapper = createWrapper({
propsData: { environment: resolvedEnvironment },
@@ -588,14 +554,9 @@ describe('~/environments/components/new_environment_item.vue', () => {
});
});
- it('should render with the namespace if `fluxResourceForEnvironment` feature flag is enabled and the environment has an agent associated', async () => {
+ it('should render with the namespace if the environment has an agent associated', async () => {
wrapper = createWrapper({
propsData: { environment: resolvedEnvironment },
- provideData: {
- glFeatures: {
- fluxResourceForEnvironment: true,
- },
- },
apolloProvider: createApolloProvider(agent),
});
diff --git a/spec/frontend/feature_flags/components/new_environments_dropdown_spec.js b/spec/frontend/feature_flags/components/new_environments_dropdown_spec.js
index 6156addd63f..b503a6f829e 100644
--- a/spec/frontend/feature_flags/components/new_environments_dropdown_spec.js
+++ b/spec/frontend/feature_flags/components/new_environments_dropdown_spec.js
@@ -1,7 +1,6 @@
-import { GlLoadingIcon, GlSearchBoxByType, GlDropdownItem } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlCollapsibleListbox } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import NewEnvironmentsDropdown from '~/feature_flags/components/new_environments_dropdown.vue';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
@@ -13,87 +12,78 @@ describe('New Environments Dropdown', () => {
let wrapper;
let axiosMock;
- beforeEach(() => {
+ const createWrapper = (axiosResult = []) => {
axiosMock = new MockAdapter(axios);
- wrapper = shallowMount(NewEnvironmentsDropdown, {
+ axiosMock.onGet(TEST_HOST).reply(HTTP_STATUS_OK, axiosResult);
+
+ wrapper = shallowMountExtended(NewEnvironmentsDropdown, {
provide: { environmentsEndpoint: TEST_HOST },
+ stubs: {
+ GlCollapsibleListbox,
+ },
});
- });
+ };
+
+ const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
+ const findCreateEnvironmentButton = () => wrapper.findByTestId('add-environment-button');
afterEach(() => {
axiosMock.restore();
});
describe('before results', () => {
+ beforeEach(() => {
+ createWrapper();
+ });
+
it('should show a loading icon', () => {
- axiosMock.onGet(TEST_HOST).reply(() => {
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- });
- wrapper.findComponent(GlSearchBoxByType).vm.$emit('focus');
- return axios.waitForAll();
+ expect(findListbox().props('searching')).toBe(true);
});
it('should not show any dropdown items', () => {
- axiosMock.onGet(TEST_HOST).reply(() => {
- expect(wrapper.findAllComponents(GlDropdownItem)).toHaveLength(0);
- });
- wrapper.findComponent(GlSearchBoxByType).vm.$emit('focus');
- return axios.waitForAll();
+ expect(findListbox().props('items')).toEqual([]);
});
});
describe('with empty results', () => {
- let item;
beforeEach(async () => {
- axiosMock.onGet(TEST_HOST).reply(HTTP_STATUS_OK, []);
- wrapper.findComponent(GlSearchBoxByType).vm.$emit('focus');
- wrapper.findComponent(GlSearchBoxByType).vm.$emit('input', TEST_SEARCH);
+ createWrapper();
+ findListbox().vm.$emit('search', TEST_SEARCH);
await axios.waitForAll();
- await nextTick();
- item = wrapper.findComponent(GlDropdownItem);
});
it('should display a Create item label', () => {
- expect(item.text()).toBe('Create production');
- });
-
- it('should display that no matching items are found', () => {
- expect(wrapper.findComponent({ ref: 'noResults' }).exists()).toBe(true);
+ expect(findCreateEnvironmentButton().text()).toBe(`Create ${TEST_SEARCH}`);
});
it('should emit a new scope when selected', () => {
- item.vm.$emit('click');
+ findCreateEnvironmentButton().vm.$emit('click');
expect(wrapper.emitted('add')).toEqual([[TEST_SEARCH]]);
});
});
describe('with results', () => {
- let items;
- beforeEach(() => {
- axiosMock.onGet(TEST_HOST).reply(HTTP_STATUS_OK, ['prod', 'production']);
- wrapper.findComponent(GlSearchBoxByType).vm.$emit('focus');
- wrapper.findComponent(GlSearchBoxByType).vm.$emit('input', 'prod');
- return axios.waitForAll().then(() => {
- items = wrapper.findAllComponents(GlDropdownItem);
- });
+ beforeEach(async () => {
+ createWrapper(['prod', 'production']);
+ findListbox().vm.$emit('search', TEST_SEARCH);
+ await axios.waitForAll();
});
- it('should display one item per result', () => {
- expect(items).toHaveLength(2);
+ it('should populate results properly', () => {
+ expect(findListbox().props().items).toHaveLength(2);
});
- it('should emit an add if an item is clicked', () => {
- items.at(0).vm.$emit('click');
+ it('should emit an add on selection', () => {
+ findListbox().vm.$emit('select', ['prod']);
expect(wrapper.emitted('add')).toEqual([['prod']]);
});
- it('should not display a create label', () => {
- items = items.filter((i) => i.text().startsWith('Create'));
- expect(items).toHaveLength(0);
- });
-
it('should not display a message about no results', () => {
expect(wrapper.findComponent({ ref: 'noResults' }).exists()).toBe(false);
});
+
+ it('should not display a footer with the create button', () => {
+ expect(findCreateEnvironmentButton().exists()).toBe(false);
+ });
});
});
diff --git a/spec/frontend/feature_flags/components/strategy_spec.js b/spec/frontend/feature_flags/components/strategy_spec.js
index ca6e338ac6c..90021829212 100644
--- a/spec/frontend/feature_flags/components/strategy_spec.js
+++ b/spec/frontend/feature_flags/components/strategy_spec.js
@@ -1,11 +1,14 @@
import { GlAlert, GlFormSelect, GlLink, GlToken, GlButton } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import { last } from 'lodash';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import Api from '~/api';
+import axios from '~/lib/utils/axios_utils';
import NewEnvironmentsDropdown from '~/feature_flags/components/new_environments_dropdown.vue';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import Strategy from '~/feature_flags/components/strategy.vue';
import StrategyParameters from '~/feature_flags/components/strategy_parameters.vue';
import {
@@ -22,16 +25,18 @@ import { userList } from '../mock_data';
jest.mock('~/api');
+const TEST_HOST = '/test';
const provide = {
strategyTypeDocsPagePath: 'link-to-strategy-docs',
environmentsScopeDocsPath: 'link-scope-docs',
- environmentsEndpoint: '',
+ environmentsEndpoint: TEST_HOST,
};
Vue.use(Vuex);
describe('Feature flags strategy', () => {
let wrapper;
+ let axiosMock;
const findStrategyParameters = () => wrapper.findComponent(StrategyParameters);
const findDocsLinks = () => wrapper.findAllComponents(GlLink);
@@ -45,6 +50,8 @@ describe('Feature flags strategy', () => {
provide,
},
) => {
+ axiosMock = new MockAdapter(axios);
+ axiosMock.onGet(TEST_HOST).reply(HTTP_STATUS_OK, []);
wrapper = mount(Strategy, { store: createStore({ projectId: '1' }), ...opts });
};
@@ -52,6 +59,10 @@ describe('Feature flags strategy', () => {
Api.searchFeatureFlagUserLists.mockResolvedValue({ data: [userList] });
});
+ afterEach(() => {
+ axiosMock.restore();
+ });
+
describe('helper links', () => {
const propsData = { strategy: {}, index: 0, userLists: [userList] };
factory({ propsData, provide });
diff --git a/spec/frontend/filtered_search/filtered_search_manager_spec.js b/spec/frontend/filtered_search/filtered_search_manager_spec.js
index 8c16ff100eb..c55099d89d9 100644
--- a/spec/frontend/filtered_search/filtered_search_manager_spec.js
+++ b/spec/frontend/filtered_search/filtered_search_manager_spec.js
@@ -24,7 +24,7 @@ describe('Filtered Search Manager', () => {
let manager;
let tokensContainer;
const page = 'issues';
- const placeholder = 'Search or filter results...';
+ const placeholder = 'Search or filter results…';
function dispatchBackspaceEvent(element, eventType) {
const event = new Event(eventType);
diff --git a/spec/frontend/fixtures/abuse_reports.rb b/spec/frontend/fixtures/abuse_reports.rb
deleted file mode 100644
index ad0fb9be8dc..00000000000
--- a/spec/frontend/fixtures/abuse_reports.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Admin::AbuseReportsController, '(JavaScript fixtures)', type: :controller do
- include JavaScriptFixturesHelpers
- include AdminModeHelper
-
- let(:admin) { create(:admin) }
- let!(:abuse_report) { create(:abuse_report) }
- let!(:abuse_report_with_short_message) { create(:abuse_report, message: 'SHORT MESSAGE') }
- let!(:abuse_report_with_long_message) { create(:abuse_report, message: "LONG MESSAGE\n" * 50) }
-
- render_views
-
- before do
- stub_feature_flags(abuse_reports_list: false)
-
- sign_in(admin)
- enable_admin_mode!(admin)
- end
-
- it 'abuse_reports/abuse_reports_list.html' do
- get :index
-
- expect(response).to be_successful
- end
-end
diff --git a/spec/frontend/fixtures/issues.rb b/spec/frontend/fixtures/issues.rb
index 73594ddf686..9e6fcea2d17 100644
--- a/spec/frontend/fixtures/issues.rb
+++ b/spec/frontend/fixtures/issues.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::IssuesController, '(JavaScript fixtures)', :with_license, type: :controller do
include JavaScriptFixturesHelpers
- let(:user) { create(:user, feed_token: 'feedtoken:coldfeed') }
+ let(:user) { create(:user, :no_super_sidebar, feed_token: 'feedtoken:coldfeed') }
let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'issues-project') }
diff --git a/spec/frontend/fixtures/jobs.rb b/spec/frontend/fixtures/jobs.rb
index 6c0b87c5a68..1502999ac9c 100644
--- a/spec/frontend/fixtures/jobs.rb
+++ b/spec/frontend/fixtures/jobs.rb
@@ -89,28 +89,28 @@ RSpec.describe 'Jobs (JavaScript fixtures)' do
end
end
- it_behaves_like 'graphql queries', 'jobs/components/table/graphql/queries', 'get_jobs.query.graphql' do
+ it_behaves_like 'graphql queries', 'ci/jobs_page/graphql/queries', 'get_jobs.query.graphql' do
let(:variables) { { fullPath: 'frontend-fixtures/builds-project' } }
let(:success_path) { %w[project jobs] }
end
- it_behaves_like 'graphql queries', 'jobs/components/table/graphql/queries', 'get_jobs_count.query.graphql', true do
+ it_behaves_like 'graphql queries', 'ci/jobs_page/graphql/queries', 'get_jobs_count.query.graphql', true do
let(:variables) { { fullPath: 'frontend-fixtures/builds-project' } }
let(:success_path) { %w[project jobs] }
end
- it_behaves_like 'graphql queries', 'pages/admin/jobs/components/table/graphql/queries', 'get_all_jobs.query.graphql' do
+ it_behaves_like 'graphql queries', 'ci/admin/jobs_table/graphql/queries', 'get_all_jobs.query.graphql' do
let(:user) { create(:admin) }
let(:success_path) { 'jobs' }
end
- it_behaves_like 'graphql queries', 'pages/admin/jobs/components/table/graphql/queries', 'get_cancelable_jobs_count.query.graphql', true do
+ it_behaves_like 'graphql queries', 'ci/admin/jobs_table/graphql/queries', 'get_cancelable_jobs_count.query.graphql', true do
let(:variables) { { statuses: %w[PENDING RUNNING] } }
let(:user) { create(:admin) }
let(:success_path) { %w[cancelable count] }
end
- it_behaves_like 'graphql queries', 'pages/admin/jobs/components/table/graphql/queries', 'get_all_jobs_count.query.graphql', true do
+ it_behaves_like 'graphql queries', 'ci/admin/jobs_table/graphql/queries', 'get_all_jobs_count.query.graphql', true do
let(:user) { create(:admin) }
let(:success_path) { 'jobs' }
end
diff --git a/spec/frontend/fixtures/pipeline_header.rb b/spec/frontend/fixtures/pipeline_header.rb
index 3fdc45b1194..744df18a403 100644
--- a/spec/frontend/fixtures/pipeline_header.rb
+++ b/spec/frontend/fixtures/pipeline_header.rb
@@ -12,7 +12,7 @@ RSpec.describe "GraphQL Pipeline Header", '(JavaScript fixtures)', type: :reques
let_it_be(:user) { project.first_owner }
let_it_be(:commit) { create(:commit, project: project) }
- let(:query_path) { 'pipelines/graphql/queries/get_pipeline_header_data.query.graphql' }
+ let(:query_path) { 'ci/pipeline_details/header/graphql/queries/get_pipeline_header_data.query.graphql' }
context 'with successful pipeline' do
let_it_be(:pipeline) do
diff --git a/spec/frontend/fixtures/pipeline_schedules.rb b/spec/frontend/fixtures/pipeline_schedules.rb
index 7bba7910b87..4c95e7ecd20 100644
--- a/spec/frontend/fixtures/pipeline_schedules.rb
+++ b/spec/frontend/fixtures/pipeline_schedules.rb
@@ -16,35 +16,6 @@ RSpec.describe 'Pipeline schedules (JavaScript fixtures)' do
let!(:pipeline_schedule_variable1) { create(:ci_pipeline_schedule_variable, key: 'foo', value: 'foovalue', pipeline_schedule: pipeline_schedule_populated) }
let!(:pipeline_schedule_variable2) { create(:ci_pipeline_schedule_variable, key: 'bar', value: 'barvalue', pipeline_schedule: pipeline_schedule_populated) }
- describe Projects::PipelineSchedulesController, type: :controller do
- render_views
-
- before do
- sign_in(user)
- stub_feature_flags(pipeline_schedules_vue: false)
- end
-
- it 'pipeline_schedules/edit.html' do
- get :edit, params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: pipeline_schedule.id
- }
-
- expect(response).to be_successful
- end
-
- it 'pipeline_schedules/edit_with_variables.html' do
- get :edit, params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: pipeline_schedule_populated.id
- }
-
- expect(response).to be_successful
- end
- end
-
describe GraphQL::Query, type: :request do
before do
pipeline_schedule.pipelines << build(:ci_pipeline, project: project)
diff --git a/spec/frontend/fixtures/pipelines.rb b/spec/frontend/fixtures/pipelines.rb
index 24a6f6f7de6..151d4a763c0 100644
--- a/spec/frontend/fixtures/pipelines.rb
+++ b/spec/frontend/fixtures/pipelines.rb
@@ -71,7 +71,7 @@ RSpec.describe Projects::PipelinesController, '(JavaScript fixtures)', type: :co
end
let_it_be(:query) do
- get_graphql_query_as_string("pipelines/graphql/queries/#{get_pipeline_actions_query}")
+ get_graphql_query_as_string("ci/pipelines_page/graphql/queries/#{get_pipeline_actions_query}")
end
it "#{fixtures_path}#{get_pipeline_actions_query}.json" do
diff --git a/spec/frontend/fixtures/snippet.rb b/spec/frontend/fixtures/snippet.rb
index 0510746a944..23df89a244c 100644
--- a/spec/frontend/fixtures/snippet.rb
+++ b/spec/frontend/fixtures/snippet.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe SnippetsController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
+ let(:user) { create(:user, :no_super_sidebar) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures', owner: user) }
let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') }
- let(:user) { project.first_owner }
let(:snippet) { create(:personal_snippet, :public, title: 'snippet.md', content: '# snippet', file_name: 'snippet.md', author: user) }
render_views
diff --git a/spec/frontend/groups/components/empty_states/groups_dashboard_empty_state_spec.js b/spec/frontend/groups/components/empty_states/groups_dashboard_empty_state_spec.js
new file mode 100644
index 00000000000..d2afbad802c
--- /dev/null
+++ b/spec/frontend/groups/components/empty_states/groups_dashboard_empty_state_spec.js
@@ -0,0 +1,29 @@
+import { GlEmptyState } from '@gitlab/ui';
+
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import GroupsDashboardEmptyState from '~/groups/components/empty_states/groups_dashboard_empty_state.vue';
+
+let wrapper;
+
+const defaultProvide = {
+ groupsEmptyStateIllustration: '/assets/illustrations/empty-state/empty-groups-md.svg',
+};
+
+const createComponent = () => {
+ wrapper = shallowMountExtended(GroupsDashboardEmptyState, {
+ provide: defaultProvide,
+ });
+};
+
+describe('GroupsDashboardEmptyState', () => {
+ it('renders empty state', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({
+ title: 'A group is a collection of several projects',
+ description:
+ "If you organize your projects under a group, it works like a folder. You can manage your group member's permissions and access to each project in the group.",
+ svgPath: defaultProvide.groupsEmptyStateIllustration,
+ });
+ });
+});
diff --git a/spec/frontend/groups/components/empty_states/groups_explore_empty_state_spec.js b/spec/frontend/groups/components/empty_states/groups_explore_empty_state_spec.js
new file mode 100644
index 00000000000..f4c425902f5
--- /dev/null
+++ b/spec/frontend/groups/components/empty_states/groups_explore_empty_state_spec.js
@@ -0,0 +1,27 @@
+import { GlEmptyState } from '@gitlab/ui';
+
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import GroupsExploreEmptyState from '~/groups/components/empty_states/groups_explore_empty_state.vue';
+
+let wrapper;
+
+const defaultProvide = {
+ groupsEmptyStateIllustration: '/assets/illustrations/empty-state/empty-groups-md.svg',
+};
+
+const createComponent = () => {
+ wrapper = shallowMountExtended(GroupsExploreEmptyState, {
+ provide: defaultProvide,
+ });
+};
+
+describe('GroupsExploreEmptyState', () => {
+ it('renders empty state', () => {
+ createComponent();
+
+ expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({
+ title: 'No public groups',
+ svgPath: defaultProvide.groupsEmptyStateIllustration,
+ });
+ });
+});
diff --git a/spec/frontend/ide/components/file_templates/dropdown_spec.js b/spec/frontend/ide/components/file_templates/dropdown_spec.js
deleted file mode 100644
index 9ccdaf8b916..00000000000
--- a/spec/frontend/ide/components/file_templates/dropdown_spec.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import { GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-import $ from 'jquery';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import Dropdown from '~/ide/components/file_templates/dropdown.vue';
-
-Vue.use(Vuex);
-
-describe('IDE file templates dropdown component', () => {
- let wrapper;
- let element;
- let fetchTemplateTypesMock;
-
- const defaultProps = {
- label: 'label',
- };
-
- const findItemButtons = () => wrapper.findAll('button');
- const findSearch = () => wrapper.find('input[type="search"]');
- const triggerDropdown = () => $(element).trigger('show.bs.dropdown');
-
- const createComponent = ({ props, state } = {}) => {
- fetchTemplateTypesMock = jest.fn();
- const fakeStore = new Vuex.Store({
- modules: {
- fileTemplates: {
- namespaced: true,
- state: {
- templates: [],
- isLoading: false,
- ...state,
- },
- actions: {
- fetchTemplateTypes: fetchTemplateTypesMock,
- },
- },
- },
- });
-
- wrapper = shallowMount(Dropdown, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- store: fakeStore,
- });
-
- ({ element } = wrapper);
- };
-
- it('calls clickItem on click', async () => {
- const itemData = { name: 'test.yml ' };
- createComponent({ props: { data: [itemData] } });
- const item = findItemButtons().at(0);
- item.trigger('click');
-
- await nextTick();
- expect(wrapper.emitted().click[0][0]).toBe(itemData);
- });
-
- it('renders dropdown title', () => {
- const title = 'Test title';
- createComponent({ props: { title } });
-
- expect(wrapper.find('.dropdown-title').text()).toContain(title);
- });
-
- describe('in async mode', () => {
- const defaultAsyncProps = { ...defaultProps, isAsyncData: true };
-
- it('calls `fetchTemplateTypes` on dropdown event', () => {
- createComponent({ props: defaultAsyncProps });
-
- triggerDropdown();
-
- expect(fetchTemplateTypesMock).toHaveBeenCalled();
- });
-
- it('does not call `fetchTemplateTypes` on dropdown event if destroyed', () => {
- createComponent({ props: defaultAsyncProps });
- wrapper.destroy();
-
- triggerDropdown();
-
- expect(fetchTemplateTypesMock).not.toHaveBeenCalled();
- });
-
- it('shows loader when isLoading is true', () => {
- createComponent({ props: defaultAsyncProps, state: { isLoading: true } });
-
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- });
-
- it('renders templates', () => {
- const templates = [{ name: 'file-1' }, { name: 'file-2' }];
- createComponent({
- props: { ...defaultAsyncProps, data: [{ name: 'should-never-appear ' }] },
- state: {
- templates,
- },
- });
- const items = findItemButtons();
-
- expect(items.wrappers.map((x) => x.text())).toEqual(templates.map((x) => x.name));
- });
-
- it('searches template data', async () => {
- const templates = [{ name: 'match 1' }, { name: 'other' }, { name: 'match 2' }];
- const matches = ['match 1', 'match 2'];
- createComponent({
- props: { ...defaultAsyncProps, data: matches, searchable: true },
- state: { templates },
- });
- findSearch().setValue('match');
- await nextTick();
- const items = findItemButtons();
-
- expect(items.length).toBe(matches.length);
- expect(items.wrappers.map((x) => x.text())).toEqual(matches);
- });
-
- it('does not render input when `searchable` is true & `showLoading` is true', () => {
- createComponent({
- props: { ...defaultAsyncProps, searchable: true },
- state: { isLoading: true },
- });
-
- expect(findSearch().exists()).toBe(false);
- });
- });
-
- describe('in sync mode', () => {
- it('renders props data', () => {
- const data = [{ name: 'file-1' }, { name: 'file-2' }];
- createComponent({
- props: { data },
- state: {
- templates: [{ name: 'should-never-appear ' }],
- },
- });
-
- const items = findItemButtons();
-
- expect(items.length).toBe(data.length);
- expect(items.wrappers.map((x) => x.text())).toEqual(data.map((x) => x.name));
- });
-
- it('renders input when `searchable` is true', () => {
- createComponent({ props: { searchable: true } });
-
- expect(findSearch().exists()).toBe(true);
- });
-
- it('searches data', async () => {
- const data = [{ name: 'match 1' }, { name: 'other' }, { name: 'match 2' }];
- const matches = ['match 1', 'match 2'];
- createComponent({ props: { searchable: true, data } });
- findSearch().setValue('match');
- await nextTick();
- const items = findItemButtons();
-
- expect(items.length).toBe(matches.length);
- expect(items.wrappers.map((x) => x.text())).toEqual(matches);
- });
- });
-});
diff --git a/spec/frontend/ide/components/pipelines/__snapshots__/list_spec.js.snap b/spec/frontend/ide/components/pipelines/__snapshots__/list_spec.js.snap
index 069b6927bac..f7b690fb3a4 100644
--- a/spec/frontend/ide/components/pipelines/__snapshots__/list_spec.js.snap
+++ b/spec/frontend/ide/components/pipelines/__snapshots__/list_spec.js.snap
@@ -4,10 +4,8 @@ exports[`IDE pipelines list when loaded renders empty state when no latestPipeli
<div
class="ide-pipeline"
>
- <!---->
-
<div
- class="gl-h-full gl-display-flex gl-flex-direction-column gl-justify-content-center"
+ class="gl-display-flex gl-flex-direction-column gl-h-full gl-justify-content-center"
>
<empty-state-stub />
</div>
diff --git a/spec/frontend/ide/init_gitlab_web_ide_spec.js b/spec/frontend/ide/init_gitlab_web_ide_spec.js
index f8af8459025..efbbd6c7514 100644
--- a/spec/frontend/ide/init_gitlab_web_ide_spec.js
+++ b/spec/frontend/ide/init_gitlab_web_ide_spec.js
@@ -18,6 +18,7 @@ jest.mock('~/lib/utils/csrf', () => ({
const ROOT_ELEMENT_ID = 'ide';
const TEST_NONCE = 'test123nonce';
+const TEST_USERNAME = 'lipsum';
const TEST_PROJECT_PATH = 'group1/project1';
const TEST_BRANCH_NAME = '12345-foo-patch';
const TEST_USER_PREFERENCES_PATH = '/user/preferences';
@@ -69,6 +70,7 @@ describe('ide/init_gitlab_web_ide', () => {
};
beforeEach(() => {
+ gon.current_username = TEST_USERNAME;
process.env.GITLAB_WEB_IDE_PUBLIC_PATH = TEST_GITLAB_WEB_IDE_PUBLIC_PATH;
confirmAction.mockImplementation(
@@ -100,6 +102,7 @@ describe('ide/init_gitlab_web_ide', () => {
mrId: TEST_MR_ID,
mrTargetProject: '',
forkInfo: null,
+ username: gon.current_username,
gitlabUrl: TEST_HOST,
nonce: TEST_NONCE,
httpHeaders: {
diff --git a/spec/frontend/ide/lib/gitlab_web_ide/setup_root_element_spec.js b/spec/frontend/ide/lib/gitlab_web_ide/setup_root_element_spec.js
index 35cf41b31f5..011f2564cec 100644
--- a/spec/frontend/ide/lib/gitlab_web_ide/setup_root_element_spec.js
+++ b/spec/frontend/ide/lib/gitlab_web_ide/setup_root_element_spec.js
@@ -24,8 +24,8 @@ describe('~/ide/lib/gitlab_web_ide/setup_root_element', () => {
expect(result).toBe(findIDERoot());
expect(result).toMatchInlineSnapshot(`
<div
- class="gl--flex-center gl-relative gl-h-full"
- id="ide-test-root"
+ class="gl--flex-center gl-h-full gl-relative"
+ id="reference-0"
/>
`);
});
diff --git a/spec/frontend/import_entities/import_groups/components/import_table_spec.js b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
index dae5671777c..03d0920994c 100644
--- a/spec/frontend/import_entities/import_groups/components/import_table_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
@@ -317,7 +317,7 @@ describe('import table', () => {
});
it('updates page size when selected in Dropdown', async () => {
- const otherOption = findPaginationDropdown().findAll('li p').at(1);
+ const otherOption = findPaginationDropdown().findAll('.gl-new-dropdown-item-content').at(1);
expect(otherOption.text()).toMatchInterpolatedText('50 items per page');
bulkImportSourceGroupsQueryMock.mockResolvedValue({
diff --git a/spec/frontend/incidents/components/incidents_list_spec.js b/spec/frontend/incidents/components/incidents_list_spec.js
index a0710ddb06c..470d63e7c2a 100644
--- a/spec/frontend/incidents/components/incidents_list_spec.js
+++ b/spec/frontend/incidents/components/incidents_list_spec.js
@@ -46,7 +46,7 @@ describe('Incidents List', () => {
const findLoader = () => wrapper.findComponent(GlLoadingIcon);
const findTimeAgo = () => wrapper.findAllComponents(TimeAgoTooltip);
const findAssignees = () => wrapper.findAll('[data-testid="incident-assignees"]');
- const findCreateIncidentBtn = () => wrapper.find('[data-testid="createIncidentBtn"]');
+ const findCreateIncidentBtn = () => wrapper.find('[data-testid="create-incident-button"]');
const findClosedIcon = () => wrapper.findAll("[data-testid='incident-closed']");
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findSeverity = () => wrapper.findAllComponents(SeverityToken);
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
index b5f8f0023f9..f8a7c47e634 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
@@ -2,14 +2,11 @@
exports[`Alert integration settings form should match the default snapshot 1`] = `
<div>
- <!---->
-
<p>
<gl-sprintf-stub
message="Create a GitLab incident for each PagerDuty incident by %{linkStart}configuring a webhook in PagerDuty%{linkEnd}"
/>
</p>
-
<form>
<gl-form-group-stub
class="col-8 col-md-9 gl-p-0"
@@ -17,13 +14,12 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
optionaltext="(optional)"
>
<gl-toggle-stub
- id="active"
+ id="reference-0"
label="Active"
labelposition="top"
value="true"
/>
</gl-form-group-stub>
-
<gl-form-group-stub
class="col-8 col-md-9 gl-p-0"
label="Webhook URL"
@@ -33,7 +29,7 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
>
<gl-form-input-group-stub
data-testid="webhook-url"
- id="url"
+ id="reference-1"
inputclass=""
predefinedoptions="[object Object]"
readonly=""
@@ -48,7 +44,6 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
variant="default"
/>
</gl-form-input-group-stub>
-
<gl-button-stub
buttontextclasses=""
category="primary"
@@ -60,11 +55,8 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
tabindex="0"
variant="default"
>
-
Reset webhook URL
-
</gl-button-stub>
-
<gl-modal-stub
actioncancel="[object Object]"
actionprimary="[object Object]"
@@ -76,9 +68,7 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
title="Reset webhook URL"
titletag="h4"
>
-
Resetting the webhook URL for this project will require updating this integration's settings in PagerDuty.
-
</gl-modal-stub>
</gl-form-group-stub>
</form>
diff --git a/spec/frontend/integrations/index/mock_data.js b/spec/frontend/integrations/index/mock_data.js
index c07b320c0d3..65c1e5643e9 100644
--- a/spec/frontend/integrations/index/mock_data.js
+++ b/spec/frontend/integrations/index/mock_data.js
@@ -1,6 +1,7 @@
export const mockActiveIntegrations = [
{
active: true,
+ configured: true,
title: 'Asana',
description: 'Asana - Teamwork without email',
updated_at: '2021-03-18T00:27:09.634Z',
@@ -10,6 +11,7 @@ export const mockActiveIntegrations = [
},
{
active: true,
+ configured: true,
title: 'Jira',
description: 'Jira issue tracker',
updated_at: '2021-01-29T06:41:25.806Z',
@@ -22,6 +24,7 @@ export const mockActiveIntegrations = [
export const mockInactiveIntegrations = [
{
active: false,
+ configured: false,
title: 'Webex Teams',
description: 'Receive event notifications in Webex Teams',
updated_at: null,
@@ -31,6 +34,7 @@ export const mockInactiveIntegrations = [
},
{
active: false,
+ configured: false,
title: 'YouTrack',
description: 'YouTrack issue tracker',
updated_at: null,
@@ -40,6 +44,7 @@ export const mockInactiveIntegrations = [
},
{
active: false,
+ configured: false,
title: 'Atlassian Bamboo CI',
description: 'A continuous integration and build server',
updated_at: null,
@@ -49,6 +54,7 @@ export const mockInactiveIntegrations = [
},
{
active: false,
+ configured: false,
title: 'Prometheus',
description: 'A monitoring tool for Kubernetes',
updated_at: null,
diff --git a/spec/frontend/invite_members/components/invite_members_modal_spec.js b/spec/frontend/invite_members/components/invite_members_modal_spec.js
index 1a9b0fae52a..526487f6460 100644
--- a/spec/frontend/invite_members/components/invite_members_modal_spec.js
+++ b/spec/frontend/invite_members/components/invite_members_modal_spec.js
@@ -1,4 +1,4 @@
-import { GlLink, GlModal, GlSprintf, GlFormGroup, GlCollapse, GlIcon } from '@gitlab/ui';
+import { GlModal, GlSprintf, GlFormGroup, GlCollapse, GlIcon } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import { stubComponent } from 'helpers/stub_component';
@@ -12,7 +12,6 @@ import ModalConfetti from '~/invite_members/components/confetti.vue';
import MembersTokenSelect from '~/invite_members/components/members_token_select.vue';
import UserLimitNotification from '~/invite_members/components/user_limit_notification.vue';
import {
- INVITE_MEMBERS_FOR_TASK,
MEMBERS_MODAL_CELEBRATE_INTRO,
MEMBERS_MODAL_CELEBRATE_TITLE,
MEMBERS_PLACEHOLDER,
@@ -31,7 +30,6 @@ import {
HTTP_STATUS_CREATED,
HTTP_STATUS_INTERNAL_SERVER_ERROR,
} from '~/lib/utils/http_status';
-import { getParameterValues } from '~/lib/utils/url_utility';
import {
displaySuccessfulInvitationAlert,
reloadOnInvitationSuccess,
@@ -54,10 +52,6 @@ import {
jest.mock('~/invite_members/utils/trigger_successful_invite_alert');
jest.mock('~/experimentation/experiment_tracking');
-jest.mock('~/lib/utils/url_utility', () => ({
- ...jest.requireActual('~/lib/utils/url_utility'),
- getParameterValues: jest.fn(() => []),
-}));
describe('InviteMembersModal', () => {
let wrapper;
@@ -129,7 +123,6 @@ describe('InviteMembersModal', () => {
});
const findModal = () => wrapper.findComponent(GlModal);
- const findBase = () => wrapper.findComponent(InviteModalBase);
const findIntroText = () => wrapper.findByTestId('modal-base-intro-text').text();
const findEmptyInvitesAlert = () => wrapper.findByTestId('empty-invites-alert');
const findMemberErrorAlert = () => wrapper.findByTestId('alert-member-error');
@@ -155,10 +148,6 @@ describe('InviteMembersModal', () => {
findMembersFormGroup().attributes('invalid-feedback');
const membersFormGroupDescription = () => findMembersFormGroup().attributes('description');
const findMembersSelect = () => wrapper.findComponent(MembersTokenSelect);
- const findTasksToBeDone = () => wrapper.findByTestId('invite-members-modal-tasks-to-be-done');
- const findTasks = () => wrapper.findByTestId('invite-members-modal-tasks');
- const findProjectSelect = () => wrapper.findByTestId('invite-members-modal-project-select');
- const findNoProjectsAlert = () => wrapper.findByTestId('invite-members-modal-no-projects-alert');
const findCelebrationEmoji = () => wrapper.findComponent(GlEmoji);
const triggerOpenModal = async ({ mode = 'default', source } = {}) => {
eventHub.$emit('openModal', { mode, source });
@@ -168,131 +157,11 @@ describe('InviteMembersModal', () => {
findMembersSelect().vm.$emit('input', val);
await nextTick();
};
- const triggerTasks = async (val) => {
- findTasks().vm.$emit('input', val);
- await nextTick();
- };
- const triggerAccessLevel = async (val) => {
- findBase().vm.$emit('access-level', val);
- await nextTick();
- };
const removeMembersToken = async (val) => {
findMembersSelect().vm.$emit('token-remove', val);
await nextTick();
};
- describe('rendering the tasks to be done', () => {
- const setupComponent = async (props = {}, urlParameter = ['invite_members_for_task']) => {
- getParameterValues.mockImplementation(() => urlParameter);
- createComponent(props);
-
- await triggerAccessLevel(30);
- };
-
- const setupComponentWithTasks = async (...args) => {
- await setupComponent(...args);
- await triggerTasks(['ci', 'code']);
- };
-
- afterAll(() => {
- getParameterValues.mockImplementation(() => []);
- });
-
- it('renders the tasks to be done', async () => {
- await setupComponent();
-
- expect(findTasksToBeDone().exists()).toBe(true);
- });
-
- describe('when the selected access level is lower than 30', () => {
- it('does not render the tasks to be done', async () => {
- await setupComponent();
- await triggerAccessLevel(20);
-
- expect(findTasksToBeDone().exists()).toBe(false);
- });
- });
-
- describe('when the url does not contain the parameter `open_modal=invite_members_for_task`', () => {
- it('does not render the tasks to be done', async () => {
- await setupComponent({}, []);
-
- expect(findTasksToBeDone().exists()).toBe(false);
- });
- });
-
- describe('rendering the tasks', () => {
- it('renders the tasks', async () => {
- await setupComponent();
-
- expect(findTasks().exists()).toBe(true);
- });
-
- it('does not render an alert', async () => {
- await setupComponent();
-
- expect(findNoProjectsAlert().exists()).toBe(false);
- });
-
- describe('when there are no projects passed in the data', () => {
- it('does not render the tasks', async () => {
- await setupComponent({ projects: [] });
-
- expect(findTasks().exists()).toBe(false);
- });
-
- it('renders an alert with a link to the new projects path', async () => {
- await setupComponent({ projects: [] });
-
- expect(findNoProjectsAlert().exists()).toBe(true);
- expect(findNoProjectsAlert().findComponent(GlLink).attributes('href')).toBe(
- newProjectPath,
- );
- });
- });
- });
-
- describe('rendering the project dropdown', () => {
- it('renders the project select', async () => {
- await setupComponentWithTasks();
-
- expect(findProjectSelect().exists()).toBe(true);
- });
-
- describe('when the modal is shown for a project', () => {
- it('does not render the project select', async () => {
- await setupComponentWithTasks({ isProject: true });
-
- expect(findProjectSelect().exists()).toBe(false);
- });
- });
-
- describe('when no tasks are selected', () => {
- it('does not render the project select', async () => {
- await setupComponent();
-
- expect(findProjectSelect().exists()).toBe(false);
- });
- });
- });
-
- describe('tracking events', () => {
- it('tracks the submit for invite_members_for_task', async () => {
- await setupComponentWithTasks();
-
- await triggerMembersTokenSelect([user1]);
-
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
-
- clickInviteButton();
-
- expectTracking(INVITE_MEMBERS_FOR_TASK.submit, 'selected_tasks_to_be_done', 'ci,code');
-
- unmockTracking();
- });
- });
- });
-
describe('rendering with tracking considerations', () => {
describe('when inviting to a project', () => {
describe('when inviting members', () => {
@@ -624,6 +493,18 @@ describe('InviteMembersModal', () => {
expect(membersFormGroupInvalidFeedback()).toBe('');
expect(findMembersSelect().props('exceptionState')).not.toBe(false);
});
+
+ it('displays invite limit error message', async () => {
+ mockInvitationsApi(HTTP_STATUS_CREATED, invitationsApiResponse.INVITE_LIMIT);
+
+ clickInviteButton();
+
+ await waitForPromises();
+
+ expect(membersFormGroupInvalidFeedback()).toBe(
+ invitationsApiResponse.INVITE_LIMIT.message,
+ );
+ });
});
});
diff --git a/spec/frontend/invite_members/mock_data/api_responses.js b/spec/frontend/invite_members/mock_data/api_responses.js
index e3e2426fcfc..4f773009f37 100644
--- a/spec/frontend/invite_members/mock_data/api_responses.js
+++ b/spec/frontend/invite_members/mock_data/api_responses.js
@@ -47,6 +47,11 @@ const EMAIL_TAKEN = {
status: 'error',
};
+const INVITE_LIMIT = {
+ message: 'Invite limit of 5 per day exceeded.',
+ status: 'error',
+};
+
export const GROUPS_INVITATIONS_PATH = '/api/v4/groups/1/invitations';
export const invitationsApiResponse = {
@@ -56,6 +61,7 @@ export const invitationsApiResponse = {
MULTIPLE_RESTRICTED,
EMAIL_TAKEN,
EXPANDED_RESTRICTED,
+ INVITE_LIMIT,
};
export const IMPORT_PROJECT_MEMBERS_PATH = '/api/v4/projects/1/import_project_members/2';
diff --git a/spec/frontend/invite_members/mock_data/member_modal.js b/spec/frontend/invite_members/mock_data/member_modal.js
index 67fb1dcbfbd..8cde13bf69c 100644
--- a/spec/frontend/invite_members/mock_data/member_modal.js
+++ b/spec/frontend/invite_members/mock_data/member_modal.js
@@ -6,14 +6,6 @@ export const propsData = {
accessLevels: { Guest: 10, Reporter: 20, Developer: 30, Maintainer: 40, Owner: 50 },
defaultAccessLevel: 30,
helpLink: 'https://example.com',
- tasksToBeDoneOptions: [
- { text: 'First task', value: 'first' },
- { text: 'Second task', value: 'second' },
- ],
- projects: [
- { text: 'First project', value: '1' },
- { text: 'Second project', value: '2' },
- ],
};
export const inviteSource = 'unknown';
@@ -51,8 +43,6 @@ export const postData = {
expires_at: undefined,
invite_source: inviteSource,
format: 'json',
- tasks_to_be_done: [],
- tasks_project_id: '',
};
export const emailPostData = {
@@ -60,8 +50,6 @@ export const emailPostData = {
expires_at: undefined,
email: `${user3.name}`,
invite_source: inviteSource,
- tasks_to_be_done: [],
- tasks_project_id: '',
format: 'json',
};
@@ -71,8 +59,6 @@ export const singleUserPostData = {
user_id: `${user1.id}`,
email: `${user3.name}`,
invite_source: inviteSource,
- tasks_to_be_done: [],
- tasks_project_id: '',
format: 'json',
};
diff --git a/spec/frontend/invite_members/utils/member_utils_spec.js b/spec/frontend/invite_members/utils/member_utils_spec.js
index b6fc70038bb..abae43c3dbb 100644
--- a/spec/frontend/invite_members/utils/member_utils_spec.js
+++ b/spec/frontend/invite_members/utils/member_utils_spec.js
@@ -1,10 +1,4 @@
-import {
- memberName,
- triggerExternalAlert,
- qualifiesForTasksToBeDone,
-} from '~/invite_members/utils/member_utils';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import { getParameterValues } from '~/lib/utils/url_utility';
+import { memberName, triggerExternalAlert } from '~/invite_members/utils/member_utils';
jest.mock('~/lib/utils/url_utility');
@@ -24,17 +18,3 @@ describe('Trigger External Alert', () => {
expect(triggerExternalAlert()).toBe(false);
});
});
-
-describe('Qualifies For Tasks To Be Done', () => {
- it.each([
- ['invite_members_for_task', true],
- ['blah', false],
- ])(`returns name from supplied member token: %j`, (value, result) => {
- setWindowLocation(`blah/blah?open_modal=${value}`);
- getParameterValues.mockImplementation(() => {
- return [value];
- });
-
- expect(qualifiesForTasksToBeDone()).toBe(result);
- });
-});
diff --git a/spec/frontend/issuable/components/csv_export_modal_spec.js b/spec/frontend/issuable/components/csv_export_modal_spec.js
index ccd53e64c4d..118ba9ab378 100644
--- a/spec/frontend/issuable/components/csv_export_modal_spec.js
+++ b/spec/frontend/issuable/components/csv_export_modal_spec.js
@@ -53,7 +53,7 @@ describe('CsvExportModal', () => {
href: 'export/csv/path',
variant: 'confirm',
'data-method': 'post',
- 'data-qa-selector': `export_issues_button`,
+ 'data-testid': 'export-issues-button',
'data-track-action': 'click_button',
'data-track-label': dataTrackLabel,
},
diff --git a/spec/frontend/issuable/components/issuable_header_warnings_spec.js b/spec/frontend/issuable/components/issuable_header_warnings_spec.js
deleted file mode 100644
index 34f36bdf6cb..00000000000
--- a/spec/frontend/issuable/components/issuable_header_warnings_spec.js
+++ /dev/null
@@ -1,105 +0,0 @@
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import mrStore from '~/mr_notes/stores';
-import createIssueStore from '~/notes/stores';
-import IssuableHeaderWarnings from '~/issuable/components/issuable_header_warnings.vue';
-
-const ISSUABLE_TYPE_ISSUE = 'issue';
-const ISSUABLE_TYPE_MR = 'merge_request';
-
-jest.mock('~/mr_notes/stores', () => jest.requireActual('helpers/mocks/mr_notes/stores'));
-
-describe('IssuableHeaderWarnings', () => {
- let wrapper;
-
- const findConfidentialIcon = () => wrapper.findByTestId('confidential');
- const findLockedIcon = () => wrapper.findByTestId('locked');
- const findHiddenIcon = () => wrapper.findByTestId('hidden');
-
- const renderTestMessage = (renders) => (renders ? 'renders' : 'does not render');
-
- const createComponent = ({ store, provide }) => {
- wrapper = shallowMountExtended(IssuableHeaderWarnings, {
- mocks: {
- $store: store,
- },
- provide,
- directives: {
- GlTooltip: createMockDirective('gl-tooltip'),
- },
- });
- };
-
- describe.each`
- issuableType
- ${ISSUABLE_TYPE_ISSUE} | ${ISSUABLE_TYPE_MR}
- `(`when issuableType=$issuableType`, ({ issuableType }) => {
- describe.each`
- lockStatus | confidentialStatus | hiddenStatus
- ${true} | ${true} | ${false}
- ${true} | ${false} | ${false}
- ${false} | ${true} | ${false}
- ${false} | ${false} | ${false}
- ${true} | ${true} | ${true}
- ${true} | ${false} | ${true}
- ${false} | ${true} | ${true}
- ${false} | ${false} | ${true}
- `(
- `when locked=$lockStatus, confidential=$confidentialStatus, and hidden=$hiddenStatus`,
- ({ lockStatus, confidentialStatus, hiddenStatus }) => {
- const store = issuableType === ISSUABLE_TYPE_ISSUE ? createIssueStore() : mrStore;
-
- beforeEach(() => {
- // TODO: simplify to single assignment after issue store is mock
- if (store === mrStore) {
- store.getters.getNoteableData = {};
- }
-
- store.getters.getNoteableData.confidential = confidentialStatus;
- store.getters.getNoteableData.discussion_locked = lockStatus;
- store.getters.getNoteableData.targetType = issuableType;
-
- createComponent({ store, provide: { hidden: hiddenStatus } });
- });
-
- it(`${renderTestMessage(lockStatus)} the locked icon`, () => {
- const lockedIcon = findLockedIcon();
-
- expect(lockedIcon.exists()).toBe(lockStatus);
-
- if (lockStatus) {
- expect(lockedIcon.attributes('title')).toBe(
- `This ${issuableType.replace('_', ' ')} is locked. Only project members can comment.`,
- );
- expect(getBinding(lockedIcon.element, 'gl-tooltip')).not.toBeUndefined();
- }
- });
-
- it(`${renderTestMessage(confidentialStatus)} the confidential icon`, () => {
- const confidentialEl = findConfidentialIcon();
- expect(confidentialEl.exists()).toBe(confidentialStatus);
-
- if (confidentialStatus && !hiddenStatus) {
- expect(confidentialEl.props()).toMatchObject({
- workspaceType: 'project',
- issuableType: 'issue',
- });
- }
- });
-
- it(`${renderTestMessage(confidentialStatus)} the hidden icon`, () => {
- const hiddenIcon = findHiddenIcon();
-
- expect(hiddenIcon.exists()).toBe(hiddenStatus);
-
- if (hiddenStatus) {
- expect(hiddenIcon.attributes('title')).toBe(
- `This ${issuableType.replace('_', ' ')} is hidden because its author has been banned`,
- );
- expect(getBinding(hiddenIcon.element, 'gl-tooltip')).not.toBeUndefined();
- }
- });
- },
- );
- });
-});
diff --git a/spec/frontend/issuable/components/status_badge_spec.js b/spec/frontend/issuable/components/status_badge_spec.js
new file mode 100644
index 00000000000..cdc848626c7
--- /dev/null
+++ b/spec/frontend/issuable/components/status_badge_spec.js
@@ -0,0 +1,43 @@
+import { GlBadge, GlIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import StatusBadge from '~/issuable/components/status_badge.vue';
+
+describe('StatusBadge component', () => {
+ let wrapper;
+
+ const mountComponent = (propsData) => {
+ wrapper = shallowMount(StatusBadge, { propsData });
+ };
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+
+ describe.each`
+ issuableType | badgeText | state | badgeVariant | badgeIcon
+ ${'merge_request'} | ${'Open'} | ${'opened'} | ${'success'} | ${'merge-request-open'}
+ ${'merge_request'} | ${'Closed'} | ${'closed'} | ${'danger'} | ${'merge-request-close'}
+ ${'merge_request'} | ${'Merged'} | ${'merged'} | ${'info'} | ${'merge'}
+ ${'issue'} | ${'Open'} | ${'opened'} | ${'success'} | ${'issues'}
+ ${'issue'} | ${'Closed'} | ${'closed'} | ${'info'} | ${'issue-closed'}
+ ${'epic'} | ${'Open'} | ${'opened'} | ${'success'} | ${'epic'}
+ ${'epic'} | ${'Closed'} | ${'closed'} | ${'info'} | ${'epic-closed'}
+ `(
+ 'when issuableType=$issuableType and state=$state',
+ ({ issuableType, badgeText, state, badgeVariant, badgeIcon }) => {
+ beforeEach(() => {
+ mountComponent({ state, issuableType });
+ });
+
+ it(`renders badge with text '${badgeText}'`, () => {
+ expect(findBadge().text()).toBe(badgeText);
+ });
+
+ it(`sets badge variant as '${badgeVariant}`, () => {
+ expect(findBadge().props('variant')).toBe(badgeVariant);
+ });
+
+ it(`sets badge icon as '${badgeIcon}'`, () => {
+ expect(findBadge().findComponent(GlIcon).props('name')).toBe(badgeIcon);
+ });
+ },
+ );
+});
diff --git a/spec/frontend/issuable/components/status_box_spec.js b/spec/frontend/issuable/components/status_box_spec.js
deleted file mode 100644
index 0d47595c9e6..00000000000
--- a/spec/frontend/issuable/components/status_box_spec.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { GlBadge, GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import StatusBox from '~/issuable/components/status_box.vue';
-
-let wrapper;
-
-function factory(propsData) {
- wrapper = shallowMount(StatusBox, { propsData, stubs: { GlBadge } });
-}
-
-describe('Merge request status box component', () => {
- const findBadge = () => wrapper.findComponent(GlBadge);
-
- describe.each`
- issuableType | badgeText | initialState | badgeClass | badgeVariant | badgeIcon
- ${'merge_request'} | ${'Open'} | ${'opened'} | ${'issuable-status-badge-open'} | ${'success'} | ${'merge-request-open'}
- ${'merge_request'} | ${'Closed'} | ${'closed'} | ${'issuable-status-badge-closed'} | ${'danger'} | ${'merge-request-close'}
- ${'merge_request'} | ${'Merged'} | ${'merged'} | ${'issuable-status-badge-merged'} | ${'info'} | ${'merge'}
- ${'issue'} | ${'Open'} | ${'opened'} | ${'issuable-status-badge-open'} | ${'success'} | ${'issues'}
- ${'issue'} | ${'Closed'} | ${'closed'} | ${'issuable-status-badge-closed'} | ${'info'} | ${'issue-closed'}
- ${'epic'} | ${'Open'} | ${'opened'} | ${'issuable-status-badge-open'} | ${'success'} | ${'epic'}
- ${'epic'} | ${'Closed'} | ${'closed'} | ${'issuable-status-badge-closed'} | ${'info'} | ${'epic-closed'}
- `(
- 'with issuableType set to "$issuableType" and state set to "$initialState"',
- ({ issuableType, badgeText, initialState, badgeClass, badgeVariant, badgeIcon }) => {
- beforeEach(() => {
- factory({
- initialState,
- issuableType,
- });
- });
-
- it(`renders badge with text '${badgeText}'`, () => {
- expect(findBadge().text()).toBe(badgeText);
- });
-
- it(`sets badge css class as '${badgeClass}'`, () => {
- expect(findBadge().classes()).toContain(badgeClass);
- });
-
- it(`sets badge variant as '${badgeVariant}`, () => {
- expect(findBadge().props('variant')).toBe(badgeVariant);
- });
-
- it(`sets badge icon as '${badgeIcon}'`, () => {
- expect(findBadge().findComponent(GlIcon).props('name')).toBe(badgeIcon);
- });
- },
- );
-});
diff --git a/spec/frontend/issuable/popover/components/issue_popover_spec.js b/spec/frontend/issuable/popover/components/issue_popover_spec.js
index 0596433ce9a..2db3a83572c 100644
--- a/spec/frontend/issuable/popover/components/issue_popover_spec.js
+++ b/spec/frontend/issuable/popover/components/issue_popover_spec.js
@@ -8,7 +8,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import IssueDueDate from '~/boards/components/issue_due_date.vue';
import IssueMilestone from '~/issuable/components/issue_milestone.vue';
-import StatusBox from '~/issuable/components/status_box.vue';
+import StatusBadge from '~/issuable/components/status_badge.vue';
import IssuePopover from '~/issuable/popover/components/issue_popover.vue';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
@@ -52,9 +52,9 @@ describe('Issue Popover', () => {
});
it('shows status badge', () => {
- expect(wrapper.findComponent(StatusBox).props()).toEqual({
+ expect(wrapper.findComponent(StatusBadge).props()).toEqual({
issuableType: 'issue',
- initialState: issueQueryResponse.data.project.issue.state,
+ state: issueQueryResponse.data.project.issue.state,
});
});
diff --git a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
index 4686a4fe0c4..f6c9fab76d1 100644
--- a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
+++ b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
@@ -137,7 +137,6 @@ describe('IssuesDashboardApp component', () => {
issuablesLoading: false,
namespace: 'dashboard',
recentSearchesStorageKey: 'issues',
- searchInputPlaceholder: i18n.searchPlaceholder,
showPaginationControls: true,
sortOptions: getSortOptions({
hasBlockedIssuesFeature: defaultProvide.hasBlockedIssuesFeature,
diff --git a/spec/frontend/issues/dashboard/mock_data.js b/spec/frontend/issues/dashboard/mock_data.js
index adcd4268449..1e3abd5a018 100644
--- a/spec/frontend/issues/dashboard/mock_data.js
+++ b/spec/frontend/issues/dashboard/mock_data.js
@@ -19,6 +19,7 @@ export const issuesQueryResponse = {
reference: 'group/project#123456',
state: 'opened',
title: 'Issue title',
+ titleHtml: 'Issue title',
type: 'issue',
updatedAt: '2021-05-22T04:08:01Z',
upvotes: 3,
diff --git a/spec/frontend/issues/list/components/issue_card_time_info_spec.js b/spec/frontend/issues/list/components/issue_card_time_info_spec.js
index e80ffea0591..8286f84b98a 100644
--- a/spec/frontend/issues/list/components/issue_card_time_info_spec.js
+++ b/spec/frontend/issues/list/components/issue_card_time_info_spec.js
@@ -3,13 +3,14 @@ import { shallowMount } from '@vue/test-utils';
import { useFakeDate } from 'helpers/fake_date';
import { STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import IssueCardTimeInfo from '~/issues/list/components/issue_card_time_info.vue';
+import { WIDGET_TYPE_MILESTONE, WIDGET_TYPE_START_AND_DUE_DATE } from '~/work_items/constants';
describe('CE IssueCardTimeInfo component', () => {
useFakeDate(2020, 11, 11); // 2020 Dec 11
let wrapper;
- const issue = {
+ const issueObject = {
milestone: {
dueDate: '2020-12-17',
startDate: '2020-12-10',
@@ -20,22 +21,41 @@ describe('CE IssueCardTimeInfo component', () => {
humanTimeEstimate: '1w',
};
+ const workItemObject = {
+ widgets: [
+ {
+ type: WIDGET_TYPE_MILESTONE,
+ milestone: {
+ dueDate: '2020-12-17',
+ startDate: '2020-12-10',
+ title: 'My milestone',
+ webPath: '/milestone/webPath',
+ },
+ },
+ {
+ type: WIDGET_TYPE_START_AND_DUE_DATE,
+ dueDate: '2020-12-12',
+ },
+ ],
+ };
+
const findMilestone = () => wrapper.find('[data-testid="issuable-milestone"]');
const findMilestoneTitle = () => findMilestone().findComponent(GlLink).attributes('title');
const findDueDate = () => wrapper.find('[data-testid="issuable-due-date"]');
const mountComponent = ({
+ issue = issueObject,
state = STATUS_OPEN,
- dueDate = issue.dueDate,
- milestoneDueDate = issue.milestone.dueDate,
- milestoneStartDate = issue.milestone.startDate,
+ dueDate = issueObject.dueDate,
+ milestoneDueDate = issueObject.milestone.dueDate,
+ milestoneStartDate = issueObject.milestone.startDate,
} = {}) =>
shallowMount(IssueCardTimeInfo, {
propsData: {
issue: {
...issue,
milestone: {
- ...issue.milestone,
+ ...issueObject.milestone,
dueDate: milestoneDueDate,
startDate: milestoneStartDate,
},
@@ -45,63 +65,70 @@ describe('CE IssueCardTimeInfo component', () => {
},
});
- describe('milestone', () => {
- it('renders', () => {
- wrapper = mountComponent();
+ describe.each`
+ type | obj
+ ${'issue'} | ${issueObject}
+ ${'work item'} | ${workItemObject}
+ `('with $type object', ({ obj }) => {
+ describe('milestone', () => {
+ it('renders', () => {
+ wrapper = mountComponent({ issue: obj });
- const milestone = findMilestone();
+ const milestone = findMilestone();
- expect(milestone.text()).toBe(issue.milestone.title);
- expect(milestone.findComponent(GlIcon).props('name')).toBe('clock');
- expect(milestone.findComponent(GlLink).attributes('href')).toBe(issue.milestone.webPath);
- });
+ expect(milestone.text()).toBe('My milestone');
+ expect(milestone.findComponent(GlIcon).props('name')).toBe('clock');
+ expect(milestone.findComponent(GlLink).attributes('href')).toBe('/milestone/webPath');
+ });
- describe.each`
- time | text | milestoneDueDate | milestoneStartDate | expected
- ${'due date is in past'} | ${'Past due'} | ${'2020-09-09'} | ${null} | ${'Sep 9, 2020 (Past due)'}
- ${'due date is today'} | ${'Today'} | ${'2020-12-11'} | ${null} | ${'Dec 11, 2020 (Today)'}
- ${'start date is in future'} | ${'Upcoming'} | ${'2021-03-01'} | ${'2021-02-01'} | ${'Mar 1, 2021 (Upcoming)'}
- ${'due date is in future'} | ${'2 weeks remaining'} | ${'2020-12-25'} | ${null} | ${'Dec 25, 2020 (2 weeks remaining)'}
- `('when $description', ({ text, milestoneDueDate, milestoneStartDate, expected }) => {
- it(`renders with "${text}"`, () => {
- wrapper = mountComponent({ milestoneDueDate, milestoneStartDate });
-
- expect(findMilestoneTitle()).toBe(expected);
+ describe.each`
+ time | text | milestoneDueDate | milestoneStartDate | expected
+ ${'due date is in past'} | ${'Past due'} | ${'2020-09-09'} | ${null} | ${'Sep 9, 2020 (Past due)'}
+ ${'due date is today'} | ${'Today'} | ${'2020-12-11'} | ${null} | ${'Dec 11, 2020 (Today)'}
+ ${'start date is in future'} | ${'Upcoming'} | ${'2021-03-01'} | ${'2021-02-01'} | ${'Mar 1, 2021 (Upcoming)'}
+ ${'due date is in future'} | ${'2 weeks remaining'} | ${'2020-12-25'} | ${null} | ${'Dec 25, 2020 (2 weeks remaining)'}
+ `('when $description', ({ text, milestoneDueDate, milestoneStartDate, expected }) => {
+ it(`renders with "${text}"`, () => {
+ wrapper = mountComponent({ issue: obj, milestoneDueDate, milestoneStartDate });
+
+ expect(findMilestoneTitle()).toBe(expected);
+ });
});
});
- });
- describe('due date', () => {
- describe('when upcoming', () => {
- it('renders', () => {
- wrapper = mountComponent();
+ describe('due date', () => {
+ describe('when upcoming', () => {
+ it('renders', () => {
+ wrapper = mountComponent({ issue: obj });
- const dueDate = findDueDate();
+ const dueDate = findDueDate();
- expect(dueDate.text()).toBe('Dec 12, 2020');
- expect(dueDate.attributes('title')).toBe('Due date');
- expect(dueDate.findComponent(GlIcon).props('name')).toBe('calendar');
- expect(dueDate.classes()).not.toContain('gl-text-red-500');
+ expect(dueDate.text()).toBe('Dec 12, 2020');
+ expect(dueDate.attributes('title')).toBe('Due date');
+ expect(dueDate.findComponent(GlIcon).props('name')).toBe('calendar');
+ expect(dueDate.classes()).not.toContain('gl-text-red-500');
+ });
});
- });
- describe('when in the past', () => {
- describe('when issue is open', () => {
- it('renders in red', () => {
- wrapper = mountComponent({ dueDate: '2020-10-10' });
+ describe('when in the past', () => {
+ describe('when issue is open', () => {
+ it('renders in red', () => {
+ wrapper = mountComponent({ issue: obj, dueDate: '2020-10-10' });
- expect(findDueDate().classes()).toContain('gl-text-red-500');
+ expect(findDueDate().classes()).toContain('gl-text-red-500');
+ });
});
- });
- describe('when issue is closed', () => {
- it('does not render in red', () => {
- wrapper = mountComponent({
- dueDate: '2020-10-10',
- state: STATUS_CLOSED,
- });
+ describe('when issue is closed', () => {
+ it('does not render in red', () => {
+ wrapper = mountComponent({
+ issue: obj,
+ dueDate: '2020-10-10',
+ state: STATUS_CLOSED,
+ });
- expect(findDueDate().classes()).not.toContain('gl-text-red-500');
+ expect(findDueDate().classes()).not.toContain('gl-text-red-500');
+ });
});
});
});
@@ -112,7 +139,7 @@ describe('CE IssueCardTimeInfo component', () => {
const timeEstimate = wrapper.find('[data-testid="time-estimate"]');
- expect(timeEstimate.text()).toBe(issue.humanTimeEstimate);
+ expect(timeEstimate.text()).toBe(issueObject.humanTimeEstimate);
expect(timeEstimate.attributes('title')).toBe('Estimate');
expect(timeEstimate.findComponent(GlIcon).props('name')).toBe('timer');
});
diff --git a/spec/frontend/issues/list/components/issues_list_app_spec.js b/spec/frontend/issues/list/components/issues_list_app_spec.js
index de027a21c8f..f830168ce5d 100644
--- a/spec/frontend/issues/list/components/issues_list_app_spec.js
+++ b/spec/frontend/issues/list/components/issues_list_app_spec.js
@@ -237,7 +237,6 @@ describe('CE IssuesListApp component', () => {
expect(findIssuableList().props()).toMatchObject({
namespace: defaultProvide.fullPath,
recentSearchesStorageKey: 'issues',
- searchInputPlaceholder: IssuesListApp.i18n.searchPlaceholder,
sortOptions: getSortOptions({
hasBlockedIssuesFeature: defaultProvide.hasBlockedIssuesFeature,
hasIssuableHealthStatusFeature: defaultProvide.hasIssuableHealthStatusFeature,
diff --git a/spec/frontend/issues/list/mock_data.js b/spec/frontend/issues/list/mock_data.js
index b9a8bc171db..73fda11f38c 100644
--- a/spec/frontend/issues/list/mock_data.js
+++ b/spec/frontend/issues/list/mock_data.js
@@ -49,6 +49,7 @@ export const getIssuesQueryResponse = {
moved: false,
state: 'opened',
title: 'Issue title',
+ titleHtml: 'Issue title',
updatedAt: '2021-05-22T04:08:01Z',
closedAt: null,
upvotes: 3,
diff --git a/spec/frontend/issues/new/components/__snapshots__/type_popover_spec.js.snap b/spec/frontend/issues/new/components/__snapshots__/type_popover_spec.js.snap
index 1a199ed2ee9..a4bd9608e34 100644
--- a/spec/frontend/issues/new/components/__snapshots__/type_popover_spec.js.snap
+++ b/spec/frontend/issues/new/components/__snapshots__/type_popover_spec.js.snap
@@ -3,15 +3,14 @@
exports[`Issue type info popover renders 1`] = `
<span
class="gl-ml-2"
- id="popovercontainer"
+ id="reference-0"
>
<gl-icon-stub
class="gl-text-blue-600"
- id="issue-type-info"
+ id="reference-1"
name="question-o"
size="16"
/>
-
<gl-popover-stub
container="popovercontainer"
cssclasses=""
@@ -20,7 +19,7 @@ exports[`Issue type info popover renders 1`] = `
triggers="focus hover"
>
<ul
- class="gl-list-style-none gl-p-0 gl-m-0"
+ class="gl-list-style-none gl-m-0 gl-p-0"
>
<li
class="gl-mb-3"
@@ -30,19 +29,16 @@ exports[`Issue type info popover renders 1`] = `
>
Issue
</div>
-
<span>
For general work
</span>
</li>
-
<li>
<div
class="gl-font-weight-bold"
>
Incident
</div>
-
<span>
For investigating IT service disruptions or outages
</span>
diff --git a/spec/frontend/issues/service_desk/components/empty_state_with_any_issues_spec.js b/spec/frontend/issues/service_desk/components/empty_state_with_any_issues_spec.js
new file mode 100644
index 00000000000..90f0847f37b
--- /dev/null
+++ b/spec/frontend/issues/service_desk/components/empty_state_with_any_issues_spec.js
@@ -0,0 +1,74 @@
+import { GlEmptyState } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import EmptyStateWithAnyIssues from '~/issues/service_desk/components/empty_state_with_any_issues.vue';
+import {
+ noSearchResultsTitle,
+ noSearchResultsDescription,
+ infoBannerUserNote,
+ noOpenIssuesTitle,
+ noClosedIssuesTitle,
+} from '~/issues/service_desk/constants';
+
+describe('EmptyStateWithAnyIssues component', () => {
+ let wrapper;
+
+ const defaultProvide = {
+ emptyStateSvgPath: 'empty/state/svg/path',
+ newIssuePath: 'new/issue/path',
+ showNewIssueLink: false,
+ };
+
+ const findGlEmptyState = () => wrapper.findComponent(GlEmptyState);
+
+ const mountComponent = (props = {}) => {
+ wrapper = shallowMount(EmptyStateWithAnyIssues, {
+ propsData: {
+ hasSearch: true,
+ isOpenTab: true,
+ ...props,
+ },
+ provide: defaultProvide,
+ });
+ };
+
+ describe('when there is a search (with no results)', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('shows empty state', () => {
+ expect(findGlEmptyState().props()).toMatchObject({
+ description: noSearchResultsDescription,
+ title: noSearchResultsTitle,
+ svgPath: defaultProvide.emptyStateSvgPath,
+ });
+ });
+ });
+
+ describe('when "Open" tab is active', () => {
+ beforeEach(() => {
+ mountComponent({ hasSearch: false });
+ });
+
+ it('shows empty state', () => {
+ expect(findGlEmptyState().props()).toMatchObject({
+ description: infoBannerUserNote,
+ title: noOpenIssuesTitle,
+ svgPath: defaultProvide.emptyStateSvgPath,
+ });
+ });
+ });
+
+ describe('when "Closed" tab is active', () => {
+ beforeEach(() => {
+ mountComponent({ hasSearch: false, isClosedTab: true, isOpenTab: false });
+ });
+
+ it('shows empty state', () => {
+ expect(findGlEmptyState().props()).toMatchObject({
+ title: noClosedIssuesTitle,
+ svgPath: defaultProvide.emptyStateSvgPath,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/issues/service_desk/components/empty_state_without_any_issues_spec.js b/spec/frontend/issues/service_desk/components/empty_state_without_any_issues_spec.js
new file mode 100644
index 00000000000..7f281d6fbfe
--- /dev/null
+++ b/spec/frontend/issues/service_desk/components/empty_state_without_any_issues_spec.js
@@ -0,0 +1,90 @@
+import { GlEmptyState, GlLink } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import EmptyStateWithoutAnyIssues from '~/issues/service_desk/components/empty_state_without_any_issues.vue';
+import {
+ infoBannerTitle,
+ noIssuesSignedOutButtonText,
+ learnMore,
+} from '~/issues/service_desk/constants';
+
+describe('EmptyStateWithoutAnyIssues component', () => {
+ let wrapper;
+
+ const defaultProvide = {
+ emptyStateSvgPath: 'empty/state/svg/path',
+ isSignedIn: true,
+ signInPath: 'sign/in/path',
+ canAdminIssues: true,
+ isServiceDeskEnabled: true,
+ serviceDeskEmailAddress: 'email@address.com',
+ serviceDeskHelpPath: 'service/desk/help/path',
+ };
+
+ const findGlEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findGlLink = () => wrapper.findComponent(GlLink);
+ const findIssuesHelpPageLink = () => wrapper.findByRole('link', { name: learnMore });
+
+ const mountComponent = ({ provide = {} } = {}) => {
+ wrapper = mountExtended(EmptyStateWithoutAnyIssues, {
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ });
+ };
+
+ describe('when signed in', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('renders empty state', () => {
+ expect(findGlEmptyState().props()).toMatchObject({
+ title: infoBannerTitle,
+ svgPath: defaultProvide.emptyStateSvgPath,
+ contentClass: 'gl-max-w-80!',
+ });
+ });
+
+ it('renders description with service desk docs link', () => {
+ expect(findIssuesHelpPageLink().attributes('href')).toBe(defaultProvide.serviceDeskHelpPath);
+ });
+
+ it('renders email address, when user can admin issues and service desk is enabled', () => {
+ expect(wrapper.text()).toContain(wrapper.vm.serviceDeskEmailAddress);
+ });
+
+ it('does not render email address, when user can not admin issues', () => {
+ mountComponent({ provide: { canAdminIssues: false } });
+
+ expect(wrapper.text()).not.toContain(wrapper.vm.serviceDeskEmailAddress);
+ });
+
+ it('does not render email address, when service desk is not setup', () => {
+ mountComponent({ provide: { isServiceDeskEnabled: false } });
+
+ expect(wrapper.text()).not.toContain(wrapper.vm.serviceDeskEmailAddress);
+ });
+ });
+
+ describe('when signed out', () => {
+ beforeEach(() => {
+ mountComponent({ provide: { isSignedIn: false } });
+ });
+
+ it('renders empty state', () => {
+ expect(findGlEmptyState().props()).toMatchObject({
+ title: infoBannerTitle,
+ svgPath: defaultProvide.emptyStateSvgPath,
+ primaryButtonText: noIssuesSignedOutButtonText,
+ primaryButtonLink: defaultProvide.signInPath,
+ contentClass: 'gl-max-w-80!',
+ });
+ });
+
+ it('renders service desk docs link', () => {
+ expect(findGlLink().attributes('href')).toBe(defaultProvide.serviceDeskHelpPath);
+ expect(findGlLink().text()).toBe(learnMore);
+ });
+ });
+});
diff --git a/spec/frontend/issues/service_desk/components/info_banner_spec.js b/spec/frontend/issues/service_desk/components/info_banner_spec.js
new file mode 100644
index 00000000000..593455f5deb
--- /dev/null
+++ b/spec/frontend/issues/service_desk/components/info_banner_spec.js
@@ -0,0 +1,81 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLink, GlButton } from '@gitlab/ui';
+import InfoBanner from '~/issues/service_desk/components/info_banner.vue';
+import { infoBannerAdminNote, enableServiceDesk } from '~/issues/service_desk/constants';
+
+describe('InfoBanner', () => {
+ let wrapper;
+
+ const defaultProvide = {
+ serviceDeskCalloutSvgPath: 'callout.svg',
+ serviceDeskEmailAddress: 'sd@gmail.com',
+ canAdminIssues: true,
+ canEditProjectSettings: true,
+ serviceDeskSettingsPath: 'path/to/project/settings',
+ serviceDeskHelpPath: 'path/to/documentation',
+ isServiceDeskEnabled: true,
+ };
+
+ const findEnableSDButton = () => wrapper.findComponent(GlButton);
+
+ const mountComponent = (provide) => {
+ return shallowMount(InfoBanner, {
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ stubs: {
+ GlLink,
+ GlButton,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ wrapper = mountComponent();
+ });
+
+ describe('Service Desk email address', () => {
+ it('renders when user can admin issues and service desk is enabled', () => {
+ expect(wrapper.text()).toContain(infoBannerAdminNote);
+ expect(wrapper.text()).toContain(wrapper.vm.serviceDeskEmailAddress);
+ });
+
+ it('does not render, when user can not admin issues', () => {
+ wrapper = mountComponent({ canAdminIssues: false });
+
+ expect(wrapper.text()).not.toContain(infoBannerAdminNote);
+ expect(wrapper.text()).not.toContain(wrapper.vm.serviceDeskEmailAddress);
+ });
+
+ it('does not render, when service desk is not setup', () => {
+ wrapper = mountComponent({ isServiceDeskEnabled: false });
+
+ expect(wrapper.text()).not.toContain(infoBannerAdminNote);
+ expect(wrapper.text()).not.toContain(wrapper.vm.serviceDeskEmailAddress);
+ });
+ });
+
+ describe('Link to Service Desk settings', () => {
+ it('renders when user can edit settings and service desk is not enabled', () => {
+ wrapper = mountComponent({ isServiceDeskEnabled: false });
+
+ expect(wrapper.text()).toContain(enableServiceDesk);
+ expect(findEnableSDButton().exists()).toBe(true);
+ });
+
+ it('does not render when service desk is enabled', () => {
+ wrapper = mountComponent();
+
+ expect(wrapper.text()).not.toContain(enableServiceDesk);
+ expect(findEnableSDButton().exists()).toBe(false);
+ });
+
+ it('does not render when user cannot edit settings', () => {
+ wrapper = mountComponent({ canEditProjectSettings: false });
+
+ expect(wrapper.text()).not.toContain(enableServiceDesk);
+ expect(findEnableSDButton().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/issues/service_desk/components/service_desk_list_app_spec.js b/spec/frontend/issues/service_desk/components/service_desk_list_app_spec.js
new file mode 100644
index 00000000000..d28b4f2fe76
--- /dev/null
+++ b/spec/frontend/issues/service_desk/components/service_desk_list_app_spec.js
@@ -0,0 +1,717 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { cloneDeep } from 'lodash';
+import VueRouter from 'vue-router';
+import * as Sentry from '@sentry/browser';
+import AxiosMockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import { TEST_HOST } from 'helpers/test_constants';
+import { joinPaths } from '~/lib/utils/url_utility';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
+import waitForPromises from 'helpers/wait_for_promises';
+import { scrollUp } from '~/lib/utils/scroll_utils';
+import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
+import { issuableListTabs } from '~/vue_shared/issuable/list/constants';
+import { TYPENAME_USER } from '~/graphql_shared/constants';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { getSortKey, getSortOptions } from '~/issues/list/utils';
+import { STATUS_CLOSED, STATUS_OPEN, STATUS_ALL } from '~/issues/service_desk/constants';
+import getServiceDeskIssuesQuery from 'ee_else_ce/issues/service_desk/queries/get_service_desk_issues.query.graphql';
+import getServiceDeskIssuesCountsQuery from 'ee_else_ce/issues/service_desk/queries/get_service_desk_issues_counts.query.graphql';
+import setSortingPreferenceMutation from '~/issues/service_desk/queries/set_sorting_preference.mutation.graphql';
+import ServiceDeskListApp from '~/issues/service_desk/components/service_desk_list_app.vue';
+import InfoBanner from '~/issues/service_desk/components/info_banner.vue';
+import EmptyStateWithAnyIssues from '~/issues/service_desk/components/empty_state_with_any_issues.vue';
+import EmptyStateWithoutAnyIssues from '~/issues/service_desk/components/empty_state_without_any_issues.vue';
+import { createAlert, VARIANT_INFO } from '~/alert';
+import {
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_SEARCH_WITHIN,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ CREATED_DESC,
+ UPDATED_DESC,
+ RELATIVE_POSITION_ASC,
+ RELATIVE_POSITION,
+ urlSortParams,
+} from '~/issues/list/constants';
+import {
+ getServiceDeskIssuesQueryResponse,
+ getServiceDeskIssuesQueryEmptyResponse,
+ getServiceDeskIssuesCountsQueryResponse,
+ setSortPreferenceMutationResponse,
+ setSortPreferenceMutationResponseWithErrors,
+ filteredTokens,
+ urlParams,
+ locationSearch,
+} from '../mock_data';
+
+jest.mock('@sentry/browser');
+jest.mock('~/alert');
+jest.mock('~/lib/utils/scroll_utils', () => ({ scrollUp: jest.fn() }));
+
+describe('CE ServiceDeskListApp', () => {
+ let wrapper;
+ let router;
+ let axiosMock;
+
+ Vue.use(VueApollo);
+ Vue.use(VueRouter);
+
+ const defaultProvide = {
+ releasesPath: 'releases/path',
+ autocompleteAwardEmojisPath: 'autocomplete/award/emojis/path',
+ hasBlockedIssuesFeature: false,
+ hasIterationsFeature: true,
+ hasIssueWeightsFeature: true,
+ hasIssuableHealthStatusFeature: true,
+ groupPath: 'group/path',
+ emptyStateSvgPath: 'empty-state.svg',
+ isProject: true,
+ isSignedIn: true,
+ fullPath: 'path/to/project',
+ isServiceDeskSupported: true,
+ hasAnyIssues: true,
+ initialSort: CREATED_DESC,
+ isIssueRepositioningDisabled: false,
+ issuablesLoading: false,
+ showPaginationControls: true,
+ useKeysetPagination: true,
+ hasPreviousPage: getServiceDeskIssuesQueryResponse.data.project.issues.pageInfo.hasPreviousPage,
+ hasNextPage: getServiceDeskIssuesQueryResponse.data.project.issues.pageInfo.hasNextPage,
+ };
+
+ let defaultQueryResponse = getServiceDeskIssuesQueryResponse;
+ if (IS_EE) {
+ defaultQueryResponse = cloneDeep(getServiceDeskIssuesQueryResponse);
+ defaultQueryResponse.data.project.issues.nodes[0].healthStatus = null;
+ defaultQueryResponse.data.project.issues.nodes[0].weight = 5;
+ }
+
+ const mockServiceDeskIssuesQueryResponseHandler = jest
+ .fn()
+ .mockResolvedValue(defaultQueryResponse);
+ const mockServiceDeskIssuesQueryEmptyResponseHandler = jest
+ .fn()
+ .mockResolvedValue(getServiceDeskIssuesQueryEmptyResponse);
+ const mockServiceDeskIssuesCountsQueryResponseHandler = jest
+ .fn()
+ .mockResolvedValue(getServiceDeskIssuesCountsQueryResponse);
+
+ const findIssuableList = () => wrapper.findComponent(IssuableList);
+ const findInfoBanner = () => wrapper.findComponent(InfoBanner);
+ const findLabelsToken = () =>
+ findIssuableList()
+ .props('searchTokens')
+ .find((token) => token.type === TOKEN_TYPE_LABEL);
+
+ const createComponent = ({
+ provide = {},
+ serviceDeskIssuesQueryResponseHandler = mockServiceDeskIssuesQueryResponseHandler,
+ serviceDeskIssuesCountsQueryResponseHandler = mockServiceDeskIssuesCountsQueryResponseHandler,
+ sortPreferenceMutationResponse = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse),
+ } = {}) => {
+ const requestHandlers = [
+ [getServiceDeskIssuesQuery, serviceDeskIssuesQueryResponseHandler],
+ [getServiceDeskIssuesCountsQuery, serviceDeskIssuesCountsQueryResponseHandler],
+ [setSortingPreferenceMutation, sortPreferenceMutationResponse],
+ ];
+
+ router = new VueRouter({ mode: 'history' });
+
+ return shallowMount(ServiceDeskListApp, {
+ apolloProvider: createMockApollo(
+ requestHandlers,
+ {},
+ {
+ typePolicies: {
+ Query: {
+ fields: {
+ project: {
+ merge: true,
+ },
+ },
+ },
+ },
+ },
+ ),
+ router,
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ setWindowLocation(TEST_HOST);
+ axiosMock = new AxiosMockAdapter(axios);
+ wrapper = createComponent();
+ return waitForPromises();
+ });
+
+ afterEach(() => {
+ axiosMock.reset();
+ });
+
+ it('renders the issuable list with skeletons while fetching service desk issues', async () => {
+ wrapper = createComponent();
+ await nextTick();
+
+ expect(findIssuableList().props('issuablesLoading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findIssuableList().props('issuablesLoading')).toBe(false);
+ });
+
+ it('fetches service desk issues and renders them in the issuable list', () => {
+ expect(findIssuableList().props()).toMatchObject({
+ namespace: 'service-desk',
+ recentSearchesStorageKey: 'service-desk-issues',
+ issuables: defaultQueryResponse.data.project.issues.nodes,
+ tabs: issuableListTabs,
+ currentTab: STATUS_OPEN,
+ tabCounts: {
+ opened: 1,
+ closed: 1,
+ all: 1,
+ },
+ sortOptions: getSortOptions({
+ hasBlockedIssuesFeature: defaultProvide.hasBlockedIssuesFeature,
+ hasIssuableHealthStatusFeature: defaultProvide.hasIssuableHealthStatusFeature,
+ hasIssueWeightsFeature: defaultProvide.hasIssueWeightsFeature,
+ }),
+ initialSortBy: CREATED_DESC,
+ isManualOrdering: false,
+ });
+ });
+
+ describe('InfoBanner', () => {
+ it('renders when Service Desk is supported and has any number of issues', () => {
+ expect(findInfoBanner().exists()).toBe(true);
+ });
+
+ it('does not render when Service Desk is not supported and has any number of issues', () => {
+ wrapper = createComponent({ provide: { isServiceDeskSupported: false } });
+
+ expect(findInfoBanner().exists()).toBe(false);
+ });
+
+ it('does not render, when there are no issues', () => {
+ wrapper = createComponent({
+ serviceDeskIssuesQueryResponseHandler: mockServiceDeskIssuesQueryEmptyResponseHandler,
+ });
+
+ expect(findInfoBanner().exists()).toBe(false);
+ });
+ });
+
+ describe('Empty states', () => {
+ describe('when there are issues', () => {
+ it('shows EmptyStateWithAnyIssues component', () => {
+ setWindowLocation(locationSearch);
+ wrapper = createComponent({
+ serviceDeskIssuesQueryResponseHandler: mockServiceDeskIssuesQueryEmptyResponseHandler,
+ });
+
+ expect(wrapper.findComponent(EmptyStateWithAnyIssues).props()).toEqual({
+ hasSearch: true,
+ isOpenTab: true,
+ });
+ });
+ });
+
+ describe('when there are no issues', () => {
+ it('shows EmptyStateWithoutAnyIssues component', () => {
+ wrapper = createComponent({
+ provide: { hasAnyIssues: false },
+ serviceDeskIssuesQueryResponseHandler: mockServiceDeskIssuesQueryEmptyResponseHandler,
+ });
+
+ expect(wrapper.findComponent(EmptyStateWithoutAnyIssues).exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('Initial url params', () => {
+ describe('search', () => {
+ it('is set from the url params', () => {
+ setWindowLocation(locationSearch);
+ wrapper = createComponent();
+
+ expect(router.history.current.query).toMatchObject({ search: 'find issues' });
+ });
+ });
+
+ describe('sort', () => {
+ describe('when initial sort value uses old enum values', () => {
+ const oldEnumSortValues = Object.values(urlSortParams);
+
+ it.each(oldEnumSortValues)('initial sort is set with value %s', async (sort) => {
+ wrapper = createComponent({ provide: { initialSort: sort } });
+ await waitForPromises();
+
+ expect(findIssuableList().props('initialSortBy')).toBe(getSortKey(sort));
+ });
+ });
+
+ describe('when initial sort value uses new GraphQL enum values', () => {
+ const graphQLEnumSortValues = Object.keys(urlSortParams);
+
+ it.each(graphQLEnumSortValues)('initial sort is set with value %s', async (sort) => {
+ wrapper = createComponent({ provide: { initialSort: sort.toLowerCase() } });
+ await waitForPromises();
+
+ expect(findIssuableList().props('initialSortBy')).toBe(sort);
+ });
+ });
+
+ describe('when initial sort value is invalid', () => {
+ it.each(['', 'asdf', null, undefined])(
+ 'initial sort is set to value CREATED_DESC',
+ async (sort) => {
+ wrapper = createComponent({ provide: { initialSort: sort } });
+ await waitForPromises();
+
+ expect(findIssuableList().props('initialSortBy')).toBe(CREATED_DESC);
+ },
+ );
+ });
+
+ describe('when sort is manual and issue repositioning is disabled', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({
+ provide: { initialSort: RELATIVE_POSITION, isIssueRepositioningDisabled: true },
+ });
+ await waitForPromises();
+ });
+
+ it('changes the sort to the default of created descending', () => {
+ expect(findIssuableList().props('initialSortBy')).toBe(CREATED_DESC);
+ });
+
+ it('shows an alert to tell the user that manual reordering is disabled', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: ServiceDeskListApp.i18n.issueRepositioningMessage,
+ variant: VARIANT_INFO,
+ });
+ });
+ });
+ });
+
+ describe('state', () => {
+ it('is set from the url params', async () => {
+ const initialState = STATUS_ALL;
+ setWindowLocation(`?state=${initialState}`);
+ wrapper = createComponent();
+ await waitForPromises();
+
+ expect(findIssuableList().props('currentTab')).toBe(initialState);
+ });
+ });
+
+ describe('filter tokens', () => {
+ it('are set from the url params', () => {
+ setWindowLocation(locationSearch);
+ wrapper = createComponent();
+
+ expect(findIssuableList().props('initialFilterValue')).toEqual(filteredTokens);
+ });
+ });
+ });
+
+ describe('Tokens', () => {
+ const mockCurrentUser = {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ avatar_url: 'avatar/url',
+ };
+
+ describe('when user is signed out', () => {
+ beforeEach(() => {
+ wrapper = createComponent({ provide: { isSignedIn: false } });
+ return waitForPromises();
+ });
+
+ it('does not render My-Reaction or Confidential tokens', () => {
+ expect(findIssuableList().props('searchTokens')).not.toMatchObject([
+ { type: TOKEN_TYPE_AUTHOR, preloadedUsers: [mockCurrentUser] },
+ { type: TOKEN_TYPE_ASSIGNEE, preloadedUsers: [mockCurrentUser] },
+ { type: TOKEN_TYPE_MY_REACTION },
+ { type: TOKEN_TYPE_CONFIDENTIAL },
+ ]);
+ });
+ });
+
+ describe('when all tokens are available', () => {
+ beforeEach(() => {
+ window.gon = {
+ current_user_id: mockCurrentUser.id,
+ current_user_fullname: mockCurrentUser.name,
+ current_username: mockCurrentUser.username,
+ current_user_avatar_url: mockCurrentUser.avatar_url,
+ };
+
+ wrapper = createComponent();
+ return waitForPromises();
+ });
+
+ it('renders all tokens alphabetically', () => {
+ const preloadedUsers = [
+ { ...mockCurrentUser, id: convertToGraphQLId(TYPENAME_USER, mockCurrentUser.id) },
+ ];
+
+ expect(findIssuableList().props('searchTokens')).toMatchObject([
+ { type: TOKEN_TYPE_ASSIGNEE, preloadedUsers },
+ { type: TOKEN_TYPE_CONFIDENTIAL },
+ { type: TOKEN_TYPE_LABEL },
+ { type: TOKEN_TYPE_MILESTONE },
+ { type: TOKEN_TYPE_MY_REACTION },
+ { type: TOKEN_TYPE_RELEASE },
+ { type: TOKEN_TYPE_SEARCH_WITHIN },
+ ]);
+ });
+ });
+ });
+
+ describe('Events', () => {
+ describe('when "click-tab" event is emitted by IssuableList', () => {
+ beforeEach(async () => {
+ wrapper = createComponent();
+ router.push = jest.fn();
+ await waitForPromises();
+
+ findIssuableList().vm.$emit('click-tab', STATUS_CLOSED);
+ });
+
+ it('updates ui to the new tab', () => {
+ expect(findIssuableList().props('currentTab')).toBe(STATUS_CLOSED);
+ });
+
+ it('updates url to the new tab', () => {
+ expect(router.push).toHaveBeenCalledWith({
+ query: expect.objectContaining({ state: STATUS_CLOSED }),
+ });
+ });
+ });
+
+ describe('when "reorder" event is emitted by IssuableList', () => {
+ const issueOne = {
+ ...defaultQueryResponse.data.project.issues.nodes[0],
+ id: 'gid://gitlab/Issue/1',
+ iid: '101',
+ reference: 'group/project#1',
+ webPath: '/group/project/-/issues/1',
+ };
+ const issueTwo = {
+ ...defaultQueryResponse.data.project.issues.nodes[0],
+ id: 'gid://gitlab/Issue/2',
+ iid: '102',
+ reference: 'group/project#2',
+ webPath: '/group/project/-/issues/2',
+ };
+ const issueThree = {
+ ...defaultQueryResponse.data.project.issues.nodes[0],
+ id: 'gid://gitlab/Issue/3',
+ iid: '103',
+ reference: 'group/project#3',
+ webPath: '/group/project/-/issues/3',
+ };
+ const issueFour = {
+ ...defaultQueryResponse.data.project.issues.nodes[0],
+ id: 'gid://gitlab/Issue/4',
+ iid: '104',
+ reference: 'group/project#4',
+ webPath: '/group/project/-/issues/4',
+ };
+ const response = () => ({
+ data: {
+ project: {
+ id: '1',
+ issues: {
+ ...defaultQueryResponse.data.project.issues,
+ nodes: [issueOne, issueTwo, issueThree, issueFour],
+ },
+ },
+ },
+ });
+
+ describe('when successful', () => {
+ describe.each`
+ description | issueToMove | oldIndex | newIndex | moveBeforeId | moveAfterId
+ ${'to the beginning of the list'} | ${issueThree} | ${2} | ${0} | ${null} | ${issueOne.id}
+ ${'down the list'} | ${issueOne} | ${0} | ${1} | ${issueTwo.id} | ${issueThree.id}
+ ${'up the list'} | ${issueThree} | ${2} | ${1} | ${issueOne.id} | ${issueTwo.id}
+ ${'to the end of the list'} | ${issueTwo} | ${1} | ${3} | ${issueFour.id} | ${null}
+ `(
+ 'when moving issue $description',
+ ({ issueToMove, oldIndex, newIndex, moveBeforeId, moveAfterId }) => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ serviceDeskIssuesQueryResponseHandler: jest.fn().mockResolvedValue(response()),
+ });
+ return waitForPromises();
+ });
+
+ it('makes API call to reorder the issue', async () => {
+ findIssuableList().vm.$emit('reorder', { oldIndex, newIndex });
+ await waitForPromises();
+
+ expect(axiosMock.history.put[0]).toMatchObject({
+ url: joinPaths(issueToMove.webPath, 'reorder'),
+ data: JSON.stringify({
+ move_before_id: getIdFromGraphQLId(moveBeforeId),
+ move_after_id: getIdFromGraphQLId(moveAfterId),
+ }),
+ });
+ });
+ },
+ );
+ });
+
+ describe('when unsuccessful', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ serviceDeskIssuesQueryResponseHandler: jest.fn().mockResolvedValue(response()),
+ });
+ return waitForPromises();
+ });
+
+ it('displays an error message', async () => {
+ axiosMock
+ .onPut(joinPaths(issueOne.webPath, 'reorder'))
+ .reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
+
+ findIssuableList().vm.$emit('reorder', { oldIndex: 0, newIndex: 1 });
+ await waitForPromises();
+
+ expect(findIssuableList().props('error')).toBe(ServiceDeskListApp.i18n.reorderError);
+ expect(Sentry.captureException).toHaveBeenCalledWith(
+ new Error('Request failed with status code 500'),
+ );
+ });
+ });
+ });
+
+ describe('when "sort" event is emitted by IssuableList', () => {
+ it.each(Object.keys(urlSortParams))(
+ 'updates to the new sort when payload is `%s`',
+ async (sortKey) => {
+ // Ensure initial sort key is different so we can trigger an update when emitting a sort key
+ wrapper =
+ sortKey === CREATED_DESC
+ ? createComponent({ provide: { initialSort: UPDATED_DESC } })
+ : createComponent();
+ router.push = jest.fn();
+ await waitForPromises();
+
+ findIssuableList().vm.$emit('sort', sortKey);
+
+ expect(router.push).toHaveBeenCalledWith({
+ query: expect.objectContaining({ sort: urlSortParams[sortKey] }),
+ });
+ },
+ );
+
+ describe('when issue repositioning is disabled', () => {
+ const initialSort = CREATED_DESC;
+
+ beforeEach(async () => {
+ wrapper = createComponent({
+ provide: { initialSort, isIssueRepositioningDisabled: true },
+ });
+ router.push = jest.fn();
+ await waitForPromises();
+
+ findIssuableList().vm.$emit('sort', RELATIVE_POSITION_ASC);
+ });
+
+ it('does not update the sort to manual', () => {
+ expect(router.push).not.toHaveBeenCalled();
+ });
+
+ it('shows an alert to tell the user that manual reordering is disabled', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: ServiceDeskListApp.i18n.issueRepositioningMessage,
+ variant: VARIANT_INFO,
+ });
+ });
+ });
+
+ describe('when user is signed in', () => {
+ it('calls mutation to save sort preference', async () => {
+ const mutationMock = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse);
+ wrapper = createComponent({ sortPreferenceMutationResponse: mutationMock });
+ await waitForPromises();
+
+ findIssuableList().vm.$emit('sort', UPDATED_DESC);
+
+ expect(mutationMock).toHaveBeenCalledWith({ input: { issuesSort: UPDATED_DESC } });
+ });
+
+ it('captures error when mutation response has errors', async () => {
+ const mutationMock = jest
+ .fn()
+ .mockResolvedValue(setSortPreferenceMutationResponseWithErrors);
+ wrapper = createComponent({ sortPreferenceMutationResponse: mutationMock });
+ await waitForPromises();
+
+ findIssuableList().vm.$emit('sort', UPDATED_DESC);
+ await waitForPromises();
+
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error('oh no!'));
+ });
+ });
+
+ describe('when user is signed out', () => {
+ it('does not call mutation to save sort preference', async () => {
+ const mutationMock = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse);
+ wrapper = createComponent({
+ provide: { isSignedIn: false },
+ sortPreferenceMutationResponse: mutationMock,
+ });
+ await waitForPromises();
+
+ findIssuableList().vm.$emit('sort', CREATED_DESC);
+
+ expect(mutationMock).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe.each`
+ event | params
+ ${'next-page'} | ${{ page_after: 'endcursor', page_before: undefined, first_page_size: 20, last_page_size: undefined }}
+ ${'previous-page'} | ${{ page_after: undefined, page_before: 'startcursor', first_page_size: undefined, last_page_size: 20 }}
+ `('when "$event" event is emitted by IssuableList', ({ event, params }) => {
+ beforeEach(async () => {
+ wrapper = createComponent({
+ data: {
+ pageInfo: {
+ endCursor: 'endCursor',
+ startCursor: 'startCursor',
+ },
+ },
+ });
+ await waitForPromises();
+ router.push = jest.fn();
+
+ findIssuableList().vm.$emit(event);
+ });
+
+ it('scrolls to the top', () => {
+ expect(scrollUp).toHaveBeenCalled();
+ });
+
+ it('updates url', () => {
+ expect(router.push).toHaveBeenCalledWith({
+ query: expect.objectContaining(params),
+ });
+ });
+ });
+
+ describe('when "filter" event is emitted by IssuableList', () => {
+ it('updates IssuableList with url params', async () => {
+ wrapper = createComponent();
+ router.push = jest.fn();
+ await waitForPromises();
+
+ findIssuableList().vm.$emit('filter', filteredTokens);
+ await nextTick();
+
+ expect(router.push).toHaveBeenCalledWith({
+ query: expect.objectContaining(urlParams),
+ });
+ });
+ });
+
+ describe('when "page-size-change" event is emitted by IssuableList', () => {
+ it('updates url params with new page size', async () => {
+ wrapper = createComponent();
+ router.push = jest.fn();
+ await waitForPromises();
+
+ findIssuableList().vm.$emit('page-size-change', 50);
+ await nextTick();
+
+ expect(router.push).toHaveBeenCalledTimes(1);
+ expect(router.push).toHaveBeenCalledWith({
+ query: expect.objectContaining({ first_page_size: 50 }),
+ });
+ });
+ });
+ });
+
+ describe('Errors', () => {
+ describe.each`
+ error | responseHandler | message
+ ${'fetching issues'} | ${'serviceDeskIssuesQueryResponseHandler'} | ${'An error occurred while loading issues'}
+ ${'fetching issue counts'} | ${'serviceDeskIssuesCountsQueryResponseHandler'} | ${'An error occurred while getting issue counts'}
+ `('when there is an error $error', ({ responseHandler, message }) => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ [responseHandler]: jest.fn().mockRejectedValue(new Error('ERROR')),
+ });
+ return waitForPromises();
+ });
+
+ it('shows an error message', () => {
+ expect(findIssuableList().props('error')).toBe(message);
+ });
+
+ it('is captured with Sentry', () => {
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error('ERROR'));
+ });
+ });
+
+ it('clears error message when "dismiss-alert" event is emitted from IssuableList', async () => {
+ wrapper = createComponent({
+ serviceDeskIssuesQueryResponseHandler: jest.fn().mockRejectedValue(new Error()),
+ });
+ await waitForPromises();
+ findIssuableList().vm.$emit('dismiss-alert');
+ await nextTick();
+
+ expect(findIssuableList().props('error')).toBe('');
+ });
+ });
+
+ describe('When providing token for labels', () => {
+ it('passes function to fetchLatestLabels property if frontend caching is enabled', async () => {
+ wrapper = createComponent({
+ provide: {
+ glFeatures: {
+ frontendCaching: true,
+ },
+ },
+ });
+ await waitForPromises();
+
+ expect(typeof findLabelsToken().fetchLatestLabels).toBe('function');
+ });
+
+ it('passes null to fetchLatestLabels property if frontend caching is disabled', async () => {
+ wrapper = createComponent({
+ provide: {
+ glFeatures: {
+ frontendCaching: false,
+ },
+ },
+ });
+ await waitForPromises();
+
+ expect(findLabelsToken().fetchLatestLabels).toBe(null);
+ });
+ });
+});
diff --git a/spec/frontend/issues/service_desk/mock_data.js b/spec/frontend/issues/service_desk/mock_data.js
new file mode 100644
index 00000000000..1e2f209d732
--- /dev/null
+++ b/spec/frontend/issues/service_desk/mock_data.js
@@ -0,0 +1,253 @@
+import {
+ FILTERED_SEARCH_TERM,
+ OPERATOR_IS,
+ OPERATOR_NOT,
+ OPERATOR_OR,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_EPIC,
+ TOKEN_TYPE_ITERATION,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_WEIGHT,
+ TOKEN_TYPE_HEALTH,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+
+export const getServiceDeskIssuesQueryResponse = {
+ data: {
+ project: {
+ id: '1',
+ __typename: 'Project',
+ issues: {
+ __persist: true,
+ pageInfo: {
+ __typename: 'PageInfo',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'startcursor',
+ endCursor: 'endcursor',
+ },
+ nodes: [
+ {
+ __persist: true,
+ __typename: 'Issue',
+ id: 'gid://gitlab/Issue/123456',
+ iid: '789',
+ confidential: false,
+ createdAt: '2021-05-22T04:08:01Z',
+ downvotes: 2,
+ dueDate: '2021-05-29',
+ hidden: false,
+ humanTimeEstimate: null,
+ mergeRequestsCount: false,
+ moved: false,
+ state: 'opened',
+ title: 'Issue title',
+ updatedAt: '2021-05-22T04:08:01Z',
+ closedAt: null,
+ upvotes: 3,
+ userDiscussionsCount: 4,
+ webPath: 'project/-/issues/789',
+ webUrl: 'project/-/issues/789',
+ type: 'issue',
+ assignees: {
+ nodes: [
+ {
+ __persist: true,
+ __typename: 'UserCore',
+ id: 'gid://gitlab/User/234',
+ avatarUrl: 'avatar/url',
+ name: 'Marge Simpson',
+ username: 'msimpson',
+ webUrl: 'url/msimpson',
+ },
+ ],
+ },
+ author: {
+ __persist: true,
+ __typename: 'UserCore',
+ id: 'gid://gitlab/User/456',
+ avatarUrl: 'avatar/url',
+ name: 'GitLab Support Bot',
+ username: 'support-bot',
+ webUrl: 'url/hsimpson',
+ },
+ externalAuthor: 'client@client.com',
+ labels: {
+ nodes: [
+ {
+ __persist: true,
+ id: 'gid://gitlab/ProjectLabel/456',
+ color: '#333',
+ title: 'Label title',
+ description: 'Label description',
+ },
+ ],
+ },
+ milestone: null,
+ taskCompletionStatus: {
+ completedCount: 1,
+ count: 2,
+ },
+ },
+ ],
+ },
+ },
+ },
+};
+
+export const getServiceDeskIssuesQueryEmptyResponse = {
+ data: {
+ project: {
+ id: '1',
+ __typename: 'Project',
+ issues: {
+ __persist: true,
+ pageInfo: {
+ __typename: 'PageInfo',
+ hasNextPage: true,
+ hasPreviousPage: false,
+ startCursor: 'startcursor',
+ endCursor: 'endcursor',
+ },
+ nodes: [],
+ },
+ },
+ },
+};
+
+export const getServiceDeskIssuesCountsQueryResponse = {
+ data: {
+ project: {
+ id: '1',
+ openedIssues: {
+ count: 1,
+ },
+ closedIssues: {
+ count: 1,
+ },
+ allIssues: {
+ count: 1,
+ },
+ },
+ },
+};
+
+export const setSortPreferenceMutationResponse = {
+ data: {
+ userPreferencesUpdate: {
+ errors: [],
+ },
+ },
+};
+
+export const setSortPreferenceMutationResponseWithErrors = {
+ data: {
+ userPreferencesUpdate: {
+ errors: ['oh no!'],
+ },
+ },
+};
+
+export const filteredTokens = [
+ { type: FILTERED_SEARCH_TERM, value: { data: 'find issues', operator: 'undefined' } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'bart', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'lisa', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: '5', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'patty', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'selma', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'carl', operator: OPERATOR_OR } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'lenny', operator: OPERATOR_OR } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 3', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 4', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 20', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 30', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'cartoon', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'tv', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'live action', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'drama', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'comedy', operator: OPERATOR_OR } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'sitcom', operator: OPERATOR_OR } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v3', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v4', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v20', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v30', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_MY_REACTION, value: { data: 'thumbsup', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_MY_REACTION, value: { data: 'thumbsdown', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_CONFIDENTIAL, value: { data: 'yes', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: '4', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: '12', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: '20', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: '42', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_EPIC, value: { data: '12', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_EPIC, value: { data: '34', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_WEIGHT, value: { data: '1', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_WEIGHT, value: { data: '3', operator: OPERATOR_NOT } },
+ { type: TOKEN_TYPE_HEALTH, value: { data: 'atRisk', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_HEALTH, value: { data: 'onTrack', operator: OPERATOR_NOT } },
+];
+
+export const urlParams = {
+ search: 'find issues',
+ 'assignee_username[]': ['bart', 'lisa', '5'],
+ 'not[assignee_username][]': ['patty', 'selma'],
+ 'or[assignee_username][]': ['carl', 'lenny'],
+ milestone_title: ['season 3', 'season 4'],
+ 'not[milestone_title]': ['season 20', 'season 30'],
+ 'label_name[]': ['cartoon', 'tv'],
+ 'not[label_name][]': ['live action', 'drama'],
+ 'or[label_name][]': ['comedy', 'sitcom'],
+ release_tag: ['v3', 'v4'],
+ 'not[release_tag]': ['v20', 'v30'],
+ my_reaction_emoji: 'thumbsup',
+ 'not[my_reaction_emoji]': 'thumbsdown',
+ confidential: 'yes',
+ iteration_id: ['4', '12'],
+ 'not[iteration_id]': ['20', '42'],
+ epic_id: '12',
+ 'not[epic_id]': '34',
+ weight: '1',
+ 'not[weight]': '3',
+ health_status: 'atRisk',
+ 'not[health_status]': 'onTrack',
+};
+
+export const locationSearch = [
+ '?search=find+issues',
+ 'assignee_username[]=bart',
+ 'assignee_username[]=lisa',
+ 'assignee_username[]=5',
+ 'not[assignee_username][]=patty',
+ 'not[assignee_username][]=selma',
+ 'or[assignee_username][]=carl',
+ 'or[assignee_username][]=lenny',
+ 'milestone_title=season+3',
+ 'milestone_title=season+4',
+ 'not[milestone_title]=season+20',
+ 'not[milestone_title]=season+30',
+ 'label_name[]=cartoon',
+ 'label_name[]=tv',
+ 'not[label_name][]=live action',
+ 'not[label_name][]=drama',
+ 'or[label_name][]=comedy',
+ 'or[label_name][]=sitcom',
+ 'release_tag=v3',
+ 'release_tag=v4',
+ 'not[release_tag]=v20',
+ 'not[release_tag]=v30',
+ 'my_reaction_emoji=thumbsup',
+ 'not[my_reaction_emoji]=thumbsdown',
+ 'confidential=yes',
+ 'iteration_id=4',
+ 'iteration_id=12',
+ 'not[iteration_id]=20',
+ 'not[iteration_id]=42',
+ 'epic_id=12',
+ 'not[epic_id]=34',
+ 'weight=1',
+ 'not[weight]=3',
+ 'health_status=atRisk',
+ 'not[health_status]=onTrack',
+].join('&');
diff --git a/spec/frontend/issues/show/components/app_spec.js b/spec/frontend/issues/show/components/app_spec.js
index de183f94277..8999952c54c 100644
--- a/spec/frontend/issues/show/components/app_spec.js
+++ b/spec/frontend/issues/show/components/app_spec.js
@@ -1,23 +1,14 @@
-import { GlIcon, GlIntersectionObserver } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
-import {
- issuableStatusText,
- STATUS_CLOSED,
- STATUS_OPEN,
- STATUS_REOPENED,
- TYPE_EPIC,
- TYPE_INCIDENT,
- TYPE_ISSUE,
-} from '~/issues/constants';
+import { TYPE_EPIC, TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import IssuableApp from '~/issues/show/components/app.vue';
import DescriptionComponent from '~/issues/show/components/description.vue';
import EditedComponent from '~/issues/show/components/edited.vue';
import FormComponent from '~/issues/show/components/form.vue';
+import StickyHeader from '~/issues/show/components/sticky_header.vue';
import TitleComponent from '~/issues/show/components/title.vue';
import IncidentTabs from '~/issues/show/components/incidents/incident_tabs.vue';
import PinnedLinks from '~/issues/show/components/pinned_links.vue';
@@ -44,22 +35,15 @@ describe('Issuable output', () => {
let axiosMock;
let wrapper;
- const findStickyHeader = () => wrapper.findByTestId('issue-sticky-header');
- const findLockedBadge = () => wrapper.findByTestId('locked');
- const findConfidentialBadge = () => wrapper.findByTestId('confidential');
- const findHiddenBadge = () => wrapper.findByTestId('hidden');
-
+ const findStickyHeader = () => wrapper.findComponent(StickyHeader);
const findTitle = () => wrapper.findComponent(TitleComponent);
const findDescription = () => wrapper.findComponent(DescriptionComponent);
const findEdited = () => wrapper.findComponent(EditedComponent);
const findForm = () => wrapper.findComponent(FormComponent);
const findPinnedLinks = () => wrapper.findComponent(PinnedLinks);
- const createComponent = ({ props = {}, options = {}, data = {} } = {}) => {
- wrapper = shallowMountExtended(IssuableApp, {
- directives: {
- GlTooltip: createMockDirective('gl-tooltip'),
- },
+ const createComponent = ({ props = {}, options = {} } = {}) => {
+ wrapper = shallowMount(IssuableApp, {
propsData: { ...appProps, ...props },
provide: {
fullPath: 'gitlab-org/incidents',
@@ -69,11 +53,6 @@ describe('Issuable output', () => {
HighlightBar: true,
IncidentTabs: true,
},
- data() {
- return {
- ...data,
- };
- },
...options,
});
@@ -81,13 +60,6 @@ describe('Issuable output', () => {
return waitForPromises();
};
- const createComponentAndScroll = async (props) => {
- await createComponent({ props });
- global.pageYOffset = 100;
- wrapper.findComponent(GlIntersectionObserver).vm.$emit('disappear');
- await nextTick();
- };
-
const emitHubEvent = (event) => {
eventHub.$emit(event);
return waitForPromises();
@@ -332,104 +304,36 @@ describe('Issuable output', () => {
describe('when title is in view', () => {
it('is not shown', async () => {
await createComponent();
- wrapper.findComponent(GlIntersectionObserver).vm.$emit('disappear');
- expect(findStickyHeader().exists()).toBe(false);
+ wrapper.findComponent(StickyHeader).vm.$emit('show');
+
+ expect(findStickyHeader().props('show')).toBe(false);
});
});
- describe('when title is not in view', () => {
- it.each([TYPE_INCIDENT, TYPE_ISSUE, TYPE_EPIC])(
- 'shows with title when issuableType="%s"',
- async (issuableType) => {
- await createComponentAndScroll({ issuableType });
-
- expect(findStickyHeader().text()).toContain('this is a title');
- },
- );
-
- it.each`
- issuableType | issuableStatus | statusIcon
- ${TYPE_INCIDENT} | ${STATUS_OPEN} | ${'issues'}
- ${TYPE_INCIDENT} | ${STATUS_CLOSED} | ${'issue-closed'}
- ${TYPE_ISSUE} | ${STATUS_OPEN} | ${'issues'}
- ${TYPE_ISSUE} | ${STATUS_CLOSED} | ${'issue-closed'}
- ${TYPE_EPIC} | ${STATUS_OPEN} | ${'epic'}
- ${TYPE_EPIC} | ${STATUS_CLOSED} | ${'epic-closed'}
- `(
- 'shows with state icon "$statusIcon" for $issuableType when status is $issuableStatus',
- async ({ issuableType, issuableStatus, statusIcon }) => {
- await createComponentAndScroll({ issuableType, issuableStatus });
-
- expect(findStickyHeader().findComponent(GlIcon).props('name')).toBe(statusIcon);
- },
- );
-
- it.each`
- title | issuableStatus
- ${'shows with Open when status is opened'} | ${STATUS_OPEN}
- ${'shows with Closed when status is closed'} | ${STATUS_CLOSED}
- ${'shows with Open when status is reopened'} | ${STATUS_REOPENED}
- `('$title', async ({ issuableStatus }) => {
- await createComponentAndScroll({ issuableStatus });
-
- expect(findStickyHeader().text()).toContain(issuableStatusText[issuableStatus]);
- });
+ describe.each([TYPE_INCIDENT, TYPE_ISSUE, TYPE_EPIC])(
+ 'when title is not in view',
+ (issuableType) => {
+ beforeEach(async () => {
+ await createComponent({ props: { issuableType } });
- it.each`
- title | isConfidential
- ${'does not show confidential badge when issue is not confidential'} | ${false}
- ${'shows confidential badge when issue is confidential'} | ${true}
- `('$title', async ({ isConfidential }) => {
- await createComponentAndScroll({ isConfidential });
- const confidentialEl = findConfidentialBadge();
-
- expect(confidentialEl.exists()).toBe(isConfidential);
-
- if (isConfidential) {
- expect(confidentialEl.props()).toMatchObject({
- workspaceType: 'project',
- issuableType: 'issue',
- });
- }
- });
+ global.pageYOffset = 100;
+ wrapper.findComponent(StickyHeader).vm.$emit('show');
+ await nextTick();
+ });
- it.each`
- title | isLocked
- ${'does not show locked badge when issue is not locked'} | ${false}
- ${'shows locked badge when issue is locked'} | ${true}
- `('$title', async ({ isLocked }) => {
- await createComponentAndScroll({ isLocked });
- const lockedBadge = findLockedBadge();
-
- expect(lockedBadge.exists()).toBe(isLocked);
-
- if (isLocked) {
- expect(lockedBadge.attributes('title')).toBe(
- 'This issue is locked. Only project members can comment.',
- );
- expect(getBinding(lockedBadge.element, 'gl-tooltip')).not.toBeUndefined();
- }
- });
+ it(`shows when issuableType=${issuableType}`, () => {
+ expect(findStickyHeader().props('show')).toBe(true);
+ });
- it.each`
- title | isHidden
- ${'does not show hidden badge when issue is not hidden'} | ${false}
- ${'shows hidden badge when issue is hidden'} | ${true}
- `('$title', async ({ isHidden }) => {
- await createComponentAndScroll({ isHidden });
- const hiddenBadge = findHiddenBadge();
-
- expect(hiddenBadge.exists()).toBe(isHidden);
-
- if (isHidden) {
- expect(hiddenBadge.attributes('title')).toBe(
- 'This issue is hidden because its author has been banned',
- );
- expect(getBinding(hiddenBadge.element, 'gl-tooltip')).not.toBeUndefined();
- }
- });
- });
+ it('hides again when title is back in view', async () => {
+ wrapper.findComponent(StickyHeader).vm.$emit('hide');
+ await nextTick();
+
+ expect(findStickyHeader().props('show')).toBe(false);
+ });
+ },
+ );
});
describe('Composable description component', () => {
diff --git a/spec/frontend/issues/show/components/sticky_header_spec.js b/spec/frontend/issues/show/components/sticky_header_spec.js
new file mode 100644
index 00000000000..0c54ae45e70
--- /dev/null
+++ b/spec/frontend/issues/show/components/sticky_header_spec.js
@@ -0,0 +1,135 @@
+import { GlIcon } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import {
+ issuableStatusText,
+ STATUS_CLOSED,
+ STATUS_OPEN,
+ STATUS_REOPENED,
+ TYPE_EPIC,
+ TYPE_INCIDENT,
+ TYPE_ISSUE,
+} from '~/issues/constants';
+import StickyHeader from '~/issues/show/components/sticky_header.vue';
+import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
+
+describe('StickyHeader component', () => {
+ let wrapper;
+
+ const findConfidentialBadge = () => wrapper.findComponent(ConfidentialityBadge);
+ const findHiddenBadge = () => wrapper.findByTestId('hidden');
+ const findLockedBadge = () => wrapper.findByTestId('locked');
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMountExtended(StickyHeader, {
+ directives: {
+ GlTooltip: createMockDirective('gl-tooltip'),
+ },
+ propsData: {
+ issuableStatus: STATUS_OPEN,
+ issuableType: TYPE_ISSUE,
+ show: true,
+ title: 'A sticky issue',
+ titleHtml: '',
+ ...props,
+ },
+ });
+ };
+
+ it.each`
+ issuableType | issuableStatus | statusIcon
+ ${TYPE_INCIDENT} | ${STATUS_OPEN} | ${'issues'}
+ ${TYPE_INCIDENT} | ${STATUS_CLOSED} | ${'issue-closed'}
+ ${TYPE_ISSUE} | ${STATUS_OPEN} | ${'issues'}
+ ${TYPE_ISSUE} | ${STATUS_CLOSED} | ${'issue-closed'}
+ ${TYPE_EPIC} | ${STATUS_OPEN} | ${'epic'}
+ ${TYPE_EPIC} | ${STATUS_CLOSED} | ${'epic-closed'}
+ `(
+ 'shows with state icon "$statusIcon" for $issuableType when status is $issuableStatus',
+ ({ issuableType, issuableStatus, statusIcon }) => {
+ createComponent({ issuableType, issuableStatus });
+
+ expect(wrapper.findComponent(GlIcon).props('name')).toBe(statusIcon);
+ },
+ );
+
+ it.each`
+ title | issuableStatus
+ ${'shows with Open when status is opened'} | ${STATUS_OPEN}
+ ${'shows with Closed when status is closed'} | ${STATUS_CLOSED}
+ ${'shows with Open when status is reopened'} | ${STATUS_REOPENED}
+ `('$title', ({ issuableStatus }) => {
+ createComponent({ issuableStatus });
+
+ expect(wrapper.text()).toContain(issuableStatusText[issuableStatus]);
+ });
+
+ it.each`
+ title | isConfidential
+ ${'does not show confidential badge when issue is not confidential'} | ${false}
+ ${'shows confidential badge when issue is confidential'} | ${true}
+ `('$title', ({ isConfidential }) => {
+ createComponent({ isConfidential });
+ const confidentialBadge = findConfidentialBadge();
+
+ expect(confidentialBadge.exists()).toBe(isConfidential);
+
+ if (isConfidential) {
+ expect(confidentialBadge.props()).toMatchObject({
+ workspaceType: 'project',
+ issuableType: 'issue',
+ });
+ }
+ });
+
+ it.each`
+ title | isLocked
+ ${'does not show locked badge when issue is not locked'} | ${false}
+ ${'shows locked badge when issue is locked'} | ${true}
+ `('$title', ({ isLocked }) => {
+ createComponent({ isLocked });
+ const lockedBadge = findLockedBadge();
+
+ expect(lockedBadge.exists()).toBe(isLocked);
+
+ if (isLocked) {
+ expect(lockedBadge.attributes('title')).toBe(
+ 'This issue is locked. Only project members can comment.',
+ );
+ expect(getBinding(lockedBadge.element, 'gl-tooltip')).not.toBeUndefined();
+ }
+ });
+
+ it.each`
+ title | isHidden
+ ${'does not show hidden badge when issue is not hidden'} | ${false}
+ ${'shows hidden badge when issue is hidden'} | ${true}
+ `('$title', ({ isHidden }) => {
+ createComponent({ isHidden });
+ const hiddenBadge = findHiddenBadge();
+
+ expect(hiddenBadge.exists()).toBe(isHidden);
+
+ if (isHidden) {
+ expect(hiddenBadge.attributes('title')).toBe(
+ 'This issue is hidden because its author has been banned',
+ );
+ expect(getBinding(hiddenBadge.element, 'gl-tooltip')).not.toBeUndefined();
+ }
+ });
+
+ it('shows with title', () => {
+ createComponent();
+ const title = wrapper.find('a');
+
+ expect(title.text()).toContain('A sticky issue');
+ expect(title.attributes('href')).toBe('#top');
+ });
+
+ it('shows title containing markup', () => {
+ const titleHtml = '<b>A sticky issue</b>';
+ createComponent({ titleHtml });
+
+ expect(wrapper.find('a').html()).toContain(titleHtml);
+ });
+});
diff --git a/spec/frontend/issues/show/components/task_list_item_actions_spec.js b/spec/frontend/issues/show/components/task_list_item_actions_spec.js
index 93cb7b5ae16..b2e57bf49d0 100644
--- a/spec/frontend/issues/show/components/task_list_item_actions_spec.js
+++ b/spec/frontend/issues/show/components/task_list_item_actions_spec.js
@@ -1,5 +1,6 @@
-import { GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { GlDisclosureDropdown } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { TYPE_EPIC, TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import TaskListItemActions from '~/issues/show/components/task_list_item_actions.vue';
import eventHub from '~/issues/show/event_hub';
@@ -9,26 +10,24 @@ describe('TaskListItemActions component', () => {
let wrapper;
const findGlDisclosureDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
- const findConvertToTaskItem = () => wrapper.findAllComponents(GlDisclosureDropdownItem).at(0);
- const findDeleteItem = () => wrapper.findAllComponents(GlDisclosureDropdownItem).at(1);
+ const findConvertToTaskItem = () => wrapper.findByTestId('convert');
+ const findDeleteItem = () => wrapper.findByTestId('delete');
- const mountComponent = () => {
+ const mountComponent = ({ issuableType = TYPE_ISSUE } = {}) => {
const li = document.createElement('li');
li.dataset.sourcepos = '3:1-3:10';
li.appendChild(document.createElement('div'));
document.body.appendChild(li);
- wrapper = shallowMount(TaskListItemActions, {
- provide: { canUpdate: true },
+ wrapper = shallowMountExtended(TaskListItemActions, {
+ provide: { canUpdate: true, issuableType },
attachTo: document.querySelector('div'),
});
};
- beforeEach(() => {
+ it('renders dropdown', () => {
mountComponent();
- });
- it('renders dropdown', () => {
expect(findGlDisclosureDropdown().props()).toMatchObject({
category: 'tertiary',
icon: 'ellipsis_v',
@@ -38,15 +37,36 @@ describe('TaskListItemActions component', () => {
});
});
- it('emits event when `Convert to task` dropdown item is clicked', () => {
- findConvertToTaskItem().vm.$emit('action');
+ describe('"Convert to task" dropdown item', () => {
+ describe.each`
+ issuableType | exists
+ ${TYPE_EPIC} | ${false}
+ ${TYPE_INCIDENT} | ${true}
+ ${TYPE_ISSUE} | ${true}
+ `(`when $issuableType`, ({ issuableType, exists }) => {
+ it(`${exists ? 'renders' : 'does not render'}`, () => {
+ mountComponent({ issuableType });
- expect(eventHub.$emit).toHaveBeenCalledWith('convert-task-list-item', '3:1-3:10');
+ expect(findConvertToTaskItem().exists()).toBe(exists);
+ });
+ });
});
- it('emits event when `Delete` dropdown item is clicked', () => {
- findDeleteItem().vm.$emit('action');
+ describe('events', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('emits event when `Convert to task` dropdown item is clicked', () => {
+ findConvertToTaskItem().vm.$emit('action');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('convert-task-list-item', '3:1-3:10');
+ });
- expect(eventHub.$emit).toHaveBeenCalledWith('delete-task-list-item', '3:1-3:10');
+ it('emits event when `Delete` dropdown item is clicked', () => {
+ findDeleteItem().vm.$emit('action');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('delete-task-list-item', '3:1-3:10');
+ });
});
});
diff --git a/spec/frontend/issues/show/issue_spec.js b/spec/frontend/issues/show/issue_spec.js
deleted file mode 100644
index 561035242eb..00000000000
--- a/spec/frontend/issues/show/issue_spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import waitForPromises from 'helpers/wait_for_promises';
-import { initIssueApp } from '~/issues/show';
-import * as parseData from '~/issues/show/utils/parse_data';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import createStore from '~/notes/stores';
-import { appProps } from './mock_data/mock_data';
-
-const mock = new MockAdapter(axios);
-mock.onGet().reply(HTTP_STATUS_OK);
-
-jest.mock('~/lib/utils/poll');
-
-const setupHTML = (initialData) => {
- document.body.innerHTML = `<div id="js-issuable-app"></div>`;
- document.getElementById('js-issuable-app').dataset.initial = JSON.stringify(initialData);
-};
-
-describe('Issue show index', () => {
- describe('initIssueApp', () => {
- // quarantine: https://gitlab.com/gitlab-org/gitlab/-/issues/390368
- // eslint-disable-next-line jest/no-disabled-tests
- it.skip('should initialize app with no potential XSS attack', async () => {
- const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
- const parseDataSpy = jest.spyOn(parseData, 'parseIssuableData');
-
- setupHTML({
- ...appProps,
- initialDescriptionHtml: '<svg onload=window.alert(1)>',
- });
-
- const initialDataEl = document.getElementById('js-issuable-app');
- const issuableData = parseData.parseIssuableData(initialDataEl);
- initIssueApp(issuableData, createStore());
-
- await waitForPromises();
-
- expect(parseDataSpy).toHaveBeenCalled();
- expect(alertSpy).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/issues/show/mock_data/mock_data.js b/spec/frontend/issues/show/mock_data/mock_data.js
index ed969a08ac5..37aa18ced8d 100644
--- a/spec/frontend/issues/show/mock_data/mock_data.js
+++ b/spec/frontend/issues/show/mock_data/mock_data.js
@@ -1,8 +1,9 @@
import { TEST_HOST } from 'helpers/test_constants';
export const initialRequest = {
- title: '<p>this is a title</p>',
+ title: '<gl-emoji title="party-parrot"></gl-emoji>this is a title',
title_text: 'this is a title',
+ title_html: '<gl-emoji title="party-parrot"></gl-emoji>this is a title',
description: '<p>this is a description!</p>',
description_text: 'this is a description',
task_completion_status: { completed_count: 2, count: 4 },
diff --git a/spec/frontend/issues/show/store_spec.js b/spec/frontend/issues/show/store_spec.js
deleted file mode 100644
index 20d3a6cdaae..00000000000
--- a/spec/frontend/issues/show/store_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import Store from '~/issues/show/stores';
-import updateDescription from '~/issues/show/utils/update_description';
-
-jest.mock('~/issues/show/utils/update_description');
-
-describe('Store', () => {
- let store;
-
- beforeEach(() => {
- store = new Store({
- descriptionHtml: '<p>This is a description</p>',
- });
- });
-
- describe('updateState', () => {
- beforeEach(() => {
- document.body.innerHTML = `
- <div class="detail-page-description content-block">
- <details open>
- <summary>One</summary>
- </details>
- <details>
- <summary>Two</summary>
- </details>
- </div>
- `;
- });
-
- afterEach(() => {
- document.getElementsByTagName('html')[0].innerHTML = '';
- });
-
- it('calls updateDetailsState', () => {
- store.updateState({ description: '' });
-
- expect(updateDescription).toHaveBeenCalledTimes(1);
- });
- });
-});
diff --git a/spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js b/spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js
index cf2dacb50d8..95658f66d09 100644
--- a/spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js
+++ b/spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js
@@ -1,58 +1,45 @@
-import { GlCollapsibleListbox } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
+import { GlCollapsibleListbox } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
+
import SourceBranchDropdown from '~/jira_connect/branches/components/source_branch_dropdown.vue';
import { BRANCHES_PER_PAGE } from '~/jira_connect/branches/constants';
import getProjectQuery from '~/jira_connect/branches/graphql/queries/get_project.query.graphql';
-import { mockProjects } from '../mock_data';
-
-const mockProject = {
- id: 'test',
- repository: {
- branchNames: ['main', 'f-test', 'release'],
- rootRef: 'main',
- },
-};
-const mockSelectedProject = mockProjects[0];
-
-const mockProjectQueryResponse = {
- data: {
- project: mockProject,
- },
-};
-const mockGetProjectQuery = jest.fn().mockResolvedValue(mockProjectQueryResponse);
-const mockQueryLoading = jest.fn().mockReturnValue(new Promise(() => {}));
+import {
+ mockBranchNames,
+ mockBranchNames2,
+ mockProjects,
+ mockProjectQueryResponse,
+} from '../mock_data';
+
+Vue.use(VueApollo);
describe('SourceBranchDropdown', () => {
let wrapper;
+ const mockSelectedProject = mockProjects[0];
+ const querySuccessHandler = jest.fn().mockResolvedValue(mockProjectQueryResponse());
+ const queryLoadingHandler = jest.fn().mockReturnValue(new Promise(() => {}));
+
const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
- const assertListboxItems = () => {
+ const assertListboxItems = (branchNames = mockBranchNames) => {
const listboxItems = findListbox().props('items');
- expect(listboxItems).toHaveLength(mockProject.repository.branchNames.length);
- expect(listboxItems.map((item) => item.text)).toEqual(mockProject.repository.branchNames);
+ expect(listboxItems).toHaveLength(branchNames.length);
+ expect(listboxItems.map((item) => item.text)).toEqual(branchNames);
};
- function createMockApolloProvider({ getProjectQueryLoading = false } = {}) {
- Vue.use(VueApollo);
-
- const mockApollo = createMockApollo([
- [getProjectQuery, getProjectQueryLoading ? mockQueryLoading : mockGetProjectQuery],
- ]);
+ const createComponent = ({ props, handler = querySuccessHandler } = {}) => {
+ const mockApollo = createMockApollo([[getProjectQuery, handler]]);
- return mockApollo;
- }
-
- function createComponent({ mockApollo, props, mountFn = shallowMount } = {}) {
- wrapper = mountFn(SourceBranchDropdown, {
- apolloProvider: mockApollo || createMockApolloProvider(),
+ wrapper = shallowMount(SourceBranchDropdown, {
+ apolloProvider: mockApollo,
propsData: props,
});
- }
+ };
describe('when `selectedProject` prop is not specified', () => {
beforeEach(() => {
@@ -78,6 +65,7 @@ describe('SourceBranchDropdown', () => {
loading: false,
searchable: true,
searching: false,
+ selected: null,
toggleText: 'Select a branch',
});
});
@@ -92,23 +80,26 @@ describe('SourceBranchDropdown', () => {
describe('when branches are loading', () => {
it('sets loading prop to true', () => {
createComponent({
- mockApollo: createMockApolloProvider({ getProjectQueryLoading: true }),
props: { selectedProject: mockSelectedProject },
+ handler: queryLoadingHandler,
});
- expect(findListbox().props('loading')).toEqual(true);
+ expect(findListbox().props('loading')).toBe(true);
});
});
describe('when branches have loaded', () => {
describe('when searching branches', () => {
it('triggers a refetch', async () => {
- createComponent({ mountFn: mount, props: { selectedProject: mockSelectedProject } });
+ createComponent({ props: { selectedProject: mockSelectedProject } });
await waitForPromises();
const mockSearchTerm = 'mai';
+ expect(querySuccessHandler).toHaveBeenCalledTimes(1);
+
await findListbox().vm.$emit('search', mockSearchTerm);
- expect(mockGetProjectQuery).toHaveBeenCalledWith({
+ expect(querySuccessHandler).toHaveBeenCalledTimes(2);
+ expect(querySuccessHandler).toHaveBeenLastCalledWith({
branchNamesLimit: BRANCHES_PER_PAGE,
branchNamesOffset: 0,
branchNamesSearchPattern: `*${mockSearchTerm}*`,
@@ -129,10 +120,15 @@ describe('SourceBranchDropdown', () => {
loading: false,
searchable: true,
searching: false,
+ selected: null,
toggleText: 'Select a branch',
});
});
+ it('disables infinite scroll', () => {
+ expect(findListbox().props('infiniteScroll')).toBe(false);
+ });
+
it('omits monospace styling from listbox', () => {
expect(findListbox().classes()).not.toContain('gl-font-monospace');
});
@@ -142,19 +138,19 @@ describe('SourceBranchDropdown', () => {
});
it("emits `change` event with the repository's `rootRef` by default", () => {
- expect(wrapper.emitted('change')[0]).toEqual([mockProject.repository.rootRef]);
+ expect(wrapper.emitted('change')[0]).toEqual([mockBranchNames[0]]);
});
describe('when selecting a listbox item', () => {
it('emits `change` event with the selected branch name', () => {
- const mockBranchName = mockProject.repository.branchNames[1];
+ const mockBranchName = mockBranchNames[1];
findListbox().vm.$emit('select', mockBranchName);
expect(wrapper.emitted('change')[1]).toEqual([mockBranchName]);
});
});
describe('when `selectedBranchName` prop is specified', () => {
- const mockBranchName = mockProject.repository.branchNames[2];
+ const mockBranchName = mockBranchNames[2];
beforeEach(() => {
wrapper.setProps({
@@ -162,6 +158,10 @@ describe('SourceBranchDropdown', () => {
});
});
+ it('sets listbox selected to `selectedBranchName`', () => {
+ expect(findListbox().props('selected')).toBe(mockBranchName);
+ });
+
it('sets listbox text to `selectedBranchName` value', () => {
expect(findListbox().props('toggleText')).toBe(mockBranchName);
});
@@ -170,6 +170,66 @@ describe('SourceBranchDropdown', () => {
expect(findListbox().classes()).toContain('gl-font-monospace');
});
});
+
+ describe('when full page of branches returns', () => {
+ const fullPageBranchNames = Array(BRANCHES_PER_PAGE)
+ .fill(1)
+ .map((_, i) => mockBranchNames[i % mockBranchNames.length]);
+
+ beforeEach(async () => {
+ createComponent({
+ props: { selectedProject: mockSelectedProject },
+ handler: () => Promise.resolve(mockProjectQueryResponse(fullPageBranchNames)),
+ });
+ await waitForPromises();
+ });
+
+ it('enables infinite scroll', () => {
+ expect(findListbox().props('infiniteScroll')).toBe(true);
+ });
+ });
+ });
+
+ describe('when loading more branches from infinite scroll', () => {
+ const queryLoadMoreHandler = jest.fn();
+
+ beforeEach(async () => {
+ queryLoadMoreHandler.mockResolvedValueOnce(mockProjectQueryResponse());
+ queryLoadMoreHandler.mockResolvedValueOnce(mockProjectQueryResponse(mockBranchNames2));
+ createComponent({
+ props: { selectedProject: mockSelectedProject },
+ handler: queryLoadMoreHandler,
+ });
+
+ await waitForPromises();
+
+ await findListbox().vm.$emit('bottom-reached');
+ });
+
+ it('sets loading more prop to true', () => {
+ expect(findListbox().props('infiniteScrollLoading')).toBe(true);
+ });
+
+ it('triggers load more query', () => {
+ expect(queryLoadMoreHandler).toHaveBeenLastCalledWith({
+ branchNamesLimit: BRANCHES_PER_PAGE,
+ branchNamesOffset: 3,
+ branchNamesSearchPattern: '*',
+ projectPath: 'test-path',
+ });
+ });
+
+ it('renders available source branches as listbox items', async () => {
+ await waitForPromises();
+
+ assertListboxItems([...mockBranchNames, ...mockBranchNames2]);
+ });
+
+ it('sets loading more prop to false once done', async () => {
+ await waitForPromises();
+
+ expect(findListbox().props('infiniteScrollLoading')).toBe(false);
+ });
});
});
});
diff --git a/spec/frontend/jira_connect/branches/mock_data.js b/spec/frontend/jira_connect/branches/mock_data.js
index 742ab5392c8..1720e0118c8 100644
--- a/spec/frontend/jira_connect/branches/mock_data.js
+++ b/spec/frontend/jira_connect/branches/mock_data.js
@@ -1,3 +1,6 @@
+export const mockBranchNames = ['main', 'f-test', 'release'];
+export const mockBranchNames2 = ['dev', 'dev-1', 'dev-2'];
+
export const mockProjects = [
{
id: 'test',
@@ -28,3 +31,15 @@ export const mockProjects = [
},
},
];
+
+export const mockProjectQueryResponse = (branchNames = mockBranchNames) => ({
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/27',
+ repository: {
+ branchNames,
+ rootRef: 'main',
+ },
+ },
+ },
+});
diff --git a/spec/frontend/jira_connect/subscriptions/components/__snapshots__/group_item_name_spec.js.snap b/spec/frontend/jira_connect/subscriptions/components/__snapshots__/group_item_name_spec.js.snap
index 21c903f064d..af9f827117f 100644
--- a/spec/frontend/jira_connect/subscriptions/components/__snapshots__/group_item_name_spec.js.snap
+++ b/spec/frontend/jira_connect/subscriptions/components/__snapshots__/group_item_name_spec.js.snap
@@ -2,16 +2,15 @@
exports[`GroupItemName template matches the snapshot 1`] = `
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
>
<gl-icon-stub
class="gl-mr-3"
name="folder-o"
size="16"
/>
-
<div
- class="gl-display-none gl-flex-shrink-0 gl-sm-display-flex gl-mr-3"
+ class="gl-display-none gl-flex-shrink-0 gl-mr-3 gl-sm-display-flex"
>
<gl-avatar-stub
alt="avatar"
@@ -22,19 +21,15 @@ exports[`GroupItemName template matches the snapshot 1`] = `
src="avatar.png"
/>
</div>
-
<div>
<span
- class="gl-mr-3 gl-text-gray-900! gl-font-weight-bold"
+ class="gl-font-weight-bold gl-mr-3 gl-text-gray-900!"
>
-
Gitlab Org
-
</span>
-
<div>
<p
- class="gl-mt-2! gl-mb-0 gl-text-gray-600"
+ class="gl-mb-0 gl-mt-2! gl-text-gray-600"
>
Open source software to collaborate on code
</p>
diff --git a/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap b/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
index abd849b387e..263deb3b616 100644
--- a/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
+++ b/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
@@ -4,23 +4,17 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<table
aria-busy=""
aria-colcount="3"
- class="table b-table gl-table b-table-fixed"
+ class="b-table b-table-fixed gl-table table"
role="table"
>
- <!---->
- <!---->
<thead
- class=""
role="rowgroup"
>
- <!---->
<tr
- class=""
role="row"
>
<th
aria-colindex="1"
- class=""
role="columnheader"
scope="col"
>
@@ -31,7 +25,6 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<th
aria-colindex="2"
aria-label="Arrow"
- class=""
role="columnheader"
scope="col"
>
@@ -39,7 +32,6 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
</th>
<th
aria-colindex="3"
- class=""
role="columnheader"
scope="col"
>
@@ -52,21 +44,17 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<tbody
role="rowgroup"
>
- <!---->
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
Jane Doe
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
<svg
@@ -82,33 +70,26 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
</td>
<td
aria-colindex="3"
- class=""
role="cell"
>
<div
aria-label="The GitLab user to which the Jira user Jane Doe will be mapped"
- class="dropdown b-dropdown gl-dropdown w-100 btn-group"
+ class="b-dropdown btn-group dropdown gl-dropdown w-100"
>
- <!---->
<button
aria-expanded="false"
aria-haspopup="menu"
- class="btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle"
+ class="btn btn-default btn-md dropdown-toggle gl-button gl-dropdown-toggle"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-dropdown-button-text"
>
janedoe
</span>
-
<svg
aria-hidden="true"
- class="gl-button-icon dropdown-chevron gl-icon s16"
+ class="dropdown-chevron gl-button-icon gl-icon s16"
data-testid="chevron-down-icon"
role="img"
>
@@ -125,21 +106,15 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<div
class="gl-dropdown-inner"
>
- <!---->
-
- <!---->
-
<div
class="gl-dropdown-contents"
>
- <!---->
-
<div
class="gl-search-box-by-type"
>
<svg
aria-hidden="true"
- class="gl-search-box-by-type-search-icon gl-icon s16"
+ class="gl-icon gl-search-box-by-type-search-icon s16"
data-testid="search-icon"
role="img"
>
@@ -147,17 +122,13 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
href="file-mock#search"
/>
</svg>
-
<input
aria-label="Search"
- class="gl-form-input form-control gl-search-box-by-type-input"
+ class="form-control gl-form-input gl-search-box-by-type-input"
placeholder="Search"
type="search"
/>
-
- <!---->
</div>
-
<li
class="gl-dropdown-text text-secondary"
role="presentation"
@@ -165,33 +136,26 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<p
class="b-dropdown-text"
>
-
- No matches found
-
+ No matches found
</p>
</li>
</div>
-
- <!---->
</div>
</ul>
</div>
</td>
</tr>
<tr
- class=""
role="row"
>
<td
aria-colindex="1"
- class=""
role="cell"
>
Fred Chopin
</td>
<td
aria-colindex="2"
- class=""
role="cell"
>
<svg
@@ -207,33 +171,26 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
</td>
<td
aria-colindex="3"
- class=""
role="cell"
>
<div
aria-label="The GitLab user to which the Jira user Fred Chopin will be mapped"
- class="dropdown b-dropdown gl-dropdown w-100 btn-group"
+ class="b-dropdown btn-group dropdown gl-dropdown w-100"
>
- <!---->
<button
aria-expanded="false"
aria-haspopup="menu"
- class="btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle"
+ class="btn btn-default btn-md dropdown-toggle gl-button gl-dropdown-toggle"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-dropdown-button-text"
>
mrgitlab
</span>
-
<svg
aria-hidden="true"
- class="gl-button-icon dropdown-chevron gl-icon s16"
+ class="dropdown-chevron gl-button-icon gl-icon s16"
data-testid="chevron-down-icon"
role="img"
>
@@ -250,21 +207,15 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<div
class="gl-dropdown-inner"
>
- <!---->
-
- <!---->
-
<div
class="gl-dropdown-contents"
>
- <!---->
-
<div
class="gl-search-box-by-type"
>
<svg
aria-hidden="true"
- class="gl-search-box-by-type-search-icon gl-icon s16"
+ class="gl-icon gl-search-box-by-type-search-icon s16"
data-testid="search-icon"
role="img"
>
@@ -272,17 +223,13 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
href="file-mock#search"
/>
</svg>
-
<input
aria-label="Search"
- class="gl-form-input form-control gl-search-box-by-type-input"
+ class="form-control gl-form-input gl-search-box-by-type-input"
placeholder="Search"
type="search"
/>
-
- <!---->
</div>
-
<li
class="gl-dropdown-text text-secondary"
role="presentation"
@@ -290,22 +237,15 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<p
class="b-dropdown-text"
>
-
- No matches found
-
+ No matches found
</p>
</li>
</div>
-
- <!---->
</div>
</ul>
</div>
</td>
</tr>
- <!---->
- <!---->
</tbody>
- <!---->
</table>
`;
diff --git a/spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js b/spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js
deleted file mode 100644
index 5ecddc7efd6..00000000000
--- a/spec/frontend/jobs/components/filtered_search/jobs_filtered_search_spec.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { GlFilteredSearch } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import {
- OPERATORS_IS,
- TOKEN_TITLE_STATUS,
- TOKEN_TYPE_STATUS,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import JobsFilteredSearch from '~/jobs/components/filtered_search/jobs_filtered_search.vue';
-import { mockFailedSearchToken } from '../../mock_data';
-
-describe('Jobs filtered search', () => {
- let wrapper;
-
- const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
- const getSearchToken = (type) =>
- findFilteredSearch()
- .props('availableTokens')
- .find((token) => token.type === type);
-
- const findStatusToken = () => getSearchToken('status');
-
- const createComponent = (props) => {
- wrapper = shallowMount(JobsFilteredSearch, {
- propsData: {
- ...props,
- },
- });
- };
-
- it('displays filtered search', () => {
- createComponent();
-
- expect(findFilteredSearch().exists()).toBe(true);
- });
-
- it('displays status token', () => {
- createComponent();
-
- expect(findStatusToken()).toMatchObject({
- type: TOKEN_TYPE_STATUS,
- icon: 'status',
- title: TOKEN_TITLE_STATUS,
- unique: true,
- operators: OPERATORS_IS,
- });
- });
-
- it('emits filter token to parent component', () => {
- createComponent();
-
- findFilteredSearch().vm.$emit('submit', mockFailedSearchToken);
-
- expect(wrapper.emitted('filterJobsBySearch')).toEqual([[mockFailedSearchToken]]);
- });
-
- it('filtered search value is empty array when no query string is passed', () => {
- createComponent();
-
- expect(findFilteredSearch().props('value')).toEqual([]);
- });
-
- it('filtered search returns correct data shape when passed query string', () => {
- const value = 'SUCCESS';
-
- createComponent({ queryString: { statuses: value } });
-
- expect(findFilteredSearch().props('value')).toEqual([
- { type: TOKEN_TYPE_STATUS, value: { data: value, operator: '=' } },
- ]);
- });
-});
diff --git a/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js b/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js
deleted file mode 100644
index 6755b854f01..00000000000
--- a/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { stubComponent } from 'helpers/stub_component';
-import JobStatusToken from '~/jobs/components/filtered_search/tokens/job_status_token.vue';
-import {
- TOKEN_TITLE_STATUS,
- TOKEN_TYPE_STATUS,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-
-describe('Job Status Token', () => {
- let wrapper;
-
- const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
- const findAllFilteredSearchSuggestions = () =>
- wrapper.findAllComponents(GlFilteredSearchSuggestion);
- const findAllGlIcons = () => wrapper.findAllComponents(GlIcon);
-
- const defaultProps = {
- config: {
- type: TOKEN_TYPE_STATUS,
- icon: 'status',
- title: TOKEN_TITLE_STATUS,
- unique: true,
- },
- value: {
- data: '',
- },
- cursorPosition: 'start',
- };
-
- const createComponent = () => {
- wrapper = shallowMount(JobStatusToken, {
- propsData: {
- ...defaultProps,
- },
- stubs: {
- GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
- template: `<div><slot name="suggestions"></slot></div>`,
- }),
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('passes config correctly', () => {
- expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
- });
-
- it('renders all job statuses available', () => {
- const expectedLength = 11;
-
- expect(findAllFilteredSearchSuggestions()).toHaveLength(expectedLength);
- expect(findAllGlIcons()).toHaveLength(expectedLength);
- });
-});
diff --git a/spec/frontend/jobs/components/filtered_search/utils_spec.js b/spec/frontend/jobs/components/filtered_search/utils_spec.js
deleted file mode 100644
index 8440ab42b86..00000000000
--- a/spec/frontend/jobs/components/filtered_search/utils_spec.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { validateQueryString } from '~/jobs/components/filtered_search/utils';
-
-describe('Filtered search utils', () => {
- describe('validateQueryString', () => {
- it.each`
- queryStringObject | expected
- ${{ statuses: 'SUCCESS' }} | ${{ statuses: 'SUCCESS' }}
- ${{ statuses: 'failed' }} | ${{ statuses: 'FAILED' }}
- ${{ wrong: 'SUCCESS' }} | ${null}
- ${{ statuses: 'wrong' }} | ${null}
- ${{ wrong: 'wrong' }} | ${null}
- `(
- 'when provided $queryStringObject, the expected result is $expected',
- ({ queryStringObject, expected }) => {
- expect(validateQueryString(queryStringObject)).toEqual(expected);
- },
- );
- });
-});
diff --git a/spec/frontend/jobs/components/job/artifacts_block_spec.js b/spec/frontend/jobs/components/job/artifacts_block_spec.js
deleted file mode 100644
index f9e52a5ae43..00000000000
--- a/spec/frontend/jobs/components/job/artifacts_block_spec.js
+++ /dev/null
@@ -1,193 +0,0 @@
-import { GlPopover } from '@gitlab/ui';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { trimText } from 'helpers/text_helper';
-import ArtifactsBlock from '~/jobs/components/job/sidebar/artifacts_block.vue';
-import { getTimeago } from '~/lib/utils/datetime_utility';
-
-describe('Artifacts block', () => {
- let wrapper;
-
- const createWrapper = (propsData) =>
- mountExtended(ArtifactsBlock, {
- propsData: {
- helpUrl: 'help-url',
- ...propsData,
- },
- });
-
- const findArtifactRemoveElt = () => wrapper.findByTestId('artifacts-remove-timeline');
- const findJobLockedElt = () => wrapper.findByTestId('job-locked-message');
- const findKeepBtn = () => wrapper.findByTestId('keep-artifacts');
- const findDownloadBtn = () => wrapper.findByTestId('download-artifacts');
- const findBrowseBtn = () => wrapper.findByTestId('browse-artifacts');
- const findArtifactsHelpLink = () => wrapper.findByTestId('artifacts-help-link');
- const findPopover = () => wrapper.findComponent(GlPopover);
-
- const expireAt = '2018-08-14T09:38:49.157Z';
- const timeago = getTimeago();
- const formattedDate = timeago.format(expireAt);
- const lockedText =
- 'These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available.';
-
- const expiredArtifact = {
- expire_at: expireAt,
- expired: true,
- locked: false,
- };
-
- const nonExpiredArtifact = {
- download_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/download',
- browse_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/browse',
- keep_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/keep',
- expire_at: expireAt,
- expired: false,
- locked: false,
- };
-
- const lockedExpiredArtifact = {
- ...expiredArtifact,
- download_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/download',
- browse_path: '/gitlab-org/gitlab-foss/-/jobs/98314558/artifacts/browse',
- expired: true,
- locked: true,
- };
-
- const lockedNonExpiredArtifact = {
- ...nonExpiredArtifact,
- keep_path: undefined,
- locked: true,
- };
-
- describe('with expired artifacts that are not locked', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: expiredArtifact,
- });
- });
-
- it('renders expired artifact date and info', () => {
- expect(trimText(findArtifactRemoveElt().text())).toBe(
- `The artifacts were removed ${formattedDate}`,
- );
-
- expect(
- findArtifactRemoveElt()
- .find('[data-testid="artifact-expired-help-link"]')
- .attributes('href'),
- ).toBe('help-url');
- });
-
- it('does not show the keep button', () => {
- expect(findKeepBtn().exists()).toBe(false);
- });
-
- it('does not show the download button', () => {
- expect(findDownloadBtn().exists()).toBe(false);
- });
-
- it('does not show the browse button', () => {
- expect(findBrowseBtn().exists()).toBe(false);
- });
- });
-
- describe('with artifacts that will expire', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: nonExpiredArtifact,
- });
- });
-
- it('renders will expire artifact date and info', () => {
- expect(trimText(findArtifactRemoveElt().text())).toBe(
- `The artifacts will be removed ${formattedDate}`,
- );
-
- expect(
- findArtifactRemoveElt()
- .find('[data-testid="artifact-expired-help-link"]')
- .attributes('href'),
- ).toBe('help-url');
- });
-
- it('renders the keep button', () => {
- expect(findKeepBtn().exists()).toBe(true);
- });
-
- it('renders the download button', () => {
- expect(findDownloadBtn().exists()).toBe(true);
- });
-
- it('renders the browse button', () => {
- expect(findBrowseBtn().exists()).toBe(true);
- });
- });
-
- describe('with expired locked artifacts', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: lockedExpiredArtifact,
- });
- });
-
- it('renders the information that the artefacts are locked', () => {
- expect(findArtifactRemoveElt().exists()).toBe(false);
- expect(trimText(findJobLockedElt().text())).toBe(lockedText);
- });
-
- it('does not render the keep button', () => {
- expect(findKeepBtn().exists()).toBe(false);
- });
-
- it('renders the download button', () => {
- expect(findDownloadBtn().exists()).toBe(true);
- });
-
- it('renders the browse button', () => {
- expect(findBrowseBtn().exists()).toBe(true);
- });
- });
-
- describe('with non expired locked artifacts', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: lockedNonExpiredArtifact,
- });
- });
-
- it('renders the information that the artefacts are locked', () => {
- expect(findArtifactRemoveElt().exists()).toBe(false);
- expect(trimText(findJobLockedElt().text())).toBe(lockedText);
- });
-
- it('does not render the keep button', () => {
- expect(findKeepBtn().exists()).toBe(false);
- });
-
- it('renders the download button', () => {
- expect(findDownloadBtn().exists()).toBe(true);
- });
-
- it('renders the browse button', () => {
- expect(findBrowseBtn().exists()).toBe(true);
- });
- });
-
- describe('artifacts help text', () => {
- beforeEach(() => {
- wrapper = createWrapper({
- artifact: lockedNonExpiredArtifact,
- });
- });
-
- it('displays help text', () => {
- const expectedHelpText =
- 'Job artifacts are files that are configured to be uploaded when a job finishes execution. Artifacts could be compiled files, unit tests or scanning reports, or any other files generated by a job.';
-
- expect(findPopover().text()).toBe(expectedHelpText);
- });
-
- it('links to artifacts help page', () => {
- expect(findArtifactsHelpLink().attributes('href')).toBe('/help/ci/jobs/job_artifacts');
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/commit_block_spec.js b/spec/frontend/jobs/components/job/commit_block_spec.js
deleted file mode 100644
index 1c28b5079d7..00000000000
--- a/spec/frontend/jobs/components/job/commit_block_spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import CommitBlock from '~/jobs/components/job/sidebar/commit_block.vue';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-
-describe('Commit block', () => {
- let wrapper;
-
- const commit = {
- short_id: '1f0fb84f',
- id: '1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
- commit_path: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
- title: 'Update README.md',
- };
-
- const mergeRequest = {
- iid: '!21244',
- path: 'merge_requests/21244',
- };
-
- const findCommitSha = () => wrapper.findByTestId('commit-sha');
- const findLinkSha = () => wrapper.findByTestId('link-commit');
-
- const mountComponent = (props) => {
- wrapper = extendedWrapper(
- shallowMount(CommitBlock, {
- propsData: {
- commit,
- ...props,
- },
- }),
- );
- };
-
- describe('without merge request', () => {
- beforeEach(() => {
- mountComponent();
- });
-
- it('renders pipeline short sha link', () => {
- expect(findCommitSha().attributes('href')).toBe(commit.commit_path);
- expect(findCommitSha().text()).toBe(commit.short_id);
- });
-
- it('renders clipboard button', () => {
- expect(wrapper.findComponent(ClipboardButton).attributes('text')).toBe(commit.id);
- });
-
- it('renders git commit title', () => {
- expect(wrapper.text()).toContain(commit.title);
- });
-
- it('does not render merge request', () => {
- expect(findLinkSha().exists()).toBe(false);
- });
- });
-
- describe('with merge request', () => {
- it('renders merge request link and reference', () => {
- mountComponent({ mergeRequest });
-
- expect(findLinkSha().attributes('href')).toBe(mergeRequest.path);
- expect(findLinkSha().text()).toBe(`!${mergeRequest.iid}`);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/empty_state_spec.js b/spec/frontend/jobs/components/job/empty_state_spec.js
deleted file mode 100644
index 970c2591795..00000000000
--- a/spec/frontend/jobs/components/job/empty_state_spec.js
+++ /dev/null
@@ -1,140 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import EmptyState from '~/jobs/components/job/empty_state.vue';
-import ManualVariablesForm from '~/jobs/components/job/manual_variables_form.vue';
-import { mockFullPath, mockId } from './mock_data';
-
-describe('Empty State', () => {
- let wrapper;
-
- const defaultProps = {
- illustrationPath: 'illustrations/pending_job_empty.svg',
- illustrationSizeClass: 'svg-430',
- jobId: mockId,
- title: 'This job has not started yet',
- playable: false,
- isRetryable: true,
- };
-
- const createWrapper = (props) => {
- wrapper = shallowMountExtended(EmptyState, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- provide: {
- projectPath: mockFullPath,
- },
- });
- };
-
- const content = 'This job is in pending state and is waiting to be picked by a runner';
-
- const findEmptyStateImage = () => wrapper.find('img');
- const findTitle = () => wrapper.findByTestId('job-empty-state-title');
- const findContent = () => wrapper.findByTestId('job-empty-state-content');
- const findAction = () => wrapper.findByTestId('job-empty-state-action');
- const findManualVarsForm = () => wrapper.findComponent(ManualVariablesForm);
-
- describe('renders image and title', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders empty state image', () => {
- expect(findEmptyStateImage().exists()).toBe(true);
- });
-
- it('renders provided title', () => {
- expect(findTitle().text().trim()).toBe(defaultProps.title);
- });
- });
-
- describe('with content', () => {
- beforeEach(() => {
- createWrapper({ content });
- });
-
- it('renders content', () => {
- expect(findContent().text().trim()).toBe(content);
- });
- });
-
- describe('without content', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('does not render content', () => {
- expect(findContent().exists()).toBe(false);
- });
- });
-
- describe('with action', () => {
- beforeEach(() => {
- createWrapper({
- action: {
- path: 'runner',
- button_title: 'Check runner',
- method: 'post',
- },
- });
- });
-
- it('renders action', () => {
- expect(findAction().attributes('href')).toBe('runner');
- });
- });
-
- describe('without action', () => {
- beforeEach(() => {
- createWrapper({
- action: null,
- });
- });
-
- it('does not render action', () => {
- expect(findAction().exists()).toBe(false);
- });
-
- it('does not render manual variables form', () => {
- expect(findManualVarsForm().exists()).toBe(false);
- });
- });
-
- describe('with playable action and not scheduled job', () => {
- beforeEach(() => {
- createWrapper({
- content,
- playable: true,
- scheduled: false,
- action: {
- path: 'runner',
- button_title: 'Check runner',
- method: 'post',
- },
- });
- });
-
- it('renders manual variables form', () => {
- expect(findManualVarsForm().exists()).toBe(true);
- });
-
- it('does not render the empty state action', () => {
- expect(findAction().exists()).toBe(false);
- });
- });
-
- describe('with playable action and scheduled job', () => {
- beforeEach(() => {
- createWrapper({
- playable: true,
- scheduled: true,
- content,
- });
- });
-
- it('does not render manual variables form', () => {
- expect(findManualVarsForm().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/environments_block_spec.js b/spec/frontend/jobs/components/job/environments_block_spec.js
deleted file mode 100644
index ab36f79ea5e..00000000000
--- a/spec/frontend/jobs/components/job/environments_block_spec.js
+++ /dev/null
@@ -1,260 +0,0 @@
-import { mount } from '@vue/test-utils';
-import EnvironmentsBlock from '~/jobs/components/job/environments_block.vue';
-
-const TEST_CLUSTER_NAME = 'test_cluster';
-const TEST_CLUSTER_PATH = 'path/to/test_cluster';
-const TEST_KUBERNETES_NAMESPACE = 'this-is-a-kubernetes-namespace';
-
-describe('Environments block', () => {
- let wrapper;
-
- const status = {
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- };
-
- const environment = {
- environment_path: '/environment',
- name: 'environment',
- };
-
- const lastDeployment = { iid: 'deployment', deployable: { build_path: 'bar' } };
-
- const createEnvironmentWithLastDeployment = () => ({
- ...environment,
- last_deployment: { ...lastDeployment },
- });
-
- const createDeploymentWithCluster = () => ({ name: TEST_CLUSTER_NAME, path: TEST_CLUSTER_PATH });
-
- const createDeploymentWithClusterAndKubernetesNamespace = () => ({
- name: TEST_CLUSTER_NAME,
- path: TEST_CLUSTER_PATH,
- kubernetes_namespace: TEST_KUBERNETES_NAMESPACE,
- });
-
- const createComponent = (deploymentStatus = {}, deploymentCluster = {}) => {
- wrapper = mount(EnvironmentsBlock, {
- propsData: {
- deploymentStatus,
- deploymentCluster,
- iconStatus: status,
- },
- });
- };
-
- const findText = () => wrapper.findComponent(EnvironmentsBlock).text();
- const findJobDeploymentLink = () => wrapper.find('[data-testid="job-deployment-link"]');
- const findEnvironmentLink = () => wrapper.find('[data-testid="job-environment-link"]');
- const findClusterLink = () => wrapper.find('[data-testid="job-cluster-link"]');
-
- describe('with last deployment', () => {
- it('renders info for most recent deployment', () => {
- createComponent({
- status: 'last',
- environment,
- });
-
- expect(findText()).toBe('This job is deployed to environment.');
- });
-
- describe('when there is a cluster', () => {
- it('renders info with cluster', () => {
- createComponent(
- {
- status: 'last',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithCluster(),
- );
-
- expect(findText()).toBe(
- `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME}.`,
- );
- });
-
- describe('when there is a kubernetes namespace', () => {
- it('renders info with cluster', () => {
- createComponent(
- {
- status: 'last',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithClusterAndKubernetesNamespace(),
- );
-
- expect(findText()).toBe(
- `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME} and namespace ${TEST_KUBERNETES_NAMESPACE}.`,
- );
- });
- });
- });
- });
-
- describe('with out of date deployment', () => {
- describe('with last deployment', () => {
- it('renders info for out date and most recent', () => {
- createComponent({
- status: 'out_of_date',
- environment: createEnvironmentWithLastDeployment(),
- });
-
- expect(findText()).toBe(
- 'This job is an out-of-date deployment to environment. View the most recent deployment.',
- );
-
- expect(findJobDeploymentLink().attributes('href')).toBe('bar');
- });
-
- describe('when there is a cluster', () => {
- it('renders info with cluster', () => {
- createComponent(
- {
- status: 'out_of_date',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithCluster(),
- );
-
- expect(findText()).toBe(
- `This job is an out-of-date deployment to environment using cluster ${TEST_CLUSTER_NAME}. View the most recent deployment.`,
- );
- });
-
- describe('when there is a kubernetes namespace', () => {
- it('renders info with cluster', () => {
- createComponent(
- {
- status: 'out_of_date',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithClusterAndKubernetesNamespace(),
- );
-
- expect(findText()).toBe(
- `This job is an out-of-date deployment to environment using cluster ${TEST_CLUSTER_NAME} and namespace ${TEST_KUBERNETES_NAMESPACE}. View the most recent deployment.`,
- );
- });
- });
- });
- });
-
- describe('without last deployment', () => {
- it('renders info about out of date deployment', () => {
- createComponent({
- status: 'out_of_date',
- environment,
- });
-
- expect(findText()).toBe('This job is an out-of-date deployment to environment.');
- });
- });
- });
-
- describe('with failed deployment', () => {
- it('renders info about failed deployment', () => {
- createComponent({
- status: 'failed',
- environment,
- });
-
- expect(findText()).toBe('The deployment of this job to environment did not succeed.');
- });
- });
-
- describe('creating deployment', () => {
- describe('with last deployment', () => {
- it('renders info about creating deployment and overriding latest deployment', () => {
- createComponent({
- status: 'creating',
- environment: createEnvironmentWithLastDeployment(),
- });
-
- expect(findText()).toBe(
- 'This job is creating a deployment to environment. This will overwrite the latest deployment.',
- );
-
- expect(findEnvironmentLink().attributes('href')).toBe(environment.environment_path);
-
- expect(findJobDeploymentLink().attributes('href')).toBe('bar');
-
- expect(findClusterLink().exists()).toBe(false);
- });
- });
-
- describe('without last deployment', () => {
- it('renders info about deployment being created', () => {
- createComponent({
- status: 'creating',
- environment,
- });
-
- expect(findText()).toBe('This job is creating a deployment to environment.');
- });
-
- describe('when there is a cluster', () => {
- it('inclues information about the cluster', () => {
- createComponent(
- {
- status: 'creating',
- environment,
- },
- createDeploymentWithCluster(),
- );
-
- expect(findText()).toBe(
- `This job is creating a deployment to environment using cluster ${TEST_CLUSTER_NAME}.`,
- );
- });
- });
- });
-
- describe('without environment', () => {
- it('does not render environment link', () => {
- createComponent({
- status: 'creating',
- environment: null,
- });
-
- expect(findEnvironmentLink().exists()).toBe(false);
- });
- });
- });
-
- describe('with a cluster', () => {
- it('renders the cluster link', () => {
- createComponent(
- {
- status: 'last',
- environment: createEnvironmentWithLastDeployment(),
- },
- createDeploymentWithCluster(),
- );
-
- expect(findText()).toBe(
- `This job is deployed to environment using cluster ${TEST_CLUSTER_NAME}.`,
- );
-
- expect(findClusterLink().attributes('href')).toBe(TEST_CLUSTER_PATH);
- });
-
- describe('when the cluster is missing the path', () => {
- it('renders the name without a link', () => {
- createComponent(
- {
- status: 'last',
- environment: createEnvironmentWithLastDeployment(),
- },
- { name: 'the-cluster' },
- );
-
- expect(findText()).toContain('using cluster the-cluster.');
-
- expect(findClusterLink().exists()).toBe(false);
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/erased_block_spec.js b/spec/frontend/jobs/components/job/erased_block_spec.js
deleted file mode 100644
index aeab676fc7e..00000000000
--- a/spec/frontend/jobs/components/job/erased_block_spec.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import ErasedBlock from '~/jobs/components/job/erased_block.vue';
-import { getTimeago } from '~/lib/utils/datetime_utility';
-
-describe('Erased block', () => {
- let wrapper;
-
- const erasedAt = '2016-11-07T11:11:16.525Z';
- const timeago = getTimeago();
- const formattedDate = timeago.format(erasedAt);
-
- const findLink = () => wrapper.findComponent(GlLink);
-
- const createComponent = (props) => {
- wrapper = mount(ErasedBlock, {
- propsData: props,
- });
- };
-
- describe('with job erased by user', () => {
- beforeEach(() => {
- createComponent({
- user: {
- username: 'root',
- web_url: 'gitlab.com/root',
- },
- erasedAt,
- });
- });
-
- it('renders username and link', () => {
- expect(findLink().attributes('href')).toEqual('gitlab.com/root');
-
- expect(wrapper.text().trim()).toContain('Job has been erased by');
- expect(wrapper.text().trim()).toContain('root');
- });
-
- it('renders erasedAt', () => {
- expect(wrapper.text().trim()).toContain(formattedDate);
- });
- });
-
- describe('with erased job', () => {
- beforeEach(() => {
- createComponent({
- erasedAt,
- });
- });
-
- it('renders username and link', () => {
- expect(wrapper.text().trim()).toContain('Job has been erased');
- });
-
- it('renders erasedAt', () => {
- expect(wrapper.text().trim()).toContain(formattedDate);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_app_spec.js b/spec/frontend/jobs/components/job/job_app_spec.js
deleted file mode 100644
index 8f5700ee22d..00000000000
--- a/spec/frontend/jobs/components/job/job_app_spec.js
+++ /dev/null
@@ -1,343 +0,0 @@
-import Vue, { nextTick } from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import { GlLoadingIcon } from '@gitlab/ui';
-import MockAdapter from 'axios-mock-adapter';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { TEST_HOST } from 'helpers/test_constants';
-import EmptyState from '~/jobs/components/job/empty_state.vue';
-import EnvironmentsBlock from '~/jobs/components/job/environments_block.vue';
-import ErasedBlock from '~/jobs/components/job/erased_block.vue';
-import JobApp from '~/jobs/components/job/job_app.vue';
-import JobLog from '~/jobs/components/log/log.vue';
-import JobLogTopBar from 'ee_else_ce/jobs/components/job/job_log_controllers.vue';
-import Sidebar from '~/jobs/components/job/sidebar/sidebar.vue';
-import StuckBlock from '~/jobs/components/job/stuck_block.vue';
-import UnmetPrerequisitesBlock from '~/jobs/components/job/unmet_prerequisites_block.vue';
-import createStore from '~/jobs/store';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import { MANUAL_STATUS } from '~/jobs/constants';
-import job from '../../mock_data';
-import { mockPendingJobData } from './mock_data';
-
-describe('Job App', () => {
- Vue.use(Vuex);
-
- let store;
- let wrapper;
- let mock;
-
- const initSettings = {
- endpoint: `${TEST_HOST}jobs/123.json`,
- pagePath: `${TEST_HOST}jobs/123`,
- logState:
- 'eyJvZmZzZXQiOjE3NDUxLCJuX29wZW5fdGFncyI6MCwiZmdfY29sb3IiOm51bGwsImJnX2NvbG9yIjpudWxsLCJzdHlsZV9tYXNrIjowfQ%3D%3D',
- };
-
- const props = {
- artifactHelpUrl: 'help/artifact',
- deploymentHelpUrl: 'help/deployment',
- runnerSettingsUrl: 'settings/ci-cd/runners',
- terminalPath: 'jobs/123/terminal',
- projectPath: 'user-name/project-name',
- subscriptionsMoreMinutesUrl: 'https://customers.gitlab.com/buy_pipeline_minutes',
- };
-
- const createComponent = () => {
- wrapper = shallowMountExtended(JobApp, {
- propsData: { ...props },
- store,
- });
- };
-
- const setupAndMount = async ({ jobData = {}, jobLogData = {} } = {}) => {
- mock.onGet(initSettings.endpoint).replyOnce(HTTP_STATUS_OK, { ...job, ...jobData });
- mock.onGet(`${initSettings.pagePath}/trace.json`).reply(HTTP_STATUS_OK, jobLogData);
-
- const asyncInit = store.dispatch('init', initSettings);
-
- createComponent();
-
- await asyncInit;
- jest.runOnlyPendingTimers();
- await axios.waitForAll();
- await nextTick();
- };
-
- const findLoadingComponent = () => wrapper.findComponent(GlLoadingIcon);
- const findSidebar = () => wrapper.findComponent(Sidebar);
- const findStuckBlockComponent = () => wrapper.findComponent(StuckBlock);
- const findFailedJobComponent = () => wrapper.findComponent(UnmetPrerequisitesBlock);
- const findEnvironmentsBlockComponent = () => wrapper.findComponent(EnvironmentsBlock);
- const findErasedBlock = () => wrapper.findComponent(ErasedBlock);
- const findEmptyState = () => wrapper.findComponent(EmptyState);
- const findJobLog = () => wrapper.findComponent(JobLog);
- const findJobLogTopBar = () => wrapper.findComponent(JobLogTopBar);
-
- const findJobContent = () => wrapper.findByTestId('job-content');
- const findArchivedJob = () => wrapper.findByTestId('archived-job');
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- store = createStore();
- });
-
- afterEach(() => {
- mock.restore();
- // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
- wrapper.destroy();
- });
-
- describe('while loading', () => {
- beforeEach(() => {
- store.state.isLoading = true;
- createComponent();
- });
-
- it('renders loading icon', () => {
- expect(findLoadingComponent().exists()).toBe(true);
- expect(findSidebar().exists()).toBe(false);
- expect(findJobContent().exists()).toBe(false);
- });
- });
-
- describe('with successful request', () => {
- describe('Header section', () => {
- describe('job callout message', () => {
- it('should not render the reason when reason is absent', () =>
- setupAndMount().then(() => {
- expect(wrapper.vm.shouldRenderCalloutMessage).toBe(false);
- }));
-
- it('should render the reason when reason is present', () =>
- setupAndMount({
- jobData: {
- callout_message: 'There is an unkown failure, please try again',
- },
- }).then(() => {
- expect(wrapper.vm.shouldRenderCalloutMessage).toBe(true);
- }));
- });
- });
-
- describe('stuck block', () => {
- describe('without active runners available', () => {
- it('renders stuck block when there are no runners', () =>
- setupAndMount({
- jobData: {
- status: {
- group: 'pending',
- icon: 'status_pending',
- label: 'pending',
- text: 'pending',
- details_path: 'path',
- },
- stuck: true,
- runners: {
- available: false,
- online: false,
- },
- tags: [],
- },
- }).then(() => {
- expect(findStuckBlockComponent().exists()).toBe(true);
- }));
- });
-
- it('does not render stuck block when there are runners', () =>
- setupAndMount({
- jobData: {
- runners: { available: true },
- },
- }).then(() => {
- expect(findStuckBlockComponent().exists()).toBe(false);
- }));
- });
-
- describe('unmet prerequisites block', () => {
- it('renders unmet prerequisites block when there is an unmet prerequisites failure', () =>
- setupAndMount({
- jobData: {
- status: {
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- details_path: 'path',
- illustration: {
- content: 'Retry this job in order to create the necessary resources.',
- image: 'path',
- size: 'svg-430',
- title: 'Failed to create resources',
- },
- },
- failure_reason: 'unmet_prerequisites',
- has_trace: false,
- runners: {
- available: true,
- },
- tags: [],
- },
- }).then(() => {
- expect(findFailedJobComponent().exists()).toBe(true);
- }));
- });
-
- describe('environments block', () => {
- it('renders environment block when job has environment', () =>
- setupAndMount({
- jobData: {
- deployment_status: {
- environment: {
- environment_path: '/path',
- name: 'foo',
- },
- },
- },
- }).then(() => {
- expect(findEnvironmentsBlockComponent().exists()).toBe(true);
- }));
-
- it('does not render environment block when job has environment', () =>
- setupAndMount().then(() => {
- expect(findEnvironmentsBlockComponent().exists()).toBe(false);
- }));
- });
-
- describe('erased block', () => {
- it('renders erased block when `erased` is true', () =>
- setupAndMount({
- jobData: {
- erased_by: {
- username: 'root',
- web_url: 'gitlab.com/root',
- },
- erased_at: '2016-11-07T11:11:16.525Z',
- },
- }).then(() => {
- expect(findErasedBlock().exists()).toBe(true);
- }));
-
- it('does not render erased block when `erased` is false', () =>
- setupAndMount({
- jobData: {
- erased_at: null,
- },
- }).then(() => {
- expect(findErasedBlock().exists()).toBe(false);
- }));
- });
-
- describe('empty states block', () => {
- it('renders empty state when job does not have log and is not running', () =>
- setupAndMount({
- jobData: {
- has_trace: false,
- status: {
- group: 'pending',
- icon: 'status_pending',
- label: 'pending',
- text: 'pending',
- details_path: 'path',
- illustration: {
- image: 'path',
- size: '340',
- title: 'Empty State',
- content: 'This is an empty state',
- },
- action: {
- button_title: 'Retry job',
- method: 'post',
- path: '/path',
- },
- },
- },
- }).then(() => {
- expect(findEmptyState().exists()).toBe(true);
- }));
-
- it('does not render empty state when job does not have log but it is running', () =>
- setupAndMount({
- jobData: {
- has_trace: false,
- status: {
- group: 'running',
- icon: 'status_running',
- label: 'running',
- text: 'running',
- details_path: 'path',
- },
- },
- }).then(() => {
- expect(findEmptyState().exists()).toBe(false);
- }));
-
- it('does not render empty state when job has log but it is not running', () =>
- setupAndMount({ jobData: { has_trace: true } }).then(() => {
- expect(findEmptyState().exists()).toBe(false);
- }));
- });
-
- describe('sidebar', () => {
- it('renders sidebar', async () => {
- await setupAndMount();
-
- expect(findSidebar().exists()).toBe(true);
- });
- });
- });
-
- describe('archived job', () => {
- beforeEach(() => setupAndMount({ jobData: { archived: true } }));
-
- it('renders warning about job being archived', () => {
- expect(findArchivedJob().exists()).toBe(true);
- });
- });
-
- describe('non-archived job', () => {
- beforeEach(() => setupAndMount());
-
- it('does not warning about job being archived', () => {
- expect(findArchivedJob().exists()).toBe(false);
- });
- });
-
- describe('job log', () => {
- beforeEach(() => setupAndMount());
-
- it('should render job log header', () => {
- expect(findJobLogTopBar().exists()).toBe(true);
- });
-
- it('should render job log', () => {
- expect(findJobLog().exists()).toBe(true);
- });
- });
-
- describe('job log polling', () => {
- beforeEach(() => {
- jest.spyOn(store, 'dispatch');
- });
-
- it('should poll job log by default', async () => {
- await setupAndMount({
- jobData: mockPendingJobData,
- });
-
- expect(store.dispatch).toHaveBeenCalledWith('fetchJobLog');
- });
-
- it('should NOT poll job log for manual variables form empty state', async () => {
- const manualPendingJobData = mockPendingJobData;
- manualPendingJobData.status.group = MANUAL_STATUS;
-
- await setupAndMount({
- jobData: manualPendingJobData,
- });
-
- expect(store.dispatch).not.toHaveBeenCalledWith('fetchJobLog');
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_container_item_spec.js b/spec/frontend/jobs/components/job/job_container_item_spec.js
deleted file mode 100644
index 39782130d38..00000000000
--- a/spec/frontend/jobs/components/job/job_container_item_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import { GlIcon, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import delayedJobFixture from 'test_fixtures/jobs/delayed.json';
-import JobContainerItem from '~/jobs/components/job/sidebar/job_container_item.vue';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import job from '../../mock_data';
-
-describe('JobContainerItem', () => {
- let wrapper;
-
- const findCiIcon = () => wrapper.findComponent(CiIcon);
- const findGlIcon = () => wrapper.findComponent(GlIcon);
-
- function createComponent(jobData = {}, props = { isActive: false, retried: false }) {
- wrapper = shallowMount(JobContainerItem, {
- propsData: {
- job: {
- ...jobData,
- retried: props.retried,
- },
- isActive: props.isActive,
- },
- });
- }
-
- describe('when a job is not active and not retried', () => {
- beforeEach(() => {
- createComponent(job);
- });
-
- it('displays a status icon', () => {
- expect(findCiIcon().props('status')).toBe(job.status);
- });
-
- it('displays the job name', () => {
- expect(wrapper.text()).toContain(job.name);
- });
-
- it('displays a link to the job', () => {
- const link = wrapper.findComponent(GlLink);
-
- expect(link.attributes('href')).toBe(job.status.details_path);
- });
- });
-
- describe('when a job is active', () => {
- beforeEach(() => {
- createComponent(job, { isActive: true });
- });
-
- it('displays an arrow sprite icon', () => {
- expect(findGlIcon().props('name')).toBe('arrow-right');
- });
- });
-
- describe('when a job is retried', () => {
- beforeEach(() => {
- createComponent(job, { isActive: false, retried: true });
- });
-
- it('displays a retry icon', () => {
- expect(findGlIcon().props('name')).toBe('retry');
- });
- });
-
- describe('for a delayed job', () => {
- beforeEach(() => {
- const remainingMilliseconds = 1337000;
- jest
- .spyOn(Date, 'now')
- .mockImplementation(
- () => new Date(delayedJobFixture.scheduled_at).getTime() - remainingMilliseconds,
- );
-
- createComponent(delayedJobFixture);
- });
-
- it('displays remaining time in tooltip', async () => {
- await nextTick();
-
- const link = wrapper.findComponent(GlLink);
-
- expect(link.attributes('title')).toMatch('delayed job - delayed manual action (00:22:17)');
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_log_controllers_spec.js b/spec/frontend/jobs/components/job/job_log_controllers_spec.js
deleted file mode 100644
index 7b6d58f63d1..00000000000
--- a/spec/frontend/jobs/components/job/job_log_controllers_spec.js
+++ /dev/null
@@ -1,323 +0,0 @@
-import { GlSearchBoxByClick } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import JobLogControllers from '~/jobs/components/job/job_log_controllers.vue';
-import HelpPopover from '~/vue_shared/components/help_popover.vue';
-import { backoffMockImplementation } from 'helpers/backoff_helper';
-import * as commonUtils from '~/lib/utils/common_utils';
-import { mockJobLog } from '../../mock_data';
-
-const mockToastShow = jest.fn();
-
-describe('Job log controllers', () => {
- let wrapper;
-
- beforeEach(() => {
- jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation);
- });
-
- afterEach(() => {
- commonUtils.backOff.mockReset();
- });
-
- const defaultProps = {
- rawPath: '/raw',
- size: 511952,
- isScrollTopDisabled: false,
- isScrollBottomDisabled: false,
- isScrollingDown: true,
- isJobLogSizeVisible: true,
- isComplete: true,
- jobLog: mockJobLog,
- };
-
- const createWrapper = (props, { jobLogJumpToFailures = false } = {}) => {
- wrapper = mount(JobLogControllers, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- provide: {
- glFeatures: {
- jobLogJumpToFailures,
- },
- },
- data() {
- return {
- searchTerm: '82',
- };
- },
- mocks: {
- $toast: {
- show: mockToastShow,
- },
- },
- });
- };
-
- const findTruncatedInfo = () => wrapper.find('[data-testid="log-truncated-info"]');
- const findRawLink = () => wrapper.find('[data-testid="raw-link"]');
- const findRawLinkController = () => wrapper.find('[data-testid="job-raw-link-controller"]');
- const findScrollTop = () => wrapper.find('[data-testid="job-controller-scroll-top"]');
- const findScrollBottom = () => wrapper.find('[data-testid="job-controller-scroll-bottom"]');
- const findJobLogSearch = () => wrapper.findComponent(GlSearchBoxByClick);
- const findSearchHelp = () => wrapper.findComponent(HelpPopover);
- const findScrollFailure = () => wrapper.find('[data-testid="job-controller-scroll-to-failure"]');
-
- describe('Truncate information', () => {
- describe('with isJobLogSizeVisible', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders size information', () => {
- expect(findTruncatedInfo().text()).toMatch('499.95 KiB');
- });
-
- it('renders link to raw job log', () => {
- expect(findRawLink().attributes('href')).toBe(defaultProps.rawPath);
- });
- });
- });
-
- describe('links section', () => {
- describe('with raw job log path', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders raw job log link', () => {
- expect(findRawLinkController().attributes('href')).toBe(defaultProps.rawPath);
- });
- });
-
- describe('without raw job log path', () => {
- beforeEach(() => {
- createWrapper({
- rawPath: null,
- });
- });
-
- it('does not render raw job log link', () => {
- expect(findRawLinkController().exists()).toBe(false);
- });
- });
- });
-
- describe('scroll buttons', () => {
- describe('scroll top button', () => {
- describe('when user can scroll top', () => {
- beforeEach(() => {
- createWrapper({
- isScrollTopDisabled: false,
- });
- });
-
- it('emits scrollJobLogTop event on click', async () => {
- await findScrollTop().trigger('click');
-
- expect(wrapper.emitted().scrollJobLogTop).toHaveLength(1);
- });
- });
-
- describe('when user can not scroll top', () => {
- beforeEach(() => {
- createWrapper({
- isScrollTopDisabled: true,
- isScrollBottomDisabled: false,
- isScrollingDown: false,
- });
- });
-
- it('renders disabled scroll top button', () => {
- expect(findScrollTop().attributes('disabled')).toBeDefined();
- });
-
- it('does not emit scrollJobLogTop event on click', async () => {
- await findScrollTop().trigger('click');
-
- expect(wrapper.emitted().scrollJobLogTop).toBeUndefined();
- });
- });
- });
-
- describe('scroll bottom button', () => {
- describe('when user can scroll bottom', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('emits scrollJobLogBottom event on click', async () => {
- await findScrollBottom().trigger('click');
-
- expect(wrapper.emitted().scrollJobLogBottom).toHaveLength(1);
- });
- });
-
- describe('when user can not scroll bottom', () => {
- beforeEach(() => {
- createWrapper({
- isScrollTopDisabled: false,
- isScrollBottomDisabled: true,
- isScrollingDown: false,
- });
- });
-
- it('renders disabled scroll bottom button', () => {
- expect(findScrollBottom().attributes('disabled')).toEqual('disabled');
- });
-
- it('does not emit scrollJobLogBottom event on click', async () => {
- await findScrollBottom().trigger('click');
-
- expect(wrapper.emitted().scrollJobLogBottom).toBeUndefined();
- });
- });
-
- describe('while isScrollingDown is true', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders animate class for the scroll down button', () => {
- expect(findScrollBottom().classes()).toContain('animate');
- });
- });
-
- describe('while isScrollingDown is false', () => {
- beforeEach(() => {
- createWrapper({
- isScrollTopDisabled: true,
- isScrollBottomDisabled: false,
- isScrollingDown: false,
- });
- });
-
- it('does not render animate class for the scroll down button', () => {
- expect(findScrollBottom().classes()).not.toContain('animate');
- });
- });
- });
-
- describe('scroll to failure button', () => {
- describe('with feature flag disabled', () => {
- it('does not display button', () => {
- createWrapper();
-
- expect(findScrollFailure().exists()).toBe(false);
- });
- });
-
- describe('with red text failures on the page', () => {
- let firstFailure;
- let secondFailure;
-
- beforeEach(() => {
- jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce(['mock-element']);
-
- createWrapper({}, { jobLogJumpToFailures: true });
-
- firstFailure = document.createElement('div');
- firstFailure.className = 'term-fg-l-red';
- document.body.appendChild(firstFailure);
-
- secondFailure = document.createElement('div');
- secondFailure.className = 'term-fg-l-red';
- document.body.appendChild(secondFailure);
- });
-
- afterEach(() => {
- if (firstFailure) {
- firstFailure.remove();
- firstFailure = null;
- }
-
- if (secondFailure) {
- secondFailure.remove();
- secondFailure = null;
- }
- });
-
- it('is enabled', () => {
- expect(findScrollFailure().props('disabled')).toBe(false);
- });
-
- it('scrolls to each failure', async () => {
- jest.spyOn(firstFailure, 'scrollIntoView');
-
- await findScrollFailure().trigger('click');
-
- expect(firstFailure.scrollIntoView).toHaveBeenCalled();
-
- await findScrollFailure().trigger('click');
-
- expect(secondFailure.scrollIntoView).toHaveBeenCalled();
-
- await findScrollFailure().trigger('click');
-
- expect(firstFailure.scrollIntoView).toHaveBeenCalled();
- });
- });
-
- describe('with no red text failures on the page', () => {
- beforeEach(() => {
- jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce([]);
-
- createWrapper({}, { jobLogJumpToFailures: true });
- });
-
- it('is disabled', () => {
- expect(findScrollFailure().props('disabled')).toBe(true);
- });
- });
-
- describe('when the job log is not complete', () => {
- beforeEach(() => {
- jest.spyOn(document, 'querySelectorAll').mockReturnValueOnce(['mock-element']);
-
- createWrapper({ isComplete: false }, { jobLogJumpToFailures: true });
- });
-
- it('is enabled', () => {
- expect(findScrollFailure().props('disabled')).toBe(false);
- });
- });
-
- describe('on error', () => {
- beforeEach(() => {
- jest.spyOn(commonUtils, 'backOff').mockRejectedValueOnce();
-
- createWrapper({}, { jobLogJumpToFailures: true });
- });
-
- it('stays disabled', () => {
- expect(findScrollFailure().props('disabled')).toBe(true);
- });
- });
- });
- });
-
- describe('Job log search', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('displays job log search', () => {
- expect(findJobLogSearch().exists()).toBe(true);
- expect(findSearchHelp().exists()).toBe(true);
- });
-
- it('emits search results', () => {
- const expectedSearchResults = [[[mockJobLog[6].lines[1], mockJobLog[6].lines[2]]]];
-
- findJobLogSearch().vm.$emit('submit');
-
- expect(wrapper.emitted('searchResults')).toEqual(expectedSearchResults);
- });
-
- it('clears search results', () => {
- findJobLogSearch().vm.$emit('clear');
-
- expect(wrapper.emitted('searchResults')).toEqual([[[]]]);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js b/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js
deleted file mode 100644
index a44a13259aa..00000000000
--- a/spec/frontend/jobs/components/job/job_retry_forward_deployment_modal_spec.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { GlLink, GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import JobRetryForwardDeploymentModal from '~/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue';
-import { JOB_RETRY_FORWARD_DEPLOYMENT_MODAL } from '~/jobs/constants';
-import createStore from '~/jobs/store';
-import job from '../../mock_data';
-
-describe('Job Retry Forward Deployment Modal', () => {
- let store;
- let wrapper;
-
- const retryOutdatedJobDocsUrl = 'url-to-docs';
- const findLink = () => wrapper.findComponent(GlLink);
- const findModal = () => wrapper.findComponent(GlModal);
-
- const createWrapper = ({ props = {}, provide = {}, stubs = {} } = {}) => {
- store = createStore();
- wrapper = shallowMount(JobRetryForwardDeploymentModal, {
- propsData: {
- modalId: 'modal-id',
- href: job.retry_path,
- ...props,
- },
- provide,
- store,
- stubs,
- });
- };
-
- beforeEach(createWrapper);
-
- describe('Modal configuration', () => {
- it('should display the correct messages', () => {
- const modal = findModal();
- expect(modal.attributes('title')).toMatch(JOB_RETRY_FORWARD_DEPLOYMENT_MODAL.title);
- expect(modal.text()).toMatch(JOB_RETRY_FORWARD_DEPLOYMENT_MODAL.info);
- expect(modal.text()).toMatch(JOB_RETRY_FORWARD_DEPLOYMENT_MODAL.areYouSure);
- });
- });
-
- describe('Modal docs help link', () => {
- it('should not display an info link when none is provided', () => {
- createWrapper();
-
- expect(findLink().exists()).toBe(false);
- });
-
- it('should display an info link when one is provided', () => {
- createWrapper({ provide: { retryOutdatedJobDocsUrl } });
-
- expect(findLink().attributes('href')).toBe(retryOutdatedJobDocsUrl);
- expect(findLink().text()).toMatch(JOB_RETRY_FORWARD_DEPLOYMENT_MODAL.moreInfo);
- });
- });
-
- describe('Modal actions', () => {
- beforeEach(createWrapper);
-
- it('should correctly configure the primary action', () => {
- expect(findModal().props('actionPrimary').attributes).toMatchObject({
- 'data-method': 'post',
- href: job.retry_path,
- variant: 'danger',
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_sidebar_details_container_spec.js b/spec/frontend/jobs/components/job/job_sidebar_details_container_spec.js
deleted file mode 100644
index c1028f3929d..00000000000
--- a/spec/frontend/jobs/components/job/job_sidebar_details_container_spec.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import DetailRow from '~/jobs/components/job/sidebar/sidebar_detail_row.vue';
-import SidebarJobDetailsContainer from '~/jobs/components/job/sidebar/sidebar_job_details_container.vue';
-import createStore from '~/jobs/store';
-import job from '../../mock_data';
-
-describe('Job Sidebar Details Container', () => {
- let store;
- let wrapper;
-
- const findJobTimeout = () => wrapper.findByTestId('job-timeout');
- const findJobTags = () => wrapper.findByTestId('job-tags');
- const findAllDetailsRow = () => wrapper.findAllComponents(DetailRow);
-
- const createWrapper = ({ props = {} } = {}) => {
- store = createStore();
- wrapper = extendedWrapper(
- shallowMount(SidebarJobDetailsContainer, {
- propsData: props,
- store,
- stubs: {
- DetailRow,
- },
- }),
- );
- };
-
- describe('when no details are available', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('should render an empty container', () => {
- expect(wrapper.html()).toBe('');
- });
-
- it.each(['duration', 'erased_at', 'finished_at', 'queued_at', 'runner', 'coverage'])(
- 'should not render %s details when missing',
- async (detail) => {
- await store.dispatch('receiveJobSuccess', { [detail]: undefined });
-
- expect(findAllDetailsRow()).toHaveLength(0);
- },
- );
- });
-
- describe('when some of the details are available', () => {
- beforeEach(createWrapper);
-
- it.each([
- ['duration', 'Elapsed time: 6 seconds'],
- ['erased_at', 'Erased: 3 weeks ago'],
- ['finished_at', 'Finished: 3 weeks ago'],
- ['queued_duration', 'Queued: 9 seconds'],
- ['runner', 'Runner: #1 (ABCDEFGH) local ci runner'],
- ['coverage', 'Coverage: 20%'],
- ])('uses %s to render job-%s', async (detail, value) => {
- await store.dispatch('receiveJobSuccess', { [detail]: job[detail] });
- const detailsRow = findAllDetailsRow();
-
- expect(detailsRow).toHaveLength(1);
- expect(detailsRow.at(0).text()).toBe(value);
- });
-
- it('only renders tags', async () => {
- const { tags } = job;
- await store.dispatch('receiveJobSuccess', { tags });
- const tagsComponent = findJobTags();
-
- expect(tagsComponent.text()).toBe('Tags: tag');
- });
- });
-
- describe('when all the info are available', () => {
- it('renders all the details components', async () => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', job);
-
- expect(findAllDetailsRow()).toHaveLength(7);
- });
-
- describe('duration row', () => {
- it('renders all the details components', async () => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', job);
-
- expect(findAllDetailsRow().at(0).text()).toBe('Duration: 6 seconds');
- });
- });
- });
-
- describe('timeout', () => {
- const {
- metadata: { timeout_human_readable, timeout_source },
- } = job;
-
- beforeEach(createWrapper);
-
- it('does not render if metadata is empty', async () => {
- const metadata = {};
- await store.dispatch('receiveJobSuccess', { metadata });
- const detailsRow = findAllDetailsRow();
-
- expect(wrapper.html()).toBe('');
- expect(detailsRow.exists()).toBe(false);
- });
-
- it('uses metadata to render timeout', async () => {
- const metadata = { timeout_human_readable };
- await store.dispatch('receiveJobSuccess', { metadata });
- const detailsRow = findAllDetailsRow();
-
- expect(detailsRow).toHaveLength(1);
- expect(detailsRow.at(0).text()).toBe('Timeout: 1m 40s');
- });
-
- it('uses metadata to render timeout and the source', async () => {
- const metadata = { timeout_human_readable, timeout_source };
- await store.dispatch('receiveJobSuccess', { metadata });
- const detailsRow = findAllDetailsRow();
-
- expect(detailsRow.at(0).text()).toBe('Timeout: 1m 40s (from runner)');
- });
-
- it('should not render when no time is provided', async () => {
- const metadata = { timeout_source };
- await store.dispatch('receiveJobSuccess', { metadata });
-
- expect(findJobTimeout().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/job_sidebar_retry_button_spec.js b/spec/frontend/jobs/components/job/job_sidebar_retry_button_spec.js
deleted file mode 100644
index 8a63bfdc3d6..00000000000
--- a/spec/frontend/jobs/components/job/job_sidebar_retry_button_spec.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import JobsSidebarRetryButton from '~/jobs/components/job/sidebar/job_sidebar_retry_button.vue';
-import createStore from '~/jobs/store';
-import job from '../../mock_data';
-
-describe('Job Sidebar Retry Button', () => {
- let store;
- let wrapper;
-
- const forwardDeploymentFailure = 'forward_deployment_failure';
- const findRetryButton = () => wrapper.findByTestId('retry-job-button');
- const findRetryLink = () => wrapper.findByTestId('retry-job-link');
-
- const createWrapper = ({ props = {} } = {}) => {
- store = createStore();
- wrapper = shallowMountExtended(JobsSidebarRetryButton, {
- propsData: {
- href: job.retry_path,
- isManualJob: false,
- modalId: 'modal-id',
- ...props,
- },
- store,
- });
- };
-
- beforeEach(createWrapper);
-
- it.each([
- [null, false, true],
- ['unmet_prerequisites', false, true],
- [forwardDeploymentFailure, true, false],
- ])(
- 'when error is: %s, should render button: %s | should render link: %s',
- async (failureReason, buttonExists, linkExists) => {
- await store.dispatch('receiveJobSuccess', { ...job, failure_reason: failureReason });
-
- expect(findRetryButton().exists()).toBe(buttonExists);
- expect(findRetryLink().exists()).toBe(linkExists);
- },
- );
-
- describe('Button', () => {
- it('should have the correct configuration', async () => {
- await store.dispatch('receiveJobSuccess', { failure_reason: forwardDeploymentFailure });
-
- expect(findRetryButton().attributes()).toMatchObject({
- category: 'primary',
- variant: 'confirm',
- icon: 'retry',
- });
- });
- });
-
- describe('Link', () => {
- it('should have the correct configuration', () => {
- expect(findRetryLink().attributes()).toMatchObject({
- 'data-method': 'post',
- href: job.retry_path,
- icon: 'retry',
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/jobs_container_spec.js b/spec/frontend/jobs/components/job/jobs_container_spec.js
deleted file mode 100644
index 05660880751..00000000000
--- a/spec/frontend/jobs/components/job/jobs_container_spec.js
+++ /dev/null
@@ -1,143 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import JobsContainer from '~/jobs/components/job/sidebar/jobs_container.vue';
-
-describe('Jobs List block', () => {
- let wrapper;
-
- const retried = {
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- id: 233432756,
- tooltip: 'build - passed',
- retried: true,
- };
-
- const active = {
- name: 'test',
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- id: 2322756,
- tooltip: 'build - passed',
- active: true,
- };
-
- const job = {
- name: 'build',
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- id: 232153,
- tooltip: 'build - passed',
- };
-
- const findAllJobs = () => wrapper.findAllComponents(GlLink);
- const findJob = () => findAllJobs().at(0);
-
- const findArrowIcon = () => wrapper.findByTestId('arrow-right-icon');
- const findRetryIcon = () => wrapper.findByTestId('retry-icon');
-
- const createComponent = (props) => {
- wrapper = extendedWrapper(
- mount(JobsContainer, {
- propsData: {
- ...props,
- },
- }),
- );
- };
-
- it('renders a list of jobs', () => {
- createComponent({
- jobs: [job, retried, active],
- jobId: 12313,
- });
-
- expect(findAllJobs()).toHaveLength(3);
- });
-
- it('renders the arrow right icon when job id matches `jobId`', () => {
- createComponent({
- jobs: [active],
- jobId: active.id,
- });
-
- expect(findArrowIcon().exists()).toBe(true);
- });
-
- it('does not render the arrow right icon when the job is not active', () => {
- createComponent({
- jobs: [job],
- jobId: active.id,
- });
-
- expect(findArrowIcon().exists()).toBe(false);
- });
-
- it('renders the job name when present', () => {
- createComponent({
- jobs: [job],
- jobId: active.id,
- });
-
- expect(findJob().text()).toBe(job.name);
- expect(findJob().text()).not.toContain(job.id.toString());
- });
-
- it('renders job id when job name is not available', () => {
- createComponent({
- jobs: [retried],
- jobId: active.id,
- });
-
- expect(findJob().text()).toBe(retried.id.toString());
- });
-
- it('links to the job page', () => {
- createComponent({
- jobs: [job],
- jobId: active.id,
- });
-
- expect(findJob().attributes('href')).toBe(job.status.details_path);
- });
-
- it('renders retry icon when job was retried', () => {
- createComponent({
- jobs: [retried],
- jobId: active.id,
- });
-
- expect(findRetryIcon().exists()).toBe(true);
- });
-
- it('does not render retry icon when job was not retried', () => {
- createComponent({
- jobs: [job],
- jobId: active.id,
- });
-
- expect(findRetryIcon().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/jobs/components/job/manual_variables_form_spec.js b/spec/frontend/jobs/components/job/manual_variables_form_spec.js
deleted file mode 100644
index 989fe5c11e9..00000000000
--- a/spec/frontend/jobs/components/job/manual_variables_form_spec.js
+++ /dev/null
@@ -1,364 +0,0 @@
-import { GlSprintf, GlLink } from '@gitlab/ui';
-import { createLocalVue } from '@vue/test-utils';
-import VueApollo from 'vue-apollo';
-import { nextTick } from 'vue';
-import { createAlert } from '~/alert';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { TYPENAME_CI_BUILD } from '~/graphql_shared/constants';
-import { JOB_GRAPHQL_ERRORS } from '~/jobs/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import waitForPromises from 'helpers/wait_for_promises';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import ManualVariablesForm from '~/jobs/components/job/manual_variables_form.vue';
-import getJobQuery from '~/jobs/components/job/graphql/queries/get_job.query.graphql';
-import playJobMutation from '~/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql';
-import retryJobMutation from '~/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql';
-
-import {
- mockFullPath,
- mockId,
- mockJobResponse,
- mockJobWithVariablesResponse,
- mockJobPlayMutationData,
- mockJobRetryMutationData,
-} from './mock_data';
-
-const localVue = createLocalVue();
-jest.mock('~/alert');
-localVue.use(VueApollo);
-
-jest.mock('~/lib/utils/url_utility', () => ({
- ...jest.requireActual('~/lib/utils/url_utility'),
- redirectTo: jest.fn(),
-}));
-
-const defaultProvide = {
- projectPath: mockFullPath,
-};
-
-describe('Manual Variables Form', () => {
- let wrapper;
- let mockApollo;
- let requestHandlers;
-
- const getJobQueryResponseHandlerWithVariables = jest.fn().mockResolvedValue(mockJobResponse);
- const playJobMutationHandler = jest.fn().mockResolvedValue({});
- const retryJobMutationHandler = jest.fn().mockResolvedValue({});
-
- const defaultHandlers = {
- getJobQueryResponseHandlerWithVariables,
- playJobMutationHandler,
- retryJobMutationHandler,
- };
-
- const createComponent = ({ props = {}, handlers = defaultHandlers } = {}) => {
- requestHandlers = handlers;
-
- mockApollo = createMockApollo([
- [getJobQuery, handlers.getJobQueryResponseHandlerWithVariables],
- [playJobMutation, handlers.playJobMutationHandler],
- [retryJobMutation, handlers.retryJobMutationHandler],
- ]);
-
- const options = {
- localVue,
- apolloProvider: mockApollo,
- };
-
- wrapper = mountExtended(ManualVariablesForm, {
- propsData: {
- jobId: mockId,
- isRetryable: false,
- ...props,
- },
- provide: {
- ...defaultProvide,
- },
- ...options,
- });
-
- return waitForPromises();
- };
-
- const findHelpText = () => wrapper.findComponent(GlSprintf);
- const findHelpLink = () => wrapper.findComponent(GlLink);
- const findCancelBtn = () => wrapper.findByTestId('cancel-btn');
- const findRunBtn = () => wrapper.findByTestId('run-manual-job-btn');
- const findDeleteVarBtn = () => wrapper.findByTestId('delete-variable-btn');
- const findAllDeleteVarBtns = () => wrapper.findAllByTestId('delete-variable-btn');
- const findDeleteVarBtnPlaceholder = () => wrapper.findByTestId('delete-variable-btn-placeholder');
- const findCiVariableKey = () => wrapper.findByTestId('ci-variable-key');
- const findAllCiVariableKeys = () => wrapper.findAllByTestId('ci-variable-key');
- const findCiVariableValue = () => wrapper.findByTestId('ci-variable-value');
- const findAllVariables = () => wrapper.findAllByTestId('ci-variable-row');
-
- const setCiVariableKey = () => {
- findCiVariableKey().setValue('new key');
- findCiVariableKey().vm.$emit('change');
- nextTick();
- };
-
- const setCiVariableKeyByPosition = (position, value) => {
- findAllCiVariableKeys().at(position).setValue(value);
- findAllCiVariableKeys().at(position).vm.$emit('change');
- nextTick();
- };
-
- afterEach(() => {
- createAlert.mockClear();
- });
-
- describe('when page renders', () => {
- beforeEach(async () => {
- await createComponent();
- });
-
- it('renders help text with provided link', () => {
- expect(findHelpText().exists()).toBe(true);
- expect(findHelpLink().attributes('href')).toBe(
- '/help/ci/variables/index#add-a-cicd-variable-to-a-project',
- );
- });
- });
-
- describe('when query is unsuccessful', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest.fn().mockRejectedValue({}),
- },
- });
- });
-
- it('shows an alert with error', () => {
- expect(createAlert).toHaveBeenCalledWith({
- message: JOB_GRAPHQL_ERRORS.jobQueryErrorText,
- });
- });
- });
-
- describe('when job has not been retried', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest
- .fn()
- .mockResolvedValue(mockJobWithVariablesResponse),
- },
- });
- });
-
- it('does not render the cancel button', () => {
- expect(findCancelBtn().exists()).toBe(false);
- expect(findRunBtn().exists()).toBe(true);
- });
- });
-
- describe('when job has variables', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest
- .fn()
- .mockResolvedValue(mockJobWithVariablesResponse),
- },
- });
- });
-
- it('sets manual job variables', () => {
- const queryKey = mockJobWithVariablesResponse.data.project.job.manualVariables.nodes[0].key;
- const queryValue =
- mockJobWithVariablesResponse.data.project.job.manualVariables.nodes[0].value;
-
- expect(findCiVariableKey().element.value).toBe(queryKey);
- expect(findCiVariableValue().element.value).toBe(queryValue);
- });
- });
-
- describe('when play mutation fires', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- playJobMutationHandler: jest.fn().mockResolvedValue(mockJobPlayMutationData),
- },
- });
- });
-
- it('passes variables in correct format', async () => {
- await setCiVariableKey();
-
- await findCiVariableValue().setValue('new value');
-
- await findRunBtn().vm.$emit('click');
-
- expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledTimes(1);
- expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledWith({
- id: convertToGraphQLId(TYPENAME_CI_BUILD, mockId),
- variables: [
- {
- key: 'new key',
- value: 'new value',
- },
- ],
- });
- });
-
- it('redirects to job properly after job is run', async () => {
- findRunBtn().vm.$emit('click');
- await waitForPromises();
-
- expect(requestHandlers.playJobMutationHandler).toHaveBeenCalledTimes(1);
- expect(redirectTo).toHaveBeenCalledWith(mockJobPlayMutationData.data.jobPlay.job.webPath); // eslint-disable-line import/no-deprecated
- });
- });
-
- describe('when play mutation is unsuccessful', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- playJobMutationHandler: jest.fn().mockRejectedValue({}),
- },
- });
- });
-
- it('shows an alert with error', async () => {
- findRunBtn().vm.$emit('click');
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: JOB_GRAPHQL_ERRORS.jobMutationErrorText,
- });
- });
- });
-
- describe('when job is retryable', () => {
- beforeEach(async () => {
- await createComponent({
- props: { isRetryable: true },
- handlers: {
- retryJobMutationHandler: jest.fn().mockResolvedValue(mockJobRetryMutationData),
- },
- });
- });
-
- it('renders cancel button', () => {
- expect(findCancelBtn().exists()).toBe(true);
- });
-
- it('redirects to job properly after rerun', async () => {
- findRunBtn().vm.$emit('click');
- await waitForPromises();
-
- expect(requestHandlers.retryJobMutationHandler).toHaveBeenCalledTimes(1);
- expect(redirectTo).toHaveBeenCalledWith(mockJobRetryMutationData.data.jobRetry.job.webPath); // eslint-disable-line import/no-deprecated
- });
- });
-
- describe('when retry mutation is unsuccessful', () => {
- beforeEach(async () => {
- await createComponent({
- props: { isRetryable: true },
- handlers: {
- retryJobMutationHandler: jest.fn().mockRejectedValue({}),
- },
- });
- });
-
- it('shows an alert with error', async () => {
- findRunBtn().vm.$emit('click');
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: JOB_GRAPHQL_ERRORS.jobMutationErrorText,
- });
- });
- });
-
- describe('updating variables in UI', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest.fn().mockResolvedValue(mockJobResponse),
- },
- });
- });
-
- it('creates a new variable when user enters a new key value', async () => {
- expect(findAllVariables()).toHaveLength(1);
-
- await setCiVariableKey();
-
- expect(findAllVariables()).toHaveLength(2);
- });
-
- it('does not create extra empty variables', async () => {
- expect(findAllVariables()).toHaveLength(1);
-
- await setCiVariableKey();
-
- expect(findAllVariables()).toHaveLength(2);
-
- await setCiVariableKey();
-
- expect(findAllVariables()).toHaveLength(2);
- });
-
- it('removes the correct variable row', async () => {
- const variableKeyNameOne = 'key-one';
- const variableKeyNameThree = 'key-three';
-
- await setCiVariableKeyByPosition(0, variableKeyNameOne);
-
- await setCiVariableKeyByPosition(1, 'key-two');
-
- await setCiVariableKeyByPosition(2, variableKeyNameThree);
-
- expect(findAllVariables()).toHaveLength(4);
-
- await findAllDeleteVarBtns().at(1).trigger('click');
-
- expect(findAllVariables()).toHaveLength(3);
-
- expect(findAllCiVariableKeys().at(0).element.value).toBe(variableKeyNameOne);
- expect(findAllCiVariableKeys().at(1).element.value).toBe(variableKeyNameThree);
- expect(findAllCiVariableKeys().at(2).element.value).toBe('');
- });
-
- it('delete variable button should only show when there is more than one variable', async () => {
- expect(findDeleteVarBtn().exists()).toBe(false);
-
- await setCiVariableKey();
-
- expect(findDeleteVarBtn().exists()).toBe(true);
- });
- });
-
- describe('variable delete button placeholder', () => {
- beforeEach(async () => {
- await createComponent({
- handlers: {
- getJobQueryResponseHandlerWithVariables: jest.fn().mockResolvedValue(mockJobResponse),
- },
- });
- });
-
- it('delete variable button placeholder should only exist when a user cannot remove', () => {
- expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
- });
-
- it('does not show the placeholder button', () => {
- expect(findDeleteVarBtnPlaceholder().classes('gl-opacity-0')).toBe(true);
- });
-
- it('placeholder button will not delete the row on click', async () => {
- expect(findAllCiVariableKeys()).toHaveLength(1);
- expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
-
- await findDeleteVarBtnPlaceholder().trigger('click');
-
- expect(findAllCiVariableKeys()).toHaveLength(1);
- expect(findDeleteVarBtnPlaceholder().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js b/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js
deleted file mode 100644
index 546f5392caf..00000000000
--- a/spec/frontend/jobs/components/job/sidebar_detail_row_spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import SidebarDetailRow from '~/jobs/components/job/sidebar/sidebar_detail_row.vue';
-import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
-
-describe('Sidebar detail row', () => {
- let wrapper;
-
- const title = 'this is the title';
- const value = 'this is the value';
- const helpUrl = `${DOCS_URL}/runner/register/index.html`;
- const path = 'path/to/value';
-
- const findHelpLink = () => wrapper.findByTestId('job-sidebar-help-link');
- const findValueLink = () => wrapper.findByTestId('job-sidebar-value-link');
-
- const createComponent = (props) => {
- wrapper = shallowMountExtended(SidebarDetailRow, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('with title/value and without helpUrl/path', () => {
- beforeEach(() => {
- createComponent({ title, value });
- });
-
- it('should render the provided title and value', () => {
- expect(wrapper.text()).toBe(`${title}: ${value}`);
- });
-
- it('should not render the help link', () => {
- expect(findHelpLink().exists()).toBe(false);
- });
-
- it('should not render the value link', () => {
- expect(findValueLink().exists()).toBe(false);
- });
- });
-
- describe('when helpUrl provided', () => {
- beforeEach(() => {
- createComponent({
- helpUrl,
- title,
- value,
- });
- });
-
- it('should render the help link', () => {
- expect(findHelpLink().exists()).toBe(true);
- expect(findHelpLink().attributes('href')).toBe(helpUrl);
- });
- });
-
- describe('when path is provided', () => {
- it('should render link to value', () => {
- createComponent({
- path,
- title,
- value,
- });
-
- expect(findValueLink().attributes('href')).toBe(path);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/sidebar_header_spec.js b/spec/frontend/jobs/components/job/sidebar_header_spec.js
deleted file mode 100644
index cf182330578..00000000000
--- a/spec/frontend/jobs/components/job/sidebar_header_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import SidebarHeader from '~/jobs/components/job/sidebar/sidebar_header.vue';
-import JobRetryButton from '~/jobs/components/job/sidebar/job_sidebar_retry_button.vue';
-import getJobQuery from '~/jobs/components/job/graphql/queries/get_job.query.graphql';
-import { mockFullPath, mockId, mockJobResponse } from './mock_data';
-
-Vue.use(VueApollo);
-
-const defaultProvide = {
- projectPath: mockFullPath,
-};
-
-describe('Sidebar Header', () => {
- let wrapper;
-
- const createComponent = ({ options = {}, props = {}, restJob = {} } = {}) => {
- wrapper = shallowMountExtended(SidebarHeader, {
- propsData: {
- ...props,
- jobId: mockId,
- restJob,
- },
- provide: {
- ...defaultProvide,
- },
- ...options,
- });
- };
-
- const createComponentWithApollo = ({ props = {}, restJob = {} } = {}) => {
- const getJobQueryResponse = jest.fn().mockResolvedValue(mockJobResponse);
-
- const requestHandlers = [[getJobQuery, getJobQueryResponse]];
-
- const apolloProvider = createMockApollo(requestHandlers);
-
- const options = {
- apolloProvider,
- };
-
- createComponent({
- props,
- restJob,
- options,
- });
-
- return waitForPromises();
- };
-
- const findCancelButton = () => wrapper.findByTestId('cancel-button');
- const findEraseButton = () => wrapper.findByTestId('job-log-erase-link');
- const findJobName = () => wrapper.findByTestId('job-name');
- const findRetryButton = () => wrapper.findComponent(JobRetryButton);
-
- describe('when rendering contents', () => {
- it('renders the correct job name', async () => {
- await createComponentWithApollo();
- expect(findJobName().text()).toBe(mockJobResponse.data.project.job.name);
- });
-
- it('does not render buttons with no paths', async () => {
- await createComponentWithApollo();
- expect(findCancelButton().exists()).toBe(false);
- expect(findEraseButton().exists()).toBe(false);
- expect(findRetryButton().exists()).toBe(false);
- });
-
- it('renders a retry button with a path', async () => {
- await createComponentWithApollo({ restJob: { retry_path: 'retry/path' } });
- expect(findRetryButton().exists()).toBe(true);
- });
-
- it('renders a cancel button with a path', async () => {
- await createComponentWithApollo({ restJob: { cancel_path: 'cancel/path' } });
- expect(findCancelButton().exists()).toBe(true);
- });
-
- it('renders an erase button with a path', async () => {
- await createComponentWithApollo({ restJob: { erase_path: 'erase/path' } });
- expect(findEraseButton().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/sidebar_spec.js b/spec/frontend/jobs/components/job/sidebar_spec.js
deleted file mode 100644
index fbff64b4d78..00000000000
--- a/spec/frontend/jobs/components/job/sidebar_spec.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import MockAdapter from 'axios-mock-adapter';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import ArtifactsBlock from '~/jobs/components/job/sidebar/artifacts_block.vue';
-import JobRetryForwardDeploymentModal from '~/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue';
-import JobsContainer from '~/jobs/components/job/sidebar/jobs_container.vue';
-import Sidebar from '~/jobs/components/job/sidebar/sidebar.vue';
-import StagesDropdown from '~/jobs/components/job/sidebar/stages_dropdown.vue';
-import createStore from '~/jobs/store';
-import job, { jobsInStage } from '../../mock_data';
-
-describe('Sidebar details block', () => {
- let mock;
- let store;
- let wrapper;
-
- const forwardDeploymentFailure = 'forward_deployment_failure';
- const findModal = () => wrapper.findComponent(JobRetryForwardDeploymentModal);
- const findArtifactsBlock = () => wrapper.findComponent(ArtifactsBlock);
- const findNewIssueButton = () => wrapper.findByTestId('job-new-issue');
- const findTerminalLink = () => wrapper.findByTestId('terminal-link');
- const findJobStagesDropdown = () => wrapper.findComponent(StagesDropdown);
- const findJobsContainer = () => wrapper.findComponent(JobsContainer);
-
- const createWrapper = (props) => {
- store = createStore();
-
- store.state.job = job;
-
- wrapper = extendedWrapper(
- shallowMount(Sidebar, {
- propsData: {
- ...props,
- },
-
- store,
- }),
- );
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- mock.onGet().reply(HTTP_STATUS_OK, {
- name: job.stage,
- });
- });
-
- describe('without terminal path', () => {
- it('does not render terminal link', async () => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', job);
-
- expect(findTerminalLink().exists()).toBe(false);
- });
- });
-
- describe('with terminal path', () => {
- it('renders terminal link', async () => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', { ...job, terminal_path: 'job/43123/terminal' });
-
- expect(findTerminalLink().exists()).toBe(true);
- });
- });
-
- describe('actions', () => {
- beforeEach(() => {
- createWrapper();
- return store.dispatch('receiveJobSuccess', job);
- });
-
- it('should render link to new issue', () => {
- expect(findNewIssueButton().attributes('href')).toBe(job.new_issue_path);
- expect(findNewIssueButton().text()).toBe('New issue');
- });
- });
-
- describe('forward deployment failure', () => {
- describe('when the relevant data is missing', () => {
- it.each`
- retryPath | failureReason
- ${null} | ${null}
- ${''} | ${''}
- ${job.retry_path} | ${''}
- ${''} | ${forwardDeploymentFailure}
- ${job.retry_path} | ${'unmet_prerequisites'}
- `(
- 'should not render the modal when path and failure are $retryPath, $failureReason',
- async ({ retryPath, failureReason }) => {
- createWrapper();
- await store.dispatch('receiveJobSuccess', {
- ...job,
- failure_reason: failureReason,
- retry_path: retryPath,
- });
- expect(findModal().exists()).toBe(false);
- },
- );
- });
-
- describe('when there is the relevant error', () => {
- beforeEach(() => {
- createWrapper();
- return store.dispatch('receiveJobSuccess', {
- ...job,
- failure_reason: forwardDeploymentFailure,
- });
- });
-
- it('should render the modal', () => {
- expect(findModal().exists()).toBe(true);
- });
- });
- });
-
- describe('stages dropdown', () => {
- beforeEach(() => {
- createWrapper();
- return store.dispatch('receiveJobSuccess', job);
- });
-
- describe('with stages', () => {
- it('renders value provided as selectedStage as selected', () => {
- expect(findJobStagesDropdown().props('selectedStage')).toBe(job.stage);
- });
- });
-
- describe('without jobs for stages', () => {
- it('does not render jobs container', () => {
- expect(findJobsContainer().exists()).toBe(false);
- });
- });
-
- describe('with jobs for stages', () => {
- beforeEach(() => {
- return store.dispatch('receiveJobsForStageSuccess', jobsInStage.latest_statuses);
- });
-
- it('renders list of jobs', () => {
- expect(findJobsContainer().exists()).toBe(true);
- });
- });
-
- describe('when job data changes', () => {
- const stageArg = job.pipeline.details.stages.find((stage) => stage.name === job.stage);
-
- beforeEach(() => {
- jest.spyOn(store, 'dispatch');
- });
-
- describe('and the job stage is currently selected', () => {
- describe('when the status changed', () => {
- it('refetch the jobs list for the stage', async () => {
- await store.dispatch('receiveJobSuccess', { ...job, status: 'new' });
-
- expect(store.dispatch).toHaveBeenNthCalledWith(2, 'fetchJobsForStage', { ...stageArg });
- });
- });
-
- describe('when the status did not change', () => {
- it('does not refetch the jobs list for the stage', async () => {
- await store.dispatch('receiveJobSuccess', { ...job });
-
- expect(store.dispatch).toHaveBeenCalledTimes(1);
- expect(store.dispatch).toHaveBeenNthCalledWith(1, 'receiveJobSuccess', {
- ...job,
- });
- });
- });
- });
-
- describe('and the job stage is not currently selected', () => {
- it('does not refetch the jobs list for the stage', async () => {
- // Setting stage to `random` on the job means that we are looking
- // at `build` stage currently, but the job we are seeing in the logs
- // belong to `random`, so we shouldn't have to refetch
- await store.dispatch('receiveJobSuccess', { ...job, stage: 'random' });
-
- expect(store.dispatch).toHaveBeenCalledTimes(1);
- expect(store.dispatch).toHaveBeenNthCalledWith(1, 'receiveJobSuccess', {
- ...job,
- stage: 'random',
- });
- });
- });
- });
- });
-
- describe('artifacts', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('artifacts are not shown if there are no properties other than locked', () => {
- expect(findArtifactsBlock().exists()).toBe(false);
- });
-
- it('artifacts are shown if present', async () => {
- store.state.job.artifact = {
- download_path: '/root/ci-project/-/jobs/1960/artifacts/download',
- browse_path: '/root/ci-project/-/jobs/1960/artifacts/browse',
- keep_path: '/root/ci-project/-/jobs/1960/artifacts/keep',
- expire_at: '2021-03-23T17:57:11.211Z',
- expired: false,
- locked: false,
- };
-
- await nextTick();
-
- expect(findArtifactsBlock().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/stages_dropdown_spec.js b/spec/frontend/jobs/components/job/stages_dropdown_spec.js
deleted file mode 100644
index c42edc62183..00000000000
--- a/spec/frontend/jobs/components/job/stages_dropdown_spec.js
+++ /dev/null
@@ -1,191 +0,0 @@
-import { GlDisclosureDropdown, GlLink, GlSprintf } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { Mousetrap } from '~/lib/mousetrap';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import StagesDropdown from '~/jobs/components/job/sidebar/stages_dropdown.vue';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import * as copyToClipboard from '~/behaviors/copy_to_clipboard';
-import {
- mockPipelineWithoutRef,
- mockPipelineWithoutMR,
- mockPipelineWithAttachedMR,
- mockPipelineDetached,
-} from '../../mock_data';
-
-describe('Stages Dropdown', () => {
- let wrapper;
-
- const findStatus = () => wrapper.findComponent(CiIcon);
- const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
- const findSelectedStageText = () => findDropdown().props('toggleText');
-
- const findPipelineInfoText = () => wrapper.findByTestId('pipeline-info').text();
-
- const createComponent = (props) => {
- wrapper = extendedWrapper(
- shallowMount(StagesDropdown, {
- propsData: {
- stages: [],
- selectedStage: 'deploy',
- ...props,
- },
- stubs: {
- GlSprintf,
- GlLink,
- },
- }),
- );
- };
-
- describe('without a merge request pipeline', () => {
- beforeEach(() => {
- createComponent({
- pipeline: mockPipelineWithoutMR,
- stages: [{ name: 'build' }, { name: 'test' }],
- });
- });
-
- it('renders pipeline status', () => {
- expect(findStatus().exists()).toBe(true);
- });
-
- it('renders dropdown with stages', () => {
- expect(findDropdown().props('items')).toEqual([
- expect.objectContaining({ text: 'build' }),
- expect.objectContaining({ text: 'test' }),
- ]);
- });
-
- it('renders selected stage', () => {
- expect(findSelectedStageText()).toBe('deploy');
- });
- });
-
- describe('pipelineInfo', () => {
- const allElements = [
- 'pipeline-path',
- 'mr-link',
- 'source-ref-link',
- 'copy-source-ref-link',
- 'source-branch-link',
- 'copy-source-branch-link',
- 'target-branch-link',
- 'copy-target-branch-link',
- ];
- describe.each([
- [
- 'does not have a ref',
- {
- pipeline: mockPipelineWithoutRef,
- text: `Pipeline #${mockPipelineWithoutRef.id}`,
- foundElements: [
- { testId: 'pipeline-path', props: [{ href: mockPipelineWithoutRef.path }] },
- ],
- },
- ],
- [
- 'hasRef but not triggered by MR',
- {
- pipeline: mockPipelineWithoutMR,
- text: `Pipeline #${mockPipelineWithoutMR.id} for ${mockPipelineWithoutMR.ref.name}`,
- foundElements: [
- { testId: 'pipeline-path', props: [{ href: mockPipelineWithoutMR.path }] },
- { testId: 'source-ref-link', props: [{ href: mockPipelineWithoutMR.ref.path }] },
- { testId: 'copy-source-ref-link', props: [{ text: mockPipelineWithoutMR.ref.name }] },
- ],
- },
- ],
- [
- 'hasRef and MR but not MR pipeline',
- {
- pipeline: mockPipelineDetached,
- text: `Pipeline #${mockPipelineDetached.id} for !${mockPipelineDetached.merge_request.iid} with ${mockPipelineDetached.merge_request.source_branch}`,
- foundElements: [
- { testId: 'pipeline-path', props: [{ href: mockPipelineDetached.path }] },
- { testId: 'mr-link', props: [{ href: mockPipelineDetached.merge_request.path }] },
- {
- testId: 'source-branch-link',
- props: [{ href: mockPipelineDetached.merge_request.source_branch_path }],
- },
- {
- testId: 'copy-source-branch-link',
- props: [{ text: mockPipelineDetached.merge_request.source_branch }],
- },
- ],
- },
- ],
- [
- 'hasRef and MR and MR pipeline',
- {
- pipeline: mockPipelineWithAttachedMR,
- text: `Pipeline #${mockPipelineWithAttachedMR.id} for !${mockPipelineWithAttachedMR.merge_request.iid} with ${mockPipelineWithAttachedMR.merge_request.source_branch} into ${mockPipelineWithAttachedMR.merge_request.target_branch}`,
- foundElements: [
- { testId: 'pipeline-path', props: [{ href: mockPipelineWithAttachedMR.path }] },
- { testId: 'mr-link', props: [{ href: mockPipelineWithAttachedMR.merge_request.path }] },
- {
- testId: 'source-branch-link',
- props: [{ href: mockPipelineWithAttachedMR.merge_request.source_branch_path }],
- },
- {
- testId: 'copy-source-branch-link',
- props: [{ text: mockPipelineWithAttachedMR.merge_request.source_branch }],
- },
- {
- testId: 'target-branch-link',
- props: [{ href: mockPipelineWithAttachedMR.merge_request.target_branch_path }],
- },
- {
- testId: 'copy-target-branch-link',
- props: [{ text: mockPipelineWithAttachedMR.merge_request.target_branch }],
- },
- ],
- },
- ],
- ])('%s', (_, { pipeline, text, foundElements }) => {
- beforeEach(() => {
- createComponent({
- pipeline,
- });
- });
-
- it('should render the text', () => {
- expect(findPipelineInfoText()).toMatchInterpolatedText(text);
- });
-
- it('should find components with props', () => {
- foundElements.forEach((element) => {
- element.props.forEach((prop) => {
- const key = Object.keys(prop)[0];
- expect(wrapper.findByTestId(element.testId).attributes(key)).toBe(prop[key]);
- });
- });
- });
-
- it('should not find components', () => {
- const foundTestIds = foundElements.map((element) => element.testId);
- allElements
- .filter((testId) => !foundTestIds.includes(testId))
- .forEach((testId) => {
- expect(wrapper.findByTestId(testId).exists()).toBe(false);
- });
- });
- });
- });
-
- describe('mousetrap', () => {
- it.each([
- ['copy-source-ref-link', mockPipelineWithoutMR],
- ['copy-source-branch-link', mockPipelineWithAttachedMR],
- ])(
- 'calls clickCopyToClipboardButton with `%s` button when `b` is pressed',
- (button, pipeline) => {
- const copyToClipboardMock = jest.spyOn(copyToClipboard, 'clickCopyToClipboardButton');
- createComponent({ pipeline });
-
- Mousetrap.trigger('b');
-
- expect(copyToClipboardMock).toHaveBeenCalledWith(wrapper.findByTestId(button).element);
- },
- );
- });
-});
diff --git a/spec/frontend/jobs/components/job/stuck_block_spec.js b/spec/frontend/jobs/components/job/stuck_block_spec.js
deleted file mode 100644
index 0f014a9222b..00000000000
--- a/spec/frontend/jobs/components/job/stuck_block_spec.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import { GlBadge, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import StuckBlock from '~/jobs/components/job/stuck_block.vue';
-
-describe('Stuck Block Job component', () => {
- let wrapper;
-
- const createWrapper = (props) => {
- wrapper = shallowMount(StuckBlock, {
- propsData: {
- ...props,
- },
- });
- };
-
- const tags = ['docker', 'gitlab-org'];
-
- const findStuckNoActiveRunners = () =>
- wrapper.find('[data-testid="job-stuck-no-active-runners"]');
- const findStuckNoRunners = () => wrapper.find('[data-testid="job-stuck-no-runners"]');
- const findStuckWithTags = () => wrapper.find('[data-testid="job-stuck-with-tags"]');
- const findRunnerPathLink = () => wrapper.findComponent(GlLink);
- const findAllBadges = () => wrapper.findAllComponents(GlBadge);
-
- describe('with no runners for project', () => {
- beforeEach(() => {
- createWrapper({
- hasOfflineRunnersForProject: true,
- runnersPath: '/root/project/runners#js-runners-settings',
- });
- });
-
- it('renders only information about project not having runners', () => {
- expect(findStuckNoRunners().exists()).toBe(true);
- expect(findStuckWithTags().exists()).toBe(false);
- expect(findStuckNoActiveRunners().exists()).toBe(false);
- });
-
- it('renders link to runners page', () => {
- expect(findRunnerPathLink().attributes('href')).toBe(
- '/root/project/runners#js-runners-settings',
- );
- });
- });
-
- describe('with tags', () => {
- beforeEach(() => {
- createWrapper({
- hasOfflineRunnersForProject: false,
- tags,
- runnersPath: '/root/project/runners#js-runners-settings',
- });
- });
-
- it('renders information about the tags not being set', () => {
- expect(findStuckWithTags().exists()).toBe(true);
- expect(findStuckNoActiveRunners().exists()).toBe(false);
- expect(findStuckNoRunners().exists()).toBe(false);
- });
-
- it('renders tags', () => {
- findAllBadges().wrappers.forEach((badgeElt, index) => {
- return expect(badgeElt.text()).toBe(tags[index]);
- });
- });
-
- it('renders link to runners page', () => {
- expect(findRunnerPathLink().attributes('href')).toBe(
- '/root/project/runners#js-runners-settings',
- );
- });
- });
-
- describe('without active runners', () => {
- beforeEach(() => {
- createWrapper({
- hasOfflineRunnersForProject: false,
- runnersPath: '/root/project/runners#js-runners-settings',
- });
- });
-
- it('renders information about project not having runners', () => {
- expect(findStuckNoActiveRunners().exists()).toBe(true);
- expect(findStuckNoRunners().exists()).toBe(false);
- expect(findStuckWithTags().exists()).toBe(false);
- });
-
- it('renders link to runners page', () => {
- expect(findRunnerPathLink().attributes('href')).toBe(
- '/root/project/runners#js-runners-settings',
- );
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/trigger_block_spec.js b/spec/frontend/jobs/components/job/trigger_block_spec.js
deleted file mode 100644
index 8bb2c1f3ad8..00000000000
--- a/spec/frontend/jobs/components/job/trigger_block_spec.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { GlButton, GlTableLite } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import TriggerBlock from '~/jobs/components/job/sidebar/trigger_block.vue';
-
-describe('Trigger block', () => {
- let wrapper;
-
- const findRevealButton = () => wrapper.findComponent(GlButton);
- const findVariableTable = () => wrapper.findComponent(GlTableLite);
- const findShortToken = () => wrapper.find('[data-testid="trigger-short-token"]');
- const findVariableValue = (index) =>
- wrapper.findAll('[data-testid="trigger-build-value"]').at(index);
- const findVariableKey = (index) => wrapper.findAll('[data-testid="trigger-build-key"]').at(index);
-
- const createComponent = (props) => {
- wrapper = mount(TriggerBlock, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('with short token and no variables', () => {
- it('renders short token', () => {
- createComponent({
- trigger: {
- short_token: '0a666b2',
- variables: [],
- },
- });
-
- expect(findShortToken().text()).toContain('0a666b2');
- });
- });
-
- describe('without variables or short token', () => {
- beforeEach(() => {
- createComponent({ trigger: { variables: [] } });
- });
-
- it('does not render short token', () => {
- expect(findShortToken().exists()).toBe(false);
- });
-
- it('does not render variables', () => {
- expect(findRevealButton().exists()).toBe(false);
- expect(findVariableTable().exists()).toBe(false);
- });
- });
-
- describe('with variables', () => {
- describe('hide/reveal variables', () => {
- it('should toggle variables on click', async () => {
- const hiddenValue = '••••••';
- const gcsVar = { key: 'UPLOAD_TO_GCS', value: 'false', public: false };
- const s3Var = { key: 'UPLOAD_TO_S3', value: 'true', public: false };
-
- createComponent({
- trigger: {
- variables: [gcsVar, s3Var],
- },
- });
-
- expect(findRevealButton().text()).toBe('Reveal values');
-
- expect(findVariableValue(0).text()).toBe(hiddenValue);
- expect(findVariableValue(1).text()).toBe(hiddenValue);
-
- expect(findVariableKey(0).text()).toBe(gcsVar.key);
- expect(findVariableKey(1).text()).toBe(s3Var.key);
-
- await findRevealButton().trigger('click');
-
- expect(findRevealButton().text()).toBe('Hide values');
-
- expect(findVariableValue(0).text()).toBe(gcsVar.value);
- expect(findVariableValue(1).text()).toBe(s3Var.value);
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js b/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js
deleted file mode 100644
index 1072cdd6781..00000000000
--- a/spec/frontend/jobs/components/job/unmet_prerequisites_block_spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { GlAlert, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import UnmetPrerequisitesBlock from '~/jobs/components/job/unmet_prerequisites_block.vue';
-
-describe('Unmet Prerequisites Block Job component', () => {
- let wrapper;
- const helpPath = '/user/project/clusters/index.html#troubleshooting-failed-deployment-jobs';
-
- const createComponent = () => {
- wrapper = shallowMount(UnmetPrerequisitesBlock, {
- propsData: {
- helpPath,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('renders an alert with the correct message', () => {
- const container = wrapper.findComponent(GlAlert);
- const alertMessage =
- 'This job failed because the necessary resources were not successfully created.';
-
- expect(container).not.toBeNull();
- expect(container.text()).toContain(alertMessage);
- });
-
- it('renders link to help page', () => {
- const helpLink = wrapper.findComponent(GlLink);
-
- expect(helpLink).not.toBeNull();
- expect(helpLink.text()).toContain('More information');
- expect(helpLink.attributes().href).toEqual(helpPath);
- });
-});
diff --git a/spec/frontend/jobs/components/log/collapsible_section_spec.js b/spec/frontend/jobs/components/log/collapsible_section_spec.js
deleted file mode 100644
index 5adedea28a5..00000000000
--- a/spec/frontend/jobs/components/log/collapsible_section_spec.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import CollapsibleSection from '~/jobs/components/log/collapsible_section.vue';
-import { collapsibleSectionClosed, collapsibleSectionOpened } from './mock_data';
-
-describe('Job Log Collapsible Section', () => {
- let wrapper;
-
- const jobLogEndpoint = 'jobs/335';
-
- const findCollapsibleLine = () => wrapper.find('.collapsible-line');
- const findCollapsibleLineSvg = () => wrapper.find('.collapsible-line svg');
-
- const createComponent = (props = {}) => {
- wrapper = mount(CollapsibleSection, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('with closed section', () => {
- beforeEach(() => {
- createComponent({
- section: collapsibleSectionClosed,
- jobLogEndpoint,
- });
- });
-
- it('renders clickable header line', () => {
- expect(findCollapsibleLine().attributes('role')).toBe('button');
- });
-
- it('renders an icon with the closed state', () => {
- expect(findCollapsibleLineSvg().attributes('data-testid')).toBe('chevron-lg-right-icon');
- });
- });
-
- describe('with opened section', () => {
- beforeEach(() => {
- createComponent({
- section: collapsibleSectionOpened,
- jobLogEndpoint,
- });
- });
-
- it('renders clickable header line', () => {
- expect(findCollapsibleLine().attributes('role')).toBe('button');
- });
-
- it('renders an icon with the open state', () => {
- expect(findCollapsibleLineSvg().attributes('data-testid')).toBe('chevron-lg-down-icon');
- });
-
- it('renders collapsible lines content', () => {
- expect(wrapper.findAll('.js-line').length).toEqual(collapsibleSectionOpened.lines.length);
- });
- });
-
- it('emits onClickCollapsibleLine on click', async () => {
- createComponent({
- section: collapsibleSectionOpened,
- jobLogEndpoint,
- });
-
- findCollapsibleLine().trigger('click');
-
- await nextTick();
- expect(wrapper.emitted('onClickCollapsibleLine').length).toBe(1);
- });
-});
diff --git a/spec/frontend/jobs/components/log/duration_badge_spec.js b/spec/frontend/jobs/components/log/duration_badge_spec.js
deleted file mode 100644
index 644d05366a0..00000000000
--- a/spec/frontend/jobs/components/log/duration_badge_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import DurationBadge from '~/jobs/components/log/duration_badge.vue';
-
-describe('Job Log Duration Badge', () => {
- let wrapper;
-
- const data = {
- duration: '00:30:01',
- };
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(DurationBadge, {
- propsData: {
- ...props,
- },
- });
- };
-
- beforeEach(() => {
- createComponent(data);
- });
-
- it('renders provided duration', () => {
- expect(wrapper.text()).toBe(data.duration);
- });
-});
diff --git a/spec/frontend/jobs/components/log/line_header_spec.js b/spec/frontend/jobs/components/log/line_header_spec.js
deleted file mode 100644
index c02d8c22655..00000000000
--- a/spec/frontend/jobs/components/log/line_header_spec.js
+++ /dev/null
@@ -1,119 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import DurationBadge from '~/jobs/components/log/duration_badge.vue';
-import LineHeader from '~/jobs/components/log/line_header.vue';
-import LineNumber from '~/jobs/components/log/line_number.vue';
-
-describe('Job Log Header Line', () => {
- let wrapper;
-
- const data = {
- line: {
- content: [
- {
- text: 'Running with gitlab-runner 12.1.0 (de7731dd)',
- style: 'term-fg-l-green',
- },
- ],
- lineNumber: 76,
- },
- isClosed: true,
- path: '/jashkenas/underscore/-/jobs/335',
- };
-
- const createComponent = (props = {}) => {
- wrapper = mount(LineHeader, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('line', () => {
- beforeEach(() => {
- createComponent(data);
- });
-
- it('renders the line number component', () => {
- expect(wrapper.findComponent(LineNumber).exists()).toBe(true);
- });
-
- it('renders a span the provided text', () => {
- expect(wrapper.find('span').text()).toBe(data.line.content[0].text);
- });
-
- it('renders the provided style as a class attribute', () => {
- expect(wrapper.find('span').classes()).toContain(data.line.content[0].style);
- });
- });
-
- describe('when isCloses is true', () => {
- beforeEach(() => {
- createComponent({ ...data, isClosed: true });
- });
-
- it('sets icon name to be chevron-lg-right', () => {
- expect(wrapper.vm.iconName).toEqual('chevron-lg-right');
- });
- });
-
- describe('when isCloses is false', () => {
- beforeEach(() => {
- createComponent({ ...data, isClosed: false });
- });
-
- it('sets icon name to be chevron-lg-down', () => {
- expect(wrapper.vm.iconName).toEqual('chevron-lg-down');
- });
- });
-
- describe('on click', () => {
- beforeEach(() => {
- createComponent(data);
- });
-
- it('emits toggleLine event', async () => {
- wrapper.trigger('click');
-
- await nextTick();
- expect(wrapper.emitted().toggleLine.length).toBe(1);
- });
- });
-
- describe('with duration', () => {
- beforeEach(() => {
- createComponent({ ...data, duration: '00:10' });
- });
-
- it('renders the duration badge', () => {
- expect(wrapper.findComponent(DurationBadge).exists()).toBe(true);
- });
- });
-
- describe('line highlighting', () => {
- describe('with hash', () => {
- beforeEach(() => {
- setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353#L77`);
-
- createComponent(data);
- });
-
- it('highlights line', () => {
- expect(wrapper.classes()).toContain('gl-bg-gray-700');
- });
- });
-
- describe('without hash', () => {
- beforeEach(() => {
- setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353`);
-
- createComponent(data);
- });
-
- it('does not highlight line', () => {
- expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/log/line_number_spec.js b/spec/frontend/jobs/components/log/line_number_spec.js
deleted file mode 100644
index 4130c124a30..00000000000
--- a/spec/frontend/jobs/components/log/line_number_spec.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import LineNumber from '~/jobs/components/log/line_number.vue';
-
-describe('Job Log Line Number', () => {
- let wrapper;
-
- const data = {
- lineNumber: 0,
- path: '/jashkenas/underscore/-/jobs/335',
- };
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(LineNumber, {
- propsData: {
- ...props,
- },
- });
- };
-
- beforeEach(() => {
- createComponent(data);
- });
-
- it('renders incremented lineNunber by 1', () => {
- expect(wrapper.text()).toBe('1');
- });
-
- it('renders link with lineNumber as an ID', () => {
- expect(wrapper.attributes().id).toBe('L1');
- });
-
- it('links to the provided path with line number as anchor', () => {
- expect(wrapper.attributes().href).toBe(`${data.path}#L1`);
- });
-});
diff --git a/spec/frontend/jobs/components/log/line_spec.js b/spec/frontend/jobs/components/log/line_spec.js
deleted file mode 100644
index fad7a03beef..00000000000
--- a/spec/frontend/jobs/components/log/line_spec.js
+++ /dev/null
@@ -1,267 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import Line from '~/jobs/components/log/line.vue';
-import LineNumber from '~/jobs/components/log/line_number.vue';
-import setWindowLocation from 'helpers/set_window_location_helper';
-
-const httpUrl = 'http://example.com';
-const httpsUrl = 'https://example.com';
-const queryUrl = 'https://example.com?param=val';
-
-const mockProps = ({ text = 'Running with gitlab-runner 12.1.0 (de7731dd)' } = {}) => ({
- line: {
- content: [
- {
- text,
- style: 'term-fg-l-green',
- },
- ],
- lineNumber: 0,
- },
- path: '/jashkenas/underscore/-/jobs/335',
-});
-
-describe('Job Log Line', () => {
- let wrapper;
- let data;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(Line, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findLine = () => wrapper.find('span');
- const findLink = () => findLine().find('a');
- const findLinks = () => findLine().findAll('a');
- const findLinkAttributeByIndex = (i) => findLinks().at(i).attributes();
-
- beforeEach(() => {
- data = mockProps();
- createComponent(data);
- });
-
- it('renders the line number component', () => {
- expect(wrapper.findComponent(LineNumber).exists()).toBe(true);
- });
-
- it('renders a span the provided text', () => {
- expect(findLine().text()).toBe(data.line.content[0].text);
- });
-
- it('renders the provided style as a class attribute', () => {
- expect(findLine().classes()).toContain(data.line.content[0].style);
- });
-
- describe('job urls as links', () => {
- it('renders an http link', () => {
- createComponent(mockProps({ text: httpUrl }));
-
- expect(findLink().text()).toBe(httpUrl);
- expect(findLink().attributes().href).toBe(httpUrl);
- });
-
- it('renders an https link', () => {
- createComponent(mockProps({ text: httpsUrl }));
-
- expect(findLink().text()).toBe(httpsUrl);
- expect(findLink().attributes().href).toBe(httpsUrl);
- });
-
- it('renders a link with rel nofollow and noopener', () => {
- createComponent(mockProps({ text: httpsUrl }));
-
- expect(findLink().attributes().rel).toBe('nofollow noopener noreferrer');
- });
-
- it('renders a link with corresponding styles', () => {
- createComponent(mockProps({ text: httpsUrl }));
-
- expect(findLink().classes()).toEqual(['gl-reset-color!', 'gl-text-decoration-underline']);
- });
-
- it('renders links with queries, surrounded by questions marks', () => {
- createComponent(mockProps({ text: `Did you see my url ${queryUrl}??` }));
-
- expect(findLine().text()).toBe('Did you see my url https://example.com?param=val??');
- expect(findLinkAttributeByIndex(0).href).toBe(queryUrl);
- });
-
- it('renders links with queries, surrounded by exclamation marks', () => {
- createComponent(mockProps({ text: `No! The ${queryUrl}!?` }));
-
- expect(findLine().text()).toBe('No! The https://example.com?param=val!?');
- expect(findLinkAttributeByIndex(0).href).toBe(queryUrl);
- });
-
- it('renders links that have brackets `[]` in their parameters', () => {
- const url = `${httpUrl}?label_name[]=frontend`;
-
- createComponent(mockProps({ text: url }));
-
- expect(findLine().text()).toBe(url);
- expect(findLinks().at(0).text()).toBe(url);
- expect(findLinks().at(0).attributes('href')).toBe(url);
- });
-
- it('renders multiple links surrounded by text', () => {
- createComponent(
- mockProps({ text: `Well, my HTTP url: ${httpUrl} and my HTTPS url: ${httpsUrl}` }),
- );
- expect(findLine().text()).toBe(
- 'Well, my HTTP url: http://example.com and my HTTPS url: https://example.com',
- );
-
- expect(findLinks()).toHaveLength(2);
-
- expect(findLinkAttributeByIndex(0).href).toBe(httpUrl);
- expect(findLinkAttributeByIndex(1).href).toBe(httpsUrl);
- });
-
- it('renders multiple links surrounded by text, with other symbols', () => {
- createComponent(
- mockProps({ text: `${httpUrl}, ${httpUrl}: ${httpsUrl}; ${httpsUrl}. ${httpsUrl}...` }),
- );
- expect(findLine().text()).toBe(
- 'http://example.com, http://example.com: https://example.com; https://example.com. https://example.com...',
- );
-
- expect(findLinks()).toHaveLength(5);
-
- expect(findLinkAttributeByIndex(0).href).toBe(httpUrl);
- expect(findLinkAttributeByIndex(1).href).toBe(httpUrl);
- expect(findLinkAttributeByIndex(2).href).toBe(httpsUrl);
- expect(findLinkAttributeByIndex(3).href).toBe(httpsUrl);
- expect(findLinkAttributeByIndex(4).href).toBe(httpsUrl);
- });
-
- it('renders multiple links surrounded by brackets', () => {
- createComponent(mockProps({ text: `(${httpUrl}) <${httpUrl}> {${httpsUrl}}` }));
- expect(findLine().text()).toBe(
- '(http://example.com) <http://example.com> {https://example.com}',
- );
-
- const links = findLinks();
-
- expect(links).toHaveLength(3);
-
- expect(links.at(0).text()).toBe(httpUrl);
- expect(links.at(0).attributes('href')).toBe(httpUrl);
-
- expect(links.at(1).text()).toBe(httpUrl);
- expect(links.at(1).attributes('href')).toBe(httpUrl);
-
- expect(links.at(2).text()).toBe(httpsUrl);
- expect(links.at(2).attributes('href')).toBe(httpsUrl);
- });
-
- it('renders text with symbols in it', () => {
- const text = 'apt-get update < /dev/null > /dev/null';
- createComponent(mockProps({ text }));
-
- expect(findLine().text()).toBe(text);
- });
-
- const jshref = 'javascript:doEvil();'; // eslint-disable-line no-script-url
-
- it.each`
- type | text
- ${'html link'} | ${'<a href="#">linked</a>'}
- ${'html script'} | ${'<script>doEvil();</script>'}
- ${'html strong'} | ${'<strong>highlighted</strong>'}
- ${'js'} | ${jshref}
- ${'file'} | ${'file:///a-file'}
- ${'ftp'} | ${'ftp://example.com/file'}
- ${'email'} | ${'email@example.com'}
- ${'no scheme'} | ${'example.com/page'}
- `('does not render a $type link', ({ text }) => {
- createComponent(mockProps({ text }));
- expect(findLink().exists()).toBe(false);
- });
- });
-
- describe('job log search', () => {
- const mockSearchResults = [
- {
- offset: 1533,
- content: [{ text: '$ echo "82.71"', style: 'term-fg-l-green term-bold' }],
- section: 'step-script',
- lineNumber: 20,
- },
- { offset: 1560, content: [{ text: '82.71' }], section: 'step-script', lineNumber: 21 },
- ];
-
- it('applies highlight class to search result elements', () => {
- createComponent({
- line: {
- offset: 1560,
- content: [{ text: '82.71' }],
- section: 'step-script',
- lineNumber: 21,
- },
- path: '/root/ci-project/-/jobs/1089',
- searchResults: mockSearchResults,
- });
-
- expect(wrapper.classes()).toContain('gl-bg-gray-700');
- });
-
- it('does not apply highlight class to search result elements', () => {
- createComponent({
- line: {
- offset: 1560,
- content: [{ text: 'docker' }],
- section: 'step-script',
- lineNumber: 29,
- },
- path: '/root/ci-project/-/jobs/1089',
- searchResults: mockSearchResults,
- });
-
- expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
- });
- });
-
- describe('job log hash highlighting', () => {
- describe('with hash', () => {
- beforeEach(() => {
- setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353#L77`);
- });
-
- it('applies highlight class to job log line', () => {
- createComponent({
- line: {
- offset: 24526,
- content: [{ text: 'job log content' }],
- section: 'custom-section',
- lineNumber: 76,
- },
- path: '/root/ci-project/-/jobs/6353',
- });
-
- expect(wrapper.classes()).toContain('gl-bg-gray-700');
- });
- });
-
- describe('without hash', () => {
- beforeEach(() => {
- setWindowLocation(`http://foo.com/root/ci-project/-/jobs/6353`);
- });
-
- it('does not apply highlight class to job log line', () => {
- createComponent({
- line: {
- offset: 24500,
- content: [{ text: 'line' }],
- section: 'custom-section',
- lineNumber: 10,
- },
- path: '/root/ci-project/-/jobs/6353',
- });
-
- expect(wrapper.classes()).not.toContain('gl-bg-gray-700');
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/log/log_spec.js b/spec/frontend/jobs/components/log/log_spec.js
deleted file mode 100644
index 9407b340950..00000000000
--- a/spec/frontend/jobs/components/log/log_spec.js
+++ /dev/null
@@ -1,135 +0,0 @@
-import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import waitForPromises from 'helpers/wait_for_promises';
-import { scrollToElement } from '~/lib/utils/common_utils';
-import Log from '~/jobs/components/log/log.vue';
-import LogLineHeader from '~/jobs/components/log/line_header.vue';
-import { logLinesParser } from '~/jobs/store/utils';
-import { jobLog } from './mock_data';
-
-jest.mock('~/lib/utils/common_utils', () => ({
- ...jest.requireActual('~/lib/utils/common_utils'),
- scrollToElement: jest.fn(),
-}));
-
-describe('Job Log', () => {
- let wrapper;
- let actions;
- let state;
- let store;
- let toggleCollapsibleLineMock;
-
- Vue.use(Vuex);
-
- const createComponent = () => {
- wrapper = mount(Log, {
- store,
- });
- };
-
- beforeEach(() => {
- toggleCollapsibleLineMock = jest.fn();
- actions = {
- toggleCollapsibleLine: toggleCollapsibleLineMock,
- };
-
- state = {
- jobLog: logLinesParser(jobLog),
- jobLogEndpoint: 'jobs/id',
- };
-
- store = new Vuex.Store({
- actions,
- state,
- });
- });
-
- const findCollapsibleLine = () => wrapper.findComponent(LogLineHeader);
-
- describe('line numbers', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders a line number for each open line', () => {
- expect(wrapper.find('#L1').text()).toBe('1');
- expect(wrapper.find('#L2').text()).toBe('2');
- expect(wrapper.find('#L3').text()).toBe('3');
- });
-
- it('links to the provided path and correct line number', () => {
- expect(wrapper.find('#L1').attributes('href')).toBe(`${state.jobLogEndpoint}#L1`);
- });
- });
-
- describe('collapsible sections', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders a clickable header section', () => {
- expect(findCollapsibleLine().attributes('role')).toBe('button');
- });
-
- it('renders an icon with the open state', () => {
- expect(findCollapsibleLine().find('[data-testid="chevron-lg-down-icon"]').exists()).toBe(
- true,
- );
- });
-
- describe('on click header section', () => {
- it('calls toggleCollapsibleLine', () => {
- findCollapsibleLine().trigger('click');
-
- expect(toggleCollapsibleLineMock).toHaveBeenCalled();
- });
- });
- });
-
- describe('anchor scrolling', () => {
- afterEach(() => {
- window.location.hash = '';
- });
-
- describe('when hash is not present', () => {
- it('does not scroll to line number', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(wrapper.find('#L6').exists()).toBe(false);
- expect(scrollToElement).not.toHaveBeenCalled();
- });
- });
-
- describe('when hash is present', () => {
- beforeEach(() => {
- window.location.hash = '#L6';
- });
-
- it('scrolls to line number', async () => {
- createComponent();
-
- state.jobLog = logLinesParser(jobLog, [], '#L6');
- await waitForPromises();
-
- expect(scrollToElement).toHaveBeenCalledTimes(1);
-
- state.jobLog = logLinesParser(jobLog, [], '#L7');
- await waitForPromises();
-
- expect(scrollToElement).toHaveBeenCalledTimes(1);
- });
-
- it('line number within collapsed section is visible', () => {
- state.jobLog = logLinesParser(jobLog, [], '#L6');
-
- createComponent();
-
- expect(wrapper.find('#L6').exists()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
deleted file mode 100644
index f2d249b6014..00000000000
--- a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
+++ /dev/null
@@ -1,240 +0,0 @@
-import { GlModal } from '@gitlab/ui';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import ActionsCell from '~/jobs/components/table/cells/actions_cell.vue';
-import eventHub from '~/jobs/components/table/event_hub';
-import JobPlayMutation from '~/jobs/components/table/graphql/mutations/job_play.mutation.graphql';
-import JobRetryMutation from '~/jobs/components/table/graphql/mutations/job_retry.mutation.graphql';
-import JobUnscheduleMutation from '~/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql';
-import JobCancelMutation from '~/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql';
-import {
- mockJobsNodes,
- mockJobsNodesAsGuest,
- playMutationResponse,
- retryMutationResponse,
- unscheduleMutationResponse,
- cancelMutationResponse,
-} from '../../../mock_data';
-
-jest.mock('~/lib/utils/url_utility');
-
-Vue.use(VueApollo);
-
-describe('Job actions cell', () => {
- let wrapper;
-
- const findMockJob = (jobName, nodes = mockJobsNodes) => {
- const job = nodes.find(({ name }) => name === jobName);
- expect(job).toBeDefined(); // ensure job is present
- return job;
- };
-
- const mockJob = findMockJob('build');
- const cancelableJob = findMockJob('cancelable');
- const playableJob = findMockJob('playable');
- const retryableJob = findMockJob('retryable');
- const failedJob = findMockJob('failed');
- const scheduledJob = findMockJob('scheduled');
- const jobWithArtifact = findMockJob('with_artifact');
- const cannotPlayJob = findMockJob('playable', mockJobsNodesAsGuest);
- const cannotRetryJob = findMockJob('retryable', mockJobsNodesAsGuest);
- const cannotPlayScheduledJob = findMockJob('scheduled', mockJobsNodesAsGuest);
-
- const findRetryButton = () => wrapper.findByTestId('retry');
- const findPlayButton = () => wrapper.findByTestId('play');
- const findCancelButton = () => wrapper.findByTestId('cancel-button');
- const findDownloadArtifactsButton = () => wrapper.findByTestId('download-artifacts');
- const findCountdownButton = () => wrapper.findByTestId('countdown');
- const findPlayScheduledJobButton = () => wrapper.findByTestId('play-scheduled');
- const findUnscheduleButton = () => wrapper.findByTestId('unschedule');
-
- const findModal = () => wrapper.findComponent(GlModal);
-
- const playMutationHandler = jest.fn().mockResolvedValue(playMutationResponse);
- const retryMutationHandler = jest.fn().mockResolvedValue(retryMutationResponse);
- const unscheduleMutationHandler = jest.fn().mockResolvedValue(unscheduleMutationResponse);
- const cancelMutationHandler = jest.fn().mockResolvedValue(cancelMutationResponse);
-
- const $toast = {
- show: jest.fn(),
- };
-
- const createMockApolloProvider = (requestHandlers) => {
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = (job, requestHandlers, props = {}) => {
- wrapper = shallowMountExtended(ActionsCell, {
- propsData: {
- job,
- ...props,
- },
- apolloProvider: createMockApolloProvider(requestHandlers),
- mocks: {
- $toast,
- },
- });
- };
-
- it('displays the artifacts download button with correct link', () => {
- createComponent(jobWithArtifact);
-
- expect(findDownloadArtifactsButton().attributes('href')).toBe(
- jobWithArtifact.artifacts.nodes[0].downloadPath,
- );
- });
-
- it('does not display an artifacts download button', () => {
- createComponent(mockJob);
-
- expect(findDownloadArtifactsButton().exists()).toBe(false);
- });
-
- it.each`
- button | action | jobType
- ${findPlayButton} | ${'play'} | ${cannotPlayJob}
- ${findRetryButton} | ${'retry'} | ${cannotRetryJob}
- ${findPlayScheduledJobButton} | ${'play scheduled'} | ${cannotPlayScheduledJob}
- `('does not display the $action button if user cannot update build', ({ button, jobType }) => {
- createComponent(jobType);
-
- expect(button().exists()).toBe(false);
- });
-
- it.each`
- button | action | jobType
- ${findPlayButton} | ${'play'} | ${playableJob}
- ${findRetryButton} | ${'retry'} | ${retryableJob}
- ${findDownloadArtifactsButton} | ${'download artifacts'} | ${jobWithArtifact}
- ${findCancelButton} | ${'cancel'} | ${cancelableJob}
- `('displays the $action button', ({ button, jobType }) => {
- createComponent(jobType);
-
- expect(button().exists()).toBe(true);
- });
-
- it.each`
- button | action | jobType | mutationFile | handler | jobId
- ${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${playableJob.id}
- ${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${retryableJob.id}
- ${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler} | ${cancelableJob.id}
- `('performs the $action mutation', ({ button, jobType, mutationFile, handler, jobId }) => {
- createComponent(jobType, [[mutationFile, handler]]);
-
- button().vm.$emit('click');
-
- expect(handler).toHaveBeenCalledWith({ id: jobId });
- });
-
- it.each`
- button | action | jobType | mutationFile | handler
- ${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob} | ${JobUnscheduleMutation} | ${unscheduleMutationHandler}
- ${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler}
- `(
- 'the mutation action $action emits the jobActionPerformed event',
- async ({ button, jobType, mutationFile, handler }) => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
-
- createComponent(jobType, [[mutationFile, handler]]);
-
- button().vm.$emit('click');
-
- await waitForPromises();
-
- expect(eventHub.$emit).toHaveBeenCalledWith('jobActionPerformed');
- expect(redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
- },
- );
-
- it.each`
- button | action | jobType | mutationFile | handler | redirectLink
- ${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${'/root/project/-/jobs/1986'}
- ${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${'/root/project/-/jobs/1985'}
- `(
- 'the mutation action $action redirects to the job',
- async ({ button, jobType, mutationFile, handler, redirectLink }) => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
-
- createComponent(jobType, [[mutationFile, handler]]);
-
- button().vm.$emit('click');
-
- await waitForPromises();
-
- expect(redirectTo).toHaveBeenCalledWith(redirectLink); // eslint-disable-line import/no-deprecated
- expect(eventHub.$emit).not.toHaveBeenCalled();
- },
- );
-
- it.each`
- button | action | jobType
- ${findPlayButton} | ${'play'} | ${playableJob}
- ${findRetryButton} | ${'retry'} | ${retryableJob}
- ${findCancelButton} | ${'cancel'} | ${cancelableJob}
- ${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob}
- `('disables the $action button after first request', async ({ button, jobType }) => {
- createComponent(jobType);
-
- expect(button().props('disabled')).toBe(false);
-
- button().vm.$emit('click');
-
- await waitForPromises();
-
- expect(button().props('disabled')).toBe(true);
- });
-
- describe('Retry button title', () => {
- it('displays retry title when job has failed and is retryable', () => {
- createComponent(failedJob);
-
- expect(findRetryButton().attributes('title')).toBe('Retry');
- });
-
- it('displays run again title when job has passed and is retryable', () => {
- createComponent(retryableJob);
-
- expect(findRetryButton().attributes('title')).toBe('Run again');
- });
- });
-
- describe('Scheduled Jobs', () => {
- const today = () => new Date('2021-08-31');
-
- beforeEach(() => {
- jest.spyOn(Date, 'now').mockImplementation(today);
- });
-
- it('displays the countdown, play and unschedule buttons', () => {
- createComponent(scheduledJob);
-
- expect(findCountdownButton().exists()).toBe(true);
- expect(findPlayScheduledJobButton().exists()).toBe(true);
- expect(findUnscheduleButton().exists()).toBe(true);
- });
-
- it('unschedules a job', () => {
- createComponent(scheduledJob, [[JobUnscheduleMutation, unscheduleMutationHandler]]);
-
- findUnscheduleButton().vm.$emit('click');
-
- expect(unscheduleMutationHandler).toHaveBeenCalledWith({
- id: scheduledJob.id,
- });
- });
-
- it('shows the play job confirmation modal', async () => {
- createComponent(scheduledJob);
-
- findPlayScheduledJobButton().vm.$emit('click');
-
- await nextTick();
-
- expect(findModal().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/cells/duration_cell_spec.js b/spec/frontend/jobs/components/table/cells/duration_cell_spec.js
deleted file mode 100644
index d015edb0e91..00000000000
--- a/spec/frontend/jobs/components/table/cells/duration_cell_spec.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import DurationCell from '~/jobs/components/table/cells/duration_cell.vue';
-
-describe('Duration Cell', () => {
- let wrapper;
-
- const findJobDuration = () => wrapper.findByTestId('job-duration');
- const findJobFinishedTime = () => wrapper.findByTestId('job-finished-time');
- const findDurationIcon = () => wrapper.findByTestId('duration-icon');
- const findFinishedTimeIcon = () => wrapper.findByTestId('finished-time-icon');
-
- const createComponent = (props) => {
- wrapper = extendedWrapper(
- shallowMount(DurationCell, {
- propsData: {
- job: {
- ...props,
- },
- },
- }),
- );
- };
-
- it('does not display duration or finished time when no properties are present', () => {
- createComponent();
-
- expect(findJobDuration().exists()).toBe(false);
- expect(findJobFinishedTime().exists()).toBe(false);
- });
-
- it('displays duration and finished time when both properties are present', () => {
- const props = {
- duration: 7,
- finishedAt: '2021-04-26T13:37:52Z',
- };
-
- createComponent(props);
-
- expect(findJobDuration().exists()).toBe(true);
- expect(findJobFinishedTime().exists()).toBe(true);
- });
-
- it('displays only the duration of the job when the duration property is present', () => {
- const props = {
- duration: 7,
- };
-
- createComponent(props);
-
- expect(findJobDuration().exists()).toBe(true);
- expect(findJobFinishedTime().exists()).toBe(false);
- });
-
- it('displays only the finished time of the job when the finshedAt property is present', () => {
- const props = {
- finishedAt: '2021-04-26T13:37:52Z',
- };
-
- createComponent(props);
-
- expect(findJobFinishedTime().exists()).toBe(true);
- expect(findJobDuration().exists()).toBe(false);
- });
-
- it('displays icons for finished time and duration', () => {
- const props = {
- duration: 7,
- finishedAt: '2021-04-26T13:37:52Z',
- };
-
- createComponent(props);
-
- expect(findFinishedTimeIcon().props('name')).toBe('calendar');
- expect(findDurationIcon().props('name')).toBe('timer');
- });
-});
diff --git a/spec/frontend/jobs/components/table/cells/job_cell_spec.js b/spec/frontend/jobs/components/table/cells/job_cell_spec.js
deleted file mode 100644
index 73e37eed5f1..00000000000
--- a/spec/frontend/jobs/components/table/cells/job_cell_spec.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import JobCell from '~/jobs/components/table/cells/job_cell.vue';
-import { mockJobsNodes, mockJobsNodesAsGuest } from '../../../mock_data';
-
-describe('Job Cell', () => {
- let wrapper;
-
- const findMockJob = (jobName, nodes = mockJobsNodes) => {
- const job = nodes.find(({ name }) => name === jobName);
- expect(job).toBeDefined(); // ensure job is present
- return job;
- };
-
- const mockJob = findMockJob('build');
- const jobCreatedByTag = findMockJob('created_by_tag');
- const pendingJob = findMockJob('pending');
- const jobAsGuest = findMockJob('build', mockJobsNodesAsGuest);
-
- const findJobIdLink = () => wrapper.findByTestId('job-id-link');
- const findJobIdNoLink = () => wrapper.findByTestId('job-id-limited-access');
- const findJobRef = () => wrapper.findByTestId('job-ref');
- const findJobSha = () => wrapper.findByTestId('job-sha');
- const findLabelIcon = () => wrapper.findByTestId('label-icon');
- const findForkIcon = () => wrapper.findByTestId('fork-icon');
- const findStuckIcon = () => wrapper.findByTestId('stuck-icon');
- const findAllTagBadges = () => wrapper.findAllByTestId('job-tag-badge');
-
- const findBadgeById = (id) => wrapper.findByTestId(id);
-
- const createComponent = (job = mockJob) => {
- wrapper = extendedWrapper(
- shallowMount(JobCell, {
- propsData: {
- job,
- },
- }),
- );
- };
-
- describe('Job Id', () => {
- it('displays the job id and links to the job', () => {
- createComponent();
-
- const expectedJobId = `#${getIdFromGraphQLId(mockJob.id)}`;
-
- expect(findJobIdLink().text()).toBe(expectedJobId);
- expect(findJobIdLink().attributes('href')).toBe(mockJob.detailedStatus.detailsPath);
- expect(findJobIdNoLink().exists()).toBe(false);
- });
-
- it('display the job id with no link', () => {
- createComponent(jobAsGuest);
-
- const expectedJobId = `#${getIdFromGraphQLId(jobAsGuest.id)}`;
-
- expect(findJobIdNoLink().text()).toBe(expectedJobId);
- expect(findJobIdNoLink().exists()).toBe(true);
- expect(findJobIdLink().exists()).toBe(false);
- });
- });
-
- describe('Ref of the job', () => {
- it('displays the ref name and links to the ref', () => {
- createComponent();
-
- expect(findJobRef().text()).toBe(mockJob.refName);
- expect(findJobRef().attributes('href')).toBe(mockJob.refPath);
- });
-
- it('displays fork icon when job is not created by tag', () => {
- createComponent();
-
- expect(findForkIcon().exists()).toBe(true);
- expect(findLabelIcon().exists()).toBe(false);
- });
-
- it('displays label icon when job is created by a tag', () => {
- createComponent(jobCreatedByTag);
-
- expect(findLabelIcon().exists()).toBe(true);
- expect(findForkIcon().exists()).toBe(false);
- });
- });
-
- describe('Commit of the job', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('displays the sha and links to the commit', () => {
- expect(findJobSha().text()).toBe(mockJob.shortSha);
- expect(findJobSha().attributes('href')).toBe(mockJob.commitPath);
- });
- });
-
- describe('Job badges', () => {
- it('displays tags of the job', () => {
- const mockJobWithTags = {
- tags: ['tag-1', 'tag-2', 'tag-3'],
- };
-
- createComponent(mockJobWithTags);
-
- expect(findAllTagBadges()).toHaveLength(mockJobWithTags.tags.length);
- });
-
- it.each`
- testId | text
- ${'manual-job-badge'} | ${'manual'}
- ${'triggered-job-badge'} | ${'triggered'}
- ${'fail-job-badge'} | ${'allowed to fail'}
- ${'delayed-job-badge'} | ${'delayed'}
- `('displays the static $text badge', ({ testId, text }) => {
- createComponent({
- manualJob: true,
- triggered: true,
- allowFailure: true,
- scheduledAt: '2021-03-09T14:58:50+00:00',
- });
-
- expect(findBadgeById(testId).exists()).toBe(true);
- expect(findBadgeById(testId).text()).toBe(text);
- });
- });
-
- describe('Job icons', () => {
- it('stuck icon is not shown if job is not stuck', () => {
- createComponent();
-
- expect(findStuckIcon().exists()).toBe(false);
- });
-
- it('stuck icon is shown if job is pending', () => {
- createComponent(pendingJob);
-
- expect(findStuckIcon().exists()).toBe(true);
- expect(findStuckIcon().attributes('name')).toBe('warning');
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js b/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js
deleted file mode 100644
index 3d424b20964..00000000000
--- a/spec/frontend/jobs/components/table/cells/pipeline_cell_spec.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import { GlAvatar } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import PipelineCell from '~/jobs/components/table/cells/pipeline_cell.vue';
-
-const mockJobWithoutUser = {
- id: 'gid://gitlab/Ci::Build/2264',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/460',
- path: '/root/ci-project/-/pipelines/460',
- },
-};
-
-const mockJobWithUser = {
- id: 'gid://gitlab/Ci::Build/2264',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/460',
- path: '/root/ci-project/-/pipelines/460',
- user: {
- avatarUrl:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- webPath: '/root',
- },
- },
-};
-
-describe('Pipeline Cell', () => {
- let wrapper;
-
- const findPipelineId = () => wrapper.findByTestId('pipeline-id');
- const findPipelineUserLink = () => wrapper.findByTestId('pipeline-user-link');
- const findUserAvatar = () => wrapper.findComponent(GlAvatar);
-
- const createComponent = (props = mockJobWithUser) => {
- wrapper = extendedWrapper(
- shallowMount(PipelineCell, {
- propsData: {
- job: props,
- },
- }),
- );
- };
-
- describe('Pipeline Id', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('displays the pipeline id and links to the pipeline', () => {
- const expectedPipelineId = `#${getIdFromGraphQLId(mockJobWithUser.pipeline.id)}`;
-
- expect(findPipelineId().text()).toBe(expectedPipelineId);
- expect(findPipelineId().attributes('href')).toBe(mockJobWithUser.pipeline.path);
- });
- });
-
- describe('Pipeline created by', () => {
- const apiWrapperText = 'API';
-
- it('shows and links to the pipeline user', () => {
- createComponent();
-
- expect(findPipelineUserLink().exists()).toBe(true);
- expect(findPipelineUserLink().attributes('href')).toBe(mockJobWithUser.pipeline.user.webPath);
- expect(findUserAvatar().attributes('src')).toBe(mockJobWithUser.pipeline.user.avatarUrl);
- expect(wrapper.text()).not.toContain(apiWrapperText);
- });
-
- it('shows pipeline was created by the API', () => {
- createComponent(mockJobWithoutUser);
-
- expect(findPipelineUserLink().exists()).toBe(false);
- expect(findUserAvatar().exists()).toBe(false);
- expect(wrapper.text()).toContain(apiWrapperText);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/graphql/cache_config_spec.js b/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
deleted file mode 100644
index e3b1ca1cce3..00000000000
--- a/spec/frontend/jobs/components/table/graphql/cache_config_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import cacheConfig from '~/jobs/components/table/graphql/cache_config';
-import {
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCache,
- CIJobConnectionIncomingCacheRunningStatus,
-} from '../../../mock_data';
-
-const firstLoadArgs = { first: 3, statuses: 'PENDING' };
-const runningArgs = { first: 3, statuses: 'RUNNING' };
-
-describe('jobs/components/table/graphql/cache_config', () => {
- describe('when fetching data with the same statuses', () => {
- it('should contain cache nodes and a status when merging caches on first load', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
- args: firstLoadArgs,
- });
-
- expect(res.nodes).toHaveLength(CIJobConnectionIncomingCache.nodes.length);
- expect(res.statuses).toBe('PENDING');
- });
-
- it('should add to existing caches when merging caches after first load', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCache,
- {
- args: firstLoadArgs,
- },
- );
-
- expect(res.nodes).toHaveLength(
- CIJobConnectionIncomingCache.nodes.length + CIJobConnectionExistingCache.nodes.length,
- );
- });
-
- it('should not add to existing cache if the incoming elements are the same', () => {
- // simulate that this is the last page
- const finalExistingCache = {
- ...CIJobConnectionExistingCache,
- pageInfo: {
- hasNextPage: false,
- },
- };
-
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- finalExistingCache,
- {
- args: firstLoadArgs,
- },
- );
-
- expect(res.nodes).toHaveLength(CIJobConnectionExistingCache.nodes.length);
- });
-
- it('should contain the pageInfo key as part of the result', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
- args: firstLoadArgs,
- });
-
- expect(res.pageInfo).toEqual(
- expect.objectContaining({
- __typename: 'PageInfo',
- endCursor: 'eyJpZCI6IjIwNTEifQ',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'eyJpZCI6IjIxNzMifQ',
- }),
- );
- });
- });
-
- describe('when fetching data with different statuses', () => {
- it('should reset cache when a cache already exists', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCacheRunningStatus,
- {
- args: runningArgs,
- },
- );
-
- expect(res.nodes).not.toEqual(CIJobConnectionExistingCache.nodes);
- expect(res.nodes).toHaveLength(CIJobConnectionIncomingCacheRunningStatus.nodes.length);
- });
- });
-
- describe('when incoming data has no nodes', () => {
- it('should return existing cache', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- { __typename: 'CiJobConnection', count: 500 },
- {
- args: { statuses: 'SUCCESS' },
- },
- );
-
- const expectedResponse = {
- ...CIJobConnectionExistingCache,
- statuses: 'SUCCESS',
- };
-
- expect(res).toEqual(expectedResponse);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/job_table_app_spec.js b/spec/frontend/jobs/components/table/job_table_app_spec.js
deleted file mode 100644
index 032b83ca22b..00000000000
--- a/spec/frontend/jobs/components/table/job_table_app_spec.js
+++ /dev/null
@@ -1,338 +0,0 @@
-import { GlAlert, GlEmptyState, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import { s__ } from '~/locale';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { TEST_HOST } from 'spec/test_constants';
-import { createAlert } from '~/alert';
-import getJobsQuery from '~/jobs/components/table/graphql/queries/get_jobs.query.graphql';
-import getJobsCountQuery from '~/jobs/components/table/graphql/queries/get_jobs_count.query.graphql';
-import JobsTable from '~/jobs/components/table/jobs_table.vue';
-import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue';
-import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
-import JobsFilteredSearch from '~/jobs/components/filtered_search/jobs_filtered_search.vue';
-import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
-import * as urlUtils from '~/lib/utils/url_utility';
-import {
- mockJobsResponsePaginated,
- mockJobsResponseEmpty,
- mockFailedSearchToken,
- mockJobsCountResponse,
-} from '../../mock_data';
-
-const projectPath = 'gitlab-org/gitlab';
-Vue.use(VueApollo);
-
-jest.mock('~/alert');
-
-describe('Job table app', () => {
- let wrapper;
-
- const successHandler = jest.fn().mockResolvedValue(mockJobsResponsePaginated);
- const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
- const emptyHandler = jest.fn().mockResolvedValue(mockJobsResponseEmpty);
-
- const countSuccessHandler = jest.fn().mockResolvedValue(mockJobsCountResponse);
-
- const findSkeletonLoader = () => wrapper.findComponent(JobsSkeletonLoader);
- const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
- const findTable = () => wrapper.findComponent(JobsTable);
- const findTabs = () => wrapper.findComponent(JobsTableTabs);
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findEmptyState = () => wrapper.findComponent(GlEmptyState);
- const findFilteredSearch = () => wrapper.findComponent(JobsFilteredSearch);
-
- const triggerInfiniteScroll = () =>
- wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
-
- const createMockApolloProvider = (handler, countHandler) => {
- const requestHandlers = [
- [getJobsQuery, handler],
- [getJobsCountQuery, countHandler],
- ];
-
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = ({
- handler = successHandler,
- countHandler = countSuccessHandler,
- mountFn = shallowMount,
- } = {}) => {
- wrapper = mountFn(JobsTableApp, {
- provide: {
- fullPath: projectPath,
- },
- apolloProvider: createMockApolloProvider(handler, countHandler),
- });
- };
-
- describe('loading state', () => {
- it('should display skeleton loader when loading', () => {
- createComponent();
-
- expect(findSkeletonLoader().exists()).toBe(true);
- expect(findTable().exists()).toBe(false);
- expect(findLoadingSpinner().exists()).toBe(false);
- });
-
- it('when switching tabs only the skeleton loader should show', () => {
- createComponent();
-
- findTabs().vm.$emit('fetchJobsByStatus', null);
-
- expect(findSkeletonLoader().exists()).toBe(true);
- expect(findLoadingSpinner().exists()).toBe(false);
- });
- });
-
- describe('loaded state', () => {
- beforeEach(async () => {
- createComponent();
-
- await waitForPromises();
- });
-
- it('should display the jobs table with data', () => {
- expect(findTable().exists()).toBe(true);
- expect(findSkeletonLoader().exists()).toBe(false);
- expect(findLoadingSpinner().exists()).toBe(false);
- });
-
- it('should refetch jobs query on fetchJobsByStatus event', async () => {
- expect(successHandler).toHaveBeenCalledTimes(1);
-
- await findTabs().vm.$emit('fetchJobsByStatus');
-
- expect(successHandler).toHaveBeenCalledTimes(2);
- });
-
- it('avoids refetch jobs query when scope has not changed', async () => {
- expect(successHandler).toHaveBeenCalledTimes(1);
-
- await findTabs().vm.$emit('fetchJobsByStatus', null);
-
- expect(successHandler).toHaveBeenCalledTimes(1);
- });
-
- it('should refetch jobs count query when the amount jobs and count do not match', async () => {
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
-
- // after applying filter a new count is fetched
- findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(countSuccessHandler).toHaveBeenCalledTimes(2);
-
- // tab is switched to `finished`, no count
- await findTabs().vm.$emit('fetchJobsByStatus', ['FAILED', 'SUCCESS', 'CANCELED']);
-
- // tab is switched back to `all`, the old filter count has to be overwritten with new count
- await findTabs().vm.$emit('fetchJobsByStatus', null);
-
- expect(countSuccessHandler).toHaveBeenCalledTimes(3);
- });
-
- describe('when infinite scrolling is triggered', () => {
- it('does not display a skeleton loader', () => {
- triggerInfiniteScroll();
-
- expect(findSkeletonLoader().exists()).toBe(false);
- });
-
- it('handles infinite scrolling by calling fetch more', async () => {
- triggerInfiniteScroll();
-
- await nextTick();
-
- const pageSize = 30;
-
- expect(findLoadingSpinner().exists()).toBe(true);
-
- await waitForPromises();
-
- expect(findLoadingSpinner().exists()).toBe(false);
-
- expect(successHandler).toHaveBeenLastCalledWith({
- first: pageSize,
- fullPath: projectPath,
- after: mockJobsResponsePaginated.data.project.jobs.pageInfo.endCursor,
- });
- });
- });
- });
-
- describe('error state', () => {
- it('should show an alert if there is an error fetching the jobs data', async () => {
- createComponent({ handler: failedHandler });
-
- await waitForPromises();
-
- expect(findAlert().text()).toBe('There was an error fetching the jobs for your project.');
- expect(findTable().exists()).toBe(false);
- });
-
- it('should show an alert if there is an error fetching the jobs count data', async () => {
- createComponent({ handler: successHandler, countHandler: failedHandler });
-
- await waitForPromises();
-
- expect(findAlert().text()).toBe(
- 'There was an error fetching the number of jobs for your project.',
- );
- });
-
- it('jobs table should still load if count query fails', async () => {
- createComponent({ handler: successHandler, countHandler: failedHandler });
-
- await waitForPromises();
-
- expect(findTable().exists()).toBe(true);
- });
-
- it('jobs count should be zero if count query fails', async () => {
- createComponent({ handler: successHandler, countHandler: failedHandler });
-
- await waitForPromises();
-
- expect(findTabs().props('allJobsCount')).toBe(0);
- });
- });
-
- describe('empty state', () => {
- it('should display empty state if there are no jobs and tab scope is null', async () => {
- createComponent({ handler: emptyHandler, mountFn: mount });
-
- await waitForPromises();
-
- expect(findEmptyState().exists()).toBe(true);
- expect(findTable().exists()).toBe(false);
- });
-
- it('should not display empty state if there are jobs and tab scope is not null', async () => {
- createComponent({ handler: successHandler, mountFn: mount });
-
- await waitForPromises();
-
- expect(findEmptyState().exists()).toBe(false);
- expect(findTable().exists()).toBe(true);
- });
- });
-
- describe('filtered search', () => {
- it('should display filtered search', () => {
- createComponent();
-
- expect(findFilteredSearch().exists()).toBe(true);
- });
-
- // this test should be updated once BE supports tab and filtered search filtering
- // https://gitlab.com/gitlab-org/gitlab/-/issues/356210
- it.each`
- scope | shouldDisplay
- ${null} | ${true}
- ${['FAILED', 'SUCCESS', 'CANCELED']} | ${false}
- `(
- 'with tab scope $scope the filtered search displays $shouldDisplay',
- async ({ scope, shouldDisplay }) => {
- createComponent();
-
- await waitForPromises();
-
- await findTabs().vm.$emit('fetchJobsByStatus', scope);
-
- expect(findFilteredSearch().exists()).toBe(shouldDisplay);
- },
- );
-
- it('refetches jobs query when filtering', async () => {
- createComponent();
-
- expect(successHandler).toHaveBeenCalledTimes(1);
-
- await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(successHandler).toHaveBeenCalledTimes(2);
- });
-
- it('refetches jobs count query when filtering', async () => {
- createComponent();
-
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
-
- await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(countSuccessHandler).toHaveBeenCalledTimes(2);
- });
-
- it('shows raw text warning when user inputs raw text', async () => {
- const expectedWarning = {
- message: s__(
- 'Jobs|Raw text search is not currently supported for the jobs filtered search feature. Please use the available search tokens.',
- ),
- type: 'warning',
- };
-
- createComponent();
-
- expect(successHandler).toHaveBeenCalledTimes(1);
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
-
- await findFilteredSearch().vm.$emit('filterJobsBySearch', ['raw text']);
-
- expect(createAlert).toHaveBeenCalledWith(expectedWarning);
- expect(successHandler).toHaveBeenCalledTimes(1);
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
- });
-
- it('updates URL query string when filtering jobs by status', async () => {
- createComponent();
-
- jest.spyOn(urlUtils, 'updateHistory');
-
- await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(urlUtils.updateHistory).toHaveBeenCalledWith({
- url: `${TEST_HOST}/?statuses=FAILED`,
- });
- });
-
- it('resets query param after clearing tokens', () => {
- createComponent();
-
- jest.spyOn(urlUtils, 'updateHistory');
-
- findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
-
- expect(successHandler).toHaveBeenCalledWith({
- first: 30,
- fullPath: 'gitlab-org/gitlab',
- statuses: 'FAILED',
- });
- expect(countSuccessHandler).toHaveBeenCalledWith({
- fullPath: 'gitlab-org/gitlab',
- statuses: 'FAILED',
- });
- expect(urlUtils.updateHistory).toHaveBeenCalledWith({
- url: `${TEST_HOST}/?statuses=FAILED`,
- });
-
- findFilteredSearch().vm.$emit('filterJobsBySearch', []);
-
- expect(urlUtils.updateHistory).toHaveBeenCalledWith({
- url: `${TEST_HOST}/`,
- });
-
- expect(successHandler).toHaveBeenCalledWith({
- first: 30,
- fullPath: 'gitlab-org/gitlab',
- statuses: null,
- });
- expect(countSuccessHandler).toHaveBeenCalledWith({
- fullPath: 'gitlab-org/gitlab',
- statuses: null,
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/jobs_table_empty_state_spec.js b/spec/frontend/jobs/components/table/jobs_table_empty_state_spec.js
deleted file mode 100644
index 05b066a9edc..00000000000
--- a/spec/frontend/jobs/components/table/jobs_table_empty_state_spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { GlEmptyState } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import JobsTableEmptyState from '~/jobs/components/table/jobs_table_empty_state.vue';
-
-describe('Jobs table empty state', () => {
- let wrapper;
-
- const pipelineEditorPath = '/root/project/-/ci/editor';
- const emptyStateSvgPath = 'assets/jobs-empty-state.svg';
-
- const findEmptyState = () => wrapper.findComponent(GlEmptyState);
-
- const createComponent = () => {
- wrapper = shallowMount(JobsTableEmptyState, {
- provide: {
- pipelineEditorPath,
- emptyStateSvgPath,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('displays empty state', () => {
- expect(findEmptyState().exists()).toBe(true);
- });
-
- it('links to the pipeline editor', () => {
- expect(findEmptyState().props('primaryButtonLink')).toBe(pipelineEditorPath);
- });
-
- it('shows an empty state image', () => {
- expect(findEmptyState().props('svgPath')).toBe(emptyStateSvgPath);
- });
-});
diff --git a/spec/frontend/jobs/components/table/jobs_table_spec.js b/spec/frontend/jobs/components/table/jobs_table_spec.js
deleted file mode 100644
index 654b6d1c130..00000000000
--- a/spec/frontend/jobs/components/table/jobs_table_spec.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import { GlTable } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import JobsTable from '~/jobs/components/table/jobs_table.vue';
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import { DEFAULT_FIELDS_ADMIN } from '~/pages/admin/jobs/components/constants';
-import ProjectCell from '~/pages/admin/jobs/components/table/cell/project_cell.vue';
-import RunnerCell from '~/pages/admin/jobs/components/table/cells/runner_cell.vue';
-import { mockJobsNodes, mockAllJobsNodes } from '../../mock_data';
-
-describe('Jobs Table', () => {
- let wrapper;
-
- const findTable = () => wrapper.findComponent(GlTable);
- const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
- const findTableRows = () => wrapper.findAllByTestId('jobs-table-row');
- const findJobStage = () => wrapper.findByTestId('job-stage-name');
- const findJobName = () => wrapper.findByTestId('job-name');
- const findJobProject = () => wrapper.findComponent(ProjectCell);
- const findJobRunner = () => wrapper.findComponent(RunnerCell);
- const findAllCoverageJobs = () => wrapper.findAllByTestId('job-coverage');
-
- const createComponent = (props = {}) => {
- wrapper = extendedWrapper(
- mount(JobsTable, {
- propsData: {
- ...props,
- },
- }),
- );
- };
-
- describe('jobs table', () => {
- beforeEach(() => {
- createComponent({ jobs: mockJobsNodes });
- });
-
- it('displays the jobs table', () => {
- expect(findTable().exists()).toBe(true);
- });
-
- it('displays correct number of job rows', () => {
- expect(findTableRows()).toHaveLength(mockJobsNodes.length);
- });
-
- it('displays job status', () => {
- expect(findCiBadgeLink().exists()).toBe(true);
- });
-
- it('displays the job stage and name', () => {
- const [firstJob] = mockJobsNodes;
-
- expect(findJobStage().text()).toBe(firstJob.stage.name);
- expect(findJobName().text()).toBe(firstJob.name);
- });
-
- it('displays the coverage for only jobs that have coverage', () => {
- const jobsThatHaveCoverage = mockJobsNodes.filter((job) => job.coverage !== null);
-
- jobsThatHaveCoverage.forEach((job, index) => {
- expect(findAllCoverageJobs().at(index).text()).toBe(`${job.coverage}%`);
- });
- expect(findAllCoverageJobs()).toHaveLength(jobsThatHaveCoverage.length);
- });
- });
-
- describe('regular user', () => {
- beforeEach(() => {
- createComponent({ jobs: mockJobsNodes });
- });
-
- it('hides the job runner', () => {
- expect(findJobRunner().exists()).toBe(false);
- });
-
- it('hides the job project link', () => {
- expect(findJobProject().exists()).toBe(false);
- });
- });
-
- describe('admin mode', () => {
- beforeEach(() => {
- createComponent({ jobs: mockAllJobsNodes, tableFields: DEFAULT_FIELDS_ADMIN, admin: true });
- });
-
- it('displays the runner cell', () => {
- expect(findJobRunner().exists()).toBe(true);
- });
-
- it('displays the project cell', () => {
- expect(findJobProject().exists()).toBe(true);
- });
-
- it('displays correct number of job rows', () => {
- expect(findTableRows()).toHaveLength(mockAllJobsNodes.length);
- });
- });
-});
diff --git a/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js b/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js
deleted file mode 100644
index d20a732508a..00000000000
--- a/spec/frontend/jobs/components/table/jobs_table_tabs_spec.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { GlTab } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import { trimText } from 'helpers/text_helper';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
-import CancelJobs from '~/pages/admin/jobs/components/cancel_jobs.vue';
-
-describe('Jobs Table Tabs', () => {
- let wrapper;
-
- const defaultProps = {
- allJobsCount: 286,
- loading: false,
- };
-
- const adminProps = {
- ...defaultProps,
- showCancelAllJobsButton: true,
- };
-
- const statuses = {
- success: 'SUCCESS',
- failed: 'FAILED',
- canceled: 'CANCELED',
- };
-
- const findAllTab = () => wrapper.findByTestId('jobs-all-tab');
- const findFinishedTab = () => wrapper.findByTestId('jobs-finished-tab');
- const findCancelJobsButton = () => wrapper.findAllComponents(CancelJobs);
-
- const triggerTabChange = (index) => wrapper.findAllComponents(GlTab).at(index).vm.$emit('click');
-
- const createComponent = (props = defaultProps) => {
- wrapper = extendedWrapper(
- mount(JobsTableTabs, {
- provide: {
- jobStatuses: {
- ...statuses,
- },
- },
- propsData: {
- ...props,
- },
- }),
- );
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('displays All tab with count', () => {
- expect(trimText(findAllTab().text())).toBe(`All ${defaultProps.allJobsCount}`);
- });
-
- it('displays Finished tab with no count', () => {
- expect(findFinishedTab().text()).toBe('Finished');
- });
-
- it.each`
- tabIndex | expectedScope
- ${0} | ${null}
- ${1} | ${[statuses.success, statuses.failed, statuses.canceled]}
- `('emits fetchJobsByStatus with $expectedScope on tab change', ({ tabIndex, expectedScope }) => {
- triggerTabChange(tabIndex);
-
- expect(wrapper.emitted()).toEqual({ fetchJobsByStatus: [[expectedScope]] });
- });
-
- it('does not displays cancel all jobs button', () => {
- expect(findCancelJobsButton().exists()).toBe(false);
- });
-
- describe('admin mode', () => {
- it('displays cancel all jobs button', () => {
- createComponent(adminProps);
-
- expect(findCancelJobsButton().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js b/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js
deleted file mode 100644
index 098a63719fe..00000000000
--- a/spec/frontend/jobs/mixins/delayed_job_mixin_spec.js
+++ /dev/null
@@ -1,119 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import delayedJobFixture from 'test_fixtures/jobs/delayed.json';
-import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
-
-describe('DelayedJobMixin', () => {
- let wrapper;
- const dummyComponent = {
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- mixins: [delayedJobMixin],
- template: '<div>{{remainingTime}}</div>',
- };
-
- describe('if job is empty object', () => {
- beforeEach(() => {
- wrapper = shallowMount(dummyComponent, {
- propsData: {
- job: {},
- },
- });
- });
-
- it('sets remaining time to 00:00:00', () => {
- expect(wrapper.text()).toBe('00:00:00');
- });
-
- it('does not update remaining time after mounting', async () => {
- await nextTick();
-
- expect(wrapper.text()).toBe('00:00:00');
- });
- });
-
- describe('in REST component', () => {
- describe('if job is delayed job', () => {
- let remainingTimeInMilliseconds = 42000;
-
- beforeEach(async () => {
- jest
- .spyOn(Date, 'now')
- .mockImplementation(
- () => new Date(delayedJobFixture.scheduled_at).getTime() - remainingTimeInMilliseconds,
- );
-
- wrapper = shallowMount(dummyComponent, {
- propsData: {
- job: delayedJobFixture,
- },
- });
-
- await nextTick();
- });
-
- it('sets remaining time', () => {
- expect(wrapper.text()).toBe('00:00:42');
- });
-
- it('updates remaining time', async () => {
- remainingTimeInMilliseconds = 41000;
- jest.advanceTimersByTime(1000);
-
- await nextTick();
- expect(wrapper.text()).toBe('00:00:41');
- });
- });
- });
-
- describe('in GraphQL component', () => {
- const mockGraphQlJob = {
- name: 'build_b',
- scheduledAt: new Date(delayedJobFixture.scheduled_at),
- status: {
- icon: 'status_success',
- tooltip: 'passed',
- hasDetails: true,
- detailsPath: '/root/abcd-dag/-/jobs/1515',
- group: 'success',
- action: null,
- },
- };
-
- describe('if job is delayed job', () => {
- let remainingTimeInMilliseconds = 42000;
-
- beforeEach(async () => {
- jest
- .spyOn(Date, 'now')
- .mockImplementation(
- () => mockGraphQlJob.scheduledAt.getTime() - remainingTimeInMilliseconds,
- );
-
- wrapper = shallowMount(dummyComponent, {
- propsData: {
- job: mockGraphQlJob,
- },
- });
-
- await nextTick();
- });
-
- it('sets remaining time', () => {
- expect(wrapper.text()).toBe('00:00:42');
- });
-
- it('updates remaining time', async () => {
- remainingTimeInMilliseconds = 41000;
- jest.advanceTimersByTime(1000);
-
- await nextTick();
- expect(wrapper.text()).toBe('00:00:41');
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js
deleted file mode 100644
index 253e669e889..00000000000
--- a/spec/frontend/jobs/mock_data.js
+++ /dev/null
@@ -1,1628 +0,0 @@
-import mockJobsCount from 'test_fixtures/graphql/jobs/get_jobs_count.query.graphql.json';
-import mockAllJobsCount from 'test_fixtures/graphql/jobs/get_all_jobs_count.query.graphql.json';
-import mockJobsEmpty from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.empty.json';
-import mockAllJobsEmpty from 'test_fixtures/graphql/jobs/get_all_jobs.query.graphql.empty.json';
-import mockJobsPaginated from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.paginated.json';
-import mockAllJobsPaginated from 'test_fixtures/graphql/jobs/get_all_jobs.query.graphql.paginated.json';
-import mockJobs from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.json';
-import mockAllJobs from 'test_fixtures/graphql/jobs/get_all_jobs.query.graphql.json';
-import mockJobsAsGuest from 'test_fixtures/graphql/jobs/get_jobs.query.graphql.as_guest.json';
-import mockCancelableJobsCount from 'test_fixtures/graphql/jobs/get_cancelable_jobs_count.query.graphql.json';
-import { TEST_HOST } from 'spec/test_constants';
-import { TOKEN_TYPE_STATUS } from '~/vue_shared/components/filtered_search_bar/constants';
-
-const threeWeeksAgo = new Date();
-threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
-
-// Fixtures generated at spec/frontend/fixtures/jobs.rb
-export const mockJobsResponsePaginated = mockJobsPaginated;
-export const mockAllJobsResponsePaginated = mockAllJobsPaginated;
-export const mockJobsResponseEmpty = mockJobsEmpty;
-export const mockAllJobsResponseEmpty = mockAllJobsEmpty;
-export const mockJobsNodes = mockJobs.data.project.jobs.nodes;
-export const mockAllJobsNodes = mockAllJobs.data.jobs.nodes;
-export const mockJobsNodesAsGuest = mockJobsAsGuest.data.project.jobs.nodes;
-export const mockJobsCountResponse = mockJobsCount;
-export const mockAllJobsCountResponse = mockAllJobsCount;
-export const mockCancelableJobsCountResponse = mockCancelableJobsCount;
-
-export const stages = [
- {
- name: 'build',
- title: 'build: running',
- groups: [
- {
- name: 'build:linux',
- size: 1,
- status: {
- icon: 'status_pending',
- text: 'pending',
- label: 'pending',
- group: 'pending',
- tooltip: 'pending',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
- illustration: {
- image: 'illustrations/pending_job_empty.svg',
- size: 'svg-430',
- title: 'This job has not started yet',
- content: 'This job is in pending state and is waiting to be picked by a runner',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
- action: {
- icon: 'cancel',
- title: 'Cancel',
- path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 1180,
- name: 'build:linux',
- started: false,
- build_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
- cancel_path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
- playable: false,
- created_at: '2018-09-28T11:09:57.229Z',
- updated_at: '2018-09-28T11:09:57.503Z',
- status: {
- icon: 'status_pending',
- text: 'pending',
- label: 'pending',
- group: 'pending',
- tooltip: 'pending',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
- illustration: {
- image: 'illustrations/pending_job_empty.svg',
- size: 'svg-430',
- title: 'This job has not started yet',
- content: 'This job is in pending state and is waiting to be picked by a runner',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
- action: {
- icon: 'cancel',
- title: 'Cancel',
- path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
- method: 'post',
- },
- },
- },
- ],
- },
- {
- name: 'build:osx',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/444',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 444,
- name: 'build:osx',
- started: '2018-05-18T05:32:20.655Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/444',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.364Z',
- updated_at: '2018-05-18T15:32:54.364Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/444',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
- method: 'post',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_running',
- text: 'running',
- label: 'running',
- group: 'running',
- tooltip: 'running',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/pipelines/27#build',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_running-9c635b2419a8e1ec991c993061b89cc5aefc0743bb238ecd0c381e7741a70e8c.png',
- },
- path: '/gitlab-org/gitlab-shell/pipelines/27#build',
- dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=build',
- },
- {
- name: 'test',
- title: 'test: passed with warnings',
- groups: [
- {
- name: 'jenkins',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: null,
- group: 'success',
- tooltip: null,
- has_details: false,
- details_path: null,
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- jobs: [
- {
- id: 459,
- name: 'jenkins',
- started: '2018-05-18T09:32:20.658Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/459',
- playable: false,
- created_at: '2018-05-18T15:32:55.330Z',
- updated_at: '2018-05-18T15:32:55.330Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: null,
- group: 'success',
- tooltip: null,
- has_details: false,
- details_path: null,
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- },
- ],
- },
- {
- name: 'rspec:linux',
- size: 3,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: false,
- details_path: null,
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- jobs: [
- {
- id: 445,
- name: 'rspec:linux 0 3',
- started: '2018-05-18T07:32:20.655Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/445',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/445/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.425Z',
- updated_at: '2018-05-18T15:32:54.425Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/445',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/445/retry',
- method: 'post',
- },
- },
- },
- {
- id: 446,
- name: 'rspec:linux 1 3',
- started: '2018-05-18T07:32:20.655Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/446',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/446/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.506Z',
- updated_at: '2018-05-18T15:32:54.506Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/446',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/446/retry',
- method: 'post',
- },
- },
- },
- {
- id: 447,
- name: 'rspec:linux 2 3',
- started: '2018-05-18T07:32:20.656Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/447',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/447/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.572Z',
- updated_at: '2018-05-18T15:32:54.572Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/447',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/447/retry',
- method: 'post',
- },
- },
- },
- ],
- },
- {
- name: 'rspec:osx',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/452',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/452/retry',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 452,
- name: 'rspec:osx',
- started: '2018-05-18T07:32:20.657Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/452',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/452/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.920Z',
- updated_at: '2018-05-18T15:32:54.920Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/452',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/452/retry',
- method: 'post',
- },
- },
- },
- ],
- },
- {
- name: 'rspec:windows',
- size: 3,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: false,
- details_path: null,
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- jobs: [
- {
- id: 448,
- name: 'rspec:windows 0 3',
- started: '2018-05-18T07:32:20.656Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/448',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/448/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.639Z',
- updated_at: '2018-05-18T15:32:54.639Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/448',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/448/retry',
- method: 'post',
- },
- },
- },
- {
- id: 449,
- name: 'rspec:windows 1 3',
- started: '2018-05-18T07:32:20.656Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/449',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/449/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.703Z',
- updated_at: '2018-05-18T15:32:54.703Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/449',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/449/retry',
- method: 'post',
- },
- },
- },
- {
- id: 451,
- name: 'rspec:windows 2 3',
- started: '2018-05-18T07:32:20.657Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/451',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/451/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.853Z',
- updated_at: '2018-05-18T15:32:54.853Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/451',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/451/retry',
- method: 'post',
- },
- },
- },
- ],
- },
- {
- name: 'spinach:linux',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/453',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/453/retry',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 453,
- name: 'spinach:linux',
- started: '2018-05-18T07:32:20.657Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/453',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/453/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.993Z',
- updated_at: '2018-05-18T15:32:54.993Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/453',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/453/retry',
- method: 'post',
- },
- },
- },
- ],
- },
- {
- name: 'spinach:osx',
- size: 1,
- status: {
- icon: 'status_warning',
- text: 'failed',
- label: 'failed (allowed to fail)',
- group: 'failed-with-warnings',
- tooltip: 'failed - (unknown failure) (allowed to fail)',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/454',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 454,
- name: 'spinach:osx',
- started: '2018-05-18T07:32:20.657Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/454',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
- playable: false,
- created_at: '2018-05-18T15:32:55.053Z',
- updated_at: '2018-05-18T15:32:55.053Z',
- status: {
- icon: 'status_warning',
- text: 'failed',
- label: 'failed (allowed to fail)',
- group: 'failed-with-warnings',
- tooltip: 'failed - (unknown failure) (allowed to fail)',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/454',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
- method: 'post',
- },
- },
- callout_message: 'There is an unknown failure, please try again',
- recoverable: true,
- },
- ],
- },
- ],
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/pipelines/27#test',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/gitlab-org/gitlab-shell/pipelines/27#test',
- dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=test',
- },
- {
- name: 'deploy',
- title: 'deploy: running',
- groups: [
- {
- name: 'production',
- size: 1,
- status: {
- icon: 'status_created',
- text: 'created',
- label: 'created',
- group: 'created',
- tooltip: 'created',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/457',
- illustration: {
- image: 'illustrations/job_not_triggered.svg',
- size: 'svg-306',
- title: 'This job has not been triggered yet',
- content:
- 'This job depends on upstream jobs that need to succeed in order for this job to be triggered',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png',
- action: {
- icon: 'cancel',
- title: 'Cancel',
- path: '/gitlab-org/gitlab-shell/-/jobs/457/cancel',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 457,
- name: 'production',
- started: false,
- build_path: '/gitlab-org/gitlab-shell/-/jobs/457',
- cancel_path: '/gitlab-org/gitlab-shell/-/jobs/457/cancel',
- playable: false,
- created_at: '2018-05-18T15:32:55.259Z',
- updated_at: '2018-09-28T11:09:57.454Z',
- status: {
- icon: 'status_created',
- text: 'created',
- label: 'created',
- group: 'created',
- tooltip: 'created',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/457',
- illustration: {
- image: 'illustrations/job_not_triggered.svg',
- size: 'svg-306',
- title: 'This job has not been triggered yet',
- content:
- 'This job depends on upstream jobs that need to succeed in order for this job to be triggered',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png',
- action: {
- icon: 'cancel',
- title: 'Cancel',
- path: '/gitlab-org/gitlab-shell/-/jobs/457/cancel',
- method: 'post',
- },
- },
- },
- ],
- },
- {
- name: 'staging',
- size: 1,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/455',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/455/retry',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 455,
- name: 'staging',
- started: '2018-05-18T09:32:20.658Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/455',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/455/retry',
- playable: false,
- created_at: '2018-05-18T15:32:55.119Z',
- updated_at: '2018-05-18T15:32:55.119Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/455',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/455/retry',
- method: 'post',
- },
- },
- },
- ],
- },
- {
- name: 'stop staging',
- size: 1,
- status: {
- icon: 'status_created',
- text: 'created',
- label: 'created',
- group: 'created',
- tooltip: 'created',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/456',
- illustration: {
- image: 'illustrations/job_not_triggered.svg',
- size: 'svg-306',
- title: 'This job has not been triggered yet',
- content:
- 'This job depends on upstream jobs that need to succeed in order for this job to be triggered',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png',
- action: {
- icon: 'cancel',
- title: 'Cancel',
- path: '/gitlab-org/gitlab-shell/-/jobs/456/cancel',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 456,
- name: 'stop staging',
- started: false,
- build_path: '/gitlab-org/gitlab-shell/-/jobs/456',
- cancel_path: '/gitlab-org/gitlab-shell/-/jobs/456/cancel',
- playable: false,
- created_at: '2018-05-18T15:32:55.205Z',
- updated_at: '2018-09-28T11:09:57.396Z',
- status: {
- icon: 'status_created',
- text: 'created',
- label: 'created',
- group: 'created',
- tooltip: 'created',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/456',
- illustration: {
- image: 'illustrations/job_not_triggered.svg',
- size: 'svg-306',
- title: 'This job has not been triggered yet',
- content:
- 'This job depends on upstream jobs that need to succeed in order for this job to be triggered',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_created-4b975aa976d24e5a3ea7cd9a5713e6ce2cd9afd08b910415e96675de35f64955.png',
- action: {
- icon: 'cancel',
- title: 'Cancel',
- path: '/gitlab-org/gitlab-shell/-/jobs/456/cancel',
- method: 'post',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_running',
- text: 'running',
- label: 'running',
- group: 'running',
- tooltip: 'running',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/pipelines/27#deploy',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_running-9c635b2419a8e1ec991c993061b89cc5aefc0743bb238ecd0c381e7741a70e8c.png',
- },
- path: '/gitlab-org/gitlab-shell/pipelines/27#deploy',
- dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=deploy',
- },
- {
- name: 'notify',
- title: 'notify: manual action',
- groups: [
- {
- name: 'slack',
- size: 1,
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/458',
- illustration: {
- image: 'illustrations/manual_action.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-org/gitlab-shell/-/jobs/458/play',
- method: 'post',
- },
- },
- jobs: [
- {
- id: 458,
- name: 'slack',
- started: null,
- build_path: '/gitlab-org/gitlab-shell/-/jobs/458',
- play_path: '/gitlab-org/gitlab-shell/-/jobs/458/play',
- playable: true,
- created_at: '2018-05-18T15:32:55.303Z',
- updated_at: '2018-05-18T15:34:08.535Z',
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual play action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/458',
- illustration: {
- image: 'illustrations/manual_action.svg',
- size: 'svg-394',
- title: 'This job requires a manual action',
- content:
- 'This job depends on a user to trigger its process. Often they are used to deploy code to production environments',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/gitlab-org/gitlab-shell/-/jobs/458/play',
- method: 'post',
- },
- },
- },
- ],
- },
- ],
- status: {
- icon: 'status_manual',
- text: 'manual',
- label: 'manual action',
- group: 'manual',
- tooltip: 'manual action',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/pipelines/27#notify',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_manual-829a0804612cef47d9efc1618dba38325483657c847dba0546c3b9f0295bb36c.png',
- },
- path: '/gitlab-org/gitlab-shell/pipelines/27#notify',
- dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=notify',
- },
-];
-
-export const statuses = {
- success: 'SUCCESS',
- failed: 'FAILED',
- canceled: 'CANCELED',
- pending: 'PENDING',
- running: 'RUNNING',
-};
-
-export default {
- id: 4757,
- artifact: {
- locked: false,
- },
- name: 'test',
- stage: 'build',
- build_path: '/root/ci-mock/-/jobs/4757',
- retry_path: '/root/ci-mock/-/jobs/4757/retry',
- cancel_path: '/root/ci-mock/-/jobs/4757/cancel',
- new_issue_path: '/root/ci-mock/issues/new',
- playable: false,
- complete: true,
- created_at: threeWeeksAgo.toISOString(),
- updated_at: threeWeeksAgo.toISOString(),
- finished_at: threeWeeksAgo.toISOString(),
- queued_duration: 9.54,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- has_details: true,
- details_path: `${TEST_HOST}/root/ci-mock/-/jobs/4757`,
- favicon:
- '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/root/ci-mock/-/jobs/4757/retry',
- method: 'post',
- },
- },
- coverage: 20,
- erased_at: threeWeeksAgo.toISOString(),
- erased: false,
- duration: 6.785563,
- tags: ['tag'],
- user: {
- name: 'Root',
- username: 'root',
- id: 1,
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
- web_url: 'http://localhost:3000/root',
- },
- erase_path: '/root/ci-mock/-/jobs/4757/erase',
- artifacts: [null],
- runner: {
- id: 1,
- short_sha: 'ABCDEFGH',
- description: 'local ci runner',
- edit_path: '/root/ci-mock/runners/1/edit',
- },
- pipeline: {
- id: 140,
- user: {
- name: 'Root',
- username: 'root',
- id: 1,
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
- web_url: 'http://localhost:3000/root',
- },
- active: false,
- coverage: null,
- source: 'unknown',
- created_at: '2017-05-24T09:59:58.634Z',
- updated_at: '2017-06-01T17:32:00.062Z',
- path: '/root/ci-mock/pipelines/140',
- flags: {
- latest: true,
- stuck: false,
- yaml_errors: false,
- retryable: false,
- cancelable: false,
- },
- details: {
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- has_details: true,
- details_path: '/root/ci-mock/pipelines/140',
- favicon:
- '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png',
- },
- duration: 6,
- finished_at: '2017-06-01T17:32:00.042Z',
- stages: [
- {
- dropdown_path: '/jashkenas/underscore/pipelines/16/stage.json?stage=build',
- name: 'build',
- path: '/jashkenas/underscore/pipelines/16#build',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- },
- title: 'build: passed',
- },
- {
- dropdown_path: '/jashkenas/underscore/pipelines/16/stage.json?stage=test',
- name: 'test',
- path: '/jashkenas/underscore/pipelines/16#test',
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- },
- title: 'test: passed with warnings',
- },
- ],
- },
- ref: {
- name: 'abc',
- path: '/root/ci-mock/commits/abc',
- tag: false,
- branch: true,
- },
- commit: {
- id: 'c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
- short_id: 'c5864777',
- title: 'Add new file',
- created_at: '2017-05-24T10:59:52.000+01:00',
- parent_ids: ['798e5f902592192afaba73f4668ae30e56eae492'],
- message: 'Add new file',
- author_name: 'Root',
- author_email: 'admin@example.com',
- authored_date: '2017-05-24T10:59:52.000+01:00',
- committer_name: 'Root',
- committer_email: 'admin@example.com',
- committed_date: '2017-05-24T10:59:52.000+01:00',
- author: {
- name: 'Root',
- username: 'root',
- id: 1,
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
- web_url: 'http://localhost:3000/root',
- },
- author_gravatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
- commit_url:
- 'http://localhost:3000/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
- commit_path: '/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
- },
- },
- metadata: {
- timeout_human_readable: '1m 40s',
- timeout_source: 'runner',
- },
- merge_request: {
- iid: 2,
- path: '/root/ci-mock/merge_requests/2',
- },
- raw_path: '/root/ci-mock/builds/4757/raw',
- has_trace: true,
-};
-
-export const failedJobStatus = {
- icon: 'status_warning',
- text: 'failed',
- label: 'failed (allowed to fail)',
- group: 'failed-with-warnings',
- tooltip: 'failed - (unknown failure) (allowed to fail)',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/454',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
- method: 'post',
- },
-};
-
-export const jobsInStage = {
- name: 'build',
- title: 'build: running',
- latest_statuses: [
- {
- id: 1180,
- name: 'build:linux',
- started: false,
- build_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
- cancel_path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
- playable: false,
- created_at: '2018-09-28T11:09:57.229Z',
- updated_at: '2018-09-28T11:09:57.503Z',
- status: {
- icon: 'status_pending',
- text: 'pending',
- label: 'pending',
- group: 'pending',
- tooltip: 'pending',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/1180',
- illustration: {
- image: 'illustrations/pending_job_empty.svg',
- size: 'svg-430',
- title: 'This job has not started yet',
- content: 'This job is in pending state and is waiting to be picked by a runner',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
- action: {
- icon: 'cancel',
- title: 'Cancel',
- path: '/gitlab-org/gitlab-shell/-/jobs/1180/cancel',
- method: 'post',
- },
- },
- },
- {
- id: 444,
- name: 'build:osx',
- started: '2018-05-18T05:32:20.655Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/444',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.364Z',
- updated_at: '2018-05-18T15:32:54.364Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/444',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/444/retry',
- method: 'post',
- },
- },
- },
- ],
- retried: [
- {
- id: 443,
- name: 'build:linux',
- started: '2018-05-18T06:32:20.655Z',
- build_path: '/gitlab-org/gitlab-shell/-/jobs/443',
- retry_path: '/gitlab-org/gitlab-shell/-/jobs/443/retry',
- playable: false,
- created_at: '2018-05-18T15:32:54.296Z',
- updated_at: '2018-05-18T15:32:54.296Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed (retried)',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/-/jobs/443',
- illustration: {
- image: 'illustrations/skipped-job_empty.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/gitlab-org/gitlab-shell/-/jobs/443/retry',
- method: 'post',
- },
- },
- },
- ],
- status: {
- icon: 'status_running',
- text: 'running',
- label: 'running',
- group: 'running',
- tooltip: 'running',
- has_details: true,
- details_path: '/gitlab-org/gitlab-shell/pipelines/27#build',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_running-9c635b2419a8e1ec991c993061b89cc5aefc0743bb238ecd0c381e7741a70e8c.png',
- },
- path: '/gitlab-org/gitlab-shell/pipelines/27#build',
- dropdown_path: '/gitlab-org/gitlab-shell/pipelines/27/stage.json?stage=build',
-};
-
-export const mockPipelineWithoutMR = {
- id: 28029444,
- details: {
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- },
- path: 'pipeline/28029444',
- ref: {
- name: 'test-branch',
- },
-};
-
-export const mockPipelineWithoutRef = {
- ...mockPipelineWithoutMR,
- ref: null,
-};
-
-export const mockPipelineWithAttachedMR = {
- id: 28029444,
- details: {
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- },
- path: 'pipeline/28029444',
- flags: {
- merge_request_pipeline: true,
- detached_merge_request_pipeline: false,
- },
- merge_request: {
- iid: 1234,
- path: '/root/detached-merge-request-pipelines/-/merge_requests/1',
- title: 'Update README.md',
- source_branch: 'feature-1234',
- source_branch_path: '/root/detached-merge-request-pipelines/branches/feature-1234',
- target_branch: 'main',
- target_branch_path: '/root/detached-merge-request-pipelines/branches/main',
- },
- ref: {
- name: 'test-branch',
- },
-};
-
-export const mockPipelineDetached = {
- id: 28029444,
- details: {
- status: {
- details_path: '/gitlab-org/gitlab-foss/pipelines/28029444',
- group: 'success',
- has_details: true,
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed',
- },
- },
- path: 'pipeline/28029444',
- flags: {
- merge_request_pipeline: false,
- detached_merge_request_pipeline: true,
- },
- merge_request: {
- iid: 1234,
- path: '/root/detached-merge-request-pipelines/-/merge_requests/1',
- title: 'Update README.md',
- source_branch: 'feature-1234',
- source_branch_path: '/root/detached-merge-request-pipelines/branches/feature-1234',
- target_branch: 'main',
- target_branch_path: '/root/detached-merge-request-pipelines/branches/main',
- },
- ref: {
- name: 'test-branch',
- },
-};
-
-export const CIJobConnectionIncomingCache = {
- __typename: 'CiJobConnection',
- pageInfo: {
- __typename: 'PageInfo',
- endCursor: 'eyJpZCI6IjIwNTEifQ',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'eyJpZCI6IjIxNzMifQ',
- },
- nodes: [
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2057' },
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2056' },
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2051' },
- ],
-};
-
-export const CIJobConnectionIncomingCacheRunningStatus = {
- __typename: 'CiJobConnection',
- pageInfo: {
- __typename: 'PageInfo',
- endCursor: 'eyJpZCI6IjIwNTEifQ',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'eyJpZCI6IjIxNzMifQ',
- },
- nodes: [
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2000' },
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2001' },
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2002' },
- ],
-};
-
-export const CIJobConnectionExistingCache = {
- pageInfo: {
- __typename: 'PageInfo',
- endCursor: 'eyJpZCI6IjIwNTEifQ',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'eyJpZCI6IjIxNzMifQ',
- },
- nodes: [
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2100' },
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2101' },
- { __ref: 'CiJob:gid://gitlab/Ci::Build/2102' },
- ],
- statuses: 'PENDING',
-};
-
-export const mockFailedSearchToken = {
- type: TOKEN_TYPE_STATUS,
- value: { data: 'FAILED', operator: '=' },
-};
-
-export const retryMutationResponse = {
- data: {
- jobRetry: {
- job: {
- __typename: 'CiJob',
- id: '"gid://gitlab/Ci::Build/1985"',
- detailedStatus: {
- detailsPath: '/root/project/-/jobs/1985',
- id: 'pending-1985-1985',
- __typename: 'DetailedStatus',
- },
- },
- errors: [],
- __typename: 'JobRetryPayload',
- },
- },
-};
-
-export const playMutationResponse = {
- data: {
- jobPlay: {
- job: {
- __typename: 'CiJob',
- id: '"gid://gitlab/Ci::Build/1986"',
- detailedStatus: {
- detailsPath: '/root/project/-/jobs/1986',
- id: 'pending-1986-1986',
- __typename: 'DetailedStatus',
- },
- },
- errors: [],
- __typename: 'JobRetryPayload',
- },
- },
-};
-
-export const cancelMutationResponse = {
- data: {
- jobCancel: {
- job: {
- __typename: 'CiJob',
- id: '"gid://gitlab/Ci::Build/1987"',
- detailedStatus: {
- detailsPath: '/root/project/-/jobs/1987',
- id: 'pending-1987-1987',
- __typename: 'DetailedStatus',
- },
- },
- errors: [],
- __typename: 'JobRetryPayload',
- },
- },
-};
-
-export const unscheduleMutationResponse = {
- data: {
- jobUnschedule: {
- job: {
- __typename: 'CiJob',
- id: '"gid://gitlab/Ci::Build/1988"',
- detailedStatus: {
- detailsPath: '/root/project/-/jobs/1988',
- id: 'pending-1988-1988',
- __typename: 'DetailedStatus',
- },
- },
- errors: [],
- __typename: 'JobRetryPayload',
- },
- },
-};
-
-export const mockJobLog = [
- { offset: 0, content: [{ text: 'Running with gitlab-runner 15.0.0 (febb2a09)' }], lineNumber: 0 },
- { offset: 54, content: [{ text: ' on colima-docker EwM9WzgD' }], lineNumber: 1 },
- {
- isClosed: false,
- isHeader: true,
- line: {
- offset: 91,
- content: [{ text: 'Resolving secrets', style: 'term-fg-l-cyan term-bold' }],
- section: 'resolve-secrets',
- section_header: true,
- lineNumber: 2,
- section_duration: '00:00',
- },
- lines: [],
- },
- {
- isClosed: false,
- isHeader: true,
- line: {
- offset: 218,
- content: [{ text: 'Preparing the "docker" executor', style: 'term-fg-l-cyan term-bold' }],
- section: 'prepare-executor',
- section_header: true,
- lineNumber: 4,
- section_duration: '00:01',
- },
- lines: [
- {
- offset: 317,
- content: [{ text: 'Using Docker executor with image ruby:2.7 ...' }],
- section: 'prepare-executor',
- lineNumber: 5,
- },
- {
- offset: 372,
- content: [{ text: 'Pulling docker image ruby:2.7 ...' }],
- section: 'prepare-executor',
- lineNumber: 6,
- },
- {
- offset: 415,
- content: [
- {
- text:
- 'Using docker image sha256:55106bf6ba7f452c38d01ea760affc6ceb67d4b60068ffadab98d1b7b007668c for ruby:2.7 with digest ruby@sha256:23d08a4bae1a12ee3fce017f83204fcf9a02243443e4a516e65e5ff73810a449 ...',
- },
- ],
- section: 'prepare-executor',
- lineNumber: 7,
- },
- ],
- },
- {
- isClosed: false,
- isHeader: true,
- line: {
- offset: 665,
- content: [{ text: 'Preparing environment', style: 'term-fg-l-cyan term-bold' }],
- section: 'prepare-script',
- section_header: true,
- lineNumber: 9,
- section_duration: '00:01',
- },
- lines: [
- {
- offset: 752,
- content: [
- { text: 'Running on runner-ewm9wzgd-project-20-concurrent-0 via 8ea689ec6969...' },
- ],
- section: 'prepare-script',
- lineNumber: 10,
- },
- ],
- },
- {
- isClosed: false,
- isHeader: true,
- line: {
- offset: 865,
- content: [{ text: 'Getting source from Git repository', style: 'term-fg-l-cyan term-bold' }],
- section: 'get-sources',
- section_header: true,
- lineNumber: 12,
- section_duration: '00:01',
- },
- lines: [
- {
- offset: 962,
- content: [
- {
- text: 'Fetching changes with git depth set to 20...',
- style: 'term-fg-l-green term-bold',
- },
- ],
- section: 'get-sources',
- lineNumber: 13,
- },
- {
- offset: 1019,
- content: [
- { text: 'Reinitialized existing Git repository in /builds/root/ci-project/.git/' },
- ],
- section: 'get-sources',
- lineNumber: 14,
- },
- {
- offset: 1090,
- content: [{ text: 'Checking out e0f63d76 as main...', style: 'term-fg-l-green term-bold' }],
- section: 'get-sources',
- lineNumber: 15,
- },
- {
- offset: 1136,
- content: [{ text: 'Skipping Git submodules setup', style: 'term-fg-l-green term-bold' }],
- section: 'get-sources',
- lineNumber: 16,
- },
- ],
- },
- {
- isClosed: false,
- isHeader: true,
- line: {
- offset: 1217,
- content: [
- {
- text: 'Executing "step_script" stage of the job script',
- style: 'term-fg-l-cyan term-bold',
- },
- ],
- section: 'step-script',
- section_header: true,
- lineNumber: 18,
- section_duration: '00:00',
- },
- lines: [
- {
- offset: 1327,
- content: [
- {
- text:
- 'Using docker image sha256:55106bf6ba7f452c38d01ea760affc6ceb67d4b60068ffadab98d1b7b007668c for ruby:2.7 with digest ruby@sha256:23d08a4bae1a12ee3fce017f83204fcf9a02243443e4a516e65e5ff73810a449 ...',
- },
- ],
- section: 'step-script',
- lineNumber: 19,
- },
- {
- offset: 1533,
- content: [{ text: '$ echo "82.71"', style: 'term-fg-l-green term-bold' }],
- section: 'step-script',
- lineNumber: 20,
- },
- { offset: 1560, content: [{ text: '82.71' }], section: 'step-script', lineNumber: 21 },
- ],
- },
- {
- offset: 1605,
- content: [{ text: 'Job succeeded', style: 'term-fg-l-green term-bold' }],
- lineNumber: 23,
- },
-];
diff --git a/spec/frontend/jobs/store/actions_spec.js b/spec/frontend/jobs/store/actions_spec.js
deleted file mode 100644
index 73a158d52d8..00000000000
--- a/spec/frontend/jobs/store/actions_spec.js
+++ /dev/null
@@ -1,502 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import { TEST_HOST } from 'helpers/test_constants';
-import testAction from 'helpers/vuex_action_helper';
-import {
- setJobEndpoint,
- setJobLogOptions,
- clearEtagPoll,
- stopPolling,
- requestJob,
- fetchJob,
- receiveJobSuccess,
- receiveJobError,
- scrollTop,
- scrollBottom,
- requestJobLog,
- fetchJobLog,
- startPollingJobLog,
- stopPollingJobLog,
- receiveJobLogSuccess,
- receiveJobLogError,
- toggleCollapsibleLine,
- requestJobsForStage,
- fetchJobsForStage,
- receiveJobsForStageSuccess,
- receiveJobsForStageError,
- hideSidebar,
- showSidebar,
- toggleSidebar,
-} from '~/jobs/store/actions';
-import * as types from '~/jobs/store/mutation_types';
-import state from '~/jobs/store/state';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-
-describe('Job State actions', () => {
- let mockedState;
-
- beforeEach(() => {
- mockedState = state();
- });
-
- describe('setJobEndpoint', () => {
- it('should commit SET_JOB_ENDPOINT mutation', () => {
- return testAction(
- setJobEndpoint,
- 'job/872324.json',
- mockedState,
- [{ type: types.SET_JOB_ENDPOINT, payload: 'job/872324.json' }],
- [],
- );
- });
- });
-
- describe('setJobLogOptions', () => {
- it('should commit SET_JOB_LOG_OPTIONS mutation', () => {
- return testAction(
- setJobLogOptions,
- { pagePath: 'job/872324/trace.json' },
- mockedState,
- [{ type: types.SET_JOB_LOG_OPTIONS, payload: { pagePath: 'job/872324/trace.json' } }],
- [],
- );
- });
- });
-
- describe('hideSidebar', () => {
- it('should commit HIDE_SIDEBAR mutation', () => {
- return testAction(hideSidebar, null, mockedState, [{ type: types.HIDE_SIDEBAR }], []);
- });
- });
-
- describe('showSidebar', () => {
- it('should commit SHOW_SIDEBAR mutation', () => {
- return testAction(showSidebar, null, mockedState, [{ type: types.SHOW_SIDEBAR }], []);
- });
- });
-
- describe('toggleSidebar', () => {
- describe('when isSidebarOpen is true', () => {
- it('should dispatch hideSidebar', () => {
- return testAction(toggleSidebar, null, mockedState, [], [{ type: 'hideSidebar' }]);
- });
- });
-
- describe('when isSidebarOpen is false', () => {
- it('should dispatch showSidebar', () => {
- mockedState.isSidebarOpen = false;
-
- return testAction(toggleSidebar, null, mockedState, [], [{ type: 'showSidebar' }]);
- });
- });
- });
-
- describe('requestJob', () => {
- it('should commit REQUEST_JOB mutation', () => {
- return testAction(requestJob, null, mockedState, [{ type: types.REQUEST_JOB }], []);
- });
- });
-
- describe('fetchJob', () => {
- let mock;
-
- beforeEach(() => {
- mockedState.jobEndpoint = `${TEST_HOST}/endpoint.json`;
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- stopPolling();
- clearEtagPoll();
- });
-
- describe('success', () => {
- it('dispatches requestJob and receiveJobSuccess', () => {
- mock
- .onGet(`${TEST_HOST}/endpoint.json`)
- .replyOnce(HTTP_STATUS_OK, { id: 121212, name: 'karma' });
-
- return testAction(
- fetchJob,
- null,
- mockedState,
- [],
- [
- {
- type: 'requestJob',
- },
- {
- payload: { id: 121212, name: 'karma' },
- type: 'receiveJobSuccess',
- },
- ],
- );
- });
- });
-
- describe('error', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/endpoint.json`).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
- });
-
- it('dispatches requestJob and receiveJobError', () => {
- return testAction(
- fetchJob,
- null,
- mockedState,
- [],
- [
- {
- type: 'requestJob',
- },
- {
- type: 'receiveJobError',
- },
- ],
- );
- });
- });
- });
-
- describe('receiveJobSuccess', () => {
- it('should commit RECEIVE_JOB_SUCCESS mutation', () => {
- return testAction(
- receiveJobSuccess,
- { id: 121232132 },
- mockedState,
- [{ type: types.RECEIVE_JOB_SUCCESS, payload: { id: 121232132 } }],
- [],
- );
- });
- });
-
- describe('receiveJobError', () => {
- it('should commit RECEIVE_JOB_ERROR mutation', () => {
- return testAction(
- receiveJobError,
- null,
- mockedState,
- [{ type: types.RECEIVE_JOB_ERROR }],
- [],
- );
- });
- });
-
- describe('scrollTop', () => {
- it('should dispatch toggleScrollButtons action', () => {
- return testAction(scrollTop, null, mockedState, [], [{ type: 'toggleScrollButtons' }]);
- });
- });
-
- describe('scrollBottom', () => {
- it('should dispatch toggleScrollButtons action', () => {
- return testAction(scrollBottom, null, mockedState, [], [{ type: 'toggleScrollButtons' }]);
- });
- });
-
- describe('requestJobLog', () => {
- it('should commit REQUEST_JOB_LOG mutation', () => {
- return testAction(requestJobLog, null, mockedState, [{ type: types.REQUEST_JOB_LOG }], []);
- });
- });
-
- describe('fetchJobLog', () => {
- let mock;
-
- beforeEach(() => {
- mockedState.jobLogEndpoint = `${TEST_HOST}/endpoint`;
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- stopPolling();
- clearEtagPoll();
- });
-
- describe('success', () => {
- it('dispatches requestJobLog, receiveJobLogSuccess and stopPollingJobLog when job is complete', () => {
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, {
- html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
- complete: true,
- });
-
- return testAction(
- fetchJobLog,
- null,
- mockedState,
- [],
- [
- {
- type: 'toggleScrollisInBottom',
- payload: true,
- },
- {
- payload: {
- html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
- complete: true,
- },
- type: 'receiveJobLogSuccess',
- },
- {
- type: 'stopPollingJobLog',
- },
- ],
- );
- });
-
- describe('when job is incomplete', () => {
- let jobLogPayload;
-
- beforeEach(() => {
- jobLogPayload = {
- html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
- complete: false,
- };
-
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, jobLogPayload);
- });
-
- it('dispatches startPollingJobLog', () => {
- return testAction(
- fetchJobLog,
- null,
- mockedState,
- [],
- [
- { type: 'toggleScrollisInBottom', payload: true },
- { type: 'receiveJobLogSuccess', payload: jobLogPayload },
- { type: 'startPollingJobLog' },
- ],
- );
- });
-
- it('does not dispatch startPollingJobLog when timeout is non-empty', () => {
- mockedState.jobLogTimeout = 1;
-
- return testAction(
- fetchJobLog,
- null,
- mockedState,
- [],
- [
- { type: 'toggleScrollisInBottom', payload: true },
- { type: 'receiveJobLogSuccess', payload: jobLogPayload },
- ],
- );
- });
- });
- });
-
- describe('error', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
- });
-
- it('dispatches requestJobLog and receiveJobLogError', () => {
- return testAction(
- fetchJobLog,
- null,
- mockedState,
- [],
- [
- {
- type: 'receiveJobLogError',
- },
- ],
- );
- });
- });
- });
-
- describe('startPollingJobLog', () => {
- let dispatch;
- let commit;
-
- beforeEach(() => {
- dispatch = jest.fn();
- commit = jest.fn();
-
- startPollingJobLog({ dispatch, commit });
- });
-
- afterEach(() => {
- jest.clearAllTimers();
- });
-
- it('should save the timeout id but not call fetchJobLog', () => {
- expect(commit).toHaveBeenCalledWith(types.SET_JOB_LOG_TIMEOUT, expect.any(Number));
- expect(commit.mock.calls[0][1]).toBeGreaterThan(0);
-
- expect(dispatch).not.toHaveBeenCalledWith('fetchJobLog');
- });
-
- describe('after timeout has passed', () => {
- beforeEach(() => {
- jest.advanceTimersByTime(4000);
- });
-
- it('should clear the timeout id and fetchJobLog', () => {
- expect(commit).toHaveBeenCalledWith(types.SET_JOB_LOG_TIMEOUT, 0);
- expect(dispatch).toHaveBeenCalledWith('fetchJobLog');
- });
- });
- });
-
- describe('stopPollingJobLog', () => {
- let origTimeout;
-
- beforeEach(() => {
- // Can't use spyOn(window, 'clearTimeout') because this caused unrelated specs to timeout
- // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23838#note_280277727
- origTimeout = window.clearTimeout;
- window.clearTimeout = jest.fn();
- });
-
- afterEach(() => {
- window.clearTimeout = origTimeout;
- });
-
- it('should commit STOP_POLLING_JOB_LOG mutation', async () => {
- const jobLogTimeout = 7;
-
- await testAction(
- stopPollingJobLog,
- null,
- { ...mockedState, jobLogTimeout },
- [{ type: types.SET_JOB_LOG_TIMEOUT, payload: 0 }, { type: types.STOP_POLLING_JOB_LOG }],
- [],
- );
- expect(window.clearTimeout).toHaveBeenCalledWith(jobLogTimeout);
- });
- });
-
- describe('receiveJobLogSuccess', () => {
- it('should commit RECEIVE_JOB_LOG_SUCCESS mutation', () => {
- return testAction(
- receiveJobLogSuccess,
- 'hello world',
- mockedState,
- [{ type: types.RECEIVE_JOB_LOG_SUCCESS, payload: 'hello world' }],
- [],
- );
- });
- });
-
- describe('receiveJobLogError', () => {
- it('should commit stop polling job log', () => {
- return testAction(receiveJobLogError, null, mockedState, [], [{ type: 'stopPollingJobLog' }]);
- });
- });
-
- describe('toggleCollapsibleLine', () => {
- it('should commit TOGGLE_COLLAPSIBLE_LINE mutation', () => {
- return testAction(
- toggleCollapsibleLine,
- { isClosed: true },
- mockedState,
- [{ type: types.TOGGLE_COLLAPSIBLE_LINE, payload: { isClosed: true } }],
- [],
- );
- });
- });
-
- describe('requestJobsForStage', () => {
- it('should commit REQUEST_JOBS_FOR_STAGE mutation', () => {
- return testAction(
- requestJobsForStage,
- { name: 'deploy' },
- mockedState,
- [{ type: types.REQUEST_JOBS_FOR_STAGE, payload: { name: 'deploy' } }],
- [],
- );
- });
- });
-
- describe('fetchJobsForStage', () => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('success', () => {
- it('dispatches requestJobsForStage and receiveJobsForStageSuccess', () => {
- mock.onGet(`${TEST_HOST}/jobs.json`).replyOnce(HTTP_STATUS_OK, {
- latest_statuses: [{ id: 121212, name: 'build' }],
- retried: [],
- });
-
- return testAction(
- fetchJobsForStage,
- { dropdown_path: `${TEST_HOST}/jobs.json` },
- mockedState,
- [],
- [
- {
- type: 'requestJobsForStage',
- payload: { dropdown_path: `${TEST_HOST}/jobs.json` },
- },
- {
- payload: [{ id: 121212, name: 'build' }],
- type: 'receiveJobsForStageSuccess',
- },
- ],
- );
- });
- });
-
- describe('error', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/jobs.json`).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
- });
-
- it('dispatches requestJobsForStage and receiveJobsForStageError', () => {
- return testAction(
- fetchJobsForStage,
- { dropdown_path: `${TEST_HOST}/jobs.json` },
- mockedState,
- [],
- [
- {
- type: 'requestJobsForStage',
- payload: { dropdown_path: `${TEST_HOST}/jobs.json` },
- },
- {
- type: 'receiveJobsForStageError',
- },
- ],
- );
- });
- });
- });
-
- describe('receiveJobsForStageSuccess', () => {
- it('should commit RECEIVE_JOBS_FOR_STAGE_SUCCESS mutation', () => {
- return testAction(
- receiveJobsForStageSuccess,
- [{ id: 121212, name: 'karma' }],
- mockedState,
- [{ type: types.RECEIVE_JOBS_FOR_STAGE_SUCCESS, payload: [{ id: 121212, name: 'karma' }] }],
- [],
- );
- });
- });
-
- describe('receiveJobsForStageError', () => {
- it('should commit RECEIVE_JOBS_FOR_STAGE_ERROR mutation', () => {
- return testAction(
- receiveJobsForStageError,
- null,
- mockedState,
- [{ type: types.RECEIVE_JOBS_FOR_STAGE_ERROR }],
- [],
- );
- });
- });
-});
diff --git a/spec/frontend/jobs/store/getters_spec.js b/spec/frontend/jobs/store/getters_spec.js
deleted file mode 100644
index c13b051c672..00000000000
--- a/spec/frontend/jobs/store/getters_spec.js
+++ /dev/null
@@ -1,245 +0,0 @@
-import * as getters from '~/jobs/store/getters';
-import state from '~/jobs/store/state';
-
-describe('Job Store Getters', () => {
- let localState;
-
- beforeEach(() => {
- localState = state();
- });
-
- describe('headerTime', () => {
- describe('when the job has started key', () => {
- it('returns started_at value', () => {
- const started = '2018-08-31T16:20:49.023Z';
- const startedAt = '2018-08-31T16:20:49.023Z';
- localState.job.started_at = startedAt;
- localState.job.started = started;
-
- expect(getters.headerTime(localState)).toEqual(startedAt);
- });
- });
-
- describe('when the job does not have started key', () => {
- it('returns created_at value', () => {
- const created = '2018-08-31T16:20:49.023Z';
- localState.job.created_at = created;
-
- expect(getters.headerTime(localState)).toEqual(created);
- });
- });
- });
-
- describe('shouldRenderCalloutMessage', () => {
- describe('with status and callout message', () => {
- it('returns true', () => {
- localState.job.callout_message = 'Callout message';
- localState.job.status = { icon: 'passed' };
-
- expect(getters.shouldRenderCalloutMessage(localState)).toEqual(true);
- });
- });
-
- describe('without status & with callout message', () => {
- it('returns false', () => {
- localState.job.callout_message = 'Callout message';
-
- expect(getters.shouldRenderCalloutMessage(localState)).toEqual(false);
- });
- });
-
- describe('with status & without callout message', () => {
- it('returns false', () => {
- localState.job.status = { icon: 'passed' };
-
- expect(getters.shouldRenderCalloutMessage(localState)).toEqual(false);
- });
- });
- });
-
- describe('shouldRenderTriggeredLabel', () => {
- describe('when started equals null', () => {
- it('returns false', () => {
- localState.job.started_at = null;
-
- expect(getters.shouldRenderTriggeredLabel(localState)).toEqual(false);
- });
- });
-
- describe('when started equals string', () => {
- it('returns true', () => {
- localState.job.started_at = '2018-08-31T16:20:49.023Z';
-
- expect(getters.shouldRenderTriggeredLabel(localState)).toEqual(true);
- });
- });
- });
-
- describe('hasEnvironment', () => {
- describe('without `deployment_status`', () => {
- it('returns false', () => {
- expect(getters.hasEnvironment(localState)).toEqual(false);
- });
- });
-
- describe('with an empty object for `deployment_status`', () => {
- it('returns false', () => {
- localState.job.deployment_status = {};
-
- expect(getters.hasEnvironment(localState)).toEqual(false);
- });
- });
-
- describe('when `deployment_status` is defined and not empty', () => {
- it('returns true', () => {
- localState.job.deployment_status = {
- status: 'creating',
- environment: {
- last_deployment: {},
- },
- };
-
- expect(getters.hasEnvironment(localState)).toEqual(true);
- });
- });
- });
-
- describe('hasJobLog', () => {
- describe('when has_trace is true', () => {
- it('returns true', () => {
- localState.job.has_trace = true;
- localState.job.status = {};
-
- expect(getters.hasJobLog(localState)).toEqual(true);
- });
- });
-
- describe('when job is running', () => {
- it('returns true', () => {
- localState.job.has_trace = false;
- localState.job.status = { group: 'running' };
-
- expect(getters.hasJobLog(localState)).toEqual(true);
- });
- });
-
- describe('when has_trace is false and job is not running', () => {
- it('returns false', () => {
- localState.job.has_trace = false;
- localState.job.status = { group: 'pending' };
-
- expect(getters.hasJobLog(localState)).toEqual(false);
- });
- });
- });
-
- describe('emptyStateIllustration', () => {
- describe('with defined illustration', () => {
- it('returns the state illustration object', () => {
- localState.job.status = {
- illustration: {
- path: 'foo',
- },
- };
-
- expect(getters.emptyStateIllustration(localState)).toEqual({ path: 'foo' });
- });
- });
-
- describe('when illustration is not defined', () => {
- it('returns an empty object', () => {
- expect(getters.emptyStateIllustration(localState)).toEqual({});
- });
- });
- });
-
- describe('shouldRenderSharedRunnerLimitWarning', () => {
- describe('without runners information', () => {
- it('returns false', () => {
- expect(getters.shouldRenderSharedRunnerLimitWarning(localState)).toEqual(false);
- });
- });
-
- describe('with runners information', () => {
- describe('when used quota is less than limit', () => {
- it('returns false', () => {
- localState.job.runners = {
- quota: {
- used: 33,
- limit: 2000,
- },
- available: true,
- online: true,
- };
-
- expect(getters.shouldRenderSharedRunnerLimitWarning(localState)).toEqual(false);
- });
- });
-
- describe('when used quota is equal to limit', () => {
- it('returns true', () => {
- localState.job.runners = {
- quota: {
- used: 2000,
- limit: 2000,
- },
- available: true,
- online: true,
- };
-
- expect(getters.shouldRenderSharedRunnerLimitWarning(localState)).toEqual(true);
- });
- });
-
- describe('when used quota is bigger than limit', () => {
- it('returns true', () => {
- localState.job.runners = {
- quota: {
- used: 2002,
- limit: 2000,
- },
- available: true,
- online: true,
- };
-
- expect(getters.shouldRenderSharedRunnerLimitWarning(localState)).toEqual(true);
- });
- });
- });
- });
-
- describe('hasOfflineRunnersForProject', () => {
- describe('with available and offline runners', () => {
- it('returns true', () => {
- localState.job.runners = {
- available: true,
- online: false,
- };
-
- expect(getters.hasOfflineRunnersForProject(localState)).toEqual(true);
- });
- });
-
- describe('with non available runners', () => {
- it('returns false', () => {
- localState.job.runners = {
- available: false,
- online: false,
- };
-
- expect(getters.hasOfflineRunnersForProject(localState)).toEqual(false);
- });
- });
-
- describe('with online runners', () => {
- it('returns false', () => {
- localState.job.runners = {
- available: false,
- online: true,
- };
-
- expect(getters.hasOfflineRunnersForProject(localState)).toEqual(false);
- });
- });
- });
-});
diff --git a/spec/frontend/jobs/store/helpers.js b/spec/frontend/jobs/store/helpers.js
deleted file mode 100644
index 402ae58971a..00000000000
--- a/spec/frontend/jobs/store/helpers.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import state from '~/jobs/store/state';
-
-export const resetStore = (store) => {
- store.replaceState(state());
-};
diff --git a/spec/frontend/jobs/store/mutations_spec.js b/spec/frontend/jobs/store/mutations_spec.js
deleted file mode 100644
index 89cda3b0544..00000000000
--- a/spec/frontend/jobs/store/mutations_spec.js
+++ /dev/null
@@ -1,269 +0,0 @@
-import * as types from '~/jobs/store/mutation_types';
-import mutations from '~/jobs/store/mutations';
-import state from '~/jobs/store/state';
-
-describe('Jobs Store Mutations', () => {
- let stateCopy;
-
- const html =
- 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- : Writing /builds/ab89e95b0fa0b9272ea0c797b76908f24d36992630e9325273a4ce3.png<br>I';
-
- beforeEach(() => {
- stateCopy = state();
- });
-
- describe('SET_JOB_ENDPOINT', () => {
- it('should set jobEndpoint', () => {
- mutations[types.SET_JOB_ENDPOINT](stateCopy, 'job/21312321.json');
-
- expect(stateCopy.jobEndpoint).toEqual('job/21312321.json');
- });
- });
-
- describe('HIDE_SIDEBAR', () => {
- it('should set isSidebarOpen to false', () => {
- mutations[types.HIDE_SIDEBAR](stateCopy);
-
- expect(stateCopy.isSidebarOpen).toEqual(false);
- });
- });
-
- describe('SHOW_SIDEBAR', () => {
- it('should set isSidebarOpen to true', () => {
- mutations[types.SHOW_SIDEBAR](stateCopy);
-
- expect(stateCopy.isSidebarOpen).toEqual(true);
- });
- });
-
- describe('RECEIVE_JOB_LOG_SUCCESS', () => {
- describe('when job log has state', () => {
- it('sets jobLogState', () => {
- const stateLog =
- 'eyJvZmZzZXQiOjczNDQ1MSwibl9vcGVuX3RhZ3MiOjAsImZnX2NvbG9yIjpudWxsLCJiZ19jb2xvciI6bnVsbCwic3R5bGVfbWFzayI6MH0=';
- mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
- state: stateLog,
- });
-
- expect(stateCopy.jobLogState).toEqual(stateLog);
- });
- });
-
- describe('when jobLogSize is smaller than the total size', () => {
- it('sets isJobLogSizeVisible to true', () => {
- mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, { total: 51184600, size: 1231 });
-
- expect(stateCopy.isJobLogSizeVisible).toEqual(true);
- });
- });
-
- describe('when jobLogSize is bigger than the total size', () => {
- it('sets isJobLogSizeVisible to false', () => {
- const copy = { ...stateCopy, jobLogSize: 5118460, size: 2321312 };
-
- mutations[types.RECEIVE_JOB_LOG_SUCCESS](copy, { total: 511846 });
-
- expect(copy.isJobLogSizeVisible).toEqual(false);
- });
- });
-
- it('sets job log size and isJobLogComplete', () => {
- mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
- append: true,
- html,
- size: 511846,
- complete: true,
- lines: [],
- });
-
- expect(stateCopy.jobLogSize).toEqual(511846);
- expect(stateCopy.isJobLogComplete).toEqual(true);
- });
-
- describe('with new job log', () => {
- describe('log.lines', () => {
- describe('when append is true', () => {
- it('sets the parsed log', () => {
- mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
- append: true,
- size: 511846,
- complete: true,
- lines: [
- {
- offset: 1,
- content: [{ text: 'Running with gitlab-runner 11.12.1 (5a147c92)' }],
- },
- ],
- });
-
- expect(stateCopy.jobLog).toEqual([
- {
- offset: 1,
- content: [{ text: 'Running with gitlab-runner 11.12.1 (5a147c92)' }],
- lineNumber: 0,
- },
- ]);
- });
- });
-
- describe('when it is defined', () => {
- it('sets the parsed log', () => {
- mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
- append: false,
- size: 511846,
- complete: true,
- lines: [
- { offset: 0, content: [{ text: 'Running with gitlab-runner 11.11.1 (5a147c92)' }] },
- ],
- });
-
- expect(stateCopy.jobLog).toEqual([
- {
- offset: 0,
- content: [{ text: 'Running with gitlab-runner 11.11.1 (5a147c92)' }],
- lineNumber: 0,
- },
- ]);
- });
- });
-
- describe('when it is null', () => {
- it('sets the default value', () => {
- mutations[types.RECEIVE_JOB_LOG_SUCCESS](stateCopy, {
- append: true,
- html,
- size: 511846,
- complete: false,
- lines: null,
- });
-
- expect(stateCopy.jobLog).toEqual([]);
- });
- });
- });
- });
- });
-
- describe('SET_JOB_LOG_TIMEOUT', () => {
- it('sets the jobLogTimeout id', () => {
- const id = 7;
-
- expect(stateCopy.jobLogTimeout).not.toEqual(id);
-
- mutations[types.SET_JOB_LOG_TIMEOUT](stateCopy, id);
-
- expect(stateCopy.jobLogTimeout).toEqual(id);
- });
- });
-
- describe('STOP_POLLING_JOB_LOG', () => {
- it('sets isJobLogComplete to true', () => {
- mutations[types.STOP_POLLING_JOB_LOG](stateCopy);
-
- expect(stateCopy.isJobLogComplete).toEqual(true);
- });
- });
-
- describe('TOGGLE_COLLAPSIBLE_LINE', () => {
- it('toggles the `isClosed` property of the provided object', () => {
- const section = { isClosed: true };
- mutations[types.TOGGLE_COLLAPSIBLE_LINE](stateCopy, section);
- expect(section.isClosed).toEqual(false);
- });
- });
-
- describe('REQUEST_JOB', () => {
- it('sets isLoading to true', () => {
- mutations[types.REQUEST_JOB](stateCopy);
-
- expect(stateCopy.isLoading).toEqual(true);
- });
- });
-
- describe('RECEIVE_JOB_SUCCESS', () => {
- it('sets is loading to false', () => {
- mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321 });
-
- expect(stateCopy.isLoading).toEqual(false);
- });
-
- it('sets hasError to false', () => {
- mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321 });
-
- expect(stateCopy.hasError).toEqual(false);
- });
-
- it('sets job data', () => {
- mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321 });
-
- expect(stateCopy.job).toEqual({ id: 1312321 });
- });
-
- it('sets selectedStage when the selectedStage is empty', () => {
- expect(stateCopy.selectedStage).toEqual('');
- mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321, stage: 'deploy' });
-
- expect(stateCopy.selectedStage).toEqual('deploy');
- });
-
- it('does not set selectedStage when the selectedStage is not More', () => {
- stateCopy.selectedStage = 'notify';
-
- expect(stateCopy.selectedStage).toEqual('notify');
- mutations[types.RECEIVE_JOB_SUCCESS](stateCopy, { id: 1312321, stage: 'deploy' });
-
- expect(stateCopy.selectedStage).toEqual('notify');
- });
- });
-
- describe('RECEIVE_JOB_ERROR', () => {
- it('resets job data', () => {
- mutations[types.RECEIVE_JOB_ERROR](stateCopy);
-
- expect(stateCopy.isLoading).toEqual(false);
- expect(stateCopy.job).toEqual({});
- });
- });
-
- describe('REQUEST_JOBS_FOR_STAGE', () => {
- it('sets isLoadingJobs to true', () => {
- mutations[types.REQUEST_JOBS_FOR_STAGE](stateCopy, { name: 'deploy' });
-
- expect(stateCopy.isLoadingJobs).toEqual(true);
- });
-
- it('sets selectedStage', () => {
- mutations[types.REQUEST_JOBS_FOR_STAGE](stateCopy, { name: 'deploy' });
-
- expect(stateCopy.selectedStage).toEqual('deploy');
- });
- });
-
- describe('RECEIVE_JOBS_FOR_STAGE_SUCCESS', () => {
- beforeEach(() => {
- mutations[types.RECEIVE_JOBS_FOR_STAGE_SUCCESS](stateCopy, [{ name: 'karma' }]);
- });
-
- it('sets isLoadingJobs to false', () => {
- expect(stateCopy.isLoadingJobs).toEqual(false);
- });
-
- it('sets jobs', () => {
- expect(stateCopy.jobs).toEqual([{ name: 'karma' }]);
- });
- });
-
- describe('RECEIVE_JOBS_FOR_STAGE_ERROR', () => {
- beforeEach(() => {
- mutations[types.RECEIVE_JOBS_FOR_STAGE_ERROR](stateCopy);
- });
-
- it('sets isLoadingJobs to false', () => {
- expect(stateCopy.isLoadingJobs).toEqual(false);
- });
-
- it('resets jobs', () => {
- expect(stateCopy.jobs).toEqual([]);
- });
- });
-});
diff --git a/spec/frontend/jobs/store/utils_spec.js b/spec/frontend/jobs/store/utils_spec.js
deleted file mode 100644
index 37a6722c555..00000000000
--- a/spec/frontend/jobs/store/utils_spec.js
+++ /dev/null
@@ -1,510 +0,0 @@
-import {
- logLinesParser,
- updateIncrementalJobLog,
- parseHeaderLine,
- parseLine,
- addDurationToHeader,
- isCollapsibleSection,
- findOffsetAndRemove,
- getIncrementalLineNumber,
-} from '~/jobs/store/utils';
-import {
- utilsMockData,
- originalTrace,
- regularIncremental,
- regularIncrementalRepeated,
- headerTrace,
- headerTraceIncremental,
- collapsibleTrace,
- collapsibleTraceIncremental,
-} from '../components/log/mock_data';
-
-describe('Jobs Store Utils', () => {
- describe('parseHeaderLine', () => {
- it('returns a new object with the header keys and the provided line parsed', () => {
- const headerLine = { content: [{ text: 'foo' }] };
- const parsedHeaderLine = parseHeaderLine(headerLine, 2);
-
- expect(parsedHeaderLine).toEqual({
- isClosed: false,
- isHeader: true,
- line: {
- ...headerLine,
- lineNumber: 2,
- },
- lines: [],
- });
- });
-
- it('pre-closes a section when specified in options', () => {
- const headerLine = { content: [{ text: 'foo' }], section_options: { collapsed: 'true' } };
-
- const parsedHeaderLine = parseHeaderLine(headerLine, 2);
-
- expect(parsedHeaderLine.isClosed).toBe(true);
- });
-
- it('expands all pre-closed sections if hash is present', () => {
- const headerLine = { content: [{ text: 'foo' }], section_options: { collapsed: 'true' } };
-
- const parsedHeaderLine = parseHeaderLine(headerLine, 2, '#L33');
-
- expect(parsedHeaderLine.isClosed).toBe(false);
- });
- });
-
- describe('parseLine', () => {
- it('returns a new object with the lineNumber key added to the provided line object', () => {
- const line = { content: [{ text: 'foo' }] };
- const parsed = parseLine(line, 1);
- expect(parsed.content).toEqual(line.content);
- expect(parsed.lineNumber).toEqual(1);
- });
- });
-
- describe('addDurationToHeader', () => {
- const duration = {
- offset: 106,
- content: [],
- section: 'prepare-script',
- section_duration: '00:03',
- };
-
- it('adds the section duration to the correct header', () => {
- const parsed = [
- {
- isClosed: false,
- isHeader: true,
- line: {
- section: 'prepare-script',
- content: [{ text: 'foo' }],
- },
- lines: [],
- },
- {
- isClosed: false,
- isHeader: true,
- line: {
- section: 'foo-bar',
- content: [{ text: 'foo' }],
- },
- lines: [],
- },
- ];
-
- addDurationToHeader(parsed, duration);
-
- expect(parsed[0].line.section_duration).toEqual(duration.section_duration);
- expect(parsed[1].line.section_duration).toEqual(undefined);
- });
-
- it('does not add the section duration when the headers do not match', () => {
- const parsed = [
- {
- isClosed: false,
- isHeader: true,
- line: {
- section: 'bar-foo',
- content: [{ text: 'foo' }],
- },
- lines: [],
- },
- {
- isClosed: false,
- isHeader: true,
- line: {
- section: 'foo-bar',
- content: [{ text: 'foo' }],
- },
- lines: [],
- },
- ];
- addDurationToHeader(parsed, duration);
-
- expect(parsed[0].line.section_duration).toEqual(undefined);
- expect(parsed[1].line.section_duration).toEqual(undefined);
- });
-
- it('does not add when content has no headers', () => {
- const parsed = [
- {
- section: 'bar-foo',
- content: [{ text: 'foo' }],
- lineNumber: 1,
- },
- {
- section: 'foo-bar',
- content: [{ text: 'foo' }],
- lineNumber: 2,
- },
- ];
-
- addDurationToHeader(parsed, duration);
-
- expect(parsed[0].line).toEqual(undefined);
- expect(parsed[1].line).toEqual(undefined);
- });
- });
-
- describe('isCollapsibleSection', () => {
- const header = {
- isHeader: true,
- line: {
- section: 'foo',
- },
- };
- const line = {
- lineNumber: 1,
- section: 'foo',
- content: [],
- };
-
- it('returns true when line belongs to the last section', () => {
- expect(isCollapsibleSection([header], header, { section: 'foo', content: [] })).toEqual(true);
- });
-
- it('returns false when last line was not an header', () => {
- expect(isCollapsibleSection([line], line, { section: 'bar' })).toEqual(false);
- });
-
- it('returns false when accumulator is empty', () => {
- expect(isCollapsibleSection([], { isHeader: true }, { section: 'bar' })).toEqual(false);
- });
-
- it('returns false when section_duration is defined', () => {
- expect(isCollapsibleSection([header], header, { section_duration: '10:00' })).toEqual(false);
- });
-
- it('returns false when `section` is not a match', () => {
- expect(isCollapsibleSection([header], header, { section: 'bar' })).toEqual(false);
- });
-
- it('returns false when no parameters are provided', () => {
- expect(isCollapsibleSection()).toEqual(false);
- });
- });
- describe('logLinesParser', () => {
- let result;
-
- beforeEach(() => {
- result = logLinesParser(utilsMockData);
- });
-
- describe('regular line', () => {
- it('adds a lineNumber property with correct index', () => {
- expect(result[0].lineNumber).toEqual(0);
- expect(result[1].line.lineNumber).toEqual(1);
- });
- });
-
- describe('collapsible section', () => {
- it('adds a `isClosed` property', () => {
- expect(result[1].isClosed).toEqual(false);
- });
-
- it('adds a `isHeader` property', () => {
- expect(result[1].isHeader).toEqual(true);
- });
-
- it('creates a lines array property with the content of the collapsible section', () => {
- expect(result[1].lines.length).toEqual(2);
- expect(result[1].lines[0].content).toEqual(utilsMockData[2].content);
- expect(result[1].lines[1].content).toEqual(utilsMockData[3].content);
- });
- });
-
- describe('section duration', () => {
- it('adds the section information to the header section', () => {
- expect(result[1].line.section_duration).toEqual(utilsMockData[4].section_duration);
- });
-
- it('does not add section duration as a line', () => {
- expect(result[1].lines.includes(utilsMockData[4])).toEqual(false);
- });
- });
- });
-
- describe('findOffsetAndRemove', () => {
- describe('when last item is header', () => {
- const existingLog = [
- {
- isHeader: true,
- isClosed: false,
- line: { content: [{ text: 'bar' }], offset: 10, lineNumber: 1 },
- },
- ];
-
- describe('and matches the offset', () => {
- it('returns an array with the item removed', () => {
- const newData = [{ offset: 10, content: [{ text: 'foobar' }] }];
- const result = findOffsetAndRemove(newData, existingLog);
-
- expect(result).toEqual([]);
- });
- });
-
- describe('and does not match the offset', () => {
- it('returns the provided existing log', () => {
- const newData = [{ offset: 110, content: [{ text: 'foobar' }] }];
- const result = findOffsetAndRemove(newData, existingLog);
-
- expect(result).toEqual(existingLog);
- });
- });
- });
-
- describe('when last item is a regular line', () => {
- const existingLog = [{ content: [{ text: 'bar' }], offset: 10, lineNumber: 1 }];
-
- describe('and matches the offset', () => {
- it('returns an array with the item removed', () => {
- const newData = [{ offset: 10, content: [{ text: 'foobar' }] }];
- const result = findOffsetAndRemove(newData, existingLog);
-
- expect(result).toEqual([]);
- });
- });
-
- describe('and does not match the fofset', () => {
- it('returns the provided old log', () => {
- const newData = [{ offset: 101, content: [{ text: 'foobar' }] }];
- const result = findOffsetAndRemove(newData, existingLog);
-
- expect(result).toEqual(existingLog);
- });
- });
- });
-
- describe('when last item is nested', () => {
- const existingLog = [
- {
- isHeader: true,
- isClosed: false,
- lines: [{ offset: 101, content: [{ text: 'foobar' }], lineNumber: 2 }],
- line: {
- offset: 10,
- lineNumber: 1,
- section_duration: '10:00',
- },
- },
- ];
-
- describe('and matches the offset', () => {
- it('returns an array with the last nested line item removed', () => {
- const newData = [{ offset: 101, content: [{ text: 'foobar' }] }];
-
- const result = findOffsetAndRemove(newData, existingLog);
- expect(result[0].lines).toEqual([]);
- });
- });
-
- describe('and does not match the offset', () => {
- it('returns the provided old log', () => {
- const newData = [{ offset: 120, content: [{ text: 'foobar' }] }];
-
- const result = findOffsetAndRemove(newData, existingLog);
- expect(result).toEqual(existingLog);
- });
- });
- });
-
- describe('when no data is provided', () => {
- it('returns an empty array', () => {
- const result = findOffsetAndRemove();
- expect(result).toEqual([]);
- });
- });
- });
-
- describe('getIncrementalLineNumber', () => {
- describe('when last line is 0', () => {
- it('returns 1', () => {
- const log = [
- {
- content: [],
- lineNumber: 0,
- },
- ];
-
- expect(getIncrementalLineNumber(log)).toEqual(1);
- });
- });
-
- describe('with unnested line', () => {
- it('returns the lineNumber of the last item in the array', () => {
- const log = [
- {
- content: [],
- lineNumber: 10,
- },
- {
- content: [],
- lineNumber: 101,
- },
- ];
-
- expect(getIncrementalLineNumber(log)).toEqual(102);
- });
- });
-
- describe('when last line is the header section', () => {
- it('returns the lineNumber of the last item in the array', () => {
- const log = [
- {
- content: [],
- lineNumber: 10,
- },
- {
- isHeader: true,
- line: {
- lineNumber: 101,
- content: [],
- },
- lines: [],
- },
- ];
-
- expect(getIncrementalLineNumber(log)).toEqual(102);
- });
- });
-
- describe('when last line is a nested line', () => {
- it('returns the lineNumber of the last item in the nested array', () => {
- const log = [
- {
- content: [],
- lineNumber: 10,
- },
- {
- isHeader: true,
- line: {
- lineNumber: 101,
- content: [],
- },
- lines: [
- {
- lineNumber: 102,
- content: [],
- },
- { lineNumber: 103, content: [] },
- ],
- },
- ];
-
- expect(getIncrementalLineNumber(log)).toEqual(104);
- });
- });
- });
-
- describe('updateIncrementalJobLog', () => {
- describe('without repeated section', () => {
- it('concats and parses both arrays', () => {
- const oldLog = logLinesParser(originalTrace);
- const result = updateIncrementalJobLog(regularIncremental, oldLog);
-
- expect(result).toEqual([
- {
- offset: 1,
- content: [
- {
- text: 'Downloading',
- },
- ],
- lineNumber: 0,
- },
- {
- offset: 2,
- content: [
- {
- text: 'log line',
- },
- ],
- lineNumber: 1,
- },
- ]);
- });
- });
-
- describe('with regular line repeated offset', () => {
- it('updates the last line and formats with the incremental part', () => {
- const oldLog = logLinesParser(originalTrace);
- const result = updateIncrementalJobLog(regularIncrementalRepeated, oldLog);
-
- expect(result).toEqual([
- {
- offset: 1,
- content: [
- {
- text: 'log line',
- },
- ],
- lineNumber: 0,
- },
- ]);
- });
- });
-
- describe('with header line repeated', () => {
- it('updates the header line and formats with the incremental part', () => {
- const oldLog = logLinesParser(headerTrace);
- const result = updateIncrementalJobLog(headerTraceIncremental, oldLog);
-
- expect(result).toEqual([
- {
- isClosed: false,
- isHeader: true,
- line: {
- offset: 1,
- section_header: true,
- content: [
- {
- text: 'updated log line',
- },
- ],
- section: 'section',
- lineNumber: 0,
- },
- lines: [],
- },
- ]);
- });
- });
-
- describe('with collapsible line repeated', () => {
- it('updates the collapsible line and formats with the incremental part', () => {
- const oldLog = logLinesParser(collapsibleTrace);
- const result = updateIncrementalJobLog(collapsibleTraceIncremental, oldLog);
-
- expect(result).toEqual([
- {
- isClosed: false,
- isHeader: true,
- line: {
- offset: 1,
- section_header: true,
- content: [
- {
- text: 'log line',
- },
- ],
- section: 'section',
- lineNumber: 0,
- },
- lines: [
- {
- offset: 2,
- content: [
- {
- text: 'updated log line',
- },
- ],
- section: 'section',
- lineNumber: 1,
- },
- ],
- },
- ]);
- });
- });
- });
-});
diff --git a/spec/frontend/lib/utils/array_utility_spec.js b/spec/frontend/lib/utils/array_utility_spec.js
index 64ddd400114..94461c72106 100644
--- a/spec/frontend/lib/utils/array_utility_spec.js
+++ b/spec/frontend/lib/utils/array_utility_spec.js
@@ -42,4 +42,40 @@ describe('array_utility', () => {
expect(arrayUtils.getDuplicateItemsFromArray(array)).toEqual(result);
});
});
+
+ describe('toggleArrayItem', () => {
+ it('adds an item to the array if it does not exist', () => {
+ expect(arrayUtils.toggleArrayItem([], 'item')).toStrictEqual(['item']);
+ });
+
+ it('removes an item from the array if it already exists', () => {
+ expect(arrayUtils.toggleArrayItem(['item'], 'item')).toStrictEqual([]);
+ });
+
+ describe('pass by value', () => {
+ it('does not toggle the array item when passed a new object', () => {
+ expect(arrayUtils.toggleArrayItem([{ a: 1 }], { a: 1 })).toStrictEqual([
+ { a: 1 },
+ { a: 1 },
+ ]);
+ });
+
+ it('does not toggle the array item when passed a new array', () => {
+ expect(arrayUtils.toggleArrayItem([[1]], [1])).toStrictEqual([[1], [1]]);
+ });
+ });
+
+ describe('pass by reference', () => {
+ const array = [1];
+ const object = { a: 1 };
+
+ it('toggles the array item when passed a object reference', () => {
+ expect(arrayUtils.toggleArrayItem([object], object)).toStrictEqual([]);
+ });
+
+ it('toggles the array item when passed an array reference', () => {
+ expect(arrayUtils.toggleArrayItem([array], array)).toStrictEqual([]);
+ });
+ });
+ });
});
diff --git a/spec/frontend/lib/utils/breadcrumbs_spec.js b/spec/frontend/lib/utils/breadcrumbs_spec.js
new file mode 100644
index 00000000000..3c29e3723d3
--- /dev/null
+++ b/spec/frontend/lib/utils/breadcrumbs_spec.js
@@ -0,0 +1,84 @@
+import { createWrapper } from '@vue/test-utils';
+import Vue from 'vue';
+import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs';
+import { resetHTMLFixture, setHTMLFixture } from 'helpers/fixtures';
+import createMockApollo from 'helpers/mock_apollo_helper';
+
+describe('Breadcrumbs utils', () => {
+ const breadcrumbsHTML = `
+ <nav>
+ <ul class="js-breadcrumbs-list">
+ <li>
+ <a href="/group-name" data-testid="existing-crumb">Group name</a>
+ </li>
+ <li>
+ <a href="/group-name/project-name/-/subpage" data-testid="last-crumb">Subpage</a>
+ </li>
+ </ul>
+ </nav>
+ `;
+
+ const emptyBreadcrumbsHTML = `
+ <nav>
+ <ul class="js-breadcrumbs-list" data-testid="breadcumbs-list">
+ </ul>
+ </nav>
+ `;
+
+ const mockRouter = jest.fn();
+ let MockComponent;
+ let mockApolloProvider;
+
+ beforeEach(() => {
+ MockComponent = Vue.component('MockComponent', {
+ render: (createElement) =>
+ createElement('span', {
+ attrs: {
+ 'data-testid': 'mock-component',
+ },
+ }),
+ });
+ mockApolloProvider = createMockApollo();
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ MockComponent = null;
+ });
+
+ describe('injectVueAppBreadcrumbs', () => {
+ describe('without any breadcrumbs', () => {
+ beforeEach(() => {
+ setHTMLFixture(emptyBreadcrumbsHTML);
+ });
+
+ it('returns early and stops trying to inject', () => {
+ expect(injectVueAppBreadcrumbs(mockRouter, MockComponent)).toBe(false);
+ });
+ });
+
+ describe('with breadcrumbs', () => {
+ beforeEach(() => {
+ setHTMLFixture(breadcrumbsHTML);
+ });
+
+ describe.each`
+ testLabel | apolloProvider
+ ${'set'} | ${mockApolloProvider}
+ ${'not set'} | ${null}
+ `('given the apollo provider is $testLabel', ({ apolloProvider }) => {
+ beforeEach(() => {
+ createWrapper(injectVueAppBreadcrumbs(mockRouter, MockComponent, apolloProvider));
+ });
+
+ it('returns a new breadcrumbs component replacing the inject HTML', () => {
+ // Using `querySelectorAll` because we're not testing a full Vue app.
+ // We are testing a partial Vue app added into the pages HTML.
+ expect(document.querySelectorAll('[data-testid="existing-crumb"]')).toHaveLength(1);
+ expect(document.querySelectorAll('[data-testid="last-crumb"]')).toHaveLength(0);
+ expect(document.querySelectorAll('[data-testid="mock-component"]')).toHaveLength(1);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/common_utils_spec.js b/spec/frontend/lib/utils/common_utils_spec.js
index 444d4a96f9c..8697249ebf5 100644
--- a/spec/frontend/lib/utils/common_utils_spec.js
+++ b/spec/frontend/lib/utils/common_utils_spec.js
@@ -1174,4 +1174,43 @@ describe('common_utils', () => {
});
});
});
+
+ describe('cloneWithoutReferences', () => {
+ it('clones the provided object', () => {
+ const obj = {
+ foo: 'bar',
+ cool: 1337,
+ nested: {
+ peanut: 'butter',
+ },
+ arrays: [0, 1, 2],
+ };
+
+ const cloned = commonUtils.cloneWithoutReferences(obj);
+
+ expect(cloned).toMatchObject({
+ foo: 'bar',
+ cool: 1337,
+ nested: {
+ peanut: 'butter',
+ },
+ arrays: [0, 1, 2],
+ });
+ });
+
+ it('does not persist object references after cloning', () => {
+ const ref = {
+ foo: 'bar',
+ };
+
+ const obj = {
+ ref,
+ };
+
+ const cloned = commonUtils.cloneWithoutReferences(obj);
+
+ expect(cloned.ref).toMatchObject({ foo: 'bar' });
+ expect(cloned.ref === ref).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/lib/utils/datetime_range_spec.js b/spec/frontend/lib/utils/datetime_range_spec.js
deleted file mode 100644
index 996a8e2e47b..00000000000
--- a/spec/frontend/lib/utils/datetime_range_spec.js
+++ /dev/null
@@ -1,382 +0,0 @@
-import _ from 'lodash';
-import {
- getRangeType,
- convertToFixedRange,
- isEqualTimeRanges,
- findTimeRange,
- timeRangeToParams,
- timeRangeFromParams,
-} from '~/lib/utils/datetime_range';
-
-const MOCK_NOW = Date.UTC(2020, 0, 23, 20);
-
-const MOCK_NOW_ISO_STRING = new Date(MOCK_NOW).toISOString();
-
-const mockFixedRange = {
- label: 'January 2020',
- start: '2020-01-01T00:00:00.000Z',
- end: '2020-01-31T23:59:00.000Z',
-};
-
-const mockAnchoredRange = {
- label: 'First two minutes of 2020',
- anchor: '2020-01-01T00:00:00.000Z',
- direction: 'after',
- duration: {
- seconds: 60 * 2,
- },
-};
-
-const mockRollingRange = {
- label: 'Next 2 minutes',
- direction: 'after',
- duration: {
- seconds: 60 * 2,
- },
-};
-
-const mockOpenRange = {
- label: '2020 so far',
- anchor: '2020-01-01T00:00:00.000Z',
- direction: 'after',
-};
-
-describe('Date time range utils', () => {
- describe('getRangeType', () => {
- it('infers correctly the range type from the input object', () => {
- const rangeTypes = {
- fixed: [{ start: MOCK_NOW_ISO_STRING, end: MOCK_NOW_ISO_STRING }],
- anchored: [{ anchor: MOCK_NOW_ISO_STRING, duration: { seconds: 0 } }],
- rolling: [{ duration: { seconds: 0 } }],
- open: [{ anchor: MOCK_NOW_ISO_STRING }],
- invalid: [
- {},
- { start: MOCK_NOW_ISO_STRING },
- { end: MOCK_NOW_ISO_STRING },
- { start: 'NOT_A_DATE', end: 'NOT_A_DATE' },
- { duration: { seconds: 'NOT_A_NUMBER' } },
- { duration: { seconds: Infinity } },
- { duration: { minutes: 20 } },
- { anchor: MOCK_NOW_ISO_STRING, duration: { seconds: 'NOT_A_NUMBER' } },
- { anchor: MOCK_NOW_ISO_STRING, duration: { seconds: Infinity } },
- { junk: 'exists' },
- ],
- };
-
- Object.entries(rangeTypes).forEach(([type, examples]) => {
- examples.forEach((example) => expect(getRangeType(example)).toEqual(type));
- });
- });
- });
-
- describe('convertToFixedRange', () => {
- beforeEach(() => {
- jest.spyOn(Date, 'now').mockImplementation(() => MOCK_NOW);
- });
-
- afterEach(() => {
- Date.now.mockRestore();
- });
-
- describe('When a fixed range is input', () => {
- it('converts a fixed range to an equal fixed range', () => {
- expect(convertToFixedRange(mockFixedRange)).toEqual({
- start: mockFixedRange.start,
- end: mockFixedRange.end,
- });
- });
-
- it('throws an error when fixed range does not contain an end time', () => {
- const aFixedRangeMissingEnd = _.omit(mockFixedRange, 'end');
-
- expect(() => convertToFixedRange(aFixedRangeMissingEnd)).toThrow();
- });
-
- it('throws an error when fixed range does not contain a start time', () => {
- const aFixedRangeMissingStart = _.omit(mockFixedRange, 'start');
-
- expect(() => convertToFixedRange(aFixedRangeMissingStart)).toThrow();
- });
-
- it('throws an error when the dates cannot be parsed', () => {
- const wrongStart = { ...mockFixedRange, start: 'I_CANNOT_BE_PARSED' };
- const wrongEnd = { ...mockFixedRange, end: 'I_CANNOT_BE_PARSED' };
-
- expect(() => convertToFixedRange(wrongStart)).toThrow();
- expect(() => convertToFixedRange(wrongEnd)).toThrow();
- });
- });
-
- describe('When an anchored range is input', () => {
- it('converts to a fixed range', () => {
- expect(convertToFixedRange(mockAnchoredRange)).toEqual({
- start: '2020-01-01T00:00:00.000Z',
- end: '2020-01-01T00:02:00.000Z',
- });
- });
-
- it('converts to a fixed range with a `before` direction', () => {
- expect(convertToFixedRange({ ...mockAnchoredRange, direction: 'before' })).toEqual({
- start: '2019-12-31T23:58:00.000Z',
- end: '2020-01-01T00:00:00.000Z',
- });
- });
-
- it('converts to a fixed range without an explicit direction, defaulting to `before`', () => {
- const defaultDirectionRange = _.omit(mockAnchoredRange, 'direction');
-
- expect(convertToFixedRange(defaultDirectionRange)).toEqual({
- start: '2019-12-31T23:58:00.000Z',
- end: '2020-01-01T00:00:00.000Z',
- });
- });
-
- it('throws an error when the anchor cannot be parsed', () => {
- const wrongAnchor = { ...mockAnchoredRange, anchor: 'I_CANNOT_BE_PARSED' };
-
- expect(() => convertToFixedRange(wrongAnchor)).toThrow();
- });
- });
-
- describe('when a rolling range is input', () => {
- it('converts to a fixed range', () => {
- expect(convertToFixedRange(mockRollingRange)).toEqual({
- start: '2020-01-23T20:00:00.000Z',
- end: '2020-01-23T20:02:00.000Z',
- });
- });
-
- it('converts to a fixed range with an implicit `before` direction', () => {
- const noDirection = _.omit(mockRollingRange, 'direction');
-
- expect(convertToFixedRange(noDirection)).toEqual({
- start: '2020-01-23T19:58:00.000Z',
- end: '2020-01-23T20:00:00.000Z',
- });
- });
-
- it('throws an error when the duration is not in the right format', () => {
- const wrongDuration = { ...mockRollingRange, duration: { minutes: 20 } };
-
- expect(() => convertToFixedRange(wrongDuration)).toThrow();
- });
-
- it('throws an error when the anchor is not valid', () => {
- const wrongAnchor = { ...mockRollingRange, anchor: 'CAN_T_PARSE_THIS' };
-
- expect(() => convertToFixedRange(wrongAnchor)).toThrow();
- });
- });
-
- describe('when an open range is input', () => {
- it('converts to a fixed range with an `after` direction', () => {
- expect(convertToFixedRange(mockOpenRange)).toEqual({
- start: '2020-01-01T00:00:00.000Z',
- end: '2020-01-23T20:00:00.000Z',
- });
- });
-
- it('converts to a fixed range with the explicit `before` direction', () => {
- const beforeOpenRange = { ...mockOpenRange, direction: 'before' };
-
- expect(convertToFixedRange(beforeOpenRange)).toEqual({
- start: '1970-01-01T00:00:00.000Z',
- end: '2020-01-01T00:00:00.000Z',
- });
- });
-
- it('converts to a fixed range with the implicit `before` direction', () => {
- const noDirectionOpenRange = _.omit(mockOpenRange, 'direction');
-
- expect(convertToFixedRange(noDirectionOpenRange)).toEqual({
- start: '1970-01-01T00:00:00.000Z',
- end: '2020-01-01T00:00:00.000Z',
- });
- });
-
- it('throws an error when the anchor cannot be parsed', () => {
- const wrongAnchor = { ...mockOpenRange, anchor: 'CAN_T_PARSE_THIS' };
-
- expect(() => convertToFixedRange(wrongAnchor)).toThrow();
- });
- });
- });
-
- describe('isEqualTimeRanges', () => {
- it('equal only compares relevant properies', () => {
- expect(
- isEqualTimeRanges(
- {
- ...mockFixedRange,
- label: 'A label',
- default: true,
- },
- {
- ...mockFixedRange,
- label: 'Another label',
- default: false,
- anotherKey: 'anotherValue',
- },
- ),
- ).toBe(true);
-
- expect(
- isEqualTimeRanges(
- {
- ...mockAnchoredRange,
- label: 'A label',
- default: true,
- },
- {
- ...mockAnchoredRange,
- anotherKey: 'anotherValue',
- },
- ),
- ).toBe(true);
- });
- });
-
- describe('findTimeRange', () => {
- const timeRanges = [
- {
- label: 'Before 2020',
- anchor: '2020-01-01T00:00:00.000Z',
- },
- {
- label: 'Last 30 minutes',
- duration: { seconds: 60 * 30 },
- },
- {
- label: 'In 2019',
- start: '2019-01-01T00:00:00.000Z',
- end: '2019-12-31T12:59:59.999Z',
- },
- {
- label: 'Next 2 minutes',
- direction: 'after',
- duration: {
- seconds: 60 * 2,
- },
- },
- ];
-
- it('finds a time range', () => {
- const tr0 = {
- anchor: '2020-01-01T00:00:00.000Z',
- };
- expect(findTimeRange(tr0, timeRanges)).toBe(timeRanges[0]);
-
- const tr1 = {
- duration: { seconds: 60 * 30 },
- };
- expect(findTimeRange(tr1, timeRanges)).toBe(timeRanges[1]);
-
- const tr1Direction = {
- direction: 'before',
- duration: {
- seconds: 60 * 30,
- },
- };
- expect(findTimeRange(tr1Direction, timeRanges)).toBe(timeRanges[1]);
-
- const tr2 = {
- someOtherLabel: 'Added arbitrarily',
- start: '2019-01-01T00:00:00.000Z',
- end: '2019-12-31T12:59:59.999Z',
- };
- expect(findTimeRange(tr2, timeRanges)).toBe(timeRanges[2]);
-
- const tr3 = {
- direction: 'after',
- duration: {
- seconds: 60 * 2,
- },
- };
- expect(findTimeRange(tr3, timeRanges)).toBe(timeRanges[3]);
- });
-
- it('doesnot finds a missing time range', () => {
- const nonExistant = {
- direction: 'before',
- duration: {
- seconds: 200,
- },
- };
- expect(findTimeRange(nonExistant, timeRanges)).toBeUndefined();
- });
- });
-
- describe('conversion to/from params', () => {
- const mockFixedParams = {
- start: '2020-01-01T00:00:00.000Z',
- end: '2020-01-31T23:59:00.000Z',
- };
-
- const mockAnchoredParams = {
- anchor: '2020-01-01T00:00:00.000Z',
- direction: 'after',
- duration_seconds: '120',
- };
-
- const mockRollingParams = {
- direction: 'after',
- duration_seconds: '120',
- };
-
- describe('timeRangeToParams', () => {
- it('converts fixed ranges to params', () => {
- expect(timeRangeToParams(mockFixedRange)).toEqual(mockFixedParams);
- });
-
- it('converts anchored ranges to params', () => {
- expect(timeRangeToParams(mockAnchoredRange)).toEqual(mockAnchoredParams);
- });
-
- it('converts rolling ranges to params', () => {
- expect(timeRangeToParams(mockRollingRange)).toEqual(mockRollingParams);
- });
- });
-
- describe('timeRangeFromParams', () => {
- it('converts fixed ranges from params', () => {
- const params = { ...mockFixedParams, other_param: 'other_value' };
- const expectedRange = _.omit(mockFixedRange, 'label');
-
- expect(timeRangeFromParams(params)).toEqual(expectedRange);
- });
-
- it('converts anchored ranges to params', () => {
- const expectedRange = _.omit(mockRollingRange, 'label');
-
- expect(timeRangeFromParams(mockRollingParams)).toEqual(expectedRange);
- });
-
- it('converts rolling ranges from params', () => {
- const params = { ...mockRollingParams, other_param: 'other_value' };
- const expectedRange = _.omit(mockRollingRange, 'label');
-
- expect(timeRangeFromParams(params)).toEqual(expectedRange);
- });
-
- it('converts rolling ranges from params with a default direction', () => {
- const params = {
- ...mockRollingParams,
- direction: 'before',
- other_param: 'other_value',
- };
- const expectedRange = _.omit(mockRollingRange, 'label', 'direction');
-
- expect(timeRangeFromParams(params)).toEqual(expectedRange);
- });
-
- it('converts to null when for no relevant params', () => {
- const range = {
- useless_param_1: 'value1',
- useless_param_2: 'value2',
- };
-
- expect(timeRangeFromParams(range)).toBe(null);
- });
- });
- });
-});
diff --git a/spec/frontend/lib/utils/secret_detection_spec.js b/spec/frontend/lib/utils/secret_detection_spec.js
index 3213ecf3fe1..761062f0340 100644
--- a/spec/frontend/lib/utils/secret_detection_spec.js
+++ b/spec/frontend/lib/utils/secret_detection_spec.js
@@ -28,6 +28,7 @@ describe('containsSensitiveToken', () => {
'token: feed_token=ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'token: feed_token=glft-ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'token: feed_token=glft-a8cc74ccb0de004d09a968705ba49099229b288b3de43f26c473a9d8d7fb7693-1234',
+ 'token: gloas-a8cc74ccb0de004d09a968705ba49099229b288b3de43f26c473a9d8d7fb7693',
'https://example.com/feed?feed_token=123456789_abcdefghij',
'glpat-1234567890 and feed_token=ABCDEFGHIJKLMNOPQRSTUVWXYZ',
];
diff --git a/spec/frontend/lib/utils/text_utility_spec.js b/spec/frontend/lib/utils/text_utility_spec.js
index b7d6bbd3991..6821ed56857 100644
--- a/spec/frontend/lib/utils/text_utility_spec.js
+++ b/spec/frontend/lib/utils/text_utility_spec.js
@@ -221,23 +221,6 @@ describe('text_utility', () => {
});
});
- describe('getFirstCharacterCapitalized', () => {
- it('returns the first character capitalized, if first character is alphabetic', () => {
- expect(textUtils.getFirstCharacterCapitalized('loremIpsumDolar')).toEqual('L');
- expect(textUtils.getFirstCharacterCapitalized('Sit amit !')).toEqual('S');
- });
-
- it('returns the first character, if first character is non-alphabetic', () => {
- expect(textUtils.getFirstCharacterCapitalized(' lorem')).toEqual(' ');
- expect(textUtils.getFirstCharacterCapitalized('%#!')).toEqual('%');
- });
-
- it('returns an empty string, if string is falsey', () => {
- expect(textUtils.getFirstCharacterCapitalized('')).toEqual('');
- expect(textUtils.getFirstCharacterCapitalized(null)).toEqual('');
- });
- });
-
describe('slugifyWithUnderscore', () => {
it('should replaces whitespaces with underscore and convert to lower case', () => {
expect(textUtils.slugifyWithUnderscore('My Input String')).toEqual('my_input_string');
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index 450eeefd898..ecd2d7f888d 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -1,11 +1,8 @@
-import * as Sentry from '@sentry/browser';
import setWindowLocation from 'helpers/set_window_location_helper';
import { TEST_HOST } from 'helpers/test_constants';
import * as urlUtils from '~/lib/utils/url_utility';
import { safeUrls, unsafeUrls } from './mock_data';
-jest.mock('@sentry/browser');
-
const shas = {
valid: [
'ad9be38573f9ee4c4daec22673478c2dd1d81cd8',
@@ -434,11 +431,10 @@ describe('URL utility', () => {
it('does not navigate to unsafe urls', () => {
// eslint-disable-next-line no-script-url
const url = 'javascript:alert(document.domain)';
- urlUtils.visitUrl(url);
- expect(Sentry.captureException).toHaveBeenCalledWith(
- new RangeError(`Only http and https protocols are allowed: ${url}`),
- );
+ expect(() => {
+ urlUtils.visitUrl(url);
+ }).toThrow(new RangeError(`Only http and https protocols are allowed: ${url}`));
});
it('navigates to a page', () => {
diff --git a/spec/frontend/members/components/table/__snapshots__/member_activity_spec.js.snap b/spec/frontend/members/components/table/__snapshots__/member_activity_spec.js.snap
index a0d9bae8a0b..3ad02d3851d 100644
--- a/spec/frontend/members/components/table/__snapshots__/member_activity_spec.js.snap
+++ b/spec/frontend/members/components/table/__snapshots__/member_activity_spec.js.snap
@@ -2,21 +2,14 @@
exports[`MemberActivity with a member that does not have all of the fields renders \`User created\` field 1`] = `
<div>
- <!---->
-
<div>
<strong>
Access granted:
</strong>
-
<span>
-
- Aug 06, 2020
-
+ Aug 06, 2020
</span>
</div>
-
- <!---->
</div>
`;
@@ -26,35 +19,24 @@ exports[`MemberActivity with a member that has all fields renders \`User created
<strong>
User created:
</strong>
-
<span>
-
- Mar 10, 2022
-
+ Mar 10, 2022
</span>
</div>
-
<div>
<strong>
Access granted:
</strong>
-
<span>
-
- Jul 17, 2020
-
+ Jul 17, 2020
</span>
</div>
-
<div>
<strong>
Last activity:
</strong>
-
<span>
-
- Mar 15, 2022
-
+ Mar 15, 2022
</span>
</div>
</div>
diff --git a/spec/frontend/merge_request_tabs_spec.js b/spec/frontend/merge_request_tabs_spec.js
index 3b8c9dd3bf3..6c4ea7063ad 100644
--- a/spec/frontend/merge_request_tabs_spec.js
+++ b/spec/frontend/merge_request_tabs_spec.js
@@ -281,6 +281,14 @@ describe('MergeRequestTabs', () => {
testContext.class.expandViewContainer();
expect($('.content-wrapper .container-limited')).toHaveLength(0);
});
+
+ it('adds the diff-specific width-limiter', () => {
+ testContext.class.expandViewContainer();
+
+ expect(testContext.class.contentWrapper.classList.contains('diffs-container-limited')).toBe(
+ true,
+ );
+ });
});
describe('resetViewContainer', () => {
@@ -302,6 +310,14 @@ describe('MergeRequestTabs', () => {
expect($('.content-wrapper .container-limited')).toHaveLength(1);
});
+
+ it('removes the diff-specific width-limiter', () => {
+ testContext.class.resetViewContainer();
+
+ expect(testContext.class.contentWrapper.classList.contains('diffs-container-limited')).toBe(
+ false,
+ );
+ });
});
describe('tabShown', () => {
diff --git a/spec/frontend/merge_requests/components/compare_app_spec.js b/spec/frontend/merge_requests/components/compare_app_spec.js
index ba129363ffd..887f79f9fad 100644
--- a/spec/frontend/merge_requests/components/compare_app_spec.js
+++ b/spec/frontend/merge_requests/components/compare_app_spec.js
@@ -1,10 +1,14 @@
-import { shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import axios from '~/lib/utils/axios_utils';
import CompareApp from '~/merge_requests/components/compare_app.vue';
let wrapper;
+let mock;
function factory(provideData = {}) {
- wrapper = shallowMount(CompareApp, {
+ wrapper = shallowMountExtended(CompareApp, {
provide: {
inputs: {
project: {
@@ -16,6 +20,7 @@ function factory(provideData = {}) {
name: 'branch',
},
},
+ branchCommitPath: '/commit',
toggleClass: {
project: 'project',
branch: 'branch',
@@ -29,7 +34,18 @@ function factory(provideData = {}) {
});
}
+const findCommitBox = () => wrapper.findByTestId('commit-box');
+
describe('Merge requests compare app component', () => {
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet('/commit').reply(200, 'commit content');
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
it('shows commit box when selected branch is empty', () => {
factory({
currentBranch: {
@@ -38,9 +54,41 @@ describe('Merge requests compare app component', () => {
},
});
- const commitBox = wrapper.find('[data-testid="commit-box"]');
+ const commitBox = findCommitBox();
expect(commitBox.exists()).toBe(true);
expect(commitBox.text()).toBe('Select a branch to compare');
});
+
+ it('emits select-branch on selected event', () => {
+ factory({
+ currentBranch: {
+ text: '',
+ value: '',
+ },
+ });
+
+ wrapper.findByTestId('compare-dropdown').vm.$emit('selected', { value: 'main' });
+
+ expect(wrapper.emitted('select-branch')).toEqual([['main']]);
+ });
+
+ describe('currentBranch watcher', () => {
+ it('changes selected value', async () => {
+ factory({
+ currentBranch: {
+ text: '',
+ value: '',
+ },
+ });
+
+ expect(findCommitBox().text()).toBe('Select a branch to compare');
+
+ wrapper.setProps({ currentBranch: { text: 'main', value: 'main ' } });
+
+ await waitForPromises();
+
+ expect(findCommitBox().text()).toBe('commit content');
+ });
+ });
});
diff --git a/spec/frontend/merge_requests/components/header_metadata_spec.js b/spec/frontend/merge_requests/components/header_metadata_spec.js
new file mode 100644
index 00000000000..2823b4b9d97
--- /dev/null
+++ b/spec/frontend/merge_requests/components/header_metadata_spec.js
@@ -0,0 +1,93 @@
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import HeaderMetadata from '~/merge_requests/components/header_metadata.vue';
+import mrStore from '~/mr_notes/stores';
+import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
+
+jest.mock('~/mr_notes/stores', () => jest.requireActual('helpers/mocks/mr_notes/stores'));
+
+describe('HeaderMetadata component', () => {
+ let wrapper;
+
+ const findConfidentialIcon = () => wrapper.findComponent(ConfidentialityBadge);
+ const findLockedIcon = () => wrapper.findByTestId('locked');
+ const findHiddenIcon = () => wrapper.findByTestId('hidden');
+
+ const renderTestMessage = (renders) => (renders ? 'renders' : 'does not render');
+
+ const createComponent = ({ store, provide }) => {
+ wrapper = shallowMountExtended(HeaderMetadata, {
+ mocks: {
+ $store: store,
+ },
+ provide,
+ directives: {
+ GlTooltip: createMockDirective('gl-tooltip'),
+ },
+ });
+ };
+
+ describe.each`
+ lockStatus | confidentialStatus | hiddenStatus
+ ${true} | ${true} | ${false}
+ ${true} | ${false} | ${false}
+ ${false} | ${true} | ${false}
+ ${false} | ${false} | ${false}
+ ${true} | ${true} | ${true}
+ ${true} | ${false} | ${true}
+ ${false} | ${true} | ${true}
+ ${false} | ${false} | ${true}
+ `(
+ `when locked=$lockStatus, confidential=$confidentialStatus, and hidden=$hiddenStatus`,
+ ({ lockStatus, confidentialStatus, hiddenStatus }) => {
+ const store = mrStore;
+
+ beforeEach(() => {
+ store.getters.getNoteableData = {};
+ store.getters.getNoteableData.confidential = confidentialStatus;
+ store.getters.getNoteableData.discussion_locked = lockStatus;
+ store.getters.getNoteableData.targetType = 'merge_request';
+
+ createComponent({ store, provide: { hidden: hiddenStatus } });
+ });
+
+ it(`${renderTestMessage(lockStatus)} the locked icon`, () => {
+ const lockedIcon = findLockedIcon();
+
+ expect(lockedIcon.exists()).toBe(lockStatus);
+
+ if (lockStatus) {
+ expect(lockedIcon.attributes('title')).toBe(
+ `This merge request is locked. Only project members can comment.`,
+ );
+ expect(getBinding(lockedIcon.element, 'gl-tooltip')).not.toBeUndefined();
+ }
+ });
+
+ it(`${renderTestMessage(confidentialStatus)} the confidential icon`, () => {
+ const confidentialIcon = findConfidentialIcon();
+ expect(confidentialIcon.exists()).toBe(confidentialStatus);
+
+ if (confidentialStatus && !hiddenStatus) {
+ expect(confidentialIcon.props()).toMatchObject({
+ workspaceType: 'project',
+ issuableType: 'issue',
+ });
+ }
+ });
+
+ it(`${renderTestMessage(confidentialStatus)} the hidden icon`, () => {
+ const hiddenIcon = findHiddenIcon();
+
+ expect(hiddenIcon.exists()).toBe(hiddenStatus);
+
+ if (hiddenStatus) {
+ expect(hiddenIcon.attributes('title')).toBe(
+ `This merge request is hidden because its author has been banned`,
+ );
+ expect(getBinding(hiddenIcon.element, 'gl-tooltip')).not.toBeUndefined();
+ }
+ });
+ },
+ );
+});
diff --git a/spec/frontend/nav/components/top_nav_new_dropdown_spec.js b/spec/frontend/nav/components/top_nav_new_dropdown_spec.js
index 2cd65307b0b..432ee5e9ecd 100644
--- a/spec/frontend/nav/components/top_nav_new_dropdown_spec.js
+++ b/spec/frontend/nav/components/top_nav_new_dropdown_spec.js
@@ -57,7 +57,8 @@ describe('~/nav/components/top_nav_menu_sections.vue', () => {
if (type === 'divider') {
return { type };
- } else if (type === 'header') {
+ }
+ if (type === 'header') {
return { type, text: child.text() };
}
diff --git a/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap b/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
index a4611149432..277ff2aa441 100644
--- a/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
+++ b/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
@@ -1,17 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`note_app when sort direction is asc shows skeleton notes after the loaded discussions 1`] = `
-"<ul id=\\"notes-list\\" class=\\"notes main-notes-list timeline\\">
- <noteable-discussion-stub discussion=\\"[object Object]\\" renderdifffile=\\"true\\" helppagepath=\\"\\" isoverviewtab=\\"true\\" shouldscrolltonote=\\"true\\"></noteable-discussion-stub>
- <skeleton-loading-container-stub class=\\"note-skeleton\\"></skeleton-loading-container-stub>
- <!---->
-</ul>"
+<ul
+ class="main-notes-list notes timeline"
+ id="reference-0"
+>
+ <noteable-discussion-stub
+ discussion="[object Object]"
+ helppagepath=""
+ isoverviewtab="true"
+ renderdifffile="true"
+ shouldscrolltonote="true"
+ />
+ <skeleton-loading-container-stub
+ class="note-skeleton"
+ />
+</ul>
`;
exports[`note_app when sort direction is desc shows skeleton notes before the loaded discussions 1`] = `
-"<ul id=\\"notes-list\\" class=\\"notes main-notes-list timeline\\">
- <skeleton-loading-container-stub class=\\"note-skeleton\\"></skeleton-loading-container-stub>
- <noteable-discussion-stub discussion=\\"[object Object]\\" renderdifffile=\\"true\\" helppagepath=\\"\\" isoverviewtab=\\"true\\" shouldscrolltonote=\\"true\\"></noteable-discussion-stub>
- <!---->
-</ul>"
+<ul
+ class="main-notes-list notes timeline"
+ id="reference-0"
+>
+ <skeleton-loading-container-stub
+ class="note-skeleton"
+ />
+ <noteable-discussion-stub
+ discussion="[object Object]"
+ helppagepath=""
+ isoverviewtab="true"
+ renderdifffile="true"
+ shouldscrolltonote="true"
+ />
+</ul>
`;
diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js
index 0728646246d..9b1678c0a8a 100644
--- a/spec/frontend/notes/components/comment_form_spec.js
+++ b/spec/frontend/notes/components/comment_form_spec.js
@@ -153,21 +153,18 @@ describe('issue_comment_form component', () => {
mountComponent({ mountFunction: mount, initialData: { note: 'hello world' } });
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
- jest.spyOn(wrapper.vm, 'stopPolling');
findCloseReopenButton().trigger('click');
expect(wrapper.vm.isSubmitting).toBe(true);
expect(wrapper.vm.note).toBe('');
expect(wrapper.vm.saveNote).toHaveBeenCalled();
- expect(wrapper.vm.stopPolling).toHaveBeenCalled();
});
it('tracks event', () => {
mountComponent({ mountFunction: mount, initialData: { note: 'hello world' } });
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
- jest.spyOn(wrapper.vm, 'stopPolling');
findCloseReopenButton().trigger('click');
@@ -302,7 +299,6 @@ describe('issue_comment_form component', () => {
const saveNotePromise = Promise.resolve();
jest.spyOn(wrapper.vm, 'saveNote').mockReturnValue(saveNotePromise);
- jest.spyOn(wrapper.vm, 'stopPolling');
const actionButton = findCloseReopenButton();
@@ -351,7 +347,6 @@ describe('issue_comment_form component', () => {
it('should make textarea disabled while requesting', async () => {
mountComponent({ mountFunction: mount });
- jest.spyOn(wrapper.vm, 'stopPolling');
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
findMarkdownEditor().vm.$emit('input', 'hello world');
diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js
index caf47febedd..d49ab0d71db 100644
--- a/spec/frontend/notes/components/notes_app_spec.js
+++ b/spec/frontend/notes/components/notes_app_spec.js
@@ -288,7 +288,6 @@ describe('note_app', () => {
wrapper.vm.$store.hotUpdate({
actions: {
toggleAward: toggleAwardAction,
- stopPolling() {},
},
});
diff --git a/spec/frontend/notes/stores/actions_spec.js b/spec/frontend/notes/stores/actions_spec.js
index 0205f606297..104c297b44e 100644
--- a/spec/frontend/notes/stores/actions_spec.js
+++ b/spec/frontend/notes/stores/actions_spec.js
@@ -8,11 +8,7 @@ import { createAlert } from '~/alert';
import toast from '~/vue_shared/plugins/global_toast';
import { EVENT_ISSUABLE_VUE_APP_CHANGE } from '~/issuable/constants';
import axios from '~/lib/utils/axios_utils';
-import {
- HTTP_STATUS_INTERNAL_SERVER_ERROR,
- HTTP_STATUS_OK,
- HTTP_STATUS_SERVICE_UNAVAILABLE,
-} from '~/lib/utils/http_status';
+import { HTTP_STATUS_OK, HTTP_STATUS_SERVICE_UNAVAILABLE } from '~/lib/utils/http_status';
import * as notesConstants from '~/notes/constants';
import createStore from '~/notes/stores';
import * as actions from '~/notes/stores/actions';
@@ -24,7 +20,6 @@ import updateMergeRequestLockMutation from '~/sidebar/queries/update_merge_reque
import promoteTimelineEvent from '~/notes/graphql/promote_timeline_event.mutation.graphql';
import mrWidgetEventHub from '~/vue_merge_request_widget/event_hub';
import notesEventHub from '~/notes/event_hub';
-import waitForPromises from 'helpers/wait_for_promises';
import { resetStore } from '../helpers';
import {
discussionMock,
@@ -262,13 +257,7 @@ describe('Actions Notes Store', () => {
});
describe('initPolling', () => {
- afterEach(() => {
- gon.features = {};
- });
-
it('creates the Action Cable subscription', () => {
- gon.features = { actionCableNotes: true };
-
store.dispatch('setNotesData', notesDataMock);
store.dispatch('initPolling');
@@ -290,8 +279,6 @@ describe('Actions Notes Store', () => {
const response = { notes: [], last_fetched_at: '123456' };
const successMock = () =>
axiosMock.onGet(notesDataMock.notesPath).reply(HTTP_STATUS_OK, response);
- const failureMock = () =>
- axiosMock.onGet(notesDataMock.notesPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
beforeEach(() => {
return store.dispatch('setNotesData', notesDataMock);
@@ -304,153 +291,6 @@ describe('Actions Notes Store', () => {
expect(store.state.lastFetchedAt).toBe('123456');
});
-
- it('shows an alert when fetching fails', async () => {
- failureMock();
-
- await store.dispatch('fetchUpdatedNotes');
-
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('poll', () => {
- const pollInterval = 6000;
- const pollResponse = { notes: [], last_fetched_at: '123456' };
- const pollHeaders = { 'poll-interval': `${pollInterval}` };
- const successMock = () =>
- axiosMock.onGet(notesDataMock.notesPath).reply(HTTP_STATUS_OK, pollResponse, pollHeaders);
- const failureMock = () =>
- axiosMock.onGet(notesDataMock.notesPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
- const advanceAndRAF = (time) => {
- if (time) {
- jest.advanceTimersByTime(time);
- }
-
- return waitForPromises();
- };
- const advanceXMoreIntervals = (number) => {
- const timeoutLength = pollInterval * number;
-
- return advanceAndRAF(timeoutLength);
- };
- const startPolling = async () => {
- await store.dispatch('poll');
- await advanceAndRAF(2);
- };
- const cleanUp = () => {
- jest.clearAllTimers();
-
- return store.dispatch('stopPolling');
- };
-
- beforeEach(() => {
- return store.dispatch('setNotesData', notesDataMock);
- });
-
- afterEach(() => {
- return cleanUp();
- });
-
- it('calls service with last fetched state', async () => {
- successMock();
-
- await startPolling();
-
- expect(store.state.lastFetchedAt).toBe('123456');
-
- await advanceXMoreIntervals(1);
-
- expect(axiosMock.history.get).toHaveLength(2);
- expect(axiosMock.history.get[1].headers).toMatchObject({
- 'X-Last-Fetched-At': '123456',
- });
- });
-
- describe('polling side effects', () => {
- it('retries twice', async () => {
- failureMock();
-
- await startPolling();
-
- // This is the first request, not a retry
- expect(axiosMock.history.get).toHaveLength(1);
-
- await advanceXMoreIntervals(1);
-
- // Retry #1
- expect(axiosMock.history.get).toHaveLength(2);
-
- await advanceXMoreIntervals(1);
-
- // Retry #2
- expect(axiosMock.history.get).toHaveLength(3);
-
- await advanceXMoreIntervals(10);
-
- // There are no more retries
- expect(axiosMock.history.get).toHaveLength(3);
- });
-
- it('shows the error display on the second failure', async () => {
- failureMock();
-
- await startPolling();
-
- expect(axiosMock.history.get).toHaveLength(1);
- expect(createAlert).not.toHaveBeenCalled();
-
- await advanceXMoreIntervals(1);
-
- expect(axiosMock.history.get).toHaveLength(2);
- expect(createAlert).toHaveBeenCalled();
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
-
- it('resets the failure counter on success', async () => {
- // We can't get access to the actual counter in the polling closure.
- // So we can infer that it's reset by ensuring that the error is only
- // shown when we cause two failures in a row - no successes between
-
- axiosMock
- .onGet(notesDataMock.notesPath)
- .replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR) // cause one error
- .onGet(notesDataMock.notesPath)
- .replyOnce(HTTP_STATUS_OK, pollResponse, pollHeaders) // then a success
- .onGet(notesDataMock.notesPath)
- .reply(HTTP_STATUS_INTERNAL_SERVER_ERROR); // and then more errors
-
- await startPolling(); // Failure #1
- await advanceXMoreIntervals(1); // Success #1
- await advanceXMoreIntervals(1); // Failure #2
-
- // That was the first failure AFTER a success, so we should NOT see the error displayed
- expect(createAlert).not.toHaveBeenCalled();
-
- // Now we'll allow another failure
- await advanceXMoreIntervals(1); // Failure #3
-
- // Since this is the second failure in a row, the error should happen
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
-
- it('hides the error display if it exists on success', async () => {
- failureMock();
-
- await startPolling();
- await advanceXMoreIntervals(2);
-
- // After two errors, the error should be displayed
- expect(createAlert).toHaveBeenCalledTimes(1);
-
- axiosMock.reset();
- successMock();
-
- await advanceXMoreIntervals(1);
-
- expect(mockAlertDismiss).toHaveBeenCalledTimes(1);
- });
- });
});
describe('setNotesFetchedState', () => {
@@ -996,11 +836,7 @@ describe('Actions Notes Store', () => {
[mutationTypes.SET_RESOLVING_DISCUSSION, false],
]);
- expect(dispatch.mock.calls).toEqual([
- ['stopPolling'],
- ['resolveDiscussion', { discussionId }],
- ['restartPolling'],
- ]);
+ expect(dispatch.mock.calls).toEqual([['resolveDiscussion', { discussionId }]]);
expect(createAlert).not.toHaveBeenCalled();
});
});
@@ -1015,7 +851,6 @@ describe('Actions Notes Store', () => {
[mutationTypes.SET_RESOLVING_DISCUSSION, true],
[mutationTypes.SET_RESOLVING_DISCUSSION, false],
]);
- expect(dispatch.mock.calls).toEqual([['stopPolling'], ['restartPolling']]);
expect(createAlert).toHaveBeenCalledWith({
message: TEST_ERROR_MESSAGE,
parent: flashContainer,
@@ -1033,7 +868,6 @@ describe('Actions Notes Store', () => {
[mutationTypes.SET_RESOLVING_DISCUSSION, true],
[mutationTypes.SET_RESOLVING_DISCUSSION, false],
]);
- expect(dispatch.mock.calls).toEqual([['stopPolling'], ['restartPolling']]);
expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while applying the suggestion. Please try again.',
parent: flashContainer,
@@ -1081,10 +915,8 @@ describe('Actions Notes Store', () => {
]);
expect(dispatch.mock.calls).toEqual([
- ['stopPolling'],
['resolveDiscussion', { discussionId: discussionIds[0] }],
['resolveDiscussion', { discussionId: discussionIds[1] }],
- ['restartPolling'],
]);
expect(createAlert).not.toHaveBeenCalled();
@@ -1104,7 +936,6 @@ describe('Actions Notes Store', () => {
[mutationTypes.SET_RESOLVING_DISCUSSION, false],
]);
- expect(dispatch.mock.calls).toEqual([['stopPolling'], ['restartPolling']]);
expect(createAlert).toHaveBeenCalledWith({
message: TEST_ERROR_MESSAGE,
parent: flashContainer,
@@ -1125,7 +956,6 @@ describe('Actions Notes Store', () => {
[mutationTypes.SET_RESOLVING_DISCUSSION, false],
]);
- expect(dispatch.mock.calls).toEqual([['stopPolling'], ['restartPolling']]);
expect(createAlert).toHaveBeenCalledWith({
message:
'Something went wrong while applying the batch of suggestions. Please try again.',
diff --git a/spec/frontend/observability/client_spec.js b/spec/frontend/observability/client_spec.js
index 10fdc8c33c4..056175eac07 100644
--- a/spec/frontend/observability/client_spec.js
+++ b/spec/frontend/observability/client_spec.js
@@ -1,15 +1,19 @@
import MockAdapter from 'axios-mock-adapter';
+import * as Sentry from '@sentry/browser';
import { buildClient } from '~/observability/client';
import axios from '~/lib/utils/axios_utils';
jest.mock('~/lib/utils/axios_utils');
+jest.mock('@sentry/browser');
describe('buildClient', () => {
let client;
let axiosMock;
const tracingUrl = 'https://example.com/tracing';
- const EXPECTED_ERROR_MESSAGE = 'traces are missing/invalid in the response';
+ const provisioningUrl = 'https://example.com/provisioning';
+
+ const FETCHING_TRACES_ERROR = 'traces are missing/invalid in the response';
beforeEach(() => {
axiosMock = new MockAdapter(axios);
@@ -17,7 +21,7 @@ describe('buildClient', () => {
client = buildClient({
tracingUrl,
- provisioningUrl: 'https://example.com/provisioning',
+ provisioningUrl,
});
});
@@ -25,10 +29,85 @@ describe('buildClient', () => {
axiosMock.restore();
});
+ describe('isTracingEnabled', () => {
+ it('returns true if requests succeedes', async () => {
+ axiosMock.onGet(provisioningUrl).reply(200, {
+ status: 'ready',
+ });
+
+ const enabled = await client.isTracingEnabled();
+
+ expect(enabled).toBe(true);
+ });
+
+ it('returns false if response is 404', async () => {
+ axiosMock.onGet(provisioningUrl).reply(404);
+
+ const enabled = await client.isTracingEnabled();
+
+ expect(enabled).toBe(false);
+ });
+
+ // we currently ignore the 'status' payload and just check if the request was successful
+ // We might improve this as part of https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2315
+ it('returns true for any status', async () => {
+ axiosMock.onGet(provisioningUrl).reply(200, {
+ status: 'not ready',
+ });
+
+ const enabled = await client.isTracingEnabled();
+
+ expect(enabled).toBe(true);
+ });
+
+ it('throws in case of any non-404 error', async () => {
+ axiosMock.onGet(provisioningUrl).reply(500);
+
+ const e = 'Request failed with status code 500';
+ await expect(client.isTracingEnabled()).rejects.toThrow(e);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e));
+ });
+
+ it('throws in case of unexpected response', async () => {
+ axiosMock.onGet(provisioningUrl).reply(200, {});
+
+ const e = 'Failed to check provisioning';
+ await expect(client.isTracingEnabled()).rejects.toThrow(e);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e));
+ });
+ });
+
+ describe('enableTraces', () => {
+ it('makes a PUT request to the provisioning URL', async () => {
+ let putConfig;
+ axiosMock.onPut(provisioningUrl).reply((config) => {
+ putConfig = config;
+ return [200];
+ });
+
+ await client.enableTraces();
+
+ expect(putConfig.withCredentials).toBe(true);
+ });
+
+ it('reports an error if the req fails', async () => {
+ axiosMock.onPut(provisioningUrl).reply(401);
+
+ const e = 'Request failed with status code 401';
+
+ await expect(client.enableTraces()).rejects.toThrow(e);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e));
+ });
+ });
+
describe('fetchTrace', () => {
it('fetches the trace from the tracing URL', async () => {
const mockTraces = [
- { trace_id: 'trace-1', spans: [{ duration_nano: 1000 }, { duration_nano: 2000 }] },
+ {
+ trace_id: 'trace-1',
+ duration_nano: 3000,
+ spans: [{ duration_nano: 1000 }, { duration_nano: 2000 }],
+ },
];
axiosMock.onGet(tracingUrl).reply(200, {
@@ -42,34 +121,37 @@ describe('buildClient', () => {
withCredentials: true,
params: { trace_id: 'trace-1' },
});
- expect(result).toEqual({
- ...mockTraces[0],
- duration: 1,
- });
+ expect(result).toEqual(mockTraces[0]);
});
it('rejects if trace id is missing', () => {
return expect(client.fetchTrace()).rejects.toThrow('traceId is required.');
});
- it('rejects if traces are empty', () => {
+ it('rejects if traces are empty', async () => {
axiosMock.onGet(tracingUrl).reply(200, { traces: [] });
- return expect(client.fetchTrace('trace-1')).rejects.toThrow(EXPECTED_ERROR_MESSAGE);
+ await expect(client.fetchTrace('trace-1')).rejects.toThrow(FETCHING_TRACES_ERROR);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(FETCHING_TRACES_ERROR));
});
- it('rejects if traces are invalid', () => {
+ it('rejects if traces are invalid', async () => {
axiosMock.onGet(tracingUrl).reply(200, { traces: 'invalid' });
- return expect(client.fetchTraces()).rejects.toThrow(EXPECTED_ERROR_MESSAGE);
+ await expect(client.fetchTraces()).rejects.toThrow(FETCHING_TRACES_ERROR);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(FETCHING_TRACES_ERROR));
});
});
describe('fetchTraces', () => {
it('fetches traces from the tracing URL', async () => {
const mockTraces = [
- { trace_id: 'trace-1', spans: [{ duration_nano: 1000 }, { duration_nano: 2000 }] },
- { trace_id: 'trace-2', spans: [{ duration_nano: 2000 }] },
+ {
+ trace_id: 'trace-1',
+ duration_nano: 3000,
+ spans: [{ duration_nano: 1000 }, { duration_nano: 2000 }],
+ },
+ { trace_id: 'trace-2', duration_nano: 3000, spans: [{ duration_nano: 2000 }] },
];
axiosMock.onGet(tracingUrl).reply(200, {
@@ -83,28 +165,21 @@ describe('buildClient', () => {
withCredentials: true,
params: new URLSearchParams(),
});
- expect(result).toEqual([
- {
- ...mockTraces[0],
- duration: 1,
- },
- {
- ...mockTraces[1],
- duration: 2,
- },
- ]);
+ expect(result).toEqual(mockTraces);
});
- it('rejects if traces are missing', () => {
+ it('rejects if traces are missing', async () => {
axiosMock.onGet(tracingUrl).reply(200, {});
- return expect(client.fetchTraces()).rejects.toThrow(EXPECTED_ERROR_MESSAGE);
+ await expect(client.fetchTraces()).rejects.toThrow(FETCHING_TRACES_ERROR);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(FETCHING_TRACES_ERROR));
});
- it('rejects if traces are invalid', () => {
+ it('rejects if traces are invalid', async () => {
axiosMock.onGet(tracingUrl).reply(200, { traces: 'invalid' });
- return expect(client.fetchTraces()).rejects.toThrow(EXPECTED_ERROR_MESSAGE);
+ await expect(client.fetchTraces()).rejects.toThrow(FETCHING_TRACES_ERROR);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(FETCHING_TRACES_ERROR));
});
describe('query filter', () => {
diff --git a/spec/frontend/organizations/groups_and_projects/components/app_spec.js b/spec/frontend/organizations/groups_and_projects/components/app_spec.js
index 64182b74e4f..e2301de8607 100644
--- a/spec/frontend/organizations/groups_and_projects/components/app_spec.js
+++ b/spec/frontend/organizations/groups_and_projects/components/app_spec.js
@@ -1,10 +1,9 @@
import { GlCollapsibleListbox, GlSorting, GlSortingItem } from '@gitlab/ui';
import App from '~/organizations/groups_and_projects/components/app.vue';
-import GroupsPage from '~/organizations/groups_and_projects/components/groups_page.vue';
-import ProjectsPage from '~/organizations/groups_and_projects/components/projects_page.vue';
+import GroupsView from '~/organizations/shared/components/groups_view.vue';
+import ProjectsView from '~/organizations/shared/components/projects_view.vue';
+import { RESOURCE_TYPE_GROUPS, RESOURCE_TYPE_PROJECTS } from '~/organizations/constants';
import {
- DISPLAY_QUERY_GROUPS,
- DISPLAY_QUERY_PROJECTS,
SORT_ITEM_CREATED,
SORT_DIRECTION_DESC,
} from '~/organizations/groups_and_projects/constants';
@@ -36,10 +35,10 @@ describe('GroupsAndProjectsApp', () => {
describe.each`
display | expectedComponent | expectedDisplayListboxSelectedProp
- ${null} | ${GroupsPage} | ${DISPLAY_QUERY_GROUPS}
- ${'unsupported_value'} | ${GroupsPage} | ${DISPLAY_QUERY_GROUPS}
- ${DISPLAY_QUERY_GROUPS} | ${GroupsPage} | ${DISPLAY_QUERY_GROUPS}
- ${DISPLAY_QUERY_PROJECTS} | ${ProjectsPage} | ${DISPLAY_QUERY_PROJECTS}
+ ${null} | ${GroupsView} | ${RESOURCE_TYPE_GROUPS}
+ ${'unsupported_value'} | ${GroupsView} | ${RESOURCE_TYPE_GROUPS}
+ ${RESOURCE_TYPE_GROUPS} | ${GroupsView} | ${RESOURCE_TYPE_GROUPS}
+ ${RESOURCE_TYPE_PROJECTS} | ${ProjectsView} | ${RESOURCE_TYPE_PROJECTS}
`(
'when `display` query string is $display',
({ display, expectedComponent, expectedDisplayListboxSelectedProp }) => {
@@ -122,11 +121,11 @@ describe('GroupsAndProjectsApp', () => {
beforeEach(() => {
createComponent();
- findListbox().vm.$emit('select', DISPLAY_QUERY_PROJECTS);
+ findListbox().vm.$emit('select', RESOURCE_TYPE_PROJECTS);
});
it('updates `display` query string', () => {
- expect(routerMock.push).toHaveBeenCalledWith({ query: { display: DISPLAY_QUERY_PROJECTS } });
+ expect(routerMock.push).toHaveBeenCalledWith({ query: { display: RESOURCE_TYPE_PROJECTS } });
});
});
diff --git a/spec/frontend/organizations/groups_and_projects/components/groups_page_spec.js b/spec/frontend/organizations/groups_and_projects/components/groups_page_spec.js
deleted file mode 100644
index 537f8114fcf..00000000000
--- a/spec/frontend/organizations/groups_and_projects/components/groups_page_spec.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import VueApollo from 'vue-apollo';
-import Vue from 'vue';
-import { GlLoadingIcon } from '@gitlab/ui';
-import GroupsPage from '~/organizations/groups_and_projects/components/groups_page.vue';
-import { formatGroups } from '~/organizations/groups_and_projects/utils';
-import resolvers from '~/organizations/groups_and_projects/graphql/resolvers';
-import GroupsList from '~/vue_shared/components/groups_list/groups_list.vue';
-import { createAlert } from '~/alert';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { organizationGroups } from '../mock_data';
-
-jest.mock('~/alert');
-
-Vue.use(VueApollo);
-jest.useFakeTimers();
-
-describe('GroupsPage', () => {
- let wrapper;
- let mockApollo;
-
- const createComponent = ({ mockResolvers = resolvers } = {}) => {
- mockApollo = createMockApollo([], mockResolvers);
-
- wrapper = shallowMountExtended(GroupsPage, { apolloProvider: mockApollo });
- };
-
- afterEach(() => {
- mockApollo = null;
- });
-
- describe('when API call is loading', () => {
- beforeEach(() => {
- const mockResolvers = {
- Query: {
- organization: jest.fn().mockReturnValueOnce(new Promise(() => {})),
- },
- };
-
- createComponent({ mockResolvers });
- });
-
- it('renders loading icon', () => {
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- });
- });
-
- describe('when API call is successful', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders `GroupsList` component and passes correct props', async () => {
- jest.runAllTimers();
- await waitForPromises();
-
- expect(wrapper.findComponent(GroupsList).props()).toEqual({
- groups: formatGroups(organizationGroups.nodes),
- showGroupIcon: true,
- });
- });
- });
-
- describe('when API call is not successful', () => {
- const error = new Error();
-
- beforeEach(() => {
- const mockResolvers = {
- Query: {
- organization: jest.fn().mockRejectedValueOnce(error),
- },
- };
-
- createComponent({ mockResolvers });
- });
-
- it('displays error alert', async () => {
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: GroupsPage.i18n.errorMessage,
- error,
- captureError: true,
- });
- });
- });
-});
diff --git a/spec/frontend/organizations/groups_and_projects/components/projects_page_spec.js b/spec/frontend/organizations/groups_and_projects/components/projects_page_spec.js
deleted file mode 100644
index 7cadcab5021..00000000000
--- a/spec/frontend/organizations/groups_and_projects/components/projects_page_spec.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import VueApollo from 'vue-apollo';
-import Vue from 'vue';
-import { GlLoadingIcon } from '@gitlab/ui';
-import ProjectsPage from '~/organizations/groups_and_projects/components/projects_page.vue';
-import { formatProjects } from '~/organizations/groups_and_projects/utils';
-import resolvers from '~/organizations/groups_and_projects/graphql/resolvers';
-import ProjectsList from '~/vue_shared/components/projects_list/projects_list.vue';
-import { createAlert } from '~/alert';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { organizationProjects } from '../mock_data';
-
-jest.mock('~/alert');
-
-Vue.use(VueApollo);
-jest.useFakeTimers();
-
-describe('ProjectsPage', () => {
- let wrapper;
- let mockApollo;
-
- const createComponent = ({ mockResolvers = resolvers } = {}) => {
- mockApollo = createMockApollo([], mockResolvers);
-
- wrapper = shallowMountExtended(ProjectsPage, { apolloProvider: mockApollo });
- };
-
- afterEach(() => {
- mockApollo = null;
- });
-
- describe('when API call is loading', () => {
- beforeEach(() => {
- const mockResolvers = {
- Query: {
- organization: jest.fn().mockReturnValueOnce(new Promise(() => {})),
- },
- };
-
- createComponent({ mockResolvers });
- });
-
- it('renders loading icon', () => {
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- });
- });
-
- describe('when API call is successful', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders `ProjectsList` component and passes correct props', async () => {
- jest.runAllTimers();
- await waitForPromises();
-
- expect(wrapper.findComponent(ProjectsList).props()).toEqual({
- projects: formatProjects(organizationProjects.nodes),
- showProjectIcon: true,
- });
- });
- });
-
- describe('when API call is not successful', () => {
- const error = new Error();
-
- beforeEach(() => {
- const mockResolvers = {
- Query: {
- organization: jest.fn().mockRejectedValueOnce(error),
- },
- };
-
- createComponent({ mockResolvers });
- });
-
- it('displays error alert', async () => {
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: ProjectsPage.i18n.errorMessage,
- error,
- captureError: true,
- });
- });
- });
-});
diff --git a/spec/frontend/organizations/groups_and_projects/mock_data.js b/spec/frontend/organizations/groups_and_projects/mock_data.js
deleted file mode 100644
index eb829a24f50..00000000000
--- a/spec/frontend/organizations/groups_and_projects/mock_data.js
+++ /dev/null
@@ -1,252 +0,0 @@
-export const organization = {
- id: 'gid://gitlab/Organization/1',
- __typename: 'Organization',
-};
-
-export const organizationProjects = {
- nodes: [
- {
- id: 'gid://gitlab/Project/8',
- nameWithNamespace: 'Twitter / Typeahead.Js',
- webUrl: 'http://127.0.0.1:3000/twitter/Typeahead.Js',
- topics: ['JavaScript', 'Vue.js'],
- forksCount: 4,
- avatarUrl: null,
- starCount: 0,
- visibility: 'public',
- openIssuesCount: 48,
- descriptionHtml:
- '<p data-sourcepos="1:1-1:59" dir="auto">Optio et reprehenderit enim doloremque deserunt et commodi.</p>',
- issuesAccessLevel: 'enabled',
- forkingAccessLevel: 'enabled',
- isForked: true,
- accessLevel: {
- integerValue: 30,
- },
- },
- {
- id: 'gid://gitlab/Project/7',
- nameWithNamespace: 'Flightjs / Flight',
- webUrl: 'http://127.0.0.1:3000/flightjs/Flight',
- topics: [],
- forksCount: 0,
- avatarUrl: null,
- starCount: 0,
- visibility: 'private',
- openIssuesCount: 37,
- descriptionHtml:
- '<p data-sourcepos="1:1-1:49" dir="auto">Dolor dicta rerum et ut eius voluptate earum qui.</p>',
- issuesAccessLevel: 'enabled',
- forkingAccessLevel: 'enabled',
- isForked: false,
- accessLevel: {
- integerValue: 20,
- },
- },
- {
- id: 'gid://gitlab/Project/6',
- nameWithNamespace: 'Jashkenas / Underscore',
- webUrl: 'http://127.0.0.1:3000/jashkenas/Underscore',
- topics: [],
- forksCount: 0,
- avatarUrl: null,
- starCount: 0,
- visibility: 'private',
- openIssuesCount: 34,
- descriptionHtml:
- '<p data-sourcepos="1:1-1:52" dir="auto">Incidunt est aliquam autem nihil eveniet quis autem.</p>',
- issuesAccessLevel: 'enabled',
- forkingAccessLevel: 'enabled',
- isForked: false,
- accessLevel: {
- integerValue: 40,
- },
- },
- {
- id: 'gid://gitlab/Project/5',
- nameWithNamespace: 'Commit451 / Lab Coat',
- webUrl: 'http://127.0.0.1:3000/Commit451/lab-coat',
- topics: [],
- forksCount: 0,
- avatarUrl: null,
- starCount: 0,
- visibility: 'internal',
- openIssuesCount: 49,
- descriptionHtml:
- '<p data-sourcepos="1:1-1:34" dir="auto">Sint eos dolorem impedit rerum et.</p>',
- issuesAccessLevel: 'enabled',
- forkingAccessLevel: 'enabled',
- isForked: false,
- accessLevel: {
- integerValue: 10,
- },
- },
- {
- id: 'gid://gitlab/Project/1',
- nameWithNamespace: 'Toolbox / Gitlab Smoke Tests',
- webUrl: 'http://127.0.0.1:3000/toolbox/gitlab-smoke-tests',
- topics: [],
- forksCount: 0,
- avatarUrl: null,
- starCount: 0,
- visibility: 'internal',
- openIssuesCount: 34,
- descriptionHtml:
- '<p data-sourcepos="1:1-1:40" dir="auto">Veritatis error laboriosam libero autem.</p>',
- issuesAccessLevel: 'enabled',
- forkingAccessLevel: 'enabled',
- isForked: false,
- accessLevel: {
- integerValue: 30,
- },
- },
- ],
-};
-
-export const organizationGroups = {
- nodes: [
- {
- id: 'gid://gitlab/Group/29',
- fullName: 'Commit451',
- parent: null,
- webUrl: 'http://127.0.0.1:3000/groups/Commit451',
- descriptionHtml:
- '<p data-sourcepos="1:1-1:52" dir="auto">Autem praesentium vel ut ratione itaque ullam culpa.</p>',
- avatarUrl: null,
- descendantGroupsCount: 0,
- projectsCount: 3,
- groupMembersCount: 2,
- visibility: 'public',
- accessLevel: {
- integerValue: 30,
- },
- },
- {
- id: 'gid://gitlab/Group/33',
- fullName: 'Flightjs',
- parent: null,
- webUrl: 'http://127.0.0.1:3000/groups/flightjs',
- descriptionHtml:
- '<p data-sourcepos="1:1-1:60" dir="auto">Ipsa reiciendis deleniti officiis illum nostrum quo aliquam.</p>',
- avatarUrl: null,
- descendantGroupsCount: 4,
- projectsCount: 3,
- groupMembersCount: 1,
- visibility: 'private',
- accessLevel: {
- integerValue: 20,
- },
- },
- {
- id: 'gid://gitlab/Group/24',
- fullName: 'Gitlab Org',
- parent: null,
- webUrl: 'http://127.0.0.1:3000/groups/gitlab-org',
- descriptionHtml:
- '<p data-sourcepos="1:1-1:64" dir="auto">Dolorem dolorem omnis impedit cupiditate pariatur officia velit.</p>',
- avatarUrl: null,
- descendantGroupsCount: 1,
- projectsCount: 1,
- groupMembersCount: 2,
- visibility: 'internal',
- accessLevel: {
- integerValue: 10,
- },
- },
- {
- id: 'gid://gitlab/Group/27',
- fullName: 'Gnuwget',
- parent: null,
- webUrl: 'http://127.0.0.1:3000/groups/gnuwgetf',
- descriptionHtml:
- '<p data-sourcepos="1:1-1:47" dir="auto">Culpa soluta aut eius dolores est vel sapiente.</p>',
- avatarUrl: null,
- descendantGroupsCount: 4,
- projectsCount: 2,
- groupMembersCount: 3,
- visibility: 'public',
- accessLevel: {
- integerValue: 40,
- },
- },
- {
- id: 'gid://gitlab/Group/31',
- fullName: 'Jashkenas',
- parent: null,
- webUrl: 'http://127.0.0.1:3000/groups/jashkenas',
- descriptionHtml: '<p data-sourcepos="1:1-1:25" dir="auto">Ut ut id aliquid nostrum.</p>',
- avatarUrl: null,
- descendantGroupsCount: 3,
- projectsCount: 3,
- groupMembersCount: 10,
- visibility: 'private',
- accessLevel: {
- integerValue: 10,
- },
- },
- {
- id: 'gid://gitlab/Group/22',
- fullName: 'Toolbox',
- parent: null,
- webUrl: 'http://127.0.0.1:3000/groups/toolbox',
- descriptionHtml:
- '<p data-sourcepos="1:1-1:46" dir="auto">Quo voluptatem magnam facere voluptates alias.</p>',
- avatarUrl: null,
- descendantGroupsCount: 2,
- projectsCount: 3,
- groupMembersCount: 40,
- visibility: 'internal',
- accessLevel: {
- integerValue: 30,
- },
- },
- {
- id: 'gid://gitlab/Group/35',
- fullName: 'Twitter',
- parent: null,
- webUrl: 'http://127.0.0.1:3000/groups/twitter',
- descriptionHtml:
- '<p data-sourcepos="1:1-1:40" dir="auto">Quae nulla consequatur assumenda id quo.</p>',
- avatarUrl: null,
- descendantGroupsCount: 20,
- projectsCount: 30,
- groupMembersCount: 100,
- visibility: 'public',
- accessLevel: {
- integerValue: 40,
- },
- },
- {
- id: 'gid://gitlab/Group/73',
- fullName: 'test',
- parent: null,
- webUrl: 'http://127.0.0.1:3000/groups/test',
- descriptionHtml: '',
- avatarUrl: null,
- descendantGroupsCount: 1,
- projectsCount: 1,
- groupMembersCount: 1,
- visibility: 'private',
- accessLevel: {
- integerValue: 30,
- },
- },
- {
- id: 'gid://gitlab/Group/74',
- fullName: 'Twitter / test subgroup',
- parent: {
- id: 'gid://gitlab/Group/35',
- },
- webUrl: 'http://127.0.0.1:3000/groups/twitter/test-subgroup',
- descriptionHtml: '',
- avatarUrl: null,
- descendantGroupsCount: 4,
- projectsCount: 4,
- groupMembersCount: 4,
- visibility: 'internal',
- accessLevel: {
- integerValue: 20,
- },
- },
- ],
-};
diff --git a/spec/frontend/organizations/groups_and_projects/utils_spec.js b/spec/frontend/organizations/groups_and_projects/utils_spec.js
deleted file mode 100644
index 2cb1ee02061..00000000000
--- a/spec/frontend/organizations/groups_and_projects/utils_spec.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { formatProjects, formatGroups } from '~/organizations/groups_and_projects/utils';
-import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/projects_list/constants';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { organizationProjects, organizationGroups } from './mock_data';
-
-describe('formatProjects', () => {
- it('correctly formats the projects', () => {
- const [firstMockProject] = organizationProjects.nodes;
- const formattedProjects = formatProjects(organizationProjects.nodes);
- const [firstFormattedProject] = formattedProjects;
-
- expect(firstFormattedProject).toMatchObject({
- id: getIdFromGraphQLId(firstMockProject.id),
- name: firstMockProject.nameWithNamespace,
- permissions: {
- projectAccess: {
- accessLevel: firstMockProject.accessLevel.integerValue,
- },
- },
- actions: [ACTION_EDIT, ACTION_DELETE],
- });
- expect(formattedProjects.length).toBe(organizationProjects.nodes.length);
- });
-});
-
-describe('formatGroups', () => {
- it('correctly formats the groups', () => {
- const [firstMockGroup] = organizationGroups.nodes;
- const formattedGroups = formatGroups(organizationGroups.nodes);
- const [firstFormattedGroup] = formattedGroups;
-
- expect(firstFormattedGroup.id).toBe(getIdFromGraphQLId(firstMockGroup.id));
- expect(formattedGroups.length).toBe(organizationGroups.nodes.length);
- });
-});
diff --git a/spec/frontend/organizations/shared/components/groups_view_spec.js b/spec/frontend/organizations/shared/components/groups_view_spec.js
new file mode 100644
index 00000000000..8d6ea60ffd2
--- /dev/null
+++ b/spec/frontend/organizations/shared/components/groups_view_spec.js
@@ -0,0 +1,146 @@
+import VueApollo from 'vue-apollo';
+import Vue from 'vue';
+import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
+import GroupsView from '~/organizations/shared/components/groups_view.vue';
+import { formatGroups } from '~/organizations/shared/utils';
+import resolvers from '~/organizations/shared/graphql/resolvers';
+import GroupsList from '~/vue_shared/components/groups_list/groups_list.vue';
+import { createAlert } from '~/alert';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { organizationGroups } from '~/organizations/mock_data';
+
+jest.mock('~/alert');
+
+Vue.use(VueApollo);
+jest.useFakeTimers();
+
+describe('GroupsView', () => {
+ let wrapper;
+ let mockApollo;
+
+ const defaultProvide = {
+ groupsEmptyStateSvgPath: 'illustrations/empty-state/empty-groups-md.svg',
+ newGroupPath: '/groups/new',
+ };
+
+ const createComponent = ({ mockResolvers = resolvers, propsData = {} } = {}) => {
+ mockApollo = createMockApollo([], mockResolvers);
+
+ wrapper = shallowMountExtended(GroupsView, {
+ apolloProvider: mockApollo,
+ provide: defaultProvide,
+ propsData,
+ });
+ };
+
+ afterEach(() => {
+ mockApollo = null;
+ });
+
+ describe('when API call is loading', () => {
+ beforeEach(() => {
+ const mockResolvers = {
+ Query: {
+ organization: jest.fn().mockReturnValueOnce(new Promise(() => {})),
+ },
+ };
+
+ createComponent({ mockResolvers });
+ });
+
+ it('renders loading icon', () => {
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ });
+ });
+
+ describe('when API call is successful', () => {
+ describe('when there are no groups', () => {
+ it('renders empty state without buttons by default', async () => {
+ const mockResolvers = {
+ Query: {
+ organization: jest.fn().mockResolvedValueOnce({
+ groups: { nodes: [] },
+ }),
+ },
+ };
+ createComponent({ mockResolvers });
+
+ jest.runAllTimers();
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({
+ title: "You don't have any groups yet.",
+ description:
+ 'A group is a collection of several projects. If you organize your projects under a group, it works like a folder.',
+ svgHeight: 144,
+ svgPath: defaultProvide.groupsEmptyStateSvgPath,
+ primaryButtonLink: null,
+ primaryButtonText: null,
+ });
+ });
+
+ describe('when `shouldShowEmptyStateButtons` is `true` and `groupsEmptyStateSvgPath` is set', () => {
+ it('renders empty state with buttons', async () => {
+ const mockResolvers = {
+ Query: {
+ organization: jest.fn().mockResolvedValueOnce({
+ groups: { nodes: [] },
+ }),
+ },
+ };
+ createComponent({ mockResolvers, propsData: { shouldShowEmptyStateButtons: true } });
+
+ jest.runAllTimers();
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({
+ primaryButtonLink: defaultProvide.newGroupPath,
+ primaryButtonText: 'New group',
+ });
+ });
+ });
+ });
+
+ describe('when there are groups', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders `GroupsList` component and passes correct props', async () => {
+ jest.runAllTimers();
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GroupsList).props()).toEqual({
+ groups: formatGroups(organizationGroups.nodes),
+ showGroupIcon: true,
+ });
+ });
+ });
+ });
+
+ describe('when API call is not successful', () => {
+ const error = new Error();
+
+ beforeEach(() => {
+ const mockResolvers = {
+ Query: {
+ organization: jest.fn().mockRejectedValueOnce(error),
+ },
+ };
+
+ createComponent({ mockResolvers });
+ });
+
+ it('displays error alert', async () => {
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: GroupsView.i18n.errorMessage,
+ error,
+ captureError: true,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/organizations/shared/components/projects_view_spec.js b/spec/frontend/organizations/shared/components/projects_view_spec.js
new file mode 100644
index 00000000000..490b0c89348
--- /dev/null
+++ b/spec/frontend/organizations/shared/components/projects_view_spec.js
@@ -0,0 +1,146 @@
+import VueApollo from 'vue-apollo';
+import Vue from 'vue';
+import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
+import ProjectsView from '~/organizations/shared/components/projects_view.vue';
+import { formatProjects } from '~/organizations/shared/utils';
+import resolvers from '~/organizations/shared/graphql/resolvers';
+import ProjectsList from '~/vue_shared/components/projects_list/projects_list.vue';
+import { createAlert } from '~/alert';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { organizationProjects } from '~/organizations/mock_data';
+
+jest.mock('~/alert');
+
+Vue.use(VueApollo);
+jest.useFakeTimers();
+
+describe('ProjectsView', () => {
+ let wrapper;
+ let mockApollo;
+
+ const defaultProvide = {
+ projectsEmptyStateSvgPath: 'illustrations/empty-state/empty-projects-md.svg',
+ newProjectPath: '/projects/new',
+ };
+
+ const createComponent = ({ mockResolvers = resolvers, propsData = {} } = {}) => {
+ mockApollo = createMockApollo([], mockResolvers);
+
+ wrapper = shallowMountExtended(ProjectsView, {
+ apolloProvider: mockApollo,
+ provide: defaultProvide,
+ propsData,
+ });
+ };
+
+ afterEach(() => {
+ mockApollo = null;
+ });
+
+ describe('when API call is loading', () => {
+ beforeEach(() => {
+ const mockResolvers = {
+ Query: {
+ organization: jest.fn().mockReturnValueOnce(new Promise(() => {})),
+ },
+ };
+
+ createComponent({ mockResolvers });
+ });
+
+ it('renders loading icon', () => {
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ });
+ });
+
+ describe('when API call is successful', () => {
+ describe('when there are no projects', () => {
+ it('renders empty state without buttons by default', async () => {
+ const mockResolvers = {
+ Query: {
+ organization: jest.fn().mockResolvedValueOnce({
+ projects: { nodes: [] },
+ }),
+ },
+ };
+ createComponent({ mockResolvers });
+
+ jest.runAllTimers();
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({
+ title: "You don't have any projects yet.",
+ description:
+ 'Projects are where you can store your code, access issues, wiki, and other features of Gitlab.',
+ svgHeight: 144,
+ svgPath: defaultProvide.projectsEmptyStateSvgPath,
+ primaryButtonLink: null,
+ primaryButtonText: null,
+ });
+ });
+
+ describe('when `shouldShowEmptyStateButtons` is `true` and `projectsEmptyStateSvgPath` is set', () => {
+ it('renders empty state with buttons', async () => {
+ const mockResolvers = {
+ Query: {
+ organization: jest.fn().mockResolvedValueOnce({
+ projects: { nodes: [] },
+ }),
+ },
+ };
+ createComponent({ mockResolvers, propsData: { shouldShowEmptyStateButtons: true } });
+
+ jest.runAllTimers();
+ await waitForPromises();
+
+ expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({
+ primaryButtonLink: defaultProvide.newProjectPath,
+ primaryButtonText: 'New project',
+ });
+ });
+ });
+ });
+
+ describe('when there are projects', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders `ProjectsList` component and passes correct props', async () => {
+ jest.runAllTimers();
+ await waitForPromises();
+
+ expect(wrapper.findComponent(ProjectsList).props()).toEqual({
+ projects: formatProjects(organizationProjects.nodes),
+ showProjectIcon: true,
+ });
+ });
+ });
+ });
+
+ describe('when API call is not successful', () => {
+ const error = new Error();
+
+ beforeEach(() => {
+ const mockResolvers = {
+ Query: {
+ organization: jest.fn().mockRejectedValueOnce(error),
+ },
+ };
+
+ createComponent({ mockResolvers });
+ });
+
+ it('displays error alert', async () => {
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: ProjectsView.i18n.errorMessage,
+ error,
+ captureError: true,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/organizations/shared/utils_spec.js b/spec/frontend/organizations/shared/utils_spec.js
new file mode 100644
index 00000000000..778a18ab2bc
--- /dev/null
+++ b/spec/frontend/organizations/shared/utils_spec.js
@@ -0,0 +1,39 @@
+import { formatProjects, formatGroups } from '~/organizations/shared/utils';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { organizationProjects, organizationGroups } from '~/organizations/mock_data';
+
+describe('formatProjects', () => {
+ it('correctly formats the projects', () => {
+ const [firstMockProject] = organizationProjects.nodes;
+ const formattedProjects = formatProjects(organizationProjects.nodes);
+ const [firstFormattedProject] = formattedProjects;
+
+ expect(firstFormattedProject).toMatchObject({
+ id: getIdFromGraphQLId(firstMockProject.id),
+ name: firstMockProject.nameWithNamespace,
+ permissions: {
+ projectAccess: {
+ accessLevel: firstMockProject.accessLevel.integerValue,
+ },
+ },
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+ });
+ expect(formattedProjects.length).toBe(organizationProjects.nodes.length);
+ });
+});
+
+describe('formatGroups', () => {
+ it('correctly formats the groups', () => {
+ const [firstMockGroup] = organizationGroups.nodes;
+ const formattedGroups = formatGroups(organizationGroups.nodes);
+ const [firstFormattedGroup] = formattedGroups;
+
+ expect(firstFormattedGroup).toMatchObject({
+ id: getIdFromGraphQLId(firstMockGroup.id),
+ editPath: `${firstFormattedGroup.webUrl}/-/edit`,
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+ });
+ expect(formattedGroups.length).toBe(organizationGroups.nodes.length);
+ });
+});
diff --git a/spec/frontend/organizations/show/components/app_spec.js b/spec/frontend/organizations/show/components/app_spec.js
new file mode 100644
index 00000000000..46496e40bdd
--- /dev/null
+++ b/spec/frontend/organizations/show/components/app_spec.js
@@ -0,0 +1,49 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import App from '~/organizations/show/components/app.vue';
+import OrganizationAvatar from '~/organizations/show/components/organization_avatar.vue';
+import GroupsAndProjects from '~/organizations/show/components/groups_and_projects.vue';
+import AssociationCount from '~/organizations/show/components/association_counts.vue';
+
+describe('OrganizationShowApp', () => {
+ let wrapper;
+
+ const defaultPropsData = {
+ organization: {
+ id: 1,
+ name: 'GitLab',
+ },
+ associationCounts: {
+ groups: 10,
+ projects: 5,
+ users: 6,
+ },
+ groupsAndProjectsOrganizationPath: '/-/organizations/default/groups_and_projects',
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(App, { propsData: defaultPropsData });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders organization avatar and passes organization prop', () => {
+ expect(wrapper.findComponent(OrganizationAvatar).props('organization')).toEqual(
+ defaultPropsData.organization,
+ );
+ });
+
+ it('renders groups and projects component and passes `groupsAndProjectsOrganizationPath` prop', () => {
+ expect(
+ wrapper.findComponent(GroupsAndProjects).props('groupsAndProjectsOrganizationPath'),
+ ).toEqual(defaultPropsData.groupsAndProjectsOrganizationPath);
+ });
+
+ it('renders associations count component and passes expected props', () => {
+ expect(wrapper.findComponent(AssociationCount).props()).toEqual({
+ associationCounts: defaultPropsData.associationCounts,
+ groupsAndProjectsOrganizationPath: defaultPropsData.groupsAndProjectsOrganizationPath,
+ });
+ });
+});
diff --git a/spec/frontend/organizations/show/components/association_count_card_spec.js b/spec/frontend/organizations/show/components/association_count_card_spec.js
new file mode 100644
index 00000000000..752a02110b6
--- /dev/null
+++ b/spec/frontend/organizations/show/components/association_count_card_spec.js
@@ -0,0 +1,48 @@
+import { GlCard, GlLink } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import AssociationCountCard from '~/organizations/show/components/association_count_card.vue';
+
+describe('AssociationCountCard', () => {
+ let wrapper;
+
+ const defaultPropsData = {
+ title: 'Groups',
+ iconName: 'group',
+ count: 1050,
+ linkHref: '/-/organizations/default/groups_and_projects?display=groups',
+ };
+
+ const createComponent = ({ propsData = {} } = {}) => {
+ wrapper = shallowMountExtended(AssociationCountCard, {
+ propsData: { ...defaultPropsData, ...propsData },
+ });
+ };
+
+ const findCard = () => wrapper.findComponent(GlCard);
+ const findLink = () => findCard().findComponent(GlLink);
+
+ it('renders card with title, link and count', () => {
+ createComponent();
+
+ const card = findCard();
+ const link = findLink();
+
+ expect(card.text()).toContain(defaultPropsData.title);
+ expect(card.text()).toContain('1k');
+ expect(link.text()).toBe('View all');
+ expect(link.attributes('href')).toBe(defaultPropsData.linkHref);
+ });
+
+ describe('when `linkText` prop is set', () => {
+ const linkText = 'Manage';
+ beforeEach(() => {
+ createComponent({
+ propsData: { linkText },
+ });
+ });
+
+ it('sets link text', () => {
+ expect(findLink().text()).toBe(linkText);
+ });
+ });
+});
diff --git a/spec/frontend/organizations/show/components/association_counts_spec.js b/spec/frontend/organizations/show/components/association_counts_spec.js
new file mode 100644
index 00000000000..80e57ede502
--- /dev/null
+++ b/spec/frontend/organizations/show/components/association_counts_spec.js
@@ -0,0 +1,61 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import AssociationCounts from '~/organizations/show/components/association_counts.vue';
+import AssociationCountCard from '~/organizations/show/components/association_count_card.vue';
+
+describe('AssociationCounts', () => {
+ let wrapper;
+
+ const defaultPropsData = {
+ associationCounts: {
+ groups: 10,
+ projects: 5,
+ users: 6,
+ },
+ groupsAndProjectsOrganizationPath: '/-/organizations/default/groups_and_projects',
+ };
+
+ const createComponent = ({ propsData = {} } = {}) => {
+ wrapper = shallowMountExtended(AssociationCounts, {
+ propsData: { ...defaultPropsData, ...propsData },
+ });
+ };
+
+ const findAssociationCountCardAt = (index) =>
+ wrapper.findAllComponents(AssociationCountCard).at(index);
+
+ it('renders groups association count card', () => {
+ createComponent();
+
+ expect(findAssociationCountCardAt(0).props()).toEqual({
+ title: 'Groups',
+ iconName: 'group',
+ count: defaultPropsData.associationCounts.groups,
+ linkText: 'View all',
+ linkHref: '/-/organizations/default/groups_and_projects?display=groups',
+ });
+ });
+
+ it('renders projects association count card', () => {
+ createComponent();
+
+ expect(findAssociationCountCardAt(1).props()).toEqual({
+ title: 'Projects',
+ iconName: 'project',
+ count: defaultPropsData.associationCounts.projects,
+ linkText: 'View all',
+ linkHref: '/-/organizations/default/groups_and_projects?display=projects',
+ });
+ });
+
+ it('renders users association count card', () => {
+ createComponent();
+
+ expect(findAssociationCountCardAt(2).props()).toEqual({
+ title: 'Users',
+ iconName: 'users',
+ count: defaultPropsData.associationCounts.users,
+ linkText: 'Manage',
+ linkHref: '/',
+ });
+ });
+});
diff --git a/spec/frontend/organizations/show/components/groups_and_projects_spec.js b/spec/frontend/organizations/show/components/groups_and_projects_spec.js
new file mode 100644
index 00000000000..83970d4e76d
--- /dev/null
+++ b/spec/frontend/organizations/show/components/groups_and_projects_spec.js
@@ -0,0 +1,106 @@
+import { GlCollapsibleListbox, GlLink } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import GroupsAndProjects from '~/organizations/show/components/groups_and_projects.vue';
+import { createRouter } from '~/organizations/show';
+import GroupsView from '~/organizations/shared/components/groups_view.vue';
+import ProjectsView from '~/organizations/shared/components/projects_view.vue';
+
+describe('OrganizationShowGroupsAndProjects', () => {
+ const router = createRouter();
+ const routerMock = {
+ push: jest.fn(),
+ };
+ const defaultPropsData = {
+ groupsAndProjectsOrganizationPath: '/-/organizations/default/groups_and_projects',
+ };
+
+ let wrapper;
+
+ const createComponent = ({ routeQuery = {} } = {}) => {
+ wrapper = shallowMountExtended(GroupsAndProjects, {
+ router,
+ mocks: { $route: { path: '/', query: routeQuery }, $router: routerMock },
+ propsData: defaultPropsData,
+ });
+ };
+
+ const findCollapsibleListbox = () => wrapper.findComponent(GlCollapsibleListbox);
+
+ it('renders listbox with expected props', () => {
+ createComponent();
+
+ expect(findCollapsibleListbox().props()).toMatchObject({
+ items: [
+ {
+ value: 'frequently_visited_projects',
+ text: 'Frequently visited projects',
+ },
+ {
+ value: 'frequently_visited_groups',
+ text: 'Frequently visited groups',
+ },
+ ],
+ selected: 'frequently_visited_projects',
+ });
+ });
+
+ describe.each`
+ displayQueryParam | expectedViewAllLinkQuery | expectedViewComponent | expectedDisplayListboxSelectedProp
+ ${'frequently_visited_projects'} | ${'?display=projects'} | ${ProjectsView} | ${'frequently_visited_projects'}
+ ${'frequently_visited_groups'} | ${'?display=groups'} | ${GroupsView} | ${'frequently_visited_groups'}
+ ${'unsupported'} | ${'?display=projects'} | ${ProjectsView} | ${'frequently_visited_projects'}
+ `(
+ 'when display query param is $displayQueryParam',
+ ({
+ displayQueryParam,
+ expectedViewAllLinkQuery,
+ expectedViewComponent,
+ expectedDisplayListboxSelectedProp,
+ }) => {
+ beforeEach(() => {
+ createComponent({ routeQuery: { display: displayQueryParam } });
+ });
+
+ it('sets listbox `selected` prop correctly', () => {
+ expect(findCollapsibleListbox().props('selected')).toBe(expectedDisplayListboxSelectedProp);
+ });
+
+ it('renders "View all" link with correct href', () => {
+ expect(wrapper.findComponent(GlLink).attributes('href')).toBe(
+ `${defaultPropsData.groupsAndProjectsOrganizationPath}${expectedViewAllLinkQuery}`,
+ );
+ });
+
+ it('renders expected view', () => {
+ expect(
+ wrapper.findComponent(expectedViewComponent).props('shouldShowEmptyStateButtons'),
+ ).toBe(true);
+ });
+ },
+ );
+
+ it('renders label and associates listbox with it', () => {
+ createComponent();
+
+ const expectedId = 'display-listbox-label';
+
+ expect(wrapper.findByTestId('label').attributes('id')).toBe(expectedId);
+ expect(findCollapsibleListbox().props('toggleAriaLabelledBy')).toBe(expectedId);
+ });
+
+ describe('when listbox item is selected', () => {
+ const selectValue = 'frequently_visited_groups';
+
+ beforeEach(() => {
+ createComponent();
+
+ findCollapsibleListbox().vm.$emit('select', selectValue);
+ });
+
+ it('updates `display` query param', () => {
+ expect(routerMock.push).toHaveBeenCalledWith({
+ query: { display: selectValue },
+ });
+ });
+ });
+});
diff --git a/spec/frontend/organizations/show/components/organization_avatar_spec.js b/spec/frontend/organizations/show/components/organization_avatar_spec.js
new file mode 100644
index 00000000000..c98fa14e49b
--- /dev/null
+++ b/spec/frontend/organizations/show/components/organization_avatar_spec.js
@@ -0,0 +1,64 @@
+import { GlAvatar, GlIcon } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import OrganizationAvatar from '~/organizations/show/components/organization_avatar.vue';
+import {
+ VISIBILITY_TYPE_ICON,
+ ORGANIZATION_VISIBILITY_TYPE,
+ VISIBILITY_LEVEL_PUBLIC_STRING,
+} from '~/visibility_level/constants';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+describe('OrganizationAvatar', () => {
+ let wrapper;
+
+ const defaultPropsData = {
+ organization: {
+ id: 1,
+ name: 'GitLab',
+ },
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(OrganizationAvatar, {
+ propsData: defaultPropsData,
+ directives: {
+ GlTooltip: createMockDirective('gl-tooltip'),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders avatar', () => {
+ expect(wrapper.findComponent(GlAvatar).props()).toMatchObject({
+ entityId: defaultPropsData.organization.id,
+ entityName: defaultPropsData.organization.name,
+ });
+ });
+
+ it('renders organization name', () => {
+ expect(
+ wrapper.findByRole('heading', { name: defaultPropsData.organization.name }).exists(),
+ ).toBe(true);
+ });
+
+ it('renders visibility icon', () => {
+ const icon = wrapper.findComponent(GlIcon);
+ const tooltip = getBinding(icon.element, 'gl-tooltip');
+
+ expect(icon.props('name')).toBe(VISIBILITY_TYPE_ICON[VISIBILITY_LEVEL_PUBLIC_STRING]);
+ expect(tooltip.value).toBe(ORGANIZATION_VISIBILITY_TYPE[VISIBILITY_LEVEL_PUBLIC_STRING]);
+ });
+
+ it('renders button to copy organization ID', () => {
+ expect(wrapper.findComponent(ClipboardButton).props()).toMatchObject({
+ category: 'tertiary',
+ title: 'Copy organization ID',
+ text: '1',
+ size: 'small',
+ });
+ });
+});
diff --git a/spec/frontend/organizations/show/utils_spec.js b/spec/frontend/organizations/show/utils_spec.js
new file mode 100644
index 00000000000..583f105c8c0
--- /dev/null
+++ b/spec/frontend/organizations/show/utils_spec.js
@@ -0,0 +1,20 @@
+import { buildDisplayListboxItem } from '~/organizations/show/utils';
+import { RESOURCE_TYPE_PROJECTS } from '~/organizations/constants';
+import { FILTER_FREQUENTLY_VISITED } from '~/organizations/show/constants';
+
+describe('buildDisplayListboxItem', () => {
+ it('returns list item in correct format', () => {
+ const text = 'Frequently visited projects';
+
+ expect(
+ buildDisplayListboxItem({
+ filter: FILTER_FREQUENTLY_VISITED,
+ resourceType: RESOURCE_TYPE_PROJECTS,
+ text,
+ }),
+ ).toEqual({
+ text,
+ value: 'frequently_visited_projects',
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap
index 5f191ef5561..771fb9e4e08 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/__snapshots__/tags_loader_spec.js.snap
@@ -10,7 +10,6 @@ exports[`TagsLoader component has the correct markup 1`] = `
x="0"
y="12.5"
/>
-
<rect
height="20"
rx="4"
@@ -18,13 +17,11 @@ exports[`TagsLoader component has the correct markup 1`] = `
x="25"
y="10"
/>
-
<circle
cx="290"
cy="20"
r="10"
/>
-
<rect
height="20"
rx="4"
@@ -32,7 +29,6 @@ exports[`TagsLoader component has the correct markup 1`] = `
x="315"
y="10"
/>
-
<rect
height="20"
rx="4"
@@ -40,7 +36,6 @@ exports[`TagsLoader component has the correct markup 1`] = `
x="500"
y="10"
/>
-
<rect
height="20"
rx="4"
@@ -48,7 +43,6 @@ exports[`TagsLoader component has the correct markup 1`] = `
x="630"
y="10"
/>
-
<rect
height="40"
rx="4"
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap
index 56579847468..3e136c750cd 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/group_empty_state_spec.js.snap
@@ -3,7 +3,7 @@
exports[`Registry Group Empty state to match the default snapshot 1`] = `
<div>
<p>
- With the Container Registry, every project can have its own space to store its Docker images. Push at least one Docker image in one of this group's projects in order to show up here.
+ With the Container Registry, every project can have its own space to store its Docker images. Push at least one Docker image in one of this group's projects in order to show up here.
<gl-link-stub
href="baz"
target="_blank"
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap
index 4b52e84d1a6..5a6d84734a0 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/__snapshots__/project_empty_state_spec.js.snap
@@ -3,7 +3,7 @@
exports[`Registry Project Empty state to match the default snapshot 1`] = `
<div>
<p>
- With the Container Registry, every project can have its own space to store its Docker images.
+ With the Container Registry, every project can have its own space to store its Docker images.
<gl-link-stub
href="baz"
target="_blank"
@@ -11,29 +11,26 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
More Information
</gl-link-stub>
</p>
-
<h5>
CLI Commands
</h5>
-
<p>
- If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have
+ If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have
<gl-link-stub
href="barBaz"
target="_blank"
>
Two-Factor Authentication
</gl-link-stub>
- enabled, use a
+ enabled, use a
<gl-link-stub
href="fooBaz"
target="_blank"
>
Personal Access Token
</gl-link-stub>
- instead of a password.
+ instead of a password.
</p>
-
<gl-form-input-group-stub
class="gl-mb-4"
inputclass=""
@@ -47,15 +44,11 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
value="bazbaz"
/>
</gl-form-input-group-stub>
-
<p
class="gl-mb-4"
>
-
- You can add an image to this registry with the following commands:
-
+ You can add an image to this registry with the following commands:
</p>
-
<gl-form-input-group-stub
class="gl-mb-4"
inputclass=""
@@ -69,7 +62,6 @@ exports[`Registry Project Empty state to match the default snapshot 1`] = `
value="foofoo"
/>
</gl-form-input-group-stub>
-
<gl-form-input-group-stub
inputclass=""
predefinedoptions="[object Object]"
diff --git a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
index f590cff0312..dd70fca9dd2 100644
--- a/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
+++ b/spec/frontend/packages_and_registries/dependency_proxy/app_spec.js
@@ -1,12 +1,12 @@
import {
GlAlert,
- GlDropdown,
- GlDropdownItem,
GlFormInputGroup,
GlFormGroup,
GlModal,
GlSprintf,
GlSkeletonLoader,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
} from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
@@ -18,12 +18,13 @@ import waitForPromises from 'helpers/wait_for_promises';
import { GRAPHQL_PAGE_SIZE } from '~/packages_and_registries/dependency_proxy/constants';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_ACCEPTED } from '~/lib/utils/http_status';
-
+import setWindowLocation from 'helpers/set_window_location_helper';
+import { TEST_HOST } from 'helpers/test_constants';
import DependencyProxyApp from '~/packages_and_registries/dependency_proxy/app.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import ManifestsList from '~/packages_and_registries/dependency_proxy/components/manifests_list.vue';
-
+import createRouter from '~/packages_and_registries/dependency_proxy/router';
import getDependencyProxyDetailsQuery from '~/packages_and_registries/dependency_proxy/graphql/queries/get_dependency_proxy_details.query.graphql';
import { proxyDetailsQuery, proxyData, pagination, proxyManifests } from './mock_data';
@@ -37,6 +38,7 @@ Vue.use(VueApollo);
describe('DependencyProxyApp', () => {
let wrapper;
+ let router;
let apolloProvider;
let resolver;
let mock;
@@ -53,15 +55,14 @@ describe('DependencyProxyApp', () => {
const requestHandlers = [[getDependencyProxyDetailsQuery, resolver]];
apolloProvider = createMockApollo(requestHandlers);
+ router = createRouter('/');
wrapper = shallowMountExtended(DependencyProxyApp, {
apolloProvider,
provide,
+ router,
stubs: {
GlAlert,
- GlDropdown,
- GlDropdownItem,
- GlFormInputGroup,
GlFormGroup,
GlModal,
GlSprintf,
@@ -79,7 +80,7 @@ describe('DependencyProxyApp', () => {
const findProxyCountText = () => wrapper.findByTestId('proxy-count');
const findManifestList = () => wrapper.findComponent(ManifestsList);
const findLoader = () => wrapper.findComponent(GlSkeletonLoader);
- const findClearCacheDropdownList = () => wrapper.findComponent(GlDropdown);
+ const findClearCacheDropdownList = () => wrapper.findComponent(GlDisclosureDropdown);
const findClearCacheModal = () => wrapper.findComponent(GlModal);
const findClearCacheAlert = () => wrapper.findComponent(GlAlert);
const findSettingsLink = () => wrapper.findByTestId('settings-link');
@@ -94,6 +95,7 @@ describe('DependencyProxyApp', () => {
mock = new MockAdapter(axios);
mock.onDelete(expectedUrl).reply(HTTP_STATUS_ACCEPTED, {});
+ setWindowLocation(TEST_HOST);
});
afterEach(() => {
@@ -123,6 +125,13 @@ describe('DependencyProxyApp', () => {
return waitForPromises();
});
+ it('resolver is called with right arguments', () => {
+ expect(resolver).toHaveBeenCalledWith({
+ first: GRAPHQL_PAGE_SIZE,
+ fullPath: provideDefaults.groupPath,
+ });
+ });
+
it('renders a form group with a label', () => {
expect(findFormGroup().attributes('label')).toBe(
DependencyProxyApp.i18n.proxyImagePrefix,
@@ -225,6 +234,7 @@ describe('DependencyProxyApp', () => {
fullPath: provideDefaults.groupPath,
last: GRAPHQL_PAGE_SIZE,
});
+ expect(window.location.search).toBe(`?before=${pagination().startCursor}`);
});
});
@@ -252,6 +262,7 @@ describe('DependencyProxyApp', () => {
first: GRAPHQL_PAGE_SIZE,
fullPath: provideDefaults.groupPath,
});
+ expect(window.location.search).toBe(`?after=${pagination().endCursor}`);
});
});
@@ -270,7 +281,7 @@ describe('DependencyProxyApp', () => {
expect(findClearCacheDropdownList().exists()).toBe(true);
const clearCacheDropdownItem = findClearCacheDropdownList().findComponent(
- GlDropdownItem,
+ GlDisclosureDropdownItem,
);
expect(clearCacheDropdownItem.text()).toBe('Clear cache');
@@ -315,6 +326,48 @@ describe('DependencyProxyApp', () => {
});
});
});
+
+ describe('pagination params', () => {
+ it('after is set from the url params', async () => {
+ setWindowLocation('?after=1234');
+ createComponent();
+ await waitForPromises();
+
+ expect(resolver).toHaveBeenCalledWith({
+ first: GRAPHQL_PAGE_SIZE,
+ after: '1234',
+ fullPath: provideDefaults.groupPath,
+ });
+ });
+
+ it('before is set from the url params', async () => {
+ setWindowLocation('?before=1234');
+ createComponent();
+ await waitForPromises();
+
+ expect(resolver).toHaveBeenCalledWith({
+ first: null,
+ last: GRAPHQL_PAGE_SIZE,
+ before: '1234',
+ fullPath: provideDefaults.groupPath,
+ });
+ });
+
+ describe('when url params are changed', () => {
+ it('after is set from the url params', async () => {
+ createComponent();
+ await waitForPromises();
+ router.push('?after=1234');
+ await waitForPromises();
+
+ expect(resolver).toHaveBeenCalledWith({
+ first: GRAPHQL_PAGE_SIZE,
+ after: '1234',
+ fullPath: provideDefaults.groupPath,
+ });
+ });
+ });
+ });
});
});
});
diff --git a/spec/frontend/packages_and_registries/dependency_proxy/utils_spec.js b/spec/frontend/packages_and_registries/dependency_proxy/utils_spec.js
new file mode 100644
index 00000000000..72072c08537
--- /dev/null
+++ b/spec/frontend/packages_and_registries/dependency_proxy/utils_spec.js
@@ -0,0 +1,25 @@
+import { getPageParams } from '~/packages_and_registries/dependency_proxy/utils';
+
+describe('getPageParams', () => {
+ it('should return the previous page params if before cursor is available', () => {
+ const pageInfo = { before: 'abc123' };
+ expect(getPageParams(pageInfo)).toEqual({
+ first: null,
+ before: pageInfo.before,
+ last: 20,
+ });
+ });
+
+ it('should return the next page params if after cursor is available', () => {
+ const pageInfo = { after: 'abc123' };
+ expect(getPageParams(pageInfo)).toEqual({
+ after: pageInfo.after,
+ first: 20,
+ });
+ });
+
+ it('should return an empty object if both before and after cursors are not available', () => {
+ const pageInfo = {};
+ expect(getPageParams(pageInfo)).toEqual({});
+ });
+});
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/file_sha_spec.js.snap b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/file_sha_spec.js.snap
index f95564e3fad..8e757c136ec 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/file_sha_spec.js.snap
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/file_sha_spec.js.snap
@@ -2,18 +2,13 @@
exports[`FileSha renders 1`] = `
<div
- class="gl-display-flex gl-align-items-center gl-font-monospace gl-font-sm gl-word-break-all gl-py-2 gl-border-b-solid gl-border-gray-100 gl-border-b-1"
+ class="gl-align-items-center gl-border-b-1 gl-border-b-solid gl-border-gray-100 gl-display-flex gl-font-monospace gl-font-sm gl-py-2 gl-word-break-all"
>
- <!---->
-
<span>
<div
class="gl-px-4"
>
-
- bar:
- foo
-
+ bar: foo
<gl-button-stub
aria-label="Copy SHA"
aria-live="polite"
@@ -22,7 +17,7 @@ exports[`FileSha renders 1`] = `
data-clipboard-handle-tooltip="false"
data-clipboard-text="foo"
icon="copy-to-clipboard"
- id="clipboard-button-1"
+ id="reference-0"
size="small"
title="Copy SHA"
variant="default"
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/terraform_installation_spec.js.snap b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/terraform_installation_spec.js.snap
index 03236737572..30fe6544057 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/terraform_installation_spec.js.snap
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/__snapshots__/terraform_installation_spec.js.snap
@@ -7,7 +7,6 @@ exports[`TerraformInstallation renders all the messages 1`] = `
>
Provision instructions
</h3>
-
<code-instruction-stub
copytext="Copy Terraform Command"
instruction="module \\"my_module_name\\" {
@@ -19,13 +18,11 @@ exports[`TerraformInstallation renders all the messages 1`] = `
trackingaction=""
trackinglabel=""
/>
-
<h3
class="gl-font-lg"
>
Registry setup
</h3>
-
<code-instruction-stub
copytext="Copy Terraform Setup Command"
instruction="credentials \\"bar.dev\\" {
@@ -36,7 +33,6 @@ exports[`TerraformInstallation renders all the messages 1`] = `
trackingaction=""
trackinglabel=""
/>
-
<gl-sprintf-stub
message="For more information on the Terraform registry, %{linkStart}see our documentation%{linkEnd}."
/>
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap
index d0841c6110f..7f26ed778a5 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/__snapshots__/packages_list_app_spec.js.snap
@@ -6,12 +6,10 @@ exports[`packages_list_app renders 1`] = `
count="1"
helpurl="foo"
/>
-
<infrastructure-search-stub />
-
<div>
<section
- class="gl-display-flex empty-state gl-text-center gl-flex-direction-column"
+ class="empty-state gl-display-flex gl-flex-direction-column gl-text-center"
>
<div
class="gl-max-w-full"
@@ -21,15 +19,14 @@ exports[`packages_list_app renders 1`] = `
>
<img
alt=""
- class="gl-max-w-full gl-dark-invert-keep-hue"
+ class="gl-dark-invert-keep-hue gl-max-w-full"
role="img"
src="helpSvg"
/>
</div>
</div>
-
<div
- class="gl-max-w-full gl-m-auto"
+ class="gl-m-auto gl-max-w-full"
data-testid="gl-empty-state-content"
>
<div
@@ -38,15 +35,12 @@ exports[`packages_list_app renders 1`] = `
<h1
class="gl-font-size-h-display gl-line-height-36 h4"
>
-
- There are no packages yet
-
+ There are no packages yet
</h1>
-
<p
class="gl-mt-3"
>
- Learn how to
+ Learn how to
<b-link-stub
class="gl-link"
href="helpUrl"
@@ -54,16 +48,11 @@ exports[`packages_list_app renders 1`] = `
>
publish and share your packages
</b-link-stub>
- with GitLab.
+ with GitLab.
</p>
-
<div
class="gl-display-flex gl-flex-wrap gl-justify-content-center"
- >
- <!---->
-
- <!---->
- </div>
+ />
</div>
</div>
</section>
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap
index 250b33cbb14..edba81da1f5 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/__snapshots__/package_list_row_spec.js.snap
@@ -2,28 +2,26 @@
exports[`packages_list_row renders 1`] = `
<div
- class="gl-display-flex gl-flex-direction-column gl-border-b-solid gl-border-t-solid gl-border-t-1 gl-border-b-1 gl-border-t-transparent gl-border-b-gray-100"
+ class="gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-border-t-1 gl-border-t-solid gl-border-t-transparent gl-display-flex gl-flex-direction-column"
data-testid="package-row"
>
<div
- class="gl-display-flex gl-align-items-center gl-py-3"
+ class="gl-align-items-center gl-display-flex gl-py-3"
>
- <!---->
-
<div
- class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-grow-1"
+ class="gl-align-items-stretch gl-display-flex gl-flex-grow-1 gl-justify-content-space-between gl-xs-flex-direction-column"
>
<div
- class="gl-display-flex gl-flex-direction-column gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1"
+ class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-min-w-0 gl-xs-mb-3"
>
<div
- class="gl-display-flex gl-align-items-center gl-text-body gl-font-weight-bold gl-min-h-6 gl-min-w-0"
+ class="gl-align-items-center gl-display-flex gl-font-weight-bold gl-min-h-6 gl-min-w-0 gl-text-body"
>
<div
- class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0"
+ class="gl-align-items-center gl-display-flex gl-min-w-0 gl-mr-3"
>
<gl-link-stub
- class="gl-text-body gl-min-w-0"
+ class="gl-min-w-0 gl-text-body"
data-testid="details-link"
href="foo"
>
@@ -32,17 +30,10 @@ exports[`packages_list_row renders 1`] = `
text="Test package"
/>
</gl-link-stub>
-
- <!---->
-
- <!---->
</div>
-
- <!---->
</div>
-
<div
- class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-grow-1"
+ class="gl-align-items-center gl-display-flex gl-flex-grow-1 gl-min-h-6 gl-min-w-0 gl-text-gray-500"
>
<div
class="gl-display-flex"
@@ -50,31 +41,25 @@ exports[`packages_list_row renders 1`] = `
<span>
1.0.0
</span>
-
- <!---->
-
<div />
-
<package-path-stub
path="foo/bar/baz"
/>
</div>
</div>
</div>
-
<div
- class="gl-display-flex gl-flex-direction-column gl-sm-align-items-flex-end gl-justify-content-space-between gl-text-gray-500 gl-flex-shrink-0"
+ class="gl-display-flex gl-flex-direction-column gl-flex-shrink-0 gl-justify-content-space-between gl-sm-align-items-flex-end gl-text-gray-500"
>
<div
- class="gl-display-flex gl-align-items-center gl-sm-text-body gl-sm-font-weight-bold gl-min-h-6"
+ class="gl-align-items-center gl-display-flex gl-min-h-6 gl-sm-font-weight-bold gl-sm-text-body"
>
<publish-method-stub
packageentity="[object Object]"
/>
</div>
-
<div
- class="gl-display-flex gl-align-items-center gl-min-h-6"
+ class="gl-align-items-center gl-display-flex gl-min-h-6"
>
<span>
<gl-sprintf-stub
@@ -84,9 +69,8 @@ exports[`packages_list_row renders 1`] = `
</div>
</div>
</div>
-
<div
- class="gl-w-9 gl-display-flex gl-justify-content-end gl-pr-1"
+ class="gl-display-flex gl-justify-content-end gl-pr-1 gl-w-9"
>
<gl-button-stub
aria-label="Remove package"
@@ -100,7 +84,5 @@ exports[`packages_list_row renders 1`] = `
/>
</div>
</div>
-
- <!---->
</div>
`;
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/conan_installation_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/conan_installation_spec.js.snap
index b3d0d88be4d..cfdaebd889d 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/conan_installation_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/conan_installation_spec.js.snap
@@ -6,7 +6,6 @@ exports[`ConanInstallation renders all the messages 1`] = `
options="[object Object]"
packagetype="conan"
/>
-
<code-instruction-stub
copytext="Copy Conan Command"
instruction="conan install @gitlab-org/package-15 --remote=gitlab"
@@ -14,13 +13,11 @@ exports[`ConanInstallation renders all the messages 1`] = `
trackingaction="copy_conan_command"
trackinglabel="code_instruction"
/>
-
<h3
class="gl-font-lg"
>
Registry setup
</h3>
-
<code-instruction-stub
copytext="Copy Conan Setup Command"
instruction="conan remote add gitlab http://gdk.test:3000/api/v4/projects/1/packages/conan"
@@ -28,7 +25,7 @@ exports[`ConanInstallation renders all the messages 1`] = `
trackingaction="copy_conan_setup_command"
trackinglabel="code_instruction"
/>
- For more information on the Conan registry,
+ For more information on the Conan registry,
<gl-link-stub
href="/help/user/packages/conan_repository/index"
target="_blank"
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/dependency_row_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/dependency_row_spec.js.snap
index f83df7b11f4..37401786d21 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/dependency_row_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/dependency_row_spec.js.snap
@@ -5,25 +5,21 @@ exports[`DependencyRow renders full dependency 1`] = `
class="gl-responsive-table-row"
>
<div
- class="table-section section-50"
+ class="section-50 table-section"
>
<strong
class="gl-text-body"
>
Ninject.Extensions.Factory
</strong>
-
<span
data-testid="target-framework"
>
-
(.NETCoreApp3.1)
-
</span>
</div>
-
<div
- class="table-section section-50 gl-display-flex gl-md-justify-content-end"
+ class="gl-display-flex gl-md-justify-content-end section-50 table-section"
data-testid="version-pattern"
>
<span
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/file_sha_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/file_sha_spec.js.snap
index f95564e3fad..8e757c136ec 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/file_sha_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/file_sha_spec.js.snap
@@ -2,18 +2,13 @@
exports[`FileSha renders 1`] = `
<div
- class="gl-display-flex gl-align-items-center gl-font-monospace gl-font-sm gl-word-break-all gl-py-2 gl-border-b-solid gl-border-gray-100 gl-border-b-1"
+ class="gl-align-items-center gl-border-b-1 gl-border-b-solid gl-border-gray-100 gl-display-flex gl-font-monospace gl-font-sm gl-py-2 gl-word-break-all"
>
- <!---->
-
<span>
<div
class="gl-px-4"
>
-
- bar:
- foo
-
+ bar: foo
<gl-button-stub
aria-label="Copy SHA"
aria-live="polite"
@@ -22,7 +17,7 @@ exports[`FileSha renders 1`] = `
data-clipboard-handle-tooltip="false"
data-clipboard-text="foo"
icon="copy-to-clipboard"
- id="clipboard-button-1"
+ id="reference-0"
size="small"
title="Copy SHA"
variant="default"
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/maven_installation_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/maven_installation_spec.js.snap
index 9b429c39faa..23cdf4864de 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/maven_installation_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/maven_installation_spec.js.snap
@@ -6,7 +6,6 @@ exports[`MavenInstallation groovy renders all the messages 1`] = `
options="[object Object],[object Object],[object Object]"
packagetype="maven"
/>
-
<code-instruction-stub
class="gl-mb-5"
copytext="Copy Gradle Groovy DSL install command"
@@ -15,7 +14,6 @@ exports[`MavenInstallation groovy renders all the messages 1`] = `
trackingaction="copy_gradle_install_command"
trackinglabel="code_instruction"
/>
-
<code-instruction-stub
copytext="Copy add Gradle Groovy DSL repository command"
instruction="maven {
@@ -35,7 +33,6 @@ exports[`MavenInstallation kotlin renders all the messages 1`] = `
options="[object Object],[object Object],[object Object]"
packagetype="maven"
/>
-
<code-instruction-stub
class="gl-mb-5"
copytext="Copy Gradle Kotlin DSL install command"
@@ -44,7 +41,6 @@ exports[`MavenInstallation kotlin renders all the messages 1`] = `
trackingaction="copy_kotlin_install_command"
trackinglabel="code_instruction"
/>
-
<code-instruction-stub
copytext="Copy add Gradle Kotlin DSL repository command"
instruction="maven(\\"http://gdk.test:3000/api/v4/projects/1/packages/maven\\")"
@@ -62,81 +58,72 @@ exports[`MavenInstallation maven renders all the messages 1`] = `
options="[object Object],[object Object],[object Object]"
packagetype="maven"
/>
-
<p>
- Copy and paste this inside your
+ Copy and paste this inside your
<code>
pom.xml
</code>
-
<code>
dependencies
</code>
- block.
+ block.
</p>
-
<code-instruction-stub
copytext="Copy Maven XML"
- instruction="<dependency>
- <groupId>appGroup</groupId>
- <artifactId>appName</artifactId>
- <version>appVersion</version>
-</dependency>"
+ instruction=<dependency>
+ <groupid>
+ appGroup
+ </groupid>
+ <artifactid>
+ appName
+ </artifactid>
+ <version>
+ appVersion
+ </version>
+ </dependency>
label=""
multiline="true"
trackingaction="copy_maven_xml"
trackinglabel="code_instruction"
/>
-
<code-instruction-stub
- class="gl-w-20 gl-mt-5"
+ class="gl-mt-5 gl-w-20"
copytext="Copy Maven command"
instruction="mvn install"
label="Maven Command"
trackingaction="copy_maven_command"
trackinglabel="code_instruction"
/>
-
<h3
class="gl-font-lg"
>
Registry setup
</h3>
-
<p>
- If you haven't already done so, you will need to add the below to your
+ If you haven't already done so, you will need to add the below to your
<code>
pom.xml
</code>
- file.
+ file.
</p>
-
<code-instruction-stub
copytext="Copy Maven registry XML"
- instruction="<repositories>
- <repository>
- <id>gitlab-maven</id>
- <url>http://gdk.test:3000/api/v4/projects/1/packages/maven</url>
- </repository>
-</repositories>
-
-<distributionManagement>
- <repository>
- <id>gitlab-maven</id>
- <url>http://gdk.test:3000/api/v4/projects/1/packages/maven</url>
- </repository>
-
- <snapshotRepository>
- <id>gitlab-maven</id>
- <url>http://gdk.test:3000/api/v4/projects/1/packages/maven</url>
- </snapshotRepository>
-</distributionManagement>"
+ instruction=<repositories>
+ <repository>
+ <id>
+ gitlab-maven
+ </id>
+ <url>
+ http://gdk.test:3000/api/v4/projects/1/packages/maven
+ </url>
+ </repository>
+ </repositories>
label=""
multiline="true"
trackingaction="copy_maven_setup_xml"
trackinglabel="code_instruction"
/>
- For more information on the Maven registry,
+ For more information on the Maven registry,
<gl-link-stub
href="/help/user/packages/maven_repository/index"
target="_blank"
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/npm_installation_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/npm_installation_spec.js.snap
index 4520ae9c328..7e36bfb5dc0 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/npm_installation_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/npm_installation_spec.js.snap
@@ -6,7 +6,6 @@ exports[`NpmInstallation renders all the messages 1`] = `
options="[object Object],[object Object]"
packagetype="npm"
/>
-
<code-instruction-stub
copytext="Copy npm command"
instruction="npm i @gitlab-org/package-15"
@@ -14,13 +13,11 @@ exports[`NpmInstallation renders all the messages 1`] = `
trackingaction="copy_npm_install_command"
trackinglabel="code_instruction"
/>
-
<h3
class="gl-font-lg"
>
Registry setup
</h3>
-
<gl-form-radio-group-stub
checked="instance"
disabledfield="disabled"
@@ -29,7 +26,6 @@ exports[`NpmInstallation renders all the messages 1`] = `
textfield="text"
valuefield="value"
/>
-
<code-instruction-stub
copytext="Copy npm setup command"
instruction="echo @gitlab-org:registry=npmInstanceUrl/ >> .npmrc"
@@ -37,13 +33,13 @@ exports[`NpmInstallation renders all the messages 1`] = `
trackingaction="copy_npm_setup_command"
trackinglabel="code_instruction"
/>
- You may also need to setup authentication using an auth token.
+ You may also need to setup authentication using an auth token.
<gl-link-stub
href="/help/user/packages/npm_registry/index"
target="_blank"
>
See the documentation
</gl-link-stub>
- to find out more.
+ to find out more.
</div>
`;
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/nuget_installation_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/nuget_installation_spec.js.snap
index 92930a6309a..554d4e08523 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/nuget_installation_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/nuget_installation_spec.js.snap
@@ -6,7 +6,6 @@ exports[`NugetInstallation renders all the messages 1`] = `
options="[object Object]"
packagetype="nuget"
/>
-
<code-instruction-stub
copytext="Copy NuGet Command"
instruction="nuget install @gitlab-org/package-15 -Source \\"GitLab\\""
@@ -14,13 +13,11 @@ exports[`NugetInstallation renders all the messages 1`] = `
trackingaction="copy_nuget_install_command"
trackinglabel="code_instruction"
/>
-
<h3
class="gl-font-lg"
>
Registry setup
</h3>
-
<code-instruction-stub
copytext="Copy NuGet Setup Command"
instruction="nuget source Add -Name \\"GitLab\\" -Source \\"http://gdk.test:3000/api/v4/projects/1/packages/nuget/index.json\\" -UserName <your_username> -Password <your_token>"
@@ -28,7 +25,7 @@ exports[`NugetInstallation renders all the messages 1`] = `
trackingaction="copy_nuget_setup_command"
trackinglabel="code_instruction"
/>
- For more information on the NuGet registry,
+ For more information on the NuGet registry,
<gl-link-stub
href="/help/user/packages/nuget_repository/index"
target="_blank"
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/pypi_installation_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/pypi_installation_spec.js.snap
index 99ee6ce01b2..05a5a718e52 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/pypi_installation_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/pypi_installation_spec.js.snap
@@ -3,45 +3,37 @@
exports[`PypiInstallation renders all the messages 1`] = `
<div>
<div
- class="gl-display-flex gl-justify-content-space-between gl-align-items-center"
+ class="gl-align-items-center gl-display-flex gl-justify-content-space-between"
>
<h3
class="gl-font-lg"
>
Installation
</h3>
-
<div>
<div
class="gl-new-dropdown"
>
<button
- aria-controls="base-dropdown-10"
+ aria-controls="reference-1"
aria-haspopup="listbox"
- aria-labelledby="dropdown-toggle-btn-8"
+ aria-labelledby="reference-0"
class="btn btn-default btn-md gl-button gl-new-dropdown-toggle"
data-testid="base-dropdown-toggle"
- id="dropdown-toggle-btn-8"
+ id="reference-0"
type="button"
>
- <!---->
-
- <!---->
-
<span
class="gl-button-text"
>
<span
class="gl-new-dropdown-button-text"
>
-
- Show PyPi commands
-
+ Show PyPi commands
</span>
-
<svg
aria-hidden="true"
- class="gl-button-icon gl-new-dropdown-chevron gl-icon s16"
+ class="gl-button-icon gl-icon gl-new-dropdown-chevron s16"
data-testid="chevron-down-icon"
role="img"
>
@@ -51,24 +43,18 @@ exports[`PypiInstallation renders all the messages 1`] = `
</svg>
</span>
</button>
-
<div
class="gl-new-dropdown-panel gl-w-31!"
data-testid="base-dropdown-menu"
- id="base-dropdown-10"
+ id="reference-1"
>
<div
class="gl-new-dropdown-inner"
>
-
- <!---->
-
- <!---->
-
<ul
- aria-labelledby="dropdown-toggle-btn-8"
- class="gl-new-dropdown-contents gl-new-dropdown-contents-with-scrim-overlay gl-new-dropdown-contents"
- id="listbox-9"
+ aria-labelledby="reference-0"
+ class="gl-new-dropdown-contents gl-new-dropdown-contents-with-scrim-overlay"
+ id="reference-2"
role="listbox"
tabindex="-1"
>
@@ -81,11 +67,9 @@ exports[`PypiInstallation renders all the messages 1`] = `
class="top-scrim top-scrim-light"
/>
</li>
-
<li
aria-hidden="true"
/>
-
<li
aria-selected="true"
class="gl-new-dropdown-item"
@@ -94,11 +78,11 @@ exports[`PypiInstallation renders all the messages 1`] = `
tabindex="-1"
>
<span
- class="gl-new-dropdown-item-content gl-bg-gray-50!"
+ class="gl-bg-gray-50! gl-new-dropdown-item-content"
>
<svg
aria-hidden="true"
- class="gl-icon s16 gl-new-dropdown-item-check-icon gl-mt-3 gl-align-self-start"
+ class="gl-align-self-start gl-icon gl-mt-3 gl-new-dropdown-item-check-icon s16"
data-testid="dropdown-item-checkbox"
role="img"
>
@@ -106,25 +90,16 @@ exports[`PypiInstallation renders all the messages 1`] = `
href="file-mock#mobile-issue-close"
/>
</svg>
-
<span
class="gl-new-dropdown-item-text-wrapper"
>
-
- Show PyPi commands
-
+ Show PyPi commands
</span>
</span>
</li>
-
- <!---->
-
- <!---->
-
<li
aria-hidden="true"
/>
-
<li
aria-hidden="true"
class="bottom-scrim-wrapper"
@@ -135,56 +110,43 @@ exports[`PypiInstallation renders all the messages 1`] = `
/>
</li>
</ul>
-
- <!---->
-
</div>
</div>
</div>
</div>
</div>
-
<fieldset
class="form-group gl-form-group"
- id="installation-pip-command-group"
+ id="reference-3"
>
<legend
- class="bv-no-focus-ring col-form-label pt-0 col-form-label"
- id="installation-pip-command-group__BV_label_"
+ class="bv-no-focus-ring col-form-label pt-0"
+ id="reference-4"
tabindex="-1"
- >
-
-
-
- <!---->
-
- <!---->
- </legend>
+ />
<div>
<div
data-testid="pip-command"
- id="installation-pip-command"
+ id="reference-5"
>
<label
- for="instruction-input_11"
+ for="reference-6"
>
Pip Command
</label>
-
<div
class="gl-mb-3"
>
<div
- class="input-group gl-mb-3"
+ class="gl-mb-3 input-group"
>
<input
class="form-control gl-font-monospace"
data-testid="instruction-input"
- id="instruction-input_11"
- readonly="readonly"
+ id="reference-6"
+ readonly=""
type="text"
/>
-
<span
class="input-group-append"
data-testid="instruction-button"
@@ -192,15 +154,13 @@ exports[`PypiInstallation renders all the messages 1`] = `
<button
aria-label="Copy Pip command"
aria-live="polite"
- class="btn input-group-text btn-default btn-md gl-button btn-default-secondary btn-icon"
+ class="btn btn-default btn-default-secondary btn-icon btn-md gl-button input-group-text"
data-clipboard-handle-tooltip="false"
data-clipboard-text="pip install @gitlab-org/package-15 --index-url http://__token__:<your_personal_token>@gdk.test:3000/api/v4/projects/1/packages/pypi/simple"
- id="clipboard-button-12"
+ id="reference-7"
title="Copy Pip command"
type="button"
>
- <!---->
-
<svg
aria-hidden="true"
class="gl-button-icon gl-icon s16"
@@ -211,21 +171,17 @@ exports[`PypiInstallation renders all the messages 1`] = `
href="file-mock#copy-to-clipboard"
/>
</svg>
-
- <!---->
</button>
</span>
</div>
</div>
</div>
- <!---->
- <!---->
<small
class="form-text text-muted"
- id="installation-pip-command-group__BV_description_"
+ id="reference-8"
tabindex="-1"
>
- You will need a
+ You will need a
<a
class="gl-link"
data-testid="access-token-link"
@@ -237,39 +193,31 @@ exports[`PypiInstallation renders all the messages 1`] = `
</small>
</div>
</fieldset>
-
<h3
class="gl-font-lg"
>
Registry setup
</h3>
-
<p>
- If you haven't already done so, you will need to add the below to your
+ If you haven't already done so, you will need to add the below to your
<code>
.pypirc
</code>
- file.
+ file.
</p>
-
<div
data-testid="pypi-setup-content"
>
- <!---->
-
<div>
<pre
class="gl-font-monospace"
data-testid="multiline-instruction"
>
- [gitlab]
-repository = http://gdk.test:3000/api/v4/projects/1/packages/pypi
-username = __token__
-password = &lt;your personal access token&gt;
+ [gitlab]repository = http://gdk.test:3000/api/v4/projects/1/packages/pypiusername = __token__password = &lt;your personal access token&gt;
</pre>
</div>
</div>
- For more information on the PyPi registry,
+ For more information on the PyPi registry,
<a
class="gl-link"
data-testid="pypi-docs-link"
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap
index e0e6c101029..40fcd290b33 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap
@@ -2,36 +2,35 @@
exports[`packages_list_row renders 1`] = `
<div
- class="gl-display-flex gl-flex-direction-column gl-border-b-solid gl-border-t-solid gl-border-t-1 gl-border-b-1 gl-border-t-transparent gl-border-b-gray-100"
+ class="gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-border-t-1 gl-border-t-solid gl-border-t-transparent gl-display-flex gl-flex-direction-column"
data-testid="package-row"
>
<div
- class="gl-display-flex gl-align-items-center gl-py-3"
+ class="gl-align-items-center gl-display-flex gl-py-3"
>
<div
- class="gl-w-7 gl-display-flex gl-justify-content-start gl-pl-2"
+ class="gl-display-flex gl-justify-content-start gl-pl-2 gl-w-7"
>
<gl-form-checkbox-stub
class="gl-m-0"
- id="2"
+ id="reference-0"
/>
</div>
-
<div
- class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-grow-1"
+ class="gl-align-items-stretch gl-display-flex gl-flex-grow-1 gl-justify-content-space-between gl-xs-flex-direction-column"
>
<div
- class="gl-display-flex gl-flex-direction-column gl-xs-mb-3 gl-min-w-0 gl-flex-grow-1"
+ class="gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-min-w-0 gl-xs-mb-3"
>
<div
- class="gl-display-flex gl-align-items-center gl-text-body gl-font-weight-bold gl-min-h-6 gl-min-w-0"
+ class="gl-align-items-center gl-display-flex gl-font-weight-bold gl-min-h-6 gl-min-w-0 gl-text-body"
>
<div
- class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0"
+ class="gl-align-items-center gl-display-flex gl-min-w-0 gl-mr-3"
>
<router-link-stub
ariacurrentvalue="page"
- class="gl-text-body gl-min-w-0"
+ class="gl-min-w-0 gl-text-body"
data-testid="details-link"
event="click"
tag="a"
@@ -42,18 +41,13 @@ exports[`packages_list_row renders 1`] = `
text="@gitlab-org/package-15"
/>
</router-link-stub>
-
- <!---->
</div>
-
- <!---->
</div>
-
<div
- class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-min-h-6 gl-min-w-0 gl-flex-grow-1"
+ class="gl-align-items-center gl-display-flex gl-flex-grow-1 gl-min-h-6 gl-min-w-0 gl-text-gray-500"
>
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
data-testid="left-secondary-infos"
>
<gl-truncate-stub
@@ -62,7 +56,6 @@ exports[`packages_list_row renders 1`] = `
text="1.0.0"
withtooltip="true"
/>
-
<span
class="gl-ml-2"
data-testid="package-type"
@@ -72,25 +65,22 @@ exports[`packages_list_row renders 1`] = `
</div>
</div>
</div>
-
<div
- class="gl-display-flex gl-flex-direction-column gl-sm-align-items-flex-end gl-justify-content-space-between gl-text-gray-500 gl-flex-shrink-0"
+ class="gl-display-flex gl-flex-direction-column gl-flex-shrink-0 gl-justify-content-space-between gl-sm-align-items-flex-end gl-text-gray-500"
>
<div
- class="gl-display-flex gl-align-items-center gl-sm-text-body gl-sm-font-weight-bold gl-min-h-6"
+ class="gl-align-items-center gl-display-flex gl-min-h-6 gl-sm-font-weight-bold gl-sm-text-body"
>
<publish-method-stub />
</div>
-
<div
- class="gl-display-flex gl-align-items-center gl-min-h-6"
+ class="gl-align-items-center gl-display-flex gl-min-h-6"
>
<span
data-testid="right-secondary"
>
- Published
+ Published
<time
- class=""
datetime="2020-05-17T14:23:32Z"
title="May 17, 2020 2:23pm UTC"
>
@@ -100,9 +90,8 @@ exports[`packages_list_row renders 1`] = `
</div>
</div>
</div>
-
<div
- class="gl-w-9 gl-display-flex gl-justify-content-end gl-pr-1"
+ class="gl-display-flex gl-justify-content-end gl-pr-1 gl-w-9"
>
<gl-disclosure-dropdown-stub
autoclose="true"
@@ -125,15 +114,11 @@ exports[`packages_list_row renders 1`] = `
<span
class="gl-text-red-500"
>
-
Delete package
-
</span>
</gl-disclosure-dropdown-item-stub>
</gl-disclosure-dropdown-stub>
</div>
</div>
-
- <!---->
</div>
`;
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/publish_method_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/publish_method_spec.js.snap
index 4407c4a2003..f202635d717 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/publish_method_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/publish_method_spec.js.snap
@@ -2,27 +2,24 @@
exports[`publish_method renders 1`] = `
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
>
<gl-icon-stub
class="gl-mr-2"
name="git-merge"
size="16"
/>
-
<span
class="gl-mr-2"
data-testid="pipeline-ref"
>
master
</span>
-
<gl-icon-stub
class="gl-mr-2"
name="commit"
size="16"
/>
-
<gl-link-stub
class="gl-mr-2"
data-testid="pipeline-sha"
@@ -30,7 +27,6 @@ exports[`publish_method renders 1`] = `
>
b83d6e39
</gl-link-stub>
-
<clipboard-button-stub
category="tertiary"
size="small"
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
index fad8863e3d9..acf8b718400 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
@@ -37,7 +37,6 @@ describe('packages_list', () => {
const defaultProps = {
list: [firstPackage, secondPackage],
isLoading: false,
- pageInfo: {},
groupSettings: defaultPackageGroupSettings,
};
@@ -113,7 +112,6 @@ describe('packages_list', () => {
expect(findRegistryList().props()).toMatchObject({
title: '2 packages',
items: defaultProps.list,
- pagination: defaultProps.pageInfo,
hiddenDelete: false,
isLoading: false,
});
@@ -314,22 +312,4 @@ describe('packages_list', () => {
expect(emptySlot.exists()).toBe(true);
});
});
-
- describe('pagination', () => {
- beforeEach(() => {
- mountComponent({ props: { pageInfo: { hasPreviousPage: true } } });
- });
-
- it('emits prev-page events when the prev event is fired', () => {
- findRegistryList().vm.$emit('prev-page');
-
- expect(wrapper.emitted('prev-page')).toHaveLength(1);
- });
-
- it('emits next-page events when the next event is fired', () => {
- findRegistryList().vm.$emit('next-page');
-
- expect(wrapper.emitted('next-page')).toHaveLength(1);
- });
- });
});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js
index 82fa5b76367..f4e36f51c27 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_search_spec.js
@@ -3,19 +3,12 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { sortableFields } from '~/packages_and_registries/package_registry/utils';
import component from '~/packages_and_registries/package_registry/components/list/package_search.vue';
import PackageTypeToken from '~/packages_and_registries/package_registry/components/list/tokens/package_type_token.vue';
-import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
-import UrlSync from '~/vue_shared/components/url_sync.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
+import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue';
import { LIST_KEY_CREATED_AT } from '~/packages_and_registries/package_registry/constants';
-import { getQueryParams, extractFilterAndSorting } from '~/packages_and_registries/shared/utils';
import { TOKEN_TYPE_TYPE } from '~/vue_shared/components/filtered_search_bar/constants';
-jest.mock('~/packages_and_registries/shared/utils');
-
-useMockLocationHelper();
-
describe('Package Search', () => {
let wrapper;
@@ -24,8 +17,7 @@ describe('Package Search', () => {
sorting: { sort: 'desc' },
};
- const findRegistrySearch = () => wrapper.findComponent(RegistrySearch);
- const findUrlSync = () => wrapper.findComponent(UrlSync);
+ const findPersistedSearch = () => wrapper.findComponent(PersistedSearch);
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
const mountComponent = (isGroupPage = false) => {
@@ -36,34 +28,23 @@ describe('Package Search', () => {
};
},
stubs: {
- UrlSync,
LocalStorageSync,
},
});
};
- beforeEach(() => {
- extractFilterAndSorting.mockReturnValue(defaultQueryParamsMock);
- });
-
it('has a registry search component', async () => {
mountComponent();
await nextTick();
- expect(findRegistrySearch().exists()).toBe(true);
+ expect(findPersistedSearch().exists()).toBe(true);
});
it('registry search is mounted after mount', () => {
mountComponent();
- expect(findRegistrySearch().exists()).toBe(false);
- });
-
- it('has a UrlSync component', () => {
- mountComponent();
-
- expect(findUrlSync().exists()).toBe(true);
+ expect(findPersistedSearch().exists()).toBe(false);
});
it('has a LocalStorageSync component', () => {
@@ -87,7 +68,7 @@ describe('Package Search', () => {
await nextTick();
- expect(findRegistrySearch().props()).toMatchObject({
+ expect(findPersistedSearch().props()).toMatchObject({
tokens: expect.arrayContaining([
expect.objectContaining({
token: PackageTypeToken,
@@ -99,85 +80,63 @@ describe('Package Search', () => {
});
});
- it('on sorting:changed emits update event and update internal sort', async () => {
- const payload = { sort: 'foo' };
+ it('on update event re-emits update event and updates internal sort', async () => {
+ const payload = {
+ sort: 'CREATED_FOO',
+ filters: defaultQueryParamsMock.filters,
+ sorting: { sort: 'foo', orderBy: 'created_at' },
+ };
mountComponent();
await nextTick();
- findRegistrySearch().vm.$emit('sorting:changed', payload);
+ findPersistedSearch().vm.$emit('update', payload);
await nextTick();
- expect(findRegistrySearch().props('sorting')).toEqual({ sort: 'foo', orderBy: 'created_at' });
+ expect(findLocalStorageSync().props('value')).toEqual({ sort: 'foo', orderBy: 'created_at' });
- // there is always a first call on mounted that emits up default values
- expect(wrapper.emitted('update')[1]).toEqual([
+ expect(wrapper.emitted('update')[0]).toEqual([
{
filters: {
packageName: '',
packageType: undefined,
},
- sort: 'CREATED_FOO',
+ sort: payload.sort,
+ sorting: payload.sorting,
},
]);
});
- it('on filter:changed updates the filters', async () => {
- const payload = ['foo'];
+ it('on update event, re-emits update event with formatted filters', async () => {
+ const payload = {
+ sort: 'CREATED_FOO',
+ filters: [
+ { type: 'type', value: { data: 'Generic', operator: '=' }, id: 'token-3' },
+ { id: 'token-4', type: 'filtered-search-term', value: { data: 'gl' } },
+ { id: 'token-5', type: 'filtered-search-term', value: { data: '' } },
+ ],
+ sorting: { sort: 'foo', orderBy: 'created_at' },
+ };
mountComponent();
await nextTick();
- findRegistrySearch().vm.$emit('filter:changed', payload);
+ findPersistedSearch().vm.$emit('update', payload);
await nextTick();
- expect(findRegistrySearch().props('filters')).toEqual(['foo']);
- });
-
- it('on filter:submit emits update event', async () => {
- mountComponent();
-
- await nextTick();
-
- findRegistrySearch().vm.$emit('filter:submit');
-
- expect(wrapper.emitted('update')[1]).toEqual([
+ expect(wrapper.emitted('update')[0]).toEqual([
{
filters: {
- packageName: '',
- packageType: undefined,
+ packageName: 'gl',
+ packageType: 'GENERIC',
},
- sort: 'CREATED_DESC',
+ sort: payload.sort,
+ sorting: payload.sorting,
},
]);
});
-
- it('on query:changed calls updateQuery from UrlSync', async () => {
- jest.spyOn(UrlSync.methods, 'updateQuery').mockImplementation(() => {});
-
- mountComponent();
-
- await nextTick();
-
- findRegistrySearch().vm.$emit('query:changed');
-
- expect(UrlSync.methods.updateQuery).toHaveBeenCalled();
- });
-
- it('sets the component sorting and filtering based on the querystring', async () => {
- mountComponent();
-
- await nextTick();
-
- expect(getQueryParams).toHaveBeenCalled();
-
- expect(findRegistrySearch().props()).toMatchObject({
- filters: defaultQueryParamsMock.filters,
- sorting: defaultQueryParamsMock.sorting,
- });
- });
});
diff --git a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
index 0d262036ee7..0ce2b86b9a4 100644
--- a/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/pages/list_spec.js
@@ -17,7 +17,7 @@ import {
EMPTY_LIST_HELP_URL,
PACKAGE_HELP_URL,
} from '~/packages_and_registries/package_registry/constants';
-
+import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue';
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
import { packagesListQuery, packageData, pagination } from '../mock_data';
@@ -53,6 +53,7 @@ describe('PackagesListApp', () => {
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findDeletePackages = () => wrapper.findComponent(DeletePackages);
const findSettingsLink = () => wrapper.findComponent(GlButton);
+ const findPagination = () => wrapper.findComponent(PersistedPagination);
const mountComponent = ({
resolver = jest.fn().mockResolvedValue(packagesListQuery()),
@@ -99,6 +100,15 @@ describe('PackagesListApp', () => {
expect(resolver).not.toHaveBeenCalled();
});
+ it('has persisted pagination', async () => {
+ const resolver = jest.fn().mockResolvedValue(packagesListQuery());
+
+ mountComponent({ resolver });
+ await waitForFirstRequest();
+
+ expect(findPagination().props('pagination')).toEqual(pagination());
+ });
+
it('has a package title', async () => {
mountComponent();
@@ -194,7 +204,6 @@ describe('PackagesListApp', () => {
expect(findListComponent().props()).toMatchObject({
list: expect.arrayContaining([expect.objectContaining({ id: packageData().id })]),
isLoading: false,
- pageInfo: expect.objectContaining({ endCursor: pagination().endCursor }),
groupSettings: expect.objectContaining({
mavenPackageRequestsForwarding: true,
npmPackageRequestsForwarding: true,
@@ -203,9 +212,9 @@ describe('PackagesListApp', () => {
});
});
- it('when list emits next-page fetches the next set of records', async () => {
+ it('when pagination emits next event fetches the next set of records', async () => {
await waitForFirstRequest();
- findListComponent().vm.$emit('next-page');
+ findPagination().vm.$emit('next');
await waitForPromises();
expect(resolver).toHaveBeenCalledWith(
@@ -213,9 +222,9 @@ describe('PackagesListApp', () => {
);
});
- it('when list emits prev-page fetches the prev set of records', async () => {
+ it('when pagination emits prev event fetches the prev set of records', async () => {
await waitForFirstRequest();
- findListComponent().vm.$emit('prev-page');
+ findPagination().vm.$emit('prev');
await waitForPromises();
expect(resolver).toHaveBeenCalledWith(
diff --git a/spec/frontend/packages_and_registries/package_registry/utils_spec.js b/spec/frontend/packages_and_registries/package_registry/utils_spec.js
index 019f94aaec2..ecb5a8a77f1 100644
--- a/spec/frontend/packages_and_registries/package_registry/utils_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/utils_spec.js
@@ -1,4 +1,9 @@
-import { getPackageTypeLabel } from '~/packages_and_registries/package_registry/utils';
+import {
+ getPackageTypeLabel,
+ getNextPageParams,
+ getPreviousPageParams,
+ getPageParams,
+} from '~/packages_and_registries/package_registry/utils';
describe('Packages shared utils', () => {
describe('getPackageTypeLabel', () => {
@@ -21,3 +26,48 @@ describe('Packages shared utils', () => {
});
});
});
+
+describe('getNextPageParams', () => {
+ it('should return the next page params with the provided cursor', () => {
+ const cursor = 'abc123';
+ expect(getNextPageParams(cursor)).toEqual({
+ after: cursor,
+ first: 20,
+ });
+ });
+});
+
+describe('getPreviousPageParams', () => {
+ it('should return the previous page params with the provided cursor', () => {
+ const cursor = 'abc123';
+ expect(getPreviousPageParams(cursor)).toEqual({
+ first: null,
+ before: cursor,
+ last: 20,
+ });
+ });
+});
+
+describe('getPageParams', () => {
+ it('should return the previous page params if before cursor is available', () => {
+ const pageInfo = { before: 'abc123' };
+ expect(getPageParams(pageInfo)).toEqual({
+ first: null,
+ before: pageInfo.before,
+ last: 20,
+ });
+ });
+
+ it('should return the next page params if after cursor is available', () => {
+ const pageInfo = { after: 'abc123' };
+ expect(getPageParams(pageInfo)).toEqual({
+ after: pageInfo.after,
+ first: 20,
+ });
+ });
+
+ it('should return an empty object if both before and after cursors are not available', () => {
+ const pageInfo = {};
+ expect(getPageParams(pageInfo)).toEqual({});
+ });
+});
diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap
index 5d08574234c..d3298984f9d 100644
--- a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap
+++ b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap
@@ -2,7 +2,7 @@
exports[`Container Expiration Policy Settings Form Cadence matches snapshot 1`] = `
<expiration-dropdown-stub
- class="gl-mr-7 gl-mb-0!"
+ class="gl-mb-0! gl-mr-7"
data-testid="cadence-dropdown"
description=""
dropdownclass=""
diff --git a/spec/frontend/packages_and_registries/shared/components/__snapshots__/publish_method_spec.js.snap b/spec/frontend/packages_and_registries/shared/components/__snapshots__/publish_method_spec.js.snap
index 5f243799bae..084e4a2b2f3 100644
--- a/spec/frontend/packages_and_registries/shared/components/__snapshots__/publish_method_spec.js.snap
+++ b/spec/frontend/packages_and_registries/shared/components/__snapshots__/publish_method_spec.js.snap
@@ -2,27 +2,24 @@
exports[`publish_method renders 1`] = `
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
>
<gl-icon-stub
class="gl-mr-2"
name="git-merge"
size="16"
/>
-
<span
class="gl-mr-2"
data-testid="pipeline-ref"
>
branch-name
</span>
-
<gl-icon-stub
class="gl-mr-2"
name="commit"
size="16"
/>
-
<gl-link-stub
class="gl-mr-2"
data-testid="pipeline-sha"
@@ -30,7 +27,6 @@ exports[`publish_method renders 1`] = `
>
sha-baz
</gl-link-stub>
-
<clipboard-button-stub
category="tertiary"
size="small"
diff --git a/spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap b/spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap
index e9ee6ebdb5c..e67bded6a7e 100644
--- a/spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap
+++ b/spec/frontend/packages_and_registries/shared/components/__snapshots__/registry_breadcrumb_spec.js.snap
@@ -12,34 +12,22 @@ exports[`Registry Breadcrumb when is not rootRoute renders 1`] = `
class="gl-breadcrumb-item"
>
<a
- class=""
target="_self"
>
- <!---->
- <span>
-
- </span>
+ <span />
</a>
</li>
-
- <!---->
<li
class="gl-breadcrumb-item"
>
<a
aria-current="page"
- class=""
href="#"
target="_self"
>
- <!---->
- <span>
-
- </span>
+ <span />
</a>
</li>
-
- <!---->
</ol>
</nav>
`;
@@ -57,17 +45,11 @@ exports[`Registry Breadcrumb when is rootRoute renders 1`] = `
>
<a
aria-current="page"
- class=""
target="_self"
>
- <!---->
- <span>
-
- </span>
+ <span />
</a>
</li>
-
- <!---->
</ol>
</nav>
`;
diff --git a/spec/frontend/packages_and_registries/shared/components/cli_commands_spec.js b/spec/frontend/packages_and_registries/shared/components/cli_commands_spec.js
index 328f83394f9..9041cb757ab 100644
--- a/spec/frontend/packages_and_registries/shared/components/cli_commands_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/cli_commands_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdown } from '@gitlab/ui';
+import { GlDisclosureDropdown } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import Vue from 'vue';
// eslint-disable-next-line no-restricted-imports
@@ -23,7 +23,7 @@ Vue.use(Vuex);
describe('cli_commands', () => {
let wrapper;
- const findDropdownButton = () => wrapper.findComponent(GlDropdown);
+ const findDropdownButton = () => wrapper.findComponent(GlDisclosureDropdown);
const findCodeInstruction = () => wrapper.findAllComponents(CodeInstruction);
const mountComponent = () => {
diff --git a/spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js b/spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js
index 296caf091d5..615fba2e282 100644
--- a/spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js
+++ b/spec/frontend/packages_and_registries/shared/components/persisted_search_spec.js
@@ -86,6 +86,7 @@ describe('Persisted Search', () => {
after: '123',
before: null,
},
+ sorting: defaultQueryParamsMock.sorting,
},
]);
});
@@ -109,6 +110,7 @@ describe('Persisted Search', () => {
{
filters: [],
sort: 'TEST_DESC',
+ sorting: defaultQueryParamsMock.sorting,
pageInfo: {
before: '456',
after: null,
@@ -136,6 +138,7 @@ describe('Persisted Search', () => {
filters: ['foo'],
sort: 'TEST_DESC',
pageInfo: {},
+ sorting: payload,
},
]);
});
@@ -169,6 +172,7 @@ describe('Persisted Search', () => {
after: '123',
before: null,
},
+ sorting: defaultQueryParamsMock.sorting,
},
]);
});
diff --git a/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js b/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js
deleted file mode 100644
index 6cf30e84288..00000000000
--- a/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import $ from 'jquery';
-import htmlAbuseReportsList from 'test_fixtures/abuse_reports/abuse_reports_list.html';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import AbuseReports from '~/pages/admin/abuse_reports/abuse_reports';
-
-describe('Abuse Reports', () => {
- const MAX_MESSAGE_LENGTH = 500;
-
- let $messages;
-
- const assertMaxLength = ($message) => {
- expect($message.text().length).toEqual(MAX_MESSAGE_LENGTH);
- };
- const findMessage = (searchText) =>
- $messages.filter((index, element) => element.innerText.indexOf(searchText) > -1).first();
-
- beforeEach(() => {
- setHTMLFixture(htmlAbuseReportsList);
- new AbuseReports(); // eslint-disable-line no-new
- $messages = $('.abuse-reports .message');
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- it('should truncate long messages', () => {
- const $longMessage = findMessage('LONG MESSAGE');
-
- expect($longMessage.data('originalMessage')).toEqual(expect.anything());
- assertMaxLength($longMessage);
- });
-
- it('should not truncate short messages', () => {
- const $shortMessage = findMessage('SHORT MESSAGE');
-
- expect($shortMessage.data('originalMessage')).not.toEqual(expect.anything());
- });
-
- it('should allow clicking a truncated message to expand and collapse the full message', () => {
- const $longMessage = findMessage('LONG MESSAGE');
- $longMessage.click();
-
- expect($longMessage.data('originalMessage').length).toEqual($longMessage.text().length);
- $longMessage.click();
- assertMaxLength($longMessage);
- });
-});
diff --git a/spec/frontend/pages/admin/jobs/components/cancel_jobs_modal_spec.js b/spec/frontend/pages/admin/jobs/components/cancel_jobs_modal_spec.js
deleted file mode 100644
index d90393d8ab3..00000000000
--- a/spec/frontend/pages/admin/jobs/components/cancel_jobs_modal_spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { nextTick } from 'vue';
-import { mount } from '@vue/test-utils';
-import { GlModal } from '@gitlab/ui';
-import { TEST_HOST } from 'helpers/test_constants';
-import axios from '~/lib/utils/axios_utils';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import CancelJobsModal from '~/pages/admin/jobs/components/cancel_jobs_modal.vue';
-import { setVueErrorHandler } from '../../../../__helpers__/set_vue_error_handler';
-
-jest.mock('~/lib/utils/url_utility', () => ({
- ...jest.requireActual('~/lib/utils/url_utility'),
- redirectTo: jest.fn(),
-}));
-
-describe('Cancel jobs modal', () => {
- const props = {
- url: `${TEST_HOST}/cancel_jobs_modal.vue/cancelAll`,
- modalId: 'cancel-jobs-modal',
- };
- let wrapper;
-
- beforeEach(() => {
- wrapper = mount(CancelJobsModal, { propsData: props });
- });
-
- describe('on submit', () => {
- it('cancels jobs and redirects to overview page', async () => {
- const responseURL = `${TEST_HOST}/cancel_jobs_modal.vue/jobs`;
- // TODO: We can't use axios-mock-adapter because our current version
- // does not support responseURL
- //
- // see https://gitlab.com/gitlab-org/gitlab/-/issues/375308 for details
- jest.spyOn(axios, 'post').mockImplementation((url) => {
- expect(url).toBe(props.url);
- return Promise.resolve({
- request: {
- responseURL,
- },
- });
- });
-
- wrapper.findComponent(GlModal).vm.$emit('primary');
- await nextTick();
-
- expect(redirectTo).toHaveBeenCalledWith(responseURL); // eslint-disable-line import/no-deprecated
- });
-
- it('displays error if canceling jobs failed', async () => {
- const dummyError = new Error('canceling jobs failed');
- // TODO: We can't use axios-mock-adapter because our current version
- // does not support responseURL
- //
- // see https://gitlab.com/gitlab-org/gitlab/-/issues/375308 for details
- jest.spyOn(axios, 'post').mockImplementation((url) => {
- expect(url).toBe(props.url);
- return Promise.reject(dummyError);
- });
-
- setVueErrorHandler({ instance: wrapper.vm, handler: () => {} }); // silencing thrown error
- wrapper.findComponent(GlModal).vm.$emit('primary');
- await nextTick();
-
- expect(redirectTo).not.toHaveBeenCalled(); // eslint-disable-line import/no-deprecated
- });
- });
-});
diff --git a/spec/frontend/pages/admin/jobs/components/cancel_jobs_spec.js b/spec/frontend/pages/admin/jobs/components/cancel_jobs_spec.js
index d94de48f238..2884e4ed521 100644
--- a/spec/frontend/pages/admin/jobs/components/cancel_jobs_spec.js
+++ b/spec/frontend/pages/admin/jobs/components/cancel_jobs_spec.js
@@ -2,12 +2,9 @@ import { GlButton } from '@gitlab/ui';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { TEST_HOST } from 'helpers/test_constants';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import CancelJobs from '~/pages/admin/jobs/components/cancel_jobs.vue';
-import CancelJobsModal from '~/pages/admin/jobs/components/cancel_jobs_modal.vue';
-import {
- CANCEL_JOBS_MODAL_ID,
- CANCEL_BUTTON_TOOLTIP,
-} from '~/pages/admin/jobs/components/constants';
+import CancelJobs from '~/ci/admin/jobs_table/components/cancel_jobs.vue';
+import CancelJobsModal from '~/ci/admin/jobs_table/components/cancel_jobs_modal.vue';
+import { CANCEL_JOBS_MODAL_ID, CANCEL_BUTTON_TOOLTIP } from '~/ci/admin/jobs_table/constants';
describe('CancelJobs component', () => {
let wrapper;
diff --git a/spec/frontend/pages/admin/jobs/components/jobs_skeleton_loader_spec.js b/spec/frontend/pages/admin/jobs/components/jobs_skeleton_loader_spec.js
deleted file mode 100644
index 03e5cd75420..00000000000
--- a/spec/frontend/pages/admin/jobs/components/jobs_skeleton_loader_spec.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { GlSkeletonLoader } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
-
-describe('jobs_skeleton_loader.vue', () => {
- let wrapper;
-
- const findGlSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
-
- const WIDTH = '1248';
- const HEIGHT = '73';
-
- beforeEach(() => {
- wrapper = shallowMount(JobsSkeletonLoader);
- });
-
- it('renders a GlSkeletonLoader', () => {
- expect(findGlSkeletonLoader().exists()).toBe(true);
- });
-
- it('has correct width', () => {
- expect(findGlSkeletonLoader().attributes('width')).toBe(WIDTH);
- });
-
- it('has correct height', () => {
- expect(findGlSkeletonLoader().attributes('height')).toBe(HEIGHT);
- });
-});
diff --git a/spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js b/spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js
index 71ebf64f43c..d14b78d2f4d 100644
--- a/spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js
+++ b/spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js
@@ -4,17 +4,17 @@ import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import JobsTableTabs from '~/jobs/components/table/jobs_table_tabs.vue';
-import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
-import getAllJobsQuery from '~/pages/admin/jobs/components/table/graphql/queries/get_all_jobs.query.graphql';
-import getAllJobsCount from '~/pages/admin/jobs/components/table/graphql/queries/get_all_jobs_count.query.graphql';
-import getCancelableJobsQuery from '~/pages/admin/jobs/components/table/graphql/queries/get_cancelable_jobs_count.query.graphql';
-import AdminJobsTableApp from '~/pages/admin/jobs/components/table/admin_jobs_table_app.vue';
-import CancelJobs from '~/pages/admin/jobs/components/cancel_jobs.vue';
-import JobsTable from '~/jobs/components/table/jobs_table.vue';
+import JobsTableTabs from '~/ci/jobs_page/components/jobs_table_tabs.vue';
+import JobsSkeletonLoader from '~/ci/admin/jobs_table/components/jobs_skeleton_loader.vue';
+import getAllJobsQuery from '~/ci/admin/jobs_table/graphql/queries/get_all_jobs.query.graphql';
+import getAllJobsCount from '~/ci/admin/jobs_table/graphql/queries/get_all_jobs_count.query.graphql';
+import getCancelableJobsQuery from '~/ci/admin/jobs_table/graphql/queries/get_cancelable_jobs_count.query.graphql';
+import AdminJobsTableApp from '~/ci/admin/jobs_table/admin_jobs_table_app.vue';
+import CancelJobs from '~/ci/admin/jobs_table/components/cancel_jobs.vue';
+import JobsTable from '~/ci/jobs_page/components/jobs_table.vue';
import { createAlert } from '~/alert';
import { TEST_HOST } from 'spec/test_constants';
-import JobsFilteredSearch from '~/jobs/components/filtered_search/jobs_filtered_search.vue';
+import JobsFilteredSearch from '~/ci/common/private/jobs_filtered_search/app.vue';
import * as urlUtils from '~/lib/utils/url_utility';
import {
JOBS_FETCH_ERROR_MSG,
@@ -22,7 +22,8 @@ import {
LOADING_ARIA_LABEL,
RAW_TEXT_WARNING_ADMIN,
JOBS_COUNT_ERROR_MESSAGE,
-} from '~/pages/admin/jobs/components/constants';
+} from '~/ci/admin/jobs_table/constants';
+import { TOKEN_TYPE_JOBS_RUNNER_TYPE } from '~/vue_shared/components/filtered_search_bar/constants';
import {
mockAllJobsResponsePaginated,
mockCancelableJobsCountResponse,
@@ -30,7 +31,7 @@ import {
statuses,
mockFailedSearchToken,
mockAllJobsCountResponse,
-} from '../../../../../jobs/mock_data';
+} from 'jest/ci/jobs_mock_data';
Vue.use(VueApollo);
@@ -54,6 +55,11 @@ describe('Job table app', () => {
const findCancelJobsButton = () => wrapper.findComponent(CancelJobs);
const findFilteredSearch = () => wrapper.findComponent(JobsFilteredSearch);
+ const mockSearchTokenRunnerType = {
+ type: TOKEN_TYPE_JOBS_RUNNER_TYPE,
+ value: { data: 'INSTANCE_TYPE', operator: '=' },
+ };
+
const triggerInfiniteScroll = () =>
wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
@@ -73,6 +79,7 @@ describe('Job table app', () => {
countHandler = countSuccessHandler,
mountFn = shallowMount,
data = {},
+ provideOptions = {},
} = {}) => {
wrapper = mountFn(AdminJobsTableApp, {
data() {
@@ -82,6 +89,8 @@ describe('Job table app', () => {
},
provide: {
jobStatuses: statuses,
+ glFeatures: { adminJobsFilterRunnerType: true },
+ ...provideOptions,
},
apolloProvider: createMockApolloProvider(handler, cancelableHandler, countHandler),
});
@@ -304,24 +313,37 @@ describe('Job table app', () => {
},
);
- it('refetches jobs query when filtering', async () => {
- createComponent();
+ describe.each`
+ searchTokens | expectedQueryParams
+ ${[]} | ${{ runnerTypes: null, statuses: null }}
+ ${[mockFailedSearchToken]} | ${{ runnerTypes: null, statuses: 'FAILED' }}
+ ${[mockFailedSearchToken, mockSearchTokenRunnerType]} | ${{ runnerTypes: 'INSTANCE_TYPE', statuses: 'FAILED' }}
+ `('when filtering jobs by searchTokens', ({ searchTokens, expectedQueryParams }) => {
+ it(`refetches jobs query including filters ${JSON.stringify(
+ expectedQueryParams,
+ )}`, async () => {
+ createComponent();
- expect(successHandler).toHaveBeenCalledTimes(1);
+ expect(successHandler).toHaveBeenCalledTimes(1);
- await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', searchTokens);
- expect(successHandler).toHaveBeenCalledTimes(2);
- });
+ expect(successHandler).toHaveBeenCalledTimes(2);
+ expect(successHandler).toHaveBeenNthCalledWith(2, { first: 50, ...expectedQueryParams });
+ });
- it('refetches jobs count query when filtering', async () => {
- createComponent();
+ it(`refetches jobs count query including filters ${JSON.stringify(
+ expectedQueryParams,
+ )}`, async () => {
+ createComponent();
- expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
- await findFilteredSearch().vm.$emit('filterJobsBySearch', [mockFailedSearchToken]);
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', searchTokens);
- expect(countSuccessHandler).toHaveBeenCalledTimes(2);
+ expect(countSuccessHandler).toHaveBeenCalledTimes(2);
+ expect(countSuccessHandler).toHaveBeenNthCalledWith(2, expectedQueryParams);
+ });
});
it('shows raw text warning when user inputs raw text', async () => {
@@ -364,6 +386,7 @@ describe('Job table app', () => {
expect(successHandler).toHaveBeenCalledWith({
first: 50,
statuses: 'FAILED',
+ runnerTypes: null,
});
expect(urlUtils.updateHistory).toHaveBeenCalledWith({
url: `${TEST_HOST}/?statuses=FAILED`,
@@ -378,6 +401,44 @@ describe('Job table app', () => {
expect(successHandler).toHaveBeenCalledWith({
first: 50,
statuses: null,
+ runnerTypes: null,
+ });
+ });
+
+ describe('when feature flag `adminJobsFilterRunnerType` is disabled', () => {
+ const provideOptions = { glFeatures: { adminJobsFilterRunnerType: false } };
+
+ describe.each`
+ searchTokens | expectedQueryParams
+ ${[]} | ${{ statuses: null }}
+ ${[mockFailedSearchToken]} | ${{ statuses: 'FAILED' }}
+ ${[mockFailedSearchToken, mockSearchTokenRunnerType]} | ${{ statuses: 'FAILED' }}
+ `('when filtering jobs by searchTokens', ({ searchTokens, expectedQueryParams }) => {
+ it(`refetches jobs query including filters ${JSON.stringify(
+ expectedQueryParams,
+ )}`, async () => {
+ createComponent({ provideOptions });
+
+ expect(successHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', searchTokens);
+
+ expect(successHandler).toHaveBeenCalledTimes(2);
+ expect(successHandler).toHaveBeenNthCalledWith(2, { first: 50, ...expectedQueryParams });
+ });
+
+ it(`refetches jobs count query including filters ${JSON.stringify(
+ expectedQueryParams,
+ )}`, async () => {
+ createComponent({ provideOptions });
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(1);
+
+ await findFilteredSearch().vm.$emit('filterJobsBySearch', searchTokens);
+
+ expect(countSuccessHandler).toHaveBeenCalledTimes(2);
+ expect(countSuccessHandler).toHaveBeenNthCalledWith(2, expectedQueryParams);
+ });
});
});
});
diff --git a/spec/frontend/pages/admin/jobs/components/table/cells/project_cell_spec.js b/spec/frontend/pages/admin/jobs/components/table/cells/project_cell_spec.js
deleted file mode 100644
index 3366d60d9f3..00000000000
--- a/spec/frontend/pages/admin/jobs/components/table/cells/project_cell_spec.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import ProjectCell from '~/pages/admin/jobs/components/table/cell/project_cell.vue';
-import { mockAllJobsNodes } from '../../../../../../jobs/mock_data';
-
-const mockJob = mockAllJobsNodes[0];
-
-describe('Project cell', () => {
- let wrapper;
-
- const findProjectLink = () => wrapper.findComponent(GlLink);
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(ProjectCell, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('Project Link', () => {
- beforeEach(() => {
- createComponent({ job: mockJob });
- });
-
- it('shows and links to the project', () => {
- expect(findProjectLink().exists()).toBe(true);
- expect(findProjectLink().text()).toBe(mockJob.pipeline.project.fullPath);
- expect(findProjectLink().attributes('href')).toBe(mockJob.pipeline.project.webUrl);
- });
- });
-});
diff --git a/spec/frontend/pages/admin/jobs/components/table/cells/runner_cell_spec.js b/spec/frontend/pages/admin/jobs/components/table/cells/runner_cell_spec.js
deleted file mode 100644
index 2f76ad66dd5..00000000000
--- a/spec/frontend/pages/admin/jobs/components/table/cells/runner_cell_spec.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerCell from '~/pages/admin/jobs/components/table/cells/runner_cell.vue';
-import { RUNNER_EMPTY_TEXT } from '~/pages/admin/jobs/components/constants';
-import { allRunnersData } from '../../../../../../ci/runner/mock_data';
-
-const mockRunner = allRunnersData.data.runners.nodes[0];
-
-const mockJobWithRunner = {
- id: 'gid://gitlab/Ci::Build/2264',
- runner: mockRunner,
-};
-
-const mockJobWithoutRunner = {
- id: 'gid://gitlab/Ci::Build/2265',
-};
-
-describe('Runner Cell', () => {
- let wrapper;
-
- const findRunnerLink = () => wrapper.findComponent(GlLink);
- const findEmptyRunner = () => wrapper.find('[data-testid="empty-runner-text"]');
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(RunnerCell, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('Runner Link', () => {
- describe('Job with runner', () => {
- beforeEach(() => {
- createComponent({ job: mockJobWithRunner });
- });
-
- it('shows and links to the runner', () => {
- expect(findRunnerLink().exists()).toBe(true);
- expect(findRunnerLink().text()).toBe(mockRunner.description);
- expect(findRunnerLink().attributes('href')).toBe(mockRunner.adminUrl);
- });
-
- it('hides the empty runner text', () => {
- expect(findEmptyRunner().exists()).toBe(false);
- });
- });
-
- describe('Job without runner', () => {
- beforeEach(() => {
- createComponent({ job: mockJobWithoutRunner });
- });
-
- it('shows default `empty` text', () => {
- expect(findEmptyRunner().exists()).toBe(true);
- expect(findEmptyRunner().text()).toBe(RUNNER_EMPTY_TEXT);
- });
-
- it('hides the runner link', () => {
- expect(findRunnerLink().exists()).toBe(false);
- });
- });
- });
-});
diff --git a/spec/frontend/pages/admin/jobs/components/table/graphql/cache_config_spec.js b/spec/frontend/pages/admin/jobs/components/table/graphql/cache_config_spec.js
deleted file mode 100644
index 59e9eda6343..00000000000
--- a/spec/frontend/pages/admin/jobs/components/table/graphql/cache_config_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import cacheConfig from '~/pages/admin/jobs/components/table/graphql/cache_config';
-import {
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCache,
- CIJobConnectionIncomingCacheRunningStatus,
-} from '../../../../../../jobs/mock_data';
-
-const firstLoadArgs = { first: 3, statuses: 'PENDING' };
-const runningArgs = { first: 3, statuses: 'RUNNING' };
-
-describe('jobs/components/table/graphql/cache_config', () => {
- describe('when fetching data with the same statuses', () => {
- it('should contain cache nodes and a status when merging caches on first load', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
- args: firstLoadArgs,
- });
-
- expect(res.nodes).toHaveLength(CIJobConnectionIncomingCache.nodes.length);
- expect(res.statuses).toBe('PENDING');
- });
-
- it('should add to existing caches when merging caches after first load', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCache,
- {
- args: firstLoadArgs,
- },
- );
-
- expect(res.nodes).toHaveLength(
- CIJobConnectionIncomingCache.nodes.length + CIJobConnectionExistingCache.nodes.length,
- );
- });
-
- it('should not add to existing cache if the incoming elements are the same', () => {
- // simulate that this is the last page
- const finalExistingCache = {
- ...CIJobConnectionExistingCache,
- pageInfo: {
- hasNextPage: false,
- },
- };
-
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- finalExistingCache,
- {
- args: firstLoadArgs,
- },
- );
-
- expect(res.nodes).toHaveLength(CIJobConnectionExistingCache.nodes.length);
- });
-
- it('should contain the pageInfo key as part of the result', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge({}, CIJobConnectionIncomingCache, {
- args: firstLoadArgs,
- });
-
- expect(res.pageInfo).toEqual(
- expect.objectContaining({
- __typename: 'PageInfo',
- endCursor: 'eyJpZCI6IjIwNTEifQ',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'eyJpZCI6IjIxNzMifQ',
- }),
- );
- });
- });
-
- describe('when fetching data with different statuses', () => {
- it('should reset cache when a cache already exists', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- CIJobConnectionIncomingCacheRunningStatus,
- {
- args: runningArgs,
- },
- );
-
- expect(res.nodes).not.toEqual(CIJobConnectionExistingCache.nodes);
- expect(res.nodes).toHaveLength(CIJobConnectionIncomingCacheRunningStatus.nodes.length);
- });
- });
-
- describe('when incoming data has no nodes', () => {
- it('should return existing cache', () => {
- const res = cacheConfig.typePolicies.CiJobConnection.merge(
- CIJobConnectionExistingCache,
- { __typename: 'CiJobConnection', count: 500 },
- {
- args: { statuses: 'SUCCESS' },
- },
- );
-
- const expectedResponse = {
- ...CIJobConnectionExistingCache,
- statuses: 'SUCCESS',
- };
-
- expect(res).toEqual(expectedResponse);
- });
- });
-});
diff --git a/spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js b/spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js
index 40d5dff9d06..50bc5bc590b 100644
--- a/spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js
+++ b/spec/frontend/pages/import/bitbucket_server/components/bitbucket_server_status_table_spec.js
@@ -12,11 +12,7 @@ const BitbucketStatusTableStub = {
describe('BitbucketServerStatusTable', () => {
let wrapper;
- const findReconfigureButton = () =>
- wrapper
- .findAllComponents(GlButton)
- .filter((w) => w.props().variant === 'info')
- .at(0);
+ const findReconfigureButton = () => wrapper.findComponent(GlButton);
function createComponent(bitbucketStatusTableStub = true) {
wrapper = shallowMount(BitbucketServerStatusTable, {
diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
deleted file mode 100644
index e20c2fa47a7..00000000000
--- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import { GlButton } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import Cookies from '~/lib/utils/cookies';
-import PipelineSchedulesCallout from '~/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue';
-
-const cookieKey = 'pipeline_schedules_callout_dismissed';
-const docsUrl = 'help/ci/scheduled_pipelines';
-const illustrationUrl = 'pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg';
-
-describe('Pipeline Schedule Callout', () => {
- let wrapper;
-
- const createComponent = () => {
- wrapper = shallowMount(PipelineSchedulesCallout, {
- provide: {
- docsUrl,
- illustrationUrl,
- },
- });
- };
-
- const findInnerContentOfCallout = () => wrapper.find('[data-testid="innerContent"]');
- const findDismissCalloutBtn = () => wrapper.findComponent(GlButton);
-
- describe(`when ${cookieKey} cookie is set`, () => {
- beforeEach(async () => {
- Cookies.set(cookieKey, true);
- createComponent();
-
- await nextTick();
- });
-
- it('does not render the callout', () => {
- expect(findInnerContentOfCallout().exists()).toBe(false);
- });
- });
-
- describe('when cookie is not set', () => {
- beforeEach(() => {
- Cookies.remove(cookieKey);
- createComponent();
- });
-
- it('renders the callout container', () => {
- expect(findInnerContentOfCallout().exists()).toBe(true);
- });
-
- it('renders the callout title', () => {
- expect(wrapper.find('h4').text()).toBe('Scheduling Pipelines');
- });
-
- it('renders the callout text', () => {
- expect(wrapper.find('p').text()).toContain('runs pipelines in the future');
- });
-
- it('renders the documentation url', () => {
- expect(wrapper.find('a').attributes('href')).toBe(docsUrl);
- });
-
- describe('methods', () => {
- it('#dismissCallout sets calloutDismissed to true', async () => {
- expect(wrapper.vm.calloutDismissed).toBe(false);
-
- findDismissCalloutBtn().vm.$emit('click');
-
- await nextTick();
-
- expect(findInnerContentOfCallout().exists()).toBe(false);
- });
-
- it('sets cookie on dismiss', () => {
- const setCookiesSpy = jest.spyOn(Cookies, 'set');
-
- findDismissCalloutBtn().vm.$emit('click');
-
- expect(setCookiesSpy).toHaveBeenCalledWith('pipeline_schedules_callout_dismissed', true, {
- expires: 365,
- secure: false,
- });
- });
- });
-
- it('is hidden when close button is clicked', async () => {
- findDismissCalloutBtn().vm.$emit('click');
-
- await nextTick();
-
- expect(findInnerContentOfCallout().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap b/spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap
deleted file mode 100644
index cb5f6ff5307..00000000000
--- a/spec/frontend/pipelines/components/dag/__snapshots__/dag_graph_spec.js.snap
+++ /dev/null
@@ -1,230 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`The DAG graph in the basic case renders the graph svg 1`] = `
-"<svg viewBox=\\"0,0,1000,540\\" width=\\"1000\\" height=\\"540\\">
- <g fill=\\"none\\" stroke-opacity=\\"0.8\\">
- <g id=\\"dag-link43\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad53\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"116\\" x2=\\"361.3333333333333\\">
- <stop offset=\\"0%\\" stop-color=\\"#e17223\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#83ab4a\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip63\\">
- <path d=\\"
- M100, 129
- V158
- H377.3333333333333
- V100
- H100
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M108,129L190,129L190,129L369.3333333333333,129\\" stroke=\\"url(#dag-grad53)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip63)\\"></path>
- </g>
- <g id=\\"dag-link44\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad54\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"377.3333333333333\\" x2=\\"622.6666666666666\\">
- <stop offset=\\"0%\\" stop-color=\\"#83ab4a\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#6f3500\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip64\\">
- <path d=\\"
- M361.3333333333333, 129.0000000000002
- V158.0000000000002
- H638.6666666666666
- V100
- H361.3333333333333
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M369.3333333333333,129L509.3333333333333,129L509.3333333333333,129.0000000000002L630.6666666666666,129.0000000000002\\" stroke=\\"url(#dag-grad54)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip64)\\"></path>
- </g>
- <g id=\\"dag-link45\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad55\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"116\\" x2=\\"622.6666666666666\\">
- <stop offset=\\"0%\\" stop-color=\\"#5772ff\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#6f3500\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip65\\">
- <path d=\\"
- M100, 187.0000000000002
- V241.00000000000003
- H638.6666666666666
- V158.0000000000002
- H100
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M108,212.00000000000003L306,212.00000000000003L306,187.0000000000002L630.6666666666666,187.0000000000002\\" stroke=\\"url(#dag-grad55)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip65)\\"></path>
- </g>
- <g id=\\"dag-link46\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad56\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"116\\" x2=\\"361.3333333333333\\">
- <stop offset=\\"0%\\" stop-color=\\"#b24800\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#006887\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip66\\">
- <path d=\\"
- M100, 269.9999999999998
- V324
- H377.3333333333333
- V240.99999999999977
- H100
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M108,295L338.93333333333334,295L338.93333333333334,269.9999999999998L369.3333333333333,269.9999999999998\\" stroke=\\"url(#dag-grad56)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip66)\\"></path>
- </g>
- <g id=\\"dag-link47\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad57\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"116\\" x2=\\"361.3333333333333\\">
- <stop offset=\\"0%\\" stop-color=\\"#25d2d2\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#487900\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip67\\">
- <path d=\\"
- M100, 352.99999999999994
- V407.00000000000006
- H377.3333333333333
- V323.99999999999994
- H100
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M108,378.00000000000006L144.66666666666669,378.00000000000006L144.66666666666669,352.99999999999994L369.3333333333333,352.99999999999994\\" stroke=\\"url(#dag-grad57)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip67)\\"></path>
- </g>
- <g id=\\"dag-link48\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad58\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"377.3333333333333\\" x2=\\"622.6666666666666\\">
- <stop offset=\\"0%\\" stop-color=\\"#006887\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#d84280\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip68\\">
- <path d=\\"
- M361.3333333333333, 270.0000000000001
- V299.0000000000001
- H638.6666666666666
- V240.99999999999977
- H361.3333333333333
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M369.3333333333333,269.9999999999998L464,269.9999999999998L464,270.0000000000001L630.6666666666666,270.0000000000001\\" stroke=\\"url(#dag-grad58)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip68)\\"></path>
- </g>
- <g id=\\"dag-link49\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad59\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"377.3333333333333\\" x2=\\"622.6666666666666\\">
- <stop offset=\\"0%\\" stop-color=\\"#487900\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#d84280\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip69\\">
- <path d=\\"
- M361.3333333333333, 328.0000000000001
- V381.99999999999994
- H638.6666666666666
- V299.0000000000001
- H361.3333333333333
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M369.3333333333333,352.99999999999994L522,352.99999999999994L522,328.0000000000001L630.6666666666666,328.0000000000001\\" stroke=\\"url(#dag-grad59)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip69)\\"></path>
- </g>
- <g id=\\"dag-link50\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad60\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"377.3333333333333\\" x2=\\"622.6666666666666\\">
- <stop offset=\\"0%\\" stop-color=\\"#487900\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#3547de\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip70\\">
- <path d=\\"
- M361.3333333333333, 411
- V440
- H638.6666666666666
- V381.99999999999994
- H361.3333333333333
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M369.3333333333333,410.99999999999994L580,410.99999999999994L580,411L630.6666666666666,411\\" stroke=\\"url(#dag-grad60)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip70)\\"></path>
- </g>
- <g id=\\"dag-link51\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad61\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"638.6666666666666\\" x2=\\"884\\">
- <stop offset=\\"0%\\" stop-color=\\"#d84280\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#006887\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip71\\">
- <path d=\\"
- M622.6666666666666, 270.1890725105691
- V299.1890725105691
- H900
- V241.0000000000001
- H622.6666666666666
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M630.6666666666666,270.0000000000001L861.6,270.0000000000001L861.6,270.1890725105691L892,270.1890725105691\\" stroke=\\"url(#dag-grad61)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip71)\\"></path>
- </g>
- <g id=\\"dag-link52\\" class=\\"dag-link gl-transition-property-stroke-opacity gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\">
- <linearGradient id=\\"dag-grad62\\" gradientUnits=\\"userSpaceOnUse\\" x1=\\"638.6666666666666\\" x2=\\"884\\">
- <stop offset=\\"0%\\" stop-color=\\"#3547de\\"></stop>
- <stop offset=\\"100%\\" stop-color=\\"#275600\\"></stop>
- </linearGradient>
- <clipPath id=\\"dag-clip72\\">
- <path d=\\"
- M622.6666666666666, 411
- V440
- H900
- V382
- H622.6666666666666
- Z
- \\"></path>
- </clipPath>
- <path d=\\"M630.6666666666666,411L679.9999999999999,411L679.9999999999999,411L892,411\\" stroke=\\"url(#dag-grad62)\\" style=\\"stroke-linejoin: round;\\" stroke-width=\\"56\\" clip-path=\\"url(#dag-clip72)\\"></path>
- </g>
- </g>
- <g>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node73\\" stroke=\\"#e17223\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"108\\" x2=\\"108\\" y1=\\"104\\" y2=\\"154.00000000000003\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node74\\" stroke=\\"#83ab4a\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"369\\" x2=\\"369\\" y1=\\"104\\" y2=\\"154\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node75\\" stroke=\\"#5772ff\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"108\\" x2=\\"108\\" y1=\\"187.00000000000003\\" y2=\\"237.00000000000003\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node76\\" stroke=\\"#b24800\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"108\\" x2=\\"108\\" y1=\\"270\\" y2=\\"320.00000000000006\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node77\\" stroke=\\"#25d2d2\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"108\\" x2=\\"108\\" y1=\\"353.00000000000006\\" y2=\\"403.0000000000001\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node78\\" stroke=\\"#6f3500\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"630\\" x2=\\"630\\" y1=\\"104.0000000000002\\" y2=\\"212.00000000000009\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node79\\" stroke=\\"#006887\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"369\\" x2=\\"369\\" y1=\\"244.99999999999977\\" y2=\\"294.99999999999994\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node80\\" stroke=\\"#487900\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"369\\" x2=\\"369\\" y1=\\"327.99999999999994\\" y2=\\"436\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node81\\" stroke=\\"#d84280\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"630\\" x2=\\"630\\" y1=\\"245.00000000000009\\" y2=\\"353\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node82\\" stroke=\\"#3547de\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"630\\" x2=\\"630\\" y1=\\"386\\" y2=\\"436\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node83\\" stroke=\\"#006887\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"892\\" x2=\\"892\\" y1=\\"245.18907251056908\\" y2=\\"295.1890725105691\\"></line>
- <line class=\\"dag-node gl-transition-property-stroke gl-cursor-pointer gl-transition-duration-slow gl-transition-timing-function-ease\\" id=\\"dag-node84\\" stroke=\\"#275600\\" stroke-width=\\"16\\" stroke-linecap=\\"round\\" x1=\\"892\\" x2=\\"892\\" y1=\\"386\\" y2=\\"436\\"></line>
- </g>
- <g class=\\"gl-font-sm\\">
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58.00000000000003px\\" width=\\"84\\" x=\\"8\\" y=\\"100\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58.00000000000003px; text-align: right;\\">build_a</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"369.3333333333333\\" y=\\"75\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: left;\\">test_a</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58px\\" width=\\"84\\" x=\\"8\\" y=\\"183.00000000000003\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58px; text-align: right;\\">test_b</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58.00000000000006px\\" width=\\"84\\" x=\\"8\\" y=\\"266\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58.00000000000006px; text-align: right;\\">post_test_a</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58.00000000000006px\\" width=\\"84\\" x=\\"8\\" y=\\"349.00000000000006\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58.00000000000006px; text-align: right;\\">post_test_b</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"630.6666666666666\\" y=\\"75.0000000000002\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: right;\\">post_test_c</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"369.3333333333333\\" y=\\"215.99999999999977\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: left;\\">staging_a</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"369.3333333333333\\" y=\\"298.99999999999994\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: left;\\">staging_b</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"630.6666666666666\\" y=\\"216.00000000000009\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: right;\\">canary_a</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"25px\\" width=\\"84\\" x=\\"630.6666666666666\\" y=\\"357\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 25px; text-align: right;\\">canary_c</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58px\\" width=\\"84\\" x=\\"908\\" y=\\"241.18907251056908\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58px; text-align: left;\\">production_a</div>
- </foreignObject>
- <foreignObject requiredFeatures=\\"http://www.w3.org/TR/SVG11/feature#Extensibility\\" height=\\"58px\\" width=\\"84\\" x=\\"908\\" y=\\"382\\" class=\\"gl-overflow-visible\\">
- <div class=\\"gl-display-flex gl-pointer-events-none gl-flex-direction-column gl-justify-content-center gl-overflow-wrap-break\\" style=\\"height: 58px; text-align: left;\\">production_d</div>
- </foreignObject>
- </g>
-</svg>"
-`;
diff --git a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js b/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
deleted file mode 100644
index 124f02bcec7..00000000000
--- a/spec/frontend/pipelines/components/dag/dag_annotations_spec.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import { GlButton } from '@gitlab/ui';
-import { shallowMount, mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import DagAnnotations from '~/pipelines/components/dag/dag_annotations.vue';
-import { singleNote, multiNote } from './mock_data';
-
-describe('The DAG annotations', () => {
- let wrapper;
-
- const getColorBlock = () => wrapper.find('[data-testid="dag-color-block"]');
- const getAllColorBlocks = () => wrapper.findAll('[data-testid="dag-color-block"]');
- const getTextBlock = () => wrapper.find('[data-testid="dag-note-text"]');
- const getAllTextBlocks = () => wrapper.findAll('[data-testid="dag-note-text"]');
- const getToggleButton = () => wrapper.findComponent(GlButton);
-
- const createComponent = (propsData = {}, method = shallowMount) => {
- wrapper = method(DagAnnotations, {
- propsData,
- data() {
- return {
- showList: true,
- };
- },
- });
- };
-
- describe('when there is one annotation', () => {
- const currentNote = singleNote['dag-link103'];
-
- beforeEach(() => {
- createComponent({ annotations: singleNote });
- });
-
- it('displays the color block', () => {
- expect(getColorBlock().exists()).toBe(true);
- });
-
- it('displays the text block', () => {
- expect(getTextBlock().exists()).toBe(true);
- expect(getTextBlock().text()).toBe(`${currentNote.source.name} → ${currentNote.target.name}`);
- });
-
- it('does not display the list toggle link', () => {
- expect(getToggleButton().exists()).toBe(false);
- });
- });
-
- describe('when there are multiple annoataions', () => {
- beforeEach(() => {
- createComponent({ annotations: multiNote });
- });
-
- it('displays a color block for each link', () => {
- expect(getAllColorBlocks().length).toBe(Object.keys(multiNote).length);
- });
-
- it('displays a text block for each link', () => {
- expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length);
-
- Object.values(multiNote).forEach((item, idx) => {
- expect(getAllTextBlocks().at(idx).text()).toBe(`${item.source.name} → ${item.target.name}`);
- });
- });
-
- it('displays the list toggle link', () => {
- expect(getToggleButton().exists()).toBe(true);
- expect(getToggleButton().text()).toBe('Hide list');
- });
- });
-
- describe('the list toggle', () => {
- beforeEach(() => {
- createComponent({ annotations: multiNote }, mount);
- });
-
- describe('clicking hide', () => {
- it('hides listed items and changes text to show', async () => {
- expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length);
- expect(getToggleButton().text()).toBe('Hide list');
- getToggleButton().trigger('click');
- await nextTick();
- expect(getAllTextBlocks().length).toBe(0);
- expect(getToggleButton().text()).toBe('Show list');
- });
- });
-
- describe('clicking show', () => {
- it('shows listed items and changes text to hide', async () => {
- getToggleButton().trigger('click');
- getToggleButton().trigger('click');
-
- await nextTick();
- expect(getAllTextBlocks().length).toBe(Object.keys(multiNote).length);
- expect(getToggleButton().text()).toBe('Hide list');
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/dag/dag_graph_spec.js b/spec/frontend/pipelines/components/dag/dag_graph_spec.js
deleted file mode 100644
index 6b46be3dd49..00000000000
--- a/spec/frontend/pipelines/components/dag/dag_graph_spec.js
+++ /dev/null
@@ -1,209 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { IS_HIGHLIGHTED, LINK_SELECTOR, NODE_SELECTOR } from '~/pipelines/components/dag/constants';
-import DagGraph from '~/pipelines/components/dag/dag_graph.vue';
-import { createSankey } from '~/pipelines/components/dag/drawing_utils';
-import { highlightIn, highlightOut } from '~/pipelines/components/dag/interactions';
-import { removeOrphanNodes } from '~/pipelines/components/parsing_utils';
-import { parsedData } from './mock_data';
-
-describe('The DAG graph', () => {
- let wrapper;
-
- const getGraph = () => wrapper.find('.dag-graph-container > svg');
- const getAllLinks = () => wrapper.findAll(`.${LINK_SELECTOR}`);
- const getAllNodes = () => wrapper.findAll(`.${NODE_SELECTOR}`);
- const getAllLabels = () => wrapper.findAll('foreignObject');
-
- const createComponent = (propsData = {}) => {
- if (wrapper?.destroy) {
- wrapper.destroy();
- }
-
- wrapper = shallowMount(DagGraph, {
- attachTo: document.body,
- propsData,
- data() {
- return {
- color: () => {},
- width: 0,
- height: 0,
- };
- },
- });
- };
-
- beforeEach(() => {
- createComponent({ graphData: parsedData });
- });
-
- describe('in the basic case', () => {
- beforeEach(() => {
- /*
- The graph uses random to offset links. To keep the snapshot consistent,
- we mock Math.random. Wheeeee!
- */
- const randomNumber = jest.spyOn(global.Math, 'random');
- randomNumber.mockImplementation(() => 0.2);
- createComponent({ graphData: parsedData });
- });
-
- it('renders the graph svg', () => {
- expect(getGraph().exists()).toBe(true);
- expect(getGraph().html()).toMatchSnapshot();
- });
- });
-
- describe('links', () => {
- it('renders the expected number of links', () => {
- expect(getAllLinks()).toHaveLength(parsedData.links.length);
- });
-
- it('renders the expected number of gradients', () => {
- expect(wrapper.findAll('linearGradient')).toHaveLength(parsedData.links.length);
- });
-
- it('renders the expected number of clip paths', () => {
- expect(wrapper.findAll('clipPath')).toHaveLength(parsedData.links.length);
- });
- });
-
- describe('nodes and labels', () => {
- const sankeyNodes = createSankey()(parsedData).nodes;
- const processedNodes = removeOrphanNodes(sankeyNodes);
-
- describe('nodes', () => {
- it('renders the expected number of nodes', () => {
- expect(getAllNodes()).toHaveLength(processedNodes.length);
- });
- });
-
- describe('labels', () => {
- it('renders the expected number of labels as foreignObjects', () => {
- expect(getAllLabels()).toHaveLength(processedNodes.length);
- });
-
- it('renders the title as text', () => {
- expect(getAllLabels().at(0).text()).toBe(parsedData.nodes[0].name);
- });
- });
- });
-
- describe('interactions', () => {
- const strokeOpacity = (opacity) => `stroke-opacity: ${opacity};`;
- const baseOpacity = () => wrapper.vm.$options.viewOptions.baseOpacity;
-
- describe('links', () => {
- const liveLink = () => getAllLinks().at(4);
- const otherLink = () => getAllLinks().at(1);
-
- describe('on hover', () => {
- it('sets the link opacity to baseOpacity and background links to 0.2', () => {
- liveLink().trigger('mouseover');
- expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
- expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
- });
-
- it('reverts the styles on mouseout', () => {
- liveLink().trigger('mouseover');
- liveLink().trigger('mouseout');
- expect(liveLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
- expect(otherLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
- });
- });
-
- describe('on click', () => {
- describe('toggles link liveness', () => {
- it('turns link on', () => {
- liveLink().trigger('click');
- expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
- expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
- });
-
- it('turns link off on second click', () => {
- liveLink().trigger('click');
- liveLink().trigger('click');
- expect(liveLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
- expect(otherLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
- });
- });
-
- it('the link remains live even after mouseout', () => {
- liveLink().trigger('click');
- liveLink().trigger('mouseout');
- expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
- expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
- });
-
- it('preserves state when multiple links are toggled on and off', () => {
- const anotherLiveLink = () => getAllLinks().at(2);
-
- liveLink().trigger('click');
- anotherLiveLink().trigger('click');
- expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
- expect(anotherLiveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
- expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
-
- anotherLiveLink().trigger('click');
- expect(liveLink().attributes('style')).toBe(strokeOpacity(highlightIn));
- expect(anotherLiveLink().attributes('style')).toBe(strokeOpacity(highlightOut));
- expect(otherLink().attributes('style')).toBe(strokeOpacity(highlightOut));
-
- liveLink().trigger('click');
- expect(liveLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
- expect(anotherLiveLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
- expect(otherLink().attributes('style')).toBe(strokeOpacity(baseOpacity()));
- });
- });
- });
-
- describe('nodes', () => {
- const liveNode = () => getAllNodes().at(10);
- const anotherLiveNode = () => getAllNodes().at(5);
- const nodesNotHighlighted = () => getAllNodes().filter((n) => !n.classes(IS_HIGHLIGHTED));
- const linksNotHighlighted = () => getAllLinks().filter((n) => !n.classes(IS_HIGHLIGHTED));
- const nodesHighlighted = () => getAllNodes().filter((n) => n.classes(IS_HIGHLIGHTED));
- const linksHighlighted = () => getAllLinks().filter((n) => n.classes(IS_HIGHLIGHTED));
-
- describe('on click', () => {
- it('highlights the clicked node and predecessors', () => {
- liveNode().trigger('click');
-
- expect(nodesNotHighlighted().length < getAllNodes().length).toBe(true);
- expect(linksNotHighlighted().length < getAllLinks().length).toBe(true);
-
- linksHighlighted().wrappers.forEach((link) => {
- expect(link.attributes('style')).toBe(strokeOpacity(highlightIn));
- });
-
- nodesHighlighted().wrappers.forEach((node) => {
- expect(node.attributes('stroke')).not.toBe('#f2f2f2');
- });
-
- linksNotHighlighted().wrappers.forEach((link) => {
- expect(link.attributes('style')).toBe(strokeOpacity(highlightOut));
- });
-
- nodesNotHighlighted().wrappers.forEach((node) => {
- expect(node.attributes('stroke')).toBe('#f2f2f2');
- });
- });
-
- it('toggles path off on second click', () => {
- liveNode().trigger('click');
- liveNode().trigger('click');
-
- expect(nodesNotHighlighted().length).toBe(getAllNodes().length);
- expect(linksNotHighlighted().length).toBe(getAllLinks().length);
- });
-
- it('preserves state when multiple nodes are toggled on and off', () => {
- anotherLiveNode().trigger('click');
- liveNode().trigger('click');
- anotherLiveNode().trigger('click');
- expect(nodesNotHighlighted().length < getAllNodes().length).toBe(true);
- expect(linksNotHighlighted().length < getAllLinks().length).toBe(true);
- });
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/dag/dag_spec.js b/spec/frontend/pipelines/components/dag/dag_spec.js
deleted file mode 100644
index 53719065611..00000000000
--- a/spec/frontend/pipelines/components/dag/dag_spec.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import { GlAlert, GlEmptyState } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import { ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from '~/pipelines/components/dag/constants';
-import Dag from '~/pipelines/components/dag/dag.vue';
-import DagAnnotations from '~/pipelines/components/dag/dag_annotations.vue';
-import DagGraph from '~/pipelines/components/dag/dag_graph.vue';
-
-import { PARSE_FAILURE, UNSUPPORTED_DATA } from '~/pipelines/constants';
-import {
- mockParsedGraphQLNodes,
- tooSmallGraph,
- unparseableGraph,
- graphWithoutDependencies,
- singleNote,
- multiNote,
-} from './mock_data';
-
-describe('Pipeline DAG graph wrapper', () => {
- let wrapper;
- const getAlert = () => wrapper.findComponent(GlAlert);
- const getAllAlerts = () => wrapper.findAllComponents(GlAlert);
- const getGraph = () => wrapper.findComponent(DagGraph);
- const getNotes = () => wrapper.findComponent(DagAnnotations);
- const getErrorText = (type) => wrapper.vm.$options.errorTexts[type];
- const getEmptyState = () => wrapper.findComponent(GlEmptyState);
-
- const createComponent = ({
- graphData = mockParsedGraphQLNodes,
- provideOverride = {},
- method = shallowMount,
- } = {}) => {
- wrapper = method(Dag, {
- provide: {
- pipelineProjectPath: 'root/abc-dag',
- pipelineIid: '1',
- emptySvgPath: '/my-svg',
- dagDocPath: '/my-doc',
- ...provideOverride,
- },
- data() {
- return {
- graphData,
- showFailureAlert: false,
- };
- },
- });
- };
-
- describe('when a query argument is undefined', () => {
- beforeEach(() => {
- createComponent({
- provideOverride: { pipelineProjectPath: undefined },
- graphData: null,
- });
- });
-
- it('does not render the graph', () => {
- expect(getGraph().exists()).toBe(false);
- });
-
- it('does not render the empty state', () => {
- expect(getEmptyState().exists()).toBe(false);
- });
- });
-
- describe('when all query variables are defined', () => {
- describe('but the parse fails', () => {
- beforeEach(() => {
- createComponent({
- graphData: unparseableGraph,
- });
- });
-
- it('shows the PARSE_FAILURE alert and not the graph', () => {
- expect(getAlert().exists()).toBe(true);
- expect(getAlert().text()).toBe(getErrorText(PARSE_FAILURE));
- expect(getGraph().exists()).toBe(false);
- });
-
- it('does not render the empty state', () => {
- expect(getEmptyState().exists()).toBe(false);
- });
- });
-
- describe('parse succeeds', () => {
- beforeEach(() => {
- createComponent({ method: mount });
- });
-
- it('shows the graph', () => {
- expect(getGraph().exists()).toBe(true);
- });
-
- it('does not render the empty state', () => {
- expect(getEmptyState().exists()).toBe(false);
- });
- });
-
- describe('parse succeeds, but the resulting graph is too small', () => {
- beforeEach(() => {
- createComponent({
- graphData: tooSmallGraph,
- });
- });
-
- it('shows the UNSUPPORTED_DATA alert and not the graph', () => {
- expect(getAlert().exists()).toBe(true);
- expect(getAlert().text()).toBe(getErrorText(UNSUPPORTED_DATA));
- expect(getGraph().exists()).toBe(false);
- });
-
- it('does not show the empty dag graph state', () => {
- expect(getEmptyState().exists()).toBe(false);
- });
- });
-
- describe('the returned data is empty', () => {
- beforeEach(() => {
- createComponent({
- method: mount,
- graphData: graphWithoutDependencies,
- });
- });
-
- it('does not render an error alert or the graph', () => {
- expect(getAllAlerts().length).toBe(0);
- expect(getGraph().exists()).toBe(false);
- });
-
- it('shows the empty dag graph state', () => {
- expect(getEmptyState().exists()).toBe(true);
- });
- });
- });
-
- describe('annotations', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('toggles on link mouseover and mouseout', async () => {
- const currentNote = singleNote['dag-link103'];
-
- expect(getNotes().exists()).toBe(false);
-
- getGraph().vm.$emit('update-annotation', { type: ADD_NOTE, data: currentNote });
- await nextTick();
- expect(getNotes().exists()).toBe(true);
-
- getGraph().vm.$emit('update-annotation', { type: REMOVE_NOTE, data: currentNote });
- await nextTick();
- expect(getNotes().exists()).toBe(false);
- });
-
- it('toggles on node and link click', async () => {
- expect(getNotes().exists()).toBe(false);
-
- getGraph().vm.$emit('update-annotation', { type: REPLACE_NOTES, data: multiNote });
- await nextTick();
- expect(getNotes().exists()).toBe(true);
-
- getGraph().vm.$emit('update-annotation', { type: REPLACE_NOTES, data: {} });
- await nextTick();
- expect(getNotes().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/dag/drawing_utils_spec.js b/spec/frontend/pipelines/components/dag/drawing_utils_spec.js
deleted file mode 100644
index 095ded01298..00000000000
--- a/spec/frontend/pipelines/components/dag/drawing_utils_spec.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import { createSankey } from '~/pipelines/components/dag/drawing_utils';
-import { parseData } from '~/pipelines/components/parsing_utils';
-import { mockParsedGraphQLNodes } from './mock_data';
-
-describe('DAG visualization drawing utilities', () => {
- const parsed = parseData(mockParsedGraphQLNodes);
-
- const layoutSettings = {
- width: 200,
- height: 200,
- nodeWidth: 10,
- nodePadding: 20,
- paddingForLabels: 100,
- };
-
- const sankeyLayout = createSankey(layoutSettings)(parsed);
-
- describe('createSankey', () => {
- it('returns a nodes data structure with expected d3-added properties', () => {
- const exampleNode = sankeyLayout.nodes[0];
- expect(exampleNode).toHaveProperty('sourceLinks');
- expect(exampleNode).toHaveProperty('targetLinks');
- expect(exampleNode).toHaveProperty('depth');
- expect(exampleNode).toHaveProperty('layer');
- expect(exampleNode).toHaveProperty('x0');
- expect(exampleNode).toHaveProperty('x1');
- expect(exampleNode).toHaveProperty('y0');
- expect(exampleNode).toHaveProperty('y1');
- });
-
- it('returns a links data structure with expected d3-added properties', () => {
- const exampleLink = sankeyLayout.links[0];
- expect(exampleLink).toHaveProperty('source');
- expect(exampleLink).toHaveProperty('target');
- expect(exampleLink).toHaveProperty('width');
- expect(exampleLink).toHaveProperty('y0');
- expect(exampleLink).toHaveProperty('y1');
- });
-
- describe('data structure integrity', () => {
- const newObject = { name: 'bad-actor' };
-
- beforeEach(() => {
- sankeyLayout.nodes.unshift(newObject);
- });
-
- it('sankey does not propagate changes back to the original', () => {
- expect(sankeyLayout.nodes[0]).toBe(newObject);
- expect(parsed.nodes[0]).not.toBe(newObject);
- });
-
- afterEach(() => {
- sankeyLayout.nodes.shift();
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js
deleted file mode 100644
index 6a2453704db..00000000000
--- a/spec/frontend/pipelines/components/jobs/failed_jobs_app_spec.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import { GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import FailedJobsApp from '~/pipelines/components/jobs/failed_jobs_app.vue';
-import FailedJobsTable from '~/pipelines/components/jobs/failed_jobs_table.vue';
-import GetFailedJobsQuery from '~/pipelines/graphql/queries/get_failed_jobs.query.graphql';
-import { mockFailedJobsQueryResponse } from '../../mock_data';
-
-Vue.use(VueApollo);
-
-jest.mock('~/alert');
-
-describe('Failed Jobs App', () => {
- let wrapper;
- let resolverSpy;
-
- const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
- const findJobsTable = () => wrapper.findComponent(FailedJobsTable);
-
- const createMockApolloProvider = (resolver) => {
- const requestHandlers = [[GetFailedJobsQuery, resolver]];
-
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = (resolver) => {
- wrapper = shallowMount(FailedJobsApp, {
- provide: {
- fullPath: 'root/ci-project',
- pipelineIid: 1,
- },
- apolloProvider: createMockApolloProvider(resolver),
- });
- };
-
- beforeEach(() => {
- resolverSpy = jest.fn().mockResolvedValue(mockFailedJobsQueryResponse);
- });
-
- describe('loading spinner', () => {
- it('displays loading spinner when fetching failed jobs', () => {
- createComponent(resolverSpy);
-
- expect(findLoadingSpinner().exists()).toBe(true);
- });
-
- it('hides loading spinner after the failed jobs have been fetched', async () => {
- createComponent(resolverSpy);
-
- await waitForPromises();
-
- expect(findLoadingSpinner().exists()).toBe(false);
- });
- });
-
- it('displays the failed jobs table', async () => {
- createComponent(resolverSpy);
-
- await waitForPromises();
-
- expect(findJobsTable().exists()).toBe(true);
- expect(createAlert).not.toHaveBeenCalled();
- });
-
- it('handles query fetch error correctly', async () => {
- resolverSpy = jest.fn().mockRejectedValue(new Error('GraphQL error'));
-
- createComponent(resolverSpy);
-
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: 'There was a problem fetching the failed jobs.',
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js b/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
deleted file mode 100644
index 99a178120cc..00000000000
--- a/spec/frontend/pipelines/components/jobs/failed_jobs_table_spec.js
+++ /dev/null
@@ -1,141 +0,0 @@
-import { GlButton, GlLink, GlTableLite } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { createAlert } from '~/alert';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import FailedJobsTable from '~/pipelines/components/jobs/failed_jobs_table.vue';
-import RetryFailedJobMutation from '~/pipelines/graphql/mutations/retry_failed_job.mutation.graphql';
-import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-import {
- successRetryMutationResponse,
- failedRetryMutationResponse,
- mockFailedJobsData,
- mockFailedJobsDataNoPermission,
-} from '../../mock_data';
-
-jest.mock('~/alert');
-jest.mock('~/lib/utils/url_utility');
-
-Vue.use(VueApollo);
-
-describe('Failed Jobs Table', () => {
- let wrapper;
-
- const successRetryMutationHandler = jest.fn().mockResolvedValue(successRetryMutationResponse);
- const failedRetryMutationHandler = jest.fn().mockResolvedValue(failedRetryMutationResponse);
-
- const findJobsTable = () => wrapper.findComponent(GlTableLite);
- const findRetryButton = () => wrapper.findComponent(GlButton);
- const findJobLink = () => wrapper.findComponent(GlLink);
- const findJobLog = () => wrapper.findByTestId('job-log');
- const findSummary = (index) => wrapper.findAllByTestId('job-trace-summary').at(index);
- const findFirstFailureMessage = () => wrapper.findAllByTestId('job-failure-message').at(0);
-
- const createMockApolloProvider = (resolver) => {
- const requestHandlers = [[RetryFailedJobMutation, resolver]];
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = (resolver, failedJobsData = mockFailedJobsData) => {
- wrapper = mountExtended(FailedJobsTable, {
- propsData: {
- failedJobs: failedJobsData,
- },
- apolloProvider: createMockApolloProvider(resolver),
- });
- };
-
- it('displays the failed jobs table', () => {
- createComponent();
-
- expect(findJobsTable().exists()).toBe(true);
- });
-
- it('displays failed job summary', () => {
- createComponent();
-
- expect(findSummary(0).text()).toBe('Html Summary');
- });
-
- it('displays no job log when no trace', () => {
- createComponent();
-
- expect(findSummary(1).text()).toBe('No job log');
- });
-
- it('displays failure reason', () => {
- createComponent();
-
- expect(findFirstFailureMessage().text()).toBe('Job failed');
- });
-
- it('calls the retry failed job mutation and tracks the click', () => {
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
-
- createComponent(successRetryMutationHandler);
-
- findRetryButton().trigger('click');
-
- expect(successRetryMutationHandler).toHaveBeenCalledWith({
- id: mockFailedJobsData[0].id,
- });
- expect(trackingSpy).toHaveBeenCalledTimes(1);
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_retry', {
- label: TRACKING_CATEGORIES.failed,
- });
-
- unmockTracking();
- });
-
- it('redirects to the new job after the mutation', async () => {
- const {
- data: {
- jobRetry: { job },
- },
- } = successRetryMutationResponse;
-
- createComponent(successRetryMutationHandler);
-
- findRetryButton().trigger('click');
-
- await waitForPromises();
-
- expect(redirectTo).toHaveBeenCalledWith(job.detailedStatus.detailsPath); // eslint-disable-line import/no-deprecated
- });
-
- it('shows error message if the retry failed job mutation fails', async () => {
- createComponent(failedRetryMutationHandler);
-
- findRetryButton().trigger('click');
-
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: 'There was a problem retrying the failed job.',
- });
- });
-
- it('hides the job log and retry button if a user does not have permission', () => {
- createComponent([[]], mockFailedJobsDataNoPermission);
-
- expect(findJobLog().exists()).toBe(false);
- expect(findRetryButton().exists()).toBe(false);
- });
-
- it('displays the job log and retry button if a user has permission', () => {
- createComponent();
-
- expect(findJobLog().exists()).toBe(true);
- expect(findRetryButton().exists()).toBe(true);
- });
-
- it('job name links to the correct job', () => {
- createComponent();
-
- expect(findJobLink().attributes('href')).toBe(mockFailedJobsData[0].detailedStatus.detailsPath);
- });
-});
diff --git a/spec/frontend/pipelines/components/jobs/jobs_app_spec.js b/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
deleted file mode 100644
index 39475788fe2..00000000000
--- a/spec/frontend/pipelines/components/jobs/jobs_app_spec.js
+++ /dev/null
@@ -1,127 +0,0 @@
-import { GlIntersectionObserver, GlSkeletonLoader, GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import JobsApp from '~/pipelines/components/jobs/jobs_app.vue';
-import JobsTable from '~/jobs/components/table/jobs_table.vue';
-import getPipelineJobsQuery from '~/pipelines/graphql/queries/get_pipeline_jobs.query.graphql';
-import { mockPipelineJobsQueryResponse } from '../../mock_data';
-
-Vue.use(VueApollo);
-
-jest.mock('~/alert');
-
-describe('Jobs app', () => {
- let wrapper;
- let resolverSpy;
-
- const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
- const findLoadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
- const findJobsTable = () => wrapper.findComponent(JobsTable);
-
- const triggerInfiniteScroll = () =>
- wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear');
-
- const createMockApolloProvider = (resolver) => {
- const requestHandlers = [[getPipelineJobsQuery, resolver]];
-
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = (resolver) => {
- wrapper = shallowMount(JobsApp, {
- provide: {
- projectPath: 'root/ci-project',
- pipelineIid: 1,
- },
- apolloProvider: createMockApolloProvider(resolver),
- });
- };
-
- beforeEach(() => {
- resolverSpy = jest.fn().mockResolvedValue(mockPipelineJobsQueryResponse);
- });
-
- describe('loading spinner', () => {
- const setup = async () => {
- createComponent(resolverSpy);
-
- await waitForPromises();
-
- triggerInfiniteScroll();
- };
-
- it('displays loading spinner when fetching more jobs', async () => {
- await setup();
-
- expect(findLoadingSpinner().exists()).toBe(true);
- expect(findSkeletonLoader().exists()).toBe(false);
- });
-
- it('hides loading spinner after jobs have been fetched', async () => {
- await setup();
- await waitForPromises();
-
- expect(findLoadingSpinner().exists()).toBe(false);
- expect(findSkeletonLoader().exists()).toBe(false);
- });
- });
-
- it('displays the skeleton loader', () => {
- createComponent(resolverSpy);
-
- expect(findSkeletonLoader().exists()).toBe(true);
- expect(findJobsTable().exists()).toBe(false);
- });
-
- it('displays the jobs table', async () => {
- createComponent(resolverSpy);
-
- await waitForPromises();
-
- expect(findJobsTable().exists()).toBe(true);
- expect(findSkeletonLoader().exists()).toBe(false);
- expect(createAlert).not.toHaveBeenCalled();
- });
-
- it('handles job fetch error correctly', async () => {
- resolverSpy = jest.fn().mockRejectedValue(new Error('GraphQL error'));
-
- createComponent(resolverSpy);
-
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: 'An error occurred while fetching the pipelines jobs.',
- });
- });
-
- it('handles infinite scrolling by calling fetchMore', async () => {
- createComponent(resolverSpy);
- await waitForPromises();
-
- triggerInfiniteScroll();
- await waitForPromises();
-
- expect(resolverSpy).toHaveBeenCalledWith({
- after: 'eyJpZCI6Ijg0NyJ9',
- fullPath: 'root/ci-project',
- iid: 1,
- });
- });
-
- it('does not display skeleton loader again after fetchMore', async () => {
- createComponent(resolverSpy);
-
- expect(findSkeletonLoader().exists()).toBe(true);
- await waitForPromises();
-
- triggerInfiniteScroll();
- await waitForPromises();
-
- expect(findSkeletonLoader().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/job_item_spec.js b/spec/frontend/pipelines/components/pipeline_mini_graph/job_item_spec.js
deleted file mode 100644
index b89f27e5c05..00000000000
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/job_item_spec.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import JobItem from '~/pipelines/components/pipeline_mini_graph/job_item.vue';
-
-describe('JobItem', () => {
- let wrapper;
-
- const defaultProps = {
- job: { id: '3' },
- };
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = shallowMount(JobItem, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- describe('when mounted', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders the received HTML', () => {
- expect(wrapper.html()).toContain(defaultProps.job.id);
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph_spec.js b/spec/frontend/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph_spec.js
deleted file mode 100644
index 6661bb079d2..00000000000
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph_spec.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { pipelines } from 'test_fixtures/pipelines/pipelines.json';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
-import PipelineStages from '~/pipelines/components/pipeline_mini_graph/pipeline_stages.vue';
-import mockLinkedPipelines from './linked_pipelines_mock_data';
-
-const mockStages = pipelines[0].details.stages;
-
-describe('Legacy Pipeline Mini Graph', () => {
- let wrapper;
-
- const findLegacyPipelineMiniGraph = () => wrapper.findComponent(LegacyPipelineMiniGraph);
- const findPipelineStages = () => wrapper.findComponent(PipelineStages);
-
- const findLinkedPipelineUpstream = () =>
- wrapper.findComponent('[data-testid="pipeline-mini-graph-upstream"]');
- const findLinkedPipelineDownstream = () =>
- wrapper.findComponent('[data-testid="pipeline-mini-graph-downstream"]');
- const findDownstreamArrowIcon = () => wrapper.find('[data-testid="downstream-arrow-icon"]');
- const findUpstreamArrowIcon = () => wrapper.find('[data-testid="upstream-arrow-icon"]');
-
- const createComponent = (props = {}) => {
- wrapper = mount(LegacyPipelineMiniGraph, {
- propsData: {
- stages: mockStages,
- ...props,
- },
- });
- };
-
- describe('rendered state without upstream or downstream pipelines', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('should render the pipeline stages', () => {
- expect(findPipelineStages().exists()).toBe(true);
- });
-
- it('should have the correct props', () => {
- expect(findLegacyPipelineMiniGraph().props()).toMatchObject({
- downstreamPipelines: [],
- isMergeTrain: false,
- pipelinePath: '',
- stages: expect.any(Array),
- updateDropdown: false,
- upstreamPipeline: undefined,
- });
- });
-
- it('should have no linked pipelines', () => {
- expect(findLinkedPipelineDownstream().exists()).toBe(false);
- expect(findLinkedPipelineUpstream().exists()).toBe(false);
- });
-
- it('should not render arrow icons', () => {
- expect(findUpstreamArrowIcon().exists()).toBe(false);
- expect(findDownstreamArrowIcon().exists()).toBe(false);
- });
- });
-
- describe('rendered state with upstream pipeline', () => {
- beforeEach(() => {
- createComponent({
- upstreamPipeline: mockLinkedPipelines.triggered_by,
- });
- });
-
- it('should have the correct props', () => {
- expect(findLegacyPipelineMiniGraph().props()).toMatchObject({
- downstreamPipelines: [],
- isMergeTrain: false,
- pipelinePath: '',
- stages: expect.any(Array),
- updateDropdown: false,
- upstreamPipeline: expect.any(Object),
- });
- });
-
- it('should render the upstream linked pipelines mini list only', () => {
- expect(findLinkedPipelineUpstream().exists()).toBe(true);
- expect(findLinkedPipelineDownstream().exists()).toBe(false);
- });
-
- it('should render an upstream arrow icon only', () => {
- expect(findDownstreamArrowIcon().exists()).toBe(false);
- expect(findUpstreamArrowIcon().exists()).toBe(true);
- expect(findUpstreamArrowIcon().props('name')).toBe('long-arrow');
- });
- });
-
- describe('rendered state with downstream pipelines', () => {
- beforeEach(() => {
- createComponent({
- downstreamPipelines: mockLinkedPipelines.triggered,
- pipelinePath: 'my/pipeline/path',
- });
- });
-
- it('should have the correct props', () => {
- expect(findLegacyPipelineMiniGraph().props()).toMatchObject({
- downstreamPipelines: expect.any(Array),
- isMergeTrain: false,
- pipelinePath: 'my/pipeline/path',
- stages: expect.any(Array),
- updateDropdown: false,
- upstreamPipeline: undefined,
- });
- });
-
- it('should render the downstream linked pipelines mini list only', () => {
- expect(findLinkedPipelineDownstream().exists()).toBe(true);
- expect(findLinkedPipelineUpstream().exists()).toBe(false);
- });
-
- it('should render a downstream arrow icon only', () => {
- expect(findUpstreamArrowIcon().exists()).toBe(false);
- expect(findDownstreamArrowIcon().exists()).toBe(true);
- expect(findDownstreamArrowIcon().props('name')).toBe('long-arrow');
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage_spec.js b/spec/frontend/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage_spec.js
deleted file mode 100644
index 3697eaeea1a..00000000000
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage_spec.js
+++ /dev/null
@@ -1,247 +0,0 @@
-import { GlDropdown } from '@gitlab/ui';
-import { nextTick } from 'vue';
-import { mount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import LegacyPipelineStage from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage.vue';
-import eventHub from '~/pipelines/event_hub';
-import waitForPromises from 'helpers/wait_for_promises';
-import { stageReply } from '../../mock_data';
-
-const dropdownPath = 'path.json';
-
-describe('Pipelines stage component', () => {
- let wrapper;
- let mock;
- let glTooltipDirectiveMock;
-
- const createComponent = (props = {}) => {
- glTooltipDirectiveMock = jest.fn();
- wrapper = mount(LegacyPipelineStage, {
- attachTo: document.body,
- directives: {
- GlTooltip: glTooltipDirectiveMock,
- },
- propsData: {
- stage: {
- status: {
- group: 'success',
- icon: 'status_success',
- title: 'success',
- },
- dropdown_path: dropdownPath,
- },
- updateDropdown: false,
- ...props,
- },
- });
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- jest.spyOn(eventHub, '$emit');
- });
-
- afterEach(() => {
- eventHub.$emit.mockRestore();
- mock.restore();
- // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
- wrapper.destroy();
- });
-
- const findCiActionBtn = () => wrapper.find('.js-ci-action');
- const findCiIcon = () => wrapper.findComponent(CiIcon);
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDropdownToggle = () => wrapper.find('button.dropdown-toggle');
- const findDropdownMenu = () =>
- wrapper.find('[data-testid="mini-pipeline-graph-dropdown-menu-list"]');
- const findDropdownMenuTitle = () =>
- wrapper.find('[data-testid="pipeline-stage-dropdown-menu-title"]');
- const findMergeTrainWarning = () => wrapper.find('[data-testid="warning-message-merge-trains"]');
- const findLoadingState = () => wrapper.find('[data-testid="pipeline-stage-loading-state"]');
-
- const openStageDropdown = async () => {
- await findDropdownToggle().trigger('click');
- await waitForPromises();
- await nextTick();
- };
-
- describe('loading state', () => {
- beforeEach(async () => {
- createComponent({ updateDropdown: true });
-
- mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
-
- await openStageDropdown();
- });
-
- it('displays loading state while jobs are being fetched', async () => {
- jest.runOnlyPendingTimers();
- await nextTick();
-
- expect(findLoadingState().exists()).toBe(true);
- expect(findLoadingState().text()).toBe(LegacyPipelineStage.i18n.loadingText);
- });
-
- it('does not display loading state after jobs have been fetched', async () => {
- await waitForPromises();
-
- expect(findLoadingState().exists()).toBe(false);
- });
- });
-
- describe('default appearance', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('sets up the tooltip to not have a show delay animation', () => {
- expect(glTooltipDirectiveMock.mock.calls[0][1].modifiers.ds0).toBe(true);
- });
-
- it('renders a dropdown with the status icon', () => {
- expect(findDropdown().exists()).toBe(true);
- expect(findDropdownToggle().exists()).toBe(true);
- expect(findCiIcon().exists()).toBe(true);
- });
-
- it('renders a borderless ci-icon', () => {
- expect(findCiIcon().exists()).toBe(true);
- expect(findCiIcon().props('isBorderless')).toBe(true);
- expect(findCiIcon().classes('borderless')).toBe(true);
- });
-
- it('renders a ci-icon with a custom border class', () => {
- expect(findCiIcon().exists()).toBe(true);
- expect(findCiIcon().classes('gl-border')).toBe(true);
- });
- });
-
- describe('when user opens dropdown and stage request is successful', () => {
- beforeEach(async () => {
- mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
- createComponent();
-
- await openStageDropdown();
- await jest.runAllTimers();
- await axios.waitForAll();
- });
-
- it('renders the received data and emits the correct events', () => {
- expect(findDropdownMenu().text()).toContain(stageReply.latest_statuses[0].name);
- expect(findDropdownMenuTitle().text()).toContain(stageReply.name);
- expect(eventHub.$emit).toHaveBeenCalledWith('clickedDropdown');
- expect(wrapper.emitted('miniGraphStageClick')).toEqual([[]]);
- });
-
- it('refreshes when updateDropdown is set to true', async () => {
- expect(mock.history.get).toHaveLength(1);
-
- wrapper.setProps({ updateDropdown: true });
- await axios.waitForAll();
-
- expect(mock.history.get).toHaveLength(2);
- });
- });
-
- describe('when user opens dropdown and stage request fails', () => {
- it('should close the dropdown', async () => {
- mock.onGet(dropdownPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
- createComponent();
-
- await openStageDropdown();
- await axios.waitForAll();
- await waitForPromises();
-
- expect(findDropdown().classes('show')).toBe(false);
- });
- });
-
- describe('update endpoint correctly', () => {
- beforeEach(async () => {
- const copyStage = { ...stageReply };
- copyStage.latest_statuses[0].name = 'this is the updated content';
- mock.onGet('bar.json').reply(HTTP_STATUS_OK, copyStage);
- createComponent({
- stage: {
- status: {
- group: 'running',
- icon: 'status_running',
- title: 'running',
- },
- dropdown_path: 'bar.json',
- },
- });
- await axios.waitForAll();
- });
-
- it('should update the stage to request the new endpoint provided', async () => {
- await openStageDropdown();
- jest.runOnlyPendingTimers();
- await waitForPromises();
-
- expect(findDropdownMenu().text()).toContain('this is the updated content');
- });
- });
-
- describe('job update in dropdown', () => {
- beforeEach(async () => {
- mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
- mock.onPost(`${stageReply.latest_statuses[0].status.action.path}.json`).reply(HTTP_STATUS_OK);
-
- createComponent();
- await waitForPromises();
- await nextTick();
- });
-
- const clickCiAction = async () => {
- await openStageDropdown();
- jest.runOnlyPendingTimers();
- await waitForPromises();
-
- await findCiActionBtn().trigger('click');
- };
-
- it('keeps dropdown open when job item action is clicked', async () => {
- await clickCiAction();
- await waitForPromises();
-
- expect(findDropdown().classes('show')).toBe(true);
- });
- });
-
- describe('With merge trains enabled', () => {
- it('shows a warning on the dropdown', async () => {
- mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
- createComponent({
- isMergeTrain: true,
- });
-
- await openStageDropdown();
- jest.runOnlyPendingTimers();
- await waitForPromises();
-
- const warning = findMergeTrainWarning();
-
- expect(warning.text()).toBe('Merge train pipeline jobs can not be retried');
- });
- });
-
- describe('With merge trains disabled', () => {
- beforeEach(async () => {
- mock.onGet(dropdownPath).reply(HTTP_STATUS_OK, stageReply);
- createComponent();
-
- await openStageDropdown();
- await axios.waitForAll();
- });
-
- it('does not show a warning on the dropdown', () => {
- const warning = findMergeTrainWarning();
-
- expect(warning.exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list_spec.js b/spec/frontend/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list_spec.js
deleted file mode 100644
index a4ecb9041c9..00000000000
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list_spec.js
+++ /dev/null
@@ -1,166 +0,0 @@
-import { mount } from '@vue/test-utils';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import LinkedPipelinesMiniList from '~/pipelines/components/pipeline_mini_graph/linked_pipelines_mini_list.vue';
-import mockData from './linked_pipelines_mock_data';
-
-describe('Linked pipeline mini list', () => {
- let wrapper;
-
- const findCiIcon = () => wrapper.findComponent(CiIcon);
- const findCiIcons = () => wrapper.findAllComponents(CiIcon);
- const findLinkedPipelineCounter = () => wrapper.find('[data-testid="linked-pipeline-counter"]');
- const findLinkedPipelineMiniItem = () =>
- wrapper.find('[data-testid="linked-pipeline-mini-item"]');
- const findLinkedPipelineMiniItems = () =>
- wrapper.findAll('[data-testid="linked-pipeline-mini-item"]');
- const findLinkedPipelineMiniList = () => wrapper.findComponent(LinkedPipelinesMiniList);
-
- const createComponent = (props = {}) => {
- wrapper = mount(LinkedPipelinesMiniList, {
- directives: {
- GlTooltip: createMockDirective('gl-tooltip'),
- },
- propsData: {
- ...props,
- },
- });
- };
-
- describe('when passed an upstream pipeline as prop', () => {
- beforeEach(() => {
- createComponent({
- triggeredBy: [mockData.triggered_by],
- });
- });
-
- it('should render one linked pipeline item', () => {
- expect(findLinkedPipelineMiniItem().exists()).toBe(true);
- });
-
- it('should render a linked pipeline with the correct href', () => {
- expect(findLinkedPipelineMiniItem().exists()).toBe(true);
-
- expect(findLinkedPipelineMiniItem().attributes('href')).toBe(
- '/gitlab-org/gitlab-foss/-/pipelines/129',
- );
- });
-
- it('should render one ci status icon', () => {
- expect(findCiIcon().exists()).toBe(true);
- });
-
- it('should render a borderless ci-icon', () => {
- expect(findCiIcon().exists()).toBe(true);
-
- expect(findCiIcon().props('isBorderless')).toBe(true);
- expect(findCiIcon().classes('borderless')).toBe(true);
- });
-
- it('should render a ci-icon with a custom border class', () => {
- expect(findCiIcon().exists()).toBe(true);
-
- expect(findCiIcon().classes('gl-border')).toBe(true);
- });
-
- it('should render the correct ci status icon', () => {
- expect(findCiIcon().classes('ci-status-icon-running')).toBe(true);
- });
-
- it('should have an activated tooltip', () => {
- expect(findLinkedPipelineMiniItem().exists()).toBe(true);
- const tooltip = getBinding(findLinkedPipelineMiniItem().element, 'gl-tooltip');
-
- expect(tooltip.value.title).toBe('GitLabCE - running');
- });
-
- it('should correctly set is-upstream', () => {
- expect(findLinkedPipelineMiniList().exists()).toBe(true);
-
- expect(findLinkedPipelineMiniList().classes('is-upstream')).toBe(true);
- });
-
- it('should correctly compute shouldRenderCounter', () => {
- expect(findLinkedPipelineMiniList().vm.shouldRenderCounter).toBe(false);
- });
-
- it('should not render the pipeline counter', () => {
- expect(findLinkedPipelineCounter().exists()).toBe(false);
- });
- });
-
- describe('when passed downstream pipelines as props', () => {
- beforeEach(() => {
- createComponent({
- triggered: mockData.triggered,
- pipelinePath: 'my/pipeline/path',
- });
- });
-
- it('should render three linked pipeline items', () => {
- expect(findLinkedPipelineMiniItems().exists()).toBe(true);
- expect(findLinkedPipelineMiniItems().length).toBe(3);
- });
-
- it('should render three ci status icons', () => {
- expect(findCiIcons().exists()).toBe(true);
- expect(findCiIcons().length).toBe(3);
- });
-
- it('should render the correct ci status icon', () => {
- expect(findCiIcon().classes('ci-status-icon-running')).toBe(true);
- });
-
- it('should have an activated tooltip', () => {
- expect(findLinkedPipelineMiniItem().exists()).toBe(true);
- const tooltip = getBinding(findLinkedPipelineMiniItem().element, 'gl-tooltip');
-
- expect(tooltip.value.title).toBe('GitLabCE - running');
- });
-
- it('should correctly set is-downstream', () => {
- expect(findLinkedPipelineMiniList().exists()).toBe(true);
-
- expect(findLinkedPipelineMiniList().classes('is-downstream')).toBe(true);
- });
-
- it('should render a borderless ci-icon', () => {
- expect(findCiIcon().exists()).toBe(true);
-
- expect(findCiIcon().props('isBorderless')).toBe(true);
- expect(findCiIcon().classes('borderless')).toBe(true);
- });
-
- it('should render a ci-icon with a custom border class', () => {
- expect(findCiIcon().exists()).toBe(true);
-
- expect(findCiIcon().classes('gl-border')).toBe(true);
- });
-
- it('should render the pipeline counter', () => {
- expect(findLinkedPipelineCounter().exists()).toBe(true);
- });
-
- it('should correctly compute shouldRenderCounter', () => {
- expect(findLinkedPipelineMiniList().vm.shouldRenderCounter).toBe(true);
- });
-
- it('should correctly trim linkedPipelines', () => {
- expect(findLinkedPipelineMiniList().props('triggered').length).toBe(6);
- expect(findLinkedPipelineMiniList().vm.linkedPipelinesTrimmed.length).toBe(3);
- });
-
- it('should set the correct pipeline path', () => {
- expect(findLinkedPipelineCounter().exists()).toBe(true);
-
- expect(findLinkedPipelineCounter().attributes('href')).toBe('my/pipeline/path');
- });
-
- it('should render the correct counterTooltipText', () => {
- expect(findLinkedPipelineCounter().exists()).toBe(true);
- const tooltip = getBinding(findLinkedPipelineCounter().element, 'gl-tooltip');
-
- expect(tooltip.value.title).toBe(findLinkedPipelineMiniList().vm.counterTooltipText);
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/mock_data.js b/spec/frontend/pipelines/components/pipeline_mini_graph/mock_data.js
deleted file mode 100644
index 1c13e9eb62b..00000000000
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/mock_data.js
+++ /dev/null
@@ -1,150 +0,0 @@
-export const mockDownstreamPipelinesGraphql = ({ includeSourceJobRetried = true } = {}) => ({
- nodes: [
- {
- id: 'gid://gitlab/Ci::Pipeline/612',
- path: '/root/job-log-sections/-/pipelines/612',
- project: {
- id: 'gid://gitlab/Project/21',
- name: 'job-log-sections',
- __typename: 'Project',
- },
- detailedStatus: {
- id: 'success-612-612',
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- __typename: 'DetailedStatus',
- },
- sourceJob: {
- id: 'gid://gitlab/Ci::Bridge/532',
- retried: includeSourceJobRetried ? false : null,
- },
- __typename: 'Pipeline',
- },
- {
- id: 'gid://gitlab/Ci::Pipeline/611',
- path: '/root/job-log-sections/-/pipelines/611',
- project: {
- id: 'gid://gitlab/Project/21',
- name: 'job-log-sections',
- __typename: 'Project',
- },
- detailedStatus: {
- id: 'success-611-611',
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- __typename: 'DetailedStatus',
- },
- sourceJob: {
- id: 'gid://gitlab/Ci::Bridge/531',
- retried: includeSourceJobRetried ? true : null,
- },
- __typename: 'Pipeline',
- },
- {
- id: 'gid://gitlab/Ci::Pipeline/609',
- path: '/root/job-log-sections/-/pipelines/609',
- project: {
- id: 'gid://gitlab/Project/21',
- name: 'job-log-sections',
- __typename: 'Project',
- },
- detailedStatus: {
- id: 'success-609-609',
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- __typename: 'DetailedStatus',
- },
- sourceJob: {
- id: 'gid://gitlab/Ci::Bridge/530',
- retried: includeSourceJobRetried ? true : null,
- },
- __typename: 'Pipeline',
- },
- ],
- __typename: 'PipelineConnection',
-});
-
-const upstream = {
- id: 'gid://gitlab/Ci::Pipeline/610',
- path: '/root/trigger-downstream/-/pipelines/610',
- project: {
- id: 'gid://gitlab/Project/21',
- name: 'trigger-downstream',
- __typename: 'Project',
- },
- detailedStatus: {
- id: 'success-610-610',
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- __typename: 'DetailedStatus',
- },
- __typename: 'Pipeline',
-};
-
-export const mockPipelineStagesQueryResponse = {
- data: {
- project: {
- id: 'gid://gitlab/Project/20',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/320',
- stages: {
- nodes: [
- {
- __typename: 'CiStage',
- id: 'gid://gitlab/Ci::Stage/409',
- name: 'build',
- detailedStatus: {
- __typename: 'DetailedStatus',
- id: 'success-409-409',
- icon: 'status_success',
- group: 'success',
- },
- },
- ],
- },
- },
- },
- },
-};
-
-export const mockPipelineStatusResponse = {
- data: {
- project: {
- id: 'gid://gitlab/Project/20',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/320',
- detailedStatus: {
- id: 'pending-320-320',
- detailsPath: '/root/ci-project/-/pipelines/320',
- icon: 'status_pending',
- group: 'pending',
- __typename: 'DetailedStatus',
- },
- __typename: 'Pipeline',
- },
- __typename: 'Project',
- },
- },
-};
-
-export const mockUpstreamDownstreamQueryResponse = {
- data: {
- project: {
- id: '1',
- pipeline: {
- id: 'pipeline-1',
- path: '/root/ci-project/-/pipelines/790',
- downstream: mockDownstreamPipelinesGraphql(),
- upstream,
- },
- __typename: 'Project',
- },
- },
-};
-
-export const linkedPipelinesFetchError = 'There was a problem fetching linked pipelines.';
-export const stagesFetchError = 'There was a problem fetching the pipeline stages.';
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_mini_graph_spec.js b/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_mini_graph_spec.js
deleted file mode 100644
index b3e157f75f6..00000000000
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_mini_graph_spec.js
+++ /dev/null
@@ -1,123 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { GlLoadingIcon } from '@gitlab/ui';
-
-import { createAlert } from '~/alert';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import createMockApollo from 'helpers/mock_apollo_helper';
-
-import getLinkedPipelinesQuery from '~/pipelines/graphql/queries/get_linked_pipelines.query.graphql';
-import getPipelineStagesQuery from '~/pipelines/graphql/queries/get_pipeline_stages.query.graphql';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
-import PipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/pipeline_mini_graph.vue';
-import * as sharedGraphQlUtils from '~/graphql_shared/utils';
-
-import {
- linkedPipelinesFetchError,
- stagesFetchError,
- mockPipelineStagesQueryResponse,
- mockUpstreamDownstreamQueryResponse,
-} from './mock_data';
-
-Vue.use(VueApollo);
-jest.mock('~/alert');
-
-describe('PipelineMiniGraph', () => {
- let wrapper;
- let linkedPipelinesResponse;
- let pipelineStagesResponse;
-
- const fullPath = 'gitlab-org/gitlab';
- const iid = '315';
- const pipelineEtag = '/api/graphql:pipelines/id/315';
-
- const createComponent = ({
- pipelineStagesHandler = pipelineStagesResponse,
- linkedPipelinesHandler = linkedPipelinesResponse,
- } = {}) => {
- const handlers = [
- [getLinkedPipelinesQuery, linkedPipelinesHandler],
- [getPipelineStagesQuery, pipelineStagesHandler],
- ];
- const mockApollo = createMockApollo(handlers);
-
- wrapper = shallowMountExtended(PipelineMiniGraph, {
- propsData: {
- fullPath,
- iid,
- pipelineEtag,
- },
- apolloProvider: mockApollo,
- });
-
- return waitForPromises();
- };
-
- const findLegacyPipelineMiniGraph = () => wrapper.findComponent(LegacyPipelineMiniGraph);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
-
- beforeEach(() => {
- linkedPipelinesResponse = jest.fn().mockResolvedValue(mockUpstreamDownstreamQueryResponse);
- pipelineStagesResponse = jest.fn().mockResolvedValue(mockPipelineStagesQueryResponse);
- });
-
- describe('when initial queries are loading', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('shows a loading icon and no mini graph', () => {
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findLegacyPipelineMiniGraph().exists()).toBe(false);
- });
- });
-
- describe('when queries have loaded', () => {
- it('does not show a loading icon', async () => {
- await createComponent();
-
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('renders the Pipeline Mini Graph', async () => {
- await createComponent();
-
- expect(findLegacyPipelineMiniGraph().exists()).toBe(true);
- });
-
- it('fires the queries', async () => {
- await createComponent();
-
- expect(linkedPipelinesResponse).toHaveBeenCalledWith({ iid, fullPath });
- expect(pipelineStagesResponse).toHaveBeenCalledWith({ iid, fullPath });
- });
- });
-
- describe('polling', () => {
- it('toggles query polling with visibility check', async () => {
- jest.spyOn(sharedGraphQlUtils, 'toggleQueryPollingByVisibility');
-
- createComponent();
-
- await waitForPromises();
-
- expect(sharedGraphQlUtils.toggleQueryPollingByVisibility).toHaveBeenCalledTimes(2);
- });
- });
-
- describe('when pipeline queries are unsuccessful', () => {
- const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
- it.each`
- query | handlerName | errorMessage
- ${'pipeline stages'} | ${'pipelineStagesHandler'} | ${stagesFetchError}
- ${'linked pipelines'} | ${'linkedPipelinesHandler'} | ${linkedPipelinesFetchError}
- `('throws an error for the $query query', async ({ errorMessage, handlerName }) => {
- await createComponent({ [handlerName]: failedHandler });
-
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({ message: errorMessage });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stage_spec.js b/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stage_spec.js
deleted file mode 100644
index 1989aad12b0..00000000000
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stage_spec.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import createMockApollo from 'helpers/mock_apollo_helper';
-
-import getPipelineStageQuery from '~/pipelines/graphql/queries/get_pipeline_stage.query.graphql';
-import PipelineStage from '~/pipelines/components/pipeline_mini_graph/pipeline_stage.vue';
-
-Vue.use(VueApollo);
-
-describe('PipelineStage', () => {
- let wrapper;
- let pipelineStageResponse;
-
- const defaultProps = {
- pipelineEtag: '/etag',
- stageId: '1',
- };
-
- const createComponent = ({ pipelineStageHandler = pipelineStageResponse } = {}) => {
- const handlers = [[getPipelineStageQuery, pipelineStageHandler]];
- const mockApollo = createMockApollo(handlers);
-
- wrapper = shallowMountExtended(PipelineStage, {
- propsData: {
- ...defaultProps,
- },
- apolloProvider: mockApollo,
- });
-
- return waitForPromises();
- };
-
- const findPipelineStage = () => wrapper.findComponent(PipelineStage);
-
- describe('when mounted', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders job item', () => {
- expect(findPipelineStage().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stages_spec.js b/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stages_spec.js
deleted file mode 100644
index c212087b7e3..00000000000
--- a/spec/frontend/pipelines/components/pipeline_mini_graph/pipeline_stages_spec.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { pipelines } from 'test_fixtures/pipelines/pipelines.json';
-import LegacyPipelineStage from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_stage.vue';
-import PipelineStages from '~/pipelines/components/pipeline_mini_graph/pipeline_stages.vue';
-
-const mockStages = pipelines[0].details.stages;
-
-describe('Pipeline Stages', () => {
- let wrapper;
-
- const findLegacyPipelineStages = () => wrapper.findAllComponents(LegacyPipelineStage);
- const findPipelineStagesAt = (i) => findLegacyPipelineStages().at(i);
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(PipelineStages, {
- propsData: {
- stages: mockStages,
- ...props,
- },
- });
- };
-
- it('renders stages', () => {
- createComponent();
-
- expect(findLegacyPipelineStages()).toHaveLength(mockStages.length);
- });
-
- it('does not fail when stages are empty', () => {
- createComponent({ stages: [] });
-
- expect(wrapper.exists()).toBe(true);
- expect(findLegacyPipelineStages()).toHaveLength(0);
- });
-
- it('update dropdown is false by default', () => {
- createComponent();
-
- expect(findPipelineStagesAt(0).props('updateDropdown')).toBe(false);
- expect(findPipelineStagesAt(1).props('updateDropdown')).toBe(false);
- });
-
- it('update dropdown is set to true', () => {
- createComponent({ updateDropdown: true });
-
- expect(findPipelineStagesAt(0).props('updateDropdown')).toBe(true);
- expect(findPipelineStagesAt(1).props('updateDropdown')).toBe(true);
- });
-
- it('is merge train is false by default', () => {
- createComponent();
-
- expect(findPipelineStagesAt(0).props('isMergeTrain')).toBe(false);
- expect(findPipelineStagesAt(1).props('isMergeTrain')).toBe(false);
- });
-
- it('is merge train is set to true', () => {
- createComponent({ isMergeTrain: true });
-
- expect(findPipelineStagesAt(0).props('isMergeTrain')).toBe(true);
- expect(findPipelineStagesAt(1).props('isMergeTrain')).toBe(true);
- });
-});
diff --git a/spec/frontend/pipelines/components/pipeline_tabs_spec.js b/spec/frontend/pipelines/components/pipeline_tabs_spec.js
deleted file mode 100644
index 0951e1ffb46..00000000000
--- a/spec/frontend/pipelines/components/pipeline_tabs_spec.js
+++ /dev/null
@@ -1,114 +0,0 @@
-import { GlTab } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import PipelineTabs from '~/pipelines/components/pipeline_tabs.vue';
-import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-
-describe('The Pipeline Tabs', () => {
- let wrapper;
- let trackingSpy;
-
- const $router = { push: jest.fn() };
-
- const findDagTab = () => wrapper.findByTestId('dag-tab');
- const findFailedJobsTab = () => wrapper.findByTestId('failed-jobs-tab');
- const findJobsTab = () => wrapper.findByTestId('jobs-tab');
- const findPipelineTab = () => wrapper.findByTestId('pipeline-tab');
- const findTestsTab = () => wrapper.findByTestId('tests-tab');
-
- const findFailedJobsBadge = () => wrapper.findByTestId('failed-builds-counter');
- const findJobsBadge = () => wrapper.findByTestId('builds-counter');
- const findTestsBadge = () => wrapper.findByTestId('tests-counter');
-
- const defaultProvide = {
- defaultTabValue: '',
- failedJobsCount: 1,
- totalJobCount: 10,
- testsCount: 123,
- };
-
- const createComponent = (provide = {}) => {
- wrapper = shallowMountExtended(PipelineTabs, {
- provide: {
- ...defaultProvide,
- ...provide,
- },
- stubs: {
- GlTab,
- RouterView: true,
- },
- mocks: {
- $router,
- },
- });
- };
-
- describe('Tabs', () => {
- it.each`
- tabName | tabComponent
- ${'Pipeline'} | ${findPipelineTab}
- ${'Dag'} | ${findDagTab}
- ${'Jobs'} | ${findJobsTab}
- ${'Failed Jobs'} | ${findFailedJobsTab}
- ${'Tests'} | ${findTestsTab}
- `('shows $tabName tab', ({ tabComponent }) => {
- createComponent();
-
- expect(tabComponent().exists()).toBe(true);
- });
-
- describe('with no failed jobs', () => {
- beforeEach(() => {
- createComponent({ failedJobsCount: 0 });
- });
-
- it('hides the failed jobs tab', () => {
- expect(findFailedJobsTab().exists()).toBe(false);
- });
- });
- });
-
- describe('Tabs badges', () => {
- it.each`
- tabName | badgeComponent | badgeText
- ${'Jobs'} | ${findJobsBadge} | ${String(defaultProvide.totalJobCount)}
- ${'Failed Jobs'} | ${findFailedJobsBadge} | ${String(defaultProvide.failedJobsCount)}
- ${'Tests'} | ${findTestsBadge} | ${String(defaultProvide.testsCount)}
- `('shows badge for $tabName with the correct text', ({ badgeComponent, badgeText }) => {
- createComponent();
-
- expect(badgeComponent().exists()).toBe(true);
- expect(badgeComponent().text()).toBe(badgeText);
- });
- });
-
- describe('Tab tracking', () => {
- beforeEach(() => {
- createComponent();
-
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks failed jobs tab click', () => {
- findFailedJobsTab().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledTimes(1);
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', {
- label: TRACKING_CATEGORIES.failed,
- });
- });
-
- it('tracks tests tab click', () => {
- findTestsTab().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledTimes(1);
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', {
- label: TRACKING_CATEGORIES.tests,
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
deleted file mode 100644
index 51a4487a3ef..00000000000
--- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js
+++ /dev/null
@@ -1,199 +0,0 @@
-import { GlFilteredSearch } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import Api from '~/api';
-import axios from '~/lib/utils/axios_utils';
-import PipelinesFilteredSearch from '~/pipelines/components/pipelines_list/pipelines_filtered_search.vue';
-import {
- FILTERED_SEARCH_TERM,
- OPERATORS_IS,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-import { users, mockSearch, branches, tags } from '../mock_data';
-
-describe('Pipelines filtered search', () => {
- let wrapper;
- let mock;
-
- const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
- const getSearchToken = (type) =>
- findFilteredSearch()
- .props('availableTokens')
- .find((token) => token.type === type);
- const findBranchToken = () => getSearchToken('ref');
- const findTagToken = () => getSearchToken('tag');
- const findUserToken = () => getSearchToken('username');
- const findStatusToken = () => getSearchToken('status');
- const findSourceToken = () => getSearchToken('source');
-
- const createComponent = (params = {}) => {
- wrapper = mount(PipelinesFilteredSearch, {
- propsData: {
- projectId: '21',
- defaultBranchName: 'main',
- params,
- },
- attachTo: document.body,
- });
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
- jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
- jest.spyOn(Api, 'tags').mockResolvedValue({ data: tags });
-
- createComponent();
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('displays UI elements', () => {
- expect(findFilteredSearch().exists()).toBe(true);
- });
-
- it('displays search tokens', () => {
- expect(findUserToken()).toMatchObject({
- type: 'username',
- icon: 'user',
- title: 'Trigger author',
- unique: true,
- projectId: '21',
- operators: OPERATORS_IS,
- });
-
- expect(findBranchToken()).toMatchObject({
- type: 'ref',
- icon: 'branch',
- title: 'Branch name',
- unique: true,
- projectId: '21',
- defaultBranchName: 'main',
- operators: OPERATORS_IS,
- });
-
- expect(findSourceToken()).toMatchObject({
- type: 'source',
- icon: 'trigger-source',
- title: 'Source',
- unique: true,
- operators: OPERATORS_IS,
- });
-
- expect(findStatusToken()).toMatchObject({
- type: 'status',
- icon: 'status',
- title: 'Status',
- unique: true,
- operators: OPERATORS_IS,
- });
-
- expect(findTagToken()).toMatchObject({
- type: 'tag',
- icon: 'tag',
- title: 'Tag name',
- unique: true,
- operators: OPERATORS_IS,
- });
- });
-
- it('emits filterPipelines on submit with correct filter', () => {
- findFilteredSearch().vm.$emit('submit', mockSearch);
-
- expect(wrapper.emitted('filterPipelines')).toHaveLength(1);
- expect(wrapper.emitted('filterPipelines')[0]).toEqual([mockSearch]);
- });
-
- it('disables tag name token when branch name token is active', async () => {
- findFilteredSearch().vm.$emit('input', [
- { type: 'ref', value: { data: 'branch-1', operator: '=' } },
- { type: FILTERED_SEARCH_TERM, value: { data: '' } },
- ]);
-
- await nextTick();
- expect(findBranchToken().disabled).toBe(false);
- expect(findTagToken().disabled).toBe(true);
- });
-
- it('disables branch name token when tag name token is active', async () => {
- findFilteredSearch().vm.$emit('input', [
- { type: 'tag', value: { data: 'tag-1', operator: '=' } },
- { type: FILTERED_SEARCH_TERM, value: { data: '' } },
- ]);
-
- await nextTick();
- expect(findBranchToken().disabled).toBe(true);
- expect(findTagToken().disabled).toBe(false);
- });
-
- it('resets tokens disabled state on clear', async () => {
- findFilteredSearch().vm.$emit('clearInput');
-
- await nextTick();
- expect(findBranchToken().disabled).toBe(false);
- expect(findTagToken().disabled).toBe(false);
- });
-
- it('resets tokens disabled state when clearing tokens by backspace', async () => {
- findFilteredSearch().vm.$emit('input', [{ type: FILTERED_SEARCH_TERM, value: { data: '' } }]);
-
- await nextTick();
- expect(findBranchToken().disabled).toBe(false);
- expect(findTagToken().disabled).toBe(false);
- });
-
- describe('Url query params', () => {
- const params = {
- username: 'deja.green',
- ref: 'main',
- };
-
- beforeEach(() => {
- createComponent(params);
- });
-
- it('sets default value if url query params', () => {
- const expectedValueProp = [
- {
- type: 'username',
- value: {
- data: params.username,
- operator: '=',
- },
- },
- {
- type: 'ref',
- value: {
- data: params.ref,
- operator: '=',
- },
- },
- { type: FILTERED_SEARCH_TERM, value: { data: '' } },
- ];
-
- expect(findFilteredSearch().props('value')).toMatchObject(expectedValueProp);
- expect(findFilteredSearch().props('value')).toHaveLength(expectedValueProp.length);
- });
- });
-
- describe('tracking', () => {
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks filtered search click', () => {
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
-
- findFilteredSearch().vm.$emit('submit', mockSearch);
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_filtered_search', {
- label: TRACKING_CATEGORIES.search,
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js b/spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js
deleted file mode 100644
index b560eea4882..00000000000
--- a/spec/frontend/pipelines/components/pipelines_list/empty_state/ci_templates_spec.js
+++ /dev/null
@@ -1,107 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import CiTemplates from '~/pipelines/components/pipelines_list/empty_state/ci_templates.vue';
-
-const pipelineEditorPath = '/-/ci/editor';
-const suggestedCiTemplates = [
- { name: 'Android', logo: '/assets/illustrations/logos/android.svg' },
- { name: 'Bash', logo: '/assets/illustrations/logos/bash.svg' },
- { name: 'C++', logo: '/assets/illustrations/logos/c_plus_plus.svg' },
-];
-
-describe('CI Templates', () => {
- let wrapper;
- let trackingSpy;
-
- const createWrapper = (propsData = {}) => {
- wrapper = shallowMountExtended(CiTemplates, {
- provide: {
- pipelineEditorPath,
- suggestedCiTemplates,
- },
- propsData,
- });
- };
-
- const findTemplateDescription = () => wrapper.findByTestId('template-description');
- const findTemplateLink = () => wrapper.findByTestId('template-link');
- const findTemplateNames = () => wrapper.findAllByTestId('template-name');
- const findTemplateName = () => wrapper.findByTestId('template-name');
- const findTemplateLogo = () => wrapper.findByTestId('template-logo');
-
- describe('renders template list', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders all suggested templates', () => {
- expect(findTemplateNames().length).toBe(3);
- expect(wrapper.text()).toContain('Android', 'Bash', 'C++');
- });
-
- it('has the correct template name', () => {
- expect(findTemplateName().text()).toBe('Android');
- });
-
- it('links to the correct template', () => {
- expect(findTemplateLink().attributes('href')).toBe(
- pipelineEditorPath.concat('?template=Android'),
- );
- });
-
- it('has the link button enabled', () => {
- expect(findTemplateLink().props('disabled')).toBe(false);
- });
-
- it('has the description of the template', () => {
- expect(findTemplateDescription().text()).toBe(
- 'Continuous integration and deployment template to test and deploy your Android project.',
- );
- });
-
- it('has the right logo of the template', () => {
- expect(findTemplateLogo().attributes('src')).toBe('/assets/illustrations/logos/android.svg');
- });
- });
-
- describe('filtering the templates', () => {
- beforeEach(() => {
- createWrapper({ filterTemplates: ['Bash'] });
- });
-
- it('renders only the filtered templates', () => {
- expect(findTemplateNames()).toHaveLength(1);
- expect(findTemplateName().text()).toBe('Bash');
- });
- });
-
- describe('disabling the templates', () => {
- beforeEach(() => {
- createWrapper({ disabled: true });
- });
-
- it('has the link button disabled', () => {
- expect(findTemplateLink().props('disabled')).toBe(true);
- });
- });
-
- describe('tracking', () => {
- beforeEach(() => {
- createWrapper();
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- it('sends an event when template is clicked', () => {
- findTemplateLink().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledTimes(1);
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'template_clicked', {
- label: 'Android',
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js b/spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js
deleted file mode 100644
index 700be076e0c..00000000000
--- a/spec/frontend/pipelines/components/pipelines_list/empty_state/ios_templates_spec.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import '~/commons';
-import { nextTick } from 'vue';
-import { GlPopover, GlButton } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
-import IosTemplates from '~/pipelines/components/pipelines_list/empty_state/ios_templates.vue';
-import CiTemplates from '~/pipelines/components/pipelines_list/empty_state/ci_templates.vue';
-
-const pipelineEditorPath = '/-/ci/editor';
-const registrationToken = 'SECRET_TOKEN';
-const iOSTemplateName = 'iOS-Fastlane';
-
-describe('iOS Templates', () => {
- let wrapper;
-
- const createWrapper = (providedPropsData = {}) => {
- return shallowMountExtended(IosTemplates, {
- provide: {
- pipelineEditorPath,
- iosRunnersAvailable: true,
- ...providedPropsData,
- },
- propsData: {
- registrationToken,
- },
- stubs: {
- GlButton,
- },
- });
- };
-
- const findIosTemplate = () => wrapper.findComponent(CiTemplates);
- const findRunnerInstructionsModal = () => wrapper.findComponent(RunnerInstructionsModal);
- const findRunnerInstructionsPopover = () => wrapper.findComponent(GlPopover);
- const findRunnerSetupTodoEmoji = () => wrapper.findByTestId('runner-setup-marked-todo');
- const findRunnerSetupCompletedEmoji = () => wrapper.findByTestId('runner-setup-marked-completed');
- const findSetupRunnerLink = () => wrapper.findByText('Set up a runner');
- const configurePipelineLink = () => wrapper.findByTestId('configure-pipeline-link');
-
- describe('when ios runners are not available', () => {
- beforeEach(() => {
- wrapper = createWrapper({ iosRunnersAvailable: false });
- });
-
- describe('the runner setup section', () => {
- it('marks the section as todo', () => {
- expect(findRunnerSetupTodoEmoji().isVisible()).toBe(true);
- expect(findRunnerSetupCompletedEmoji().isVisible()).toBe(false);
- });
-
- it('renders the setup runner link', () => {
- expect(findSetupRunnerLink().exists()).toBe(true);
- });
-
- it('renders the runner instructions modal with a popover once clicked', async () => {
- findSetupRunnerLink().element.parentElement.click();
-
- await nextTick();
-
- expect(findRunnerInstructionsModal().exists()).toBe(true);
- expect(findRunnerInstructionsModal().props('registrationToken')).toBe(registrationToken);
- expect(findRunnerInstructionsModal().props('defaultPlatformName')).toBe('osx');
-
- findRunnerInstructionsModal().vm.$emit('shown');
-
- await nextTick();
-
- expect(findRunnerInstructionsPopover().exists()).toBe(true);
- });
- });
-
- describe('the configure pipeline section', () => {
- it('has a disabled link button', () => {
- expect(configurePipelineLink().props('disabled')).toBe(true);
- });
- });
-
- describe('the ios-Fastlane template', () => {
- it('renders the template', () => {
- expect(findIosTemplate().props('filterTemplates')).toStrictEqual([iOSTemplateName]);
- });
-
- it('has a disabled link button', () => {
- expect(findIosTemplate().props('disabled')).toBe(true);
- });
- });
- });
-
- describe('when ios runners are available', () => {
- beforeEach(() => {
- wrapper = createWrapper();
- });
-
- describe('the runner setup section', () => {
- it('marks the section as completed', () => {
- expect(findRunnerSetupTodoEmoji().isVisible()).toBe(false);
- expect(findRunnerSetupCompletedEmoji().isVisible()).toBe(true);
- });
-
- it('does not render the setup runner link', () => {
- expect(findSetupRunnerLink().exists()).toBe(false);
- });
- });
-
- describe('the configure pipeline section', () => {
- it('has an enabled link button', () => {
- expect(configurePipelineLink().props('disabled')).toBe(false);
- });
-
- it('links to the pipeline editor with the right template', () => {
- expect(configurePipelineLink().attributes('href')).toBe(
- `${pipelineEditorPath}?template=${iOSTemplateName}`,
- );
- });
- });
-
- describe('the ios-Fastlane template', () => {
- it('renders the template', () => {
- expect(findIosTemplate().props('filterTemplates')).toStrictEqual([iOSTemplateName]);
- });
-
- it('has an enabled link button', () => {
- expect(findIosTemplate().props('disabled')).toBe(false);
- });
-
- it('links to the pipeline editor with the right template', () => {
- expect(configurePipelineLink().attributes('href')).toBe(
- `${pipelineEditorPath}?template=${iOSTemplateName}`,
- );
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js b/spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js
deleted file mode 100644
index 4bf4257f462..00000000000
--- a/spec/frontend/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates_spec.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import '~/commons';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import PipelinesCiTemplates from '~/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue';
-import CiTemplates from '~/pipelines/components/pipelines_list/empty_state/ci_templates.vue';
-
-const pipelineEditorPath = '/-/ci/editor';
-
-describe('Pipelines CI Templates', () => {
- let wrapper;
- let trackingSpy;
-
- const createWrapper = (propsData = {}, stubs = {}) => {
- return shallowMountExtended(PipelinesCiTemplates, {
- provide: {
- pipelineEditorPath,
- ...propsData,
- },
- stubs,
- });
- };
-
- const findTestTemplateLink = () => wrapper.findByTestId('test-template-link');
- const findCiTemplates = () => wrapper.findComponent(CiTemplates);
-
- describe('templates', () => {
- beforeEach(() => {
- wrapper = createWrapper();
- });
-
- it('renders test template and Ci templates', () => {
- expect(findTestTemplateLink().attributes('href')).toBe(
- pipelineEditorPath.concat('?template=Getting-Started'),
- );
- expect(findCiTemplates().exists()).toBe(true);
- });
- });
-
- describe('tracking', () => {
- beforeEach(() => {
- wrapper = createWrapper();
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- it('sends an event when Getting-Started template is clicked', () => {
- findTestTemplateLink().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledTimes(1);
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'template_clicked', {
- label: 'Getting-Started',
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/failed_job_details_spec.js b/spec/frontend/pipelines/components/pipelines_list/failure_widget/failed_job_details_spec.js
deleted file mode 100644
index 479ee854ecf..00000000000
--- a/spec/frontend/pipelines/components/pipelines_list/failure_widget/failed_job_details_spec.js
+++ /dev/null
@@ -1,254 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { GlIcon, GlLink } from '@gitlab/ui';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import FailedJobDetails from '~/pipelines/components/pipelines_list/failure_widget/failed_job_details.vue';
-import RetryMrFailedJobMutation from '~/pipelines/graphql/mutations/retry_mr_failed_job.mutation.graphql';
-import { BRIDGE_KIND } from '~/pipelines/components/graph/constants';
-import { job } from './mock';
-
-Vue.use(VueApollo);
-jest.mock('~/alert');
-
-const createFakeEvent = () => ({ stopPropagation: jest.fn() });
-
-describe('FailedJobDetails component', () => {
- let wrapper;
- let mockRetryResponse;
-
- const retrySuccessResponse = {
- data: {
- jobRetry: {
- errors: [],
- },
- },
- };
-
- const defaultProps = {
- job,
- };
-
- const createComponent = ({ props = {} } = {}) => {
- const handlers = [[RetryMrFailedJobMutation, mockRetryResponse]];
-
- wrapper = shallowMountExtended(FailedJobDetails, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- apolloProvider: createMockApollo(handlers),
- });
- };
-
- const findArrowIcon = () => wrapper.findComponent(GlIcon);
- const findJobId = () => wrapper.findComponent(GlLink);
- const findJobLog = () => wrapper.findByTestId('job-log');
- const findJobName = () => wrapper.findByText(defaultProps.job.name);
- const findRetryButton = () => wrapper.findByLabelText('Retry');
- const findRow = () => wrapper.findByTestId('widget-row');
- const findStageName = () => wrapper.findByText(defaultProps.job.stage.name);
-
- beforeEach(() => {
- mockRetryResponse = jest.fn();
- mockRetryResponse.mockResolvedValue(retrySuccessResponse);
- });
-
- describe('ui', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders the job name', () => {
- expect(findJobName().exists()).toBe(true);
- });
-
- it('renders the stage name', () => {
- expect(findStageName().exists()).toBe(true);
- });
-
- it('renders the job id as a link', () => {
- const jobId = getIdFromGraphQLId(defaultProps.job.id);
-
- expect(findJobId().exists()).toBe(true);
- expect(findJobId().text()).toContain(String(jobId));
- });
-
- it('does not renders the job lob', () => {
- expect(findJobLog().exists()).toBe(false);
- });
- });
-
- describe('Retry action', () => {
- describe('when the job is not retryable', () => {
- beforeEach(() => {
- createComponent({ props: { job: { ...job, retryable: false } } });
- });
-
- it('disables the retry button', () => {
- expect(findRetryButton().props().disabled).toBe(true);
- });
- });
-
- describe('when the job is a bridge', () => {
- beforeEach(() => {
- createComponent({ props: { job: { ...job, kind: BRIDGE_KIND } } });
- });
-
- it('disables the retry button', () => {
- expect(findRetryButton().props().disabled).toBe(true);
- });
- });
-
- describe('when the job is retryable', () => {
- describe('and user has permission to update the build', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('enables the retry button', () => {
- expect(findRetryButton().props().disabled).toBe(false);
- });
-
- describe('when clicking on the retry button', () => {
- it('passes the loading state to the button', async () => {
- await findRetryButton().vm.$emit('click', createFakeEvent());
-
- expect(findRetryButton().props().loading).toBe(true);
- });
-
- describe('and it succeeds', () => {
- beforeEach(async () => {
- findRetryButton().vm.$emit('click', createFakeEvent());
- await waitForPromises();
- });
-
- it('is no longer loading', () => {
- expect(findRetryButton().props().loading).toBe(false);
- });
-
- it('calls the retry mutation', () => {
- expect(mockRetryResponse).toHaveBeenCalled();
- expect(mockRetryResponse).toHaveBeenCalledWith({
- id: job.id,
- });
- });
-
- it('emits the `retried-job` event', () => {
- expect(wrapper.emitted('job-retried')).toStrictEqual([[job.name]]);
- });
- });
-
- describe('and it fails', () => {
- const customErrorMsg = 'Custom error message from API';
-
- beforeEach(async () => {
- mockRetryResponse.mockResolvedValue({
- data: { jobRetry: { errors: [customErrorMsg] } },
- });
- findRetryButton().vm.$emit('click', createFakeEvent());
-
- await waitForPromises();
- });
-
- it('shows an error message', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: customErrorMsg });
- });
-
- it('does not emits the `refetch-jobs` event', () => {
- expect(wrapper.emitted('refetch-jobs')).toBeUndefined();
- });
- });
- });
- });
-
- describe('and user does not have permission to update the build', () => {
- beforeEach(() => {
- createComponent({
- props: { job: { ...job, retryable: true, userPermissions: { updateBuild: false } } },
- });
- });
-
- it('disables the retry button', () => {
- expect(findRetryButton().props().disabled).toBe(true);
- });
- });
- });
- });
-
- describe('Job log', () => {
- describe('without permissions', () => {
- beforeEach(async () => {
- createComponent({ props: { job: { ...job, userPermissions: { readBuild: false } } } });
- await findRow().trigger('click');
- });
-
- it('does not renders the received html of the job log', () => {
- expect(findJobLog().html()).not.toContain(defaultProps.job.trace.htmlSummary);
- });
-
- it('shows a permission error message', () => {
- expect(findJobLog().text()).toBe("You do not have permission to read this job's log.");
- });
- });
-
- describe('with permissions', () => {
- beforeEach(() => {
- createComponent();
- });
-
- describe('when clicking on the row', () => {
- beforeEach(async () => {
- await findRow().trigger('click');
- });
-
- describe('while collapsed', () => {
- it('expands the job log', () => {
- expect(findJobLog().exists()).toBe(true);
- });
-
- it('renders the down arrow', () => {
- expect(findArrowIcon().props().name).toBe('chevron-down');
- });
-
- it('renders the received html of the job log', () => {
- expect(findJobLog().html()).toContain(defaultProps.job.trace.htmlSummary);
- });
- });
-
- describe('while expanded', () => {
- it('collapes the job log', async () => {
- expect(findJobLog().exists()).toBe(true);
-
- await findRow().trigger('click');
-
- expect(findJobLog().exists()).toBe(false);
- });
-
- it('renders the right arrow', async () => {
- expect(findArrowIcon().props().name).toBe('chevron-down');
-
- await findRow().trigger('click');
-
- expect(findArrowIcon().props().name).toBe('chevron-right');
- });
- });
- });
-
- describe('when clicking on a link element within the row', () => {
- it('does not expands/collapse the job log', async () => {
- expect(findJobLog().exists()).toBe(false);
- expect(findArrowIcon().props().name).toBe('chevron-right');
-
- await findJobId().vm.$emit('click');
-
- expect(findJobLog().exists()).toBe(false);
- expect(findArrowIcon().props().name).toBe('chevron-right');
- });
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/failed_jobs_list_spec.js b/spec/frontend/pipelines/components/pipelines_list/failure_widget/failed_jobs_list_spec.js
deleted file mode 100644
index 967812cc627..00000000000
--- a/spec/frontend/pipelines/components/pipelines_list/failure_widget/failed_jobs_list_spec.js
+++ /dev/null
@@ -1,279 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-
-import { GlLoadingIcon, GlToast } from '@gitlab/ui';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import FailedJobsList from '~/pipelines/components/pipelines_list/failure_widget/failed_jobs_list.vue';
-import FailedJobDetails from '~/pipelines/components/pipelines_list/failure_widget/failed_job_details.vue';
-import * as utils from '~/pipelines/components/pipelines_list/failure_widget/utils';
-import getPipelineFailedJobs from '~/pipelines/graphql/queries/get_pipeline_failed_jobs.query.graphql';
-import { failedJobsMock, failedJobsMock2, failedJobsMockEmpty, activeFailedJobsMock } from './mock';
-
-Vue.use(VueApollo);
-Vue.use(GlToast);
-
-jest.mock('~/alert');
-
-describe('FailedJobsList component', () => {
- let wrapper;
- let mockFailedJobsResponse;
- const showToast = jest.fn();
-
- const defaultProps = {
- failedJobsCount: 0,
- graphqlResourceEtag: 'api/graphql',
- isPipelineActive: false,
- pipelineIid: 1,
- projectPath: 'namespace/project/',
- };
-
- const defaultProvide = {
- graphqlPath: 'api/graphql',
- };
-
- const createComponent = ({ props = {}, provide } = {}) => {
- const handlers = [[getPipelineFailedJobs, mockFailedJobsResponse]];
- const mockApollo = createMockApollo(handlers);
-
- wrapper = shallowMountExtended(FailedJobsList, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- provide: {
- ...defaultProvide,
- ...provide,
- },
- apolloProvider: mockApollo,
- mocks: {
- $toast: {
- show: showToast,
- },
- },
- });
- };
-
- const findAllHeaders = () => wrapper.findAllByTestId('header');
- const findFailedJobRows = () => wrapper.findAllComponents(FailedJobDetails);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findNoFailedJobsText = () => wrapper.findByText('No failed jobs in this pipeline 🎉');
-
- beforeEach(() => {
- mockFailedJobsResponse = jest.fn();
- });
-
- describe('on mount', () => {
- beforeEach(() => {
- mockFailedJobsResponse.mockResolvedValue(failedJobsMock);
- createComponent();
- });
-
- it('fires the graphql query', () => {
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
- expect(mockFailedJobsResponse).toHaveBeenCalledWith({
- fullPath: defaultProps.projectPath,
- pipelineIid: defaultProps.pipelineIid,
- });
- });
- });
-
- describe('when loading failed jobs', () => {
- beforeEach(() => {
- mockFailedJobsResponse.mockResolvedValue(failedJobsMock);
- createComponent();
- });
-
- it('shows a loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(true);
- });
- });
-
- describe('when failed jobs have loaded', () => {
- beforeEach(async () => {
- mockFailedJobsResponse.mockResolvedValue(failedJobsMock);
- jest.spyOn(utils, 'sortJobsByStatus');
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('does not renders a loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('renders table column', () => {
- expect(findAllHeaders()).toHaveLength(3);
- });
-
- it('shows the list of failed jobs', () => {
- expect(findFailedJobRows()).toHaveLength(
- failedJobsMock.data.project.pipeline.jobs.nodes.length,
- );
- });
-
- it('does not renders the empty state', () => {
- expect(findNoFailedJobsText().exists()).toBe(false);
- });
-
- it('calls sortJobsByStatus', () => {
- expect(utils.sortJobsByStatus).toHaveBeenCalledWith(
- failedJobsMock.data.project.pipeline.jobs.nodes,
- );
- });
- });
-
- describe('when there are no failed jobs', () => {
- beforeEach(async () => {
- mockFailedJobsResponse.mockResolvedValue(failedJobsMockEmpty);
- jest.spyOn(utils, 'sortJobsByStatus');
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('renders the empty state', () => {
- expect(findNoFailedJobsText().exists()).toBe(true);
- });
- });
-
- describe('polling', () => {
- it.each`
- isGraphqlActive | text
- ${true} | ${'polls'}
- ${false} | ${'does not poll'}
- `(`$text when isGraphqlActive: $isGraphqlActive`, async ({ isGraphqlActive }) => {
- const defaultCount = 2;
- const newCount = 1;
-
- const expectedCount = isGraphqlActive ? newCount : defaultCount;
- const expectedCallCount = isGraphqlActive ? 2 : 1;
- const mockResponse = isGraphqlActive ? activeFailedJobsMock : failedJobsMock;
-
- // Second result is to simulate polling with a different response
- mockFailedJobsResponse.mockResolvedValueOnce(mockResponse);
- mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock2);
-
- createComponent();
- await waitForPromises();
-
- // Initially, we get the first response which is always the default
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
- expect(findFailedJobRows()).toHaveLength(defaultCount);
-
- jest.advanceTimersByTime(10000);
- await waitForPromises();
-
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(expectedCallCount);
- expect(findFailedJobRows()).toHaveLength(expectedCount);
- });
- });
-
- describe('when a REST action occurs', () => {
- beforeEach(() => {
- // Second result is to simulate polling with a different response
- mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock);
- mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock2);
- });
-
- it.each([true, false])('triggers a refetch of the jobs count', async (isPipelineActive) => {
- const defaultCount = 2;
- const newCount = 1;
-
- createComponent({ props: { isPipelineActive } });
- await waitForPromises();
-
- // Initially, we get the first response which is always the default
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
- expect(findFailedJobRows()).toHaveLength(defaultCount);
-
- wrapper.setProps({ isPipelineActive: !isPipelineActive });
- await waitForPromises();
-
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(2);
- expect(findFailedJobRows()).toHaveLength(newCount);
- });
- });
-
- describe('When the job count changes from REST', () => {
- beforeEach(() => {
- mockFailedJobsResponse.mockResolvedValue(failedJobsMockEmpty);
-
- createComponent();
- });
-
- describe('and the count is the same', () => {
- it('does not re-fetch the query', async () => {
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
-
- await wrapper.setProps({ failedJobsCount: 0 });
-
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('and the count is different', () => {
- it('re-fetches the query', async () => {
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(1);
-
- await wrapper.setProps({ failedJobsCount: 10 });
-
- expect(mockFailedJobsResponse).toHaveBeenCalledTimes(2);
- });
- });
- });
-
- describe('when an error occurs loading jobs', () => {
- const errorMessage = "We couldn't fetch jobs for you because you are not qualified";
-
- beforeEach(async () => {
- mockFailedJobsResponse.mockRejectedValue({ message: errorMessage });
-
- createComponent();
-
- await waitForPromises();
- });
- it('does not renders a loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('calls create Alert with the error message and danger variant', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: errorMessage, variant: 'danger' });
- });
- });
-
- describe('when `refetch-jobs` job is fired from the widget', () => {
- beforeEach(async () => {
- mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock);
- mockFailedJobsResponse.mockResolvedValueOnce(failedJobsMock2);
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('refetches all failed jobs', async () => {
- expect(findFailedJobRows()).not.toHaveLength(
- failedJobsMock2.data.project.pipeline.jobs.nodes.length,
- );
-
- await findFailedJobRows().at(0).vm.$emit('job-retried', 'job-name');
- await waitForPromises();
-
- expect(findFailedJobRows()).toHaveLength(
- failedJobsMock2.data.project.pipeline.jobs.nodes.length,
- );
- });
-
- it('shows a toast message', async () => {
- await findFailedJobRows().at(0).vm.$emit('job-retried', 'job-name');
- await waitForPromises();
-
- expect(showToast).toHaveBeenCalledWith('job-name job is being retried');
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js b/spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js
deleted file mode 100644
index 5bbb874edb0..00000000000
--- a/spec/frontend/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget_spec.js
+++ /dev/null
@@ -1,139 +0,0 @@
-import { GlButton, GlCard, GlIcon, GlPopover } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import PipelineFailedJobsWidget from '~/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget.vue';
-import FailedJobsList from '~/pipelines/components/pipelines_list/failure_widget/failed_jobs_list.vue';
-
-jest.mock('~/alert');
-
-describe('PipelineFailedJobsWidget component', () => {
- let wrapper;
-
- const defaultProps = {
- failedJobsCount: 4,
- isPipelineActive: false,
- pipelineIid: 1,
- pipelinePath: '/pipelines/1',
- projectPath: 'namespace/project/',
- };
-
- const defaultProvide = {
- fullPath: 'namespace/project/',
- };
-
- const createComponent = ({ props = {}, provide = {} } = {}) => {
- wrapper = shallowMountExtended(PipelineFailedJobsWidget, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- provide: {
- ...defaultProvide,
- ...provide,
- },
- stubs: { GlCard },
- });
- };
-
- const findFailedJobsCard = () => wrapper.findByTestId('failed-jobs-card');
- const findFailedJobsButton = () => wrapper.findComponent(GlButton);
- const findFailedJobsList = () => wrapper.findAllComponents(FailedJobsList);
- const findInfoIcon = () => wrapper.findComponent(GlIcon);
- const findInfoPopover = () => wrapper.findComponent(GlPopover);
-
- describe('when there are no failed jobs', () => {
- beforeEach(() => {
- createComponent({ props: { failedJobsCount: 0 } });
- });
-
- it('renders the show failed jobs button with a count of 0', () => {
- expect(findFailedJobsButton().exists()).toBe(true);
- expect(findFailedJobsButton().text()).toBe('Failed jobs (0)');
- });
- });
-
- describe('when there are failed jobs', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders the show failed jobs button with correct count', () => {
- expect(findFailedJobsButton().exists()).toBe(true);
- expect(findFailedJobsButton().text()).toBe(`Failed jobs (${defaultProps.failedJobsCount})`);
- });
-
- it('renders the info icon', () => {
- expect(findInfoIcon().exists()).toBe(true);
- });
-
- it('renders the info popover', () => {
- expect(findInfoPopover().exists()).toBe(true);
- });
-
- it('does not render the failed jobs widget', () => {
- expect(findFailedJobsList().exists()).toBe(false);
- });
- });
-
- describe('when the job button is clicked', () => {
- beforeEach(async () => {
- createComponent();
- await findFailedJobsButton().vm.$emit('click');
- });
-
- it('renders the failed jobs widget', () => {
- expect(findFailedJobsList().exists()).toBe(true);
- });
-
- it('removes the CSS border classes', () => {
- expect(findFailedJobsCard().attributes('class')).not.toContain(
- 'gl-border-white gl-hover-border-gray-100',
- );
- });
- });
-
- describe('when the job details are not expanded', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('has the CSS border classes', () => {
- expect(findFailedJobsCard().attributes('class')).toContain(
- 'gl-border-white gl-hover-border-gray-100',
- );
- });
- });
-
- describe('when the job count changes', () => {
- beforeEach(() => {
- createComponent();
- });
-
- describe('from the prop', () => {
- it('updates the job count', async () => {
- const newJobCount = 12;
-
- expect(findFailedJobsButton().text()).toContain(String(defaultProps.failedJobsCount));
-
- await wrapper.setProps({ failedJobsCount: newJobCount });
-
- expect(findFailedJobsButton().text()).toContain(String(newJobCount));
- });
- });
-
- describe('from the event', () => {
- beforeEach(async () => {
- await findFailedJobsButton().vm.$emit('click');
- });
-
- it('updates the job count', async () => {
- const newJobCount = 12;
-
- expect(findFailedJobsButton().text()).toContain(String(defaultProps.failedJobsCount));
-
- await findFailedJobsList().at(0).vm.$emit('failed-jobs-count', newJobCount);
-
- expect(findFailedJobsButton().text()).toContain(String(newJobCount));
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/failure_widget/utils_spec.js b/spec/frontend/pipelines/components/pipelines_list/failure_widget/utils_spec.js
deleted file mode 100644
index 44f16478151..00000000000
--- a/spec/frontend/pipelines/components/pipelines_list/failure_widget/utils_spec.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import {
- isFailedJob,
- sortJobsByStatus,
-} from '~/pipelines/components/pipelines_list/failure_widget/utils';
-
-describe('isFailedJob', () => {
- describe('when the job argument is undefined', () => {
- it('returns false', () => {
- expect(isFailedJob()).toBe(false);
- });
- });
-
- describe('when the job is of status `failed`', () => {
- it('returns false', () => {
- expect(isFailedJob({ detailedStatus: { group: 'success' } })).toBe(false);
- });
- });
-
- describe('when the job status is `failed`', () => {
- it('returns true', () => {
- expect(isFailedJob({ detailedStatus: { group: 'failed' } })).toBe(true);
- });
- });
-});
-
-describe('sortJobsByStatus', () => {
- describe('when the arg is undefined', () => {
- it('returns an empty array', () => {
- expect(sortJobsByStatus()).toEqual([]);
- });
- });
-
- describe('when receiving an empty array', () => {
- it('returns an empty array', () => {
- expect(sortJobsByStatus([])).toEqual([]);
- });
- });
-
- describe('when reciving a list of jobs', () => {
- const jobArr = [
- { detailedStatus: { group: 'failed' } },
- { detailedStatus: { group: 'allowed_to_fail' } },
- { detailedStatus: { group: 'failed' } },
- { detailedStatus: { group: 'success' } },
- ];
-
- const expectedResult = [
- { detailedStatus: { group: 'failed' } },
- { detailedStatus: { group: 'failed' } },
- { detailedStatus: { group: 'allowed_to_fail' } },
- { detailedStatus: { group: 'success' } },
- ];
-
- it('sorts failed jobs first', () => {
- expect(sortJobsByStatus(jobArr)).toEqual(expectedResult);
- });
- });
-});
diff --git a/spec/frontend/pipelines/components/pipelines_list/pipieline_stop_modal_spec.js b/spec/frontend/pipelines/components/pipelines_list/pipieline_stop_modal_spec.js
deleted file mode 100644
index 249126390f1..00000000000
--- a/spec/frontend/pipelines/components/pipelines_list/pipieline_stop_modal_spec.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlSprintf } from '@gitlab/ui';
-import PipelineStopModal from '~/pipelines/components/pipelines_list/pipeline_stop_modal.vue';
-import { mockPipelineHeader } from '../../mock_data';
-
-describe('PipelineStopModal', () => {
- let wrapper;
-
- const createComponent = () => {
- wrapper = shallowMount(PipelineStopModal, {
- propsData: {
- pipeline: mockPipelineHeader,
- },
- stubs: {
- GlSprintf,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('should render "stop pipeline" warning', () => {
- expect(wrapper.text()).toMatch(`You’re about to stop pipeline #${mockPipelineHeader.id}.`);
- });
-});
diff --git a/spec/frontend/pipelines/empty_state_spec.js b/spec/frontend/pipelines/empty_state_spec.js
deleted file mode 100644
index 5465e4d77da..00000000000
--- a/spec/frontend/pipelines/empty_state_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import '~/commons';
-import { shallowMount } from '@vue/test-utils';
-import { GlEmptyState } from '@gitlab/ui';
-import { stubExperiments } from 'helpers/experimentation_helper';
-import EmptyState from '~/pipelines/components/pipelines_list/empty_state.vue';
-import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
-import PipelinesCiTemplates from '~/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue';
-import IosTemplates from '~/pipelines/components/pipelines_list/empty_state/ios_templates.vue';
-
-describe('Pipelines Empty State', () => {
- let wrapper;
-
- const findIllustration = () => wrapper.find('img');
- const findButton = () => wrapper.find('a');
- const pipelinesCiTemplates = () => wrapper.findComponent(PipelinesCiTemplates);
- const iosTemplates = () => wrapper.findComponent(IosTemplates);
-
- const createWrapper = (props = {}) => {
- wrapper = shallowMount(EmptyState, {
- provide: {
- pipelineEditorPath: '',
- suggestedCiTemplates: [],
- anyRunnersAvailable: true,
- ciRunnerSettingsPath: '',
- },
- propsData: {
- emptyStateSvgPath: 'foo.svg',
- canSetCi: true,
- ...props,
- },
- stubs: {
- GlEmptyState,
- GitlabExperiment,
- },
- });
- };
-
- describe('when user can configure CI', () => {
- describe('when the ios_specific_templates experiment is active', () => {
- beforeEach(() => {
- stubExperiments({ ios_specific_templates: 'candidate' });
- createWrapper();
- });
-
- it('should render the iOS templates', () => {
- expect(iosTemplates().exists()).toBe(true);
- });
-
- it('should not render the CI/CD templates', () => {
- expect(pipelinesCiTemplates().exists()).toBe(false);
- });
- });
-
- describe('when the ios_specific_templates experiment is inactive', () => {
- beforeEach(() => {
- stubExperiments({ ios_specific_templates: 'control' });
- createWrapper();
- });
-
- it('should render the CI/CD templates', () => {
- expect(pipelinesCiTemplates().exists()).toBe(true);
- });
-
- it('should not render the iOS templates', () => {
- expect(iosTemplates().exists()).toBe(false);
- });
- });
- });
-
- describe('when user cannot configure CI', () => {
- beforeEach(() => {
- createWrapper({ canSetCi: false });
- });
-
- it('should render empty state SVG', () => {
- expect(findIllustration().attributes('src')).toBe('foo.svg');
- });
-
- it('should render empty state header', () => {
- expect(wrapper.text()).toBe('This project is not currently set up to run pipelines.');
- });
-
- it('should not render a link', () => {
- expect(findButton().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph/action_component_spec.js b/spec/frontend/pipelines/graph/action_component_spec.js
deleted file mode 100644
index 890255f225e..00000000000
--- a/spec/frontend/pipelines/graph/action_component_spec.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import { GlButton } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
-import waitForPromises from 'helpers/wait_for_promises';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import ActionComponent from '~/pipelines/components/jobs_shared/action_component.vue';
-
-describe('pipeline graph action component', () => {
- let wrapper;
- let mock;
- const findButton = () => wrapper.findComponent(GlButton);
- const findTooltipWrapper = () => wrapper.find('[data-testid="ci-action-icon-tooltip-wrapper"]');
-
- const defaultProps = {
- tooltipText: 'bar',
- link: 'foo',
- actionIcon: 'cancel',
- };
-
- const createComponent = ({ props } = {}) => {
- wrapper = mount(ActionComponent, {
- propsData: { ...defaultProps, ...props },
- });
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- mock.onPost('foo.json').reply(HTTP_STATUS_OK);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('render', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('should render the provided title as a bootstrap tooltip', () => {
- expect(findTooltipWrapper().attributes('title')).toBe('bar');
- });
-
- it('should update bootstrap tooltip when title changes', async () => {
- wrapper.setProps({ tooltipText: 'changed' });
-
- await nextTick();
- expect(findTooltipWrapper().attributes('title')).toBe('changed');
- });
-
- it('should render an svg', () => {
- expect(wrapper.find('.ci-action-icon-wrapper').exists()).toBe(true);
- expect(wrapper.find('svg').exists()).toBe(true);
- });
- });
-
- describe('on click', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('emits `pipelineActionRequestComplete` after a successful request', async () => {
- findButton().trigger('click');
-
- await waitForPromises();
-
- expect(wrapper.emitted().pipelineActionRequestComplete).toHaveLength(1);
- });
-
- it('renders a loading icon while waiting for request', async () => {
- findButton().trigger('click');
-
- await nextTick();
- expect(wrapper.find('.js-action-icon-loading').exists()).toBe(true);
- });
- });
-
- describe('when has a confirmation modal', () => {
- beforeEach(() => {
- createComponent({ props: { withConfirmationModal: true, shouldTriggerClick: false } });
- });
-
- describe('and a first click is initiated', () => {
- beforeEach(async () => {
- findButton().trigger('click');
-
- await waitForPromises();
- });
-
- it('emits `showActionConfirmationModal` event', () => {
- expect(wrapper.emitted().showActionConfirmationModal).toHaveLength(1);
- });
-
- it('does not emit `pipelineActionRequestComplete` event', () => {
- expect(wrapper.emitted().pipelineActionRequestComplete).toBeUndefined();
- });
- });
-
- describe('and the `shouldTriggerClick` value becomes true', () => {
- beforeEach(async () => {
- await wrapper.setProps({ shouldTriggerClick: true });
- });
-
- it('does not emit `showActionConfirmationModal` event', () => {
- expect(wrapper.emitted().showActionConfirmationModal).toBeUndefined();
- });
-
- it('emits `actionButtonClicked` event', () => {
- expect(wrapper.emitted().actionButtonClicked).toHaveLength(1);
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph/graph_component_spec.js b/spec/frontend/pipelines/graph/graph_component_spec.js
deleted file mode 100644
index e9bce037800..00000000000
--- a/spec/frontend/pipelines/graph/graph_component_spec.js
+++ /dev/null
@@ -1,182 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { LAYER_VIEW, STAGE_VIEW } from '~/pipelines/components/graph/constants';
-import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
-import JobItem from '~/pipelines/components/graph/job_item.vue';
-import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue';
-import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
-import { calculatePipelineLayersInfo } from '~/pipelines/components/graph/utils';
-import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
-
-import { generateResponse, pipelineWithUpstreamDownstream } from './mock_data';
-
-describe('graph component', () => {
- let wrapper;
-
- const findDownstreamColumn = () => wrapper.findByTestId('downstream-pipelines');
- const findLinkedColumns = () => wrapper.findAllComponents(LinkedPipelinesColumn);
- const findLinksLayer = () => wrapper.findComponent(LinksLayer);
- const findStageColumns = () => wrapper.findAllComponents(StageColumnComponent);
- const findStageNameInJob = () => wrapper.findByTestId('stage-name-in-job');
-
- const defaultProps = {
- pipeline: generateResponse(mockPipelineResponse, 'root/fungi-xoxo'),
- showLinks: false,
- viewType: STAGE_VIEW,
- configPaths: {
- metricsPath: '',
- graphqlResourceEtag: 'this/is/a/path',
- },
- };
-
- const defaultData = {
- measurements: {
- width: 800,
- height: 800,
- },
- };
-
- const createComponent = ({
- data = {},
- mountFn = shallowMount,
- props = {},
- stubOverride = {},
- } = {}) => {
- wrapper = mountFn(PipelineGraph, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- data() {
- return {
- ...defaultData,
- ...data,
- };
- },
- stubs: {
- 'links-inner': true,
- 'linked-pipeline': true,
- 'job-item': true,
- 'job-group-dropdown': true,
- ...stubOverride,
- },
- });
- };
-
- describe('with data', () => {
- beforeEach(() => {
- createComponent({ mountFn: mountExtended });
- });
-
- it('renders the main columns in the graph', () => {
- expect(findStageColumns()).toHaveLength(defaultProps.pipeline.stages.length);
- });
-
- it('renders the links layer', () => {
- expect(findLinksLayer().exists()).toBe(true);
- });
-
- it('does not display stage name on the job in default (stage) mode', () => {
- expect(findStageNameInJob().exists()).toBe(false);
- });
-
- describe('when column requests a refresh', () => {
- beforeEach(() => {
- findStageColumns().at(0).vm.$emit('refreshPipelineGraph');
- });
-
- it('refreshPipelineGraph is emitted', () => {
- expect(wrapper.emitted().refreshPipelineGraph).toHaveLength(1);
- });
- });
-
- describe('when column request an update to the retry confirmation modal', () => {
- beforeEach(() => {
- findStageColumns().at(0).vm.$emit('setSkipRetryModal');
- });
-
- it('setSkipRetryModal is emitted', () => {
- expect(wrapper.emitted().setSkipRetryModal).toHaveLength(1);
- });
- });
-
- describe('when links are present', () => {
- beforeEach(() => {
- createComponent({
- mountFn: mountExtended,
- stubOverride: { 'job-item': false },
- data: { hoveredJobName: 'test_a' },
- });
- findLinksLayer().vm.$emit('highlightedJobsChange', ['test_c', 'build_c']);
- });
-
- it('dims unrelated jobs', () => {
- const unrelatedJob = wrapper.findComponent(JobItem);
- expect(findLinksLayer().emitted().highlightedJobsChange).toHaveLength(1);
- expect(unrelatedJob.classes('gl-opacity-3')).toBe(true);
- });
- });
- });
-
- describe('when linked pipelines are not present', () => {
- beforeEach(() => {
- createComponent({ mountFn: mountExtended });
- });
-
- it('should not render a linked pipelines column', () => {
- expect(findLinkedColumns()).toHaveLength(0);
- });
- });
-
- describe('when linked pipelines are present', () => {
- beforeEach(() => {
- createComponent({
- mountFn: mountExtended,
- props: { pipeline: pipelineWithUpstreamDownstream(mockPipelineResponse) },
- });
- });
-
- it('should render linked pipelines columns', () => {
- expect(findLinkedColumns()).toHaveLength(2);
- });
- });
-
- describe('in layers mode', () => {
- beforeEach(() => {
- createComponent({
- mountFn: mountExtended,
- stubOverride: {
- 'job-item': false,
- 'job-group-dropdown': false,
- },
- props: {
- viewType: LAYER_VIEW,
- computedPipelineInfo: calculatePipelineLayersInfo(defaultProps.pipeline, 'layer', ''),
- },
- });
- });
-
- it('displays the stage name on the job', () => {
- expect(findStageNameInJob().exists()).toBe(true);
- });
- });
-
- describe('downstream pipelines', () => {
- beforeEach(() => {
- createComponent({
- mountFn: mountExtended,
- props: {
- pipeline: pipelineWithUpstreamDownstream(mockPipelineResponse),
- },
- });
- });
-
- it('filters pipelines spawned from the same trigger job', () => {
- // The mock data has one downstream with `retried: true and one
- // with retried false. We filter the `retried: true` out so we
- // should only pass one downstream
- expect(findDownstreamColumn().props().linkedPipelines).toHaveLength(1);
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js b/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
deleted file mode 100644
index 7b59d82ae6f..00000000000
--- a/spec/frontend/pipelines/graph/graph_component_wrapper_spec.js
+++ /dev/null
@@ -1,603 +0,0 @@
-import { GlAlert, GlButton, GlButtonGroup, GlLoadingIcon, GlToggle } from '@gitlab/ui';
-import MockAdapter from 'axios-mock-adapter';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
-import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { stubPerformanceWebAPI } from 'helpers/performance';
-import waitForPromises from 'helpers/wait_for_promises';
-import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
-import getUserCallouts from '~/graphql_shared/queries/get_user_callouts.query.graphql';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import {
- PIPELINES_DETAIL_LINK_DURATION,
- PIPELINES_DETAIL_LINKS_TOTAL,
- PIPELINES_DETAIL_LINKS_JOB_RATIO,
-} from '~/performance/constants';
-import * as perfUtils from '~/performance/utils';
-import {
- ACTION_FAILURE,
- LAYER_VIEW,
- STAGE_VIEW,
- VIEW_TYPE_KEY,
-} from '~/pipelines/components/graph/constants';
-import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
-import PipelineGraphWrapper from '~/pipelines/components/graph/graph_component_wrapper.vue';
-import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector.vue';
-import * as Api from '~/pipelines/components/graph_shared/api';
-import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
-import * as parsingUtils from '~/pipelines/components/parsing_utils';
-import getPipelineHeaderData from '~/pipelines/graphql/queries/get_pipeline_header_data.query.graphql';
-import * as sentryUtils from '~/pipelines/utils';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-import { mockRunningPipelineHeaderData } from '../mock_data';
-import {
- mapCallouts,
- mockCalloutsResponse,
- mockPipelineResponseWithTooManyJobs,
-} from './mock_data';
-
-const defaultProvide = {
- graphqlResourceEtag: 'frog/amphibirama/etag/',
- metricsPath: '',
- pipelineProjectPath: 'frog/amphibirama',
- pipelineIid: '22',
-};
-
-describe('Pipeline graph wrapper', () => {
- Vue.use(VueApollo);
- useLocalStorageSpy();
-
- let wrapper;
- let requestHandlers;
- let pipelineDetailsHandler;
-
- const findAlert = () => wrapper.findByTestId('error-alert');
- const findJobCountWarning = () => wrapper.findByTestId('job-count-warning');
- const findDependenciesToggle = () => wrapper.findByTestId('show-links-toggle');
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findLinksLayer = () => wrapper.findComponent(LinksLayer);
- const findGraph = () => wrapper.findComponent(PipelineGraph);
- const findStageColumnTitle = () => wrapper.findByTestId('stage-column-title');
- const findViewSelector = () => wrapper.findComponent(GraphViewSelector);
- const findViewSelectorToggle = () => findViewSelector().findComponent(GlToggle);
- const findViewSelectorTrip = () => findViewSelector().findComponent(GlAlert);
- const getLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
-
- const createComponent = ({
- apolloProvider,
- data = {},
- provide = {},
- mountFn = shallowMountExtended,
- } = {}) => {
- wrapper = mountFn(PipelineGraphWrapper, {
- provide: {
- ...defaultProvide,
- ...provide,
- },
- apolloProvider,
- data() {
- return {
- ...data,
- };
- },
- });
- };
-
- const createComponentWithApollo = ({
- calloutsList = [],
- data = {},
- mountFn = shallowMountExtended,
- provide = {},
- } = {}) => {
- const callouts = mapCallouts(calloutsList);
-
- requestHandlers = {
- getUserCalloutsHandler: jest.fn().mockResolvedValue(mockCalloutsResponse(callouts)),
- getPipelineHeaderDataHandler: jest.fn().mockResolvedValue(mockRunningPipelineHeaderData),
- getPipelineDetailsHandler: pipelineDetailsHandler,
- };
-
- const handlers = [
- [getPipelineHeaderData, requestHandlers.getPipelineHeaderDataHandler],
- [getPipelineDetails, requestHandlers.getPipelineDetailsHandler],
- [getUserCallouts, requestHandlers.getUserCalloutsHandler],
- ];
-
- const apolloProvider = createMockApollo(handlers);
- createComponent({ apolloProvider, data, provide, mountFn });
- };
-
- beforeEach(() => {
- pipelineDetailsHandler = jest.fn();
- pipelineDetailsHandler.mockResolvedValue(mockPipelineResponse);
- });
-
- describe('when data is loading', () => {
- beforeEach(() => {
- createComponentWithApollo();
- });
-
- it('displays the loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(true);
- });
-
- it('does not display the alert', () => {
- expect(findAlert().exists()).toBe(false);
- });
-
- it('does not display the graph', () => {
- expect(findGraph().exists()).toBe(false);
- });
-
- it('skips querying headerPipeline', () => {
- expect(wrapper.vm.$apollo.queries.headerPipeline.skip).toBe(true);
- });
- });
-
- describe('when data has loaded', () => {
- beforeEach(async () => {
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('does not display the loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('does not display the alert', () => {
- expect(findAlert().exists()).toBe(false);
- });
-
- it('displays the graph', () => {
- expect(findGraph().exists()).toBe(true);
- });
-
- it('passes the etag resource and metrics path to the graph', () => {
- expect(findGraph().props('configPaths')).toMatchObject({
- graphqlResourceEtag: defaultProvide.graphqlResourceEtag,
- metricsPath: defaultProvide.metricsPath,
- });
- });
- });
-
- describe('when a stage has 100 jobs or more', () => {
- beforeEach(async () => {
- pipelineDetailsHandler.mockResolvedValue(mockPipelineResponseWithTooManyJobs);
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('show a warning alert', () => {
- expect(findJobCountWarning().exists()).toBe(true);
- expect(findJobCountWarning().props().title).toBe(
- 'Only the first 100 jobs per stage are displayed',
- );
- });
- });
-
- describe('when there is an error', () => {
- beforeEach(async () => {
- pipelineDetailsHandler.mockRejectedValue(new Error('GraphQL error'));
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('does not display the loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('displays the alert', () => {
- expect(findAlert().exists()).toBe(true);
- });
-
- it('does not display the graph', () => {
- expect(findGraph().exists()).toBe(false);
- });
- });
-
- describe('when there is no pipeline iid available', () => {
- beforeEach(async () => {
- createComponentWithApollo({
- provide: {
- pipelineIid: '',
- },
- });
- await waitForPromises();
- });
-
- it('does not display the loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('displays the no iid alert', () => {
- expect(findAlert().exists()).toBe(true);
- expect(findAlert().text()).toBe(
- 'The data in this pipeline is too old to be rendered as a graph. Please check the Jobs tab to access historical data.',
- );
- });
-
- it('does not display the graph', () => {
- expect(findGraph().exists()).toBe(false);
- });
- });
-
- describe('events', () => {
- beforeEach(async () => {
- createComponentWithApollo();
- await waitForPromises();
- });
- describe('when receiving `setSkipRetryModal` event', () => {
- it('passes down `skipRetryModal` value as true', async () => {
- expect(findGraph().props('skipRetryModal')).toBe(false);
-
- await findGraph().vm.$emit('setSkipRetryModal');
-
- expect(findGraph().props('skipRetryModal')).toBe(true);
- });
- });
- });
-
- describe('when there is an error with an action in the graph', () => {
- beforeEach(async () => {
- createComponentWithApollo();
- await waitForPromises();
- await findGraph().vm.$emit('error', { type: ACTION_FAILURE });
- });
-
- it('does not display the loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('displays the action error alert', () => {
- expect(findAlert().exists()).toBe(true);
- expect(findAlert().text()).toBe('An error occurred while performing this action.');
- });
-
- it('displays the graph', () => {
- expect(findGraph().exists()).toBe(true);
- });
- });
-
- describe('when refresh action is emitted', () => {
- beforeEach(async () => {
- createComponentWithApollo();
- await waitForPromises();
- findGraph().vm.$emit('refreshPipelineGraph');
- });
-
- it('calls refetch', () => {
- expect(requestHandlers.getPipelineHeaderDataHandler).toHaveBeenCalledWith({
- fullPath: 'frog/amphibirama',
- iid: '22',
- });
- expect(requestHandlers.getPipelineDetailsHandler).toHaveBeenCalledTimes(2);
- expect(requestHandlers.getUserCalloutsHandler).toHaveBeenCalledWith({});
- });
- });
-
- describe('when query times out', () => {
- const advanceApolloTimers = async () => {
- jest.runOnlyPendingTimers();
- await waitForPromises();
- };
-
- beforeEach(async () => {
- const errorData = {
- data: {
- project: {
- pipelines: null,
- },
- },
- errors: [{ message: 'timeout' }],
- };
-
- pipelineDetailsHandler
- .mockResolvedValueOnce(errorData)
- .mockResolvedValueOnce(mockPipelineResponse)
- .mockResolvedValueOnce(errorData);
-
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('shows correct errors and does not overwrite populated data when data is empty', async () => {
- /* fails at first, shows error, no data yet */
- expect(findAlert().exists()).toBe(true);
- expect(findGraph().exists()).toBe(false);
-
- /* succeeds, clears error, shows graph */
- await advanceApolloTimers();
- expect(findAlert().exists()).toBe(false);
- expect(findGraph().exists()).toBe(true);
-
- /* fails again, alert returns but data persists */
- await advanceApolloTimers();
- expect(findAlert().exists()).toBe(true);
- expect(findGraph().exists()).toBe(true);
- });
- });
-
- describe('view dropdown', () => {
- describe('default', () => {
- let layersFn;
- beforeEach(async () => {
- layersFn = jest.spyOn(parsingUtils, 'listByLayers');
- createComponentWithApollo({
- mountFn: mountExtended,
- });
-
- await waitForPromises();
- });
-
- it('appears when pipeline uses needs', () => {
- expect(findViewSelector().exists()).toBe(true);
- });
-
- it('switches between views', async () => {
- expect(findStageColumnTitle().text()).toBe('deploy');
-
- await findViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
-
- expect(findStageColumnTitle().text()).toBe('');
- });
-
- it('saves the view type to local storage', async () => {
- await findViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
- expect(localStorage.setItem.mock.calls).toEqual([[VIEW_TYPE_KEY, LAYER_VIEW]]);
- });
-
- it('calls listByLayers only once no matter how many times view is switched', async () => {
- expect(layersFn).not.toHaveBeenCalled();
- await findViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
- expect(layersFn).toHaveBeenCalledTimes(1);
- await findViewSelector().vm.$emit('updateViewType', STAGE_VIEW);
- await findViewSelector().vm.$emit('updateViewType', LAYER_VIEW);
- await findViewSelector().vm.$emit('updateViewType', STAGE_VIEW);
- expect(layersFn).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('when layers view is selected', () => {
- beforeEach(async () => {
- createComponentWithApollo({
- data: {
- currentViewType: LAYER_VIEW,
- },
- mountFn: mountExtended,
- });
-
- jest.runOnlyPendingTimers();
- await waitForPromises();
- });
-
- it('sets showLinks to true', async () => {
- /* This spec uses .props for performance reasons. */
- expect(findLinksLayer().exists()).toBe(true);
- expect(findLinksLayer().props('showLinks')).toBe(false);
- expect(findViewSelector().props('type')).toBe(LAYER_VIEW);
- await findDependenciesToggle().vm.$emit('change', true);
-
- jest.runOnlyPendingTimers();
- await waitForPromises();
- expect(wrapper.findComponent(LinksLayer).props('showLinks')).toBe(true);
- });
- });
-
- describe('when layers view is selected, and links are active', () => {
- beforeEach(async () => {
- createComponentWithApollo({
- data: {
- currentViewType: LAYER_VIEW,
- showLinks: true,
- },
- mountFn: mountExtended,
- });
-
- await waitForPromises();
- });
-
- it('shows the hover tip in the view selector', async () => {
- await findViewSelectorToggle().vm.$emit('change', true);
- expect(findViewSelectorTrip().exists()).toBe(true);
- });
- });
-
- describe('when hover tip would otherwise show, but it has been previously dismissed', () => {
- beforeEach(async () => {
- createComponentWithApollo({
- data: {
- currentViewType: LAYER_VIEW,
- showLinks: true,
- },
- mountFn: mountExtended,
- calloutsList: ['pipeline_needs_hover_tip'.toUpperCase()],
- });
-
- jest.runOnlyPendingTimers();
- await waitForPromises();
- });
-
- it('does not show the hover tip', async () => {
- await findViewSelectorToggle().vm.$emit('change', true);
- expect(findViewSelectorTrip().exists()).toBe(false);
- });
- });
-
- describe('when feature flag is on and local storage is set', () => {
- beforeEach(async () => {
- localStorage.setItem(VIEW_TYPE_KEY, LAYER_VIEW);
-
- createComponentWithApollo({
- mountFn: mountExtended,
- });
-
- await waitForPromises();
- });
-
- afterEach(() => {
- localStorage.clear();
- });
-
- it('sets the asString prop on the LocalStorageSync component', () => {
- expect(getLocalStorageSync().props('asString')).toBe(true);
- });
-
- it('reads the view type from localStorage when available', () => {
- const viewSelectorNeedsSegment = wrapper
- .findComponent(GlButtonGroup)
- .findAllComponents(GlButton)
- .at(1);
- expect(viewSelectorNeedsSegment.classes()).toContain('selected');
- });
- });
-
- describe('when feature flag is on and local storage is set, but the graph does not use needs', () => {
- beforeEach(async () => {
- const nonNeedsResponse = { ...mockPipelineResponse };
- nonNeedsResponse.data.project.pipeline.usesNeeds = false;
-
- localStorage.setItem(VIEW_TYPE_KEY, LAYER_VIEW);
-
- pipelineDetailsHandler.mockResolvedValue(nonNeedsResponse);
- createComponentWithApollo({
- mountFn: mountExtended,
- });
-
- await waitForPromises();
- });
-
- afterEach(() => {
- localStorage.clear();
- });
-
- it('still passes stage type to graph', () => {
- expect(findGraph().props('viewType')).toBe(STAGE_VIEW);
- });
- });
-
- describe('when feature flag is on but pipeline does not use needs', () => {
- beforeEach(async () => {
- const nonNeedsResponse = { ...mockPipelineResponse };
- nonNeedsResponse.data.project.pipeline.usesNeeds = false;
-
- pipelineDetailsHandler.mockResolvedValue(nonNeedsResponse);
- createComponentWithApollo({
- mountFn: mountExtended,
- });
-
- jest.runOnlyPendingTimers();
- await waitForPromises();
- });
-
- it('does not appear when pipeline does not use needs', () => {
- expect(findViewSelector().exists()).toBe(false);
- });
- });
- });
-
- describe('performance metrics', () => {
- const metricsPath = '/root/project/-/ci/prometheus_metrics/histograms.json';
- let markAndMeasure;
- let reportToSentry;
- let reportPerformance;
- let mock;
-
- beforeEach(() => {
- jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => cb());
- markAndMeasure = jest.spyOn(perfUtils, 'performanceMarkAndMeasure');
- reportToSentry = jest.spyOn(sentryUtils, 'reportToSentry');
- reportPerformance = jest.spyOn(Api, 'reportPerformance');
- });
-
- describe('with no metrics path', () => {
- beforeEach(async () => {
- createComponentWithApollo();
- await waitForPromises();
- });
-
- it('is not called', () => {
- expect(markAndMeasure).not.toHaveBeenCalled();
- expect(reportToSentry).not.toHaveBeenCalled();
- expect(reportPerformance).not.toHaveBeenCalled();
- });
- });
-
- describe('with metrics path', () => {
- const duration = 500;
- const numLinks = 3;
- const totalGroups = 7;
- const metricsData = {
- histograms: [
- { name: PIPELINES_DETAIL_LINK_DURATION, value: duration / 1000 },
- { name: PIPELINES_DETAIL_LINKS_TOTAL, value: numLinks },
- {
- name: PIPELINES_DETAIL_LINKS_JOB_RATIO,
- value: numLinks / totalGroups,
- },
- ],
- };
-
- describe('when no duration is obtained', () => {
- beforeEach(async () => {
- stubPerformanceWebAPI();
-
- createComponentWithApollo({
- provide: {
- metricsPath,
- glFeatures: {
- pipelineGraphLayersView: true,
- },
- },
- data: {
- currentViewType: LAYER_VIEW,
- },
- });
-
- await waitForPromises();
- });
-
- it('attempts to collect metrics', () => {
- expect(markAndMeasure).toHaveBeenCalled();
- expect(reportPerformance).not.toHaveBeenCalled();
- expect(reportToSentry).not.toHaveBeenCalled();
- });
- });
-
- describe('with duration and no error', () => {
- beforeEach(async () => {
- mock = new MockAdapter(axios);
- mock.onPost(metricsPath).reply(HTTP_STATUS_OK, {});
-
- jest.spyOn(window.performance, 'getEntriesByName').mockImplementation(() => {
- return [{ duration }];
- });
-
- createComponentWithApollo({
- provide: {
- metricsPath,
- },
- data: {
- currentViewType: LAYER_VIEW,
- },
- });
- await waitForPromises();
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('calls reportPerformance with expected arguments', () => {
- expect(markAndMeasure).toHaveBeenCalled();
- expect(reportPerformance).toHaveBeenCalled();
- expect(reportPerformance).toHaveBeenCalledWith(metricsPath, metricsData);
- expect(reportToSentry).not.toHaveBeenCalled();
- });
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph/graph_view_selector_spec.js b/spec/frontend/pipelines/graph/graph_view_selector_spec.js
deleted file mode 100644
index 65ae9d19978..00000000000
--- a/spec/frontend/pipelines/graph/graph_view_selector_spec.js
+++ /dev/null
@@ -1,217 +0,0 @@
-import { GlAlert, GlButton, GlButtonGroup, GlLoadingIcon } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
-import { LAYER_VIEW, STAGE_VIEW } from '~/pipelines/components/graph/constants';
-import GraphViewSelector from '~/pipelines/components/graph/graph_view_selector.vue';
-
-describe('the graph view selector component', () => {
- let wrapper;
-
- const findDependenciesToggle = () => wrapper.find('[data-testid="show-links-toggle"]');
- const findViewTypeSelector = () => wrapper.findComponent(GlButtonGroup);
- const findStageViewButton = () => findViewTypeSelector().findAllComponents(GlButton).at(0);
- const findLayerViewButton = () => findViewTypeSelector().findAllComponents(GlButton).at(1);
- const findSwitcherLoader = () => wrapper.find('[data-testid="switcher-loading-state"]');
- const findToggleLoader = () => findDependenciesToggle().findComponent(GlLoadingIcon);
- const findHoverTip = () => wrapper.findComponent(GlAlert);
-
- const defaultProps = {
- showLinks: false,
- tipPreviouslyDismissed: false,
- type: STAGE_VIEW,
- };
-
- const defaultData = {
- hoverTipDismissed: false,
- isToggleLoading: false,
- isSwitcherLoading: false,
- showLinksActive: false,
- };
-
- const createComponent = ({ data = {}, mountFn = shallowMount, props = {} } = {}) => {
- wrapper = mountFn(GraphViewSelector, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- data() {
- return {
- ...defaultData,
- ...data,
- };
- },
- });
- };
-
- describe('when showing stage view', () => {
- beforeEach(() => {
- createComponent({ mountFn: mount });
- });
-
- it('shows the Stage view button as selected', () => {
- expect(findStageViewButton().classes('selected')).toBe(true);
- });
-
- it('shows the Job dependencies view button not selected', () => {
- expect(findLayerViewButton().exists()).toBe(true);
- expect(findLayerViewButton().classes('selected')).toBe(false);
- });
-
- it('does not show the Job dependencies (links) toggle', () => {
- expect(findDependenciesToggle().exists()).toBe(false);
- });
- });
-
- describe('when showing Job dependencies view', () => {
- beforeEach(() => {
- createComponent({
- mountFn: mount,
- props: {
- type: LAYER_VIEW,
- },
- });
- });
-
- it('shows the Job dependencies view as selected', () => {
- expect(findLayerViewButton().classes('selected')).toBe(true);
- });
-
- it('shows the Stage button as not selected', () => {
- expect(findStageViewButton().exists()).toBe(true);
- expect(findStageViewButton().classes('selected')).toBe(false);
- });
-
- it('shows the Job dependencies (links) toggle', () => {
- expect(findDependenciesToggle().exists()).toBe(true);
- });
- });
-
- describe('events', () => {
- beforeEach(() => {
- createComponent({
- mountFn: mount,
- props: {
- type: LAYER_VIEW,
- },
- });
- });
-
- it('shows loading state and emits updateViewType when view type toggled', async () => {
- expect(wrapper.emitted().updateViewType).toBeUndefined();
- expect(findSwitcherLoader().exists()).toBe(false);
-
- await findStageViewButton().trigger('click');
- /*
- Loading happens before the event is emitted or timers are run.
- Then we run the timer because the event is emitted in setInterval
- which is what gives the loader a chace to show up.
- */
- expect(findSwitcherLoader().exists()).toBe(true);
- jest.runOnlyPendingTimers();
-
- expect(wrapper.emitted().updateViewType).toHaveLength(1);
- expect(wrapper.emitted().updateViewType).toEqual([[STAGE_VIEW]]);
- });
-
- it('shows loading state and emits updateShowLinks when show links toggle is clicked', async () => {
- expect(wrapper.emitted().updateShowLinksState).toBeUndefined();
- expect(findToggleLoader().exists()).toBe(false);
-
- await findDependenciesToggle().vm.$emit('change', true);
- /*
- Loading happens before the event is emitted or timers are run.
- Then we run the timer because the event is emitted in setInterval
- which is what gives the loader a chace to show up.
- */
- expect(findToggleLoader().exists()).toBe(true);
- jest.runOnlyPendingTimers();
-
- expect(wrapper.emitted().updateShowLinksState).toHaveLength(1);
- expect(wrapper.emitted().updateShowLinksState).toEqual([[true]]);
- });
-
- it('does not emit an event if the click occurs on the currently selected view button', async () => {
- expect(wrapper.emitted().updateShowLinksState).toBeUndefined();
-
- await findLayerViewButton().trigger('click');
-
- expect(wrapper.emitted().updateShowLinksState).toBeUndefined();
- });
- });
-
- describe('hover tip callout', () => {
- describe('when links are live and it has not been previously dismissed', () => {
- beforeEach(() => {
- createComponent({
- props: {
- showLinks: true,
- type: LAYER_VIEW,
- },
- data: {
- showLinksActive: true,
- },
- mountFn: mount,
- });
- });
-
- it('is displayed', () => {
- expect(findHoverTip().exists()).toBe(true);
- expect(findHoverTip().text()).toBe(wrapper.vm.$options.i18n.hoverTipText);
- });
-
- it('emits dismissHoverTip event when the tip is dismissed', async () => {
- expect(wrapper.emitted().dismissHoverTip).toBeUndefined();
- await findHoverTip().find('button').trigger('click');
- expect(wrapper.emitted().dismissHoverTip).toHaveLength(1);
- });
-
- it('is displayed at first then hidden on swith to STAGE_VIEW then displayed on switch to LAYER_VIEW', async () => {
- expect(findHoverTip().exists()).toBe(true);
- expect(findHoverTip().text()).toBe(wrapper.vm.$options.i18n.hoverTipText);
-
- await findStageViewButton().trigger('click');
- expect(findHoverTip().exists()).toBe(false);
-
- await findLayerViewButton().trigger('click');
- expect(findHoverTip().exists()).toBe(true);
- expect(findHoverTip().text()).toBe(wrapper.vm.$options.i18n.hoverTipText);
- });
- });
-
- describe('when links are live and it has been previously dismissed', () => {
- beforeEach(() => {
- createComponent({
- props: {
- showLinks: true,
- tipPreviouslyDismissed: true,
- type: LAYER_VIEW,
- },
- data: {
- showLinksActive: true,
- },
- });
- });
-
- it('is not displayed', () => {
- expect(findHoverTip().exists()).toBe(false);
- });
- });
-
- describe('when links are not live', () => {
- beforeEach(() => {
- createComponent({
- props: {
- showLinks: true,
- type: LAYER_VIEW,
- },
- data: {
- showLinksActive: false,
- },
- });
- });
-
- it('is not displayed', () => {
- expect(findHoverTip().exists()).toBe(false);
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph/job_group_dropdown_spec.js b/spec/frontend/pipelines/graph/job_group_dropdown_spec.js
deleted file mode 100644
index 1419a7b9982..00000000000
--- a/spec/frontend/pipelines/graph/job_group_dropdown_spec.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import { shallowMount, mount } from '@vue/test-utils';
-import JobGroupDropdown from '~/pipelines/components/graph/job_group_dropdown.vue';
-
-describe('job group dropdown component', () => {
- const group = {
- jobs: [
- {
- id: 4256,
- name: '<img src=x onerror=alert(document.domain)>',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- tooltip: 'passed',
- group: 'success',
- details_path: '/root/ci-mock/builds/4256',
- has_details: true,
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/root/ci-mock/builds/4256/retry',
- method: 'post',
- },
- },
- },
- {
- id: 4299,
- name: 'test',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- tooltip: 'passed',
- group: 'success',
- details_path: '/root/ci-mock/builds/4299',
- has_details: true,
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/root/ci-mock/builds/4299/retry',
- method: 'post',
- },
- },
- },
- ],
- name: 'rspec:linux',
- size: 2,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- tooltip: 'passed',
- group: 'success',
- details_path: '/root/ci-mock/builds/4256',
- has_details: true,
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/root/ci-mock/builds/4256/retry',
- method: 'post',
- },
- },
- };
-
- let wrapper;
- const findButton = () => wrapper.find('button');
-
- const createComponent = ({ mountFn = shallowMount }) => {
- wrapper = mountFn(JobGroupDropdown, { propsData: { group } });
- };
-
- beforeEach(() => {
- createComponent({ mountFn: mount });
- });
-
- it('renders button with group name and size', () => {
- expect(findButton().text()).toContain(group.name);
- expect(findButton().text()).toContain(group.size.toString());
- });
-
- it('renders dropdown with jobs', () => {
- expect(wrapper.findAll('.scrollable-menu>ul>li').length).toBe(group.jobs.length);
- });
-});
diff --git a/spec/frontend/pipelines/graph/job_item_spec.js b/spec/frontend/pipelines/graph/job_item_spec.js
deleted file mode 100644
index 8a8b0e9aa63..00000000000
--- a/spec/frontend/pipelines/graph/job_item_spec.js
+++ /dev/null
@@ -1,492 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import Vue, { nextTick } from 'vue';
-import { GlBadge, GlModal, GlToast } from '@gitlab/ui';
-import JobItem from '~/pipelines/components/graph/job_item.vue';
-import axios from '~/lib/utils/axios_utils';
-import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-import ActionComponent from '~/pipelines/components/jobs_shared/action_component.vue';
-
-import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import {
- delayedJob,
- mockJob,
- mockJobWithoutDetails,
- mockJobWithUnauthorizedAction,
- mockFailedJob,
- triggerJob,
- triggerJobWithRetryAction,
-} from './mock_data';
-
-describe('pipeline graph job item', () => {
- useLocalStorageSpy();
- Vue.use(GlToast);
-
- let wrapper;
- let mockAxios;
-
- const findJobWithoutLink = () => wrapper.findByTestId('job-without-link');
- const findJobWithLink = () => wrapper.findByTestId('job-with-link');
- const findActionVueComponent = () => wrapper.findComponent(ActionComponent);
- const findActionComponent = () => wrapper.findByTestId('ci-action-component');
- const findBadge = () => wrapper.findComponent(GlBadge);
- const findJobLink = () => wrapper.findByTestId('job-with-link');
- const findModal = () => wrapper.findComponent(GlModal);
-
- const clickOnModalPrimaryBtn = () => findModal().vm.$emit('primary');
- const clickOnModalCancelBtn = () => findModal().vm.$emit('hide');
- const clickOnModalCloseBtn = () => findModal().vm.$emit('close');
-
- const myCustomClass1 = 'my-class-1';
- const myCustomClass2 = 'my-class-2';
-
- const defaultProps = {
- job: mockJob,
- };
-
- const createWrapper = ({ props, data, mountFn = mountExtended, mocks = {} } = {}) => {
- wrapper = mountFn(JobItem, {
- data() {
- return {
- ...data,
- };
- },
- propsData: {
- ...defaultProps,
- ...props,
- },
- mocks: {
- ...mocks,
- },
- });
- };
-
- const triggerActiveClass = 'gl-shadow-x0-y0-b3-s1-blue-500';
-
- beforeEach(() => {
- mockAxios = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mockAxios.restore();
- });
-
- describe('name with link', () => {
- it('should render the job name and status with a link', async () => {
- createWrapper();
-
- await nextTick();
- const link = findJobLink();
-
- expect(link.attributes('href')).toBe(mockJob.status.detailsPath);
-
- expect(link.attributes('title')).toBe(`${mockJob.name} - ${mockJob.status.label}`);
-
- expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
-
- expect(wrapper.text()).toBe(mockJob.name);
- });
- });
-
- describe('name without link', () => {
- beforeEach(() => {
- createWrapper({
- props: {
- job: mockJobWithoutDetails,
- cssClassJobName: 'css-class-job-name',
- jobHovered: 'test',
- },
- });
- });
-
- it('should render status and name', () => {
- expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
- expect(findJobLink().exists()).toBe(false);
-
- expect(wrapper.text()).toBe(mockJobWithoutDetails.name);
- });
-
- it('should apply hover class and provided class name', () => {
- expect(findJobWithoutLink().classes()).toContain('css-class-job-name');
- });
- });
-
- describe('action icon', () => {
- it('should render the action icon', () => {
- createWrapper();
-
- const actionComponent = findActionComponent();
-
- expect(actionComponent.exists()).toBe(true);
- expect(actionComponent.props('actionIcon')).toBe('retry');
- expect(actionComponent.attributes('disabled')).toBeUndefined();
- });
-
- it('should render disabled action icon when user cannot run the action', () => {
- createWrapper({
- props: {
- job: mockJobWithUnauthorizedAction,
- },
- });
-
- const actionComponent = findActionComponent();
-
- expect(actionComponent.exists()).toBe(true);
- expect(actionComponent.props('actionIcon')).toBe('stop');
- expect(actionComponent.attributes('disabled')).toBeDefined();
- });
-
- it('action icon tooltip text when job has passed but can be ran again', () => {
- createWrapper({ props: { job: mockJob } });
-
- expect(findActionComponent().props('tooltipText')).toBe('Run again');
- });
-
- it('action icon tooltip text when job has failed and can be retried', () => {
- createWrapper({ props: { job: mockFailedJob } });
-
- expect(findActionComponent().props('tooltipText')).toBe('Retry');
- });
- });
-
- describe('job style', () => {
- beforeEach(() => {
- createWrapper({
- props: {
- job: mockJob,
- cssClassJobName: 'css-class-job-name',
- },
- });
- });
-
- it('should render provided class name', () => {
- expect(findJobLink().classes()).toContain('css-class-job-name');
- });
-
- it('does not show a badge on the job item', () => {
- expect(findBadge().exists()).toBe(false);
- });
-
- it('does not apply the trigger job class', () => {
- expect(findJobWithLink().classes()).not.toContain('gl-rounded-lg');
- });
- });
-
- describe('status label', () => {
- it('should not render status label when it is not provided', () => {
- createWrapper({
- props: {
- job: {
- id: 4258,
- name: 'test',
- status: {
- icon: 'status_success',
- },
- },
- },
- });
-
- expect(findJobWithoutLink().attributes('title')).toBe('test');
- });
-
- it('should not render status label when it is provided', () => {
- createWrapper({
- props: {
- job: {
- id: 4259,
- name: 'test',
- status: {
- icon: 'status_success',
- label: 'success',
- tooltip: 'success',
- },
- },
- },
- });
-
- expect(findJobWithoutLink().attributes('title')).toBe('test - success');
- });
- });
-
- describe('for delayed job', () => {
- it('displays remaining time in tooltip', () => {
- createWrapper({
- props: {
- job: delayedJob,
- },
- });
-
- expect(findJobWithLink().attributes('title')).toBe(
- `delayed job - delayed manual action (00:00:00)`,
- );
- });
- });
-
- describe('trigger job', () => {
- describe('card', () => {
- beforeEach(() => {
- createWrapper({
- props: {
- job: triggerJob,
- },
- });
- });
-
- it('shows a badge on the job item', () => {
- expect(findBadge().exists()).toBe(true);
- expect(findBadge().text()).toBe('Trigger job');
- });
-
- it('applies a rounded corner style instead of the usual pill shape', () => {
- expect(findJobWithoutLink().classes()).toContain('gl-rounded-lg');
- });
- });
-
- describe('when retrying', () => {
- const mockToastShow = jest.fn();
-
- beforeEach(async () => {
- createWrapper({
- mountFn: shallowMountExtended,
- props: {
- skipRetryModal: true,
- job: triggerJobWithRetryAction,
- },
- mocks: {
- $toast: {
- show: mockToastShow,
- },
- },
- });
-
- await findActionVueComponent().vm.$emit('pipelineActionRequestComplete');
- await nextTick();
- });
-
- it('shows a toast message that the downstream is being created', () => {
- expect(mockToastShow).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('highlighting', () => {
- it.each`
- job | jobName | expanded | link
- ${mockJob} | ${mockJob.name} | ${true} | ${true}
- ${mockJobWithoutDetails} | ${mockJobWithoutDetails.name} | ${true} | ${false}
- `(
- `trigger job should stay highlighted when downstream is expanded`,
- ({ job, jobName, expanded, link }) => {
- createWrapper({
- props: {
- job,
- pipelineExpanded: { jobName, expanded },
- },
- });
- const findJobEl = link ? findJobWithLink : findJobWithoutLink;
-
- expect(findJobEl().classes()).toContain(triggerActiveClass);
- },
- );
-
- it.each`
- job | jobName | expanded | link
- ${mockJob} | ${mockJob.name} | ${false} | ${true}
- ${mockJobWithoutDetails} | ${mockJobWithoutDetails.name} | ${false} | ${false}
- `(
- `trigger job should not be highlighted when downstream is not expanded`,
- ({ job, jobName, expanded, link }) => {
- createWrapper({
- props: {
- job,
- pipelineExpanded: { jobName, expanded },
- },
- });
- const findJobEl = link ? findJobWithLink : findJobWithoutLink;
-
- expect(findJobEl().classes()).not.toContain(triggerActiveClass);
- },
- );
- });
- });
-
- describe('job classes', () => {
- it('job class is shown', () => {
- createWrapper({
- props: {
- job: mockJob,
- cssClassJobName: 'my-class',
- },
- });
-
- const jobLinkEl = findJobLink();
-
- expect(jobLinkEl.classes()).toContain('my-class');
-
- expect(jobLinkEl.classes()).not.toContain(triggerActiveClass);
- });
-
- it('job class is shown, along with hover', () => {
- createWrapper({
- props: {
- job: mockJob,
- cssClassJobName: 'my-class',
- sourceJobHovered: mockJob.name,
- },
- });
-
- const jobLinkEl = findJobLink();
-
- expect(jobLinkEl.classes()).toContain('my-class');
- expect(jobLinkEl.classes()).toContain(triggerActiveClass);
- });
-
- it('multiple job classes are shown', () => {
- createWrapper({
- props: {
- job: mockJob,
- cssClassJobName: [myCustomClass1, myCustomClass2],
- },
- });
-
- const jobLinkEl = findJobLink();
-
- expect(jobLinkEl.classes()).toContain(myCustomClass1);
- expect(jobLinkEl.classes()).toContain(myCustomClass2);
-
- expect(jobLinkEl.classes()).not.toContain(triggerActiveClass);
- });
-
- it('multiple job classes are shown conditionally', () => {
- createWrapper({
- props: {
- job: mockJob,
- cssClassJobName: { [myCustomClass1]: true, [myCustomClass2]: true },
- },
- });
-
- const jobLinkEl = findJobLink();
-
- expect(jobLinkEl.classes()).toContain(myCustomClass1);
- expect(jobLinkEl.classes()).toContain(myCustomClass2);
-
- expect(jobLinkEl.classes()).not.toContain(triggerActiveClass);
- });
-
- it('multiple job classes are shown, along with a hover', () => {
- createWrapper({
- props: {
- job: mockJob,
- cssClassJobName: [myCustomClass1, myCustomClass2],
- sourceJobHovered: mockJob.name,
- },
- });
-
- const jobLinkEl = findJobLink();
-
- expect(jobLinkEl.classes()).toContain(myCustomClass1);
- expect(jobLinkEl.classes()).toContain(myCustomClass2);
- expect(jobLinkEl.classes()).toContain(triggerActiveClass);
- });
- });
-
- describe('confirmation modal', () => {
- describe('when clicking on the action component', () => {
- it.each`
- skipRetryModal | exists | visibilityText
- ${false} | ${true} | ${'shows'}
- ${true} | ${false} | ${'hides'}
- `(
- '$visibilityText the modal when `skipRetryModal` is $skipRetryModal',
- async ({ exists, skipRetryModal }) => {
- createWrapper({
- props: {
- skipRetryModal,
- job: triggerJobWithRetryAction,
- },
- });
- await findActionComponent().trigger('click');
-
- expect(findModal().exists()).toBe(exists);
- },
- );
- });
-
- describe('when showing the modal', () => {
- it.each`
- buttonName | shouldTriggerActionClick | actionBtn
- ${'primary'} | ${true} | ${clickOnModalPrimaryBtn}
- ${'cancel'} | ${false} | ${clickOnModalCancelBtn}
- ${'close'} | ${false} | ${clickOnModalCloseBtn}
- `(
- 'clicking on $buttonName will pass down shouldTriggerActionClick as $shouldTriggerActionClick to the action component',
- async ({ shouldTriggerActionClick, actionBtn }) => {
- createWrapper({
- props: {
- skipRetryModal: false,
- job: triggerJobWithRetryAction,
- },
- });
- await findActionComponent().trigger('click');
-
- await actionBtn();
-
- expect(findActionComponent().props().shouldTriggerClick).toBe(shouldTriggerActionClick);
- },
- );
- });
-
- describe('when not checking the "do not show this again" checkbox', () => {
- it.each`
- actionName | actionBtn
- ${'closing'} | ${clickOnModalCloseBtn}
- ${'cancelling'} | ${clickOnModalCancelBtn}
- ${'confirming'} | ${clickOnModalPrimaryBtn}
- `(
- 'does not emit any event and will not modify localstorage on $actionName',
- async ({ actionBtn }) => {
- createWrapper({
- props: {
- skipRetryModal: false,
- job: triggerJobWithRetryAction,
- },
- });
- await findActionComponent().trigger('click');
- await actionBtn();
-
- expect(wrapper.emitted().setSkipRetryModal).toBeUndefined();
- expect(localStorage.setItem).not.toHaveBeenCalled();
- },
- );
- });
-
- describe('when checking the "do not show this again" checkbox', () => {
- it.each`
- actionName | actionBtn
- ${'closing'} | ${clickOnModalCloseBtn}
- ${'cancelling'} | ${clickOnModalCancelBtn}
- ${'confirming'} | ${clickOnModalPrimaryBtn}
- `(
- 'emits "setSkipRetryModal" and set local storage key on $actionName the modal',
- async ({ actionBtn }) => {
- // We are passing the checkbox as a slot to the GlModal.
- // The way GlModal is mounted, we can neither click on the box
- // or emit an event directly. We therefore set the data property
- // as it would be if the box was checked.
- createWrapper({
- data: {
- currentSkipModalValue: true,
- },
- props: {
- skipRetryModal: false,
- job: triggerJobWithRetryAction,
- },
- });
- await findActionComponent().trigger('click');
- await actionBtn();
-
- expect(wrapper.emitted().setSkipRetryModal).toHaveLength(1);
- expect(localStorage.setItem).toHaveBeenCalledWith('skip_retry_modal', 'true');
- },
- );
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph/job_name_component_spec.js b/spec/frontend/pipelines/graph/job_name_component_spec.js
deleted file mode 100644
index fca4c43d9fa..00000000000
--- a/spec/frontend/pipelines/graph/job_name_component_spec.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { mount } from '@vue/test-utils';
-import jobNameComponent from '~/pipelines/components/jobs_shared/job_name_component.vue';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-
-describe('job name component', () => {
- let wrapper;
-
- const propsData = {
- name: 'foo',
- status: {
- icon: 'status_success',
- group: 'success',
- },
- };
-
- beforeEach(() => {
- wrapper = mount(jobNameComponent, {
- propsData,
- });
- });
-
- it('should render the provided name', () => {
- expect(wrapper.text()).toBe(propsData.name);
- });
-
- it('should render an icon with the provided status', () => {
- expect(wrapper.findComponent(CiIcon).exists()).toBe(true);
- expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
- });
-});
diff --git a/spec/frontend/pipelines/graph/linked_pipeline_spec.js b/spec/frontend/pipelines/graph/linked_pipeline_spec.js
deleted file mode 100644
index 8dae2aac664..00000000000
--- a/spec/frontend/pipelines/graph/linked_pipeline_spec.js
+++ /dev/null
@@ -1,464 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { GlButton, GlLoadingIcon, GlTooltip } from '@gitlab/ui';
-import { createWrapper } from '@vue/test-utils';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
-import { ACTION_FAILURE, UPSTREAM, DOWNSTREAM } from '~/pipelines/components/graph/constants';
-import LinkedPipelineComponent from '~/pipelines/components/graph/linked_pipeline.vue';
-import CancelPipelineMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql';
-import RetryPipelineMutation from '~/pipelines/graphql/mutations/retry_pipeline.mutation.graphql';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import mockPipeline from './linked_pipelines_mock_data';
-
-describe('Linked pipeline', () => {
- let wrapper;
- let requestHandlers;
-
- const downstreamProps = {
- pipeline: {
- ...mockPipeline,
- multiproject: false,
- },
- columnTitle: 'Downstream',
- type: DOWNSTREAM,
- expanded: false,
- isLoading: false,
- };
-
- const upstreamProps = {
- ...downstreamProps,
- columnTitle: 'Upstream',
- type: UPSTREAM,
- };
-
- const findButton = () => wrapper.findComponent(GlButton);
- const findCancelButton = () => wrapper.findByLabelText('Cancel downstream pipeline');
- const findCardTooltip = () => wrapper.findComponent(GlTooltip);
- const findDownstreamPipelineTitle = () => wrapper.findByTestId('downstream-title');
- const findExpandButton = () => wrapper.findByTestId('expand-pipeline-button');
- const findLinkedPipeline = () => wrapper.findComponent({ ref: 'linkedPipeline' });
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findPipelineLabel = () => wrapper.findByTestId('downstream-pipeline-label');
- const findPipelineLink = () => wrapper.findByTestId('pipelineLink');
- const findRetryButton = () => wrapper.findByLabelText('Retry downstream pipeline');
-
- const defaultHandlers = {
- cancelPipeline: jest.fn().mockResolvedValue({ data: { pipelineCancel: { errors: [] } } }),
- retryPipeline: jest.fn().mockResolvedValue({ data: { pipelineRetry: { errors: [] } } }),
- };
-
- const createMockApolloProvider = (handlers) => {
- Vue.use(VueApollo);
-
- requestHandlers = handlers;
- return createMockApollo([
- [CancelPipelineMutation, requestHandlers.cancelPipeline],
- [RetryPipelineMutation, requestHandlers.retryPipeline],
- ]);
- };
-
- const createComponent = ({ propsData, handlers = defaultHandlers }) => {
- const mockApollo = createMockApolloProvider(handlers);
-
- wrapper = mountExtended(LinkedPipelineComponent, {
- propsData,
- apolloProvider: mockApollo,
- });
- };
-
- describe('rendered output', () => {
- const props = {
- pipeline: mockPipeline,
- columnTitle: 'Downstream',
- type: DOWNSTREAM,
- expanded: false,
- isLoading: false,
- };
-
- beforeEach(() => {
- createComponent({ propsData: props });
- });
-
- it('should render the project name', () => {
- expect(wrapper.text()).toContain(props.pipeline.project.name);
- });
-
- it('should render an svg within the status container', () => {
- const pipelineStatusElement = wrapper.findComponent(CiIcon);
-
- expect(pipelineStatusElement.find('svg').exists()).toBe(true);
- });
-
- it('should render the pipeline status icon svg', () => {
- expect(wrapper.find('.ci-status-icon-success svg').exists()).toBe(true);
- });
-
- it('should have a ci-status child component', () => {
- expect(wrapper.findComponent(CiIcon).exists()).toBe(true);
- });
-
- it('should render the pipeline id', () => {
- expect(wrapper.text()).toContain(`#${props.pipeline.id}`);
- });
-
- it('adds the card tooltip text to the DOM', () => {
- expect(findCardTooltip().exists()).toBe(true);
-
- expect(findCardTooltip().text()).toContain(mockPipeline.project.name);
- expect(findCardTooltip().text()).toContain(mockPipeline.status.label);
- expect(findCardTooltip().text()).toContain(mockPipeline.sourceJob.name);
- expect(findCardTooltip().text()).toContain(mockPipeline.id.toString());
- });
-
- it('should display multi-project label when pipeline project id is not the same as triggered pipeline project id', () => {
- expect(findPipelineLabel().text()).toBe('Multi-project');
- });
- });
-
- describe('upstream pipelines', () => {
- beforeEach(() => {
- createComponent({ propsData: upstreamProps });
- });
-
- it('should display parent label when pipeline project id is the same as triggered_by pipeline project id', () => {
- expect(findPipelineLabel().exists()).toBe(true);
- });
-
- it('upstream pipeline should contain the correct link', () => {
- expect(findPipelineLink().attributes('href')).toBe(upstreamProps.pipeline.path);
- });
-
- it('applies the reverse-row css class to the card', () => {
- expect(findLinkedPipeline().classes()).toContain('gl-flex-direction-row-reverse');
- expect(findLinkedPipeline().classes()).not.toContain('gl-flex-direction-row');
- });
- });
-
- describe('downstream pipelines', () => {
- describe('styling', () => {
- beforeEach(() => {
- createComponent({ propsData: downstreamProps });
- });
-
- it('parent/child label container should exist', () => {
- expect(findPipelineLabel().exists()).toBe(true);
- });
-
- it('should display child label when pipeline project id is the same as triggered pipeline project id', () => {
- expect(findPipelineLabel().exists()).toBe(true);
- });
-
- it('should have the name of the trigger job on the card when it is a child pipeline', () => {
- expect(findDownstreamPipelineTitle().text()).toBe(mockPipeline.sourceJob.name);
- });
-
- it('downstream pipeline should contain the correct link', () => {
- expect(findPipelineLink().attributes('href')).toBe(downstreamProps.pipeline.path);
- });
-
- it('applies the flex-row css class to the card', () => {
- expect(findLinkedPipeline().classes()).toContain('gl-flex-direction-row');
- expect(findLinkedPipeline().classes()).not.toContain('gl-flex-direction-row-reverse');
- });
- });
-
- describe('action button', () => {
- describe('with permissions', () => {
- describe('on an upstream', () => {
- describe('when retryable', () => {
- beforeEach(() => {
- const retryablePipeline = {
- ...upstreamProps,
- pipeline: { ...mockPipeline, retryable: true },
- };
-
- createComponent({ propsData: retryablePipeline });
- });
-
- it('does not show the retry or cancel button', () => {
- expect(findCancelButton().exists()).toBe(false);
- expect(findRetryButton().exists()).toBe(false);
- });
- });
- });
-
- describe('on a downstream', () => {
- const retryablePipeline = {
- ...downstreamProps,
- pipeline: { ...mockPipeline, retryable: true },
- };
-
- describe('when retryable', () => {
- beforeEach(() => {
- createComponent({ propsData: retryablePipeline });
- });
-
- it('shows only the retry button', () => {
- expect(findCancelButton().exists()).toBe(false);
- expect(findRetryButton().exists()).toBe(true);
- });
-
- it.each`
- findElement | name
- ${findRetryButton} | ${'retry button'}
- ${findExpandButton} | ${'expand button'}
- `('hides the card tooltip when $name is hovered', async ({ findElement }) => {
- expect(findCardTooltip().exists()).toBe(true);
-
- await findElement().trigger('mouseover');
-
- expect(findCardTooltip().exists()).toBe(false);
- });
-
- describe('and the retry button is clicked', () => {
- describe('on success', () => {
- beforeEach(async () => {
- await findRetryButton().trigger('click');
- });
-
- it('calls the retry mutation', () => {
- expect(requestHandlers.retryPipeline).toHaveBeenCalledTimes(1);
- expect(requestHandlers.retryPipeline).toHaveBeenCalledWith({
- id: 'gid://gitlab/Ci::Pipeline/195',
- });
- });
-
- it('emits the refreshPipelineGraph event', async () => {
- await waitForPromises();
- expect(wrapper.emitted('refreshPipelineGraph')).toHaveLength(1);
- });
- });
-
- describe('on failure', () => {
- beforeEach(async () => {
- createComponent({
- propsData: retryablePipeline,
- handlers: {
- retryPipeline: jest.fn().mockRejectedValue({ errors: [] }),
- cancelPipeline: jest.fn().mockRejectedValue({ errors: [] }),
- },
- });
-
- await findRetryButton().trigger('click');
- });
-
- it('emits an error event', async () => {
- await waitForPromises();
- expect(wrapper.emitted('error')).toEqual([[{ type: ACTION_FAILURE }]]);
- });
- });
- });
- });
-
- describe('when cancelable', () => {
- const cancelablePipeline = {
- ...downstreamProps,
- pipeline: { ...mockPipeline, cancelable: true },
- };
-
- beforeEach(() => {
- createComponent({ propsData: cancelablePipeline });
- });
-
- it('shows only the cancel button', () => {
- expect(findCancelButton().exists()).toBe(true);
- expect(findRetryButton().exists()).toBe(false);
- });
-
- it.each`
- findElement | name
- ${findCancelButton} | ${'cancel button'}
- ${findExpandButton} | ${'expand button'}
- `('hides the card tooltip when $name is hovered', async ({ findElement }) => {
- expect(findCardTooltip().exists()).toBe(true);
-
- await findElement().trigger('mouseover');
-
- expect(findCardTooltip().exists()).toBe(false);
- });
-
- describe('and the cancel button is clicked', () => {
- describe('on success', () => {
- beforeEach(async () => {
- await findCancelButton().trigger('click');
- });
-
- it('calls the cancel mutation', () => {
- expect(requestHandlers.cancelPipeline).toHaveBeenCalledTimes(1);
- expect(requestHandlers.cancelPipeline).toHaveBeenCalledWith({
- id: 'gid://gitlab/Ci::Pipeline/195',
- });
- });
- it('emits the refreshPipelineGraph event', async () => {
- await waitForPromises();
- expect(wrapper.emitted('refreshPipelineGraph')).toHaveLength(1);
- });
- });
-
- describe('on failure', () => {
- beforeEach(async () => {
- createComponent({
- propsData: cancelablePipeline,
- handlers: {
- retryPipeline: jest.fn().mockRejectedValue({ errors: [] }),
- cancelPipeline: jest.fn().mockRejectedValue({ errors: [] }),
- },
- });
-
- await findCancelButton().trigger('click');
- });
-
- it('emits an error event', async () => {
- await waitForPromises();
- expect(wrapper.emitted('error')).toEqual([[{ type: ACTION_FAILURE }]]);
- });
- });
- });
- });
-
- describe('when both cancellable and retryable', () => {
- beforeEach(() => {
- const pipelineWithTwoActions = {
- ...downstreamProps,
- pipeline: { ...mockPipeline, cancelable: true, retryable: true },
- };
-
- createComponent({ propsData: pipelineWithTwoActions });
- });
-
- it('only shows the cancel button', () => {
- expect(findRetryButton().exists()).toBe(false);
- expect(findCancelButton().exists()).toBe(true);
- });
- });
- });
- });
-
- describe('without permissions', () => {
- beforeEach(() => {
- const pipelineWithTwoActions = {
- ...downstreamProps,
- pipeline: {
- ...mockPipeline,
- cancelable: true,
- retryable: true,
- userPermissions: { updatePipeline: false },
- },
- };
-
- createComponent({ propsData: pipelineWithTwoActions });
- });
-
- it('does not show any action button', () => {
- expect(findRetryButton().exists()).toBe(false);
- expect(findCancelButton().exists()).toBe(false);
- });
- });
- });
- });
-
- describe('expand button', () => {
- it.each`
- pipelineType | chevronPosition | buttonBorderClasses | expanded
- ${downstreamProps} | ${'chevron-lg-right'} | ${'gl-border-l-0!'} | ${false}
- ${downstreamProps} | ${'chevron-lg-left'} | ${'gl-border-l-0!'} | ${true}
- ${upstreamProps} | ${'chevron-lg-left'} | ${'gl-border-r-0!'} | ${false}
- ${upstreamProps} | ${'chevron-lg-right'} | ${'gl-border-r-0!'} | ${true}
- `(
- '$pipelineType.columnTitle pipeline button icon should be $chevronPosition with $buttonBorderClasses if expanded state is $expanded',
- ({ pipelineType, chevronPosition, buttonBorderClasses, expanded }) => {
- createComponent({ propsData: { ...pipelineType, expanded } });
- expect(findExpandButton().props('icon')).toBe(chevronPosition);
- expect(findExpandButton().classes()).toContain(buttonBorderClasses);
- },
- );
-
- describe('shadow border', () => {
- beforeEach(() => {
- createComponent({ propsData: downstreamProps });
- });
-
- it.each`
- activateEventName | deactivateEventName
- ${'mouseover'} | ${'mouseout'}
- ${'focus'} | ${'blur'}
- `(
- 'applies the class on $activateEventName and removes it on $deactivateEventName',
- async ({ activateEventName, deactivateEventName }) => {
- const shadowClass = 'gl-shadow-none!';
-
- expect(findExpandButton().classes()).toContain(shadowClass);
-
- await findExpandButton().vm.$emit(activateEventName);
- expect(findExpandButton().classes()).not.toContain(shadowClass);
-
- await findExpandButton().vm.$emit(deactivateEventName);
- expect(findExpandButton().classes()).toContain(shadowClass);
- },
- );
- });
- });
-
- describe('when isLoading is true', () => {
- const props = {
- pipeline: mockPipeline,
- columnTitle: 'Downstream',
- type: DOWNSTREAM,
- expanded: false,
- isLoading: true,
- };
-
- beforeEach(() => {
- createComponent({ propsData: props });
- });
-
- it('loading icon is visible', () => {
- expect(findLoadingIcon().exists()).toBe(true);
- });
- });
-
- describe('on click/hover', () => {
- const props = {
- pipeline: mockPipeline,
- columnTitle: 'Downstream',
- type: DOWNSTREAM,
- expanded: false,
- isLoading: false,
- };
-
- beforeEach(() => {
- createComponent({ propsData: props });
- });
-
- it('emits `pipelineClicked` event', () => {
- findButton().trigger('click');
-
- expect(wrapper.emitted('pipelineClicked')).toHaveLength(1);
- });
-
- it(`should emit ${BV_HIDE_TOOLTIP} to close the tooltip`, async () => {
- const root = createWrapper(wrapper.vm.$root);
- await findButton().vm.$emit('click');
-
- expect(root.emitted(BV_HIDE_TOOLTIP)).toHaveLength(1);
- });
-
- it('should emit downstreamHovered with job name on mouseover', () => {
- findLinkedPipeline().trigger('mouseover');
- expect(wrapper.emitted('downstreamHovered')).toStrictEqual([['test_c']]);
- });
-
- it('should emit downstreamHovered with empty string on mouseleave', () => {
- findLinkedPipeline().trigger('mouseleave');
- expect(wrapper.emitted('downstreamHovered')).toStrictEqual([['']]);
- });
-
- it('should emit pipelineExpanded with job name and expanded state on click', () => {
- findExpandButton().trigger('click');
- expect(wrapper.emitted('pipelineExpandToggle')).toStrictEqual([['test_c', true]]);
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js b/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
deleted file mode 100644
index bcea140f2dd..00000000000
--- a/spec/frontend/pipelines/graph/linked_pipelines_column_spec.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import { mount, shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
-import {
- DOWNSTREAM,
- UPSTREAM,
- LAYER_VIEW,
- STAGE_VIEW,
-} from '~/pipelines/components/graph/constants';
-import PipelineGraph from '~/pipelines/components/graph/graph_component.vue';
-import LinkedPipeline from '~/pipelines/components/graph/linked_pipeline.vue';
-import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue';
-import * as parsingUtils from '~/pipelines/components/parsing_utils';
-import { LOAD_FAILURE } from '~/pipelines/constants';
-
-import { pipelineWithUpstreamDownstream, wrappedPipelineReturn } from './mock_data';
-
-const processedPipeline = pipelineWithUpstreamDownstream(mockPipelineResponse);
-
-describe('Linked Pipelines Column', () => {
- const defaultProps = {
- columnTitle: 'Downstream',
- linkedPipelines: processedPipeline.downstream,
- showLinks: false,
- type: DOWNSTREAM,
- viewType: STAGE_VIEW,
- configPaths: {
- metricsPath: '',
- graphqlResourceEtag: 'this/is/a/path',
- },
- };
-
- let wrapper;
- const findLinkedColumnTitle = () => wrapper.find('[data-testid="linked-column-title"]');
- const findLinkedPipelineElements = () => wrapper.findAllComponents(LinkedPipeline);
- const findPipelineGraph = () => wrapper.findComponent(PipelineGraph);
- const findExpandButton = () => wrapper.find('[data-testid="expand-pipeline-button"]');
-
- Vue.use(VueApollo);
-
- const createComponent = ({ apolloProvider, mountFn = shallowMount, props = {} } = {}) => {
- wrapper = mountFn(LinkedPipelinesColumn, {
- apolloProvider,
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- const createComponentWithApollo = ({
- mountFn = shallowMount,
- getPipelineDetailsHandler = jest.fn().mockResolvedValue(wrappedPipelineReturn),
- props = {},
- } = {}) => {
- const requestHandlers = [[getPipelineDetails, getPipelineDetailsHandler]];
-
- const apolloProvider = createMockApollo(requestHandlers);
- createComponent({ apolloProvider, mountFn, props });
- };
-
- describe('it renders correctly', () => {
- beforeEach(() => {
- createComponentWithApollo();
- });
-
- it('renders the pipeline title', () => {
- expect(findLinkedColumnTitle().text()).toBe(defaultProps.columnTitle);
- });
-
- it('renders the correct number of linked pipelines', () => {
- expect(findLinkedPipelineElements()).toHaveLength(defaultProps.linkedPipelines.length);
- });
- });
-
- describe('click action', () => {
- const clickExpandButton = async () => {
- await findExpandButton().trigger('click');
- await waitForPromises();
- };
-
- describe('layer type rendering', () => {
- let layersFn;
-
- beforeEach(() => {
- layersFn = jest.spyOn(parsingUtils, 'listByLayers');
- createComponentWithApollo({ mountFn: mount });
- });
-
- it('calls listByLayers only once no matter how many times view is switched', async () => {
- expect(layersFn).not.toHaveBeenCalled();
- await clickExpandButton();
- await wrapper.setProps({ viewType: LAYER_VIEW });
- await nextTick();
- expect(layersFn).toHaveBeenCalledTimes(1);
- await wrapper.setProps({ viewType: STAGE_VIEW });
- await wrapper.setProps({ viewType: LAYER_VIEW });
- await wrapper.setProps({ viewType: STAGE_VIEW });
- expect(layersFn).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('when graph does not use needs', () => {
- beforeEach(() => {
- const nonNeedsResponse = { ...wrappedPipelineReturn };
- nonNeedsResponse.data.project.pipeline.usesNeeds = false;
-
- createComponentWithApollo({
- props: {
- viewType: LAYER_VIEW,
- },
- getPipelineDetailsHandler: jest.fn().mockResolvedValue(nonNeedsResponse),
- mountFn: mount,
- });
- });
-
- it('shows the stage view, even when the main graph view type is layers', async () => {
- await clickExpandButton();
- expect(findPipelineGraph().props('viewType')).toBe(STAGE_VIEW);
- });
- });
-
- describe('downstream', () => {
- describe('when successful', () => {
- beforeEach(() => {
- createComponentWithApollo({ mountFn: mount });
- });
-
- it('toggles the pipeline visibility', async () => {
- expect(findPipelineGraph().exists()).toBe(false);
- await clickExpandButton();
- expect(findPipelineGraph().exists()).toBe(true);
- await clickExpandButton();
- expect(findPipelineGraph().exists()).toBe(false);
- });
- });
-
- describe('on error', () => {
- beforeEach(() => {
- createComponentWithApollo({
- mountFn: mount,
- getPipelineDetailsHandler: jest.fn().mockRejectedValue(new Error('GraphQL error')),
- });
- });
-
- it('emits the error', async () => {
- await clickExpandButton();
- expect(wrapper.emitted().error).toEqual([[{ type: LOAD_FAILURE, skipSentry: true }]]);
- });
-
- it('does not show the pipeline', async () => {
- expect(findPipelineGraph().exists()).toBe(false);
- await clickExpandButton();
- expect(findPipelineGraph().exists()).toBe(false);
- });
- });
- });
-
- describe('upstream', () => {
- const upstreamProps = {
- columnTitle: 'Upstream',
- /*
- Because the IDs need to match to work, rather
- than make new mock data, we are representing
- the upstream pipeline with the downstream data.
- */
- linkedPipelines: processedPipeline.downstream,
- type: UPSTREAM,
- };
-
- describe('when successful', () => {
- beforeEach(() => {
- createComponentWithApollo({
- mountFn: mount,
- props: upstreamProps,
- });
- });
-
- it('toggles the pipeline visibility', async () => {
- expect(findPipelineGraph().exists()).toBe(false);
- await clickExpandButton();
- expect(findPipelineGraph().exists()).toBe(true);
- await clickExpandButton();
- expect(findPipelineGraph().exists()).toBe(false);
- });
- });
-
- describe('on error', () => {
- beforeEach(() => {
- createComponentWithApollo({
- mountFn: mount,
- getPipelineDetailsHandler: jest.fn().mockRejectedValue(new Error('GraphQL error')),
- props: upstreamProps,
- });
- });
-
- it('emits the error', async () => {
- await clickExpandButton();
- expect(wrapper.emitted().error).toEqual([[{ type: LOAD_FAILURE, skipSentry: true }]]);
- });
-
- it('does not show the pipeline', async () => {
- expect(findPipelineGraph().exists()).toBe(false);
- await clickExpandButton();
- expect(findPipelineGraph().exists()).toBe(false);
- });
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph/mock_data.js b/spec/frontend/pipelines/graph/mock_data.js
deleted file mode 100644
index 8d06d6931ed..00000000000
--- a/spec/frontend/pipelines/graph/mock_data.js
+++ /dev/null
@@ -1,387 +0,0 @@
-import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
-import { unwrapPipelineData } from '~/pipelines/components/graph/utils';
-import {
- BUILD_KIND,
- BRIDGE_KIND,
- RETRY_ACTION_TITLE,
-} from '~/pipelines/components/graph/constants';
-
-// We mock this instead of using fixtures for performance reason.
-const mockPipelineResponseCopy = JSON.parse(JSON.stringify(mockPipelineResponse));
-const groups = new Array(100).fill({
- ...mockPipelineResponse.data.project.pipeline.stages.nodes[0].groups.nodes[0],
-});
-mockPipelineResponseCopy.data.project.pipeline.stages.nodes[0].groups.nodes = groups;
-export const mockPipelineResponseWithTooManyJobs = mockPipelineResponseCopy;
-
-export const downstream = {
- nodes: [
- {
- id: 175,
- iid: '31',
- path: '/root/elemenohpee/-/pipelines/175',
- retryable: true,
- cancelable: false,
- userPermissions: {
- updatePipeline: true,
- },
- status: {
- id: '70',
- group: 'success',
- label: 'passed',
- icon: 'status_success',
- __typename: 'DetailedStatus',
- },
- sourceJob: {
- name: 'test_c',
- id: '71',
- retried: false,
- __typename: 'CiJob',
- },
- project: {
- id: 'gid://gitlab/Project/25',
- name: 'elemenohpee',
- fullPath: 'root/elemenohpee',
- __typename: 'Project',
- },
- __typename: 'Pipeline',
- multiproject: true,
- },
- {
- id: 181,
- iid: '27',
- path: '/root/abcd-dag/-/pipelines/181',
- retryable: true,
- cancelable: false,
- userPermissions: {
- updatePipeline: true,
- },
- status: {
- id: '72',
- group: 'success',
- label: 'passed',
- icon: 'status_success',
- __typename: 'DetailedStatus',
- },
- sourceJob: {
- id: '73',
- name: 'test_d',
- retried: true,
- __typename: 'CiJob',
- },
- project: {
- id: 'gid://gitlab/Project/23',
- name: 'abcd-dag',
- fullPath: 'root/abcd-dag',
- __typename: 'Project',
- },
- __typename: 'Pipeline',
- multiproject: false,
- },
- ],
-};
-
-export const upstream = {
- id: 161,
- iid: '24',
- path: '/root/abcd-dag/-/pipelines/161',
- retryable: true,
- cancelable: false,
- userPermissions: {
- updatePipeline: true,
- },
- status: {
- id: '74',
- group: 'success',
- label: 'passed',
- icon: 'status_success',
- __typename: 'DetailedStatus',
- },
- sourceJob: null,
- project: {
- id: 'gid://gitlab/Project/23',
- name: 'abcd-dag',
- fullPath: 'root/abcd-dag',
- __typename: 'Project',
- },
- __typename: 'Pipeline',
- multiproject: true,
-};
-
-export const wrappedPipelineReturn = {
- data: {
- project: {
- __typename: 'Project',
- id: '75',
- pipeline: {
- __typename: 'Pipeline',
- id: 'gid://gitlab/Ci::Pipeline/175',
- iid: '38',
- complete: true,
- usesNeeds: true,
- userPermissions: {
- __typename: 'PipelinePermissions',
- updatePipeline: true,
- },
- downstream: {
- retryable: true,
- cancelable: false,
- userPermissions: {
- updatePipeline: true,
- },
- __typename: 'PipelineConnection',
- nodes: [],
- },
- upstream: {
- id: 'gid://gitlab/Ci::Pipeline/174',
- iid: '37',
- path: '/root/elemenohpee/-/pipelines/174',
- retryable: true,
- cancelable: false,
- userPermissions: {
- updatePipeline: true,
- },
- __typename: 'Pipeline',
- status: {
- __typename: 'DetailedStatus',
- id: '77',
- group: 'success',
- label: 'passed',
- icon: 'status_success',
- },
- sourceJob: {
- name: 'test_c',
- id: '78',
- retried: false,
- __typename: 'CiJob',
- },
- project: {
- id: 'gid://gitlab/Project/25',
- name: 'elemenohpee',
- fullPath: 'root/elemenohpee',
- __typename: 'Project',
- },
- },
- stages: {
- __typename: 'CiStageConnection',
- nodes: [
- {
- name: 'build',
- __typename: 'CiStage',
- id: '79',
- status: {
- action: null,
- id: '80',
- __typename: 'DetailedStatus',
- },
- groups: {
- __typename: 'CiGroupConnection',
- nodes: [
- {
- __typename: 'CiGroup',
- id: '81',
- status: {
- __typename: 'DetailedStatus',
- id: '82',
- label: 'passed',
- group: 'success',
- icon: 'status_success',
- },
- name: 'build_n',
- size: 1,
- jobs: {
- __typename: 'CiJobConnection',
- nodes: [
- {
- __typename: 'CiJob',
- id: '83',
- kind: BUILD_KIND,
- name: 'build_n',
- scheduledAt: null,
- needs: {
- __typename: 'CiBuildNeedConnection',
- nodes: [],
- },
- previousStageJobsOrNeeds: {
- __typename: 'CiJobConnection',
- nodes: [],
- },
- status: {
- __typename: 'DetailedStatus',
- id: '84',
- icon: 'status_success',
- tooltip: 'passed',
- label: 'passed',
- hasDetails: true,
- detailsPath: '/root/elemenohpee/-/jobs/1662',
- group: 'success',
- action: {
- __typename: 'StatusAction',
- id: '85',
- buttonTitle: 'Retry this job',
- icon: 'retry',
- path: '/root/elemenohpee/-/jobs/1662/retry',
- title: 'Retry',
- },
- },
- },
- ],
- },
- },
- ],
- },
- },
- ],
- },
- },
- },
- },
-};
-
-export const generateResponse = (raw, mockPath) => unwrapPipelineData(mockPath, raw.data);
-
-export const pipelineWithUpstreamDownstream = (base) => {
- const pip = { ...base };
- pip.data.project.pipeline.downstream = downstream;
- pip.data.project.pipeline.upstream = upstream;
-
- return generateResponse(pip, 'root/abcd-dag');
-};
-
-export const mapCallouts = (callouts) =>
- callouts.map((callout) => {
- return { featureName: callout, __typename: 'UserCallout' };
- });
-
-export const mockCalloutsResponse = (mappedCallouts) => ({
- data: {
- currentUser: {
- id: 45,
- __typename: 'User',
- callouts: {
- id: 5,
- __typename: 'UserCalloutConnection',
- nodes: mappedCallouts,
- },
- },
- },
-});
-
-export const delayedJob = {
- __typename: 'CiJob',
- kind: BUILD_KIND,
- name: 'delayed job',
- scheduledAt: '2015-07-03T10:01:00.000Z',
- needs: [],
- status: {
- __typename: 'DetailedStatus',
- icon: 'status_scheduled',
- tooltip: 'delayed manual action (%{remainingTime})',
- hasDetails: true,
- detailsPath: '/root/kinder-pipe/-/jobs/5339',
- group: 'scheduled',
- action: {
- __typename: 'StatusAction',
- icon: 'time-out',
- title: 'Unschedule',
- path: '/frontend-fixtures/builds-project/-/jobs/142/unschedule',
- buttonTitle: 'Unschedule job',
- },
- },
-};
-
-export const mockJob = {
- id: 4256,
- name: 'test',
- kind: BUILD_KIND,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- tooltip: 'passed',
- group: 'success',
- detailsPath: '/root/ci-mock/builds/4256',
- hasDetails: true,
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/root/ci-mock/builds/4256/retry',
- method: 'post',
- },
- },
-};
-
-export const mockJobWithoutDetails = {
- id: 4257,
- name: 'job_without_details',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- detailsPath: '/root/ci-mock/builds/4257',
- hasDetails: false,
- },
-};
-
-export const mockJobWithUnauthorizedAction = {
- id: 4258,
- name: 'stop-environment',
- status: {
- icon: 'status_manual',
- label: 'manual stop action (not allowed)',
- tooltip: 'manual action',
- group: 'manual',
- detailsPath: '/root/ci-mock/builds/4258',
- hasDetails: true,
- action: null,
- },
-};
-
-export const triggerJob = {
- id: 4259,
- name: 'trigger',
- kind: BRIDGE_KIND,
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- action: null,
- },
-};
-
-export const triggerJobWithRetryAction = {
- ...triggerJob,
- status: {
- ...triggerJob.status,
- action: {
- icon: 'retry',
- title: RETRY_ACTION_TITLE,
- path: '/root/ci-mock/builds/4259/retry',
- method: 'post',
- },
- },
-};
-
-export const mockFailedJob = {
- id: 3999,
- name: 'failed job',
- kind: BUILD_KIND,
- status: {
- id: 'failed-3999-3999',
- icon: 'status_failed',
- tooltip: 'failed - (stuck or timeout failure)',
- hasDetails: true,
- detailsPath: '/root/ci-project/-/jobs/3999',
- group: 'failed',
- label: 'failed',
- action: {
- id: 'Ci::BuildPresenter-failed-3999',
- buttonTitle: 'Retry this job',
- icon: 'retry',
- path: '/root/ci-project/-/jobs/3999/retry',
- title: 'Retry',
- },
- },
-};
diff --git a/spec/frontend/pipelines/graph/stage_column_component_spec.js b/spec/frontend/pipelines/graph/stage_column_component_spec.js
deleted file mode 100644
index d4d7f1618c5..00000000000
--- a/spec/frontend/pipelines/graph/stage_column_component_spec.js
+++ /dev/null
@@ -1,228 +0,0 @@
-import { mount, shallowMount } from '@vue/test-utils';
-import JobItem from '~/pipelines/components/graph/job_item.vue';
-import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
-import ActionComponent from '~/pipelines/components/jobs_shared/action_component.vue';
-
-const mockJob = {
- id: 4250,
- name: 'test',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- details_path: '/root/ci-mock/builds/4250',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/root/ci-mock/builds/4250/retry',
- method: 'post',
- },
- },
-};
-
-const mockGroups = Array(4)
- .fill(0)
- .map((item, idx) => {
- return { ...mockJob, jobs: [mockJob], id: idx, name: `fish-${idx}` };
- });
-
-const defaultProps = {
- name: 'Fish',
- groups: mockGroups,
- pipelineId: 159,
- userPermissions: {
- updatePipeline: true,
- },
-};
-
-describe('stage column component', () => {
- let wrapper;
-
- const findStageColumnTitle = () => wrapper.find('[data-testid="stage-column-title"]');
- const findStageColumnGroup = () => wrapper.find('[data-testid="stage-column-group"]');
- const findAllStageColumnGroups = () => wrapper.findAll('[data-testid="stage-column-group"]');
- const findJobItem = () => wrapper.findComponent(JobItem);
- const findActionComponent = () => wrapper.findComponent(ActionComponent);
-
- const createComponent = ({ method = shallowMount, props = {} } = {}) => {
- wrapper = method(StageColumnComponent, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- describe('when mounted', () => {
- beforeEach(() => {
- createComponent({ method: mount });
- });
-
- it('should render provided title', () => {
- expect(findStageColumnTitle().text()).toBe(defaultProps.name);
- });
-
- it('should render the provided groups', () => {
- expect(findAllStageColumnGroups().length).toBe(mockGroups.length);
- });
-
- it('should emit updateMeasurements event on mount', () => {
- expect(wrapper.emitted().updateMeasurements).toHaveLength(1);
- });
- });
-
- describe('when job notifies action is complete', () => {
- beforeEach(() => {
- createComponent({
- method: mount,
- props: {
- groups: [
- {
- title: 'Fish',
- size: 1,
- jobs: [mockJob],
- },
- ],
- },
- });
- findJobItem().vm.$emit('pipelineActionRequestComplete');
- });
-
- it('emits refreshPipelineGraph', () => {
- expect(wrapper.emitted().refreshPipelineGraph).toHaveLength(1);
- });
- });
-
- describe('job', () => {
- describe('text handling', () => {
- beforeEach(() => {
- createComponent({
- method: mount,
- props: {
- groups: [
- {
- ...mockJob,
- name: '<img src=x onerror=alert(document.domain)>',
- jobs: [
- {
- id: 4259,
- name: '<img src=x onerror=alert(document.domain)>',
- status: {
- icon: 'status_success',
- label: 'success',
- tooltip: '<img src=x onerror=alert(document.domain)>',
- },
- },
- ],
- },
- ],
- name: 'test <img src=x onerror=alert(document.domain)>',
- },
- });
- });
-
- it('escapes name', () => {
- expect(findStageColumnTitle().html()).toContain(
- 'test &lt;img src=x onerror=alert(document.domain)&gt;',
- );
- });
-
- it('escapes id', () => {
- expect(findStageColumnGroup().attributes('id')).toBe(
- 'ci-badge-&lt;img src=x onerror=alert(document.domain)&gt;',
- );
- });
- });
-
- describe('interactions', () => {
- beforeEach(() => {
- createComponent({ method: mount });
- });
-
- it('emits jobHovered event on mouseenter and mouseleave', async () => {
- await findStageColumnGroup().trigger('mouseenter');
- expect(wrapper.emitted().jobHover).toEqual([[defaultProps.groups[0].name]]);
- await findStageColumnGroup().trigger('mouseleave');
- expect(wrapper.emitted().jobHover).toEqual([[defaultProps.groups[0].name], ['']]);
- });
- });
- });
-
- describe('with action', () => {
- const defaults = {
- groups: [
- {
- id: 4259,
- name: '<img src=x onerror=alert(document.domain)>',
- status: {
- icon: 'status_success',
- label: 'success',
- tooltip: '<img src=x onerror=alert(document.domain)>',
- },
- jobs: [mockJob],
- },
- ],
- title: 'test',
- hasTriggeredBy: false,
- action: {
- icon: 'play',
- title: 'Play all',
- path: 'action',
- },
- };
-
- it('renders action button if permissions are permitted', () => {
- createComponent({
- method: mount,
- props: {
- ...defaults,
- },
- });
-
- expect(findActionComponent().exists()).toBe(true);
- });
-
- it('does not render action button if permissions are not permitted', () => {
- createComponent({
- method: mount,
- props: {
- ...defaults,
- userPermissions: {
- updatePipeline: false,
- },
- },
- });
-
- expect(findActionComponent().exists()).toBe(false);
- });
- });
-
- describe('without action', () => {
- beforeEach(() => {
- createComponent({
- method: mount,
- props: {
- groups: [
- {
- id: 4259,
- name: '<img src=x onerror=alert(document.domain)>',
- status: {
- icon: 'status_success',
- label: 'success',
- tooltip: '<img src=x onerror=alert(document.domain)>',
- },
- jobs: [mockJob],
- },
- ],
- title: 'test',
- hasTriggeredBy: false,
- },
- });
- });
-
- it('does not render action button', () => {
- expect(findActionComponent().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph_shared/__snapshots__/links_inner_spec.js.snap b/spec/frontend/pipelines/graph_shared/__snapshots__/links_inner_spec.js.snap
deleted file mode 100644
index 82206e907ff..00000000000
--- a/spec/frontend/pipelines/graph_shared/__snapshots__/links_inner_spec.js.snap
+++ /dev/null
@@ -1,30 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Links Inner component with a large number of needs matches snapshot and has expected path 1`] = `
-"<div class=\\"gl-display-flex gl-relative\\" totalgroups=\\"10\\"><svg id=\\"link-svg\\" viewBox=\\"0,0,1019,445\\" width=\\"1019px\\" height=\\"445px\\" class=\\"gl-absolute gl-pointer-events-none\\">
- <path d=\\"M202,118C52,118,52,138,102,138\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- <path d=\\"M202,118C62,118,62,148,112,148\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- <path d=\\"M222,138C72,138,72,158,122,158\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- <path d=\\"M212,128C82,128,82,168,132,168\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- <path d=\\"M232,148C92,148,92,178,142,178\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- </svg> </div>"
-`;
-
-exports[`Links Inner component with a parallel need matches snapshot and has expected path 1`] = `
-"<div class=\\"gl-display-flex gl-relative\\" totalgroups=\\"10\\"><svg id=\\"link-svg\\" viewBox=\\"0,0,1019,445\\" width=\\"1019px\\" height=\\"445px\\" class=\\"gl-absolute gl-pointer-events-none\\">
- <path d=\\"M192,108C32,108,32,118,82,118\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- </svg> </div>"
-`;
-
-exports[`Links Inner component with one need matches snapshot and has expected path 1`] = `
-"<div class=\\"gl-display-flex gl-relative\\" totalgroups=\\"10\\"><svg id=\\"link-svg\\" viewBox=\\"0,0,1019,445\\" width=\\"1019px\\" height=\\"445px\\" class=\\"gl-absolute gl-pointer-events-none\\">
- <path d=\\"M202,118C52,118,52,138,102,138\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- </svg> </div>"
-`;
-
-exports[`Links Inner component with same stage needs matches snapshot and has expected path 1`] = `
-"<div class=\\"gl-display-flex gl-relative\\" totalgroups=\\"10\\"><svg id=\\"link-svg\\" viewBox=\\"0,0,1019,445\\" width=\\"1019px\\" height=\\"445px\\" class=\\"gl-absolute gl-pointer-events-none\\">
- <path d=\\"M192,108C32,108,32,118,82,118\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- <path d=\\"M202,118C42,118,42,128,92,128\\" stroke-width=\\"2\\" class=\\"gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease gl-stroke-gray-200\\"></path>
- </svg> </div>"
-`;
diff --git a/spec/frontend/pipelines/graph_shared/links_inner_spec.js b/spec/frontend/pipelines/graph_shared/links_inner_spec.js
deleted file mode 100644
index b4ffd2658fe..00000000000
--- a/spec/frontend/pipelines/graph_shared/links_inner_spec.js
+++ /dev/null
@@ -1,223 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import LinksInner from '~/pipelines/components/graph_shared/links_inner.vue';
-import { parseData } from '~/pipelines/components/parsing_utils';
-import { createJobsHash } from '~/pipelines/utils';
-import {
- jobRect,
- largePipelineData,
- parallelNeedData,
- pipelineData,
- pipelineDataWithNoNeeds,
- rootRect,
- sameStageNeeds,
-} from '../pipeline_graph/mock_data';
-
-describe('Links Inner component', () => {
- const containerId = 'pipeline-graph-container';
- const defaultProps = {
- containerId,
- containerMeasurements: { width: 1019, height: 445 },
- pipelineId: 1,
- pipelineData: [],
- totalGroups: 10,
- };
-
- let wrapper;
-
- const createComponent = (props) => {
- const currentPipelineData = props?.pipelineData || defaultProps.pipelineData;
- wrapper = shallowMount(LinksInner, {
- propsData: {
- ...defaultProps,
- ...props,
- linksData: parseData(currentPipelineData.flatMap(({ groups }) => groups)).links,
- },
- });
- };
-
- const findLinkSvg = () => wrapper.find('#link-svg');
- const findAllLinksPath = () => findLinkSvg().findAll('path');
-
- // We create fixture so that each job has an empty div that represent
- // the JobPill in the DOM. Each `JobPill` would have different coordinates,
- // so we increment their coordinates on each iteration to simulate different positions.
- const setHTMLFixtureLocal = ({ stages }) => {
- const jobs = createJobsHash(stages);
- const arrayOfJobs = Object.keys(jobs);
-
- const linksHtmlElements = arrayOfJobs.map((job) => {
- return `<div id=${job}-${defaultProps.pipelineId} />`;
- });
-
- setHTMLFixture(`<div id="${containerId}">${linksHtmlElements.join(' ')}</div>`);
-
- // We are mocking the clientRect data of each job and the container ID.
- jest
- .spyOn(document.getElementById(containerId), 'getBoundingClientRect')
- .mockImplementation(() => rootRect);
-
- arrayOfJobs.forEach((job, index) => {
- jest
- .spyOn(
- document.getElementById(`${job}-${defaultProps.pipelineId}`),
- 'getBoundingClientRect',
- )
- .mockImplementation(() => {
- const newValue = 10 * index;
- const { left, right, top, bottom, x, y } = jobRect;
- return {
- ...jobRect,
- left: left + newValue,
- right: right + newValue,
- top: top + newValue,
- bottom: bottom + newValue,
- x: x + newValue,
- y: y + newValue,
- };
- });
- });
- };
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- describe('basic SVG creation', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders an SVG of the right size', () => {
- expect(findLinkSvg().exists()).toBe(true);
- expect(findLinkSvg().attributes('width')).toBe(
- `${defaultProps.containerMeasurements.width}px`,
- );
- expect(findLinkSvg().attributes('height')).toBe(
- `${defaultProps.containerMeasurements.height}px`,
- );
- });
- });
-
- describe('no pipeline data', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders the component', () => {
- expect(findLinkSvg().exists()).toBe(true);
- expect(findAllLinksPath()).toHaveLength(0);
- });
- });
-
- describe('pipeline data with no needs', () => {
- beforeEach(() => {
- createComponent({ pipelineData: pipelineDataWithNoNeeds.stages });
- });
-
- it('renders no links', () => {
- expect(findLinkSvg().exists()).toBe(true);
- expect(findAllLinksPath()).toHaveLength(0);
- });
- });
-
- describe('with one need', () => {
- beforeEach(() => {
- setHTMLFixtureLocal(pipelineData);
- createComponent({ pipelineData: pipelineData.stages });
- });
-
- it('renders one link', () => {
- expect(findAllLinksPath()).toHaveLength(1);
- });
-
- it('path does not contain NaN values', () => {
- expect(wrapper.html()).not.toContain('NaN');
- });
-
- it('matches snapshot and has expected path', () => {
- expect(wrapper.html()).toMatchSnapshot();
- });
- });
-
- describe('with a parallel need', () => {
- beforeEach(() => {
- setHTMLFixtureLocal(parallelNeedData);
- createComponent({ pipelineData: parallelNeedData.stages });
- });
-
- it('renders only one link for all the same parallel jobs', () => {
- expect(findAllLinksPath()).toHaveLength(1);
- });
-
- it('path does not contain NaN values', () => {
- expect(wrapper.html()).not.toContain('NaN');
- });
-
- it('matches snapshot and has expected path', () => {
- expect(wrapper.html()).toMatchSnapshot();
- });
- });
-
- describe('with same stage needs', () => {
- beforeEach(() => {
- setHTMLFixtureLocal(sameStageNeeds);
- createComponent({ pipelineData: sameStageNeeds.stages });
- });
-
- it('renders the correct number of links', () => {
- expect(findAllLinksPath()).toHaveLength(2);
- });
-
- it('path does not contain NaN values', () => {
- expect(wrapper.html()).not.toContain('NaN');
- });
-
- it('matches snapshot and has expected path', () => {
- expect(wrapper.html()).toMatchSnapshot();
- });
- });
-
- describe('with a large number of needs', () => {
- beforeEach(() => {
- setHTMLFixtureLocal(largePipelineData);
- createComponent({ pipelineData: largePipelineData.stages });
- });
-
- it('renders the correct number of links', () => {
- expect(findAllLinksPath()).toHaveLength(5);
- });
-
- it('path does not contain NaN values', () => {
- expect(wrapper.html()).not.toContain('NaN');
- });
-
- it('matches snapshot and has expected path', () => {
- expect(wrapper.html()).toMatchSnapshot();
- });
- });
-
- describe('interactions', () => {
- beforeEach(() => {
- setHTMLFixtureLocal(largePipelineData);
- createComponent({ pipelineData: largePipelineData.stages });
- });
-
- it('highlight needs on hover', async () => {
- const firstLink = findAllLinksPath().at(0);
-
- const defaultColorClass = 'gl-stroke-gray-200';
- const hoverColorClass = 'gl-stroke-blue-400';
-
- expect(firstLink.classes(defaultColorClass)).toBe(true);
- expect(firstLink.classes(hoverColorClass)).toBe(false);
-
- // Because there is a watcher, we need to set the props after the component
- // has mounted.
- await wrapper.setProps({ highlightedJob: 'test_1' });
-
- expect(firstLink.classes(defaultColorClass)).toBe(false);
- expect(firstLink.classes(hoverColorClass)).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/pipelines/graph_shared/links_layer_spec.js b/spec/frontend/pipelines/graph_shared/links_layer_spec.js
deleted file mode 100644
index 88ba84c395a..00000000000
--- a/spec/frontend/pipelines/graph_shared/links_layer_spec.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
-import LinksInner from '~/pipelines/components/graph_shared/links_inner.vue';
-import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
-
-import { generateResponse } from '../graph/mock_data';
-
-describe('links layer component', () => {
- let wrapper;
-
- const findLinksInner = () => wrapper.findComponent(LinksInner);
-
- const pipeline = generateResponse(mockPipelineResponse, 'root/fungi-xoxo');
- const containerId = `pipeline-links-container-${pipeline.id}`;
- const slotContent = "<div>Ceci n'est pas un graphique</div>";
-
- const defaultProps = {
- containerId,
- containerMeasurements: { width: 400, height: 400 },
- pipelineId: pipeline.id,
- pipelineData: pipeline.stages,
- showLinks: false,
- };
-
- const createComponent = ({ mountFn = shallowMount, props = {} } = {}) => {
- wrapper = mountFn(LinksLayer, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- slots: {
- default: slotContent,
- },
- stubs: {
- 'links-inner': true,
- },
- });
- };
-
- describe('with show links off', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders the default slot', () => {
- expect(wrapper.html()).toContain(slotContent);
- });
-
- it('does not render inner links component', () => {
- expect(findLinksInner().exists()).toBe(false);
- });
- });
-
- describe('with show links on', () => {
- beforeEach(() => {
- createComponent({
- props: {
- showLinks: true,
- },
- });
- });
-
- it('renders the default slot', () => {
- expect(wrapper.html()).toContain(slotContent);
- });
-
- it('renders the inner links component', () => {
- expect(findLinksInner().exists()).toBe(true);
- });
- });
-
- describe('with width or height measurement at 0', () => {
- beforeEach(() => {
- createComponent({ props: { containerMeasurements: { width: 0, height: 100 } } });
- });
-
- it('renders the default slot', () => {
- expect(wrapper.html()).toContain(slotContent);
- });
-
- it('does not render the inner links component', () => {
- expect(findLinksInner().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/mock_data.js b/spec/frontend/pipelines/mock_data.js
deleted file mode 100644
index 673db3b5178..00000000000
--- a/spec/frontend/pipelines/mock_data.js
+++ /dev/null
@@ -1,1379 +0,0 @@
-import pipelineHeaderSuccess from 'test_fixtures/graphql/pipelines/pipeline_header_success.json';
-import pipelineHeaderRunning from 'test_fixtures/graphql/pipelines/pipeline_header_running.json';
-import pipelineHeaderRunningWithDuration from 'test_fixtures/graphql/pipelines/pipeline_header_running_with_duration.json';
-import pipelineHeaderFailed from 'test_fixtures/graphql/pipelines/pipeline_header_failed.json';
-
-const PIPELINE_RUNNING = 'RUNNING';
-const PIPELINE_CANCELED = 'CANCELED';
-const PIPELINE_FAILED = 'FAILED';
-
-const threeWeeksAgo = new Date();
-threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
-
-export {
- pipelineHeaderSuccess,
- pipelineHeaderRunning,
- pipelineHeaderRunningWithDuration,
- pipelineHeaderFailed,
-};
-
-export const pipelineRetryMutationResponseSuccess = {
- data: { pipelineRetry: { errors: [] } },
-};
-
-export const pipelineRetryMutationResponseFailed = {
- data: { pipelineRetry: { errors: ['error'] } },
-};
-
-export const pipelineCancelMutationResponseSuccess = {
- data: { pipelineCancel: { errors: [] } },
-};
-
-export const pipelineCancelMutationResponseFailed = {
- data: { pipelineCancel: { errors: ['error'] } },
-};
-
-export const pipelineDeleteMutationResponseSuccess = {
- data: { pipelineDestroy: { errors: [] } },
-};
-
-export const pipelineDeleteMutationResponseFailed = {
- data: { pipelineDestroy: { errors: ['error'] } },
-};
-
-export const mockPipelineHeader = {
- detailedStatus: {},
- id: 123,
- userPermissions: {
- destroyPipeline: true,
- updatePipeline: true,
- },
- createdAt: threeWeeksAgo.toISOString(),
- user: {
- id: 'user-1',
- name: 'Foo',
- username: 'foobar',
- email: 'foo@bar.com',
- avatarUrl: 'link',
- },
-};
-
-export const mockFailedPipelineHeader = {
- ...mockPipelineHeader,
- status: PIPELINE_FAILED,
- retryable: true,
- cancelable: false,
- detailedStatus: {
- id: 'status-1',
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- detailsPath: 'path',
- },
-};
-
-export const mockFailedPipelineNoPermissions = {
- id: 123,
- userPermissions: {
- destroyPipeline: false,
- updatePipeline: false,
- },
- createdAt: threeWeeksAgo.toISOString(),
- user: {
- id: 'user-1',
- name: 'Foo',
- username: 'foobar',
- email: 'foo@bar.com',
- avatarUrl: 'link',
- },
- status: PIPELINE_RUNNING,
- retryable: true,
- cancelable: false,
- detailedStatus: {
- id: 'status-1',
- group: 'running',
- icon: 'status_running',
- label: 'running',
- text: 'running',
- detailsPath: 'path',
- },
-};
-
-export const mockRunningPipelineHeader = {
- ...mockPipelineHeader,
- status: PIPELINE_RUNNING,
- retryable: false,
- cancelable: true,
- detailedStatus: {
- id: 'status-1',
- group: 'running',
- icon: 'status_running',
- label: 'running',
- text: 'running',
- detailsPath: 'path',
- },
-};
-
-export const mockRunningPipelineNoPermissions = {
- id: 123,
- userPermissions: {
- destroyPipeline: false,
- updatePipeline: false,
- },
- createdAt: threeWeeksAgo.toISOString(),
- user: {
- id: 'user-1',
- name: 'Foo',
- username: 'foobar',
- email: 'foo@bar.com',
- avatarUrl: 'link',
- },
- status: PIPELINE_RUNNING,
- retryable: false,
- cancelable: true,
- detailedStatus: {
- id: 'status-1',
- group: 'running',
- icon: 'status_running',
- label: 'running',
- text: 'running',
- detailsPath: 'path',
- },
-};
-
-export const mockCancelledPipelineHeader = {
- ...mockPipelineHeader,
- status: PIPELINE_CANCELED,
- retryable: true,
- cancelable: false,
- detailedStatus: {
- id: 'status-1',
- group: 'cancelled',
- icon: 'status_cancelled',
- label: 'cancelled',
- text: 'cancelled',
- detailsPath: 'path',
- },
-};
-
-export const mockSuccessfulPipelineHeader = {
- ...mockPipelineHeader,
- status: 'SUCCESS',
- retryable: false,
- cancelable: false,
- detailedStatus: {
- id: 'status-1',
- group: 'success',
- icon: 'status_success',
- label: 'success',
- text: 'success',
- detailsPath: 'path',
- },
-};
-
-export const mockRunningPipelineHeaderData = {
- data: {
- project: {
- id: '1',
- pipeline: {
- ...mockRunningPipelineHeader,
- iid: '28',
- user: {
- id: 'user-1',
- name: 'Foo',
- username: 'foobar',
- webPath: '/foo',
- webUrl: '/foo',
- email: 'foo@bar.com',
- avatarUrl: 'link',
- status: null,
- __typename: 'UserCore',
- },
- __typename: 'Pipeline',
- },
- __typename: 'Project',
- },
- },
-};
-
-export const stageReply = {
- name: 'deploy',
- title: 'deploy: running',
- latest_statuses: [
- {
- id: 928,
- name: 'stop staging',
- started: false,
- build_path: '/twitter/flight/-/jobs/928',
- cancel_path: '/twitter/flight/-/jobs/928/cancel',
- playable: false,
- created_at: '2018-04-04T20:02:02.728Z',
- updated_at: '2018-04-04T20:02:02.766Z',
- status: {
- icon: 'status_pending',
- text: 'pending',
- label: 'pending',
- group: 'pending',
- tooltip: 'pending',
- has_details: true,
- details_path: '/twitter/flight/-/jobs/928',
- favicon:
- '/assets/ci_favicons/dev/favicon_status_pending-db32e1faf94b9f89530ac519790920d1f18ea8f6af6cd2e0a26cd6840cacf101.ico',
- action: {
- icon: 'cancel',
- title: 'Cancel',
- path: '/twitter/flight/-/jobs/928/cancel',
- method: 'post',
- },
- },
- },
- {
- id: 926,
- name: 'production',
- started: false,
- build_path: '/twitter/flight/-/jobs/926',
- retry_path: '/twitter/flight/-/jobs/926/retry',
- play_path: '/twitter/flight/-/jobs/926/play',
- playable: true,
- created_at: '2018-04-04T20:00:57.202Z',
- updated_at: '2018-04-04T20:11:13.110Z',
- status: {
- icon: 'status_canceled',
- text: 'canceled',
- label: 'manual play action',
- group: 'canceled',
- tooltip: 'canceled',
- has_details: true,
- details_path: '/twitter/flight/-/jobs/926',
- favicon:
- '/assets/ci_favicons/dev/favicon_status_canceled-5491840b9b6feafba0bc599cbd49ee9580321dc809683856cf1b0d51532b1af6.ico',
- action: {
- icon: 'play',
- title: 'Play',
- path: '/twitter/flight/-/jobs/926/play',
- method: 'post',
- },
- },
- },
- {
- id: 217,
- name: 'staging',
- started: '2018-03-07T08:41:46.234Z',
- build_path: '/twitter/flight/-/jobs/217',
- retry_path: '/twitter/flight/-/jobs/217/retry',
- playable: false,
- created_at: '2018-03-07T14:41:58.093Z',
- updated_at: '2018-03-07T14:41:58.093Z',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/twitter/flight/-/jobs/217',
- favicon:
- '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/twitter/flight/-/jobs/217/retry',
- method: 'post',
- },
- },
- },
- ],
- status: {
- icon: 'status_running',
- text: 'running',
- label: 'running',
- group: 'running',
- tooltip: 'running',
- has_details: true,
- details_path: '/twitter/flight/pipelines/13#deploy',
- favicon:
- '/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico',
- },
- path: '/twitter/flight/pipelines/13#deploy',
- dropdown_path: '/twitter/flight/pipelines/13/stage.json?stage=deploy',
-};
-
-export const users = [
- {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
- web_url: 'http://192.168.1.22:3000/root',
- },
- {
- id: 10,
- name: 'Angel Spinka',
- username: 'shalonda',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/709df1b65ad06764ee2b0edf1b49fc27?s=80\u0026d=identicon',
- web_url: 'http://192.168.1.22:3000/shalonda',
- },
- {
- id: 11,
- name: 'Art Davis',
- username: 'deja.green',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/bb56834c061522760e7a6dd7d431a306?s=80\u0026d=identicon',
- web_url: 'http://192.168.1.22:3000/deja.green',
- },
- {
- id: 32,
- name: 'Arnold Mante',
- username: 'reported_user_10',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/ab558033a82466d7905179e837d7723a?s=80\u0026d=identicon',
- web_url: 'http://192.168.1.22:3000/reported_user_10',
- },
- {
- id: 38,
- name: 'Cher Wintheiser',
- username: 'reported_user_16',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/2640356e8b5bc4314133090994ed162b?s=80\u0026d=identicon',
- web_url: 'http://192.168.1.22:3000/reported_user_16',
- },
- {
- id: 39,
- name: 'Bethel Wolf',
- username: 'reported_user_17',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/4b948694fadba4b01e4acfc06b065e8e?s=80\u0026d=identicon',
- web_url: 'http://192.168.1.22:3000/reported_user_17',
- },
-];
-
-export const branches = [
- {
- name: 'branch-1',
- commit: {
- id: '21fb056cc47dcf706670e6de635b1b326490ebdc',
- short_id: '21fb056c',
- created_at: '2020-05-07T10:58:28.000-04:00',
- parent_ids: null,
- title: 'Add new file',
- message: 'Add new file',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2020-05-07T10:58:28.000-04:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2020-05-07T10:58:28.000-04:00',
- web_url:
- 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/21fb056cc47dcf706670e6de635b1b326490ebdc',
- },
- merged: false,
- protected: false,
- developers_can_push: false,
- developers_can_merge: false,
- can_push: true,
- default: false,
- web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-1',
- },
- {
- name: 'branch-10',
- commit: {
- id: '66673b07efef254dab7d537f0433a40e61cf84fe',
- short_id: '66673b07',
- created_at: '2020-03-16T11:04:46.000-04:00',
- parent_ids: null,
- title: 'Update .gitlab-ci.yml',
- message: 'Update .gitlab-ci.yml',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2020-03-16T11:04:46.000-04:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2020-03-16T11:04:46.000-04:00',
- web_url:
- 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
- },
- merged: false,
- protected: false,
- developers_can_push: false,
- developers_can_merge: false,
- can_push: true,
- default: false,
- web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-10',
- },
- {
- name: 'branch-11',
- commit: {
- id: '66673b07efef254dab7d537f0433a40e61cf84fe',
- short_id: '66673b07',
- created_at: '2020-03-16T11:04:46.000-04:00',
- parent_ids: null,
- title: 'Update .gitlab-ci.yml',
- message: 'Update .gitlab-ci.yml',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2020-03-16T11:04:46.000-04:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2020-03-16T11:04:46.000-04:00',
- web_url:
- 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
- },
- merged: false,
- protected: false,
- developers_can_push: false,
- developers_can_merge: false,
- can_push: true,
- default: false,
- web_url: 'http://192.168.1.22:3000/root/dag-pipeline/-/tree/branch-11',
- },
-];
-
-export const tags = [
- {
- name: 'tag-3',
- message: '',
- target: '66673b07efef254dab7d537f0433a40e61cf84fe',
- commit: {
- id: '66673b07efef254dab7d537f0433a40e61cf84fe',
- short_id: '66673b07',
- created_at: '2020-03-16T11:04:46.000-04:00',
- parent_ids: ['def28bf679235071140180495f25b657e2203587'],
- title: 'Update .gitlab-ci.yml',
- message: 'Update .gitlab-ci.yml',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2020-03-16T11:04:46.000-04:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2020-03-16T11:04:46.000-04:00',
- web_url:
- 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
- },
- release: null,
- protected: false,
- },
- {
- name: 'tag-2',
- message: '',
- target: '66673b07efef254dab7d537f0433a40e61cf84fe',
- commit: {
- id: '66673b07efef254dab7d537f0433a40e61cf84fe',
- short_id: '66673b07',
- created_at: '2020-03-16T11:04:46.000-04:00',
- parent_ids: ['def28bf679235071140180495f25b657e2203587'],
- title: 'Update .gitlab-ci.yml',
- message: 'Update .gitlab-ci.yml',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2020-03-16T11:04:46.000-04:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2020-03-16T11:04:46.000-04:00',
- web_url:
- 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
- },
- release: null,
- protected: false,
- },
- {
- name: 'tag-1',
- message: '',
- target: '66673b07efef254dab7d537f0433a40e61cf84fe',
- commit: {
- id: '66673b07efef254dab7d537f0433a40e61cf84fe',
- short_id: '66673b07',
- created_at: '2020-03-16T11:04:46.000-04:00',
- parent_ids: ['def28bf679235071140180495f25b657e2203587'],
- title: 'Update .gitlab-ci.yml',
- message: 'Update .gitlab-ci.yml',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2020-03-16T11:04:46.000-04:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2020-03-16T11:04:46.000-04:00',
- web_url:
- 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
- },
- release: null,
- protected: false,
- },
- {
- name: 'main-tag',
- message: '',
- target: '66673b07efef254dab7d537f0433a40e61cf84fe',
- commit: {
- id: '66673b07efef254dab7d537f0433a40e61cf84fe',
- short_id: '66673b07',
- created_at: '2020-03-16T11:04:46.000-04:00',
- parent_ids: ['def28bf679235071140180495f25b657e2203587'],
- title: 'Update .gitlab-ci.yml',
- message: 'Update .gitlab-ci.yml',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2020-03-16T11:04:46.000-04:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2020-03-16T11:04:46.000-04:00',
- web_url:
- 'http://192.168.1.22:3000/root/dag-pipeline/-/commit/66673b07efef254dab7d537f0433a40e61cf84fe',
- },
- release: null,
- protected: false,
- },
-];
-
-export const mockSearch = [
- { type: 'username', value: { data: 'root', operator: '=' } },
- { type: 'ref', value: { data: 'main', operator: '=' } },
- { type: 'status', value: { data: 'pending', operator: '=' } },
-];
-
-export const mockBranchesAfterMap = ['branch-1', 'branch-10', 'branch-11'];
-
-export const mockTagsAfterMap = ['tag-3', 'tag-2', 'tag-1', 'main-tag'];
-
-export const mockPipelineJobsQueryResponse = {
- data: {
- project: {
- id: 'gid://gitlab/Project/20',
- __typename: 'Project',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/224',
- __typename: 'Pipeline',
- jobs: {
- __typename: 'CiJobConnection',
- pageInfo: {
- endCursor: 'eyJpZCI6Ijg0NyJ9',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'eyJpZCI6IjYyMCJ9',
- __typename: 'PageInfo',
- },
- nodes: [
- {
- artifacts: {
- nodes: [
- {
- downloadPath: '/root/ci-project/-/jobs/620/artifacts/download?file_type=trace',
- fileType: 'TRACE',
- __typename: 'CiJobArtifact',
- },
- ],
- __typename: 'CiJobArtifactConnection',
- },
- allowFailure: false,
- status: 'SUCCESS',
- scheduledAt: null,
- manualJob: false,
- triggered: null,
- createdByTag: false,
- detailedStatus: {
- id: 'success-620-620',
- detailsPath: '/root/ci-project/-/jobs/620',
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed (retried)',
- action: null,
- __typename: 'DetailedStatus',
- },
- id: 'gid://gitlab/Ci::Build/620',
- refName: 'main',
- refPath: '/root/ci-project/-/commits/main',
- tags: [],
- shortSha: '5acce24b',
- commitPath: '/root/ci-project/-/commit/5acce24b3737d4f0d649ad0a26ae1903a2b35f5e',
- stage: { id: 'gid://gitlab/Ci::Stage/148', name: 'test', __typename: 'CiStage' },
- name: 'coverage_job',
- duration: 4,
- finishedAt: '2021-12-06T14:13:49Z',
- coverage: 82.71,
- retryable: false,
- playable: false,
- cancelable: false,
- active: false,
- stuck: false,
- userPermissions: {
- readBuild: true,
- readJobArtifacts: true,
- updateBuild: true,
- __typename: 'JobPermissions',
- },
- __typename: 'CiJob',
- },
- {
- artifacts: {
- nodes: [
- {
- downloadPath: '/root/ci-project/-/jobs/619/artifacts/download?file_type=trace',
- fileType: 'TRACE',
- __typename: 'CiJobArtifact',
- },
- ],
- __typename: 'CiJobArtifactConnection',
- },
- allowFailure: false,
- status: 'SUCCESS',
- scheduledAt: null,
- manualJob: false,
- triggered: null,
- createdByTag: false,
- detailedStatus: {
- id: 'success-619-619',
- detailsPath: '/root/ci-project/-/jobs/619',
- group: 'success',
- icon: 'status_success',
- label: 'passed',
- text: 'passed',
- tooltip: 'passed (retried)',
- action: null,
- __typename: 'DetailedStatus',
- },
- id: 'gid://gitlab/Ci::Build/619',
- refName: 'main',
- refPath: '/root/ci-project/-/commits/main',
- tags: [],
- shortSha: '5acce24b',
- commitPath: '/root/ci-project/-/commit/5acce24b3737d4f0d649ad0a26ae1903a2b35f5e',
- stage: { id: 'gid://gitlab/Ci::Stage/148', name: 'test', __typename: 'CiStage' },
- name: 'test_job_two',
- duration: 4,
- finishedAt: '2021-12-06T14:13:44Z',
- coverage: null,
- retryable: false,
- playable: false,
- cancelable: false,
- active: false,
- stuck: false,
- userPermissions: {
- readBuild: true,
- readJobArtifacts: true,
- updateBuild: true,
- __typename: 'JobPermissions',
- },
- __typename: 'CiJob',
- },
- ],
- },
- },
- },
- },
-};
-
-export const mockPipeline = (projectPath) => {
- return {
- pipeline: {
- id: 1,
- user: {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url: '',
- web_url: 'http://0.0.0.0:3000/root',
- show_status: false,
- path: '/root',
- },
- active: false,
- source: 'merge_request_event',
- created_at: '2021-10-19T21:17:38.698Z',
- updated_at: '2021-10-21T18:00:42.758Z',
- path: 'foo',
- flags: {},
- merge_request: {
- iid: 1,
- path: `/${projectPath}/1`,
- title: 'commit',
- source_branch: 'test-commit-name',
- source_branch_path: `/${projectPath}`,
- target_branch: 'main',
- target_branch_path: `/${projectPath}/-/commit/main`,
- },
- ref: {
- name: 'refs/merge-requests/1/head',
- path: `/${projectPath}/-/commits/refs/merge-requests/1/head`,
- tag: false,
- branch: false,
- merge_request: true,
- },
- commit: {
- id: 'fd6df5b3229e213c97d308844a6f3e7fd71e8f8c',
- short_id: 'fd6df5b3',
- created_at: '2021-10-19T21:17:12.000+00:00',
- parent_ids: ['7147906b84306e83cb3fec6582a25390b75713c6'],
- title: 'Commit',
- message: 'Commit',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2021-10-19T21:17:12.000+00:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2021-10-19T21:17:12.000+00:00',
- trailers: {},
- web_url: '',
- author: {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url: '',
- web_url: '',
- show_status: false,
- path: '/root',
- },
- author_gravatar_url: '',
- commit_url: `/${projectPath}/fd6df5b3229e213c97d308844a6f3e7fd71e8f8c`,
- commit_path: `/${projectPath}/commit/fd6df5b3229e213c97d308844a6f3e7fd71e8f8c`,
- },
- project: {
- full_path: `/${projectPath}`,
- },
- triggered_by: null,
- triggered: [],
- },
- pipelineScheduleUrl: 'foo',
- pipelineKey: 'id',
- viewType: 'root',
- };
-};
-
-export const mockPipelineTag = () => {
- return {
- pipeline: {
- id: 311,
- iid: 37,
- user: {
- id: 1,
- username: 'root',
- name: 'Administrator',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- web_url: 'http://gdk.test:3000/root',
- show_status: false,
- path: '/root',
- },
- active: false,
- source: 'push',
- name: 'Build pipeline',
- created_at: '2022-02-02T15:39:04.012Z',
- updated_at: '2022-02-02T15:40:59.573Z',
- path: '/root/mr-widgets/-/pipelines/311',
- flags: {
- stuck: false,
- auto_devops: false,
- merge_request: false,
- yaml_errors: false,
- retryable: true,
- cancelable: false,
- failure_reason: false,
- detached_merge_request_pipeline: false,
- merge_request_pipeline: false,
- merge_train_pipeline: false,
- latest: true,
- },
- details: {
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/311',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- stages: [
- {
- name: 'accessibility',
- title: 'accessibility: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/311#accessibility',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/mr-widgets/-/pipelines/311#accessibility',
- dropdown_path: '/root/mr-widgets/-/pipelines/311/stage.json?stage=accessibility',
- },
- {
- name: 'validate',
- title: 'validate: passed with warnings',
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/311#validate',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/mr-widgets/-/pipelines/311#validate',
- dropdown_path: '/root/mr-widgets/-/pipelines/311/stage.json?stage=validate',
- },
- {
- name: 'test',
- title: 'test: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/311#test',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/mr-widgets/-/pipelines/311#test',
- dropdown_path: '/root/mr-widgets/-/pipelines/311/stage.json?stage=test',
- },
- {
- name: 'build',
- title: 'build: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/311#build',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/mr-widgets/-/pipelines/311#build',
- dropdown_path: '/root/mr-widgets/-/pipelines/311/stage.json?stage=build',
- },
- ],
- duration: 93,
- finished_at: '2022-02-02T15:40:59.384Z',
- event_type_name: 'Pipeline',
- manual_actions: [],
- scheduled_actions: [],
- },
- ref: {
- name: 'test',
- path: '/root/mr-widgets/-/commits/test',
- tag: true,
- branch: false,
- merge_request: false,
- },
- commit: {
- id: '9b92b4f730d1611bd9a086ca221ae206d5da1e59',
- short_id: '9b92b4f7',
- created_at: '2022-01-13T13:59:03.000+00:00',
- parent_ids: ['0ba763634114e207dc72c65c8e9459556b1204fb'],
- title: 'Update hello_world.js',
- message: 'Update hello_world.js',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2022-01-13T13:59:03.000+00:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2022-01-13T13:59:03.000+00:00',
- trailers: {},
- web_url:
- 'http://gdk.test:3000/root/mr-widgets/-/commit/9b92b4f730d1611bd9a086ca221ae206d5da1e59',
- author: {
- id: 1,
- username: 'root',
- name: 'Administrator',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- web_url: 'http://gdk.test:3000/root',
- show_status: false,
- path: '/root',
- },
- author_gravatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- commit_url:
- 'http://gdk.test:3000/root/mr-widgets/-/commit/9b92b4f730d1611bd9a086ca221ae206d5da1e59',
- commit_path: '/root/mr-widgets/-/commit/9b92b4f730d1611bd9a086ca221ae206d5da1e59',
- },
- retry_path: '/root/mr-widgets/-/pipelines/311/retry',
- delete_path: '/root/mr-widgets/-/pipelines/311',
- failed_builds: [
- {
- id: 1696,
- name: 'fmt',
- started: '2022-02-02T15:39:45.192Z',
- complete: true,
- archived: false,
- build_path: '/root/mr-widgets/-/jobs/1696',
- retry_path: '/root/mr-widgets/-/jobs/1696/retry',
- playable: false,
- scheduled: false,
- created_at: '2022-02-02T15:39:04.136Z',
- updated_at: '2022-02-02T15:39:57.969Z',
- status: {
- icon: 'status_warning',
- text: 'failed',
- label: 'failed (allowed to fail)',
- group: 'failed-with-warnings',
- tooltip: 'failed - (script failure) (allowed to fail)',
- has_details: true,
- details_path: '/root/mr-widgets/-/jobs/1696',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-29a8a37d8a61d1b6f68cf3484f9024e53cd6eb95e28eae3554f8011a1146bf27.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/root/mr-widgets/-/jobs/1696/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- recoverable: false,
- },
- ],
- project: {
- id: 23,
- name: 'mr-widgets',
- full_path: '/root/mr-widgets',
- full_name: 'Administrator / mr-widgets',
- },
- triggered_by: null,
- triggered: [],
- },
- pipelineScheduleUrl: 'foo',
- pipelineKey: 'id',
- viewType: 'root',
- };
-};
-
-export const mockPipelineBranch = () => {
- return {
- pipeline: {
- id: 268,
- iid: 34,
- user: {
- id: 1,
- username: 'root',
- name: 'Administrator',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- web_url: 'http://gdk.test:3000/root',
- show_status: false,
- path: '/root',
- },
- active: false,
- source: 'push',
- name: 'Build pipeline',
- created_at: '2022-01-14T17:40:27.866Z',
- updated_at: '2022-01-14T18:02:35.850Z',
- path: '/root/mr-widgets/-/pipelines/268',
- flags: {
- stuck: false,
- auto_devops: false,
- merge_request: false,
- yaml_errors: false,
- retryable: true,
- cancelable: false,
- failure_reason: false,
- detached_merge_request_pipeline: false,
- merge_request_pipeline: false,
- merge_train_pipeline: false,
- latest: true,
- },
- details: {
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/268',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- stages: [
- {
- name: 'validate',
- title: 'validate: passed with warnings',
- status: {
- icon: 'status_warning',
- text: 'passed',
- label: 'passed with warnings',
- group: 'success-with-warnings',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/268#validate',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/mr-widgets/-/pipelines/268#validate',
- dropdown_path: '/root/mr-widgets/-/pipelines/268/stage.json?stage=validate',
- },
- {
- name: 'test',
- title: 'test: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/268#test',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/mr-widgets/-/pipelines/268#test',
- dropdown_path: '/root/mr-widgets/-/pipelines/268/stage.json?stage=test',
- },
- {
- name: 'build',
- title: 'build: passed',
- status: {
- icon: 'status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- tooltip: 'passed',
- has_details: true,
- details_path: '/root/mr-widgets/-/pipelines/268#build',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png',
- },
- path: '/root/mr-widgets/-/pipelines/268#build',
- dropdown_path: '/root/mr-widgets/-/pipelines/268/stage.json?stage=build',
- },
- ],
- duration: 75,
- finished_at: '2022-01-14T18:02:35.842Z',
- event_type_name: 'Pipeline',
- manual_actions: [],
- scheduled_actions: [],
- },
- ref: {
- name: 'update-ci',
- path: '/root/mr-widgets/-/commits/update-ci',
- tag: false,
- branch: true,
- merge_request: false,
- },
- commit: {
- id: '96aef9ecec5752c09371c1ade5fc77860aafc863',
- short_id: '96aef9ec',
- created_at: '2022-01-14T17:40:26.000+00:00',
- parent_ids: ['06860257572d4cf84b73806250b78169050aed83'],
- title: 'Update main.tf',
- message: 'Update main.tf',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2022-01-14T17:40:26.000+00:00',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2022-01-14T17:40:26.000+00:00',
- trailers: {},
- web_url:
- 'http://gdk.test:3000/root/mr-widgets/-/commit/96aef9ecec5752c09371c1ade5fc77860aafc863',
- author: {
- id: 1,
- username: 'root',
- name: 'Administrator',
- state: 'active',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- web_url: 'http://gdk.test:3000/root',
- show_status: false,
- path: '/root',
- },
- author_gravatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- commit_url:
- 'http://gdk.test:3000/root/mr-widgets/-/commit/96aef9ecec5752c09371c1ade5fc77860aafc863',
- commit_path: '/root/mr-widgets/-/commit/96aef9ecec5752c09371c1ade5fc77860aafc863',
- },
- retry_path: '/root/mr-widgets/-/pipelines/268/retry',
- delete_path: '/root/mr-widgets/-/pipelines/268',
- failed_builds: [
- {
- id: 1260,
- name: 'fmt',
- started: '2022-01-14T17:40:36.435Z',
- complete: true,
- archived: false,
- build_path: '/root/mr-widgets/-/jobs/1260',
- retry_path: '/root/mr-widgets/-/jobs/1260/retry',
- playable: false,
- scheduled: false,
- created_at: '2022-01-14T17:40:27.879Z',
- updated_at: '2022-01-14T17:40:42.129Z',
- status: {
- icon: 'status_warning',
- text: 'failed',
- label: 'failed (allowed to fail)',
- group: 'failed-with-warnings',
- tooltip: 'failed - (script failure) (allowed to fail)',
- has_details: true,
- details_path: '/root/mr-widgets/-/jobs/1260',
- illustration: {
- image:
- '/assets/illustrations/skipped-job_empty-29a8a37d8a61d1b6f68cf3484f9024e53cd6eb95e28eae3554f8011a1146bf27.svg',
- size: 'svg-430',
- title: 'This job does not have a trace.',
- },
- favicon:
- '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
- action: {
- icon: 'retry',
- title: 'Retry',
- path: '/root/mr-widgets/-/jobs/1260/retry',
- method: 'post',
- button_title: 'Retry this job',
- },
- },
- recoverable: false,
- },
- ],
- project: {
- id: 23,
- name: 'mr-widgets',
- full_path: '/root/mr-widgets',
- full_name: 'Administrator / mr-widgets',
- },
- triggered_by: null,
- triggered: [],
- },
- pipelineScheduleUrl: 'foo',
- pipelineKey: 'id',
- viewType: 'root',
- };
-};
-
-export const mockFailedJobsQueryResponse = {
- data: {
- project: {
- __typename: 'Project',
- id: 'gid://gitlab/Project/20',
- pipeline: {
- __typename: 'Pipeline',
- id: 'gid://gitlab/Ci::Pipeline/300',
- jobs: {
- __typename: 'CiJobConnection',
- nodes: [
- {
- __typename: 'CiJob',
- status: 'FAILED',
- detailedStatus: {
- __typename: 'DetailedStatus',
- id: 'failed-1848-1848',
- detailsPath: '/root/ci-project/-/jobs/1848',
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- tooltip: 'failed - (script failure)',
- action: {
- __typename: 'StatusAction',
- id: 'Ci::Build-failed-1848',
- buttonTitle: 'Retry this job',
- icon: 'retry',
- method: 'post',
- path: '/root/ci-project/-/jobs/1848/retry',
- title: 'Retry',
- },
- },
- id: 'gid://gitlab/Ci::Build/1848',
- stage: {
- __typename: 'CiStage',
- id: 'gid://gitlab/Ci::Stage/358',
- name: 'build',
- },
- name: 'wait_job',
- retryable: true,
- userPermissions: {
- __typename: 'JobPermissions',
- readBuild: true,
- updateBuild: true,
- },
- trace: {
- htmlSummary: '<span>Html Summary</span>',
- },
- failureMessage: 'Failed',
- },
- {
- __typename: 'CiJob',
- status: 'FAILED',
- detailedStatus: {
- __typename: 'DetailedStatus',
- id: 'failed-1710-1710',
- detailsPath: '/root/ci-project/-/jobs/1710',
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- tooltip: 'failed - (script failure) (retried)',
- action: null,
- },
- id: 'gid://gitlab/Ci::Build/1710',
- stage: {
- __typename: 'CiStage',
- id: 'gid://gitlab/Ci::Stage/358',
- name: 'build',
- },
- name: 'wait_job',
- retryable: false,
- userPermissions: {
- __typename: 'JobPermissions',
- readBuild: true,
- updateBuild: true,
- },
- trace: null,
- failureMessage: 'Failed',
- },
- ],
- },
- },
- },
- },
-};
-
-export const mockFailedJobsData = [
- {
- __typename: 'CiJob',
- status: 'FAILED',
- detailedStatus: {
- __typename: 'DetailedStatus',
- id: 'failed-1848-1848',
- detailsPath: '/root/ci-project/-/jobs/1848',
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- tooltip: 'failed - (script failure)',
- action: {
- __typename: 'StatusAction',
- id: 'Ci::Build-failed-1848',
- buttonTitle: 'Retry this job',
- icon: 'retry',
- method: 'post',
- path: '/root/ci-project/-/jobs/1848/retry',
- title: 'Retry',
- },
- },
- id: 'gid://gitlab/Ci::Build/1848',
- stage: {
- __typename: 'CiStage',
- id: 'gid://gitlab/Ci::Stage/358',
- name: 'build',
- },
- name: 'wait_job',
- retryable: true,
- userPermissions: {
- __typename: 'JobPermissions',
- readBuild: true,
- updateBuild: true,
- },
- trace: {
- htmlSummary: '<span>Html Summary</span>',
- },
- failureMessage: 'Job failed',
- _showDetails: true,
- },
- {
- __typename: 'CiJob',
- status: 'FAILED',
- detailedStatus: {
- __typename: 'DetailedStatus',
- id: 'failed-1710-1710',
- detailsPath: '/root/ci-project/-/jobs/1710',
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- tooltip: 'failed - (script failure) (retried)',
- action: null,
- },
- id: 'gid://gitlab/Ci::Build/1710',
- stage: {
- __typename: 'CiStage',
- id: 'gid://gitlab/Ci::Stage/358',
- name: 'build',
- },
- name: 'wait_job',
- retryable: false,
- userPermissions: {
- __typename: 'JobPermissions',
- readBuild: true,
- updateBuild: true,
- },
- trace: null,
- failureMessage: 'Job failed',
- _showDetails: true,
- },
-];
-
-export const mockFailedJobsDataNoPermission = [
- {
- ...mockFailedJobsData[0],
- userPermissions: { __typename: 'JobPermissions', readBuild: false, updateBuild: false },
- },
-];
-
-export const successRetryMutationResponse = {
- data: {
- jobRetry: {
- job: {
- __typename: 'CiJob',
- id: '"gid://gitlab/Ci::Build/1985"',
- detailedStatus: {
- detailsPath: '/root/project/-/jobs/1985',
- id: 'pending-1985-1985',
- __typename: 'DetailedStatus',
- },
- },
- errors: [],
- __typename: 'JobRetryPayload',
- },
- },
-};
-
-export const failedRetryMutationResponse = {
- data: {
- jobRetry: {
- job: {},
- errors: ['New Error'],
- __typename: 'JobRetryPayload',
- },
- },
-};
diff --git a/spec/frontend/pipelines/nav_controls_spec.js b/spec/frontend/pipelines/nav_controls_spec.js
deleted file mode 100644
index 15de7dc51f1..00000000000
--- a/spec/frontend/pipelines/nav_controls_spec.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import NavControls from '~/pipelines/components/pipelines_list/nav_controls.vue';
-
-describe('Pipelines Nav Controls', () => {
- let wrapper;
-
- const createComponent = (props) => {
- wrapper = shallowMountExtended(NavControls, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findRunPipelineButton = () => wrapper.findByTestId('run-pipeline-button');
- const findCiLintButton = () => wrapper.findByTestId('ci-lint-button');
- const findClearCacheButton = () => wrapper.findByTestId('clear-cache-button');
-
- it('should render link to create a new pipeline', () => {
- const mockData = {
- newPipelinePath: 'foo',
- ciLintPath: 'foo',
- resetCachePath: 'foo',
- };
-
- createComponent(mockData);
-
- const runPipelineButton = findRunPipelineButton();
- expect(runPipelineButton.text()).toContain('Run pipeline');
- expect(runPipelineButton.attributes('href')).toBe(mockData.newPipelinePath);
- });
-
- it('should not render link to create pipeline if no path is provided', () => {
- const mockData = {
- helpPagePath: 'foo',
- ciLintPath: 'foo',
- resetCachePath: 'foo',
- };
-
- createComponent(mockData);
-
- expect(findRunPipelineButton().exists()).toBe(false);
- });
-
- it('should render link for CI lint', () => {
- const mockData = {
- newPipelinePath: 'foo',
- helpPagePath: 'foo',
- ciLintPath: 'foo',
- resetCachePath: 'foo',
- };
-
- createComponent(mockData);
- const ciLintButton = findCiLintButton();
-
- expect(ciLintButton.text()).toContain('CI lint');
- expect(ciLintButton.attributes('href')).toBe(mockData.ciLintPath);
- });
-
- describe('Reset Runners Cache', () => {
- beforeEach(() => {
- const mockData = {
- newPipelinePath: 'foo',
- ciLintPath: 'foo',
- resetCachePath: 'foo',
- };
- createComponent(mockData);
- });
-
- it('should render button for resetting runner caches', () => {
- expect(findClearCacheButton().text()).toContain('Clear runner caches');
- });
-
- it('should emit postAction event when reset runner cache button is clicked', () => {
- findClearCacheButton().vm.$emit('click');
-
- expect(wrapper.emitted('resetRunnersCache')).toEqual([['foo']]);
- });
- });
-});
diff --git a/spec/frontend/pipelines/notification/mock_data.js b/spec/frontend/pipelines/notification/mock_data.js
deleted file mode 100644
index e36f391a854..00000000000
--- a/spec/frontend/pipelines/notification/mock_data.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const randomWarning = {
- content: 'another random warning',
- id: 'gid://gitlab/Ci::PipelineMessage/272',
-};
-
-const rootTypeWarning = {
- content: 'root `types` will be removed in 15.0.',
- id: 'gid://gitlab/Ci::PipelineMessage/273',
-};
-
-const typeWarning = {
- content: '`type` will be removed in 15.0.',
- id: 'gid://gitlab/Ci::PipelineMessage/274',
-};
-
-function createWarningMock(warnings) {
- return {
- data: {
- project: {
- id: 'gid://gitlab/Project/28"',
- pipeline: {
- id: 'gid://gitlab/Ci::Pipeline/183',
- warningMessages: warnings,
- },
- },
- },
- };
-}
-
-export const mockWarningsWithoutDeprecation = createWarningMock([randomWarning]);
-export const mockWarningsRootType = createWarningMock([rootTypeWarning]);
-export const mockWarningsType = createWarningMock([typeWarning]);
-export const mockWarningsTypesAll = createWarningMock([rootTypeWarning, typeWarning]);
diff --git a/spec/frontend/pipelines/pipeline_details_header_spec.js b/spec/frontend/pipelines/pipeline_details_header_spec.js
deleted file mode 100644
index 5c75020afad..00000000000
--- a/spec/frontend/pipelines/pipeline_details_header_spec.js
+++ /dev/null
@@ -1,452 +0,0 @@
-import { GlAlert, GlBadge, GlLoadingIcon, GlModal, GlSprintf } from '@gitlab/ui';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import PipelineDetailsHeader from '~/pipelines/components/pipeline_details_header.vue';
-import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL } from '~/pipelines/constants';
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import cancelPipelineMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql';
-import deletePipelineMutation from '~/pipelines/graphql/mutations/delete_pipeline.mutation.graphql';
-import retryPipelineMutation from '~/pipelines/graphql/mutations/retry_pipeline.mutation.graphql';
-import getPipelineDetailsQuery from '~/pipelines/graphql/queries/get_pipeline_header_data.query.graphql';
-import {
- pipelineHeaderSuccess,
- pipelineHeaderRunning,
- pipelineHeaderRunningWithDuration,
- pipelineHeaderFailed,
- pipelineRetryMutationResponseSuccess,
- pipelineCancelMutationResponseSuccess,
- pipelineDeleteMutationResponseSuccess,
- pipelineRetryMutationResponseFailed,
- pipelineCancelMutationResponseFailed,
- pipelineDeleteMutationResponseFailed,
-} from './mock_data';
-
-Vue.use(VueApollo);
-
-describe('Pipeline details header', () => {
- let wrapper;
- let glModalDirective;
-
- const successHandler = jest.fn().mockResolvedValue(pipelineHeaderSuccess);
- const runningHandler = jest.fn().mockResolvedValue(pipelineHeaderRunning);
- const runningHandlerWithDuration = jest.fn().mockResolvedValue(pipelineHeaderRunningWithDuration);
- const failedHandler = jest.fn().mockResolvedValue(pipelineHeaderFailed);
-
- const retryMutationHandlerSuccess = jest
- .fn()
- .mockResolvedValue(pipelineRetryMutationResponseSuccess);
- const cancelMutationHandlerSuccess = jest
- .fn()
- .mockResolvedValue(pipelineCancelMutationResponseSuccess);
- const deleteMutationHandlerSuccess = jest
- .fn()
- .mockResolvedValue(pipelineDeleteMutationResponseSuccess);
- const retryMutationHandlerFailed = jest
- .fn()
- .mockResolvedValue(pipelineRetryMutationResponseFailed);
- const cancelMutationHandlerFailed = jest
- .fn()
- .mockResolvedValue(pipelineCancelMutationResponseFailed);
- const deleteMutationHandlerFailed = jest
- .fn()
- .mockResolvedValue(pipelineDeleteMutationResponseFailed);
-
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findStatus = () => wrapper.findComponent(CiBadgeLink);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findAllBadges = () => wrapper.findAllComponents(GlBadge);
- const findDeleteModal = () => wrapper.findComponent(GlModal);
- const findCreatedTimeAgo = () => wrapper.findByTestId('pipeline-created-time-ago');
- const findFinishedTimeAgo = () => wrapper.findByTestId('pipeline-finished-time-ago');
- const findPipelineName = () => wrapper.findByTestId('pipeline-name');
- const findCommitTitle = () => wrapper.findByTestId('pipeline-commit-title');
- const findTotalJobs = () => wrapper.findByTestId('total-jobs');
- const findComputeMinutes = () => wrapper.findByTestId('compute-minutes');
- const findCommitLink = () => wrapper.findByTestId('commit-link');
- const findPipelineRunningText = () => wrapper.findByTestId('pipeline-running-text').text();
- const findPipelineRefText = () => wrapper.findByTestId('pipeline-ref-text').text();
- const findRetryButton = () => wrapper.findByTestId('retry-pipeline');
- const findCancelButton = () => wrapper.findByTestId('cancel-pipeline');
- const findDeleteButton = () => wrapper.findByTestId('delete-pipeline');
- const findPipelineUserLink = () => wrapper.findByTestId('pipeline-user-link');
- const findPipelineDuration = () => wrapper.findByTestId('pipeline-duration-text');
-
- const defaultHandlers = [[getPipelineDetailsQuery, successHandler]];
-
- const defaultProvideOptions = {
- pipelineIid: 1,
- paths: {
- pipelinesPath: '/namespace/my-project/-/pipelines',
- fullProject: '/namespace/my-project',
- triggeredByPath: '',
- },
- };
-
- const defaultProps = {
- name: 'Ruby 3.0 master branch pipeline',
- totalJobs: '50',
- computeMinutes: '0.65',
- yamlErrors: 'errors',
- failureReason: 'pipeline failed',
- badges: {
- schedule: true,
- child: false,
- latest: true,
- mergeTrainPipeline: false,
- invalid: false,
- failed: false,
- autoDevops: false,
- detached: false,
- stuck: false,
- },
- refText:
- 'Related merge request <a class="mr-iid" href="/root/ci-project/-/merge_requests/1">!1</a> to merge <a class="ref-name" href="/root/ci-project/-/commits/test">test</a>',
- };
-
- const createMockApolloProvider = (handlers) => {
- return createMockApollo(handlers);
- };
-
- const createComponent = (handlers = defaultHandlers, props = defaultProps) => {
- glModalDirective = jest.fn();
-
- wrapper = shallowMountExtended(PipelineDetailsHeader, {
- provide: {
- ...defaultProvideOptions,
- },
- propsData: {
- ...props,
- },
- directives: {
- glModal: {
- bind(_, { value }) {
- glModalDirective(value);
- },
- },
- },
- stubs: { GlSprintf },
- apolloProvider: createMockApolloProvider(handlers),
- });
- };
-
- describe('loading state', () => {
- it('shows a loading state while graphQL is fetching initial data', () => {
- createComponent();
-
- expect(findLoadingIcon().exists()).toBe(true);
- });
- });
-
- describe('defaults', () => {
- beforeEach(async () => {
- createComponent();
-
- await waitForPromises();
- });
-
- it('does not display loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('displays pipeline status', () => {
- expect(findStatus().exists()).toBe(true);
- });
-
- it('displays pipeline name', () => {
- expect(findPipelineName().text()).toBe(defaultProps.name);
- });
-
- it('displays total jobs', () => {
- expect(findTotalJobs().text()).toBe('50 Jobs');
- });
-
- it('has link to commit', () => {
- const {
- data: {
- project: { pipeline },
- },
- } = pipelineHeaderSuccess;
-
- expect(findCommitLink().attributes('href')).toBe(pipeline.commit.webPath);
- });
-
- it('displays correct badges', () => {
- expect(findAllBadges()).toHaveLength(2);
- expect(wrapper.findByText('latest').exists()).toBe(true);
- expect(wrapper.findByText('Scheduled').exists()).toBe(true);
- });
-
- it('displays ref text', () => {
- expect(findPipelineRefText()).toBe('Related merge request !1 to merge test');
- });
-
- it('displays pipeline user link with required user popover attributes', () => {
- const {
- data: {
- project: {
- pipeline: { user },
- },
- },
- } = pipelineHeaderSuccess;
-
- const userId = getIdFromGraphQLId(user.id).toString();
-
- expect(findPipelineUserLink().classes()).toContain('js-user-link');
- expect(findPipelineUserLink().attributes('data-user-id')).toBe(userId);
- expect(findPipelineUserLink().attributes('data-username')).toBe(user.username);
- expect(findPipelineUserLink().attributes('href')).toBe(user.webUrl);
- });
- });
-
- describe('without pipeline name', () => {
- it('displays commit title', async () => {
- createComponent(defaultHandlers, { ...defaultProps, name: '' });
-
- await waitForPromises();
-
- const expectedTitle = pipelineHeaderSuccess.data.project.pipeline.commit.title;
-
- expect(findPipelineName().exists()).toBe(false);
- expect(findCommitTitle().text()).toBe(expectedTitle);
- });
- });
-
- describe('finished pipeline', () => {
- it('displays compute minutes when not zero', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(findComputeMinutes().text()).toBe('0.65');
- });
-
- it('does not display compute minutes when zero', async () => {
- createComponent(defaultHandlers, { ...defaultProps, computeMinutes: '0.0' });
-
- await waitForPromises();
-
- expect(findComputeMinutes().exists()).toBe(false);
- });
-
- it('does not display created time ago', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(findCreatedTimeAgo().exists()).toBe(false);
- });
-
- it('displays finished time ago', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(findFinishedTimeAgo().exists()).toBe(true);
- });
-
- it('displays pipeline duartion text', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(findPipelineDuration().text()).toBe(
- '120 minutes 10 seconds, queued for 3,600 seconds',
- );
- });
- });
-
- describe('running pipeline', () => {
- beforeEach(async () => {
- createComponent([[getPipelineDetailsQuery, runningHandler]]);
-
- await waitForPromises();
- });
-
- it('does not display compute minutes', () => {
- expect(findComputeMinutes().exists()).toBe(false);
- });
-
- it('does not display finished time ago', () => {
- expect(findFinishedTimeAgo().exists()).toBe(false);
- });
-
- it('does not display pipeline duration text', () => {
- expect(findPipelineDuration().exists()).toBe(false);
- });
-
- it('displays pipeline running text', () => {
- expect(findPipelineRunningText()).toBe('In progress, queued for 3,600 seconds');
- });
-
- it('displays created time ago', () => {
- expect(findCreatedTimeAgo().exists()).toBe(true);
- });
- });
-
- describe('running pipeline with duration', () => {
- beforeEach(async () => {
- createComponent([[getPipelineDetailsQuery, runningHandlerWithDuration]]);
-
- await waitForPromises();
- });
-
- it('does not display pipeline duration text', () => {
- expect(findPipelineDuration().exists()).toBe(false);
- });
- });
-
- describe('actions', () => {
- describe('retry action', () => {
- beforeEach(async () => {
- createComponent([
- [getPipelineDetailsQuery, failedHandler],
- [retryPipelineMutation, retryMutationHandlerSuccess],
- ]);
-
- await waitForPromises();
- });
-
- it('should call retryPipeline Mutation with pipeline id', () => {
- findRetryButton().vm.$emit('click');
-
- expect(retryMutationHandlerSuccess).toHaveBeenCalledWith({
- id: pipelineHeaderFailed.data.project.pipeline.id,
- });
- expect(findAlert().exists()).toBe(false);
- });
-
- it('should render retry action tooltip', () => {
- expect(findRetryButton().attributes('title')).toBe(BUTTON_TOOLTIP_RETRY);
- });
- });
-
- describe('retry action failed', () => {
- beforeEach(async () => {
- createComponent([
- [getPipelineDetailsQuery, failedHandler],
- [retryPipelineMutation, retryMutationHandlerFailed],
- ]);
-
- await waitForPromises();
- });
-
- it('should display error message on failure', async () => {
- findRetryButton().vm.$emit('click');
-
- await waitForPromises();
-
- expect(findAlert().exists()).toBe(true);
- });
-
- it('retry button loading state should reset on error', async () => {
- findRetryButton().vm.$emit('click');
-
- await nextTick();
-
- expect(findRetryButton().props('loading')).toBe(true);
-
- await waitForPromises();
-
- expect(findRetryButton().props('loading')).toBe(false);
- });
- });
-
- describe('cancel action', () => {
- it('should call cancelPipeline Mutation with pipeline id', async () => {
- createComponent([
- [getPipelineDetailsQuery, runningHandler],
- [cancelPipelineMutation, cancelMutationHandlerSuccess],
- ]);
-
- await waitForPromises();
-
- findCancelButton().vm.$emit('click');
-
- expect(cancelMutationHandlerSuccess).toHaveBeenCalledWith({
- id: pipelineHeaderRunning.data.project.pipeline.id,
- });
- expect(findAlert().exists()).toBe(false);
- });
-
- it('should render cancel action tooltip', async () => {
- createComponent([
- [getPipelineDetailsQuery, runningHandler],
- [cancelPipelineMutation, cancelMutationHandlerSuccess],
- ]);
-
- await waitForPromises();
-
- expect(findCancelButton().attributes('title')).toBe(BUTTON_TOOLTIP_CANCEL);
- });
-
- it('should display error message on failure', async () => {
- createComponent([
- [getPipelineDetailsQuery, runningHandler],
- [cancelPipelineMutation, cancelMutationHandlerFailed],
- ]);
-
- await waitForPromises();
-
- findCancelButton().vm.$emit('click');
-
- await waitForPromises();
-
- expect(findAlert().exists()).toBe(true);
- });
- });
-
- describe('delete action', () => {
- it('displays delete modal when clicking on delete and does not call the delete action', async () => {
- createComponent([
- [getPipelineDetailsQuery, successHandler],
- [deletePipelineMutation, deleteMutationHandlerSuccess],
- ]);
-
- await waitForPromises();
-
- findDeleteButton().vm.$emit('click');
-
- const modalId = 'pipeline-delete-modal';
-
- expect(findDeleteModal().props('modalId')).toBe(modalId);
- expect(glModalDirective).toHaveBeenCalledWith(modalId);
- expect(deleteMutationHandlerSuccess).not.toHaveBeenCalled();
- expect(findAlert().exists()).toBe(false);
- });
-
- it('should call deletePipeline Mutation with pipeline id when modal is submitted', async () => {
- createComponent([
- [getPipelineDetailsQuery, successHandler],
- [deletePipelineMutation, deleteMutationHandlerSuccess],
- ]);
-
- await waitForPromises();
-
- findDeleteModal().vm.$emit('primary');
-
- expect(deleteMutationHandlerSuccess).toHaveBeenCalledWith({
- id: pipelineHeaderSuccess.data.project.pipeline.id,
- });
- });
-
- it('should display error message on failure', async () => {
- createComponent([
- [getPipelineDetailsQuery, successHandler],
- [deletePipelineMutation, deleteMutationHandlerFailed],
- ]);
-
- await waitForPromises();
-
- findDeleteModal().vm.$emit('primary');
-
- await waitForPromises();
-
- expect(findAlert().exists()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js b/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
deleted file mode 100644
index 123f2e011c3..00000000000
--- a/spec/frontend/pipelines/pipeline_graph/pipeline_graph_spec.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import { GlAlert } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { setHTMLFixture } from 'helpers/fixtures';
-import { CI_CONFIG_STATUS_VALID } from '~/ci/pipeline_editor/constants';
-import LinksInner from '~/pipelines/components/graph_shared/links_inner.vue';
-import LinksLayer from '~/pipelines/components/graph_shared/links_layer.vue';
-import JobPill from '~/pipelines/components/pipeline_graph/job_pill.vue';
-import PipelineGraph from '~/pipelines/components/pipeline_graph/pipeline_graph.vue';
-import StageName from '~/pipelines/components/pipeline_graph/stage_name.vue';
-import { pipelineData, singleStageData } from './mock_data';
-
-describe('pipeline graph component', () => {
- const defaultProps = { pipelineData };
- let wrapper;
-
- const containerId = 'pipeline-graph-container-0';
- setHTMLFixture(`<div id="${containerId}"></div>`);
-
- const createComponent = (props = defaultProps) => {
- return shallowMount(PipelineGraph, {
- propsData: {
- ...props,
- },
- stubs: { LinksLayer, LinksInner },
- data() {
- return {
- measurements: {
- width: 1000,
- height: 1000,
- },
- };
- },
- });
- };
-
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findAllJobPills = () => wrapper.findAllComponents(JobPill);
- const findAllStageNames = () => wrapper.findAllComponents(StageName);
- const findLinksLayer = () => wrapper.findComponent(LinksLayer);
- const findPipelineGraph = () => wrapper.find('[data-testid="graph-container"]');
-
- describe('with `VALID` status', () => {
- beforeEach(() => {
- wrapper = createComponent({
- pipelineData: {
- status: CI_CONFIG_STATUS_VALID,
- stages: [{ name: 'hello', groups: [] }],
- },
- });
- });
-
- it('renders the graph with no status error', () => {
- expect(findAlert().exists()).toBe(false);
- expect(findPipelineGraph().exists()).toBe(true);
- expect(findLinksLayer().exists()).toBe(true);
- });
- });
-
- describe('with only one stage', () => {
- beforeEach(() => {
- wrapper = createComponent({ pipelineData: singleStageData });
- });
-
- it('renders the right number of stage titles', () => {
- const expectedStagesLength = singleStageData.stages.length;
-
- expect(findAllStageNames()).toHaveLength(expectedStagesLength);
- });
-
- it('renders the right number of job pills', () => {
- // We count the number of jobs in the mock data
- const expectedJobsLength = singleStageData.stages.reduce((acc, val) => {
- return acc + val.groups.length;
- }, 0);
-
- expect(findAllJobPills()).toHaveLength(expectedJobsLength);
- });
- });
-
- describe('with multiple stages and jobs', () => {
- beforeEach(() => {
- wrapper = createComponent();
- });
-
- it('renders the right number of stage titles', () => {
- const expectedStagesLength = pipelineData.stages.length;
-
- expect(findAllStageNames()).toHaveLength(expectedStagesLength);
- });
-
- it('renders the right number of job pills', () => {
- // We count the number of jobs in the mock data
- const expectedJobsLength = pipelineData.stages.reduce((acc, val) => {
- return acc + val.groups.length;
- }, 0);
-
- expect(findAllJobPills()).toHaveLength(expectedJobsLength);
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipeline_graph/utils_spec.js b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
deleted file mode 100644
index 96b18fcf96f..00000000000
--- a/spec/frontend/pipelines/pipeline_graph/utils_spec.js
+++ /dev/null
@@ -1,197 +0,0 @@
-import { createJobsHash, generateJobNeedsDict, getPipelineDefaultTab } from '~/pipelines/utils';
-import { validPipelineTabNames, pipelineTabName } from '~/pipelines/constants';
-
-describe('utils functions', () => {
- const jobName1 = 'build_1';
- const jobName2 = 'build_2';
- const jobName3 = 'test_1';
- const jobName4 = 'deploy_1';
- const job1 = { name: jobName1, script: 'echo hello', stage: 'build' };
- const job2 = { name: jobName2, script: 'echo build', stage: 'build' };
- const job3 = {
- name: jobName3,
- script: 'echo test',
- stage: 'test',
- needs: [jobName1, jobName2],
- };
- const job4 = {
- name: jobName4,
- script: 'echo deploy',
- stage: 'deploy',
- needs: [jobName3],
- };
- const userDefinedStage = 'myStage';
-
- const pipelineGraphData = {
- stages: [
- {
- name: userDefinedStage,
- groups: [],
- },
- {
- name: job4.stage,
- groups: [
- {
- name: jobName4,
- jobs: [{ ...job4 }],
- },
- ],
- },
- {
- name: job1.stage,
- groups: [
- {
- name: jobName1,
- jobs: [{ ...job1 }],
- },
- {
- name: jobName2,
- jobs: [{ ...job2 }],
- },
- ],
- },
- {
- name: job3.stage,
- groups: [
- {
- name: jobName3,
- jobs: [{ ...job3 }],
- },
- ],
- },
- ],
- };
-
- describe('createJobsHash', () => {
- it('returns an empty object if there are no jobs received as argument', () => {
- expect(createJobsHash([])).toEqual({});
- });
-
- it('returns a hash with the jobname as key and all its data as value', () => {
- const jobs = {
- [jobName1]: { jobs: [job1], name: jobName1, needs: [] },
- [jobName2]: { jobs: [job2], name: jobName2, needs: [] },
- [jobName3]: { jobs: [job3], name: jobName3, needs: job3.needs },
- [jobName4]: { jobs: [job4], name: jobName4, needs: job4.needs },
- };
-
- expect(createJobsHash(pipelineGraphData.stages)).toEqual(jobs);
- });
- });
-
- describe('generateJobNeedsDict', () => {
- it('generates an empty object if it receives no jobs', () => {
- expect(generateJobNeedsDict({})).toEqual({});
- });
-
- it('generates a dict with empty needs if there are no dependencies', () => {
- const smallGraph = {
- [jobName1]: job1,
- [jobName2]: job2,
- };
-
- expect(generateJobNeedsDict(smallGraph)).toEqual({
- [jobName1]: [],
- [jobName2]: [],
- });
- });
-
- it('generates a dict where key is the a job and its value is an array of all its needs', () => {
- const jobsWithNeeds = {
- [jobName1]: job1,
- [jobName2]: job2,
- [jobName3]: job3,
- [jobName4]: job4,
- };
-
- expect(generateJobNeedsDict(jobsWithNeeds)).toEqual({
- [jobName1]: [],
- [jobName2]: [],
- [jobName3]: [jobName1, jobName2],
- [jobName4]: [jobName3, jobName1, jobName2],
- });
- });
-
- it('removes needs which are not in the data', () => {
- const inexistantJobName = 'job5';
- const jobsWithNeeds = {
- [jobName1]: job1,
- [jobName2]: job2,
- [jobName3]: job3,
- [jobName4]: {
- name: jobName4,
- script: 'echo deploy',
- stage: 'deploy',
- needs: [inexistantJobName],
- },
- };
-
- expect(generateJobNeedsDict(jobsWithNeeds)).toEqual({
- [jobName1]: [],
- [jobName2]: [],
- [jobName3]: [jobName1, jobName2],
- [jobName4]: [],
- });
- });
-
- it('handles parallel jobs by adding the group name as a need', () => {
- const size = 3;
- const jobOptimize1 = 'optimize_1';
- const jobPrepareA = 'prepare_a';
- const jobPrepareA1 = `${jobPrepareA} 1/${size}`;
- const jobPrepareA2 = `${jobPrepareA} 2/${size}`;
- const jobPrepareA3 = `${jobPrepareA} 3/${size}`;
-
- const jobsParallel = {
- [jobOptimize1]: {
- jobs: [job1],
- name: [jobOptimize1],
- needs: [jobPrepareA1, jobPrepareA2, jobPrepareA3],
- },
- [jobPrepareA]: { jobs: [], name: jobPrepareA, needs: [], size },
- [jobPrepareA1]: { jobs: [], name: jobPrepareA, needs: [], size },
- [jobPrepareA2]: { jobs: [], name: jobPrepareA, needs: [], size },
- [jobPrepareA3]: { jobs: [], name: jobPrepareA, needs: [], size },
- };
-
- expect(generateJobNeedsDict(jobsParallel)).toEqual({
- [jobOptimize1]: [
- jobPrepareA1,
- // This is the important part, the `jobPrepareA` group name has been
- // added to our list of needs.
- jobPrepareA,
- jobPrepareA2,
- jobPrepareA3,
- ],
- [jobPrepareA]: [],
- [jobPrepareA1]: [],
- [jobPrepareA2]: [],
- [jobPrepareA3]: [],
- });
- });
- });
-
- describe('getPipelineDefaultTab', () => {
- const baseUrl = 'http://gitlab.com/user/multi-projects-small/-/pipelines/332/';
- it('returns pipeline tab name if there is only the base url', () => {
- expect(getPipelineDefaultTab(baseUrl)).toBe(pipelineTabName);
- });
-
- it('returns null if there was no valid last url part', () => {
- expect(getPipelineDefaultTab(`${baseUrl}something`)).toBe(null);
- });
-
- it('returns the correct tab name if present', () => {
- validPipelineTabNames.forEach((tabName) => {
- expect(getPipelineDefaultTab(`${baseUrl}${tabName}`)).toBe(tabName);
- });
- });
-
- it('returns the right value even with query params', () => {
- const [tabName] = validPipelineTabNames;
- expect(getPipelineDefaultTab(`${baseUrl}${tabName}?query="something"&query2="else"`)).toBe(
- tabName,
- );
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipeline_labels_spec.js b/spec/frontend/pipelines/pipeline_labels_spec.js
deleted file mode 100644
index 6a37e36352b..00000000000
--- a/spec/frontend/pipelines/pipeline_labels_spec.js
+++ /dev/null
@@ -1,164 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { trimText } from 'helpers/text_helper';
-import PipelineLabelsComponent from '~/pipelines/components/pipelines_list/pipeline_labels.vue';
-import { mockPipeline } from './mock_data';
-
-const projectPath = 'test/test';
-
-describe('Pipeline label component', () => {
- let wrapper;
-
- const findScheduledTag = () => wrapper.findByTestId('pipeline-url-scheduled');
- const findLatestTag = () => wrapper.findByTestId('pipeline-url-latest');
- const findYamlTag = () => wrapper.findByTestId('pipeline-url-yaml');
- const findStuckTag = () => wrapper.findByTestId('pipeline-url-stuck');
- const findAutoDevopsTag = () => wrapper.findByTestId('pipeline-url-autodevops');
- const findAutoDevopsTagLink = () => wrapper.findByTestId('pipeline-url-autodevops-link');
- const findDetachedTag = () => wrapper.findByTestId('pipeline-url-detached');
- const findFailureTag = () => wrapper.findByTestId('pipeline-url-failure');
- const findForkTag = () => wrapper.findByTestId('pipeline-url-fork');
- const findTrainTag = () => wrapper.findByTestId('pipeline-url-train');
-
- const defaultProps = mockPipeline(projectPath);
-
- const createComponent = (props) => {
- wrapper = shallowMountExtended(PipelineLabelsComponent, {
- propsData: { ...defaultProps, ...props },
- provide: {
- targetProjectFullPath: projectPath,
- },
- });
- };
-
- it('should not render tags when flags are not set', () => {
- createComponent();
-
- expect(findStuckTag().exists()).toBe(false);
- expect(findLatestTag().exists()).toBe(false);
- expect(findYamlTag().exists()).toBe(false);
- expect(findAutoDevopsTag().exists()).toBe(false);
- expect(findFailureTag().exists()).toBe(false);
- expect(findScheduledTag().exists()).toBe(false);
- expect(findForkTag().exists()).toBe(false);
- expect(findTrainTag().exists()).toBe(false);
- });
-
- it('should render the stuck tag when flag is provided', () => {
- const stuckPipeline = defaultProps.pipeline;
- stuckPipeline.flags.stuck = true;
-
- createComponent({
- ...stuckPipeline.pipeline,
- });
-
- expect(findStuckTag().text()).toContain('stuck');
- });
-
- it('should render latest tag when flag is provided', () => {
- const latestPipeline = defaultProps.pipeline;
- latestPipeline.flags.latest = true;
-
- createComponent({
- ...latestPipeline,
- });
-
- expect(findLatestTag().text()).toContain('latest');
- });
-
- it('should render a yaml badge when it is invalid', () => {
- const yamlPipeline = defaultProps.pipeline;
- yamlPipeline.flags.yaml_errors = true;
-
- createComponent({
- ...yamlPipeline,
- });
-
- expect(findYamlTag().text()).toContain('yaml invalid');
- });
-
- it('should render an autodevops badge when flag is provided', () => {
- const autoDevopsPipeline = defaultProps.pipeline;
- autoDevopsPipeline.flags.auto_devops = true;
-
- createComponent({
- ...autoDevopsPipeline,
- });
-
- expect(trimText(findAutoDevopsTag().text())).toBe('Auto DevOps');
-
- expect(findAutoDevopsTagLink().attributes()).toMatchObject({
- href: '/help/topics/autodevops/index.md',
- target: '_blank',
- });
- });
-
- it('should render a detached badge when flag is provided', () => {
- const detachedMRPipeline = defaultProps.pipeline;
- detachedMRPipeline.flags.detached_merge_request_pipeline = true;
-
- createComponent({
- ...detachedMRPipeline,
- });
-
- expect(findDetachedTag().text()).toBe('merge request');
- });
-
- it('should render error badge when pipeline has a failure reason set', () => {
- const failedPipeline = defaultProps.pipeline;
- failedPipeline.flags.failure_reason = true;
- failedPipeline.failure_reason = 'some reason';
-
- createComponent({
- ...failedPipeline,
- });
-
- expect(findFailureTag().text()).toContain('error');
- expect(findFailureTag().attributes('title')).toContain('some reason');
- });
-
- it('should render scheduled badge when pipeline was triggered by a schedule', () => {
- const scheduledPipeline = defaultProps.pipeline;
- scheduledPipeline.source = 'schedule';
-
- createComponent({
- ...scheduledPipeline,
- });
-
- expect(findScheduledTag().exists()).toBe(true);
- expect(findScheduledTag().text()).toContain('Scheduled');
- });
-
- it('should render the fork badge when the pipeline was run in a fork', () => {
- const forkedPipeline = defaultProps.pipeline;
- forkedPipeline.project.full_path = '/test/forked';
-
- createComponent({
- ...forkedPipeline,
- });
-
- expect(findForkTag().exists()).toBe(true);
- expect(findForkTag().text()).toBe('fork');
- });
-
- it('should render the train badge when the pipeline is a merge train pipeline', () => {
- const mergeTrainPipeline = defaultProps.pipeline;
- mergeTrainPipeline.flags.merge_train_pipeline = true;
-
- createComponent({
- ...mergeTrainPipeline,
- });
-
- expect(findTrainTag().text()).toBe('merge train');
- });
-
- it('should not render the train badge when the pipeline is not a merge train pipeline', () => {
- const mergeTrainPipeline = defaultProps.pipeline;
- mergeTrainPipeline.flags.merge_train_pipeline = false;
-
- createComponent({
- ...mergeTrainPipeline,
- });
-
- expect(findTrainTag().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/pipelines/pipeline_multi_actions_spec.js b/spec/frontend/pipelines/pipeline_multi_actions_spec.js
deleted file mode 100644
index 0fdc45a5931..00000000000
--- a/spec/frontend/pipelines/pipeline_multi_actions_spec.js
+++ /dev/null
@@ -1,288 +0,0 @@
-import { nextTick } from 'vue';
-import { GlAlert, GlDropdown, GlSprintf, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { stubComponent } from 'helpers/stub_component';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import PipelineMultiActions, {
- i18n,
-} from '~/pipelines/components/pipelines_list/pipeline_multi_actions.vue';
-import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-
-describe('Pipeline Multi Actions Dropdown', () => {
- let wrapper;
- let mockAxios;
- const focusInputMock = jest.fn();
-
- const artifacts = [
- {
- name: 'job my-artifact',
- path: '/download/path',
- },
- {
- name: 'job-2 my-artifact-2',
- path: '/download/path-two',
- },
- ];
- const newArtifacts = [
- {
- name: 'job-3 my-new-artifact',
- path: '/new/download/path',
- },
- {
- name: 'job-4 my-new-artifact-2',
- path: '/new/download/path-two',
- },
- {
- name: 'job-5 my-new-artifact-3',
- path: '/new/download/path-three',
- },
- ];
- const artifactItemTestId = 'artifact-item';
- const artifactsEndpointPlaceholder = ':pipeline_artifacts_id';
- const artifactsEndpoint = `endpoint/${artifactsEndpointPlaceholder}/artifacts.json`;
- const pipelineId = 108;
-
- const createComponent = () => {
- wrapper = extendedWrapper(
- shallowMount(PipelineMultiActions, {
- provide: {
- artifactsEndpoint,
- artifactsEndpointPlaceholder,
- },
- propsData: {
- pipelineId,
- },
- stubs: {
- GlSprintf,
- GlDropdown,
- GlSearchBoxByType: stubComponent(GlSearchBoxByType, {
- methods: { focusInput: focusInputMock },
- }),
- },
- }),
- );
- };
-
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findAllArtifactItems = () => wrapper.findAllByTestId(artifactItemTestId);
- const findFirstArtifactItem = () => wrapper.findByTestId(artifactItemTestId);
- const findAllArtifactItemsData = () =>
- wrapper.findAllByTestId(artifactItemTestId).wrappers.map((x) => ({
- path: x.attributes('href'),
- name: x.text(),
- }));
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
- const findEmptyMessage = () => wrapper.findByTestId('artifacts-empty-message');
- const findWarning = () => wrapper.findByTestId('artifacts-fetch-warning');
- const changePipelineId = (newId) => wrapper.setProps({ pipelineId: newId });
-
- beforeEach(() => {
- mockAxios = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mockAxios.restore();
- });
-
- it('should render the dropdown', () => {
- createComponent();
-
- expect(findDropdown().exists()).toBe(true);
- });
-
- describe('Artifacts', () => {
- const endpoint = artifactsEndpoint.replace(artifactsEndpointPlaceholder, pipelineId);
-
- describe('while loading artifacts', () => {
- beforeEach(() => {
- mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_OK, { artifacts });
- });
-
- it('should render a loading spinner and no empty message', async () => {
- createComponent();
-
- findDropdown().vm.$emit('show');
- await nextTick();
-
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findEmptyMessage().exists()).toBe(false);
- });
- });
-
- describe('artifacts loaded successfully', () => {
- describe('artifacts exist', () => {
- beforeEach(async () => {
- mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_OK, { artifacts });
-
- createComponent();
-
- findDropdown().vm.$emit('show');
- await waitForPromises();
- });
-
- it('should fetch artifacts and show search box on dropdown click', () => {
- expect(mockAxios.history.get).toHaveLength(1);
- expect(findSearchBox().exists()).toBe(true);
- });
-
- it('should focus the search box when opened with artifacts', () => {
- findDropdown().vm.$emit('shown');
-
- expect(focusInputMock).toHaveBeenCalled();
- });
-
- it('should render all the provided artifacts when search query is empty', () => {
- findSearchBox().vm.$emit('input', '');
-
- expect(findAllArtifactItems()).toHaveLength(artifacts.length);
- expect(findEmptyMessage().exists()).toBe(false);
- });
-
- it('should render filtered artifacts when search query is not empty', async () => {
- findSearchBox().vm.$emit('input', 'job-2');
- await waitForPromises();
-
- expect(findAllArtifactItems()).toHaveLength(1);
- expect(findEmptyMessage().exists()).toBe(false);
- });
-
- it('should render the correct artifact name and path', () => {
- expect(findFirstArtifactItem().attributes('href')).toBe(artifacts[0].path);
- expect(findFirstArtifactItem().text()).toBe(artifacts[0].name);
- });
-
- describe('when opened again with new artifacts', () => {
- describe('with a successful refetch', () => {
- beforeEach(async () => {
- mockAxios.resetHistory();
- mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_OK, { artifacts: newArtifacts });
-
- findDropdown().vm.$emit('show');
- await nextTick();
- });
-
- it('should hide list and render a loading spinner on dropdown click', () => {
- expect(findAllArtifactItems()).toHaveLength(0);
- expect(findLoadingIcon().exists()).toBe(true);
- });
-
- it('should not render warning or empty message while loading', () => {
- expect(findEmptyMessage().exists()).toBe(false);
- expect(findWarning().exists()).toBe(false);
- });
-
- it('should render the correct new list', async () => {
- await waitForPromises();
-
- expect(findAllArtifactItemsData()).toEqual(newArtifacts);
- });
- });
-
- describe('with a failing refetch', () => {
- beforeEach(async () => {
- mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
-
- findDropdown().vm.$emit('show');
- await waitForPromises();
- });
-
- it('should render warning', () => {
- expect(findWarning().text()).toBe(i18n.artifactsFetchWarningMessage);
- });
-
- it('should render old list', () => {
- expect(findAllArtifactItemsData()).toEqual(artifacts);
- });
- });
- });
-
- describe('pipeline id has changed', () => {
- const newEndpoint = artifactsEndpoint.replace(
- artifactsEndpointPlaceholder,
- pipelineId + 1,
- );
-
- beforeEach(() => {
- changePipelineId(pipelineId + 1);
- });
-
- describe('followed by a failing request', () => {
- beforeEach(async () => {
- mockAxios.onGet(newEndpoint).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
-
- findDropdown().vm.$emit('show');
- await waitForPromises();
- });
-
- it('should render error message and no warning', () => {
- expect(findWarning().exists()).toBe(false);
- expect(findAlert().text()).toBe(i18n.artifactsFetchErrorMessage);
- });
-
- it('should clear list', () => {
- expect(findAllArtifactItems()).toHaveLength(0);
- });
- });
- });
- });
-
- describe('artifacts list is empty', () => {
- beforeEach(() => {
- mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_OK, { artifacts: [] });
- });
-
- it('should render empty message and no search box when no artifacts are found', async () => {
- createComponent();
-
- findDropdown().vm.$emit('show');
- await waitForPromises();
-
- expect(findEmptyMessage().exists()).toBe(true);
- expect(findSearchBox().exists()).toBe(false);
- expect(findLoadingIcon().exists()).toBe(false);
- });
- });
- });
-
- describe('with a failing request', () => {
- beforeEach(() => {
- mockAxios.onGet(endpoint).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
- });
-
- it('should render an error message', async () => {
- createComponent();
- findDropdown().vm.$emit('show');
- await waitForPromises();
-
- const error = findAlert();
- expect(error.exists()).toBe(true);
- expect(error.text()).toBe(i18n.artifactsFetchErrorMessage);
- });
- });
- });
-
- describe('tracking', () => {
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks artifacts dropdown click', () => {
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
-
- createComponent();
-
- findDropdown().vm.$emit('show');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_artifacts_dropdown', {
- label: TRACKING_CATEGORIES.table,
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipeline_operations_spec.js b/spec/frontend/pipelines/pipeline_operations_spec.js
deleted file mode 100644
index b2191453824..00000000000
--- a/spec/frontend/pipelines/pipeline_operations_spec.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import PipelinesManualActions from '~/pipelines/components/pipelines_list/pipelines_manual_actions.vue';
-import PipelineMultiActions from '~/pipelines/components/pipelines_list/pipeline_multi_actions.vue';
-import PipelineOperations from '~/pipelines/components/pipelines_list/pipeline_operations.vue';
-import eventHub from '~/pipelines/event_hub';
-
-describe('Pipeline operations', () => {
- let wrapper;
-
- const defaultProps = {
- pipeline: {
- id: 329,
- iid: 234,
- details: {
- has_manual_actions: true,
- has_scheduled_actions: false,
- },
- flags: {
- retryable: true,
- cancelable: true,
- },
- cancel_path: '/root/ci-project/-/pipelines/329/cancel',
- retry_path: '/root/ci-project/-/pipelines/329/retry',
- },
- };
-
- const createComponent = (props = defaultProps) => {
- wrapper = shallowMountExtended(PipelineOperations, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findManualActions = () => wrapper.findComponent(PipelinesManualActions);
- const findMultiActions = () => wrapper.findComponent(PipelineMultiActions);
- const findRetryBtn = () => wrapper.findByTestId('pipelines-retry-button');
- const findCancelBtn = () => wrapper.findByTestId('pipelines-cancel-button');
-
- it('should display pipeline manual actions', () => {
- createComponent();
-
- expect(findManualActions().exists()).toBe(true);
- });
-
- it('should display pipeline multi actions', () => {
- createComponent();
-
- expect(findMultiActions().exists()).toBe(true);
- });
-
- describe('events', () => {
- beforeEach(() => {
- createComponent();
-
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- });
-
- it('should emit retryPipeline event', () => {
- findRetryBtn().vm.$emit('click');
-
- expect(eventHub.$emit).toHaveBeenCalledWith(
- 'retryPipeline',
- defaultProps.pipeline.retry_path,
- );
- });
-
- it('should emit openConfirmationModal event', () => {
- findCancelBtn().vm.$emit('click');
-
- expect(eventHub.$emit).toHaveBeenCalledWith('openConfirmationModal', {
- pipeline: defaultProps.pipeline,
- endpoint: defaultProps.pipeline.cancel_path,
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipeline_tabs_spec.js b/spec/frontend/pipelines/pipeline_tabs_spec.js
deleted file mode 100644
index 8d1cd98e981..00000000000
--- a/spec/frontend/pipelines/pipeline_tabs_spec.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import { createAppOptions } from '~/pipelines/pipeline_tabs';
-
-jest.mock('~/lib/utils/url_utility', () => ({
- removeParams: () => 'gitlab.com',
- joinPaths: () => {},
- setUrlFragment: () => {},
-}));
-
-jest.mock('~/pipelines/utils', () => ({
- getPipelineDefaultTab: () => '',
-}));
-
-describe('~/pipelines/pipeline_tabs.js', () => {
- describe('createAppOptions', () => {
- const SELECTOR = 'SELECTOR';
-
- let el;
-
- const createElement = () => {
- el = document.createElement('div');
- el.id = SELECTOR;
- el.dataset.canGenerateCodequalityReports = 'true';
- el.dataset.codequalityReportDownloadPath = 'codequalityReportDownloadPath';
- el.dataset.downloadablePathForReportType = 'downloadablePathForReportType';
- el.dataset.exposeSecurityDashboard = 'true';
- el.dataset.exposeLicenseScanningData = 'true';
- el.dataset.failedJobsCount = 1;
- el.dataset.graphqlResourceEtag = 'graphqlResourceEtag';
- el.dataset.pipelineIid = '123';
- el.dataset.pipelineProjectPath = 'pipelineProjectPath';
-
- document.body.appendChild(el);
- };
-
- afterEach(() => {
- el = null;
- });
-
- it("extracts the properties from the element's dataset", () => {
- createElement();
- const options = createAppOptions(`#${SELECTOR}`, null);
-
- expect(options).toMatchObject({
- el,
- provide: {
- canGenerateCodequalityReports: true,
- codequalityReportDownloadPath: 'codequalityReportDownloadPath',
- downloadablePathForReportType: 'downloadablePathForReportType',
- exposeSecurityDashboard: true,
- exposeLicenseScanningData: true,
- failedJobsCount: '1',
- graphqlResourceEtag: 'graphqlResourceEtag',
- pipelineIid: '123',
- pipelineProjectPath: 'pipelineProjectPath',
- },
- });
- });
-
- it('returns `null` if el does not exist', () => {
- expect(createAppOptions('foo', null)).toBe(null);
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipeline_triggerer_spec.js b/spec/frontend/pipelines/pipeline_triggerer_spec.js
deleted file mode 100644
index 856c0484075..00000000000
--- a/spec/frontend/pipelines/pipeline_triggerer_spec.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import { GlAvatar, GlAvatarLink } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import pipelineTriggerer from '~/pipelines/components/pipelines_list/pipeline_triggerer.vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-
-describe('Pipelines Triggerer', () => {
- let wrapper;
-
- const mockData = {
- pipeline: {
- user: {
- name: 'foo',
- avatar_url: '/avatar',
- path: '/path',
- },
- },
- };
-
- const createComponent = (props) => {
- wrapper = shallowMountExtended(pipelineTriggerer, {
- propsData: {
- ...props,
- },
- directives: {
- GlTooltip: createMockDirective('gl-tooltip'),
- },
- });
- };
-
- const findAvatarLink = () => wrapper.findComponent(GlAvatarLink);
- const findAvatar = () => wrapper.findComponent(GlAvatar);
- const findTriggerer = () => wrapper.findByText('API');
-
- describe('when user was a triggerer', () => {
- beforeEach(() => {
- createComponent(mockData);
- });
-
- it('should render pipeline triggerer table cell', () => {
- expect(wrapper.find('[data-testid="pipeline-triggerer"]').exists()).toBe(true);
- });
-
- it('should render only user avatar', () => {
- expect(findAvatarLink().exists()).toBe(true);
- expect(findTriggerer().exists()).toBe(false);
- });
-
- it('should set correct props on avatar link component', () => {
- expect(findAvatarLink().attributes()).toMatchObject({
- title: mockData.pipeline.user.name,
- href: mockData.pipeline.user.path,
- });
- });
-
- it('should add tooltip to avatar link', () => {
- const tooltip = getBinding(findAvatarLink().element, 'gl-tooltip');
-
- expect(tooltip).toBeDefined();
- });
-
- it('should set correct props on avatar component', () => {
- expect(findAvatar().attributes().src).toBe(mockData.pipeline.user.avatar_url);
- });
- });
-
- describe('when API was a triggerer', () => {
- beforeEach(() => {
- createComponent({ pipeline: {} });
- });
-
- it('should render label only', () => {
- expect(findAvatarLink().exists()).toBe(false);
- expect(findTriggerer().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipeline_url_spec.js b/spec/frontend/pipelines/pipeline_url_spec.js
deleted file mode 100644
index 797ec676ccc..00000000000
--- a/spec/frontend/pipelines/pipeline_url_spec.js
+++ /dev/null
@@ -1,184 +0,0 @@
-import { merge } from 'lodash';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import PipelineUrlComponent from '~/pipelines/components/pipelines_list/pipeline_url.vue';
-import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
-import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-import { mockPipeline, mockPipelineBranch, mockPipelineTag } from './mock_data';
-
-const projectPath = 'test/test';
-
-describe('Pipeline Url Component', () => {
- let wrapper;
- let trackingSpy;
-
- const findTableCell = () => wrapper.findByTestId('pipeline-url-table-cell');
- const findPipelineUrlLink = () => wrapper.findByTestId('pipeline-url-link');
- const findRefName = () => wrapper.findByTestId('merge-request-ref');
- const findCommitShortSha = () => wrapper.findByTestId('commit-short-sha');
- const findCommitIcon = () => wrapper.findByTestId('commit-icon');
- const findCommitIconType = () => wrapper.findByTestId('commit-icon-type');
- const findCommitRefName = () => wrapper.findByTestId('commit-ref-name');
-
- const findCommitTitleContainer = () => wrapper.findByTestId('commit-title-container');
- const findPipelineNameContainer = () => wrapper.findByTestId('pipeline-name-container');
- const findCommitTitle = (commitWrapper) => commitWrapper.find('[data-testid="commit-title"]');
-
- const defaultProps = { ...mockPipeline(projectPath), refClass: 'gl-text-black' };
-
- const createComponent = (props) => {
- wrapper = shallowMountExtended(PipelineUrlComponent, {
- propsData: { ...defaultProps, ...props },
- provide: {
- targetProjectFullPath: projectPath,
- },
- });
- };
-
- it('should render pipeline url table cell', () => {
- createComponent();
-
- expect(findTableCell().exists()).toBe(true);
- });
-
- it('should render a link the provided path and id', () => {
- createComponent();
-
- expect(findPipelineUrlLink().attributes('href')).toBe('foo');
-
- expect(findPipelineUrlLink().text()).toBe('#1');
- });
-
- it('should render the pipeline name instead of commit title', () => {
- createComponent(merge(mockPipeline(projectPath), { pipeline: { name: 'Build pipeline' } }));
-
- expect(findCommitTitleContainer().exists()).toBe(false);
- expect(findPipelineNameContainer().exists()).toBe(true);
- expect(findRefName().exists()).toBe(true);
- expect(findCommitShortSha().exists()).toBe(true);
- });
-
- it('should render the commit title when pipeline has no name', () => {
- createComponent();
-
- const commitWrapper = findCommitTitleContainer();
-
- expect(findCommitTitle(commitWrapper).exists()).toBe(true);
- expect(findRefName().exists()).toBe(true);
- expect(findCommitShortSha().exists()).toBe(true);
- expect(findPipelineNameContainer().exists()).toBe(false);
- });
-
- it('should pass the refClass prop to merge request link', () => {
- createComponent();
-
- expect(findRefName().classes()).toContain(defaultProps.refClass);
- });
-
- it('should pass the refClass prop to the commit ref name link', () => {
- createComponent(mockPipelineBranch());
-
- expect(findCommitRefName().classes()).toContain(defaultProps.refClass);
- });
-
- describe('commit user avatar', () => {
- it('renders when commit author exists', () => {
- const pipelineBranch = mockPipelineBranch();
- const { avatar_url: imgSrc, name, path } = pipelineBranch.pipeline.commit.author;
- createComponent(pipelineBranch);
-
- const component = wrapper.findComponent(UserAvatarLink);
- expect(component.exists()).toBe(true);
- expect(component.props()).toMatchObject({
- imgSize: 16,
- imgSrc,
- imgAlt: name,
- linkHref: path,
- tooltipText: name,
- });
- });
-
- it('does not render when commit author does not exist', () => {
- createComponent();
-
- expect(wrapper.findComponent(UserAvatarLink).exists()).toBe(false);
- });
- });
-
- it('should render commit icon tooltip', () => {
- createComponent();
-
- expect(findCommitIcon().attributes('title')).toBe('Commit');
- });
-
- it.each`
- pipeline | expectedTitle
- ${mockPipelineTag()} | ${'Tag'}
- ${mockPipelineBranch()} | ${'Branch'}
- ${mockPipeline()} | ${'Merge Request'}
- `('should render tooltip $expectedTitle for commit icon type', ({ pipeline, expectedTitle }) => {
- createComponent(pipeline);
-
- expect(findCommitIconType().attributes('title')).toBe(expectedTitle);
- });
-
- describe('tracking', () => {
- beforeEach(() => {
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks pipeline id click', () => {
- createComponent();
-
- findPipelineUrlLink().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_pipeline_id', {
- label: TRACKING_CATEGORIES.table,
- });
- });
-
- it('tracks merge request ref click', () => {
- createComponent();
-
- findRefName().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_mr_ref', {
- label: TRACKING_CATEGORIES.table,
- });
- });
-
- it('tracks commit ref name click', () => {
- createComponent(mockPipelineBranch());
-
- findCommitRefName().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_name', {
- label: TRACKING_CATEGORIES.table,
- });
- });
-
- it('tracks commit title click', () => {
- createComponent(merge(mockPipelineBranch(), { pipeline: { name: null } }));
-
- findCommitTitle(findCommitTitleContainer()).vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_title', {
- label: TRACKING_CATEGORIES.table,
- });
- });
-
- it('tracks commit short sha click', () => {
- createComponent(mockPipelineBranch());
-
- findCommitShortSha().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_commit_sha', {
- label: TRACKING_CATEGORIES.table,
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipelines_artifacts_spec.js b/spec/frontend/pipelines/pipelines_artifacts_spec.js
deleted file mode 100644
index 1abc2887682..00000000000
--- a/spec/frontend/pipelines/pipelines_artifacts_spec.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import {
- GlDisclosureDropdown,
- GlDisclosureDropdownItem,
- GlDisclosureDropdownGroup,
- GlSprintf,
-} from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue';
-
-describe('Pipelines Artifacts dropdown', () => {
- let wrapper;
-
- const artifacts = [
- {
- name: 'job my-artifact',
- path: '/download/path',
- },
- {
- name: 'job-2 my-artifact-2',
- path: '/download/path-two',
- },
- ];
- const pipelineId = 108;
-
- const createComponent = ({ mockArtifacts = artifacts } = {}) => {
- wrapper = shallowMount(PipelineArtifacts, {
- propsData: {
- pipelineId,
- artifacts: mockArtifacts,
- },
- stubs: {
- GlSprintf,
- GlDisclosureDropdown,
- GlDisclosureDropdownItem,
- GlDisclosureDropdownGroup,
- },
- });
- };
-
- const findGlDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
- const findFirstGlDropdownItem = () => wrapper.findComponent(GlDisclosureDropdownItem);
-
- it('should render a dropdown with all the provided artifacts', () => {
- createComponent();
-
- const [{ items }] = findGlDropdown().props('items');
- expect(items).toHaveLength(artifacts.length);
- });
-
- it('should render a link with the provided path', () => {
- createComponent();
-
- expect(findFirstGlDropdownItem().props('item').href).toBe(artifacts[0].path);
- expect(findFirstGlDropdownItem().text()).toBe(artifacts[0].name);
- });
-
- describe('with no artifacts', () => {
- it('should not render the dropdown', () => {
- createComponent({ mockArtifacts: [] });
-
- expect(findGlDropdown().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipelines_manual_actions_spec.js b/spec/frontend/pipelines/pipelines_manual_actions_spec.js
deleted file mode 100644
index 82cab88c9eb..00000000000
--- a/spec/frontend/pipelines/pipelines_manual_actions_spec.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import { GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
-import MockAdapter from 'axios-mock-adapter';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import mockPipelineActionsQueryResponse from 'test_fixtures/graphql/pipelines/get_pipeline_actions.query.graphql.json';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
-import PipelinesManualActions from '~/pipelines/components/pipelines_list/pipelines_manual_actions.vue';
-import getPipelineActionsQuery from '~/pipelines/graphql/queries/get_pipeline_actions.query.graphql';
-import { TRACKING_CATEGORIES } from '~/pipelines/constants';
-import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
-
-Vue.use(VueApollo);
-
-jest.mock('~/alert');
-jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
-
-describe('Pipeline manual actions', () => {
- let wrapper;
- let mock;
-
- const queryHandler = jest.fn().mockResolvedValue(mockPipelineActionsQueryResponse);
- const {
- data: {
- project: {
- pipeline: {
- jobs: { nodes },
- },
- },
- },
- } = mockPipelineActionsQueryResponse;
-
- const mockPath = nodes[2].playPath;
-
- const createComponent = (limit = 50) => {
- wrapper = shallowMountExtended(PipelinesManualActions, {
- provide: {
- fullPath: 'root/ci-project',
- manualActionsLimit: limit,
- },
- propsData: {
- iid: 100,
- },
- stubs: {
- GlDropdown,
- },
- apolloProvider: createMockApollo([[getPipelineActionsQuery, queryHandler]]),
- });
- };
-
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findAllCountdowns = () => wrapper.findAllComponents(GlCountdown);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findLimitMessage = () => wrapper.findByTestId('limit-reached-msg');
-
- it('skips calling query on mount', () => {
- createComponent();
-
- expect(queryHandler).not.toHaveBeenCalled();
- });
-
- describe('loading', () => {
- beforeEach(() => {
- createComponent();
-
- findDropdown().vm.$emit('shown');
- });
-
- it('display loading state while actions are being fetched', () => {
- expect(findAllDropdownItems().at(0).text()).toBe('Loading...');
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findAllDropdownItems()).toHaveLength(1);
- });
- });
-
- describe('loaded', () => {
- beforeEach(async () => {
- mock = new MockAdapter(axios);
-
- createComponent();
-
- findDropdown().vm.$emit('shown');
-
- await waitForPromises();
- });
-
- afterEach(() => {
- mock.restore();
- confirmAction.mockReset();
- });
-
- it('displays dropdown with the provided actions', () => {
- expect(findAllDropdownItems()).toHaveLength(3);
- });
-
- it("displays a disabled action when it's not playable", () => {
- expect(findAllDropdownItems().at(0).attributes('disabled')).toBeDefined();
- });
-
- describe('on action click', () => {
- it('makes a request and toggles the loading state', async () => {
- mock.onPost(mockPath).reply(HTTP_STATUS_OK);
-
- findAllDropdownItems().at(1).vm.$emit('click');
-
- await nextTick();
-
- expect(findDropdown().props('loading')).toBe(true);
-
- await waitForPromises();
-
- expect(findDropdown().props('loading')).toBe(false);
- });
-
- it('makes a failed request and toggles the loading state', async () => {
- mock.onPost(mockPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
-
- findAllDropdownItems().at(1).vm.$emit('click');
-
- await nextTick();
-
- expect(findDropdown().props('loading')).toBe(true);
-
- await waitForPromises();
-
- expect(findDropdown().props('loading')).toBe(false);
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('tracking', () => {
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks manual actions click', () => {
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
-
- findDropdown().vm.$emit('shown');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_manual_actions', {
- label: TRACKING_CATEGORIES.table,
- });
- });
- });
-
- describe('scheduled jobs', () => {
- beforeEach(() => {
- jest
- .spyOn(Date, 'now')
- .mockImplementation(() => new Date('2063-04-04T00:42:00Z').getTime());
- });
-
- it('makes post request after confirming', async () => {
- mock.onPost(mockPath).reply(HTTP_STATUS_OK);
-
- confirmAction.mockResolvedValueOnce(true);
-
- findAllDropdownItems().at(2).vm.$emit('click');
-
- expect(confirmAction).toHaveBeenCalled();
-
- await waitForPromises();
-
- expect(mock.history.post).toHaveLength(1);
- });
-
- it('does not make post request if confirmation is cancelled', async () => {
- mock.onPost(mockPath).reply(HTTP_STATUS_OK);
-
- confirmAction.mockResolvedValueOnce(false);
-
- findAllDropdownItems().at(2).vm.$emit('click');
-
- expect(confirmAction).toHaveBeenCalled();
-
- await waitForPromises();
-
- expect(mock.history.post).toHaveLength(0);
- });
-
- it('displays the remaining time in the dropdown', () => {
- expect(findAllCountdowns().at(0).props('endDateString')).toBe(nodes[2].scheduledAt);
- });
- });
- });
-
- describe('limit message', () => {
- it('limit message does not show', async () => {
- createComponent();
-
- findDropdown().vm.$emit('shown');
-
- await waitForPromises();
-
- expect(findLimitMessage().exists()).toBe(false);
- });
-
- it('limit message does show', async () => {
- createComponent(3);
-
- findDropdown().vm.$emit('shown');
-
- await waitForPromises();
-
- expect(findLimitMessage().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
deleted file mode 100644
index cc85d6d99e0..00000000000
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ /dev/null
@@ -1,850 +0,0 @@
-import '~/commons';
-import {
- GlButton,
- GlEmptyState,
- GlFilteredSearch,
- GlLoadingIcon,
- GlPagination,
- GlCollapsibleListbox,
-} from '@gitlab/ui';
-import * as Sentry from '@sentry/browser';
-import { mount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import { chunk } from 'lodash';
-import { nextTick } from 'vue';
-import mockPipelinesResponse from 'test_fixtures/pipelines/pipelines.json';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import { TEST_HOST } from 'helpers/test_constants';
-import { mockTracking } from 'helpers/tracking_helper';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import Api from '~/api';
-import { createAlert, VARIANT_WARNING } from '~/alert';
-import setSortPreferenceMutation from '~/issues/list/queries/set_sort_preference.mutation.graphql';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import NavigationControls from '~/pipelines/components/pipelines_list/nav_controls.vue';
-import PipelinesComponent from '~/pipelines/components/pipelines_list/pipelines.vue';
-import PipelinesCiTemplates from '~/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue';
-import PipelinesTableComponent from '~/pipelines/components/pipelines_list/pipelines_table.vue';
-import { RAW_TEXT_WARNING, TRACKING_CATEGORIES } from '~/pipelines/constants';
-import Store from '~/pipelines/stores/pipelines_store';
-import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
-import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
-import {
- setIdTypePreferenceMutationResponse,
- setIdTypePreferenceMutationResponseWithErrors,
-} from 'jest/issues/list/mock_data';
-
-import { stageReply, users, mockSearch, branches } from './mock_data';
-
-jest.mock('@sentry/browser');
-jest.mock('~/alert');
-
-const mockProjectPath = 'twitter/flight';
-const mockProjectId = '21';
-const mockDefaultBranchName = 'main';
-const mockPipelinesEndpoint = `/${mockProjectPath}/pipelines.json`;
-const mockPipelinesIds = mockPipelinesResponse.pipelines.map(({ id }) => id);
-const mockPipelineWithStages = mockPipelinesResponse.pipelines.find(
- (p) => p.details.stages && p.details.stages.length,
-);
-
-describe('Pipelines', () => {
- let wrapper;
- let mockApollo;
- let mock;
- let trackingSpy;
-
- const paths = {
- emptyStateSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
- errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
- noPipelinesSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
- ciLintPath: '/ci/lint',
- resetCachePath: `${mockProjectPath}/settings/ci_cd/reset_cache`,
- newPipelinePath: `${mockProjectPath}/pipelines/new`,
-
- ciRunnerSettingsPath: `${mockProjectPath}/-/settings/ci_cd#js-runners-settings`,
- };
-
- const noPermissions = {
- emptyStateSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
- errorStateSvgPath: '/assets/illustrations/pipelines_failed.svg',
- noPipelinesSvgPath: '/assets/illustrations/empty-state/empty-pipeline-md.svg',
- };
-
- const defaultProps = {
- hasGitlabCi: true,
- canCreatePipeline: true,
- ...paths,
- };
-
- const findFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
- const findEmptyState = () => wrapper.findComponent(GlEmptyState);
- const findNavigationTabs = () => wrapper.findComponent(NavigationTabs);
- const findNavigationControls = () => wrapper.findComponent(NavigationControls);
- const findPipelinesTable = () => wrapper.findComponent(PipelinesTableComponent);
- const findTablePagination = () => wrapper.findComponent(TablePagination);
- const findPipelineKeyCollapsibleBoxVue = () => wrapper.findComponent(GlCollapsibleListbox);
-
- const findTab = (tab) => wrapper.findByTestId(`pipelines-tab-${tab}`);
- const findPipelineKeyCollapsibleBox = () => wrapper.findByTestId('pipeline-key-collapsible-box');
- const findRunPipelineButton = () => wrapper.findByTestId('run-pipeline-button');
- const findCiLintButton = () => wrapper.findByTestId('ci-lint-button');
- const findCleanCacheButton = () => wrapper.findByTestId('clear-cache-button');
- const findStagesDropdownToggle = () =>
- wrapper.find('[data-testid="mini-pipeline-graph-dropdown"] .dropdown-toggle');
- const findPipelineUrlLinks = () => wrapper.findAll('[data-testid="pipeline-url-link"]');
-
- const createComponent = (props = defaultProps) => {
- const { mutationMock, ...restProps } = props;
- mockApollo = createMockApollo([[setSortPreferenceMutation, mutationMock]]);
-
- wrapper = extendedWrapper(
- mount(PipelinesComponent, {
- provide: {
- pipelineEditorPath: '',
- suggestedCiTemplates: [],
- ciRunnerSettingsPath: paths.ciRunnerSettingsPath,
- anyRunnersAvailable: true,
- },
- propsData: {
- store: new Store(),
- projectId: mockProjectId,
- defaultBranchName: mockDefaultBranchName,
- endpoint: mockPipelinesEndpoint,
- params: {},
- ...restProps,
- },
- apolloProvider: mockApollo,
- }),
- );
- };
-
- beforeEach(() => {
- setWindowLocation(TEST_HOST);
- });
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- jest.spyOn(window.history, 'pushState');
- jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
- jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
- });
-
- afterEach(() => {
- mock.reset();
- mockApollo = null;
- window.history.pushState.mockReset();
- });
-
- describe('when pipelines are not yet loaded', () => {
- beforeEach(async () => {
- createComponent();
- await nextTick();
- });
-
- it('shows loading state when the app is loading', () => {
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- });
-
- it('does not display tabs when the first request has not yet been made', () => {
- expect(findNavigationTabs().exists()).toBe(false);
- });
-
- it('does not display buttons', () => {
- expect(findNavigationControls().exists()).toBe(false);
- });
- });
-
- describe('when there are pipelines in the project', () => {
- beforeEach(() => {
- mock
- .onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
- .reply(HTTP_STATUS_OK, mockPipelinesResponse);
- });
-
- describe('when user has no permissions', () => {
- beforeEach(async () => {
- createComponent({ hasGitlabCi: true, canCreatePipeline: false, ...noPermissions });
- await waitForPromises();
- });
-
- it('renders "All" tab with count different from "0"', () => {
- expect(findTab('all').text()).toMatchInterpolatedText('All 3');
- });
-
- it('does not render buttons', () => {
- expect(findNavigationControls().exists()).toBe(false);
-
- expect(findRunPipelineButton().exists()).toBe(false);
- expect(findCiLintButton().exists()).toBe(false);
- expect(findCleanCacheButton().exists()).toBe(false);
- });
-
- it('renders pipelines in a table', () => {
- expect(findPipelinesTable().exists()).toBe(true);
-
- expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
- expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
- expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
- });
- });
-
- describe('when user has permissions', () => {
- beforeEach(async () => {
- createComponent();
- await waitForPromises();
- });
-
- it('should set up navigation tabs', () => {
- expect(findNavigationTabs().props('tabs')).toEqual([
- { name: 'All', scope: 'all', count: '3', isActive: true },
- { name: 'Finished', scope: 'finished', count: undefined, isActive: false },
- { name: 'Branches', scope: 'branches', isActive: false },
- { name: 'Tags', scope: 'tags', isActive: false },
- ]);
- });
-
- it('renders "All" tab with count different from "0"', () => {
- expect(findTab('all').text()).toMatchInterpolatedText('All 3');
- });
-
- it('should render other navigation tabs', () => {
- expect(findTab('finished').text()).toBe('Finished');
- expect(findTab('branches').text()).toBe('Branches');
- expect(findTab('tags').text()).toBe('Tags');
- });
-
- it('shows navigation controls', () => {
- expect(findNavigationControls().exists()).toBe(true);
- });
-
- it('renders Run pipeline link', () => {
- expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
- });
-
- it('renders CI lint link', () => {
- expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
- });
-
- it('renders Clear runner cache button', () => {
- expect(findCleanCacheButton().text()).toBe('Clear runner caches');
- });
-
- it('renders pipelines in a table', () => {
- expect(findPipelinesTable().exists()).toBe(true);
-
- expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
- expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
- expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
- });
-
- describe('when user goes to a tab', () => {
- const goToTab = (tab) => {
- findNavigationTabs().vm.$emit('onChangeTab', tab);
- };
-
- describe('when the scope in the tab has pipelines', () => {
- const mockFinishedPipeline = mockPipelinesResponse.pipelines[0];
-
- beforeEach(async () => {
- mock
- .onGet(mockPipelinesEndpoint, { params: { scope: 'finished', page: '1' } })
- .reply(HTTP_STATUS_OK, {
- pipelines: [mockFinishedPipeline],
- count: mockPipelinesResponse.count,
- });
-
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
-
- goToTab('finished');
-
- await waitForPromises();
- });
-
- it('should filter pipelines', () => {
- expect(findPipelinesTable().exists()).toBe(true);
-
- expect(findPipelineUrlLinks()).toHaveLength(1);
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFinishedPipeline.id}`);
- });
-
- it('should update browser bar', () => {
- expect(window.history.pushState).toHaveBeenCalledTimes(1);
- expect(window.history.pushState).toHaveBeenCalledWith(
- expect.anything(),
- expect.anything(),
- `${window.location.pathname}?scope=finished&page=1`,
- );
- });
-
- it.each(['all', 'finished', 'branches', 'tags'])('tracks %p tab click', async (scope) => {
- goToTab(scope);
-
- await waitForPromises();
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_filter_tabs', {
- label: TRACKING_CATEGORIES.tabs,
- property: scope,
- });
- });
- });
-
- describe('when the scope in the tab is empty', () => {
- beforeEach(async () => {
- mock
- .onGet(mockPipelinesEndpoint, { params: { scope: 'branches', page: '1' } })
- .reply(HTTP_STATUS_OK, {
- pipelines: [],
- count: mockPipelinesResponse.count,
- });
-
- goToTab('branches');
-
- await waitForPromises();
- });
-
- it('should filter pipelines', () => {
- expect(findEmptyState().text()).toBe('There are currently no pipelines.');
- });
-
- it('should update browser bar', () => {
- expect(window.history.pushState).toHaveBeenCalledTimes(1);
- expect(window.history.pushState).toHaveBeenCalledWith(
- expect.anything(),
- expect.anything(),
- `${window.location.pathname}?scope=branches&page=1`,
- );
- });
- });
- });
-
- describe('when user triggers a filtered search', () => {
- const mockFilteredPipeline = mockPipelinesResponse.pipelines[1];
-
- let expectedParams;
-
- beforeEach(async () => {
- expectedParams = {
- page: '1',
- scope: 'all',
- username: 'root',
- ref: 'main',
- status: 'pending',
- };
-
- mock
- .onGet(mockPipelinesEndpoint, {
- params: expectedParams,
- })
- .replyOnce(HTTP_STATUS_OK, {
- pipelines: [mockFilteredPipeline],
- count: mockPipelinesResponse.count,
- });
-
- findFilteredSearch().vm.$emit('submit', mockSearch);
-
- await waitForPromises();
- });
-
- it('requests data with query params on filter submit', () => {
- expect(mock.history.get[1].params).toEqual(expectedParams);
- });
-
- it('renders filtered pipelines', () => {
- expect(findPipelineUrlLinks()).toHaveLength(1);
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFilteredPipeline.id}`);
- });
-
- it('should update browser bar', () => {
- expect(window.history.pushState).toHaveBeenCalledTimes(1);
- expect(window.history.pushState).toHaveBeenCalledWith(
- expect.anything(),
- expect.anything(),
- `${window.location.pathname}?page=1&scope=all&username=root&ref=main&status=pending`,
- );
- });
- });
-
- describe('when user changes Show Pipeline ID to Show Pipeline IID', () => {
- const mockFilteredPipeline = mockPipelinesResponse.pipelines[0];
-
- beforeEach(() => {
- gon.current_user_id = 1;
- });
-
- it('should change the text to Show Pipeline IID', async () => {
- expect(findPipelineKeyCollapsibleBox().exists()).toBe(true);
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFilteredPipeline.id}`);
- findPipelineKeyCollapsibleBoxVue().vm.$emit('select', 'iid');
-
- await waitForPromises();
-
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockFilteredPipeline.iid}`);
- });
-
- it('calls mutation to save idType preference', () => {
- const mutationMock = jest.fn().mockResolvedValue(setIdTypePreferenceMutationResponse);
- createComponent({ ...defaultProps, mutationMock });
-
- findPipelineKeyCollapsibleBoxVue().vm.$emit('select', 'iid');
-
- expect(mutationMock).toHaveBeenCalledWith({ input: { visibilityPipelineIdType: 'IID' } });
- });
-
- it('captures error when mutation response has errors', async () => {
- const mutationMock = jest
- .fn()
- .mockResolvedValue(setIdTypePreferenceMutationResponseWithErrors);
- createComponent({ ...defaultProps, mutationMock });
-
- findPipelineKeyCollapsibleBoxVue().vm.$emit('select', 'iid');
- await waitForPromises();
-
- expect(Sentry.captureException).toHaveBeenCalledWith(new Error('oh no!'));
- });
- });
-
- describe('when user triggers a filtered search with raw text', () => {
- beforeEach(async () => {
- findFilteredSearch().vm.$emit('submit', ['rawText']);
-
- await waitForPromises();
- });
-
- it('requests data with query params on filter submit', () => {
- expect(mock.history.get[1].params).toEqual({ page: '1', scope: 'all' });
- });
-
- it('displays a warning message if raw text search is used', () => {
- expect(createAlert).toHaveBeenCalledTimes(1);
- expect(createAlert).toHaveBeenCalledWith({
- message: RAW_TEXT_WARNING,
- variant: VARIANT_WARNING,
- });
- });
-
- it('should update browser bar', () => {
- expect(window.history.pushState).toHaveBeenCalledTimes(1);
- expect(window.history.pushState).toHaveBeenCalledWith(
- expect.anything(),
- expect.anything(),
- `${window.location.pathname}?page=1&scope=all`,
- );
- });
- });
- });
- });
-
- describe('when there are multiple pages of pipelines', () => {
- const mockPageSize = 2;
- const mockPageHeaders = ({ page = 1 } = {}) => {
- return {
- 'X-PER-PAGE': `${mockPageSize}`,
- 'X-PREV-PAGE': `${page - 1}`,
- 'X-PAGE': `${page}`,
- 'X-NEXT-PAGE': `${page + 1}`,
- };
- };
- const [firstPage, secondPage] = chunk(mockPipelinesResponse.pipelines, mockPageSize);
-
- const goToPage = (page) => {
- findTablePagination().findComponent(GlPagination).vm.$emit('input', page);
- };
-
- beforeEach(async () => {
- mock.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } }).reply(
- HTTP_STATUS_OK,
- {
- pipelines: firstPage,
- count: mockPipelinesResponse.count,
- },
- mockPageHeaders({ page: 1 }),
- );
- mock.onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '2' } }).reply(
- HTTP_STATUS_OK,
- {
- pipelines: secondPage,
- count: mockPipelinesResponse.count,
- },
- mockPageHeaders({ page: 2 }),
- );
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('shows the first page of pipelines', () => {
- expect(findPipelineUrlLinks()).toHaveLength(firstPage.length);
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${firstPage[0].id}`);
- expect(findPipelineUrlLinks().at(1).text()).toBe(`#${firstPage[1].id}`);
- });
-
- it('should not update browser bar', () => {
- expect(window.history.pushState).not.toHaveBeenCalled();
- });
-
- describe('when user goes to next page', () => {
- beforeEach(async () => {
- goToPage(2);
- await waitForPromises();
- });
-
- it('should update page and keep scope the same scope', () => {
- expect(findPipelineUrlLinks()).toHaveLength(secondPage.length);
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${secondPage[0].id}`);
- });
-
- it('should update browser bar', () => {
- expect(window.history.pushState).toHaveBeenCalledTimes(1);
- expect(window.history.pushState).toHaveBeenCalledWith(
- expect.anything(),
- expect.anything(),
- `${window.location.pathname}?page=2&scope=all`,
- );
- });
-
- it('should reset page to 1 when filtering pipelines', () => {
- expect(window.history.pushState).toHaveBeenCalledTimes(1);
- expect(window.history.pushState).toHaveBeenCalledWith(
- expect.anything(),
- expect.anything(),
- `${window.location.pathname}?page=2&scope=all`,
- );
-
- findFilteredSearch().vm.$emit('submit', [
- { type: 'status', value: { data: 'success', operator: '=' } },
- ]);
-
- expect(window.history.pushState).toHaveBeenCalledTimes(2);
- expect(window.history.pushState).toHaveBeenCalledWith(
- expect.anything(),
- expect.anything(),
- `${window.location.pathname}?page=1&scope=all&status=success`,
- );
- });
- });
- });
-
- describe('when pipelines can be polled', () => {
- beforeEach(() => {
- const emptyResponse = {
- pipelines: [],
- count: { all: '0' },
- };
-
- // Mock no pipelines in the first attempt
- mock
- .onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
- .replyOnce(HTTP_STATUS_OK, emptyResponse, {
- 'POLL-INTERVAL': 100,
- });
- // Mock pipelines in the next attempt
- mock
- .onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
- .reply(HTTP_STATUS_OK, mockPipelinesResponse, {
- 'POLL-INTERVAL': 100,
- });
- });
-
- describe('data is loaded for the first time', () => {
- beforeEach(async () => {
- createComponent();
- await waitForPromises();
- });
-
- it('shows tabs', () => {
- expect(findNavigationTabs().exists()).toBe(true);
- });
-
- it('should update page and keep scope the same scope', () => {
- expect(findPipelineUrlLinks()).toHaveLength(0);
- });
-
- describe('data is loaded for a second time', () => {
- beforeEach(async () => {
- jest.runOnlyPendingTimers();
- await waitForPromises();
- });
-
- it('shows tabs', () => {
- expect(findNavigationTabs().exists()).toBe(true);
- });
-
- it('is loading after a time', () => {
- expect(findPipelineUrlLinks()).toHaveLength(mockPipelinesIds.length);
- expect(findPipelineUrlLinks().at(0).text()).toBe(`#${mockPipelinesIds[0]}`);
- expect(findPipelineUrlLinks().at(1).text()).toBe(`#${mockPipelinesIds[1]}`);
- expect(findPipelineUrlLinks().at(2).text()).toBe(`#${mockPipelinesIds[2]}`);
- });
- });
- });
- });
-
- describe('when no pipelines exist', () => {
- beforeEach(() => {
- mock
- .onGet(mockPipelinesEndpoint, { params: { scope: 'all', page: '1' } })
- .reply(HTTP_STATUS_OK, {
- pipelines: [],
- count: { all: '0' },
- });
- });
-
- describe('when CI is enabled and user has permissions', () => {
- beforeEach(async () => {
- createComponent();
- await waitForPromises();
- });
-
- it('renders tab with count of "0"', () => {
- expect(findNavigationTabs().exists()).toBe(true);
- expect(findTab('all').text()).toMatchInterpolatedText('All 0');
- });
-
- it('renders Run pipeline link', () => {
- expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
- });
-
- it('renders CI lint link', () => {
- expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
- });
-
- it('renders Clear runner cache button', () => {
- expect(findCleanCacheButton().text()).toBe('Clear runner caches');
- });
-
- it('renders empty state', () => {
- expect(findEmptyState().text()).toBe('There are currently no pipelines.');
- });
-
- it('renders filtered search', () => {
- expect(findFilteredSearch().exists()).toBe(true);
- });
-
- it('renders the pipeline key collapsible box', () => {
- expect(findPipelineKeyCollapsibleBox().exists()).toBe(true);
- });
-
- it('renders tab empty state finished scope', async () => {
- mock
- .onGet(mockPipelinesEndpoint, { params: { scope: 'finished', page: '1' } })
- .reply(HTTP_STATUS_OK, {
- pipelines: [],
- count: { all: '0' },
- });
-
- findNavigationTabs().vm.$emit('onChangeTab', 'finished');
-
- await waitForPromises();
-
- expect(findEmptyState().text()).toBe('There are currently no finished pipelines.');
- });
- });
-
- describe('when CI is not enabled and user has permissions', () => {
- beforeEach(async () => {
- createComponent({ hasGitlabCi: false, canCreatePipeline: true, ...paths });
- await waitForPromises();
- });
-
- it('renders the CI/CD templates', () => {
- expect(wrapper.findComponent(PipelinesCiTemplates).exists()).toBe(true);
- });
-
- it('does not render filtered search', () => {
- expect(findFilteredSearch().exists()).toBe(false);
- });
-
- it('does not render the pipeline key dropdown', () => {
- expect(findPipelineKeyCollapsibleBox().exists()).toBe(false);
- });
-
- it('does not render tabs nor buttons', () => {
- expect(findNavigationTabs().exists()).toBe(false);
- expect(findTab('all').exists()).toBe(false);
- expect(findRunPipelineButton().exists()).toBe(false);
- expect(findCiLintButton().exists()).toBe(false);
- expect(findCleanCacheButton().exists()).toBe(false);
- });
- });
-
- describe('when CI is not enabled and user has no permissions', () => {
- beforeEach(async () => {
- createComponent({ hasGitlabCi: false, canCreatePipeline: false, ...noPermissions });
- await waitForPromises();
- });
-
- it('renders empty state without button to set CI', () => {
- expect(findEmptyState().text()).toBe(
- 'This project is not currently set up to run pipelines.',
- );
-
- expect(findEmptyState().findComponent(GlButton).exists()).toBe(false);
- });
-
- it('does not render tabs or buttons', () => {
- expect(findTab('all').exists()).toBe(false);
- expect(findRunPipelineButton().exists()).toBe(false);
- expect(findCiLintButton().exists()).toBe(false);
- expect(findCleanCacheButton().exists()).toBe(false);
- });
- });
-
- describe('when CI is enabled and user has no permissions', () => {
- beforeEach(() => {
- createComponent({ hasGitlabCi: true, canCreatePipeline: false, ...noPermissions });
-
- return waitForPromises();
- });
-
- it('renders tab with count of "0"', () => {
- expect(findTab('all').text()).toMatchInterpolatedText('All 0');
- });
-
- it('does not render buttons', () => {
- expect(findRunPipelineButton().exists()).toBe(false);
- expect(findCiLintButton().exists()).toBe(false);
- expect(findCleanCacheButton().exists()).toBe(false);
- });
-
- it('renders empty state', () => {
- expect(findEmptyState().text()).toBe('There are currently no pipelines.');
- });
- });
- });
-
- describe('when a pipeline with stages exists', () => {
- describe('updates results when a staged is clicked', () => {
- let stopMock;
- let restartMock;
- let cancelMock;
-
- beforeEach(() => {
- mock.onGet(mockPipelinesEndpoint, { scope: 'all', page: '1' }).reply(
- HTTP_STATUS_OK,
- {
- pipelines: [mockPipelineWithStages],
- count: { all: '1' },
- },
- {
- 'POLL-INTERVAL': 100,
- },
- );
-
- mock
- .onGet(mockPipelineWithStages.details.stages[0].dropdown_path)
- .reply(HTTP_STATUS_OK, stageReply);
-
- createComponent();
-
- stopMock = jest.spyOn(window, 'clearTimeout');
- restartMock = jest.spyOn(axios, 'get');
- });
-
- describe('when a request is being made', () => {
- beforeEach(async () => {
- mock.onGet(mockPipelinesEndpoint).reply(HTTP_STATUS_OK, mockPipelinesResponse);
-
- await waitForPromises();
- });
-
- it('stops polling, cancels the request, & restarts polling', async () => {
- // Mock init a polling cycle
- wrapper.vm.poll.options.notificationCallback(true);
-
- await findStagesDropdownToggle().trigger('click');
- jest.runOnlyPendingTimers();
-
- // cancelMock is getting overwritten in pipelines_service.js#L29
- // so we have to spy on it again here
- cancelMock = jest.spyOn(axios.CancelToken, 'source');
-
- await waitForPromises();
-
- expect(cancelMock).toHaveBeenCalled();
- expect(stopMock).toHaveBeenCalled();
- expect(restartMock).toHaveBeenCalledWith(
- `${mockPipelinesResponse.pipelines[0].path}/stage.json?stage=build`,
- );
- });
-
- it('stops polling & restarts polling', async () => {
- await findStagesDropdownToggle().trigger('click');
- jest.runOnlyPendingTimers();
- await waitForPromises();
-
- expect(cancelMock).not.toHaveBeenCalled();
- expect(stopMock).toHaveBeenCalled();
- expect(restartMock).toHaveBeenCalledWith(
- `${mockPipelinesResponse.pipelines[0].path}/stage.json?stage=build`,
- );
- });
- });
- });
- });
-
- describe('when pipelines cannot be loaded', () => {
- beforeEach(() => {
- mock.onGet(mockPipelinesEndpoint).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR, {});
- });
-
- describe('when user has no permissions', () => {
- beforeEach(async () => {
- createComponent({ hasGitlabCi: false, canCreatePipeline: true, ...noPermissions });
-
- await waitForPromises();
- });
-
- it('renders tabs', () => {
- expect(findNavigationTabs().exists()).toBe(true);
- expect(findTab('all').text()).toBe('All');
- });
-
- it('does not render buttons', () => {
- expect(findRunPipelineButton().exists()).toBe(false);
- expect(findCiLintButton().exists()).toBe(false);
- expect(findCleanCacheButton().exists()).toBe(false);
- });
-
- it('shows error state', () => {
- expect(findEmptyState().props('title')).toBe('There was an error fetching the pipelines.');
- expect(findEmptyState().props('description')).toBe(
- 'Try again in a few moments or contact your support team.',
- );
- });
- });
-
- describe('when user has permissions', () => {
- beforeEach(async () => {
- createComponent();
-
- await waitForPromises();
- });
-
- it('renders tabs', () => {
- expect(findTab('all').text()).toBe('All');
- });
-
- it('renders buttons', () => {
- expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
-
- expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
- expect(findCleanCacheButton().text()).toBe('Clear runner caches');
- });
-
- it('shows error state', () => {
- expect(findEmptyState().props('title')).toBe('There was an error fetching the pipelines.');
- expect(findEmptyState().props('description')).toBe(
- 'Try again in a few moments or contact your support team.',
- );
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipelines_store_spec.js b/spec/frontend/pipelines/pipelines_store_spec.js
deleted file mode 100644
index f374ecd0c0a..00000000000
--- a/spec/frontend/pipelines/pipelines_store_spec.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import PipelineStore from '~/pipelines/stores/pipelines_store';
-
-describe('Pipelines Store', () => {
- let store;
-
- beforeEach(() => {
- store = new PipelineStore();
- });
-
- it('should be initialized with an empty state', () => {
- expect(store.state.pipelines).toEqual([]);
- expect(store.state.count).toEqual({});
- expect(store.state.pageInfo).toEqual({});
- });
-
- describe('storePipelines', () => {
- it('should use the default parameter if none is provided', () => {
- store.storePipelines();
-
- expect(store.state.pipelines).toEqual([]);
- });
-
- it('should store the provided array', () => {
- const array = [
- { id: 1, status: 'running' },
- { id: 2, status: 'success' },
- ];
- store.storePipelines(array);
-
- expect(store.state.pipelines).toEqual(array);
- });
- });
-
- describe('storeCount', () => {
- it('should use the default parameter if none is provided', () => {
- store.storeCount();
-
- expect(store.state.count).toEqual({});
- });
-
- it('should store the provided count', () => {
- const count = { all: 20, finished: 10 };
- store.storeCount(count);
-
- expect(store.state.count).toEqual(count);
- });
- });
-
- describe('storePagination', () => {
- it('should use the default parameter if none is provided', () => {
- store.storePagination();
-
- expect(store.state.pageInfo).toEqual({});
- });
-
- it('should store pagination information normalized and parsed', () => {
- const pagination = {
- 'X-nExt-pAge': '2',
- 'X-page': '1',
- 'X-Per-Page': '1',
- 'X-Prev-Page': '2',
- 'X-TOTAL': '37',
- 'X-Total-Pages': '2',
- };
-
- const expectedResult = {
- perPage: 1,
- page: 1,
- total: 37,
- totalPages: 2,
- nextPage: 2,
- previousPage: 2,
- };
-
- store.storePagination(pagination);
-
- expect(store.state.pageInfo).toEqual(expectedResult);
- });
- });
-});
diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js
deleted file mode 100644
index 950a6b21e16..00000000000
--- a/spec/frontend/pipelines/pipelines_table_spec.js
+++ /dev/null
@@ -1,280 +0,0 @@
-import '~/commons';
-import { GlTableLite } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import fixture from 'test_fixtures/pipelines/pipelines.json';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
-import PipelineFailedJobsWidget from '~/pipelines/components/pipelines_list/failure_widget/pipeline_failed_jobs_widget.vue';
-import PipelineOperations from '~/pipelines/components/pipelines_list/pipeline_operations.vue';
-import PipelineTriggerer from '~/pipelines/components/pipelines_list/pipeline_triggerer.vue';
-import PipelineUrl from '~/pipelines/components/pipelines_list/pipeline_url.vue';
-import PipelinesTable from '~/pipelines/components/pipelines_list/pipelines_table.vue';
-import PipelinesTimeago from '~/pipelines/components/pipelines_list/time_ago.vue';
-import {
- PipelineKeyOptions,
- BUTTON_TOOLTIP_RETRY,
- BUTTON_TOOLTIP_CANCEL,
- TRACKING_CATEGORIES,
-} from '~/pipelines/constants';
-
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-
-jest.mock('~/pipelines/event_hub');
-
-describe('Pipelines Table', () => {
- let pipeline;
- let wrapper;
- let trackingSpy;
-
- const defaultProvide = {
- glFeatures: {},
- withFailedJobsDetails: false,
- };
-
- const provideWithDetails = {
- glFeatures: {
- ciJobFailuresInMr: true,
- },
- withFailedJobsDetails: true,
- };
-
- const defaultProps = {
- pipelines: [],
- viewType: 'root',
- pipelineKeyOption: PipelineKeyOptions[0],
- };
-
- const createMockPipeline = () => {
- // Clone fixture as it could be modified by tests
- const { pipelines } = JSON.parse(JSON.stringify(fixture));
- return pipelines.find((p) => p.user !== null && p.commit !== null);
- };
-
- const createComponent = (props = {}, provide = {}) => {
- wrapper = extendedWrapper(
- mount(PipelinesTable, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- provide: {
- ...defaultProvide,
- ...provide,
- },
- stubs: ['PipelineFailedJobsWidget'],
- }),
- );
- };
-
- const findGlTableLite = () => wrapper.findComponent(GlTableLite);
- const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
- const findPipelineInfo = () => wrapper.findComponent(PipelineUrl);
- const findTriggerer = () => wrapper.findComponent(PipelineTriggerer);
- const findLegacyPipelineMiniGraph = () => wrapper.findComponent(LegacyPipelineMiniGraph);
- const findTimeAgo = () => wrapper.findComponent(PipelinesTimeago);
- const findActions = () => wrapper.findComponent(PipelineOperations);
-
- const findPipelineFailureWidget = () => wrapper.findComponent(PipelineFailedJobsWidget);
- const findTableRows = () => wrapper.findAllByTestId('pipeline-table-row');
- const findStatusTh = () => wrapper.findByTestId('status-th');
- const findPipelineTh = () => wrapper.findByTestId('pipeline-th');
- const findStagesTh = () => wrapper.findByTestId('stages-th');
- const findActionsTh = () => wrapper.findByTestId('actions-th');
- const findRetryBtn = () => wrapper.findByTestId('pipelines-retry-button');
- const findCancelBtn = () => wrapper.findByTestId('pipelines-cancel-button');
-
- beforeEach(() => {
- pipeline = createMockPipeline();
- });
-
- describe('Pipelines Table', () => {
- beforeEach(() => {
- createComponent({ pipelines: [pipeline], viewType: 'root' });
- });
-
- it('displays table', () => {
- expect(findGlTableLite().exists()).toBe(true);
- });
-
- it('should render table head with correct columns', () => {
- expect(findStatusTh().text()).toBe('Status');
- expect(findPipelineTh().text()).toBe('Pipeline');
- expect(findStagesTh().text()).toBe('Stages');
- expect(findActionsTh().text()).toBe('Actions');
- });
-
- it('should display a table row', () => {
- expect(findTableRows()).toHaveLength(1);
- });
-
- describe('status cell', () => {
- it('should render a status badge', () => {
- expect(findCiBadgeLink().exists()).toBe(true);
- });
- });
-
- describe('pipeline cell', () => {
- it('should render pipeline information', () => {
- expect(findPipelineInfo().exists()).toBe(true);
- });
-
- it('should display the pipeline id', () => {
- expect(findPipelineInfo().text()).toContain(`#${pipeline.id}`);
- });
- });
-
- describe('stages cell', () => {
- it('should render pipeline mini graph', () => {
- expect(findLegacyPipelineMiniGraph().exists()).toBe(true);
- });
-
- it('should render the right number of stages', () => {
- const stagesLength = pipeline.details.stages.length;
- expect(findLegacyPipelineMiniGraph().props('stages').length).toBe(stagesLength);
- });
-
- it('should render the latest downstream pipelines only', () => {
- // component receives two downstream pipelines. one of them is already outdated
- // because we retried the trigger job, so the mini pipeline graph will only
- // render the newly created downstream pipeline instead
- expect(pipeline.triggered).toHaveLength(2);
- expect(findLegacyPipelineMiniGraph().props('downstreamPipelines')).toHaveLength(1);
- });
-
- describe('when pipeline does not have stages', () => {
- beforeEach(() => {
- pipeline = createMockPipeline();
- pipeline.details.stages = [];
-
- createComponent({ pipelines: [pipeline] });
- });
-
- it('stages are not rendered', () => {
- expect(findLegacyPipelineMiniGraph().props('stages')).toHaveLength(0);
- });
- });
- });
-
- describe('duration cell', () => {
- it('should render duration information', () => {
- expect(findTimeAgo().exists()).toBe(true);
- });
- });
-
- describe('operations cell', () => {
- it('should render pipeline operations', () => {
- expect(findActions().exists()).toBe(true);
- });
-
- it('should render retry action tooltip', () => {
- expect(findRetryBtn().attributes('title')).toBe(BUTTON_TOOLTIP_RETRY);
- });
-
- it('should render cancel action tooltip', () => {
- expect(findCancelBtn().attributes('title')).toBe(BUTTON_TOOLTIP_CANCEL);
- });
- });
-
- describe('triggerer cell', () => {
- it('should render the pipeline triggerer', () => {
- expect(findTriggerer().exists()).toBe(true);
- });
- });
-
- describe('failed jobs details', () => {
- describe('row', () => {
- describe('when the FF is disabled', () => {
- beforeEach(() => {
- createComponent({ pipelines: [pipeline] });
- });
-
- it('does not render', () => {
- expect(findTableRows()).toHaveLength(1);
- expect(findPipelineFailureWidget().exists()).toBe(false);
- });
- });
-
- describe('when the FF is enabled', () => {
- describe('and `withFailedJobsDetails` value is provided', () => {
- beforeEach(() => {
- createComponent({ pipelines: [pipeline] }, provideWithDetails);
- });
-
- it('renders', () => {
- expect(findTableRows()).toHaveLength(2);
- expect(findPipelineFailureWidget().exists()).toBe(true);
- });
-
- it('passes the expected props', () => {
- expect(findPipelineFailureWidget().props()).toStrictEqual({
- failedJobsCount: pipeline.failed_builds.length,
- isPipelineActive: pipeline.active,
- pipelineIid: pipeline.iid,
- pipelinePath: pipeline.path,
- // Make sure the forward slash was removed
- projectPath: 'frontend-fixtures/pipelines-project',
- });
- });
- });
-
- describe('and `withFailedJobsDetails` value is not provided', () => {
- beforeEach(() => {
- createComponent(
- { pipelines: [pipeline] },
- { glFeatures: { ciJobFailuresInMr: true } },
- );
- });
-
- it('does not render', () => {
- expect(findTableRows()).toHaveLength(1);
- expect(findPipelineFailureWidget().exists()).toBe(false);
- });
- });
- });
- });
- });
-
- describe('tracking', () => {
- beforeEach(() => {
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- it('tracks status badge click', () => {
- findCiBadgeLink().vm.$emit('ciStatusBadgeClick');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_ci_status_badge', {
- label: TRACKING_CATEGORIES.table,
- });
- });
-
- it('tracks retry pipeline button click', () => {
- findRetryBtn().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_retry_button', {
- label: TRACKING_CATEGORIES.table,
- });
- });
-
- it('tracks cancel pipeline button click', () => {
- findCancelBtn().vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_cancel_button', {
- label: TRACKING_CATEGORIES.table,
- });
- });
-
- it('tracks pipeline mini graph stage click', () => {
- findLegacyPipelineMiniGraph().vm.$emit('miniGraphStageClick');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_minigraph', {
- label: TRACKING_CATEGORIES.table,
- });
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/empty_state_spec.js b/spec/frontend/pipelines/test_reports/empty_state_spec.js
deleted file mode 100644
index ee0f8a90a11..00000000000
--- a/spec/frontend/pipelines/test_reports/empty_state_spec.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { GlEmptyState } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import EmptyState, { i18n } from '~/pipelines/components/test_reports/empty_state.vue';
-
-describe('Test report empty state', () => {
- let wrapper;
-
- const findEmptyState = () => wrapper.findComponent(GlEmptyState);
-
- const createComponent = ({ hasTestReport = true } = {}) => {
- wrapper = shallowMount(EmptyState, {
- provide: {
- emptyStateImagePath: '/image/path',
- hasTestReport,
- },
- stubs: {
- GlEmptyState,
- },
- });
- };
-
- describe('when pipeline has a test report', () => {
- it('should render empty test report message', () => {
- createComponent();
-
- expect(findEmptyState().props()).toMatchObject({
- primaryButtonText: i18n.noTestsButton,
- description: i18n.noTestsDescription,
- title: i18n.noTestsTitle,
- });
- });
- });
-
- describe('when pipeline does not have a test report', () => {
- it('should render no test report message', () => {
- createComponent({ hasTestReport: false });
-
- expect(findEmptyState().props()).toMatchObject({
- primaryButtonText: i18n.noReportsButton,
- description: i18n.noReportsDescription,
- title: i18n.noReportsTitle,
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/mock_data.js b/spec/frontend/pipelines/test_reports/mock_data.js
deleted file mode 100644
index c3ca1429842..00000000000
--- a/spec/frontend/pipelines/test_reports/mock_data.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { TestStatus } from '~/pipelines/constants';
-
-export default [
- {
- classname: 'spec.test_spec',
- file: 'spec/trace_spec.rb',
- execution_time: 0,
- name: 'Test#skipped text',
- stack_trace: null,
- status: TestStatus.SKIPPED,
- system_output: null,
- },
- {
- classname: 'spec.test_spec',
- file: 'spec/trace_spec.rb',
- execution_time: 0,
- name: 'Test#error text',
- stack_trace: null,
- status: TestStatus.ERROR,
- system_output: null,
- },
- {
- classname: 'spec.test_spec',
- file: 'spec/trace_spec.rb',
- execution_time: 0,
- name: 'Test#unknown text',
- stack_trace: null,
- status: TestStatus.UNKNOWN,
- system_output: null,
- },
-];
diff --git a/spec/frontend/pipelines/test_reports/stores/actions_spec.js b/spec/frontend/pipelines/test_reports/stores/actions_spec.js
deleted file mode 100644
index e05d2151f0a..00000000000
--- a/spec/frontend/pipelines/test_reports/stores/actions_spec.js
+++ /dev/null
@@ -1,149 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import testReports from 'test_fixtures/pipelines/test_report.json';
-import { TEST_HOST } from 'helpers/test_constants';
-import testAction from 'helpers/vuex_action_helper';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import * as actions from '~/pipelines/stores/test_reports/actions';
-import * as types from '~/pipelines/stores/test_reports/mutation_types';
-
-jest.mock('~/alert');
-
-describe('Actions TestReports Store', () => {
- let mock;
- let state;
-
- const summary = { total_count: 1 };
-
- const suiteEndpoint = `${TEST_HOST}/tests/suite.json`;
- const summaryEndpoint = `${TEST_HOST}/test_reports/summary.json`;
- const defaultState = {
- suiteEndpoint,
- summaryEndpoint,
- testReports: {},
- selectedSuite: null,
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- state = { ...defaultState };
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('fetch report summary', () => {
- beforeEach(() => {
- mock.onGet(summaryEndpoint).replyOnce(HTTP_STATUS_OK, summary, {});
- });
-
- it('sets testReports and shows tests', () => {
- return testAction(
- actions.fetchSummary,
- null,
- state,
- [{ type: types.SET_SUMMARY, payload: summary }],
- [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
- );
- });
-
- it('should create alert on API error', async () => {
- await testAction(
- actions.fetchSummary,
- null,
- { summaryEndpoint: null },
- [],
- [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
- );
- expect(createAlert).toHaveBeenCalled();
- });
- });
-
- describe('fetch test suite', () => {
- beforeEach(() => {
- const buildIds = [1];
- testReports.test_suites[0].build_ids = buildIds;
- mock
- .onGet(suiteEndpoint, { params: { build_ids: buildIds } })
- .replyOnce(HTTP_STATUS_OK, testReports.test_suites[0], {});
- });
-
- it('sets test suite and shows tests', () => {
- const suite = testReports.test_suites[0];
- const index = 0;
-
- return testAction(
- actions.fetchTestSuite,
- index,
- { ...state, testReports },
- [{ type: types.SET_SUITE, payload: { suite, index } }],
- [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
- );
- });
-
- it('should call SET_SUITE_ERROR on error', () => {
- const index = 0;
-
- return testAction(
- actions.fetchTestSuite,
- index,
- { ...state, testReports, suiteEndpoint: null },
- [{ type: types.SET_SUITE_ERROR, payload: expect.any(Error) }],
- [{ type: 'toggleLoading' }, { type: 'toggleLoading' }],
- );
- });
-
- describe('when we already have the suite data', () => {
- it('should not fetch suite', () => {
- const index = 0;
- testReports.test_suites[0].hasFullSuite = true;
-
- return testAction(actions.fetchTestSuite, index, { ...state, testReports }, [], []);
- });
- });
- });
-
- describe('set selected suite index', () => {
- it('sets selectedSuiteIndex', () => {
- const selectedSuiteIndex = 0;
-
- return testAction(
- actions.setSelectedSuiteIndex,
- selectedSuiteIndex,
- { ...state, hasFullReport: true },
- [{ type: types.SET_SELECTED_SUITE_INDEX, payload: selectedSuiteIndex }],
- [],
- );
- });
- });
-
- describe('remove selected suite index', () => {
- it('sets selectedSuiteIndex to null', () => {
- return testAction(
- actions.removeSelectedSuiteIndex,
- {},
- state,
- [{ type: types.SET_SELECTED_SUITE_INDEX, payload: null }],
- [],
- );
- });
- });
-
- describe('toggles loading', () => {
- it('sets isLoading to true', () => {
- return testAction(actions.toggleLoading, {}, state, [{ type: types.TOGGLE_LOADING }], []);
- });
-
- it('toggles isLoading to false', () => {
- return testAction(
- actions.toggleLoading,
- {},
- { ...state, isLoading: true },
- [{ type: types.TOGGLE_LOADING }],
- [],
- );
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/stores/getters_spec.js b/spec/frontend/pipelines/test_reports/stores/getters_spec.js
deleted file mode 100644
index 70e3a01dbf1..00000000000
--- a/spec/frontend/pipelines/test_reports/stores/getters_spec.js
+++ /dev/null
@@ -1,171 +0,0 @@
-import testReports from 'test_fixtures/pipelines/test_report.json';
-import * as getters from '~/pipelines/stores/test_reports/getters';
-import {
- iconForTestStatus,
- formatFilePath,
- formattedTime,
-} from '~/pipelines/stores/test_reports/utils';
-
-describe('Getters TestReports Store', () => {
- let state;
-
- const defaultState = {
- blobPath: '/test/blob/path',
- testReports,
- selectedSuiteIndex: 0,
- pageInfo: {
- page: 1,
- perPage: 2,
- },
- };
-
- const emptyState = {
- blobPath: '',
- testReports: {},
- selectedSuite: null,
- pageInfo: {
- page: 1,
- perPage: 2,
- },
- };
-
- beforeEach(() => {
- state = {
- testReports,
- };
- });
-
- const setupState = (testState = defaultState) => {
- state = testState;
- };
-
- describe('getTestSuites', () => {
- it('should return the test suites', () => {
- setupState();
-
- const suites = getters.getTestSuites(state);
- const expected = testReports.test_suites.map((x) => ({
- ...x,
- formattedTime: formattedTime(x.total_time),
- }));
-
- expect(suites).toEqual(expected);
- });
-
- it('should return an empty array when testReports is empty', () => {
- setupState(emptyState);
-
- expect(getters.getTestSuites(state)).toEqual([]);
- });
- });
-
- describe('getSelectedSuite', () => {
- it('should return the selected suite', () => {
- setupState();
-
- const selectedSuite = getters.getSelectedSuite(state);
- const expected = testReports.test_suites[state.selectedSuiteIndex];
-
- expect(selectedSuite).toEqual(expected);
- });
- });
-
- describe('getSuiteTests', () => {
- it('should return the current page of test cases inside the suite', () => {
- setupState();
-
- const cases = getters.getSuiteTests(state);
- const expected = testReports.test_suites[0].test_cases
- .map((x) => ({
- ...x,
- filePath: `${state.blobPath}/${formatFilePath(x.file)}`,
- formattedTime: formattedTime(x.execution_time),
- icon: iconForTestStatus(x.status),
- }))
- .slice(0, state.pageInfo.perPage);
-
- expect(cases).toEqual(expected);
- });
-
- it('should return an empty array when testReports is empty', () => {
- setupState(emptyState);
-
- expect(getters.getSuiteTests(state)).toEqual([]);
- });
-
- describe('when a test case classname property is null', () => {
- it('should return an empty string value for the classname property', () => {
- const testCases = testReports.test_suites[0].test_cases;
- setupState({
- ...defaultState,
- testReports: {
- ...testReports,
- test_suites: [
- {
- test_cases: testCases.map((testCase) => ({
- ...testCase,
- classname: null,
- })),
- },
- ],
- },
- });
-
- const expected = testCases
- .map((x) => ({
- ...x,
- classname: '',
- filePath: `${state.blobPath}/${formatFilePath(x.file)}`,
- formattedTime: formattedTime(x.execution_time),
- icon: iconForTestStatus(x.status),
- }))
- .slice(0, state.pageInfo.perPage);
-
- expect(getters.getSuiteTests(state)).toEqual(expected);
- });
- });
-
- describe('when a test case name property is null', () => {
- it('should return an empty string value for the name property', () => {
- const testCases = testReports.test_suites[0].test_cases;
- setupState({
- ...defaultState,
- testReports: {
- ...testReports,
- test_suites: [
- {
- test_cases: testCases.map((testCase) => ({
- ...testCase,
- name: null,
- })),
- },
- ],
- },
- });
-
- const expected = testCases
- .map((x) => ({
- ...x,
- name: '',
- filePath: `${state.blobPath}/${formatFilePath(x.file)}`,
- formattedTime: formattedTime(x.execution_time),
- icon: iconForTestStatus(x.status),
- }))
- .slice(0, state.pageInfo.perPage);
-
- expect(getters.getSuiteTests(state)).toEqual(expected);
- });
- });
- });
-
- describe('getSuiteTestCount', () => {
- it('should return the total number of test cases', () => {
- setupState();
-
- const testCount = getters.getSuiteTestCount(state);
- const expected = testReports.test_suites[0].test_cases.length;
-
- expect(testCount).toEqual(expected);
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
deleted file mode 100644
index 685ac6ea3e5..00000000000
--- a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js
+++ /dev/null
@@ -1,114 +0,0 @@
-import testReports from 'test_fixtures/pipelines/test_report.json';
-import * as types from '~/pipelines/stores/test_reports/mutation_types';
-import mutations from '~/pipelines/stores/test_reports/mutations';
-import { createAlert } from '~/alert';
-
-jest.mock('~/alert');
-
-describe('Mutations TestReports Store', () => {
- let mockState;
-
- const defaultState = {
- endpoint: '',
- testReports: {},
- selectedSuite: null,
- isLoading: false,
- pageInfo: {
- page: 1,
- perPage: 2,
- },
- };
-
- beforeEach(() => {
- mockState = { ...defaultState };
- });
-
- describe('set page', () => {
- it('should set the current page to display', () => {
- const pageToDisplay = 3;
- mutations[types.SET_PAGE](mockState, pageToDisplay);
-
- expect(mockState.pageInfo.page).toEqual(pageToDisplay);
- });
- });
-
- describe('set suite', () => {
- it('should set the suite at the given index', () => {
- mockState.testReports = testReports;
- const suite = { name: 'test_suite' };
- const index = 0;
- const expectedState = { ...mockState };
- expectedState.testReports.test_suites[index] = { suite, hasFullSuite: true };
- mutations[types.SET_SUITE](mockState, { suite, index });
-
- expect(mockState.testReports.test_suites[index]).toEqual(
- expectedState.testReports.test_suites[index],
- );
- });
- });
-
- describe('set suite error', () => {
- it('should set the error message in state if provided', () => {
- const message = 'Test report artifacts not found';
-
- mutations[types.SET_SUITE_ERROR](mockState, {
- response: { data: { errors: message } },
- });
-
- expect(mockState.errorMessage).toBe(message);
- });
-
- it('should show an alert otherwise', () => {
- mutations[types.SET_SUITE_ERROR](mockState, {});
-
- expect(createAlert).toHaveBeenCalled();
- });
- });
-
- describe('set selected suite index', () => {
- it('should set selectedSuiteIndex', () => {
- const selectedSuiteIndex = 0;
- mutations[types.SET_SELECTED_SUITE_INDEX](mockState, selectedSuiteIndex);
-
- expect(mockState.selectedSuiteIndex).toEqual(selectedSuiteIndex);
- });
- });
-
- describe('set summary', () => {
- it('should set summary', () => {
- const summary = {
- total: { time: 0, count: 10, success: 1, failed: 2, skipped: 3, error: 4 },
- };
- const expectedSummary = {
- ...summary,
- total_time: 0,
- total_count: 10,
- success_count: 1,
- failed_count: 2,
- skipped_count: 3,
- error_count: 4,
- };
- mutations[types.SET_SUMMARY](mockState, summary);
-
- expect(mockState.testReports).toEqual(expectedSummary);
- });
- });
-
- describe('toggle loading', () => {
- it('should set to true', () => {
- const expectedState = { ...mockState, isLoading: true };
- mutations[types.TOGGLE_LOADING](mockState);
-
- expect(mockState.isLoading).toEqual(expectedState.isLoading);
- });
-
- it('should toggle back to false', () => {
- const expectedState = { ...mockState, isLoading: false };
- mockState.isLoading = true;
-
- mutations[types.TOGGLE_LOADING](mockState);
-
- expect(mockState.isLoading).toEqual(expectedState.isLoading);
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/stores/utils_spec.js b/spec/frontend/pipelines/test_reports/stores/utils_spec.js
deleted file mode 100644
index 703fe69026c..00000000000
--- a/spec/frontend/pipelines/test_reports/stores/utils_spec.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import { formatFilePath, formattedTime } from '~/pipelines/stores/test_reports/utils';
-
-describe('Test reports utils', () => {
- describe('formatFilePath', () => {
- it.each`
- file | expected
- ${'./test.js'} | ${'test.js'}
- ${'/test.js'} | ${'test.js'}
- ${'.//////////////test.js'} | ${'test.js'}
- ${'test.js'} | ${'test.js'}
- ${'mock/path./test.js'} | ${'mock/path./test.js'}
- ${'./mock/path./test.js'} | ${'mock/path./test.js'}
- `('should format $file to be $expected', ({ file, expected }) => {
- expect(formatFilePath(file)).toBe(expected);
- });
- });
-
- describe('formattedTime', () => {
- describe('when time is smaller than a second', () => {
- it('should return time in milliseconds fixed to 2 decimals', () => {
- const result = formattedTime(0.4815162342);
- expect(result).toBe('481.52ms');
- });
- });
-
- describe('when time is equal to a second', () => {
- it('should return time in seconds fixed to 2 decimals', () => {
- const result = formattedTime(1);
- expect(result).toBe('1.00s');
- });
- });
-
- describe('when time is greater than a second', () => {
- it('should return time in seconds fixed to 2 decimals', () => {
- const result = formattedTime(4.815162342);
- expect(result).toBe('4.82s');
- });
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/test_case_details_spec.js b/spec/frontend/pipelines/test_reports/test_case_details_spec.js
deleted file mode 100644
index f8663408817..00000000000
--- a/spec/frontend/pipelines/test_reports/test_case_details_spec.js
+++ /dev/null
@@ -1,149 +0,0 @@
-import { GlModal, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import TestCaseDetails from '~/pipelines/components/test_reports/test_case_details.vue';
-import CodeBlock from '~/vue_shared/components/code_block.vue';
-import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
-
-describe('Test case details', () => {
- let wrapper;
- const defaultTestCase = {
- classname: 'spec.test_spec',
- name: 'Test#something cool',
- file: '~/index.js',
- filePath: '/src/javascripts/index.js',
- formattedTime: '10.04ms',
- recent_failures: {
- count: 2,
- base_branch: 'main',
- },
- system_output: 'Line 42 is broken',
- };
-
- const findCopyFileBtn = () => wrapper.findComponent(ModalCopyButton);
- const findModal = () => wrapper.findComponent(GlModal);
- const findName = () => wrapper.findByTestId('test-case-name');
- const findFile = () => wrapper.findByTestId('test-case-file');
- const findFileLink = () => wrapper.findComponent(GlLink);
- const findDuration = () => wrapper.findByTestId('test-case-duration');
- const findRecentFailures = () => wrapper.findByTestId('test-case-recent-failures');
- const findAttachmentUrl = () => wrapper.findByTestId('test-case-attachment-url');
- const findSystemOutput = () => wrapper.findByTestId('test-case-trace');
-
- const createComponent = (testCase = {}) => {
- wrapper = extendedWrapper(
- shallowMount(TestCaseDetails, {
- propsData: {
- modalId: 'my-modal',
- testCase: {
- ...defaultTestCase,
- ...testCase,
- },
- },
- stubs: { CodeBlock, GlModal },
- }),
- );
- };
-
- describe('required details', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders the test case classname as modal title', () => {
- expect(findModal().props('title')).toBe(defaultTestCase.classname);
- });
-
- it('renders the test case name', () => {
- expect(findName().text()).toBe(defaultTestCase.name);
- });
-
- it('renders the test case file', () => {
- expect(findFile().text()).toBe(defaultTestCase.file);
- expect(findFileLink().attributes('href')).toBe(defaultTestCase.filePath);
- });
-
- it('renders copy button for test case file', () => {
- expect(findCopyFileBtn().attributes('text')).toBe(defaultTestCase.file);
- });
-
- it('renders the test case duration', () => {
- expect(findDuration().text()).toBe(defaultTestCase.formattedTime);
- });
- });
-
- describe('when test case has execution time instead of formatted time', () => {
- beforeEach(() => {
- createComponent({ ...defaultTestCase, formattedTime: null, execution_time: 17 });
- });
-
- it('renders the test case duration', () => {
- expect(findDuration().text()).toBe('17 s');
- });
- });
-
- describe('when test case has recent failures', () => {
- describe('has only 1 recent failure', () => {
- it('renders the recent failure', () => {
- createComponent({ recent_failures: { ...defaultTestCase.recent_failures, count: 1 } });
-
- expect(findRecentFailures().text()).toContain(
- `Failed 1 time in ${defaultTestCase.recent_failures.base_branch} in the last 14 days`,
- );
- });
- });
-
- describe('has more than 1 recent failure', () => {
- it('renders the recent failures', () => {
- createComponent();
-
- expect(findRecentFailures().text()).toContain(
- `Failed ${defaultTestCase.recent_failures.count} times in ${defaultTestCase.recent_failures.base_branch} in the last 14 days`,
- );
- });
- });
- });
-
- describe('when test case does not have recent failures', () => {
- it('does not render the recent failures', () => {
- createComponent({ recent_failures: null });
-
- expect(findRecentFailures().exists()).toBe(false);
- });
- });
-
- describe('when test case has attachment URL', () => {
- it('renders the attachment URL as a link', () => {
- const expectedUrl = '/my/path.jpg';
- createComponent({ attachment_url: expectedUrl });
- const attachmentUrl = findAttachmentUrl();
-
- expect(attachmentUrl.exists()).toBe(true);
- expect(attachmentUrl.attributes('href')).toBe(expectedUrl);
- });
- });
-
- describe('when test case does not have attachment URL', () => {
- it('does not render the attachment URL', () => {
- createComponent({ attachment_url: null });
-
- expect(findAttachmentUrl().exists()).toBe(false);
- });
- });
-
- describe('when test case has system output', () => {
- it('renders the test case system output', () => {
- createComponent();
-
- expect(findSystemOutput().text()).toContain(defaultTestCase.system_output);
- });
- });
-
- describe('when test case does not have system output', () => {
- it('does not render the test case system output', () => {
- createComponent({ system_output: null });
-
- expect(findSystemOutput().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/test_reports_spec.js b/spec/frontend/pipelines/test_reports/test_reports_spec.js
deleted file mode 100644
index de16f496eff..00000000000
--- a/spec/frontend/pipelines/test_reports/test_reports_spec.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import { GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import testReports from 'test_fixtures/pipelines/test_report.json';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import EmptyState from '~/pipelines/components/test_reports/empty_state.vue';
-import TestReports from '~/pipelines/components/test_reports/test_reports.vue';
-import TestSummary from '~/pipelines/components/test_reports/test_summary.vue';
-import TestSummaryTable from '~/pipelines/components/test_reports/test_summary_table.vue';
-import * as getters from '~/pipelines/stores/test_reports/getters';
-
-Vue.use(Vuex);
-
-describe('Test reports app', () => {
- let wrapper;
- let store;
-
- const loadingSpinner = () => wrapper.findComponent(GlLoadingIcon);
- const testsDetail = () => wrapper.findByTestId('tests-detail');
- const emptyState = () => wrapper.findComponent(EmptyState);
- const testSummary = () => wrapper.findComponent(TestSummary);
- const testSummaryTable = () => wrapper.findComponent(TestSummaryTable);
-
- const actionSpies = {
- fetchTestSuite: jest.fn(),
- fetchSummary: jest.fn(),
- setSelectedSuiteIndex: jest.fn(),
- removeSelectedSuiteIndex: jest.fn(),
- };
-
- const createComponent = ({ state = {} } = {}) => {
- store = new Vuex.Store({
- modules: {
- testReports: {
- namespaced: true,
- state: {
- isLoading: false,
- selectedSuiteIndex: null,
- testReports,
- ...state,
- },
- actions: actionSpies,
- getters,
- },
- },
- });
-
- jest.spyOn(store, 'registerModule').mockReturnValue(null);
-
- wrapper = extendedWrapper(
- shallowMount(TestReports, {
- provide: {
- blobPath: '/blob/path',
- summaryEndpoint: '/summary.json',
- suiteEndpoint: '/suite.json',
- },
- store,
- }),
- );
- };
-
- describe('when component is created', () => {
- it('should call fetchSummary when pipeline has test report', () => {
- createComponent();
-
- expect(actionSpies.fetchSummary).toHaveBeenCalled();
- });
- });
-
- describe('when loading', () => {
- beforeEach(() => createComponent({ state: { isLoading: true } }));
-
- it('shows the loading spinner', () => {
- expect(emptyState().exists()).toBe(false);
- expect(testsDetail().exists()).toBe(false);
- expect(loadingSpinner().exists()).toBe(true);
- });
- });
-
- describe('when the api returns no data', () => {
- it('displays empty state component', () => {
- createComponent({ state: { testReports: {} } });
-
- expect(emptyState().exists()).toBe(true);
- });
- });
-
- describe('when the api returns data', () => {
- beforeEach(() => createComponent());
-
- it('sets testReports and shows tests', () => {
- expect(wrapper.vm.testReports).toEqual(expect.any(Object));
- expect(wrapper.vm.showTests).toBe(true);
- });
-
- it('shows tests details', () => {
- expect(testsDetail().exists()).toBe(true);
- });
- });
-
- describe('when a suite is clicked', () => {
- beforeEach(() => {
- createComponent({ state: { hasFullReport: true } });
- testSummaryTable().vm.$emit('row-click', 0);
- });
-
- it('should call setSelectedSuiteIndex and fetchTestSuite', () => {
- expect(actionSpies.setSelectedSuiteIndex).toHaveBeenCalled();
- expect(actionSpies.fetchTestSuite).toHaveBeenCalled();
- });
- });
-
- describe('when clicking back to summary', () => {
- beforeEach(() => {
- createComponent({ state: { selectedSuiteIndex: 0 } });
- testSummary().vm.$emit('on-back-click');
- });
-
- it('should call removeSelectedSuiteIndex', () => {
- expect(actionSpies.removeSelectedSuiteIndex).toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
deleted file mode 100644
index 08b430fa703..00000000000
--- a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
+++ /dev/null
@@ -1,169 +0,0 @@
-import { GlButton, GlFriendlyWrap, GlLink, GlPagination, GlEmptyState } from '@gitlab/ui';
-import Vue from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import testReports from 'test_fixtures/pipelines/test_report.json';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import SuiteTable, { i18n } from '~/pipelines/components/test_reports/test_suite_table.vue';
-import { TestStatus } from '~/pipelines/constants';
-import * as getters from '~/pipelines/stores/test_reports/getters';
-import { formatFilePath } from '~/pipelines/stores/test_reports/utils';
-import { ARTIFACTS_EXPIRED_ERROR_MESSAGE } from '~/pipelines/stores/test_reports/constants';
-import skippedTestCases from './mock_data';
-
-Vue.use(Vuex);
-
-describe('Test reports suite table', () => {
- let wrapper;
- let store;
-
- const {
- test_suites: [testSuite],
- } = testReports;
-
- testSuite.test_cases = [...testSuite.test_cases, ...skippedTestCases];
- const testCases = testSuite.test_cases;
- const blobPath = '/test/blob/path';
-
- const noCasesMessage = () => wrapper.findByTestId('no-test-cases');
- const artifactsExpiredMessage = () => wrapper.findByTestId('artifacts-expired');
- const artifactsExpiredEmptyState = () => wrapper.findComponent(GlEmptyState);
- const allCaseRows = () => wrapper.findAllByTestId('test-case-row');
- const findCaseRowAtIndex = (index) => wrapper.findAllByTestId('test-case-row').at(index);
- const findLinkForRow = (row) => row.findComponent(GlLink);
- const findIconForRow = (row, status) => row.find(`.ci-status-icon-${status}`);
-
- const createComponent = ({ suite = testSuite, perPage = 20, errorMessage } = {}) => {
- store = new Vuex.Store({
- modules: {
- testReports: {
- namespaced: true,
- state: {
- blobPath,
- testReports: {
- test_suites: [suite],
- },
- selectedSuiteIndex: 0,
- pageInfo: {
- page: 1,
- perPage,
- },
- errorMessage,
- },
- getters,
- },
- },
- });
-
- wrapper = shallowMountExtended(SuiteTable, {
- provide: {
- blobPath: '/blob/path',
- summaryEndpoint: '/summary.json',
- suiteEndpoint: '/suite.json',
- },
- store,
- stubs: { GlFriendlyWrap },
- });
- };
-
- it('should render a message when there are no test cases', () => {
- createComponent({ suite: [] });
-
- expect(noCasesMessage().exists()).toBe(true);
- expect(artifactsExpiredMessage().exists()).toBe(false);
- });
-
- it('should render an empty state when artifacts have expired', () => {
- createComponent({ suite: [], errorMessage: ARTIFACTS_EXPIRED_ERROR_MESSAGE });
- const emptyState = artifactsExpiredEmptyState();
-
- expect(noCasesMessage().exists()).toBe(false);
- expect(artifactsExpiredMessage().exists()).toBe(true);
-
- expect(emptyState.exists()).toBe(true);
- expect(emptyState.props('title')).toBe(i18n.expiredArtifactsTitle);
- });
-
- describe('when a test suite is supplied', () => {
- beforeEach(() => createComponent());
-
- it('renders the correct number of rows', () => {
- expect(allCaseRows()).toHaveLength(testCases.length);
- });
-
- it.each([
- TestStatus.ERROR,
- TestStatus.FAILED,
- TestStatus.SKIPPED,
- TestStatus.SUCCESS,
- 'unknown',
- ])('renders the correct icon for test case with %s status', (status) => {
- const test = testCases.findIndex((x) => x.status === status);
- const row = findCaseRowAtIndex(test);
-
- expect(findIconForRow(row, status).exists()).toBe(true);
- });
-
- it('renders the file name for the test with a copy button', () => {
- const { file } = testCases[0];
- const relativeFile = formatFilePath(file);
- const filePath = `${blobPath}/${relativeFile}`;
- const row = findCaseRowAtIndex(0);
- const fileLink = findLinkForRow(row);
- const button = row.findComponent(GlButton);
-
- expect(fileLink.attributes('href')).toBe(filePath);
- expect(row.text()).toContain(file);
- expect(button.exists()).toBe(true);
- expect(button.attributes('data-clipboard-text')).toBe(file);
- });
- });
-
- describe('when a test suite has more test cases than the pagination size', () => {
- const perPage = 2;
-
- beforeEach(() => {
- createComponent({ testSuite, perPage });
- });
-
- it('renders one page of test cases', () => {
- expect(allCaseRows().length).toBe(perPage);
- });
-
- it('renders a pagination component', () => {
- expect(wrapper.findComponent(GlPagination).exists()).toBe(true);
- });
- });
-
- describe('when a test case classname property is null', () => {
- it('still renders all test cases', () => {
- createComponent({
- testSuite: {
- ...testSuite,
- test_cases: testSuite.test_cases.map((testCase) => ({
- ...testCase,
- classname: null,
- })),
- },
- });
-
- expect(allCaseRows()).toHaveLength(testCases.length);
- });
- });
-
- describe('when a test case name property is null', () => {
- it('still renders all test cases', () => {
- createComponent({
- testSuite: {
- ...testSuite,
- test_cases: testSuite.test_cases.map((testCase) => ({
- ...testCase,
- name: null,
- })),
- },
- });
-
- expect(allCaseRows()).toHaveLength(testCases.length);
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/test_summary_spec.js b/spec/frontend/pipelines/test_reports/test_summary_spec.js
deleted file mode 100644
index 7eed6671fb9..00000000000
--- a/spec/frontend/pipelines/test_reports/test_summary_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import { mount } from '@vue/test-utils';
-import testReports from 'test_fixtures/pipelines/test_report.json';
-import Summary from '~/pipelines/components/test_reports/test_summary.vue';
-import { formattedTime } from '~/pipelines/stores/test_reports/utils';
-
-describe('Test reports summary', () => {
- let wrapper;
-
- const {
- test_suites: [testSuite],
- } = testReports;
-
- const backButton = () => wrapper.find('.js-back-button');
- const totalTests = () => wrapper.find('.js-total-tests');
- const failedTests = () => wrapper.find('.js-failed-tests');
- const erroredTests = () => wrapper.find('.js-errored-tests');
- const successRate = () => wrapper.find('.js-success-rate');
- const duration = () => wrapper.find('.js-duration');
-
- const defaultProps = {
- report: testSuite,
- showBack: false,
- };
-
- const createComponent = (props) => {
- wrapper = mount(Summary, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- describe('should not render', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('a back button by default', () => {
- expect(backButton().exists()).toBe(false);
- });
- });
-
- describe('should render', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('a back button and emit on-back-click event', () => {
- createComponent({
- showBack: true,
- });
-
- expect(backButton().exists()).toBe(true);
- });
- });
-
- describe('when a report is supplied', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('displays the correct total', () => {
- expect(totalTests().text()).toBe('4 tests');
- });
-
- it('displays the correct failure count', () => {
- expect(failedTests().text()).toBe('2 failures');
- });
-
- it('displays the correct error count', () => {
- expect(erroredTests().text()).toBe('0 errors');
- });
-
- it('calculates and displays percentages correctly', () => {
- expect(successRate().text()).toBe('50% success rate');
- });
-
- it('displays the correctly formatted duration', () => {
- expect(duration().text()).toBe(formattedTime(testSuite.total_time));
- });
- });
-
- describe('success percentage calculation', () => {
- it.each`
- name | successCount | totalCount | skippedCount | result
- ${'displays 0 when there are no tests'} | ${0} | ${0} | ${0} | ${'0'}
- ${'displays whole number when possible'} | ${10} | ${50} | ${0} | ${'20'}
- ${'excludes skipped tests from total'} | ${10} | ${50} | ${5} | ${'22.22'}
- ${'rounds to 0.01'} | ${1} | ${16604} | ${0} | ${'0.01'}
- ${'correctly rounds to 50'} | ${8302} | ${16604} | ${0} | ${'50'}
- ${'rounds down for large close numbers'} | ${16603} | ${16604} | ${0} | ${'99.99'}
- ${'correctly displays 100'} | ${16604} | ${16604} | ${0} | ${'100'}
- `('$name', ({ successCount, totalCount, skippedCount, result }) => {
- createComponent({
- report: {
- success_count: successCount,
- skipped_count: skippedCount,
- total_count: totalCount,
- },
- });
-
- expect(successRate().text()).toBe(`${result}% success rate`);
- });
- });
-});
diff --git a/spec/frontend/pipelines/test_reports/test_summary_table_spec.js b/spec/frontend/pipelines/test_reports/test_summary_table_spec.js
deleted file mode 100644
index a45946d5a03..00000000000
--- a/spec/frontend/pipelines/test_reports/test_summary_table_spec.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import testReports from 'test_fixtures/pipelines/test_report.json';
-import SummaryTable from '~/pipelines/components/test_reports/test_summary_table.vue';
-import * as getters from '~/pipelines/stores/test_reports/getters';
-
-Vue.use(Vuex);
-
-describe('Test reports summary table', () => {
- let wrapper;
- let store;
-
- const allSuitesRows = () => wrapper.findAll('.js-suite-row');
- const noSuitesToShow = () => wrapper.find('.js-no-tests-suites');
-
- const defaultProps = {
- testReports,
- };
-
- const createComponent = (reports = null) => {
- store = new Vuex.Store({
- modules: {
- testReports: {
- namespaced: true,
- state: {
- testReports: reports || testReports,
- },
- getters,
- },
- },
- });
-
- wrapper = mount(SummaryTable, {
- provide: {
- blobPath: '/blob/path',
- summaryEndpoint: '/summary.json',
- suiteEndpoint: '/suite.json',
- },
- propsData: defaultProps,
- store,
- });
- };
-
- describe('when test reports are supplied', () => {
- beforeEach(() => createComponent());
- const findErrorIcon = () => wrapper.findComponent({ ref: 'suiteErrorIcon' });
-
- it('renders the correct number of rows', () => {
- expect(noSuitesToShow().exists()).toBe(false);
- expect(allSuitesRows().length).toBe(testReports.test_suites.length);
- });
-
- describe('when there is a suite error', () => {
- beforeEach(() => {
- createComponent({
- test_suites: [
- {
- ...testReports.test_suites[0],
- suite_error: 'Suite Error',
- },
- ],
- });
- });
-
- it('renders error icon', () => {
- expect(findErrorIcon().exists()).toBe(true);
- expect(findErrorIcon().attributes('title')).toEqual('Suite Error');
- });
- });
-
- describe('when there is not a suite error', () => {
- beforeEach(() => {
- createComponent({
- test_suites: [
- {
- ...testReports.test_suites[0],
- suite_error: null,
- },
- ],
- });
- });
-
- it('does not render error icon', () => {
- expect(findErrorIcon().exists()).toBe(false);
- });
- });
- });
-
- describe('when there are no test suites', () => {
- beforeEach(() => {
- createComponent({ test_suites: [] });
- });
-
- it('displays the no suites to show message', () => {
- expect(noSuitesToShow().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/pipelines/time_ago_spec.js b/spec/frontend/pipelines/time_ago_spec.js
deleted file mode 100644
index d2aa340a980..00000000000
--- a/spec/frontend/pipelines/time_ago_spec.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import { GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import TimeAgo from '~/pipelines/components/pipelines_list/time_ago.vue';
-
-describe('Timeago component', () => {
- let wrapper;
-
- const defaultProps = { duration: 0, finished_at: '' };
-
- const createComponent = (props = defaultProps, extraProps) => {
- wrapper = extendedWrapper(
- shallowMount(TimeAgo, {
- propsData: {
- pipeline: {
- details: {
- ...props,
- },
- },
- ...extraProps,
- },
- data() {
- return {
- iconTimerSvg: `<svg></svg>`,
- };
- },
- }),
- );
- };
-
- const duration = () => wrapper.find('.duration');
- const finishedAt = () => wrapper.find('.finished-at');
- const findCalendarIcon = () => wrapper.findByTestId('calendar-icon');
-
- describe('with duration', () => {
- beforeEach(() => {
- createComponent({ duration: 10, finished_at: '' });
- });
-
- it('should render duration and timer svg', () => {
- const icon = duration().findComponent(GlIcon);
-
- expect(duration().exists()).toBe(true);
- expect(icon.props('name')).toBe('timer');
- });
- });
-
- describe('without duration', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('should not render duration and timer svg', () => {
- expect(duration().exists()).toBe(false);
- });
- });
-
- describe('with finishedTime', () => {
- it('should render time', () => {
- createComponent({ duration: 0, finished_at: '2017-04-26T12:40:23.277Z' });
-
- const time = finishedAt().find('time');
-
- expect(finishedAt().exists()).toBe(true);
- expect(time.exists()).toBe(true);
- });
-
- it('should display calendar icon', () => {
- createComponent({ duration: 0, finished_at: '2017-04-26T12:40:23.277Z' });
-
- expect(findCalendarIcon().exists()).toBe(true);
- });
- });
-
- describe('without finishedTime', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('should not render time and calendar icon', () => {
- expect(finishedAt().exists()).toBe(false);
- expect(findCalendarIcon().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
deleted file mode 100644
index d518519a424..00000000000
--- a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
-import { nextTick } from 'vue';
-import { shallowMount } from '@vue/test-utils';
-import waitForPromises from 'helpers/wait_for_promises';
-import Api from '~/api';
-import PipelineBranchNameToken from '~/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue';
-import { branches, mockBranchesAfterMap } from '../mock_data';
-
-describe('Pipeline Branch Name Token', () => {
- let wrapper;
-
- const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
- const findAllFilteredSearchSuggestions = () =>
- wrapper.findAllComponents(GlFilteredSearchSuggestion);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const getBranchSuggestions = () =>
- findAllFilteredSearchSuggestions().wrappers.map((w) => w.text());
-
- const stubs = {
- GlFilteredSearchToken: {
- template: `<div><slot name="suggestions"></slot></div>`,
- },
- };
-
- const defaultProps = {
- config: {
- type: 'ref',
- icon: 'branch',
- title: 'Branch name',
- unique: true,
- projectId: '21',
- defaultBranchName: null,
- disabled: false,
- },
- value: {
- data: '',
- },
- cursorPosition: 'start',
- };
-
- const optionsWithDefaultBranchName = (options) => {
- return {
- propsData: {
- ...defaultProps,
- config: {
- ...defaultProps.config,
- defaultBranchName: 'main',
- },
- },
- ...options,
- };
- };
-
- const createComponent = (options, data) => {
- wrapper = shallowMount(PipelineBranchNameToken, {
- propsData: {
- ...defaultProps,
- },
- data() {
- return {
- ...data,
- };
- },
- ...options,
- });
- };
-
- beforeEach(() => {
- jest.spyOn(Api, 'branches').mockResolvedValue({ data: branches });
-
- createComponent();
- });
-
- it('passes config correctly', () => {
- expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
- });
-
- it('fetches and sets project branches', () => {
- expect(Api.branches).toHaveBeenCalled();
-
- expect(wrapper.vm.branches).toEqual(mockBranchesAfterMap);
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- describe('displays loading icon correctly', () => {
- it('shows loading icon', () => {
- createComponent({ stubs }, { loading: true });
-
- expect(findLoadingIcon().exists()).toBe(true);
- });
-
- it('does not show loading icon', () => {
- createComponent({ stubs }, { loading: false });
-
- expect(findLoadingIcon().exists()).toBe(false);
- });
- });
-
- describe('shows branches correctly', () => {
- it('renders all branches', () => {
- createComponent({ stubs }, { branches, loading: false });
-
- expect(findAllFilteredSearchSuggestions()).toHaveLength(branches.length);
- });
-
- it('renders only the branch searched for', () => {
- const mockBranches = ['main'];
- createComponent({ stubs }, { branches: mockBranches, loading: false });
-
- expect(findAllFilteredSearchSuggestions()).toHaveLength(mockBranches.length);
- });
-
- it('shows the default branch first if no branch was searched for', async () => {
- const mockBranches = [{ name: 'branch-1' }];
- jest.spyOn(Api, 'branches').mockResolvedValue({ data: mockBranches });
-
- createComponent(optionsWithDefaultBranchName({ stubs }), { loading: false });
- await nextTick();
- expect(getBranchSuggestions()).toEqual(['main', 'branch-1']);
- });
-
- it('does not show the default branch if a search term was provided', async () => {
- const mockBranches = [{ name: 'branch-1' }];
- jest.spyOn(Api, 'branches').mockResolvedValue({ data: mockBranches });
-
- createComponent(optionsWithDefaultBranchName(), { loading: false });
-
- findFilteredSearchToken().vm.$emit('input', { data: 'branch-1' });
- await waitForPromises();
- expect(getBranchSuggestions()).toEqual(['branch-1']);
- });
-
- it('shows the default branch only once if it appears in the results', async () => {
- const mockBranches = [{ name: 'main' }];
- jest.spyOn(Api, 'branches').mockResolvedValue({ data: mockBranches });
-
- createComponent(optionsWithDefaultBranchName({ stubs }), { loading: false });
- await nextTick();
- expect(getBranchSuggestions()).toEqual(['main']);
- });
- });
-});
diff --git a/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js
deleted file mode 100644
index 60abb63a7e0..00000000000
--- a/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { PIPELINE_SOURCES } from 'ee_else_ce/pipelines/components/pipelines_list/tokens/constants';
-import { stubComponent } from 'helpers/stub_component';
-import PipelineSourceToken from '~/pipelines/components/pipelines_list/tokens/pipeline_source_token.vue';
-
-describe('Pipeline Source Token', () => {
- let wrapper;
-
- const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
- const findAllFilteredSearchSuggestions = () =>
- wrapper.findAllComponents(GlFilteredSearchSuggestion);
-
- const defaultProps = {
- config: {
- type: 'source',
- icon: 'trigger-source',
- title: 'Source',
- unique: true,
- },
- value: {
- data: '',
- },
- cursorPosition: 'start',
- };
-
- const createComponent = () => {
- wrapper = shallowMount(PipelineSourceToken, {
- propsData: {
- ...defaultProps,
- },
- stubs: {
- GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
- template: `<div><slot name="suggestions"></slot></div>`,
- }),
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('passes config correctly', () => {
- expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
- });
-
- describe('shows sources correctly', () => {
- it('renders all pipeline sources available', () => {
- expect(findAllFilteredSearchSuggestions()).toHaveLength(PIPELINE_SOURCES.length);
- });
- });
-});
diff --git a/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js
deleted file mode 100644
index cf4ccb5ce43..00000000000
--- a/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { stubComponent } from 'helpers/stub_component';
-import PipelineStatusToken from '~/pipelines/components/pipelines_list/tokens/pipeline_status_token.vue';
-import {
- TOKEN_TITLE_STATUS,
- TOKEN_TYPE_STATUS,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-
-describe('Pipeline Status Token', () => {
- let wrapper;
-
- const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
- const findAllFilteredSearchSuggestions = () =>
- wrapper.findAllComponents(GlFilteredSearchSuggestion);
- const findAllGlIcons = () => wrapper.findAllComponents(GlIcon);
-
- const defaultProps = {
- config: {
- type: TOKEN_TYPE_STATUS,
- icon: 'status',
- title: TOKEN_TITLE_STATUS,
- unique: true,
- },
- value: {
- data: '',
- },
- cursorPosition: 'start',
- };
-
- const createComponent = () => {
- wrapper = shallowMount(PipelineStatusToken, {
- propsData: {
- ...defaultProps,
- },
- stubs: {
- GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
- template: `<div><slot name="suggestions"></slot></div>`,
- }),
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- it('passes config correctly', () => {
- expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
- });
-
- describe('shows statuses correctly', () => {
- it('renders all pipeline statuses available', () => {
- expect(findAllFilteredSearchSuggestions()).toHaveLength(wrapper.vm.statuses.length);
- expect(findAllGlIcons()).toHaveLength(wrapper.vm.statuses.length);
- });
- });
-});
diff --git a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
deleted file mode 100644
index 88c88d8f16f..00000000000
--- a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Api from '~/api';
-import PipelineTagNameToken from '~/pipelines/components/pipelines_list/tokens/pipeline_tag_name_token.vue';
-import { tags, mockTagsAfterMap } from '../mock_data';
-
-describe('Pipeline Branch Name Token', () => {
- let wrapper;
-
- const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
- const findAllFilteredSearchSuggestions = () =>
- wrapper.findAllComponents(GlFilteredSearchSuggestion);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
-
- const stubs = {
- GlFilteredSearchToken: {
- template: `<div><slot name="suggestions"></slot></div>`,
- },
- };
-
- const defaultProps = {
- config: {
- type: 'tag',
- icon: 'tag',
- title: 'Tag name',
- unique: true,
- projectId: '21',
- disabled: false,
- },
- value: {
- data: '',
- },
- cursorPosition: 'start',
- };
-
- const createComponent = (options, data) => {
- wrapper = shallowMount(PipelineTagNameToken, {
- propsData: {
- ...defaultProps,
- },
- data() {
- return {
- ...data,
- };
- },
- ...options,
- });
- };
-
- beforeEach(() => {
- jest.spyOn(Api, 'tags').mockResolvedValue({ data: tags });
-
- createComponent();
- });
-
- it('passes config correctly', () => {
- expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
- });
-
- it('fetches and sets project tags', () => {
- expect(Api.tags).toHaveBeenCalled();
-
- expect(wrapper.vm.tags).toEqual(mockTagsAfterMap);
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- describe('displays loading icon correctly', () => {
- it('shows loading icon', () => {
- createComponent({ stubs }, { loading: true });
-
- expect(findLoadingIcon().exists()).toBe(true);
- });
-
- it('does not show loading icon', () => {
- createComponent({ stubs }, { loading: false });
-
- expect(findLoadingIcon().exists()).toBe(false);
- });
- });
-
- describe('shows tags correctly', () => {
- it('renders all tags', () => {
- createComponent({ stubs }, { tags, loading: false });
-
- expect(findAllFilteredSearchSuggestions()).toHaveLength(tags.length);
- });
-
- it('renders only the tag searched for', () => {
- const mockTags = ['main-tag'];
- createComponent({ stubs }, { tags: mockTags, loading: false });
-
- expect(findAllFilteredSearchSuggestions()).toHaveLength(mockTags.length);
- });
- });
-});
diff --git a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
deleted file mode 100644
index e9ec684a350..00000000000
--- a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import { GlFilteredSearchToken, GlFilteredSearchSuggestion, GlLoadingIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { stubComponent } from 'helpers/stub_component';
-import Api from '~/api';
-import PipelineTriggerAuthorToken from '~/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue';
-import { users } from '../mock_data';
-
-describe('Pipeline Trigger Author Token', () => {
- let wrapper;
-
- const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
- const findAllFilteredSearchSuggestions = () =>
- wrapper.findAllComponents(GlFilteredSearchSuggestion);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
-
- const defaultProps = {
- config: {
- type: 'username',
- icon: 'user',
- title: 'Trigger author',
- dataType: 'username',
- unique: true,
- triggerAuthors: users,
- },
- value: {
- data: '',
- },
- cursorPosition: 'start',
- };
-
- const createComponent = (data) => {
- wrapper = shallowMount(PipelineTriggerAuthorToken, {
- propsData: {
- ...defaultProps,
- },
- data() {
- return {
- ...data,
- };
- },
- stubs: {
- GlFilteredSearchToken: stubComponent(GlFilteredSearchToken, {
- template: `<div><slot name="suggestions"></slot></div>`,
- }),
- },
- });
- };
-
- beforeEach(() => {
- jest.spyOn(Api, 'projectUsers').mockResolvedValue(users);
-
- createComponent();
- });
-
- it('passes config correctly', () => {
- expect(findFilteredSearchToken().props('config')).toEqual(defaultProps.config);
- });
-
- it('fetches and sets project users', () => {
- expect(Api.projectUsers).toHaveBeenCalled();
-
- expect(wrapper.vm.users).toEqual(users);
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- describe('displays loading icon correctly', () => {
- it('shows loading icon', () => {
- createComponent({ loading: true });
-
- expect(findLoadingIcon().exists()).toBe(true);
- });
-
- it('does not show loading icon', () => {
- createComponent({ loading: false });
-
- expect(findLoadingIcon().exists()).toBe(false);
- });
- });
-
- describe('shows trigger authors correctly', () => {
- beforeEach(() => {});
-
- it('renders all trigger authors', () => {
- createComponent({ users, loading: false });
-
- // should have length of all users plus the static 'Any' option
- expect(findAllFilteredSearchSuggestions()).toHaveLength(users.length + 1);
- });
-
- it('renders only the trigger author searched for', () => {
- createComponent({
- users: [{ name: 'Arnold', username: 'admin', state: 'active', avatar_url: 'avatar-link' }],
- loading: false,
- });
-
- expect(findAllFilteredSearchSuggestions()).toHaveLength(2);
- });
- });
-});
diff --git a/spec/frontend/pipelines/unwrapping_utils_spec.js b/spec/frontend/pipelines/unwrapping_utils_spec.js
deleted file mode 100644
index a6ce7d4049f..00000000000
--- a/spec/frontend/pipelines/unwrapping_utils_spec.js
+++ /dev/null
@@ -1,127 +0,0 @@
-import {
- unwrapGroups,
- unwrapNodesWithName,
- unwrapStagesWithNeeds,
-} from '~/pipelines/components/unwrapping_utils';
-
-const groupsArray = [
- {
- name: 'build_a',
- size: 1,
- status: {
- label: 'passed',
- group: 'success',
- icon: 'status_success',
- },
- },
- {
- name: 'bob_the_build',
- size: 1,
- status: {
- label: 'passed',
- group: 'success',
- icon: 'status_success',
- },
- },
-];
-
-const basicStageInfo = {
- name: 'center_stage',
- status: {
- action: null,
- },
-};
-
-const stagesAndGroups = [
- {
- ...basicStageInfo,
- groups: {
- nodes: groupsArray,
- },
- },
-];
-
-const needArray = [
- {
- name: 'build_b',
- },
-];
-
-const elephantArray = [
- {
- name: 'build_b',
- elephant: 'gray',
- },
-];
-
-const baseJobs = {
- name: 'test_d',
- status: {
- icon: 'status_success',
- tooltip: null,
- hasDetails: true,
- detailsPath: '/root/abcd-dag/-/pipelines/162',
- group: 'success',
- action: null,
- },
-};
-
-const jobArrayWithNeeds = [
- {
- ...baseJobs,
- needs: {
- nodes: needArray,
- },
- },
-];
-
-const jobArrayWithElephant = [
- {
- ...baseJobs,
- needs: {
- nodes: elephantArray,
- },
- },
-];
-
-const completeMock = [
- {
- ...basicStageInfo,
- groups: {
- nodes: groupsArray.map((group) => ({ ...group, jobs: { nodes: jobArrayWithNeeds } })),
- },
- },
-];
-
-describe('Shared pipeline unwrapping utils', () => {
- describe('unwrapGroups', () => {
- it('takes stages without nodes and returns the unwrapped groups', () => {
- expect(unwrapGroups(stagesAndGroups)[0].node.groups).toEqual(groupsArray);
- });
-
- it('keeps other stage properties intact', () => {
- expect(unwrapGroups(stagesAndGroups)[0].node).toMatchObject(basicStageInfo);
- });
- });
-
- describe('unwrapNodesWithName', () => {
- it('works with no field argument', () => {
- expect(unwrapNodesWithName(jobArrayWithNeeds, 'needs')[0].needs).toEqual([needArray[0].name]);
- });
-
- it('works with custom field argument', () => {
- expect(unwrapNodesWithName(jobArrayWithElephant, 'needs', 'elephant')[0].needs).toEqual([
- elephantArray[0].elephant,
- ]);
- });
- });
-
- describe('unwrapStagesWithNeeds', () => {
- it('removes nodes from groups, jobs, and needs', () => {
- const firstProcessedGroup = unwrapStagesWithNeeds(completeMock)[0].groups[0];
- expect(firstProcessedGroup).toMatchObject(groupsArray[0]);
- expect(firstProcessedGroup.jobs[0]).toMatchObject(baseJobs);
- expect(firstProcessedGroup.jobs[0].needs[0]).toBe(needArray[0].name);
- });
- });
-});
diff --git a/spec/frontend/pipelines/utils_spec.js b/spec/frontend/pipelines/utils_spec.js
deleted file mode 100644
index 286d79edc6c..00000000000
--- a/spec/frontend/pipelines/utils_spec.js
+++ /dev/null
@@ -1,191 +0,0 @@
-import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
-import { createSankey } from '~/pipelines/components/dag/drawing_utils';
-import {
- makeLinksFromNodes,
- filterByAncestors,
- generateColumnsFromLayersListBare,
- keepLatestDownstreamPipelines,
- listByLayers,
- parseData,
- removeOrphanNodes,
- getMaxNodes,
-} from '~/pipelines/components/parsing_utils';
-import { createNodeDict } from '~/pipelines/utils';
-
-import { mockDownstreamPipelinesRest } from '../vue_merge_request_widget/mock_data';
-import { mockDownstreamPipelinesGraphql } from '../commit/mock_data';
-import { mockParsedGraphQLNodes, missingJob } from './components/dag/mock_data';
-import { generateResponse } from './graph/mock_data';
-
-describe('DAG visualization parsing utilities', () => {
- const nodeDict = createNodeDict(mockParsedGraphQLNodes);
- const unfilteredLinks = makeLinksFromNodes(mockParsedGraphQLNodes, nodeDict);
- const parsed = parseData(mockParsedGraphQLNodes);
-
- describe('makeLinksFromNodes', () => {
- it('returns the expected link structure', () => {
- expect(unfilteredLinks[0]).toHaveProperty('source', 'build_a');
- expect(unfilteredLinks[0]).toHaveProperty('target', 'test_a');
- expect(unfilteredLinks[0]).toHaveProperty('value', 10);
- });
-
- it('does not generate a link for non-existing jobs', () => {
- const sources = unfilteredLinks.map(({ source }) => source);
-
- expect(sources.includes(missingJob)).toBe(false);
- });
- });
-
- describe('filterByAncestors', () => {
- const allLinks = [
- { source: 'job1', target: 'job4' },
- { source: 'job1', target: 'job2' },
- { source: 'job2', target: 'job4' },
- ];
-
- const dedupedLinks = [
- { source: 'job1', target: 'job2' },
- { source: 'job2', target: 'job4' },
- ];
-
- const nodeLookup = {
- job1: {
- name: 'job1',
- },
- job2: {
- name: 'job2',
- needs: ['job1'],
- },
- job4: {
- name: 'job4',
- needs: ['job1', 'job2'],
- category: 'build',
- },
- };
-
- it('dedupes links', () => {
- expect(filterByAncestors(allLinks, nodeLookup)).toMatchObject(dedupedLinks);
- });
- });
-
- describe('parseData parent function', () => {
- it('returns an object containing a list of nodes and links', () => {
- // an array of nodes exist and the values are defined
- expect(parsed).toHaveProperty('nodes');
- expect(Array.isArray(parsed.nodes)).toBe(true);
- expect(parsed.nodes.filter(Boolean)).not.toHaveLength(0);
-
- // an array of links exist and the values are defined
- expect(parsed).toHaveProperty('links');
- expect(Array.isArray(parsed.links)).toBe(true);
- expect(parsed.links.filter(Boolean)).not.toHaveLength(0);
- });
- });
-
- describe('removeOrphanNodes', () => {
- it('removes sankey nodes that have no needs and are not needed', () => {
- const layoutSettings = {
- width: 200,
- height: 200,
- nodeWidth: 10,
- nodePadding: 20,
- paddingForLabels: 100,
- };
-
- const sankeyLayout = createSankey(layoutSettings)(parsed);
- const cleanedNodes = removeOrphanNodes(sankeyLayout.nodes);
- /*
- These lengths are determined by the mock data.
- If the data changes, the numbers may also change.
- */
- expect(parsed.nodes).toHaveLength(mockParsedGraphQLNodes.length);
- expect(cleanedNodes).toHaveLength(12);
- });
- });
-
- describe('getMaxNodes', () => {
- it('returns the number of nodes in the most populous generation', () => {
- const layerNodes = [
- { layer: 0 },
- { layer: 0 },
- { layer: 1 },
- { layer: 1 },
- { layer: 0 },
- { layer: 3 },
- { layer: 2 },
- { layer: 4 },
- { layer: 1 },
- { layer: 3 },
- { layer: 4 },
- ];
- expect(getMaxNodes(layerNodes)).toBe(3);
- });
- });
-
- describe('generateColumnsFromLayersList', () => {
- const pipeline = generateResponse(mockPipelineResponse, 'root/fungi-xoxo');
- const { pipelineLayers } = listByLayers(pipeline);
- const columns = generateColumnsFromLayersListBare(pipeline, pipelineLayers);
-
- it('returns stage-like objects with default name, id, and status', () => {
- columns.forEach((col, idx) => {
- expect(col).toMatchObject({
- name: '',
- status: { action: null },
- id: `layer-${idx}`,
- });
- });
- });
-
- it('creates groups that match the list created in listByLayers', () => {
- columns.forEach((col, idx) => {
- const groupNames = col.groups.map(({ name }) => name);
- expect(groupNames).toEqual(pipelineLayers[idx]);
- });
- });
-
- it('looks up the correct group object', () => {
- columns.forEach((col) => {
- col.groups.forEach((group) => {
- const groupStage = pipeline.stages.find((el) => el.name === group.stageName);
- const groupObject = groupStage.groups.find((el) => el.name === group.name);
- expect(group).toBe(groupObject);
- });
- });
- });
- });
-});
-
-describe('linked pipeline utilities', () => {
- describe('keepLatestDownstreamPipelines', () => {
- it('filters data from GraphQL', () => {
- const downstream = mockDownstreamPipelinesGraphql().nodes;
- const latestDownstream = keepLatestDownstreamPipelines(downstream);
-
- expect(downstream).toHaveLength(3);
- expect(latestDownstream).toHaveLength(1);
- });
-
- it('filters data from REST', () => {
- const downstream = mockDownstreamPipelinesRest();
- const latestDownstream = keepLatestDownstreamPipelines(downstream);
-
- expect(downstream).toHaveLength(2);
- expect(latestDownstream).toHaveLength(1);
- });
-
- it('returns downstream pipelines if sourceJob.retried is null', () => {
- const downstream = mockDownstreamPipelinesGraphql({ includeSourceJobRetried: false }).nodes;
- const latestDownstream = keepLatestDownstreamPipelines(downstream);
-
- expect(latestDownstream).toHaveLength(downstream.length);
- });
-
- it('returns downstream pipelines if source_job.retried is null', () => {
- const downstream = mockDownstreamPipelinesRest({ includeSourceJobRetried: false });
- const latestDownstream = keepLatestDownstreamPipelines(downstream);
-
- expect(latestDownstream).toHaveLength(downstream.length);
- });
- });
-});
diff --git a/spec/frontend/profile/preferences/components/__snapshots__/diffs_colors_preview_spec.js.snap b/spec/frontend/profile/preferences/components/__snapshots__/diffs_colors_preview_spec.js.snap
index f675b6cf15c..7d5e0cccb38 100644
--- a/spec/frontend/profile/preferences/components/__snapshots__/diffs_colors_preview_spec.js.snap
+++ b/spec/frontend/profile/preferences/components/__snapshots__/diffs_colors_preview_spec.js.snap
@@ -7,7 +7,6 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
<label>
Preview
</label>
-
<table
class="code"
>
@@ -16,71 +15,66 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="1"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
<span
class="c1"
>
- #
+ #
<span
- class="idiff deletion"
+ class="deletion idiff"
>
Removed
</span>
- content
+ content
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="1"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
<span
class="c1"
>
- #
+ #
<span
- class="idiff addition"
+ class="addition idiff"
>
Added
</span>
- content
+ content
</span>
</span>
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="2"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
<span
@@ -88,13 +82,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
v
</span>
-
<span
class="o"
>
=
</span>
-
<span
class="mi"
>
@@ -102,17 +94,15 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="2"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
<span
@@ -120,13 +110,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
v
</span>
-
<span
class="o"
>
=
</span>
-
<span
class="mi"
>
@@ -135,20 +123,18 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="3"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
<span
@@ -156,13 +142,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
s
</span>
-
<span
class="o"
>
=
</span>
-
<span
class="s"
>
@@ -170,17 +154,15 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="3"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
<span
@@ -188,13 +170,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
s
</span>
-
<span
class="o"
>
=
</span>
-
<span
class="s"
>
@@ -203,52 +183,46 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="4"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span />
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="4"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span />
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="5"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
<span
@@ -256,19 +230,16 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
for
</span>
-
<span
class="n"
>
i
</span>
-
<span
class="ow"
>
in
</span>
-
<span
class="nb"
>
@@ -294,7 +265,6 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
,
</span>
-
<span
class="mi"
>
@@ -307,17 +277,15 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="5"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
<span
@@ -325,19 +293,16 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
for
</span>
-
<span
class="n"
>
i
</span>
-
<span
class="ow"
>
in
</span>
-
<span
class="nb"
>
@@ -363,7 +328,6 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
,
</span>
-
<span
class="mi"
>
@@ -377,25 +341,21 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="6"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
- <span>
-
- </span>
+ <span />
<span
class="k"
>
@@ -411,13 +371,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
i
</span>
-
<span
class="o"
>
+
</span>
-
<span
class="mi"
>
@@ -430,22 +388,18 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="6"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
- <span>
-
- </span>
+ <span />
<span
class="k"
>
@@ -461,13 +415,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
i
</span>
-
<span
class="o"
>
+
</span>
-
<span
class="mi"
>
@@ -481,52 +433,46 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="7"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span />
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="7"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span />
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="8"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
<span
@@ -534,7 +480,6 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
class
</span>
-
<span
class="nc"
>
@@ -557,17 +502,15 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="8"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
<span
@@ -575,7 +518,6 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
class
</span>
-
<span
class="nc"
>
@@ -599,31 +541,26 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="9"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
- <span>
-
- </span>
+ <span />
<span
class="k"
>
def
</span>
-
<span
class="nf"
>
@@ -644,7 +581,6 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
,
</span>
-
<span
class="n"
>
@@ -657,28 +593,23 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="9"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
- <span>
-
- </span>
+ <span />
<span
class="k"
>
def
</span>
-
<span
class="nf"
>
@@ -699,7 +630,6 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
,
</span>
-
<span
class="n"
>
@@ -713,25 +643,21 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="10"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
- <span>
-
- </span>
+ <span />
<span
class="bp"
>
@@ -747,13 +673,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
val
</span>
-
<span
class="o"
>
=
</span>
-
<span
class="n"
>
@@ -761,22 +685,18 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="10"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
- <span>
-
- </span>
+ <span />
<span
class="bp"
>
@@ -792,13 +712,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
val
</span>
-
<span
class="o"
>
=
</span>
-
<span
class="n"
>
@@ -807,25 +725,21 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</td>
</tr>
-
<tr
class="line_holder parallel"
>
<td
- class="old_line diff-line-num old"
+ class="diff-line-num old old_line"
>
<a
data-linenumber="11"
/>
</td>
-
<td
- class="line_content parallel left-side old"
+ class="left-side line_content old parallel"
>
<span>
- <span>
-
- </span>
+ <span />
<span
class="bp"
>
@@ -841,13 +755,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
next
</span>
-
<span
class="o"
>
=
</span>
-
<span
class="bp"
>
@@ -855,22 +767,18 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
</span>
</span>
</td>
-
<td
- class="new_line diff-line-num new"
+ class="diff-line-num new new_line"
>
<a
data-linenumber="11"
/>
</td>
-
<td
- class="line_content parallel right-side new"
+ class="line_content new parallel right-side"
>
<span>
- <span>
-
- </span>
+ <span />
<span
class="bp"
>
@@ -886,13 +794,11 @@ exports[`DiffsColorsPreview component renders diff colors preview 1`] = `
>
next
</span>
-
<span
class="o"
>
=
</span>
-
<span
class="bp"
>
diff --git a/spec/frontend/projects/commit/components/form_modal_spec.js b/spec/frontend/projects/commit/components/form_modal_spec.js
index d40e2d7a48c..7ea3a74418d 100644
--- a/spec/frontend/projects/commit/components/form_modal_spec.js
+++ b/spec/frontend/projects/commit/components/form_modal_spec.js
@@ -72,11 +72,11 @@ describe('CommitFormModal', () => {
it('Shows modal', () => {
createComponent();
- const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit');
+ const rootWrapper = createWrapper(wrapper.vm.$root);
- wrapper.vm.show();
+ eventHub.$emit(mockData.modalPropsData.openModal);
- expect(rootEmit).toHaveBeenCalledWith(BV_SHOW_MODAL, mockData.modalPropsData.modalId);
+ expect(rootWrapper.emitted(BV_SHOW_MODAL)[0]).toContain(mockData.modalPropsData.modalId);
});
it('Clears the modal state once modal is hidden', () => {
@@ -150,8 +150,9 @@ describe('CommitFormModal', () => {
it('Action primary button dispatches submit action', () => {
getByText(mockData.modalPropsData.i18n.actionPrimaryText).trigger('click');
+ const formSubmitSpy = jest.spyOn(findForm().element, 'submit');
- expect(wrapper.vm.$refs.form.$el.submit).toHaveBeenCalled();
+ expect(formSubmitSpy).toHaveBeenCalled();
});
it('Changes the start_branch input value', async () => {
diff --git a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
deleted file mode 100644
index e289569f8ce..00000000000
--- a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import AxiosMockAdapter from 'axios-mock-adapter';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import RevisionDropdown from '~/projects/compare/components/revision_dropdown_legacy.vue';
-
-const defaultProps = {
- refsProjectPath: 'some/refs/path',
- revisionText: 'Target',
- paramsName: 'from',
- paramsBranch: 'main',
-};
-
-jest.mock('~/alert');
-
-describe('RevisionDropdown component', () => {
- let wrapper;
- let axiosMock;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(RevisionDropdown, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- beforeEach(() => {
- axiosMock = new AxiosMockAdapter(axios);
- createComponent();
- });
-
- afterEach(() => {
- axiosMock.restore();
- });
-
- const findGlDropdown = () => wrapper.findComponent(GlDropdown);
- const findBranchesDropdownItem = () =>
- wrapper.findAllComponents('[data-testid="branches-dropdown-item"]');
- const findTagsDropdownItem = () =>
- wrapper.findAllComponents('[data-testid="tags-dropdown-item"]');
-
- it('sets hidden input', () => {
- expect(wrapper.find('input[type="hidden"]').attributes('value')).toBe(
- defaultProps.paramsBranch,
- );
- });
-
- it('update the branches on success', async () => {
- const Branches = ['branch-1', 'branch-2'];
- const Tags = ['tag-1', 'tag-2', 'tag-3'];
-
- axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(HTTP_STATUS_OK, {
- Branches,
- Tags,
- });
-
- createComponent();
-
- expect(findBranchesDropdownItem()).toHaveLength(0);
- expect(findTagsDropdownItem()).toHaveLength(0);
-
- await waitForPromises();
-
- Branches.forEach((branch, index) => {
- expect(findBranchesDropdownItem().at(index).text()).toBe(branch);
- });
-
- Tags.forEach((tag, index) => {
- expect(findTagsDropdownItem().at(index).text()).toBe(tag);
- });
-
- expect(findBranchesDropdownItem()).toHaveLength(Branches.length);
- expect(findTagsDropdownItem()).toHaveLength(Tags.length);
- });
-
- it('sets branches and tags to be an empty array when no tags or branches are given', async () => {
- axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(HTTP_STATUS_OK, {
- Branches: undefined,
- Tags: undefined,
- });
-
- await waitForPromises();
-
- expect(findBranchesDropdownItem()).toHaveLength(0);
- expect(findTagsDropdownItem()).toHaveLength(0);
- });
-
- it('shows an alert on error', async () => {
- axiosMock.onGet('some/invalid/path').replyOnce(HTTP_STATUS_NOT_FOUND);
-
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalled();
- });
-
- describe('GlDropdown component', () => {
- it('renders props', () => {
- expect(wrapper.props()).toEqual(expect.objectContaining(defaultProps));
- });
-
- it('display default text', () => {
- createComponent({
- paramsBranch: null,
- });
- expect(findGlDropdown().props('text')).toBe('Select branch/tag');
- });
-
- it('display params branch text', () => {
- expect(findGlDropdown().props('text')).toBe(defaultProps.paramsBranch);
- });
-
- it('emits a "selectRevision" event when a revision is selected', async () => {
- const findGlDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findFirstGlDropdownItem = () => findGlDropdownItems().at(0);
- const branchName = 'some-branch';
-
- axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(HTTP_STATUS_OK, {
- Branches: [branchName],
- });
-
- createComponent();
- await waitForPromises();
-
- findFirstGlDropdownItem().vm.$emit('click');
-
- expect(wrapper.emitted()).toEqual({
- selectRevision: [[{ direction: 'from', revision: branchName }]],
- });
- });
- });
-});
diff --git a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
index 4893ee26178..479530c1d38 100644
--- a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
+++ b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
@@ -10,12 +10,10 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
type="hidden"
value="delete"
/>
-
<input
name="authenticity_token"
type="hidden"
/>
-
<delete-modal-stub
confirmphrase="foo"
forkscount="3"
@@ -23,7 +21,6 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
mergerequestscount="2"
starscount="4"
/>
-
<gl-button-stub
buttontextclasses=""
category="primary"
diff --git a/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap b/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap
index 61bcd44724c..efce72271e0 100644
--- a/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap
+++ b/spec/frontend/projects/pipelines/charts/components/__snapshots__/ci_cd_analytics_area_chart_spec.js.snap
@@ -7,7 +7,6 @@ exports[`CiCdAnalyticsAreaChart matches the snapshot 1`] = `
<p>
Some title
</p>
-
<glareachart-stub
annotations=""
data="[object Object],[object Object]"
diff --git a/spec/frontend/projects/pipelines/charts/components/__snapshots__/statistics_list_spec.js.snap b/spec/frontend/projects/pipelines/charts/components/__snapshots__/statistics_list_spec.js.snap
index 5ec0ad794fb..16d291804cc 100644
--- a/spec/frontend/projects/pipelines/charts/components/__snapshots__/statistics_list_spec.js.snap
+++ b/spec/frontend/projects/pipelines/charts/components/__snapshots__/statistics_list_spec.js.snap
@@ -6,7 +6,6 @@ exports[`StatisticsList displays the counts data with labels 1`] = `
<span>
Total:
</span>
-
<strong>
4 pipelines
</strong>
@@ -15,7 +14,6 @@ exports[`StatisticsList displays the counts data with labels 1`] = `
<span>
Successful:
</span>
-
<strong>
2 pipelines
</strong>
@@ -24,20 +22,16 @@ exports[`StatisticsList displays the counts data with labels 1`] = `
<span>
Failed:
</span>
-
<gl-link-stub
href="/flightjs/Flight/-/pipelines?page=1&scope=all&status=failed"
>
-
- 2 pipelines
-
+ 2 pipelines
</gl-link-stub>
</li>
<li>
<span>
Success ratio:
</span>
-
<strong>
50.00%
</strong>
diff --git a/spec/frontend/projects/settings/access_dropdown_spec.js b/spec/frontend/projects/settings/access_dropdown_spec.js
deleted file mode 100644
index a94d7669b2b..00000000000
--- a/spec/frontend/projects/settings/access_dropdown_spec.js
+++ /dev/null
@@ -1,204 +0,0 @@
-import $ from 'jquery';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import AccessDropdown from '~/projects/settings/access_dropdown';
-import { LEVEL_TYPES } from '~/projects/settings/constants';
-
-describe('AccessDropdown', () => {
- const defaultLabel = 'dummy default label';
- let dropdown;
-
- beforeEach(() => {
- setHTMLFixture(`
- <div id="dummy-dropdown">
- <span class="dropdown-toggle-text"></span>
- </div>
- `);
- const $dropdown = $('#dummy-dropdown');
- $dropdown.data('defaultLabel', defaultLabel);
- const options = {
- $dropdown,
- accessLevelsData: {
- roles: [
- {
- id: 42,
- text: 'Dummy Role',
- },
- ],
- },
- };
- dropdown = new AccessDropdown(options);
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- describe('toggleLabel', () => {
- let $dropdownToggleText;
- const dummyItems = [
- { type: LEVEL_TYPES.ROLE, access_level: 42 },
- { type: LEVEL_TYPES.USER },
- { type: LEVEL_TYPES.USER },
- { type: LEVEL_TYPES.GROUP },
- { type: LEVEL_TYPES.GROUP },
- { type: LEVEL_TYPES.GROUP },
- { type: LEVEL_TYPES.DEPLOY_KEY },
- { type: LEVEL_TYPES.DEPLOY_KEY },
- { type: LEVEL_TYPES.DEPLOY_KEY },
- ];
-
- beforeEach(() => {
- $dropdownToggleText = $('.dropdown-toggle-text');
- });
-
- it('displays number of items', () => {
- dropdown.setSelectedItems(dummyItems);
- $dropdownToggleText.addClass('is-default');
-
- const label = dropdown.toggleLabel();
-
- expect(label).toBe('1 role, 2 users, 3 deploy keys, 3 groups');
- expect($dropdownToggleText).not.toHaveClass('is-default');
- });
-
- describe('without selected items', () => {
- beforeEach(() => {
- dropdown.setSelectedItems([]);
- });
-
- it('falls back to default label', () => {
- const label = dropdown.toggleLabel();
-
- expect(label).toBe(defaultLabel);
- expect($dropdownToggleText).toHaveClass('is-default');
- });
- });
-
- describe('with only role', () => {
- beforeEach(() => {
- dropdown.setSelectedItems(dummyItems.filter((item) => item.type === LEVEL_TYPES.ROLE));
- $dropdownToggleText.addClass('is-default');
- });
-
- it('displays the role name', () => {
- const label = dropdown.toggleLabel();
-
- expect(label).toBe('Dummy Role');
- expect($dropdownToggleText).not.toHaveClass('is-default');
- });
- });
-
- describe('with only users', () => {
- beforeEach(() => {
- dropdown.setSelectedItems(dummyItems.filter((item) => item.type === LEVEL_TYPES.USER));
- $dropdownToggleText.addClass('is-default');
- });
-
- it('displays number of users', () => {
- const label = dropdown.toggleLabel();
-
- expect(label).toBe('2 users');
- expect($dropdownToggleText).not.toHaveClass('is-default');
- });
- });
-
- describe('with only groups', () => {
- beforeEach(() => {
- dropdown.setSelectedItems(dummyItems.filter((item) => item.type === LEVEL_TYPES.GROUP));
- $dropdownToggleText.addClass('is-default');
- });
-
- it('displays number of groups', () => {
- const label = dropdown.toggleLabel();
-
- expect(label).toBe('3 groups');
- expect($dropdownToggleText).not.toHaveClass('is-default');
- });
- });
-
- describe('with users and groups', () => {
- beforeEach(() => {
- const selectedTypes = [LEVEL_TYPES.GROUP, LEVEL_TYPES.USER];
- dropdown.setSelectedItems(dummyItems.filter((item) => selectedTypes.includes(item.type)));
- $dropdownToggleText.addClass('is-default');
- });
-
- it('displays number of groups', () => {
- const label = dropdown.toggleLabel();
-
- expect(label).toBe('2 users, 3 groups');
- expect($dropdownToggleText).not.toHaveClass('is-default');
- });
- });
-
- describe('with users and deploy keys', () => {
- beforeEach(() => {
- const selectedTypes = [LEVEL_TYPES.DEPLOY_KEY, LEVEL_TYPES.USER];
- dropdown.setSelectedItems(dummyItems.filter((item) => selectedTypes.includes(item.type)));
- $dropdownToggleText.addClass('is-default');
- });
-
- it('displays number of deploy keys', () => {
- const label = dropdown.toggleLabel();
-
- expect(label).toBe('2 users, 3 deploy keys');
- expect($dropdownToggleText).not.toHaveClass('is-default');
- });
- });
- });
-
- describe('userRowHtml', () => {
- it('escapes users name', () => {
- const user = {
- avatar_url: '',
- name: '<img src=x onerror=alert(document.domain)>',
- username: 'test',
- };
- const template = dropdown.userRowHtml(user);
-
- expect(template).not.toContain(user.name);
- });
-
- it('show user avatar correctly', () => {
- const user = {
- id: 613,
- avatar_url: 'some_valid_avatar.png',
- name: 'test',
- username: 'test',
- };
- const template = dropdown.userRowHtml(user);
-
- expect(template).toContain(user.avatar_url);
- expect(template).not.toContain('identicon');
- });
-
- it('show identicon when user do not have avatar', () => {
- const user = {
- id: 613,
- avatar_url: '',
- name: 'test',
- username: 'test',
- };
- const template = dropdown.userRowHtml(user);
-
- expect(template).toContain('identicon');
- });
- });
-
- describe('deployKeyRowHtml', () => {
- const deployKey = {
- id: 1,
- title: 'title <script>alert(document.domain)</script>',
- fullname: 'fullname <script>alert(document.domain)</script>',
- avatar_url: '',
- username: '',
- };
-
- it('escapes deploy key title and fullname', () => {
- const template = dropdown.deployKeyRowHtml(deployKey);
-
- expect(template).not.toContain(deployKey.title);
- expect(template).not.toContain(deployKey.fullname);
- });
- });
-});
diff --git a/spec/frontend/projects/settings/components/new_access_dropdown_spec.js b/spec/frontend/projects/settings/components/new_access_dropdown_spec.js
index ce696ee321b..0ed2e51e8c3 100644
--- a/spec/frontend/projects/settings/components/new_access_dropdown_spec.js
+++ b/spec/frontend/projects/settings/components/new_access_dropdown_spec.js
@@ -14,13 +14,11 @@ import AccessDropdown, { i18n } from '~/projects/settings/components/access_drop
import { ACCESS_LEVELS, LEVEL_TYPES } from '~/projects/settings/constants';
jest.mock('~/projects/settings/api/access_dropdown_api', () => ({
- getGroups: jest.fn().mockResolvedValue({
- data: [
- { id: 4, name: 'group4' },
- { id: 5, name: 'group5' },
- { id: 6, name: 'group6' },
- ],
- }),
+ getGroups: jest.fn().mockResolvedValue([
+ { id: 4, name: 'group4' },
+ { id: 5, name: 'group5' },
+ { id: 6, name: 'group6' },
+ ]),
getUsers: jest.fn().mockResolvedValue({
data: [
{ id: 7, name: 'user7' },
@@ -50,6 +48,7 @@ jest.mock('~/projects/settings/api/access_dropdown_api', () => ({
describe('Access Level Dropdown', () => {
let wrapper;
+ const defaultToggleClass = 'gl-text-gray-500!';
const mockAccessLevelsData = [
{
id: 1,
@@ -63,6 +62,10 @@ describe('Access Level Dropdown', () => {
id: 3,
text: 'role3',
},
+ {
+ id: 0,
+ text: 'No one',
+ },
];
const createComponent = ({
@@ -140,7 +143,7 @@ describe('Access Level Dropdown', () => {
});
it('renders dropdown item for each access level type', () => {
- expect(findAllDropdownItems()).toHaveLength(12);
+ expect(findAllDropdownItems()).toHaveLength(13);
});
it.each`
@@ -177,26 +180,26 @@ describe('Access Level Dropdown', () => {
const customLabel = 'Set the access level';
createComponent({ label: customLabel });
expect(findDropdownToggleLabel()).toBe(customLabel);
- expect(findDropdown().props('toggleClass')).toBe('gl-text-gray-500!');
+ expect(findDropdown().props('toggleClass')[defaultToggleClass]).toBe(true);
});
it('when no items selected, displays a default fallback label and has default CSS class', () => {
- expect(findDropdownToggleLabel()).toBe(i18n.selectUsers);
- expect(findDropdown().props('toggleClass')).toBe('gl-text-gray-500!');
+ expect(findDropdownToggleLabel()).toBe(i18n.defaultLabel);
+ expect(findDropdown().props('toggleClass')[defaultToggleClass]).toBe(true);
});
- it('displays a number of selected items for each group level', async () => {
+ it('displays selected items for each group level', async () => {
dropdownItems.wrappers.forEach((item) => {
item.trigger('click');
});
await nextTick();
- expect(findDropdownToggleLabel()).toBe('3 roles, 3 users, 3 deploy keys, 3 groups');
+ expect(findDropdownToggleLabel()).toBe('No role, 3 users, 3 deploy keys, 3 groups');
});
it('with only role selected displays the role name and has no class applied', async () => {
await findItemByNameAndClick('role1');
expect(findDropdownToggleLabel()).toBe('role1');
- expect(findDropdown().props('toggleClass')).toBe('');
+ expect(findDropdown().props('toggleClass')[defaultToggleClass]).toBe(false);
});
it('with only groups selected displays the number of selected groups', async () => {
@@ -204,14 +207,14 @@ describe('Access Level Dropdown', () => {
await findItemByNameAndClick('group5');
await findItemByNameAndClick('group6');
expect(findDropdownToggleLabel()).toBe('3 groups');
- expect(findDropdown().props('toggleClass')).toBe('');
+ expect(findDropdown().props('toggleClass')[defaultToggleClass]).toBe(false);
});
it('with only users selected displays the number of selected users', async () => {
await findItemByNameAndClick('user7');
await findItemByNameAndClick('user8');
expect(findDropdownToggleLabel()).toBe('2 users');
- expect(findDropdown().props('toggleClass')).toBe('');
+ expect(findDropdown().props('toggleClass')[defaultToggleClass]).toBe(false);
});
it('with users and groups selected displays the number of selected users & groups', async () => {
@@ -220,7 +223,7 @@ describe('Access Level Dropdown', () => {
await findItemByNameAndClick('user7');
await findItemByNameAndClick('user9');
expect(findDropdownToggleLabel()).toBe('2 users, 2 groups');
- expect(findDropdown().props('toggleClass')).toBe('');
+ expect(findDropdown().props('toggleClass')[defaultToggleClass]).toBe(false);
});
it('with users and deploy keys selected displays the number of selected users & keys', async () => {
@@ -228,7 +231,7 @@ describe('Access Level Dropdown', () => {
await findItemByNameAndClick('key10');
await findItemByNameAndClick('key11');
expect(findDropdownToggleLabel()).toBe('1 user, 2 deploy keys');
- expect(findDropdown().props('toggleClass')).toBe('');
+ expect(findDropdown().props('toggleClass')[defaultToggleClass]).toBe(false);
});
});
@@ -393,4 +396,20 @@ describe('Access Level Dropdown', () => {
expect(wrapper.emitted('hidden')[0][0]).toStrictEqual([{ access_level: 2 }]);
});
});
+
+ describe('when no license and accessLevel is MERGE', () => {
+ beforeEach(async () => {
+ createComponent({ hasLicense: false, accessLevel: ACCESS_LEVELS.MERGE });
+ await waitForPromises();
+ });
+
+ it('dropdown is single-select', () => {
+ const dropdownItems = findAllDropdownItems();
+
+ findDropdownItemWithText(dropdownItems, mockAccessLevelsData[0].text).trigger('click');
+ findDropdownItemWithText(dropdownItems, mockAccessLevelsData[1].text).trigger('click');
+
+ expect(wrapper.emitted('select')[1]).toHaveLength(1);
+ });
+ });
});
diff --git a/spec/frontend/projects/settings_service_desk/components/custom_email_form_spec.js b/spec/frontend/projects/settings_service_desk/components/custom_email_form_spec.js
index ded8b181c4e..9b012995ea4 100644
--- a/spec/frontend/projects/settings_service_desk/components/custom_email_form_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/custom_email_form_spec.js
@@ -1,6 +1,8 @@
import { mount } from '@vue/test-utils';
+import { GlLink } from '@gitlab/ui';
import { nextTick } from 'vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { helpPagePath } from '~/helpers/help_page_helper';
import CustomEmailForm from '~/projects/settings_service_desk/components/custom_email_form.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { I18N_FORM_FORWARDING_CLIPBOARD_BUTTON_TITLE } from '~/projects/settings_service_desk/custom_email_constants';
@@ -15,6 +17,7 @@ describe('CustomEmailForm', () => {
const findForm = () => wrapper.find('form');
const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
+ const findLink = () => wrapper.findComponent(GlLink);
const findInputByTestId = (testId) => wrapper.findByTestId(testId).find('input');
const findCustomEmailInput = () => findInputByTestId('form-custom-email');
const findSmtpAddressInput = () => findInputByTestId('form-smtp-address');
@@ -35,6 +38,16 @@ describe('CustomEmailForm', () => {
wrapper = extendedWrapper(mount(CustomEmailForm, { propsData: { ...defaultProps, ...props } }));
};
+ it('displays help page link', () => {
+ createWrapper();
+
+ expect(findLink().attributes('href')).toBe(
+ helpPagePath('user/project/service_desk/configure.html', {
+ anchor: 'custom-email-address',
+ }),
+ );
+ });
+
it('renders a copy to clipboard button', () => {
createWrapper();
diff --git a/spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js b/spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js
index e54d09cf82f..174e05ceeee 100644
--- a/spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/custom_email_wrapper_spec.js
@@ -1,7 +1,8 @@
import { nextTick } from 'vue';
-import { GlLink, GlLoadingIcon, GlAlert } from '@gitlab/ui';
+import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import axios from '~/lib/utils/axios_utils';
import waitForPromises from 'helpers/wait_for_promises';
import { HTTP_STATUS_OK, HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
@@ -40,19 +41,21 @@ describe('CustomEmailWrapper', () => {
const showToast = jest.fn();
const createWrapper = (props = {}) => {
- wrapper = mount(CustomEmailWrapper, {
- propsData: { ...defaultProps, ...props },
- mocks: {
- $toast: {
- show: showToast,
+ wrapper = extendedWrapper(
+ mount(CustomEmailWrapper, {
+ propsData: { ...defaultProps, ...props },
+ mocks: {
+ $toast: {
+ show: showToast,
+ },
},
- },
- });
+ }),
+ );
};
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findAlert = () => wrapper.findComponent(GlAlert);
- const findFeedbackLink = () => wrapper.findComponent(GlLink);
+ const findFeedbackLink = () => wrapper.findByTestId('feedback-link');
const findCustomEmailForm = () => wrapper.findComponent(CustomEmailForm);
const findCustomEmail = () => wrapper.findComponent(CustomEmail);
const findCustomEmailConfirmModal = () => wrapper.findComponent(CustomEmailConfirmModal);
diff --git a/spec/frontend/protected_branches/protected_branch_create_spec.js b/spec/frontend/protected_branches/protected_branch_create_spec.js
index 4b634c52b01..e2a0f02e0cf 100644
--- a/spec/frontend/protected_branches/protected_branch_create_spec.js
+++ b/spec/frontend/protected_branches/protected_branch_create_spec.js
@@ -1,5 +1,8 @@
+import MockAdapter from 'axios-mock-adapter';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import ProtectedBranchCreate from '~/protected_branches/protected_branch_create';
+import { ACCESS_LEVELS } from '~/protected_branches/constants';
+import axios from '~/lib/utils/axios_utils';
const FORCE_PUSH_TOGGLE_TESTID = 'force-push-toggle';
const CODE_OWNER_TOGGLE_TESTID = 'code-owner-toggle';
@@ -9,7 +12,12 @@ const IS_LOADING_CLASS = 'toggle-loading';
describe('ProtectedBranchCreate', () => {
beforeEach(() => {
- jest.spyOn(ProtectedBranchCreate.prototype, 'buildDropdowns').mockImplementation();
+ // eslint-disable-next-line no-unused-vars
+ const mock = new MockAdapter(axios);
+ window.gon = {
+ merge_access_levels: { roles: [] },
+ push_access_levels: { roles: [] },
+ };
});
const findForcePushToggle = () =>
@@ -34,6 +42,12 @@ describe('ProtectedBranchCreate', () => {
data-label="Toggle code owner approval"
data-is-checked="${codeOwnerToggleChecked}"
data-testid="${CODE_OWNER_TOGGLE_TESTID}"></span>
+ <div class="merge_access_levels-container">
+ <div class="js-allowed-to-merge"/>
+ </div>
+ <div class="push_access_levels-container">
+ <div class="js-allowed-to-push"/>
+ </div>
<input type="submit" />
</form>
`);
@@ -85,14 +99,6 @@ describe('ProtectedBranchCreate', () => {
forcePushToggleChecked: false,
codeOwnerToggleChecked: true,
});
-
- // Mock access levels. This should probably be improved in future iterations.
- protectedBranchCreate.merge_access_levels_dropdown = {
- getSelectedItems: () => [],
- };
- protectedBranchCreate.push_access_levels_dropdown = {
- getSelectedItems: () => [],
- };
});
afterEach(() => {
@@ -116,4 +122,31 @@ describe('ProtectedBranchCreate', () => {
});
});
});
+
+ describe('access dropdown', () => {
+ let protectedBranchCreate;
+
+ beforeEach(() => {
+ protectedBranchCreate = create();
+ });
+
+ it('should be initialized', () => {
+ expect(protectedBranchCreate[`${ACCESS_LEVELS.MERGE}_dropdown`]).toBeDefined();
+ expect(protectedBranchCreate[`${ACCESS_LEVELS.PUSH}_dropdown`]).toBeDefined();
+ });
+
+ describe('`select` event is emitted', () => {
+ const selected = ['foo', 'bar'];
+
+ it('should update selected merged access items', () => {
+ protectedBranchCreate[`${ACCESS_LEVELS.MERGE}_dropdown`].$emit('select', selected);
+ expect(protectedBranchCreate.selectedItems[ACCESS_LEVELS.MERGE]).toEqual(selected);
+ });
+
+ it('should update selected push access items', () => {
+ protectedBranchCreate[`${ACCESS_LEVELS.PUSH}_dropdown`].$emit('select', selected);
+ expect(protectedBranchCreate.selectedItems[ACCESS_LEVELS.PUSH]).toEqual(selected);
+ });
+ });
+ });
});
diff --git a/spec/frontend/protected_branches/protected_branch_edit_spec.js b/spec/frontend/protected_branches/protected_branch_edit_spec.js
index e1966908452..6422856ba22 100644
--- a/spec/frontend/protected_branches/protected_branch_edit_spec.js
+++ b/spec/frontend/protected_branches/protected_branch_edit_spec.js
@@ -20,7 +20,7 @@ describe('ProtectedBranchEdit', () => {
let mock;
beforeEach(() => {
- jest.spyOn(ProtectedBranchEdit.prototype, 'buildDropdowns').mockImplementation();
+ jest.spyOn(ProtectedBranchEdit.prototype, 'initDropdowns').mockImplementation();
mock = new MockAdapter(axios);
});
diff --git a/spec/frontend/protected_tags/mock_data.js b/spec/frontend/protected_tags/mock_data.js
new file mode 100644
index 00000000000..dacdecdfe74
--- /dev/null
+++ b/spec/frontend/protected_tags/mock_data.js
@@ -0,0 +1,18 @@
+export const mockAccessLevels = [
+ {
+ id: 30,
+ text: 'Developers + Maintainers',
+ },
+ {
+ id: 40,
+ text: 'Maintainers',
+ },
+ {
+ id: 60,
+ text: 'Instance admins',
+ },
+ {
+ id: 0,
+ text: 'No one',
+ },
+];
diff --git a/spec/frontend/protected_tags/protected_tag_edit_spec.js b/spec/frontend/protected_tags/protected_tag_edit_spec.js
new file mode 100644
index 00000000000..f56b3a70d1b
--- /dev/null
+++ b/spec/frontend/protected_tags/protected_tag_edit_spec.js
@@ -0,0 +1,113 @@
+import MockAdapter from 'axios-mock-adapter';
+import { ACCESS_LEVELS, LEVEL_TYPES } from '~/protected_tags/constants';
+import ProtectedTagEdit, { i18n } from '~/protected_tags/protected_tag_edit.vue';
+import AccessDropdown from '~/projects/settings/components/access_dropdown.vue';
+import axios from '~/lib/utils/axios_utils';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/alert';
+import { mockAccessLevels } from './mock_data';
+
+jest.mock('~/alert');
+
+describe('Protected Tag Edit', () => {
+ let wrapper;
+ let mockAxios;
+
+ const url = 'http://some.url';
+ const toggleClass = 'js-allowed-to-create gl-max-w-34';
+
+ const findAccessDropdown = () => wrapper.findComponent(AccessDropdown);
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(ProtectedTagEdit, {
+ propsData: {
+ url,
+ accessLevelsData: mockAccessLevels,
+ searchEnabled: false,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ window.gon = {
+ api_version: 'v4',
+ deploy_access_levels: {
+ roles: [],
+ },
+ };
+ mockAxios = new MockAdapter(axios);
+ createComponent();
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ it('renders access dropdown with correct props', () => {
+ expect(findAccessDropdown().props()).toMatchObject({
+ toggleClass,
+ accessLevel: ACCESS_LEVELS.CREATE,
+ accessLevelsData: mockAccessLevels,
+ searchEnabled: false,
+ });
+ });
+
+ describe('when dropdown is closed and has no changes', () => {
+ it('does not make a patch request to update permission', () => {
+ jest.spyOn(axios, 'patch');
+
+ findAccessDropdown().vm.$emit('hidden', []);
+
+ expect(axios.patch).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when dropdown is closed and has changes', () => {
+ it('makes patch request to update permission', () => {
+ jest.spyOn(axios, 'patch');
+
+ const newPermissions = [{ id: 1, access_level: 30 }];
+ findAccessDropdown().vm.$emit('hidden', newPermissions);
+
+ expect(axios.patch).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when permission is updated successfully', () => {
+ beforeEach(async () => {
+ const updatedPermissions = [
+ { user_id: 1, id: 1 },
+ { group_id: 1, id: 2 },
+ { access_level: 3, id: 3 },
+ ];
+ mockAxios.onPatch().replyOnce(HTTP_STATUS_OK, { [ACCESS_LEVELS.CREATE]: updatedPermissions });
+ findAccessDropdown().vm.$emit('hidden', [{ user_id: 1 }]);
+ await waitForPromises();
+ });
+
+ it('should update selected items', () => {
+ const newPreselected = [
+ { user_id: 1, id: 1, type: LEVEL_TYPES.USER },
+ { group_id: 1, id: 2, type: LEVEL_TYPES.GROUP },
+ { access_level: 3, id: 3, type: LEVEL_TYPES.ROLE },
+ ];
+ expect(findAccessDropdown().props('preselectedItems')).toEqual(newPreselected);
+ });
+ });
+
+ describe('when permission update fails', () => {
+ beforeEach(async () => {
+ mockAxios.onPatch().replyOnce(HTTP_STATUS_BAD_REQUEST, {});
+ findAccessDropdown().vm.$emit('hidden', [{ user_id: 1 }]);
+ await waitForPromises();
+ });
+
+ it('should show error message', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: i18n.failureMessage,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/releases/__snapshots__/util_spec.js.snap b/spec/frontend/releases/__snapshots__/util_spec.js.snap
index 79792a4a0ea..c02c1bb959c 100644
--- a/spec/frontend/releases/__snapshots__/util_spec.js.snap
+++ b/spec/frontend/releases/__snapshots__/util_spec.js.snap
@@ -54,7 +54,19 @@ Object {
},
"commitPath": "http://localhost/releases-namespace/releases-project/-/commit/b83d6e391c22777fca1ed3012fce84f633d7fed0",
"createdAt": 2019-01-03T00:00:00.000Z,
- "descriptionHtml": "<p data-sourcepos=\\"1:1-1:23\\" dir=\\"auto\\">An okay release <gl-emoji title=\\"shrug\\" data-name=\\"shrug\\" data-unicode-version=\\"9.0\\">🤷</gl-emoji></p>",
+ "descriptionHtml": <p
+ data-sourcepos="1:1-1:23"
+ dir="auto"
+ >
+ An okay release
+ <gl-emoji
+ data-name="shrug"
+ data-unicode-version="9.0"
+ title="shrug"
+ >
+ 🤷
+ </gl-emoji>
+ </p>,
"evidences": Array [],
"historicalRelease": false,
"milestones": Array [],
@@ -148,7 +160,22 @@ Object {
},
"commitPath": "http://localhost/releases-namespace/releases-project/-/commit/b83d6e391c22777fca1ed3012fce84f633d7fed0",
"createdAt": 2018-12-03T00:00:00.000Z,
- "descriptionHtml": "<p data-sourcepos=\\"1:1-1:33\\" dir=\\"auto\\">Best. Release. <strong>Ever.</strong> <gl-emoji title=\\"rocket\\" data-name=\\"rocket\\" data-unicode-version=\\"6.0\\">🚀</gl-emoji></p>",
+ "descriptionHtml": <p
+ data-sourcepos="1:1-1:33"
+ dir="auto"
+ >
+ Best. Release.
+ <strong>
+ Ever.
+ </strong>
+ <gl-emoji
+ data-name="rocket"
+ data-unicode-version="6.0"
+ title="rocket"
+ >
+ 🚀
+ </gl-emoji>
+ </p>,
"evidences": Array [
Object {
"__typename": "ReleaseEvidence",
@@ -368,7 +395,22 @@ Object {
},
"commitPath": "http://localhost/releases-namespace/releases-project/-/commit/b83d6e391c22777fca1ed3012fce84f633d7fed0",
"createdAt": 2018-12-03T00:00:00.000Z,
- "descriptionHtml": "<p data-sourcepos=\\"1:1-1:33\\" dir=\\"auto\\">Best. Release. <strong>Ever.</strong> <gl-emoji title=\\"rocket\\" data-name=\\"rocket\\" data-unicode-version=\\"6.0\\">🚀</gl-emoji></p>",
+ "descriptionHtml": <p
+ data-sourcepos="1:1-1:33"
+ dir="auto"
+ >
+ Best. Release.
+ <strong>
+ Ever.
+ </strong>
+ <gl-emoji
+ data-name="rocket"
+ data-unicode-version="6.0"
+ title="rocket"
+ >
+ 🚀
+ </gl-emoji>
+ </p>,
"evidences": Array [
Object {
"__typename": "ReleaseEvidence",
diff --git a/spec/frontend/releases/components/__snapshots__/issuable_stats_spec.js.snap b/spec/frontend/releases/components/__snapshots__/issuable_stats_spec.js.snap
index e53ea6b2ec6..8f811d31af8 100644
--- a/spec/frontend/releases/components/__snapshots__/issuable_stats_spec.js.snap
+++ b/spec/frontend/releases/components/__snapshots__/issuable_stats_spec.js.snap
@@ -1,9 +1,68 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`~/releases/components/issuable_stats.vue matches snapshot 1`] = `
-"<div class=\\"gl-display-flex gl-flex-direction-column gl-flex-shrink-0 gl-mr-6 gl-mb-5\\"><span class=\\"gl-mb-2\\">
+<div
+ class="gl-display-flex gl-flex-direction-column gl-flex-shrink-0 gl-mb-5 gl-mr-6"
+>
+ <span
+ class="gl-mb-2"
+ >
Items
- <span class=\\"badge badge-muted badge-pill gl-badge sm\\"><!----> 10</span></span>
- <div class=\\"gl-display-flex\\"><span data-testid=\\"open-stat\\" class=\\"gl-white-space-pre-wrap\\">Open: <a href=\\"path/to/opened/items\\" class=\\"gl-link\\">1</a></span> <span class=\\"gl-mx-2\\">•</span> <span data-testid=\\"merged-stat\\" class=\\"gl-white-space-pre-wrap\\">Merged: <a href=\\"path/to/merged/items\\" class=\\"gl-link\\">7</a></span> <span class=\\"gl-mx-2\\">•</span> <span data-testid=\\"closed-stat\\" class=\\"gl-white-space-pre-wrap\\">Closed: <a href=\\"path/to/closed/items\\" class=\\"gl-link\\">2</a></span></div>
-</div>"
+ <span
+ class="badge badge-muted badge-pill gl-badge sm"
+ >
+ 10
+ </span>
+ </span>
+ <div
+ class="gl-display-flex"
+ >
+ <span
+ class="gl-white-space-pre-wrap"
+ data-testid="open-stat"
+ >
+ Open:
+ <a
+ class="gl-link"
+ href="path/to/opened/items"
+ >
+ 1
+ </a>
+ </span>
+ <span
+ class="gl-mx-2"
+ >
+ •
+ </span>
+ <span
+ class="gl-white-space-pre-wrap"
+ data-testid="merged-stat"
+ >
+ Merged:
+ <a
+ class="gl-link"
+ href="path/to/merged/items"
+ >
+ 7
+ </a>
+ </span>
+ <span
+ class="gl-mx-2"
+ >
+ •
+ </span>
+ <span
+ class="gl-white-space-pre-wrap"
+ data-testid="closed-stat"
+ >
+ Closed:
+ <a
+ class="gl-link"
+ href="path/to/closed/items"
+ >
+ 2
+ </a>
+ </span>
+ </div>
+</div>
`;
diff --git a/spec/frontend/releases/components/release_block_milestone_info_spec.js b/spec/frontend/releases/components/release_block_milestone_info_spec.js
index b8030ae1fd2..26068b392d1 100644
--- a/spec/frontend/releases/components/release_block_milestone_info_spec.js
+++ b/spec/frontend/releases/components/release_block_milestone_info_spec.js
@@ -41,10 +41,10 @@ describe('Release block milestone info', () => {
const progressBar = milestoneProgressBarContainer().findComponent(GlProgressBar);
expect(progressBar.exists()).toBe(true);
- expect(progressBar.attributes()).toEqual(
+ expect(progressBar.vm.$attrs).toEqual(
expect.objectContaining({
- value: '4',
- max: '9',
+ value: 4,
+ max: 9,
}),
);
});
diff --git a/spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap b/spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap
index 836ae5c22e6..02f75edd57a 100644
--- a/spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap
+++ b/spec/frontend/repository/components/__snapshots__/directory_download_links_spec.js.snap
@@ -2,14 +2,13 @@
exports[`Repository directory download links component renders downloads links for path app 1`] = `
<section
- class="border-top pt-1 mt-1"
+ class="border-top mt-1 pt-1"
>
<h5
- class="m-0 dropdown-bold-header"
+ class="dropdown-bold-header m-0"
>
Download this directory
</h5>
-
<div
class="dropdown-menu-content"
>
@@ -24,9 +23,7 @@ exports[`Repository directory download links component renders downloads links f
size="small"
variant="confirm"
>
-
zip
-
</gl-button-stub>
<gl-button-stub
buttontextclasses=""
@@ -36,9 +33,7 @@ exports[`Repository directory download links component renders downloads links f
size="small"
variant="default"
>
-
tar
-
</gl-button-stub>
</div>
</div>
@@ -47,14 +42,13 @@ exports[`Repository directory download links component renders downloads links f
exports[`Repository directory download links component renders downloads links for path app/assets 1`] = `
<section
- class="border-top pt-1 mt-1"
+ class="border-top mt-1 pt-1"
>
<h5
- class="m-0 dropdown-bold-header"
+ class="dropdown-bold-header m-0"
>
Download this directory
</h5>
-
<div
class="dropdown-menu-content"
>
@@ -69,9 +63,7 @@ exports[`Repository directory download links component renders downloads links f
size="small"
variant="confirm"
>
-
zip
-
</gl-button-stub>
<gl-button-stub
buttontextclasses=""
@@ -81,9 +73,7 @@ exports[`Repository directory download links component renders downloads links f
size="small"
variant="default"
>
-
tar
-
</gl-button-stub>
</div>
</div>
diff --git a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
index ede04390586..3f901dc61b8 100644
--- a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
+++ b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
@@ -2,10 +2,10 @@
exports[`Repository last commit component renders commit widget 1`] = `
<div
- class="well-segment commit gl-p-5 gl-w-full gl-display-flex"
+ class="commit gl-display-flex gl-p-5 gl-w-full well-segment"
>
<user-avatar-link-stub
- class="gl-my-2 gl-mr-4"
+ class="gl-mr-4 gl-my-2"
imgalt=""
imgcssclasses=""
imgcsswrapperclasses=""
@@ -18,9 +18,8 @@ exports[`Repository last commit component renders commit widget 1`] = `
tooltiptext=""
username=""
/>
-
<div
- class="commit-detail flex-list gl-display-flex gl-justify-content-space-between gl-align-items-center gl-flex-grow-1 gl-min-w-0"
+ class="commit-detail flex-list gl-align-items-center gl-display-flex gl-flex-grow-1 gl-justify-content-space-between gl-min-w-0"
>
<div
class="commit-content"
@@ -32,9 +31,6 @@ exports[`Repository last commit component renders commit widget 1`] = `
>
Commit title
</gl-link-stub>
-
- <!---->
-
<div
class="committer"
>
@@ -42,12 +38,9 @@ exports[`Repository last commit component renders commit widget 1`] = `
class="commit-author-link js-user-link"
href="/test"
>
-
- Test
+ Test
</gl-link-stub>
-
- authored
-
+ authored
<timeago-tooltip-stub
cssclass=""
datetimeformat="DATE_WITH_TIME_FORMAT"
@@ -55,36 +48,24 @@ exports[`Repository last commit component renders commit widget 1`] = `
tooltipplacement="bottom"
/>
</div>
-
- <!---->
</div>
-
<div
class="gl-flex-grow-1"
/>
-
<div
- class="commit-actions gl-display-flex gl-flex-align gl-align-items-center gl-flex-direction-row"
+ class="commit-actions gl-align-items-center gl-display-flex gl-flex-align gl-flex-direction-row"
>
- <!---->
-
<div
class="ci-status-link"
>
- <gl-link-stub
+ <ci-badge-link-stub
+ aria-label="Pipeline: failed"
class="js-commit-pipeline"
- href="https://test.com/pipeline"
- title="Pipeline: failed"
- >
- <ci-icon-stub
- aria-label="Pipeline: failed"
- cssclasses=""
- size="24"
- status="[object Object]"
- />
- </gl-link-stub>
+ details-path="https://test.com/pipeline"
+ size="lg"
+ status="[object Object]"
+ />
</div>
-
<gl-button-group-stub
class="gl-ml-4 js-commit-sha-group"
>
@@ -100,7 +81,6 @@ exports[`Repository last commit component renders commit widget 1`] = `
>
12345678
</gl-button-stub>
-
<clipboard-button-stub
category="secondary"
class="input-group-text"
diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js
index 5ac2627dc5d..cc077e20e0b 100644
--- a/spec/frontend/repository/components/blob_content_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_content_viewer_spec.js
@@ -8,11 +8,11 @@ import MockAdapter from 'axios-mock-adapter';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/alert';
import BlobContent from '~/blob/components/blob_content.vue';
import BlobHeader from '~/blob/components/blob_header.vue';
import BlobButtonGroup from '~/repository/components/blob_button_group.vue';
import BlobContentViewer from '~/repository/components/blob_content_viewer.vue';
-import WebIdeLink from 'ee_else_ce/vue_shared/components/web_ide_link.vue';
import ForkSuggestion from '~/repository/components/fork_suggestion.vue';
import { loadViewer } from '~/repository/components/blob_viewers';
import DownloadViewer from '~/repository/components/blob_viewers/download_viewer.vue';
@@ -20,8 +20,6 @@ import EmptyViewer from '~/repository/components/blob_viewers/empty_viewer.vue';
import SourceViewer from '~/vue_shared/components/source_viewer/source_viewer.vue';
import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql';
import projectInfoQuery from '~/repository/queries/project_info.query.graphql';
-import userInfoQuery from '~/repository/queries/user_info.query.graphql';
-import applicationInfoQuery from '~/repository/queries/application_info.query.graphql';
import CodeIntelligence from '~/code_navigation/components/app.vue';
import * as urlUtility from '~/lib/utils/url_utility';
import { isLoggedIn, handleLocationHash } from '~/lib/utils/common_utils';
@@ -34,8 +32,6 @@ import {
simpleViewerMock,
richViewerMock,
projectMock,
- userInfoMock,
- applicationInfoMock,
userPermissionsMock,
propsMock,
refMock,
@@ -46,12 +42,11 @@ jest.mock('~/repository/components/blob_viewers');
jest.mock('~/lib/utils/url_utility');
jest.mock('~/lib/utils/common_utils');
jest.mock('~/blob/line_highlighter');
+jest.mock('~/alert');
let wrapper;
let blobInfoMockResolver;
-let userInfoMockResolver;
let projectInfoMockResolver;
-let applicationInfoMockResolver;
Vue.use(Vuex);
@@ -95,7 +90,7 @@ const createComponent = async (mockData = {}, mountFn = shallowMount, mockRoute
const projectInfo = {
__typename: 'Project',
- id: '123',
+ id: projectMock.id,
userPermissions: {
pushCode,
forkProject,
@@ -121,19 +116,9 @@ const createComponent = async (mockData = {}, mountFn = shallowMount, mockRoute
data: { isBinary, project: blobInfo },
});
- userInfoMockResolver = jest.fn().mockResolvedValue({
- data: { ...userInfoMock },
- });
-
- applicationInfoMockResolver = jest.fn().mockResolvedValue({
- data: { ...applicationInfoMock },
- });
-
const fakeApollo = createMockApollo([
[blobInfoQuery, blobInfoMockResolver],
- [userInfoQuery, userInfoMockResolver],
[projectInfoQuery, projectInfoMockResolver],
- [applicationInfoQuery, applicationInfoMockResolver],
]);
wrapper = extendedWrapper(
@@ -167,7 +152,6 @@ const execImmediately = (callback) => {
describe('Blob content viewer component', () => {
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findBlobHeader = () => wrapper.findComponent(BlobHeader);
- const findWebIdeLink = () => wrapper.findComponent(WebIdeLink);
const findBlobContent = () => wrapper.findComponent(BlobContent);
const findBlobButtonGroup = () => wrapper.findComponent(BlobButtonGroup);
const findForkSuggestion = () => wrapper.findComponent(ForkSuggestion);
@@ -197,9 +181,22 @@ describe('Blob content viewer component', () => {
expect(findBlobHeader().props('hasRenderError')).toEqual(false);
expect(findBlobHeader().props('hideViewerSwitcher')).toEqual(true);
expect(findBlobHeader().props('blob')).toEqual(simpleViewerMock);
+ expect(findBlobHeader().props('showForkSuggestion')).toEqual(false);
+ expect(findBlobHeader().props('projectPath')).toEqual(propsMock.projectPath);
+ expect(findBlobHeader().props('projectId')).toEqual(projectMock.id);
expect(mockRouterPush).not.toHaveBeenCalled();
});
+ it('creates an alert when the BlobHeader component emits an error', async () => {
+ await createComponent();
+
+ findBlobHeader().vm.$emit('error');
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: 'An error occurred while loading the file. Please try again.',
+ });
+ });
+
it('copies blob text to clipboard', async () => {
jest.spyOn(navigator.clipboard, 'writeText');
await createComponent();
@@ -401,45 +398,6 @@ describe('Blob content viewer component', () => {
});
describe('BlobHeader action slot', () => {
- const { ideEditPath, editBlobPath } = simpleViewerMock;
-
- it('renders WebIdeLink button in simple viewer', async () => {
- await createComponent({ inject: { BlobContent: true, BlobReplace: true } }, mount);
-
- expect(findWebIdeLink().props()).toMatchObject({
- editUrl: editBlobPath,
- webIdeUrl: ideEditPath,
- showEditButton: true,
- showGitpodButton: applicationInfoMock.gitpodEnabled,
- gitpodEnabled: userInfoMock.currentUser.gitpodEnabled,
- showPipelineEditorButton: true,
- gitpodUrl: simpleViewerMock.gitpodBlobUrl,
- pipelineEditorUrl: simpleViewerMock.pipelineEditorPath,
- userPreferencesGitpodPath: userInfoMock.currentUser.preferencesGitpodPath,
- userProfileEnableGitpodPath: userInfoMock.currentUser.profileEnableGitpodPath,
- });
- });
-
- it('renders WebIdeLink button in rich viewer', async () => {
- await createComponent({ blob: richViewerMock }, mount);
-
- expect(findWebIdeLink().props()).toMatchObject({
- editUrl: editBlobPath,
- webIdeUrl: ideEditPath,
- showEditButton: true,
- });
- });
-
- it('renders WebIdeLink button for binary files', async () => {
- mockAxios.onGet(legacyViewerUrl).replyOnce(HTTP_STATUS_OK, axiosMockResponse);
- await createComponent({}, mount);
- expect(findWebIdeLink().props()).toMatchObject({
- editUrl: editBlobPath,
- webIdeUrl: ideEditPath,
- showEditButton: false,
- });
- });
-
describe('blob header binary file', () => {
it('passes the correct isBinary value when viewing a binary file', async () => {
mockAxios.onGet(legacyViewerUrl).replyOnce(HTTP_STATUS_OK, axiosMockResponse);
@@ -465,7 +423,6 @@ describe('Blob content viewer component', () => {
expect(findBlobHeader().props('hideViewerSwitcher')).toBe(true);
expect(findBlobHeader().props('isBinary')).toBe(true);
- expect(findWebIdeLink().props('showEditButton')).toBe(false);
});
});
@@ -538,12 +495,12 @@ describe('Blob content viewer component', () => {
beforeEach(() => createComponent({}, mount));
it('simple edit redirects to the simple editor', () => {
- findWebIdeLink().vm.$emit('edit', 'simple');
+ findBlobHeader().vm.$emit('edit', 'simple');
expect(urlUtility.redirectTo).toHaveBeenCalledWith(simpleViewerMock.editBlobPath); // eslint-disable-line import/no-deprecated
});
it('IDE edit redirects to the IDE editor', () => {
- findWebIdeLink().vm.$emit('edit', 'ide');
+ findBlobHeader().vm.$emit('edit', 'ide');
expect(urlUtility.redirectTo).toHaveBeenCalledWith(simpleViewerMock.ideEditPath); // eslint-disable-line import/no-deprecated
});
@@ -572,7 +529,7 @@ describe('Blob content viewer component', () => {
mount,
);
- findWebIdeLink().vm.$emit('edit', 'simple');
+ findBlobHeader().vm.$emit('edit', 'simple');
await nextTick();
expect(findForkSuggestion().exists()).toBe(showForkSuggestion);
diff --git a/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap b/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
index 85bf683fdf6..17ebdf8725d 100644
--- a/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
+++ b/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
@@ -5,10 +5,10 @@ exports[`Repository table row component renders a symlink table row 1`] = `
class="tree-item"
>
<td
- class="tree-item-file-name cursor-default position-relative"
+ class="cursor-default position-relative tree-item-file-name"
>
<a
- class="tree-item-link str-truncated"
+ class="str-truncated tree-item-link"
data-qa-selector="file_name_link"
href="https://test.com"
title="test"
@@ -26,11 +26,6 @@ exports[`Repository table row component renders a symlink table row 1`] = `
test
</span>
</a>
-
- <!---->
-
- <!---->
-
<gl-icon-stub
class="ml-1"
name="lock"
@@ -38,30 +33,25 @@ exports[`Repository table row component renders a symlink table row 1`] = `
title="Locked by Root"
/>
</td>
-
<td
- class="d-none d-sm-table-cell tree-commit cursor-default gl-text-secondary"
+ class="cursor-default d-none d-sm-table-cell gl-text-secondary tree-commit"
>
<gl-link-stub
- class="str-truncated-100 tree-commit-link gl-text-secondary"
+ class="gl-text-secondary str-truncated-100 tree-commit-link"
/>
-
- <gl-intersection-observer-stub>
- <!---->
- </gl-intersection-observer-stub>
+ <gl-intersection-observer-stub />
</td>
-
<td
- class="tree-time-ago text-right cursor-default gl-text-secondary"
+ class="cursor-default gl-text-secondary text-right tree-time-ago"
>
- <timeago-tooltip-stub
- cssclass=""
- datetimeformat="DATE_WITH_TIME_FORMAT"
- time="2019-01-01"
- tooltipplacement="top"
- />
-
- <!---->
+ <gl-intersection-observer-stub>
+ <timeago-tooltip-stub
+ cssclass=""
+ datetimeformat="DATE_WITH_TIME_FORMAT"
+ time="2019-01-01"
+ tooltipplacement="top"
+ />
+ </gl-intersection-observer-stub>
</td>
</tr>
`;
@@ -71,10 +61,10 @@ exports[`Repository table row component renders table row 1`] = `
class="tree-item"
>
<td
- class="tree-item-file-name cursor-default position-relative"
+ class="cursor-default position-relative tree-item-file-name"
>
<a
- class="tree-item-link str-truncated"
+ class="str-truncated tree-item-link"
data-qa-selector="file_name_link"
href="https://test.com"
title="test"
@@ -92,11 +82,6 @@ exports[`Repository table row component renders table row 1`] = `
test
</span>
</a>
-
- <!---->
-
- <!---->
-
<gl-icon-stub
class="ml-1"
name="lock"
@@ -104,30 +89,25 @@ exports[`Repository table row component renders table row 1`] = `
title="Locked by Root"
/>
</td>
-
<td
- class="d-none d-sm-table-cell tree-commit cursor-default gl-text-secondary"
+ class="cursor-default d-none d-sm-table-cell gl-text-secondary tree-commit"
>
<gl-link-stub
- class="str-truncated-100 tree-commit-link gl-text-secondary"
+ class="gl-text-secondary str-truncated-100 tree-commit-link"
/>
-
- <gl-intersection-observer-stub>
- <!---->
- </gl-intersection-observer-stub>
+ <gl-intersection-observer-stub />
</td>
-
<td
- class="tree-time-ago text-right cursor-default gl-text-secondary"
+ class="cursor-default gl-text-secondary text-right tree-time-ago"
>
- <timeago-tooltip-stub
- cssclass=""
- datetimeformat="DATE_WITH_TIME_FORMAT"
- time="2019-01-01"
- tooltipplacement="top"
- />
-
- <!---->
+ <gl-intersection-observer-stub>
+ <timeago-tooltip-stub
+ cssclass=""
+ datetimeformat="DATE_WITH_TIME_FORMAT"
+ time="2019-01-01"
+ tooltipplacement="top"
+ />
+ </gl-intersection-observer-stub>
</td>
</tr>
`;
@@ -137,10 +117,10 @@ exports[`Repository table row component renders table row for path with special
class="tree-item"
>
<td
- class="tree-item-file-name cursor-default position-relative"
+ class="cursor-default position-relative tree-item-file-name"
>
<a
- class="tree-item-link str-truncated"
+ class="str-truncated tree-item-link"
data-qa-selector="file_name_link"
href="https://test.com"
title="test"
@@ -158,11 +138,6 @@ exports[`Repository table row component renders table row for path with special
test
</span>
</a>
-
- <!---->
-
- <!---->
-
<gl-icon-stub
class="ml-1"
name="lock"
@@ -170,30 +145,25 @@ exports[`Repository table row component renders table row for path with special
title="Locked by Root"
/>
</td>
-
<td
- class="d-none d-sm-table-cell tree-commit cursor-default gl-text-secondary"
+ class="cursor-default d-none d-sm-table-cell gl-text-secondary tree-commit"
>
<gl-link-stub
- class="str-truncated-100 tree-commit-link gl-text-secondary"
+ class="gl-text-secondary str-truncated-100 tree-commit-link"
/>
-
- <gl-intersection-observer-stub>
- <!---->
- </gl-intersection-observer-stub>
+ <gl-intersection-observer-stub />
</td>
-
<td
- class="tree-time-ago text-right cursor-default gl-text-secondary"
+ class="cursor-default gl-text-secondary text-right tree-time-ago"
>
- <timeago-tooltip-stub
- cssclass=""
- datetimeformat="DATE_WITH_TIME_FORMAT"
- time="2019-01-01"
- tooltipplacement="top"
- />
-
- <!---->
+ <gl-intersection-observer-stub>
+ <timeago-tooltip-stub
+ cssclass=""
+ datetimeformat="DATE_WITH_TIME_FORMAT"
+ time="2019-01-01"
+ tooltipplacement="top"
+ />
+ </gl-intersection-observer-stub>
</td>
</tr>
`;
diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js
index e20849d1085..c60b6ace598 100644
--- a/spec/frontend/repository/mock_data.js
+++ b/spec/frontend/repository/mock_data.js
@@ -73,17 +73,6 @@ export const projectMock = {
},
};
-export const userInfoMock = {
- currentUser: {
- id: '123',
- gitpodEnabled: true,
- preferencesGitpodPath: '/-/profile/preferences#user_gitpod_enabled',
- profileEnableGitpodPath: '/-/profile?user%5Bgitpod_enabled%5D=true',
- },
-};
-
-export const applicationInfoMock = { gitpodEnabled: true };
-
export const propsMock = { path: 'some_file.js', projectPath: 'some/path' };
export const refMock = 'default-ref';
diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js
index a063f20aca6..7bddc4b1c48 100644
--- a/spec/frontend/search/mock_data.js
+++ b/spec/frontend/search/mock_data.js
@@ -194,7 +194,7 @@ export const MOCK_DATA_FOR_NAVIGATION_ACTION_MUTATION = {
label: 'Projects',
scope: 'projects',
link: '/search?scope=projects&search=et',
- count_link: '/search/count?scope=projects&search=et',
+ count_link: null,
},
};
diff --git a/spec/frontend/search/sidebar/components/app_spec.js b/spec/frontend/search/sidebar/components/app_spec.js
index a4559c2dc34..8e23f9c1680 100644
--- a/spec/frontend/search/sidebar/components/app_spec.js
+++ b/spec/frontend/search/sidebar/components/app_spec.js
@@ -2,14 +2,26 @@ import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
+import {
+ SEARCH_TYPE_ZOEKT,
+ SEARCH_TYPE_ADVANCED,
+ SEARCH_TYPE_BASIC,
+} from '~/search/sidebar/constants';
import { MOCK_QUERY } from 'jest/search/mock_data';
+import { toggleSuperSidebarCollapsed } from '~/super_sidebar/super_sidebar_collapsed_state_manager';
import GlobalSearchSidebar from '~/search/sidebar/components/app.vue';
import IssuesFilters from '~/search/sidebar/components/issues_filters.vue';
import MergeRequestsFilters from '~/search/sidebar/components/merge_requests_filters.vue';
import BlobsFilters from '~/search/sidebar/components/blobs_filters.vue';
import ProjectsFilters from '~/search/sidebar/components/projects_filters.vue';
+import NotesFilters from '~/search/sidebar/components/notes_filters.vue';
+import CommitsFilters from '~/search/sidebar/components/commits_filters.vue';
import ScopeLegacyNavigation from '~/search/sidebar/components/scope_legacy_navigation.vue';
+import SmallScreenDrawerNavigation from '~/search/sidebar/components/small_screen_drawer_navigation.vue';
import ScopeSidebarNavigation from '~/search/sidebar/components/scope_sidebar_navigation.vue';
+import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
+
+jest.mock('~/super_sidebar/super_sidebar_collapsed_state_manager');
Vue.use(Vuex);
@@ -20,7 +32,7 @@ describe('GlobalSearchSidebar', () => {
currentScope: jest.fn(() => 'issues'),
};
- const createComponent = (initialState = {}, ff = false) => {
+ const createComponent = (initialState = {}) => {
const store = new Vuex.Store({
state: {
urlQuery: MOCK_QUERY,
@@ -33,7 +45,8 @@ describe('GlobalSearchSidebar', () => {
store,
provide: {
glFeatures: {
- searchProjectsHideArchived: ff,
+ searchNotesHideArchivedProjects: true,
+ searchCommitsHideArchivedProjects: true,
},
},
});
@@ -44,69 +57,111 @@ describe('GlobalSearchSidebar', () => {
const findMergeRequestsFilters = () => wrapper.findComponent(MergeRequestsFilters);
const findBlobsFilters = () => wrapper.findComponent(BlobsFilters);
const findProjectsFilters = () => wrapper.findComponent(ProjectsFilters);
+ const findNotesFilters = () => wrapper.findComponent(NotesFilters);
+ const findCommitsFilters = () => wrapper.findComponent(CommitsFilters);
const findScopeLegacyNavigation = () => wrapper.findComponent(ScopeLegacyNavigation);
+ const findSmallScreenDrawerNavigation = () => wrapper.findComponent(SmallScreenDrawerNavigation);
const findScopeSidebarNavigation = () => wrapper.findComponent(ScopeSidebarNavigation);
+ const findDomElementListener = () => wrapper.findComponent(DomElementListener);
describe('renders properly', () => {
describe('always', () => {
beforeEach(() => {
createComponent();
});
+
it(`shows section`, () => {
expect(findSidebarSection().exists()).toBe(true);
});
});
describe.each`
- scope | filter
- ${'issues'} | ${findIssuesFilters}
- ${'merge_requests'} | ${findMergeRequestsFilters}
- ${'blobs'} | ${findBlobsFilters}
- `('with sidebar $scope scope:', ({ scope, filter }) => {
+ scope | filter | searchType | isShown
+ ${'issues'} | ${findIssuesFilters} | ${SEARCH_TYPE_BASIC} | ${true}
+ ${'merge_requests'} | ${findMergeRequestsFilters} | ${SEARCH_TYPE_BASIC} | ${true}
+ ${'projects'} | ${findProjectsFilters} | ${SEARCH_TYPE_BASIC} | ${true}
+ ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_BASIC} | ${false}
+ ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
+ ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_ZOEKT} | ${false}
+ ${'notes'} | ${findNotesFilters} | ${SEARCH_TYPE_BASIC} | ${false}
+ ${'notes'} | ${findNotesFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
+ ${'commits'} | ${findCommitsFilters} | ${SEARCH_TYPE_BASIC} | ${false}
+ ${'commits'} | ${findCommitsFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
+ `('with sidebar $scope scope:', ({ scope, filter, searchType, isShown }) => {
beforeEach(() => {
getterSpies.currentScope = jest.fn(() => scope);
- createComponent({ urlQuery: { scope } });
+ createComponent({ urlQuery: { scope }, searchType });
});
- it(`shows filter ${filter.name.replace('find', '')}`, () => {
- expect(filter().exists()).toBe(true);
+ it(`renders correctly filter ${filter.name.replace(
+ 'find',
+ '',
+ )} when search_type ${searchType}`, () => {
+ expect(filter().exists()).toBe(isShown);
});
});
- describe.each`
- featureFlag
- ${false}
- ${true}
- `('with sidebar $scope scope:', ({ featureFlag }) => {
+ describe('filters for blobs will not load if zoekt is enabled', () => {
+ beforeEach(() => {
+ createComponent({ urlQuery: { scope: 'blobs' }, searchType: SEARCH_TYPE_ZOEKT });
+ });
+
+ it("doesn't render blobs filters", () => {
+ expect(findBlobsFilters().exists()).toBe(false);
+ });
+ });
+
+ describe('with sidebar scope: projects', () => {
beforeEach(() => {
getterSpies.currentScope = jest.fn(() => 'projects');
- createComponent({ urlQuery: { scope: 'projects' } }, featureFlag);
+ createComponent({ urlQuery: { scope: 'projects' } });
});
- it(`shows filter ProjectsFilters}`, () => {
- expect(findProjectsFilters().exists()).toBe(featureFlag);
+ it(`shows filter ProjectsFilters`, () => {
+ expect(findProjectsFilters().exists()).toBe(true);
});
});
describe.each`
currentScope | sidebarNavShown | legacyNavShown
${'issues'} | ${false} | ${true}
- ${''} | ${false} | ${false}
+ ${'test'} | ${false} | ${true}
${'issues'} | ${true} | ${false}
- ${''} | ${true} | ${false}
- `('renders navigation', ({ currentScope, sidebarNavShown, legacyNavShown }) => {
- beforeEach(() => {
- getterSpies.currentScope = jest.fn(() => currentScope);
- createComponent({ useSidebarNavigation: sidebarNavShown });
- });
+ ${'test'} | ${true} | ${false}
+ `(
+ 'renders navigation for scope $currentScope',
+ ({ currentScope, sidebarNavShown, legacyNavShown }) => {
+ beforeEach(() => {
+ getterSpies.currentScope = jest.fn(() => currentScope);
+ createComponent({ useSidebarNavigation: sidebarNavShown });
+ });
- it(`${!legacyNavShown ? 'hides' : 'shows'} the legacy navigation`, () => {
- expect(findScopeLegacyNavigation().exists()).toBe(legacyNavShown);
- });
+ it(`renders navigation correctly with legacyNavShown ${legacyNavShown}`, () => {
+ expect(findScopeLegacyNavigation().exists()).toBe(legacyNavShown);
+ expect(findSmallScreenDrawerNavigation().exists()).toBe(legacyNavShown);
+ });
- it(`${!sidebarNavShown ? 'hides' : 'shows'} the sidebar navigation`, () => {
- expect(findScopeSidebarNavigation().exists()).toBe(sidebarNavShown);
- });
+ it(`renders navigation correctly with sidebarNavShown ${sidebarNavShown}`, () => {
+ expect(findScopeSidebarNavigation().exists()).toBe(sidebarNavShown);
+ });
+ },
+ );
+ });
+
+ describe('when useSidebarNavigation=true', () => {
+ beforeEach(() => {
+ createComponent({ useSidebarNavigation: true });
+ });
+
+ it('toggles super sidebar when button is clicked', () => {
+ const elListener = findDomElementListener();
+
+ expect(toggleSuperSidebarCollapsed).not.toHaveBeenCalled();
+
+ elListener.vm.$emit('click');
+
+ expect(toggleSuperSidebarCollapsed).toHaveBeenCalledTimes(1);
+ expect(elListener.props('selector')).toBe('#js-open-mobile-filters');
});
});
});
diff --git a/spec/frontend/search/sidebar/components/blobs_filters_spec.js b/spec/frontend/search/sidebar/components/blobs_filters_spec.js
index ff93e6f32e4..729fae44c19 100644
--- a/spec/frontend/search/sidebar/components/blobs_filters_spec.js
+++ b/spec/frontend/search/sidebar/components/blobs_filters_spec.js
@@ -1,28 +1,93 @@
import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import { MOCK_QUERY } from 'jest/search/mock_data';
import BlobsFilters from '~/search/sidebar/components/blobs_filters.vue';
import LanguageFilter from '~/search/sidebar/components/language_filter/index.vue';
-import FiltersTemplate from '~/search/sidebar/components/filters_template.vue';
+import ArchivedFilter from '~/search/sidebar/components/archived_filter/index.vue';
+import { SEARCH_TYPE_ADVANCED } from '~/search/sidebar/constants';
+
+Vue.use(Vuex);
describe('GlobalSearch BlobsFilters', () => {
let wrapper;
- const findLanguageFilter = () => wrapper.findComponent(LanguageFilter);
- const findFiltersTemplate = () => wrapper.findComponent(FiltersTemplate);
+ const defaultGetters = {
+ currentScope: () => 'blobs',
+ };
- const createComponent = () => {
- wrapper = shallowMount(BlobsFilters);
+ const createComponent = ({ initialState = {}, searchBlobsHideArchivedProjects = true } = {}) => {
+ const store = new Vuex.Store({
+ state: {
+ urlQuery: MOCK_QUERY,
+ useSidebarNavigation: false,
+ searchType: SEARCH_TYPE_ADVANCED,
+ ...initialState,
+ },
+ getters: defaultGetters,
+ });
+
+ wrapper = shallowMount(BlobsFilters, {
+ store,
+ provide: {
+ glFeatures: {
+ searchBlobsHideArchivedProjects,
+ },
+ },
+ });
};
- describe('Renders correctly', () => {
+ const findLanguageFilter = () => wrapper.findComponent(LanguageFilter);
+ const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
+ const findDividers = () => wrapper.findAll('hr');
+
+ describe.each`
+ description | searchBlobsHideArchivedProjects
+ ${'Renders correctly with Archived Filter enabled'} | ${true}
+ ${'Renders correctly with Archived Filter disabled'} | ${false}
+ `('$description', ({ searchBlobsHideArchivedProjects }) => {
+ beforeEach(() => {
+ createComponent({
+ searchBlobsHideArchivedProjects,
+ });
+ });
+
+ it('renders LanguageFilter', () => {
+ expect(findLanguageFilter().exists()).toBe(true);
+ });
+
+ it(`renders correctly ArchivedFilter when searchBlobsHideArchivedProjects is ${searchBlobsHideArchivedProjects}`, () => {
+ expect(findArchivedFilter().exists()).toBe(searchBlobsHideArchivedProjects);
+ });
+
+ it('renders divider correctly', () => {
+ const dividersCount = searchBlobsHideArchivedProjects ? 1 : 0;
+ expect(findDividers()).toHaveLength(dividersCount);
+ });
+ });
+
+ describe('Renders correctly in new nav', () => {
beforeEach(() => {
- createComponent();
+ createComponent({
+ initialState: {
+ searchType: SEARCH_TYPE_ADVANCED,
+ useSidebarNavigation: true,
+ },
+ searchBlobsHideArchivedProjects: true,
+ });
});
- it('renders FiltersTemplate', () => {
+
+ it('renders correctly LanguageFilter', () => {
expect(findLanguageFilter().exists()).toBe(true);
});
- it('renders ConfidentialityFilter', () => {
- expect(findFiltersTemplate().exists()).toBe(true);
+ it('renders correctly ArchivedFilter', () => {
+ expect(findArchivedFilter().exists()).toBe(true);
+ });
+
+ it("doesn't render dividers", () => {
+ expect(findDividers()).toHaveLength(0);
});
});
});
diff --git a/spec/frontend/search/sidebar/components/commits_filters_spec.js b/spec/frontend/search/sidebar/components/commits_filters_spec.js
new file mode 100644
index 00000000000..cb47c6833ef
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/commits_filters_spec.js
@@ -0,0 +1,28 @@
+import { shallowMount } from '@vue/test-utils';
+import CommitsFilters from '~/search/sidebar/components/projects_filters.vue';
+import ArchivedFilter from '~/search/sidebar/components/archived_filter/index.vue';
+import FiltersTemplate from '~/search/sidebar/components/filters_template.vue';
+
+describe('GlobalSearch CommitsFilters', () => {
+ let wrapper;
+
+ const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
+ const findFiltersTemplate = () => wrapper.findComponent(FiltersTemplate);
+
+ const createComponent = () => {
+ wrapper = shallowMount(CommitsFilters);
+ };
+
+ describe('Renders correctly', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+ it('renders ArchivedFilter', () => {
+ expect(findArchivedFilter().exists()).toBe(true);
+ });
+
+ it('renders FiltersTemplate', () => {
+ expect(findFiltersTemplate().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/search/sidebar/components/issues_filters_spec.js b/spec/frontend/search/sidebar/components/issues_filters_spec.js
index 84c4258cbdb..39d10cbb8b4 100644
--- a/spec/frontend/search/sidebar/components/issues_filters_spec.js
+++ b/spec/frontend/search/sidebar/components/issues_filters_spec.js
@@ -7,6 +7,8 @@ import IssuesFilters from '~/search/sidebar/components/issues_filters.vue';
import ConfidentialityFilter from '~/search/sidebar/components/confidentiality_filter/index.vue';
import StatusFilter from '~/search/sidebar/components/status_filter/index.vue';
import LabelFilter from '~/search/sidebar/components/label_filter/index.vue';
+import ArchivedFilter from '~/search/sidebar/components/archived_filter/index.vue';
+import { SEARCH_TYPE_ADVANCED, SEARCH_TYPE_BASIC } from '~/search/sidebar/constants';
Vue.use(Vuex);
@@ -17,10 +19,16 @@ describe('GlobalSearch IssuesFilters', () => {
currentScope: () => 'issues',
};
- const createComponent = (initialState, ff = true) => {
+ const createComponent = ({
+ initialState = {},
+ searchIssueLabelAggregation = true,
+ searchIssuesHideArchivedProjects = true,
+ } = {}) => {
const store = new Vuex.Store({
state: {
urlQuery: MOCK_QUERY,
+ useSidebarNavigation: false,
+ searchType: SEARCH_TYPE_ADVANCED,
...initialState,
},
getters: defaultGetters,
@@ -30,7 +38,8 @@ describe('GlobalSearch IssuesFilters', () => {
store,
provide: {
glFeatures: {
- searchIssueLabelAggregation: ff,
+ searchIssueLabelAggregation,
+ searchIssuesHideArchivedProjects,
},
},
});
@@ -39,12 +48,23 @@ describe('GlobalSearch IssuesFilters', () => {
const findStatusFilter = () => wrapper.findComponent(StatusFilter);
const findConfidentialityFilter = () => wrapper.findComponent(ConfidentialityFilter);
const findLabelFilter = () => wrapper.findComponent(LabelFilter);
+ const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
const findDividers = () => wrapper.findAll('hr');
- describe('Renders correctly with FF enabled', () => {
+ describe.each`
+ description | searchIssueLabelAggregation | searchIssuesHideArchivedProjects
+ ${'Renders correctly with Label Filter disabled'} | ${false} | ${true}
+ ${'Renders correctly with Archived Filter disabled'} | ${true} | ${false}
+ ${'Renders correctly with Archived Filter and Label Filter disabled'} | ${false} | ${false}
+ ${'Renders correctly with Archived Filter and Label Filter enabled'} | ${true} | ${true}
+ `('$description', ({ searchIssueLabelAggregation, searchIssuesHideArchivedProjects }) => {
beforeEach(() => {
- createComponent({ urlQuery: MOCK_QUERY });
+ createComponent({
+ searchIssueLabelAggregation,
+ searchIssuesHideArchivedProjects,
+ });
});
+
it('renders StatusFilter', () => {
expect(findStatusFilter().exists()).toBe(true);
});
@@ -53,18 +73,30 @@ describe('GlobalSearch IssuesFilters', () => {
expect(findConfidentialityFilter().exists()).toBe(true);
});
- it('renders LabelFilter', () => {
- expect(findLabelFilter().exists()).toBe(true);
+ it(`renders correctly LabelFilter when searchIssueLabelAggregation is ${searchIssueLabelAggregation}`, () => {
+ expect(findLabelFilter().exists()).toBe(searchIssueLabelAggregation);
});
- it('renders dividers correctly', () => {
- expect(findDividers()).toHaveLength(2);
+ it(`renders correctly ArchivedFilter when searchIssuesHideArchivedProjects is ${searchIssuesHideArchivedProjects}`, () => {
+ expect(findArchivedFilter().exists()).toBe(searchIssuesHideArchivedProjects);
+ });
+
+ it('renders divider correctly', () => {
+ // one divider can't be disabled
+ let dividersCount = 1;
+ if (searchIssueLabelAggregation) {
+ dividersCount += 1;
+ }
+ if (searchIssuesHideArchivedProjects) {
+ dividersCount += 1;
+ }
+ expect(findDividers()).toHaveLength(dividersCount);
});
});
- describe('Renders correctly with FF disabled', () => {
+ describe('Renders correctly with basic search', () => {
beforeEach(() => {
- createComponent({ urlQuery: MOCK_QUERY }, false);
+ createComponent({ initialState: { searchType: SEARCH_TYPE_BASIC } });
});
it('renders StatusFilter', () => {
expect(findStatusFilter().exists()).toBe(true);
@@ -78,15 +110,51 @@ describe('GlobalSearch IssuesFilters', () => {
expect(findLabelFilter().exists()).toBe(false);
});
- it('renders divider correctly', () => {
+ it("doesn't render ArchivedFilter", () => {
+ expect(findArchivedFilter().exists()).toBe(false);
+ });
+
+ it('renders 1 divider', () => {
expect(findDividers()).toHaveLength(1);
});
});
+ describe('Renders correctly in new nav', () => {
+ beforeEach(() => {
+ createComponent({
+ initialState: {
+ searchType: SEARCH_TYPE_ADVANCED,
+ useSidebarNavigation: true,
+ },
+ searchIssueLabelAggregation: true,
+ searchIssuesHideArchivedProjects: true,
+ });
+ });
+ it('renders StatusFilter', () => {
+ expect(findStatusFilter().exists()).toBe(true);
+ });
+
+ it('renders ConfidentialityFilter', () => {
+ expect(findConfidentialityFilter().exists()).toBe(true);
+ });
+
+ it('renders LabelFilter', () => {
+ expect(findLabelFilter().exists()).toBe(true);
+ });
+
+ it('renders ArchivedFilter', () => {
+ expect(findArchivedFilter().exists()).toBe(true);
+ });
+
+ it("doesn't render dividers", () => {
+ expect(findDividers()).toHaveLength(0);
+ });
+ });
+
describe('Renders correctly with wrong scope', () => {
beforeEach(() => {
- defaultGetters.currentScope = () => 'blobs';
- createComponent({ urlQuery: MOCK_QUERY });
+ defaultGetters.currentScope = () => 'test';
+ createComponent();
});
it("doesn't render StatusFilter", () => {
expect(findStatusFilter().exists()).toBe(false);
@@ -100,6 +168,10 @@ describe('GlobalSearch IssuesFilters', () => {
expect(findLabelFilter().exists()).toBe(false);
});
+ it("doesn't render ArchivedFilter", () => {
+ expect(findArchivedFilter().exists()).toBe(false);
+ });
+
it("doesn't render dividers", () => {
expect(findDividers()).toHaveLength(0);
});
diff --git a/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js b/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js
index 0932f8e47d2..b50f348be69 100644
--- a/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js
+++ b/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js
@@ -1,28 +1,131 @@
import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import { MOCK_QUERY } from 'jest/search/mock_data';
import MergeRequestsFilters from '~/search/sidebar/components/merge_requests_filters.vue';
import StatusFilter from '~/search/sidebar/components/status_filter/index.vue';
-import FiltersTemplate from '~/search/sidebar/components/filters_template.vue';
+import ArchivedFilter from '~/search/sidebar/components/archived_filter/index.vue';
+import { SEARCH_TYPE_ADVANCED, SEARCH_TYPE_BASIC } from '~/search/sidebar/constants';
+
+Vue.use(Vuex);
describe('GlobalSearch MergeRequestsFilters', () => {
let wrapper;
- const findStatusFilter = () => wrapper.findComponent(StatusFilter);
- const findFiltersTemplate = () => wrapper.findComponent(FiltersTemplate);
+ const defaultGetters = {
+ currentScope: () => 'merge_requests',
+ };
- const createComponent = () => {
- wrapper = shallowMount(MergeRequestsFilters);
+ const createComponent = ({
+ initialState = {},
+ searchMergeRequestsHideArchivedProjects = true,
+ } = {}) => {
+ const store = new Vuex.Store({
+ state: {
+ urlQuery: MOCK_QUERY,
+ useSidebarNavigation: false,
+ searchType: SEARCH_TYPE_ADVANCED,
+ ...initialState,
+ },
+ getters: defaultGetters,
+ });
+
+ wrapper = shallowMount(MergeRequestsFilters, {
+ store,
+ provide: {
+ glFeatures: {
+ searchMergeRequestsHideArchivedProjects,
+ },
+ },
+ });
};
- describe('Renders correctly', () => {
+ const findStatusFilter = () => wrapper.findComponent(StatusFilter);
+ const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
+ const findDividers = () => wrapper.findAll('hr');
+
+ describe.each`
+ description | searchMergeRequestsHideArchivedProjects
+ ${'Renders correctly with Archived Filter disabled'} | ${false}
+ ${'Renders correctly with Archived Filter enabled'} | ${true}
+ `('$description', ({ searchMergeRequestsHideArchivedProjects }) => {
beforeEach(() => {
- createComponent();
+ createComponent({
+ searchMergeRequestsHideArchivedProjects,
+ });
+ });
+
+ it('renders StatusFilter', () => {
+ expect(findStatusFilter().exists()).toBe(true);
+ });
+
+ it(`renders correctly ArchivedFilter when searchMergeRequestsHideArchivedProjects is ${searchMergeRequestsHideArchivedProjects}`, () => {
+ expect(findArchivedFilter().exists()).toBe(searchMergeRequestsHideArchivedProjects);
});
- it('renders ConfidentialityFilter', () => {
+
+ it('renders divider correctly', () => {
+ const dividersCount = searchMergeRequestsHideArchivedProjects ? 1 : 0;
+ expect(findDividers()).toHaveLength(dividersCount);
+ });
+ });
+
+ describe('Renders correctly with basic search', () => {
+ beforeEach(() => {
+ createComponent({ initialState: { searchType: SEARCH_TYPE_BASIC } });
+ });
+
+ it('renders StatusFilter', () => {
expect(findStatusFilter().exists()).toBe(true);
});
- it('renders FiltersTemplate', () => {
- expect(findFiltersTemplate().exists()).toBe(true);
+ it("doesn't render ArchivedFilter", () => {
+ expect(findArchivedFilter().exists()).toBe(false);
+ });
+
+ it('renders 1 divider', () => {
+ expect(findDividers()).toHaveLength(0);
+ });
+ });
+
+ describe('Renders correctly in new nav', () => {
+ beforeEach(() => {
+ createComponent({
+ initialState: {
+ searchType: SEARCH_TYPE_ADVANCED,
+ useSidebarNavigation: true,
+ },
+ searchMergeRequestsHideArchivedProjects: true,
+ });
+ });
+ it('renders StatusFilter', () => {
+ expect(findStatusFilter().exists()).toBe(true);
+ });
+
+ it('renders ArchivedFilter', () => {
+ expect(findArchivedFilter().exists()).toBe(true);
+ });
+
+ it("doesn't render divider", () => {
+ expect(findDividers()).toHaveLength(0);
+ });
+ });
+
+ describe('Renders correctly with wrong scope', () => {
+ beforeEach(() => {
+ defaultGetters.currentScope = () => 'test';
+ createComponent();
+ });
+ it("doesn't render StatusFilter", () => {
+ expect(findStatusFilter().exists()).toBe(false);
+ });
+
+ it("doesn't render ArchivedFilter", () => {
+ expect(findArchivedFilter().exists()).toBe(false);
+ });
+
+ it("doesn't render dividers", () => {
+ expect(findDividers()).toHaveLength(0);
});
});
});
diff --git a/spec/frontend/search/sidebar/components/notes_filters_spec.js b/spec/frontend/search/sidebar/components/notes_filters_spec.js
new file mode 100644
index 00000000000..2fb8e731ef5
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/notes_filters_spec.js
@@ -0,0 +1,28 @@
+import { shallowMount } from '@vue/test-utils';
+import NotesFilters from '~/search/sidebar/components/projects_filters.vue';
+import ArchivedFilter from '~/search/sidebar/components/archived_filter/index.vue';
+import FiltersTemplate from '~/search/sidebar/components/filters_template.vue';
+
+describe('GlobalSearch ProjectsFilters', () => {
+ let wrapper;
+
+ const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
+ const findFiltersTemplate = () => wrapper.findComponent(FiltersTemplate);
+
+ const createComponent = () => {
+ wrapper = shallowMount(NotesFilters);
+ };
+
+ describe('Renders correctly', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+ it('renders ArchivedFilter', () => {
+ expect(findArchivedFilter().exists()).toBe(true);
+ });
+
+ it('renders FiltersTemplate', () => {
+ expect(findFiltersTemplate().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/search/sidebar/components/projects_filters_spec.js b/spec/frontend/search/sidebar/components/projects_filters_spec.js
new file mode 100644
index 00000000000..930b7263ea4
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/projects_filters_spec.js
@@ -0,0 +1,28 @@
+import { shallowMount } from '@vue/test-utils';
+import ProjectsFilters from '~/search/sidebar/components/projects_filters.vue';
+import ArchivedFilter from '~/search/sidebar/components/archived_filter/index.vue';
+import FiltersTemplate from '~/search/sidebar/components/filters_template.vue';
+
+describe('GlobalSearch ProjectsFilters', () => {
+ let wrapper;
+
+ const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
+ const findFiltersTemplate = () => wrapper.findComponent(FiltersTemplate);
+
+ const createComponent = () => {
+ wrapper = shallowMount(ProjectsFilters);
+ };
+
+ describe('Renders correctly', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+ it('renders ArchivedFilter', () => {
+ expect(findArchivedFilter().exists()).toBe(true);
+ });
+
+ it('renders FiltersTemplate', () => {
+ expect(findFiltersTemplate().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/search/sidebar/components/projects_filters_specs.js b/spec/frontend/search/sidebar/components/projects_filters_specs.js
deleted file mode 100644
index 15e3254e289..00000000000
--- a/spec/frontend/search/sidebar/components/projects_filters_specs.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import ProjectsFilters from '~/search/sidebar/components/projects_filters.vue';
-import ArchivedFilter from '~/search/sidebar/components/language_filter/index.vue';
-import FiltersTemplate from '~/search/sidebar/components/filters_template.vue';
-
-describe('GlobalSearch ProjectsFilters', () => {
- let wrapper;
-
- const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
- const findFiltersTemplate = () => wrapper.findComponent(FiltersTemplate);
-
- const createComponent = () => {
- wrapper = shallowMount(ProjectsFilters);
- };
-
- describe('Renders correctly', () => {
- beforeEach(() => {
- createComponent();
- });
- it('renders ArchivedFilter', () => {
- expect(findArchivedFilter().exists()).toBe(true);
- });
-
- it('renders FiltersTemplate', () => {
- expect(findFiltersTemplate().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/search/sidebar/components/small_screen_drawer_navigation_spec.js b/spec/frontend/search/sidebar/components/small_screen_drawer_navigation_spec.js
new file mode 100644
index 00000000000..5ab4afba7f0
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/small_screen_drawer_navigation_spec.js
@@ -0,0 +1,68 @@
+import { nextTick } from 'vue';
+import { GlDrawer } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
+import { DRAWER_Z_INDEX } from '~/lib/utils/constants';
+import SmallScreenDrawerNavigation from '~/search/sidebar/components/small_screen_drawer_navigation.vue';
+
+describe('ScopeLegacyNavigation', () => {
+ let wrapper;
+ let closeSpy;
+ let toggleSpy;
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(SmallScreenDrawerNavigation, {
+ slots: {
+ default: '<div data-testid="default-slot-content">test</div>',
+ },
+ });
+ };
+
+ const findGlDrawer = () => wrapper.findComponent(GlDrawer);
+ const findTitle = () => wrapper.findComponent('h2');
+ const findSlot = () => wrapper.findByTestId('default-slot-content');
+ const findDomElementListener = () => wrapper.findComponent(DomElementListener);
+
+ describe('small screen navigation', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders drawer', () => {
+ expect(findGlDrawer().exists()).toBe(true);
+ expect(findGlDrawer().attributes('zindex')).toBe(DRAWER_Z_INDEX.toString());
+ expect(findGlDrawer().attributes('headerheight')).toBe('0');
+ });
+
+ it('renders title', () => {
+ expect(findTitle().exists()).toBe(true);
+ });
+
+ it('renders slots', () => {
+ expect(findSlot().exists()).toBe(true);
+ });
+ });
+
+ describe('actions', () => {
+ beforeEach(() => {
+ closeSpy = jest.spyOn(SmallScreenDrawerNavigation.methods, 'closeSmallScreenFilters');
+ toggleSpy = jest.spyOn(SmallScreenDrawerNavigation.methods, 'toggleSmallScreenFilters');
+ createComponent();
+ });
+
+ it('calls onClose', () => {
+ findGlDrawer().vm.$emit('close');
+ expect(closeSpy).toHaveBeenCalled();
+ });
+
+ it('calls toggleSmallScreenFilters', async () => {
+ expect(findGlDrawer().props('open')).toBe(false);
+
+ findDomElementListener().vm.$emit('click');
+ await nextTick();
+
+ expect(toggleSpy).toHaveBeenCalled();
+ expect(findGlDrawer().props('open')).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js
index cc9c555b6c7..889260fc478 100644
--- a/spec/frontend/search/store/actions_spec.js
+++ b/spec/frontend/search/store/actions_spec.js
@@ -1,4 +1,5 @@
import MockAdapter from 'axios-mock-adapter';
+import { mapValues } from 'lodash';
import testAction from 'helpers/vuex_action_helper';
import Api from '~/api';
import { createAlert } from '~/alert';
@@ -312,6 +313,21 @@ describe('Global Search Store Actions', () => {
});
});
+ describe('fetchSidebarCount with no count_link', () => {
+ beforeEach(() => {
+ state.navigation = mapValues(MOCK_NAVIGATION_DATA, (navItem) => ({
+ ...navItem,
+ count_link: null,
+ }));
+ });
+
+ it('should not request anything', async () => {
+ await testAction({ action: actions.fetchSidebarCount, state, expectedMutations: [] });
+
+ expect(mock.history.get.length).toBe(0);
+ });
+ });
+
describe.each`
action | axiosMock | type | expectedMutations | errorLogs
${actions.fetchAllAggregation} | ${{ method: 'onGet', code: HTTP_STATUS_OK }} | ${'success'} | ${MOCK_RECEIVE_AGGREGATIONS_SUCCESS_MUTATION} | ${0}
diff --git a/spec/frontend/security_configuration/components/continuous_vulnerability_scan_spec.js b/spec/frontend/security_configuration/components/continuous_vulnerability_scan_spec.js
new file mode 100644
index 00000000000..84a468e4dd8
--- /dev/null
+++ b/spec/frontend/security_configuration/components/continuous_vulnerability_scan_spec.js
@@ -0,0 +1,124 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlBadge, GlToggle } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import Vue from 'vue';
+import ProjectSetContinuousVulnerabilityScanning from '~/security_configuration/graphql/project_set_continuous_vulnerability_scanning.graphql';
+import ContinuousVulnerabilityScan from '~/security_configuration/components/continuous_vulnerability_scan.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+
+Vue.use(VueApollo);
+
+const setCVSMockResponse = {
+ data: {
+ projectSetContinuousVulnerabilityScanning: {
+ continuousVulnerabilityScanningEnabled: true,
+ errors: [],
+ },
+ },
+};
+
+const defaultProvide = {
+ continuousVulnerabilityScansEnabled: true,
+ projectFullPath: 'project/full/path',
+};
+
+describe('ContinuousVulnerabilityScan', () => {
+ let wrapper;
+ let apolloProvider;
+ let requestHandlers;
+
+ const createComponent = (options) => {
+ requestHandlers = {
+ setCVSMutationHandler: jest.fn().mockResolvedValue(setCVSMockResponse),
+ };
+
+ apolloProvider = createMockApollo([
+ [ProjectSetContinuousVulnerabilityScanning, requestHandlers.setCVSMutationHandler],
+ ]);
+
+ wrapper = shallowMount(ContinuousVulnerabilityScan, {
+ propsData: {
+ feature: {
+ available: true,
+ configured: true,
+ },
+ },
+ provide: {
+ glFeatures: {
+ dependencyScanningOnAdvisoryIngestion: true,
+ },
+ ...defaultProvide,
+ },
+ apolloProvider,
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ apolloProvider = null;
+ });
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const findToggle = () => wrapper.findComponent(GlToggle);
+
+ it('renders the component', () => {
+ expect(wrapper.exists()).toBe(true);
+ });
+
+ it('renders the correct title', () => {
+ expect(wrapper.text()).toContain('Continuous Vulnerability Scan');
+ });
+
+ it('renders the badge and toggle component with correct values', () => {
+ expect(findBadge().exists()).toBe(true);
+ expect(findBadge().text()).toBe('Experiment');
+
+ expect(findToggle().exists()).toBe(true);
+ expect(findToggle().props('value')).toBe(defaultProvide.continuousVulnerabilityScansEnabled);
+ });
+
+ it('should disable toggle when feature is not configured', () => {
+ createComponent({
+ propsData: {
+ feature: {
+ available: true,
+ configured: false,
+ },
+ },
+ });
+ expect(findToggle().props('disabled')).toBe(true);
+ });
+
+ it('calls mutation on toggle change with correct payload', () => {
+ findToggle().vm.$emit('change', true);
+
+ expect(requestHandlers.setCVSMutationHandler).toHaveBeenCalledWith({
+ input: {
+ projectPath: 'project/full/path',
+ enable: true,
+ },
+ });
+ });
+
+ describe('when feature flag is disabled', () => {
+ beforeEach(() => {
+ createComponent({
+ provide: {
+ glFeatures: {
+ dependencyScanningOnAdvisoryIngestion: false,
+ },
+ ...defaultProvide,
+ },
+ });
+ });
+
+ it('should not render toggle and badge', () => {
+ expect(findToggle().exists()).toBe(false);
+ expect(findBadge().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/security_configuration/components/feature_card_spec.js b/spec/frontend/security_configuration/components/feature_card_spec.js
index 983a66a7fd3..c715d01dd58 100644
--- a/spec/frontend/security_configuration/components/feature_card_spec.js
+++ b/spec/frontend/security_configuration/components/feature_card_spec.js
@@ -1,5 +1,6 @@
import { GlIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
+import Vue from 'vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { securityFeatures } from '~/security_configuration/components/constants';
import FeatureCard from '~/security_configuration/components/feature_card.vue';
@@ -13,6 +14,10 @@ import {
import { manageViaMRErrorMessage } from '../constants';
import { makeFeature } from './utils';
+const MockComponent = Vue.component('MockComponent', {
+ render: (createElement) => createElement('span'),
+});
+
describe('FeatureCard component', () => {
let feature;
let wrapper;
@@ -389,4 +394,17 @@ describe('FeatureCard component', () => {
});
});
});
+
+ describe('when a slot component is passed', () => {
+ beforeEach(() => {
+ feature = makeFeature({
+ slotComponent: MockComponent,
+ });
+ createComponent({ feature });
+ });
+
+ it('renders the component properly', () => {
+ expect(wrapper.findComponent(MockComponent).exists()).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/security_configuration/utils_spec.js b/spec/frontend/security_configuration/utils_spec.js
index 6e731e45da2..ea04e9e7993 100644
--- a/spec/frontend/security_configuration/utils_spec.js
+++ b/spec/frontend/security_configuration/utils_spec.js
@@ -34,6 +34,33 @@ describe('augmentFeatures', () => {
},
];
+ const mockSecurityFeaturesDast = [
+ {
+ name: 'DAST',
+ type: 'dast',
+ },
+ ];
+
+ const mockValidCustomFeatureWithOnDemandAvailableFalse = [
+ {
+ name: 'DAST',
+ type: 'dast',
+ customField: 'customvalue',
+ onDemandAvailable: false,
+ badge: {},
+ },
+ ];
+
+ const mockValidCustomFeatureWithOnDemandAvailableTrue = [
+ {
+ name: 'DAST',
+ type: 'dast',
+ customField: 'customvalue',
+ onDemandAvailable: true,
+ badge: {},
+ },
+ ];
+
const mockValidCustomFeatureSnakeCase = [
{
name: 'SAST',
@@ -54,6 +81,29 @@ describe('augmentFeatures', () => {
augmentedSecurityFeatures: mockValidCustomFeature,
};
+ const expectedOutputCustomFeatureWithOnDemandAvailableFalse = {
+ augmentedSecurityFeatures: [
+ {
+ name: 'DAST',
+ type: 'dast',
+ customField: 'customvalue',
+ onDemandAvailable: false,
+ },
+ ],
+ };
+
+ const expectedOutputCustomFeatureWithOnDemandAvailableTrue = {
+ augmentedSecurityFeatures: [
+ {
+ name: 'DAST',
+ type: 'dast',
+ customField: 'customvalue',
+ onDemandAvailable: true,
+ badge: {},
+ },
+ ],
+ };
+
describe('returns an object with augmentedSecurityFeatures when', () => {
it('given an empty array', () => {
expect(augmentFeatures(mockSecurityFeatures, [])).toEqual(expectedOutputDefault);
@@ -85,6 +135,20 @@ describe('augmentFeatures', () => {
);
});
});
+
+ describe('follows onDemandAvailable', () => {
+ it('deletes badge when false', () => {
+ expect(
+ augmentFeatures(mockSecurityFeaturesDast, mockValidCustomFeatureWithOnDemandAvailableFalse),
+ ).toEqual(expectedOutputCustomFeatureWithOnDemandAvailableFalse);
+ });
+
+ it('keeps badge when true', () => {
+ expect(
+ augmentFeatures(mockSecurityFeaturesDast, mockValidCustomFeatureWithOnDemandAvailableTrue),
+ ).toEqual(expectedOutputCustomFeatureWithOnDemandAvailableTrue);
+ });
+ });
});
describe('translateScannerNames', () => {
diff --git a/spec/frontend/sentry/index_spec.js b/spec/frontend/sentry/index_spec.js
deleted file mode 100644
index 3130e01cc9e..00000000000
--- a/spec/frontend/sentry/index_spec.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import index from '~/sentry/index';
-
-import LegacySentryConfig from '~/sentry/legacy_sentry_config';
-import SentryConfig from '~/sentry/sentry_config';
-
-describe('Sentry init', () => {
- const version = '1.0.0';
- const dsn = 'https://123@sentry.gitlab.test/123';
- const environment = 'test';
- const currentUserId = '1';
- const gitlabUrl = 'gitlabUrl';
- const revision = 'revision';
- const featureCategory = 'my_feature_category';
-
- beforeEach(() => {
- window.gon = {
- version,
- sentry_dsn: dsn,
- sentry_environment: environment,
- current_user_id: currentUserId,
- gitlab_url: gitlabUrl,
- revision,
- feature_category: featureCategory,
- };
-
- jest.spyOn(LegacySentryConfig, 'init').mockImplementation();
- jest.spyOn(SentryConfig, 'init').mockImplementation();
- });
-
- it('exports new version of Sentry in the global object', () => {
- // eslint-disable-next-line no-underscore-dangle
- expect(window._Sentry.SDK_VERSION).not.toMatch(/^5\./);
- });
-
- describe('when called', () => {
- beforeEach(() => {
- index();
- });
-
- it('configures sentry', () => {
- expect(SentryConfig.init).toHaveBeenCalledTimes(1);
- expect(SentryConfig.init).toHaveBeenCalledWith({
- dsn,
- currentUserId,
- allowUrls: [gitlabUrl, 'webpack-internal://'],
- environment,
- release: version,
- tags: {
- revision,
- feature_category: featureCategory,
- },
- });
- });
-
- it('does not configure legacy sentry', () => {
- expect(LegacySentryConfig.init).not.toHaveBeenCalled();
- });
- });
-
- describe('with "data-page" attr in body', () => {
- const mockPage = 'projects:show';
-
- beforeEach(() => {
- document.body.dataset.page = mockPage;
-
- index();
- });
-
- afterEach(() => {
- delete document.body.dataset.page;
- });
-
- it('configures sentry with a "page" tag', () => {
- expect(SentryConfig.init).toHaveBeenCalledTimes(1);
- expect(SentryConfig.init).toHaveBeenCalledWith(
- expect.objectContaining({
- tags: {
- revision,
- page: mockPage,
- feature_category: featureCategory,
- },
- }),
- );
- });
- });
-
- describe('with no tags configuration', () => {
- beforeEach(() => {
- window.gon.revision = undefined;
- window.gon.feature_category = undefined;
-
- index();
- });
-
- it('configures sentry with no tags', () => {
- expect(SentryConfig.init).toHaveBeenCalledTimes(1);
- expect(SentryConfig.init).toHaveBeenCalledWith(
- expect.objectContaining({
- tags: {},
- }),
- );
- });
- });
-});
diff --git a/spec/frontend/sentry/init_sentry_spec.js b/spec/frontend/sentry/init_sentry_spec.js
new file mode 100644
index 00000000000..e31068b935b
--- /dev/null
+++ b/spec/frontend/sentry/init_sentry_spec.js
@@ -0,0 +1,177 @@
+import {
+ BrowserClient,
+ defaultStackParser,
+ makeFetchTransport,
+ defaultIntegrations,
+
+ // exports
+ captureException,
+ captureMessage,
+ withScope,
+ SDK_VERSION,
+} from 'sentrybrowser';
+import * as Sentry from 'sentrybrowser';
+
+import { initSentry } from '~/sentry/init_sentry';
+
+const mockDsn = 'https://123@sentry.gitlab.test/123';
+const mockEnvironment = 'development';
+const mockCurrentUserId = 1;
+const mockGitlabUrl = 'https://gitlab.com';
+const mockVersion = '1.0.0';
+const mockRevision = '00112233';
+const mockFeatureCategory = 'my_feature_category';
+const mockPage = 'index:page';
+const mockSentryClientsideTracesSampleRate = 0.1;
+
+jest.mock('sentrybrowser', () => {
+ return {
+ ...jest.createMockFromModule('sentrybrowser'),
+
+ // unmock actual configuration options
+ defaultStackParser: jest.requireActual('sentrybrowser').defaultStackParser,
+ makeFetchTransport: jest.requireActual('sentrybrowser').makeFetchTransport,
+ defaultIntegrations: jest.requireActual('sentrybrowser').defaultIntegrations,
+ };
+});
+
+describe('SentryConfig', () => {
+ let mockBindClient;
+ let mockSetTags;
+ let mockSetUser;
+ let mockBrowserClient;
+ let mockStartSession;
+ let mockCaptureSession;
+
+ beforeEach(() => {
+ window.gon = {
+ sentry_dsn: mockDsn,
+ sentry_environment: mockEnvironment,
+ current_user_id: mockCurrentUserId,
+ gitlab_url: mockGitlabUrl,
+ version: mockVersion,
+ revision: mockRevision,
+ feature_category: mockFeatureCategory,
+ sentry_clientside_traces_sample_rate: mockSentryClientsideTracesSampleRate,
+ };
+
+ document.body.dataset.page = mockPage;
+
+ mockBindClient = jest.fn();
+ mockSetTags = jest.fn();
+ mockSetUser = jest.fn();
+ mockStartSession = jest.fn();
+ mockCaptureSession = jest.fn();
+ mockBrowserClient = jest.spyOn(Sentry, 'BrowserClient');
+
+ jest.spyOn(Sentry, 'getCurrentHub').mockReturnValue({
+ bindClient: mockBindClient,
+ setTags: mockSetTags,
+ setUser: mockSetUser,
+ startSession: mockStartSession,
+ captureSession: mockCaptureSession,
+ });
+ });
+
+ afterEach(() => {
+ // eslint-disable-next-line no-underscore-dangle
+ window._Sentry = undefined;
+ });
+
+ describe('initSentry', () => {
+ describe('when sentry is initialized', () => {
+ beforeEach(() => {
+ initSentry();
+ });
+
+ it('creates BrowserClient with gon values and configuration', () => {
+ expect(mockBrowserClient).toHaveBeenCalledWith(
+ expect.objectContaining({
+ dsn: mockDsn,
+ release: mockVersion,
+ allowUrls: [mockGitlabUrl, 'webpack-internal://'],
+ environment: mockEnvironment,
+ tracesSampleRate: mockSentryClientsideTracesSampleRate,
+ tracePropagationTargets: [/^\//],
+
+ transport: makeFetchTransport,
+ stackParser: defaultStackParser,
+ integrations: defaultIntegrations,
+ }),
+ );
+ });
+
+ it('binds the BrowserClient to the hub', () => {
+ expect(mockBindClient).toHaveBeenCalledTimes(1);
+ expect(mockBindClient).toHaveBeenCalledWith(expect.any(BrowserClient));
+ });
+
+ it('calls Sentry.setTags with gon values', () => {
+ expect(mockSetTags).toHaveBeenCalledTimes(1);
+ expect(mockSetTags).toHaveBeenCalledWith({
+ page: mockPage,
+ revision: mockRevision,
+ feature_category: mockFeatureCategory,
+ });
+ });
+
+ it('calls Sentry.setUser with gon values', () => {
+ expect(mockSetUser).toHaveBeenCalledTimes(1);
+ expect(mockSetUser).toHaveBeenCalledWith({
+ id: mockCurrentUserId,
+ });
+ });
+
+ it('sets global sentry', () => {
+ // eslint-disable-next-line no-underscore-dangle
+ expect(window._Sentry).toEqual({
+ captureException,
+ captureMessage,
+ withScope,
+ SDK_VERSION,
+ });
+ });
+ });
+
+ describe('when user is not logged in', () => {
+ beforeEach(() => {
+ window.gon.current_user_id = undefined;
+ initSentry();
+ });
+
+ it('does not call Sentry.setUser', () => {
+ expect(mockSetUser).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when gon is not defined', () => {
+ beforeEach(() => {
+ window.gon = undefined;
+ initSentry();
+ });
+
+ it('Sentry.init is not called', () => {
+ expect(mockBrowserClient).not.toHaveBeenCalled();
+ expect(mockBindClient).not.toHaveBeenCalled();
+
+ // eslint-disable-next-line no-underscore-dangle
+ expect(window._Sentry).toBe(undefined);
+ });
+ });
+
+ describe('when dsn is not configured', () => {
+ beforeEach(() => {
+ window.gon.sentry_dsn = undefined;
+ initSentry();
+ });
+
+ it('Sentry.init is not called', () => {
+ expect(mockBrowserClient).not.toHaveBeenCalled();
+ expect(mockBindClient).not.toHaveBeenCalled();
+
+ // eslint-disable-next-line no-underscore-dangle
+ expect(window._Sentry).toBe(undefined);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/sentry/legacy_index_spec.js b/spec/frontend/sentry/legacy_index_spec.js
index 493b4dfde67..fad1760ffc5 100644
--- a/spec/frontend/sentry/legacy_index_spec.js
+++ b/spec/frontend/sentry/legacy_index_spec.js
@@ -1,7 +1,6 @@
import index from '~/sentry/legacy_index';
import LegacySentryConfig from '~/sentry/legacy_sentry_config';
-import SentryConfig from '~/sentry/sentry_config';
describe('Sentry init', () => {
const dsn = 'https://123@sentry.gitlab.test/123';
@@ -22,7 +21,6 @@ describe('Sentry init', () => {
};
jest.spyOn(LegacySentryConfig, 'init').mockImplementation();
- jest.spyOn(SentryConfig, 'init').mockImplementation();
});
it('exports legacy version of Sentry in the global object', () => {
@@ -49,9 +47,5 @@ describe('Sentry init', () => {
},
});
});
-
- it('does not configure new sentry', () => {
- expect(SentryConfig.init).not.toHaveBeenCalled();
- });
});
});
diff --git a/spec/frontend/sentry/sentry_config_spec.js b/spec/frontend/sentry/sentry_config_spec.js
deleted file mode 100644
index 34c5221ef0d..00000000000
--- a/spec/frontend/sentry/sentry_config_spec.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import * as Sentry from 'sentrybrowser7';
-
-import SentryConfig from '~/sentry/sentry_config';
-
-describe('SentryConfig', () => {
- describe('init', () => {
- const options = {
- currentUserId: 1,
- };
-
- beforeEach(() => {
- jest.spyOn(SentryConfig, 'configure');
- jest.spyOn(SentryConfig, 'setUser');
-
- SentryConfig.init(options);
- });
-
- it('should set the options property', () => {
- expect(SentryConfig.options).toEqual(options);
- });
-
- it('should call the configure method', () => {
- expect(SentryConfig.configure).toHaveBeenCalled();
- });
-
- it('should call setUser', () => {
- expect(SentryConfig.setUser).toHaveBeenCalled();
- });
-
- it('should not call setUser if there is no current user ID', () => {
- SentryConfig.setUser.mockClear();
- SentryConfig.init({ currentUserId: undefined });
-
- expect(SentryConfig.setUser).not.toHaveBeenCalled();
- });
- });
-
- describe('configure', () => {
- const sentryConfig = {};
- const options = {
- dsn: 'https://123@sentry.gitlab.test/123',
- allowUrls: ['//gitlabUrl', 'webpack-internal://'],
- environment: 'test',
- release: 'revision',
- tags: {
- revision: 'revision',
- feature_category: 'my_feature_category',
- },
- };
-
- beforeEach(() => {
- jest.spyOn(Sentry, 'init').mockImplementation();
- jest.spyOn(Sentry, 'setTags').mockImplementation();
-
- sentryConfig.options = options;
-
- SentryConfig.configure.call(sentryConfig);
- });
-
- it('should call Sentry.init', () => {
- expect(Sentry.init).toHaveBeenCalledWith({
- dsn: options.dsn,
- release: options.release,
- allowUrls: options.allowUrls,
- environment: options.environment,
- });
- });
-
- it('should call Sentry.setTags', () => {
- expect(Sentry.setTags).toHaveBeenCalledWith(options.tags);
- });
-
- it('should set environment from options', () => {
- sentryConfig.options.environment = 'development';
-
- SentryConfig.configure.call(sentryConfig);
-
- expect(Sentry.init).toHaveBeenCalledWith({
- dsn: options.dsn,
- release: options.release,
- allowUrls: options.allowUrls,
- environment: 'development',
- });
- });
- });
-
- describe('setUser', () => {
- let sentryConfig;
-
- beforeEach(() => {
- sentryConfig = { options: { currentUserId: 1 } };
- jest.spyOn(Sentry, 'setUser');
-
- SentryConfig.setUser.call(sentryConfig);
- });
-
- it('should call .setUser', () => {
- expect(Sentry.setUser).toHaveBeenCalledWith({
- id: sentryConfig.options.currentUserId,
- });
- });
- });
-});
diff --git a/spec/frontend/service_desk/components/empty_state_with_any_issues_spec.js b/spec/frontend/service_desk/components/empty_state_with_any_issues_spec.js
deleted file mode 100644
index ce8a78767d4..00000000000
--- a/spec/frontend/service_desk/components/empty_state_with_any_issues_spec.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import { GlEmptyState } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import EmptyStateWithAnyIssues from '~/service_desk/components/empty_state_with_any_issues.vue';
-import {
- noSearchResultsTitle,
- noSearchResultsDescription,
- infoBannerUserNote,
- noOpenIssuesTitle,
- noClosedIssuesTitle,
-} from '~/service_desk/constants';
-
-describe('EmptyStateWithAnyIssues component', () => {
- let wrapper;
-
- const defaultProvide = {
- emptyStateSvgPath: 'empty/state/svg/path',
- newIssuePath: 'new/issue/path',
- showNewIssueLink: false,
- };
-
- const findGlEmptyState = () => wrapper.findComponent(GlEmptyState);
-
- const mountComponent = (props = {}) => {
- wrapper = shallowMount(EmptyStateWithAnyIssues, {
- propsData: {
- hasSearch: true,
- isOpenTab: true,
- ...props,
- },
- provide: defaultProvide,
- });
- };
-
- describe('when there is a search (with no results)', () => {
- beforeEach(() => {
- mountComponent();
- });
-
- it('shows empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- description: noSearchResultsDescription,
- title: noSearchResultsTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- });
- });
- });
-
- describe('when "Open" tab is active', () => {
- beforeEach(() => {
- mountComponent({ hasSearch: false });
- });
-
- it('shows empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- description: infoBannerUserNote,
- title: noOpenIssuesTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- });
- });
- });
-
- describe('when "Closed" tab is active', () => {
- beforeEach(() => {
- mountComponent({ hasSearch: false, isClosedTab: true, isOpenTab: false });
- });
-
- it('shows empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- title: noClosedIssuesTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- });
- });
- });
-});
diff --git a/spec/frontend/service_desk/components/empty_state_without_any_issues_spec.js b/spec/frontend/service_desk/components/empty_state_without_any_issues_spec.js
deleted file mode 100644
index c67f9588ed4..00000000000
--- a/spec/frontend/service_desk/components/empty_state_without_any_issues_spec.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import { GlEmptyState, GlLink } from '@gitlab/ui';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import EmptyStateWithoutAnyIssues from '~/service_desk/components/empty_state_without_any_issues.vue';
-import { infoBannerTitle, noIssuesSignedOutButtonText, learnMore } from '~/service_desk/constants';
-
-describe('EmptyStateWithoutAnyIssues component', () => {
- let wrapper;
-
- const defaultProvide = {
- emptyStateSvgPath: 'empty/state/svg/path',
- isSignedIn: true,
- signInPath: 'sign/in/path',
- canAdminIssues: true,
- isServiceDeskEnabled: true,
- serviceDeskEmailAddress: 'email@address.com',
- serviceDeskHelpPath: 'service/desk/help/path',
- };
-
- const findGlEmptyState = () => wrapper.findComponent(GlEmptyState);
- const findGlLink = () => wrapper.findComponent(GlLink);
- const findIssuesHelpPageLink = () => wrapper.findByRole('link', { name: learnMore });
-
- const mountComponent = ({ provide = {} } = {}) => {
- wrapper = mountExtended(EmptyStateWithoutAnyIssues, {
- provide: {
- ...defaultProvide,
- ...provide,
- },
- });
- };
-
- describe('when signed in', () => {
- beforeEach(() => {
- mountComponent();
- });
-
- it('renders empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- title: infoBannerTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- contentClass: 'gl-max-w-80!',
- });
- });
-
- it('renders description with service desk docs link', () => {
- expect(findIssuesHelpPageLink().attributes('href')).toBe(defaultProvide.serviceDeskHelpPath);
- });
-
- it('renders email address, when user can admin issues and service desk is enabled', () => {
- expect(wrapper.text()).toContain(wrapper.vm.serviceDeskEmailAddress);
- });
-
- it('does not render email address, when user can not admin issues', () => {
- mountComponent({ provide: { canAdminIssues: false } });
-
- expect(wrapper.text()).not.toContain(wrapper.vm.serviceDeskEmailAddress);
- });
-
- it('does not render email address, when service desk is not setup', () => {
- mountComponent({ provide: { isServiceDeskEnabled: false } });
-
- expect(wrapper.text()).not.toContain(wrapper.vm.serviceDeskEmailAddress);
- });
- });
-
- describe('when signed out', () => {
- beforeEach(() => {
- mountComponent({ provide: { isSignedIn: false } });
- });
-
- it('renders empty state', () => {
- expect(findGlEmptyState().props()).toMatchObject({
- title: infoBannerTitle,
- svgPath: defaultProvide.emptyStateSvgPath,
- primaryButtonText: noIssuesSignedOutButtonText,
- primaryButtonLink: defaultProvide.signInPath,
- contentClass: 'gl-max-w-80!',
- });
- });
-
- it('renders service desk docs link', () => {
- expect(findGlLink().attributes('href')).toBe(defaultProvide.serviceDeskHelpPath);
- expect(findGlLink().text()).toBe(learnMore);
- });
- });
-});
diff --git a/spec/frontend/service_desk/components/info_banner_spec.js b/spec/frontend/service_desk/components/info_banner_spec.js
deleted file mode 100644
index 7487d5d8b64..00000000000
--- a/spec/frontend/service_desk/components/info_banner_spec.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlLink, GlButton } from '@gitlab/ui';
-import InfoBanner from '~/service_desk/components/info_banner.vue';
-import { infoBannerAdminNote, enableServiceDesk } from '~/service_desk/constants';
-
-describe('InfoBanner', () => {
- let wrapper;
-
- const defaultProvide = {
- serviceDeskCalloutSvgPath: 'callout.svg',
- serviceDeskEmailAddress: 'sd@gmail.com',
- canAdminIssues: true,
- canEditProjectSettings: true,
- serviceDeskSettingsPath: 'path/to/project/settings',
- serviceDeskHelpPath: 'path/to/documentation',
- isServiceDeskEnabled: true,
- };
-
- const findEnableSDButton = () => wrapper.findComponent(GlButton);
-
- const mountComponent = (provide) => {
- return shallowMount(InfoBanner, {
- provide: {
- ...defaultProvide,
- ...provide,
- },
- stubs: {
- GlLink,
- GlButton,
- },
- });
- };
-
- beforeEach(() => {
- wrapper = mountComponent();
- });
-
- describe('Service Desk email address', () => {
- it('renders when user can admin issues and service desk is enabled', () => {
- expect(wrapper.text()).toContain(infoBannerAdminNote);
- expect(wrapper.text()).toContain(wrapper.vm.serviceDeskEmailAddress);
- });
-
- it('does not render, when user can not admin issues', () => {
- wrapper = mountComponent({ canAdminIssues: false });
-
- expect(wrapper.text()).not.toContain(infoBannerAdminNote);
- expect(wrapper.text()).not.toContain(wrapper.vm.serviceDeskEmailAddress);
- });
-
- it('does not render, when service desk is not setup', () => {
- wrapper = mountComponent({ isServiceDeskEnabled: false });
-
- expect(wrapper.text()).not.toContain(infoBannerAdminNote);
- expect(wrapper.text()).not.toContain(wrapper.vm.serviceDeskEmailAddress);
- });
- });
-
- describe('Link to Service Desk settings', () => {
- it('renders when user can edit settings and service desk is not enabled', () => {
- wrapper = mountComponent({ isServiceDeskEnabled: false });
-
- expect(wrapper.text()).toContain(enableServiceDesk);
- expect(findEnableSDButton().exists()).toBe(true);
- });
-
- it('does not render when service desk is enabled', () => {
- wrapper = mountComponent();
-
- expect(wrapper.text()).not.toContain(enableServiceDesk);
- expect(findEnableSDButton().exists()).toBe(false);
- });
-
- it('does not render when user cannot edit settings', () => {
- wrapper = mountComponent({ canEditProjectSettings: false });
-
- expect(wrapper.text()).not.toContain(enableServiceDesk);
- expect(findEnableSDButton().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/service_desk/components/service_desk_list_app_spec.js b/spec/frontend/service_desk/components/service_desk_list_app_spec.js
deleted file mode 100644
index bdb6a48895e..00000000000
--- a/spec/frontend/service_desk/components/service_desk_list_app_spec.js
+++ /dev/null
@@ -1,376 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import { cloneDeep } from 'lodash';
-import VueRouter from 'vue-router';
-import * as Sentry from '@sentry/browser';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import { TEST_HOST } from 'helpers/test_constants';
-import waitForPromises from 'helpers/wait_for_promises';
-import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
-import { issuableListTabs } from '~/vue_shared/issuable/list/constants';
-import { TYPENAME_USER } from '~/graphql_shared/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import { STATUS_CLOSED, STATUS_OPEN, STATUS_ALL } from '~/service_desk/constants';
-import getServiceDeskIssuesQuery from 'ee_else_ce/service_desk/queries/get_service_desk_issues.query.graphql';
-import getServiceDeskIssuesCountsQuery from 'ee_else_ce/service_desk/queries/get_service_desk_issues_counts.query.graphql';
-import ServiceDeskListApp from '~/service_desk/components/service_desk_list_app.vue';
-import InfoBanner from '~/service_desk/components/info_banner.vue';
-import EmptyStateWithAnyIssues from '~/service_desk/components/empty_state_with_any_issues.vue';
-import EmptyStateWithoutAnyIssues from '~/service_desk/components/empty_state_without_any_issues.vue';
-
-import {
- TOKEN_TYPE_ASSIGNEE,
- TOKEN_TYPE_AUTHOR,
- TOKEN_TYPE_CONFIDENTIAL,
- TOKEN_TYPE_LABEL,
- TOKEN_TYPE_MILESTONE,
- TOKEN_TYPE_MY_REACTION,
- TOKEN_TYPE_RELEASE,
- TOKEN_TYPE_SEARCH_WITHIN,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-import {
- getServiceDeskIssuesQueryResponse,
- getServiceDeskIssuesQueryEmptyResponse,
- getServiceDeskIssuesCountsQueryResponse,
- filteredTokens,
- urlParams,
- locationSearch,
-} from '../mock_data';
-
-jest.mock('@sentry/browser');
-
-describe('CE ServiceDeskListApp', () => {
- let wrapper;
- let router;
-
- Vue.use(VueApollo);
- Vue.use(VueRouter);
-
- const defaultProvide = {
- releasesPath: 'releases/path',
- autocompleteAwardEmojisPath: 'autocomplete/award/emojis/path',
- hasIterationsFeature: true,
- hasIssueWeightsFeature: true,
- hasIssuableHealthStatusFeature: true,
- groupPath: 'group/path',
- emptyStateSvgPath: 'empty-state.svg',
- isProject: true,
- isSignedIn: true,
- fullPath: 'path/to/project',
- isServiceDeskSupported: true,
- hasAnyIssues: true,
- initialSort: '',
- issuablesLoading: false,
- };
-
- let defaultQueryResponse = getServiceDeskIssuesQueryResponse;
- if (IS_EE) {
- defaultQueryResponse = cloneDeep(getServiceDeskIssuesQueryResponse);
- defaultQueryResponse.data.project.issues.nodes[0].healthStatus = null;
- defaultQueryResponse.data.project.issues.nodes[0].weight = 5;
- }
-
- const mockServiceDeskIssuesQueryResponseHandler = jest
- .fn()
- .mockResolvedValue(defaultQueryResponse);
- const mockServiceDeskIssuesQueryEmptyResponseHandler = jest
- .fn()
- .mockResolvedValue(getServiceDeskIssuesQueryEmptyResponse);
- const mockServiceDeskIssuesCountsQueryResponseHandler = jest
- .fn()
- .mockResolvedValue(getServiceDeskIssuesCountsQueryResponse);
-
- const findIssuableList = () => wrapper.findComponent(IssuableList);
- const findInfoBanner = () => wrapper.findComponent(InfoBanner);
- const findLabelsToken = () =>
- findIssuableList()
- .props('searchTokens')
- .find((token) => token.type === TOKEN_TYPE_LABEL);
-
- const createComponent = ({
- provide = {},
- serviceDeskIssuesQueryResponseHandler = mockServiceDeskIssuesQueryResponseHandler,
- serviceDeskIssuesCountsQueryResponseHandler = mockServiceDeskIssuesCountsQueryResponseHandler,
- } = {}) => {
- const requestHandlers = [
- [getServiceDeskIssuesQuery, serviceDeskIssuesQueryResponseHandler],
- [getServiceDeskIssuesCountsQuery, serviceDeskIssuesCountsQueryResponseHandler],
- ];
-
- router = new VueRouter({ mode: 'history' });
-
- return shallowMount(ServiceDeskListApp, {
- apolloProvider: createMockApollo(
- requestHandlers,
- {},
- {
- typePolicies: {
- Query: {
- fields: {
- project: {
- merge: true,
- },
- },
- },
- },
- },
- ),
- router,
- provide: {
- ...defaultProvide,
- ...provide,
- },
- });
- };
-
- beforeEach(() => {
- setWindowLocation(TEST_HOST);
- wrapper = createComponent();
- return waitForPromises();
- });
-
- it('renders the issuable list with skeletons while fetching service desk issues', async () => {
- wrapper = createComponent();
- await nextTick();
-
- expect(findIssuableList().props('issuablesLoading')).toBe(true);
-
- await waitForPromises();
-
- expect(findIssuableList().props('issuablesLoading')).toBe(false);
- });
-
- it('fetches service desk issues and renders them in the issuable list', () => {
- expect(findIssuableList().props()).toMatchObject({
- namespace: 'service-desk',
- recentSearchesStorageKey: 'service-desk-issues',
- issuables: defaultQueryResponse.data.project.issues.nodes,
- tabs: issuableListTabs,
- currentTab: STATUS_OPEN,
- tabCounts: {
- opened: 1,
- closed: 1,
- all: 1,
- },
- });
- });
-
- describe('InfoBanner', () => {
- it('renders when Service Desk is supported and has any number of issues', () => {
- expect(findInfoBanner().exists()).toBe(true);
- });
-
- it('does not render when Service Desk is not supported and has any number of issues', () => {
- wrapper = createComponent({ provide: { isServiceDeskSupported: false } });
-
- expect(findInfoBanner().exists()).toBe(false);
- });
-
- it('does not render, when there are no issues', () => {
- wrapper = createComponent({
- serviceDeskIssuesQueryResponseHandler: mockServiceDeskIssuesQueryEmptyResponseHandler,
- });
-
- expect(findInfoBanner().exists()).toBe(false);
- });
- });
-
- describe('Empty states', () => {
- describe('when there are issues', () => {
- it('shows EmptyStateWithAnyIssues component', () => {
- setWindowLocation(locationSearch);
- wrapper = createComponent({
- serviceDeskIssuesQueryResponseHandler: mockServiceDeskIssuesQueryEmptyResponseHandler,
- });
-
- expect(wrapper.findComponent(EmptyStateWithAnyIssues).props()).toEqual({
- hasSearch: true,
- isOpenTab: true,
- });
- });
- });
-
- describe('when there are no issues', () => {
- it('shows EmptyStateWithoutAnyIssues component', () => {
- wrapper = createComponent({
- provide: { hasAnyIssues: false },
- serviceDeskIssuesQueryResponseHandler: mockServiceDeskIssuesQueryEmptyResponseHandler,
- });
-
- expect(wrapper.findComponent(EmptyStateWithoutAnyIssues).exists()).toBe(true);
- });
- });
- });
-
- describe('Initial url params', () => {
- describe('search', () => {
- it('is set from the url params', () => {
- setWindowLocation(locationSearch);
- wrapper = createComponent();
-
- expect(router.history.current.query).toMatchObject({ search: 'find issues' });
- });
- });
-
- describe('state', () => {
- it('is set from the url params', async () => {
- const initialState = STATUS_ALL;
- setWindowLocation(`?state=${initialState}`);
- wrapper = createComponent();
- await waitForPromises();
-
- expect(findIssuableList().props('currentTab')).toBe(initialState);
- });
- });
-
- describe('filter tokens', () => {
- it('are set from the url params', () => {
- setWindowLocation(locationSearch);
- wrapper = createComponent();
-
- expect(findIssuableList().props('initialFilterValue')).toEqual(filteredTokens);
- });
- });
- });
-
- describe('Tokens', () => {
- const mockCurrentUser = {
- id: 1,
- name: 'Administrator',
- username: 'root',
- avatar_url: 'avatar/url',
- };
-
- describe('when user is signed out', () => {
- beforeEach(() => {
- wrapper = createComponent({ provide: { isSignedIn: false } });
- return waitForPromises();
- });
-
- it('does not render My-Reaction or Confidential tokens', () => {
- expect(findIssuableList().props('searchTokens')).not.toMatchObject([
- { type: TOKEN_TYPE_AUTHOR, preloadedUsers: [mockCurrentUser] },
- { type: TOKEN_TYPE_ASSIGNEE, preloadedUsers: [mockCurrentUser] },
- { type: TOKEN_TYPE_MY_REACTION },
- { type: TOKEN_TYPE_CONFIDENTIAL },
- ]);
- });
- });
-
- describe('when all tokens are available', () => {
- beforeEach(() => {
- window.gon = {
- current_user_id: mockCurrentUser.id,
- current_user_fullname: mockCurrentUser.name,
- current_username: mockCurrentUser.username,
- current_user_avatar_url: mockCurrentUser.avatar_url,
- };
-
- wrapper = createComponent();
- return waitForPromises();
- });
-
- it('renders all tokens alphabetically', () => {
- const preloadedUsers = [
- { ...mockCurrentUser, id: convertToGraphQLId(TYPENAME_USER, mockCurrentUser.id) },
- ];
-
- expect(findIssuableList().props('searchTokens')).toMatchObject([
- { type: TOKEN_TYPE_ASSIGNEE, preloadedUsers },
- { type: TOKEN_TYPE_CONFIDENTIAL },
- { type: TOKEN_TYPE_LABEL },
- { type: TOKEN_TYPE_MILESTONE },
- { type: TOKEN_TYPE_MY_REACTION },
- { type: TOKEN_TYPE_RELEASE },
- { type: TOKEN_TYPE_SEARCH_WITHIN },
- ]);
- });
- });
- });
-
- describe('Events', () => {
- describe('when "click-tab" event is emitted by IssuableList', () => {
- beforeEach(async () => {
- wrapper = createComponent();
- router.push = jest.fn();
- await waitForPromises();
-
- findIssuableList().vm.$emit('click-tab', STATUS_CLOSED);
- });
-
- it('updates ui to the new tab', () => {
- expect(findIssuableList().props('currentTab')).toBe(STATUS_CLOSED);
- });
-
- it('updates url to the new tab', () => {
- expect(router.push).toHaveBeenCalledWith({
- query: expect.objectContaining({ state: STATUS_CLOSED }),
- });
- });
- });
-
- describe('when "filter" event is emitted by IssuableList', () => {
- it('updates IssuableList with url params', async () => {
- wrapper = createComponent();
- router.push = jest.fn();
- await waitForPromises();
-
- findIssuableList().vm.$emit('filter', filteredTokens);
- await nextTick();
-
- expect(router.push).toHaveBeenCalledWith({
- query: expect.objectContaining(urlParams),
- });
- });
- });
- });
-
- describe('Errors', () => {
- describe.each`
- error | responseHandler
- ${'fetching issues'} | ${'serviceDeskIssuesQueryResponseHandler'}
- ${'fetching issue counts'} | ${'serviceDeskIssuesCountsQueryResponseHandler'}
- `('when there is an error $error', ({ responseHandler }) => {
- beforeEach(() => {
- wrapper = createComponent({
- [responseHandler]: jest.fn().mockRejectedValue(new Error('ERROR')),
- });
- return waitForPromises();
- });
-
- it('shows an error message', () => {
- expect(Sentry.captureException).toHaveBeenCalledWith(new Error('ERROR'));
- });
- });
- });
-
- describe('When providing token for labels', () => {
- it('passes function to fetchLatestLabels property if frontend caching is enabled', async () => {
- wrapper = createComponent({
- provide: {
- glFeatures: {
- frontendCaching: true,
- },
- },
- });
- await waitForPromises();
-
- expect(typeof findLabelsToken().fetchLatestLabels).toBe('function');
- });
-
- it('passes null to fetchLatestLabels property if frontend caching is disabled', async () => {
- wrapper = createComponent({
- provide: {
- glFeatures: {
- frontendCaching: false,
- },
- },
- });
- await waitForPromises();
-
- expect(findLabelsToken().fetchLatestLabels).toBe(null);
- });
- });
-});
diff --git a/spec/frontend/service_desk/mock_data.js b/spec/frontend/service_desk/mock_data.js
deleted file mode 100644
index dc875cb5c1e..00000000000
--- a/spec/frontend/service_desk/mock_data.js
+++ /dev/null
@@ -1,236 +0,0 @@
-import {
- FILTERED_SEARCH_TERM,
- OPERATOR_IS,
- OPERATOR_NOT,
- OPERATOR_OR,
- TOKEN_TYPE_ASSIGNEE,
- TOKEN_TYPE_CONFIDENTIAL,
- TOKEN_TYPE_EPIC,
- TOKEN_TYPE_ITERATION,
- TOKEN_TYPE_LABEL,
- TOKEN_TYPE_MILESTONE,
- TOKEN_TYPE_MY_REACTION,
- TOKEN_TYPE_RELEASE,
- TOKEN_TYPE_WEIGHT,
- TOKEN_TYPE_HEALTH,
-} from '~/vue_shared/components/filtered_search_bar/constants';
-
-export const getServiceDeskIssuesQueryResponse = {
- data: {
- project: {
- id: '1',
- __typename: 'Project',
- issues: {
- __persist: true,
- pageInfo: {
- __typename: 'PageInfo',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'startcursor',
- endCursor: 'endcursor',
- },
- nodes: [
- {
- __persist: true,
- __typename: 'Issue',
- id: 'gid://gitlab/Issue/123456',
- iid: '789',
- confidential: false,
- createdAt: '2021-05-22T04:08:01Z',
- downvotes: 2,
- dueDate: '2021-05-29',
- hidden: false,
- humanTimeEstimate: null,
- mergeRequestsCount: false,
- moved: false,
- state: 'opened',
- title: 'Issue title',
- updatedAt: '2021-05-22T04:08:01Z',
- closedAt: null,
- upvotes: 3,
- userDiscussionsCount: 4,
- webPath: 'project/-/issues/789',
- webUrl: 'project/-/issues/789',
- type: 'issue',
- assignees: {
- nodes: [
- {
- __persist: true,
- __typename: 'UserCore',
- id: 'gid://gitlab/User/234',
- avatarUrl: 'avatar/url',
- name: 'Marge Simpson',
- username: 'msimpson',
- webUrl: 'url/msimpson',
- },
- ],
- },
- author: {
- __persist: true,
- __typename: 'UserCore',
- id: 'gid://gitlab/User/456',
- avatarUrl: 'avatar/url',
- name: 'GitLab Support Bot',
- username: 'support-bot',
- webUrl: 'url/hsimpson',
- },
- labels: {
- nodes: [
- {
- __persist: true,
- id: 'gid://gitlab/ProjectLabel/456',
- color: '#333',
- title: 'Label title',
- description: 'Label description',
- },
- ],
- },
- milestone: null,
- taskCompletionStatus: {
- completedCount: 1,
- count: 2,
- },
- },
- ],
- },
- },
- },
-};
-
-export const getServiceDeskIssuesQueryEmptyResponse = {
- data: {
- project: {
- id: '1',
- __typename: 'Project',
- issues: {
- __persist: true,
- pageInfo: {
- __typename: 'PageInfo',
- hasNextPage: true,
- hasPreviousPage: false,
- startCursor: 'startcursor',
- endCursor: 'endcursor',
- },
- nodes: [],
- },
- },
- },
-};
-
-export const getServiceDeskIssuesCountsQueryResponse = {
- data: {
- project: {
- id: '1',
- openedIssues: {
- count: 1,
- },
- closedIssues: {
- count: 1,
- },
- allIssues: {
- count: 1,
- },
- },
- },
-};
-
-export const filteredTokens = [
- { type: FILTERED_SEARCH_TERM, value: { data: 'find issues', operator: 'undefined' } },
- { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'bart', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'lisa', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_ASSIGNEE, value: { data: '5', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'patty', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'selma', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'carl', operator: OPERATOR_OR } },
- { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'lenny', operator: OPERATOR_OR } },
- { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 3', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 4', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 20', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 30', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_LABEL, value: { data: 'cartoon', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_LABEL, value: { data: 'tv', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_LABEL, value: { data: 'live action', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_LABEL, value: { data: 'drama', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_LABEL, value: { data: 'comedy', operator: OPERATOR_OR } },
- { type: TOKEN_TYPE_LABEL, value: { data: 'sitcom', operator: OPERATOR_OR } },
- { type: TOKEN_TYPE_RELEASE, value: { data: 'v3', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_RELEASE, value: { data: 'v4', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_RELEASE, value: { data: 'v20', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_RELEASE, value: { data: 'v30', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_MY_REACTION, value: { data: 'thumbsup', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_MY_REACTION, value: { data: 'thumbsdown', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_CONFIDENTIAL, value: { data: 'yes', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_ITERATION, value: { data: '4', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_ITERATION, value: { data: '12', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_ITERATION, value: { data: '20', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_ITERATION, value: { data: '42', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_EPIC, value: { data: '12', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_EPIC, value: { data: '34', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_WEIGHT, value: { data: '1', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_WEIGHT, value: { data: '3', operator: OPERATOR_NOT } },
- { type: TOKEN_TYPE_HEALTH, value: { data: 'atRisk', operator: OPERATOR_IS } },
- { type: TOKEN_TYPE_HEALTH, value: { data: 'onTrack', operator: OPERATOR_NOT } },
-];
-
-export const urlParams = {
- search: 'find issues',
- 'assignee_username[]': ['bart', 'lisa', '5'],
- 'not[assignee_username][]': ['patty', 'selma'],
- 'or[assignee_username][]': ['carl', 'lenny'],
- milestone_title: ['season 3', 'season 4'],
- 'not[milestone_title]': ['season 20', 'season 30'],
- 'label_name[]': ['cartoon', 'tv'],
- 'not[label_name][]': ['live action', 'drama'],
- 'or[label_name][]': ['comedy', 'sitcom'],
- release_tag: ['v3', 'v4'],
- 'not[release_tag]': ['v20', 'v30'],
- my_reaction_emoji: 'thumbsup',
- 'not[my_reaction_emoji]': 'thumbsdown',
- confidential: 'yes',
- iteration_id: ['4', '12'],
- 'not[iteration_id]': ['20', '42'],
- epic_id: '12',
- 'not[epic_id]': '34',
- weight: '1',
- 'not[weight]': '3',
- health_status: 'atRisk',
- 'not[health_status]': 'onTrack',
-};
-
-export const locationSearch = [
- '?search=find+issues',
- 'assignee_username[]=bart',
- 'assignee_username[]=lisa',
- 'assignee_username[]=5',
- 'not[assignee_username][]=patty',
- 'not[assignee_username][]=selma',
- 'or[assignee_username][]=carl',
- 'or[assignee_username][]=lenny',
- 'milestone_title=season+3',
- 'milestone_title=season+4',
- 'not[milestone_title]=season+20',
- 'not[milestone_title]=season+30',
- 'label_name[]=cartoon',
- 'label_name[]=tv',
- 'not[label_name][]=live action',
- 'not[label_name][]=drama',
- 'or[label_name][]=comedy',
- 'or[label_name][]=sitcom',
- 'release_tag=v3',
- 'release_tag=v4',
- 'not[release_tag]=v20',
- 'not[release_tag]=v30',
- 'my_reaction_emoji=thumbsup',
- 'not[my_reaction_emoji]=thumbsdown',
- 'confidential=yes',
- 'iteration_id=4',
- 'iteration_id=12',
- 'not[iteration_id]=20',
- 'not[iteration_id]=42',
- 'epic_id=12',
- 'not[epic_id]=34',
- 'weight=1',
- 'not[weight]=3',
- 'health_status=atRisk',
- 'not[health_status]=onTrack',
-].join('&');
diff --git a/spec/frontend/sidebar/components/assignees/assignees_spec.js b/spec/frontend/sidebar/components/assignees/assignees_spec.js
index 65a07382ebc..2767d36ac3d 100644
--- a/spec/frontend/sidebar/components/assignees/assignees_spec.js
+++ b/spec/frontend/sidebar/components/assignees/assignees_spec.js
@@ -145,7 +145,7 @@ describe('Assignee component', () => {
});
expect(findAllAvatarLinks()).toHaveLength(users.length);
- expect(wrapper.find('.user-list-more').exists()).toBe(false);
+ expect(wrapper.find('[data-testid="user-list-more"]').exists()).toBe(false);
});
it('shows sorted assignee where "can merge" users are sorted first', () => {
diff --git a/spec/frontend/sidebar/components/assignees/sidebar_invite_members_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_invite_members_spec.js
index 501048bf056..8c42e61548f 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_invite_members_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_invite_members_spec.js
@@ -26,7 +26,7 @@ describe('Sidebar invite members component', () => {
});
it('has expected attributes on the trigger', () => {
- expect(findDirectInviteLink().props('triggerSource')).toBe('issue-assignee-dropdown');
+ expect(findDirectInviteLink().props('triggerSource')).toBe('issue_assignee_dropdown');
});
});
});
diff --git a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js
index c74a714cca4..9e7a198d32c 100644
--- a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js
+++ b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js
@@ -24,7 +24,7 @@ describe('UncollapsedAssigneeList component', () => {
});
}
- const findMoreButton = () => wrapper.find('.user-list-more button');
+ const findMoreButton = () => wrapper.find('[data-testid="user-list-more-button"]');
describe('One assignee/user', () => {
let user;
diff --git a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js
index 1ca20dad1c6..3588e92d515 100644
--- a/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js
+++ b/spec/frontend/sidebar/components/confidential/sidebar_confidentiality_form_spec.js
@@ -4,7 +4,7 @@ import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import SidebarConfidentialityForm from '~/sidebar/components/confidential/sidebar_confidentiality_form.vue';
-import { confidentialityQueries } from '~/sidebar/constants';
+import { confidentialityQueries } from '~/sidebar/queries/constants';
jest.mock('~/alert');
@@ -38,6 +38,23 @@ describe('Sidebar Confidentiality Form', () => {
});
};
+ const confidentialityMutation = (confidential, workspacePath) => {
+ return {
+ mutation: confidentialityQueries[wrapper.vm.issuableType].mutation,
+ variables: {
+ input: {
+ confidential,
+ iid: '1',
+ ...workspacePath,
+ },
+ },
+ };
+ };
+
+ const clickConfidentialToggle = () => {
+ findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
+ };
+
it('emits a `closeForm` event when Cancel button is clicked', () => {
createComponent();
findCancelButton().vm.$emit('click');
@@ -94,17 +111,10 @@ describe('Sidebar Confidentiality Form', () => {
});
it('calls a mutation to set confidential to true on button click', () => {
- findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: confidentialityQueries[wrapper.vm.issuableType].mutation,
- variables: {
- input: {
- confidential: true,
- iid: '1',
- projectPath: 'group/project',
- },
- },
- });
+ clickConfidentialToggle();
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith(
+ confidentialityMutation(true, { projectPath: 'group/project' }),
+ );
});
});
@@ -150,17 +160,49 @@ describe('Sidebar Confidentiality Form', () => {
});
it('calls a mutation to set epic confidentiality with correct parameters', () => {
- findConfidentialToggle().vm.$emit('click', new MouseEvent('click'));
+ clickConfidentialToggle();
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith(
+ confidentialityMutation(false, { groupPath: 'group/project' }),
+ );
+ });
+ });
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: confidentialityQueries[wrapper.vm.issuableType].mutation,
- variables: {
- input: {
- confidential: false,
- iid: '1',
- groupPath: 'group/project',
- },
- },
+ describe('when issuable type is `test_case`', () => {
+ describe('when test case is confidential', () => {
+ beforeEach(() => {
+ createComponent({ props: { confidential: true, issuableType: 'test_case' } });
+ });
+
+ it('renders a message about making a test case non-confidential', () => {
+ expect(findWarningMessage().text()).toBe(
+ 'You are going to turn off the confidentiality. This means everyone will be able to see this test case.',
+ );
+ });
+
+ it('calls a mutation to set confidential to false on button click', () => {
+ clickConfidentialToggle();
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith(
+ confidentialityMutation(false, { projectPath: 'group/project' }),
+ );
+ });
+ });
+
+ describe('when test case is not confidential', () => {
+ beforeEach(() => {
+ createComponent({ props: { issuableType: 'test_case' } });
+ });
+
+ it('renders a message about making a test case confidential', () => {
+ expect(findWarningMessage().text()).toBe(
+ 'You are going to turn on confidentiality. Only project members with at least the Reporter role can view or be notified about this test case.',
+ );
+ });
+
+ it('calls a mutation to set confidential to true on button click', () => {
+ clickConfidentialToggle();
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith(
+ confidentialityMutation(true, { projectPath: 'group/project' }),
+ );
});
});
});
diff --git a/spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js b/spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js
index 00b57b4916e..f3d50f17e2d 100644
--- a/spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js
+++ b/spec/frontend/sidebar/components/incidents/sidebar_escalation_status_spec.js
@@ -11,11 +11,8 @@ import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import SidebarEscalationStatus from '~/sidebar/components/incidents/sidebar_escalation_status.vue';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
-import {
- escalationStatusQuery,
- escalationStatusMutation,
- STATUS_ACKNOWLEDGED,
-} from '~/sidebar/constants';
+import { STATUS_ACKNOWLEDGED } from '~/sidebar/constants';
+import { escalationStatusQuery, escalationStatusMutation } from '~/sidebar/queries/constants';
import waitForPromises from 'helpers/wait_for_promises';
import EscalationStatus from 'ee_else_ce/sidebar/components/incidents/escalation_status.vue';
import { createAlert } from '~/alert';
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js
index 9c8d9656955..5e2ff73878f 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view_spec.js
@@ -5,11 +5,14 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
-import { workspaceLabelsQueries } from '~/sidebar/constants';
+import { workspaceLabelsQueries, workspaceCreateLabelMutation } from '~/sidebar/queries/constants';
import DropdownContentsCreateView from '~/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue';
-import createLabelMutation from '~/sidebar/components/labels/labels_select_widget/graphql/create_label.mutation.graphql';
import { DEFAULT_LABEL_COLOR } from '~/sidebar/components/labels/labels_select_widget/constants';
import {
+ mockCreateLabelResponse as createAbuseReportLabelSuccessfulResponse,
+ mockLabelsQueryResponse as abuseReportLabelsQueryResponse,
+} from '../../../../admin/abuse_report/mock_data';
+import {
mockRegularLabel,
mockSuggestedColors,
createLabelSuccessfulResponse,
@@ -38,6 +41,9 @@ const titleTakenError = {
};
const createLabelSuccessHandler = jest.fn().mockResolvedValue(createLabelSuccessfulResponse);
+const createAbuseReportLabelSuccessHandler = jest
+ .fn()
+ .mockResolvedValue(createAbuseReportLabelSuccessfulResponse);
const createLabelUserRecoverableErrorHandler = jest.fn().mockResolvedValue(userRecoverableError);
const createLabelDuplicateErrorHandler = jest.fn().mockResolvedValue(titleTakenError);
const createLabelErrorHandler = jest.fn().mockRejectedValue('Houston, we have a problem');
@@ -66,6 +72,7 @@ describe('DropdownContentsCreateView', () => {
labelsResponse = workspaceLabelsQueryResponse,
searchTerm = '',
} = {}) => {
+ const createLabelMutation = workspaceCreateLabelMutation[workspaceType];
const mockApollo = createMockApollo([[createLabelMutation, mutationHandler]]);
mockApollo.clients.defaultClient.cache.writeQuery({
query: workspaceLabelsQueries[workspaceType].query,
@@ -203,6 +210,22 @@ describe('DropdownContentsCreateView', () => {
});
});
+ it('calls the correct mutation when workspaceType is `abuseReport`', () => {
+ createComponent({
+ mutationHandler: createAbuseReportLabelSuccessHandler,
+ labelCreateType: '',
+ workspaceType: 'abuseReport',
+ labelsResponse: abuseReportLabelsQueryResponse,
+ });
+ fillLabelAttributes();
+ findCreateButton().vm.$emit('click');
+
+ expect(createAbuseReportLabelSuccessHandler).toHaveBeenCalledWith({
+ color: '#009966',
+ title: 'Test title',
+ });
+ });
+
it('calls createAlert is mutation has a user-recoverable error', async () => {
createComponent({ mutationHandler: createLabelUserRecoverableErrorHandler });
fillLabelAttributes();
diff --git a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js
index ad1edaa6671..7a1131b8cce 100644
--- a/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js
+++ b/spec/frontend/sidebar/components/labels/labels_select_widget/dropdown_footer_spec.js
@@ -1,12 +1,11 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DropdownFooter from '~/sidebar/components/labels/labels_select_widget/dropdown_footer.vue';
describe('DropdownFooter', () => {
let wrapper;
const createComponent = ({ props = {}, injected = {} } = {}) => {
- wrapper = shallowMount(DropdownFooter, {
+ wrapper = shallowMountExtended(DropdownFooter, {
propsData: {
footerCreateLabelTitle: 'create',
footerManageLabelTitle: 'manage',
@@ -20,7 +19,8 @@ describe('DropdownFooter', () => {
});
};
- const findCreateLabelButton = () => wrapper.find('[data-testid="create-label-button"]');
+ const findCreateLabelButton = () => wrapper.findByTestId('create-label-button');
+ const findManageLabelsButton = () => wrapper.findByTestId('manage-labels-button');
describe('Labels view', () => {
beforeEach(() => {
@@ -42,12 +42,37 @@ describe('DropdownFooter', () => {
expect(findCreateLabelButton().exists()).toBe(true);
});
- it('emits `toggleDropdownContentsCreateView` event on create label button click', async () => {
+ it('emits `toggleDropdownContentsCreateView` event on create label button click', () => {
findCreateLabelButton().trigger('click');
- await nextTick();
expect(wrapper.emitted('toggleDropdownContentsCreateView')).toEqual([[]]);
});
});
+
+ describe('manage labels button', () => {
+ it('is rendered', () => {
+ expect(findManageLabelsButton().exists()).toBe(true);
+ });
+
+ describe('when footerManageLabelTitle is not given', () => {
+ beforeEach(() => {
+ createComponent({ props: { footerManageLabelTitle: undefined } });
+ });
+
+ it('does not render manage labels button', () => {
+ expect(findManageLabelsButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when labelsManagePath is not provided', () => {
+ beforeEach(() => {
+ createComponent({ injected: { labelsManagePath: '' } });
+ });
+
+ it('does not render manage labels button', () => {
+ expect(findManageLabelsButton().exists()).toBe(false);
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/sidebar/components/lock/__snapshots__/edit_form_spec.js.snap b/spec/frontend/sidebar/components/lock/__snapshots__/edit_form_spec.js.snap
index 18d4df297df..d5bbd3bb3c9 100644
--- a/spec/frontend/sidebar/components/lock/__snapshots__/edit_form_spec.js.snap
+++ b/spec/frontend/sidebar/components/lock/__snapshots__/edit_form_spec.js.snap
@@ -12,7 +12,6 @@ exports[`Edit Form Dropdown In issue page when locked the appropriate warning te
message="Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment."
/>
</p>
-
<edit-form-buttons-stub
islocked="true"
issuabledisplayname="issue"
@@ -32,7 +31,6 @@ exports[`Edit Form Dropdown In issue page when unlocked the appropriate warning
message="Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment."
/>
</p>
-
<edit-form-buttons-stub
issuabledisplayname="issue"
/>
@@ -51,7 +49,6 @@ exports[`Edit Form Dropdown In merge request page when locked the appropriate wa
message="Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment."
/>
</p>
-
<edit-form-buttons-stub
islocked="true"
issuabledisplayname="merge request"
@@ -71,7 +68,6 @@ exports[`Edit Form Dropdown In merge request page when unlocked the appropriate
message="Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment."
/>
</p>
-
<edit-form-buttons-stub
issuabledisplayname="merge request"
/>
diff --git a/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js b/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js
index f43fb17ca37..5dd54d4867e 100644
--- a/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js
+++ b/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js
@@ -120,11 +120,11 @@ describe('Issuable Time Tracker', () => {
describe('Remaining meter', () => {
it('should display the remaining meter with the correct width', () => {
- expect(findTimeRemainingProgress().attributes('value')).toBe('5');
+ expect(findTimeRemainingProgress().vm.$attrs.value).toBe(5);
});
it('should display the remaining meter with the correct background color when within estimate', () => {
- expect(findTimeRemainingProgress().attributes('variant')).toBe('primary');
+ expect(findTimeRemainingProgress().vm.$attrs.variant).toBe('primary');
});
it('should display the remaining meter with the correct background color when over estimate', () => {
@@ -138,7 +138,7 @@ describe('Issuable Time Tracker', () => {
},
});
- expect(findTimeRemainingProgress().attributes('variant')).toBe('danger');
+ expect(findTimeRemainingProgress().vm.$attrs.variant).toBe('danger');
});
});
});
diff --git a/spec/frontend/sidebar/components/todo_toggle/__snapshots__/todo_spec.js.snap b/spec/frontend/sidebar/components/todo_toggle/__snapshots__/todo_spec.js.snap
index fd525474923..b5d8d31f88f 100644
--- a/spec/frontend/sidebar/components/todo_toggle/__snapshots__/todo_spec.js.snap
+++ b/spec/frontend/sidebar/components/todo_toggle/__snapshots__/todo_spec.js.snap
@@ -3,7 +3,7 @@
exports[`SidebarTodo template renders component container element with proper data attributes 1`] = `
<button
aria-label="Mark as done"
- class="gl-button btn btn-default btn-todo issuable-header-btn float-right"
+ class="btn btn-default btn-todo float-right gl-button issuable-header-btn"
data-issuable-id="1"
data-issuable-type="epic"
type="button"
@@ -14,13 +14,11 @@ exports[`SidebarTodo template renders component container element with proper da
size="16"
style="display: none;"
/>
-
<span
class="issuable-todo-inner"
>
Mark as done
</span>
-
<gl-loading-icon-stub
color="dark"
inline="true"
diff --git a/spec/frontend/sidebar/mock_data.js b/spec/frontend/sidebar/mock_data.js
index 05a7f504fd4..9d8392ad5f0 100644
--- a/spec/frontend/sidebar/mock_data.js
+++ b/spec/frontend/sidebar/mock_data.js
@@ -414,6 +414,33 @@ export const searchQueryResponse = {
},
};
+export const searchAutocompleteQueryResponse = {
+ data: {
+ workspace: {
+ __typename: 'Project',
+ id: '',
+ users: [
+ {
+ id: '1',
+ avatarUrl: '/avatar',
+ name: 'root',
+ username: 'root',
+ webUrl: 'root',
+ status: null,
+ },
+ {
+ id: '2',
+ avatarUrl: '/avatar2',
+ name: 'rookie',
+ username: 'rookie',
+ webUrl: 'rookie',
+ status: null,
+ },
+ ],
+ },
+ },
+};
+
export const updateIssueAssigneesMutationResponse = {
data: {
issuableSetAssignees: {
@@ -545,6 +572,29 @@ export const searchResponseOnMR = {
},
};
+export const searchAutocompleteResponseOnMR = {
+ data: {
+ workspace: {
+ __typename: 'Project',
+ id: '1',
+ users: [
+ {
+ ...mockUser1,
+ mergeRequestInteraction: {
+ canMerge: true,
+ },
+ },
+ {
+ ...mockUser2,
+ mergeRequestInteraction: {
+ canMerge: false,
+ },
+ },
+ ],
+ },
+ },
+};
+
export const projectMembersResponse = {
data: {
workspace: {
@@ -585,6 +635,36 @@ export const projectMembersResponse = {
},
};
+export const projectAutocompleteMembersResponse = {
+ data: {
+ workspace: {
+ id: '1',
+ __typename: 'Project',
+ users: [
+ // Remove nulls https://gitlab.com/gitlab-org/gitlab/-/issues/329750
+ null,
+ null,
+ // Remove duplicated entry https://gitlab.com/gitlab-org/gitlab/-/issues/327822
+ mockUser1,
+ mockUser1,
+ mockUser2,
+ {
+ __typename: 'UserCore',
+ id: 'gid://gitlab/User/2',
+ avatarUrl:
+ 'https://www.gravatar.com/avatar/a95e5b71488f4b9d69ce5ff58bfd28d6?s=80\u0026d=identicon',
+ name: 'Jacki Kub',
+ username: 'francina.skiles',
+ webUrl: '/franc',
+ status: {
+ availability: 'BUSY',
+ },
+ },
+ ],
+ },
+ },
+};
+
export const groupMembersResponse = {
data: {
workspace: {
diff --git a/spec/frontend/silent_mode_settings/components/app_spec.js b/spec/frontend/silent_mode_settings/components/app_spec.js
new file mode 100644
index 00000000000..5997bfd1b5f
--- /dev/null
+++ b/spec/frontend/silent_mode_settings/components/app_spec.js
@@ -0,0 +1,133 @@
+import { GlToggle, GlBadge } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/alert';
+import toast from '~/vue_shared/plugins/global_toast';
+import { updateApplicationSettings } from '~/rest_api';
+import SilentModeSettingsApp from '~/silent_mode_settings/components/app.vue';
+
+jest.mock('~/rest_api.js');
+jest.mock('~/alert');
+jest.mock('~/vue_shared/plugins/global_toast');
+
+const MOCK_DEFAULT_SILENT_MODE_ENABLED = false;
+
+describe('SilentModeSettingsApp', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ const defaultProps = {
+ isSilentModeEnabled: MOCK_DEFAULT_SILENT_MODE_ENABLED,
+ };
+
+ wrapper = shallowMount(SilentModeSettingsApp, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ const findGlToggle = () => wrapper.findComponent(GlToggle);
+ const findGlBadge = () => wrapper.findComponent(GlBadge);
+
+ describe('template', () => {
+ describe('experiment badge', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders properly', () => {
+ expect(findGlBadge().exists()).toBe(true);
+ });
+ });
+
+ describe('when silent mode is already enabled', () => {
+ beforeEach(() => {
+ createComponent({ isSilentModeEnabled: true });
+ });
+
+ it('renders the component with the GlToggle set to true', () => {
+ expect(findGlToggle().attributes('value')).toBe('true');
+ });
+ });
+
+ describe('when silent mode is no already enabled', () => {
+ beforeEach(() => {
+ createComponent({ isSilentModeEnabled: false });
+ });
+
+ it('renders the component with the GlToggle set to undefined', () => {
+ expect(findGlToggle().attributes('value')).toBeUndefined();
+ });
+ });
+ });
+
+ describe.each`
+ enabled | message
+ ${false} | ${'Silent mode disabled'}
+ ${true} | ${'Silent mode enabled'}
+ `(`toast message`, ({ enabled, message }) => {
+ beforeEach(() => {
+ updateApplicationSettings.mockImplementation(() => Promise.resolve());
+ createComponent();
+ });
+
+ it(`when successfully toggled to ${enabled}, toast message is ${message}`, async () => {
+ await findGlToggle().vm.$emit('change', enabled);
+ await waitForPromises();
+
+ expect(toast).toHaveBeenCalledWith(message);
+ });
+ });
+
+ describe.each`
+ description | mockApi | toastMsg | error
+ ${'onSuccess'} | ${() => Promise.resolve()} | ${'Silent mode enabled'} | ${false}
+ ${'onError'} | ${() => Promise.reject()} | ${false} | ${'There was an error updating the Silent Mode Settings.'}
+ `(`when submitting the form $description`, ({ mockApi, toastMsg, error }) => {
+ beforeEach(() => {
+ updateApplicationSettings.mockImplementation(mockApi);
+
+ createComponent();
+ });
+
+ it('calls updateApplicationSettings correctly', () => {
+ findGlToggle().vm.$emit('change', !MOCK_DEFAULT_SILENT_MODE_ENABLED);
+
+ expect(updateApplicationSettings).toHaveBeenCalledWith({
+ silent_mode_enabled: !MOCK_DEFAULT_SILENT_MODE_ENABLED,
+ });
+ });
+
+ it('handles the loading icon correctly', async () => {
+ expect(findGlToggle().props('isLoading')).toBe(false);
+
+ await findGlToggle().vm.$emit('change', !MOCK_DEFAULT_SILENT_MODE_ENABLED);
+
+ expect(findGlToggle().props('isLoading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findGlToggle().props('isLoading')).toBe(false);
+ });
+
+ it(`does ${toastMsg ? '' : 'not '}render an success toast message`, async () => {
+ await findGlToggle().vm.$emit('change', !MOCK_DEFAULT_SILENT_MODE_ENABLED);
+ await waitForPromises();
+
+ return toastMsg
+ ? expect(toast).toHaveBeenCalledWith(toastMsg)
+ : expect(toast).not.toHaveBeenCalled();
+ });
+
+ it(`does ${error ? '' : 'not '}render an error message`, async () => {
+ await findGlToggle().vm.$emit('change', !MOCK_DEFAULT_SILENT_MODE_ENABLED);
+ await waitForPromises();
+
+ return error
+ ? expect(createAlert).toHaveBeenCalledWith({ message: error })
+ : expect(createAlert).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap
index 76e84fa183c..1c60c3af310 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap
@@ -8,11 +8,10 @@ exports[`Snippet Blob Edit component with loaded blob matches snapshot 1`] = `
<blob-header-edit-stub
candelete="true"
data-qa-selector="file_name_field"
- id="blob_local_7_file_path"
+ id="reference-0"
showdelete="true"
value="foo/bar/test.md"
/>
-
<source-editor-stub
debouncevalue="250"
editoroptions="[object Object]"
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
index e783927f87b..5ed3b520b70 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
@@ -5,16 +5,15 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
class="form-group js-description-input"
>
<label
- for="snippet-description"
+ for="reference-0"
>
Description (optional)
</label>
-
<div
class="js-collapsible-input"
>
<div
- class="js-collapsed d-none"
+ class="d-none js-collapsed"
>
<gl-form-input-stub
class="form-control"
@@ -22,9 +21,8 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
placeholder="Describe what your snippet does or how to use it…"
/>
</div>
-
<div
- class="js-vue-markdown-field md-area position-relative gfm-form gl-overflow-hidden js-expanded"
+ class="gfm-form gl-overflow-hidden js-expanded js-vue-markdown-field md-area position-relative"
data-uploads-path=""
>
<markdown-header-stub
@@ -36,23 +34,22 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
suggestionstartindex="0"
uploadspath=""
/>
-
<div
class="md-write-holder"
>
<div
- class="zen-backdrop div-dropzone-wrapper"
+ class="div-dropzone-wrapper zen-backdrop"
>
<div
class="div-dropzone js-invalid-dropzone"
>
<textarea
aria-label="Description"
- class="note-textarea js-gfm-input js-autosize markdown-area js-gfm-input-initialized"
+ class="js-autosize js-gfm-input js-gfm-input-initialized markdown-area note-textarea"
data-qa-selector="snippet_description_field"
data-supports-quick-actions="false"
dir="auto"
- id="snippet-description"
+ id="reference-0"
placeholder="Write a comment or drag your files here…"
style="overflow-x: hidden; word-wrap: break-word; overflow-y: hidden;"
/>
@@ -68,10 +65,9 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
</svg>
</div>
</div>
-
<a
aria-label="Leave zen mode"
- class="zen-control zen-control-leave js-zen-leave gl-text-gray-500"
+ class="gl-text-gray-500 js-zen-leave zen-control zen-control-leave"
href="#"
>
<gl-icon-stub
@@ -79,7 +75,6 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
size="16"
/>
</a>
-
<markdown-toolbar-stub
canattachfile="true"
markdowndocspath="help/"
@@ -87,19 +82,14 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
/>
</div>
</div>
-
<div
- class="js-vue-md-preview md-preview-holder gl-px-5"
+ class="gl-px-5 js-vue-md-preview md-preview-holder"
style="display: none;"
>
<div
class="md"
/>
</div>
-
- <!---->
-
- <!---->
</div>
</div>
</div>
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap
index 9fb43815cbc..2b2335036f6 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap
@@ -6,7 +6,7 @@ exports[`Snippet Description component matches the snapshot 1`] = `
data-qa-selector="snippet_description_content"
>
<div
- class="md js-snippet-description"
+ class="js-snippet-description md"
>
<h2>
The property of Thor
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap
index ed54582ca29..3274f41e4af 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_visibility_edit_spec.js.snap
@@ -5,9 +5,7 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
class="form-group"
>
<label>
-
Visibility level
-
<gl-link-stub
href="/foo/bar"
target="_blank"
@@ -18,10 +16,9 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
/>
</gl-link-stub>
</label>
-
<gl-form-group-stub
class="gl-mb-0"
- id="visibility-level-setting"
+ id="reference-0"
labeldescription=""
optionaltext="(optional)"
>
@@ -39,15 +36,14 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
value="private"
>
<div
- class="d-flex align-items-center"
+ class="align-items-center d-flex"
>
<gl-icon-stub
name="lock"
size="16"
/>
-
<span
- class="font-weight-bold ml-1 js-visibility-option"
+ class="font-weight-bold js-visibility-option ml-1"
data-qa-selector="visibility_content"
data-qa-visibility="Private"
>
@@ -60,15 +56,14 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
value="internal"
>
<div
- class="d-flex align-items-center"
+ class="align-items-center d-flex"
>
<gl-icon-stub
name="shield"
size="16"
/>
-
<span
- class="font-weight-bold ml-1 js-visibility-option"
+ class="font-weight-bold js-visibility-option ml-1"
data-qa-selector="visibility_content"
data-qa-visibility="Internal"
>
@@ -81,15 +76,14 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
value="public"
>
<div
- class="d-flex align-items-center"
+ class="align-items-center d-flex"
>
<gl-icon-stub
name="earth"
size="16"
/>
-
<span
- class="font-weight-bold ml-1 js-visibility-option"
+ class="font-weight-bold js-visibility-option ml-1"
data-qa-selector="visibility_content"
data-qa-visibility="Public"
>
@@ -99,12 +93,9 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
</gl-form-radio-stub>
</gl-form-radio-group-stub>
</gl-form-group-stub>
-
<div
class="text-muted"
data-testid="restricted-levels-info"
- >
- <!---->
- </div>
+ />
</div>
`;
diff --git a/spec/frontend/snippets/components/embed_dropdown_spec.js b/spec/frontend/snippets/components/embed_dropdown_spec.js
index d8c6ad3278a..cb9b9800bfe 100644
--- a/spec/frontend/snippets/components/embed_dropdown_spec.js
+++ b/spec/frontend/snippets/components/embed_dropdown_spec.js
@@ -1,6 +1,6 @@
import { GlFormInputGroup } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
import { escape as esc } from 'lodash';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { TEST_HOST } from 'helpers/test_constants';
import EmbedDropdown from '~/snippets/components/embed_dropdown.vue';
@@ -10,56 +10,24 @@ describe('snippets/components/embed_dropdown', () => {
let wrapper;
const createComponent = () => {
- wrapper = mount(EmbedDropdown, {
+ wrapper = shallowMountExtended(EmbedDropdown, {
propsData: {
url: TEST_URL,
},
});
};
- const findSectionsData = () => {
- const sections = [];
- let current = {};
-
- wrapper.findAll('[data-testid="header"],[data-testid="input"]').wrappers.forEach((x) => {
- const type = x.attributes('data-testid');
-
- if (type === 'header') {
- current = {
- header: x.text(),
- };
-
- sections.push(current);
- } else {
- const value = x.findComponent(GlFormInputGroup).props('value');
- const copyValue = x.find('button[title="Copy"]').attributes('data-clipboard-text');
-
- Object.assign(current, {
- value,
- copyValue,
- });
- }
- });
-
- return sections;
- };
+ const findEmbedSection = () => wrapper.findByTestId('section-Embed');
+ const findShareSection = () => wrapper.findByTestId('section-Share');
it('renders dropdown items', () => {
createComponent();
const embedValue = `<script src="${esc(TEST_URL)}.js"></script>`;
- expect(findSectionsData()).toEqual([
- {
- header: 'Embed',
- value: embedValue,
- copyValue: embedValue,
- },
- {
- header: 'Share',
- value: TEST_URL,
- copyValue: TEST_URL,
- },
- ]);
+ expect(findEmbedSection().text()).toBe('Embed');
+ expect(findShareSection().text()).toBe('Share');
+ expect(findEmbedSection().findComponent(GlFormInputGroup).attributes('value')).toBe(embedValue);
+ expect(findShareSection().findComponent(GlFormInputGroup).attributes('value')).toBe(TEST_URL);
});
});
diff --git a/spec/frontend/super_sidebar/components/context_header_spec.js b/spec/frontend/super_sidebar/components/context_header_spec.js
deleted file mode 100644
index 943b659c997..00000000000
--- a/spec/frontend/super_sidebar/components/context_header_spec.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { GlAvatar } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import ContextHeader from '~/super_sidebar/components/context_header.vue';
-
-describe('ContextHeader component', () => {
- let wrapper;
-
- const context = {
- id: 1,
- title: 'Title',
- avatar: '/path/to/avatar.png',
- };
-
- const findGlAvatar = () => wrapper.getComponent(GlAvatar);
-
- const createWrapper = (props = {}) => {
- wrapper = shallowMountExtended(ContextHeader, {
- propsData: {
- context,
- expanded: false,
- ...props,
- },
- });
- };
-
- describe('with an avatar', () => {
- it('passes the correct props to GlAvatar', () => {
- createWrapper();
- const avatar = findGlAvatar();
-
- expect(avatar.props('shape')).toBe('rect');
- expect(avatar.props('entityName')).toBe(context.title);
- expect(avatar.props('entityId')).toBe(context.id);
- expect(avatar.props('src')).toBe(context.avatar);
- });
-
- it('renders the avatar with a custom shape', () => {
- const customShape = 'circle';
- createWrapper({
- context: {
- ...context,
- avatar_shape: customShape,
- },
- });
- const avatar = findGlAvatar();
-
- expect(avatar.props('shape')).toBe(customShape);
- });
- });
-});
diff --git a/spec/frontend/super_sidebar/components/context_switcher_spec.js b/spec/frontend/super_sidebar/components/context_switcher_spec.js
deleted file mode 100644
index dd8f39e7cb7..00000000000
--- a/spec/frontend/super_sidebar/components/context_switcher_spec.js
+++ /dev/null
@@ -1,302 +0,0 @@
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import { GlDisclosureDropdown, GlSearchBoxByType, GlLoadingIcon, GlAlert } from '@gitlab/ui';
-import * as Sentry from '@sentry/browser';
-import { s__ } from '~/locale';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import ContextSwitcher from '~/super_sidebar/components/context_switcher.vue';
-import ContextSwitcherToggle from '~/super_sidebar/components/context_switcher_toggle.vue';
-import NavItem from '~/super_sidebar/components/nav_item.vue';
-import ProjectsList from '~/super_sidebar/components/projects_list.vue';
-import GroupsList from '~/super_sidebar/components/groups_list.vue';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import searchUserProjectsAndGroupsQuery from '~/super_sidebar/graphql/queries/search_user_groups_and_projects.query.graphql';
-import { trackContextAccess, formatContextSwitcherItems } from '~/super_sidebar/utils';
-import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import waitForPromises from 'helpers/wait_for_promises';
-import { stubComponent } from 'helpers/stub_component';
-import { contextSwitcherLinks, searchUserProjectsAndGroupsResponseMock } from '../mock_data';
-
-jest.mock('~/super_sidebar/utils', () => ({
- getStorageKeyFor: jest.requireActual('~/super_sidebar/utils').getStorageKeyFor,
- getTopFrequentItems: jest.requireActual('~/super_sidebar/utils').getTopFrequentItems,
- formatContextSwitcherItems: jest.requireActual('~/super_sidebar/utils')
- .formatContextSwitcherItems,
- trackContextAccess: jest.fn(),
-}));
-const focusInputMock = jest.fn();
-
-const username = 'root';
-const projectsPath = 'projectsPath';
-const groupsPath = 'groupsPath';
-const contextHeader = { avatar_shape: 'circle' };
-
-Vue.use(VueApollo);
-
-describe('ContextSwitcher component', () => {
- let wrapper;
- let mockApollo;
-
- const findDisclosureDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
- const findContextSwitcherToggle = () => wrapper.findComponent(ContextSwitcherToggle);
- const findNavItems = () => wrapper.findAllComponents(NavItem);
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
- const findProjectsList = () => wrapper.findComponent(ProjectsList);
- const findGroupsList = () => wrapper.findComponent(GroupsList);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findAlert = () => wrapper.findComponent(GlAlert);
-
- const triggerSearchQuery = async () => {
- findSearchBox().vm.$emit('input', 'foo');
- await nextTick();
- jest.advanceTimersByTime(DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
- return waitForPromises();
- };
-
- const searchUserProjectsAndGroupsHandlerSuccess = jest
- .fn()
- .mockResolvedValue(searchUserProjectsAndGroupsResponseMock);
-
- const createWrapper = ({ props = {}, requestHandlers = {} } = {}) => {
- mockApollo = createMockApollo([
- [
- searchUserProjectsAndGroupsQuery,
- requestHandlers.searchUserProjectsAndGroupsQueryHandler ??
- searchUserProjectsAndGroupsHandlerSuccess,
- ],
- ]);
-
- wrapper = shallowMountExtended(ContextSwitcher, {
- apolloProvider: mockApollo,
- provide: {
- contextSwitcherLinks,
- },
- propsData: {
- username,
- projectsPath,
- groupsPath,
- contextHeader,
- ...props,
- },
- stubs: {
- GlDisclosureDropdown: stubComponent(GlDisclosureDropdown, {
- template: `
- <div>
- <slot name="toggle" />
- <slot />
- </div>
- `,
- }),
- GlSearchBoxByType: stubComponent(GlSearchBoxByType, {
- props: ['placeholder'],
- methods: { focusInput: focusInputMock },
- }),
- ProjectsList: stubComponent(ProjectsList, {
- props: ['username', 'viewAllLink', 'isSearch', 'searchResults'],
- }),
- GroupsList: stubComponent(GroupsList, {
- props: ['username', 'viewAllLink', 'isSearch', 'searchResults'],
- }),
- },
- });
- };
-
- describe('default', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders the context switcher links', () => {
- const navItems = findNavItems();
- const firstNavItem = navItems.at(0);
-
- expect(navItems.length).toBe(contextSwitcherLinks.length);
- expect(firstNavItem.props('item')).toBe(contextSwitcherLinks[0]);
- expect(firstNavItem.props('linkClasses')).toEqual({
- [contextSwitcherLinks[0].link_classes]: contextSwitcherLinks[0].link_classes,
- });
- });
-
- it('passes the placeholder to the search box', () => {
- expect(findSearchBox().props('placeholder')).toBe(
- s__('Navigation|Search your projects or groups'),
- );
- });
-
- it('passes the correct props to the frequent projects list', () => {
- expect(findProjectsList().props()).toEqual({
- username,
- viewAllLink: projectsPath,
- isSearch: false,
- searchResults: [],
- });
- });
-
- it('passes the correct props to the frequent groups list', () => {
- expect(findGroupsList().props()).toEqual({
- username,
- viewAllLink: groupsPath,
- isSearch: false,
- searchResults: [],
- });
- });
-
- it('does not trigger the search query on mount', () => {
- expect(searchUserProjectsAndGroupsHandlerSuccess).not.toHaveBeenCalled();
- });
-
- it('shows a loading spinner when search query is typed in', async () => {
- findSearchBox().vm.$emit('input', 'foo');
- await nextTick();
-
- expect(findLoadingIcon().exists()).toBe(true);
- });
-
- it('passes the correct props to the toggle', () => {
- expect(findContextSwitcherToggle().props('context')).toEqual(contextHeader);
- expect(findContextSwitcherToggle().props('expanded')).toEqual(false);
- });
-
- it('does not emit the `toggle` event initially', () => {
- expect(wrapper.emitted('toggle')).toBe(undefined);
- });
- });
-
- describe('visibility changes', () => {
- beforeEach(() => {
- createWrapper();
- findDisclosureDropdown().vm.$emit('shown');
- });
-
- it('emits the `toggle` event, focuses the search input and puts the toggle in the expanded state when opened', () => {
- expect(wrapper.emitted('toggle')).toHaveLength(1);
- expect(wrapper.emitted('toggle')[0]).toEqual([true]);
- expect(focusInputMock).toHaveBeenCalledTimes(1);
- expect(findContextSwitcherToggle().props('expanded')).toBe(true);
- });
-
- it("emits the `toggle` event, does not attempt to focus the input, and resets the toggle's `expanded` props to `false` when closed", async () => {
- findDisclosureDropdown().vm.$emit('hidden');
- await nextTick();
-
- expect(wrapper.emitted('toggle')).toHaveLength(2);
- expect(wrapper.emitted('toggle')[1]).toEqual([false]);
- expect(focusInputMock).toHaveBeenCalledTimes(1);
- expect(findContextSwitcherToggle().props('expanded')).toBe(false);
- });
- });
-
- describe('item access tracking', () => {
- it('does not track anything if not within a trackable context', () => {
- createWrapper();
-
- expect(trackContextAccess).not.toHaveBeenCalled();
- });
-
- it('tracks item access if within a trackable context', () => {
- const currentContext = { namespace: 'groups' };
- createWrapper({
- props: {
- currentContext,
- },
- });
-
- expect(trackContextAccess).toHaveBeenCalledWith(username, currentContext);
- });
- });
-
- describe('on search', () => {
- beforeEach(() => {
- createWrapper();
- return triggerSearchQuery();
- });
-
- it('hides persistent links', () => {
- expect(findNavItems().length).toBe(0);
- });
-
- it('triggers the search query on search', () => {
- expect(searchUserProjectsAndGroupsHandlerSuccess).toHaveBeenCalled();
- });
-
- it('hides the loading spinner', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('passes the projects to the frequent projects list', () => {
- expect(findProjectsList().props('isSearch')).toBe(true);
- expect(findProjectsList().props('searchResults')).toEqual(
- formatContextSwitcherItems(searchUserProjectsAndGroupsResponseMock.data.projects.nodes),
- );
- });
-
- it('passes the groups to the frequent groups list', () => {
- expect(findGroupsList().props('isSearch')).toBe(true);
- expect(findGroupsList().props('searchResults')).toEqual(
- formatContextSwitcherItems(searchUserProjectsAndGroupsResponseMock.data.user.groups.nodes),
- );
- });
- });
-
- describe('when search query does not match any items', () => {
- beforeEach(() => {
- createWrapper({
- requestHandlers: {
- searchUserProjectsAndGroupsQueryHandler: jest.fn().mockResolvedValue({
- data: {
- projects: {
- nodes: [],
- },
- user: {
- id: '1',
- groups: {
- nodes: [],
- },
- },
- },
- }),
- },
- });
- return triggerSearchQuery();
- });
-
- it('passes empty results to the lists', () => {
- expect(findProjectsList().props('isSearch')).toBe(true);
- expect(findProjectsList().props('searchResults')).toEqual([]);
- expect(findGroupsList().props('isSearch')).toBe(true);
- expect(findGroupsList().props('searchResults')).toEqual([]);
- });
- });
-
- describe('when search query fails', () => {
- beforeEach(() => {
- jest.spyOn(Sentry, 'captureException');
- });
-
- it('captures exception and shows an alert if response is formatted incorrectly', async () => {
- createWrapper({
- requestHandlers: {
- searchUserProjectsAndGroupsQueryHandler: jest.fn().mockResolvedValue({
- data: {},
- }),
- },
- });
- await triggerSearchQuery();
-
- expect(Sentry.captureException).toHaveBeenCalled();
- expect(findAlert().exists()).toBe(true);
- });
-
- it('captures exception and shows an alert if query fails', async () => {
- createWrapper({
- requestHandlers: {
- searchUserProjectsAndGroupsQueryHandler: jest.fn().mockRejectedValue(),
- },
- });
- await triggerSearchQuery();
-
- expect(Sentry.captureException).toHaveBeenCalled();
- expect(findAlert().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js b/spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js
deleted file mode 100644
index c20d3c2745f..00000000000
--- a/spec/frontend/super_sidebar/components/context_switcher_toggle_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { GlIcon } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import ContextSwitcherToggle from '~/super_sidebar/components/context_switcher_toggle.vue';
-
-describe('ContextSwitcherToggle component', () => {
- let wrapper;
-
- const context = {
- id: 1,
- title: 'Title',
- avatar: '/path/to/avatar.png',
- };
-
- const findGlIcon = () => wrapper.getComponent(GlIcon);
-
- const createWrapper = (props = {}) => {
- wrapper = shallowMountExtended(ContextSwitcherToggle, {
- propsData: {
- context,
- expanded: false,
- ...props,
- },
- });
- };
-
- it('renders "chevron-down" icon when not expanded', () => {
- createWrapper();
-
- expect(findGlIcon().props('name')).toBe('chevron-down');
- });
-
- it('renders "chevron-up" icon when expanded', () => {
- createWrapper({
- expanded: true,
- });
-
- expect(findGlIcon().props('name')).toBe('chevron-up');
- });
-});
diff --git a/spec/frontend/super_sidebar/components/create_menu_spec.js b/spec/frontend/super_sidebar/components/create_menu_spec.js
index 510a3f5b913..b967fb18a39 100644
--- a/spec/frontend/super_sidebar/components/create_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/create_menu_spec.js
@@ -1,7 +1,6 @@
import { nextTick } from 'vue';
import {
GlDisclosureDropdown,
- GlTooltip,
GlDisclosureDropdownGroup,
GlDisclosureDropdownItem,
} from '@gitlab/ui';
@@ -9,6 +8,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import { __ } from '~/locale';
import CreateMenu from '~/super_sidebar/components/create_menu.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { createNewMenuGroups } from '../mock_data';
describe('CreateMenu component', () => {
@@ -18,7 +18,6 @@ describe('CreateMenu component', () => {
const findGlDisclosureDropdownGroups = () => wrapper.findAllComponents(GlDisclosureDropdownGroup);
const findGlDisclosureDropdownItems = () => wrapper.findAllComponents(GlDisclosureDropdownItem);
const findInviteMembersTrigger = () => wrapper.findComponent(InviteMembersTrigger);
- const findGlTooltip = () => wrapper.findComponent(GlTooltip);
const createWrapper = ({ provide = {} } = {}) => {
wrapper = shallowMountExtended(CreateMenu, {
@@ -33,6 +32,9 @@ describe('CreateMenu component', () => {
InviteMembersTrigger,
GlDisclosureDropdown,
},
+ directives: {
+ GlTooltip: createMockDirective('gl-tooltip'),
+ },
});
};
@@ -45,7 +47,7 @@ describe('CreateMenu component', () => {
createWrapper();
expect(findGlDisclosureDropdown().props('dropdownOffset')).toEqual({
- crossAxis: -147,
+ crossAxis: -179,
mainAxis: 4,
});
});
@@ -74,16 +76,12 @@ describe('CreateMenu component', () => {
expect(findInviteMembersTrigger().exists()).toBe(true);
});
- it("sets the toggle ID and tooltip's target", () => {
- expect(findGlDisclosureDropdown().props('toggleId')).toBe(wrapper.vm.$options.toggleId);
- expect(findGlTooltip().props('target')).toBe(`#${wrapper.vm.$options.toggleId}`);
- });
-
it('hides the tooltip when the dropdown is opened', async () => {
findGlDisclosureDropdown().vm.$emit('shown');
await nextTick();
- expect(findGlTooltip().exists()).toBe(false);
+ const tooltip = getBinding(findGlDisclosureDropdown().element, 'gl-tooltip');
+ expect(tooltip.value).toBe('');
});
it('shows the tooltip when the dropdown is closed', async () => {
@@ -91,7 +89,8 @@ describe('CreateMenu component', () => {
findGlDisclosureDropdown().vm.$emit('hidden');
await nextTick();
- expect(findGlTooltip().exists()).toBe(true);
+ const tooltip = getBinding(findGlDisclosureDropdown().element, 'gl-tooltip');
+ expect(tooltip.value).toBe('Create new...');
});
});
@@ -99,7 +98,7 @@ describe('CreateMenu component', () => {
createWrapper({ provide: { isImpersonating: true } });
expect(findGlDisclosureDropdown().props('dropdownOffset')).toEqual({
- crossAxis: -115,
+ crossAxis: -147,
mainAxis: 4,
});
});
diff --git a/spec/frontend/super_sidebar/components/flyout_menu_spec.js b/spec/frontend/super_sidebar/components/flyout_menu_spec.js
index b894d29c875..bf24de870d9 100644
--- a/spec/frontend/super_sidebar/components/flyout_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/flyout_menu_spec.js
@@ -1,16 +1,26 @@
-import { shallowMount } from '@vue/test-utils';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import FlyoutMenu from '~/super_sidebar/components/flyout_menu.vue';
jest.mock('@floating-ui/dom');
describe('FlyoutMenu', () => {
let wrapper;
+ let dummySection;
const createComponent = () => {
- wrapper = shallowMount(FlyoutMenu, {
+ dummySection = document.createElement('section');
+ dummySection.addEventListener = jest.fn();
+
+ dummySection.getBoundingClientRect = jest.fn();
+ dummySection.getBoundingClientRect.mockReturnValue({ top: 0, bottom: 5, width: 10 });
+
+ document.querySelector = jest.fn();
+ document.querySelector.mockReturnValue(dummySection);
+
+ wrapper = mountExtended(FlyoutMenu, {
propsData: {
targetId: 'section-1',
- items: [],
+ items: [{ id: 1, title: 'item 1', link: 'https://example.com' }],
},
});
};
diff --git a/spec/frontend/super_sidebar/components/frequent_items_list_spec.js b/spec/frontend/super_sidebar/components/frequent_items_list_spec.js
deleted file mode 100644
index 63dd941974a..00000000000
--- a/spec/frontend/super_sidebar/components/frequent_items_list_spec.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
-import { s__ } from '~/locale';
-import FrequentItemsList from '~/super_sidebar/components//frequent_items_list.vue';
-import ItemsList from '~/super_sidebar/components/items_list.vue';
-import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-import { cachedFrequentProjects } from '../mock_data';
-
-const title = s__('Navigation|FREQUENT PROJECTS');
-const pristineText = s__('Navigation|Projects you visit often will appear here.');
-const storageKey = 'storageKey';
-const maxItems = 5;
-
-describe('FrequentItemsList component', () => {
- useLocalStorageSpy();
-
- let wrapper;
-
- const findListTitle = () => wrapper.findByTestId('list-title');
- const findItemsList = () => wrapper.findComponent(ItemsList);
- const findEmptyText = () => wrapper.findByTestId('empty-text');
- const findRemoveItemButton = () => wrapper.findByTestId('item-remove');
-
- const createWrapperFactory = (mountFn = shallowMountExtended) => () => {
- wrapper = mountFn(FrequentItemsList, {
- propsData: {
- title,
- pristineText,
- storageKey,
- maxItems,
- },
- });
- };
- const createWrapper = createWrapperFactory();
- const createFullWrapper = createWrapperFactory(mountExtended);
-
- describe('default', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it("renders the list's title", () => {
- expect(findListTitle().text()).toBe(title);
- });
-
- it('renders the empty text', () => {
- expect(findEmptyText().exists()).toBe(true);
- expect(findEmptyText().text()).toBe(pristineText);
- });
- });
-
- describe('when there are cached frequent items', () => {
- beforeEach(() => {
- window.localStorage.setItem(storageKey, cachedFrequentProjects);
- createWrapper();
- });
-
- it('attempts to retrieve the items from the local storage', () => {
- expect(window.localStorage.getItem).toHaveBeenCalledTimes(1);
- expect(window.localStorage.getItem).toHaveBeenCalledWith(storageKey);
- });
-
- it('renders the maximum amount of items', () => {
- expect(findItemsList().props('items').length).toBe(maxItems);
- });
-
- it('does not render the empty text slot', () => {
- expect(findEmptyText().exists()).toBe(false);
- });
- });
-
- describe('items editing', () => {
- beforeEach(() => {
- window.localStorage.setItem(storageKey, cachedFrequentProjects);
- createFullWrapper();
- });
-
- it('remove-item event emission from items-list causes list item to be removed', async () => {
- const localStorageProjects = findItemsList().props('items');
- await findRemoveItemButton().trigger('click');
-
- expect(findItemsList().props('items')).toHaveLength(maxItems - 1);
- expect(findItemsList().props('items')).not.toContain(localStorageProjects[0]);
- });
- });
-});
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap b/spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap
index d16d137db2f..e6635672ccf 100644
--- a/spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/__snapshots__/search_item_spec.js.snap
@@ -2,7 +2,7 @@
exports[`SearchItem should render the item 1`] = `
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
>
<gl-avatar-stub
alt="avatar"
@@ -14,33 +14,25 @@ exports[`SearchItem should render the item 1`] = `
size="16"
src="https://www.gravatar.com/avatar/a9638f4ec70148d51e56bf05ad41e993?s=80&d=identicon"
/>
-
- <!---->
-
<span
class="gl-display-flex gl-flex-direction-column"
>
<span
class="gl-text-gray-900"
/>
-
- <!---->
</span>
</div>
`;
exports[`SearchItem should render the item 2`] = `
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
>
- <!---->
-
<gl-icon-stub
class="gl-mr-3"
name="users"
size="16"
/>
-
<span
class="gl-display-flex gl-flex-direction-column"
>
@@ -49,15 +41,13 @@ exports[`SearchItem should render the item 2`] = `
>
Manage &gt; Activity
</span>
-
- <!---->
</span>
</div>
`;
exports[`SearchItem should render the item 3`] = `
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
>
<gl-avatar-stub
alt="avatar"
@@ -69,9 +59,6 @@ exports[`SearchItem should render the item 3`] = `
size="32"
src="/project/avatar/1/avatar.png"
/>
-
- <!---->
-
<span
class="gl-display-flex gl-flex-direction-column"
>
@@ -80,7 +67,6 @@ exports[`SearchItem should render the item 3`] = `
>
MockProject1
</span>
-
<span
class="gl-font-sm gl-text-gray-500"
>
@@ -92,7 +78,7 @@ exports[`SearchItem should render the item 3`] = `
exports[`SearchItem should render the item 4`] = `
<div
- class="gl-display-flex gl-align-items-center"
+ class="gl-align-items-center gl-display-flex"
>
<gl-avatar-stub
alt="avatar"
@@ -104,9 +90,6 @@ exports[`SearchItem should render the item 4`] = `
size="16"
src=""
/>
-
- <!---->
-
<span
class="gl-display-flex gl-flex-direction-column"
>
@@ -115,8 +98,6 @@ exports[`SearchItem should render the item 4`] = `
>
Dismiss Cipher with no integrity
</span>
-
- <!---->
</span>
</div>
`;
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js b/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js
index 85eb7e2e241..7d85dbcbdd3 100644
--- a/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js
@@ -9,6 +9,7 @@ import {
PATH_GROUP_TITLE,
USER_HANDLE,
PATH_HANDLE,
+ PROJECT_HANDLE,
SEARCH_SCOPE,
MAX_ROWS,
} from '~/super_sidebar/components/global_search/command_palette/constants';
@@ -20,6 +21,7 @@ import {
import { getFormattedItem } from '~/super_sidebar/components/global_search/utils';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import { mockTracking } from 'helpers/tracking_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { COMMANDS, LINKS, USERS, FILES } from './mock_data';
@@ -32,7 +34,7 @@ describe('CommandPaletteItems', () => {
const projectFilesPath = 'project/files/path';
const projectBlobPath = '/blob/main';
- const createComponent = (props) => {
+ const createComponent = (props, options = {}) => {
wrapper = shallowMount(CommandPaletteItems, {
propsData: {
handle: COMMAND_HANDLE,
@@ -51,6 +53,7 @@ describe('CommandPaletteItems', () => {
projectFilesPath,
projectBlobPath,
},
+ ...options,
});
};
@@ -227,4 +230,41 @@ describe('CommandPaletteItems', () => {
expect(axios.get).toHaveBeenCalledTimes(1);
});
});
+
+ describe('Tracking', () => {
+ let trackingSpy;
+ let mockAxios;
+
+ beforeEach(() => {
+ trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
+ mockAxios = new MockAdapter(axios);
+ createComponent({ attachTo: document.body });
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ it('tracks event immediately', () => {
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'activate_command_palette', {
+ label: 'command',
+ });
+ });
+
+ it.each`
+ handle | label
+ ${USER_HANDLE} | ${'user'}
+ ${PROJECT_HANDLE} | ${'project'}
+ ${PATH_HANDLE} | ${'path'}
+ `('tracks changing the handle to "$handle"', async ({ handle, label }) => {
+ trackingSpy.mockClear();
+
+ await wrapper.setProps({ handle });
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'activate_command_palette', {
+ label,
+ });
+ });
+ });
});
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js b/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js
index d01e5c85741..25a23433b1e 100644
--- a/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js
@@ -69,24 +69,41 @@ export const TRANSFORMED_LINKS = [
icon: 'users',
keywords: 'Manage',
text: 'Manage',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'item_without_id',
+ 'data-track-extra': '{"title":"Manage"}',
+ },
},
{
href: '/flightjs/Flight/activity',
icon: 'users',
keywords: 'Activity',
text: 'Manage > Activity',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'activity',
+ },
},
{
href: '/flightjs/Flight/-/project_members',
icon: 'users',
keywords: 'Members',
text: 'Manage > Members',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'members',
+ },
},
{
href: '/flightjs/Flight/-/labels',
icon: 'users',
keywords: 'Labels',
text: 'Manage > Labels',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'labels',
+ },
},
];
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js b/spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js
index ebc52e2d910..76768bd8da9 100644
--- a/spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/utils_spec.js
@@ -26,6 +26,10 @@ describe('fileMapper', () => {
icon: 'doc-code',
text: file,
href: `${projectBlobPath}/${file}`,
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'file',
+ },
});
});
});
diff --git a/spec/frontend/super_sidebar/components/global_search/components/global_search_default_places_spec.js b/spec/frontend/super_sidebar/components/global_search/components/global_search_default_places_spec.js
index c6126a348f5..f91c8034fe9 100644
--- a/spec/frontend/super_sidebar/components/global_search/components/global_search_default_places_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_default_places_spec.js
@@ -67,10 +67,26 @@ describe('GlobalSearchDefaultPlaces', () => {
{
text: 'Explore',
href: '/explore',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-extra': '{"title":"Explore"}',
+ 'data-track-label': 'item_without_id',
+ 'data-track-property': 'nav_panel_unknown',
+ 'data-testid': 'places-item-link',
+ 'data-qa-places-item': 'Explore',
+ },
},
{
text: 'Admin area',
href: '/admin',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-extra': '{"title":"Admin area"}',
+ 'data-track-label': 'item_without_id',
+ 'data-track-property': 'nav_panel_unknown',
+ 'data-testid': 'places-item-link',
+ 'data-qa-places-item': 'Admin area',
+ },
},
]);
});
diff --git a/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js b/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js
index f9a6690a391..038c7a96adc 100644
--- a/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_spec.js
@@ -23,7 +23,6 @@ import {
ICON_SUBGROUP,
SCOPE_TOKEN_MAX_LENGTH,
} from '~/super_sidebar/components/global_search/constants';
-import { SEARCH_GITLAB } from '~/vue_shared/global_search/constants';
import { truncate } from '~/lib/utils/text_utility';
import { visitUrl } from '~/lib/utils/url_utility';
import { ENTER_KEY } from '~/lib/utils/keys';
@@ -52,7 +51,7 @@ describe('GlobalSearchModal', () => {
clearAutocomplete: jest.fn(),
};
- const deafaultMockState = {
+ const defaultMockState = {
searchContext: {
project: MOCK_PROJECT,
group: MOCK_GROUP,
@@ -66,15 +65,14 @@ describe('GlobalSearchModal', () => {
};
const createComponent = ({
- initialState = deafaultMockState,
+ initialState = defaultMockState,
mockGetters = defaultMockGetters,
stubs,
- glFeatures = { commandPalette: false },
...mountOptions
} = {}) => {
const store = new Vuex.Store({
state: {
- ...deafaultMockState,
+ ...defaultMockState,
...initialState,
},
actions: actionSpies,
@@ -89,7 +87,6 @@ describe('GlobalSearchModal', () => {
wrapper = shallowMountExtended(GlobalSearchModal, {
store,
stubs,
- provide: { glFeatures },
...mountOptions,
});
};
@@ -271,49 +268,28 @@ describe('GlobalSearchModal', () => {
});
describe('Command palette', () => {
- describe('when FF `command_palette` is disabled', () => {
+ describe.each([...COMMON_HANDLES, PATH_HANDLE])('when search handle is %s', (handle) => {
beforeEach(() => {
- createComponent();
+ createComponent({
+ initialState: { search: handle },
+ });
});
- it('should not render command mode components', () => {
- expect(findCommandPaletteItems().exists()).toBe(false);
- expect(findFakeSearchInput().exists()).toBe(false);
+ it('should render command mode components', () => {
+ expect(findCommandPaletteItems().exists()).toBe(true);
+ expect(findFakeSearchInput().exists()).toBe(true);
});
- it('should provide default placeholder to the search input', () => {
- expect(findGlobalSearchInput().attributes('placeholder')).toBe(SEARCH_GITLAB);
+ it('should provide an alternative placeholder to the search input', () => {
+ expect(findGlobalSearchInput().attributes('placeholder')).toBe(
+ SEARCH_OR_COMMAND_MODE_PLACEHOLDER,
+ );
});
- });
-
- describe.each([...COMMON_HANDLES, PATH_HANDLE])(
- 'when FF `command_palette` is enabled and search handle is %s',
- (handle) => {
- beforeEach(() => {
- createComponent({
- initialState: { search: handle },
- glFeatures: {
- commandPalette: true,
- },
- });
- });
- it('should render command mode components', () => {
- expect(findCommandPaletteItems().exists()).toBe(true);
- expect(findFakeSearchInput().exists()).toBe(true);
- });
-
- it('should provide an alternative placeholder to the search input', () => {
- expect(findGlobalSearchInput().attributes('placeholder')).toBe(
- SEARCH_OR_COMMAND_MODE_PLACEHOLDER,
- );
- });
-
- it('should not render the scope token', () => {
- expect(findScopeToken().exists()).toBe(false);
- });
- },
- );
+ it('should not render the scope token', () => {
+ expect(findScopeToken().exists()).toBe(false);
+ });
+ });
});
});
@@ -373,9 +349,6 @@ describe('GlobalSearchModal', () => {
beforeEach(() => {
createComponent({
initialState: { search: '>' },
- glFeatures: {
- commandPalette: true,
- },
});
submitSearch();
});
diff --git a/spec/frontend/super_sidebar/components/global_search/mock_data.js b/spec/frontend/super_sidebar/components/global_search/mock_data.js
index dfa8b458844..61ddfb6cae1 100644
--- a/spec/frontend/super_sidebar/components/global_search/mock_data.js
+++ b/spec/frontend/super_sidebar/components/global_search/mock_data.js
@@ -109,6 +109,10 @@ export const MOCK_SCOPED_SEARCH_OPTIONS_DEF = [
scopeCategory: PROJECTS_CATEGORY,
icon: ICON_PROJECT,
href: MOCK_PROJECT.path,
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'scoped_in_project',
+ },
},
{
text: 'scoped-in-group',
@@ -116,11 +120,19 @@ export const MOCK_SCOPED_SEARCH_OPTIONS_DEF = [
scopeCategory: GROUPS_CATEGORY,
icon: ICON_GROUP,
href: MOCK_GROUP.path,
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'scoped_in_group',
+ },
},
{
text: 'scoped-in-all',
description: MSG_IN_ALL_GITLAB,
href: MOCK_ALL_PATH,
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'scoped_in_all',
+ },
},
];
export const MOCK_SCOPED_SEARCH_OPTIONS = [
@@ -263,6 +275,10 @@ export const MOCK_GROUPED_AUTOCOMPLETE_OPTIONS = [
avatar_size: 32,
entity_id: 1,
entity_name: 'MockGroup1',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'groups',
+ },
},
],
},
@@ -281,6 +297,10 @@ export const MOCK_GROUPED_AUTOCOMPLETE_OPTIONS = [
avatar_size: 32,
entity_id: 1,
entity_name: 'MockProject1',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'projects',
+ },
},
{
category: 'Projects',
@@ -294,6 +314,10 @@ export const MOCK_GROUPED_AUTOCOMPLETE_OPTIONS = [
avatar_size: 32,
entity_id: 2,
entity_name: 'MockProject2',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'projects',
+ },
},
],
},
@@ -307,6 +331,10 @@ export const MOCK_GROUPED_AUTOCOMPLETE_OPTIONS = [
href: 'help/gitlab',
avatar_size: 16,
entity_name: 'GitLab Help',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'help',
+ },
},
],
},
@@ -325,6 +353,10 @@ export const MOCK_SORTED_AUTOCOMPLETE_OPTIONS = [
avatar_size: 32,
entity_id: 1,
entity_name: 'MockGroup1',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'groups',
+ },
},
{
avatar_size: 32,
@@ -338,6 +370,10 @@ export const MOCK_SORTED_AUTOCOMPLETE_OPTIONS = [
namespace: 'Gitlab Org / MockProject1',
text: 'MockProject1',
value: 'MockProject1',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'projects',
+ },
},
{
avatar_size: 32,
@@ -351,6 +387,10 @@ export const MOCK_SORTED_AUTOCOMPLETE_OPTIONS = [
namespace: 'Gitlab Org / MockProject2',
text: 'MockProject2',
value: 'MockProject2',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'projects',
+ },
},
{
avatar_size: 16,
@@ -359,6 +399,10 @@ export const MOCK_SORTED_AUTOCOMPLETE_OPTIONS = [
label: 'GitLab Help',
text: 'GitLab Help',
href: 'help/gitlab',
+ extraAttrs: {
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': 'help',
+ },
},
];
diff --git a/spec/frontend/super_sidebar/components/global_search/utils_spec.js b/spec/frontend/super_sidebar/components/global_search/utils_spec.js
index 3b12063e733..3c30445e936 100644
--- a/spec/frontend/super_sidebar/components/global_search/utils_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/utils_spec.js
@@ -13,48 +13,58 @@ import {
describe('getFormattedItem', () => {
describe.each`
- item | avatarSize | searchContext | entityId | entityName
- ${{ category: PROJECTS_CATEGORY, label: 'project1' }} | ${LARGE_AVATAR_PX} | ${{ project: { id: 29 } }} | ${29} | ${'project1'}
- ${{ category: GROUPS_CATEGORY, label: 'project1' }} | ${LARGE_AVATAR_PX} | ${{ group: { id: 12 } }} | ${12} | ${'project1'}
- ${{ category: 'Help', label: 'project1' }} | ${SMALL_AVATAR_PX} | ${null} | ${undefined} | ${'project1'}
- ${{ category: 'Settings', label: 'project1' }} | ${SMALL_AVATAR_PX} | ${null} | ${undefined} | ${'project1'}
- ${{ category: GROUPS_CATEGORY, value: 'group1', label: 'Group 1' }} | ${LARGE_AVATAR_PX} | ${{ group: { id: 1, name: 'test1' } }} | ${1} | ${'group1'}
- ${{ category: PROJECTS_CATEGORY, value: 'group2', label: 'Group2' }} | ${LARGE_AVATAR_PX} | ${{ project: { id: 2, name: 'test2' } }} | ${2} | ${'group2'}
- ${{ category: ISSUES_CATEGORY }} | ${SMALL_AVATAR_PX} | ${{ project: { id: 3, name: 'test3' } }} | ${3} | ${'test3'}
- ${{ category: MERGE_REQUEST_CATEGORY }} | ${SMALL_AVATAR_PX} | ${{ project: { id: 4, name: 'test4' } }} | ${4} | ${'test4'}
- ${{ category: RECENT_EPICS_CATEGORY }} | ${SMALL_AVATAR_PX} | ${{ group: { id: 5, name: 'test5' } }} | ${5} | ${'test5'}
- ${{ category: GROUPS_CATEGORY, group_id: 6, group_name: 'test6' }} | ${LARGE_AVATAR_PX} | ${null} | ${6} | ${'test6'}
- ${{ category: PROJECTS_CATEGORY, project_id: 7, project_name: 'test7' }} | ${LARGE_AVATAR_PX} | ${null} | ${7} | ${'test7'}
- ${{ category: ISSUES_CATEGORY, project_id: 8, project_name: 'test8' }} | ${SMALL_AVATAR_PX} | ${null} | ${8} | ${'test8'}
- ${{ category: MERGE_REQUEST_CATEGORY, project_id: 9, project_name: 'test9' }} | ${SMALL_AVATAR_PX} | ${null} | ${9} | ${'test9'}
- ${{ category: RECENT_EPICS_CATEGORY, group_id: 10, group_name: 'test10' }} | ${SMALL_AVATAR_PX} | ${null} | ${10} | ${'test10'}
- ${{ category: GROUPS_CATEGORY, group_id: 11, group_name: 'test11' }} | ${LARGE_AVATAR_PX} | ${{ group: { id: 1, name: 'test1' } }} | ${11} | ${'test11'}
- ${{ category: PROJECTS_CATEGORY, project_id: 12, project_name: 'test12' }} | ${LARGE_AVATAR_PX} | ${{ project: { id: 2, name: 'test2' } }} | ${12} | ${'test12'}
- ${{ category: ISSUES_CATEGORY, project_id: 13, project_name: 'test13' }} | ${SMALL_AVATAR_PX} | ${{ project: { id: 3, name: 'test3' } }} | ${13} | ${'test13'}
- ${{ category: MERGE_REQUEST_CATEGORY, project_id: 14, project_name: 'test14' }} | ${SMALL_AVATAR_PX} | ${{ project: { id: 4, name: 'test4' } }} | ${14} | ${'test14'}
- ${{ category: RECENT_EPICS_CATEGORY, group_id: 15, group_name: 'test15' }} | ${SMALL_AVATAR_PX} | ${{ group: { id: 5, name: 'test5' } }} | ${15} | ${'test15'}
- `('formats the item', ({ item, avatarSize, searchContext, entityId, entityName }) => {
- describe(`when item is ${JSON.stringify(item)}`, () => {
- let formattedItem;
- beforeEach(() => {
- formattedItem = getFormattedItem(item, searchContext);
- });
+ item | avatarSize | searchContext | entityId | entityName | trackingLabel
+ ${{ category: PROJECTS_CATEGORY, label: 'project1' }} | ${LARGE_AVATAR_PX} | ${{ project: { id: 29 } }} | ${29} | ${'project1'} | ${'projects'}
+ ${{ category: GROUPS_CATEGORY, label: 'project1' }} | ${LARGE_AVATAR_PX} | ${{ group: { id: 12 } }} | ${12} | ${'project1'} | ${'groups'}
+ ${{ category: 'Help', label: 'project1' }} | ${SMALL_AVATAR_PX} | ${null} | ${undefined} | ${'project1'} | ${'help'}
+ ${{ category: 'Settings', label: 'project1' }} | ${SMALL_AVATAR_PX} | ${null} | ${undefined} | ${'project1'} | ${'settings'}
+ ${{ category: GROUPS_CATEGORY, value: 'group1', label: 'Group 1' }} | ${LARGE_AVATAR_PX} | ${{ group: { id: 1, name: 'test1' } }} | ${1} | ${'group1'} | ${'groups'}
+ ${{ category: PROJECTS_CATEGORY, value: 'group2', label: 'Group2' }} | ${LARGE_AVATAR_PX} | ${{ project: { id: 2, name: 'test2' } }} | ${2} | ${'group2'} | ${'projects'}
+ ${{ category: ISSUES_CATEGORY }} | ${SMALL_AVATAR_PX} | ${{ project: { id: 3, name: 'test3' } }} | ${3} | ${'test3'} | ${'recent_issues'}
+ ${{ category: MERGE_REQUEST_CATEGORY }} | ${SMALL_AVATAR_PX} | ${{ project: { id: 4, name: 'test4' } }} | ${4} | ${'test4'} | ${'recent_merge_requests'}
+ ${{ category: RECENT_EPICS_CATEGORY }} | ${SMALL_AVATAR_PX} | ${{ group: { id: 5, name: 'test5' } }} | ${5} | ${'test5'} | ${'recent_epics'}
+ ${{ category: GROUPS_CATEGORY, group_id: 6, group_name: 'test6' }} | ${LARGE_AVATAR_PX} | ${null} | ${6} | ${'test6'} | ${'groups'}
+ ${{ category: PROJECTS_CATEGORY, project_id: 7, project_name: 'test7' }} | ${LARGE_AVATAR_PX} | ${null} | ${7} | ${'test7'} | ${'projects'}
+ ${{ category: ISSUES_CATEGORY, project_id: 8, project_name: 'test8' }} | ${SMALL_AVATAR_PX} | ${null} | ${8} | ${'test8'} | ${'recent_issues'}
+ ${{ category: MERGE_REQUEST_CATEGORY, project_id: 9, project_name: 'test9' }} | ${SMALL_AVATAR_PX} | ${null} | ${9} | ${'test9'} | ${'recent_merge_requests'}
+ ${{ category: RECENT_EPICS_CATEGORY, group_id: 10, group_name: 'test10' }} | ${SMALL_AVATAR_PX} | ${null} | ${10} | ${'test10'} | ${'recent_epics'}
+ ${{ category: GROUPS_CATEGORY, group_id: 11, group_name: 'test11' }} | ${LARGE_AVATAR_PX} | ${{ group: { id: 1, name: 'test1' } }} | ${11} | ${'test11'} | ${'groups'}
+ ${{ category: PROJECTS_CATEGORY, project_id: 12, project_name: 'test12' }} | ${LARGE_AVATAR_PX} | ${{ project: { id: 2, name: 'test2' } }} | ${12} | ${'test12'} | ${'projects'}
+ ${{ category: ISSUES_CATEGORY, project_id: 13, project_name: 'test13' }} | ${SMALL_AVATAR_PX} | ${{ project: { id: 3, name: 'test3' } }} | ${13} | ${'test13'} | ${'recent_issues'}
+ ${{ category: MERGE_REQUEST_CATEGORY, project_id: 14, project_name: 'test14' }} | ${SMALL_AVATAR_PX} | ${{ project: { id: 4, name: 'test4' } }} | ${14} | ${'test14'} | ${'recent_merge_requests'}
+ ${{ category: RECENT_EPICS_CATEGORY, group_id: 15, group_name: 'test15' }} | ${SMALL_AVATAR_PX} | ${{ group: { id: 5, name: 'test5' } }} | ${15} | ${'test15'} | ${'recent_epics'}
+ `(
+ 'formats the item',
+ ({ item, avatarSize, searchContext, entityId, entityName, trackingLabel }) => {
+ describe(`when item is ${JSON.stringify(item)}`, () => {
+ let formattedItem;
+ beforeEach(() => {
+ formattedItem = getFormattedItem(item, searchContext);
+ });
- it(`should set text to ${item.value || item.label}`, () => {
- expect(formattedItem.text).toBe(item.value || item.label);
- });
+ it(`should set text to ${item.value || item.label}`, () => {
+ expect(formattedItem.text).toBe(item.value || item.label);
+ });
- it(`should set avatarSize to ${avatarSize}`, () => {
- expect(formattedItem.avatar_size).toBe(avatarSize);
- });
+ it(`should set avatarSize to ${avatarSize}`, () => {
+ expect(formattedItem.avatar_size).toBe(avatarSize);
+ });
- it(`should set avatar entityId to ${entityId}`, () => {
- expect(formattedItem.entity_id).toBe(entityId);
- });
+ it(`should set avatar entityId to ${entityId}`, () => {
+ expect(formattedItem.entity_id).toBe(entityId);
+ });
+
+ it(`should set avatar entityName to ${entityName}`, () => {
+ expect(formattedItem.entity_name).toBe(entityName);
+ });
- it(`should set avatar entityName to ${entityName}`, () => {
- expect(formattedItem.entity_name).toBe(entityName);
+ it('should add tracking label', () => {
+ expect(formattedItem.extraAttrs).toEqual({
+ 'data-track-action': 'click_command_palette_item',
+ 'data-track-label': trackingLabel,
+ });
+ });
});
- });
- });
+ },
+ );
});
diff --git a/spec/frontend/super_sidebar/components/groups_list_spec.js b/spec/frontend/super_sidebar/components/groups_list_spec.js
deleted file mode 100644
index 4fa3303c12f..00000000000
--- a/spec/frontend/super_sidebar/components/groups_list_spec.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { s__ } from '~/locale';
-import GroupsList from '~/super_sidebar/components/groups_list.vue';
-import SearchResults from '~/super_sidebar/components/search_results.vue';
-import FrequentItemsList from '~/super_sidebar/components/frequent_items_list.vue';
-import NavItem from '~/super_sidebar/components/nav_item.vue';
-import { MAX_FREQUENT_GROUPS_COUNT } from '~/super_sidebar/constants';
-
-const username = 'root';
-const viewAllLink = '/path/to/groups';
-const storageKey = `${username}/frequent-groups`;
-
-describe('GroupsList component', () => {
- let wrapper;
-
- const findSearchResults = () => wrapper.findComponent(SearchResults);
- const findFrequentItemsList = () => wrapper.findComponent(FrequentItemsList);
- const findViewAllLink = () => wrapper.findComponent(NavItem);
-
- const itRendersViewAllItem = () => {
- it('renders the "View all..." item', () => {
- const link = findViewAllLink();
-
- expect(link.props('item')).toEqual({
- icon: 'group',
- link: viewAllLink,
- title: s__('Navigation|View all your groups'),
- });
- expect(link.props('linkClasses')).toEqual({ 'dashboard-shortcuts-groups': true });
- });
- };
-
- const createWrapper = (props = {}) => {
- wrapper = shallowMountExtended(GroupsList, {
- propsData: {
- username,
- viewAllLink,
- ...props,
- },
- });
- };
-
- describe('when displaying search results', () => {
- const searchResults = ['A search result'];
-
- beforeEach(() => {
- createWrapper({
- isSearch: true,
- searchResults,
- });
- });
-
- it('renders the search results component', () => {
- expect(findSearchResults().exists()).toBe(true);
- expect(findFrequentItemsList().exists()).toBe(false);
- });
-
- it('passes the correct props to the search results component', () => {
- expect(findSearchResults().props()).toEqual({
- title: s__('Navigation|Groups'),
- noResultsText: s__('Navigation|No group matches found'),
- searchResults,
- });
- });
-
- itRendersViewAllItem();
- });
-
- describe('when displaying frequent groups', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('renders the frequent items list', () => {
- expect(findFrequentItemsList().exists()).toBe(true);
- expect(findSearchResults().exists()).toBe(false);
- });
-
- it('passes the correct props to the frequent items list', () => {
- expect(findFrequentItemsList().props()).toEqual({
- title: s__('Navigation|Frequently visited groups'),
- storageKey,
- maxItems: MAX_FREQUENT_GROUPS_COUNT,
- pristineText: s__('Navigation|Groups you visit often will appear here.'),
- });
- });
-
- itRendersViewAllItem();
- });
-});
diff --git a/spec/frontend/super_sidebar/components/items_list_spec.js b/spec/frontend/super_sidebar/components/items_list_spec.js
deleted file mode 100644
index 8e00984f500..00000000000
--- a/spec/frontend/super_sidebar/components/items_list_spec.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import ItemsList from '~/super_sidebar/components/items_list.vue';
-import NavItem from '~/super_sidebar/components/nav_item.vue';
-import { cachedFrequentProjects } from '../mock_data';
-
-const mockItems = JSON.parse(cachedFrequentProjects);
-const [firstMockedProject] = mockItems;
-
-describe('ItemsList component', () => {
- let wrapper;
-
- const findNavItems = () => wrapper.findAllComponents(NavItem);
-
- const createWrapper = ({ props = {}, slots = {} } = {}) => {
- wrapper = shallowMountExtended(ItemsList, {
- propsData: {
- ...props,
- },
- slots,
- });
- };
-
- it('does not render nav items when there are no items', () => {
- createWrapper();
-
- expect(findNavItems().length).toBe(0);
- });
-
- it('renders one nav item per item', () => {
- createWrapper({
- props: {
- items: mockItems,
- },
- });
-
- expect(findNavItems().length).not.toBe(0);
- expect(findNavItems().length).toBe(mockItems.length);
- });
-
- it('passes the correct props to the nav items', () => {
- createWrapper({
- props: {
- items: mockItems,
- },
- });
- const firstNavItem = findNavItems().at(0);
-
- expect(firstNavItem.props('item')).toEqual(firstMockedProject);
- });
-
- it('renders the `view-all-items` slot', () => {
- const testId = 'view-all-items';
- createWrapper({
- slots: {
- 'view-all-items': {
- template: `<div data-testid="${testId}" />`,
- },
- },
- });
-
- expect(wrapper.findByTestId(testId).exists()).toBe(true);
- });
-});
diff --git a/spec/frontend/super_sidebar/components/menu_section_spec.js b/spec/frontend/super_sidebar/components/menu_section_spec.js
index 288e317d4c6..e76bb699301 100644
--- a/spec/frontend/super_sidebar/components/menu_section_spec.js
+++ b/spec/frontend/super_sidebar/components/menu_section_spec.js
@@ -79,39 +79,55 @@ describe('MenuSection component', () => {
});
describe('when hasFlyout is true', () => {
- it('is rendered', () => {
+ it('is not yet rendered', () => {
createWrapper({ title: 'Asdf' }, { 'has-flyout': true });
- expect(findFlyout().exists()).toBe(true);
+ expect(findFlyout().exists()).toBe(false);
});
describe('on mouse hover', () => {
describe('when section is expanded', () => {
- it('is not shown', async () => {
+ it('is not rendered', async () => {
createWrapper({ title: 'Asdf' }, { 'has-flyout': true, expanded: true });
await findButton().trigger('pointerover', { pointerType: 'mouse' });
- expect(findFlyout().isVisible()).toBe(false);
+ expect(findFlyout().exists()).toBe(false);
});
});
describe('when section is not expanded', () => {
- it('is shown', async () => {
- createWrapper({ title: 'Asdf' }, { 'has-flyout': true, expanded: false });
- await findButton().trigger('pointerover', { pointerType: 'mouse' });
- expect(findFlyout().isVisible()).toBe(true);
+ describe('when section has no items', () => {
+ it('is not rendered', async () => {
+ createWrapper({ title: 'Asdf' }, { 'has-flyout': true, expanded: false });
+ await findButton().trigger('pointerover', { pointerType: 'mouse' });
+ expect(findFlyout().exists()).toBe(false);
+ });
+ });
+
+ describe('when section has items', () => {
+ it('is rendered and shown', async () => {
+ createWrapper(
+ { title: 'Asdf', items: [{ title: 'Item1', href: '/item1' }] },
+ { 'has-flyout': true, expanded: false },
+ );
+ await findButton().trigger('pointerover', { pointerType: 'mouse' });
+ expect(findFlyout().isVisible()).toBe(true);
+ });
});
});
});
describe('when section gets closed', () => {
beforeEach(async () => {
- createWrapper({ title: 'Asdf' }, { expanded: true, 'has-flyout': true });
+ createWrapper(
+ { title: 'Asdf', items: [{ title: 'Item1', href: '/item1' }] },
+ { expanded: true, 'has-flyout': true },
+ );
await findButton().trigger('click');
await findButton().trigger('pointerover', { pointerType: 'mouse' });
});
it('shows the flyout only after section title gets hovered out and in again', async () => {
expect(findCollapse().props('visible')).toBe(false);
- expect(findFlyout().isVisible()).toBe(false);
+ expect(findFlyout().exists()).toBe(false);
await findButton().trigger('pointerleave');
await findButton().trigger('pointerover', { pointerType: 'mouse' });
diff --git a/spec/frontend/super_sidebar/components/nav_item_spec.js b/spec/frontend/super_sidebar/components/nav_item_spec.js
index f41f6954ed1..89d774c4b43 100644
--- a/spec/frontend/super_sidebar/components/nav_item_spec.js
+++ b/spec/frontend/super_sidebar/components/nav_item_spec.js
@@ -1,5 +1,6 @@
-import { GlBadge } from '@gitlab/ui';
+import { GlBadge, GlButton, GlAvatar } from '@gitlab/ui';
import { RouterLinkStub } from '@vue/test-utils';
+import { nextTick } from 'vue';
import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper';
import NavItem from '~/super_sidebar/components/nav_item.vue';
import NavItemRouterLink from '~/super_sidebar/components/nav_item_router_link.vue';
@@ -13,8 +14,10 @@ import {
describe('NavItem component', () => {
let wrapper;
+ const findAvatar = () => wrapper.findComponent(GlAvatar);
const findLink = () => wrapper.findByTestId('nav-item-link');
const findPill = () => wrapper.findComponent(GlBadge);
+ const findPinButton = () => wrapper.findComponent(GlButton);
const findNavItemRouterLink = () => extendedWrapper(wrapper.findComponent(NavItemRouterLink));
const findNavItemLink = () => extendedWrapper(wrapper.findComponent(NavItemLink));
@@ -59,6 +62,66 @@ describe('NavItem component', () => {
);
});
+ describe('pins', () => {
+ describe('when pins are not supported', () => {
+ it('does not render pin button', () => {
+ createWrapper({
+ item: { title: 'Foo' },
+ provide: {
+ panelSupportsPins: false,
+ },
+ });
+
+ expect(findPinButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when pins are supported', () => {
+ beforeEach(() => {
+ createWrapper({
+ item: { title: 'Foo' },
+ provide: {
+ panelSupportsPins: true,
+ },
+ });
+ });
+
+ it('renders pin button', () => {
+ expect(findPinButton().exists()).toBe(true);
+ });
+
+ it('contains an aria-label', () => {
+ expect(findPinButton().attributes('aria-label')).toBe('Pin Foo');
+ });
+
+ it('toggles pointer events on after CSS fade-in', async () => {
+ const pinButton = findPinButton();
+
+ expect(pinButton.classes()).toContain('gl-pointer-events-none');
+
+ wrapper.trigger('mouseenter');
+ pinButton.vm.$emit('transitionend');
+ await nextTick();
+
+ expect(pinButton.classes()).not.toContain('gl-pointer-events-none');
+ });
+
+ it('does not toggle pointer events if mouse leaves before CSS fade-in ends', async () => {
+ const pinButton = findPinButton();
+
+ expect(pinButton.classes()).toContain('gl-pointer-events-none');
+
+ wrapper.trigger('mouseenter');
+ wrapper.trigger('mousemove');
+ wrapper.trigger('mouseleave');
+ pinButton.vm.$emit('transitionend');
+ await nextTick();
+
+ expect(pinButton.classes()).toContain('gl-pointer-events-none');
+ });
+ });
+ });
+
it('applies custom link classes', () => {
const customClass = 'customClass';
createWrapper({
@@ -153,4 +216,36 @@ describe('NavItem component', () => {
});
});
});
+
+ describe('when `item` prop has `entity_id` attribute', () => {
+ it('renders an avatar', () => {
+ createWrapper({
+ item: { title: 'Foo', entity_id: 123, avatar: '/avatar.png', avatar_shape: 'circle' },
+ });
+
+ expect(findAvatar().props()).toMatchObject({
+ entityId: 123,
+ shape: 'circle',
+ src: '/avatar.png',
+ });
+ });
+ });
+
+ describe('when `item.is_active` is true', () => {
+ it('scrolls into view', () => {
+ createWrapper({
+ item: { is_active: true },
+ });
+ expect(wrapper.element.scrollIntoView).toHaveBeenNthCalledWith(1, false);
+ });
+ });
+
+ describe('when `item.is_active` is false', () => {
+ it('scrolls not into view', () => {
+ createWrapper({
+ item: { is_active: false },
+ });
+ expect(wrapper.element.scrollIntoView).not.toHaveBeenCalled();
+ });
+ });
});
diff --git a/spec/frontend/super_sidebar/components/pinned_section_spec.js b/spec/frontend/super_sidebar/components/pinned_section_spec.js
index 00cc7cf29c9..fe1653f1177 100644
--- a/spec/frontend/super_sidebar/components/pinned_section_spec.js
+++ b/spec/frontend/super_sidebar/components/pinned_section_spec.js
@@ -87,4 +87,33 @@ describe('PinnedSection component', () => {
});
});
});
+
+ describe('ambiguous settings names', () => {
+ it('get renamed to be unambiguous', () => {
+ createWrapper({
+ items: [
+ { title: 'CI/CD', id: 'ci_cd' },
+ { title: 'Merge requests', id: 'merge_request_settings' },
+ { title: 'Monitor', id: 'monitor' },
+ { title: 'Repository', id: 'repository' },
+ { title: 'Repository', id: 'code' },
+ { title: 'Something else', id: 'not_a_setting' },
+ ],
+ });
+
+ expect(
+ wrapper
+ .findComponent(MenuSection)
+ .props('item')
+ .items.map((i) => i.title),
+ ).toEqual([
+ 'CI/CD settings',
+ 'Merge requests settings',
+ 'Monitor settings',
+ 'Repository settings',
+ 'Repository',
+ 'Something else',
+ ]);
+ });
+ });
});
diff --git a/spec/frontend/super_sidebar/components/projects_list_spec.js b/spec/frontend/super_sidebar/components/projects_list_spec.js
deleted file mode 100644
index 93a414e1e8c..00000000000
--- a/spec/frontend/super_sidebar/components/projects_list_spec.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { s__ } from '~/locale';
-import ProjectsList from '~/super_sidebar/components/projects_list.vue';
-import SearchResults from '~/super_sidebar/components/search_results.vue';
-import FrequentItemsList from '~/super_sidebar/components/frequent_items_list.vue';
-import NavItem from '~/super_sidebar/components/nav_item.vue';
-import { MAX_FREQUENT_PROJECTS_COUNT } from '~/super_sidebar/constants';
-
-const username = 'root';
-const viewAllLink = '/path/to/projects';
-const storageKey = `${username}/frequent-projects`;
-
-describe('ProjectsList component', () => {
- let wrapper;
-
- const findSearchResults = () => wrapper.findComponent(SearchResults);
- const findFrequentItemsList = () => wrapper.findComponent(FrequentItemsList);
- const findViewAllLink = () => wrapper.findComponent(NavItem);
-
- const itRendersViewAllItem = () => {
- it('renders the "View all..." item', () => {
- const link = findViewAllLink();
-
- expect(link.props('item')).toEqual({
- icon: 'project',
- link: viewAllLink,
- title: s__('Navigation|View all your projects'),
- });
- expect(link.props('linkClasses')).toEqual({ 'dashboard-shortcuts-projects': true });
- });
- };
-
- const createWrapper = (props = {}) => {
- wrapper = shallowMountExtended(ProjectsList, {
- propsData: {
- username,
- viewAllLink,
- ...props,
- },
- });
- };
-
- describe('when displaying search results', () => {
- const searchResults = ['A search result'];
-
- beforeEach(() => {
- createWrapper({
- isSearch: true,
- searchResults,
- });
- });
-
- it('renders the search results component', () => {
- expect(findSearchResults().exists()).toBe(true);
- expect(findFrequentItemsList().exists()).toBe(false);
- });
-
- it('passes the correct props to the search results component', () => {
- expect(findSearchResults().props()).toEqual({
- title: s__('Navigation|Projects'),
- noResultsText: s__('Navigation|No project matches found'),
- searchResults,
- });
- });
-
- itRendersViewAllItem();
- });
-
- describe('when displaying frequent projects', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it('passes the correct props to the frequent items list', () => {
- expect(findFrequentItemsList().props()).toEqual({
- title: s__('Navigation|Frequently visited projects'),
- storageKey,
- maxItems: MAX_FREQUENT_PROJECTS_COUNT,
- pristineText: s__('Navigation|Projects you visit often will appear here.'),
- });
- });
-
- itRendersViewAllItem();
- });
-});
diff --git a/spec/frontend/super_sidebar/components/search_results_spec.js b/spec/frontend/super_sidebar/components/search_results_spec.js
deleted file mode 100644
index daec5c2a9b4..00000000000
--- a/spec/frontend/super_sidebar/components/search_results_spec.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import { GlCollapse } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { s__ } from '~/locale';
-import SearchResults from '~/super_sidebar/components/search_results.vue';
-import ItemsList from '~/super_sidebar/components/items_list.vue';
-import { stubComponent } from 'helpers/stub_component';
-
-const title = s__('Navigation|PROJECTS');
-const noResultsText = s__('Navigation|No project matches found');
-
-describe('SearchResults component', () => {
- let wrapper;
-
- const findSearchResultsToggle = () => wrapper.findByTestId('search-results-toggle');
- const findCollapsibleSection = () => wrapper.findComponent(GlCollapse);
- const findItemsList = () => wrapper.findComponent(ItemsList);
- const findEmptyText = () => wrapper.findByTestId('empty-text');
-
- const createWrapper = ({ props = {} } = {}) => {
- wrapper = shallowMountExtended(SearchResults, {
- propsData: {
- title,
- noResultsText,
- ...props,
- },
- stubs: {
- GlCollapse: stubComponent(GlCollapse, {
- props: ['visible'],
- }),
- },
- });
- };
-
- describe('default state', () => {
- beforeEach(() => {
- createWrapper();
- });
-
- it("renders the list's title", () => {
- expect(findSearchResultsToggle().text()).toBe(title);
- });
-
- it('is expanded', () => {
- expect(findCollapsibleSection().props('visible')).toBe(true);
- });
-
- it('renders the empty text', () => {
- expect(findEmptyText().exists()).toBe(true);
- expect(findEmptyText().text()).toBe(noResultsText);
- });
- });
-
- describe('when displaying search results', () => {
- it('shows search results', () => {
- const searchResults = [{ id: 1 }];
- createWrapper({ props: { isSearch: true, searchResults } });
-
- expect(findItemsList().props('items')[0]).toEqual(searchResults[0]);
- });
-
- it('shows the no results text if search results are empty', () => {
- const searchResults = [];
- createWrapper({ props: { isSearch: true, searchResults } });
-
- expect(findItemsList().props('items').length).toEqual(0);
- expect(findEmptyText().text()).toBe(noResultsText);
- });
- });
-});
diff --git a/spec/frontend/super_sidebar/components/sidebar_hover_peek_behavior_spec.js b/spec/frontend/super_sidebar/components/sidebar_hover_peek_behavior_spec.js
new file mode 100644
index 00000000000..75b834ee7c9
--- /dev/null
+++ b/spec/frontend/super_sidebar/components/sidebar_hover_peek_behavior_spec.js
@@ -0,0 +1,213 @@
+import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import {
+ SUPER_SIDEBAR_PEEK_OPEN_DELAY,
+ SUPER_SIDEBAR_PEEK_CLOSE_DELAY,
+ JS_TOGGLE_EXPAND_CLASS,
+ SUPER_SIDEBAR_PEEK_STATE_CLOSED as STATE_CLOSED,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_OPEN as STATE_WILL_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_OPEN as STATE_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_CLOSE as STATE_WILL_CLOSE,
+} from '~/super_sidebar/constants';
+import SidebarHoverPeek from '~/super_sidebar/components/sidebar_hover_peek_behavior.vue';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { moveMouse, mouseEnter, mouseLeave, moveMouseOutOfDocument } from '../mocks';
+
+// This is measured at runtime in the browser, but statically defined here
+// since Jest does not do layout/styling.
+const X_SIDEBAR_EDGE = 10;
+
+jest.mock('~/lib/utils/css_utils', () => ({
+ getCssClassDimensions: () => ({ width: X_SIDEBAR_EDGE }),
+}));
+
+describe('SidebarHoverPeek component', () => {
+ let wrapper;
+ let toggle;
+ let trackingSpy = null;
+
+ const createComponent = (props = { isMouseOverSidebar: false }) => {
+ wrapper = mount(SidebarHoverPeek, {
+ propsData: props,
+ });
+
+ return nextTick();
+ };
+
+ const lastNChangeEvents = (n = 1) => wrapper.emitted('change').slice(-n).flat();
+
+ beforeEach(() => {
+ toggle = document.createElement('button');
+ toggle.classList.add(JS_TOGGLE_EXPAND_CLASS);
+ document.body.appendChild(toggle);
+ trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ // We destroy the wrapper ourselves as that needs to happen before the toggle is removed.
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
+ wrapper.destroy();
+ toggle?.remove();
+ });
+
+ it('begins in the closed state', async () => {
+ await createComponent();
+
+ expect(lastNChangeEvents(Infinity)).toEqual([STATE_CLOSED]);
+ });
+
+ describe('when mouse enters the toggle', () => {
+ beforeEach(async () => {
+ await createComponent();
+ mouseEnter(toggle);
+ });
+
+ it('does not emit duplicate events in a region', () => {
+ mouseEnter(toggle);
+
+ expect(lastNChangeEvents(Infinity)).toEqual([STATE_CLOSED, STATE_WILL_OPEN]);
+ });
+
+ it('transitions to will-open when hovering the toggle', () => {
+ expect(lastNChangeEvents(1)).toEqual([STATE_WILL_OPEN]);
+ });
+
+ describe('when transitioning away from the will-open state', () => {
+ beforeEach(() => {
+ jest.advanceTimersByTime(SUPER_SIDEBAR_PEEK_OPEN_DELAY - 1);
+ });
+
+ it('transitions to open after delay', () => {
+ expect(lastNChangeEvents(1)).toEqual([STATE_WILL_OPEN]);
+
+ jest.advanceTimersByTime(1);
+
+ expect(lastNChangeEvents(2)).toEqual([STATE_WILL_OPEN, STATE_OPEN]);
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'nav_hover_peek', {
+ label: 'nav_sidebar_toggle',
+ property: 'nav_sidebar',
+ });
+ });
+
+ it('cancels transition to open if mouse out of toggle', () => {
+ mouseLeave(toggle);
+ jest.runOnlyPendingTimers();
+
+ expect(lastNChangeEvents(3)).toEqual([STATE_WILL_OPEN, STATE_WILL_CLOSE, STATE_CLOSED]);
+ });
+
+ it('transitions to closed if cursor leaves document', () => {
+ moveMouseOutOfDocument();
+
+ expect(lastNChangeEvents(2)).toEqual([STATE_WILL_OPEN, STATE_CLOSED]);
+ });
+ });
+
+ describe('when transitioning away from the will-close state', () => {
+ beforeEach(() => {
+ jest.runOnlyPendingTimers();
+ moveMouse(X_SIDEBAR_EDGE);
+ jest.advanceTimersByTime(SUPER_SIDEBAR_PEEK_CLOSE_DELAY - 1);
+ });
+
+ it('transitions to closed after delay', () => {
+ expect(lastNChangeEvents(1)).toEqual([STATE_WILL_CLOSE]);
+
+ jest.advanceTimersByTime(1);
+
+ expect(lastNChangeEvents(2)).toEqual([STATE_WILL_CLOSE, STATE_CLOSED]);
+ });
+
+ it('cancels transition to close if mouse moves back to toggle', () => {
+ expect(lastNChangeEvents(1)).toEqual([STATE_WILL_CLOSE]);
+
+ mouseEnter(toggle);
+ jest.runOnlyPendingTimers();
+
+ expect(lastNChangeEvents(4)).toEqual([
+ STATE_OPEN,
+ STATE_WILL_CLOSE,
+ STATE_WILL_OPEN,
+ STATE_OPEN,
+ ]);
+ });
+ });
+
+ describe('when transitioning away from the open state', () => {
+ beforeEach(() => {
+ jest.runOnlyPendingTimers();
+ });
+
+ it('transitions to will-close if mouse out of sidebar region', () => {
+ expect(lastNChangeEvents(1)).toEqual([STATE_OPEN]);
+
+ moveMouse(X_SIDEBAR_EDGE);
+
+ expect(lastNChangeEvents(2)).toEqual([STATE_OPEN, STATE_WILL_CLOSE]);
+ });
+
+ it('transitions to will-close if cursor leaves document', () => {
+ moveMouseOutOfDocument();
+
+ expect(lastNChangeEvents(2)).toEqual([STATE_OPEN, STATE_WILL_CLOSE]);
+ });
+ });
+
+ it('cleans up its mouseleave listener before destroy', () => {
+ jest.runOnlyPendingTimers();
+
+ expect(lastNChangeEvents(1)).toEqual([STATE_OPEN]);
+
+ wrapper.destroy();
+ mouseLeave(toggle);
+
+ expect(lastNChangeEvents(1)).toEqual([STATE_OPEN]);
+ });
+
+ it('cleans up its timers before destroy', () => {
+ wrapper.destroy();
+ jest.runOnlyPendingTimers();
+
+ expect(lastNChangeEvents(1)).toEqual([STATE_WILL_OPEN]);
+ });
+
+ it('cleans up document mouseleave listener before destroy', () => {
+ mouseEnter(toggle);
+
+ wrapper.destroy();
+
+ moveMouseOutOfDocument();
+
+ expect(lastNChangeEvents(1)).not.toEqual([STATE_CLOSED]);
+ });
+ });
+
+ describe('when mouse is over sidebar child element', () => {
+ beforeEach(async () => {
+ await createComponent({ isMouseOverSidebar: true });
+ });
+
+ it('does not transition to will-close or closed when mouse is over sidebar child element', () => {
+ mouseEnter(toggle);
+ jest.runOnlyPendingTimers();
+ mouseLeave(toggle);
+
+ expect(lastNChangeEvents(1)).toEqual([STATE_OPEN]);
+ });
+ });
+
+ it('cleans up its mouseenter listener before destroy', async () => {
+ await createComponent();
+
+ mouseLeave(toggle);
+ jest.runOnlyPendingTimers();
+
+ expect(lastNChangeEvents(1)).toEqual([STATE_CLOSED]);
+
+ wrapper.destroy();
+ mouseEnter(toggle);
+
+ expect(lastNChangeEvents(1)).toEqual([STATE_CLOSED]);
+ });
+});
diff --git a/spec/frontend/super_sidebar/components/sidebar_menu_spec.js b/spec/frontend/super_sidebar/components/sidebar_menu_spec.js
index 5d9a35fbf70..c85a6609e6f 100644
--- a/spec/frontend/super_sidebar/components/sidebar_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/sidebar_menu_spec.js
@@ -16,13 +16,8 @@ const menuItems = [
describe('Sidebar Menu', () => {
let wrapper;
- let flyoutFlag = false;
-
const createWrapper = (extraProps = {}) => {
wrapper = shallowMountExtended(SidebarMenu, {
- provide: {
- glFeatures: { superSidebarFlyoutMenus: flyoutFlag },
- },
propsData: {
items: sidebarData.current_menu_items,
isLoggedIn: sidebarData.is_logged_in,
@@ -125,8 +120,11 @@ describe('Sidebar Menu', () => {
});
describe('flyout menus', () => {
- describe('when feature is disabled', () => {
+ describe('when screen width is smaller than "md" breakpoint', () => {
beforeEach(() => {
+ jest.spyOn(GlBreakpointInstance, 'windowWidth').mockImplementation(() => {
+ return 767;
+ });
createWrapper({
items: menuItems,
});
@@ -140,59 +138,27 @@ describe('Sidebar Menu', () => {
});
});
- describe('when feature is enabled', () => {
+ describe('when screen width is equal or larger than "md" breakpoint', () => {
beforeEach(() => {
- flyoutFlag = true;
- });
-
- describe('when screen width is smaller than "md" breakpoint', () => {
- beforeEach(() => {
- jest.spyOn(GlBreakpointInstance, 'windowWidth').mockImplementation(() => {
- return 767;
- });
- createWrapper({
- items: menuItems,
- });
+ jest.spyOn(GlBreakpointInstance, 'windowWidth').mockImplementation(() => {
+ return 768;
});
-
- it('does not add flyout menus to sections', () => {
- expect(findNonStaticSectionItems().wrappers.map((w) => w.props('hasFlyout'))).toEqual([
- false,
- false,
- ]);
+ createWrapper({
+ items: menuItems,
});
});
- describe('when screen width is equal or larger than "md" breakpoint', () => {
- beforeEach(() => {
- jest.spyOn(GlBreakpointInstance, 'windowWidth').mockImplementation(() => {
- return 768;
- });
- createWrapper({
- items: menuItems,
- });
- });
-
- it('adds flyout menus to sections', () => {
- expect(findNonStaticSectionItems().wrappers.map((w) => w.props('hasFlyout'))).toEqual([
- true,
- true,
- ]);
- });
+ it('adds flyout menus to sections', () => {
+ expect(findNonStaticSectionItems().wrappers.map((w) => w.props('hasFlyout'))).toEqual([
+ true,
+ true,
+ ]);
});
});
});
});
describe('Separators', () => {
- it('should add the separator above pinned section', () => {
- createWrapper({
- items: menuItems,
- panelType: 'project',
- });
- expect(findPinnedSection().props('separated')).toBe(true);
- });
-
it('should add the separator above main menu items when there is a pinned section', () => {
createWrapper({
items: menuItems,
@@ -209,11 +175,4 @@ describe('Sidebar Menu', () => {
expect(findMainMenuSeparator().exists()).toBe(false);
});
});
-
- describe('ARIA attributes', () => {
- it('adds aria-label attribute to nav element', () => {
- createWrapper();
- expect(wrapper.find('nav').attributes('aria-label')).toBe('Main navigation');
- });
- });
});
diff --git a/spec/frontend/super_sidebar/components/sidebar_peek_behavior_spec.js b/spec/frontend/super_sidebar/components/sidebar_peek_behavior_spec.js
index 94ef072a951..90a950c5f35 100644
--- a/spec/frontend/super_sidebar/components/sidebar_peek_behavior_spec.js
+++ b/spec/frontend/super_sidebar/components/sidebar_peek_behavior_spec.js
@@ -2,14 +2,14 @@ import { mount } from '@vue/test-utils';
import {
SUPER_SIDEBAR_PEEK_OPEN_DELAY,
SUPER_SIDEBAR_PEEK_CLOSE_DELAY,
+ SUPER_SIDEBAR_PEEK_STATE_CLOSED as STATE_CLOSED,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_OPEN as STATE_WILL_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_OPEN as STATE_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_CLOSE as STATE_WILL_CLOSE,
} from '~/super_sidebar/constants';
-import SidebarPeek, {
- STATE_CLOSED,
- STATE_WILL_OPEN,
- STATE_OPEN,
- STATE_WILL_CLOSE,
-} from '~/super_sidebar/components/sidebar_peek_behavior.vue';
+import SidebarPeek from '~/super_sidebar/components/sidebar_peek_behavior.vue';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { moveMouse, moveMouseOutOfDocument } from '../mocks';
// These are measured at runtime in the browser, but statically defined here
// since Jest does not do layout/styling.
@@ -41,19 +41,6 @@ describe('SidebarPeek component', () => {
});
};
- const moveMouse = (clientX) => {
- const event = new MouseEvent('mousemove', {
- clientX,
- });
-
- document.dispatchEvent(event);
- };
-
- const moveMouseOutOfDocument = () => {
- const event = new MouseEvent('mouseleave');
- document.documentElement.dispatchEvent(event);
- };
-
const lastNChangeEvents = (n = 1) => wrapper.emitted('change').slice(-n).flat();
beforeEach(() => {
diff --git a/spec/frontend/super_sidebar/components/super_sidebar_spec.js b/spec/frontend/super_sidebar/components/super_sidebar_spec.js
index 7b7b8a7be13..1371f8f00a7 100644
--- a/spec/frontend/super_sidebar/components/super_sidebar_spec.js
+++ b/spec/frontend/super_sidebar/components/super_sidebar_spec.js
@@ -4,29 +4,32 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import SuperSidebar from '~/super_sidebar/components/super_sidebar.vue';
import HelpCenter from '~/super_sidebar/components/help_center.vue';
import UserBar from '~/super_sidebar/components/user_bar.vue';
-import SidebarPeekBehavior, {
- STATE_CLOSED,
- STATE_WILL_OPEN,
- STATE_OPEN,
- STATE_WILL_CLOSE,
-} from '~/super_sidebar/components/sidebar_peek_behavior.vue';
+import SidebarPeekBehavior from '~/super_sidebar/components/sidebar_peek_behavior.vue';
+import SidebarHoverPeekBehavior from '~/super_sidebar/components/sidebar_hover_peek_behavior.vue';
import SidebarPortalTarget from '~/super_sidebar/components/sidebar_portal_target.vue';
-import ContextHeader from '~/super_sidebar/components/context_header.vue';
-import ContextSwitcher from '~/super_sidebar/components/context_switcher.vue';
import SidebarMenu from '~/super_sidebar/components/sidebar_menu.vue';
-import { sidebarState } from '~/super_sidebar/constants';
+import {
+ sidebarState,
+ SUPER_SIDEBAR_PEEK_STATE_CLOSED as STATE_CLOSED,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_OPEN as STATE_WILL_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_OPEN as STATE_OPEN,
+ SUPER_SIDEBAR_PEEK_STATE_WILL_CLOSE as STATE_WILL_CLOSE,
+} from '~/super_sidebar/constants';
import {
toggleSuperSidebarCollapsed,
isCollapsed,
} from '~/super_sidebar/super_sidebar_collapsed_state_manager';
-import { stubComponent } from 'helpers/stub_component';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import { trackContextAccess } from '~/super_sidebar/utils';
import { sidebarData as mockSidebarData, loggedOutSidebarData } from '../mock_data';
const initialSidebarState = { ...sidebarState };
jest.mock('~/super_sidebar/super_sidebar_collapsed_state_manager');
-const closeContextSwitcherMock = jest.fn();
+jest.mock('~/super_sidebar/utils', () => ({
+ ...jest.requireActual('~/super_sidebar/utils'),
+ trackContextAccess: jest.fn(),
+}));
const trialStatusWidgetStubTestId = 'trial-status-widget';
const TrialStatusWidgetStub = { template: `<div data-testid="${trialStatusWidgetStubTestId}" />` };
@@ -36,6 +39,7 @@ const TrialStatusPopoverStub = {
};
const peekClass = 'super-sidebar-peek';
+const hasPeekedClass = 'super-sidebar-has-peeked';
const peekHintClass = 'super-sidebar-peek-hint';
describe('SuperSidebar component', () => {
@@ -43,12 +47,11 @@ describe('SuperSidebar component', () => {
const findSidebar = () => wrapper.findByTestId('super-sidebar');
const findUserBar = () => wrapper.findComponent(UserBar);
- const findContextHeader = () => wrapper.findComponent(ContextHeader);
- const findContextSwitcher = () => wrapper.findComponent(ContextSwitcher);
const findNavContainer = () => wrapper.findByTestId('nav-container');
const findHelpCenter = () => wrapper.findComponent(HelpCenter);
const findSidebarPortalTarget = () => wrapper.findComponent(SidebarPortalTarget);
const findPeekBehavior = () => wrapper.findComponent(SidebarPeekBehavior);
+ const findHoverPeekBehavior = () => wrapper.findComponent(SidebarHoverPeekBehavior);
const findTrialStatusWidget = () => wrapper.findByTestId(trialStatusWidgetStubTestId);
const findTrialStatusPopover = () => wrapper.findByTestId(trialStatusPopoverStubTestId);
const findSidebarMenu = () => wrapper.findComponent(SidebarMenu);
@@ -70,9 +73,6 @@ describe('SuperSidebar component', () => {
sidebarData,
},
stubs: {
- ContextSwitcher: stubComponent(ContextSwitcher, {
- methods: { close: closeContextSwitcherMock },
- }),
TrialStatusWidget: TrialStatusWidgetStub,
TrialStatusPopover: TrialStatusPopoverStub,
},
@@ -128,12 +128,6 @@ describe('SuperSidebar component', () => {
expect(findSidebarPortalTarget().exists()).toBe(true);
});
- it("does not call the context switcher's close method initially", () => {
- createWrapper();
-
- expect(closeContextSwitcherMock).not.toHaveBeenCalled();
- });
-
it('renders hidden shortcut links', () => {
createWrapper();
const [linkAttrs] = mockSidebarData.shortcut_links;
@@ -181,21 +175,43 @@ describe('SuperSidebar component', () => {
expect(findTrialStatusPopover().exists()).toBe(false);
});
- it('does not have peek behavior', () => {
+ it('does not have peek behaviors', () => {
createWrapper();
expect(findPeekBehavior().exists()).toBe(false);
+ expect(findHoverPeekBehavior().exists()).toBe(false);
});
- });
- describe('on collapse', () => {
- beforeEach(() => {
+ it('renders the context header', () => {
createWrapper();
- sidebarState.isCollapsed = true;
+
+ expect(wrapper.text()).toContain('Your work');
});
- it('closes the context switcher', () => {
- expect(closeContextSwitcherMock).toHaveBeenCalled();
+ describe('item access tracking', () => {
+ it('does not track anything if logged out', () => {
+ createWrapper({ sidebarData: loggedOutSidebarData });
+
+ expect(trackContextAccess).not.toHaveBeenCalled();
+ });
+
+ it('does not track anything if logged in and not within a trackable context', () => {
+ createWrapper();
+
+ expect(trackContextAccess).not.toHaveBeenCalled();
+ });
+
+ it('tracks item access if logged in within a trackable context', () => {
+ const currentContext = { namespace: 'groups' };
+ createWrapper({
+ sidebarData: {
+ ...mockSidebarData,
+ current_context: currentContext,
+ },
+ });
+
+ expect(trackContextAccess).toHaveBeenCalledWith('root', currentContext, '/-/track_visits');
+ });
});
});
@@ -205,6 +221,7 @@ describe('SuperSidebar component', () => {
expect(findSidebar().attributes('inert')).toBe('inert');
expect(findSidebar().classes()).not.toContain(peekHintClass);
+ expect(findSidebar().classes()).not.toContain(hasPeekedClass);
expect(findSidebar().classes()).not.toContain(peekClass);
});
@@ -216,6 +233,7 @@ describe('SuperSidebar component', () => {
expect(findSidebar().attributes('inert')).toBe('inert');
expect(findSidebar().classes()).toContain(peekHintClass);
+ expect(findSidebar().classes()).toContain(hasPeekedClass);
expect(findSidebar().classes()).not.toContain(peekClass);
});
@@ -230,9 +248,23 @@ describe('SuperSidebar component', () => {
expect(findSidebar().attributes('inert')).toBe(undefined);
expect(findSidebar().classes()).toContain(peekClass);
expect(findSidebar().classes()).not.toContain(peekHintClass);
+ expect(findHoverPeekBehavior().exists()).toBe(false);
},
);
+ it(`makes sidebar interactive and visible when hover peek state is ${STATE_OPEN}`, async () => {
+ createWrapper({ sidebarState: { isCollapsed: true, isPeekable: true } });
+
+ findHoverPeekBehavior().vm.$emit('change', STATE_OPEN);
+ await nextTick();
+
+ expect(findSidebar().attributes('inert')).toBe(undefined);
+ expect(findSidebar().classes()).toContain(peekClass);
+ expect(findSidebar().classes()).toContain(hasPeekedClass);
+ expect(findSidebar().classes()).not.toContain(peekHintClass);
+ expect(findPeekBehavior().exists()).toBe(false);
+ });
+
it('keeps track of if sidebar has mouseover or not', async () => {
createWrapper({ sidebarState: { isCollapsed: false, isPeekable: true } });
expect(findPeekBehavior().props('isMouseOverSidebar')).toBe(false);
@@ -248,16 +280,9 @@ describe('SuperSidebar component', () => {
createWrapper();
});
- it('allows overflow while the context switcher is closed', () => {
+ it('allows overflow', () => {
expect(findNavContainer().classes()).toContain('gl-overflow-auto');
});
-
- it('hides overflow when context switcher is opened', async () => {
- findContextSwitcher().vm.$emit('toggle', true);
- await nextTick();
-
- expect(findNavContainer().classes()).not.toContain('gl-overflow-auto');
- });
});
describe('when a trial is active', () => {
@@ -271,14 +296,10 @@ describe('SuperSidebar component', () => {
});
});
- describe('Logged out', () => {
- beforeEach(() => {
- createWrapper({ sidebarData: loggedOutSidebarData });
- });
-
- it('renders context header instead of context switcher', () => {
- expect(findContextHeader().exists()).toBe(true);
- expect(findContextSwitcher().exists()).toBe(false);
+ describe('ARIA attributes', () => {
+ it('adds aria-label attribute to nav element', () => {
+ createWrapper();
+ expect(wrapper.find('nav').attributes('aria-label')).toBe('Primary');
});
});
});
diff --git a/spec/frontend/super_sidebar/components/super_sidebar_toggle_spec.js b/spec/frontend/super_sidebar/components/super_sidebar_toggle_spec.js
index 23b735c2773..1f2e5602d10 100644
--- a/spec/frontend/super_sidebar/components/super_sidebar_toggle_spec.js
+++ b/spec/frontend/super_sidebar/components/super_sidebar_toggle_spec.js
@@ -1,6 +1,5 @@
import { nextTick } from 'vue';
import { GlButton } from '@gitlab/ui';
-import { __ } from '~/locale';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -46,31 +45,29 @@ describe('SuperSidebarToggle component', () => {
expect(findButton().attributes('aria-expanded')).toBe('true');
});
- it('has aria-expanded as false when collapsed', () => {
- createWrapper({ sidebarState: { isCollapsed: true } });
- expect(findButton().attributes('aria-expanded')).toBe('false');
- });
+ it.each(['isCollapsed', 'isPeek', 'isHoverPeek'])(
+ 'has aria-expanded as false when %s is `true`',
+ (stateProp) => {
+ createWrapper({ sidebarState: { [stateProp]: true } });
+ expect(findButton().attributes('aria-expanded')).toBe('false');
+ },
+ );
it('has aria-label attribute', () => {
createWrapper();
- expect(findButton().attributes('aria-label')).toBe(__('Navigation sidebar'));
- });
-
- it('is disabled when isPeek is true', () => {
- createWrapper({ sidebarState: { isPeek: true } });
- expect(findButton().attributes('disabled')).toBeDefined();
+ expect(findButton().attributes('aria-label')).toBe('Primary navigation sidebar');
});
});
describe('tooltip', () => {
it('displays collapse when expanded', () => {
createWrapper();
- expect(getTooltip().title).toBe(__('Hide sidebar'));
+ expect(getTooltip().title).toBe('Hide sidebar');
});
it('displays expand when collapsed', () => {
createWrapper({ sidebarState: { isCollapsed: true } });
- expect(getTooltip().title).toBe(__('Show sidebar'));
+ expect(getTooltip().title).toBe('Keep sidebar visible');
});
});
diff --git a/spec/frontend/super_sidebar/components/user_bar_spec.js b/spec/frontend/super_sidebar/components/user_bar_spec.js
index c6dd8441094..b58b65f09f5 100644
--- a/spec/frontend/super_sidebar/components/user_bar_spec.js
+++ b/spec/frontend/super_sidebar/components/user_bar_spec.js
@@ -65,8 +65,20 @@ describe('UserBar component', () => {
createWrapper();
});
- it('passes the "Create new..." menu groups to the create-menu component', () => {
- expect(findCreateMenu().props('groups')).toBe(mockSidebarData.create_new_menu_groups);
+ describe('"Create new..." menu', () => {
+ describe('when there are no menu items for it', () => {
+ // This scenario usually happens for an "External" user.
+ it('does not render it', () => {
+ createWrapper({ sidebarData: { ...mockSidebarData, create_new_menu_groups: [] } });
+ expect(findCreateMenu().exists()).toBe(false);
+ });
+ });
+
+ describe('when there are menu items for it', () => {
+ it('passes the "Create new..." menu groups to the create-menu component', () => {
+ expect(findCreateMenu().props('groups')).toBe(mockSidebarData.create_new_menu_groups);
+ });
+ });
});
it('passes the "Merge request" menu groups to the merge_request_menu component', () => {
@@ -165,7 +177,7 @@ describe('UserBar component', () => {
it('search button should have tooltip', () => {
const tooltip = getBinding(findSearchButton().element, 'gl-tooltip');
- expect(tooltip.value).toBe(`Search GitLab <kbd>/</kbd>`);
+ expect(tooltip.value).toBe(`Type <kbd>/</kbd> to search`);
});
it('should render search modal', () => {
@@ -184,7 +196,7 @@ describe('UserBar component', () => {
findSearchModal().vm.$emit('hidden');
await nextTick();
const tooltip = getBinding(findSearchButton().element, 'gl-tooltip');
- expect(tooltip.value).toBe(`Search GitLab <kbd>/</kbd>`);
+ expect(tooltip.value).toBe(`Type <kbd>/</kbd> to search`);
});
});
});
diff --git a/spec/frontend/super_sidebar/components/user_menu_spec.js b/spec/frontend/super_sidebar/components/user_menu_spec.js
index 662677be40f..bcc3383bcd4 100644
--- a/spec/frontend/super_sidebar/components/user_menu_spec.js
+++ b/spec/frontend/super_sidebar/components/user_menu_spec.js
@@ -468,27 +468,6 @@ describe('UserMenu component', () => {
});
});
- describe('Feedback item', () => {
- let item;
-
- beforeEach(() => {
- createWrapper();
- item = wrapper.findByTestId('feedback-item');
- });
-
- it('should render feedback item with a link to a new GitLab issue', () => {
- expect(item.find('a').attributes('href')).toBe(UserMenu.feedbackUrl);
- });
-
- it('has Snowplow tracking attributes', () => {
- expect(item.find('a').attributes()).toMatchObject({
- 'data-track-property': 'nav_user_menu',
- 'data-track-action': 'click_link',
- 'data-track-label': 'provide_nav_feedback',
- });
- });
- });
-
describe('Sign out group', () => {
const findSignOutGroup = () => wrapper.findByTestId('sign-out-group');
diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js
index 6fb9715824f..d464ce372ed 100644
--- a/spec/frontend/super_sidebar/mock_data.js
+++ b/spec/frontend/super_sidebar/mock_data.js
@@ -79,10 +79,8 @@ export const contextSwitcherLinks = [
export const sidebarData = {
is_logged_in: true,
current_menu_items: [],
- current_context_header: {
- title: 'Your Work',
- icon: 'work',
- },
+ current_context: {},
+ current_context_header: 'Your work',
name: 'Administrator',
username: 'root',
avatar_url: 'path/to/img_administrator',
@@ -124,15 +122,14 @@ export const sidebarData = {
css_class: 'shortcut-link-class',
},
],
+ track_visits_path: '/-/track_visits',
};
export const loggedOutSidebarData = {
is_logged_in: false,
current_menu_items: [],
- current_context_header: {
- title: 'Your Work',
- icon: 'work',
- },
+ current_context: {},
+ current_context_header: 'Your work',
support_path: '/support',
display_whats_new: true,
whats_new_most_recent_release_items_count: 5,
@@ -285,36 +282,3 @@ export const cachedFrequentGroups = JSON.stringify([
frequency: 3,
},
]);
-
-export const searchUserProjectsAndGroupsResponseMock = {
- data: {
- projects: {
- nodes: [
- {
- id: 'gid://gitlab/Project/2',
- name: 'Gitlab Shell',
- namespace: 'Gitlab Org / Gitlab Shell',
- webUrl: 'http://gdk.test:3000/gitlab-org/gitlab-shell',
- avatarUrl: null,
- __typename: 'Project',
- },
- ],
- },
-
- user: {
- id: 'gid://gitlab/User/1',
- groups: {
- nodes: [
- {
- id: 'gid://gitlab/Group/60',
- name: 'GitLab Instance',
- namespace: 'gitlab-instance-2e4abb29',
- webUrl: 'http://gdk.test:3000/groups/gitlab-instance-2e4abb29',
- avatarUrl: null,
- __typename: 'Group',
- },
- ],
- },
- },
- },
-};
diff --git a/spec/frontend/super_sidebar/mocks.js b/spec/frontend/super_sidebar/mocks.js
new file mode 100644
index 00000000000..d13e5f1f361
--- /dev/null
+++ b/spec/frontend/super_sidebar/mocks.js
@@ -0,0 +1,24 @@
+export const moveMouse = (clientX) => {
+ const event = new MouseEvent('mousemove', {
+ clientX,
+ });
+
+ document.dispatchEvent(event);
+};
+
+export const mouseEnter = (el) => {
+ const event = new MouseEvent('mouseenter');
+
+ el.dispatchEvent(event);
+};
+
+export const mouseLeave = (el) => {
+ const event = new MouseEvent('mouseleave');
+
+ el.dispatchEvent(event);
+};
+
+export const moveMouseOutOfDocument = () => {
+ const event = new MouseEvent('mouseleave');
+ document.documentElement.dispatchEvent(event);
+};
diff --git a/spec/frontend/super_sidebar/utils_spec.js b/spec/frontend/super_sidebar/utils_spec.js
index 536599e6c12..85f45de06ba 100644
--- a/spec/frontend/super_sidebar/utils_spec.js
+++ b/spec/frontend/super_sidebar/utils_spec.js
@@ -1,17 +1,20 @@
import * as Sentry from '@sentry/browser';
+import MockAdapter from 'axios-mock-adapter';
import {
getTopFrequentItems,
trackContextAccess,
- formatContextSwitcherItems,
getItemsFromLocalStorage,
removeItemFromLocalStorage,
ariaCurrent,
} from '~/super_sidebar/utils';
+import axios from '~/lib/utils/axios_utils';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import AccessorUtilities from '~/lib/utils/accessor';
import { FREQUENT_ITEMS, FIFTEEN_MINUTES_IN_MS } from '~/frequent_items/constants';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import waitForPromises from 'helpers/wait_for_promises';
import { unsortedFrequentItems, sortedFrequentItems } from '../frequent_items/mock_data';
-import { cachedFrequentProjects, searchUserProjectsAndGroupsResponseMock } from './mock_data';
+import { cachedFrequentProjects } from './mock_data';
jest.mock('@sentry/browser');
@@ -42,13 +45,29 @@ describe('Super sidebar utils spec', () => {
});
describe('trackContextAccess', () => {
+ useLocalStorageSpy();
+
+ let axiosMock;
+
const username = 'root';
+ const trackVisitsPath = '/-/track_visits';
const context = {
namespace: 'groups',
item: { id: 1 },
};
const storageKey = `${username}/frequent-${context.namespace}`;
+ beforeEach(() => {
+ gon.features = { serverSideFrecentNamespaces: true };
+ axiosMock = new MockAdapter(axios);
+ axiosMock.onPost(trackVisitsPath).reply(HTTP_STATUS_OK);
+ });
+
+ afterEach(() => {
+ gon.features = {};
+ axiosMock.restore();
+ });
+
it('returns `false` if local storage is not available', () => {
jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(false);
@@ -56,7 +75,7 @@ describe('Super sidebar utils spec', () => {
});
it('creates a new item if it does not exist in the local storage', () => {
- trackContextAccess(username, context);
+ trackContextAccess(username, context, trackVisitsPath);
expect(window.localStorage.setItem).toHaveBeenCalledWith(
storageKey,
@@ -70,6 +89,24 @@ describe('Super sidebar utils spec', () => {
);
});
+ it('sends a POST request to persist the visit in the DB', async () => {
+ expect(axiosMock.history.post).toHaveLength(0);
+
+ trackContextAccess(username, context, trackVisitsPath);
+ await waitForPromises();
+
+ expect(axiosMock.history.post).toHaveLength(1);
+ expect(axiosMock.history.post[0].url).toBe(trackVisitsPath);
+ });
+
+ it('does not send a POST request when the serverSideFrecentNamespaces feature flag is disabled', async () => {
+ gon.features = { serverSideFrecentNamespaces: false };
+ trackContextAccess(username, context, trackVisitsPath);
+ await waitForPromises();
+
+ expect(axiosMock.history.post).toHaveLength(0);
+ });
+
it('updates existing item frequency/access time if it was persisted to the local storage over 15 minutes ago', () => {
window.localStorage.setItem(
storageKey,
@@ -81,7 +118,7 @@ describe('Super sidebar utils spec', () => {
},
]),
);
- trackContextAccess(username, context);
+ trackContextAccess(username, context, trackVisitsPath);
expect(window.localStorage.setItem).toHaveBeenCalledWith(
storageKey,
@@ -95,7 +132,7 @@ describe('Super sidebar utils spec', () => {
);
});
- it('leaves item frequency/access time as is if it was persisted to the local storage under 15 minutes ago', () => {
+ it('leaves item frequency/access time as is if it was persisted to the local storage under 15 minutes ago, and does not send a POST request', () => {
const jsonString = JSON.stringify([
{
id: 1,
@@ -108,10 +145,12 @@ describe('Super sidebar utils spec', () => {
expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
expect(window.localStorage.setItem).toHaveBeenCalledWith(storageKey, jsonString);
- trackContextAccess(username, context);
+ trackContextAccess(username, context, trackVisitsPath);
expect(window.localStorage.setItem).toHaveBeenCalledTimes(3);
expect(window.localStorage.setItem).toHaveBeenLastCalledWith(storageKey, jsonString);
+
+ expect(axiosMock.history.post).toHaveLength(0);
});
it('always updates stored item metadata', () => {
@@ -163,10 +202,14 @@ describe('Super sidebar utils spec', () => {
const newItem = {
id: FREQUENT_ITEMS.MAX_COUNT + 1,
};
- trackContextAccess(username, {
- namespace: 'groups',
- item: newItem,
- });
+ trackContextAccess(
+ username,
+ {
+ namespace: 'groups',
+ item: newItem,
+ },
+ trackVisitsPath,
+ );
// Finally, retrieve the final data from the local storage
const finallyStoredItems = JSON.parse(window.localStorage.getItem(storageKey));
@@ -182,21 +225,6 @@ describe('Super sidebar utils spec', () => {
});
});
- describe('formatContextSwitcherItems', () => {
- it('returns the formatted items', () => {
- const projects = searchUserProjectsAndGroupsResponseMock.data.projects.nodes;
- expect(formatContextSwitcherItems(projects)).toEqual([
- {
- id: projects[0].id,
- avatar: null,
- title: projects[0].name,
- subtitle: 'Gitlab Org',
- link: projects[0].webUrl,
- },
- ]);
- });
- });
-
describe('getItemsFromLocalStorage', () => {
const storageKey = 'mockStorageKey';
const maxItems = 5;
diff --git a/spec/frontend/time_tracking/components/timelogs_app_spec.js b/spec/frontend/time_tracking/components/timelogs_app_spec.js
index ca470ce63ac..13188f3b937 100644
--- a/spec/frontend/time_tracking/components/timelogs_app_spec.js
+++ b/spec/frontend/time_tracking/components/timelogs_app_spec.js
@@ -95,12 +95,12 @@ describe('Timelogs app', () => {
mountComponent();
const username = 'johnsmith';
- const fromDate = new Date('2023-02-28');
- const toDate = new Date('2023-03-28');
+ const fromDateTime = new Date('2023-02-28');
+ const toDateTime = new Date('2023-03-28');
findUsernameInput().vm.$emit('input', username);
- findFromDatepicker().vm.$emit('input', fromDate);
- findToDatepicker().vm.$emit('input', toDate);
+ findFromDatepicker().vm.$emit('input', fromDateTime);
+ findToDatepicker().vm.$emit('input', toDateTime);
resolvedEmptyListMock.mockClear();
@@ -110,8 +110,8 @@ describe('Timelogs app', () => {
expect(resolvedEmptyListMock).toHaveBeenCalledWith({
username,
- startDate: fromDate,
- endDate: toDate,
+ startTime: fromDateTime,
+ endTime: toDateTime,
groupId: null,
projectId: null,
first: 20,
@@ -119,6 +119,15 @@ describe('Timelogs app', () => {
after: null,
before: null,
});
+
+ expect(`${wrapper.vm.queryVariables.startTime}`).toEqual(
+ 'Tue Feb 28 2023 00:00:00 GMT+0000 (Greenwich Mean Time)',
+ );
+ // should be 1 day ahead of the initial To Date value
+ expect(`${wrapper.vm.queryVariables.endTime}`).toEqual(
+ 'Wed Mar 29 2023 00:00:00 GMT+0000 (Greenwich Mean Time)',
+ );
+
expect(createAlert).not.toHaveBeenCalled();
expect(Sentry.captureException).not.toHaveBeenCalled();
});
@@ -140,8 +149,8 @@ describe('Timelogs app', () => {
expect(resolvedEmptyListMock).toHaveBeenCalledWith({
username,
- startDate: null,
- endDate: null,
+ startTime: null,
+ endTime: null,
groupId: null,
projectId: null,
first: 20,
diff --git a/spec/frontend/tracing/components/tracing_details_spec.js b/spec/frontend/tracing/components/tracing_details_spec.js
deleted file mode 100644
index c5efa2a7eb5..00000000000
--- a/spec/frontend/tracing/components/tracing_details_spec.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import { GlLoadingIcon } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import TracingDetails from '~/tracing/components/tracing_details.vue';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import { visitUrl, isSafeURL } from '~/lib/utils/url_utility';
-
-jest.mock('~/alert');
-jest.mock('~/lib/utils/url_utility');
-
-describe('TracingDetails', () => {
- let wrapper;
- let observabilityClientMock;
-
- const TRACE_ID = 'test-trace-id';
- const TRACING_INDEX_URL = 'https://www.gitlab.com/flightjs/Flight/-/tracing';
-
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findTraceDetails = () => wrapper.findComponentByTestId('trace-details');
-
- const props = {
- traceId: TRACE_ID,
- tracingIndexUrl: TRACING_INDEX_URL,
- };
-
- const mountComponent = async () => {
- wrapper = shallowMountExtended(TracingDetails, {
- propsData: {
- ...props,
- observabilityClient: observabilityClientMock,
- },
- });
- await waitForPromises();
- };
-
- beforeEach(() => {
- isSafeURL.mockReturnValue(true);
-
- observabilityClientMock = {
- isTracingEnabled: jest.fn(),
- fetchTrace: jest.fn(),
- };
- });
-
- it('renders the loading indicator while checking if tracing is enabled', () => {
- mountComponent();
-
- expect(findLoadingIcon().exists()).toBe(true);
- expect(observabilityClientMock.isTracingEnabled).toHaveBeenCalled();
- });
-
- describe('when tracing is enabled', () => {
- const mockTrace = { traceId: 'test-trace-id', foo: 'bar' };
- beforeEach(async () => {
- observabilityClientMock.isTracingEnabled.mockResolvedValueOnce(true);
- observabilityClientMock.fetchTrace.mockResolvedValueOnce(mockTrace);
-
- await mountComponent();
- });
-
- it('fetches the trace and renders the trace details', () => {
- expect(observabilityClientMock.isTracingEnabled).toHaveBeenCalled();
- expect(observabilityClientMock.fetchTrace).toHaveBeenCalled();
- expect(findLoadingIcon().exists()).toBe(false);
- expect(findTraceDetails().exists()).toBe(true);
- });
- });
-
- describe('when tracing is not enabled', () => {
- beforeEach(async () => {
- observabilityClientMock.isTracingEnabled.mockResolvedValueOnce(false);
-
- await mountComponent();
- });
-
- it('redirects to tracingIndexUrl', () => {
- expect(visitUrl).toHaveBeenCalledWith(props.tracingIndexUrl);
- });
- });
-
- describe('error handling', () => {
- it('if isTracingEnabled fails, it renders an alert and empty page', async () => {
- observabilityClientMock.isTracingEnabled.mockRejectedValueOnce('error');
-
- await mountComponent();
-
- expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to load trace details.' });
- expect(findLoadingIcon().exists()).toBe(false);
- expect(findTraceDetails().exists()).toBe(false);
- });
-
- it('if fetchTrace fails, it renders an alert and empty page', async () => {
- observabilityClientMock.isTracingEnabled.mockReturnValueOnce(true);
- observabilityClientMock.fetchTrace.mockRejectedValueOnce('error');
-
- await mountComponent();
-
- expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to load trace details.' });
- expect(findLoadingIcon().exists()).toBe(false);
- expect(findTraceDetails().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/tracing/components/tracing_empty_state_spec.js b/spec/frontend/tracing/components/tracing_empty_state_spec.js
deleted file mode 100644
index d91c62a1dad..00000000000
--- a/spec/frontend/tracing/components/tracing_empty_state_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { GlButton, GlEmptyState } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import TracingEmptyState from '~/tracing/components/tracing_empty_state.vue';
-
-describe('TracingEmptyState', () => {
- let wrapper;
-
- const findEnableButton = () => wrapper.findComponent(GlButton);
-
- beforeEach(() => {
- wrapper = shallowMountExtended(TracingEmptyState);
- });
-
- it('renders the component properly', () => {
- expect(wrapper.exists()).toBe(true);
- });
-
- it('displays the correct title', () => {
- const { title } = wrapper.findComponent(GlEmptyState).props();
- expect(title).toBe('Get started with Tracing');
- });
-
- it('displays the correct description', () => {
- const description = wrapper.find('span').text();
- expect(description).toBe('Monitor your applications with GitLab Distributed Tracing.');
- });
-
- it('displays the enable button', () => {
- const enableButton = findEnableButton();
- expect(enableButton.exists()).toBe(true);
- expect(enableButton.text()).toBe('Enable');
- });
-
- it('emits enable-tracing when enable button is clicked', () => {
- findEnableButton().vm.$emit('click');
-
- expect(wrapper.emitted('enable-tracing')).toHaveLength(1);
- });
-});
diff --git a/spec/frontend/tracing/components/tracing_list_filtered_search_spec.js b/spec/frontend/tracing/components/tracing_list_filtered_search_spec.js
deleted file mode 100644
index ad15dd4a371..00000000000
--- a/spec/frontend/tracing/components/tracing_list_filtered_search_spec.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { GlFilteredSearch } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-
-import TracingListFilteredSearch from '~/tracing/components/tracing_list_filtered_search.vue';
-
-describe('TracingListFilteredSearch', () => {
- let wrapper;
- const initialFilters = [
- { type: 'period', value: '1h' },
- { type: 'service_name', value: 'example-service' },
- ];
- beforeEach(() => {
- wrapper = shallowMountExtended(TracingListFilteredSearch, {
- propsData: {
- initialFilters,
- },
- });
- });
-
- it('renders the component', () => {
- expect(wrapper.exists()).toBe(true);
- });
-
- it('sets initialFilters prop correctly', () => {
- expect(wrapper.findComponent(GlFilteredSearch).props('value')).toEqual(initialFilters);
- });
-
- it('emits submit event on filtered search submit', () => {
- wrapper
- .findComponent(GlFilteredSearch)
- .vm.$emit('submit', { filters: [{ type: 'period', value: '1h' }] });
-
- expect(wrapper.emitted('submit')).toHaveLength(1);
- expect(wrapper.emitted('submit')[0][0]).toEqual({
- filters: [{ type: 'period', value: '1h' }],
- });
- });
-});
diff --git a/spec/frontend/tracing/components/tracing_list_spec.js b/spec/frontend/tracing/components/tracing_list_spec.js
deleted file mode 100644
index 9aa37ac9c9c..00000000000
--- a/spec/frontend/tracing/components/tracing_list_spec.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import { GlLoadingIcon } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import TracingList from '~/tracing/components/tracing_list.vue';
-import TracingEmptyState from '~/tracing/components/tracing_empty_state.vue';
-import TracingTableList from '~/tracing/components/tracing_table_list.vue';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/alert';
-import * as urlUtility from '~/lib/utils/url_utility';
-import {
- queryToFilterObj,
- filterObjToQuery,
- filterObjToFilterToken,
- filterTokensToFilterObj,
-} from '~/tracing/filters';
-import FilteredSearch from '~/tracing/components/tracing_list_filtered_search.vue';
-import UrlSync from '~/vue_shared/components/url_sync.vue';
-import setWindowLocation from 'helpers/set_window_location_helper';
-
-jest.mock('~/alert');
-jest.mock('~/tracing/filters');
-
-describe('TracingList', () => {
- let wrapper;
- let observabilityClientMock;
-
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findEmptyState = () => wrapper.findComponent(TracingEmptyState);
- const findTableList = () => wrapper.findComponent(TracingTableList);
- const findFilteredSearch = () => wrapper.findComponent(FilteredSearch);
- const findUrlSync = () => wrapper.findComponent(UrlSync);
-
- const mountComponent = async () => {
- wrapper = shallowMountExtended(TracingList, {
- propsData: {
- observabilityClient: observabilityClientMock,
- },
- });
- await waitForPromises();
- };
-
- beforeEach(() => {
- observabilityClientMock = {
- isTracingEnabled: jest.fn(),
- enableTraces: jest.fn(),
- fetchTraces: jest.fn(),
- };
- });
-
- it('renders the loading indicator while checking if tracing is enabled', () => {
- mountComponent();
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findEmptyState().exists()).toBe(false);
- expect(findTableList().exists()).toBe(false);
- expect(findFilteredSearch().exists()).toBe(false);
- expect(findUrlSync().exists()).toBe(false);
- expect(observabilityClientMock.isTracingEnabled).toHaveBeenCalled();
- });
-
- describe('when tracing is enabled', () => {
- const mockTraces = ['trace1', 'trace2'];
- beforeEach(async () => {
- observabilityClientMock.isTracingEnabled.mockResolvedValueOnce(true);
- observabilityClientMock.fetchTraces.mockResolvedValueOnce(mockTraces);
-
- await mountComponent();
- });
-
- it('fetches the traces and renders the trace list with filtered search', () => {
- expect(observabilityClientMock.isTracingEnabled).toHaveBeenCalled();
- expect(observabilityClientMock.fetchTraces).toHaveBeenCalled();
- expect(findLoadingIcon().exists()).toBe(false);
- expect(findEmptyState().exists()).toBe(false);
- expect(findTableList().exists()).toBe(true);
- expect(findFilteredSearch().exists()).toBe(true);
- expect(findUrlSync().exists()).toBe(true);
- expect(findTableList().props('traces')).toBe(mockTraces);
- });
-
- it('calls fetchTraces method when TracingTableList emits reload event', () => {
- observabilityClientMock.fetchTraces.mockClear();
- observabilityClientMock.fetchTraces.mockResolvedValueOnce(['trace1']);
-
- findTableList().vm.$emit('reload');
-
- expect(observabilityClientMock.fetchTraces).toHaveBeenCalledTimes(1);
- });
-
- it('on trace selection it redirects to the details url', () => {
- setWindowLocation('base_path');
- const visitUrlMock = jest.spyOn(urlUtility, 'visitUrl').mockReturnValue({});
-
- findTableList().vm.$emit('trace-selected', { trace_id: 'test-trace-id' });
-
- expect(visitUrlMock).toHaveBeenCalledTimes(1);
- expect(visitUrlMock).toHaveBeenCalledWith('/base_path/test-trace-id');
- });
- });
-
- describe('filtered search', () => {
- let mockFilterObj;
- let mockFilterToken;
- let mockQuery;
- let mockUpdatedFilterObj;
-
- beforeEach(async () => {
- observabilityClientMock.isTracingEnabled.mockResolvedValue(true);
- observabilityClientMock.fetchTraces.mockResolvedValue([]);
-
- setWindowLocation('?trace-id=foo');
-
- mockFilterObj = { mock: 'filter-obj' };
- queryToFilterObj.mockReturnValue(mockFilterObj);
-
- mockFilterToken = ['mock-token'];
- filterObjToFilterToken.mockReturnValue(mockFilterToken);
-
- mockQuery = { mock: 'query' };
- filterObjToQuery.mockReturnValueOnce(mockQuery);
-
- mockUpdatedFilterObj = { mock: 'filter-obj-upd' };
- filterTokensToFilterObj.mockReturnValue(mockUpdatedFilterObj);
-
- await mountComponent();
- });
-
- it('renders FilteredSeach with initial filters parsed from window.location', () => {
- expect(queryToFilterObj).toHaveBeenCalledWith('?trace-id=foo');
- expect(filterObjToFilterToken).toHaveBeenCalledWith(mockFilterObj);
- expect(findFilteredSearch().props('initialFilters')).toBe(mockFilterToken);
- });
-
- it('renders UrlSync and sets query prop', () => {
- expect(filterObjToQuery).toHaveBeenCalledWith(mockFilterObj);
- expect(findUrlSync().props('query')).toBe(mockQuery);
- });
-
- it('process filters on search submit', async () => {
- const mockUpdatedQuery = { mock: 'updated-query' };
- filterObjToQuery.mockReturnValueOnce(mockUpdatedQuery);
- const mockFilters = { mock: 'some-filter' };
-
- findFilteredSearch().vm.$emit('submit', mockFilters);
- await waitForPromises();
-
- expect(filterTokensToFilterObj).toHaveBeenCalledWith(mockFilters);
- expect(filterObjToQuery).toHaveBeenCalledWith(mockUpdatedFilterObj);
- expect(findUrlSync().props('query')).toBe(mockUpdatedQuery);
- });
-
- it('fetches traces with filters', () => {
- expect(observabilityClientMock.fetchTraces).toHaveBeenCalledWith(mockFilterObj);
-
- findFilteredSearch().vm.$emit('submit', {});
-
- expect(observabilityClientMock.fetchTraces).toHaveBeenLastCalledWith(mockUpdatedFilterObj);
- });
- });
-
- describe('when tracing is not enabled', () => {
- beforeEach(async () => {
- observabilityClientMock.isTracingEnabled.mockResolvedValueOnce(false);
- observabilityClientMock.fetchTraces.mockResolvedValueOnce([]);
-
- await mountComponent();
- });
-
- it('renders TracingEmptyState', () => {
- expect(findEmptyState().exists()).toBe(true);
- });
-
- it('calls enableTracing when TracingEmptyState emits enable-tracing', () => {
- findEmptyState().vm.$emit('enable-tracing');
-
- expect(observabilityClientMock.enableTraces).toHaveBeenCalled();
- });
- });
-
- describe('error handling', () => {
- it('if isTracingEnabled fails, it renders an alert and empty page', async () => {
- observabilityClientMock.isTracingEnabled.mockRejectedValueOnce('error');
-
- await mountComponent();
-
- expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to load page.' });
- expect(findLoadingIcon().exists()).toBe(false);
- expect(findEmptyState().exists()).toBe(false);
- expect(findTableList().exists()).toBe(false);
- });
-
- it('if fetchTraces fails, it renders an alert and empty list', async () => {
- observabilityClientMock.fetchTraces.mockRejectedValueOnce('error');
- observabilityClientMock.isTracingEnabled.mockReturnValueOnce(true);
-
- await mountComponent();
-
- expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to load traces.' });
- expect(findTableList().exists()).toBe(true);
- expect(findTableList().props('traces')).toEqual([]);
- });
-
- it('if enableTraces fails, it renders an alert and empty-state', async () => {
- observabilityClientMock.isTracingEnabled.mockReturnValueOnce(false);
- observabilityClientMock.enableTraces.mockRejectedValueOnce('error');
-
- await mountComponent();
-
- findEmptyState().vm.$emit('enable-tracing');
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to enable tracing.' });
- expect(findLoadingIcon().exists()).toBe(false);
- expect(findEmptyState().exists()).toBe(true);
- expect(findTableList().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/tracing/components/tracing_table_list_spec.js b/spec/frontend/tracing/components/tracing_table_list_spec.js
deleted file mode 100644
index aa96b9b370f..00000000000
--- a/spec/frontend/tracing/components/tracing_table_list_spec.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import { nextTick } from 'vue';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import TracingTableList from '~/tracing/components/tracing_table_list.vue';
-
-describe('TracingTableList', () => {
- let wrapper;
- const mockTraces = [
- {
- timestamp: '2023-07-10T15:02:30.677538Z',
- service_name: 'tracegen',
- operation: 'lets-go',
- duration: 150,
- },
- {
- timestamp: '2023-07-10T15:02:30.677538Z',
- service_name: 'tracegen',
- operation: 'lets-go',
- duration: 200,
- },
- ];
-
- const mountComponent = ({ traces = mockTraces } = {}) => {
- wrapper = mountExtended(TracingTableList, {
- propsData: {
- traces,
- },
- });
- };
-
- const getRows = () => wrapper.findComponent({ name: 'GlTable' }).find('tbody').findAll('tr');
- const getRow = (idx) => getRows().at(idx);
- const getCells = (trIdx) => getRows().at(trIdx).findAll('td');
-
- const getCell = (trIdx, tdIdx) => {
- return getCells(trIdx).at(tdIdx);
- };
-
- const selectRow = async (idx) => {
- getRow(idx).trigger('click');
- await nextTick();
- };
-
- it('renders traces as table', () => {
- mountComponent();
-
- const rows = wrapper.findAll('table tbody tr');
-
- expect(rows.length).toBe(mockTraces.length);
-
- mockTraces.forEach((trace, i) => {
- expect(getCells(i).length).toBe(4);
- expect(getCell(i, 0).text()).toBe(trace.timestamp);
- expect(getCell(i, 1).text()).toBe(trace.service_name);
- expect(getCell(i, 2).text()).toBe(trace.operation);
- expect(getCell(i, 3).text()).toBe(`${trace.duration} ms`);
- });
- });
-
- it('emits trace-selected on row selection', async () => {
- mountComponent();
-
- await selectRow(0);
- expect(wrapper.emitted('trace-selected')).toHaveLength(1);
- expect(wrapper.emitted('trace-selected')[0][0]).toBe(mockTraces[0]);
- });
-
- it('renders the empty state when no traces are provided', () => {
- mountComponent({ traces: [] });
-
- expect(getCell(0, 0).text()).toContain('No traces to display');
- const link = getCell(0, 0).findComponent({ name: 'GlLink' });
- expect(link.text()).toBe('Check again');
-
- link.trigger('click');
- expect(wrapper.emitted('reload')).toHaveLength(1);
- });
-});
diff --git a/spec/frontend/tracing/details_index_spec.js b/spec/frontend/tracing/details_index_spec.js
deleted file mode 100644
index e0d368b6cb7..00000000000
--- a/spec/frontend/tracing/details_index_spec.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import DetailsIndex from '~/tracing/details_index.vue';
-import TracingDetails from '~/tracing/components/tracing_details.vue';
-import ObservabilityContainer from '~/observability/components/observability_container.vue';
-
-describe('DetailsIndex', () => {
- const props = {
- traceId: 'test-trace-id',
- tracingIndexUrl: 'https://example.com/tracing/index',
- oauthUrl: 'https://example.com/oauth',
- tracingUrl: 'https://example.com/tracing',
- provisioningUrl: 'https://example.com/provisioning',
- };
-
- let wrapper;
-
- const mountComponent = () => {
- wrapper = shallowMountExtended(DetailsIndex, {
- propsData: props,
- });
- };
-
- it('renders ObservabilityContainer component', () => {
- mountComponent();
-
- const observabilityContainer = wrapper.findComponent(ObservabilityContainer);
- expect(observabilityContainer.exists()).toBe(true);
- expect(observabilityContainer.props('oauthUrl')).toBe(props.oauthUrl);
- expect(observabilityContainer.props('tracingUrl')).toBe(props.tracingUrl);
- expect(observabilityContainer.props('provisioningUrl')).toBe(props.provisioningUrl);
- });
-
- it('renders TracingList component inside ObservabilityContainer', () => {
- mountComponent();
-
- const observabilityContainer = wrapper.findComponent(ObservabilityContainer);
- const detailsCmp = observabilityContainer.findComponent(TracingDetails);
- expect(detailsCmp.exists()).toBe(true);
- expect(detailsCmp.props('traceId')).toBe(props.traceId);
- expect(detailsCmp.props('tracingIndexUrl')).toBe(props.tracingIndexUrl);
- });
-});
diff --git a/spec/frontend/tracing/filters_spec.js b/spec/frontend/tracing/filters_spec.js
deleted file mode 100644
index ee396326f45..00000000000
--- a/spec/frontend/tracing/filters_spec.js
+++ /dev/null
@@ -1,141 +0,0 @@
-import {
- filterToQueryObject,
- urlQueryToFilter,
- prepareTokens,
- processFilters,
-} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
-import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
-
-import {
- PERIOD_FILTER_TOKEN_TYPE,
- SERVICE_NAME_FILTER_TOKEN_TYPE,
- OPERATION_FILTER_TOKEN_TYPE,
- TRACE_ID_FILTER_TOKEN_TYPE,
- DURATION_MS_FILTER_TOKEN_TYPE,
- queryToFilterObj,
- filterObjToQuery,
- filterObjToFilterToken,
- filterTokensToFilterObj,
-} from '~/tracing/filters';
-
-jest.mock('~/vue_shared/components/filtered_search_bar/filtered_search_utils');
-
-describe('utils', () => {
- describe('queryToFilterObj', () => {
- it('should build a filter obj', () => {
- const url = 'http://example.com/';
- urlQueryToFilter.mockReturnValue({
- period: '7d',
- service: 'my_service',
- operation: 'my_operation',
- trace_id: 'my_trace_id',
- durationMs: '500',
- [FILTERED_SEARCH_TERM]: 'test',
- });
-
- const filterObj = queryToFilterObj(url);
-
- expect(urlQueryToFilter).toHaveBeenCalledWith(url, {
- customOperators: [
- { operator: '>', prefix: 'gt' },
- { operator: '<', prefix: 'lt' },
- ],
- filteredSearchTermKey: 'search',
- });
- expect(filterObj).toEqual({
- period: '7d',
- service: 'my_service',
- operation: 'my_operation',
- traceId: 'my_trace_id',
- durationMs: '500',
- search: 'test',
- });
- });
- });
-
- describe('filterObjToQuery', () => {
- it('should convert filter object to URL query', () => {
- filterToQueryObject.mockReturnValue('mockquery');
-
- const query = filterObjToQuery({
- period: '7d',
- serviceName: 'my_service',
- operation: 'my_operation',
- traceId: 'my_trace_id',
- durationMs: '500',
- search: 'test',
- });
-
- expect(filterToQueryObject).toHaveBeenCalledWith(
- {
- period: '7d',
- service: 'my_service',
- operation: 'my_operation',
- trace_id: 'my_trace_id',
- durationMs: '500',
- 'filtered-search-term': 'test',
- },
- {
- customOperators: [
- { applyOnlyToKey: 'durationMs', operator: '>', prefix: 'gt' },
- { applyOnlyToKey: 'durationMs', operator: '<', prefix: 'lt' },
- ],
- filteredSearchTermKey: 'search',
- },
- );
- expect(query).toBe('mockquery');
- });
- });
-
- describe('filterObjToFilterToken', () => {
- it('should convert filter object to filter tokens', () => {
- const mockTokens = [];
- prepareTokens.mockReturnValue(mockTokens);
-
- const tokens = filterObjToFilterToken({
- period: '7d',
- serviceName: 'my_service',
- operation: 'my_operation',
- traceId: 'my_trace_id',
- durationMs: '500',
- search: 'test',
- });
-
- expect(prepareTokens).toHaveBeenCalledWith({
- [PERIOD_FILTER_TOKEN_TYPE]: '7d',
- [SERVICE_NAME_FILTER_TOKEN_TYPE]: 'my_service',
- [OPERATION_FILTER_TOKEN_TYPE]: 'my_operation',
- [TRACE_ID_FILTER_TOKEN_TYPE]: 'my_trace_id',
- [DURATION_MS_FILTER_TOKEN_TYPE]: '500',
- [FILTERED_SEARCH_TERM]: 'test',
- });
- expect(tokens).toBe(mockTokens);
- });
- });
-
- describe('filterTokensToFilterObj', () => {
- it('should convert filter tokens to filter object', () => {
- const mockTokens = [];
- processFilters.mockReturnValue({
- [SERVICE_NAME_FILTER_TOKEN_TYPE]: 'my_service',
- [PERIOD_FILTER_TOKEN_TYPE]: '7d',
- [OPERATION_FILTER_TOKEN_TYPE]: 'my_operation',
- [TRACE_ID_FILTER_TOKEN_TYPE]: 'my_trace_id',
- [DURATION_MS_FILTER_TOKEN_TYPE]: '500',
- [FILTERED_SEARCH_TERM]: 'test',
- });
-
- const filterObj = filterTokensToFilterObj(mockTokens);
-
- expect(processFilters).toHaveBeenCalledWith(mockTokens);
- expect(filterObj).toEqual({
- serviceName: 'my_service',
- period: '7d',
- operation: 'my_operation',
- traceId: 'my_trace_id',
- durationMs: '500',
- search: 'test',
- });
- });
- });
-});
diff --git a/spec/frontend/tracing/list_index_spec.js b/spec/frontend/tracing/list_index_spec.js
deleted file mode 100644
index a5759035c2f..00000000000
--- a/spec/frontend/tracing/list_index_spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import ListIndex from '~/tracing/list_index.vue';
-import TracingList from '~/tracing/components/tracing_list.vue';
-import ObservabilityContainer from '~/observability/components/observability_container.vue';
-
-describe('ListIndex', () => {
- const props = {
- oauthUrl: 'https://example.com/oauth',
- tracingUrl: 'https://example.com/tracing',
- provisioningUrl: 'https://example.com/provisioning',
- };
-
- let wrapper;
-
- const mountComponent = () => {
- wrapper = shallowMountExtended(ListIndex, {
- propsData: props,
- });
- };
-
- it('renders ObservabilityContainer component', () => {
- mountComponent();
-
- const observabilityContainer = wrapper.findComponent(ObservabilityContainer);
- expect(observabilityContainer.exists()).toBe(true);
- expect(observabilityContainer.props('oauthUrl')).toBe(props.oauthUrl);
- expect(observabilityContainer.props('tracingUrl')).toBe(props.tracingUrl);
- expect(observabilityContainer.props('provisioningUrl')).toBe(props.provisioningUrl);
- });
-
- it('renders TracingList component inside ObservabilityContainer', () => {
- mountComponent();
-
- const observabilityContainer = wrapper.findComponent(ObservabilityContainer);
- expect(observabilityContainer.findComponent(TracingList).exists()).toBe(true);
- });
-});
diff --git a/spec/frontend/tracking/dispatch_snowplow_event_spec.js b/spec/frontend/tracking/dispatch_snowplow_event_spec.js
new file mode 100644
index 00000000000..5f4d065d504
--- /dev/null
+++ b/spec/frontend/tracking/dispatch_snowplow_event_spec.js
@@ -0,0 +1,76 @@
+import * as Sentry from '@sentry/browser';
+
+import { dispatchSnowplowEvent } from '~/tracking/dispatch_snowplow_event';
+import getStandardContext from '~/tracking/get_standard_context';
+import { extraContext, servicePingContext } from './mock_data';
+
+jest.mock('@sentry/browser');
+jest.mock('~/tracking/get_standard_context');
+
+const category = 'Incident Management';
+const action = 'view_incident_details';
+
+describe('dispatchSnowplowEvent', () => {
+ const snowplowMock = jest.fn();
+ global.window.snowplow = snowplowMock;
+
+ const mockStandardContext = { some: 'context' };
+ getStandardContext.mockReturnValue(mockStandardContext);
+
+ beforeEach(() => {
+ snowplowMock.mockClear();
+ Sentry.captureException.mockClear();
+ });
+
+ it('calls snowplow trackStructEvent with correct arguments', () => {
+ const data = {
+ label: 'Show Incident',
+ property: 'click_event',
+ value: '12',
+ context: extraContext,
+ extra: { namespace: 'GitLab' },
+ };
+
+ dispatchSnowplowEvent(category, action, data);
+
+ expect(snowplowMock).toHaveBeenCalledWith('trackStructEvent', {
+ category,
+ action,
+ label: data.label,
+ property: data.property,
+ value: Number(data.value),
+ context: [mockStandardContext, data.context],
+ });
+ });
+
+ it('throws an error if no category is provided', () => {
+ expect(() => {
+ dispatchSnowplowEvent(undefined, 'some-action', {});
+ }).toThrow('Tracking: no category provided for tracking.');
+ });
+
+ it('handles an array of contexts', () => {
+ const data = {
+ context: [extraContext, servicePingContext],
+ extra: { namespace: 'GitLab' },
+ };
+
+ dispatchSnowplowEvent(category, action, data);
+
+ expect(snowplowMock).toHaveBeenCalledWith('trackStructEvent', {
+ category,
+ action,
+ context: [mockStandardContext, ...data.context],
+ });
+ });
+
+ it('handles Sentry error capturing', () => {
+ snowplowMock.mockImplementation(() => {
+ throw new Error('some error');
+ });
+
+ dispatchSnowplowEvent(category, action, {});
+
+ expect(Sentry.captureException).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/spec/frontend/tracking/internal_events_spec.js b/spec/frontend/tracking/internal_events_spec.js
index ca244c25b06..6e773fde4db 100644
--- a/spec/frontend/tracking/internal_events_spec.js
+++ b/spec/frontend/tracking/internal_events_spec.js
@@ -6,9 +6,11 @@ import {
GITLAB_INTERNAL_EVENT_CATEGORY,
SERVICE_PING_SCHEMA,
LOAD_INTERNAL_EVENTS_SELECTOR,
+ USER_CONTEXT_SCHEMA,
} from '~/tracking/constants';
import * as utils from '~/tracking/utils';
import { Tracker } from '~/tracking/tracker';
+import { extraContext } from './mock_data';
jest.mock('~/api', () => ({
trackInternalEvent: jest.fn(),
@@ -21,11 +23,11 @@ jest.mock('~/tracking/utils', () => ({
Tracker.enabled = jest.fn();
+const event = 'TestEvent';
+
describe('InternalEvents', () => {
describe('track_event', () => {
it('track_event calls API.trackInternalEvent with correct arguments', () => {
- const event = 'TestEvent';
-
InternalEvents.track_event(event);
expect(API.trackInternalEvent).toHaveBeenCalledTimes(1);
@@ -35,42 +37,65 @@ describe('InternalEvents', () => {
it('track_event calls tracking.event functions with correct arguments', () => {
const trackingSpy = mockTracking(GITLAB_INTERNAL_EVENT_CATEGORY, undefined, jest.spyOn);
- const event = 'TestEvent';
-
- InternalEvents.track_event(event);
+ InternalEvents.track_event(event, { context: extraContext });
expect(trackingSpy).toHaveBeenCalledTimes(1);
expect(trackingSpy).toHaveBeenCalledWith(GITLAB_INTERNAL_EVENT_CATEGORY, event, {
- context: {
- schema: SERVICE_PING_SCHEMA,
- data: {
- event_name: event,
- data_source: 'redis_hll',
+ context: [
+ {
+ schema: SERVICE_PING_SCHEMA,
+ data: {
+ event_name: event,
+ data_source: 'redis_hll',
+ },
},
- },
+ extraContext,
+ ],
});
});
});
describe('mixin', () => {
let wrapper;
+ const Component = {
+ template: `
+ <div>
+ <button data-testid="button1" @click="handleButton1Click">Button 1</button>
+ <button data-testid="button2" @click="handleButton2Click">Button 2</button>
+ </div>
+ `,
+ methods: {
+ handleButton1Click() {
+ this.track_event(event);
+ },
+ handleButton2Click() {
+ this.track_event(event, extraContext);
+ },
+ },
+ mixins: [InternalEvents.mixin()],
+ };
beforeEach(() => {
- const Component = {
- render() {},
- mixins: [InternalEvents.mixin()],
- };
wrapper = shallowMountExtended(Component);
});
- it('this.track_event function calls InternalEvent`s track function with an event', () => {
- const event = 'TestEvent';
+ it('this.track_event function calls InternalEvent`s track function with an event', async () => {
+ const trackEventSpy = jest.spyOn(InternalEvents, 'track_event');
+
+ await wrapper.findByTestId('button1').trigger('click');
+
+ expect(trackEventSpy).toHaveBeenCalledTimes(1);
+ expect(trackEventSpy).toHaveBeenCalledWith(event, {});
+ });
+
+ it("this.track_event function calls InternalEvent's track function with an event and data", async () => {
+ const data = extraContext;
const trackEventSpy = jest.spyOn(InternalEvents, 'track_event');
- wrapper.vm.track_event(event);
+ await wrapper.findByTestId('button2').trigger('click');
expect(trackEventSpy).toHaveBeenCalledTimes(1);
- expect(trackEventSpy).toHaveBeenCalledWith(event);
+ expect(trackEventSpy).toHaveBeenCalledWith(event, data);
});
});
@@ -145,4 +170,88 @@ describe('InternalEvents', () => {
});
});
});
+
+ describe('initBrowserSDK', () => {
+ beforeEach(() => {
+ window.glClient = {
+ setDocumentTitle: jest.fn(),
+ page: jest.fn(),
+ };
+ window.gl = {
+ environment: 'testing',
+ key: 'value',
+ };
+ window.gl.snowplowStandardContext = {
+ schema: 'iglu:com.gitlab/gitlab_standard',
+ data: {
+ environment: 'testing',
+ key: 'value',
+ google_analytics_id: '',
+ source: 'gitlab-javascript',
+ extra: {},
+ },
+ };
+ });
+
+ it('should not call setDocumentTitle or page methods when window.glClient is undefined', () => {
+ window.glClient = undefined;
+
+ InternalEvents.initBrowserSDK();
+
+ expect(window.glClient?.setDocumentTitle).toBeUndefined();
+ expect(window.glClient?.page).toBeUndefined();
+ });
+
+ it('should call setDocumentTitle and page methods on window.glClient when it is defined', () => {
+ const mockStandardContext = window.gl.snowplowStandardContext;
+ const userContext = {
+ schema: USER_CONTEXT_SCHEMA,
+ data: mockStandardContext?.data,
+ };
+
+ InternalEvents.initBrowserSDK();
+
+ expect(window.glClient.setDocumentTitle).toHaveBeenCalledWith('GitLab');
+ expect(window.glClient.page).toHaveBeenCalledWith({
+ title: 'GitLab',
+ context: [userContext],
+ });
+ });
+
+ it('should call page method with combined standard and experiment contexts', () => {
+ const mockStandardContext = window.gl.snowplowStandardContext;
+ const userContext = {
+ schema: USER_CONTEXT_SCHEMA,
+ data: mockStandardContext?.data,
+ };
+
+ InternalEvents.initBrowserSDK();
+
+ expect(window.glClient.page).toHaveBeenCalledWith({
+ title: 'GitLab',
+ context: [userContext],
+ });
+ });
+
+ it('should call setDocumentTitle and page methods with default data when window.gl is undefined', () => {
+ window.gl = undefined;
+
+ InternalEvents.initBrowserSDK();
+
+ expect(window.glClient.setDocumentTitle).toHaveBeenCalledWith('GitLab');
+ expect(window.glClient.page).toHaveBeenCalledWith({
+ title: 'GitLab',
+ context: [
+ {
+ schema: USER_CONTEXT_SCHEMA,
+ data: {
+ google_analytics_id: '',
+ source: 'gitlab-javascript',
+ extra: {},
+ },
+ },
+ ],
+ });
+ });
+ });
});
diff --git a/spec/frontend/tracking/mock_data.js b/spec/frontend/tracking/mock_data.js
new file mode 100644
index 00000000000..acde8676291
--- /dev/null
+++ b/spec/frontend/tracking/mock_data.js
@@ -0,0 +1,17 @@
+export const extraContext = {
+ schema: 'iglu:com.gitlab/design_management_context/jsonschema/1-0-0',
+ data: {
+ 'design-version-number': '1.0.0',
+ 'design-is-current-version': '1.0.0',
+ 'internal-object-referrer': 'https://gitlab.com',
+ 'design-collection-owner': 'GitLab',
+ },
+};
+
+export const servicePingContext = {
+ schema: 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-1',
+ data: {
+ event_name: 'track_incident_event',
+ data_source: 'redis_hll',
+ },
+};
diff --git a/spec/frontend/tracking/tracking_initialization_spec.js b/spec/frontend/tracking/tracking_initialization_spec.js
index 3c512cf73a7..2dc3c6ab41c 100644
--- a/spec/frontend/tracking/tracking_initialization_spec.js
+++ b/spec/frontend/tracking/tracking_initialization_spec.js
@@ -1,6 +1,6 @@
import { TRACKING_CONTEXT_SCHEMA } from '~/experimentation/constants';
import { getExperimentData, getAllExperimentContexts } from '~/experimentation/utils';
-import Tracking, { initUserTracking, initDefaultTrackers } from '~/tracking';
+import Tracking, { initUserTracking, initDefaultTrackers, InternalEvents } from '~/tracking';
import getStandardContext from '~/tracking/get_standard_context';
jest.mock('~/experimentation/utils', () => ({
@@ -15,6 +15,9 @@ describe('Tracking', () => {
let trackLoadEventsSpy;
let enableFormTracking;
let setAnonymousUrlsSpy;
+ let bindInternalEventDocumentSpy;
+ let trackInternalLoadEventsSpy;
+ let initBrowserSDKSpy;
beforeAll(() => {
window.gl = window.gl || {};
@@ -74,6 +77,15 @@ describe('Tracking', () => {
.spyOn(Tracking, 'enableFormTracking')
.mockImplementation(() => null);
setAnonymousUrlsSpy = jest.spyOn(Tracking, 'setAnonymousUrls').mockImplementation(() => null);
+ bindInternalEventDocumentSpy = jest
+ .spyOn(InternalEvents, 'bindInternalEventDocument')
+ .mockImplementation(() => null);
+ trackInternalLoadEventsSpy = jest
+ .spyOn(InternalEvents, 'trackInternalLoadEvents')
+ .mockImplementation(() => null);
+ initBrowserSDKSpy = jest
+ .spyOn(InternalEvents, 'initBrowserSDK')
+ .mockImplementation(() => null);
});
it('should activate features based on what has been enabled', () => {
@@ -117,6 +129,21 @@ describe('Tracking', () => {
expect(setAnonymousUrlsSpy).toHaveBeenCalled();
});
+ it('binds the document event handling for intenral events', () => {
+ initDefaultTrackers();
+ expect(bindInternalEventDocumentSpy).toHaveBeenCalled();
+ });
+
+ it('tracks page loaded events for internal events', () => {
+ initDefaultTrackers();
+ expect(trackInternalLoadEventsSpy).toHaveBeenCalled();
+ });
+
+ it('calls initBrowserSDKSpy', () => {
+ initDefaultTrackers();
+ expect(initBrowserSDKSpy).toHaveBeenCalled();
+ });
+
describe('when there are experiment contexts', () => {
const experimentContexts = [
{
diff --git a/spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js b/spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js
index 88ab51cf135..0ae01083a09 100644
--- a/spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js
+++ b/spec/frontend/usage_quotas/storage/components/project_storage_app_spec.js
@@ -5,7 +5,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import ProjectStorageApp from '~/usage_quotas/storage/components/project_storage_app.vue';
-import UsageGraph from '~/usage_quotas/storage/components/usage_graph.vue';
+import SectionedPercentageBar from '~/usage_quotas/components/sectioned_percentage_bar.vue';
import {
descendingStorageUsageSort,
getStorageTypesFromProjectStatistics,
@@ -56,7 +56,7 @@ describe('ProjectStorageApp', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findUsagePercentage = () => wrapper.findByTestId('total-usage');
- const findUsageGraph = () => wrapper.findComponent(UsageGraph);
+ const findSectionedPercentageBar = () => wrapper.findComponent(SectionedPercentageBar);
const findProjectDetailsTable = () => wrapper.findByTestId('usage-quotas-project-usage-details');
const findNamespaceDetailsTable = () =>
wrapper.findByTestId('usage-quotas-namespace-usage-details');
@@ -157,7 +157,7 @@ describe('ProjectStorageApp', () => {
});
});
- describe('rendering <usage-graph />', () => {
+ describe('rendering <sectioned-percentage-bar />', () => {
let mockApollo;
beforeEach(async () => {
@@ -168,16 +168,23 @@ describe('ProjectStorageApp', () => {
await waitForPromises();
});
- it('renders usage-graph component if project.statistics exists', () => {
- expect(findUsageGraph().exists()).toBe(true);
+ it('renders sectioned-percentage-bar component if project.statistics exists', () => {
+ expect(findSectionedPercentageBar().exists()).toBe(true);
});
- it('passes project.statistics to usage-graph component', () => {
- const {
- __typename,
- ...statistics
- } = mockGetProjectStorageStatisticsGraphQLResponse.data.project.statistics;
- expect(findUsageGraph().props('rootStorageStatistics')).toMatchObject(statistics);
+ it('passes processed project statistics to sectioned-percentage-bar component', () => {
+ expect(findSectionedPercentageBar().props('sections')).toMatchObject([
+ { formattedValue: '4.58 MiB', id: 'lfsObjects', label: 'LFS', value: 4800000 },
+ { formattedValue: '3.72 MiB', id: 'repository', label: 'Repository', value: 3900000 },
+ { formattedValue: '3.62 MiB', id: 'packages', label: 'Packages', value: 3800000 },
+ {
+ formattedValue: '390.63 KiB',
+ id: 'buildArtifacts',
+ label: 'Job artifacts',
+ value: 400000,
+ },
+ { formattedValue: '292.97 KiB', id: 'wiki', label: 'Wiki', value: 300000 },
+ ]);
});
});
});
diff --git a/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js b/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js
deleted file mode 100644
index fc116211bf0..00000000000
--- a/spec/frontend/usage_quotas/storage/components/usage_graph_spec.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { numberToHumanSize } from '~/lib/utils/number_utils';
-import UsageGraph from '~/usage_quotas/storage/components/usage_graph.vue';
-
-let data;
-let wrapper;
-
-function mountComponent({ rootStorageStatistics, limit }) {
- wrapper = shallowMount(UsageGraph, {
- propsData: {
- rootStorageStatistics,
- limit,
- },
- });
-}
-function findStorageTypeUsagesSerialized() {
- return wrapper
- .findAll('[data-testid="storage-type-usage"]')
- .wrappers.map((wp) => wp.element.style.flex);
-}
-
-describe('UsageGraph', () => {
- beforeEach(() => {
- data = {
- rootStorageStatistics: {
- wikiSize: 5000,
- repositorySize: 4000,
- packagesSize: 3000,
- containerRegistrySize: 2500,
- lfsObjectsSize: 2000,
- buildArtifactsSize: 700,
- snippetsSize: 2000,
- storageSize: 17000,
- },
- limit: 2000,
- };
- mountComponent(data);
- });
-
- it('renders the legend in order', () => {
- const types = wrapper.findAll('[data-testid="storage-type-legend"]');
-
- const {
- buildArtifactsSize,
- lfsObjectsSize,
- packagesSize,
- repositorySize,
- wikiSize,
- snippetsSize,
- } = data.rootStorageStatistics;
-
- expect(types.at(0).text()).toMatchInterpolatedText(`Wiki ${numberToHumanSize(wikiSize)}`);
- expect(types.at(1).text()).toMatchInterpolatedText(
- `Repository ${numberToHumanSize(repositorySize)}`,
- );
- expect(types.at(2).text()).toMatchInterpolatedText(
- `Packages ${numberToHumanSize(packagesSize)}`,
- );
- expect(types.at(3).text()).toMatchInterpolatedText(`LFS ${numberToHumanSize(lfsObjectsSize)}`);
- expect(types.at(4).text()).toMatchInterpolatedText(
- `Snippets ${numberToHumanSize(snippetsSize)}`,
- );
- expect(types.at(5).text()).toMatchInterpolatedText(
- `Job artifacts ${numberToHumanSize(buildArtifactsSize)}`,
- );
- });
-
- describe('when storage type is not used', () => {
- beforeEach(() => {
- data.rootStorageStatistics.wikiSize = 0;
- mountComponent(data);
- });
-
- it('filters the storage type', () => {
- expect(wrapper.text()).not.toContain('Wikis');
- });
- });
-
- describe('when there is no storage usage', () => {
- beforeEach(() => {
- data.rootStorageStatistics.storageSize = 0;
- mountComponent(data);
- });
-
- it('does not render', () => {
- expect(wrapper.html()).toEqual('');
- });
- });
-
- describe('when limit is 0', () => {
- beforeEach(() => {
- data.limit = 0;
- mountComponent(data);
- });
-
- it('sets correct flex values', () => {
- expect(findStorageTypeUsagesSerialized()).toStrictEqual([
- '0.29411764705882354',
- '0.23529411764705882',
- '0.17647058823529413',
- '0.11764705882352941',
- '0.11764705882352941',
- '0.041176470588235294',
- ]);
- });
- });
-
- describe('when storage exceeds limit', () => {
- beforeEach(() => {
- data.limit = data.rootStorageStatistics.storageSize - 1;
- mountComponent(data);
- });
-
- it('does render correclty', () => {
- expect(findStorageTypeUsagesSerialized()).toStrictEqual([
- '0.29411764705882354',
- '0.23529411764705882',
- '0.17647058823529413',
- '0.11764705882352941',
- '0.11764705882352941',
- '0.041176470588235294',
- ]);
- });
- });
-});
diff --git a/spec/frontend/user_lists/components/user_list_spec.js b/spec/frontend/user_lists/components/user_list_spec.js
index 286fb9fef5f..0ed21114778 100644
--- a/spec/frontend/user_lists/components/user_list_spec.js
+++ b/spec/frontend/user_lists/components/user_list_spec.js
@@ -169,7 +169,7 @@ describe('User List', () => {
it('displays the alert message', () => {
const alert = findAlert();
- expect(alert.text()).toBe('Something went wrong on our end. Please try again!');
+ expect(alert.text()).toBe('Unable to load user list. Reload the page and try again.');
});
it('can dismiss the alert', async () => {
diff --git a/spec/frontend/users_select/test_helper.js b/spec/frontend/users_select/test_helper.js
index b38400446a9..5aae922fec2 100644
--- a/spec/frontend/users_select/test_helper.js
+++ b/spec/frontend/users_select/test_helper.js
@@ -70,7 +70,8 @@ export const findDropdownItemsModel = () =>
return {
type: 'divider',
};
- } else if (el.classList.contains('dropdown-header')) {
+ }
+ if (el.classList.contains('dropdown-header')) {
return {
type: 'dropdown-header',
text: el.textContent,
diff --git a/spec/frontend/vue_merge_request_widget/components/action_buttons.js b/spec/frontend/vue_merge_request_widget/components/action_buttons.js
deleted file mode 100644
index 7334f061dc9..00000000000
--- a/spec/frontend/vue_merge_request_widget/components/action_buttons.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { GlButton, GlDropdownItem } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Actions from '~/vue_merge_request_widget/components/action_buttons.vue';
-
-let wrapper;
-
-function factory(propsData = {}) {
- wrapper = shallowMount(Actions, {
- propsData: { ...propsData, widget: 'test' },
- });
-}
-
-describe('MR widget extension actions', () => {
- describe('tertiaryButtons', () => {
- it('renders buttons', () => {
- factory({
- tertiaryButtons: [{ text: 'hello world', href: 'https://gitlab.com', target: '_blank' }],
- });
-
- expect(wrapper.findAllComponents(GlButton)).toHaveLength(1);
- });
-
- it('calls action click handler', async () => {
- const onClick = jest.fn();
-
- factory({
- tertiaryButtons: [{ text: 'hello world', onClick }],
- });
-
- await wrapper.findComponent(GlButton).vm.$emit('click');
-
- expect(onClick).toHaveBeenCalled();
- });
-
- it('renders tertiary actions in dropdown', () => {
- factory({
- tertiaryButtons: [{ text: 'hello world', href: 'https://gitlab.com', target: '_blank' }],
- });
-
- expect(wrapper.findAllComponents(GlDropdownItem)).toHaveLength(1);
- });
- });
-});
diff --git a/spec/frontend/vue_merge_request_widget/components/action_buttons_spec.js b/spec/frontend/vue_merge_request_widget/components/action_buttons_spec.js
new file mode 100644
index 00000000000..02e23b81413
--- /dev/null
+++ b/spec/frontend/vue_merge_request_widget/components/action_buttons_spec.js
@@ -0,0 +1,61 @@
+import { GlButton, GlDisclosureDropdown } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Actions from '~/vue_merge_request_widget/components/action_buttons.vue';
+
+let wrapper;
+
+function factory(propsData = {}) {
+ wrapper = shallowMount(Actions, {
+ propsData,
+ });
+}
+
+describe('MR widget extension actions', () => {
+ describe('tertiaryButtons', () => {
+ it('renders buttons', () => {
+ factory({
+ tertiaryButtons: [{ text: 'hello world', href: 'https://gitlab.com', target: '_blank' }],
+ });
+
+ expect(wrapper.findAllComponents(GlButton)).toHaveLength(1);
+ });
+
+ it('calls action click handler', async () => {
+ const onClick = jest.fn();
+
+ factory({
+ tertiaryButtons: [{ text: 'hello world', onClick }],
+ });
+
+ await wrapper.findComponent(GlButton).vm.$emit('click');
+
+ expect(onClick).toHaveBeenCalled();
+ });
+
+ it('renders tertiary actions in dropdown', () => {
+ const action = { text: 'hello world', href: 'https://gitlab.com', target: '_blank' };
+ factory({
+ tertiaryButtons: [action, action],
+ });
+
+ const component = wrapper.findComponent(GlDisclosureDropdown);
+ expect(component.exists()).toBe(true);
+ expect(component.props('items')).toMatchObject([
+ {
+ text: action.text,
+ href: action.href,
+ extraAttrs: {
+ target: action.target,
+ },
+ },
+ {
+ text: action.text,
+ href: action.href,
+ extraAttrs: {
+ target: action.target,
+ },
+ },
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js
index a0064224b46..35b4e222e01 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js
@@ -6,7 +6,7 @@ import { trimText } from 'helpers/text_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import MRWidgetPipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
-import LegacyPipelineMiniGraph from '~/pipelines/components/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
+import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
import { SUCCESS } from '~/vue_merge_request_widget/constants';
import mockData from '../mock_data';
diff --git a/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/new_ready_to_merge_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/new_ready_to_merge_spec.js.snap
index f9936f22ea3..ecf4040cbda 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/new_ready_to_merge_spec.js.snap
+++ b/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/new_ready_to_merge_spec.js.snap
@@ -2,36 +2,30 @@
exports[`New ready to merge state component renders permission text if canMerge (false) is false 1`] = `
<div
- class="mr-widget-body media"
+ class="media mr-widget-body"
>
<status-icon-stub
status="success"
/>
-
<p
- class="media-body gl-m-0! gl-font-weight-bold gl-text-gray-900!"
+ class="gl-font-weight-bold gl-m-0! gl-text-gray-900! media-body"
>
-
- Ready to merge by members who can write to the target branch.
-
+ Ready to merge by members who can write to the target branch.
</p>
</div>
`;
exports[`New ready to merge state component renders permission text if canMerge (true) is false 1`] = `
<div
- class="mr-widget-body media"
+ class="media mr-widget-body"
>
<status-icon-stub
status="success"
/>
-
<p
- class="media-body gl-m-0! gl-font-weight-bold gl-text-gray-900!"
+ class="gl-font-weight-bold gl-m-0! gl-text-gray-900! media-body"
>
-
- Ready to merge!
-
+ Ready to merge!
</p>
</div>
`;
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js
index e44e2834a0e..5efb1dcce42 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_merged_spec.js
@@ -1,4 +1,4 @@
-import { getByRole } from '@testing-library/dom';
+import { getAllByRole } from '@testing-library/dom';
import { nextTick } from 'vue';
import { mount } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises';
@@ -132,7 +132,7 @@ describe('MRWidgetMerged', () => {
createComponent();
const eventHubSpy = jest.spyOn(modalEventHub, '$emit');
- getByRole(wrapper.element, 'button', { name: /Revert/i }).click();
+ getAllByRole(wrapper.element, 'button', { name: /Revert/i })[0].click();
expect(eventHubSpy).toHaveBeenCalledWith(OPEN_REVERT_MODAL);
});
@@ -141,7 +141,7 @@ describe('MRWidgetMerged', () => {
createComponent();
const eventHubSpy = jest.spyOn(modalEventHub, '$emit');
- getByRole(wrapper.element, 'button', { name: /Cherry-pick/i }).click();
+ getAllByRole(wrapper.element, 'button', { name: /Cherry-pick/i })[0].click();
expect(eventHubSpy).toHaveBeenCalledWith(OPEN_CHERRY_PICK_MODAL);
});
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap
index ce4bf11f16b..d5d3f56e451 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap
+++ b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap
@@ -1,63 +1,133 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue renders given data 1`] = `
-"<div class=\\"gl-display-flex gl-border-t gl-py-3 gl-pl-7 gl-align-items-baseline\\">
- <!---->
- <div class=\\"gl-w-full gl-min-w-0\\">
- <div class=\\"gl-display-flex\\">
- <div class=\\"gl-mb-2\\"><strong class=\\"gl-display-block\\">This is a header</strong><span class=\\"gl-display-block\\">This is a subheader</span></div>
- <div class=\\"gl-ml-auto gl-display-flex gl-align-items-baseline\\">
- <help-popover-stub options=\\"[object Object]\\" icon=\\"information-o\\" triggerclass=\\"\\" class=\\"\\">
- <p class=\\"gl-mb-0\\">Widget help popover content</p>
- <!---->
+<div
+ class="gl-align-items-baseline gl-border-t gl-display-flex gl-pl-7 gl-py-3"
+>
+ <div
+ class="gl-min-w-0 gl-w-full"
+ >
+ <div
+ class="gl-display-flex"
+ >
+ <div
+ class="gl-mb-2"
+ >
+ <strong
+ class="gl-display-block"
+ >
+ This is a header
+ </strong>
+ <span
+ class="gl-display-block"
+ >
+ This is a subheader
+ </span>
+ </div>
+ <div
+ class="gl-align-items-baseline gl-display-flex gl-ml-auto"
+ >
+ <help-popover-stub
+ icon="information-o"
+ options="[object Object]"
+ triggerclass=""
+ >
+ <p
+ class="gl-mb-0"
+ >
+ Widget help popover content
+ </p>
</help-popover-stub>
- <!---->
</div>
</div>
- <div class=\\"gl-display-flex gl-align-items-baseline\\">
- <status-icon-stub level=\\"2\\" name=\\"MyWidget\\" iconname=\\"success\\"></status-icon-stub>
- <div class=\\"gl-w-full gl-display-flex\\">
- <div class=\\"gl-display-flex gl-flex-grow-1\\">
- <div class=\\"gl-display-flex gl-flex-grow-1 gl-align-items-baseline\\">
+ <div
+ class="gl-align-items-baseline gl-display-flex"
+ >
+ <status-icon-stub
+ iconname="success"
+ level="2"
+ name="MyWidget"
+ />
+ <div
+ class="gl-display-flex gl-w-full"
+ >
+ <div
+ class="gl-display-flex gl-flex-grow-1"
+ >
+ <div
+ class="gl-align-items-baseline gl-display-flex gl-flex-grow-1"
+ >
<div>
- <p class=\\"gl-mb-0 gl-mr-1\\">Main text for the row</p>
- <gl-link-stub href=\\"https://gitlab.com\\">Optional link to display after text</gl-link-stub>
- <!---->
+ <p
+ class="gl-mb-0 gl-mr-1"
+ >
+ Main text for the row
+ </p>
+ <gl-link-stub
+ href="https://gitlab.com"
+ >
+ Optional link to display after text
+ </gl-link-stub>
</div>
- <gl-badge-stub size=\\"md\\" variant=\\"info\\" iconsize=\\"md\\">
+ <gl-badge-stub
+ iconsize="md"
+ size="md"
+ variant="info"
+ >
Badge is optional. Text to be displayed inside badge
</gl-badge-stub>
</div>
- <!---->
- <p class=\\"gl-m-0 gl-font-sm\\">Optional: Smaller sub-text to be displayed below the main text</p>
+ <p
+ class="gl-font-sm gl-m-0"
+ >
+ Optional: Smaller sub-text to be displayed below the main text
+ </p>
</div>
- <ul class=\\"gl-m-0 gl-p-0 gl-list-style-none\\">
+ <ul
+ class="gl-list-style-none gl-m-0 gl-p-0"
+ >
<li>
- <div class=\\"gl-display-flex gl-align-items-center\\" data-qa-selector=\\"child_content\\">
- <!---->
- <div class=\\"gl-w-full gl-min-w-0\\">
- <div class=\\"gl-display-flex\\">
- <div class=\\"gl-mb-2\\"><strong class=\\"gl-display-block\\">Child row header</strong>
- <!---->
+ <div
+ class="gl-align-items-center gl-display-flex"
+ data-qa-selector="child_content"
+ >
+ <div
+ class="gl-min-w-0 gl-w-full"
+ >
+ <div
+ class="gl-display-flex"
+ >
+ <div
+ class="gl-mb-2"
+ >
+ <strong
+ class="gl-display-block"
+ >
+ Child row header
+ </strong>
</div>
- <!---->
</div>
- <div class=\\"gl-display-flex gl-align-items-baseline\\">
- <!---->
- <div class=\\"gl-w-full gl-display-flex\\">
- <div class=\\"gl-display-flex gl-flex-grow-1\\">
- <div class=\\"gl-display-flex gl-flex-grow-1 gl-align-items-baseline\\">
+ <div
+ class="gl-align-items-baseline gl-display-flex"
+ >
+ <div
+ class="gl-display-flex gl-w-full"
+ >
+ <div
+ class="gl-display-flex gl-flex-grow-1"
+ >
+ <div
+ class="gl-align-items-baseline gl-display-flex gl-flex-grow-1"
+ >
<div>
- <p class=\\"gl-mb-0 gl-mr-1\\">This is recursive. It will be listed in level 3.</p>
- <!---->
- <!---->
+ <p
+ class="gl-mb-0 gl-mr-1"
+ >
+ This is recursive. It will be listed in level 3.
+ </p>
</div>
- <!---->
</div>
- <!---->
- <!---->
</div>
- <!---->
</div>
</div>
</div>
@@ -67,5 +137,5 @@ exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue render
</div>
</div>
</div>
-</div>"
+</div>
`;
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js
index bf318cd6b88..205824c3edd 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/widget/app_spec.js
@@ -1,13 +1,23 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import App from '~/vue_merge_request_widget/components/widget/app.vue';
+import MrSecurityWidgetCE from '~/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue';
+import MrTestReportWidget from '~/vue_merge_request_widget/extensions/test_report/index.vue';
+import MrTerraformWidget from '~/vue_merge_request_widget/extensions/terraform/index.vue';
+import MrCodeQualityWidget from '~/vue_merge_request_widget/extensions/code_quality/index.vue';
describe('MR Widget App', () => {
let wrapper;
- const createComponent = () => {
+ const createComponent = ({ mr = {} } = {}) => {
wrapper = shallowMountExtended(App, {
propsData: {
- mr: {},
+ mr: {
+ pipeline: {
+ path: '/path/to/pipeline',
+ },
+ ...mr,
+ },
},
});
};
@@ -16,4 +26,35 @@ describe('MR Widget App', () => {
createComponent();
expect(wrapper.findByTestId('mr-widget-app').exists()).toBe(true);
});
+
+ describe('MRSecurityWidget', () => {
+ it('mounts MrSecurityWidgetCE', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(wrapper.findComponent(MrSecurityWidgetCE).exists()).toBe(true);
+ });
+ });
+
+ describe.each`
+ widgetName | widget | endpoint
+ ${'testReportWidget'} | ${MrTestReportWidget} | ${'testResultsPath'}
+ ${'terraformPlansWidget'} | ${MrTerraformWidget} | ${'terraformReportsPath'}
+ ${'codeQualityWidget'} | ${MrCodeQualityWidget} | ${'codequalityReportsPath'}
+ `('$widgetName', ({ widget, endpoint }) => {
+ it(`is mounted when ${endpoint} is defined`, async () => {
+ createComponent({ mr: { [endpoint]: `path/to/${endpoint}` } });
+ await waitForPromises();
+
+ expect(wrapper.findComponent(widget).exists()).toBe(true);
+ });
+
+ it(`is not mounted when ${endpoint} is not defined`, async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(wrapper.findComponent(widget).exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js
index b901b80e8bf..6f5e08a0829 100644
--- a/spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js
+++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js
@@ -2,7 +2,6 @@ import { mount } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
-import { visitUrl } from '~/lib/utils/url_utility';
import {
CREATED,
MANUAL_DEPLOY,
@@ -20,6 +19,7 @@ import {
deploymentMockData,
playDetails,
retryDetails,
+ mockRedeployProps,
} from './deployment_mock_data';
jest.mock('~/alert');
@@ -36,7 +36,6 @@ describe('DeploymentAction component', () => {
const findStopButton = () => wrapper.find('.js-stop-env');
const findDeployButton = () => wrapper.find('.js-manual-deploy-action');
- const findManualRedeployButton = () => wrapper.find('.js-manual-redeploy-action');
const findRedeployButton = () => wrapper.find('.js-redeploy-action');
beforeEach(() => {
@@ -78,23 +77,25 @@ describe('DeploymentAction component', () => {
expect(findDeployButton().exists()).toBe(false);
});
});
-
- describe('when there is no retry_path in details', () => {
- it('the manual redeploy button does not appear', () => {
- expect(findManualRedeployButton().exists()).toBe(false);
- });
- });
});
describe('when conditions are met', () => {
describe.each`
- configConst | computedDeploymentStatus | displayConditionChanges | finderFn | endpoint
- ${STOPPING} | ${CREATED} | ${{}} | ${findStopButton} | ${deploymentMockData.stop_url}
- ${DEPLOYING} | ${MANUAL_DEPLOY} | ${playDetails} | ${findDeployButton} | ${playDetails.playable_build.play_path}
- ${REDEPLOYING} | ${FAILED} | ${retryDetails} | ${findManualRedeployButton} | ${retryDetails.playable_build.retry_path}
+ configConst | computedDeploymentStatus | displayConditionChanges | finderFn | endpoint | props
+ ${STOPPING} | ${CREATED} | ${{}} | ${findStopButton} | ${deploymentMockData.stop_url} | ${{}}
+ ${DEPLOYING} | ${MANUAL_DEPLOY} | ${playDetails} | ${findDeployButton} | ${playDetails.playable_build.play_path} | ${{}}
+ ${REDEPLOYING} | ${FAILED} | ${{}} | ${findRedeployButton} | ${retryDetails.playable_build.retry_path} | ${mockRedeployProps}
+ ${REDEPLOYING} | ${SUCCESS} | ${{}} | ${findRedeployButton} | ${retryDetails.playable_build.retry_path} | ${mockRedeployProps}
`(
'$configConst action',
- ({ configConst, computedDeploymentStatus, displayConditionChanges, finderFn, endpoint }) => {
+ ({
+ configConst,
+ computedDeploymentStatus,
+ displayConditionChanges,
+ finderFn,
+ endpoint,
+ props,
+ }) => {
describe(`${configConst} action`, () => {
beforeEach(() => {
factory({
@@ -103,6 +104,7 @@ describe('DeploymentAction component', () => {
deployment: {
...deploymentMockData,
details: displayConditionChanges,
+ ...props,
},
},
});
@@ -163,25 +165,6 @@ describe('DeploymentAction component', () => {
expect(createAlert).not.toHaveBeenCalled();
});
- describe('response includes redirect_url', () => {
- const url = '/root/example';
- beforeEach(async () => {
- executeActionSpy.mockResolvedValueOnce({
- data: { redirect_url: url },
- });
-
- await waitForPromises();
-
- confirmAction.mockResolvedValueOnce(true);
- finderFn().trigger('click');
- });
-
- it('calls visit url with the redirect_url', () => {
- expect(visitUrl).toHaveBeenCalled();
- expect(visitUrl).toHaveBeenCalledWith(url);
- });
- });
-
describe('it should call the executeAction method', () => {
beforeEach(async () => {
jest.spyOn(wrapper.vm, 'executeAction').mockImplementation();
@@ -234,7 +217,7 @@ describe('DeploymentAction component', () => {
);
});
- describe('with the reviewAppsRedeployMrWidget feature flag turned on', () => {
+ describe('redeploy action', () => {
beforeEach(() => {
factory({
propsData: {
@@ -246,11 +229,6 @@ describe('DeploymentAction component', () => {
environment_available: false,
},
},
- provide: {
- glFeatures: {
- reviewAppsRedeployMrWidget: true,
- },
- },
});
});
@@ -304,24 +282,6 @@ describe('DeploymentAction component', () => {
expect(createAlert).not.toHaveBeenCalled();
});
- describe('response includes redirect_url', () => {
- const url = '/root/example';
- beforeEach(async () => {
- executeActionSpy.mockResolvedValueOnce({
- data: { redirect_url: url },
- });
-
- await waitForPromises();
-
- confirmAction.mockResolvedValueOnce(true);
- findRedeployButton().trigger('click');
- });
-
- it('does not call visit url', () => {
- expect(visitUrl).not.toHaveBeenCalled();
- });
- });
-
describe('it should call the executeAction method', () => {
beforeEach(async () => {
jest.spyOn(wrapper.vm, 'executeAction').mockImplementation();
diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js
index 374fe4e1b95..2c6a40c6e16 100644
--- a/spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js
+++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js
@@ -74,4 +74,9 @@ const retryDetails = {
},
};
-export { actionButtonMocks, deploymentMockData, playDetails, retryDetails };
+const mockRedeployProps = {
+ retry_url: retryDetails.playable_build.retry_path,
+ environment_available: false,
+};
+
+export { actionButtonMocks, deploymentMockData, playDetails, retryDetails, mockRedeployProps };
diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js
index 234491c531a..0a96feb184f 100644
--- a/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js
+++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js
@@ -10,7 +10,12 @@ import {
import DeploymentComponent from '~/vue_merge_request_widget/components/deployment/deployment.vue';
import DeploymentInfo from '~/vue_merge_request_widget/components/deployment/deployment_info.vue';
import DeploymentViewButton from '~/vue_merge_request_widget/components/deployment/deployment_view_button.vue';
-import { deploymentMockData, playDetails, retryDetails } from './deployment_mock_data';
+import {
+ deploymentMockData,
+ playDetails,
+ retryDetails,
+ mockRedeployProps,
+} from './deployment_mock_data';
describe('Deployment component', () => {
let wrapper;
@@ -46,7 +51,6 @@ describe('Deployment component', () => {
};
const defaultGroup = ['.js-deploy-url', '.js-stop-env'];
const manualDeployGroup = ['.js-manual-deploy-action', ...defaultGroup];
- const manualRedeployGroup = ['.js-manual-redeploy-action', ...defaultGroup];
describe.each`
status | previous | deploymentDetails | text | actionButtons
@@ -62,7 +66,7 @@ describe('Deployment component', () => {
${SUCCESS} | ${true} | ${noDetails} | ${'Deployed to'} | ${defaultGroup}
${SUCCESS} | ${false} | ${deployDetail} | ${'Deployed to'} | ${defaultGroup}
${SUCCESS} | ${false} | ${noDetails} | ${'Deployed to'} | ${defaultGroup}
- ${FAILED} | ${true} | ${retryDetail} | ${'Failed to deploy to'} | ${manualRedeployGroup}
+ ${FAILED} | ${true} | ${retryDetail} | ${'Failed to deploy to'} | ${defaultGroup}
${FAILED} | ${true} | ${noDetails} | ${'Failed to deploy to'} | ${defaultGroup}
${FAILED} | ${false} | ${retryDetail} | ${'Failed to deploy to'} | ${noActions}
${FAILED} | ${false} | ${noDetails} | ${'Failed to deploy to'} | ${noActions}
@@ -139,6 +143,27 @@ describe('Deployment component', () => {
}
},
);
+
+ describe('redeploy action', () => {
+ beforeEach(() => {
+ factory({
+ propsData: {
+ showMetrics: false,
+ deployment: {
+ ...deploymentMockData,
+ ...mockRedeployProps,
+ },
+ },
+ });
+ });
+
+ it('shows only the redeploy button', () => {
+ expect(wrapper.find('.js-redeploy-action').exists()).toBe(true);
+ expect(wrapper.find('.js-deploy-url').exists()).toBe(false);
+ expect(wrapper.find('.js-stop-env').exists()).toBe(false);
+ expect(wrapper.find('.js-manual-deploy-action').exists()).toBe(false);
+ });
+ });
});
describe('hasExternalUrls', () => {
diff --git a/spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js b/spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js
index d2d622d0534..88c348629cb 100644
--- a/spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extensions/test_report/index_spec.js
@@ -1,19 +1,17 @@
import { nextTick } from 'vue';
import MockAdapter from 'axios-mock-adapter';
-import testReportExtension from '~/vue_merge_request_widget/extensions/test_report';
+import testReportExtension from '~/vue_merge_request_widget/extensions/test_report/index.vue';
import { i18n } from '~/vue_merge_request_widget/extensions/test_report/constants';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { trimText } from 'helpers/text_helper';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
-import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container';
-import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
import {
HTTP_STATUS_INTERNAL_SERVER_ERROR,
HTTP_STATUS_NO_CONTENT,
HTTP_STATUS_OK,
} from '~/lib/utils/http_status';
-import TestCaseDetails from '~/pipelines/components/test_reports/test_case_details.vue';
+import TestCaseDetails from '~/ci/pipeline_details/test_reports/test_case_details.vue';
import { failedReport } from 'jest/ci/reports/mock_data/mock_data';
import mixedResultsTestReports from 'jest/ci/reports/mock_data/new_and_fixed_failures_report.json';
@@ -34,12 +32,10 @@ describe('Test report extension', () => {
let wrapper;
let mock;
- registerExtension(testReportExtension);
-
const endpoint = '/root/repo/-/merge_requests/4/test_reports.json';
const mockApi = (statusCode, data = mixedResultsTestReports) => {
- mock.onGet(endpoint).reply(statusCode, data);
+ mock.onGet(endpoint).reply(statusCode, data, {});
};
const findToggleCollapsedButton = () => wrapper.findByTestId('toggle-button');
@@ -49,7 +45,7 @@ describe('Test report extension', () => {
const findModal = () => wrapper.findComponent(TestCaseDetails);
const createComponent = () => {
- wrapper = mountExtended(extensionsContainer, {
+ wrapper = mountExtended(testReportExtension, {
propsData: {
mr: {
testResultsPath: endpoint,
@@ -84,7 +80,7 @@ describe('Test report extension', () => {
expect(wrapper.text()).toContain(i18n.loading);
});
- it('with a 204 response, continues to display loading state', async () => {
+ it('with a "no content" response, continues to display loading state', async () => {
mockApi(HTTP_STATUS_NO_CONTENT, '');
createComponent();
@@ -269,7 +265,7 @@ describe('Test report extension', () => {
beforeEach(async () => {
await createExpandedWidgetWithData();
- wrapper.findByTestId('modal-link').trigger('click');
+ wrapper.findByTestId('extension-actions-button').trigger('click');
});
it('opens a modal to display test case details', () => {
diff --git a/spec/frontend/vue_merge_request_widget/mock_data.js b/spec/frontend/vue_merge_request_widget/mock_data.js
index 5b3f533f34e..34f147307fc 100644
--- a/spec/frontend/vue_merge_request_widget/mock_data.js
+++ b/spec/frontend/vue_merge_request_widget/mock_data.js
@@ -352,7 +352,7 @@ export default {
merge_request_widget_path: '/root/acets-app/-/merge_requests/22/widget.json',
merge_request_cached_widget_path: '/cached.json',
merge_check_path: '/root/acets-app/-/merge_requests/22/merge_check',
- ci_environments_status_url: '/root/acets-app/-/merge_requests/22/ci_environments_status',
+ ci_environments_status_path: '/root/acets-app/-/merge_requests/22/ci_environments_status',
project_archived: false,
default_merge_commit_message_with_description:
"Merge branch 'daaaa' into 'main'\n\nUpdate README.md\n\nSee merge request !22",
@@ -452,3 +452,169 @@ export const mockStore = {
hasCI: true,
exposedArtifactsPath: 'exposed_artifacts.json',
};
+
+export const mockMergePipeline = {
+ id: 127,
+ user: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url: null,
+ web_url: 'http://localhost:3000/root',
+ status_tooltip_html: null,
+ path: '/root',
+ },
+ active: true,
+ coverage: null,
+ source: 'push',
+ created_at: '2018-10-22T11:41:35.186Z',
+ updated_at: '2018-10-22T11:41:35.433Z',
+ path: '/root/ci-web-terminal/pipelines/127',
+ flags: {
+ latest: true,
+ stuck: true,
+ auto_devops: false,
+ yaml_errors: false,
+ retryable: false,
+ cancelable: true,
+ failure_reason: false,
+ },
+ details: {
+ status: {
+ icon: 'status_pending',
+ text: 'pending',
+ label: 'pending',
+ group: 'pending',
+ tooltip: 'pending',
+ has_details: true,
+ details_path: '/root/ci-web-terminal/pipelines/127',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
+ },
+ duration: null,
+ finished_at: null,
+ stages: [
+ {
+ name: 'test',
+ title: 'test: pending',
+ status: {
+ icon: 'status_pending',
+ text: 'pending',
+ label: 'pending',
+ group: 'pending',
+ tooltip: 'pending',
+ has_details: true,
+ details_path: '/root/ci-web-terminal/pipelines/127#test',
+ illustration: null,
+ favicon:
+ '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
+ },
+ path: '/root/ci-web-terminal/pipelines/127#test',
+ dropdown_path: '/root/ci-web-terminal/pipelines/127/stage.json?stage=test',
+ },
+ ],
+ artifacts: [],
+ manual_actions: [],
+ scheduled_actions: [],
+ },
+ ref: {
+ name: 'main',
+ path: '/root/ci-web-terminal/commits/main',
+ tag: false,
+ branch: true,
+ },
+ commit: {
+ id: 'aa1939133d373c94879becb79d91828a892ee319',
+ short_id: 'aa193913',
+ title: "Merge branch 'main-test' into 'main'",
+ created_at: '2018-10-22T11:41:33.000Z',
+ parent_ids: [
+ '4622f4dd792468993003caf2e3be978798cbe096',
+ '76598df914cdfe87132d0c3c40f80db9fa9396a4',
+ ],
+ message:
+ "Merge branch 'main-test' into 'main'\n\nUpdate .gitlab-ci.yml\n\nSee merge request root/ci-web-terminal!1",
+ author_name: 'Administrator',
+ author_email: 'admin@example.com',
+ authored_date: '2018-10-22T11:41:33.000Z',
+ committer_name: 'Administrator',
+ committer_email: 'admin@example.com',
+ committed_date: '2018-10-22T11:41:33.000Z',
+ author: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url: null,
+ web_url: 'http://localhost:3000/root',
+ status_tooltip_html: null,
+ path: '/root',
+ },
+ author_gravatar_url: null,
+ commit_url:
+ 'http://localhost:3000/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319',
+ commit_path: '/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319',
+ },
+ cancel_path: '/root/ci-web-terminal/pipelines/127/cancel',
+};
+
+export const mockPostMergeDeployments = [
+ {
+ id: 15,
+ name: 'review/diplo',
+ url: '/root/acets-review-apps/environments/15',
+ stop_url: '/root/acets-review-apps/environments/15/stop',
+ metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
+ metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
+ external_url: 'http://diplo.',
+ external_url_formatted: 'diplo.',
+ deployed_at: '2017-03-22T22:44:42.258Z',
+ deployed_at_formatted: 'Mar 22, 2017 10:44pm',
+ changes: [
+ {
+ path: 'index.html',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/index.html',
+ },
+ {
+ path: 'imgs/gallery.html',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
+ },
+ {
+ path: 'about/',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/about/',
+ },
+ ],
+ status: 'success',
+ },
+];
+
+export const mockDeployment = {
+ id: 15,
+ name: 'review/diplo',
+ url: '/root/acets-review-apps/environments/15',
+ stop_url: '/root/acets-review-apps/environments/15/stop',
+ metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
+ metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
+ external_url: 'http://diplo.',
+ external_url_formatted: 'diplo.',
+ deployed_at: '2017-03-22T22:44:42.258Z',
+ deployed_at_formatted: 'Mar 22, 2017 10:44pm',
+ changes: [
+ {
+ path: 'index.html',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/index.html',
+ },
+ {
+ path: 'imgs/gallery.html',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
+ },
+ {
+ path: 'about/',
+ external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/about/',
+ },
+ ],
+ status: SUCCESS,
+ environment_available: true,
+};
diff --git a/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js b/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
index ecb5a8448f9..09f58f17fd9 100644
--- a/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
+++ b/spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js
@@ -21,12 +21,15 @@ import {
registerExtension,
registeredExtensions,
} from '~/vue_merge_request_widget/components/extensions';
+import { STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import { STATE_QUERY_POLLING_INTERVAL_BACKOFF } from '~/vue_merge_request_widget/constants';
import { SUCCESS } from '~/vue_merge_request_widget/components/deployment/constants';
import eventHub from '~/vue_merge_request_widget/event_hub';
import MrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
import Approvals from '~/vue_merge_request_widget/components/approvals/approvals.vue';
+import ConflictsState from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue';
import Preparing from '~/vue_merge_request_widget/components/states/mr_widget_preparing.vue';
+import ShaMismatch from '~/vue_merge_request_widget/components/states/sha_mismatch.vue';
import WidgetContainer from '~/vue_merge_request_widget/components/widget/app.vue';
import WidgetSuggestPipeline from '~/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue';
import MrWidgetAlertMessage from '~/vue_merge_request_widget/components/mr_widget_alert_message.vue';
@@ -40,7 +43,7 @@ import approvedBySubscription from 'ee_else_ce/vue_merge_request_widget/componen
import userPermissionsQuery from '~/vue_merge_request_widget/queries/permissions.query.graphql';
import conflictsStateQuery from '~/vue_merge_request_widget/queries/states/conflicts.query.graphql';
import { faviconDataUrl, overlayDataUrl } from '../lib/utils/mock_data';
-import mockData from './mock_data';
+import mockData, { mockDeployment, mockMergePipeline, mockPostMergeDeployments } from './mock_data';
import {
workingExtension,
collapsedDataErrorExtension,
@@ -60,9 +63,7 @@ jest.mock('~/smart_interval');
jest.mock('~/lib/utils/favicon');
jest.mock('@sentry/browser', () => ({
- setExtra: jest.fn(),
- setExtras: jest.fn(),
- captureMessage: jest.fn(),
+ ...jest.requireActual('@sentry/browser'),
captureException: jest.fn(),
}));
@@ -76,36 +77,25 @@ describe('MrWidgetOptions', () => {
let stateSubscription;
const COLLABORATION_MESSAGE = 'Members who can merge are allowed to add commits';
- const findApprovalsWidget = () => wrapper.findComponent(Approvals);
- const findPreparingWidget = () => wrapper.findComponent(Preparing);
- const findMergedPipelineContainer = () => wrapper.findByTestId('merged-pipeline-container');
- const findPipelineContainer = () => wrapper.findByTestId('pipeline-container');
- const findAlertMessage = () => wrapper.findComponent(MrWidgetAlertMessage);
-
- beforeEach(() => {
- gl.mrWidgetData = { ...mockData };
- gon.features = { asyncMrWidget: true };
- mock = new MockAdapter(axios);
- mock.onGet(mockData.merge_request_widget_path).reply(() => [HTTP_STATUS_OK, { ...mockData }]);
+ const setInitialData = (data) => {
+ gl.mrWidgetData = { ...mockData, ...data };
+ mock
+ .onGet(mockData.merge_request_widget_path)
+ .reply(() => [HTTP_STATUS_OK, { ...mockData, ...data }]);
mock
.onGet(mockData.merge_request_cached_widget_path)
- .reply(() => [HTTP_STATUS_OK, { ...mockData }]);
- });
-
- afterEach(() => {
- mock.restore();
- // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
- wrapper.destroy();
- gl.mrWidgetData = {};
- });
+ .reply(() => [HTTP_STATUS_OK, { ...mockData, ...data }]);
+ };
const createComponent = ({
- mrData = mockData,
+ updatedMrData = {},
options = {},
data = {},
mountFn = shallowMountExtended,
} = {}) => {
+ setInitialData(updatedMrData);
+ const mrData = { ...mockData, ...updatedMrData };
const mockedApprovalsSubscription = createMockApolloSubscription();
queryResponse = {
data: {
@@ -153,9 +143,7 @@ describe('MrWidgetOptions', () => {
});
wrapper = mountFn(MrWidgetOptions, {
- propsData: {
- mrData: { ...mrData },
- },
+ propsData: { mrData },
data() {
return {
loading: false,
@@ -170,6 +158,12 @@ describe('MrWidgetOptions', () => {
return axios.waitForAll();
};
+ const findApprovalsWidget = () => wrapper.findComponent(Approvals);
+ const findPreparingWidget = () => wrapper.findComponent(Preparing);
+ const findMergedPipelineContainer = () => wrapper.findByTestId('merged-pipeline-container');
+ const findPipelineContainer = () => wrapper.findByTestId('pipeline-container');
+ const findAlertMessage = () => wrapper.findComponent(MrWidgetAlertMessage);
+ const findMergePipelineForkAlert = () => wrapper.findByTestId('merge-pipeline-fork-warning');
const findExtensionToggleButton = () =>
wrapper.find('[data-testid="widget-extension"] [data-testid="toggle-button"]');
const findExtensionLink = (linkHref) =>
@@ -177,23 +171,25 @@ describe('MrWidgetOptions', () => {
const findSuggestPipeline = () => wrapper.findComponent(WidgetSuggestPipeline);
const findWidgetContainer = () => wrapper.findComponent(WidgetContainer);
- describe('default', () => {
- beforeEach(() => {
- jest.spyOn(document, 'dispatchEvent');
- return createComponent();
- });
+ beforeEach(() => {
+ gon.features = { asyncMrWidget: true };
+ mock = new MockAdapter(axios);
+ });
- // quarantine: https://gitlab.com/gitlab-org/gitlab/-/issues/385238
- // eslint-disable-next-line jest/no-disabled-tests
- describe.skip('data', () => {
- it('should instantiate Store and Service', () => {
- expect(wrapper.vm.mr).toBeDefined();
- expect(wrapper.vm.service).toBeDefined();
- });
- });
+ afterEach(() => {
+ mock.restore();
+ // eslint-disable-next-line @gitlab/vtu-no-explicit-wrapper-destroy
+ wrapper.destroy();
+ gl.mrWidgetData = {};
+ });
+ describe('default', () => {
describe('computed', () => {
describe('componentName', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
// quarantine: https://gitlab.com/gitlab-org/gitlab/-/issues/409365
// eslint-disable-next-line jest/no-disabled-tests
it.skip.each`
@@ -205,137 +201,134 @@ describe('MrWidgetOptions', () => {
});
it.each`
- state | componentName
- ${'conflicts'} | ${'mr-widget-conflicts'}
- ${'shaMismatch'} | ${'sha-mismatch'}
- `('should translate $state into $componentName', ({ state, componentName }) => {
- wrapper.vm.mr.state = state;
-
- expect(wrapper.vm.componentName).toEqual(componentName);
+ state | componentName | component
+ ${'conflicts'} | ${'ConflictsState'} | ${ConflictsState}
+ ${'shaMismatch'} | ${'ShaMismatch'} | ${ShaMismatch}
+ `('should translate $state into $componentName component', async ({ state, component }) => {
+ Vue.set(wrapper.vm.mr, 'state', state);
+ await nextTick();
+ expect(wrapper.findComponent(component).exists()).toBe(true);
});
});
describe('MrWidgetPipelineContainer', () => {
- it('should return true when hasCI is true', async () => {
- wrapper.vm.mr.hasCI = true;
- await nextTick();
+ it('renders the pipeline container when it has CI', () => {
+ createComponent({ updatedMrData: { has_ci: true } });
expect(findPipelineContainer().exists()).toBe(true);
});
- it('should return false when hasCI is false', async () => {
- wrapper.vm.mr.hasCI = false;
- await nextTick();
-
+ it('does not render the pipeline container when it does not have CI', () => {
+ createComponent({ updatedMrData: { has_ci: false } });
expect(findPipelineContainer().exists()).toBe(false);
});
});
describe('shouldRenderCollaborationStatus', () => {
- describe('when collaboration is allowed', () => {
- beforeEach(() => {
- wrapper.vm.mr.allowCollaboration = true;
- });
-
- describe('when merge request is opened', () => {
- beforeEach(() => {
- wrapper.vm.mr.isOpen = true;
- return nextTick();
- });
-
- it('should render collaboration status', () => {
- expect(wrapper.text()).toContain(COLLABORATION_MESSAGE);
- });
+ it('renders collaboration message when collaboration is allowed and the MR is open', () => {
+ createComponent({
+ updatedMrData: { allow_collaboration: true, state: STATUS_OPEN, not: false },
});
-
- describe('when merge request is not opened', () => {
- beforeEach(() => {
- wrapper.vm.mr.isOpen = false;
- return nextTick();
- });
-
- it('should not render collaboration status', () => {
- expect(wrapper.text()).not.toContain(COLLABORATION_MESSAGE);
- });
+ expect(findPipelineContainer().props('mr')).toMatchObject({
+ allowCollaboration: true,
+ isOpen: true,
});
+ expect(wrapper.text()).toContain(COLLABORATION_MESSAGE);
});
- describe('when collaboration is not allowed', () => {
- beforeEach(() => {
- wrapper.vm.mr.allowCollaboration = false;
+ it('does not render collaboration message when collaboration is allowed and the MR is closed', () => {
+ createComponent({
+ updatedMrData: { allow_collaboration: true, state: STATUS_CLOSED, not: true },
});
-
- describe('when merge request is opened', () => {
- beforeEach(() => {
- wrapper.vm.mr.isOpen = true;
- return nextTick();
- });
-
- it('should not render collaboration status', () => {
- expect(wrapper.text()).not.toContain(COLLABORATION_MESSAGE);
- });
+ expect(findPipelineContainer().props('mr')).toMatchObject({
+ allowCollaboration: true,
+ isOpen: false,
});
+ expect(wrapper.text()).not.toContain(COLLABORATION_MESSAGE);
});
- });
- describe('showMergePipelineForkWarning', () => {
- describe('when the source project and target project are the same', () => {
- beforeEach(() => {
- Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', true);
- Vue.set(wrapper.vm.mr, 'sourceProjectId', 1);
- Vue.set(wrapper.vm.mr, 'targetProjectId', 1);
- return nextTick();
+ it('does not render collaboration message when collaboration is not allowed and the MR is closed', () => {
+ createComponent({
+ updatedMrData: { allow_collaboration: undefined, state: STATUS_CLOSED, not: true },
});
-
- it('should be false', () => {
- expect(findAlertMessage().exists()).toBe(false);
+ expect(findPipelineContainer().props('mr')).toMatchObject({
+ allowCollaboration: undefined,
+ isOpen: false,
});
+ expect(wrapper.text()).not.toContain(COLLABORATION_MESSAGE);
});
- describe('when merge pipelines are not enabled', () => {
- beforeEach(() => {
- Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', false);
- Vue.set(wrapper.vm.mr, 'sourceProjectId', 1);
- Vue.set(wrapper.vm.mr, 'targetProjectId', 2);
- return nextTick();
+ it('does not render collaboration message when collaboration is not allowed and the MR is open', () => {
+ createComponent({
+ updatedMrData: { allow_collaboration: undefined, state: STATUS_OPEN, not: true },
+ });
+ expect(findPipelineContainer().props('mr')).toMatchObject({
+ allowCollaboration: undefined,
+ isOpen: true,
});
+ expect(wrapper.text()).not.toContain(COLLABORATION_MESSAGE);
+ });
+ });
- it('should be false', () => {
- expect(findAlertMessage().exists()).toBe(false);
+ describe('showMergePipelineForkWarning', () => {
+ it('hides the alert when the source project and target project are the same', async () => {
+ createComponent({
+ updatedMrData: {
+ source_project_id: 1,
+ target_project_id: 1,
+ },
});
+ await nextTick();
+ Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', true);
+ await nextTick();
+ expect(findMergePipelineForkAlert().exists()).toBe(false);
});
- describe('when merge pipelines are enabled _and_ the source project and target project are different', () => {
- beforeEach(() => {
- Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', true);
- Vue.set(wrapper.vm.mr, 'sourceProjectId', 1);
- Vue.set(wrapper.vm.mr, 'targetProjectId', 2);
- return nextTick();
+ it('hides the alert when merge pipelines are not enabled', async () => {
+ createComponent({
+ updatedMrData: {
+ source_project_id: 1,
+ target_project_id: 2,
+ },
});
+ await nextTick();
+ expect(findMergePipelineForkAlert().exists()).toBe(false);
+ });
- it('should be true', () => {
- expect(findAlertMessage().exists()).toBe(true);
+ it('shows the alert when merge pipelines are enabled and the source project and target project are different', async () => {
+ createComponent({
+ updatedMrData: {
+ source_project_id: 1,
+ target_project_id: 2,
+ },
});
+ await nextTick();
+ Vue.set(wrapper.vm.mr, 'mergePipelinesEnabled', true);
+ await nextTick();
+ expect(findMergePipelineForkAlert().exists()).toBe(true);
});
});
describe('formattedHumanAccess', () => {
- it('when user is a tool admin but not a member of project', async () => {
- wrapper.vm.mr.humanAccess = null;
- wrapper.vm.mr.mergeRequestAddCiConfigPath = 'test';
- wrapper.vm.mr.hasCI = false;
- wrapper.vm.mr.isDismissedSuggestPipeline = false;
- await nextTick();
-
+ it('renders empty string when user is a tool admin but not a member of project', () => {
+ createComponent({
+ updatedMrData: {
+ human_access: null,
+ merge_request_add_ci_config_path: 'test',
+ has_ci: false,
+ is_dismissed_suggest_pipeline: false,
+ },
+ });
expect(findSuggestPipeline().props('humanAccess')).toBe('');
});
-
- it('when user a member of the project', async () => {
- wrapper.vm.mr.humanAccess = 'Owner';
- wrapper.vm.mr.mergeRequestAddCiConfigPath = 'test';
- wrapper.vm.mr.hasCI = false;
- wrapper.vm.mr.isDismissedSuggestPipeline = false;
- await nextTick();
-
+ it('renders human access when user is a member of the project', () => {
+ createComponent({
+ updatedMrData: {
+ human_access: 'Owner',
+ merge_request_add_ci_config_path: 'test',
+ has_ci: false,
+ is_dismissed_suggest_pipeline: false,
+ },
+ });
expect(findSuggestPipeline().props('humanAccess')).toBe('owner');
});
});
@@ -343,33 +336,50 @@ describe('MrWidgetOptions', () => {
describe('methods', () => {
describe('checkStatus', () => {
- let cb;
- let isCbExecuted;
-
- beforeEach(() => {
- jest.spyOn(wrapper.vm.service, 'checkStatus').mockResolvedValue({ data: mockData });
- jest.spyOn(wrapper.vm.mr, 'setData').mockImplementation(() => {});
- jest.spyOn(wrapper.vm, 'handleNotification').mockImplementation(() => {});
-
- isCbExecuted = false;
- cb = () => {
- isCbExecuted = true;
- };
+ it('checks the status of the pipelines', async () => {
+ const callback = jest.fn();
+ await createComponent({ updatedMrData: { foo: 1 } });
+ await waitForPromises();
+ eventHub.$emit('MRWidgetUpdateRequested', callback);
+ await waitForPromises();
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining({ foo: 1 }));
});
- it('should tell service to check status if document is visible', () => {
- wrapper.vm.checkStatus(cb);
+ it('notifies the user of the pipeline status', async () => {
+ jest.spyOn(notify, 'notifyMe').mockImplementation(() => {});
+ const logoFilename = 'logo.png';
+ await createComponent({
+ updatedMrData: { gitlabLogo: logoFilename },
+ });
+ eventHub.$emit('MRWidgetUpdateRequested');
+ await waitForPromises();
+ expect(notify.notifyMe).toHaveBeenCalledWith(
+ `Pipeline passed`,
+ `Pipeline passed for "${mockData.title}"`,
+ logoFilename,
+ );
+ });
- return nextTick().then(() => {
- expect(wrapper.vm.service.checkStatus).toHaveBeenCalled();
- expect(wrapper.vm.mr.setData).toHaveBeenCalled();
- expect(wrapper.vm.handleNotification).toHaveBeenCalledWith(mockData);
- expect(isCbExecuted).toBe(true);
+ it('updates the stores data', async () => {
+ const mockSetData = jest.fn();
+ await createComponent({
+ data: {
+ mr: {
+ setData: mockSetData,
+ setGraphqlData: jest.fn(),
+ },
+ },
});
+ eventHub.$emit('MRWidgetUpdateRequested');
+ expect(mockSetData).toHaveBeenCalled();
});
});
describe('initDeploymentsPolling', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
+
it('should call SmartInterval', () => {
wrapper.vm.initDeploymentsPolling();
@@ -382,83 +392,98 @@ describe('MrWidgetOptions', () => {
});
describe('fetchDeployments', () => {
- it('should fetch deployments', () => {
- jest
- .spyOn(wrapper.vm.service, 'fetchDeployments')
- .mockResolvedValue({ data: [{ id: 1, status: SUCCESS }] });
-
- wrapper.vm.fetchPreMergeDeployments();
+ beforeEach(async () => {
+ mock
+ .onGet(mockData.ci_environments_status_path)
+ .reply(() => [HTTP_STATUS_OK, [{ id: 1, status: SUCCESS }]]);
+ await createComponent();
+ });
- return nextTick().then(() => {
- expect(wrapper.vm.service.fetchDeployments).toHaveBeenCalled();
- expect(wrapper.vm.mr.deployments.length).toEqual(1);
- expect(wrapper.vm.mr.deployments[0].id).toBe(1);
- });
+ it('should fetch deployments', async () => {
+ eventHub.$emit('FetchDeployments', {});
+ await waitForPromises();
+ expect(wrapper.vm.mr.deployments.length).toEqual(1);
+ expect(wrapper.vm.mr.deployments[0].id).toBe(1);
});
});
describe('fetchActionsContent', () => {
- it('should fetch content of Cherry Pick and Revert modals', () => {
- jest
- .spyOn(wrapper.vm.service, 'fetchMergeActionsContent')
- .mockResolvedValue({ data: 'hello world' });
-
- wrapper.vm.fetchActionsContent();
-
- return nextTick().then(() => {
- expect(wrapper.vm.service.fetchMergeActionsContent).toHaveBeenCalled();
- expect(document.body.textContent).toContain('hello world');
- expect(document.dispatchEvent).toHaveBeenCalledWith(
- new CustomEvent('merged:UpdateActions'),
- );
- });
+ const innerHTML = 'hello world';
+ beforeEach(async () => {
+ jest.spyOn(document, 'dispatchEvent');
+ mock.onGet(mockData.commit_change_content_path).reply(() => [HTTP_STATUS_OK, innerHTML]);
+ await createComponent();
+ });
+
+ it('should fetch content of Cherry Pick and Revert modals', async () => {
+ eventHub.$emit('FetchActionsContent');
+ await waitForPromises();
+ expect(document.body.textContent).toContain(innerHTML);
+ expect(document.dispatchEvent).toHaveBeenCalledWith(
+ new CustomEvent('merged:UpdateActions'),
+ );
});
});
describe('bindEventHubListeners', () => {
- it.each`
- event | method | methodArgs
- ${'MRWidgetUpdateRequested'} | ${'checkStatus'} | ${(x) => [x]}
- ${'MRWidgetRebaseSuccess'} | ${'checkStatus'} | ${(x) => [x, true]}
- ${'FetchActionsContent'} | ${'fetchActionsContent'} | ${() => []}
- ${'EnablePolling'} | ${'resumePolling'} | ${() => []}
- ${'DisablePolling'} | ${'stopPolling'} | ${() => []}
- ${'FetchDeployments'} | ${'fetchPreMergeDeployments'} | ${() => []}
- `('should bind to $event', ({ event, method, methodArgs }) => {
- jest.spyOn(wrapper.vm, method).mockImplementation();
-
- const eventArg = {};
- eventHub.$emit(event, eventArg);
-
- expect(wrapper.vm[method]).toHaveBeenCalledWith(...methodArgs(eventArg));
+ const mockSetData = jest.fn();
+ beforeEach(async () => {
+ await createComponent({
+ data: {
+ mr: {
+ setData: mockSetData,
+ setGraphqlData: jest.fn(),
+ },
+ },
+ });
});
- it('should bind to SetBranchRemoveFlag', () => {
- expect(wrapper.vm.mr.isRemovingSourceBranch).toBe(false);
-
- eventHub.$emit('SetBranchRemoveFlag', [true]);
+ it('refetches when "MRWidgetUpdateRequested" event is emitted', async () => {
+ expect(stateQueryHandler).toHaveBeenCalledTimes(1);
+ eventHub.$emit('MRWidgetUpdateRequested', () => {});
+ await waitForPromises();
+ expect(stateQueryHandler).toHaveBeenCalledTimes(2);
+ });
- expect(wrapper.vm.mr.isRemovingSourceBranch).toBe(true);
+ it('refetches when "MRWidgetRebaseSuccess" event is emitted', async () => {
+ expect(stateQueryHandler).toHaveBeenCalledTimes(1);
+ eventHub.$emit('MRWidgetRebaseSuccess', () => {});
+ await waitForPromises();
+ expect(stateQueryHandler).toHaveBeenCalledTimes(2);
});
- it('should bind to FailedToMerge', () => {
- wrapper.vm.mr.state = '';
- wrapper.vm.mr.mergeError = '';
+ it('should bind to SetBranchRemoveFlag', () => {
+ expect(findPipelineContainer().props('mr')).toMatchObject({
+ isRemovingSourceBranch: false,
+ });
+ eventHub.$emit('SetBranchRemoveFlag', [true]);
+ expect(findPipelineContainer().props('mr')).toMatchObject({
+ isRemovingSourceBranch: true,
+ });
+ });
+ it('should bind to FailedToMerge', async () => {
+ expect(findAlertMessage().exists()).toBe(false);
+ expect(findPipelineContainer().props('mr')).toMatchObject({
+ mergeError: undefined,
+ state: 'merged',
+ });
const mergeError = 'Something bad happened!';
- eventHub.$emit('FailedToMerge', mergeError);
+ await eventHub.$emit('FailedToMerge', mergeError);
- expect(wrapper.vm.mr.state).toBe('failedToMerge');
- expect(wrapper.vm.mr.mergeError).toBe(mergeError);
+ expect(findAlertMessage().exists()).toBe(true);
+ expect(findAlertMessage().text()).toBe(`${mergeError}. Try again.`);
+ expect(findPipelineContainer().props('mr')).toMatchObject({
+ mergeError,
+ state: 'failedToMerge',
+ });
});
it('should bind to UpdateWidgetData', () => {
- jest.spyOn(wrapper.vm.mr, 'setData').mockImplementation();
-
const data = { ...mockData };
eventHub.$emit('UpdateWidgetData', data);
- expect(wrapper.vm.mr.setData).toHaveBeenCalledWith(data);
+ expect(mockSetData).toHaveBeenCalledWith(data);
});
});
@@ -479,58 +504,39 @@ describe('MrWidgetOptions', () => {
});
it('should call setFavicon method', async () => {
- wrapper.vm.mr.faviconOverlayPath = overlayDataUrl;
-
- await wrapper.vm.setFaviconHelper();
-
+ await createComponent({ updatedMrData: { favicon_overlay_path: overlayDataUrl } });
expect(setFaviconOverlay).toHaveBeenCalledWith(overlayDataUrl);
});
it('should not call setFavicon when there is no faviconOverlayPath', async () => {
- wrapper.vm.mr.faviconOverlayPath = null;
- await wrapper.vm.setFaviconHelper();
+ await createComponent({ updatedMrData: { favicon_overlay_path: null } });
expect(faviconElement.getAttribute('href')).toEqual(null);
});
});
describe('handleNotification', () => {
- const data = {
- ci_status: 'running',
- title: 'title',
- pipeline: { details: { status: { label: 'running-label' } } },
- };
-
beforeEach(() => {
jest.spyOn(notify, 'notifyMe').mockImplementation(() => {});
-
- wrapper.vm.mr.ciStatus = 'failed';
- wrapper.vm.mr.gitlabLogo = 'logo.png';
});
- it('should call notifyMe', () => {
- wrapper.vm.handleNotification(data);
-
+ it('should call notifyMe', async () => {
+ const logoFilename = 'logo.png';
+ await createComponent({ updatedMrData: { gitlabLogo: logoFilename } });
expect(notify.notifyMe).toHaveBeenCalledWith(
- 'Pipeline running-label',
- 'Pipeline running-label for "title"',
- 'logo.png',
+ `Pipeline passed`,
+ `Pipeline passed for "${mockData.title}"`,
+ logoFilename,
);
});
- it('should not call notifyMe if the status has not changed', () => {
- wrapper.vm.mr.ciStatus = data.ci_status;
-
- wrapper.vm.handleNotification(data);
-
+ it('should not call notifyMe if the status has not changed', async () => {
+ await createComponent({ updatedMrData: { ci_status: undefined } });
+ await eventHub.$emit('MRWidgetUpdateRequested');
expect(notify.notifyMe).not.toHaveBeenCalled();
});
- it('should not notify if no pipeline provided', () => {
- wrapper.vm.handleNotification({
- ...data,
- pipeline: undefined,
- });
-
+ it('should not notify if no pipeline provided', async () => {
+ await createComponent({ updatedMrData: { pipeline: undefined } });
expect(notify.notifyMe).not.toHaveBeenCalled();
});
});
@@ -546,7 +552,6 @@ describe('MrWidgetOptions', () => {
wrapper.destroy();
return createComponent({
- mrData: mockData,
options: {},
data: {
pollInterval: interval,
@@ -597,47 +602,18 @@ describe('MrWidgetOptions', () => {
});
describe('rendering deployments', () => {
- const changes = [
- {
- path: 'index.html',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/index.html',
- },
- {
- path: 'imgs/gallery.html',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
- },
- {
- path: 'about/',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/about/',
- },
- ];
- const deploymentMockData = {
- id: 15,
- name: 'review/diplo',
- url: '/root/acets-review-apps/environments/15',
- stop_url: '/root/acets-review-apps/environments/15/stop',
- metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
- metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
- external_url: 'http://diplo.',
- external_url_formatted: 'diplo.',
- deployed_at: '2017-03-22T22:44:42.258Z',
- deployed_at_formatted: 'Mar 22, 2017 10:44pm',
- changes,
- status: SUCCESS,
- environment_available: true,
- };
-
it('renders multiple deployments', async () => {
- wrapper.vm.mr.deployments.push(
- {
- ...deploymentMockData,
- },
- {
- ...deploymentMockData,
- id: deploymentMockData.id + 1,
+ await createComponent({
+ updatedMrData: {
+ deployments: [
+ mockDeployment,
+ {
+ ...mockDeployment,
+ id: mockDeployment.id + 1,
+ },
+ ],
},
- );
- await nextTick();
+ });
expect(findPipelineContainer().props('isPostMerge')).toBe(false);
expect(findPipelineContainer().props('mr').deployments).toHaveLength(2);
expect(findPipelineContainer().props('mr').postMergeDeployments).toHaveLength(0);
@@ -646,189 +622,44 @@ describe('MrWidgetOptions', () => {
describe('pipeline for target branch after merge', () => {
describe('with information for target branch pipeline', () => {
- beforeEach(() => {
- wrapper.vm.mr.state = 'merged';
- wrapper.vm.mr.mergePipeline = {
- id: 127,
- user: {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url: null,
- web_url: 'http://localhost:3000/root',
- status_tooltip_html: null,
- path: '/root',
- },
- active: true,
- coverage: null,
- source: 'push',
- created_at: '2018-10-22T11:41:35.186Z',
- updated_at: '2018-10-22T11:41:35.433Z',
- path: '/root/ci-web-terminal/pipelines/127',
- flags: {
- latest: true,
- stuck: true,
- auto_devops: false,
- yaml_errors: false,
- retryable: false,
- cancelable: true,
- failure_reason: false,
- },
- details: {
- status: {
- icon: 'status_pending',
- text: 'pending',
- label: 'pending',
- group: 'pending',
- tooltip: 'pending',
- has_details: true,
- details_path: '/root/ci-web-terminal/pipelines/127',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
- },
- duration: null,
- finished_at: null,
- stages: [
- {
- name: 'test',
- title: 'test: pending',
- status: {
- icon: 'status_pending',
- text: 'pending',
- label: 'pending',
- group: 'pending',
- tooltip: 'pending',
- has_details: true,
- details_path: '/root/ci-web-terminal/pipelines/127#test',
- illustration: null,
- favicon:
- '/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png',
- },
- path: '/root/ci-web-terminal/pipelines/127#test',
- dropdown_path: '/root/ci-web-terminal/pipelines/127/stage.json?stage=test',
- },
- ],
- artifacts: [],
- manual_actions: [],
- scheduled_actions: [],
- },
- ref: {
- name: 'main',
- path: '/root/ci-web-terminal/commits/main',
- tag: false,
- branch: true,
- },
- commit: {
- id: 'aa1939133d373c94879becb79d91828a892ee319',
- short_id: 'aa193913',
- title: "Merge branch 'main-test' into 'main'",
- created_at: '2018-10-22T11:41:33.000Z',
- parent_ids: [
- '4622f4dd792468993003caf2e3be978798cbe096',
- '76598df914cdfe87132d0c3c40f80db9fa9396a4',
- ],
- message:
- "Merge branch 'main-test' into 'main'\n\nUpdate .gitlab-ci.yml\n\nSee merge request root/ci-web-terminal!1",
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2018-10-22T11:41:33.000Z',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2018-10-22T11:41:33.000Z',
- author: {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url: null,
- web_url: 'http://localhost:3000/root',
- status_tooltip_html: null,
- path: '/root',
- },
- author_gravatar_url: null,
- commit_url:
- 'http://localhost:3000/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319',
- commit_path: '/root/ci-web-terminal/commit/aa1939133d373c94879becb79d91828a892ee319',
- },
- cancel_path: '/root/ci-web-terminal/pipelines/127/cancel',
- };
- return nextTick();
- });
+ const state = 'merged';
- it('renders pipeline block', () => {
+ it('renders pipeline block', async () => {
+ await createComponent({ updatedMrData: { state, merge_pipeline: mockMergePipeline } });
expect(findMergedPipelineContainer().exists()).toBe(true);
});
describe('with post merge deployments', () => {
- beforeEach(() => {
- wrapper.vm.mr.postMergeDeployments = [
- {
- id: 15,
- name: 'review/diplo',
- url: '/root/acets-review-apps/environments/15',
- stop_url: '/root/acets-review-apps/environments/15/stop',
- metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
- metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
- external_url: 'http://diplo.',
- external_url_formatted: 'diplo.',
- deployed_at: '2017-03-22T22:44:42.258Z',
- deployed_at_formatted: 'Mar 22, 2017 10:44pm',
- changes: [
- {
- path: 'index.html',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/index.html',
- },
- {
- path: 'imgs/gallery.html',
- external_url:
- 'http://root-main-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
- },
- {
- path: 'about/',
- external_url: 'http://root-main-patch-91341.volatile-watch.surge.sh/about/',
- },
- ],
- status: 'success',
+ it('renders post deployment information', async () => {
+ await createComponent({
+ updatedMrData: {
+ state,
+ merge_pipeline: mockMergePipeline,
+ post_merge_deployments: mockPostMergeDeployments,
},
- ];
-
- return nextTick();
- });
-
- it('renders post deployment information', () => {
+ });
expect(findMergedPipelineContainer().exists()).toBe(true);
});
});
});
describe('without information for target branch pipeline', () => {
- beforeEach(() => {
- wrapper.vm.mr.state = 'merged';
-
- return nextTick();
- });
-
- it('does not render pipeline block', () => {
+ it('does not render pipeline block', async () => {
+ await createComponent({ updatedMrData: { merge_pipeline: undefined } });
expect(findMergedPipelineContainer().exists()).toBe(false);
});
});
describe('when state is not merged', () => {
- beforeEach(() => {
- wrapper.vm.mr.state = 'archived';
-
- return nextTick();
- });
-
- it('does not render pipeline block', () => {
+ it('does not render pipeline block', async () => {
+ await createComponent({ updatedMrData: { state: 'archived' } });
expect(findMergedPipelineContainer().exists()).toBe(false);
});
});
});
it('should not suggest pipelines when feature flag is not present', () => {
+ createComponent();
expect(findSuggestPipeline().exists()).toBe(false);
});
});
@@ -839,28 +670,23 @@ describe('MrWidgetOptions', () => {
});
describe('given feature flag is enabled', () => {
- beforeEach(async () => {
- await createComponent();
- wrapper.vm.mr.hasCI = false;
- });
-
- it('should suggest pipelines when none exist', () => {
+ it('should suggest pipelines when none exist', async () => {
+ await createComponent({ updatedMrData: { has_ci: false } });
expect(findSuggestPipeline().exists()).toBe(true);
});
it.each([
- { isDismissedSuggestPipeline: true },
- { mergeRequestAddCiConfigPath: null },
- { hasCI: true },
+ { is_dismissed_suggest_pipeline: true },
+ { merge_request_add_ci_config_path: null },
+ { has_ci: true },
])('with %s, should not suggest pipeline', async (obj) => {
- Object.assign(wrapper.vm.mr, obj);
-
- await nextTick();
+ await createComponent({ updatedMrData: { has_ci: false, ...obj } });
expect(findSuggestPipeline().exists()).toBe(false);
});
it('should allow dismiss of the suggest pipeline message', async () => {
+ await createComponent({ updatedMrData: { has_ci: false } });
await findSuggestPipeline().vm.$emit('dismiss');
expect(findSuggestPipeline().exists()).toBe(false);
@@ -875,11 +701,11 @@ describe('MrWidgetOptions', () => {
${'merged'} | ${true} | ${'shows'}
${'open'} | ${true} | ${'shows'}
`('$showText merge error when state is $state', async ({ state, show }) => {
- createComponent({ mrData: { ...mockData, state, mergeError: 'Error!' } });
+ createComponent({ updatedMrData: { state, mergeError: 'Error!' } });
await waitForPromises();
- expect(wrapper.find('[data-testid="merge_error"]').exists()).toBe(show);
+ expect(wrapper.findByTestId('merge-error').exists()).toBe(show);
});
});
@@ -1111,6 +937,67 @@ describe('MrWidgetOptions', () => {
registeredExtensions.extensions = [];
});
+ describe('component name tier suffixes', () => {
+ let extension;
+
+ beforeEach(() => {
+ extension = workingExtension();
+ });
+
+ it('reports events without a CE suffix', () => {
+ extension.name = `${extension.name}CE`;
+
+ registerExtension(extension);
+ createComponent({ mountFn: mountExtended });
+
+ expect(api.trackRedisHllUserEvent).toHaveBeenCalledWith(
+ 'i_code_review_merge_request_widget_test_extension_view',
+ );
+ expect(api.trackRedisHllUserEvent).not.toHaveBeenCalledWith(
+ 'i_code_review_merge_request_widget_test_extension_c_e_view',
+ );
+ });
+
+ it('reports events without a EE suffix', () => {
+ extension.name = `${extension.name}EE`;
+
+ registerExtension(extension);
+ createComponent({ mountFn: mountExtended });
+
+ expect(api.trackRedisHllUserEvent).toHaveBeenCalledWith(
+ 'i_code_review_merge_request_widget_test_extension_view',
+ );
+ expect(api.trackRedisHllUserEvent).not.toHaveBeenCalledWith(
+ 'i_code_review_merge_request_widget_test_extension_e_e_view',
+ );
+ });
+
+ it('leaves non-CE & non-EE all caps suffixes intact', () => {
+ extension.name = `${extension.name}HI`;
+
+ registerExtension(extension);
+ createComponent({ mountFn: mountExtended });
+
+ expect(api.trackRedisHllUserEvent).not.toHaveBeenCalledWith(
+ 'i_code_review_merge_request_widget_test_extension_view',
+ );
+ expect(api.trackRedisHllUserEvent).toHaveBeenCalledWith(
+ 'i_code_review_merge_request_widget_test_extension_h_i_view',
+ );
+ });
+
+ it("doesn't remove CE or EE from the middle of a widget name", () => {
+ extension.name = 'TestCEExtensionEETest';
+
+ registerExtension(extension);
+ createComponent({ mountFn: mountExtended });
+
+ expect(api.trackRedisHllUserEvent).toHaveBeenCalledWith(
+ 'i_code_review_merge_request_widget_test_c_e_extension_e_e_test_view',
+ );
+ });
+ });
+
it('triggers view events when mounted', () => {
registerExtension(workingExtension());
createComponent({ mountFn: mountExtended });
@@ -1217,11 +1104,7 @@ describe('MrWidgetOptions', () => {
it('renders the Preparing state component when the MR state is initially "preparing"', async () => {
await createComponent({
- mrData: {
- ...mockData,
- state: 'opened',
- detailedMergeStatus: 'PREPARING',
- },
+ updatedMrData: { state: 'opened', detailedMergeStatus: 'PREPARING' },
});
expect(findApprovalsWidget().exists()).toBe(false);
@@ -1235,11 +1118,7 @@ describe('MrWidgetOptions', () => {
it("shows the Preparing widget when the MR reports it's not ready yet", async () => {
await createComponent({
- mrData: {
- ...mockData,
- state: 'opened',
- detailedMergeStatus: 'PREPARING',
- },
+ updatedMrData: { state: 'opened', detailedMergeStatus: 'PREPARING' },
options: {},
data: {},
});
@@ -1249,11 +1128,7 @@ describe('MrWidgetOptions', () => {
it('removes the Preparing widget when the MR indicates it has been prepared', async () => {
await createComponent({
- mrData: {
- ...mockData,
- state: 'opened',
- detailedMergeStatus: 'PREPARING',
- },
+ updatedMrData: { state: 'opened', detailedMergeStatus: 'PREPARING' },
options: {},
data: {},
});
diff --git a/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
index b93c64efbcb..da1a15b1b2b 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
@@ -4,12 +4,10 @@ exports[`Expand button on click when short text is provided renders button after
<span>
<button
aria-label="Click to expand text"
- class="btn js-text-expander-prepend text-expander btn-blank btn-default btn-md gl-button btn-icon button-ellipsis-horizontal"
+ class="btn btn-blank btn-default btn-icon btn-md button-ellipsis-horizontal gl-button js-text-expander-prepend text-expander"
style="display: none;"
type="button"
>
- <!---->
-
<svg
aria-hidden="true"
class="gl-button-icon gl-icon s16"
@@ -20,26 +18,18 @@ exports[`Expand button on click when short text is provided renders button after
href="file-mock#ellipsis_h"
/>
</svg>
-
- <!---->
</button>
-
- <!---->
-
<span>
<p>
Expanded!
</p>
</span>
-
<button
aria-label="Click to expand text"
- class="btn js-text-expander-append text-expander btn-blank btn-default btn-md gl-button btn-icon button-ellipsis-horizontal"
+ class="btn btn-blank btn-default btn-icon btn-md button-ellipsis-horizontal gl-button js-text-expander-append text-expander"
style=""
type="button"
>
- <!---->
-
<svg
aria-hidden="true"
class="gl-button-icon gl-icon s16"
@@ -50,8 +40,6 @@ exports[`Expand button on click when short text is provided renders button after
href="file-mock#ellipsis_h"
/>
</svg>
-
- <!---->
</button>
</span>
`;
@@ -60,11 +48,9 @@ exports[`Expand button when short text is provided renders button before text 1`
<span>
<button
aria-label="Click to expand text"
- class="btn js-text-expander-prepend text-expander btn-blank btn-default btn-md gl-button btn-icon button-ellipsis-horizontal"
+ class="btn btn-blank btn-default btn-icon btn-md button-ellipsis-horizontal gl-button js-text-expander-prepend text-expander"
type="button"
>
- <!---->
-
<svg
aria-hidden="true"
class="gl-button-icon gl-icon s16"
@@ -75,26 +61,18 @@ exports[`Expand button when short text is provided renders button before text 1`
href="file-mock#ellipsis_h"
/>
</svg>
-
- <!---->
</button>
-
<span>
<p>
Short
</p>
</span>
-
- <!---->
-
<button
aria-label="Click to expand text"
- class="btn js-text-expander-append text-expander btn-blank btn-default btn-md gl-button btn-icon button-ellipsis-horizontal"
+ class="btn btn-blank btn-default btn-icon btn-md button-ellipsis-horizontal gl-button js-text-expander-append text-expander"
style="display: none;"
type="button"
>
- <!---->
-
<svg
aria-hidden="true"
class="gl-button-icon gl-icon s16"
@@ -105,8 +83,6 @@ exports[`Expand button when short text is provided renders button before text 1`
href="file-mock#ellipsis_h"
/>
</svg>
-
- <!---->
</button>
</span>
`;
diff --git a/spec/frontend/vue_shared/components/__snapshots__/integration_help_text_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/integration_help_text_spec.js.snap
index df0fcf5da1c..d630d23873f 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/integration_help_text_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/integration_help_text_spec.js.snap
@@ -8,14 +8,12 @@ exports[`IntegrationHelpText component should not render the link when start and
exports[`IntegrationHelpText component should render the help text 1`] = `
<span>
- Click
+ Click
<gl-link-stub
href="http://bar.com"
target="_blank"
>
-
- Bar
-
+ Bar
<gl-icon-stub
class="gl-vertical-align-middle"
name="external-link"
diff --git a/spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap
index f414359fef2..76deb4d0b36 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/source_editor_spec.js.snap
@@ -3,8 +3,8 @@
exports[`Source Editor component rendering matches the snapshot 1`] = `
<div
data-editor-loading=""
- data-qa-selector="source_editor_container"
- id="source-editor-snippet_777"
+ data-testid="source-editor-container"
+ id="reference-0"
>
<pre
class="editor-loading-content"
diff --git a/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap
deleted file mode 100644
index 62d75fbdc5f..00000000000
--- a/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap
+++ /dev/null
@@ -1,59 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`SplitButton renders actionItems 1`] = `
-<gl-dropdown-stub
- category="primary"
- clearalltext="Clear all"
- clearalltextclass="gl-px-5"
- headertext=""
- hideheaderborder="true"
- highlighteditemstitle="Selected"
- highlighteditemstitleclass="gl-px-5"
- menu-class=""
- size="medium"
- split="true"
- splithref=""
- text="professor"
- variant="default"
->
- <gl-dropdown-item-stub
- avatarurl=""
- iconcolor=""
- iconname=""
- iconrightarialabel=""
- iconrightname=""
- ischecked="true"
- ischeckitem="true"
- secondarytext=""
- >
- <strong>
- professor
- </strong>
-
- <div>
- very symphonic
- </div>
- </gl-dropdown-item-stub>
-
- <gl-dropdown-divider-stub />
- <gl-dropdown-item-stub
- avatarurl=""
- iconcolor=""
- iconname=""
- iconrightarialabel=""
- iconrightname=""
- ischeckitem="true"
- secondarytext=""
- >
- <strong>
- captain
- </strong>
-
- <div>
- warp drive
- </div>
- </gl-dropdown-item-stub>
-
- <!---->
-</gl-dropdown-stub>
-`;
diff --git a/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap b/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap
index 24b2c54f20b..359aaacde0b 100644
--- a/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap
+++ b/spec/frontend/vue_shared/components/badges/__snapshots__/beta_badge_spec.js.snap
@@ -11,7 +11,6 @@ exports[`Beta badge component renders the badge 1`] = `
>
Beta
</gl-badge-stub>
-
<gl-popover-stub
cssclasses=""
data-testid="beta-badge"
@@ -23,28 +22,23 @@ exports[`Beta badge component renders the badge 1`] = `
<p>
A Beta feature is not production-ready, but is unlikely to change drastically before it's released. We encourage users to try Beta features and provide feedback.
</p>
-
<p
class="gl-mb-0"
>
A Beta feature:
</p>
-
<ul
class="gl-pl-4"
>
<li>
May be unstable.
</li>
-
<li>
Should not cause data loss.
</li>
-
<li>
Is supported by a commercially reasonable effort.
</li>
-
<li>
Is complete or near completion.
</li>
diff --git a/spec/frontend/vue_shared/components/blob_viewers/__snapshots__/simple_viewer_spec.js.snap b/spec/frontend/vue_shared/components/blob_viewers/__snapshots__/simple_viewer_spec.js.snap
index fbf3d17fd64..1f3f1fef365 100644
--- a/spec/frontend/vue_shared/components/blob_viewers/__snapshots__/simple_viewer_spec.js.snap
+++ b/spec/frontend/vue_shared/components/blob_viewers/__snapshots__/simple_viewer_spec.js.snap
@@ -3,80 +3,69 @@
exports[`Blob Simple Viewer component rendering matches the snapshot 1`] = `
<div>
<div
- class="file-content code js-syntax-highlight"
+ class="code file-content js-syntax-highlight"
>
<div
- class="line-numbers gl-pt-0!"
+ class="gl-pt-0! line-numbers"
>
<a
class="diff-line-num js-line-number"
data-line-number="1"
href="#LC1"
- id="L1"
+ id="reference-0"
>
<gl-icon-stub
name="link"
size="12"
/>
-
1
-
</a>
<a
class="diff-line-num js-line-number"
data-line-number="2"
href="#LC2"
- id="L2"
+ id="reference-1"
>
<gl-icon-stub
name="link"
size="12"
/>
-
2
-
</a>
<a
class="diff-line-num js-line-number"
data-line-number="3"
href="#LC3"
- id="L3"
+ id="reference-2"
>
<gl-icon-stub
name="link"
size="12"
/>
-
3
-
</a>
</div>
-
<div
class="blob-content"
>
<pre
- class="code highlight gl-p-0! gl-display-flex"
+ class="code gl-display-flex gl-p-0! highlight"
>
<code
data-blob-hash="foo-bar"
>
<span
- id="LC1"
+ id="reference-3"
>
First
</span>
-
-
<span
- id="LC2"
+ id="reference-4"
>
Second
</span>
-
-
<span
- id="LC3"
+ id="reference-5"
>
Third
</span>
diff --git a/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js b/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
index fc8155bd381..eadcd452929 100644
--- a/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
+++ b/spec/frontend/vue_shared/components/blob_viewers/rich_viewer_spec.js
@@ -3,6 +3,10 @@ import { shallowMount } from '@vue/test-utils';
import { handleBlobRichViewer } from '~/blob/viewer';
import RichViewer from '~/vue_shared/components/blob_viewers/rich_viewer.vue';
import MarkdownFieldView from '~/vue_shared/components/markdown/field_view.vue';
+import {
+ MARKUP_FILE_TYPE,
+ CONTENT_LOADED_EVENT,
+} from '~/vue_shared/components/blob_viewers/constants';
import { handleLocationHash } from '~/lib/utils/common_utils';
jest.mock('~/blob/viewer');
@@ -10,10 +14,10 @@ jest.mock('~/lib/utils/common_utils');
describe('Blob Rich Viewer component', () => {
let wrapper;
- const content = '<h1 id="markdown">Foo Bar</h1>';
+ const dummyContent = '<h1 id="markdown">Foo Bar</h1>';
const defaultType = 'markdown';
- function createComponent(type = defaultType, richViewer) {
+ function createComponent(type = defaultType, richViewer, content = dummyContent) {
wrapper = shallowMount(RichViewer, {
propsData: {
richViewer,
@@ -23,26 +27,75 @@ describe('Blob Rich Viewer component', () => {
});
}
- beforeEach(() => {
- const execImmediately = (callback) => callback();
- jest.spyOn(window, 'requestIdleCallback').mockImplementation(execImmediately);
+ beforeEach(() => createComponent());
- createComponent();
- });
+ const findMarkdownFieldView = () => wrapper.findComponent(MarkdownFieldView);
+
+ describe('Markdown content', () => {
+ const generateDummyContent = (contentLength) => {
+ let generatedContent = '';
+ for (let i = 0; i < contentLength; i += 1) {
+ generatedContent += `<span>Line: ${i + 1}</span>\n`;
+ }
+
+ generatedContent += '<img src="x" onerror="alert(`XSS`)">'; // for testing against XSS
+ return `<div class="js-markup-content">${generatedContent}</div>`;
+ };
+
+ describe('Large file', () => {
+ const content = generateDummyContent(50);
+ beforeEach(() => createComponent(MARKUP_FILE_TYPE, null, content));
+
+ it('renders the top of the file immediately and does not emit a content loaded event', () => {
+ expect(wrapper.text()).toContain('Line: 10');
+ expect(wrapper.text()).not.toContain('Line: 50');
+ expect(wrapper.emitted(CONTENT_LOADED_EVENT)).toBeUndefined();
+ expect(findMarkdownFieldView().props('isLoading')).toBe(true);
+ });
+
+ it('renders the rest of the file later and emits a content loaded event', async () => {
+ jest.runAllTimers();
+ await nextTick();
+
+ expect(wrapper.text()).toContain('Line: 10');
+ expect(wrapper.text()).toContain('Line: 50');
+ expect(wrapper.emitted(CONTENT_LOADED_EVENT)).toHaveLength(1);
+ expect(findMarkdownFieldView().props('isLoading')).toBe(false);
+ });
- it('listens to requestIdleCallback', () => {
- expect(window.requestIdleCallback).toHaveBeenCalled();
+ it('sanitizes the content', () => {
+ jest.runAllTimers();
+
+ expect(wrapper.html()).toContain('<img src="x">');
+ });
+ });
+
+ describe('Small file', () => {
+ const content = generateDummyContent(5);
+ beforeEach(() => createComponent(MARKUP_FILE_TYPE, null, content));
+
+ it('renders the entire file immediately and emits a content loaded event', () => {
+ expect(wrapper.text()).toContain('Line: 5');
+ expect(wrapper.emitted(CONTENT_LOADED_EVENT)).toHaveLength(1);
+ expect(findMarkdownFieldView().props('isLoading')).toBe(false);
+ });
+
+ it('sanitizes the content', () => {
+ expect(wrapper.html()).toContain('<img src="x">');
+ });
+ });
});
it('renders the passed content without transformations', () => {
- expect(wrapper.html()).toContain(content);
+ expect(wrapper.html()).toContain(dummyContent);
});
- it('renders the richViewer if one is present', async () => {
+ it('renders the richViewer if one is present and emits a content loaded event', async () => {
const richViewer = '<div class="js-pdf-viewer"></div>';
createComponent('pdf', richViewer);
await nextTick();
expect(wrapper.html()).toContain(richViewer);
+ expect(wrapper.emitted(CONTENT_LOADED_EVENT)).toHaveLength(1);
});
it('queries for advanced viewer', () => {
@@ -50,7 +103,7 @@ describe('Blob Rich Viewer component', () => {
});
it('is using Markdown View Field', () => {
- expect(wrapper.findComponent(MarkdownFieldView).exists()).toBe(true);
+ expect(findMarkdownFieldView().exists()).toBe(true);
});
it('scrolls to the hash location', () => {
diff --git a/spec/frontend/vue_shared/components/ci_badge_link_spec.js b/spec/frontend/vue_shared/components/ci_badge_link_spec.js
index 8c860c9b06f..c74964c13f5 100644
--- a/spec/frontend/vue_shared/components/ci_badge_link_spec.js
+++ b/spec/frontend/vue_shared/components/ci_badge_link_spec.js
@@ -145,7 +145,7 @@ describe('CI Badge Link Component', () => {
});
it('should render dynamic badge size', () => {
- createComponent({ status: statuses.success, badgeSize: 'lg' });
+ createComponent({ status: statuses.success, size: 'lg' });
expect(findBadge().props('size')).toBe('lg');
});
diff --git a/spec/frontend/vue_shared/components/code_block_highlighted_spec.js b/spec/frontend/vue_shared/components/code_block_highlighted_spec.js
index 5720f45f4dd..a8436af33f2 100644
--- a/spec/frontend/vue_shared/components/code_block_highlighted_spec.js
+++ b/spec/frontend/vue_shared/components/code_block_highlighted_spec.js
@@ -28,7 +28,7 @@ describe('Code Block Highlighted', () => {
>
const
</span>
- foo =
+ foo =
<span
class="hljs-number"
>
diff --git a/spec/frontend/vue_shared/components/code_block_spec.js b/spec/frontend/vue_shared/components/code_block_spec.js
index 0fdfb96cb23..1bcf0c3938c 100644
--- a/spec/frontend/vue_shared/components/code_block_spec.js
+++ b/spec/frontend/vue_shared/components/code_block_spec.js
@@ -17,12 +17,12 @@ describe('Code Block', () => {
createComponent({}, { default: 'DEFAULT SLOT' });
expect(wrapper.element).toMatchInlineSnapshot(`
- <pre
- class="code-block rounded code"
- >
- DEFAULT SLOT
- </pre>
- `);
+ <pre
+ class="code code-block rounded"
+ >
+ DEFAULT SLOT
+ </pre>
+ `);
});
it('renders with empty code prop', () => {
@@ -30,13 +30,11 @@ describe('Code Block', () => {
expect(wrapper.element).toMatchInlineSnapshot(`
<pre
- class="code-block rounded code"
+ class="code code-block rounded"
>
<code
class="d-block"
- >
-
- </code>
+ />
</pre>
`);
});
@@ -45,32 +43,32 @@ describe('Code Block', () => {
createComponent({ code });
expect(wrapper.element).toMatchInlineSnapshot(`
- <pre
- class="code-block rounded code"
+ <pre
+ class="code code-block rounded"
+ >
+ <code
+ class="d-block"
>
- <code
- class="d-block"
- >
- test-code
- </code>
- </pre>
- `);
+ test-code
+ </code>
+ </pre>
+ `);
});
it('sets maxHeight properly when provided', () => {
createComponent({ code, maxHeight: '200px' });
expect(wrapper.element).toMatchInlineSnapshot(`
- <pre
- class="code-block rounded code"
- style="max-height: 200px; overflow-y: auto;"
+ <pre
+ class="code code-block rounded"
+ style="max-height: 200px; overflow-y: auto;"
+ >
+ <code
+ class="d-block"
>
- <code
- class="d-block"
- >
- test-code
- </code>
- </pre>
- `);
+ test-code
+ </code>
+ </pre>
+ `);
});
});
diff --git a/spec/frontend/vue_shared/components/confidentiality_badge_spec.js b/spec/frontend/vue_shared/components/confidentiality_badge_spec.js
index 92cd7597637..7f6d97e8e68 100644
--- a/spec/frontend/vue_shared/components/confidentiality_badge_spec.js
+++ b/spec/frontend/vue_shared/components/confidentiality_badge_spec.js
@@ -1,15 +1,20 @@
-import { GlBadge } from '@gitlab/ui';
+import { GlBadge, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { TYPE_ISSUE, TYPE_EPIC, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
-const createComponent = ({ workspaceType = WORKSPACE_PROJECT, issuableType = TYPE_ISSUE } = {}) =>
+const createComponent = ({
+ workspaceType = WORKSPACE_PROJECT,
+ issuableType = TYPE_ISSUE,
+ hideTextInSmallScreens = false,
+} = {}) =>
shallowMount(ConfidentialityBadge, {
propsData: {
workspaceType,
issuableType,
+ hideTextInSmallScreens,
},
});
@@ -20,6 +25,11 @@ describe('ConfidentialityBadge', () => {
wrapper = createComponent();
});
+ const findConfidentialityBadgeText = () =>
+ wrapper.find('[data-testid="confidential-badge-text"]');
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const findBadgeIcon = () => wrapper.findComponent(GlIcon);
+
it.each`
workspaceType | issuableType | expectedTooltip
${WORKSPACE_PROJECT} | ${TYPE_ISSUE} | ${'Only project members with at least the Reporter role, the author, and assignees can view or be notified about this issue.'}
@@ -32,14 +42,30 @@ describe('ConfidentialityBadge', () => {
issuableType,
});
- const badgeEl = wrapper.findComponent(GlBadge);
-
- expect(badgeEl.props()).toMatchObject({
- icon: 'eye-slash',
+ expect(findBadgeIcon().props('name')).toBe('eye-slash');
+ expect(findBadge().props()).toMatchObject({
variant: 'warning',
});
- expect(badgeEl.attributes('title')).toBe(expectedTooltip);
- expect(badgeEl.text()).toBe('Confidential');
+ expect(findBadge().attributes('title')).toBe(expectedTooltip);
+ expect(findBadge().text()).toBe('Confidential');
},
);
+
+ it('does not have `gl-sm-display-block` and `gl-display-none` when `hideTextInSmallScreens` is false', () => {
+ wrapper = createComponent({ hideTextInSmallScreens: false });
+
+ expect(findConfidentialityBadgeText().classes()).not.toContain(
+ 'gl-display-none',
+ 'gl-sm-display-block',
+ );
+ });
+
+ it('has `gl-sm-display-block` and `gl-display-none` when `hideTextInSmallScreens` is true', () => {
+ wrapper = createComponent({ hideTextInSmallScreens: true });
+
+ expect(findConfidentialityBadgeText().classes()).toContain(
+ 'gl-display-none',
+ 'gl-sm-display-block',
+ );
+ });
});
diff --git a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
index 0b5c8d9afc3..53218d794c7 100644
--- a/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_danger/confirm_danger_modal_spec.js
@@ -31,6 +31,7 @@ describe('Confirm Danger Modal', () => {
propsData: {
modalId,
phrase,
+ visible: false,
},
provide,
stubs: { GlSprintf },
@@ -103,4 +104,16 @@ describe('Confirm Danger Modal', () => {
expect(wrapper.emitted('confirm')).not.toBeUndefined();
});
});
+
+ describe('v-model', () => {
+ it('emit `change` event', () => {
+ findModal().vm.$emit('change', true);
+
+ expect(wrapper.emitted('change')).toEqual([[true]]);
+ });
+
+ it('sets `visible` prop', () => {
+ expect(findModal().props('visible')).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_input_spec.js b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_input_spec.js
deleted file mode 100644
index a3e5f187f9b..00000000000
--- a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_input_spec.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import { mount } from '@vue/test-utils';
-import DateTimePickerInput from '~/vue_shared/components/date_time_picker/date_time_picker_input.vue';
-
-const inputLabel = 'This is a label';
-const inputValue = 'something';
-
-describe('DateTimePickerInput', () => {
- let wrapper;
-
- const createComponent = (propsData = {}) => {
- wrapper = mount(DateTimePickerInput, {
- propsData: {
- state: null,
- value: '',
- label: '',
- ...propsData,
- },
- });
- };
-
- it('renders label above the input', () => {
- createComponent({
- label: inputLabel,
- });
-
- expect(wrapper.find('.gl-form-group label').text()).toBe(inputLabel);
- });
-
- it('renders the same `ID` for input and `for` for label', () => {
- createComponent({ label: inputLabel });
-
- expect(wrapper.find('.gl-form-group label').attributes('for')).toBe(
- wrapper.find('input').attributes('id'),
- );
- });
-
- it('renders valid input in gray color instead of green', () => {
- createComponent({
- state: true,
- });
-
- expect(wrapper.find('input').classes('is-valid')).toBe(false);
- });
-
- it('renders invalid input in red color', () => {
- createComponent({
- state: false,
- });
-
- expect(wrapper.find('input').classes('is-invalid')).toBe(true);
- });
-
- it('input event is emitted when focus is lost', () => {
- createComponent();
-
- const input = wrapper.find('input');
- input.setValue(inputValue);
- input.trigger('blur');
-
- expect(wrapper.emitted('input')[0][0]).toEqual(inputValue);
- });
-});
diff --git a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_lib_spec.js b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_lib_spec.js
deleted file mode 100644
index 7a8f94b3746..00000000000
--- a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_lib_spec.js
+++ /dev/null
@@ -1,190 +0,0 @@
-import timezoneMock from 'timezone-mock';
-
-import {
- isValidInputString,
- inputStringToIsoDate,
- isoDateToInputString,
-} from '~/vue_shared/components/date_time_picker/date_time_picker_lib';
-
-describe('date time picker lib', () => {
- describe('isValidInputString', () => {
- [
- {
- input: '2019-09-09T00:00:00.000Z',
- output: true,
- },
- {
- input: '2019-09-09T000:00.000Z',
- output: false,
- },
- {
- input: 'a2019-09-09T000:00.000Z',
- output: false,
- },
- {
- input: '2019-09-09T',
- output: false,
- },
- {
- input: '2019-09-09',
- output: true,
- },
- {
- input: '2019-9-9',
- output: true,
- },
- {
- input: '2019-9-',
- output: true,
- },
- {
- input: '2019--',
- output: false,
- },
- {
- input: '2019',
- output: true,
- },
- {
- input: '',
- output: false,
- },
- {
- input: null,
- output: false,
- },
- ].forEach(({ input, output }) => {
- it(`isValidInputString return ${output} for ${input}`, () => {
- expect(isValidInputString(input)).toBe(output);
- });
- });
- });
-
- describe('inputStringToIsoDate', () => {
- [
- '',
- 'null',
- undefined,
- 'abc',
- 'xxxx-xx-xx',
- '9999-99-19',
- '2019-19-23',
- '2019-09-23 x',
- '2019-09-29 24:24:24',
- ].forEach((input) => {
- it(`throws error for invalid input like ${input}`, () => {
- expect(() => inputStringToIsoDate(input)).toThrow();
- });
- });
-
- [
- {
- input: '2019-09-08 01:01:01',
- output: '2019-09-08T01:01:01Z',
- },
- {
- input: '2019-09-08 00:00:00',
- output: '2019-09-08T00:00:00Z',
- },
- {
- input: '2019-09-08 23:59:59',
- output: '2019-09-08T23:59:59Z',
- },
- {
- input: '2019-09-08',
- output: '2019-09-08T00:00:00Z',
- },
- {
- input: '2019-09-08',
- output: '2019-09-08T00:00:00Z',
- },
- {
- input: '2019-09-08 00:00:00',
- output: '2019-09-08T00:00:00Z',
- },
- {
- input: '2019-09-08 23:24:24',
- output: '2019-09-08T23:24:24Z',
- },
- {
- input: '2019-09-08 0:0:0',
- output: '2019-09-08T00:00:00Z',
- },
- ].forEach(({ input, output }) => {
- it(`returns ${output} from ${input}`, () => {
- expect(inputStringToIsoDate(input)).toBe(output);
- });
- });
-
- describe('timezone formatting', () => {
- const value = '2019-09-08 01:01:01';
- const utcResult = '2019-09-08T01:01:01Z';
- const localResult = '2019-09-08T08:01:01Z';
-
- it.each`
- val | locatTimezone | utc | result
- ${value} | ${'UTC'} | ${undefined} | ${utcResult}
- ${value} | ${'UTC'} | ${false} | ${utcResult}
- ${value} | ${'UTC'} | ${true} | ${utcResult}
- ${value} | ${'US/Pacific'} | ${undefined} | ${localResult}
- ${value} | ${'US/Pacific'} | ${false} | ${localResult}
- ${value} | ${'US/Pacific'} | ${true} | ${utcResult}
- `(
- 'when timezone is $locatTimezone, formats $result for utc = $utc',
- ({ val, locatTimezone, utc, result }) => {
- timezoneMock.register(locatTimezone);
-
- expect(inputStringToIsoDate(val, utc)).toBe(result);
-
- timezoneMock.unregister();
- },
- );
- });
- });
-
- describe('isoDateToInputString', () => {
- [
- {
- input: '2019-09-08T01:01:01Z',
- output: '2019-09-08 01:01:01',
- },
- {
- input: '2019-09-08T01:01:01.999Z',
- output: '2019-09-08 01:01:01',
- },
- {
- input: '2019-09-08T00:00:00Z',
- output: '2019-09-08 00:00:00',
- },
- ].forEach(({ input, output }) => {
- it(`returns ${output} for ${input}`, () => {
- expect(isoDateToInputString(input)).toBe(output);
- });
- });
-
- describe('timezone formatting', () => {
- const value = '2019-09-08T08:01:01Z';
- const utcResult = '2019-09-08 08:01:01';
- const localResult = '2019-09-08 01:01:01';
-
- it.each`
- val | locatTimezone | utc | result
- ${value} | ${'UTC'} | ${undefined} | ${utcResult}
- ${value} | ${'UTC'} | ${false} | ${utcResult}
- ${value} | ${'UTC'} | ${true} | ${utcResult}
- ${value} | ${'US/Pacific'} | ${undefined} | ${localResult}
- ${value} | ${'US/Pacific'} | ${false} | ${localResult}
- ${value} | ${'US/Pacific'} | ${true} | ${utcResult}
- `(
- 'when timezone is $locatTimezone, formats $result for utc = $utc',
- ({ val, locatTimezone, utc, result }) => {
- timezoneMock.register(locatTimezone);
-
- expect(isoDateToInputString(val, utc)).toBe(result);
-
- timezoneMock.unregister();
- },
- );
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js
deleted file mode 100644
index 5620b569409..00000000000
--- a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js
+++ /dev/null
@@ -1,326 +0,0 @@
-import { mount } from '@vue/test-utils';
-import timezoneMock from 'timezone-mock';
-import { nextTick } from 'vue';
-import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
-import {
- defaultTimeRanges,
- defaultTimeRange,
-} from '~/vue_shared/components/date_time_picker/date_time_picker_lib';
-
-const optionsCount = defaultTimeRanges.length;
-
-describe('DateTimePicker', () => {
- let wrapper;
-
- const dropdownToggle = () => wrapper.find('.dropdown-toggle');
- const dropdownMenu = () => wrapper.find('.dropdown-menu');
- const cancelButton = () => wrapper.find('[data-testid="cancelButton"]');
- const applyButtonElement = () => wrapper.find('button.btn-confirm').element;
- const findQuickRangeItems = () => wrapper.findAll('.dropdown-item');
-
- const createComponent = (props) => {
- wrapper = mount(DateTimePicker, {
- propsData: {
- ...props,
- },
- });
- };
-
- it('renders dropdown toggle button with selected text', async () => {
- createComponent();
- await nextTick();
- expect(dropdownToggle().text()).toBe(defaultTimeRange.label);
- });
-
- it('renders dropdown toggle button with selected text and utc label', async () => {
- createComponent({ utc: true });
- await nextTick();
- expect(dropdownToggle().text()).toContain(defaultTimeRange.label);
- expect(dropdownToggle().text()).toContain('UTC');
- });
-
- it('renders dropdown with 2 custom time range inputs', async () => {
- createComponent();
- await nextTick();
- expect(wrapper.findAll('input').length).toBe(2);
- });
-
- describe('renders label with h/m/s truncated if possible', () => {
- [
- {
- start: '2019-10-10T00:00:00.000Z',
- end: '2019-10-10T00:00:00.000Z',
- label: '2019-10-10 to 2019-10-10',
- },
- {
- start: '2019-10-10T00:00:00.000Z',
- end: '2019-10-14T00:10:00.000Z',
- label: '2019-10-10 to 2019-10-14 00:10:00',
- },
- {
- start: '2019-10-10T00:00:00.000Z',
- end: '2019-10-10T00:00:01.000Z',
- label: '2019-10-10 to 2019-10-10 00:00:01',
- },
- {
- start: '2019-10-10T00:00:01.000Z',
- end: '2019-10-10T00:00:01.000Z',
- label: '2019-10-10 00:00:01 to 2019-10-10 00:00:01',
- },
- {
- start: '2019-10-10T00:00:01.000Z',
- end: '2019-10-10T00:00:01.000Z',
- utc: true,
- label: '2019-10-10 00:00:01 to 2019-10-10 00:00:01 UTC',
- },
- ].forEach(({ start, end, utc, label }) => {
- it(`for start ${start}, end ${end}, and utc ${utc}, label is ${label}`, async () => {
- createComponent({
- value: { start, end },
- utc,
- });
- await nextTick();
- expect(dropdownToggle().text()).toBe(label);
- });
- });
- });
-
- it(`renders dropdown with ${optionsCount} (default) items in quick range`, async () => {
- createComponent();
- dropdownToggle().trigger('click');
- await nextTick();
- expect(findQuickRangeItems().length).toBe(optionsCount);
- });
-
- it('renders dropdown with a default quick range item selected', async () => {
- createComponent();
- dropdownToggle().trigger('click');
- await nextTick();
- expect(wrapper.find('.dropdown-item.active').exists()).toBe(true);
- expect(wrapper.find('.dropdown-item.active').text()).toBe(defaultTimeRange.label);
- });
-
- it('renders a disabled apply button on wrong input', () => {
- createComponent({
- start: 'invalid-input-date',
- });
-
- expect(applyButtonElement().getAttribute('disabled')).toBe('disabled');
- });
-
- describe('user input', () => {
- const fillInputAndBlur = async (input, val) => {
- wrapper.find(input).setValue(val);
- await nextTick();
- wrapper.find(input).trigger('blur');
- await nextTick();
- };
-
- beforeEach(async () => {
- createComponent();
- await nextTick();
- });
-
- it('displays inline error message if custom time range inputs are invalid', async () => {
- await fillInputAndBlur('#custom-time-from', '2019-10-01abc');
- await fillInputAndBlur('#custom-time-to', '2019-10-10abc');
- expect(wrapper.findAll('.invalid-feedback').length).toBe(2);
- });
-
- it('keeps apply button disabled with invalid custom time range inputs', async () => {
- await fillInputAndBlur('#custom-time-from', '2019-10-01abc');
- await fillInputAndBlur('#custom-time-to', '2019-09-19');
- expect(applyButtonElement().getAttribute('disabled')).toBe('disabled');
- });
-
- it('enables apply button with valid custom time range inputs', async () => {
- await fillInputAndBlur('#custom-time-from', '2019-10-01');
- await fillInputAndBlur('#custom-time-to', '2019-10-19');
- expect(applyButtonElement().getAttribute('disabled')).toBeNull();
- });
-
- describe('when "apply" is clicked', () => {
- it('emits iso dates', async () => {
- await fillInputAndBlur('#custom-time-from', '2019-10-01 00:00:00');
- await fillInputAndBlur('#custom-time-to', '2019-10-19 00:00:00');
- applyButtonElement().click();
-
- expect(wrapper.emitted().input).toHaveLength(1);
- expect(wrapper.emitted().input[0]).toEqual([
- {
- end: '2019-10-19T00:00:00Z',
- start: '2019-10-01T00:00:00Z',
- },
- ]);
- });
-
- it('emits iso dates, for dates without time of day', async () => {
- await fillInputAndBlur('#custom-time-from', '2019-10-01');
- await fillInputAndBlur('#custom-time-to', '2019-10-19');
- applyButtonElement().click();
-
- expect(wrapper.emitted().input).toHaveLength(1);
- expect(wrapper.emitted().input[0]).toEqual([
- {
- end: '2019-10-19T00:00:00Z',
- start: '2019-10-01T00:00:00Z',
- },
- ]);
- });
-
- describe('when timezone is different', () => {
- beforeAll(() => {
- timezoneMock.register('US/Pacific');
- });
- afterAll(() => {
- timezoneMock.unregister();
- });
-
- it('emits iso dates', async () => {
- await fillInputAndBlur('#custom-time-from', '2019-10-01 00:00:00');
- await fillInputAndBlur('#custom-time-to', '2019-10-19 12:00:00');
- applyButtonElement().click();
-
- expect(wrapper.emitted().input).toHaveLength(1);
- expect(wrapper.emitted().input[0]).toEqual([
- {
- start: '2019-10-01T07:00:00Z',
- end: '2019-10-19T19:00:00Z',
- },
- ]);
- });
-
- it('emits iso dates with utc format', async () => {
- wrapper.setProps({ utc: true });
- await nextTick();
- await fillInputAndBlur('#custom-time-from', '2019-10-01 00:00:00');
- await fillInputAndBlur('#custom-time-to', '2019-10-19 12:00:00');
- applyButtonElement().click();
-
- expect(wrapper.emitted().input).toHaveLength(1);
- expect(wrapper.emitted().input[0]).toEqual([
- {
- start: '2019-10-01T00:00:00Z',
- end: '2019-10-19T12:00:00Z',
- },
- ]);
- });
- });
- });
-
- it('unchecks quick range when text is input is clicked', async () => {
- const findActiveItems = () =>
- findQuickRangeItems().filter((w) => w.classes().includes('active'));
-
- expect(findActiveItems().length).toBe(1);
-
- await fillInputAndBlur('#custom-time-from', '2019-10-01');
- expect(findActiveItems().length).toBe(0);
- });
-
- it('emits dates in an object when a is clicked', () => {
- findQuickRangeItems()
- .at(3) // any item
- .trigger('click');
-
- expect(wrapper.emitted().input).toHaveLength(1);
- expect(wrapper.emitted().input[0][0]).toMatchObject({
- duration: {
- seconds: expect.any(Number),
- },
- });
- });
-
- it('hides the popover with cancel button', async () => {
- dropdownToggle().trigger('click');
-
- await nextTick();
- cancelButton().trigger('click');
-
- await nextTick();
- expect(dropdownMenu().classes('show')).toBe(false);
- });
- });
-
- describe('when using non-default time windows', () => {
- const MOCK_NOW = Date.UTC(2020, 0, 23, 20);
-
- const otherTimeRanges = [
- {
- label: '1 minute',
- duration: { seconds: 60 },
- },
- {
- label: '2 minutes',
- duration: { seconds: 60 * 2 },
- default: true,
- },
- {
- label: '5 minutes',
- duration: { seconds: 60 * 5 },
- },
- ];
-
- beforeEach(() => {
- jest.spyOn(Date, 'now').mockImplementation(() => MOCK_NOW);
- });
-
- it('renders dropdown with a label in the quick range', async () => {
- createComponent({
- value: {
- duration: { seconds: 60 * 5 },
- },
- options: otherTimeRanges,
- });
- dropdownToggle().trigger('click');
- await nextTick();
- expect(dropdownToggle().text()).toBe('5 minutes');
- });
-
- it('renders dropdown with a label in the quick range and utc label', async () => {
- createComponent({
- value: {
- duration: { seconds: 60 * 5 },
- },
- utc: true,
- options: otherTimeRanges,
- });
- dropdownToggle().trigger('click');
- await nextTick();
- expect(dropdownToggle().text()).toBe('5 minutes UTC');
- });
-
- it('renders dropdown with quick range items', async () => {
- createComponent({
- value: {
- duration: { seconds: 60 * 2 },
- },
- options: otherTimeRanges,
- });
- dropdownToggle().trigger('click');
- await nextTick();
- const items = findQuickRangeItems();
-
- expect(items.length).toBe(Object.keys(otherTimeRanges).length);
- expect(items.at(0).text()).toBe('1 minute');
- expect(items.at(0).classes()).not.toContain('active');
-
- expect(items.at(1).text()).toBe('2 minutes');
- expect(items.at(1).classes()).toContain('active');
-
- expect(items.at(2).text()).toBe('5 minutes');
- expect(items.at(2).classes()).not.toContain('active');
- });
-
- it('renders dropdown with a label not in the quick range', async () => {
- createComponent({
- value: {
- duration: { seconds: 60 * 4 },
- },
- });
- dropdownToggle().trigger('click');
- await nextTick();
- expect(dropdownToggle().text()).toBe('2020-01-23 19:56:00 to 2020-01-23 20:00:00');
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/design_management/__snapshots__/design_note_pin_spec.js.snap b/spec/frontend/vue_shared/components/design_management/__snapshots__/design_note_pin_spec.js.snap
index eb0adb0bebd..a0b1bb7df09 100644
--- a/spec/frontend/vue_shared/components/design_management/__snapshots__/design_note_pin_spec.js.snap
+++ b/spec/frontend/vue_shared/components/design_management/__snapshots__/design_note_pin_spec.js.snap
@@ -3,20 +3,18 @@
exports[`Design note pin component should match the snapshot of note with index 1`] = `
<button
aria-label="Comment '1' position"
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-font-sm js-image-badge design-note-pin gl-absolute"
+ class="design-note-pin gl-absolute gl-align-items-center gl-display-flex gl-font-sm gl-justify-content-center js-image-badge"
style="left: 10px; top: 10px;"
type="button"
>
-
- 1
-
+ 1
</button>
`;
exports[`Design note pin component should match the snapshot of note without index 1`] = `
<button
aria-label="Comment form position"
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-font-sm btn-transparent comment-indicator gl-absolute"
+ class="btn-transparent comment-indicator gl-absolute gl-align-items-center gl-display-flex gl-font-sm gl-justify-content-center"
style="left: 10px; top: 10px;"
type="button"
>
@@ -30,7 +28,7 @@ exports[`Design note pin component should match the snapshot of note without ind
exports[`Design note pin component should match the snapshot when pin is resolved 1`] = `
<button
aria-label="Comment form position"
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-font-sm btn-transparent comment-indicator resolved gl-absolute"
+ class="btn-transparent comment-indicator gl-absolute gl-align-items-center gl-display-flex gl-font-sm gl-justify-content-center resolved"
style="left: 10px; top: 10px;"
type="button"
>
@@ -44,7 +42,7 @@ exports[`Design note pin component should match the snapshot when pin is resolve
exports[`Design note pin component should match the snapshot when position is absent 1`] = `
<button
aria-label="Comment form position"
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-font-sm btn-transparent comment-indicator"
+ class="btn-transparent comment-indicator gl-align-items-center gl-display-flex gl-font-sm gl-justify-content-center"
type="button"
>
<gl-icon-stub
diff --git a/spec/frontend/vue_shared/components/entity_select/utils_spec.js b/spec/frontend/vue_shared/components/entity_select/utils_spec.js
index 9aa1baf204e..1d73924aa58 100644
--- a/spec/frontend/vue_shared/components/entity_select/utils_spec.js
+++ b/spec/frontend/vue_shared/components/entity_select/utils_spec.js
@@ -2,12 +2,16 @@ import { groupsPath } from '~/vue_shared/components/entity_select/utils';
describe('entity_select utils', () => {
describe('groupsPath', () => {
+ beforeEach(() => {
+ window.gon = { api_version: 'v4' };
+ });
+
it.each`
groupsFilter | parentGroupID | expectedPath
- ${undefined} | ${undefined} | ${'/api/:version/groups.json'}
- ${undefined} | ${1} | ${'/api/:version/groups.json'}
- ${'descendant_groups'} | ${1} | ${'/api/:version/groups/1/descendant_groups'}
- ${'subgroups'} | ${1} | ${'/api/:version/groups/1/subgroups'}
+ ${undefined} | ${undefined} | ${'/api/v4/groups.json'}
+ ${undefined} | ${1} | ${'/api/v4/groups.json'}
+ ${'descendant_groups'} | ${1} | ${'/api/v4/groups/1/descendant_groups'}
+ ${'subgroups'} | ${1} | ${'/api/v4/groups/1/subgroups'}
`(
'returns $expectedPath with groupsFilter = $groupsFilter and parentGroupID = $parentGroupID',
({ groupsFilter, parentGroupID, expectedPath }) => {
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
index b2f4c780f51..a22ad4c450e 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
@@ -84,6 +84,19 @@ export const mockMilestones = [
mockEscapedMilestone,
];
+export const projectMilestonesResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/1',
+ attributes: {
+ nodes: mockMilestones,
+ __typename: 'MilestoneConnection',
+ },
+ __typename: 'Project',
+ },
+ },
+};
+
export const mockCrmContacts = [
{
__typename: 'CustomerRelationsContact',
@@ -257,7 +270,8 @@ export const mockMilestoneToken = {
symbol: '%',
token: MilestoneToken,
operators: OPERATORS_IS,
- fetchMilestones: () => Promise.resolve({ data: mockMilestones }),
+ fullPath: 'gitlab-org',
+ isProject: true,
};
export const mockReleaseToken = {
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js
index db51b4a05b1..36e82b39df4 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js
@@ -6,17 +6,27 @@ import {
} from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { sortMilestonesByDueDate } from '~/milestones/utils';
+import searchMilestonesQuery from '~/issues/list/queries/search_milestones.query.graphql';
import { DEFAULT_MILESTONES } from '~/vue_shared/components/filtered_search_bar/constants';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
-import { mockMilestoneToken, mockMilestones, mockRegularMilestone } from '../mock_data';
+import {
+ mockMilestoneToken,
+ mockMilestones,
+ mockRegularMilestone,
+ projectMilestonesResponse,
+} from '../mock_data';
+
+Vue.use(VueApollo);
jest.mock('~/alert');
jest.mock('~/milestones/utils');
@@ -31,6 +41,9 @@ const defaultStubs = {
},
};
+const milestonesQueryHandler = jest.fn().mockResolvedValue(projectMilestonesResponse);
+const mockApollo = createMockApollo([[searchMilestonesQuery, milestonesQueryHandler]]);
+
function createComponent(options = {}) {
const {
config = { ...mockMilestoneToken, shouldSkipSort: true },
@@ -39,6 +52,7 @@ function createComponent(options = {}) {
stubs = defaultStubs,
} = options;
return mount(MilestoneToken, {
+ apolloProvider: mockApollo,
propsData: {
config,
value,
@@ -102,6 +116,33 @@ describe('MilestoneToken', () => {
});
});
+ describe('default - when fetchMilestones function is not provided in config', () => {
+ beforeEach(() => {
+ wrapper = createComponent({});
+ return triggerFetchMilestones();
+ });
+
+ it('calls searchMilestonesQuery to fetch milestones', () => {
+ expect(milestonesQueryHandler).toHaveBeenCalledWith({
+ fullPath: mockMilestoneToken.fullPath,
+ isProject: mockMilestoneToken.isProject,
+ search: null,
+ });
+ });
+
+ it('calls searchMilestonesQuery with search parameter when provided', async () => {
+ const searchTerm = 'foo';
+
+ await triggerFetchMilestones(searchTerm);
+
+ expect(milestonesQueryHandler).toHaveBeenCalledWith({
+ fullPath: mockMilestoneToken.fullPath,
+ isProject: mockMilestoneToken.isProject,
+ search: searchTerm,
+ });
+ });
+ });
+
describe('when request is successful', () => {
const searchTerm = 'foo';
diff --git a/spec/frontend/vue_shared/components/form/__snapshots__/form_footer_actions_spec.js.snap b/spec/frontend/vue_shared/components/form/__snapshots__/form_footer_actions_spec.js.snap
index 6f98a74a82f..52684cf4259 100644
--- a/spec/frontend/vue_shared/components/form/__snapshots__/form_footer_actions_spec.js.snap
+++ b/spec/frontend/vue_shared/components/form/__snapshots__/form_footer_actions_spec.js.snap
@@ -2,7 +2,7 @@
exports[`Form Footer Actions renders content properly 1`] = `
<footer
- class="gl-mt-5 footer-block"
+ class="footer-block gl-mt-5"
>
Bar Foo Abrakadabra
</footer>
diff --git a/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js b/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js
index 271214907fc..36efcb9efa8 100644
--- a/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js
+++ b/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js
@@ -1,5 +1,5 @@
import { GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
+import { shallowMount, createWrapper } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
@@ -123,24 +123,24 @@ describe('GlModalVuex', () => {
state.isVisible = false;
factory();
- const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit');
+ const rootWrapper = createWrapper(wrapper.vm.$root);
state.isVisible = true;
await nextTick();
- expect(rootEmit).toHaveBeenCalledWith(BV_SHOW_MODAL, TEST_MODAL_ID);
+ expect(rootWrapper.emitted(BV_SHOW_MODAL)[0]).toContain(TEST_MODAL_ID);
});
it('calls bootstrap hide when isVisible changes', async () => {
state.isVisible = true;
factory();
- const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit');
+ const rootWrapper = createWrapper(wrapper.vm.$root);
state.isVisible = false;
await nextTick();
- expect(rootEmit).toHaveBeenCalledWith(BV_HIDE_MODAL, TEST_MODAL_ID);
+ expect(rootWrapper.emitted(BV_HIDE_MODAL)[0]).toContain(TEST_MODAL_ID);
});
it.each(['ok', 'cancel'])(
diff --git a/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js b/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js
index 877de4f4695..cba9f78790d 100644
--- a/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js
+++ b/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js
@@ -9,6 +9,9 @@ import {
} from '~/visibility_level/constants';
import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
import { ACCESS_LEVEL_LABELS } from '~/access_level/constants';
+import ListActions from '~/vue_shared/components/list_actions/list_actions.vue';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+import DangerConfirmModal from '~/vue_shared/components/confirm_danger/confirm_danger_modal.vue';
import { groups } from './mock_data';
describe('GroupsListItem', () => {
@@ -30,6 +33,8 @@ describe('GroupsListItem', () => {
const findAvatarLabeled = () => wrapper.findComponent(GlAvatarLabeled);
const findGroupDescription = () => wrapper.findByTestId('group-description');
const findVisibilityIcon = () => findAvatarLabeled().findComponent(GlIcon);
+ const findListActions = () => wrapper.findComponent(ListActions);
+ const findConfirmationModal = () => wrapper.findComponent(DangerConfirmModal);
it('renders group avatar', () => {
createComponent();
@@ -179,4 +184,68 @@ describe('GroupsListItem', () => {
expect(wrapper.findByTestId('group-icon').exists()).toBe(false);
});
});
+
+ describe('when group has actions', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays actions dropdown', () => {
+ expect(findListActions().props()).toMatchObject({
+ actions: {
+ [ACTION_EDIT]: {
+ href: group.editPath,
+ },
+ [ACTION_DELETE]: {
+ action: expect.any(Function),
+ },
+ },
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+ });
+ });
+
+ describe('when delete action is fired', () => {
+ beforeEach(() => {
+ findListActions().props('actions')[ACTION_DELETE].action();
+ });
+
+ it('displays confirmation modal with correct props', () => {
+ expect(findConfirmationModal().props()).toMatchObject({
+ visible: true,
+ phrase: group.fullName,
+ });
+ });
+
+ describe('when deletion is confirmed', () => {
+ beforeEach(() => {
+ findConfirmationModal().vm.$emit('confirm');
+ });
+
+ it('emits `delete` event', () => {
+ expect(wrapper.emitted('delete')).toMatchObject([[group]]);
+ });
+ });
+ });
+ });
+
+ describe('when group does not have actions', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ group: {
+ ...group,
+ availableActions: [],
+ },
+ },
+ });
+ });
+
+ it('does not display actions dropdown', () => {
+ expect(findListActions().exists()).toBe(false);
+ });
+
+ it('does not display confirmation modal', () => {
+ expect(findConfirmationModal().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/groups_list/groups_list_spec.js b/spec/frontend/vue_shared/components/groups_list/groups_list_spec.js
index c65aa347bcf..ec6a1dc9576 100644
--- a/spec/frontend/vue_shared/components/groups_list/groups_list_spec.js
+++ b/spec/frontend/vue_shared/components/groups_list/groups_list_spec.js
@@ -31,4 +31,18 @@ describe('GroupsList', () => {
})),
);
});
+
+ describe('when `GroupsListItem` emits `delete` event', () => {
+ const [firstGroup] = defaultPropsData.groups;
+
+ beforeEach(() => {
+ createComponent();
+
+ wrapper.findComponent(GroupsListItem).vm.$emit('delete', firstGroup);
+ });
+
+ it('emits `delete` event', () => {
+ expect(wrapper.emitted('delete')).toEqual([[firstGroup]]);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/groups_list/mock_data.js b/spec/frontend/vue_shared/components/groups_list/mock_data.js
index 0dad27f8311..08ee962892c 100644
--- a/spec/frontend/vue_shared/components/groups_list/mock_data.js
+++ b/spec/frontend/vue_shared/components/groups_list/mock_data.js
@@ -1,3 +1,5 @@
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+
export const groups = [
{
id: 1,
@@ -14,6 +16,8 @@ export const groups = [
accessLevel: {
integerValue: 10,
},
+ editPath: 'http://127.0.0.1:3000/groups/gitlab-org/-/edit',
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
},
{
id: 2,
@@ -31,5 +35,7 @@ export const groups = [
accessLevel: {
integerValue: 20,
},
+ editPath: 'http://127.0.0.1:3000/groups/gitlab-org/test-subgroup/-/edit',
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
},
];
diff --git a/spec/frontend/vue_shared/components/header_ci_component_spec.js b/spec/frontend/vue_shared/components/header_ci_component_spec.js
deleted file mode 100644
index da9bc0f8a2f..00000000000
--- a/spec/frontend/vue_shared/components/header_ci_component_spec.js
+++ /dev/null
@@ -1,165 +0,0 @@
-import { GlButton, GlAvatarLink, GlTooltip } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import HeaderCi from '~/vue_shared/components/header_ci_component.vue';
-import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-
-describe('Header CI Component', () => {
- let wrapper;
-
- const defaultProps = {
- status: {
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- details_path: 'path',
- },
- time: '2017-05-08T14:57:39.781Z',
- user: {
- id: 1234,
- web_url: 'path',
- name: 'Foo',
- username: 'foobar',
- email: 'foo@bar.com',
- avatar_url: 'link',
- },
- hasSidebarButton: true,
- };
-
- const findCiBadgeLink = () => wrapper.findComponent(CiBadgeLink);
- const findTimeAgo = () => wrapper.findComponent(TimeagoTooltip);
- const findUserLink = () => wrapper.findComponent(GlAvatarLink);
- const findSidebarToggleBtn = () => wrapper.findComponent(GlButton);
- const findStatusTooltip = () => wrapper.findComponent(GlTooltip);
- const findActionButtons = () => wrapper.findByTestId('ci-header-action-buttons');
- const findHeaderItemText = () => wrapper.findByTestId('ci-header-item-text');
-
- const createComponent = (props, slots) => {
- wrapper = extendedWrapper(
- shallowMount(HeaderCi, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- ...slots,
- }),
- );
- };
-
- describe('render', () => {
- beforeEach(() => {
- createComponent({ itemName: 'Pipeline' });
- });
-
- it('should render status badge', () => {
- expect(findCiBadgeLink().exists()).toBe(true);
- });
-
- it('should render timeago date', () => {
- expect(findTimeAgo().exists()).toBe(true);
- });
-
- it('should render sidebar toggle button', () => {
- expect(findSidebarToggleBtn().exists()).toBe(true);
- });
-
- it('should not render header action buttons when slot is empty', () => {
- expect(findActionButtons().exists()).toBe(false);
- });
- });
-
- describe('user avatar', () => {
- beforeEach(() => {
- createComponent({ itemName: 'Pipeline' });
- });
-
- it('contains the username', () => {
- expect(findUserLink().text()).toContain(defaultProps.user.username);
- });
-
- it('has the correct HTML attributes', () => {
- expect(findUserLink().attributes()).toMatchObject({
- 'data-user-id': defaultProps.user.id.toString(),
- 'data-username': defaultProps.user.username,
- 'data-name': defaultProps.user.name,
- href: defaultProps.user.web_url,
- });
- });
-
- describe('when the user has a status', () => {
- const STATUS_MESSAGE = 'Working on exciting features...';
-
- beforeEach(() => {
- createComponent({
- itemName: 'Pipeline',
- user: { ...defaultProps.user, status: { message: STATUS_MESSAGE } },
- });
- });
-
- it('renders a tooltip', () => {
- expect(findStatusTooltip().text()).toBe(STATUS_MESSAGE);
- });
- });
-
- describe('with data from GraphQL', () => {
- const userId = 1;
-
- beforeEach(() => {
- createComponent({
- itemName: 'Pipeline',
- user: { ...defaultProps.user, id: `gid://gitlab/User/${1}` },
- });
- });
-
- it('has the correct user id', () => {
- expect(findUserLink().attributes('data-user-id')).toBe(userId.toString());
- });
- });
-
- describe('with data from REST', () => {
- it('has the correct user id', () => {
- expect(findUserLink().attributes('data-user-id')).toBe(defaultProps.user.id.toString());
- });
- });
- });
-
- describe('with item id', () => {
- beforeEach(() => {
- createComponent({ itemName: 'Pipeline', itemId: '123' });
- });
-
- it('should render item name and id', () => {
- expect(findHeaderItemText().text()).toBe('Pipeline #123');
- });
- });
-
- describe('without item id', () => {
- beforeEach(() => {
- createComponent({ itemName: 'Job build_job' });
- });
-
- it('should render item name', () => {
- expect(findHeaderItemText().text()).toBe('Job build_job');
- });
- });
-
- describe('slot', () => {
- it('should render header action buttons', () => {
- createComponent({ itemName: 'Job build_job' }, { slots: { default: 'Test Actions' } });
-
- expect(findActionButtons().exists()).toBe(true);
- expect(findActionButtons().text()).toBe('Test Actions');
- });
- });
-
- describe('shouldRenderTriggeredLabel', () => {
- it('should render created keyword when the shouldRenderTriggeredLabel is false', () => {
- createComponent({ shouldRenderTriggeredLabel: false, itemName: 'Job build_job' });
-
- expect(wrapper.text()).toContain('created');
- expect(wrapper.text()).not.toContain('triggered');
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/list_actions/list_actions_spec.js b/spec/frontend/vue_shared/components/list_actions/list_actions_spec.js
new file mode 100644
index 00000000000..ae70cf091a5
--- /dev/null
+++ b/spec/frontend/vue_shared/components/list_actions/list_actions_spec.js
@@ -0,0 +1,135 @@
+import { GlDisclosureDropdown } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ListActions from '~/vue_shared/components/list_actions/list_actions.vue';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
+
+describe('ListActions', () => {
+ let wrapper;
+
+ const defaultPropsData = {
+ actions: {
+ [ACTION_EDIT]: {
+ href: '/-/edit',
+ },
+ [ACTION_DELETE]: {
+ action: () => {},
+ },
+ },
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
+ };
+
+ const createComponent = ({ propsData = {} } = {}) => {
+ wrapper = shallowMountExtended(ListActions, {
+ propsData: {
+ ...defaultPropsData,
+ ...propsData,
+ },
+ });
+ };
+
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const getDropdownItemsProp = () => findDropdown().props('items');
+
+ it('allows extending of base actions', () => {
+ createComponent();
+
+ expect(getDropdownItemsProp()).toEqual([
+ {
+ text: 'Edit',
+ href: '/-/edit',
+ },
+ {
+ text: 'Delete',
+ extraAttrs: {
+ class: 'gl-text-red-500!',
+ },
+ action: expect.any(Function),
+ },
+ ]);
+ });
+
+ it('allows adding custom actions', () => {
+ const ACTION_LEAVE = 'leave';
+
+ createComponent({
+ propsData: {
+ actions: {
+ ...defaultPropsData.actions,
+ [ACTION_LEAVE]: {
+ text: 'Leave project',
+ action: () => {},
+ },
+ },
+ availableActions: [ACTION_EDIT, ACTION_LEAVE, ACTION_DELETE],
+ },
+ });
+
+ expect(getDropdownItemsProp()).toEqual([
+ {
+ text: 'Edit',
+ href: '/-/edit',
+ },
+ {
+ text: 'Leave project',
+ action: expect.any(Function),
+ },
+ {
+ text: 'Delete',
+ extraAttrs: {
+ class: 'gl-text-red-500!',
+ },
+ action: expect.any(Function),
+ },
+ ]);
+ });
+
+ it('only shows available actions', () => {
+ createComponent({
+ propsData: {
+ availableActions: [ACTION_EDIT],
+ },
+ });
+
+ expect(getDropdownItemsProp()).toEqual([
+ {
+ text: 'Edit',
+ href: '/-/edit',
+ },
+ ]);
+ });
+
+ it('displays actions in the order set in `availableActions` prop', () => {
+ createComponent({
+ propsData: {
+ availableActions: [ACTION_DELETE, ACTION_EDIT],
+ },
+ });
+
+ expect(getDropdownItemsProp()).toEqual([
+ {
+ text: 'Delete',
+ extraAttrs: {
+ class: 'gl-text-red-500!',
+ },
+ action: expect.any(Function),
+ },
+ {
+ text: 'Edit',
+ href: '/-/edit',
+ },
+ ]);
+ });
+
+ it('renders `GlDisclosureDropdown` with expected appearance related props', () => {
+ createComponent();
+
+ expect(findDropdown().props()).toMatchObject({
+ icon: 'ellipsis_v',
+ noCaret: true,
+ toggleText: 'Actions',
+ textSrOnly: true,
+ placement: 'right',
+ category: 'tertiary',
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
index 3b49536799c..baf40115e7a 100644
--- a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
+++ b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
@@ -13,9 +13,8 @@ exports[`Suggestion Diff component matches snapshot 1`] = `
isbatched="true"
suggestionscount="0"
/>
-
<table
- class="mb-3 md-suggestion-diff js-syntax-highlight code"
+ class="code js-syntax-highlight mb-3 md-suggestion-diff"
>
<tbody>
<suggestion-diff-row-stub
diff --git a/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js b/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js
index 8aab867f32a..cdbdbfab9d1 100644
--- a/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdown, GlFormTextarea, GlButton, GlAlert } from '@gitlab/ui';
+import { GlDisclosureDropdown, GlFormTextarea, GlButton, GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import ApplySuggestionComponent from '~/vue_shared/components/markdown/apply_suggestion.vue';
@@ -10,10 +10,11 @@ describe('Apply Suggestion component', () => {
wrapper = shallowMount(ApplySuggestionComponent, { propsData: { ...propsData, ...props } });
};
- const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
const findTextArea = () => wrapper.findComponent(GlFormTextarea);
const findApplyButton = () => wrapper.findComponent(GlButton);
const findAlert = () => wrapper.findComponent(GlAlert);
+ const findHelpText = () => wrapper.find('span');
beforeEach(() => createWrapper());
@@ -22,7 +23,7 @@ describe('Apply Suggestion component', () => {
const dropdown = findDropdown();
expect(dropdown.exists()).toBe(true);
- expect(dropdown.props('text')).toBe('Apply suggestion');
+ expect(dropdown.props('toggleText')).toBe('Apply suggestion');
expect(dropdown.props('disabled')).toBe(false);
});
@@ -41,6 +42,22 @@ describe('Apply Suggestion component', () => {
});
});
+ describe('help text', () => {
+ describe('when applying a single suggestion', () => {
+ it('renders the correct help text', () => {
+ expect(findHelpText().text()).toEqual('This also resolves this thread');
+ });
+ });
+
+ describe('when applying in batch', () => {
+ it('renders the correct help text', () => {
+ createWrapper({ batchSuggestionsCount: 3 });
+
+ expect(findHelpText().text()).toEqual('This also resolves all related threads');
+ });
+ });
+ });
+
describe('disabled', () => {
it('disables the dropdown', () => {
createWrapper({ disabled: true });
diff --git a/spec/frontend/vue_shared/components/markdown/comment_templates_dropdown_spec.js b/spec/frontend/vue_shared/components/markdown/comment_templates_dropdown_spec.js
index cd9f27dccbd..11c57fc5768 100644
--- a/spec/frontend/vue_shared/components/markdown/comment_templates_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/comment_templates_dropdown_spec.js
@@ -12,6 +12,7 @@ import savedRepliesQuery from '~/vue_shared/components/markdown/saved_replies.qu
import {
TRACKING_SAVED_REPLIES_USE,
TRACKING_SAVED_REPLIES_USE_IN_MR,
+ TRACKING_SAVED_REPLIES_USE_IN_OTHER,
} from '~/vue_shared/components/markdown/constants';
let wrapper;
@@ -87,6 +88,12 @@ describe('Comment templates dropdown', () => {
});
describe('tracking', () => {
+ it('always sends two tracking events', async () => {
+ await selectSavedReply();
+
+ expect(trackingSpy).toHaveBeenCalledTimes(2);
+ });
+
it('tracks overall usage', async () => {
await selectSavedReply();
@@ -108,7 +115,6 @@ describe('Comment templates dropdown', () => {
TRACKING_SAVED_REPLIES_USE_IN_MR,
expect.any(Object),
);
- expect(trackingSpy).toHaveBeenCalledTimes(2);
});
it('is not sent when not in an MR', async () => {
@@ -121,7 +127,32 @@ describe('Comment templates dropdown', () => {
TRACKING_SAVED_REPLIES_USE_IN_MR,
expect.any(Object),
);
- expect(trackingSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('non-MR usage event', () => {
+ it('is sent when not in an MR', async () => {
+ window.location.toString.mockReturnValue('this/looks/like/a/-/issues/1');
+
+ await selectSavedReply();
+
+ expect(trackingSpy).toHaveBeenCalledWith(
+ expect.any(String),
+ TRACKING_SAVED_REPLIES_USE_IN_OTHER,
+ expect.any(Object),
+ );
+ });
+
+ it('is not sent when in an MR', async () => {
+ window.location.toString.mockReturnValue('this/looks/like/a/-/merge_requests/1');
+
+ await selectSavedReply();
+
+ expect(trackingSpy).not.toHaveBeenCalledWith(
+ expect.any(String),
+ TRACKING_SAVED_REPLIES_USE_IN_OTHER,
+ expect.any(Object),
+ );
});
});
});
diff --git a/spec/frontend/vue_shared/components/markdown/field_view_spec.js b/spec/frontend/vue_shared/components/markdown/field_view_spec.js
index 1bbbe0896f2..f61c67c4f9b 100644
--- a/spec/frontend/vue_shared/components/markdown/field_view_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/field_view_spec.js
@@ -6,15 +6,27 @@ import { renderGFM } from '~/behaviors/markdown/render_gfm';
jest.mock('~/behaviors/markdown/render_gfm');
describe('Markdown Field View component', () => {
- function createComponent() {
- shallowMount(MarkdownFieldView);
+ function createComponent(isLoading = false) {
+ shallowMount(MarkdownFieldView, { propsData: { isLoading } });
}
- beforeEach(() => {
+ it('processes rendering with GFM', () => {
createComponent();
- });
- it('processes rendering with GFM', () => {
expect(renderGFM).toHaveBeenCalledTimes(1);
});
+
+ describe('watchers', () => {
+ it('does not process rendering with GFM if isLoading is true', () => {
+ createComponent(true);
+
+ expect(renderGFM).not.toHaveBeenCalled();
+ });
+
+ it('processes rendering with GFM when isLoading is updated to `false`', () => {
+ createComponent(false);
+
+ expect(renderGFM).toHaveBeenCalledTimes(1);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
index 31c0fa6f699..c69b18bca88 100644
--- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
@@ -489,6 +489,11 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(localStorage.getItem('autosave/issue/1234')).toBe(newValue);
});
+ it('does not autofocus the content editor', () => {
+ buildWrapper({ propsData: { autosaveKey: 'issue/1234' } });
+ expect(findContentEditor().props().autofocus).toBe(false);
+ });
+
it('bubbles up keydown event', () => {
const event = new Event('keydown');
diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
index 9768bc7a6dd..bc82357cb81 100644
--- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
@@ -219,12 +219,11 @@ describe('Suggestion Diff component', () => {
describe('tooltip message for apply button', () => {
const findTooltip = () => getBinding(findApplyButton().element, 'gl-tooltip');
- it('renders correct tooltip message when button is applicable', () => {
- createComponent({ batchSuggestionsCount: 0 });
+ it('renders no tooltip message when button is applicable', () => {
+ createComponent({ batchSuggestionsCount: 1, isBatched: true });
const tooltip = findTooltip();
- expect(tooltip.modifiers.viewport).toBe(true);
- expect(tooltip.value).toBe('This also resolves this thread');
+ expect(tooltip.value).toBe(false);
});
it('renders the inapplicable reason in the tooltip when button is not applicable', () => {
diff --git a/spec/frontend/vue_shared/components/metric_images/__snapshots__/metric_images_table_spec.js.snap b/spec/frontend/vue_shared/components/metric_images/__snapshots__/metric_images_table_spec.js.snap
index 015049795a1..2dd7149069f 100644
--- a/spec/frontend/vue_shared/components/metric_images/__snapshots__/metric_images_table_spec.js.snap
+++ b/spec/frontend/vue_shared/components/metric_images/__snapshots__/metric_images_table_spec.js.snap
@@ -3,7 +3,7 @@
exports[`Metrics upload item render the metrics image component 1`] = `
<gl-card-stub
bodyclass="gl-border-1,gl-border-t-solid,gl-border-gray-100,[object Object]"
- class="collapsible-card border gl-p-0 gl-mb-5"
+ class="border collapsible-card gl-mb-5 gl-p-0"
footerclass=""
headerclass="gl-display-flex gl-align-items-center gl-border-b-0 gl-py-3"
>
@@ -18,12 +18,10 @@ exports[`Metrics upload item render the metrics image component 1`] = `
size="sm"
titletag="h4"
>
-
<p>
Are you sure you wish to delete this image?
</p>
</gl-modal-stub>
-
<gl-modal-stub
actioncancel="[object Object]"
actionprimary="[object Object]"
@@ -35,7 +33,6 @@ exports[`Metrics upload item render the metrics image component 1`] = `
size="sm"
titletag="h4"
>
-
<gl-form-group-stub
label="Text (optional)"
label-for="upload-text-input"
@@ -44,10 +41,9 @@ exports[`Metrics upload item render the metrics image component 1`] = `
>
<gl-form-input-stub
data-testid="metric-image-text-field"
- id="upload-text-input"
+ id="reference-0"
/>
</gl-form-group-stub>
-
<gl-form-group-stub
description="Must start with http or https"
label="Link (optional)"
@@ -57,17 +53,16 @@ exports[`Metrics upload item render the metrics image component 1`] = `
>
<gl-form-input-stub
data-testid="metric-image-url-field"
- id="upload-url-input"
+ id="reference-1"
/>
</gl-form-group-stub>
</gl-modal-stub>
-
<div
class="gl-display-flex gl-flex-direction-column"
data-testid="metric-image-body"
>
<img
- class="gl-max-w-full gl-align-self-center"
+ class="gl-align-self-center gl-max-w-full"
src="test_file_path"
/>
</div>
diff --git a/spec/frontend/vue_shared/components/notes/__snapshots__/noteable_warning_spec.js.snap b/spec/frontend/vue_shared/components/notes/__snapshots__/noteable_warning_spec.js.snap
index 8a187f3cb1f..891b0c95f0e 100644
--- a/spec/frontend/vue_shared/components/notes/__snapshots__/noteable_warning_spec.js.snap
+++ b/spec/frontend/vue_shared/components/notes/__snapshots__/noteable_warning_spec.js.snap
@@ -2,10 +2,7 @@
exports[`Issue Warning Component when issue is locked but not confidential renders information about locked issue 1`] = `
<span>
-
- This issue is locked.
- Only project members can comment.
-
+ This issue is locked. Only project members can comment.
<gl-link-stub
href="locked-path"
target="_blank"
@@ -17,10 +14,7 @@ exports[`Issue Warning Component when issue is locked but not confidential rende
exports[`Issue Warning Component when noteable is confidential but not locked renders information about confidential issue 1`] = `
<span>
-
- This is a confidential issue.
- People without permission will never get a notification.
-
+ This is a confidential issue. People without permission will never get a notification.
<gl-link-stub
href="confidential-path"
target="_blank"
@@ -33,14 +27,14 @@ exports[`Issue Warning Component when noteable is confidential but not locked re
exports[`Issue Warning Component when noteable is locked and confidential renders information about locked and confidential noteable 1`] = `
<span>
<span>
- This issue is
+ This issue is
<gl-link-stub
href=""
target="_blank"
>
confidential
</gl-link-stub>
- and
+ and
<gl-link-stub
href=""
target="_blank"
@@ -49,8 +43,6 @@ exports[`Issue Warning Component when noteable is locked and confidential render
</gl-link-stub>
.
</span>
-
- People without permission will never get a notification and won't be able to comment.
-
+ People without permission will never get a notification and won't be able to comment.
</span>
`;
diff --git a/spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_note_spec.js.snap b/spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_note_spec.js.snap
index de53caa66c7..c489fb08be5 100644
--- a/spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_note_spec.js.snap
+++ b/spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_note_spec.js.snap
@@ -2,10 +2,10 @@
exports[`Issue placeholder note component matches snapshot 1`] = `
<timeline-entry-item-stub
- class="note note-wrapper note-comment being-posted fade-in-half"
+ class="being-posted fade-in-half note note-comment note-wrapper"
>
<div
- class="timeline-avatar gl-float-left"
+ class="gl-float-left timeline-avatar"
>
<gl-avatar-link-stub
href="/root"
@@ -20,9 +20,8 @@ exports[`Issue placeholder note component matches snapshot 1`] = `
/>
</gl-avatar-link-stub>
</div>
-
<div
- class="timeline-content discussion"
+ class="discussion timeline-content"
>
<div
class="note-header"
@@ -34,11 +33,10 @@ exports[`Issue placeholder note component matches snapshot 1`] = `
href="/root"
>
<span
- class="d-none d-sm-inline-block bold"
+ class="bold d-none d-sm-inline-block"
>
Root
</span>
-
<span
class="note-headline-light"
>
@@ -47,7 +45,6 @@ exports[`Issue placeholder note component matches snapshot 1`] = `
</a>
</div>
</div>
-
<div
class="timeline-discussion-body"
>
@@ -55,15 +52,13 @@ exports[`Issue placeholder note component matches snapshot 1`] = `
class="note-body"
>
<div
- class="note-text md"
+ class="md note-text"
>
<p
dir="auto"
>
Foo
</p>
-
-
</div>
</div>
</div>
diff --git a/spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_system_note_spec.js.snap b/spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_system_note_spec.js.snap
index 10c33269107..a609df5e775 100644
--- a/spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_system_note_spec.js.snap
+++ b/spec/frontend/vue_shared/components/notes/__snapshots__/placeholder_system_note_spec.js.snap
@@ -2,7 +2,7 @@
exports[`Placeholder system note component matches snapshot 1`] = `
<timeline-entry-item-stub
- class="note system-note being-posted fade-in-half"
+ class="being-posted fade-in-half note system-note"
>
<div
class="timeline-content"
diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js
index e5b641c61fd..335c5bdfc46 100644
--- a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js
+++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js
@@ -291,7 +291,7 @@ describe('AlertManagementEmptyState', () => {
it('renders the search component for incidents', () => {
const filteredSearchBar = findFilteredSearchBar();
- expect(filteredSearchBar.props('searchInputPlaceholder')).toBe('Search or filter results…');
+
expect(filteredSearchBar.props('tokens')).toEqual([
{
type: TOKEN_TYPE_AUTHOR,
diff --git a/spec/frontend/vue_shared/components/pagination_bar/pagination_bar_spec.js b/spec/frontend/vue_shared/components/pagination_bar/pagination_bar_spec.js
index 2a1a6342c38..4cb1c1f3616 100644
--- a/spec/frontend/vue_shared/components/pagination_bar/pagination_bar_spec.js
+++ b/spec/frontend/vue_shared/components/pagination_bar/pagination_bar_spec.js
@@ -1,4 +1,4 @@
-import { GlPagination, GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlPagination, GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import PaginationBar from '~/vue_shared/components/pagination_bar/pagination_bar.vue';
import PaginationLinks from '~/vue_shared/components/pagination_links.vue';
@@ -42,8 +42,8 @@ describe('Pagination bar', () => {
});
it('emits set-page-size event when page size is selected', () => {
- const firstItemInPageSizeDropdown = wrapper.findComponent(GlDropdownItem);
- firstItemInPageSizeDropdown.vm.$emit('click');
+ const firstItemInPageSizeDropdown = wrapper.findComponent(GlDisclosureDropdownItem);
+ firstItemInPageSizeDropdown.vm.$emit('action');
const [emittedPageSizeChange] = wrapper.emitted('set-page-size')[0];
expect(firstItemInPageSizeDropdown.text()).toMatchInterpolatedText(
@@ -62,9 +62,9 @@ describe('Pagination bar', () => {
},
});
- expect(wrapper.findComponent(GlDropdown).find('button').text()).toMatchInterpolatedText(
- `${CURRENT_PAGE_SIZE} items per page`,
- );
+ expect(
+ wrapper.findComponent(GlDisclosureDropdown).find('button').text(),
+ ).toMatchInterpolatedText(`${CURRENT_PAGE_SIZE} items per page`);
});
it('renders current page information', () => {
diff --git a/spec/frontend/vue_shared/components/projects_list/projects_list_item_spec.js b/spec/frontend/vue_shared/components/projects_list/projects_list_item_spec.js
index 2490422e4e8..7cf560745b6 100644
--- a/spec/frontend/vue_shared/components/projects_list/projects_list_item_spec.js
+++ b/spec/frontend/vue_shared/components/projects_list/projects_list_item_spec.js
@@ -1,10 +1,10 @@
-import { GlAvatarLabeled, GlBadge, GlIcon, GlPopover, GlDisclosureDropdown } from '@gitlab/ui';
+import { GlAvatarLabeled, GlBadge, GlIcon, GlPopover } from '@gitlab/ui';
import uniqueId from 'lodash/uniqueId';
import projects from 'test_fixtures/api/users/projects/get.json';
import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { __ } from '~/locale';
import ProjectsListItem from '~/vue_shared/components/projects_list/projects_list_item.vue';
-import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/projects_list/constants';
+import ListActions from '~/vue_shared/components/list_actions/list_actions.vue';
+import { ACTION_EDIT, ACTION_DELETE } from '~/vue_shared/components/list_actions/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import {
@@ -43,6 +43,7 @@ describe('ProjectsListItem', () => {
const findPopover = () => findProjectTopics().findComponent(GlPopover);
const findProjectDescription = () => wrapper.findByTestId('project-description');
const findVisibilityIcon = () => findAvatarLabeled().findComponent(GlIcon);
+ const findListActions = () => wrapper.findComponent(ListActions);
beforeEach(() => {
uniqueId.mockImplementation(jest.requireActual('lodash/uniqueId'));
@@ -327,7 +328,7 @@ describe('ProjectsListItem', () => {
propsData: {
project: {
...project,
- actions: [ACTION_EDIT, ACTION_DELETE],
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
isForked: true,
editPath,
},
@@ -336,32 +337,22 @@ describe('ProjectsListItem', () => {
});
it('displays actions dropdown', () => {
- expect(wrapper.findComponent(GlDisclosureDropdown).props()).toMatchObject({
- items: [
- {
- id: ACTION_EDIT,
- text: __('Edit'),
+ expect(findListActions().props()).toMatchObject({
+ actions: {
+ [ACTION_EDIT]: {
href: editPath,
},
- {
- id: ACTION_DELETE,
- text: __('Delete'),
- extraAttrs: {
- class: 'gl-text-red-500!',
- },
+ [ACTION_DELETE]: {
action: expect.any(Function),
},
- ],
+ },
+ availableActions: [ACTION_EDIT, ACTION_DELETE],
});
});
describe('when delete action is fired', () => {
beforeEach(() => {
- wrapper
- .findComponent(GlDisclosureDropdown)
- .props('items')
- .find((item) => item.id === ACTION_DELETE)
- .action();
+ findListActions().props('actions')[ACTION_DELETE].action();
});
it('displays confirmation modal with correct props', () => {
diff --git a/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap b/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
index eadcb6ceeb7..64bab2de3b7 100644
--- a/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
+++ b/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
@@ -7,14 +7,12 @@ exports[`Package code instruction multiline to match the snapshot 1`] = `
>
foo_label
</label>
-
<div>
<pre
class="gl-font-monospace"
data-testid="multiline-instruction"
>
- this is some
-multiline text
+ this is somemultiline text
</pre>
</div>
</div>
@@ -23,25 +21,23 @@ multiline text
exports[`Package code instruction single line to match the default snapshot 1`] = `
<div>
<label
- for="instruction-input_1"
+ for="reference-0"
>
foo_label
</label>
-
<div
class="gl-mb-3"
>
<div
- class="input-group gl-mb-3"
+ class="gl-mb-3 input-group"
>
<input
class="form-control gl-font-monospace"
data-testid="instruction-input"
- id="instruction-input_1"
- readonly="readonly"
+ id="reference-0"
+ readonly=""
type="text"
/>
-
<span
class="input-group-append"
data-testid="instruction-button"
diff --git a/spec/frontend/vue_shared/components/registry/__snapshots__/history_item_spec.js.snap b/spec/frontend/vue_shared/components/registry/__snapshots__/history_item_spec.js.snap
index 5c487754b87..8eb0e08908b 100644
--- a/spec/frontend/vue_shared/components/registry/__snapshots__/history_item_spec.js.snap
+++ b/spec/frontend/vue_shared/components/registry/__snapshots__/history_item_spec.js.snap
@@ -2,20 +2,19 @@
exports[`History Item renders the correct markup 1`] = `
<li
- class="timeline-entry system-note note-wrapper"
+ class="note-wrapper system-note timeline-entry"
>
<div
class="timeline-entry-inner"
>
<div
- class="gl--flex-center gl-rounded-full gl-mt-n1 gl-ml-2 gl-w-6 gl-h-6 gl-bg-gray-50 gl-text-gray-600 gl-float-left"
+ class="gl--flex-center gl-bg-gray-50 gl-float-left gl-h-6 gl-ml-2 gl-mt-n1 gl-rounded-full gl-text-gray-600 gl-w-6"
>
<gl-icon-stub
name="pencil"
size="16"
/>
</div>
-
<div
class="timeline-content"
>
@@ -30,7 +29,6 @@ exports[`History Item renders the correct markup 1`] = `
/>
</div>
</div>
-
<div
class="note-body"
>
diff --git a/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/skeleton_loader_spec.js.snap b/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/skeleton_loader_spec.js.snap
index 65427374e1b..22cfe8a5fc7 100644
--- a/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/skeleton_loader_spec.js.snap
+++ b/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/skeleton_loader_spec.js.snap
@@ -23,7 +23,7 @@ exports[`Resizable Skeleton Loader default setup renders the bars, labels, and g
/>
<defs>
<clippath
- id="null-idClip"
+ id="reference-0"
>
<rect
data-testid="skeleton-chart-grid"
@@ -46,7 +46,6 @@ exports[`Resizable Skeleton Loader default setup renders the bars, labels, and g
x="0"
y="90%"
/>
-
<rect
data-testid="skeleton-chart-bar"
height="5%"
@@ -111,7 +110,6 @@ exports[`Resizable Skeleton Loader default setup renders the bars, labels, and g
x="90%"
y="10%"
/>
-
<rect
data-testid="skeleton-chart-label"
height="3%"
@@ -178,7 +176,7 @@ exports[`Resizable Skeleton Loader default setup renders the bars, labels, and g
/>
</clippath>
<lineargradient
- id="null-idGradient"
+ id="reference-1"
>
<stop
class="primary-stop"
@@ -242,7 +240,7 @@ exports[`Resizable Skeleton Loader with custom settings renders the correct posi
/>
<defs>
<clippath
- id="-idClip"
+ id="reference-0"
>
<rect
data-testid="skeleton-chart-grid"
@@ -265,7 +263,6 @@ exports[`Resizable Skeleton Loader with custom settings renders the correct posi
x="0"
y="90%"
/>
-
<rect
data-testid="skeleton-chart-bar"
height="5%"
@@ -330,7 +327,6 @@ exports[`Resizable Skeleton Loader with custom settings renders the correct posi
x="90.9375%"
y="10%"
/>
-
<rect
data-testid="skeleton-chart-label"
height="2%"
@@ -397,7 +393,7 @@ exports[`Resizable Skeleton Loader with custom settings renders the correct posi
/>
</clippath>
<lineargradient
- id="-idGradient"
+ id="reference-1"
>
<stop
class="primary-stop"
diff --git a/spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap b/spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap
index a0f46f07d6a..91d1b0accf1 100644
--- a/spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap
+++ b/spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap
@@ -9,11 +9,11 @@ exports[`Settings Block renders the correct markup 1`] = `
>
<h4>
<span
- aria-controls="settings_content_3"
+ aria-controls="reference-1"
aria-expanded="false"
class="gl-cursor-pointer"
data-testid="section-title-button"
- id="settings_label_2"
+ id="reference-0"
role="button"
tabindex="0"
>
@@ -22,9 +22,8 @@ exports[`Settings Block renders the correct markup 1`] = `
/>
</span>
</h4>
-
<gl-button-stub
- aria-controls="settings_content_3"
+ aria-controls="reference-1"
aria-expanded="false"
aria-label="Expand settings section"
buttontextclasses=""
@@ -33,22 +32,18 @@ exports[`Settings Block renders the correct markup 1`] = `
size="medium"
variant="default"
>
-
Expand
-
</gl-button-stub>
-
<p>
<div
data-testid="description-slot"
/>
</p>
</div>
-
<div
- aria-labelledby="settings_label_2"
+ aria-labelledby="reference-0"
class="settings-content"
- id="settings_content_3"
+ id="reference-1"
role="region"
style="display: none;"
tabindex="-1"
diff --git a/spec/frontend/vue_shared/components/source_viewer/components/__snapshots__/chunk_new_spec.js.snap b/spec/frontend/vue_shared/components/source_viewer/components/__snapshots__/chunk_new_spec.js.snap
index 26c9a6f8d5a..bab1920fd3a 100644
--- a/spec/frontend/vue_shared/components/source_viewer/components/__snapshots__/chunk_new_spec.js.snap
+++ b/spec/frontend/vue_shared/components/source_viewer/components/__snapshots__/chunk_new_spec.js.snap
@@ -2,23 +2,20 @@
exports[`Chunk component rendering isHighlighted is true renders line numbers 1`] = `
<div
- class="gl-p-0! gl-z-index-3 diff-line-num gl-border-r gl-display-flex line-links line-numbers"
+ class="diff-line-num gl-border-r gl-display-flex gl-p-0! gl-z-index-3 line-links line-numbers"
data-testid="line-numbers"
>
<a
- class="gl-user-select-none gl-shadow-none! file-line-blame"
+ class="file-line-blame gl-shadow-none! gl-user-select-none"
href="some/blame/path.js#L71"
/>
-
<a
- class="gl-user-select-none gl-shadow-none! file-line-num"
+ class="file-line-num gl-shadow-none! gl-user-select-none"
data-line-number="71"
href="#L71"
- id="L71"
+ id="reference-0"
>
-
- 71
-
+ 71
</a>
</div>
`;
diff --git a/spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js b/spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js
index 1154c930e5d..852598b13dc 100644
--- a/spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js
@@ -35,6 +35,7 @@ describe('Chunk component', () => {
await nextTick();
expect(findContent().exists()).toBe(true);
+ expect(wrapper.emitted('appear')).toHaveLength(1);
});
});
diff --git a/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js b/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js
index 431ede17954..1a498d0c5b1 100644
--- a/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js
@@ -58,7 +58,8 @@ describe('Source Viewer component', () => {
describe('hash highlighting', () => {
it('calls highlightHash with expected parameter', () => {
- expect(lineHighlighter.highlightHash).toHaveBeenCalledWith(hash);
+ const scrollEnabled = false;
+ expect(lineHighlighter.highlightHash).toHaveBeenCalledWith(hash, scrollEnabled);
});
});
});
diff --git a/spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js b/spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js
index a486d13a856..2043f36443d 100644
--- a/spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js
@@ -1,10 +1,9 @@
import hljs from 'highlight.js/lib/core';
-import Vue from 'vue';
-import VueRouter from 'vue-router';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import SourceViewer from '~/vue_shared/components/source_viewer/source_viewer.vue';
+import CodeownersValidation from 'ee_component/blob/components/codeowners_validation.vue';
import { registerPlugins } from '~/vue_shared/components/source_viewer/plugins/index';
import Chunk from '~/vue_shared/components/source_viewer/components/chunk.vue';
import {
@@ -24,11 +23,10 @@ import LineHighlighter from '~/blob/line_highlighter';
import eventHub from '~/notes/event_hub';
import Tracking from '~/tracking';
-jest.mock('~/blob/line_highlighter');
+const lineHighlighter = new LineHighlighter();
+jest.mock('~/blob/line_highlighter', () => jest.fn().mockReturnValue({ highlightHash: jest.fn() }));
jest.mock('highlight.js/lib/core');
jest.mock('~/vue_shared/components/source_viewer/plugins/index');
-Vue.use(VueRouter);
-const router = new VueRouter();
const mockAxios = new MockAdapter(axios);
const generateContent = (content, totalLines = 1, delimiter = '\n') => {
@@ -44,6 +42,7 @@ const execImmediately = (callback) => callback();
describe('Source Viewer component', () => {
let wrapper;
const language = 'docker';
+ const selectedRangeHash = '#L1-2';
const mappedLanguage = ROUGE_TO_HLJS_LANGUAGE_MAP[language];
const chunk1 = generateContent('// Some source code 1', 70);
const chunk2 = generateContent('// Some source code 2', 70);
@@ -55,11 +54,13 @@ describe('Source Viewer component', () => {
const fileType = 'javascript';
const DEFAULT_BLOB_DATA = { language, rawTextBlob: content, path, blamePath, fileType };
const highlightedContent = `<span data-testid='test-highlighted' id='LC1'>${content}</span><span id='LC2'></span>`;
+ const currentRef = 'main';
+ const projectPath = 'test/project';
const createComponent = async (blob = {}) => {
wrapper = shallowMountExtended(SourceViewer, {
- router,
- propsData: { blob: { ...DEFAULT_BLOB_DATA, ...blob } },
+ propsData: { blob: { ...DEFAULT_BLOB_DATA, ...blob }, currentRef, projectPath },
+ mocks: { $route: { hash: selectedRangeHash } },
});
await waitForPromises();
};
@@ -268,5 +269,25 @@ describe('Source Viewer component', () => {
it('instantiates the lineHighlighter class', () => {
expect(LineHighlighter).toHaveBeenCalledWith({ scrollBehavior: 'auto' });
});
+
+ it('highlights the range when chunk appears', () => {
+ findChunks().at(0).vm.$emit('appear');
+ const scrollEnabled = false;
+ expect(lineHighlighter.highlightHash).toHaveBeenCalledWith(selectedRangeHash, scrollEnabled);
+ });
+ });
+
+ describe('Codeowners validation', () => {
+ const findCodeownersValidation = () => wrapper.findComponent(CodeownersValidation);
+
+ it('does not render codeowners validation when file is not CODEOWNERS', async () => {
+ await createComponent();
+ expect(findCodeownersValidation().exists()).toBe(false);
+ });
+
+ it('renders codeowners validation when file is CODEOWNERS', async () => {
+ await createComponent({ name: CODEOWNERS_FILE_NAME });
+ expect(findCodeownersValidation().exists()).toBe(true);
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/split_button_spec.js b/spec/frontend/vue_shared/components/split_button_spec.js
deleted file mode 100644
index ffa25ae8448..00000000000
--- a/spec/frontend/vue_shared/components/split_button_spec.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-
-import { nextTick } from 'vue';
-import { assertProps } from 'helpers/assert_props';
-import SplitButton from '~/vue_shared/components/split_button.vue';
-
-const mockActionItems = [
- {
- eventName: 'concert',
- title: 'professor',
- description: 'very symphonic',
- },
- {
- eventName: 'apocalypse',
- title: 'captain',
- description: 'warp drive',
- },
-];
-
-describe('SplitButton', () => {
- let wrapper;
-
- const createComponent = (propsData) => {
- wrapper = shallowMount(SplitButton, {
- propsData,
- });
- };
-
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDropdownItem = (index = 0) =>
- findDropdown().findAllComponents(GlDropdownItem).at(index);
- const selectItem = async (index) => {
- findDropdownItem(index).vm.$emit('click');
-
- await nextTick();
- };
- const clickToggleButton = async () => {
- findDropdown().vm.$emit('click');
-
- await nextTick();
- };
-
- it('fails for empty actionItems', () => {
- const actionItems = [];
- expect(() => assertProps(SplitButton, { actionItems })).toThrow();
- });
-
- it('fails for single actionItems', () => {
- const actionItems = [mockActionItems[0]];
- expect(() => assertProps(SplitButton, { actionItems })).toThrow();
- });
-
- it('renders actionItems', () => {
- createComponent({ actionItems: mockActionItems });
-
- expect(wrapper.element).toMatchSnapshot();
- });
-
- describe('toggle button text', () => {
- beforeEach(() => {
- createComponent({ actionItems: mockActionItems });
- });
-
- it('defaults to first actionItems title', () => {
- expect(findDropdown().props().text).toBe(mockActionItems[0].title);
- });
-
- it('changes to selected actionItems title', () =>
- selectItem(1).then(() => {
- expect(findDropdown().props().text).toBe(mockActionItems[1].title);
- }));
- });
-
- describe('emitted event', () => {
- let eventHandler;
- let changeEventHandler;
-
- beforeEach(() => {
- createComponent({ actionItems: mockActionItems });
- });
-
- const addEventHandler = ({ eventName }) => {
- eventHandler = jest.fn();
- wrapper.vm.$once(eventName, () => eventHandler());
- };
-
- const addChangeEventHandler = () => {
- changeEventHandler = jest.fn();
- wrapper.vm.$once('change', (item) => changeEventHandler(item));
- };
-
- it('defaults to first actionItems event', () => {
- addEventHandler(mockActionItems[0]);
-
- return clickToggleButton().then(() => {
- expect(eventHandler).toHaveBeenCalled();
- });
- });
-
- it('changes to selected actionItems event', () =>
- selectItem(1)
- .then(() => addEventHandler(mockActionItems[1]))
- .then(clickToggleButton)
- .then(() => {
- expect(eventHandler).toHaveBeenCalled();
- }));
-
- it('change to selected actionItem emits change event', () => {
- addChangeEventHandler();
-
- return selectItem(1).then(() => {
- expect(changeEventHandler).toHaveBeenCalledWith(mockActionItems[1]);
- });
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap b/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
index c816fe790a8..cffe26f8175 100644
--- a/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
+++ b/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
@@ -2,14 +2,14 @@
exports[`Upload dropzone component correctly overrides description and drop messages 1`] = `
<div
- class="gl-w-full gl-relative"
+ class="gl-relative gl-w-full"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-px-5 gl-py-4 gl-mb-0"
+ class="card gl-align-items-center gl-h-full gl-justify-content-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
type="button"
>
<div
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
+ class="gl-align-items-center gl-display-flex gl-flex-direction-column gl-justify-content-center gl-text-center"
data-testid="dropzone-area"
>
<gl-icon-stub
@@ -17,7 +17,6 @@ exports[`Upload dropzone component correctly overrides description and drop mess
name="upload"
size="24"
/>
-
<p
class="gl-mb-0"
data-testid="upload-text"
@@ -28,50 +27,37 @@ exports[`Upload dropzone component correctly overrides description and drop mess
</p>
</div>
</button>
-
<input
accept="image/jpg,image/jpeg"
class="hide"
- multiple="multiple"
+ multiple=""
name="upload_file"
type="file"
/>
-
<transition-stub
name="upload-dropzone-fade"
>
<div
- class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card gl-absolute gl-align-items-center gl-display-flex gl-h-full gl-justify-content-center gl-p-4 gl-w-full upload-dropzone-border upload-dropzone-overlay"
style="display: none;"
>
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style="display: none;"
>
- <h3
- class=""
- >
-
- Oh no!
-
+ <h3>
+ Oh no!
</h3>
-
<span>
You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
</span>
</div>
-
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
>
- <h3
- class=""
- >
-
- Incoming!
-
+ <h3>
+ Incoming!
</h3>
-
<span>
Test drop-to-start message.
</span>
@@ -83,14 +69,14 @@ exports[`Upload dropzone component correctly overrides description and drop mess
exports[`Upload dropzone component when dragging renders correct template when drag event contains files 1`] = `
<div
- class="gl-w-full gl-relative"
+ class="gl-relative gl-w-full"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-px-5 gl-py-4 gl-mb-0"
+ class="card gl-align-items-center gl-h-full gl-justify-content-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
type="button"
>
<div
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
+ class="gl-align-items-center gl-display-flex gl-flex-direction-column gl-justify-content-center gl-text-center"
data-testid="dropzone-area"
>
<gl-icon-stub
@@ -98,65 +84,49 @@ exports[`Upload dropzone component when dragging renders correct template when d
name="upload"
size="24"
/>
-
<p
class="gl-mb-0"
data-testid="upload-text"
>
- Drop or
+ Drop or
<gl-link-stub>
-
- upload
-
+ upload
</gl-link-stub>
- files to attach
+ files to attach
</p>
</div>
</button>
-
<input
accept="image/*"
class="hide"
- multiple="multiple"
+ multiple=""
name="upload_file"
type="file"
/>
-
<transition-stub
name="upload-dropzone-fade"
>
<div
- class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card gl-absolute gl-align-items-center gl-display-flex gl-h-full gl-justify-content-center gl-p-4 gl-w-full upload-dropzone-border upload-dropzone-overlay"
style=""
>
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style="display: none;"
>
- <h3
- class=""
- >
-
- Oh no!
-
+ <h3>
+ Oh no!
</h3>
-
<span>
You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
</span>
</div>
-
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
>
- <h3
- class=""
- >
-
- Incoming!
-
+ <h3>
+ Incoming!
</h3>
-
<span>
Drop your files to start your upload.
</span>
@@ -168,14 +138,14 @@ exports[`Upload dropzone component when dragging renders correct template when d
exports[`Upload dropzone component when dragging renders correct template when drag event contains files and text 1`] = `
<div
- class="gl-w-full gl-relative"
+ class="gl-relative gl-w-full"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-px-5 gl-py-4 gl-mb-0"
+ class="card gl-align-items-center gl-h-full gl-justify-content-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
type="button"
>
<div
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
+ class="gl-align-items-center gl-display-flex gl-flex-direction-column gl-justify-content-center gl-text-center"
data-testid="dropzone-area"
>
<gl-icon-stub
@@ -183,65 +153,49 @@ exports[`Upload dropzone component when dragging renders correct template when d
name="upload"
size="24"
/>
-
<p
class="gl-mb-0"
data-testid="upload-text"
>
- Drop or
+ Drop or
<gl-link-stub>
-
- upload
-
+ upload
</gl-link-stub>
- files to attach
+ files to attach
</p>
</div>
</button>
-
<input
accept="image/*"
class="hide"
- multiple="multiple"
+ multiple=""
name="upload_file"
type="file"
/>
-
<transition-stub
name="upload-dropzone-fade"
>
<div
- class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card gl-absolute gl-align-items-center gl-display-flex gl-h-full gl-justify-content-center gl-p-4 gl-w-full upload-dropzone-border upload-dropzone-overlay"
style=""
>
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style="display: none;"
>
- <h3
- class=""
- >
-
- Oh no!
-
+ <h3>
+ Oh no!
</h3>
-
<span>
You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
</span>
</div>
-
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
>
- <h3
- class=""
- >
-
- Incoming!
-
+ <h3>
+ Incoming!
</h3>
-
<span>
Drop your files to start your upload.
</span>
@@ -253,14 +207,14 @@ exports[`Upload dropzone component when dragging renders correct template when d
exports[`Upload dropzone component when dragging renders correct template when drag event contains text 1`] = `
<div
- class="gl-w-full gl-relative"
+ class="gl-relative gl-w-full"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-px-5 gl-py-4 gl-mb-0"
+ class="card gl-align-items-center gl-h-full gl-justify-content-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
type="button"
>
<div
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
+ class="gl-align-items-center gl-display-flex gl-flex-direction-column gl-justify-content-center gl-text-center"
data-testid="dropzone-area"
>
<gl-icon-stub
@@ -268,66 +222,50 @@ exports[`Upload dropzone component when dragging renders correct template when d
name="upload"
size="24"
/>
-
<p
class="gl-mb-0"
data-testid="upload-text"
>
- Drop or
+ Drop or
<gl-link-stub>
-
- upload
-
+ upload
</gl-link-stub>
- files to attach
+ files to attach
</p>
</div>
</button>
-
<input
accept="image/*"
class="hide"
- multiple="multiple"
+ multiple=""
name="upload_file"
type="file"
/>
-
<transition-stub
name="upload-dropzone-fade"
>
<div
- class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card gl-absolute gl-align-items-center gl-display-flex gl-h-full gl-justify-content-center gl-p-4 gl-w-full upload-dropzone-border upload-dropzone-overlay"
style=""
>
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style=""
>
- <h3
- class=""
- >
-
- Oh no!
-
+ <h3>
+ Oh no!
</h3>
-
<span>
You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
</span>
</div>
-
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style="display: none;"
>
- <h3
- class=""
- >
-
- Incoming!
-
+ <h3>
+ Incoming!
</h3>
-
<span>
Drop your files to start your upload.
</span>
@@ -339,14 +277,14 @@ exports[`Upload dropzone component when dragging renders correct template when d
exports[`Upload dropzone component when dragging renders correct template when drag event is empty 1`] = `
<div
- class="gl-w-full gl-relative"
+ class="gl-relative gl-w-full"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-px-5 gl-py-4 gl-mb-0"
+ class="card gl-align-items-center gl-h-full gl-justify-content-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
type="button"
>
<div
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
+ class="gl-align-items-center gl-display-flex gl-flex-direction-column gl-justify-content-center gl-text-center"
data-testid="dropzone-area"
>
<gl-icon-stub
@@ -354,66 +292,50 @@ exports[`Upload dropzone component when dragging renders correct template when d
name="upload"
size="24"
/>
-
<p
class="gl-mb-0"
data-testid="upload-text"
>
- Drop or
+ Drop or
<gl-link-stub>
-
- upload
-
+ upload
</gl-link-stub>
- files to attach
+ files to attach
</p>
</div>
</button>
-
<input
accept="image/*"
class="hide"
- multiple="multiple"
+ multiple=""
name="upload_file"
type="file"
/>
-
<transition-stub
name="upload-dropzone-fade"
>
<div
- class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card gl-absolute gl-align-items-center gl-display-flex gl-h-full gl-justify-content-center gl-p-4 gl-w-full upload-dropzone-border upload-dropzone-overlay"
style=""
>
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style=""
>
- <h3
- class=""
- >
-
- Oh no!
-
+ <h3>
+ Oh no!
</h3>
-
<span>
You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
</span>
</div>
-
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style="display: none;"
>
- <h3
- class=""
- >
-
- Incoming!
-
+ <h3>
+ Incoming!
</h3>
-
<span>
Drop your files to start your upload.
</span>
@@ -425,14 +347,14 @@ exports[`Upload dropzone component when dragging renders correct template when d
exports[`Upload dropzone component when dragging renders correct template when dragging stops 1`] = `
<div
- class="gl-w-full gl-relative"
+ class="gl-relative gl-w-full"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-px-5 gl-py-4 gl-mb-0"
+ class="card gl-align-items-center gl-h-full gl-justify-content-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
type="button"
>
<div
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
+ class="gl-align-items-center gl-display-flex gl-flex-direction-column gl-justify-content-center gl-text-center"
data-testid="dropzone-area"
>
<gl-icon-stub
@@ -440,66 +362,50 @@ exports[`Upload dropzone component when dragging renders correct template when d
name="upload"
size="24"
/>
-
<p
class="gl-mb-0"
data-testid="upload-text"
>
- Drop or
+ Drop or
<gl-link-stub>
-
- upload
-
+ upload
</gl-link-stub>
- files to attach
+ files to attach
</p>
</div>
</button>
-
<input
accept="image/*"
class="hide"
- multiple="multiple"
+ multiple=""
name="upload_file"
type="file"
/>
-
<transition-stub
name="upload-dropzone-fade"
>
<div
- class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card gl-absolute gl-align-items-center gl-display-flex gl-h-full gl-justify-content-center gl-p-4 gl-w-full upload-dropzone-border upload-dropzone-overlay"
style="display: none;"
>
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style=""
>
- <h3
- class=""
- >
-
- Oh no!
-
+ <h3>
+ Oh no!
</h3>
-
<span>
You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
</span>
</div>
-
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style="display: none;"
>
- <h3
- class=""
- >
-
- Incoming!
-
+ <h3>
+ Incoming!
</h3>
-
<span>
Drop your files to start your upload.
</span>
@@ -511,14 +417,14 @@ exports[`Upload dropzone component when dragging renders correct template when d
exports[`Upload dropzone component when no slot provided renders default dropzone card 1`] = `
<div
- class="gl-w-full gl-relative"
+ class="gl-relative gl-w-full"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-px-5 gl-py-4 gl-mb-0"
+ class="card gl-align-items-center gl-h-full gl-justify-content-center gl-mb-0 gl-px-5 gl-py-4 gl-w-full upload-dropzone-border upload-dropzone-card"
type="button"
>
<div
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
+ class="gl-align-items-center gl-display-flex gl-flex-direction-column gl-justify-content-center gl-text-center"
data-testid="dropzone-area"
>
<gl-icon-stub
@@ -526,65 +432,49 @@ exports[`Upload dropzone component when no slot provided renders default dropzon
name="upload"
size="24"
/>
-
<p
class="gl-mb-0"
data-testid="upload-text"
>
- Drop or
+ Drop or
<gl-link-stub>
-
- upload
-
+ upload
</gl-link-stub>
- files to attach
+ files to attach
</p>
</div>
</button>
-
<input
accept="image/*"
class="hide"
- multiple="multiple"
+ multiple=""
name="upload_file"
type="file"
/>
-
<transition-stub
name="upload-dropzone-fade"
>
<div
- class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card gl-absolute gl-align-items-center gl-display-flex gl-h-full gl-justify-content-center gl-p-4 gl-w-full upload-dropzone-border upload-dropzone-overlay"
style="display: none;"
>
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style="display: none;"
>
- <h3
- class=""
- >
-
- Oh no!
-
+ <h3>
+ Oh no!
</h3>
-
<span>
You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
</span>
</div>
-
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
>
- <h3
- class=""
- >
-
- Incoming!
-
+ <h3>
+ Incoming!
</h3>
-
<span>
Drop your files to start your upload.
</span>
@@ -596,47 +486,35 @@ exports[`Upload dropzone component when no slot provided renders default dropzon
exports[`Upload dropzone component when slot provided renders dropzone with slot content 1`] = `
<div
- class="gl-w-full gl-relative"
+ class="gl-relative gl-w-full"
>
<div>
dropzone slot
</div>
-
<transition-stub
name="upload-dropzone-fade"
>
<div
- class="card upload-dropzone-border upload-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card gl-absolute gl-align-items-center gl-display-flex gl-h-full gl-justify-content-center gl-p-4 gl-w-full upload-dropzone-border upload-dropzone-overlay"
style="display: none;"
>
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
style="display: none;"
>
- <h3
- class=""
- >
-
- Oh no!
-
+ <h3>
+ Oh no!
</h3>
-
<span>
You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.
</span>
</div>
-
<div
- class="mw-50 gl-text-center"
+ class="gl-text-center mw-50"
>
- <h3
- class=""
- >
-
- Incoming!
-
+ <h3>
+ Incoming!
</h3>
-
<span>
Drop your files to start your upload.
</span>
diff --git a/spec/frontend/vue_shared/components/user_select_spec.js b/spec/frontend/vue_shared/components/user_select_spec.js
index 8c7657da8bc..119b892392f 100644
--- a/spec/frontend/vue_shared/components/user_select_spec.js
+++ b/spec/frontend/vue_shared/components/user_select_spec.js
@@ -5,17 +5,17 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import searchUsersQuery from '~/graphql_shared/queries/users_search.query.graphql';
-import searchUsersQueryOnMR from '~/graphql_shared/queries/users_search_with_mr_permissions.graphql';
+import searchUsersQuery from '~/graphql_shared/queries/project_autocomplete_users.query.graphql';
+import searchUsersQueryOnMR from '~/graphql_shared/queries/project_autocomplete_users_with_mr_permissions.query.graphql';
import { TYPE_MERGE_REQUEST } from '~/issues/constants';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import SidebarParticipant from '~/sidebar/components/assignees/sidebar_participant.vue';
import getIssueParticipantsQuery from '~/sidebar/queries/get_issue_participants.query.graphql';
import UserSelect from '~/vue_shared/components/user_select/user_select.vue';
import {
- searchResponse,
- searchResponseOnMR,
- projectMembersResponse,
+ projectAutocompleteMembersResponse,
+ searchAutocompleteQueryResponse,
+ searchAutocompleteResponseOnMR,
participantsQueryResponse,
mockUser1,
mockUser2,
@@ -59,7 +59,7 @@ describe('User select dropdown', () => {
const findUnassignLink = () => wrapper.findByTestId('unassign');
const findEmptySearchResults = () => wrapper.findAllByTestId('empty-results');
- const searchQueryHandlerSuccess = jest.fn().mockResolvedValue(projectMembersResponse);
+ const searchQueryHandlerSuccess = jest.fn().mockResolvedValue(projectAutocompleteMembersResponse);
const participantsQueryHandlerSuccess = jest.fn().mockResolvedValue(participantsQueryResponse);
const createComponent = ({
@@ -69,7 +69,7 @@ describe('User select dropdown', () => {
} = {}) => {
fakeApollo = createMockApollo([
[searchUsersQuery, searchQueryHandler],
- [searchUsersQueryOnMR, jest.fn().mockResolvedValue(searchResponseOnMR)],
+ [searchUsersQueryOnMR, jest.fn().mockResolvedValue(searchAutocompleteResponseOnMR)],
[getIssueParticipantsQuery, participantsQueryHandler],
]);
wrapper = shallowMountExtended(UserSelect, {
@@ -200,7 +200,7 @@ describe('User select dropdown', () => {
});
await waitForPromises();
- expect(findUnselectedParticipantByIndex(0).props('user')).toEqual(mockUser2);
+ expect(findUnselectedParticipantByIndex(0).props('user')).toMatchObject(mockUser2);
});
it('moves issuable author on top of unassigned list after current user, if author and current user are unassigned project members', async () => {
@@ -372,7 +372,9 @@ describe('User select dropdown', () => {
});
it('renders a list of found users and external participants matching search term', async () => {
- createComponent({ searchQueryHandler: jest.fn().mockResolvedValue(searchResponse) });
+ createComponent({
+ searchQueryHandler: jest.fn().mockResolvedValue(searchAutocompleteQueryResponse),
+ });
await waitForPromises();
findSearchField().vm.$emit('input', 'ro');
@@ -382,7 +384,9 @@ describe('User select dropdown', () => {
});
it('renders a list of found users only if no external participants match search term', async () => {
- createComponent({ searchQueryHandler: jest.fn().mockResolvedValue(searchResponse) });
+ createComponent({
+ searchQueryHandler: jest.fn().mockResolvedValue(searchAutocompleteQueryResponse),
+ });
await waitForPromises();
findSearchField().vm.$emit('input', 'roo');
@@ -392,8 +396,8 @@ describe('User select dropdown', () => {
});
it('shows a message about no matches if search returned an empty list', async () => {
- const responseCopy = cloneDeep(searchResponse);
- responseCopy.data.workspace.users.nodes = [];
+ const responseCopy = cloneDeep(searchAutocompleteQueryResponse);
+ responseCopy.data.workspace.users = [];
createComponent({
searchQueryHandler: jest.fn().mockResolvedValue(responseCopy),
diff --git a/spec/frontend/vue_shared/issuable/__snapshots__/issuable_blocked_icon_spec.js.snap b/spec/frontend/vue_shared/issuable/__snapshots__/issuable_blocked_icon_spec.js.snap
deleted file mode 100644
index 1d4aa1afeaf..00000000000
--- a/spec/frontend/vue_shared/issuable/__snapshots__/issuable_blocked_icon_spec.js.snap
+++ /dev/null
@@ -1,30 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`IssuableBlockedIcon on mouseenter on blocked icon with more than three blocking issues matches the snapshot 1`] = `
-"<div class=\\"gl-display-inline\\"><svg data-testid=\\"issuable-blocked-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"issuable-blocked-icon gl-mr-2 gl-cursor-pointer gl-text-red-500 gl-icon s16\\" id=\\"blocked-icon-uniqueId\\">
- <use href=\\"file-mock#issue-block\\"></use>
- </svg>
- <div class=\\"gl-popover\\">
- <ul class=\\"gl-list-style-none gl-p-0 gl-mb-0\\">
- <li><a href=\\"http://gdk.test:3000/gitlab-org/my-project-1/-/issues/6\\" class=\\"gl-link gl-text-blue-500! gl-font-sm\\">my-project-1#6</a>
- <p data-testid=\\"issuable-title\\" class=\\"gl-display-block! gl-mb-3\\">
- blocking issue title 1
- </p>
- </li>
- <li><a href=\\"http://gdk.test:3000/gitlab-org/my-project-1/-/issues/5\\" class=\\"gl-link gl-text-blue-500! gl-font-sm\\">my-project-1#5</a>
- <p data-testid=\\"issuable-title\\" class=\\"gl-display-block! gl-mb-3\\">
- blocking issue title 2 + blocking issue title 2 + blocking issue title 2 + bloc…
- </p>
- </li>
- <li><a href=\\"http://gdk.test:3000/gitlab-org/my-project-1/-/issues/4\\" class=\\"gl-link gl-text-blue-500! gl-font-sm\\">my-project-1#4</a>
- <p data-testid=\\"issuable-title\\" class=\\"gl-display-block! gl-mb-0\\">
- blocking issue title 3
- </p>
- </li>
- </ul>
- <div class=\\"gl-mt-4\\">
- <p data-testid=\\"hidden-blocking-count\\" class=\\"gl-mb-3\\">+ 1 more issue</p> <a data-testid=\\"view-all-issues\\" href=\\"http://gdk.test:3000/gitlab-org/my-project-1/-/issues/0#related-issues\\" class=\\"gl-link gl-text-blue-500! gl-font-sm\\">View all blocking issues</a>
- </div><span data-testid=\\"popover-title\\">Blocked by 4 issues</span>
- </div>
-</div>"
-`;
diff --git a/spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js b/spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js
index 338dc80b43e..62361705843 100644
--- a/spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js
+++ b/spec/frontend/vue_shared/issuable/create/components/issuable_form_spec.js
@@ -81,7 +81,7 @@ describe('IssuableForm', () => {
ariaLabel: __('Description'),
class: 'rspec-issuable-form-description',
placeholder: __('Write a comment or drag your files here…'),
- dataQaSelector: 'issuable_form_description_field',
+ dataTestid: 'issuable-form-description-field',
id: 'issuable-description',
name: 'issuable-description',
},
diff --git a/spec/frontend/vue_shared/issuable/issuable_blocked_icon_spec.js b/spec/frontend/vue_shared/issuable/issuable_blocked_icon_spec.js
index d5603d4ba4b..6512da07125 100644
--- a/spec/frontend/vue_shared/issuable/issuable_blocked_icon_spec.js
+++ b/spec/frontend/vue_shared/issuable/issuable_blocked_icon_spec.js
@@ -237,10 +237,6 @@ describe('IssuableBlockedIcon', () => {
await mouseenter();
});
- it('matches the snapshot', () => {
- expect(wrapper.html()).toMatchSnapshot();
- });
-
it('should render popover title with correct blocking issuable count', () => {
expect(findPopoverTitle().text()).toBe('Blocked by 4 issues');
});
diff --git a/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js b/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js
index 77333a878d1..9f7254ba0e6 100644
--- a/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js
+++ b/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js
@@ -1,5 +1,6 @@
import { GlLink, GlLabel, GlIcon, GlFormCheckbox, GlSprintf } from '@gitlab/ui';
import { nextTick } from 'vue';
+import { escape } from 'lodash';
import { useFakeDate } from 'helpers/fake_date';
import { shallowMountExtended as shallowMount } from 'helpers/vue_test_utils_helper';
import IssuableItem from '~/vue_shared/issuable/list/components/issuable_item.vue';
@@ -63,6 +64,14 @@ describe('IssuableItem', () => {
});
});
+ describe('externalAuthor', () => {
+ it('returns `externalAuthor` reference', () => {
+ wrapper = createComponent();
+
+ expect(wrapper.vm.externalAuthor).toEqual(mockIssuable.externalAuthor);
+ });
+ });
+
describe('authorId', () => {
it.each`
authorId | returnValue
@@ -279,10 +288,23 @@ describe('IssuableItem', () => {
expect(titleEl.exists()).toBe(true);
expect(titleEl.findComponent(GlLink).attributes('href')).toBe(expectedHref);
expect(titleEl.findComponent(GlLink).attributes('target')).toBe(expectedTarget);
- expect(titleEl.findComponent(GlLink).text()).toBe(mockIssuable.title);
+ expect(titleEl.findComponent(GlLink).html()).toContain(mockIssuable.titleHtml);
},
);
+ it('renders issuable title with escaped markup when issue tracker is external', () => {
+ const mockTitle = '<script>foobar</script>';
+ wrapper = createComponent({
+ issuable: {
+ ...mockIssuable,
+ title: mockTitle,
+ externalTracker: 'jira',
+ },
+ });
+
+ expect(wrapper.findByTestId('issuable-title').html()).toContain(escape(mockTitle));
+ });
+
it('renders checkbox when `showCheckbox` prop is true', async () => {
wrapper = createComponent({
showCheckbox: true,
@@ -437,6 +459,15 @@ describe('IssuableItem', () => {
expect(authorEl.text()).toBe(mockAuthor.name);
});
+ it('renders issuable external author info via author slot', () => {
+ wrapper = createComponent({
+ issuableSymbol: '#',
+ issuable: { ...mockIssuable, externalAuthor: 'client@example.com' },
+ });
+
+ expect(wrapper.findByTestId('external-author').text()).toBe('client@example.com via');
+ });
+
it('renders timeframe via slot', () => {
wrapper = createComponent({
issuableSymbol: '#',
diff --git a/spec/frontend/vue_shared/issuable/list/mock_data.js b/spec/frontend/vue_shared/issuable/list/mock_data.js
index f8cf3ba5271..b39d177f292 100644
--- a/spec/frontend/vue_shared/issuable/list/mock_data.js
+++ b/spec/frontend/vue_shared/issuable/list/mock_data.js
@@ -42,7 +42,7 @@ export const mockCurrentUserTodo = {
export const mockIssuable = {
iid: '30',
title: 'Dismiss Cipher with no integrity',
- titleHtml: 'Dismiss Cipher with no integrity',
+ titleHtml: '<gl-emoji title="party-parrot"></gl-emoji>Dismiss Cipher with no integrity',
description: 'fortitudinis _fomentis_ dolor mitigari solet.',
descriptionHtml: 'fortitudinis <i>fomentis</i> dolor mitigari solet.',
state: 'opened',
diff --git a/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js b/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
index 4d08ad54e58..3b6f06d835b 100644
--- a/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
+++ b/spec/frontend/vue_shared/issuable/show/components/issuable_header_spec.js
@@ -2,13 +2,7 @@ import { GlBadge, GlButton, GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { resetHTMLFixture, setHTMLFixture } from 'helpers/fixtures';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import {
- STATUS_CLOSED,
- STATUS_OPEN,
- STATUS_REOPENED,
- TYPE_ISSUE,
- WORKSPACE_PROJECT,
-} from '~/issues/constants';
+import { STATUS_CLOSED, STATUS_OPEN, STATUS_REOPENED, TYPE_ISSUE } from '~/issues/constants';
import { __ } from '~/locale';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
@@ -45,7 +39,6 @@ describe('IssuableHeader component', () => {
...mockIssuableShowProps,
issuableState: STATUS_OPEN,
issuableType: TYPE_ISSUE,
- workspaceType: WORKSPACE_PROJECT,
...props,
},
slots: {
@@ -107,6 +100,7 @@ describe('IssuableHeader component', () => {
expect(findConfidentialityBadge().props()).toEqual({
issuableType: 'issue',
workspaceType: 'project',
+ hideTextInSmallScreens: false,
});
});
@@ -169,7 +163,7 @@ describe('IssuableHeader component', () => {
expect(findWorkItemTypeIcon().props()).toMatchObject({
showText: true,
- workItemType: 'ISSUE',
+ workItemType: 'issue',
});
});
diff --git a/spec/frontend/vue_shared/issuable/show/components/issuable_title_spec.js b/spec/frontend/vue_shared/issuable/show/components/issuable_title_spec.js
index 39316dfa249..eefc9142064 100644
--- a/spec/frontend/vue_shared/issuable/show/components/issuable_title_spec.js
+++ b/spec/frontend/vue_shared/issuable/show/components/issuable_title_spec.js
@@ -66,11 +66,11 @@ describe('IssuableTitle', () => {
});
await nextTick();
- const titleEl = wrapperWithTitle.find('[data-testid="title"]');
+ const titleEl = wrapperWithTitle.find('[data-testid="issuable-title"]');
expect(titleEl.exists()).toBe(true);
expect(titleEl.html()).toBe(
- '<h1 dir="auto" data-qa-selector="title_content" data-testid="title" class="title gl-font-size-h-display"><b>Sample</b> title</h1>',
+ '<h1 dir="auto" data-testid="issuable-title" class="title gl-font-size-h-display"><b>Sample</b> title</h1>',
);
wrapperWithTitle.destroy();
diff --git a/spec/frontend/vue_shared/issuable/show/mock_data.js b/spec/frontend/vue_shared/issuable/show/mock_data.js
index 5ec205a2d5c..946ad33555d 100644
--- a/spec/frontend/vue_shared/issuable/show/mock_data.js
+++ b/spec/frontend/vue_shared/issuable/show/mock_data.js
@@ -38,6 +38,7 @@ export const mockIssuableShowProps = {
showFieldTitle: false,
statusIcon: 'issues',
statusIconClass: 'gl-sm-display-none',
+ workspaceType: 'project',
taskCompletionStatus: {
completedCount: 0,
count: 5,
diff --git a/spec/frontend/vue_shared/new_namespace/new_namespace_page_spec.js b/spec/frontend/vue_shared/new_namespace/new_namespace_page_spec.js
index a7ddcbdd8bc..109b7732539 100644
--- a/spec/frontend/vue_shared/new_namespace/new_namespace_page_spec.js
+++ b/spec/frontend/vue_shared/new_namespace/new_namespace_page_spec.js
@@ -1,6 +1,6 @@
import { GlBreadcrumb } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import LegacyContainer from '~/vue_shared/new_namespace/components/legacy_container.vue';
import WelcomePage from '~/vue_shared/new_namespace/components/welcome.vue';
import NewNamespacePage from '~/vue_shared/new_namespace/new_namespace_page.vue';
@@ -14,6 +14,7 @@ describe('Experimental new namespace creation app', () => {
const findWelcomePage = () => wrapper.findComponent(WelcomePage);
const findLegacyContainer = () => wrapper.findComponent(LegacyContainer);
+ const findTopBar = () => wrapper.findByTestId('top-bar');
const findBreadcrumb = () => wrapper.findComponent(GlBreadcrumb);
const findImage = () => wrapper.find('img');
const findNewTopLevelGroupAlert = () => wrapper.findComponent(NewTopLevelGroupAlert);
@@ -30,7 +31,7 @@ describe('Experimental new namespace creation app', () => {
};
const createComponent = ({ slots, propsData } = {}) => {
- wrapper = shallowMount(NewNamespacePage, {
+ wrapper = shallowMountExtended(NewNamespacePage, {
slots,
propsData: {
...DEFAULT_PROPS,
@@ -167,4 +168,19 @@ describe('Experimental new namespace creation app', () => {
});
});
});
+
+ describe('top bar', () => {
+ it('adds "top-bar-fixed" and "container-fluid" classes when new navigation enabled', () => {
+ gon.use_new_navigation = true;
+ createComponent();
+
+ expect(findTopBar().classes()).toEqual(['top-bar-fixed', 'container-fluid']);
+ });
+
+ it('does not add classes when new navigation is not enabled', () => {
+ createComponent();
+
+ expect(findTopBar().classes()).toEqual([]);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js b/spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js
index 299a3d62421..f5bc23a91fd 100644
--- a/spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js
+++ b/spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdown } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import SecurityReportDownloadDropdown from '~/vue_shared/security_reports/components/security_report_download_dropdown.vue';
@@ -12,8 +12,7 @@ describe('SecurityReportDownloadDropdown component', () => {
});
};
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
describe('given report artifacts', () => {
beforeEach(() => {
@@ -28,21 +27,36 @@ describe('SecurityReportDownloadDropdown component', () => {
},
];
- createComponent({ artifacts });
+ createComponent({ artifacts, text: 'test' });
});
it('renders a dropdown', () => {
expect(findDropdown().props('loading')).toBe(false);
+ expect(findDropdown().props('toggleText')).toBe('test');
+ expect(findDropdown().attributes()).toMatchObject({
+ placement: 'right',
+ size: 'small',
+ icon: 'download',
+ });
});
- it('renders a dropdown item for each artifact', () => {
- artifacts.forEach((artifact, i) => {
- const item = findDropdownItems().at(i);
- expect(item.text()).toContain(artifact.name);
-
- expect(item.element.getAttribute('href')).toBe(artifact.path);
- expect(item.element.getAttribute('download')).toBeDefined();
- });
+ it('passes artifacts as items', () => {
+ expect(findDropdown().props('items')).toMatchObject([
+ {
+ text: 'Download foo',
+ href: '/foo.json',
+ extraAttrs: {
+ download: '',
+ },
+ },
+ {
+ text: 'Download bar',
+ href: '/bar.json',
+ extraAttrs: {
+ download: '',
+ },
+ },
+ ]);
});
});
@@ -56,31 +70,13 @@ describe('SecurityReportDownloadDropdown component', () => {
});
});
- describe('given title props', () => {
+ describe('given it is not loading and no artifacts', () => {
beforeEach(() => {
- createComponent({ artifacts: [], loading: true, title: 'test title' });
- });
-
- it('should render title', () => {
- expect(findDropdown().attributes('title')).toBe('test title');
- });
-
- it('should not render text', () => {
- expect(findDropdown().text().trim()).toBe('');
- });
- });
-
- describe('given text props', () => {
- beforeEach(() => {
- createComponent({ artifacts: [], loading: true, text: 'test text' });
- });
-
- it('should not render title', () => {
- expect(findDropdown().props().title).not.toBeDefined();
+ createComponent({ artifacts: [], loading: false });
});
- it('should render text', () => {
- expect(findDropdown().props().text).toContain('test text');
+ it('does not render dropdown', () => {
+ expect(findDropdown().exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap b/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap
index aec0f84cb82..4150bd75c16 100644
--- a/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap
+++ b/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap
@@ -11,7 +11,7 @@ exports[`Webhook push events form editor component Different push events rules w
valuefield="value"
>
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_all_branches"
value="all_branches"
>
@@ -21,50 +21,34 @@ exports[`Webhook push events form editor component Different push events rules w
All branches
</div>
</gl-form-radio-stub>
-
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_wildcard"
value="wildcard"
>
<div
data-qa-selector="strategy_radio_wildcard"
>
-
- Wildcard pattern
-
+ Wildcard pattern
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
- >
- <!---->
- </div>
-
- <!---->
-
+ />
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_regex"
value="regex"
>
<div
data-qa-selector="strategy_radio_regex"
>
-
- Regular expression
-
+ Regular expression
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
- >
- <!---->
- </div>
-
- <!---->
+ />
</gl-form-radio-group-stub>
`;
@@ -79,7 +63,7 @@ exports[`Webhook push events form editor component Different push events rules w
valuefield="value"
>
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_all_branches"
value="all_branches"
>
@@ -89,43 +73,31 @@ exports[`Webhook push events form editor component Different push events rules w
All branches
</div>
</gl-form-radio-stub>
-
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_wildcard"
value="wildcard"
>
<div
data-qa-selector="strategy_radio_wildcard"
>
-
- Wildcard pattern
-
+ Wildcard pattern
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
- >
- <!---->
- </div>
-
- <!---->
-
+ />
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_regex"
value="regex"
>
<div
data-qa-selector="strategy_radio_regex"
>
-
- Regular expression
-
+ Regular expression
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
>
@@ -136,9 +108,8 @@ exports[`Webhook push events form editor component Different push events rules w
value="foo"
/>
</div>
-
<p
- class="form-text text-muted custom-control"
+ class="custom-control form-text text-muted"
>
<gl-sprintf-stub
message="Regular expressions such as %{REGEX_CODE} are supported."
@@ -158,7 +129,7 @@ exports[`Webhook push events form editor component Different push events rules w
valuefield="value"
>
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_all_branches"
value="all_branches"
>
@@ -168,21 +139,17 @@ exports[`Webhook push events form editor component Different push events rules w
All branches
</div>
</gl-form-radio-stub>
-
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_wildcard"
value="wildcard"
>
<div
data-qa-selector="strategy_radio_wildcard"
>
-
- Wildcard pattern
-
+ Wildcard pattern
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
>
@@ -193,36 +160,27 @@ exports[`Webhook push events form editor component Different push events rules w
value="foo"
/>
</div>
-
<p
- class="form-text text-muted custom-control"
+ class="custom-control form-text text-muted"
>
<gl-sprintf-stub
message="Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
/>
</p>
-
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_regex"
value="regex"
>
<div
data-qa-selector="strategy_radio_regex"
>
-
- Regular expression
-
+ Regular expression
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
- >
- <!---->
- </div>
-
- <!---->
+ />
</gl-form-radio-group-stub>
`;
@@ -237,7 +195,7 @@ exports[`Webhook push events form editor component Different push events rules w
valuefield="value"
>
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_all_branches"
value="all_branches"
>
@@ -247,50 +205,34 @@ exports[`Webhook push events form editor component Different push events rules w
All branches
</div>
</gl-form-radio-stub>
-
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_wildcard"
value="wildcard"
>
<div
data-qa-selector="strategy_radio_wildcard"
>
-
- Wildcard pattern
-
+ Wildcard pattern
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
- >
- <!---->
- </div>
-
- <!---->
-
+ />
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_regex"
value="regex"
>
<div
data-qa-selector="strategy_radio_regex"
>
-
- Regular expression
-
+ Regular expression
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
- >
- <!---->
- </div>
-
- <!---->
+ />
</gl-form-radio-group-stub>
`;
@@ -305,7 +247,7 @@ exports[`Webhook push events form editor component Different push events rules w
valuefield="value"
>
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_all_branches"
value="all_branches"
>
@@ -315,43 +257,31 @@ exports[`Webhook push events form editor component Different push events rules w
All branches
</div>
</gl-form-radio-stub>
-
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_wildcard"
value="wildcard"
>
<div
data-qa-selector="strategy_radio_wildcard"
>
-
- Wildcard pattern
-
+ Wildcard pattern
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
- >
- <!---->
- </div>
-
- <!---->
-
+ />
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_regex"
value="regex"
>
<div
data-qa-selector="strategy_radio_regex"
>
-
- Regular expression
-
+ Regular expression
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
>
@@ -362,9 +292,8 @@ exports[`Webhook push events form editor component Different push events rules w
value=""
/>
</div>
-
<p
- class="form-text text-muted custom-control"
+ class="custom-control form-text text-muted"
>
<gl-sprintf-stub
message="Regular expressions such as %{REGEX_CODE} are supported."
@@ -384,7 +313,7 @@ exports[`Webhook push events form editor component Different push events rules w
valuefield="value"
>
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_all_branches"
value="all_branches"
>
@@ -394,21 +323,17 @@ exports[`Webhook push events form editor component Different push events rules w
All branches
</div>
</gl-form-radio-stub>
-
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_wildcard"
value="wildcard"
>
<div
data-qa-selector="strategy_radio_wildcard"
>
-
- Wildcard pattern
-
+ Wildcard pattern
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
>
@@ -419,35 +344,26 @@ exports[`Webhook push events form editor component Different push events rules w
value=""
/>
</div>
-
<p
- class="form-text text-muted custom-control"
+ class="custom-control form-text text-muted"
>
<gl-sprintf-stub
message="Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
/>
</p>
-
<gl-form-radio-stub
- class="gl-mt-2 branch-filter-strategy-radio"
+ class="branch-filter-strategy-radio gl-mt-2"
data-testid="rule_regex"
value="regex"
>
<div
data-qa-selector="strategy_radio_regex"
>
-
- Regular expression
-
+ Regular expression
</div>
</gl-form-radio-stub>
-
<div
class="gl-ml-6"
- >
- <!---->
- </div>
-
- <!---->
+ />
</gl-form-radio-group-stub>
`;
diff --git a/spec/frontend/work_items/components/notes/__snapshots__/work_item_note_body_spec.js.snap b/spec/frontend/work_items/components/notes/__snapshots__/work_item_note_body_spec.js.snap
index 52838dcd0bc..841b8b57f88 100644
--- a/spec/frontend/work_items/components/notes/__snapshots__/work_item_note_body_spec.js.snap
+++ b/spec/frontend/work_items/components/notes/__snapshots__/work_item_note_body_spec.js.snap
@@ -1,9 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Work Item Note Body should have the wrapper to show the note body 1`] = `
-"<div data-testid=\\"work-item-note-body\\" class=\\"note-text md\\">
- <p dir=\\"auto\\" data-sourcepos=\\"1:1-1:76\\">
- <gl-emoji data-unicode-version=\\"6.0\\" data-name=\\"wave\\" title=\\"waving hand sign\\">👋</gl-emoji> Hi <a title=\\"Sherie Nitzsche\\" class=\\"gfm gfm-project_member js-user-link\\" data-placement=\\"top\\" data-container=\\"body\\" data-user=\\"3\\" data-reference-type=\\"user\\" href=\\"/fredda.brekke\\">@fredda.brekke</a> How are you ? what do you think about this ? <gl-emoji data-unicode-version=\\"6.0\\" data-name=\\"pray\\" title=\\"person with folded hands\\">ðŸ™</gl-emoji>
+<div
+ class="md note-text"
+ data-testid="work-item-note-body"
+>
+ <p
+ data-sourcepos="1:1-1:76"
+ dir="auto"
+ >
+ <gl-emoji
+ data-name="wave"
+ data-unicode-version="6.0"
+ title="waving hand sign"
+ >
+ 👋
+ </gl-emoji>
+ Hi
+ <a
+ class="gfm gfm-project_member js-user-link"
+ data-container="body"
+ data-placement="top"
+ data-reference-type="user"
+ data-user="3"
+ href="/fredda.brekke"
+ title="Sherie Nitzsche"
+ >
+ @fredda.brekke
+ </a>
+ How are you ? what do you think about this ?
+ <gl-emoji
+ data-name="pray"
+ data-unicode-version="6.0"
+ title="person with folded hands"
+ >
+ ðŸ™
+ </gl-emoji>
</p>
-</div>"
+</div>
`;
diff --git a/spec/frontend/work_items/components/notes/__snapshots__/work_item_note_replying_spec.js.snap b/spec/frontend/work_items/components/notes/__snapshots__/work_item_note_replying_spec.js.snap
index 30577dc60cf..af930f56509 100644
--- a/spec/frontend/work_items/components/notes/__snapshots__/work_item_note_replying_spec.js.snap
+++ b/spec/frontend/work_items/components/notes/__snapshots__/work_item_note_replying_spec.js.snap
@@ -1,3 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Work Item Note Replying should have the note body and header 1`] = `"<note-header-stub author=\\"[object Object]\\" actiontext=\\"\\" noteabletype=\\"\\" expanded=\\"true\\" showspinner=\\"true\\" noteurl=\\"\\" emailparticipant=\\"\\"></note-header-stub>"`;
+exports[`Work Item Note Replying should have the note body and header 1`] = `
+<note-header-stub
+ actiontext=""
+ author="[object Object]"
+ emailparticipant=""
+ expanded="true"
+ noteabletype=""
+ noteurl=""
+ showspinner="true"
+/>
+`;
diff --git a/spec/frontend/work_items/components/notes/work_item_activity_sort_filter_spec.js b/spec/frontend/work_items/components/notes/work_item_activity_sort_filter_spec.js
index 5ed9d581446..0d0235f4b20 100644
--- a/spec/frontend/work_items/components/notes/work_item_activity_sort_filter_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_activity_sort_filter_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlCollapsibleListbox } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import WorkItemActivitySortFilter from '~/work_items/components/notes/work_item_activity_sort_filter.vue';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
@@ -19,15 +19,13 @@ describe('Work Item Activity/Discussions Filtering', () => {
let wrapper;
const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findByDataTestId = (dataTestId) => wrapper.findByTestId(dataTestId);
+ const findListbox = () => wrapper.findComponent(GlCollapsibleListbox);
const createComponent = ({
loading = false,
workItemType = 'Task',
sortFilterProp = ASC,
- filterOptions = WORK_ITEM_ACTIVITY_SORT_OPTIONS,
+ items = WORK_ITEM_ACTIVITY_SORT_OPTIONS,
trackingLabel = 'item_track_notes_sorting',
trackingAction = 'work_item_notes_sort_order_changed',
filterEvent = 'changeSort',
@@ -39,7 +37,7 @@ describe('Work Item Activity/Discussions Filtering', () => {
loading,
workItemType,
sortFilterProp,
- filterOptions,
+ items,
trackingLabel,
trackingAction,
filterEvent,
@@ -50,13 +48,13 @@ describe('Work Item Activity/Discussions Filtering', () => {
};
describe.each`
- usedFor | filterOptions | storageKey | filterEvent | newInputOption | trackingLabel | trackingAction | defaultSortFilterProp | sortFilterProp | nonDefaultDataTestId
- ${'Sorting'} | ${WORK_ITEM_ACTIVITY_SORT_OPTIONS} | ${WORK_ITEM_NOTES_SORT_ORDER_KEY} | ${'changeSort'} | ${DESC} | ${'item_track_notes_sorting'} | ${'work_item_notes_sort_order_changed'} | ${ASC} | ${ASC} | ${'newest-first'}
- ${'Filtering'} | ${WORK_ITEM_ACTIVITY_FILTER_OPTIONS} | ${WORK_ITEM_NOTES_FILTER_KEY} | ${'changeFilter'} | ${WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS} | ${'item_track_notes_sorting'} | ${'work_item_notes_filter_changed'} | ${WORK_ITEM_NOTES_FILTER_ALL_NOTES} | ${WORK_ITEM_NOTES_FILTER_ALL_NOTES} | ${'comments-activity'}
+ usedFor | items | storageKey | filterEvent | newInputOption | trackingLabel | trackingAction | defaultSortFilterProp | sortFilterProp | nonDefaultValue
+ ${'Sorting'} | ${WORK_ITEM_ACTIVITY_SORT_OPTIONS} | ${WORK_ITEM_NOTES_SORT_ORDER_KEY} | ${'changeSort'} | ${DESC} | ${'item_track_notes_sorting'} | ${'work_item_notes_sort_order_changed'} | ${ASC} | ${ASC} | ${DESC}
+ ${'Filtering'} | ${WORK_ITEM_ACTIVITY_FILTER_OPTIONS} | ${WORK_ITEM_NOTES_FILTER_KEY} | ${'changeFilter'} | ${WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS} | ${'item_track_notes_sorting'} | ${'work_item_notes_filter_changed'} | ${WORK_ITEM_NOTES_FILTER_ALL_NOTES} | ${WORK_ITEM_NOTES_FILTER_ALL_NOTES} | ${WORK_ITEM_NOTES_FILTER_ONLY_COMMENTS}
`(
'When used for $usedFor',
({
- filterOptions,
+ items,
storageKey,
filterEvent,
trackingLabel,
@@ -64,12 +62,12 @@ describe('Work Item Activity/Discussions Filtering', () => {
newInputOption,
defaultSortFilterProp,
sortFilterProp,
- nonDefaultDataTestId,
+ nonDefaultValue,
}) => {
beforeEach(() => {
createComponent({
sortFilterProp,
- filterOptions,
+ items,
trackingLabel,
trackingAction,
filterEvent,
@@ -79,8 +77,7 @@ describe('Work Item Activity/Discussions Filtering', () => {
});
it('has a dropdown with options equal to the length of `filterOptions`', () => {
- expect(findDropdown().exists()).toBe(true);
- expect(findAllDropdownItems()).toHaveLength(filterOptions.length);
+ expect(findListbox().props('items')).toEqual(items);
});
it('has local storage sync with the correct props', () => {
@@ -96,7 +93,7 @@ describe('Work Item Activity/Discussions Filtering', () => {
it('emits tracking event when the a non default dropdown item is clicked', () => {
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- findByDataTestId(nonDefaultDataTestId).vm.$emit('click');
+ findListbox().vm.$emit('select', nonDefaultValue);
expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, trackingAction, {
category: TRACKING_CATEGORY_SHOW,
diff --git a/spec/frontend/work_items/components/notes/work_item_add_note_spec.js b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
index 4b1b7b27ad9..826fc2b2230 100644
--- a/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
@@ -255,6 +255,20 @@ describe('Work item add note', () => {
expect(wrapper.emitted('error')).toEqual([[error]]);
});
+
+ it('sends confidential prop to work item comment form', async () => {
+ await createComponent({ isEditing: true, signedIn: true });
+
+ const {
+ data: {
+ workspace: {
+ workItems: { nodes },
+ },
+ },
+ } = workItemByIidResponseFactory({ canUpdate: true, canCreateNote: true });
+
+ expect(findCommentForm().props('isWorkItemConfidential')).toBe(nodes[0].confidential);
+ });
});
});
diff --git a/spec/frontend/work_items/components/notes/work_item_note_spec.js b/spec/frontend/work_items/components/notes/work_item_note_spec.js
index c5d1decfb42..9049a69656a 100644
--- a/spec/frontend/work_items/components/notes/work_item_note_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_note_spec.js
@@ -388,6 +388,13 @@ describe('Work Item Note', () => {
});
});
+ it('confidential information on note', async () => {
+ createComponent();
+ await findNoteActions().vm.$emit('startEditing');
+ const { confidential } = workItemByIidResponseFactory().data.workspace.workItems.nodes[0];
+ expect(findCommentForm().props('isWorkItemConfidential')).toBe(confidential);
+ });
+
describe('author and user role badges', () => {
describe('author badge props', () => {
it.each`
diff --git a/spec/frontend/work_items/components/shared/work_item_link_child_contents_spec.js b/spec/frontend/work_items/components/shared/work_item_link_child_contents_spec.js
index 9a20e2ec98f..b86f9ff34ae 100644
--- a/spec/frontend/work_items/components/shared/work_item_link_child_contents_spec.js
+++ b/spec/frontend/work_items/components/shared/work_item_link_child_contents_spec.js
@@ -10,7 +10,7 @@ import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip
import WorkItemLinkChildContents from '~/work_items/components/shared/work_item_link_child_contents.vue';
import WorkItemLinksMenu from '~/work_items/components/shared/work_item_links_menu.vue';
-import { TASK_TYPE_NAME, WORK_ITEM_TYPE_VALUE_OBJECTIVE } from '~/work_items/constants';
+import { WORK_ITEM_TYPE_VALUE_OBJECTIVE } from '~/work_items/constants';
import {
workItemTask,
@@ -26,11 +26,9 @@ jest.mock('~/alert');
describe('WorkItemLinkChildContents', () => {
Vue.use(VueApollo);
- const WORK_ITEM_ID = 'gid://gitlab/WorkItem/2';
let wrapper;
const { LABELS } = workItemObjectiveMetadataWidgets;
const mockLabels = LABELS.labels.nodes;
- const mockFullPath = 'gitlab-org/gitlab-test';
const findStatusIconComponent = () =>
wrapper.findByTestId('item-status-icon').findComponent(GlIcon);
@@ -43,19 +41,11 @@ describe('WorkItemLinkChildContents', () => {
const findScopedLabel = () => findAllLabels().at(1);
const findLinksMenuComponent = () => wrapper.findComponent(WorkItemLinksMenu);
- const createComponent = ({
- canUpdate = true,
- parentWorkItemId = WORK_ITEM_ID,
- childItem = workItemTask,
- workItemType = TASK_TYPE_NAME,
- } = {}) => {
+ const createComponent = ({ canUpdate = true, childItem = workItemTask } = {}) => {
wrapper = shallowMountExtended(WorkItemLinkChildContents, {
propsData: {
canUpdate,
- parentWorkItemId,
childItem,
- workItemType,
- fullPath: mockFullPath,
childPath: '/gitlab-org/gitlab-test/-/work_items/4',
},
});
diff --git a/spec/frontend/work_items/components/shared/work_item_links_menu_spec.js b/spec/frontend/work_items/components/shared/work_item_links_menu_spec.js
index 721db6c3315..338a70feae4 100644
--- a/spec/frontend/work_items/components/shared/work_item_links_menu_spec.js
+++ b/spec/frontend/work_items/components/shared/work_item_links_menu_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import WorkItemLinksMenu from '~/work_items/components/shared/work_item_links_menu.vue';
@@ -10,8 +10,8 @@ describe('WorkItemLinksMenu', () => {
wrapper = shallowMountExtended(WorkItemLinksMenu);
};
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findRemoveDropdownItem = () => wrapper.findComponent(GlDropdownItem);
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const findRemoveDropdownItem = () => wrapper.findComponent(GlDisclosureDropdownItem);
beforeEach(() => {
createComponent();
@@ -23,7 +23,7 @@ describe('WorkItemLinksMenu', () => {
});
it('emits removeChild event on click Remove', () => {
- findRemoveDropdownItem().vm.$emit('click');
+ findRemoveDropdownItem().vm.$emit('action');
expect(wrapper.emitted('removeChild')).toHaveLength(1);
});
diff --git a/spec/frontend/work_items/components/shared/work_item_token_input_spec.js b/spec/frontend/work_items/components/shared/work_item_token_input_spec.js
new file mode 100644
index 00000000000..075b69415cf
--- /dev/null
+++ b/spec/frontend/work_items/components/shared/work_item_token_input_spec.js
@@ -0,0 +1,81 @@
+import Vue from 'vue';
+import { GlTokenSelector } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import WorkItemTokenInput from '~/work_items/components/shared/work_item_token_input.vue';
+import { WORK_ITEM_TYPE_ENUM_TASK } from '~/work_items/constants';
+import projectWorkItemsQuery from '~/work_items/graphql/project_work_items.query.graphql';
+import { availableWorkItemsResponse, searchedWorkItemsResponse } from '../../mock_data';
+
+Vue.use(VueApollo);
+
+describe('WorkItemTokenInput', () => {
+ let wrapper;
+
+ const availableWorkItemsResolver = jest.fn().mockResolvedValue(availableWorkItemsResponse);
+ const searchedWorkItemResolver = jest.fn().mockResolvedValue(searchedWorkItemsResponse);
+
+ const createComponent = async ({
+ workItemsToAdd = [],
+ parentConfidential = false,
+ childrenType = WORK_ITEM_TYPE_ENUM_TASK,
+ areWorkItemsToAddValid = true,
+ workItemsResolver = searchedWorkItemResolver,
+ } = {}) => {
+ wrapper = shallowMountExtended(WorkItemTokenInput, {
+ apolloProvider: createMockApollo([[projectWorkItemsQuery, workItemsResolver]]),
+ propsData: {
+ value: workItemsToAdd,
+ childrenType,
+ childrenIds: [],
+ fullPath: 'test-project-path',
+ parentWorkItemId: 'gid://gitlab/WorkItem/1',
+ parentConfidential,
+ areWorkItemsToAddValid,
+ },
+ });
+
+ await waitForPromises();
+ };
+
+ const findTokenSelector = () => wrapper.findComponent(GlTokenSelector);
+
+ it('searches for available work items on focus', async () => {
+ createComponent({ workItemsResolver: availableWorkItemsResolver });
+ findTokenSelector().vm.$emit('focus');
+ await waitForPromises();
+
+ expect(availableWorkItemsResolver).toHaveBeenCalledWith({
+ fullPath: 'test-project-path',
+ searchTerm: '',
+ types: [WORK_ITEM_TYPE_ENUM_TASK],
+ in: undefined,
+ });
+ expect(findTokenSelector().props('dropdownItems')).toHaveLength(3);
+ });
+
+ it('searches for available work items when typing in input', async () => {
+ createComponent({ workItemsResolver: searchedWorkItemResolver });
+ findTokenSelector().vm.$emit('focus');
+ findTokenSelector().vm.$emit('text-input', 'Task 2');
+ await waitForPromises();
+
+ expect(searchedWorkItemResolver).toHaveBeenCalledWith({
+ fullPath: 'test-project-path',
+ searchTerm: 'Task 2',
+ types: [WORK_ITEM_TYPE_ENUM_TASK],
+ in: 'TITLE',
+ });
+ expect(findTokenSelector().props('dropdownItems')).toHaveLength(1);
+ });
+
+ it('renders red border around token selector input when work item is not valid', () => {
+ createComponent({
+ areWorkItemsToAddValid: false,
+ });
+
+ expect(findTokenSelector().props('containerClass')).toBe('gl-inset-border-1-red-500!');
+ });
+});
diff --git a/spec/frontend/work_items/components/work_item_actions_spec.js b/spec/frontend/work_items/components/work_item_actions_spec.js
index 0fe517d7d74..0098a2e0864 100644
--- a/spec/frontend/work_items/components/work_item_actions_spec.js
+++ b/spec/frontend/work_items/components/work_item_actions_spec.js
@@ -1,4 +1,4 @@
-import { GlDropdownDivider, GlModal, GlToggle } from '@gitlab/ui';
+import { GlDisclosureDropdown, GlDropdownDivider, GlModal, GlToggle } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
@@ -140,7 +140,12 @@ describe('WorkItemActions component', () => {
stubs: {
GlModal: stubComponent(GlModal, {
methods: {
- show: modalShowSpy,
+ show: jest.fn(),
+ },
+ }),
+ GlDisclosureDropdown: stubComponent(GlDisclosureDropdown, {
+ methods: {
+ close: modalShowSpy,
},
}),
},
@@ -208,7 +213,7 @@ describe('WorkItemActions component', () => {
it('emits `toggleWorkItemConfidentiality` event when clicked', () => {
createComponent();
- findConfidentialityToggleButton().vm.$emit('click');
+ findConfidentialityToggleButton().vm.$emit('action');
expect(wrapper.emitted('toggleWorkItemConfidentiality')[0]).toEqual([true]);
});
@@ -228,7 +233,7 @@ describe('WorkItemActions component', () => {
it('shows confirm modal when clicked', () => {
createComponent();
- findDeleteButton().vm.$emit('click');
+ findDeleteButton().vm.$emit('action');
expect(modalShowSpy).toHaveBeenCalled();
});
@@ -359,7 +364,7 @@ describe('WorkItemActions component', () => {
await waitForPromises();
expect(findPromoteButton().exists()).toBe(true);
- findPromoteButton().vm.$emit('click');
+ findPromoteButton().vm.$emit('action');
await waitForPromises();
@@ -378,7 +383,7 @@ describe('WorkItemActions component', () => {
await waitForPromises();
expect(findPromoteButton().exists()).toBe(true);
- findPromoteButton().vm.$emit('click');
+ findPromoteButton().vm.$emit('action');
await waitForPromises();
@@ -394,7 +399,7 @@ describe('WorkItemActions component', () => {
createComponent();
expect(findCopyReferenceButton().exists()).toBe(true);
- findCopyReferenceButton().vm.$emit('click');
+ findCopyReferenceButton().vm.$emit('action');
expect(toast).toHaveBeenCalledWith('Reference copied');
});
@@ -416,7 +421,7 @@ describe('WorkItemActions component', () => {
createComponent();
expect(findCopyCreateNoteEmailButton().exists()).toBe(true);
- findCopyCreateNoteEmailButton().vm.$emit('click');
+ findCopyCreateNoteEmailButton().vm.$emit('action');
expect(toast).toHaveBeenCalledWith('Email address copied');
});
diff --git a/spec/frontend/work_items/components/work_item_detail_spec.js b/spec/frontend/work_items/components/work_item_detail_spec.js
index d3c7c9e2074..fec6d0673c6 100644
--- a/spec/frontend/work_items/components/work_item_detail_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_spec.js
@@ -20,6 +20,7 @@ import WorkItemCreatedUpdated from '~/work_items/components/work_item_created_up
import WorkItemAttributesWrapper from '~/work_items/components/work_item_attributes_wrapper.vue';
import WorkItemTitle from '~/work_items/components/work_item_title.vue';
import WorkItemTree from '~/work_items/components/work_item_links/work_item_tree.vue';
+import WorkItemRelationships from '~/work_items/components/work_item_relationships/work_item_relationships.vue';
import WorkItemNotes from '~/work_items/components/work_item_notes.vue';
import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
@@ -37,6 +38,7 @@ import {
workItemByIidResponseFactory,
objectiveType,
mockWorkItemCommentNote,
+ mockBlockingLinkedItem,
} from '../mock_data';
jest.mock('~/lib/utils/common_utils');
@@ -76,6 +78,7 @@ describe('WorkItemDetail component', () => {
const findCloseButton = () => wrapper.findByTestId('work-item-close');
const findWorkItemType = () => wrapper.findByTestId('work-item-type');
const findHierarchyTree = () => wrapper.findComponent(WorkItemTree);
+ const findWorkItemRelationships = () => wrapper.findComponent(WorkItemRelationships);
const findNotesWidget = () => wrapper.findComponent(WorkItemNotes);
const findModal = () => wrapper.findComponent(WorkItemDetailModal);
const findAbuseCategorySelector = () => wrapper.findComponent(AbuseCategorySelector);
@@ -96,6 +99,7 @@ describe('WorkItemDetail component', () => {
confidentialityMock = [updateWorkItemMutation, jest.fn()],
error = undefined,
workItemsMvc2Enabled = false,
+ linkedWorkItemsEnabled = false,
} = {}) => {
const handlers = [
[workItemByIidQuery, handler],
@@ -119,6 +123,7 @@ describe('WorkItemDetail component', () => {
provide: {
glFeatures: {
workItemsMvc2: workItemsMvc2Enabled,
+ linkedWorkItems: linkedWorkItemsEnabled,
},
hasIssueWeightsFeature: true,
hasIterationsFeature: true,
@@ -581,12 +586,91 @@ describe('WorkItemDetail component', () => {
});
});
+ describe('relationship widget', () => {
+ it('does not render linked items by default', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(findWorkItemRelationships().exists()).toBe(false);
+ });
+
+ describe('work item has children', () => {
+ const mockWorkItemLinkedItem = workItemByIidResponseFactory({
+ linkedItems: mockBlockingLinkedItem,
+ });
+ const handler = jest.fn().mockResolvedValue(mockWorkItemLinkedItem);
+
+ it('renders relationship widget when work item has linked items', async () => {
+ createComponent({ handler, linkedWorkItemsEnabled: true });
+ await waitForPromises();
+
+ expect(findWorkItemRelationships().exists()).toBe(true);
+ });
+
+ it('opens the modal with the linked item when `showModal` is emitted', async () => {
+ createComponent({
+ handler,
+ linkedWorkItemsEnabled: true,
+ workItemsMvc2Enabled: true,
+ });
+ await waitForPromises();
+
+ const event = {
+ preventDefault: jest.fn(),
+ };
+
+ findWorkItemRelationships().vm.$emit('showModal', {
+ event,
+ modalWorkItem: { id: 'childWorkItemId' },
+ });
+ await waitForPromises();
+
+ expect(findModal().props().workItemId).toBe('childWorkItemId');
+ expect(showModalHandler).toHaveBeenCalled();
+ });
+
+ describe('linked work item is rendered in a modal and has linked items', () => {
+ beforeEach(async () => {
+ createComponent({
+ isModal: true,
+ handler,
+ workItemsMvc2Enabled: true,
+ linkedWorkItemsEnabled: true,
+ });
+
+ await waitForPromises();
+ });
+
+ it('does not render a new modal', () => {
+ expect(findModal().exists()).toBe(false);
+ });
+
+ it('emits `update-modal` when `show-modal` is emitted', async () => {
+ const event = {
+ preventDefault: jest.fn(),
+ };
+
+ findWorkItemRelationships().vm.$emit('showModal', {
+ event,
+ modalWorkItem: { id: 'childWorkItemId' },
+ });
+ await waitForPromises();
+
+ expect(wrapper.emitted('update-modal')).toBeDefined();
+ });
+ });
+ });
+ });
+
describe('notes widget', () => {
it('renders notes by default', async () => {
createComponent();
await waitForPromises();
+ const { confidential } = workItemQueryResponse.data.workspace.workItems.nodes[0];
+
expect(findNotesWidget().exists()).toBe(true);
+ expect(findNotesWidget().props('isWorkItemConfidential')).toBe(confidential);
});
});
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js
index 803ff950cbe..a624bbe8567 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js
@@ -93,8 +93,6 @@ describe('WorkItemLinkChild', () => {
expect(findWorkItemLinkChildContents().props()).toEqual({
childItem: workItemObjectiveWithChild,
canUpdate: true,
- parentWorkItemId: 'gid://gitlab/WorkItem/2',
- workItemType: 'Objective',
childPath: '/gitlab-org/gitlab-test/-/work_items/12',
});
});
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js
index 8caacc2dc97..aaab22fd18d 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js
@@ -1,11 +1,12 @@
import Vue from 'vue';
-import { GlForm, GlFormInput, GlFormCheckbox, GlTooltip, GlTokenSelector } from '@gitlab/ui';
+import { GlForm, GlFormInput, GlFormCheckbox, GlTooltip } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import { sprintf, s__ } from '~/locale';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import WorkItemLinksForm from '~/work_items/components/work_item_links/work_item_links_form.vue';
+import WorkItemTokenInput from '~/work_items/components/shared/work_item_token_input.vue';
import {
FORM_TYPES,
WORK_ITEM_TYPE_ENUM_TASK,
@@ -70,10 +71,12 @@ describe('WorkItemLinksForm', () => {
};
const findForm = () => wrapper.findComponent(GlForm);
- const findTokenSelector = () => wrapper.findComponent(GlTokenSelector);
+ const findWorkItemTokenInput = () => wrapper.findComponent(WorkItemTokenInput);
const findInput = () => wrapper.findComponent(GlFormInput);
const findConfidentialCheckbox = () => wrapper.findComponent(GlFormCheckbox);
+ const findTooltip = () => wrapper.findComponent(GlTooltip);
const findAddChildButton = () => wrapper.findByTestId('add-child-button');
+ const findValidationElement = () => wrapper.findByTestId('work-items-invalid');
describe('creating a new work item', () => {
beforeEach(async () => {
@@ -84,7 +87,7 @@ describe('WorkItemLinksForm', () => {
expect(findForm().exists()).toBe(true);
expect(findInput().exists()).toBe(true);
expect(findAddChildButton().text()).toBe('Create task');
- expect(findTokenSelector().exists()).toBe(false);
+ expect(findWorkItemTokenInput().exists()).toBe(false);
});
it('creates child task in non confidential parent', async () => {
@@ -137,7 +140,7 @@ describe('WorkItemLinksForm', () => {
const confidentialCheckbox = findConfidentialCheckbox();
expect(confidentialCheckbox.exists()).toBe(true);
- expect(wrapper.findComponent(GlTooltip).exists()).toBe(false);
+ expect(findTooltip().exists()).toBe(false);
expect(confidentialCheckbox.text()).toBe(
sprintf(I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_LABEL, {
workItemType: WORK_ITEM_TYPE_ENUM_TASK.toLocaleLowerCase(),
@@ -149,12 +152,11 @@ describe('WorkItemLinksForm', () => {
createComponent({ parentConfidential: true });
const confidentialCheckbox = findConfidentialCheckbox();
- const confidentialTooltip = wrapper.findComponent(GlTooltip);
expect(confidentialCheckbox.attributes('disabled')).toBeDefined();
expect(confidentialCheckbox.attributes('checked')).toBe('true');
- expect(confidentialTooltip.exists()).toBe(true);
- expect(confidentialTooltip.text()).toBe(
+ expect(findTooltip().exists()).toBe(true);
+ expect(findTooltip().text()).toBe(
sprintf(I18N_WORK_ITEM_CONFIDENTIALITY_CHECKBOX_TOOLTIP, {
workItemType: WORK_ITEM_TYPE_ENUM_TASK.toLocaleLowerCase(),
parentWorkItemType: WORK_ITEM_TYPE_VALUE_ISSUE.toLocaleLowerCase(),
@@ -165,14 +167,11 @@ describe('WorkItemLinksForm', () => {
});
describe('adding an existing work item', () => {
- const selectAvailableWorkItemTokens = async () => {
- findTokenSelector().vm.$emit(
+ const selectAvailableWorkItemTokens = () => {
+ findWorkItemTokenInput().vm.$emit(
'input',
availableWorkItemsResponse.data.workspace.workItems.nodes,
);
- findTokenSelector().vm.$emit('blur', new FocusEvent({ relatedTarget: null }));
-
- await waitForPromises();
};
beforeEach(async () => {
@@ -181,24 +180,31 @@ describe('WorkItemLinksForm', () => {
it('renders add form', () => {
expect(findForm().exists()).toBe(true);
- expect(findTokenSelector().exists()).toBe(true);
+ expect(findWorkItemTokenInput().exists()).toBe(true);
expect(findAddChildButton().text()).toBe('Add task');
expect(findInput().exists()).toBe(false);
expect(findConfidentialCheckbox().exists()).toBe(false);
});
- it('searches for available work items as prop when typing in input', async () => {
- findTokenSelector().vm.$emit('focus');
- findTokenSelector().vm.$emit('text-input', 'Task');
- await waitForPromises();
-
- expect(availableWorkItemsResolver).toHaveBeenCalled();
+ it('renders work item token input with default props', () => {
+ expect(findWorkItemTokenInput().props()).toMatchObject({
+ value: [],
+ fullPath: 'project/path',
+ childrenType: WORK_ITEM_TYPE_ENUM_TASK,
+ childrenIds: [],
+ parentWorkItemId: 'gid://gitlab/WorkItem/1',
+ areWorkItemsToAddValid: true,
+ });
});
it('selects and adds children', async () => {
await selectAvailableWorkItemTokens();
expect(findAddChildButton().text()).toBe('Add tasks');
+ expect(findWorkItemTokenInput().props('areWorkItemsToAddValid')).toBe(true);
+ expect(findWorkItemTokenInput().props('value')).toBe(
+ availableWorkItemsResponse.data.workspace.workItems.nodes,
+ );
findForm().vm.$emit('submit', {
preventDefault: jest.fn(),
});
@@ -211,9 +217,9 @@ describe('WorkItemLinksForm', () => {
await selectAvailableWorkItemTokens();
- const validationEl = wrapper.findByTestId('work-items-invalid');
- expect(validationEl.exists()).toBe(true);
- expect(validationEl.text().trim()).toBe(
+ expect(findWorkItemTokenInput().props('areWorkItemsToAddValid')).toBe(false);
+ expect(findValidationElement().exists()).toBe(true);
+ expect(findValidationElement().text().trim()).toBe(
sprintf(
s__(
'WorkItem|%{invalidWorkItemsList} cannot be added: Cannot assign a non-confidential %{childWorkItemType} to a confidential parent %{parentWorkItemType}. Make the selected %{childWorkItemType} confidential and try again.',
diff --git a/spec/frontend/work_items/components/work_item_notes_spec.js b/spec/frontend/work_items/components/work_item_notes_spec.js
index c2821cc99f9..35f01c85ec8 100644
--- a/spec/frontend/work_items/components/work_item_notes_spec.js
+++ b/spec/frontend/work_items/components/work_item_notes_spec.js
@@ -88,6 +88,7 @@ describe('WorkItemNotes component', () => {
defaultWorkItemNotesQueryHandler = workItemNotesQueryHandler,
deleteWINoteMutationHandler = deleteWorkItemNoteMutationSuccessHandler,
isModal = false,
+ isWorkItemConfidential = false,
} = {}) => {
wrapper = shallowMount(WorkItemNotes, {
apolloProvider: createMockApollo([
@@ -106,6 +107,7 @@ describe('WorkItemNotes component', () => {
workItemType: 'task',
reportAbusePath: '/report/abuse/path',
isModal,
+ isWorkItemConfidential,
},
stubs: {
GlModal: stubComponent(GlModal, { methods: { show: showModal } }),
@@ -344,4 +346,14 @@ describe('WorkItemNotes component', () => {
});
});
});
+
+ it('passes confidential props when the work item is confidential', async () => {
+ createComponent({
+ isWorkItemConfidential: true,
+ defaultWorkItemNotesQueryHandler: workItemNotesWithCommentsQueryHandler,
+ });
+ await waitForPromises();
+
+ expect(findWorkItemCommentNoteAtIndex(0).props('isWorkItemConfidential')).toBe(true);
+ });
});
diff --git a/spec/frontend/work_items/components/work_item_relationships/__snapshots__/work_item_relationship_list_spec.js.snap b/spec/frontend/work_items/components/work_item_relationships/__snapshots__/work_item_relationship_list_spec.js.snap
new file mode 100644
index 00000000000..9105e4de5e0
--- /dev/null
+++ b/spec/frontend/work_items/components/work_item_relationships/__snapshots__/work_item_relationship_list_spec.js.snap
@@ -0,0 +1,29 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`WorkItemRelationshipList renders linked item list 1`] = `
+<div>
+ <h4
+ class="gl-font-sm gl-font-weight-semibold gl-mb-2 gl-mt-3 gl-mx-2 gl-text-gray-700"
+ data-testid="work-items-list-heading"
+ >
+ Blocking
+ </h4>
+ <div
+ class="work-items-list-body"
+ >
+ <ul
+ class="content-list work-items-list"
+ >
+ <li
+ class="gl-border-b-0! gl-pb-0! gl-pt-0!"
+ >
+ <work-item-link-child-contents-stub
+ canupdate="true"
+ childitem="[object Object]"
+ childpath="/test-project-path/-/work_items/83"
+ />
+ </li>
+ </ul>
+ </div>
+</div>
+`;
diff --git a/spec/frontend/work_items/components/work_item_relationships/work_item_relationship_list_spec.js b/spec/frontend/work_items/components/work_item_relationships/work_item_relationship_list_spec.js
new file mode 100644
index 00000000000..759ab7e14da
--- /dev/null
+++ b/spec/frontend/work_items/components/work_item_relationships/work_item_relationship_list_spec.js
@@ -0,0 +1,41 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import WorkItemRelationshipList from '~/work_items/components/work_item_relationships/work_item_relationship_list.vue';
+import WorkItemLinkChildContents from '~/work_items/components/shared/work_item_link_child_contents.vue';
+
+import { mockBlockingLinkedItem } from '../../mock_data';
+
+describe('WorkItemRelationshipList', () => {
+ let wrapper;
+ const mockLinkedItems = mockBlockingLinkedItem.linkedItems.nodes;
+
+ const createComponent = ({ linkedItems = [], heading = 'Blocking', canUpdate = true } = {}) => {
+ wrapper = shallowMountExtended(WorkItemRelationshipList, {
+ propsData: {
+ linkedItems,
+ heading,
+ canUpdate,
+ workItemFullPath: 'test-project-path',
+ },
+ });
+ };
+
+ const findHeading = () => wrapper.findByTestId('work-items-list-heading');
+ const findWorkItemLinkChildContents = () => wrapper.findComponent(WorkItemLinkChildContents);
+
+ beforeEach(() => {
+ createComponent({ linkedItems: mockLinkedItems });
+ });
+
+ it('renders linked item list', () => {
+ expect(findHeading().text()).toBe('Blocking');
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+
+ it('renders work item link child contents with correct props', () => {
+ expect(findWorkItemLinkChildContents().props()).toMatchObject({
+ childItem: mockLinkedItems[0].workItem,
+ canUpdate: true,
+ childPath: '/test-project-path/-/work_items/83',
+ });
+ });
+});
diff --git a/spec/frontend/work_items/components/work_item_relationships/work_item_relationships_spec.js b/spec/frontend/work_items/components/work_item_relationships/work_item_relationships_spec.js
new file mode 100644
index 00000000000..c9a2499b127
--- /dev/null
+++ b/spec/frontend/work_items/components/work_item_relationships/work_item_relationships_spec.js
@@ -0,0 +1,93 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { GlLoadingIcon } from '@gitlab/ui';
+
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+
+import WidgetWrapper from '~/work_items/components/widget_wrapper.vue';
+import WorkItemRelationships from '~/work_items/components/work_item_relationships/work_item_relationships.vue';
+import WorkItemRelationshipList from '~/work_items/components/work_item_relationships/work_item_relationship_list.vue';
+import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
+
+import {
+ workItemByIidResponseFactory,
+ mockLinkedItems,
+ mockBlockingLinkedItem,
+} from '../../mock_data';
+
+describe('WorkItemRelationships', () => {
+ Vue.use(VueApollo);
+
+ let wrapper;
+ const emptyLinkedWorkItemsQueryHandler = jest
+ .fn()
+ .mockResolvedValue(workItemByIidResponseFactory());
+ const linkedWorkItemsQueryHandler = jest
+ .fn()
+ .mockResolvedValue(workItemByIidResponseFactory({ linkedItems: mockLinkedItems }));
+ const blockingLinkedWorkItemQueryHandler = jest
+ .fn()
+ .mockResolvedValue(workItemByIidResponseFactory({ linkedItems: mockBlockingLinkedItem }));
+
+ const createComponent = async ({
+ workItemQueryHandler = emptyLinkedWorkItemsQueryHandler,
+ } = {}) => {
+ const mockApollo = createMockApollo([[workItemByIidQuery, workItemQueryHandler]]);
+
+ wrapper = shallowMountExtended(WorkItemRelationships, {
+ apolloProvider: mockApollo,
+ propsData: {
+ workItemIid: '1',
+ workItemFullPath: 'test-project-path',
+ },
+ });
+
+ await waitForPromises();
+ };
+
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findWidgetWrapper = () => wrapper.findComponent(WidgetWrapper);
+ const findEmptyRelatedMessageContainer = () => wrapper.findByTestId('links-empty');
+ const findLinkedItemsCountContainer = () => wrapper.findByTestId('linked-items-count');
+ const findAllWorkItemRelationshipListComponents = () =>
+ wrapper.findAllComponents(WorkItemRelationshipList);
+
+ it('shows loading icon when query is not processed', () => {
+ createComponent();
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('renders the component with empty message when there are no items', async () => {
+ await createComponent();
+
+ expect(wrapper.find('.work-item-relationships').exists()).toBe(true);
+ expect(findEmptyRelatedMessageContainer().exists()).toBe(true);
+ });
+
+ it('renders blocking linked item lists', async () => {
+ await createComponent({ workItemQueryHandler: blockingLinkedWorkItemQueryHandler });
+
+ expect(findAllWorkItemRelationshipListComponents().length).toBe(1);
+ expect(findLinkedItemsCountContainer().text()).toBe('1');
+ });
+
+ it('renders blocking, blocked by and related to linked item lists with proper count', async () => {
+ await createComponent({ workItemQueryHandler: linkedWorkItemsQueryHandler });
+
+ // renders all 3 lists: blocking, blocked by and related to
+ expect(findAllWorkItemRelationshipListComponents().length).toBe(3);
+ expect(findLinkedItemsCountContainer().text()).toBe('3');
+ });
+
+ it('shows an alert when list loading fails', async () => {
+ const errorMessage = 'Some error';
+ await createComponent({
+ workItemQueryHandler: jest.fn().mockRejectedValue(new Error(errorMessage)),
+ });
+
+ expect(findWidgetWrapper().props('error')).toBe(errorMessage);
+ });
+});
diff --git a/spec/frontend/work_items/components/work_item_state_badge_spec.js b/spec/frontend/work_items/components/work_item_state_badge_spec.js
index 888d712cc5a..248f16a4081 100644
--- a/spec/frontend/work_items/components/work_item_state_badge_spec.js
+++ b/spec/frontend/work_items/components/work_item_state_badge_spec.js
@@ -1,4 +1,4 @@
-import { GlBadge } from '@gitlab/ui';
+import { GlBadge, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { STATE_OPEN, STATE_CLOSED } from '~/work_items/constants';
import WorkItemStateBadge from '~/work_items/components/work_item_state_badge.vue';
@@ -14,6 +14,7 @@ describe('WorkItemStateBadge', () => {
});
};
const findStatusBadge = () => wrapper.findComponent(GlBadge);
+ const findStatusBadgeIcon = () => wrapper.findComponent(GlIcon);
it.each`
state | icon | stateText | variant
@@ -24,7 +25,7 @@ describe('WorkItemStateBadge', () => {
({ state, icon, stateText, variant }) => {
createComponent({ workItemState: state });
- expect(findStatusBadge().props('icon')).toBe(icon);
+ expect(findStatusBadgeIcon().props('name')).toBe(icon);
expect(findStatusBadge().props('variant')).toBe(variant);
expect(findStatusBadge().text()).toBe(stateText);
},
diff --git a/spec/frontend/work_items/list/components/work_items_list_app_spec.js b/spec/frontend/work_items/list/components/work_items_list_app_spec.js
index c92d092eb43..96083478e77 100644
--- a/spec/frontend/work_items/list/components/work_items_list_app_spec.js
+++ b/spec/frontend/work_items/list/components/work_items_list_app_spec.js
@@ -2,6 +2,8 @@ import * as Sentry from '@sentry/browser';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
+import IssueCardStatistics from 'ee_else_ce/issues/list/components/issue_card_statistics.vue';
+import IssueCardTimeInfo from 'ee_else_ce/issues/list/components/issue_card_time_info.vue';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { STATUS_OPEN } from '~/issues/constants';
@@ -20,6 +22,8 @@ describe('WorkItemsListApp component', () => {
const defaultQueryHandler = jest.fn().mockResolvedValue(groupWorkItemsQueryResponse);
const findIssuableList = () => wrapper.findComponent(IssuableList);
+ const findIssueCardStatistics = () => wrapper.findComponent(IssueCardStatistics);
+ const findIssueCardTimeInfo = () => wrapper.findComponent(IssueCardTimeInfo);
const mountComponent = ({ queryHandler = defaultQueryHandler } = {}) => {
wrapper = shallowMount(WorkItemsListApp, {
@@ -37,9 +41,9 @@ describe('WorkItemsListApp component', () => {
currentTab: STATUS_OPEN,
error: '',
issuables: [],
+ issuablesLoading: true,
namespace: 'work-items',
recentSearchesStorageKey: 'issues',
- searchInputPlaceholder: 'Search or filter results...',
searchTokens: [],
showWorkItemTypeIcon: true,
sortOptions: [],
@@ -47,6 +51,18 @@ describe('WorkItemsListApp component', () => {
});
});
+ it('renders IssueCardStatistics component', () => {
+ mountComponent();
+
+ expect(findIssueCardStatistics().exists()).toBe(true);
+ });
+
+ it('renders IssueCardTimeInfo component', () => {
+ mountComponent();
+
+ expect(findIssueCardTimeInfo().exists()).toBe(true);
+ });
+
it('renders work items', async () => {
mountComponent();
await waitForPromises();
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index 05e83c0df3d..ba244b19eb5 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -1,3 +1,5 @@
+import { WIDGET_TYPE_LINKED_ITEMS } from '~/work_items/constants';
+
export const mockAssignees = [
{
__typename: 'UserCore',
@@ -451,6 +453,126 @@ export const objectiveType = {
iconName: 'issue-type-objective',
};
+export const mockEmptyLinkedItems = {
+ type: WIDGET_TYPE_LINKED_ITEMS,
+ blocked: false,
+ blockedByCount: 0,
+ blockingCount: 0,
+ linkedItems: {
+ nodes: [],
+ __typename: 'LinkedWorkItemTypeConnection',
+ },
+ __typename: 'WorkItemWidgetLinkedItems',
+};
+
+export const mockBlockingLinkedItem = {
+ type: WIDGET_TYPE_LINKED_ITEMS,
+ linkedItems: {
+ nodes: [
+ {
+ linkId: 'gid://gitlab/WorkItems::RelatedWorkItemLink/8',
+ linkType: 'blocks',
+ workItem: {
+ id: 'gid://gitlab/WorkItem/675',
+ iid: '83',
+ confidential: true,
+ workItemType: {
+ id: 'gid://gitlab/WorkItems::Type/5',
+ name: 'Task',
+ iconName: 'issue-type-task',
+ __typename: 'WorkItemType',
+ },
+ title: 'Task 1201',
+ state: 'OPEN',
+ createdAt: '2023-03-28T10:50:16Z',
+ closedAt: null,
+ widgets: [],
+ __typename: 'WorkItem',
+ },
+ __typename: 'LinkedWorkItemType',
+ },
+ ],
+ __typename: 'LinkedWorkItemTypeConnection',
+ },
+ __typename: 'WorkItemWidgetLinkedItems',
+};
+
+export const mockLinkedItems = {
+ type: WIDGET_TYPE_LINKED_ITEMS,
+ linkedItems: {
+ nodes: [
+ {
+ linkId: 'gid://gitlab/WorkItems::RelatedWorkItemLink/8',
+ linkType: 'relates_to',
+ workItem: {
+ id: 'gid://gitlab/WorkItem/675',
+ iid: '83',
+ confidential: true,
+ workItemType: {
+ id: 'gid://gitlab/WorkItems::Type/5',
+ name: 'Task',
+ iconName: 'issue-type-task',
+ __typename: 'WorkItemType',
+ },
+ title: 'Task 1201',
+ state: 'OPEN',
+ createdAt: '2023-03-28T10:50:16Z',
+ closedAt: null,
+ widgets: [],
+ __typename: 'WorkItem',
+ },
+ __typename: 'LinkedWorkItemType',
+ },
+ {
+ linkId: 'gid://gitlab/WorkItems::RelatedWorkItemLink/9',
+ linkType: 'is_blocked_by',
+ workItem: {
+ id: 'gid://gitlab/WorkItem/646',
+ iid: '55',
+ confidential: true,
+ workItemType: {
+ id: 'gid://gitlab/WorkItems::Type/6',
+ name: 'Objective',
+ iconName: 'issue-type-objective',
+ __typename: 'WorkItemType',
+ },
+ title: 'Multilevel Objective 1',
+ state: 'OPEN',
+ createdAt: '2023-03-28T10:50:16Z',
+ closedAt: null,
+ widgets: [],
+ __typename: 'WorkItem',
+ },
+ __typename: 'LinkedWorkItemType',
+ },
+ {
+ linkId: 'gid://gitlab/WorkItems::RelatedWorkItemLink/10',
+ linkType: 'blocks',
+ workItem: {
+ id: 'gid://gitlab/WorkItem/647',
+ iid: '56',
+ confidential: true,
+ workItemType: {
+ id: 'gid://gitlab/WorkItems::Type/6',
+ name: 'Objective',
+ iconName: 'issue-type-objective',
+ __typename: 'WorkItemType',
+ },
+ title: 'Multilevel Objective 2',
+ state: 'OPEN',
+ createdAt: '2023-03-28T10:50:16Z',
+ closedAt: null,
+ widgets: [],
+ __typename: 'WorkItem',
+ },
+ __typename: 'LinkedWorkItemType',
+ },
+ ],
+ __typename: 'LinkedWorkItemTypeConnection',
+ },
+ __typename: 'WorkItemWidgetLinkedItems',
+};
+
export const workItemResponseFactory = ({
iid = '1',
canUpdate = false,
@@ -473,6 +595,7 @@ export const workItemResponseFactory = ({
confidential = false,
canInviteMembers = false,
labelsWidgetPresent = true,
+ linkedItemsWidgetPresent = true,
labels = mockLabels,
allowsScopedLabels = false,
lastEditedAt = null,
@@ -485,6 +608,7 @@ export const workItemResponseFactory = ({
updatedAt = '2022-08-08T12:32:54Z',
awardEmoji = mockAwardsWidget,
state = 'OPEN',
+ linkedItems = mockEmptyLinkedItems,
} = {}) => ({
data: {
workItem: {
@@ -683,6 +807,7 @@ export const workItemResponseFactory = ({
awardEmoji,
}
: { type: 'MOCK TYPE' },
+ linkedItemsWidgetPresent ? linkedItems : { type: 'MOCK TYPE' },
],
},
},
@@ -1471,6 +1596,27 @@ export const availableWorkItemsResponse = {
},
};
+export const searchedWorkItemsResponse = {
+ data: {
+ workspace: {
+ __typename: 'Project',
+ id: 'gid://gitlab/Project/2',
+ workItems: {
+ nodes: [
+ {
+ id: 'gid://gitlab/WorkItem/459',
+ title: 'Task 2',
+ state: 'OPEN',
+ createdAt: '2022-08-03T12:41:54Z',
+ confidential: false,
+ __typename: 'WorkItem',
+ },
+ ],
+ },
+ },
+ },
+};
+
export const projectMembersResponseWithCurrentUser = {
data: {
workspace: {
@@ -1883,8 +2029,7 @@ export const mockWorkItemNotesResponse = {
systemNoteIconName: 'link',
createdAt: '2022-11-14T04:18:59Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_199',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_199',
lastEditedBy: null,
system: true,
internal: false,
@@ -1934,8 +2079,7 @@ export const mockWorkItemNotesResponse = {
systemNoteIconName: 'clock',
createdAt: '2022-11-14T04:18:59Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_201',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_201',
lastEditedBy: null,
system: true,
internal: false,
@@ -1984,8 +2128,7 @@ export const mockWorkItemNotesResponse = {
systemNoteIconName: 'weight',
createdAt: '2022-11-25T07:16:20Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_202',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_202',
lastEditedBy: null,
system: true,
internal: false,
@@ -2097,8 +2240,7 @@ export const mockWorkItemNotesByIidResponse = {
systemNoteIconName: 'link',
createdAt: '2022-11-14T04:18:59Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
@@ -2153,8 +2295,7 @@ export const mockWorkItemNotesByIidResponse = {
systemNoteIconName: 'clock',
createdAt: '2022-11-14T04:18:59Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
@@ -2210,8 +2351,7 @@ export const mockWorkItemNotesByIidResponse = {
systemNoteIconName: 'iteration',
createdAt: '2022-11-14T04:19:00Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
@@ -2325,8 +2465,7 @@ export const mockMoreWorkItemNotesResponse = {
systemNoteIconName: 'link',
createdAt: '2022-11-14T04:18:59Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
@@ -2381,8 +2520,7 @@ export const mockMoreWorkItemNotesResponse = {
systemNoteIconName: 'clock',
createdAt: '2022-11-14T04:18:59Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
@@ -2435,8 +2573,7 @@ export const mockMoreWorkItemNotesResponse = {
systemNoteIconName: 'weight',
createdAt: '2022-11-25T07:16:20Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
@@ -2511,7 +2648,7 @@ export const createWorkItemNoteResponse = {
systemNoteIconName: null,
createdAt: '2023-01-25T04:49:46Z',
lastEditedAt: null,
- url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
maxAccessLevelOfAuthor: 'Owner',
authorIsContributor: false,
@@ -2565,7 +2702,7 @@ export const mockWorkItemCommentNote = {
systemNoteIconName: false,
createdAt: '2022-11-25T07:16:20Z',
lastEditedAt: null,
- url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: false,
internal: false,
@@ -2665,8 +2802,7 @@ export const mockWorkItemNotesResponseWithComments = {
systemNoteIconName: null,
createdAt: '2023-01-12T07:47:40Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
maxAccessLevelOfAuthor: 'Owner',
authorIsContributor: false,
@@ -2708,8 +2844,7 @@ export const mockWorkItemNotesResponseWithComments = {
systemNoteIconName: null,
createdAt: '2023-01-18T09:09:54Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
maxAccessLevelOfAuthor: 'Owner',
authorIsContributor: false,
@@ -2758,8 +2893,7 @@ export const mockWorkItemNotesResponseWithComments = {
systemNoteIconName: 'weight',
createdAt: '2022-11-25T07:16:20Z',
lastEditedAt: null,
- url:
- 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: false,
internal: false,
@@ -2821,7 +2955,7 @@ export const workItemNotesCreateSubscriptionResponse = {
systemNoteIconName: 'weight',
createdAt: '2022-11-25T07:16:20Z',
lastEditedAt: null,
- url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
@@ -2836,7 +2970,7 @@ export const workItemNotesCreateSubscriptionResponse = {
systemNoteIconName: 'weight',
createdAt: '2022-11-25T07:16:20Z',
lastEditedAt: null,
- url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
@@ -2914,7 +3048,7 @@ export const workItemNotesUpdateSubscriptionResponse = {
systemNoteIconName: 'pencil',
createdAt: '2022-11-25T07:16:20Z',
lastEditedAt: null,
- url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37?iid_path=true#note_191',
+ url: 'http://127.0.0.1:3000/flightjs/Flight/-/work_items/37#note_191',
lastEditedBy: null,
system: true,
internal: false,
diff --git a/spec/frontend/work_items/utils_spec.js b/spec/frontend/work_items/utils_spec.js
index aa24b80cf08..8a49140119d 100644
--- a/spec/frontend/work_items/utils_spec.js
+++ b/spec/frontend/work_items/utils_spec.js
@@ -1,4 +1,4 @@
-import { autocompleteDataSources, markdownPreviewPath } from '~/work_items/utils';
+import { autocompleteDataSources, markdownPreviewPath, workItemPath } from '~/work_items/utils';
describe('autocompleteDataSources', () => {
beforeEach(() => {
@@ -25,3 +25,14 @@ describe('markdownPreviewPath', () => {
);
});
});
+
+describe('workItemPath', () => {
+ it('returns corrrect data sources', () => {
+ expect(workItemPath('project/group', '2')).toEqual('/project/group/-/work_items/2');
+ });
+
+ it('returns corrrect data sources with relative url root', () => {
+ gon.relative_url_root = '/foobar';
+ expect(workItemPath('project/group', '2')).toEqual('/foobar/project/group/-/work_items/2');
+ });
+});
diff --git a/spec/graphql/mutations/base_mutation_spec.rb b/spec/graphql/mutations/base_mutation_spec.rb
index 6b366b0c234..a73d914f48f 100644
--- a/spec/graphql/mutations/base_mutation_spec.rb
+++ b/spec/graphql/mutations/base_mutation_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Mutations::BaseMutation do
+RSpec.describe ::Mutations::BaseMutation, feature_category: :api do
include GraphqlHelpers
describe 'argument nullability' do
diff --git a/spec/graphql/mutations/design_management/delete_spec.rb b/spec/graphql/mutations/design_management/delete_spec.rb
index a76943b9ff8..9a2efb61e55 100644
--- a/spec/graphql/mutations/design_management/delete_spec.rb
+++ b/spec/graphql/mutations/design_management/delete_spec.rb
@@ -90,12 +90,12 @@ RSpec.describe Mutations::DesignManagement::Delete do
allow(Gitlab::Tracking).to receive(:event) # rubocop:disable RSpec/ExpectGitlabTracking
filenames.each(&:present?) # ignore setup
- # Queries: as of 2022-06-15
+ # Queries: as of 2022-08-30
# -------------
# 01. routing query
- # 02. find project by id
- # 03. project.project_features
- # 04. find namespace by id and type
+ # 02. policy query: find namespace by type and id
+ # 03. policy query: find namespace by id
+ # 04. policy query: project.project_feature
# 05,06. project.authorizations for user (same query twice)
# 07. find issue by iid
# 08. find project by id
@@ -109,21 +109,22 @@ RSpec.describe Mutations::DesignManagement::Delete do
# 16, 17 project.authorizations for user (same query as 5)
# 18. find design_management_repository for project
# 19. find route by id and source_type
- # 20. find plan for standard context
# ------------- our queries are below:
- # 21. start transaction 1
- # 22. start transaction 2
- # 23. find version by sha and issue
- # 24. exists version with sha and issue?
- # 25. leave transaction 2
- # 26. create version with sha and issue
- # 27. create design-version links
- # 28. validate version.actions.present?
- # 29. validate version.issue.present?
- # 30. validate version.sha is unique
- # 31. leave transaction 1
+ # 20. start transaction
+ # 21. create version with sha and issue
+ # 22. create design-version links
+ # 23. validate version.actions.present?
+ # 24. validate version.sha is unique
+ # 25. validate version.issue.present?
+ # 26. leave transaction
+ # 27. find project by id (same query as 8)
+ # 28. find namespace by id (same query as 9)
+ # 29. find project by id (same query as 8)
+ # 30. find project by id (same query as 8)
+ # 31. create event
+ # 32. find plan for standard context
#
- expect { run_mutation }.not_to exceed_query_limit(31)
+ expect { run_mutation }.not_to exceed_query_limit(32)
end
end
diff --git a/spec/graphql/mutations/work_items/linked_items/base_spec.rb b/spec/graphql/mutations/work_items/linked_items/base_spec.rb
index 7061c37abd3..bc52aee443e 100644
--- a/spec/graphql/mutations/work_items/linked_items/base_spec.rb
+++ b/spec/graphql/mutations/work_items/linked_items/base_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe Mutations::WorkItems::LinkedItems::Base, feature_category: :group
it 'raises a NotImplementedError error if the update_links method is called on the base class' do
mutation = described_class.new(context: { current_user: user }, object: nil, field: nil)
- expect { mutation.resolve(id: work_item.to_gid) }.to raise_error(NotImplementedError)
+ expect { mutation.resolve(id: work_item.to_gid) }
+ .to raise_error(NotImplementedError, "#{described_class} does not implement update_links")
end
end
diff --git a/spec/graphql/resolvers/base_resolver_spec.rb b/spec/graphql/resolvers/base_resolver_spec.rb
index d80a61fd318..27c62da31c3 100644
--- a/spec/graphql/resolvers/base_resolver_spec.rb
+++ b/spec/graphql/resolvers/base_resolver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Resolvers::BaseResolver do
+RSpec.describe Resolvers::BaseResolver, feature_category: :api do
include GraphqlHelpers
let(:resolver) do
diff --git a/spec/graphql/resolvers/blame_resolver_spec.rb b/spec/graphql/resolvers/blame_resolver_spec.rb
new file mode 100644
index 00000000000..a3344132928
--- /dev/null
+++ b/spec/graphql/resolvers/blame_resolver_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::BlameResolver, feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+
+ let(:path) { 'files/ruby/popen.rb' }
+ let(:commit) { project.commit('master') }
+ let(:blob) { project.repository.blob_at(commit.id, path) }
+ let(:args) { { from_line: 1, to_line: 2 } }
+
+ subject(:resolve_blame) { resolve(described_class, obj: blob, args: args, ctx: { current_user: user }) }
+
+ context 'when unauthorized' do
+ it 'generates an error' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
+ resolve_blame
+ end
+ end
+ end
+
+ context 'when authorized' do
+ before_all do
+ project.add_developer(user)
+ end
+
+ context 'when feature is disabled' do
+ before do
+ stub_feature_flags(graphql_git_blame: false)
+ end
+
+ it 'returns nothing' do
+ expect(subject).to be_nil
+ end
+ end
+
+ shared_examples 'argument error' do
+ it 'raises an ArgumentError' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError,
+ '`from_line` and `to_line` must be greater than or equal to 1') do
+ resolve_blame
+ end
+ end
+ end
+
+ context 'when feature is enabled' do
+ context 'when from_line is below 1' do
+ let(:args) { { from_line: 0, to_line: 2 } }
+
+ it_behaves_like 'argument error'
+ end
+
+ context 'when to_line is below 1' do
+ let(:args) { { from_line: 1, to_line: 0 } }
+
+ it_behaves_like 'argument error'
+ end
+
+ context 'when to_line less than from_line' do
+ let(:args) { { from_line: 3, to_line: 1 } }
+
+ it 'returns blame object' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError,
+ '`to_line` must be greater than or equal to `from_line`') do
+ resolve_blame
+ end
+ end
+ end
+
+ it 'returns blame object' do
+ expect(resolve_blame).to be_an_instance_of(Gitlab::Blame)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/branch_commit_resolver_spec.rb b/spec/graphql/resolvers/branch_commit_resolver_spec.rb
index 3d5702539fa..f901306a355 100644
--- a/spec/graphql/resolvers/branch_commit_resolver_spec.rb
+++ b/spec/graphql/resolvers/branch_commit_resolver_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Resolvers::BranchCommitResolver do
commit_a = repository.commits('master', limit: 1).last
commit_b = repository.commits('spooky-stuff', limit: 1).last
- commits = batch_sync(max_queries: 1) do
+ commits = batch_sync(max_queries: 2) do
[
resolve(described_class, obj: branch),
resolve(described_class, obj: repository.find_branch('spooky-stuff'))
diff --git a/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb b/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb
index fddc73fadfe..6b9e3a484b1 100644
--- a/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/all_jobs_resolver_spec.rb
@@ -5,37 +5,114 @@ require 'spec_helper'
RSpec.describe Resolvers::Ci::AllJobsResolver, feature_category: :continuous_integration do
include GraphqlHelpers
- let_it_be(:successful_job) { create(:ci_build, :success, name: 'Job One') }
- let_it_be(:successful_job_two) { create(:ci_build, :success, name: 'Job Two') }
- let_it_be(:failed_job) { create(:ci_build, :failed, name: 'Job Three') }
- let_it_be(:pending_job) { create(:ci_build, :pending, name: 'Job Three') }
+ let_it_be(:instance_runner) { create(:ci_runner, :instance) }
+ let_it_be(:successful_job) { create(:ci_build, :success, name: 'successful_job') }
+ let_it_be(:successful_job_two) { create(:ci_build, :success, name: 'successful_job_two') }
+ let_it_be(:failed_job) { create(:ci_build, :failed, name: 'failed_job') }
+ let_it_be(:pending_job) { create(:ci_build, :pending, name: 'pending_job') }
let(:args) { {} }
- subject { resolve_jobs(args) }
-
describe '#resolve' do
- context 'with admin' do
- let(:current_user) { create(:admin) }
+ subject(:request) { resolve_jobs(args) }
+
+ context 'when current user is an admin' do
+ let_it_be(:current_user) { create(:admin) }
shared_examples 'executes as admin' do
- context 'with statuses argument' do
- let(:args) { { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS')] } }
+ context "with argument `statuses`" do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:statuses, :expected_jobs) do
+ nil | lazy { [successful_job, successful_job_two, failed_job, pending_job] }
+ %w[SUCCESS] | lazy { [successful_job, successful_job_two] }
+ %w[SUCCESS FAILED] | lazy { [successful_job, successful_job_two, failed_job] }
+ %w[CANCELED] | lazy { [] }
+ end
- it { is_expected.to contain_exactly(successful_job, successful_job_two) }
+ with_them do
+ let(:args) do
+ { statuses: statuses&.map { |status| Types::Ci::JobStatusEnum.coerce_isolated_input(status) } }
+ end
+
+ it { is_expected.to contain_exactly(*expected_jobs) }
+ end
end
- context 'with multiple statuses' do
- let(:args) do
- { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS'),
- Types::Ci::JobStatusEnum.coerce_isolated_input('FAILED')] }
+ context "with argument `runner_types`" do
+ let_it_be(:successful_job_with_instance_runner) do
+ create(:ci_build, :success, name: 'successful_job_with_instance_runner', runner: instance_runner)
end
- it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job) }
+ context 'with feature flag :admin_jobs_filter_runner_type enabled' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:runner_types, :expected_jobs) do
+ nil | lazy do
+ [
+ successful_job,
+ successful_job_two,
+ failed_job,
+ pending_job,
+ successful_job_with_instance_runner
+ ]
+ end
+ %w[INSTANCE_TYPE] | lazy { [successful_job_with_instance_runner] }
+ %w[INSTANCE_TYPE GROUP_TYPE] | lazy { [successful_job_with_instance_runner] }
+ %w[PROJECT_TYPE] | lazy { [] }
+ end
+
+ with_them do
+ let(:args) do
+ {
+ runner_types: runner_types&.map { |type| Types::Ci::RunnerTypeEnum.coerce_isolated_input(type) }
+ }
+ end
+
+ it { is_expected.to match_array(expected_jobs) }
+ end
+ end
end
- context 'without statuses argument' do
- it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job, pending_job) }
+ context "with argument combination" do
+ let_it_be(:successful_job_with_instance_runner) do
+ create(
+ :ci_build,
+ :success,
+ name: 'successful_job_with_instance_runner',
+ runner: instance_runner
+ )
+ end
+
+ let_it_be(:running_job_with_group_runner) do
+ create(:ci_build, :running, name: 'running_job_with_instance_runner', runner: create(:ci_runner, :group))
+ end
+
+ context 'with feature flag :admin_jobs_filter_runner_type enabled' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:statuses, :runner_types, :expected_jobs) do
+ %w[SUCCESS] | %w[INSTANCE_TYPE] | lazy { [successful_job_with_instance_runner] }
+ %w[CANCELED] | %w[INSTANCE_TYPE] | lazy { [] }
+ %w[SUCCESS RUNNING] | %w[INSTANCE_TYPE GROUP_TYPE] | lazy do
+ [
+ successful_job_with_instance_runner,
+ running_job_with_group_runner
+ ]
+ end
+ end
+
+ with_them do
+ let(:args) do
+ {
+ statuses: statuses&.map { |status| Types::Ci::JobStatusEnum.coerce_isolated_input(status) },
+ runner_types: runner_types&.map { |type| Types::Ci::RunnerTypeEnum.coerce_isolated_input(type) }
+ }
+ end
+
+ it { is_expected.to contain_exactly(*expected_jobs) }
+ end
+ end
end
end
@@ -55,7 +132,9 @@ RSpec.describe Resolvers::Ci::AllJobsResolver, feature_category: :continuous_int
end
context 'with unauthorized user' do
- let(:current_user) { nil }
+ let_it_be(:unauth_user) { create(:user) }
+
+ let(:current_user) { unauth_user }
it { is_expected.to be_empty }
end
diff --git a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
index ff343f3f43d..fedae5c86a8 100644
--- a/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/group_runners_resolver_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
include GraphqlHelpers
describe '#resolve' do
- subject do
+ subject(:resolve_scope) do
resolve(described_class, obj: obj, ctx: { current_user: user }, args: args,
arg_style: :internal)
end
@@ -18,8 +18,10 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
# First, we can do a couple of basic real tests to verify common cases. That ensures that the code works.
context 'when user cannot see runners' do
- it 'returns no runners' do
- expect(subject.items.to_a).to eq([])
+ it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
+ resolve_scope
+ end
end
end
@@ -29,14 +31,16 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
end
it 'returns all the runners' do
- expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner)
+ expect(resolve_scope.items.to_a).to contain_exactly(
+ inactive_project_runner, offline_project_runner, group_runner, subgroup_runner
+ )
end
context 'with membership direct' do
let(:args) { { membership: :direct } }
it 'returns only direct runners' do
- expect(subject.items.to_a).to contain_exactly(group_runner)
+ expect(resolve_scope.items.to_a).to contain_exactly(group_runner)
end
end
end
@@ -46,7 +50,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
let(:obj) { nil }
it 'raises an error' do
- expect { subject }.to raise_error('Expected group missing')
+ expect { resolve_scope }.to raise_error('Expected group missing')
end
end
@@ -54,7 +58,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
let(:obj) { build(:project) }
it 'raises an error' do
- expect { subject }.to raise_error('Expected group missing')
+ expect { resolve_scope }.to raise_error('Expected group missing')
end
end
@@ -90,7 +94,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
allow(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
- expect(subject.items.to_a).to eq([:execute_return_value])
+ expect(resolve_scope.items.to_a).to eq([:execute_return_value])
end
end
end
diff --git a/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb b/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb
index 83435db2ea7..55a98106baf 100644
--- a/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/project_runners_resolver_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
include GraphqlHelpers
describe '#resolve' do
- subject do
+ subject(:resolve_scope) do
resolve(described_class, obj: obj, ctx: { current_user: user }, args: args,
arg_style: :internal)
end
@@ -17,8 +17,10 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
let(:args) { {} }
context 'when user cannot see runners' do
- it 'returns no runners' do
- expect(subject.items.to_a).to eq([])
+ it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
+ resolve_scope
+ end
end
end
@@ -30,7 +32,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
let(:available_runners) { [inactive_project_runner, offline_project_runner, group_runner, instance_runner] }
it 'returns all runners available to the project' do
- expect(subject.items.to_a).to match_array(available_runners)
+ expect(resolve_scope.items.to_a).to match_array(available_runners)
end
end
@@ -38,7 +40,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
let(:obj) { nil }
it 'raises an error' do
- expect { subject }.to raise_error('Expected project missing')
+ expect { resolve_scope }.to raise_error('Expected project missing')
end
end
@@ -46,7 +48,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
let(:obj) { build(:group) }
it 'raises an error' do
- expect { subject }.to raise_error('Expected project missing')
+ expect { resolve_scope }.to raise_error('Expected project missing')
end
end
@@ -79,7 +81,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
- expect(subject.items.to_a).to eq([:execute_return_value])
+ expect(resolve_scope.items.to_a).to contain_exactly(:execute_return_value)
end
end
end
diff --git a/spec/graphql/resolvers/ci/runners_resolver_spec.rb b/spec/graphql/resolvers/ci/runners_resolver_spec.rb
index 02fc7d28255..35831579799 100644
--- a/spec/graphql/resolvers/ci/runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/runners_resolver_spec.rb
@@ -20,8 +20,10 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
context 'when user cannot see runners' do
let(:user) { build(:user) }
- it 'returns no runners' do
- expect(subject.items.to_a).to eq([])
+ it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
+ resolve_scope
+ end
end
end
@@ -30,20 +32,26 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
context 'when admin mode setting is disabled', :do_not_mock_admin_mode_setting do
it 'returns all the runners' do
- expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner)
+ expect(resolve_scope.items.to_a).to contain_exactly(
+ inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner
+ )
end
end
context 'when admin mode setting is enabled' do
context 'when in admin mode', :enable_admin_mode do
it 'returns all the runners' do
- expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner)
+ expect(resolve_scope.items.to_a).to contain_exactly(
+ inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner
+ )
end
end
context 'when not in admin mode' do
- it 'returns no runners' do
- expect(subject.items.to_a).to eq([])
+ it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
+ resolve_scope
+ end
end
end
end
@@ -54,7 +62,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
let(:obj) { build(:project) }
it 'raises an error' do
- expect { subject }.to raise_error(a_string_including('Unexpected parent type'))
+ expect { resolve_scope }.to raise_error(a_string_including('Unexpected parent type'))
end
end
@@ -93,7 +101,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
- expect(subject.items.to_a).to eq([:execute_return_value])
+ expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value
end
end
@@ -116,7 +124,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
- expect(subject.items.to_a).to eq([:execute_return_value])
+ expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value
end
end
@@ -136,7 +144,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
- expect(subject.items.to_a).to eq([:execute_return_value])
+ expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value
end
end
@@ -153,7 +161,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
- expect(subject.items.to_a).to eq([:execute_return_value])
+ expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value
end
end
end
diff --git a/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb b/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb
index 75e0a816086..a4b957ef8e9 100644
--- a/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb
+++ b/spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb
@@ -24,22 +24,8 @@ RSpec.describe Resolvers::Metrics::Dashboards::AnnotationResolver, feature_categ
environment.project.add_developer(current_user)
end
- before do
- stub_feature_flags(remove_monitor_metrics: false)
- end
-
context 'with annotation records' do
- context 'when metrics dashboard feature is unavailable' do
- before do
- stub_feature_flags(remove_monitor_metrics: true)
- end
-
- it 'returns nothing' do
- expect(resolve_annotations).to be_nil
- end
- end
-
- it 'returns [] all the time' do
+ it 'returns empty all the time' do
expect(resolve_annotations).to be_empty
end
end
diff --git a/spec/graphql/resolvers/work_items_resolver_spec.rb b/spec/graphql/resolvers/work_items_resolver_spec.rb
index 6da62e3adb7..c856f990e7a 100644
--- a/spec/graphql/resolvers/work_items_resolver_spec.rb
+++ b/spec/graphql/resolvers/work_items_resolver_spec.rb
@@ -46,11 +46,6 @@ RSpec.describe Resolvers::WorkItemsResolver do
expect(resolve_items).to contain_exactly(item1, item2)
end
- it 'filters by state' do
- expect(resolve_items(state: 'opened')).to contain_exactly(item1)
- expect(resolve_items(state: 'closed')).to contain_exactly(item2)
- end
-
context 'when searching items' do
it_behaves_like 'graphql query for searching issuables' do
let_it_be(:parent) { project }
diff --git a/spec/graphql/types/base_argument_spec.rb b/spec/graphql/types/base_argument_spec.rb
index 8f5f2e08799..0ce6aa3667d 100644
--- a/spec/graphql/types/base_argument_spec.rb
+++ b/spec/graphql/types/base_argument_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::BaseArgument do
+RSpec.describe Types::BaseArgument, feature_category: :api do
let_it_be(:field) do
Types::BaseField.new(name: 'field', type: String, null: true)
end
diff --git a/spec/graphql/types/base_edge_spec.rb b/spec/graphql/types/base_edge_spec.rb
index b02ccbaffef..0cc0c838fac 100644
--- a/spec/graphql/types/base_edge_spec.rb
+++ b/spec/graphql/types/base_edge_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::BaseEdge do
+RSpec.describe Types::BaseEdge, feature_category: :api do
include GraphqlHelpers
let_it_be(:test_schema) do
diff --git a/spec/graphql/types/base_enum_spec.rb b/spec/graphql/types/base_enum_spec.rb
index 65a345052c7..db8fb877390 100644
--- a/spec/graphql/types/base_enum_spec.rb
+++ b/spec/graphql/types/base_enum_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::BaseEnum do
+RSpec.describe Types::BaseEnum, feature_category: :api do
describe '.from_rails_enum' do
let(:enum_type) { Class.new(described_class) }
let(:template) { "The name is '%{name}', James %{name}." }
diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb
index 9f8a8717efb..831d36950db 100644
--- a/spec/graphql/types/base_field_spec.rb
+++ b/spec/graphql/types/base_field_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::BaseField do
+RSpec.describe Types::BaseField, feature_category: :api do
describe 'authorized?' do
let(:object) { double }
let(:current_user) { nil }
diff --git a/spec/graphql/types/base_object_spec.rb b/spec/graphql/types/base_object_spec.rb
index 3c42c708187..af0639e84d3 100644
--- a/spec/graphql/types/base_object_spec.rb
+++ b/spec/graphql/types/base_object_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Types::BaseObject do
+RSpec.describe Types::BaseObject, feature_category: :api do
include GraphqlHelpers
describe 'scoping items' do
diff --git a/spec/graphql/types/blame/blame_type_spec.rb b/spec/graphql/types/blame/blame_type_spec.rb
new file mode 100644
index 00000000000..15846130edb
--- /dev/null
+++ b/spec/graphql/types/blame/blame_type_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Blame::BlameType, feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ specify { expect(described_class.graphql_name).to eq('Blame') }
+
+ specify do
+ expect(described_class).to have_graphql_fields(
+ :first_line,
+ :groups
+ ).at_least
+ end
+end
diff --git a/spec/graphql/types/blame/commit_data_type_spec.rb b/spec/graphql/types/blame/commit_data_type_spec.rb
new file mode 100644
index 00000000000..432f09bf8f7
--- /dev/null
+++ b/spec/graphql/types/blame/commit_data_type_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Blame::CommitDataType,
+ feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ specify { expect(described_class.graphql_name).to eq('CommitData') }
+
+ specify do
+ expect(described_class).to have_graphql_fields(
+ :age_map_class,
+ :author_avatar,
+ :commit_author_link,
+ :commit_link,
+ :project_blame_link,
+ :time_ago_tooltip
+ ).at_least
+ end
+end
diff --git a/spec/graphql/types/blame/groups_type_spec.rb b/spec/graphql/types/blame/groups_type_spec.rb
new file mode 100644
index 00000000000..9e870e1cdc0
--- /dev/null
+++ b/spec/graphql/types/blame/groups_type_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Blame::GroupsType, feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ specify { expect(described_class.graphql_name).to eq('Groups') }
+
+ specify do
+ expect(described_class).to have_graphql_fields(
+ :commit,
+ :commit_data,
+ :lineno,
+ :lines,
+ :span
+ ).at_least
+ end
+end
diff --git a/spec/graphql/types/ci/job_base_field_spec.rb b/spec/graphql/types/ci/job_base_field_spec.rb
new file mode 100644
index 00000000000..2d283ce854d
--- /dev/null
+++ b/spec/graphql/types/ci/job_base_field_spec.rb
@@ -0,0 +1,143 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::JobBaseField, feature_category: :runner_fleet do
+ describe 'authorized?' do
+ let_it_be(:current_user) { create(:user) }
+
+ let(:object) { double }
+ let(:ctx) { { current_user: current_user, current_field: current_field } }
+ let(:current_field) { instance_double(described_class, original_name: current_field_name.to_sym) }
+ let(:args) { {} }
+
+ subject(:field) do
+ described_class.new(name: current_field_name, type: GraphQL::Types::String, null: true, **args)
+ end
+
+ context 'when :job_field_authorization is specified' do
+ let(:ctx) { { current_user: current_user, current_field: current_field, job_field_authorization: :foo } }
+
+ context 'with public field' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:current_field_name) do
+ %i[allow_failure duration id kind status created_at finished_at queued_at queued_duration updated_at runner]
+ end
+
+ with_them do
+ it 'returns true without authorizing' do
+ is_expected.to be_authorized(object, nil, ctx)
+ end
+ end
+ end
+
+ context 'with private field' do
+ let(:current_field_name) { 'short_sha' }
+
+ context 'when permission is not allowed' do
+ it 'returns false' do
+ expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(false)
+
+ is_expected.not_to be_authorized(object, nil, ctx)
+ end
+ end
+
+ context 'when permission is allowed' do
+ it 'returns true' do
+ expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(true)
+
+ is_expected.to be_authorized(object, nil, ctx)
+ end
+ end
+ end
+ end
+
+ context 'when :job_field_authorization is not specified' do
+ let(:current_field_name) { 'status' }
+
+ it 'defaults to true' do
+ is_expected.to be_authorized(object, nil, ctx)
+ end
+
+ context 'when field is authorized' do
+ let(:args) { { authorize: :foo } }
+
+ it 'tests the field authorization' do
+ expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(false)
+
+ expect(field).not_to be_authorized(object, nil, ctx)
+ end
+
+ it 'tests the field authorization, if provided, when it succeeds' do
+ expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(true)
+
+ expect(field).to be_authorized(object, nil, ctx)
+ end
+ end
+
+ context 'with field resolver' do
+ let(:resolver) { Class.new }
+ let(:args) { { resolver_class: resolver } }
+
+ it 'only tests the resolver authorization if it authorizes_object?' do
+ is_expected.to be_authorized(object, nil, ctx)
+ end
+
+ context 'when resolver authorizes object' do
+ let(:resolver) do
+ Class.new do
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ authorizes_object!
+ end
+ end
+
+ it 'tests the resolver authorization, if provided' do
+ expect(resolver).to receive(:authorized?).with(object, ctx).and_return(false)
+
+ expect(field).not_to be_authorized(object, nil, ctx)
+ end
+
+ context 'when field is authorized' do
+ let(:args) { { authorize: :foo, resolver_class: resolver } }
+
+ it 'tests field authorization before resolver authorization, when field auth fails' do
+ expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(false)
+ expect(resolver).not_to receive(:authorized?)
+
+ expect(field).not_to be_authorized(object, nil, ctx)
+ end
+
+ it 'tests field authorization before resolver authorization, when field auth succeeds' do
+ expect(Ability).to receive(:allowed?).with(current_user, :foo, object).and_return(true)
+ expect(resolver).to receive(:authorized?).with(object, ctx).and_return(false)
+
+ expect(field).not_to be_authorized(object, nil, ctx)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe '#resolve' do
+ context 'when late_extensions is given' do
+ it 'registers the late extensions after the regular extensions' do
+ extension_class = Class.new(GraphQL::Schema::Field::ConnectionExtension)
+ field = described_class.new(name: 'private_field', type: GraphQL::Types::String.connection_type,
+ null: true, late_extensions: [extension_class])
+
+ expect(field.extensions.last.class).to be(extension_class)
+ end
+ end
+ end
+
+ include_examples 'Gitlab-style deprecations' do
+ def subject(args = {})
+ base_args = { name: 'private_field', type: GraphQL::Types::String, null: true }
+
+ described_class.new(**base_args.merge(args))
+ end
+ end
+end
diff --git a/spec/graphql/types/ci/job_kind_enum_spec.rb b/spec/graphql/types/ci/job_kind_enum_spec.rb
index b48d20b71e2..a09cd89ec8b 100644
--- a/spec/graphql/types/ci/job_kind_enum_spec.rb
+++ b/spec/graphql/types/ci/job_kind_enum_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['CiJobKind'] do
it 'exposes some job type values' do
expect(described_class.values.keys).to match_array(
- (%w[BRIDGE BUILD])
+ %w[BRIDGE BUILD]
)
end
end
diff --git a/spec/graphql/types/ci/job_trace_type_spec.rb b/spec/graphql/types/ci/job_trace_type_spec.rb
index 71803aa9ece..69123445b8b 100644
--- a/spec/graphql/types/ci/job_trace_type_spec.rb
+++ b/spec/graphql/types/ci/job_trace_type_spec.rb
@@ -13,15 +13,187 @@ RSpec.describe GitlabSchema.types['CiJobTrace'], feature_category: :continuous_i
expect(described_class).to have_graphql_fields(*expected_fields)
end
- it 'shows the correct trace contents' do
- job.trace.set('BUILD TRACE')
+ describe 'htmlSummary' do
+ subject(:resolved_field) { resolve_field(:html_summary, job.trace, args: args) }
- expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
- expect(trace).to receive(:html).with(last_lines: 10).and_call_original
+ context 'when trace contains few lines' do
+ before do
+ job.trace.set('BUILD TRACE')
+ end
+
+ context 'when last_lines is set to 10' do
+ let(:args) { { last_lines: 10 } }
+
+ it 'shows the correct trace contents' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 10, max_size: 16384).and_call_original
+ end
+
+ is_expected.to eq('<span>BUILD TRACE</span>')
+ end
+ end
+ end
+
+ context 'when trace contains many lines' do
+ before do
+ job.trace.set((1..200).map { |i| "Line #{i}" }.join("\n"))
+ end
+
+ def expected_html_trace_contents(line_count)
+ "<span>#{((200 - (line_count - 1))..200).map { |i| "Line #{i}" }.join('<br/>')}</span>"
+ end
+
+ context 'when last_lines is not set' do
+ let(:args) { {} }
+
+ it 'shows the last 10 lines of trace contents' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 10, max_size: 16384).and_call_original
+ end
+
+ is_expected.to eq expected_html_trace_contents(10)
+ end
+ end
+
+ context 'when last_lines is set to a negative number' do
+ let(:args) { { last_lines: -10 } }
+
+ it 'shows the last line of trace contents' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 1, max_size: 16384).and_call_original
+ end
+
+ is_expected.to eq expected_html_trace_contents(1)
+ end
+ end
+
+ context 'when last_lines is set to 10' do
+ let(:args) { { last_lines: 10 } }
+
+ it 'shows the correct trace contents' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 10, max_size: 16384).and_call_original
+ end
+
+ is_expected.to eq expected_html_trace_contents(10)
+ end
+ end
+
+ context 'when last_lines is set to 150' do
+ let(:args) { { last_lines: 150 } }
+
+ it 'shows the last 100 lines of trace contents' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 100, max_size: 16384).and_call_original
+ end
+
+ is_expected.to eq expected_html_trace_contents(100)
+ end
+ end
+ end
+
+ context 'when trace contains long lines' do
+ before do
+ # Creates lines of "aaaaaaaa...aaaaaaaa"
+ job.trace.set((1..20).map { (1..1024).map { "a" }.join("") }.join("\n"))
+ end
+
+ context 'when last_lines is lower than 16KB' do
+ let(:args) { {} }
+
+ it 'shows the whole lines' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 10, max_size: 16384).and_call_original
+ end
+
+ is_expected.to eq "<span>#{(1..10).map { (1..1024).map { 'a' }.join('') }.join('<br/>')}</span>"
+ end
+ end
+
+ context 'when last_lines is higher than 16KB' do
+ let(:args) { { last_lines: 20 } }
+
+ it 'shows only the latest byte' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 20, max_size: 16384).and_call_original
+ end
+
+ is_expected.to eq "<span>#{(1..1009).map { 'a' }.join('')}<br/>" \
+ "#{(1..15).map { (1..1024).map { 'a' }.join('') }.join('<br/>')}</span>"
+ end
+ end
+
+ context 'when FF graphql_job_trace_html_summary_max_size is disabled' do
+ before do
+ stub_feature_flags(graphql_job_trace_html_summary_max_size: false)
+ end
+
+ let(:args) { { last_lines: 20 } }
+
+ it 'does not limit the read size from the raw trace' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 20, max_size: nil).and_call_original
+ end
+
+ is_expected.to eq "<span>#{(1..20).map { (1..1024).map { 'a' }.join('') }.join('<br/>')}</span>"
+ end
+ end
+
+ context 'when trace is cut in middle of a line' do
+ let(:args) { {} }
+
+ before do
+ stub_const('Types::Ci::JobTraceType::MAX_SIZE_B', 1536)
+ end
+
+ it 'shows only the latest byte' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 10, max_size: 1536).and_call_original
+ end
+
+ is_expected.to eq "<span>#{(1..511).map { 'a' }.join('')}<br/>#{(1..1024).map { 'a' }.join('')}</span>"
+ end
+ end
+
+ context 'when trace is cut at end of a line' do
+ let(:args) { {} }
+
+ before do
+ stub_const('Types::Ci::JobTraceType::MAX_SIZE_B', 2050)
+ end
+
+ it 'shows only the latest byte' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 10, max_size: 2050).and_call_original
+ end
+
+ is_expected.to eq "<span><br/>#{(1..2).map { (1..1024).map { 'a' }.join('') }.join('<br/>')}</span>"
+ end
+ end
end
- resolved_field = resolve_field(:html_summary, job.trace)
+ context 'when trace contains multi-bytes UTF-8' do
+ before do
+ # Creates lines of 4 pound symbol, pound symbol is 2 byte wise in UTF-8
+ # Append an "a" (1 byte character) at the end to cut in the middle of UTF-8
+ job.trace.set((1..20).map { (1..4).map { "£" }.join("") }.join("\n"))
+ end
+
+ context 'when cut in the middle of a codepoint' do
+ before do
+ stub_const('Types::Ci::JobTraceType::MAX_SIZE_B', 5)
+ end
+
+ let(:args) { {} }
- expect(resolved_field).to eq("<span>BUILD TRACE</span>")
+ it 'shows a single "invalid utf-8" symbol' do
+ expect_next_instance_of(Gitlab::Ci::Trace) do |trace|
+ expect(trace).to receive(:html).with(last_lines: 10, max_size: 5).and_call_original
+ end
+
+ is_expected.to eq "<span>�££</span>"
+ end
+ end
+ end
end
end
diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb
index f31c0d5255c..a69c6f37ee1 100644
--- a/spec/graphql/types/ci/job_type_spec.rb
+++ b/spec/graphql/types/ci/job_type_spec.rb
@@ -32,6 +32,7 @@ RSpec.describe Types::Ci::JobType, feature_category: :continuous_integration do
needs
pipeline
playable
+ previousStageJobs
previousStageJobsOrNeeds
project
queued_at
diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb
index 6c4e68fba6b..d4d0eff9adb 100644
--- a/spec/graphql/types/issue_type_spec.rb
+++ b/spec/graphql/types/issue_type_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
confidential hidden discussion_locked upvotes downvotes merge_requests_count user_notes_count user_discussions_count web_path web_url relative_position
emails_disabled emails_enabled subscribed time_estimate total_time_spent human_time_estimate human_total_time_spent closed_at created_at updated_at task_completion_status
design_collection alert_management_alert alert_management_alerts severity current_user_todos moved moved_to
- closed_as_duplicate_of create_note_email timelogs project_id customer_relations_contacts escalation_status]
+ closed_as_duplicate_of create_note_email timelogs project_id customer_relations_contacts escalation_status external_author]
fields.each do |field_name|
expect(described_class).to have_graphql_field(field_name)
diff --git a/spec/graphql/types/label_type_spec.rb b/spec/graphql/types/label_type_spec.rb
index 427b5d2dcef..d68945b01e6 100644
--- a/spec/graphql/types/label_type_spec.rb
+++ b/spec/graphql/types/label_type_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe GitlabSchema.types['Label'] do
:description_html,
:title,
:color,
+ :lock_on_merge,
:text_color,
:created_at,
:updated_at
diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb
index bd271da55a9..9742908edf9 100644
--- a/spec/graphql/types/merge_request_type_spec.rb
+++ b/spec/graphql/types/merge_request_type_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe GitlabSchema.types['MergeRequest'], feature_category: :code_revie
commit_count current_user_todos conflicts auto_merge_enabled approved_by source_branch_protected
squash_on_merge available_auto_merge_strategies
has_ci mergeable commits committers commits_without_merge_commits squash security_auto_fix default_squash_commit_message
- auto_merge_strategy merge_user award_emoji prepared_at
+ auto_merge_strategy merge_user award_emoji prepared_at codequality_reports_comparer supports_lock_on_merge
]
expect(described_class).to have_graphql_fields(*expected_fields).at_least
diff --git a/spec/graphql/types/organizations/group_sort_enum_spec.rb b/spec/graphql/types/organizations/group_sort_enum_spec.rb
new file mode 100644
index 00000000000..57915d95c45
--- /dev/null
+++ b/spec/graphql/types/organizations/group_sort_enum_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['OrganizationGroupSort'], feature_category: :cell do
+ let(:sort_values) do
+ %w[
+ ID_ASC
+ ID_DESC
+ NAME_ASC
+ NAME_DESC
+ PATH_ASC
+ PATH_DESC
+ UPDATED_AT_ASC
+ UPDATED_AT_DESC
+ CREATED_AT_ASC
+ CREATED_AT_DESC
+ ]
+ end
+
+ specify { expect(described_class.graphql_name).to eq('OrganizationGroupSort') }
+
+ it 'exposes all the organization groups sort values' do
+ expect(described_class.values.keys).to include(*sort_values)
+ end
+end
diff --git a/spec/graphql/types/organizations/organization_type_spec.rb b/spec/graphql/types/organizations/organization_type_spec.rb
new file mode 100644
index 00000000000..26d7c10a715
--- /dev/null
+++ b/spec/graphql/types/organizations/organization_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['Organization'], feature_category: :cell do
+ let(:expected_fields) { %w[groups id name organization_users path] }
+
+ specify { expect(described_class.graphql_name).to eq('Organization') }
+ specify { expect(described_class).to require_graphql_authorizations(:read_organization) }
+ specify { expect(described_class).to have_graphql_fields(*expected_fields) }
+end
diff --git a/spec/graphql/types/organizations/organization_user_type_spec.rb b/spec/graphql/types/organizations/organization_user_type_spec.rb
new file mode 100644
index 00000000000..876080b0f15
--- /dev/null
+++ b/spec/graphql/types/organizations/organization_user_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['OrganizationUser'], feature_category: :cell do
+ let(:expected_fields) { %w[badges id user] }
+
+ specify { expect(described_class.graphql_name).to eq('OrganizationUser') }
+ specify { expect(described_class).to require_graphql_authorizations(:read_organization_user) }
+ specify { expect(described_class).to have_graphql_fields(*expected_fields) }
+end
diff --git a/spec/graphql/types/permission_types/work_item_spec.rb b/spec/graphql/types/permission_types/work_item_spec.rb
index 3ee42e2e3ad..cdbf94304de 100644
--- a/spec/graphql/types/permission_types/work_item_spec.rb
+++ b/spec/graphql/types/permission_types/work_item_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Types::PermissionTypes::WorkItem do
it do
expected_permissions = [
:read_work_item, :update_work_item, :delete_work_item, :admin_work_item,
- :admin_parent_link, :set_work_item_metadata, :create_note
+ :admin_parent_link, :set_work_item_metadata, :create_note, :admin_work_item_link
]
expected_permissions.each do |permission|
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index cd9a0642ae6..a20a4767bb5 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -892,22 +892,25 @@ RSpec.describe GitlabSchema.types['Project'] do
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
- before do
+ before_all do
fork_reporter.add_reporter(user)
fork_developer.add_developer(user)
fork_group_developer.group.add_developer(user)
+ fork_private.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end
it 'contains all forks' do
- expect(forks.count).to eq(5)
+ expect(forks.count).to eq(4)
end
context 'with minimum_access_level DEVELOPER' do
let(:minimum_access_level) { '(minimumAccessLevel: DEVELOPER)' }
it 'contains forks with developer access' do
- expect(forks).to contain_exactly(a_hash_including('fullPath' => fork_developer.full_path),
-a_hash_including('fullPath' => fork_group_developer.full_path))
+ expect(forks).to contain_exactly(
+ a_hash_including('fullPath' => fork_developer.full_path),
+ a_hash_including('fullPath' => fork_group_developer.full_path)
+ )
end
context 'when current user is not set' do
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index 100ecc94f35..8bda738751d 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -23,6 +23,16 @@ RSpec.describe GitlabSchema.types['Query'], feature_category: :shared do
end
end
+ describe 'organization field' do
+ subject { described_class.fields['organization'] }
+
+ it 'finds organization by path' do
+ is_expected.to have_graphql_arguments(:id)
+ is_expected.to have_graphql_type(Types::Organizations::OrganizationType)
+ is_expected.to have_graphql_resolver(Resolvers::Organizations::OrganizationResolver)
+ end
+ end
+
describe 'project field' do
subject { described_class.fields['project'] }
diff --git a/spec/graphql/types/repository/blob_type_spec.rb b/spec/graphql/types/repository/blob_type_spec.rb
index 9537fca7322..104093bd909 100644
--- a/spec/graphql/types/repository/blob_type_spec.rb
+++ b/spec/graphql/types/repository/blob_type_spec.rb
@@ -30,6 +30,7 @@ RSpec.describe Types::Repository::BlobType, feature_category: :source_code_manag
:gitpod_blob_url,
:find_file_path,
:blame_path,
+ :blame,
:history_path,
:permalink_path,
:environment_formatted_external_url,
diff --git a/spec/graphql/types/security/codequality_reports_comparer/degradation_type_spec.rb b/spec/graphql/types/security/codequality_reports_comparer/degradation_type_spec.rb
new file mode 100644
index 00000000000..9ae1b3fcf94
--- /dev/null
+++ b/spec/graphql/types/security/codequality_reports_comparer/degradation_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CodequalityReportsComparerReportDegradation'], feature_category: :code_quality do
+ specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparerReportDegradation') }
+
+ it 'has expected fields' do
+ expected_fields = %i[description fingerprint severity file_path line web_url engine_name]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/security/codequality_reports_comparer/report_type_spec.rb b/spec/graphql/types/security/codequality_reports_comparer/report_type_spec.rb
new file mode 100644
index 00000000000..a1788126f1b
--- /dev/null
+++ b/spec/graphql/types/security/codequality_reports_comparer/report_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CodequalityReportsComparerReport'], feature_category: :code_quality do
+ specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparerReport') }
+
+ it 'has expected fields' do
+ expected_fields = %i[status new_errors resolved_errors existing_errors summary]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/security/codequality_reports_comparer/status_enum_spec.rb b/spec/graphql/types/security/codequality_reports_comparer/status_enum_spec.rb
new file mode 100644
index 00000000000..6e5bdd1e91d
--- /dev/null
+++ b/spec/graphql/types/security/codequality_reports_comparer/status_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CodequalityReportsComparerReportStatus'], feature_category: :code_quality do
+ specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparerReportStatus') }
+
+ it 'exposes all codequality report status values' do
+ expect(described_class.values.keys).to contain_exactly('SUCCESS', 'FAILED', 'NOT_FOUND')
+ end
+end
diff --git a/spec/graphql/types/security/codequality_reports_comparer/summary_type_spec.rb b/spec/graphql/types/security/codequality_reports_comparer/summary_type_spec.rb
new file mode 100644
index 00000000000..41de93b27ad
--- /dev/null
+++ b/spec/graphql/types/security/codequality_reports_comparer/summary_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CodequalityReportsComparerReportSummary'], feature_category: :code_quality do
+ specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparerReportSummary') }
+
+ it 'has expected fields' do
+ expected_fields = %i[total resolved errored]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/security/codequality_reports_comparer_type_spec.rb b/spec/graphql/types/security/codequality_reports_comparer_type_spec.rb
new file mode 100644
index 00000000000..02f7a9d6925
--- /dev/null
+++ b/spec/graphql/types/security/codequality_reports_comparer_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CodequalityReportsComparer'], feature_category: :code_quality do
+ specify { expect(described_class.graphql_name).to eq('CodequalityReportsComparer') }
+
+ it 'has expected fields' do
+ expect(described_class).to have_graphql_fields(:report)
+ end
+end
diff --git a/spec/helpers/admin/abuse_reports_helper_spec.rb b/spec/helpers/admin/abuse_reports_helper_spec.rb
index 6a7630dc76a..d6f102682ba 100644
--- a/spec/helpers/admin/abuse_reports_helper_spec.rb
+++ b/spec/helpers/admin/abuse_reports_helper_spec.rb
@@ -25,10 +25,14 @@ RSpec.describe Admin::AbuseReportsHelper, feature_category: :insider_threat do
describe '#abuse_report_data' do
let(:report) { build_stubbed(:abuse_report) }
- subject(:data) { helper.abuse_report_data(report)[:abuse_report_data] }
+ subject(:data) { helper.abuse_report_data(report) }
it 'has the expected attributes' do
- expect(data).to include('user', 'reporter', 'report')
+ expect(data[:abuse_report_data]).to include('user', 'reporter', 'report')
+ end
+
+ it 'includes path to abuse reports list page' do
+ expect(data[:abuse_reports_list_path]).to eq admin_abuse_reports_path
end
end
end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index ad81c125055..757f832faa4 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -679,15 +679,75 @@ RSpec.describe ApplicationHelper do
end
describe '#page_class' do
+ let_it_be(:user) { build(:user) }
+
subject(:page_class) do
helper.page_class.flatten
end
- before do
- allow(helper).to receive(:current_user).and_return(nil)
+ describe 'with-header' do
+ using RSpec::Parameterized::TableSyntax
+
+ before do
+ allow(helper).to receive(:show_super_sidebar?).and_return(show_super_sidebar)
+ allow(helper).to receive(:current_user).and_return(current_user)
+ end
+
+ where(:show_super_sidebar, :current_user) do
+ true | nil
+ false | ref(:user)
+ false | nil
+ end
+
+ with_them do
+ it { is_expected.to include('with-header') }
+ end
+
+ context 'when with-header should not be shown' do
+ let(:show_super_sidebar) { true }
+ let(:current_user) { user }
+
+ it { is_expected.not_to include('with-header') }
+ end
end
- it { is_expected.not_to include('logged-out-marketing-header') }
+ describe 'with-top-bar' do
+ context 'when show_super_sidebar? is true' do
+ context 'when @hide_top_bar_padding is false' do
+ before do
+ allow(helper).to receive(:show_super_sidebar?).and_return(true)
+ helper.instance_variable_set(:@hide_top_bar_padding, false)
+ end
+
+ it { is_expected.to include('with-top-bar') }
+ end
+
+ context 'when @hide_top_bar_padding is true' do
+ before do
+ allow(helper).to receive(:show_super_sidebar?).and_return(true)
+ helper.instance_variable_set(:@hide_top_bar_padding, true)
+ end
+
+ it { is_expected.not_to include('with-top-bar') }
+ end
+ end
+
+ context 'when show_super_sidebar? is false' do
+ before do
+ allow(helper).to receive(:show_super_sidebar?).and_return(false)
+ end
+
+ it { is_expected.not_to include('with-top-bar') }
+ end
+ end
+
+ describe 'logged-out-marketing-header' do
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ end
+
+ it { is_expected.not_to include('logged-out-marketing-header') }
+ end
end
describe '#dispensable_render' do
@@ -891,4 +951,38 @@ RSpec.describe ApplicationHelper do
end
end
end
+
+ describe '#controller_full_path' do
+ let(:path) { 'some_path' }
+ let(:action) { 'show' }
+
+ before do
+ allow(helper.controller).to receive(:controller_path).and_return(path)
+ allow(helper.controller).to receive(:action_name).and_return(action)
+ end
+
+ context 'when is create action' do
+ let(:action) { 'create' }
+
+ it 'transforms to "new" path' do
+ expect(helper.controller_full_path).to eq("#{path}/new")
+ end
+ end
+
+ context 'when is update action' do
+ let(:action) { 'update' }
+
+ it 'transforms to "edit" path' do
+ expect(helper.controller_full_path).to eq("#{path}/edit")
+ end
+ end
+
+ context 'when is show action' do
+ let(:action) { 'show' }
+
+ it 'passes through' do
+ expect(helper.controller_full_path).to eq("#{path}/#{action}")
+ end
+ end
+ end
end
diff --git a/spec/helpers/artifacts_helper_spec.rb b/spec/helpers/artifacts_helper_spec.rb
index 7c577cbf11c..30f9421954e 100644
--- a/spec/helpers/artifacts_helper_spec.rb
+++ b/spec/helpers/artifacts_helper_spec.rb
@@ -17,8 +17,7 @@ RSpec.describe ArtifactsHelper, feature_category: :build_artifacts do
it 'returns expected data' do
expect(subject).to include({
project_path: project.full_path,
- project_id: project.id,
- artifacts_management_feedback_image_path: match_asset_path('illustrations/chat-bubble-sm.svg')
+ project_id: project.id
})
end
diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb
index a59f172061e..a7153ca4006 100644
--- a/spec/helpers/button_helper_spec.rb
+++ b/spec/helpers/button_helper_spec.rb
@@ -149,7 +149,7 @@ RSpec.describe ButtonHelper do
describe 'clipboard_button' do
include IconsHelper
- let(:user) { create(:user) }
+ let_it_be(:user) { create(:user) }
let(:project) { build_stubbed(:project) }
def element(data = {})
@@ -164,7 +164,9 @@ RSpec.describe ButtonHelper do
context 'with default options' do
context 'when no `text` attribute is not provided' do
it 'shows copy to clipboard button with default configuration and no text set to copy' do
- expect(element.attr('class')).to eq('btn btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm')
+ expect(element.attr('class')).to match('btn-sm')
+ expect(element.attr('class')).to match('btn-default')
+ expect(element.attr('class')).to match('btn-default-tertiary')
expect(element.attr('title')).to eq('Copy')
expect(element.attr('type')).to eq('button')
expect(element.attr('aria-label')).to eq('Copy')
@@ -174,9 +176,9 @@ RSpec.describe ButtonHelper do
expect(element.attr('data-container')).to eq('body')
expect(element.attr('data-clipboard-text')).to eq(nil)
expect(element.attr('itemprop')).to eq(nil)
- expect(element.inner_text).to eq("")
+ expect(element.inner_text.strip).to eq('')
- expect(element.to_html).to include sprite_icon('copy-to-clipboard', css_class: 'gl-icon')
+ expect(element.to_html).to match('svg#copy-to-clipboard')
end
end
@@ -195,7 +197,7 @@ RSpec.describe ButtonHelper do
context 'with `button_text` attribute provided' do
it 'shows copy to clipboard button with provided `button_text` as button label' do
- expect(element(button_text: 'Copy text').inner_text).to eq('Copy text')
+ expect(element(button_text: 'Copy text').inner_text.strip).to eq('Copy text')
end
it 'adds `gl-button-icon` class to icon' do
@@ -213,6 +215,92 @@ RSpec.describe ButtonHelper do
context 'with `hide_button_icon` attribute provided' do
it 'shows copy to clipboard button without tooltip support' do
+ expect(element(hide_button_icon: true).to_html).not_to match('svg#copy-to-clipboard')
+ end
+ end
+
+ context 'with `itemprop` attribute provided' do
+ it 'shows copy to clipboard button with `itemprop` attribute' do
+ expect(element(itemprop: 'identifier').attr('itemprop')).to eq('identifier')
+ end
+ end
+
+ context 'when variant option is provided' do
+ it 'inherits the correct ButtonComponent class' do
+ expect(element(variant: :confirm).attr('class')).to match('btn-confirm-tertiary')
+ end
+ end
+
+ context 'when category option is provided' do
+ it 'inherits the correct ButtonComponent class' do
+ expect(element(category: :secondary).attr('class')).to match('btn-default-secondary')
+ end
+ end
+
+ context 'when size option is provided' do
+ it 'inherits the correct ButtonComponent class' do
+ expect(element(size: :medium).attr('class')).to match('btn-md')
+ end
+ end
+ end
+
+ describe 'deprecated_clipboard_button' do
+ include IconsHelper
+
+ let(:user) { create(:user) }
+ let(:project) { build_stubbed(:project) }
+
+ def element(data = {})
+ element = helper.deprecated_clipboard_button(data)
+ Nokogiri::HTML::DocumentFragment.parse(element).first_element_child
+ end
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ context 'with default options' do
+ context 'when no `text` attribute is not provided' do
+ it 'shows copy to clipboard button with default configuration and no text set to copy' do
+ expect(element.attr('class')).to eq('btn btn-clipboard gl-button btn-default-tertiary btn-icon btn-sm')
+ expect(element.attr('title')).to eq('Copy')
+ expect(element.attr('type')).to eq('button')
+ expect(element.attr('aria-label')).to eq('Copy')
+ expect(element.attr('aria-live')).to eq('polite')
+ expect(element.attr('data-toggle')).to eq('tooltip')
+ expect(element.attr('data-placement')).to eq('bottom')
+ expect(element.attr('data-container')).to eq('body')
+ expect(element.attr('data-clipboard-text')).to eq(nil)
+ expect(element.attr('itemprop')).to eq(nil)
+ expect(element.inner_text).to eq("")
+
+ expect(element.to_html).to include sprite_icon('copy-to-clipboard', css_class: 'gl-icon')
+ end
+ end
+
+ context 'when `text` attribute is provided' do
+ it 'shows copy to clipboard button with provided `text` to copy' do
+ expect(element(text: 'Hello World!').attr('data-clipboard-text')).to eq('Hello World!')
+ end
+ end
+
+ context 'when `title` attribute is provided' do
+ it 'shows copy to clipboard button with provided `title` as tooltip' do
+ expect(element(title: 'Copy to my clipboard!').attr('aria-label')).to eq('Copy to my clipboard!')
+ end
+ end
+ end
+
+ context 'with `hide_tooltip` attribute provided' do
+ it 'shows copy to clipboard button without tooltip support' do
+ expect(element(hide_tooltip: true).attr('data-placement')).to eq(nil)
+ expect(element(hide_tooltip: true).attr('data-toggle')).to eq(nil)
+ expect(element(hide_tooltip: true).attr('data-container')).to eq(nil)
+ end
+ end
+
+ context 'with `hide_button_icon` attribute provided' do
+ it 'shows copy to clipboard button without tooltip support' do
expect(element(hide_button_icon: true).to_html).not_to include sprite_icon('duplicate')
end
end
diff --git a/spec/helpers/ci/status_helper_spec.rb b/spec/helpers/ci/status_helper_spec.rb
index 0af396149ef..66c821df8f1 100644
--- a/spec/helpers/ci/status_helper_spec.rb
+++ b/spec/helpers/ci/status_helper_spec.rb
@@ -20,29 +20,6 @@ RSpec.describe Ci::StatusHelper do
end
end
- describe '#ci_text_for_status' do
- context 'when status is manual' do
- it 'changes the status to blocked' do
- expect(helper.ci_text_for_status('manual'))
- .to eq 'blocked'
- end
- end
-
- context 'when status is success' do
- it 'changes the status to passed' do
- expect(helper.ci_text_for_status('success'))
- .to eq 'passed'
- end
- end
-
- context 'when status is something else' do
- it 'returns status unchanged' do
- expect(helper.ci_text_for_status('some-status'))
- .to eq 'some-status'
- end
- end
- end
-
describe "#pipeline_status_cache_key" do
it "builds a cache key for pipeline status" do
pipeline_status = Gitlab::Cache::Ci::ProjectPipelineStatus.new(
diff --git a/spec/helpers/environment_helper_spec.rb b/spec/helpers/environment_helper_spec.rb
index b9316e46d9d..1383bf34881 100644
--- a/spec/helpers/environment_helper_spec.rb
+++ b/spec/helpers/environment_helper_spec.rb
@@ -22,6 +22,15 @@ RSpec.describe EnvironmentHelper, feature_category: :environment_management do
end
end
+ context 'when deploying from a bridge' do
+ it 'renders a span tag' do
+ deploy = build(:deployment, deployable: create(:ci_bridge), status: :success)
+ html = helper.render_deployment_status(deploy)
+
+ expect(html).to have_css('span.ci-status.ci-success')
+ end
+ end
+
context 'for a blocked deployment' do
subject { helper.render_deployment_status(deployment) }
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index c0c729f2b67..6624404bc49 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -34,12 +34,10 @@ RSpec.describe EnvironmentsHelper, feature_category: :environment_management do
'project_path' => project_path(project),
'tags_path' => project_tags_path(project),
'has_metrics' => environment.has_metrics?.to_s,
- 'external_dashboard_url' => nil,
'environment_state' => environment.state,
'custom_metrics_path' => project_prometheus_metrics_path(project),
'validate_query_path' => validate_query_project_prometheus_metrics_path(project),
'custom_metrics_available' => 'true',
- 'custom_dashboard_base_path' => Gitlab::Metrics::Dashboard::RepoDashboardFinder::DASHBOARD_ROOT,
'operations_settings_path' => project_settings_operations_path(project),
'can_access_operations_settings' => 'true'
)
@@ -59,16 +57,6 @@ RSpec.describe EnvironmentsHelper, feature_category: :environment_management do
end
end
- context 'with metrics_setting' do
- before do
- create(:project_metrics_setting, project: project, external_dashboard_url: 'http://gitlab.com')
- end
-
- it 'adds external_dashboard_url' do
- expect(metrics_data['external_dashboard_url']).to eq('http://gitlab.com')
- end
- end
-
context 'when the environment is not available' do
before do
environment.stop
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index 2f1682e9194..106184b5e4a 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -53,6 +53,13 @@ RSpec.describe IconsHelper do
.to eq "<svg class=\"s72 icon-danger\" data-testid=\"#{icon_name}-icon\"><use href=\"#{icons_path}##{icon_name}\"></use></svg>"
end
+ it 'returns a file icon' do
+ file_icons_path = ActionController::Base.helpers.image_path("file_icons/file_icons.svg")
+
+ expect(sprite_icon('coffee', file_icon: true).to_s)
+ .to eq "<svg class=\"s#{IconsHelper::DEFAULT_ICON_SIZE}\" data-testid=\"coffee-icon\"><use href=\"#{file_icons_path}#coffee\"></use></svg>"
+ end
+
describe 'non existing icon' do
non_existing = 'non_existing_icon_sprite'
@@ -60,20 +67,24 @@ RSpec.describe IconsHelper do
stub_rails_env('development')
expect { sprite_icon(non_existing) }.to raise_error(ArgumentError, /is not a known icon/)
+ expect { sprite_icon(non_existing, file_icon: true) }.to raise_error(ArgumentError, /is not a known icon/)
end
it 'raises in test mode' do
stub_rails_env('test')
expect { sprite_icon(non_existing) }.to raise_error(ArgumentError, /is not a known icon/)
+ expect { sprite_icon(non_existing, file_icon: true) }.to raise_error(ArgumentError, /is not a known icon/)
end
it 'does not raise in production mode' do
stub_rails_env('production')
expect_file_not_to_read(Rails.root.join('node_modules/@gitlab/svgs/dist/icons.json'))
+ expect_file_not_to_read(Rails.root.join('node_modules/@gitlab/svgs/dist/file_icons/file_icons.json'))
expect { sprite_icon(non_existing) }.not_to raise_error
+ expect { sprite_icon(non_existing, file_icon: true) }.not_to raise_error
end
end
end
diff --git a/spec/helpers/integrations_helper_spec.rb b/spec/helpers/integrations_helper_spec.rb
index 6c5a489e664..7c626743f3a 100644
--- a/spec/helpers/integrations_helper_spec.rb
+++ b/spec/helpers/integrations_helper_spec.rb
@@ -172,6 +172,26 @@ RSpec.describe IntegrationsHelper, feature_category: :integrations do
it { is_expected.to include(*fields) }
end
+ describe '#serialize_integration' do
+ subject { helper.send(:serialize_integration, integration) }
+
+ let(:integration) { build(:jenkins_integration) }
+
+ it 'serializes the integration' do
+ is_expected.to match(a_hash_including(
+ id: nil,
+ active: true,
+ configured: false,
+ title: 'Jenkins',
+ description: _('Run CI/CD pipelines with Jenkins.'),
+ updated_at: nil,
+ edit_path: '/admin/application_settings/integrations/jenkins/edit',
+ name: 'jenkins',
+ icon: nil
+ ))
+ end
+ end
+
describe '#scoped_reset_integration_path' do
let(:integration) { build_stubbed(:jira_integration) }
let(:group) { nil }
diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb
index abf8b65dc1e..7cf9ffa0621 100644
--- a/spec/helpers/invite_members_helper_spec.rb
+++ b/spec/helpers/invite_members_helper_spec.rb
@@ -65,62 +65,6 @@ RSpec.describe InviteMembersHelper do
expect(helper.common_invite_modal_dataset(project)).to include(attributes)
end
-
- context 'with tasks_to_be_done' do
- using RSpec::Parameterized::TableSyntax
-
- subject(:output) { helper.common_invite_modal_dataset(source) }
-
- shared_examples_for 'including the tasks to be done attributes' do
- it 'includes the tasks to be done attributes when expected' do
- if expected?
- expect(output[:tasks_to_be_done_options]).to eq(
- [
- { value: :code, text: 'Create/import code into a project (repository)' },
- { value: :ci, text: 'Set up CI/CD pipelines to build, test, deploy, and monitor code' },
- { value: :issues, text: 'Create/import issues (tickets) to collaborate on ideas and plan work' }
- ].to_json
- )
- expect(output[:projects]).to eq([{ id: project.id, title: project.title }].to_json)
- expect(output[:new_project_path]).to eq(
- source.is_a?(Project) ? '' : new_project_path(namespace_id: group.id)
- )
- else
- expect(output[:tasks_to_be_done_options]).to be_nil
- expect(output[:projects]).to be_nil
- expect(output[:new_project_path]).to be_nil
- end
- end
- end
-
- context 'when inviting members for tasks' do
- where(:open_modal_param?, :logged_in?, :expected?) do
- true | true | true
- true | false | false
- false | true | false
- false | false | false
- end
-
- with_them do
- before do
- allow(helper).to receive(:current_user).and_return(developer) if logged_in?
- allow(helper).to receive(:params).and_return({ open_modal: 'invite_members_for_task' }) if open_modal_param?
- end
-
- context 'when the source is a project' do
- let_it_be(:source) { project }
-
- it_behaves_like 'including the tasks to be done attributes'
- end
-
- context 'when the source is a group' do
- let_it_be(:source) { group }
-
- it_behaves_like 'including the tasks to be done attributes'
- end
- end
- end
- end
end
context 'with project' do
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 7b5537c54cc..9fe820ccae9 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -134,109 +134,6 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
end
- describe '#issuable_meta', time_travel_to: '2022-08-05 00:00:00 +0000' do
- let(:user) { create(:user) }
-
- let_it_be(:project) { create(:project) }
-
- describe 'Issuable created status text' do
- subject { helper.issuable_meta(issuable, project) }
-
- context 'when issuable is a work item and flag is off' do
- using RSpec::Parameterized::TableSyntax
-
- before do
- stub_feature_flags(work_items: false)
- end
-
- where(:issuable_type, :text) do
- :issue | 'Issue created Aug 05, 2022 by'
- :incident | 'Incident created Aug 05, 2022 by'
- end
-
- let(:issuable) { build_stubbed(:work_item, issuable_type, created_at: Date.current) }
-
- with_them do
- it { is_expected.to have_content(text) }
- end
- end
-
- context 'when issuable is a work item and flag is on' do
- using RSpec::Parameterized::TableSyntax
-
- where(:issuable_type, :text) do
- :issue | 'Issue created Aug 05, 2022 by'
- :incident | 'Incident created Aug 05, 2022 by'
- end
-
- let(:issuable) { build_stubbed(:work_item, issuable_type, created_at: Date.current) }
-
- with_them do
- it { is_expected.to have_content(text) }
- end
- end
-
- context 'when issuable is not a work item' do
- let(:issuable) { build_stubbed(:merge_request, created_at: Date.current) }
-
- it { is_expected.to have_content('Created Aug 05, 2022') }
- end
- end
-
- describe 'author status' do
- let(:issuable) { build(:merge_request, source_project: project, author: user, created_at: '2020-01-30') }
-
- it 'displays an emoji if the user status is set' do
- user.status = UserStatus.new(message: 'lol')
- content = helper.issuable_meta(issuable, project)
- expect(content).to match('<span class="user-status-emoji has-tooltip" title="lol" data-html="true" data-placement="top">')
- expect(content).to match('<gl-emoji title="speech balloon" data-name="speech_balloon" data-unicode-version="6.0">')
- end
-
- it 'does not displays an emoji if the user status is not set' do
- user.status = UserStatus.new
- content = helper.issuable_meta(issuable, project)
- expect(content).not_to match('class="user-status-emoji has-tooltip"')
- 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
let_it_be(:user) { create(:user) }
@@ -348,80 +245,74 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
end
- describe '#updated_at_by' do
+ describe '#issuable_initial_data' do
let(:user) { create(:user) }
- let(:unedited_issuable) { create(:issue) }
- let(:edited_issuable) { create(:issue, last_edited_by: user, created_at: 3.days.ago, updated_at: 1.day.ago, last_edited_at: 2.days.ago) }
- let(:edited_updated_at_by) do
- {
- updatedAt: edited_issuable.last_edited_at.to_time.iso8601,
- updatedBy: {
- name: user.name,
- path: user_path(user)
- }
- }
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ allow(helper).to receive(:can?).and_return(true)
+ stub_commonmark_sourcepos_disabled
end
- it { expect(helper.updated_at_by(unedited_issuable)).to eq({}) }
- it { expect(helper.updated_at_by(edited_issuable)).to eq(edited_updated_at_by) }
+ context 'when issue' do
+ it 'returns the correct data for an issue' do
+ issue = create(:issue, author: user, description: 'issue text')
+ @project = issue.project
+
+ base_data = {
+ endpoint: "/#{@project.full_path}/-/issues/#{issue.iid}",
+ updateEndpoint: "/#{@project.full_path}/-/issues/#{issue.iid}.json",
+ canUpdate: true,
+ canDestroy: true,
+ issuableRef: "##{issue.iid}",
+ markdownPreviewPath: "/#{@project.full_path}/preview_markdown?target_id=#{issue.iid}&target_type=Issue",
+ markdownDocsPath: '/help/user/markdown',
+ lockVersion: issue.lock_version,
+ state: issue.state,
+ issuableTemplateNamesPath: template_names_path(@project, issue),
+ initialTitleHtml: issue.title,
+ initialTitleText: issue.title,
+ initialDescriptionHtml: '<p dir="auto">issue text</p>',
+ initialDescriptionText: 'issue text',
+ initialTaskCompletionStatus: { completed_count: 0, count: 0 }
+ }
- context 'when updated by a deleted user' do
- let(:edited_updated_at_by) do
- {
- updatedAt: edited_issuable.last_edited_at.to_time.iso8601,
- updatedBy: {
- name: User.ghost.name,
- path: user_path(User.ghost)
- }
+ issue_only_data = {
+ canCreateIncident: true,
+ fullPath: issue.project.full_path,
+ iid: issue.iid,
+ issuableId: issue.id,
+ issueType: 'issue',
+ isHidden: false,
+ sentryIssueIdentifier: nil,
+ zoomMeetingUrl: nil
}
- end
- before do
- user.destroy!
- end
+ issue_header_data = {
+ authorId: issue.author.id,
+ authorName: issue.author.name,
+ authorUsername: issue.author.username,
+ authorWebUrl: url_for(user_path(issue.author)),
+ createdAt: issue.created_at.to_time.iso8601,
+ isFirstContribution: issue.first_contribution?,
+ serviceDeskReplyTo: nil
+ }
- it 'returns "Ghost user" as edited_by' do
- expect(helper.updated_at_by(edited_issuable.reload)).to eq(edited_updated_at_by)
- end
- end
- end
+ work_items_data = {
+ registerPath: '/users/sign_up?redirect_to_referer=yes',
+ signInPath: '/users/sign_in?redirect_to_referer=yes'
+ }
- describe '#issuable_initial_data' do
- let(:user) { create(:user) }
+ path_data = {
+ projectPath: @project.path,
+ projectId: @project.id,
+ projectNamespace: @project.namespace.path
+ }
- before do
- allow(helper).to receive(:current_user).and_return(user)
- allow(helper).to receive(:can?).and_return(true)
- stub_commonmark_sourcepos_disabled
- end
+ expected = base_data.merge(issue_only_data, issue_header_data, work_items_data, path_data)
- it 'returns the correct data for an issue' do
- issue = create(:issue, author: user, description: 'issue text')
- @project = issue.project
-
- expected_data = {
- endpoint: "/#{@project.full_path}/-/issues/#{issue.iid}",
- updateEndpoint: "/#{@project.full_path}/-/issues/#{issue.iid}.json",
- canUpdate: true,
- canDestroy: true,
- issuableRef: "##{issue.iid}",
- markdownPreviewPath: "/#{@project.full_path}/preview_markdown?target_id=#{issue.iid}&target_type=Issue",
- markdownDocsPath: '/help/user/markdown',
- lockVersion: issue.lock_version,
- projectPath: @project.path,
- projectId: @project.id,
- projectNamespace: @project.namespace.path,
- state: issue.state,
- initialTitleHtml: issue.title,
- initialTitleText: issue.title,
- initialDescriptionHtml: '<p dir="auto">issue text</p>',
- initialDescriptionText: 'issue text',
- initialTaskCompletionStatus: { completed_count: 0, count: 0 },
- issueType: 'issue',
- iid: issue.iid.to_s,
- isHidden: false
- }
- expect(helper.issuable_initial_data(issue)).to match(hash_including(expected_data))
+ expect(helper.issuable_initial_data(issue)).to include(expected)
+ end
end
context 'for incident tab' do
@@ -453,6 +344,46 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
end
+ context 'when edited' do
+ it 'contains edited metadata' do
+ edited_issuable = create(:issue, author: user, description: 'issue text', last_edited_by: user, created_at: 3.days.ago, updated_at: 1.day.ago, last_edited_at: 2.days.ago)
+ @project = edited_issuable.project
+
+ expected = {
+ updatedAt: edited_issuable.last_edited_at.to_time.iso8601,
+ updatedBy: {
+ name: user.name,
+ path: user_path(user)
+ }
+ }
+
+ expect(helper.issuable_initial_data(edited_issuable)).to include(expected)
+ end
+
+ context 'when updated by a deleted user' do
+ let(:destroyed_user) { create(:user) }
+
+ before do
+ destroyed_user.destroy!
+ end
+
+ it 'returns "Ghost user" for updated by data' do
+ edited_issuable = create(:issue, author: user, description: 'issue text', last_edited_by: destroyed_user, created_at: 3.days.ago, updated_at: 1.day.ago, last_edited_at: 2.days.ago)
+ @project = edited_issuable.project
+
+ expected = {
+ updatedAt: edited_issuable.last_edited_at.to_time.iso8601,
+ updatedBy: {
+ name: Users::Internal.ghost.name,
+ path: user_path(Users::Internal.ghost)
+ }
+ }
+
+ expect(helper.issuable_initial_data(edited_issuable.reload)).to include(expected)
+ end
+ end
+ end
+
describe '#sentryIssueIdentifier' do
let(:issue) { create(:issue, author: user) }
@@ -613,38 +544,6 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
end
- describe '#reviewer_sidebar_data' do
- let(:user) { create(:user) }
-
- subject { helper.reviewer_sidebar_data(user, merge_request: merge_request) }
-
- context 'without merge_request' do
- let(:merge_request) { nil }
-
- it 'returns hash of reviewer data' do
- is_expected.to eql({
- avatar_url: user.avatar_url,
- name: user.name,
- username: user.username
- })
- end
- end
-
- context 'with merge_request' do
- let(:merge_request) { build(:merge_request) }
-
- where(can_merge: [true, false])
-
- with_them do
- before do
- allow(merge_request).to receive(:can_be_merged_by?).and_return(can_merge)
- end
-
- it { is_expected.to include({ can_merge: can_merge }) }
- end
- end
- end
-
describe '#issuable_squash_option?' do
using RSpec::Parameterized::TableSyntax
@@ -704,34 +603,6 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
end
end
- describe '#issuable_display_type' do
- using RSpec::Parameterized::TableSyntax
-
- where(:issuable_type, :issuable_display_type) do
- :issue | 'issue'
- :incident | 'incident'
- :merge_request | 'merge request'
- end
-
- with_them do
- let(:issuable) { build_stubbed(issuable_type) }
-
- subject { helper.issuable_display_type(issuable) }
-
- it { is_expected.to eq(issuable_display_type) }
- end
- end
-
- describe '#sidebar_milestone_tooltip_label' do
- it 'escapes HTML in the milestone title' do
- milestone = build(:milestone, title: '&lt;img onerror=alert(1)&gt;', due_date: Date.new(2022, 6, 26))
-
- expect(helper.sidebar_milestone_tooltip_label(milestone)).to eq(
- '&lt;img onerror=alert(1)&gt;<br/>Jun 26, 2022 (<strong>Past due</strong>)'
- )
- end
- end
-
describe '#issuable_type_selector_data' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 0cde9aeac8d..72fa264698d 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe IssuesHelper do
+RSpec.describe IssuesHelper, feature_category: :team_planning do
include Features::MergeRequestHelpers
let_it_be(:project) { create(:project) }
@@ -136,86 +136,11 @@ RSpec.describe IssuesHelper do
end
end
- describe '#issue_closed_link' do
- let(:new_issue) { create(:issue, project: project) }
- let(:guest) { create(:user) }
-
- before do
- allow(helper).to receive(:can?) do |*args|
- Ability.allowed?(*args)
- end
- end
-
- shared_examples 'successfully displays link to issue and with css class' do |action|
- it 'returns link' do
- link = "<a class=\"#{css_class}\" href=\"/#{new_issue.project.full_path}/-/issues/#{new_issue.iid}\">(#{action})</a>"
-
- expect(helper.issue_closed_link(issue, user, css_class: css_class)).to match(link)
- end
- end
-
- shared_examples 'does not display link' do
- it 'returns nil' do
- expect(helper.issue_closed_link(issue, user)).to be_nil
- end
- end
-
- context 'with linked issue' do
- context 'with moved issue' do
- before do
- issue.update!(moved_to: new_issue)
- end
-
- context 'when user has permission to see new issue' do
- let(:user) { project.owner }
- let(:css_class) { 'text-white text-underline' }
-
- it_behaves_like 'successfully displays link to issue and with css class', 'moved'
- end
-
- context 'when user has no permission to see new issue' do
- let(:user) { guest }
-
- it_behaves_like 'does not display link'
- end
- end
-
- context 'with duplicated issue' do
- before do
- issue.update!(duplicated_to: new_issue)
- end
-
- context 'when user has permission to see new issue' do
- let(:user) { project.owner }
- let(:css_class) { 'text-white text-underline' }
-
- it_behaves_like 'successfully displays link to issue and with css class', 'duplicated'
- end
-
- context 'when user has no permission to see new issue' do
- let(:user) { guest }
-
- it_behaves_like 'does not display link'
- end
- end
- end
-
- context 'without linked issue' do
- let(:user) { project.owner }
-
- before do
- issue.update!(moved_to: nil, duplicated_to: nil)
- end
-
- it_behaves_like 'does not display link'
- end
- end
-
describe '#show_moved_service_desk_issue_warning?' do
let(:project1) { create(:project, service_desk_enabled: true) }
let(:project2) { create(:project, service_desk_enabled: true) }
- let!(:old_issue) { create(:issue, author: User.support_bot, project: project1) }
- let!(:new_issue) { create(:issue, author: User.support_bot, project: project2) }
+ let!(:old_issue) { create(:issue, author: Users::Internal.support_bot, project: project1) }
+ let!(:new_issue) { create(:issue, author: Users::Internal.support_bot, project: project2) }
before do
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?) { true }
@@ -249,14 +174,13 @@ RSpec.describe IssuesHelper do
it 'returns expected result' do
expected = {
can_create_issue: 'true',
+ can_create_incident: 'true',
can_destroy_issue: 'true',
can_reopen_issue: 'true',
can_report_spam: 'false',
can_update_issue: 'true',
- iid: issue.iid,
is_issue_author: 'false',
issue_path: issue_path(issue),
- issue_type: 'issue',
new_issue_path: new_project_issue_path(project, { add_related_issue: issue.iid }),
project_path: project.full_path,
report_abuse_path: add_category_abuse_reports_path,
diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb
index 005fce1730f..68a12d8dbf7 100644
--- a/spec/helpers/members_helper_spec.rb
+++ b/spec/helpers/members_helper_spec.rb
@@ -69,12 +69,6 @@ RSpec.describe MembersHelper do
it { expect(leave_confirmation_message(group)).to eq "Are you sure you want to leave the \"#{group.name}\" group?" }
end
- describe '#localized_tasks_to_be_done_choices' do
- it 'has a translation for all `TASKS_TO_BE_DONE` keys' do
- expect(localized_tasks_to_be_done_choices).to include(*MemberTask::TASKS.keys)
- end
- end
-
describe '#member_request_access_link' do
let(:project) { create(:project) }
let(:group) { create(:group) }
diff --git a/spec/helpers/nav/new_dropdown_helper_spec.rb b/spec/helpers/nav/new_dropdown_helper_spec.rb
index 4ec120d152b..47f23c4fa21 100644
--- a/spec/helpers/nav/new_dropdown_helper_spec.rb
+++ b/spec/helpers/nav/new_dropdown_helper_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Nav::NewDropdownHelper, feature_category: :navigation do
partial: partial,
component: 'invite_members',
data: {
- trigger_source: 'top-nav',
+ trigger_source: 'top_nav',
trigger_element: 'text-emoji'
}
)
diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb
index 4b83561b265..950d8b77d01 100644
--- a/spec/helpers/nav_helper_spec.rb
+++ b/spec/helpers/nav_helper_spec.rb
@@ -144,15 +144,14 @@ RSpec.describe NavHelper, feature_category: :navigation do
context 'when user has not interacted with the new nav toggle yet' do
let(:user_preference) { nil }
- specify { expect(subject).to eq false }
+ specify { expect(subject).to eq true }
- context 'when the user was enrolled into the new nav via a special feature flag' do
+ context 'when the user was not enrolled into the new nav via a special feature flag' do
before do
- # this ff is disabled in globally to keep tests of the old nav working
- stub_feature_flags(super_sidebar_nav_enrolled: true)
+ stub_feature_flags(super_sidebar_nav_enrolled: false)
end
- specify { expect(subject).to eq true }
+ specify { expect(subject).to eq false }
end
end
diff --git a/spec/helpers/organizations/organization_helper_spec.rb b/spec/helpers/organizations/organization_helper_spec.rb
new file mode 100644
index 00000000000..ec99d928059
--- /dev/null
+++ b/spec/helpers/organizations/organization_helper_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Organizations::OrganizationHelper, feature_category: :cell do
+ let_it_be(:organization) { build_stubbed(:organization) }
+ let_it_be(:new_group_path) { '/groups/new' }
+ let_it_be(:new_project_path) { '/projects/new' }
+ let_it_be(:groups_empty_state_svg_path) { 'illustrations/empty-state/empty-groups-md.svg' }
+ let_it_be(:projects_empty_state_svg_path) { 'illustrations/empty-state/empty-projects-md.svg' }
+
+ before do
+ allow(helper).to receive(:new_group_path).and_return(new_group_path)
+ allow(helper).to receive(:new_project_path).and_return(new_project_path)
+ allow(helper).to receive(:image_path).with(groups_empty_state_svg_path).and_return(groups_empty_state_svg_path)
+ allow(helper).to receive(:image_path).with(projects_empty_state_svg_path).and_return(projects_empty_state_svg_path)
+ end
+
+ describe '#organization_show_app_data' do
+ before do
+ allow(helper).to receive(:groups_and_projects_organization_path)
+ .with(organization)
+ .and_return('/-/organizations/default/groups_and_projects')
+ end
+
+ it 'returns expected json' do
+ expect(
+ Gitlab::Json.parse(
+ helper.organization_show_app_data(organization)
+ )
+ ).to eq(
+ {
+ 'organization' => { 'id' => organization.id, 'name' => organization.name },
+ 'groups_and_projects_organization_path' => '/-/organizations/default/groups_and_projects',
+ 'new_group_path' => new_group_path,
+ 'new_project_path' => new_project_path,
+ 'groups_empty_state_svg_path' => groups_empty_state_svg_path,
+ 'projects_empty_state_svg_path' => projects_empty_state_svg_path,
+ 'association_counts' => {
+ 'groups' => 10,
+ 'projects' => 5,
+ 'users' => 1050
+ }
+ }
+ )
+ end
+ end
+
+ describe '#organization_groups_and_projects_app_data' do
+ it 'returns expected json' do
+ expect(
+ Gitlab::Json.parse(
+ helper.organization_groups_and_projects_app_data
+ )
+ ).to eq(
+ {
+ 'new_group_path' => new_group_path,
+ 'new_project_path' => new_project_path,
+ 'groups_empty_state_svg_path' => groups_empty_state_svg_path,
+ 'projects_empty_state_svg_path' => projects_empty_state_svg_path
+ }
+ )
+ end
+ end
+end
diff --git a/spec/helpers/projects/observability_helper_spec.rb b/spec/helpers/projects/observability_helper_spec.rb
deleted file mode 100644
index 0f47cdb8be2..00000000000
--- a/spec/helpers/projects/observability_helper_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require 'json'
-
-RSpec.describe Projects::ObservabilityHelper, type: :helper, feature_category: :tracing do
- include Gitlab::Routing.url_helpers
-
- let_it_be(:group) { build_stubbed(:group) }
- let_it_be(:project) { build_stubbed(:project, group: group) }
-
- describe '#observability_tracing_view_model' do
- it 'generates the correct JSON' do
- expected_json = {
- tracingUrl: Gitlab::Observability.tracing_url(project),
- provisioningUrl: Gitlab::Observability.provisioning_url(project),
- oauthUrl: Gitlab::Observability.oauth_url
- }.to_json
-
- expect(helper.observability_tracing_view_model(project)).to eq(expected_json)
- end
- end
-
- describe '#observability_tracing_details_model' do
- it 'generates the correct JSON' do
- expected_json = {
- tracingIndexUrl: namespace_project_tracing_index_path(project.group, project),
- traceId: "trace-id",
- tracingUrl: Gitlab::Observability.tracing_url(project),
- provisioningUrl: Gitlab::Observability.provisioning_url(project),
- oauthUrl: Gitlab::Observability.oauth_url
- }.to_json
-
- expect(helper.observability_tracing_details_model(project, "trace-id")).to eq(expected_json)
- end
- end
-end
diff --git a/spec/helpers/projects/pipeline_helper_spec.rb b/spec/helpers/projects/pipeline_helper_spec.rb
index baeafe6b7e7..16c9b8a85ec 100644
--- a/spec/helpers/projects/pipeline_helper_spec.rb
+++ b/spec/helpers/projects/pipeline_helper_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Projects::PipelineHelper do
blob_path: project_blob_path(project, pipeline.sha),
has_test_report: pipeline.complete_and_has_reports?(Ci::JobArtifact.of_report_type(:test)),
empty_dag_svg_path: match_asset_path('illustrations/empty-state/empty-dag-md.svg'),
- empty_state_image_path: match_asset_path('illustrations/empty-state/empty-test-cases-lg.svg'),
+ empty_state_image_path: match_asset_path('illustrations/empty-todos-md.svg'),
artifacts_expired_image_path: match_asset_path('illustrations/pipeline.svg'),
tests_count: pipeline.test_report_summary.total[:count]
})
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index e1537c7b287..9f9372f94cc 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -809,22 +809,6 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
end
end
- describe '#metrics_external_dashboard_url' do
- context 'metrics_setting exists' do
- it 'returns external_dashboard_url' do
- metrics_setting = create(:project_metrics_setting, project: project)
-
- expect(helper.metrics_external_dashboard_url).to eq(metrics_setting.external_dashboard_url)
- end
- end
-
- context 'metrics_setting does not exist' do
- it 'returns nil' do
- expect(helper.metrics_external_dashboard_url).to eq(nil)
- end
- end
- end
-
describe '#grafana_integration_url' do
subject { helper.grafana_integration_url }
diff --git a/spec/helpers/registrations_helper_spec.rb b/spec/helpers/registrations_helper_spec.rb
index 85cedd4aace..74d46245cc2 100644
--- a/spec/helpers/registrations_helper_spec.rb
+++ b/spec/helpers/registrations_helper_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe RegistrationsHelper, feature_category: :user_management do
describe '#signup_username_data_attributes' do
it 'has expected attributes' do
- expect(helper.signup_username_data_attributes.keys).to include(:min_length, :min_length_message, :max_length, :max_length_message, :qa_selector)
+ expect(helper.signup_username_data_attributes.keys).to include(:min_length, :min_length_message, :max_length, :max_length_message, :testid)
end
end
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index 4109eb01caa..3e5ee714b32 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -71,6 +71,36 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
let(:project) { nil }
let(:current_user_mode) { Gitlab::Auth::CurrentUserMode.new(user) }
+ let(:global_shortcut_links) do
+ [
+ {
+ title: _('Milestones'),
+ href: dashboard_milestones_path,
+ css_class: 'dashboard-shortcuts-milestones'
+ },
+ {
+ title: _('Snippets'),
+ href: dashboard_snippets_path,
+ css_class: 'dashboard-shortcuts-snippets'
+ },
+ {
+ title: _('Activity'),
+ href: activity_dashboard_path,
+ css_class: 'dashboard-shortcuts-activity'
+ },
+ {
+ title: _('Groups'),
+ href: dashboard_groups_path,
+ css_class: 'dashboard-shortcuts-groups'
+ },
+ {
+ title: _('Projects'),
+ href: dashboard_projects_path,
+ css_class: 'dashboard-shortcuts-projects'
+ }
+ ]
+ end
+
subject do
helper.super_sidebar_context(user, group: group, project: project, panel: panel, panel_type: panel_type)
end
@@ -139,65 +169,65 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
canary_toggle_com_url: Gitlab::Saas.canary_toggle_com_url,
pinned_items: %w[foo bar],
update_pins_url: pins_path,
- shortcut_links: [
- {
- title: _('Milestones'),
- href: dashboard_milestones_path,
- css_class: 'dashboard-shortcuts-milestones'
- },
- {
- title: _('Snippets'),
- href: dashboard_snippets_path,
- css_class: 'dashboard-shortcuts-snippets'
- },
- {
- title: _('Activity'),
- href: activity_dashboard_path,
- css_class: 'dashboard-shortcuts-activity'
- }
- ]
+ shortcut_links: global_shortcut_links,
+ track_visits_path: track_namespace_visits_path
})
end
describe "shortcut links" do
- let(:global_shortcut_links) do
- [
- {
- title: _('Milestones'),
- href: dashboard_milestones_path,
- css_class: 'dashboard-shortcuts-milestones'
- },
- {
- title: _('Snippets'),
- href: dashboard_snippets_path,
- css_class: 'dashboard-shortcuts-snippets'
- },
- {
- title: _('Activity'),
- href: activity_dashboard_path,
- css_class: 'dashboard-shortcuts-activity'
- }
- ]
- end
+ describe "as the anonymous user" do
+ let_it_be(:user) { nil }
+ let(:global_shortcut_links) do
+ [
+ {
+ title: _('Snippets'),
+ href: explore_snippets_path,
+ css_class: 'dashboard-shortcuts-snippets'
+ },
+ {
+ title: _('Groups'),
+ href: explore_groups_path,
+ css_class: 'dashboard-shortcuts-groups'
+ },
+ {
+ title: _('Projects'),
+ href: explore_projects_path,
+ css_class: 'dashboard-shortcuts-projects'
+ }
+ ]
+ end
+
+ it 'returns global shortcut links' do
+ expect(subject[:shortcut_links]).to eq(global_shortcut_links)
+ end
+
+ context 'in a project' do
+ let_it_be(:project) { build_stubbed(:project) }
- it 'returns global shortcut links' do
- expect(subject[:shortcut_links]).to eq(global_shortcut_links)
+ it 'returns project-specific shortcut links' do
+ expect(subject[:shortcut_links]).to eq(global_shortcut_links)
+ end
+ end
end
- context 'in a project' do
- # rubocop: disable RSpec/FactoryBot/AvoidCreate
- let_it_be(:project) { create(:project) }
- # rubocop: enable RSpec/FactoryBot/AvoidCreate
+ describe "as logged-in user" do
+ it 'returns global shortcut links' do
+ expect(subject[:shortcut_links]).to eq(global_shortcut_links)
+ end
- it 'returns project-specific shortcut links' do
- expect(subject[:shortcut_links]).to eq([
- *global_shortcut_links,
- {
- title: _('Create a new issue'),
- href: new_project_issue_path(project),
- css_class: 'shortcuts-new-issue'
- }
- ])
+ context 'in a project' do
+ let_it_be(:project) { build_stubbed(:project) }
+
+ it 'returns project-specific shortcut links' do
+ expect(subject[:shortcut_links]).to eq([
+ *global_shortcut_links,
+ {
+ title: _('Create a new issue'),
+ href: new_project_issue_path(project),
+ css_class: 'shortcuts-new-issue'
+ }
+ ])
+ end
end
end
end
@@ -488,7 +518,6 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
end
describe '#super_sidebar_nav_panel' do
- let(:user) { build(:user) }
let(:group) { build(:group) }
let(:project) { build(:project) }
let(:organization) { build(:organization) }
@@ -500,48 +529,84 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
{ current_user: nil, container: group, show_discover_group_security: false })
allow(group).to receive(:to_global_id).and_return(5)
- Rails.cache.write(['users', user.id, 'assigned_open_issues_count'], 1)
- Rails.cache.write(['users', user.id, 'assigned_open_merge_requests_count'], 4)
- Rails.cache.write(['users', user.id, 'review_requested_open_merge_requests_count'], 0)
- Rails.cache.write(['users', user.id, 'todos_pending_count'], 3)
end
- it 'returns Project Panel for project nav' do
- expect(helper.super_sidebar_nav_panel(nav: 'project')).to be_a(Sidebars::Projects::SuperSidebarPanel)
- end
+ shared_examples 'nav panels available to logged-out users' do
+ it 'returns Project Panel for project nav' do
+ expect(helper.super_sidebar_nav_panel(nav: 'project',
+ user: user)).to be_a(Sidebars::Projects::SuperSidebarPanel)
+ end
- it 'returns Group Panel for group nav' do
- expect(helper.super_sidebar_nav_panel(nav: 'group')).to be_a(Sidebars::Groups::SuperSidebarPanel)
- end
+ it 'returns Group Panel for group nav' do
+ expect(helper.super_sidebar_nav_panel(nav: 'group', user: user)).to be_a(Sidebars::Groups::SuperSidebarPanel)
+ end
- it 'returns User Settings Panel for profile nav' do
- expect(helper.super_sidebar_nav_panel(nav: 'profile')).to be_a(Sidebars::UserSettings::Panel)
- end
+ it 'returns User profile Panel for user profile nav' do
+ viewed_user = build(:user)
+ expect(helper.super_sidebar_nav_panel(nav: 'user_profile', user: user,
+ viewed_user: viewed_user)).to be_a(Sidebars::UserProfile::Panel)
+ end
- it 'returns User profile Panel for user profile nav' do
- expect(helper.super_sidebar_nav_panel(nav: 'user_profile')).to be_a(Sidebars::UserProfile::Panel)
- end
+ it 'returns Explore Panel for explore nav' do
+ expect(helper.super_sidebar_nav_panel(nav: 'explore', user: user)).to be_a(Sidebars::Explore::Panel)
+ end
- it 'returns Admin Panel for admin nav' do
- expect(helper.super_sidebar_nav_panel(nav: 'admin')).to be_a(Sidebars::Admin::Panel)
- end
+ it 'returns Organization Panel for organization nav' do
+ expect(
+ helper.super_sidebar_nav_panel(nav: 'organization', organization: organization, user: user)
+ ).to be_a(Sidebars::Organizations::SuperSidebarPanel)
+ end
- it 'returns Organization Panel for organization nav' do
- expect(
- helper.super_sidebar_nav_panel(nav: 'organization', organization: organization)
- ).to be_a(Sidebars::Organizations::SuperSidebarPanel)
+ it 'returns Search Panel for search nav' do
+ expect(helper.super_sidebar_nav_panel(nav: 'search', user: user)).to be_a(Sidebars::Search::Panel)
+ end
end
- it 'returns "Your Work" Panel for your_work nav', :use_clean_rails_memory_store_caching do
- expect(helper.super_sidebar_nav_panel(nav: 'your_work', user: user)).to be_a(Sidebars::YourWork::Panel)
- end
+ describe 'when logged-in' do
+ let(:user) { build(:user) }
+
+ before do
+ Rails.cache.write(['users', user.id, 'assigned_open_issues_count'], 1)
+ Rails.cache.write(['users', user.id, 'assigned_open_merge_requests_count'], 4)
+ Rails.cache.write(['users', user.id, 'review_requested_open_merge_requests_count'], 0)
+ Rails.cache.write(['users', user.id, 'todos_pending_count'], 3)
+ end
+
+ it 'returns User Settings Panel for profile nav' do
+ expect(helper.super_sidebar_nav_panel(nav: 'profile', user: user)).to be_a(Sidebars::UserSettings::Panel)
+ end
+
+ describe 'admin user' do
+ it 'returns Admin Panel for admin nav', :aggregate_failures do
+ allow(user).to receive(:can_admin_all_resources?).and_return(true)
+
+ expect(helper.super_sidebar_nav_panel(nav: 'admin', user: user)).to be_a(Sidebars::Admin::Panel)
+ end
+ end
+
+ it 'returns Your Work Panel for admin nav' do
+ expect(helper.super_sidebar_nav_panel(nav: 'admin', user: user)).to be_a(Sidebars::YourWork::Panel)
+ end
+
+ it 'returns "Your Work" Panel for your_work nav', :use_clean_rails_memory_store_caching do
+ expect(helper.super_sidebar_nav_panel(nav: 'your_work', user: user)).to be_a(Sidebars::YourWork::Panel)
+ end
+
+ it 'returns "Your Work" Panel as a fallback', :use_clean_rails_memory_store_caching do
+ expect(helper.super_sidebar_nav_panel(user: user)).to be_a(Sidebars::YourWork::Panel)
+ end
- it 'returns Search Panel for search nav' do
- expect(helper.super_sidebar_nav_panel(nav: 'search', user: user)).to be_a(Sidebars::Search::Panel)
+ it_behaves_like 'nav panels available to logged-out users'
end
- it 'returns "Your Work" Panel as a fallback', :use_clean_rails_memory_store_caching do
- expect(helper.super_sidebar_nav_panel(user: user)).to be_a(Sidebars::YourWork::Panel)
+ describe 'when logged-out' do
+ let(:user) { nil }
+
+ it_behaves_like 'nav panels available to logged-out users'
+
+ it 'returns "Explore" Panel as a fallback' do
+ expect(helper.super_sidebar_nav_panel(user: user)).to be_a(Sidebars::Explore::Panel)
+ end
end
end
diff --git a/spec/helpers/sidekiq_helper_spec.rb b/spec/helpers/sidekiq_helper_spec.rb
index 6a0a92bafd8..594996bac95 100644
--- a/spec/helpers/sidekiq_helper_spec.rb
+++ b/spec/helpers/sidekiq_helper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SidekiqHelper do
+RSpec.describe SidekiqHelper, feature_category: :shared do
describe 'parse_sidekiq_ps' do
it 'parses line with time' do
line = '55137 10,0 2,1 S+ 2:30pm sidekiq 4.1.4 gitlab [0 of 25 busy] '
diff --git a/spec/helpers/vite_helper_spec.rb b/spec/helpers/vite_helper_spec.rb
new file mode 100644
index 00000000000..edb5650ab1a
--- /dev/null
+++ b/spec/helpers/vite_helper_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ViteHelper, feature_category: :tooling do
+ let(:source) { 'foo.js' }
+ let(:vite_source) { 'vite/foo.js' }
+ let(:vite_tag) { '<tag src="vite/foo"></tag>' }
+ let(:webpack_source) { 'webpack/foo.js' }
+ let(:webpack_tag) { '<tag src="webpack/foo"></tag>' }
+
+ context 'when vite enabled' do
+ before do
+ stub_rails_env('development')
+ stub_feature_flags(vite: true)
+
+ allow(helper).to receive(:vite_javascript_tag).and_return(vite_tag)
+ allow(helper).to receive(:vite_asset_path).and_return(vite_source)
+ allow(helper).to receive(:vite_stylesheet_tag).and_return(vite_tag)
+ allow(helper).to receive(:vite_asset_url).and_return(vite_source)
+ allow(helper).to receive(:vite_running).and_return(true)
+ end
+
+ describe '#universal_javascript_include_tag' do
+ it 'returns vite javascript tag' do
+ expect(helper.universal_javascript_include_tag(source)).to eq(vite_tag)
+ end
+ end
+
+ describe '#universal_asset_path' do
+ it 'returns vite asset path' do
+ expect(helper.universal_asset_path(source)).to eq(vite_source)
+ end
+ end
+ end
+
+ context 'when vite disabled' do
+ before do
+ stub_feature_flags(vite: false)
+
+ allow(helper).to receive(:javascript_include_tag).and_return(webpack_tag)
+ allow(helper).to receive(:asset_path).and_return(webpack_source)
+ allow(helper).to receive(:stylesheet_link_tag).and_return(webpack_tag)
+ allow(helper).to receive(:path_to_stylesheet).and_return(webpack_source)
+ end
+
+ describe '#universal_javascript_include_tag' do
+ it 'returns webpack javascript tag' do
+ expect(helper.universal_javascript_include_tag(source)).to eq(webpack_tag)
+ end
+ end
+
+ describe '#universal_asset_path' do
+ it 'returns ActionView asset path' do
+ expect(helper.universal_asset_path(source)).to eq(webpack_source)
+ end
+ end
+ end
+end
diff --git a/spec/helpers/webpack_helper_spec.rb b/spec/helpers/webpack_helper_spec.rb
index f9e2d265153..23585c47239 100644
--- a/spec/helpers/webpack_helper_spec.rb
+++ b/spec/helpers/webpack_helper_spec.rb
@@ -34,4 +34,22 @@ RSpec.describe WebpackHelper do
expect(output).to eq("<link rel=\"prefetch\" href=\"#{asset_path}\">")
end
end
+
+ context 'when vite enabled' do
+ let(:bundle) { 'bundle.js' }
+
+ before do
+ stub_rails_env('development')
+ stub_feature_flags(vite: true)
+
+ allow(helper).to receive(:vite_javascript_tag).and_return('vite')
+ allow(helper).to receive(:vite_running).and_return(true)
+ end
+
+ describe '#webpack_bundle_tag' do
+ it 'return vite javascript tag' do
+ expect(helper.webpack_bundle_tag(bundle)).to eq('vite')
+ end
+ end
+ end
end
diff --git a/spec/helpers/work_items_helper_spec.rb b/spec/helpers/work_items_helper_spec.rb
index 4e1eca3d411..b790f21d412 100644
--- a/spec/helpers/work_items_helper_spec.rb
+++ b/spec/helpers/work_items_helper_spec.rb
@@ -21,4 +21,18 @@ RSpec.describe WorkItemsHelper, feature_category: :team_planning do
)
end
end
+
+ describe '#work_items_list_data' do
+ let_it_be(:group) { build(:group) }
+
+ subject(:work_items_list_data) { helper.work_items_list_data(group) }
+
+ it 'returns expected data' do
+ expect(work_items_list_data).to include(
+ {
+ full_path: group.full_path
+ }
+ )
+ end
+ end
end
diff --git a/spec/initializers/action_cable_subscription_adapter_identifier_spec.rb b/spec/initializers/action_cable_subscription_adapter_identifier_spec.rb
index cf82fd751dd..dd2bf298611 100644
--- a/spec/initializers/action_cable_subscription_adapter_identifier_spec.rb
+++ b/spec/initializers/action_cable_subscription_adapter_identifier_spec.rb
@@ -27,7 +27,8 @@ RSpec.describe 'ActionCableSubscriptionAdapterIdentifier override' do
sub = ActionCable.server.pubsub.send(:redis_connection)
- expect(sub.connection[:id]).to eq('unix:///home/localuser/redis/redis.socket/0')
+ expect(sub.is_a?(::Gitlab::Redis::MultiStore)).to eq(true)
+ expect(sub.secondary_store.connection[:id]).to eq('unix:///home/localuser/redis/redis.socket/0')
expect(ActionCable.server.config.cable[:id]).to be_nil
end
end
diff --git a/spec/initializers/mail_starttls_patch_spec.rb b/spec/initializers/mail_starttls_patch_spec.rb
index 99c8edddd12..0ceeb78a5b8 100644
--- a/spec/initializers/mail_starttls_patch_spec.rb
+++ b/spec/initializers/mail_starttls_patch_spec.rb
@@ -17,6 +17,37 @@ RSpec.describe 'Mail STARTTLS patch', feature_category: :shared do
end
end
+ # As long as this monkey patch exists and overrides the constructor
+ # we should test that the defaults of Mail::SMTP are not overriden.
+ #
+ # @see issue https://gitlab.com/gitlab-org/gitlab/-/issues/423268
+ # @see incident https://gitlab.com/gitlab-com/gl-infra/production/-/issues/16223
+ it 'does not override default constants values' do
+ expected_settings = Mail::SMTP.new({}).settings.dup
+
+ Mail.new.delivery_method(Mail::SMTP, { user_name: 'user@example.com' })
+
+ expect(Mail::SMTP.new({}).settings).to eq(expected_settings)
+ end
+
+ describe 'enable_starttls_auto setting' do
+ let(:settings) { {} }
+
+ subject(:smtp) { Mail::SMTP.new(settings) }
+
+ it 'uses default for enable_starttls_auto' do
+ expect(smtp.settings).to include(enable_starttls_auto: nil)
+ end
+
+ context 'when set to false' do
+ let(:settings) { { enable_starttls_auto: false } }
+
+ it 'overrides default and sets value' do
+ expect(smtp.settings).to include(enable_starttls_auto: false)
+ end
+ end
+ end
+
# Taken from https://github.com/mikel/mail/pull/1536#issue-1490438378
where(:ssl, :tls, :enable_starttls, :enable_starttls_auto, :smtp_tls, :smtp_starttls_mode) do
true | nil | nil | nil | true | false
diff --git a/spec/initializers/sidekiq_spec.rb b/spec/initializers/sidekiq_spec.rb
index 063dddd8c46..a034e628d25 100644
--- a/spec/initializers/sidekiq_spec.rb
+++ b/spec/initializers/sidekiq_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'sidekiq' do
+RSpec.describe 'sidekiq', feature_category: :build do
describe 'enable_reliable_fetch?' do
subject { enable_reliable_fetch? }
diff --git a/spec/lib/api/ci/helpers/runner_spec.rb b/spec/lib/api/ci/helpers/runner_spec.rb
index 62b79c77b4a..70504a58af3 100644
--- a/spec/lib/api/ci/helpers/runner_spec.rb
+++ b/spec/lib/api/ci/helpers/runner_spec.rb
@@ -3,10 +3,18 @@
require 'spec_helper'
RSpec.describe API::Ci::Helpers::Runner do
- let(:helper) { Class.new { include API::Ci::Helpers::Runner }.new }
+ let(:helper) do
+ Class.new do
+ include API::Ci::Helpers::Runner
+ include Gitlab::RackLoadBalancingHelpers
+ end.new
+ end
+
+ let(:env_hash) { {} }
+ let(:request) { instance_double(Rack::Request, env: env_hash) }
before do
- allow(helper).to receive(:env).and_return({})
+ allow(helper).to receive(:request).and_return(request)
end
describe '#current_job', feature_category: :continuous_integration do
@@ -16,17 +24,22 @@ RSpec.describe API::Ci::Helpers::Runner do
allow(helper).to receive(:params).and_return(id: build.id)
expect(Ci::Build.sticking)
- .to receive(:stick_or_unstick_request)
- .with({}, :build, build.id)
+ .to receive(:find_caught_up_replica)
+ .with(:build, build.id)
helper.current_job
+
+ stick_object = env_hash[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].first
+ expect(stick_object[0]).to eq(Ci::Build.sticking)
+ expect(stick_object[1]).to eq(:build)
+ expect(stick_object[2]).to eq(build.id)
end
it 'does not handle sticking if no build ID was specified' do
allow(helper).to receive(:params).and_return({})
expect(Ci::Build.sticking)
- .not_to receive(:stick_or_unstick_request)
+ .not_to receive(:find_caught_up_replica)
helper.current_job
end
@@ -45,17 +58,22 @@ RSpec.describe API::Ci::Helpers::Runner do
allow(helper).to receive(:params).and_return(token: runner.token)
expect(Ci::Runner.sticking)
- .to receive(:stick_or_unstick_request)
- .with({}, :runner, runner.token)
+ .to receive(:find_caught_up_replica)
+ .with(:runner, runner.token)
helper.current_runner
+
+ stick_object = env_hash[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].first
+ expect(stick_object[0]).to eq(Ci::Runner.sticking)
+ expect(stick_object[1]).to eq(:runner)
+ expect(stick_object[2]).to eq(runner.token)
end
it 'does not handle sticking if no token was specified' do
allow(helper).to receive(:params).and_return({})
expect(Ci::Runner.sticking)
- .not_to receive(:stick_or_unstick_request)
+ .not_to receive(:find_caught_up_replica)
helper.current_runner
end
diff --git a/spec/lib/api/entities/merge_request_basic_spec.rb b/spec/lib/api/entities/merge_request_basic_spec.rb
index 89e19f8529e..0cf0a57fa87 100644
--- a/spec/lib/api/entities/merge_request_basic_spec.rb
+++ b/spec/lib/api/entities/merge_request_basic_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::API::Entities::MergeRequestBasic do
+RSpec.describe ::API::Entities::MergeRequestBasic, feature_category: :code_review_workflow do
let_it_be(:user) { create(:user) }
let_it_be(:merge_request) { create(:merge_request) }
let_it_be(:labels) { create_list(:label, 3) }
diff --git a/spec/lib/api/entities/merge_request_diff_spec.rb b/spec/lib/api/entities/merge_request_diff_spec.rb
new file mode 100644
index 00000000000..a6927914316
--- /dev/null
+++ b/spec/lib/api/entities/merge_request_diff_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::API::Entities::MergeRequestDiff, feature_category: :code_review_workflow do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:merge_request) { create(:merge_request) }
+ let_it_be(:project) { merge_request.target_project }
+ let_it_be(:entity) { described_class.new(merge_request.merge_request_diffs.first) }
+
+ before do
+ merge_request.merge_request_diffs.create!(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9')
+ merge_request.merge_request_diffs.create!(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e')
+ end
+
+ subject(:json) { entity.as_json }
+
+ it "includes expected fields" do
+ expected_fields = %i[
+ id head_commit_sha base_commit_sha start_commit_sha created_at
+ merge_request_id state real_size patch_id_sha
+ ]
+
+ is_expected.to include(*expected_fields)
+ end
+
+ it "returns expected data" do
+ merge_request_diff = merge_request.merge_request_diffs.first
+
+ expect(entity.as_json).to eq(
+ {
+ id: merge_request_diff.id,
+ head_commit_sha: merge_request_diff.head_commit_sha,
+ base_commit_sha: merge_request_diff.base_commit_sha,
+ start_commit_sha: merge_request_diff.start_commit_sha,
+ created_at: merge_request_diff.created_at,
+ merge_request_id: merge_request.id,
+ state: merge_request_diff.state,
+ real_size: merge_request_diff.real_size,
+ patch_id_sha: merge_request_diff.patch_id_sha
+ }
+ )
+ end
+end
diff --git a/spec/lib/api/entities/ml/mlflow/get_run_spec.rb b/spec/lib/api/entities/ml/mlflow/get_run_spec.rb
new file mode 100644
index 00000000000..513ecdeee3c
--- /dev/null
+++ b/spec/lib/api/entities/ml/mlflow/get_run_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Entities::Ml::Mlflow::GetRun, feature_category: :mlops do
+ let_it_be(:candidate) { build(:ml_candidates, :with_metrics_and_params) }
+
+ subject { described_class.new(candidate).as_json }
+
+ it 'has run key' do
+ expect(subject).to have_key(:run)
+ end
+
+ it 'has the id' do
+ expect(subject.dig(:run, :info, :run_id)).to eq(candidate.eid.to_s)
+ end
+
+ it 'presents the metrics' do
+ expect(subject.dig(:run, :data, :metrics).size).to eq(candidate.metrics.size)
+ end
+
+ it 'presents metrics correctly' do
+ presented_metric = subject.dig(:run, :data, :metrics)[0]
+ metric = candidate.metrics[0]
+
+ expect(presented_metric[:key]).to eq(metric.name)
+ expect(presented_metric[:value]).to eq(metric.value)
+ expect(presented_metric[:timestamp]).to eq(metric.tracked_at)
+ expect(presented_metric[:step]).to eq(metric.step)
+ end
+
+ it 'presents the params' do
+ expect(subject.dig(:run, :data, :params).size).to eq(candidate.params.size)
+ end
+
+ it 'presents params correctly' do
+ presented_param = subject.dig(:run, :data, :params)[0]
+ param = candidate.params[0]
+
+ expect(presented_param[:key]).to eq(param.name)
+ expect(presented_param[:value]).to eq(param.value)
+ end
+
+ context 'when candidate has no metrics' do
+ before do
+ allow(candidate).to receive(:metrics).and_return([])
+ end
+
+ it 'returns empty data' do
+ expect(subject.dig(:run, :data, :metrics)).to be_empty
+ end
+ end
+
+ context 'when candidate has no params' do
+ before do
+ allow(candidate).to receive(:params).and_return([])
+ end
+
+ it 'data is empty' do
+ expect(subject.dig(:run, :data, :params)).to be_empty
+ end
+ end
+end
diff --git a/spec/lib/api/entities/ml/mlflow/run_info_spec.rb b/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
index 28fef16a532..1664d9f18d2 100644
--- a/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
+++ b/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe API::Entities::Ml::Mlflow::RunInfo, feature_category: :mlops do
- let_it_be(:candidate) { create(:ml_candidates) }
+ let_it_be(:candidate) { build(:ml_candidates) }
subject { described_class.new(candidate, packages_url: 'http://example.com').as_json }
diff --git a/spec/lib/api/entities/ml/mlflow/run_spec.rb b/spec/lib/api/entities/ml/mlflow/run_spec.rb
index a57f70f788b..58148212a7b 100644
--- a/spec/lib/api/entities/ml/mlflow/run_spec.rb
+++ b/spec/lib/api/entities/ml/mlflow/run_spec.rb
@@ -3,24 +3,20 @@
require 'spec_helper'
RSpec.describe API::Entities::Ml::Mlflow::Run do
- let_it_be(:candidate) { create(:ml_candidates, :with_metrics_and_params) }
+ let_it_be(:candidate) { build(:ml_candidates, :with_metrics_and_params) }
subject { described_class.new(candidate).as_json }
- it 'has run key' do
- expect(subject).to have_key(:run)
- end
-
it 'has the id' do
- expect(subject.dig(:run, :info, :run_id)).to eq(candidate.eid.to_s)
+ expect(subject.dig(:info, :run_id)).to eq(candidate.eid.to_s)
end
it 'presents the metrics' do
- expect(subject.dig(:run, :data, :metrics).size).to eq(candidate.metrics.size)
+ expect(subject.dig(:data, :metrics).size).to eq(candidate.metrics.size)
end
it 'presents metrics correctly' do
- presented_metric = subject.dig(:run, :data, :metrics)[0]
+ presented_metric = subject.dig(:data, :metrics)[0]
metric = candidate.metrics[0]
expect(presented_metric[:key]).to eq(metric.name)
@@ -30,11 +26,11 @@ RSpec.describe API::Entities::Ml::Mlflow::Run do
end
it 'presents the params' do
- expect(subject.dig(:run, :data, :params).size).to eq(candidate.params.size)
+ expect(subject.dig(:data, :params).size).to eq(candidate.params.size)
end
it 'presents params correctly' do
- presented_param = subject.dig(:run, :data, :params)[0]
+ presented_param = subject.dig(:data, :params)[0]
param = candidate.params[0]
expect(presented_param[:key]).to eq(param.name)
@@ -47,7 +43,7 @@ RSpec.describe API::Entities::Ml::Mlflow::Run do
end
it 'returns empty data' do
- expect(subject.dig(:run, :data, :metrics)).to be_empty
+ expect(subject.dig(:data, :metrics)).to be_empty
end
end
@@ -57,7 +53,7 @@ RSpec.describe API::Entities::Ml::Mlflow::Run do
end
it 'data is empty' do
- expect(subject.dig(:run, :data, :params)).to be_empty
+ expect(subject.dig(:data, :params)).to be_empty
end
end
end
diff --git a/spec/lib/api/entities/ml/mlflow/search_runs_spec.rb b/spec/lib/api/entities/ml/mlflow/search_runs_spec.rb
new file mode 100644
index 00000000000..6ed59d454fa
--- /dev/null
+++ b/spec/lib/api/entities/ml/mlflow/search_runs_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Entities::Ml::Mlflow::SearchRuns, feature_category: :mlops do
+ let_it_be(:candidates) { [build_stubbed(:ml_candidates, :with_metrics_and_params), build_stubbed(:ml_candidates)] }
+
+ let(:next_page_token) { 'abcdef' }
+
+ subject { described_class.new({ candidates: candidates, next_page_token: next_page_token }).as_json }
+
+ it 'presents the candidates', :aggregate_failures do
+ expect(subject[:runs].size).to eq(2)
+ expect(subject.dig(:runs, 0, :info, :run_id)).to eq(candidates[0].eid.to_s)
+ expect(subject.dig(:runs, 1, :info, :run_id)).to eq(candidates[1].eid.to_s)
+ end
+
+ it 'presents metrics', :aggregate_failures do
+ expect(subject.dig(:runs, 0, :data, :metrics).size).to eq(candidates[0].metrics.size)
+ expect(subject.dig(:runs, 1, :data, :metrics).size).to eq(0)
+
+ presented_metric = subject.dig(:runs, 0, :data, :metrics, 0, :key)
+ metric = candidates[0].metrics[0].name
+
+ expect(presented_metric).to eq(metric)
+ end
+
+ it 'presents params', :aggregate_failures do
+ expect(subject.dig(:runs, 0, :data, :params).size).to eq(candidates[0].params.size)
+ expect(subject.dig(:runs, 1, :data, :params).size).to eq(0)
+
+ presented_param = subject.dig(:runs, 0, :data, :params, 0, :key)
+ param = candidates[0].params[0].name
+
+ expect(presented_param).to eq(param)
+ end
+end
diff --git a/spec/lib/api/entities/project_spec.rb b/spec/lib/api/entities/project_spec.rb
index 5d18b93228f..2c2cabba5e9 100644
--- a/spec/lib/api/entities/project_spec.rb
+++ b/spec/lib/api/entities/project_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe ::API::Entities::Project do
end
end
- describe '.service_desk_address' do
+ describe '.service_desk_address', feature_category: :service_desk do
before do
allow(project).to receive(:service_desk_enabled?).and_return(true)
end
diff --git a/spec/lib/api/helpers/packages_helpers_spec.rb b/spec/lib/api/helpers/packages_helpers_spec.rb
index 6ba4396c396..bb7b9d688ea 100644
--- a/spec/lib/api/helpers/packages_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages_helpers_spec.rb
@@ -292,7 +292,7 @@ RSpec.describe API::Helpers::PackagesHelpers, feature_category: :package_registr
let(:label) { 'counts.package_events_i_package_push_package_by_deploy_token' }
let(:property) { 'i_package_push_package_by_deploy_token' }
let(:service_ping_context) do
- [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: 'counts.package_events_i_package_push_package_by_deploy_token').to_h]
+ [Gitlab::Usage::MetricDefinition.context_for('counts.package_events_i_package_push_package_by_deploy_token').to_h]
end
it 'logs a snowplow event' do
@@ -320,7 +320,7 @@ RSpec.describe API::Helpers::PackagesHelpers, feature_category: :package_registr
let(:label) { 'counts.package_events_i_package_pull_package_by_guest' }
let(:property) { 'i_package_pull_package_by_guest' }
let(:service_ping_context) do
- [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: 'counts.package_events_i_package_pull_package_by_guest').to_h]
+ [Gitlab::Usage::MetricDefinition.context_for('counts.package_events_i_package_pull_package_by_guest').to_h]
end
it 'logs a snowplow event' do
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 667ee72f821..dd62343890e 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -11,7 +11,6 @@ RSpec.describe API::Helpers, feature_category: :shared do
include Rack::Test::Methods
let(:user) { build(:user, id: 42) }
- let(:request) { instance_double(Rack::Request) }
let(:helper) do
Class.new(Grape::API::Instance) do
helpers API::APIGuard::HelperMethods
@@ -36,18 +35,23 @@ RSpec.describe API::Helpers, feature_category: :shared do
allow_any_instance_of(described_class).to receive(:initial_current_user).and_return(user)
expect(ApplicationRecord.sticking)
- .to receive(:stick_or_unstick_request).with(any_args, :user, 42)
+ .to receive(:find_caught_up_replica).with(:user, 42)
get 'user'
expect(Gitlab::Json.parse(last_response.body)).to eq({ 'id' => user.id })
+
+ stick_object = last_request.env[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].first
+ expect(stick_object[0]).to eq(User.sticking)
+ expect(stick_object[1]).to eq(:user)
+ expect(stick_object[2]).to eq(42)
end
it 'does not handle sticking if no user could be found' do
allow_any_instance_of(described_class).to receive(:initial_current_user).and_return(nil)
expect(ApplicationRecord.sticking)
- .not_to receive(:stick_or_unstick_request)
+ .not_to receive(:find_caught_up_replica)
get 'user'
@@ -243,6 +247,165 @@ RSpec.describe API::Helpers, feature_category: :shared do
end
end
+ describe '#find_pipeline' do
+ let(:pipeline) { create(:ci_pipeline) }
+
+ shared_examples 'pipeline finder' do
+ context 'when pipeline exists' do
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline(existing_id)).to eq(pipeline)
+ end
+ end
+
+ context 'when pipeline does not exists' do
+ it 'returns nil' do
+ expect(helper.find_pipeline(non_existing_id)).to be_nil
+ end
+ end
+
+ context 'when pipeline id is not provided' do
+ it 'returns nil' do
+ expect(helper.find_pipeline(nil)).to be_nil
+ end
+ end
+ end
+
+ context 'when ID is used as an argument' do
+ let(:existing_id) { pipeline.id }
+ let(:non_existing_id) { non_existing_record_id }
+
+ it_behaves_like 'pipeline finder'
+ end
+
+ context 'when string ID is used as an argument' do
+ let(:existing_id) { pipeline.id.to_s }
+ let(:non_existing_id) { non_existing_record_id }
+
+ it_behaves_like 'pipeline finder'
+ end
+
+ context 'when ID is a negative number' do
+ let(:existing_id) { pipeline.id }
+ let(:non_existing_id) { -1 }
+
+ it_behaves_like 'pipeline finder'
+ end
+ end
+
+ describe '#find_pipeline!' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:user) { create(:user) }
+
+ shared_examples 'private project without access' do
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value('private'))
+ allow(helper).to receive(:authenticate_non_public?).and_return(false)
+ end
+
+ it 'returns not found' do
+ expect(helper).to receive(:not_found!)
+
+ helper.find_pipeline!(pipeline.id)
+ end
+ end
+
+ context 'when user is authenticated' do
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ allow(helper).to receive(:initial_current_user).and_return(user)
+ end
+
+ context 'public project' do
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline)
+ end
+ end
+
+ context 'private project' do
+ it_behaves_like 'private project without access'
+
+ context 'without read pipeline permission' do
+ before do
+ allow(helper).to receive(:can?).with(user, :read_pipeline, pipeline).and_return(false)
+ end
+
+ it_behaves_like 'private project without access'
+ end
+ end
+
+ context 'with read pipeline permission' do
+ before do
+ allow(helper).to receive(:can?).with(user, :read_pipeline, pipeline).and_return(true)
+ end
+
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline)
+ end
+ end
+ end
+
+ context 'when user is not authenticated' do
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ allow(helper).to receive(:initial_current_user).and_return(nil)
+ end
+
+ context 'public project' do
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline)
+ end
+ end
+
+ context 'private project' do
+ it_behaves_like 'private project without access'
+ end
+ end
+
+ context 'support for IDs and paths as argument' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+
+ let(:user) { project.first_owner }
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ allow(helper).to receive(:authorized_project_scope?).and_return(true)
+ allow(helper).to receive(:job_token_authentication?).and_return(false)
+ allow(helper).to receive(:authenticate_non_public?).and_return(false)
+ end
+
+ shared_examples 'pipeline finder' do
+ context 'when pipeline exists' do
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline!(existing_id)).to eq(pipeline)
+ end
+
+ it 'returns nil' do
+ expect(helper).to receive(:render_api_error!).with('404 Pipeline Not Found', 404)
+ expect(helper.find_pipeline!(non_existing_id)).to be_nil
+ end
+ end
+ end
+
+ context 'when ID is used as an argument' do
+ context 'when pipeline id is an integer' do
+ let(:existing_id) { pipeline.id }
+ let(:non_existing_id) { non_existing_record_id }
+
+ it_behaves_like 'pipeline finder'
+ end
+
+ context 'when pipeline id is a string' do
+ let(:existing_id) { pipeline.id.to_s }
+ let(:non_existing_id) { "non_existing_record_id" }
+
+ it_behaves_like 'pipeline finder'
+ end
+ end
+ end
+ end
+
describe '#find_group!' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:user) { create(:user) }
@@ -628,10 +791,12 @@ RSpec.describe API::Helpers, feature_category: :shared do
end
it 'logs an exception for unknown event' do
- expect(Gitlab::AppLogger).to receive(:warn).with(
- "Internal Event tracking event failed for event: #{unknown_event}, message: Unknown event: #{unknown_event}"
- )
-
+ expect(Gitlab::InternalEvents).to receive(:track_event).and_raise(Gitlab::InternalEvents::UnknownEventError, "Unknown event: #{unknown_event}")
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ .with(
+ instance_of(Gitlab::InternalEvents::UnknownEventError),
+ event_name: unknown_event
+ )
helper.track_event(unknown_event, user_id: user_id, namespace_id: namespace_id, project_id: project_id)
end
@@ -1072,4 +1237,47 @@ RSpec.describe API::Helpers, feature_category: :shared do
it_behaves_like 'authorized'
end
end
+
+ describe "attributes_for_keys" do
+ let(:hash) do
+ {
+ existing_key_with_present_value: 'actual value',
+ existing_key_with_nil_value: nil,
+ existing_key_with_false_value: false
+ }
+ end
+
+ let(:parameters) { ::ActionController::Parameters.new(hash) }
+ let(:symbol_keys) do
+ %i[
+ existing_key_with_present_value
+ existing_key_with_nil_value
+ existing_key_with_false_value
+ non_existing_key
+ ]
+ end
+
+ let(:string_keys) { symbol_keys.map(&:to_s) }
+ let(:filtered_attrs) do
+ {
+ 'existing_key_with_present_value' => 'actual value',
+ 'existing_key_with_false_value' => false
+ }
+ end
+
+ let(:empty_attrs) { {} }
+
+ where(:params, :keys, :attrs_result) do
+ ref(:hash) | ref(:symbol_keys) | ref(:filtered_attrs)
+ ref(:hash) | ref(:string_keys) | ref(:empty_attrs)
+ ref(:parameters) | ref(:symbol_keys) | ref(:filtered_attrs)
+ ref(:parameters) | ref(:string_keys) | ref(:filtered_attrs)
+ end
+
+ with_them do
+ it 'returns the values for given keys' do
+ expect(helper.attributes_for_keys(keys, params)).to eq(attrs_result)
+ end
+ end
+ end
end
diff --git a/spec/lib/api/ml/mlflow/api_helpers_spec.rb b/spec/lib/api/ml/mlflow/api_helpers_spec.rb
index 4f6a37c66c4..757a73ed612 100644
--- a/spec/lib/api/ml/mlflow/api_helpers_spec.rb
+++ b/spec/lib/api/ml/mlflow/api_helpers_spec.rb
@@ -37,4 +37,28 @@ RSpec.describe API::Ml::Mlflow::ApiHelpers, feature_category: :mlops do
it { is_expected.to eql("http://localhost/gitlab/root/api/v4/projects/#{user_project.id}/packages/generic") }
end
end
+
+ describe '#candidates_order_params' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { candidates_order_params(params) }
+
+ where(:input, :order_by, :order_by_type, :sort) do
+ '' | nil | nil | nil
+ 'created_at' | 'created_at' | 'column' | nil
+ 'created_at ASC' | 'created_at' | 'column' | 'ASC'
+ 'metrics.something' | 'something' | 'metric' | nil
+ 'metrics.something asc' | 'something' | 'metric' | 'asc'
+ 'metrics.something.blah asc' | 'something' | 'metric' | 'asc'
+ 'params.something ASC' | nil | nil | 'ASC'
+ 'metadata.something ASC' | nil | nil | 'ASC'
+ end
+ with_them do
+ let(:params) { { order_by: input } }
+
+ it 'is correct' do
+ is_expected.to include({ order_by: order_by, order_by_type: order_by_type, sort: sort })
+ end
+ end
+ end
end
diff --git a/spec/lib/backup/database_model_spec.rb b/spec/lib/backup/database_model_spec.rb
new file mode 100644
index 00000000000..5758ad2c1aa
--- /dev/null
+++ b/spec/lib/backup/database_model_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Backup::DatabaseModel, :reestablished_active_record_base, feature_category: :backup_restore do
+ let(:gitlab_database_name) { 'main' }
+
+ describe '#connection' do
+ subject { described_class.new(gitlab_database_name).connection }
+
+ it 'an instance of a ActiveRecord::Base.connection' do
+ subject.is_a? ActiveRecord::Base.connection.class # rubocop:disable Database/MultipleDatabases
+ end
+ end
+
+ describe '#config' do
+ let(:application_config) do
+ {
+ adapter: 'postgresql',
+ host: 'some_host',
+ port: '5432'
+ }
+ end
+
+ subject { described_class.new(gitlab_database_name).config }
+
+ before do
+ allow(
+ Gitlab::Database.database_base_models_with_gitlab_shared[gitlab_database_name].connection_db_config
+ ).to receive(:configuration_hash).and_return(application_config)
+ end
+
+ context 'when no GITLAB_BACKUP_PG* variables are set' do
+ it 'ActiveRecord backup configuration is expected to equal application configuration' do
+ expect(subject[:activerecord]).to eq(application_config)
+ end
+
+ it 'PostgreSQL ENV is expected to equal application configuration' do
+ expect(subject[:pg_env]).to eq(
+ {
+ 'PGHOST' => application_config[:host],
+ 'PGPORT' => application_config[:port]
+ }
+ )
+ end
+ end
+
+ context 'when GITLAB_BACKUP_PG* variables are set' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:env_variable, :overridden_value) do
+ 'GITLAB_BACKUP_PGHOST' | 'test.invalid.'
+ 'GITLAB_BACKUP_PGUSER' | 'some_user'
+ 'GITLAB_BACKUP_PGPORT' | '1543'
+ 'GITLAB_BACKUP_PGPASSWORD' | 'secret'
+ 'GITLAB_BACKUP_PGSSLMODE' | 'allow'
+ 'GITLAB_BACKUP_PGSSLKEY' | 'some_key'
+ 'GITLAB_BACKUP_PGSSLCERT' | '/path/to/cert'
+ 'GITLAB_BACKUP_PGSSLROOTCERT' | '/path/to/root/cert'
+ 'GITLAB_BACKUP_PGSSLCRL' | '/path/to/crl'
+ 'GITLAB_BACKUP_PGSSLCOMPRESSION' | '1'
+ end
+
+ with_them do
+ let(:pg_env) { env_variable[/GITLAB_BACKUP_(\w+)/, 1] }
+ let(:active_record_key) { described_class::SUPPORTED_OVERRIDES.invert[pg_env] }
+
+ before do
+ stub_env(env_variable, overridden_value)
+ end
+
+ it 'ActiveRecord backup configuration overrides application configuration' do
+ expect(subject[:activerecord]).to eq(application_config.merge(active_record_key => overridden_value))
+ end
+
+ it 'PostgreSQL ENV overrides application configuration' do
+ expect(subject[:pg_env]).to include({ pg_env => overridden_value })
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/backup/database_spec.rb b/spec/lib/backup/database_spec.rb
index 61e6c59a1a5..2f14b403576 100644
--- a/spec/lib/backup/database_spec.rb
+++ b/spec/lib/backup/database_spec.rb
@@ -2,13 +2,7 @@
require 'spec_helper'
-RSpec.configure do |rspec|
- rspec.expect_with :rspec do |c|
- c.max_formatted_output_length = nil
- end
-end
-
-RSpec.describe Backup::Database, feature_category: :backup_restore do
+RSpec.describe Backup::Database, :reestablished_active_record_base, feature_category: :backup_restore do
let(:progress) { StringIO.new }
let(:output) { progress.string }
let(:one_database_configured?) { base_models_for_backup.one? }
@@ -37,13 +31,6 @@ RSpec.describe Backup::Database, feature_category: :backup_restore do
subject { described_class.new(progress, force: force) }
- before do
- base_models_for_backup.each do |_, base_model|
- base_model.connection.rollback_transaction unless base_model.connection.open_transactions.zero?
- allow(base_model.connection).to receive(:execute).and_call_original
- end
- end
-
it 'creates gzipped database dumps' do
Dir.mktmpdir do |dir|
subject.dump(dir, backup_id)
@@ -62,14 +49,15 @@ RSpec.describe Backup::Database, feature_category: :backup_restore do
it 'uses snapshots' do
Dir.mktmpdir do |dir|
- base_model = Gitlab::Database.database_base_models['main']
- expect(base_model.connection).to receive(:begin_transaction).with(
- isolation: :repeatable_read
- ).and_call_original
- expect(base_model.connection).to receive(:select_value).with(
- "SELECT pg_export_snapshot()"
- ).and_call_original
- expect(base_model.connection).to receive(:rollback_transaction).and_call_original
+ expect_next_instances_of(Backup::DatabaseModel, 2) do |adapter|
+ expect(adapter.connection).to receive(:begin_transaction).with(
+ isolation: :repeatable_read
+ ).and_call_original
+ expect(adapter.connection).to receive(:select_value).with(
+ "SELECT pg_export_snapshot()"
+ ).and_call_original
+ expect(adapter.connection).to receive(:rollback_transaction).and_call_original
+ end
subject.dump(dir, backup_id)
end
@@ -95,7 +83,7 @@ RSpec.describe Backup::Database, feature_category: :backup_restore do
it 'does not use snapshots' do
Dir.mktmpdir do |dir|
- base_model = Gitlab::Database.database_base_models['main']
+ base_model = Backup::DatabaseModel.new('main')
expect(base_model.connection).not_to receive(:begin_transaction).with(
isolation: :repeatable_read
).and_call_original
@@ -111,7 +99,7 @@ RSpec.describe Backup::Database, feature_category: :backup_restore do
describe 'pg_dump arguments' do
let(:snapshot_id) { 'fake_id' }
- let(:pg_args) do
+ let(:default_pg_args) do
args = [
'--clean',
'--if-exists'
@@ -130,24 +118,35 @@ RSpec.describe Backup::Database, feature_category: :backup_restore do
before do
allow(Backup::Dump::Postgres).to receive(:new).and_return(dumper)
allow(dumper).to receive(:dump).with(any_args).and_return(true)
+ end
- base_models_for_backup.each do |_, base_model|
- allow(base_model.connection).to receive(:select_value).with(
- "SELECT pg_export_snapshot()"
- ).and_return(snapshot_id)
+ shared_examples 'pg_dump arguments' do
+ it 'calls Backup::Dump::Postgres with correct pg_dump arguments' do
+ number_of_databases = base_models_for_backup.count
+ if number_of_databases > 1
+ expect_next_instances_of(Backup::DatabaseModel, number_of_databases) do |model|
+ expect(model.connection).to receive(:select_value).with(
+ "SELECT pg_export_snapshot()"
+ ).and_return(snapshot_id)
+ end
+ end
+
+ expect(dumper).to receive(:dump).with(anything, anything, expected_pg_args)
+
+ subject.dump(destination_dir, backup_id)
end
end
- it 'calls Backup::Dump::Postgres with correct pg_dump arguments' do
- expect(dumper).to receive(:dump).with(anything, anything, pg_args)
+ context 'when no PostgreSQL schemas are specified' do
+ let(:expected_pg_args) { default_pg_args }
- subject.dump(destination_dir, backup_id)
+ include_examples 'pg_dump arguments'
end
context 'when a PostgreSQL schema is used' do
let(:schema) { 'gitlab' }
- let(:additional_args) do
- pg_args + ['-n', schema] + Gitlab::Database::EXTRA_SCHEMAS.flat_map do |schema|
+ let(:expected_pg_args) do
+ default_pg_args + ['-n', schema] + Gitlab::Database::EXTRA_SCHEMAS.flat_map do |schema|
['-n', schema.to_s]
end
end
@@ -156,11 +155,7 @@ RSpec.describe Backup::Database, feature_category: :backup_restore do
allow(Gitlab.config.backup).to receive(:pg_schema).and_return(schema)
end
- it 'calls Backup::Dump::Postgres with correct pg_dump arguments' do
- expect(dumper).to receive(:dump).with(anything, anything, additional_args)
-
- subject.dump(destination_dir, backup_id)
- end
+ include_examples 'pg_dump arguments'
end
end
@@ -180,6 +175,25 @@ RSpec.describe Backup::Database, feature_category: :backup_restore do
end
end
end
+
+ context 'when using GITLAB_BACKUP_* environment variables' do
+ before do
+ stub_env('GITLAB_BACKUP_PGHOST', 'test.invalid.')
+ end
+
+ it 'will override database.yml configuration' do
+ # Expect an error because we can't connect to test.invalid.
+ expect do
+ Dir.mktmpdir { |dir| subject.dump(dir, backup_id) }
+ end.to raise_error(Backup::DatabaseBackupError)
+
+ expect do
+ ApplicationRecord.connection.select_value('select 1')
+ end.not_to raise_error
+
+ expect(ENV['PGHOST']).to be_nil
+ end
+ end
end
describe '#restore' do
@@ -288,7 +302,7 @@ RSpec.describe Backup::Database, feature_category: :backup_restore do
expect(Rake::Task['gitlab:db:drop_tables:main']).to receive(:invoke)
end
- expect(ENV).to receive(:[]=).with('PGHOST', 'test.example.com')
+ expect(ENV).to receive(:merge!).with(hash_including { 'PGHOST' => 'test.example.com' })
expect(ENV).not_to receive(:[]=).with('PGPASSWORD', anything)
subject.restore(backup_dir)
diff --git a/spec/lib/backup/gitaly_backup_spec.rb b/spec/lib/backup/gitaly_backup_spec.rb
index 1105f39124b..6c2656b1c48 100644
--- a/spec/lib/backup/gitaly_backup_spec.rb
+++ b/spec/lib/backup/gitaly_backup_spec.rb
@@ -45,9 +45,9 @@ RSpec.describe Backup::GitalyBackup, feature_category: :backup_restore do
context 'create' do
RSpec.shared_examples 'creates a repository backup' do
it 'creates repository bundles', :aggregate_failures do
- # Add data to the wiki, design repositories, and snippets, so they will be included in the dump.
+ # Add data to the wiki, and snippets, so they will be included in the dump.
+ # Design repositories already have data through the factory :project_with_design
create(:wiki_page, container: project)
- create(:design, :with_file, issue: create(:issue, project: project))
project_snippet = create(:project_snippet, :repository, project: project)
personal_snippet = create(:personal_snippet, :repository, author: project.first_owner)
@@ -56,7 +56,7 @@ RSpec.describe Backup::GitalyBackup, feature_category: :backup_restore do
subject.start(:create, destination, backup_id: backup_id)
subject.enqueue(project, Gitlab::GlRepository::PROJECT)
subject.enqueue(project, Gitlab::GlRepository::WIKI)
- subject.enqueue(project, Gitlab::GlRepository::DESIGN)
+ subject.enqueue(project.design_management_repository, Gitlab::GlRepository::DESIGN)
subject.enqueue(personal_snippet, Gitlab::GlRepository::SNIPPET)
subject.enqueue(project_snippet, Gitlab::GlRepository::SNIPPET)
subject.finish!
@@ -126,13 +126,13 @@ RSpec.describe Backup::GitalyBackup, feature_category: :backup_restore do
end
context 'hashed storage' do
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
it_behaves_like 'creates a repository backup'
end
context 'legacy storage' do
- let_it_be(:project) { create(:project, :repository, :legacy_storage) }
+ let_it_be(:project) { create(:project_with_design, :repository, :legacy_storage) }
it_behaves_like 'creates a repository backup'
end
@@ -162,7 +162,7 @@ RSpec.describe Backup::GitalyBackup, feature_category: :backup_restore do
end
context 'restore' do
- let_it_be(:project) { create(:project, :repository, :design_repo) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
let_it_be(:personal_snippet) { create(:personal_snippet, author: project.first_owner) }
let_it_be(:project_snippet) { create(:project_snippet, project: project, author: project.first_owner) }
@@ -189,7 +189,7 @@ RSpec.describe Backup::GitalyBackup, feature_category: :backup_restore do
subject.start(:restore, destination, backup_id: backup_id)
subject.enqueue(project, Gitlab::GlRepository::PROJECT)
subject.enqueue(project, Gitlab::GlRepository::WIKI)
- subject.enqueue(project, Gitlab::GlRepository::DESIGN)
+ subject.enqueue(project.design_management_repository, Gitlab::GlRepository::DESIGN)
subject.enqueue(personal_snippet, Gitlab::GlRepository::SNIPPET)
subject.enqueue(project_snippet, Gitlab::GlRepository::SNIPPET)
subject.finish!
diff --git a/spec/lib/backup/repositories_spec.rb b/spec/lib/backup/repositories_spec.rb
index d8794ba68a0..1f3818de4a0 100644
--- a/spec/lib/backup/repositories_spec.rb
+++ b/spec/lib/backup/repositories_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
end
describe '#dump' do
- let_it_be(:projects) { create_list(:project, 5, :repository) }
+ let_it_be(:projects) { create_list(:project_with_design, 5, :repository) }
RSpec.shared_examples 'creates repository bundles' do
it 'calls enqueue for each repository type', :aggregate_failures do
@@ -34,7 +34,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).to have_received(:start).with(:create, destination, backup_id: backup_id)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:enqueue).with(project_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:finish!)
@@ -42,13 +42,13 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
end
context 'hashed storage' do
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
it_behaves_like 'creates repository bundles'
end
context 'legacy storage' do
- let_it_be(:project) { create(:project, :repository, :legacy_storage) }
+ let_it_be(:project) { create(:project_with_design, :repository, :legacy_storage) }
it_behaves_like 'creates repository bundles'
end
@@ -75,15 +75,19 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
create_list(:project, 2, :repository)
create_list(:snippet, 2, :repository)
+ # Number of expected queries are 2 more than control_count
+ # to account for the queries for project.design_management_repository
+ # for each project.
+ # We are using 2 projects here.
expect do
subject.dump(destination, backup_id)
- end.not_to exceed_query_limit(control_count)
+ end.not_to exceed_query_limit(control_count + 2)
end
describe 'storages' do
let(:storages) { %w{default} }
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
before do
stub_storage_settings('test_second_storage' => {
@@ -93,7 +97,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
end
it 'calls enqueue for all repositories on the specified storage', :aggregate_failures do
- excluded_project = create(:project, :repository, repository_storage: 'test_second_storage')
+ excluded_project = create(:project_with_design, :repository, repository_storage: 'test_second_storage')
excluded_project_snippet = create(:project_snippet, :repository, project: excluded_project)
excluded_project_snippet.track_snippet_repository('test_second_storage')
excluded_personal_snippet = create(:personal_snippet, :repository, author: excluded_project.first_owner)
@@ -107,13 +111,13 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).not_to have_received(:enqueue).with(excluded_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
describe 'paths' do
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
context 'project path' do
let(:paths) { [project.full_path] }
@@ -131,7 +135,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).not_to have_received(:enqueue).with(excluded_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
@@ -152,14 +156,14 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).not_to have_received(:enqueue).with(excluded_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
end
describe 'skip_paths' do
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
let_it_be(:excluded_project) { create(:project, :repository) }
context 'project path' do
@@ -177,7 +181,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).to have_received(:enqueue).with(included_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
@@ -197,7 +201,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).to have_received(:enqueue).with(included_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
@@ -205,7 +209,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
end
describe '#restore' do
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: project.first_owner) }
let_it_be(:project_snippet) { create(:project_snippet, :repository, project: project, author: project.first_owner) }
@@ -216,7 +220,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).to have_received(:start).with(:restore, destination, remove_all_repositories: %w[default])
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:enqueue).with(project_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:finish!)
@@ -300,7 +304,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).not_to have_received(:enqueue).with(excluded_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
@@ -322,7 +326,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).not_to have_received(:enqueue).with(excluded_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
@@ -343,7 +347,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).not_to have_received(:enqueue).with(excluded_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
@@ -367,7 +371,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).to have_received(:enqueue).with(included_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
@@ -387,7 +391,7 @@ RSpec.describe Backup::Repositories, feature_category: :backup_restore do
expect(strategy).to have_received(:enqueue).with(included_personal_snippet, Gitlab::GlRepository::SNIPPET)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::PROJECT)
expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::WIKI)
- expect(strategy).to have_received(:enqueue).with(project, Gitlab::GlRepository::DESIGN)
+ expect(strategy).to have_received(:enqueue).with(project.design_management_repository, Gitlab::GlRepository::DESIGN)
expect(strategy).to have_received(:finish!)
end
end
diff --git a/spec/lib/banzai/filter/code_language_filter_spec.rb b/spec/lib/banzai/filter/code_language_filter_spec.rb
index 25f844ee575..d6be088eaff 100644
--- a/spec/lib/banzai/filter/code_language_filter_spec.rb
+++ b/spec/lib/banzai/filter/code_language_filter_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Banzai::Filter::CodeLanguageFilter, feature_category: :team_plann
end
end
- context 'when lang is specified' do
+ context 'when lang is specified on `pre`' do
it 'adds data-canonical-lang and removes lang attribute' do
result = filter('<pre lang="ruby"><code>def fun end</code></pre>')
@@ -36,19 +36,39 @@ RSpec.describe Banzai::Filter::CodeLanguageFilter, feature_category: :team_plann
end
end
- context 'when lang has extra params' do
- let(:lang_params) { 'foo-bar-kux' }
- let(:xss_lang) { %(ruby data-meta="foo-bar-kux"&lt;script&gt;alert(1)&lt;/script&gt;) }
+ context 'when lang is specified on `code`' do
+ it 'adds data-canonical-lang to `pre` and removes lang attribute' do
+ result = filter('<pre><code lang="ruby">def fun end</code></pre>')
+
+ expect(result.to_html.delete("\n"))
+ .to eq('<pre data-canonical-lang="ruby"><code>def fun end</code></pre>')
+ end
+ end
- it 'includes data-lang-params tag with extra information and removes data-meta' do
- expected_result = <<~HTML
+ context 'when lang has extra params' do
+ let_it_be(:lang_params) { 'foo-bar-kux' }
+ let_it_be(:xss_lang) { %(ruby data-meta="foo-bar-kux"&lt;script&gt;alert(1)&lt;/script&gt;) }
+ let_it_be(:expected_result) do
+ <<~HTML
<pre data-canonical-lang="ruby" data-lang-params="#{lang_params}">
<code>This is a test</code></pre>
HTML
+ end
+
+ context 'when lang is specified on `pre`' do
+ it 'includes data-lang-params tag with extra information and removes data-meta' do
+ result = filter(%(<pre lang="ruby" data-meta="#{lang_params}"><code>This is a test</code></pre>))
+
+ expect(result.to_html.delete("\n")).to eq(expected_result.delete("\n"))
+ end
+ end
- result = filter(%(<pre lang="ruby" data-meta="#{lang_params}"><code>This is a test</code></pre>))
+ context 'when lang is specified on `code`' do
+ it 'includes data-lang-params tag with extra information and removes data-meta' do
+ result = filter(%(<pre><code lang="ruby" data-meta="#{lang_params}">This is a test</code></pre>))
- expect(result.to_html.delete("\n")).to eq(expected_result.delete("\n"))
+ expect(result.to_html.delete("\n")).to eq(expected_result.delete("\n"))
+ end
end
include_examples 'XSS prevention', 'ruby'
diff --git a/spec/lib/banzai/filter/inline_diff_filter_spec.rb b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
index 1388a9053d9..89ee17837e0 100644
--- a/spec/lib/banzai/filter/inline_diff_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Banzai::Filter::InlineDiffFilter do
+RSpec.describe Banzai::Filter::InlineDiffFilter, feature_category: :source_code_management do
include FilterSpecHelper
it 'adds inline diff span tags for deletions when using square brackets' do
diff --git a/spec/lib/bitbucket/representation/pull_request_spec.rb b/spec/lib/bitbucket/representation/pull_request_spec.rb
index f39222805d0..9ebf59ecf82 100644
--- a/spec/lib/bitbucket/representation/pull_request_spec.rb
+++ b/spec/lib/bitbucket/representation/pull_request_spec.rb
@@ -56,4 +56,55 @@ RSpec.describe Bitbucket::Representation::PullRequest, feature_category: :import
describe '#updated_at' do
it { expect(described_class.new('updated_on' => '2023-01-01').updated_at).to eq('2023-01-01') }
end
+
+ describe '#merge_commit_sha' do
+ it { expect(described_class.new('merge_commit' => { 'hash' => 'SHA' }).merge_commit_sha).to eq('SHA') }
+ it { expect(described_class.new({}).merge_commit_sha).to be_nil }
+ end
+
+ describe '#to_hash' do
+ it do
+ raw = {
+ 'id' => 11,
+ 'description' => 'description',
+ 'author' => { 'nickname' => 'user-1' },
+ 'state' => 'MERGED',
+ 'created_on' => 'created-at',
+ 'updated_on' => 'updated-at',
+ 'title' => 'title',
+ 'source' => {
+ 'branch' => { 'name' => 'source-branch-name' },
+ 'commit' => { 'hash' => 'source-commit-hash' }
+ },
+ 'destination' => {
+ 'branch' => { 'name' => 'destination-branch-name' },
+ 'commit' => { 'hash' => 'destination-commit-hash' }
+ },
+ 'merge_commit' => { 'hash' => 'merge-commit-hash' },
+ 'reviewers' => [
+ {
+ 'username' => 'user-2'
+ }
+ ]
+ }
+
+ expected_hash = {
+ author: 'user-1',
+ created_at: 'created-at',
+ description: 'description',
+ iid: 11,
+ source_branch_name: 'source-branch-name',
+ source_branch_sha: 'source-commit-hash',
+ merge_commit_sha: 'merge-commit-hash',
+ state: 'merged',
+ target_branch_name: 'destination-branch-name',
+ target_branch_sha: 'destination-commit-hash',
+ title: 'title',
+ updated_at: 'updated-at',
+ reviewers: ['user-2']
+ }
+
+ expect(described_class.new(raw).to_hash).to eq(expected_hash)
+ end
+ end
end
diff --git a/spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb b/spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb
index bcc2d6fd5ed..4a97e092141 100644
--- a/spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb
+++ b/spec/lib/bulk_imports/common/graphql/get_members_query_spec.rb
@@ -41,7 +41,17 @@ RSpec.describe BulkImports::Common::Graphql::GetMembersQuery, feature_category:
it 'queries group & group members' do
expect(query.to_s).to include('group')
expect(query.to_s).to include('groupMembers')
- expect(query.to_s).to include('SHARED_FROM_GROUPS')
+ expect(query.to_s).to include('DIRECT INHERITED')
+ end
+
+ context "when source version is past 14.7.0" do
+ before do
+ entity.bulk_import.update!(source_version: "14.8.0")
+ end
+
+ it 'includes SHARED_FROM_GROUPS' do
+ expect(query.to_s).to include('DIRECT INHERITED SHARED_FROM_GROUPS')
+ end
end
end
@@ -51,7 +61,17 @@ RSpec.describe BulkImports::Common::Graphql::GetMembersQuery, feature_category:
it 'queries project & project members' do
expect(query.to_s).to include('project')
expect(query.to_s).to include('projectMembers')
- expect(query.to_s).to include('INVITED_GROUPS SHARED_INTO_ANCESTORS')
+ expect(query.to_s).to include('DIRECT INHERITED INVITED_GROUPS')
+ end
+
+ context "when source version is at least 16.0.0" do
+ before do
+ entity.bulk_import.update!(source_version: "16.0.0")
+ end
+
+ it 'includes SHARED_INTO_ANCESTORS' do
+ expect(query.to_s).to include('DIRECT INHERITED INVITED_GROUPS SHARED_INTO_ANCESTORS')
+ end
end
end
end
diff --git a/spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb b/spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb
index dc17dc594a8..8ca74565788 100644
--- a/spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb
+++ b/spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-RSpec.describe BulkImports::Common::Pipelines::EntityFinisher do
+RSpec.describe BulkImports::Common::Pipelines::EntityFinisher, feature_category: :importers do
it 'updates the entity status to finished' do
- entity = create(:bulk_import_entity, :started)
+ entity = create(:bulk_import_entity, :project_entity, :started)
pipeline_tracker = create(:bulk_import_tracker, entity: entity)
context = BulkImports::Pipeline::Context.new(pipeline_tracker)
subject = described_class.new(context)
@@ -24,7 +24,7 @@ RSpec.describe BulkImports::Common::Pipelines::EntityFinisher do
)
end
- expect(context.portable).to receive(:try).with(:after_import)
+ expect(BulkImports::FinishProjectImportWorker).to receive(:perform_async).with(entity.project_id)
expect { subject.run }
.to change(entity, :status_name).to(:finished)
diff --git a/spec/lib/bulk_imports/common/transformers/member_attributes_transformer_spec.rb b/spec/lib/bulk_imports/common/transformers/member_attributes_transformer_spec.rb
index 1c9ed4f0f97..4565de32c70 100644
--- a/spec/lib/bulk_imports/common/transformers/member_attributes_transformer_spec.rb
+++ b/spec/lib/bulk_imports/common/transformers/member_attributes_transformer_spec.rb
@@ -85,14 +85,15 @@ RSpec.describe BulkImports::Common::Transformers::MemberAttributesTransformer, f
end
end
- describe 'source user id caching' do
+ describe 'source user id and username caching' do
context 'when user gid is present' do
- it 'caches source user id' do
+ it 'caches source user id and username' do
gid = 'gid://gitlab/User/7'
data = member_data(email: user.email, gid: gid)
expect_next_instance_of(BulkImports::UsersMapper) do |mapper|
expect(mapper).to receive(:cache_source_user_id).with('7', user.id)
+ expect(mapper).to receive(:cache_source_username).with('source_username', user.username)
end
subject.transform(context, data)
@@ -108,6 +109,35 @@ RSpec.describe BulkImports::Common::Transformers::MemberAttributesTransformer, f
subject.transform(context, data)
end
end
+
+ context 'when username is nil' do
+ it 'caches source user id only' do
+ gid = 'gid://gitlab/User/7'
+ data = nil_username_member_data(email: user.email, gid: gid)
+
+ expect_next_instance_of(BulkImports::UsersMapper) do |mapper|
+ expect(mapper).to receive(:cache_source_user_id).with('7', user.id)
+ expect(mapper).not_to receive(:cache_source_username)
+ end
+
+ subject.transform(context, data)
+ end
+ end
+
+ context 'when source username matches destination username' do
+ it 'caches source user id only' do
+ gid = 'gid://gitlab/User/7'
+ data = member_data(email: user.email, gid: gid)
+ data["user"]["username"] = user.username
+
+ expect_next_instance_of(BulkImports::UsersMapper) do |mapper|
+ expect(mapper).to receive(:cache_source_user_id).with('7', user.id)
+ expect(mapper).not_to receive(:cache_source_username)
+ end
+
+ subject.transform(context, data)
+ end
+ end
end
end
end
@@ -136,7 +166,24 @@ RSpec.describe BulkImports::Common::Transformers::MemberAttributesTransformer, f
},
'user' => {
'user_gid' => gid,
- 'public_email' => email
+ 'public_email' => email,
+ 'username' => 'source_username'
+ }
+ }
+ end
+
+ def nil_username_member_data(email: '', gid: nil, access_level: 30)
+ {
+ 'created_at' => '2020-01-01T00:00:00Z',
+ 'updated_at' => '2020-01-01T00:00:00Z',
+ 'expires_at' => nil,
+ 'access_level' => {
+ 'integer_value' => access_level
+ },
+ 'user' => {
+ 'user_gid' => gid,
+ 'public_email' => email,
+ 'username' => nil
}
}
end
diff --git a/spec/lib/bulk_imports/file_downloads/validations_spec.rb b/spec/lib/bulk_imports/file_downloads/validations_spec.rb
index 85f45c2a8f0..95f3f78310f 100644
--- a/spec/lib/bulk_imports/file_downloads/validations_spec.rb
+++ b/spec/lib/bulk_imports/file_downloads/validations_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::FileDownloads::Validations do
+RSpec.describe BulkImports::FileDownloads::Validations, feature_category: :importers do
let(:dummy_instance) { dummy_class.new }
let(:dummy_class) do
Class.new do
diff --git a/spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb b/spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb
index 7d1f9ae5da0..87b64ef198e 100644
--- a/spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb
+++ b/spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb
@@ -84,6 +84,33 @@ RSpec.describe BulkImports::Groups::Loaders::GroupLoader, feature_category: :imp
include_examples 'calls Group Create Service to create a new group'
end
+
+ context 'when user does not have 2FA enabled' do
+ before do
+ allow(user).to receive(:two_factor_enabled?).and_return(false)
+ end
+
+ context 'when require_two_factor_authentication is not passed' do
+ include_examples 'calls Group Create Service to create a new group'
+ end
+
+ context 'when require_two_factor_authentication is false' do
+ let(:data) { { 'require_two_factor_authentication' => false, 'path' => 'test' } }
+
+ include_examples 'calls Group Create Service to create a new group'
+ end
+
+ context 'when require_two_factor_authentication is true' do
+ let(:data) { { 'require_two_factor_authentication' => true, 'path' => 'test' } }
+
+ it 'does not create new group' do
+ expect(::Groups::CreateService).not_to receive(:new)
+
+ expect { subject.load(context, data) }
+ .to raise_error(described_class::GroupCreationError, 'User requires Two-Factor Authentication')
+ end
+ end
+ end
end
context 'when user cannot create group' do
diff --git a/spec/lib/bulk_imports/network_error_spec.rb b/spec/lib/bulk_imports/network_error_spec.rb
index 54d6554df96..d5e2b739c8f 100644
--- a/spec/lib/bulk_imports/network_error_spec.rb
+++ b/spec/lib/bulk_imports/network_error_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::NetworkError, :clean_gitlab_redis_cache do
+RSpec.describe BulkImports::NetworkError, :clean_gitlab_redis_cache, feature_category: :importers do
let(:tracker) { double(id: 1, stage: 2, entity: double(id: 3)) }
describe '.new' do
@@ -65,10 +65,32 @@ RSpec.describe BulkImports::NetworkError, :clean_gitlab_redis_cache do
end
describe '#retry_delay' do
- it 'returns the default value when there is not a rate limit error' do
- exception = described_class.new('foo')
+ context 'when the exception is not a rate limit error' do
+ let(:exception) { described_class.new('Error!') }
- expect(exception.retry_delay).to eq(described_class::DEFAULT_RETRY_DELAY_SECONDS.seconds)
+ it 'returns the default value' do
+ expect(exception.retry_delay).to eq(described_class::DEFAULT_RETRY_DELAY_SECONDS.seconds)
+ end
+
+ context 'when the exception is a decompression error' do
+ before do
+ allow(exception).to receive(:cause).and_return(Zlib::Error.new('Error!'))
+ end
+
+ it 'returns the exception delay value' do
+ expect(exception.retry_delay).to eq(60.seconds)
+ end
+ end
+
+ context 'when the exception is a no space left error' do
+ before do
+ allow(exception).to receive(:cause).and_return(Errno::ENOSPC.new('Error!'))
+ end
+
+ it 'returns the exception delay value' do
+ expect(exception.retry_delay).to eq(120.seconds)
+ end
+ end
end
context 'when the exception is a rate limit error' do
diff --git a/spec/lib/bulk_imports/pipeline/runner_spec.rb b/spec/lib/bulk_imports/pipeline/runner_spec.rb
index e66f2d26911..2f54ab111c8 100644
--- a/spec/lib/bulk_imports/pipeline/runner_spec.rb
+++ b/spec/lib/bulk_imports/pipeline/runner_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::Pipeline::Runner do
+RSpec.describe BulkImports::Pipeline::Runner, feature_category: :importers do
let(:extractor) do
Class.new do
def initialize(options = {}); end
diff --git a/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb
index a0789522ea8..fd13c10d61e 100644
--- a/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/projects/pipelines/issues_pipeline_spec.rb
@@ -164,6 +164,40 @@ RSpec.describe BulkImports::Projects::Pipelines::IssuesPipeline do
expect(note.award_emoji.first.name).to eq('clapper')
end
end
+
+ context "when importing an issue with one award emoji and other relations with one item" do
+ let(:issue_attributes) do
+ {
+ "notes" => [
+ {
+ 'note' => 'Description changed',
+ 'author_id' => 22,
+ 'author' => {
+ 'name' => 'User 22'
+ },
+ 'updated_at' => '2016-06-14T15:02:47.770Z'
+ }
+ ],
+ 'award_emoji' => [
+ {
+ 'name' => 'thumbsup',
+ 'user_id' => 22
+ }
+ ]
+ }
+ end
+
+ it 'saves properly' do
+ issue = project.issues.last
+ notes = issue.notes
+
+ aggregate_failures do
+ expect(notes.count).to eq 1
+ expect(notes[0].note).to include("Description changed")
+ expect(issue.award_emoji.first.name).to eq "thumbsup"
+ end
+ end
+ end
end
end
end
diff --git a/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb
index 3a808851f81..af8bce47c3d 100644
--- a/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
create(
:merge_request,
source_project: project,
- description: 'https://my.gitlab.com/source/full/path/-/merge_requests/1'
+ description: 'https://my.gitlab.com/source/full/path/-/merge_requests/1 @source_username? @bob, @alice!'
)
end
@@ -33,7 +33,7 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
:note,
project: project,
noteable: issue,
- note: 'https://my.gitlab.com/source/full/path/-/issues/1'
+ note: 'https://my.gitlab.com/source/full/path/-/issues/1 @older_username, not_a@username, and @old_username.'
)
end
@@ -42,7 +42,16 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
:note,
project: project,
noteable: mr,
- note: 'https://my.gitlab.com/source/full/path/-/merge_requests/1'
+ note: 'https://my.gitlab.com/source/full/path/-/merge_requests/1 @same_username'
+ )
+ end
+
+ let(:interchanged_usernames) do
+ create(
+ :note,
+ project: project,
+ noteable: mr,
+ note: '@manuelgrabowski-admin, @boaty-mc-boatface'
)
end
@@ -53,19 +62,48 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
project: project,
system: true,
noteable: issue,
- note: "mentioned in merge request !#{mr.iid}",
+ note: "mentioned in merge request !#{mr.iid} created by @old_username",
note_html: old_note_html
)
end
+ let(:username_system_note) do
+ create(
+ :note,
+ project: project,
+ system: true,
+ noteable: issue,
+ note: "mentioned in merge request created by @source_username.",
+ note_html: 'empty'
+ )
+ end
+
subject(:pipeline) { described_class.new(context) }
before do
project.add_owner(user)
+
+ allow(Gitlab::Cache::Import::Caching)
+ .to receive(:values_from_hash)
+ .and_return({
+ 'old_username' => 'new_username',
+ 'older_username' => 'newer_username',
+ 'source_username' => 'destination_username',
+ 'bob' => 'alice-gdk',
+ 'alice' => 'bob-gdk',
+ 'manuelgrabowski' => 'manuelgrabowski-admin',
+ 'manuelgrabowski-admin' => 'manuelgrabowski',
+ 'boaty-mc-boatface' => 'boatymcboatface',
+ 'boatymcboatface' => 'boaty-mc-boatface'
+ })
end
def create_project_data
- [issue, mr, issue_note, mr_note, system_note]
+ [issue, mr, issue_note, mr_note, system_note, username_system_note]
+ end
+
+ def create_username_project_data
+ [username_system_note]
end
describe '#extract' do
@@ -75,11 +113,14 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
extracted_data = subject.extract(context)
expect(extracted_data).to be_instance_of(BulkImports::Pipeline::ExtractedData)
- expect(extracted_data.data).to contain_exactly(issue_note, mr, issue, mr_note)
+ expect(extracted_data.data).to contain_exactly(issue, mr, issue_note, system_note, username_system_note, mr_note)
expect(system_note.note_html).not_to eq(old_note_html)
expect(system_note.note_html)
- .to include("class=\"gfm gfm-merge_request\">!#{mr.iid}</a></p>")
+ .to include("class=\"gfm gfm-merge_request\">!#{mr.iid}</a>")
.and include(project.full_path.to_s)
+ .and include("@old_username")
+ expect(username_system_note.note_html)
+ .to include("@source_username")
end
context 'when object body is nil' do
@@ -94,9 +135,13 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
end
describe '#transform' do
- it 'updates matching urls with new ones' do
+ it 'updates matching urls and usernames with new ones' do
transformed_mr = subject.transform(context, mr)
transformed_note = subject.transform(context, mr_note)
+ transformed_issue = subject.transform(context, issue)
+ transformed_issue_note = subject.transform(context, issue_note)
+ transformed_system_note = subject.transform(context, system_note)
+ transformed_username_system_note = subject.transform(context, username_system_note)
expected_url = URI('')
expected_url.scheme = ::Gitlab.config.gitlab.https ? 'https' : 'http'
@@ -104,11 +149,44 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
expected_url.port = ::Gitlab.config.gitlab.port
expected_url.path = "/#{project.full_path}/-/merge_requests/#{mr.iid}"
- expect(transformed_mr.description).to eq(expected_url.to_s)
- expect(transformed_note.note).to eq(expected_url.to_s)
+ expect(transformed_issue_note.note).not_to include("@older_username")
+ expect(transformed_mr.description).not_to include("@source_username")
+ expect(transformed_system_note.note).not_to include("@old_username")
+ expect(transformed_username_system_note.note).not_to include("@source_username")
+
+ expect(transformed_issue.description).to eq('http://localhost:80/namespace1/project-1/-/issues/1')
+ expect(transformed_mr.description).to eq("#{expected_url} @destination_username? @alice-gdk, @bob-gdk!")
+ expect(transformed_note.note).to eq("#{expected_url} @same_username")
+ expect(transformed_issue_note.note).to include("@newer_username, not_a@username, and @new_username.")
+ expect(transformed_system_note.note).to eq("mentioned in merge request !#{mr.iid} created by @new_username")
+ expect(transformed_username_system_note.note).to include("@destination_username.")
end
- context 'when object does not have reference' do
+ it 'handles situations where old usernames are substrings of new usernames' do
+ transformed_mr = subject.transform(context, mr)
+
+ expect(transformed_mr.description).to include("@alice-gdk")
+ expect(transformed_mr.description).not_to include("@bob-gdk-gdk")
+ end
+
+ it 'handles situations where old and new usernames are interchanged' do
+ # e.g
+ # |------------------------|-------------------------|
+ # | old_username | new_username |
+ # |------------------------|-------------------------|
+ # | @manuelgrabowski-admin | @manuelgrabowski |
+ # | @manuelgrabowski | @manuelgrabowski-admin |
+ # |------------------------|-------------------------|
+
+ transformed_interchanged_usernames = subject.transform(context, interchanged_usernames)
+
+ expect(transformed_interchanged_usernames.note).to include("@manuelgrabowski")
+ expect(transformed_interchanged_usernames.note).to include("@boatymcboatface")
+ expect(transformed_interchanged_usernames.note).not_to include("@manuelgrabowski-admin")
+ expect(transformed_interchanged_usernames.note).not_to include("@boaty-mc-boatface")
+ end
+
+ context 'when object does not have reference or username' do
it 'returns object unchanged' do
issue.update!(description: 'foo')
@@ -118,35 +196,35 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
end
end
- context 'when there are not matched urls' do
- let(:url) { 'https://my.gitlab.com/another/project/path/-/issues/1' }
+ context 'when there are not matched urls or usernames' do
+ let(:description) { 'https://my.gitlab.com/another/project/path/-/issues/1 @random_username' }
shared_examples 'returns object unchanged' do
it 'returns object unchanged' do
- issue.update!(description: url)
+ issue.update!(description: description)
transformed_issue = subject.transform(context, issue)
- expect(transformed_issue.description).to eq(url)
+ expect(transformed_issue.description).to eq(description)
end
end
include_examples 'returns object unchanged'
context 'when url path does not start with source full path' do
- let(:url) { 'https://my.gitlab.com/another/source/full/path/-/issues/1' }
+ let(:description) { 'https://my.gitlab.com/another/source/full/path/-/issues/1' }
include_examples 'returns object unchanged'
end
context 'when host does not match and url path starts with source full path' do
- let(:url) { 'https://another.gitlab.com/source/full/path/-/issues/1' }
+ let(:description) { 'https://another.gitlab.com/source/full/path/-/issues/1' }
include_examples 'returns object unchanged'
end
context 'when url does not match at all' do
- let(:url) { 'https://website.example/foo/bar' }
+ let(:description) { 'https://website.example/foo/bar' }
include_examples 'returns object unchanged'
end
@@ -156,13 +234,22 @@ RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline, feature_cat
describe '#load' do
it 'saves the object when object body changed' do
transformed_issue = subject.transform(context, issue)
- transformed_note = subject.transform(context, issue_note)
+ transformed_note = subject.transform(context, mr_note)
+ transformed_mr = subject.transform(context, mr)
+ transformed_issue_note = subject.transform(context, issue_note)
+ transformed_system_note = subject.transform(context, system_note)
expect(transformed_issue).to receive(:save!)
expect(transformed_note).to receive(:save!)
+ expect(transformed_mr).to receive(:save!)
+ expect(transformed_issue_note).to receive(:save!)
+ expect(transformed_system_note).to receive(:save!)
subject.load(context, transformed_issue)
subject.load(context, transformed_note)
+ subject.load(context, transformed_mr)
+ subject.load(context, transformed_issue_note)
+ subject.load(context, transformed_system_note)
end
context 'when object body is not changed' do
diff --git a/spec/lib/bulk_imports/users_mapper_spec.rb b/spec/lib/bulk_imports/users_mapper_spec.rb
index e6357319d05..dc2beb42080 100644
--- a/spec/lib/bulk_imports/users_mapper_spec.rb
+++ b/spec/lib/bulk_imports/users_mapper_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkImports::UsersMapper do
+RSpec.describe BulkImports::UsersMapper, feature_category: :importers do
let_it_be(:user) { create(:user) }
let_it_be(:import) { create(:bulk_import, user: user) }
let_it_be(:entity) { create(:bulk_import_entity, bulk_import: import) }
@@ -34,6 +34,22 @@ RSpec.describe BulkImports::UsersMapper do
end
end
+ describe '#map_usernames' do
+ context 'when value for specified key exists' do
+ it 'returns a map of source & destination usernames from redis' do
+ allow(Gitlab::Cache::Import::Caching).to receive(:values_from_hash).and_return({ "source_username" => "destination_username" })
+
+ expect(subject.map_usernames).to eq({ "source_username" => "destination_username" })
+ end
+ end
+
+ context 'when value for specified key does not exist' do
+ it 'returns nil' do
+ expect(subject.map_usernames[:non_existent_key]).to be_nil
+ end
+ end
+ end
+
describe '#default_user_id' do
it 'returns current user id' do
expect(subject.default_user_id).to eq(user.id)
@@ -65,4 +81,12 @@ RSpec.describe BulkImports::UsersMapper do
subject.cache_source_user_id(1, 2)
end
end
+
+ describe '#cache_source_username' do
+ it 'caches provided source & destination usernames in redis' do
+ expect(Gitlab::Cache::Import::Caching).to receive(:hash_add).with("bulk_imports/#{import.id}/#{entity.id}/source_usernames", 'source', 'destination')
+
+ subject.cache_source_username('source', 'destination')
+ end
+ end
end
diff --git a/spec/lib/click_house/bind_index_manager_spec.rb b/spec/lib/click_house/bind_index_manager_spec.rb
deleted file mode 100644
index 1c659017c63..00000000000
--- a/spec/lib/click_house/bind_index_manager_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ClickHouse::BindIndexManager, feature_category: :database do
- describe '#next_bind_str' do
- context 'when initialized without a start index' do
- let(:bind_manager) { described_class.new }
-
- it 'starts from index 1 by default' do
- expect(bind_manager.next_bind_str).to eq('$1')
- end
-
- it 'increments the bind string on subsequent calls' do
- bind_manager.next_bind_str
- expect(bind_manager.next_bind_str).to eq('$2')
- end
- end
-
- context 'when initialized with a start index' do
- let(:bind_manager) { described_class.new(2) }
-
- it 'starts from the given index' do
- expect(bind_manager.next_bind_str).to eq('$2')
- end
-
- it 'increments the bind string on subsequent calls' do
- bind_manager.next_bind_str
- expect(bind_manager.next_bind_str).to eq('$3')
- end
- end
- end
-end
diff --git a/spec/lib/click_house/query_builder_spec.rb b/spec/lib/click_house/query_builder_spec.rb
index 9e3f1118eeb..f5e1d53e7c1 100644
--- a/spec/lib/click_house/query_builder_spec.rb
+++ b/spec/lib/click_house/query_builder_spec.rb
@@ -288,7 +288,8 @@ RSpec.describe ClickHouse::QueryBuilder, feature_category: :database do
describe '#to_redacted_sql' do
it 'calls ::ClickHouse::Redactor correctly' do
- expect(::ClickHouse::Redactor).to receive(:redact).with(builder)
+ expect(::ClickHouse::Redactor).to receive(:redact).with(builder,
+ an_instance_of(ClickHouse::Client::BindIndexManager))
builder.to_redacted_sql
end
@@ -331,4 +332,27 @@ RSpec.describe ClickHouse::QueryBuilder, feature_category: :database do
expect(sql).to eq(expected_sql)
end
end
+
+ context 'when combining with a raw query' do
+ it 'correctly generates the SQL query' do
+ raw_query = 'SELECT * FROM isues WHERE title = {title:String} AND id IN ({query:Subquery})'
+ placeholders = {
+ title: "'test'",
+ query: builder.select(:id).where(column1: 'value1', column2: 'value2')
+ }
+
+ query = ClickHouse::Client::Query.new(raw_query: raw_query, placeholders: placeholders)
+ expected_sql = "SELECT * FROM isues WHERE title = {title:String} AND id IN (SELECT \"test_table\".\"id\" " \
+ "FROM \"test_table\" WHERE \"test_table\".\"column1\" = 'value1' AND " \
+ "\"test_table\".\"column2\" = 'value2')"
+
+ expect(query.to_sql).to eq(expected_sql)
+
+ expected_redacted_sql = "SELECT * FROM isues WHERE title = $1 AND id IN (SELECT \"test_table\".\"id\" " \
+ "FROM \"test_table\" WHERE \"test_table\".\"column1\" = $2 AND " \
+ "\"test_table\".\"column2\" = $3)"
+
+ expect(query.to_redacted_sql).to eq(expected_redacted_sql)
+ end
+ end
end
diff --git a/spec/lib/click_house/record_sync_context_spec.rb b/spec/lib/click_house/record_sync_context_spec.rb
new file mode 100644
index 00000000000..7873796cd9c
--- /dev/null
+++ b/spec/lib/click_house/record_sync_context_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ClickHouse::RecordSyncContext, feature_category: :value_stream_management do
+ let(:records) { [Issue.new(id: 1), Issue.new(id: 2), Issue.new(id: 3), Issue.new(id: 4)] }
+
+ subject(:sync_context) { described_class.new(last_record_id: 0, max_records_per_batch: 3) }
+
+ it 'allows processing 3 records per batch' do
+ records.take(3).each do |record|
+ sync_context.last_processed_id = record.id
+ end
+
+ expect(sync_context).to be_record_limit_reached
+ expect(sync_context.last_processed_id).to eq(3)
+
+ expect { sync_context.new_batch! }.to change { sync_context.record_count_in_current_batch }.from(3).to(0)
+
+ expect(sync_context).not_to be_record_limit_reached
+
+ records.take(3).each do |record|
+ sync_context.last_processed_id = record.id
+ end
+
+ expect(sync_context).to be_record_limit_reached
+ end
+
+ it 'sets the no more records flag' do
+ expect { sync_context.no_more_records! }.to change { sync_context.no_more_records? }.from(false).to(true)
+ end
+end
diff --git a/spec/lib/click_house/sync_cursor_spec.rb b/spec/lib/click_house/sync_cursor_spec.rb
new file mode 100644
index 00000000000..43ffaa76e1d
--- /dev/null
+++ b/spec/lib/click_house/sync_cursor_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ClickHouse::SyncCursor, feature_category: :value_stream_management, click_house: {} do
+ def value
+ ClickHouse::SyncCursor.cursor_for(:my_table)
+ end
+
+ context 'when cursor is empty' do
+ it 'returns the default value: 0' do
+ expect(value).to eq(0)
+ end
+ end
+
+ context 'when cursor is present' do
+ it 'updates and returns the current cursor value' do
+ described_class.update_cursor_for(:my_table, 1111)
+
+ expect(value).to eq(1111)
+
+ described_class.update_cursor_for(:my_table, 2222)
+
+ expect(value).to eq(2222)
+ end
+ end
+
+ context 'when updating a different cursor' do
+ it 'does not affect the other cursors' do
+ described_class.update_cursor_for(:other_table, 1111)
+
+ expect(value).to eq(0)
+ end
+ end
+end
diff --git a/spec/lib/constraints/activity_pub_constrainer_spec.rb b/spec/lib/constraints/activity_pub_constrainer_spec.rb
new file mode 100644
index 00000000000..2a3d23501a9
--- /dev/null
+++ b/spec/lib/constraints/activity_pub_constrainer_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Constraints::ActivityPubConstrainer, feature_category: :groups_and_projects do
+ subject(:constraint) { described_class.new }
+
+ describe '#matches?' do
+ subject { constraint.matches?(request) }
+
+ let(:request) { ActionDispatch::Request.new(headers) }
+
+ ['application/ld+json; profile="https://www.w3.org/ns/activitystreams"', 'application/activity+json'].each do |mime|
+ context "when Accept header is #{mime}" do
+ let(:headers) { { 'HTTP_ACCEPT' => mime } }
+
+ it 'matches the header' do
+ is_expected.to be_truthy
+ end
+ end
+
+ context "when Content-Type header is #{mime}" do
+ let(:headers) { { 'CONTENT_TYPE' => mime } }
+
+ it 'matches the header' do
+ is_expected.to be_truthy
+ end
+ end
+ end
+
+ context 'when Accept and Content-Type headers are missing' do
+ let(:headers) { {} }
+
+ it 'does not match' do
+ is_expected.to be_falsey
+ end
+ end
+ end
+end
diff --git a/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_spec_matcher.txt b/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_spec_matcher.txt
index 2728d65d54b..185f6deeade 100644
--- a/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_spec_matcher.txt
+++ b/spec/lib/generators/batched_background_migration/expected_files/my_batched_migration_spec_matcher.txt
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe Gitlab::BackgroundMigration::MyBatchedMigration, schema: [0-9]+, feature_category: :database do # rubocop:disable Layout/LineLength
+RSpec.describe Gitlab::BackgroundMigration::MyBatchedMigration, feature_category: :database do # rubocop:disable Layout/LineLength
# Tests go here
end
diff --git a/spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb b/spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb
index e67e48d83a3..b75d75107ee 100644
--- a/spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb
+++ b/spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb
@@ -141,8 +141,10 @@ RSpec.describe Gitlab::Analytics::InternalEventsGenerator, :silence_stdout, feat
.to receive(:known_event?).with(event).and_return(true)
end
- it 'raises error' do
- expect { described_class.new([], options).invoke_all }.to raise_error(RuntimeError)
+ it 'does not create event definition' do
+ described_class.new([], options).invoke_all
+
+ expect(event_definition_path).to eq(nil)
end
end
diff --git a/spec/lib/generators/gitlab/partitioning/foreign_keys_generator_spec.rb b/spec/lib/generators/gitlab/partitioning/foreign_keys_generator_spec.rb
index 7c7ca8207ff..229100186be 100644
--- a/spec/lib/generators/gitlab/partitioning/foreign_keys_generator_spec.rb
+++ b/spec/lib/generators/gitlab/partitioning/foreign_keys_generator_spec.rb
@@ -33,8 +33,6 @@ feature_category: :continuous_integration do
SQL
end
- let_it_be(:destination_root) { File.expand_path("../tmp", __dir__) }
-
let(:generator_config) { { destination_root: destination_root } }
let(:generator_args) { ['--source', '_test_tmp_metadata', '--target', '_test_tmp_builds', '--database', 'main'] }
@@ -124,4 +122,8 @@ feature_category: :continuous_integration do
def schema_migrate_down!
# no-op
end
+
+ def destination_root
+ File.expand_path("../tmp", __dir__)
+ end
end
diff --git a/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb b/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb
index 62a52ee5fb9..740cfa767e4 100644
--- a/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb
+++ b/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb
@@ -6,7 +6,10 @@ RSpec.describe Gitlab::SnowplowEventDefinitionGenerator, :silence_stdout, featur
let(:ce_temp_dir) { Dir.mktmpdir }
let(:ee_temp_dir) { Dir.mktmpdir }
let(:timestamp) { Time.now.utc.strftime('%Y%m%d%H%M%S') }
- let(:generator_options) { { 'category' => 'Groups::EmailCampaignsController', 'action' => 'click' } }
+
+ let(:generator_options) do
+ { 'category' => 'Projects::Pipelines::EmailCampaignsController', 'action' => 'click' }
+ end
before do
stub_const("#{described_class}::CE_DIR", ce_temp_dir)
diff --git a/spec/lib/gitlab/auth/o_auth/provider_spec.rb b/spec/lib/gitlab/auth/o_auth/provider_spec.rb
index 226669bab33..291cfb951c3 100644
--- a/spec/lib/gitlab/auth/o_auth/provider_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/provider_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Auth::OAuth::Provider do
+RSpec.describe Gitlab::Auth::OAuth::Provider, feature_category: :system_access do
describe '.enabled?' do
before do
allow(described_class).to receive(:providers).and_return([:ldapmain, :google_oauth2])
@@ -62,25 +62,27 @@ RSpec.describe Gitlab::Auth::OAuth::Provider do
context 'for an OmniAuth provider' do
before do
- provider = ActiveSupport::InheritableOptions.new(
+ provider = GitlabSettings::Options.new(
name: 'google_oauth2',
app_id: 'asd123',
app_secret: 'asd123'
)
- allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider])
+ openid_connect = GitlabSettings::Options.new(name: 'openid_connect')
+
+ stub_omniauth_setting(providers: [provider, openid_connect])
end
context 'when the provider exists' do
- subject { described_class.config_for('google_oauth2') }
+ subject(:config) { described_class.config_for('google_oauth2') }
it 'returns the config' do
- expect(subject).to be_a(ActiveSupport::InheritableOptions)
+ expect(config).to be_a(GitlabSettings::Options)
end
it 'merges defaults with the given configuration' do
defaults = Gitlab::OmniauthInitializer.default_arguments_for('google_oauth2').deep_stringify_keys
- expect(subject['args']).to include(defaults)
+ expect(config['args']).to include(defaults)
end
end
diff --git a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
index e5bc51edc2d..f12ed5a0e9c 100644
--- a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
+++ b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe Gitlab::Auth::UserAccessDeniedReason do
end
context 'when the user is internal' do
- let(:user) { User.ghost }
+ let(:user) { Users::Internal.ghost }
it { is_expected.to match /This action cannot be performed by internal users/ }
end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index c4fa8513618..8da617175ca 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
describe 'constants' do
it 'API_SCOPES contains all scopes for API access' do
- expect(subject::API_SCOPES).to match_array %i[api read_user read_api create_runner]
+ expect(subject::API_SCOPES).to match_array %i[api read_user read_api create_runner k8s_proxy]
end
it 'ADMIN_SCOPES contains all scopes for ADMIN access' do
@@ -40,29 +40,29 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
it 'contains all non-default scopes' do
- expect(subject.all_available_scopes).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry sudo admin_mode read_observability write_observability create_runner]
+ expect(subject.all_available_scopes).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry sudo admin_mode read_observability write_observability create_runner k8s_proxy ai_features]
end
it 'contains for non-admin user all non-default scopes without ADMIN access and without observability scopes' do
user = build_stubbed(:user, admin: false)
- expect(subject.available_scopes_for(user)).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry create_runner]
+ expect(subject.available_scopes_for(user)).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry create_runner k8s_proxy ai_features]
end
it 'contains for admin user all non-default scopes with ADMIN access and without observability scopes' do
user = build_stubbed(:user, admin: true)
- expect(subject.available_scopes_for(user)).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry sudo admin_mode create_runner]
+ expect(subject.available_scopes_for(user)).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry sudo admin_mode create_runner k8s_proxy ai_features]
end
it 'contains for project all resource bot scopes without observability scopes' do
- expect(subject.available_scopes_for(project)).to match_array %i[api read_api read_repository write_repository read_registry write_registry create_runner]
+ expect(subject.available_scopes_for(project)).to match_array %i[api read_api read_repository write_repository read_registry write_registry create_runner k8s_proxy ai_features]
end
it 'contains for group all resource bot scopes' do
group = build_stubbed(:group)
- expect(subject.available_scopes_for(group)).to match_array %i[api read_api read_repository write_repository read_registry write_registry read_observability write_observability create_runner]
+ expect(subject.available_scopes_for(group)).to match_array %i[api read_api read_repository write_repository read_registry write_registry read_observability write_observability create_runner k8s_proxy ai_features]
end
it 'contains for unsupported type no scopes' do
@@ -70,7 +70,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
it 'optional_scopes contains all non-default scopes' do
- expect(subject.optional_scopes).to match_array %i[read_user read_api read_repository write_repository read_registry write_registry sudo admin_mode openid profile email read_observability write_observability create_runner]
+ expect(subject.optional_scopes).to match_array %i[read_user read_api read_repository write_repository read_registry write_registry sudo admin_mode openid profile email read_observability write_observability create_runner k8s_proxy ai_features]
end
context 'with observability_group_tab feature flag' do
@@ -82,7 +82,7 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
it 'contains for group all resource bot scopes without observability scopes' do
group = build_stubbed(:group)
- expect(subject.available_scopes_for(group)).to match_array %i[api read_api read_repository write_repository read_registry write_registry create_runner]
+ expect(subject.available_scopes_for(group)).to match_array %i[api read_api read_repository write_repository read_registry write_registry create_runner k8s_proxy ai_features]
end
end
@@ -94,23 +94,23 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
it 'contains for other group all resource bot scopes including observability scopes' do
- expect(subject.available_scopes_for(group)).to match_array %i[api read_api read_repository write_repository read_registry write_registry read_observability write_observability create_runner]
+ expect(subject.available_scopes_for(group)).to match_array %i[api read_api read_repository write_repository read_registry write_registry read_observability write_observability create_runner k8s_proxy ai_features]
end
it 'contains for admin user all non-default scopes with ADMIN access and without observability scopes' do
user = build_stubbed(:user, admin: true)
- expect(subject.available_scopes_for(user)).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry sudo admin_mode create_runner]
+ expect(subject.available_scopes_for(user)).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry sudo admin_mode create_runner k8s_proxy ai_features]
end
it 'contains for project all resource bot scopes without observability scopes' do
- expect(subject.available_scopes_for(project)).to match_array %i[api read_api read_repository write_repository read_registry write_registry create_runner]
+ expect(subject.available_scopes_for(project)).to match_array %i[api read_api read_repository write_repository read_registry write_registry create_runner k8s_proxy ai_features]
end
it 'contains for other group all resource bot scopes without observability scopes' do
other_group = build_stubbed(:group)
- expect(subject.available_scopes_for(other_group)).to match_array %i[api read_api read_repository write_repository read_registry write_registry create_runner]
+ expect(subject.available_scopes_for(other_group)).to match_array %i[api read_api read_repository write_repository read_registry write_registry create_runner k8s_proxy ai_features]
end
end
end
diff --git a/spec/lib/gitlab/background_migration/backfill_has_merge_request_of_vulnerability_reads_spec.rb b/spec/lib/gitlab/background_migration/backfill_has_merge_request_of_vulnerability_reads_spec.rb
new file mode 100644
index 00000000000..fc4597fbb96
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_has_merge_request_of_vulnerability_reads_spec.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillHasMergeRequestOfVulnerabilityReads, schema: 20230907155247, feature_category: :database do # rubocop:disable Layout/LineLength
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:users) { table(:users) }
+ let(:scanners) { table(:vulnerability_scanners) }
+ let(:vulnerabilities) { table(:vulnerabilities) }
+ let(:vulnerability_reads) { table(:vulnerability_reads) }
+ let(:merge_requests) { table(:merge_requests) }
+ let(:merge_request_links) { table(:vulnerability_merge_request_links) }
+
+ let(:namespace) { namespaces.create!(name: 'user', path: 'user') }
+ let(:project) { projects.create!(namespace_id: namespace.id, project_namespace_id: namespace.id) }
+ let(:user) { users.create!(username: 'john_doe', email: 'johndoe@gitlab.com', projects_limit: 10) }
+ let(:scanner) { scanners.create!(project_id: project.id, external_id: 'external_id', name: 'Test Scanner') }
+
+ let(:vulnerability) do
+ vulnerabilities.create!(
+ project_id: project.id,
+ author_id: user.id,
+ title: 'test',
+ severity: 1,
+ confidence: 1,
+ report_type: 1
+ )
+ end
+
+ let(:merge_request) do
+ merge_requests.create!(
+ target_project_id: project.id,
+ source_branch: "other",
+ target_branch: "main",
+ author_id: user.id,
+ title: 'Feedback Merge Request'
+ )
+ end
+
+ let!(:vulnerability_read) do
+ vulnerability_reads.create!(
+ project_id: project.id,
+ vulnerability_id: vulnerability.id,
+ scanner_id: scanner.id,
+ severity: 1,
+ report_type: 1,
+ state: 1,
+ uuid: SecureRandom.uuid
+ )
+ end
+
+ let!(:merge_request_link) do
+ merge_request_links.create!(
+ vulnerability_id: vulnerability.id, merge_request_id: merge_request.id)
+ end
+
+ subject(:perform_migration) do
+ described_class.new(
+ start_id: vulnerability_reads.first.vulnerability_id,
+ end_id: vulnerability_reads.last.vulnerability_id,
+ batch_table: :vulnerability_reads,
+ batch_column: :vulnerability_id,
+ sub_batch_size: vulnerability_reads.count,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
+ end
+
+ before do
+ # Unset since the trigger already sets during merge_request_link creation.
+ vulnerability_reads.update_all(has_merge_request: false)
+ end
+
+ it 'sets the has_merge_request of existing record' do
+ expect { perform_migration }.to change { vulnerability_read.reload.has_merge_request }.from(false).to(true)
+ end
+
+ it 'does not modify has_merge_request of other vulnerabilities which do not have merge request' do
+ vulnerability_2 = vulnerabilities.create!(
+ project_id: project.id,
+ author_id: user.id,
+ title: 'test 2',
+ severity: 1,
+ confidence: 1,
+ report_type: 1
+ )
+
+ vulnerability_read_2 = vulnerability_reads.create!(
+ project_id: project.id,
+ vulnerability_id: vulnerability_2.id,
+ scanner_id: scanner.id,
+ severity: 1,
+ report_type: 1,
+ state: 1,
+ uuid: SecureRandom.uuid
+ )
+
+ expect { perform_migration }.not_to change { vulnerability_read_2.reload.has_merge_request }.from(false)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/backfill_nuget_normalized_version_spec.rb b/spec/lib/gitlab/background_migration/backfill_nuget_normalized_version_spec.rb
new file mode 100644
index 00000000000..3f0bd417955
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_nuget_normalized_version_spec.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillNugetNormalizedVersion, schema: 20230811103457,
+ feature_category: :package_registry do
+ let(:packages_nuget_metadata) { table(:packages_nuget_metadata) }
+ let(:versions) do
+ {
+ '1' => '1.0.0',
+ '1.0' => '1.0.0',
+ '1.0.0' => '1.0.0',
+ '1.00' => '1.0.0',
+ '1.00.01' => '1.0.1',
+ '1.01.1' => '1.1.1',
+ '1.0.0.0' => '1.0.0',
+ '1.0.01.0' => '1.0.1',
+ '1.0.7+r3456' => '1.0.7',
+ '1.0.0-Alpha' => '1.0.0-alpha',
+ '1.00.05-alpha.0' => '1.0.5-alpha.0'
+ }
+ end
+
+ let!(:migration_attrs) do
+ {
+ start_id: packages_nuget_metadata.minimum(:package_id),
+ end_id: packages_nuget_metadata.maximum(:package_id),
+ batch_table: :packages_nuget_metadata,
+ batch_column: :package_id,
+ sub_batch_size: 1000,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection
+ }
+ end
+
+ let(:migration) { described_class.new(**migration_attrs) }
+ let(:packages) { table(:packages_packages) }
+
+ let(:namespace) { table(:namespaces).create!(name: 'project', path: 'project', type: 'Project') }
+ let(:project) do
+ table(:projects).create!(name: 'project', path: 'project', project_namespace_id: namespace.id,
+ namespace_id: namespace.id)
+ end
+
+ let(:package_ids) { [] }
+
+ subject(:perform_migration) { migration.perform }
+
+ before do
+ versions.each_key do |version|
+ packages.create!(name: 'test', version: version, package_type: 4, project_id: project.id).tap do |package|
+ package_ids << package.id
+ packages_nuget_metadata.create!(package_id: package.id)
+ end
+ end
+ end
+
+ it 'executes 5 queries and updates the normalized_version column' do
+ queries = ActiveRecord::QueryRecorder.new do
+ perform_migration
+ end
+
+ # each_batch lower bound query
+ # each_batch upper bound query
+ # SELECT packages_nuget_metadata.package_id FROM packages_nuget_metadata....
+ # SELECT packages_packages.id, packages_packages.version FROM packages_packages....
+ # UPDATE packages_nuget_metadata SET normalized_version =....
+ expect(queries.count).to eq(5)
+
+ expect(
+ packages_nuget_metadata.where(package_id: package_ids).pluck(:normalized_version)
+ ).to match_array(versions.values)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/backfill_project_statistics_storage_size_with_recent_size_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_statistics_storage_size_with_recent_size_spec.rb
new file mode 100644
index 00000000000..2884fb9b10b
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_project_statistics_storage_size_with_recent_size_spec.rb
@@ -0,0 +1,165 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillProjectStatisticsStorageSizeWithRecentSize,
+ schema: 20230823090001,
+ feature_category: :consumables_cost_management do
+ include MigrationHelpers::ProjectStatisticsHelper
+
+ include_context 'when backfilling project statistics'
+
+ let(:recent_size_enabled_at) { described_class::RECENT_OBJECTS_SIZE_ENABLED_AT }
+ let(:default_stats) do
+ {
+ repository_size: 1,
+ wiki_size: 1,
+ lfs_objects_size: 1,
+ build_artifacts_size: 1,
+ packages_size: 1,
+ snippets_size: 1,
+ uploads_size: 1,
+ storage_size: default_storage_size,
+ updated_at: recent_size_enabled_at - 1.month
+ }
+ end
+
+ describe '#filter_batch' do
+ let!(:project_statistics) { generate_records(default_projects, project_statistics_table, default_stats) }
+ let!(:expected) { project_statistics.map(&:id) }
+
+ it 'filters out project_statistics with no repository_size' do
+ project_statistics_table.create!(
+ project_id: proj5.id,
+ namespace_id: proj5.namespace_id,
+ repository_size: 0,
+ wiki_size: 1,
+ lfs_objects_size: 1,
+ build_artifacts_size: 1,
+ packages_size: 1,
+ snippets_size: 1,
+ uploads_size: 1,
+ storage_size: 6,
+ updated_at: recent_size_enabled_at - 1.month
+ )
+
+ actual = migration.filter_batch(project_statistics_table).pluck(:id)
+
+ expect(actual).to match_array(expected)
+ end
+
+ shared_examples 'filters out project_statistics updated since recent objects went live' do
+ it 'filters out project_statistics updated since recent objects went live' do
+ project_statistics_table.create!(
+ project_id: proj5.id,
+ namespace_id: proj5.namespace_id,
+ repository_size: 10,
+ wiki_size: 1,
+ lfs_objects_size: 1,
+ build_artifacts_size: 1,
+ packages_size: 1,
+ snippets_size: 1,
+ uploads_size: 1,
+ storage_size: 6,
+ updated_at: recent_size_enabled_at + 1.month
+ )
+
+ actual = migration.filter_batch(project_statistics_table).pluck(:id)
+
+ expect(actual).to match_array(expected)
+ end
+ end
+
+ context 'when on GitLab.com' do
+ before do
+ allow(Gitlab).to receive(:org_or_com?).and_return(true)
+ end
+
+ it_behaves_like 'filters out project_statistics updated since recent objects went live'
+ end
+
+ context 'when Gitlab.dev_or_test_env? is true ' do
+ before do
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(true)
+ end
+
+ it_behaves_like 'filters out project_statistics updated since recent objects went live'
+ end
+
+ context 'when on self-managed' do
+ before do
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
+ allow(Gitlab).to receive(:org_or_com?).and_return(false)
+ end
+
+ it 'does not filter out project_statistics updated since recent objects went live' do
+ latest = project_statistics_table.create!(
+ project_id: proj5.id,
+ namespace_id: proj5.namespace_id,
+ repository_size: 10,
+ wiki_size: 1,
+ lfs_objects_size: 1,
+ build_artifacts_size: 1,
+ packages_size: 1,
+ snippets_size: 1,
+ uploads_size: 1,
+ storage_size: 6,
+ updated_at: recent_size_enabled_at + 1.month
+ )
+
+ actual = migration.filter_batch(project_statistics_table).pluck(:id)
+
+ expect(actual).to match_array(expected.push(latest.id))
+ end
+ end
+ end
+
+ describe '#perform' do
+ subject(:perform_migration) { migration.perform }
+
+ before do
+ allow_next_instance_of(Repository) do |repo|
+ allow(repo).to receive(:recent_objects_size).and_return(10)
+ end
+ end
+
+ context 'when project_statistics backfill runs' do
+ before do
+ generate_records(default_projects, project_statistics_table, default_stats)
+ allow(::Namespaces::ScheduleAggregationWorker).to receive(:perform_async)
+ end
+
+ it 'uses repository#recent_objects_size for repository_size' do
+ project_statistics = create_project_stats(projects, namespaces, default_stats)
+ migration = create_migration(end_id: project_statistics.project_id)
+
+ migration.perform
+
+ project_statistics.reload
+ expect(project_statistics.storage_size).to eq(6 + 10.megabytes)
+ end
+ end
+
+ it 'coerces a null wiki_size to 0' do
+ project_statistics = create_project_stats(projects, namespaces, default_stats, { wiki_size: nil })
+ allow(::Namespaces::ScheduleAggregationWorker).to receive(:perform_async)
+ migration = create_migration(end_id: project_statistics.project_id)
+
+ migration.perform
+
+ project_statistics.reload
+ expect(project_statistics.storage_size).to eq(5 + 10.megabytes)
+ end
+
+ it 'coerces a null snippets_size to 0' do
+ project_statistics = create_project_stats(projects, namespaces, default_stats, { snippets_size: nil })
+ allow(::Namespaces::ScheduleAggregationWorker).to receive(:perform_async)
+ migration = create_migration(end_id: project_statistics.project_id)
+
+ migration.perform
+
+ project_statistics.reload
+ expect(project_statistics.storage_size).to eq(5 + 10.megabytes)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
index 9f76e4131b2..06b66b599ab 100644
--- a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb
@@ -250,7 +250,7 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migrat
end
context 'when user name is invalid' do
- let(:user_name) { '.' }
+ let(:user_name) { ',' }
let!(:snippet) { snippets.create!(id: 4, type: 'PersonalSnippet', author_id: user.id, file_name: file_name, content: content) }
let(:ids) { [4, 4] }
@@ -262,7 +262,7 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migrat
end
context 'when both user name and snippet file_name are invalid' do
- let(:user_name) { '.' }
+ let(:user_name) { ',' }
let!(:other_user) do
users.create!(
id: 2,
diff --git a/spec/lib/gitlab/background_migration/backfill_user_preferences_with_defaults_spec.rb b/spec/lib/gitlab/background_migration/backfill_user_preferences_with_defaults_spec.rb
new file mode 100644
index 00000000000..b66b930b7ac
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_user_preferences_with_defaults_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillUserPreferencesWithDefaults,
+ schema: 20230818085219,
+ feature_category: :user_profile do
+ let(:user_preferences) { table(:user_preferences) }
+ let(:users) { table(:users) }
+ let(:columns) { [:tab_width, :time_display_relative, :render_whitespace_in_code] }
+ let(:initial_column_values) do
+ [
+ [nil, nil, nil],
+ [10, nil, nil],
+ [nil, false, nil],
+ [nil, nil, true]
+ ]
+ .map { |row| columns.zip(row).to_h }
+ end
+
+ let(:final_column_values) do
+ [
+ [8, true, false],
+ [10, true, false],
+ [8, false, false],
+ [8, true, true]
+ ]
+ .map { |row| columns.zip(row).to_h }
+ end
+
+ subject(:perform_migration) do
+ described_class
+ .new(
+ start_id: user_preferences.minimum(:id),
+ end_id: user_preferences.maximum(:id),
+ batch_table: :user_preferences,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ )
+ .perform
+ end
+
+ before do
+ initial_column_values.each_with_index do |attributes, index|
+ user = users.create!(projects_limit: 1, email: "user#{index}@gitlab.com")
+ user_preference = user_preferences.create!(attributes.merge(user_id: user.id))
+ final_column_values[index].merge!(id: user_preference.id)
+ end
+ end
+
+ it 'backfills the null values with the default values' do
+ perform_migration
+
+ final_column_values.each { |attributes| match_attributes(attributes) }
+ end
+
+ def match_attributes(attributes)
+ migrated_user_preference = user_preferences.find(attributes[:id])
+
+ expect(migrated_user_preference.tab_width).to eq(attributes[:tab_width])
+ expect(migrated_user_preference.time_display_relative).to eq(attributes[:time_display_relative])
+ expect(migrated_user_preference.render_whitespace_in_code).to eq(attributes[:render_whitespace_in_code])
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/backfill_users_with_defaults_spec.rb b/spec/lib/gitlab/background_migration/backfill_users_with_defaults_spec.rb
new file mode 100644
index 00000000000..78f36933435
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_users_with_defaults_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillUsersWithDefaults,
+ schema: 20230818083610,
+ feature_category: :user_profile do
+ let(:users) { table(:users) }
+ let(:columns) { [:project_view, :hide_no_ssh_key, :hide_no_password, :notified_of_own_activity] }
+ let(:initial_column_values) do
+ [
+ [nil, nil, nil, nil],
+ [0, nil, nil, nil],
+ [nil, true, nil, nil],
+ [nil, nil, true, nil],
+ [nil, nil, nil, true]
+ ]
+ .map { |row| columns.zip(row).to_h }
+ end
+
+ let(:final_column_values) do
+ [
+ [2, false, false, false],
+ [0, false, false, false],
+ [2, true, false, false],
+ [2, false, true, false],
+ [2, false, false, true]
+ ]
+ .map { |row| columns.zip(row).to_h }
+ end
+
+ subject(:perform_migration) do
+ described_class
+ .new(
+ start_id: users.minimum(:id),
+ end_id: users.maximum(:id),
+ batch_table: :users,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ )
+ .perform
+ end
+
+ before do
+ initial_column_values.each_with_index do |attributes, index|
+ user = users.create!(**attributes.merge(projects_limit: 1, email: "user#{index}@gitlab.com"))
+ final_column_values[index].merge!(id: user.id)
+ end
+ end
+
+ it 'backfills the null values with the default values' do
+ perform_migration
+
+ final_column_values.each { |attributes| match_attributes(attributes) }
+ end
+
+ private
+
+ def match_attributes(attributes)
+ migrated_user = users.find(attributes[:id])
+ expect(migrated_user.project_view).to eq(attributes[:project_view])
+ expect(migrated_user.hide_no_ssh_key).to eq(attributes[:hide_no_ssh_key])
+ expect(migrated_user.hide_no_password).to eq(attributes[:hide_no_password])
+ expect(migrated_user.notified_of_own_activity).to eq(attributes[:notified_of_own_activity])
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/convert_credit_card_validation_data_to_hashes_spec.rb b/spec/lib/gitlab/background_migration/convert_credit_card_validation_data_to_hashes_spec.rb
new file mode 100644
index 00000000000..97f69afca55
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/convert_credit_card_validation_data_to_hashes_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::ConvertCreditCardValidationDataToHashes, schema: 20230821081603, feature_category: :user_profile do # rubocop:disable Layout/LineLength
+ let(:users_table) { table(:users) }
+ let(:credit_card_validations_table) { table(:user_credit_card_validations) }
+ let(:rows) { 5 }
+
+ describe '#perform' do
+ let(:network) { 'Visa' }
+ let(:holder_name) { 'John Smith' }
+ let(:last_digits) { 1111 }
+ let(:expiration_date) { 1.year.from_now.to_date }
+
+ subject(:perform_migration) do
+ described_class.new(
+ start_id: 1,
+ end_id: rows,
+ batch_table: :user_credit_card_validations,
+ batch_column: :user_id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection
+ ).perform
+ end
+
+ before do
+ (1..rows).each do |i|
+ users_table.create!(id: i, username: "John #{i}", email: "johndoe_#{i}@gitlab.com", projects_limit: 10)
+
+ credit_card_validations_table.create!(
+ id: i,
+ user_id: i,
+ network: network,
+ holder_name: holder_name,
+ last_digits: last_digits,
+ expiration_date: expiration_date,
+ credit_card_validated_at: Date.today
+ )
+ end
+ end
+
+ it 'updates values to hash for records in the specified batch', :aggregate_failures do
+ perform_migration
+
+ (1..rows).each do |i|
+ credit_card = credit_card_validations_table.find_by(user_id: i)
+
+ expect(credit_card.last_digits_hash).to eq(hashed_value(last_digits))
+ expect(credit_card.holder_name_hash).to eq(hashed_value(holder_name.downcase))
+ expect(credit_card.network_hash).to eq(hashed_value(network.downcase))
+ expect(credit_card.expiration_date_hash).to eq(hashed_value(expiration_date.to_s))
+ end
+ end
+
+ context 'with NULL columns' do
+ let(:network) { nil }
+ let(:holder_name) { nil }
+ let(:last_digits) { nil }
+ let(:expiration_date) { nil }
+
+ it 'does not update values for records in the specified batch', :aggregate_failures do
+ perform_migration
+
+ (1..rows).each do |i|
+ credit_card = credit_card_validations_table.find_by(user_id: i)
+
+ expect(credit_card.last_digits_hash).to eq(nil)
+ expect(credit_card.holder_name_hash).to eq(nil)
+ expect(credit_card.network_hash).to eq(nil)
+ expect(credit_card.expiration_date_hash).to eq(nil)
+ end
+ end
+ end
+ end
+
+ def hashed_value(value)
+ Gitlab::CryptoHelper.sha256(value)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/rebalance_partition_id_spec.rb b/spec/lib/gitlab/background_migration/rebalance_partition_id_spec.rb
deleted file mode 100644
index 195e57e4e59..00000000000
--- a/spec/lib/gitlab/background_migration/rebalance_partition_id_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::RebalancePartitionId,
- :migration,
- schema: 20230125093723,
- feature_category: :continuous_integration do
- let(:ci_builds_table) { table(:ci_builds, database: :ci) }
- let(:ci_pipelines_table) { table(:ci_pipelines, database: :ci) }
-
- let!(:valid_ci_pipeline) { ci_pipelines_table.create!(id: 1, partition_id: 100) }
- let!(:invalid_ci_pipeline) { ci_pipelines_table.create!(id: 2, partition_id: 101) }
-
- describe '#perform' do
- using RSpec::Parameterized::TableSyntax
-
- where(:table_name, :invalid_record, :valid_record) do
- :ci_pipelines | invalid_ci_pipeline | valid_ci_pipeline
- end
-
- subject(:perform) do
- described_class.new(
- start_id: 1,
- end_id: 2,
- batch_table: table_name,
- batch_column: :id,
- sub_batch_size: 1,
- pause_ms: 0,
- connection: Ci::ApplicationRecord.connection
- ).perform
- end
-
- shared_examples 'fix invalid records' do
- it 'rebalances partition_id to 100 when partition_id is 101' do
- expect { perform }
- .to change { invalid_record.reload.partition_id }.from(101).to(100)
- .and not_change { valid_record.reload.partition_id }
- end
- end
-
- with_them do
- it_behaves_like 'fix invalid records'
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/update_users_set_external_if_service_account_spec.rb b/spec/lib/gitlab/background_migration/update_users_set_external_if_service_account_spec.rb
new file mode 100644
index 00000000000..19ad70337dc
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/update_users_set_external_if_service_account_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::UpdateUsersSetExternalIfServiceAccount, feature_category: :system_access do
+ describe "#perform" do
+ let(:users_table) { table(:users) }
+ let(:service_account_user) do
+ users_table.create!(username: 'john_doe', email: 'johndoe@gitlab.com',
+ user_type: HasUserType::USER_TYPES[:service_account], projects_limit: 5)
+ end
+
+ let(:service_user) do
+ users_table.create!(username: 'john_doe2', email: 'johndoe2@gitlab.com',
+ user_type: HasUserType::USER_TYPES[:service_user], projects_limit: 5)
+ end
+
+ let(:table_name) { :users }
+ let(:batch_column) { :id }
+ let(:sub_batch_size) { 2 }
+ let(:pause_ms) { 0 }
+ let(:migration) do
+ described_class.new(
+ start_id: service_account_user.id, end_id: service_user.id,
+ batch_table: table_name, batch_column: batch_column,
+ sub_batch_size: sub_batch_size, pause_ms: pause_ms,
+ connection: ApplicationRecord.connection
+ )
+ end
+
+ subject(:perform_migration) do
+ migration.perform
+ end
+
+ it "changes external field for service_account user" do
+ perform_migration
+
+ expect(service_account_user.reload.external).to eq(true)
+ expect(service_user.reload.external).to eq(false)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 4c94ecfe745..9786e7a364e 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -92,6 +92,7 @@ RSpec.describe Gitlab::BitbucketImport::Importer, :clean_gitlab_redis_cache, fea
describe '#import_pull_requests' do
let(:source_branch_sha) { sample.commits.last }
+ let(:merge_commit_sha) { sample.commits.second }
let(:target_branch_sha) { sample.commits.first }
let(:pull_request) do
instance_double(
@@ -101,6 +102,7 @@ RSpec.describe Gitlab::BitbucketImport::Importer, :clean_gitlab_redis_cache, fea
source_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.source_branch,
target_branch_sha: target_branch_sha,
target_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.target_branch,
+ merge_commit_sha: merge_commit_sha,
title: 'This is a title',
description: 'This is a test pull request',
state: 'merged',
@@ -217,17 +219,29 @@ RSpec.describe Gitlab::BitbucketImport::Importer, :clean_gitlab_redis_cache, fea
end
end
- context "when branches' sha is not found in the repository" do
+ context 'when source SHA is not found in the repository' do
let(:source_branch_sha) { 'a' * Commit::MIN_SHA_LENGTH }
- let(:target_branch_sha) { 'b' * Commit::MIN_SHA_LENGTH }
+ let(:target_branch_sha) { 'c' * Commit::MIN_SHA_LENGTH }
- it 'uses the pull request sha references' do
+ it 'uses merge commit SHA for source' do
expect { subject.execute }.to change { MergeRequest.count }.by(1)
merge_request_diff = MergeRequest.first.merge_request_diff
- expect(merge_request_diff.head_commit_sha).to eq source_branch_sha
+ expect(merge_request_diff.head_commit_sha).to eq merge_commit_sha
expect(merge_request_diff.start_commit_sha).to eq target_branch_sha
end
+
+ context 'when the merge commit SHA is also not found' do
+ let(:merge_commit_sha) { 'b' * Commit::MIN_SHA_LENGTH }
+
+ it 'uses the pull request sha references' do
+ expect { subject.execute }.to change { MergeRequest.count }.by(1)
+
+ merge_request_diff = MergeRequest.first.merge_request_diff
+ expect(merge_request_diff.head_commit_sha).to eq source_branch_sha
+ expect(merge_request_diff.start_commit_sha).to eq target_branch_sha
+ end
+ end
end
context "when target_branch_sha is blank" do
diff --git a/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb
new file mode 100644
index 00000000000..2eca6bb47d6
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/importers/pull_request_importer_spec.rb
@@ -0,0 +1,166 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestImporter, :clean_gitlab_redis_cache, feature_category: :importers do
+ include AfterNextHelpers
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:bitbucket_user) { create(:user) }
+ let_it_be(:user_2) { create(:user) }
+ let_it_be(:user_3) { create(:user) }
+ let_it_be(:identity) { create(:identity, user: bitbucket_user, extern_uid: 'bitbucket_user', provider: :bitbucket) }
+ let_it_be(:identity_2) { create(:identity, user: user_2, extern_uid: 'user_2', provider: :bitbucket) }
+ let(:source_branch_sha) { project.repository.commit.sha }
+ let(:target_branch_sha) { project.repository.commit('refs/heads/master').sha }
+
+ let(:hash) do
+ {
+ author: 'bitbucket_user',
+ created_at: Date.today,
+ description: 'description',
+ iid: 11,
+ source_branch_name: 'source-branch-name',
+ source_branch_sha: source_branch_sha,
+ state: 'merged',
+ target_branch_name: 'destination-branch-name',
+ target_branch_sha: target_branch_sha,
+ title: 'title',
+ updated_at: Date.today,
+ reviewers: %w[user_2 user_3]
+ }
+ end
+
+ subject(:importer) { described_class.new(project, hash) }
+
+ describe '#execute' do
+ it 'calls MergeRequestCreator' do
+ expect(Gitlab::Import::MergeRequestCreator).to receive_message_chain(:new, :execute)
+
+ importer.execute
+ end
+
+ it 'creates a merge request with the correct attributes' do
+ expect { importer.execute }.to change { project.merge_requests.count }.from(0).to(1)
+
+ merge_request = project.merge_requests.first
+
+ expect(merge_request.iid).to eq(11)
+ expect(merge_request.author).to eq(bitbucket_user)
+ expect(merge_request.title).to eq('title')
+ expect(merge_request.merged?).to be_truthy
+ expect(merge_request.created_at).to eq(Date.today)
+ expect(merge_request.description).to eq('description')
+ expect(merge_request.source_project_id).to eq(project.id)
+ expect(merge_request.target_project_id).to eq(project.id)
+ expect(merge_request.source_branch).to eq('source-branch-name')
+ expect(merge_request.target_branch).to eq('destination-branch-name')
+ expect(merge_request.assignee_ids).to eq([bitbucket_user.id])
+ expect(merge_request.reviewer_ids).to eq([user_2.id])
+ expect(merge_request.merge_request_diffs.first.base_commit_sha).to eq(source_branch_sha)
+ expect(merge_request.merge_request_diffs.first.head_commit_sha).to eq(target_branch_sha)
+ end
+
+ context 'when the state is closed' do
+ it 'marks merge request as closed' do
+ described_class.new(project, hash.merge(state: 'closed')).execute
+
+ expect(project.merge_requests.first.closed?).to be_truthy
+ end
+ end
+
+ context 'when the state is opened' do
+ it 'marks merge request as opened' do
+ described_class.new(project, hash.merge(state: 'opened')).execute
+
+ expect(project.merge_requests.first.opened?).to be_truthy
+ end
+ end
+
+ context 'when the author does not have a bitbucket identity' do
+ before do
+ identity.update!(provider: :github)
+ end
+
+ it 'sets the author and assignee to the project creator and adds the author to the description' do
+ importer.execute
+
+ merge_request = project.merge_requests.first
+
+ expect(merge_request.author).to eq(project.creator)
+ expect(merge_request.assignee).to eq(project.creator)
+ expect(merge_request.description).to eq("*Created by: bitbucket_user*\n\ndescription")
+ end
+ end
+
+ context 'when none of the reviewers have an identity' do
+ before do
+ identity_2.destroy!
+ end
+
+ it 'does not set reviewer_ids' do
+ importer.execute
+
+ merge_request = project.merge_requests.first
+
+ expect(merge_request.reviewer_ids).to be_empty
+ end
+ end
+
+ describe 'head_commit_sha for merge request diff' do
+ let(:diff) { project.merge_requests.first.merge_request_diffs.first }
+ let(:min_length) { Commit::MIN_SHA_LENGTH }
+
+ context 'when the source commit hash from Bitbucket is found on the repo' do
+ it 'is set to the source commit hash' do
+ described_class.new(project, hash.merge(source_branch_sha: source_branch_sha)).execute
+
+ expect(diff.head_commit_sha).to eq(source_branch_sha)
+ end
+ end
+
+ context 'when the source commit hash is not found but the merge commit hash is found' do
+ it 'is set to the merge commit hash' do
+ attrs = { source_branch_sha: 'x' * min_length, merge_commit_sha: source_branch_sha }
+
+ described_class.new(project, hash.merge(attrs)).execute
+
+ expect(diff.head_commit_sha).to eq(source_branch_sha)
+ end
+ end
+
+ context 'when both the source commit and merge commit hash are not found' do
+ it 'is nil' do
+ attrs = { source_branch_sha: 'x' * min_length, merge_commit_sha: 'y' * min_length }
+
+ described_class.new(project, hash.merge(attrs)).execute
+
+ expect(diff.head_commit_sha).to be_nil
+ end
+ end
+ end
+
+ context 'when an error is raised' do
+ before do
+ allow(Gitlab::Import::MergeRequestCreator).to receive(:new).and_raise(StandardError)
+ end
+
+ it 'tracks the failure and does not fail' do
+ expect(Gitlab::Import::ImportFailureService).to receive(:track).once
+
+ importer.execute
+ end
+ end
+
+ it 'logs its progress' do
+ allow(Gitlab::Import::MergeRequestCreator).to receive_message_chain(:new, :execute)
+
+ expect(Gitlab::BitbucketImport::Logger)
+ .to receive(:info).with(include(message: 'starting', iid: anything)).and_call_original
+ expect(Gitlab::BitbucketImport::Logger)
+ .to receive(:info).with(include(message: 'finished', iid: anything)).and_call_original
+
+ importer.execute
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb
new file mode 100644
index 00000000000..46bf099de0c
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/importers/pull_requests_importer_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Importers::PullRequestsImporter, feature_category: :importers do
+ let_it_be(:project) do
+ create(:project, :import_started,
+ import_data_attributes: {
+ data: { 'project_key' => 'key', 'repo_slug' => 'slug' },
+ credentials: { 'base_uri' => 'http://bitbucket.org/', 'user' => 'bitbucket', 'password' => 'password' }
+ }
+ )
+ end
+
+ subject(:importer) { described_class.new(project) }
+
+ describe '#execute', :clean_gitlab_redis_cache do
+ before do
+ allow_next_instance_of(Bitbucket::Client) do |client|
+ allow(client).to receive(:pull_requests).and_return(
+ [
+ Bitbucket::Representation::PullRequest.new({ 'id' => 1, 'state' => 'OPENED' }),
+ Bitbucket::Representation::PullRequest.new({ 'id' => 2, 'state' => 'DECLINED' }),
+ Bitbucket::Representation::PullRequest.new({ 'id' => 3, 'state' => 'MERGED' })
+ ],
+ []
+ )
+ end
+ end
+
+ it 'imports each pull request in parallel', :aggregate_failures do
+ expect(Gitlab::BitbucketImport::ImportPullRequestWorker).to receive(:perform_in).exactly(3).times
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(3)
+ expect(Gitlab::Cache::Import::Caching.values_from_set(importer.already_enqueued_cache_key))
+ .to match_array(%w[1 2 3])
+ end
+
+ context 'when the client raises an error' do
+ before do
+ allow_next_instance_of(Bitbucket::Client) do |client|
+ allow(client).to receive(:pull_requests).and_raise(StandardError)
+ end
+ end
+
+ it 'tracks the failure and does not fail' do
+ expect(Gitlab::Import::ImportFailureService).to receive(:track).once
+
+ importer.execute
+ end
+ end
+
+ context 'when pull request was already enqueued' do
+ before do
+ Gitlab::Cache::Import::Caching.set_add(importer.already_enqueued_cache_key, 1)
+ end
+
+ it 'does not schedule job for enqueued pull requests', :aggregate_failures do
+ expect(Gitlab::BitbucketImport::ImportPullRequestWorker).to receive(:perform_in).twice
+
+ waiter = importer.execute
+
+ expect(waiter).to be_an_instance_of(Gitlab::JobWaiter)
+ expect(waiter.jobs_remaining).to eq(3)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb
new file mode 100644
index 00000000000..1caf0b884c2
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/importers/repository_importer_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Importers::RepositoryImporter, feature_category: :importers do
+ let_it_be(:project) { create(:project, import_url: 'https://bitbucket.org/vim/vim.git') }
+
+ subject(:importer) { described_class.new(project) }
+
+ describe '#execute' do
+ context 'when repository is empty' do
+ it 'imports the repository' do
+ expect(project.repository).to receive(:import_repository).with(project.import_url)
+ expect(project.repository).to receive(:fetch_as_mirror).with(project.import_url,
+ refmap: ['+refs/pull-requests/*/to:refs/merge-requests/*/head'])
+ expect(project.last_repository_updated_at).to be_present
+
+ importer.execute
+ end
+ end
+
+ context 'when repository is not empty' do
+ before do
+ allow(project).to receive(:empty_repo?).and_return(false)
+
+ project.last_repository_updated_at = 1.day.ago
+ end
+
+ it 'does not import the repository' do
+ expect(project.repository).not_to receive(:import_repository)
+
+ expect { importer.execute }.not_to change { project.last_repository_updated_at }
+ end
+ end
+
+ context 'when a Git CommandError is raised and the repository exists' do
+ before do
+ allow(project.repository).to receive(:import_repository).and_raise(::Gitlab::Git::CommandError)
+ allow(project).to receive(:repository_exists?).and_return(true)
+ end
+
+ it 'expires repository caches' do
+ expect(project.repository).to receive(:expire_content_cache)
+
+ expect { importer.execute }.to raise_error(::Gitlab::Git::CommandError)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/parallel_importer_spec.rb b/spec/lib/gitlab/bitbucket_import/parallel_importer_spec.rb
new file mode 100644
index 00000000000..29919c43d23
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/parallel_importer_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::ParallelImporter, feature_category: :importers do
+ subject { described_class }
+
+ it { is_expected.to be_async }
+
+ describe '.track_start_import' do
+ it 'tracks the start of import' do
+ project = build_stubbed(:project)
+
+ expect_next_instance_of(Gitlab::Import::Metrics, :bitbucket_importer, project) do |metric|
+ expect(metric).to receive(:track_start_import)
+ end
+
+ subject.track_start_import(project)
+ end
+ end
+
+ describe '#execute', :clean_gitlab_redis_shared_state do
+ let_it_be(:project) { create(:project) }
+ let(:importer) { subject.new(project) }
+
+ before do
+ create(:import_state, :started, project: project)
+ end
+
+ it 'schedules the importing of the repository' do
+ expect(Gitlab::BitbucketImport::Stage::ImportRepositoryWorker)
+ .to receive_message_chain(:with_status, :perform_async).with(project.id)
+
+ expect(importer.execute).to eq(true)
+ end
+
+ it 'sets the JID in Redis' do
+ expect(Gitlab::Import::SetAsyncJid).to receive(:set_jid).with(project.import_state).and_call_original
+
+ importer.execute
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_import/user_finder_spec.rb b/spec/lib/gitlab/bitbucket_import/user_finder_spec.rb
new file mode 100644
index 00000000000..4ac4c2e4813
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/user_finder_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::UserFinder, :clean_gitlab_redis_cache, feature_category: :importers do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:identity) { create(:identity, user: user, extern_uid: 'uid', provider: :bitbucket) }
+ let(:created_id) { 1 }
+ let(:project) { instance_double(Project, creator_id: created_id, id: 1) }
+ let(:author) { 'uid' }
+ let(:cache_key) { format(described_class::USER_ID_FOR_AUTHOR_CACHE_KEY, project_id: project.id, author: author) }
+
+ subject(:user_finder) { described_class.new(project) }
+
+ describe '#find_user_id' do
+ it 'returns the user id' do
+ expect(User).to receive(:by_provider_and_extern_uid).and_call_original.once
+
+ expect(user_finder.find_user_id(author)).to eq(user.id)
+ expect(user_finder.find_user_id(author)).to eq(user.id)
+ end
+
+ context 'when the id is cached' do
+ before do
+ Gitlab::Cache::Import::Caching.write(cache_key, user.id)
+ end
+
+ it 'does not attempt to find the user' do
+ expect(User).not_to receive(:by_provider_and_extern_uid)
+
+ expect(user_finder.find_user_id(author)).to eq(user.id)
+ end
+ end
+
+ context 'when -1 is cached' do
+ before do
+ Gitlab::Cache::Import::Caching.write(cache_key, -1)
+ end
+
+ it 'does not attempt to find the user and returns nil' do
+ expect(User).not_to receive(:by_provider_and_extern_uid)
+
+ expect(user_finder.find_user_id(author)).to be_nil
+ end
+ end
+
+ context 'when the user does not have a matching bitbucket identity' do
+ before do
+ identity.update!(provider: :github)
+ end
+
+ it 'returns nil' do
+ expect(user_finder.find_user_id(author)).to be_nil
+ end
+ end
+ end
+
+ describe '#gitlab_user_id' do
+ context 'when find_user_id returns a user' do
+ it 'returns the user id' do
+ expect(user_finder.gitlab_user_id(project, author)).to eq(user.id)
+ end
+ end
+
+ context 'when find_user_id does not return a user' do
+ before do
+ allow(user_finder).to receive(:find_user_id).and_return(nil)
+ end
+
+ it 'returns the project creator' do
+ expect(user_finder.gitlab_user_id(project, author)).to eq(created_id)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb
deleted file mode 100644
index 4ff61bf329c..00000000000
--- a/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb
+++ /dev/null
@@ -1,653 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BitbucketServerImport::Importer, feature_category: :importers do
- include ImportSpecHelper
-
- let(:import_url) { 'http://my-bitbucket' }
- let(:bitbucket_user) { 'bitbucket' }
- let(:project_creator) { create(:user, username: 'project_creator', email: 'project_creator@example.org') }
- let(:password) { 'test' }
- let(:project) { create(:project, :repository, import_url: import_url, creator: project_creator) }
- let(:now) { Time.now.utc.change(usec: 0) }
- let(:project_key) { 'TEST' }
- let(:repo_slug) { 'rouge-repo' }
- let(:sample) { RepoHelpers.sample_compare }
-
- subject { described_class.new(project, recover_missing_commits: true) }
-
- before do
- data = project.create_or_update_import_data(
- data: { project_key: project_key, repo_slug: repo_slug },
- credentials: { base_uri: import_url, user: bitbucket_user, password: password }
- )
- data.save!
- project.save!
- end
-
- describe '#import_repository' do
- let(:repo_url) { 'http://bitbucket:test@my-bitbucket' }
-
- before do
- expect(project.repository).to receive(:import_repository).with(repo_url)
- end
-
- it 'adds a remote' do
- expect(subject).to receive(:import_pull_requests)
- expect(subject).to receive(:delete_temp_branches)
- expect(project.repository).to receive(:fetch_as_mirror)
- .with(repo_url,
- refmap: ['+refs/pull-requests/*/to:refs/merge-requests/*/head'])
-
- subject.execute
- end
-
- it 'raises a Gitlab::Git::CommandError in the fetch' do
- expect(project.repository).to receive(:fetch_as_mirror).and_raise(::Gitlab::Git::CommandError)
-
- expect { subject.execute }.to raise_error(::Gitlab::Git::CommandError)
- end
-
- it 'raises an unhandled exception in the fetch' do
- expect(project.repository).to receive(:fetch_as_mirror).and_raise(RuntimeError)
-
- expect { subject.execute }.to raise_error(RuntimeError)
- end
- end
-
- describe '#import_pull_requests' do
- let(:pull_request_author) { create(:user, username: 'pull_request_author', email: 'pull_request_author@example.org') }
- let(:note_author) { create(:user, username: 'note_author', email: 'note_author@example.org') }
-
- let(:pull_request) do
- instance_double(
- BitbucketServer::Representation::PullRequest,
- iid: 10,
- source_branch_sha: sample.commits.last,
- source_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.source_branch,
- target_branch_sha: sample.commits.first,
- target_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.target_branch,
- title: 'This is a title',
- description: 'This is a test pull request',
- reviewers: [],
- state: 'merged',
- author: 'Test Author',
- author_email: pull_request_author.email,
- author_username: pull_request_author.username,
- created_at: Time.now,
- updated_at: Time.now,
- raw: {},
- merged?: true)
- end
-
- let(:merge_event) do
- instance_double(
- BitbucketServer::Representation::Activity,
- comment?: false,
- merge_event?: true,
- committer_email: pull_request_author.email,
- merge_timestamp: now,
- merge_commit: '12345678'
- )
- end
-
- let(:pr_note) do
- instance_double(
- BitbucketServer::Representation::Comment,
- note: 'Hello world',
- author_email: note_author.email,
- author_username: note_author.username,
- comments: [],
- created_at: now,
- updated_at: now,
- parent_comment: nil)
- end
-
- let(:pr_comment) do
- instance_double(
- BitbucketServer::Representation::Activity,
- comment?: true,
- inline_comment?: false,
- merge_event?: false,
- comment: pr_note)
- end
-
- before do
- allow(subject).to receive(:import_repository)
- allow(subject).to receive(:delete_temp_branches)
- allow(subject).to receive(:restore_branches)
-
- allow(subject.client).to receive(:pull_requests).and_return([pull_request], [])
- end
-
- # As we are using Caching with redis, it is best to clean the cache after each test run, else we need to wait for
- # the expiration by the importer
- after do
- Gitlab::Cache::Import::Caching.expire(subject.already_imported_cache_key, 0)
- end
-
- it 'imports merge event' do
- expect(subject.client).to receive(:activities).and_return([merge_event])
-
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- merge_request = MergeRequest.first
- expect(merge_request.metrics.merged_by).to eq(pull_request_author)
- expect(merge_request.metrics.merged_at).to eq(merge_event.merge_timestamp)
- expect(merge_request.merge_commit_sha).to eq('12345678')
- expect(merge_request.state_id).to eq(3)
- end
-
- describe 'pull request author user mapping' do
- before do
- allow(subject.client).to receive(:activities).and_return([merge_event])
- end
-
- shared_examples 'imports pull requests' do
- it 'maps user' do
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- merge_request = MergeRequest.first
- expect(merge_request.author).to eq(expected_author)
- end
- end
-
- context 'when bitbucket_server_user_mapping_by_username feature flag is disabled' do
- before do
- stub_feature_flags(bitbucket_server_user_mapping_by_username: false)
- end
-
- context 'when email is not present' do
- before do
- allow(pull_request).to receive(:author_email).and_return(nil)
- end
-
- let(:expected_author) { project_creator }
-
- include_examples 'imports pull requests'
- end
-
- context 'when email is present' do
- before do
- allow(pull_request).to receive(:author_email).and_return(pull_request_author.email)
- end
-
- let(:expected_author) { pull_request_author }
-
- include_examples 'imports pull requests'
- end
- end
-
- context 'when bitbucket_server_user_mapping_by_username feature flag is enabled' do
- before do
- stub_feature_flags(bitbucket_server_user_mapping_by_username: true)
- end
-
- context 'when username is not present' do
- before do
- allow(pull_request).to receive(:author_username).and_return(nil)
- end
-
- let(:expected_author) { project_creator }
-
- include_examples 'imports pull requests'
- end
-
- context 'when username is present' do
- before do
- allow(pull_request).to receive(:author_username).and_return(pull_request_author.username)
- end
-
- let(:expected_author) { pull_request_author }
-
- include_examples 'imports pull requests'
- end
- end
-
- context 'when user is not found' do
- before do
- allow(pull_request).to receive(:author_username).and_return(nil)
- allow(pull_request).to receive(:author_email).and_return(nil)
- end
-
- it 'maps importer user' do
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- merge_request = MergeRequest.first
- expect(merge_request.author).to eq(project_creator)
- end
- end
- end
-
- describe 'comments' do
- shared_examples 'imports comments' do
- it 'imports comments' do
- expect(subject.client).to receive(:activities).and_return([pr_comment])
-
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- merge_request = MergeRequest.first
- expect(merge_request.notes.count).to eq(1)
- note = merge_request.notes.first
- expect(note.note).to end_with(pr_note.note)
- expect(note.author).to eq(note_author)
- expect(note.created_at).to eq(pr_note.created_at)
- expect(note.updated_at).to eq(pr_note.created_at)
- end
- end
-
- context 'when bitbucket_server_user_mapping_by_username feature flag is disabled' do
- before do
- stub_feature_flags(bitbucket_server_user_mapping_by_username: false)
- end
-
- include_examples 'imports comments'
- end
-
- context 'when bitbucket_server_user_mapping_by_username feature flag is enabled' do
- before do
- stub_feature_flags(bitbucket_server_user_mapping_by_username: true)
- end
-
- include_examples 'imports comments'
-
- context 'when username is not present' do
- before do
- allow(pr_note).to receive(:author_username).and_return(nil)
- allow(subject.client).to receive(:activities).and_return([pr_comment])
- end
-
- it 'defaults to import user' do
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- merge_request = MergeRequest.first
- expect(merge_request.notes.count).to eq(1)
- note = merge_request.notes.first
- expect(note.author).to eq(project_creator)
- end
- end
-
- context 'when username is present' do
- before do
- allow(pr_note).to receive(:author_username).and_return(note_author.username)
- allow(subject.client).to receive(:activities).and_return([pr_comment])
- end
-
- it 'maps by username' do
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- merge_request = MergeRequest.first
- expect(merge_request.notes.count).to eq(1)
- note = merge_request.notes.first
- expect(note.author).to eq(note_author)
- end
- end
- end
- end
-
- context 'metrics' do
- let(:histogram) { double(:histogram).as_null_object }
- let(:counter) { double('counter', increment: true) }
-
- before do
- allow(Gitlab::Metrics).to receive(:counter) { counter }
- allow(Gitlab::Metrics).to receive(:histogram) { histogram }
- allow(subject.client).to receive(:activities).and_return([merge_event])
- end
-
- it 'counts and measures duration of imported projects' do
- expect(Gitlab::Metrics).to receive(:counter).with(
- :bitbucket_server_importer_imported_projects_total,
- 'The number of imported projects'
- )
-
- expect(Gitlab::Metrics).to receive(:histogram).with(
- :bitbucket_server_importer_total_duration_seconds,
- 'Total time spent importing projects, in seconds',
- {},
- Gitlab::Import::Metrics::IMPORT_DURATION_BUCKETS
- )
-
- expect(counter).to receive(:increment)
- expect(histogram).to receive(:observe).with({ importer: :bitbucket_server_importer }, anything)
-
- subject.execute
- end
-
- it 'counts imported pull requests' do
- expect(Gitlab::Metrics).to receive(:counter).with(
- :bitbucket_server_importer_imported_merge_requests_total,
- 'The number of imported merge (pull) requests'
- )
-
- expect(counter).to receive(:increment)
-
- subject.execute
- end
- end
-
- describe 'threaded discussions' do
- let(:reply_author) { create(:user, username: 'reply_author', email: 'reply_author@example.org') }
- let(:inline_note_author) { create(:user, username: 'inline_note_author', email: 'inline_note_author@example.org') }
-
- let(:reply) do
- instance_double(
- BitbucketServer::Representation::PullRequestComment,
- author_email: reply_author.email,
- author_username: reply_author.username,
- note: 'I agree',
- created_at: now,
- updated_at: now)
- end
-
- # https://gitlab.com/gitlab-org/gitlab-test/compare/c1acaa58bbcbc3eafe538cb8274ba387047b69f8...5937ac0a7beb003549fc5fd26fc247ad
- let(:inline_note) do
- instance_double(
- BitbucketServer::Representation::PullRequestComment,
- file_type: 'ADDED',
- from_sha: sample.commits.first,
- to_sha: sample.commits.last,
- file_path: '.gitmodules',
- old_pos: nil,
- new_pos: 4,
- note: 'Hello world',
- author_email: inline_note_author.email,
- author_username: inline_note_author.username,
- comments: [reply],
- created_at: now,
- updated_at: now,
- parent_comment: nil)
- end
-
- let(:inline_comment) do
- instance_double(
- BitbucketServer::Representation::Activity,
- comment?: true,
- inline_comment?: true,
- merge_event?: false,
- comment: inline_note)
- end
-
- before do
- allow(reply).to receive(:parent_comment).and_return(inline_note)
- allow(subject.client).to receive(:activities).and_return([inline_comment])
- end
-
- shared_examples 'imports threaded discussions' do
- it 'imports threaded discussions' do
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- merge_request = MergeRequest.first
- expect(merge_request.notes.count).to eq(2)
- expect(merge_request.notes.map(&:discussion_id).uniq.count).to eq(1)
-
- notes = merge_request.notes.order(:id).to_a
- start_note = notes.first
- expect(start_note.type).to eq('DiffNote')
- expect(start_note.note).to end_with(inline_note.note)
- expect(start_note.created_at).to eq(inline_note.created_at)
- expect(start_note.updated_at).to eq(inline_note.updated_at)
- expect(start_note.position.base_sha).to eq(inline_note.from_sha)
- expect(start_note.position.start_sha).to eq(inline_note.from_sha)
- expect(start_note.position.head_sha).to eq(inline_note.to_sha)
- expect(start_note.position.old_line).to be_nil
- expect(start_note.position.new_line).to eq(inline_note.new_pos)
- expect(start_note.author).to eq(inline_note_author)
-
- reply_note = notes.last
- # Make sure author and reply context is included
- expect(reply_note.note).to start_with("> #{inline_note.note}\n\n#{reply.note}")
- expect(reply_note.author).to eq(reply_author)
- expect(reply_note.created_at).to eq(reply.created_at)
- expect(reply_note.updated_at).to eq(reply.created_at)
- expect(reply_note.position.base_sha).to eq(inline_note.from_sha)
- expect(reply_note.position.start_sha).to eq(inline_note.from_sha)
- expect(reply_note.position.head_sha).to eq(inline_note.to_sha)
- expect(reply_note.position.old_line).to be_nil
- expect(reply_note.position.new_line).to eq(inline_note.new_pos)
- end
- end
-
- context 'when bitbucket_server_user_mapping_by_username feature flag is disabled' do
- before do
- stub_feature_flags(bitbucket_server_user_mapping_by_username: false)
- end
-
- include_examples 'imports threaded discussions'
- end
-
- context 'when bitbucket_server_user_mapping_by_username feature flag is enabled' do
- before do
- stub_feature_flags(bitbucket_server_user_mapping_by_username: true)
- end
-
- include_examples 'imports threaded discussions' do
- context 'when username is not present' do
- before do
- allow(reply).to receive(:author_username).and_return(nil)
- allow(inline_note).to receive(:author_username).and_return(nil)
- end
-
- it 'defaults to import user' do
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- notes = MergeRequest.first.notes.order(:id).to_a
-
- expect(notes.first.author).to eq(project_creator)
- expect(notes.last.author).to eq(project_creator)
- end
- end
- end
- end
-
- context 'when user is not found' do
- before do
- allow(reply).to receive(:author_username).and_return(nil)
- allow(reply).to receive(:author_email).and_return(nil)
- allow(inline_note).to receive(:author_username).and_return(nil)
- allow(inline_note).to receive(:author_email).and_return(nil)
- end
-
- it 'maps importer user' do
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- notes = MergeRequest.first.notes.order(:id).to_a
-
- expect(notes.first.author).to eq(project_creator)
- expect(notes.last.author).to eq(project_creator)
- end
- end
- end
-
- it 'falls back to comments if diff comments fail to validate' do
- reply = instance_double(
- BitbucketServer::Representation::Comment,
- author_email: 'someuser@gitlab.com',
- author_username: 'Aquaman',
- note: 'I agree',
- created_at: now,
- updated_at: now)
-
- # https://gitlab.com/gitlab-org/gitlab-test/compare/c1acaa58bbcbc3eafe538cb8274ba387047b69f8...5937ac0a7beb003549fc5fd26fc247ad
- inline_note = instance_double(
- BitbucketServer::Representation::PullRequestComment,
- file_type: 'REMOVED',
- from_sha: sample.commits.first,
- to_sha: sample.commits.last,
- file_path: '.gitmodules',
- old_pos: 8,
- new_pos: 9,
- note: 'This is a note with an invalid line position.',
- author_email: project.owner.email,
- author_username: 'Owner',
- comments: [reply],
- created_at: now,
- updated_at: now,
- parent_comment: nil)
-
- inline_comment = instance_double(
- BitbucketServer::Representation::Activity,
- comment?: true,
- inline_comment?: true,
- merge_event?: false,
- comment: inline_note)
-
- allow(reply).to receive(:parent_comment).and_return(inline_note)
-
- expect(subject.client).to receive(:activities).and_return([inline_comment])
-
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- merge_request = MergeRequest.first
- expect(merge_request.notes.count).to eq(2)
- notes = merge_request.notes
-
- expect(notes.first.note).to start_with('*Comment on .gitmodules')
- expect(notes.second.note).to start_with('*Comment on .gitmodules')
- end
-
- it 'reports an error if an exception is raised' do
- allow(subject).to receive(:import_bitbucket_pull_request).and_raise(RuntimeError)
- expect(Gitlab::ErrorTracking).to receive(:log_exception)
-
- subject.execute
- end
-
- describe 'import pull requests with caching' do
- let(:pull_request_already_imported) do
- instance_double(
- BitbucketServer::Representation::PullRequest,
- iid: 11)
- end
-
- let(:pull_request_to_be_imported) do
- instance_double(
- BitbucketServer::Representation::PullRequest,
- iid: 12,
- source_branch_sha: sample.commits.last,
- source_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.source_branch,
- target_branch_sha: sample.commits.first,
- target_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.target_branch,
- title: 'This is a title',
- description: 'This is a test pull request',
- reviewers: sample.reviewers,
- state: 'merged',
- author: 'Test Author',
- author_email: pull_request_author.email,
- author_username: pull_request_author.username,
- created_at: Time.now,
- updated_at: Time.now,
- raw: {},
- merged?: true)
- end
-
- before do
- Gitlab::Cache::Import::Caching.set_add(subject.already_imported_cache_key, pull_request_already_imported.iid)
- allow(subject.client).to receive(:pull_requests).and_return([pull_request_to_be_imported, pull_request_already_imported], [])
- end
-
- it 'only imports one Merge Request, as the other on is in the cache' do
- expect(subject.client).to receive(:activities).and_return([merge_event])
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
-
- expect(Gitlab::Cache::Import::Caching.set_includes?(subject.already_imported_cache_key, pull_request_already_imported.iid)).to eq(true)
- expect(Gitlab::Cache::Import::Caching.set_includes?(subject.already_imported_cache_key, pull_request_to_be_imported.iid)).to eq(true)
- end
- end
- end
-
- describe 'inaccessible branches' do
- let(:id) { 10 }
- let(:temp_branch_from) { "gitlab/import/pull-request/#{id}/from" }
- let(:temp_branch_to) { "gitlab/import/pull-request/#{id}/to" }
-
- before do
- pull_request = instance_double(
- BitbucketServer::Representation::PullRequest,
- iid: id,
- source_branch_sha: '12345678',
- source_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.source_branch,
- target_branch_sha: '98765432',
- target_branch_name: Gitlab::Git::BRANCH_REF_PREFIX + sample.target_branch,
- title: 'This is a title',
- description: 'This is a test pull request',
- reviewers: [],
- state: 'merged',
- author: 'Test Author',
- author_email: project.owner.email,
- author_username: 'author',
- created_at: Time.now,
- updated_at: Time.now,
- merged?: true)
-
- expect(subject.client).to receive(:pull_requests).and_return([pull_request], [])
- expect(subject.client).to receive(:activities).and_return([])
- expect(subject).to receive(:import_repository).twice
- end
-
- it '#restore_branches' do
- expect(subject).to receive(:restore_branches).and_call_original
- expect(subject).to receive(:delete_temp_branches)
- expect(subject.client).to receive(:create_branch)
- .with(project_key, repo_slug,
- temp_branch_from,
- '12345678')
- expect(subject.client).to receive(:create_branch)
- .with(project_key, repo_slug,
- temp_branch_to,
- '98765432')
-
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
- end
-
- it '#delete_temp_branches' do
- expect(subject.client).to receive(:create_branch).twice
- expect(subject).to receive(:delete_temp_branches).and_call_original
- expect(subject.client).to receive(:delete_branch)
- .with(project_key, repo_slug,
- temp_branch_from,
- '12345678')
- expect(subject.client).to receive(:delete_branch)
- .with(project_key, repo_slug,
- temp_branch_to,
- '98765432')
- expect(project.repository).to receive(:delete_branch).with(temp_branch_from)
- expect(project.repository).to receive(:delete_branch).with(temp_branch_to)
-
- expect { subject.execute }.to change { MergeRequest.count }.by(1)
- end
- end
-
- context "lfs files" do
- before do
- allow(project).to receive(:lfs_enabled?).and_return(true)
- allow(subject).to receive(:import_repository)
- allow(subject).to receive(:import_pull_requests)
- end
-
- it "downloads lfs objects if lfs_enabled is enabled for project" do
- expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |lfs_import_service|
- expect(lfs_import_service).to receive(:execute).and_return(status: :success)
- end
-
- subject.execute
- end
-
- it "adds the error message when the lfs download fails" do
- allow_next_instance_of(Projects::LfsPointers::LfsImportService) do |lfs_import_service|
- expect(lfs_import_service).to receive(:execute).and_return(status: :error, message: "LFS server not reachable")
- end
-
- subject.execute
-
- expect(project.import_state.reload.last_error).to eq(Gitlab::Json.dump({
- message: "The remote data could not be fully imported.",
- errors: [{
- type: "lfs_objects",
- errors: "The Lfs import process failed. LFS server not reachable"
- }]
- }))
- end
- end
-end
diff --git a/spec/lib/gitlab/checks/matching_merge_request_spec.rb b/spec/lib/gitlab/checks/matching_merge_request_spec.rb
index c65a1e4d656..5397aea90a9 100644
--- a/spec/lib/gitlab/checks/matching_merge_request_spec.rb
+++ b/spec/lib/gitlab/checks/matching_merge_request_spec.rb
@@ -31,33 +31,40 @@ RSpec.describe Gitlab::Checks::MatchingMergeRequest do
expect(matcher.match?).to be false
end
- context 'with load balancing enabled' do
+ context 'with load balancing enabled', :redis do
let(:session) { ::Gitlab::Database::LoadBalancing::Session.current }
- let(:all_caught_up) { true }
before do
+ # Need to mock as though we actually have replicas
+ allow(::ApplicationRecord.load_balancer)
+ .to receive(:primary_only?)
+ .and_return(false)
+
+ # Put some sticking position for the primary in Redis
+ ::ApplicationRecord.sticking.stick(:project, project.id)
+
Gitlab::Database::LoadBalancing::Session.clear_session
- allow(::ApplicationRecord.sticking)
- .to receive(:all_caught_up?)
- .and_return(all_caught_up)
+ # Mock the load balancer result since we don't actually have real replicas to match against
+ expect(::ApplicationRecord.load_balancer)
+ .to receive(:select_up_to_date_host)
+ .and_return(load_balancer_result)
+ # Expect sticking called with correct arguments but don't mock it so that we can also test the internal
+ # behaviour of updating the Session.use_primary?
expect(::ApplicationRecord.sticking)
- .to receive(:select_valid_host)
- .with(:project, project.id)
+ .to receive(:find_caught_up_replica)
+ .with(:project, project.id, use_primary_on_empty_location: true)
.and_call_original
-
- allow(::ApplicationRecord.sticking)
- .to receive(:select_caught_up_replicas)
- .with(:project, project.id)
- .and_return(all_caught_up)
end
after do
Gitlab::Database::LoadBalancing::Session.clear_session
end
- shared_examples 'secondary that has caught up to a primary' do
+ context 'when any secondary is caught up' do
+ let(:load_balancer_result) { ::Gitlab::Database::LoadBalancing::LoadBalancer::ANY_CAUGHT_UP }
+
it 'continues to use the secondary' do
expect(session.use_primary?).to be false
expect(subject.match?).to be true
@@ -70,7 +77,9 @@ RSpec.describe Gitlab::Checks::MatchingMergeRequest do
end
end
- shared_examples 'secondary that is lagging primary' do
+ context 'when all secondaries are lagging behind' do
+ let(:load_balancer_result) { ::Gitlab::Database::LoadBalancing::LoadBalancer::NONE_CAUGHT_UP }
+
it 'sticks to the primary' do
expect(subject.match?).to be true
expect(session.use_primary?).to be true
@@ -82,14 +91,6 @@ RSpec.describe Gitlab::Checks::MatchingMergeRequest do
.and change { stale_counter.get }.by(1)
end
end
-
- it_behaves_like 'secondary that has caught up to a primary'
-
- context 'on secondary behind primary' do
- let(:all_caught_up) { false }
-
- it_behaves_like 'secondary that is lagging primary'
- end
end
end
end
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
index efe99cd276c..1f3ba0ef76e 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Build::Artifacts::Metadata do
+RSpec.describe Gitlab::Ci::Build::Artifacts::Metadata, feature_category: :build_artifacts do
def metadata(path = '', **opts)
described_class.new(metadata_file_stream, path, **opts)
end
@@ -19,132 +19,158 @@ RSpec.describe Gitlab::Ci::Build::Artifacts::Metadata do
metadata_file_stream&.close
end
- context 'metadata file exists' do
- describe '#find_entries! empty string' do
- subject { metadata('').find_entries! }
+ describe '#to_entry' do
+ subject(:entry) { metadata.to_entry }
- it 'matches correct paths' do
- expect(subject.keys).to contain_exactly 'ci_artifacts.txt',
- 'other_artifacts_0.1.2/',
- 'rails_sample.jpg',
- 'tests_encoding/'
- end
-
- it 'matches metadata for every path' do
- expect(subject.keys.count).to eq 4
- end
+ it { is_expected.to be_an_instance_of(Gitlab::Ci::Build::Artifacts::Metadata::Entry) }
- it 'return Hashes for each metadata' do
- expect(subject.values).to all(be_kind_of(Hash))
+ context 'when given path starts with a ./ prefix' do
+ it 'instantiates the entry without the ./ prefix from the path' do
+ meta = metadata("./some/path")
+ expect(Gitlab::Ci::Build::Artifacts::Metadata::Entry).to receive(:new).with("some/path", {})
+ meta.to_entry
end
end
+ end
- describe '#find_entries! other_artifacts_0.1.2/' do
- subject { metadata('other_artifacts_0.1.2/').find_entries! }
+ describe '#full_version' do
+ subject { metadata.full_version }
- it 'matches correct paths' do
- expect(subject.keys)
- .to contain_exactly 'other_artifacts_0.1.2/',
- 'other_artifacts_0.1.2/doc_sample.txt',
- 'other_artifacts_0.1.2/another-subdirectory/'
- end
- end
+ it { is_expected.to eq 'GitLab Build Artifacts Metadata 0.0.1' }
+ end
- describe '#find_entries! other_artifacts_0.1.2/another-subdirectory/' do
- subject { metadata('other_artifacts_0.1.2/another-subdirectory/').find_entries! }
+ describe '#version' do
+ subject { metadata.version }
- it 'matches correct paths' do
- expect(subject.keys)
- .to contain_exactly 'other_artifacts_0.1.2/another-subdirectory/',
- 'other_artifacts_0.1.2/another-subdirectory/empty_directory/',
- 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif'
- end
- end
+ it { is_expected.to eq '0.0.1' }
+ end
- describe '#find_entries! recursively for other_artifacts_0.1.2/' do
- subject { metadata('other_artifacts_0.1.2/', recursive: true).find_entries! }
+ describe '#errors' do
+ subject { metadata.errors }
- it 'matches correct paths' do
- expect(subject.keys)
- .to contain_exactly 'other_artifacts_0.1.2/',
- 'other_artifacts_0.1.2/doc_sample.txt',
- 'other_artifacts_0.1.2/another-subdirectory/',
- 'other_artifacts_0.1.2/another-subdirectory/empty_directory/',
- 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif'
- end
- end
+ it { is_expected.to eq({}) }
+ end
- describe '#to_entry' do
- subject { metadata('').to_entry }
+ describe '#find_entries!' do
+ let(:recursive) { false }
- it { is_expected.to be_an_instance_of(Gitlab::Ci::Build::Artifacts::Metadata::Entry) }
- end
+ subject(:find_entries) { metadata(path, recursive: recursive).find_entries! }
- describe '#full_version' do
- subject { metadata('').full_version }
+ context 'when metadata file exists' do
+ context 'and given path is an empty string' do
+ let(:path) { '' }
- it { is_expected.to eq 'GitLab Build Artifacts Metadata 0.0.1' }
- end
+ it 'returns paths to all files and directories at the root level' do
+ expect(find_entries.keys).to contain_exactly(
+ 'ci_artifacts.txt',
+ 'other_artifacts_0.1.2/',
+ 'rails_sample.jpg',
+ 'tests_encoding/'
+ )
+ end
- describe '#version' do
- subject { metadata('').version }
+ it 'return Hashes for each metadata' do
+ expect(find_entries.values).to all(be_kind_of(Hash))
+ end
+ end
- it { is_expected.to eq '0.0.1' }
- end
+ shared_examples 'finding entries for a given path' do |options|
+ let(:path) { "#{options[:path_prefix]}#{target_path}" }
+
+ context 'when given path targets a directory at the root level' do
+ let(:target_path) { 'other_artifacts_0.1.2/' }
+
+ it 'returns paths to all files and directories at the first level of the directory' do
+ expect(find_entries.keys).to contain_exactly(
+ 'other_artifacts_0.1.2/',
+ 'other_artifacts_0.1.2/doc_sample.txt',
+ 'other_artifacts_0.1.2/another-subdirectory/'
+ )
+ end
+ end
+
+ context 'when given path targets a sub-directory' do
+ let(:target_path) { 'other_artifacts_0.1.2/another-subdirectory/' }
+
+ it 'returns paths to all files and directories at the first level of the sub-directory' do
+ expect(find_entries.keys).to contain_exactly(
+ 'other_artifacts_0.1.2/another-subdirectory/',
+ 'other_artifacts_0.1.2/another-subdirectory/empty_directory/',
+ 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif'
+ )
+ end
+ end
+
+ context 'when given path targets a directory recursively' do
+ let(:target_path) { 'other_artifacts_0.1.2/' }
+ let(:recursive) { true }
+
+ it 'returns all paths recursively within the target directory' do
+ expect(subject.keys).to contain_exactly(
+ 'other_artifacts_0.1.2/',
+ 'other_artifacts_0.1.2/doc_sample.txt',
+ 'other_artifacts_0.1.2/another-subdirectory/',
+ 'other_artifacts_0.1.2/another-subdirectory/empty_directory/',
+ 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif'
+ )
+ end
+ end
+ end
- describe '#errors' do
- subject { metadata('').errors }
+ context 'and given path does not start with a ./ prefix' do
+ it_behaves_like 'finding entries for a given path', path_prefix: ''
+ end
- it { is_expected.to eq({}) }
+ context 'and given path starts with a ./ prefix' do
+ it_behaves_like 'finding entries for a given path', path_prefix: './'
+ end
end
- end
- context 'metadata file does not exist' do
- let(:metadata_file_path) { nil }
+ context 'when metadata file stream is nil' do
+ let(:path) { '' }
+ let(:metadata_file_stream) { nil }
- describe '#find_entries!' do
it 'raises error' do
- expect { metadata.find_entries! }.to raise_error(described_class::InvalidStreamError, /Invalid stream/)
+ expect { find_entries }.to raise_error(described_class::InvalidStreamError, /Invalid stream/)
end
end
- end
- context 'metadata file is invalid' do
- let(:metadata_file_path) { Rails.root + 'spec/fixtures/ci_build_artifacts.zip' }
+ context 'when metadata file is invalid' do
+ let(:path) { '' }
+ let(:metadata_file_path) { Rails.root + 'spec/fixtures/ci_build_artifacts.zip' }
- describe '#find_entries!' do
it 'raises error' do
- expect { metadata.find_entries! }.to raise_error(described_class::InvalidStreamError, /not in gzip format/)
+ expect { find_entries }.to raise_error(described_class::InvalidStreamError, /not in gzip format/)
end
end
- end
- context 'generated metadata' do
- let(:tmpfile) { Tempfile.new('test-metadata') }
- let(:generator) { CiArtifactMetadataGenerator.new(tmpfile) }
- let(:entry_count) { 5 }
+ context 'with generated metadata' do
+ let(:tmpfile) { Tempfile.new('test-metadata') }
+ let(:generator) { CiArtifactMetadataGenerator.new(tmpfile) }
+ let(:entry_count) { 5 }
- before do
- tmpfile.binmode
+ before do
+ tmpfile.binmode
- (1..entry_count).each do |index|
- generator.add_entry("public/test-#{index}.txt")
- end
+ (1..entry_count).each do |index|
+ generator.add_entry("public/test-#{index}.txt")
+ end
- generator.write
- end
+ generator.write
+ end
- after do
- File.unlink(tmpfile.path)
- end
+ after do
+ File.unlink(tmpfile.path)
+ end
- describe '#find_entries!' do
- it 'reads expected number of entries' do
- stream = File.open(tmpfile.path)
+ describe '#find_entries!' do
+ it 'reads expected number of entries' do
+ stream = File.open(tmpfile.path)
- metadata = described_class.new(stream, 'public', recursive: true)
+ metadata = described_class.new(stream, 'public', recursive: true)
- expect(metadata.find_entries!.count).to eq entry_count
+ expect(metadata.find_entries!.count).to eq entry_count
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/build/duration_parser_spec.rb b/spec/lib/gitlab/ci/build/duration_parser_spec.rb
index 7f5ff1eb0ee..bc905aa0a35 100644
--- a/spec/lib/gitlab/ci/build/duration_parser_spec.rb
+++ b/spec/lib/gitlab/ci/build/duration_parser_spec.rb
@@ -25,8 +25,8 @@ RSpec.describe Gitlab::Ci::Build::DurationParser do
it { is_expected.to be_truthy }
it 'caches data' do
- expect(ChronicDuration).to receive(:parse).with(value).once.and_call_original
- expect(ChronicDuration).to receive(:parse).with(other_value).once.and_call_original
+ expect(ChronicDuration).to receive(:parse).with(value, use_complete_matcher: true).once.and_call_original
+ expect(ChronicDuration).to receive(:parse).with(other_value, use_complete_matcher: true).once.and_call_original
2.times do
expect(described_class.validate_duration(value)).to eq(86400)
@@ -41,7 +41,7 @@ RSpec.describe Gitlab::Ci::Build::DurationParser do
it { is_expected.to be_falsy }
it 'caches data' do
- expect(ChronicDuration).to receive(:parse).with(value).once.and_call_original
+ expect(ChronicDuration).to receive(:parse).with(value, use_complete_matcher: true).once.and_call_original
2.times do
expect(described_class.validate_duration(value)).to be_falsey
diff --git a/spec/lib/gitlab/ci/components/instance_path_spec.rb b/spec/lib/gitlab/ci/components/instance_path_spec.rb
index f4bc706f9b4..97843781891 100644
--- a/spec/lib/gitlab/ci/components/instance_path_spec.rb
+++ b/spec/lib/gitlab/ci/components/instance_path_spec.rb
@@ -14,125 +14,214 @@ RSpec.describe Gitlab::Ci::Components::InstancePath, feature_category: :pipeline
end
describe 'FQDN path' do
- let_it_be(:existing_project) { create(:project, :repository) }
-
- let(:project_path) { existing_project.full_path }
- let(:address) { "acme.com/#{project_path}/component@#{version}" }
let(:version) { 'master' }
+ let(:project_path) { project.full_path }
+ let(:address) { "acme.com/#{project_path}/secret-detection@#{version}" }
+
+ context 'when the project repository contains a templates directory' do
+ let_it_be(:project) do
+ create(
+ :project, :custom_repo,
+ files: {
+ 'templates/secret-detection.yml' => 'image: alpine_1',
+ 'templates/dast/template.yml' => 'image: alpine_2',
+ 'templates/dast/another-template.yml' => 'image: alpine_3',
+ 'templates/dast/another-folder/template.yml' => 'image: alpine_4'
+ }
+ )
+ end
- context 'when project exists' do
- it 'provides the expected attributes', :aggregate_failures do
- expect(path.project).to eq(existing_project)
- expect(path.host).to eq(current_host)
- expect(path.sha).to eq(existing_project.commit('master').id)
- expect(path.project_file_path).to eq('component/template.yml')
+ before do
+ project.add_developer(user)
end
- context 'when content exists' do
- let(:content) { 'image: alpine' }
+ context 'when user does not have permissions' do
+ it 'raises an error when fetching the content' do
+ expect { path.fetch_content!(current_user: build(:user)) }
+ .to raise_error(Gitlab::Access::AccessDeniedError)
+ end
+ end
- before do
- allow_next_instance_of(Repository) do |instance|
- allow(instance)
- .to receive(:blob_data_at)
- .with(existing_project.commit('master').id, 'component/template.yml')
- .and_return(content)
- end
+ context 'when the component is simple (single file template)' do
+ it 'fetches the component content', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to eq('image: alpine_1')
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to eq('templates/secret-detection.yml')
+ expect(path.project).to eq(project)
+ expect(path.sha).to eq(project.commit('master').id)
end
+ end
- context 'when user has permissions to read code' do
- before do
- existing_project.add_developer(user)
- end
+ context 'when the component is complex (directory-based template)' do
+ let(:address) { "acme.com/#{project_path}/dast@#{version}" }
+
+ it 'fetches the component content', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to eq('image: alpine_2')
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to eq('templates/dast/template.yml')
+ expect(path.project).to eq(project)
+ expect(path.sha).to eq(project.commit('master').id)
+ end
- it 'fetches the content' do
- expect(path.fetch_content!(current_user: user)).to eq(content)
+ context 'when there is an invalid nested component folder' do
+ let(:address) { "acme.com/#{project_path}/dast/another-folder@#{version}" }
+
+ it 'returns nil' do
+ expect(path.fetch_content!(current_user: user)).to be_nil
end
end
- context 'when user does not have permissions to download code' do
- it 'raises an error when fetching the content' do
- expect { path.fetch_content!(current_user: user) }
- .to raise_error(Gitlab::Access::AccessDeniedError)
+ context 'when there is an invalid nested component path' do
+ let(:address) { "acme.com/#{project_path}/dast/another-template@#{version}" }
+
+ it 'returns nil' do
+ expect(path.fetch_content!(current_user: user)).to be_nil
end
end
end
- end
- context 'when project path is nested under a subgroup' do
- let(:existing_group) { create(:group, :nested) }
- let(:existing_project) { create(:project, :repository, group: existing_group) }
+ context 'when fetching the latest version of a component' do
+ let_it_be(:project) do
+ create(
+ :project, :custom_repo,
+ files: {
+ 'templates/secret-detection.yml' => 'image: alpine_1'
+ }
+ )
+ end
- it 'provides the expected attributes', :aggregate_failures do
- expect(path.project).to eq(existing_project)
- expect(path.host).to eq(current_host)
- expect(path.sha).to eq(existing_project.commit('master').id)
- expect(path.project_file_path).to eq('component/template.yml')
- end
- end
+ let(:version) { '~latest' }
- context 'when current GitLab instance is installed on a relative URL' do
- let(:address) { "acme.com/gitlab/#{project_path}/component@#{version}" }
- let(:current_host) { 'acme.com/gitlab/' }
+ let(:latest_sha) do
+ project.repository.commit('master').id
+ end
- it 'provides the expected attributes', :aggregate_failures do
- expect(path.project).to eq(existing_project)
- expect(path.host).to eq(current_host)
- expect(path.sha).to eq(existing_project.commit('master').id)
- expect(path.project_file_path).to eq('component/template.yml')
+ before do
+ create(:release, project: project, sha: project.repository.root_ref_sha,
+ released_at: Time.zone.now - 1.day)
+
+ project.repository.update_file(
+ user, 'templates/secret-detection.yml', 'image: alpine_2',
+ message: 'Updates image', branch_name: project.default_branch
+ )
+
+ create(:release, project: project, sha: latest_sha,
+ released_at: Time.zone.now)
+ end
+
+ it 'fetches the component content', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to eq('image: alpine_2')
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to eq('templates/secret-detection.yml')
+ expect(path.project).to eq(project)
+ expect(path.sha).to eq(latest_sha)
+ end
end
- end
- context 'when version does not exist' do
- let(:version) { 'non-existent' }
+ context 'when version does not exist' do
+ let(:version) { 'non-existent' }
- it 'provides the expected attributes', :aggregate_failures do
- expect(path.project).to eq(existing_project)
- expect(path.host).to eq(current_host)
- expect(path.sha).to be_nil
- expect(path.project_file_path).to eq('component/template.yml')
+ it 'returns nil', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to be_nil
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to be_nil
+ expect(path.project).to eq(project)
+ expect(path.sha).to be_nil
+ end
end
- it 'returns nil when fetching the content' do
- expect(path.fetch_content!(current_user: user)).to be_nil
+ context 'when current GitLab instance is installed on a relative URL' do
+ let(:address) { "acme.com/gitlab/#{project_path}/secret-detection@#{version}" }
+ let(:current_host) { 'acme.com/gitlab/' }
+
+ it 'fetches the component content', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to eq('image: alpine_1')
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to eq('templates/secret-detection.yml')
+ expect(path.project).to eq(project)
+ expect(path.sha).to eq(project.commit('master').id)
+ end
end
end
- context 'when version is `~latest`' do
- let(:version) { '~latest' }
+ # All the following tests are for deprecated code and will be removed
+ # in https://gitlab.com/gitlab-org/gitlab/-/issues/415855
+ context 'when the project does not contain a templates directory' do
+ let(:project_path) { project.full_path }
+ let(:address) { "acme.com/#{project_path}/component@#{version}" }
+
+ let_it_be(:project) do
+ create(
+ :project, :custom_repo,
+ files: {
+ 'component/template.yml' => 'image: alpine'
+ }
+ )
+ end
+
+ before do
+ project.add_developer(user)
+ end
- context 'when project has releases' do
- let_it_be(:latest_release) do
- create(:release, project: existing_project, sha: 'sha-1', released_at: Time.zone.now)
- end
+ it 'fetches the component content', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to eq('image: alpine')
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to eq('component/template.yml')
+ expect(path.project).to eq(project)
+ expect(path.sha).to eq(project.commit('master').id)
+ end
- before_all do
- # Previous release
- create(:release, project: existing_project, sha: 'sha-2', released_at: Time.zone.now - 1.day)
+ context 'when project path is nested under a subgroup' do
+ let_it_be(:group) { create(:group, :nested) }
+ let_it_be(:project) do
+ create(
+ :project, :custom_repo,
+ files: {
+ 'component/template.yml' => 'image: alpine'
+ },
+ group: group
+ )
end
- it 'returns the sha of the latest release' do
- expect(path.sha).to eq(latest_release.sha)
+ it 'fetches the component content', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to eq('image: alpine')
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to eq('component/template.yml')
+ expect(path.project).to eq(project)
+ expect(path.sha).to eq(project.commit('master').id)
end
end
- context 'when project does not have releases' do
- it { expect(path.sha).to be_nil }
+ context 'when current GitLab instance is installed on a relative URL' do
+ let(:address) { "acme.com/gitlab/#{project_path}/component@#{version}" }
+ let(:current_host) { 'acme.com/gitlab/' }
+
+ it 'fetches the component content', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to eq('image: alpine')
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to eq('component/template.yml')
+ expect(path.project).to eq(project)
+ expect(path.sha).to eq(project.commit('master').id)
+ end
end
- end
- context 'when project does not exist' do
- let(:project_path) { 'non-existent/project' }
+ context 'when version does not exist' do
+ let(:version) { 'non-existent' }
- it 'provides the expected attributes', :aggregate_failures do
- expect(path.project).to be_nil
- expect(path.host).to eq(current_host)
- expect(path.sha).to be_nil
- expect(path.project_file_path).to be_nil
+ it 'returns nil', :aggregate_failures do
+ expect(path.fetch_content!(current_user: user)).to be_nil
+ expect(path.host).to eq(current_host)
+ expect(path.project_file_path).to be_nil
+ expect(path.project).to eq(project)
+ expect(path.sha).to be_nil
+ end
end
- it 'returns nil when fetching the content' do
- expect(path.fetch_content!(current_user: user)).to be_nil
+ context 'when user does not have permissions' do
+ it 'raises an error when fetching the content' do
+ expect { path.fetch_content!(current_user: build(:user)) }
+ .to raise_error(Gitlab::Access::AccessDeniedError)
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index 736c184a289..567ffa68836 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
# as they do not have sense in context of Bridge
let(:ignored_inheritable_columns) do
%i[before_script after_script hooks image services cache interruptible timeout
- retry tags artifacts]
+ retry tags artifacts id_tokens]
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/default_spec.rb b/spec/lib/gitlab/ci/config/entry/default_spec.rb
index 46e96843ee3..17e716629cd 100644
--- a/spec/lib/gitlab/ci/config/entry/default_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/default_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Default do
it 'contains the expected node names' do
expect(described_class.nodes.keys)
.to match_array(%i[before_script after_script hooks cache image services
- interruptible timeout retry tags artifacts])
+ interruptible timeout retry tags artifacts id_tokens])
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb b/spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb
index dd15b049b9b..cd8e35ede61 100644
--- a/spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/include/rules/rule_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper' # Change this to fast spec helper when FF `ci_refactor_external_rules` is removed
+require 'fast_spec_helper'
require_dependency 'active_model'
RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules::Rule, feature_category: :pipeline_composition do
@@ -14,21 +14,11 @@ RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules::Rule, feature_category
entry.compose!
end
- shared_examples 'a valid config' do
+ shared_examples 'a valid config' do |expected_value = nil|
it { is_expected.to be_valid }
it 'returns the expected value' do
- expect(entry.value).to eq(config.compact)
- end
-
- context 'when FF `ci_refactor_external_rules` is disabled' do
- before do
- stub_feature_flags(ci_refactor_external_rules: false)
- end
-
- it 'returns the expected value' do
- expect(entry.value).to eq(config)
- end
+ expect(entry.value).to eq(expected_value || config.compact)
end
end
@@ -99,19 +89,37 @@ RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules::Rule, feature_category
it_behaves_like 'a valid config'
- context 'when array' do
+ context 'when exists: clause is an array' do
let(:config) { { exists: ['./this.md', './that.md'] } }
it_behaves_like 'a valid config'
end
- context 'when null' do
+ context 'when exists: clause is null' do
let(:config) { { exists: nil } }
it_behaves_like 'a valid config'
end
end
+ context 'when specifying a changes: clause' do
+ let(:config) { { changes: %w[Dockerfile lib/* paths/**/*.rb] } }
+
+ it_behaves_like 'a valid config', { changes: { paths: %w[Dockerfile lib/* paths/**/*.rb] } }
+
+ context 'with paths:' do
+ let(:config) { { changes: { paths: %w[Dockerfile lib/* paths/**/*.rb] } } }
+
+ it_behaves_like 'a valid config'
+ end
+
+ context 'with paths: and compare_to:' do
+ let(:config) { { changes: { paths: ['Dockerfile'], compare_to: 'branch1' } } }
+
+ it_behaves_like 'a valid config'
+ end
+ end
+
context 'when specifying an unknown keyword' do
let(:config) { { invalid: :something } }
diff --git a/spec/lib/gitlab/ci/config/entry/include/rules_spec.rb b/spec/lib/gitlab/ci/config/entry/include/rules_spec.rb
index 05db81abfc1..503020e2202 100644
--- a/spec/lib/gitlab/ci/config/entry/include/rules_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/include/rules_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper' # Change this to fast spec helper when FF `ci_refactor_external_rules` is removed
+require 'fast_spec_helper'
require_dependency 'active_model'
RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules, feature_category: :pipeline_composition do
@@ -50,7 +50,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules, feature_category: :pip
entry.compose!
end
- it_behaves_like 'an invalid config', /contains unknown keys: changes/
+ it_behaves_like 'a valid config'
end
end
@@ -80,7 +80,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules, feature_category: :pip
let(:config) do
[
{ if: '$THIS == "that"' },
- { if: '$SKIP', when: 'never' }
+ { if: '$SKIP', when: 'never' },
+ { changes: ['Dockerfile'] }
]
end
@@ -96,7 +97,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules, feature_category: :pip
is_expected.to eq(
[
{ if: '$THIS == "that"' },
- { if: '$SKIP', when: 'never' }
+ { if: '$SKIP', when: 'never' },
+ { changes: { paths: ['Dockerfile'] } }
]
)
end
@@ -115,30 +117,5 @@ RSpec.describe Gitlab::Ci::Config::Entry::Include::Rules, feature_category: :pip
end
end
end
-
- context 'when FF `ci_refactor_external_rules` is disabled' do
- before do
- stub_feature_flags(ci_refactor_external_rules: false)
- end
-
- context 'with an "if"' do
- let(:config) do
- [{ if: '$THIS == "that"' }]
- end
-
- it { is_expected.to eq(config) }
- end
-
- context 'with a list of two rules' do
- let(:config) do
- [
- { if: '$THIS == "that"' },
- { if: '$SKIP' }
- ]
- end
-
- it { is_expected.to eq(config) }
- end
- end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 4be7c11fab0..1a78d929871 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_composition do
+ using RSpec::Parameterized::TableSyntax
+
let(:entry) { described_class.new(config, name: :rspec) }
it_behaves_like 'with inheritable CI config' do
@@ -29,7 +31,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
let(:result) do
%i[before_script script after_script hooks stage cache
image services only except rules needs variables artifacts
- environment coverage retry interruptible timeout release tags
+ coverage retry interruptible timeout release tags
inherit parallel]
end
@@ -696,8 +698,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
end
context 'with workflow rules' do
- using RSpec::Parameterized::TableSyntax
-
where(:name, :has_workflow_rules?, :only, :rules, :result) do
"uses default only" | false | nil | nil | { refs: %w[branches tags] }
"uses user only" | false | %w[branches] | nil | { refs: %w[branches] }
@@ -739,6 +739,20 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
end
end
+ describe '#pages_job?', :aggregate_failures, feature_category: :pages do
+ where(:name, :result) do
+ :pages | true
+ :'pages:staging' | false
+ :'something:pages:else' | false
+ end
+
+ with_them do
+ subject { described_class.new({}, name: name).pages_job? }
+
+ it { is_expected.to eq(result) }
+ end
+ end
+
context 'when composed' do
before do
entry.compose!
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index 4f13940d7e2..132e75a808b 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -371,6 +371,39 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable, feature_category: :pipeli
end
end
+ context 'with environment' do
+ context 'when environment name is specified' do
+ let(:config) { { script: 'ls', environment: 'prod' }.compact }
+
+ it 'sets environment name and action to the entry value' do
+ entry.compose!(deps)
+
+ expect(entry.value[:environment]).to eq({ action: 'start', name: 'prod' })
+ expect(entry.value[:environment_name]).to eq('prod')
+ end
+ end
+
+ context 'when environment name, url and action are specified' do
+ let(:config) do
+ {
+ script: 'ls',
+ environment: {
+ name: 'staging',
+ url: 'https://gitlab.com',
+ action: 'prepare'
+ }
+ }.compact
+ end
+
+ it 'sets environment name, action and url to the entry value' do
+ entry.compose!(deps)
+
+ expect(entry.value[:environment]).to eq({ action: 'prepare', name: 'staging', url: 'https://gitlab.com' })
+ expect(entry.value[:environment_name]).to eq('staging')
+ end
+ end
+ end
+
context 'with inheritance' do
context 'of default:tags' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/lib/gitlab/ci/config/external/context_spec.rb b/spec/lib/gitlab/ci/config/external/context_spec.rb
index d8bd578be94..9ac72ebbac8 100644
--- a/spec/lib/gitlab/ci/config/external/context_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/context_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipeline_composition do
let(:project) { build(:project) }
+ let(:pipeline) { double('Pipeline') }
let(:user) { double('User') }
let(:sha) { '12345' }
let(:variables) { Gitlab::Ci::Variables::Collection.new([{ 'key' => 'a', 'value' => 'b' }]) }
@@ -11,6 +12,7 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
let(:attributes) do
{
project: project,
+ pipeline: pipeline,
user: user,
sha: sha,
variables: variables,
@@ -32,7 +34,7 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
end
context 'without values' do
- let(:attributes) { { project: nil, user: nil, sha: nil } }
+ let(:attributes) { { project: nil, pipeline: nil, user: nil, sha: nil } }
it { is_expected.to have_attributes(**attributes) }
it { expect(subject.expandset).to eq([]) }
@@ -148,6 +150,7 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
let(:attributes) do
{
project: project,
+ pipeline: pipeline,
user: user,
sha: sha,
logger: double('logger')
@@ -165,6 +168,7 @@ RSpec.describe Gitlab::Ci::Config::External::Context, feature_category: :pipelin
it { expect(mutated).not_to eq(subject) }
it { expect(mutated).to be_a(described_class) }
it { expect(mutated).to have_attributes(new_attributes) }
+ it { expect(mutated.pipeline).to eq(subject.pipeline) }
it { expect(mutated.expandset).to eq(subject.expandset) }
it { expect(mutated.execution_deadline).to eq(mutated.execution_deadline) }
it { expect(mutated.logger).to eq(mutated.logger) }
diff --git a/spec/lib/gitlab/ci/config/external/file/component_spec.rb b/spec/lib/gitlab/ci/config/external/file/component_spec.rb
index 487690296b5..0f7b811b5df 100644
--- a/spec/lib/gitlab/ci/config/external/file/component_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/component_spec.rb
@@ -120,6 +120,41 @@ RSpec.describe Gitlab::Ci::Config::External::File::Component, feature_category:
end
end
+ describe '#content' do
+ context 'when component is valid' do
+ let(:content) do
+ <<~COMPONENT
+ job:
+ script: echo
+ COMPONENT
+ end
+
+ let(:response) do
+ ServiceResponse.success(payload: {
+ content: content,
+ path: instance_double(::Gitlab::Ci::Components::InstancePath, project: project, sha: '12345')
+ })
+ end
+
+ it 'tracks the event' do
+ expect(::Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with('cicd_component_usage',
+ values: external_resource.context.user.id)
+
+ external_resource.content
+ end
+ end
+
+ context 'when component is invalid' do
+ let(:content) { 'the-content' }
+
+ it 'does not track the event' do
+ expect(::Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+
+ external_resource.content
+ end
+ end
+ end
+
describe '#metadata' do
subject(:metadata) { external_resource.metadata }
diff --git a/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb
index 69b0524be9e..f542c0485e0 100644
--- a/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb
@@ -409,32 +409,6 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category:
expect { process }.to raise_error(expected_error_class)
end
end
-
- context 'when introduce_ci_max_total_yaml_size_bytes is disabled' do
- before do
- stub_feature_flags(introduce_ci_max_total_yaml_size_bytes: false)
- end
-
- context 'when pipeline tree size is within the limit' do
- before do
- stub_application_setting(ci_max_total_yaml_size_bytes: 10000)
- end
-
- it 'passes the verification' do
- expect(process.all?(&:valid?)).to be_truthy
- end
- end
-
- context 'when pipeline tree size is larger then the limit' do
- before do
- stub_application_setting(ci_max_total_yaml_size_bytes: 100)
- end
-
- it 'passes the verification' do
- expect(process.all?(&:valid?)).to be_truthy
- end
- end
- end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index 19113ce6a4e..68cdf56f198 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -557,21 +557,11 @@ RSpec.describe Gitlab::Ci::Config::External::Processor, feature_category: :pipel
context 'when rules defined' do
context 'when a rule is invalid' do
let(:values) do
- { include: [{ local: 'builds.yml', rules: [{ changes: ['$MY_VAR'] }] }] }
+ { include: [{ local: 'builds.yml', rules: [{ allow_failure: ['$MY_VAR'] }] }] }
end
it 'raises IncludeError' do
- expect { subject }.to raise_error(described_class::IncludeError, /contains unknown keys: changes/)
- end
-
- context 'when FF `ci_refactor_external_rules` is disabled' do
- before do
- stub_feature_flags(ci_refactor_external_rules: false)
- end
-
- it 'raises IncludeError' do
- expect { subject }.to raise_error(described_class::IncludeError, /invalid include rule/)
- end
+ expect { subject }.to raise_error(described_class::IncludeError, /contains unknown keys: allow_failure/)
end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/rules_spec.rb b/spec/lib/gitlab/ci/config/external/rules_spec.rb
index 8674af7ab65..15d7801ff2a 100644
--- a/spec/lib/gitlab/ci/config/external/rules_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/rules_spec.rb
@@ -4,76 +4,45 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::External::Rules, feature_category: :pipeline_composition do
let(:context) { double(variables_hash: {}) }
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"' }] }
+ let(:rule_hashes) {}
+ let(:pipeline) { instance_double(Ci::Pipeline) }
+ let_it_be(:project) { create(:project, :custom_repo, files: { 'file.txt' => 'file' }) }
subject(:rules) { described_class.new(rule_hashes) }
+ before do
+ allow(context).to receive(:project).and_return(project)
+ allow(context).to receive(:pipeline).and_return(pipeline)
+ end
+
describe '#evaluate' do
subject(:result) { rules.evaluate(context).pass? }
context 'when there is no rule' do
- let(:rule_hashes) {}
-
it { is_expected.to eq(true) }
end
- shared_examples 'when there is a rule with if' do |rule_matched_result = true, rule_not_matched_result = false|
- context 'when the rule matches' do
- let(:context) { double(variables_hash: { 'MY_VAR' => 'hello' }) }
-
- it { is_expected.to eq(rule_matched_result) }
- end
-
- context 'when the rule does not match' do
- let(:context) { double(variables_hash: { 'MY_VAR' => 'invalid' }) }
-
- it { is_expected.to eq(rule_not_matched_result) }
- end
- end
-
- shared_examples 'when there is a rule with exists' do |file_exists_result = true, file_not_exists_result = false|
- let(:project) { create(:project, :repository) }
-
- context 'when the file exists' do
- let(:context) { double(project: project, sha: project.repository.tree.sha, top_level_worktree_paths: ['Dockerfile']) }
-
+ shared_examples 'with when: specified' do
+ context 'with when: never' do
before do
- project.repository.create_file(project.first_owner, 'Dockerfile', "commit", message: 'test', branch_name: "master")
+ rule_hashes.first[:when] = 'never'
end
- it { is_expected.to eq(file_exists_result) }
- end
-
- context 'when the file does not exist' do
- let(:context) { double(project: project, sha: project.repository.tree.sha, top_level_worktree_paths: ['test.md']) }
-
- it { is_expected.to eq(file_not_exists_result) }
- end
- end
-
- it_behaves_like 'when there is a rule with if'
-
- context 'when there is a rule with exists' do
- let(:rule_hashes) { [{ exists: 'Dockerfile' }] }
-
- it_behaves_like 'when there is a rule with exists'
- end
-
- context 'when there is a rule with if and when' do
- context 'with when: never' do
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: 'never' }] }
-
- it_behaves_like 'when there is a rule with if', false, false
+ it { is_expected.to eq(false) }
end
context 'with when: always' do
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: 'always' }] }
+ before do
+ rule_hashes.first[:when] = 'always'
+ end
- it_behaves_like 'when there is a rule with if'
+ it { is_expected.to eq(true) }
end
context 'with when: <invalid string>' do
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: 'on_success' }] }
+ before do
+ rule_hashes.first[:when] = 'on_success'
+ end
it 'raises an error' do
expect { result }.to raise_error(described_class::InvalidIncludeRulesError, /when unknown value: on_success/)
@@ -81,132 +50,125 @@ RSpec.describe Gitlab::Ci::Config::External::Rules, feature_category: :pipeline_
end
context 'with when: null' do
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: nil }] }
+ before do
+ rule_hashes.first[:when] = nil
+ end
- it_behaves_like 'when there is a rule with if'
+ it { is_expected.to eq(true) }
end
end
- context 'when there is a rule with exists and when' do
- context 'with when: never' do
- let(:rule_hashes) { [{ exists: 'Dockerfile', when: 'never' }] }
+ context 'when there is a rule with if:' do
+ let(:rule_hashes) { [{ if: '$MY_VAR == "hello"' }] }
- it_behaves_like 'when there is a rule with exists', false, false
- end
+ context 'when the rule matches' do
+ let(:context) { double(variables_hash: { 'MY_VAR' => 'hello' }) }
- context 'with when: always' do
- let(:rule_hashes) { [{ exists: 'Dockerfile', when: 'always' }] }
+ it { is_expected.to eq(true) }
- it_behaves_like 'when there is a rule with exists'
+ it_behaves_like 'with when: specified'
end
- context 'with when: <invalid string>' do
- let(:rule_hashes) { [{ exists: 'Dockerfile', when: 'on_success' }] }
+ context 'when the rule does not match' do
+ let(:context) { double(variables_hash: { 'MY_VAR' => 'invalid' }) }
- it 'raises an error' do
- expect { result }.to raise_error(described_class::InvalidIncludeRulesError, /when unknown value: on_success/)
- end
+ it { is_expected.to eq(false) }
end
+ end
- context 'with when: null' do
- let(:rule_hashes) { [{ exists: 'Dockerfile', when: nil }] }
+ context 'when there is a rule with exists:' do
+ let(:rule_hashes) { [{ exists: 'file.txt' }] }
- it_behaves_like 'when there is a rule with exists'
+ context 'when the file exists' do
+ let(:context) { double(top_level_worktree_paths: ['file.txt']) }
+
+ it { is_expected.to eq(true) }
+
+ it_behaves_like 'with when: specified'
end
- end
- context 'when there is a rule with changes' do
- let(:rule_hashes) { [{ changes: ['$MY_VAR'] }] }
+ context 'when the file does not exist' do
+ let(:context) { double(top_level_worktree_paths: ['README.md']) }
- it 'raises an error' do
- expect { result }.to raise_error(described_class::InvalidIncludeRulesError, /contains unknown keys: changes/)
+ it { is_expected.to eq(false) }
end
end
- context 'when FF `ci_refactor_external_rules` is disabled' do
- before do
- stub_feature_flags(ci_refactor_external_rules: false)
- end
+ context 'when there is a rule with changes:' do
+ let(:rule_hashes) { [{ changes: ['file.txt'] }] }
- context 'when there is no rule' do
- let(:rule_hashes) {}
+ shared_examples 'when the pipeline has modified paths' do
+ let(:modified_paths) { ['file.txt'] }
- it { is_expected.to eq(true) }
- end
+ before do
+ allow(pipeline).to receive(:modified_paths).and_return(modified_paths)
+ end
- it_behaves_like 'when there is a rule with if'
+ context 'when the file has changed' do
+ it { is_expected.to eq(true) }
- context 'when there is a rule with exists' do
- let(:rule_hashes) { [{ exists: 'Dockerfile' }] }
+ it_behaves_like 'with when: specified'
+ end
- it_behaves_like 'when there is a rule with exists'
+ context 'when the file has not changed' do
+ let(:modified_paths) { ['README.md'] }
+
+ it { is_expected.to eq(false) }
+ end
end
- context 'when there is a rule with if and when' do
- context 'with when: never' do
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: 'never' }] }
+ it_behaves_like 'when the pipeline has modified paths'
- it_behaves_like 'when there is a rule with if', false, false
- end
+ context 'with paths: specified' do
+ let(:rule_hashes) { [{ changes: { paths: ['file.txt'] } }] }
- context 'with when: always' do
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: 'always' }] }
+ it_behaves_like 'when the pipeline has modified paths'
+ end
- it_behaves_like 'when there is a rule with if'
- end
+ context 'with paths: and compare_to: specified' do
+ before_all do
+ project.repository.add_branch(project.owner, 'branch1', 'master')
- context 'with when: <invalid string>' do
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: 'on_success' }] }
+ project.repository.update_file(
+ project.owner, 'file.txt', 'file updated', message: 'Update file.txt', branch_name: 'branch1'
+ )
- it 'raises an error' do
- expect { result }.to raise_error(described_class::InvalidIncludeRulesError,
- 'invalid include rule: {:if=>"$MY_VAR == \"hello\"", :when=>"on_success"}')
- end
+ project.repository.add_branch(project.owner, 'branch2', 'branch1')
end
- context 'with when: null' do
- let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: nil }] }
-
- it_behaves_like 'when there is a rule with if'
+ let_it_be(:pipeline) do
+ build(:ci_pipeline, project: project, ref: 'branch2', sha: project.commit('branch2').sha)
end
- end
- context 'when there is a rule with exists and when' do
- context 'with when: never' do
- let(:rule_hashes) { [{ exists: 'Dockerfile', when: 'never' }] }
+ context 'when the file has changed compared to the given ref' do
+ let(:rule_hashes) { [{ changes: { paths: ['file.txt'], compare_to: 'master' } }] }
+
+ it { is_expected.to eq(true) }
- it_behaves_like 'when there is a rule with exists', false, false
+ it_behaves_like 'with when: specified'
end
- context 'with when: always' do
- let(:rule_hashes) { [{ exists: 'Dockerfile', when: 'always' }] }
+ context 'when the file has not changed compared to the given ref' do
+ let(:rule_hashes) { [{ changes: { paths: ['file.txt'], compare_to: 'branch1' } }] }
- it_behaves_like 'when there is a rule with exists'
+ it { is_expected.to eq(false) }
end
- context 'with when: <invalid string>' do
- let(:rule_hashes) { [{ exists: 'Dockerfile', when: 'on_success' }] }
+ context 'when compare_to: is invalid' do
+ let(:rule_hashes) { [{ changes: { paths: ['file.txt'], compare_to: 'invalid' } }] }
it 'raises an error' do
- expect { result }.to raise_error(described_class::InvalidIncludeRulesError,
- 'invalid include rule: {:exists=>"Dockerfile", :when=>"on_success"}')
+ expect { result }.to raise_error(described_class::InvalidIncludeRulesError, /compare_to is not a valid ref/)
end
end
-
- context 'with when: null' do
- let(:rule_hashes) { [{ exists: 'Dockerfile', when: nil }] }
-
- it_behaves_like 'when there is a rule with exists'
- end
end
+ end
- context 'when there is a rule with changes' do
- let(:rule_hashes) { [{ changes: ['$MY_VAR'] }] }
+ context 'when there is a rule with an invalid key' do
+ let(:rule_hashes) { [{ invalid: ['$MY_VAR'] }] }
- it 'raises an error' do
- expect { result }.to raise_error(described_class::InvalidIncludeRulesError,
- 'invalid include rule: {:changes=>["$MY_VAR"]}')
- end
+ it 'raises an error' do
+ expect { result }.to raise_error(described_class::InvalidIncludeRulesError, /contains unknown keys: invalid/)
end
end
end
diff --git a/spec/lib/gitlab/ci/config/interpolation/interpolator_spec.rb b/spec/lib/gitlab/ci/config/interpolation/interpolator_spec.rb
index 7bb09d35064..804164c933a 100644
--- a/spec/lib/gitlab/ci/config/interpolation/interpolator_spec.rb
+++ b/spec/lib/gitlab/ci/config/interpolation/interpolator_spec.rb
@@ -57,7 +57,8 @@ RSpec.describe Gitlab::Ci::Config::Interpolation::Interpolator, feature_category
expect(subject).not_to be_valid
expect(subject.error_message).to eq subject.errors.first
- expect(subject.errors).to include('unknown input arguments')
+ expect(subject.errors).to include('Given inputs not defined in the `spec` section of the included ' \
+ 'configuration file')
end
end
diff --git a/spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb b/spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb
index bf89942bf14..0af1b721eb6 100644
--- a/spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb
+++ b/spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Yaml::Tags::Reference do
+RSpec.describe Gitlab::Ci::Config::Yaml::Tags::Reference, feature_category: :pipeline_composition do
let(:config) do
- Gitlab::Ci::Config::Yaml.load!(yaml)
+ Gitlab::Ci::Config::Yaml::Loader.new(yaml).load.content
end
describe '.tag' do
diff --git a/spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb b/spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb
index 594242c33cc..74d7513ebdf 100644
--- a/spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb
+++ b/spec/lib/gitlab/ci/config/yaml/tags/resolver_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Config::Yaml::Tags::Resolver do
+RSpec.describe Gitlab::Ci::Config::Yaml::Tags::Resolver, feature_category: :pipeline_composition do
let(:config) do
- Gitlab::Ci::Config::Yaml.load!(yaml)
+ Gitlab::Ci::Config::Yaml::Loader.new(yaml).load.content
end
describe '#to_hash' do
diff --git a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
index d06537ac330..a331af9a9ac 100644
--- a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
@@ -3,18 +3,20 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependency_management do
- let(:report) { instance_double('Gitlab::Ci::Reports::Sbom::Report') }
+ let(:report) { Gitlab::Ci::Reports::Sbom::Report.new }
let(:report_data) { base_report_data }
let(:raw_report_data) { report_data.to_json }
let(:report_valid?) { true }
let(:validator_errors) { [] }
let(:properties_parser) { class_double('Gitlab::Ci::Parsers::Sbom::CyclonedxProperties') }
+ let(:uuid) { 'c9d550a3-feb8-483b-a901-5aa892d039f9' }
let(:base_report_data) do
{
'bomFormat' => 'CycloneDX',
'specVersion' => '1.4',
- 'version' => 1
+ 'version' => 1,
+ 'serialNumber' => "urn:uuid:#{uuid}"
}
end
@@ -28,6 +30,7 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen
allow(properties_parser).to receive(:parse_source)
stub_const('Gitlab::Ci::Parsers::Sbom::CyclonedxProperties', properties_parser)
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
end
context 'when report JSON is invalid' do
@@ -149,8 +152,22 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen
end
end
- context 'when report has metadata properties' do
- let(:report_data) { base_report_data.merge({ 'metadata' => { 'properties' => properties } }) }
+ context 'when report has metadata tools, author and properties' do
+ let(:report_data) { base_report_data.merge(metadata) }
+
+ let(:tools) do
+ [
+ { name: 'Gemnasium', vendor: 'vendor-1', version: '2.34.0' },
+ { name: 'Gemnasium', vendor: 'vendor-2', version: '2.34.0' }
+ ]
+ end
+
+ let(:authors) do
+ [
+ { name: 'author-1', email: 'support@gitlab.com' },
+ { name: 'author-2', email: 'support@gitlab.com' }
+ ]
+ end
let(:properties) do
[
@@ -163,10 +180,44 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx, feature_category: :dependen
]
end
- it 'passes them to the properties parser' do
- expect(properties_parser).to receive(:parse_source).with(properties)
+ context 'when metadata attributes are present' do
+ let(:metadata) do
+ {
+ 'metadata' => {
+ 'tools' => tools,
+ 'authors' => authors,
+ 'properties' => properties
+ }
+ }
+ end
- parse!
+ it 'passes them to the report' do
+ expect(properties_parser).to receive(:parse_source).with(properties)
+
+ parse!
+
+ expect(report.metadata).to have_attributes(
+ tools: tools.map(&:with_indifferent_access),
+ authors: authors.map(&:with_indifferent_access),
+ properties: properties.map(&:with_indifferent_access)
+ )
+ end
+ end
+
+ context 'when metadata attributes are not present' do
+ let(:metadata) { { 'metadata' => {} } }
+
+ it 'passes them to the report' do
+ expect(properties_parser).to receive(:parse_source).with(nil)
+
+ parse!
+
+ expect(report.metadata).to have_attributes(
+ tools: [],
+ authors: [],
+ properties: []
+ )
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/parsers/security/common_spec.rb b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
index dc16ddf4e0e..9470d59f502 100644
--- a/spec/lib/gitlab/ci/parsers/security/common_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
@@ -229,8 +229,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
describe 'parsing finding.details' do
context 'when details are provided' do
+ let(:finding) { report.findings[4] }
+
it 'sets details from the report' do
- finding = report.findings.find { |x| x.compare_key == 'CVE-1020' }
expected_details = Gitlab::Json.parse(finding.raw_metadata)['details']
expect(finding.details).to eq(expected_details)
@@ -238,8 +239,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
end
context 'when details are not provided' do
+ let(:finding) { report.findings[5] }
+
it 'sets empty hash' do
- finding = report.findings.find { |x| x.compare_key == 'CVE-1030' }
expect(finding.details).to eq({})
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 5f87e0ccc33..54e569f424b 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -1081,6 +1081,126 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build, feature_category: :pipeline_co
end
end
+ context 'with a rule using CI_ENVIRONMENT_ACTION variable' do
+ let(:rule_set) do
+ [{ if: '$CI_ENVIRONMENT_ACTION == "start"' }]
+ end
+
+ context 'when environment:action satisfies the rule' do
+ let(:attributes) do
+ { name: 'rspec', rules: rule_set, environment: 'test', when: 'on_success',
+ options: { environment: { action: 'start' } } }
+ end
+
+ it { is_expected.to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'on_success')
+ end
+ end
+
+ context 'when environment:action does not satisfy rule' do
+ let(:attributes) do
+ { name: 'rspec', rules: rule_set, environment: 'test', when: 'on_success',
+ options: { environment: { action: 'stop' } } }
+ end
+
+ it { is_expected.not_to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'never')
+ end
+ end
+
+ context 'when environment:action is not set' do
+ it { is_expected.not_to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'never')
+ end
+ end
+ end
+
+ context 'with a rule using CI_ENVIRONMENT_TIER variable' do
+ let(:rule_set) do
+ [{ if: '$CI_ENVIRONMENT_TIER == "production"' }]
+ end
+
+ context 'when environment:deployment_tier satisfies the rule' do
+ let(:attributes) do
+ { name: 'rspec', rules: rule_set, environment: 'test', when: 'on_success',
+ options: { environment: { deployment_tier: 'production' } } }
+ end
+
+ it { is_expected.to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'on_success')
+ end
+ end
+
+ context 'when environment:deployment_tier does not satisfy rule' do
+ let(:attributes) do
+ { name: 'rspec', rules: rule_set, environment: 'test', when: 'on_success',
+ options: { environment: { deployment_tier: 'development' } } }
+ end
+
+ it { is_expected.not_to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'never')
+ end
+ end
+
+ context 'when environment:action is not set' do
+ it { is_expected.not_to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'never')
+ end
+ end
+ end
+
+ context 'with a rule using CI_ENVIRONMENT_URL variable' do
+ let(:rule_set) do
+ [{ if: '$CI_ENVIRONMENT_URL == "http://gitlab.com"' }]
+ end
+
+ context 'when environment:url satisfies the rule' do
+ let(:attributes) do
+ { name: 'rspec', rules: rule_set, environment: 'test', when: 'on_success',
+ options: { environment: { url: 'http://gitlab.com' } } }
+ end
+
+ it { is_expected.to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'on_success')
+ end
+ end
+
+ context 'when environment:url does not satisfy rule' do
+ let(:attributes) do
+ { name: 'rspec', rules: rule_set, environment: 'test', when: 'on_success',
+ options: { environment: { url: 'http://staging.gitlab.com' } } }
+ end
+
+ it { is_expected.not_to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'never')
+ end
+ end
+
+ context 'when environment:action is not set' do
+ it { is_expected.not_to be_included }
+
+ it 'correctly populates when:' do
+ expect(seed_build.attributes).to include(when: 'never')
+ end
+ end
+ end
+
context 'with no rules' do
let(:rule_set) { [] }
diff --git a/spec/lib/gitlab/ci/reports/sbom/component_spec.rb b/spec/lib/gitlab/ci/reports/sbom/component_spec.rb
index d62d25aeefe..4c9fd00f96a 100644
--- a/spec/lib/gitlab/ci/reports/sbom/component_spec.rb
+++ b/spec/lib/gitlab/ci/reports/sbom/component_spec.rb
@@ -49,6 +49,18 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Component, feature_category: :dependen
end
end
+ describe '#purl_type' do
+ subject { component.purl_type }
+
+ it { is_expected.to eq(purl_type) }
+ end
+
+ describe '#type' do
+ subject { component.type }
+
+ it { is_expected.to eq(component_type) }
+ end
+
describe '#<=>' do
where do
{
diff --git a/spec/lib/gitlab/ci/reports/sbom/metadata_spec.rb b/spec/lib/gitlab/ci/reports/sbom/metadata_spec.rb
new file mode 100644
index 00000000000..fe0b9481039
--- /dev/null
+++ b/spec/lib/gitlab/ci/reports/sbom/metadata_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Reports::Sbom::Metadata, feature_category: :dependency_management do
+ let(:tools) do
+ [
+ {
+ vendor: "vendor",
+ name: "Gemnasium",
+ version: "2.34.0"
+ }
+ ]
+ end
+
+ let(:authors) do
+ [
+ {
+ name: "author_name",
+ email: "support@gitlab.com"
+ }
+ ]
+ end
+
+ let(:properties) do
+ [
+ {
+ name: "property_name",
+ value: "package-lock.json"
+ }
+ ]
+ end
+
+ let(:timestamp) { "2020-04-13T20:20:39+00:00" }
+
+ subject(:metadata) do
+ metadata = described_class.new(
+ tools: tools,
+ authors: authors,
+ properties: properties
+ )
+ metadata.timestamp = timestamp
+ metadata
+ end
+
+ it 'has correct attributes' do
+ expect(metadata).to have_attributes(
+ tools: tools,
+ authors: authors,
+ properties: properties,
+ timestamp: timestamp
+ )
+ end
+end
diff --git a/spec/lib/gitlab/ci/templates/MATLAB_spec.rb b/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
index 3889d1fc8c9..8b6ff7f27a2 100644
--- a/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
+++ b/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe 'MATLAB.gitlab-ci.yml' do
end
it 'creates all jobs' do
- expect(build_names).to include('command', 'test', 'test_artifacts')
+ expect(build_names).to include('command', 'test', 'test_artifacts', 'build')
end
end
end
diff --git a/spec/lib/gitlab/ci/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb
index d65b6fb41f6..9439d29aa11 100644
--- a/spec/lib/gitlab/ci/trace/stream_spec.rb
+++ b/spec/lib/gitlab/ci/trace/stream_spec.rb
@@ -243,6 +243,56 @@ RSpec.describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
expect(result.encoding).to eq(Encoding.default_external)
end
end
+
+ context 'limit max size' do
+ before do
+ # specifying BUFFER_SIZE forces to seek backwards
+ allow(described_class).to receive(:BUFFER_SIZE)
+ .and_return(2)
+ end
+
+ it 'returns every lines with respect of the size' do
+ all_lines = lines.join
+ max_size = all_lines.bytesize.div(2)
+ result = stream.raw(max_size: max_size)
+
+ expect(result.bytes).to eq(all_lines.bytes[-max_size..])
+ expect(result.lines.count).to be > 1
+ expect(result.encoding).to eq(Encoding.default_external)
+ end
+
+ it 'returns everything if trying to get too many bytes' do
+ all_lines = lines.join
+ result = stream.raw(max_size: all_lines.bytesize * 2)
+
+ expect(result).to eq(all_lines)
+ expect(result.encoding).to eq(Encoding.default_external)
+ end
+ end
+
+ context 'limit max lines and max size' do
+ before do
+ # specifying BUFFER_SIZE forces to seek backwards
+ allow(described_class).to receive(:BUFFER_SIZE)
+ .and_return(2)
+ end
+
+ it 'returns max lines if max size is greater' do
+ result = stream.raw(last_lines: 2, max_size: lines.join.bytesize * 2)
+
+ expect(result).to eq(lines.last(2).join)
+ expect(result.encoding).to eq(Encoding.default_external)
+ end
+
+ it 'returns max size if max lines is greater' do
+ all_lines = lines.join
+ max_size = all_lines.bytesize.div(2)
+ result = stream.raw(last_lines: lines.size * 2, max_size: max_size)
+
+ expect(result.bytes).to eq(all_lines.bytes[-max_size..])
+ expect(result.encoding).to eq(Encoding.default_external)
+ end
+ end
end
let(:path) { __FILE__ }
diff --git a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
index 0880c556523..860a1fd30bd 100644
--- a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
@@ -108,12 +108,17 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
'CI_MERGE_REQUEST_SOURCE_PROJECT_URL' => merge_request.source_project.web_url,
'CI_MERGE_REQUEST_SOURCE_BRANCH_NAME' => merge_request.source_branch.to_s,
'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA' => '',
+ 'CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED' => ProtectedBranch.protected?(
+ merge_request.source_project,
+ merge_request.source_branch
+ ).to_s,
'CI_MERGE_REQUEST_TITLE' => merge_request.title,
'CI_MERGE_REQUEST_ASSIGNEES' => merge_request.assignee_username_list,
'CI_MERGE_REQUEST_MILESTONE' => milestone.title,
'CI_MERGE_REQUEST_LABELS' => labels.map(&:title).sort.join(','),
'CI_MERGE_REQUEST_EVENT_TYPE' => 'detached',
- 'CI_OPEN_MERGE_REQUESTS' => merge_request.to_reference(full: true))
+ 'CI_OPEN_MERGE_REQUESTS' => merge_request.to_reference(full: true)),
+ 'CI_MERGE_REQUEST_SQUASH_ON_MERGE' => merge_request.squash_on_merge?.to_s
end
it 'exposes diff variables' do
diff --git a/spec/lib/gitlab/ci/variables/builder_spec.rb b/spec/lib/gitlab/ci/variables/builder_spec.rb
index 3411426fcdb..af745c75f42 100644
--- a/spec/lib/gitlab/ci/variables/builder_spec.rb
+++ b/spec/lib/gitlab/ci/variables/builder_spec.rb
@@ -10,18 +10,27 @@ RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, featur
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:job) do
create(:ci_build,
+ :with_deployment,
name: 'rspec:test 1',
pipeline: pipeline,
user: user,
yaml_variables: [{ key: 'YAML_VARIABLE', value: 'value' }],
- environment: 'test'
+ environment: 'review/$CI_COMMIT_REF_NAME',
+ options: {
+ environment: {
+ name: 'review/$CI_COMMIT_REF_NAME',
+ action: 'prepare',
+ deployment_tier: 'testing',
+ url: 'https://gitlab.com'
+ }
+ }
)
end
let(:builder) { described_class.new(pipeline) }
describe '#scoped_variables' do
- let(:environment) { job.expanded_environment_name }
+ let(:environment_name) { job.expanded_environment_name }
let(:dependencies) { true }
let(:predefined_variables) do
[
@@ -34,7 +43,13 @@ RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, featur
{ key: 'CI_NODE_TOTAL',
value: '1' },
{ key: 'CI_ENVIRONMENT_NAME',
- value: 'test' },
+ value: 'review/master' },
+ { key: 'CI_ENVIRONMENT_ACTION',
+ value: 'prepare' },
+ { key: 'CI_ENVIRONMENT_TIER',
+ value: 'testing' },
+ { key: 'CI_ENVIRONMENT_URL',
+ value: 'https://gitlab.com' },
{ key: 'CI',
value: 'true' },
{ key: 'GITLAB_CI',
@@ -150,7 +165,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, featur
].map { |var| var.merge(public: true, masked: false) }
end
- subject { builder.scoped_variables(job, environment: environment, dependencies: dependencies) }
+ subject { builder.scoped_variables(job, environment: environment_name, dependencies: dependencies) }
it { is_expected.to be_instance_of(Gitlab::Ci::Variables::Collection) }
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index f8f1d71e773..c09c0b31e97 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -794,6 +794,28 @@ module Gitlab
it_behaves_like 'returns errors', 'test_job_1 has the following needs duplicated: test_job_2.'
end
+
+ context 'when needed job name is too long' do
+ let(:job_name) { 'a' * (::Ci::BuildNeed::MAX_JOB_NAME_LENGTH + 1) }
+
+ let(:config) do
+ <<-EOYML
+ lint_job:
+ script: 'echo lint_job'
+ rules:
+ - if: $var == null
+ needs: [#{job_name}]
+ #{job_name}:
+ script: 'echo job'
+ EOYML
+ end
+
+ it 'returns an error' do
+ expect(subject.errors).to include(
+ "lint_job job: need `#{job_name}` name is too long (maximum is #{::Ci::BuildNeed::MAX_JOB_NAME_LENGTH} characters)"
+ )
+ end
+ end
end
context 'rule needs as hash' do
@@ -2020,6 +2042,52 @@ module Gitlab
end
end
+ describe 'id_tokens' do
+ subject(:execute) { described_class.new(config).execute }
+
+ let(:build) { execute.builds.first }
+ let(:id_tokens_vars) { { ID_TOKEN_1: { aud: 'http://gcp.com' } } }
+ let(:job_id_tokens_vars) { { ID_TOKEN_2: { aud: 'http://job.com' } } }
+
+ context 'when defined on job level' do
+ let(:config) do
+ YAML.dump({
+ rspec: { script: 'rspec', id_tokens: id_tokens_vars }
+ })
+ end
+
+ it 'returns defined id_tokens' do
+ expect(build[:id_tokens]).to eq(id_tokens_vars)
+ end
+ end
+
+ context 'when defined as default' do
+ let(:config) do
+ YAML.dump({
+ default: { id_tokens: id_tokens_vars },
+ rspec: { script: 'rspec' }
+ })
+ end
+
+ it 'returns inherited by default id_tokens' do
+ expect(build[:id_tokens]).to eq(id_tokens_vars)
+ end
+ end
+
+ context 'when defined as default and on job level' do
+ let(:config) do
+ YAML.dump({
+ default: { id_tokens: id_tokens_vars },
+ rspec: { script: 'rspec', id_tokens: job_id_tokens_vars }
+ })
+ end
+
+ it 'overrides default and returns defined on job level' do
+ expect(build[:id_tokens]).to eq(job_id_tokens_vars)
+ end
+ end
+ end
+
describe "Artifacts" do
it "returns artifacts when defined" do
config = YAML.dump(
@@ -2553,6 +2621,60 @@ module Gitlab
scheduling_type: :dag
)
end
+
+ context 'when expanded job name is too long' do
+ let(:parallel_job_name) { 'a' * ::Ci::BuildNeed::MAX_JOB_NAME_LENGTH }
+ let(:needs) { [parallel_job_name] }
+
+ before do
+ config[parallel_job_name] = { stage: 'build', script: 'test', parallel: 1 }
+ end
+
+ it 'returns an error' do
+ expect(subject.errors).to include(
+ "test1 job: need `#{parallel_job_name} 1/1` name is too long (maximum is #{::Ci::BuildNeed::MAX_JOB_NAME_LENGTH} characters)"
+ )
+ end
+ end
+
+ context 'when parallel job has matrix specified' do
+ let(:var1) { '1' }
+ let(:var2) { '2' }
+
+ before do
+ config[:parallel] = { stage: 'build', script: 'test', parallel: { matrix: [{ VAR1: var1, VAR2: var2 }] } }
+ end
+
+ it 'does create jobs with valid specification' do
+ expect(subject.builds.size).to eq(6)
+ expect(subject.builds[3]).to eq(
+ stage: 'test',
+ stage_idx: 2,
+ name: 'test1',
+ only: { refs: %w[branches tags] },
+ options: { script: ['test'] },
+ needs_attributes: [
+ { name: 'parallel: [1, 2]', artifacts: true, optional: false }
+ ],
+ when: "on_success",
+ allow_failure: false,
+ job_variables: [],
+ root_variables_inheritance: true,
+ scheduling_type: :dag
+ )
+ end
+
+ context 'when expanded job name is too long' do
+ let(:var1) { '1' * (::Ci::BuildNeed::MAX_JOB_NAME_LENGTH / 2) }
+ let(:var2) { '2' * (::Ci::BuildNeed::MAX_JOB_NAME_LENGTH / 2) }
+
+ it 'returns an error' do
+ expect(subject.errors).to include(
+ "test1 job: need `parallel: [#{var1}, #{var2}]` name is too long (maximum is #{::Ci::BuildNeed::MAX_JOB_NAME_LENGTH} characters)"
+ )
+ end
+ end
+ end
end
context 'needs dependencies artifacts' do
diff --git a/spec/lib/gitlab/composer/version_index_spec.rb b/spec/lib/gitlab/composer/version_index_spec.rb
index a4d016636aa..63efa8cae95 100644
--- a/spec/lib/gitlab/composer/version_index_spec.rb
+++ b/spec/lib/gitlab/composer/version_index_spec.rb
@@ -2,52 +2,111 @@
require 'spec_helper'
-RSpec.describe Gitlab::Composer::VersionIndex do
+RSpec.describe Gitlab::Composer::VersionIndex, feature_category: :package_registry do
let_it_be(:package_name) { 'sample-project' }
let_it_be(:json) { { 'name' => package_name } }
let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, :custom_repo, files: { 'composer.json' => json.to_json }, group: group) }
+ let_it_be(:files) { { 'composer.json' => json.to_json } }
+ let_it_be_with_reload(:project) { create(:project, :public, :custom_repo, files: files, group: group) }
let_it_be(:package1) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '1.0.0', json: json) }
let_it_be(:package2) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '2.0.0', json: json) }
+ let(:url) { "http://localhost/#{group.path}/#{project.path}.git" }
let(:branch) { project.repository.find_branch('master') }
-
let(:packages) { [package1, package2] }
describe '#as_json' do
+ let(:index) { described_class.new(packages).as_json }
+ let(:ssh_path_prefix) { 'username@localhost:' }
+
subject(:package_index) { index['packages'][package_name] }
- let(:index) { described_class.new(packages).as_json }
+ before do
+ allow(Gitlab.config.gitlab_shell).to receive(:ssh_path_prefix)
+ .and_return(ssh_path_prefix)
+ end
+
+ shared_examples 'returns the packages json' do
+ def expected_json(package)
+ {
+ 'dist' => {
+ 'reference' => branch.target,
+ 'shasum' => '',
+ 'type' => 'zip',
+ 'url' => "http://localhost/api/v4/projects/#{project.id}/packages/composer/archives/#{package.name}.zip?sha=#{branch.target}"
+ },
+ 'source' => {
+ 'reference' => branch.target,
+ 'type' => 'git',
+ 'url' => url
+ },
+ 'name' => package.name,
+ 'uid' => package.id,
+ 'version' => package.version
+ }
+ end
+
+ it 'returns the packages json' do
+ expect(package_index['1.0.0']).to eq(expected_json(package1))
+ expect(package_index['2.0.0']).to eq(expected_json(package2))
+ end
+
+ context 'with an unordered list of packages' do
+ let(:packages) { [package2, package1] }
+
+ it 'returns the packages sorted by version' do
+ expect(package_index.keys).to eq ['1.0.0', '2.0.0']
+ end
+ end
+ end
+
+ context 'with a public project' do
+ it_behaves_like 'returns the packages json'
+ end
+
+ context 'with an internal project' do
+ let(:url) { "#{ssh_path_prefix}#{group.path}/#{project.path}.git" }
+
+ before do
+ project.update!(visibility: Gitlab::VisibilityLevel::INTERNAL)
+ end
- def expected_json(package)
- {
- 'dist' => {
- 'reference' => branch.target,
- 'shasum' => '',
- 'type' => 'zip',
- 'url' => "http://localhost/api/v4/projects/#{project.id}/packages/composer/archives/#{package.name}.zip?sha=#{branch.target}"
- },
- 'source' => {
- 'reference' => branch.target,
- 'type' => 'git',
- 'url' => project.http_url_to_repo
- },
- 'name' => package.name,
- 'uid' => package.id,
- 'version' => package.version
- }
+ it_behaves_like 'returns the packages json'
end
- it 'returns the packages json' do
- expect(package_index['1.0.0']).to eq(expected_json(package1))
- expect(package_index['2.0.0']).to eq(expected_json(package2))
+ context 'with a private project' do
+ let(:url) { "#{ssh_path_prefix}#{group.path}/#{project.path}.git" }
+
+ before do
+ project.update!(visibility: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it_behaves_like 'returns the packages json'
end
- context 'with an unordered list of packages' do
- let(:packages) { [package2, package1] }
+ context 'with composer_use_ssh_source_urls disabled' do
+ before do
+ stub_feature_flags(composer_use_ssh_source_urls: false)
+ end
+
+ context 'with a public project' do
+ it_behaves_like 'returns the packages json'
+ end
+
+ context 'with an internal project' do
+ before do
+ project.update!(visibility: Gitlab::VisibilityLevel::INTERNAL)
+ end
+
+ it_behaves_like 'returns the packages json'
+ end
+
+ context 'with a private project' do
+ before do
+ project.update!(visibility: Gitlab::VisibilityLevel::PRIVATE)
+ end
- it 'returns the packages sorted by version' do
- expect(package_index.keys).to eq ['1.0.0', '2.0.0']
+ it_behaves_like 'returns the packages json'
end
end
end
diff --git a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
index 6d24ced138e..3682a654181 100644
--- a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
+++ b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
@@ -80,6 +80,10 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader, feature_category: :s
let(:style_src) { directives['style_src'] }
let(:worker_src) { directives['worker_src'] }
+ before do
+ stub_env('GITLAB_ANALYTICS_URL', nil)
+ end
+
it 'returns default directives' do
directive_names = (described_class::DIRECTIVES - ['report_uri'])
directive_names.each do |directive|
@@ -542,6 +546,58 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader, feature_category: :s
end
end
end
+
+ describe 'browsersdk_tracking' do
+ let(:analytics_url) { 'https://analytics.gitlab.com' }
+ let(:is_gitlab_com) { true }
+
+ before do
+ allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
+ end
+
+ context 'when browsersdk_tracking is enabled, GITLAB_ANALYTICS_URL is set, and Gitlab.com? is true' do
+ before do
+ stub_env('GITLAB_ANALYTICS_URL', analytics_url)
+ end
+
+ it 'adds GITLAB_ANALYTICS_URL to connect-src' do
+ expect(connect_src).to include(analytics_url)
+ end
+ end
+
+ context 'when Gitlab.com? is false' do
+ let(:is_gitlab_com) { false }
+
+ before do
+ stub_env('GITLAB_ANALYTICS_URL', analytics_url)
+ end
+
+ it 'does not add GITLAB_ANALYTICS_URL to connect-src' do
+ expect(connect_src).not_to include(analytics_url)
+ end
+ end
+
+ context 'when browsersdk_tracking is disabled' do
+ before do
+ stub_feature_flags(browsersdk_tracking: false)
+ stub_env('GITLAB_ANALYTICS_URL', analytics_url)
+ end
+
+ it 'does not add GITLAB_ANALYTICS_URL to connect-src' do
+ expect(connect_src).not_to include(analytics_url)
+ end
+ end
+
+ context 'when GITLAB_ANALYTICS_URL is not set' do
+ before do
+ stub_env('GITLAB_ANALYTICS_URL', nil)
+ end
+
+ it 'does not add GITLAB_ANALYTICS_URL to connect-src' do
+ expect(connect_src).not_to include(analytics_url)
+ end
+ end
+ end
end
describe '#load' do
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index 0e93a85764f..df1b12e479f 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -2,15 +2,14 @@
require 'spec_helper'
-RSpec.describe Gitlab::CurrentSettings do
+RSpec.describe Gitlab::CurrentSettings, feature_category: :shared do
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end
shared_context 'with settings in cache' do
before do
- create(:application_setting)
- described_class.current_application_settings # warm the cache
+ 2.times { described_class.current_application_settings } # warm the cache
end
end
@@ -29,7 +28,7 @@ RSpec.describe Gitlab::CurrentSettings do
context 'when there are allowed domains' do
before do
- create(:application_setting, domain_allowlist: ['www.gitlab.com'])
+ stub_application_setting(domain_allowlist: ['www.gitlab.com'])
end
it { is_expected.to be_truthy }
@@ -37,7 +36,7 @@ RSpec.describe Gitlab::CurrentSettings do
context 'when there are email restrictions' do
before do
- create(:application_setting, email_restrictions_enabled: true)
+ stub_application_setting(email_restrictions_enabled: true)
end
it { is_expected.to be_truthy }
@@ -45,7 +44,7 @@ RSpec.describe Gitlab::CurrentSettings do
context 'when the admin has to approve signups' do
before do
- create(:application_setting, require_admin_approval_after_user_signup: true)
+ stub_application_setting(require_admin_approval_after_user_signup: true)
end
it { is_expected.to be_truthy }
@@ -53,7 +52,7 @@ RSpec.describe Gitlab::CurrentSettings do
context 'when new users are set to external' do
before do
- create(:application_setting, user_default_external: true)
+ stub_application_setting(user_default_external: true)
end
it { is_expected.to be_truthy }
@@ -61,7 +60,7 @@ RSpec.describe Gitlab::CurrentSettings do
context 'when there are no restrictions' do
before do
- create(:application_setting, domain_allowlist: [], email_restrictions_enabled: false, require_admin_approval_after_user_signup: false, user_default_external: false)
+ stub_application_setting(domain_allowlist: [], email_restrictions_enabled: false, require_admin_approval_after_user_signup: false, user_default_external: false)
end
it { is_expected.to be_falsey }
@@ -73,7 +72,7 @@ RSpec.describe Gitlab::CurrentSettings do
context 'when signup is enabled' do
before do
- create(:application_setting, signup_enabled: true)
+ stub_application_setting(signup_enabled: true)
end
it { is_expected.to be_falsey }
@@ -81,7 +80,7 @@ RSpec.describe Gitlab::CurrentSettings do
context 'when signup is disabled' do
before do
- create(:application_setting, signup_enabled: false)
+ stub_application_setting(signup_enabled: false)
end
it { is_expected.to be_truthy }
@@ -90,11 +89,9 @@ RSpec.describe Gitlab::CurrentSettings do
describe '#current_application_settings', :use_clean_rails_memory_store_caching do
it 'allows keys to be called directly' do
- db_settings = create(:application_setting,
- home_page_url: 'http://mydomain.com',
- signup_enabled: false)
+ described_class.update!(home_page_url: 'http://mydomain.com', signup_enabled: false)
- expect(described_class.home_page_url).to eq(db_settings.home_page_url)
+ expect(described_class.home_page_url).to eq('http://mydomain.com')
expect(described_class.signup_enabled?).to be_falsey
expect(described_class.signup_enabled).to be_falsey
expect(described_class.metrics_sample_interval).to be(15)
@@ -253,12 +250,14 @@ RSpec.describe Gitlab::CurrentSettings do
end
context 'with an existing ApplicationSetting DB record' do
- let!(:db_settings) { ApplicationSetting.build_from_defaults(home_page_url: 'http://mydomain.com').save! && ApplicationSetting.last }
+ before do
+ described_class.update!(home_page_url: 'http://mydomain.com')
+ end
it_behaves_like 'a non-persisted ApplicationSetting object'
it 'uses the value from the DB attribute if present and not overridden by an accessor' do
- expect(current_settings.home_page_url).to eq(db_settings.home_page_url)
+ expect(current_settings.home_page_url).to eq('http://mydomain.com')
end
end
end
@@ -277,10 +276,11 @@ RSpec.describe Gitlab::CurrentSettings do
describe '#current_application_settings?', :use_clean_rails_memory_store_caching do
before do
allow(described_class).to receive(:current_application_settings?).and_call_original
+ ApplicationSetting.delete_all # ensure no settings exist
end
it 'returns true when settings exist' do
- create(:application_setting,
+ described_class.update!(
home_page_url: 'http://mydomain.com',
signup_enabled: false)
diff --git a/spec/lib/gitlab/data_builder/deployment_spec.rb b/spec/lib/gitlab/data_builder/deployment_spec.rb
index bbcfa1973ea..bf97f40e97f 100644
--- a/spec/lib/gitlab/data_builder/deployment_spec.rb
+++ b/spec/lib/gitlab/data_builder/deployment_spec.rb
@@ -50,6 +50,15 @@ RSpec.describe Gitlab::DataBuilder::Deployment, feature_category: :continuous_de
expect(data[:deployable_url]).to be_nil
end
+ it 'does not include the deployable URL when deployable is bridge' do
+ project = create(:project, :repository)
+ bridge = create(:ci_bridge, project: project)
+ deployment = create(:deployment, status: :failed, project: project, deployable: bridge)
+ data = described_class.build(deployment, 'failed', Time.current)
+
+ expect(data[:deployable_url]).to be_nil
+ end
+
context 'when commit does not exist in the repository' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:deployment) { create(:deployment, project: project) }
diff --git a/spec/lib/gitlab/database/async_indexes/migration_helpers_spec.rb b/spec/lib/gitlab/database/async_indexes/migration_helpers_spec.rb
index 309bbf1e3f0..c5a20b5ef3d 100644
--- a/spec/lib/gitlab/database/async_indexes/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/async_indexes/migration_helpers_spec.rb
@@ -141,6 +141,14 @@ RSpec.describe Gitlab::Database::AsyncIndexes::MigrationHelpers, feature_categor
expect { migration.prepare_async_index(table_name, 'id') }.not_to raise_error
end
end
+
+ context 'when the target table does not exist' do
+ it 'raises an error' do
+ expect { migration.prepare_async_index(:non_existent_table, 'id') }.to(
+ raise_error("Table non_existent_table does not exist")
+ )
+ end
+ end
end
describe '#prepare_async_index_from_sql' do
diff --git a/spec/lib/gitlab/database/click_house_client_spec.rb b/spec/lib/gitlab/database/click_house_client_spec.rb
index 50086795b2b..6e63ae56557 100644
--- a/spec/lib/gitlab/database/click_house_client_spec.rb
+++ b/spec/lib/gitlab/database/click_house_client_spec.rb
@@ -2,98 +2,135 @@
require 'spec_helper'
-RSpec.describe 'ClickHouse::Client', feature_category: :database do
- context 'when click_house spec tag is not added' do
- it 'does not have any ClickHouse databases configured' do
- databases = ClickHouse::Client.configuration.databases
+RSpec.describe 'ClickHouse::Client', :click_house, feature_category: :database do
+ it 'has a ClickHouse database configured' do
+ databases = ClickHouse::Client.configuration.databases
- expect(databases).to be_empty
- end
+ expect(databases).not_to be_empty
end
- describe 'when click_house spec tag is added', :click_house do
- it 'has a ClickHouse database configured' do
- databases = ClickHouse::Client.configuration.databases
-
- expect(databases).not_to be_empty
- end
+ it 'does not return data via `execute` method' do
+ result = ClickHouse::Client.execute("SELECT 1 AS value", :main)
- it 'does not return data via `execute` method' do
- result = ClickHouse::Client.execute("SELECT 1 AS value", :main)
+ # does not return data, just true if successful. Otherwise error.
+ expect(result).to eq(true)
+ end
- # does not return data, just true if successful. Otherwise error.
- expect(result).to eq(true)
- end
+ describe 'data manipulation' do
+ describe 'inserting' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project) }
+
+ let_it_be(:author1) { create(:user).tap { |u| project.add_developer(u) } }
+ let_it_be(:author2) { create(:user).tap { |u| project.add_developer(u) } }
+
+ let_it_be(:issue1) { create(:issue, project: project) }
+ let_it_be(:issue2) { create(:issue, project: project) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+
+ let_it_be(:event1) { create(:event, :created, target: issue1, author: author1) }
+ let_it_be(:event2) { create(:event, :closed, target: issue2, author: author2) }
+ let_it_be(:event3) { create(:event, :merged, target: merge_request, author: author1) }
+
+ let(:events) { [event1, event2, event3] }
+
+ def format_row(event)
+ path = event.project.reload.project_namespace.traversal_ids.join('/')
+
+ action = Event.actions[event.action]
+ [
+ event.id,
+ "'#{path}/'",
+ event.author_id,
+ event.target_id,
+ "'#{event.target_type}'",
+ action,
+ event.created_at.to_f,
+ event.updated_at.to_f
+ ].join(',')
+ end
- describe 'data manipulation' do
- describe 'inserting' do
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project) }
-
- let_it_be(:author1) { create(:user).tap { |u| project.add_developer(u) } }
- let_it_be(:author2) { create(:user).tap { |u| project.add_developer(u) } }
-
- let_it_be(:issue1) { create(:issue, project: project) }
- let_it_be(:issue2) { create(:issue, project: project) }
- let_it_be(:merge_request) { create(:merge_request, source_project: project) }
-
- let_it_be(:event1) { create(:event, :created, target: issue1, author: author1) }
- let_it_be(:event2) { create(:event, :closed, target: issue2, author: author2) }
- let_it_be(:event3) { create(:event, :merged, target: merge_request, author: author1) }
-
- let(:events) { [event1, event2, event3] }
-
- def format_row(event)
- path = event.project.reload.project_namespace.traversal_ids.join('/')
-
- action = Event.actions[event.action]
- [
- event.id,
- "'#{path}/'",
- event.author_id,
- event.target_id,
- "'#{event.target_type}'",
- action,
- event.created_at.to_f,
- event.updated_at.to_f
- ].join(',')
+ describe 'RSpec hooks' do
+ it 'ensures that tables are empty' do
+ results = ClickHouse::Client.select('SELECT * FROM events', :main)
+ expect(results).to be_empty
end
- describe 'RSpec hooks' do
- it 'ensures that tables are empty' do
- results = ClickHouse::Client.select('SELECT * FROM events', :main)
- expect(results).to be_empty
+ it 'inserts data from CSV' do
+ time = Time.current.utc
+ Tempfile.open(['test', '.csv.gz']) do |f|
+ csv = "id,path,created_at\n10,1/2/,#{time.to_f}\n20,1/,#{time.to_f}"
+ File.binwrite(f.path, ActiveSupport::Gzip.compress(csv))
+
+ ClickHouse::Client.insert_csv('INSERT INTO events (id, path, created_at) FORMAT CSV', File.open(f.path),
+ :main)
end
- end
- it 'inserts and modifies data' do
- insert_query = <<~SQL
- INSERT INTO events
- (id, path, author_id, target_id, target_type, action, created_at, updated_at)
- VALUES
- (#{format_row(event1)}),
- (#{format_row(event2)}),
- (#{format_row(event3)})
- SQL
+ results = ClickHouse::Client.select('SELECT id, path, created_at FROM events ORDER BY id', :main)
- ClickHouse::Client.execute(insert_query, :main)
+ expect(results).to match([
+ { 'id' => 10, 'path' => '1/2/', 'created_at' => be_within(0.1.seconds).of(time) },
+ { 'id' => 20, 'path' => '1/', 'created_at' => be_within(0.1.seconds).of(time) }
+ ])
+ end
+ end
- results = ClickHouse::Client.select('SELECT * FROM events ORDER BY id', :main)
- expect(results.size).to eq(3)
+ it 'inserts and modifies data' do
+ insert_query = <<~SQL
+ INSERT INTO events
+ (id, path, author_id, target_id, target_type, action, created_at, updated_at)
+ VALUES
+ (#{format_row(event1)}),
+ (#{format_row(event2)}),
+ (#{format_row(event3)})
+ SQL
+
+ ClickHouse::Client.execute(insert_query, :main)
+
+ results = ClickHouse::Client.select('SELECT * FROM events ORDER BY id', :main)
+ expect(results.size).to eq(3)
+
+ last = results.last
+ expect(last).to match(a_hash_including(
+ 'id' => event3.id,
+ 'author_id' => event3.author_id,
+ 'created_at' => be_within(0.05).of(event3.created_at),
+ 'target_type' => event3.target_type
+ ))
+
+ delete_query = ClickHouse::Client::Query.new(
+ raw_query: 'DELETE FROM events WHERE id = {id:UInt64}',
+ placeholders: { id: event3.id }
+ )
+
+ ClickHouse::Client.execute(delete_query, :main)
+
+ select_query = ClickHouse::Client::Query.new(
+ raw_query: 'SELECT * FROM events WHERE id = {id:UInt64}',
+ placeholders: { id: event3.id }
+ )
+
+ results = ClickHouse::Client.select(select_query, :main)
+ expect(results).to be_empty
+ end
+ end
+ end
- last = results.last
- expect(last).to match(a_hash_including(
- 'id' => event3.id,
- 'author_id' => event3.author_id,
- 'created_at' => be_within(0.05).of(event3.created_at),
- 'target_type' => event3.target_type
- ))
+ describe 'logging' do
+ let(:query_string) { "SELECT * FROM events WHERE id IN (4, 5, 6)" }
- ClickHouse::Client.execute("DELETE FROM events WHERE id = #{event3.id}", :main)
+ context 'on dev and test environments' do
+ it 'logs the un-redacted query' do
+ expect(ClickHouse::Client.configuration.logger).to receive(:info).with({
+ query: query_string,
+ correlation_id: a_kind_of(String)
+ })
- results = ClickHouse::Client.select("SELECT * FROM events WHERE id = #{event3.id}", :main)
- expect(results).to be_empty
- end
+ ClickHouse::Client.select(query_string, :main)
+ end
+
+ it 'has a ClickHouse logger' do
+ expect(ClickHouse::Client.configuration.logger).to be_a(ClickHouse::Logger)
end
end
end
diff --git a/spec/lib/gitlab/database/gitlab_schema_spec.rb b/spec/lib/gitlab/database/gitlab_schema_spec.rb
index 14ff1a462e3..e402014df90 100644
--- a/spec/lib/gitlab/database/gitlab_schema_spec.rb
+++ b/spec/lib/gitlab/database/gitlab_schema_spec.rb
@@ -148,7 +148,7 @@ RSpec.describe Gitlab::Database::GitlabSchema, feature_category: :database do
subject { described_class.table_schemas!(tables) }
it 'returns the matched schemas' do
- expect(subject).to match_array %i[gitlab_main_cell gitlab_main gitlab_ci].to_set
+ expect(subject).to match_array %i[gitlab_main_cell gitlab_ci].to_set
end
context 'when one of the tables does not have a matching table schema' do
diff --git a/spec/lib/gitlab/database/load_balancing/host_spec.rb b/spec/lib/gitlab/database/load_balancing/host_spec.rb
index 5ef6d9173c4..89cecaff075 100644
--- a/spec/lib/gitlab/database/load_balancing/host_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/host_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::LoadBalancing::Host do
+RSpec.describe Gitlab::Database::LoadBalancing::Host, feature_category: :database do
let(:load_balancer) do
Gitlab::Database::LoadBalancing::LoadBalancer
.new(Gitlab::Database::LoadBalancing::Configuration.new(ActiveRecord::Base))
@@ -124,13 +124,36 @@ RSpec.describe Gitlab::Database::LoadBalancing::Host do
end
it 'refreshes the status' do
- expect(Gitlab::Database::LoadBalancing::Logger).to receive(:info)
- .with(hash_including(event: :host_online))
- .and_call_original
-
expect(host).to be_online
end
+ context 'and the host was previously online' do
+ # Hosts are online by default
+
+ it 'does not log the online event' do
+ expect(Gitlab::Database::LoadBalancing::Logger)
+ .not_to receive(:info)
+ .with(hash_including(event: :host_online))
+
+ expect(host).to be_online
+ end
+ end
+
+ context 'and the host was previously offline' do
+ before do
+ host.offline!
+ end
+
+ it 'logs the online event' do
+ expect(Gitlab::Database::LoadBalancing::Logger)
+ .to receive(:info)
+ .with(hash_including(event: :host_online))
+ .and_call_original
+
+ expect(host).to be_online
+ end
+ end
+
context 'and replica is not up to date' do
before do
expect(host).to receive(:replica_is_up_to_date?).and_return(false)
diff --git a/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb b/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
index 26c8969efd8..c975f5b5ee4 100644
--- a/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
@@ -469,25 +469,58 @@ RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store, fe
context 'when none of the replicas are caught up' do
before do
- expect(hosts).to all(receive(:caught_up?).with(location).and_return(false))
+ expect(hosts[0]).to receive(:caught_up?).with(location).and_return(false)
+ expect(hosts[1]).to receive(:caught_up?).with(location).and_return(false)
end
- it 'returns false and does not update the host thread-local variable' do
- expect(subject).to be false
+ it 'returns NONE_CAUGHT_UP and does not update the host thread-local variable' do
+ expect(subject).to eq(described_class::NONE_CAUGHT_UP)
expect(set_host).to be_nil
end
+
+ it 'notifies caught_up_replica_pick.load_balancing with result false' do
+ expect(ActiveSupport::Notifications).to receive(:instrument)
+ .with('caught_up_replica_pick.load_balancing', { result: false })
+
+ subject
+ end
end
- context 'when any of the replicas is caught up' do
+ context 'when any replica is caught up' do
before do
- # `allow` for non-caught up host, because we may not even check it, if will find the caught up one earlier
- allow(hosts[0]).to receive(:caught_up?).with(location).and_return(false)
+ expect(hosts[0]).to receive(:caught_up?).with(location).and_return(true)
+ expect(hosts[1]).to receive(:caught_up?).with(location).and_return(false)
+ end
+
+ it 'returns ANY_CAUGHT_UP and sets host thread-local variable' do
+ expect(subject).to eq(described_class::ANY_CAUGHT_UP)
+ expect(set_host).to eq(hosts[0])
+ end
+
+ it 'notifies caught_up_replica_pick.load_balancing with result true' do
+ expect(ActiveSupport::Notifications).to receive(:instrument)
+ .with('caught_up_replica_pick.load_balancing', { result: true })
+
+ subject
+ end
+ end
+
+ context 'when all of the replicas is caught up' do
+ before do
+ expect(hosts[0]).to receive(:caught_up?).with(location).and_return(true)
expect(hosts[1]).to receive(:caught_up?).with(location).and_return(true)
end
- it 'returns true and sets host thread-local variable' do
- expect(subject).to be true
- expect(set_host).to eq(hosts[1])
+ it 'returns ALL_CAUGHT_UP and sets host thread-local variable' do
+ expect(subject).to eq(described_class::ALL_CAUGHT_UP)
+ expect(set_host).to be_in([hosts[0], hosts[1]])
+ end
+
+ it 'notifies caught_up_replica_pick.load_balancing with result true' do
+ expect(ActiveSupport::Notifications).to receive(:instrument)
+ .with('caught_up_replica_pick.load_balancing', { result: true })
+
+ subject
end
end
end
diff --git a/spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb b/spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb
index 713bff5feea..863b1fb099b 100644
--- a/spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/rack_middleware_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
let(:app) { double(:app) }
let(:middleware) { described_class.new(app) }
let(:warden_user) { double(:warden, user: double(:user, id: 42)) }
- let(:single_sticking_object) { Set.new([[ActiveRecord::Base.sticking, :user, 42]]) }
+ let(:single_sticking_object) { Set.new([[ActiveRecord::Base.sticking, :user, 99]]) }
let(:multiple_sticking_objects) do
Set.new([
[ActiveRecord::Base.sticking, :user, 42],
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
expect(middleware).to receive(:clear).twice
- expect(middleware).to receive(:unstick_or_continue_sticking).with(env)
+ expect(middleware).to receive(:find_caught_up_replica).with(env)
expect(middleware).to receive(:stick_if_necessary).with(env)
expect(app).to receive(:call).with(env).and_return(10)
@@ -41,12 +41,12 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
end
end
- describe '#unstick_or_continue_sticking' do
+ describe '#find_caught_up_replica' do
it 'does not stick if no namespace and identifier could be found' do
expect(ApplicationRecord.sticking)
- .not_to receive(:unstick_or_continue_sticking)
+ .not_to receive(:find_caught_up_replica)
- middleware.unstick_or_continue_sticking({})
+ middleware.find_caught_up_replica({})
end
it 'sticks to the primary if a warden user is found' do
@@ -54,94 +54,125 @@ RSpec.describe Gitlab::Database::LoadBalancing::RackMiddleware, :redis do
Gitlab::Database::LoadBalancing.base_models.each do |model|
expect(model.sticking)
- .to receive(:unstick_or_continue_sticking)
+ .to receive(:find_caught_up_replica)
.with(:user, 42)
end
- middleware.unstick_or_continue_sticking(env)
+ middleware.find_caught_up_replica(env)
end
it 'sticks to the primary if a sticking namespace and identifier is found' do
env = { described_class::STICK_OBJECT => single_sticking_object }
expect(ApplicationRecord.sticking)
- .to receive(:unstick_or_continue_sticking)
- .with(:user, 42)
+ .to receive(:find_caught_up_replica)
+ .with(:user, 99)
- middleware.unstick_or_continue_sticking(env)
+ middleware.find_caught_up_replica(env)
end
it 'sticks to the primary if multiple sticking namespaces and identifiers were found' do
env = { described_class::STICK_OBJECT => multiple_sticking_objects }
expect(ApplicationRecord.sticking)
- .to receive(:unstick_or_continue_sticking)
+ .to receive(:find_caught_up_replica)
.with(:user, 42)
.ordered
expect(ApplicationRecord.sticking)
- .to receive(:unstick_or_continue_sticking)
+ .to receive(:find_caught_up_replica)
.with(:runner, '123456789')
.ordered
expect(ApplicationRecord.sticking)
- .to receive(:unstick_or_continue_sticking)
+ .to receive(:find_caught_up_replica)
.with(:runner, '1234')
.ordered
- middleware.unstick_or_continue_sticking(env)
+ middleware.find_caught_up_replica(env)
end
end
describe '#stick_if_necessary' do
- it 'does not stick to the primary if not necessary' do
- expect(ApplicationRecord.sticking)
- .not_to receive(:stick_if_necessary)
-
- middleware.stick_if_necessary({})
+ let(:env) { { 'warden' => warden, described_class::STICK_OBJECT => stick_object }.compact }
+ let(:stick_object) { nil }
+ let(:write_performed) { true }
+ let(:warden) { warden_user }
+
+ before do
+ allow(::Gitlab::Database::LoadBalancing::Session.current).to receive(:performed_write?)
+ .and_return(write_performed)
end
- it 'sticks to the primary if a warden user is found' do
- env = { 'warden' => warden_user }
+ subject { middleware.stick_if_necessary(env) }
+ it 'sticks to the primary for the user' do
Gitlab::Database::LoadBalancing.base_models.each do |model|
expect(model.sticking)
- .to receive(:stick_if_necessary)
+ .to receive(:stick)
.with(:user, 42)
end
- middleware.stick_if_necessary(env)
+ subject
end
- it 'sticks to the primary if a a single sticking object is found' do
- env = { described_class::STICK_OBJECT => single_sticking_object }
+ context 'when no write was performed' do
+ let(:write_performed) { false }
- expect(ApplicationRecord.sticking)
- .to receive(:stick_if_necessary)
- .with(:user, 42)
+ it 'does not stick to the primary' do
+ expect(ApplicationRecord.sticking)
+ .not_to receive(:stick)
- middleware.stick_if_necessary(env)
+ subject
+ end
end
- it 'sticks to the primary if multiple sticking namespaces and identifiers were found' do
- env = { described_class::STICK_OBJECT => multiple_sticking_objects }
+ context 'when there is no user in the env' do
+ let(:warden) { nil }
- expect(ApplicationRecord.sticking)
- .to receive(:stick_if_necessary)
- .with(:user, 42)
- .ordered
+ context 'when there is an explicit single sticking object in the env' do
+ let(:stick_object) { single_sticking_object }
- expect(ApplicationRecord.sticking)
- .to receive(:stick_if_necessary)
- .with(:runner, '123456789')
- .ordered
+ it 'sticks to the single sticking object' do
+ expect(ApplicationRecord.sticking)
+ .to receive(:stick)
+ .with(:user, 99)
- expect(ApplicationRecord.sticking)
- .to receive(:stick_if_necessary)
- .with(:runner, '1234')
- .ordered
+ subject
+ end
+ end
+
+ context 'when there is multiple explicit sticking objects' do
+ let(:stick_object) { multiple_sticking_objects }
+
+ it 'sticks to the sticking objects' do
+ expect(ApplicationRecord.sticking)
+ .to receive(:stick)
+ .with(:user, 42)
+ .ordered
- middleware.stick_if_necessary(env)
+ expect(ApplicationRecord.sticking)
+ .to receive(:stick)
+ .with(:runner, '123456789')
+ .ordered
+
+ expect(ApplicationRecord.sticking)
+ .to receive(:stick)
+ .with(:runner, '1234')
+ .ordered
+
+ subject
+ end
+ end
+
+ context 'when there no explicit sticking objects' do
+ it 'does not stick to the primary' do
+ expect(ApplicationRecord.sticking)
+ .not_to receive(:stick)
+
+ subject
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb b/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
index 789919d2a51..7197b99fe33 100644
--- a/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
@@ -15,7 +15,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery, feature_catego
load_balancer,
nameserver: 'localhost',
port: 8600,
- record: 'foo'
+ record: 'foo',
+ disconnect_timeout: 1 # Short disconnect timeout to keep tests fast
)
end
@@ -192,6 +193,13 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery, feature_catego
end
describe '#replace_hosts' do
+ before do
+ stub_env('LOAD_BALANCER_PARALLEL_DISCONNECT', 'true')
+ allow(service)
+ .to receive(:load_balancer)
+ .and_return(load_balancer)
+ end
+
let(:address_foo) { described_class::Address.new('foo') }
let(:address_bar) { described_class::Address.new('bar') }
@@ -202,19 +210,13 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery, feature_catego
)
end
- before do
- allow(service)
- .to receive(:load_balancer)
- .and_return(load_balancer)
- end
-
it 'replaces the hosts of the load balancer' do
service.replace_hosts([address_bar])
expect(load_balancer.host_list.host_names_and_ports).to eq([['bar', nil]])
end
- it 'disconnects the old connections' do
+ it 'disconnects the old connections gracefully if possible' do
host = load_balancer.host_list.hosts.first
allow(service)
@@ -222,11 +224,59 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery, feature_catego
.and_return(2)
expect(host)
- .to receive(:disconnect!)
- .with(timeout: 2)
+ .to receive(:try_disconnect).and_return(true)
+
+ expect(host).not_to receive(:force_disconnect!)
service.replace_hosts([address_bar])
end
+
+ it 'disconnects the old connections forcefully if necessary' do
+ host = load_balancer.host_list.hosts.first
+
+ allow(service)
+ .to receive(:disconnect_timeout)
+ .and_return(2)
+
+ expect(host)
+ .to receive(:try_disconnect).and_return(false)
+
+ expect(host).to receive(:force_disconnect!)
+
+ service.replace_hosts([address_bar])
+ end
+
+ context 'without old hosts' do
+ before do
+ allow(load_balancer.host_list).to receive(:hosts).and_return([])
+ end
+
+ it 'does not log any load balancing event' do
+ expect(::Gitlab::Database::LoadBalancing::Logger).not_to receive(:info)
+
+ service.replace_hosts([address_foo, address_bar])
+ end
+ end
+
+ context 'when LOAD_BALANCER_PARALLEL_DISCONNECT is false' do
+ before do
+ stub_env('LOAD_BALANCER_PARALLEL_DISCONNECT', 'false')
+ end
+
+ it 'disconnects them sequentially' do
+ host = load_balancer.host_list.hosts.first
+
+ allow(service)
+ .to receive(:disconnect_timeout)
+ .and_return(2)
+
+ expect(host)
+ .to receive(:disconnect!)
+ .with(timeout: 2)
+
+ service.replace_hosts([address_bar])
+ end
+ end
end
describe '#addresses_from_dns' do
@@ -475,4 +525,61 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery, feature_catego
end
end
end
+
+ context 'with service discovery connected to a real load balancer' do
+ let(:database_address) do
+ host, port = ApplicationRecord.connection_pool.db_config.configuration_hash.fetch(:host, :port)
+ described_class::Address.new(host, port)
+ end
+
+ before do
+ # set up the load balancer to point to the test postgres instance with three seperate conections
+ allow(service).to receive(:addresses_from_dns)
+ .and_return([Gitlab::Database::LoadBalancing::Resolver::FAR_FUTURE_TTL,
+ [database_address, database_address, database_address]])
+ .once
+
+ service.perform_service_discovery
+ end
+
+ it 'configures service discovery with three replicas' do
+ expect(service.load_balancer.host_list.hosts.count).to eq(3)
+ end
+
+ it 'swaps the hosts out gracefully when not contended' do
+ expect(service.load_balancer.host_list.hosts.count).to eq(3)
+
+ host = service.load_balancer.host_list.next
+
+ # Check out and use a connection from a host so that there is something to clean up
+ host.pool.with_connection do |connection|
+ expect { connection.execute('select 1') }.not_to raise_error
+ end
+
+ allow(service).to receive(:addresses_from_dns).and_return([Gitlab::Database::LoadBalancing::Resolver::FAR_FUTURE_TTL, []])
+
+ service.load_balancer.host_list.hosts.each do |h|
+ # Expect that the host gets gracefully disconnected
+ expect(h).not_to receive(:force_disconnect!)
+ end
+
+ expect { service.perform_service_discovery }.to change { host.pool.stat[:connections] }.from(1).to(0)
+ end
+
+ it 'swaps the hosts out forcefully when contended' do
+ host = service.load_balancer.host_list.next
+
+ # Check out a connection and leave it checked out (simulate a web request)
+ connection = host.pool.checkout
+ connection.execute('select 1')
+
+ # Expect that the connection is forcefully checked in
+ expect(host).to receive(:force_disconnect!).and_call_original
+ expect(connection).to receive(:steal!).and_call_original
+
+ allow(service).to receive(:addresses_from_dns).and_return([Gitlab::Database::LoadBalancing::Resolver::FAR_FUTURE_TTL, []])
+
+ service.perform_service_discovery
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb b/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
index 7703b5680c2..aaca544ef80 100644
--- a/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
@@ -8,6 +8,9 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
let(:location) { '0/D525E3A8' }
let(:wal_locations) { { Gitlab::Database::MAIN_DATABASE_NAME.to_s => location } }
let(:job) { { "retry" => 3, "job_id" => "a180b47c-3fd6-41b8-81e9-34da61c3400e", 'wal_locations' => wal_locations } }
+ let(:any_caught_up) { Gitlab::Database::LoadBalancing::LoadBalancer::ANY_CAUGHT_UP }
+ let(:all_caught_up) { Gitlab::Database::LoadBalancing::LoadBalancer::ALL_CAUGHT_UP }
+ let(:none_caught_up) { Gitlab::Database::LoadBalancing::LoadBalancer::NONE_CAUGHT_UP }
before do
skip_feature_flags_yaml_validation
@@ -67,7 +70,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
expect(ActiveRecord::Base.load_balancer)
.to receive(:select_up_to_date_host)
.with(location)
- .and_return(true)
+ .and_return(any_caught_up)
run_middleware do
expect(Gitlab::Database::LoadBalancing::Session.current.use_primary?).not_to be_truthy
@@ -86,7 +89,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
allow(lb)
.to receive(:select_up_to_date_host)
.with(location)
- .and_return(true)
+ .and_return(any_caught_up)
end
end
@@ -100,7 +103,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
allow(ActiveRecord::Base.load_balancer)
.to receive(:select_up_to_date_host)
.with(wal_locations[:main])
- .and_return(true)
+ .and_return(any_caught_up)
end
it_behaves_like 'replica is up to date', 'replica'
@@ -133,7 +136,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
context 'when replica is up to date' do
before do
Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
- allow(lb).to receive(:select_up_to_date_host).and_return(true)
+ allow(lb).to receive(:select_up_to_date_host).and_return(any_caught_up)
end
end
@@ -147,7 +150,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
context 'when replica is not up to date' do
before do
Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
- allow(lb).to receive(:select_up_to_date_host).and_return(false, true)
+ allow(lb).to receive(:select_up_to_date_host).and_return(none_caught_up, any_caught_up)
end
end
@@ -161,7 +164,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
context 'when replica is never not up to date' do
before do
Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
- allow(lb).to receive(:select_up_to_date_host).and_return(false, false)
+ allow(lb).to receive(:select_up_to_date_host).and_return(none_caught_up, none_caught_up)
end
end
@@ -267,7 +270,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
context 'when replica is not up to date' do
before do
Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
- allow(lb).to receive(:select_up_to_date_host).and_return(false)
+ allow(lb).to receive(:select_up_to_date_host).and_return(none_caught_up)
end
end
@@ -282,7 +285,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
.to eq(true)
end
- it 'returns true when all load balancers are in sync' do
+ it 'returns true when all load balancers are in sync for some replicas' do
locations = {}
Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
@@ -291,7 +294,23 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
expect(lb)
.to receive(:select_up_to_date_host)
.with('foo')
- .and_return(true)
+ .and_return(any_caught_up)
+ end
+
+ expect(middleware.send(:databases_in_sync?, locations))
+ .to eq(true)
+ end
+
+ it 'returns true when all load balancers are in sync for all replicas' do
+ locations = {}
+
+ Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
+ locations[lb.name] = 'foo'
+
+ expect(lb)
+ .to receive(:select_up_to_date_host)
+ .with('foo')
+ .and_return(all_caught_up)
end
expect(middleware.send(:databases_in_sync?, locations))
@@ -307,7 +326,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
allow(lb)
.to receive(:select_up_to_date_host)
.with('foo')
- .and_return(false)
+ .and_return(none_caught_up)
end
expect(middleware.send(:databases_in_sync?, locations))
@@ -324,7 +343,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
allow(lb)
.to receive(:select_up_to_date_host)
.with('foo')
- .and_return(false)
+ .and_return(none_caught_up)
end
expect(middleware.send(:databases_in_sync?, locations))
@@ -346,8 +365,9 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
end
def replication_lag!(exists)
+ caught_up = exists ? none_caught_up : all_caught_up
Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
- allow(lb).to receive(:select_up_to_date_host).and_return(!exists)
+ allow(lb).to receive(:select_up_to_date_host).and_return(caught_up)
end
end
end
diff --git a/spec/lib/gitlab/database/load_balancing/sticking_spec.rb b/spec/lib/gitlab/database/load_balancing/sticking_spec.rb
index ff31a5cd6cb..8c2901c3b89 100644
--- a/spec/lib/gitlab/database/load_balancing/sticking_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/sticking_spec.rb
@@ -3,327 +3,142 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do
- let(:sticking) do
- described_class.new(ActiveRecord::Base.load_balancer)
- end
+ let(:load_balancer) { ActiveRecord::Base.load_balancer }
+ let(:primary_write_location) { 'the-primary-lsn' }
+ let(:last_write_location) { 'the-last-write-lsn' }
- after do
- Gitlab::Database::LoadBalancing::Session.clear_session
+ let(:sticking) do
+ described_class.new(load_balancer)
end
- shared_examples 'sticking' do
- before do
- allow(ActiveRecord::Base.load_balancer)
- .to receive(:primary_write_location)
- .and_return('foo')
- end
-
- it 'sticks an entity to the primary', :aggregate_failures do
- allow(ActiveRecord::Base.load_balancer)
- .to receive(:primary_only?)
- .and_return(false)
-
- ids.each do |id|
- expect(sticking)
- .to receive(:set_write_location_for)
- .with(:user, id, 'foo')
- end
+ let(:redis) { instance_double(::Gitlab::Redis::MultiStore) }
- expect(Gitlab::Database::LoadBalancing::Session.current)
- .to receive(:use_primary!)
-
- subject
- end
+ before do
+ allow(::Gitlab::Redis::DbLoadBalancing).to receive(:with).and_yield(redis)
- it 'does not update the write location when no replicas are used' do
- expect(sticking).not_to receive(:set_write_location_for)
+ allow(ActiveRecord::Base.load_balancer)
+ .to receive(:primary_write_location)
+ .and_return(primary_write_location)
- subject
- end
+ allow(redis).to receive(:get)
+ .with("database-load-balancing/write-location/#{load_balancer.name}/user/42")
+ .and_return(last_write_location)
end
- shared_examples 'tracking status in redis' do
- describe '#stick_or_unstick_request' do
- it 'sticks or unsticks a single object and updates the Rack environment' do
- expect(sticking)
- .to receive(:unstick_or_continue_sticking)
- .with(:user, 42)
-
- env = {}
-
- sticking.stick_or_unstick_request(env, :user, 42)
-
- expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a)
- .to eq([[sticking, :user, 42]])
- end
-
- it 'sticks or unsticks multiple objects and updates the Rack environment' do
- expect(sticking)
- .to receive(:unstick_or_continue_sticking)
- .with(:user, 42)
- .ordered
-
- expect(sticking)
- .to receive(:unstick_or_continue_sticking)
- .with(:runner, '123456789')
- .ordered
-
- env = {}
-
- sticking.stick_or_unstick_request(env, :user, 42)
- sticking.stick_or_unstick_request(env, :runner, '123456789')
-
- expect(env[Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].to_a).to eq(
- [
- [sticking, :user, 42],
- [sticking, :runner,
- '123456789']
- ])
- end
- end
-
- describe '#stick_if_necessary' do
- it 'does not stick if no write was performed' do
- allow(Gitlab::Database::LoadBalancing::Session.current)
- .to receive(:performed_write?)
- .and_return(false)
-
- expect(sticking).not_to receive(:stick)
-
- sticking.stick_if_necessary(:user, 42)
- end
-
- it 'sticks to the primary if a write was performed' do
- allow(Gitlab::Database::LoadBalancing::Session.current)
- .to receive(:performed_write?)
- .and_return(true)
-
- expect(sticking)
- .to receive(:stick)
- .with(:user, 42)
+ after do
+ Gitlab::Database::LoadBalancing::Session.clear_session
+ end
- sticking.stick_if_necessary(:user, 42)
- end
+ describe '#find_caught_up_replica' do
+ before do
+ allow(ActiveSupport::Notifications).to receive(:instrument).and_call_original
end
- describe '#all_caught_up?' do
- let(:lb) { ActiveRecord::Base.load_balancer }
- let(:last_write_location) { 'foo' }
-
- before do
- allow(ActiveSupport::Notifications).to receive(:instrument).and_call_original
-
- allow(sticking)
- .to receive(:last_write_location_for)
- .with(:user, 42)
- .and_return(last_write_location)
- end
-
- context 'when no write location could be found' do
- let(:last_write_location) { nil }
-
- it 'returns true' do
- expect(lb).not_to receive(:select_up_to_date_host)
-
- expect(sticking.all_caught_up?(:user, 42)).to eq(true)
- end
- end
-
- context 'when all secondaries have caught up' do
- before do
- allow(lb).to receive(:select_up_to_date_host).with('foo').and_return(true)
- end
-
- it 'returns true, and unsticks' do
- expect(sticking)
- .to receive(:unstick)
- .with(:user, 42)
-
- expect(sticking.all_caught_up?(:user, 42)).to eq(true)
- end
+ context 'when no write location could be found' do
+ let(:last_write_location) { nil }
- it 'notifies with the proper event payload' do
- expect(ActiveSupport::Notifications)
- .to receive(:instrument)
- .with('caught_up_replica_pick.load_balancing', { result: true })
- .and_call_original
+ it 'returns true' do
+ expect(load_balancer).not_to receive(:select_up_to_date_host)
- sticking.all_caught_up?(:user, 42)
- end
+ expect(sticking.find_caught_up_replica(:user, 42)).to eq(true)
end
- context 'when the secondaries have not yet caught up' do
- before do
- allow(lb).to receive(:select_up_to_date_host).with('foo').and_return(false)
- end
-
- it 'returns false' do
- expect(sticking.all_caught_up?(:user, 42)).to eq(false)
- end
+ context 'when use_primary_on_empty_location is true' do
+ it 'returns false, does not unstick and calls use_primary!' do
+ expect(load_balancer).not_to receive(:select_up_to_date_host)
- it 'notifies with the proper event payload' do
- expect(ActiveSupport::Notifications)
- .to receive(:instrument)
- .with('caught_up_replica_pick.load_balancing', { result: false })
- .and_call_original
+ expect(redis).not_to receive(:del)
+ expect(::Gitlab::Database::LoadBalancing::Session.current).to receive(:use_primary!)
- sticking.all_caught_up?(:user, 42)
+ expect(sticking.find_caught_up_replica(:user, 42, use_primary_on_empty_location: true)).to eq(false)
end
end
end
- describe '#unstick_or_continue_sticking' do
- let(:lb) { ActiveRecord::Base.load_balancer }
-
- it 'simply returns if no write location could be found' do
- allow(sticking)
- .to receive(:last_write_location_for)
- .with(:user, 42)
- .and_return(nil)
-
- expect(lb).not_to receive(:select_up_to_date_host)
-
- sticking.unstick_or_continue_sticking(:user, 42)
- end
-
- it 'unsticks if all secondaries have caught up' do
- allow(sticking)
- .to receive(:last_write_location_for)
- .with(:user, 42)
- .and_return('foo')
+ context 'when all replicas have caught up' do
+ it 'returns true and unsticks' do
+ expect(load_balancer).to receive(:select_up_to_date_host).with(last_write_location)
+ .and_return(::Gitlab::Database::LoadBalancing::LoadBalancer::ALL_CAUGHT_UP)
- allow(lb).to receive(:select_up_to_date_host).with('foo').and_return(true)
+ expect(redis)
+ .to receive(:del)
+ .with("database-load-balancing/write-location/#{load_balancer.name}/user/42")
- expect(sticking)
- .to receive(:unstick)
- .with(:user, 42)
-
- sticking.unstick_or_continue_sticking(:user, 42)
+ expect(sticking.find_caught_up_replica(:user, 42)).to eq(true)
end
+ end
- it 'continues using the primary if the secondaries have not yet caught up' do
- allow(sticking)
- .to receive(:last_write_location_for)
- .with(:user, 42)
- .and_return('foo')
-
- allow(lb).to receive(:select_up_to_date_host).with('foo').and_return(false)
-
- expect(Gitlab::Database::LoadBalancing::Session.current)
- .to receive(:use_primary!)
+ context 'when only some of the replicas have caught up' do
+ it 'returns true and does not unstick' do
+ expect(load_balancer).to receive(:select_up_to_date_host).with(last_write_location)
+ .and_return(::Gitlab::Database::LoadBalancing::LoadBalancer::ANY_CAUGHT_UP)
- sticking.unstick_or_continue_sticking(:user, 42)
- end
- end
+ expect(redis).not_to receive(:del)
- describe '#stick' do
- it_behaves_like 'sticking' do
- let(:ids) { [42] }
- subject { sticking.stick(:user, ids.first) }
+ expect(sticking.find_caught_up_replica(:user, 42)).to eq(true)
end
end
- describe '#bulk_stick' do
- it_behaves_like 'sticking' do
- let(:ids) { [42, 43] }
- subject { sticking.bulk_stick(:user, ids) }
+ context 'when none of the replicas have caught up' do
+ before do
+ allow(load_balancer).to receive(:select_up_to_date_host).with(last_write_location)
+ .and_return(::Gitlab::Database::LoadBalancing::LoadBalancer::NONE_CAUGHT_UP)
end
- end
-
- describe '#mark_primary_write_location' do
- it 'updates the write location with the load balancer' do
- allow(ActiveRecord::Base.load_balancer)
- .to receive(:primary_write_location)
- .and_return('foo')
- allow(ActiveRecord::Base.load_balancer)
- .to receive(:primary_only?)
- .and_return(false)
+ it 'returns false, does not unstick and calls use_primary!' do
+ expect(redis).not_to receive(:del)
+ expect(::Gitlab::Database::LoadBalancing::Session.current).to receive(:use_primary!)
- expect(sticking)
- .to receive(:set_write_location_for)
- .with(:user, 42, 'foo')
-
- sticking.mark_primary_write_location(:user, 42)
+ expect(sticking.find_caught_up_replica(:user, 42)).to eq(false)
end
- it 'does nothing when no replicas are used' do
- expect(sticking).not_to receive(:set_write_location_for)
+ context 'when use_primary_on_failure is false' do
+ it 'does not call use_primary!' do
+ expect(redis).not_to receive(:del)
+ expect(::Gitlab::Database::LoadBalancing::Session.current).not_to receive(:use_primary!)
- sticking.mark_primary_write_location(:user, 42)
+ expect(sticking.find_caught_up_replica(:user, 42, use_primary_on_failure: false)).to eq(false)
+ end
end
end
+ end
- describe '#unstick' do
- it 'removes the sticking data from Redis' do
- sticking.set_write_location_for(:user, 4, 'foo')
- sticking.unstick(:user, 4)
+ shared_examples 'sticking' do
+ it 'sticks an entity to the primary', :aggregate_failures do
+ allow(ActiveRecord::Base.load_balancer)
+ .to receive(:primary_only?)
+ .and_return(false)
- expect(sticking.last_write_location_for(:user, 4)).to be_nil
+ ids.each do |id|
+ expect(redis)
+ .to receive(:set)
+ .with("database-load-balancing/write-location/#{load_balancer.name}/user/#{id}", 'the-primary-lsn', ex: 30)
end
- end
- describe '#last_write_location_for' do
- it 'returns the last WAL write location for a user' do
- sticking.set_write_location_for(:user, 4, 'foo')
+ expect(Gitlab::Database::LoadBalancing::Session.current)
+ .to receive(:use_primary!)
- expect(sticking.last_write_location_for(:user, 4)).to eq('foo')
- end
+ subject
end
- describe '#select_caught_up_replicas' do
- let(:lb) { ActiveRecord::Base.load_balancer }
-
- context 'with no write location' do
- before do
- allow(sticking)
- .to receive(:last_write_location_for)
- .with(:project, 42)
- .and_return(nil)
- end
-
- it 'returns false and does not try to find caught up hosts' do
- expect(lb).not_to receive(:select_up_to_date_host)
- expect(sticking.select_caught_up_replicas(:project, 42)).to be false
- end
- end
-
- context 'with write location' do
- before do
- allow(sticking)
- .to receive(:last_write_location_for)
- .with(:project, 42)
- .and_return('foo')
- end
+ it 'does not update the write location when no replicas are used' do
+ expect(sticking).not_to receive(:set_write_location_for)
- it 'returns true, selects hosts, and unsticks if any secondary has caught up' do
- expect(lb).to receive(:select_up_to_date_host).and_return(true)
- expect(sticking)
- .to receive(:unstick)
- .with(:project, 42)
- expect(sticking.select_caught_up_replicas(:project, 42)).to be true
- end
- end
+ subject
end
end
- context 'with multi-store feature flags turned on' do
- it_behaves_like 'tracking status in redis'
- end
-
- context 'when both multi-store feature flags are off' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_db_load_balancing: false)
- stub_feature_flags(use_primary_store_as_default_for_db_load_balancing: false)
+ describe '#stick' do
+ it_behaves_like 'sticking' do
+ let(:ids) { [42] }
+ subject { sticking.stick(:user, ids.first) }
end
-
- it_behaves_like 'tracking status in redis'
end
- describe '#redis_key_for' do
- it 'returns a String' do
- expect(sticking.redis_key_for(:user, 42))
- .to eq('database-load-balancing/write-location/main/user/42')
+ describe '#bulk_stick' do
+ it_behaves_like 'sticking' do
+ let(:ids) { [42, 43] }
+ subject { sticking.bulk_stick(:user, ids) }
end
end
end
diff --git a/spec/lib/gitlab/database/migrations/instrumentation_spec.rb b/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
index 0b25389c667..a12e0909dc2 100644
--- a/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
+++ b/spec/lib/gitlab/database/migrations/instrumentation_spec.rb
@@ -107,6 +107,8 @@ RSpec.describe Gitlab::Database::Migrations::Instrumentation do
before do
observe
+ rescue Exception # rubocop:disable Lint/RescueException
+ # ignore (we expect this exception)
end
it 'records a valid observation', :aggregate_failures do
diff --git a/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb b/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
index 6cac7abb703..2fa4c9e562f 100644
--- a/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
+++ b/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
@@ -14,14 +14,17 @@ RSpec.describe 'cross-database foreign keys' do
'gitlab_subscriptions.hosted_plan_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422012
'group_import_states.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421210
'identities.saml_provider_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422010
- 'project_authorizations.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422044
+ 'issues.author_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422154
+ 'issues.closed_by_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422154
+ 'issues.updated_by_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422154
+ 'issue_assignees.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422154
'merge_requests.assignee_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
'merge_requests.updated_by_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
'merge_requests.merge_user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
'merge_requests.author_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080
+ 'project_authorizations.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422044
'projects.creator_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421844
'projects.marked_for_deletion_by_user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421844
- 'routes.namespace_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/420869
'user_group_callouts.user_id' # https://gitlab.com/gitlab-org/gitlab/-/issues/421287
]
end
diff --git a/spec/lib/gitlab/database/no_overrides_for_through_associations_spec.rb b/spec/lib/gitlab/database/no_overrides_for_through_associations_spec.rb
new file mode 100644
index 00000000000..ca7b6c8aa98
--- /dev/null
+++ b/spec/lib/gitlab/database/no_overrides_for_through_associations_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'overridden has_many :through associations', :eager_load, feature_category: :database do
+ let!(:allowed_overrides) do
+ [
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/424851
+ override_class.new(:assignees, 'app/models/concerns/deprecated_assignee.rb'),
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/424852
+ override_class.new(:authorized_projects, 'app/models/user.rb'),
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/424853
+ override_class.new(:project, 'app/models/incident_management/issuable_escalation_status.rb'),
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/424854
+ override_class.new(:remediations, 'ee/app/models/vulnerabilities/finding.rb')
+ ]
+ end
+
+ let!(:override_class) do
+ Struct.new(:method_name, :file_path, :association_class) do
+ def initialize(method_name, file_path, association_class = nil)
+ super(method_name, file_path, association_class)
+ end
+
+ def ==(other)
+ full_source_path, short_path =
+ file_path.length > other.file_path.length ? [file_path, other.file_path] : [other.file_path, file_path]
+ method_name == other.method_name && full_source_path.include?(short_path)
+ end
+
+ def association_type_name
+ if association_class == ActiveRecord::Associations::HasOneThroughAssociation
+ 'has_one through:'
+ else
+ 'has_many through:'
+ end
+ end
+ end
+ end
+
+ let!(:documentation_link) do
+ 'https://docs.gitlab.com/ee/development/gotchas.html#do-not-override-has_many-through-or-has_one-through-associations'
+ end
+
+ it 'onlies have allowed list of overridden has_many/has_one :through associations', :aggregate_failures do
+ overridden_associations.each do |overriden_method|
+ expect(allowed_override?(overriden_method)).to be_truthy,
+ "Found an overridden #{overriden_method.association_type_name} association " \
+ "named `#{overriden_method.method_name}`, in #{overriden_method.file_path}, which isn't allowed. " \
+ "Overriding such associations can have dangerous impacts, see: #{documentation_link}"
+ end
+ end
+
+ private
+
+ def allowed_override?(overriden_method)
+ allowed_overrides.find do |override|
+ override == overriden_method
+ end
+ end
+
+ def overridden_associations
+ ApplicationRecord.descendants.reject(&:abstract_class?).each_with_object([]) do |klass, array|
+ through_reflections = klass.reflect_on_all_associations.select do |assoc|
+ assoc.is_a?(ActiveRecord::Reflection::ThroughReflection)
+ end
+
+ overridden_methods = through_reflections
+ .map { |association| [association.association_class, association.name] }
+ .map { |association_class, method_name| [method_name, source_location(klass, method_name), association_class] }
+ .reject { |_, source_location, _| source_location.include?('activerecord-') }
+
+ array << override_class.new(*overridden_methods.flatten) if overridden_methods.any?
+ end
+ end
+
+ def source_location(klass, method_name)
+ klass.instance_method(method_name).source_location.first
+ end
+end
diff --git a/spec/lib/gitlab/database/partitioning/ci_sliding_list_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/ci_sliding_list_strategy_spec.rb
index f415e892818..79c2c9e32d2 100644
--- a/spec/lib/gitlab/database/partitioning/ci_sliding_list_strategy_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/ci_sliding_list_strategy_spec.rb
@@ -175,4 +175,30 @@ RSpec.describe Gitlab::Database::Partitioning::CiSlidingListStrategy, feature_ca
end.not_to raise_error
end
end
+
+ describe 'attributes' do
+ let(:partitioning_key) { :partition }
+ let(:next_partition_if) { -> { true } }
+ let(:detach_partition_if) { -> { false } }
+ let(:analyze_interval) { 1.week }
+
+ subject(:strategy) do
+ described_class.new(
+ model, partitioning_key,
+ next_partition_if: next_partition_if,
+ detach_partition_if: detach_partition_if,
+ analyze_interval: analyze_interval
+ )
+ end
+
+ specify do
+ expect(strategy).to have_attributes({
+ model: model,
+ partitioning_key: partitioning_key,
+ next_partition_if: next_partition_if,
+ detach_partition_if: detach_partition_if,
+ analyze_interval: analyze_interval
+ })
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
index 50115a6f3dd..3afa338fdf7 100644
--- a/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
+RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy, feature_category: :database do
let(:connection) { ActiveRecord::Base.connection }
describe '#current_partitions' do
@@ -273,4 +273,32 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
end
end
end
+
+ describe 'attributes' do
+ let(:partitioning_key) { :partition }
+ let(:retain_non_empty_partitions) { true }
+ let(:retain_for) { 12.months }
+ let(:analyze_interval) { 1.week }
+ let(:model) { class_double(ApplicationRecord, table_name: table_name, connection: connection) }
+ let(:table_name) { :_test_partitioned_test }
+
+ subject(:strategy) do
+ described_class.new(
+ model, partitioning_key,
+ retain_for: retain_for,
+ retain_non_empty_partitions: retain_non_empty_partitions,
+ analyze_interval: analyze_interval
+ )
+ end
+
+ specify do
+ expect(strategy).to have_attributes({
+ model: model,
+ partitioning_key: partitioning_key,
+ retain_for: retain_for,
+ retain_non_empty_partitions: retain_non_empty_partitions,
+ analyze_interval: analyze_interval
+ })
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb b/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb
index eac4a162879..c41228777ca 100644
--- a/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/partition_manager_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
+RSpec.describe Gitlab::Database::Partitioning::PartitionManager, feature_category: :database do
+ include ActiveSupport::Testing::TimeHelpers
include Database::PartitioningHelpers
include ExclusiveLeaseHelpers
@@ -15,7 +16,7 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
let(:connection) { ActiveRecord::Base.connection }
let(:table) { partitioned_table_name }
let(:partitioning_strategy) do
- double(missing_partitions: partitions, extra_partitions: [], after_adding_partitions: nil)
+ double(missing_partitions: partitions, extra_partitions: [], after_adding_partitions: nil, analyze_interval: nil)
end
let(:partitions) do
@@ -125,7 +126,7 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
let(:connection) { ActiveRecord::Base.connection }
let(:table) { :_test_foo }
let(:partitioning_strategy) do
- double(extra_partitions: extra_partitions, missing_partitions: [], after_adding_partitions: nil)
+ double(extra_partitions: extra_partitions, missing_partitions: [], after_adding_partitions: nil, analyze_interval: nil)
end
before do
@@ -256,6 +257,154 @@ RSpec.describe Gitlab::Database::Partitioning::PartitionManager do
end
end
+ describe 'analyze partitioned table' do
+ let(:analyze) { true }
+ let(:analyze_table) { partitioned_table_name }
+ let(:analyze_partition) { "#{partitioned_table_name}_1" }
+ let(:analyze_regex) { /ANALYZE VERBOSE "#{analyze_table}"/ }
+ let(:analyze_interval) { 1.week }
+ let(:connection) { my_model.connection }
+ let(:create_partition) { true }
+ let(:my_model) do
+ interval = analyze_interval
+ Class.new(ApplicationRecord) do
+ include PartitionedTable
+
+ partitioned_by :partition_id,
+ strategy: :ci_sliding_list,
+ next_partition_if: proc { false },
+ detach_partition_if: proc { false },
+ analyze_interval: interval
+ end
+ end
+
+ shared_examples_for 'run only once analyze within interval' do
+ specify do
+ control = ActiveRecord::QueryRecorder.new { described_class.new(my_model, connection: connection).sync_partitions(analyze: analyze) }
+ expect(control.occurrences).to include(analyze_regex)
+
+ control = ActiveRecord::QueryRecorder.new { described_class.new(my_model, connection: connection).sync_partitions(analyze: analyze) }
+ expect(control.occurrences).not_to include(analyze_regex)
+
+ travel_to((analyze_interval * 2).since) do
+ control = ActiveRecord::QueryRecorder.new { described_class.new(my_model, connection: connection).sync_partitions(analyze: analyze) }
+ expect(control.occurrences).to include(analyze_regex)
+ end
+ end
+ end
+
+ shared_examples_for 'not to run the analyze at all' do
+ specify do
+ control = ActiveRecord::QueryRecorder.new { described_class.new(my_model, connection: connection).sync_partitions(analyze: analyze) }
+ expect(control.occurrences).not_to include(analyze_regex)
+
+ control = ActiveRecord::QueryRecorder.new { described_class.new(my_model, connection: connection).sync_partitions(analyze: analyze) }
+ expect(control.occurrences).not_to include(analyze_regex)
+
+ travel_to((analyze_interval * 2).since) do
+ control = ActiveRecord::QueryRecorder.new { described_class.new(my_model, connection: connection).sync_partitions(analyze: analyze) }
+ expect(control.occurrences).not_to include(analyze_regex)
+ end
+ end
+ end
+
+ before do
+ my_model.table_name = partitioned_table_name
+
+ connection.execute(<<~SQL)
+ CREATE TABLE #{analyze_table}(id serial) PARTITION BY LIST (id);
+ SQL
+
+ connection.execute(<<~SQL) if create_partition
+ CREATE TABLE IF NOT EXISTS #{analyze_partition} PARTITION OF #{analyze_table} FOR VALUES IN (1);
+ SQL
+
+ allow(connection).to receive(:select_value).and_return(nil, Time.current, Time.current)
+ end
+
+ context 'when feature flag database_analyze_on_partitioned_tables is enabled' do
+ before do
+ stub_feature_flags(database_analyze_on_partitioned_tables: true)
+ end
+
+ it_behaves_like 'run only once analyze within interval'
+
+ context 'when analyze is false' do
+ let(:analyze) { false }
+
+ it_behaves_like 'not to run the analyze at all'
+ end
+
+ context 'when model does not set analyze_interval' do
+ let(:my_model) do
+ Class.new(ApplicationRecord) do
+ include PartitionedTable
+
+ partitioned_by :partition_id,
+ strategy: :ci_sliding_list,
+ next_partition_if: proc { false },
+ detach_partition_if: proc { false }
+ end
+ end
+
+ it_behaves_like 'not to run the analyze at all'
+ end
+
+ context 'when no partition is created' do
+ let(:create_partition) { false }
+
+ it_behaves_like 'run only once analyze within interval'
+ end
+ end
+
+ context 'when feature flag database_analyze_on_partitioned_tables is disabled' do
+ before do
+ stub_feature_flags(database_analyze_on_partitioned_tables: false)
+ end
+
+ it_behaves_like 'not to run the analyze at all'
+
+ context 'when analyze is false' do
+ let(:analyze) { false }
+
+ it_behaves_like 'not to run the analyze at all'
+ end
+
+ context 'when model does not set analyze_interval' do
+ let(:my_model) do
+ Class.new(ApplicationRecord) do
+ include PartitionedTable
+
+ partitioned_by :partition_id,
+ strategy: :ci_sliding_list,
+ next_partition_if: proc { false },
+ detach_partition_if: proc { false }
+ end
+ end
+
+ it_behaves_like 'not to run the analyze at all'
+ end
+
+ context 'when no partition is created' do
+ let(:create_partition) { false }
+
+ it_behaves_like 'not to run the analyze at all'
+ end
+ end
+ end
+
+ describe 'strategies that support analyze_interval' do
+ [
+ ::Gitlab::Database::Partitioning::MonthlyStrategy,
+ ::Gitlab::Database::Partitioning::SlidingListStrategy,
+ ::Gitlab::Database::Partitioning::CiSlidingListStrategy
+ ].each do |klass|
+ specify "#{klass} supports analyze_interval" do
+ expect(klass).to be_method_defined(:analyze_interval)
+ end
+ end
+ end
+
context 'creating and then detaching partitions for a table' do
let(:connection) { ActiveRecord::Base.connection }
let(:my_model) do
diff --git a/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
index 5b6967c2d14..ac4d345271e 100644
--- a/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb
@@ -290,4 +290,30 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy, feature_cate
expect(partition_3_model.partition).to eq(3)
end
end
+
+ describe 'attributes' do
+ let(:partitioning_key) { :partition }
+ let(:next_partition_if) { -> { puts "next_partition_if" } }
+ let(:detach_partition_if) { -> { puts "detach_partition_if" } }
+ let(:analyze_interval) { 1.week }
+
+ subject(:strategy) do
+ described_class.new(
+ model, partitioning_key,
+ next_partition_if: next_partition_if,
+ detach_partition_if: detach_partition_if,
+ analyze_interval: analyze_interval
+ )
+ end
+
+ specify do
+ expect(strategy).to have_attributes({
+ model: model,
+ partitioning_key: partitioning_key,
+ next_partition_if: next_partition_if,
+ detach_partition_if: detach_partition_if,
+ analyze_interval: analyze_interval
+ })
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/partitioning_spec.rb b/spec/lib/gitlab/database/partitioning_spec.rb
index a1ae75ac916..e53e0cb8def 100644
--- a/spec/lib/gitlab/database/partitioning_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_spec.rb
@@ -8,6 +8,10 @@ RSpec.describe Gitlab::Database::Partitioning, feature_category: :database do
let(:main_connection) { ApplicationRecord.connection }
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: false)
+ end
+
around do |example|
previously_registered_models = described_class.registered_models.dup
described_class.instance_variable_set(:@registered_models, Set.new)
@@ -32,7 +36,7 @@ RSpec.describe Gitlab::Database::Partitioning, feature_category: :database do
describe '.sync_partitions_ignore_db_error' do
it 'calls sync_partitions' do
- expect(described_class).to receive(:sync_partitions)
+ expect(described_class).to receive(:sync_partitions).with(analyze: false)
described_class.sync_partitions_ignore_db_error
end
@@ -100,6 +104,55 @@ RSpec.describe Gitlab::Database::Partitioning, feature_category: :database do
.and change { find_partitions(table_names.last).size }.from(0)
end
+ context 'for analyze' do
+ let(:analyze_regex) { /ANALYZE VERBOSE / }
+ let(:analyze) { true }
+
+ shared_examples_for 'not running analyze' do
+ specify do
+ control = ActiveRecord::QueryRecorder.new { described_class.sync_partitions(analyze: analyze) }
+ expect(control.occurrences).not_to include(analyze_regex)
+ end
+ end
+
+ context 'when analyze_interval is not set' do
+ it_behaves_like 'not running analyze'
+
+ context 'when analyze is set to false' do
+ it_behaves_like 'not running analyze'
+ end
+ end
+
+ context 'when analyze_interval is set' do
+ let(:models) do
+ [
+ Class.new(ApplicationRecord) do
+ include PartitionedTable
+
+ self.table_name = :_test_partitioning_test1
+ partitioned_by :created_at, strategy: :monthly, analyze_interval: 1.week
+ end,
+ Class.new(Gitlab::Database::Partitioning::TableWithoutModel).tap do |klass|
+ klass.table_name = :_test_partitioning_test2
+ klass.partitioned_by(:created_at, strategy: :monthly, analyze_interval: 1.week)
+ klass.limit_connection_names = %i[main]
+ end
+ ]
+ end
+
+ it 'runs analyze' do
+ control = ActiveRecord::QueryRecorder.new { described_class.sync_partitions(models, analyze: analyze) }
+ expect(control.occurrences).to include(analyze_regex)
+ end
+
+ context 'analyze is false' do
+ let(:analyze) { false }
+
+ it_behaves_like 'not running analyze'
+ end
+ end
+ end
+
context 'with multiple databases' do
it 'creates partitions in each database' do
skip_if_shared_database(:ci)
@@ -165,11 +218,11 @@ RSpec.describe Gitlab::Database::Partitioning, feature_category: :database do
execute_on_each_database("DROP TABLE IF EXISTS #{table_name}")
execute_on_each_database(<<~SQL)
- CREATE TABLE #{table_name} (
- id serial not null,
- created_at timestamptz not null,
- PRIMARY KEY (id, created_at))
- PARTITION BY RANGE (created_at);
+ CREATE TABLE #{table_name} (
+ id serial not null,
+ created_at timestamptz not null,
+ PRIMARY KEY (id, created_at))
+ PARTITION BY RANGE (created_at);
SQL
end
end
@@ -204,6 +257,20 @@ RSpec.describe Gitlab::Database::Partitioning, feature_category: :database do
described_class.sync_partitions(models)
end
end
+
+ context 'when disallow_database_ddl_feature_flags feature flag is enabled' do
+ before do
+ described_class.register_models(models)
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+ end
+
+ it 'skips sync_partitions' do
+ expect(described_class::PartitionManager).not_to receive(:new)
+ expect(described_class).to receive(:sync_partitions).and_call_original
+
+ described_class.sync_partitions(models)
+ end
+ end
end
describe '.report_metrics' do
@@ -277,6 +344,18 @@ RSpec.describe Gitlab::Database::Partitioning, feature_category: :database do
end
end
+ context 'when the feature disallow DDL feature flags is enabled' do
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+ end
+
+ it 'does not call the DetachedPartitionDropper' do
+ expect(Gitlab::Database::Partitioning::DetachedPartitionDropper).not_to receive(:new)
+
+ described_class.drop_detached_partitions
+ end
+ end
+
def table_exists?(table_name)
table_oid(table_name).present?
end
diff --git a/spec/lib/gitlab/database/reindexing_spec.rb b/spec/lib/gitlab/database/reindexing_spec.rb
index 851fc7ea3cd..441f6476abe 100644
--- a/spec/lib/gitlab/database/reindexing_spec.rb
+++ b/spec/lib/gitlab/database/reindexing_spec.rb
@@ -6,6 +6,10 @@ RSpec.describe Gitlab::Database::Reindexing, feature_category: :database, time_t
include ExclusiveLeaseHelpers
include Database::DatabaseHelpers
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: false)
+ end
+
describe '.invoke' do
let(:databases) { Gitlab::Database.database_base_models_with_gitlab_shared }
let(:databases_count) { databases.count }
@@ -44,6 +48,14 @@ RSpec.describe Gitlab::Database::Reindexing, feature_category: :database, time_t
described_class.invoke
end
+
+ it 'does not execute async index creation when disable ddl flag is enabled' do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+
+ expect(Gitlab::Database::AsyncIndexes).not_to receive(:create_pending_indexes!)
+
+ described_class.invoke
+ end
end
it 'executes async index destruction prior to any reindexing actions' do
@@ -86,6 +98,14 @@ RSpec.describe Gitlab::Database::Reindexing, feature_category: :database, time_t
described_class.invoke
end
+
+ it 'does not execute async index creation when disable ddl flag is enabled' do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+
+ expect(Gitlab::Database::AsyncIndexes).not_to receive(:validate_pending_entries!)
+
+ described_class.invoke
+ end
end
end
diff --git a/spec/lib/gitlab/database/tables_truncate_spec.rb b/spec/lib/gitlab/database/tables_truncate_spec.rb
index 04bec50088d..e41c7d34378 100644
--- a/spec/lib/gitlab/database/tables_truncate_spec.rb
+++ b/spec/lib/gitlab/database/tables_truncate_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
let(:min_batch_size) { 1 }
let(:main_connection) { ApplicationRecord.connection }
let(:ci_connection) { Ci::ApplicationRecord.connection }
+ let(:logger) { instance_double(Logger) }
# Main Database
let(:main_db_main_item_model) { table("_test_gitlab_main_items", database: "main") }
@@ -32,8 +33,123 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
table("gitlab_partitions_dynamic._test_gitlab_hook_logs_202201", database: "ci")
end
+ before do
+ skip_if_shared_database(:ci)
+
+ # Creating some test tables on the main database
+ main_tables_sql = <<~SQL
+ CREATE TABLE _test_gitlab_main_items (id serial NOT NULL PRIMARY KEY);
+
+ CREATE TABLE _test_gitlab_main_references (
+ id serial NOT NULL PRIMARY KEY,
+ item_id BIGINT NOT NULL,
+ CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_main_items(id)
+ );
+
+ CREATE TABLE _test_gitlab_hook_logs (
+ id bigserial not null,
+ created_at timestamptz not null,
+ item_id BIGINT NOT NULL,
+ PRIMARY KEY (id, created_at),
+ CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_main_items(id)
+ ) PARTITION BY RANGE(created_at);
+
+ CREATE TABLE gitlab_partitions_dynamic._test_gitlab_hook_logs_202201
+ PARTITION OF _test_gitlab_hook_logs
+ FOR VALUES FROM ('20220101') TO ('20220131');
+
+ CREATE TABLE gitlab_partitions_dynamic._test_gitlab_hook_logs_202202
+ PARTITION OF _test_gitlab_hook_logs
+ FOR VALUES FROM ('20220201') TO ('20220228');
+
+ ALTER TABLE _test_gitlab_hook_logs DETACH PARTITION gitlab_partitions_dynamic._test_gitlab_hook_logs_202201;
+ SQL
+
+ execute_on_each_database(main_tables_sql)
+
+ ci_tables_sql = <<~SQL
+ CREATE TABLE _test_gitlab_ci_items (id serial NOT NULL PRIMARY KEY);
+
+ CREATE TABLE _test_gitlab_ci_references (
+ id serial NOT NULL PRIMARY KEY,
+ item_id BIGINT NOT NULL,
+ CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_ci_items(id)
+ );
+ SQL
+
+ execute_on_each_database(ci_tables_sql)
+
+ internal_tables_sql = <<~SQL
+ CREATE TABLE _test_gitlab_shared_items (id serial NOT NULL PRIMARY KEY);
+ SQL
+
+ execute_on_each_database(internal_tables_sql)
+
+ # Filling the tables
+ 5.times do |i|
+ # Main Database
+ main_db_main_item_model.create!(id: i)
+ main_db_main_reference_model.create!(item_id: i)
+ main_db_ci_item_model.create!(id: i)
+ main_db_ci_reference_model.create!(item_id: i)
+ main_db_shared_item_model.create!(id: i)
+ main_db_partitioned_item.create!(item_id: i, created_at: '2022-02-02 02:00')
+ main_db_partitioned_item_detached.create!(item_id: i, created_at: '2022-01-01 01:00')
+ # CI Database
+ ci_db_main_item_model.create!(id: i)
+ ci_db_main_reference_model.create!(item_id: i)
+ ci_db_ci_item_model.create!(id: i)
+ ci_db_ci_reference_model.create!(item_id: i)
+ ci_db_shared_item_model.create!(id: i)
+ ci_db_partitioned_item.create!(item_id: i, created_at: '2022-02-02 02:00')
+ ci_db_partitioned_item_detached.create!(item_id: i, created_at: '2022-01-01 01:00')
+ end
+
+ Gitlab::Database::SharedModel.using_connection(main_connection) do
+ Postgresql::DetachedPartition.create!(
+ table_name: '_test_gitlab_hook_logs_202201',
+ drop_after: Time.current
+ )
+ end
+
+ Gitlab::Database::SharedModel.using_connection(ci_connection) do
+ Postgresql::DetachedPartition.create!(
+ table_name: '_test_gitlab_hook_logs_202201',
+ drop_after: Time.current
+ )
+ end
+
+ allow(Gitlab::Database::GitlabSchema).to receive(:tables_to_schema).and_return(
+ {
+ "_test_gitlab_main_items" => :gitlab_main,
+ "_test_gitlab_main_references" => :gitlab_main,
+ "_test_gitlab_hook_logs" => :gitlab_main,
+ "_test_gitlab_ci_items" => :gitlab_ci,
+ "_test_gitlab_ci_references" => :gitlab_ci,
+ "_test_gitlab_shared_items" => :gitlab_shared,
+ "_test_gitlab_geo_items" => :gitlab_geo
+ }
+ )
+
+ allow(Gitlab::Database::GitlabSchema).to receive(:views_and_tables_to_schema).and_return(
+ {
+ "_test_gitlab_main_items" => :gitlab_main,
+ "_test_gitlab_main_references" => :gitlab_main,
+ "_test_gitlab_hook_logs" => :gitlab_main,
+ "_test_gitlab_ci_items" => :gitlab_ci,
+ "_test_gitlab_ci_references" => :gitlab_ci,
+ "_test_gitlab_shared_items" => :gitlab_shared,
+ "_test_gitlab_geo_items" => :gitlab_geo,
+ "detached_partitions" => :gitlab_shared,
+ "postgres_foreign_keys" => :gitlab_shared,
+ "postgres_partitions" => :gitlab_shared
+ }
+ )
+
+ allow(logger).to receive(:info).with(any_args)
+ end
+
shared_examples 'truncating legacy tables on a database' do
- let(:logger) { instance_double(Logger) }
let(:dry_run) { false }
let(:until_table) { nil }
@@ -47,122 +163,6 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
).execute
end
- before do
- skip_if_shared_database(:ci)
-
- # Creating some test tables on the main database
- main_tables_sql = <<~SQL
- CREATE TABLE _test_gitlab_main_items (id serial NOT NULL PRIMARY KEY);
-
- CREATE TABLE _test_gitlab_main_references (
- id serial NOT NULL PRIMARY KEY,
- item_id BIGINT NOT NULL,
- CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_main_items(id)
- );
-
- CREATE TABLE _test_gitlab_hook_logs (
- id bigserial not null,
- created_at timestamptz not null,
- item_id BIGINT NOT NULL,
- PRIMARY KEY (id, created_at),
- CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_main_items(id)
- ) PARTITION BY RANGE(created_at);
-
- CREATE TABLE gitlab_partitions_dynamic._test_gitlab_hook_logs_202201
- PARTITION OF _test_gitlab_hook_logs
- FOR VALUES FROM ('20220101') TO ('20220131');
-
- CREATE TABLE gitlab_partitions_dynamic._test_gitlab_hook_logs_202202
- PARTITION OF _test_gitlab_hook_logs
- FOR VALUES FROM ('20220201') TO ('20220228');
-
- ALTER TABLE _test_gitlab_hook_logs DETACH PARTITION gitlab_partitions_dynamic._test_gitlab_hook_logs_202201;
- SQL
-
- execute_on_each_database(main_tables_sql)
-
- ci_tables_sql = <<~SQL
- CREATE TABLE _test_gitlab_ci_items (id serial NOT NULL PRIMARY KEY);
-
- CREATE TABLE _test_gitlab_ci_references (
- id serial NOT NULL PRIMARY KEY,
- item_id BIGINT NOT NULL,
- CONSTRAINT fk_constrained_1 FOREIGN KEY(item_id) REFERENCES _test_gitlab_ci_items(id)
- );
- SQL
-
- execute_on_each_database(ci_tables_sql)
-
- internal_tables_sql = <<~SQL
- CREATE TABLE _test_gitlab_shared_items (id serial NOT NULL PRIMARY KEY);
- SQL
-
- execute_on_each_database(internal_tables_sql)
-
- # Filling the tables
- 5.times do |i|
- # Main Database
- main_db_main_item_model.create!(id: i)
- main_db_main_reference_model.create!(item_id: i)
- main_db_ci_item_model.create!(id: i)
- main_db_ci_reference_model.create!(item_id: i)
- main_db_shared_item_model.create!(id: i)
- main_db_partitioned_item.create!(item_id: i, created_at: '2022-02-02 02:00')
- main_db_partitioned_item_detached.create!(item_id: i, created_at: '2022-01-01 01:00')
- # CI Database
- ci_db_main_item_model.create!(id: i)
- ci_db_main_reference_model.create!(item_id: i)
- ci_db_ci_item_model.create!(id: i)
- ci_db_ci_reference_model.create!(item_id: i)
- ci_db_shared_item_model.create!(id: i)
- ci_db_partitioned_item.create!(item_id: i, created_at: '2022-02-02 02:00')
- ci_db_partitioned_item_detached.create!(item_id: i, created_at: '2022-01-01 01:00')
- end
-
- Gitlab::Database::SharedModel.using_connection(main_connection) do
- Postgresql::DetachedPartition.create!(
- table_name: '_test_gitlab_hook_logs_202201',
- drop_after: Time.current
- )
- end
-
- Gitlab::Database::SharedModel.using_connection(ci_connection) do
- Postgresql::DetachedPartition.create!(
- table_name: '_test_gitlab_hook_logs_202201',
- drop_after: Time.current
- )
- end
-
- allow(Gitlab::Database::GitlabSchema).to receive(:tables_to_schema).and_return(
- {
- "_test_gitlab_main_items" => :gitlab_main,
- "_test_gitlab_main_references" => :gitlab_main,
- "_test_gitlab_hook_logs" => :gitlab_main,
- "_test_gitlab_ci_items" => :gitlab_ci,
- "_test_gitlab_ci_references" => :gitlab_ci,
- "_test_gitlab_shared_items" => :gitlab_shared,
- "_test_gitlab_geo_items" => :gitlab_geo
- }
- )
-
- allow(Gitlab::Database::GitlabSchema).to receive(:views_and_tables_to_schema).and_return(
- {
- "_test_gitlab_main_items" => :gitlab_main,
- "_test_gitlab_main_references" => :gitlab_main,
- "_test_gitlab_hook_logs" => :gitlab_main,
- "_test_gitlab_ci_items" => :gitlab_ci,
- "_test_gitlab_ci_references" => :gitlab_ci,
- "_test_gitlab_shared_items" => :gitlab_shared,
- "_test_gitlab_geo_items" => :gitlab_geo,
- "detached_partitions" => :gitlab_shared,
- "postgres_foreign_keys" => :gitlab_shared,
- "postgres_partitions" => :gitlab_shared
- }
- )
-
- allow(logger).to receive(:info).with(any_args)
- end
-
context 'when the truncated tables are not locked for writes' do
it 'raises an error that the tables are not locked for writes' do
error_message = /is not locked for writes. Run the rake task gitlab:db:lock_writes first/
@@ -348,6 +348,50 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
end
end
+ describe '#needs_truncation?' do
+ let(:database_name) { 'ci' }
+
+ subject { described_class.new(database_name: database_name).needs_truncation? }
+
+ context 'when running in a single database mode' do
+ before do
+ skip_if_multiple_databases_are_setup(:ci)
+ end
+
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when running in a multiple database mode' do
+ before do
+ skip_if_shared_database(:ci)
+ end
+
+ context 'with main data in ci database' do
+ it { is_expected.to eq(true) }
+ end
+
+ context 'with no main data in ci datatabase' do
+ before do
+ # Remove 'main' data in ci database
+ ci_connection.truncate_tables([:_test_gitlab_main_items, :_test_gitlab_main_references])
+ end
+
+ it { is_expected.to eq(false) }
+
+ it 'supresses some QueryAnalyzers' do
+ expect(
+ Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection
+ ).to receive(:with_suppressed).and_call_original
+ expect(
+ Gitlab::Database::QueryAnalyzers::Ci::PartitioningRoutingAnalyzer
+ ).to receive(:with_suppressed).and_call_original
+
+ subject
+ end
+ end
+ end
+ end
+
def geo_configured?
!!ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'geo')
end
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index 0d8fa4dad6d..6dd7d29ab42 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -198,59 +198,6 @@ RSpec.describe Gitlab::Database, feature_category: :database do
end
end
- describe '.check_postgres_version_and_print_warning' do
- let(:reflect) { instance_spy(Gitlab::Database::Reflection) }
-
- subject { described_class.check_postgres_version_and_print_warning }
-
- before do
- allow(Gitlab::Database::Reflection)
- .to receive(:new)
- .and_return(reflect)
- end
-
- it 'prints a warning if not compliant with minimum postgres version' do
- allow(reflect).to receive(:postgresql_minimum_supported_version?).and_return(false)
-
- expect(Kernel)
- .to receive(:warn)
- .with(/You are using PostgreSQL/)
- .exactly(described_class.database_base_models.length)
- .times
-
- subject
- end
-
- it 'doesnt print a warning if compliant with minimum postgres version' do
- allow(reflect).to receive(:postgresql_minimum_supported_version?).and_return(true)
-
- expect(Kernel).not_to receive(:warn).with(/You are using PostgreSQL/)
-
- subject
- end
-
- it 'doesnt print a warning in Rails runner environment' do
- allow(reflect).to receive(:postgresql_minimum_supported_version?).and_return(false)
- allow(Gitlab::Runtime).to receive(:rails_runner?).and_return(true)
-
- expect(Kernel).not_to receive(:warn).with(/You are using PostgreSQL/)
-
- subject
- end
-
- it 'ignores ActiveRecord errors' do
- allow(reflect).to receive(:postgresql_minimum_supported_version?).and_raise(ActiveRecord::ActiveRecordError)
-
- expect { subject }.not_to raise_error
- end
-
- it 'ignores Postgres errors' do
- allow(reflect).to receive(:postgresql_minimum_supported_version?).and_raise(PG::Error)
-
- expect { subject }.not_to raise_error
- end
- end
-
describe '.db_config_for_connection' do
context 'when the regular connection is used' do
it 'returns db_config' do
diff --git a/spec/lib/gitlab/database_warnings_spec.rb b/spec/lib/gitlab/database_warnings_spec.rb
new file mode 100644
index 00000000000..6658190b94c
--- /dev/null
+++ b/spec/lib/gitlab/database_warnings_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::DatabaseWarnings, feature_category: :database do
+ describe '.check_postgres_version_and_print_warning' do
+ let(:reflect) { instance_spy(Gitlab::Database::Reflection) }
+
+ subject { described_class.check_postgres_version_and_print_warning }
+
+ before do
+ allow(Gitlab::Database::Reflection)
+ .to receive(:new)
+ .and_return(reflect)
+ end
+
+ it 'prints a warning if not compliant with minimum postgres version' do
+ allow(reflect).to receive(:postgresql_minimum_supported_version?).and_return(false)
+
+ expect(Kernel)
+ .to receive(:warn)
+ .with(/You are using PostgreSQL/)
+ .exactly(Gitlab::Database.database_base_models.length)
+ .times
+
+ subject
+ end
+
+ it 'does not print a warning if compliant with minimum postgres version' do
+ allow(reflect).to receive(:postgresql_minimum_supported_version?).and_return(true)
+
+ expect(Kernel).not_to receive(:warn).with(/You are using PostgreSQL/)
+
+ subject
+ end
+
+ it 'does not print a warning in Rails runner environment' do
+ allow(reflect).to receive(:postgresql_minimum_supported_version?).and_return(false)
+ allow(Gitlab::Runtime).to receive(:rails_runner?).and_return(true)
+
+ expect(Kernel).not_to receive(:warn).with(/You are using PostgreSQL/)
+
+ subject
+ end
+
+ it 'ignores ActiveRecord errors' do
+ allow(reflect).to receive(:postgresql_minimum_supported_version?).and_raise(ActiveRecord::ActiveRecordError)
+
+ expect { subject }.not_to raise_error
+ end
+
+ it 'ignores Postgres errors' do
+ allow(reflect).to receive(:postgresql_minimum_supported_version?).and_raise(PG::Error)
+
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ describe '.check_single_connection_and_print_warning' do
+ subject { described_class.check_single_connection_and_print_warning }
+
+ it 'prints a warning if single connection' do
+ allow(Gitlab::Database).to receive(:database_mode).and_return(Gitlab::Database::MODE_SINGLE_DATABASE)
+
+ expect(Kernel).to receive(:warn).with(/Your database has a single connection/)
+
+ subject
+ end
+
+ it 'does not print a warning if single ci connection' do
+ allow(Gitlab::Database).to receive(:database_mode)
+ .and_return(Gitlab::Database::MODE_SINGLE_DATABASE_CI_CONNECTION)
+
+ expect(Kernel).not_to receive(:warn)
+
+ subject
+ end
+
+ it 'does not print a warning if multiple connection' do
+ allow(Gitlab::Database).to receive(:database_mode).and_return(Gitlab::Database::MODE_MULTIPLE_DATABASES)
+
+ expect(Kernel).not_to receive(:warn)
+
+ subject
+ end
+
+ it 'does not print a warning in Rails runner environment' do
+ allow(Gitlab::Database).to receive(:database_mode).and_return(Gitlab::Database::MODE_SINGLE_DATABASE)
+ allow(Gitlab::Runtime).to receive(:rails_runner?).and_return(true)
+
+ expect(Kernel).not_to receive(:warn)
+
+ subject
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
index e3b0e90bff9..c7b69f39951 100644
--- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe Gitlab::Email::Handler::CreateNoteHandler do
end
context 'when the issue is a Service Desk issue' do
- let(:original_recipient) { User.support_bot }
+ let(:original_recipient) { Users::Internal.support_bot }
it 'does not raise a UserNotFoundError' do
expect { receiver.execute }.not_to raise_error
@@ -209,7 +209,7 @@ RSpec.describe Gitlab::Email::Handler::CreateNoteHandler do
context 'when note is authored from external author for service desk' do
before do
- SentNotification.find_by(reply_key: mail_key).update!(recipient: User.support_bot)
+ SentNotification.find_by(reply_key: mail_key).update!(recipient: Users::Internal.support_bot)
end
context 'when email contains text, quoted text and quick commands' do
diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
index 98522c53a47..6941ebd2e11 100644
--- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
new_issue = Issue.last
- expect(new_issue.author).to eql(User.support_bot)
+ expect(new_issue.author).to eql(Users::Internal.support_bot)
expect(new_issue.confidential?).to be true
expect(new_issue.all_references.all).to be_empty
expect(new_issue.title).to eq("The message subject! @all")
@@ -131,7 +131,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
expect(notes.count).to eq(1)
expect(new_note.note).to eq("Service desk reply!\n\n`/label ~label2`")
- expect(new_note.author).to eql(User.support_bot)
+ expect(new_note.author).to eql(Users::Internal.support_bot)
end
it 'does not send thank you email' do
@@ -267,7 +267,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
issue = Issue.last
expect(issue.description).to include('Text from service_desk2 template')
expect(issue.label_ids).to include(label.id)
- expect(issue.author_id).to eq(User.support_bot.id)
+ expect(issue.author_id).to eq(Users::Internal.support_bot.id)
expect(issue.milestone).to eq(milestone)
end
end
@@ -294,7 +294,7 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler, feature_category: :se
note = Note.last
expect(note.note).to include("WARNING: The template file unknown.md used for service desk issues is empty or could not be found.")
- expect(note.author).to eq(User.support_bot)
+ expect(note.author).to eq(Users::Internal.support_bot)
end
it 'does not send warning note email' do
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/admin_verify_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/admin_verify_spec.rb
deleted file mode 100644
index 7a09feb5b64..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing/admin_verify_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing::AdminVerify do
- let_it_be(:group) { build(:group) }
- let_it_be(:user) { build(:user) }
-
- let(:series) { 0 }
-
- subject(:message) { described_class.new(group: group, user: user, series: series) }
-
- describe 'public methods' do
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to eq 'Create a custom CI runner with just a few clicks'
- expect(message.tagline).to be_nil
- expect(message.title).to eq 'Spin up an autoscaling runner in GitLab'
- expect(message.subtitle).to eq 'Use our AWS cloudformation template to spin up your runners in just a few clicks!'
- expect(message.body_line1).to be_empty
- expect(message.body_line2).to be_empty
- expect(message.cta_text).to eq 'Create a custom runner'
- expect(message.logo_path).to eq 'mailers/in_product_marketing/admin_verify-0.png'
- end
-
- describe '#progress' do
- subject { message.progress }
-
- before do
- allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
- end
-
- context 'on gitlab.com' do
- let(:is_gitlab_com) { true }
-
- it { is_expected.to eq('This is email 1 of 1 in the Admin series.') }
- end
-
- context 'not on gitlab.com' do
- let(:is_gitlab_com) { false }
-
- it { is_expected.to include('This is email 1 of 1 in the Admin series', Gitlab::Routing.url_helpers.profile_notifications_url) }
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb
deleted file mode 100644
index ab6b1cd6171..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb
+++ /dev/null
@@ -1,108 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing::Base do
- let_it_be(:group) { build(:group) }
- let_it_be(:user) { build(:user) }
-
- let(:series) { 0 }
- let(:test_class) { Gitlab::Email::Message::InProductMarketing::Create }
-
- describe 'initialize' do
- subject { test_class.new(group: group, user: user, series: series) }
-
- context 'when series does not exist' do
- let(:series) { 3 }
-
- it 'raises error' do
- expect { subject }.to raise_error(ArgumentError)
- end
- end
-
- context 'when series exists' do
- let(:series) { 0 }
-
- it 'does not raise error' do
- expect { subject }.not_to raise_error
- end
- end
- end
-
- describe '#logo_path' do
- subject { test_class.new(group: group, user: user, series: series).logo_path }
-
- it { is_expected.to eq('mailers/in_product_marketing/create-0.png') }
- end
-
- describe '#unsubscribe' do
- subject { test_class.new(group: group, user: user, series: series).unsubscribe }
-
- before do
- allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
- end
-
- context 'on gitlab.com' do
- let(:is_gitlab_com) { true }
-
- it { is_expected.to include('%tag_unsubscribe_url%') }
- end
-
- context 'not on gitlab.com' do
- let(:is_gitlab_com) { false }
-
- it { is_expected.to include(Gitlab::Routing.url_helpers.profile_notifications_url) }
- end
- end
-
- describe '#cta_link' do
- subject(:cta_link) { test_class.new(group: group, user: user, series: series).cta_link }
-
- it 'renders link' do
- expect(CGI.unescapeHTML(cta_link)).to include(Gitlab::Routing.url_helpers.group_email_campaigns_url(group, track: :create, series: series))
- end
- end
-
- describe '#progress' do
- subject { test_class.new(group: group, user: user, series: series).progress }
-
- before do
- allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
- end
-
- context 'on gitlab.com' do
- let(:is_gitlab_com) { true }
-
- it { is_expected.to include('This is email 1 of 3 in the Create series') }
- end
-
- context 'not on gitlab.com' do
- let(:is_gitlab_com) { false }
-
- it { is_expected.to include('This is email 1 of 3 in the Create series', Gitlab::Routing.url_helpers.profile_notifications_url) }
- end
- end
-
- describe '#series?' do
- using RSpec::Parameterized::TableSyntax
-
- subject do
- test_class = "Gitlab::Email::Message::InProductMarketing::#{track.to_s.classify}".constantize
- test_class.new(group: group, user: user, series: series).series?
- end
-
- where(:track, :result) do
- :create | true
- :team_short | true
- :trial_short | true
- :admin_verify | true
- :verify | true
- :trial | true
- :team | true
- end
-
- with_them do
- it { is_expected.to eq result }
- end
- end
-end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb
deleted file mode 100644
index d5aec280ea6..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing::Create do
- using RSpec::Parameterized::TableSyntax
-
- let_it_be(:group) { build(:group) }
- let_it_be(:user) { build(:user) }
-
- subject(:message) { described_class.new(group: group, user: user, series: series) }
-
- describe "public methods" do
- where(series: [0, 1, 2])
-
- with_them do
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to be_present
- expect(message.tagline).to be_present
- expect(message.title).to be_present
- expect(message.subtitle).to be_present
- expect(message.body_line1).to be_present
- expect(message.body_line2).to be_present
- expect(message.cta_text).to be_present
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/team_short_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/team_short_spec.rb
deleted file mode 100644
index 3ac2076bf35..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing/team_short_spec.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing::TeamShort do
- using RSpec::Parameterized::TableSyntax
-
- let_it_be(:group) { build(:group) }
- let_it_be(:user) { build(:user) }
-
- let(:series) { 0 }
-
- subject(:message) { described_class.new(group: group, user: user, series: series) }
-
- describe 'public methods' do
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to eq 'Team up in GitLab for greater efficiency'
- expect(message.tagline).to be_nil
- expect(message.title).to eq 'Turn coworkers into collaborators'
- expect(message.subtitle).to eq 'Invite your team today to build better code (and processes) together'
- expect(message.body_line1).to be_empty
- expect(message.body_line2).to be_empty
- expect(message.cta_text).to eq 'Invite your colleagues today'
- expect(message.logo_path).to eq 'mailers/in_product_marketing/team-0.png'
- end
-
- describe '#progress' do
- subject { message.progress }
-
- before do
- allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
- end
-
- context 'on gitlab.com' do
- let(:is_gitlab_com) { true }
-
- it { is_expected.to include('This is email 1 of 4 in the Team series') }
- end
-
- context 'not on gitlab.com' do
- let(:is_gitlab_com) { false }
-
- it { is_expected.to include('This is email 1 of 4 in the Team series', Gitlab::Routing.url_helpers.profile_notifications_url) }
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb
deleted file mode 100644
index 3354b2ed5cf..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing::Team do
- using RSpec::Parameterized::TableSyntax
-
- let_it_be(:group) { build(:group) }
- let_it_be(:user) { build(:user) }
-
- subject(:message) { described_class.new(group: group, user: user, series: series) }
-
- describe "public methods" do
- where(series: [0, 1])
-
- with_them do
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to be_present
- expect(message.tagline).to be_present
- expect(message.title).to be_present
- expect(message.subtitle).to be_present
- expect(message.body_line1).to be_present
- expect(message.body_line2).to be_present
- expect(message.cta_text).to be_present
- end
-
- describe '#progress' do
- subject { message.progress }
-
- before do
- allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
- end
-
- context 'on gitlab.com' do
- let(:is_gitlab_com) { true }
-
- it { is_expected.to include("This is email #{series + 2} of 4 in the Team series") }
- end
-
- context 'not on gitlab.com' do
- let(:is_gitlab_com) { false }
-
- it { is_expected.to include("This is email #{series + 2} of 4 in the Team series", Gitlab::Routing.url_helpers.profile_notifications_url) }
- end
- end
- end
-
- context 'with series 2' do
- let(:series) { 2 }
-
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to be_present
- expect(message.tagline).to be_nil
- expect(message.title).to be_present
- expect(message.subtitle).to be_present
- expect(message.body_line1).to be_present
- expect(message.body_line2).to be_present
- expect(message.cta_text).to be_present
- end
-
- describe '#progress' do
- subject { message.progress }
-
- before do
- allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
- end
-
- context 'on gitlab.com' do
- let(:is_gitlab_com) { true }
-
- it { is_expected.to include('This is email 4 of 4 in the Team series') }
- end
-
- context 'not on gitlab.com' do
- let(:is_gitlab_com) { false }
-
- it { is_expected.to include('This is email 4 of 4 in the Team series', Gitlab::Routing.url_helpers.profile_notifications_url) }
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/trial_short_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/trial_short_spec.rb
deleted file mode 100644
index cf0a119ea80..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing/trial_short_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing::TrialShort do
- let_it_be(:group) { build(:group) }
- let_it_be(:user) { build(:user) }
-
- let(:series) { 0 }
-
- subject(:message) { described_class.new(group: group, user: user, series: series) }
-
- describe 'public methods' do
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to eq 'Be a DevOps hero'
- expect(message.tagline).to be_nil
- expect(message.title).to eq 'Expand your DevOps journey with a free GitLab trial'
- expect(message.subtitle).to eq 'Start your trial today to experience single application success and discover all the features of GitLab Ultimate for free!'
- expect(message.body_line1).to be_empty
- expect(message.body_line2).to be_empty
- expect(message.cta_text).to eq 'Start a trial'
- expect(message.logo_path).to eq 'mailers/in_product_marketing/trial-0.png'
- end
-
- describe '#progress' do
- subject { message.progress }
-
- before do
- allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
- end
-
- context 'on gitlab.com' do
- let(:is_gitlab_com) { true }
-
- it { is_expected.to eq('This is email 1 of 4 in the Trial series.') }
- end
-
- context 'not on gitlab.com' do
- let(:is_gitlab_com) { false }
-
- it { is_expected.to include('This is email 1 of 4 in the Trial series', Gitlab::Routing.url_helpers.profile_notifications_url) }
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb
deleted file mode 100644
index 7f86c9a6c6f..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing::Trial do
- using RSpec::Parameterized::TableSyntax
-
- let_it_be(:group) { build(:group) }
- let_it_be(:user) { build(:user) }
-
- subject(:message) { described_class.new(group: group, user: user, series: series) }
-
- describe "public methods" do
- where(series: [0, 1, 2])
-
- with_them do
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to be_present
- expect(message.tagline).to be_present
- expect(message.title).to be_present
- expect(message.subtitle).to be_present
- expect(message.body_line1).to be_present
- expect(message.body_line2).to be_present
- expect(message.cta_text).to be_present
- end
-
- describe '#progress' do
- subject { message.progress }
-
- before do
- allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
- end
-
- context 'on gitlab.com' do
- let(:is_gitlab_com) { true }
-
- it { is_expected.to eq("This is email #{series + 2} of 4 in the Trial series.") }
- end
-
- context 'not on gitlab.com' do
- let(:is_gitlab_com) { false }
-
- it { is_expected.to include("This is email #{series + 2} of 4 in the Trial series", Gitlab::Routing.url_helpers.profile_notifications_url) }
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb
deleted file mode 100644
index 7e6f62289d2..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing::Verify do
- let_it_be(:group) { build(:group) }
- let_it_be(:user) { build(:user) }
-
- subject(:message) { described_class.new(group: group, user: user, series: series) }
-
- describe "public methods" do
- context 'with series 0' do
- let(:series) { 0 }
-
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to be_present
- expect(message.tagline).to be_present
- expect(message.title).to be_present
- expect(message.subtitle).to be_present
- expect(message.body_line1).to be_present
- expect(message.body_line2).to be_nil
- expect(message.cta_text).to be_present
- end
- end
-
- context 'with series 1' do
- let(:series) { 1 }
-
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to be_present
- expect(message.tagline).to be_present
- expect(message.title).to be_present
- expect(message.subtitle).to be_present
- expect(message.body_line1).to be_present
- expect(message.body_line2).to be_present
- expect(message.cta_text).to be_present
- end
- end
-
- context 'with series 2' do
- let(:series) { 2 }
-
- it 'returns value for series', :aggregate_failures do
- expect(message.subject_line).to be_present
- expect(message.tagline).to be_present
- expect(message.title).to be_present
- expect(message.subtitle).to be_present
- expect(message.body_line1).to be_present
- expect(message.body_line2).to be_nil
- expect(message.cta_text).to be_present
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing_spec.rb
deleted file mode 100644
index 1c59d9c8208..00000000000
--- a/spec/lib/gitlab/email/message/in_product_marketing_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Email::Message::InProductMarketing do
- describe '.for' do
- using RSpec::Parameterized::TableSyntax
-
- subject { described_class.for(track) }
-
- context 'when track exists' do
- where(:track, :expected_class) do
- :create | described_class::Create
- :team_short | described_class::TeamShort
- :trial_short | described_class::TrialShort
- :admin_verify | described_class::AdminVerify
- :verify | described_class::Verify
- :trial | described_class::Trial
- :team | described_class::Team
- end
-
- with_them do
- it { is_expected.to eq(expected_class) }
- end
- end
-
- context 'when track does not exist' do
- let(:track) { :non_existent }
-
- it 'raises error' do
- expect { subject }.to raise_error(described_class::UnknownTrackError)
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/email/service_desk/custom_email_spec.rb b/spec/lib/gitlab/email/service_desk/custom_email_spec.rb
new file mode 100644
index 00000000000..bba1ca1c8be
--- /dev/null
+++ b/spec/lib/gitlab/email/service_desk/custom_email_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Email::ServiceDesk::CustomEmail, feature_category: :service_desk do
+ let(:reply_key) { 'b7721fc7e8419911a8bea145236a0519' }
+ let(:custom_email) { 'support@example.com' }
+ let(:email_with_reply_key) { 'support+b7721fc7e8419911a8bea145236a0519@example.com' }
+
+ describe '.reply_address' do
+ let_it_be(:project) { create(:project) }
+
+ subject(:reply_address) { described_class.reply_address(nil, nil) }
+
+ it { is_expected.to be nil }
+
+ context 'with reply key' do
+ subject(:reply_address) { described_class.reply_address(nil, reply_key) }
+
+ it { is_expected.to be nil }
+
+ context 'with issue' do
+ let_it_be(:issue) { create(:issue, project: project) }
+
+ subject(:reply_address) { described_class.reply_address(issue, reply_key) }
+
+ it { is_expected.to be nil }
+
+ context 'with service_desk_setting and custom email' do
+ let!(:service_desk_setting) { create(:service_desk_setting, custom_email: custom_email, project: project) }
+
+ it { is_expected.to eq(email_with_reply_key) }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb
index d25511843ff..8df4a9fa84a 100644
--- a/spec/lib/gitlab/etag_caching/middleware_spec.rb
+++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state
let(:middleware) { described_class.new(app) }
let(:app_status_code) { 200 }
let(:if_none_match) { nil }
- let(:enabled_path) { '/gitlab-org/gitlab-foss/noteable/issue/1/notes' }
- let(:endpoint) { 'issue_notes' }
+ let(:enabled_path) { '/gitlab-org/gitlab-foss/commit/aaaaaaaa/pipelines.json' }
+ let(:endpoint) { 'commit_pipelines' }
describe '.skip!' do
it 'sets the skip header on the response' do
@@ -124,12 +124,12 @@ RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state
method: 'GET',
path: enabled_path,
status: status_code,
- request_urgency: :medium,
- target_duration_s: 0.5,
+ request_urgency: :low,
+ target_duration_s: 5,
metadata: a_hash_including(
{
- 'meta.caller_id' => 'Projects::NotesController#index',
- 'meta.feature_category' => 'team_planning'
+ 'meta.caller_id' => 'Projects::CommitController#pipelines',
+ 'meta.feature_category' => 'source_code_management'
}
)
}
@@ -185,8 +185,8 @@ RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state
it "pushes expected information in to the context" do
expect(Gitlab::ApplicationContext).to receive(:push).with(
- feature_category: 'team_planning',
- caller_id: 'Projects::NotesController#index',
+ feature_category: 'source_code_management',
+ caller_id: 'Projects::CommitController#pipelines',
remote_ip: '127.0.0.1'
)
diff --git a/spec/lib/gitlab/etag_caching/router/rails_spec.rb b/spec/lib/gitlab/etag_caching/router/rails_spec.rb
index 251f634aac1..de260f43dfb 100644
--- a/spec/lib/gitlab/etag_caching/router/rails_spec.rb
+++ b/spec/lib/gitlab/etag_caching/router/rails_spec.rb
@@ -3,20 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::EtagCaching::Router::Rails do
- it 'matches issue notes endpoint' do
- result = match_route('/my-group/and-subgroup/here-comes-the-project/noteable/issue/1/notes')
-
- expect(result).to be_present
- expect(result.name).to eq 'issue_notes'
- end
-
- it 'matches MR notes endpoint' do
- result = match_route('/my-group/and-subgroup/here-comes-the-project/noteable/merge_request/1/notes')
-
- expect(result).to be_present
- expect(result.name).to eq 'merge_request_notes'
- end
-
it 'matches issue title endpoint' do
result = match_route('/my-group/my-project/-/issues/123/realtime_changes')
diff --git a/spec/lib/gitlab/etag_caching/store_spec.rb b/spec/lib/gitlab/etag_caching/store_spec.rb
index 6188a3fc8b3..117480f2a99 100644
--- a/spec/lib/gitlab/etag_caching/store_spec.rb
+++ b/spec/lib/gitlab/etag_caching/store_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::EtagCaching::Store, :clean_gitlab_redis_shared_state do
+RSpec.describe Gitlab::EtagCaching::Store, :clean_gitlab_redis_cache do
let(:store) { described_class.new }
describe '#get' do
diff --git a/spec/lib/gitlab/event_store/store_spec.rb b/spec/lib/gitlab/event_store/store_spec.rb
index bbdfecc897a..04d0706c130 100644
--- a/spec/lib/gitlab/event_store/store_spec.rb
+++ b/spec/lib/gitlab/event_store/store_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::EventStore::Store do
+RSpec.describe Gitlab::EventStore::Store, feature_category: :shared do
let(:event_klass) { stub_const('TestEvent', Class.new(Gitlab::EventStore::Event)) }
let(:event) { event_klass.new(data: data) }
let(:another_event_klass) { stub_const('TestAnotherEvent', Class.new(Gitlab::EventStore::Event)) }
@@ -222,8 +222,6 @@ RSpec.describe Gitlab::EventStore::Store do
end
end
- let(:event) { event_klass.new(data: data) }
-
it 'dispatches the event to the workers satisfying the condition' do
expect(worker).to receive(:perform_async).with('TestEvent', serialized_data)
expect(another_worker).not_to receive(:perform_async)
@@ -232,6 +230,20 @@ RSpec.describe Gitlab::EventStore::Store do
end
end
+ context 'when subscription has delayed dispatching of event' do
+ let(:store) do
+ described_class.new do |s|
+ s.subscribe worker, to: event_klass, delay: 1.minute
+ end
+ end
+
+ it 'dispatches the event to the worker after some time' do
+ expect(worker).to receive(:perform_in).with(1.minute, 'TestEvent', serialized_data)
+
+ store.publish(event)
+ end
+ end
+
context 'when the event does not have any subscribers' do
let(:store) do
described_class.new do |s|
@@ -239,8 +251,6 @@ RSpec.describe Gitlab::EventStore::Store do
end
end
- let(:event) { event_klass.new(data: data) }
-
it 'returns successfully' do
expect { store.publish(event) }.not_to raise_error
end
diff --git a/spec/lib/gitlab/experiment/rollout/feature_spec.rb b/spec/lib/gitlab/experiment/rollout/feature_spec.rb
index a66f4fea207..cd46e7b3386 100644
--- a/spec/lib/gitlab/experiment/rollout/feature_spec.rb
+++ b/spec/lib/gitlab/experiment/rollout/feature_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Experiment::Rollout::Feature, :experiment do
- subject { described_class.new.for(subject_experiment) }
+ subject { described_class.new(subject_experiment) }
let(:subject_experiment) { experiment('namespaced/stub') }
diff --git a/spec/lib/gitlab/git/blame_spec.rb b/spec/lib/gitlab/git/blame_spec.rb
index d21ac36bf34..77361b09857 100644
--- a/spec/lib/gitlab/git/blame_spec.rb
+++ b/spec/lib/gitlab/git/blame_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Gitlab::Git::Blame do
+RSpec.describe Gitlab::Git::Blame, feature_category: :source_code_management do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository.raw }
let(:sha) { TestEnv::BRANCH_SHA['master'] }
@@ -38,6 +38,14 @@ RSpec.describe Gitlab::Git::Blame do
expect(result.size).to eq(range.size)
expect(result.map { |r| r[:line] }).to eq(['', 'This guide details how contribute to GitLab.', ''])
end
+
+ context 'when range is outside of the file content range' do
+ let(:range) { 9999..10000 }
+
+ it 'returns an empty array' do
+ expect(result).to eq([])
+ end
+ end
end
context "ISO-8859 encoding" do
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index 6745c700b92..4d78e194da8 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -131,6 +131,31 @@ EOT
expect(diff.diff).to be_utf8
end
end
+
+ context 'using a diff that it too large but collecting all paths' do
+ let(:gitaly_diff) do
+ Gitlab::GitalyClient::Diff.new(
+ from_path: '.gitmodules',
+ to_path: '.gitmodules',
+ old_mode: 0100644,
+ new_mode: 0100644,
+ from_id: '0792c58905eff3432b721f8c4a64363d8e28d9ae',
+ to_id: 'efd587ccb47caf5f31fc954edb21f0a713d9ecc3',
+ overflow_marker: true,
+ collapsed: false,
+ too_large: false,
+ patch: ''
+ )
+ end
+
+ let(:diff) { described_class.new(gitaly_diff) }
+
+ it 'is already pruned and collapsed but not too large' do
+ expect(diff.diff).to be_empty
+ expect(diff).not_to be_too_large
+ expect(diff).to be_collapsed
+ end
+ end
end
context 'using a Gitaly::CommitDelta' do
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index e27b97ea0e6..18a090a00be 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -589,6 +589,37 @@ RSpec.describe Gitlab::Git::Repository, feature_category: :source_code_managemen
end
end
+ describe '#update_refs' do
+ let(:repository) { mutable_repository }
+ let(:sha) { TestEnv::BRANCH_SHA['master'] }
+ let(:tmp_ref) { "refs/tmp/#{SecureRandom.hex}" }
+
+ before do
+ repository.write_ref(tmp_ref, sha)
+ end
+
+ it 'updates the ref' do
+ expect do
+ repository.update_refs(
+ [
+ {
+ old_sha: sha,
+ new_sha: Gitlab::Git::BLANK_SHA,
+ reference: tmp_ref
+ }
+ ]
+ )
+ end.to change { repository.ref_exists?(tmp_ref) }
+ .from(true).to(false)
+ end
+
+ it 'does not call gitaly when no refs given' do
+ expect_any_instance_of(Gitlab::GitalyClient::RefService).not_to receive(:update_refs)
+
+ repository.update_refs([])
+ end
+ end
+
describe '#delete_refs' do
let(:repository) { mutable_repository }
diff --git a/spec/lib/gitlab/git_access_snippet_spec.rb b/spec/lib/gitlab/git_access_snippet_spec.rb
index 9ba021e838e..7916481a853 100644
--- a/spec/lib/gitlab/git_access_snippet_spec.rb
+++ b/spec/lib/gitlab/git_access_snippet_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Gitlab::GitAccessSnippet do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:snippet) { create(:project_snippet, :public, :repository, project: project) }
- let_it_be(:migration_bot) { User.migration_bot }
+ let_it_be(:migration_bot) { Users::Internal.migration_bot }
let(:repository) { snippet.repository }
let(:actor) { user }
diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
index 9055b284119..bd0341d51bf 100644
--- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
@@ -567,20 +567,58 @@ RSpec.describe Gitlab::GitalyClient::OperationService, feature_category: :source
end
end
- describe '#user_cherry_pick' do
+ describe '#user_cherry_pick', :freeze_time do
let(:response_class) { Gitaly::UserCherryPickResponse }
+ let(:sha) { '54cec5282aa9f21856362fe321c800c236a61615' }
+ let(:branch_name) { 'master' }
+ let(:cherry_pick_message) { 'Cherry-pick message' }
+ let(:time) { Time.now.utc }
+
+ let(:branch_update) do
+ Gitaly::OperationBranchUpdate.new(
+ commit_id: sha,
+ repo_created: false,
+ branch_created: false
+ )
+ end
+
+ let(:request) do
+ Gitaly::UserCherryPickRequest.new(
+ repository: repository.gitaly_repository,
+ user: gitaly_user,
+ commit: repository.commit.to_gitaly_commit,
+ branch_name: branch_name,
+ start_branch_name: branch_name,
+ start_repository: repository.gitaly_repository,
+ message: cherry_pick_message,
+ timestamp: Google::Protobuf::Timestamp.new(seconds: time.to_i)
+ )
+ end
+
+ let(:response) { Gitaly::UserCherryPickResponse.new(branch_update: branch_update) }
subject do
client.user_cherry_pick(
user: user,
commit: repository.commit,
- branch_name: 'master',
- message: 'Cherry-pick message',
- start_branch_name: 'master',
+ branch_name: branch_name,
+ message: cherry_pick_message,
+ start_branch_name: branch_name,
start_repository: repository
)
end
+ it 'sends a user_cherry_pick message and returns a BranchUpdate' do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_cherry_pick).with(request, kind_of(Hash))
+ .and_return(response)
+
+ expect(subject).to be_a(Gitlab::Git::OperationService::BranchUpdate)
+ expect(subject.newrev).to be_present
+ expect(subject.repo_created).to be(false)
+ expect(subject.branch_created).to be(false)
+ end
+
context 'when AccessCheckError is raised' do
let(:raised_error) do
new_detailed_error(
@@ -641,27 +679,68 @@ RSpec.describe Gitlab::GitalyClient::OperationService, feature_category: :source
end
end
- describe '#user_revert' do
- let(:response_class) { Gitaly::UserRevertResponse }
+ describe '#user_revert', :freeze_time do
+ let(:sha) { '54cec5282aa9f21856362fe321c800c236a61615' }
+ let(:branch_name) { 'master' }
+ let(:revert_message) { 'revert message' }
+ let(:time) { Time.now.utc }
+
+ let(:branch_update) do
+ Gitaly::OperationBranchUpdate.new(
+ commit_id: sha,
+ repo_created: false,
+ branch_created: false
+ )
+ end
+
+ let(:request) do
+ Gitaly::UserRevertRequest.new(
+ repository: repository.gitaly_repository,
+ user: gitaly_user,
+ commit: repository.commit.to_gitaly_commit,
+ branch_name: branch_name,
+ start_branch_name: branch_name,
+ start_repository: repository.gitaly_repository,
+ message: revert_message,
+ timestamp: Google::Protobuf::Timestamp.new(seconds: time.to_i)
+ )
+ end
+
+ let(:response) { Gitaly::UserRevertResponse.new(branch_update: branch_update) }
subject do
client.user_revert(
user: user,
commit: repository.commit,
- branch_name: 'master',
- message: 'Revert message',
- start_branch_name: 'master',
+ branch_name: branch_name,
+ message: revert_message,
+ start_branch_name: branch_name,
start_repository: repository
)
end
- before do
+ it 'sends a user_revert message and returns a BranchUpdate' do
expect_any_instance_of(Gitaly::OperationService::Stub)
- .to receive(:user_revert).with(kind_of(Gitaly::UserRevertRequest), kind_of(Hash))
- .and_return(response)
+ .to receive(:user_revert).with(request, kind_of(Hash))
+ .and_return(response)
+
+ expect(subject).to be_a(Gitlab::Git::OperationService::BranchUpdate)
+ expect(subject.newrev).to be_present
+ expect(subject.repo_created).to be(false)
+ expect(subject.branch_created).to be(false)
end
- it_behaves_like 'cherry pick and revert errors'
+ context 'when errors are raised' do
+ let(:response_class) { Gitaly::UserRevertResponse }
+
+ before do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_revert).with(kind_of(Gitaly::UserRevertRequest), kind_of(Hash))
+ .and_return(response)
+ end
+
+ it_behaves_like 'cherry pick and revert errors'
+ end
end
describe '#rebase' do
diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
index fe04ad36e9a..ae9276cf90b 100644
--- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
@@ -314,6 +314,116 @@ RSpec.describe Gitlab::GitalyClient::RefService, feature_category: :gitaly do
end
end
+ describe '#update_refs' do
+ let(:old_sha) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' }
+ let(:new_sha) { Gitlab::Git::EMPTY_TREE_ID }
+ let(:reference) { 'refs/does/not/exist' }
+ let(:expected_param) do
+ Gitaly::UpdateReferencesRequest::Update.new(
+ old_object_id: old_sha,
+ new_object_id: new_sha,
+ reference: reference
+ )
+ end
+
+ let(:ref_list) do
+ [
+ {
+ old_sha: old_sha,
+ new_sha: new_sha,
+ reference: reference
+ }
+ ]
+ end
+
+ subject(:update_refs) { client.update_refs(ref_list: ref_list) }
+
+ it 'sends a update_refs message' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:update_references)
+ .with(array_including(gitaly_request_with_params(updates: [expected_param])), kind_of(Hash))
+ .and_return(double('update_refs_response', git_error: ""))
+
+ update_refs
+ end
+
+ context 'with a generic BadStatus error' do
+ let(:generic_error) do
+ GRPC::BadStatus.new(
+ GRPC::Core::StatusCodes::FAILED_PRECONDITION,
+ "error message"
+ )
+ end
+
+ it 'raises the BadStatus error' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:update_references)
+ .with(array_including(gitaly_request_with_params(updates: [expected_param])), kind_of(Hash))
+ .and_raise(generic_error)
+
+ expect { update_refs }.to raise_error(GRPC::BadStatus)
+ end
+ end
+
+ context 'with a reference state mismatch error' do
+ let(:reference_state_mismatch_error) do
+ new_detailed_error(
+ GRPC::Core::StatusCodes::FAILED_PRECONDITION,
+ "error message",
+ Gitaly::UpdateReferencesError.new(reference_state_mismatch: Gitaly::ReferenceStateMismatchError.new))
+ end
+
+ it 'raises ReferencesLockedError' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:update_references)
+ .with(array_including(gitaly_request_with_params(updates: [expected_param])), kind_of(Hash))
+ .and_raise(reference_state_mismatch_error)
+
+ expect { update_refs }.to raise_error(Gitlab::Git::ReferenceStateMismatchError)
+ end
+ end
+
+ context 'with a references locked error' do
+ let(:references_locked_error) do
+ new_detailed_error(
+ GRPC::Core::StatusCodes::FAILED_PRECONDITION,
+ "error message",
+ Gitaly::UpdateReferencesError.new(references_locked: Gitaly::ReferencesLockedError.new))
+ end
+
+ it 'raises ReferencesLockedError' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:update_references)
+ .with(array_including(gitaly_request_with_params(updates: [expected_param])), kind_of(Hash))
+ .and_raise(references_locked_error)
+
+ expect { update_refs }.to raise_error(Gitlab::Git::ReferencesLockedError)
+ end
+ end
+
+ context 'with a invalid format error' do
+ let(:invalid_refs) { ['\invali.\d/1', '\.invali/d/2'] }
+ let(:invalid_reference_format_error) do
+ new_detailed_error(
+ GRPC::Core::StatusCodes::INVALID_ARGUMENT,
+ "error message",
+ Gitaly::UpdateReferencesError.new(invalid_format: Gitaly::InvalidRefFormatError.new(refs: invalid_refs)))
+ end
+
+ it 'raises InvalidRefFormatError' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:update_references)
+ .with(array_including(gitaly_request_with_params(updates: [expected_param])), kind_of(Hash))
+ .and_raise(invalid_reference_format_error)
+
+ expect { update_refs }.to raise_error do |error|
+ expect(error).to be_a(Gitlab::Git::InvalidRefFormatError)
+ expect(error.message).to eq("references have an invalid format: #{invalid_refs.join(",")}")
+ end
+ end
+ end
+ end
+
describe '#delete_refs' do
let(:prefixes) { %w(refs/heads refs/keep-around) }
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
index d8ae7d70bb2..8e0e4525729 100644
--- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -319,19 +319,8 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService, feature_category: :gital
end
end
- describe '#create_from_snapshot' do
- it 'sends a create_repository_from_snapshot message' do
- expect_any_instance_of(Gitaly::RepositoryService::Stub)
- .to receive(:create_repository_from_snapshot)
- .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
- .and_return(double)
-
- client.create_from_snapshot('http://example.com?wiki=1', 'Custom xyz')
- end
- end
-
describe '#raw_changes_between' do
- it 'sends a create_repository_from_snapshot message' do
+ it 'sends a get_raw_changes message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:get_raw_changes)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
diff --git a/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb b/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb
index 42153a9a3d8..49b4f90cdf9 100644
--- a/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb
@@ -10,6 +10,8 @@ RSpec.describe Gitlab::GitalyClient::WithFeatureFlagActors do
end.new
end
+ let_it_be(:group) { create(:group) }
+
describe '#user_actor' do
context 'when user is not available in ApplicationContext' do
it 'returns nil' do
@@ -40,7 +42,7 @@ RSpec.describe Gitlab::GitalyClient::WithFeatureFlagActors do
describe '#repository, #project_actor, #group_actor' do
context 'when normal project repository' do
- let_it_be(:project) { create(:project, group: create(:group)) }
+ let_it_be(:project) { create(:project, group: group) }
let(:expected_project) { project }
let(:expected_group) { Feature::Gitaly::ActorWrapper.new(::Group, project.group.id) }
@@ -58,7 +60,7 @@ RSpec.describe Gitlab::GitalyClient::WithFeatureFlagActors do
end
context 'when project wiki repository' do
- let_it_be(:project) { create(:project, :wiki_repo, group: create(:group)) }
+ let_it_be(:project) { create(:project, :wiki_repo, group: group) }
let(:expected_project) { nil }
let(:expected_group) { nil }
@@ -112,7 +114,7 @@ RSpec.describe Gitlab::GitalyClient::WithFeatureFlagActors do
end
context 'when project snippet' do
- let_it_be(:project) { create(:project, group: create(:group)) }
+ let_it_be(:project) { create(:project, group: group) }
let(:snippet) { create(:project_snippet, project: project) }
let(:expected_project) { nil }
let(:expected_group) { nil }
@@ -131,23 +133,20 @@ RSpec.describe Gitlab::GitalyClient::WithFeatureFlagActors do
end
context 'when project design' do
- let_it_be(:design_repo) do
- create(:design_management_repository, project: create(:project, group: create(:group)))
- end
-
- let(:expected_project) { design_repo.project }
- let(:expected_group) { design_repo.project.group }
+ let_it_be(:project) { create(:project_with_design, group: group) }
+ let(:expected_project) { project }
+ let(:expected_group) { group }
it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
- let(:repository) { design_repo.repository }
+ let(:repository) { project.design_repository }
end
it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
- let(:repository) { design_repo.repository.raw }
+ let(:repository) { project.design_repository.raw }
end
it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
- let(:repository) { raw_repo_without_container(design_repo.repository) }
+ let(:repository) { raw_repo_without_container(project.design_repository) }
end
end
end
diff --git a/spec/lib/gitlab/github_import/attachments_downloader_spec.rb b/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
index 086aa4be17e..72d8a9c0403 100644
--- a/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
+++ b/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
@@ -93,6 +93,57 @@ RSpec.describe Gitlab::GithubImport::AttachmentsDownloader, feature_category: :i
expect(File.basename(file)).to eq('av.png')
end
end
+
+ context 'when attachment is behind a redirect' do
+ let_it_be(:file_url) { "https://github.com/test/project/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11" }
+ let(:redirect_url) { "https://https://github-production-user-asset-6210df.s3.amazonaws.com/142635249/740edb05293e.jpg" }
+ let(:sample_response) do
+ instance_double(HTTParty::Response, redirection?: true, headers: { location: redirect_url })
+ end
+
+ it 'gets redirection url' do
+ expect(Gitlab::HTTP).to receive(:perform_request)
+ .with(Net::HTTP::Get, file_url, { follow_redirects: false })
+ .and_return sample_response
+
+ expect(Gitlab::HTTP).to receive(:perform_request)
+ .with(Net::HTTP::Get, redirect_url, stream_body: true).and_yield(chunk_double)
+
+ file = downloader.perform
+
+ expect(File.exist?(file.path)).to eq(true)
+ end
+
+ context 'when url is not a redirection' do
+ let(:sample_response) do
+ instance_double(HTTParty::Response, code: 200, redirection?: false)
+ end
+
+ before do
+ allow(Gitlab::HTTP).to receive(:perform_request)
+ .with(Net::HTTP::Get, file_url, { follow_redirects: false })
+ .and_return sample_response
+ end
+
+ it 'raises upon unsuccessful redirection' do
+ expect { downloader.perform }.to raise_error("expected a redirect response, got #{sample_response.code}")
+ end
+ end
+
+ context 'when redirection url is not supported' do
+ let(:redirect_url) { "https://https://github-production-user-asset-6210df.s3.amazonaws.com/142635249/740edb05293e.idk" }
+
+ before do
+ allow(Gitlab::HTTP).to receive(:perform_request)
+ .with(Net::HTTP::Get, file_url, { follow_redirects: false })
+ .and_return sample_response
+ end
+
+ it 'raises UnsupportedAttachmentError on unsupported extension' do
+ expect { downloader.perform }.to raise_error(described_class::UnsupportedAttachmentError)
+ end
+ end
+ end
end
describe '#delete' do
diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb
index c9f7fd4f748..4b0d61e3188 100644
--- a/spec/lib/gitlab/github_import/client_spec.rb
+++ b/spec/lib/gitlab/github_import/client_spec.rb
@@ -20,11 +20,29 @@ RSpec.describe Gitlab::GithubImport::Client, feature_category: :importers do
end
describe '#user' do
+ let(:status_code) { 200 }
+ let(:body) { { id: 1 } }
+ let(:headers) { { 'Content-Type' => 'application/json' } }
+
+ before do
+ stub_request(:get, 'https://api.github.com/users/foo')
+ .to_return(status: status_code, body: body.to_json, headers: headers)
+ end
+
+ subject(:user) { client.user('foo') }
+
it 'returns the details for the given username' do
- expect(client.octokit).to receive(:user).with('foo')
expect(client).to receive(:with_rate_limit).and_yield
+ expect(user).to eq({ id: 1 })
+ end
+
+ context 'when a not modified response is returned' do
+ let(:status_code) { 304 }
- client.user('foo')
+ it 'returns nil' do
+ expect(client).to receive(:with_rate_limit).and_yield
+ expect(user).to eq(nil)
+ end
end
end
diff --git a/spec/lib/gitlab/github_import/importer/note_attachments_importer_spec.rb b/spec/lib/gitlab/github_import/importer/note_attachments_importer_spec.rb
index 450ebe9a719..b9829c09cfd 100644
--- a/spec/lib/gitlab/github_import/importer/note_attachments_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/note_attachments_importer_spec.rb
@@ -53,6 +53,19 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter, feature_
record.reload
expect(record.description).to include("[link to other project blob file](#{other_project_blob_url})")
end
+
+ context 'with new github image format' do
+ let(:image_url) { 'https://github.com/nickname/public-test-repo/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11' }
+ let(:image_tag_url) { 'https://github.com/nickname/public-test-repo/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11' }
+
+ it 'changes image attachment links' do
+ importer.execute
+
+ record.reload
+ expect(record.description).to include('![image.jpeg](/uploads/')
+ expect(record.description).to include('<img width="248" alt="tag-image" src="/uploads')
+ end
+ end
end
describe '#execute' do
@@ -60,16 +73,19 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter, feature_
let(:tmp_stub_doc) { Tempfile.create('attachment_download_test.txt') }
let(:tmp_stub_image) { Tempfile.create('image.jpeg') }
let(:tmp_stub_image_tag) { Tempfile.create('image-tag.jpeg') }
+ let(:access_token) { 'exampleGitHubToken' }
+ let(:options) { { headers: { 'Authorization' => "Bearer #{access_token}" } } }
before do
- allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(doc_url)
+ allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(doc_url, options: options)
.and_return(downloader_stub)
- allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(image_url)
+ allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(image_url, options: options)
.and_return(downloader_stub)
- allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(image_tag_url)
+ allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(image_tag_url, options: options)
.and_return(downloader_stub)
allow(downloader_stub).to receive(:perform).and_return(tmp_stub_doc, tmp_stub_image, tmp_stub_image_tag)
allow(downloader_stub).to receive(:delete).exactly(3).times
+ allow(client).to receive_message_chain(:octokit, :access_token).and_return(access_token)
end
context 'when importing release attachments' do
@@ -118,5 +134,24 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter, feature_
expect(record.note).to include("[link to other project blob file](#{other_project_blob_url})")
end
end
+
+ context "when attachment behind redirection link is unsupported file type" do
+ let(:record) { create(:issue, project: project, description: text) }
+ let(:image_url) { 'https://github.com/nickname/public-test-repo/assets/142635249/123' }
+ let(:image_tag_url) { 'https://github.com/nickname/public-test-repo/assets/142635249/123' }
+
+ before do
+ allow(downloader_stub).to receive(:perform)
+ .and_raise(Gitlab::GithubImport::AttachmentsDownloader::UnsupportedAttachmentError)
+ end
+
+ it "does not replace url" do
+ importer.execute
+
+ record.reload
+ expect(record.description).to include("![image.jpeg](#{image_url}")
+ expect(record.description).to include("<img width=\"248\" alt=\"tag-image\" src=\"#{image_tag_url}\"")
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/github_import/importer/pull_requests/merged_by_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests/merged_by_importer_spec.rb
index 25381594632..8cd96295bbd 100644
--- a/spec/lib/gitlab/github_import/importer/pull_requests/merged_by_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_requests/merged_by_importer_spec.rb
@@ -26,6 +26,10 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequests::MergedByImporter,
subject { described_class.new(pull_request, project, client_double) }
+ before do
+ allow(client_double).to receive_message_chain(:octokit, :last_response, :headers).and_return({ etag: nil })
+ end
+
shared_examples 'adds a note referencing the merger user' do
it 'adds a note referencing the merger user' do
expect { subject.execute }
diff --git a/spec/lib/gitlab/github_import/importer/pull_requests/review_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests/review_importer_spec.rb
index ba14ea603e0..6846c99fb63 100644
--- a/spec/lib/gitlab/github_import/importer/pull_requests/review_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_requests/review_importer_spec.rb
@@ -17,6 +17,10 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewImporter,
)
end
+ before do
+ allow(client_double).to receive_message_chain(:octokit, :last_response, :headers).and_return({ etag: nil })
+ end
+
subject { described_class.new(review, project, client_double) }
shared_examples 'imports a reviewer for the Merge Request' do
diff --git a/spec/lib/gitlab/github_import/markdown/attachment_spec.rb b/spec/lib/gitlab/github_import/markdown/attachment_spec.rb
index 84b0886ebcc..5b9d077aac9 100644
--- a/spec/lib/gitlab/github_import/markdown/attachment_spec.rb
+++ b/spec/lib/gitlab/github_import/markdown/attachment_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :importers do
let(:name) { FFaker::Lorem.word }
let(:url) { FFaker::Internet.uri('https') }
+ let(:import_source) { 'nickname/public-test-repo' }
describe '.from_markdown' do
context "when it's a doc attachment" do
@@ -75,6 +76,17 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :im
it { expect(described_class.from_markdown(markdown_node)).to eq nil }
end
+
+ context 'when image attachment is in the new format' do
+ let(:url) { "https://github.com/#{import_source}/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11" }
+
+ it 'returns instance with attachment info' do
+ attachment = described_class.from_markdown(markdown_node)
+
+ expect(attachment.name).to eq name
+ expect(attachment.url).to eq url
+ end
+ end
end
context "when it's an inline html node" do
@@ -103,7 +115,6 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :im
describe '#part_of_project_blob?' do
let(:attachment) { described_class.new('test', url) }
- let(:import_source) { 'nickname/public-test-repo' }
context 'when url is a part of project blob' do
let(:url) { "https://github.com/#{import_source}/blob/main/example.md" }
@@ -120,7 +131,6 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :im
describe '#doc_belongs_to_project?' do
let(:attachment) { described_class.new('test', url) }
- let(:import_source) { 'nickname/public-test-repo' }
context 'when url relates to this project' do
let(:url) { "https://github.com/#{import_source}/files/9020437/git-cheat-sheet.txt" }
@@ -147,13 +157,19 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :im
context 'when it is a media link' do
let(:url) { 'https://user-images.githubusercontent.com/6833842/0cf366b61ef2.jpeg' }
- it { expect(attachment.media?).to eq true }
+ it { expect(attachment.media?(import_source)).to eq true }
+
+ context 'when it is a new media link' do
+ let(:url) { "https://github.com/#{import_source}/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11" }
+
+ it { expect(attachment.media?(import_source)).to eq true }
+ end
end
context 'when it is not a media link' do
let(:url) { 'https://github.com/nickname/public-test-repo/files/9020437/git-cheat-sheet.txt' }
- it { expect(attachment.media?).to eq false }
+ it { expect(attachment.media?(import_source)).to eq false }
end
end
diff --git a/spec/lib/gitlab/github_import/object_counter_spec.rb b/spec/lib/gitlab/github_import/object_counter_spec.rb
index 92a979eddd2..e41a2cff989 100644
--- a/spec/lib/gitlab/github_import/object_counter_spec.rb
+++ b/spec/lib/gitlab/github_import/object_counter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache do
+RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache, feature_category: :importers do
let_it_be(:project) { create(:project, :import_started, import_type: 'github', import_url: 'https://github.com/vim/vim.git') }
it 'validates the operation being incremented' do
@@ -38,9 +38,6 @@ RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache do
expect(Gitlab::Metrics)
.not_to receive(:counter)
- expect(Gitlab::Metrics)
- .not_to receive(:counter)
-
described_class.increment(project, :issue, :fetched, value: 0)
described_class.increment(project, :issue, :imported, value: nil)
@@ -73,6 +70,27 @@ RSpec.describe Gitlab::GithubImport::ObjectCounter, :clean_gitlab_redis_cache do
end
end
+ context 'when import is in progress but cache expired' do
+ before do
+ described_class.increment(project, :issue, :fetched, value: 10)
+ described_class.increment(project, :issue, :imported, value: 8)
+ allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(nil)
+ end
+
+ it 'returns 0 instead of nil so process can complete' do
+ expect(described_class.summary(project)).to eq(
+ {
+ "fetched" => {
+ "issue" => 0
+ },
+ "imported" => {
+ "issue" => 0
+ }
+ }
+ )
+ end
+ end
+
context 'when there are no cached import statistics' do
context 'when project import is in progress' do
it 'includes an empty object counts stats in response' do
diff --git a/spec/lib/gitlab/github_import/user_finder_spec.rb b/spec/lib/gitlab/github_import/user_finder_spec.rb
index 1739425c294..a394b4eba13 100644
--- a/spec/lib/gitlab/github_import/user_finder_spec.rb
+++ b/spec/lib/gitlab/github_import/user_finder_spec.rb
@@ -37,11 +37,11 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache, feat
it 'returns the ID of the ghost user when the object has no user' do
note = { author: nil }
- expect(finder.author_id_for(note)).to eq([User.ghost.id, true])
+ expect(finder.author_id_for(note)).to eq([Users::Internal.ghost.id, true])
end
it 'returns the ID of the ghost user when the given object is nil' do
- expect(finder.author_id_for(nil)).to eq([User.ghost.id, true])
+ expect(finder.author_id_for(nil)).to eq([Users::Internal.ghost.id, true])
end
end
@@ -208,57 +208,254 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache, feat
describe '#email_for_github_username' do
let(:email) { 'kittens@example.com' }
+ let(:username) { 'kittens' }
+ let(:user) { {} }
+ let(:etag) { 'etag' }
+ let(:cache_key) { described_class::EMAIL_FOR_USERNAME_CACHE_KEY % username }
+ let(:etag_cache_key) { described_class::USERNAME_ETAG_CACHE_KEY % username }
+ let(:email_fetched_for_project_key) do
+ format(described_class::EMAIL_FETCHED_FOR_PROJECT_CACHE_KEY, project: project.id, username: username)
+ end
- context 'when an Email address is cached' do
- it 'reads the Email address from the cache' do
- expect(Gitlab::Cache::Import::Caching)
- .to receive(:read)
- .and_return(email)
+ subject(:email_for_github_username) { finder.email_for_github_username(username) }
+
+ shared_examples 'returns and caches the email' do
+ it 'returns the email' do
+ expect(email_for_github_username).to eq(email)
+ end
+
+ it 'caches the email and expires the etag and project check caches' do
+ expect(Gitlab::Cache::Import::Caching).to receive(:write).with(cache_key, email).once
+ expect(Gitlab::Cache::Import::Caching).to receive(:expire).with(etag_cache_key, 0).once
+ expect(Gitlab::Cache::Import::Caching).to receive(:expire).with(email_fetched_for_project_key, 0).once
- expect(client).not_to receive(:user)
- expect(finder.email_for_github_username('kittens')).to eq(email)
+ email_for_github_username
+ email_for_github_username
end
end
- context 'when an Email address is not cached' do
- let(:user) { { email: email } }
+ shared_examples 'returns nil and caches a negative lookup' do
+ it 'returns nil' do
+ expect(email_for_github_username).to be_nil
+ end
- it 'retrieves and caches the Email address when an Email address is available' do
- expect(client).to receive(:user).with('kittens').and_return(user).once
+ it 'caches a blank email and marks the project as checked' do
+ expect(Gitlab::Cache::Import::Caching).to receive(:write).with(cache_key, '').once
+ expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(etag_cache_key, anything)
+ expect(Gitlab::Cache::Import::Caching).to receive(:write).with(email_fetched_for_project_key, 1).once
- expect(Gitlab::Cache::Import::Caching)
- .to receive(:write)
- .with(an_instance_of(String), email, timeout: Gitlab::Cache::Import::Caching::TIMEOUT).and_call_original
+ email_for_github_username
+ email_for_github_username
+ end
+ end
- expect(finder.email_for_github_username('kittens')).to eq(email)
- expect(finder.email_for_github_username('kittens')).to eq(email)
+ shared_examples 'does not change caches' do
+ it 'does not write to any of the caches' do
+ expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(cache_key, anything)
+ expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(etag_cache_key, anything)
+ expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(email_fetched_for_project_key, anything)
+
+ email_for_github_username
+ email_for_github_username
end
+ end
- it 'shortens the timeout for Email address in cache when an Email address is private/nil from GitHub' do
- user = { email: nil }
- expect(client).to receive(:user).with('kittens').and_return(user).once
+ shared_examples 'a user resource not found on GitHub' do
+ before do
+ allow(client).to receive(:user).and_raise(::Octokit::NotFound)
+ end
- expect(Gitlab::Cache::Import::Caching)
- .to receive(:write)
- .with(an_instance_of(String), '', timeout: Gitlab::Cache::Import::Caching::SHORTER_TIMEOUT)
- .and_call_original
+ it 'returns nil' do
+ expect(email_for_github_username).to be_nil
+ end
+
+ it 'caches a blank email' do
+ expect(Gitlab::Cache::Import::Caching).to receive(:write).with(cache_key, '').once
+ expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(etag_cache_key, anything)
+ expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(email_fetched_for_project_key, anything)
+
+ email_for_github_username
+ email_for_github_username
+ end
+ end
+
+ context 'when the email is cached' do
+ before do
+ Gitlab::Cache::Import::Caching.write(cache_key, email)
+ end
+
+ it 'returns the email from the cache' do
+ expect(email_for_github_username).to eq(email)
+ end
+
+ it 'does not make a rate-limited API call' do
+ expect(client).not_to receive(:user).with(username, { headers: {} })
+
+ email_for_github_username
+ email_for_github_username
+ end
+ end
+
+ context 'when the email cache is nil' do
+ context 'if the email has not been checked for the project' do
+ context 'if the cached etag is nil' do
+ before do
+ allow(client).to receive_message_chain(:octokit, :last_response, :headers).and_return({ etag: etag })
+ end
+
+ it 'makes an API call' do
+ expect(client).to receive(:user).with(username, { headers: {} }).and_return({ email: email }).once
+
+ email_for_github_username
+ end
+
+ context 'if the response contains an email' do
+ before do
+ allow(client).to receive(:user).and_return({ email: email })
+ end
+
+ it_behaves_like 'returns and caches the email'
+ end
+
+ context 'if the response does not contain an email' do
+ before do
+ allow(client).to receive(:user).and_return({})
+ end
+
+ it 'returns nil' do
+ expect(email_for_github_username).to be_nil
+ end
+
+ it 'caches a blank email and etag and marks the project as checked' do
+ expect(Gitlab::Cache::Import::Caching).to receive(:write).with(cache_key, '').once
+ expect(Gitlab::Cache::Import::Caching).to receive(:write).with(etag_cache_key, etag).once
+ expect(Gitlab::Cache::Import::Caching).to receive(:write).with(email_fetched_for_project_key, 1).once
- expect(finder.email_for_github_username('kittens')).to be_nil
- expect(finder.email_for_github_username('kittens')).to be_nil
+ email_for_github_username
+ email_for_github_username
+ end
+ end
+ end
+
+ context 'if the cached etag is not nil' do
+ before do
+ Gitlab::Cache::Import::Caching.write(etag_cache_key, etag)
+ end
+
+ it 'makes a non-rate-limited API call' do
+ expect(client).to receive(:user).with(username, { headers: { 'If-None-Match' => etag } }).once
+
+ email_for_github_username
+ end
+
+ context 'if the response contains an email' do
+ before do
+ allow(client).to receive(:user).and_return({ email: email })
+ end
+
+ it_behaves_like 'returns and caches the email'
+ end
+
+ context 'if the response does not contain an email' do
+ before do
+ allow(client).to receive(:user).and_return({})
+ end
+
+ it_behaves_like 'returns nil and caches a negative lookup'
+ end
+
+ context 'if the response is nil' do
+ before do
+ allow(client).to receive(:user).and_return(nil)
+ end
+
+ it 'returns nil' do
+ expect(email_for_github_username).to be_nil
+ end
+
+ it 'marks the project as checked' do
+ expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(cache_key, anything)
+ expect(Gitlab::Cache::Import::Caching).not_to receive(:write).with(etag_cache_key, anything)
+ expect(Gitlab::Cache::Import::Caching).to receive(:write).with(email_fetched_for_project_key, 1).once
+
+ email_for_github_username
+ email_for_github_username
+ end
+ end
+ end
+ end
+
+ context 'if the email has been checked for the project' do
+ before do
+ Gitlab::Cache::Import::Caching.write(email_fetched_for_project_key, 1)
+ end
+
+ it 'returns nil' do
+ expect(email_for_github_username).to be_nil
+ end
+
+ it_behaves_like 'does not change caches'
end
- context 'when a username does not exist on GitHub' do
- it 'caches github username inexistence' do
- expect(client)
- .to receive(:user)
- .with('kittens')
- .and_raise(::Octokit::NotFound)
- .once
+ it_behaves_like 'a user resource not found on GitHub'
+ end
+
+ context 'when the email cache is blank' do
+ before do
+ Gitlab::Cache::Import::Caching.write(cache_key, '')
+ end
+
+ context 'if the email has not been checked for the project' do
+ context 'if the cached etag is not nil' do
+ before do
+ Gitlab::Cache::Import::Caching.write(etag_cache_key, etag)
+ end
+
+ it 'makes a non-rate-limited API call' do
+ expect(client).to receive(:user).with(username, { headers: { 'If-None-Match' => etag } }).once
+
+ email_for_github_username
+ end
+
+ context 'if the response contains an email' do
+ before do
+ allow(client).to receive(:user).and_return({ email: email })
+ end
+
+ it_behaves_like 'returns and caches the email'
+ end
+
+ context 'if the response does not contain an email' do
+ before do
+ allow(client).to receive(:user).and_return({})
+ end
- expect(finder.email_for_github_username('kittens')).to be_nil
- expect(finder.email_for_github_username('kittens')).to be_nil
+ it_behaves_like 'returns nil and caches a negative lookup'
+ end
+
+ context 'if the response is nil' do
+ before do
+ allow(client).to receive(:user).and_return(nil)
+ end
+
+ it_behaves_like 'returns nil and caches a negative lookup'
+ end
+
+ it_behaves_like 'a user resource not found on GitHub'
end
end
+
+ context 'if the email has been checked for the project' do
+ before do
+ Gitlab::Cache::Import::Caching.write(email_fetched_for_project_key, 1)
+ end
+
+ it 'returns nil' do
+ expect(email_for_github_username).to be_nil
+ end
+
+ it_behaves_like 'does not change caches'
+ end
end
end
diff --git a/spec/lib/gitlab/github_import_spec.rb b/spec/lib/gitlab/github_import_spec.rb
index 898bc40ec1f..8453f002bc0 100644
--- a/spec/lib/gitlab/github_import_spec.rb
+++ b/spec/lib/gitlab/github_import_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe Gitlab::GithubImport, feature_category: :importers do
end
it 'returns the ID of the ghost user', :clean_gitlab_redis_cache do
- expect(described_class.ghost_user_id).to eq(User.ghost.id)
+ expect(described_class.ghost_user_id).to eq(Users::Internal.ghost.id)
end
it 'caches the ghost user ID', :clean_gitlab_redis_cache do
@@ -97,7 +97,7 @@ RSpec.describe Gitlab::GithubImport, feature_category: :importers do
end
it 'returns the ID of the ghost user', :clean_gitlab_redis_cache do
- expect(described_class.ghost_user_id).to eq(User.ghost.id)
+ expect(described_class.ghost_user_id).to eq(Users::Internal.ghost.id)
end
it 'caches the ghost user ID', :clean_gitlab_redis_cache do
diff --git a/spec/lib/gitlab/gl_repository/identifier_spec.rb b/spec/lib/gitlab/gl_repository/identifier_spec.rb
index dbdcafea6d6..bf7a21899f0 100644
--- a/spec/lib/gitlab/gl_repository/identifier_spec.rb
+++ b/spec/lib/gitlab/gl_repository/identifier_spec.rb
@@ -68,12 +68,10 @@ RSpec.describe Gitlab::GlRepository::Identifier do
end
describe 'design' do
- let(:design_repository_container) { project.design_repository.container }
-
it_behaves_like 'parsing gl_repository identifier' do
let(:record_id) { project.id }
- let(:identifier) { "design-#{design_repository_container.id}" }
- let(:expected_container) { design_repository_container }
+ let(:identifier) { "design-#{project.find_or_create_design_management_repository.id}" }
+ let(:expected_container) { project.design_management_repository }
let(:expected_type) { Gitlab::GlRepository::DESIGN }
end
end
diff --git a/spec/lib/gitlab/gl_repository/repo_type_spec.rb b/spec/lib/gitlab/gl_repository/repo_type_spec.rb
index 4ff8137dbd4..807f37b96c9 100644
--- a/spec/lib/gitlab/gl_repository/repo_type_spec.rb
+++ b/spec/lib/gitlab/gl_repository/repo_type_spec.rb
@@ -12,8 +12,6 @@ RSpec.describe Gitlab::GlRepository::RepoType do
let(:personal_snippet_path) { "snippets/#{personal_snippet.id}" }
let(:project_snippet_path) { "#{project.full_path}/snippets/#{project_snippet.id}" }
- let(:expected_repository_resolver) { expected_container }
-
describe Gitlab::GlRepository::PROJECT do
it_behaves_like 'a repo type' do
let(:expected_id) { project.id }
@@ -136,11 +134,10 @@ RSpec.describe Gitlab::GlRepository::RepoType do
describe Gitlab::GlRepository::DESIGN do
it_behaves_like 'a repo type' do
let(:expected_repository) { project.design_repository }
- let(:expected_container) { expected_repository.container }
+ let(:expected_container) { project.design_management_repository }
let(:expected_id) { expected_container.id }
let(:expected_identifier) { "design-#{expected_id}" }
let(:expected_suffix) { '.design' }
- let(:expected_repository_resolver) { project }
end
it 'uses the design access checker' do
@@ -167,15 +164,22 @@ RSpec.describe Gitlab::GlRepository::RepoType do
end
describe '.project_for' do
- it 'returns a project' do
- expect(described_class.project_for(project.design_repository.container)).to be_instance_of(Project)
+ it 'returns a project when container is a design_management_repository' do
+ expect(described_class.project_for(project.design_management_repository)).to be_instance_of(Project)
end
end
+ end
- describe '.repository_for' do
- it 'returns a DesignManagement::GitRepository when a project is passed' do
- expect(described_class.repository_for(project)).to be_instance_of(DesignManagement::GitRepository)
- end
+ describe '.repository_for' do
+ subject { Gitlab::GlRepository::DESIGN }
+
+ let(:expected_message) do
+ "Expected container class to be #{subject.container_class} for " \
+ "repo type #{subject.name}, but found #{project.class.name} instead."
+ end
+
+ it 'raises an error when container class does not match given container_class' do
+ expect { subject.repository_for(project) }.to raise_error(Gitlab::GlRepository::ContainerClassMismatchError, expected_message)
end
end
end
diff --git a/spec/lib/gitlab/gl_repository_spec.rb b/spec/lib/gitlab/gl_repository_spec.rb
index 7be01507a82..b03edcb31a6 100644
--- a/spec/lib/gitlab/gl_repository_spec.rb
+++ b/spec/lib/gitlab/gl_repository_spec.rb
@@ -4,9 +4,8 @@ require 'spec_helper'
RSpec.describe ::Gitlab::GlRepository do
describe '.parse' do
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
let_it_be(:snippet) { create(:personal_snippet) }
- let(:design_repository_container) { project.design_repository.container }
it 'parses a project gl_repository' do
expect(described_class.parse("project-#{project.id}")).to eq([project, project, Gitlab::GlRepository::PROJECT])
@@ -21,11 +20,11 @@ RSpec.describe ::Gitlab::GlRepository do
end
it 'parses a design gl_repository' do
- expect(described_class.parse("design-#{design_repository_container.id}")).to eq(
+ expect(described_class.parse("design-#{project.design_management_repository.id}")).to eq(
[
- design_repository_container,
- project,
- Gitlab::GlRepository::DESIGN
+ project.design_management_repository, # container
+ project, # project for container
+ Gitlab::GlRepository::DESIGN # repo type
]
)
end
diff --git a/spec/lib/gitlab/gon_helper_spec.rb b/spec/lib/gitlab/gon_helper_spec.rb
index 1135cfc22ac..fc722402917 100644
--- a/spec/lib/gitlab/gon_helper_spec.rb
+++ b/spec/lib/gitlab/gon_helper_spec.rb
@@ -58,6 +58,7 @@ RSpec.describe Gitlab::GonHelper do
context 'when sentry is configured' do
let(:clientside_dsn) { 'https://xxx@sentry.example.com/1' }
let(:environment) { 'staging' }
+ let(:sentry_clientside_traces_sample_rate) { 0.5 }
context 'with legacy sentry configuration' do
before do
@@ -77,6 +78,15 @@ RSpec.describe Gitlab::GonHelper do
stub_application_setting(sentry_enabled: true)
stub_application_setting(sentry_clientside_dsn: clientside_dsn)
stub_application_setting(sentry_environment: environment)
+ stub_application_setting(sentry_clientside_traces_sample_rate: sentry_clientside_traces_sample_rate)
+ end
+
+ it 'sets sentry dsn and environment from config' do
+ expect(gon).to receive(:sentry_dsn=).with(clientside_dsn)
+ expect(gon).to receive(:sentry_environment=).with(environment)
+ expect(gon).to receive(:sentry_clientside_traces_sample_rate=).with(sentry_clientside_traces_sample_rate)
+
+ helper.add_gon_variables
end
context 'when enable_new_sentry_clientside_integration is disabled' do
@@ -87,19 +97,8 @@ RSpec.describe Gitlab::GonHelper do
it 'does not set sentry dsn and environment from config' do
expect(gon).not_to receive(:sentry_dsn=).with(clientside_dsn)
expect(gon).not_to receive(:sentry_environment=).with(environment)
-
- helper.add_gon_variables
- end
- end
-
- context 'when enable_new_sentry_clientside_integration is enabled' do
- before do
- stub_feature_flags(enable_new_sentry_clientside_integration: true)
- end
-
- it 'sets sentry dsn and environment from config' do
- expect(gon).to receive(:sentry_dsn=).with(clientside_dsn)
- expect(gon).to receive(:sentry_environment=).with(environment)
+ expect(gon).not_to receive(:sentry_clientside_traces_sample_rate=)
+ .with(sentry_clientside_traces_sample_rate)
helper.add_gon_variables
end
@@ -169,4 +168,67 @@ RSpec.describe Gitlab::GonHelper do
expect(url).to match(/no_avatar.*png$/)
end
end
+
+ describe '#add_browsersdk_tracking' do
+ let(:gon) { double('gon').as_null_object }
+ let(:analytics_url) { 'https://analytics.gitlab.com' }
+ let(:is_gitlab_com) { true }
+
+ before do
+ allow(helper).to receive(:gon).and_return(gon)
+ allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
+ end
+
+ context 'when environment variables are set' do
+ before do
+ stub_env('GITLAB_ANALYTICS_URL', analytics_url)
+ stub_env('GITLAB_ANALYTICS_ID', 'analytics-id')
+ end
+
+ it 'sets the analytics_url and analytics_id' do
+ expect(gon).to receive(:analytics_url=).with(analytics_url)
+ expect(gon).to receive(:analytics_id=).with('analytics-id')
+
+ helper.add_browsersdk_tracking
+ end
+
+ context 'when Gitlab.com? is false' do
+ let(:is_gitlab_com) { false }
+
+ it "doesn't set the analytics_url and analytics_id" do
+ expect(gon).not_to receive(:analytics_url=)
+ expect(gon).not_to receive(:analytics_id=)
+
+ helper.add_browsersdk_tracking
+ end
+ end
+
+ context 'when feature flag is false' do
+ before do
+ stub_feature_flags(browsersdk_tracking: false)
+ end
+
+ it "doesn't set the analytics_url and analytics_id" do
+ expect(gon).not_to receive(:analytics_url=)
+ expect(gon).not_to receive(:analytics_id=)
+
+ helper.add_browsersdk_tracking
+ end
+ end
+ end
+
+ context 'when environment variables are not set' do
+ before do
+ stub_env('GITLAB_ANALYTICS_URL', nil)
+ stub_env('GITLAB_ANALYTICS_ID', nil)
+ end
+
+ it "doesn't set the analytics_url and analytics_id" do
+ expect(gon).not_to receive(:analytics_url=)
+ expect(gon).not_to receive(:analytics_id=)
+
+ helper.add_browsersdk_tracking
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/graphql/deprecations/deprecation_spec.rb b/spec/lib/gitlab/graphql/deprecations/deprecation_spec.rb
index 172872fd7eb..55650b0480e 100644
--- a/spec/lib/gitlab/graphql/deprecations/deprecation_spec.rb
+++ b/spec/lib/gitlab/graphql/deprecations/deprecation_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe ::Gitlab::Graphql::Deprecations::Deprecation, feature_category: :
it 'raises an error' do
expect { parsed_deprecation }.to raise_error(ArgumentError,
- '`experiment` and `deprecated` arguments cannot be passed at the same time'
+ '`alpha` and `deprecated` arguments cannot be passed at the same time'
)
end
end
diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb
index 071b303d777..314759fb8a4 100644
--- a/spec/lib/gitlab/group_search_results_spec.rb
+++ b/spec/lib/gitlab/group_search_results_spec.rb
@@ -51,6 +51,17 @@ RSpec.describe Gitlab::GroupSearchResults, feature_category: :global_search do
include_examples 'search results filtered by archived', 'search_merge_requests_hide_archived_projects'
end
+ describe 'milestones search' do
+ let!(:unarchived_project) { create(:project, :public, group: group) }
+ let!(:archived_project) { create(:project, :public, :archived, group: group) }
+ let!(:unarchived_result) { create(:milestone, project: unarchived_project, title: 'foo') }
+ let!(:archived_result) { create(:milestone, project: archived_project, title: 'foo') }
+ let(:query) { 'foo' }
+ let(:scope) { 'milestones' }
+
+ include_examples 'search results filtered by archived', 'search_milestones_hide_archived_projects'
+ end
+
describe '#projects' do
let(:scope) { 'projects' }
let(:query) { 'Test' }
@@ -60,7 +71,7 @@ RSpec.describe Gitlab::GroupSearchResults, feature_category: :global_search do
let_it_be(:unarchived_result) { create(:project, :public, group: group, name: 'Test1') }
let_it_be(:archived_result) { create(:project, :archived, :public, group: group, name: 'Test2') }
- it_behaves_like 'search results filtered by archived', 'search_projects_hide_archived'
+ it_behaves_like 'search results filtered by archived'
end
end
diff --git a/spec/lib/gitlab/http_spec.rb b/spec/lib/gitlab/http_spec.rb
index 93d48379414..9d89167bf81 100644
--- a/spec/lib/gitlab/http_spec.rb
+++ b/spec/lib/gitlab/http_spec.rb
@@ -35,11 +35,14 @@ RSpec.describe Gitlab::HTTP do
super do |response|
response.instance_eval do
def read_body(*)
- @body.each do |fragment|
+ mock_stream = @body.split(' ')
+ mock_stream.each do |fragment|
sleep 0.002.seconds
yield fragment if block_given?
end
+
+ @body
end
end
@@ -64,8 +67,8 @@ RSpec.describe Gitlab::HTTP do
before do
stub_const("#{described_class}::DEFAULT_READ_TOTAL_TIMEOUT", 0.001.seconds)
- WebMock.stub_request(:post, /.*/).to_return do |request|
- { body: %w(a b), status: 200 }
+ WebMock.stub_request(:post, /.*/).to_return do
+ { body: "chunk-1 chunk-2", status: 200 }
end
end
diff --git a/spec/lib/gitlab/import/errors_spec.rb b/spec/lib/gitlab/import/errors_spec.rb
index 3b45af0618b..21d96601609 100644
--- a/spec/lib/gitlab/import/errors_spec.rb
+++ b/spec/lib/gitlab/import/errors_spec.rb
@@ -39,6 +39,7 @@ RSpec.describe Gitlab::Import::Errors, feature_category: :importers do
"Noteable can't be blank",
"Author can't be blank",
"Project does not match noteable project",
+ "Namespace can't be blank",
"User can't be blank",
"Name is not a valid emoji name"
)
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 5bbb95b3ea5..d337a37c69f 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -85,6 +85,7 @@ events:
notes:
- award_emoji
- project
+- namespace
- noteable
- author
- updated_by
@@ -103,6 +104,7 @@ note_metadata:
- note
- email_participant
commit_notes:
+- namespace
- award_emoji
- noteable
- author
@@ -621,6 +623,7 @@ project:
- project_members
- project_repository
- users
+- maintainers
- requesters
- namespace_members
- namespace_requesters
@@ -690,7 +693,6 @@ project:
- pool_repository
- kubernetes_namespaces
- error_tracking_setting
-- metrics_setting
- gitlab_slack_application_integration
- github_integration
- protected_environments
@@ -738,6 +740,7 @@ project:
- project_registry
- packages
- package_files
+- package_protection_rules
- rpm_repository_files
- npm_metadata_caches
- packages_cleanup_policy
@@ -823,6 +826,7 @@ project:
- project_state
- security_policy_bots
- target_branch_rules
+- organization
award_emoji:
- awardable
- user
@@ -872,8 +876,6 @@ suggestions:
- note
diff_note_positions:
- note
-metrics_setting:
-- project
protected_environments:
- project
- group
diff --git a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
index 8089b40cae8..08abd7908d2 100644
--- a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
+++ b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
@@ -97,7 +97,6 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter, feature_category: :imp
:user | true
:author | false
:ci_cd_settings | true
- :metrics_setting | true
:project_badges | true
:pipeline_schedules | true
:error_tracking_setting | true
diff --git a/spec/lib/gitlab/import_export/base/relation_object_saver_spec.rb b/spec/lib/gitlab/import_export/base/relation_object_saver_spec.rb
index e42a1d0ff8b..13d94fdb6fe 100644
--- a/spec/lib/gitlab/import_export/base/relation_object_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/base/relation_object_saver_spec.rb
@@ -27,8 +27,8 @@ RSpec.describe Gitlab::ImportExport::Base::RelationObjectSaver, feature_category
expect { saver.execute }.to change(project.issues, :count).by(1)
end
- context 'when subrelation is present' do
- let(:notes) { build_list(:note, 6, project: project, importing: true) }
+ context 'when subrelation collection is present' do
+ let(:notes) { build_list(:note, 2, project: project, importing: true) }
let(:relation_object) { build(:issue, project: project, notes: notes) }
let(:relation_definition) { { 'notes' => {} } }
@@ -39,7 +39,7 @@ RSpec.describe Gitlab::ImportExport::Base::RelationObjectSaver, feature_category
saver.execute
issue = project.issues.last
- expect(issue.notes.count).to eq(6)
+ expect(issue.notes.count).to eq(2)
end
end
@@ -58,25 +58,10 @@ RSpec.describe Gitlab::ImportExport::Base::RelationObjectSaver, feature_category
end
end
- context 'when subrelation collection count is small' do
- let(:note) { build(:note, project: project, importing: true) }
- let(:relation_object) { build(:issue, project: project, notes: [note]) }
- let(:relation_definition) { { 'notes' => {} } }
-
- it 'saves subrelation as part of the relation object itself' do
- expect(relation_object.notes).not_to receive(:<<)
-
- saver.execute
-
- issue = project.issues.last
- expect(issue.notes.count).to eq(1)
- end
- end
-
context 'when some subrelations are invalid' do
- let(:notes) { build_list(:note, 5, project: project, importing: true) }
+ let(:note) { build(:note, project: project, importing: true) }
let(:invalid_note) { build(:note) }
- let(:relation_object) { build(:issue, project: project, notes: notes + [invalid_note]) }
+ let(:relation_object) { build(:issue, project: project, notes: [note, invalid_note]) }
let(:relation_definition) { { 'notes' => {} } }
it 'saves valid subrelations and logs invalid subrelation' do
@@ -88,7 +73,7 @@ RSpec.describe Gitlab::ImportExport::Base::RelationObjectSaver, feature_category
issue = project.issues.last
expect(invalid_note.persisted?).to eq(false)
- expect(issue.notes.count).to eq(5)
+ expect(issue.notes.count).to eq(1)
end
context 'when invalid subrelation can still be persisted' do
@@ -112,14 +97,14 @@ RSpec.describe Gitlab::ImportExport::Base::RelationObjectSaver, feature_category
let(:relation_key) { 'labels' }
let(:relation_definition) { { 'priorities' => {} } }
let(:importable) { create(:group) }
- let(:valid_priorities) { build_list(:label_priority, 5, importing: true) }
+ let(:valid_priorities) { [build(:label_priority, importing: true)] }
let(:invalid_priority) { build(:label_priority, priority: -1) }
let(:relation_object) { build(:group_label, group: importable, title: 'test', priorities: valid_priorities + [invalid_priority]) }
it 'saves relation without invalid subrelations' do
saver.execute
- expect(importable.labels.last.priorities.count).to eq(5)
+ expect(importable.labels.last.priorities.count).to eq(1)
end
end
end
diff --git a/spec/lib/gitlab/import_export/command_line_util_spec.rb b/spec/lib/gitlab/import_export/command_line_util_spec.rb
index 8ed3a60d7fc..76a35d07c7f 100644
--- a/spec/lib/gitlab/import_export/command_line_util_spec.rb
+++ b/spec/lib/gitlab/import_export/command_line_util_spec.rb
@@ -203,7 +203,7 @@ RSpec.describe Gitlab::ImportExport::CommandLineUtil, feature_category: :importe
it 'throws a blocked url error' do
Tempfile.create('test') do |file|
- expect { subject.download(url, file.path) }.to raise_error((Gitlab::HTTP::BlockedUrlError))
+ expect { subject.download(url, file.path) }.to raise_error(Gitlab::HTTP::BlockedUrlError)
end
end
diff --git a/spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb b/spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb
index aceea70be92..04e25dee905 100644
--- a/spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb
+++ b/spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb
@@ -13,13 +13,13 @@ RSpec.describe Gitlab::ImportExport::DecompressedArchiveSizeValidator, feature_c
FileUtils.rm(filepath)
end
- subject { described_class.new(archive_path: filepath, max_bytes: max_bytes) }
+ subject { described_class.new(archive_path: filepath) }
describe '#valid?' do
- let(:max_bytes) { 1 }
-
context 'when file does not exceed allowed decompressed size' do
- let(:max_bytes) { 20 }
+ before do
+ stub_application_setting(max_decompressed_archive_size: 20)
+ end
it 'returns true' do
expect(subject.valid?).to eq(true)
@@ -35,6 +35,10 @@ RSpec.describe Gitlab::ImportExport::DecompressedArchiveSizeValidator, feature_c
end
context 'when file exceeds allowed decompressed size' do
+ before do
+ stub_application_setting(max_decompressed_archive_size: 0.000001)
+ end
+
it 'logs error message returns false' do
expect(Gitlab::Import::Logger)
.to receive(:info)
@@ -93,7 +97,7 @@ RSpec.describe Gitlab::ImportExport::DecompressedArchiveSizeValidator, feature_c
end
context 'when timeout occurs' do
- let(:error_message) { 'Timeout reached during archive decompression' }
+ let(:error_message) { 'Timeout of 210 seconds reached during archive decompression' }
let(:exception) { Timeout::Error }
include_examples 'logs raised exception and terminates validator process group'
diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb
index d449446d7be..ef118d2987c 100644
--- a/spec/lib/gitlab/import_export/file_importer_spec.rb
+++ b/spec/lib/gitlab/import_export/file_importer_spec.rb
@@ -198,8 +198,7 @@ RSpec.describe Gitlab::ImportExport::FileImporter, feature_category: :importers
context 'when validate_import_decompressed_archive_size feature flag is enabled' do
before do
stub_feature_flags(validate_import_decompressed_archive_size: true)
-
- allow(Gitlab::ImportExport::DecompressedArchiveSizeValidator).to receive(:max_bytes).and_return(1)
+ stub_application_setting(max_decompressed_archive_size: 0.000001)
end
it 'returns false and sets an error on shared' do
diff --git a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
index 1d3fc764b50..09a2417ce1e 100644
--- a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
+++ b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
@@ -48,7 +48,6 @@ RSpec.describe 'Test coverage of the Project Import', feature_category: :importe
project.ci_pipelines.notes.events.push_event_payload
project.protected_branches.unprotect_access_levels
project.prometheus_metrics
- project.metrics_setting
project.boards.lists.label.priorities
project.service_desk_setting
project.security_setting
diff --git a/spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb b/spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb
index 452d63d548e..486d179ae05 100644
--- a/spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb
+++ b/spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Gitlab::ImportExport::Json::NdjsonWriter do
+RSpec.describe Gitlab::ImportExport::Json::NdjsonWriter, feature_category: :importers do
include ImportExport::CommonUtil
let(:path) { "#{Dir.tmpdir}/ndjson_writer_spec/tree" }
@@ -35,13 +35,18 @@ RSpec.describe Gitlab::ImportExport::Json::NdjsonWriter do
end
context "when single relation is already serialized" do
- it "raise exception" do
+ it "appends to the existing file" do
values = [{ "key" => "value_1", "key_1" => "value_1" }, { "key" => "value_2", "key_1" => "value_2" }]
relation = "relation"
file_path = File.join(path, exportable_path, "#{relation}.ndjson")
subject.write_relation(exportable_path, relation, values[0])
- expect { subject.write_relation(exportable_path, relation, values[1]) }.to raise_exception("The #{file_path} already exist")
+ expect { subject.write_relation(exportable_path, relation, values[1]) }.not_to raise_exception
+
+ file_data = File.read(file_path)
+
+ expect(file_data).to include(values[0].to_json)
+ expect(file_data).to include(values[1].to_json)
end
end
end
diff --git a/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb b/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
index f4c9189030b..e5058e029c8 100644
--- a/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
+++ b/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb
@@ -70,8 +70,9 @@ RSpec.describe Gitlab::ImportExport::Json::StreamingSerializer, feature_category
create_list(:issue, 3, :with_desc_relative_position, project: exportable ) # ascending ids, descending position
end
- it 'calls json_writer.write_relation_array with proper params' do
+ it 'calls json_writer.write_relation_array with proper params and clears SafeRequestStore' do
expect(json_writer).to receive(:write_relation_array).with(exportable_path, :issues, array_including(issue.to_json))
+ expect(Gitlab::SafeRequestStore).to receive(:clear!)
subject.execute
end
diff --git a/spec/lib/gitlab/import_export/project/export_task_spec.rb b/spec/lib/gitlab/import_export/project/export_task_spec.rb
index 95971d08175..0837874526a 100644
--- a/spec/lib/gitlab/import_export/project/export_task_spec.rb
+++ b/spec/lib/gitlab/import_export/project/export_task_spec.rb
@@ -2,7 +2,7 @@
require 'rake_helper'
-RSpec.describe Gitlab::ImportExport::Project::ExportTask, :silence_stdout do
+RSpec.describe Gitlab::ImportExport::Project::ExportTask, :silence_stdout, feature_category: :importers do
let_it_be(:username) { 'root' }
let(:namespace_path) { username }
let_it_be(:user) { create(:user, username: username) }
diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
index 47003707172..c83cfb0e2f5 100644
--- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
@@ -467,7 +467,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
aggregate_failures do
expect(release.tag).to eq('release-1.0')
- expect(release.author_id).to eq(User.select(:id).ghost.id)
+ expect(release.author_id).to eq(Users::Internal.ghost.id)
end
end
diff --git a/spec/lib/gitlab/import_sources_spec.rb b/spec/lib/gitlab/import_sources_spec.rb
index b243780a020..db23e3b1fd4 100644
--- a/spec/lib/gitlab/import_sources_spec.rb
+++ b/spec/lib/gitlab/import_sources_spec.rb
@@ -58,7 +58,7 @@ RSpec.describe Gitlab::ImportSources, feature_category: :importers do
describe '.importer' do
import_sources = {
'github' => Gitlab::GithubImport::ParallelImporter,
- 'bitbucket' => Gitlab::BitbucketImport::Importer,
+ 'bitbucket' => Gitlab::BitbucketImport::ParallelImporter,
'bitbucket_server' => Gitlab::BitbucketServerImport::ParallelImporter,
'fogbugz' => Gitlab::FogbugzImport::Importer,
'git' => nil,
@@ -72,45 +72,37 @@ RSpec.describe Gitlab::ImportSources, feature_category: :importers do
expect(described_class.importer(name)).to eq(klass)
end
end
-
- context 'when flag is disabled' do
- before do
- stub_feature_flags(bitbucket_server_parallel_importer: false)
- end
-
- it 'returns Gitlab::BitbucketServerImport::Importer when given bitbucket_server' do
- expect(described_class.importer('bitbucket_server')).to eq(Gitlab::BitbucketServerImport::Importer)
- end
- end
end
describe '.import_table' do
subject { described_class.import_table }
- it 'returns the ParallelImporter for Bitbucket server' do
- is_expected.to include(
- described_class::ImportSource.new(
- 'bitbucket_server',
- 'Bitbucket Server',
- Gitlab::BitbucketServerImport::ParallelImporter
- )
- )
- end
-
- context 'when flag is disabled' do
- before do
- stub_feature_flags(bitbucket_server_parallel_importer: false)
- end
-
- it 'returns the legacy Importer for Bitbucket server' do
+ describe 'Bitbucket cloud' do
+ it 'returns the ParallelImporter' do
is_expected.to include(
described_class::ImportSource.new(
- 'bitbucket_server',
- 'Bitbucket Server',
- Gitlab::BitbucketServerImport::Importer
+ 'bitbucket',
+ 'Bitbucket Cloud',
+ Gitlab::BitbucketImport::ParallelImporter
)
)
end
+
+ context 'when flag is disabled' do
+ before do
+ stub_feature_flags(bitbucket_parallel_importer: false)
+ end
+
+ it 'returns the legacy Importer' do
+ is_expected.to include(
+ described_class::ImportSource.new(
+ 'bitbucket',
+ 'Bitbucket Cloud',
+ Gitlab::BitbucketImport::Importer
+ )
+ )
+ end
+ end
end
end
@@ -134,7 +126,7 @@ RSpec.describe Gitlab::ImportSources, feature_category: :importers do
end
describe 'imports_repository? checker' do
- let(:allowed_importers) { %w[github gitlab_project bitbucket_server] }
+ let(:allowed_importers) { %w[github gitlab_project bitbucket bitbucket_server] }
it 'fails if any importer other than the allowed ones implements this method' do
current_importers = described_class.values.select { |kind| described_class.importer(kind).try(:imports_repository?) }
diff --git a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
index 6271885d80e..4168fdf5425 100644
--- a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
@@ -62,6 +62,7 @@ RSpec.describe Gitlab::Instrumentation::RedisInterceptor, :request_store, featur
it 'counts successful pipelined requests' do
expect(instrumentation_class).to receive(:instance_count_request).with(2).and_call_original
+ expect(instrumentation_class).to receive(:instance_count_pipelined_request).with(2).and_call_original
redis_store_class.with do |redis|
redis.pipelined do |pipeline|
diff --git a/spec/lib/gitlab/job_waiter_spec.rb b/spec/lib/gitlab/job_waiter_spec.rb
index af2da8f20c0..b000f55e739 100644
--- a/spec/lib/gitlab/job_waiter_spec.rb
+++ b/spec/lib/gitlab/job_waiter_spec.rb
@@ -4,13 +4,21 @@ require 'spec_helper'
RSpec.describe Gitlab::JobWaiter, :redis, feature_category: :shared do
describe '.notify' do
- it 'pushes the jid to the named queue' do
- key = described_class.new.key
+ let(:key) { described_class.new.key }
+ it 'pushes the jid to the named queue', :freeze_time do
described_class.notify(key, 123)
Gitlab::Redis::SharedState.with do |redis|
- expect(redis.ttl(key)).to be > 0
+ expect(redis.ttl(key)).to eq(described_class::DEFAULT_TTL)
+ end
+ end
+
+ it 'can be passed a custom TTL', :freeze_time do
+ described_class.notify(key, 123, ttl: 5.minutes)
+
+ Gitlab::Redis::SharedState.with do |redis|
+ expect(redis.ttl(key)).to eq(5.minutes.to_i)
end
end
end
@@ -23,6 +31,32 @@ RSpec.describe Gitlab::JobWaiter, :redis, feature_category: :shared do
end
end
+ describe '.delete_key' do
+ let(:key) { described_class.generate_key }
+
+ it 'deletes the key' do
+ described_class.notify(key, '1')
+ described_class.delete_key(key)
+
+ Gitlab::Redis::SharedState.with do |redis|
+ expect(redis.llen(key)).to eq(0)
+ end
+ end
+
+ context 'when key is not a JobWaiter key' do
+ let(:key) { 'foo' }
+
+ it 'does not delete the key' do
+ described_class.notify(key, '1')
+ described_class.delete_key(key)
+
+ Gitlab::Redis::SharedState.with do |redis|
+ expect(redis.llen(key)).to eq(1)
+ end
+ end
+ end
+ end
+
describe '#wait' do
let(:waiter) { described_class.new(2) }
diff --git a/spec/lib/gitlab/manifest_import/metadata_spec.rb b/spec/lib/gitlab/manifest_import/metadata_spec.rb
index c55b407088d..011371782fe 100644
--- a/spec/lib/gitlab/manifest_import/metadata_spec.rb
+++ b/spec/lib/gitlab/manifest_import/metadata_spec.rb
@@ -46,16 +46,6 @@ RSpec.describe Gitlab::ManifestImport::Metadata, :clean_gitlab_redis_shared_stat
expect(status.repositories).to eq(repositories)
end
-
- it 'reads non-hash-tagged keys if hash-tag keys are missing' do
- status = described_class.new(user)
-
- Gitlab::Redis::SharedState.with do |redis|
- redis.set(repositories_key, Gitlab::Json.dump(repositories))
- end
-
- expect(status.repositories).to eq(repositories)
- end
end
describe '#group_id' do
@@ -73,13 +63,5 @@ RSpec.describe Gitlab::ManifestImport::Metadata, :clean_gitlab_redis_shared_stat
expect(status.group_id).to eq(3)
end
-
- it 'reads non-hash-tagged keys if hash-tag keys are missing' do
- status = described_class.new(user)
-
- Gitlab::Redis::SharedState.with { |redis| redis.set(group_id_key, 2) }
-
- expect(status.group_id).to eq(2)
- end
end
end
diff --git a/spec/lib/gitlab/metrics/dashboard/cache_spec.rb b/spec/lib/gitlab/metrics/dashboard/cache_spec.rb
deleted file mode 100644
index 8c2edc85c35..00000000000
--- a/spec/lib/gitlab/metrics/dashboard/cache_spec.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/RedundantFetchBlock
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Metrics::Dashboard::Cache, :use_clean_rails_memory_store_caching do
- let_it_be(:project1) { build_stubbed(:project) }
- let_it_be(:project2) { build_stubbed(:project) }
-
- let(:project1_key1) { "#{project1.id}_key1" }
- let(:project1_key2) { "#{project1.id}_key2" }
- let(:project2_key1) { "#{project2.id}_key1" }
-
- let(:cache1) { described_class.for(project1) }
- let(:cache2) { described_class.for(project2) }
-
- before do
- cache1.fetch(project1_key1) { 'data1' }
- cache1.fetch(project1_key2) { 'data2' }
- cache2.fetch(project2_key1) { 'data3' }
- end
-
- describe '.fetch' do
- it 'stores data correctly' do
- described_class.fetch('key1') { 'data1' }
- described_class.fetch('key2') { 'data2' }
-
- expect(described_class.fetch('key1')).to eq('data1')
- expect(described_class.fetch('key2')).to eq('data2')
- end
- end
-
- describe '.for' do
- it 'returns a new instance' do
- expect(described_class.for(project1)).to be_instance_of(described_class)
- end
- end
-
- describe '#fetch' do
- it 'stores data correctly' do
- expect(cache1.fetch(project1_key1)).to eq('data1')
- expect(cache1.fetch(project1_key2)).to eq('data2')
- expect(cache2.fetch(project2_key1)).to eq('data3')
- end
- end
-
- describe '#delete_all!' do
- it 'deletes keys of the given project', :aggregate_failures do
- cache1.delete_all!
-
- expect(Rails.cache.exist?(project1_key1)).to be(false)
- expect(Rails.cache.exist?(project1_key2)).to be(false)
- expect(cache2.fetch(project2_key1)).to eq('data3')
-
- cache2.delete_all!
-
- expect(Rails.cache.exist?(project2_key1)).to be(false)
- end
-
- it 'does not fail when nothing to delete' do
- project3 = build_stubbed(:project)
- cache3 = described_class.for(project3)
-
- expect { cache3.delete_all! }.not_to raise_error
- end
- end
-
- context 'multiple fetches and deletes' do
- specify :aggregate_failures do
- cache1.delete_all!
-
- expect(Rails.cache.exist?(project1_key1)).to be(false)
- expect(Rails.cache.exist?(project1_key2)).to be(false)
-
- cache1.fetch("#{project1.id}_key3") { 'data1' }
- cache1.fetch("#{project1.id}_key4") { 'data2' }
-
- expect(cache1.fetch("#{project1.id}_key3")).to eq('data1')
- expect(cache1.fetch("#{project1.id}_key4")).to eq('data2')
-
- cache1.delete_all!
-
- expect(Rails.cache.exist?("#{project1.id}_key3")).to be(false)
- expect(Rails.cache.exist?("#{project1.id}_key4")).to be(false)
- end
- end
-end
-# rubocop:enable Style/RedundantFetchBlock
diff --git a/spec/lib/gitlab/metrics/dashboard/processor_spec.rb b/spec/lib/gitlab/metrics/dashboard/processor_spec.rb
deleted file mode 100644
index 11b587e4905..00000000000
--- a/spec/lib/gitlab/metrics/dashboard/processor_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Metrics::Dashboard::Processor do
- include MetricsDashboardHelpers
-
- let(:project) { build(:project) }
- let(:environment) { create(:environment, project: project) }
- let(:dashboard_yml) { load_sample_dashboard }
-
- describe 'process' do
- let(:sequence) do
- [
- Gitlab::Metrics::Dashboard::Stages::UrlValidator
- ]
- end
-
- let(:process_params) { [project, dashboard_yml, sequence, { environment: environment }] }
- let(:dashboard) { described_class.new(*process_params).process }
-
- context 'when the dashboard is not present' do
- let(:dashboard_yml) { nil }
-
- it 'returns nil' do
- expect(dashboard).to be_nil
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/metrics/dashboard/repo_dashboard_finder_spec.rb b/spec/lib/gitlab/metrics/dashboard/repo_dashboard_finder_spec.rb
deleted file mode 100644
index a2c9906c0e9..00000000000
--- a/spec/lib/gitlab/metrics/dashboard/repo_dashboard_finder_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Metrics::Dashboard::RepoDashboardFinder do
- include MetricsDashboardHelpers
-
- let_it_be(:project) { create(:project) }
-
- describe '.list_dashboards' do
- it 'deletes dashboard cache entries' do
- cache = instance_double(Gitlab::Metrics::Dashboard::Cache)
- allow(Gitlab::Metrics::Dashboard::Cache).to receive(:for).and_return(cache)
-
- expect(cache).to receive(:delete_all!)
-
- described_class.list_dashboards(project)
- end
-
- it 'returns empty array when there are no dashboards' do
- expect(described_class.list_dashboards(project)).to eq([])
- end
-
- context 'when there are project dashboards available' do
- let_it_be(:dashboard_path) { '.gitlab/dashboards/test.yml' }
- let_it_be(:project) { project_with_dashboard(dashboard_path) }
-
- it 'returns the dashboard list' do
- expect(described_class.list_dashboards(project)).to contain_exactly(dashboard_path)
- end
- end
- end
-
- describe '.read_dashboard' do
- it 'raises error when dashboard does not exist' do
- dashboard_path = '.gitlab/dashboards/test.yml'
-
- expect { described_class.read_dashboard(project, dashboard_path) }.to raise_error(
- Gitlab::Metrics::Dashboard::Errors::NOT_FOUND_ERROR
- )
- end
-
- context 'when there are project dashboards available' do
- let_it_be(:dashboard_path) { '.gitlab/dashboards/test.yml' }
- let_it_be(:project) { project_with_dashboard(dashboard_path) }
-
- it 'reads dashboard' do
- expect(described_class.read_dashboard(project, dashboard_path)).to eq(
- fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml')
- )
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/metrics/dashboard/stages/url_validator_spec.rb b/spec/lib/gitlab/metrics/dashboard/stages/url_validator_spec.rb
deleted file mode 100644
index 83cf161c4e2..00000000000
--- a/spec/lib/gitlab/metrics/dashboard/stages/url_validator_spec.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Metrics::Dashboard::Stages::UrlValidator do
- let(:project) { build_stubbed(:project) }
-
- describe '#transform!' do
- context 'when the links contain a blocked url' do
- let(:dashboard) do
- {
- dashboard: "Test Dashboard",
- links: [
- { url: "http://1.1.1.1.1" },
- { url: "https://gitlab.com" },
- { url: "http://0.0.0.0" }
- ],
- panel_groups: [
- {
- group: "Group A",
- panels: [
- {
- title: "Super Chart A1",
- type: "area-chart",
- y_label: "y_label",
- metrics: [
- {
- id: "metric_a1",
- query_range: "query",
- unit: "unit",
- label: "Legend Label"
- }
- ],
- links: [
- { url: "http://1.1.1.1.1" },
- { url: "https://gitlab.com" },
- { url: "http://0.0.0.0" }
- ]
- }
- ]
- }
- ]
- }
- end
-
- let(:expected) do
- [{ url: '' }, { url: 'https://gitlab.com' }, { url: 'http://0.0.0.0' }]
- end
-
- let(:transform!) { described_class.new(project, dashboard, nil).transform! }
-
- before do
- stub_env('RSPEC_ALLOW_INVALID_URLS', 'false')
- stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
- end
-
- context 'dashboard related links' do
- it 'replaces the blocked url with an empty string' do
- transform!
-
- expect(dashboard[:links]).to eq(expected)
- end
- end
-
- context 'chart links' do
- it 'replaces the blocked url with an empty string' do
- transform!
-
- result = dashboard.dig(:panel_groups, 0, :panels, 0, :links)
- expect(result).to eq(expected)
- end
- end
-
- context 'when local requests are not allowed' do
- before do
- stub_application_setting(allow_local_requests_from_web_hooks_and_services: false)
- end
-
- let(:expected) do
- [{ url: '' }, { url: 'https://gitlab.com' }, { url: '' }]
- end
-
- it 'replaces the blocked url with an empty string' do
- transform!
-
- expect(dashboard[:links]).to eq(expected)
- end
- end
-
- context 'when the links are an array of strings instead of hashes' do
- before do
- dashboard[:links] = dashboard[:links].map(&:values)
- end
-
- it 'prevents an invalid link definition from erroring out' do
- expect { transform! }.not_to raise_error
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/metrics/dashboard/url_spec.rb b/spec/lib/gitlab/metrics/dashboard/url_spec.rb
deleted file mode 100644
index a035cf02da4..00000000000
--- a/spec/lib/gitlab/metrics/dashboard/url_spec.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Metrics::Dashboard::Url do
- include Gitlab::Routing.url_helpers
-
- describe '#clusters_regex' do
- let(:url) { Gitlab::Routing.url_helpers.namespace_project_cluster_url(*url_params) }
- let(:url_params) do
- [
- 'foo',
- 'bar',
- '1',
- {
- group: 'Cluster Health',
- title: 'Memory Usage',
- y_label: 'Memory 20(GiB)',
- anchor: 'title'
- }
- ]
- end
-
- let(:expected_params) do
- {
- 'url' => url,
- 'namespace' => 'foo',
- 'project' => 'bar',
- 'cluster_id' => '1',
- 'query' => '?group=Cluster+Health&title=Memory+Usage&y_label=Memory+20%28GiB%29',
- 'anchor' => '#title'
- }
- end
-
- subject { described_class.clusters_regex }
-
- it_behaves_like 'regex which matches url when expected'
-
- context 'for metrics_dashboard route' do
- let(:url) do
- metrics_dashboard_namespace_project_cluster_url(
- *url_params, cluster_type: :project, embedded: true, format: :json
- )
- end
-
- let(:expected_params) do
- {
- 'url' => url,
- 'namespace' => 'foo',
- 'project' => 'bar',
- 'cluster_id' => '1',
- 'query' => '?cluster_type=project&embedded=true',
- 'anchor' => nil
- }
- end
-
- it_behaves_like 'regex which matches url when expected'
- end
- end
-
- describe '#alert_regex' do
- let(:url) { Gitlab::Routing.url_helpers.metrics_dashboard_namespace_project_prometheus_alert_url(*url_params) }
- let(:url_params) do
- [
- 'foo',
- 'bar',
- '1',
- {
- start: '2020-02-10T12:59:49.938Z',
- end: '2020-02-10T20:59:49.938Z',
- anchor: "anchor"
- }
- ]
- end
-
- let(:expected_params) do
- {
- 'url' => url,
- 'namespace' => 'foo',
- 'project' => 'bar',
- 'alert' => '1',
- 'query' => "?end=2020-02-10T20%3A59%3A49.938Z&start=2020-02-10T12%3A59%3A49.938Z",
- 'anchor' => '#anchor'
- }
- end
-
- subject { described_class.alert_regex }
-
- it_behaves_like 'regex which matches url when expected'
-
- it_behaves_like 'regex which matches url when expected' do
- let(:url) { Gitlab::Routing.url_helpers.metrics_dashboard_namespace_project_prometheus_alert_url(*url_params, format: :json) }
-
- let(:expected_params) do
- {
- 'url' => url,
- 'namespace' => 'foo',
- 'project' => 'bar',
- 'alert' => '1',
- 'query' => nil,
- 'anchor' => nil
- }
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/metrics/samplers/database_sampler_spec.rb b/spec/lib/gitlab/metrics/samplers/database_sampler_spec.rb
index 57790ad78a8..85e8b366f29 100644
--- a/spec/lib/gitlab/metrics/samplers/database_sampler_spec.rb
+++ b/spec/lib/gitlab/metrics/samplers/database_sampler_spec.rb
@@ -8,6 +8,32 @@ RSpec.describe Gitlab::Metrics::Samplers::DatabaseSampler do
it_behaves_like 'metrics sampler', 'DATABASE_SAMPLER'
describe '#sample' do
+ let(:main_load_balancer) do
+ double(:main_load_balancer, host_list: main_host_list, configuration: main_configuration, primary_only?: false)
+ end
+
+ let(:main_configuration) { double(:configuration, connection_specification_name: 'ActiveRecord::Base') }
+ let(:main_host_list) { double(:host_list, hosts: [main_replica_host]) }
+ let(:main_replica_host) { double(:host, pool: main_replica_pool, host: 'main-replica-host', port: 2345) }
+ let(:main_replica_pool) do
+ double(:main_replica_pool, db_config: double(:main_replica_db_config, name: 'main_replica'), stat: stats)
+ end
+
+ let(:stats) do
+ { size: 123, connections: 100, busy: 10, dead: 5, idle: 85, waiting: 1 }
+ end
+
+ let(:ci_load_balancer) do
+ double(:ci_load_balancer, host_list: ci_host_list, configuration: ci_configuration, primary_only?: false)
+ end
+
+ let(:ci_configuration) { double(:configuration, connection_specification_name: 'Ci::ApplicationRecord') }
+ let(:ci_host_list) { double(:host_list, hosts: [ci_replica_host]) }
+ let(:ci_replica_host) { double(:host, pool: ci_replica_pool, host: 'ci-replica-host', port: 3456) }
+ let(:ci_replica_pool) do
+ double(:ci_replica_pool, db_config: double(:ci_replica_db_config, name: 'ci_replica'), stat: stats)
+ end
+
let(:main_labels) do
{
class: 'ActiveRecord::Base',
@@ -62,35 +88,9 @@ RSpec.describe Gitlab::Metrics::Samplers::DatabaseSampler do
end
context 'when replica hosts are configured' do
- let(:main_load_balancer) { ApplicationRecord.load_balancer }
- let(:main_replica_host) { main_load_balancer.host }
-
- let(:ci_load_balancer) { double(:load_balancer, host_list: ci_host_list, configuration: configuration) }
- let(:configuration) { double(:configuration, connection_specification_name: 'Ci::ApplicationRecord') }
- let(:ci_host_list) { double(:host_list, hosts: [ci_replica_host]) }
- let(:ci_replica_host) { double(:host, connection: ci_connection) }
- let(:ci_connection) { double(:connection, pool: Ci::ApplicationRecord.connection_pool) }
-
before do
allow(Gitlab::Database::LoadBalancing).to receive(:each_load_balancer)
.and_return([main_load_balancer, ci_load_balancer].to_enum)
-
- allow(main_load_balancer).to receive(:primary_only?).and_return(false)
- allow(ci_load_balancer).to receive(:primary_only?).and_return(false)
-
- allow(main_replica_host).to receive(:host).and_return('main-replica-host')
- allow(ci_replica_host).to receive(:host).and_return('ci-replica-host')
-
- allow(main_replica_host).to receive(:port).and_return(2345)
- allow(ci_replica_host).to receive(:port).and_return(3456)
-
- allow(Gitlab::Database).to receive(:db_config_name)
- .with(main_replica_host.connection)
- .and_return('main_replica')
-
- allow(Gitlab::Database).to receive(:db_config_name)
- .with(ci_replica_host.connection)
- .and_return('ci_replica')
end
it 'samples connection pool statistics for primaries and replicas' do
@@ -117,35 +117,9 @@ RSpec.describe Gitlab::Metrics::Samplers::DatabaseSampler do
end
context 'when the base model has replica connections' do
- let(:main_load_balancer) { ApplicationRecord.load_balancer }
- let(:main_replica_host) { main_load_balancer.host }
-
- let(:ci_load_balancer) { double(:load_balancer, host_list: ci_host_list, configuration: configuration) }
- let(:configuration) { double(:configuration, connection_specification_name: 'Ci::ApplicationRecord') }
- let(:ci_host_list) { double(:host_list, hosts: [ci_replica_host]) }
- let(:ci_replica_host) { double(:host, connection: ci_connection) }
- let(:ci_connection) { double(:connection, pool: Ci::ApplicationRecord.connection_pool) }
-
before do
allow(Gitlab::Database::LoadBalancing).to receive(:each_load_balancer)
.and_return([main_load_balancer, ci_load_balancer].to_enum)
-
- allow(main_load_balancer).to receive(:primary_only?).and_return(false)
- allow(ci_load_balancer).to receive(:primary_only?).and_return(false)
-
- allow(main_replica_host).to receive(:host).and_return('main-replica-host')
- allow(ci_replica_host).to receive(:host).and_return('ci-replica-host')
-
- allow(main_replica_host).to receive(:port).and_return(2345)
- allow(ci_replica_host).to receive(:port).and_return(3456)
-
- allow(Gitlab::Database).to receive(:db_config_name)
- .with(main_replica_host.connection)
- .and_return('main_replica')
-
- allow(Gitlab::Database).to receive(:db_config_name)
- .with(ci_replica_host.connection)
- .and_return('ci_replica')
end
it 'still records the replica metrics' do
diff --git a/spec/lib/gitlab/middleware/webhook_recursion_detection_spec.rb b/spec/lib/gitlab/middleware/webhook_recursion_detection_spec.rb
index 5394cea64af..b85256f32c5 100644
--- a/spec/lib/gitlab/middleware/webhook_recursion_detection_spec.rb
+++ b/spec/lib/gitlab/middleware/webhook_recursion_detection_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
require 'action_dispatch'
require 'rack'
-require 'request_store'
+require 'gitlab/safe_request_store'
RSpec.describe Gitlab::Middleware::WebhookRecursionDetection do
let(:app) { double(:app) }
diff --git a/spec/lib/gitlab/observability_spec.rb b/spec/lib/gitlab/observability_spec.rb
index 61f69a0171a..04c35f0ee3a 100644
--- a/spec/lib/gitlab/observability_spec.rb
+++ b/spec/lib/gitlab/observability_spec.rb
@@ -40,16 +40,10 @@ RSpec.describe Gitlab::Observability, feature_category: :error_tracking do
it { is_expected.to eq("#{described_class.observability_url}/v1/auth/start") }
end
- describe '.tracing_url' do
- subject { described_class.tracing_url(project) }
-
- it { is_expected.to eq("#{described_class.observability_url}/query/#{group.id}/#{project.id}/v1/traces") }
- end
-
describe '.provisioning_url' do
subject { described_class.provisioning_url(project) }
- it { is_expected.to eq(described_class.observability_url.to_s) }
+ it { is_expected.to eq("#{described_class.observability_url}/v3/tenant/#{project.id}") }
end
describe '.build_full_url' do
@@ -169,27 +163,6 @@ RSpec.describe Gitlab::Observability, feature_category: :error_tracking do
end
end
- describe '.tracing_enabled?' do
- let_it_be(:project) { create(:project, :repository) }
-
- it 'returns true if feature is enabled globally' do
- expect(described_class.tracing_enabled?(project)).to eq(true)
- end
-
- it 'returns true if feature is enabled for the project' do
- stub_feature_flags(observability_tracing: false)
- stub_feature_flags(observability_tracing: project)
-
- expect(described_class.tracing_enabled?(project)).to eq(true)
- end
-
- it 'returns false if feature is disabled globally' do
- stub_feature_flags(observability_tracing: false)
-
- expect(described_class.tracing_enabled?(project)).to eq(false)
- end
- end
-
describe '.allowed_for_action?' do
let(:group) { build_stubbed(:group) }
let(:user) { build_stubbed(:user) }
diff --git a/spec/lib/gitlab/other_markup_spec.rb b/spec/lib/gitlab/other_markup_spec.rb
index 74e2c5e26c1..34f1e0cfbc5 100644
--- a/spec/lib/gitlab/other_markup_spec.rb
+++ b/spec/lib/gitlab/other_markup_spec.rb
@@ -2,9 +2,48 @@
require 'spec_helper'
-RSpec.describe Gitlab::OtherMarkup do
+RSpec.describe Gitlab::OtherMarkup, feature_category: :wiki do
let(:context) { {} }
+ context 'when restructured text' do
+ it 'renders' do
+ input = <<~RST
+ Header
+ ======
+
+ *emphasis*; **strong emphasis**; `interpreted text`
+ RST
+
+ output = <<~HTML
+ <h1>Header</h1>
+ <p><em>emphasis</em>; <strong>strong emphasis</strong>; <cite>interpreted text</cite></p>
+ HTML
+
+ expect(render('unimportant_name.rst', input, context)).to include(output.strip)
+ end
+
+ context 'when PlantUML is enabled' do
+ it 'generates the diagram' do
+ Gitlab::CurrentSettings.current_application_settings.update!(plantuml_enabled: true, plantuml_url: 'https://plantuml.com/plantuml')
+
+ input = <<~RST
+ .. plantuml::
+ :caption: Caption with **bold** and *italic*
+
+ Bob -> Alice: hello
+ Alice -> Bob: hi
+ RST
+
+ output = <<~HTML
+ <img class="plantuml" src="https://plantuml.com/plantuml/png/U9npoazIqBLJSCp9J4wrKiX8pSd9vm9pGA9E-Kb0iKm0o4SAt000" data-diagram="plantuml" data-diagram-src="data:text/plain;base64,Qm9iIC0+IEFsaWNlOiBoZWxsbwpBbGljZSAtPiBCb2I6IGhp">
+ <p>Caption with <strong>bold</strong> and <em>italic</em></p>
+ HTML
+
+ expect(render('unimportant_name.rst', input, context)).to include(output.strip)
+ end
+ end
+ end
+
context 'XSS Checks' do
links = {
'links' => {
diff --git a/spec/lib/gitlab/pages/cache_control_spec.rb b/spec/lib/gitlab/pages/cache_control_spec.rb
deleted file mode 100644
index 72240f52580..00000000000
--- a/spec/lib/gitlab/pages/cache_control_spec.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Pages::CacheControl, feature_category: :pages do
- RSpec.shared_examples 'cache_control' do |type|
- it { expect(subject.cache_key).to match(/pages_domain_for_#{type}_1_*/) }
-
- describe '#clear_cache', :use_clean_rails_redis_caching do
- before do
- Rails.cache.write("pages_domain_for_#{type}_1", ['settings-hash'])
- Rails.cache.write("pages_domain_for_#{type}_1_settings-hash", 'payload')
- end
-
- it 'clears the cache' do
- cached_keys = [
- "pages_domain_for_#{type}_1_settings-hash",
- "pages_domain_for_#{type}_1"
- ]
-
- expect(::Gitlab::AppLogger)
- .to receive(:info)
- .with(
- message: 'clear pages cache',
- pages_keys: cached_keys,
- pages_type: type,
- pages_id: 1
- )
-
- expect(Rails.cache)
- .to receive(:delete_multi)
- .with(cached_keys)
-
- subject.clear_cache
- end
- end
- end
-
- describe '.for_namespace' do
- subject(:cache_control) { described_class.for_namespace(1) }
-
- it_behaves_like 'cache_control', :namespace
- end
-
- describe '.for_domain' do
- subject(:cache_control) { described_class.for_domain(1) }
-
- it_behaves_like 'cache_control', :domain
- end
-
- describe '#cache_key' do
- it 'does not change the pages config' do
- expect { described_class.new(type: :domain, id: 1).cache_key }
- .not_to change(Gitlab.config, :pages)
- end
-
- it 'is based on pages settings' do
- access_control = Gitlab.config.pages.access_control
- cache_key = described_class.new(type: :domain, id: 1).cache_key
-
- stub_config(pages: { access_control: !access_control })
-
- expect(described_class.new(type: :domain, id: 1).cache_key).not_to eq(cache_key)
- end
-
- it 'is based on the force_pages_access_control settings' do
- force_pages_access_control = ::Gitlab::CurrentSettings.force_pages_access_control
- cache_key = described_class.new(type: :domain, id: 1).cache_key
-
- ::Gitlab::CurrentSettings.force_pages_access_control = !force_pages_access_control
-
- expect(described_class.new(type: :domain, id: 1).cache_key).not_to eq(cache_key)
- end
-
- it 'caches the application settings hash' do
- expect(Rails.cache)
- .to receive(:write)
- .with('pages_domain_for_domain_1', kind_of(Set))
-
- described_class.new(type: :domain, id: 1).cache_key
- end
- end
-
- it 'fails with invalid type' do
- expect { described_class.new(type: :unknown, id: nil) }
- .to raise_error(ArgumentError, 'type must be :namespace or :domain')
- end
-end
diff --git a/spec/lib/gitlab/pages/virtual_host_finder_spec.rb b/spec/lib/gitlab/pages/virtual_host_finder_spec.rb
index 49eee772f8d..8c34968bbfc 100644
--- a/spec/lib/gitlab/pages/virtual_host_finder_spec.rb
+++ b/spec/lib/gitlab/pages/virtual_host_finder_spec.rb
@@ -40,23 +40,9 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
it 'returns the virual domain when there are pages deployed for the project' do
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.cache_key).to match(/pages_domain_for_domain_#{pages_domain.id}_/)
expect(virtual_domain.lookup_paths.length).to eq(1)
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
end
-
- context 'when :cache_pages_domain_api is disabled' do
- before do
- stub_feature_flags(cache_pages_domain_api: false)
- end
-
- it 'returns the virual domain when there are pages deployed for the project' do
- expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.cache_key).to be_nil
- expect(virtual_domain.lookup_paths.length).to eq(1)
- expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
- end
- end
end
end
@@ -76,23 +62,8 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
virtual_domain = described_class.new("#{project.namespace.path}.example.com").execute
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.cache_key).to match(/pages_domain_for_namespace_#{project.namespace.id}_/)
expect(virtual_domain.lookup_paths.length).to eq(0)
end
-
- context 'when :cache_pages_domain_api is disabled' do
- before do
- stub_feature_flags(cache_pages_domain_api: false)
- end
-
- it 'returns the virual domain with no lookup_paths' do
- virtual_domain = described_class.new("#{project.namespace.path}.example.com".downcase).execute
-
- expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.cache_key).to be_nil
- expect(virtual_domain.lookup_paths.length).to eq(0)
- end
- end
end
context 'when there are pages deployed for the project' do
@@ -111,7 +82,6 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
virtual_domain = described_class.new("#{project.namespace.path}.example.com").execute
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.cache_key).to match(/pages_domain_for_namespace_#{project.namespace.id}_/)
expect(virtual_domain.lookup_paths.length).to eq(1)
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
end
@@ -120,25 +90,9 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
virtual_domain = described_class.new("#{project.namespace.path}.Example.com").execute
expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.cache_key).to match(/pages_domain_for_namespace_#{project.namespace.id}_/)
expect(virtual_domain.lookup_paths.length).to eq(1)
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
end
-
- context 'when :cache_pages_domain_api is disabled' do
- before_all do
- stub_feature_flags(cache_pages_domain_api: false)
- end
-
- it 'returns the virual domain when there are pages deployed for the project' do
- virtual_domain = described_class.new("#{project.namespace.path}.example.com").execute
-
- expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.cache_key).to be_nil
- expect(virtual_domain.lookup_paths.length).to eq(1)
- expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
- end
- end
end
end
@@ -187,18 +141,6 @@ RSpec.describe Gitlab::Pages::VirtualHostFinder, feature_category: :pages do
expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
end
end
-
- context 'when :cache_pages_domain_api is disabled' do
- before do
- stub_feature_flags(cache_pages_domain_api: false)
- end
-
- it 'returns the virual domain when there are pages deployed for the project' do
- expect(virtual_domain).to be_an_instance_of(Pages::VirtualDomain)
- expect(virtual_domain.lookup_paths.length).to eq(1)
- expect(virtual_domain.lookup_paths.first.project_id).to eq(project.id)
- end
- end
end
end
diff --git a/spec/lib/gitlab/pages_spec.rb b/spec/lib/gitlab/pages_spec.rb
index 9f85efd56e6..c20956788ac 100644
--- a/spec/lib/gitlab/pages_spec.rb
+++ b/spec/lib/gitlab/pages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Pages do
+RSpec.describe Gitlab::Pages, feature_category: :pages do
using RSpec::Parameterized::TableSyntax
let(:pages_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) }
@@ -48,4 +48,89 @@ RSpec.describe Gitlab::Pages do
it { is_expected.to eq(result) }
end
end
+
+ describe '.multiple_versions_enabled_for?' do
+ context 'when project is nil' do
+ it 'returns false' do
+ expect(described_class.multiple_versions_enabled_for?(nil)).to eq(false)
+ end
+ end
+
+ context 'when a project is given' do
+ let_it_be(:project) { create(:project) }
+
+ where(:setting, :feature_flag, :license, :result) do
+ false | false | false | false
+ false | false | true | false
+ false | true | false | false
+ false | true | true | false
+ true | false | false | false
+ true | false | true | false
+ true | true | false | false
+ true | true | true | true
+ end
+
+ with_them do
+ let_it_be(:project) { create(:project) }
+
+ subject { described_class.multiple_versions_enabled_for?(project) }
+
+ before do
+ stub_licensed_features(pages_multiple_versions: license)
+ stub_feature_flags(pages_multiple_versions_setting: feature_flag)
+ project.project_setting.update!(pages_multiple_versions_enabled: setting)
+ end
+
+ # this feature is only available in EE
+ it { is_expected.to eq(result && Gitlab.ee?) }
+ end
+ end
+ end
+
+ describe '#add_unique_domain_to' do
+ let(:project) { build(:project) }
+
+ context 'when pages is not enabled' do
+ before do
+ stub_pages_setting(enabled: false)
+ end
+
+ it 'does not set pages unique domain' do
+ expect(Gitlab::Pages::RandomDomain).not_to receive(:generate)
+
+ described_class.add_unique_domain_to(project)
+
+ expect(project.project_setting.pages_unique_domain_enabled).to eq(false)
+ expect(project.project_setting.pages_unique_domain).to eq(nil)
+ end
+ end
+
+ context 'when pages is enabled' do
+ before do
+ stub_pages_setting(enabled: true)
+ end
+
+ it 'enables unique domain by default' do
+ allow(Gitlab::Pages::RandomDomain)
+ .to receive(:generate)
+ .and_return('unique-domain')
+
+ described_class.add_unique_domain_to(project)
+
+ expect(project.project_setting.pages_unique_domain_enabled).to eq(true)
+ expect(project.project_setting.pages_unique_domain).to eq('unique-domain')
+ end
+
+ context 'when project already have a unique domain' do
+ it 'does not changes the original unique domain' do
+ expect(Gitlab::Pages::RandomDomain).not_to receive(:generate)
+ project.project_setting.update!(pages_unique_domain: 'unique-domain')
+
+ described_class.add_unique_domain_to(project.reload)
+
+ expect(project.project_setting.pages_unique_domain).to eq('unique-domain')
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb b/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb
index 7cee65c13f7..4128f745ce7 100644
--- a/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb
+++ b/spec/lib/gitlab/pagination/cursor_based_keyset_spec.rb
@@ -6,20 +6,52 @@ RSpec.describe Gitlab::Pagination::CursorBasedKeyset do
subject { described_class }
describe '.available_for_type?' do
- it 'returns true for Group' do
- expect(subject.available_for_type?(Group.all)).to be_truthy
- end
+ context 'with api_keyset_pagination_multi_order FF disabled' do
+ before do
+ stub_feature_flags(api_keyset_pagination_multi_order: false)
+ end
- it 'returns true for Ci::Build' do
- expect(subject.available_for_type?(Ci::Build.all)).to be_truthy
- end
+ it 'returns true for Group' do
+ expect(subject.available_for_type?(Group.all)).to be_truthy
+ end
- it 'returns true for Packages::BuildInfo' do
- expect(subject.available_for_type?(Packages::BuildInfo.all)).to be_truthy
+ it 'returns true for Ci::Build' do
+ expect(subject.available_for_type?(Ci::Build.all)).to be_truthy
+ end
+
+ it 'returns true for Packages::BuildInfo' do
+ expect(subject.available_for_type?(Packages::BuildInfo.all)).to be_truthy
+ end
+
+ it 'return false for User' do
+ expect(subject.available_for_type?(User.all)).to be_falsey
+ end
end
- it 'return false for other types of relations' do
- expect(subject.available_for_type?(User.all)).to be_falsey
+ context 'with api_keyset_pagination_multi_order FF enabled' do
+ before do
+ stub_feature_flags(api_keyset_pagination_multi_order: true)
+ end
+
+ it 'returns true for Group' do
+ expect(subject.available_for_type?(Group.all)).to be_truthy
+ end
+
+ it 'returns true for Ci::Build' do
+ expect(subject.available_for_type?(Ci::Build.all)).to be_truthy
+ end
+
+ it 'returns true for Packages::BuildInfo' do
+ expect(subject.available_for_type?(Packages::BuildInfo.all)).to be_truthy
+ end
+
+ it 'returns true for User' do
+ expect(subject.available_for_type?(User.all)).to be_truthy
+ end
+
+ it 'return false for other types of relations' do
+ expect(subject.available_for_type?(Issue.all)).to be_falsey
+ end
end
end
@@ -58,7 +90,7 @@ RSpec.describe Gitlab::Pagination::CursorBasedKeyset do
end
it 'return false for other types of relations' do
- expect(subject.available?(cursor_based_request_context, User.all)).to be_falsey
+ expect(subject.available?(cursor_based_request_context, Issue.all)).to be_falsey
expect(subject.available?(cursor_based_request_context, Ci::Build.all)).to be_falsey
expect(subject.available?(cursor_based_request_context, Packages::BuildInfo.all)).to be_falsey
end
@@ -68,16 +100,48 @@ RSpec.describe Gitlab::Pagination::CursorBasedKeyset do
let(:order_by) { :id }
let(:sort) { :desc }
- it 'returns true for Ci::Build' do
- expect(subject.available?(cursor_based_request_context, Ci::Build.all)).to be_truthy
- end
+ context 'with api_keyset_pagination_multi_order FF disabled' do
+ before do
+ stub_feature_flags(api_keyset_pagination_multi_order: false)
+ end
+
+ it 'returns true for Ci::Build' do
+ expect(subject.available?(cursor_based_request_context, Ci::Build.all)).to be_truthy
+ end
+
+ it 'returns true for AuditEvent' do
+ expect(subject.available?(cursor_based_request_context, AuditEvent.all)).to be_truthy
+ end
- it 'returns true for AuditEvent' do
- expect(subject.available?(cursor_based_request_context, AuditEvent.all)).to be_truthy
+ it 'returns true for Packages::BuildInfo' do
+ expect(subject.available?(cursor_based_request_context, Packages::BuildInfo.all)).to be_truthy
+ end
+
+ it 'returns false for User' do
+ expect(subject.available?(cursor_based_request_context, User.all)).to be_falsey
+ end
end
- it 'returns true for Packages::BuildInfo' do
- expect(subject.available?(cursor_based_request_context, Packages::BuildInfo.all)).to be_truthy
+ context 'with api_keyset_pagination_multi_order FF enabled' do
+ before do
+ stub_feature_flags(api_keyset_pagination_multi_order: true)
+ end
+
+ it 'returns true for Ci::Build' do
+ expect(subject.available?(cursor_based_request_context, Ci::Build.all)).to be_truthy
+ end
+
+ it 'returns true for AuditEvent' do
+ expect(subject.available?(cursor_based_request_context, AuditEvent.all)).to be_truthy
+ end
+
+ it 'returns true for Packages::BuildInfo' do
+ expect(subject.available?(cursor_based_request_context, Packages::BuildInfo.all)).to be_truthy
+ end
+
+ it 'returns true for User' do
+ expect(subject.available?(cursor_based_request_context, User.all)).to be_truthy
+ end
end
end
@@ -90,7 +154,7 @@ RSpec.describe Gitlab::Pagination::CursorBasedKeyset do
end
it 'return false for other types of relations' do
- expect(subject.available?(cursor_based_request_context, User.all)).to be_falsey
+ expect(subject.available?(cursor_based_request_context, Issue.all)).to be_falsey
end
end
end
diff --git a/spec/lib/gitlab/patch/redis_cache_store_spec.rb b/spec/lib/gitlab/patch/redis_cache_store_spec.rb
index 5a674d443bb..21c256fdbbe 100644
--- a/spec/lib/gitlab/patch/redis_cache_store_spec.rb
+++ b/spec/lib/gitlab/patch/redis_cache_store_spec.rb
@@ -34,36 +34,58 @@ RSpec.describe Gitlab::Patch::RedisCacheStore, :use_clean_rails_redis_caching, f
end
context 'when reading large amount of keys' do
- it 'batches get into pipelines of 100' do
- cache.redis.with do |redis|
- normal_cluster = !redis.is_a?(Gitlab::Redis::MultiStore) && Gitlab::Redis::ClusterUtil.cluster?(redis)
- multistore_cluster = redis.is_a?(Gitlab::Redis::MultiStore) &&
- ::Gitlab::Redis::ClusterUtil.cluster?(redis.default_store)
+ let(:input_size) { 2000 }
+ let(:chunk_size) { 1000 }
+
+ shared_examples 'read large amount of keys' do
+ it 'breaks the input into 2 chunks for redis cluster' do
+ cache.redis.with do |redis|
+ normal_cluster = !redis.is_a?(Gitlab::Redis::MultiStore) && Gitlab::Redis::ClusterUtil.cluster?(redis)
+ multistore_cluster = redis.is_a?(Gitlab::Redis::MultiStore) &&
+ ::Gitlab::Redis::ClusterUtil.cluster?(redis.default_store)
+
+ if normal_cluster || multistore_cluster
+ expect_next_instances_of(Gitlab::Redis::CrossSlot::Pipeline, 2) do |pipeline|
+ obj = instance_double(::Redis)
+ expect(pipeline).to receive(:pipelined).and_yield(obj)
+ expect(obj).to receive(:get).exactly(chunk_size).times
+ end
+ else
+ expect(redis).to receive(:mget).and_call_original
+ end
+ end
- if normal_cluster || multistore_cluster
- expect(redis).to receive(:pipelined).at_least(2).and_call_original
- else
- expect(redis).to receive(:mget).and_call_original
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ cache.read_multi(*Array.new(input_size) { |i| i })
end
end
+ end
- Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
- cache.read_multi(*Array.new(101) { |i| i })
+ context 'when GITLAB_REDIS_CLUSTER_PIPELINE_BATCH_LIMIT is smaller than the default' do
+ before do
+ stub_env('GITLAB_REDIS_CLUSTER_PIPELINE_BATCH_LIMIT', 10)
end
+
+ it_behaves_like 'read large amount of keys'
end
- end
- end
- context 'when cache is Rails.cache' do
- let(:cache) { Rails.cache }
+ context 'when GITLAB_REDIS_CLUSTER_PIPELINE_BATCH_LIMIT is larger than the default' do
+ let(:input_size) { 4000 }
+ let(:chunk_size) { 2000 }
- context 'when reading using secondary store as default' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_cache: false)
+ before do
+ stub_env('GITLAB_REDIS_CLUSTER_PIPELINE_BATCH_LIMIT', chunk_size)
+ end
+
+ it_behaves_like 'read large amount of keys'
end
- it_behaves_like 'reading using cache stores'
+ it_behaves_like 'read large amount of keys'
end
+ end
+
+ context 'when cache is Rails.cache' do
+ let(:cache) { Rails.cache }
it_behaves_like 'reading using cache stores'
end
@@ -97,7 +119,7 @@ RSpec.describe Gitlab::Patch::RedisCacheStore, :use_clean_rails_redis_caching, f
context 'when deleting large amount of keys' do
before do
- 200.times { |i| cache.write(i, i) }
+ 2000.times { |i| cache.write(i, i) }
end
it 'calls pipeline multiple times' do
@@ -113,9 +135,9 @@ RSpec.describe Gitlab::Patch::RedisCacheStore, :use_clean_rails_redis_caching, f
expect(
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
- cache.delete_multi(Array(0..199))
+ cache.delete_multi(Array(0..1999))
end
- ).to eq(200)
+ ).to eq(2000)
end
end
end
diff --git a/spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb b/spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb
new file mode 100644
index 00000000000..f57257cd1c0
--- /dev/null
+++ b/spec/lib/gitlab/patch/sidekiq_scheduled_enq_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Patch::SidekiqScheduledEnq, :clean_gitlab_redis_queues, feature_category: :scalability do
+ describe '#enqueue_jobs' do
+ let_it_be(:payload) { {} }
+
+ before do
+ allow(Sidekiq).to receive(:load_json).and_return(payload)
+
+ # stub data in both namespaces
+ Sidekiq.redis { |c| c.zadd('schedule', 100, 'dummy') }
+ Gitlab::Redis::Queues.with { |c| c.zadd('schedule', 100, 'dummy') }
+ end
+
+ subject { Sidekiq::Scheduled::Enq.new.enqueue_jobs }
+
+ it 'polls both namespaces by default' do
+ expect(Sidekiq::Client).to receive(:push).with(payload).twice
+
+ subject
+
+ Sidekiq.redis do |conn|
+ expect(conn.zcard('schedule')).to eq(0)
+ end
+
+ Gitlab::Redis::Queues.with do |conn|
+ expect(conn.zcard('schedule')).to eq(0)
+ end
+ end
+
+ context 'when SIDEKIQ_ENABLE_DUAL_NAMESPACE_POLLING is disabled' do
+ before do
+ stub_env('SIDEKIQ_ENABLE_DUAL_NAMESPACE_POLLING', 'false')
+ end
+
+ it 'polls via Sidekiq.redis only' do
+ expect(Sidekiq::Client).to receive(:push).with(payload).once
+
+ subject
+
+ Sidekiq.redis do |conn|
+ expect(conn.zcard('schedule')).to eq(0)
+ end
+
+ Gitlab::Redis::Queues.with do |conn|
+ expect(conn.zcard('schedule')).to eq(1)
+ end
+ end
+ end
+
+ context 'when both envvar are enabled' do
+ around do |example|
+ # runs the zadd to ensure it goes into namespaced set
+ Sidekiq.redis { |c| c.zadd('schedule', 100, 'dummy') }
+
+ holder = Sidekiq.redis_pool
+
+ # forcibly replace Sidekiq.redis since this is set in config/initializer/sidekiq.rb
+ Sidekiq.redis = Gitlab::Redis::Queues.pool
+
+ example.run
+
+ ensure
+ Sidekiq.redis = holder
+ end
+
+ before do
+ stub_env('SIDEKIQ_ENQUEUE_NON_NAMESPACED', 'true')
+ stub_env('SIDEKIQ_ENABLE_DUAL_NAMESPACE_POLLING', 'true')
+ end
+
+ it 'polls both sets' do
+ expect(Sidekiq::Client).to receive(:push).with(payload).twice
+
+ subject
+
+ Sidekiq.redis do |conn|
+ expect(conn.zcard('schedule')).to eq(0)
+ end
+
+ Gitlab::Redis::Queues.with do |conn|
+ expect(conn.zcard('schedule')).to eq(0)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb b/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb
deleted file mode 100644
index 559557f9313..00000000000
--- a/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb
+++ /dev/null
@@ -1,248 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Prometheus::AdditionalMetricsParser do
- include Prometheus::MetricBuilders
-
- let(:parser_error_class) { Gitlab::Prometheus::ParsingError }
-
- describe '#load_groups_from_yaml' do
- subject { described_class.load_groups_from_yaml('dummy.yaml') }
-
- describe 'parsing sample yaml' do
- let(:sample_yaml) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - title: "title"
- required_metrics: [ metric_a, metric_b ]
- weight: 1
- queries: [{ query_range: 'query_range_a', label: label, unit: unit }]
- - title: "title"
- required_metrics: [metric_a]
- weight: 1
- queries: [{ query_range: 'query_range_empty' }]
- - group: group_b
- priority: 1
- metrics:
- - title: title
- required_metrics: ['metric_a']
- weight: 1
- queries: [{query_range: query_range_a}]
- EOF
- end
-
- before do
- allow(described_class).to receive(:load_yaml_file) { YAML.safe_load(sample_yaml) }
- end
-
- it 'parses to two metric groups with 2 and 1 metric respectively' do
- expect(subject.count).to eq(2)
- expect(subject[0].metrics.count).to eq(2)
- expect(subject[1].metrics.count).to eq(1)
- end
-
- it 'provide group data' do
- expect(subject[0]).to have_attributes(name: 'group_a', priority: 1)
- expect(subject[1]).to have_attributes(name: 'group_b', priority: 1)
- end
-
- it 'provides metrics data' do
- metrics = subject.flat_map(&:metrics)
-
- expect(metrics.count).to eq(3)
- expect(metrics[0]).to have_attributes(title: 'title', required_metrics: %w(metric_a metric_b), weight: 1)
- expect(metrics[1]).to have_attributes(title: 'title', required_metrics: %w(metric_a), weight: 1)
- expect(metrics[2]).to have_attributes(title: 'title', required_metrics: %w{metric_a}, weight: 1)
- end
-
- it 'provides query data' do
- queries = subject.flat_map(&:metrics).flat_map(&:queries)
-
- expect(queries.count).to eq(3)
- expect(queries[0]).to eq(query_range: 'query_range_a', label: 'label', unit: 'unit')
- expect(queries[1]).to eq(query_range: 'query_range_empty')
- expect(queries[2]).to eq(query_range: 'query_range_a')
- end
- end
-
- shared_examples 'required field' do |field_name|
- context "when #{field_name} is nil" do
- before do
- allow(described_class).to receive(:load_yaml_file) { YAML.safe_load(field_missing) }
- end
-
- it 'throws parsing error' do
- expect { subject }.to raise_error(parser_error_class, /#{field_name} can't be blank/i)
- end
- end
-
- context "when #{field_name} are not specified" do
- before do
- allow(described_class).to receive(:load_yaml_file) { YAML.safe_load(field_nil) }
- end
-
- it 'throws parsing error' do
- expect { subject }.to raise_error(parser_error_class, /#{field_name} can't be blank/i)
- end
- end
- end
-
- describe 'group required fields' do
- it_behaves_like 'required field', 'metrics' do
- let(:field_nil) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- EOF
- end
-
- let(:field_missing) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- EOF
- end
- end
-
- it_behaves_like 'required field', 'name' do
- let(:field_nil) do
- <<-EOF.strip_heredoc
- - group:
- priority: 1
- metrics: []
- EOF
- end
-
- let(:field_missing) do
- <<-EOF.strip_heredoc
- - priority: 1
- metrics: []
- EOF
- end
- end
-
- it_behaves_like 'required field', 'priority' do
- let(:field_nil) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority:
- metrics: []
- EOF
- end
-
- let(:field_missing) do
- <<-EOF.strip_heredoc
- - group: group_a
- metrics: []
- EOF
- end
- end
- end
-
- describe 'metrics fields parsing' do
- it_behaves_like 'required field', 'title' do
- let(:field_nil) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - title:
- required_metrics: []
- weight: 1
- queries: []
- EOF
- end
-
- let(:field_missing) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - required_metrics: []
- weight: 1
- queries: []
- EOF
- end
- end
-
- it_behaves_like 'required field', 'required metrics' do
- let(:field_nil) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - title: title
- required_metrics:
- weight: 1
- queries: []
- EOF
- end
-
- let(:field_missing) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - title: title
- weight: 1
- queries: []
- EOF
- end
- end
-
- it_behaves_like 'required field', 'weight' do
- let(:field_nil) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - title: title
- required_metrics: []
- weight:
- queries: []
- EOF
- end
-
- let(:field_missing) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - title: title
- required_metrics: []
- queries: []
- EOF
- end
- end
-
- it_behaves_like 'required field', :queries do
- let(:field_nil) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - title: title
- required_metrics: []
- weight: 1
- queries:
- EOF
- end
-
- let(:field_missing) do
- <<-EOF.strip_heredoc
- - group: group_a
- priority: 1
- metrics:
- - title: title
- required_metrics: []
- weight: 1
- EOF
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb
deleted file mode 100644
index b2350eff9f9..00000000000
--- a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do
- around do |example|
- travel_to(Time.local(2008, 9, 1, 12, 0, 0)) { example.run }
- end
-
- include_examples 'additional metrics query' do
- let(:project) { create(:project, :repository) }
- let(:deployment) { create(:deployment, environment: environment, project: project) }
- let(:query_params) { [deployment.id] }
-
- it 'queries using specific time' do
- expect(client).to receive(:query_range).with(anything,
- start_time: (deployment.created_at - 30.minutes).to_f,
- end_time: (deployment.created_at + 30.minutes).to_f)
-
- expect(query_result).not_to be_nil
- end
- end
-end
diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb
deleted file mode 100644
index d0dee2ad366..00000000000
--- a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery do
- around do |example|
- freeze_time { example.run }
- end
-
- include_examples 'additional metrics query' do
- let(:query_params) { [environment.id] }
-
- it 'queries using specific time' do
- expect(client).to receive(:query_range)
- .with(anything, start_time: 8.hours.ago.to_f, end_time: Time.now.to_f)
- expect(query_result).not_to be_nil
- end
-
- context 'when start and end time parameters are provided' do
- let(:query_params) { [environment.id, start_time, end_time] }
-
- context 'as unix timestamps' do
- let(:start_time) { 4.hours.ago.to_f }
- let(:end_time) { 2.hours.ago.to_f }
-
- it 'queries using the provided times' do
- expect(client).to receive(:query_range)
- .with(anything, start_time: start_time, end_time: end_time)
- expect(query_result).not_to be_nil
- end
- end
-
- context 'as Date/Time objects' do
- let(:start_time) { 4.hours.ago }
- let(:end_time) { 2.hours.ago }
-
- it 'queries using the provided times converted to unix' do
- expect(client).to receive(:query_range)
- .with(anything, start_time: start_time.to_f, end_time: end_time.to_f)
- expect(query_result).not_to be_nil
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/rack_attack/request_spec.rb b/spec/lib/gitlab/rack_attack/request_spec.rb
index e8433d99d15..9d2144f75db 100644
--- a/spec/lib/gitlab/rack_attack/request_spec.rb
+++ b/spec/lib/gitlab/rack_attack/request_spec.rb
@@ -249,6 +249,39 @@ RSpec.describe Gitlab::RackAttack::Request do
end
end
+ describe '#get_request_protected_path?' do
+ subject { request.get_request_protected_path? }
+
+ before do
+ stub_application_setting(
+ protected_paths_for_get_request: %w[/protected /secure])
+ end
+
+ where(:path, :expected) do
+ '/' | false
+ '/groups' | false
+ '/foo/protected' | false
+ '/foo/secure' | false
+
+ '/protected' | true
+ '/secure' | true
+ '/secure/' | true
+ '/secure/foo' | true
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+
+ context 'when the application is mounted at a relative URL' do
+ before do
+ stub_config_setting(relative_url_root: '/gitlab/root')
+ end
+
+ it { is_expected.to eq(expected) }
+ end
+ end
+ end
+
describe '#frontend_request?', :allow_forgery_protection do
subject { request.send(:frontend_request?) }
diff --git a/spec/lib/gitlab/redis/chat_spec.rb b/spec/lib/gitlab/redis/chat_spec.rb
index 7a008580936..f9080b4409f 100644
--- a/spec/lib/gitlab/redis/chat_spec.rb
+++ b/spec/lib/gitlab/redis/chat_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe Gitlab::Redis::Chat, feature_category: :no_category do # rubocop: disable RSpec/InvalidFeatureCategory
+RSpec.describe Gitlab::Redis::Chat, feature_category: :ai_abstraction_layer do
include_examples "redis_new_instance_shared_examples", 'chat', Gitlab::Redis::Cache
end
diff --git a/spec/lib/gitlab/redis/etag_cache_spec.rb b/spec/lib/gitlab/redis/etag_cache_spec.rb
deleted file mode 100644
index 182a41bac80..00000000000
--- a/spec/lib/gitlab/redis/etag_cache_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Redis::EtagCache, feature_category: :shared do
- # Note: this is a pseudo-store in front of `Cache`, meant only as a tool
- # to move away from `SharedState` for etag cache data. Thus, we use the
- # same store configuration as the former.
- let(:instance_specific_config_file) { "config/redis.cache.yml" }
-
- include_examples "redis_shared_examples"
-
- describe '#pool' do
- let(:config_new_format_host) { "spec/fixtures/config/redis_new_format_host.yml" }
- let(:config_new_format_socket) { "spec/fixtures/config/redis_new_format_socket.yml" }
- let(:rails_root) { mktmpdir }
-
- subject { described_class.pool }
-
- before do
- # Override rails root to avoid having our fixtures overwritten by `redis.yml` if it exists
- allow(Gitlab::Redis::SharedState).to receive(:rails_root).and_return(rails_root)
- allow(Gitlab::Redis::Cache).to receive(:rails_root).and_return(rails_root)
-
- allow(Gitlab::Redis::SharedState).to receive(:config_file_name).and_return(config_new_format_host)
- allow(Gitlab::Redis::Cache).to receive(:config_file_name).and_return(config_new_format_socket)
- end
-
- around do |example|
- clear_pool
- example.run
- ensure
- clear_pool
- end
-
- it 'instantiates an instance of MultiStore' do
- subject.with do |redis_instance|
- expect(redis_instance).to be_instance_of(::Gitlab::Redis::MultiStore)
-
- expect(redis_instance.primary_store.connection[:id]).to eq("unix:///path/to/redis.sock/0")
- expect(redis_instance.secondary_store.connection[:id]).to eq("redis://test-host:6379/99")
-
- expect(redis_instance.instance_name).to eq('EtagCache')
- end
- end
-
- it_behaves_like 'multi store feature flags', :use_primary_and_secondary_stores_for_etag_cache,
- :use_primary_store_as_default_for_etag_cache
- end
-
- describe '#store_name' do
- it 'returns the name of the Cache store' do
- expect(described_class.store_name).to eq('Cache')
- end
- end
-end
diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb
index e15375c88c7..ce21c2269cc 100644
--- a/spec/lib/gitlab/redis/multi_store_spec.rb
+++ b/spec/lib/gitlab/redis/multi_store_spec.rb
@@ -1130,4 +1130,104 @@ RSpec.describe Gitlab::Redis::MultiStore, feature_category: :redis do
end
end
end
+
+ # NOTE: for pub/sub, unit tests are favoured over integration tests to avoid long polling
+ # with threads which could lead to flaky specs. The multiplexing behaviour are verified in
+ # 'with WRITE redis commands' and 'with READ redis commands' contexts.
+ context 'with pub/sub commands' do
+ let(:channel_name) { 'chanA' }
+ let(:message) { "msg" }
+
+ shared_examples 'publishes to stores' do
+ it 'publishes to one or more stores' do
+ expect(stores).to all(receive(:publish))
+
+ multi_store.publish(channel_name, message)
+ end
+ end
+
+ shared_examples 'subscribes and unsubscribes' do
+ it 'subscribes to the default store' do
+ expect(default_store).to receive(:subscribe)
+ expect(non_default_store).not_to receive(:subscribe)
+
+ multi_store.subscribe(channel_name)
+ end
+
+ it 'unsubscribes to the default store' do
+ expect(default_store).to receive(:unsubscribe)
+ expect(non_default_store).not_to receive(:unsubscribe)
+
+ multi_store.unsubscribe
+ end
+ end
+
+ context 'when using both stores' do
+ before do
+ stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
+ end
+
+ it_behaves_like 'publishes to stores' do
+ let(:stores) { [primary_store, secondary_store] }
+ end
+
+ context 'with primary store set as default' do
+ before do
+ stub_feature_flags(use_primary_store_as_default_for_test_store: true)
+ end
+
+ it_behaves_like 'subscribes and unsubscribes' do
+ let(:default_store) { primary_store }
+ let(:non_default_store) { secondary_store }
+ end
+ end
+
+ context 'with secondary store set as default' do
+ before do
+ stub_feature_flags(use_primary_store_as_default_for_test_store: false)
+ end
+
+ it_behaves_like 'subscribes and unsubscribes' do
+ let(:default_store) { secondary_store }
+ let(:non_default_store) { primary_store }
+ end
+ end
+ end
+
+ context 'when only using the primary store' do
+ before do
+ stub_feature_flags(
+ use_primary_and_secondary_stores_for_test_store: false,
+ use_primary_store_as_default_for_test_store: true
+ )
+ end
+
+ it_behaves_like 'subscribes and unsubscribes' do
+ let(:default_store) { primary_store }
+ let(:non_default_store) { secondary_store }
+ end
+
+ it_behaves_like 'publishes to stores' do
+ let(:stores) { [primary_store] }
+ end
+ end
+
+ context 'when only using the secondary store' do
+ before do
+ stub_feature_flags(
+ use_primary_and_secondary_stores_for_test_store: false,
+ use_primary_store_as_default_for_test_store: false
+ )
+ end
+
+ it_behaves_like 'subscribes and unsubscribes' do
+ let(:default_store) { secondary_store }
+ let(:non_default_store) { primary_store }
+ end
+
+ it_behaves_like 'publishes to stores' do
+ let(:stores) { [secondary_store] }
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/redis/pubsub_spec.rb b/spec/lib/gitlab/redis/pubsub_spec.rb
new file mode 100644
index 00000000000..e196d02116e
--- /dev/null
+++ b/spec/lib/gitlab/redis/pubsub_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Redis::Pubsub, feature_category: :redis do
+ include_examples "redis_new_instance_shared_examples", 'pubsub', Gitlab::Redis::SharedState
+ include_examples "redis_shared_examples"
+end
diff --git a/spec/lib/gitlab/redis/queues_metadata_spec.rb b/spec/lib/gitlab/redis/queues_metadata_spec.rb
new file mode 100644
index 00000000000..693e8074b45
--- /dev/null
+++ b/spec/lib/gitlab/redis/queues_metadata_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Redis::QueuesMetadata, feature_category: :redis do
+ include_examples "redis_new_instance_shared_examples", 'queues_metadata', Gitlab::Redis::Queues
+ include_examples "redis_shared_examples"
+
+ describe '#pool' do
+ let(:config_new_format_host) { "spec/fixtures/config/redis_new_format_host.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_new_format_socket.yml" }
+
+ subject { described_class.pool }
+
+ around do |example|
+ clear_pool
+ example.run
+ ensure
+ clear_pool
+ end
+
+ before do
+ allow(described_class).to receive(:config_file_name).and_return(config_new_format_host)
+
+ allow(described_class).to receive(:config_file_name).and_return(config_new_format_host)
+ allow(Gitlab::Redis::Queues).to receive(:config_file_name).and_return(config_new_format_socket)
+ end
+
+ it 'instantiates an instance of MultiStore' do
+ subject.with do |redis_instance|
+ expect(redis_instance).to be_instance_of(::Gitlab::Redis::MultiStore)
+
+ expect(redis_instance.primary_store.connection[:id]).to eq("redis://test-host:6379/99")
+ expect(redis_instance.secondary_store.connection[:id]).to eq("unix:///path/to/redis.sock/0")
+
+ expect(redis_instance.instance_name).to eq('QueuesMetadata')
+ end
+ end
+
+ it_behaves_like 'multi store feature flags', :use_primary_and_secondary_stores_for_queues_metadata,
+ :use_primary_store_as_default_for_queues_metadata
+ end
+end
diff --git a/spec/lib/gitlab/redis/workhorse_spec.rb b/spec/lib/gitlab/redis/workhorse_spec.rb
new file mode 100644
index 00000000000..46931a6afcb
--- /dev/null
+++ b/spec/lib/gitlab/redis/workhorse_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Redis::Workhorse, feature_category: :scalability do
+ include_examples "redis_new_instance_shared_examples", 'workhorse', Gitlab::Redis::SharedState
+ include_examples "redis_shared_examples"
+
+ describe '#pool' do
+ let(:config_new_format_host) { "spec/fixtures/config/redis_new_format_host.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_new_format_socket.yml" }
+
+ subject { described_class.pool }
+
+ before do
+ allow(described_class).to receive(:config_file_name).and_return(config_new_format_host)
+
+ # Override rails root to avoid having our fixtures overwritten by `redis.yml` if it exists
+ allow(Gitlab::Redis::SharedState).to receive(:rails_root).and_return(mktmpdir)
+ allow(Gitlab::Redis::SharedState).to receive(:config_file_name).and_return(config_new_format_socket)
+ end
+
+ around do |example|
+ clear_pool
+ example.run
+ ensure
+ clear_pool
+ end
+
+ it 'instantiates an instance of MultiStore' do
+ subject.with do |redis_instance|
+ expect(redis_instance).to be_instance_of(::Gitlab::Redis::MultiStore)
+
+ expect(redis_instance.primary_store.connection[:id]).to eq("redis://test-host:6379/99")
+ expect(redis_instance.secondary_store.connection[:id]).to eq("unix:///path/to/redis.sock/0")
+
+ expect(redis_instance.instance_name).to eq('Workhorse')
+ end
+ end
+
+ it_behaves_like 'multi store feature flags', :use_primary_and_secondary_stores_for_workhorse,
+ :use_primary_store_as_default_for_workhorse
+ end
+end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index df123ef638f..02ae3f63918 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -86,31 +86,6 @@ RSpec.describe Gitlab::Regex, feature_category: :tooling do
it { is_expected.to match('<any-Charact3r$|any-Charact3r$>') }
end
- describe '.bulk_import_destination_namespace_path_regex_message' do
- subject { described_class.bulk_import_destination_namespace_path_regex_message }
-
- it {
- is_expected
- .to eq("must have a relative path structure with no HTTP " \
- "protocol characters, or leading or trailing forward slashes. Path segments must not start or " \
- "end with a special character, and must not contain consecutive special characters."
- )
- }
- end
-
- describe '.bulk_import_source_full_path_regex_message' do
- subject { described_class.bulk_import_source_full_path_regex_message }
-
- it {
- is_expected
- .to eq(
- "must have a relative path structure with no HTTP " \
- "protocol characters, or leading or trailing forward slashes. Path segments must not start or " \
- "end with a special character, and must not contain consecutive special characters."
- )
- }
- end
-
describe '.group_path_regex' do
subject { described_class.group_path_regex }
diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb
index 6cff0eff7e8..a4a7c139beb 100644
--- a/spec/lib/gitlab/repo_path_spec.rb
+++ b/spec/lib/gitlab/repo_path_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe ::Gitlab::RepoPath do
include Gitlab::Routing
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project_with_design, :repository) }
let_it_be(:personal_snippet) { create(:personal_snippet) }
let_it_be(:project_snippet) { create(:project_snippet, project: project) }
let_it_be(:redirect_route) { 'foo/bar/baz' }
@@ -28,6 +28,10 @@ RSpec.describe ::Gitlab::RepoPath do
it 'parses a project snippet repository path' do
expect(described_class.parse("#{project.full_path}/snippets/#{project_snippet.id}")).to eq([project_snippet, project, Gitlab::GlRepository::SNIPPET, nil])
end
+
+ it 'parses a full project design repository path' do
+ expect(described_class.parse(project.design_repository.full_path)).to match_array([project.design_management_repository, project, Gitlab::GlRepository::DESIGN, nil])
+ end
end
context 'a relative path' do
@@ -43,6 +47,10 @@ RSpec.describe ::Gitlab::RepoPath do
expect(described_class.parse('/' + project.full_path + '.git')).to eq([project, project, Gitlab::GlRepository::PROJECT, nil])
end
+ it 'parses a relative design repository path' do
+ expect(described_class.parse(project.full_path + '.design.git')).to match_array([project.design_management_repository, project, Gitlab::GlRepository::DESIGN, nil])
+ end
+
context 'of a redirected project' do
it 'parses a relative repository path' do
expect(described_class.parse(redirect.path + '.git')).to eq([project, project, Gitlab::GlRepository::PROJECT, redirect_route])
@@ -52,6 +60,10 @@ RSpec.describe ::Gitlab::RepoPath do
expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project.wiki, project, Gitlab::GlRepository::WIKI, "#{redirect_route}.wiki"])
end
+ it 'parses a relative design repository path' do
+ expect(described_class.parse(redirect.path + '.design.git')).to match_array([project.design_management_repository, project, Gitlab::GlRepository::DESIGN, "#{redirect_route}.design"])
+ end
+
it 'parses a relative path starting with /' do
expect(described_class.parse('/' + redirect.path + '.git')).to eq([project, project, Gitlab::GlRepository::PROJECT, redirect_route])
end
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index 725b7901e68..d1f19a5e1ba 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -16,8 +16,9 @@ RSpec.describe Gitlab::SearchResults, feature_category: :global_search do
let(:query) { 'foo' }
let(:filters) { {} }
let(:sort) { nil }
+ let(:limit_projects) { Project.order(:id) }
- subject(:results) { described_class.new(user, query, Project.order(:id), sort: sort, filters: filters) }
+ subject(:results) { described_class.new(user, query, limit_projects, sort: sort, filters: filters) }
context 'as a user with access' do
before do
@@ -236,9 +237,14 @@ RSpec.describe Gitlab::SearchResults, feature_category: :global_search do
let_it_be(:closed_result) { create(:issue, :closed, project: project, title: 'foo closed') }
let_it_be(:opened_result) { create(:issue, :opened, project: project, title: 'foo open') }
let_it_be(:confidential_result) { create(:issue, :confidential, project: project, title: 'foo confidential') }
+ let_it_be(:unarchived_project) { project }
+ let_it_be(:archived_project) { create(:project, :public, :archived) }
+ let_it_be(:unarchived_result) { create(:issue, project: unarchived_project, title: 'foo unarchived') }
+ let_it_be(:archived_result) { create(:issue, project: archived_project, title: 'foo archived') }
include_examples 'search results filtered by state'
include_examples 'search results filtered by confidential'
+ include_examples 'search results filtered by archived', 'search_issues_hide_archived_projects'
end
context 'ordering' do
@@ -274,7 +280,7 @@ RSpec.describe Gitlab::SearchResults, feature_category: :global_search do
let_it_be(:unarchived_result) { create(:project, :public, group: group, name: 'Test1') }
let_it_be(:archived_result) { create(:project, :archived, :public, group: group, name: 'Test2') }
- it_behaves_like 'search results filtered by archived', 'search_projects_hide_archived'
+ it_behaves_like 'search results filtered by archived'
end
end
@@ -433,26 +439,32 @@ RSpec.describe Gitlab::SearchResults, feature_category: :global_search do
end
context 'milestones' do
- it 'returns correct set of milestones' do
- private_project_1 = create(:project, :private)
- private_project_2 = create(:project, :private)
- internal_project = create(:project, :internal)
- public_project_1 = create(:project, :public)
- public_project_2 = create(:project, :public, :issues_disabled, :merge_requests_disabled)
+ let_it_be(:archived_project) { create(:project, :public, :archived) }
+ let_it_be(:private_project_1) { create(:project, :private) }
+ let_it_be(:private_project_2) { create(:project, :private) }
+ let_it_be(:internal_project) { create(:project, :internal) }
+ let_it_be(:public_project_1) { create(:project, :public) }
+ let_it_be(:public_project_2) { create(:project, :public, :issues_disabled, :merge_requests_disabled) }
+ let_it_be(:hidden_milestone_1) { create(:milestone, project: private_project_2, title: 'Private project without access milestone') }
+ let_it_be(:hidden_milestone_2) { create(:milestone, project: public_project_2, title: 'Public project with milestones disabled milestone') }
+ let_it_be(:hidden_milestone_3) { create(:milestone, project: archived_project, title: 'Milestone from an archived project') }
+ let_it_be(:milestone_1) { create(:milestone, project: private_project_1, title: 'Private project with access milestone', state: 'closed') }
+ let_it_be(:milestone_2) { create(:milestone, project: internal_project, title: 'Internal project milestone') }
+ let_it_be(:milestone_3) { create(:milestone, project: public_project_1, title: 'Public project with milestones enabled milestone') }
+ let(:unarchived_result) { milestone_1 }
+ let(:archived_result) { hidden_milestone_3 }
+ let(:limit_projects) { ProjectsFinder.new(current_user: user).execute }
+ let(:query) { 'milestone' }
+ let(:scope) { 'milestones' }
+
+ before do
private_project_1.add_developer(user)
- # milestones that should not be visible
- create(:milestone, project: private_project_2, title: 'Private project without access milestone')
- create(:milestone, project: public_project_2, title: 'Public project with milestones disabled milestone')
- # milestones that should be visible
- milestone_1 = create(:milestone, project: private_project_1, title: 'Private project with access milestone', state: 'closed')
- milestone_2 = create(:milestone, project: internal_project, title: 'Internal project milestone')
- milestone_3 = create(:milestone, project: public_project_1, title: 'Public project with milestones enabled milestone')
- # Global search scope takes user authorized projects, internal projects and public projects.
- limit_projects = ProjectsFinder.new(current_user: user).execute
-
- milestones = described_class.new(user, 'milestone', limit_projects).objects('milestones')
-
- expect(milestones).to match_array([milestone_1, milestone_2, milestone_3])
end
+
+ it 'returns correct set of milestones' do
+ expect(results.objects(scope)).to match_array([milestone_1, milestone_2, milestone_3])
+ end
+
+ include_examples 'search results filtered by archived', 'search_milestones_hide_archived_projects'
end
end
diff --git a/spec/lib/gitlab/security/scan_configuration_spec.rb b/spec/lib/gitlab/security/scan_configuration_spec.rb
index 774a362617a..faa8a206d74 100644
--- a/spec/lib/gitlab/security/scan_configuration_spec.rb
+++ b/spec/lib/gitlab/security/scan_configuration_spec.rb
@@ -57,6 +57,16 @@ RSpec.describe ::Gitlab::Security::ScanConfiguration do
it { is_expected.to be_nil }
end
+ describe '#on_demand_available?' do
+ subject { scan.on_demand_available? }
+
+ let(:configured) { true }
+ let(:available) { true }
+ let(:type) { :sast }
+
+ it { is_expected.to be_falsey }
+ end
+
describe '#can_enable_by_merge_request?' do
subject { scan.can_enable_by_merge_request? }
diff --git a/spec/lib/gitlab/setup_helper/workhorse_spec.rb b/spec/lib/gitlab/setup_helper/workhorse_spec.rb
index 726b73a9dfe..e5a44abc731 100644
--- a/spec/lib/gitlab/setup_helper/workhorse_spec.rb
+++ b/spec/lib/gitlab/setup_helper/workhorse_spec.rb
@@ -24,8 +24,8 @@ RSpec.describe Gitlab::SetupHelper::Workhorse do
end
describe '.redis_url' do
- it 'matches the SharedState URL' do
- expect(Gitlab::Redis::SharedState).to receive(:url).and_return('foo')
+ it 'matches the Workhorse URL' do
+ expect(Gitlab::Redis::Workhorse).to receive(:url).and_return('foo')
expect(described_class.redis_url).to eq('foo')
end
@@ -34,14 +34,14 @@ RSpec.describe Gitlab::SetupHelper::Workhorse do
describe '.redis_db' do
subject { described_class.redis_db }
- it 'matches the SharedState DB' do
- expect(Gitlab::Redis::SharedState).to receive(:params).and_return(db: 1)
+ it 'matches the Workhorse DB' do
+ expect(Gitlab::Redis::Workhorse).to receive(:params).and_return(db: 1)
is_expected.to eq(1)
end
it 'defaults to 0 if unspecified' do
- expect(Gitlab::Redis::SharedState).to receive(:params).and_return({})
+ expect(Gitlab::Redis::Workhorse).to receive(:params).and_return({})
is_expected.to eq(0)
end
diff --git a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb
index 14eb568b974..3ae1236cc7c 100644
--- a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::Client, :clean_gitlab_redis_queues,
-:clean_gitlab_redis_shared_state do
+:clean_gitlab_redis_queues_metadata do
shared_context 'deduplication worker class' do |strategy, including_scheduled|
let(:worker_class) do
Class.new do
diff --git a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
index c22e7a1240f..937a1751cc7 100644
--- a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gitlab_redis_queues, :clean_gitlab_redis_shared_state,
+RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob,
+ :clean_gitlab_redis_queues, :clean_gitlab_redis_shared_state, :clean_gitlab_redis_queues_metadata,
feature_category: :shared do
using RSpec::Parameterized::TableSyntax
@@ -78,11 +79,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
end
end
- context 'with Redis cookies' do
- def with_redis(&block)
- Gitlab::Redis::Queues.with(&block)
- end
-
+ shared_examples 'with Redis cookies' do
let(:cookie_key) { "#{Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE}:#{idempotency_key}:cookie:v2" }
let(:cookie) { get_redis_msgpack(cookie_key) }
@@ -416,6 +413,62 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
end
end
+ context 'with multi-store feature flags turned on' do
+ def with_redis(&block)
+ Gitlab::Redis::QueuesMetadata.with(&block)
+ end
+
+ shared_examples 'uses QueuesMetadata' do
+ it 'use Gitlab::Redis::QueuesMetadata.with' do
+ expect(Gitlab::Redis::QueuesMetadata).to receive(:with).and_call_original
+ expect(Gitlab::Redis::Queues).not_to receive(:with)
+
+ duplicate_job.check!
+ end
+ end
+
+ context 'when migration is ongoing with double-write' do
+ before do
+ stub_feature_flags(use_primary_store_as_default_for_queues_metadata: false)
+ end
+
+ it_behaves_like 'uses QueuesMetadata'
+ it_behaves_like 'with Redis cookies'
+ end
+
+ context 'when migration is completed' do
+ before do
+ stub_feature_flags(use_primary_and_secondary_stores_for_queues_metadata: false)
+ end
+
+ it_behaves_like 'uses QueuesMetadata'
+ it_behaves_like 'with Redis cookies'
+ end
+
+ it_behaves_like 'uses QueuesMetadata'
+ it_behaves_like 'with Redis cookies'
+ end
+
+ context 'when both multi-store feature flags are off' do
+ def with_redis(&block)
+ Gitlab::Redis::Queues.with(&block)
+ end
+
+ before do
+ stub_feature_flags(use_primary_and_secondary_stores_for_queues_metadata: false)
+ stub_feature_flags(use_primary_store_as_default_for_queues_metadata: false)
+ end
+
+ it 'use Gitlab::Redis::Queues' do
+ expect(Gitlab::Redis::Queues).to receive(:with).and_call_original
+ expect(Gitlab::Redis::QueuesMetadata).not_to receive(:with)
+
+ duplicate_job.check!
+ end
+
+ it_behaves_like 'with Redis cookies'
+ end
+
describe '#scheduled?' do
it 'returns false for non-scheduled jobs' do
expect(duplicate_job.scheduled?).to be(false)
diff --git a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
index 0cbf9eab3d8..a27e723e392 100644
--- a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
@@ -402,11 +402,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
include Sidekiq::Worker
include WorkerAttributes
- if category
- feature_category category
- else
- feature_category :not_owned
- end
+ feature_category category || :not_owned
def perform; end
end
diff --git a/spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb b/spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb
index c66e36c5621..bf379d9cb0d 100644
--- a/spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb
+++ b/spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
+RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues,
+ :clean_gitlab_redis_queues_metadata do
def clear_queues
Sidekiq::Queue.new('authorized_projects').clear
Sidekiq::Queue.new('post_receive').clear
diff --git a/spec/lib/gitlab/sidekiq_queue_spec.rb b/spec/lib/gitlab/sidekiq_queue_spec.rb
index 93632848788..8ceba7ca4b7 100644
--- a/spec/lib/gitlab/sidekiq_queue_spec.rb
+++ b/spec/lib/gitlab/sidekiq_queue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::SidekiqQueue, :clean_gitlab_redis_queues do
+RSpec.describe Gitlab::SidekiqQueue, :clean_gitlab_redis_queues, :clean_gitlab_redis_queues_metadata do
around do |example|
Sidekiq::Queue.new('foobar').clear
Sidekiq::Testing.disable!(&example)
diff --git a/spec/lib/gitlab/sql/cte_spec.rb b/spec/lib/gitlab/sql/cte_spec.rb
index 523380eae34..d2d3fdbb450 100644
--- a/spec/lib/gitlab/sql/cte_spec.rb
+++ b/spec/lib/gitlab/sql/cte_spec.rb
@@ -15,8 +15,7 @@ RSpec.describe Gitlab::SQL::CTE do
expected = [
"#{name} AS ",
- Gitlab::Database::AsWithMaterialized.materialized_if_supported,
- (' ' unless Gitlab::Database::AsWithMaterialized.materialized_if_supported.blank?),
+ 'MATERIALIZED ',
"(#{sql1})"
].join
diff --git a/spec/lib/gitlab/sql/pattern_spec.rb b/spec/lib/gitlab/sql/pattern_spec.rb
index a34ddf8773c..7bd2ddf2889 100644
--- a/spec/lib/gitlab/sql/pattern_spec.rb
+++ b/spec/lib/gitlab/sql/pattern_spec.rb
@@ -9,36 +9,44 @@ RSpec.describe Gitlab::SQL::Pattern do
let_it_be(:issue1) { create(:issue, title: 'noise foo noise', description: 'noise bar noise') }
let_it_be(:issue2) { create(:issue, title: 'noise baz noise', description: 'noise foo noise') }
let_it_be(:issue3) { create(:issue, title: 'Oh', description: 'Ah') }
+ let_it_be(:issue4) { create(:issue, title: 'beep beep', description: 'beep beep') }
+ let_it_be(:issue5) { create(:issue, title: 'beep', description: 'beep') }
- subject(:fuzzy_search) { Issue.fuzzy_search(query, columns) }
+ subject(:fuzzy_search) { Issue.fuzzy_search(query, columns, exact_matches_first: exact_matches_first) }
- where(:query, :columns, :expected) do
- 'foo' | [Issue.arel_table[:title]] | %i[issue1]
+ where(:query, :columns, :exact_matches_first, :expected) do
+ 'foo' | [Issue.arel_table[:title]] | false | %i[issue1]
- 'foo' | %i[title] | %i[issue1]
- 'foo' | %w[title] | %i[issue1]
- 'foo' | %i[description] | %i[issue2]
- 'foo' | %i[title description] | %i[issue1 issue2]
- 'bar' | %i[title description] | %i[issue1]
- 'baz' | %i[title description] | %i[issue2]
- 'qux' | %i[title description] | []
+ 'foo' | %i[title] | false | %i[issue1]
+ 'foo' | %w[title] | false | %i[issue1]
+ 'foo' | %i[description] | false | %i[issue2]
+ 'foo' | %i[title description] | false | %i[issue1 issue2]
+ 'bar' | %i[title description] | false | %i[issue1]
+ 'baz' | %i[title description] | false | %i[issue2]
+ 'qux' | %i[title description] | false | []
- 'oh' | %i[title description] | %i[issue3]
- 'OH' | %i[title description] | %i[issue3]
- 'ah' | %i[title description] | %i[issue3]
- 'AH' | %i[title description] | %i[issue3]
- 'oh' | %i[title] | %i[issue3]
- 'ah' | %i[description] | %i[issue3]
+ 'oh' | %i[title description] | false | %i[issue3]
+ 'OH' | %i[title description] | false | %i[issue3]
+ 'ah' | %i[title description] | false | %i[issue3]
+ 'AH' | %i[title description] | false | %i[issue3]
+ 'oh' | %i[title] | false | %i[issue3]
+ 'ah' | %i[description] | false | %i[issue3]
- '' | %i[title] | %i[issue1 issue2 issue3]
- %w[a b] | %i[title] | %i[issue1 issue2 issue3]
+ '' | %i[title] | false | %i[issue1 issue2 issue3 issue4 issue5]
+ %w[a b] | %i[title] | false | %i[issue1 issue2 issue3 issue4 issue5]
+
+ 'beep' | %i[title] | true | %i[issue5 issue4]
end
with_them do
let(:expected_issues) { expected.map { |sym| send(sym) } }
it 'finds the expected issues' do
- expect(fuzzy_search).to match_array(expected_issues)
+ if exact_matches_first
+ expect(fuzzy_search).to eq(expected_issues)
+ else
+ expect(fuzzy_search).to match_array(expected_issues)
+ end
end
end
end
diff --git a/spec/lib/gitlab/time_tracking_formatter_spec.rb b/spec/lib/gitlab/time_tracking_formatter_spec.rb
index aa755d64a7a..b3372f676d4 100644
--- a/spec/lib/gitlab/time_tracking_formatter_spec.rb
+++ b/spec/lib/gitlab/time_tracking_formatter_spec.rb
@@ -28,6 +28,14 @@ RSpec.describe Gitlab::TimeTrackingFormatter, feature_category: :team_planning d
end
end
+ context 'when the duration is nil' do
+ let(:duration_string) { nil }
+
+ it 'returns nil' do
+ expect(subject).to be_nil
+ end
+ end
+
context 'when the duration is zero' do
let(:duration_string) { '0h' }
diff --git a/spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb b/spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb
index 78a869b535a..5a5c7123971 100644
--- a/spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb
+++ b/spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb
@@ -63,6 +63,10 @@ RSpec.describe Gitlab::Tracking::Destinations::DatabaseEventsSnowplow, :do_not_s
context 'when on gitlab.com environment' do
let(:endpoint) { 'db-snowplow.trx.gitlab.net' }
+ before do
+ stub_application_setting(snowplow_database_collector_hostname: endpoint)
+ end
+
it 'sends event to tracker' do
allow(Gitlab).to receive(:com?).and_return(true)
allow(tracker).to receive(:track_struct_event).and_call_original
diff --git a/spec/lib/gitlab/tracking/service_ping_context_spec.rb b/spec/lib/gitlab/tracking/service_ping_context_spec.rb
index 7530650b902..3da9a588c0e 100644
--- a/spec/lib/gitlab/tracking/service_ping_context_spec.rb
+++ b/spec/lib/gitlab/tracking/service_ping_context_spec.rb
@@ -7,29 +7,27 @@ RSpec.describe Gitlab::Tracking::ServicePingContext do
using RSpec::Parameterized::TableSyntax
context 'with valid configuration' do
- where(:data_source, :event, :key_path) do
- :redis | nil | 'counts.some_metric'
- :redis_hll | 'some_event' | nil
+ where(:data_source, :event) do
+ :redis | 'some_event'
+ :redis_hll | 'some_event'
end
with_them do
it 'does not raise errors' do
- expect { described_class.new(data_source: data_source, event: event, key_path: key_path) }.not_to raise_error
+ expect { described_class.new(data_source: data_source, event: event) }.not_to raise_error
end
end
end
context 'with invalid configuration' do
- where(:data_source, :event, :key_path) do
- :redis | nil | nil
- :redis | 'some_event' | nil
- :redis_hll | nil | nil
- :redis_hll | nil | 'some key_path'
- :random | 'some_event' | nil
+ where(:data_source, :event) do
+ :redis | nil
+ :redis_hll | nil
+ :random | 'some_event'
end
with_them do
- subject(:new_instance) { described_class.new(data_source: data_source, event: event, key_path: key_path) }
+ subject(:new_instance) { described_class.new(data_source: data_source, event: event) }
it 'does not raise errors' do
expect { new_instance }.to raise_error(ArgumentError)
@@ -48,10 +46,10 @@ RSpec.describe Gitlab::Tracking::ServicePingContext do
end
context 'for redis data source' do
- let(:context_instance) { described_class.new(data_source: :redis, key_path: 'counts.sample_metric') }
+ let(:context_instance) { described_class.new(data_source: :redis, event: 'some_event') }
it 'contains event_name' do
- expect(context_instance.to_context.to_json.dig(:data, :key_path)).to eq('counts.sample_metric')
+ expect(context_instance.to_context.to_json.dig(:data, :event_name)).to eq('some_event')
end
end
end
diff --git a/spec/lib/gitlab/tracking/standard_context_spec.rb b/spec/lib/gitlab/tracking/standard_context_spec.rb
index c44cfdea1cd..4485a30ae66 100644
--- a/spec/lib/gitlab/tracking/standard_context_spec.rb
+++ b/spec/lib/gitlab/tracking/standard_context_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Tracking::StandardContext do
+RSpec.describe Gitlab::Tracking::StandardContext, feature_category: :service_ping do
let(:snowplow_context) { subject.to_context }
describe '#to_context' do
@@ -76,6 +76,7 @@ RSpec.describe Gitlab::Tracking::StandardContext do
it 'holds the correct values', :aggregate_failures do
json_data = snowplow_context.to_json.fetch(:data)
expect(json_data[:user_id]).to eq(user_id)
+ expect(json_data[:is_gitlab_team_member]).to eq(nil)
expect(json_data[:project_id]).to eq(project_id)
expect(json_data[:namespace_id]).to eq(namespace_id)
expect(json_data[:plan]).to eq(plan_name)
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index 73627d3e6ff..865a8384405 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -32,6 +32,9 @@ RSpec.describe Gitlab::UrlBuilder do
:ci_build | ->(build) { "/#{build.project.full_path}/-/jobs/#{build.id}" }
:design | ->(design) { "/#{design.project.full_path}/-/design_management/designs/#{design.id}/raw_image" }
+ [:issue, :group_level] | ->(issue) { "/groups/#{issue.namespace.full_path}/-/work_items/#{issue.iid}" }
+ [:work_item, :group_level] | ->(work_item) { "/groups/#{work_item.namespace.full_path}/-/work_items/#{work_item.iid}" }
+
:group | ->(group) { "/groups/#{group.full_path}" }
:group_milestone | ->(milestone) { "/groups/#{milestone.group.full_path}/-/milestones/#{milestone.iid}" }
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
index 5f76c1de5b1..2c2ef8f13fb 100644
--- a/spec/lib/gitlab/url_sanitizer_spec.rb
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -91,6 +91,25 @@ RSpec.describe Gitlab::UrlSanitizer do
end
end
+ describe '.sanitize_masked_url' do
+ where(:original_url, :masked_url) do
+ 'http://{domain}.com' | 'http://{domain}.com'
+ 'http://{domain}/{hook}' | 'http://{domain}/{hook}'
+ 'http://user:pass@{domain}/hook' | 'http://*****:*****@{domain}/hook'
+ 'http://user:pass@{domain}:{port}/hook' | 'http://*****:*****@{domain}:{port}/hook'
+ 'http://user:@{domain}:{port}/hook' | 'http://*****:*****@{domain}:{port}/hook'
+ 'http://:pass@{domain}:{port}/hook' | 'http://*****:*****@{domain}:{port}/hook'
+ 'http://user@{domain}:{port}/hook' | 'http://*****:*****@{domain}:{port}/hook'
+ 'http://u:p@{domain}/hook?email=james@example.com' | 'http://*****:*****@{domain}/hook?email=james@example.com'
+ 'http://{domain}/hook?email=james@example.com' | 'http://{domain}/hook?email=james@example.com'
+ 'http://user:{pass}@example.com' | 'http://*****:*****@example.com'
+ end
+
+ with_them do
+ it { expect(described_class.sanitize_masked_url(original_url)).to eq(masked_url) }
+ end
+ end
+
describe '#sanitized_url' do
context 'credentials in hash' do
where(username: ['foo', '', nil], password: ['bar', '', nil])
diff --git a/spec/lib/gitlab/usage/metric_definition_spec.rb b/spec/lib/gitlab/usage/metric_definition_spec.rb
index 859f3f7a8d7..6695736e54c 100644
--- a/spec/lib/gitlab/usage/metric_definition_spec.rb
+++ b/spec/lib/gitlab/usage/metric_definition_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Usage::MetricDefinition do
+RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping do
let(:attributes) do
{
description: 'GitLab instance unique identifier',
@@ -109,6 +109,42 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
end
end
+ describe '#to_context' do
+ subject { definition.to_context }
+
+ context 'with data_source redis_hll metric' do
+ before do
+ attributes[:data_source] = 'redis_hll'
+ attributes[:options] = { events: %w[some_event_1 some_event_2] }
+ end
+
+ it 'returns a ServicePingContext with first event as event_name' do
+ expect(subject.to_h[:data][:event_name]).to eq('some_event_1')
+ end
+ end
+
+ context 'with data_source redis metric' do
+ before do
+ attributes[:data_source] = 'redis'
+ attributes[:options] = { prefix: 'web_ide', event: 'views_count', include_usage_prefix: false }
+ end
+
+ it 'returns a ServicePingContext with redis key as event_name' do
+ expect(subject.to_h[:data][:event_name]).to eq('WEB_IDE_VIEWS_COUNT')
+ end
+ end
+
+ context 'with data_source database metric' do
+ before do
+ attributes[:data_source] = 'database'
+ end
+
+ it 'returns nil' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
describe '#validate' do
using RSpec::Parameterized::TableSyntax
@@ -117,7 +153,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
:value_type | nil
:value_type | 'test'
:status | nil
- :milestone | nil
+ :milestone | 10.0
:data_category | nil
:key_path | nil
:product_group | nil
@@ -233,26 +269,6 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
end
end
- describe 'statuses' do
- using RSpec::Parameterized::TableSyntax
-
- where(:status, :skip_validation?) do
- 'active' | false
- 'broken' | false
- 'removed' | true
- end
-
- with_them do
- subject(:validation) do
- described_class.new(path, attributes.merge( { status: status } )).send(:skip_validation?)
- end
-
- it 'returns true/false for skip_validation' do
- expect(validation).to eq(skip_validation?)
- end
- end
- end
-
describe '.load_all!' do
let(:metric1) { Dir.mktmpdir('metric1') }
let(:metric2) { Dir.mktmpdir('metric2') }
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb
index e66dd04b69b..4544a3a60a1 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/batched_background_migration_failed_jobs_metric_spec.rb
@@ -18,6 +18,20 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::BatchedBackgroundMigrat
]
end
+ let(:start) { 9.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
+
+ let(:expected_query) do
+ "SELECT \"batched_background_migrations\".\"table_name\", \"batched_background_migrations\".\"job_class_name\", " \
+ "COUNT(batched_jobs) AS number_of_failed_jobs " \
+ "FROM \"batched_background_migrations\" " \
+ "INNER JOIN \"batched_background_migration_jobs\" \"batched_jobs\" " \
+ "ON \"batched_jobs\".\"batched_background_migration_id\" = \"batched_background_migrations\".\"id\" " \
+ "WHERE \"batched_jobs\".\"status\" = 2 " \
+ "AND \"batched_background_migrations\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' " \
+ "GROUP BY \"batched_background_migrations\".\"table_name\", \"batched_background_migrations\".\"job_class_name\""
+ end
+
let_it_be(:active_migration) do
create(:batched_background_migration, :active, table_name: 'users', job_class_name: 'test', created_at: 5.days.ago)
end
@@ -36,5 +50,5 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::BatchedBackgroundMigrat
let_it_be(:old_batched_job) { create(:batched_background_migration_job, :failed, batched_migration: old_migration) }
- it_behaves_like 'a correct instrumented metric value', { time_frame: '7d' }
+ it_behaves_like 'a correct instrumented metric value and query', { time_frame: '7d' }
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_connected_agents_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_connected_agents_metric_spec.rb
new file mode 100644
index 00000000000..208d5c259ca
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_connected_agents_metric_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountConnectedAgentsMetric, feature_category: :service_ping do
+ let_it_be(:agent_token_connected) { create(:cluster_agent_token, :active, last_used_at: 2.minutes.ago) }
+ let_it_be(:agent_token_disconnected) { create(:cluster_agent_token) }
+
+ let(:expected_value) { 1 }
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }
+end
diff --git a/spec/lib/gitlab/usage/metrics/query_spec.rb b/spec/lib/gitlab/usage/metrics/query_spec.rb
index 355d619f768..750d340551a 100644
--- a/spec/lib/gitlab/usage/metrics/query_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/query_spec.rb
@@ -77,7 +77,7 @@ RSpec.describe Gitlab::Usage::Metrics::Query do
it 'returns the histogram sql' do
expect(described_class.for(:histogram, AlertManagement::HttpIntegration.active,
:project_id, buckets: 1..2, bucket_size: 101))
- .to match(/^WITH "count_cte" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
+ .to match(/^WITH "count_cte" AS MATERIALIZED/)
end
end
diff --git a/spec/lib/gitlab/usage/time_series_storable_spec.rb b/spec/lib/gitlab/usage/time_series_storable_spec.rb
new file mode 100644
index 00000000000..420a87c5483
--- /dev/null
+++ b/spec/lib/gitlab/usage/time_series_storable_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::TimeSeriesStorable, feature_category: :service_ping do
+ let(:counter_class) do
+ Class.new do
+ include Gitlab::Usage::TimeSeriesStorable
+
+ def redis_key(event, date)
+ key = apply_time_aggregation(event, date)
+ "#{key}:"
+ end
+ end
+ end
+
+ let(:counter_instance) { counter_class.new }
+
+ describe '#apply_time_aggregation' do
+ let(:key) { "key3" }
+ let(:time) { Date.new(2023, 5, 1) }
+
+ it 'returns proper key for given time' do
+ expect(counter_instance.apply_time_aggregation(key, time)).to eq("key3-2023-18")
+ end
+ end
+
+ describe '#keys_for_aggregation' do
+ let(:result) { counter_instance.keys_for_aggregation(**params) }
+ let(:params) { base_params }
+ let(:base_params) { { events: events, start_date: start_date, end_date: end_date } }
+ let(:events) { %w[event1 event2] }
+ let(:start_date) { Date.new(2023, 4, 1) }
+ let(:end_date) { Date.new(2023, 4, 15) }
+
+ it 'returns proper keys' do
+ expect(result).to match_array(["event1-2023-13:", "event1-2023-14:", "event2-2023-13:", "event2-2023-14:"])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
index 11c6ea2fc9d..eeef9406841 100644
--- a/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter do
+RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter, feature_category: :pipeline_composition do
describe '.track_unique_project_event' do
using RSpec::Parameterized::TableSyntax
include SnowplowHelpers
diff --git a/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
index 50e20e4fbcf..21a820deaa4 100644
--- a/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
@@ -3,304 +3,244 @@
require 'spec_helper'
RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_gitlab_redis_shared_state do
- let_it_be(:user1) { build(:user, id: 1) }
+ let_it_be(:user) { build(:user, id: 1) }
let_it_be(:user2) { build(:user, id: 2) }
let_it_be(:user3) { build(:user, id: 3) }
let_it_be(:project) { create(:project) }
- let_it_be(:category) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CATEGORY }
- let_it_be(:event_action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_ACTION }
- let_it_be(:event_label) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_LABEL }
- let(:original_params) { nil }
- let(:event_property) { action }
let(:time) { Time.zone.now }
+ let(:namespace) { project&.namespace }
context 'for Issue title edit actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_TITLE_CHANGED }
- def track_action(params)
- described_class.track_issue_title_changed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_title_changed_action(author: user, project: project) }
end
end
context 'for Issue description edit actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_DESCRIPTION_CHANGED }
- def track_action(params)
- described_class.track_issue_description_changed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_description_changed_action(author: user, project: project) }
end
end
context 'for Issue assignee edit actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_ASSIGNEE_CHANGED }
- def track_action(params)
- described_class.track_issue_assignee_changed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_assignee_changed_action(author: user, project: project) }
end
end
context 'for Issue make confidential actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_MADE_CONFIDENTIAL }
- def track_action(params)
- described_class.track_issue_made_confidential_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_made_confidential_action(author: user, project: project) }
end
end
context 'for Issue make visible actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_MADE_VISIBLE }
- def track_action(params)
- described_class.track_issue_made_visible_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_made_visible_action(author: user, project: project) }
end
end
context 'for Issue created actions' do
- it_behaves_like 'tracked issuable internal event with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_CREATED }
- let(:original_params) { { namespace: project.project_namespace.reload } }
+ let(:project) { nil }
- def track_action(params)
- described_class.track_issue_created_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_created_action(author: user, namespace: namespace) }
end
end
context 'for Issue closed actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_CLOSED }
- def track_action(params)
- described_class.track_issue_closed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_closed_action(author: user, project: project) }
end
end
context 'for Issue reopened actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_REOPENED }
- def track_action(params)
- described_class.track_issue_reopened_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_reopened_action(author: user, project: project) }
end
end
context 'for Issue label changed actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_LABEL_CHANGED }
- def track_action(params)
- described_class.track_issue_label_changed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_label_changed_action(author: user, project: project) }
end
end
context 'for Issue label milestone actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_MILESTONE_CHANGED }
- def track_action(params)
- described_class.track_issue_milestone_changed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_milestone_changed_action(author: user, project: project) }
end
end
context 'for Issue cross-referenced actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_CROSS_REFERENCED }
- def track_action(params)
- described_class.track_issue_cross_referenced_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_cross_referenced_action(author: user, project: project) }
end
end
context 'for Issue moved actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_MOVED }
- def track_action(params)
- described_class.track_issue_moved_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_moved_action(author: user, project: project) }
end
end
context 'for Issue cloned actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
- let_it_be(:action) { described_class::ISSUE_CLONED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { described_class::ISSUE_CLONED }
- def track_action(params)
- described_class.track_issue_cloned_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_cloned_action(author: user, project: project) }
end
end
context 'for Issue relate actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_RELATED }
- def track_action(params)
- described_class.track_issue_related_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_related_action(author: user, project: project) }
end
end
context 'for Issue unrelate actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_UNRELATED }
- def track_action(params)
- described_class.track_issue_unrelated_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_unrelated_action(author: user, project: project) }
end
end
context 'for Issue marked as duplicate actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_MARKED_AS_DUPLICATE }
- def track_action(params)
- described_class.track_issue_marked_as_duplicate_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_marked_as_duplicate_action(author: user, project: project) }
end
end
context 'for Issue locked actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_LOCKED }
- def track_action(params)
- described_class.track_issue_locked_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_locked_action(author: user, project: project) }
end
end
context 'for Issue unlocked actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_UNLOCKED }
- def track_action(params)
- described_class.track_issue_unlocked_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_unlocked_action(author: user, project: project) }
end
end
context 'for Issue designs added actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_DESIGNS_ADDED }
- def track_action(params)
- described_class.track_issue_designs_added_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_designs_added_action(author: user, project: project) }
end
end
context 'for Issue designs modified actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_DESIGNS_MODIFIED }
- def track_action(params)
- described_class.track_issue_designs_modified_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_designs_modified_action(author: user, project: project) }
end
end
context 'for Issue designs removed actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_DESIGNS_REMOVED }
- def track_action(params)
- described_class.track_issue_designs_removed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_designs_removed_action(author: user, project: project) }
end
end
context 'for Issue due date changed actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_DUE_DATE_CHANGED }
- def track_action(params)
- described_class.track_issue_due_date_changed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_due_date_changed_action(author: user, project: project) }
end
end
context 'for Issue time estimate changed actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_TIME_ESTIMATE_CHANGED }
- def track_action(params)
- described_class.track_issue_time_estimate_changed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_time_estimate_changed_action(author: user, project: project) }
end
end
context 'for Issue time spent changed actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_TIME_SPENT_CHANGED }
- def track_action(params)
- described_class.track_issue_time_spent_changed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_time_spent_changed_action(author: user, project: project) }
end
end
context 'for Issue comment added actions', :snowplow do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_COMMENT_ADDED }
- def track_action(params)
- described_class.track_issue_comment_added_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_comment_added_action(author: user, project: project) }
end
end
context 'for Issue comment edited actions', :snowplow do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_COMMENT_EDITED }
- def track_action(params)
- described_class.track_issue_comment_edited_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_comment_edited_action(author: user, project: project) }
end
end
context 'for Issue comment removed actions', :snowplow do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_COMMENT_REMOVED }
- def track_action(params)
- described_class.track_issue_comment_removed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_comment_removed_action(author: user, project: project) }
end
end
context 'for Issue design comment removed actions' do
- it_behaves_like 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'internal event tracking' do
let(:action) { described_class::ISSUE_DESIGN_COMMENT_REMOVED }
- def track_action(params)
- described_class.track_issue_design_comment_removed_action(**params)
- end
+ subject(:track_event) { described_class.track_issue_design_comment_removed_action(author: user, project: project) }
end
end
it 'can return the count of actions per user deduplicated' do
travel_to(Date.today.beginning_of_week) do # because events aggregated by week we need to emit events in the same week
- described_class.track_issue_title_changed_action(author: user1, project: project)
- described_class.track_issue_description_changed_action(author: user1, project: project)
- described_class.track_issue_assignee_changed_action(author: user1, project: project)
+ described_class.track_issue_title_changed_action(author: user, project: project)
+ described_class.track_issue_description_changed_action(author: user, project: project)
+ described_class.track_issue_assignee_changed_action(author: user, project: project)
end
travel_to(Date.today.beginning_of_week + 2.days) do
diff --git a/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
index 9562f1c5500..1ea2ea144df 100644
--- a/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
@@ -15,7 +15,8 @@ RSpec.describe Gitlab::UsageDataCounters::KubernetesAgentCounter do
'k8s_api_proxy_request' => 2,
'flux_git_push_notifications_total' => 3,
'k8s_api_proxy_requests_via_ci_access' => 4,
- 'k8s_api_proxy_requests_via_user_access' => 5
+ 'k8s_api_proxy_requests_via_user_access' => 5,
+ 'k8s_api_proxy_requests_via_pat_access' => 6
}
end
@@ -31,7 +32,8 @@ RSpec.describe Gitlab::UsageDataCounters::KubernetesAgentCounter do
kubernetes_agent_k8s_api_proxy_request: 6,
kubernetes_agent_flux_git_push_notifications_total: 9,
kubernetes_agent_k8s_api_proxy_requests_via_ci_access: 12,
- kubernetes_agent_k8s_api_proxy_requests_via_user_access: 15
+ kubernetes_agent_k8s_api_proxy_requests_via_user_access: 15,
+ kubernetes_agent_k8s_api_proxy_requests_via_pat_access: 18
)
end
diff --git a/spec/lib/gitlab/usage_data_queries_spec.rb b/spec/lib/gitlab/usage_data_queries_spec.rb
index 30588324adf..3ec7bf33623 100644
--- a/spec/lib/gitlab/usage_data_queries_spec.rb
+++ b/spec/lib/gitlab/usage_data_queries_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe Gitlab::UsageDataQueries do
it 'returns the histogram sql' do
expect(described_class.histogram(AlertManagement::HttpIntegration.active,
:project_id, buckets: 1..2, bucket_size: 101))
- .to match(/^WITH "count_cte" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
+ .to match(/^WITH "count_cte" AS MATERIALIZED/)
end
end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 94c4544f754..143d0484392 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -397,7 +397,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
user = create(:user)
project = create(:project, creator: user)
issue = create(:issue, project: project, author: user)
- create(:issue, project: project, author: User.support_bot)
+ create(:issue, project: project, author: Users::Internal.support_bot)
create(:note, project: project, noteable: issue, author: user)
create(:todo, project: project, target: issue, author: user)
create(:jira_integration, :jira_cloud_service, active: true, project: create(:project, :jira_dvcs_cloud, creator: user))
@@ -431,7 +431,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
user = create(:user)
project = create(:project, creator: user)
create(:issue, project: project, author: user)
- create(:issue, project: project, author: User.support_bot)
+ create(:issue, project: project, author: Users::Internal.support_bot)
end
expect(described_class.usage_activity_by_stage_plan({})).to include(issues: 3)
@@ -556,7 +556,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
expect(count_data[:issues_using_zoom_quick_actions]).to eq(3)
expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2)
expect(count_data[:incident_issues]).to eq(4)
- expect(count_data[:issues_created_from_alerts]).to eq(3)
+ expect(count_data[:issues_created_from_alerts]).to eq(2)
expect(count_data[:alert_bot_incident_issues]).to eq(4)
expect(count_data[:clusters_enabled]).to eq(6)
expect(count_data[:project_clusters_enabled]).to eq(4)
@@ -883,7 +883,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures, feature_category: :servic
let(:project) { create(:project, :service_desk_enabled) }
it 'gathers Service Desk data' do
- create_list(:issue, 2, :confidential, author: User.support_bot, project: project)
+ create_list(:issue, 2, :confidential, author: Users::Internal.support_bot, project: project)
expect(subject).to eq(service_desk_enabled_projects: 1,
service_desk_issues: 2)
diff --git a/spec/lib/gitlab/user_access_snippet_spec.rb b/spec/lib/gitlab/user_access_snippet_spec.rb
index 916e920e2ac..fd71a6ce0a5 100644
--- a/spec/lib/gitlab/user_access_snippet_spec.rb
+++ b/spec/lib/gitlab/user_access_snippet_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Gitlab::UserAccessSnippet do
let_it_be(:project) { create(:project, :private) }
let_it_be(:snippet) { create(:project_snippet, :private, project: project) }
- let_it_be(:migration_bot) { User.migration_bot }
+ let_it_be(:migration_bot) { Users::Internal.migration_bot }
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/utils/markdown_spec.rb b/spec/lib/gitlab/utils/markdown_spec.rb
index 45953c7906e..d707cf51712 100644
--- a/spec/lib/gitlab/utils/markdown_spec.rb
+++ b/spec/lib/gitlab/utils/markdown_spec.rb
@@ -2,7 +2,7 @@
require 'fast_spec_helper'
-RSpec.describe Gitlab::Utils::Markdown do
+RSpec.describe Gitlab::Utils::Markdown, feature_category: :gitlab_docs do
let(:klass) do
Class.new do
include Gitlab::Utils::Markdown
@@ -53,25 +53,30 @@ RSpec.describe Gitlab::Utils::Markdown do
end
context 'when string has a product suffix' do
- %w[CORE STARTER PREMIUM ULTIMATE FREE BRONZE SILVER GOLD].each do |tier|
- ['', ' ONLY', ' SELF', ' SAAS'].each do |modifier|
- context "#{tier}#{modifier}" do
- let(:string) { "My Header (#{tier}#{modifier})" }
-
- it 'ignores a product suffix' do
- is_expected.to eq 'my-header'
- end
-
- context 'with "*" around a product suffix' do
- let(:string) { "My Header **(#{tier}#{modifier})**" }
-
- it 'ignores a product suffix' do
- is_expected.to eq 'my-header'
+ %w[PREMIUM ULTIMATE FREE].each do |tier|
+ [' ALL', ' SELF', ' SAAS'].each do |modifier|
+ ['', ' BETA', ' EXPERIMENT'].each do |status|
+ context "#{tier}#{modifier}#{status}" do
+ context 'with "*" around a product suffix' do
+ let(:string) { "My Header **(#{tier}#{modifier}#{status})**" }
+
+ it 'ignores a product suffix' do
+ is_expected.to eq 'my-header'
+ end
end
end
end
end
end
+ %w[BETA EXPERIMENT].each do |status|
+ context 'with "*" around a product suffix' do
+ let(:string) { "My Header **(#{status})**" }
+
+ it 'ignores a product suffix' do
+ is_expected.to eq 'my-header'
+ end
+ end
+ end
end
context 'when string is empty' do
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index a1c2f7d667f..9bc1ebaebcb 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Workhorse do
+RSpec.describe Gitlab::Workhorse, feature_category: :shared do
let_it_be(:project) { create(:project, :repository) }
let(:features) { { 'gitaly-feature-enforce-requests-limits' => 'true' } }
@@ -365,19 +365,72 @@ RSpec.describe Gitlab::Workhorse do
end
end
+ describe '.cleanup_key' do
+ let(:key) { 'test-key' }
+ let(:value) { 'test-value' }
+
+ subject(:cleanup_key) { described_class.cleanup_key(key) }
+
+ shared_examples 'cleans up key' do |redis = Gitlab::Redis::Workhorse|
+ before do
+ described_class.set_key_and_notify(key, value)
+ end
+
+ it 'deletes the key' do
+ expect { cleanup_key }
+ .to change { redis.with { |c| c.exists?(key) } }.from(true).to(false)
+ end
+ end
+
+ it_behaves_like 'cleans up key'
+
+ context 'when workhorse migration feature flags are disabled' do
+ before do
+ stub_feature_flags(
+ use_primary_and_secondary_stores_for_workhorse: false,
+ use_primary_store_as_default_for_workhorse: false
+ )
+ end
+
+ it_behaves_like 'cleans up key', Gitlab::Redis::SharedState
+ end
+
+ context 'when either workhorse migration feature flags are enabled' do
+ context 'when use_primary_and_secondary_stores_for_workhorse is enabled' do
+ before do
+ stub_feature_flags(
+ use_primary_store_as_default_for_workhorse: false
+ )
+ end
+
+ it_behaves_like 'cleans up key'
+ end
+
+ context 'when use_primary_store_as_default_for_workhorse is enabled' do
+ before do
+ stub_feature_flags(
+ use_primary_and_secondary_stores_for_workhorse: false
+ )
+ end
+
+ it_behaves_like 'cleans up key'
+ end
+ end
+ end
+
describe '.set_key_and_notify' do
let(:key) { 'test-key' }
let(:value) { 'test-value' }
subject { described_class.set_key_and_notify(key, value, overwrite: overwrite) }
- shared_examples 'set and notify' do
+ shared_examples 'set and notify' do |redis = Gitlab::Redis::Workhorse|
it 'set and return the same value' do
is_expected.to eq(value)
end
it 'set and notify' do
- expect(Gitlab::Redis::SharedState).to receive(:with).and_call_original
+ expect(redis).to receive(:with).and_call_original
expect_any_instance_of(::Redis).to receive(:publish)
.with(described_class::NOTIFICATION_PREFIX + 'test-key', "test-value")
@@ -389,6 +442,39 @@ RSpec.describe Gitlab::Workhorse do
let(:overwrite) { true }
it_behaves_like 'set and notify'
+
+ context 'when workhorse migration feature flags are disabled' do
+ before do
+ stub_feature_flags(
+ use_primary_and_secondary_stores_for_workhorse: false,
+ use_primary_store_as_default_for_workhorse: false
+ )
+ end
+
+ it_behaves_like 'set and notify', Gitlab::Redis::SharedState
+ end
+
+ context 'when either workhorse migration feature flags are enabled' do
+ context 'when use_primary_and_secondary_stores_for_workhorse is enabled' do
+ before do
+ stub_feature_flags(
+ use_primary_store_as_default_for_workhorse: false
+ )
+ end
+
+ it_behaves_like 'set and notify'
+ end
+
+ context 'when use_primary_store_as_default_for_workhorse is enabled' do
+ before do
+ stub_feature_flags(
+ use_primary_and_secondary_stores_for_workhorse: false
+ )
+ end
+
+ it_behaves_like 'set and notify'
+ end
+ end
end
context 'when we set an existing key' do
@@ -519,18 +605,53 @@ RSpec.describe Gitlab::Workhorse do
describe '.send_dependency' do
let(:headers) { { Accept: 'foo', Authorization: 'Bearer asdf1234' } }
let(:url) { 'https://foo.bar.com/baz' }
+ let(:upload_method) { nil }
+ let(:upload_url) { nil }
+ let(:upload_headers) { {} }
+ let(:upload_config) { { method: upload_method, headers: upload_headers, url: upload_url }.compact_blank! }
- subject { described_class.send_dependency(headers, url) }
+ subject { described_class.send_dependency(headers, url, upload_config: upload_config) }
- it 'sets the header correctly', :aggregate_failures do
- key, command, params = decode_workhorse_header(subject)
+ shared_examples 'setting the header correctly' do |ensure_upload_config_field: nil|
+ it 'sets the header correctly' do
+ key, command, params = decode_workhorse_header(subject)
+ expected_params = {
+ 'Headers' => headers.transform_values { |v| Array.wrap(v) },
+ 'Url' => url,
+ 'UploadConfig' => {
+ 'Method' => upload_method,
+ 'Url' => upload_url,
+ 'Headers' => upload_headers.transform_values { |v| Array.wrap(v) }
+ }.compact_blank!
+ }
+ expected_params.compact_blank!
- expect(key).to eq("Gitlab-Workhorse-Send-Data")
- expect(command).to eq("send-dependency")
- expect(params).to eq({
- 'Header' => headers,
- 'Url' => url
- }.deep_stringify_keys)
+ expect(key).to eq("Gitlab-Workhorse-Send-Data")
+ expect(command).to eq("send-dependency")
+ expect(params).to eq(expected_params.deep_stringify_keys)
+
+ expect(params.dig('UploadConfig', ensure_upload_config_field)).to be_present if ensure_upload_config_field
+ end
+ end
+
+ it_behaves_like 'setting the header correctly'
+
+ context 'overriding the method' do
+ let(:upload_method) { 'PUT' }
+
+ it_behaves_like 'setting the header correctly', ensure_upload_config_field: 'Method'
+ end
+
+ context 'overriding the upload url' do
+ let(:upload_url) { 'https://test.dev' }
+
+ it_behaves_like 'setting the header correctly', ensure_upload_config_field: 'Url'
+ end
+
+ context 'with upload headers set' do
+ let(:upload_headers) { { 'Private-Token' => '1234567890' } }
+
+ it_behaves_like 'setting the header correctly', ensure_upload_config_field: 'Headers'
end
end
diff --git a/spec/lib/gitlab/x509/certificate_spec.rb b/spec/lib/gitlab/x509/certificate_spec.rb
index d919b99de2a..a81bdfcbd42 100644
--- a/spec/lib/gitlab/x509/certificate_spec.rb
+++ b/spec/lib/gitlab/x509/certificate_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::X509::Certificate do
+RSpec.describe Gitlab::X509::Certificate, feature_category: :source_code_management do
include SmimeHelper
let(:sample_ca_certs_path) { Rails.root.join('spec/fixtures/clusters').to_s }
diff --git a/spec/lib/gitlab/x509/commit_sigstore_spec.rb b/spec/lib/gitlab/x509/commit_sigstore_spec.rb
new file mode 100644
index 00000000000..7079fa28108
--- /dev/null
+++ b/spec/lib/gitlab/x509/commit_sigstore_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::X509::Commit, feature_category: :source_code_management do
+ let(:commit_sha) { '440bf5b2b499a90d9adcbebe3752f8c6f245a1aa' }
+ let_it_be(:user) { create(:user, email: X509Helpers::User2.certificate_email) }
+ let_it_be(:project) { create(:project, :repository, path: X509Helpers::User2.path, creator: user) }
+ let(:commit) { create(:commit, project: project) }
+ let(:signature) { described_class.new(commit).signature }
+ let(:store) { OpenSSL::X509::Store.new }
+ let(:certificate) { OpenSSL::X509::Certificate.new(X509Helpers::User2.trust_cert) }
+
+ before do
+ store.add_cert(certificate) if certificate
+ allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
+ end
+
+ describe '#signature' do
+ context 'on second call' do
+ it 'returns the cached signature' do
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:new).and_call_original
+ end
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:create_cached_signature!).and_call_original
+ end
+
+ signature
+
+ # consecutive call
+ expect(described_class).not_to receive(:create_cached_signature!).and_call_original
+ signature
+ end
+ end
+ end
+
+ describe '#update_signature!' do
+ let(:certificate) { nil }
+
+ it 'updates verification status' do
+ signature
+
+ cert = OpenSSL::X509::Certificate.new(X509Helpers::User2.trust_cert)
+ store.add_cert(cert)
+
+ # stored_signature = CommitSignatures::X509CommitSignature.find_by_commit_sha(commit_sha)
+ # expect { described_class.new(commit).update_signature!(stored_signature) }.to(
+ # change { signature.reload.verification_status }.from('unverified').to('verified')
+ # ) # TODO sigstore support pending
+ end
+ end
+end
diff --git a/spec/lib/gitlab/x509/commit_spec.rb b/spec/lib/gitlab/x509/commit_spec.rb
index 412fa6e5a7f..2766a1a9bac 100644
--- a/spec/lib/gitlab/x509/commit_spec.rb
+++ b/spec/lib/gitlab/x509/commit_spec.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Gitlab::X509::Commit do
+RSpec.describe Gitlab::X509::Commit, feature_category: :source_code_management do
let(:commit_sha) { '189a6c924013fc3fe40d6f1ec1dc20214183bc97' }
- let(:user) { create(:user, email: X509Helpers::User1.certificate_email) }
- let(:project) { create(:project, :repository, path: X509Helpers::User1.path, creator: user) }
+ let_it_be(:user) { create(:user, email: X509Helpers::User1.certificate_email) }
+ let_it_be(:project) { create(:project, :repository, path: X509Helpers::User1.path, creator: user) }
let(:commit) { project.commit_by(oid: commit_sha ) }
let(:signature) { described_class.new(commit).signature }
let(:store) { OpenSSL::X509::Store.new }
diff --git a/spec/lib/gitlab/x509/signature_sigstore_spec.rb b/spec/lib/gitlab/x509/signature_sigstore_spec.rb
new file mode 100644
index 00000000000..84962576ea2
--- /dev/null
+++ b/spec/lib/gitlab/x509/signature_sigstore_spec.rb
@@ -0,0 +1,453 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::X509::Signature, feature_category: :source_code_management do
+ let(:issuer_attributes) do
+ {
+ subject_key_identifier: X509Helpers::User2.issuer_subject_key_identifier,
+ subject: X509Helpers::User2.certificate_issuer
+ }
+ end
+
+ it_behaves_like 'signature with type checking', :x509 do
+ subject(:signature) do
+ described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ X509Helpers::User2.signed_commit_base_data,
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ )
+ end
+ end
+
+ shared_examples "a verified signature" do
+ let!(:user) { create(:user, email: X509Helpers::User2.certificate_email) }
+
+ subject(:signature) do
+ described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ X509Helpers::User2.signed_commit_base_data,
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ )
+ end
+
+ it 'returns a verified signature if email does match' do
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey # TODO sigstore support pending
+ expect(signature.verification_status).to eq(:unverified) # TODO sigstore support pending
+ end
+
+ it 'returns a verified signature if email does match, case-insensitively' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ X509Helpers::User2.signed_commit_base_data,
+ X509Helpers::User2.certificate_email.upcase,
+ X509Helpers::User2.signed_commit_time
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey # TODO sigstore support pending
+ expect(signature.verification_status).to eq(:unverified) # TODO sigstore support pending
+ end
+
+ context 'when the certificate contains multiple emails' do
+ before do
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:get_certificate_extension).and_call_original
+ allow(instance).to receive(:get_certificate_extension)
+ .with('subjectAltName')
+ .and_return("email:gitlab2@example.com, othername:<unsupported>, email:#{
+ X509Helpers::User2.certificate_email
+ }")
+ end
+ end
+
+ context 'and the email matches one of them' do
+ it 'returns a verified signature' do
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes.except(:email, :emails))
+ expect(signature.x509_certificate.email).to eq('gitlab2@example.com')
+ expect(signature.x509_certificate.emails).to contain_exactly('gitlab2@example.com',
+ X509Helpers::User2.certificate_email)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey # TODO sigstore support pending
+ expect(signature.verification_status).to eq(:unverified) # TODO sigstore support pending
+ end
+ end
+ end
+
+ context "if the email matches but isn't confirmed" do
+ let!(:user) { create(:user, :unconfirmed, email: X509Helpers::User2.certificate_email) }
+
+ it "returns an unverified signature" do
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+
+ it 'returns an unverified signature if email does not match' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ X509Helpers::User2.signed_commit_base_data,
+ "gitlab@example.com",
+ X509Helpers::User2.signed_commit_time
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey # TODO sigstore support pending
+ expect(signature.verification_status).to eq(:unverified)
+ end
+
+ it 'returns an unverified signature if email does match and time is wrong' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ X509Helpers::User2.signed_commit_base_data,
+ X509Helpers::User2.certificate_email,
+ Time.zone.local(2020, 2, 22)
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+
+ it 'returns an unverified signature if certificate is revoked' do
+ expect(signature.verification_status).to eq(:unverified) # TODO sigstore support pending
+
+ signature.x509_certificate.revoked!
+
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+
+ context 'with commit signature' do
+ let(:certificate_attributes) do
+ {
+ subject_key_identifier: X509Helpers::User2.certificate_subject_key_identifier,
+ subject: X509Helpers::User2.certificate_subject,
+ email: X509Helpers::User2.certificate_email,
+ emails: [X509Helpers::User2.certificate_email],
+ serial_number: X509Helpers::User2.certificate_serial
+ }
+ end
+
+ context 'with verified signature' do
+ context 'with trusted certificate store' do
+ before do
+ store = OpenSSL::X509::Store.new
+ certificate = OpenSSL::X509::Certificate.new(X509Helpers::User2.trust_cert)
+ store.add_cert(certificate)
+ allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
+ end
+
+ it_behaves_like "a verified signature"
+ end
+
+ context 'with the certificate defined by OpenSSL::X509::DEFAULT_CERT_FILE' do
+ before do
+ store = OpenSSL::X509::Store.new
+ certificate = OpenSSL::X509::Certificate.new(X509Helpers::User2.trust_cert)
+ file_path = Rails.root.join("tmp/cert.pem").to_s
+
+ File.open(file_path, "wb") do |f|
+ f.print certificate.to_pem
+ end
+
+ allow(Gitlab::X509::Certificate).to receive(:default_cert_file).and_return(file_path)
+
+ allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
+ end
+
+ it_behaves_like "a verified signature"
+ end
+
+ context 'without trusted certificate within store' do
+ before do
+ store = OpenSSL::X509::Store.new
+ allow(OpenSSL::X509::Store).to receive(:new)
+ .and_return(
+ store
+ )
+ end
+
+ it 'returns an unverified signature' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ X509Helpers::User2.signed_commit_base_data,
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+ end
+
+ context 'with invalid signature' do
+ it 'returns nil' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_commit_signature.tr('A', 'B'),
+ X509Helpers::User2.signed_commit_base_data,
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ )
+ expect(signature.x509_certificate).to be_nil
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+
+ context 'with invalid commit message' do
+ it 'returns nil' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ 'x',
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ )
+ expect(signature.x509_certificate).to be_nil
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+ end
+
+ context 'with email' do
+ describe 'subjectAltName with email, othername' do
+ before do
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:get_certificate_extension).and_call_original
+ allow(instance).to receive(:get_certificate_extension)
+ .with('subjectAltName')
+ .and_return("email:gitlab@example.com, othername:<unsupported>")
+ end
+ end
+
+ let(:signature) do
+ described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ X509Helpers::User2.signed_commit_base_data,
+ 'gitlab@example.com',
+ X509Helpers::User2.signed_commit_time
+ )
+ end
+
+ it 'extracts email' do
+ expect(signature.x509_certificate.email).to eq("gitlab@example.com")
+ expect(signature.x509_certificate.emails).to contain_exactly("gitlab@example.com")
+ end
+
+ context 'when there are multiple emails' do
+ before do
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:get_certificate_extension).and_call_original
+ allow(instance).to receive(:get_certificate_extension)
+ .with('subjectAltName')
+ .and_return("email:gitlab@example.com, othername:<unsupported>, email:gitlab2@example.com")
+ end
+ end
+
+ it 'extracts all the emails' do
+ expect(signature.x509_certificate.email).to eq("gitlab@example.com")
+ expect(signature.x509_certificate.emails).to contain_exactly("gitlab@example.com", "gitlab2@example.com")
+ end
+ end
+ end
+
+ describe 'subjectAltName with othername, email' do
+ before do
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:get_certificate_extension).and_call_original
+ end
+
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:get_certificate_extension).and_call_original
+ allow(instance).to receive(:get_certificate_extension)
+ .with('subjectAltName')
+ .and_return("othername:<unsupported>, email:gitlab@example.com")
+ end
+ end
+
+ it 'extracts email' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_commit_signature,
+ X509Helpers::User2.signed_commit_base_data,
+ 'gitlab@example.com',
+ X509Helpers::User2.signed_commit_time
+ )
+
+ expect(signature.x509_certificate.email).to eq("gitlab@example.com")
+ end
+ end
+ end
+
+ describe '#signed_by_user' do
+ subject do
+ described_class.new(
+ X509Helpers::User2.signed_tag_signature,
+ X509Helpers::User2.signed_tag_base_data,
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ ).signed_by_user
+ end
+
+ context 'if email is assigned to a user' do
+ let!(:signed_by_user) { create(:user, email: X509Helpers::User2.certificate_email) }
+
+ it 'returns user' do
+ is_expected.to eq(signed_by_user)
+ end
+ end
+
+ it 'if email is not assigned to a user, return nil' do
+ is_expected.to be_nil
+ end
+ end
+
+ context 'with tag signature' do
+ let(:certificate_attributes) do
+ {
+ subject_key_identifier: X509Helpers::User2.tag_certificate_subject_key_identifier,
+ subject: X509Helpers::User2.certificate_subject,
+ email: X509Helpers::User2.certificate_email,
+ emails: [X509Helpers::User2.certificate_email],
+ serial_number: X509Helpers::User2.tag_certificate_serial
+ }
+ end
+
+ let(:issuer_attributes) do
+ {
+ subject_key_identifier: X509Helpers::User2.tag_issuer_subject_key_identifier,
+ subject: X509Helpers::User2.tag_certificate_issuer
+ }
+ end
+
+ context 'with verified signature' do
+ let_it_be(:user) { create(:user, :unconfirmed, email: X509Helpers::User2.certificate_email) }
+
+ subject(:signature) do
+ described_class.new(
+ X509Helpers::User2.signed_tag_signature,
+ X509Helpers::User2.signed_tag_base_data,
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ )
+ end
+
+ context 'with trusted certificate store' do
+ before do
+ store = OpenSSL::X509::Store.new
+ certificate = OpenSSL::X509::Certificate.new X509Helpers::User2.trust_cert
+ store.add_cert(certificate)
+ allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
+ end
+
+ context 'when user email is confirmed' do
+ before_all do
+ user.confirm
+ end
+
+ it 'returns a verified signature if email does match', :ggregate_failures do
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey # TODO sigstore support pending
+ expect(signature.verification_status).to eq(:unverified) # TODO sigstore support pending
+ end
+
+ it 'returns an unverified signature if email does not match', :aggregate_failures do
+ signature = described_class.new(
+ X509Helpers::User2.signed_tag_signature,
+ X509Helpers::User2.signed_tag_base_data,
+ "gitlab@example.com",
+ X509Helpers::User2.signed_commit_time
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey # TODO sigstore support pending
+ expect(signature.verification_status).to eq(:unverified)
+ end
+
+ it 'returns an unverified signature if email does match and time is wrong', :aggregate_failures do
+ signature = described_class.new(
+ X509Helpers::User2.signed_tag_signature,
+ X509Helpers::User2.signed_tag_base_data,
+ X509Helpers::User2.certificate_email,
+ Time.zone.local(2020, 2, 22)
+ )
+
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+
+ it 'returns an unverified signature if certificate is revoked' do
+ expect(signature.verification_status).to eq(:unverified) # TODO sigstore support pending
+
+ signature.x509_certificate.revoked!
+
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+
+ it 'returns an unverified signature if the email matches but is not confirmed' do
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+
+ context 'without trusted certificate within store' do
+ before do
+ store = OpenSSL::X509::Store.new
+ allow(OpenSSL::X509::Store).to receive(:new)
+ .and_return(
+ store
+ )
+ end
+
+ it 'returns an unverified signature' do
+ expect(signature.x509_certificate).to have_attributes(certificate_attributes)
+ expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes)
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+ end
+
+ context 'with invalid signature' do
+ it 'returns nil' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_tag_signature.tr('A', 'B'),
+ X509Helpers::User2.signed_tag_base_data,
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ )
+ expect(signature.x509_certificate).to be_nil
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+
+ context 'with invalid message' do
+ it 'returns nil' do
+ signature = described_class.new(
+ X509Helpers::User2.signed_tag_signature,
+ 'x',
+ X509Helpers::User2.certificate_email,
+ X509Helpers::User2.signed_commit_time
+ )
+ expect(signature.x509_certificate).to be_nil
+ expect(signature.verified_signature).to be_falsey
+ expect(signature.verification_status).to eq(:unverified)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/x509/signature_spec.rb b/spec/lib/gitlab/x509/signature_spec.rb
index e0823aa8153..8043cefe888 100644
--- a/spec/lib/gitlab/x509/signature_spec.rb
+++ b/spec/lib/gitlab/x509/signature_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::X509::Signature do
+RSpec.describe Gitlab::X509::Signature, feature_category: :source_code_management do
let(:issuer_attributes) do
{
subject_key_identifier: X509Helpers::User1.issuer_subject_key_identifier,
diff --git a/spec/lib/gitlab/x509/tag_sigstore_spec.rb b/spec/lib/gitlab/x509/tag_sigstore_spec.rb
new file mode 100644
index 00000000000..3cf864ea442
--- /dev/null
+++ b/spec/lib/gitlab/x509/tag_sigstore_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::X509::Tag, feature_category: :source_code_management do
+ describe '#signature' do
+ let(:tag_id) { 'v1.1.2' }
+ let(:tag) { instance_double('Gitlab::Git::Tag') }
+ let_it_be(:user) { create(:user, email: X509Helpers::User2.tag_email) }
+ let_it_be(:project) { create(:project, path: X509Helpers::User2.path, creator: user) }
+ let(:signature) { described_class.new(project.repository, tag).signature }
+
+ before do
+ allow(tag).to receive(:id).and_return(tag_id)
+ allow(tag).to receive(:has_signature?).and_return(true)
+ allow(tag).to receive(:user_email).and_return(user.email)
+ allow(tag).to receive(:date).and_return(X509Helpers::User2.signed_tag_time)
+ allow(Gitlab::Git::Tag).to receive(:extract_signature_lazily).with(project.repository, tag_id)
+ .and_return([X509Helpers::User2.signed_tag_signature, X509Helpers::User2.signed_tag_base_data])
+ end
+
+ describe 'signed tag' do
+ let(:certificate_attributes) do
+ {
+ subject_key_identifier: X509Helpers::User2.tag_certificate_subject_key_identifier,
+ subject: X509Helpers::User2.certificate_subject,
+ email: X509Helpers::User2.certificate_email,
+ serial_number: X509Helpers::User2.tag_certificate_serial
+ }
+ end
+
+ let(:issuer_attributes) do
+ {
+ subject_key_identifier: X509Helpers::User2.tag_issuer_subject_key_identifier,
+ subject: X509Helpers::User2.tag_certificate_issuer
+ }
+ end
+
+ it { expect(signature).not_to be_nil }
+ it { expect(signature.verification_status).to eq(:unverified) }
+ it { expect(signature.x509_certificate).to have_attributes(certificate_attributes) }
+ it { expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/x509/tag_spec.rb b/spec/lib/gitlab/x509/tag_spec.rb
index e20ef688db5..4368c3d7a4b 100644
--- a/spec/lib/gitlab/x509/tag_spec.rb
+++ b/spec/lib/gitlab/x509/tag_spec.rb
@@ -1,15 +1,24 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Gitlab::X509::Tag do
- subject(:signature) { described_class.new(project.repository, tag).signature }
-
+RSpec.describe Gitlab::X509::Tag, feature_category: :source_code_management do
describe '#signature' do
- let_it_be(:project) { create(:project, :repository) }
- let_it_be(:repository) { project.repository.raw }
+ let(:tag_id) { 'v1.1.1' }
+ let(:tag) { instance_double('Gitlab::Git::Tag') }
+ let_it_be(:user) { create(:user, email: X509Helpers::User1.tag_email) }
+ let_it_be(:project) { create(:project, path: X509Helpers::User1.path, creator: user) }
+ let(:signature) { described_class.new(project.repository, tag).signature }
+
+ before do
+ allow(tag).to receive(:id).and_return(tag_id)
+ allow(tag).to receive(:has_signature?).and_return(true)
+ allow(tag).to receive(:user_email).and_return(user.email)
+ allow(tag).to receive(:date).and_return(X509Helpers::User1.signed_tag_time)
+ allow(Gitlab::Git::Tag).to receive(:extract_signature_lazily).with(project.repository, tag_id)
+ .and_return([X509Helpers::User1.signed_tag_signature, X509Helpers::User1.signed_tag_base_data])
+ end
describe 'signed tag' do
- let(:tag) { project.repository.find_tag('v1.1.1') }
let(:certificate_attributes) do
{
subject_key_identifier: X509Helpers::User1.tag_certificate_subject_key_identifier,
@@ -32,11 +41,5 @@ RSpec.describe Gitlab::X509::Tag do
it { expect(signature.x509_certificate).to have_attributes(certificate_attributes) }
it { expect(signature.x509_certificate.x509_issuer).to have_attributes(issuer_attributes) }
end
-
- describe 'unsigned tag' do
- let(:tag) { project.repository.find_tag('v1.0.0') }
-
- it { expect(signature).to be_nil }
- end
end
end
diff --git a/spec/lib/peek/views/click_house_spec.rb b/spec/lib/peek/views/click_house_spec.rb
index 9d7d06204fc..1ff49afd728 100644
--- a/spec/lib/peek/views/click_house_spec.rb
+++ b/spec/lib/peek/views/click_house_spec.rb
@@ -16,9 +16,15 @@ RSpec.describe Peek::Views::ClickHouse, :click_house, :request_store, feature_ca
data = ClickHouse::Client.select('SELECT 1 AS value', :main)
ClickHouse::Client.execute('INSERT INTO events (id) VALUES (1)', :main)
+ Tempfile.open(['test', '.csv.gz']) do |f|
+ File.binwrite(f.path, ActiveSupport::Gzip.compress("id\n10\n20"))
+
+ ClickHouse::Client.insert_csv('INSERT INTO events (id) FORMAT CSV', File.open(f.path), :main)
+ end
+
expect(data).to eq([{ 'value' => 1 }])
- expect(results[:calls]).to eq(2)
+ expect(results[:calls]).to eq(3)
expect(results[:duration]).to be_kind_of(String)
expect(results[:details]).to match_array([
@@ -30,6 +36,11 @@ RSpec.describe Peek::Views::ClickHouse, :click_house, :request_store, feature_ca
sql: 'INSERT INTO events (id) VALUES (1)',
database: 'database: main',
statistics: include('written_rows=>"1"')
+ }),
+ a_hash_including({
+ sql: 'INSERT INTO events (id) FORMAT CSV',
+ database: 'database: main',
+ statistics: include('written_rows=>"2"')
})
])
end
diff --git a/spec/lib/sidebars/admin/panel_spec.rb b/spec/lib/sidebars/admin/panel_spec.rb
index 9c362f527f5..83ad867050c 100644
--- a/spec/lib/sidebars/admin/panel_spec.rb
+++ b/spec/lib/sidebars/admin/panel_spec.rb
@@ -18,14 +18,10 @@ RSpec.describe Sidebars::Admin::Panel, feature_category: :navigation do
describe '#super_sidebar_context_header' do
it 'returns a hash with the correct title and icon' do
- expected_header = {
- title: panel.aria_label,
- icon: 'admin'
- }
-
- expect(panel.super_sidebar_context_header).to eq(expected_header)
+ expect(panel.super_sidebar_context_header).to eq(_('Admin Area'))
end
end
it_behaves_like 'a panel with uniquely identifiable menu items'
+ it_behaves_like 'a panel instantiable by the anonymous user'
end
diff --git a/spec/lib/sidebars/concerns/has_avatar_spec.rb b/spec/lib/sidebars/concerns/has_avatar_spec.rb
new file mode 100644
index 00000000000..bc9038c216e
--- /dev/null
+++ b/spec/lib/sidebars/concerns/has_avatar_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Sidebars::Concerns::HasAvatar, feature_category: :navigation do
+ subject do
+ Class.new do
+ include Sidebars::Concerns::HasAvatar
+ end.new
+ end
+
+ describe '#avatar' do
+ it 'returns nil' do
+ expect(subject.avatar).to be_nil
+ end
+ end
+
+ describe '#avatar_shape' do
+ it 'returns rect' do
+ expect(subject.avatar_shape).to eq('rect')
+ end
+ end
+
+ describe '#entity_id' do
+ it 'returns nil' do
+ expect(subject.entity_id).to be_nil
+ end
+ end
+end
diff --git a/spec/lib/sidebars/explore/panel_spec.rb b/spec/lib/sidebars/explore/panel_spec.rb
new file mode 100644
index 00000000000..b3030dfe2e4
--- /dev/null
+++ b/spec/lib/sidebars/explore/panel_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Explore::Panel, feature_category: :navigation do
+ let(:user) { build_stubbed(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it_behaves_like 'a panel with uniquely identifiable menu items'
+
+ it 'implements #super_sidebar_context_header' do
+ expect(subject.super_sidebar_context_header).to eq(_('Explore'))
+ end
+end
diff --git a/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb b/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb
index 382ee07e458..713e22e2e76 100644
--- a/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/packages_registries_menu_spec.rb
@@ -24,29 +24,16 @@ RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu, feature_category
expect(menu.render?).to eq true
end
end
-
- context 'when menu does not have any menu item to show' do
- it 'returns false' do
- stub_feature_flags(harbor_registry_integration: false)
- stub_container_registry_config(enabled: false)
- stub_config(packages: { enabled: false })
- stub_config(dependency_proxy: { enabled: false })
-
- expect(menu.render?).to eq false
- end
- end
end
describe '#link' do
let(:registry_enabled) { true }
let(:packages_enabled) { true }
- let(:harbor_registry_integration) { true }
before do
stub_container_registry_config(enabled: registry_enabled)
stub_config(packages: { enabled: packages_enabled })
stub_config(dependency_proxy: { enabled: true })
- stub_feature_flags(harbor_registry_integration: harbor_registry_integration)
end
subject { menu.link }
@@ -70,14 +57,6 @@ RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu, feature_category
it 'menu link points to Harbor Registry page' do
expect(subject).to eq find_menu(menu, :harbor_registry).link
end
-
- context 'when Harbor Registry is not visible' do
- let(:harbor_registry_integration) { false }
-
- it 'menu link points to Dependency Proxy page' do
- expect(subject).to eq find_menu(menu, :dependency_proxy).link
- end
- end
end
end
end
@@ -194,29 +173,13 @@ RSpec.describe Sidebars::Groups::Menus::PackagesRegistriesMenu, feature_category
describe 'Harbor Registry' do
let(:item_id) { :harbor_registry }
- before do
- stub_feature_flags(harbor_registry_integration: harbor_registry_enabled)
- end
-
- context 'when config harbor registry setting is disabled' do
- let(:harbor_registry_enabled) { false }
-
- it_behaves_like 'the menu entry is not available'
- end
-
- context 'when config harbor registry setting is enabled' do
- let(:harbor_registry_enabled) { true }
-
- it_behaves_like 'the menu entry is available'
- end
+ it_behaves_like 'the menu entry is available'
context 'when config harbor registry setting is not activated' do
before do
harbor_integration.update!(active: false)
end
- let(:harbor_registry_enabled) { true }
-
it_behaves_like 'the menu entry is not available'
end
end
diff --git a/spec/lib/sidebars/groups/menus/scope_menu_spec.rb b/spec/lib/sidebars/groups/menus/scope_menu_spec.rb
index d3aceaf422b..2cce2d28e68 100644
--- a/spec/lib/sidebars/groups/menus/scope_menu_spec.rb
+++ b/spec/lib/sidebars/groups/menus/scope_menu_spec.rb
@@ -17,9 +17,10 @@ RSpec.describe Sidebars::Groups::Menus::ScopeMenu, feature_category: :navigation
it_behaves_like 'serializable as super_sidebar_menu_args' do
let(:extra_attrs) do
{
- sprite_icon: 'group',
super_sidebar_parent: ::Sidebars::StaticMenu,
- title: _('Group overview'),
+ title: group.name,
+ avatar: group.avatar_url,
+ entity_id: group.id,
item_id: :group_overview
}
end
diff --git a/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb b/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb
index 52c3a35a9d7..c939dd870c4 100644
--- a/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb
+++ b/spec/lib/sidebars/groups/super_sidebar_panel_spec.rb
@@ -20,12 +20,7 @@ RSpec.describe Sidebars::Groups::SuperSidebarPanel, feature_category: :navigatio
subject { described_class.new(context) }
it 'implements #super_sidebar_context_header' do
- expect(subject.super_sidebar_context_header).to eq(
- {
- title: group.name,
- avatar: group.avatar_url,
- id: group.id
- })
+ expect(subject.super_sidebar_context_header).to eq(_('Group'))
end
describe '#renderable_menus' do
@@ -53,4 +48,5 @@ RSpec.describe Sidebars::Groups::SuperSidebarPanel, feature_category: :navigatio
it_behaves_like 'a panel with uniquely identifiable menu items'
it_behaves_like 'a panel with all menu_items categorized'
+ it_behaves_like 'a panel instantiable by the anonymous user'
end
diff --git a/spec/lib/sidebars/menu_item_spec.rb b/spec/lib/sidebars/menu_item_spec.rb
index 3ff5b80e5d9..7f67b5a2e8d 100644
--- a/spec/lib/sidebars/menu_item_spec.rb
+++ b/spec/lib/sidebars/menu_item_spec.rb
@@ -5,7 +5,8 @@ require 'fast_spec_helper'
RSpec.describe Sidebars::MenuItem, feature_category: :navigation do
let(:title) { 'foo' }
let(:html_options) { {} }
- let(:menu_item) { described_class.new(title: title, active_routes: {}, link: '', container_html_options: html_options) }
+ let(:extra) { {} }
+ let(:menu_item) { described_class.new(title: title, active_routes: {}, link: '', container_html_options: html_options, **extra) }
it 'includes by default aria-label attribute set to the title' do
expect(menu_item.container_html_options).to eq({ aria: { label: title } })
@@ -21,11 +22,17 @@ RSpec.describe Sidebars::MenuItem, feature_category: :navigation do
describe "#serialize_for_super_sidebar" do
let(:html_options) { { class: 'custom-class' } }
+ let(:extra) { { avatar: '/avatar.png', entity_id: 123 } }
subject { menu_item.serialize_for_super_sidebar }
it 'includes custom CSS classes' do
expect(subject[:link_classes]).to be('custom-class')
end
+
+ it 'includes avatar data' do
+ expect(subject[:avatar]).to be('/avatar.png')
+ expect(subject[:entity_id]).to be(123)
+ end
end
end
diff --git a/spec/lib/sidebars/menu_spec.rb b/spec/lib/sidebars/menu_spec.rb
index 00202ac7d2b..e59a8cd2163 100644
--- a/spec/lib/sidebars/menu_spec.rb
+++ b/spec/lib/sidebars/menu_spec.rb
@@ -33,6 +33,8 @@ RSpec.describe Sidebars::Menu, feature_category: :navigation do
item_id: 'id1',
title: 'Is active',
link: 'foo2',
+ avatar: '/avatar.png',
+ entity_id: 123,
active_routes: { controller: 'fooc' }
))
menu.add_item(Sidebars::MenuItem.new(
@@ -51,6 +53,9 @@ RSpec.describe Sidebars::Menu, feature_category: :navigation do
{
title: "Title",
icon: nil,
+ avatar: nil,
+ avatar_shape: 'rect',
+ entity_id: nil,
link: "foo2",
is_active: true,
pill_count: nil,
@@ -60,6 +65,8 @@ RSpec.describe Sidebars::Menu, feature_category: :navigation do
id: 'id1',
title: "Is active",
icon: nil,
+ avatar: '/avatar.png',
+ entity_id: 123,
link: "foo2",
is_active: true,
pill_count: nil,
@@ -69,6 +76,8 @@ RSpec.describe Sidebars::Menu, feature_category: :navigation do
id: 'id2',
title: "Not active",
icon: nil,
+ avatar: nil,
+ entity_id: nil,
link: "foo3",
is_active: false,
pill_count: 10,
@@ -85,6 +94,9 @@ RSpec.describe Sidebars::Menu, feature_category: :navigation do
{
title: "Title",
icon: nil,
+ avatar: nil,
+ avatar_shape: 'rect',
+ entity_id: nil,
link: nil,
is_active: false,
pill_count: 'foo',
diff --git a/spec/lib/sidebars/organizations/menus/scope_menu_spec.rb b/spec/lib/sidebars/organizations/menus/scope_menu_spec.rb
index bc03787e95f..999889a72ee 100644
--- a/spec/lib/sidebars/organizations/menus/scope_menu_spec.rb
+++ b/spec/lib/sidebars/organizations/menus/scope_menu_spec.rb
@@ -11,8 +11,8 @@ RSpec.describe Sidebars::Organizations::Menus::ScopeMenu, feature_category: :nav
let(:menu) { described_class.new(context) }
let(:extra_attrs) do
{
- title: s_('Organization|Organization overview'),
- sprite_icon: 'organization',
+ avatar: nil,
+ entity_id: organization.id,
super_sidebar_parent: ::Sidebars::StaticMenu,
item_id: :organization_overview
}
diff --git a/spec/lib/sidebars/organizations/panel_spec.rb b/spec/lib/sidebars/organizations/panel_spec.rb
index 1f0b8d72aef..edaa676aa41 100644
--- a/spec/lib/sidebars/organizations/panel_spec.rb
+++ b/spec/lib/sidebars/organizations/panel_spec.rb
@@ -14,4 +14,5 @@ RSpec.describe Sidebars::Organizations::Panel, feature_category: :navigation do
end
it_behaves_like 'a panel with uniquely identifiable menu items'
+ it_behaves_like 'a panel instantiable by the anonymous user'
end
diff --git a/spec/lib/sidebars/organizations/super_sidebar_panel_spec.rb b/spec/lib/sidebars/organizations/super_sidebar_panel_spec.rb
index 99b33a5edf8..b8ceda615c4 100644
--- a/spec/lib/sidebars/organizations/super_sidebar_panel_spec.rb
+++ b/spec/lib/sidebars/organizations/super_sidebar_panel_spec.rb
@@ -15,11 +15,7 @@ RSpec.describe Sidebars::Organizations::SuperSidebarPanel, feature_category: :na
subject { described_class.new(context) }
it 'implements #super_sidebar_context_header' do
- expect(subject.super_sidebar_context_header).to eq(
- {
- title: organization.name,
- id: organization.id
- })
+ expect(subject.super_sidebar_context_header).to eq(s_('Organization|Organization'))
end
describe '#renderable_menus' do
@@ -36,4 +32,5 @@ RSpec.describe Sidebars::Organizations::SuperSidebarPanel, feature_category: :na
end
it_behaves_like 'a panel with uniquely identifiable menu items'
+ it_behaves_like 'a panel instantiable by the anonymous user'
end
diff --git a/spec/lib/sidebars/panel_spec.rb b/spec/lib/sidebars/panel_spec.rb
index 857cb1139b5..e4b3b973484 100644
--- a/spec/lib/sidebars/panel_spec.rb
+++ b/spec/lib/sidebars/panel_spec.rb
@@ -46,17 +46,25 @@ RSpec.describe Sidebars::Panel, feature_category: :navigation do
end
end
- describe '#has_renderable_menus?' do
- it 'returns false when no renderable menus' do
- expect(panel.has_renderable_menus?).to be false
+ describe '#render?' do
+ it 'returns false with no menus' do
+ expect(panel.render?).to be false
end
- it 'returns true when no renderable menus' do
+ it 'returns false with no renderable menus' do
+ allow(menu1).to receive(:render?).and_return(false)
+
+ panel.add_menu(menu1)
+
+ expect(panel.render?).to be false
+ end
+
+ it 'returns true with renderable menus' do
allow(menu1).to receive(:render?).and_return(true)
panel.add_menu(menu1)
- expect(panel.has_renderable_menus?).to be true
+ expect(panel.render?).to be true
end
end
diff --git a/spec/lib/sidebars/projects/menus/issues_menu_spec.rb b/spec/lib/sidebars/projects/menus/issues_menu_spec.rb
index 53d92d013a9..91913e5b733 100644
--- a/spec/lib/sidebars/projects/menus/issues_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/issues_menu_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe Sidebars::Projects::Menus::IssuesMenu, feature_category: :navigat
let(:extra_attrs) do
{
item_id: :project_issue_list,
+ active_routes: { path: %w[projects/issues#index projects/issues#show projects/issues#new] },
pill_count: menu.pill_count,
has_pill: menu.has_pill?,
super_sidebar_parent: Sidebars::Projects::SuperSidebarMenus::PlanMenu
diff --git a/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb b/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb
index c0787aa9db5..f1df56823b1 100644
--- a/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb
@@ -88,19 +88,5 @@ RSpec.describe Sidebars::Projects::Menus::MonitorMenu, feature_category: :naviga
it_behaves_like 'access rights checks'
end
-
- describe 'Tracing' do
- let(:item_id) { :tracing }
-
- specify { is_expected.not_to be_nil }
-
- describe 'when feature is disabled' do
- before do
- stub_feature_flags(observability_tracing: false)
- end
-
- specify { is_expected.to be_nil }
- end
- end
end
end
diff --git a/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb b/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb
index b917208bac1..0cf95391a26 100644
--- a/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu, feature_catego
before do
stub_container_registry_config(enabled: registry_enabled)
stub_config(packages: { enabled: packages_enabled })
- stub_feature_flags(harbor_registry_integration: false, ml_experiment_tracking: false)
+ stub_feature_flags(ml_experiment_tracking: false)
end
context 'when Packages Registry is visible' do
@@ -58,8 +58,8 @@ RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu, feature_catego
context 'when Container Registry is not visible' do
let(:registry_enabled) { false }
- it 'does not display menu link' do
- expect(subject.render?).to eq false
+ it 'displays menu link' do
+ expect(subject.render?).to eq true
end
end
end
@@ -155,26 +155,13 @@ RSpec.describe Sidebars::Projects::Menus::PackagesRegistriesMenu, feature_catego
describe 'Harbor Registry' do
let(:item_id) { :harbor_registry }
- context 'when config harbor registry setting is disabled' do
- it 'does not add the menu item to the list' do
- stub_feature_flags(harbor_registry_integration: false)
-
- is_expected.to be_nil
- end
- end
-
- context 'when config harbor registry setting is enabled' do
- it 'the menu item is added to list of menu items' do
- stub_feature_flags(harbor_registry_integration: true)
-
- is_expected.not_to be_nil
- expect(subject.active_routes[:controller]).to eq('projects/harbor/repositories')
- end
+ it 'the menu item is added to list of menu items' do
+ is_expected.not_to be_nil
+ expect(subject.active_routes[:controller]).to eq('projects/harbor/repositories')
end
context 'when config harbor registry setting is not activated' do
it 'does not add the menu item to the list' do
- stub_feature_flags(harbor_registry_integration: true)
project.harbor_integration.update!(active: false)
is_expected.to be_nil
diff --git a/spec/lib/sidebars/projects/menus/scope_menu_spec.rb b/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
index 45464278880..1c2d159950a 100644
--- a/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/scope_menu_spec.rb
@@ -11,8 +11,9 @@ RSpec.describe Sidebars::Projects::Menus::ScopeMenu, feature_category: :navigati
let(:menu) { described_class.new(context) }
let(:extra_attrs) do
{
- title: _('Project overview'),
- sprite_icon: 'project',
+ title: project.name,
+ avatar: project.avatar_url,
+ entity_id: project.id,
super_sidebar_parent: ::Sidebars::StaticMenu,
item_id: :project_overview
}
diff --git a/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb b/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb
index 3fc6cd5083f..dc264c1c14f 100644
--- a/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb
+++ b/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb
@@ -31,12 +31,7 @@ RSpec.describe Sidebars::Projects::SuperSidebarPanel, feature_category: :navigat
end
it 'implements #super_sidebar_context_header' do
- expect(subject.super_sidebar_context_header).to eq(
- {
- title: project.name,
- avatar: project.avatar_url,
- id: project.id
- })
+ expect(subject.super_sidebar_context_header).to eq(_('Project'))
end
describe '#renderable_menus' do
@@ -64,4 +59,5 @@ RSpec.describe Sidebars::Projects::SuperSidebarPanel, feature_category: :navigat
it_behaves_like 'a panel with uniquely identifiable menu items'
it_behaves_like 'a panel with all menu_items categorized'
+ it_behaves_like 'a panel instantiable by the anonymous user'
end
diff --git a/spec/lib/sidebars/search/panel_spec.rb b/spec/lib/sidebars/search/panel_spec.rb
index 39c0f112793..fa1b4266a2f 100644
--- a/spec/lib/sidebars/search/panel_spec.rb
+++ b/spec/lib/sidebars/search/panel_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe Sidebars::Search::Panel, feature_category: :navigation do
subject { described_class.new(context) }
it_behaves_like 'a panel with uniquely identifiable menu items'
+ it_behaves_like 'a panel instantiable by the anonymous user'
describe '#aria_label' do
it 'returns the correct aria label' do
@@ -21,11 +22,7 @@ RSpec.describe Sidebars::Search::Panel, feature_category: :navigation do
describe '#super_sidebar_context_header' do
it 'returns a hash with the correct title and icon' do
- expected_header = {
- title: 'Search results',
- icon: 'search-results'
- }
- expect(panel.super_sidebar_context_header).to eq(expected_header)
+ expect(panel.super_sidebar_context_header).to eq(_('Search results'))
end
end
end
diff --git a/spec/lib/sidebars/static_menu_spec.rb b/spec/lib/sidebars/static_menu_spec.rb
index 3d9feee0494..fda953c0791 100644
--- a/spec/lib/sidebars/static_menu_spec.rb
+++ b/spec/lib/sidebars/static_menu_spec.rb
@@ -23,6 +23,8 @@ RSpec.describe Sidebars::StaticMenu, feature_category: :navigation do
id: 'id1',
title: "Is active",
icon: nil,
+ avatar: nil,
+ entity_id: nil,
link: "foo2",
is_active: true,
pill_count: nil,
@@ -32,6 +34,8 @@ RSpec.describe Sidebars::StaticMenu, feature_category: :navigation do
id: 'id2',
title: "Not active",
icon: nil,
+ avatar: nil,
+ entity_id: nil,
link: "foo3",
is_active: false,
pill_count: nil,
diff --git a/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb b/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb
index 7cf86676892..ef12ce023b4 100644
--- a/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb
+++ b/spec/lib/sidebars/user_profile/menus/overview_menu_spec.rb
@@ -4,8 +4,9 @@ require 'spec_helper'
RSpec.describe Sidebars::UserProfile::Menus::OverviewMenu, feature_category: :navigation do
it_behaves_like 'User profile menu',
- title: s_('UserProfile|Overview'),
- icon: 'overview',
+ icon: nil,
+ expect_avatar: true,
+ avatar_shape: 'circle',
active_route: 'users#show' do
let(:link) { "/#{user.username}" }
end
diff --git a/spec/lib/sidebars/user_profile/panel_spec.rb b/spec/lib/sidebars/user_profile/panel_spec.rb
index a2bf490bc58..97fe13397a9 100644
--- a/spec/lib/sidebars/user_profile/panel_spec.rb
+++ b/spec/lib/sidebars/user_profile/panel_spec.rb
@@ -11,16 +11,13 @@ RSpec.describe Sidebars::UserProfile::Panel, feature_category: :navigation do
subject { described_class.new(context) }
it_behaves_like 'a panel with uniquely identifiable menu items'
+ it_behaves_like 'a panel instantiable by the anonymous user'
it 'implements #aria_label' do
expect(subject.aria_label).to eq(s_('UserProfile|User profile navigation'))
end
it 'implements #super_sidebar_context_header' do
- expect(subject.super_sidebar_context_header).to eq({
- title: user.name,
- avatar: user.avatar_url,
- avatar_shape: 'circle'
- })
+ expect(subject.super_sidebar_context_header).to eq(_('Profile'))
end
end
diff --git a/spec/lib/sidebars/user_settings/panel_spec.rb b/spec/lib/sidebars/user_settings/panel_spec.rb
index d574652188d..e65717d75d6 100644
--- a/spec/lib/sidebars/user_settings/panel_spec.rb
+++ b/spec/lib/sidebars/user_settings/panel_spec.rb
@@ -10,8 +10,9 @@ RSpec.describe Sidebars::UserSettings::Panel, feature_category: :navigation do
subject { described_class.new(context) }
it_behaves_like 'a panel with uniquely identifiable menu items'
+ it_behaves_like 'a panel instantiable by the anonymous user'
it 'implements #super_sidebar_context_header' do
- expect(subject.super_sidebar_context_header).to eq({ title: _('User settings'), avatar: user.avatar_url })
+ expect(subject.super_sidebar_context_header).to eq(_('User settings'))
end
end
diff --git a/spec/lib/sidebars/your_work/menus/organizations_menu_spec.rb b/spec/lib/sidebars/your_work/menus/organizations_menu_spec.rb
new file mode 100644
index 00000000000..304725ce8ca
--- /dev/null
+++ b/spec/lib/sidebars/your_work/menus/organizations_menu_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::YourWork::Menus::OrganizationsMenu, feature_category: :navigation do
+ let(:user) { build_stubbed(:user) }
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ describe '#render?' do
+ context 'when `ui_for_organizations` feature flag is enabled' do
+ context 'when `current_user` is available' do
+ before do
+ stub_feature_flags(ui_for_organizations: [user])
+ end
+
+ it 'returns true' do
+ expect(subject.render?).to eq true
+ end
+ end
+
+ context 'when `current_user` is not available' do
+ let(:user) { nil }
+
+ it 'returns false' do
+ expect(subject.render?).to eq false
+ end
+ end
+ end
+
+ context 'when `ui_for_organizations` feature flag is disabled' do
+ before do
+ stub_feature_flags(ui_for_organizations: false)
+ end
+
+ it 'returns false' do
+ expect(subject.render?).to eq false
+ end
+ end
+ end
+end
diff --git a/spec/lib/sidebars/your_work/panel_spec.rb b/spec/lib/sidebars/your_work/panel_spec.rb
index 65c2786a16d..8037f7eb7c1 100644
--- a/spec/lib/sidebars/your_work/panel_spec.rb
+++ b/spec/lib/sidebars/your_work/panel_spec.rb
@@ -10,8 +10,9 @@ RSpec.describe Sidebars::YourWork::Panel, feature_category: :navigation do
subject { described_class.new(context) }
it_behaves_like 'a panel with uniquely identifiable menu items'
+ it_behaves_like 'a panel instantiable by the anonymous user'
it 'implements #super_sidebar_context_header' do
- expect(subject.super_sidebar_context_header).to eq({ title: 'Your work', icon: 'work' })
+ expect(subject.super_sidebar_context_header).to eq(_('Your work'))
end
end
diff --git a/spec/lib/system_check/app/table_truncate_check_spec.rb b/spec/lib/system_check/app/table_truncate_check_spec.rb
new file mode 100644
index 00000000000..673365f3e5e
--- /dev/null
+++ b/spec/lib/system_check/app/table_truncate_check_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe SystemCheck::App::TableTruncateCheck, feature_category: :cell do
+ context 'when running on single databases' do
+ before do
+ skip_if_database_exists(:ci)
+ end
+
+ describe '#skip?' do
+ subject { described_class.new.skip? }
+
+ it { is_expected.to eq(true) }
+ end
+ end
+
+ context 'when running on multiple databases' do
+ let(:needs_truncation) { true }
+
+ before do
+ skip_if_shared_database(:ci)
+
+ allow_next_instances_of(Gitlab::Database::TablesTruncate, 2) do |instance|
+ allow(instance).to receive(:needs_truncation?).and_return(needs_truncation)
+ end
+ end
+
+ describe '#skip?' do
+ subject { described_class.new.skip? }
+
+ it { is_expected.to eq(false) }
+ end
+
+ describe '#check?' do
+ subject { described_class.new.check? }
+
+ context 'when TableTruncate returns false' do
+ let(:needs_truncation) { false }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when TableTruncate returns true' do
+ let(:needs_truncation) { true }
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
+ describe '#show_error' do
+ let(:needs_truncation) { true }
+ let(:checker) { described_class.new }
+
+ before do
+ checker.check?
+ end
+
+ subject(:show_error) { checker.show_error }
+
+ it 'outputs error information' do
+ expected = %r{
+ Try\sfixing\sit:\s+
+ sudo\s-u\s.+?\s-H\sbundle\sexec\srake\sgitlab:db:truncate_legacy_tables:main\s
+ gitlab:db:truncate_legacy_tables:ci\s+
+ For\smore\sinformation\ssee:\s+
+ doc/development/database/multiple_databases.md\sin\ssection\s'Truncating\stables'\s+
+ Please\sfix\sthe\serror\sabove\sand\srerun\sthe\schecks.\s+
+ }x
+
+ expect { show_error }.to output(expected).to_stdout
+ end
+ end
+ end
+end
diff --git a/spec/lib/unnested_in_filters/rewriter_spec.rb b/spec/lib/unnested_in_filters/rewriter_spec.rb
index e094563e8fb..ea561c42993 100644
--- a/spec/lib/unnested_in_filters/rewriter_spec.rb
+++ b/spec/lib/unnested_in_filters/rewriter_spec.rb
@@ -68,92 +68,92 @@ RSpec.describe UnnestedInFilters::Rewriter do
describe '#rewrite' do
let(:recorded_queries) { ActiveRecord::QueryRecorder.new { rewriter.rewrite.load } }
let(:relation) { User.where(state: :active, user_type: %i(support_bot alert_bot)).limit(2) }
+ let(:users_select) { 'SELECT "users".*' }
+ let(:users_select_with_ignored_columns) { 'SELECT ("users"."\w+", )+("users"."\w+")' }
- let(:expected_query) do
- <<~SQL
- SELECT
- "users".*
- FROM
- unnest('{1,2}'::smallint[]) AS "user_types"("user_type"),
- LATERAL (
- SELECT
- "users".*
- FROM
- "users"
- WHERE
- "users"."state" = 'active' AND
- (users."user_type" = "user_types"."user_type")
- LIMIT 2
- ) AS users
- LIMIT 2
- SQL
+ let(:users_unnest) do
+ 'FROM unnest\(\'{1\,2}\'::smallint\[\]\) AS "user_types"\("user_type"\)\, LATERAL \('
+ end
+
+ let(:users_where) do
+ 'FROM
+ "users"
+ WHERE
+ "users"."state" = \'active\' AND
+ \(users."user_type" = "user_types"."user_type"\)
+ LIMIT 2\)
+ AS users
+ LIMIT 2'
+ end
+
+ let(:expected_query_regexp) do
+ Regexp.new(
+ "(#{users_select}|#{users_select_with_ignored_columns})
+ #{users_unnest}(#{users_select}|#{users_select_with_ignored_columns})
+ #{users_where}".squish
+ )
end
subject(:issued_query) { recorded_queries.occurrences.each_key.first }
it 'changes the query' do
- expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
+ expect(issued_query).to match(expected_query_regexp)
end
context 'when the relation has a subquery' do
let(:relation) { User.where(state: User.select(:state), user_type: %i(support_bot alert_bot)).limit(1) }
- let(:expected_query) do
- <<~SQL
- SELECT
- "users".*
- FROM
- unnest(ARRAY(SELECT "users"."state" FROM "users")::character varying[]) AS "states"("state"),
- unnest('{1,2}'::smallint[]) AS "user_types"("user_type"),
- LATERAL (
- SELECT
- "users".*
- FROM
- "users"
- WHERE
- (users."state" = "states"."state") AND
- (users."user_type" = "user_types"."user_type")
- LIMIT 1
- ) AS users
- LIMIT 1
- SQL
+ let(:users_unnest) do
+ 'FROM
+ unnest\(ARRAY\(SELECT "users"."state" FROM "users"\)::character varying\[\]\) AS "states"\("state"\)\,
+ unnest\(\'{1\,2}\'::smallint\[\]\) AS "user_types"\("user_type"\)\,
+ LATERAL \('
+ end
+
+ let(:users_where) do
+ 'FROM
+ "users"
+ WHERE
+ \(users."state" = "states"."state"\) AND
+ \(users."user_type" = "user_types"."user_type"\)
+ LIMIT 1\)
+ AS users
+ LIMIT 1'
end
it 'changes the query' do
- expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
+ expect(issued_query).to match(expected_query_regexp)
end
end
context 'when there is an order' do
let(:relation) { User.where(state: %w(active blocked banned)).order(order).limit(2) }
- let(:expected_query) do
- <<~SQL
- SELECT
- "users".*
- FROM
- unnest('{active,blocked,banned}'::charactervarying[]) AS "states"("state"),
- LATERAL (
- SELECT
- "users".*
- FROM
- "users"
- WHERE
- (users."state" = "states"."state")
- ORDER BY
- "users"."user_type" DESC
- LIMIT 2
- ) AS users
- ORDER BY
- "users"."user_type" DESC
- LIMIT 2
- SQL
+
+ let(:users_unnest) do
+ 'FROM
+ unnest\(\'{active\,blocked\,banned}\'::character varying\[\]\) AS "states"\("state"\)\,
+ LATERAL \('
+ end
+
+ let(:users_where) do
+ 'FROM
+ "users"
+ WHERE
+ \(users."state" = "states"."state"\)
+ ORDER BY
+ "users"."user_type" DESC
+ LIMIT 2\)
+ AS users
+ ORDER BY
+ "users"."user_type" DESC
+ LIMIT 2'
end
context 'when the order is an Arel node' do
let(:order) { { user_type: :desc } }
it 'changes the query' do
- expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
+ expect(issued_query).to match(expected_query_regexp)
end
end
@@ -171,7 +171,7 @@ RSpec.describe UnnestedInFilters::Rewriter do
end
it 'changes the query' do
- expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
+ expect(issued_query).to match(expected_query_regexp)
end
end
end
@@ -179,85 +179,82 @@ RSpec.describe UnnestedInFilters::Rewriter do
context 'when the combined attributes include the primary key' do
let(:relation) { User.where(user_type: %i(support_bot alert_bot)).order(id: :desc).limit(2) }
- let(:expected_query) do
- <<~SQL
- SELECT
- "users".*
- FROM
- "users"
- WHERE
- "users"."id" IN (
- SELECT
- "users"."id"
- FROM
- unnest('{1,2}' :: smallint []) AS "user_types"("user_type"),
- LATERAL (
- SELECT
- "users"."user_type",
- "users"."id"
- FROM
- "users"
- WHERE
- (users."user_type" = "user_types"."user_type")
- ORDER BY
- "users"."id" DESC
- LIMIT
- 2
- ) AS users
- ORDER BY
- "users"."id" DESC
- LIMIT
- 2
- )
- ORDER BY
+ let(:users_where) do
+ 'FROM
+ "users"
+ WHERE
+ "users"."id" IN
+ \(SELECT
+ "users"."id"
+ FROM
+ unnest\(\'{1\,2}\'::smallint\[\]\) AS "user_types"\("user_type"\)\,
+ LATERAL
+ \(SELECT
+ "users"."user_type"\,
+ "users"."id"
+ FROM
+ "users"
+ WHERE
+ \(users."user_type" = "user_types"."user_type"\)
+ ORDER BY
+ "users"."id" DESC
+ LIMIT 2\)
+ AS users
+ ORDER BY
"users"."id" DESC
- LIMIT
- 2
- SQL
+ LIMIT 2\)
+ ORDER BY
+ "users"."id" DESC
+ LIMIT 2'
+ end
+
+ let(:expected_query_regexp) do
+ Regexp.new("(#{users_select}|#{users_select_with_ignored_columns}) #{users_where}".squish)
end
it 'changes the query' do
- expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
+ expect(issued_query).to match(expected_query_regexp)
end
end
context 'when a join table is receiving an IN list query' do
let(:relation) { User.joins(:status).where(status: { message: %w[foo bar] }).order(id: :desc).limit(2) }
- let(:expected_query) do
- <<~SQL
- SELECT
- "users".*
- FROM
- "users"
- WHERE
- "users"."id" IN (
- SELECT
- "users"."id"
- FROM
- LATERAL (
- SELECT
- message,
- "users"."id"
- FROM
- "users"
- INNER JOIN "user_statuses" "status" ON "status"."user_id" = "users"."id"
- WHERE
- "status"."message" IN ('foo', 'bar')
- ORDER BY
- "users"."id" DESC
- LIMIT 2) AS users
- ORDER BY
- "users"."id" DESC
- LIMIT 2)
- ORDER BY
+ let(:users_where) do
+ 'FROM
+ "users"
+ WHERE
+ "users"."id" IN
+ \(SELECT
+ "users"."id"
+ FROM
+ LATERAL
+ \(SELECT
+ message,
+ "users"."id"
+ FROM
+ "users"
+ INNER JOIN "user_statuses" "status" ON "status"."user_id" = "users"."id"
+ WHERE
+ "status"."message" IN \(\'foo\'\, \'bar\'\)
+ ORDER BY
+ "users"."id" DESC
+ LIMIT 2\)
+ AS users
+ ORDER BY
"users"."id" DESC
- LIMIT 2
- SQL
+ LIMIT 2\)
+ ORDER BY
+ "users"."id" DESC
+ LIMIT 2'
+ end
+
+ let(:expected_query_regexp) do
+ Regexp.new("(#{users_select}|#{users_select_with_ignored_columns}) #{users_where}".squish)
end
it 'does not rewrite the in statement for the joined table' do
- expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
+ expect(issued_query).to match(expected_query_regexp)
end
end
diff --git a/spec/lib/users/internal_spec.rb b/spec/lib/users/internal_spec.rb
new file mode 100644
index 00000000000..b7368f5042e
--- /dev/null
+++ b/spec/lib/users/internal_spec.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::Internal, feature_category: :user_profile do
+ shared_examples 'bot users' do |bot_type, username, email|
+ it 'creates the user if it does not exist' do
+ expect do
+ described_class.public_send(bot_type)
+ end.to change { User.where(user_type: bot_type).count }.by(1)
+ end
+
+ it 'creates a route for the namespace of the created user' do
+ bot_user = described_class.public_send(bot_type)
+
+ expect(bot_user.namespace.route).to be_present
+ end
+
+ it 'does not create a new user if it already exists' do
+ described_class.public_send(bot_type)
+
+ expect do
+ described_class.public_send(bot_type)
+ end.not_to change { User.count }
+ end
+
+ context 'when a regular user exists with the bot usernane' do
+ it 'creates a user with a non-conflicting username' do
+ create(:user, username: username)
+
+ expect do
+ described_class.public_send(bot_type)
+ end.to change { User.where(user_type: bot_type).count }.by(1)
+ end
+ end
+
+ context 'when a regular user exists with the bot user email' do
+ it 'creates a user with a non-conflicting email' do
+ create(:user, email: email)
+
+ expect do
+ described_class.public_send(bot_type)
+ end.to change { User.where(user_type: bot_type).count }.by(1)
+ end
+ end
+
+ context 'when a domain allowlist is in place' do
+ before do
+ stub_application_setting(domain_allowlist: ['gitlab.com'])
+ end
+
+ it 'creates the bot user' do
+ expect do
+ described_class.public_send(bot_type)
+ end.to change { User.where(user_type: bot_type).count }.by(1)
+ end
+ end
+ end
+
+ shared_examples 'bot user avatars' do |bot_type, avatar_filename|
+ it 'sets the custom avatar for the created bot' do
+ bot_user = described_class.public_send(bot_type)
+
+ expect(bot_user.avatar.url).to be_present
+ expect(bot_user.avatar.filename).to eq(avatar_filename)
+ end
+ end
+
+ it_behaves_like 'bot users', :alert_bot, 'alert-bot', 'alert@example.com'
+ it_behaves_like 'bot users', :support_bot, 'support-bot', 'support@example.com'
+ it_behaves_like 'bot users', :migration_bot, 'migration-bot', 'noreply+gitlab-migration-bot@example.com'
+ it_behaves_like 'bot users', :security_bot, 'GitLab-Security-Bot', 'security-bot@example.com'
+ it_behaves_like 'bot users', :ghost, 'ghost', 'ghost@example.com'
+ it_behaves_like 'bot users', :automation_bot, 'automation-bot', 'automation@example.com'
+ it_behaves_like 'bot users', :llm_bot, 'GitLab-Llm-Bot', 'llm-bot@example.com'
+ it_behaves_like 'bot users', :admin_bot, 'GitLab-Admin-Bot', 'admin-bot@example.com'
+
+ it_behaves_like 'bot user avatars', :alert_bot, 'alert-bot.png'
+ it_behaves_like 'bot user avatars', :support_bot, 'support-bot.png'
+ it_behaves_like 'bot user avatars', :security_bot, 'security-bot.png'
+ it_behaves_like 'bot user avatars', :automation_bot, 'support-bot.png'
+ it_behaves_like 'bot user avatars', :llm_bot, 'support-bot.png'
+ it_behaves_like 'bot user avatars', :admin_bot, 'admin-bot.png'
+
+ context 'when bot is the support_bot' do
+ subject { described_class.support_bot }
+
+ it { is_expected.to be_confirmed }
+ end
+
+ context 'when bot is the admin bot' do
+ subject { described_class.admin_bot }
+
+ it { is_expected.to be_admin }
+ it { is_expected.to be_confirmed }
+ end
+end
diff --git a/spec/mailers/emails/in_product_marketing_spec.rb b/spec/mailers/emails/in_product_marketing_spec.rb
index 2d332dd99d6..93a06bfc881 100644
--- a/spec/mailers/emails/in_product_marketing_spec.rb
+++ b/spec/mailers/emails/in_product_marketing_spec.rb
@@ -25,75 +25,6 @@ RSpec.describe Emails::InProductMarketing do
end
end
- describe '#in_product_marketing_email' do
- let_it_be(:group) { create(:group) }
-
- let!(:onboarding_progress) { create(:onboarding_progress, namespace: group) }
-
- using RSpec::Parameterized::TableSyntax
-
- let(:track) { :create }
- let(:series) { 0 }
-
- subject { Notify.in_product_marketing_email(user.id, group.id, track, series) }
-
- include_context 'gitlab email notification'
-
- it_behaves_like 'has custom headers when on gitlab.com'
-
- it 'sends to the right user with a link to unsubscribe' do
- aggregate_failures do
- expect(subject).to deliver_to(user.notification_email_or_default)
- expect(subject).to have_body_text(profile_notifications_url)
- end
- end
-
- where(:track, :series) do
- :create | 0
- :create | 1
- :create | 2
- :verify | 0
- :verify | 1
- :verify | 2
- :trial | 0
- :trial | 1
- :trial | 2
- :team | 0
- :team | 1
- :team | 2
- :team_short | 0
- :trial_short | 0
- :admin_verify | 0
- end
-
- with_them do
- before do
- group.add_owner(user)
- end
-
- it 'has the correct subject and content' do
- message = Gitlab::Email::Message::InProductMarketing.for(track).new(group: group, user: user, series: series)
-
- aggregate_failures do
- is_expected.to have_subject(message.subject_line)
- is_expected.to have_body_text(message.title)
- is_expected.to have_body_text(message.subtitle)
- is_expected.to have_body_text(CGI.unescapeHTML(message.cta_link))
-
- if /create|verify/.match?(track)
- is_expected.to have_body_text(message.invite_text)
- is_expected.to have_body_text(CGI.unescapeHTML(message.invite_link))
- else
- is_expected.not_to have_body_text(message.invite_text)
- is_expected.not_to have_body_text(CGI.unescapeHTML(message.invite_link))
- end
-
- is_expected.to have_body_text(message.progress)
- end
- end
- end
- end
-
describe '#build_ios_app_guide_email' do
subject { Notify.build_ios_app_guide_email(user.notification_email_or_default) }
diff --git a/spec/mailers/emails/profile_spec.rb b/spec/mailers/emails/profile_spec.rb
index 140b067f7aa..4816e88a311 100644
--- a/spec/mailers/emails/profile_spec.rb
+++ b/spec/mailers/emails/profile_spec.rb
@@ -157,42 +157,67 @@ RSpec.describe Emails::Profile, feature_category: :user_profile do
end
end
- describe 'user personal access token is about to expire' do
+ describe 'resource access token is about to expire' do
let_it_be(:user) { create(:user) }
- let_it_be(:expiring_token) { create(:personal_access_token, user: user, expires_at: 5.days.from_now) }
- subject { Notify.access_token_about_to_expire_email(user, [expiring_token.name]) }
+ shared_examples 'resource about to expire email' do
+ it 'is sent to the owners' do
+ is_expected.to deliver_to user
+ end
- it_behaves_like 'an email sent from GitLab'
- it_behaves_like 'it should not have Gmail Actions links'
- it_behaves_like 'a user cannot unsubscribe through footer link'
+ it 'has the correct subject' do
+ is_expected.to have_subject /^Your resource access tokens will expire in 7 days or less$/i
+ end
- it 'is sent to the user' do
- is_expected.to deliver_to user.email
- end
+ it 'includes a link to access tokens page' do
+ is_expected.to have_body_text /#{resource_access_tokens_path}/
+ end
- it 'has the correct subject' do
- is_expected.to have_subject /^Your personal access tokens will expire in 7 days or less$/i
- end
+ it 'provides the names of expiring tokens' do
+ is_expected.to have_body_text /#{expiring_token.name}/
+ end
- it 'mentions the access tokens will expire' do
- is_expected.to have_body_text /One or more of your personal access tokens will expire in 7 days or less/
+ it 'includes the email reason' do
+ is_expected.to have_body_text %r{You're receiving this email because of your account on <a .*>localhost</a>}
+ end
end
- it 'provides the names of expiring tokens' do
- is_expected.to have_body_text /#{expiring_token.name}/
- end
+ context 'when access token belongs to a group' do
+ let_it_be(:project_bot) { create(:user, :project_bot) }
+ let_it_be(:expiring_token) { create(:personal_access_token, user: project_bot, expires_at: 5.days.from_now) }
+ let_it_be(:resource) { create(:group) }
+ let_it_be(:resource_access_tokens_path) { group_settings_access_tokens_path(resource) }
- it 'includes a link to personal access tokens page' do
- is_expected.to have_body_text /#{profile_personal_access_tokens_path}/
- end
+ before_all do
+ resource.add_owner(user)
+ resource.add_developer(project_bot)
+ end
- it 'includes the email reason' do
- is_expected.to have_body_text %r{You're receiving this email because of your account on <a .*>localhost</a>}
+ subject { Notify.resource_access_tokens_about_to_expire_email(user, resource, [expiring_token.name]) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
+ it_behaves_like 'resource about to expire email'
end
- context 'with User does not exist' do
- it { expect { Notify.access_token_about_to_expire_email('foo') }.not_to raise_error }
+ context 'when access token belongs to a project' do
+ let_it_be(:project_bot) { create(:user, :project_bot) }
+ let_it_be(:expiring_token) { create(:personal_access_token, user: project_bot, expires_at: 5.days.from_now) }
+ let_it_be(:resource) { create(:project) }
+ let_it_be(:resource_access_tokens_path) { project_settings_access_tokens_path(resource) }
+
+ before_all do
+ resource.add_maintainer(user)
+ resource.add_reporter(project_bot)
+ end
+
+ subject { Notify.resource_access_tokens_about_to_expire_email(user, resource, [expiring_token.name]) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
+ it_behaves_like 'resource about to expire email'
end
end
diff --git a/spec/mailers/emails/service_desk_spec.rb b/spec/mailers/emails/service_desk_spec.rb
index 8c0efe3f480..e3fe36237df 100644
--- a/spec/mailers/emails/service_desk_spec.rb
+++ b/spec/mailers/emails/service_desk_spec.rb
@@ -26,6 +26,16 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
issue.issue_email_participants.create!(email: email)
end
+ before do
+ # Because we use global project and custom email instances, make sure
+ # custom email is disabled in all regular cases to avoid flakiness.
+ unless service_desk_setting.custom_email_verification.started?
+ service_desk_setting.custom_email_verification.mark_as_started!(user)
+ end
+
+ service_desk_setting.update!(custom_email_enabled: false) unless service_desk_setting.custom_email_enabled?
+ end
+
shared_examples 'a service desk notification email' do |attachments_count|
it 'builds the email correctly' do
aggregate_failures do
@@ -42,6 +52,10 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
expect(subject.parts[1].content_type).to include('text/html')
end
end
+
+ it 'uses system noreply address as Reply-To address' do
+ expect(subject.reply_to.first).to eq(Gitlab.config.gitlab.email_reply_to)
+ end
end
shared_examples 'a service desk notification email with template content' do |template_key, attachments_count|
@@ -145,6 +159,45 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
end
end
+ shared_examples 'a service desk notification email that uses custom email' do
+ before do
+ # Access via service_desk_setting to avoid flakiness
+ unless service_desk_setting.custom_email_verification.finished?
+ service_desk_setting.custom_email_verification.error = nil
+ service_desk_setting.custom_email_verification.mark_as_finished!
+ end
+
+ # Reset because we access changed records through these objects
+ service_desk_setting.reset
+ project.reset
+
+ service_desk_setting.update!(custom_email_enabled: true) unless service_desk_setting.custom_email_enabled?
+
+ allow(Gitlab::AppLogger).to receive(:info)
+ end
+
+ it 'uses SMTP delivery method and custom email settings' do
+ expect_service_desk_custom_email_delivery_options(service_desk_setting)
+
+ expect(Gitlab::AppLogger).to have_received(:info).with({ category: 'custom_email' })
+ end
+
+ it 'generates Reply-To address from custom email' do
+ reply_address = subject.reply_to.first
+ expected_reply_address = service_desk_setting.custom_email.sub('@', "+#{SentNotification.last.reply_key}@")
+
+ expect(reply_address).to eq(expected_reply_address)
+ end
+
+ context 'when feature flag service_desk_custom_email_reply is disabled' do
+ before do
+ stub_feature_flags(service_desk_custom_email_reply: false)
+ end
+
+ it { is_expected.to have_header 'Reply-To', /<reply+(.*)@#{Gitlab.config.gitlab.host}>\Z/ }
+ end
+ end
+
describe '.service_desk_thank_you_email' do
let_it_be(:reply_in_subject) { true }
let_it_be(:expected_text) do
@@ -234,6 +287,12 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
end
end
end
+
+ context 'when custom email is enabled' do
+ subject { Notify.service_desk_thank_you_email(issue.id) }
+
+ it_behaves_like 'a service desk notification email that uses custom email'
+ end
end
describe '.service_desk_new_note_email' do
@@ -295,7 +354,7 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
end
context 'with all-user reference in a an external author comment' do
- let_it_be(:note) { create(:note_on_issue, noteable: issue, project: project, note: "Hey @all, just a ping", author: User.support_bot) }
+ let_it_be(:note) { create(:note_on_issue, noteable: issue, project: project, note: "Hey @all, just a ping", author: Users::Internal.support_bot) }
let(:template_content) { 'some text %{ NOTE_TEXT }' }
@@ -435,19 +494,44 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
it_behaves_like 'a service desk notification email with template content', 'new_note'
end
end
+
+ context 'when custom email is enabled' do
+ subject { Notify.service_desk_new_note_email(issue.id, note.id, email) }
+
+ it_behaves_like 'a service desk notification email that uses custom email'
+ end
end
describe '.service_desk_custom_email_verification_email' do
+ # Use strict definition here because Mail::SMTP.new({}).settings
+ # might have been changed before.
+ let(:expected_delivery_method_defaults) do
+ {
+ address: 'localhost',
+ domain: 'localhost.localdomain',
+ port: 25,
+ password: nil,
+ user_name: nil
+ }
+ end
+
subject { Notify.service_desk_custom_email_verification_email(service_desk_setting) }
it_behaves_like 'a custom email verification process email'
it 'uses service bot name and custom email as sender' do
- expect_sender(User.support_bot, sender_email: service_desk_setting.custom_email)
+ expect_sender(Users::Internal.support_bot, sender_email: service_desk_setting.custom_email)
end
it 'forcibly uses SMTP delivery method and has correct settings' do
expect_service_desk_custom_email_delivery_options(service_desk_setting)
+
+ # defaults are unchanged after email overrode settings
+ expect(Mail::SMTP.new({}).settings).to include(expected_delivery_method_defaults)
+
+ # other mailers are unchanged after email overrode settings
+ other_mail = Notify.test_email(email, 'Test subject', 'Test body')
+ expect(other_mail.delivery_method).to be_a(Mail::TestMailer)
end
it 'uses verification email address as recipient' do
@@ -455,7 +539,7 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
end
it 'contains verification token' do
- is_expected.to have_body_text("Verification token: #{verification.token}")
+ is_expected.to have_body_text("Verification token: #{service_desk_setting.custom_email_verification.token}")
end
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 976fe214c95..9df89f84450 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -1059,21 +1059,10 @@ RSpec.describe Notify do
is_expected.to have_body_text project_member.human_access
is_expected.to have_body_text 'leave the project'
is_expected.to have_body_text project_url(project, leave: 1)
- is_expected.not_to have_body_text 'You were assigned the following tasks:'
- end
-
- context 'with tasks to be done present' do
- let(:project_member) { create(:project_member, project: project, user: user, tasks_to_be_done: [:ci, :code]) }
-
- it 'contains the assigned tasks to be done' do
- is_expected.to have_body_text 'You were assigned the following tasks:'
- is_expected.to have_body_text localized_tasks_to_be_done_choices[:ci]
- is_expected.to have_body_text localized_tasks_to_be_done_choices[:code]
- end
end
end
- def invite_to_project(project, inviter:, user: nil, tasks_to_be_done: [])
+ def invite_to_project(project, inviter:, user: nil)
create(
:project_member,
:developer,
@@ -1081,8 +1070,7 @@ RSpec.describe Notify do
invite_token: '1234',
invite_email: 'toto@example.com',
user: user,
- created_by: inviter,
- tasks_to_be_done: tasks_to_be_done
+ created_by: inviter
)
end
@@ -1115,7 +1103,6 @@ RSpec.describe Notify do
is_expected.to have_content("#{inviter.name} invited you to join the")
is_expected.to have_content('Project details')
is_expected.to have_content("What's it about?")
- is_expected.not_to have_body_text 'and has assigned you the following tasks:'
end
end
@@ -1161,16 +1148,6 @@ RSpec.describe Notify do
end
end
end
-
- context 'with tasks to be done present', :aggregate_failures do
- let(:project_member) { invite_to_project(project, inviter: inviter, tasks_to_be_done: [:ci, :code]) }
-
- it 'contains the assigned tasks to be done' do
- is_expected.to have_body_text 'and has assigned you the following tasks:'
- is_expected.to have_body_text localized_tasks_to_be_done_choices[:ci]
- is_expected.to have_body_text localized_tasks_to_be_done_choices[:code]
- end
- end
end
describe 'project invitation accepted' do
@@ -1560,7 +1537,7 @@ RSpec.describe Notify do
end
it 'uses service bot name by default' do
- expect_sender(User.support_bot)
+ expect_sender(Users::Internal.support_bot)
end
context 'when custom outgoing name is set' do
@@ -1577,7 +1554,7 @@ RSpec.describe Notify do
let_it_be(:settings) { create(:service_desk_setting, project: project, outgoing_name: '') }
it 'uses service bot name' do
- expect_sender(User.support_bot)
+ expect_sender(Users::Internal.support_bot)
end
end
@@ -1589,7 +1566,7 @@ RSpec.describe Notify do
it_behaves_like 'a mail with default delivery method'
it 'uses service bot name by default' do
- expect_sender(User.support_bot)
+ expect_sender(Users::Internal.support_bot)
end
context 'when custom email is enabled' do
@@ -1611,7 +1588,7 @@ RSpec.describe Notify do
end
it 'uses custom email and service bot name in "from" header' do
- expect_sender(User.support_bot, sender_email: 'supersupport@example.com')
+ expect_sender(Users::Internal.support_bot, sender_email: 'supersupport@example.com')
end
it 'uses SMTP delivery method and has correct settings' do
@@ -1773,7 +1750,7 @@ RSpec.describe Notify do
end
end
- def invite_to_group(group, inviter:, user: nil, tasks_to_be_done: [])
+ def invite_to_group(group, inviter:, user: nil)
create(
:group_member,
:developer,
@@ -1781,8 +1758,7 @@ RSpec.describe Notify do
invite_token: '1234',
invite_email: 'toto@example.com',
user: user,
- created_by: inviter,
- tasks_to_be_done: tasks_to_be_done
+ created_by: inviter
)
end
@@ -1807,7 +1783,6 @@ RSpec.describe Notify do
is_expected.to have_body_text group.name
is_expected.to have_body_text group_member.human_access.downcase
is_expected.to have_body_text group_member.invite_token
- is_expected.not_to have_body_text 'and has assigned you the following tasks:'
end
end
@@ -1821,24 +1796,6 @@ RSpec.describe Notify do
is_expected.to have_body_text group_member.invite_token
end
end
-
- context 'with tasks to be done present', :aggregate_failures do
- let(:group_member) { invite_to_group(group, inviter: inviter, tasks_to_be_done: [:ci, :code]) }
-
- it 'contains the assigned tasks to be done' do
- is_expected.to have_body_text 'and has assigned you the following tasks:'
- is_expected.to have_body_text localized_tasks_to_be_done_choices[:ci]
- is_expected.to have_body_text localized_tasks_to_be_done_choices[:code]
- end
-
- context 'when there is no inviter' do
- let(:inviter) { nil }
-
- it 'does not contain the assigned tasks to be done' do
- is_expected.not_to have_body_text 'and has assigned you the following tasks:'
- end
- end
- end
end
describe 'group invitation reminders' do
@@ -2534,17 +2491,4 @@ RSpec.describe Notify do
end
end
end
-
- describe 'in product marketing', :mailer do
- let_it_be(:group) { create(:group) }
-
- let(:mail) { ActionMailer::Base.deliveries.last }
-
- it 'does not raise error' do
- described_class.in_product_marketing_email(user.id, group.id, :trial, 0).deliver
-
- expect(mail.subject).to eq('Go farther with GitLab')
- expect(mail.body.parts.first.to_s).to include('Start a GitLab Ultimate trial today in less than one minute, no credit card required.')
- end
- end
end
diff --git a/spec/migrations/20230125093723_rebalance_partition_id_ci_pipeline_spec.rb b/spec/migrations/20230125093723_rebalance_partition_id_ci_pipeline_spec.rb
deleted file mode 100644
index 3ccd92e15a4..00000000000
--- a/spec/migrations/20230125093723_rebalance_partition_id_ci_pipeline_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe RebalancePartitionIdCiPipeline, migration: :gitlab_ci, feature_category: :continuous_integration do
- let(:migration) { described_class::MIGRATION }
-
- context 'when on sass' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- describe '#up' do
- it 'schedules background jobs for each batch of ci_builds' do
- migrate!
-
- expect(migration).to have_scheduled_batched_migration(
- gitlab_schema: :gitlab_ci,
- table_name: :ci_pipelines,
- column_name: :id,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
- )
- end
- end
-
- describe '#down' do
- it 'deletes all batched migration records' do
- migrate!
- schema_migrate_down!
-
- expect(migration).not_to have_scheduled_batched_migration
- end
- end
- end
-
- context 'when on self-managed instance' do
- let(:migration) { described_class.new }
-
- describe '#up' do
- it 'does not schedule background job' do
- expect(migration).not_to receive(:queue_batched_background_migration)
-
- migration.up
- end
- end
-
- describe '#down' do
- it 'does not delete background job' do
- expect(migration).not_to receive(:delete_batched_background_migration)
-
- migration.down
- end
- end
- end
-end
diff --git a/spec/migrations/20230125093840_rebalance_partition_id_ci_build_spec.rb b/spec/migrations/20230125093840_rebalance_partition_id_ci_build_spec.rb
deleted file mode 100644
index b983564a2d9..00000000000
--- a/spec/migrations/20230125093840_rebalance_partition_id_ci_build_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe RebalancePartitionIdCiBuild, migration: :gitlab_ci, feature_category: :continuous_integration do
- let(:migration) { described_class::MIGRATION }
-
- context 'when on sass' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- describe '#up' do
- it 'schedules background jobs for each batch of ci_builds' do
- migrate!
-
- expect(migration).to have_scheduled_batched_migration(
- gitlab_schema: :gitlab_ci,
- table_name: :ci_builds,
- column_name: :id,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
- )
- end
- end
-
- describe '#down' do
- it 'deletes all batched migration records' do
- migrate!
- schema_migrate_down!
-
- expect(migration).not_to have_scheduled_batched_migration
- end
- end
- end
-
- context 'when on self-managed instance' do
- let(:migration) { described_class.new }
-
- describe '#up' do
- it 'does not schedule background job' do
- expect(migration).not_to receive(:queue_batched_background_migration)
-
- migration.up
- end
- end
-
- describe '#down' do
- it 'does not delete background job' do
- expect(migration).not_to receive(:delete_batched_background_migration)
-
- migration.down
- end
- end
- end
-end
diff --git a/spec/migrations/20230208100917_fix_partition_ids_for_ci_pipeline_variable_spec.rb b/spec/migrations/20230208100917_fix_partition_ids_for_ci_pipeline_variable_spec.rb
deleted file mode 100644
index fb0e1fe17ec..00000000000
--- a/spec/migrations/20230208100917_fix_partition_ids_for_ci_pipeline_variable_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe FixPartitionIdsForCiPipelineVariable, migration: :gitlab_ci, feature_category: :continuous_integration do
- let(:migration) { described_class::MIGRATION }
-
- context 'when on saas' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- describe '#up' do
- it 'schedules background jobs for each batch of ci_pipeline_variables' do
- migrate!
-
- expect(migration).to have_scheduled_batched_migration(
- gitlab_schema: :gitlab_ci,
- table_name: :ci_pipeline_variables,
- column_name: :id,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
- )
- end
- end
-
- describe '#down' do
- it 'deletes all batched migration records' do
- migrate!
- schema_migrate_down!
-
- expect(migration).not_to have_scheduled_batched_migration
- end
- end
- end
-
- context 'when on self-managed instance' do
- let(:migration) { described_class.new }
-
- describe '#up' do
- it 'does not schedule background job' do
- expect(migration).not_to receive(:queue_batched_background_migration)
-
- migration.up
- end
- end
-
- describe '#down' do
- it 'does not delete background job' do
- expect(migration).not_to receive(:delete_batched_background_migration)
-
- migration.down
- end
- end
- end
-end
diff --git a/spec/migrations/20230208103009_fix_partition_ids_for_ci_job_artifact_spec.rb b/spec/migrations/20230208103009_fix_partition_ids_for_ci_job_artifact_spec.rb
deleted file mode 100644
index de2386c6a0d..00000000000
--- a/spec/migrations/20230208103009_fix_partition_ids_for_ci_job_artifact_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe FixPartitionIdsForCiJobArtifact, migration: :gitlab_ci, feature_category: :continuous_integration do
- let(:migration) { described_class::MIGRATION }
-
- context 'when on saas' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- describe '#up' do
- it 'schedules background jobs for each batch of ci_job_artifacts' do
- migrate!
-
- expect(migration).to have_scheduled_batched_migration(
- gitlab_schema: :gitlab_ci,
- table_name: :ci_job_artifacts,
- column_name: :id,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
- )
- end
- end
-
- describe '#down' do
- it 'deletes all batched migration records' do
- migrate!
- schema_migrate_down!
-
- expect(migration).not_to have_scheduled_batched_migration
- end
- end
- end
-
- context 'when on self-managed instance' do
- let(:migration) { described_class.new }
-
- describe '#up' do
- it 'does not schedule background job' do
- expect(migration).not_to receive(:queue_batched_background_migration)
-
- migration.up
- end
- end
-
- describe '#down' do
- it 'does not delete background job' do
- expect(migration).not_to receive(:delete_batched_background_migration)
-
- migration.down
- end
- end
- end
-end
diff --git a/spec/migrations/20230208132608_fix_partition_ids_for_ci_stage_spec.rb b/spec/migrations/20230208132608_fix_partition_ids_for_ci_stage_spec.rb
deleted file mode 100644
index 8b057afc1e9..00000000000
--- a/spec/migrations/20230208132608_fix_partition_ids_for_ci_stage_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe FixPartitionIdsForCiStage, migration: :gitlab_ci, feature_category: :continuous_integration do
- let(:migration) { described_class::MIGRATION }
-
- context 'when on saas' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- describe '#up' do
- it 'schedules background jobs for each batch of ci_stages' do
- migrate!
-
- expect(migration).to have_scheduled_batched_migration(
- gitlab_schema: :gitlab_ci,
- table_name: :ci_stages,
- column_name: :id,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
- )
- end
- end
-
- describe '#down' do
- it 'deletes all batched migration records' do
- migrate!
- schema_migrate_down!
-
- expect(migration).not_to have_scheduled_batched_migration
- end
- end
- end
-
- context 'when on self-managed instance' do
- let(:migration) { described_class.new }
-
- describe '#up' do
- it 'does not schedule background job' do
- expect(migration).not_to receive(:queue_batched_background_migration)
-
- migration.up
- end
- end
-
- describe '#down' do
- it 'does not delete background job' do
- expect(migration).not_to receive(:delete_batched_background_migration)
-
- migration.down
- end
- end
- end
-end
diff --git a/spec/migrations/20230209090702_fix_partition_ids_for_ci_build_report_result_spec.rb b/spec/migrations/20230209090702_fix_partition_ids_for_ci_build_report_result_spec.rb
deleted file mode 100644
index f0ac8239f58..00000000000
--- a/spec/migrations/20230209090702_fix_partition_ids_for_ci_build_report_result_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe FixPartitionIdsForCiBuildReportResult,
- migration: :gitlab_ci,
- feature_category: :continuous_integration do
- let(:migration) { described_class::MIGRATION }
-
- context 'when on saas' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- describe '#up' do
- it 'schedules background jobs for each batch of ci_build_report_results' do
- migrate!
-
- expect(migration).to have_scheduled_batched_migration(
- gitlab_schema: :gitlab_ci,
- table_name: :ci_build_report_results,
- column_name: :build_id,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
- )
- end
- end
-
- describe '#down' do
- it 'deletes all batched migration records' do
- migrate!
- schema_migrate_down!
-
- expect(migration).not_to have_scheduled_batched_migration
- end
- end
- end
-
- context 'when on self-managed instance' do
- let(:migration) { described_class.new }
-
- describe '#up' do
- it 'does not schedule background job' do
- expect(migration).not_to receive(:queue_batched_background_migration)
-
- migration.up
- end
- end
-
- describe '#down' do
- it 'does not delete background job' do
- expect(migration).not_to receive(:delete_batched_background_migration)
-
- migration.down
- end
- end
- end
-end
diff --git a/spec/migrations/20230209092204_fix_partition_ids_for_ci_build_trace_metadata_spec.rb b/spec/migrations/20230209092204_fix_partition_ids_for_ci_build_trace_metadata_spec.rb
deleted file mode 100644
index a93ba36d9ae..00000000000
--- a/spec/migrations/20230209092204_fix_partition_ids_for_ci_build_trace_metadata_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe FixPartitionIdsForCiBuildTraceMetadata,
- migration: :gitlab_ci,
- feature_category: :continuous_integration do
- let(:migration) { described_class::MIGRATION }
-
- context 'when on saas' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- describe '#up' do
- it 'schedules background jobs for each batch of ci_build_trace_metadata' do
- migrate!
-
- expect(migration).to have_scheduled_batched_migration(
- gitlab_schema: :gitlab_ci,
- table_name: :ci_build_trace_metadata,
- column_name: :build_id,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
- )
- end
- end
-
- describe '#down' do
- it 'deletes all batched migration records' do
- migrate!
- schema_migrate_down!
-
- expect(migration).not_to have_scheduled_batched_migration
- end
- end
- end
-
- context 'when on self-managed instance' do
- let(:migration) { described_class.new }
-
- describe '#up' do
- it 'does not schedule background job' do
- expect(migration).not_to receive(:queue_batched_background_migration)
-
- migration.up
- end
- end
-
- describe '#down' do
- it 'does not delete background job' do
- expect(migration).not_to receive(:delete_batched_background_migration)
-
- migration.down
- end
- end
- end
-end
diff --git a/spec/migrations/20230209140102_fix_partition_ids_for_ci_build_metadata_spec.rb b/spec/migrations/20230209140102_fix_partition_ids_for_ci_build_metadata_spec.rb
deleted file mode 100644
index c354d68749f..00000000000
--- a/spec/migrations/20230209140102_fix_partition_ids_for_ci_build_metadata_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe FixPartitionIdsForCiBuildMetadata,
- migration: :gitlab_ci,
- feature_category: :continuous_integration do
- let(:migration) { described_class::MIGRATION }
-
- context 'when on saas' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- describe '#up' do
- it 'schedules background jobs for each batch of p_ci_builds_metadata' do
- migrate!
-
- expect(migration).to have_scheduled_batched_migration(
- gitlab_schema: :gitlab_ci,
- table_name: :p_ci_builds_metadata,
- column_name: :id,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
- )
- end
- end
-
- describe '#down' do
- it 'deletes all batched migration records' do
- migrate!
- schema_migrate_down!
-
- expect(migration).not_to have_scheduled_batched_migration
- end
- end
- end
-
- context 'when on self-managed instance' do
- let(:migration) { described_class.new }
-
- describe '#up' do
- it 'does not schedule background job' do
- expect(migration).not_to receive(:queue_batched_background_migration)
-
- migration.up
- end
- end
-
- describe '#down' do
- it 'does not delete background job' do
- expect(migration).not_to receive(:delete_batched_background_migration)
-
- migration.down
- end
- end
- end
-end
diff --git a/spec/migrations/20230214122717_fix_partition_ids_for_ci_job_variables_spec.rb b/spec/migrations/20230214122717_fix_partition_ids_for_ci_job_variables_spec.rb
deleted file mode 100644
index 64275855262..00000000000
--- a/spec/migrations/20230214122717_fix_partition_ids_for_ci_job_variables_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe FixPartitionIdsForCiJobVariables, migration: :gitlab_ci, feature_category: :continuous_integration do
- let(:builds) { table(:ci_builds, database: :ci) }
- let(:job_variables) { table(:ci_job_variables, database: :ci) }
- let(:connection) { job_variables.connection }
-
- around do |example|
- connection.execute "ALTER TABLE #{job_variables.quoted_table_name} DISABLE TRIGGER ALL;"
-
- example.run
- ensure
- connection.execute "ALTER TABLE #{job_variables.quoted_table_name} ENABLE TRIGGER ALL;"
- end
-
- before do
- job = builds.create!(partition_id: 100)
-
- job_variables.insert_all!([
- { job_id: job.id, partition_id: 100, key: 'variable-100' },
- { job_id: job.id, partition_id: 101, key: 'variable-101' }
- ])
- end
-
- describe '#up', :aggregate_failures do
- context 'when on sass' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- it 'fixes partition_id' do
- expect { migrate! }.not_to raise_error
-
- expect(job_variables.where(partition_id: 100).count).to eq(2)
- expect(job_variables.where(partition_id: 101).count).to eq(0)
- end
- end
-
- context 'when on self managed' do
- it 'does not change partition_id' do
- expect { migrate! }.not_to raise_error
-
- expect(job_variables.where(partition_id: 100).count).to eq(1)
- expect(job_variables.where(partition_id: 101).count).to eq(1)
- end
- end
- end
-end
diff --git a/spec/migrations/20230214154101_fix_partition_ids_on_ci_sources_pipelines_spec.rb b/spec/migrations/20230214154101_fix_partition_ids_on_ci_sources_pipelines_spec.rb
deleted file mode 100644
index 44031175497..00000000000
--- a/spec/migrations/20230214154101_fix_partition_ids_on_ci_sources_pipelines_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe FixPartitionIdsOnCiSourcesPipelines, migration: :gitlab_ci, feature_category: :continuous_integration do
- let(:sources_pipelines) { table(:ci_sources_pipelines, database: :ci) }
-
- before do
- sources_pipelines.insert_all!([
- { partition_id: 100, source_partition_id: 100 },
- { partition_id: 100, source_partition_id: 101 },
- { partition_id: 101, source_partition_id: 100 },
- { partition_id: 101, source_partition_id: 101 }
- ])
- end
-
- describe '#up' do
- context 'when on sass' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- it 'fixes partition_id and source_partition_id' do
- expect { migrate! }.not_to raise_error
-
- expect(sources_pipelines.where(partition_id: 100).count).to eq(4)
- expect(sources_pipelines.where(partition_id: 101).count).to eq(0)
- expect(sources_pipelines.where(source_partition_id: 100).count).to eq(4)
- expect(sources_pipelines.where(source_partition_id: 101).count).to eq(0)
- end
- end
-
- context 'when on self managed' do
- it 'does not change partition_id or source_partition_id' do
- expect { migrate! }.not_to raise_error
-
- expect(sources_pipelines.where(partition_id: 100).count).to eq(2)
- expect(sources_pipelines.where(partition_id: 100).count).to eq(2)
- expect(sources_pipelines.where(source_partition_id: 101).count).to eq(2)
- expect(sources_pipelines.where(source_partition_id: 101).count).to eq(2)
- end
- end
- end
-end
diff --git a/spec/migrations/20230726142555_ensure_notes_bigint_backfill_is_finished_for_self_managed_spec.rb b/spec/migrations/20230726142555_ensure_notes_bigint_backfill_is_finished_for_self_managed_spec.rb
new file mode 100644
index 00000000000..a76ad767cf2
--- /dev/null
+++ b/spec/migrations/20230726142555_ensure_notes_bigint_backfill_is_finished_for_self_managed_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe EnsureNotesBigintBackfillIsFinishedForSelfManaged, feature_category: :database do
+ describe '#up' do
+ let(:migration_arguments) do
+ {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'notes',
+ column_name: 'id',
+ job_arguments: [['id'], ['id_convert_to_bigint']]
+ }
+ end
+
+ it 'ensures the migration is completed for self-managed instances' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+
+ migrate!
+ end
+
+ it 'skips the check for GitLab.com, dev, or test' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+ expect(instance).not_to receive(:ensure_batched_background_migration_is_finished)
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/20230726144458_swap_notes_id_to_bigint_for_self_managed_spec.rb b/spec/migrations/20230726144458_swap_notes_id_to_bigint_for_self_managed_spec.rb
new file mode 100644
index 00000000000..b4552cebc58
--- /dev/null
+++ b/spec/migrations/20230726144458_swap_notes_id_to_bigint_for_self_managed_spec.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapNotesIdToBigintForSelfManaged, feature_category: :database do
+ let(:connection) { described_class.new.connection }
+
+ shared_examples 'column `id_convert_to_bigint` is already dropped' do
+ before do
+ connection.execute('ALTER TABLE notes ALTER COLUMN id TYPE bigint')
+ connection.execute('ALTER TABLE notes DROP COLUMN IF EXISTS id_convert_to_bigint')
+ end
+
+ after do
+ connection.execute('ALTER TABLE notes DROP COLUMN IF EXISTS id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ notes_table.reset_column_information
+
+ expect(notes_table.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
+ expect(notes_table.columns.find { |c| c.name == 'id_convert_to_bigint' }).to be_nil
+ }
+
+ migration.after -> {
+ notes_table.reset_column_information
+
+ expect(notes_table.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
+ expect(notes_table.columns.find { |c| c.name == 'id_convert_to_bigint' }).to be_nil
+ }
+ end
+ end
+ end
+ end
+
+ describe '#up' do
+ let!(:notes_table) { table(:notes) }
+
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to(
+ receive(:com_or_dev_or_test_but_not_jh?).and_return(com_or_dev_or_test_but_not_jh?)
+ )
+ # rubocop:enable RSpec/AnyInstanceOf
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ let(:com_or_dev_or_test_but_not_jh?) { true }
+
+ it_behaves_like 'column `id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance with the `id_convert_to_bigint` column already dropped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ it_behaves_like 'column `id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance columns already swapped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE notes ALTER COLUMN id TYPE bigint')
+ connection.execute('ALTER TABLE notes ADD COLUMN IF NOT EXISTS id_convert_to_bigint integer')
+
+ disable_migrations_output { migrate! }
+ end
+
+ after do
+ connection.execute('ALTER TABLE notes DROP COLUMN IF EXISTS id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ expect(notes_table.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
+ expect(notes_table.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('integer')
+ end
+ end
+
+ context 'when self-managed instance' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE notes ALTER COLUMN id TYPE integer')
+ connection.execute('ALTER TABLE notes ADD COLUMN IF NOT EXISTS id_convert_to_bigint bigint')
+ connection.execute('ALTER TABLE notes ALTER COLUMN id_convert_to_bigint TYPE bigint')
+ connection.execute('DROP INDEX IF EXISTS index_notes_on_id_convert_to_bigint CASCADE')
+ connection.execute('CREATE OR REPLACE FUNCTION trigger_080e73845bfd() RETURNS trigger LANGUAGE plpgsql AS $$
+ BEGIN NEW."id_convert_to_bigint" := NEW."id"; RETURN NEW; END; $$;')
+ end
+
+ after do
+ connection.execute('ALTER TABLE notes DROP COLUMN IF EXISTS id_convert_to_bigint')
+ end
+
+ it 'swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ notes_table.reset_column_information
+
+ expect(notes_table.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer')
+ expect(notes_table.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ notes_table.reset_column_information
+
+ expect(notes_table.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
+ expect(notes_table.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('integer')
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230802212443_add_current_user_todos_widget_to_epic_work_item_type_spec.rb b/spec/migrations/20230802212443_add_current_user_todos_widget_to_epic_work_item_type_spec.rb
new file mode 100644
index 00000000000..22a8f93b524
--- /dev/null
+++ b/spec/migrations/20230802212443_add_current_user_todos_widget_to_epic_work_item_type_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddCurrentUserTodosWidgetToEpicWorkItemType, :migration, feature_category: :team_planning do
+ it_behaves_like 'migration that adds a widget to a work item type' do
+ let(:target_type_enum_value) { described_class::EPIC_ENUM_VALUE }
+ let(:target_type) { :epic }
+ let(:widgets_for_type) do
+ {
+ 'Assignees' => 0,
+ 'Description' => 1,
+ 'Hierarchy' => 2,
+ 'Labels' => 3,
+ 'Notes' => 5,
+ 'Start and due date' => 6,
+ 'Health status' => 7,
+ 'Status' => 11,
+ 'Notifications' => 14,
+ 'Award emoji' => 16
+ }.freeze
+ end
+ end
+end
diff --git a/spec/migrations/20230809170822_ensure_system_note_metadata_bigint_backfill_is_finished_for_self_managed_spec.rb b/spec/migrations/20230809170822_ensure_system_note_metadata_bigint_backfill_is_finished_for_self_managed_spec.rb
new file mode 100644
index 00000000000..1c33872142d
--- /dev/null
+++ b/spec/migrations/20230809170822_ensure_system_note_metadata_bigint_backfill_is_finished_for_self_managed_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe EnsureSystemNoteMetadataBigintBackfillIsFinishedForSelfManaged, feature_category: :database do
+ describe '#up' do
+ let(:migration_arguments) do
+ {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'system_note_metadata',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ }
+ end
+
+ it 'ensures the migration is completed for self-managed instances' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+
+ migrate!
+ end
+
+ it 'skips the check for GitLab.com, dev, or test' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+ expect(instance).not_to receive(:ensure_batched_background_migration_is_finished)
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/20230809174702_swap_system_note_metadata_note_id_to_bigint_for_self_managed_spec.rb b/spec/migrations/20230809174702_swap_system_note_metadata_note_id_to_bigint_for_self_managed_spec.rb
new file mode 100644
index 00000000000..e8413b24ae9
--- /dev/null
+++ b/spec/migrations/20230809174702_swap_system_note_metadata_note_id_to_bigint_for_self_managed_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapSystemNoteMetadataNoteIdToBigintForSelfManaged, feature_category: :database do
+ let(:connection) { described_class.new.connection }
+ let(:system_note_metadata) { table(:system_note_metadata) }
+
+ shared_examples 'column `note_id_convert_to_bigint` is already dropped' do
+ before do
+ connection.execute('ALTER TABLE system_note_metadata ALTER COLUMN note_id TYPE bigint')
+ connection.execute('ALTER TABLE system_note_metadata DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'does not swap the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ system_note_metadata.reset_column_information
+
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }).to be_nil
+ }
+
+ migration.after -> {
+ system_note_metadata.reset_column_information
+
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }).to be_nil
+ }
+ end
+ end
+ end
+ end
+
+ describe '#up' do
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to(
+ receive(:com_or_dev_or_test_but_not_jh?).and_return(com_or_dev_or_test_but_not_jh?)
+ )
+ # rubocop:enable RSpec/AnyInstanceOf
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ let(:com_or_dev_or_test_but_not_jh?) { true }
+
+ it_behaves_like 'column `note_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance with the `note_id_convert_to_bigint` column already dropped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ it_behaves_like 'column `note_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance columns already swapped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE system_note_metadata ALTER COLUMN note_id TYPE bigint')
+ connection.execute(
+ 'ALTER TABLE system_note_metadata ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint integer'
+ )
+
+ disable_migrations_output { migrate! }
+ end
+
+ after do
+ connection.execute('ALTER TABLE system_note_metadata DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ end
+ end
+
+ context 'when self-managed instance' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE system_note_metadata ALTER COLUMN note_id TYPE integer')
+ connection.execute('ALTER TABLE system_note_metadata ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint bigint')
+ connection.execute('CREATE OR REPLACE FUNCTION trigger_482bac5ec48a() RETURNS trigger LANGUAGE plpgsql AS $$
+ BEGIN NEW."note_id_convert_to_bigint" := NEW."note_id"; RETURN NEW; END; $$;')
+ end
+
+ after do
+ connection.execute('ALTER TABLE system_note_metadata DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ system_note_metadata.reset_column_information
+
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('bigint')
+ )
+ }
+
+ migration.after -> {
+ system_note_metadata.reset_column_information
+
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(system_note_metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230809203254_ensure_issue_user_mentions_bigint_backfill_is_finished_for_self_managed_spec.rb b/spec/migrations/20230809203254_ensure_issue_user_mentions_bigint_backfill_is_finished_for_self_managed_spec.rb
new file mode 100644
index 00000000000..09694a2ee8d
--- /dev/null
+++ b/spec/migrations/20230809203254_ensure_issue_user_mentions_bigint_backfill_is_finished_for_self_managed_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe EnsureIssueUserMentionsBigintBackfillIsFinishedForSelfManaged, feature_category: :database do
+ describe '#up' do
+ let(:migration_arguments) do
+ {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'issue_user_mentions',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ }
+ end
+
+ it 'ensures the migration is completed for self-managed instances' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+
+ migrate!
+ end
+
+ it 'skips the check for GitLab.com, dev, or test' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+ expect(instance).not_to receive(:ensure_batched_background_migration_is_finished)
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/20230809210550_swap_issue_user_mentions_note_id_to_bigint_for_self_managed_spec.rb b/spec/migrations/20230809210550_swap_issue_user_mentions_note_id_to_bigint_for_self_managed_spec.rb
new file mode 100644
index 00000000000..a311f876890
--- /dev/null
+++ b/spec/migrations/20230809210550_swap_issue_user_mentions_note_id_to_bigint_for_self_managed_spec.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapIssueUserMentionsNoteIdToBigintForSelfManaged, feature_category: :database do
+ let(:connection) { described_class.new.connection }
+ let(:issue_user_mentions) { table(:issue_user_mentions) }
+
+ shared_examples 'column `note_id_convert_to_bigint` is already dropped' do
+ before do
+ connection.execute('ALTER TABLE issue_user_mentions ALTER COLUMN note_id TYPE bigint')
+ connection.execute('ALTER TABLE issue_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ after do
+ connection.execute('ALTER TABLE issue_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ issue_user_mentions.reset_column_information
+
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }).to be_nil
+ }
+
+ migration.after -> {
+ issue_user_mentions.reset_column_information
+
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }).to be_nil
+ }
+ end
+ end
+ end
+ end
+
+ describe '#up' do
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to(
+ receive(:com_or_dev_or_test_but_not_jh?).and_return(com_or_dev_or_test_but_not_jh?)
+ )
+ # rubocop:enable RSpec/AnyInstanceOf
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ let(:com_or_dev_or_test_but_not_jh?) { true }
+
+ it_behaves_like 'column `note_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance with the `note_id_convert_to_bigint` column already dropped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ it_behaves_like 'column `note_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance columns already swapped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE issue_user_mentions ALTER COLUMN note_id TYPE bigint')
+ connection.execute(
+ 'ALTER TABLE issue_user_mentions ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint integer'
+ )
+
+ disable_migrations_output { migrate! }
+ end
+
+ after do
+ connection.execute('ALTER TABLE issue_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ end
+ end
+
+ context 'when self-managed instance' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE issue_user_mentions ALTER COLUMN note_id TYPE integer')
+ connection.execute('ALTER TABLE issue_user_mentions ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint bigint')
+ connection.execute('ALTER TABLE issue_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint')
+ connection.execute('DROP INDEX IF EXISTS index_issue_user_mentions_on_note_id_convert_to_bigint CASCADE')
+ connection.execute('CREATE OR REPLACE FUNCTION trigger_c2051020aa8b() RETURNS trigger LANGUAGE plpgsql AS $$
+ BEGIN NEW."note_id_convert_to_bigint" := NEW."note_id"; RETURN NEW; END; $$;')
+ end
+
+ after do
+ connection.execute('ALTER TABLE issue_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ issue_user_mentions.reset_column_information
+
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('bigint')
+ )
+ }
+
+ migration.after -> {
+ issue_user_mentions.reset_column_information
+
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(issue_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230810113227_swap_note_diff_files_note_id_to_bigint_for_self_hosts_spec.rb b/spec/migrations/20230810113227_swap_note_diff_files_note_id_to_bigint_for_self_hosts_spec.rb
new file mode 100644
index 00000000000..de169d9d21b
--- /dev/null
+++ b/spec/migrations/20230810113227_swap_note_diff_files_note_id_to_bigint_for_self_hosts_spec.rb
@@ -0,0 +1,156 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapNoteDiffFilesNoteIdToBigintForSelfHosts, feature_category: :database do
+ describe '#up' do
+ after(:all) do
+ connection = described_class.new.connection
+ connection.execute('ALTER TABLE note_diff_files DROP COLUMN IF EXISTS diff_note_id_convert_to_bigint')
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ before do
+ # As we call `schema_migrate_down!` before each example, and for this migration
+ # `#down` is same as `#up`, we need to ensure we start from the expected state.
+ connection = described_class.new.connection
+ connection.execute('ALTER TABLE note_diff_files ALTER COLUMN diff_note_id TYPE bigint')
+ connection.execute('ALTER TABLE note_diff_files DROP COLUMN IF EXISTS diff_note_id_convert_to_bigint')
+ end
+
+ it 'does not swap the columns' do
+ # rubocop: disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+ # rubocop: enable RSpec/AnyInstanceOf
+
+ note_diff_files = table(:note_diff_files)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ note_diff_files.reset_column_information
+
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('bigint')
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id_convert_to_bigint' }).to be nil
+ }
+
+ migration.after -> {
+ note_diff_files.reset_column_information
+
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('bigint')
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id_convert_to_bigint' }).to be nil
+ }
+ end
+ end
+ end
+ end
+
+ context 'when self-managed instance with the columns already swapped' do
+ before do
+ # As we call `schema_migrate_down!` before each example, and for this migration
+ # `#down` is same as `#up`, we need to ensure we start from the expected state.
+ connection = described_class.new.connection
+ connection.execute('ALTER TABLE note_diff_files ALTER COLUMN diff_note_id TYPE bigint')
+ connection.execute(
+ 'ALTER TABLE note_diff_files ADD COLUMN IF NOT EXISTS diff_note_id_convert_to_bigint integer'
+ )
+ end
+
+ it 'does not swap the columns' do
+ # rubocop: disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ # rubocop: enable RSpec/AnyInstanceOf
+
+ note_diff_files = table(:note_diff_files)
+
+ migrate!
+
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('bigint')
+ expect(note_diff_files.columns.find do |c|
+ c.name == 'diff_note_id_convert_to_bigint'
+ end.sql_type).to eq('integer')
+ end
+ end
+
+ context 'when self-managed instance with the `diff_note_id_convert_to_bigint` column already dropped ' do
+ before do
+ # As we call `schema_migrate_down!` before each example, and for this migration
+ # `#down` is same as `#up`, we need to ensure we start from the expected state.
+ connection = described_class.new.connection
+ connection.execute('ALTER TABLE note_diff_files ALTER COLUMN diff_note_id TYPE bigint')
+ connection.execute('ALTER TABLE note_diff_files DROP COLUMN IF EXISTS diff_note_id_convert_to_bigint')
+ end
+
+ it 'does not swap the columns' do
+ # rubocop: disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ # rubocop: enable RSpec/AnyInstanceOf
+
+ note_diff_files = table(:note_diff_files)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ note_diff_files.reset_column_information
+
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('bigint')
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id_convert_to_bigint' }).to be nil
+ }
+
+ migration.after -> {
+ note_diff_files.reset_column_information
+
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('bigint')
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id_convert_to_bigint' }).to be nil
+ }
+ end
+ end
+ end
+ end
+
+ context 'when self-managed instance' do
+ before do
+ # As we call `schema_migrate_down!` before each example, and for this migration
+ # `#down` is same as `#up`, we need to ensure we start from the expected state.
+ connection = described_class.new.connection
+ connection.execute('ALTER TABLE note_diff_files ALTER COLUMN diff_note_id TYPE integer')
+ connection.execute('ALTER TABLE note_diff_files ADD COLUMN IF NOT EXISTS diff_note_id_convert_to_bigint bigint')
+ connection.execute('ALTER TABLE note_diff_files ALTER COLUMN diff_note_id_convert_to_bigint TYPE bigint')
+ connection.execute('DROP INDEX IF EXISTS index_note_diff_files_on_note_id_convert_to_bigint')
+ connection.execute('CREATE OR REPLACE FUNCTION trigger_775287b6d67a() RETURNS trigger LANGUAGE plpgsql AS $$
+ BEGIN NEW."diff_note_id_convert_to_bigint" := NEW."diff_note_id"; RETURN NEW; END; $$;')
+ end
+
+ it 'swaps the columns' do
+ # rubocop: disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ # rubocop: enable RSpec/AnyInstanceOf
+
+ note_diff_files = table(:note_diff_files)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ note_diff_files.reset_column_information
+
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('integer')
+ expect(note_diff_files.columns.find do |c|
+ c.name == 'diff_note_id_convert_to_bigint'
+ end.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ note_diff_files.reset_column_information
+
+ expect(note_diff_files.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('bigint')
+ expect(note_diff_files.columns.find do |c|
+ c.name == 'diff_note_id_convert_to_bigint'
+ end.sql_type).to eq('integer')
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230810124545_schedule_fixing_namespace_ids_of_vulnerability_reads_spec.rb b/spec/migrations/20230810124545_schedule_fixing_namespace_ids_of_vulnerability_reads_spec.rb
new file mode 100644
index 00000000000..294545bed2b
--- /dev/null
+++ b/spec/migrations/20230810124545_schedule_fixing_namespace_ids_of_vulnerability_reads_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe ScheduleFixingNamespaceIdsOfVulnerabilityReads, feature_category: :vulnerability_management do
+ let(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :vulnerability_reads,
+ column_name: :vulnerability_id,
+ interval: 2.minutes,
+ batch_size: 10_000,
+ sub_batch_size: 100
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230811103457_queue_backfill_nuget_normalized_version_spec.rb b/spec/migrations/20230811103457_queue_backfill_nuget_normalized_version_spec.rb
new file mode 100644
index 00000000000..6eb7ba0e2cd
--- /dev/null
+++ b/spec/migrations/20230811103457_queue_backfill_nuget_normalized_version_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillNugetNormalizedVersion, feature_category: :package_registry do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :packages_nuget_metadata,
+ column_name: :package_id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230815140656_queue_populate_denormalized_columns_for_sbom_occurrences_spec.rb b/spec/migrations/20230815140656_queue_populate_denormalized_columns_for_sbom_occurrences_spec.rb
new file mode 100644
index 00000000000..3976e398607
--- /dev/null
+++ b/spec/migrations/20230815140656_queue_populate_denormalized_columns_for_sbom_occurrences_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueuePopulateDenormalizedColumnsForSbomOccurrences, feature_category: :dependency_management do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :sbom_occurrences,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230815160428_rename_plans_titles_with_legacy_plan_names_spec.rb b/spec/migrations/20230815160428_rename_plans_titles_with_legacy_plan_names_spec.rb
new file mode 100644
index 00000000000..21c17a60e90
--- /dev/null
+++ b/spec/migrations/20230815160428_rename_plans_titles_with_legacy_plan_names_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe RenamePlansTitlesWithLegacyPlanNames, feature_category: :subscription_management do
+ let(:plans) { table(:plans) }
+
+ let!(:premium_plan) { plans.create!(name: 'premium', title: 'Premium (Formerly Silver)') }
+ let!(:ultimate_plan) { plans.create!(name: 'ultimate', title: 'Ultimate (Formerly Gold)') }
+
+ describe '#up' do
+ it 'updates the plan titles' do
+ expect(premium_plan.title).to eq('Premium (Formerly Silver)')
+ expect(ultimate_plan.title).to eq('Ultimate (Formerly Gold)')
+
+ migrate!
+
+ expect(premium_plan.reload.title).to eq('Premium')
+ expect(ultimate_plan.reload.title).to eq('Ultimate')
+ end
+ end
+end
diff --git a/spec/migrations/20230816152540_ensure_dum_note_id_bigint_backfill_is_finished_for_self_managed_spec.rb b/spec/migrations/20230816152540_ensure_dum_note_id_bigint_backfill_is_finished_for_self_managed_spec.rb
new file mode 100644
index 00000000000..c8590250c62
--- /dev/null
+++ b/spec/migrations/20230816152540_ensure_dum_note_id_bigint_backfill_is_finished_for_self_managed_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe EnsureDumNoteIdBigintBackfillIsFinishedForSelfManaged, feature_category: :database do
+ describe '#up' do
+ let(:migration_arguments) do
+ {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'design_user_mentions',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ }
+ end
+
+ it 'ensures the migration is completed for self-managed instances' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+
+ migrate!
+ end
+
+ it 'skips the check for GitLab.com, dev, or test' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+ expect(instance).not_to receive(:ensure_batched_background_migration_is_finished)
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/20230816152639_swap_design_user_mentions_note_id_to_big_int_for_self_managed_spec.rb b/spec/migrations/20230816152639_swap_design_user_mentions_note_id_to_big_int_for_self_managed_spec.rb
new file mode 100644
index 00000000000..f6342fe6388
--- /dev/null
+++ b/spec/migrations/20230816152639_swap_design_user_mentions_note_id_to_big_int_for_self_managed_spec.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe SwapDesignUserMentionsNoteIdToBigIntForSelfManaged, feature_category: :database do
+ let(:connection) { described_class.new.connection }
+ let(:design_user_mentions) { table(:design_user_mentions) }
+
+ shared_examples 'column `note_id_convert_to_bigint` is already dropped' do
+ before do
+ connection.execute('ALTER TABLE design_user_mentions ALTER COLUMN note_id TYPE bigint')
+ connection.execute('ALTER TABLE design_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'does not swap the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ design_user_mentions.reset_column_information
+
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }).to be_nil
+ }
+
+ migration.after -> {
+ design_user_mentions.reset_column_information
+
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }).to be_nil
+ }
+ end
+ end
+ end
+ end
+
+ describe '#up' do
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to(
+ receive(:com_or_dev_or_test_but_not_jh?).and_return(com_or_dev_or_test_but_not_jh?)
+ )
+ # rubocop:enable RSpec/AnyInstanceOf
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ let(:com_or_dev_or_test_but_not_jh?) { true }
+
+ it_behaves_like 'column `note_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance with the `note_id_convert_to_bigint` column already dropped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ it_behaves_like 'column `note_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance columns already swapped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE design_user_mentions ALTER COLUMN note_id TYPE bigint')
+ connection.execute(
+ 'ALTER TABLE design_user_mentions ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint integer'
+ )
+
+ disable_migrations_output { migrate! }
+ end
+
+ after do
+ connection.execute('ALTER TABLE design_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ end
+ end
+
+ context 'when self-managed instance' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE design_user_mentions ALTER COLUMN note_id TYPE integer')
+ connection.execute('ALTER TABLE design_user_mentions ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint bigint')
+ connection.execute('CREATE OR REPLACE FUNCTION trigger_3dc62927cae8() RETURNS trigger LANGUAGE plpgsql AS $$
+ BEGIN NEW."note_id_convert_to_bigint" := NEW."note_id"; RETURN NEW; END; $$;')
+ end
+
+ after do
+ connection.execute('ALTER TABLE design_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ design_user_mentions.reset_column_information
+
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('bigint')
+ )
+ }
+
+ migration.after -> {
+ design_user_mentions.reset_column_information
+
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(design_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230817111938_swap_events_target_id_to_bigint_for_self_hosts_spec.rb b/spec/migrations/20230817111938_swap_events_target_id_to_bigint_for_self_hosts_spec.rb
new file mode 100644
index 00000000000..515d4f21fc6
--- /dev/null
+++ b/spec/migrations/20230817111938_swap_events_target_id_to_bigint_for_self_hosts_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapEventsTargetIdToBigintForSelfHosts, feature_category: :database do
+ let(:connection) { described_class.new.connection }
+ let(:events) { table(:events) }
+
+ shared_examples 'column `target_id_convert_to_bigint` is already dropped' do
+ before do
+ connection.execute('ALTER TABLE events ALTER COLUMN target_id TYPE bigint')
+ connection.execute('ALTER TABLE events DROP COLUMN IF EXISTS target_id_convert_to_bigint')
+ end
+
+ it 'does not swap the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ events.reset_column_information
+
+ expect(events.columns.find { |c| c.name == 'target_id' }.sql_type).to eq('bigint')
+ expect(events.columns.find { |c| c.name == 'target_id_convert_to_bigint' }).to be_nil
+ }
+
+ migration.after -> {
+ events.reset_column_information
+
+ expect(events.columns.find { |c| c.name == 'target_id' }.sql_type).to eq('bigint')
+ expect(events.columns.find { |c| c.name == 'target_id_convert_to_bigint' }).to be_nil
+ }
+ end
+ end
+ end
+ end
+
+ describe '#up' do
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to(
+ receive(:com_or_dev_or_test_but_not_jh?).and_return(com_or_dev_or_test_but_not_jh?)
+ )
+ # rubocop:enable RSpec/AnyInstanceOf
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ let(:com_or_dev_or_test_but_not_jh?) { true }
+
+ it_behaves_like 'column `target_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance with the `target_id_convert_to_bigint` column already dropped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ it_behaves_like 'column `target_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance columns already swapped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE events ALTER COLUMN target_id TYPE bigint')
+ connection.execute(
+ 'ALTER TABLE events ADD COLUMN IF NOT EXISTS target_id_convert_to_bigint integer'
+ )
+
+ disable_migrations_output { migrate! }
+ end
+
+ after do
+ connection.execute('ALTER TABLE events DROP COLUMN IF EXISTS target_id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ expect(events.columns.find { |c| c.name == 'target_id' }.sql_type).to eq('bigint')
+ expect(events.columns.find { |c| c.name == 'target_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ end
+ end
+
+ context 'when self-managed instance' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE events ALTER COLUMN target_id TYPE integer')
+ connection.execute('ALTER TABLE events ADD COLUMN IF NOT EXISTS target_id_convert_to_bigint bigint')
+ connection.execute('CREATE OR REPLACE FUNCTION trigger_cd1aeb22b34a() RETURNS trigger LANGUAGE plpgsql AS $$
+ BEGIN NEW."target_id_convert_to_bigint" := NEW."target_id"; RETURN NEW; END; $$;')
+ end
+
+ after do
+ connection.execute('ALTER TABLE events DROP COLUMN IF EXISTS target_id_convert_to_bigint')
+ end
+
+ it 'swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ events.reset_column_information
+
+ expect(events.columns.find { |c| c.name == 'target_id' }.sql_type).to eq('integer')
+ expect(events.columns.find { |c| c.name == 'target_id_convert_to_bigint' }.sql_type).to(
+ eq('bigint')
+ )
+ }
+
+ migration.after -> {
+ events.reset_column_information
+
+ expect(events.columns.find { |c| c.name == 'target_id' }.sql_type).to eq('bigint')
+ expect(events.columns.find { |c| c.name == 'target_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230817143637_swap_award_emoji_note_id_to_bigint_for_self_hosts_spec.rb b/spec/migrations/20230817143637_swap_award_emoji_note_id_to_bigint_for_self_hosts_spec.rb
new file mode 100644
index 00000000000..a9521a40d0d
--- /dev/null
+++ b/spec/migrations/20230817143637_swap_award_emoji_note_id_to_bigint_for_self_hosts_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapAwardEmojiNoteIdToBigintForSelfHosts, feature_category: :database do
+ let(:connection) { described_class.new.connection }
+ let(:award_emoji) { table(:award_emoji) }
+
+ shared_examples 'column `awardable_id_convert_to_bigint` is already dropped' do
+ before do
+ connection.execute('ALTER TABLE award_emoji ALTER COLUMN awardable_id TYPE bigint')
+ connection.execute('ALTER TABLE award_emoji DROP COLUMN IF EXISTS awardable_id_convert_to_bigint')
+ end
+
+ it 'does not swap the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ award_emoji.reset_column_information
+
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('bigint')
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }).to be_nil
+ }
+
+ migration.after -> {
+ award_emoji.reset_column_information
+
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('bigint')
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }).to be_nil
+ }
+ end
+ end
+ end
+ end
+
+ describe '#up' do
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to(
+ receive(:com_or_dev_or_test_but_not_jh?).and_return(com_or_dev_or_test_but_not_jh?)
+ )
+ # rubocop:enable RSpec/AnyInstanceOf
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ let(:com_or_dev_or_test_but_not_jh?) { true }
+
+ it_behaves_like 'column `awardable_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance with the `awardable_id_convert_to_bigint` column already dropped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ it_behaves_like 'column `awardable_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance columns already swapped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE award_emoji ALTER COLUMN awardable_id TYPE bigint')
+ connection.execute(
+ 'ALTER TABLE award_emoji ADD COLUMN IF NOT EXISTS awardable_id_convert_to_bigint integer'
+ )
+
+ disable_migrations_output { migrate! }
+ end
+
+ after do
+ connection.execute('ALTER TABLE award_emoji DROP COLUMN IF EXISTS awardable_id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('bigint')
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ end
+ end
+
+ context 'when self-managed instance' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE award_emoji ALTER COLUMN awardable_id TYPE integer')
+ connection.execute('ALTER TABLE award_emoji ADD COLUMN IF NOT EXISTS awardable_id_convert_to_bigint bigint')
+ connection.execute('CREATE OR REPLACE FUNCTION trigger_909cf0a06094() RETURNS trigger LANGUAGE plpgsql AS $$
+ BEGIN NEW."awardable_id_convert_to_bigint" := NEW."awardable_id"; RETURN NEW; END; $$;')
+ end
+
+ after do
+ connection.execute('ALTER TABLE award_emoji DROP COLUMN IF EXISTS awardable_id_convert_to_bigint')
+ end
+
+ it 'swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ award_emoji.reset_column_information
+
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('integer')
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }.sql_type).to(
+ eq('bigint')
+ )
+ }
+
+ migration.after -> {
+ award_emoji.reset_column_information
+
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('bigint')
+ expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230818083610_queue_backfill_users_with_defaults_spec.rb b/spec/migrations/20230818083610_queue_backfill_users_with_defaults_spec.rb
new file mode 100644
index 00000000000..4cd72b4fa7a
--- /dev/null
+++ b/spec/migrations/20230818083610_queue_backfill_users_with_defaults_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillUsersWithDefaults, feature_category: :user_profile do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :users,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE,
+ max_batch_size: described_class::MAX_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230818085219_queue_backfill_user_preferences_with_defaults_spec.rb b/spec/migrations/20230818085219_queue_backfill_user_preferences_with_defaults_spec.rb
new file mode 100644
index 00000000000..eff14be22f6
--- /dev/null
+++ b/spec/migrations/20230818085219_queue_backfill_user_preferences_with_defaults_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillUserPreferencesWithDefaults, feature_category: :user_profile do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :user_preferences,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE,
+ max_batch_size: described_class::MAX_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230818142801_queue_create_compliance_standards_adherence_spec.rb b/spec/migrations/20230818142801_queue_create_compliance_standards_adherence_spec.rb
new file mode 100644
index 00000000000..466d0bca997
--- /dev/null
+++ b/spec/migrations/20230818142801_queue_create_compliance_standards_adherence_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueCreateComplianceStandardsAdherence, feature_category: :compliance_management do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ context 'for EE' do
+ before do
+ allow(Gitlab).to receive(:ee?).and_return(true)
+ end
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :projects,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+ end
+
+ context 'for FOSS' do
+ before do
+ allow(Gitlab).to receive(:ee?).and_return(false)
+ end
+
+ it 'does not schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230821081603_queue_convert_credit_card_validation_data_to_hashes_spec.rb b/spec/migrations/20230821081603_queue_convert_credit_card_validation_data_to_hashes_spec.rb
new file mode 100644
index 00000000000..36ab25ffa3e
--- /dev/null
+++ b/spec/migrations/20230821081603_queue_convert_credit_card_validation_data_to_hashes_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueConvertCreditCardValidationDataToHashes, feature_category: :user_profile do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :user_credit_card_validations,
+ column_name: :user_id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230822104028_delete_project_callout_three_spec.rb b/spec/migrations/20230822104028_delete_project_callout_three_spec.rb
new file mode 100644
index 00000000000..127af643976
--- /dev/null
+++ b/spec/migrations/20230822104028_delete_project_callout_three_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe DeleteProjectCalloutThree, feature_category: :groups_and_projects do
+ let(:migration) { described_class.new }
+
+ let(:user) { table(:users).create!(name: 'test', email: 'test@example.com', projects_limit: 5) }
+ let(:namespace) { table(:namespaces).create!(name: 'name', path: 'path') }
+ let(:project) { table(:projects).create!(namespace_id: namespace.id, project_namespace_id: namespace.id) }
+ let(:project_callout) { table(:user_project_callouts) }
+
+ let!(:project_callouts_1) { project_callout.create!(project_id: project.id, user_id: user.id, feature_name: 1) }
+ let!(:project_callouts_3) { project_callout.create!(project_id: project.id, user_id: user.id, feature_name: 3) }
+
+ it 'deletes only feature name 3' do
+ expect { migrate! }.to change { project_callout.count }.from(2).to(1)
+ expect(project_callout.find_by_id(project_callouts_3.id)).to be_nil
+ end
+end
diff --git a/spec/migrations/20230822151454_remove_free_user_cap_email_workers_spec.rb b/spec/migrations/20230822151454_remove_free_user_cap_email_workers_spec.rb
new file mode 100644
index 00000000000..fd56c9a0988
--- /dev/null
+++ b/spec/migrations/20230822151454_remove_free_user_cap_email_workers_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe RemoveFreeUserCapEmailWorkers, :migration, feature_category: :onboarding do
+ describe '#up' do
+ it 'calls sidekiq_remove_jobs with correct argument' do
+ deprecated_job_classes = %w[
+ Namespaces::FreeUserCap::BackfillNotificationClearingJobsWorker
+ Namespaces::FreeUserCap::BackfillNotificationJobsWorker
+ Namespaces::FreeUserCap::NotificationClearingWorker
+ Namespaces::FreeUserCap::OverLimitNotificationWorker
+ ]
+
+ expect_next_instance_of(described_class) do |migration|
+ expect(migration).to receive(:sidekiq_remove_jobs)
+ .with({ job_klasses: deprecated_job_classes })
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/20230823090001_queue_backfill_project_statistics_storage_size_with_recent_size_spec.rb b/spec/migrations/20230823090001_queue_backfill_project_statistics_storage_size_with_recent_size_spec.rb
new file mode 100644
index 00000000000..07e15663d1d
--- /dev/null
+++ b/spec/migrations/20230823090001_queue_backfill_project_statistics_storage_size_with_recent_size_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillProjectStatisticsStorageSizeWithRecentSize, feature_category: :consumables_cost_management do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :project_statistics,
+ column_name: :project_id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230823140934_add_linked_items_widget_to_ticket_work_item_type_spec.rb b/spec/migrations/20230823140934_add_linked_items_widget_to_ticket_work_item_type_spec.rb
new file mode 100644
index 00000000000..6a83b4b1a7c
--- /dev/null
+++ b/spec/migrations/20230823140934_add_linked_items_widget_to_ticket_work_item_type_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddLinkedItemsWidgetToTicketWorkItemType, :migration, feature_category: :portfolio_management do
+ it_behaves_like 'migration that adds a widget to a work item type' do
+ let(:target_type_enum_value) { described_class::TICKET_ENUM_VALUE }
+ let(:target_type) { :ticket }
+ let(:additional_types) { { ticket: 8 } }
+ let(:widgets_for_type) do
+ {
+ 'Assignees' => 0,
+ 'Description' => 1,
+ 'Hierarchy' => 2,
+ 'Labels' => 3,
+ 'Notes' => 5,
+ 'Iteration' => 9,
+ 'Milestone' => 4,
+ 'Weight' => 8,
+ 'Current user todos' => 15,
+ 'Start and due date' => 6,
+ 'Health status' => 7,
+ 'Notifications' => 14,
+ 'Award emoji' => 16
+ }.freeze
+ end
+ end
+end
diff --git a/spec/migrations/20230830121830_queue_update_users_set_external_if_service_account_spec.rb b/spec/migrations/20230830121830_queue_update_users_set_external_if_service_account_spec.rb
new file mode 100644
index 00000000000..12839e0852b
--- /dev/null
+++ b/spec/migrations/20230830121830_queue_update_users_set_external_if_service_account_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueUpdateUsersSetExternalIfServiceAccount, feature_category: :system_access do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :users,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL.to_i,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230831084632_queue_sync_scan_result_policies_spec.rb b/spec/migrations/20230831084632_queue_sync_scan_result_policies_spec.rb
new file mode 100644
index 00000000000..3c4a7382e02
--- /dev/null
+++ b/spec/migrations/20230831084632_queue_sync_scan_result_policies_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueSyncScanResultPolicies, feature_category: :security_policy_management do
+ let!(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :security_orchestration_policy_configurations,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/20230906204934_restart_self_hosted_sent_notifications_bigint_conversion_spec.rb b/spec/migrations/20230906204934_restart_self_hosted_sent_notifications_bigint_conversion_spec.rb
new file mode 100644
index 00000000000..01dbb5d1ef8
--- /dev/null
+++ b/spec/migrations/20230906204934_restart_self_hosted_sent_notifications_bigint_conversion_spec.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+def column_type_from_table(table, column)
+ table.columns.find { |c| c.name == column }.sql_type
+end
+
+RSpec.describe RestartSelfHostedSentNotificationsBigintConversion, feature_category: :database do
+ let(:sent_notifications) { table(:sent_notifications) }
+
+ before do
+ # rubocop: disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(!self_hosted)
+ # rubocop: enable RSpec/AnyInstanceOf
+ end
+
+ context 'when is self-hosted' do
+ let(:self_hosted) { true }
+
+ describe '#up' do
+ context 'when id is already a bigint' do
+ it 'does nothing' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ sent_notifications.reset_column_information
+ expect(column_type_from_table(sent_notifications, 'id')).to eq('bigint')
+ }
+ migration.after -> {
+ sent_notifications.reset_column_information
+ expect(column_type_from_table(sent_notifications, 'id')).to eq('bigint')
+ }
+ end
+ end
+ end
+ end
+
+ context 'when id is an integer and id_convert_to_bigint exists' do
+ before do
+ conn = described_class.new.connection
+ conn.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE integer')
+ conn.execute('ALTER TABLE sent_notifications ADD COLUMN id_convert_to_bigint BIGINT')
+ sent_notifications.reset_column_information
+ end
+
+ after do
+ conn = described_class.new.connection
+ conn.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE bigint')
+ conn.execute('ALTER TABLE sent_notifications DROP COLUMN id_convert_to_bigint')
+ sent_notifications.reset_column_information
+ end
+
+ it 'does nothing' do
+ disable_migrations_output do
+ expect(column_type_from_table(sent_notifications, 'id')).to eq('integer')
+ expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }).not_to be_nil
+ migrate!
+ expect(column_type_from_table(sent_notifications, 'id')).to eq('integer')
+ expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }).not_to be_nil
+ end
+ end
+ end
+
+ context 'when id is an integer and id_convert_to_bigint does not exist' do
+ before do
+ conn = described_class.new.connection
+ conn.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE integer')
+ conn.execute('ALTER TABLE sent_notifications DROP COLUMN IF EXISTS id_convert_to_bigint')
+ sent_notifications.reset_column_information
+ end
+
+ after do
+ conn = described_class.new.connection
+ conn.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE bigint')
+ conn.execute('ALTER TABLE sent_notifications DROP COLUMN IF EXISTS id_convert_to_bigint')
+ sent_notifications.reset_column_information
+ end
+
+ it 'creates id_convert_to_bigint' do
+ disable_migrations_output do
+ expect(column_type_from_table(sent_notifications, 'id')).to eq('integer')
+ expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }).to be_nil
+ migrate!
+ sent_notifications.reset_column_information
+ expect(column_type_from_table(sent_notifications, 'id')).to eq('integer')
+ expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }).not_to be_nil
+ end
+ end
+ end
+ end
+
+ describe '#down' do
+ context 'when id is an integer and id_convert_to_bigint exists' do
+ before do
+ conn = described_class.new.connection
+ conn.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE integer')
+ conn.execute('ALTER TABLE sent_notifications ADD COLUMN id_convert_to_bigint BIGINT')
+ sent_notifications.reset_column_information
+ end
+
+ after do
+ conn = described_class.new.connection
+ conn.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE bigint')
+ conn.execute('ALTER TABLE sent_notifications DROP COLUMN IF EXISTS id_convert_to_bigint')
+ sent_notifications.reset_column_information
+ end
+
+ it 'drops id_convert_to_bigint' do
+ disable_migrations_output do
+ migrate!
+ schema_migrate_down!
+ end
+ expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }).to be_nil
+ end
+ end
+ end
+ end
+
+ context 'when is not self-hosted' do
+ let(:self_hosted) { false }
+
+ describe '#up' do
+ it 'is a bigint and result in no change' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ sent_notifications.reset_column_information
+ expect(sent_notifications.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
+ }
+ migration.after -> {
+ sent_notifications.reset_column_information
+ expect(sent_notifications.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint')
+ }
+ end
+ end
+ end
+ end
+
+ # Do not need to describe #down since it's a no-op and we did reversible test above
+ end
+end
diff --git a/spec/migrations/20230906204935_restart_self_hosted_sent_notifications_backfill_spec.rb b/spec/migrations/20230906204935_restart_self_hosted_sent_notifications_backfill_spec.rb
new file mode 100644
index 00000000000..f2c9ce3d005
--- /dev/null
+++ b/spec/migrations/20230906204935_restart_self_hosted_sent_notifications_backfill_spec.rb
@@ -0,0 +1,162 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+def column_type_from_table(table, column)
+ table.columns.find { |c| c.name == column }.sql_type
+end
+
+def sent_notifications_backfills(connection)
+ res = connection.execute <<~SQL
+ SELECT * FROM batched_background_migrations WHERE table_name = 'sent_notifications'
+ SQL
+
+ res.ntuples
+end
+
+def create_previous_backfill(connection)
+ connection.execute <<~SQL
+ INSERT INTO batched_background_migrations
+ (min_value, max_value, batch_size, sub_batch_size, interval, "status",#{' '}
+ job_class_name, batch_class_name,
+ table_name, column_name, job_arguments,
+ gitlab_schema, created_at, updated_at)
+ VALUES
+ (1, 3, 20000, 1000, 120, 3,
+ 'CopyColumnUsingBackgroundMigrationJob', 'PrimaryKeyBatchingStrategy',
+ 'sent_notifications', 'id', '[["id"], ["id_convert_to_bigint"]]',
+ 'gitlab_main', NOW(), NOW())
+ SQL
+end
+
+RSpec.describe RestartSelfHostedSentNotificationsBackfill, feature_category: :database do
+ let(:sent_notifications) { table(:sent_notifications) }
+
+ before do
+ # rubocop: disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(!self_hosted)
+ # rubocop: enable RSpec/AnyInstanceOf
+ end
+
+ describe '#up' do
+ context 'when is self-hosted' do
+ let(:self_hosted) { true }
+
+ context 'when id is integer' do
+ before do
+ described_class.new.connection.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE integer')
+ described_class.new.connection.execute(
+ 'ALTER TABLE sent_notifications ADD COLUMN IF NOT EXISTS id_convert_to_bigint BIGINT'
+ )
+ sent_notifications.reset_column_information
+ end
+
+ after do
+ described_class.new.connection.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE bigint')
+ described_class.new.connection.execute(
+ 'ALTER TABLE sent_notifications DROP COLUMN IF EXISTS id_convert_to_bigint'
+ )
+ sent_notifications.reset_column_information
+ end
+
+ context 'when a backfill has never been done' do
+ let(:id_convert_to_bigint_sample) { 0 }
+
+ before do
+ described_class.new.connection.execute <<~SQL
+ INSERT INTO
+ sent_notifications
+ (id_convert_to_bigint, reply_key)
+ VALUES (#{id_convert_to_bigint_sample}, 4)
+ SQL
+ end
+
+ after do
+ described_class.new.connection.execute <<~SQL
+ DELETE FROM sent_notifications
+ SQL
+ end
+
+ context 'when there is a record of an incomplete backfill' do
+ before do
+ create_previous_backfill(described_class.new.connection)
+ end
+
+ after do
+ described_class.new.connection.execute <<~SQL
+ DELETE FROM batched_background_migrations
+ SQL
+ end
+
+ it 'calls delete_batched_background_migration and does not raise an error' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:delete_batched_background_migration)
+ end
+ disable_migrations_output do
+ expect { migrate! }.not_to raise_error
+ end
+ expect(sent_notifications_backfills(described_class.new.connection)).to eq 1
+ end
+ end
+
+ context 'when there is no previous record of a backfill' do
+ it 'begins a backfill' do
+ disable_migrations_output do
+ migrate!
+ end
+ expect(sent_notifications_backfills(described_class.new.connection)).to eq 1
+ end
+ end
+ end
+
+ context 'when a backfill has previously been done' do
+ let(:id_convert_to_bigint_sample) { 4 }
+
+ before do
+ described_class.new.connection.execute <<~SQL
+ INSERT INTO
+ sent_notifications
+ (id_convert_to_bigint, reply_key)
+ VALUES (#{id_convert_to_bigint_sample}, 4)
+ SQL
+ end
+
+ after do
+ described_class.new.connection.execute <<~SQL
+ DELETE FROM sent_notifications
+ SQL
+ end
+
+ it 'does not start a backfill' do
+ disable_migrations_output do
+ migrate!
+ end
+ expect(sent_notifications_backfills(described_class.new.connection)).to eq 0
+ end
+ end
+ end
+
+ context 'when id is a bigint' do
+ it 'does not start a backfill' do
+ disable_migrations_output do
+ migrate!
+ end
+ expect(sent_notifications_backfills(described_class.new.connection)).to eq 0
+ end
+ end
+ end
+
+ context 'when is not self-hosted' do
+ let(:self_hosted) { false }
+
+ it 'does not start a backfill' do
+ disable_migrations_output do
+ migrate!
+ end
+ expect(sent_notifications_backfills(described_class.new.connection)).to eq 0
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20230907155247_queue_backfill_has_merge_request_of_vulnerability_reads_spec.rb b/spec/migrations/20230907155247_queue_backfill_has_merge_request_of_vulnerability_reads_spec.rb
new file mode 100644
index 00000000000..7214e0114d4
--- /dev/null
+++ b/spec/migrations/20230907155247_queue_backfill_has_merge_request_of_vulnerability_reads_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillHasMergeRequestOfVulnerabilityReads, feature_category: :database do
+ let!(:batched_migration) { described_class::MIGRATION_NAME }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :vulnerability_reads,
+ column_name: :vulnerability_id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/backfill_alert_management_prometheus_integrations_spec.rb b/spec/migrations/backfill_alert_management_prometheus_integrations_spec.rb
new file mode 100644
index 00000000000..dcc364aa44a
--- /dev/null
+++ b/spec/migrations/backfill_alert_management_prometheus_integrations_spec.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe BackfillAlertManagementPrometheusIntegrations, feature_category: :incident_management do
+ let(:namespace_class) { table(:namespaces) }
+ let(:project_class) { table(:projects) }
+ let(:settings_class) { table(:project_alerting_settings) }
+ let(:http_integrations_class) { table(:alert_management_http_integrations) }
+ let(:integration_class) { table(:integrations) }
+
+ let!(:namespace_1) { namespace_class.create!(name: "namespace_1", path: "namespace_1") }
+ let!(:namespace_2) { namespace_class.create!(name: "namespace_2", path: "namespace_2") }
+ let!(:namespace_3) { namespace_class.create!(name: "namespace_3", path: "namespace_3") }
+ let!(:project_1) { project_class.create!(project_namespace_id: namespace_1.id, namespace_id: namespace_1.id) }
+ let!(:project_2) { project_class.create!(project_namespace_id: namespace_2.id, namespace_id: namespace_1.id) }
+ let!(:project_3) { project_class.create!(project_namespace_id: namespace_3.id, namespace_id: namespace_1.id) }
+
+ let!(:http_integrations) do
+ [
+ create_http_integration(project_2, 'legacy', name: 'Legacy HTTP'),
+ create_http_integration(project_2, 'other', name: 'Other Prometheus', type: 1)
+ ]
+ end
+
+ before do
+ stub_const("#{described_class.name}::BATCH_SIZE", 1)
+
+ # disabled integration
+ create_prometheus_integration(project_1, active: false)
+ create_alerting_settings(project_1, token: :a)
+
+ # enabled integration
+ create_prometheus_integration(project_2, active: true)
+ create_alerting_settings(project_2, token: :b)
+
+ # settings without integration
+ create_alerting_settings(project_3, token: :c)
+
+ # Should ignore: another type of integration in the same project
+ integration_class.create!(
+ project_id: project_3.id,
+ type_new: 'Integrations::Bamboo',
+ active: true
+ )
+ end
+
+ it 'correctly migrates up and down' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(http_integrations_class.all).to match_array(http_integrations)
+ }
+
+ migration.after -> {
+ expect(http_integrations_class.all).to contain_exactly(
+ *http_integrations,
+ expected_http_integration(project_1, token: :a, active: false),
+ expected_http_integration(project_2, token: :b, active: true),
+ expected_http_integration(project_3, token: :c, active: false)
+ )
+ }
+ end
+ end
+
+ context 'with existing synced http integrations' do
+ let(:synced_integration) do
+ create_http_integration(project_2, 'legacy-prometheus', name: 'Prometheus', active: false)
+ end
+
+ let!(:http_integrations) { [synced_integration] }
+
+ it 'does not overwrite synced attributes' do
+ expect { migrate! }.to not_change { synced_integration.attributes }
+
+ expect(http_integrations_class.all).to contain_exactly(
+ expected_http_integration(project_1, token: :a, active: false),
+ synced_integration,
+ expected_http_integration(project_3, token: :c, active: false)
+ )
+ end
+ end
+
+ private
+
+ def create_prometheus_integration(project, active: true, **args)
+ integration_class.create!(
+ project_id: project.id,
+ type_new: 'Integrations::Prometheus',
+ active: active,
+ **args
+ )
+ end
+
+ def create_alerting_settings(project, token:)
+ settings_class.create!(
+ project_id: project.id,
+ encrypted_token: "token_#{token}",
+ encrypted_token_iv: "iv_#{token}"
+ )
+ end
+
+ def create_http_integration(project, endpoint_id, type: 0, **args)
+ http_integrations_class.create!(
+ project_id: project.id,
+ active: true,
+ encrypted_token_iv: 'iv',
+ encrypted_token: 'token',
+ endpoint_identifier: endpoint_id,
+ type_identifier: type,
+ **args
+ )
+ end
+
+ def expected_http_integration(project, token:, active:)
+ having_attributes(
+ project_id: project.id,
+ active: active,
+ encrypted_token: "token_#{token}",
+ encrypted_token_iv: "iv_#{token}",
+ name: 'Prometheus',
+ endpoint_identifier: 'legacy-prometheus',
+ type_identifier: 1
+ )
+ end
+end
diff --git a/spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_self_managed_spec.rb b/spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_self_managed_spec.rb
new file mode 100644
index 00000000000..482cca67e46
--- /dev/null
+++ b/spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_self_managed_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe EnsureMrUserMentionsNoteIdBigintBackfillIsFinishedForSelfManaged, feature_category: :database do
+ describe '#up' do
+ let(:migration_arguments) do
+ {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'merge_request_user_mentions',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ }
+ end
+
+ it 'ensures the migration is completed for self-managed instances' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+
+ migrate!
+ end
+
+ it 'skips the check for GitLab.com, dev, or test' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+ expect(instance).not_to receive(:ensure_batched_background_migration_is_finished)
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_for_self_managed_spec.rb b/spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_for_self_managed_spec.rb
new file mode 100644
index 00000000000..5cba691e20e
--- /dev/null
+++ b/spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_for_self_managed_spec.rb
@@ -0,0 +1,135 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapMergeRequestUserMentionsNoteIdToBigintForSelfManaged, feature_category: :database do
+ let(:connection) { described_class.new.connection }
+ let(:merge_request_user_mentions) { table(:merge_request_user_mentions) }
+
+ shared_examples 'column `note_id_convert_to_bigint` is already dropped' do
+ before do
+ connection.execute('ALTER TABLE merge_request_user_mentions ALTER COLUMN note_id TYPE bigint')
+ connection.execute('ALTER TABLE merge_request_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ after do
+ connection.execute('ALTER TABLE merge_request_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ merge_request_user_mentions.reset_column_information
+
+ expect(merge_request_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(merge_request_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }).to be_nil
+ }
+
+ migration.after -> {
+ merge_request_user_mentions.reset_column_information
+
+ expect(merge_request_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(merge_request_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }).to be_nil
+ }
+ end
+ end
+ end
+ end
+
+ describe '#up' do
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(described_class).to(
+ receive(:com_or_dev_or_test_but_not_jh?).and_return(com_or_dev_or_test_but_not_jh?)
+ )
+ # rubocop:enable RSpec/AnyInstanceOf
+ end
+
+ context 'when GitLab.com, dev, or test' do
+ let(:com_or_dev_or_test_but_not_jh?) { true }
+
+ it_behaves_like 'column `note_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance with the `note_id_convert_to_bigint` column already dropped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ it_behaves_like 'column `note_id_convert_to_bigint` is already dropped'
+ end
+
+ context 'when self-managed instance columns already swapped' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE merge_request_user_mentions ALTER COLUMN note_id TYPE bigint')
+ connection.execute(
+ 'ALTER TABLE merge_request_user_mentions ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint integer'
+ )
+
+ disable_migrations_output { migrate! }
+ end
+
+ after do
+ connection.execute('ALTER TABLE merge_request_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'does not swaps the columns' do
+ expect(merge_request_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(merge_request_user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to(
+ eq('integer')
+ )
+ end
+ end
+
+ context 'when self-managed instance' do
+ let(:com_or_dev_or_test_but_not_jh?) { false }
+
+ before do
+ connection.execute('ALTER TABLE merge_request_user_mentions ALTER COLUMN note_id TYPE integer')
+ connection.execute(
+ 'ALTER TABLE merge_request_user_mentions ADD COLUMN IF NOT EXISTS note_id_convert_to_bigint bigint'
+ )
+ connection.execute('ALTER TABLE merge_request_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint')
+ connection.execute(
+ 'DROP INDEX IF EXISTS index_merge_request_user_mentions_on_note_id_convert_to_bigint CASCADE'
+ )
+ connection.execute('CREATE OR REPLACE FUNCTION trigger_bfcbace4260d() RETURNS trigger LANGUAGE plpgsql AS $$
+ BEGIN NEW."note_id_convert_to_bigint" := NEW."note_id"; RETURN NEW; END; $$;')
+ end
+
+ after do
+ connection.execute('ALTER TABLE merge_request_user_mentions DROP COLUMN IF EXISTS note_id_convert_to_bigint')
+ end
+
+ it 'swaps the columns' do
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ merge_request_user_mentions.reset_column_information
+
+ expect(merge_request_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(merge_request_user_mentions.columns.find do |c|
+ c.name == 'note_id_convert_to_bigint'
+ end.sql_type).to(
+ eq('bigint')
+ )
+ }
+
+ migration.after -> {
+ merge_request_user_mentions.reset_column_information
+
+ expect(merge_request_user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(merge_request_user_mentions.columns.find do |c|
+ c.name == 'note_id_convert_to_bigint'
+ end.sql_type).to(
+ eq('integer')
+ )
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb
index 422dd9a463b..a808cb1c823 100644
--- a/spec/models/ability_spec.rb
+++ b/spec/models/ability_spec.rb
@@ -270,6 +270,11 @@ RSpec.describe Ability do
end
describe '.issues_readable_by_user' do
+ it 'is aliased to .work_items_readable_by_user' do
+ expect(described_class.method(:issues_readable_by_user))
+ .to eq(described_class.method(:work_items_readable_by_user))
+ end
+
context 'with an admin when admin mode is enabled', :enable_admin_mode do
it 'returns all given issues' do
user = build(:user, admin: true)
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index 584f9b010ad..1fa60a210e2 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -385,13 +385,28 @@ RSpec.describe AbuseReport, feature_category: :insider_threat do
end
end
- describe '#other_reports_for_user' do
- let(:report) { create(:abuse_report) }
- let(:another_user_report) { create(:abuse_report, user: report.user) }
- let(:another_report) { create(:abuse_report) }
+ describe '#past_closed_reports_for_user' do
+ let(:report_1) { create(:abuse_report, :closed) }
+ let(:report_2) { create(:abuse_report, user: report.user) }
+ let(:report_3) { create(:abuse_report, :closed, user: report.user) }
- it 'returns other reports for the same user' do
- expect(report.other_reports_for_user).to match_array(another_user_report)
+ it 'returns past closed reports for the same user' do
+ expect(report.past_closed_reports_for_user).to match_array(report_3)
+ end
+ end
+
+ describe '#similar_open_reports_for_user' do
+ let(:report_1) { create(:abuse_report, category: 'spam') }
+ let(:report_2) { create(:abuse_report, category: 'spam', user: report.user) }
+ let(:report_3) { create(:abuse_report, category: 'offensive', user: report.user) }
+ let(:report_4) { create(:abuse_report, :closed, category: 'spam', user: report.user) }
+
+ it 'returns open reports for the same user and category' do
+ expect(report.similar_open_reports_for_user).to match_array(report_2)
+ end
+
+ it 'returns no abuse reports when the report is closed' do
+ expect(report_4.similar_open_reports_for_user).to match_array(described_class.none)
end
end
diff --git a/spec/models/active_session_spec.rb b/spec/models/active_session_spec.rb
index 54169c254a6..af884fdb83c 100644
--- a/spec/models/active_session_spec.rb
+++ b/spec/models/active_session_spec.rb
@@ -650,25 +650,13 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
end
end
- describe '.set_active_user_cookie' do
+ describe '.set_active_user_cookie', :freeze_time do
let(:auth) { double(cookies: {}) }
it 'sets marketing cookie' do
described_class.set_active_user_cookie(auth)
- expect(auth.cookies[:about_gitlab_active_user][:value]).to be_truthy
- end
- end
-
- describe '.unset_active_user_cookie' do
- let(:auth) { double(cookies: {}) }
-
- before do
- described_class.set_active_user_cookie(auth)
- end
-
- it 'unsets marketing cookie' do
- described_class.unset_active_user_cookie(auth)
- expect(auth.cookies[:about_gitlab_active_user]).to be_nil
+ expect(auth.cookies[:gitlab_user][:value]).to be_truthy
+ expect(auth.cookies[:gitlab_user][:expires]).to be_within(1.minute).of(2.weeks.from_now)
end
end
end
diff --git a/spec/models/alert_management/http_integration_spec.rb b/spec/models/alert_management/http_integration_spec.rb
index 479ae8a4966..dc26d0323d7 100644
--- a/spec/models/alert_management/http_integration_spec.rb
+++ b/spec/models/alert_management/http_integration_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe AlertManagement::HttpIntegration, feature_category: :incident_man
let_it_be(:project) { create(:project) }
- subject(:integration) { build(:alert_management_http_integration) }
+ subject(:integration) { build(:alert_management_http_integration, project: project) }
describe 'associations' do
it { is_expected.to belong_to(:project) }
diff --git a/spec/models/alerting/project_alerting_setting_spec.rb b/spec/models/alerting/project_alerting_setting_spec.rb
index 90c5f8313b0..0424b94a1b7 100644
--- a/spec/models/alerting/project_alerting_setting_spec.rb
+++ b/spec/models/alerting/project_alerting_setting_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Alerting::ProjectAlertingSetting do
+RSpec.describe Alerting::ProjectAlertingSetting, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
subject { create(:project_alerting_setting, project: project) }
@@ -37,4 +37,31 @@ RSpec.describe Alerting::ProjectAlertingSetting do
end
end
end
+
+ describe '#sync_http_integration after_save callback' do
+ let_it_be_with_reload(:setting) { create(:project_alerting_setting, :with_http_integration, project: project) }
+ let_it_be_with_reload(:http_integration) { setting.project.alert_management_http_integrations.last! }
+ let_it_be(:new_token) { 'new_token' }
+
+ context 'with corresponding HTTP integration' do
+ let_it_be(:original_token) { http_integration.token }
+
+ it 'syncs the attribute' do
+ expect { setting.update!(token: new_token) }
+ .to change { http_integration.reload.token }
+ .from(original_token).to(new_token)
+ end
+ end
+
+ context 'without corresponding HTTP integration' do
+ before do
+ http_integration.update_columns(endpoint_identifier: 'legacy')
+ end
+
+ it 'does not sync the attribute or execute extra queries' do
+ expect { setting.update!(token: new_token) }
+ .not_to change { http_integration.reload.token }
+ end
+ end
+ end
end
diff --git a/spec/models/analytics/cycle_analytics/runtime_limiter_spec.rb b/spec/models/analytics/cycle_analytics/runtime_limiter_spec.rb
new file mode 100644
index 00000000000..1a5200719c8
--- /dev/null
+++ b/spec/models/analytics/cycle_analytics/runtime_limiter_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Analytics::CycleAnalytics::RuntimeLimiter, feature_category: :value_stream_management do
+ let(:max_runtime) { 321 }
+ let(:runtime_limiter) { described_class.new(max_runtime) }
+
+ describe '#elapsed_time' do
+ it 'reports monotonic elapsed time since instantiation' do
+ elapsed = 123
+ first_monotonic_time = 100
+ second_monotonic_time = first_monotonic_time + elapsed
+
+ expect(Gitlab::Metrics::System).to receive(:monotonic_time)
+ .and_return(first_monotonic_time, second_monotonic_time)
+
+ expect(runtime_limiter.elapsed_time).to eq(elapsed)
+ end
+ end
+
+ describe '#over_time?' do
+ it 'returns true if over time' do
+ start_time = 100
+ allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(start_time, start_time + max_runtime - 1)
+
+ expect(runtime_limiter.over_time?).to be(false)
+
+ allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(start_time + max_runtime)
+ expect(runtime_limiter.over_time?).to be(true)
+
+ allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(start_time + max_runtime + 1)
+ expect(runtime_limiter.over_time?).to be(true)
+ end
+ end
+
+ describe '#was_over_time?' do
+ it 'returns true if over_time? returned true at an earlier step' do
+ first_monotonic_time = 10
+ second_monotonic_time = first_monotonic_time + 50
+ third_monotonic_time = second_monotonic_time + 50 # over time: 110 > 100
+
+ expect(Gitlab::Metrics::System).to receive(:monotonic_time)
+ .and_return(first_monotonic_time, second_monotonic_time, third_monotonic_time)
+
+ runtime_limiter = described_class.new(100)
+
+ expect(runtime_limiter.over_time?).to be(false) # uses the second_monotonic_time
+ expect(runtime_limiter.was_over_time?).to be(false)
+
+ expect(runtime_limiter.over_time?).to be(true) # uses the third_monotonic_time
+ expect(runtime_limiter.was_over_time?).to be(true)
+ end
+ end
+end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 5a70bec8b33..3fc7d8f6fc8 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -25,6 +25,7 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { expect(setting.kroki_formats).to eq({}) }
it { expect(setting.default_branch_protection_defaults).to eq({}) }
it { expect(setting.max_decompressed_archive_size).to eq(25600) }
+ it { expect(setting.decompress_archive_file_timeout).to eq(210) }
end
describe 'validations' do
@@ -134,6 +135,9 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { is_expected.to validate_presence_of(:container_registry_import_target_plan) }
it { is_expected.to validate_presence_of(:container_registry_import_created_before) }
+ it { is_expected.to validate_numericality_of(:decompress_archive_file_timeout).only_integer.is_greater_than_or_equal_to(0) }
+ it { is_expected.not_to allow_value(nil).for(:decompress_archive_file_timeout) }
+
it { is_expected.to validate_numericality_of(:dependency_proxy_ttl_group_policy_worker_capacity).only_integer.is_greater_than_or_equal_to(0) }
it { is_expected.not_to allow_value(nil).for(:dependency_proxy_ttl_group_policy_worker_capacity) }
@@ -237,6 +241,11 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { is_expected.not_to allow_value(nil).for(:users_get_by_id_limit_allowlist) }
it { is_expected.to allow_value([]).for(:users_get_by_id_limit_allowlist) }
+ it { is_expected.to allow_value(many_usernames(100)).for(:search_rate_limit_allowlist) }
+ it { is_expected.not_to allow_value(many_usernames(101)).for(:search_rate_limit_allowlist) }
+ it { is_expected.not_to allow_value(nil).for(:search_rate_limit_allowlist) }
+ it { is_expected.to allow_value([]).for(:search_rate_limit_allowlist) }
+
it { is_expected.to allow_value('all_tiers').for(:whats_new_variant) }
it { is_expected.to allow_value('current_tier').for(:whats_new_variant) }
it { is_expected.to allow_value('disabled').for(:whats_new_variant) }
@@ -436,11 +445,14 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
it { is_expected.not_to allow_value(nil).for(:snowplow_collector_hostname) }
it { is_expected.to allow_value("snowplow.gitlab.com").for(:snowplow_collector_hostname) }
+ it { is_expected.to allow_value("db-snowplow.gitlab.com").for(:snowplow_database_collector_hostname) }
+ it { is_expected.not_to allow_value("#{'a' * 256}db-snowplow.gitlab.com").for(:snowplow_database_collector_hostname) }
it { is_expected.not_to allow_value('/example').for(:snowplow_collector_hostname) }
end
context 'when snowplow is not enabled' do
it { is_expected.to allow_value(nil).for(:snowplow_collector_hostname) }
+ it { is_expected.to allow_value(nil).for(:snowplow_database_collector_hostname) }
end
end
diff --git a/spec/models/award_emoji_spec.rb b/spec/models/award_emoji_spec.rb
index 586ec8f723a..b179f2df816 100644
--- a/spec/models/award_emoji_spec.rb
+++ b/spec/models/award_emoji_spec.rb
@@ -2,7 +2,9 @@
require 'spec_helper'
-RSpec.describe AwardEmoji do
+RSpec.describe AwardEmoji, feature_category: :team_planning do
+ let_it_be(:user) { create(:user) }
+
describe 'Associations' do
it { is_expected.to belong_to(:awardable) }
it { is_expected.to belong_to(:user) }
@@ -60,7 +62,6 @@ RSpec.describe AwardEmoji do
end
context 'custom emoji' do
- let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:emoji) { create(:custom_emoji, name: 'partyparrot', namespace: group) }
let_it_be(:project) { create(:project, namespace: group) }
@@ -144,27 +145,27 @@ RSpec.describe AwardEmoji do
describe 'broadcasting updates' do
context 'on a note' do
let(:note) { create(:note_on_issue) }
- let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: note) }
+ let(:award_emoji) { build(:award_emoji, user: user, awardable: note) }
it 'broadcasts updates on the note when saved' do
- expect(note).to receive(:expire_etag_cache)
+ expect(note).to receive(:broadcast_noteable_notes_changed)
expect(note).to receive(:trigger_note_subscription_update)
award_emoji.save!
end
it 'broadcasts updates on the note when destroyed' do
- expect(note).to receive(:expire_etag_cache)
+ expect(note).to receive(:broadcast_noteable_notes_changed)
expect(note).to receive(:trigger_note_subscription_update)
award_emoji.destroy!
end
context 'when importing' do
- let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: note, importing: true) }
+ let(:award_emoji) { build(:award_emoji, user: user, awardable: note, importing: true) }
it 'does not broadcast updates on the note when saved' do
- expect(note).not_to receive(:expire_etag_cache)
+ expect(note).not_to receive(:broadcast_noteable_notes_changed)
expect(note).not_to receive(:trigger_note_subscription_update)
award_emoji.save!
@@ -174,17 +175,17 @@ RSpec.describe AwardEmoji do
context 'on another awardable' do
let(:issue) { create(:issue) }
- let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: issue) }
+ let(:award_emoji) { build(:award_emoji, user: user, awardable: issue) }
it 'does not broadcast updates on the issue when saved' do
- expect(issue).not_to receive(:expire_etag_cache)
+ expect(issue).not_to receive(:broadcast_noteable_notes_changed)
expect(issue).not_to receive(:trigger_note_subscription_update)
award_emoji.save!
end
it 'does not broadcast updates on the issue when destroyed' do
- expect(issue).not_to receive(:expire_etag_cache)
+ expect(issue).not_to receive(:broadcast_noteable_notes_changed)
expect(issue).not_to receive(:trigger_note_subscription_update)
award_emoji.destroy!
@@ -194,7 +195,7 @@ RSpec.describe AwardEmoji do
describe 'bumping updated at' do
let(:note) { create(:note_on_issue) }
- let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: note) }
+ let(:award_emoji) { build(:award_emoji, user: user, awardable: note) }
it 'calls bump_updated_at on the note when saved' do
expect(note).to receive(:bump_updated_at)
@@ -210,7 +211,7 @@ RSpec.describe AwardEmoji do
context 'on another awardable' do
let(:issue) { create(:issue) }
- let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: issue) }
+ let(:award_emoji) { build(:award_emoji, user: user, awardable: issue) }
it 'does not error out when saved' do
expect { award_emoji.save! }.not_to raise_error
@@ -248,8 +249,8 @@ RSpec.describe AwardEmoji do
describe 'updating upvotes_count' do
context 'on an issue' do
let(:issue) { create(:issue) }
- let(:upvote) { build(:award_emoji, :upvote, user: build(:user), awardable: issue) }
- let(:downvote) { build(:award_emoji, :downvote, user: build(:user), awardable: issue) }
+ let(:upvote) { build(:award_emoji, :upvote, user: user, awardable: issue) }
+ let(:downvote) { build(:award_emoji, :downvote, user: user, awardable: issue) }
it 'updates upvotes_count on the issue when saved' do
expect(issue).to receive(:update_column).with(:upvotes_count, 1).once
@@ -268,7 +269,7 @@ RSpec.describe AwardEmoji do
context 'on another awardable' do
let(:merge_request) { create(:merge_request) }
- let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: merge_request) }
+ let(:award_emoji) { build(:award_emoji, user: user, awardable: merge_request) }
it 'does not update upvotes_count on the merge_request when saved' do
expect(merge_request).not_to receive(:update_column)
@@ -329,7 +330,7 @@ RSpec.describe AwardEmoji do
describe '#to_ability_name' do
let(:merge_request) { create(:merge_request) }
- let(:award_emoji) { build(:award_emoji, user: build(:user), awardable: merge_request) }
+ let(:award_emoji) { build(:award_emoji, user: user, awardable: merge_request) }
it 'returns correct ability name' do
expect(award_emoji.to_ability_name).to be('emoji')
diff --git a/spec/models/bulk_imports/entity_spec.rb b/spec/models/bulk_imports/entity_spec.rb
index da1eb12e9b8..3e98ba0973e 100644
--- a/spec/models/bulk_imports/entity_spec.rb
+++ b/spec/models/bulk_imports/entity_spec.rb
@@ -438,4 +438,12 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
end
end
end
+
+ describe '#source_version' do
+ subject { build(:bulk_import_entity, :group_entity) }
+
+ it 'pulls the source version from the associated BulkImport' do
+ expect(subject.source_version).to eq(subject.bulk_import.source_version_info)
+ end
+ end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index a556244ae00..2a5d781edc7 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -3,6 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_default: :keep do
+ using RSpec::Parameterized::TableSyntax
include Ci::TemplateHelpers
include AfterNextHelpers
@@ -1493,8 +1494,6 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
describe 'state transition metrics' do
- using RSpec::Parameterized::TableSyntax
-
subject { build.send(event) }
where(:state, :report_count, :trait) do
@@ -2129,8 +2128,6 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
describe '#ref_slug' do
- using RSpec::Parameterized::TableSyntax
-
where(:ref, :slug) do
'master' | 'master'
'1-foo' | '1-foo'
@@ -2468,8 +2465,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
context 'when build has environment and user-provided variables' do
let(:expected_variables) do
predefined_variables.map { |variable| variable.fetch(:key) } +
- %w[YAML_VARIABLE CI_ENVIRONMENT_NAME CI_ENVIRONMENT_SLUG
- CI_ENVIRONMENT_ACTION CI_ENVIRONMENT_TIER CI_ENVIRONMENT_URL]
+ %w[YAML_VARIABLE CI_ENVIRONMENT_SLUG CI_ENVIRONMENT_URL]
end
before do
@@ -2478,8 +2474,14 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
build.yaml_variables = [{ key: 'YAML_VARIABLE', value: 'var', public: true }]
build.environment = 'staging'
- # CI_ENVIRONMENT_NAME is set in predefined_variables when job environment is provided
- predefined_variables.insert(18, { key: 'CI_ENVIRONMENT_NAME', value: 'staging', public: true, masked: false })
+ insert_expected_predefined_variables(
+ [
+ { key: 'CI_ENVIRONMENT_NAME', value: 'staging', public: true, masked: false },
+ { key: 'CI_ENVIRONMENT_ACTION', value: 'start', public: true, masked: false },
+ { key: 'CI_ENVIRONMENT_TIER', value: 'staging', public: true, masked: false },
+ { key: 'CI_ENVIRONMENT_URL', value: 'https://gitlab.com', public: true, masked: false }
+ ],
+ after: 'CI_NODE_TOTAL')
end
it 'matches explicit variables ordering' do
@@ -2550,6 +2552,11 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
expect(runner_vars).not_to include('CI_JOB_JWT_V2')
end
end
+
+ def insert_expected_predefined_variables(variables, after:)
+ index = predefined_variables.index { |h| h[:key] == after }
+ predefined_variables.insert(index + 1, *variables)
+ end
end
context 'when build has user' do
@@ -2583,34 +2590,28 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
context 'when build has an environment' do
- let(:environment_variables) do
+ let(:expected_environment_variables) do
[
{ key: 'CI_ENVIRONMENT_NAME', value: 'production', public: true, masked: false },
- { key: 'CI_ENVIRONMENT_SLUG', value: 'prod-slug', public: true, masked: false },
- { key: 'CI_ENVIRONMENT_TIER', value: 'production', public: true, masked: false }
+ { key: 'CI_ENVIRONMENT_ACTION', value: 'start', public: true, masked: false },
+ { key: 'CI_ENVIRONMENT_TIER', value: 'production', public: true, masked: false },
+ { key: 'CI_ENVIRONMENT_URL', value: 'http://prd.example.com/$CI_JOB_NAME', public: true, masked: false }
]
end
- let!(:environment) do
- create(
- :environment,
- project: build.project,
- name: 'production',
- slug: 'prod-slug',
- tier: 'production',
- external_url: ''
- )
- end
-
- before do
- build.update!(environment: 'production')
- end
+ let(:build) { create(:ci_build, :with_deployment, :deploy_to_production, ref: pipeline.ref, pipeline: pipeline) }
shared_examples 'containing environment variables' do
- it { is_expected.to include(*environment_variables) }
+ it { is_expected.to include(*expected_environment_variables) }
end
context 'when no URL was set' do
+ before do
+ build.update!(options: { environment: { url: nil } })
+ build.persisted_environment.update!(external_url: nil)
+ expected_environment_variables.delete_if { |var| var[:key] == 'CI_ENVIRONMENT_URL' }
+ end
+
it_behaves_like 'containing environment variables'
it 'does not have CI_ENVIRONMENT_URL' do
@@ -2620,12 +2621,26 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
end
+ context 'when environment is created dynamically' do
+ let(:build) { create(:ci_build, :with_deployment, :start_review_app, ref: pipeline.ref, pipeline: pipeline) }
+
+ let(:expected_environment_variables) do
+ [
+ { key: 'CI_ENVIRONMENT_NAME', value: 'review/master', public: true, masked: false },
+ { key: 'CI_ENVIRONMENT_ACTION', value: 'start', public: true, masked: false },
+ { key: 'CI_ENVIRONMENT_TIER', value: 'development', public: true, masked: false },
+ { key: 'CI_ENVIRONMENT_URL', value: 'http://staging.example.com/$CI_JOB_NAME', public: true, masked: false }
+ ]
+ end
+
+ it_behaves_like 'containing environment variables'
+ end
+
context 'when an URL was set' do
let(:url) { 'http://host/test' }
before do
- environment_variables <<
- { key: 'CI_ENVIRONMENT_URL', value: url, public: true, masked: false }
+ expected_environment_variables.find { |var| var[:key] == 'CI_ENVIRONMENT_URL' }[:value] = url
end
context 'when the URL was set from the job' do
@@ -2641,14 +2656,15 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
it_behaves_like 'containing environment variables'
it 'puts $CI_ENVIRONMENT_URL in the last so all other variables are available to be used when runners are trying to expand it' do
- expect(subject.to_runner_variables.last).to eq(environment_variables.last)
+ expect(subject.to_runner_variables.last).to eq(expected_environment_variables.last)
end
end
end
context 'when the URL was not set from the job, but environment' do
before do
- environment.update!(external_url: url)
+ build.update!(options: { environment: { url: nil } })
+ build.persisted_environment.update!(external_url: url)
end
it_behaves_like 'containing environment variables'
@@ -2682,10 +2698,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
context 'when environment scope matches build environment' do
- before do
- create(:environment, name: 'staging', project: project)
- build.update!(environment: 'staging')
- end
+ let(:build) { create(:ci_build, :with_deployment, :start_staging, ref: pipeline.ref, pipeline: pipeline) }
it { is_expected.to include(environment_specific_variable) }
end
@@ -4001,73 +4014,61 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
end
- describe 'pages deployments' do
- let_it_be(:build, reload: true) { create(:ci_build, pipeline: pipeline, user: user) }
+ describe '#pages_generator?', feature_category: :pages do
+ where(:name, :enabled, :result) do
+ 'foo' | false | false
+ 'pages' | false | false
+ 'pages:preview' | true | false
+ 'pages' | true | true
+ end
- context 'when job is "pages"' do
+ with_them do
before do
- build.name = 'pages'
+ stub_pages_setting(enabled: enabled)
+ build.update!(name: name)
end
- context 'when pages are enabled' do
- before do
- allow(Gitlab.config.pages).to receive_messages(enabled: true)
- end
-
- it 'is marked as pages generator' do
- expect(build).to be_pages_generator
- end
-
- context 'job succeeds' do
- it "calls pages worker" do
- expect(PagesWorker).to receive(:perform_async).with(:deploy, build.id)
+ subject { build.pages_generator? }
- build.success!
- end
- end
+ it { is_expected.to eq(result) }
+ end
+ end
- context 'job fails' do
- it "does not call pages worker" do
- expect(PagesWorker).not_to receive(:perform_async)
+ describe 'pages deployments', feature_category: :pages do
+ let_it_be(:build, reload: true) { create(:ci_build, name: 'pages', pipeline: pipeline, user: user) }
- build.drop!
- end
- end
+ context 'when pages are enabled' do
+ before do
+ stub_pages_setting(enabled: true)
end
- context 'when pages are disabled' do
- before do
- allow(Gitlab.config.pages).to receive_messages(enabled: false)
- end
+ context 'and job succeeds' do
+ it "calls pages worker" do
+ expect(PagesWorker).to receive(:perform_async).with(:deploy, build.id)
- it 'is not marked as pages generator' do
- expect(build).not_to be_pages_generator
+ build.success!
end
+ end
- context 'job succeeds' do
- it "does not call pages worker" do
- expect(PagesWorker).not_to receive(:perform_async)
+ context 'and job fails' do
+ it "does not call pages worker" do
+ expect(PagesWorker).not_to receive(:perform_async)
- build.success!
- end
+ build.drop!
end
end
end
- context 'when job is not "pages"' do
+ context 'when pages are disabled' do
before do
- build.name = 'other-job'
+ stub_pages_setting(enabled: false)
end
- it 'is not marked as pages generator' do
- expect(build).not_to be_pages_generator
- end
-
- context 'job succeeds' do
+ context 'and job succeeds' do
it "does not call pages worker" do
expect(PagesWorker).not_to receive(:perform_async)
- build.success
+ build.success!
end
end
end
@@ -5604,26 +5605,4 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def
end
end
end
-
- describe 'routing table switch' do
- context 'with ff disabled' do
- before do
- stub_feature_flags(ci_partitioning_use_ci_builds_routing_table: false)
- end
-
- it 'uses the legacy table' do
- expect(described_class.table_name).to eq('ci_builds')
- end
- end
-
- context 'with ff enabled' do
- before do
- stub_feature_flags(ci_partitioning_use_ci_builds_routing_table: true)
- end
-
- it 'uses the routing table' do
- expect(described_class.table_name).to eq('p_ci_builds')
- end
- end
- end
end
diff --git a/spec/models/ci/catalog/listing_spec.rb b/spec/models/ci/catalog/listing_spec.rb
index 159b70d7f8f..f28a0e82bbd 100644
--- a/spec/models/ci/catalog/listing_spec.rb
+++ b/spec/models/ci/catalog/listing_spec.rb
@@ -34,9 +34,9 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
end
context 'when the namespace has catalog resources' do
- let_it_be(:resource) { create(:catalog_resource, project: project_1) }
- let_it_be(:resource_2) { create(:catalog_resource, project: project_2) }
- let_it_be(:other_namespace_resource) { create(:catalog_resource, project: project_3) }
+ let_it_be(:resource) { create(:ci_catalog_resource, project: project_1) }
+ let_it_be(:resource_2) { create(:ci_catalog_resource, project: project_2) }
+ let_it_be(:other_namespace_resource) { create(:ci_catalog_resource, project: project_3) }
it 'contains only catalog resources for projects in that namespace' do
is_expected.to contain_exactly(resource, resource_2)
@@ -65,8 +65,8 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
end
context 'when the user only has access to some projects in the namespace' do
- let!(:resource_1) { create(:catalog_resource, project: project_1) }
- let!(:resource_2) { create(:catalog_resource, project: project_2) }
+ let!(:resource_1) { create(:ci_catalog_resource, project: project_1) }
+ let!(:resource_2) { create(:ci_catalog_resource, project: project_2) }
before do
project_1.add_developer(user)
@@ -79,7 +79,7 @@ RSpec.describe Ci::Catalog::Listing, feature_category: :pipeline_composition do
end
context 'when the user does not have access to the namespace' do
- let!(:resource) { create(:catalog_resource, project: project_1) }
+ let!(:resource) { create(:ci_catalog_resource, project: project_1) }
it { is_expected.to be_empty }
end
diff --git a/spec/models/ci/catalog/resource_spec.rb b/spec/models/ci/catalog/resource_spec.rb
index 4608e611ea1..082283bb7bc 100644
--- a/spec/models/ci/catalog/resource_spec.rb
+++ b/spec/models/ci/catalog/resource_spec.rb
@@ -6,9 +6,9 @@ RSpec.describe Ci::Catalog::Resource, feature_category: :pipeline_composition do
let_it_be(:project) { create(:project, name: 'A') }
let_it_be(:project_2) { build(:project, name: 'Z') }
let_it_be(:project_3) { build(:project, name: 'L') }
- let_it_be(:resource) { create(:catalog_resource, project: project) }
- let_it_be(:resource_2) { create(:catalog_resource, project: project_2) }
- let_it_be(:resource_3) { create(:catalog_resource, project: project_3) }
+ let_it_be(:resource) { create(:ci_catalog_resource, project: project) }
+ let_it_be(:resource_2) { create(:ci_catalog_resource, project: project_2) }
+ let_it_be(:resource_3) { create(:ci_catalog_resource, project: project_3) }
let_it_be(:release1) { create(:release, project: project, released_at: Time.zone.now - 2.days) }
let_it_be(:release2) { create(:release, project: project, released_at: Time.zone.now - 1.day) }
diff --git a/spec/models/ci/catalog/resources/component_spec.rb b/spec/models/ci/catalog/resources/component_spec.rb
index caaf76e610d..e8c92ce0788 100644
--- a/spec/models/ci/catalog/resources/component_spec.rb
+++ b/spec/models/ci/catalog/resources/component_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::Catalog::Resources::Component, type: :model, feature_category: :pipeline_composition do
- let(:component) { build(:catalog_resource_component) }
+ let(:component) { build(:ci_catalog_resource_component) }
it { is_expected.to belong_to(:catalog_resource).class_name('Ci::Catalog::Resource') }
it { is_expected.to belong_to(:project) }
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 56e69cc2b9c..a8e9d36a3a7 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1216,13 +1216,12 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do
before do
runner.tick_runner_queue
- runner.destroy!
end
it 'cleans up the queue' do
- Gitlab::Redis::Cache.with do |redis|
- expect(redis.get(queue_key)).to be_nil
- end
+ expect(Gitlab::Workhorse).to receive(:cleanup_key).with(queue_key)
+
+ runner.destroy!
end
end
end
diff --git a/spec/models/clusters/agent_token_spec.rb b/spec/models/clusters/agent_token_spec.rb
index 41f8215b713..bc158fc9117 100644
--- a/spec/models/clusters/agent_token_spec.rb
+++ b/spec/models/clusters/agent_token_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Clusters::AgentToken do
+RSpec.describe Clusters::AgentToken, feature_category: :deployment_management do
it { is_expected.to belong_to(:agent).class_name('Clusters::Agent').required }
it { is_expected.to belong_to(:created_by_user).class_name('User').optional }
it { is_expected.to validate_length_of(:description).is_at_most(1024) }
@@ -12,8 +12,9 @@ RSpec.describe Clusters::AgentToken do
it_behaves_like 'having unique enum values'
describe 'scopes' do
+ let_it_be(:agent) { create(:cluster_agent) }
+
describe '.order_last_used_at_desc' do
- let_it_be(:agent) { create(:cluster_agent) }
let_it_be(:token_1) { create(:cluster_agent_token, agent: agent, last_used_at: 7.days.ago) }
let_it_be(:token_2) { create(:cluster_agent_token, agent: agent, last_used_at: nil) }
let_it_be(:token_3) { create(:cluster_agent_token, agent: agent, last_used_at: 2.days.ago) }
@@ -25,8 +26,8 @@ RSpec.describe Clusters::AgentToken do
end
describe 'status-related scopes' do
- let!(:active_token) { create(:cluster_agent_token) }
- let!(:revoked_token) { create(:cluster_agent_token, :revoked) }
+ let!(:active_token) { create(:cluster_agent_token, agent: agent) }
+ let!(:revoked_token) { create(:cluster_agent_token, :revoked, agent: agent) }
describe '.with_status' do
context 'when filtering by active status' do
@@ -48,6 +49,29 @@ RSpec.describe Clusters::AgentToken do
it { is_expected.to contain_exactly(active_token) }
end
end
+
+ describe '.connected' do
+ let!(:token) { create(:cluster_agent_token, agent: agent, status: status, last_used_at: last_used_at) }
+
+ let(:status) { :active }
+ let(:last_used_at) { 2.minutes.ago }
+
+ subject { described_class.connected }
+
+ it { is_expected.to contain_exactly(token) }
+
+ context 'when the token has not been used recently' do
+ let(:last_used_at) { 2.hours.ago }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when the token is not active' do
+ let(:status) { :revoked }
+
+ it { is_expected.to be_empty }
+ end
+ end
end
describe '#token' do
@@ -64,6 +88,13 @@ RSpec.describe Clusters::AgentToken do
agent_token = create(:cluster_agent_token)
expect(agent_token.token.length).to be >= 50
end
+
+ it 'has a prefix' do
+ agent_token = build(:cluster_agent_token, token_encrypted: nil)
+ agent_token.save!
+
+ expect(agent_token.token).to start_with described_class::TOKEN_PREFIX
+ end
end
describe '#to_ability_name' do
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 9ce9f0e13b5..e9257b08bca 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -44,6 +44,24 @@ RSpec.describe CommitStatus, feature_category: :continuous_integration do
it { is_expected.not_to be_retried }
it { expect(described_class.primary_key).to eq('id') }
+ describe '.switch_table_names' do
+ before do
+ stub_env('USE_CI_BUILDS_ROUTING_TABLE', flag_value)
+ end
+
+ context 'with the env flag disabled' do
+ let(:flag_value) { 'false' }
+
+ it { expect(described_class.switch_table_names).to eq(:ci_builds) }
+ end
+
+ context 'with the env flag enabled' do
+ let(:flag_value) { 'true' }
+
+ it { expect(described_class.switch_table_names).to eq(:p_ci_builds) }
+ end
+ end
+
describe '#author' do
subject { commit_status.author }
@@ -1067,26 +1085,4 @@ RSpec.describe CommitStatus, feature_category: :continuous_integration do
it_behaves_like 'having enum with nil value'
end
-
- describe 'routing table switch' do
- context 'with ff disabled' do
- before do
- stub_feature_flags(ci_partitioning_use_ci_builds_routing_table: false)
- end
-
- it 'uses the legacy table' do
- expect(described_class.table_name).to eq('ci_builds')
- end
- end
-
- context 'with ff enabled' do
- before do
- stub_feature_flags(ci_partitioning_use_ci_builds_routing_table: true)
- end
-
- it 'uses the routing table' do
- expect(described_class.table_name).to eq('p_ci_builds')
- end
- end
- end
end
diff --git a/spec/models/concerns/as_cte_spec.rb b/spec/models/concerns/as_cte_spec.rb
index 06d9650ec46..c92d46ef25f 100644
--- a/spec/models/concerns/as_cte_spec.rb
+++ b/spec/models/concerns/as_cte_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe AsCte do
it { expect(subject.query).to eq(query) }
it { expect(subject.table.name).to eq(name.to_s) }
- context 'with materialized parameter', if: Gitlab::Database::AsWithMaterialized.materialized_supported? do
+ context 'with materialized parameter' do
subject { query.as_cte(name, materialized: materialized).to_arel.to_sql }
context 'as true' do
diff --git a/spec/models/concerns/each_batch_spec.rb b/spec/models/concerns/each_batch_spec.rb
index 75c5cac899b..f274f8c96ff 100644
--- a/spec/models/concerns/each_batch_spec.rb
+++ b/spec/models/concerns/each_batch_spec.rb
@@ -75,6 +75,26 @@ RSpec.describe EachBatch do
expect(ids).to eq(ids.sort.reverse)
end
+ shared_examples 'preloaded batch' do |method|
+ it 'respects preloading without N+1 queries' do
+ one, two = User.first(2)
+
+ create(:key, user: one)
+
+ scope = User.send(method, :keys)
+
+ control = ActiveRecord::QueryRecorder.new { scope.each_batch(of: 5) { |batch| batch.each(&:keys) } }
+
+ create(:key, user: one)
+ create(:key, user: two)
+
+ expect { scope.each_batch(of: 5) { |batch| batch.each(&:keys) } }.not_to exceed_query_limit(control)
+ end
+ end
+
+ it_behaves_like 'preloaded batch', :preload
+ it_behaves_like 'preloaded batch', :includes
+
describe 'current scope' do
let(:entry) { create(:user, sign_in_count: 1) }
let(:ids_with_new_relation) { model.where(id: entry.id).pluck(:id) }
diff --git a/spec/models/concerns/expirable_spec.rb b/spec/models/concerns/expirable_spec.rb
index 78fe265a6bb..f7f1ce611b4 100644
--- a/spec/models/concerns/expirable_spec.rb
+++ b/spec/models/concerns/expirable_spec.rb
@@ -17,8 +17,11 @@ RSpec.describe Expirable do
it 'scopes the query when multiple models are expirable' do
expired_access_token = create(:personal_access_token, :expired, user: no_expire.user)
- expect(PersonalAccessToken.expired.joins(user: :members)).to match_array([expired_access_token])
- expect(PersonalAccessToken.joins(user: :members).merge(ProjectMember.expired)).to eq([])
+ ::Gitlab::Database.allow_cross_joins_across_databases(url:
+ 'https://gitlab.com/gitlab-org/gitlab/-/issues/422405') do
+ expect(PersonalAccessToken.expired.joins(user: :members)).to match_array([expired_access_token])
+ expect(PersonalAccessToken.joins(user: :members).merge(ProjectMember.expired)).to eq([])
+ end
end
it 'works with a timestamp expired_at field', time_travel_to: '2022-03-14T11:30:00Z' do
diff --git a/spec/models/concerns/has_user_type_spec.rb b/spec/models/concerns/has_user_type_spec.rb
index 49c3d11ed6b..54614ec2b21 100644
--- a/spec/models/concerns/has_user_type_spec.rb
+++ b/spec/models/concerns/has_user_type_spec.rb
@@ -3,6 +3,13 @@
require 'spec_helper'
RSpec.describe User, feature_category: :system_access do
+ User::USER_TYPES.keys.each do |type| # rubocop:disable RSpec/UselessDynamicDefinition
+ let_it_be(type) { create(:user, username: type, user_type: type) }
+ end
+ let(:bots) { User::BOT_USER_TYPES.map { |type| public_send(type) } }
+ let(:non_internal) { User::NON_INTERNAL_USER_TYPES.map { |type| public_send(type) } }
+ let(:everyone) { User::USER_TYPES.keys.map { |type| public_send(type) } }
+
specify 'types consistency checks', :aggregate_failures do
expect(described_class::USER_TYPES.keys)
.to match_array(%w[human ghost alert_bot project_bot support_bot service_user security_bot
@@ -20,13 +27,6 @@ RSpec.describe User, feature_category: :system_access do
end
describe 'scopes & predicates' do
- User::USER_TYPES.keys.each do |type| # rubocop:disable RSpec/UselessDynamicDefinition
- let_it_be(type) { create(:user, username: type, user_type: type) }
- end
- let(:bots) { User::BOT_USER_TYPES.map { |type| public_send(type) } }
- let(:non_internal) { User::NON_INTERNAL_USER_TYPES.map { |type| public_send(type) } }
- let(:everyone) { User::USER_TYPES.keys.map { |type| public_send(type) } }
-
describe '.bots' do
it 'includes all bots' do
expect(described_class.bots).to match_array(bots)
@@ -118,5 +118,71 @@ RSpec.describe User, feature_category: :system_access do
end
end
end
+
+ describe '#resource_bot_resource' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:group2) { create(:group) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:project2) { create(:project) }
+
+ using RSpec::Parameterized::TableSyntax
+
+ where(:bot_user, :member_of, :owning_resource) do
+ ref(:human) | [ref(:group)] | nil
+ ref(:project_bot) | [] | nil # orphaned project bot
+ ref(:project_bot) | [ref(:group)] | ref(:group)
+ ref(:project_bot) | [ref(:project)] | ref(:project)
+
+ # Project bot can only be added to one group or project.
+ # That first group or project becomes the owning resource.
+ ref(:project_bot) | [ref(:group), ref(:project)] | ref(:group)
+ ref(:project_bot) | [ref(:group), ref(:group2)] | ref(:group)
+ ref(:project_bot) | [ref(:project), ref(:group)] | ref(:project)
+ ref(:project_bot) | [ref(:project), ref(:project2)] | ref(:project)
+ end
+
+ with_them do
+ before do
+ member_of.each { |resource| resource.add_developer(bot_user) }
+ end
+
+ it 'returns the owning resource' do
+ expect(bot_user.resource_bot_resource).to eq(owning_resource)
+ end
+ end
+ end
+
+ describe 'resource_bot_owners' do
+ it 'returns nil when user is not a project bot' do
+ expect(human.resource_bot_resource).to be_nil
+ end
+
+ context 'when the user is a project bot' do
+ let(:user1) { create(:user) }
+ let(:user2) { create(:user) }
+
+ subject(:owners) { project_bot.resource_bot_owners }
+
+ it 'returns an empty array when there is no owning resource' do
+ expect(owners).to match_array([])
+ end
+
+ it 'returns group owners when owned by a group' do
+ group = create(:group)
+ group.add_developer(project_bot)
+ group.add_owner(user1)
+
+ expect(owners).to match_array([user1])
+ end
+
+ it 'returns project maintainers when owned by a project' do
+ project = create(:project)
+ project.add_developer(project_bot)
+ project.add_maintainer(user2)
+
+ expect(owners).to match_array([user2])
+ end
+ end
+ end
end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index e4af778b967..705f8f46a90 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -626,6 +626,21 @@ RSpec.describe Issuable, feature_category: :team_planning do
end
end
+ describe "#importing_or_transitioning?" do
+ let(:merge_request) { build(:merge_request, transitioning: transitioning, importing: importing) }
+
+ where(:transitioning, :importing, :result) do
+ true | false | true
+ false | true | true
+ true | true | true
+ false | false | false
+ end
+
+ with_them do
+ it { expect(merge_request.importing_or_transitioning?).to eq(result) }
+ end
+ end
+
describe '#labels_array' do
let(:project) { create(:project) }
let(:bug) { create(:label, project: project, title: 'bug') }
@@ -1023,6 +1038,22 @@ RSpec.describe Issuable, feature_category: :team_planning do
end
end
+ describe '#supports_lock_on_merge?' do
+ where(:issuable_type, :supports_lock_on_merge) do
+ :issue | false
+ :merge_request | false
+ :incident | false
+ end
+
+ with_them do
+ let(:issuable) { build_stubbed(issuable_type) }
+
+ subject { issuable.supports_lock_on_merge? }
+
+ it { is_expected.to eq(supports_lock_on_merge) }
+ end
+ end
+
describe '#severity' do
subject { issuable.severity }
diff --git a/spec/models/concerns/prometheus_adapter_spec.rb b/spec/models/concerns/prometheus_adapter_spec.rb
index 31ab8c23a84..a3f2e99f3da 100644
--- a/spec/models/concerns/prometheus_adapter_spec.rb
+++ b/spec/models/concerns/prometheus_adapter_spec.rb
@@ -100,28 +100,6 @@ RSpec.describe PrometheusAdapter, :use_clean_rails_memory_store_caching do
end
end
end
-
- describe 'additional_metrics' do
- let(:additional_metrics_environment_query) { Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery }
- let(:environment) { build_stubbed(:environment, slug: 'env-slug') }
- let(:time_window) { [1552642245.067, 1552642095.831] }
-
- around do |example|
- freeze_time { example.run }
- end
-
- context 'with valid data' do
- subject { integration.query(:additional_metrics_environment, environment, *time_window) }
-
- before do
- stub_reactive_cache(integration, prometheus_data, additional_metrics_environment_query, environment.id, *time_window)
- end
-
- it 'returns reactive data' do
- expect(subject).to eq(prometheus_data)
- end
- end
- end
end
describe '#calculate_reactive_cache' do
diff --git a/spec/models/concerns/require_email_verification_spec.rb b/spec/models/concerns/require_email_verification_spec.rb
index 1fb54e4276f..63312d4e1f1 100644
--- a/spec/models/concerns/require_email_verification_spec.rb
+++ b/spec/models/concerns/require_email_verification_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe RequireEmailVerification, feature_category: :insider_threat do
context 'when failed_attempts is LT overridden amount' do
before do
- instance.failed_attempts = 5
+ instance.failed_attempts = 2
end
it { is_expected.to eq(false) }
diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb
index 1423b56fa5d..e83a3d3417e 100644
--- a/spec/models/concerns/resolvable_discussion_spec.rb
+++ b/spec/models/concerns/resolvable_discussion_spec.rb
@@ -446,8 +446,8 @@ RSpec.describe Discussion, ResolvableDiscussion, feature_category: :code_review_
expect(subject.resolved?).to be true
end
- it "expires the etag cache of the noteable" do
- expect(subject.noteable).to receive(:expire_note_etag_cache)
+ it "broadcasts note change of the noteable" do
+ expect(subject.noteable).to receive(:broadcast_notes_changed)
subject.resolve!(current_user)
end
@@ -532,8 +532,8 @@ RSpec.describe Discussion, ResolvableDiscussion, feature_category: :code_review_
expect(subject.resolved?).to be false
end
- it "expires the etag cache of the noteable" do
- expect(subject.noteable).to receive(:expire_note_etag_cache)
+ it "broadcasts note change of the noteable" do
+ expect(subject.noteable).to receive(:broadcast_notes_changed)
subject.unresolve!
end
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index 0bbe3dea812..2b6f8535743 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -3,24 +3,20 @@
require 'spec_helper'
RSpec.shared_examples 'routable resource' do
- describe '.find_by_full_path', :aggregate_failures do
+ shared_examples_for '.find_by_full_path' do
it 'finds records by their full path' do
expect(described_class.find_by_full_path(record.full_path)).to eq(record)
expect(described_class.find_by_full_path(record.full_path.upcase)).to eq(record)
end
- it 'returns nil for unknown paths' do
- expect(described_class.find_by_full_path('unknown')).to be_nil
- end
+ it 'checks if `optimize_routable` is enabled only once' do
+ expect(Routable).to receive(:optimize_routable_enabled?).once
- it 'includes route information when loading a record' do
- control_count = ActiveRecord::QueryRecorder.new do
- described_class.find_by_full_path(record.full_path)
- end.count
+ described_class.find_by_full_path(record.full_path)
+ end
- expect do
- described_class.find_by_full_path(record.full_path).route
- end.not_to exceed_all_query_limit(control_count)
+ it 'returns nil for unknown paths' do
+ expect(described_class.find_by_full_path('unknown')).to be_nil
end
context 'when path is a negative number' do
@@ -56,6 +52,26 @@ RSpec.shared_examples 'routable resource' do
end
end
end
+
+ it_behaves_like '.find_by_full_path', :aggregate_failures
+
+ context 'when the `optimize_routable` feature flag is turned OFF' do
+ before do
+ stub_feature_flags(optimize_routable: false)
+ end
+
+ it_behaves_like '.find_by_full_path', :aggregate_failures
+
+ it 'includes route information when loading a record' do
+ control_count = ActiveRecord::QueryRecorder.new do
+ described_class.find_by_full_path(record.full_path)
+ end.count
+
+ expect do
+ described_class.find_by_full_path(record.full_path).route
+ end.not_to exceed_all_query_limit(control_count)
+ end
+ end
end
RSpec.shared_examples 'routable resource with parent' do
@@ -93,7 +109,7 @@ RSpec.shared_examples 'routable resource with parent' do
end
end
-RSpec.describe Group, 'Routable', :with_clean_rails_cache do
+RSpec.describe Group, 'Routable', :with_clean_rails_cache, feature_category: :groups_and_projects do
let_it_be_with_reload(:group) { create(:group, name: 'foo') }
let_it_be(:nested_group) { create(:group, parent: group) }
@@ -223,7 +239,7 @@ RSpec.describe Group, 'Routable', :with_clean_rails_cache do
end
end
-RSpec.describe Project, 'Routable', :with_clean_rails_cache do
+RSpec.describe Project, 'Routable', :with_clean_rails_cache, feature_category: :groups_and_projects do
let_it_be(:namespace) { create(:namespace) }
let_it_be(:project) { create(:project, namespace: namespace) }
@@ -235,9 +251,20 @@ RSpec.describe Project, 'Routable', :with_clean_rails_cache do
expect(project.route).not_to be_nil
expect(project.route.namespace).to eq(project.project_namespace)
end
+
+ describe '.find_by_full_path' do
+ it 'does not return a record if the sources are different, but the IDs match' do
+ group = create(:group, id: 1992)
+ project = create(:project, id: 1992)
+
+ record = described_class.where(id: project.id).find_by_full_path(group.full_path)
+
+ expect(record).to be_nil
+ end
+ end
end
-RSpec.describe Namespaces::ProjectNamespace, 'Routable', :with_clean_rails_cache do
+RSpec.describe Namespaces::ProjectNamespace, 'Routable', :with_clean_rails_cache, feature_category: :groups_and_projects do
let_it_be(:group) { create(:group) }
it 'skips route creation for the resource' do
@@ -247,6 +274,22 @@ RSpec.describe Namespaces::ProjectNamespace, 'Routable', :with_clean_rails_cache
end
end
+RSpec.describe Routable, feature_category: :groups_and_projects do
+ describe '.optimize_routable_enabled?' do
+ subject { described_class.optimize_routable_enabled? }
+
+ it { is_expected.to eq(true) }
+
+ context 'when the `optimize_routable` feature flag is turned OFF' do
+ before do
+ stub_feature_flags(optimize_routable: false)
+ end
+
+ it { is_expected.to eq(false) }
+ end
+ end
+end
+
def forcibly_hit_cached_lookup(record, method)
stub_feature_flags(cached_route_lookups: true)
expect(record).to receive(:persisted?).and_return(true)
diff --git a/spec/models/concerns/transitionable_spec.rb b/spec/models/concerns/transitionable_spec.rb
new file mode 100644
index 00000000000..b80d363ef78
--- /dev/null
+++ b/spec/models/concerns/transitionable_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Transitionable, feature_category: :code_review_workflow do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:klass) do
+ Class.new do
+ include Transitionable
+
+ def initialize(transitioning)
+ @transitioning = transitioning
+ end
+
+ def project
+ Project.new
+ end
+ end
+ end
+
+ let(:object) { klass.new(transitioning) }
+
+ describe '#transitioning?' do
+ where(:transitioning, :feature_flag, :result) do
+ true | true | true
+ false | false | false
+ true | false | false
+ false | true | false
+ end
+
+ with_them do
+ before do
+ stub_feature_flags(skip_validations_during_transitions: feature_flag)
+ end
+
+ it { expect(object.transitioning?).to eq(result) }
+ end
+ end
+end
diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb
index 528b36babc6..2959556f5ae 100644
--- a/spec/models/deploy_key_spec.rb
+++ b/spec/models/deploy_key_spec.rb
@@ -67,7 +67,7 @@ RSpec.describe DeployKey, :mailer do
context 'when user is not set' do
it 'returns the ghost user' do
- expect(deploy_key.user).to eq(User.ghost)
+ expect(deploy_key.user).to eq(Users::Internal.ghost)
end
end
end
diff --git a/spec/models/design_management/design_spec.rb b/spec/models/design_management/design_spec.rb
index 72c0d1d1a64..98e5399f737 100644
--- a/spec/models/design_management/design_spec.rb
+++ b/spec/models/design_management/design_spec.rb
@@ -467,16 +467,6 @@ RSpec.describe DesignManagement::Design, feature_category: :design_management do
end
end
- describe '#note_etag_key' do
- it 'returns a correct etag key' do
- design = design1
-
- expect(design.note_etag_key).to eq(
- ::Gitlab::Routing.url_helpers.designs_project_issue_path(design.project, design.issue, { vueroute: design.filename })
- )
- end
- end
-
describe '#user_notes_count', :use_clean_rails_memory_store_caching do
# Note: Cache invalidation tests are in `design_user_notes_count_service_spec.rb`
it 'returns a count of user-generated notes' do
diff --git a/spec/models/doorkeeper/application_spec.rb b/spec/models/doorkeeper/application_spec.rb
new file mode 100644
index 00000000000..85b28346dfa
--- /dev/null
+++ b/spec/models/doorkeeper/application_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Doorkeeper::Application, type: :model, feature_category: :system_access do
+ let(:application) { create(:oauth_application) }
+
+ it 'uses a prefixed secret' do
+ expect(application.plaintext_secret).to match(/gloas-\h{64}/)
+ end
+end
diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb
index 9814eed8b45..eeb8583251d 100644
--- a/spec/models/environment_status_spec.rb
+++ b/spec/models/environment_status_spec.rb
@@ -270,18 +270,6 @@ RSpec.describe EnvironmentStatus do
context 'when environment is stopped' do
before do
- stub_feature_flags(review_apps_redeploy_mr_widget: false)
- environment.stop!
- end
-
- it 'does not return environment status' do
- expect(subject.count).to eq(0)
- end
- end
-
- context 'when environment is stopped and review_apps_redeploy_mr_widget is turned on' do
- before do
- stub_feature_flags(review_apps_redeploy_mr_widget: true)
environment.stop!
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 23e72f6663a..3f671fc3f70 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -2666,14 +2666,16 @@ RSpec.describe Group, feature_category: :groups_and_projects do
let(:group) { build(:group) }
context 'the group has owners' do
- before do
- group.add_owner(create(:user))
- group.add_owner(create(:user))
- end
-
it 'is the first owner' do
+ user_1 = create(:user)
+ user_2 = create(:user)
+ group.add_owner(user_2)
+ group.add_owner(user_1)
+
+ # The senior-most user (not member) who is an OWNER in the group
+ # is always treated as the first owner
expect(group.first_owner)
- .to eq(group.owners.first)
+ .to eq(user_1)
.and be_a(User)
end
end
@@ -3307,6 +3309,13 @@ RSpec.describe Group, feature_category: :groups_and_projects do
end
end
+ describe '#supports_lock_on_merge?' do
+ it_behaves_like 'checks self and root ancestor feature flag' do
+ let(:feature_flag) { :enforce_locked_labels_on_merge }
+ let(:feature_flag_method) { :supports_lock_on_merge? }
+ end
+ end
+
describe 'group shares' do
let!(:sub_group) { create(:group, parent: group) }
let!(:sub_sub_group) { create(:group, parent: sub_group) }
diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb
index 4b88b3b3e65..e9a2635bf28 100644
--- a/spec/models/hooks/web_hook_log_spec.rb
+++ b/spec/models/hooks/web_hook_log_spec.rb
@@ -46,6 +46,20 @@ RSpec.describe WebHookLog, feature_category: :webhooks do
end
end
+ context 'with basic auth credentials and masked components' do
+ let(:web_hook_log) { build(:web_hook_log, web_hook: hook, url: 'http://test:123@{domain}.com:{port}') }
+
+ subject { web_hook_log.save! }
+
+ it { is_expected.to eq(true) }
+
+ it 'obfuscates the basic auth credentials' do
+ subject
+
+ expect(web_hook_log.url).to eq('http://*****:*****@{domain}.com:{port}')
+ end
+ end
+
context "with users' emails" do
let(:author) { build(:user) }
let(:user) { build(:user) }
@@ -235,4 +249,28 @@ RSpec.describe WebHookLog, feature_category: :webhooks do
it { expect(web_hook_log.request_headers).to eq(expected_headers) }
end
end
+
+ describe '#url_current?' do
+ let(:url) { 'example@gitlab.com' }
+
+ let(:hook) { build(:project_hook, url: url) }
+ let(:web_hook_log) do
+ build(
+ :web_hook_log,
+ web_hook: hook,
+ interpolated_url: hook.url,
+ url_hash: Gitlab::CryptoHelper.sha256('example@gitlab.com')
+ )
+ end
+
+ context 'with matching url' do
+ it { expect(web_hook_log.url_current?).to be_truthy }
+ end
+
+ context 'with different url' do
+ let(:url) { 'example@gitlab2.com' }
+
+ it { expect(web_hook_log.url_current?).to be_falsey }
+ end
+ end
end
diff --git a/spec/models/integration_spec.rb b/spec/models/integration_spec.rb
index 0b41b46ae3d..67e12092e1a 100644
--- a/spec/models/integration_spec.rb
+++ b/spec/models/integration_spec.rb
@@ -1041,9 +1041,9 @@ RSpec.describe Integration, feature_category: :integrations do
it 'returns all fields with type `password`' do
allow(subject).to receive(:fields).and_return(
[
- { name: 'password', type: :password },
- { name: 'secret', type: :password },
- { name: 'public', type: :text }
+ Integrations::Field.new(name: 'password', integration_class: subject.class, type: :password),
+ Integrations::Field.new(name: 'secret', integration_class: subject.class, type: :password),
+ Integrations::Field.new(name: 'public', integration_class: subject.class, type: :text)
])
expect(subject.secret_fields).to match_array(%w[password secret])
diff --git a/spec/models/integrations/base_chat_notification_spec.rb b/spec/models/integrations/base_chat_notification_spec.rb
index 675035095c5..497f2f1e7c9 100644
--- a/spec/models/integrations/base_chat_notification_spec.rb
+++ b/spec/models/integrations/base_chat_notification_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe Integrations::BaseChatNotification, feature_category: :integratio
context 'when webhook is not required' do
it 'returns true' do
- allow(chat_integration).to receive(:requires_webhook?).and_return(false)
+ allow(chat_integration.class).to receive(:requires_webhook?).and_return(false)
expect(chat_integration).to receive(:notify).and_return(true)
expect(chat_integration.execute(data)).to be true
@@ -347,6 +347,12 @@ RSpec.describe Integrations::BaseChatNotification, feature_category: :integratio
end
end
+ describe '#help' do
+ it 'raises an error' do
+ expect { subject.help }.to raise_error(NotImplementedError)
+ end
+ end
+
describe '#event_channel_name' do
it 'returns the channel field name for the given event' do
expect(subject.event_channel_name(:event)).to eq('event_channel')
@@ -364,4 +370,17 @@ RSpec.describe Integrations::BaseChatNotification, feature_category: :integratio
expect { subject.event_channel_value(:foo) }.to raise_error(NoMethodError)
end
end
+
+ describe '#api_field_names' do
+ context 'when channels are masked' do
+ let(:project) { build(:project) }
+ let(:integration) { build(:discord_integration, project: project, webhook: 'https://discord.com/api/') }
+
+ it 'does not include channel properties', :aggregate_failures do
+ integration.event_channel_names.each do |field|
+ expect(integration.api_field_names).not_to include(field)
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/integrations/chat_message/deployment_message_spec.rb b/spec/models/integrations/chat_message/deployment_message_spec.rb
index d16c191bd08..630ae902331 100644
--- a/spec/models/integrations/chat_message/deployment_message_spec.rb
+++ b/spec/models/integrations/chat_message/deployment_message_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::ChatMessage::DeploymentMessage do
+RSpec.describe Integrations::ChatMessage::DeploymentMessage, feature_category: :integrations do
subject { described_class.new(args) }
let_it_be(:user) { create(:user, name: 'John Smith', username: 'smith') }
@@ -103,15 +103,33 @@ RSpec.describe Integrations::ChatMessage::DeploymentMessage do
}.merge(params)
end
- it 'returns attachments with the data returned by the deployment data builder' do
- job_url = Gitlab::Routing.url_helpers.project_job_url(project, ci_build)
- commit_url = Gitlab::UrlBuilder.build(deployment.commit)
- user_url = Gitlab::Routing.url_helpers.user_url(user)
+ context 'without markdown' do
+ it 'returns attachments with the data returned by the deployment data builder' do
+ job_url = Gitlab::Routing.url_helpers.project_job_url(project, ci_build)
+ commit_url = Gitlab::UrlBuilder.build(deployment.commit)
+ user_url = Gitlab::Routing.url_helpers.user_url(user)
+
+ expect(subject.attachments).to eq([{
+ text: "<#{project.web_url}|myspace/myproject> with job <#{job_url}|##{ci_build.id}> by <#{user_url}|John Smith (smith)>\n<#{commit_url}|#{deployment.short_sha}>: #{commit.title}",
+ color: "good"
+ }])
+ end
+ end
- expect(subject.attachments).to eq([{
- text: "[myspace/myproject](#{project.web_url}) with job [##{ci_build.id}](#{job_url}) by [John Smith (smith)](#{user_url})\n[#{deployment.short_sha}](#{commit_url}): #{commit.title}",
- color: "good"
- }])
+ context 'with markdown' do
+ before do
+ args.merge!(markdown: true)
+ end
+
+ it 'returns attachments with the data returned by the deployment data builder' do
+ job_url = Gitlab::Routing.url_helpers.project_job_url(project, ci_build)
+ commit_url = Gitlab::UrlBuilder.build(deployment.commit)
+ user_url = Gitlab::Routing.url_helpers.user_url(user)
+
+ expect(subject.attachments).to eq(
+ "[myspace/myproject](#{project.web_url}) with job [##{ci_build.id}](#{job_url}) by [John Smith (smith)](#{user_url})\n[#{deployment.short_sha}](#{commit_url}): #{commit.title}"
+ )
+ end
end
it 'returns attachments for a failed deployment' do
diff --git a/spec/models/integrations/confluence_spec.rb b/spec/models/integrations/confluence_spec.rb
index d267e4a71c2..a34b55c3c6b 100644
--- a/spec/models/integrations/confluence_spec.rb
+++ b/spec/models/integrations/confluence_spec.rb
@@ -63,6 +63,12 @@ RSpec.describe Integrations::Confluence, feature_category: :integrations do
end
end
+ describe '#avatar_url' do
+ it 'returns the avatar image path' do
+ expect(subject.avatar_url).to eq(ActionController::Base.helpers.image_path('confluence.svg'))
+ end
+ end
+
describe 'Caching has_confluence on project_settings' do
subject { project.project_setting.has_confluence? }
diff --git a/spec/models/integrations/mattermost_spec.rb b/spec/models/integrations/mattermost_spec.rb
index f7702846b6c..224bc4acdda 100644
--- a/spec/models/integrations/mattermost_spec.rb
+++ b/spec/models/integrations/mattermost_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe Integrations::Mattermost do
+RSpec.describe Integrations::Mattermost, feature_category: :integrations do
it_behaves_like Integrations::SlackMattermostNotifier, "Mattermost"
end
diff --git a/spec/models/integrations/prometheus_spec.rb b/spec/models/integrations/prometheus_spec.rb
index da43d851b31..4a998efe665 100644
--- a/spec/models/integrations/prometheus_spec.rb
+++ b/spec/models/integrations/prometheus_spec.rb
@@ -422,6 +422,34 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
end
end
+ describe '#sync_http_integration after_save callback' do
+ context 'with corresponding HTTP integration' do
+ let_it_be_with_reload(:http_integration) { create(:alert_management_prometheus_integration, :legacy, project: project) }
+
+ it 'syncs the attribute' do
+ expect { integration.update!(manual_configuration: false) }
+ .to change { http_integration.reload.active }
+ .from(true).to(false)
+ end
+
+ context 'when changing a different attribute' do
+ it 'does not sync the attribute or execute extra queries' do
+ expect { integration.update!(api_url: 'https://any.url') }
+ .to issue_fewer_queries_than { integration.update!(manual_configuration: false) }
+ end
+ end
+ end
+
+ context 'without corresponding HTTP integration' do
+ let_it_be(:other_http_integration) { create(:alert_management_prometheus_integration, project: project) }
+
+ it 'does not sync the attribute or execute extra queries' do
+ expect { integration.update!(manual_configuration: false) }
+ .not_to change { other_http_integration.reload.active }
+ end
+ end
+ end
+
describe '#editable?' do
it 'is editable' do
expect(integration.editable?).to be(true)
diff --git a/spec/models/integrations/shimo_spec.rb b/spec/models/integrations/shimo_spec.rb
index be626012ab2..95289343d0d 100644
--- a/spec/models/integrations/shimo_spec.rb
+++ b/spec/models/integrations/shimo_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Integrations::Shimo do
+RSpec.describe ::Integrations::Shimo, feature_category: :integrations do
describe '#fields' do
let(:shimo_integration) { build(:shimo_integration) }
@@ -60,4 +60,10 @@ RSpec.describe ::Integrations::Shimo do
expect { create(:shimo_integration) }.to change(ProjectSetting, :count).by(1)
end
end
+
+ describe '#avatar_url' do
+ it 'returns the avatar image path' do
+ expect(subject.avatar_url).to eq(ActionController::Base.helpers.image_path('logos/shimo.svg'))
+ end
+ end
end
diff --git a/spec/models/integrations/slack_spec.rb b/spec/models/integrations/slack_spec.rb
index 218d92ffe05..59ee3746d8f 100644
--- a/spec/models/integrations/slack_spec.rb
+++ b/spec/models/integrations/slack_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::Slack do
+RSpec.describe Integrations::Slack, feature_category: :integrations do
it_behaves_like Integrations::SlackMattermostNotifier, 'Slack'
it_behaves_like Integrations::BaseSlackNotification, factory: :integrations_slack do
before do
diff --git a/spec/models/integrations/zentao_spec.rb b/spec/models/integrations/zentao_spec.rb
index 2fa4df0e900..460ce7629cc 100644
--- a/spec/models/integrations/zentao_spec.rb
+++ b/spec/models/integrations/zentao_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Integrations::Zentao do
+RSpec.describe Integrations::Zentao, feature_category: :integrations do
let(:url) { 'https://jihudemo.zentao.net' }
let(:api_url) { 'https://jihudemo.zentao.net' }
let(:api_token) { 'ZENTAO_TOKEN' }
@@ -80,6 +80,12 @@ RSpec.describe Integrations::Zentao do
end
end
+ describe '#avatar_url' do
+ it 'returns the avatar image path' do
+ expect(subject.avatar_url).to eq(ActionController::Base.helpers.image_path('logos/zentao.svg'))
+ end
+ end
+
describe '#client_url' do
subject(:integration) { build(:zentao_integration, api_url: api_url, url: 'url').client_url }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 9db710cb3cc..4e217e3a9f7 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -28,7 +28,6 @@ RSpec.describe Issue, feature_category: :team_planning do
it { is_expected.to have_many(:resource_milestone_events) }
it { is_expected.to have_many(:resource_state_events) }
it { is_expected.to have_and_belong_to_many(:prometheus_alert_events) }
- it { is_expected.to have_and_belong_to_many(:self_managed_prometheus_alert_events) }
it { is_expected.to have_many(:prometheus_alerts) }
it { is_expected.to have_many(:issue_email_participants) }
it { is_expected.to have_one(:email) }
@@ -953,7 +952,7 @@ RSpec.describe Issue, feature_category: :team_planning do
subject { issue.from_service_desk? }
context 'when issue author is support bot' do
- let(:issue) { create(:issue, project: reusable_project, author: ::User.support_bot) }
+ let(:issue) { create(:issue, project: reusable_project, author: ::Users::Internal.support_bot) }
it { is_expected.to be_truthy }
end
@@ -1527,7 +1526,7 @@ RSpec.describe Issue, feature_category: :team_planning do
end
describe '#check_for_spam?' do
- let_it_be(:support_bot) { ::User.support_bot }
+ let_it_be(:support_bot) { ::Users::Internal.support_bot }
where(:support_bot?, :visibility_level, :confidential, :new_attributes, :check_for_spam?) do
### non-support-bot cases
@@ -1640,7 +1639,7 @@ RSpec.describe Issue, feature_category: :team_planning do
describe '.service_desk' do
it 'returns the service desk issue' do
- service_desk_issue = create(:issue, project: reusable_project, author: ::User.support_bot)
+ service_desk_issue = create(:issue, project: reusable_project, author: ::Users::Internal.support_bot)
regular_issue = create(:issue, project: reusable_project)
expect(described_class.service_desk).to include(service_desk_issue)
diff --git a/spec/models/loose_foreign_keys/modification_tracker_spec.rb b/spec/models/loose_foreign_keys/modification_tracker_spec.rb
index 069ccf85141..afc62f28f92 100644
--- a/spec/models/loose_foreign_keys/modification_tracker_spec.rb
+++ b/spec/models/loose_foreign_keys/modification_tracker_spec.rb
@@ -2,12 +2,12 @@
require 'spec_helper'
-RSpec.describe LooseForeignKeys::ModificationTracker do
+RSpec.describe LooseForeignKeys::ModificationTracker, feature_category: :database do
subject(:tracker) { described_class.new }
describe '#over_limit?' do
- it 'is true when deletion MAX_DELETES is exceeded' do
- stub_const('LooseForeignKeys::ModificationTracker::MAX_DELETES', 5)
+ it 'is true when deletion max_deletes is exceeded' do
+ expect(tracker).to receive(:max_deletes).and_return(5)
tracker.add_deletions('issues', 10)
expect(tracker).to be_over_limit
@@ -20,7 +20,7 @@ RSpec.describe LooseForeignKeys::ModificationTracker do
end
it 'is true when deletion MAX_UPDATES is exceeded' do
- stub_const('LooseForeignKeys::ModificationTracker::MAX_UPDATES', 5)
+ expect(tracker).to receive(:max_updates).and_return(5)
tracker.add_updates('issues', 3)
tracker.add_updates('issues', 4)
@@ -36,9 +36,11 @@ RSpec.describe LooseForeignKeys::ModificationTracker do
it 'is true when max runtime is exceeded' do
monotonic_time_before = 1 # this will be the start time
- monotonic_time_after = described_class::MAX_RUNTIME.to_i + 1 # this will be returned when over_limit? is called
+ monotonic_time_after = 31 # this will be returned when over_limit? is called
- allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(monotonic_time_before, monotonic_time_after)
+ expect(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(
+ monotonic_time_before, monotonic_time_after
+ )
tracker
diff --git a/spec/models/loose_foreign_keys/turbo_modification_tracker_spec.rb b/spec/models/loose_foreign_keys/turbo_modification_tracker_spec.rb
new file mode 100644
index 00000000000..0916a0845f5
--- /dev/null
+++ b/spec/models/loose_foreign_keys/turbo_modification_tracker_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe LooseForeignKeys::TurboModificationTracker, feature_category: :database do
+ subject(:tracker) { described_class.new }
+
+ let(:normal_tracker) { LooseForeignKeys::ModificationTracker.new }
+
+ context 'with limits should be higher than LooseForeignKeys::ModificationTracker' do
+ it 'expect max_deletes to be equal or higher' do
+ expect(tracker.max_deletes).to be >= normal_tracker.max_deletes
+ end
+
+ it 'expect max_updates to be equal or higher' do
+ expect(tracker.max_updates).to be >= normal_tracker.max_updates
+ end
+
+ it 'expect max_runtime to be equal or higher' do
+ expect(tracker.max_runtime).to be >= normal_tracker.max_runtime
+ end
+ end
+end
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index f8aaae3edad..6dd5f9dec8c 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -1177,4 +1177,11 @@ RSpec.describe Member, feature_category: :groups_and_projects do
expect(described_class.sort_by_attribute('oldest_last_activity')).to eq([member3, member2, member1])
end
end
+
+ context 'with loose foreign key on members.user_id' do
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let!(:parent) { create(:user) }
+ let!(:model) { create(:group_member, user: parent) }
+ end
+ end
end
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index a07829abece..7307e76272d 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -69,7 +69,7 @@ RSpec.describe GroupMember, feature_category: :cell do
describe '#update_two_factor_requirement' do
it 'is called after creation and deletion' do
- user = build :user
+ user = create :user
group = create :group
group_member = build :group_member, user: user, group: group
@@ -288,4 +288,18 @@ RSpec.describe GroupMember, feature_category: :cell do
it_behaves_like 'calls AuthorizedProjectsWorker inline to recalculate authorizations'
end
end
+
+ context 'group member welcome email', :sidekiq_inline, :saas do
+ let_it_be(:group) { create(:group) }
+
+ let(:user) { create(:user) }
+
+ it 'schedules plain welcome to the group email' do
+ expect_next_instance_of(NotificationService) do |notification|
+ expect(notification).to receive(:new_group_member)
+ end
+
+ group.add_developer(user)
+ end
+ end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index da3f691b63a..b36737fc19d 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -135,10 +135,22 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
let_it_be(:user1) { create(:user) }
let_it_be(:user2) { create(:user) }
- let_it_be(:merge_request1) { create(:merge_request, :unique_branches, reviewers: [user1]) }
- let_it_be(:merge_request2) { create(:merge_request, :unique_branches, reviewers: [user2]) }
- let_it_be(:merge_request3) { create(:merge_request, :unique_branches, reviewers: []) }
- let_it_be(:merge_request4) { create(:merge_request, :draft_merge_request) }
+ let_it_be(:merge_request1) do
+ create(:merge_request, :prepared, :unique_branches, reviewers: [user1], created_at:
+ 2.days.ago)
+ end
+
+ let_it_be(:merge_request2) do
+ create(:merge_request, :unprepared, :unique_branches, reviewers: [user2], created_at:
+ 3.hours.ago)
+ end
+
+ let_it_be(:merge_request3) do
+ create(:merge_request, :unprepared, :unique_branches, reviewers: [], created_at:
+ Time.current)
+ end
+
+ let_it_be(:merge_request4) { create(:merge_request, :prepared, :draft_merge_request) }
describe '.preload_target_project_with_namespace' do
subject(:mr) { described_class.preload_target_project_with_namespace.first }
@@ -180,6 +192,14 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
end
end
+ describe '.recently_unprepared' do
+ it 'only returns the recently unprepared mrs' do
+ merge_request5 = create(:merge_request, :unprepared, :unique_branches, created_at: merge_request3.created_at)
+
+ expect(described_class.recently_unprepared).to eq([merge_request3, merge_request5])
+ end
+ end
+
describe '.by_sorted_source_branches' do
let(:fork_for_project) { fork_project(project) }
@@ -340,6 +360,23 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
end
end
+ describe "#validate_reviewer_size_length" do
+ let(:merge_request) { build(:merge_request, transitioning: transitioning) }
+
+ where(:transitioning, :to_or_not_to) do
+ false | :to
+ true | :not_to
+ end
+
+ with_them do
+ it do
+ expect(merge_request).send(to_or_not_to, receive(:validate_reviewer_size_length))
+
+ merge_request.valid?
+ end
+ end
+ end
+
describe '#validate_target_project' do
let(:merge_request) do
build(:merge_request, source_project: project, target_project: project, importing: importing)
@@ -366,6 +403,23 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
it { expect(merge_request.valid?(false)).to eq true }
end
end
+
+ context "with the skip_validations_during_transition_feature_flag" do
+ let(:merge_request) { build(:merge_request, transitioning: transitioning) }
+
+ where(:transitioning, :to_or_not_to) do
+ false | :to
+ true | :not_to
+ end
+
+ with_them do
+ it do
+ expect(merge_request).send(to_or_not_to, receive(:validate_target_project))
+
+ merge_request.valid?
+ end
+ end
+ end
end
end
@@ -2099,6 +2153,16 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
subject.mark_as_merged!
end
+ context 'and merged_commit_sha is present' do
+ before do
+ subject.update_attribute(:merged_commit_sha, pipeline.sha)
+ end
+
+ it 'returns the pipeline associated with that merge request' do
+ expect(subject.merge_pipeline).to eq(pipeline)
+ end
+ end
+
context 'and there is a merge commit' do
before do
subject.update_attribute(:merge_commit_sha, pipeline.sha)
@@ -2850,6 +2914,12 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
subject.mark_as_merged!
end
+ it 'returns merged_commit_sha when there is a merged_commit_sha' do
+ subject.update_attribute(:merged_commit_sha, sha)
+
+ expect(subject.merged_commit_sha).to eq(sha)
+ end
+
it 'returns merge_commit_sha when there is a merge_commit_sha' do
subject.update_attribute(:merge_commit_sha, sha)
@@ -3275,6 +3345,31 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
subject.mergeable?(check_mergeability_retry_lease: true)
end
end
+
+ context 'with skip_rebase_check option' do
+ before do
+ allow(subject).to receive_messages(
+ mergeable_state?: true,
+ check_mergeability: nil,
+ can_be_merged?: true
+ )
+ end
+
+ where(:should_be_rebased, :skip_rebase_check, :expected_mergeable) do
+ false | false | true
+ false | true | true
+ true | false | false
+ true | true | true
+ end
+
+ with_them do
+ it 'overrides should_be_rebased?' do
+ allow(subject).to receive(:should_be_rebased?) { should_be_rebased }
+
+ expect(subject.mergeable?(skip_rebase_check: skip_rebase_check)).to eq(expected_mergeable)
+ end
+ end
+ end
end
describe '#skipped_mergeable_checks' do
@@ -4442,6 +4537,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
shared_examples 'for an invalid state transition' do
specify 'is not a valid state transition' do
expect { transition! }.to raise_error(StateMachines::InvalidTransition)
+ expect(subject.transitioning?).to be_falsey
end
end
@@ -4451,6 +4547,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
.to change { subject.merge_status }
.from(merge_status.to_s)
.to(expected_merge_status)
+ expect(subject.transitioning?).to be_falsey
end
end
@@ -5493,7 +5590,8 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
let(:ref) { subject.target_project.repository.commit.id }
before do
- expect(subject.target_project).to receive(:mark_primary_write_location)
+ expect(subject.target_project.sticking).to receive(:stick)
+ .with(:project, subject.target_project.id)
end
it 'updates commit ID' do
@@ -5806,4 +5904,56 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
it { is_expected.to eq(false) }
end
end
+
+ describe '#supports_lock_on_merge?' do
+ let(:merge_request) { build_stubbed(:merge_request) }
+
+ subject { merge_request.supports_lock_on_merge? }
+
+ context 'when MR is open' do
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when MR is merged' do
+ before do
+ merge_request.state = :merged
+ end
+
+ it { is_expected.to eq(true) }
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: false)
+ end
+
+ it { is_expected.to eq(false) }
+ end
+ end
+ end
+
+ describe '#missing_required_squash?' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:squash, :project_requires_squash, :expected) do
+ false | true | true
+ false | false | false
+ true | true | false
+ true | false | false
+ end
+
+ with_them do
+ let(:merge_request) { build_stubbed(:merge_request, squash: squash) }
+
+ subject { merge_request.missing_required_squash? }
+
+ before do
+ allow(merge_request.target_project).to(
+ receive(:squash_always?)
+ .and_return(project_requires_squash)
+ )
+ end
+
+ it { is_expected.to eq(expected) }
+ end
+ end
end
diff --git a/spec/models/metrics/dashboard/annotation_spec.rb b/spec/models/metrics/dashboard/annotation_spec.rb
deleted file mode 100644
index 7c4f392fcdc..00000000000
--- a/spec/models/metrics/dashboard/annotation_spec.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Metrics::Dashboard::Annotation do
- using RSpec::Parameterized::TableSyntax
-
- describe 'validation' do
- it { is_expected.to validate_presence_of(:description) }
- it { is_expected.to validate_presence_of(:dashboard_path) }
- it { is_expected.to validate_presence_of(:starting_at) }
- it { is_expected.to validate_length_of(:dashboard_path).is_at_most(255) }
- it { is_expected.to validate_length_of(:panel_xid).is_at_most(255) }
- it { is_expected.to validate_length_of(:description).is_at_most(255) }
-
- context 'ending_at_after_starting_at' do
- where(:starting_at, :ending_at, :valid?, :message) do
- 2.days.ago.beginning_of_day | 1.day.ago.beginning_of_day | true | nil
- 1.day.ago.beginning_of_day | nil | true | nil
- 1.day.ago.beginning_of_day | 1.day.ago.beginning_of_day | true | nil
- 1.day.ago.beginning_of_day | 2.days.ago.beginning_of_day | false | /Ending at can't be before starting_at time/
- nil | 2.days.ago.beginning_of_day | false | /Starting at can't be blank/ # validation is covered by other method, be we need to assure, that ending_at_after_starting_at will not break with nil as starting_at
- nil | nil | false | /Starting at can't be blank/ # validation is covered by other method, be we need to assure, that ending_at_after_starting_at will not break with nil as starting_at
- end
-
- with_them do
- subject(:annotation) { build(:metrics_dashboard_annotation, starting_at: starting_at, ending_at: ending_at) }
-
- it do
- expect(annotation.valid?).to be(valid?)
- expect(annotation.errors.full_messages).to include(message) if message
- end
- end
- end
- end
-
- describe 'scopes' do
- let_it_be(:nine_minutes_old_annotation) { create(:metrics_dashboard_annotation, starting_at: 9.minutes.ago) }
- let_it_be(:fifteen_minutes_old_annotation) { create(:metrics_dashboard_annotation, starting_at: 15.minutes.ago) }
- let_it_be(:just_created_annotation) { create(:metrics_dashboard_annotation) }
-
- describe '#after' do
- it 'returns only younger annotations' do
- expect(described_class.after(12.minutes.ago)).to match_array [nine_minutes_old_annotation, just_created_annotation]
- end
- end
-
- describe '#before' do
- it 'returns only older annotations' do
- expect(described_class.before(5.minutes.ago)).to match_array [fifteen_minutes_old_annotation, nine_minutes_old_annotation]
- end
- end
-
- describe '#for_dashboard' do
- let!(:other_dashboard_annotation) { create(:metrics_dashboard_annotation, dashboard_path: 'other_dashboard.yml') }
-
- it 'returns annotations only for appointed dashboard' do
- expect(described_class.for_dashboard('other_dashboard.yml')).to match_array [other_dashboard_annotation]
- end
- end
-
- describe '#ending_before' do
- it 'returns annotations only for appointed dashboard' do
- freeze_time do
- twelve_minutes_old_annotation = create(:metrics_dashboard_annotation, starting_at: 15.minutes.ago, ending_at: 12.minutes.ago)
- create(:metrics_dashboard_annotation, starting_at: 15.minutes.ago, ending_at: 11.minutes.ago)
-
- expect(described_class.ending_before(11.minutes.ago)).to match_array [fifteen_minutes_old_annotation, twelve_minutes_old_annotation]
- end
- end
- end
- end
-end
diff --git a/spec/models/metrics/users_starred_dashboard_spec.rb b/spec/models/metrics/users_starred_dashboard_spec.rb
deleted file mode 100644
index c89344c0a1c..00000000000
--- a/spec/models/metrics/users_starred_dashboard_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Metrics::UsersStarredDashboard do
- describe 'associations' do
- it { is_expected.to belong_to(:project).inverse_of(:metrics_users_starred_dashboards) }
- it { is_expected.to belong_to(:user).inverse_of(:metrics_users_starred_dashboards) }
- end
-
- describe 'validation' do
- subject { build(:metrics_users_starred_dashboard) }
-
- it { is_expected.to validate_presence_of(:user_id) }
- it { is_expected.to validate_presence_of(:project_id) }
- it { is_expected.to validate_presence_of(:dashboard_path) }
- it { is_expected.to validate_length_of(:dashboard_path).is_at_most(255) }
- it { is_expected.to validate_uniqueness_of(:dashboard_path).scoped_to(%i[user_id project_id]) }
- end
-
- context 'scopes' do
- let_it_be(:project) { create(:project) }
- let_it_be(:starred_dashboard_a) { create(:metrics_users_starred_dashboard, project: project, dashboard_path: 'path_a') }
- let_it_be(:starred_dashboard_b) { create(:metrics_users_starred_dashboard, project: project, dashboard_path: 'path_b') }
- let_it_be(:starred_dashboard_c) { create(:metrics_users_starred_dashboard, dashboard_path: 'path_b') }
-
- describe '#for_project' do
- it 'selects only starred dashboards belonging to project' do
- expect(described_class.for_project(project)).to contain_exactly starred_dashboard_a, starred_dashboard_b
- end
- end
-
- describe '#for_project_dashboard' do
- it 'selects only starred dashboards belonging to project with given dashboard path' do
- expect(described_class.for_project_dashboard(project, 'path_b')).to contain_exactly starred_dashboard_b
- end
- end
- end
-end
diff --git a/spec/models/ml/model_version_spec.rb b/spec/models/ml/model_version_spec.rb
index 4bb272fef5d..83639fca9e1 100644
--- a/spec/models/ml/model_version_spec.rb
+++ b/spec/models/ml/model_version_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Ml::ModelVersion, feature_category: :mlops do
describe 'associations' do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:model) }
- it { is_expected.to belong_to(:package) }
+ it { is_expected.to belong_to(:package).class_name('Packages::MlModel::Package') }
end
describe 'validation' do
@@ -83,14 +83,6 @@ RSpec.describe Ml::ModelVersion, feature_category: :mlops do
it { expect(errors[:package]).to include(error_message) }
end
-
- context 'when package is not ml_model' do
- let(:package) do
- build_stubbed(:generic_package, project: base_project, name: model1.name, version: valid_version)
- end
-
- it { expect(errors[:package]).to include('package must be ml_model') }
- end
end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 623c9c7e07c..a0deee0f2d3 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -443,6 +443,15 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
end
end
+ describe '.by_root_id' do
+ it 'returns correct namespaces' do
+ expect(described_class.by_root_id(namespace1.id)).to match_array([namespace1, namespace1sub])
+ expect(described_class.by_root_id(namespace2.id)).to match_array([namespace2, namespace2sub])
+ expect(described_class.by_root_id(namespace1sub.id)).to be_empty
+ expect(described_class.by_root_id(nil)).to be_empty
+ end
+ end
+
describe '.filter_by_path' do
it 'includes correct namespaces' do
expect(described_class.filter_by_path(namespace1.path)).to eq([namespace1])
@@ -1070,17 +1079,30 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
end
it 'defaults use_minimum_char_limit to true' do
- expect(described_class).to receive(:fuzzy_search).with(anything, anything, use_minimum_char_limit: true).once
+ expect(described_class).to receive(:fuzzy_search).with(anything, anything, use_minimum_char_limit: true, exact_matches_first: false).once
described_class.search('my namespace')
end
it 'passes use_minimum_char_limit if it is set' do
- expect(described_class).to receive(:fuzzy_search).with(anything, anything, use_minimum_char_limit: false).once
+ expect(described_class).to receive(:fuzzy_search).with(anything, anything, use_minimum_char_limit: false, exact_matches_first: false).once
described_class.search('my namespace', use_minimum_char_limit: false)
end
+ context 'with multiple matching namespaces' do
+ let_it_be(:first_group) { create(:group, name: 'some name', path: 'z-path') }
+ let_it_be(:second_group) { create(:group, name: 'some name too', path: 'a-path') }
+
+ it 'returns exact matches first' do
+ expect(described_class.search('some name', exact_matches_first: true).to_a).to eq([first_group, second_group])
+ end
+
+ it 'returns exact matches first when parents are included' do
+ expect(described_class.search('some name', include_parents: true, exact_matches_first: true).to_a).to eq([first_group, second_group])
+ end
+ end
+
context 'with project namespaces' do
let_it_be(:project) { create(:project, namespace: parent_group, path: 'some-new-path') }
let_it_be(:project_namespace) { project.project_namespace }
@@ -1186,8 +1208,11 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
end
describe '#move_dir', :request_store do
- shared_examples "namespace restrictions" do
- context "when any project has container images" do
+ context 'hashed storage' do
+ let_it_be(:namespace) { create(:namespace) }
+ let_it_be(:project) { create(:project_empty_repo, namespace: namespace) }
+
+ context 'when any project has container images' do
let(:container_repository) { create(:container_repository) }
before do
@@ -1207,190 +1232,6 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
)
end
end
- end
-
- context 'legacy storage' do
- let(:namespace) { create(:namespace) }
- let!(:project) { create(:project_empty_repo, :legacy_storage, namespace: namespace) }
-
- it_behaves_like 'namespace restrictions'
-
- it "raises error when directory exists" do
- expect { namespace.move_dir }.to raise_error("namespace directory cannot be moved")
- end
-
- it "moves dir if path changed" do
- namespace.update!(path: namespace.full_path + '_new')
-
- expect(gitlab_shell.repository_exists?(project.repository_storage, "#{namespace.path}/#{project.path}.git")).to be_truthy
- end
-
- context 'when #write_projects_repository_config raises an error' do
- context 'in test environment' do
- it 'raises an exception' do
- expect(namespace).to receive(:write_projects_repository_config).and_raise('foo')
-
- expect do
- namespace.update!(path: namespace.full_path + '_new')
- end.to raise_error('foo')
- end
- end
-
- context 'in production environment' do
- it 'does not cancel later callbacks' do
- expect(namespace).to receive(:write_projects_repository_config).and_raise('foo')
- expect(namespace).to receive(:move_dir).and_wrap_original do |m, *args|
- move_dir_result = m.call(*args)
-
- expect(move_dir_result).to be_truthy # Must be truthy, or else later callbacks would be canceled
-
- move_dir_result
- end
- expect(Gitlab::ErrorTracking).to receive(:should_raise_for_dev?).and_return(false) # like prod
-
- namespace.update!(path: namespace.full_path + '_new')
- end
- end
- end
-
- shared_examples 'move_dir without repository storage feature' do |storage_version|
- let(:namespace) { create(:namespace) }
- let(:gitlab_shell) { namespace.gitlab_shell }
- let!(:project) { create(:project_empty_repo, namespace: namespace, storage_version: storage_version) }
-
- it 'calls namespace service' do
- expect(gitlab_shell).to receive(:add_namespace).and_return(true)
- expect(gitlab_shell).to receive(:mv_namespace).and_return(true)
-
- namespace.move_dir
- end
- end
-
- shared_examples 'move_dir with repository storage feature' do |storage_version|
- let(:namespace) { create(:namespace) }
- let(:gitlab_shell) { namespace.gitlab_shell }
- let!(:project) { create(:project_empty_repo, namespace: namespace, storage_version: storage_version) }
-
- it 'does not call namespace service' do
- expect(gitlab_shell).not_to receive(:add_namespace)
- expect(gitlab_shell).not_to receive(:mv_namespace)
-
- namespace.move_dir
- end
- end
-
- context 'project is without repository storage feature' do
- [nil, 0].each do |storage_version|
- it_behaves_like 'move_dir without repository storage feature', storage_version
- end
- end
-
- context 'project has repository storage feature' do
- [1, 2].each do |storage_version|
- it_behaves_like 'move_dir with repository storage feature', storage_version
- end
- end
-
- context 'with subgroups' do
- let(:parent) { create(:group, name: 'parent', path: 'parent') }
- let(:new_parent) { create(:group, name: 'new_parent', path: 'new_parent') }
- let(:child) { create(:group, name: 'child', path: 'child', parent: parent) }
- let!(:project) { create(:project_empty_repo, :legacy_storage, path: 'the-project', namespace: child, skip_disk_validation: true) }
- let(:uploads_dir) { FileUploader.root }
- let(:pages_dir) { File.join(TestEnv.pages_path) }
-
- def expect_project_directories_at(namespace_path, with_pages: true)
- expected_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, namespace_path, 'the-project.git')
- end
- expected_upload_path = File.join(uploads_dir, namespace_path, 'the-project')
- expected_pages_path = File.join(pages_dir, namespace_path, 'the-project')
-
- expect(File.directory?(expected_repository_path)).to be_truthy
- expect(File.directory?(expected_upload_path)).to be_truthy
- expect(File.directory?(expected_pages_path)).to be(with_pages)
- end
-
- before do
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- FileUtils.mkdir_p(File.join(TestEnv.repos_path, "#{project.full_path}.git"))
- end
- FileUtils.mkdir_p(File.join(uploads_dir, project.full_path))
- FileUtils.mkdir_p(File.join(pages_dir, project.full_path))
- end
-
- after do
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- FileUtils.remove_entry(File.join(TestEnv.repos_path, parent.full_path), true)
- FileUtils.remove_entry(File.join(TestEnv.repos_path, new_parent.full_path), true)
- FileUtils.remove_entry(File.join(TestEnv.repos_path, child.full_path), true)
- end
- FileUtils.remove_entry(File.join(uploads_dir, project.full_path), true)
- FileUtils.remove_entry(pages_dir, true)
- end
-
- context 'renaming child' do
- context 'when no projects have pages deployed' do
- it 'moves the repository and uploads', :sidekiq_inline do
- project.pages_metadatum.update!(deployed: false)
- child.update!(path: 'renamed')
-
- expect_project_directories_at('parent/renamed', with_pages: false)
- end
- end
- end
-
- context 'renaming parent' do
- context 'when no projects have pages deployed' do
- it 'moves the repository and uploads', :sidekiq_inline do
- project.pages_metadatum.update!(deployed: false)
- parent.update!(path: 'renamed')
-
- expect_project_directories_at('renamed/child', with_pages: false)
- end
- end
- end
-
- context 'moving from one parent to another' do
- context 'when no projects have pages deployed' do
- it 'moves the repository and uploads', :sidekiq_inline do
- project.pages_metadatum.update!(deployed: false)
- child.update!(parent: new_parent)
-
- expect_project_directories_at('new_parent/child', with_pages: false)
- end
- end
- end
-
- context 'moving from having a parent to root' do
- context 'when no projects have pages deployed' do
- it 'moves the repository and uploads', :sidekiq_inline do
- project.pages_metadatum.update!(deployed: false)
- child.update!(parent: nil)
-
- expect_project_directories_at('child', with_pages: false)
- end
- end
- end
-
- context 'moving from root to having a parent' do
- context 'when no projects have pages deployed' do
- it 'moves the repository and uploads', :sidekiq_inline do
- project.pages_metadatum.update!(deployed: false)
- parent.update!(parent: new_parent)
-
- expect_project_directories_at('new_parent/parent/child', with_pages: false)
- end
- end
- end
- end
- end
-
- context 'hashed storage' do
- let(:namespace) { create(:namespace) }
- let!(:project) { create(:project_empty_repo, namespace: namespace) }
-
- it_behaves_like 'namespace restrictions'
it "repository directory remains unchanged if path changed" do
before_disk_path = project.disk_path
@@ -1430,73 +1271,6 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
end
end
- describe '#rm_dir', 'callback' do
- let(:repository_storage_path) do
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- Gitlab.config.repositories.storages.default.legacy_disk_path
- end
- end
-
- let(:path_in_dir) { File.join(repository_storage_path, namespace.full_path) }
- let(:deleted_path) { namespace.full_path.gsub(namespace.path, "#{namespace.full_path}+#{namespace.id}+deleted") }
- let(:deleted_path_in_dir) { File.join(repository_storage_path, deleted_path) }
-
- context 'legacy storage' do
- let!(:project) { create(:project_empty_repo, :legacy_storage, namespace: namespace) }
-
- it 'renames its dirs when deleted' do
- allow(GitlabShellWorker).to receive(:perform_in)
-
- namespace.destroy!
-
- expect(File.exist?(deleted_path_in_dir)).to be(true)
- end
-
- it 'schedules the namespace for deletion' do
- expect(GitlabShellWorker).to receive(:perform_in).with(5.minutes, :rm_namespace, repository_storage, deleted_path)
-
- namespace.destroy!
- end
-
- context 'in sub-groups' do
- let(:parent) { create(:group, path: 'parent') }
- let(:child) { create(:group, parent: parent, path: 'child') }
- let!(:project) { create(:project_empty_repo, :legacy_storage, namespace: child) }
- let(:path_in_dir) { File.join(repository_storage_path, 'parent', 'child') }
- let(:deleted_path) { File.join('parent', "child+#{child.id}+deleted") }
- let(:deleted_path_in_dir) { File.join(repository_storage_path, deleted_path) }
-
- it 'renames its dirs when deleted' do
- allow(GitlabShellWorker).to receive(:perform_in)
-
- child.destroy!
-
- expect(File.exist?(deleted_path_in_dir)).to be(true)
- end
-
- it 'schedules the namespace for deletion' do
- expect(GitlabShellWorker).to receive(:perform_in).with(5.minutes, :rm_namespace, repository_storage, deleted_path)
-
- child.destroy!
- end
- end
- end
-
- context 'hashed storage' do
- let!(:project) { create(:project_empty_repo, namespace: namespace) }
-
- it 'has no repositories base directories to remove' do
- expect(GitlabShellWorker).not_to receive(:perform_in)
-
- expect(File.exist?(path_in_dir)).to be(false)
-
- namespace.destroy!
-
- expect(File.exist?(deleted_path_in_dir)).to be(false)
- end
- end
- end
-
describe '.find_by_path_or_name' do
before do
@namespace = create(:namespace, name: 'WoW', path: 'woW')
@@ -2126,6 +1900,48 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
end
end
+ describe '#first_auto_devops_config' do
+ let(:instance_autodevops_status) { Gitlab::CurrentSettings.auto_devops_enabled? }
+
+ context 'when namespace.auto_devops_enabled is not set' do
+ let(:group) { create(:group) }
+
+ it 'returns the config values using the instance setting' do
+ expect(group.first_auto_devops_config).to eq({ scope: :instance, status: instance_autodevops_status })
+ end
+
+ context 'when namespace does not have auto_deveops enabled but has a parent' do
+ let!(:parent) { create(:group, auto_devops_enabled: true) }
+ let!(:group) { create(:group, parent: parent) }
+
+ it 'returns the first_auto_devops_config of the parent' do
+ expect(parent).to receive(:first_auto_devops_config).and_call_original
+
+ expect(group.first_auto_devops_config).to eq({ scope: :group, status: true })
+ end
+
+ context 'then the parent is deleted' do
+ before do
+ parent.delete
+ group.reload
+ end
+
+ it 'returns its own config with status based on the instance settings' do
+ expect(group.first_auto_devops_config).to eq({ scope: :instance, status: instance_autodevops_status })
+ end
+ end
+ end
+ end
+
+ context 'when namespace.auto_devops_enable is set' do
+ let(:group) { create(:group, auto_devops_enabled: false) }
+
+ it 'returns the correct config values' do
+ expect(group.first_auto_devops_config).to eq({ scope: :group, status: false })
+ end
+ end
+ end
+
describe '#user_namespace?' do
subject { namespace.user_namespace? }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 0fc689b9f6c..2b26c73aa7a 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe Note, feature_category: :team_planning do
describe 'associations' do
it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:noteable).touch(false) }
it { is_expected.to belong_to(:author).class_name('User') }
@@ -32,6 +33,7 @@ RSpec.describe Note, feature_category: :team_planning do
it { is_expected.to validate_length_of(:note).is_at_most(1_000_000) }
it { is_expected.to validate_presence_of(:note) }
it { is_expected.to validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:namespace) }
context 'when note is on commit' do
before do
@@ -310,6 +312,70 @@ RSpec.describe Note, feature_category: :team_planning do
it { is_expected.to be false }
end
end
+
+ describe '#ensure_namespace_id' do
+ context 'for a project noteable' do
+ let_it_be(:issue) { create(:issue) }
+
+ it 'copies the project_namespace_id of the project' do
+ note = build(:note, noteable: issue, project: issue.project)
+
+ note.valid?
+
+ expect(note.namespace_id).to eq(issue.project.project_namespace_id)
+ end
+
+ context 'when noteable is changed' do
+ let_it_be(:another_issue) { create(:issue) }
+
+ it 'updates the namespace_id' do
+ note = create(:note, noteable: issue, project: issue.project)
+
+ note.noteable = another_issue
+ note.project = another_issue.project
+ note.valid?
+
+ expect(note.namespace_id).to eq(another_issue.project.project_namespace_id)
+ end
+ end
+
+ context 'when project is missing' do
+ it 'does not raise an exception' do
+ note = build(:note, noteable: issue, project: nil)
+
+ expect { note.valid? }.not_to raise_error
+ end
+ end
+ end
+
+ context 'for a personal snippet note' do
+ let_it_be(:snippet) { create(:personal_snippet) }
+
+ it 'copies the personal namespace_id of the author' do
+ note = build(:note, noteable: snippet, project: nil)
+
+ note.valid?
+
+ expect(note.namespace_id).to eq(snippet.author.namespace.id)
+ end
+
+ context 'when snippet author is missing' do
+ it 'does not raise an exception' do
+ note = build(:note, noteable: build(:personal_snippet, author: nil), project: nil)
+
+ expect { note.valid? }.not_to raise_error
+ end
+ end
+ end
+
+ context 'when noteable is missing' do
+ it 'does not raise an exception' do
+ note = build(:note, noteable: nil, project: nil)
+
+ expect { note.valid? }.not_to raise_error
+ end
+ end
+ end
end
describe "Commit notes" do
@@ -1595,53 +1661,30 @@ RSpec.describe Note, feature_category: :team_planning do
end
end
- describe 'expiring ETag cache' do
+ describe 'broadcasting note changes' do
let_it_be(:issue) { create(:issue) }
let(:note) { build(:note, project: issue.project, noteable: issue) }
- def expect_expiration(noteable)
- expect_any_instance_of(Gitlab::EtagCaching::Store)
- .to receive(:touch)
- .with("/#{noteable.project.namespace.to_param}/#{noteable.project.to_param}/noteable/#{noteable.class.name.underscore}/#{noteable.id}/notes")
- end
-
it 'broadcasts an Action Cable event for the noteable' do
expect(Noteable::NotesChannel).to receive(:broadcast_to).with(note.noteable, event: 'updated')
note.save!
end
- context 'when action_cable_notes is disabled' do
- before do
- stub_feature_flags(action_cable_notes: false)
- end
-
- it 'does not broadcast an Action Cable event' do
- expect(Noteable::NotesChannel).not_to receive(:broadcast_to)
-
- note.save!
- end
- end
-
- it "expires cache for note's issue when note is saved" do
- expect_expiration(note.noteable)
-
+ it 'broadcast an Action Cable event for the noteable when note is destroyed' do
note.save!
- end
- it "expires cache for note's issue when note is destroyed" do
- note.save!
- expect_expiration(note.noteable)
+ expect(Noteable::NotesChannel).to receive(:broadcast_to).with(note.noteable, event: 'updated')
note.destroy!
end
- context 'when issuable etag caching is disabled' do
- it 'does not store cache key' do
- allow(note.noteable).to receive(:etag_caching_enabled?).and_return(false)
+ context 'when issuable real_time_notes is disabled' do
+ it 'does not broadcast an Action Cable event' do
+ allow(note.noteable).to receive(:real_time_notes_enabled?).and_return(false)
- expect_any_instance_of(Gitlab::EtagCaching::Store).not_to receive(:touch)
+ expect(Noteable::NotesChannel).not_to receive(:broadcast_to)
note.save!
end
@@ -1653,8 +1696,8 @@ RSpec.describe Note, feature_category: :team_planning do
context 'when adding a note to the MR' do
let(:note) { build(:note, noteable: merge_request, project: merge_request.project) }
- it 'expires the MR note etag cache' do
- expect_expiration(merge_request)
+ it 'broadcasts an Action Cable event for the MR' do
+ expect(Noteable::NotesChannel).to receive(:broadcast_to).with(merge_request, event: 'updated')
note.save!
end
@@ -1663,8 +1706,8 @@ RSpec.describe Note, feature_category: :team_planning do
context 'when adding a note to a commit on the MR' do
let(:note) { build(:note_on_commit, commit_id: merge_request.commits.first.id, project: merge_request.project) }
- it 'expires the MR note etag cache' do
- expect_expiration(merge_request)
+ it 'broadcasts an Action Cable event for the MR' do
+ expect(Noteable::NotesChannel).to receive(:broadcast_to).with(merge_request, event: 'updated')
note.save!
end
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index 730a9045d7f..9bf95051730 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -221,4 +221,11 @@ RSpec.describe NotificationSetting do
it { is_expected.to eq([notification_setting_1, notification_setting_3]) }
end
+
+ context 'with loose foreign key on notification_settings.user_id' do
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let!(:parent) { create(:user) }
+ let!(:model) { create(:notification_setting, user: parent) }
+ end
+ end
end
diff --git a/spec/models/oauth_access_token_spec.rb b/spec/models/oauth_access_token_spec.rb
index b21a2bf2079..55c82369f33 100644
--- a/spec/models/oauth_access_token_spec.rb
+++ b/spec/models/oauth_access_token_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe OauthAccessToken do
+RSpec.describe OauthAccessToken, feature_category: :system_access do
let(:app_one) { create(:oauth_application) }
let(:app_two) { create(:oauth_application) }
let(:app_three) { create(:oauth_application) }
@@ -23,6 +23,10 @@ RSpec.describe OauthAccessToken do
end
describe 'Doorkeeper secret storing' do
+ it 'does not have a prefix' do
+ expect(token.plaintext_token).not_to start_with('gl')
+ end
+
it 'stores the token in hashed format' do
expect(token.token).not_to eq(token.plaintext_token)
end
diff --git a/spec/models/organizations/organization_spec.rb b/spec/models/organizations/organization_spec.rb
index 7838fc1c5a4..2f9f04fd3e6 100644
--- a/spec/models/organizations/organization_spec.rb
+++ b/spec/models/organizations/organization_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe Organizations::Organization, type: :model, feature_category: :cel
it { is_expected.to have_many :groups }
it { is_expected.to have_many(:users).through(:organization_users).inverse_of(:organizations) }
it { is_expected.to have_many(:organization_users).inverse_of(:organization) }
+ it { is_expected.to have_many :projects }
end
describe 'validations' do
diff --git a/spec/models/packages/dependency_link_spec.rb b/spec/models/packages/dependency_link_spec.rb
index d8fde8f5eb3..3022a960c4c 100644
--- a/spec/models/packages/dependency_link_spec.rb
+++ b/spec/models/packages/dependency_link_spec.rb
@@ -1,7 +1,28 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Packages::DependencyLink, type: :model do
+RSpec.describe Packages::DependencyLink, type: :model, feature_category: :package_registry do
+ let_it_be(:package1) { create(:package) }
+ let_it_be(:package2) { create(:package) }
+ let_it_be(:dependency1) { create(:packages_dependency) }
+ let_it_be(:dependency2) { create(:packages_dependency) }
+
+ let_it_be(:dependency_link1) do
+ create(:packages_dependency_link, :dev_dependencies, package: package1, dependency: dependency1)
+ end
+
+ let_it_be(:dependency_link2) do
+ create(:packages_dependency_link, :dependencies, package: package1, dependency: dependency2)
+ end
+
+ let_it_be(:dependency_link3) do
+ create(:packages_dependency_link, :dependencies, package: package2, dependency: dependency1)
+ end
+
+ let_it_be(:dependency_link4) do
+ create(:packages_dependency_link, :dependencies, package: package2, dependency: dependency2)
+ end
+
describe 'relationships' do
it { is_expected.to belong_to(:package).inverse_of(:dependency_links) }
it { is_expected.to belong_to(:dependency).inverse_of(:dependency_links) }
@@ -53,4 +74,49 @@ RSpec.describe Packages::DependencyLink, type: :model do
end
end
end
+
+ describe '.dependency_ids_grouped_by_type' do
+ let(:packages) { Packages::Package.where(id: [package1.id, package2.id]) }
+
+ subject { described_class.dependency_ids_grouped_by_type(packages) }
+
+ it 'aggregates dependencies by type', :aggregate_failures do
+ result = Gitlab::Json.parse(subject.to_json)
+
+ expect(result.count).to eq(2)
+ expect(result).to include(
+ hash_including(
+ 'package_id' => package1.id,
+ 'dependency_ids_by_type' => {
+ '1' => [dependency2.id],
+ '2' => [dependency1.id]
+ }
+ ),
+ hash_including(
+ 'package_id' => package2.id,
+ 'dependency_ids_by_type' => {
+ '1' => [dependency1.id, dependency2.id]
+ }
+ )
+ )
+ end
+ end
+
+ describe '.for_packages' do
+ let(:packages) { Packages::Package.where(id: package1.id) }
+
+ subject { described_class.for_packages(packages) }
+
+ it 'returns dependency links for selected packages' do
+ expect(subject).to contain_exactly(dependency_link1, dependency_link2)
+ end
+ end
+
+ describe '.select_dependency_id' do
+ subject { described_class.select_dependency_id }
+
+ it 'returns only dependency_id' do
+ expect(subject[0].attributes).to eq('dependency_id' => dependency1.id, 'id' => nil)
+ end
+ end
end
diff --git a/spec/models/packages/ml_model/package_spec.rb b/spec/models/packages/ml_model/package_spec.rb
new file mode 100644
index 00000000000..6a327197672
--- /dev/null
+++ b/spec/models/packages/ml_model/package_spec.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::MlModel::Package, feature_category: :mlops do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:ml_model) { create(:ml_model_package, project: project) }
+ let_it_be(:generic_package) { create(:generic_package, project: project) }
+
+ describe 'associations' do
+ it { is_expected.to have_one(:model_version) }
+ end
+
+ describe 'all' do
+ it 'fetches only ml_model packages' do
+ expect(described_class.all).to eq([ml_model])
+ end
+ end
+
+ describe '#valid?' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:valid_version) { '1.0.0' }
+ let_it_be(:valid_name) { 'some_model' }
+
+ let(:version) { valid_version }
+ let(:name) { valid_name }
+
+ let(:ml_model) { described_class.new(version: version, name: name, project: project) }
+
+ subject(:errors) do
+ ml_model.validate
+ ml_model.errors
+ end
+
+ it { expect(ml_model).to validate_presence_of(:name) }
+ it { expect(ml_model).to validate_presence_of(:version) }
+
+ it 'validates a valid ml_model package' do
+ expect(errors).to be_empty
+ end
+
+ describe 'name' do
+ where(:ctx, :name) do
+ 'name is blank' | ''
+ 'name is nil' | nil
+ 'name is not valid package name' | '!!()()'
+ 'name is too large' | ('a' * 256)
+ end
+ with_them do
+ it { expect(errors).to include(:name) }
+ end
+ end
+
+ describe 'version' do
+ where(:ctx, :version) do
+ 'version is blank' | ''
+ 'version is nil' | nil
+ 'version is not valid semver' | 'v1.0.0'
+ 'version is too large' | ('a' * 256)
+ end
+ with_them do
+ it { expect(errors).to include(:version) }
+ end
+ end
+ end
+end
diff --git a/spec/models/packages/nuget/metadatum_spec.rb b/spec/models/packages/nuget/metadatum_spec.rb
index e1520c0782f..c8e052baf6f 100644
--- a/spec/models/packages/nuget/metadatum_spec.rb
+++ b/spec/models/packages/nuget/metadatum_spec.rb
@@ -16,18 +16,7 @@ RSpec.describe Packages::Nuget::Metadatum, type: :model, feature_category: :pack
it { is_expected.to validate_length_of(:authors).is_at_most(described_class::MAX_AUTHORS_LENGTH) }
it { is_expected.to validate_presence_of(:description) }
it { is_expected.to validate_length_of(:description).is_at_most(described_class::MAX_DESCRIPTION_LENGTH) }
-
- context 'for normalized_version presence' do
- it { is_expected.to validate_presence_of(:normalized_version) }
-
- context 'when nuget_normalized_version feature flag is disabled' do
- before do
- stub_feature_flags(nuget_normalized_version: false)
- end
-
- it { is_expected.not_to validate_presence_of(:normalized_version) }
- end
- end
+ it { is_expected.to validate_presence_of(:normalized_version) }
%i[license_url project_url icon_url].each do |url|
describe "##{url}" do
@@ -87,16 +76,6 @@ RSpec.describe Packages::Nuget::Metadatum, type: :model, feature_category: :pack
expect(nuget_metadatum.normalized_version).to eq(normalized_version)
end
-
- context 'when the nuget_normalized_version feature flag is disabled' do
- before do
- stub_feature_flags(nuget_normalized_version: false)
- end
-
- it 'does not save the normalized version' do
- expect(nuget_metadatum.normalized_version).not_to eq(normalized_version)
- end
- end
end
end
end
diff --git a/spec/models/packages/nuget/symbol_spec.rb b/spec/models/packages/nuget/symbol_spec.rb
new file mode 100644
index 00000000000..52e95c11939
--- /dev/null
+++ b/spec/models/packages/nuget/symbol_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Nuget::Symbol, type: :model, feature_category: :package_registry do
+ subject(:symbol) { create(:nuget_symbol) }
+
+ it { is_expected.to be_a FileStoreMounter }
+
+ describe 'relationships' do
+ it { is_expected.to belong_to(:package).inverse_of(:nuget_symbols) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:file) }
+ it { is_expected.to validate_presence_of(:file_path) }
+ it { is_expected.to validate_presence_of(:signature) }
+ it { is_expected.to validate_presence_of(:object_storage_key) }
+ it { is_expected.to validate_presence_of(:size) }
+ it { is_expected.to validate_uniqueness_of(:signature).scoped_to(:file_path) }
+ it { is_expected.to validate_uniqueness_of(:object_storage_key).case_insensitive }
+ end
+
+ describe 'delegations' do
+ it { is_expected.to delegate_method(:project_id).to(:package) }
+ end
+
+ describe 'callbacks' do
+ describe 'before_validation' do
+ describe '#set_object_storage_key' do
+ context 'when signature and project_id are present' do
+ it 'sets the object_storage_key' do
+ expected_key = Gitlab::HashedPath.new(
+ 'packages', 'nuget', symbol.package_id, 'symbols', OpenSSL::Digest::SHA256.hexdigest(symbol.signature),
+ root_hash: symbol.project_id
+ ).to_s
+
+ symbol.valid?
+
+ expect(symbol.object_storage_key).to eq(expected_key)
+ end
+ end
+
+ context 'when signature is not present' do
+ subject(:symbol) { build(:nuget_symbol, signature: nil) }
+
+ it 'does not set the object_storage_key' do
+ symbol.valid?
+
+ expect(symbol.object_storage_key).to be_nil
+ end
+ end
+
+ context 'when project_id is not present' do
+ subject(:symbol) { build(:nuget_symbol) }
+
+ before do
+ allow(symbol).to receive(:project_id).and_return(nil)
+ end
+
+ it 'does not set the object_storage_key' do
+ symbol.valid?
+
+ expect(symbol.object_storage_key).to be_nil
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/packages/package_spec.rb b/spec/models/packages/package_spec.rb
index 381b5af117e..e113218e828 100644
--- a/spec/models/packages/package_spec.rb
+++ b/spec/models/packages/package_spec.rb
@@ -25,6 +25,7 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis
it { is_expected.to have_one(:rubygems_metadatum).inverse_of(:package) }
it { is_expected.to have_one(:npm_metadatum).inverse_of(:package) }
it { is_expected.to have_one(:rpm_metadatum).inverse_of(:package) }
+ it { is_expected.to have_many(:nuget_symbols).inverse_of(:package) }
end
describe '.with_debian_codename' do
@@ -875,14 +876,6 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis
subject { described_class.with_npm_scope('test') }
it { is_expected.to contain_exactly(package1) }
-
- context 'when npm_package_registry_fix_group_path_validation is disabled' do
- before do
- stub_feature_flags(npm_package_registry_fix_group_path_validation: false)
- end
-
- it { is_expected.to contain_exactly(package1) }
- end
end
describe '.without_nuget_temporary_name' do
@@ -1505,4 +1498,38 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis
end
end
end
+
+ describe 'inheritance' do
+ let_it_be(:project) { create(:project) }
+
+ let(:format) { "" }
+ let(:package) { create("#{format}_package", project: project) }
+ let(:package_id) { package.id }
+
+ subject { described_class.find_by(id: package_id).class }
+
+ described_class
+ .package_types
+ .keys
+ .map(&:to_sym)
+ .each do |package_format|
+ if described_class.inheritance_column_to_class_map[package_format].nil?
+ context "for package format #{package_format}" do
+ let(:format) { package_format }
+
+ it 'maps to Packages::Package' do
+ is_expected.to eq(described_class)
+ end
+ end
+ else
+ context "for package format #{package_format}" do
+ let(:format) { package_format }
+
+ it 'maps to the correct class' do
+ is_expected.to eq(described_class.inheritance_column_to_class_map[package_format].constantize)
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/packages/protection/rule_spec.rb b/spec/models/packages/protection/rule_spec.rb
new file mode 100644
index 00000000000..b368687e6d8
--- /dev/null
+++ b/spec/models/packages/protection/rule_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Protection::Rule, type: :model, feature_category: :package_registry do
+ it_behaves_like 'having unique enum values'
+
+ describe 'relationships' do
+ it { is_expected.to belong_to(:project).inverse_of(:package_protection_rules) }
+ end
+
+ describe 'enums' do
+ describe '#package_type' do
+ it { is_expected.to define_enum_for(:package_type).with_values(npm: Packages::Package.package_types[:npm]) }
+ end
+ end
+
+ describe 'validations' do
+ subject { build(:package_protection_rule) }
+
+ describe '#package_name_pattern' do
+ it { is_expected.to validate_presence_of(:package_name_pattern) }
+ it { is_expected.to validate_uniqueness_of(:package_name_pattern).scoped_to(:project_id, :package_type) }
+ it { is_expected.to validate_length_of(:package_name_pattern).is_at_most(255) }
+ end
+
+ describe '#package_type' do
+ it { is_expected.to validate_presence_of(:package_type) }
+ end
+
+ describe '#push_protected_up_to_access_level' do
+ it { is_expected.to validate_presence_of(:push_protected_up_to_access_level) }
+
+ it {
+ is_expected.to validate_inclusion_of(:push_protected_up_to_access_level).in_array([Gitlab::Access::DEVELOPER,
+ Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER])
+ }
+ end
+ end
+end
diff --git a/spec/models/pages/virtual_domain_spec.rb b/spec/models/pages/virtual_domain_spec.rb
index b5a421295b2..02e3fd67f2d 100644
--- a/spec/models/pages/virtual_domain_spec.rb
+++ b/spec/models/pages/virtual_domain_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Pages::VirtualDomain do
+RSpec.describe Pages::VirtualDomain, feature_category: :pages do
describe '#certificate and #key pair' do
let(:domain) { nil }
let(:project) { instance_double(Project) }
@@ -25,6 +25,8 @@ RSpec.describe Pages::VirtualDomain do
end
describe '#lookup_paths' do
+ let(:domain) { nil }
+ let(:trim_prefix) { nil }
let(:project_a) { instance_double(Project) }
let(:project_b) { instance_double(Project) }
let(:project_c) { instance_double(Project) }
@@ -32,44 +34,43 @@ RSpec.describe Pages::VirtualDomain do
let(:pages_lookup_path_b) { instance_double(Pages::LookupPath, prefix: 'bbb', source: { type: 'zip', path: 'https://example.com' }) }
let(:pages_lookup_path_without_source) { instance_double(Pages::LookupPath, prefix: 'ccc', source: nil) }
+ subject(:virtual_domain) do
+ described_class.new(projects: project_list, domain: domain, trim_prefix: trim_prefix)
+ end
+
+ before do
+ allow(Pages::LookupPath)
+ .to receive(:new)
+ .with(project_a, domain: domain, trim_prefix: trim_prefix)
+ .and_return(pages_lookup_path_a)
+
+ allow(Pages::LookupPath)
+ .to receive(:new)
+ .with(project_b, domain: domain, trim_prefix: trim_prefix)
+ .and_return(pages_lookup_path_b)
+
+ allow(Pages::LookupPath)
+ .to receive(:new)
+ .with(project_c, domain: domain, trim_prefix: trim_prefix)
+ .and_return(pages_lookup_path_without_source)
+ end
+
context 'when there is pages domain provided' do
let(:domain) { instance_double(PagesDomain) }
-
- subject(:virtual_domain) { described_class.new(projects: [project_a, project_b, project_c], domain: domain) }
+ let(:project_list) { [project_a, project_b, project_c] }
it 'returns collection of projects pages lookup paths sorted by prefix in reverse' do
- expect(project_a).to receive(:pages_lookup_path).with(domain: domain, trim_prefix: nil).and_return(pages_lookup_path_a)
- expect(project_b).to receive(:pages_lookup_path).with(domain: domain, trim_prefix: nil).and_return(pages_lookup_path_b)
- expect(project_c).to receive(:pages_lookup_path).with(domain: domain, trim_prefix: nil).and_return(pages_lookup_path_without_source)
-
expect(virtual_domain.lookup_paths).to eq([pages_lookup_path_b, pages_lookup_path_a])
end
end
context 'when there is trim_prefix provided' do
- subject(:virtual_domain) { described_class.new(projects: [project_a, project_b], trim_prefix: 'group/') }
+ let(:trim_prefix) { 'group/' }
+ let(:project_list) { [project_a, project_b] }
it 'returns collection of projects pages lookup paths sorted by prefix in reverse' do
- expect(project_a).to receive(:pages_lookup_path).with(trim_prefix: 'group/', domain: nil).and_return(pages_lookup_path_a)
- expect(project_b).to receive(:pages_lookup_path).with(trim_prefix: 'group/', domain: nil).and_return(pages_lookup_path_b)
-
expect(virtual_domain.lookup_paths).to eq([pages_lookup_path_b, pages_lookup_path_a])
end
end
end
-
- describe '#cache_key' do
- it 'returns the cache key based in the given cache_control' do
- cache_control = instance_double(::Gitlab::Pages::CacheControl, cache_key: 'cache_key')
- virtual_domain = described_class.new(projects: [instance_double(Project)], cache: cache_control)
-
- expect(virtual_domain.cache_key).to eq('cache_key')
- end
-
- it 'returns nil when no cache_control is given' do
- virtual_domain = described_class.new(projects: [instance_double(Project)])
-
- expect(virtual_domain.cache_key).to be_nil
- end
- end
end
diff --git a/spec/models/pages_deployment_spec.rb b/spec/models/pages_deployment_spec.rb
index bff69485e43..916197fe5e9 100644
--- a/spec/models/pages_deployment_spec.rb
+++ b/spec/models/pages_deployment_spec.rb
@@ -81,6 +81,57 @@ RSpec.describe PagesDeployment, feature_category: :pages do
end
end
+ describe '.deactivate_deployments_older_than', :freeze_time do
+ let!(:other_project_deployment) do
+ create(:pages_deployment)
+ end
+
+ let!(:other_path_prefix_deployment) do
+ create(:pages_deployment, project: project, path_prefix: 'other')
+ end
+
+ let!(:deactivated_deployment) do
+ create(:pages_deployment, project: project, deleted_at: 5.minutes.ago)
+ end
+
+ it 'updates only older deployments for the same project and path prefix' do
+ deployment1 = create(:pages_deployment, project: project, updated_at: 5.minutes.ago)
+ deployment2 = create(:pages_deployment, project: project, updated_at: 5.minutes.ago)
+ deployment3 = create(:pages_deployment, project: project, updated_at: 5.minutes.ago)
+
+ expect { described_class.deactivate_deployments_older_than(deployment2) }
+ .to change { deployment1.reload.deleted_at }
+ .from(nil).to(Time.zone.now)
+ .and change { deployment1.reload.updated_at }
+ .to(Time.zone.now)
+
+ expect(deployment2.reload.deleted_at).to be_nil
+ expect(deployment3.reload.deleted_at).to be_nil
+ expect(other_project_deployment.deleted_at).to be_nil
+ expect(other_path_prefix_deployment.reload.deleted_at).to be_nil
+ expect(deactivated_deployment.reload.deleted_at).to eq(5.minutes.ago)
+ end
+
+ it 'updates only older deployments for the same project with the given time' do
+ deployment1 = create(:pages_deployment, project: project, updated_at: 5.minutes.ago)
+ deployment2 = create(:pages_deployment, project: project, updated_at: 5.minutes.ago)
+ deployment3 = create(:pages_deployment, project: project, updated_at: 5.minutes.ago)
+ time = 30.minutes.from_now
+
+ expect { described_class.deactivate_deployments_older_than(deployment2, time: time) }
+ .to change { deployment1.reload.deleted_at }
+ .from(nil).to(time)
+ .and change { deployment1.reload.updated_at }
+ .to(Time.zone.now)
+
+ expect(deployment2.reload.deleted_at).to be_nil
+ expect(deployment3.reload.deleted_at).to be_nil
+ expect(other_project_deployment.deleted_at).to be_nil
+ expect(other_path_prefix_deployment.reload.deleted_at).to be_nil
+ expect(deactivated_deployment.reload.deleted_at).to eq(5.minutes.ago)
+ end
+ end
+
describe '#migrated?' do
it 'returns false for normal deployment' do
deployment = create(:pages_deployment)
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index 3030756a413..cd740bca502 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -201,6 +201,17 @@ RSpec.describe PagesDomain do
describe 'validations' do
it { is_expected.to validate_presence_of(:verification_code) }
+
+ context 'when validating max certificate key length' do
+ it 'validates the certificate key length' do
+ valid_domain = build(:pages_domain, :key_length_8192)
+ expect(valid_domain).to be_valid
+
+ invalid_domain = build(:pages_domain, :extra_long_key)
+ expect(invalid_domain).to be_invalid
+ expect(invalid_domain.errors[:key]).to include('Certificate Key is too long. (Max 8192 bytes)')
+ end
+ end
end
describe 'default values' do
diff --git a/spec/models/performance_monitoring/prometheus_metric_spec.rb b/spec/models/performance_monitoring/prometheus_metric_spec.rb
deleted file mode 100644
index 58bb59793cf..00000000000
--- a/spec/models/performance_monitoring/prometheus_metric_spec.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe PerformanceMonitoring::PrometheusMetric do
- let(:json_content) do
- {
- "id" => "metric_of_ages",
- "unit" => "count",
- "label" => "Metric of Ages",
- "query_range" => "http_requests_total"
- }
- end
-
- describe '.from_json' do
- subject { described_class.from_json(json_content) }
-
- it 'creates a PrometheusMetric object' do
- expect(subject).to be_a described_class
- expect(subject.id).to eq(json_content['id'])
- expect(subject.unit).to eq(json_content['unit'])
- expect(subject.label).to eq(json_content['label'])
- expect(subject.query_range).to eq(json_content['query_range'])
- end
-
- describe 'validations' do
- context 'json_content is not a hash' do
- let(:json_content) { nil }
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when unit is missing' do
- before do
- json_content['unit'] = nil
- end
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when query and query_range is missing' do
- before do
- json_content['query_range'] = nil
- end
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when query_range is missing but query is available' do
- before do
- json_content['query_range'] = nil
- json_content['query'] = 'http_requests_total'
- end
-
- subject { described_class.from_json(json_content) }
-
- it { is_expected.to be_valid }
- end
- end
- end
-end
diff --git a/spec/models/performance_monitoring/prometheus_panel_group_spec.rb b/spec/models/performance_monitoring/prometheus_panel_group_spec.rb
deleted file mode 100644
index 497f80483eb..00000000000
--- a/spec/models/performance_monitoring/prometheus_panel_group_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe PerformanceMonitoring::PrometheusPanelGroup do
- let(:json_content) do
- {
- "group" => "Group Title",
- "panels" => [{
- "type" => "area-chart",
- "title" => "Chart Title",
- "y_label" => "Y-Axis",
- "metrics" => [{
- "id" => "metric_of_ages",
- "unit" => "count",
- "label" => "Metric of Ages",
- "query_range" => "http_requests_total"
- }]
- }]
- }
- end
-
- describe '.from_json' do
- subject { described_class.from_json(json_content) }
-
- it 'creates a PrometheusPanelGroup object' do
- expect(subject).to be_a described_class
- expect(subject.group).to eq(json_content['group'])
- expect(subject.panels).to all(be_a PerformanceMonitoring::PrometheusPanel)
- end
-
- describe 'validations' do
- context 'json_content is not a hash' do
- let(:json_content) { nil }
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when group is missing' do
- before do
- json_content.delete('group')
- end
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when panels are missing' do
- before do
- json_content['panels'] = []
- end
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
- end
- end
-end
diff --git a/spec/models/performance_monitoring/prometheus_panel_spec.rb b/spec/models/performance_monitoring/prometheus_panel_spec.rb
deleted file mode 100644
index 42dcbbdb8e0..00000000000
--- a/spec/models/performance_monitoring/prometheus_panel_spec.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe PerformanceMonitoring::PrometheusPanel do
- let(:json_content) do
- {
- "max_value" => 1,
- "type" => "area-chart",
- "title" => "Chart Title",
- "y_label" => "Y-Axis",
- "weight" => 1,
- "metrics" => [{
- "id" => "metric_of_ages",
- "unit" => "count",
- "label" => "Metric of Ages",
- "query_range" => "http_requests_total"
- }]
- }
- end
-
- describe '#new' do
- it 'accepts old schema format' do
- expect { described_class.new(json_content) }.not_to raise_error
- end
-
- it 'accepts new schema format' do
- expect { described_class.new(json_content.merge("y_axis" => { "precision" => 0 })) }.not_to raise_error
- end
- end
-
- describe '.from_json' do
- subject { described_class.from_json(json_content) }
-
- it 'creates a PrometheusPanelGroup object' do
- expect(subject).to be_a described_class
- expect(subject.type).to eq(json_content['type'])
- expect(subject.title).to eq(json_content['title'])
- expect(subject.y_label).to eq(json_content['y_label'])
- expect(subject.weight).to eq(json_content['weight'])
- expect(subject.metrics).to all(be_a PerformanceMonitoring::PrometheusMetric)
- end
-
- describe 'validations' do
- context 'json_content is not a hash' do
- let(:json_content) { nil }
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when title is missing' do
- before do
- json_content['title'] = nil
- end
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
-
- context 'when metrics are missing' do
- before do
- json_content.delete('metrics')
- end
-
- subject { described_class.from_json(json_content) }
-
- it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
- end
- end
- end
-
- describe '.id' do
- it 'returns hexdigest of group_title, type and title as the panel id' do
- group_title = 'Business Group'
- panel_type = 'area-chart'
- panel_title = 'New feature requests made'
-
- expect(Digest::SHA2).to receive(:hexdigest).with("#{group_title}#{panel_type}#{panel_title}").and_return('hexdigest')
- expect(described_class.new(title: panel_title, type: panel_type).id(group_title)).to eql 'hexdigest'
- end
- end
-end
diff --git a/spec/models/plan_spec.rb b/spec/models/plan_spec.rb
index 73e88a17e24..fe3365ca78f 100644
--- a/spec/models/plan_spec.rb
+++ b/spec/models/plan_spec.rb
@@ -3,6 +3,18 @@
require 'spec_helper'
RSpec.describe Plan do
+ describe 'scopes', :aggregate_failures do
+ let_it_be(:default_plan) { create(:default_plan) }
+
+ describe '.by_name' do
+ it 'returns plans by their name' do
+ expect(described_class.by_name('default')).to match_array([default_plan])
+ expect(described_class.by_name(%w[default unknown])).to match_array([default_plan])
+ expect(described_class.by_name(nil)).to be_empty
+ end
+ end
+ end
+
describe '#default?' do
subject { plan.default? }
diff --git a/spec/models/pool_repository_spec.rb b/spec/models/pool_repository_spec.rb
index 93c1e59458d..bafda406774 100644
--- a/spec/models/pool_repository_spec.rb
+++ b/spec/models/pool_repository_spec.rb
@@ -13,15 +13,17 @@ RSpec.describe PoolRepository, feature_category: :source_code_management do
let!(:pool_repository) { create(:pool_repository) }
it { is_expected.to validate_presence_of(:shard) }
- it { is_expected.to validate_presence_of(:source_project) }
end
describe 'scopes' do
let_it_be(:project1) { create(:project) }
let_it_be(:project2) { create(:project) }
let_it_be(:new_shard) { create(:shard, name: 'new') }
- let_it_be(:pool_repository1) { create(:pool_repository, source_project: project1) }
- let_it_be(:pool_repository2) { create(:pool_repository, source_project: project1, shard: new_shard) }
+ let_it_be(:pool_repository1) { create(:pool_repository, source_project: project1, disk_path: 'disk_path') }
+ let_it_be(:pool_repository2) do
+ create(:pool_repository, source_project: project1, disk_path: 'disk_path', shard: new_shard)
+ end
+
let_it_be(:another_pool_repository) { create(:pool_repository, source_project: project2) }
describe '.by_source_project' do
@@ -32,8 +34,8 @@ RSpec.describe PoolRepository, feature_category: :source_code_management do
end
end
- describe '.by_source_project_and_shard_name' do
- subject { described_class.by_source_project_and_shard_name(project1, new_shard.name) }
+ describe '.by_disk_path_and_shard_name' do
+ subject { described_class.by_disk_path_and_shard_name('disk_path', new_shard.name) }
it 'returns only a requested pool repository' do
is_expected.to match_array([pool_repository2])
@@ -91,4 +93,38 @@ RSpec.describe PoolRepository, feature_category: :source_code_management do
end
end
end
+
+ describe '#object_pool' do
+ subject { pool.object_pool }
+
+ let(:pool) { build(:pool_repository, :ready, source_project: project, disk_path: disk_path) }
+ let(:project) { build(:project) }
+ let(:disk_path) { 'disk_path' }
+
+ it 'returns an object pool instance' do
+ is_expected.to be_a_kind_of(Gitlab::Git::ObjectPool)
+
+ is_expected.to have_attributes(
+ storage: pool.shard.name,
+ relative_path: "#{pool.disk_path}.git",
+ source_repository: pool.source_project.repository.raw,
+ gl_project_path: pool.source_project.full_path
+ )
+ end
+
+ context 'when source project is missing' do
+ let(:project) { nil }
+
+ it 'returns an object pool instance' do
+ is_expected.to be_a_kind_of(Gitlab::Git::ObjectPool)
+
+ is_expected.to have_attributes(
+ storage: pool.shard.name,
+ relative_path: "#{pool.disk_path}.git",
+ source_repository: nil,
+ gl_project_path: nil
+ )
+ end
+ end
+ end
end
diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb
index 2ba7f5c4ca4..9fed05342aa 100644
--- a/spec/models/project_authorization_spec.rb
+++ b/spec/models/project_authorization_spec.rb
@@ -3,6 +3,23 @@
require 'spec_helper'
RSpec.describe ProjectAuthorization, feature_category: :groups_and_projects do
+ describe 'create' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project_1) { create(:project) }
+
+ let(:project_auth) do
+ build(
+ :project_authorization,
+ user: user,
+ project: project_1
+ )
+ end
+
+ it 'sets is_unique' do
+ expect { project_auth.save! }.to change { project_auth.is_unique }.to(true)
+ end
+ end
+
describe 'unique user, project authorizations' do
let_it_be(:user) { create(:user) }
let_it_be(:project_1) { create(:project) }
@@ -65,6 +82,26 @@ RSpec.describe ProjectAuthorization, feature_category: :groups_and_projects do
it { is_expected.to validate_inclusion_of(:access_level).in_array(Gitlab::Access.all_values) }
end
+ describe 'scopes' do
+ describe '.non_guests' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:project_original_owner_authorization) { project.owner.project_authorizations.first }
+ let_it_be(:project_authorization_guest) { create(:project_authorization, :guest, project: project) }
+ let_it_be(:project_authorization_reporter) { create(:project_authorization, :reporter, project: project) }
+ let_it_be(:project_authorization_developer) { create(:project_authorization, :developer, project: project) }
+ let_it_be(:project_authorization_maintainer) { create(:project_authorization, :maintainer, project: project) }
+ let_it_be(:project_authorization_owner) { create(:project_authorization, :owner, project: project) }
+
+ it 'returns all records which are greater than Guests access' do
+ expect(described_class.non_guests.map(&:attributes)).to match_array([
+ project_authorization_reporter, project_authorization_developer,
+ project_authorization_maintainer, project_authorization_owner,
+ project_original_owner_authorization
+ ].map(&:attributes))
+ end
+ end
+ end
+
describe '.insert_all' do
let_it_be(:user) { create(:user) }
let_it_be(:project_1) { create(:project) }
diff --git a/spec/models/project_authorizations/changes_spec.rb b/spec/models/project_authorizations/changes_spec.rb
index d0718153d16..5f4dd963fb3 100644
--- a/spec/models/project_authorizations/changes_spec.rb
+++ b/spec/models/project_authorizations/changes_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe ProjectAuthorizations::Changes, feature_category: :groups_and_pro
apply_project_authorization_changes
expect(user.project_authorizations.pluck(:user_id, :project_id,
- :access_level)).to match_array(authorizations_to_add.map(&:values))
+ :access_level, :is_unique)).to match_array(authorizations_to_add.map(&:values))
end
end
@@ -101,7 +101,13 @@ RSpec.describe ProjectAuthorizations::Changes, feature_category: :groups_and_pro
apply_project_authorization_changes
expect(user.project_authorizations.pluck(:user_id, :project_id,
- :access_level)).to match_array(authorizations_to_add.map(&:values))
+ :access_level, :is_unique)).to match_array(authorizations_to_add.map(&:values))
+ end
+
+ it 'writes is_unique' do
+ apply_project_authorization_changes
+
+ expect(user.project_authorizations.pluck(:is_unique)).to all(be(true))
end
it_behaves_like 'logs the detail', batch_size: 2
diff --git a/spec/models/project_ci_cd_setting_spec.rb b/spec/models/project_ci_cd_setting_spec.rb
index 0a818147bfc..1c53f6eae52 100644
--- a/spec/models/project_ci_cd_setting_spec.rb
+++ b/spec/models/project_ci_cd_setting_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProjectCiCdSetting do
+RSpec.describe ProjectCiCdSetting, feature_category: :continuous_integration do
using RSpec::Parameterized::TableSyntax
describe 'validations' do
diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb
index 48c9567ebb3..39e77df1900 100644
--- a/spec/models/project_feature_spec.rb
+++ b/spec/models/project_feature_spec.rb
@@ -437,4 +437,24 @@ RSpec.describe ProjectFeature, feature_category: :groups_and_projects do
end
end
# rubocop:enable Gitlab/FeatureAvailableUsage
+
+ describe '#private?' do
+ where(:merge_requests_access_level, :expected_value) do
+ ProjectFeature::PUBLIC | false
+ ProjectFeature::ENABLED | false
+ ProjectFeature::PRIVATE | true
+ end
+
+ with_them do
+ let(:project) { build_stubbed(:project) }
+
+ subject { project.project_feature.private?(:merge_requests) }
+
+ before do
+ project.project_feature.merge_requests_access_level = merge_requests_access_level
+ end
+
+ it { is_expected.to be(expected_value) }
+ end
+ end
end
diff --git a/spec/models/project_import_state_spec.rb b/spec/models/project_import_state_spec.rb
index 7ceb4931c4f..10f4791b216 100644
--- a/spec/models/project_import_state_spec.rb
+++ b/spec/models/project_import_state_spec.rb
@@ -125,6 +125,14 @@ RSpec.describe ProjectImportState, type: :model, feature_category: :importers do
end
end
+ describe '#completed?' do
+ it { expect(described_class.new(status: :failed)).to be_completed }
+ it { expect(described_class.new(status: :finished)).to be_completed }
+ it { expect(described_class.new(status: :canceled)).to be_completed }
+ it { expect(described_class.new(status: :scheduled)).not_to be_completed }
+ it { expect(described_class.new(status: :started)).not_to be_completed }
+ end
+
describe '#expire_etag_cache' do
context 'when project import type has realtime changes endpoint' do
before do
diff --git a/spec/models/project_metrics_setting_spec.rb b/spec/models/project_metrics_setting_spec.rb
deleted file mode 100644
index 6639f9cb208..00000000000
--- a/spec/models/project_metrics_setting_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ProjectMetricsSetting do
- describe 'Associations' do
- it { is_expected.to belong_to(:project) }
- end
-
- describe 'Validations' do
- context 'when external_dashboard_url is over 255 chars' do
- before do
- subject.external_dashboard_url = 'https://' + 'a' * 250
- end
-
- it 'fails validation' do
- expect(subject).not_to be_valid
- expect(subject.errors.messages[:external_dashboard_url])
- .to include('is too long (maximum is 255 characters)')
- end
- end
-
- context 'with unsafe url' do
- before do
- subject.external_dashboard_url = %{https://replaceme.com/'><script>alert(document.cookie)</script>}
- end
-
- it { is_expected.to be_invalid }
- end
-
- context 'non ascii chars in external_dashboard_url' do
- before do
- subject.external_dashboard_url = 'http://gitlab.com/api/0/projects/project1/something€'
- end
-
- it { is_expected.to be_invalid }
- end
-
- context 'internal url in external_dashboard_url' do
- before do
- subject.external_dashboard_url = 'http://192.168.1.1'
- end
-
- it { is_expected.to be_valid }
- end
-
- context 'dashboard_timezone' do
- it { is_expected.to define_enum_for(:dashboard_timezone).with_values({ local: 0, utc: 1 }) }
-
- it 'defaults to local' do
- expect(subject.dashboard_timezone).to eq('local')
- end
- end
- end
-
- describe '#dashboard_timezone=' do
- it 'downcases string' do
- subject.dashboard_timezone = 'UTC'
-
- expect(subject.dashboard_timezone).to eq('utc')
- end
- end
-end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 5d622b8eccd..aedfc7fca53 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -17,12 +17,14 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
it_behaves_like 'ensures runners_token is prefixed', :project
describe 'associations' do
+ it { is_expected.to belong_to(:organization) }
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:project_namespace).class_name('Namespaces::ProjectNamespace').with_foreign_key('project_namespace_id').inverse_of(:project) }
it { is_expected.to belong_to(:creator).class_name('User') }
it { is_expected.to belong_to(:pool_repository) }
it { is_expected.to have_many(:users) }
+ it { is_expected.to have_many(:maintainers).through(:project_members).source(:user).conditions(members: { access_level: Gitlab::Access::MAINTAINER }) }
it { is_expected.to have_many(:events) }
it { is_expected.to have_many(:merge_requests) }
it { is_expected.to have_many(:merge_request_metrics).class_name('MergeRequest::Metrics') }
@@ -139,11 +141,9 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
it { is_expected.to have_many(:sourced_pipelines) }
it { is_expected.to have_many(:source_pipelines) }
it { is_expected.to have_many(:prometheus_alert_events) }
- it { is_expected.to have_many(:self_managed_prometheus_alert_events) }
it { is_expected.to have_many(:alert_management_alerts) }
it { is_expected.to have_many(:alert_management_http_integrations) }
it { is_expected.to have_many(:jira_imports) }
- it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:project) }
it { is_expected.to have_many(:repository_storage_moves) }
it { is_expected.to have_many(:reviews).inverse_of(:project) }
it { is_expected.to have_many(:packages).class_name('Packages::Package') }
@@ -152,6 +152,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
it { is_expected.to have_many(:debian_distributions).class_name('Packages::Debian::ProjectDistribution').dependent(:destroy) }
it { is_expected.to have_many(:npm_metadata_caches).class_name('Packages::Npm::MetadataCache') }
it { is_expected.to have_one(:packages_cleanup_policy).class_name('Packages::Cleanup::Policy').inverse_of(:project) }
+ it { is_expected.to have_many(:package_protection_rules).class_name('Packages::Protection::Rule').inverse_of(:project) }
it { is_expected.to have_many(:pipeline_artifacts).dependent(:restrict_with_error) }
it { is_expected.to have_many(:terraform_states).class_name('Terraform::State').inverse_of(:project) }
it { is_expected.to have_many(:timelogs) }
@@ -224,6 +225,23 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
expect(project.lfs_objects.to_a).to eql([lfs_object])
end
+ describe 'maintainers association' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:maintainer1) { create(:user) }
+ let_it_be(:maintainer2) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+
+ before do
+ project.add_maintainer(maintainer1)
+ project.add_maintainer(maintainer2)
+ project.add_reporter(reporter)
+ end
+
+ it 'returns only maintainers' do
+ expect(project.maintainers).to match_array([maintainer1, maintainer2])
+ end
+ end
+
context 'after initialized' do
it "has a project_feature" do
expect(described_class.new.project_feature).to be_present
@@ -1140,6 +1158,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
merge_pipelines_enabled
merge_trains_enabled
auto_rollback_enabled
+ merge_trains_skip_train_allowed
)
end
end
@@ -2380,7 +2399,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
end
- describe '#service_desk_address' do
+ describe '#service_desk_address', feature_category: :service_desk do
let_it_be(:project, reload: true) { create(:project, service_desk_enabled: true) }
subject { project.service_desk_address }
@@ -2424,7 +2443,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
context 'when project_key is set' do
- it 'returns custom address including the project_key' do
+ it 'returns Service Desk alias address including the project_key' do
create(:service_desk_setting, project: project, project_key: 'key1')
expect(subject).to eq("foo+#{project.full_path_slug}-key1@bar.com")
@@ -2432,11 +2451,35 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
context 'when project_key is not set' do
- it 'returns custom address including the project full path' do
+ it 'returns Service Desk alias address including the project full path' do
expect(subject).to eq("foo+#{project.full_path_slug}-#{project.project_id}-issue-@bar.com")
end
end
end
+
+ context 'when custom email is enabled' do
+ let(:custom_email) { 'support@example.com' }
+
+ before do
+ setting = ServiceDeskSetting.new(project: project, custom_email: custom_email, custom_email_enabled: true)
+ allow(project).to receive(:service_desk_setting).and_return(setting)
+ end
+
+ it 'returns custom email address' do
+ expect(subject).to eq(custom_email)
+ end
+
+ context 'when feature flag service_desk_custom_email is disabled' do
+ before do
+ stub_feature_flags(service_desk_custom_email: false)
+ end
+
+ it 'returns custom email address' do
+ # Don't check for a specific value. Just make sure it's not the custom email
+ expect(subject).not_to eq(custom_email)
+ end
+ end
+ end
end
describe '.with_service_desk_key' do
@@ -3882,16 +3925,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
end
- describe '#mark_primary_write_location' do
- let(:project) { create(:project) }
-
- it 'marks the location with project ID' do
- expect(ApplicationRecord.sticking).to receive(:mark_primary_write_location).with(:project, project.id)
-
- project.mark_primary_write_location
- end
- end
-
describe '#mark_stuck_remote_mirrors_as_failed!' do
it 'fails stuck remote mirrors' do
project = create(:project, :repository, :remote_mirror)
@@ -5086,7 +5119,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
subject { described_class.wrap_with_cte(projects) }
it 'wrapped query matches original' do
- expect(subject.to_sql).to match(/^WITH "projects_cte" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
+ expect(subject.to_sql).to match(/^WITH "projects_cte" AS MATERIALIZED/)
expect(subject).to match_array(projects)
end
end
@@ -6986,8 +7019,11 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
let_it_be_with_reload(:project) { create(:project, :empty_repo) }
let_it_be(:shard_to) { create(:shard, name: 'test_second_storage') }
- let!(:pool1) { create(:pool_repository, source_project: project) }
- let!(:pool2) { create(:pool_repository, shard: shard_to, source_project: project) }
+ let(:disk_path1) { '@pool/aa/bb' }
+ let(:disk_path2) { disk_path1 }
+
+ let!(:pool1) { create(:pool_repository, disk_path: disk_path1, source_project: project) }
+ let!(:pool2) { create(:pool_repository, disk_path: disk_path2, shard: shard_to, source_project: project) }
let(:project_pool) { pool1 }
let(:repository_storage) { shard_to.name }
@@ -7045,6 +7081,14 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
expect { swap_pool_repository! }.to raise_error(ActiveRecord::RecordNotFound)
end
end
+
+ context 'when pool repository has a different disk path' do
+ let(:disk_path2) { '@pool/different' }
+
+ it 'raises record not found error' do
+ expect { swap_pool_repository! }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
end
describe '#leave_pool_repository' do
@@ -7412,17 +7456,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
end
- describe '#pages_lookup_path' do
- let(:pages_domain) { build(:pages_domain) }
- let(:project) { build(:project) }
-
- it 'returns instance of Pages::LookupPath' do
- expect(Pages::LookupPath).to receive(:new).with(project, domain: pages_domain, trim_prefix: 'mygroup').and_call_original
-
- expect(project.pages_lookup_path(domain: pages_domain, trim_prefix: 'mygroup')).to be_a(Pages::LookupPath)
- end
- end
-
describe '.with_pages_deployed' do
it 'returns only projects that have pages deployed' do
_project_without_pages = create(:project)
@@ -8088,14 +8121,6 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
it { is_expected.not_to include(user) }
end
- describe "#metrics_setting" do
- let(:project) { build(:project) }
-
- it 'creates setting if it does not exist' do
- expect(project.metrics_setting).to be_an_instance_of(ProjectMetricsSetting)
- end
- end
-
describe '#enabled_group_deploy_keys' do
let_it_be(:project) { create(:project) }
@@ -9170,6 +9195,20 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
end
+ describe '#supports_lock_on_merge?' do
+ it_behaves_like 'checks self (project) and root ancestor feature flag' do
+ let(:feature_flag) { :enforce_locked_labels_on_merge }
+ let(:feature_flag_method) { :supports_lock_on_merge? }
+ end
+ end
+
+ context 'with loose foreign key on organization_id' do
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let_it_be(:parent) { create(:organization) }
+ let_it_be(:model) { create(:project, organization: parent) }
+ end
+ end
+
private
def finish_job(export_job)
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index ea229ddf31f..af7457c78e2 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -2113,6 +2113,17 @@ RSpec.describe Repository, feature_category: :source_code_management do
end
end
+ describe '#update_refs' do
+ let(:expected_return) { 'updated' }
+ let(:params) { double }
+
+ it 'calls the update_refs method on the raw repo with the same params' do
+ expect(repository.raw_repository).to receive(:update_refs).with(params).and_return('updated')
+
+ expect(repository.update_refs(params)).to eq(expected_return)
+ end
+ end
+
describe '#ff_merge' do
let(:target_branch) { 'ff-target' }
let(:merge_request) do
@@ -2424,7 +2435,6 @@ RSpec.describe Repository, feature_category: :source_code_management do
:has_visible_content?,
:issue_template_names_hash,
:merge_request_template_names_hash,
- :user_defined_metrics_dashboard_paths,
:xcode_project?,
:has_ambiguous_refs?
]
@@ -3822,9 +3832,24 @@ RSpec.describe Repository, feature_category: :source_code_management do
end
end
+ context 'when one of the param is nonexistant' do
+ it 'returns nil' do
+ expect(repository.get_patch_id('HEAD', "f" * 40)).to be_nil
+ end
+ end
+
context 'when two revisions are the same' do
- it 'raises an Gitlab::Git::CommandError error' do
- expect { repository.get_patch_id('HEAD', 'HEAD') }.to raise_error(Gitlab::Git::CommandError)
+ it 'returns nil' do
+ expect(repository.get_patch_id('HEAD', 'HEAD')).to be_nil
+ end
+ end
+
+ context 'when a Gitlab::Git::CommandError is raised' do
+ it 'returns nil' do
+ expect(repository.raw_repository)
+ .to receive(:get_patch_id).and_raise(Gitlab::Git::CommandError)
+
+ expect(repository.get_patch_id('HEAD', "f" * 40)).to be_nil
end
end
end
diff --git a/spec/models/resource_label_event_spec.rb b/spec/models/resource_label_event_spec.rb
index eb28010d57f..8cc89578e0e 100644
--- a/spec/models/resource_label_event_spec.rb
+++ b/spec/models/resource_label_event_spec.rb
@@ -52,24 +52,17 @@ RSpec.describe ResourceLabelEvent, feature_category: :team_planning, type: :mode
end
context 'callbacks' do
- describe '#expire_etag_cache' do
- def expect_expiration(issue)
- expect_next_instance_of(Gitlab::EtagCaching::Store) do |instance|
- expect(instance).to receive(:touch)
- .with("/#{issue.project.namespace.to_param}/#{issue.project.to_param}/noteable/issue/#{issue.id}/notes")
- end
- end
-
- it 'expires resource note etag cache on event save' do
- expect_expiration(subject.issuable)
+ describe '#broadcast_notes_changed' do
+ it 'broadcasts note change on event save' do
+ expect(subject.issuable).to receive(:broadcast_notes_changed)
subject.save!
end
- it 'expires resource note etag cache on event destroy' do
+ it 'broadcasts note change on event destroy' do
subject.save!
- expect_expiration(subject.issuable)
+ expect(subject.issuable).to receive(:broadcast_notes_changed)
subject.destroy!
end
diff --git a/spec/models/resource_state_event_spec.rb b/spec/models/resource_state_event_spec.rb
index de101107268..5bd8b664d23 100644
--- a/spec/models/resource_state_event_spec.rb
+++ b/spec/models/resource_state_event_spec.rb
@@ -58,11 +58,13 @@ RSpec.describe ResourceStateEvent, feature_category: :team_planning, type: :mode
close_issue
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CLOSED }
+ it_behaves_like 'internal event tracking' do
+ subject(:service_action) { close_issue }
+
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CLOSED }
let(:project) { issue.project }
+ let(:namespace) { issue.project.namespace }
let(:user) { issue.author }
- subject(:service_action) { close_issue }
end
end
@@ -81,11 +83,13 @@ RSpec.describe ResourceStateEvent, feature_category: :team_planning, type: :mode
reopen_issue
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_REOPENED }
+ it_behaves_like 'internal event tracking' do
+ subject(:service_action) { reopen_issue }
+
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_REOPENED }
let(:project) { issue.project }
let(:user) { issue.author }
- subject(:service_action) { reopen_issue }
+ let(:namespace) { issue.project.namespace }
end
end
diff --git a/spec/models/review_spec.rb b/spec/models/review_spec.rb
index 2683dc93a4b..75cdea5bca7 100644
--- a/spec/models/review_spec.rb
+++ b/spec/models/review_spec.rb
@@ -41,4 +41,23 @@ RSpec.describe Review do
expect(review.participants).to include(review.author)
end
end
+
+ describe '#from_merge_request_author?' do
+ let(:merge_request) { build_stubbed(:merge_request) }
+ let(:review) { build_stubbed(:review, merge_request: merge_request, author: author) }
+
+ subject(:from_merge_request_author?) { review.from_merge_request_author? }
+
+ context 'when review author is the merge request author' do
+ let(:author) { merge_request.author }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when review author is not the merge request author' do
+ let(:author) { build_stubbed(:user) }
+
+ it { is_expected.to eq(false) }
+ end
+ end
end
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index 0bdaa4994e5..aa5fc231e14 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Route do
+ include LooseForeignKeysHelper
+
let(:group) { create(:group, path: 'git_lab', name: 'git_lab') }
let(:route) { group.route }
@@ -285,6 +287,7 @@ RSpec.describe Route do
expect do
Group.delete(conflicting_group) # delete group with conflicting route
+ process_loose_foreign_key_deletions(record: conflicting_group)
end.to change { described_class.count }.by(-1)
# check the conflicting route is gone
@@ -305,4 +308,11 @@ RSpec.describe Route do
end
end
end
+
+ context 'with loose foreign key on routes.namespace_id' do
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let!(:parent) { create(:namespace) }
+ let!(:model) { parent.route }
+ end
+ end
end
diff --git a/spec/models/snippet_repository_spec.rb b/spec/models/snippet_repository_spec.rb
index c2fbede8ea9..8048f255272 100644
--- a/spec/models/snippet_repository_spec.rb
+++ b/spec/models/snippet_repository_spec.rb
@@ -293,7 +293,7 @@ RSpec.describe SnippetRepository do
it_behaves_like 'snippet repository with git errors', 'README', described_class::CommitError
context 'when user name is invalid' do
- let(:user) { create(:user, name: '.') }
+ let(:user) { create(:user, name: ',') }
it_behaves_like 'snippet repository with git errors', 'non_existing_file', described_class::InvalidSignatureError
end
diff --git a/spec/models/user_custom_attribute_spec.rb b/spec/models/user_custom_attribute_spec.rb
index 7d3806fcdfa..4c27e8d8944 100644
--- a/spec/models/user_custom_attribute_spec.rb
+++ b/spec/models/user_custom_attribute_spec.rb
@@ -49,8 +49,8 @@ RSpec.describe UserCustomAttribute, feature_category: :user_profile do
it 'adds the abuse report ID to user custom attributes' do
subject
- custom_attribute = user.custom_attributes.by_key(UserCustomAttribute::AUTO_BANNED_BY_ABUSE_REPORT_ID).first
- expect(custom_attribute.value).to eq(abuse_report.id.to_s)
+ custom_attribute = user.custom_attributes.by_key(UserCustomAttribute::AUTO_BANNED_BY_ABUSE_REPORT_ID)
+ expect(custom_attribute.map(&:value)).to match([abuse_report.id.to_s])
end
context 'when abuse report is nil' do
@@ -65,6 +65,31 @@ RSpec.describe UserCustomAttribute, feature_category: :user_profile do
end
end
+ describe '.set_banned_by_spam_log' do
+ let_it_be(:user) { create(:user) }
+ let(:spam_log) { create(:spam_log, user: user) }
+
+ subject { described_class.set_banned_by_spam_log(spam_log) }
+
+ it 'adds the spam log ID to user custom attributes' do
+ subject
+
+ custom_attribute = user.custom_attributes.by_key(UserCustomAttribute::AUTO_BANNED_BY_SPAM_LOG_ID)
+ expect(custom_attribute.map(&:value)).to match([spam_log.id.to_s])
+ end
+
+ context 'when the spam log is nil' do
+ let(:spam_log) { nil }
+
+ it 'does not update custom attributes' do
+ subject
+
+ custom_attribute = user.custom_attributes.by_key(UserCustomAttribute::AUTO_BANNED_BY_SPAM_LOG_ID).first
+ expect(custom_attribute).to be_nil
+ end
+ end
+ end
+
describe '#upsert_custom_attributes' do
subject { described_class.upsert_custom_attributes(custom_attributes) }
diff --git a/spec/models/user_preference_spec.rb b/spec/models/user_preference_spec.rb
index 729635b5a27..401a85e2f82 100644
--- a/spec/models/user_preference_spec.rb
+++ b/spec/models/user_preference_spec.rb
@@ -238,6 +238,20 @@ RSpec.describe UserPreference, feature_category: :user_profile do
end
end
+ describe '#keyboard_shortcuts_enabled' do
+ it 'is set to true by default' do
+ pref = described_class.new
+
+ expect(pref.keyboard_shortcuts_enabled).to eq(true)
+ end
+
+ it 'returns assigned value' do
+ pref = described_class.new(keyboard_shortcuts_enabled: false)
+
+ expect(pref.keyboard_shortcuts_enabled).to eq(false)
+ end
+ end
+
describe '#render_whitespace_in_code' do
it 'is set to false by default' do
pref = described_class.new
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 788600194a5..c611c3c26e3 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -65,6 +65,9 @@ RSpec.describe User, feature_category: :user_profile do
it { is_expected.to delegate_method(:project_shortcut_buttons).to(:user_preference) }
it { is_expected.to delegate_method(:project_shortcut_buttons=).to(:user_preference).with_arguments(:args) }
+ it { is_expected.to delegate_method(:keyboard_shortcuts_enabled).to(:user_preference) }
+ it { is_expected.to delegate_method(:keyboard_shortcuts_enabled=).to(:user_preference).with_arguments(:args) }
+
it { is_expected.to delegate_method(:render_whitespace_in_code).to(:user_preference) }
it { is_expected.to delegate_method(:render_whitespace_in_code=).to(:user_preference).with_arguments(:args) }
@@ -168,7 +171,6 @@ RSpec.describe User, feature_category: :user_profile do
it { is_expected.to have_many(:abuse_events).class_name('Abuse::Event').inverse_of(:user) }
it { is_expected.to have_many(:custom_attributes).class_name('UserCustomAttribute') }
it { is_expected.to have_many(:releases).dependent(:nullify) }
- it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:user) }
it { is_expected.to have_many(:reviews).inverse_of(:author) }
it { is_expected.to have_many(:merge_request_assignees).inverse_of(:assignee) }
it { is_expected.to have_many(:merge_request_reviewers).inverse_of(:reviewer) }
@@ -2093,6 +2095,7 @@ RSpec.describe User, feature_category: :user_profile do
it 'uses SecureRandom to generate the incoming email token' do
allow_next_instance_of(User) do |user|
allow(user).to receive(:update_highest_role)
+ allow(user).to receive(:associate_with_enterprise_group)
end
allow_next_instance_of(Namespaces::UserNamespace) do |namespace|
@@ -2906,7 +2909,7 @@ RSpec.describe User, feature_category: :user_profile do
it 'applies defaults to user' do
expect(user.projects_limit).to eq(123)
expect(user.can_create_group).to be_falsey
- expect(user.theme_id).to eq(1)
+ expect(user.theme_id).to eq(3)
end
it 'does not undo projects_limit setting if it matches old DB default of 10' do
@@ -5343,56 +5346,6 @@ RSpec.describe User, feature_category: :user_profile do
end
end
- describe '.ghost' do
- it "creates a ghost user if one isn't already present" do
- ghost = described_class.ghost
-
- expect(ghost).to be_ghost
- expect(ghost).to be_persisted
- expect(ghost.namespace).not_to be_nil
- expect(ghost.namespace).to be_persisted
- expect(ghost.user_type).to eq 'ghost'
- end
-
- it 'does not create a second ghost user if one is already present' do
- expect do
- described_class.ghost
- described_class.ghost
- end.to change { described_class.count }.by(1)
- expect(described_class.ghost).to eq(described_class.ghost)
- end
-
- context "when a regular user exists with the username 'ghost'" do
- it 'creates a ghost user with a non-conflicting username' do
- create(:user, username: 'ghost')
- ghost = described_class.ghost
-
- expect(ghost).to be_persisted
- expect(ghost.username).to eq('ghost1')
- end
- end
-
- context "when a regular user exists with the email 'ghost@example.com'" do
- it 'creates a ghost user with a non-conflicting email' do
- create(:user, email: 'ghost@example.com')
- ghost = described_class.ghost
-
- expect(ghost).to be_persisted
- expect(ghost.email).to eq('ghost1@example.com')
- end
- end
-
- context 'when a domain allowlist is in place' do
- before do
- stub_application_setting(domain_allowlist: ['gitlab.com'])
- end
-
- it 'creates a ghost user' do
- expect(described_class.ghost).to be_persisted
- end
- end
- end
-
describe '#update_two_factor_requirement' do
let(:user) { create :user }
@@ -6088,7 +6041,7 @@ RSpec.describe User, feature_category: :user_profile do
it 'creates an abuse report with the correct data' do
expect { subject }.to change { AbuseReport.count }.from(0).to(1)
expect(AbuseReport.last.attributes).to include({
- reporter_id: described_class.security_bot.id,
+ reporter_id: Users::Internal.security_bot.id,
user_id: user.id,
category: "spam",
message: 'Potential spammer account deletion'
@@ -6109,7 +6062,9 @@ RSpec.describe User, feature_category: :user_profile do
end
context 'when there is an existing abuse report' do
- let!(:abuse_report) { create(:abuse_report, user: user, reporter: described_class.security_bot, message: 'Existing') }
+ let!(:abuse_report) do
+ create(:abuse_report, user: user, reporter: Users::Internal.security_bot, message: 'Existing')
+ end
it 'updates the abuse report' do
subject
@@ -7535,66 +7490,6 @@ RSpec.describe User, feature_category: :user_profile do
end
end
- context 'bot users' do
- shared_examples 'bot users' do |bot_type|
- it 'creates the user if it does not exist' do
- expect do
- described_class.public_send(bot_type)
- end.to change { User.where(user_type: bot_type).count }.by(1)
- end
-
- it 'creates a route for the namespace of the created user' do
- bot_user = described_class.public_send(bot_type)
-
- expect(bot_user.namespace.route).to be_present
- end
-
- it 'does not create a new user if it already exists' do
- described_class.public_send(bot_type)
-
- expect do
- described_class.public_send(bot_type)
- end.not_to change { User.count }
- end
- end
-
- shared_examples 'bot user avatars' do |bot_type, avatar_filename|
- it 'sets the custom avatar for the created bot' do
- bot_user = described_class.public_send(bot_type)
-
- expect(bot_user.avatar.url).to be_present
- expect(bot_user.avatar.filename).to eq(avatar_filename)
- end
- end
-
- it_behaves_like 'bot users', :alert_bot
- it_behaves_like 'bot users', :support_bot
- it_behaves_like 'bot users', :migration_bot
- it_behaves_like 'bot users', :security_bot
- it_behaves_like 'bot users', :ghost
- it_behaves_like 'bot users', :automation_bot
- it_behaves_like 'bot users', :admin_bot
-
- it_behaves_like 'bot user avatars', :alert_bot, 'alert-bot.png'
- it_behaves_like 'bot user avatars', :support_bot, 'support-bot.png'
- it_behaves_like 'bot user avatars', :security_bot, 'security-bot.png'
- it_behaves_like 'bot user avatars', :automation_bot, 'support-bot.png'
- it_behaves_like 'bot user avatars', :admin_bot, 'admin-bot.png'
-
- context 'when bot is the support_bot' do
- subject { described_class.support_bot }
-
- it { is_expected.to be_confirmed }
- end
-
- context 'when bot is the admin bot' do
- subject { described_class.admin_bot }
-
- it { is_expected.to be_admin }
- it { is_expected.to be_confirmed }
- end
- end
-
describe '#confirmation_required_on_sign_in?' do
subject { user.confirmation_required_on_sign_in? }
@@ -7868,7 +7763,7 @@ RSpec.describe User, feature_category: :user_profile do
let_it_be(:external_user) { create(:user, :external) }
let_it_be(:unconfirmed_user) { create(:user, confirmed_at: nil) }
let_it_be(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
- let_it_be(:internal_user) { User.alert_bot.tap { |u| u.confirm } }
+ let_it_be(:internal_user) { Users::Internal.alert_bot.tap { |u| u.confirm } }
it 'does not return blocked or banned users' do
expect(described_class.without_forbidden_states).to match_array(
diff --git a/spec/models/users/credit_card_validation_spec.rb b/spec/models/users/credit_card_validation_spec.rb
index 4db3683c057..486d1c6d3ea 100644
--- a/spec/models/users/credit_card_validation_spec.rb
+++ b/spec/models/users/credit_card_validation_spec.rb
@@ -2,14 +2,19 @@
require 'spec_helper'
-RSpec.describe Users::CreditCardValidation do
+RSpec.describe Users::CreditCardValidation, feature_category: :user_profile do
it { is_expected.to belong_to(:user) }
it { is_expected.to validate_length_of(:holder_name).is_at_most(50) }
it { is_expected.to validate_length_of(:network).is_at_most(32) }
it { is_expected.to validate_numericality_of(:last_digits).is_less_than_or_equal_to(9999) }
- describe '.similar_records' do
+ it { is_expected.to validate_length_of(:last_digits_hash).is_at_most(44) }
+ it { is_expected.to validate_length_of(:holder_name_hash).is_at_most(44) }
+ it { is_expected.to validate_length_of(:expiration_date_hash).is_at_most(44) }
+ it { is_expected.to validate_length_of(:network_hash).is_at_most(44) }
+
+ describe '#similar_records' do
let(:card_details) do
subject.attributes.with_indifferent_access.slice(:expiration_date, :last_digits, :network, :holder_name)
end
@@ -53,6 +58,22 @@ RSpec.describe Users::CreditCardValidation do
end
describe 'scopes' do
+ describe '.find_or_initialize_by_user' do
+ subject(:find_or_initialize_by_user) { described_class.find_or_initialize_by_user(user.id) }
+
+ let_it_be(:user) { create(:user) }
+
+ context 'with no existing credit card record' do
+ it { is_expected.to be_a_new_record }
+ end
+
+ context 'with existing credit card record' do
+ let_it_be(:credit_card_validation) { create(:credit_card_validation, user: user) }
+
+ it { is_expected.to eq(credit_card_validation) }
+ end
+ end
+
describe '.by_banned_user' do
let(:banned_user) { create(:banned_user) }
let!(:credit_card) { create(:credit_card_validation) }
@@ -154,4 +175,122 @@ RSpec.describe Users::CreditCardValidation do
it { is_expected.not_to be_used_by_banned_user }
end
end
+
+ describe 'before_save' do
+ describe '#set_last_digits_hash' do
+ let(:credit_card_validation) { build(:credit_card_validation, last_digits: last_digits) }
+
+ subject(:save_credit_card_validation) { credit_card_validation.save! }
+
+ context 'when last_digits are nil' do
+ let(:last_digits) { nil }
+
+ it { expect { save_credit_card_validation }.not_to change { credit_card_validation.last_digits_hash } }
+ end
+
+ context 'when last_digits has a blank value' do
+ let(:last_digits) { ' ' }
+
+ it { expect { save_credit_card_validation }.not_to change { credit_card_validation.last_digits_hash } }
+ end
+
+ context 'when last_digits has a value' do
+ let(:last_digits) { 1111 }
+ let(:expected_last_digits_hash) { Gitlab::CryptoHelper.sha256(last_digits) }
+
+ it 'assigns correct last_digits_hash value' do
+ expect { save_credit_card_validation }.to change {
+ credit_card_validation.last_digits_hash
+ }.from(nil).to(expected_last_digits_hash)
+ end
+ end
+ end
+
+ describe '#set_holder_name_hash' do
+ let(:credit_card_validation) { build(:credit_card_validation, holder_name: holder_name) }
+
+ subject(:save_credit_card_validation) { credit_card_validation.save! }
+
+ context 'when holder_name is nil' do
+ let(:holder_name) { nil }
+
+ it { expect { save_credit_card_validation }.not_to change { credit_card_validation.holder_name_hash } }
+ end
+
+ context 'when holder_name has a blank value' do
+ let(:holder_name) { ' ' }
+
+ it { expect { save_credit_card_validation }.not_to change { credit_card_validation.holder_name_hash } }
+ end
+
+ context 'when holder_name has a value' do
+ let(:holder_name) { 'John Smith' }
+ let(:expected_holder_name_hash) { Gitlab::CryptoHelper.sha256(holder_name.downcase) }
+
+ it 'lowercases holder_name and assigns correct holder_name_hash value' do
+ expect { save_credit_card_validation }.to change {
+ credit_card_validation.holder_name_hash
+ }.from(nil).to(expected_holder_name_hash)
+ end
+ end
+ end
+
+ describe '#set_network_hash' do
+ let(:credit_card_validation) { build(:credit_card_validation, network: network) }
+
+ subject(:save_credit_card_validation) { credit_card_validation.save! }
+
+ context 'when network is nil' do
+ let(:network) { nil }
+
+ it { expect { save_credit_card_validation }.not_to change { credit_card_validation.network_hash } }
+ end
+
+ context 'when network has a blank value' do
+ let(:network) { ' ' }
+
+ it { expect { save_credit_card_validation }.not_to change { credit_card_validation.network_hash } }
+ end
+
+ context 'when network has a value' do
+ let(:network) { 'Visa' }
+ let(:expected_network_hash) { Gitlab::CryptoHelper.sha256(network.downcase) }
+
+ it 'lowercases network and assigns correct network_hash value' do
+ expect { save_credit_card_validation }.to change {
+ credit_card_validation.network_hash
+ }.from(nil).to(expected_network_hash)
+ end
+ end
+ end
+
+ describe '#set_expiration_date_hash' do
+ let(:credit_card_validation) { build(:credit_card_validation, expiration_date: expiration_date) }
+
+ subject(:save_credit_card_validation) { credit_card_validation.save! }
+
+ context 'when expiration_date is nil' do
+ let(:expiration_date) { nil }
+
+ it { expect { save_credit_card_validation }.not_to change { credit_card_validation.expiration_date_hash } }
+ end
+
+ context 'when expiration_date has a blank value' do
+ let(:expiration_date) { ' ' }
+
+ it { expect { save_credit_card_validation }.not_to change { credit_card_validation.expiration_date_hash } }
+ end
+
+ context 'when expiration_date has a value' do
+ let(:expiration_date) { 1.year.from_now.to_date }
+ let(:expected_expiration_date_hash) { Gitlab::CryptoHelper.sha256(expiration_date.to_s) }
+
+ it 'assigns correct expiration_date_hash value' do
+ expect { save_credit_card_validation }.to change {
+ credit_card_validation.expiration_date_hash
+ }.from(nil).to(expected_expiration_date_hash)
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/users/group_visit_spec.rb b/spec/models/users/group_visit_spec.rb
new file mode 100644
index 00000000000..63c4631ad7d
--- /dev/null
+++ b/spec/models/users/group_visit_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::GroupVisit, feature_category: :navigation do
+ let_it_be(:entity) { create(:group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:base_time) { DateTime.now }
+
+ before do
+ described_class.create!(entity_id: entity.id, user_id: user.id, visited_at: base_time)
+ end
+
+ it_behaves_like 'namespace visits model'
+
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let!(:model) { create(:group_visit, entity_id: entity.id, user_id: user.id, visited_at: base_time) }
+ let!(:parent) { entity }
+ end
+
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let!(:model) { create(:group_visit, entity_id: entity.id, user_id: user.id, visited_at: base_time) }
+ let!(:parent) { user }
+ end
+end
diff --git a/spec/models/users/project_visit_spec.rb b/spec/models/users/project_visit_spec.rb
new file mode 100644
index 00000000000..38747bd6462
--- /dev/null
+++ b/spec/models/users/project_visit_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::ProjectVisit, feature_category: :navigation do
+ let_it_be(:entity) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:base_time) { DateTime.now }
+
+ before do
+ described_class.create!(entity_id: entity.id, user_id: user.id, visited_at: base_time)
+ end
+
+ it_behaves_like 'namespace visits model'
+
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let!(:model) { create(:project_visit, entity_id: entity.id, user_id: user.id, visited_at: base_time) }
+ let!(:parent) { entity }
+ end
+
+ it_behaves_like 'cleanup by a loose foreign key' do
+ let!(:model) { create(:project_visit, entity_id: entity.id, user_id: user.id, visited_at: base_time) }
+ let!(:parent) { user }
+ end
+end
diff --git a/spec/models/work_item_spec.rb b/spec/models/work_item_spec.rb
index 541199e08cb..4b675faf99e 100644
--- a/spec/models/work_item_spec.rb
+++ b/spec/models/work_item_spec.rb
@@ -165,7 +165,8 @@ RSpec.describe WorkItem, feature_category: :portfolio_management do
subject { work_item.supported_quick_action_commands }
it 'returns quick action commands supported for all work items' do
- is_expected.to include(:title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to)
+ is_expected.to include(:title, :reopen, :close, :cc, :tableflip, :shrug, :type, :promote_to, :checkin_reminder,
+ :subscribe, :unsubscribe, :confidential, :award)
end
context 'when work item supports the assignee widget' do
@@ -635,4 +636,82 @@ RSpec.describe WorkItem, feature_category: :portfolio_management do
end
end
end
+
+ describe '#linked_work_items' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:authorized_project) { create(:project) }
+ let_it_be(:authorized_project2) { create(:project) }
+ let_it_be(:unauthorized_project) { create(:project, :private) }
+
+ let_it_be(:authorized_item_a) { create(:work_item, project: authorized_project) }
+ let_it_be(:authorized_item_b) { create(:work_item, project: authorized_project) }
+ let_it_be(:authorized_item_c) { create(:work_item, project: authorized_project2) }
+ let_it_be(:unauthorized_item) { create(:work_item, project: unauthorized_project) }
+
+ let_it_be(:work_item_link_a) { create(:work_item_link, source: authorized_item_a, target: authorized_item_b) }
+ let_it_be(:work_item_link_b) { create(:work_item_link, source: authorized_item_a, target: unauthorized_item) }
+ let_it_be(:work_item_link_c) { create(:work_item_link, source: authorized_item_a, target: authorized_item_c) }
+
+ before_all do
+ authorized_project.add_guest(user)
+ authorized_project2.add_guest(user)
+ end
+
+ it 'returns only authorized linked work items for given user' do
+ expect(authorized_item_a.linked_work_items(user)).to contain_exactly(authorized_item_b, authorized_item_c)
+ end
+
+ it 'returns work items with valid work_item_link_type' do
+ link_types = authorized_item_a.linked_work_items(user).map(&:issue_link_type)
+
+ expect(link_types).not_to be_empty
+ expect(link_types).not_to include(nil)
+ end
+
+ it 'returns work items including the link creation time' do
+ dates = authorized_item_a.linked_work_items(user).map(&:issue_link_created_at)
+
+ expect(dates).not_to be_empty
+ expect(dates).not_to include(nil)
+ end
+
+ it 'returns work items including the link update time' do
+ dates = authorized_item_a.linked_work_items(user).map(&:issue_link_updated_at)
+
+ expect(dates).not_to be_empty
+ expect(dates).not_to include(nil)
+ end
+
+ context 'when a user cannot read cross project' do
+ it 'only returns work items within the same project' do
+ allow(Ability).to receive(:allowed?).with(user, :read_all_resources, :global).and_call_original
+ expect(Ability).to receive(:allowed?).with(user, :read_cross_project).and_return(false)
+
+ expect(authorized_item_a.linked_work_items(user)).to contain_exactly(authorized_item_b)
+ end
+ end
+
+ context 'when filtering by link type' do
+ before do
+ work_item_link_c.update!(link_type: 'blocks')
+ end
+
+ it 'returns authorized work items with given link type' do
+ expect(authorized_item_a.linked_work_items(user, link_type: 'relates_to')).to contain_exactly(authorized_item_b)
+ end
+ end
+
+ context 'when authorize option is true and current_user is nil' do
+ it 'returns empty result' do
+ expect(authorized_item_a.linked_work_items).to be_empty
+ end
+ end
+
+ context 'when authorize option is false' do
+ it 'returns all work items linked to the work item' do
+ expect(authorized_item_a.linked_work_items(authorize: false))
+ .to contain_exactly(authorized_item_b, authorized_item_c, unauthorized_item)
+ end
+ end
+ end
end
diff --git a/spec/models/work_items/related_work_item_link_spec.rb b/spec/models/work_items/related_work_item_link_spec.rb
index 349e4c0ba49..3217ac52489 100644
--- a/spec/models/work_items/related_work_item_link_spec.rb
+++ b/spec/models/work_items/related_work_item_link_spec.rb
@@ -21,6 +21,46 @@ RSpec.describe WorkItems::RelatedWorkItemLink, type: :model, feature_category: :
let_it_be(:item_type) { described_class.issuable_name }
end
+ describe 'validations' do
+ let_it_be(:task1) { create(:work_item, :task, project: project) }
+ let_it_be(:task2) { create(:work_item, :task, project: project) }
+ let_it_be(:task3) { create(:work_item, :task, project: project) }
+
+ subject(:link) { build(:work_item_link, source_id: task1.id, target_id: task2.id) }
+
+ describe '#validate_max_number_of_links' do
+ shared_examples 'invalid due to exceeding max number of links' do
+ let(:error_msg) { 'This work item would exceed the maximum number of linked items.' }
+
+ before do
+ create(:work_item_link, source: source, target: target)
+ stub_const("#{described_class}::MAX_LINKS_COUNT", 1)
+ end
+
+ specify do
+ is_expected.to be_invalid
+ expect(link.errors.messages[error_item]).to include(error_msg)
+ end
+ end
+
+ context 'when source exceeds max' do
+ let(:source) { task1 }
+ let(:target) { task3 }
+ let(:error_item) { :source }
+
+ it_behaves_like 'invalid due to exceeding max number of links'
+ end
+
+ context 'when target exceeds max' do
+ let(:source) { task2 }
+ let(:target) { task3 }
+ let(:error_item) { :target }
+
+ it_behaves_like 'invalid due to exceeding max number of links'
+ end
+ end
+ end
+
describe '.issuable_type' do
it { expect(described_class.issuable_type).to eq(:issue) }
end
diff --git a/spec/models/work_items/widgets/description_spec.rb b/spec/models/work_items/widgets/description_spec.rb
index c24dc9cfb9c..a089cc32ecd 100644
--- a/spec/models/work_items/widgets/description_spec.rb
+++ b/spec/models/work_items/widgets/description_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe WorkItems::Widgets::Description do
work_item.update!(last_edited_by: nil)
end
- it { is_expected.to eq(User.ghost) }
+ it { is_expected.to eq(Users::Internal.ghost) }
end
end
diff --git a/spec/models/work_items/widgets/linked_items_spec.rb b/spec/models/work_items/widgets/linked_items_spec.rb
index b4a53b75561..fb3001b286b 100644
--- a/spec/models/work_items/widgets/linked_items_spec.rb
+++ b/spec/models/work_items/widgets/linked_items_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe WorkItems::Widgets::LinkedItems, feature_category: :portfolio_man
it { is_expected.to eq(:linked_items) }
end
- describe '#related_issues' do
- it { expect(described_class.new(work_item).related_issues(user)).to eq(work_item.related_issues(user)) }
+ describe '#linked_work_items' do
+ it { expect(described_class.new(work_item).linked_work_items(user)).to eq(work_item.linked_work_items(user)) }
end
end
diff --git a/spec/models/x509_certificate_spec.rb b/spec/models/x509_certificate_spec.rb
index 5723bd80739..a550b2caa44 100644
--- a/spec/models/x509_certificate_spec.rb
+++ b/spec/models/x509_certificate_spec.rb
@@ -5,7 +5,6 @@ require 'spec_helper'
RSpec.describe X509Certificate do
describe 'validation' do
it { is_expected.to validate_presence_of(:subject_key_identifier) }
- it { is_expected.to validate_presence_of(:subject) }
it { is_expected.to validate_presence_of(:email) }
it { is_expected.to validate_presence_of(:serial_number) }
it { is_expected.to validate_presence_of(:x509_issuer_id) }
diff --git a/spec/models/x509_issuer_spec.rb b/spec/models/x509_issuer_spec.rb
index 3d04adf7e26..31470a443a2 100644
--- a/spec/models/x509_issuer_spec.rb
+++ b/spec/models/x509_issuer_spec.rb
@@ -5,8 +5,6 @@ require 'spec_helper'
RSpec.describe X509Issuer do
describe 'validation' do
it { is_expected.to validate_presence_of(:subject_key_identifier) }
- it { is_expected.to validate_presence_of(:subject) }
- it { is_expected.to validate_presence_of(:crl_url) }
end
describe '.safe_create!' do
diff --git a/spec/policies/ci/bridge_policy_spec.rb b/spec/policies/ci/bridge_policy_spec.rb
index d23355b4c1e..29eb4d94c03 100644
--- a/spec/policies/ci/bridge_policy_spec.rb
+++ b/spec/policies/ci/bridge_policy_spec.rb
@@ -16,22 +16,34 @@ RSpec.describe Ci::BridgePolicy do
it_behaves_like 'a deployable job policy', :ci_bridge
describe '#play_job' do
- before do
- fake_access = double('Gitlab::UserAccess')
- expect(fake_access).to receive(:can_update_branch?).with('master').and_return(can_update_branch)
- expect(Gitlab::UserAccess).to receive(:new).with(user, container: downstream_project).and_return(fake_access)
- end
+ context 'when downstream project exists' do
+ before do
+ fake_access = double('Gitlab::UserAccess')
+ expect(fake_access).to receive(:can_update_branch?).with('master').and_return(can_update_branch)
+ expect(Gitlab::UserAccess).to receive(:new).with(user, container: downstream_project).and_return(fake_access)
+ end
+
+ context 'when user can update the downstream branch' do
+ let(:can_update_branch) { true }
- context 'when user can update the downstream branch' do
- let(:can_update_branch) { true }
+ it 'allows' do
+ expect(policy).to be_allowed :play_job
+ end
+ end
+
+ context 'when user can not update the downstream branch' do
+ let(:can_update_branch) { false }
- it 'allows' do
- expect(policy).to be_allowed :play_job
+ it 'does not allow' do
+ expect(policy).not_to be_allowed :play_job
+ end
end
end
- context 'when user can not update the downstream branch' do
- let(:can_update_branch) { false }
+ context 'when downstream project does not exist' do
+ before do
+ bridge.update!(options: { trigger: { project: 'deleted-project' } })
+ end
it 'does not allow' do
expect(policy).not_to be_allowed :play_job
diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb
index 8a5b80e3051..e74bf8f7efa 100644
--- a/spec/policies/ci/pipeline_policy_spec.rb
+++ b/spec/policies/ci/pipeline_policy_spec.rb
@@ -142,5 +142,30 @@ RSpec.describe Ci::PipelinePolicy, :models do
end
end
end
+
+ describe 'read_dependency' do
+ let(:project) { create(:project, :repository) }
+
+ before do
+ project.add_developer(user)
+ allow(policy).to receive(:can?).with(:read_dependency, project).and_return(can_read_project_dependencies)
+ end
+
+ context 'when user is allowed to read project dependencies' do
+ let(:can_read_project_dependencies) { true }
+
+ it 'is enabled' do
+ expect(policy).to be_allowed :read_dependency
+ end
+ end
+
+ context 'when user is not allowed to read project dependencies' do
+ let(:can_read_project_dependencies) { false }
+
+ it 'is disabled' do
+ expect(policy).not_to be_allowed :read_dependency
+ end
+ end
+ end
end
end
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
index 4fafe392aac..475e8f981dd 100644
--- a/spec/policies/global_policy_spec.rb
+++ b/spec/policies/global_policy_spec.rb
@@ -509,7 +509,7 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
end
context 'when internal' do
- let(:current_user) { User.ghost }
+ let(:current_user) { Users::Internal.ghost }
it { is_expected.to be_disallowed(:use_slash_commands) }
end
@@ -695,4 +695,18 @@ RSpec.describe GlobalPolicy, feature_category: :shared do
it { is_expected.to be_disallowed(:create_instance_runner) }
end
end
+
+ describe 'create_organization' do
+ context 'with regular user' do
+ let(:current_user) { user }
+
+ it { is_expected.to be_allowed(:create_organization) }
+ end
+
+ context 'with anonymous' do
+ let(:current_user) { nil }
+
+ it { is_expected.to be_disallowed(:create_organizatinon) }
+ end
+ end
end
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index 89f083a69d6..4d72de27046 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -162,19 +162,16 @@ RSpec.describe GroupPolicy, feature_category: :system_access do
group.update!(subgroup_creation_level: ::Gitlab::Access::MAINTAINER_SUBGROUP_ACCESS)
end
- it 'allows every maintainer permission plus creating subgroups' do
- create_subgroup_permission = [:create_subgroup]
- updated_maintainer_permissions =
- maintainer_permissions + create_subgroup_permission
- updated_owner_permissions =
- owner_permissions - create_subgroup_permission
-
+ it 'allows permissions from lower roles' do
expect_allowed(*public_permissions)
expect_allowed(*guest_permissions)
expect_allowed(*reporter_permissions)
expect_allowed(*developer_permissions)
- expect_allowed(*updated_maintainer_permissions)
- expect_disallowed(*updated_owner_permissions)
+ end
+
+ it 'allows every maintainer permission plus creating subgroups' do
+ expect_allowed(:create_subgroup, *maintainer_permissions)
+ expect_disallowed(*(owner_permissions - [:create_subgroup]))
end
end
@@ -245,7 +242,7 @@ RSpec.describe GroupPolicy, feature_category: :system_access do
end
context 'migration bot' do
- let_it_be(:migration_bot) { User.migration_bot }
+ let_it_be(:migration_bot) { Users::Internal.migration_bot }
let_it_be(:current_user) { migration_bot }
it :aggregate_failures do
@@ -354,6 +351,9 @@ RSpec.describe GroupPolicy, feature_category: :system_access do
expect_allowed(*guest_permissions)
expect_allowed(*reporter_permissions)
expect_allowed(*developer_permissions)
+ end
+
+ it 'allows every maintainer permission plus creating subgroups' do
expect_allowed(*maintainer_permissions)
expect_disallowed(*owner_permissions)
end
@@ -1261,7 +1261,7 @@ RSpec.describe GroupPolicy, feature_category: :system_access do
context 'support bot' do
let_it_be_with_refind(:group) { create(:group, :private, :crm_enabled) }
- let_it_be(:current_user) { User.support_bot }
+ let_it_be(:current_user) { Users::Internal.support_bot }
before do
allow(Gitlab::ServiceDesk).to receive(:supported?).and_return(true)
diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb
index 1142d6f80fd..743d96ee3dd 100644
--- a/spec/policies/issue_policy_spec.rb
+++ b/spec/policies/issue_policy_spec.rb
@@ -18,8 +18,8 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do
let(:group) { create(:group, :public) }
let(:reporter_from_group_link) { create(:user) }
let(:non_member) { create(:user) }
- let(:support_bot) { User.support_bot }
- let(:alert_bot) { User.alert_bot }
+ let(:support_bot) { Users::Internal.support_bot }
+ let(:alert_bot) { Users::Internal.alert_bot }
def permissions(user, issue)
described_class.new(user, issue)
diff --git a/spec/policies/organizations/organization_policy_spec.rb b/spec/policies/organizations/organization_policy_spec.rb
index e51362227c9..3fcfa63b1b2 100644
--- a/spec/policies/organizations/organization_policy_spec.rb
+++ b/spec/policies/organizations/organization_policy_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Organizations::OrganizationPolicy, feature_category: :cell do
let_it_be(:organization) { create(:organization) }
+ let_it_be(:current_user) { create :user }
subject(:policy) { described_class.new(current_user, organization) }
@@ -19,6 +20,7 @@ RSpec.describe Organizations::OrganizationPolicy, feature_category: :cell do
context 'when admin mode is enabled', :enable_admin_mode do
it { is_expected.to be_allowed(:admin_organization) }
it { is_expected.to be_allowed(:read_organization) }
+ it { is_expected.to be_allowed(:read_organization_user) }
end
context 'when admin mode is disabled' do
@@ -27,13 +29,19 @@ RSpec.describe Organizations::OrganizationPolicy, feature_category: :cell do
end
end
- context 'when the user is an organization user' do
- let_it_be(:current_user) { create :user }
-
+ context 'when the user is part of the organization' do
before do
create :organization_user, organization: organization, user: current_user
end
+ it { is_expected.to be_allowed(:read_organization_user) }
+ it { is_expected.to be_allowed(:read_organization) }
+ end
+
+ context 'when the user is not part of the organization' do
+ it { is_expected.to be_disallowed(:read_organization_user) }
+ # All organizations are currently public, and hence they are allowed to be read
+ # even if the user is not a part of the organization.
it { is_expected.to be_allowed(:read_organization) }
end
end
diff --git a/spec/policies/packages/policies/project_policy_spec.rb b/spec/policies/packages/policies/project_policy_spec.rb
index fde10f64be8..1f8a653f984 100644
--- a/spec/policies/packages/policies/project_policy_spec.rb
+++ b/spec/policies/packages/policies/project_policy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Policies::ProjectPolicy do
+RSpec.describe Packages::Policies::ProjectPolicy, feature_category: :package_registry do
include_context 'ProjectPolicy context'
let(:project) { public_project }
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 350d834e63e..e7c2dcc4158 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -828,7 +828,7 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
end
context 'alert bot' do
- let(:current_user) { User.alert_bot }
+ let(:current_user) { Users::Internal.alert_bot }
it { is_expected.to be_allowed(:reporter_access) }
@@ -882,7 +882,7 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
end
context 'support bot' do
- let(:current_user) { User.support_bot }
+ let(:current_user) { Users::Internal.support_bot }
context 'with service desk disabled' do
it { expect_allowed(:public_access) }
diff --git a/spec/presenters/blob_presenter_spec.rb b/spec/presenters/blob_presenter_spec.rb
index 150c7bd5f3e..a249597e900 100644
--- a/spec/presenters/blob_presenter_spec.rb
+++ b/spec/presenters/blob_presenter_spec.rb
@@ -130,7 +130,7 @@ RSpec.describe BlobPresenter do
describe '#pipeline_editor_path' do
context 'when blob is .gitlab-ci.yml' do
- before do
+ before_all do
project.repository.create_file(
user,
'.gitlab-ci.yml',
@@ -144,6 +144,16 @@ RSpec.describe BlobPresenter do
let(:path) { '.gitlab-ci.yml' }
it { expect(presenter.pipeline_editor_path).to eq("/#{project.full_path}/-/ci/editor?branch_name=#{ref}") }
+
+ context 'when ref includes the qualifier' do
+ let(:ref) { 'refs/heads/main' }
+
+ it 'returns path to unqualified ref' do
+ allow(blob).to receive(:ref_type).and_return('heads')
+
+ expect(presenter.pipeline_editor_path).to eq("/#{project.full_path}/-/ci/editor?branch_name=main")
+ end
+ end
end
end
diff --git a/spec/presenters/event_presenter_spec.rb b/spec/presenters/event_presenter_spec.rb
index 9093791421d..3f34c96ad8e 100644
--- a/spec/presenters/event_presenter_spec.rb
+++ b/spec/presenters/event_presenter_spec.rb
@@ -76,4 +76,104 @@ RSpec.describe EventPresenter do
.to have_attributes(note_target_type_name: 'issue')
end
end
+
+ describe '#push_activity_description' do
+ subject { event.present.push_activity_description }
+
+ context 'when event is a regular event' do
+ let(:event) { build(:event, project: project) }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when event is a push event' do
+ let!(:push_event_payload) { build(:push_event_payload, event: event, ref_count: ref_count) }
+ let(:event) { build(:push_event, project: project) }
+
+ context 'when it is an individual event' do
+ let(:ref_count) { nil }
+
+ it { is_expected.to eq 'pushed to branch' }
+ end
+
+ context 'when it is a batch event' do
+ let(:ref_count) { 1 }
+
+ it { is_expected.to eq 'pushed to 1 branch' }
+ end
+ end
+ end
+
+ describe '#batch_push?' do
+ subject { event.present.batch_push? }
+
+ context 'when event is a regular event' do
+ let(:event) { build(:event, project: project) }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when event is a push event' do
+ let!(:push_event_payload) { build(:push_event_payload, event: event, ref_count: ref_count) }
+ let(:event) { build(:push_event, project: project) }
+
+ context 'when it is an individual event' do
+ let(:ref_count) { nil }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when it is a batch event' do
+ let(:ref_count) { 1 }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+ end
+
+ describe '#linked_to_reference?' do
+ subject { event.present.linked_to_reference? }
+
+ context 'when event is a regular event' do
+ let(:event) { build(:event, project: project) }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when event is a push event' do
+ let!(:push_event_payload) { build(:push_event_payload, event: event, ref: ref, ref_type: ref_type) }
+ let(:ref) { 'master' }
+ let(:ref_type) { :branch }
+
+ context 'when event belongs to group' do
+ let(:event) { build(:push_event, group: group) }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when event belongs to project' do
+ let(:event) { build(:push_event, project: project) }
+
+ it { is_expected.to be_falsey }
+
+ context 'when matching tag exists' do
+ let(:ref_type) { :tag }
+
+ before do
+ allow(project.repository).to receive(:tag_exists?).with(ref).and_return(true)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when matching branch exists' do
+ before do
+ allow(project.repository).to receive(:branch_exists?).with(ref).and_return(true)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+ end
+ end
end
diff --git a/spec/presenters/gitlab/blame_presenter_spec.rb b/spec/presenters/gitlab/blame_presenter_spec.rb
index b3b9e133a73..409d2de3fc1 100644
--- a/spec/presenters/gitlab/blame_presenter_spec.rb
+++ b/spec/presenters/gitlab/blame_presenter_spec.rb
@@ -70,4 +70,33 @@ RSpec.describe Gitlab::BlamePresenter do
end
end
end
+
+ describe '#groups_commit_data' do
+ shared_examples 'groups_commit_data' do
+ it 'combines group and commit data' do
+ data = subject.groups_commit_data
+
+ aggregate_failures do
+ expect(data.size).to eq 18
+ expect(data.first[:commit].sha).to eq("913c66a37b4a45b9769037c55c2d238bd0942d2e")
+ expect(data.first[:lines].size).to eq 3
+ expect(data.first[:commit_data].author_avatar).to include('src="https://www.gravatar.com/')
+ end
+ end
+ end
+
+ it_behaves_like 'groups_commit_data'
+
+ context 'when page is not sent as attribute' do
+ subject { described_class.new(blame, project: project, path: path) }
+
+ it_behaves_like 'groups_commit_data'
+ end
+
+ context 'when project is not sent as attribute' do
+ subject { described_class.new(blame, path: path, page: 1) }
+
+ it_behaves_like 'groups_commit_data'
+ end
+ end
end
diff --git a/spec/presenters/issue_presenter_spec.rb b/spec/presenters/issue_presenter_spec.rb
index f9a3be9bbed..99ab8582f77 100644
--- a/spec/presenters/issue_presenter_spec.rb
+++ b/spec/presenters/issue_presenter_spec.rb
@@ -98,7 +98,7 @@ RSpec.describe IssuePresenter do
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)
+ create(:issue, project: project, author: Users::Internal.support_bot, service_desk_reply_to: email)
end
let(:user) { nil }
diff --git a/spec/presenters/packages/composer/packages_presenter_spec.rb b/spec/presenters/packages/composer/packages_presenter_spec.rb
index ae88acea61d..a3a1a4c4e85 100644
--- a/spec/presenters/packages/composer/packages_presenter_spec.rb
+++ b/spec/presenters/packages/composer/packages_presenter_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe ::Packages::Composer::PackagesPresenter do
let_it_be(:package_name) { 'sample-project' }
let_it_be(:json) { { 'name' => package_name } }
let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, :custom_repo, files: { 'composer.json' => json.to_json }, group: group) }
+ let_it_be(:project) { create(:project, :public, :custom_repo, files: { 'composer.json' => json.to_json }, group: group) }
let!(:package1) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '1.0.0', json: json) }
let!(:package2) { create(:composer_package, :with_metadatum, project: project, name: package_name, version: '2.0.0', json: json) }
diff --git a/spec/presenters/projects/security/configuration_presenter_spec.rb b/spec/presenters/projects/security/configuration_presenter_spec.rb
index 4fe459a798a..beabccf6639 100644
--- a/spec/presenters/projects/security/configuration_presenter_spec.rb
+++ b/spec/presenters/projects/security/configuration_presenter_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::Security::ConfigurationPresenter do
+RSpec.describe Projects::Security::ConfigurationPresenter, feature_category: :software_composition_analysis do
include Gitlab::Routing.url_helpers
using RSpec::Parameterized::TableSyntax
@@ -87,6 +87,7 @@ RSpec.describe Projects::Security::ConfigurationPresenter do
expect(feature['available']).to eq(true)
expect(feature['can_enable_by_merge_request']).to eq(true)
expect(feature['meta_info_path']).to be_nil
+ expect(feature['on_demand_available']).to eq(false)
end
context 'when checking features configured status' do
diff --git a/spec/presenters/snippet_blob_presenter_spec.rb b/spec/presenters/snippet_blob_presenter_spec.rb
index cdd02241fbf..5777d78608e 100644
--- a/spec/presenters/snippet_blob_presenter_spec.rb
+++ b/spec/presenters/snippet_blob_presenter_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe SnippetBlobPresenter do
let(:blob) { blob_at(file) }
it 'returns rich markdown content' do
- expect(subject).to include('file-content md')
+ expect(subject).to include('file-content js-markup-content md')
end
end
diff --git a/spec/rake_helper.rb b/spec/rake_helper.rb
index 0386fef5134..53bd36542b7 100644
--- a/spec/rake_helper.rb
+++ b/spec/rake_helper.rb
@@ -6,7 +6,7 @@ require 'rake'
RSpec.configure do |config|
config.include RakeHelpers
- config.before(:all) do
+ config.before(:all, type: :task) do
Rake.application.rake_require 'tasks/gitlab/helpers'
Rake::Task.define_task :environment
end
diff --git a/spec/requests/admin/abuse_reports_controller_spec.rb b/spec/requests/admin/abuse_reports_controller_spec.rb
index c443a441af8..c25fb18e5b8 100644
--- a/spec/requests/admin/abuse_reports_controller_spec.rb
+++ b/spec/requests/admin/abuse_reports_controller_spec.rb
@@ -30,16 +30,14 @@ RSpec.describe Admin::AbuseReportsController, type: :request, feature_category:
expect(assigns(:abuse_reports).first.closed?).to eq true
end
- context 'when abuse_reports_list flag is disabled' do
- before do
- stub_feature_flags(abuse_reports_list: false)
- end
+ it 'labels does not introduce N+1 queries' do
+ get admin_abuse_reports_path # warm up
- it 'returns all reports by default' do
- get admin_abuse_reports_path
+ control = ActiveRecord::QueryRecorder.new { get admin_abuse_reports_path }
- expect(assigns(:abuse_reports).count).to eq 2
- end
+ create_list(:abuse_report, 2)
+
+ expect { get admin_abuse_reports_path }.to issue_same_number_of_queries_as(control).ignoring_cached_queries
end
end
@@ -53,13 +51,62 @@ RSpec.describe Admin::AbuseReportsController, type: :request, feature_category:
end
end
- shared_examples 'moderates user' do
+ describe 'PUT #update' do
+ let_it_be(:report) { create(:abuse_report) }
+ let_it_be(:label1) { create(:abuse_report_label, title: 'Uno') }
+
+ let(:params) { { label_ids: [Gitlab::GlobalId.build(label1, id: label1.id).to_s] } }
+ let(:expected_params) { ActionController::Parameters.new(params).permit! }
+
+ subject(:request) { put admin_abuse_report_path(report, params) }
+
+ it 'invokes the Admin::AbuseReports::UpdateService' do
+ expect_next_instance_of(Admin::AbuseReports::UpdateService, report, admin, expected_params) do |service|
+ expect(service).to receive(:execute).and_call_original
+ end
+
+ request
+ end
+
+ context 'when the service response is a success' do
+ before do
+ allow_next_instance_of(Admin::AbuseReports::UpdateService, report, admin, expected_params) do |service|
+ allow(service).to receive(:execute).and_return(ServiceResponse.success)
+ end
+
+ request
+ end
+
+ it 'returns with a success status' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the service response is an error' do
+ let(:error_message) { 'Error updating abuse report' }
+
+ before do
+ allow_next_instance_of(Admin::AbuseReports::UpdateService, report, admin, expected_params) do |service|
+ allow(service).to receive(:execute).and_return(ServiceResponse.error(message: error_message))
+ end
+
+ request
+ end
+
+ it 'returns the service response message with a failed status' do
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response['message']).to eq(error_message)
+ end
+ end
+ end
+
+ describe 'PUT #moderate_user' do
let(:report) { create(:abuse_report) }
let(:params) { { user_action: 'block_user', close: 'true', reason: 'spam', comment: 'obvious spam' } }
let(:expected_params) { ActionController::Parameters.new(params).permit! }
let(:message) { 'Service response' }
- subject(:request) { put path }
+ subject(:request) { put moderate_user_admin_abuse_report_path(report, params) }
it 'invokes the Admin::AbuseReports::ModerateUserService' do
expect_next_instance_of(Admin::AbuseReports::ModerateUserService, report, admin, expected_params) do |service|
@@ -100,18 +147,6 @@ RSpec.describe Admin::AbuseReportsController, type: :request, feature_category:
end
end
- describe 'PUT #update' do
- let(:path) { admin_abuse_report_path(report, params) }
-
- it_behaves_like 'moderates user'
- end
-
- describe 'PUT #moderate_user' do
- let(:path) { moderate_user_admin_abuse_report_path(report, params) }
-
- it_behaves_like 'moderates user'
- end
-
describe 'DELETE #destroy' do
let!(:report) { create(:abuse_report) }
let(:params) { {} }
diff --git a/spec/requests/admin/users_controller_spec.rb b/spec/requests/admin/users_controller_spec.rb
index 21cf8ab2c79..e525d615b50 100644
--- a/spec/requests/admin/users_controller_spec.rb
+++ b/spec/requests/admin/users_controller_spec.rb
@@ -10,6 +10,29 @@ RSpec.describe Admin::UsersController, :enable_admin_mode, feature_category: :us
sign_in(admin)
end
+ describe 'PATCH #update' do
+ let(:user) { create(:user) }
+
+ context "when admin changes user email" do
+ let(:new_email) { 'new-email@example.com' }
+
+ subject(:request) { patch admin_user_path(user), params: { user: { email: new_email } } }
+
+ it 'allows change user email', :aggregate_failures do
+ expect { request }
+ .to change { user.reload.email }.from(user.email).to(new_email)
+
+ expect(response).to redirect_to(admin_user_path(user))
+ expect(flash[:notice]).to eq('User was successfully updated.')
+ end
+
+ it 'does not email the user with confirmation_instructions' do
+ expect { request }
+ .not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ end
+ end
+ end
+
describe 'PUT #block' do
context 'when request format is :json' do
subject(:request) { put block_admin_user_path(user, format: :json) }
diff --git a/spec/requests/api/bulk_imports_spec.rb b/spec/requests/api/bulk_imports_spec.rb
index fdbfbf052d0..8aad56c9fc3 100644
--- a/spec/requests/api/bulk_imports_spec.rb
+++ b/spec/requests/api/bulk_imports_spec.rb
@@ -254,11 +254,10 @@ RSpec.describe API::BulkImports, feature_category: :importers do
request
expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['error']).to include('entities[0][destination_namespace] must have a relative path ' \
- 'structure with no HTTP protocol characters, or leading or ' \
- 'trailing forward slashes. Path segments must not start or end ' \
- 'with a special character, and must not contain consecutive ' \
- 'special characters.')
+ expect(json_response['error']).to include('entities[0][destination_namespace] must be a relative path ' \
+ 'and not include protocol, sub-domain, or domain information. ' \
+ "For example, 'destination/full/path' not " \
+ "'https://example.com/destination/full/path'")
end
end
@@ -311,12 +310,11 @@ RSpec.describe API::BulkImports, feature_category: :importers do
}
end
- it 'returns blocked url message in the error' do
+ it 'returns blocked url message in the error', :aggregate_failures do
request
expect(response).to have_gitlab_http_status(:unprocessable_entity)
-
- expect(json_response['message']).to include("Url is blocked: Only allowed schemes are http, https")
+ expect(json_response['message']).to eq("URL is blocked: Only allowed schemes are http, https")
end
end
@@ -336,16 +334,16 @@ RSpec.describe API::BulkImports, feature_category: :importers do
}
end
- it 'returns blocked url error' do
+ it 'returns blocked url error', :aggregate_failures do
stub_request(:get, "http://gitlab.example/api/v4/#{source_entity_type}/#{source_entity_identifier}/export_relations/status?page=1&per_page=30&private_token=access_token")
- .to_return(status: 404, body: "", headers: {})
+ .to_return(status: 404, body: "{'error':'404 Not Found'}")
request
expect(response).to have_gitlab_http_status(:unprocessable_entity)
-
- expect(json_response['message']).to include("Group import disabled on source or destination instance. " \
- "Ask an administrator to enable it on both instances and try again.")
+ expect(json_response['message']).to eq(
+ "Unsuccessful response 404 from /api/v4/groups/full_path/export_relations/status. Body: {'error':'404 Not Found'}"
+ )
end
end
diff --git a/spec/requests/api/ci/jobs_spec.rb b/spec/requests/api/ci/jobs_spec.rb
index c7b7131a600..19ac673308b 100644
--- a/spec/requests/api/ci/jobs_spec.rb
+++ b/spec/requests/api/ci/jobs_spec.rb
@@ -463,6 +463,14 @@ RSpec.describe API::Ci::Jobs, feature_category: :continuous_integration do
it { expect(response).to have_gitlab_http_status(:bad_request) }
end
+
+ it_behaves_like 'an endpoint with keyset pagination' do
+ let_it_be(:another_build) { create(:ci_build, :success, :tags, project: project, pipeline: pipeline) }
+
+ let(:first_record) { project.builds.last }
+ let(:second_record) { project.builds.first }
+ let(:api_call) { api("/projects/#{project.id}/jobs", user) }
+ end
end
context 'unauthorized user' do
diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
index ca57208eb1d..7f9c9a13311 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -260,7 +260,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
expect(runner.reload.platform).to eq('darwin')
expect(json_response['id']).to eq(job.id)
expect(json_response['token']).to eq(job.token)
- expect(json_response['job_info']).to eq(expected_job_info)
+ expect(json_response['job_info']).to include(expected_job_info)
expect(json_response['git_info']).to eq(expected_git_info)
expect(json_response['image']).to eq(
{ 'name' => 'image:1.0', 'entrypoint' => '/bin/sh', 'ports' => [], 'pull_policy' => nil }
@@ -672,7 +672,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
expect(runner.reload.platform).to eq('darwin')
expect(json_response['id']).to eq(job.id)
expect(json_response['token']).to eq(job.token)
- expect(json_response['job_info']).to eq(expected_job_info)
+ expect(json_response['job_info']).to include(expected_job_info)
expect(json_response['git_info']).to eq(expected_git_info)
expect(json_response['artifacts']).to eq(expected_artifacts)
end
@@ -785,6 +785,63 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
end
end
end
+
+ describe 'time_in_queue_seconds support' do
+ let(:job) do
+ create(:ci_build, :pending, :queued, pipeline: pipeline,
+ name: 'spinach', stage: 'test', stage_idx: 0,
+ queued_at: 60.seconds.ago)
+ end
+
+ it 'presents the time_in_queue_seconds info in the payload' do
+ request_job
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['job_info']['time_in_queue_seconds']).to be >= 60.seconds
+ end
+ end
+
+ describe 'project_jobs_running_on_instance_runners_count support' do
+ context 'when runner is not instance_type' do
+ it 'presents the project_jobs_running_on_instance_runners_count info in the payload as +Inf' do
+ request_job
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['job_info']['project_jobs_running_on_instance_runners_count']).to eq('+Inf')
+ end
+ end
+
+ context 'when runner is instance_type' do
+ let(:project) { create(:project, namespace: group, shared_runners_enabled: true) }
+ let(:runner) { create(:ci_runner, :instance) }
+
+ context 'when less than Project::INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET running jobs assigned to an instance runner are on the list' do
+ it 'presents the project_jobs_running_on_instance_runners_count info in the payload as a correct number in a string format' do
+ request_job
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['job_info']['project_jobs_running_on_instance_runners_count']).to eq('0')
+ end
+ end
+
+ context 'when at least Project::INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET running jobs assigned to an instance runner are on the list' do
+ let(:other_runner) { create(:ci_runner, :instance) }
+
+ before do
+ stub_const('Project::INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET', 1)
+
+ create(:ci_running_build, runner: other_runner, runner_type: other_runner.runner_type, project: project)
+ end
+
+ it 'presents the project_jobs_running_on_instance_runners_count info in the payload as Project::INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET+' do
+ request_job
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['job_info']['project_jobs_running_on_instance_runners_count']).to eq('1+')
+ end
+ end
+ end
+ end
end
describe 'port support' do
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index 2f0e64cd4da..9247d9366b2 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
+RSpec.describe API::CommitStatuses, :clean_gitlab_redis_cache, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:commit) { project.repository.commit }
let_it_be(:guest) { create_user(:guest) }
@@ -120,6 +120,7 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
it "does not return project commits" do
expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('403 Forbidden')
end
end
@@ -139,7 +140,8 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
context 'developer user' do
context 'uses only required parameters' do
- %w[pending running success failed canceled].each do |status|
+ valid_statues = %w[pending running success failed canceled]
+ valid_statues.each do |status|
context "for #{status}" do
context 'when pipeline for sha does not exists' do
it 'creates commit status and sets pipeline iid' do
@@ -248,12 +250,13 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
end
end
- context 'transitions status from pending' do
+ context 'when status transitions from pending' do
before do
post api(post_url, developer), params: { state: 'pending' }
end
- %w[running success failed canceled].each do |status|
+ valid_statues = %w[running success failed canceled]
+ valid_statues.each do |status|
it "to #{status}" do
expect { post api(post_url, developer), params: { state: status } }.not_to change { CommitStatus.count }
@@ -366,6 +369,7 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
send_request
expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq("Cannot transition status via :run from :running (Reason(s): Status cannot transition via \"run\")")
commit_status = project.commit_statuses.find_by!(name: 'coverage')
@@ -440,6 +444,7 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
it 'does not create commit status' do
expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq(nil)
end
end
@@ -450,6 +455,7 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
it 'does not create commit status' do
expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq(nil)
end
end
@@ -464,6 +470,7 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
it 'does not create commit status' do
expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('403 Forbidden')
end
end
@@ -485,15 +492,16 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
it 'returns not found error' do
expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 Commit Not Found')
end
end
context 'when target URL is an invalid address' do
before do
post api(post_url, developer), params: {
- state: 'pending',
- target_url: 'invalid url'
- }
+ state: 'pending',
+ target_url: 'invalid url'
+ }
end
it 'responds with bad request status and validation errors' do
@@ -506,9 +514,9 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
context 'when target URL is an unsupported scheme' do
before do
post api(post_url, developer), params: {
- state: 'pending',
- target_url: 'git://example.com'
- }
+ state: 'pending',
+ target_url: 'git://example.com'
+ }
end
it 'responds with bad request status and validation errors' do
@@ -562,6 +570,7 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
it 'does not create commit status' do
expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('403 Forbidden')
end
end
@@ -572,6 +581,7 @@ RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
it 'does not create commit status' do
expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('403 Forbidden')
end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 687ce333ca5..8b9ac7cd588 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -589,7 +589,7 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
let(:namespace) { project.namespace.reload }
let(:label) { 'counts.web_ide_commits' }
let(:context) do
- [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: 'counts.web_ide_commits').to_context.to_json]
+ [Gitlab::Usage::MetricDefinition.context_for('counts.web_ide_commits').to_context.to_json]
end
end
end
diff --git a/spec/requests/api/discussions_spec.rb b/spec/requests/api/discussions_spec.rb
index a65dc6e0175..aebdcebbc5a 100644
--- a/spec/requests/api/discussions_spec.rb
+++ b/spec/requests/api/discussions_spec.rb
@@ -116,6 +116,17 @@ RSpec.describe API::Discussions, feature_category: :team_planning do
it_behaves_like 'diff discussions API', 'projects', 'merge_requests', 'iid'
it_behaves_like 'resolvable discussions API', 'projects', 'merge_requests', 'iid'
+ context "when position_type is file" do
+ it "creates a new diff note" do
+ position = diff_note.position.to_h.merge({ position_type: 'file' }).except(:ignore_whitespace_change)
+
+ post api("/projects/#{parent.id}/merge_requests/#{noteable['iid']}/discussions", user),
+ params: { body: 'hi!', position: position }
+
+ expect(response).to have_gitlab_http_status(:created)
+ end
+ end
+
context "when position is for a previous commit on the merge request" do
it "returns a 400 bad request error because the line_code is old" do
# SHA taken from an earlier commit listed in spec/factories/merge_requests.rb
diff --git a/spec/requests/api/feature_flags_spec.rb b/spec/requests/api/feature_flags_spec.rb
index 69e3633de57..4fb0dfbb070 100644
--- a/spec/requests/api/feature_flags_spec.rb
+++ b/spec/requests/api/feature_flags_spec.rb
@@ -111,7 +111,57 @@ RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
'scopes' => [{
'id' => scope.id,
'environment_scope' => 'production'
- }]
+ }],
+ 'user_list' => nil
+ }]
+ }])
+ end
+ end
+
+ context 'with user_list strategy feature flags' do
+ let!(:feature_flag) do
+ create(:operations_feature_flag, :new_version_flag, project: project, name: 'feature1')
+ end
+
+ let!(:user_list) do
+ create(:operations_feature_flag_user_list, project: project)
+ end
+
+ let!(:strategy) do
+ create(:operations_strategy, :gitlab_userlist, user_list: user_list, feature_flag: feature_flag, name: 'gitlabUserList', parameters: {})
+ end
+
+ let!(:scope) do
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+ end
+
+ it 'returns the feature flags', :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response).to eq([{
+ 'name' => 'feature1',
+ 'description' => nil,
+ 'active' => true,
+ 'version' => 'new_version_flag',
+ 'updated_at' => feature_flag.updated_at.as_json,
+ 'created_at' => feature_flag.created_at.as_json,
+ 'scopes' => [],
+ 'strategies' => [{
+ 'id' => strategy.id,
+ 'name' => 'gitlabUserList',
+ 'parameters' => {},
+ 'scopes' => [{
+ 'id' => scope.id,
+ 'environment_scope' => 'production'
+ }],
+ 'user_list' => {
+ 'id' => user_list.id,
+ 'iid' => user_list.iid,
+ 'name' => user_list.name,
+ 'user_xids' => user_list.user_xids
+ }
}]
}])
end
@@ -162,7 +212,57 @@ RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
'scopes' => [{
'id' => scope.id,
'environment_scope' => 'production'
- }]
+ }],
+ 'user_list' => nil
+ }]
+ })
+ end
+ end
+
+ context 'with user_list strategy feature flag' do
+ let!(:feature_flag) do
+ create(:operations_feature_flag, :new_version_flag, project: project, name: 'feature1')
+ end
+
+ let(:user_list) do
+ create(:operations_feature_flag_user_list, project: project)
+ end
+
+ let!(:strategy) do
+ create(:operations_strategy, :gitlab_userlist, user_list: user_list, feature_flag: feature_flag, name: 'gitlabUserList', parameters: {})
+ end
+
+ let!(:scope) do
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+ end
+
+ it 'returns the feature flag', :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response).to eq({
+ 'name' => 'feature1',
+ 'description' => nil,
+ 'active' => true,
+ 'version' => 'new_version_flag',
+ 'updated_at' => feature_flag.updated_at.as_json,
+ 'created_at' => feature_flag.created_at.as_json,
+ 'scopes' => [],
+ 'strategies' => [{
+ 'id' => strategy.id,
+ 'name' => 'gitlabUserList',
+ 'parameters' => {},
+ 'scopes' => [{
+ 'id' => scope.id,
+ 'environment_scope' => 'production'
+ }],
+ 'user_list' => {
+ 'id' => user_list.id,
+ 'iid' => user_list.iid,
+ 'name' => user_list.name,
+ 'user_xids' => user_list.user_xids
+ }
}]
})
end
@@ -224,6 +324,10 @@ RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
end
context 'when creating a version 2 feature flag' do
+ let(:user_list) do
+ create(:operations_feature_flag_user_list, project: project)
+ end
+
it 'creates a new feature flag' do
params = {
name: 'new-feature',
@@ -348,6 +452,32 @@ RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
environment_scope: 'staging'
}])
end
+
+ it 'creates a new feature flag with user list strategy', :aggregate_failures do
+ params = {
+ name: 'new-feature',
+ version: 'new_version_flag',
+ strategies: [{
+ name: 'gitlabUserList',
+ parameters: {},
+ user_list_id: user_list.id
+ }]
+ }
+
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.name).to eq(params[:name])
+ expect(feature_flag.version).to eq('new_version_flag')
+ expect(feature_flag.strategies.map { |s| s.slice(:name, :parameters).deep_symbolize_keys }).to eq([{
+ name: 'gitlabUserList',
+ parameters: {}
+ }])
+ expect(feature_flag.strategies.first.user_list).to eq(user_list)
+ end
end
context 'when given invalid parameters' do
@@ -369,6 +499,10 @@ RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
project: project, active: true, name: 'feature1', description: 'old description')
end
+ let(:user_list) do
+ create(:operations_feature_flag_user_list, project: project)
+ end
+
it 'returns a 404 if the feature flag does not exist' do
params = { description: 'new description' }
@@ -537,6 +671,30 @@ RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
}])
end
+ it 'updates an existing feature flag strategy to be gitlab user list strategy', :aggregate_failures do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ params = {
+ strategies: [{
+ id: strategy.id,
+ name: 'gitlabUserList',
+ user_list_id: user_list.id,
+ parameters: {}
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
+ expect(result).to eq([{
+ id: strategy.id,
+ name: 'gitlabUserList',
+ parameters: {}
+ }])
+ expect(feature_flag.strategies.first.user_list).to eq(user_list)
+ end
+
it 'adds a new gradual rollout strategy to a feature flag' do
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
params = {
diff --git a/spec/requests/api/features_spec.rb b/spec/requests/api/features_spec.rb
index 2571e3b1e6a..d922947f3e9 100644
--- a/spec/requests/api/features_spec.rb
+++ b/spec/requests/api/features_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Features, stub_feature_flags: false, feature_category: :feature_flags do
+RSpec.describe API::Features, :clean_gitlab_redis_feature_flag, stub_feature_flags: false, feature_category: :feature_flags do
let_it_be(:user) { create(:user) }
let_it_be(:opted_out) { create(:user) }
let_it_be(:admin) { create(:admin) }
diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb
index 756fcd8b7cd..ab2ebf134d7 100644
--- a/spec/requests/api/graphql/ci/jobs_spec.rb
+++ b/spec/requests/api/graphql/ci/jobs_spec.rb
@@ -139,7 +139,10 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati
let(:pipeline) do
pipeline = create(:ci_pipeline, project: project, user: user)
stage = create(:ci_stage, project: project, pipeline: pipeline, name: 'first', position: 1)
- create(:ci_build, stage_id: stage.id, pipeline: pipeline, name: 'my test job', scheduling_type: :stage)
+ create(
+ :ci_build, pipeline: pipeline, name: 'my test job',
+ scheduling_type: :stage, stage_id: stage.id, stage_idx: stage.position
+ )
pipeline
end
@@ -180,10 +183,10 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati
previousStageJobsOrNeeds {
nodes {
... on CiBuildNeed {
- #{all_graphql_fields_for('CiBuildNeed')}
+ name
}
... on CiJob {
- #{all_graphql_fields_for('CiJob', excluded: %w[aiFailureAnalysis])}
+ name
}
}
}
@@ -211,10 +214,12 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati
before do
build_stage = create(:ci_stage, position: 2, name: 'build', project: project, pipeline: pipeline)
test_stage = create(:ci_stage, position: 3, name: 'test', project: project, pipeline: pipeline)
+ deploy_stage = create(:ci_stage, position: 4, name: 'deploy', project: project, pipeline: pipeline)
create(:ci_build, pipeline: pipeline, name: 'docker 1 2', scheduling_type: :stage, ci_stage: build_stage, stage_idx: build_stage.position)
create(:ci_build, pipeline: pipeline, name: 'docker 2 2', ci_stage: build_stage, stage_idx: build_stage.position, scheduling_type: :dag)
create(:ci_build, pipeline: pipeline, name: 'rspec 1 2', scheduling_type: :stage, ci_stage: test_stage, stage_idx: test_stage.position)
+ create(:ci_build, pipeline: pipeline, name: 'deploy', scheduling_type: :stage, ci_stage: deploy_stage, stage_idx: deploy_stage.position)
test_job = create(:ci_build, pipeline: pipeline, name: 'rspec 2 2', scheduling_type: :dag, ci_stage: test_stage, stage_idx: test_stage.position)
create(:ci_build_need, build: test_job, name: 'my test job')
@@ -255,6 +260,14 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati
'previousStageJobsOrNeeds' => { 'nodes' => [
a_hash_including('name' => 'my test job')
] }
+ ),
+ a_hash_including(
+ 'name' => 'deploy',
+ 'needs' => { 'nodes' => [] },
+ 'previousStageJobsOrNeeds' => { 'nodes' => [
+ a_hash_including('name' => 'rspec 1 2'),
+ a_hash_including('name' => 'rspec 2 2')
+ ] }
)
)
end
@@ -613,3 +626,87 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati
end
end
end
+
+RSpec.describe 'previousStageJobs', feature_category: :pipeline_composition do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+
+ let(:query) do
+ <<~QUERY
+ {
+ project(fullPath: "#{project.full_path}") {
+ pipeline(iid: "#{pipeline.iid}") {
+ stages {
+ nodes {
+ groups {
+ nodes {
+ jobs {
+ nodes {
+ name
+ previousStageJobs {
+ nodes {
+ name
+ downstreamPipeline {
+ id
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ it 'does not produce N+1 queries', :request_store, :use_sql_query_cache do
+ user1 = create(:user)
+ user2 = create(:user)
+
+ create_stage_with_build_and_bridge('build', 0)
+ create_stage_with_build_and_bridge('test', 1)
+
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ post_graphql(query, current_user: user1)
+ end
+
+ expect(graphql_data_previous_stage_jobs).to eq(
+ 'build_build' => [],
+ 'test_build' => %w[build_build]
+ )
+
+ create_stage_with_build_and_bridge('deploy', 2)
+
+ expect do
+ post_graphql(query, current_user: user2)
+ end.to issue_same_number_of_queries_as(control)
+
+ expect(graphql_data_previous_stage_jobs).to eq(
+ 'build_build' => [],
+ 'test_build' => %w[build_build],
+ 'deploy_build' => %w[test_build]
+ )
+ end
+
+ def create_stage_with_build_and_bridge(stage_name, stage_position)
+ stage = create(:ci_stage, position: stage_position, name: "#{stage_name}_stage", project: project, pipeline: pipeline)
+
+ create(:ci_build, pipeline: pipeline, name: "#{stage_name}_build", ci_stage: stage, stage_idx: stage.position)
+ end
+
+ def graphql_data_previous_stage_jobs
+ stages = graphql_data.dig('project', 'pipeline', 'stages', 'nodes')
+ groups = stages.flat_map { |stage| stage.dig('groups', 'nodes') }
+ jobs = groups.flat_map { |group| group.dig('jobs', 'nodes') }
+
+ jobs.each_with_object({}) do |job, previous_stage_jobs|
+ previous_stage_jobs[job['name']] = job.dig('previousStageJobs', 'nodes').pluck('name')
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 3cfb98c57fd..6f1eb77fa9b 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -2,9 +2,11 @@
require 'spec_helper'
-RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
+RSpec.describe 'Query.runner(id)', :freeze_time, feature_category: :runner_fleet do
include GraphqlHelpers
+ using RSpec::Parameterized::TableSyntax
+
let_it_be(:user) { create(:user, :admin) }
let_it_be(:another_admin) { create(:user, :admin) }
let_it_be_with_reload(:group) { create(:group) }
@@ -144,23 +146,6 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
)
expect(runner_data['tagList']).to match_array runner.tag_list
end
-
- it 'does not execute more queries per runner', :use_sql_query_cache, :aggregate_failures do
- # warm-up license cache and so on:
- personal_access_token = create(:personal_access_token, user: user)
- args = { current_user: user, token: { personal_access_token: personal_access_token } }
- post_graphql(query, **args)
- expect(graphql_data_at(:runner)).not_to be_nil
-
- personal_access_token = create(:personal_access_token, user: another_admin)
- args = { current_user: another_admin, token: { personal_access_token: personal_access_token } }
- control = ActiveRecord::QueryRecorder.new(skip_cached: false) { post_graphql(query, **args) }
-
- create(:ci_runner, :instance, version: '14.0.0', tag_list: %w[tag5 tag6], creator: another_admin)
- create(:ci_runner, :project, version: '14.0.1', projects: [project1], tag_list: %w[tag3 tag8], creator: another_admin)
-
- expect { post_graphql(query, **args) }.not_to exceed_all_query_limit(control)
- end
end
shared_examples 'retrieval with no admin url' do
@@ -228,7 +213,7 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
end
end
- context 'with build running', :freeze_time do
+ context 'with build running' do
let!(:pipeline) { create(:ci_pipeline, project: project1) }
let!(:runner_manager) do
create(:ci_runner_machine,
@@ -248,23 +233,25 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
end
describe 'for project runner' do
- describe 'locked' do
- using RSpec::Parameterized::TableSyntax
+ let_it_be_with_refind(:project_runner) do
+ create(:ci_runner, :project,
+ description: 'Runner 3',
+ contacted_at: 1.day.ago,
+ active: false,
+ locked: false,
+ version: 'adfe157',
+ revision: 'b',
+ ip_address: '10.10.10.10',
+ access_level: 1,
+ run_untagged: true)
+ end
+ describe 'locked' do
where(is_locked: [true, false])
with_them do
- let(:project_runner) do
- create(:ci_runner, :project,
- description: 'Runner 3',
- contacted_at: 1.day.ago,
- active: false,
- locked: is_locked,
- version: 'adfe157',
- revision: 'b',
- ip_address: '10.10.10.10',
- access_level: 1,
- run_untagged: true)
+ before do
+ project_runner.update!(locked: is_locked)
end
let(:query) do
@@ -357,6 +344,109 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
)
end
end
+
+ describe 'jobs' do
+ let(:query) do
+ %(
+ query {
+ runner(id: "#{project_runner.to_global_id}") { #{runner_query_fragment} }
+ }
+ )
+ end
+
+ context 'with a job from a non-owned project' do
+ let(:runner_query_fragment) do
+ %(
+ id
+ jobs {
+ nodes {
+ id status shortSha finishedAt duration queuedDuration tags webPath
+ project { id }
+ runner { id }
+ }
+ }
+ )
+ end
+
+ let_it_be(:owned_project_owner) { create(:user) }
+ let_it_be(:owned_project) { create(:project) }
+ let_it_be(:other_project) { create(:project) }
+ let_it_be(:project_runner) { create(:ci_runner, :project_type, projects: [other_project, owned_project]) }
+ let_it_be(:owned_project_pipeline) { create(:ci_pipeline, project: owned_project) }
+ let_it_be(:other_project_pipeline) { create(:ci_pipeline, project: other_project) }
+ let_it_be(:owned_build) do
+ create(:ci_build, :running, runner: project_runner, pipeline: owned_project_pipeline,
+ tag_list: %i[a b c], created_at: 1.hour.ago, started_at: 59.minutes.ago, finished_at: 30.minutes.ago)
+ end
+
+ let_it_be(:other_build) do
+ create(:ci_build, :success, runner: project_runner, pipeline: other_project_pipeline,
+ tag_list: %i[d e f], created_at: 30.minutes.ago, started_at: 19.minutes.ago, finished_at: 1.minute.ago)
+ end
+
+ before_all do
+ owned_project.add_owner(owned_project_owner)
+ end
+
+ it 'returns empty values for sensitive fields in non-owned jobs' do
+ post_graphql(query, current_user: owned_project_owner)
+
+ jobs_data = graphql_data_at(:runner, :jobs, :nodes)
+ expect(jobs_data).not_to be_nil
+ expect(jobs_data).to match([
+ a_graphql_entity_for(other_build,
+ status: other_build.status.upcase,
+ project: nil, tags: nil, web_path: nil,
+ runner: a_graphql_entity_for(project_runner),
+ short_sha: 'Unauthorized', finished_at: other_build.finished_at&.iso8601,
+ duration: a_value_within(0.001).of(other_build.duration),
+ queued_duration: a_value_within(0.001).of((other_build.started_at - other_build.queued_at).to_f)),
+ a_graphql_entity_for(owned_build,
+ status: owned_build.status.upcase,
+ project: a_graphql_entity_for(owned_project),
+ tags: owned_build.tag_list.map(&:to_s),
+ web_path: ::Gitlab::Routing.url_helpers.project_job_path(owned_project, owned_build),
+ runner: a_graphql_entity_for(project_runner),
+ short_sha: owned_build.short_sha,
+ finished_at: owned_build.finished_at&.iso8601,
+ duration: a_value_within(0.001).of(owned_build.duration),
+ queued_duration: a_value_within(0.001).of((owned_build.started_at - owned_build.queued_at).to_f))
+ ])
+ end
+ end
+ end
+
+ describe 'a query fetching all fields' do
+ let(:query) do
+ wrap_fields(query_graphql_path(query_path, all_graphql_fields_for('CiRunner')))
+ end
+
+ let(:query_path) do
+ [
+ [:runner, { id: project_runner.to_global_id.to_s }]
+ ]
+ end
+
+ it 'does not execute more queries per runner', :use_sql_query_cache, :aggregate_failures do
+ create(:ci_build, :failed, runner: project_runner)
+ create(:ci_runner_machine, runner: project_runner, version: '16.4.0')
+
+ # warm-up license cache and so on:
+ personal_access_token = create(:personal_access_token, user: user)
+ args = { current_user: user, token: { personal_access_token: personal_access_token } }
+ post_graphql(query, **args)
+ expect(graphql_data_at(:runner)).not_to be_nil
+
+ personal_access_token = create(:personal_access_token, user: another_admin)
+ args = { current_user: another_admin, token: { personal_access_token: personal_access_token } }
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) { post_graphql(query, **args) }
+
+ create(:ci_build, :failed, runner: project_runner)
+ create(:ci_runner_machine, runner: project_runner, version: '16.4.1')
+
+ expect { post_graphql(query, **args) }.not_to exceed_all_query_limit(control)
+ end
+ end
end
describe 'for inactive runner' do
@@ -501,8 +591,14 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
end
describe 'for runner with status' do
- let_it_be(:stale_runner) { create(:ci_runner, description: 'Stale runner 1', created_at: 3.months.ago) }
- let_it_be(:never_contacted_instance_runner) { create(:ci_runner, description: 'Missing runner 1', created_at: 1.month.ago, contacted_at: nil) }
+ let_it_be(:stale_runner) do
+ create(:ci_runner, description: 'Stale runner 1',
+ created_at: (3.months + 1.second).ago, contacted_at: (3.months + 1.second).ago)
+ end
+
+ let_it_be(:never_contacted_instance_runner) do
+ create(:ci_runner, description: 'Missing runner 1', created_at: 1.month.ago, contacted_at: nil)
+ end
let(:query) do
%(
@@ -918,8 +1014,6 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
end
context 'when requesting individual fields' do
- using RSpec::Parameterized::TableSyntax
-
where(:field) do
[
'detailedStatus { id detailsPath group icon text }',
diff --git a/spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb b/spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb
index e84a1ca4cc4..76e2dda4ce2 100644
--- a/spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb
@@ -25,16 +25,22 @@ RSpec.describe 'RunnerWebUrlEdge', feature_category: :runner_fleet do
GQL
end
- before do
+ subject(:request) do
post_graphql(query, current_user: user, variables: { path: group.full_path })
end
context 'with an authorized user' do
let(:user) { create_default(:user, :admin) }
- it_behaves_like 'a working graphql query'
+ it_behaves_like 'a working graphql query' do
+ before do
+ request
+ end
+ end
it 'returns correct URLs' do
+ request
+
expect(edges_graphql_data).to match_array [
{
'editUrl' => Gitlab::Routing.url_helpers.edit_group_runner_url(group, group_runner),
@@ -47,10 +53,14 @@ RSpec.describe 'RunnerWebUrlEdge', feature_category: :runner_fleet do
context 'with an unauthorized user' do
let(:user) { create(:user) }
- it_behaves_like 'a working graphql query'
+ it 'returns nil runners and an error' do
+ request
- it 'returns no edges' do
- expect(edges_graphql_data).to be_empty
+ expect(graphql_data.dig('group', 'runners')).to be_nil
+ expect(graphql_errors).to contain_exactly(a_hash_including(
+ 'message' => a_string_including("you don't have permission to perform this action"),
+ 'path' => %w[group runners]
+ ))
end
end
end
diff --git a/spec/requests/api/graphql/ci/runners_spec.rb b/spec/requests/api/graphql/ci/runners_spec.rb
index 3f6d39435fd..c5571086700 100644
--- a/spec/requests/api/graphql/ci/runners_spec.rb
+++ b/spec/requests/api/graphql/ci/runners_spec.rb
@@ -72,10 +72,16 @@ RSpec.describe 'Query.runners', feature_category: :runner_fleet do
args = { current_user: admin2, token: { personal_access_token: personal_access_token } }
control = ActiveRecord::QueryRecorder.new { post_graphql(query, **args) }
- create(:ci_runner, :instance, version: '14.0.0', tag_list: %w[tag5 tag6], creator: admin2)
- create(:ci_runner, :project, version: '14.0.1', projects: [project], tag_list: %w[tag3 tag8],
+ runner2 = create(:ci_runner, :instance, version: '14.0.0', tag_list: %w[tag5 tag6], creator: admin2)
+ runner3 = create(:ci_runner, :project, version: '14.0.1', projects: [project], tag_list: %w[tag3 tag8],
creator: current_user)
+ create(:ci_build, :failed, runner: runner2)
+ create(:ci_runner_machine, runner: runner2, version: '16.4.1')
+
+ create(:ci_build, :failed, runner: runner3)
+ create(:ci_runner_machine, runner: runner3, version: '16.4.0')
+
expect { post_graphql(query, **args) }.not_to exceed_query_limit(control)
end
end
diff --git a/spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb
index 961de84234c..869147f17b3 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb
@@ -26,7 +26,6 @@ RSpec.describe 'getting dependency proxy blobs in a group', feature_category: :d
#{query_graphql_field('dependency_proxy_blobs', {}, dependency_proxy_blob_fields)}
dependencyProxyBlobCount
dependencyProxyTotalSize
- dependencyProxyTotalSizeInBytes
dependencyProxyTotalSizeBytes
GQL
end
@@ -44,7 +43,7 @@ RSpec.describe 'getting dependency proxy blobs in a group', feature_category: :d
let(:dependency_proxy_blobs_response) { graphql_data.dig('group', 'dependencyProxyBlobs', 'edges') }
let(:dependency_proxy_blob_count_response) { graphql_data.dig('group', 'dependencyProxyBlobCount') }
let(:dependency_proxy_total_size_response) { graphql_data.dig('group', 'dependencyProxyTotalSize') }
- let(:dependency_proxy_total_size_in_bytes_response) { graphql_data.dig('group', 'dependencyProxyTotalSizeInBytes') }
+ let(:dependency_proxy_total_size_bytes_response) { graphql_data.dig('group', 'dependencyProxyTotalSizeBytes') }
before do
stub_config(dependency_proxy: { enabled: true })
@@ -131,7 +130,7 @@ RSpec.describe 'getting dependency proxy blobs in a group', feature_category: :d
it 'returns the total size in bytes' do
subject
expected_size = blobs.inject(0) { |sum, blob| sum + blob.size }
- expect(dependency_proxy_total_size_in_bytes_response).to eq(expected_size)
+ expect(dependency_proxy_total_size_bytes_response.to_i).to eq(expected_size)
end
context 'with a giant size blob' do
diff --git a/spec/requests/api/graphql/group/work_item_spec.rb b/spec/requests/api/graphql/group/work_item_spec.rb
new file mode 100644
index 00000000000..9adb0acbf6b
--- /dev/null
+++ b/spec/requests/api/graphql/group/work_item_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting a single work item associated with a group', feature_category: :team_planning do
+ include GraphqlHelpers
+
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:reporter) { create(:user).tap { |user| group.add_reporter(user) } }
+
+ let_it_be(:group_work_item) do
+ create(
+ :work_item,
+ namespace: group,
+ author: reporter
+ )
+ end
+
+ let_it_be(:confidential_work_item) do
+ create(:work_item, :confidential, namespace: group, author: reporter)
+ end
+
+ let(:work_item_data) { graphql_data.dig('group', 'workItem') }
+ let(:query_group) { group }
+ let(:query_work_item) { group_work_item }
+ let(:params) { { iid: query_work_item.iid.to_s } }
+ let(:query) do
+ graphql_query_for(
+ 'group',
+ { 'fullPath' => query_group.full_path },
+ query_graphql_field('workItem', params, all_graphql_fields_for('workItems'.classify, max_depth: 2))
+ )
+ end
+
+ context 'when the user cannot read the work item' do
+ let(:current_user) { user }
+ let(:query_work_item) { confidential_work_item }
+
+ it 'returns does not return the work item' do
+ post_graphql(query, current_user: current_user)
+
+ expect(work_item_data).to be_nil
+ end
+ end
+
+ context 'when the user can read the work item' do
+ let(:current_user) { reporter }
+
+ it 'returns the work item' do
+ post_graphql(query, current_user: current_user)
+
+ expect(work_item_data).to include(
+ 'id' => query_work_item.to_gid.to_s,
+ 'iid' => query_work_item.iid.to_s
+ )
+ end
+
+ context 'when the namespace_level_work_items feature flag is disabled' do
+ before do
+ stub_feature_flags(namespace_level_work_items: false)
+ end
+
+ it 'does not return the work item' do
+ post_graphql(query, current_user: current_user)
+
+ expect(work_item_data).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/group/work_items_spec.rb b/spec/requests/api/graphql/group/work_items_spec.rb
index f6dad577b5e..ef96ef4754a 100644
--- a/spec/requests/api/graphql/group/work_items_spec.rb
+++ b/spec/requests/api/graphql/group/work_items_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe 'getting a work_item list for a group', feature_category: :team_p
let_it_be(:other_work_item) { create(:work_item) }
let(:work_items_data) { graphql_data['group']['workItems']['nodes'] }
- let(:work_item_filter_params) { {} }
+ let(:item_filter_params) { {} }
let(:current_user) { user }
let(:query_group) { group }
@@ -47,6 +47,28 @@ RSpec.describe 'getting a work_item list for a group', feature_category: :team_p
QUERY
end
+ it_behaves_like 'graphql work item list request spec' do
+ let_it_be(:container_build_params) { { namespace: group } }
+ let(:work_item_node_path) { %w[group workItems nodes] }
+
+ def post_query(request_user = current_user)
+ post_graphql(query, current_user: request_user)
+ end
+ end
+
+ context 'when filtering by search' do
+ let(:item_filter_params) { { search: 'search_term', in: [:DESCRIPTION] } }
+
+ # TODO: https://gitlab.com/gitlab-org/gitlab/-/work_items/393126
+ it 'returns an error since search is not implemented at the group level yet' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_errors).to contain_exactly(
+ hash_including('message' => 'Searching is not available for work items at the namespace level yet')
+ )
+ end
+ end
+
context 'when the user can not see confidential work_items' do
it_behaves_like 'a working graphql query' do
before do
@@ -66,12 +88,6 @@ RSpec.describe 'getting a work_item list for a group', feature_category: :team_p
context 'when the user can see confidential work_items' do
let(:current_user) { reporter }
- it_behaves_like 'a working graphql query' do
- before do
- post_graphql(query, current_user: current_user)
- end
- end
-
it 'returns also confidential work_items' do
post_graphql(query, current_user: current_user)
@@ -96,7 +112,7 @@ RSpec.describe 'getting a work_item list for a group', feature_category: :team_p
graphql_dig_at(work_items_data, :id)
end
- def query(params = work_item_filter_params)
+ def query(params = item_filter_params)
graphql_query_for(
'group',
{ 'fullPath' => query_group.full_path },
diff --git a/spec/requests/api/graphql/group_query_spec.rb b/spec/requests/api/graphql/group_query_spec.rb
index 6debe2d3d67..1dcbc44c587 100644
--- a/spec/requests/api/graphql/group_query_spec.rb
+++ b/spec/requests/api/graphql/group_query_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'getting group information', :with_license, feature_category: :gr
# similar to the API "GET /groups/:id"
describe "Query group(fullPath)" do
def group_query(group)
- fields = all_graphql_fields_for('Group')
+ fields = all_graphql_fields_for('Group', excluded: %w[runners])
# TODO: Set required timelogs args elsewhere https://gitlab.com/gitlab-org/gitlab/-/issues/325499
fields.selection['timelogs(startDate: "2021-03-01" endDate: "2021-03-30")'] = fields.selection.delete('timelogs')
diff --git a/spec/requests/api/graphql/groups_query_spec.rb b/spec/requests/api/graphql/groups_query_spec.rb
index 460cb40b68a..7310382553f 100644
--- a/spec/requests/api/graphql/groups_query_spec.rb
+++ b/spec/requests/api/graphql/groups_query_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'searching groups', :with_license, feature_category: :groups_and_
let(:fields) do
<<~FIELDS
nodes {
- #{all_graphql_fields_for('Group')}
+ #{all_graphql_fields_for('Group', excluded: %w[runners])}
}
FIELDS
end
diff --git a/spec/requests/api/graphql/jobs_query_spec.rb b/spec/requests/api/graphql/jobs_query_spec.rb
index 4248a03fa74..7607aeac6e0 100644
--- a/spec/requests/api/graphql/jobs_query_spec.rb
+++ b/spec/requests/api/graphql/jobs_query_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'getting job information', feature_category: :continuous_integrat
:jobs, {}, %(
count
nodes {
- #{all_graphql_fields_for(::Types::Ci::JobType, max_depth: 1, excluded: %w[aiFailureAnalysis])}
+ #{all_graphql_fields_for(::Types::Ci::JobType, max_depth: 1)}
})
)
end
diff --git a/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb b/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb
new file mode 100644
index 00000000000..2939e9307e9
--- /dev/null
+++ b/spec/requests/api/graphql/merge_requests/codequality_reports_comparer_spec.rb
@@ -0,0 +1,185 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Query.project.mergeRequest.codequalityReportsComparer', feature_category: :code_quality do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:merge_request) { create(:merge_request, :with_codequality_reports, source_project: project) }
+
+ let(:mock_report) do
+ {
+ status: :parsed,
+ data: {
+ status: 'failed',
+ new_errors: [
+ {
+ description: "Method `new_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.",
+ fingerprint: "15cdb5c53afd42bc22f8ca366a08d547",
+ severity: "major",
+ file_path: "foo.rb",
+ line: 10,
+ engine_name: "structure"
+ },
+ {
+ description: "Method `backwards_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.",
+ fingerprint: "f3bdc1e8c102ba5fbd9e7f6cda51c95e",
+ severity: "major",
+ file_path: "foo.rb",
+ line: 14,
+ engine_name: "structure"
+ },
+ {
+ description: "Avoid parameter lists longer than 5 parameters. [12/5]",
+ fingerprint: "ab5f8b935886b942d621399f5a2ca16e",
+ severity: "minor",
+ file_path: "foo.rb",
+ line: 14,
+ engine_name: "rubocop"
+ }
+ ],
+ resolved_errors: [],
+ existing_errors: [],
+ summary: {
+ total: 3,
+ resolved: 0,
+ errored: 3
+ }
+ }.deep_stringify_keys
+ }
+ end
+
+ let(:codequality_reports_comparer_fields) do
+ <<~QUERY
+ codequalityReportsComparer {
+ report {
+ status
+ newErrors {
+ description
+ fingerprint
+ severity
+ filePath
+ line
+ webUrl
+ engineName
+ }
+ resolvedErrors {
+ description
+ fingerprint
+ severity
+ filePath
+ line
+ webUrl
+ engineName
+ }
+ existingErrors {
+ description
+ fingerprint
+ severity
+ filePath
+ line
+ webUrl
+ engineName
+ }
+ summary {
+ errored
+ resolved
+ total
+ }
+ }
+ }
+ QUERY
+ end
+
+ let(:merge_request_fields) do
+ query_graphql_field(:merge_request, { iid: merge_request.iid.to_s }, codequality_reports_comparer_fields)
+ end
+
+ let(:query) { graphql_query_for(:project, { full_path: project.full_path }, merge_request_fields) }
+
+ subject(:result) { graphql_data_at(:project, :merge_request, :codequality_reports_comparer) }
+
+ before do
+ allow_next_found_instance_of(MergeRequest) do |merge_request|
+ allow(merge_request).to receive(:compare_codequality_reports).and_return(mock_report)
+ end
+ end
+
+ context 'when the user is not authorized to read the field' do
+ before do
+ post_graphql(query, current_user: user)
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when the user is authorized to read the field' do
+ before_all do
+ project.add_reporter(user)
+ end
+
+ before do
+ post_graphql(query, current_user: user)
+ end
+
+ context 'when when sast_reports_in_inline_diff FF is disabled' do
+ before_all do
+ stub_feature_flags(sast_reports_in_inline_diff: false)
+ end
+
+ it 'returns null for codequality_reports_comparer field' do
+ expect(result).to be_nil
+ end
+ end
+
+ it 'returns expected data' do
+ expect(result).to match(
+ a_hash_including(
+ {
+ report: {
+ status: 'FAILED',
+ newErrors: [
+ {
+ description: 'Method `new_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.',
+ fingerprint: '15cdb5c53afd42bc22f8ca366a08d547',
+ severity: 'MAJOR',
+ filePath: 'foo.rb',
+ line: 10,
+ webUrl: nil,
+ engineName: 'structure'
+ },
+ {
+ description: 'Method `backwards_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.',
+ fingerprint: 'f3bdc1e8c102ba5fbd9e7f6cda51c95e',
+ severity: 'MAJOR',
+ filePath: 'foo.rb',
+ line: 14,
+ webUrl: nil,
+ engineName: 'structure'
+ },
+ {
+ description: 'Avoid parameter lists longer than 5 parameters. [12/5]',
+ fingerprint: 'ab5f8b935886b942d621399f5a2ca16e',
+ severity: 'MINOR',
+ filePath: 'foo.rb',
+ line: 14,
+ webUrl: nil,
+ engineName: 'rubocop'
+ }
+ ],
+ resolvedErrors: [],
+ existingErrors: [],
+ summary: {
+ errored: 3,
+ resolved: 0,
+ total: 3
+ }
+ }
+ }.deep_stringify_keys
+ )
+ )
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/admin/abuse_report_labels/create_spec.rb b/spec/requests/api/graphql/mutations/admin/abuse_report_labels/create_spec.rb
new file mode 100644
index 00000000000..2a20d96d9c8
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/admin/abuse_report_labels/create_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Admin::AbuseReportLabels::Create, feature_category: :insider_threat do
+ include GraphqlHelpers
+
+ let(:params) do
+ {
+ 'title' => 'foo',
+ 'color' => '#FF0000'
+ }
+ end
+
+ let(:mutation) { graphql_mutation(:abuse_report_label_create, params) }
+
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+ def mutation_response
+ graphql_mutation_response(:abuse_report_label_create)
+ end
+
+ context 'when the user does not have permission to create a label', :enable_admin_mode do
+ let_it_be(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not create the label' do
+ expect { subject }.not_to change { Admin::AbuseReportLabel.count }
+ end
+ end
+
+ context 'when the user has permission to create a label', :enable_admin_mode do
+ let_it_be(:current_user) { create(:admin) }
+
+ it 'creates the label' do
+ expect { subject }.to change { Admin::AbuseReportLabel.count }.to(1)
+
+ expect(mutation_response).to include('label' => a_hash_including(params))
+ end
+
+ context 'when there are errors' do
+ it 'does not create the label', :aggregate_failures do
+ create(:abuse_report_label, title: params['title'])
+
+ expect { subject }.not_to change { Label.count }
+
+ expect(mutation_response).to include({
+ 'label' => nil,
+ 'errors' => ['Title has already been taken']
+ })
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule/create_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule/create_spec.rb
index b2fe2754198..0e49fc389c8 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_schedule/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule/create_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'PipelineSchedulecreate', feature_category: :continuous_integration do
include GraphqlHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
let(:mutation) do
@@ -56,30 +56,21 @@ RSpec.describe 'PipelineSchedulecreate', feature_category: :continuous_integrati
let(:mutation_response) { graphql_mutation_response(:pipeline_schedule_create) }
context 'when unauthorized' do
- it 'returns an error' do
- post_graphql_mutation(mutation, current_user: user)
-
- expect(graphql_errors).not_to be_empty
- expect(graphql_errors[0]['message'])
- .to eq(
- "The resource that you are attempting to access does not exist " \
- "or you don't have permission to perform this action"
- )
- end
+ it_behaves_like 'a mutation on an unauthorized resource'
end
context 'when authorized' do
before_all do
- project.add_developer(user)
+ project.add_developer(current_user)
end
context 'when success' do
it do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['pipelineSchedule']['owner']['id']).to eq(user.to_global_id.to_s)
+ expect(mutation_response['pipelineSchedule']['owner']['id']).to eq(current_user.to_global_id.to_s)
%w[description cron cronTimezone active].each do |key|
expect(mutation_response['pipelineSchedule'][key]).to eq(pipeline_schedule_parameters[key.to_sym])
@@ -90,7 +81,7 @@ RSpec.describe 'PipelineSchedulecreate', feature_category: :continuous_integrati
expect(mutation_response['pipelineSchedule']['variables']['nodes'][0]['key']).to eq('AAA')
expect(mutation_response['pipelineSchedule']['variables']['nodes'][0]['value']).to eq('AAA123')
- expect(mutation_response['pipelineSchedule']['owner']['id']).to eq(user.to_global_id.to_s)
+ expect(mutation_response['pipelineSchedule']['owner']['id']).to eq(current_user.to_global_id.to_s)
expect(mutation_response['errors']).to eq([])
end
@@ -110,7 +101,7 @@ RSpec.describe 'PipelineSchedulecreate', feature_category: :continuous_integrati
end
it do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
@@ -134,7 +125,7 @@ RSpec.describe 'PipelineSchedulecreate', feature_category: :continuous_integrati
end
it 'returns error' do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule/delete_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule/delete_spec.rb
index e79395bb52c..7b1a21971df 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_schedule/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule/delete_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe 'PipelineScheduleDelete', feature_category: :continuous_integration do
include GraphqlHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
- let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: user) }
+ let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: current_user) }
let(:mutation) do
graphql_mutation(
@@ -23,26 +23,17 @@ RSpec.describe 'PipelineScheduleDelete', feature_category: :continuous_integrati
let(:mutation_response) { graphql_mutation_response(:pipeline_schedule_delete) }
context 'when unauthorized' do
- it 'returns an error' do
- post_graphql_mutation(mutation, current_user: create(:user))
-
- expect(graphql_errors).not_to be_empty
- expect(graphql_errors[0]['message'])
- .to eq(
- "The resource that you are attempting to access does not exist " \
- "or you don't have permission to perform this action"
- )
- end
+ it_behaves_like 'a mutation on an unauthorized resource'
end
context 'when authorized' do
before_all do
- project.add_maintainer(user)
+ project.add_maintainer(current_user)
end
context 'when success' do
it do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['errors']).to eq([])
@@ -58,7 +49,7 @@ RSpec.describe 'PipelineScheduleDelete', feature_category: :continuous_integrati
end
it do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
@@ -70,7 +61,7 @@ RSpec.describe 'PipelineScheduleDelete', feature_category: :continuous_integrati
let(:pipeline_schedule_id) { 'gid://gitlab/Ci::PipelineSchedule/0' }
it do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(graphql_errors).not_to be_empty
expect(graphql_errors[0]['message'])
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule/play_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule/play_spec.rb
index 55ecf8f287e..28e8913d262 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_schedule/play_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule/play_spec.rb
@@ -5,14 +5,14 @@ require 'spec_helper'
RSpec.describe 'PipelineSchedulePlay', feature_category: :continuous_integration do
include GraphqlHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:pipeline_schedule) do
create(
:ci_pipeline_schedule,
:every_minute,
project: project,
- owner: user
+ owner: current_user
)
end
@@ -30,21 +30,12 @@ RSpec.describe 'PipelineSchedulePlay', feature_category: :continuous_integration
let(:mutation_response) { graphql_mutation_response(:pipeline_schedule_play) }
context 'when unauthorized' do
- it 'returns an error' do
- post_graphql_mutation(mutation, current_user: create(:user))
-
- expect(graphql_errors).not_to be_empty
- expect(graphql_errors[0]['message'])
- .to eq(
- "The resource that you are attempting to access does not exist " \
- "or you don't have permission to perform this action"
- )
- end
+ it_behaves_like 'a mutation on an unauthorized resource'
end
context 'when authorized', :sidekiq_inline do
before_all do
- project.add_maintainer(user)
+ project.add_maintainer(current_user)
pipeline_schedule.update_columns(next_run_at: 2.hours.ago)
end
@@ -54,7 +45,7 @@ RSpec.describe 'PipelineSchedulePlay', feature_category: :continuous_integration
it do
expect(Ci::CreatePipelineService).to receive_message_chain(:new, :execute).and_return(service_response)
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['pipelineSchedule']['id']).to include(pipeline_schedule.id.to_s)
new_next_run_at = DateTime.parse(mutation_response['pipelineSchedule']['nextRunAt'])
@@ -68,9 +59,9 @@ RSpec.describe 'PipelineSchedulePlay', feature_category: :continuous_integration
it do
expect(RunPipelineScheduleWorker)
.to receive(:perform_async)
- .with(pipeline_schedule.id, user.id).and_return(nil)
+ .with(pipeline_schedule.id, current_user.id).and_return(nil)
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['pipelineSchedule']).to be_nil
expect(mutation_response['errors']).to match_array(['Unable to schedule a pipeline to run immediately.'])
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule/update_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule/update_spec.rb
index ec1595f393f..12f6e09913a 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_schedule/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule/update_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe 'PipelineScheduleUpdate', feature_category: :continuous_integration do
include GraphqlHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
- let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: user) }
+ let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: current_user) }
let_it_be(:variable_one) do
create(:ci_pipeline_schedule_variable, key: 'foo', value: 'foovalue', pipeline_schedule: pipeline_schedule)
@@ -51,21 +51,12 @@ RSpec.describe 'PipelineScheduleUpdate', feature_category: :continuous_integrati
let(:mutation_response) { graphql_mutation_response(:pipeline_schedule_update) }
context 'when unauthorized' do
- it 'returns an error' do
- post_graphql_mutation(mutation, current_user: create(:user))
-
- expect(graphql_errors).not_to be_empty
- expect(graphql_errors[0]['message'])
- .to eq(
- "The resource that you are attempting to access does not exist " \
- "or you don't have permission to perform this action"
- )
- end
+ it_behaves_like 'a mutation on an unauthorized resource'
end
context 'when authorized' do
before_all do
- project.add_developer(user)
+ project.add_developer(current_user)
end
context 'when success' do
@@ -83,7 +74,7 @@ RSpec.describe 'PipelineScheduleUpdate', feature_category: :continuous_integrati
end
it do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
@@ -117,7 +108,7 @@ RSpec.describe 'PipelineScheduleUpdate', feature_category: :continuous_integrati
end
it 'processes variables correctly' do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
@@ -145,7 +136,7 @@ RSpec.describe 'PipelineScheduleUpdate', feature_category: :continuous_integrati
end
it do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
@@ -172,7 +163,7 @@ RSpec.describe 'PipelineScheduleUpdate', feature_category: :continuous_integrati
end
it 'returns error' do
- post_graphql_mutation(mutation, current_user: user)
+ post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_trigger/create_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_trigger/create_spec.rb
index 1af12d51e1e..2711bb9a4bd 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_trigger/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_trigger/create_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'PipelineTriggerCreate', feature_category: :continuous_integration do
include GraphqlHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:current_user) { create(:user) }
let_it_be_with_reload(:project) { create(:project) }
let(:mutation) { graphql_mutation(:pipeline_trigger_create, params) }
@@ -19,24 +19,15 @@ RSpec.describe 'PipelineTriggerCreate', feature_category: :continuous_integratio
}
end
- subject { post_graphql_mutation(mutation, current_user: user) }
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
context 'when unauthorized' do
- it 'returns an error' do
- subject
-
- expect(graphql_errors).not_to be_empty
- expect(graphql_errors[0]['message'])
- .to eq(
- "The resource that you are attempting to access does not exist " \
- "or you don't have permission to perform this action"
- )
- end
+ it_behaves_like 'a mutation on an unauthorized resource'
end
context 'when authorized' do
before_all do
- project.add_owner(user)
+ project.add_owner(current_user)
end
context 'when the params are invalid' do
@@ -60,9 +51,9 @@ RSpec.describe 'PipelineTriggerCreate', feature_category: :continuous_integratio
expect(graphql_data_at(:pipeline_trigger_create, :pipeline_trigger)).to match a_hash_including(
'owner' => a_hash_including(
- 'id' => user.to_global_id.to_s,
- 'username' => user.username,
- 'name' => user.name
+ 'id' => current_user.to_global_id.to_s,
+ 'username' => current_user.username,
+ 'name' => current_user.name
),
'description' => description,
"canAccessProject" => true,
diff --git a/spec/requests/api/graphql/mutations/merge_requests/update_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/update_spec.rb
new file mode 100644
index 00000000000..48db23569b6
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/merge_requests/update_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Update of an existing merge request', feature_category: :code_review_workflow do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be_with_reload(:merge_request) { create(:merge_request, source_project: project) }
+
+ let(:input) { { 'iid' => merge_request.iid.to_s } }
+ let(:extra_params) { { project_path: project.full_path } }
+ let(:input_params) { input.merge(extra_params) }
+ let(:mutation) { graphql_mutation(:merge_request_update, input_params, nil, ['productAnalyticsState']) }
+ let(:mutation_response) { graphql_mutation_response(:merge_request_update) }
+
+ context 'when the user is not allowed to update the merge request' do
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when the user has permissions to update the merge request' do
+ before_all do
+ project.add_developer(current_user)
+ end
+
+ it_behaves_like 'updating time estimate' do
+ let(:resource) { merge_request }
+ let(:mutation_name) { 'mergeRequestUpdate' }
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
index 0e55b6f2c9f..d05cc19de96 100644
--- a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
@@ -19,10 +19,6 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create, feature_categ
graphql_mutation_response(:create_annotation)
end
- before do
- stub_feature_flags(remove_monitor_metrics: false)
- end
-
specify { expect(described_class).to require_graphql_authorizations(:admin_metrics_dashboard_annotation) }
context 'when annotation source is environment' do
@@ -38,18 +34,6 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create, feature_categ
graphql_mutation(:create_annotation, variables)
end
- context 'when the user does not have permission' do
- before do
- project.add_reporter(current_user)
- end
-
- it 'does not create the annotation' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.not_to change { Metrics::Dashboard::Annotation.count }
- end
- end
-
context 'when the user has permission' do
before do
project.add_developer(current_user)
@@ -67,7 +51,8 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create, feature_categ
graphql_mutation(:create_annotation, variables)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: [described_class::ANNOTATION_SOURCE_ARGUMENT_ERROR]
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
context 'when environment_id is invalid' do
@@ -87,10 +72,6 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create, feature_categ
end
context 'when metrics dashboard feature is unavailable' do
- before do
- stub_feature_flags(remove_monitor_metrics: true)
- end
-
it_behaves_like 'a mutation that returns top-level errors',
errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
@@ -127,19 +108,8 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create, feature_categ
graphql_mutation(:create_annotation, variables)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: [described_class::ANNOTATION_SOURCE_ARGUMENT_ERROR]
- end
- end
-
- context 'without permission' do
- before do
- project.add_guest(current_user)
- end
-
- it 'does not create the annotation' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.not_to change { Metrics::Dashboard::Annotation.count }
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
end
@@ -174,7 +144,8 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create, feature_categ
graphql_mutation(:create_annotation, variables)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: [described_class::ANNOTATION_SOURCE_ARGUMENT_ERROR]
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
[:environment_id, :cluster_id].each do |arg_name|
diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb
index c81f6381398..6768998b31c 100644
--- a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb
@@ -7,19 +7,14 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Delete, feature_categ
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :private, :repository) }
- let_it_be(:annotation) { create(:metrics_dashboard_annotation) }
- let(:variables) { { id: GitlabSchema.id_from_object(annotation).to_s } }
+ let(:variables) { { id: 'ids-dont-matter' } }
let(:mutation) { graphql_mutation(:delete_annotation, variables) }
def mutation_response
graphql_mutation_response(:delete_annotation)
end
- before do
- stub_feature_flags(remove_monitor_metrics: false)
- end
-
specify { expect(described_class).to require_graphql_authorizations(:admin_metrics_dashboard_annotation) }
context 'when the user has permission to delete the annotation' do
@@ -30,16 +25,11 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Delete, feature_categ
context 'with invalid params' do
let(:variables) { { id: GitlabSchema.id_from_object(project).to_s } }
- it_behaves_like 'a mutation that returns top-level errors' do
- let(:match_errors) { contain_exactly(include('invalid value for id')) }
- end
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
context 'when metrics dashboard feature is unavailable' do
- before do
- stub_feature_flags(remove_monitor_metrics: true)
- end
-
it_behaves_like 'a mutation that returns top-level errors',
errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
@@ -51,11 +41,5 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Delete, feature_categ
end
it_behaves_like 'a mutation that returns top-level errors', errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
-
- it 'does not delete the annotation' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.not_to change { Metrics::Dashboard::Annotation.count }
- end
end
end
diff --git a/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb b/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb
index f18e0e44905..f30b7d0ea73 100644
--- a/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/linked_items/add_spec.rb
@@ -104,18 +104,15 @@ RSpec.describe "Add linked items to a work item", feature_category: :portfolio_m
context 'when there are more than the max allowed items to link' do
let(:max_work_items) { Mutations::WorkItems::LinkedItems::Base::MAX_WORK_ITEMS }
- let(:error_msg) { "No more than #{max_work_items} work items can be linked at the same time." }
-
- before do
- max_work_items.times { |i| ids_to_link.push("gid://gitlab/WorkItem/#{i}") }
- end
+ let(:ids_to_link) { (0..max_work_items).map { |i| "gid://gitlab/WorkItem/#{i}" } }
+ let(:error_msg) { "No more than #{max_work_items} work items can be modified at the same time." }
it 'returns an error message' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.not_to change { WorkItems::RelatedWorkItemLink.count }
- expect_graphql_errors_to_include("No more than #{max_work_items} work items can be linked at the same time.")
+ expect_graphql_errors_to_include(error_msg)
end
end
end
diff --git a/spec/requests/api/graphql/mutations/work_items/linked_items/remove_spec.rb b/spec/requests/api/graphql/mutations/work_items/linked_items/remove_spec.rb
new file mode 100644
index 00000000000..2ed4e1b4602
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/work_items/linked_items/remove_spec.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "Remove items linked to a work item", feature_category: :portfolio_management do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:guest) { create(:user).tap { |user| project.add_guest(user) } }
+ let_it_be(:work_item) { create(:work_item, project: project) }
+ let_it_be(:related1) { create(:work_item, project: project) }
+ let_it_be(:related2) { create(:work_item, project: project) }
+ let_it_be(:link1) { create(:work_item_link, source: work_item, target: related1) }
+ let_it_be(:link2) { create(:work_item_link, source: work_item, target: related2) }
+
+ let(:mutation_response) { graphql_mutation_response(:work_item_remove_linked_items) }
+ let(:mutation) { graphql_mutation(:workItemRemoveLinkedItems, input, fields) }
+ let(:ids_to_unlink) { [related1.to_global_id.to_s, related2.to_global_id.to_s] }
+ let(:input) { { 'id' => work_item.to_global_id.to_s, 'workItemsIds' => ids_to_unlink } }
+
+ let(:fields) do
+ <<~FIELDS
+ workItem {
+ id
+ widgets {
+ type
+ ... on WorkItemWidgetLinkedItems {
+ linkedItems {
+ edges {
+ node {
+ linkType
+ workItem {
+ id
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ errors
+ message
+ FIELDS
+ end
+
+ context 'when the user is not allowed to read the work item' do
+ let(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user has permissions to read the work item' do
+ let(:current_user) { guest }
+
+ it 'unlinks the work items' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { WorkItems::RelatedWorkItemLink.count }.by(-2)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['workItem']).to include('id' => work_item.to_global_id.to_s)
+ expect(mutation_response['message']).to eq("Successfully unlinked IDs: #{related1.id} and #{related2.id}.")
+ expect(mutation_response['workItem']['widgets']).to include(
+ {
+ 'linkedItems' => { 'edges' => [] }, 'type' => 'LINKED_ITEMS'
+ }
+ )
+ end
+
+ context 'when some items fail' do
+ let_it_be(:other_project) { create(:project, :private) }
+ let_it_be(:not_related) { create(:work_item, project: project) }
+ let_it_be(:no_access) { create(:work_item, project: other_project) }
+ let_it_be(:no_access_link) { create(:work_item_link, source: work_item, target: no_access) }
+
+ let(:ids_to_unlink) { [related1.to_global_id.to_s, not_related.to_global_id.to_s, no_access.to_global_id.to_s] }
+ let(:error_msg) do
+ "Successfully unlinked IDs: #{related1.id}. " \
+ "IDs with errors: #{no_access.id} could not be removed due to insufficient permissions, " \
+ "#{not_related.id} could not be removed due to not being linked."
+ end
+
+ it 'remove valid item and include failing ids in response message' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { WorkItems::RelatedWorkItemLink.count }.by(-1)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['message']).to eq(error_msg)
+ end
+ end
+
+ context 'when there are more than the max allowed items to unlink' do
+ let(:max_work_items) { Mutations::WorkItems::LinkedItems::Base::MAX_WORK_ITEMS }
+ let(:ids_to_unlink) { (0..max_work_items).map { |i| "gid://gitlab/WorkItem/#{i}" } }
+
+ it 'returns an error message' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { WorkItems::RelatedWorkItemLink.count }
+
+ expect_graphql_errors_to_include("No more than #{max_work_items} work items can be modified at the same time.")
+ end
+ end
+
+ context 'when workItemsIds is empty' do
+ let(:ids_to_unlink) { [] }
+
+ it_behaves_like 'a mutation that returns top-level errors', errors: ['workItemsIds cannot be empty']
+ end
+
+ context 'when `linked_work_items` feature flag is disabled' do
+ before do
+ stub_feature_flags(linked_work_items: false)
+ end
+
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/work_items/update_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_spec.rb
index cff21c10a5a..c7c68696888 100644
--- a/spec/requests/api/graphql/mutations/work_items/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/update_spec.rb
@@ -1431,6 +1431,20 @@ RSpec.describe 'Update a work item', feature_category: :team_planning do
'User has not awarded emoji of type thumbsdown on the awardable'
end
end
+
+ context 'when toggling award emoji' do
+ let(:award_action) { 'TOGGLE' }
+
+ context 'when emoji award is present' do
+ let(:award_name) { 'thumbsup' }
+
+ it_behaves_like 'request that removes emoji'
+ end
+
+ context 'when emoji award is not present' do
+ it_behaves_like 'request that adds emoji'
+ end
+ end
end
end
diff --git a/spec/requests/api/graphql/organizations/organization_query_spec.rb b/spec/requests/api/graphql/organizations/organization_query_spec.rb
new file mode 100644
index 00000000000..d02158382eb
--- /dev/null
+++ b/spec/requests/api/graphql/organizations/organization_query_spec.rb
@@ -0,0 +1,178 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting organization information', feature_category: :cell do
+ include GraphqlHelpers
+
+ let(:query) { graphql_query_for(:organization, { id: organization.to_global_id }, organization_fields) }
+ let(:current_user) { user }
+ let(:groups) { graphql_data_at(:organization, :groups, :nodes) }
+ let(:organization_fields) do
+ <<~FIELDS
+ id
+ path
+ groups {
+ nodes {
+ id
+ }
+ }
+ FIELDS
+ end
+
+ let_it_be(:organization_user) { create(:organization_user) }
+ let_it_be(:organization) { organization_user.organization }
+ let_it_be(:user) { organization_user.user }
+ let_it_be(:public_group) { create(:group, name: 'public-group', organization: organization) }
+ let_it_be(:other_group) { create(:group, name: 'other-group', organization: organization) }
+ let_it_be(:outside_organization_group) { create(:group) }
+
+ let_it_be(:private_group) do
+ create(:group, :private, name: 'private-group', organization: organization)
+ end
+
+ let_it_be(:no_access_group_in_org) do
+ create(:group, :private, name: 'no-access', organization: organization)
+ end
+
+ before_all do
+ private_group.add_developer(user)
+ public_group.add_developer(user)
+ other_group.add_developer(user)
+ outside_organization_group.add_developer(user)
+ end
+
+ subject(:request_organization) { post_graphql(query, current_user: current_user) }
+
+ context 'when the user does not have access to the organization' do
+ let(:current_user) { create(:user) }
+
+ it 'returns the organization as all organizations are public' do
+ request_organization
+
+ expect(graphql_data_at(:organization, :id)).to eq(organization.to_global_id.to_s)
+ end
+ end
+
+ context 'when user has access to the organization' do
+ it_behaves_like 'a working graphql query' do
+ before do
+ request_organization
+ end
+ end
+
+ context 'when resolve_organization_groups feature flag is disabled' do
+ before do
+ stub_feature_flags(resolve_organization_groups: false)
+ end
+
+ it 'returns no groups' do
+ request_organization
+
+ expect(graphql_data_at(:organization)).not_to be_nil
+ expect(graphql_data_at(:organization, :groups, :nodes)).to be_empty
+ end
+ end
+
+ context 'when requesting organization user' do
+ let(:organization_fields) do
+ <<~FIELDS
+ organizationUsers {
+ nodes {
+ badges
+ id
+ user {
+ id
+ }
+ }
+ }
+ FIELDS
+ end
+
+ it 'returns correct organization user fields' do
+ request_organization
+
+ organization_user_node = graphql_data_at(:organization, :organizationUsers, :nodes).first
+ expected_attributes = {
+ "badges" => ["It's you!"],
+ "id" => organization_user.to_global_id.to_s,
+ "user" => { "id" => user.to_global_id.to_s }
+ }
+ expect(organization_user_node).to match(expected_attributes)
+ end
+
+ it 'avoids N+1 queries for all the fields' do
+ base_query_count = ActiveRecord::QueryRecorder.new { run_query }
+
+ organization_user_2 = create(:organization_user, organization: organization)
+ other_group.add_developer(organization_user_2.user)
+
+ expect { run_query }.not_to exceed_query_limit(base_query_count)
+ end
+
+ private
+
+ def run_query
+ run_with_clean_state(query, context: { current_user: current_user })
+ end
+ end
+
+ context 'with `search` argument' do
+ let(:search) { 'oth' }
+ let(:organization_fields) do
+ <<~FIELDS
+ id
+ path
+ groups(search: "#{search}") {
+ nodes {
+ id
+ name
+ }
+ }
+ FIELDS
+ end
+
+ it 'filters groups by name' do
+ request_organization
+
+ expect(groups).to contain_exactly(a_graphql_entity_for(other_group))
+ end
+ end
+
+ context 'with `sort` argument' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:authorized_groups) { [public_group, private_group, other_group] }
+
+ where(:field, :direction, :sorted_groups) do
+ 'id' | 'asc' | lazy { authorized_groups.sort_by(&:id) }
+ 'id' | 'desc' | lazy { authorized_groups.sort_by(&:id).reverse }
+ 'name' | 'asc' | lazy { authorized_groups.sort_by(&:name) }
+ 'name' | 'desc' | lazy { authorized_groups.sort_by(&:name).reverse }
+ 'path' | 'asc' | lazy { authorized_groups.sort_by(&:path) }
+ 'path' | 'desc' | lazy { authorized_groups.sort_by(&:path).reverse }
+ end
+
+ with_them do
+ let(:sort) { "#{field}_#{direction}".upcase }
+ let(:organization_fields) do
+ <<~FIELDS
+ id
+ path
+ groups(sort: #{sort}) {
+ nodes {
+ id
+ }
+ }
+ FIELDS
+ end
+
+ it 'sorts the groups' do
+ request_organization
+
+ expect(groups.pluck('id')).to eq(sorted_groups.map(&:to_global_id).map(&:to_s))
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/packages/package_spec.rb b/spec/requests/api/graphql/packages/package_spec.rb
index 7610a4aaac1..c8cef07c4ff 100644
--- a/spec/requests/api/graphql/packages/package_spec.rb
+++ b/spec/requests/api/graphql/packages/package_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'package details', feature_category: :package_registry do
end
let(:depth) { 3 }
- let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
+ let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles runners] }
let(:metadata) { query_graphql_fragment('ComposerMetadata') }
let(:package_files) { all_graphql_fields_for('PackageFile') }
let(:package_global_id) { global_id_of(composer_package) }
diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb
index 80c7258c05d..9ca5df95d30 100644
--- a/spec/requests/api/graphql/project/merge_request_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request_spec.rb
@@ -21,8 +21,11 @@ RSpec.describe 'getting merge request information nested in a project', feature_
end
it_behaves_like 'a working graphql query' do
- # we exclude Project.pipeline because it needs arguments
- let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: %w[jobs pipeline]) }
+ # we exclude Project.pipeline because it needs arguments,
+ # codequalityReportsComparer because no pipeline exist yet
+ # and runners because the user is not an admin and therefore has no access
+ let(:excluded) { %w[jobs pipeline runners codequalityReportsComparer] }
+ let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: excluded) }
before do
post_graphql(query, current_user: current_user)
diff --git a/spec/requests/api/graphql/project/runners_spec.rb b/spec/requests/api/graphql/project/runners_spec.rb
index bee7ce2e372..68e95de49bc 100644
--- a/spec/requests/api/graphql/project/runners_spec.rb
+++ b/spec/requests/api/graphql/project/runners_spec.rb
@@ -28,6 +28,8 @@ RSpec.describe 'Project.runners', feature_category: :runner do
)
end
+ subject(:request) { post_graphql(query, current_user: user) }
+
context 'when the user is a project admin' do
before do
project.add_maintainer(user)
@@ -36,7 +38,7 @@ RSpec.describe 'Project.runners', feature_category: :runner do
let(:expected_ids) { [project_runner, group_runner, instance_runner].map { |g| g.to_global_id.to_s } }
it 'returns all runners available to project' do
- post_graphql(query, current_user: user)
+ request
expect(graphql_data_at(:project, :runners, :nodes).pluck('id')).to match_array(expected_ids)
end
@@ -47,10 +49,14 @@ RSpec.describe 'Project.runners', feature_category: :runner do
project.add_developer(user)
end
- it 'returns no runners' do
- post_graphql(query, current_user: user)
+ it 'returns nil runners and an error' do
+ request
- expect(graphql_data_at(:project, :runners, :nodes)).to be_empty
+ expect(graphql_data_at(:project, :runners)).to be_nil
+ expect(graphql_errors).to contain_exactly(a_hash_including(
+ 'message' => a_string_including("you don't have permission to perform this action"),
+ 'path' => %w[project runners]
+ ))
end
end
end
diff --git a/spec/requests/api/graphql/project/work_items_spec.rb b/spec/requests/api/graphql/project/work_items_spec.rb
index 4aba83dae92..d5d3d6c578f 100644
--- a/spec/requests/api/graphql/project/work_items_spec.rb
+++ b/spec/requests/api/graphql/project/work_items_spec.rb
@@ -30,16 +30,14 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team
let_it_be(:confidential_item) { create(:work_item, confidential: true, project: project, title: 'item3') }
let_it_be(:other_item) { create(:work_item) }
- let(:items_data) { graphql_data['project']['workItems']['edges'] }
+ let(:items_data) { graphql_data['project']['workItems']['nodes'] }
let(:item_filter_params) { {} }
let(:fields) do
<<~QUERY
- edges {
- node {
+ nodes {
#{all_graphql_fields_for('workItems'.classify, max_depth: 2)}
}
- }
QUERY
end
@@ -69,6 +67,15 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team
end
end
+ it_behaves_like 'graphql work item list request spec' do
+ let_it_be(:container_build_params) { { project: project } }
+ let(:work_item_node_path) { %w[project workItems nodes] }
+
+ def post_query(request_user = current_user)
+ post_graphql(query, current_user: request_user)
+ end
+ end
+
describe 'N + 1 queries' do
context 'when querying root fields' do
it_behaves_like 'work items resolver without N + 1 queries'
@@ -199,12 +206,6 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team
end
end
- it_behaves_like 'a working graphql query' do
- before do
- post_graphql(query, current_user: current_user)
- end
- end
-
context 'when the user does not have access to the item' do
before do
project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
@@ -237,25 +238,12 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team
context 'when filtering by search' do
it_behaves_like 'query with a search term' do
- let(:issuable_data) { items_data }
+ let(:ids) { item_ids }
let(:user) { current_user }
let_it_be(:issuable) { create(:work_item, project: project, description: 'bar') }
end
end
- context 'when filtering by author username' do
- let_it_be(:author) { create(:author) }
- let_it_be(:item_3) { create(:work_item, project: project, author: author) }
-
- let(:item_filter_params) { { author_username: item_3.author.username } }
-
- it 'returns correct results' do
- post_graphql(query, current_user: current_user)
-
- expect(item_ids).to match_array([item_3.to_global_id.to_s])
- end
- end
-
describe 'sorting and pagination' do
let(:data_path) { [:project, :work_items] }
@@ -415,7 +403,7 @@ RSpec.describe 'getting a work item list for a project', feature_category: :team
end
def item_ids
- graphql_dig_at(items_data, :node, :id)
+ graphql_dig_at(items_data, :id)
end
def query(params = item_filter_params)
diff --git a/spec/requests/api/graphql/project_query_spec.rb b/spec/requests/api/graphql/project_query_spec.rb
index 783e96861b1..2d9c6367676 100644
--- a/spec/requests/api/graphql/project_query_spec.rb
+++ b/spec/requests/api/graphql/project_query_spec.rb
@@ -56,15 +56,21 @@ RSpec.describe 'getting project information', feature_category: :groups_and_proj
expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(baseline)
end
- context 'when other project member is not authorized to see the full token' do
+ context 'when another project member or owner who is not also the token owner' do
before do
- project.add_maintainer(other_user)
+ project.add_owner(other_user)
post_graphql(query, current_user: other_user)
end
- it 'shows truncated token' do
- expect(graphql_data_at(:project, :pipeline_triggers,
- :nodes).first['token']).to eql pipeline_trigger.token[0, 4]
+ it 'is not authorized and shows truncated token' do
+ expect(graphql_data_at(:project, :pipeline_triggers, :nodes).first).to match({
+ 'id' => pipeline_trigger.to_global_id.to_s,
+ 'canAccessProject' => true,
+ 'description' => pipeline_trigger.description,
+ 'hasTokenExposed' => false,
+ 'lastUsed' => nil,
+ 'token' => pipeline_trigger.token[0, 4]
+ })
end
end
@@ -199,7 +205,7 @@ RSpec.describe 'getting project information', feature_category: :groups_and_proj
context 'when the project is a catalog resource' do
before do
- create(:catalog_resource, project: project)
+ create(:ci_catalog_resource, project: project)
end
it 'is true' do
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
index fa354bc1f66..3691e023a53 100644
--- a/spec/requests/api/graphql/work_item_spec.rb
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -70,7 +70,8 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
'adminWorkItem' => true,
'adminParentLink' => true,
'setWorkItemMetadata' => true,
- 'createNote' => true
+ 'createNote' => true,
+ 'adminWorkItemLink' => true
},
'project' => hash_including('id' => project.to_gid.to_s, 'fullPath' => project.full_path)
)
@@ -541,13 +542,10 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
end
describe 'linked items widget' do
- let_it_be(:related_item1) { create(:work_item, project: project) }
- let_it_be(:related_item2) { create(:work_item, project: project) }
- let_it_be(:related_item3) { create(:work_item) }
- let_it_be(:link1) { create(:work_item_link, source: work_item, target: related_item1, link_type: 'relates_to') }
- let_it_be(:link2) { create(:work_item_link, source: work_item, target: related_item2, link_type: 'relates_to') }
- let_it_be(:link3) { create(:work_item_link, source: work_item, target: related_item3, link_type: 'relates_to') }
-
+ let_it_be(:related_item) { create(:work_item, project: project) }
+ let_it_be(:blocked_item) { create(:work_item, project: project) }
+ let_it_be(:link1) { create(:work_item_link, source: work_item, target: related_item, link_type: 'relates_to') }
+ let_it_be(:link2) { create(:work_item_link, source: work_item, target: blocked_item, link_type: 'blocks') }
let(:work_item_fields) do
<<~GRAPHQL
id
@@ -580,12 +578,12 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
hash_including(
'linkId' => link1.to_gid.to_s, 'linkType' => 'relates_to',
'linkCreatedAt' => link1.created_at.iso8601, 'linkUpdatedAt' => link1.updated_at.iso8601,
- 'workItem' => { 'id' => related_item1.to_gid.to_s }
+ 'workItem' => { 'id' => related_item.to_gid.to_s }
),
hash_including(
- 'linkId' => link2.to_gid.to_s, 'linkType' => 'relates_to',
+ 'linkId' => link2.to_gid.to_s, 'linkType' => 'blocks',
'linkCreatedAt' => link2.created_at.iso8601, 'linkUpdatedAt' => link2.updated_at.iso8601,
- 'workItem' => { 'id' => related_item2.to_gid.to_s }
+ 'workItem' => { 'id' => blocked_item.to_gid.to_s }
)
]
) }
@@ -594,6 +592,30 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
)
end
+ context 'when filtering by link type' do
+ let(:work_item_fields) do
+ <<~GRAPHQL
+ widgets {
+ type
+ ... on WorkItemWidgetLinkedItems {
+ linkedItems(filter: RELATED) {
+ nodes {
+ linkType
+ }
+ }
+ }
+ }
+ GRAPHQL
+ end
+
+ it 'returns items with specified type' do
+ widget_data = work_item_data["widgets"].find { |widget| widget.key?("linkedItems") }["linkedItems"]
+
+ expect(widget_data["nodes"].size).to eq(1)
+ expect(widget_data.dig("nodes", 0, "linkType")).to eq('relates_to')
+ end
+ end
+
context 'when `linked_work_items` feature flag is disabled' do
before do
stub_feature_flags(linked_work_items: false)
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 5296a8b3e93..7b1da1c691d 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -6,7 +6,6 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do
include GroupAPIHelpers
include UploadHelpers
include WorkhorseHelpers
- include KeysetPaginationHelpers
let_it_be(:user1) { create(:user, can_create_group: false) }
let_it_be(:user2) { create(:user) }
@@ -196,37 +195,10 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do
end
end
- context 'keyset pagination' do
- context 'on making requests with supported ordering structure' do
- it 'paginates the records correctly', :aggregate_failures do
- # first page
- get api('/groups'), params: { pagination: 'keyset', per_page: 1 }
-
- expect(response).to have_gitlab_http_status(:ok)
- records = json_response
- expect(records.size).to eq(1)
- expect(records.first['id']).to eq(group_1.id)
-
- params_for_next_page = pagination_params_from_next_url(response)
- expect(params_for_next_page).to include('cursor')
-
- get api('/groups'), params: params_for_next_page
-
- expect(response).to have_gitlab_http_status(:ok)
- records = Gitlab::Json.parse(response.body)
- expect(records.size).to eq(1)
- expect(records.first['id']).to eq(group_2.id)
- end
- end
-
- context 'on making requests with unsupported ordering structure' do
- it 'returns error', :aggregate_failures do
- get api('/groups'), params: { pagination: 'keyset', per_page: 1, order_by: 'path', sort: 'desc' }
-
- expect(response).to have_gitlab_http_status(:method_not_allowed)
- expect(json_response['error']).to eq('Keyset pagination is not yet available for this type of request')
- end
- end
+ it_behaves_like 'an endpoint with keyset pagination', invalid_order: 'path' do
+ let(:first_record) { group_1 }
+ let(:second_record) { group_2 }
+ let(:api_call) { api('/groups') }
end
end
end
diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb
index fa35e367420..cf0cd9a2e85 100644
--- a/spec/requests/api/internal/base_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -881,7 +881,6 @@ RSpec.describe API::Internal::Base, feature_category: :system_access do
end
context "custom action" do
- let(:access_checker) { double(Gitlab::GitAccess) }
let(:payload) do
{
'action' => 'geo_proxy_to_primary',
@@ -898,7 +897,8 @@ RSpec.describe API::Internal::Base, feature_category: :system_access do
before do
project.add_guest(user)
- expect(Gitlab::GitAccess).to receive(:new).with(
+
+ expect_next_instance_of(Gitlab::GitAccess,
key,
project,
'ssh',
@@ -907,11 +907,12 @@ RSpec.describe API::Internal::Base, feature_category: :system_access do
repository_path: "#{project.full_path}.git",
redirected_path: nil
}
- ).and_return(access_checker)
- expect(access_checker).to receive(:check).with(
- 'git-receive-pack',
- 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master'
- ).and_return(custom_action_result)
+ ) do |access_checker|
+ expect(access_checker).to receive(:check).with(
+ 'git-receive-pack',
+ 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master'
+ ).and_return(custom_action_result)
+ end
end
context "git push" do
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index ec30840dfd8..1e8397773be 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -131,7 +131,8 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :deployment_manageme
k8s_api_proxy_request: 5,
flux_git_push_notifications_total: 42,
k8s_api_proxy_requests_via_ci_access: 43,
- k8s_api_proxy_requests_via_user_access: 44
+ k8s_api_proxy_requests_via_user_access: 44,
+ k8s_api_proxy_requests_via_pat_access: 45
}
unique_counters = {
agent_users_using_ci_tunnel: [10, 999, 777, 10],
@@ -139,6 +140,8 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :deployment_manageme
k8s_api_proxy_requests_unique_agents_via_ci_access: [10, 999, 777, 10],
k8s_api_proxy_requests_unique_users_via_user_access: [10, 999, 777, 10],
k8s_api_proxy_requests_unique_agents_via_user_access: [10, 999, 777, 10],
+ k8s_api_proxy_requests_unique_users_via_pat_access: [10, 999, 777, 10],
+ k8s_api_proxy_requests_unique_agents_via_pat_access: [10, 999, 777, 10],
flux_git_push_notified_unique_projects: [10, 999, 777, 10]
}
expected_counters = {
@@ -146,7 +149,8 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :deployment_manageme
kubernetes_agent_k8s_api_proxy_request: request_count * counters[:k8s_api_proxy_request],
kubernetes_agent_flux_git_push_notifications_total: request_count * counters[:flux_git_push_notifications_total],
kubernetes_agent_k8s_api_proxy_requests_via_ci_access: request_count * counters[:k8s_api_proxy_requests_via_ci_access],
- kubernetes_agent_k8s_api_proxy_requests_via_user_access: request_count * counters[:k8s_api_proxy_requests_via_user_access]
+ kubernetes_agent_k8s_api_proxy_requests_via_user_access: request_count * counters[:k8s_api_proxy_requests_via_user_access],
+ kubernetes_agent_k8s_api_proxy_requests_via_pat_access: request_count * counters[:k8s_api_proxy_requests_via_pat_access]
}
request_count.times do
@@ -492,73 +496,125 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :deployment_manageme
Clusters::Agents::Authorizations::UserAccess::RefreshService.new(agent, config: user_access_config).execute
end
- it 'returns 400 when cookie is invalid' do
- send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: '123', csrf_token: mask_token(new_token) })
+ context 'when the access type is access_token' do
+ let(:personal_access_token) { create(:personal_access_token, user: user, scopes: [Gitlab::Auth::K8S_PROXY_SCOPE]) }
- expect(response).to have_gitlab_http_status(:bad_request)
- end
+ it 'returns 200 when the user has access' do
+ deployment_project.add_member(user, :developer)
- it 'returns 401 when session is not found' do
- access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id('abc')
- send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(new_token) })
+ send_request(params: { agent_id: agent.id, access_type: 'personal_access_token', access_key: personal_access_token.token })
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
+ expect(response).to have_gitlab_http_status(:success)
+ end
- it 'returns 401 when CSRF token does not match' do
- public_id = stub_user_session(user, new_token)
- access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
- send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(new_token) })
+ it 'returns 400 when the feature flag is disabled' do
+ deployment_project.add_member(user, :developer)
+ stub_feature_flags(k8s_proxy_pat: false)
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
+ send_request(params: { agent_id: agent.id, access_type: 'personal_access_token', access_key: personal_access_token.token })
- it 'returns 404 for non-existent agent' do
- token = new_token
- public_id = stub_user_session(user, token)
- access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
- send_request(params: { agent_id: non_existing_record_id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
- expect(response).to have_gitlab_http_status(:not_found)
- end
+ it 'returns 403 when user has no access' do
+ send_request(params: { agent_id: agent.id, access_type: 'personal_access_token', access_key: personal_access_token.token })
- it 'returns 403 when user has no access' do
- token = new_token
- public_id = stub_user_session(user, token)
- access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
- send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
- expect(response).to have_gitlab_http_status(:forbidden)
- end
+ it 'returns 403 when user has incorrect token scope' do
+ personal_access_token.update!(scopes: [Gitlab::Auth::READ_API_SCOPE])
+ deployment_project.add_member(user, :developer)
- it 'returns 200 when user has access' do
- deployment_project.add_member(user, :developer)
- token = new_token
- public_id = stub_user_session(user, token)
- access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
- send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+ send_request(params: { agent_id: agent.id, access_type: 'personal_access_token', access_key: personal_access_token.token })
- expect(response).to have_gitlab_http_status(:success)
- end
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns 403 when user has no access to requested agent' do
+ deployment_project.add_member(user, :developer)
+
+ send_request(params: { agent_id: another_agent.id, access_type: 'personal_access_token', access_key: personal_access_token.token })
- it 'returns 401 when user has valid KAS cookie and CSRF token but has no access to requested agent' do
- deployment_project.add_member(user, :developer)
- token = new_token
- public_id = stub_user_session(user, token)
- access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
- send_request(params: { agent_id: another_agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns 404 for non-existent agent' do
+ send_request(params: { agent_id: non_existing_record_id, access_type: 'personal_access_token', access_key: personal_access_token.token })
- expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
- it 'returns 401 when user id is not found in session' do
- deployment_project.add_member(user, :developer)
- token = new_token
- public_id = stub_user_session_with_no_user_id(user, token)
- access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
- send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+ context 'when the access type is session_cookie' do
+ it 'returns 400 when cookie is invalid' do
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: '123', csrf_token: mask_token(new_token) })
- expect(response).to have_gitlab_http_status(:unauthorized)
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'returns 401 when session is not found' do
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id('abc')
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(new_token) })
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns 401 when CSRF token does not match' do
+ public_id = stub_user_session(user, new_token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(new_token) })
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns 404 for non-existent agent' do
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: non_existing_record_id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns 403 when user has no access' do
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns 200 when user has access' do
+ deployment_project.add_member(user, :developer)
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+
+ it 'returns 401 when user has valid KAS cookie and CSRF token but has no access to requested agent' do
+ deployment_project.add_member(user, :developer)
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: another_agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns 401 when user id is not found in session' do
+ deployment_project.add_member(user, :developer)
+ token = new_token
+ public_id = stub_user_session_with_no_user_id(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 4edcd66e91a..d3f8aeb3e76 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -113,32 +113,12 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc
end
context 'with merge status recheck projection' do
- context 'with batched_api_mergeability_checks FF on' do
- it 'checks mergeability asynchronously in batch', :sidekiq_inline do
- get(api(endpoint_path, user2), params: { with_merge_status_recheck: true })
-
- expect_successful_response_with_paginated_array
-
- expect(merge_request.reload.merge_status).to eq('can_be_merged')
- end
- end
-
- context 'with batched_api_mergeability_checks FF off' do
- before do
- stub_feature_flags(batched_api_mergeability_checks: false)
- end
-
- it 'checks mergeability asynchronously' do
- expect_next_instances_of(check_service_class, (1..2)) do |service|
- expect(service).not_to receive(:execute)
- expect(service).to receive(:async_execute).and_call_original
- end
+ it 'checks mergeability asynchronously in batch', :sidekiq_inline do
+ get(api(endpoint_path, user2), params: { with_merge_status_recheck: true })
- get(api(endpoint_path, user2), params: { with_merge_status_recheck: true })
+ expect_successful_response_with_paginated_array
- expect_successful_response_with_paginated_array
- expect(mr_entity['merge_status']).to eq('checking')
- end
+ expect(merge_request.reload.merge_status).to eq('can_be_merged')
end
end
diff --git a/spec/requests/api/metadata_spec.rb b/spec/requests/api/metadata_spec.rb
index e15186c48a5..b81fe3f51b5 100644
--- a/spec/requests/api/metadata_spec.rb
+++ b/spec/requests/api/metadata_spec.rb
@@ -41,6 +41,22 @@ RSpec.describe API::Metadata, feature_category: :shared do
end
end
+ context 'with ai_features scope' do
+ let(:scopes) { %i(ai_features) }
+
+ it 'returns the metadata information' do
+ get api(endpoint, personal_access_token: personal_access_token)
+
+ expect_metadata
+ end
+
+ it 'returns "200" response on head requests' do
+ head api(endpoint, personal_access_token: personal_access_token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
context 'with read_user scope' do
let(:scopes) { %i(read_user) }
@@ -57,7 +73,7 @@ RSpec.describe API::Metadata, feature_category: :shared do
end
end
- context 'with neither api nor read_user scope' do
+ context 'with neither api, ai_features nor read_user scope' do
let(:scopes) { %i(read_repository) }
it 'returns authorization error' do
diff --git a/spec/requests/api/metrics/dashboard/annotations_spec.rb b/spec/requests/api/metrics/dashboard/annotations_spec.rb
index 6000fc2a6b7..0d4a112c527 100644
--- a/spec/requests/api/metrics/dashboard/annotations_spec.rb
+++ b/spec/requests/api/metrics/dashboard/annotations_spec.rb
@@ -10,13 +10,12 @@ RSpec.describe API::Metrics::Dashboard::Annotations, feature_category: :metrics
let(:dashboard) { 'config/prometheus/common_metrics.yml' }
let(:starting_at) { Time.now.iso8601 }
let(:ending_at) { 1.hour.from_now.iso8601 }
- let(:params) { attributes_for(:metrics_dashboard_annotation, environment: environment, starting_at: starting_at, ending_at: ending_at, dashboard_path: dashboard) }
+ let(:params) { { environment: environment, starting_at: starting_at, ending_at: ending_at, dashboard_path: dashboard, description: 'desc' } }
shared_examples 'POST /:source_type/:id/metrics_dashboard/annotations' do |source_type|
let(:url) { "/#{source_type.pluralize}/#{source.id}/metrics_dashboard/annotations" }
before do
- stub_feature_flags(remove_monitor_metrics: false)
project.add_developer(user)
end
diff --git a/spec/requests/api/metrics/user_starred_dashboards_spec.rb b/spec/requests/api/metrics/user_starred_dashboards_spec.rb
index bdeba777350..d42cec7af30 100644
--- a/spec/requests/api/metrics/user_starred_dashboards_spec.rb
+++ b/spec/requests/api/metrics/user_starred_dashboards_spec.rb
@@ -58,11 +58,6 @@ RSpec.describe API::Metrics::UserStarredDashboards, feature_category: :metrics d
end
describe 'DELETE /projects/:id/metrics/user_starred_dashboards' do
- let_it_be(:user_starred_dashboard_1) { create(:metrics_users_starred_dashboard, user: user, project: project, dashboard_path: dashboard) }
- let_it_be(:user_starred_dashboard_2) { create(:metrics_users_starred_dashboard, user: user, project: project) }
- let_it_be(:other_user_starred_dashboard) { create(:metrics_users_starred_dashboard, project: project) }
- let_it_be(:other_project_starred_dashboard) { create(:metrics_users_starred_dashboard, user: user) }
-
before do
project.add_reporter(user)
end
diff --git a/spec/requests/api/ml/mlflow/experiments_spec.rb b/spec/requests/api/ml/mlflow/experiments_spec.rb
index fc2e814752c..409b4529699 100644
--- a/spec/requests/api/ml/mlflow/experiments_spec.rb
+++ b/spec/requests/api/ml/mlflow/experiments_spec.rb
@@ -179,7 +179,7 @@ RSpec.describe API::Ml::Mlflow::Experiments, feature_category: :mlops do
end
it_behaves_like 'MLflow|shared error cases'
- it_behaves_like 'MLflow|Requires api scope'
+ it_behaves_like 'MLflow|Requires api scope and write permission'
end
end
@@ -203,7 +203,7 @@ RSpec.describe API::Ml::Mlflow::Experiments, feature_category: :mlops do
end
it_behaves_like 'MLflow|shared error cases'
- it_behaves_like 'MLflow|Requires api scope'
+ it_behaves_like 'MLflow|Requires api scope and write permission'
it_behaves_like 'MLflow|Bad Request on missing required', [:key, :value]
end
end
diff --git a/spec/requests/api/ml/mlflow/runs_spec.rb b/spec/requests/api/ml/mlflow/runs_spec.rb
index 45479666e9a..af04c387830 100644
--- a/spec/requests/api/ml/mlflow/runs_spec.rb
+++ b/spec/requests/api/ml/mlflow/runs_spec.rb
@@ -129,7 +129,7 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
end
it_behaves_like 'MLflow|shared error cases'
- it_behaves_like 'MLflow|Requires api scope'
+ it_behaves_like 'MLflow|Requires api scope and write permission'
end
end
@@ -185,6 +185,132 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
end
end
+ describe 'GET /projects/:id/ml/mlflow/api/2.0/mlflow/runs/search' do
+ let_it_be(:search_experiment) { create(:ml_experiments, user: nil, project: project) }
+ let_it_be(:first_candidate) do
+ create(:ml_candidates, experiment: search_experiment, name: 'c', user: nil).tap do |c|
+ c.metrics.create!(name: 'metric1', value: 0.3)
+ end
+ end
+
+ let_it_be(:second_candidate) do
+ create(:ml_candidates, experiment: search_experiment, name: 'a', user: nil).tap do |c|
+ c.metrics.create!(name: 'metric1', value: 0.2)
+ end
+ end
+
+ let_it_be(:third_candidate) do
+ create(:ml_candidates, experiment: search_experiment, name: 'b', user: nil).tap do |c|
+ c.metrics.create!(name: 'metric1', value: 0.6)
+ end
+ end
+
+ let(:route) { "/projects/#{project_id}/ml/mlflow/api/2.0/mlflow/runs/search" }
+ let(:order_by) { nil }
+ let(:default_params) do
+ {
+ 'max_results' => 2,
+ 'experiment_ids' => [search_experiment.iid],
+ 'order_by' => order_by
+ }
+ end
+
+ it 'searches runs for a project', :aggregate_failures do
+ is_expected.to have_gitlab_http_status(:ok)
+ is_expected.to match_response_schema('ml/search_runs')
+ end
+
+ describe 'pagination and ordering' do
+ RSpec.shared_examples 'a paginated search runs request with order' do
+ it 'paginates respecting the provided order by' do
+ first_page_runs = json_response['runs']
+ expect(first_page_runs.size).to eq(2)
+
+ expect(first_page_runs[0]['info']['run_id']).to eq(expected_order[0].eid)
+ expect(first_page_runs[1]['info']['run_id']).to eq(expected_order[1].eid)
+
+ params = default_params.merge(page_token: json_response['next_page_token'])
+
+ get api(route), params: params, headers: headers
+
+ second_page_response = Gitlab::Json.parse(response.body)
+ second_page_runs = second_page_response['runs']
+
+ expect(second_page_response['next_page_token']).to be_nil
+ expect(second_page_runs.size).to eq(1)
+ expect(second_page_runs[0]['info']['run_id']).to eq(expected_order[2].eid)
+ end
+ end
+
+ let(:default_order) { [third_candidate, second_candidate, first_candidate] }
+
+ context 'when ordering is not provided' do
+ let(:expected_order) { default_order }
+
+ it_behaves_like 'a paginated search runs request with order'
+ end
+
+ context 'when order by column is provided', 'and column exists' do
+ let(:order_by) { 'name ASC' }
+ let(:expected_order) { [second_candidate, third_candidate, first_candidate] }
+
+ it_behaves_like 'a paginated search runs request with order'
+ end
+
+ context 'when order by column is provided', 'and column does not exist' do
+ let(:order_by) { 'something DESC' }
+ let(:expected_order) { default_order }
+
+ it_behaves_like 'a paginated search runs request with order'
+ end
+
+ context 'when order by metric is provided', 'and metric exists' do
+ let(:order_by) { 'metrics.metric1' }
+ let(:expected_order) { [third_candidate, first_candidate, second_candidate] }
+
+ it_behaves_like 'a paginated search runs request with order'
+ end
+
+ context 'when order by metric is provided', 'and metric does not exist' do
+ let(:order_by) { 'metrics.something' }
+
+ it 'returns no results' do
+ expect(json_response['runs']).to be_empty
+ end
+ end
+
+ context 'when order by params is provided' do
+ let(:order_by) { 'params.something' }
+ let(:expected_order) { default_order }
+
+ it_behaves_like 'a paginated search runs request with order'
+ end
+ end
+
+ describe 'Error States' do
+ context 'when experiment_ids is not passed' do
+ let(:default_params) { {} }
+
+ it_behaves_like 'MLflow|Bad Request'
+ end
+
+ context 'when experiment_ids is empty' do
+ let(:default_params) { { 'experiment_ids' => [] } }
+
+ it_behaves_like 'MLflow|Not Found - Resource Does Not Exist'
+ end
+
+ context 'when experiment_ids is invalid' do
+ let(:default_params) { { 'experiment_ids' => [non_existing_record_id] } }
+
+ it_behaves_like 'MLflow|Not Found - Resource Does Not Exist'
+ end
+
+ it_behaves_like 'MLflow|shared error cases'
+ it_behaves_like 'MLflow|Requires read_api scope'
+ end
+ end
+
describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/runs/update' do
let(:default_params) { { run_id: candidate.eid.to_s, status: 'FAILED', end_time: Time.now.to_i } }
let(:request) { post api(route), params: params, headers: headers }
@@ -220,7 +346,7 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
end
it_behaves_like 'MLflow|shared error cases'
- it_behaves_like 'MLflow|Requires api scope'
+ it_behaves_like 'MLflow|Requires api scope and write permission'
it_behaves_like 'MLflow|run_id param error cases'
end
end
@@ -238,7 +364,7 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
describe 'Error Cases' do
it_behaves_like 'MLflow|shared error cases'
- it_behaves_like 'MLflow|Requires api scope'
+ it_behaves_like 'MLflow|Requires api scope and write permission'
it_behaves_like 'MLflow|run_id param error cases'
it_behaves_like 'MLflow|Bad Request on missing required', [:key, :value, :timestamp]
end
@@ -263,7 +389,7 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
end
it_behaves_like 'MLflow|shared error cases'
- it_behaves_like 'MLflow|Requires api scope'
+ it_behaves_like 'MLflow|Requires api scope and write permission'
it_behaves_like 'MLflow|run_id param error cases'
it_behaves_like 'MLflow|Bad Request on missing required', [:key, :value]
end
@@ -288,7 +414,7 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
end
it_behaves_like 'MLflow|shared error cases'
- it_behaves_like 'MLflow|Requires api scope'
+ it_behaves_like 'MLflow|Requires api scope and write permission'
it_behaves_like 'MLflow|run_id param error cases'
it_behaves_like 'MLflow|Bad Request on missing required', [:key, :value]
end
@@ -358,7 +484,7 @@ RSpec.describe API::Ml::Mlflow::Runs, feature_category: :mlops do
end
it_behaves_like 'MLflow|shared error cases'
- it_behaves_like 'MLflow|Requires api scope'
+ it_behaves_like 'MLflow|Requires api scope and write permission'
it_behaves_like 'MLflow|run_id param error cases'
end
end
diff --git a/spec/requests/api/npm_group_packages_spec.rb b/spec/requests/api/npm_group_packages_spec.rb
index fe0bf1d8b46..7fba75b0630 100644
--- a/spec/requests/api/npm_group_packages_spec.rb
+++ b/spec/requests/api/npm_group_packages_spec.rb
@@ -11,43 +11,12 @@ RSpec.describe API::NpmGroupPackages, feature_category: :package_registry do
let(:url) { api("/groups/#{group.id}/-/packages/npm/#{package_name}") }
it_behaves_like 'handling get metadata requests', scope: :group
-
- context 'with a duplicate package name in another project' do
+ it_behaves_like 'rejects invalid package names' do
subject { get(url) }
-
- before do
- group.add_developer(user)
- end
-
- let_it_be(:project2) { create(:project, :public, namespace: namespace) }
- let_it_be(:package2) do
- create(:npm_package,
- project: project2,
- name: "@#{group.path}/scoped_package",
- version: '1.2.0')
- end
-
- it_behaves_like 'rejects invalid package names'
-
- it 'includes all matching package versions in the response' do
- subject
-
- expect(json_response['versions'].keys).to match_array([package.version, package2.version])
- end
-
- context 'with the feature flag disabled' do
- before do
- stub_feature_flags(npm_allow_packages_in_multiple_projects: false)
- end
-
- it 'returns matching package versions from only one project' do
- subject
-
- expect(json_response['versions'].keys).to match_array([package2.version])
- end
- end
end
+ it_behaves_like 'handling get metadata requests for packages in multiple projects'
+
context 'with mixed group and project visibilities' do
subject { get(url, headers: headers) }
@@ -162,13 +131,13 @@ RSpec.describe API::NpmGroupPackages, feature_category: :package_registry do
end
end
- describe 'GET /api/v4/packages/npm/-/package/*package_name/dist-tags' do
+ describe 'GET /api/v4/groups/:id/-/packages/npm/-/package/*package_name/dist-tags' do
it_behaves_like 'handling get dist tags requests', scope: :group do
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags") }
end
end
- describe 'PUT /api/v4/packages/npm/-/package/*package_name/dist-tags/:tag' do
+ describe 'PUT /api/v4/groups/:id/-/packages/npm/-/package/*package_name/dist-tags/:tag' do
it_behaves_like 'handling create dist tag requests', scope: :group do
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
end
@@ -183,7 +152,7 @@ RSpec.describe API::NpmGroupPackages, feature_category: :package_registry do
end
end
- describe 'DELETE /api/v4/packages/npm/-/package/*package_name/dist-tags/:tag' do
+ describe 'DELETE /api/v4/groups/:id/-/packages/npm/-/package/*package_name/dist-tags/:tag' do
it_behaves_like 'handling delete dist tag requests', scope: :group do
let(:url) { api("/groups/#{group.id}/-/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
end
diff --git a/spec/requests/api/npm_instance_packages_spec.rb b/spec/requests/api/npm_instance_packages_spec.rb
index 4f965d86d66..7b74a052860 100644
--- a/spec/requests/api/npm_instance_packages_spec.rb
+++ b/spec/requests/api/npm_instance_packages_spec.rb
@@ -17,34 +17,7 @@ RSpec.describe API::NpmInstancePackages, feature_category: :package_registry do
it_behaves_like 'handling get metadata requests', scope: :instance
it_behaves_like 'rejects invalid package names'
-
- context 'with a duplicate package name in another project' do
- let_it_be(:project2) { create(:project, :public, namespace: namespace) }
- let_it_be(:package2) do
- create(:npm_package,
- project: project2,
- name: "@#{group.path}/scoped_package",
- version: '1.2.0')
- end
-
- it 'includes all matching package versions in the response' do
- subject
-
- expect(json_response['versions'].keys).to match_array([package.version, package2.version])
- end
-
- context 'with the feature flag disabled' do
- before do
- stub_feature_flags(npm_allow_packages_in_multiple_projects: false)
- end
-
- it 'returns matching package versions from only one project' do
- subject
-
- expect(json_response['versions'].keys).to match_array([package2.version])
- end
- end
- end
+ it_behaves_like 'handling get metadata requests for packages in multiple projects'
context 'when metadata cache exists' do
let_it_be(:npm_metadata_cache) { create(:npm_metadata_cache, package_name: package.name, project_id: project.id) }
diff --git a/spec/requests/api/nuget_project_packages_spec.rb b/spec/requests/api/nuget_project_packages_spec.rb
index da74409cd77..b55d992c1e4 100644
--- a/spec/requests/api/nuget_project_packages_spec.rb
+++ b/spec/requests/api/nuget_project_packages_spec.rb
@@ -34,6 +34,37 @@ RSpec.describe API::NugetProjectPackages, feature_category: :package_registry do
it_behaves_like 'returning response status', :ok
end
+ shared_examples 'nuget serialize odata package endpoint' do
+ subject { get api(url), params: params }
+
+ it { is_expected.to have_request_urgency(:low) }
+
+ it_behaves_like 'returning response status', :success
+
+ it 'returns a valid xml response and invokes OdataPackageEntryService' do
+ expect(Packages::Nuget::OdataPackageEntryService).to receive(:new).with(target, service_params).and_call_original
+
+ subject
+
+ expect(response.media_type).to eq('application/xml')
+ end
+
+ [nil, '', '%20', '..%2F..', '../..'].each do |value|
+ context "with invalid package name #{value}" do
+ let(:package_name) { value }
+
+ it_behaves_like 'returning response status', :bad_request
+ end
+ end
+
+ context 'with missing required params' do
+ let(:params) { {} }
+ let(:package_version) { nil }
+
+ it_behaves_like 'returning response status', :bad_request
+ end
+ end
+
describe 'GET /api/v4/projects/:id/packages/nuget' do
let(:url) { "/projects/#{target.id}/packages/nuget/index.json" }
@@ -228,6 +259,43 @@ RSpec.describe API::NugetProjectPackages, feature_category: :package_registry do
it_behaves_like 'rejects nuget access with invalid target id'
end
+ describe 'GET /api/v4/projects/:id/packages/nuget/v2/FindPackagesById()' do
+ it_behaves_like 'nuget serialize odata package endpoint' do
+ let(:url) { "/projects/#{target.id}/packages/nuget/v2/FindPackagesById()" }
+ let(:params) { { id: "'#{package_name}'" } }
+ let(:service_params) { { package_name: package_name } }
+ end
+ end
+
+ describe 'GET /api/v4/projects/:id/packages/nuget/v2/Packages()' do
+ it_behaves_like 'nuget serialize odata package endpoint' do
+ let(:url) { "/projects/#{target.id}/packages/nuget/v2/Packages()" }
+ let(:params) { { '$filter' => "(tolower(Id) eq '#{package_name&.downcase}')" } }
+ let(:service_params) { { package_name: package_name&.downcase } }
+ end
+ end
+
+ describe 'GET /api/v4/projects/:id/packages/nuget/v2/Packages(Id=\'*\',Version=\'*\')' do
+ let(:package_version) { '1.0.0' }
+ let(:url) { "/projects/#{target.id}/packages/nuget/v2/Packages(Id='#{package_name}',Version='#{package_version}')" }
+ let(:params) { {} }
+ let(:service_params) { { package_name: package_name, package_version: package_version } }
+
+ it_behaves_like 'nuget serialize odata package endpoint'
+
+ context 'with invalid package version' do
+ subject { get api(url) }
+
+ ['', '1', '1./2.3', '%20', '..%2F..', '../..'].each do |value|
+ context "with invalid package version #{value}" do
+ let(:package_version) { value }
+
+ it_behaves_like 'returning response status', :bad_request
+ end
+ end
+ end
+ end
+
describe 'PUT /api/v4/projects/:id/packages/nuget/authorize' do
it_behaves_like 'nuget authorize upload endpoint' do
let(:url) { "/projects/#{target.id}/packages/nuget/authorize" }
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
index aa8568d4951..d95f96c25d6 100644
--- a/spec/requests/api/project_attributes.yml
+++ b/spec/requests/api/project_attributes.yml
@@ -44,6 +44,7 @@ itself: # project
- storage_version
- topic_list
- verification_checksum
+ - organization_id
remapped_attributes:
avatar: avatar_url
build_allow_git_fetch: build_git_strategy
@@ -93,6 +94,7 @@ ci_cd_settings:
- id
- project_id
- merge_trains_enabled
+ - merge_trains_skip_train_allowed
- merge_pipelines_enabled
- auto_rollback_enabled
- inbound_job_token_scope_enabled
@@ -167,6 +169,7 @@ project_setting:
- allow_pipeline_trigger_approve_deployment
- pages_unique_domain_enabled
- pages_unique_domain
+ - pages_multiple_versions_enabled
- runner_registration_enabled
- product_analytics_instrumentation_key
- jitsu_host
diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb
index 4496e3aa7c3..49471b98eba 100644
--- a/spec/requests/api/project_import_spec.rb
+++ b/spec/requests/api/project_import_spec.rb
@@ -470,12 +470,14 @@ RSpec.describe API::ProjectImport, :aggregate_failures, feature_category: :impor
end
describe 'GET /projects/:id/import' do
- it 'public project accessible for an unauthenticated user' do
- project = create(:project, :public)
+ context 'with an unauthenticated user' do
+ it 'returns unauthorized response for public project import status' do
+ project = create(:project, :public)
- get api("/projects/#{project.id}/import", nil)
+ get api("/projects/#{project.id}/import", nil)
- expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
end
it 'returns the import status' do
diff --git a/spec/requests/api/project_packages_spec.rb b/spec/requests/api/project_packages_spec.rb
index 09991be998a..219c748c9a6 100644
--- a/spec/requests/api/project_packages_spec.rb
+++ b/spec/requests/api/project_packages_spec.rb
@@ -553,6 +553,12 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do
let(:per_page) { 2 }
+ it_behaves_like 'an endpoint with keyset pagination' do
+ let(:first_record) { pipeline3 }
+ let(:second_record) { pipeline2 }
+ let(:api_call) { api(package_pipelines_url, user) }
+ end
+
context 'with no cursor supplied' do
subject { get api(package_pipelines_url, user), params: { per_page: per_page } }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 601e8cb3081..e3e8df79a1d 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -713,7 +713,9 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
let!(:project9) { create(:project, :public, path: 'gitlab9') }
before do
- user.update!(starred_projects: [project5, project7, project8, project9])
+ [project5, project7, project8, project9].each do |project|
+ user.users_star_projects.create!(project_id: project.id)
+ end
end
context 'including owned filter' do
@@ -4657,8 +4659,8 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
end
before do
- user.update!(starred_projects: [public_project])
- private_user.update!(starred_projects: [public_project])
+ user.users_star_projects.create!(project_id: public_project.id)
+ private_user.users_star_projects.create!(project_id: public_project.id)
end
it 'returns not_found(404) for not existing project' do
diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb
index 0feff90d088..6a57cf52466 100644
--- a/spec/requests/api/search_spec.rb
+++ b/spec/requests/api/search_spec.rb
@@ -473,6 +473,21 @@ RSpec.describe API::Search, :clean_gitlab_redis_rate_limiting, feature_category:
get api(endpoint, current_user), params: { scope: 'users', search: 'foo@bar.com' }
end
end
+
+ context 'when request exceeds the rate limit', :freeze_time, :clean_gitlab_redis_rate_limiting do
+ before do
+ stub_application_setting(search_rate_limit: 1)
+ end
+
+ it 'allows user whose username is in the allowlist' do
+ stub_application_setting(search_rate_limit_allowlist: [user.username])
+
+ get api(endpoint, user), params: { scope: 'users', search: 'foo@bar.com' }
+ get api(endpoint, user), params: { scope: 'users', search: 'foo@bar.com' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
describe "GET /groups/:id/search" do
@@ -658,6 +673,21 @@ RSpec.describe API::Search, :clean_gitlab_redis_rate_limiting, feature_category:
get api(endpoint, current_user), params: { scope: 'users', search: 'foo@bar.com' }
end
end
+
+ context 'when request exceeds the rate limit', :freeze_time, :clean_gitlab_redis_rate_limiting do
+ before do
+ stub_application_setting(search_rate_limit: 1)
+ end
+
+ it 'allows user whose username is in the allowlist' do
+ stub_application_setting(search_rate_limit_allowlist: [user.username])
+
+ get api(endpoint, user), params: { scope: 'users', search: 'foo@bar.com' }
+ get api(endpoint, user), params: { scope: 'users', search: 'foo@bar.com' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
end
@@ -1057,6 +1087,21 @@ RSpec.describe API::Search, :clean_gitlab_redis_rate_limiting, feature_category:
get api(endpoint, current_user), params: { scope: 'users', search: 'foo@bar.com' }
end
end
+
+ context 'when request exceeds the rate limit', :freeze_time, :clean_gitlab_redis_rate_limiting do
+ before do
+ stub_application_setting(search_rate_limit: 1)
+ end
+
+ it 'allows user whose username is in the allowlist' do
+ stub_application_setting(search_rate_limit_allowlist: [user.username])
+
+ get api(endpoint, user), params: { scope: 'users', search: 'foo@bar.com' }
+ get api(endpoint, user), params: { scope: 'users', search: 'foo@bar.com' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
end
end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 12af1fc1b79..ad52076523c 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -27,6 +27,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
expect(json_response['secret_detection_token_revocation_url']).to be_nil
expect(json_response['secret_detection_revocation_token_types_url']).to be_nil
expect(json_response['sourcegraph_public_only']).to be_truthy
+ expect(json_response['decompress_archive_file_timeout']).to eq(210)
expect(json_response['default_preferred_language']).to be_a String
expect(json_response['default_project_visibility']).to be_a String
expect(json_response['default_snippet_visibility']).to be_a String
@@ -153,6 +154,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
enforce_terms: true,
terms: 'Hello world!',
performance_bar_allowed_group_path: group.full_path,
+ decompress_archive_file_timeout: 60,
diff_max_patch_bytes: 300_000,
diff_max_files: 2000,
diff_max_lines: 50000,
@@ -234,6 +236,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
expect(json_response['enforce_terms']).to be(true)
expect(json_response['terms']).to eq('Hello world!')
expect(json_response['performance_bar_allowed_group_id']).to eq(group.id)
+ expect(json_response['decompress_archive_file_timeout']).to eq(60)
expect(json_response['diff_max_patch_bytes']).to eq(300_000)
expect(json_response['diff_max_files']).to eq(2000)
expect(json_response['diff_max_lines']).to eq(50000)
@@ -851,7 +854,8 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, featu
sentry_enabled: true,
sentry_dsn: 'http://sentry.example.com',
sentry_clientside_dsn: 'http://sentry.example.com',
- sentry_environment: 'production'
+ sentry_environment: 'production',
+ sentry_clientside_traces_sample_rate: 0.25
}
end
diff --git a/spec/requests/api/usage_data_queries_spec.rb b/spec/requests/api/usage_data_queries_spec.rb
index 584b0f31a07..fdd186439a6 100644
--- a/spec/requests/api/usage_data_queries_spec.rb
+++ b/spec/requests/api/usage_data_queries_spec.rb
@@ -6,8 +6,8 @@ require 'rake_helper'
RSpec.describe API::UsageDataQueries, :aggregate_failures, feature_category: :service_ping do
include UsageDataHelpers
- let_it_be(:admin) { create(:user, admin: true) }
- let_it_be(:user) { create(:user) }
+ let!(:admin) { create(:user, admin: true) }
+ let!(:user) { create(:user) }
before do
stub_usage_data_connections
@@ -70,7 +70,7 @@ RSpec.describe API::UsageDataQueries, :aggregate_failures, feature_category: :se
end
end
- context 'when querying sql metrics' do
+ context 'when querying sql metrics', type: :task do
let(:file) { Rails.root.join('tmp', 'test', 'sql_metrics_queries.json') }
before do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 81881532240..5973649a9d7 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe API::Users, :aggregate_failures, feature_category: :user_profile do
include WorkhorseHelpers
+ include KeysetPaginationHelpers
let_it_be(:admin) { create(:admin) }
let_it_be(:user, reload: true) { create(:user, username: 'user.withdot') }
@@ -258,6 +259,48 @@ RSpec.describe API::Users, :aggregate_failures, feature_category: :user_profile
end.not_to exceed_all_query_limit(control_count)
end
end
+
+ context 'when api_keyset_pagination_multi_order FF is enabled' do
+ before do
+ stub_feature_flags(api_keyset_pagination_multi_order: true)
+ end
+
+ it_behaves_like 'an endpoint with keyset pagination', invalid_order: nil do
+ let(:first_record) { user }
+ let(:second_record) { admin }
+ let(:api_call) { api(path, user) }
+ end
+
+ it 'still supports offset pagination when keyset pagination params are not provided' do
+ get api(path, user)
+
+ expect(response).to include_pagination_headers
+ end
+ end
+
+ context 'when api_keyset_pagination_multi_order FF is disabled' do
+ before do
+ stub_feature_flags(api_keyset_pagination_multi_order: false)
+ end
+
+ it 'paginates the records correctly using offset pagination' do
+ get api(path, user), params: { pagination: 'keyset', per_page: 1 }
+
+ params_for_next_page = pagination_params_from_next_url(response)
+ expect(response).to include_pagination_headers
+ expect(params_for_next_page).not_to include('cursor')
+ end
+
+ context 'on making requests with unsupported ordering structure' do
+ it 'does not return error' do
+ get api(path, user),
+ params: { pagination: 'keyset', per_page: 1, order_by: 'created_at', sort: 'asc' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ end
+ end
+ end
end
end
@@ -494,7 +537,7 @@ RSpec.describe API::Users, :aggregate_failures, feature_category: :user_profile
context "when admin" do
context 'exclude_internal param' do
- let_it_be(:internal_user) { User.alert_bot }
+ let_it_be(:internal_user) { Users::Internal.alert_bot }
it 'returns all users when it is not set' do
get api("/users?exclude_internal=false", admin)
@@ -3602,7 +3645,7 @@ RSpec.describe API::Users, :aggregate_failures, feature_category: :user_profile
end
context 'for an internal user' do
- let(:user) { User.alert_bot }
+ let(:user) { Users::Internal.alert_bot }
it 'returns 403' do
deactivate
diff --git a/spec/requests/clusters/agents/dashboard_controller_spec.rb b/spec/requests/clusters/agents/dashboard_controller_spec.rb
new file mode 100644
index 00000000000..c3c16d9b385
--- /dev/null
+++ b/spec/requests/clusters/agents/dashboard_controller_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Clusters::Agents::DashboardController, feature_category: :deployment_management do
+ describe 'GET show' do
+ let_it_be(:organization) { create(:group) }
+ let_it_be(:agent_management_project) { create(:project, group: organization) }
+ let_it_be(:agent) { create(:cluster_agent, project: agent_management_project) }
+ let_it_be(:deployment_project) { create(:project, group: organization) }
+ let(:user) { create(:user) }
+ let(:stub_ff) { true }
+
+ before do
+ allow(::Gitlab::Kas).to receive(:enabled?).and_return(true)
+ end
+
+ context 'with authorized user' do
+ let!(:authorization) do
+ create(
+ :agent_user_access_project_authorization,
+ agent: agent,
+ project: deployment_project
+ )
+ end
+
+ before do
+ stub_feature_flags(k8s_dashboard: stub_ff)
+ deployment_project.add_member(user, :developer)
+ sign_in(user)
+ get kubernetes_dashboard_path(agent.id)
+ end
+
+ it 'sets the kas cookie' do
+ expect(
+ request.env['action_dispatch.cookies'][Gitlab::Kas::COOKIE_KEY]
+ ).to be_present
+ end
+
+ it 'returns not found' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ context 'with k8s_dashboard feature flag disabled' do
+ let(:stub_ff) { false }
+
+ it 'does not set the kas cookie' do
+ expect(
+ request.env['action_dispatch.cookies'][Gitlab::Kas::COOKIE_KEY]
+ ).not_to be_present
+ end
+
+ it 'returns not found' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'with unauthorized user' do
+ before do
+ sign_in(user)
+ get kubernetes_dashboard_path(agent.id)
+ end
+
+ it 'does not set the kas cookie' do
+ expect(
+ request.env['action_dispatch.cookies'][Gitlab::Kas::COOKIE_KEY]
+ ).not_to be_present
+ end
+
+ it 'returns not found' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb
index 3f0665f1ce5..3ce7e33d88a 100644
--- a/spec/requests/content_security_policy_spec.rb
+++ b/spec/requests/content_security_policy_spec.rb
@@ -7,6 +7,7 @@ require 'spec_helper'
# of testing in application_controller_spec.
RSpec.describe 'Content Security Policy', feature_category: :application_instrumentation do
let(:snowplow_host) { 'snowplow.example.com' }
+ let(:vite_origin) { "#{ViteRuby.instance.config.host}:#{ViteRuby.instance.config.port}" }
shared_examples 'snowplow is not in the CSP' do
it 'does not add the snowplow collector hostname to the CSP' do
@@ -46,5 +47,33 @@ RSpec.describe 'Content Security Policy', feature_category: :application_instrum
it_behaves_like 'snowplow is not in the CSP'
end
+
+ context 'when vite enabled during development',
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424334' do
+ before do
+ stub_rails_env('development')
+ stub_feature_flags(vite: true)
+
+ get explore_root_url
+ end
+
+ it 'adds vite csp' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers['Content-Security-Policy']).to include(vite_origin)
+ end
+ end
+
+ context 'when vite disabled' do
+ before do
+ stub_feature_flags(vite: false)
+
+ get explore_root_url
+ end
+
+ it "doesn't add vite csp" do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers['Content-Security-Policy']).not_to include(vite_origin)
+ end
+ end
end
end
diff --git a/spec/requests/groups/email_campaigns_controller_spec.rb b/spec/requests/groups/email_campaigns_controller_spec.rb
deleted file mode 100644
index b6e765eba37..00000000000
--- a/spec/requests/groups/email_campaigns_controller_spec.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Groups::EmailCampaignsController, feature_category: :navigation do
- using RSpec::Parameterized::TableSyntax
-
- describe 'GET #index', :snowplow do
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, group: group) }
- let_it_be(:user) { create(:user) }
-
- let(:track) { 'create' }
- let(:series) { '0' }
- let(:schema) { described_class::EMAIL_CAMPAIGNS_SCHEMA_URL }
- let(:subject_line_text) { Gitlab::Email::Message::InProductMarketing.for(track.to_sym).new(group: group, user: user, series: series.to_i).subject_line }
- let(:data) do
- {
- namespace_id: group.id,
- track: track.to_sym,
- series: series.to_i,
- subject_line: subject_line_text
- }
- end
-
- before do
- sign_in(user)
- group.add_developer(user)
- end
-
- subject do
- get group_email_campaigns_url(group, track: track, series: series)
- response
- end
-
- shared_examples 'track and redirect' do
- it 'redirects' do
- expect(subject).to have_gitlab_http_status(:redirect)
- end
-
- context 'on SaaS', :saas do
- it 'emits a snowplow event', :snowplow do
- subject
-
- expect_snowplow_event(
- category: described_class.name,
- action: 'click',
- context: [{
- schema: described_class::EMAIL_CAMPAIGNS_SCHEMA_URL,
- data: { namespace_id: group.id, series: series.to_i, subject_line: subject_line_text, track: track.to_s }
- }],
- user: user,
- namespace: group
- )
- end
-
- it 'does not save the cta_click' do
- expect(Users::InProductMarketingEmail).not_to receive(:save_cta_click)
-
- subject
- end
- end
-
- context 'when not on.com' do
- it 'saves the cta_click' do
- expect(Users::InProductMarketingEmail).to receive(:save_cta_click)
-
- subject
- end
-
- it 'does not track snowplow events' do
- subject
-
- expect_no_snowplow_event
- end
- end
- end
-
- shared_examples 'no track and 404' do
- it 'returns 404' do
- expect(subject).to have_gitlab_http_status(:not_found)
- end
-
- it 'does not emit a snowplow event', :snowplow do
- subject
-
- expect_no_snowplow_event
- end
- end
-
- describe 'track parameter' do
- context 'when valid' do
- where(track: Namespaces::InProductMarketingEmailsService::TRACKS.keys.without(:experience))
-
- with_them do
- it_behaves_like 'track and redirect'
- end
- end
-
- context 'when invalid' do
- where(track: [nil, 'xxxx'])
-
- with_them do
- it_behaves_like 'no track and 404'
- end
- end
- end
-
- describe 'series parameter' do
- context 'when valid' do
- where(series: (0..Namespaces::InProductMarketingEmailsService::TRACKS[:create][:interval_days].length - 1).to_a)
-
- with_them do
- it_behaves_like 'track and redirect'
- end
- end
-
- context 'when invalid' do
- where(series: [-1, nil, Namespaces::InProductMarketingEmailsService::TRACKS[:create][:interval_days].length])
-
- with_them do
- it_behaves_like 'no track and 404'
- end
- end
- end
- end
-end
diff --git a/spec/requests/groups/settings/access_tokens_controller_spec.rb b/spec/requests/groups/settings/access_tokens_controller_spec.rb
index 0204af8ea8e..8d386d8c1b7 100644
--- a/spec/requests/groups/settings/access_tokens_controller_spec.rb
+++ b/spec/requests/groups/settings/access_tokens_controller_spec.rb
@@ -112,5 +112,27 @@ RSpec.describe Groups::Settings::AccessTokensController, feature_category: :syst
expect(assigns(:active_access_tokens).to_json).to eq(active_access_tokens.to_json)
end
+
+ it 'sets available scopes' do
+ expect(assigns(:scopes)).to include(Gitlab::Auth::K8S_PROXY_SCOPE)
+ end
+
+ context 'with feature flag k8s_proxy_pat disabled' do
+ before do
+ stub_feature_flags(k8s_proxy_pat: false)
+ get group_settings_access_tokens_path(resource)
+ end
+
+ it 'includes details of the active group access tokens' do
+ active_access_tokens =
+ ::GroupAccessTokenSerializer.new.represent(resource_access_tokens.reverse, group: resource)
+
+ expect(assigns(:active_access_tokens).to_json).to eq(active_access_tokens.to_json)
+ end
+
+ it 'sets available scopes' do
+ expect(assigns(:scopes)).not_to include(Gitlab::Auth::K8S_PROXY_SCOPE)
+ end
+ end
end
end
diff --git a/spec/requests/groups/work_items_controller_spec.rb b/spec/requests/groups/work_items_controller_spec.rb
index c47b3f03ec1..e5dd88a5471 100644
--- a/spec/requests/groups/work_items_controller_spec.rb
+++ b/spec/requests/groups/work_items_controller_spec.rb
@@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe 'Group Level Work Items', feature_category: :team_planning do
let_it_be(:group) { create(:group, :private) }
- let_it_be(:project) { create(:project, group: group) }
let_it_be(:developer) { create(:user).tap { |u| group.add_developer(u) } }
describe 'GET /groups/:group/-/work_items' do
@@ -46,4 +45,47 @@ RSpec.describe 'Group Level Work Items', feature_category: :team_planning do
end
end
end
+
+ describe 'GET /groups/:group/-/work_items/:iid' do
+ let_it_be(:work_item) { create(:work_item, :group_level, namespace: group) }
+ let(:work_items_path) do
+ url_for(controller: 'groups/work_items', action: :show, group_id: group.full_path, iid: work_item.iid)
+ end
+
+ before do
+ sign_in(current_user)
+ end
+
+ context 'when the user can read the group' do
+ let(:current_user) { developer }
+
+ it 'renders index' do
+ get work_items_path
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ context 'when the namespace_level_work_items feature flag is disabled' do
+ before do
+ stub_feature_flags(namespace_level_work_items: false)
+ end
+
+ it 'returns not found' do
+ get work_items_path
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'when the user cannot read the group' do
+ let(:current_user) { create(:user) }
+
+ it 'returns not found' do
+ get work_items_path
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
end
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index 217241200ff..6573fe570db 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -273,7 +273,7 @@ RSpec.describe 'OpenID Connect requests', feature_category: :system_access do
let(:expected_scopes) do
%w[
admin_mode api read_user read_api read_repository write_repository sudo openid profile email
- read_observability write_observability create_runner
+ read_observability write_observability create_runner k8s_proxy ai_features
]
end
diff --git a/spec/requests/organizations/organizations_controller_spec.rb b/spec/requests/organizations/organizations_controller_spec.rb
index 788d740504a..953adb2cbf6 100644
--- a/spec/requests/organizations/organizations_controller_spec.rb
+++ b/spec/requests/organizations/organizations_controller_spec.rb
@@ -13,25 +13,30 @@ RSpec.describe Organizations::OrganizationsController, feature_category: :cell d
end
end
- shared_examples 'action disabled by `ui_for_organizations` feature flag' do
- before do
- stub_feature_flags(ui_for_organizations: false)
- end
-
- it 'renders 404' do
+ shared_examples 'redirects to sign in page' do
+ it 'redirects to sign in page' do
gitlab_request
- expect(response).to have_gitlab_http_status(:not_found)
+ expect(response).to redirect_to(new_user_session_path)
end
end
- shared_examples 'basic organization controller action' do
- context 'when the user is not logged in' do
- it_behaves_like 'successful response'
- it_behaves_like 'action disabled by `ui_for_organizations` feature flag'
+ shared_examples 'action disabled by `ui_for_organizations` feature flag' do
+ context 'when `ui_for_organizations` feature flag is disabled' do
+ before do
+ stub_feature_flags(ui_for_organizations: false)
+ end
+
+ it 'renders 404' do
+ gitlab_request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
+ end
- context 'when the user is logged in' do
+ shared_examples 'when the user is signed in' do
+ context 'when the user is signed in' do
before do
sign_in(user)
end
@@ -63,15 +68,52 @@ RSpec.describe Organizations::OrganizationsController, feature_category: :cell d
end
end
+ shared_examples 'controller action that requires authentication' do
+ context 'when the user is not signed in' do
+ it_behaves_like 'redirects to sign in page'
+
+ context 'when `ui_for_organizations` feature flag is disabled' do
+ before do
+ stub_feature_flags(ui_for_organizations: false)
+ end
+
+ it_behaves_like 'redirects to sign in page'
+ end
+ end
+
+ it_behaves_like 'when the user is signed in'
+ end
+
+ shared_examples 'controller action that does not require authentication' do
+ context 'when the user is not logged in' do
+ it_behaves_like 'successful response'
+ it_behaves_like 'action disabled by `ui_for_organizations` feature flag'
+ end
+
+ it_behaves_like 'when the user is signed in'
+ end
+
describe 'GET #show' do
subject(:gitlab_request) { get organization_path(organization) }
- it_behaves_like 'basic organization controller action'
+ it_behaves_like 'controller action that does not require authentication'
end
describe 'GET #groups_and_projects' do
subject(:gitlab_request) { get groups_and_projects_organization_path(organization) }
- it_behaves_like 'basic organization controller action'
+ it_behaves_like 'controller action that does not require authentication'
+ end
+
+ describe 'GET #new' do
+ subject(:gitlab_request) { get new_organization_path }
+
+ it_behaves_like 'controller action that requires authentication'
+ end
+
+ describe 'GET #index' do
+ subject(:gitlab_request) { get organizations_path }
+
+ it_behaves_like 'controller action that requires authentication'
end
end
diff --git a/spec/requests/projects/noteable_notes_spec.rb b/spec/requests/projects/noteable_notes_spec.rb
deleted file mode 100644
index a490e059680..00000000000
--- a/spec/requests/projects/noteable_notes_spec.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Project noteable notes', feature_category: :team_planning do
- describe '#index' do
- let_it_be(:merge_request) { create(:merge_request) }
-
- let(:etag_store) { Gitlab::EtagCaching::Store.new }
- let(:notes_path) { project_noteable_notes_path(project, target_type: merge_request.class.name.underscore, target_id: merge_request.id) }
- let(:project) { merge_request.project }
- let(:user) { project.first_owner }
-
- let(:response_etag) { response.headers['ETag'] }
- let(:stored_etag) { "W/\"#{etag_store.get(notes_path)}\"" }
-
- let(:default_headers) { { 'X-Last-Fetched-At' => 0 } }
-
- before do
- login_as(user)
- end
-
- it 'does not set a Gitlab::EtagCaching ETag if there is a note' do
- create(:note_on_merge_request, noteable: merge_request, project: merge_request.project)
-
- get notes_path, headers: default_headers
-
- expect(response).to have_gitlab_http_status(:ok)
-
- # Rack::ETag will set an etag based on the body digest, but that doesn't
- # interfere with notes pagination
- expect(response_etag).not_to eq(stored_etag)
- end
-
- it 'sets a Gitlab::EtagCaching ETag if there is no note' do
- get notes_path, headers: default_headers
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response_etag).to eq(stored_etag)
- end
-
- it "instruments cache hits correctly" do
- etag_store.touch(notes_path)
-
- expect(Gitlab::Metrics::RailsSlis.request_apdex).to(
- receive(:increment).with(
- labels: {
- request_urgency: :medium,
- feature_category: "team_planning",
- endpoint_id: "Projects::NotesController#index"
- },
- success: be_in([true, false])
- )
- )
- allow(ActiveSupport::Notifications).to receive(:instrument).and_call_original
-
- expect(ActiveSupport::Notifications).to(
- receive(:instrument).with(
- 'process_action.action_controller',
- a_hash_including(
- {
- request_urgency: :medium,
- target_duration_s: 0.5,
- metadata: a_hash_including({
- 'meta.feature_category' => 'team_planning',
- 'meta.caller_id' => "Projects::NotesController#index"
- })
- }
- )
- )
- )
-
- get notes_path, headers: default_headers.merge("if-none-match": stored_etag)
-
- expect(response).to have_gitlab_http_status(:not_modified)
- end
- end
-end
diff --git a/spec/requests/projects/settings/access_tokens_controller_spec.rb b/spec/requests/projects/settings/access_tokens_controller_spec.rb
index 666dc42bcab..b4cfa964ac8 100644
--- a/spec/requests/projects/settings/access_tokens_controller_spec.rb
+++ b/spec/requests/projects/settings/access_tokens_controller_spec.rb
@@ -113,5 +113,27 @@ RSpec.describe Projects::Settings::AccessTokensController, feature_category: :sy
expect(assigns(:active_access_tokens).to_json).to eq(active_access_tokens.to_json)
end
+
+ it 'sets available scopes' do
+ expect(assigns(:scopes)).to include(Gitlab::Auth::K8S_PROXY_SCOPE)
+ end
+
+ context 'with feature flag k8s_proxy_pat disabled' do
+ before do
+ stub_feature_flags(k8s_proxy_pat: false)
+ get project_settings_access_tokens_path(resource)
+ end
+
+ it 'includes details of the active project access tokens' do
+ active_access_tokens =
+ ::ProjectAccessTokenSerializer.new.represent(resource_access_tokens.reverse, project: resource)
+
+ expect(assigns(:active_access_tokens).to_json).to eq(active_access_tokens.to_json)
+ end
+
+ it 'sets available scopes' do
+ expect(assigns(:scopes)).not_to include(Gitlab::Auth::K8S_PROXY_SCOPE)
+ end
+ end
end
end
diff --git a/spec/requests/projects/tracing_controller_spec.rb b/spec/requests/projects/tracing_controller_spec.rb
deleted file mode 100644
index 8996ea7f8d6..00000000000
--- a/spec/requests/projects/tracing_controller_spec.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::TracingController, feature_category: :tracing do
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, group: group) }
- let_it_be(:user) { create(:user) }
- let(:path) { nil }
- let(:observability_tracing_ff) { true }
-
- subject do
- get path
- response
- end
-
- before do
- stub_feature_flags(observability_tracing: observability_tracing_ff)
- sign_in(user)
- end
-
- shared_examples 'tracing route request' do
- it_behaves_like 'observability csp policy' do
- before_all do
- project.add_developer(user)
- end
-
- let(:tested_path) { path }
- end
-
- context 'when user does not have permissions' do
- it 'returns 404' do
- expect(subject).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when user has permissions' do
- before_all do
- project.add_developer(user)
- end
-
- it 'returns 200' do
- expect(subject).to have_gitlab_http_status(:ok)
- end
-
- context 'when feature is disabled' do
- let(:observability_tracing_ff) { false }
-
- it 'returns 404' do
- expect(subject).to have_gitlab_http_status(:not_found)
- end
- end
- end
- end
-
- describe 'GET #index' do
- let(:path) { project_tracing_index_path(project) }
-
- it_behaves_like 'tracing route request'
-
- describe 'html response' do
- before_all do
- project.add_developer(user)
- end
-
- it 'renders the js-tracing element correctly' do
- element = Nokogiri::HTML.parse(subject.body).at_css('#js-tracing')
-
- expected_view_model = {
- tracingUrl: Gitlab::Observability.tracing_url(project),
- provisioningUrl: Gitlab::Observability.provisioning_url(project),
- oauthUrl: Gitlab::Observability.oauth_url
- }.to_json
- expect(element.attributes['data-view-model'].value).to eq(expected_view_model)
- end
- end
- end
-
- describe 'GET #show' do
- let(:path) { project_tracing_path(project, id: "test-trace-id") }
-
- it_behaves_like 'tracing route request'
-
- describe 'html response' do
- before_all do
- project.add_developer(user)
- end
-
- it 'renders the js-tracing element correctly' do
- element = Nokogiri::HTML.parse(subject.body).at_css('#js-tracing-details')
-
- expected_view_model = {
- tracingIndexUrl: project_tracing_index_path(project),
- traceId: 'test-trace-id',
- tracingUrl: Gitlab::Observability.tracing_url(project),
- provisioningUrl: Gitlab::Observability.provisioning_url(project),
- oauthUrl: Gitlab::Observability.oauth_url
- }.to_json
-
- expect(element.attributes['data-view-model'].value).to eq(expected_view_model)
- end
- end
- end
-end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index 0dd8a15c3a4..3f5cd24f3dd 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -320,6 +320,120 @@ feature_category: :system_access do
end
end
+ describe 'protected paths for get' do
+ let(:request_method) { 'GET' }
+
+ context 'unauthenticated requests' do
+ let(:protected_path_for_get_request_that_does_not_require_authentication) do
+ '/users/sign_in'
+ end
+
+ def do_request
+ get protected_path_for_get_request_that_does_not_require_authentication
+ end
+
+ before do
+ settings_to_set[:throttle_protected_paths_requests_per_period] = requests_per_period # 1
+ settings_to_set[:throttle_protected_paths_period_in_seconds] = period_in_seconds # 10_000
+ settings_to_set[:protected_paths_for_get_request] = %w[/users/sign_in]
+ end
+
+ context 'when protected paths throttle is disabled' do
+ before do
+ settings_to_set[:throttle_protected_paths_enabled] = false
+ stub_application_setting(settings_to_set)
+ end
+
+ it 'allows requests over the rate limit' do
+ (1 + requests_per_period).times do
+ do_request
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+
+ context 'when protected paths throttle is enabled' do
+ before do
+ settings_to_set[:throttle_protected_paths_enabled] = true
+ stub_application_setting(settings_to_set)
+ end
+
+ it 'rejects requests over the rate limit' do
+ requests_per_period.times do
+ do_request
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ expect_rejection { get protected_path_for_get_request_that_does_not_require_authentication }
+ end
+
+ it 'allows GET requests to unprotected paths over the rate limit' do
+ (1 + requests_per_period).times do
+ get '/api/graphql'
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ it_behaves_like 'tracking when dry-run mode is set' do
+ let(:throttle_name) { 'throttle_unauthenticated_get_protected_paths' }
+ end
+ end
+ end
+
+ context 'API requests authenticated with personal access token', :api do
+ let(:user) { create(:user) }
+ let(:token) { create(:personal_access_token, user: user) }
+ let(:other_user) { create(:user) }
+ let(:other_user_token) { create(:personal_access_token, user: other_user) }
+ let(:throttle_setting_prefix) { 'throttle_protected_paths' }
+ let(:api_partial_url) { '/user/emails' }
+
+ let(:protected_paths_for_get_request) do
+ [
+ '/api/v4/user/emails'
+ ]
+ end
+
+ before do
+ settings_to_set[:protected_paths_for_get_request] = protected_paths_for_get_request
+ stub_application_setting(settings_to_set)
+ end
+
+ context 'with the token in the query string' do
+ let(:request_args) { [api(api_partial_url, personal_access_token: token), {}] }
+ let(:other_user_request_args) { [api(api_partial_url, personal_access_token: other_user_token), {}] }
+
+ it_behaves_like 'rate-limited user based token-authenticated requests'
+ end
+
+ context 'with the token in the headers' do
+ let(:request_args) { api_get_args_with_token_headers(api_partial_url, personal_access_token_headers(token)) }
+ let(:other_user_request_args) { api_get_args_with_token_headers(api_partial_url, personal_access_token_headers(other_user_token)) }
+
+ it_behaves_like 'rate-limited user based token-authenticated requests'
+ end
+ end
+
+ describe 'web requests authenticated with regular login' do
+ let(:throttle_setting_prefix) { 'throttle_protected_paths' }
+ let(:user) { create(:user) }
+ let(:url_that_requires_authentication) { '/users/confirmation' }
+
+ let(:protected_paths_for_get_request) do
+ [
+ url_that_requires_authentication
+ ]
+ end
+
+ before do
+ settings_to_set[:protected_paths_for_get_request] = protected_paths_for_get_request
+ stub_application_setting(settings_to_set)
+ end
+
+ it_behaves_like 'rate-limited web authenticated requests'
+ end
+ end
+
describe 'Packages API' do
let(:request_method) { 'GET' }
diff --git a/spec/requests/search_controller_spec.rb b/spec/requests/search_controller_spec.rb
index 365b20ad4aa..37474aee1ee 100644
--- a/spec/requests/search_controller_spec.rb
+++ b/spec/requests/search_controller_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe SearchController, type: :request, feature_category: :global_searc
let_it_be(:projects) { create_list(:project, 5, :public, :repository, :wiki_repo) }
before do
+ stub_feature_flags(super_sidebar_nav_enrolled: false)
login_as(user)
end
diff --git a/spec/requests/sessions_spec.rb b/spec/requests/sessions_spec.rb
index 8e069427678..3428e607305 100644
--- a/spec/requests/sessions_spec.rb
+++ b/spec/requests/sessions_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe 'Sessions', feature_category: :system_access do
include SessionHelpers
- context 'authentication', :allow_forgery_protection do
- let(:user) { create(:user) }
+ let(:user) { create(:user) }
+ context 'for authentication', :allow_forgery_protection do
it 'logout does not require a csrf token' do
login_as(user)
@@ -17,29 +17,36 @@ RSpec.describe 'Sessions', feature_category: :system_access do
end
end
- describe 'about_gitlab_active_user' do
- before do
- allow(::Gitlab).to receive(:com?).and_return(true)
- end
-
- let(:user) { create(:user) }
+ describe 'gitlab_user cookie', :saas do
+ let_it_be(:user) { create(:user) }
context 'when user signs in' do
it 'sets marketing cookie' do
post user_session_path(user: { login: user.username, password: user.password })
- expect(response.cookies['about_gitlab_active_user']).to be_present
+ expect(response.cookies['gitlab_user']).to be_present
end
end
context 'when user uses remember_me' do
it 'sets marketing cookie' do
post user_session_path(user: { login: user.username, password: user.password, remember_me: true })
- expect(response.cookies['about_gitlab_active_user']).to be_present
+ expect(response.cookies['gitlab_user']).to be_present
+ end
+ end
+
+ context 'when user has pending invitations' do
+ it 'accepts the invitations and stores a user location' do
+ create(:group_member, :invited, invite_email: user.email)
+ member = create(:group_member, :invited, invite_email: user.email)
+
+ post user_session_path(user: { login: user.username, password: user.password })
+
+ expect(response).to redirect_to(activity_group_path(member.source))
end
end
context 'when using two-factor authentication via OTP' do
- let(:user) { create(:user, :two_factor, :invalid) }
+ let_it_be(:user) { create(:user, :two_factor, :invalid) }
let(:user_params) { { login: user.username, password: user.password } }
def authenticate_2fa(otp_attempt:)
@@ -67,17 +74,6 @@ RSpec.describe 'Sessions', feature_category: :system_access do
end
end
- context 'when user signs out' do
- before do
- post user_session_path(user: { login: user.username, password: user.password })
- end
-
- it 'deletes marketing cookie' do
- post(destroy_user_session_path)
- expect(response.cookies['about_gitlab_active_user']).to be_nil
- end
- end
-
context 'when user is not using GitLab SaaS' do
before do
allow(::Gitlab).to receive(:com?).and_return(false)
@@ -85,7 +81,7 @@ RSpec.describe 'Sessions', feature_category: :system_access do
it 'does not set marketing cookie' do
post user_session_path(user: { login: user.username, password: user.password })
- expect(response.cookies['about_gitlab_active_user']).to be_nil
+ expect(response.cookies['gitlab_user']).to be_nil
end
end
end
diff --git a/spec/requests/users/namespace_visits_controller_spec.rb b/spec/requests/users/namespace_visits_controller_spec.rb
new file mode 100644
index 00000000000..eeeffcce67d
--- /dev/null
+++ b/spec/requests/users/namespace_visits_controller_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::NamespaceVisitsController, type: :request, feature_category: :navigation do
+ describe "POST /" do
+ let_it_be(:path) { track_namespace_visits_path }
+ let_it_be(:request_params) { nil }
+
+ subject(:request) { post path, params: request_params }
+
+ context "when user is not signed-in" do
+ it 'throws an error 302' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:redirect)
+ end
+ end
+
+ context "when user is signed-in" do
+ let_it_be(:user) { create(:user) }
+ let(:server_side_frecent_namespaces) { true }
+
+ before do
+ stub_feature_flags(server_side_frecent_namespaces: server_side_frecent_namespaces)
+ sign_in(user)
+ end
+
+ context "when the server_side_frecent_namespaces feature flag is disabled" do
+ let(:server_side_frecent_namespaces) { false }
+
+ it 'throws an error 302' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context "when entity type is not provided" do
+ let_it_be(:request_params) { { id: '1' } }
+
+ it 'responds with a code 400' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context "when entity ID is not provided" do
+ let_it_be(:request_params) { { type: 'projects' } }
+
+ it 'responds with a code 400' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context "when entity type and ID are provided" do
+ let_it_be(:request_params) { { type: 'projects', id: 1 } }
+
+ it 'calls the worker and responds with a code 200' do
+ expect(Users::TrackNamespaceVisitsWorker).to receive(:perform_async)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/verifies_with_email_spec.rb b/spec/requests/verifies_with_email_spec.rb
index cc85ebc7ade..c8a0c0975a3 100644
--- a/spec/requests/verifies_with_email_spec.rb
+++ b/spec/requests/verifies_with_email_spec.rb
@@ -171,8 +171,8 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
it 'adds a verification error message' do
expect(json_response)
- .to include('message' => (s_('IdentityVerification|The code is incorrect. '\
- 'Enter it again, or send a new code.')))
+ .to include('message' => s_('IdentityVerification|The code is incorrect. '\
+ 'Enter it again, or send a new code.'))
end
end
@@ -184,7 +184,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
it 'adds a verification error message' do
expect(json_response)
- .to include('message' => (s_('IdentityVerification|The code has expired. Send a new code and try again.')))
+ .to include('message' => s_('IdentityVerification|The code has expired. Send a new code and try again.'))
end
end
diff --git a/spec/routing/organizations/organizations_controller_routing_spec.rb b/spec/routing/organizations/organizations_controller_routing_spec.rb
index 2b43f6d3afa..187553df2a1 100644
--- a/spec/routing/organizations/organizations_controller_routing_spec.rb
+++ b/spec/routing/organizations/organizations_controller_routing_spec.rb
@@ -10,6 +10,16 @@ RSpec.describe Organizations::OrganizationsController, :routing, feature_categor
.to route_to('organizations/organizations#show', organization_path: organization.path)
end
+ it 'routes to #new' do
+ expect(get("/-/organizations/new"))
+ .to route_to('organizations/organizations#new')
+ end
+
+ it 'routes to #index' do
+ expect(get("/-/organizations"))
+ .to route_to('organizations/organizations#index')
+ end
+
it 'routes to #groups_and_projects' do
expect(get("/-/organizations/#{organization.path}/groups_and_projects"))
.to route_to('organizations/organizations#groups_and_projects', organization_path: organization.path)
diff --git a/spec/rubocop/cop/capybara/testid_finders_spec.rb b/spec/rubocop/cop/capybara/testid_finders_spec.rb
new file mode 100644
index 00000000000..daedf5b8481
--- /dev/null
+++ b/spec/rubocop/cop/capybara/testid_finders_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+require 'rspec-parameterized'
+require_relative '../../../../rubocop/cop/capybara/testid_finders'
+
+RSpec.describe RuboCop::Cop::Capybara::TestidFinders, feature_category: :shared do
+ let(:source_file) { 'spec/features/foo_spec.rb' }
+
+ describe 'good examples' do
+ where(:code) do
+ [
+ "find_by_testid('some-testid')",
+ "find_by_testid('\#{testid}')",
+ "find('[data-testid=\"some-testid\"] > input')",
+ "find('[data-tracking=\"render\"]')",
+ "within_testid('some-testid')",
+ "within_testid('\#{testid}')",
+ "within('[data-testid=\"some-testid\"] > input')",
+ "within('[data-tracking=\"render\"]')"
+ ]
+ end
+
+ with_them do
+ it 'does not register an offense' do
+ expect_no_offenses(code)
+ end
+ end
+ end
+
+ describe 'bad examples' do
+ where(:code) do
+ [
+ "find('[data-testid=\"some-testid\"]')",
+ "find(\"[data-testid='some-testid']\")",
+ "within('[data-testid=\"some-testid\"]')",
+ "within(\"[data-testid='some-testid']\")"
+ ]
+ end
+
+ with_them do
+ it 'does not register an offense' do
+ expect_offense(<<~CODE, node: code)
+ %{node}
+ ^{node} Prefer to use custom helper method[...]
+ CODE
+ end
+ end
+ end
+end
diff --git a/spec/rubocop/cop/lint/last_keyword_argument_spec.rb b/spec/rubocop/cop/lint/last_keyword_argument_spec.rb
deleted file mode 100644
index edd54a40b79..00000000000
--- a/spec/rubocop/cop/lint/last_keyword_argument_spec.rb
+++ /dev/null
@@ -1,168 +0,0 @@
-# frozen_string_literal: true
-
-require 'rubocop_spec_helper'
-require_relative '../../../../rubocop/cop/lint/last_keyword_argument'
-
-RSpec.describe RuboCop::Cop::Lint::LastKeywordArgument, :ruby27, feature_category: :shared do
- before do
- described_class.instance_variable_set(:@keyword_warnings, nil)
- allow(Dir).to receive(:glob).and_call_original
- allow(File).to receive(:read).and_call_original
- end
-
- context 'deprecation files does not exist' do
- before do
- allow(Dir).to receive(:glob).with(described_class::DEPRECATIONS_GLOB).and_return([])
- end
-
- it 'does not register an offense' do
- expect_no_offenses(<<~SOURCE)
- users.call(params)
- SOURCE
- end
- end
-
- context 'deprecation files does exist' do
- let(:create_spec_yaml) do
- <<~YAML
- ---
- test_mutations/boards/lists/create#resolve_with_proper_permissions_backlog_list_creates_one_and_only_one_backlog:
- - |
- DEPRECATION WARNING: /Users/tkuah/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/batch-loader-1.4.0/lib/batch_loader/graphql.rb:38: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
- /Users/tkuah/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/batch-loader-1.4.0/lib/batch_loader.rb:26: warning: The called method `batch' is defined here
- test_mutations/boards/lists/create#ready?_raises_an_error_if_required_arguments_are_missing:
- - |
- DEPRECATION WARNING: /Users/tkuah/code/ee-gdk/gitlab/create_service.rb:1: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
- /Users/tkuah/code/ee-gdk/gitlab/user.rb:17: warning: The called method `call' is defined here
- - |
- DEPRECATION WARNING: /Users/tkuah/code/ee-gdk/gitlab/other_warning_type.rb:1: warning: Some other warning type
- YAML
- end
-
- let(:projects_spec_yaml) do
- <<~YAML
- ---
- test_api/projects_get_/projects_when_unauthenticated_behaves_like_projects_response_returns_an_array_of_projects:
- - |
- DEPRECATION WARNING: /Users/tkuah/code/ee-gdk/gitlab/projects_spec.rb:1: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
- /Users/tkuah/code/ee-gdk/gitlab/lib/gitlab/project.rb:15: warning: The called method `initialize' is defined here
- - |
- DEPRECATION WARNING: /Users/tkuah/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/state_machines-activerecord-0.6.0/lib/state_machines/integrations/active_record.rb:511: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
- /Users/tkuah/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/suppressor.rb:43: warning: The called method `save' is defined here
- - |
- DEPRECATION WARNING: /Users/tkuah/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/builder.rb:158: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
- /Users/tkuah/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/grape-1.4.0/lib/grape/middleware/error.rb:30: warning: The called method `initialize' is defined here
- YAML
- end
-
- before do
- allow(Dir).to receive(:glob).and_return(['deprecations/service/create_spec.yml', 'deprecations/api/projects_spec.yml'])
- allow(File).to receive(:read).with('deprecations/service/create_spec.yml').and_return(create_spec_yaml)
- allow(File).to receive(:read).with('deprecations/api/projects_spec.yml').and_return(projects_spec_yaml)
- end
-
- it 'registers an offense for last keyword warning' do
- expect_offense(<<~SOURCE, 'create_service.rb')
- users.call(params)
- ^^^^^^ Using the last argument as keyword parameters is deprecated
- SOURCE
-
- expect_correction(<<~SOURCE)
- users.call(**params)
- SOURCE
- end
-
- it 'does not register an offense for other warning types' do
- expect_no_offenses(<<~SOURCE, 'other_warning_type.rb')
- users.call(params)
- SOURCE
- end
-
- it 'registers an offense for the new method call' do
- expect_offense(<<~SOURCE, 'projects_spec.rb')
- Project.new(params)
- ^^^^^^ Using the last argument as keyword parameters is deprecated
- SOURCE
-
- expect_correction(<<~SOURCE)
- Project.new(**params)
- SOURCE
- end
-
- it 'registers an offense and corrects by converting hash to kwarg' do
- expect_offense(<<~SOURCE, 'create_service.rb')
- users.call(id, { a: :b, c: :d })
- ^^^^^^^^^^^^^^^^ Using the last argument as keyword parameters is deprecated
- SOURCE
-
- expect_correction(<<~SOURCE)
- users.call(id, a: :b, c: :d)
- SOURCE
- end
-
- it 'registers an offense on the last non-block argument' do
- expect_offense(<<~SOURCE, 'create_service.rb')
- users.call(id, params, &block)
- ^^^^^^ Using the last argument as keyword parameters is deprecated
- SOURCE
-
- expect_correction(<<~SOURCE)
- users.call(id, **params, &block)
- SOURCE
- end
-
- it 'does not register an offense if the only argument is a block argument' do
- expect_no_offenses(<<~SOURCE, 'create_service.rb')
- users.call(&block)
- SOURCE
- end
-
- it 'registers an offense and corrects by converting splat to double splat' do
- expect_offense(<<~SOURCE, 'create_service.rb')
- users.call(id, *params)
- ^^^^^^^ Using the last argument as keyword parameters is deprecated
- SOURCE
-
- expect_correction(<<~SOURCE)
- users.call(id, **params)
- SOURCE
- end
-
- it 'does not register an offense if already a kwarg', :aggregate_failures do
- expect_no_offenses(<<~SOURCE, 'create_service.rb')
- users.call(**params)
- SOURCE
-
- expect_no_offenses(<<~SOURCE, 'create_service.rb')
- users.call(id, a: :b, c: :d)
- SOURCE
- end
-
- it 'does not register an offense if the method name does not match' do
- expect_no_offenses(<<~SOURCE, 'create_service.rb')
- users.process(params)
- SOURCE
- end
-
- it 'does not register an offense if the line number does not match' do
- expect_no_offenses(<<~SOURCE, 'create_service.rb')
- users.process
- users.call(params)
- SOURCE
- end
-
- it 'does not register an offense if the filename does not match' do
- expect_no_offenses(<<~SOURCE, 'update_service.rb')
- users.call(params)
- SOURCE
- end
-
- context 'with Ruby 3.0', :ruby30 do
- it 'does not register an offense with known warning' do
- expect_no_offenses(<<~SOURCE, 'create_service.rb')
- users.call(params)
- SOURCE
- end
- end
- end
-end
diff --git a/spec/rubocop/cop/migration/versioned_migration_class_spec.rb b/spec/rubocop/cop/migration/versioned_migration_class_spec.rb
index 332b02078f4..b92d9d21498 100644
--- a/spec/rubocop/cop/migration/versioned_migration_class_spec.rb
+++ b/spec/rubocop/cop/migration/versioned_migration_class_spec.rb
@@ -82,6 +82,15 @@ RSpec.describe RuboCop::Cop::Migration::VersionedMigrationClass, feature_categor
end
RUBY
end
+
+ it 'excludes parentless classes defined inside the migration' do
+ expect_no_offenses(<<~RUBY)
+ class TestMigration < Gitlab::Database::Migration[2.1]
+ class TestClass
+ end
+ end
+ RUBY
+ end
end
end
end
diff --git a/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb b/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb
index 2747e1ec811..aa758e19dfa 100644
--- a/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb
+++ b/spec/scripts/generate_message_to_run_e2e_pipeline_spec.rb
@@ -235,7 +235,7 @@ RSpec.describe GenerateMessageToRunE2ePipeline, feature_category: :tooling do
Once done, apply the ✅ emoji on this comment.
- For any questions or help, reach out on the internal #quality Slack channel.
+ **Team members only:** for any questions or help, reach out on the internal `#quality` Slack channel.
<!-- Run e2e warning end -->
MARKDOWN
end
diff --git a/spec/scripts/trigger-build_spec.rb b/spec/scripts/trigger-build_spec.rb
index d3b520d385f..f46adb1a9f1 100644
--- a/spec/scripts/trigger-build_spec.rb
+++ b/spec/scripts/trigger-build_spec.rb
@@ -477,6 +477,18 @@ RSpec.describe Trigger, feature_category: :tooling do
end
end
+ describe "BRANCH_OPERATOR" do
+ before do
+ stub_env('CI_PROJECT_PATH', 'gitlab-org/cloud-native/gitlab-operator')
+ end
+
+ context 'when CI_PROJECT_PATH is gitlab-org/cloud-native/gitlab-operator' do
+ it 'sets BRANCH_OPERATOR to CI_COMMIT_REF_NAME' do
+ expect(subject.variables['BRANCH_OPERATOR']).to eq(env['CI_COMMIT_REF_NAME'])
+ end
+ end
+ end
+
describe "REVIEW_SLUG" do
before do
stub_env('CI_PROJECT_PATH', 'gitlab-org/gitlab-foss')
diff --git a/spec/serializers/activity_pub/activity_streams_serializer_spec.rb b/spec/serializers/activity_pub/activity_streams_serializer_spec.rb
new file mode 100644
index 00000000000..c74beba7a81
--- /dev/null
+++ b/spec/serializers/activity_pub/activity_streams_serializer_spec.rb
@@ -0,0 +1,157 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ActivityPub::ActivityStreamsSerializer, feature_category: :integrations do
+ let(:implementer_class) do
+ Class.new(described_class) do
+ include WithPagination
+ end
+ end
+
+ let(:entity_class) do
+ Class.new(Grape::Entity) do
+ expose :id do |*|
+ 'https://example.com/unique/url'
+ end
+
+ expose :type do |*|
+ 'Person'
+ end
+
+ expose :name do |*|
+ 'Alice'
+ end
+ end
+ end
+
+ shared_examples_for 'ActivityStreams document' do
+ it 'belongs to the ActivityStreams namespace' do
+ expect(subject['@context']).to eq 'https://www.w3.org/ns/activitystreams'
+ end
+
+ it 'has a unique identifier' do
+ expect(subject).to have_key 'id'
+ end
+
+ it 'has a type' do
+ expect(subject).to have_key 'type'
+ end
+ end
+
+ before do
+ implementer_class.entity entity_class
+ end
+
+ context 'when the serializer is not paginated' do
+ let(:resource) { build_stubbed(:release) }
+ let(:outbox_url) { 'https://example.com/unique/url/outbox' }
+
+ context 'with a valid represented entity' do
+ subject { implementer_class.new.represent(resource, outbox: outbox_url) }
+
+ it_behaves_like 'ActivityStreams document'
+
+ it 'exposes an outbox' do
+ expect(subject['outbox']).to eq 'https://example.com/unique/url/outbox'
+ end
+
+ it 'includes serialized data' do
+ expect(subject['name']).to eq 'Alice'
+ end
+ end
+
+ context 'when the represented entity provides no identifier' do
+ subject { implementer_class.new.represent(resource, outbox: outbox_url) }
+
+ before do
+ allow(entity_class).to receive(:represent).and_return({ type: 'Person' })
+ end
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(ActivityPub::ActivityStreamsSerializer::MissingIdentifierError)
+ end
+ end
+
+ context 'when the represented entity provides no type' do
+ subject { implementer_class.new.represent(resource, outbox: outbox_url) }
+
+ before do
+ allow(entity_class).to receive(:represent).and_return({ id: 'https://example.com/unique/url' })
+ end
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(ActivityPub::ActivityStreamsSerializer::MissingTypeError)
+ end
+ end
+
+ context 'when the caller provides no outbox parameter' do
+ subject { implementer_class.new.represent(resource) }
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(ActivityPub::ActivityStreamsSerializer::MissingOutboxError)
+ end
+ end
+ end
+
+ context 'when the serializer is paginated' do
+ let(:resources) { build_stubbed_list(:release, 3) }
+ let(:request) { ActionDispatch::Request.new(request_data) }
+ let(:response) { ActionDispatch::Response.new }
+ let(:url) { 'https://example.com/resource/url' }
+ let(:decorated) { implementer_class.new.with_pagination(request, response) }
+
+ before do
+ allow(resources).to receive(:page).and_return(resources)
+ allow(resources).to receive(:per).and_return(resources)
+ allow(resources).to receive(:current_page).and_return(2)
+ allow(resources).to receive(:total_pages).and_return(3)
+ allow(resources).to receive(:total_count).and_return(10)
+ allow(decorated.paginator).to receive(:paginate).and_return(resources)
+ end
+
+ context 'when no page parameter is provided' do
+ subject { decorated.represent(resources) }
+
+ let(:request_data) do
+ { "rack.url_scheme" => "https", "HTTP_HOST" => "example.com", "PATH_INFO" => '/resource/url' }
+ end
+
+ it_behaves_like 'ActivityStreams document'
+
+ it 'is an index document for the pagination' do
+ expect(subject['type']).to eq 'OrderedCollection'
+ end
+
+ it 'contains the total amount of items' do
+ expect(subject['totalItems']).to eq 10
+ end
+
+ it 'contains links to first and last page' do
+ expect(subject['first']).to eq "#{url}?page=1"
+ expect(subject['last']).to eq "#{url}?page=3"
+ end
+ end
+
+ context 'when a page parameter is provided' do
+ subject { decorated.represent(resources) }
+
+ let(:request_data) do
+ { 'rack.url_scheme' => 'https', 'HTTP_HOST' => 'example.com', 'PATH_INFO' => '/resource/url',
+ 'QUERY_STRING' => 'page=2&per_page=1' }
+ end
+
+ it_behaves_like 'ActivityStreams document'
+
+ it 'is a page document' do
+ expect(subject['type']).to eq 'OrderedCollectionPage'
+ end
+
+ it 'contains navigation links' do
+ expect(subject['prev']).to be_present
+ expect(subject['next']).to be_present
+ expect(subject['partOf']).to be_present
+ end
+ end
+ end
+end
diff --git a/spec/serializers/activity_pub/project_entity_spec.rb b/spec/serializers/activity_pub/project_entity_spec.rb
new file mode 100644
index 00000000000..f273acace73
--- /dev/null
+++ b/spec/serializers/activity_pub/project_entity_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ActivityPub::ProjectEntity, feature_category: :groups_and_projects do
+ let(:project) { build_stubbed(:project, name: 'Fooify', path: 'fooify') }
+ let(:entity) { described_class.new(project) }
+
+ context 'as json' do
+ subject { entity.as_json }
+
+ it 'has releases page as id' do
+ expect(subject[:id]).to match(%r{/fooify$})
+ end
+
+ it 'is an Application actor' do
+ expect(subject[:type]).to eq 'Application'
+ end
+
+ it 'provides project name' do
+ expect(subject[:name]).to eq project.name
+ end
+
+ it 'provides a description of the project' do
+ expect(subject[:summary]).to eq project.description
+ end
+
+ it 'provides an url for web content' do
+ expect(subject[:url]).to match(%r{/fooify$})
+ end
+ end
+end
diff --git a/spec/serializers/activity_pub/release_entity_spec.rb b/spec/serializers/activity_pub/release_entity_spec.rb
new file mode 100644
index 00000000000..a473fbcc2bd
--- /dev/null
+++ b/spec/serializers/activity_pub/release_entity_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ActivityPub::ReleaseEntity, feature_category: :groups_and_projects do
+ let(:release) { build_stubbed(:release) }
+ let(:entity) { described_class.new(release, url: '/outbox') }
+
+ context 'as json' do
+ subject { entity.as_json }
+
+ it 'has tag as id' do
+ expect(subject[:id]).to match(/##{release.tag}$/)
+ end
+
+ it 'is a Create activity' do
+ expect(subject[:type]).to eq 'Create'
+ end
+
+ it 'is addressed to public' do
+ expect(subject[:to]).to eq 'https://www.w3.org/ns/activitystreams#Public'
+ end
+
+ it 'has an author' do
+ expect(subject[:actor]).to include(:id, :type, :name, :preferredUsername, :url)
+ end
+
+ it 'embeds the release as an Application actor' do
+ expect(subject[:object][:type]).to eq 'Application'
+ end
+
+ it 'provides release name' do
+ expect(subject[:object][:name]).to eq release.name
+ end
+
+ it 'provides release description' do
+ expect(subject[:object][:content]).to eq release.description
+ end
+
+ it 'provides an url for web content' do
+ expect(subject[:object][:url]).to include release.tag
+ end
+
+ it 'provides project data as context' do
+ expect(subject[:object][:context]).to include(:id, :type, :name, :summary, :url)
+ end
+ end
+end
diff --git a/spec/serializers/activity_pub/releases_actor_entity_spec.rb b/spec/serializers/activity_pub/releases_actor_entity_spec.rb
new file mode 100644
index 00000000000..fe388968867
--- /dev/null
+++ b/spec/serializers/activity_pub/releases_actor_entity_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ActivityPub::ReleasesActorEntity, feature_category: :groups_and_projects do
+ let(:project) { build_stubbed(:project, name: 'Fooify', path: 'fooify') }
+ let(:releases) { build_stubbed_list(:release, 3, project: project) }
+
+ let(:entity) { described_class.new(project) }
+
+ context 'as json' do
+ subject { entity.as_json }
+
+ it 'has releases page as id' do
+ expect(subject[:id]).to include "/fooify/-/releases"
+ end
+
+ it 'is an Application actor' do
+ expect(subject[:type]).to eq 'Application'
+ end
+
+ it 'has a recognizable username' do
+ expect(subject[:preferredUsername]).to include 'releases'
+ end
+
+ it 'has a recognizable full name' do
+ expect(subject[:name]).to eq 'Releases - Fooify'
+ end
+
+ it 'provides a description of the project' do
+ expect(subject[:content]).to eq project.description
+ end
+
+ it 'provides project data as context' do
+ expect(subject[:context]).to include(:id, :type, :name, :summary, :url)
+ expect(subject[:context][:id]).to match(%r{/fooify$})
+ end
+ end
+end
diff --git a/spec/serializers/activity_pub/releases_actor_serializer_spec.rb b/spec/serializers/activity_pub/releases_actor_serializer_spec.rb
new file mode 100644
index 00000000000..bc754eabe5c
--- /dev/null
+++ b/spec/serializers/activity_pub/releases_actor_serializer_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ActivityPub::ReleasesActorSerializer, feature_category: :groups_and_projects do
+ let(:project) { build_stubbed(:project, name: 'Fooify', path: 'fooify') }
+ let(:releases) { build_stubbed_list(:release, 3, project: project) }
+
+ context 'when there is a single object provided' do
+ subject { described_class.new.represent(project, outbox: '/outbox') }
+
+ it 'serializes the actor attributes' do
+ expect(subject).to include(:id, :type, :preferredUsername, :name, :content, :context)
+ end
+ end
+end
diff --git a/spec/serializers/activity_pub/releases_outbox_serializer_spec.rb b/spec/serializers/activity_pub/releases_outbox_serializer_spec.rb
new file mode 100644
index 00000000000..606b0130e0f
--- /dev/null
+++ b/spec/serializers/activity_pub/releases_outbox_serializer_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ActivityPub::ReleasesOutboxSerializer, feature_category: :groups_and_projects do
+ let(:decorated) { described_class.new.with_pagination(request, response) }
+
+ let(:project) { build_stubbed(:project, name: 'Fooify', path: 'fooify') }
+ let(:releases) { build_stubbed_list(:release, 3, project: project) }
+
+ before do
+ allow(releases).to receive(:page).and_return(releases)
+ allow(releases).to receive(:per).and_return(releases)
+ allow(releases).to receive(:current_page).and_return(1)
+ allow(releases).to receive(:total_pages).and_return(1)
+ allow(decorated.paginator).to receive(:paginate).and_return(releases)
+ end
+
+ context 'when there is a list of objects provided' do
+ subject { decorated.represent(releases, url: '/outbox') }
+
+ let(:request) { ActionDispatch::Request.new({ 'QUERY_STRING' => 'page=1' }) }
+ let(:response) { ActionDispatch::Response.new }
+
+ it 'is a OrderedCollection document' do
+ expect(subject[:type]).to eq 'OrderedCollectionPage'
+ end
+
+ it 'serializes the releases' do
+ expect(subject[:orderedItems].count).to eq 3
+ expect(subject[:orderedItems][0]).to include(:id, :type, :to, :actor, :object)
+ end
+ end
+end
diff --git a/spec/serializers/activity_pub/user_entity_spec.rb b/spec/serializers/activity_pub/user_entity_spec.rb
new file mode 100644
index 00000000000..d9ab7a11ecf
--- /dev/null
+++ b/spec/serializers/activity_pub/user_entity_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ActivityPub::UserEntity, feature_category: :user_profile do
+ let(:user) { build_stubbed(:user, name: 'Alice', username: 'alice') }
+ let(:entity) { described_class.new(user) }
+
+ context 'as json' do
+ subject { entity.as_json }
+
+ it 'has releases page as id' do
+ expect(subject[:id]).to match(%r{/alice$})
+ end
+
+ it 'is a Person actor' do
+ expect(subject[:type]).to eq 'Person'
+ end
+
+ it 'provides project name' do
+ expect(subject[:name]).to eq 'Alice'
+ end
+
+ it 'provides an url for web content' do
+ expect(subject[:url]).to match(%r{/alice$})
+ end
+ end
+end
diff --git a/spec/serializers/admin/abuse_report_details_entity_spec.rb b/spec/serializers/admin/abuse_report_details_entity_spec.rb
index 727716d76a4..bed9775ac8c 100644
--- a/spec/serializers/admin/abuse_report_details_entity_spec.rb
+++ b/spec/serializers/admin/abuse_report_details_entity_spec.rb
@@ -5,10 +5,11 @@ require 'spec_helper'
RSpec.describe Admin::AbuseReportDetailsEntity, feature_category: :insider_threat do
include Gitlab::Routing
- let(:report) { build_stubbed(:abuse_report) }
- let(:user) { report.user }
- let(:reporter) { report.reporter }
- let!(:other_report) { create(:abuse_report, user: user) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
+ let_it_be(:report) { build_stubbed(:abuse_report) }
+ let_it_be(:user) { report.user }
+ let_it_be(:reporter) { report.reporter }
+ let_it_be(:past_report) { create_default(:abuse_report, :closed, user: user) }
+ let_it_be(:similar_open_report) { create_default(:abuse_report, user: user, category: report.category) }
let(:entity) do
described_class.new(report)
@@ -18,11 +19,10 @@ RSpec.describe Admin::AbuseReportDetailsEntity, feature_category: :insider_threa
subject(:entity_hash) { entity.as_json }
it 'exposes correct attributes' do
- expect(entity_hash.keys).to include(
+ expect(entity_hash.keys).to match_array([
:user,
- :reporter,
:report
- )
+ ])
end
it 'correctly exposes `user`', :aggregate_failures do
@@ -39,7 +39,8 @@ RSpec.describe Admin::AbuseReportDetailsEntity, feature_category: :insider_threa
:admin_path,
:plan,
:verification_state,
- :other_reports,
+ :past_closed_reports,
+ :similar_open_reports,
:most_used_ip,
:last_sign_in_ip,
:snippets_count,
@@ -53,11 +54,77 @@ RSpec.describe Admin::AbuseReportDetailsEntity, feature_category: :insider_threa
:credit_card
])
- expect(user_hash[:other_reports][0].keys).to match_array([
+ expect(user_hash[:past_closed_reports][0].keys).to match_array([
:created_at,
:category,
:report_path
])
+
+ similar_open_report_hash = user_hash[:similar_open_reports][0]
+ expect(similar_open_report_hash.keys).to match_array([
+ :id,
+ :global_id,
+ :status,
+ :message,
+ :reported_at,
+ :category,
+ :type,
+ :content,
+ :url,
+ :screenshot,
+ :update_path,
+ :moderate_user_path,
+ :reporter
+ ])
+
+ similar_reporter_hash = similar_open_report_hash[:reporter]
+ expect(similar_reporter_hash.keys).to match_array([
+ :name,
+ :username,
+ :avatar_url,
+ :path
+ ])
+ end
+
+ context 'when report is closed' do
+ let(:report) { build_stubbed(:abuse_report, :closed) }
+
+ it 'does not expose `user.similar_open_reports`' do
+ user_hash = entity_hash[:user]
+
+ expect(user_hash).not_to include(:similar_open_reports)
+ end
+ end
+
+ it 'correctly exposes `report`', :aggregate_failures do
+ report_hash = entity_hash[:report]
+
+ expect(report_hash.keys).to match_array([
+ :id,
+ :global_id,
+ :status,
+ :message,
+ :reported_at,
+ :category,
+ :type,
+ :content,
+ :url,
+ :screenshot,
+ :update_path,
+ :moderate_user_path,
+ :reporter
+ ])
+ end
+
+ it 'correctly exposes `reporter`' do
+ reporter_hash = entity_hash[:report][:reporter]
+
+ expect(reporter_hash.keys).to match_array([
+ :name,
+ :username,
+ :avatar_url,
+ :path
+ ])
end
describe 'users plan' do
@@ -110,33 +177,5 @@ RSpec.describe Admin::AbuseReportDetailsEntity, feature_category: :insider_threa
end
end
end
-
- it 'correctly exposes `reporter`' do
- reporter_hash = entity_hash[:reporter]
-
- expect(reporter_hash.keys).to match_array([
- :name,
- :username,
- :avatar_url,
- :path
- ])
- end
-
- it 'correctly exposes `report`' do
- report_hash = entity_hash[:report]
-
- expect(report_hash.keys).to match_array([
- :status,
- :message,
- :reported_at,
- :category,
- :type,
- :content,
- :url,
- :screenshot,
- :update_path,
- :moderate_user_path
- ])
- end
end
end
diff --git a/spec/serializers/admin/abuse_report_details_serializer_spec.rb b/spec/serializers/admin/abuse_report_details_serializer_spec.rb
index a42c56c0921..3bdd2e46ba3 100644
--- a/spec/serializers/admin/abuse_report_details_serializer_spec.rb
+++ b/spec/serializers/admin/abuse_report_details_serializer_spec.rb
@@ -9,11 +9,10 @@ RSpec.describe Admin::AbuseReportDetailsSerializer, feature_category: :insider_t
describe '#represent' do
it 'serializes an abuse report' do
- is_expected.to include(
+ is_expected.to match_array([
:user,
- :reporter,
:report
- )
+ ])
end
end
end
diff --git a/spec/serializers/admin/abuse_report_entity_spec.rb b/spec/serializers/admin/abuse_report_entity_spec.rb
index c7f57258f40..e84cfe73b96 100644
--- a/spec/serializers/admin/abuse_report_entity_spec.rb
+++ b/spec/serializers/admin/abuse_report_entity_spec.rb
@@ -15,15 +15,16 @@ RSpec.describe Admin::AbuseReportEntity, feature_category: :insider_threat do
subject(:entity_hash) { entity.as_json }
it 'exposes correct attributes' do
- expect(entity_hash.keys).to include(
+ expect(entity_hash.keys).to match_array([
:category,
:created_at,
:updated_at,
:count,
+ :labels,
:reported_user,
:reporter,
:report_path
- )
+ ])
end
it 'correctly exposes `reported user`' do
@@ -37,5 +38,15 @@ RSpec.describe Admin::AbuseReportEntity, feature_category: :insider_threat do
it 'correctly exposes :report_path' do
expect(entity_hash[:report_path]).to eq admin_abuse_report_path(abuse_report)
end
+
+ context 'when abuse_report_labels feature flag is disabled' do
+ before do
+ stub_feature_flags(abuse_report_labels: false)
+ end
+
+ it 'does not expose labels' do
+ expect(entity_hash.keys).not_to include(:labels)
+ end
+ end
end
end
diff --git a/spec/serializers/admin/reported_content_entity_spec.rb b/spec/serializers/admin/reported_content_entity_spec.rb
new file mode 100644
index 00000000000..0af16561005
--- /dev/null
+++ b/spec/serializers/admin/reported_content_entity_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::ReportedContentEntity, feature_category: :insider_threat do
+ let_it_be(:report) { build_stubbed(:abuse_report) }
+
+ let(:entity) do
+ described_class.new(report)
+ end
+
+ describe '#as_json' do
+ subject(:entity_hash) { entity.as_json }
+
+ it 'exposes correct attributes' do
+ expect(entity_hash.keys).to match_array([
+ :id,
+ :global_id,
+ :status,
+ :message,
+ :reported_at,
+ :category,
+ :type,
+ :content,
+ :url,
+ :screenshot,
+ :reporter,
+ :update_path,
+ :moderate_user_path
+ ])
+ end
+
+ it 'includes correct value for global_id' do
+ allow(Gitlab::GlobalId).to receive(:build).with(report, { id: report.id }).and_return(:mock_global_id)
+
+ expect(entity_hash[:global_id]).to eq 'mock_global_id'
+ end
+
+ it 'correctly exposes `reporter`' do
+ reporter_hash = entity_hash[:reporter]
+
+ expect(reporter_hash.keys).to match_array([
+ :name,
+ :username,
+ :avatar_url,
+ :path
+ ])
+ end
+ end
+end
diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb
index 86eaf160b38..a9d58b20861 100644
--- a/spec/serializers/build_details_entity_spec.rb
+++ b/spec/serializers/build_details_entity_spec.rb
@@ -298,5 +298,21 @@ RSpec.describe BuildDetailsEntity do
end
end
end
+
+ context 'when the build has annotations' do
+ let!(:build) { create(:ci_build) }
+ let!(:annotation) { create(:ci_job_annotation, job: build, name: 'external_links', data: [{ external_link: { label: 'URL', url: 'https://example.com/' } }]) }
+
+ it 'exposes job URLs' do
+ expect(subject[:annotations].count).to eq(1)
+ expect(subject[:annotations].first[:name]).to eq('external_links')
+ expect(subject[:annotations].first[:data]).to include(a_hash_including(
+ 'external_link' => a_hash_including(
+ 'label' => 'URL',
+ 'url' => 'https://example.com/'
+ )
+ ))
+ end
+ end
end
end
diff --git a/spec/serializers/ci/job_annotation_entity_spec.rb b/spec/serializers/ci/job_annotation_entity_spec.rb
new file mode 100644
index 00000000000..8aef6e8cce3
--- /dev/null
+++ b/spec/serializers/ci/job_annotation_entity_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::JobAnnotationEntity, feature_category: :build_artifacts do
+ let(:entity) { described_class.new(annotation) }
+
+ let(:job) { build(:ci_build) }
+ let(:annotation) do
+ build(:ci_job_annotation, job: job, name: 'external_links', data:
+ [{ external_link: { label: 'URL', url: 'https://example.com/' } }])
+ end
+
+ describe '#as_json' do
+ subject { entity.as_json }
+
+ it 'contains valid name' do
+ expect(subject[:name]).to eq 'external_links'
+ end
+
+ it 'contains external links' do
+ expect(subject[:data]).to include(a_hash_including(
+ 'external_link' => a_hash_including(
+ 'label' => 'URL',
+ 'url' => 'https://example.com/'
+ )
+ ))
+ end
+ end
+end
diff --git a/spec/serializers/codequality_degradation_entity_spec.rb b/spec/serializers/codequality_degradation_entity_spec.rb
index 32269e5475b..3d07564c5dc 100644
--- a/spec/serializers/codequality_degradation_entity_spec.rb
+++ b/spec/serializers/codequality_degradation_entity_spec.rb
@@ -2,18 +2,31 @@
require 'spec_helper'
-RSpec.describe CodequalityDegradationEntity do
+RSpec.describe CodequalityDegradationEntity, feature_category: :code_quality do
let(:entity) { described_class.new(codequality_degradation) }
describe '#as_json' do
subject { entity.as_json }
+ context 'when sast_reports_in_inline_diff is disabled' do
+ before do
+ stub_feature_flags(sast_reports_in_inline_diff: false)
+ end
+
+ let(:codequality_degradation) { build(:codequality_degradation_1) }
+
+ it 'does not contain fingerprint' do
+ expect(subject[:fingerprint]).to be_nil
+ end
+ end
+
context 'when codequality contains an error' do
context 'when line is included in location' do
let(:codequality_degradation) { build(:codequality_degradation_2) }
it 'contains correct codequality degradation details', :aggregate_failures do
expect(subject[:description]).to eq("Method `new_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.")
+ expect(subject[:fingerprint]).to eq("f3bdc1e8c102ba5fbd9e7f6cda51c95e")
expect(subject[:severity]).to eq("major")
expect(subject[:file_path]).to eq("file_a.rb")
expect(subject[:line]).to eq(10)
@@ -27,6 +40,7 @@ RSpec.describe CodequalityDegradationEntity do
it 'contains correct codequality degradation details', :aggregate_failures do
expect(subject[:description]).to eq("Avoid parameter lists longer than 5 parameters. [12/5]")
+ expect(subject[:fingerprint]).to eq("ab5f8b935886b942d621399f5a2ca16e")
expect(subject[:severity]).to eq("minor")
expect(subject[:file_path]).to eq("file_b.rb")
expect(subject[:line]).to eq(10)
@@ -44,6 +58,7 @@ RSpec.describe CodequalityDegradationEntity do
it 'lowercases severity', :aggregate_failures do
expect(subject[:description]).to eq("Avoid parameter lists longer than 5 parameters. [12/5]")
+ expect(subject[:fingerprint]).to eq("ab5f8b935886b942d621399f5a2ca16e")
expect(subject[:severity]).to eq("minor")
expect(subject[:file_path]).to eq("file_b.rb")
expect(subject[:line]).to eq(10)
diff --git a/spec/serializers/codequality_reports_comparer_serializer_spec.rb b/spec/serializers/codequality_reports_comparer_serializer_spec.rb
index 50c8a69737c..7d6f49bf41d 100644
--- a/spec/serializers/codequality_reports_comparer_serializer_spec.rb
+++ b/spec/serializers/codequality_reports_comparer_serializer_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe CodequalityReportsComparerSerializer do
- let(:project) { double(:project) }
+RSpec.describe CodequalityReportsComparerSerializer, feature_category: :code_quality do
+ let(:project) { build_stubbed(:project) }
let(:serializer) { described_class.new(project: project).represent(comparer) }
let(:comparer) { Gitlab::Ci::Reports::CodequalityReportsComparer.new(base_report, head_report) }
let(:base_report) { Gitlab::Ci::Reports::CodequalityReports.new }
diff --git a/spec/serializers/deployment_entity_spec.rb b/spec/serializers/deployment_entity_spec.rb
index b0f3f328a4f..53f0e0c34e1 100644
--- a/spec/serializers/deployment_entity_spec.rb
+++ b/spec/serializers/deployment_entity_spec.rb
@@ -10,8 +10,11 @@ RSpec.describe DeploymentEntity do
let_it_be(:environment) { create(:environment, project: project) }
let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project, user: user) }
let_it_be_with_reload(:build) { create(:ci_build, :manual, :environment_with_deployment_tier, pipeline: pipeline) }
+ let_it_be_with_reload(:bridge) do
+ create(:ci_bridge, :manual, :environment_with_deployment_tier, pipeline: pipeline, downstream: project)
+ end
- let_it_be_with_refind(:deployment) { create(:deployment, deployable: build, environment: environment) }
+ let!(:deployment) { create(:deployment, deployable: job, environment: environment, project: project) }
let(:request) { double('request') }
let(:entity) { described_class.new(deployment, request: request) }
@@ -28,22 +31,33 @@ RSpec.describe DeploymentEntity do
allow(request).to receive(:project).and_return(project)
end
- it 'exposes fields', :aggregate_failures do
- expect(subject).to include(:iid)
- expect(subject[:ref][:name]).to eq 'master'
- expect(subject).to include(:status)
- expect(subject).to include(:created_at)
- expect(subject).to include(:deployed_at)
- expect(subject).to include(:is_last)
- expect(subject).to include(:tier_in_yaml)
+ shared_examples_for 'exposes fields' do
+ it 'exposes fields', :aggregate_failures do
+ expect(subject).to include(:iid)
+ expect(subject[:ref][:name]).to eq 'master'
+ expect(subject).to include(:status)
+ expect(subject).to include(:created_at)
+ expect(subject).to include(:deployed_at)
+ expect(subject).to include(:is_last)
+ expect(subject).to include(:tier_in_yaml)
+ end
+ end
+
+ context 'when deployable is build job' do
+ let(:job) { build }
+
+ it_behaves_like 'exposes fields'
+ end
+
+ context 'when deployable is bridge job' do
+ let(:job) { bridge }
+
+ it_behaves_like 'exposes fields'
end
context 'when deployable is nil' do
let(:entity) { described_class.new(deployment, request: request, deployment_details: false) }
-
- before do
- deployment.update!(deployable: nil)
- end
+ let(:job) { nil }
it 'does not expose deployable entry' do
expect(subject).not_to include(:deployable)
@@ -51,15 +65,17 @@ RSpec.describe DeploymentEntity do
end
context 'when the pipeline has another manual action' do
- let_it_be(:other_build) do
- create(:ci_build, :manual, name: 'another deploy', pipeline: pipeline, environment: build.environment)
+ let!(:other_job) do
+ create(:ci_build, :manual, name: 'another deploy', pipeline: pipeline, environment: job.environment)
end
- let_it_be(:other_deployment) { create(:deployment, deployable: build, environment: environment) }
+ let!(:other_deployment) { create(:deployment, deployable: job, environment: environment) }
+
+ let(:job) { build }
it 'returns another manual action' do
- expect(subject[:manual_actions].count).to eq(1)
- expect(subject[:manual_actions].pluck(:name)).to match_array(['another deploy'])
+ expect(subject[:manual_actions].count).to eq(2)
+ expect(subject[:manual_actions].pluck(:name)).to match_array(['another deploy', 'bridge'])
end
context 'when user is a reporter' do
@@ -82,18 +98,22 @@ RSpec.describe DeploymentEntity do
end
describe 'scheduled_actions' do
- let(:build) { create(:ci_build, :success, pipeline: pipeline) }
-
- before do
- deployment.update!(deployable: build)
- end
+ let(:job) { create(:ci_build, :success, pipeline: pipeline) }
context 'when the same pipeline has a scheduled action' do
- let(:other_build) { create(:ci_build, :schedulable, :success, pipeline: pipeline, name: 'other build') }
- let!(:other_deployment) { create(:deployment, deployable: other_build, environment: environment) }
+ let(:other_job) { create(:ci_build, :schedulable, :success, pipeline: pipeline, name: 'other job') }
+ let!(:other_deployment) { create(:deployment, deployable: other_job, environment: environment) }
it 'returns other scheduled actions' do
- expect(subject[:scheduled_actions][0][:name]).to eq 'other build'
+ expect(subject[:scheduled_actions][0][:name]).to eq 'other job'
+ end
+
+ context 'when deployable is bridge job' do
+ let(:job) { create(:ci_bridge, :success, pipeline: pipeline) }
+
+ it 'returns nil' do
+ expect(subject[:scheduled_actions]).to be_nil
+ end
end
end
@@ -115,10 +135,6 @@ RSpec.describe DeploymentEntity do
end
describe 'playable_build' do
- before do
- deployment.update!(deployable: job)
- end
-
context 'when the deployment has a playable deployable' do
context 'when this job is build and ready to be played' do
let(:job) { create(:ci_build, :playable, :scheduled, pipeline: pipeline) }
@@ -161,6 +177,8 @@ RSpec.describe DeploymentEntity do
described_class.new(deployment, request: request, deployment_details: false)
end
+ let(:job) { build }
+
it 'does not serialize deployment details' do
expect(subject.with_indifferent_access)
.not_to include(:commit, :manual_actions, :scheduled_actions)
@@ -172,5 +190,16 @@ RSpec.describe DeploymentEntity do
.to eq(name: 'test', build_path: path)
end
end
+
+ context 'when deployable is bridge' do
+ let(:job) { bridge }
+
+ it 'only exposes deployable name and path' do
+ project_job_path(project, deployment.deployable).tap do |path|
+ expect(subject.fetch(:deployable))
+ .to eq(name: 'bridge', build_path: path)
+ end
+ end
+ end
end
end
diff --git a/spec/serializers/import/github_realtime_repo_entity_spec.rb b/spec/serializers/import/github_realtime_repo_entity_spec.rb
index 7f137366be2..bbaeb5c4ea8 100644
--- a/spec/serializers/import/github_realtime_repo_entity_spec.rb
+++ b/spec/serializers/import/github_realtime_repo_entity_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Import::GithubRealtimeRepoEntity, feature_category: :importers do
subject(:entity) { described_class.new(project) }
- let(:import_state) { instance_double(ProjectImportState, failed?: false, in_progress?: true) }
+ let(:import_state) { instance_double(ProjectImportState, failed?: false, completed?: true) }
let(:import_failures) { [instance_double(ImportFailure, exception_message: 'test error')] }
let(:project) do
instance_double(
@@ -27,7 +27,7 @@ RSpec.describe Import::GithubRealtimeRepoEntity, feature_category: :importers do
end
context 'when import stats is failed' do
- let(:import_state) { instance_double(ProjectImportState, failed?: true, in_progress?: false) }
+ let(:import_state) { instance_double(ProjectImportState, failed?: true, completed?: true) }
it 'includes import_error' do
data = entity.as_json
diff --git a/spec/serializers/import/github_realtime_repo_serializer_spec.rb b/spec/serializers/import/github_realtime_repo_serializer_spec.rb
index b656132e332..825118d0f80 100644
--- a/spec/serializers/import/github_realtime_repo_serializer_spec.rb
+++ b/spec/serializers/import/github_realtime_repo_serializer_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Import::GithubRealtimeRepoSerializer, feature_category: :importer
end
describe '#represent' do
- let(:import_state) { instance_double(ProjectImportState, failed?: false, in_progress?: true) }
+ let(:import_state) { instance_double(ProjectImportState, failed?: false, completed?: false) }
let(:project) do
instance_double(
Project,
diff --git a/spec/serializers/profile/event_entity_spec.rb b/spec/serializers/profile/event_entity_spec.rb
index b1246e7e47d..3dade4210b3 100644
--- a/spec/serializers/profile/event_entity_spec.rb
+++ b/spec/serializers/profile/event_entity_spec.rb
@@ -153,6 +153,17 @@ RSpec.describe Profile::EventEntity, feature_category: :user_profile do
end
end
+ context 'without target' do
+ let(:event) do
+ build(:event, :destroyed, author: user, project: project, target_type: Milestone.to_s)
+ end
+
+ it 'only exposes target.type' do
+ expect(subject[:target][:type]).to eq(Milestone.to_s)
+ expect(subject[:target]).not_to include(:web_url)
+ end
+ end
+
context 'with resource parent' do
it 'exposes resource parent fields' do
resource_parent = event.resource_parent
diff --git a/spec/services/admin/abuse_report_labels/create_service_spec.rb b/spec/services/admin/abuse_report_labels/create_service_spec.rb
new file mode 100644
index 00000000000..168229d6ed9
--- /dev/null
+++ b/spec/services/admin/abuse_report_labels/create_service_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::AbuseReportLabels::CreateService, feature_category: :insider_threat do
+ describe '#execute' do
+ let(:color) { 'red' }
+ let(:color_in_hex) { ::Gitlab::Color.of(color) }
+ let(:params) { { title: 'FancyLabel', color: color } }
+
+ subject(:execute) { described_class.new(params).execute }
+
+ shared_examples 'creates a label with the correct values' do
+ it 'creates a label with the correct values', :aggregate_failures do
+ expect { execute }.to change { Admin::AbuseReportLabel.count }.from(0).to(1)
+
+ label = Admin::AbuseReportLabel.last
+ expect(label.title).to eq params[:title]
+ expect(label.color).to eq color_in_hex
+ end
+
+ it 'returns the persisted label' do
+ result = execute
+ expect(result).to be_an_instance_of(Admin::AbuseReportLabel)
+ expect(result.persisted?).to eq true
+ end
+ end
+
+ it_behaves_like 'creates a label with the correct values'
+
+ context 'without color param' do
+ let(:params) { { title: 'FancyLabel' } }
+ let(:color_in_hex) { ::Gitlab::Color.of(Label::DEFAULT_COLOR) }
+
+ it_behaves_like 'creates a label with the correct values'
+ end
+
+ context 'with errors' do
+ let!(:existing_label) { create(:abuse_report_label, title: params[:title]) }
+
+ it 'does not create the label' do
+ expect { execute }.not_to change { Admin::AbuseReportLabel.count }
+ end
+
+ it 'returns the label with errors' do
+ label = execute
+ expect(label.errors.messages).to include({ title: ["has already been taken"] })
+ end
+ end
+ end
+end
diff --git a/spec/services/admin/abuse_reports/moderate_user_service_spec.rb b/spec/services/admin/abuse_reports/moderate_user_service_spec.rb
index 6e8a59f4e49..7e08db2b612 100644
--- a/spec/services/admin/abuse_reports/moderate_user_service_spec.rb
+++ b/spec/services/admin/abuse_reports/moderate_user_service_spec.rb
@@ -4,6 +4,10 @@ require 'spec_helper'
RSpec.describe Admin::AbuseReports::ModerateUserService, feature_category: :instance_resiliency do
let_it_be_with_reload(:abuse_report) { create(:abuse_report) }
+ let_it_be_with_reload(:similar_abuse_report) do
+ create(:abuse_report, user: abuse_report.user, category: abuse_report.category)
+ end
+
let(:action) { 'ban_user' }
let(:close) { true }
let(:reason) { 'spam' }
@@ -26,6 +30,12 @@ RSpec.describe Admin::AbuseReports::ModerateUserService, feature_category: :inst
it 'closes the report' do
expect { subject }.to change { abuse_report.closed? }.from(false).to(true)
end
+
+ context 'when similar open reports for the user exist' do
+ it 'closes the similar report' do
+ expect { subject }.to change { similar_abuse_report.reload.closed? }.from(false).to(true)
+ end
+ end
end
shared_examples 'does not close the report' do
@@ -33,6 +43,13 @@ RSpec.describe Admin::AbuseReports::ModerateUserService, feature_category: :inst
subject
expect(abuse_report.closed?).to be(false)
end
+
+ context 'when similar open reports for the user exist' do
+ it 'does not close the similar report' do
+ subject
+ expect(similar_abuse_report.reload.closed?).to be(false)
+ end
+ end
end
shared_examples 'does not record an event' do
diff --git a/spec/services/admin/abuse_reports/update_service_spec.rb b/spec/services/admin/abuse_reports/update_service_spec.rb
new file mode 100644
index 00000000000..e53b40979ec
--- /dev/null
+++ b/spec/services/admin/abuse_reports/update_service_spec.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::AbuseReports::UpdateService, feature_category: :instance_resiliency do
+ let_it_be(:current_user) { create(:admin) }
+ let_it_be(:abuse_report) { create(:abuse_report) }
+ let_it_be(:label) { create(:abuse_report_label) }
+
+ let(:params) { {} }
+ let(:service) { described_class.new(abuse_report, current_user, params) }
+
+ describe '#execute', :enable_admin_mode do
+ subject { service.execute }
+
+ shared_examples 'returns an error response' do |error|
+ it 'returns an error response' do
+ expect(subject).to be_error
+ expect(subject.message).to eq error
+ end
+ end
+
+ context 'with invalid parameters' do
+ describe 'invalid user' do
+ describe 'when no user is given' do
+ let_it_be(:current_user) { nil }
+
+ it_behaves_like 'returns an error response', 'Admin is required'
+ end
+
+ describe 'when given user is not an admin' do
+ let_it_be(:current_user) { create(:user) }
+
+ it_behaves_like 'returns an error response', 'Admin is required'
+ end
+ end
+
+ describe 'invalid label_ids' do
+ let(:params) { { label_ids: ['invalid_global_id', non_existing_record_id] } }
+
+ it 'does not update the abuse report' do
+ expect { subject }.not_to change { abuse_report.labels }
+ end
+
+ it { is_expected.to be_success }
+ end
+ end
+
+ describe 'with valid parameters' do
+ context 'when label_ids is empty' do
+ let(:params) { { label_ids: [] } }
+
+ context 'when abuse report has existing labels' do
+ before do
+ abuse_report.labels = [label]
+ end
+
+ it 'clears the abuse report labels' do
+ expect { subject }.to change { abuse_report.labels.count }.from(1).to(0)
+ end
+
+ it { is_expected.to be_success }
+ end
+
+ context 'when abuse report has no existing labels' do
+ it 'does not update the abuse report' do
+ expect { subject }.not_to change { abuse_report.labels }
+ end
+
+ it { is_expected.to be_success }
+ end
+ end
+
+ context 'when label_ids is not empty' do
+ let(:params) { { label_ids: [Gitlab::GlobalId.build(label, id: label.id).to_s] } }
+
+ it 'updates the abuse report' do
+ expect { subject }.to change { abuse_report.label_ids }.from([]).to([label.id])
+ end
+
+ it { is_expected.to be_success }
+ end
+ end
+ end
+end
diff --git a/spec/services/application_settings/update_service_spec.rb b/spec/services/application_settings/update_service_spec.rb
index 9d73a4a6cee..0b5ba1db9d4 100644
--- a/spec/services/application_settings/update_service_spec.rb
+++ b/spec/services/application_settings/update_service_spec.rb
@@ -2,10 +2,10 @@
require 'spec_helper'
-RSpec.describe ApplicationSettings::UpdateService do
+RSpec.describe ApplicationSettings::UpdateService, feature_category: :shared do
include ExternalAuthorizationServiceHelpers
- let(:application_settings) { create(:application_setting) }
+ let(:application_settings) { ::Gitlab::CurrentSettings.current_application_settings }
let(:admin) { create(:user, :admin) }
let(:params) { {} }
@@ -331,7 +331,8 @@ RSpec.describe ApplicationSettings::UpdateService do
throttle_protected_paths_enabled: 1,
throttle_protected_paths_period_in_seconds: 600,
throttle_protected_paths_requests_per_period: 100,
- protected_paths_raw: "/users/password\r\n/users/sign_in\r\n"
+ protected_paths_raw: "/users/password\r\n/users/sign_in\r\n",
+ protected_paths_for_get_request_raw: "/users/password\r\n/users/sign_up\r\n"
}
end
@@ -344,6 +345,7 @@ RSpec.describe ApplicationSettings::UpdateService do
expect(application_settings.throttle_protected_paths_period_in_seconds).to eq(600)
expect(application_settings.throttle_protected_paths_requests_per_period).to eq(100)
expect(application_settings.protected_paths).to eq(['/users/password', '/users/sign_in'])
+ expect(application_settings.protected_paths_for_get_request).to match_array(['/users/password', '/users/sign_up'])
end
end
diff --git a/spec/services/auto_merge/base_service_spec.rb b/spec/services/auto_merge/base_service_spec.rb
index d14470df9ee..be5b753f484 100644
--- a/spec/services/auto_merge/base_service_spec.rb
+++ b/spec/services/auto_merge/base_service_spec.rb
@@ -296,4 +296,9 @@ RSpec.describe AutoMerge::BaseService, feature_category: :code_review_workflow d
end
end
end
+
+ describe '#process' do
+ specify { expect(service).to respond_to :process }
+ specify { expect { service.process(nil) }.to raise_error NotImplementedError }
+ end
end
diff --git a/spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb b/spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb
deleted file mode 100644
index 9a74f5ca07a..00000000000
--- a/spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb
+++ /dev/null
@@ -1,176 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe BulkImports::CreatePipelineTrackersService, feature_category: :importers do
- describe '#execute!' do
- context 'when entity is group' do
- it 'creates trackers for group entity' do
- bulk_import = create(:bulk_import)
- entity = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import)
-
- described_class.new(entity).execute!
-
- expect(entity.trackers.to_a).to include(
- have_attributes(
- stage: 0, status_name: :created, relation: BulkImports::Groups::Pipelines::GroupPipeline.to_s
- ),
- have_attributes(
- stage: 1, status_name: :created, relation: BulkImports::Groups::Pipelines::GroupAttributesPipeline.to_s
- )
- )
- end
- end
-
- context 'when entity is project' do
- it 'creates trackers for project entity' do
- bulk_import = create(:bulk_import)
- entity = create(:bulk_import_entity, :project_entity, bulk_import: bulk_import)
-
- described_class.new(entity).execute!
-
- expect(entity.trackers.to_a).to include(
- have_attributes(
- stage: 0, status_name: :created, relation: BulkImports::Projects::Pipelines::ProjectPipeline.to_s
- ),
- have_attributes(
- stage: 1, status_name: :created, relation: BulkImports::Projects::Pipelines::RepositoryPipeline.to_s
- )
- )
- end
- end
-
- context 'when tracker configuration has a minimum version defined' do
- before do
- allow_next_instance_of(BulkImports::Groups::Stage) do |stage|
- allow(stage).to receive(:config).and_return(
- {
- pipeline1: { pipeline: 'PipelineClass1', stage: 0 },
- pipeline2: { pipeline: 'PipelineClass2', stage: 1, minimum_source_version: '14.10.0' },
- pipeline3: { pipeline: 'PipelineClass3', stage: 1, minimum_source_version: '15.0.0' },
- pipeline5: { pipeline: 'PipelineClass4', stage: 1, minimum_source_version: '15.1.0' },
- pipeline6: { pipeline: 'PipelineClass5', stage: 1, minimum_source_version: '16.0.0' }
- }
- )
- end
- end
-
- context 'when the source instance version is older than the tracker mininum version' do
- let_it_be(:bulk_import) { create(:bulk_import, source_version: '15.0.0') }
- let_it_be(:entity) { create(:bulk_import_entity, :group_entity, bulk_import: bulk_import) }
-
- it 'creates trackers as skipped if version requirement does not meet' do
- described_class.new(entity).execute!
-
- expect(entity.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }).to contain_exactly(
- [:created, 'PipelineClass1'],
- [:created, 'PipelineClass2'],
- [:created, 'PipelineClass3'],
- [:skipped, 'PipelineClass4'],
- [:skipped, 'PipelineClass5']
- )
- end
-
- it 'logs an info message for the skipped pipelines' do
- expect_next_instance_of(Gitlab::Import::Logger) do |logger|
- expect(logger).to receive(:info).with({
- message: 'Pipeline skipped as source instance version not compatible with pipeline',
- bulk_import_entity_id: entity.id,
- bulk_import_id: entity.bulk_import_id,
- bulk_import_entity_type: entity.source_type,
- source_full_path: entity.source_full_path,
- importer: 'gitlab_migration',
- pipeline_name: 'PipelineClass4',
- minimum_source_version: '15.1.0',
- maximum_source_version: nil,
- source_version: '15.0.0'
- })
-
- expect(logger).to receive(:info).with({
- message: 'Pipeline skipped as source instance version not compatible with pipeline',
- bulk_import_entity_id: entity.id,
- bulk_import_id: entity.bulk_import_id,
- bulk_import_entity_type: entity.source_type,
- source_full_path: entity.source_full_path,
- importer: 'gitlab_migration',
- pipeline_name: 'PipelineClass5',
- minimum_source_version: '16.0.0',
- maximum_source_version: nil,
- source_version: '15.0.0'
- })
- end
-
- described_class.new(entity).execute!
- end
- end
-
- context 'when the source instance version is undefined' do
- it 'creates trackers as created' do
- bulk_import = create(:bulk_import, source_version: nil)
- entity = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import)
-
- described_class.new(entity).execute!
-
- expect(entity.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }).to contain_exactly(
- [:created, 'PipelineClass1'],
- [:created, 'PipelineClass2'],
- [:created, 'PipelineClass3'],
- [:created, 'PipelineClass4'],
- [:created, 'PipelineClass5']
- )
- end
- end
- end
-
- context 'when tracker configuration has a maximum version defined' do
- before do
- allow_next_instance_of(BulkImports::Groups::Stage) do |stage|
- allow(stage).to receive(:config).and_return(
- {
- pipeline1: { pipeline: 'PipelineClass1', stage: 0 },
- pipeline2: { pipeline: 'PipelineClass2', stage: 1, maximum_source_version: '14.10.0' },
- pipeline3: { pipeline: 'PipelineClass3', stage: 1, maximum_source_version: '15.0.0' },
- pipeline5: { pipeline: 'PipelineClass4', stage: 1, maximum_source_version: '15.1.0' },
- pipeline6: { pipeline: 'PipelineClass5', stage: 1, maximum_source_version: '16.0.0' }
- }
- )
- end
- end
-
- context 'when the source instance version is older than the tracker maximum version' do
- it 'creates trackers as skipped if version requirement does not meet' do
- bulk_import = create(:bulk_import, source_version: '15.0.0')
- entity = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import)
-
- described_class.new(entity).execute!
-
- expect(entity.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }).to contain_exactly(
- [:created, 'PipelineClass1'],
- [:skipped, 'PipelineClass2'],
- [:created, 'PipelineClass3'],
- [:created, 'PipelineClass4'],
- [:created, 'PipelineClass5']
- )
- end
- end
-
- context 'when the source instance version is a patch version' do
- it 'creates trackers with the same status as the non-patch source version' do
- bulk_import_1 = create(:bulk_import, source_version: '15.0.1')
- entity_1 = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import_1)
-
- bulk_import_2 = create(:bulk_import, source_version: '15.0.0')
- entity_2 = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import_2)
-
- described_class.new(entity_1).execute!
- described_class.new(entity_2).execute!
-
- trackers_1 = entity_1.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }
- trackers_2 = entity_2.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }
-
- expect(trackers_1).to eq(trackers_2)
- end
- end
- end
- end
-end
diff --git a/spec/services/bulk_imports/create_service_spec.rb b/spec/services/bulk_imports/create_service_spec.rb
index 93feab97f44..20872623802 100644
--- a/spec/services/bulk_imports/create_service_spec.rb
+++ b/spec/services/bulk_imports/create_service_spec.rb
@@ -62,6 +62,24 @@ RSpec.describe BulkImports::CreateService, feature_category: :importers do
end
end
+ # response when authorize_admin_project in API endpoint fails
+ context 'when direct transfer status query returns a 403' do
+ it 'raises a ServiceResponse::Error' do
+ expect_next_instance_of(BulkImports::Clients::HTTP) do |client|
+ expect(client).to receive(:validate_instance_version!).and_return(true)
+ expect(client).to receive(:get)
+ .with("/groups/full%2Fpath%2Fto%2Fgroup1/export_relations/status")
+ .and_raise(BulkImports::NetworkError, '403 Forbidden')
+ end
+
+ result = subject.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result).to be_error
+ expect(result.message).to eq("403 Forbidden")
+ end
+ end
+
context 'when direct transfer setting query returns a 404' do
it 'raises a ServiceResponse::Error' do
stub_request(:get, 'http://gitlab.example/api/v4/version?private_token=token').to_return(status: 404)
@@ -313,7 +331,7 @@ RSpec.describe BulkImports::CreateService, feature_category: :importers do
"Source full path must have a relative path structure with " \
"no HTTP protocol characters, or leading or trailing forward slashes. " \
"Path segments must not start or end with a special character, and " \
- "must not contain consecutive special characters.")
+ "must not contain consecutive special characters")
end
describe '#user-role' do
@@ -470,7 +488,7 @@ RSpec.describe BulkImports::CreateService, feature_category: :importers do
context 'when the source_full_path contains only integer characters' do
let(:query_string) { BulkImports::Projects::Graphql::GetProjectQuery.new(context: nil).to_s }
let(:graphql_response) do
- double(original_hash: { 'data' => { 'project' => { 'id' => entity_source_id } } }) # rubocop:disable RSpec/VerifiedDoubles
+ double(original_hash: { 'data' => { 'project' => { 'id' => entity_source_id } } }) # rubocop:disable RSpec/VerifiedDoubles
end
let(:params) do
diff --git a/spec/services/bulk_imports/file_download_service_spec.rb b/spec/services/bulk_imports/file_download_service_spec.rb
index c035eabf767..2197b0b4fac 100644
--- a/spec/services/bulk_imports/file_download_service_spec.rb
+++ b/spec/services/bulk_imports/file_download_service_spec.rb
@@ -82,8 +82,20 @@ RSpec.describe BulkImports::FileDownloadService, feature_category: :importers do
context 'when content-type is not valid' do
let(:content_type) { 'invalid' }
+ let(:import_logger) { instance_double(Gitlab::Import::Logger) }
+
+ before do
+ allow(Gitlab::Import::Logger).to receive(:build).and_return(import_logger)
+ allow(import_logger).to receive(:warn)
+ end
+
+ it 'logs and raises an error' do
+ expect(import_logger).to receive(:warn).once.with(
+ message: 'Invalid content type',
+ response_headers: headers,
+ importer: 'gitlab_migration'
+ )
- it 'raises an error' do
expect { subject.execute }.to raise_error(described_class::ServiceError, 'Invalid content type')
end
end
diff --git a/spec/services/ci/components/fetch_service_spec.rb b/spec/services/ci/components/fetch_service_spec.rb
index 532098b3b20..21b7df19f4a 100644
--- a/spec/services/ci/components/fetch_service_spec.rb
+++ b/spec/services/ci/components/fetch_service_spec.rb
@@ -3,15 +3,35 @@
require 'spec_helper'
RSpec.describe Ci::Components::FetchService, feature_category: :pipeline_composition do
- let_it_be(:project) { create(:project, :repository, create_tag: 'v1.0') }
let_it_be(:user) { create(:user) }
let_it_be(:current_user) { user }
let_it_be(:current_host) { Gitlab.config.gitlab.host }
+ let_it_be(:content) do
+ <<~COMPONENT
+ job:
+ script: echo
+ COMPONENT
+ end
let(:service) do
described_class.new(address: address, current_user: current_user)
end
+ let_it_be(:project) do
+ project = create(
+ :project, :custom_repo,
+ files: {
+ 'template.yml' => content,
+ 'my-component/template.yml' => content,
+ 'my-dir/my-component/template.yml' => content
+ }
+ )
+
+ project.repository.add_tag(project.creator, 'v0.1', project.repository.commit.sha)
+
+ project
+ end
+
before do
project.add_developer(user)
end
@@ -22,19 +42,6 @@ RSpec.describe Ci::Components::FetchService, feature_category: :pipeline_composi
shared_examples 'an external component' do
shared_examples 'component address' do
context 'when content exists' do
- let(:sha) { project.commit(version).id }
-
- let(:content) do
- <<~COMPONENT
- job:
- script: echo
- COMPONENT
- end
-
- before do
- stub_project_blob(sha, component_yaml_path, content)
- end
-
it 'returns the content' do
expect(result).to be_success
expect(result.payload[:content]).to eq(content)
@@ -42,6 +49,8 @@ RSpec.describe Ci::Components::FetchService, feature_category: :pipeline_composi
end
context 'when content does not exist' do
+ let(:address) { "#{current_host}/#{component_path}@~version-does-not-exist" }
+
it 'returns an error' do
expect(result).to be_error
expect(result.reason).to eq(:content_not_found)
diff --git a/spec/services/ci/create_commit_status_service_spec.rb b/spec/services/ci/create_commit_status_service_spec.rb
new file mode 100644
index 00000000000..ec200e24c8f
--- /dev/null
+++ b/spec/services/ci/create_commit_status_service_spec.rb
@@ -0,0 +1,461 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::CreateCommitStatusService, :clean_gitlab_redis_cache, feature_category: :continuous_integration do
+ using RSpec::Parameterized::TableSyntax
+
+ subject(:response) { execute_service(params) }
+
+ let_it_be_with_refind(:project) { create(:project, :repository) }
+ let_it_be(:commit) { project.repository.commit }
+ let_it_be(:guest) { create_user(:guest) }
+ let_it_be(:reporter) { create_user(:reporter) }
+ let_it_be(:developer) { create_user(:developer) }
+
+ let(:user) { developer }
+ let(:sha) { commit.id }
+ let(:params) { { state: 'pending' } }
+ let(:job) { response.payload[:job] }
+
+ %w[pending running success failed canceled].each do |status|
+ context "for #{status}" do
+ let(:params) { { state: status } }
+
+ context 'when pipeline for sha does not exists' do
+ it 'creates commit status and sets pipeline iid' do
+ expect(response).to be_success
+ expect(job.sha).to eq(commit.id)
+ expect(job.status).to eq(status)
+ expect(job.name).to eq('default')
+ expect(job.ref).not_to be_empty
+ expect(job.target_url).to be_nil
+ expect(job.description).to be_nil
+ expect(job.pipeline_id).not_to be_nil
+
+ expect(CommitStatus.find(job.id)).to be_api_failure if status == 'failed'
+
+ expect(::Ci::Pipeline.last.iid).not_to be_nil
+ end
+ end
+ end
+ end
+
+ context 'when status transitions from pending' do
+ before do
+ execute_service(state: 'pending')
+ end
+
+ %w[running success failed canceled].each do |status|
+ context "for #{status}" do
+ let(:params) { { state: status } }
+
+ it "changes to #{status}" do
+ expect { response }
+ .to not_change { ::Ci::Pipeline.count }.from(1)
+ .and not_change { ::Ci::Stage.count }.from(1)
+ .and not_change { ::CommitStatus.count }.from(1)
+
+ expect(response).to be_success
+ expect(job.status).to eq(status)
+ end
+ end
+ end
+
+ context 'for invalid transition' do
+ let(:params) { { state: 'pending' } }
+
+ it 'returns bad request and error message' do
+ expect { response }
+ .to not_change { ::Ci::Pipeline.count }.from(1)
+ .and not_change { ::Ci::Stage.count }.from(1)
+ .and not_change { ::CommitStatus.count }.from(1)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:bad_request)
+ expect(response.message).to eq(
+ "Cannot transition status via :enqueue from :pending (Reason(s): Status cannot transition via \"enqueue\")"
+ )
+ end
+ end
+ end
+
+ context 'with all optional parameters' do
+ context 'when creating a commit status' do
+ let(:params) do
+ {
+ sha: sha,
+ state: 'success',
+ context: 'coverage',
+ ref: 'master',
+ description: 'test',
+ coverage: 80.0,
+ target_url: 'http://gitlab.com/status'
+ }
+ end
+
+ it 'creates commit status' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and change { ::CommitStatus.count }.by(1)
+
+ expect(response).to be_success
+ expect(job.sha).to eq(commit.id)
+ expect(job.status).to eq('success')
+ expect(job.name).to eq('coverage')
+ expect(job.ref).to eq('master')
+ expect(job.coverage).to eq(80.0)
+ expect(job.description).to eq('test')
+ expect(job.target_url).to eq('http://gitlab.com/status')
+ end
+
+ context 'when merge request exists for given branch' do
+ let!(:merge_request) do
+ create(:merge_request, source_project: project, source_branch: 'master', target_branch: 'develop')
+ end
+
+ it 'sets head pipeline' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and change { ::CommitStatus.count }.by(1)
+
+ expect(response).to be_success
+ expect(merge_request.reload.head_pipeline).not_to be_nil
+ end
+ end
+ end
+
+ context 'when updating a commit status' do
+ let(:parameters) do
+ {
+ state: 'success',
+ name: 'coverage',
+ ref: 'master'
+ }
+ end
+
+ let(:updatable_optional_attributes) do
+ {
+ description: 'new description',
+ coverage: 90.0
+ }
+ end
+
+ let(:params) { parameters.merge(updatable_optional_attributes) }
+
+ # creating the initial commit status
+ before do
+ execute_service(
+ sha: sha,
+ state: 'running',
+ context: 'coverage',
+ ref: 'master',
+ description: 'coverage test',
+ coverage: 10.0,
+ target_url: 'http://gitlab.com/status'
+ )
+ end
+
+ it 'updates a commit status' do
+ expect { response }
+ .to not_change { ::Ci::Pipeline.count }.from(1)
+ .and not_change { ::Ci::Stage.count }.from(1)
+ .and not_change { ::CommitStatus.count }.from(1)
+
+ expect(response).to be_success
+ expect(job.sha).to eq(commit.id)
+ expect(job.status).to eq('success')
+ expect(job.name).to eq('coverage')
+ expect(job.ref).to eq('master')
+ expect(job.coverage).to eq(90.0)
+ expect(job.description).to eq('new description')
+ expect(job.target_url).to eq('http://gitlab.com/status')
+ end
+
+ context 'when the `state` parameter is sent the same' do
+ let(:parameters) do
+ {
+ sha: sha,
+ state: 'running',
+ name: 'coverage',
+ ref: 'master'
+ }
+ end
+
+ it 'does not update the commit status' do
+ expect { response }
+ .to not_change { ::Ci::Pipeline.count }.from(1)
+ .and not_change { ::Ci::Stage.count }.from(1)
+ .and not_change { ::CommitStatus.count }.from(1)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:bad_request)
+ expect(response.message).to eq(
+ "Cannot transition status via :run from :running (Reason(s): Status cannot transition via \"run\")"
+ )
+
+ commit_status = project.commit_statuses.find_by!(name: 'coverage')
+
+ expect(commit_status.description).to eq('coverage test')
+ expect(commit_status.coverage).to eq(10.0)
+ end
+ end
+ end
+
+ context 'when a pipeline id is specified' do
+ let!(:first_pipeline) do
+ project.ci_pipelines.build(source: :push, sha: commit.id, ref: 'master', status: 'created').tap do |p|
+ p.ensure_project_iid! # Necessary to avoid cross-database modification error
+ p.save!
+ end
+ end
+
+ let!(:other_pipeline) do
+ project.ci_pipelines.build(source: :push, sha: commit.id, ref: 'master', status: 'created').tap do |p|
+ p.ensure_project_iid! # Necessary to avoid cross-database modification error
+ p.save!
+ end
+ end
+
+ let(:params) do
+ {
+ sha: sha,
+ pipeline_id: other_pipeline.id,
+ state: 'success',
+ ref: 'master'
+ }
+ end
+
+ it 'update the correct pipeline', :sidekiq_might_not_need_inline do
+ expect { response }
+ .to not_change { ::Ci::Pipeline.count }.from(2)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and change { ::CommitStatus.count }.by(1)
+
+ expect(first_pipeline.reload.status).to eq('created')
+ expect(other_pipeline.reload.status).to eq('success')
+ end
+ end
+ end
+
+ context 'when retrying a commit status' do
+ subject(:response) do
+ execute_service(state: 'failed', name: 'test', ref: 'master')
+
+ execute_service(state: 'success', name: 'test', ref: 'master')
+ end
+
+ it 'correctly posts a new commit status' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and change { ::CommitStatus.count }.by(2)
+
+ expect(response).to be_success
+ expect(job.sha).to eq(commit.id)
+ expect(job.status).to eq('success')
+ end
+
+ it 'retries the commit status', :sidekiq_might_not_need_inline do
+ response
+
+ expect(CommitStatus.count).to eq 2
+ expect(CommitStatus.first).to be_retried
+ expect(CommitStatus.last.pipeline).to be_success
+ end
+ end
+
+ context 'when status is invalid' do
+ let(:params) { { state: 'invalid' } }
+
+ it 'does not create commit status' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and not_change { ::CommitStatus.count }.from(0)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:bad_request)
+ expect(response.message).to eq('invalid state')
+ end
+ end
+
+ context 'when request without a state made' do
+ let(:params) { {} }
+
+ it 'does not create commit status' do
+ expect { response }
+ .to not_change { ::Ci::Pipeline.count }.from(0)
+ .and not_change { ::Ci::Stage.count }.from(0)
+ .and not_change { ::CommitStatus.count }.from(0)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:bad_request)
+ expect(response.message).to eq('State is required')
+ end
+ end
+
+ context 'when updating a protected ref' do
+ let(:params) { { state: 'running', ref: 'master' } }
+
+ before do
+ create(:protected_branch, project: project, name: 'master')
+ end
+
+ context 'with user as developer' do
+ let(:user) { developer }
+
+ it 'does not create commit status' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and not_change { ::Ci::Stage.count }.from(0)
+ .and not_change { ::CommitStatus.count }.from(0)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:forbidden)
+ expect(response.message).to eq('403 Forbidden')
+ end
+ end
+
+ context 'with user as maintainer' do
+ let(:user) { create_user(:maintainer) }
+
+ it 'creates commit status' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and change { ::CommitStatus.count }.by(1)
+
+ expect(response).to be_success
+ end
+ end
+ end
+
+ context 'when commit SHA is invalid' do
+ let(:sha) { 'invalid_sha' }
+ let(:params) { { state: 'running', sha: sha } }
+
+ it 'returns not found error' do
+ expect { response }
+ .to not_change { ::Ci::Pipeline.count }.from(0)
+ .and not_change { ::Ci::Stage.count }.from(0)
+ .and not_change { ::CommitStatus.count }.from(0)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:not_found)
+ expect(response.message).to eq('404 Commit Not Found')
+ end
+ end
+
+ context 'when target URL is an invalid address' do
+ let(:params) { { state: 'pending', target_url: 'invalid url' } }
+
+ it 'responds with bad request status and validation errors' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and not_change { ::CommitStatus.count }.from(0)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:bad_request)
+ expect(response.message[:target_url])
+ .to include 'is blocked: Only allowed schemes are http, https'
+ end
+ end
+
+ context 'when target URL is an unsupported scheme' do
+ let(:params) { { state: 'pending', target_url: 'git://example.com' } }
+
+ it 'responds with bad request status and validation errors' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and not_change { ::CommitStatus.count }.from(0)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:bad_request)
+ expect(response.message[:target_url])
+ .to include 'is blocked: Only allowed schemes are http, https'
+ end
+ end
+
+ context 'when trying to update a status of a different type' do
+ let!(:pipeline) { create(:ci_pipeline, project: project, sha: sha, ref: 'ref') }
+ let!(:ci_build) { create(:ci_build, pipeline: pipeline, name: 'test-job') }
+ let(:params) { { state: 'pending', name: 'test-job' } }
+
+ before do
+ execute_service(params)
+ end
+
+ it 'responds with bad request status and validation errors' do
+ expect { response }
+ .to not_change { ::Ci::Pipeline.count }.from(1)
+ .and not_change { ::Ci::Stage.count }.from(2)
+ .and not_change { ::CommitStatus.count }.from(1)
+
+ expect(response).to be_error
+ expect(response.http_status).to eq(:bad_request)
+ expect(response.message[:name])
+ .to include 'has already been taken'
+ end
+ end
+
+ context 'with partitions', :ci_partitionable do
+ let(:current_partition_id) { ci_testing_partition_id }
+ let(:params) { { state: 'running' } }
+
+ before do
+ allow(Ci::Pipeline)
+ .to receive(:current_partition_value) { current_partition_id }
+ end
+
+ it 'creates records in the current partition' do
+ expect { response }
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and change { ::CommitStatus.count }.by(1)
+
+ expect(response).to be_success
+
+ status = CommitStatus.find(job.id)
+
+ expect(status.partition_id).to eq(current_partition_id)
+ expect(status.pipeline.partition_id).to eq(current_partition_id)
+ end
+ end
+
+ context 'for race condition' do
+ let(:licenses_snyk_params) { { state: 'running', name: 'licenses', description: 'testing' } }
+ let(:security_snyk_params) { { state: 'running', name: 'security', description: 'testing' } }
+ let(:snyk_params_list) { [licenses_snyk_params, security_snyk_params] }
+
+ it 'creates one pipeline and two jobs (one for licenses, one for security)' do
+ expect do
+ snyk_params_list.map do |snyk_params|
+ Thread.new do
+ response = execute_service(snyk_params)
+ expect(response).to be_success
+ end
+ end.each(&:join)
+ end
+ .to change { ::Ci::Pipeline.count }.by(1)
+ .and change { ::Ci::Stage.count }.by(1)
+ .and change { ::CommitStatus.count }.by(2)
+ end
+ end
+
+ def create_user(access_level_trait)
+ user = create(:user)
+ create(:project_member, access_level_trait, user: user, project: project)
+ user
+ end
+
+ def execute_service(params = self.params)
+ described_class
+ .new(project, user, params)
+ .execute(optional_commit_status_params: params.slice(*%i[target_url description coverage]))
+ end
+end
diff --git a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
index e6bdb2a3fc6..07bc3aa28cf 100644
--- a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
+++ b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
@@ -21,6 +21,23 @@ RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_fl
create_gitlab_ci_yml(downstream_project, downstream_config)
end
+ it_behaves_like 'creating a pipeline with environment keyword' do
+ let(:execute_service) { service.execute(:push) }
+ let(:upstream_config) { config }
+ let(:expected_deployable_class) { Ci::Bridge }
+ let(:expected_deployment_status) { 'running' }
+ let(:expected_job_status) { 'running' }
+ let(:downstream_config) { YAML.dump({ deploy: { script: 'deploy' } }) }
+ let(:base_config) do
+ {
+ trigger: {
+ project: downstream_project.full_path,
+ strategy: 'depend'
+ }
+ }
+ end
+ end
+
context 'with resource group', :aggregate_failures do
let(:upstream_config) do
<<~YAML
diff --git a/spec/services/ci/create_pipeline_service/environment_spec.rb b/spec/services/ci/create_pipeline_service/environment_spec.rb
index 96e54af43cd..e900f4ba10c 100644
--- a/spec/services/ci/create_pipeline_service/environment_spec.rb
+++ b/spec/services/ci/create_pipeline_service/environment_spec.rb
@@ -14,6 +14,26 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
project.add_developer(developer)
end
+ it_behaves_like 'creating a pipeline with environment keyword' do
+ let!(:project) { create(:project, :repository) }
+ let(:execute_service) { service.execute(:push) }
+ let(:expected_deployable_class) { Ci::Build }
+ let(:expected_deployment_status) { 'created' }
+ let(:expected_job_status) { 'pending' }
+ let(:expected_tag_names) { %w[hello] }
+ let(:base_config) do
+ {
+ script: 'deploy',
+ tags: ['hello']
+ }
+ end
+
+ before do
+ project.add_developer(developer) # rubocop:disable RSpec/BeforeAllRoleAssignment
+ project.repository.create_file(developer, '.gitlab-ci.yml', config, branch_name: 'master', message: 'test')
+ end
+ end
+
describe '#execute' do
subject { service.execute(:push).payload }
@@ -104,6 +124,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
expect(pipeline).to be_created_successfully
expect(Environment.find_by_name('test/deploy/2')).to be_persisted
expect(pipeline.builds.size).to eq(1)
+ # Clearing cache of BatchLoader in `build.persisted_environment` for fetching fresh data.
+ BatchLoader::Executor.clear_current
expect(build.persisted_environment.name).to eq('test/deploy/2')
expect(build.name).to eq('deploy-review-app-2')
expect(build.environment).to eq('test/$CI_JOB_STAGE/2')
diff --git a/spec/services/ci/create_pipeline_service/logger_spec.rb b/spec/services/ci/create_pipeline_service/logger_spec.rb
index 6a1987fcc7c..6b4a1809d9a 100644
--- a/spec/services/ci/create_pipeline_service/logger_spec.rb
+++ b/spec/services/ci/create_pipeline_service/logger_spec.rb
@@ -139,74 +139,5 @@ RSpec.describe Ci::CreatePipelineService, # rubocop: disable RSpec/FilePath
expect(pipeline).to be_created_successfully
end
end
-
- describe 'pipeline includes count' do
- before do
- stub_const('Gitlab::Ci::Config::External::Context::TEMP_MAX_INCLUDES', 2)
- end
-
- context 'when the includes count exceeds the maximum' do
- before do
- allow_next_instance_of(Ci::Pipeline) do |pipeline|
- allow(pipeline).to receive(:config_metadata)
- .and_return({ includes: [{ file: 1 }, { file: 2 }, { file: 3 }] })
- end
- end
-
- it 'creates a log entry' do
- expect(Gitlab::AppJsonLogger)
- .to receive(:info)
- .with(a_hash_including({ 'pipeline_includes_count' => 3 }))
- .and_call_original
-
- expect(pipeline).to be_created_successfully
- end
- end
-
- context 'when the includes count does not exceed the maximum' do
- before do
- allow_next_instance_of(Ci::Pipeline) do |pipeline|
- allow(pipeline).to receive(:config_metadata)
- .and_return({ includes: [{ file: 1 }, { file: 2 }] })
- end
- end
-
- it 'does not create a log entry but it collects the data' do
- expect(Gitlab::AppJsonLogger).not_to receive(:info)
- expect(pipeline).to be_created_successfully
-
- expect(service.logger.observations_hash)
- .to match(a_hash_including({ 'pipeline_includes_count' => 2 }))
- end
- end
-
- context 'when the includes data is nil' do
- before do
- allow_next_instance_of(Ci::Pipeline) do |pipeline|
- allow(pipeline).to receive(:config_metadata)
- .and_return({})
- end
- end
-
- it 'does not create a log entry' do
- expect(Gitlab::AppJsonLogger).not_to receive(:info)
- expect(pipeline).to be_created_successfully
- end
- end
-
- context 'when the pipeline config_metadata is nil' do
- before do
- allow_next_instance_of(Ci::Pipeline) do |pipeline|
- allow(pipeline).to receive(:config_metadata)
- .and_return(nil)
- end
- end
-
- it 'does not create a log entry but it collects the data' do
- expect(Gitlab::AppJsonLogger).not_to receive(:info)
- expect(pipeline).to be_created_successfully
- end
- end
- end
end
end
diff --git a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
index e644273df9a..65180ac055f 100644
--- a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
+++ b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
@@ -20,7 +20,29 @@ RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_fl
before do
project.add_developer(user)
- stub_ci_pipeline_yaml_file(config)
+ end
+
+ it_behaves_like 'creating a pipeline with environment keyword' do
+ let!(:project) { create(:project, :repository) }
+ let(:execute_service) { service.execute(:push) }
+ let(:expected_deployable_class) { Ci::Bridge }
+ let(:expected_deployment_status) { 'running' }
+ let(:expected_job_status) { 'running' }
+ let(:child_config) { YAML.dump({ deploy: { script: 'deploy' } }) }
+ let(:base_config) do
+ {
+ trigger: {
+ include: [{ local: '.child.yml' }],
+ strategy: 'depend'
+ }
+ }
+ end
+
+ before do
+ project.add_developer(user)
+ project.repository.create_file(user, '.gitlab-ci.yml', config, branch_name: 'master', message: 'ok')
+ project.repository.create_file(user, '.child.yml', child_config, branch_name: 'master', message: 'ok')
+ end
end
shared_examples 'successful creation' do
@@ -67,6 +89,10 @@ RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_fl
YAML
end
+ before do
+ stub_ci_pipeline_yaml_file(config)
+ end
+
it_behaves_like 'successful creation' do
let(:expected_bridge_options) do
{
@@ -158,6 +184,10 @@ RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_fl
end
describe 'child pipeline triggers' do
+ before do
+ stub_ci_pipeline_yaml_file(config)
+ end
+
context 'when YAML is valid' do
let(:config) do
<<~YAML
diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb
index a81d1487fab..05fa3cfeba3 100644
--- a/spec/services/ci/create_pipeline_service/rules_spec.rb
+++ b/spec/services/ci/create_pipeline_service/rules_spec.rb
@@ -298,6 +298,46 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
end
+ context 'with CI_ENVIRONMENT_* predefined variables' do
+ let(:config) do
+ <<-EOY
+ deploy:
+ script: "deploy"
+ environment:
+ name: review/$CI_COMMIT_REF_NAME
+ deployment_tier: development
+ url: https://gitlab.com
+ rules:
+ - if: $CI_ENVIRONMENT_NAME =~ /^review\// && $CI_ENVIRONMENT_ACTION == "start" && $CI_ENVIRONMENT_TIER == "development" && $CI_ENVIRONMENT_URL == "https://gitlab.com"
+
+ teardown:
+ script: "teardown"
+ environment:
+ name: review/$CI_COMMIT_REF_NAME
+ deployment_tier: development
+ url: https://gitlab.com
+ action: stop
+ rules:
+ - if: $CI_ENVIRONMENT_NAME =~ /^review\// && $CI_ENVIRONMENT_ACTION == "stop" && $CI_ENVIRONMENT_TIER == "development" && $CI_ENVIRONMENT_URL == "https://gitlab.com"
+ when: manual
+ EOY
+ end
+
+ it 'assigns correct attributes to the jobs' do
+ expect(pipeline).to be_persisted
+
+ BatchLoader::Executor.clear_current
+
+ expect(build_names).to contain_exactly('deploy', 'teardown')
+ expect(find_job('deploy').when).to eq('on_success')
+ expect(find_job('teardown').when).to eq('manual')
+ expect(find_job('deploy').allow_failure).to eq(false)
+ expect(find_job('teardown').allow_failure).to eq(false)
+ expect(find_job('deploy').actual_persisted_environment.name).to eq('review/master')
+ expect(find_job('teardown').actual_persisted_environment.name).to eq('review/master')
+ end
+ end
+
context 'with simple if: clauses' do
let(:config) do
<<-EOY
diff --git a/spec/services/ci/create_pipeline_service/variables_spec.rb b/spec/services/ci/create_pipeline_service/variables_spec.rb
index aac9a0c9c2d..3039ffb2751 100644
--- a/spec/services/ci/create_pipeline_service/variables_spec.rb
+++ b/spec/services/ci/create_pipeline_service/variables_spec.rb
@@ -90,6 +90,39 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
)
end
end
+
+ context 'when trigger variables have CI_ENVIRONMENT_* predefined variables' do
+ let(:config) do
+ <<-YAML
+ child:
+ variables:
+ UPSTREAM_ENVIRONMENT_NAME: $CI_ENVIRONMENT_NAME
+ UPSTREAM_ENVIRONMENT_TIER: $CI_ENVIRONMENT_TIER
+ UPSTREAM_ENVIRONMENT_URL: $CI_ENVIRONMENT_URL
+ UPSTREAM_ENVIRONMENT_ACTION: $CI_ENVIRONMENT_ACTION
+ environment:
+ name: review/$CI_COMMIT_REF_NAME
+ deployment_tier: testing
+ url: https://gitlab.com
+ action: start
+ trigger:
+ include: child.yml
+ YAML
+ end
+
+ let(:child) { find_job('child') }
+
+ it 'creates the pipeline with a trigger job that has downstream_variables' do
+ expect(pipeline).to be_created_successfully
+
+ expect(child.downstream_variables).to include(
+ { key: 'UPSTREAM_ENVIRONMENT_NAME', value: 'review/master' },
+ { key: 'UPSTREAM_ENVIRONMENT_TIER', value: 'testing' },
+ { key: 'UPSTREAM_ENVIRONMENT_URL', value: 'https://gitlab.com' },
+ { key: 'UPSTREAM_ENVIRONMENT_ACTION', value: 'start' }
+ )
+ end
+ end
end
private
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index a28ede89cee..a28dd9e7a55 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -748,131 +748,6 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
end
- context 'with environment' do
- before do
- config = YAML.dump(
- deploy: {
- environment: { name: "review/$CI_COMMIT_REF_NAME" },
- script: 'ls',
- tags: ['hello']
- })
-
- stub_ci_pipeline_yaml_file(config)
- end
-
- it 'creates the environment with tags', :sidekiq_inline do
- result = execute_service.payload
-
- expect(result).to be_persisted
- expect(Environment.find_by(name: "review/master")).to be_present
- expect(result.builds.first.tag_list).to contain_exactly('hello')
- expect(result.builds.first.deployment).to be_persisted
- expect(result.builds.first.deployment.deployable).to be_a(Ci::Build)
- end
- end
-
- context 'with environment with auto_stop_in' do
- before do
- config = YAML.dump(
- deploy: {
- environment: { name: "review/$CI_COMMIT_REF_NAME", auto_stop_in: '1 day' },
- script: 'ls'
- })
-
- stub_ci_pipeline_yaml_file(config)
- end
-
- it 'creates the environment with auto stop in' do
- result = execute_service.payload
-
- expect(result).to be_persisted
- expect(result.builds.first.options[:environment][:auto_stop_in]).to eq('1 day')
- end
- end
-
- context 'with environment name including persisted variables' do
- before do
- config = YAML.dump(
- deploy: {
- environment: { name: "review/id1$CI_PIPELINE_ID/id2$CI_JOB_ID" },
- script: 'ls'
- }
- )
-
- stub_ci_pipeline_yaml_file(config)
- end
-
- it 'skips persisted variables in environment name' do
- result = execute_service.payload
-
- expect(result).to be_persisted
- expect(Environment.find_by(name: "review/id1/id2")).to be_present
- end
- end
-
- context 'environment with Kubernetes configuration' do
- let(:kubernetes_namespace) { 'custom-namespace' }
-
- before do
- config = YAML.dump(
- deploy: {
- environment: {
- name: "environment-name",
- kubernetes: { namespace: kubernetes_namespace }
- },
- script: 'ls'
- }
- )
-
- stub_ci_pipeline_yaml_file(config)
- end
-
- it 'stores the requested namespace' do
- result = execute_service.payload
- build = result.builds.first
-
- expect(result).to be_persisted
- expect(build.options.dig(:environment, :kubernetes, :namespace)).to eq(kubernetes_namespace)
- end
- end
-
- context 'when environment with invalid name' do
- before do
- config = YAML.dump(deploy: { environment: { name: 'name,with,commas' }, script: 'ls' })
- stub_ci_pipeline_yaml_file(config)
- end
-
- it 'does not create an environment' do
- expect do
- result = execute_service.payload
-
- expect(result).to be_persisted
- end.not_to change { Environment.count }
- end
- end
-
- context 'when environment with duplicate names' do
- let(:ci_yaml) do
- {
- deploy: { environment: { name: 'production' }, script: 'ls' },
- deploy_2: { environment: { name: 'production' }, script: 'ls' }
- }
- end
-
- before do
- stub_ci_pipeline_yaml_file(YAML.dump(ci_yaml))
- end
-
- it 'creates a pipeline with the environment', :sidekiq_inline do
- result = execute_service.payload
-
- expect(result).to be_persisted
- expect(Environment.find_by(name: 'production')).to be_present
- expect(result.builds.first.deployment).to be_persisted
- expect(result.builds.first.deployment.deployable).to be_a(Ci::Build)
- end
- end
-
context 'when builds with auto-retries are configured' do
let(:pipeline) { execute_service.payload }
let(:rspec_job) { pipeline.builds.find_by(name: 'rspec') }
@@ -1294,55 +1169,6 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
end
- context 'when pipeline has a job with environment' do
- let(:pipeline) { execute_service.payload }
-
- before do
- stub_ci_pipeline_yaml_file(YAML.dump(config))
- end
-
- context 'when environment name is valid' do
- let(:config) do
- {
- review_app: {
- script: 'deploy',
- environment: {
- name: 'review/${CI_COMMIT_REF_NAME}',
- url: 'http://${CI_COMMIT_REF_SLUG}-staging.example.com'
- }
- }
- }
- end
-
- it 'has a job with environment', :sidekiq_inline do
- expect(pipeline.builds.count).to eq(1)
- expect(pipeline.builds.first.persisted_environment.name).to eq('review/master')
- expect(pipeline.builds.first.persisted_environment.name).to eq('review/master')
- expect(pipeline.builds.first.deployment).to be_created
- end
- end
-
- context 'when environment name is invalid' do
- let(:config) do
- {
- 'job:deploy-to-test-site': {
- script: 'deploy',
- environment: {
- name: '${CI_JOB_NAME}',
- url: 'https://$APP_URL'
- }
- }
- }
- end
-
- it 'has a job without environment' do
- expect(pipeline.builds.count).to eq(1)
- expect(pipeline.builds.first.persisted_environment).to be_nil
- expect(pipeline.builds.first.deployment).to be_nil
- end
- end
- end
-
describe 'Pipeline for external pull requests' do
let(:response) do
execute_service(
diff --git a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
index 82a8e425cd0..fffac0fd64b 100644
--- a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
+++ b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
@@ -35,20 +35,6 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca
expect(build_statuses(pipeline)).to contain_exactly('pending')
expect(build_statuses(old_pipeline)).to contain_exactly('pending')
end
-
- context 'with lower_interval_for_canceling_redundant_pipelines disabled' do
- before do
- stub_feature_flags(lower_interval_for_canceling_redundant_pipelines: false)
- end
-
- it 'cancels pipelines created more than 3 days ago' do
- execute
-
- expect(build_statuses(prev_pipeline)).to contain_exactly('canceled', 'success', 'canceled')
- expect(build_statuses(pipeline)).to contain_exactly('pending')
- expect(build_statuses(old_pipeline)).to contain_exactly('canceled')
- end
- end
end
end
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 61fec82c688..83bae16a30e 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -26,7 +26,9 @@ module Ci
end
it 'result is valid if replica did caught-up', :aggregate_failures do
- expect(ApplicationRecord.sticking).to receive(:all_caught_up?).with(:runner, runner.id) { true }
+ expect(ApplicationRecord.sticking).to receive(:find_caught_up_replica)
+ .with(:runner, runner.id, use_primary_on_failure: false)
+ .and_return(true)
expect { execute }.not_to change { Ci::RunnerManagerBuild.count }.from(0)
expect(execute).to be_valid
@@ -35,8 +37,9 @@ module Ci
end
it 'result is invalid if replica did not caught-up', :aggregate_failures do
- expect(ApplicationRecord.sticking).to receive(:all_caught_up?)
- .with(:runner, shared_runner.id) { false }
+ expect(ApplicationRecord.sticking).to receive(:find_caught_up_replica)
+ .with(:runner, shared_runner.id, use_primary_on_failure: false)
+ .and_return(false)
expect(subject).not_to be_valid
expect(subject.build).to be_nil
@@ -948,8 +951,8 @@ module Ci
let(:runner) { create(:ci_runner, :instance, tag_list: %w(tag1 tag2)) }
let(:expected_shared_runner) { true }
let(:expected_shard) { ::Gitlab::Ci::Queue::Metrics::DEFAULT_METRICS_SHARD }
- let(:expected_jobs_running_for_project_first_job) { 0 }
- let(:expected_jobs_running_for_project_third_job) { 2 }
+ let(:expected_jobs_running_for_project_first_job) { '0' }
+ let(:expected_jobs_running_for_project_third_job) { '2' }
it_behaves_like 'metrics collector'
@@ -969,7 +972,7 @@ module Ci
context 'when max running jobs bucket size is exceeded' do
before do
- stub_const('Gitlab::Ci::Queue::Metrics::JOBS_RUNNING_FOR_PROJECT_MAX_BUCKET', 1)
+ stub_const('Project::INSTANCE_RUNNER_RUNNING_JOBS_MAX_BUCKET', 1)
end
let(:expected_jobs_running_for_project_third_job) { '1+' }
diff --git a/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb b/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
index d952fca25a5..8d612174a0b 100644
--- a/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
+++ b/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
@@ -97,7 +97,7 @@ RSpec.describe ::Ci::Runners::SetRunnerAssociatedProjectsService, '#execute', fe
end
expect(execute).to be_error
- expect(runner.reload.projects).to eq(original_projects)
+ expect(runner.reload.projects.order(:id)).to eq(original_projects)
end
end
@@ -117,7 +117,7 @@ RSpec.describe ::Ci::Runners::SetRunnerAssociatedProjectsService, '#execute', fe
it 'returns error response and rolls back transaction' do
expect(execute).to be_error
expect(execute.errors).to contain_exactly('user is not authorized to add runners to project')
- expect(runner.reload.projects).to eq(original_projects)
+ expect(runner.reload.projects.order(:id)).to eq(original_projects)
end
end
end
diff --git a/spec/services/concerns/rate_limited_service_spec.rb b/spec/services/concerns/rate_limited_service_spec.rb
index 2172c756ecf..2cfc6692f23 100644
--- a/spec/services/concerns/rate_limited_service_spec.rb
+++ b/spec/services/concerns/rate_limited_service_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe RateLimitedService, feature_category: :rate_limiting do
let(:key) { :issues_create }
let(:scope) { [:container, :current_user] }
- let(:opts) { { scope: scope, users_allowlist: -> { [User.support_bot.username] } } }
+ let(:opts) { { scope: scope, users_allowlist: -> { [Users::Internal.support_bot.username] } } }
let(:rate_limiter) { ::Gitlab::ApplicationRateLimiter }
describe 'RateLimitedError' do
diff --git a/spec/services/concerns/services/return_service_responses_spec.rb b/spec/services/concerns/services/return_service_responses_spec.rb
new file mode 100644
index 00000000000..3589b952e87
--- /dev/null
+++ b/spec/services/concerns/services/return_service_responses_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Services::ReturnServiceResponses, feature_category: :rate_limiting do
+ subject(:object) { Class.new { include Services::ReturnServiceResponses }.new }
+
+ let(:message) { 'a delivering message' }
+ let(:payload) { 'string payload' }
+
+ describe '#success' do
+ it 'returns a ServiceResponse instance' do
+ response = object.success(payload)
+ expect(response).to be_an(ServiceResponse)
+ expect(response).to be_success
+ expect(response.message).to be_nil
+ expect(response.payload).to eq(payload)
+ expect(response.http_status).to eq(:ok)
+ end
+ end
+
+ describe '#error' do
+ it 'returns a ServiceResponse instance' do
+ response = object.error(message, :not_found, pass_back: payload)
+ expect(response).to be_an(ServiceResponse)
+ expect(response).to be_error
+ expect(response.message).to eq(message)
+ expect(response.payload).to eq(payload)
+ expect(response.http_status).to eq(:not_found)
+ end
+ end
+end
diff --git a/spec/services/deployments/update_environment_service_spec.rb b/spec/services/deployments/update_environment_service_spec.rb
index 0a93e300eb6..79bf0d972d4 100644
--- a/spec/services/deployments/update_environment_service_spec.rb
+++ b/spec/services/deployments/update_environment_service_spec.rb
@@ -79,6 +79,27 @@ RSpec.describe Deployments::UpdateEnvironmentService, feature_category: :continu
expect(subject.execute).to eq(deployment)
end
+ context 'when deployable is bridge job' do
+ let(:job) do
+ create(:ci_bridge,
+ :with_deployment,
+ pipeline: pipeline,
+ ref: 'master',
+ tag: false,
+ environment: environment_name,
+ options: { environment: options },
+ project: project)
+ end
+
+ it 'creates ref' do
+ expect_any_instance_of(Repository)
+ .to receive(:create_ref)
+ .with(deployment.sha, "refs/environments/production/deployments/#{deployment.iid}")
+
+ service.execute
+ end
+ end
+
context 'when start action is defined' do
let(:options) { { name: 'production', action: 'start' } }
diff --git a/spec/services/design_management/delete_designs_service_spec.rb b/spec/services/design_management/delete_designs_service_spec.rb
index 22570a14443..b6a80cf26cc 100644
--- a/spec/services/design_management/delete_designs_service_spec.rb
+++ b/spec/services/design_management/delete_designs_service_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe DesignManagement::DeleteDesignsService, feature_category: :design
subject(:service) { described_class.new(project, user, issue: issue, designs: designs) }
- # Defined as a method so that the reponse is not cached. We also construct
+ # Defined as a method so that the response is not cached. We also construct
# a new service executor each time to avoid the intermediate cached values
# it constructs during its execution.
def run_service(delenda = nil)
@@ -173,8 +173,10 @@ RSpec.describe DesignManagement::DeleteDesignsService, feature_category: :design
run_service
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DESIGNS_REMOVED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DESIGNS_REMOVED }
+ let(:namespace) { project.namespace }
+
subject(:service_action) { run_service }
end
end
diff --git a/spec/services/design_management/save_designs_service_spec.rb b/spec/services/design_management/save_designs_service_spec.rb
index ea53fcc3b12..8e5065184ca 100644
--- a/spec/services/design_management/save_designs_service_spec.rb
+++ b/spec/services/design_management/save_designs_service_spec.rb
@@ -11,9 +11,7 @@ RSpec.describe DesignManagement::SaveDesignsService, feature_category: :design_m
let(:project) { issue.project }
let(:user) { developer }
let(:files) { [rails_sample] }
- let(:design_repository) do
- ::Gitlab::GlRepository::DESIGN.repository_resolver.call(project)
- end
+ let(:design_repository) { project.find_or_create_design_management_repository.repository }
let(:rails_sample_name) { 'rails_sample.jpg' }
let(:rails_sample) { sample_image(rails_sample_name) }
@@ -43,9 +41,7 @@ RSpec.describe DesignManagement::SaveDesignsService, feature_category: :design_m
design_files = files_to_upload || files
design_files.each(&:rewind)
- service = described_class.new(project, user,
- issue: issue,
- files: design_files)
+ service = described_class.new(project, user, issue: issue, files: design_files)
service.execute
end
@@ -123,8 +119,9 @@ RSpec.describe DesignManagement::SaveDesignsService, feature_category: :design_m
)
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DESIGNS_ADDED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DESIGNS_ADDED }
+ let(:namespace) { project.namespace }
subject(:service_action) { run_service }
end
@@ -221,8 +218,9 @@ RSpec.describe DesignManagement::SaveDesignsService, feature_category: :design_m
run_service
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DESIGNS_MODIFIED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DESIGNS_MODIFIED }
+ let(:namespace) { project.namespace }
subject(:service_action) { run_service }
end
@@ -390,9 +388,12 @@ RSpec.describe DesignManagement::SaveDesignsService, feature_category: :design_m
before do
path = File.join(build(:design, issue: issue, filename: filename).full_path)
design_repository.create_if_not_exists
- design_repository.create_file(user, path, 'something fake',
- branch_name: project.default_branch_or_main,
- message: 'Somehow created without being tracked in db')
+ design_repository.create_file(
+ user,
+ path, 'something fake',
+ branch_name: project.default_branch_or_main,
+ message: 'Somehow created without being tracked in db'
+ )
end
it 'creates the design and a new version for it' do
diff --git a/spec/services/discussions/resolve_service_spec.rb b/spec/services/discussions/resolve_service_spec.rb
index a6e1bad30ce..88ef390bb02 100644
--- a/spec/services/discussions/resolve_service_spec.rb
+++ b/spec/services/discussions/resolve_service_spec.rb
@@ -94,9 +94,11 @@ RSpec.describe Discussions::ResolveService, feature_category: :code_review_workf
it 'raises an argument error if discussions do not belong to the same noteable' do
other_merge_request = create(:merge_request)
- other_discussion = create(:diff_note_on_merge_request,
- noteable: other_merge_request,
- project: other_merge_request.source_project).to_discussion
+ other_discussion = create(
+ :diff_note_on_merge_request,
+ noteable: other_merge_request,
+ project: other_merge_request.source_project
+ ).to_discussion
expect do
described_class.new(project, user, one_or_more_discussions: [discussion, other_discussion])
end.to raise_error(
diff --git a/spec/services/draft_notes/publish_service_spec.rb b/spec/services/draft_notes/publish_service_spec.rb
index dab06637c1a..48959baeaa5 100644
--- a/spec/services/draft_notes/publish_service_spec.rb
+++ b/spec/services/draft_notes/publish_service_spec.rb
@@ -292,9 +292,12 @@ RSpec.describe DraftNotes::PublishService, feature_category: :code_review_workfl
other_user = create(:user)
project.add_developer(other_user)
- create(:draft_note, merge_request: merge_request,
- author: user,
- note: "thanks\n/assign #{other_user.to_reference}")
+ create(
+ :draft_note,
+ merge_request: merge_request,
+ author: user,
+ note: "thanks\n/assign #{other_user.to_reference}"
+ )
expect { publish }.to change { DraftNote.count }.by(-1).and change { Note.count }.by(2)
expect(merge_request.reload.assignees).to match_array([other_user])
diff --git a/spec/services/environments/stop_service_spec.rb b/spec/services/environments/stop_service_spec.rb
index 6e3b36b5636..04116c5238f 100644
--- a/spec/services/environments/stop_service_spec.rb
+++ b/spec/services/environments/stop_service_spec.rb
@@ -135,8 +135,7 @@ RSpec.describe Environments::StopService, feature_category: :continuous_delivery
context 'when branch for stop action is protected' do
before do
project.add_developer(user)
- create(:protected_branch, :no_one_can_push,
- name: 'master', project: project)
+ create(:protected_branch, :no_one_can_push, name: 'master', project: project)
end
it 'does not stop environment' do
diff --git a/spec/services/environments/stop_stale_service_spec.rb b/spec/services/environments/stop_stale_service_spec.rb
index 46d770c30cc..0aa5659f81d 100644
--- a/spec/services/environments/stop_stale_service_spec.rb
+++ b/spec/services/environments/stop_stale_service_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe Environments::StopStaleService,
- :clean_gitlab_redis_shared_state,
- :sidekiq_inline,
- feature_category: :continuous_delivery do
+ :clean_gitlab_redis_shared_state,
+ :sidekiq_inline,
+ feature_category: :continuous_delivery do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
diff --git a/spec/services/files/delete_service_spec.rb b/spec/services/files/delete_service_spec.rb
index dd99e5f9742..982e1bda5ac 100644
--- a/spec/services/files/delete_service_spec.rb
+++ b/spec/services/files/delete_service_spec.rb
@@ -56,9 +56,10 @@ RSpec.describe Files::DeleteService, feature_category: :source_code_management d
let(:last_commit_sha) { Gitlab::Git::Commit.last_for_path(project.repository, project.default_branch, file_path).parent_id }
it "returns a hash with the correct error message and a :error status" do
- expect { subject.execute }
- .to raise_error(Files::UpdateService::FileChangedError,
- "You are attempting to delete a file that has been previously updated.")
+ expect { subject.execute }.to raise_error(
+ Files::UpdateService::FileChangedError,
+ "You are attempting to delete a file that has been previously updated."
+ )
end
end
diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb
index 6a9f9d6b86f..be424d5cb0d 100644
--- a/spec/services/files/update_service_spec.rb
+++ b/spec/services/files/update_service_spec.rb
@@ -36,8 +36,10 @@ RSpec.describe Files::UpdateService, feature_category: :source_code_management d
it "returns a hash with the correct error message and a :error status" do
expect { subject.execute }
- .to raise_error(Files::UpdateService::FileChangedError,
- "You are attempting to update a file that has changed since you started editing it.")
+ .to raise_error(
+ Files::UpdateService::FileChangedError,
+ "You are attempting to update a file that has changed since you started editing it."
+ )
end
end
diff --git a/spec/services/git/branch_push_service_spec.rb b/spec/services/git/branch_push_service_spec.rb
index 5e43426b9dd..74f1f4bc7ac 100644
--- a/spec/services/git/branch_push_service_spec.rb
+++ b/spec/services/git/branch_push_service_spec.rb
@@ -81,18 +81,18 @@ RSpec.describe Git::BranchPushService, :use_clean_rails_redis_caching, services:
end
it 'creates a pipeline with the right parameters' do
- expect(Ci::CreatePipelineService)
- .to receive(:new)
- .with(project,
- user,
- {
- before: oldrev,
- after: newrev,
- ref: ref,
- checkout_sha: SeedRepo::Commit::ID,
- variables_attributes: [],
- push_options: {}
- }).and_call_original
+ expect(Ci::CreatePipelineService).to receive(:new).with(
+ project,
+ user,
+ {
+ before: oldrev,
+ after: newrev,
+ ref: ref,
+ checkout_sha: SeedRepo::Commit::ID,
+ variables_attributes: [],
+ push_options: {}
+ }
+ ).and_call_original
subject
end
diff --git a/spec/services/google_cloud/create_cloudsql_instance_service_spec.rb b/spec/services/google_cloud/create_cloudsql_instance_service_spec.rb
index 4f2e0bea623..c31e76170d5 100644
--- a/spec/services/google_cloud/create_cloudsql_instance_service_spec.rb
+++ b/spec/services/google_cloud/create_cloudsql_instance_service_spec.rb
@@ -28,13 +28,14 @@ RSpec.describe GoogleCloud::CreateCloudsqlInstanceService, feature_category: :de
it 'triggers creation of a cloudsql instance' do
expect_next_instance_of(GoogleApi::CloudPlatform::Client) do |client|
expected_instance_name = "gitlab-#{project.id}-postgres-8000-test-env-42"
- expect(client).to receive(:create_cloudsql_instance)
- .with(gcp_project_id,
- expected_instance_name,
- String,
- database_version,
- 'us-east1',
- tier)
+ expect(client).to receive(:create_cloudsql_instance).with(
+ gcp_project_id,
+ expected_instance_name,
+ String,
+ database_version,
+ 'us-east1',
+ tier
+ )
end
result = service.execute
@@ -74,13 +75,14 @@ RSpec.describe GoogleCloud::CreateCloudsqlInstanceService, feature_category: :de
it 'uses defined region' do
expect_next_instance_of(GoogleApi::CloudPlatform::Client) do |client|
- expect(client).to receive(:create_cloudsql_instance)
- .with(gcp_project_id,
- String,
- String,
- database_version,
- 'user-defined-region',
- tier)
+ expect(client).to receive(:create_cloudsql_instance).with(
+ gcp_project_id,
+ String,
+ String,
+ database_version,
+ 'user-defined-region',
+ tier
+ )
end
service.execute
diff --git a/spec/services/google_cloud/fetch_google_ip_list_service_spec.rb b/spec/services/google_cloud/fetch_google_ip_list_service_spec.rb
index e5f06824b9f..f8d5ba99bf6 100644
--- a/spec/services/google_cloud/fetch_google_ip_list_service_spec.rb
+++ b/spec/services/google_cloud/fetch_google_ip_list_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe GoogleCloud::FetchGoogleIpListService, :use_clean_rails_memory_store_caching,
-:clean_gitlab_redis_rate_limiting, feature_category: :build_artifacts do
+ :clean_gitlab_redis_rate_limiting, feature_category: :build_artifacts do
include StubRequests
let(:google_cloud_ips) { File.read(Rails.root.join('spec/fixtures/cdn/google_cloud.json')) }
diff --git a/spec/services/google_cloud/generate_pipeline_service_spec.rb b/spec/services/google_cloud/generate_pipeline_service_spec.rb
index b363b7b17b6..26a1ccb7e3b 100644
--- a/spec/services/google_cloud/generate_pipeline_service_spec.rb
+++ b/spec/services/google_cloud/generate_pipeline_service_spec.rb
@@ -84,11 +84,13 @@ test-java:
stage: test
script: mvn clean test
EOF
- project.repository.create_file(maintainer,
- file_name,
- file_content,
- message: 'Pipeline with three stages and two jobs',
- branch_name: project.default_branch)
+ project.repository.create_file(
+ maintainer,
+ file_name,
+ file_content,
+ message: 'Pipeline with three stages and two jobs',
+ branch_name: project.default_branch
+ )
end
it 'introduces a `deploy` stage and includes the deploy-to-cloud-run job' do
@@ -138,11 +140,13 @@ test-java:
stage: test
script: mvn clean test
EOF
- project.repository.create_file(maintainer,
- file_name,
- file_content,
- message: 'Pipeline with three stages and two jobs',
- branch_name: project.default_branch)
+ project.repository.create_file(
+ maintainer,
+ file_name,
+ file_content,
+ message: 'Pipeline with three stages and two jobs',
+ branch_name: project.default_branch
+ )
end
it 'includes the deploy-to-cloud-run job' do
@@ -178,11 +182,13 @@ stages:
include:
local: 'some-pipeline.yml'
EOF
- project.repository.create_file(maintainer,
- file_name,
- file_content,
- message: 'Pipeline with three stages and two jobs',
- branch_name: project.default_branch)
+ project.repository.create_file(
+ maintainer,
+ file_name,
+ file_content,
+ message: 'Pipeline with three stages and two jobs',
+ branch_name: project.default_branch
+ )
end
it 'includes the deploy-to-cloud-run job' do
@@ -309,11 +315,13 @@ stages:
include:
local: 'some-pipeline.yml'
EOF
- project.repository.create_file(maintainer,
- file_name,
- file_content,
- message: 'Pipeline with three stages and two jobs',
- branch_name: project.default_branch)
+ project.repository.create_file(
+ maintainer,
+ file_name,
+ file_content,
+ message: 'Pipeline with three stages and two jobs',
+ branch_name: project.default_branch
+ )
end
it 'includes the vision ai pipeline' do
diff --git a/spec/services/google_cloud/get_cloudsql_instances_service_spec.rb b/spec/services/google_cloud/get_cloudsql_instances_service_spec.rb
index ed41d0fd487..cd2ad00ac3f 100644
--- a/spec/services/google_cloud/get_cloudsql_instances_service_spec.rb
+++ b/spec/services/google_cloud/get_cloudsql_instances_service_spec.rb
@@ -39,24 +39,26 @@ RSpec.describe GoogleCloud::GetCloudsqlInstancesService, feature_category: :depl
end
it 'result is grouped by environment', :aggregate_failures do
- expect(service.execute).to contain_exactly({
- ref: '*',
- gcp_project: 'value-GCP_PROJECT_ID-*',
- instance_name: 'value-GCP_CLOUDSQL_INSTANCE_NAME-*',
- version: 'value-GCP_CLOUDSQL_VERSION-*'
- },
- {
- ref: 'STG',
- gcp_project: 'value-GCP_PROJECT_ID-STG',
- instance_name: 'value-GCP_CLOUDSQL_INSTANCE_NAME-STG',
- version: 'value-GCP_CLOUDSQL_VERSION-STG'
- },
- {
- ref: 'PRD',
- gcp_project: 'value-GCP_PROJECT_ID-PRD',
- instance_name: 'value-GCP_CLOUDSQL_INSTANCE_NAME-PRD',
- version: 'value-GCP_CLOUDSQL_VERSION-PRD'
- })
+ expect(service.execute).to contain_exactly(
+ {
+ ref: '*',
+ gcp_project: 'value-GCP_PROJECT_ID-*',
+ instance_name: 'value-GCP_CLOUDSQL_INSTANCE_NAME-*',
+ version: 'value-GCP_CLOUDSQL_VERSION-*'
+ },
+ {
+ ref: 'STG',
+ gcp_project: 'value-GCP_PROJECT_ID-STG',
+ instance_name: 'value-GCP_CLOUDSQL_INSTANCE_NAME-STG',
+ version: 'value-GCP_CLOUDSQL_VERSION-STG'
+ },
+ {
+ ref: 'PRD',
+ gcp_project: 'value-GCP_PROJECT_ID-PRD',
+ instance_name: 'value-GCP_CLOUDSQL_INSTANCE_NAME-PRD',
+ version: 'value-GCP_CLOUDSQL_VERSION-PRD'
+ }
+ )
end
end
end
diff --git a/spec/services/gpg_keys/destroy_service_spec.rb b/spec/services/gpg_keys/destroy_service_spec.rb
index b9aa3e351c9..85c1fc2893b 100644
--- a/spec/services/gpg_keys/destroy_service_spec.rb
+++ b/spec/services/gpg_keys/destroy_service_spec.rb
@@ -2,14 +2,28 @@
require 'spec_helper'
-RSpec.describe GpgKeys::DestroyService do
- let(:user) { create(:user) }
+RSpec.describe GpgKeys::DestroyService, feature_category: :source_code_management do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:gpg_key) { create(:gpg_key) }
subject { described_class.new(user) }
it 'destroys the GPG key' do
- gpg_key = create(:gpg_key)
-
expect { subject.execute(gpg_key) }.to change(GpgKey, :count).by(-1)
end
+
+ it 'nullifies the related signatures in batches' do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+
+ first_signature = create(:gpg_signature, gpg_key: gpg_key)
+ second_signature = create(:gpg_signature, gpg_key: gpg_key)
+ third_signature = create(:gpg_signature, gpg_key: create(:another_gpg_key))
+
+ control = ActiveRecord::QueryRecorder.new { subject.execute(gpg_key) }
+ expect(control.count).to eq(5)
+
+ expect(first_signature.reload.gpg_key).to be_nil
+ expect(second_signature.reload.gpg_key).to be_nil
+ expect(third_signature.reload.gpg_key).not_to be_nil
+ end
end
diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb
index 929f7d5b4e3..ebdce07d03c 100644
--- a/spec/services/groups/destroy_service_spec.rb
+++ b/spec/services/groups/destroy_service_spec.rb
@@ -44,8 +44,7 @@ RSpec.describe Groups::DestroyService, feature_category: :groups_and_projects do
destroy_group(group, user, async)
expect(
- Users::GhostUserMigration.where(user: bot,
- initiator_user: user)
+ Users::GhostUserMigration.where(user: bot, initiator_user: user)
).to be_exists
end
end
@@ -70,10 +69,6 @@ RSpec.describe Groups::DestroyService, feature_category: :groups_and_projects do
end
it 'verifies that paths have been deleted' do
- Gitlab::GitalyClient::NamespaceService.allow do
- expect(Gitlab::GitalyClient::NamespaceService.new(project.repository_storage)
- .exists?(group.path)).to be_falsey
- end
expect(removed_repo).not_to exist
end
end
@@ -101,10 +96,6 @@ RSpec.describe Groups::DestroyService, feature_category: :groups_and_projects do
end
it 'verifies original paths and projects still exist' do
- Gitlab::GitalyClient::NamespaceService.allow do
- expect(Gitlab::GitalyClient::NamespaceService.new(project.repository_storage)
- .exists?(group.path)).to be_truthy
- end
expect(removed_repo).not_to exist
expect(Project.unscoped.count).to eq(1)
expect(Group.unscoped.count).to eq(2)
diff --git a/spec/services/groups/group_links/create_service_spec.rb b/spec/services/groups/group_links/create_service_spec.rb
index 9ba664212b8..913d72eff9c 100644
--- a/spec/services/groups/group_links/create_service_spec.rb
+++ b/spec/services/groups/group_links/create_service_spec.rb
@@ -55,8 +55,7 @@ RSpec.describe Groups::GroupLinks::CreateService, '#execute', feature_category:
context 'when sharing outside the hierarchy is disabled' do
let_it_be_with_refind(:group_parent) do
- create(:group,
- namespace_settings: create(:namespace_settings, prevent_sharing_groups_outside_hierarchy: true))
+ create(:group, namespace_settings: create(:namespace_settings, prevent_sharing_groups_outside_hierarchy: true))
end
it_behaves_like 'not shareable'
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index 861728f00c6..5e37f33e4f2 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -264,18 +264,6 @@ RSpec.describe Groups::UpdateService, feature_category: :groups_and_projects do
it_behaves_like 'not allowing a path update'
it_behaves_like 'allowing an update', on: :name
-
- context 'when npm_package_registry_fix_group_path_validation is disabled' do
- before do
- stub_feature_flags(npm_package_registry_fix_group_path_validation: false)
- expect_next_instance_of(::Groups::UpdateService) do |service|
- expect(service).to receive(:valid_path_change_with_npm_packages?).and_call_original
- end
- end
-
- it_behaves_like 'not allowing a path update'
- it_behaves_like 'allowing an update', on: :name
- end
end
context 'updating the subgroup' do
@@ -283,18 +271,6 @@ RSpec.describe Groups::UpdateService, feature_category: :groups_and_projects do
it_behaves_like 'allowing an update', on: :path
it_behaves_like 'allowing an update', on: :name
-
- context 'when npm_package_registry_fix_group_path_validation is disabled' do
- before do
- stub_feature_flags(npm_package_registry_fix_group_path_validation: false)
- expect_next_instance_of(::Groups::UpdateService) do |service|
- expect(service).to receive(:valid_path_change_with_npm_packages?).and_call_original
- end
- end
-
- it_behaves_like 'not allowing a path update'
- it_behaves_like 'allowing an update', on: :name
- end
end
end
@@ -306,18 +282,6 @@ RSpec.describe Groups::UpdateService, feature_category: :groups_and_projects do
it_behaves_like 'allowing an update', on: :path
it_behaves_like 'allowing an update', on: :name
-
- context 'when npm_package_registry_fix_group_path_validation is disabled' do
- before do
- stub_feature_flags(npm_package_registry_fix_group_path_validation: false)
- expect_next_instance_of(::Groups::UpdateService) do |service|
- expect(service).to receive(:valid_path_change_with_npm_packages?).and_call_original
- end
- end
-
- it_behaves_like 'not allowing a path update'
- it_behaves_like 'allowing an update', on: :name
- end
end
context 'updating the subgroup' do
@@ -325,18 +289,6 @@ RSpec.describe Groups::UpdateService, feature_category: :groups_and_projects do
it_behaves_like 'allowing an update', on: :path
it_behaves_like 'allowing an update', on: :name
-
- context 'when npm_package_registry_fix_group_path_validation is disabled' do
- before do
- stub_feature_flags(npm_package_registry_fix_group_path_validation: false)
- expect_next_instance_of(::Groups::UpdateService) do |service|
- expect(service).to receive(:valid_path_change_with_npm_packages?).and_call_original
- end
- end
-
- it_behaves_like 'not allowing a path update'
- it_behaves_like 'allowing an update', on: :name
- end
end
end
@@ -348,18 +300,6 @@ RSpec.describe Groups::UpdateService, feature_category: :groups_and_projects do
it_behaves_like 'allowing an update', on: :path
it_behaves_like 'allowing an update', on: :name
-
- context 'when npm_package_registry_fix_group_path_validation is disabled' do
- before do
- stub_feature_flags(npm_package_registry_fix_group_path_validation: false)
- expect_next_instance_of(::Groups::UpdateService) do |service|
- expect(service).to receive(:valid_path_change_with_npm_packages?).and_call_original
- end
- end
-
- it_behaves_like 'not allowing a path update'
- it_behaves_like 'allowing an update', on: :name
- end
end
context 'updating the subgroup' do
@@ -367,18 +307,6 @@ RSpec.describe Groups::UpdateService, feature_category: :groups_and_projects do
it_behaves_like 'allowing an update', on: :path
it_behaves_like 'allowing an update', on: :name
-
- context 'when npm_package_registry_fix_group_path_validation is disabled' do
- before do
- stub_feature_flags(npm_package_registry_fix_group_path_validation: false)
- expect_next_instance_of(::Groups::UpdateService) do |service|
- expect(service).to receive(:valid_path_change_with_npm_packages?).and_call_original
- end
- end
-
- it_behaves_like 'not allowing a path update'
- it_behaves_like 'allowing an update', on: :name
- end
end
end
end
diff --git a/spec/services/import_export_clean_up_service_spec.rb b/spec/services/import_export_clean_up_service_spec.rb
index 7b638b4948b..138dee3d975 100644
--- a/spec/services/import_export_clean_up_service_spec.rb
+++ b/spec/services/import_export_clean_up_service_spec.rb
@@ -53,9 +53,11 @@ RSpec.describe ImportExportCleanUpService, feature_category: :importers do
context 'with uploader exports' do
it 'removes old files and logs' do
- upload = create(:import_export_upload,
- updated_at: 2.days.ago,
- export_file: fixture_file_upload('spec/fixtures/project_export.tar.gz'))
+ upload = create(
+ :import_export_upload,
+ updated_at: 2.days.ago,
+ export_file: fixture_file_upload('spec/fixtures/project_export.tar.gz')
+ )
expect_next_instance_of(Gitlab::Import::Logger) do |logger|
expect(logger)
@@ -73,9 +75,11 @@ RSpec.describe ImportExportCleanUpService, feature_category: :importers do
end
it 'does not remove new files or logs' do
- upload = create(:import_export_upload,
- updated_at: 1.hour.ago,
- export_file: fixture_file_upload('spec/fixtures/project_export.tar.gz'))
+ upload = create(
+ :import_export_upload,
+ updated_at: 1.hour.ago,
+ export_file: fixture_file_upload('spec/fixtures/project_export.tar.gz')
+ )
expect(Gitlab::Import::Logger).not_to receive(:new)
diff --git a/spec/services/incident_management/incidents/create_service_spec.rb b/spec/services/incident_management/incidents/create_service_spec.rb
index e6ded379434..d0f9d414044 100644
--- a/spec/services/incident_management/incidents/create_service_spec.rb
+++ b/spec/services/incident_management/incidents/create_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe IncidentManagement::Incidents::CreateService, feature_category: :incident_management do
let_it_be(:project) { create(:project) }
- let_it_be(:user) { User.alert_bot }
+ let_it_be(:user) { Users::Internal.alert_bot }
let(:description) { 'Incident description' }
diff --git a/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb b/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb
index caa5ee495b7..5bbca91cdcd 100644
--- a/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb
+++ b/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe IncidentManagement::PagerDuty::CreateIncidentIssueService, feature_category: :incident_management do
let_it_be(:project, reload: true) { create(:project) }
- let_it_be(:user) { User.alert_bot }
+ let_it_be(:user) { Users::Internal.alert_bot }
let(:webhook_payload) { Gitlab::Json.parse(fixture_file('pager_duty/webhook_incident_trigger.json')) }
let(:parsed_payload) { ::PagerDuty::WebhookPayloadParser.call(webhook_payload) }
@@ -29,7 +29,7 @@ RSpec.describe IncidentManagement::PagerDuty::CreateIncidentIssueService, featur
end
it 'the issue author is Alert bot' do
- expect(execute.payload[:issue].author).to eq(User.alert_bot)
+ expect(execute.payload[:issue].author).to eq(Users::Internal.alert_bot)
end
it 'issue has a correct title' do
diff --git a/spec/services/issuable/process_assignees_spec.rb b/spec/services/issuable/process_assignees_spec.rb
index 2751267c08b..fac7ef9ce77 100644
--- a/spec/services/issuable/process_assignees_spec.rb
+++ b/spec/services/issuable/process_assignees_spec.rb
@@ -5,75 +5,89 @@ require 'spec_helper'
RSpec.describe Issuable::ProcessAssignees, feature_category: :team_planning do
describe '#execute' do
it 'returns assignee_ids when add_assignee_ids and remove_assignee_ids are not specified' do
- process = described_class.new(assignee_ids: %w(5 7 9),
- add_assignee_ids: nil,
- remove_assignee_ids: nil,
- existing_assignee_ids: %w(1 3 9),
- extra_assignee_ids: %w(2 5 12))
+ process = described_class.new(
+ assignee_ids: %w(5 7 9),
+ add_assignee_ids: nil,
+ remove_assignee_ids: nil,
+ existing_assignee_ids: %w(1 3 9),
+ extra_assignee_ids: %w(2 5 12)
+ )
result = process.execute
expect(result).to contain_exactly(5, 7, 9)
end
it 'combines other ids when assignee_ids is nil' do
- process = described_class.new(assignee_ids: nil,
- add_assignee_ids: nil,
- remove_assignee_ids: nil,
- existing_assignee_ids: %w(1 3 11),
- extra_assignee_ids: %w(2 5 12))
+ process = described_class.new(
+ assignee_ids: nil,
+ add_assignee_ids: nil,
+ remove_assignee_ids: nil,
+ existing_assignee_ids: %w(1 3 11),
+ extra_assignee_ids: %w(2 5 12)
+ )
result = process.execute
expect(result).to contain_exactly(1, 2, 3, 5, 11, 12)
end
it 'combines other ids when both add_assignee_ids and remove_assignee_ids are not empty' do
- process = described_class.new(assignee_ids: %w(5 7 9),
- add_assignee_ids: %w(2 4 6),
- remove_assignee_ids: %w(4 7 11),
- existing_assignee_ids: %w(1 3 11),
- extra_assignee_ids: %w(2 5 12))
+ process = described_class.new(
+ assignee_ids: %w(5 7 9),
+ add_assignee_ids: %w(2 4 6),
+ remove_assignee_ids: %w(4 7 11),
+ existing_assignee_ids: %w(1 3 11),
+ extra_assignee_ids: %w(2 5 12)
+ )
result = process.execute
expect(result).to contain_exactly(1, 2, 3, 5, 6, 12)
end
it 'combines other ids when remove_assignee_ids is not empty' do
- process = described_class.new(assignee_ids: %w(5 7 9),
- add_assignee_ids: nil,
- remove_assignee_ids: %w(4 7 11),
- existing_assignee_ids: %w(1 3 11),
- extra_assignee_ids: %w(2 5 12))
+ process = described_class.new(
+ assignee_ids: %w(5 7 9),
+ add_assignee_ids: nil,
+ remove_assignee_ids: %w(4 7 11),
+ existing_assignee_ids: %w(1 3 11),
+ extra_assignee_ids: %w(2 5 12)
+ )
result = process.execute
expect(result).to contain_exactly(1, 2, 3, 5, 12)
end
it 'combines other ids when add_assignee_ids is not empty' do
- process = described_class.new(assignee_ids: %w(5 7 9),
- add_assignee_ids: %w(2 4 6),
- remove_assignee_ids: nil,
- existing_assignee_ids: %w(1 3 11),
- extra_assignee_ids: %w(2 5 12))
+ process = described_class.new(
+ assignee_ids: %w(5 7 9),
+ add_assignee_ids: %w(2 4 6),
+ remove_assignee_ids: nil,
+ existing_assignee_ids: %w(1 3 11),
+ extra_assignee_ids: %w(2 5 12)
+ )
result = process.execute
expect(result).to contain_exactly(1, 2, 4, 3, 5, 6, 11, 12)
end
it 'combines ids when existing_assignee_ids and extra_assignee_ids are omitted' do
- process = described_class.new(assignee_ids: %w(5 7 9),
- add_assignee_ids: %w(2 4 6),
- remove_assignee_ids: %w(4 7 11))
+ process = described_class.new(
+ assignee_ids: %w(5 7 9),
+ add_assignee_ids: %w(2 4 6),
+ remove_assignee_ids: %w(4 7 11)
+ )
result = process.execute
expect(result.sort).to eq([2, 6].sort)
end
it 'handles mixed string and integer arrays' do
- process = described_class.new(assignee_ids: %w(5 7 9),
- add_assignee_ids: [2, 4, 6],
- remove_assignee_ids: %w(4 7 11),
- existing_assignee_ids: [1, 3, 11],
- extra_assignee_ids: %w(2 5 12))
+ process = described_class.new(
+ assignee_ids: %w(5 7 9),
+ add_assignee_ids: [2, 4, 6],
+ remove_assignee_ids: %w(4 7 11),
+ existing_assignee_ids: [1, 3, 11],
+ extra_assignee_ids: %w(2 5 12)
+ )
result = process.execute
expect(result).to contain_exactly(1, 2, 3, 5, 6, 12)
diff --git a/spec/services/issue_links/destroy_service_spec.rb b/spec/services/issue_links/destroy_service_spec.rb
index 5c4814f5ad1..c367b0157cb 100644
--- a/spec/services/issue_links/destroy_service_spec.rb
+++ b/spec/services/issue_links/destroy_service_spec.rb
@@ -5,25 +5,22 @@ require 'spec_helper'
RSpec.describe IssueLinks::DestroyService, feature_category: :team_planning do
describe '#execute' do
let_it_be(:project) { create(:project_empty_repo, :private) }
- let_it_be(:user) { create(:user) }
+ let_it_be(:reporter) { create(:user).tap { |user| project.add_reporter(user) } }
let_it_be(:issue_a) { create(:issue, project: project) }
let_it_be(:issue_b) { create(:issue, project: project) }
let!(:issuable_link) { create(:issue_link, source: issue_a, target: issue_b) }
+ let(:user) { reporter }
subject { described_class.new(issuable_link, user).execute }
it_behaves_like 'a destroyable issuable link'
context 'when target is an incident' do
- before do
- project.add_reporter(user)
- end
-
let(:issue_b) { create(:incident, project: project) }
it_behaves_like 'an incident management tracked event', :incident_management_incident_unrelate do
- let(:current_user) { user }
+ let(:current_user) { reporter }
end
it_behaves_like 'Snowplow event tracking with RedisHLL context' do
diff --git a/spec/services/issue_links/list_service_spec.rb b/spec/services/issue_links/list_service_spec.rb
index bfb6127ed56..b5cc8c4dcdc 100644
--- a/spec/services/issue_links/list_service_spec.rb
+++ b/spec/services/issue_links/list_service_spec.rb
@@ -21,18 +21,15 @@ RSpec.describe IssueLinks::ListService, feature_category: :team_planning do
let(:issue_d) { create :issue, project: project }
let!(:issue_link_c) do
- create(:issue_link, source: issue_d,
- target: issue)
+ create(:issue_link, source: issue_d, target: issue)
end
let!(:issue_link_b) do
- create(:issue_link, source: issue,
- target: issue_c)
+ create(:issue_link, source: issue, target: issue_c)
end
let!(:issue_link_a) do
- create(:issue_link, source: issue,
- target: issue_b)
+ create(:issue_link, source: issue, target: issue_b)
end
it 'ensures no N+1 queries are made' do
@@ -53,26 +50,32 @@ RSpec.describe IssueLinks::ListService, feature_category: :team_planning do
it 'returns related issues JSON' do
expect(subject.size).to eq(3)
- expect(subject).to include(include(id: issue_b.id,
- title: issue_b.title,
- state: issue_b.state,
- reference: issue_b.to_reference(project),
- path: "/#{project.full_path}/-/issues/#{issue_b.iid}",
- relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_a.id}"))
-
- expect(subject).to include(include(id: issue_c.id,
- title: issue_c.title,
- state: issue_c.state,
- reference: issue_c.to_reference(project),
- path: "/#{project.full_path}/-/issues/#{issue_c.iid}",
- relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_b.id}"))
-
- expect(subject).to include(include(id: issue_d.id,
- title: issue_d.title,
- state: issue_d.state,
- reference: issue_d.to_reference(project),
- path: "/#{project.full_path}/-/issues/#{issue_d.iid}",
- relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_c.id}"))
+ expect(subject).to include(include(
+ id: issue_b.id,
+ title: issue_b.title,
+ state: issue_b.state,
+ reference: issue_b.to_reference(project),
+ path: "/#{project.full_path}/-/issues/#{issue_b.iid}",
+ relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_a.id}"
+ ))
+
+ expect(subject).to include(include(
+ id: issue_c.id,
+ title: issue_c.title,
+ state: issue_c.state,
+ reference: issue_c.to_reference(project),
+ path: "/#{project.full_path}/-/issues/#{issue_c.iid}",
+ relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_b.id}"
+ ))
+
+ expect(subject).to include(include(
+ id: issue_d.id,
+ title: issue_d.title,
+ state: issue_d.state,
+ reference: issue_d.to_reference(project),
+ path: "/#{project.full_path}/-/issues/#{issue_d.iid}",
+ relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_c.id}"
+ ))
end
end
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index 47925236a74..dabbd4bfa84 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -321,7 +321,7 @@ RSpec.describe Issues::CloseService, feature_category: :team_planning do
alert = create(:alert_management_alert, issue: issue, project: project)
expect(SystemNoteService).to receive(:change_alert_status)
- .with(alert, User.alert_bot, " because #{user.to_reference} closed incident #{issue.to_reference(project)}")
+ .with(alert, Users::Internal.alert_bot, " because #{user.to_reference} closed incident #{issue.to_reference(project)}")
close_issue
@@ -356,7 +356,7 @@ RSpec.describe Issues::CloseService, feature_category: :team_planning do
alerts.each do |alert|
expect(SystemNoteService).to receive(:change_alert_status)
- .with(alert, User.alert_bot, " because #{user.to_reference} closed incident #{issue.to_reference(project)}")
+ .with(alert, Users::Internal.alert_bot, " because #{user.to_reference} closed incident #{issue.to_reference(project)}")
end
close_issue
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 2daba8e359d..7cd2cd8f564 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -577,8 +577,10 @@ RSpec.describe Issues::CreateService, feature_category: :team_planning do
context "when issuable feature is private" do
before do
- project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE,
- merge_requests_access_level: ProjectFeature::PRIVATE)
+ project.project_feature.update!(
+ issues_access_level: ProjectFeature::PRIVATE,
+ merge_requests_access_level: ProjectFeature::PRIVATE
+ )
end
levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]
@@ -680,7 +682,7 @@ RSpec.describe Issues::CreateService, feature_category: :team_planning do
end
context 'with alert bot author' do
- let_it_be(:user) { User.alert_bot }
+ let_it_be(:user) { Users::Internal.alert_bot }
let_it_be(:label) { create(:label, project: project) }
let(:opts) do
diff --git a/spec/services/issues/export_csv_service_spec.rb b/spec/services/issues/export_csv_service_spec.rb
index 1ac64c0301d..31eaa72255d 100644
--- a/spec/services/issues/export_csv_service_spec.rb
+++ b/spec/services/issues/export_csv_service_spec.rb
@@ -43,18 +43,20 @@ RSpec.describe Issues::ExportCsvService, :with_license, feature_category: :team_
# so create these first.
issue.timelogs.create!(time_spent: 360, user: user)
issue.timelogs.create!(time_spent: 200, user: user)
- issue.update!(milestone: milestone,
- assignees: [user],
- description: 'Issue with details',
- state: :opened,
- due_date: DateTime.new(2014, 3, 2),
- created_at: DateTime.new(2015, 4, 3, 2, 1, 0),
- updated_at: DateTime.new(2016, 5, 4, 3, 2, 1),
- closed_at: DateTime.new(2017, 6, 5, 4, 3, 2),
- weight: 4,
- discussion_locked: true,
- labels: [feature_label, idea_label],
- time_estimate: 72000)
+ issue.update!(
+ milestone: milestone,
+ assignees: [user],
+ description: 'Issue with details',
+ state: :opened,
+ due_date: DateTime.new(2014, 3, 2),
+ created_at: DateTime.new(2015, 4, 3, 2, 1, 0),
+ updated_at: DateTime.new(2016, 5, 4, 3, 2, 1),
+ closed_at: DateTime.new(2017, 6, 5, 4, 3, 2),
+ weight: 4,
+ discussion_locked: true,
+ labels: [feature_label, idea_label],
+ time_estimate: 72000
+ )
end
shared_examples 'exports CSVs for issues' do
@@ -158,9 +160,9 @@ RSpec.describe Issues::ExportCsvService, :with_license, feature_category: :team_
context 'with issues filtered by labels and project' do
subject do
described_class.new(
- IssuesFinder.new(user,
- project_id: project.id,
- label_name: %w(Idea Feature)).execute, project)
+ IssuesFinder.new(user, project_id: project.id, label_name: %w(Idea Feature)).execute,
+ project
+ )
end
it 'returns only filtered objects' do
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index 12924df3200..55f912fb703 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -390,8 +390,7 @@ RSpec.describe Issues::MoveService, feature_category: :team_planning do
let(:moved_to_issue) { create(:issue) }
let(:old_issue) do
- create(:issue, project: old_project, author: author,
- moved_to: moved_to_issue)
+ create(:issue, project: old_project, author: author, moved_to: moved_to_issue)
end
it { expect { move }.to raise_error(StandardError, /permissions/) }
diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb
index c2111bffdda..ea4ad0440ec 100644
--- a/spec/services/issues/resolve_discussions_spec.rb
+++ b/spec/services/issues/resolve_discussions_spec.rb
@@ -60,10 +60,14 @@ RSpec.describe Issues::ResolveDiscussions, feature_category: :team_planning do
end
it "contains all discussions when only a merge request is passed" do
- second_discussion = Discussion.new([create(:diff_note_on_merge_request,
- noteable: merge_request,
- project: merge_request.target_project,
- line_number: 15)])
+ second_discussion = Discussion.new([
+ create(
+ :diff_note_on_merge_request,
+ noteable: merge_request,
+ project: merge_request.target_project,
+ line_number: 15
+ )
+ ])
service = DummyService.new(
container: project,
current_user: user,
@@ -77,11 +81,15 @@ RSpec.describe Issues::ResolveDiscussions, feature_category: :team_planning do
end
it "contains only unresolved discussions" do
- _second_discussion = Discussion.new([create(:diff_note_on_merge_request, :resolved,
- noteable: merge_request,
- project: merge_request.target_project,
- line_number: 15
- )])
+ _second_discussion = Discussion.new([
+ create(
+ :diff_note_on_merge_request,
+ :resolved,
+ noteable: merge_request,
+ project: merge_request.target_project,
+ line_number: 15
+ )
+ ])
service = DummyService.new(
container: project,
current_user: user,
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index c677dc0315c..eb9fe2b4ed7 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -15,11 +15,14 @@ RSpec.describe Issues::UpdateService, :mailer, feature_category: :team_planning
let_it_be(:milestone) { create(:milestone, project: project) }
let(:issue) do
- create(:issue, title: 'Old title',
- description: "for #{user2.to_reference}",
- assignee_ids: [user3.id],
- project: project,
- author: create(:user))
+ create(
+ :issue,
+ title: 'Old title',
+ description: "for #{user2.to_reference}",
+ assignee_ids: [user3.id],
+ project: project,
+ author: create(:user)
+ )
end
before_all do
diff --git a/spec/services/labels/available_labels_service_spec.rb b/spec/services/labels/available_labels_service_spec.rb
index c9f75283c75..2b398210034 100644
--- a/spec/services/labels/available_labels_service_spec.rb
+++ b/spec/services/labels/available_labels_service_spec.rb
@@ -108,36 +108,24 @@ RSpec.describe Labels::AvailableLabelsService, feature_category: :team_planning
end
end
- describe '#filter_locked_labels_ids_in_param' do
- let(:label_ids) { labels.map(&:id).push(non_existing_record_id) }
+ describe '#filter_locked_label_ids' do
+ let(:label_ids) { labels.map(&:id) }
context 'when parent is a project' do
- it 'returns only locked label ids' do
- result = described_class.new(user, project, ids: label_ids).filter_locked_labels_ids_in_param(:ids)
+ it 'returns only relevant label ids' do
+ result = described_class.new(user, project, ids: label_ids).filter_locked_label_ids(label_ids)
expect(result).to match_array([project_label_locked.id, group_label_locked.id])
end
-
- it 'returns labels in preserved order' do
- result = described_class.new(user, project, ids: label_ids.reverse).filter_locked_labels_ids_in_param(:ids)
-
- expect(result).to eq([group_label_locked.id, project_label_locked.id])
- end
end
context 'when parent is a group' do
- it 'returns only locked label ids' do
- result = described_class.new(user, group, ids: label_ids).filter_locked_labels_ids_in_param(:ids)
+ it 'returns only relevant label ids' do
+ result = described_class.new(user, group, ids: label_ids).filter_locked_label_ids(label_ids)
expect(result).to match_array([group_label_locked.id])
end
end
-
- it 'accepts a single id parameter' do
- result = described_class.new(user, project, label_id: project_label_locked.id).filter_locked_labels_ids_in_param(:label_id)
-
- expect(result).to match_array([project_label_locked.id])
- end
end
describe '#available_labels' do
diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb
index 9a8868dac10..61e229e3138 100644
--- a/spec/services/labels/update_service_spec.rb
+++ b/spec/services/labels/update_service_spec.rb
@@ -99,6 +99,14 @@ RSpec.describe Labels::UpdateService, feature_category: :team_planning do
expect(label.reload.lock_on_merge).to be_truthy
end
+ it 'does not allow lock_on_merge to be unset' do
+ label_locked = Labels::CreateService.new(title: 'Initial', lock_on_merge: true).execute(project: project)
+ label = described_class.new(title: 'test', lock_on_merge: false).execute(label_locked)
+
+ expect(label.reload.lock_on_merge).to be_truthy
+ expect(label.reload.title).to eq 'test'
+ end
+
it 'does not allow setting lock_on_merge for templates' do
template_label = Labels::CreateService.new(title: 'Initial').execute(template: true)
label = described_class.new(params).execute(template_label)
diff --git a/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb b/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb
index 86f528d1ea7..d9982b664e5 100644
--- a/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb
+++ b/spec/services/loose_foreign_keys/batch_cleaner_service_spec.rb
@@ -88,10 +88,11 @@ RSpec.describe LooseForeignKeys::BatchCleanerService, feature_category: :databas
expect(loose_fk_child_table_1.count).to eq(4)
expect(loose_fk_child_table_2.count).to eq(4)
- described_class.new(parent_table: '_test_loose_fk_parent_table',
- loose_foreign_key_definitions: loose_foreign_key_definitions,
- deleted_parent_records: LooseForeignKeys::DeletedRecord.load_batch_for_table('public._test_loose_fk_parent_table', 100)
- ).execute
+ described_class.new(
+ parent_table: '_test_loose_fk_parent_table',
+ loose_foreign_key_definitions: loose_foreign_key_definitions,
+ deleted_parent_records: LooseForeignKeys::DeletedRecord.load_batch_for_table('public._test_loose_fk_parent_table', 100)
+ ).execute
end
it 'cleans up the child records' do
@@ -125,11 +126,12 @@ RSpec.describe LooseForeignKeys::BatchCleanerService, feature_category: :databas
let(:deleted_records_incremented_counter) { Gitlab::Metrics.registry.get(:loose_foreign_key_incremented_deleted_records) }
let(:cleaner) do
- described_class.new(parent_table: '_test_loose_fk_parent_table',
- loose_foreign_key_definitions: loose_foreign_key_definitions,
- deleted_parent_records: LooseForeignKeys::DeletedRecord.load_batch_for_table('public._test_loose_fk_parent_table', 100),
- modification_tracker: modification_tracker
- )
+ described_class.new(
+ parent_table: '_test_loose_fk_parent_table',
+ loose_foreign_key_definitions: loose_foreign_key_definitions,
+ deleted_parent_records: LooseForeignKeys::DeletedRecord.load_batch_for_table('public._test_loose_fk_parent_table', 100),
+ modification_tracker: modification_tracker
+ )
end
before do
diff --git a/spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb b/spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb
index b59339b24b4..20a193e3b01 100644
--- a/spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb
+++ b/spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb
@@ -162,7 +162,9 @@ RSpec.describe LooseForeignKeys::ProcessDeletedRecordsService, feature_category:
end
before do
- stub_const('LooseForeignKeys::ModificationTracker::MAX_DELETES', 2)
+ allow_next_instance_of(LooseForeignKeys::ModificationTracker) do |instance|
+ allow(instance).to receive(:max_deletes).and_return(2)
+ end
stub_const('LooseForeignKeys::CleanerService::DELETE_LIMIT', 1)
end
diff --git a/spec/services/members/invitation_reminder_email_service_spec.rb b/spec/services/members/invitation_reminder_email_service_spec.rb
index 2b72a4919b4..a3c2e994c2e 100644
--- a/spec/services/members/invitation_reminder_email_service_spec.rb
+++ b/spec/services/members/invitation_reminder_email_service_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Members::InvitationReminderEmailService, feature_category: :group
with_them do
# Create an invitation today with an expiration date from 0 to 10 days in the future or without an expiration date
# We chose 10 days here, because we fetch invitations that were created at most 10 days ago.
- (0..10).each do |day|
+ 11.times do |day|
it 'sends an invitation reminder only on the expected days' do
next if day > (expires_at_days || 10) # We don't need to test after the invitation has already expired
diff --git a/spec/services/merge_requests/approval_service_spec.rb b/spec/services/merge_requests/approval_service_spec.rb
index 6140021c8d2..81fc5661032 100644
--- a/spec/services/merge_requests/approval_service_spec.rb
+++ b/spec/services/merge_requests/approval_service_spec.rb
@@ -78,6 +78,51 @@ RSpec.describe MergeRequests::ApprovalService, feature_category: :code_review_wo
service.execute(merge_request)
end
+ context 'when generating a patch_id_sha' do
+ it 'records a value' do
+ service.execute(merge_request)
+
+ expect(merge_request.approvals.last.patch_id_sha).not_to be_nil
+ end
+
+ context 'when base_sha is nil' do
+ it 'records patch_id_sha as nil' do
+ expect_next_instance_of(Gitlab::Diff::DiffRefs) do |diff_ref|
+ expect(diff_ref).to receive(:base_sha).at_least(:once).and_return(nil)
+ end
+
+ service.execute(merge_request)
+
+ expect(merge_request.approvals.last.patch_id_sha).to be_nil
+ end
+ end
+
+ context 'when head_sha is nil' do
+ it 'records patch_id_sha as nil' do
+ expect_next_instance_of(Gitlab::Diff::DiffRefs) do |diff_ref|
+ expect(diff_ref).to receive(:head_sha).at_least(:once).and_return(nil)
+ end
+
+ service.execute(merge_request)
+
+ expect(merge_request.approvals.last.patch_id_sha).to be_nil
+ end
+ end
+
+ context 'when base_sha and head_sha match' do
+ it 'records patch_id_sha as nil' do
+ expect_next_instance_of(Gitlab::Diff::DiffRefs) do |diff_ref|
+ expect(diff_ref).to receive(:base_sha).at_least(:once).and_return("abc123")
+ expect(diff_ref).to receive(:head_sha).at_least(:once).and_return("abc123")
+ end
+
+ service.execute(merge_request)
+
+ expect(merge_request.approvals.last.patch_id_sha).to be_nil
+ end
+ end
+ end
+
it 'publishes MergeRequests::ApprovedEvent' do
expect { service.execute(merge_request) }
.to publish_event(MergeRequests::ApprovedEvent)
diff --git a/spec/services/merge_requests/base_service_spec.rb b/spec/services/merge_requests/base_service_spec.rb
index 1ca4bfe622c..6a8758c8684 100644
--- a/spec/services/merge_requests/base_service_spec.rb
+++ b/spec/services/merge_requests/base_service_spec.rb
@@ -141,4 +141,32 @@ RSpec.describe MergeRequests::BaseService, feature_category: :code_review_workfl
describe '#constructor_container_arg' do
it { expect(described_class.constructor_container_arg("some-value")).to eq({ project: "some-value" }) }
end
+
+ describe '#inspect' do
+ context 'when #merge_request is defined' do
+ let(:klass) do
+ Class.new(described_class) do
+ def merge_request
+ params[:merge_request]
+ end
+ end
+ end
+
+ let(:params) { {} }
+
+ subject do
+ klass
+ .new(project: nil, current_user: nil, params: params)
+ .inspect
+ end
+
+ it { is_expected.to eq "#<#{klass}>" }
+
+ context 'when merge request is present' do
+ let(:params) { { merge_request: build(:merge_request) } }
+
+ it { is_expected.to eq "#<#{klass} #{params[:merge_request].to_reference(full: true)}>" }
+ end
+ end
+ end
end
diff --git a/spec/services/merge_requests/create_ref_service_spec.rb b/spec/services/merge_requests/create_ref_service_spec.rb
index 85ac651c1fa..5f7b9430416 100644
--- a/spec/services/merge_requests/create_ref_service_spec.rb
+++ b/spec/services/merge_requests/create_ref_service_spec.rb
@@ -6,13 +6,14 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
using RSpec::Parameterized::TableSyntax
describe '#execute' do
- let_it_be(:project) { create(:project, :empty_repo) }
+ let_it_be_with_reload(:project) { create(:project, :empty_repo) }
let_it_be(:user) { project.creator }
let_it_be(:first_parent_ref) { project.default_branch_or_main }
let_it_be(:source_branch) { 'branch' }
let(:target_ref) { "refs/merge-requests/#{merge_request.iid}/train" }
let(:source_sha) { project.commit(source_branch).sha }
let(:squash) { false }
+ let(:default_commit_message) { merge_request.default_merge_commit_message(user: user) }
let(:merge_request) do
create(
@@ -84,36 +85,40 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
)
end
- it 'writes the merged result into target_ref', :aggregate_failures do
- expect(result[:status]).to eq :success
- expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
- expect(result[:source_sha]).to eq(project.repository.commit(target_ref).parents[1].sha)
- expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
- expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
- match(
- [
- a_string_matching(/Merge branch '#{source_branch}' into '#{first_parent_ref}'/),
- 'Feature branch commit 2',
- 'Feature branch commit 1',
- 'Base parent commit 2',
- 'Base parent commit 1'
- ]
+ shared_examples_for 'writing with a merge commit' do
+ it 'merges with a merge commit', :aggregate_failures do
+ expect(result[:status]).to eq :success
+ expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
+ expect(result[:source_sha]).to eq(project.repository.commit(source_branch).sha)
+ expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
+ expect(result[:merge_commit_sha]).to be_present
+ expect(result[:squash_commit_sha]).not_to be_present
+ expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
+ match(
+ [
+ expected_merge_commit,
+ 'Feature branch commit 2',
+ 'Feature branch commit 1',
+ 'Base parent commit 2',
+ 'Base parent commit 1'
+ ]
+ )
)
- )
+ end
end
- context 'when squash is requested' do
- let(:squash) { true }
-
+ shared_examples_for 'writing with a squash and merge commit' do
it 'writes the squashed result', :aggregate_failures do
expect(result[:status]).to eq :success
expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
- expect(result[:source_sha]).to eq(project.repository.commit(target_ref).parents[1].sha)
+ expect(result[:source_sha]).to eq(project.repository.commit(source_branch).sha)
expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
+ expect(result[:merge_commit_sha]).to be_present
+ expect(result[:squash_commit_sha]).to be_present
expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
match(
[
- a_string_matching(/Merge branch '#{source_branch}' into '#{first_parent_ref}'/),
+ expected_merge_commit,
"#{merge_request.title}\n",
'Base parent commit 2',
'Base parent commit 1'
@@ -123,23 +128,18 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
end
end
- context 'when semi-linear merges are enabled' do
- before do
- project.merge_method = :rebase_merge
- project.save!
- end
-
- it 'writes the semi-linear merged result', :aggregate_failures do
+ shared_examples_for 'writing with a squash and no merge commit' do
+ it 'writes the squashed result without a merge commit', :aggregate_failures do
expect(result[:status]).to eq :success
expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
- expect(result[:source_sha]).to eq(project.repository.commit(target_ref).parents[1].sha)
+ expect(result[:source_sha]).to eq(project.repository.commit(source_branch).sha)
expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
+ expect(result[:merge_commit_sha]).not_to be_present
+ expect(result[:squash_commit_sha]).to be_present
expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
match(
[
- a_string_matching(/Merge branch '#{source_branch}' into '#{first_parent_ref}'/),
- 'Feature branch commit 2',
- 'Feature branch commit 1',
+ "#{merge_request.title}\n",
'Base parent commit 2',
'Base parent commit 1'
]
@@ -148,17 +148,14 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
end
end
- context 'when fast-forward merges are enabled' do
- before do
- project.merge_method = :ff
- project.save!
- end
-
+ shared_examples_for 'writing without a merge commit' do
it 'writes the rebased merged result', :aggregate_failures do
expect(result[:status]).to eq :success
expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
- expect(result[:source_sha]).to eq(project.repository.commit(target_ref).sha)
+ expect(result[:source_sha]).to eq(project.repository.commit(source_branch).sha)
expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
+ expect(result[:merge_commit_sha]).not_to be_present
+ expect(result[:squash_commit_sha]).not_to be_present
expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
eq(
[
@@ -171,6 +168,114 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
)
end
end
+
+ shared_examples 'merge commits without squash' do
+ context 'with a custom template' do
+ let(:expected_merge_commit) { 'This is the merge commit' } # could also be default_commit_message
+
+ before do
+ project.project_setting.update!(merge_commit_template: expected_merge_commit)
+ end
+
+ it_behaves_like 'writing with a merge commit'
+ end
+
+ context 'with no custom template' do
+ let(:expected_merge_commit) { default_commit_message }
+
+ before do
+ project.project_setting.update!(merge_commit_template: nil)
+ end
+
+ it_behaves_like 'writing with a merge commit'
+ end
+ end
+
+ shared_examples 'merge commits with squash' do
+ context 'when squash set' do
+ let(:squash) { true }
+ let(:expected_merge_commit) { merge_request.default_merge_commit_message(user: user) }
+
+ before do
+ project.project_setting.update!(merge_commit_template: 'This is the merge commit')
+ end
+
+ it_behaves_like 'writing with a squash and merge commit'
+ end
+ end
+
+ context 'when the merge commit message is provided at time of merge' do
+ let(:expected_merge_commit) { 'something custom' }
+
+ before do
+ merge_request.merge_params['commit_message'] = expected_merge_commit
+ end
+
+ it 'writes the merged result', :aggregate_failures do
+ expect(result[:status]).to eq :success
+ expect(project.repository.commits(target_ref, limit: 1, order: 'topo').map(&:message)).to(
+ match([expected_merge_commit])
+ )
+ end
+
+ context 'when squash set' do
+ let(:squash) { true }
+
+ it_behaves_like 'writing with a squash and merge commit'
+ end
+ end
+
+ context 'when merged commit strategy' do
+ include_examples 'merge commits without squash'
+ include_examples 'merge commits with squash'
+ end
+
+ context 'when semi-linear merge strategy' do
+ before do
+ project.merge_method = :rebase_merge
+ project.save!
+ end
+
+ include_examples 'merge commits without squash'
+ include_examples 'merge commits with squash'
+
+ context 'when the target ref changes between rebase and merge' do
+ # this tests internal handling of expected_old_oid
+
+ it 'returns an error', :aggregate_failures do
+ expect_next_instance_of(described_class) do |instance|
+ original = instance.method(:maybe_merge!)
+
+ expect(instance).to receive(:maybe_merge!) do |*args|
+ # Corrupt target_ref before the merge, simulating a race with
+ # another instance of the service for the same MR. source_sha is
+ # just an arbitrary valid commit that differs from what was just
+ # written.
+ project.repository.write_ref(target_ref, source_sha)
+ original.call(*args)
+ end
+ end
+
+ expect(result[:status]).to eq :error
+ expect(result[:message]).to eq "9:Could not update #{target_ref}. Please refresh and try again."
+ end
+ end
+ end
+
+ context 'when fast-forward merge strategy' do
+ before do
+ project.merge_method = :ff
+ project.save!
+ end
+
+ it_behaves_like 'writing without a merge commit'
+
+ context 'when squash set' do
+ let(:squash) { true }
+
+ it_behaves_like 'writing with a squash and no merge commit'
+ end
+ end
end
end
end
diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb
deleted file mode 100644
index c48ed19e40d..00000000000
--- a/spec/services/merge_requests/ff_merge_service_spec.rb
+++ /dev/null
@@ -1,144 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe MergeRequests::FfMergeService, feature_category: :code_review_workflow do
- let(:user) { create(:user) }
- let(:user2) { create(:user) }
- let(:merge_request) do
- create(
- :merge_request,
- source_branch: 'flatten-dir',
- target_branch: 'improve/awesome',
- assignees: [user2],
- author: create(:user)
- )
- end
-
- let(:project) { merge_request.project }
- let(:valid_merge_params) { { sha: merge_request.diff_head_sha } }
-
- before do
- stub_feature_flags(refactor_merge_service: false)
- project.add_maintainer(user)
- project.add_developer(user2)
- end
-
- describe '#execute' do
- context 'valid params' do
- let(:service) { described_class.new(project: project, current_user: user, params: valid_merge_params) }
-
- def execute_ff_merge
- perform_enqueued_jobs do
- service.execute(merge_request)
- end
- end
-
- before do
- allow(service).to receive(:execute_hooks)
- end
-
- it "does not create merge commit" do
- execute_ff_merge
-
- source_branch_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
- target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
-
- expect(source_branch_sha).to eq(target_branch_sha)
- end
-
- it 'keeps the merge request valid' do
- expect { execute_ff_merge }
- .not_to change { merge_request.valid? }
- end
-
- it 'updates the merge request to merged' do
- expect { execute_ff_merge }
- .to change { merge_request.merged? }
- .from(false)
- .to(true)
- end
-
- it 'sends email to user2 about merge of new merge_request' do
- execute_ff_merge
-
- email = ActionMailer::Base.deliveries.last
- expect(email.to.first).to eq(user2.email)
- expect(email.subject).to include(merge_request.title)
- end
-
- it 'creates resource event about merge_request merge' do
- execute_ff_merge
-
- event = merge_request.resource_state_events.last
- expect(event.state).to eq('merged')
- end
-
- it 'does not update squash_commit_sha if it is not a squash' do
- expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
-
- expect { execute_ff_merge }.not_to change { merge_request.squash_commit_sha }
- expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.in_progress_merge_commit_sha).to be_nil
- end
-
- it 'updates squash_commit_sha if it is a squash' do
- expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
-
- merge_request.update!(squash: true)
-
- expect { execute_ff_merge }
- .to change { merge_request.squash_commit_sha }
- .from(nil)
-
- expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.in_progress_merge_commit_sha).to be_nil
- end
- end
-
- context 'error handling' do
- let(:service) { described_class.new(project: project, current_user: user, params: valid_merge_params.merge(commit_message: 'Awesome message')) }
-
- before do
- allow(Gitlab::AppLogger).to receive(:error)
- end
-
- it 'logs and saves error if there is an exception' do
- error_message = 'error message'
-
- allow(service).to receive(:repository).and_raise("error message")
- allow(service).to receive(:execute_hooks)
-
- service.execute(merge_request)
-
- expect(Gitlab::AppLogger).to have_received(:error)
- .with(hash_including(message: a_string_matching(error_message)))
- end
-
- it 'logs and saves error if there is an PreReceiveError exception' do
- error_message = 'error message'
- raw_message = 'The truth is out there'
-
- pre_receive_error = Gitlab::Git::PreReceiveError.new(raw_message, fallback_message: error_message)
- allow(service).to receive(:repository).and_raise(pre_receive_error)
- allow(service).to receive(:execute_hooks)
-
- service.execute(merge_request)
-
- expect(merge_request.merge_error).to include(error_message)
- expect(Gitlab::AppLogger).to have_received(:error)
- .with(hash_including(message: a_string_matching(error_message)))
- end
-
- it 'does not update squash_commit_sha if squash merge is not successful' do
- merge_request.update!(squash: true)
-
- expect(project.repository.raw).to receive(:ff_merge) do
- raise 'Merge error'
- end
-
- expect { service.execute(merge_request) }.not_to change { merge_request.squash_commit_sha }
- end
- end
- end
-end
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 1faa1fd3644..6e34f4362c1 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -8,437 +8,506 @@ RSpec.describe MergeRequests::MergeService, feature_category: :code_review_workf
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
- where(:ff_refactor_merge_service_enabled) { [true, false] }
+ let(:merge_request) { create(:merge_request, :simple, author: user2, assignees: [user2]) }
+ let(:project) { merge_request.project }
- with_them do
- let(:merge_request) { create(:merge_request, :simple, author: user2, assignees: [user2]) }
- let(:project) { merge_request.project }
-
- before do
- stub_feature_flags(refactor_merge_service: ff_refactor_merge_service_enabled)
+ before do
+ project.add_maintainer(user)
+ project.add_developer(user2)
+ end
- project.add_maintainer(user)
- project.add_developer(user2)
+ describe '#execute' do
+ let(:service) { described_class.new(project: project, current_user: user, params: merge_params) }
+ let(:merge_params) do
+ { commit_message: 'Awesome message', sha: merge_request.diff_head_sha }
end
- describe '#execute' do
- let(:service) { described_class.new(project: project, current_user: user, params: merge_params) }
- let(:merge_params) do
- { commit_message: 'Awesome message', sha: merge_request.diff_head_sha }
- end
+ let(:lease_key) { "merge_requests_merge_service:#{merge_request.id}" }
+ let!(:lease) { stub_exclusive_lease(lease_key) }
- let(:lease_key) { "merge_requests_merge_service:#{merge_request.id}" }
- let!(:lease) { stub_exclusive_lease(lease_key) }
+ shared_examples 'with valid params' do
+ before do
+ allow(service).to receive(:execute_hooks)
+ expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
- shared_examples 'with valid params' do
- before do
- allow(service).to receive(:execute_hooks)
- expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
-
- perform_enqueued_jobs do
- service.execute(merge_request)
- end
+ perform_enqueued_jobs do
+ service.execute(merge_request)
end
+ end
- it { expect(merge_request).to be_valid }
- it { expect(merge_request).to be_merged }
+ it { expect(merge_request).to be_valid }
+ it { expect(merge_request).to be_merged }
- it 'does not update squash_commit_sha if it is not a squash' do
- expect(merge_request.squash_commit_sha).to be_nil
- end
+ it 'does not update squash_commit_sha if it is not a squash' do
+ expect(merge_request.squash_commit_sha).to be_nil
+ end
- it 'sends email to user2 about merge of new merge_request' do
- email = ActionMailer::Base.deliveries.last
- expect(email.to.first).to eq(user2.email)
- expect(email.subject).to include(merge_request.title)
- end
+ it 'sends email to user2 about merge of new merge_request' do
+ email = ActionMailer::Base.deliveries.last
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(merge_request.title)
+ end
- context 'note creation' do
- it 'creates resource state event about merge_request merge' do
- event = merge_request.resource_state_events.last
- expect(event.state).to eq('merged')
- end
+ context 'note creation' do
+ it 'creates resource state event about merge_request merge' do
+ event = merge_request.resource_state_events.last
+ expect(event.state).to eq('merged')
end
end
+ end
- shared_examples 'squashing' do
- # A merge request with 5 commits
- let(:merge_request) do
- create(
- :merge_request,
- :simple,
- author: user2,
- assignees: [user2],
- squash: true,
- source_branch: 'improve/awesome',
- target_branch: 'fix'
- )
- end
+ shared_examples 'squashing' do
+ # A merge request with 5 commits
+ let(:merge_request) do
+ create(
+ :merge_request,
+ :simple,
+ author: user2,
+ assignees: [user2],
+ squash: true,
+ source_branch: 'improve/awesome',
+ target_branch: 'fix'
+ )
+ end
- let(:merge_params) do
- { commit_message: 'Merge commit message',
- squash_commit_message: 'Squash commit message',
- sha: merge_request.diff_head_sha }
- end
+ let(:merge_params) do
+ { commit_message: 'Merge commit message',
+ squash_commit_message: 'Squash commit message',
+ sha: merge_request.diff_head_sha }
+ end
- before do
- allow(service).to receive(:execute_hooks)
- expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
+ before do
+ allow(service).to receive(:execute_hooks)
+ expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
- perform_enqueued_jobs do
- service.execute(merge_request)
- end
+ perform_enqueued_jobs do
+ service.execute(merge_request)
end
+ end
- it 'merges the merge request with squashed commits' do
- expect(merge_request).to be_merged
+ it 'merges the merge request with squashed commits' do
+ expect(merge_request).to be_merged
- merge_commit = merge_request.merge_commit
- squash_commit = merge_request.merge_commit.parents.last
+ merge_commit = merge_request.merge_commit
+ squash_commit = merge_request.merge_commit.parents.last
- expect(merge_commit.message).to eq('Merge commit message')
- expect(squash_commit.message).to eq("Squash commit message\n")
- end
+ expect(merge_commit.message).to eq('Merge commit message')
+ expect(squash_commit.message).to eq("Squash commit message\n")
+ end
- it 'persists squash_commit_sha' do
- squash_commit = merge_request.merge_commit.parents.last
+ it 'persists squash_commit_sha' do
+ squash_commit = merge_request.merge_commit.parents.last
- expect(merge_request.squash_commit_sha).to eq(squash_commit.id)
- end
+ expect(merge_request.squash_commit_sha).to eq(squash_commit.id)
end
+ end
- context 'when merge strategy is merge commit' do
- it 'persists merge_commit_sha and nullifies in_progress_merge_commit_sha' do
- service.execute(merge_request)
+ context 'when merge strategy is merge commit' do
+ it 'persists merge_commit_sha and merged_commit_sha and nullifies in_progress_merge_commit_sha' do
+ service.execute(merge_request)
- expect(merge_request.merge_commit_sha).not_to be_nil
- expect(merge_request.in_progress_merge_commit_sha).to be_nil
- end
+ expect(merge_request.merge_commit_sha).not_to be_nil
+ expect(merge_request.merged_commit_sha).to eq merge_request.merge_commit_sha
+ expect(merge_request.in_progress_merge_commit_sha).to be_nil
+ end
- it_behaves_like 'with valid params'
+ it_behaves_like 'with valid params'
- it_behaves_like 'squashing'
+ it_behaves_like 'squashing'
+ end
+
+ context 'when merge strategy is fast forward' do
+ before do
+ project.update!(merge_requests_ff_only_enabled: true)
end
- context 'when merge strategy is fast forward' do
- before do
- project.update!(merge_requests_ff_only_enabled: true)
- end
+ let(:merge_request) do
+ create(
+ :merge_request,
+ source_branch: 'flatten-dir',
+ target_branch: 'improve/awesome',
+ assignees: [user2],
+ author: create(:user)
+ )
+ end
- let(:merge_request) do
- create(
- :merge_request,
- source_branch: 'flatten-dir',
- target_branch: 'improve/awesome',
- assignees: [user2],
- author: create(:user)
- )
- end
+ it 'does not create merge_commit_sha, but persists merged_commit_sha and nullifies in_progress_merge_commit_sha' do
+ service.execute(merge_request)
- it 'does not create merge_commit_sha and nullifies in_progress_merge_commit_sha' do
- service.execute(merge_request)
+ expect(merge_request.merge_commit_sha).to be_nil
+ expect(merge_request.merged_commit_sha).not_to be_nil
+ expect(merge_request.merged_commit_sha).to eq merge_request.diff_head_sha
+ expect(merge_request.in_progress_merge_commit_sha).to be_nil
+ end
- expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.in_progress_merge_commit_sha).to be_nil
- end
+ it_behaves_like 'with valid params'
- it_behaves_like 'with valid params'
+ it 'updates squash_commit_sha and merged_commit_sha if it is a squash' do
+ expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
- it 'updates squash_commit_sha if it is a squash' do
- expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
+ merge_request.update!(squash: true)
- merge_request.update!(squash: true)
+ expect { service.execute(merge_request) }
+ .to change { merge_request.squash_commit_sha }
+ .from(nil)
- expect { service.execute(merge_request) }
- .to change { merge_request.squash_commit_sha }
- .from(nil)
+ expect(merge_request.merge_commit_sha).to be_nil
+ expect(merge_request.merged_commit_sha).to eq merge_request.squash_commit_sha
+ expect(merge_request.in_progress_merge_commit_sha).to be_nil
+ end
+ end
- expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.in_progress_merge_commit_sha).to be_nil
- end
+ context 'running the service once' do
+ let(:ref) { merge_request.to_reference(full: true) }
+ let(:jid) { SecureRandom.hex }
+
+ let(:messages) do
+ [
+ /#{ref} - Git merge started on JID #{jid}/,
+ /#{ref} - Git merge finished on JID #{jid}/,
+ /#{ref} - Post merge started on JID #{jid}/,
+ /#{ref} - Post merge finished on JID #{jid}/,
+ /#{ref} - Merge process finished on JID #{jid}/
+ ]
+ end
+
+ before do
+ merge_request.update!(merge_jid: jid)
+ ::Gitlab::ApplicationContext.push(caller_id: 'MergeWorker')
end
- context 'running the service once' do
- let(:ref) { merge_request.to_reference(full: true) }
- let(:jid) { SecureRandom.hex }
+ it 'logs status messages' do
+ allow(Gitlab::AppLogger).to receive(:info).and_call_original
- let(:messages) do
- [
- /#{ref} - Git merge started on JID #{jid}/,
- /#{ref} - Git merge finished on JID #{jid}/,
- /#{ref} - Post merge started on JID #{jid}/,
- /#{ref} - Post merge finished on JID #{jid}/,
- /#{ref} - Merge process finished on JID #{jid}/
- ]
+ messages.each do |message|
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ hash_including(
+ 'meta.caller_id' => 'MergeWorker',
+ message: message,
+ merge_request_info: ref
+ )
+ ).and_call_original
end
- before do
- merge_request.update!(merge_jid: jid)
- ::Gitlab::ApplicationContext.push(caller_id: 'MergeWorker')
- end
+ service.execute(merge_request)
+ end
+ end
- it 'logs status messages' do
- allow(Gitlab::AppLogger).to receive(:info).and_call_original
+ context 'running the service multiple time' do
+ it 'is idempotent' do
+ 2.times { service.execute(merge_request) }
- messages.each do |message|
- expect(Gitlab::AppLogger).to receive(:info).with(
- hash_including(
- 'meta.caller_id' => 'MergeWorker',
- message: message,
- merge_request_info: ref
- )
- ).and_call_original
- end
+ expect(merge_request.merge_error).to be_falsey
+ expect(merge_request).to be_valid
+ expect(merge_request).to be_merged
- service.execute(merge_request)
- end
+ commit_messages = project.repository.commits('master', limit: 2).map(&:message)
+ expect(commit_messages.uniq.size).to eq(2)
+ expect(merge_request.in_progress_merge_commit_sha).to be_nil
end
+ end
- context 'running the service multiple time' do
- it 'is idempotent' do
- 2.times { service.execute(merge_request) }
+ context 'when an invalid sha is passed' do
+ let(:merge_request) do
+ create(
+ :merge_request,
+ :simple,
+ author: user2,
+ assignees: [user2],
+ squash: true,
+ source_branch: 'improve/awesome',
+ target_branch: 'fix'
+ )
+ end
- expect(merge_request.merge_error).to be_falsey
- expect(merge_request).to be_valid
- expect(merge_request).to be_merged
+ let(:merge_params) do
+ { sha: merge_request.commits.second.sha }
+ end
- commit_messages = project.repository.commits('master', limit: 2).map(&:message)
- expect(commit_messages.uniq.size).to eq(2)
- expect(merge_request.in_progress_merge_commit_sha).to be_nil
- end
+ it 'does not merge the MR' do
+ service.execute(merge_request)
+
+ expect(merge_request).not_to be_merged
+ expect(merge_request.merge_error).to match(/Branch has been updated/)
end
+ end
- context 'when an invalid sha is passed' do
- let(:merge_request) do
- create(
- :merge_request,
- :simple,
- author: user2,
- assignees: [user2],
- squash: true,
- source_branch: 'improve/awesome',
- target_branch: 'fix'
- )
- end
+ context 'when the `sha` param is missing' do
+ let(:merge_params) { {} }
- let(:merge_params) do
- { sha: merge_request.commits.second.sha }
- end
+ it 'returns the error' do
+ merge_error = 'Branch has been updated since the merge was requested. '\
+ 'Please review the changes.'
- it 'does not merge the MR' do
- service.execute(merge_request)
+ expect { service.execute(merge_request) }
+ .to change { merge_request.merge_error }
+ .from(nil).to(merge_error)
+ end
+ end
- expect(merge_request).not_to be_merged
- expect(merge_request.merge_error).to match(/Branch has been updated/)
- end
+ context 'closes related issues' do
+ before do
+ allow(project).to receive(:default_branch).and_return(merge_request.target_branch)
end
- context 'when the `sha` param is missing' do
- let(:merge_params) { {} }
+ it 'closes GitLab issue tracker issues', :sidekiq_inline do
+ issue = create :issue, project: project
+ commit = double('commit', safe_message: "Fixes #{issue.to_reference}", date: Time.current, authored_date: Time.current)
+ allow(merge_request).to receive(:commits).and_return([commit])
+ merge_request.cache_merge_request_closes_issues!
- it 'returns the error' do
- merge_error = 'Branch has been updated since the merge was requested. '\
- 'Please review the changes.'
+ service.execute(merge_request)
- expect { service.execute(merge_request) }
- .to change { merge_request.merge_error }
- .from(nil).to(merge_error)
- end
+ expect(issue.reload.closed?).to be_truthy
end
- context 'closes related issues' do
+ context 'with Jira integration' do
+ include JiraIntegrationHelpers
+
+ let(:jira_tracker) { project.create_jira_integration }
+ let(:jira_issue) { ExternalIssue.new('JIRA-123', project) }
+ let(:commit) { double('commit', safe_message: "Fixes #{jira_issue.to_reference}") }
+
before do
- allow(project).to receive(:default_branch).and_return(merge_request.target_branch)
+ stub_jira_integration_test
+ project.update!(has_external_issue_tracker: true)
+ jira_integration_settings
+ stub_jira_urls(jira_issue.id)
+ allow(merge_request).to receive(:commits).and_return([commit])
end
- it 'closes GitLab issue tracker issues', :sidekiq_inline do
- issue = create :issue, project: project
- commit = double('commit', safe_message: "Fixes #{issue.to_reference}", date: Time.current, authored_date: Time.current)
+ it 'closes issues on Jira issue tracker' do
+ jira_issue = ExternalIssue.new('JIRA-123', project)
+ stub_jira_urls(jira_issue)
+ commit = double('commit', safe_message: "Fixes #{jira_issue.to_reference}")
allow(merge_request).to receive(:commits).and_return([commit])
- merge_request.cache_merge_request_closes_issues!
- service.execute(merge_request)
+ expect_any_instance_of(Integrations::Jira).to receive(:close_issue).with(merge_request, jira_issue, user).once
- expect(issue.reload.closed?).to be_truthy
+ service.execute(merge_request)
end
- context 'with Jira integration' do
- include JiraIntegrationHelpers
-
- let(:jira_tracker) { project.create_jira_integration }
- let(:jira_issue) { ExternalIssue.new('JIRA-123', project) }
- let(:commit) { double('commit', safe_message: "Fixes #{jira_issue.to_reference}") }
-
- before do
- stub_jira_integration_test
- project.update!(has_external_issue_tracker: true)
- jira_integration_settings
- stub_jira_urls(jira_issue.id)
- allow(merge_request).to receive(:commits).and_return([commit])
- end
-
- it 'closes issues on Jira issue tracker' do
- jira_issue = ExternalIssue.new('JIRA-123', project)
+ context 'wrong issue markdown' do
+ it 'does not close issues on Jira issue tracker' do
+ jira_issue = ExternalIssue.new('#JIRA-123', project)
stub_jira_urls(jira_issue)
commit = double('commit', safe_message: "Fixes #{jira_issue.to_reference}")
allow(merge_request).to receive(:commits).and_return([commit])
- expect_any_instance_of(Integrations::Jira).to receive(:close_issue).with(merge_request, jira_issue, user).once
+ expect_any_instance_of(Integrations::Jira).not_to receive(:close_issue)
service.execute(merge_request)
end
+ end
+ end
+ end
- context 'wrong issue markdown' do
- it 'does not close issues on Jira issue tracker' do
- jira_issue = ExternalIssue.new('#JIRA-123', project)
- stub_jira_urls(jira_issue)
- commit = double('commit', safe_message: "Fixes #{jira_issue.to_reference}")
- allow(merge_request).to receive(:commits).and_return([commit])
+ context 'closes related todos' do
+ let(:merge_request) { create(:merge_request, assignees: [user], author: user) }
+ let(:project) { merge_request.project }
- expect_any_instance_of(Integrations::Jira).not_to receive(:close_issue)
+ let!(:todo) do
+ create(:todo, :assigned,
+ project: project,
+ author: user,
+ user: user,
+ target: merge_request)
+ end
- service.execute(merge_request)
- end
- end
+ before do
+ allow(service).to receive(:execute_hooks)
+
+ perform_enqueued_jobs do
+ service.execute(merge_request)
+ todo.reload
end
end
- context 'closes related todos' do
- let(:merge_request) { create(:merge_request, assignees: [user], author: user) }
- let(:project) { merge_request.project }
+ it { expect(todo).to be_done }
+ end
- let!(:todo) do
- create(:todo, :assigned,
- project: project,
- author: user,
- user: user,
- target: merge_request)
+ context 'source branch removal' do
+ context 'when the source branch is protected' do
+ let(:service) do
+ described_class.new(project: project, current_user: user, params: merge_params.merge('should_remove_source_branch' => true))
end
before do
- allow(service).to receive(:execute_hooks)
-
- perform_enqueued_jobs do
- service.execute(merge_request)
- todo.reload
- end
+ create(:protected_branch, project: project, name: merge_request.source_branch)
end
- it { expect(todo).to be_done }
+ it 'does not delete the source branch' do
+ expect(::Branches::DeleteService).not_to receive(:new)
+
+ service.execute(merge_request)
+ end
end
- context 'source branch removal' do
- context 'when the source branch is protected' do
- let(:service) do
- described_class.new(project: project, current_user: user, params: merge_params.merge('should_remove_source_branch' => true))
- end
+ context 'when the source branch is the default branch' do
+ let(:service) do
+ described_class.new(project: project, current_user: user, params: merge_params.merge('should_remove_source_branch' => true))
+ end
+ before do
+ allow(project).to receive(:root_ref?).with(merge_request.source_branch).and_return(true)
+ end
+
+ it 'does not delete the source branch' do
+ expect(::Branches::DeleteService).not_to receive(:new)
+ service.execute(merge_request)
+ end
+ end
+
+ context 'when the source branch can be removed' do
+ context 'when MR author set the source branch to be removed' do
before do
- create(:protected_branch, project: project, name: merge_request.source_branch)
+ merge_request.update_attribute(:merge_params, { 'force_remove_source_branch' => '1' })
end
- it 'does not delete the source branch' do
- expect(::Branches::DeleteService).not_to receive(:new)
+ # Not a real use case. When a merger merges a MR , merge param 'should_remove_source_branch' is defined
+ it 'removes the source branch using the author user' do
+ expect(::MergeRequests::DeleteSourceBranchWorker).to receive(:perform_async).with(merge_request.id, merge_request.source_branch_sha, merge_request.author.id)
service.execute(merge_request)
+
+ expect(merge_request.reload.should_remove_source_branch?).to be nil
+ end
+
+ context 'when the merger set the source branch not to be removed' do
+ let(:service) { described_class.new(project: project, current_user: user, params: merge_params.merge('should_remove_source_branch' => false)) }
+
+ it 'does not delete the source branch' do
+ expect(::MergeRequests::DeleteSourceBranchWorker).not_to receive(:perform_async)
+
+ service.execute(merge_request)
+
+ expect(merge_request.reload.should_remove_source_branch?).to be false
+ end
end
end
- context 'when the source branch is the default branch' do
+ context 'when MR merger set the source branch to be removed' do
let(:service) do
described_class.new(project: project, current_user: user, params: merge_params.merge('should_remove_source_branch' => true))
end
- before do
- allow(project).to receive(:root_ref?).with(merge_request.source_branch).and_return(true)
- end
+ it 'removes the source branch using the current user' do
+ expect(::MergeRequests::DeleteSourceBranchWorker).to receive(:perform_async).with(merge_request.id, merge_request.source_branch_sha, user.id)
- it 'does not delete the source branch' do
- expect(::Branches::DeleteService).not_to receive(:new)
service.execute(merge_request)
+
+ expect(merge_request.reload.should_remove_source_branch?).to be true
end
end
+ end
+ end
- context 'when the source branch can be removed' do
- context 'when MR author set the source branch to be removed' do
- before do
- merge_request.update_attribute(:merge_params, { 'force_remove_source_branch' => '1' })
- end
+ context 'error handling' do
+ before do
+ allow(Gitlab::AppLogger).to receive(:error)
+ end
- # Not a real use case. When a merger merges a MR , merge param 'should_remove_source_branch' is defined
- it 'removes the source branch using the author user' do
- expect(::MergeRequests::DeleteSourceBranchWorker).to receive(:perform_async).with(merge_request.id, merge_request.source_branch_sha, merge_request.author.id)
+ context 'when source is missing' do
+ it 'logs and saves error' do
+ allow(merge_request).to receive(:diff_head_sha) { nil }
- service.execute(merge_request)
+ error_message = 'No source for merge'
- expect(merge_request.reload.should_remove_source_branch?).to be nil
- end
+ service.execute(merge_request)
+
+ expect(merge_request.merge_error).to eq(error_message)
+ expect(Gitlab::AppLogger).to have_received(:error).with(
+ hash_including(
+ merge_request_info: merge_request.to_reference(full: true),
+ message: a_string_matching(error_message)
+ )
+ )
+ end
+ end
- context 'when the merger set the source branch not to be removed' do
- let(:service) { described_class.new(project: project, current_user: user, params: merge_params.merge('should_remove_source_branch' => false)) }
+ it 'logs and saves error if there is an exception' do
+ error_message = 'error message'
- it 'does not delete the source branch' do
- expect(::MergeRequests::DeleteSourceBranchWorker).not_to receive(:perform_async)
+ allow_next_instance_of(MergeRequests::MergeStrategies::FromSourceBranch) do |strategy|
+ allow(strategy).to receive(:execute_git_merge!).and_raise(error_message)
+ end
- service.execute(merge_request)
+ service.execute(merge_request)
- expect(merge_request.reload.should_remove_source_branch?).to be false
- end
- end
- end
+ expect(merge_request.merge_error).to eq(described_class::GENERIC_ERROR_MESSAGE)
+ expect(Gitlab::AppLogger).to have_received(:error).with(
+ hash_including(
+ merge_request_info: merge_request.to_reference(full: true),
+ message: a_string_matching(error_message)
+ )
+ )
+ end
- context 'when MR merger set the source branch to be removed' do
- let(:service) do
- described_class.new(project: project, current_user: user, params: merge_params.merge('should_remove_source_branch' => true))
- end
+ it 'logs and saves error if user is not authorized' do
+ stub_exclusive_lease
- it 'removes the source branch using the current user' do
- expect(::MergeRequests::DeleteSourceBranchWorker).to receive(:perform_async).with(merge_request.id, merge_request.source_branch_sha, user.id)
+ unauthorized_user = create(:user)
+ project.add_reporter(unauthorized_user)
- service.execute(merge_request)
+ service = described_class.new(project: project, current_user: unauthorized_user)
- expect(merge_request.reload.should_remove_source_branch?).to be true
- end
- end
- end
+ service.execute(merge_request)
+
+ expect(merge_request.merge_error)
+ .to eq('You are not allowed to merge this merge request')
end
- context 'error handling' do
- before do
- allow(Gitlab::AppLogger).to receive(:error)
+ it 'logs and saves error if there is an PreReceiveError exception' do
+ error_message = 'error message'
+
+ allow_next_instance_of(MergeRequests::MergeStrategies::FromSourceBranch) do |strategy|
+ allow(strategy).to receive(:execute_git_merge!).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}")
end
- context 'when source is missing' do
- it 'logs and saves error' do
- allow(merge_request).to receive(:diff_head_sha) { nil }
+ service.execute(merge_request)
- error_message = 'No source for merge'
+ expect(merge_request.merge_error).to include('Something went wrong during merge pre-receive hook')
+ expect(Gitlab::AppLogger).to have_received(:error).with(
+ hash_including(
+ merge_request_info: merge_request.to_reference(full: true),
+ message: a_string_matching(error_message)
+ )
+ )
+ end
- service.execute(merge_request)
+ it 'logs and saves error if commit is not created' do
+ allow_any_instance_of(Repository).to receive(:merge).and_return(false)
+ allow(service).to receive(:execute_hooks)
- expect(merge_request.merge_error).to eq(error_message)
- expect(Gitlab::AppLogger).to have_received(:error).with(
- hash_including(
- merge_request_info: merge_request.to_reference(full: true),
- message: a_string_matching(error_message)
- )
- )
- end
- end
+ service.execute(merge_request)
- it 'logs and saves error if there is an exception' do
- error_message = 'error message'
+ expect(merge_request).to be_open
+ expect(merge_request.merge_commit_sha).to be_nil
+ expect(merge_request.merge_error).to include(described_class::GENERIC_ERROR_MESSAGE)
+ expect(Gitlab::AppLogger).to have_received(:error).with(
+ hash_including(
+ merge_request_info: merge_request.to_reference(full: true),
+ message: a_string_matching(described_class::GENERIC_ERROR_MESSAGE)
+ )
+ )
+ end
- allow_next_instance_of(MergeRequests::MergeStrategies::FromSourceBranch) do |strategy|
- allow(strategy).to receive(:execute_git_merge!).and_raise(error_message)
- end
- # we can remove these allows upon refactor_merge_service cleanup
- allow(service).to receive(:repository).and_raise(error_message)
- allow(service).to receive(:execute_hooks)
+ context 'when squashing is required' do
+ before do
+ merge_request.update!(source_branch: 'master', target_branch: 'feature')
+ merge_request.target_project.project_setting.squash_always!
+ end
+
+ it 'raises an error if squashing is not done' do
+ error_message = 'requires squashing commits'
service.execute(merge_request)
- expect(merge_request.merge_error).to eq(described_class::GENERIC_ERROR_MESSAGE)
+ expect(merge_request).to be_open
+
+ expect(merge_request.merge_commit_sha).to be_nil
+ expect(merge_request.squash_commit_sha).to be_nil
+ expect(merge_request.merge_error).to include(error_message)
expect(Gitlab::AppLogger).to have_received(:error).with(
hash_including(
merge_request_info: merge_request.to_reference(full: true),
@@ -446,34 +515,25 @@ RSpec.describe MergeRequests::MergeService, feature_category: :code_review_workf
)
)
end
+ end
- it 'logs and saves error if user is not authorized' do
- stub_exclusive_lease
-
- unauthorized_user = create(:user)
- project.add_reporter(unauthorized_user)
-
- service = described_class.new(project: project, current_user: unauthorized_user)
-
- service.execute(merge_request)
-
- expect(merge_request.merge_error)
- .to eq('You are not allowed to merge this merge request')
+ context 'when squashing' do
+ before do
+ merge_request.update!(source_branch: 'master', target_branch: 'feature')
end
- it 'logs and saves error if there is an PreReceiveError exception' do
- error_message = 'error message'
+ it 'logs and saves error if there is an error when squashing' do
+ error_message = 'Squashing failed: Squash the commits locally, resolve any conflicts, then push the branch.'
- allow_next_instance_of(MergeRequests::MergeStrategies::FromSourceBranch) do |strategy|
- allow(strategy).to receive(:execute_git_merge!).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}")
- end
- # we can remove these allows upon refactor_merge_service cleanup
- allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}")
- allow(service).to receive(:execute_hooks)
+ allow_any_instance_of(MergeRequests::SquashService).to receive(:squash!).and_return(nil)
+ merge_request.update!(squash: true)
service.execute(merge_request)
- expect(merge_request.merge_error).to include('Something went wrong during merge pre-receive hook')
+ expect(merge_request).to be_open
+ expect(merge_request.merge_commit_sha).to be_nil
+ expect(merge_request.squash_commit_sha).to be_nil
+ expect(merge_request.merge_error).to include(error_message)
expect(Gitlab::AppLogger).to have_received(:error).with(
hash_including(
merge_request_info: merge_request.to_reference(full: true),
@@ -482,65 +542,69 @@ RSpec.describe MergeRequests::MergeService, feature_category: :code_review_workf
)
end
- it 'logs and saves error if commit is not created' do
- allow_any_instance_of(Repository).to receive(:merge).and_return(false)
- allow(service).to receive(:execute_hooks)
+ it 'logs and saves error if there is an PreReceiveError exception' do
+ error_message = 'error message'
+
+ allow_next_instance_of(MergeRequests::MergeStrategies::FromSourceBranch) do |strategy|
+ allow(strategy).to receive(:execute_git_merge!).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}")
+ end
+ merge_request.update!(squash: true)
service.execute(merge_request)
expect(merge_request).to be_open
expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.merge_error).to include(described_class::GENERIC_ERROR_MESSAGE)
+ expect(merge_request.squash_commit_sha).to be_nil
+ expect(merge_request.merge_error).to include('Something went wrong during merge pre-receive hook')
expect(Gitlab::AppLogger).to have_received(:error).with(
hash_including(
merge_request_info: merge_request.to_reference(full: true),
- message: a_string_matching(described_class::GENERIC_ERROR_MESSAGE)
+ message: a_string_matching(error_message)
)
)
end
- context 'when squashing is required' do
+ context 'when fast-forward merge is not allowed' do
before do
- merge_request.update!(source_branch: 'master', target_branch: 'feature')
- merge_request.target_project.project_setting.squash_always!
+ allow_any_instance_of(Repository).to receive(:ancestor?).and_return(nil)
end
- it 'raises an error if squashing is not done' do
- error_message = 'requires squashing commits'
+ %w(semi-linear ff).each do |merge_method|
+ it "logs and saves error if merge is #{merge_method} only" do
+ merge_method = 'rebase_merge' if merge_method == 'semi-linear'
+ merge_request.project.update!(merge_method: merge_method)
+ error_message = 'Only fast-forward merge is allowed for your project. Please update your source branch'
+ allow(service).to receive(:execute_hooks)
+ expect(lease).to receive(:cancel)
- service.execute(merge_request)
-
- expect(merge_request).to be_open
+ service.execute(merge_request)
- expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.squash_commit_sha).to be_nil
- expect(merge_request.merge_error).to include(error_message)
- expect(Gitlab::AppLogger).to have_received(:error).with(
- hash_including(
- merge_request_info: merge_request.to_reference(full: true),
- message: a_string_matching(error_message)
+ expect(merge_request).to be_open
+ expect(merge_request.merge_commit_sha).to be_nil
+ expect(merge_request.squash_commit_sha).to be_nil
+ expect(merge_request.merge_error).to include(error_message)
+ expect(Gitlab::AppLogger).to have_received(:error).with(
+ hash_including(
+ merge_request_info: merge_request.to_reference(full: true),
+ message: a_string_matching(error_message)
+ )
)
- )
+ end
end
end
+ end
- context 'when squashing' do
+ context 'when not mergeable' do
+ let!(:error_message) { 'Merge request is not mergeable' }
+
+ context 'with failing CI' do
before do
- merge_request.update!(source_branch: 'master', target_branch: 'feature')
+ allow(merge_request).to receive(:mergeable_ci_state?) { false }
end
- it 'logs and saves error if there is an error when squashing' do
- error_message = 'Squashing failed: Squash the commits locally, resolve any conflicts, then push the branch.'
-
- allow_any_instance_of(MergeRequests::SquashService).to receive(:squash!).and_return(nil)
- merge_request.update!(squash: true)
-
+ it 'logs and saves error' do
service.execute(merge_request)
- expect(merge_request).to be_open
- expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.squash_commit_sha).to be_nil
- expect(merge_request.merge_error).to include(error_message)
expect(Gitlab::AppLogger).to have_received(:error).with(
hash_including(
merge_request_info: merge_request.to_reference(full: true),
@@ -548,24 +612,16 @@ RSpec.describe MergeRequests::MergeService, feature_category: :code_review_workf
)
)
end
+ end
- it 'logs and saves error if there is an PreReceiveError exception' do
- error_message = 'error message'
-
- allow_next_instance_of(MergeRequests::MergeStrategies::FromSourceBranch) do |strategy|
- allow(strategy).to receive(:execute_git_merge!).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}")
- end
- # we can remove these allows upon refactor_merge_service cleanup
- allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}")
- allow(service).to receive(:execute_hooks)
- merge_request.update!(squash: true)
+ context 'with unresolved discussions' do
+ before do
+ allow(merge_request).to receive(:mergeable_discussions_state?) { false }
+ end
+ it 'logs and saves error' do
service.execute(merge_request)
- expect(merge_request).to be_open
- expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.squash_commit_sha).to be_nil
- expect(merge_request.merge_error).to include('Something went wrong during merge pre-receive hook')
expect(Gitlab::AppLogger).to have_received(:error).with(
hash_including(
merge_request_info: merge_request.to_reference(full: true),
@@ -574,102 +630,35 @@ RSpec.describe MergeRequests::MergeService, feature_category: :code_review_workf
)
end
- context 'when fast-forward merge is not allowed' do
- before do
- allow_any_instance_of(Repository).to receive(:ancestor?).and_return(nil)
- end
-
- %w(semi-linear ff).each do |merge_method|
- it "logs and saves error if merge is #{merge_method} only" do
- merge_method = 'rebase_merge' if merge_method == 'semi-linear'
- merge_request.project.update!(merge_method: merge_method)
- error_message = 'Only fast-forward merge is allowed for your project. Please update your source branch'
- allow(service).to receive(:execute_hooks)
- expect(lease).to receive(:cancel)
-
- service.execute(merge_request)
-
- expect(merge_request).to be_open
- expect(merge_request.merge_commit_sha).to be_nil
- expect(merge_request.squash_commit_sha).to be_nil
- expect(merge_request.merge_error).to include(error_message)
- expect(Gitlab::AppLogger).to have_received(:error).with(
- hash_including(
- merge_request_info: merge_request.to_reference(full: true),
- message: a_string_matching(error_message)
- )
- )
- end
- end
- end
- end
-
- context 'when not mergeable' do
- let!(:error_message) { 'Merge request is not mergeable' }
-
- context 'with failing CI' do
- before do
- allow(merge_request).to receive(:mergeable_ci_state?) { false }
- end
-
- it 'logs and saves error' do
- service.execute(merge_request)
-
- expect(Gitlab::AppLogger).to have_received(:error).with(
- hash_including(
- merge_request_info: merge_request.to_reference(full: true),
- message: a_string_matching(error_message)
- )
- )
- end
- end
-
- context 'with unresolved discussions' do
- before do
- allow(merge_request).to receive(:mergeable_discussions_state?) { false }
- end
-
- it 'logs and saves error' do
- service.execute(merge_request)
-
- expect(Gitlab::AppLogger).to have_received(:error).with(
- hash_including(
- merge_request_info: merge_request.to_reference(full: true),
- message: a_string_matching(error_message)
- )
- )
- end
-
- context 'when passing `skip_discussions_check: true` as `options` parameter' do
- it 'merges the merge request' do
- service.execute(merge_request, skip_discussions_check: true)
+ context 'when passing `skip_discussions_check: true` as `options` parameter' do
+ it 'merges the merge request' do
+ service.execute(merge_request, skip_discussions_check: true)
- expect(merge_request).to be_valid
- expect(merge_request).to be_merged
- end
+ expect(merge_request).to be_valid
+ expect(merge_request).to be_merged
end
end
end
+ end
- context 'when passing `check_mergeability_retry_lease: true` as `options` parameter' do
- it 'call mergeable? with check_mergeability_retry_lease' do
- expect(merge_request).to receive(:mergeable?).with(hash_including(check_mergeability_retry_lease: true)).and_call_original
+ context 'when passing `check_mergeability_retry_lease: true` as `options` parameter' do
+ it 'call mergeable? with check_mergeability_retry_lease' do
+ expect(merge_request).to receive(:mergeable?).with(hash_including(check_mergeability_retry_lease: true)).and_call_original
- service.execute(merge_request, check_mergeability_retry_lease: true)
- end
+ service.execute(merge_request, check_mergeability_retry_lease: true)
end
end
+ end
- context 'when the other sidekiq worker has already been running' do
- before do
- stub_exclusive_lease_taken(lease_key)
- end
+ context 'when the other sidekiq worker has already been running' do
+ before do
+ stub_exclusive_lease_taken(lease_key)
+ end
- it 'does not execute service' do
- expect(service).not_to receive(:commit)
+ it 'does not execute service' do
+ expect(service).not_to receive(:commit)
- service.execute(merge_request)
- end
+ service.execute(merge_request)
end
end
end
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 06932af26dc..d5b7b56ccdd 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -913,7 +913,7 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor
subject { service.execute(oldrev, newrev, 'refs/heads/merge-commit-analyze-before') }
context 'feature enabled' do
- it "updates merge requests' merge_commits" do
+ it "updates merge requests' merge_commit and merged_commit values", :aggregate_failures do
expect(Gitlab::BranchPushMergeCommitAnalyzer).to receive(:new).and_wrap_original do |original_method, commits|
expect(commits.map(&:id)).to eq(%w{646ece5cfed840eca0a4feb21bcd6a81bb19bda3 29284d9bcc350bcae005872d0be6edd016e2efb5 5f82584f0a907f3b30cfce5bb8df371454a90051 8a994512e8c8f0dfcf22bb16df6e876be7a61036 689600b91aabec706e657e38ea706ece1ee8268f db46a1c5a5e474aa169b6cdb7a522d891bc4c5f9})
@@ -927,6 +927,11 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor
expect(merge_request.merge_commit.id).to eq('646ece5cfed840eca0a4feb21bcd6a81bb19bda3')
expect(merge_request_side_branch.merge_commit.id).to eq('29284d9bcc350bcae005872d0be6edd016e2efb5')
+ # we need to use read_attribute to bypass the overridden
+ # #merged_commit_sha method, which contains a fallback to
+ # #merge_commit_sha
+ expect(merge_request.read_attribute(:merged_commit_sha)).to eq('646ece5cfed840eca0a4feb21bcd6a81bb19bda3')
+ expect(merge_request_side_branch.read_attribute(:merged_commit_sha)).to eq('29284d9bcc350bcae005872d0be6edd016e2efb5')
end
end
end
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 2f6db13a041..72e41f7b814 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -1301,41 +1301,39 @@ RSpec.describe MergeRequests::UpdateService, :mailer, feature_category: :code_re
end
context 'updating labels' do
- let(:label_a) { label }
- let(:label_b) { create(:label, title: 'b', project: project) }
- let(:label_c) { create(:label, title: 'c', project: project) }
- let(:label_locked) { create(:label, title: 'locked', project: project, lock_on_merge: true) }
- let(:issuable) { merge_request }
+ context 'when merge request is not merged' do
+ let(:label_a) { label }
+ let(:label_b) { create(:label, title: 'b', project: project) }
+ let(:label_c) { create(:label, title: 'c', project: project) }
+ let(:label_locked) { create(:label, title: 'locked', project: project, lock_on_merge: true) }
+ let(:issuable) { merge_request }
- it_behaves_like 'updating issuable labels'
- it_behaves_like 'keeps issuable labels sorted after update'
- it_behaves_like 'broadcasting issuable labels updates'
+ it_behaves_like 'updating issuable labels'
+ it_behaves_like 'keeps issuable labels sorted after update'
+ it_behaves_like 'broadcasting issuable labels updates'
+ end
context 'when merge request has been merged' do
- context 'when remove_label_ids contains a locked label' do
- let(:params) { { remove_label_ids: [label_locked.id] } }
+ let(:label_a) { create(:label, title: 'a', project: project, lock_on_merge: true) }
+ let(:label_b) { create(:label, title: 'b', project: project, lock_on_merge: true) }
+ let(:label_c) { create(:label, title: 'c', project: project, lock_on_merge: true) }
+ let(:label_unlocked) { create(:label, title: 'unlocked', project: project) }
+ let(:issuable) { merge_request }
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(enforce_locked_labels_on_merge: false)
- end
+ before do
+ merge_request.update!(state: 'merged')
+ end
- it 'removes locked labels' do
- merge_request.update!(state: 'merged', labels: [label_a, label_locked])
- update_issuable(params)
+ it_behaves_like 'updating merged MR with locked labels'
- expect(merge_request.label_ids).to contain_exactly(label_a.id)
- end
- end
-
- context 'when feature flag is enabled' do
- it 'does not remove locked labels' do
- merge_request.update!(state: 'merged', labels: [label_a, label_locked])
- update_issuable(params)
+ context 'when feature flag is disabled' do
+ let(:label_locked) { create(:label, title: 'locked', project: project, lock_on_merge: true) }
- expect(merge_request.label_ids).to contain_exactly(label_a.id, label_locked.id)
- end
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: false)
end
+
+ it_behaves_like 'updating issuable labels'
end
end
diff --git a/spec/services/metrics/global_metrics_update_service_spec.rb b/spec/services/metrics/global_metrics_update_service_spec.rb
deleted file mode 100644
index 38c7f9282d9..00000000000
--- a/spec/services/metrics/global_metrics_update_service_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Metrics::GlobalMetricsUpdateService, :prometheus, feature_category: :metrics do
- describe '#execute' do
- it 'sets gitlab_maintenance_mode gauge metric' do
- metric = subject.maintenance_mode_metric
- expect(Gitlab).to receive(:maintenance_mode?).and_return(true)
-
- expect { subject.execute }.to change { metric.get }.from(0).to(1)
- end
- end
-end
diff --git a/spec/services/metrics/sample_metrics_service_spec.rb b/spec/services/metrics/sample_metrics_service_spec.rb
deleted file mode 100644
index 3442b4303db..00000000000
--- a/spec/services/metrics/sample_metrics_service_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Metrics::SampleMetricsService, feature_category: :metrics do
- describe 'query' do
- let(:range_start) { '2019-12-02T23:31:45.000Z' }
- let(:range_end) { '2019-12-03T00:01:45.000Z' }
-
- subject { described_class.new(identifier, range_start: range_start, range_end: range_end).query }
-
- context 'when the file is not found' do
- let(:identifier) { nil }
-
- it { is_expected.to be_nil }
- end
-
- context 'when the file is found' do
- let(:identifier) { 'sample_metric_query_result' }
- let(:source) { File.join(Rails.root, 'spec/fixtures/gitlab/sample_metrics', "#{identifier}.yml") }
- let(:destination) { File.join(Rails.root, Metrics::SampleMetricsService::DIRECTORY, "#{identifier}.yml") }
-
- around do |example|
- FileUtils.mkdir_p(Metrics::SampleMetricsService::DIRECTORY)
- FileUtils.cp(source, destination)
-
- example.run
- ensure
- FileUtils.rm(destination)
- end
-
- subject { described_class.new(identifier, range_start: range_start, range_end: range_end).query }
-
- it 'loads data from the sample file correctly' do
- expect(subject).to eq(YAML.load_file(source)[30])
- end
- end
-
- context 'when the identifier is for a path outside of sample_metrics' do
- let(:identifier) { '../config/secrets' }
-
- it { is_expected.to be_nil }
- end
- end
-end
diff --git a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
deleted file mode 100644
index 8a2ecd5c3e0..00000000000
--- a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
+++ /dev/null
@@ -1,216 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Namespaces::InProductMarketingEmailsService, '#execute', feature_category: :purchase do
- subject(:execute_service) { described_class.new(track, interval).execute }
-
- let(:track) { :create }
- let(:interval) { 1 }
-
- let(:frozen_time) { Time.zone.parse('23 Mar 2021 10:14:40 UTC') }
- let(:previous_action_completed_at) { frozen_time - 2.days }
- let(:current_action_completed_at) { nil }
- let(:user_can_perform_current_track_action) { true }
- let(:actions_completed) { { created_at: previous_action_completed_at, git_write_at: current_action_completed_at } }
-
- let_it_be(:group) { create(:group) }
- let_it_be(:user) { create(:user, email_opted_in: true) }
-
- before do
- travel_to(frozen_time)
- create(:onboarding_progress, namespace: group, **actions_completed)
- group.add_developer(user)
- allow(Ability).to receive(:allowed?).with(user, anything, anything).and_return(user_can_perform_current_track_action)
- allow(Notify).to receive(:in_product_marketing_email).and_return(double(deliver_later: nil))
- end
-
- RSpec::Matchers.define :send_in_product_marketing_email do |*args|
- match do
- expect(Notify).to have_received(:in_product_marketing_email).with(*args).once
- end
-
- match_when_negated do
- expect(Notify).not_to have_received(:in_product_marketing_email)
- end
- end
-
- context 'for each track and series with the right conditions' do
- using RSpec::Parameterized::TableSyntax
-
- where(:track, :interval, :actions_completed) do
- :create | 1 | { created_at: frozen_time - 2.days }
- :create | 5 | { created_at: frozen_time - 6.days }
- :create | 10 | { created_at: frozen_time - 11.days }
- :team_short | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days }
- :trial_short | 2 | { created_at: frozen_time - 3.days, git_write_at: frozen_time - 3.days }
- :admin_verify | 3 | { created_at: frozen_time - 4.days, git_write_at: frozen_time - 4.days }
- :verify | 4 | { created_at: frozen_time - 5.days, git_write_at: frozen_time - 5.days }
- :verify | 8 | { created_at: frozen_time - 9.days, git_write_at: frozen_time - 9.days }
- :verify | 13 | { created_at: frozen_time - 14.days, git_write_at: frozen_time - 14.days }
- :trial | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days, pipeline_created_at: frozen_time - 2.days }
- :trial | 5 | { created_at: frozen_time - 6.days, git_write_at: frozen_time - 6.days, pipeline_created_at: frozen_time - 6.days }
- :trial | 10 | { created_at: frozen_time - 11.days, git_write_at: frozen_time - 11.days, pipeline_created_at: frozen_time - 11.days }
- :team | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days, pipeline_created_at: frozen_time - 2.days, trial_started_at: frozen_time - 2.days }
- :team | 5 | { created_at: frozen_time - 6.days, git_write_at: frozen_time - 6.days, pipeline_created_at: frozen_time - 6.days, trial_started_at: frozen_time - 6.days }
- :team | 10 | { created_at: frozen_time - 11.days, git_write_at: frozen_time - 11.days, pipeline_created_at: frozen_time - 11.days, trial_started_at: frozen_time - 11.days }
- end
-
- with_them do
- it { is_expected.to send_in_product_marketing_email(user.id, group.id, track, described_class::TRACKS[track][:interval_days].index(interval)) }
- end
- end
-
- context 'when initialized with a different track' do
- let(:track) { :team_short }
-
- it { is_expected.not_to send_in_product_marketing_email }
-
- context 'when the previous track actions have been completed' do
- let(:current_action_completed_at) { frozen_time - 2.days }
-
- it { is_expected.to send_in_product_marketing_email(user.id, group.id, track, 0) }
- end
- end
-
- context 'when initialized with a different interval' do
- let(:interval) { 5 }
-
- it { is_expected.not_to send_in_product_marketing_email }
-
- context 'when the previous track action was completed within the intervals range' do
- let(:previous_action_completed_at) { frozen_time - 6.days }
-
- it { is_expected.to send_in_product_marketing_email(user.id, group.id, :create, 1) }
- end
- end
-
- context 'when the previous track action is not yet completed' do
- let(:previous_action_completed_at) { nil }
-
- it { is_expected.not_to send_in_product_marketing_email }
- end
-
- context 'when the previous track action is completed outside the intervals range' do
- let(:previous_action_completed_at) { frozen_time - 3.days }
-
- it { is_expected.not_to send_in_product_marketing_email }
- end
-
- context 'when the current track action is completed' do
- let(:current_action_completed_at) { frozen_time }
-
- it { is_expected.not_to send_in_product_marketing_email }
- end
-
- context "when the user cannot perform the current track's action" do
- let(:user_can_perform_current_track_action) { false }
-
- it { is_expected.not_to send_in_product_marketing_email }
- end
-
- context 'when the user has not opted into marketing emails' do
- let(:user) { create(:user, email_opted_in: false) }
-
- it { is_expected.not_to send_in_product_marketing_email }
- end
-
- describe 'do not send emails twice' do
- subject { described_class.send_for_all_tracks_and_intervals }
-
- let(:user) { create(:user, email_opted_in: true) }
-
- context 'when user already got a specific email' do
- before do
- create(:in_product_marketing_email, user: user, track: track, series: 0)
- end
-
- it { is_expected.not_to send_in_product_marketing_email(user.id, anything, track, 0) }
- end
-
- context 'when user already got sent the whole track' do
- before do
- 0.upto(2) do |series|
- create(:in_product_marketing_email, user: user, track: track, series: series)
- end
- end
-
- it 'does not send any of the emails anymore', :aggregate_failures do
- 0.upto(2) do |series|
- expect(subject).not_to send_in_product_marketing_email(user.id, anything, track, series)
- end
- end
- end
-
- context 'when user is in two groups' do
- let(:other_group) { create(:group) }
-
- before do
- other_group.add_developer(user)
- end
-
- context 'when both groups would get the same email' do
- before do
- create(:onboarding_progress, namespace: other_group, **actions_completed)
- end
-
- it 'does not send the same email twice' do
- subject
-
- expect(Notify).to have_received(:in_product_marketing_email).with(user.id, anything, :create, 0).once
- end
- end
-
- context 'when other group gets a different email' do
- before do
- create(:onboarding_progress, namespace: other_group, created_at: previous_action_completed_at, git_write_at: frozen_time - 2.days)
- end
-
- it 'sends both emails' do
- subject
-
- expect(Notify).to have_received(:in_product_marketing_email).with(user.id, group.id, :create, 0)
- expect(Notify).to have_received(:in_product_marketing_email).with(user.id, other_group.id, :team_short, 0)
- end
- end
- end
- end
-
- it 'records sent emails' do
- expect { subject }.to change { Users::InProductMarketingEmail.count }.by(1)
-
- expect(
- Users::InProductMarketingEmail.where(
- user: user,
- track: Users::InProductMarketingEmail::ACTIVE_TRACKS[:create],
- series: 0
- )
- ).to exist
- end
-
- context 'when invoked with a non existing track' do
- let(:track) { :foo }
-
- before do
- stub_const("#{described_class}::TRACKS", { bar: {} })
- end
-
- it { expect { subject }.to raise_error(ArgumentError, 'Track foo not defined') }
- end
-
- context 'when group is a sub-group' do
- let(:root_group) { create(:group) }
- let(:group) { create(:group) }
-
- before do
- group.parent = root_group
- group.save!
-
- allow(Ability).to receive(:allowed?).and_call_original
- end
-
- it 'does not raise an exception' do
- expect { execute_service }.not_to raise_error
- end
- end
-end
diff --git a/spec/services/note_summary_spec.rb b/spec/services/note_summary_spec.rb
index 1cbbb68205d..f3233ef925e 100644
--- a/spec/services/note_summary_spec.rb
+++ b/spec/services/note_summary_spec.rb
@@ -24,8 +24,13 @@ RSpec.describe NoteSummary, feature_category: :code_review_workflow do
describe '#note' do
it 'returns note hash' do
freeze_time do
- expect(create_note_summary.note).to eq(noteable: noteable, project: project, author: user, note: 'note',
- created_at: Time.current)
+ expect(create_note_summary.note).to eq(
+ noteable: noteable,
+ project: project,
+ author: user,
+ note: 'note',
+ created_at: Time.current
+ )
end
end
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 22509885c92..b5eb5f8037a 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -180,8 +180,9 @@ RSpec.describe Notes::CreateService, feature_category: :team_planning do
execute_create_service
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_COMMENT_ADDED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_COMMENT_ADDED }
+ let(:namespace) { project.namespace }
subject(:service_action) { execute_create_service }
end
end
diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb
index 396e23351c9..54782774b4e 100644
--- a/spec/services/notes/destroy_service_spec.rb
+++ b/spec/services/notes/destroy_service_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Notes::DestroyService, feature_category: :team_planning do
end
describe 'comment removed event tracking', :snowplow do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_COMMENT_REMOVED }
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_COMMENT_REMOVED }
let(:note) { create(:note, project: project, noteable: issue) }
let(:service_action) { described_class.new(project, user).execute(note) }
@@ -39,11 +39,12 @@ RSpec.describe Notes::DestroyService, feature_category: :team_planning do
expect do
service_action
end.to change {
- counter.unique_events(event_names: property, start_date: Date.today.beginning_of_week, end_date: 1.week.from_now)
+ counter.unique_events(event_names: action, start_date: Date.today.beginning_of_week, end_date: 1.week.from_now)
}.by(1)
end
- it_behaves_like 'issue_edit snowplow tracking' do
+ it_behaves_like 'internal event tracking' do
+ let(:namespace) { project.namespace }
subject(:execute_service_action) { service_action }
end
end
diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb
index 0065fd639b8..b6e29299fdd 100644
--- a/spec/services/notes/quick_actions_service_spec.rb
+++ b/spec/services/notes/quick_actions_service_spec.rb
@@ -188,6 +188,45 @@ RSpec.describe Notes::QuickActionsService, feature_category: :team_planning do
end
end
+ describe '/confidential' do
+ let_it_be_with_reload(:noteable) { create(:work_item, :issue, project: project) }
+ let_it_be(:note_text) { '/confidential' }
+ let_it_be(:note) { create(:note, noteable: noteable, project: project, note: note_text) }
+
+ context 'when work item does not have children' do
+ it 'leaves the note empty' do
+ expect(execute(note)).to be_empty
+ end
+
+ it 'marks work item as confidential' do
+ expect { execute(note) }.to change { noteable.reload.confidential }.from(false).to(true)
+ end
+ end
+
+ context 'when work item has children' do
+ before do
+ create(:parent_link, work_item: task, work_item_parent: noteable)
+ end
+
+ context 'when children are not confidential' do
+ let(:task) { create(:work_item, :task, project: project) }
+
+ it 'does not mark parent work item as confidential' do
+ expect { execute(note) }.to not_change { noteable.reload.confidential }.from(false)
+ expect(noteable.errors[:base]).to include('A confidential work item cannot have a parent that already has non-confidential children.')
+ end
+ end
+
+ context 'when children are confidential' do
+ let(:task) { create(:work_item, :confidential, :task, project: project) }
+
+ it 'marks parent work item as confidential' do
+ expect { execute(note) }.to change { noteable.reload.confidential }.from(false).to(true)
+ end
+ end
+ end
+ end
+
describe 'note with command & text' do
describe '/close, /label, /assign & /milestone' do
let(:note_text) do
diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb
index e109bfbcd0b..8389db000b8 100644
--- a/spec/services/notes/update_service_spec.rb
+++ b/spec/services/notes/update_service_spec.rb
@@ -75,6 +75,13 @@ RSpec.describe Notes::UpdateService, feature_category: :team_planning do
update_note({})
end
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_COMMENT_EDITED }
+ let(:namespace) { project.namespace }
+
+ subject(:service_action) { update_note(note: 'new text') }
+ end
+
it 'tracks issue usage data', :clean_gitlab_redis_shared_state do
counter = Gitlab::UsageDataCounters::HLLRedisCounter
@@ -85,11 +92,6 @@ RSpec.describe Notes::UpdateService, feature_category: :team_planning do
update_note(note: 'new text')
end.to change { counter.unique_events(event_names: event, start_date: Date.today.beginning_of_week, end_date: 1.week.from_now) }.by(1)
end
-
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_COMMENT_EDITED }
- subject(:service_action) { update_note(note: 'new text') }
- end
end
context 'when note text was changed' do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 028c3ea6610..40597c30c4a 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -324,7 +324,7 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
end
describe "never emails the ghost user" do
- let(:key_options) { { user: User.ghost } }
+ let(:key_options) { { user: Users::Internal.ghost } }
it "does not send email to key owner" do
expect { subject }.not_to have_enqueued_email(key.id, mail: "new_ssh_key_email")
@@ -345,7 +345,7 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
end
describe "never emails the ghost user" do
- let(:key_options) { { user: User.ghost } }
+ let(:key_options) { { user: Users::Internal.ghost } }
it "does not send email to key owner" do
expect { subject }.not_to have_enqueued_email(key.id, mail: "new_gpg_key_email")
@@ -376,6 +376,74 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
end
end
+ describe '#resource_access_token_about_to_expire' do
+ let_it_be(:project_bot) { create(:user, :project_bot) }
+ let_it_be(:expiring_token) { create(:personal_access_token, user: project_bot, expires_at: 5.days.from_now) }
+
+ let_it_be(:owner1) { create(:user) }
+ let_it_be(:owner2) { create(:user) }
+
+ subject(:notification_service) do
+ notification.resource_access_tokens_about_to_expire(project_bot, [expiring_token.name])
+ end
+
+ context 'when the resource is a group' do
+ let(:group) { create(:group) }
+
+ before do
+ group.add_owner(owner1)
+ group.add_owner(owner2)
+ group.add_reporter(project_bot)
+ end
+
+ it 'sends emails to the group owners' do
+ expect { notification_service }.to(
+ have_enqueued_email(
+ owner1,
+ project_bot.resource_bot_resource,
+ [expiring_token.name],
+ mail: "resource_access_tokens_about_to_expire_email"
+ ).and(
+ have_enqueued_email(
+ owner2,
+ project_bot.resource_bot_resource,
+ [expiring_token.name],
+ mail: "resource_access_tokens_about_to_expire_email"
+ )
+ )
+ )
+ end
+ end
+
+ context 'when the resource is a project' do
+ let(:project) { create(:project) }
+
+ before do
+ project.add_maintainer(owner1)
+ project.add_maintainer(owner2)
+ project.add_reporter(project_bot)
+ end
+
+ it 'sends emails to the group owners' do
+ expect { notification_service }.to(
+ have_enqueued_email(
+ owner1,
+ project_bot.resource_bot_resource,
+ [expiring_token.name],
+ mail: "resource_access_tokens_about_to_expire_email"
+ ).and(
+ have_enqueued_email(
+ owner2,
+ project_bot.resource_bot_resource,
+ [expiring_token.name],
+ mail: "resource_access_tokens_about_to_expire_email"
+ )
+ )
+ )
+ end
+ end
+ end
+
describe '#access_token_about_to_expire' do
let_it_be(:user) { create(:user) }
let_it_be(:pat) { create(:personal_access_token, user: user, expires_at: 5.days.from_now) }
@@ -534,7 +602,7 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
let(:subject) { described_class.new }
let(:mailer) { double(deliver_later: true) }
- let(:issue) { create(:issue, author: User.support_bot) }
+ let(:issue) { create(:issue, author: Users::Internal.support_bot) }
let(:project) { issue.project }
let(:note) { create(:note, noteable: issue, project: project) }
@@ -576,6 +644,14 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
end
it_behaves_like 'notification with exact metric events', 1
+
+ context 'when service desk is disabled' do
+ before do
+ project.update!(service_desk_enabled: false)
+ end
+
+ it_behaves_like 'no participants are notified'
+ end
end
context 'do exist and note is confidential' do
@@ -1211,9 +1287,11 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
let_it_be(:member_and_not_mentioned) { create(:user, developer_projects: [project]) }
let_it_be(:non_member_and_mentioned) { create(:user) }
let_it_be(:note) do
- create(:diff_note_on_design,
- noteable: design,
- note: "Hello #{member_and_mentioned.to_reference}, G'day #{non_member_and_mentioned.to_reference}")
+ create(
+ :diff_note_on_design,
+ noteable: design,
+ note: "Hello #{member_and_mentioned.to_reference}, G'day #{non_member_and_mentioned.to_reference}"
+ )
end
let_it_be(:note_2) do
@@ -3498,12 +3576,14 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
let(:commit) { project.commit }
def create_pipeline(user, status)
- create(:ci_pipeline, status,
- project: project,
- user: user,
- ref: 'refs/heads/master',
- sha: commit.id,
- before_sha: '00000000')
+ create(
+ :ci_pipeline, status,
+ project: project,
+ user: user,
+ ref: 'refs/heads/master',
+ sha: commit.id,
+ before_sha: '00000000'
+ )
end
before_all do
@@ -4012,12 +4092,14 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
project.add_maintainer(reviewer)
merge_request.assignees.each { |assignee| project.add_maintainer(assignee) }
- create(:diff_note_on_merge_request,
- project: project,
- noteable: merge_request,
- author: reviewer,
- review: review,
- note: "cc @mention")
+ create(
+ :diff_note_on_merge_request,
+ project: project,
+ noteable: merge_request,
+ author: reviewer,
+ review: review,
+ note: "cc @mention"
+ )
end
it 'sends emails' do
@@ -4059,10 +4141,18 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
subject { notification.inactive_project_deletion_warning(project, deletion_date) }
it "sends email to project owners and maintainers" do
- expect { subject }.to have_enqueued_email(project, maintainer, deletion_date,
- mail: "inactive_project_deletion_warning_email")
- expect { subject }.not_to have_enqueued_email(project, developer, deletion_date,
- mail: "inactive_project_deletion_warning_email")
+ expect { subject }.to have_enqueued_email(
+ project,
+ maintainer,
+ deletion_date,
+ mail: "inactive_project_deletion_warning_email"
+ )
+ expect { subject }.not_to have_enqueued_email(
+ project,
+ developer,
+ deletion_date,
+ mail: "inactive_project_deletion_warning_email"
+ )
end
end
diff --git a/spec/services/packages/ml_model/create_package_file_service_spec.rb b/spec/services/packages/ml_model/create_package_file_service_spec.rb
index 32754279e17..30a6bedd07b 100644
--- a/spec/services/packages/ml_model/create_package_file_service_spec.rb
+++ b/spec/services/packages/ml_model/create_package_file_service_spec.rb
@@ -38,12 +38,12 @@ RSpec.describe Packages::MlModel::CreatePackageFileService, feature_category: :m
it 'creates package file', :aggregate_failures do
expect { execute_service }
- .to change { project.packages.ml_model.count }.by(1)
+ .to change { Packages::MlModel::Package.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
.and change { Packages::PackageFileBuildInfo.count }.by(0)
.and change { Ml::ModelVersion.count }.by(1)
- new_model = project.packages.ml_model.last
+ new_model = Packages::MlModel::Package.last
package_file = new_model.package_files.last
new_model_version = Ml::ModelVersion.last
diff --git a/spec/services/packages/npm/generate_metadata_service_spec.rb b/spec/services/packages/npm/generate_metadata_service_spec.rb
index fdd0ab0ccee..d8e794405e6 100644
--- a/spec/services/packages/npm/generate_metadata_service_spec.rb
+++ b/spec/services/packages/npm/generate_metadata_service_spec.rb
@@ -70,6 +70,17 @@ RSpec.describe ::Packages::Npm::GenerateMetadataService, feature_category: :pack
it { expect(subject.dig(package2.version, dependency_type)).to be nil }
end
+
+ context 'when generate dependencies' do
+ let(:packages) { ::Packages::Package.where(id: package1.id) }
+
+ it 'loads grouped dependency links', :aggregate_failures do
+ expect(::Packages::DependencyLink).to receive(:dependency_ids_grouped_by_type).and_call_original
+ expect(::Packages::Package).not_to receive(:including_dependency_links)
+
+ subject
+ end
+ end
end
context 'for metadatum' do
diff --git a/spec/services/packages/nuget/check_duplicates_service_spec.rb b/spec/services/packages/nuget/check_duplicates_service_spec.rb
new file mode 100644
index 00000000000..9675aa5f5e2
--- /dev/null
+++ b/spec/services/packages/nuget/check_duplicates_service_spec.rb
@@ -0,0 +1,155 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Nuget::CheckDuplicatesService, feature_category: :package_registry do
+ include PackagesManagerApiSpecHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:file_name) { 'package.nupkg' }
+
+ let(:params) do
+ {
+ file_name: file_name,
+ file: temp_file(file_name)
+ }
+ end
+
+ let(:service) { described_class.new(project, user, params) }
+
+ describe '#execute' do
+ subject(:execute) { service.execute }
+
+ shared_examples 'returning error' do |reason:, message:|
+ it 'returns an error' do
+ response = execute
+
+ expect(response.status).to eq(:error)
+ expect(response.reason).to eq(reason)
+ expect(response.message).to eq(message)
+ end
+ end
+
+ shared_examples 'returning success' do
+ it 'returns success' do
+ response = execute
+
+ expect(response.status).to eq(:success)
+ end
+ end
+
+ shared_examples 'handling duplicates disallowed when package exists' do
+ it_behaves_like 'returning error', reason: :conflict,
+ message: 'A package with the same name and version already exists'
+
+ context 'with nuget_duplicate_exception_regex' do
+ before do
+ package_settings.update_column(:nuget_duplicate_exception_regex, ".*#{existing_package.name.last(3)}.*")
+ end
+
+ it_behaves_like 'returning success'
+ end
+ end
+
+ context 'with existing package' do
+ let_it_be(:existing_package) { create(:nuget_package, :with_metadatum, project: project, version: '1.7.15.0') }
+ let_it_be(:metadata) do
+ {
+ package_name: existing_package.name,
+ package_version: existing_package.version,
+ authors: 'authors',
+ description: 'description'
+ }
+ end
+
+ context 'when nuget duplicates are allowed' do
+ before do
+ allow_next_instance_of(Namespace::PackageSetting) do |instance|
+ allow(instance).to receive(:nuget_duplicates_allowed?).and_return(true)
+ end
+ end
+
+ it_behaves_like 'returning success'
+ end
+
+ context 'when nuget duplicates are not allowed' do
+ let!(:package_settings) do
+ create(:namespace_package_setting, :group, namespace: project.namespace, nuget_duplicates_allowed: false)
+ end
+
+ context 'when package file is in object storage' do
+ let(:params) { super().merge(remote_url: 'https://example.com') }
+
+ before do
+ allow_next_instance_of(::Packages::Nuget::ExtractRemoteMetadataFileService) do |instance|
+ allow(instance).to receive(:execute)
+ .and_return(ServiceResponse.success(payload: Nokogiri::XML::Document.new))
+ end
+ allow_next_instance_of(::Packages::Nuget::ExtractMetadataContentService) do |instance|
+ allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: metadata))
+ end
+ end
+
+ it_behaves_like 'handling duplicates disallowed when package exists'
+
+ context 'when ExtractRemoteMetadataFileService raises ExtractionError' do
+ before do
+ allow_next_instance_of(::Packages::Nuget::ExtractRemoteMetadataFileService) do |instance|
+ allow(instance).to receive(:execute).and_raise(
+ ::Packages::Nuget::ExtractRemoteMetadataFileService::ExtractionError, 'nuspec file not found'
+ )
+ end
+ end
+
+ it_behaves_like 'returning error', reason: :bad_request, message: 'nuspec file not found'
+ end
+
+ context 'when version is normalized' do
+ let(:metadata) { super().merge(package_version: '1.7.15') }
+
+ it_behaves_like 'handling duplicates disallowed when package exists'
+ end
+ end
+
+ context 'when package file is on disk' do
+ before do
+ allow_next_instance_of(::Packages::Nuget::MetadataExtractionService) do |instance|
+ allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: metadata))
+ end
+ end
+
+ it_behaves_like 'handling duplicates disallowed when package exists'
+ end
+ end
+ end
+
+ context 'with non existing package' do
+ let_it_be(:metadata) do
+ { package_name: 'foo', package_version: '1.0.0', authors: 'author', description: 'description' }
+ end
+
+ before do
+ allow_next_instance_of(::Packages::Nuget::MetadataExtractionService) do |instance|
+ allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: metadata))
+ end
+ end
+
+ context 'when nuget duplicates are allowed' do
+ let_it_be(:package_settings) do
+ create(:namespace_package_setting, :group, namespace: project.namespace, nuget_duplicates_allowed: true)
+ end
+
+ it_behaves_like 'returning success'
+ end
+
+ context 'when nuget duplicates are not allowed' do
+ let_it_be(:package_settings) do
+ create(:namespace_package_setting, :group, namespace: project.namespace, nuget_duplicates_allowed: false)
+ end
+
+ it_behaves_like 'returning success'
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/nuget/extract_metadata_file_service_spec.rb b/spec/services/packages/nuget/extract_metadata_file_service_spec.rb
index 412c22fe8de..57b08f8773c 100644
--- a/spec/services/packages/nuget/extract_metadata_file_service_spec.rb
+++ b/spec/services/packages/nuget/extract_metadata_file_service_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe Packages::Nuget::ExtractMetadataFileService, feature_category: :package_registry do
- let_it_be(:package_file) { create(:nuget_package).package_files.first }
+ let_it_be_with_reload(:package_file) { create(:nuget_package).package_files.first }
- let(:service) { described_class.new(package_file.id) }
+ let(:service) { described_class.new(package_file) }
describe '#execute' do
subject { service.execute }
@@ -14,7 +14,7 @@ RSpec.describe Packages::Nuget::ExtractMetadataFileService, feature_category: :p
it { expect { subject }.to raise_error(described_class::ExtractionError, error_message) }
end
- context 'with valid package file id' do
+ context 'with valid package file' do
expected_metadata = <<~XML.squish
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
@@ -39,8 +39,8 @@ RSpec.describe Packages::Nuget::ExtractMetadataFileService, feature_category: :p
end
end
- context 'with invalid package file id' do
- let(:package_file) { instance_double('Packages::PackageFile', id: 555) }
+ context 'with invalid package file' do
+ let(:package_file) { nil }
it_behaves_like 'raises an error', 'invalid package file'
end
@@ -53,7 +53,7 @@ RSpec.describe Packages::Nuget::ExtractMetadataFileService, feature_category: :p
it_behaves_like 'raises an error', 'invalid package file'
end
- context 'with a 0 byte package file id' do
+ context 'with a 0 byte package file' do
before do
allow_next_instance_of(Packages::PackageFileUploader) do |instance|
allow(instance).to receive(:size).and_return(0)
@@ -76,7 +76,7 @@ RSpec.describe Packages::Nuget::ExtractMetadataFileService, feature_category: :p
context 'with a too big nuspec file' do
before do
allow_next_instance_of(Zip::File) do |instance|
- allow(instance).to receive(:glob).and_return([instance_double('File', size: 6.megabytes)])
+ allow(instance).to receive(:glob).and_return([instance_double(File, size: 6.megabytes)])
end
end
diff --git a/spec/services/packages/nuget/extract_remote_metadata_file_service_spec.rb b/spec/services/packages/nuget/extract_remote_metadata_file_service_spec.rb
new file mode 100644
index 00000000000..b5aff6e7588
--- /dev/null
+++ b/spec/services/packages/nuget/extract_remote_metadata_file_service_spec.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Nuget::ExtractRemoteMetadataFileService, feature_category: :package_registry do
+ let_it_be(:remote_url) { 'http://example.com/package.nupkg' }
+ let_it_be(:nupkg_filepath) { 'packages/nuget/package.nupkg' }
+
+ describe '#execute' do
+ subject(:service) { described_class.new(remote_url) }
+
+ context 'when the remote URL is blank' do
+ let(:remote_url) { '' }
+
+ it { expect { service.execute }.to raise_error(described_class::ExtractionError, 'invalid file url') }
+ end
+
+ context 'when the package file is corrupted' do
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(remote_url, stream_body: true, allow_object_storage: true)
+ .and_yield('corrupted data')
+ end
+
+ it { expect { service.execute }.to raise_error(described_class::ExtractionError, 'nuspec file not found') }
+ end
+
+ context 'when reaching the maximum received fragments' do
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(remote_url, stream_body: true, allow_object_storage: true)
+ .and_yield('Fragment 1').and_yield('Fragment 2').and_yield('Fragment 3').and_yield('Fragment 4')
+ .and_yield('Fragment 5').and_yield(fixture_file(nupkg_filepath))
+ end
+
+ it { expect { service.execute }.to raise_error(described_class::ExtractionError, 'nuspec file not found') }
+ end
+
+ context 'when nuspec file is too big' do
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(remote_url, stream_body: true, allow_object_storage: true)
+ .and_yield(fixture_file(nupkg_filepath))
+ allow_next_instance_of(Zip::Entry) do |instance|
+ allow(instance).to receive(:size).and_return(6.megabytes)
+ end
+ end
+
+ it { expect { service.execute }.to raise_error(described_class::ExtractionError, 'nuspec file too big') }
+ end
+
+ context 'when nuspec file is fragmented' do
+ let_it_be(:nuspec_path) { expand_fixture_path('packages/nuget/with_metadata.nuspec') }
+ let_it_be(:tmp_zip) { Tempfile.new('nuget_zip') }
+ let_it_be(:zipped_nuspec) { zip_nuspec_file(nuspec_path, tmp_zip.path).get_raw_input_stream.read }
+ let_it_be(:fragments) { zipped_nuspec.chars.each_slice(zipped_nuspec.size / 2).map(&:join) }
+
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(remote_url, stream_body: true, allow_object_storage: true)
+ .and_yield(fragments[0]).and_yield(fragments[1])
+ end
+
+ after do
+ tmp_zip.unlink
+ end
+
+ it 'ignores the Zip::DecompressionError and constructs the nuspec file from the fragments' do
+ response = service.execute
+
+ expect(response).to be_success
+ expect(response.payload).to include('<id>DummyProject.WithMetadata</id>')
+ .and include('<version>1.2.3</version>')
+ end
+ end
+
+ context 'when the remote URL is valid' do
+ let(:fragments) { fixture_file(nupkg_filepath).chars.each_slice(1.kilobyte).map(&:join) }
+
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(remote_url, stream_body: true, allow_object_storage: true)
+ .and_yield(fragments[0]).and_yield(fragments[1]).and_yield(fragments[2]).and_yield(fragments[3])
+ end
+
+ it 'returns a success response with the nuspec file content' do
+ response = service.execute
+
+ expect(response).to be_success
+ expect(response.payload).to include('<id>DummyProject.DummyPackage</id>')
+ .and include('<version>1.0.0</version>')
+ end
+ end
+
+ context 'with a corrupted nupkg file with a wrong entry size' do
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(remote_url, stream_body: true, allow_object_storage: true)
+ .and_yield(fixture_file(nupkg_filepath))
+ allow_next_instance_of(Zip::Entry) do |instance|
+ allow(instance).to receive(:extract).and_raise(Zip::EntrySizeError)
+ end
+ end
+
+ it {
+ expect do
+ service.execute
+ end.to raise_error(described_class::ExtractionError, /nuspec file has the wrong entry size/)
+ }
+ end
+
+ context 'with a Zip::Error exception' do
+ before do
+ allow(Gitlab::HTTP).to receive(:get).with(remote_url, stream_body: true, allow_object_storage: true)
+ .and_yield(fixture_file(nupkg_filepath))
+ allow(Zip::InputStream).to receive(:open).and_raise(Zip::Error)
+ end
+
+ it {
+ expect do
+ service.execute
+ end.to raise_error(described_class::ExtractionError, /Error opening zip stream/)
+ }
+ end
+ end
+
+ def zip_nuspec_file(nuspec_path, zip_path)
+ Zip::File.open(zip_path, Zip::File::CREATE) do |zipfile|
+ zipfile.add('package.nuspec', nuspec_path)
+ end
+ end
+end
diff --git a/spec/services/packages/nuget/metadata_extraction_service_spec.rb b/spec/services/packages/nuget/metadata_extraction_service_spec.rb
index c8c06414830..ea7557b6d64 100644
--- a/spec/services/packages/nuget/metadata_extraction_service_spec.rb
+++ b/spec/services/packages/nuget/metadata_extraction_service_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Packages::Nuget::MetadataExtractionService, feature_category: :package_registry do
let_it_be(:package_file) { create(:nuget_package).package_files.first }
- subject { described_class.new(package_file.id) }
+ subject { described_class.new(package_file) }
describe '#execute' do
let(:nuspec_file_content) do
@@ -49,7 +49,7 @@ RSpec.describe Packages::Nuget::MetadataExtractionService, feature_category: :pa
end
it 'calls the necessary services and executes the metadata extraction' do
- expect(::Packages::Nuget::ExtractMetadataFileService).to receive(:new).with(package_file.id) do
+ expect(::Packages::Nuget::ExtractMetadataFileService).to receive(:new).with(package_file) do
double.tap do |service|
expect(service).to receive(:execute).and_return(double(payload: nuspec_file_content))
end
diff --git a/spec/services/packages/nuget/odata_package_entry_service_spec.rb b/spec/services/packages/nuget/odata_package_entry_service_spec.rb
new file mode 100644
index 00000000000..d4c47538ce2
--- /dev/null
+++ b/spec/services/packages/nuget/odata_package_entry_service_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Nuget::OdataPackageEntryService, feature_category: :package_registry do
+ let_it_be(:project) { build_stubbed(:project) }
+ let_it_be(:params) { { package_name: 'dummy', package_version: '1.0.0' } }
+ let(:doc) { Nokogiri::XML(subject.payload) }
+
+ subject { described_class.new(project, params).execute }
+
+ describe '#execute' do
+ shared_examples 'returning a package entry with the correct attributes' do |pkg_version, content_url_pkg_version|
+ it 'returns a package entry with the correct attributes' do
+ expect(doc.root.name).to eq('entry')
+ expect(doc_node('id').text).to include(
+ id_url(project.id, params[:package_name], pkg_version)
+ )
+ expect(doc_node('title').text).to eq(params[:package_name])
+ expect(doc_node('content').attr('src')).to include(
+ content_url(project.id, params[:package_name], content_url_pkg_version)
+ )
+ expect(doc_node('Version').text).to eq(pkg_version)
+ end
+ end
+
+ context 'when package_version is present' do
+ it 'returns a success ServiceResponse' do
+ expect(subject).to be_success
+ end
+
+ it_behaves_like 'returning a package entry with the correct attributes', '1.0.0', '1.0.0'
+ end
+
+ context 'when package_version is nil' do
+ let(:params) { { package_name: 'dummy', package_version: nil } }
+
+ it 'returns a success ServiceResponse' do
+ expect(subject).to be_success
+ end
+
+ it_behaves_like 'returning a package entry with the correct attributes',
+ described_class::SEMVER_LATEST_VERSION_PLACEHOLDER, described_class::LATEST_VERSION_FOR_V2_DOWNLOAD_ENDPOINT
+ end
+
+ context 'when package_version is 0.0.0-latest-version' do
+ let(:params) { { package_name: 'dummy', package_version: described_class::SEMVER_LATEST_VERSION_PLACEHOLDER } }
+
+ it 'returns a success ServiceResponse' do
+ expect(subject).to be_success
+ end
+
+ it_behaves_like 'returning a package entry with the correct attributes',
+ described_class::SEMVER_LATEST_VERSION_PLACEHOLDER, described_class::LATEST_VERSION_FOR_V2_DOWNLOAD_ENDPOINT
+ end
+ end
+
+ def doc_node(name)
+ doc.css('*').detect { |el| el.name == name }
+ end
+
+ def id_url(id, package_name, package_version)
+ "api/v4/projects/#{id}/packages/nuget/v2/Packages(Id='#{package_name}',Version='#{package_version}')"
+ end
+
+ def content_url(id, package_name, package_version)
+ "api/v4/projects/#{id}/packages/nuget/v2/download/#{package_name}/#{package_version}"
+ end
+end
diff --git a/spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb b/spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb
index b18f62c1c28..e1cce2c87eb 100644
--- a/spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb
+++ b/spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb
@@ -21,9 +21,9 @@ RSpec.describe Pages::MigrateLegacyStorageToDeploymentService, feature_category:
project.mark_pages_as_deployed
expect(project.pages_metadatum.reload.deployed).to eq(true)
- expect(service.execute).to(
- eq(status: :success,
- message: "Archive not created. Missing public directory in #{project.pages_path}? Marked project as not deployed")
+ expect(service.execute).to eq(
+ status: :success,
+ message: "Archive not created. Missing public directory in #{project.pages_path}? Marked project as not deployed"
)
expect(project.pages_metadatum.reload.deployed).to eq(false)
@@ -35,9 +35,9 @@ RSpec.describe Pages::MigrateLegacyStorageToDeploymentService, feature_category:
project.mark_pages_as_deployed
expect(project.pages_metadatum.reload.deployed).to eq(true)
- expect(service.execute).to(
- eq(status: :success,
- message: "Archive not created. Missing public directory in #{project.pages_path}? Marked project as not deployed")
+ expect(service.execute).to eq(
+ status: :success,
+ message: "Archive not created. Missing public directory in #{project.pages_path}? Marked project as not deployed"
)
expect(project.pages_metadatum.reload.deployed).to eq(true)
@@ -49,9 +49,9 @@ RSpec.describe Pages::MigrateLegacyStorageToDeploymentService, feature_category:
expect(project.pages_metadatum.reload.deployed).to eq(true)
- expect(service.execute).to(
- eq(status: :error,
- message: "Archive not created. Missing public directory in #{project.pages_path}")
+ expect(service.execute).to eq(
+ status: :error,
+ message: "Archive not created. Missing public directory in #{project.pages_path}"
)
expect(project.pages_metadatum.reload.deployed).to eq(true)
@@ -60,9 +60,9 @@ RSpec.describe Pages::MigrateLegacyStorageToDeploymentService, feature_category:
it 'removes pages archive when can not save deployment' do
archive = fixture_file_upload("spec/fixtures/pages.zip")
expect_next_instance_of(::Pages::ZipDirectoryService) do |zip_service|
- expect(zip_service).to receive(:execute).and_return(status: :success,
- archive_path: archive.path,
- entries_count: 3)
+ expect(zip_service).to receive(:execute).and_return(
+ status: :success, archive_path: archive.path, entries_count: 3
+ )
end
expect_next_instance_of(PagesDeployment) do |deployment|
diff --git a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
index 2377fbcf003..7f8992e8bbc 100644
--- a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
+++ b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
@@ -132,8 +132,7 @@ RSpec.describe PagesDomains::ObtainLetsEncryptCertificateService, feature_catego
ef.create_extension("basicConstraints", "CA:TRUE", true),
ef.create_extension("subjectKeyIdentifier", "hash")
]
- cert.add_extension ef.create_extension("authorityKeyIdentifier",
- "keyid:always,issuer:always")
+ cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
cert.sign key, OpenSSL::Digest.new('SHA256')
diff --git a/spec/services/preview_markdown_service_spec.rb b/spec/services/preview_markdown_service_spec.rb
index 6fa44310ae5..f6aca9970c8 100644
--- a/spec/services/preview_markdown_service_spec.rb
+++ b/spec/services/preview_markdown_service_spec.rb
@@ -28,9 +28,11 @@ RSpec.describe PreviewMarkdownService, feature_category: :team_planning do
let(:text) { "```suggestion\nfoo\n```" }
let(:params) do
- suggestion_params.merge(text: text,
- target_type: 'MergeRequest',
- target_id: merge_request.iid)
+ suggestion_params.merge(
+ text: text,
+ target_type: 'MergeRequest',
+ target_id: merge_request.iid
+ )
end
let(:service) { described_class.new(project, user, params) }
@@ -52,15 +54,16 @@ RSpec.describe PreviewMarkdownService, feature_category: :team_planning do
end
it 'returns suggestions referenced in text' do
- position = Gitlab::Diff::Position.new(new_path: path,
- new_line: line,
- diff_refs: diff_refs)
+ position = Gitlab::Diff::Position.new(new_path: path, new_line: line, diff_refs: diff_refs)
expect(Gitlab::Diff::SuggestionsParser)
.to receive(:parse)
- .with(text, position: position,
- project: merge_request.project,
- supports_suggestion: true)
+ .with(
+ text,
+ position: position,
+ project: merge_request.project,
+ supports_suggestion: true
+ )
.and_call_original
result = service.execute
diff --git a/spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb b/spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb
index ecabaa28119..0d7d1254428 100644
--- a/spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb
@@ -48,7 +48,24 @@ RSpec.describe Projects::ContainerRepository::Gitlab::DeleteTagsService, feature
stub_delete_reference_requests('A' => 500, 'Ba' => 500)
end
- it { is_expected.to eq(status: :error, message: 'could not delete tags') }
+ it { is_expected.to eq(status: :error, message: "could not delete tags: #{tags.join(', ')}") }
+
+ context 'when a large list of tag delete fails' do
+ let(:tags) { Array.new(135) { |i| "tag#{i}" } }
+ let(:container_repository) { instance_double(ContainerRepository) }
+
+ before do
+ allow(ContainerRepository).to receive(:find).with(repository).and_return(container_repository)
+ tags.each do |tag|
+ stub_delete_reference_requests(tag => 500)
+ end
+ allow(container_repository).to receive(:delete_tag_by_name).and_return(false)
+ end
+
+ it 'truncates the log message' do
+ expect(subject).to eq(status: :error, message: "could not delete tags: #{tags.join(', ')}".truncate(1000))
+ end
+ end
end
end
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 683e438eb08..ce7e5188c7b 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe Projects::CreateService, '#execute', feature_category: :groups_an
project = create_project(bot_user, opts)
expect(project.errors.errors.length).to eq 1
- expect(project.errors.messages[:namespace].first).to eq(("is not valid"))
+ expect(project.errors.messages[:namespace].first).to eq("is not valid")
end
end
end
@@ -640,6 +640,17 @@ RSpec.describe Projects::CreateService, '#execute', feature_category: :groups_an
expect(project.project_namespace).to be_in_sync_with_project(project)
end
+ it 'raises when repository fails to create' do
+ expect_next_instance_of(Project) do |instance|
+ expect(instance).to receive(:create_repository).and_return(false)
+ end
+
+ project = create_project(user, opts)
+ expect(project).not_to be_persisted
+ expect(project.errors.messages).to have_key(:base)
+ expect(project.errors.messages[:base].first).to match('Failed to create repository')
+ end
+
context 'when another repository already exists on disk' do
let(:opts) do
{
@@ -1158,4 +1169,17 @@ RSpec.describe Projects::CreateService, '#execute', feature_category: :groups_an
expect_not_disabled_features(project, exclude: [:repository, :builds, :merge_requests])
end
end
+
+ it 'adds pages unique domain', feature_category: :pages do
+ stub_pages_setting(enabled: true)
+
+ expect(Gitlab::Pages)
+ .to receive(:add_unique_domain_to)
+ .and_call_original
+
+ project = create_project(user, opts)
+
+ expect(project.project_setting.pages_unique_domain_enabled).to eq(true)
+ expect(project.project_setting.pages_unique_domain).to be_present
+ end
end
diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb
index 97a3b338069..16b9d2618ca 100644
--- a/spec/services/projects/import_service_spec.rb
+++ b/spec/services/projects/import_service_spec.rb
@@ -163,72 +163,100 @@ RSpec.describe Projects::ImportService, feature_category: :importers do
context 'when importer does not support refmap' do
it 'succeeds if repository import is successful' do
- expect(project.repository).to receive(:import_repository).and_return(true)
- expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
+ expect_next_instance_of(Gitlab::BitbucketImport::ParallelImporter) do |importer|
expect(importer).to receive(:execute).and_return(true)
end
- expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
- expect(service).to receive(:execute).and_return(status: :success)
- end
-
result = subject.execute
expect(result[:status]).to eq :success
end
it 'fails if repository import fails' do
- expect(project.repository)
- .to receive(:import_repository)
- .with('https://bitbucket.org/vim/vim.git', resolved_address: '')
- .and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
+ expect_next_instance_of(Gitlab::BitbucketImport::ParallelImporter) do |importer|
+ expect(importer).to receive(:execute)
+ .and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
+ end
result = subject.execute
expect(result[:status]).to eq :error
expect(result[:message]).to eq "Error importing repository #{project.safe_import_url} into #{project.full_path} - Failed to import the repository [FILTERED]"
end
- end
- context 'when lfs import fails' do
- it 'logs the error' do
- error_message = 'error message'
+ context 'when bitbucket_parallel_importer feature flag is disabled' do
+ before do
+ stub_feature_flags(bitbucket_parallel_importer: false)
+ end
- expect(project.repository).to receive(:import_repository).and_return(true)
+ it 'succeeds if repository import is successful' do
+ expect(project.repository).to receive(:import_repository).and_return(true)
+ expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
+ expect(importer).to receive(:execute).and_return(true)
+ end
- expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
- expect(importer).to receive(:execute).and_return(true)
+ expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
+ expect(service).to receive(:execute).and_return(status: :success)
+ end
+
+ result = subject.execute
+
+ expect(result[:status]).to eq :success
end
- expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
- expect(service).to receive(:execute).and_return(status: :error, message: error_message)
+ it 'fails if repository import fails' do
+ expect(project.repository)
+ .to receive(:import_repository)
+ .with('https://bitbucket.org/vim/vim.git', resolved_address: '')
+ .and_raise(Gitlab::Git::CommandError, 'Failed to import the repository /a/b/c')
+
+ result = subject.execute
+
+ expect(result[:status]).to eq :error
+ expect(result[:message]).to eq "Error importing repository #{project.safe_import_url} into #{project.full_path} - Failed to import the repository [FILTERED]"
end
- expect(Gitlab::AppLogger).to receive(:error).with("The Lfs import process failed. #{error_message}")
+ context 'when lfs import fails' do
+ it 'logs the error' do
+ error_message = 'error message'
- subject.execute
- end
- end
+ expect(project.repository).to receive(:import_repository).and_return(true)
- context 'when repository import scheduled' do
- before do
- expect(project.repository).to receive(:import_repository).and_return(true)
- allow(subject).to receive(:import_data)
- end
+ expect_next_instance_of(Gitlab::BitbucketImport::Importer) do |importer|
+ expect(importer).to receive(:execute).and_return(true)
+ end
- it 'downloads lfs objects if lfs_enabled is enabled for project' do
- allow(project).to receive(:lfs_enabled?).and_return(true)
+ expect_next_instance_of(Projects::LfsPointers::LfsImportService) do |service|
+ expect(service).to receive(:execute).and_return(status: :error, message: error_message)
+ end
- expect_any_instance_of(Projects::LfsPointers::LfsImportService).to receive(:execute)
+ expect(Gitlab::AppLogger).to receive(:error).with("The Lfs import process failed. #{error_message}")
- subject.execute
- end
+ subject.execute
+ end
+ end
- it 'does not download lfs objects if lfs_enabled is not enabled for project' do
- allow(project).to receive(:lfs_enabled?).and_return(false)
- expect_any_instance_of(Projects::LfsPointers::LfsImportService).not_to receive(:execute)
+ context 'when repository import scheduled' do
+ before do
+ expect(project.repository).to receive(:import_repository).and_return(true)
+ allow(subject).to receive(:import_data)
+ end
- subject.execute
+ it 'downloads lfs objects if lfs_enabled is enabled for project' do
+ allow(project).to receive(:lfs_enabled?).and_return(true)
+
+ expect_any_instance_of(Projects::LfsPointers::LfsImportService).to receive(:execute)
+
+ subject.execute
+ end
+
+ it 'does not download lfs objects if lfs_enabled is not enabled for project' do
+ allow(project).to receive(:lfs_enabled?).and_return(false)
+ expect_any_instance_of(Projects::LfsPointers::LfsImportService).not_to receive(:execute)
+
+ subject.execute
+ end
+ end
end
end
end
diff --git a/spec/services/projects/in_product_marketing_campaign_emails_service_spec.rb b/spec/services/projects/in_product_marketing_campaign_emails_service_spec.rb
index 4ad6fd0edff..fab8cafd1a0 100644
--- a/spec/services/projects/in_product_marketing_campaign_emails_service_spec.rb
+++ b/spec/services/projects/in_product_marketing_campaign_emails_service_spec.rb
@@ -4,33 +4,34 @@ require 'spec_helper'
RSpec.describe Projects::InProductMarketingCampaignEmailsService, feature_category: :experimentation_adoption do
describe '#execute' do
- let(:user) { create(:user, email_opted_in: true) }
+ let(:user) { create(:user) }
let(:project) { create(:project) }
let(:campaign) { Users::InProductMarketingEmail::BUILD_IOS_APP_GUIDE }
+ before do
+ allow(Notify)
+ .to receive(:build_ios_app_guide_email)
+ .and_return(instance_double(ActionMailer::MessageDelivery, deliver_later: true))
+ end
+
subject(:execute) do
described_class.new(project, campaign).execute
end
context 'users can receive marketing emails' do
- let(:owner) { create(:user, email_opted_in: true) }
- let(:maintainer) { create(:user, email_opted_in: true) }
- let(:developer) { create(:user, email_opted_in: true) }
+ let(:maintainer) { create(:user) }
+ let(:developer) { create(:user) }
before do
- project.add_owner(owner)
project.add_developer(developer)
project.add_maintainer(maintainer)
end
it 'sends the email to all project members with access_level >= Developer', :aggregate_failures do
- double = instance_double(ActionMailer::MessageDelivery, deliver_later: true)
-
- [owner, maintainer, developer].each do |user|
+ [project.owner, maintainer, developer].each do |user|
email = user.notification_email_or_default
- expect(Notify).to receive(:build_ios_app_guide_email).with(email) { double }
- expect(double).to receive(:deliver_later)
+ expect(Notify).to receive(:build_ios_app_guide_email).with(email)
end
execute
@@ -39,7 +40,7 @@ RSpec.describe Projects::InProductMarketingCampaignEmailsService, feature_catego
it 'records sent emails', :aggregate_failures do
expect { execute }.to change { Users::InProductMarketingEmail.count }.from(0).to(3)
- [owner, maintainer, developer].each do |user|
+ [project.owner, maintainer, developer].each do |user|
expect(
Users::InProductMarketingEmail.where(
user: user,
@@ -58,15 +59,24 @@ RSpec.describe Projects::InProductMarketingCampaignEmailsService, feature_catego
end
end
- shared_examples 'does nothing' do
- it 'does not send the email' do
+ shared_examples 'does not send the email' do
+ it do
email = user.notification_email_or_default
expect(Notify).not_to receive(:build_ios_app_guide_email).with(email)
execute
end
+ end
+
+ shared_examples 'does not create a record of the sent email' do
+ it do
+ expect(
+ Users::InProductMarketingEmail.where(
+ user: user,
+ campaign: campaign
+ )
+ ).not_to exist
- it 'does not create a record of the sent email' do
- expect { execute }.not_to change { Users::InProductMarketingEmail.count }
+ execute
end
end
@@ -94,12 +104,6 @@ RSpec.describe Projects::InProductMarketingCampaignEmailsService, feature_catego
execute
end
end
-
- context 'when user is not opted in to receive marketing emails' do
- let(:user) { create(:user, email_opted_in: false) }
-
- it_behaves_like 'does nothing'
- end
end
context 'when campaign email has already been sent to the user' do
@@ -108,7 +112,7 @@ RSpec.describe Projects::InProductMarketingCampaignEmailsService, feature_catego
create(:in_product_marketing_email, :campaign, user: user, campaign: campaign)
end
- it_behaves_like 'does nothing'
+ it_behaves_like 'does not send the email'
end
context "when user is a reporter" do
@@ -116,7 +120,8 @@ RSpec.describe Projects::InProductMarketingCampaignEmailsService, feature_catego
project.add_reporter(user)
end
- it_behaves_like 'does nothing'
+ it_behaves_like 'does not send the email'
+ it_behaves_like 'does not create a record of the sent email'
end
context "when user is a guest" do
@@ -124,7 +129,8 @@ RSpec.describe Projects::InProductMarketingCampaignEmailsService, feature_catego
project.add_guest(user)
end
- it_behaves_like 'does nothing'
+ it_behaves_like 'does not send the email'
+ it_behaves_like 'does not create a record of the sent email'
end
end
end
diff --git a/spec/services/projects/prometheus/alerts/notify_service_spec.rb b/spec/services/projects/prometheus/alerts/notify_service_spec.rb
index 73932887cd9..77e7be6cc0a 100644
--- a/spec/services/projects/prometheus/alerts/notify_service_spec.rb
+++ b/spec/services/projects/prometheus/alerts/notify_service_spec.rb
@@ -86,9 +86,9 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService, feature_category: :i
end
context 'with simultaneous manual configuration' do
- let_it_be(:integration) { create(:alert_management_prometheus_integration, :legacy, project: project) }
+ let_it_be(:alerting_setting) { create(:project_alerting_setting, :with_http_integration, project: project) }
let_it_be(:old_prometheus_integration) { create(:prometheus_integration, project: project) }
- let_it_be(:alerting_setting) { create(:project_alerting_setting, project: project, token: integration.token) }
+ let_it_be(:integration) { project.alert_management_http_integrations.last! }
subject { service.execute(integration.token, integration) }
diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb
index a113f3506e1..6c767876d05 100644
--- a/spec/services/projects/update_pages_service_spec.rb
+++ b/spec/services/projects/update_pages_service_spec.rb
@@ -20,13 +20,45 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
let(:custom_root_file_metadata) { "spec/fixtures/pages_with_custom_root.zip.meta" }
let(:metadata) { fixture_file_upload(metadata_filename) if File.exist?(metadata_filename) }
- subject { described_class.new(project, build) }
+ subject(:service) { described_class.new(project, build) }
+
+ RSpec.shared_examples 'pages size limit is' do |size_limit|
+ context "when size is below the limit" do
+ before do
+ allow(metadata).to receive(:total_size).and_return(size_limit - 1.megabyte)
+ allow(metadata).to receive(:entries).and_return([])
+ end
+
+ it 'updates pages correctly' do
+ subject.execute
+
+ deploy_status = GenericCommitStatus.last
+ expect(deploy_status.description).not_to be_present
+ expect(project.pages_metadatum).to be_deployed
+ end
+ end
+
+ context "when size is above the limit" do
+ before do
+ allow(metadata).to receive(:total_size).and_return(size_limit + 1.megabyte)
+ allow(metadata).to receive(:entries).and_return([])
+ end
+
+ it 'limits the maximum size of gitlab pages' do
+ subject.execute
+
+ deploy_status = GenericCommitStatus.last
+ expect(deploy_status.description).to match(/artifacts for pages are too large/)
+ expect(deploy_status).to be_script_failure
+ end
+ end
+ end
context 'when a deploy stage already exists', :aggregate_failures do
let!(:stage) { create(:ci_stage, name: 'deploy', pipeline: pipeline) }
it 'assigns the deploy stage' do
- expect { subject.execute }
+ expect { service.execute }
.to change(GenericCommitStatus, :count).by(1)
.and change(Ci::Stage.where(name: 'deploy'), :count).by(0)
@@ -41,7 +73,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
context 'when a deploy stage does not exists' do
it 'assigns the deploy stage' do
- expect { subject.execute }
+ expect { service.execute }
.to change(GenericCommitStatus, :count).by(1)
.and change(Ci::Stage.where(name: 'deploy'), :count).by(1)
@@ -64,7 +96,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
end
it "doesn't delete artifacts after deploying" do
- expect(execute).to eq(:success)
+ expect(service.execute[:status]).to eq(:success)
expect(project.pages_metadatum).to be_deployed
expect(build.artifacts?).to eq(true)
@@ -72,7 +104,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
it 'succeeds' do
expect(project.pages_deployed?).to be_falsey
- expect(execute).to eq(:success)
+ expect(service.execute[:status]).to eq(:success)
expect(project.pages_metadatum).to be_deployed
expect(project.pages_deployed?).to be_truthy
end
@@ -84,12 +116,12 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
root_namespace_id: project.root_namespace.id
}
- expect { subject.execute }.to publish_event(Pages::PageDeployedEvent).with(expected_data)
+ expect { service.execute }.to publish_event(Pages::PageDeployedEvent).with(expected_data)
end
it 'creates pages_deployment and saves it in the metadata' do
expect do
- expect(execute).to eq(:success)
+ expect(service.execute[:status]).to eq(:success)
end.to change { project.pages_deployments.count }.by(1)
deployment = project.pages_deployments.last
@@ -108,7 +140,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
project.reload
expect do
- expect(execute).to eq(:success)
+ expect(service.execute[:status]).to eq(:success)
end.to change { project.pages_deployments.count }.by(1)
expect(project.pages_metadatum.reload.pages_deployment).to eq(project.pages_deployments.last)
@@ -127,12 +159,12 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
)
)
- execute
+ service.execute
end
it 'removes older deployments', :sidekiq_inline do
expect do
- execute
+ service.execute
end.not_to change { PagesDeployment.count } # it creates one and deletes one
expect(PagesDeployment.find_by_id(old_deployment.id)).to be_nil
@@ -144,7 +176,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
let(:metadata_filename) { empty_metadata_filename }
it 'returns an error' do
- expect(execute).not_to eq(:success)
+ expect(service.execute[:status]).not_to eq(:success)
expect(GenericCommitStatus.last.description).to eq("Error: You need to either include a `public/` folder in your artifacts, or specify which one to use for Pages using `publish` in `.gitlab-ci.yml`")
end
@@ -158,7 +190,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
let(:options) { { publish: 'foo' } }
it 'creates pages_deployment and saves it in the metadata' do
- expect(execute).to eq(:success)
+ expect(service.execute[:status]).to eq(:success)
deployment = project.pages_deployments.last
expect(deployment.root_directory).to eq(options[:publish])
@@ -169,7 +201,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
let(:options) { { publish: 'bar' } }
it 'returns an error' do
- expect(execute).not_to eq(:success)
+ expect(service.execute[:status]).not_to eq(:success)
expect(GenericCommitStatus.last.description).to eq("Error: You need to either include a `public/` folder in your artifacts, or specify which one to use for Pages using `publish` in `.gitlab-ci.yml`")
end
@@ -181,7 +213,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
let(:metadata_filename) { "spec/fixtures/pages.zip.meta" }
it 'returns an error' do
- expect(execute).not_to eq(:success)
+ expect(service.execute[:status]).not_to eq(:success)
expect(GenericCommitStatus.last.description).to eq("Error: You need to either include a `public/` folder in your artifacts, or specify which one to use for Pages using `publish` in `.gitlab-ci.yml`")
end
@@ -190,13 +222,13 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
it 'limits pages size' do
stub_application_setting(max_pages_size: 1)
- expect(execute).not_to eq(:success)
+ expect(service.execute[:status]).not_to eq(:success)
end
it 'limits pages file count' do
create(:plan_limits, :default_plan, pages_file_entries: 2)
- expect(execute).not_to eq(:success)
+ expect(service.execute[:status]).not_to eq(:success)
expect(GenericCommitStatus.last.description).to eq("pages site contains 3 file entries, while limit is set to 2")
end
@@ -209,9 +241,11 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
end
it 'raises an error' do
- expect { execute }.to raise_error(SocketError)
+ expect { service.execute }.to raise_error(SocketError)
build.reload
+
+ deploy_status = GenericCommitStatus.last
expect(deploy_status).to be_failed
expect(project.pages_metadatum).not_to be_deployed
end
@@ -223,9 +257,11 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
end
it 'does not raise an error as failed job' do
- execute
+ service.execute
build.reload
+
+ deploy_status = GenericCommitStatus.last
expect(deploy_status).to be_failed
expect(project.pages_metadatum).not_to be_deployed
end
@@ -234,7 +270,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
context 'with background jobs running', :sidekiq_inline do
it 'succeeds' do
expect(project.pages_deployed?).to be_falsey
- expect(execute).to eq(:success)
+ expect(service.execute[:status]).to eq(:success)
end
end
@@ -246,41 +282,43 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
end
end
- shared_examples 'successfully deploys' do
- it 'succeeds' do
- expect do
- expect(execute).to eq(:success)
- end.to change { project.pages_deployments.count }.by(1)
+ it 'creates a new pages deployment and mark it as deployed' do
+ expect do
+ expect(service.execute[:status]).to eq(:success)
+ end.to change { project.pages_deployments.count }.by(1)
- deployment = project.pages_deployments.last
- expect(deployment.ci_build_id).to eq(build.id)
- end
+ deployment = project.pages_deployments.last
+ expect(deployment.ci_build_id).to eq(build.id)
end
- include_examples 'successfully deploys'
-
context 'when old deployment present' do
+ let!(:old_build) { create(:ci_build, name: 'pages', pipeline: old_pipeline, ref: 'HEAD') }
+ let!(:old_deployment) { create(:pages_deployment, ci_build: old_build, project: project) }
+
before do
- old_build = create(:ci_build, pipeline: old_pipeline, ref: 'HEAD')
- old_deployment = create(:pages_deployment, ci_build: old_build, project: project)
project.update_pages_deployment!(old_deployment)
end
- include_examples 'successfully deploys'
+ it 'deactivates old deployments' do
+ expect(service.execute[:status]).to eq(:success)
+
+ expect(old_deployment.reload.deleted_at).not_to be_nil
+ end
end
context 'when newer deployment present' do
before do
new_pipeline = create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha)
- new_build = create(:ci_build, pipeline: new_pipeline, ref: 'HEAD')
+ new_build = create(:ci_build, name: 'pages', pipeline: new_pipeline, ref: 'HEAD')
new_deployment = create(:pages_deployment, ci_build: new_build, project: project)
project.update_pages_deployment!(new_deployment)
end
it 'fails with outdated reference message' do
- expect(execute).to eq(:error)
+ expect(service.execute[:status]).to eq(:error)
expect(project.reload.pages_metadatum).not_to be_deployed
+ deploy_status = GenericCommitStatus.last
expect(deploy_status).to be_failed
expect(deploy_status.description).to eq('build SHA is outdated for this ref')
end
@@ -294,7 +332,7 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
.and_return(file.size + 1)
end
- expect(execute).not_to eq(:success)
+ expect(service.execute[:status]).not_to eq(:success)
expect(GenericCommitStatus.last.description).to eq('The uploaded artifact size does not match the expected value')
project.pages_metadatum.reload
@@ -318,18 +356,18 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
it 'fails with exception raised' do
expect do
- execute
+ service.execute
end.to raise_error("Validation failed: File sha256 can't be blank")
end
end
it 'fails if no artifacts' do
- expect(execute).not_to eq(:success)
+ expect(service.execute[:status]).not_to eq(:success)
end
it 'fails for invalid archive' do
create(:ci_job_artifact, :archive, file: invalid_file, job: build)
- expect(execute).not_to eq(:success)
+ expect(service.execute[:status]).not_to eq(:success)
end
describe 'maximum pages artifacts size' do
@@ -383,21 +421,13 @@ RSpec.describe Projects::UpdatePagesService, feature_category: :pages do
end
it 'marks older pages:deploy jobs retried' do
- expect(execute).to eq(:success)
+ expect(service.execute[:status]).to eq(:success)
expect(older_deploy_job.reload).to be_retried
+
+ deploy_status = GenericCommitStatus.last
expect(deploy_status.ci_stage).to eq(stage)
expect(deploy_status.stage_idx).to eq(stage.position)
end
end
-
- private
-
- def deploy_status
- GenericCommitStatus.where(name: 'pages:deploy').last
- end
-
- def execute
- subject.execute[:status]
- end
end
diff --git a/spec/services/projects/update_repository_storage_service_spec.rb b/spec/services/projects/update_repository_storage_service_spec.rb
index d3972009d38..b30c1d30044 100644
--- a/spec/services/projects/update_repository_storage_service_spec.rb
+++ b/spec/services/projects/update_repository_storage_service_spec.rb
@@ -229,6 +229,27 @@ RSpec.describe Projects::UpdateRepositoryStorageService, feature_category: :sour
end
end
+ context 'when new shard has a repository pool without the root project' do
+ let!(:new_pool_repository) { create(:pool_repository, :ready, shard: shard_to, disk_path: pool_repository.disk_path) }
+
+ before do
+ pool_repository.update!(source_project: nil)
+ new_pool_repository.update!(source_project: nil)
+ end
+
+ it 'connects project to it' do
+ result = subject.execute
+ expect(result).to be_success
+
+ project.reload.cleanup
+
+ project_pool_repository = project.pool_repository
+
+ expect(project_pool_repository).to eq(new_pool_repository)
+ expect(object_pool_double).to have_received(:link).with(project.repository.raw)
+ end
+ end
+
context 'when repository does not exist' do
let(:project) { create(:project) }
let(:checksum) { nil }
@@ -266,6 +287,32 @@ RSpec.describe Projects::UpdateRepositoryStorageService, feature_category: :sour
end
end
+ context 'when project belongs to the repository pool without a root project' do
+ let!(:pool_repository) { create(:pool_repository, :ready, shard: shard_from) }
+
+ before do
+ pool_repository.update!(source_project: nil)
+ project.update!(pool_repository: pool_repository)
+ end
+
+ it 'creates a new repository pool without a root project and connects project to it' do
+ result = subject.execute
+ expect(result).to be_success
+
+ project.reload.cleanup
+
+ new_pool_repository = project.pool_repository
+
+ expect(new_pool_repository).not_to eq(pool_repository)
+ expect(new_pool_repository.shard).to eq(shard_second_storage)
+ expect(new_pool_repository.state).to eq('ready')
+ expect(new_pool_repository.source_project).to eq(nil)
+ expect(new_pool_repository.disk_path).to eq(pool_repository.disk_path)
+
+ expect(object_pool_double).to have_received(:link).with(project.repository.raw)
+ end
+ end
+
context 'when object pool checksum does not match' do
let(:new_object_pool_checksum) { 'not_match' }
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index d9090b87514..195cfe78b3f 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -791,72 +791,26 @@ RSpec.describe Projects::UpdateService, feature_category: :groups_and_projects d
end
describe 'when updating pages unique domain', feature_category: :pages do
- let(:group) { create(:group, path: 'group') }
- let(:project) { create(:project, path: 'project', group: group) }
-
- it 'updates project pages unique domain' do
- expect do
- update_project(project, user, project_setting_attributes: {
- pages_unique_domain_enabled: true
- })
- end.to change { project.project_setting.pages_unique_domain_enabled }
-
- expect(project.project_setting.pages_unique_domain_enabled).to eq true
- expect(project.project_setting.pages_unique_domain).to match %r{project-group-\w+}
- end
-
- it 'does not changes unique domain when it already exists' do
- project.project_setting.update!(
- pages_unique_domain_enabled: false,
- pages_unique_domain: 'unique-domain'
- )
-
- expect do
- update_project(project, user, project_setting_attributes: {
- pages_unique_domain_enabled: true
- })
- end.to change { project.project_setting.pages_unique_domain_enabled }
-
- expect(project.project_setting.pages_unique_domain_enabled).to eq true
- expect(project.project_setting.pages_unique_domain).to eq 'unique-domain'
+ before do
+ stub_pages_setting(enabled: true)
end
- it 'does not changes unique domain when it disabling unique domain' do
- project.project_setting.update!(
- pages_unique_domain_enabled: true,
- pages_unique_domain: 'unique-domain'
- )
-
- expect do
- update_project(project, user, project_setting_attributes: {
- pages_unique_domain_enabled: false
- })
- end.not_to change { project.project_setting.pages_unique_domain }
+ context 'when turning it on' do
+ it 'adds pages unique domain' do
+ expect(Gitlab::Pages).to receive(:add_unique_domain_to)
- expect(project.project_setting.pages_unique_domain_enabled).to eq false
- expect(project.project_setting.pages_unique_domain).to eq 'unique-domain'
+ expect { update_project(project, user, project_setting_attributes: { pages_unique_domain_enabled: true }) }
+ .to change { project.project_setting.pages_unique_domain_enabled }
+ .from(false).to(true)
+ end
end
- context 'when there is another project with the unique domain' do
- it 'fails pages unique domain already exists' do
- create(
- :project_setting,
- pages_unique_domain_enabled: true,
- pages_unique_domain: 'unique-domain'
- )
-
- allow(Gitlab::Pages::RandomDomain)
- .to receive(:generate)
- .and_return('unique-domain')
+ context 'when turning it off' do
+ it 'adds pages unique domain' do
+ expect(Gitlab::Pages).not_to receive(:add_unique_domain_to)
- result = update_project(project, user, project_setting_attributes: {
- pages_unique_domain_enabled: true
- })
-
- expect(result).to eq(
- status: :error,
- message: 'Project setting pages unique domain has already been taken'
- )
+ expect { update_project(project, user, project_setting_attributes: { pages_unique_domain_enabled: false }) }
+ .not_to change { project.project_setting.pages_unique_domain_enabled }
end
end
end
diff --git a/spec/services/protected_branches/api_service_spec.rb b/spec/services/protected_branches/api_service_spec.rb
index f7f5f451a49..d7717f08efb 100644
--- a/spec/services/protected_branches/api_service_spec.rb
+++ b/spec/services/protected_branches/api_service_spec.rb
@@ -6,10 +6,12 @@ RSpec.describe ProtectedBranches::ApiService, feature_category: :compliance_mana
shared_examples 'execute with entity' do
it 'creates a protected branch with prefilled defaults' do
expect(::ProtectedBranches::CreateService).to receive(:new).with(
- entity, user, hash_including(
- push_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }],
- merge_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }]
- )
+ entity,
+ user,
+ hash_including(
+ push_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }],
+ merge_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }]
+ )
).and_call_original
expect(described_class.new(entity, user, { name: 'new name' }).create).to be_valid
@@ -17,10 +19,12 @@ RSpec.describe ProtectedBranches::ApiService, feature_category: :compliance_mana
it 'updates a protected branch without prefilled defaults' do
expect(::ProtectedBranches::UpdateService).to receive(:new).with(
- entity, user, hash_including(
- push_access_levels_attributes: [],
- merge_access_levels_attributes: []
- )
+ entity,
+ user,
+ hash_including(
+ push_access_levels_attributes: [],
+ merge_access_levels_attributes: []
+ )
).and_call_original
expect do
diff --git a/spec/services/push_event_payload_service_spec.rb b/spec/services/push_event_payload_service_spec.rb
index 50da5ca9b24..999b71ff754 100644
--- a/spec/services/push_event_payload_service_spec.rb
+++ b/spec/services/push_event_payload_service_spec.rb
@@ -190,9 +190,7 @@ RSpec.describe PushEventPayloadService, feature_category: :source_code_managemen
end
it 'returns :removed when removing an existing ref' do
- service = described_class.new(event,
- before: '123',
- after: Gitlab::Git::BLANK_SHA)
+ service = described_class.new(event, before: '123', after: Gitlab::Git::BLANK_SHA)
expect(service.action).to eq(:removed)
end
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 30a3c212ba5..5e7fb8397e3 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -29,9 +29,11 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
end
before do
- stub_licensed_features(multiple_issue_assignees: false,
- multiple_merge_request_reviewers: false,
- multiple_merge_request_assignees: false)
+ stub_licensed_features(
+ multiple_issue_assignees: false,
+ multiple_merge_request_reviewers: false,
+ multiple_merge_request_assignees: false
+ )
end
describe '#execute' do
@@ -1394,6 +1396,11 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
let(:issuable) { merge_request }
end
+ it_behaves_like 'subscribe command' do
+ let(:content) { '/subscribe' }
+ let(:issuable) { work_item }
+ end
+
it_behaves_like 'unsubscribe command' do
let(:content) { '/unsubscribe' }
let(:issuable) { issue }
@@ -1404,6 +1411,11 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
let(:issuable) { merge_request }
end
+ it_behaves_like 'unsubscribe command' do
+ let(:content) { '/unsubscribe' }
+ let(:issuable) { work_item }
+ end
+
it_behaves_like 'failed command', 'Could not apply due command.' do
let(:content) { '/due 2016-08-28' }
let(:issuable) { merge_request }
@@ -1860,11 +1872,21 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
let(:issuable) { merge_request }
end
+ it_behaves_like 'award command' do
+ let(:content) { '/award :100:' }
+ let(:issuable) { work_item }
+ end
+
context 'ignores command with no argument' do
it_behaves_like 'failed command' do
let(:content) { '/award' }
let(:issuable) { issue }
end
+
+ it_behaves_like 'failed command' do
+ let(:content) { '/award' }
+ let(:issuable) { work_item }
+ end
end
context 'ignores non-existing / invalid emojis' do
@@ -1877,6 +1899,11 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
let(:content) { '/award :lorem_ipsum:' }
let(:issuable) { issue }
end
+
+ it_behaves_like 'failed command' do
+ let(:content) { '/award :lorem_ipsum:' }
+ let(:issuable) { work_item }
+ end
end
context 'if issuable is a Commit' do
diff --git a/spec/services/releases/create_service_spec.rb b/spec/services/releases/create_service_spec.rb
index ca5dd912e77..0170c3abcaf 100644
--- a/spec/services/releases/create_service_spec.rb
+++ b/spec/services/releases/create_service_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe Releases::CreateService, feature_category: :continuous_integratio
context 'when project is a catalog resource' do
let(:ref) { 'master' }
- let!(:catalog_resource) { create(:catalog_resource, project: project) }
+ let!(:ci_catalog_resource) { create(:ci_catalog_resource, project: project) }
context 'and it is valid' do
let_it_be(:project) { create(:project, :repository, description: 'our components') }
diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb
index 953490ac379..2b6e96a781e 100644
--- a/spec/services/releases/destroy_service_spec.rb
+++ b/spec/services/releases/destroy_service_spec.rb
@@ -28,6 +28,26 @@ RSpec.describe Releases::DestroyService, feature_category: :release_orchestratio
it 'returns the destroyed object' do
is_expected.to include(status: :success, release: release)
end
+
+ context 'when the release is for a catalog resource' do
+ let!(:catalog_resource) { create(:ci_catalog_resource, project: project, state: 'published') }
+ let!(:version) { create(:ci_catalog_resource_version, catalog_resource: catalog_resource, release: release) }
+
+ it 'does not update the catalog resources if there are still releases' do
+ second_release = create(:release, project: project, tag: 'v1.2.0')
+ create(:ci_catalog_resource_version, catalog_resource: catalog_resource, release: second_release)
+
+ subject
+
+ expect(catalog_resource.reload.state).to eq('published')
+ end
+
+ it 'updates the catalog resource if there are no more releases' do
+ subject
+
+ expect(catalog_resource.reload.state).to eq('draft')
+ end
+ end
end
context 'when tag does not exist in the repository' do
@@ -42,9 +62,7 @@ RSpec.describe Releases::DestroyService, feature_category: :release_orchestratio
let!(:release) {}
it 'returns an error' do
- is_expected.to include(status: :error,
- message: 'Release does not exist',
- http_status: 404)
+ is_expected.to include(status: :error, message: 'Release does not exist', http_status: 404)
end
end
@@ -52,9 +70,7 @@ RSpec.describe Releases::DestroyService, feature_category: :release_orchestratio
let(:user) { repoter }
it 'returns an error' do
- is_expected.to include(status: :error,
- message: 'Access Denied',
- http_status: 403)
+ is_expected.to include(status: :error, message: 'Access Denied', http_status: 403)
end
end
diff --git a/spec/services/resource_access_tokens/revoke_service_spec.rb b/spec/services/resource_access_tokens/revoke_service_spec.rb
index c00146961e3..060697cd1df 100644
--- a/spec/services/resource_access_tokens/revoke_service_spec.rb
+++ b/spec/services/resource_access_tokens/revoke_service_spec.rb
@@ -33,8 +33,7 @@ RSpec.describe ResourceAccessTokens::RevokeService, feature_category: :system_ac
subject
expect(
- Users::GhostUserMigration.where(user: resource_bot,
- initiator_user: user)
+ Users::GhostUserMigration.where(user: resource_bot, initiator_user: user)
).to be_exists
end
diff --git a/spec/services/resource_events/change_labels_service_spec.rb b/spec/services/resource_events/change_labels_service_spec.rb
index 8393ce78df8..28b345f8191 100644
--- a/spec/services/resource_events/change_labels_service_spec.rb
+++ b/spec/services/resource_events/change_labels_service_spec.rb
@@ -49,10 +49,8 @@ RSpec.describe ResourceEvents::ChangeLabelsService, feature_category: :team_plan
expect(event.action).to eq(action)
end
- it 'expires resource note etag cache' do
- expect_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch).with(
- "/#{resource.project.namespace.to_param}/#{resource.project.to_param}/noteable/issue/#{resource.id}/notes"
- )
+ it 'broadcasts resource note change' do
+ expect(resource).to receive(:broadcast_notes_changed)
described_class.new(resource, author).execute(added_labels: [labels[0]])
end
@@ -126,9 +124,11 @@ RSpec.describe ResourceEvents::ChangeLabelsService, feature_category: :team_plan
change_labels
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_LABEL_CHANGED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_LABEL_CHANGED }
let(:user) { author }
+ let(:namespace) { project.namespace }
+
subject(:service_action) { change_labels }
end
end
diff --git a/spec/services/resource_events/merge_into_notes_service_spec.rb b/spec/services/resource_events/merge_into_notes_service_spec.rb
index 6eb6780d704..39dd2508728 100644
--- a/spec/services/resource_events/merge_into_notes_service_spec.rb
+++ b/spec/services/resource_events/merge_into_notes_service_spec.rb
@@ -61,8 +61,7 @@ RSpec.describe ResourceEvents::MergeIntoNotesService, feature_category: :team_pl
create_event(created_at: 4.days.ago)
event = create_event(created_at: 1.day.ago)
- notes = described_class.new(resource, user,
- last_fetched_at: 2.days.ago).execute
+ notes = described_class.new(resource, user, last_fetched_at: 2.days.ago).execute
expect(notes.count).to eq 1
expect(notes.first.discussion_id).to eq event.reload.discussion_id
diff --git a/spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb b/spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb
index 7ac2249642a..abd412097d2 100644
--- a/spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb
+++ b/spec/services/security/ci_configuration/dependency_scanning_create_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Security::CiConfiguration::DependencyScanningCreateService, :snowplow,
- feature_category: :software_composition_analysis do
+ feature_category: :software_composition_analysis do
subject(:result) { described_class.new(project, user).execute }
let(:branch_name) { 'set-dependency-scanning-config-1' }
diff --git a/spec/services/security/merge_reports_service_spec.rb b/spec/services/security/merge_reports_service_spec.rb
index 809d0b27c20..c141bbe5b5a 100644
--- a/spec/services/security/merge_reports_service_spec.rb
+++ b/spec/services/security/merge_reports_service_spec.rb
@@ -16,78 +16,87 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
let(:identifier_wasc) { build(:ci_reports_security_identifier, external_id: '13', external_type: 'wasc') }
let(:finding_id_1) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_1_primary, identifier_1_cve],
- scanner: scanner_1,
- severity: :low
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_1_primary, identifier_1_cve],
+ scanner: scanner_1,
+ severity: :low
+ )
end
let(:finding_id_1_extra) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_1_primary, identifier_1_cve],
- scanner: scanner_1,
- severity: :low
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_1_primary, identifier_1_cve],
+ scanner: scanner_1,
+ severity: :low
+ )
end
let(:finding_id_2_loc_1) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_2_primary, identifier_2_cve],
- location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34),
- scanner: scanner_2,
- severity: :medium
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_2_primary, identifier_2_cve],
+ location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34),
+ scanner: scanner_2,
+ severity: :medium
+ )
end
let(:finding_id_2_loc_1_extra) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_2_primary, identifier_2_cve],
- location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34),
- scanner: scanner_2,
- severity: :medium
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_2_primary, identifier_2_cve],
+ location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34),
+ scanner: scanner_2,
+ severity: :medium
+ )
end
let(:finding_id_2_loc_2) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_2_primary, identifier_2_cve],
- location: build(:ci_reports_security_locations_sast, start_line: 42, end_line: 44),
- scanner: scanner_2,
- severity: :medium
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_2_primary, identifier_2_cve],
+ location: build(:ci_reports_security_locations_sast, start_line: 42, end_line: 44),
+ scanner: scanner_2,
+ severity: :medium
+ )
end
let(:finding_cwe_1) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_cwe],
- scanner: scanner_3,
- severity: :high
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_cwe],
+ scanner: scanner_3,
+ severity: :high
+ )
end
let(:finding_cwe_2) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_cwe],
- scanner: scanner_1,
- severity: :critical
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_cwe],
+ scanner: scanner_1,
+ severity: :critical
+ )
end
let(:finding_wasc_1) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_wasc],
- scanner: scanner_1,
- severity: :medium
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_wasc],
+ scanner: scanner_1,
+ severity: :medium
+ )
end
let(:finding_wasc_2) do
- build(:ci_reports_security_finding,
- identifiers: [identifier_wasc],
- scanner: scanner_2,
- severity: :critical
- )
+ build(
+ :ci_reports_security_finding,
+ identifiers: [identifier_wasc],
+ scanner: scanner_2,
+ severity: :critical
+ )
end
let(:report_1_findings) { [finding_id_1, finding_id_2_loc_1, finding_id_2_loc_1_extra, finding_cwe_2, finding_wasc_1] }
diff --git a/spec/services/service_desk/custom_email_verifications/create_service_spec.rb b/spec/services/service_desk/custom_email_verifications/create_service_spec.rb
index fceb6fc78b4..0046213e0b2 100644
--- a/spec/services/service_desk/custom_email_verifications/create_service_spec.rb
+++ b/spec/services/service_desk/custom_email_verifications/create_service_spec.rb
@@ -14,6 +14,12 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::CreateService, feature_cat
let(:service) { described_class.new(project: project, current_user: user) }
+ let(:error_feature_flag_disabled) { 'Feature flag service_desk_custom_email is not enabled' }
+ let(:error_user_not_authorized) { s_('ServiceDesk|User cannot manage project.') }
+ let(:error_settings_missing) { s_('ServiceDesk|Service Desk setting missing') }
+ let(:expected_error_message) { error_settings_missing }
+ let(:logger_params) { { category: 'custom_email_verification' } }
+
before do
allow(message_delivery).to receive(:deliver_later)
allow(Notify).to receive(:service_desk_verification_triggered_email).and_return(message_delivery)
@@ -29,6 +35,10 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::CreateService, feature_cat
expect(service).to receive(:setup_and_deliver_verification_email).exactly(0).times
expect(Notify).to receive(:service_desk_verification_triggered_email).exactly(0).times
+ expect(Gitlab::AppLogger).to receive(:warn).with(logger_params.merge(
+ error_message: expected_error_message
+ )).once
+
response = service.execute
expect(response).to be_error
@@ -48,6 +58,10 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::CreateService, feature_cat
# Correct amount of result notification emails were sent
expect(Notify).to receive(:service_desk_verification_result_email).exactly(project.owners.size + 1).times
+ expect(Gitlab::AppLogger).to receive(:info).with(logger_params.merge(
+ error_message: error_identifier.to_s
+ )).once
+
response = service.execute
expect(response).to be_error
@@ -67,6 +81,8 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::CreateService, feature_cat
it_behaves_like 'a verification process that exits early'
context 'when feature flag :service_desk_custom_email is disabled' do
+ let(:expected_error_message) { error_feature_flag_disabled }
+
before do
stub_feature_flags(service_desk_custom_email: false)
end
@@ -77,12 +93,17 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::CreateService, feature_cat
context 'when service desk setting exists' do
let(:settings) { create(:service_desk_setting, project: project, custom_email: 'user@example.com') }
let(:service) { described_class.new(project: settings.project, current_user: user) }
+ let(:expected_error_message) { error_user_not_authorized }
it 'aborts verification process and exits early', :aggregate_failures do
# Because we exit early it should not send any verification or notification emails
expect(service).to receive(:setup_and_deliver_verification_email).exactly(0).times
expect(Notify).to receive(:service_desk_verification_triggered_email).exactly(0).times
+ expect(Gitlab::AppLogger).to receive(:warn).with(logger_params.merge(
+ error_message: expected_error_message
+ )).once
+
response = service.execute
settings.reload
@@ -105,6 +126,8 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::CreateService, feature_cat
# Check whether the correct amount of notification emails were sent
expect(Notify).to receive(:service_desk_verification_triggered_email).exactly(project.owners.size + 1).times
+ expect(Gitlab::AppLogger).to receive(:info).with(logger_params).once
+
response = service.execute
settings.reload
diff --git a/spec/services/service_desk/custom_email_verifications/update_service_spec.rb b/spec/services/service_desk/custom_email_verifications/update_service_spec.rb
index f1e683c0185..d882cd8635a 100644
--- a/spec/services/service_desk/custom_email_verifications/update_service_spec.rb
+++ b/spec/services/service_desk/custom_email_verifications/update_service_spec.rb
@@ -14,6 +14,16 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
let(:message_delivery) { instance_double(ActionMailer::MessageDelivery) }
let(:service) { described_class.new(project: settings.project, params: { mail: mail_object }) }
+ let(:error_feature_flag_disabled) { 'Feature flag service_desk_custom_email is not enabled' }
+ let(:error_parameter_missing) { s_('ServiceDesk|Service Desk setting or verification object missing') }
+ let(:error_already_finished) { s_('ServiceDesk|Custom email address has already been verified.') }
+ let(:error_already_failed) do
+ s_('ServiceDesk|Custom email address verification has already been processed and failed.')
+ end
+
+ let(:expected_error_message) { error_parameter_missing }
+ let(:logger_params) { { category: 'custom_email_verification' } }
+
before do
allow(message_delivery).to receive(:deliver_later)
allow(Notify).to receive(:service_desk_verification_result_email).and_return(message_delivery)
@@ -23,6 +33,10 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
it 'refuses to verify and sends result emails' do
expect(Notify).to receive(:service_desk_verification_result_email).twice
+ expect(Gitlab::AppLogger).to receive(:info).with(logger_params.merge(
+ error_message: expected_error_identifier.to_s
+ )).once
+
response = described_class.new(project: settings.project, params: { mail: mail_object }).execute
settings.reset
@@ -41,6 +55,10 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
it 'exits early' do
expect(Notify).to receive(:service_desk_verification_result_email).exactly(0).times
+ expect(Gitlab::AppLogger).to receive(:warn).with(logger_params.merge(
+ error_message: expected_error_message
+ )).once
+
response = service.execute
settings.reset
@@ -55,6 +73,10 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
it 'exits early' do
expect(Notify).to receive(:service_desk_verification_result_email).exactly(0).times
+ expect(Gitlab::AppLogger).to receive(:warn).with(logger_params.merge(
+ error_message: expected_error_message
+ )).once
+
response = service.execute
settings.reset
@@ -64,6 +86,8 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
end
context 'when feature flag :service_desk_custom_email is disabled' do
+ let(:expected_error_message) { error_feature_flag_disabled }
+
before do
stub_feature_flags(service_desk_custom_email: false)
end
@@ -71,6 +95,10 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
it 'exits early' do
expect(Notify).to receive(:service_desk_verification_result_email).exactly(0).times
+ expect(Gitlab::AppLogger).to receive(:warn).with(logger_params.merge(
+ error_message: expected_error_message
+ )).once
+
response = service.execute
expect(response).to be_error
@@ -85,6 +113,8 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
it_behaves_like 'a failing verification process', 'mail_not_received_within_timeframe'
context 'when already verified' do
+ let(:expected_error_message) { error_already_finished }
+
before do
verification.mark_as_finished!
end
@@ -93,6 +123,8 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
end
context 'when we already have an error' do
+ let(:expected_error_message) { error_already_failed }
+
before do
verification.mark_as_failed!(:smtp_host_issue)
end
@@ -112,6 +144,8 @@ RSpec.describe ServiceDesk::CustomEmailVerifications::UpdateService, feature_cat
it 'verifies and sends result emails' do
expect(Notify).to receive(:service_desk_verification_result_email).twice
+ expect(Gitlab::AppLogger).to receive(:info).with(logger_params).once
+
response = service.execute
settings.reset
diff --git a/spec/services/service_desk/custom_emails/create_service_spec.rb b/spec/services/service_desk/custom_emails/create_service_spec.rb
index 0d9582ba235..2029c9a0c3f 100644
--- a/spec/services/service_desk/custom_emails/create_service_spec.rb
+++ b/spec/services/service_desk/custom_emails/create_service_spec.rb
@@ -17,9 +17,14 @@ RSpec.describe ServiceDesk::CustomEmails::CreateService, feature_category: :serv
let(:params) { {} }
let(:message_delivery) { instance_double(ActionMailer::MessageDelivery) }
let(:message) { instance_double(Mail::Message) }
+ let(:logger_params) { { category: 'custom_email' } }
shared_examples 'a service that exits with error' do
it 'exits early' do
+ expect(Gitlab::AppLogger).to receive(:warn).with(logger_params.merge(
+ error_message: expected_error_message
+ )).once
+
response = service.execute
expect(response).to be_error
@@ -29,6 +34,10 @@ RSpec.describe ServiceDesk::CustomEmails::CreateService, feature_category: :serv
shared_examples 'a failing service that does not create records' do
it 'exits with error and does not create records' do
+ expect(Gitlab::AppLogger).to receive(:warn).with(logger_params.merge(
+ error_message: expected_error_message
+ )).once
+
response = service.execute
project.reset
@@ -148,6 +157,10 @@ RSpec.describe ServiceDesk::CustomEmails::CreateService, feature_category: :serv
end
it 'creates all records returns a successful response' do
+ # Because we also log in ServiceDesk::CustomEmailVerifications::CreateService
+ expect(Gitlab::AppLogger).to receive(:info).with({ category: 'custom_email_verification' }).once
+ expect(Gitlab::AppLogger).to receive(:info).with(logger_params).once
+
response = service.execute
project.reset
diff --git a/spec/services/service_desk/custom_emails/destroy_service_spec.rb b/spec/services/service_desk/custom_emails/destroy_service_spec.rb
index f5a22e26865..7f53a941d4e 100644
--- a/spec/services/service_desk/custom_emails/destroy_service_spec.rb
+++ b/spec/services/service_desk/custom_emails/destroy_service_spec.rb
@@ -12,9 +12,14 @@ RSpec.describe ServiceDesk::CustomEmails::DestroyService, feature_category: :ser
let(:error_user_not_authorized) { s_('ServiceDesk|User cannot manage project.') }
let(:error_does_not_exist) { s_('ServiceDesk|Custom email does not exist') }
let(:expected_error_message) { nil }
+ let(:logger_params) { { category: 'custom_email' } }
shared_examples 'a service that exits with error' do
it 'exits early' do
+ expect(Gitlab::AppLogger).to receive(:warn).with(logger_params.merge(
+ error_message: expected_error_message
+ )).once
+
response = service.execute
expect(response).to be_error
@@ -24,6 +29,8 @@ RSpec.describe ServiceDesk::CustomEmails::DestroyService, feature_category: :ser
shared_examples 'a successful service that destroys all custom email records' do
it 'ensures no custom email records exist' do
+ expect(Gitlab::AppLogger).to receive(:info).with(logger_params).once
+
project.reset
response = service.execute
diff --git a/spec/services/service_desk_settings/update_service_spec.rb b/spec/services/service_desk_settings/update_service_spec.rb
index ff564963677..27978225bcf 100644
--- a/spec/services/service_desk_settings/update_service_spec.rb
+++ b/spec/services/service_desk_settings/update_service_spec.rb
@@ -3,7 +3,12 @@ require 'spec_helper'
RSpec.describe ServiceDeskSettings::UpdateService, feature_category: :service_desk do
describe '#execute' do
- let_it_be(:settings) { create(:service_desk_setting, outgoing_name: 'original name') }
+ let_it_be(:settings) do
+ create(:service_desk_setting, outgoing_name: 'original name', custom_email: 'user@example.com')
+ end
+
+ let_it_be(:credential) { create(:service_desk_custom_email_credential, project: settings.project) }
+ let_it_be(:verification) { create(:service_desk_custom_email_verification, :finished, project: settings.project) }
let_it_be(:user) { create(:user) }
context 'with valid params' do
@@ -16,6 +21,24 @@ RSpec.describe ServiceDeskSettings::UpdateService, feature_category: :service_de
expect(settings.reload.outgoing_name).to eq 'some name'
expect(settings.reload.project_key).to eq 'foo'
end
+
+ context 'with custom email verification in finished state' do
+ let(:params) { { custom_email_enabled: true } }
+
+ before do
+ allow(Gitlab::AppLogger).to receive(:info)
+ end
+
+ it 'allows to enable custom email' do
+ settings.project.reset
+
+ response = described_class.new(settings.project, user, params).execute
+
+ expect(response).to be_success
+ expect(settings.reset.custom_email_enabled).to be true
+ expect(Gitlab::AppLogger).to have_received(:info).with({ category: 'custom_email' })
+ end
+ end
end
context 'when project_key is an empty string' do
diff --git a/spec/services/spam/spam_action_service_spec.rb b/spec/services/spam/spam_action_service_spec.rb
index fc86ecfe7f2..4133609d9ae 100644
--- a/spec/services/spam/spam_action_service_spec.rb
+++ b/spec/services/spam/spam_action_service_spec.rb
@@ -222,6 +222,9 @@ RSpec.describe Spam::SpamActionService, feature_category: :instance_resiliency d
end
context 'spam verdict service advises to block the user' do
+ # create a fresh user to ensure it is in the unbanned state
+ let(:user) { create(:user) }
+
before do
allow(fake_verdict_service).to receive(:execute).and_return(BLOCK_USER)
end
@@ -234,6 +237,14 @@ RSpec.describe Spam::SpamActionService, feature_category: :instance_resiliency d
expect(response.message).to match(expected_service_check_response_message)
expect(target).to be_spam
end
+
+ it 'bans the user' do
+ subject
+
+ custom_attribute = user.custom_attributes.by_key(UserCustomAttribute::AUTO_BANNED_BY_SPAM_LOG_ID).first
+ expect(custom_attribute.value).to eq(target.spam_log.id.to_s)
+ expect(user).to be_banned
+ end
end
context 'when spam verdict service conditionally allows' do
diff --git a/spec/services/system_notes/alert_management_service_spec.rb b/spec/services/system_notes/alert_management_service_spec.rb
index 1e3be24b05f..ac5682a35bb 100644
--- a/spec/services/system_notes/alert_management_service_spec.rb
+++ b/spec/services/system_notes/alert_management_service_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe ::SystemNotes::AlertManagementService, feature_category: :groups_
subject { described_class.new(noteable: noteable, project: project).create_new_alert('Some Service') }
it_behaves_like 'a system note' do
- let(:author) { User.alert_bot }
+ let(:author) { Users::Internal.alert_bot }
let(:action) { 'new_alert_added' }
end
@@ -62,7 +62,7 @@ RSpec.describe ::SystemNotes::AlertManagementService, feature_category: :groups_
subject { described_class.new(noteable: noteable, project: project).log_resolving_alert('Some Service') }
it_behaves_like 'a system note' do
- let(:author) { User.alert_bot }
+ let(:author) { Users::Internal.alert_bot }
let(:action) { 'new_alert_added' }
end
diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb
index af660a9b72e..4a795f2db20 100644
--- a/spec/services/system_notes/issuables_service_spec.rb
+++ b/spec/services/system_notes/issuables_service_spec.rb
@@ -28,6 +28,14 @@ RSpec.describe ::SystemNotes::IssuablesService, feature_category: :team_planning
expect(subject.note).to eq "marked this issue as related to #{noteable_ref.to_reference(project)}"
end
end
+
+ context 'with work items' do
+ let_it_be(:noteable) { create(:work_item, :task, project: project) }
+
+ it 'sets the note text with the correct work item type' do
+ expect(subject.note).to eq "marked this task as related to #{noteable_ref.to_reference(project)}"
+ end
+ end
end
describe '#unrelate_issuable' do
@@ -686,9 +694,10 @@ RSpec.describe ::SystemNotes::IssuablesService, feature_category: :team_planning
subject
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CLONED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_CLONED }
let(:user) { author }
+ let(:namespace) { project.namespace }
end
end
end
diff --git a/spec/services/system_notes/time_tracking_service_spec.rb b/spec/services/system_notes/time_tracking_service_spec.rb
index a3793880ff1..52b99a6976d 100644
--- a/spec/services/system_notes/time_tracking_service_spec.rb
+++ b/spec/services/system_notes/time_tracking_service_spec.rb
@@ -118,10 +118,10 @@ RSpec.describe ::SystemNotes::TimeTrackingService, feature_category: :team_plann
subject
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DUE_DATE_CHANGED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DUE_DATE_CHANGED }
let(:user) { author }
- subject(:service_action) { note }
+ let(:namespace) { project.namespace }
end
context 'when only start_date is added' do
@@ -231,10 +231,10 @@ RSpec.describe ::SystemNotes::TimeTrackingService, feature_category: :team_plann
subject
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_TIME_ESTIMATE_CHANGED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_TIME_ESTIMATE_CHANGED }
let(:user) { author }
- let(:service_action) { subject }
+ let(:namespace) { project.namespace }
end
end
@@ -363,13 +363,10 @@ RSpec.describe ::SystemNotes::TimeTrackingService, feature_category: :team_plann
subject
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_TIME_SPENT_CHANGED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_TIME_SPENT_CHANGED }
let(:user) { author }
- let(:service_action) do
- spend_time!(277200)
- subject
- end
+ let(:namespace) { project.namespace }
end
end
diff --git a/spec/services/users/authorized_build_service_spec.rb b/spec/services/users/authorized_build_service_spec.rb
index 7eed6833cba..a96854f33d9 100644
--- a/spec/services/users/authorized_build_service_spec.rb
+++ b/spec/services/users/authorized_build_service_spec.rb
@@ -12,5 +12,13 @@ RSpec.describe Users::AuthorizedBuildService, feature_category: :user_management
it_behaves_like 'common user build items'
it_behaves_like 'current user not admin build items'
+
+ context 'for additional authorized build allowed params' do
+ before do
+ params.merge!(external: true)
+ end
+
+ it { expect(user).to be_external }
+ end
end
end
diff --git a/spec/services/users/build_service_spec.rb b/spec/services/users/build_service_spec.rb
index f3236d40412..5f1949adc32 100644
--- a/spec/services/users/build_service_spec.rb
+++ b/spec/services/users/build_service_spec.rb
@@ -16,6 +16,57 @@ RSpec.describe Users::BuildService, feature_category: :user_management do
it_behaves_like 'common user build items'
it_behaves_like 'current user not admin build items'
+
+ context 'with "user_default_external" application setting' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:user_default_external, :external, :email, :user_default_internal_regex, :result) do
+ true | nil | 'fl@example.com' | nil | true
+ true | true | 'fl@example.com' | nil | true
+ true | false | 'fl@example.com' | nil | true # admin difference
+
+ true | nil | 'fl@example.com' | '' | true
+ true | true | 'fl@example.com' | '' | true
+ true | false | 'fl@example.com' | '' | true # admin difference
+
+ true | nil | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
+ true | true | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
+ true | false | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
+
+ true | nil | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true
+ true | true | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true
+ true | false | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true # admin difference
+
+ false | nil | 'fl@example.com' | nil | false
+ false | true | 'fl@example.com' | nil | false # admin difference
+ false | false | 'fl@example.com' | nil | false
+
+ false | nil | 'fl@example.com' | '' | false
+ false | true | 'fl@example.com' | '' | false # admin difference
+ false | false | 'fl@example.com' | '' | false
+
+ false | nil | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
+ false | true | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
+ false | false | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
+
+ false | nil | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false
+ false | true | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
+ false | false | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false
+ end
+
+ with_them do
+ before do
+ stub_application_setting(user_default_external: user_default_external)
+ stub_application_setting(user_default_internal_regex: user_default_internal_regex)
+
+ params.merge!({ external: external, email: email }.compact)
+ end
+
+ it 'sets the value of Gitlab::CurrentSettings.user_default_external' do
+ expect(user.external).to eq(result)
+ end
+ end
+ end
end
context 'with non admin current_user' do
diff --git a/spec/services/users/migrate_records_to_ghost_user_service_spec.rb b/spec/services/users/migrate_records_to_ghost_user_service_spec.rb
index 36b2730a2de..d6fb7a2954d 100644
--- a/spec/services/users/migrate_records_to_ghost_user_service_spec.rb
+++ b/spec/services/users/migrate_records_to_ghost_user_service_spec.rb
@@ -100,7 +100,11 @@ RSpec.describe Users::MigrateRecordsToGhostUserService, feature_category: :user_
context "when the awardable already has an award emoji of the same name assigned to the ghost user" do
let(:awardable) { create(:issue) }
- let!(:existing_award_emoji) { create(:award_emoji, user: User.ghost, name: "thumbsup", awardable: awardable) }
+
+ let!(:existing_award_emoji) do
+ create(:award_emoji, user: Users::Internal.ghost, name: "thumbsup", awardable: awardable)
+ end
+
let!(:award_emoji) { create(:award_emoji, user: user, name: "thumbsup", awardable: awardable) }
it "migrates the award emoji regardless" do
@@ -108,7 +112,7 @@ RSpec.describe Users::MigrateRecordsToGhostUserService, feature_category: :user_
migrated_record = AwardEmoji.find_by_id(award_emoji.id)
- expect(migrated_record.user).to eq(User.ghost)
+ expect(migrated_record.user).to eq(Users::Internal.ghost)
end
it "does not leave the migrated award emoji in an invalid state" do
@@ -322,7 +326,7 @@ RSpec.describe Users::MigrateRecordsToGhostUserService, feature_category: :user_
service.execute
expect(gitlab_shell.repository_exists?(repo.shard_name, "#{repo.disk_path}.git")).to be(true)
- expect(User.ghost.snippets).to include(repo.snippet)
+ expect(Users::Internal.ghost.snippets).to include(repo.snippet)
end
context 'when an error is raised deleting snippets' do
diff --git a/spec/services/users/upsert_credit_card_validation_service_spec.rb b/spec/services/users/upsert_credit_card_validation_service_spec.rb
index ebd2502398d..4e23b51cae2 100644
--- a/spec/services/users/upsert_credit_card_validation_service_spec.rb
+++ b/spec/services/users/upsert_credit_card_validation_service_spec.rb
@@ -101,6 +101,14 @@ RSpec.describe Users::UpsertCreditCardValidationService, feature_category: :user
end
context 'when unexpected exception happen' do
+ let(:exception) { StandardError.new }
+
+ before do
+ allow_next_instance_of(::Users::CreditCardValidation) do |instance|
+ allow(instance).to receive(:save).and_raise(exception)
+ end
+ end
+
it 'tracks the exception and returns an error' do
logged_params = {
credit_card_validated_at: credit_card_validated_time,
@@ -111,8 +119,7 @@ RSpec.describe Users::UpsertCreditCardValidationService, feature_category: :user
user_id: user_id
}
- expect(::Users::CreditCardValidation).to receive(:upsert).and_raise(e = StandardError.new('My exception!'))
- expect(Gitlab::ErrorTracking).to receive(:track_exception).with(e, class: described_class.to_s, params: logged_params)
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(exception, class: described_class.to_s, params: logged_params)
result = service.execute
diff --git a/spec/services/work_items/related_work_item_links/destroy_service_spec.rb b/spec/services/work_items/related_work_item_links/destroy_service_spec.rb
new file mode 100644
index 00000000000..39381078c45
--- /dev/null
+++ b/spec/services/work_items/related_work_item_links/destroy_service_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::RelatedWorkItemLinks::DestroyService, feature_category: :portfolio_management do
+ describe '#execute' do
+ let_it_be(:project) { create(:project_empty_repo, :private) }
+ let_it_be(:other_project) { create(:project_empty_repo, :private) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:source) { create(:work_item, project: project) }
+ let_it_be(:linked_item1) { create(:work_item, project: project) }
+ let_it_be(:linked_item2) { create(:work_item, project: project) }
+ let_it_be(:no_access_item) { create(:work_item, project: other_project) }
+ let_it_be(:not_linked_item) { create(:work_item, project: project) }
+
+ let_it_be(:link1) { create(:work_item_link, source: source, target: linked_item1) }
+ let_it_be(:link2) { create(:work_item_link, source: source, target: linked_item2) }
+ let_it_be(:link3) { create(:work_item_link, source: source, target: no_access_item) }
+
+ let(:ids_to_remove) { [linked_item1.id, linked_item2.id, no_access_item.id, not_linked_item.id] }
+
+ subject(:destroy_links) { described_class.new(source, user, { item_ids: ids_to_remove }).execute }
+
+ context 'when user can `admin_work_item_link` for the work item' do
+ before_all do
+ project.add_guest(user)
+ end
+
+ it 'removes existing linked items with access' do
+ expect { destroy_links }.to change { WorkItems::RelatedWorkItemLink.count }.by(-2)
+ end
+
+ it 'creates notes for the source and target of each removed link' do
+ [linked_item1, linked_item2].each do |item|
+ expect(SystemNoteService).to receive(:unrelate_issuable).with(source, item, user)
+ expect(SystemNoteService).to receive(:unrelate_issuable).with(item, source, user)
+ end
+
+ destroy_links
+ end
+
+ it 'returns correct response message' do
+ message = "Successfully unlinked IDs: #{linked_item1.id} and #{linked_item2.id}. IDs with errors: " \
+ "#{no_access_item.id} could not be removed due to insufficient permissions, " \
+ "#{not_linked_item.id} could not be removed due to not being linked."
+
+ is_expected.to eq(
+ status: :success,
+ message: message,
+ items_removed: [linked_item1.id, linked_item2.id],
+ items_with_errors: [no_access_item.id]
+ )
+ end
+
+ context 'when all items fail' do
+ let(:ids_to_remove) { [no_access_item.id] }
+ let(:params) { { item_ids: [no_access_item.id] } }
+ let(:error_msg) { "IDs with errors: #{ids_to_remove[0]} could not be removed due to insufficient permissions." }
+
+ it 'returns an error response' do
+ expect { destroy_links }.not_to change { WorkItems::RelatedWorkItemLink.count }
+
+ is_expected.to eq(status: :error, message: error_msg)
+ end
+ end
+
+ context 'when item_ids is empty' do
+ let(:ids_to_remove) { [] }
+
+ it 'returns error response' do
+ is_expected.to eq(message: 'No work item IDs provided.', status: :error, http_status: 409)
+ end
+ end
+ end
+
+ context 'when user cannot `admin_work_item_link` for the work item' do
+ it 'returns error response' do
+ is_expected.to eq(message: 'No work item found.', status: :error, http_status: 403)
+ end
+ end
+ end
+end
diff --git a/spec/services/work_items/update_service_spec.rb b/spec/services/work_items/update_service_spec.rb
index 8e19650d980..38e5d4dc153 100644
--- a/spec/services/work_items/update_service_spec.rb
+++ b/spec/services/work_items/update_service_spec.rb
@@ -76,9 +76,10 @@ RSpec.describe WorkItems::UpdateService, feature_category: :team_planning do
expect(update_work_item[:status]).to eq(:success)
end
- it_behaves_like 'issue_edit snowplow tracking' do
- let(:property) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_TITLE_CHANGED }
+ it_behaves_like 'internal event tracking' do
+ let(:action) { Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_TITLE_CHANGED }
let(:user) { current_user }
+ let(:namespace) { project.namespace }
subject(:service_action) { update_work_item[:status] }
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index d7ceab1289e..f53e930f529 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -24,6 +24,7 @@ CrystalballEnv.start!
ENV["RAILS_ENV"] = 'test'
ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true'
ENV["RSPEC_ALLOW_INVALID_URLS"] = 'true'
+ENV['USE_CI_BUILDS_ROUTING_TABLE'] = 'true'
require_relative '../config/environment'
@@ -178,10 +179,12 @@ RSpec.configure do |config|
config.include Devise::Test::IntegrationHelpers, type: :feature
config.include Devise::Test::IntegrationHelpers, type: :request
config.include LoginHelpers, type: :feature
+ config.include SignUpHelpers, type: :feature
config.include SearchHelpers, type: :feature
config.include WaitHelpers, type: :feature
config.include WaitForRequests, type: :feature
config.include Features::DomHelpers, type: :feature
+ config.include Features::HighlightContentHelper, type: :feature
config.include EmailHelpers, :mailer, type: :mailer
config.include Warden::Test::Helpers, type: :request
config.include Gitlab::Routing, type: :routing
@@ -210,6 +213,7 @@ RSpec.configure do |config|
config.include RequestUrgencyMatcher, type: :request
config.include Capybara::RSpecMatchers, type: :request
config.include PendingDirectUploadHelpers, :direct_uploads
+ config.include LabelsHelper, type: :feature
config.include_context 'when rendered has no HTML escapes', type: :view
@@ -294,16 +298,6 @@ RSpec.configure do |config|
stub_feature_flags(ci_queueing_disaster_recovery_disable_fair_scheduling: false)
stub_feature_flags(ci_queueing_disaster_recovery_disable_quota: false)
- # Only a few percent of users will be "enrolled" into the new nav with this flag.
- # Having it enabled globally would make it impossible to test the current nav.
- # https://gitlab.com/gitlab-org/gitlab/-/issues/420121
- stub_feature_flags(super_sidebar_nav_enrolled: false)
-
- # The anonymous super-sidebar is under heavy development and enabling the flag
- # globally leads to a lot of errors. This issue is for fixing all test to work with the
- # new nav: https://gitlab.com/gitlab-org/gitlab/-/issues/420119
- stub_feature_flags(super_sidebar_logged_out: false)
-
# It's disabled in specs because we don't support certain features which
# cause spec failures.
stub_feature_flags(gitlab_error_tracking: false)
@@ -349,6 +343,8 @@ RSpec.configure do |config|
# Postgres is the primary data source, and ClickHouse only when enabled in certain cases.
stub_feature_flags(clickhouse_data_collection: false)
+ stub_feature_flags(vite: false)
+
allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
else
unstub_all_feature_flags
@@ -398,8 +394,8 @@ RSpec.configure do |config|
end
config.around(:example, :quarantine) do |example|
- # Skip tests in quarantine unless we explicitly focus on them.
- example.run if config.inclusion_filter[:quarantine]
+ # Skip tests in quarantine unless we explicitly focus on them or not in CI
+ example.run if config.inclusion_filter[:quarantine] || !ENV['CI']
end
config.around(:example, :request_store) do |example|
@@ -491,6 +487,34 @@ RSpec.configure do |config|
config.before(:each, :js) do
allow_any_instance_of(VersionCheck).to receive(:response).and_return({ "severity" => "success" })
end
+
+ [:migration, :delete].each do |spec_type|
+ message = <<~STRING
+ We detected an open transaction before running the example. This is not allowed with specs that rely on a table
+ deletion strategy like those marked as `:#{spec_type}`.
+
+ A common scenario for this is using `test-prof` methods in your specs. `let_it_be` and `before_all` methods open
+ a transaction before all the specs in a context are run, and this is not compatible with these type of specs.
+ Consider replacing these methods with `let!` and `before(:all)`.
+
+ For more information see
+ https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#testprof-in-migration-specs
+ STRING
+
+ config.around(:each, spec_type) do |example|
+ self.class.use_transactional_tests = false
+
+ if DbCleaner.all_connection_classes.any? { |klass| klass.connection.transaction_open? }
+ raise message
+ end
+
+ example.run
+
+ delete_from_all_tables!(except: deletion_except_tables)
+
+ self.class.use_transactional_tests = true
+ end
+ end
end
# Disabled because it's causing N+1 queries.
diff --git a/spec/support/before_all_adapter.rb b/spec/support/before_all_adapter.rb
index f4946ff271f..35846fcecb8 100644
--- a/spec/support/before_all_adapter.rb
+++ b/spec/support/before_all_adapter.rb
@@ -25,20 +25,9 @@ module TestProfBeforeAllAdapter
end
end
- # This class is required so we can disable transactions on migration specs
- module NoTransactionAdapter
- def self.begin_transaction; end
-
- def self.rollback_transaction; end
- end
-
def self.default_adapter
MultipleDatabaseAdapter
end
-
- def self.no_transaction_adapter
- NoTransactionAdapter
- end
end
TestProf::BeforeAll.adapter = ::TestProfBeforeAllAdapter.default_adapter
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index 392743fda4a..65abbe12621 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -54,11 +54,7 @@ Capybara.register_server :puma_via_workhorse do |app, port, host, **options|
# In cases of multiple installations of chromedriver, prioritize the version installed by SeleniumManager
# selenium-manager doesn't work with Linux arm64 yet:
# https://github.com/SeleniumHQ/selenium/issues/11357
- if RUBY_PLATFORM.include?('x86_64-linux') ||
- # Rosetta is required on macOS because the selenium-manager
- # binaries (https://github.com/SeleniumHQ/selenium/tree/trunk/common/manager/macos)
- # are only compiled for macOS x86.
- (RUBY_PLATFORM.include?('darwin') && system('/usr/bin/pgrep -q oahd'))
+ if RUBY_PLATFORM.include?('x86_64-linux') || RUBY_PLATFORM.include?('darwin')
chrome_options = Selenium::WebDriver::Chrome::Options.chrome
chromedriver_path = File.dirname(Selenium::WebDriver::SeleniumManager.driver_path(chrome_options))
ENV['PATH'] = "#{chromedriver_path}:#{ENV['PATH']}" # rubocop:disable RSpec/EnvAssignment
diff --git a/spec/support/capybara_wait_for_all_requests.rb b/spec/support/capybara_wait_for_all_requests.rb
index 36b63619b08..6f272474cf6 100644
--- a/spec/support/capybara_wait_for_all_requests.rb
+++ b/spec/support/capybara_wait_for_all_requests.rb
@@ -9,9 +9,11 @@ module Capybara
include CapybaraHelpers
include WaitForRequests
- def visit(visit_uri)
+ def visit(visit_uri, &block)
super
+ yield if block
+
wait_for_all_requests
end
end
@@ -24,24 +26,26 @@ module Capybara
include CapybaraHelpers
include WaitForRequests
- module WaitForAllRequestsAfterClickButton
+ module WaitForRequestsAfterClickButton
def click_button(locator = nil, **options)
super
- wait_for_all_requests
+ wait_for_requests
end
end
- module WaitForAllRequestsAfterClickLink
- def click_link(locator = nil, **options)
+ module WaitForRequestsAfterClickLink
+ def click_link(locator = nil, **options, &block)
super
- wait_for_all_requests
+ yield if block
+
+ wait_for_requests
end
end
- prepend WaitForAllRequestsAfterClickButton
- prepend WaitForAllRequestsAfterClickLink
+ prepend WaitForRequestsAfterClickButton
+ prepend WaitForRequestsAfterClickLink
end
end
end
diff --git a/spec/support/database/auto_explain.rb b/spec/support/database/auto_explain.rb
index 108d88e37b9..799457034a1 100644
--- a/spec/support/database/auto_explain.rb
+++ b/spec/support/database/auto_explain.rb
@@ -115,11 +115,16 @@ module AutoExplain
private
def record_auto_explain?(connection)
- ENV['CI'] \
- && ENV['CI_MERGE_REQUEST_LABELS']&.include?('pipeline:record-queries') \
- && ENV['CI_JOB_NAME_SLUG'] != 'db-migrate-non-superuser' \
- && connection.database_version.to_s[0..1].to_i >= 14 \
- && connection.select_one('SHOW is_superuser')['is_superuser'] == 'on'
+ return false unless ENV['CI']
+ return false if ENV['CI_JOB_NAME_SLUG'] == 'db-migrate-non-superuser'
+ return false if connection.database_version.to_s[0..1].to_i < 14
+ return false if connection.select_one('SHOW is_superuser')['is_superuser'] != 'on'
+
+ # This condition matches the pipeline rules for if-merge-request-labels-record-queries
+ return true if ENV['CI_MERGE_REQUEST_LABELS']&.include?('pipeline:record-queries')
+
+ # This condition matches the pipeline rules for if-default-branch-refs
+ ENV['CI_COMMIT_REF_NAME'] == ENV['CI_DEFAULT_BRANCH'] && !ENV['CI_MERGE_REQUEST_IID']
end
end
end
diff --git a/spec/support/database/click_house/hooks.rb b/spec/support/database/click_house/hooks.rb
index 27abd19dc3f..b970d3daf84 100644
--- a/spec/support/database/click_house/hooks.rb
+++ b/spec/support/database/click_house/hooks.rb
@@ -4,7 +4,13 @@
class ClickHouseTestRunner
def truncate_tables
ClickHouse::Client.configuration.databases.each_key do |db|
- tables_for(db).each do |table|
+ # Select tables with at least one row
+ query = tables_for(db).map do |table|
+ "(SELECT '#{table}' AS table FROM #{table} LIMIT 1)"
+ end.join(' UNION ALL ')
+
+ tables_with_data = ClickHouse::Client.select(query, db).pluck('table')
+ tables_with_data.each do |table|
ClickHouse::Client.execute("TRUNCATE TABLE #{table}", db)
end
end
diff --git a/spec/support/database/prevent_cross_database_modification.rb b/spec/support/database/prevent_cross_database_modification.rb
index 77fa7feacd4..02572d011f7 100644
--- a/spec/support/database/prevent_cross_database_modification.rb
+++ b/spec/support/database/prevent_cross_database_modification.rb
@@ -1,15 +1,53 @@
# frozen_string_literal: true
-module PreventCrossDatabaseModificationSpecHelpers
- delegate :with_cross_database_modification_prevented,
- :allow_cross_database_modification_within_transaction,
- to: :'::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification'
+module Database
+ module PreventCrossDatabaseModificationSpecHelpers
+ delegate :with_cross_database_modification_prevented,
+ :allow_cross_database_modification_within_transaction,
+ to: :'::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification'
+ end
+
+ module AllowCrossDatabaseFactoryBotBuilt
+ extend ActiveSupport::Concern
+
+ attr_accessor :factory_bot_built
+
+ prepended do
+ around_create :_test_ignore_table_in_transaction, prepend: true, if: :factory_bot_built?
+
+ def _test_ignore_table_in_transaction(&blk)
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ [self.class.table_name], url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130277', &blk
+ )
+ end
+ end
+
+ def factory_bot_built?
+ return false unless Rails.env.test?
+
+ !!factory_bot_built
+ end
+
+ private
+
+ def ignore_cross_database_tables_if_factory_bot(tables, &blk)
+ return super unless factory_bot_built?
+
+ Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
+ tables,
+ url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130277',
+ &blk
+ )
+ end
+ end
end
+ActiveRecord::Base.prepend(Database::AllowCrossDatabaseFactoryBotBuilt)
+
CROSS_DB_MODIFICATION_ALLOW_LIST = Set.new(YAML.load_file(File.join(__dir__, 'cross-database-modification-allowlist.yml'))).freeze
RSpec.configure do |config|
- config.include(PreventCrossDatabaseModificationSpecHelpers)
+ config.include(Database::PreventCrossDatabaseModificationSpecHelpers)
# By default allow cross-modifications as we want to observe only transactions
# within a specific block of execution which is defined be `before(:each)` and `after(:each)`
diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb
index 7bd1f0c5dfa..1ffc1cc25fd 100644
--- a/spec/support/database_cleaner.rb
+++ b/spec/support/database_cleaner.rb
@@ -12,14 +12,4 @@ RSpec.configure do |config|
setup_database_cleaner
DatabaseCleaner.clean_with(:deletion)
end
-
- config.around(:each, :delete) do |example|
- self.class.use_transactional_tests = false
-
- example.run
-
- delete_from_all_tables!(except: deletion_except_tables)
-
- self.class.use_transactional_tests = true
- end
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index 17b4270fa20..3131a22a20b 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -73,7 +73,10 @@ module DbCleaner
end
end
+ disable_ddl_was = Feature.enabled?(:disallow_database_ddl_feature_flags, type: :ops)
+ stub_feature_flags(disallow_database_ddl_feature_flags: false)
Gitlab::Database::Partitioning.sync_partitions_ignore_db_error
+ stub_feature_flags(disallow_database_ddl_feature_flags: disable_ddl_was)
puts "Databases re-creation done in #{Gitlab::Metrics::System.monotonic_time - start}"
end
diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb
index 6faa2db3330..d30098a5cc0 100644
--- a/spec/support/factory_bot.rb
+++ b/spec/support/factory_bot.rb
@@ -1,5 +1,19 @@
# frozen_string_literal: true
+FactoryBot.define do
+ after(:build) do |object, _|
+ next unless object.respond_to?(:factory_bot_built=)
+
+ object.factory_bot_built = true
+ end
+
+ before(:create) do |object, _|
+ next unless object.respond_to?(:factory_bot_built=)
+
+ object.factory_bot_built = false
+ end
+end
+
FactoryBot::SyntaxRunner.class_eval do
include RSpec::Mocks::ExampleMethods
include StubMethodCalls
diff --git a/spec/support/finder_collection_allowlist.yml b/spec/support/finder_collection_allowlist.yml
index 5de8e8cdca2..860045c6ce6 100644
--- a/spec/support/finder_collection_allowlist.yml
+++ b/spec/support/finder_collection_allowlist.yml
@@ -7,6 +7,7 @@
- Namespaces::FreeUserCap::UsersFinder # Reason: There is no need to have anything else besides the count
- Groups::EnvironmentScopesFinder # Reason: There is no need to have anything else besides the simple strucutre with the scope name
- Security::RelatedPipelinesFinder # Reason: There is no need to have anything else besides the IDs of pipelines
+- Llm::ExtraResourceFinder # Reason: The finder does not deal with DB-backend resource for now.
# Temporary excludes (aka TODOs)
# For example:
@@ -61,11 +62,6 @@
- Security::PipelineVulnerabilitiesFinder
- Security::ScanExecutionPoliciesFinder
- Security::ScanResultPoliciesFinder
-- Security::TrainingProviders::BaseUrlFinder
-- Security::TrainingUrlsFinder
-- Security::TrainingProviders::KontraUrlFinder
-- Security::TrainingProviders::SecureCodeWarriorUrlFinder
-- Security::TrainingProviders::SecureFlagUrlFinder
- SentryIssueFinder
- ServerlessDomainFinder
- TagsFinder
diff --git a/spec/support/gitlab_stubs/gitlab_ci_dast_includes.yml b/spec/support/gitlab_stubs/gitlab_ci_dast_includes.yml
index 583d44c452e..097cbf5b0c8 100644
--- a/spec/support/gitlab_stubs/gitlab_ci_dast_includes.yml
+++ b/spec/support/gitlab_stubs/gitlab_ci_dast_includes.yml
@@ -1,3 +1,6 @@
+stages:
+ - dast
+
dast:
stage: dast
image:
@@ -7,4 +10,6 @@ dast:
allow_failure: true
dast_configuration:
site_profile: "site_profile_name_included"
- scanner_profile: "scanner_profile_name_included" \ No newline at end of file
+ scanner_profile: "scanner_profile_name_included"
+ script:
+ - echo "Runs DAST!"
diff --git a/spec/support/helpers/database/duplicate_indexes.rb b/spec/support/helpers/database/duplicate_indexes.rb
new file mode 100644
index 00000000000..0ad8ee1e055
--- /dev/null
+++ b/spec/support/helpers/database/duplicate_indexes.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+module Database
+ class DuplicateIndexes
+ attr_accessor :table_name, :indexes
+
+ BTREE_INDEX_STRUCT = Struct.new(:name, :columns, :unique)
+
+ def initialize(table_name, indexes)
+ @table_name = table_name
+ @indexes = indexes
+ end
+
+ def duplicate_indexes
+ ret = {}
+
+ btree_indexes.each do |btree_index|
+ matching_indexes = matching_indexes_for(btree_index)
+ next unless matching_indexes.any?
+
+ ret[btree_index] = matching_indexes
+ end
+
+ ret
+ end
+
+ def self.btree_index_struct(index)
+ BTREE_INDEX_STRUCT.new(
+ index.name,
+ Array.wrap(index.columns).map do |column|
+ # https://apidock.com/rails/ActiveRecord/ConnectionAdapters/PostgreSQL/SchemaStatements/indexes
+ # asc is the default order
+ column_order = index.orders.is_a?(Symbol) ? index.orders : (index.orders[column] || :asc)
+ { name: column, order: column_order }
+ end,
+ index.unique
+ )
+ end
+
+ private
+
+ def btree_indexes
+ return @btree_indexes if @btree_indexes
+
+ # We only scan non-conditional btree indexes
+ @btree_indexes = indexes.select do |index|
+ index.using == :btree && index.where.nil? && index.opclasses.blank?
+ end
+
+ @btree_indexes = @btree_indexes.map { |index| self.class.btree_index_struct(index) }
+ end
+
+ def matching_indexes_for(btree_index)
+ all_matching_indexes = []
+
+ # When comparing btree_index with other_index. btree_index is the index that can have more columns
+ # than the other_index.
+ (1..btree_index.columns.length).each do |subset_length|
+ columns = btree_index.columns.first(subset_length)
+ matching_indexes = btree_indexes.reject { |other_index| other_index == btree_index }.select do |other_index|
+ other_index.columns == columns
+ end
+
+ # For now we ignore other indexes that are UNIQUE and have a matching columns subset of
+ # the btree_index columns, as UNIQUE indexes are still needed to enforce uniqueness
+ # constraints on subset of the columns.
+ matching_indexes = matching_indexes.reject do |other_index|
+ (other_index.unique && (other_index.columns.length < btree_index.columns.length))
+ end
+
+ all_matching_indexes += matching_indexes
+ end
+
+ all_matching_indexes
+ end
+ end
+end
diff --git a/spec/support/helpers/database/duplicate_indexes.yml b/spec/support/helpers/database/duplicate_indexes.yml
new file mode 100644
index 00000000000..02efdabd70b
--- /dev/null
+++ b/spec/support/helpers/database/duplicate_indexes.yml
@@ -0,0 +1,265 @@
+---
+# It maps table_name to {index1: array_of_duplicate_indexes, index2: array_of_duplicate_indexes, ... }
+abuse_reports:
+ idx_abuse_reports_user_id_status_and_category:
+ - index_abuse_reports_on_user_id
+alert_management_http_integrations:
+ index_http_integrations_on_project_and_endpoint:
+ - index_alert_management_http_integrations_on_project_id
+analytics_cycle_analytics_group_stages:
+ index_group_stages_on_group_id_group_value_stream_id_and_name:
+ - index_analytics_ca_group_stages_on_group_id
+approval_project_rules_users:
+ index_approval_project_rules_users_1:
+ - index_approval_project_rules_users_on_approval_project_rule_id
+approvals:
+ index_approvals_on_merge_request_id_and_created_at:
+ - index_approvals_on_merge_request_id
+board_group_recent_visits:
+ index_board_group_recent_visits_on_user_group_and_board:
+ - index_board_group_recent_visits_on_user_id
+board_project_recent_visits:
+ index_board_project_recent_visits_on_user_project_and_board:
+ - index_board_project_recent_visits_on_user_id
+board_user_preferences:
+ index_board_user_preferences_on_user_id_and_board_id:
+ - index_board_user_preferences_on_user_id
+boards_epic_board_recent_visits:
+ index_epic_board_recent_visits_on_user_group_and_board:
+ - index_boards_epic_board_recent_visits_on_user_id
+boards_epic_user_preferences:
+ index_boards_epic_user_preferences_on_board_user_epic_unique:
+ - index_boards_epic_user_preferences_on_board_id
+bulk_import_batch_trackers:
+ i_bulk_import_trackers_id_batch_number:
+ - index_bulk_import_batch_trackers_on_tracker_id
+bulk_import_export_batches:
+ i_bulk_import_export_batches_id_batch_number:
+ - index_bulk_import_export_batches_on_export_id
+ci_job_artifacts:
+ index_ci_job_artifacts_on_id_project_id_and_created_at:
+ - index_ci_job_artifacts_on_project_id
+ index_ci_job_artifacts_on_id_project_id_and_file_type:
+ - index_ci_job_artifacts_on_project_id
+ index_ci_job_artifacts_on_project_id_and_id:
+ - index_ci_job_artifacts_on_project_id
+ci_pipeline_artifacts:
+ index_ci_pipeline_artifacts_on_pipeline_id_and_file_type:
+ - index_ci_pipeline_artifacts_on_pipeline_id
+ci_stages:
+ index_ci_stages_on_pipeline_id_and_name:
+ - index_ci_stages_on_pipeline_id
+ index_ci_stages_on_pipeline_id_and_position:
+ - index_ci_stages_on_pipeline_id
+ index_ci_stages_on_pipeline_id_convert_to_bigint_and_name:
+ - index_ci_stages_on_pipeline_id_convert_to_bigint
+ index_ci_stages_on_pipeline_id_convert_to_bigint_and_position:
+ - index_ci_stages_on_pipeline_id_convert_to_bigint
+dast_site_tokens:
+ index_dast_site_token_on_project_id_and_url:
+ - index_dast_site_tokens_on_project_id
+design_management_designs:
+ index_design_management_designs_on_iid_and_project_id:
+ - index_design_management_designs_on_project_id
+design_management_designs_versions:
+ design_management_designs_versions_uniqueness:
+ - index_design_management_designs_versions_on_design_id
+error_tracking_errors:
+ index_et_errors_on_project_id_and_status_and_id:
+ - index_error_tracking_errors_on_project_id
+ index_et_errors_on_project_id_and_status_events_count_id_desc:
+ - index_error_tracking_errors_on_project_id
+ index_et_errors_on_project_id_and_status_first_seen_at_id_desc:
+ - index_error_tracking_errors_on_project_id
+ index_et_errors_on_project_id_and_status_last_seen_at_id_desc:
+ - index_error_tracking_errors_on_project_id
+geo_node_namespace_links:
+ index_geo_node_namespace_links_on_geo_node_id_and_namespace_id:
+ - index_geo_node_namespace_links_on_geo_node_id
+in_product_marketing_emails:
+ index_in_product_marketing_emails_on_user_campaign:
+ - index_in_product_marketing_emails_on_user_id
+ index_in_product_marketing_emails_on_user_track_series:
+ - index_in_product_marketing_emails_on_user_id
+incident_management_oncall_participants:
+ index_inc_mgmnt_oncall_participants_on_user_id_and_rotation_id:
+ - index_inc_mgmnt_oncall_participants_on_oncall_user_id
+incident_management_oncall_schedules:
+ index_im_oncall_schedules_on_project_id_and_iid:
+ - index_incident_management_oncall_schedules_on_project_id
+instance_audit_events_streaming_headers:
+ idx_instance_external_audit_event_destination_id_key_uniq:
+ - idx_headers_instance_external_audit_event_destination_id
+issue_links:
+ index_issue_links_on_source_id_and_target_id:
+ - index_issue_links_on_source_id
+issues:
+ index_issues_on_author_id_and_id_and_created_at:
+ - index_issues_on_author_id
+jira_connect_subscriptions:
+ idx_jira_connect_subscriptions_on_installation_id_namespace_id:
+ - idx_jira_connect_subscriptions_on_installation_id
+list_user_preferences:
+ index_list_user_preferences_on_user_id_and_list_id:
+ - index_list_user_preferences_on_user_id
+member_tasks:
+ index_member_tasks_on_member_id_and_project_id:
+ - index_member_tasks_on_member_id
+members:
+ index_members_on_member_namespace_id_compound:
+ - index_members_on_member_namespace_id
+merge_request_assignees:
+ index_merge_request_assignees_on_merge_request_id_and_user_id:
+ - index_merge_request_assignees_on_merge_request_id
+merge_request_metrics:
+ index_mr_metrics_on_target_project_id_merged_at_nulls_last:
+ - index_merge_request_metrics_on_target_project_id
+merge_requests:
+ index_merge_requests_on_author_id_and_created_at:
+ - index_merge_requests_on_author_id
+ index_merge_requests_on_author_id_and_id:
+ - index_merge_requests_on_author_id
+ index_merge_requests_on_author_id_and_target_project_id:
+ - index_merge_requests_on_author_id
+ml_candidate_params:
+ index_ml_candidate_params_on_candidate_id_on_name:
+ - index_ml_candidate_params_on_candidate_id
+ml_candidates:
+ index_ml_candidates_on_project_id_on_internal_id:
+ - index_ml_candidates_on_project_id
+ml_model_versions:
+ index_ml_model_versions_on_project_id_and_model_id_and_version:
+ - index_ml_model_versions_on_project_id
+ml_models:
+ index_ml_models_on_project_id_and_name:
+ - index_ml_models_on_project_id
+p_ci_runner_machine_builds:
+ index_p_ci_runner_machine_builds_on_runner_machine_id:
+ - index_ci_runner_machine_builds_on_runner_machine_id
+packages_debian_group_distributions:
+ uniq_pkgs_debian_group_distributions_group_id_and_codename:
+ - index_packages_debian_group_distributions_on_group_id
+ uniq_pkgs_debian_group_distributions_group_id_and_suite:
+ - index_packages_debian_group_distributions_on_group_id
+packages_debian_project_distributions:
+ uniq_pkgs_debian_project_distributions_project_id_and_codename:
+ - index_packages_debian_project_distributions_on_project_id
+ uniq_pkgs_debian_project_distributions_project_id_and_suite:
+ - index_packages_debian_project_distributions_on_project_id
+packages_tags:
+ index_packages_tags_on_package_id_and_updated_at:
+ - index_packages_tags_on_package_id
+pages_domains:
+ index_pages_domains_on_project_id_and_enabled_until:
+ - index_pages_domains_on_project_id
+ index_pages_domains_on_verified_at_and_enabled_until:
+ - index_pages_domains_on_verified_at
+personal_access_tokens:
+ index_pat_on_user_id_and_expires_at:
+ - index_personal_access_tokens_on_user_id
+pm_affected_packages:
+ i_affected_packages_unique_for_upsert:
+ - index_pm_affected_packages_on_pm_advisory_id
+pm_package_version_licenses:
+ i_pm_package_version_licenses_join_ids:
+ - index_pm_package_version_licenses_on_pm_package_version_id
+pm_package_versions:
+ i_pm_package_versions_on_package_id_and_version:
+ - index_pm_package_versions_on_pm_package_id
+project_compliance_standards_adherence:
+ u_project_compliance_standards_adherence_for_reporting:
+ - index_project_compliance_standards_adherence_on_project_id
+project_relation_exports:
+ index_project_export_job_relation:
+ - index_project_relation_exports_on_project_export_job_id
+project_repositories:
+ index_project_repositories_on_shard_id_and_project_id:
+ - index_project_repositories_on_shard_id
+project_topics:
+ index_project_topics_on_project_id_and_topic_id:
+ - index_project_topics_on_project_id
+projects:
+ index_projects_api_path_id_desc:
+ - index_on_projects_path
+ index_projects_on_path_and_id:
+ - index_on_projects_path
+protected_environments:
+ index_protected_environments_on_project_id_and_name:
+ - index_protected_environments_on_project_id
+protected_tags:
+ index_protected_tags_on_project_id_and_name:
+ - index_protected_tags_on_project_id
+related_epic_links:
+ index_related_epic_links_on_source_id_and_target_id:
+ - index_related_epic_links_on_source_id
+requirements_management_test_reports:
+ idx_test_reports_on_issue_id_created_at_and_id:
+ - index_requirements_management_test_reports_on_issue_id
+sbom_component_versions:
+ index_sbom_component_versions_on_component_id_and_version:
+ - index_sbom_component_versions_on_component_id
+sbom_occurrences:
+ index_sbom_occurrences_for_input_file_path_search:
+ - index_sbom_occurrences_on_project_id_component_id
+ - index_sbom_occurrences_on_project_id
+ idx_sbom_occurrences_on_project_id_and_source_id:
+ - index_sbom_occurrences_on_project_id
+ index_sbom_occurrences_on_project_id_and_id:
+ - index_sbom_occurrences_on_project_id
+ index_sbom_occurrences_on_project_id_component_id:
+ - index_sbom_occurrences_on_project_id
+ index_sbom_occurrences_on_project_id_and_component_id_and_id:
+ - index_sbom_occurrences_on_project_id_component_id
+ - index_sbom_occurrences_on_project_id
+ index_sbom_occurrences_on_project_id_and_package_manager:
+ - index_sbom_occurrences_on_project_id
+scan_result_policies:
+ index_scan_result_policies_on_position_in_configuration:
+ - index_scan_result_policies_on_policy_configuration_id
+search_namespace_index_assignments:
+ index_search_namespace_index_assignments_uniqueness_index_type:
+ - index_search_namespace_index_assignments_on_namespace_id
+ index_search_namespace_index_assignments_uniqueness_on_index_id:
+ - index_search_namespace_index_assignments_on_namespace_id
+sprints:
+ sequence_is_unique_per_iterations_cadence_id:
+ - index_sprints_iterations_cadence_id
+taggings:
+ taggings_idx:
+ - index_taggings_on_tag_id
+term_agreements:
+ term_agreements_unique_index:
+ - index_term_agreements_on_user_id
+todos:
+ index_todos_on_author_id_and_created_at:
+ - index_todos_on_author_id
+user_callouts:
+ index_user_callouts_on_user_id_and_feature_name:
+ - index_user_callouts_on_user_id
+users:
+ index_users_on_state_and_user_type:
+ - index_users_on_state
+vulnerabilities:
+ index_vulnerabilities_project_id_state_severity_default_branch:
+ - index_vulnerabilities_on_project_id_and_state_and_severity
+vulnerability_external_issue_links:
+ idx_vulnerability_ext_issue_links_on_vulne_id_and_ext_issue:
+ - index_vulnerability_external_issue_links_on_vulnerability_id
+vulnerability_finding_links:
+ finding_link_name_url_idx:
+ - finding_links_on_vulnerability_occurrence_id
+vulnerability_finding_signatures:
+ idx_vuln_signatures_uniqueness_signature_sha:
+ - index_vulnerability_finding_signatures_on_finding_id
+vulnerability_flags:
+ index_vulnerability_flags_on_unique_columns:
+ - index_vulnerability_flags_on_vulnerability_occurrence_id
+web_hook_logs:
+ index_web_hook_logs_on_web_hook_id_and_created_at:
+ - index_web_hook_logs_part_on_web_hook_id
+web_hooks:
+ index_web_hooks_on_project_id_recent_failures:
+ - index_web_hooks_on_project_id
+work_item_hierarchy_restrictions:
+ index_work_item_hierarchy_restrictions_on_parent_and_child:
+ - index_work_item_hierarchy_restrictions_on_parent_type_id
diff --git a/spec/support/helpers/features/admin_users_helpers.rb b/spec/support/helpers/features/admin_users_helpers.rb
index 9a87ccf113a..b4477537a40 100644
--- a/spec/support/helpers/features/admin_users_helpers.rb
+++ b/spec/support/helpers/features/admin_users_helpers.rb
@@ -4,7 +4,7 @@ module Features
module AdminUsersHelpers
def click_user_dropdown_toggle(user_id)
page.within("[data-testid='user-actions-#{user_id}']") do
- find("[data-testid='dropdown-toggle']").click
+ find("[data-testid='user-actions-dropdown-toggle']").click
end
end
diff --git a/spec/support/helpers/features/highlight_content_helper.rb b/spec/support/helpers/features/highlight_content_helper.rb
new file mode 100644
index 00000000000..f55dd213061
--- /dev/null
+++ b/spec/support/helpers/features/highlight_content_helper.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+# This helper allows you to reliably highlight text within a given Element by
+# simulating mouse actions.
+#
+module Features
+ module HighlightContentHelper
+ def highlight_content(node)
+ height = node.native.rect.height
+ width = node.native.rect.width
+ page.driver.browser.action
+ .move_to(node.native, -(width / 2), -(height / 2))
+ .click_and_hold
+ .move_by(width, height)
+ .release
+ .perform
+ end
+ end
+end
diff --git a/spec/support/helpers/features/runners_helpers.rb b/spec/support/helpers/features/runners_helpers.rb
index dbd1edade8c..7c3618ee799 100644
--- a/spec/support/helpers/features/runners_helpers.rb
+++ b/spec/support/helpers/features/runners_helpers.rb
@@ -23,11 +23,13 @@ module Features
def input_filtered_search_keys(search_term)
focus_filtered_search
- page.find(search_bar_selector).find('input').send_keys(search_term)
- # blur input
- find('body').click
+ page.within(search_bar_selector) do
+ send_keys(search_term)
+ send_keys(:enter)
+
+ click_on 'Search'
+ end
- page.click_on 'Search'
wait_for_requests
end
diff --git a/spec/support/helpers/filtered_search_helpers.rb b/spec/support/helpers/filtered_search_helpers.rb
index 60638eb06cd..abd5d78e836 100644
--- a/spec/support/helpers/filtered_search_helpers.rb
+++ b/spec/support/helpers/filtered_search_helpers.rb
@@ -155,7 +155,7 @@ module FilteredSearchHelpers
end
def default_placeholder
- 'Search or filter results...'
+ 'Search or filter results…'
end
def get_filtered_search_placeholder
diff --git a/spec/support/helpers/loose_foreign_keys_helper.rb b/spec/support/helpers/loose_foreign_keys_helper.rb
new file mode 100644
index 00000000000..c83c60d72ed
--- /dev/null
+++ b/spec/support/helpers/loose_foreign_keys_helper.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+# Helper to process deletions of associated records created via loose foreign keys
+
+module LooseForeignKeysHelper
+ def process_loose_foreign_key_deletions(record:)
+ LooseForeignKeys::DeletedRecord.using_connection(record.connection) do
+ LooseForeignKeys::ProcessDeletedRecordsService.new(connection: record.connection).execute
+ end
+ end
+end
diff --git a/spec/support/helpers/sign_up_helpers.rb b/spec/support/helpers/sign_up_helpers.rb
new file mode 100644
index 00000000000..6259467232c
--- /dev/null
+++ b/spec/support/helpers/sign_up_helpers.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+module SignUpHelpers
+ def fill_in_sign_up_form(new_user, submit_button_text = 'Register')
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ fill_in 'new_user_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
+ fill_in 'new_user_password', with: new_user.password
+
+ wait_for_all_requests
+
+ expect_username_to_be_validated
+
+ yield if block_given?
+
+ click_button submit_button_text
+ end
+
+ private
+
+ def expect_username_to_be_validated
+ expect(page).to have_selector('[data-testid="new-user-username-field"].gl-field-success-outline')
+ end
+end
diff --git a/spec/support/helpers/stub_gitlab_calls.rb b/spec/support/helpers/stub_gitlab_calls.rb
index 6d0e97b0a75..c02ffe07159 100644
--- a/spec/support/helpers/stub_gitlab_calls.rb
+++ b/spec/support/helpers/stub_gitlab_calls.rb
@@ -23,13 +23,17 @@ module StubGitlabCalls
end
def stub_ci_pipeline_yaml_file(ci_yaml_content)
- allow_any_instance_of(Gitlab::Ci::ProjectConfig::Repository)
- .to receive(:file_in_repository?)
- .and_return(ci_yaml_content.present?)
+ blob = instance_double(Blob, empty?: ci_yaml_content.blank?, data: ci_yaml_content)
+ allow(blob).to receive(:load_all_data!)
allow_any_instance_of(Repository)
- .to receive(:gitlab_ci_yml_for)
- .and_return(ci_yaml_content)
+ .to receive(:blob_at)
+ .and_call_original
+
+ allow_any_instance_of(Repository)
+ .to receive(:blob_at)
+ .with(String, '.gitlab-ci.yml')
+ .and_return(blob)
# Ensure we don't hit auto-devops when config not found in repository
unless ci_yaml_content
diff --git a/spec/support/helpers/x509_helpers.rb b/spec/support/helpers/x509_helpers.rb
index 1dc8b1d4845..aa5c360d953 100644
--- a/spec/support/helpers/x509_helpers.rb
+++ b/spec/support/helpers/x509_helpers.rb
@@ -173,6 +173,10 @@ module X509Helpers
Time.at(1561027326)
end
+ def signed_tag_time
+ Time.at(1574261780)
+ end
+
def signed_tag_signature
<<~SIGNATURE
-----BEGIN SIGNED MESSAGE-----
@@ -337,6 +341,10 @@ module X509Helpers
'r.meier@siemens.com'
end
+ def tag_email
+ 'dmitriy.zaporozhets@gmail.com'
+ end
+
def certificate_issuer
'CN=Siemens Issuing CA EE Auth 2016,OU=Siemens Trust Center,serialNumber=ZZZZZZA2,O=Siemens,L=Muenchen,ST=Bayern,C=DE'
end
@@ -357,4 +365,177 @@ module X509Helpers
['r.meier@siemens.com']
end
end
+
+ module User2
+ extend self
+
+ def commit
+ '440bf5b2b499a90d9adcbebe3752f8c6f245a1aa'
+ end
+
+ def path
+ 'gitlab-test'
+ end
+
+ def trust_cert
+ <<~TRUSTCERTIFICATE
+ -----BEGIN CERTIFICATE-----
+ MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw
+ KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y
+ MjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl
+ LmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C
+ AQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7
+ 7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS
+ 0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB
+ BQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp
+ KFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI
+ zj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR
+ nZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP
+ mygUY7Ii2zbdCdliiow=
+ -----END CERTIFICATE-----
+ TRUSTCERTIFICATE
+ end
+
+ def signed_commit_signature
+ <<~SIGNATURE
+ -----BEGIN SIGNED MESSAGE-----
+ MIIEOQYJKoZIhvcNAQcCoIIEKjCCBCYCAQExDTALBglghkgBZQMEAgEwCwYJKoZI
+ hvcNAQcBoIIC2jCCAtYwggJdoAMCAQICFC5R9EXk+ljFhyCs4urRxmCuvQNAMAoG
+ CCqGSM49BAMDMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2ln
+ c3RvcmUtaW50ZXJtZWRpYXRlMB4XDTIzMDgxOTE3NTgwNVoXDTIzMDgxOTE4MDgw
+ NVowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBGajWb10Rt36IMxtJmjRDa7
+ 5O6YCLhVq9+LNJSAx2M7p6netqW7W+lwym4z1Y1gXLdGHBshrbx/yr6Trhh2TCej
+ ggF8MIIBeDAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYD
+ VR0OBBYEFBttEjGzNppCqA4tlZY4oaxkdmQbMB8GA1UdIwQYMBaAFN/T6c9WJBGW
+ +ajY6ShVosYuGGQ/MCUGA1UdEQEB/wQbMBmBF2dpdGxhYmdwZ3Rlc3RAZ21haWwu
+ Y29tMCwGCisGAQQBg78wAQEEHmh0dHBzOi8vZ2l0aHViLmNvbS9sb2dpbi9vYXV0
+ aDAuBgorBgEEAYO/MAEIBCAMHmh0dHBzOi8vZ2l0aHViLmNvbS9sb2dpbi9vYXV0
+ aDCBiwYKKwYBBAHWeQIEAgR9BHsAeQB3AN09MGrGxxEyYxkeHJlnNwKiSl643jyt
+ /4eKcoAvKe6OAAABig7ydOsAAAQDAEgwRgIhAMqJnFLAspeqfbK/gA/7zjceyExq
+ QN7qDXWKRLS01rTvAiEAp/uBShQb9tVa3P3fYVAMiXydvr5dqCpNiuudZiuYq0Yw
+ CgYIKoZIzj0EAwMDZwAwZAIwWKXYyP5FvbfhvfLkV0tN887ax1eg7TmF1Tzkugag
+ cLJ5MzK3xYNcUO/3AxO3H/b8AjBD9DF6R4kFO4cXoqnpsk2FTUeSPiUJ+0x2PDFG
+ gQZvoMWz7CnwjXml8XDEKNpYoPkxggElMIIBIQIBATBPMDcxFTATBgNVBAoTDHNp
+ Z3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlAhQuUfRF
+ 5PpYxYcgrOLq0cZgrr0DQDALBglghkgBZQMEAgGgaTAYBgkqhkiG9w0BCQMxCwYJ
+ KoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMzA4MTkxNzU4MDVaMC8GCSqGSIb3
+ DQEJBDEiBCB4B7DeGk22WmBseJzjjRJcQsyYxu0PNDAFXq55uJ7MSzAKBggqhkjO
+ PQQDAgRHMEUCIQCNegIrK6m1xyGuu4lw06l22VQsmO74/k3H236jCFF+bAIgAX1N
+ rxBFWnjWboZmAV1NuduTD/YToShK6iRmJ/NpILA=
+ -----END SIGNED MESSAGE-----
+ SIGNATURE
+ end
+
+ def signed_commit_base_data
+ <<~SIGNEDDATA
+ tree 7d5ee08cadaa161d731c56a9265feef130143b07
+ parent 4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6
+ author Mona Lisa <gitlabgpgtest@gmail.com> 1692467872 +0000
+ committer Mona Lisa <gitlabgpgtest@gmail.com> 1692467872 +0000
+
+ Sigstore Signed Commit
+ SIGNEDDATA
+ end
+
+ def signed_commit_time
+ Time.at(1692467872)
+ end
+
+ def signed_tag_time
+ Time.at(1692467872)
+ end
+
+ def signed_tag_signature
+ <<~SIGNATURE
+ -----BEGIN SIGNED MESSAGE-----
+ MIIEOgYJKoZIhvcNAQcCoIIEKzCCBCcCAQExDTALBglghkgBZQMEAgEwCwYJKoZI
+ hvcNAQcBoIIC2zCCAtcwggJdoAMCAQICFB5qFHBSNfcJDZecnHK5/tleuX3yMAoG
+ CCqGSM49BAMDMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2ln
+ c3RvcmUtaW50ZXJtZWRpYXRlMB4XDTIzMDgxOTE3NTgzM1oXDTIzMDgxOTE4MDgz
+ M1owADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKJtbdL88PM8lE21CuyDYlZm
+ 0xZYCThoXZSGmULrgE5+hfroCIbLswOi5i6TyB8j4CCe0Jxeu94Jn+76SXF+lbej
+ ggF8MIIBeDAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYD
+ VR0OBBYEFBkU3IBENVJYeyK9b56vbGGrjPwYMB8GA1UdIwQYMBaAFN/T6c9WJBGW
+ +ajY6ShVosYuGGQ/MCUGA1UdEQEB/wQbMBmBF2dpdGxhYmdwZ3Rlc3RAZ21haWwu
+ Y29tMCwGCisGAQQBg78wAQEEHmh0dHBzOi8vZ2l0aHViLmNvbS9sb2dpbi9vYXV0
+ aDAuBgorBgEEAYO/MAEIBCAMHmh0dHBzOi8vZ2l0aHViLmNvbS9sb2dpbi9vYXV0
+ aDCBiwYKKwYBBAHWeQIEAgR9BHsAeQB3AN09MGrGxxEyYxkeHJlnNwKiSl643jyt
+ /4eKcoAvKe6OAAABig7y4tYAAAQDAEgwRgIhAMUjWh8ayhjWDI3faFah3Du/7IuY
+ xzbUXaPQnCyUbvwwAiEAwHgWv8fmKMudbVu37Nbq/c1cdnQqDK9Y2UGtlmzaLrYw
+ CgYIKoZIzj0EAwMDaAAwZQIwZTKZlS4HNJH48km3pxG95JTbldSBhvFlrpIEVRUd
+ TEK6uGQJmpIm1WYQjbJbiVS8AjEA+2NoAdMuRpa2k13HUfWQEMtzQcxZMMNB7Yux
+ 9ZIADOlFp701ujtFSZAXgqGL3FYKMYIBJTCCASECAQEwTzA3MRUwEwYDVQQKEwxz
+ aWdzdG9yZS5kZXYxHjAcBgNVBAMTFXNpZ3N0b3JlLWludGVybWVkaWF0ZQIUHmoU
+ cFI19wkNl5yccrn+2V65ffIwCwYJYIZIAWUDBAIBoGkwGAYJKoZIhvcNAQkDMQsG
+ CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjMwODE5MTc1ODMzWjAvBgkqhkiG
+ 9w0BCQQxIgQgwpYCAlbS6KnfgxQD3SATWUbdUssLaBWkHwTkmtCye4wwCgYIKoZI
+ zj0EAwIERzBFAiB8y5bGhWJvWCHQyma7oF038ZPLzXmsDJyJffJHoAb6XAIhAOW3
+ gxuYuJAKP86B1fY0vYCZHF8vU6SZAcE6teSDowwq
+ -----END SIGNED MESSAGE-----
+ SIGNATURE
+ end
+
+ def signed_tag_base_data
+ <<~SIGNEDDATA
+ object 440bf5b2b499a90d9adcbebe3752f8c6f245a1aa
+ type commit
+ tag v1.1.2
+ tagger Mona Lisa <gitlabgpgtest@gmail.com> 1692467901 +0000
+
+ Sigstore Signed Tag
+ SIGNEDDATA
+ end
+
+ def certificate_serial
+ 264441215000592123389532407734419590292801651520
+ end
+
+ def tag_certificate_serial
+ 173635382582380059990335547381753891120957980146
+ end
+
+ def certificate_subject_key_identifier
+ '1B:6D:12:31:B3:36:9A:42:A8:0E:2D:95:96:38:A1:AC:64:76:64:1B'
+ end
+
+ def tag_certificate_subject_key_identifier
+ '19:14:DC:80:44:35:52:58:7B:22:BD:6F:9E:AF:6C:61:AB:8C:FC:18'
+ end
+
+ def issuer_subject_key_identifier
+ 'DF:D3:E9:CF:56:24:11:96:F9:A8:D8:E9:28:55:A2:C6:2E:18:64:3F'
+ end
+
+ def tag_issuer_subject_key_identifier
+ 'DF:D3:E9:CF:56:24:11:96:F9:A8:D8:E9:28:55:A2:C6:2E:18:64:3F'
+ end
+
+ def certificate_email
+ 'gitlabgpgtest@gmail.com'
+ end
+
+ def tag_email
+ 'gitlabgpgtest@gmail.com'
+ end
+
+ def certificate_issuer
+ 'CN=sigstore-intermediate,O=sigstore.dev'
+ end
+
+ def tag_certificate_issuer
+ 'CN=sigstore-intermediate,O=sigstore.dev'
+ end
+
+ def certificate_subject
+ ''
+ end
+
+ def names
+ ['Mona Lisa']
+ end
+
+ def emails
+ ['gitlabgpgtest@gmail.com']
+ end
+ end
end
diff --git a/spec/support/matchers/pagination_matcher.rb b/spec/support/matchers/pagination_matcher.rb
index a3e9c3b8474..beaba84d78c 100644
--- a/spec/support/matchers/pagination_matcher.rb
+++ b/spec/support/matchers/pagination_matcher.rb
@@ -11,3 +11,13 @@ RSpec::Matchers.define :include_limited_pagination_headers do |expected|
expect(actual.headers).to include('X-Per-Page', 'X-Page', 'X-Next-Page', 'X-Prev-Page', 'Link')
end
end
+
+RSpec::Matchers.define :include_keyset_url_params do |expected|
+ include KeysetPaginationHelpers
+
+ match do |actual|
+ params_for_next_page = pagination_params_from_next_url(actual)
+
+ expect(params_for_next_page).to include('cursor')
+ end
+end
diff --git a/spec/support/migration.rb b/spec/support/migration.rb
index b1e75d9c9e2..fc8a4bb12fb 100644
--- a/spec/support/migration.rb
+++ b/spec/support/migration.rb
@@ -20,21 +20,11 @@ RSpec.configure do |config|
Gitlab::CurrentSettings.clear_in_memory_application_settings!
end
- config.prepend_before(:all, :migration) do
- TestProf::BeforeAll.adapter = ::TestProfBeforeAllAdapter.no_transaction_adapter
- end
-
- config.append_after(:all, :migration) do
- TestProf::BeforeAll.adapter = ::TestProfBeforeAllAdapter.default_adapter
- end
-
config.append_after(:context, :migration) do
recreate_databases_and_seed_if_needed || ensure_schema_and_empty_tables
end
config.around(:each, :migration) do |example|
- self.class.use_transactional_tests = false
-
migration_schema = example.metadata[:migration]
migration_schema = :gitlab_main if migration_schema == true
base_model = Gitlab::Database.schemas_to_base_models.fetch(migration_schema).first
@@ -52,10 +42,6 @@ RSpec.configure do |config|
else
example.run
end
-
- delete_from_all_tables!(except: deletion_except_tables)
-
- self.class.use_transactional_tests = true
end
# Each example may call `migrate!`, so we must ensure we are migrated down every time
diff --git a/spec/support/multiple_databases.rb b/spec/support/multiple_databases.rb
index 616cf00269c..1c556858018 100644
--- a/spec/support/multiple_databases.rb
+++ b/spec/support/multiple_databases.rb
@@ -7,8 +7,6 @@ RSpec.configure do |config|
# at startup, but that generates its own
# `Gitlab::Database::Reflection` so the result is not memoized by
# callers of `ApplicationRecord.database.version`, such as
- # `Gitlab::Database::AsWithMaterialized.materialized_supported?`.
- # TODO This can be removed once https://gitlab.com/gitlab-org/gitlab/-/issues/325639 is completed.
[ApplicationRecord, ::Ci::ApplicationRecord].each { |record| record.database.version }
config.around(:each, :reestablished_active_record_base) do |example|
diff --git a/spec/support/protected_branch_helpers.rb b/spec/support/protected_branch_helpers.rb
index 576275e9d1d..db5118d6f88 100644
--- a/spec/support/protected_branch_helpers.rb
+++ b/spec/support/protected_branch_helpers.rb
@@ -34,7 +34,7 @@ module ProtectedBranchHelpers
select_input.click
wait_for_requests
- within('.dropdown.show .dropdown-menu', &block)
+ within('.dropdown .dropdown-menu.show', &block)
# Enhanced select is used in EE, therefore an extra click is needed.
select_input.click if select_input['aria-expanded'] == 'true'
diff --git a/spec/support/rspec.rb b/spec/support/rspec.rb
index 4479e679d67..7f3aa55fb1d 100644
--- a/spec/support/rspec.rb
+++ b/spec/support/rspec.rb
@@ -20,10 +20,18 @@ RSpec.configure do |config|
config.example_status_persistence_file_path = ENV.fetch('RSPEC_LAST_RUN_RESULTS_FILE', './spec/examples.txt')
# Makes diffs show entire non-truncated values.
- config.before(:each, :unlimited_max_formatted_output_length) do
+ config.around(:each, :unlimited_max_formatted_output_length) do |example|
+ old_max_formatted_output_length = RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length
+
config.expect_with :rspec do |c|
c.max_formatted_output_length = nil
end
+
+ example.run
+
+ config.expect_with :rspec do |c|
+ c.max_formatted_output_length = old_max_formatted_output_length
+ end
end
unless ENV['CI']
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index f52f843e56a..298f4006c3b 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -19,7 +19,6 @@
- './ee/spec/controllers/admin/elasticsearch_controller_spec.rb'
- './ee/spec/controllers/admin/emails_controller_spec.rb'
- './ee/spec/controllers/admin/geo/nodes_controller_spec.rb'
-- './ee/spec/controllers/admin/geo/projects_controller_spec.rb'
- './ee/spec/controllers/admin/geo/settings_controller_spec.rb'
- './ee/spec/controllers/admin/groups_controller_spec.rb'
- './ee/spec/controllers/admin/impersonations_controller_spec.rb'
@@ -166,7 +165,6 @@
- './ee/spec/controllers/security/vulnerabilities_controller_spec.rb'
- './ee/spec/controllers/sitemap_controller_spec.rb'
- './ee/spec/controllers/subscriptions_controller_spec.rb'
-- './ee/spec/controllers/trial_registrations_controller_spec.rb'
- './ee/spec/controllers/users_controller_spec.rb'
- './ee/spec/db/production/license_spec.rb'
- './ee/spec/elastic_integration/global_search_spec.rb'
@@ -461,7 +459,6 @@
- './ee/spec/features/read_only_spec.rb'
- './ee/spec/features/registrations/combined_registration_spec.rb'
- './ee/spec/features/registrations/one_trust_spec.rb'
-- './ee/spec/features/registrations/welcome_spec.rb'
- './ee/spec/features/search/elastic/global_search_spec.rb'
- './ee/spec/features/search/elastic/group_search_spec.rb'
- './ee/spec/features/search/elastic/project_search_spec.rb'
@@ -526,7 +523,6 @@
- './ee/spec/finders/epics_finder_spec.rb'
- './ee/spec/finders/geo/ci_secure_file_registry_finder_spec.rb'
- './ee/spec/finders/geo/container_repository_registry_finder_spec.rb'
-- './ee/spec/finders/geo/design_registry_finder_spec.rb'
- './ee/spec/finders/geo/group_wiki_repository_registry_finder_spec.rb'
- './ee/spec/finders/geo/lfs_object_registry_finder_spec.rb'
- './ee/spec/finders/geo/merge_request_diff_registry_finder_spec.rb'
@@ -594,7 +590,6 @@
- './ee/spec/graphql/api/vulnerabilities_spec.rb'
- './ee/spec/graphql/ee/mutations/boards/issues/issue_move_list_spec.rb'
- './ee/spec/graphql/ee/mutations/boards/lists/create_spec.rb'
-- './ee/spec/graphql/ee/mutations/ci/project_ci_cd_settings_update_spec.rb'
- './ee/spec/graphql/ee/mutations/ci/runner/update_spec.rb'
- './ee/spec/graphql/ee/mutations/concerns/mutations/resolves_issuable_spec.rb'
- './ee/spec/graphql/ee/resolvers/board_list_issues_resolver_spec.rb'
@@ -999,7 +994,6 @@
- './ee/spec/helpers/security_helper_spec.rb'
- './ee/spec/helpers/subscriptions_helper_spec.rb'
- './ee/spec/helpers/timeboxes_helper_spec.rb'
-- './ee/spec/helpers/trial_registrations/reassurances_helper_spec.rb'
- './ee/spec/helpers/trial_status_widget_helper_spec.rb'
- './ee/spec/helpers/users_helper_spec.rb'
- './ee/spec/helpers/vulnerabilities_helper_spec.rb'
@@ -1147,7 +1141,6 @@
- './ee/spec/lib/ee/gitlab/group_search_results_spec.rb'
- './ee/spec/lib/ee/gitlab/hook_data/group_member_builder_spec.rb'
- './ee/spec/lib/ee/gitlab/hook_data/issue_builder_spec.rb'
-- './ee/spec/lib/ee/gitlab/hook_data/user_builder_spec.rb'
- './ee/spec/lib/ee/gitlab/import_export/after_export_strategies/custom_template_export_import_strategy_spec.rb'
- './ee/spec/lib/ee/gitlab/import_export/group/tree_restorer_spec.rb'
- './ee/spec/lib/ee/gitlab/import_export/group/tree_saver_spec.rb'
@@ -1395,7 +1388,6 @@
- './ee/spec/lib/gitlab/geo/log_cursor/daemon_spec.rb'
- './ee/spec/lib/gitlab/geo/log_cursor/event_logs_spec.rb'
- './ee/spec/lib/gitlab/geo/log_cursor/events/cache_invalidation_event_spec.rb'
-- './ee/spec/lib/gitlab/geo/log_cursor/events/design_repository_updated_event_spec.rb'
- './ee/spec/lib/gitlab/geo/log_cursor/events/event_spec.rb'
- './ee/spec/lib/gitlab/geo/log_cursor/events/hashed_storage_attachments_event_spec.rb'
- './ee/spec/lib/gitlab/geo/log_cursor/events/hashed_storage_migrated_event_spec.rb'
@@ -1758,7 +1750,6 @@
- './ee/spec/models/geo/ci_secure_file_registry_spec.rb'
- './ee/spec/models/geo/container_repository_registry_spec.rb'
- './ee/spec/models/geo/deleted_project_spec.rb'
-- './ee/spec/models/geo/design_registry_spec.rb'
- './ee/spec/models/geo/event_log_spec.rb'
- './ee/spec/models/geo/event_log_state_spec.rb'
- './ee/spec/models/geo/every_geo_event_spec.rb'
@@ -2750,7 +2741,6 @@
- './ee/spec/services/geo/wiki_sync_service_spec.rb'
- './ee/spec/services/gitlab_subscriptions/activate_service_spec.rb'
- './ee/spec/services/gitlab_subscriptions/check_future_renewal_service_spec.rb'
-- './ee/spec/services/gitlab_subscriptions/create_hand_raise_lead_service_spec.rb'
- './ee/spec/services/gitlab_subscriptions/create_service_spec.rb'
- './ee/spec/services/gitlab_subscriptions/create_trial_or_lead_service_spec.rb'
- './ee/spec/services/gitlab_subscriptions/fetch_purchase_eligible_namespaces_service_spec.rb'
@@ -2828,7 +2818,6 @@
- './ee/spec/services/milestones/destroy_service_spec.rb'
- './ee/spec/services/milestones/promote_service_spec.rb'
- './ee/spec/services/milestones/update_service_spec.rb'
-- './ee/spec/services/namespaces/in_product_marketing_emails_service_spec.rb'
- './ee/spec/services/namespaces/storage/email_notification_service_spec.rb'
- './ee/spec/services/path_locks/lock_service_spec.rb'
- './ee/spec/services/path_locks/unlock_service_spec.rb'
@@ -3057,7 +3046,6 @@
- './ee/spec/views/profiles/preferences/show.html.haml_spec.rb'
- './ee/spec/views/projects/edit.html.haml_spec.rb'
- './ee/spec/views/projects/issues/show.html.haml_spec.rb'
-- './ee/spec/views/projects/_merge_request_status_checks_settings.html.haml_spec.rb'
- './ee/spec/views/projects/on_demand_scans/index.html.haml_spec.rb'
- './ee/spec/views/projects/security/corpus_management/show.html.haml_spec.rb'
- './ee/spec/views/projects/security/dast_profiles/show.html.haml_spec.rb'
@@ -3068,6 +3056,7 @@
- './ee/spec/views/projects/security/discover/show.html.haml_spec.rb'
- './ee/spec/views/projects/security/policies/index.html.haml_spec.rb'
- './ee/spec/views/projects/security/sast_configuration/show.html.haml_spec.rb'
+- './ee/spec/views/projects/settings/merge_requests/_merge_request_status_checks_settings.html.haml_spec.rb'
- './ee/spec/views/projects/settings/subscriptions/_index.html.haml_spec.rb'
- './ee/spec/views/registrations/groups/new.html.haml_spec.rb'
- './ee/spec/views/shared/billings/_billing_plan_actions.html.haml_spec.rb'
@@ -3133,7 +3122,6 @@
- './ee/spec/workers/ee/arkose/blocked_users_report_worker_spec.rb'
- './ee/spec/workers/ee/ci/build_finished_worker_spec.rb'
- './ee/spec/workers/ee/issuable_export_csv_worker_spec.rb'
-- './ee/spec/workers/ee/namespaces/in_product_marketing_emails_worker_spec.rb'
- './ee/spec/workers/ee/namespaces/root_statistics_worker_spec.rb'
- './ee/spec/workers/ee/projects/inactive_projects_deletion_cron_worker_spec.rb'
- './ee/spec/workers/ee/repository_check/batch_worker_spec.rb'
@@ -8579,7 +8567,6 @@
- './spec/requests/groups/crm/contacts_controller_spec.rb'
- './spec/requests/groups/crm/organizations_controller_spec.rb'
- './spec/requests/groups/deploy_tokens_controller_spec.rb'
-- './spec/requests/groups/email_campaigns_controller_spec.rb'
- './spec/requests/groups/harbor/artifacts_controller_spec.rb'
- './spec/requests/groups/harbor/repositories_controller_spec.rb'
- './spec/requests/groups/harbor/tags_controller_spec.rb'
@@ -9323,7 +9310,6 @@
- './spec/services/milestones/transfer_service_spec.rb'
- './spec/services/milestones/update_service_spec.rb'
- './spec/services/namespace_settings/update_service_spec.rb'
-- './spec/services/namespaces/in_product_marketing_emails_service_spec.rb'
- './spec/services/namespaces/package_settings/update_service_spec.rb'
- './spec/services/namespaces/statistics_refresher_service_spec.rb'
- './spec/services/notes/build_service_spec.rb'
@@ -10126,7 +10112,6 @@
- './spec/workers/metrics/dashboard/schedule_annotations_prune_worker_spec.rb'
- './spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb'
- './spec/workers/migrate_external_diffs_worker_spec.rb'
-- './spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb'
- './spec/workers/namespaces/process_sync_events_worker_spec.rb'
- './spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb'
- './spec/workers/namespaces/root_statistics_worker_spec.rb'
diff --git a/spec/support/shared_contexts/dependency_proxy_shared_context.rb b/spec/support/shared_contexts/dependency_proxy_shared_context.rb
new file mode 100644
index 00000000000..02625722a8c
--- /dev/null
+++ b/spec/support/shared_contexts/dependency_proxy_shared_context.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'with a server running the dependency proxy' do
+ def run_server(handler)
+ default_server = Capybara.server
+
+ Capybara.server = Capybara.servers[:puma]
+ server = Capybara::Server.new(handler)
+ server.boot
+ server
+ ensure
+ Capybara.server = default_server
+ end
+end
diff --git a/spec/support/shared_contexts/email_shared_context.rb b/spec/support/shared_contexts/email_shared_context.rb
index 8b4c1c1e243..3098fc3dc5e 100644
--- a/spec/support/shared_contexts/email_shared_context.rb
+++ b/spec/support/shared_contexts/email_shared_context.rb
@@ -191,7 +191,7 @@ RSpec.shared_examples 'note handler shared examples' do |forwardable|
context 'when the service desk' do
let(:project) { create(:project, :public, service_desk_enabled: true) }
- let(:support_bot) { User.support_bot }
+ let(:support_bot) { Users::Internal.support_bot }
let(:noteable) { create(:issue, project: project, author: support_bot, title: 'service desk issue') }
let!(:note) { create(:note, project: project, noteable: noteable) }
let(:email_raw) { with_quick_actions }
diff --git a/spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb
index 5996fcc6593..befc231f04f 100644
--- a/spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb
+++ b/spec/support/shared_contexts/features/integrations/group_integrations_shared_context.rb
@@ -22,7 +22,7 @@ RSpec.shared_context 'group integration activation' do
visit_group_integrations
within('#content-body') do
- click_link(name)
+ click_link(name, match: :first)
end
end
end
diff --git a/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb
index 3b02db994a3..c740917cec4 100644
--- a/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb
+++ b/spec/support/shared_contexts/features/integrations/instance_integrations_shared_context.rb
@@ -18,7 +18,7 @@ RSpec.shared_context 'instance integration activation' do
visit_instance_integrations
within('#content-body') do
- click_link(name)
+ click_link(name, match: :first)
end
end
end
diff --git a/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb b/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb
index a9b9a5246e6..c3da9435e05 100644
--- a/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb
+++ b/spec/support/shared_contexts/features/integrations/project_integrations_shared_context.rb
@@ -4,7 +4,7 @@ RSpec.shared_context 'project integration activation' do
include_context 'with integration activation'
let_it_be(:project) { create(:project) }
- let_it_be(:user) { create(:user) }
+ let_it_be(:user) { create(:user, :no_super_sidebar) }
before do
project.add_maintainer(user)
@@ -19,7 +19,7 @@ RSpec.shared_context 'project integration activation' do
visit_project_integrations
within('#content-body') do
- click_link(name)
+ click_link(name, match: :first)
end
end
diff --git a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb
index ef1c01f72f9..b89b1aabd87 100644
--- a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb
+++ b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb
@@ -8,5 +8,5 @@ RSpec.shared_context 'UsersFinder#execute filter by project context' do
let_it_be(:external_user) { create(:user, :external) }
let_it_be(:unconfirmed_user) { create(:user, confirmed_at: nil) }
let_it_be(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
- let_it_be(:internal_user) { User.alert_bot.tap { |u| u.confirm } }
+ let_it_be(:internal_user) { Users::Internal.alert_bot.tap { |u| u.confirm } }
end
diff --git a/spec/support/shared_contexts/lib/gitlab/database/load_balancing/wal_tracking_shared_context.rb b/spec/support/shared_contexts/lib/gitlab/database/load_balancing/wal_tracking_shared_context.rb
index cbbd3754108..46d6a1fbac0 100644
--- a/spec/support/shared_contexts/lib/gitlab/database/load_balancing/wal_tracking_shared_context.rb
+++ b/spec/support/shared_contexts/lib/gitlab/database/load_balancing/wal_tracking_shared_context.rb
@@ -62,7 +62,13 @@ RSpec.shared_context 'when tracking WAL location reference' do
def stub_replica_available!(available)
::Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
- allow(lb).to receive(:select_up_to_date_host).with(current_location).and_return(available)
+ result = if available
+ ::Gitlab::Database::LoadBalancing::LoadBalancer::ANY_CAUGHT_UP
+ else
+ ::Gitlab::Database::LoadBalancing::LoadBalancer::NONE_CAUGHT_UP
+ end
+
+ allow(lb).to receive(:select_up_to_date_host).with(current_location).and_return(result)
end
end
end
diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb
index 112b90029b8..a09319b4980 100644
--- a/spec/support/shared_contexts/navbar_structure_context.rb
+++ b/spec/support/shared_contexts/navbar_structure_context.rb
@@ -82,7 +82,6 @@ RSpec.shared_context 'project navbar structure' do
{
nav_item: _('Monitor'),
nav_sub_items: [
- _('Tracing'),
_('Error Tracking'),
_('Alerts'),
_('Incidents')
@@ -165,15 +164,6 @@ RSpec.shared_context 'group navbar structure' do
}
end
- let(:ci_cd_nav_item) do
- {
- nav_item: _('CI/CD'),
- nav_sub_items: [
- s_('Runners|Runners')
- ]
- }
- end
-
let(:issues_nav_items) do
[
_('List'),
@@ -207,6 +197,12 @@ RSpec.shared_context 'group navbar structure' do
},
(security_and_compliance_nav_item if Gitlab.ee?),
{
+ nav_item: _('CI/CD'),
+ nav_sub_items: [
+ s_('Runners|Runners')
+ ]
+ },
+ {
nav_item: _('Kubernetes'),
nav_sub_items: []
},
@@ -231,6 +227,10 @@ RSpec.shared_context 'dashboard navbar structure' do
nav_sub_items: []
},
{
+ nav_item: _('Organizations'),
+ nav_sub_items: []
+ },
+ {
nav_item: _("Issues"),
nav_sub_items: []
},
diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
index 07a4cbdb534..70b48322efd 100644
--- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
@@ -58,6 +58,7 @@ RSpec.shared_context 'GroupPolicy context' do
destroy_upload
admin_achievement
award_achievement
+ read_group_runners
]
end
@@ -73,7 +74,6 @@ RSpec.shared_context 'GroupPolicy context' do
create_subgroup
read_statistics
update_default_branch_protection
- read_group_runners
register_group_runners
read_billing
edit_billing
diff --git a/spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb b/spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb
index 36103b94542..cf5ac849f63 100644
--- a/spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb
+++ b/spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb
@@ -5,7 +5,7 @@ RSpec.shared_context 'npm api setup' do
include HttpBasicAuthHelpers
let_it_be(:user, reload: true) { create(:user) }
- let_it_be(:group) { create(:group, name: 'test-group') }
+ let_it_be(:group, reload: true) { create(:group, name: 'test-group') }
let_it_be(:namespace) { group }
let_it_be(:project, reload: true) { create(:project, :public, namespace: namespace) }
let_it_be(:package, reload: true) { create(:npm_package, project: project, name: "@#{group.path}/scoped_package", version: '1.2.3') }
diff --git a/spec/support/shared_examples/channels/noteable/notes_channel_shared_examples.rb b/spec/support/shared_examples/channels/noteable/notes_channel_shared_examples.rb
index cb7001a9faf..21bba14f3e6 100644
--- a/spec/support/shared_examples/channels/noteable/notes_channel_shared_examples.rb
+++ b/spec/support/shared_examples/channels/noteable/notes_channel_shared_examples.rb
@@ -15,16 +15,4 @@ RSpec.shared_examples 'handle subscription based on user access' do
expect(subscription).to be_rejected
end
-
- context 'when action_cable_notes is disabled' do
- before do
- stub_feature_flags(action_cable_notes: false)
- end
-
- it 'rejects the subscription' do
- subscribe(subscribe_params)
-
- expect(subscription).to be_rejected
- end
- end
end
diff --git a/spec/support/shared_examples/ci/create_pipeline_service_environment_shared_examples.rb b/spec/support/shared_examples/ci/create_pipeline_service_environment_shared_examples.rb
new file mode 100644
index 00000000000..77a352a8326
--- /dev/null
+++ b/spec/support/shared_examples/ci/create_pipeline_service_environment_shared_examples.rb
@@ -0,0 +1,166 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'creating a pipeline with environment keyword' do
+ context 'with environment' do
+ let(:config) do
+ YAML.dump(
+ deploy: {
+ environment: { name: "review/$CI_COMMIT_REF_NAME" },
+ **base_config
+ })
+ end
+
+ it 'creates the environment', :sidekiq_inline do
+ result = execute_service.payload
+
+ expect(result).to be_persisted
+ expect(Environment.find_by(name: "review/master")).to be_present
+ expect(result.all_jobs.first.deployment).to be_persisted
+ expect(result.all_jobs.first.deployment.deployable).to be_a(expected_deployable_class)
+ end
+
+ it 'sets tags when build job' do
+ skip unless expected_deployable_class == Ci::Build
+
+ result = execute_service.payload
+
+ expect(result).to be_persisted
+ expect(result.all_jobs.first.tag_list).to match_array(expected_tag_names)
+ end
+ end
+
+ context 'with environment with auto_stop_in' do
+ let(:config) do
+ YAML.dump(
+ deploy: {
+ environment: { name: "review/$CI_COMMIT_REF_NAME", auto_stop_in: '1 day' },
+ **base_config
+ })
+ end
+
+ it 'creates the environment with auto stop in' do
+ result = execute_service.payload
+
+ expect(result).to be_persisted
+ expect(result.all_jobs.first.options[:environment][:auto_stop_in]).to eq('1 day')
+ end
+ end
+
+ context 'with environment name including persisted variables' do
+ let(:config) do
+ YAML.dump(
+ deploy: {
+ environment: { name: "review/id1$CI_PIPELINE_ID/id2$CI_JOB_ID" },
+ **base_config
+ }
+ )
+ end
+
+ it 'skips persisted variables in environment name' do
+ result = execute_service.payload
+
+ expect(result).to be_persisted
+ expect(Environment.find_by(name: "review/id1/id2")).to be_present
+ end
+ end
+
+ context 'when environment with Kubernetes configuration' do
+ let(:kubernetes_namespace) { 'custom-namespace' }
+ let(:config) do
+ YAML.dump(
+ deploy: {
+ environment: {
+ name: "environment-name",
+ kubernetes: { namespace: kubernetes_namespace }
+ },
+ **base_config
+ }
+ )
+ end
+
+ it 'stores the requested namespace' do
+ result = execute_service.payload
+ job = result.all_jobs.first
+
+ expect(result).to be_persisted
+ expect(job.options.dig(:environment, :kubernetes, :namespace)).to eq(kubernetes_namespace)
+ end
+ end
+
+ context 'when environment with invalid name' do
+ let(:config) do
+ YAML.dump(deploy: { environment: { name: 'name,with,commas' }, **base_config })
+ end
+
+ it 'does not create an environment' do
+ expect do
+ result = execute_service.payload
+
+ expect(result).to be_persisted
+ end.not_to change { Environment.count }
+ end
+ end
+
+ context 'when environment with duplicate names' do
+ let(:config) do
+ YAML.dump({
+ deploy: { environment: { name: 'production' }, **base_config },
+ deploy_2: { environment: { name: 'production' }, **base_config }
+ })
+ end
+
+ it 'creates a pipeline with the environment', :sidekiq_inline do
+ result = execute_service.payload
+
+ expect(result).to be_persisted
+ expect(Environment.find_by(name: 'production')).to be_present
+ expect(result.all_jobs.first.deployment).to be_persisted
+ expect(result.all_jobs.first.deployment.deployable).to be_a(expected_deployable_class)
+ end
+ end
+
+ context 'when pipeline has a job with environment' do
+ let(:pipeline) { execute_service.payload }
+
+ context 'when environment name is valid' do
+ let(:config) do
+ YAML.dump({
+ review_app: {
+ environment: {
+ name: 'review/${CI_COMMIT_REF_NAME}',
+ url: 'http://${CI_COMMIT_REF_SLUG}-staging.example.com'
+ },
+ **base_config
+ }
+ })
+ end
+
+ it 'has a job with environment', :sidekiq_inline do
+ expect(pipeline.all_jobs.count).to eq(1)
+ expect(pipeline.all_jobs.first.persisted_environment.name).to eq('review/master')
+ expect(pipeline.all_jobs.first.deployment.status).to eq(expected_deployment_status)
+ expect(pipeline.all_jobs.first.status).to eq(expected_job_status)
+ end
+ end
+
+ context 'when environment name is invalid' do
+ let(:config) do
+ YAML.dump({
+ 'job:deploy-to-test-site': {
+ environment: {
+ name: '${CI_JOB_NAME}',
+ url: 'https://$APP_URL'
+ },
+ **base_config
+ }
+ })
+ end
+
+ it 'has a job without environment' do
+ expect(pipeline.all_jobs.count).to eq(1)
+ expect(pipeline.all_jobs.first.persisted_environment).to be_nil
+ expect(pipeline.all_jobs.first.deployment).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/ci/deployable_shared_examples.rb b/spec/support/shared_examples/ci/deployable_shared_examples.rb
index b51a8fa20e2..4f43d38e604 100644
--- a/spec/support/shared_examples/ci/deployable_shared_examples.rb
+++ b/spec/support/shared_examples/ci/deployable_shared_examples.rb
@@ -96,7 +96,7 @@ RSpec.shared_examples 'a deployable job' do
ActiveRecord::QueryRecorder.new { subject }
end
- index_for_build = recorded.log.index { |l| l.include?("UPDATE #{Ci::Build.quoted_table_name}") }
+ index_for_build = recorded.log.index { |l| l.include?("UPDATE #{described_class.quoted_table_name}") }
index_for_deployment = recorded.log.index { |l| l.include?("UPDATE \"deployments\"") }
expect(index_for_build).to be < index_for_deployment
@@ -259,7 +259,7 @@ RSpec.shared_examples 'a deployable job' do
describe '#environment_tier_from_options' do
subject { job.environment_tier_from_options }
- let(:job) { Ci::Build.new(options: options) }
+ let(:job) { described_class.new(options: options) }
let(:options) { { environment: { deployment_tier: 'production' } } }
it { is_expected.to eq('production') }
@@ -276,7 +276,7 @@ RSpec.shared_examples 'a deployable job' do
let(:options) { { environment: { deployment_tier: 'production' } } }
let!(:environment) { create(:environment, name: 'production', tier: 'development', project: project) }
- let(:job) { Ci::Build.new(options: options, environment: 'production', project: project) }
+ let(:job) { described_class.new(options: options, environment: 'production', project: project) }
it { is_expected.to eq('production') }
@@ -295,6 +295,52 @@ RSpec.shared_examples 'a deployable job' do
end
end
+ describe '#environment_url' do
+ subject { job.environment_url }
+
+ let!(:job) { create(factory_type, :with_deployment, :deploy_to_production, pipeline: pipeline) }
+
+ it { is_expected.to eq('http://prd.example.com/$CI_JOB_NAME') }
+
+ context 'when options does not include url' do
+ before do
+ job.update!(options: { environment: { url: nil } })
+ job.persisted_environment.update!(external_url: 'http://prd.example.com/$CI_JOB_NAME')
+ end
+
+ it 'fetches from the persisted environment' do
+ expect_any_instance_of(::Environment) do |environment|
+ expect(environment).to receive(:external_url).once
+ end
+
+ is_expected.to eq('http://prd.example.com/$CI_JOB_NAME')
+ end
+
+ context 'when persisted environment is absent' do
+ before do
+ job.clear_memoization(:persisted_environment)
+ job.persisted_environment = nil
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+
+ describe '#environment_slug' do
+ subject { job.environment_slug }
+
+ let!(:job) { create(factory_type, :with_deployment, :start_review_app, pipeline: pipeline) }
+
+ it { is_expected.to eq('review-master-8dyme2') }
+
+ context 'when persisted environment is absent' do
+ let!(:job) { create(factory_type, :start_review_app, pipeline: pipeline) }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
describe 'environment' do
describe '#has_environment_keyword?' do
subject { job.has_environment_keyword? }
@@ -536,10 +582,6 @@ RSpec.shared_examples 'a deployable job' do
end
describe '#deployment_status' do
- before do
- allow_any_instance_of(Ci::Build).to receive(:create_deployment) # rubocop:disable RSpec/AnyInstanceOf
- end
-
context 'when job is a last deployment' do
let(:job) { create(factory_type, :success, environment: 'production', pipeline: pipeline) }
let(:environment) { create(:environment, name: 'production', project: job.project) }
diff --git a/spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb b/spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb
index e61c884cd2b..14d0ac81250 100644
--- a/spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb
+++ b/spec/support/shared_examples/config/metrics/every_metric_definition_shared_examples.rb
@@ -121,8 +121,7 @@ RSpec.shared_examples 'every metric definition' do
let(:ignored_classes) do
[
Gitlab::Usage::Metrics::Instrumentations::IssuesWithAlertManagementAlertsMetric,
- Gitlab::Usage::Metrics::Instrumentations::IssuesWithPrometheusAlertEvents,
- Gitlab::Usage::Metrics::Instrumentations::IssuesWithSelfManagedPrometheusAlertEvents
+ Gitlab::Usage::Metrics::Instrumentations::IssuesWithPrometheusAlertEvents
].freeze
end
diff --git a/spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb b/spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb
index 56a5dcb10b2..cb4e68122d9 100644
--- a/spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/concerns/web_hooks/integrations_hook_log_actions_shared_examples.rb
@@ -43,5 +43,14 @@ RSpec.shared_examples WebHooks::HookLogActions do
expect(response).to have_gitlab_http_status(:not_found)
end
+
+ it 'redirects back with a warning if the hook log url is outdated' do
+ web_hook_log.update!(url_hash: 'some_other_value')
+
+ post retry_path, headers: { 'REFERER' => show_path }
+
+ expect(response).to redirect_to(show_path)
+ expect(flash[:warning]).to eq(_('The hook URL has changed, and this log entry cannot be retried'))
+ end
end
end
diff --git a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
index a4eb6a839c0..bd9c2582d2f 100644
--- a/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/issuable_notes_filter_shared_examples.rb
@@ -18,23 +18,6 @@ RSpec.shared_examples 'issuable notes filter' do
expect(UserPreference.count).to eq(1)
end
- it 'expires notes e-tag cache for issuable if filter changed' do
- notes_filter = UserPreference::NOTES_FILTERS[:only_comments]
-
- expect_any_instance_of(issuable.class).to receive(:expire_note_etag_cache)
-
- get :discussions, params: params.merge(notes_filter: notes_filter)
- end
-
- it 'does not expires notes e-tag cache for issuable if filter did not change' do
- notes_filter = UserPreference::NOTES_FILTERS[:only_comments]
- user.set_notes_filter(notes_filter, issuable)
-
- expect_any_instance_of(issuable.class).not_to receive(:expire_note_etag_cache)
-
- get :discussions, params: params.merge(notes_filter: notes_filter)
- end
-
it 'does not set notes filter when database is in read-only mode' do
allow(Gitlab::Database).to receive(:read_only?).and_return(true)
notes_filter = UserPreference::NOTES_FILTERS[:only_comments]
diff --git a/spec/support/shared_examples/controllers/labels_controller_shared_examples.rb b/spec/support/shared_examples/controllers/labels_controller_shared_examples.rb
new file mode 100644
index 00000000000..aea552f6ac7
--- /dev/null
+++ b/spec/support/shared_examples/controllers/labels_controller_shared_examples.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'lock_on_merge when editing labels' do
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(enforce_locked_labels_on_merge: false)
+ visit edit_label_path_unlocked
+ end
+
+ it 'does not display the checkbox/help text' do
+ expect(page).not_to have_content(_('Lock label after a merge request is merged'))
+ expect(page).not_to have_content(label_lock_on_merge_help_text)
+ end
+ end
+
+ it 'updates lock_on_merge' do
+ expect(page).to have_content(_('Lock label after a merge request is merged'))
+ expect(page).to have_content(label_lock_on_merge_help_text)
+
+ check(_('Lock label after a merge request is merged'))
+ click_button 'Save changes'
+
+ expect(label_unlocked.reload.lock_on_merge).to be_truthy
+ end
+
+ it 'checkbox is disabled if lock_on_merge already set' do
+ visit edit_label_path_locked
+
+ expect(page.find('#label_lock_on_merge')).to be_disabled
+ end
+end
+
+RSpec.shared_examples 'lock_on_merge when creating labels' do
+ it 'is not supported when creating a label' do
+ expect(page).not_to have_content(_('Lock label after a merge request is merged'))
+ expect(page).not_to have_content(label_lock_on_merge_help_text)
+ end
+end
diff --git a/spec/support/shared_examples/controllers/search_rate_limit_shared_examples.rb b/spec/support/shared_examples/controllers/search_rate_limit_shared_examples.rb
new file mode 100644
index 00000000000..aefcdc70082
--- /dev/null
+++ b/spec/support/shared_examples/controllers/search_rate_limit_shared_examples.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# - user
+# - params
+
+RSpec.shared_examples 'search request exceeding rate limit' do
+ include_examples 'rate limited endpoint', rate_limit_key: :search_rate_limit
+
+ it 'allows user in allow-list to search without applying rate limit', :freeze_time,
+ :clean_gitlab_redis_rate_limiting do
+ allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit).and_return(1)
+
+ stub_application_setting(search_rate_limit_allowlist: [current_user.username])
+
+ request
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+end
diff --git a/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb b/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb
index 3d3b619451d..29d6f202498 100644
--- a/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb
+++ b/spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb
@@ -57,7 +57,7 @@ RSpec.shared_examples 'Snowplow event tracking with Redis context' do |overrides
it_behaves_like 'Snowplow event tracking', overrides: overrides do
let(:context) do
key_path = try(:label) || action
- [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: key_path).to_context.to_json]
+ [Gitlab::Usage::MetricDefinition.context_for(key_path).to_context.to_json]
end
end
end
diff --git a/spec/support/shared_examples/features/2fa_shared_examples.rb b/spec/support/shared_examples/features/2fa_shared_examples.rb
index 6c4e98c9989..f50874b6b05 100644
--- a/spec/support/shared_examples/features/2fa_shared_examples.rb
+++ b/spec/support/shared_examples/features/2fa_shared_examples.rb
@@ -14,7 +14,7 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
end
describe "registration" do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
gitlab_sign_in(user)
@@ -67,7 +67,7 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
end
describe 'fallback code authentication' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, :no_super_sidebar) }
before do
# Register and logout
diff --git a/spec/support/shared_examples/features/content_editor_shared_examples.rb b/spec/support/shared_examples/features/content_editor_shared_examples.rb
index fff8ef915eb..3e81f969462 100644
--- a/spec/support/shared_examples/features/content_editor_shared_examples.rb
+++ b/spec/support/shared_examples/features/content_editor_shared_examples.rb
@@ -244,7 +244,8 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { wi
end
end
- it 'expands the link, updates the link attributes and text if text is updated' do
+ it 'expands the link, updates the link attributes and text if text is updated',
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/419684' do
page.within '[data-testid="link-bubble-menu"]' do
fill_in 'link-text', with: 'new text'
fill_in 'link-href', with: 'https://about.gitlab.com'
diff --git a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
index d410653ca43..58bf461c733 100644
--- a/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
+++ b/spec/support/shared_examples/features/project_features_apply_to_issuables_shared_examples.rb
@@ -4,8 +4,8 @@ RSpec.shared_examples 'project features apply to issuables' do |klass|
let(:described_class) { klass }
let(:group) { create(:group) }
- let(:user_in_group) { create(:group_member, :developer, user: create(:user), group: group ).user }
- let(:user_outside_group) { create(:user) }
+ let(:user_in_group) { create(:group_member, :developer, user: create(:user, :no_super_sidebar), group: group ).user }
+ let(:user_outside_group) { create(:user, :no_super_sidebar) }
let(:project) { create(:project, :public, project_args) }
diff --git a/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
index fb882ef8a23..fc717fbac20 100644
--- a/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
+++ b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb
@@ -2,6 +2,7 @@
RSpec.shared_examples "protected branches > access control > CE" do
let(:no_one) { ProtectedRef::AccessLevel.humanize(::Gitlab::Access::NO_ACCESS) }
+ let_it_be(:edit_form) { '.js-protected-branch-edit-form' }
ProtectedRef::AccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
it "allows creating protected branches that #{access_type_name} can push to" do
@@ -30,7 +31,8 @@ RSpec.shared_examples "protected branches > access control > CE" do
expect(ProtectedBranch.last.merge_access_levels.map(&:access_level)).to eq([access_type_id])
end
- it "allows updating protected branches so that #{access_type_name} can push to them" do
+ it "allows updating protected branches so that #{access_type_name} can push to them",
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/425080' do
visit project_protected_branches_path(project)
show_add_form
@@ -41,18 +43,14 @@ RSpec.shared_examples "protected branches > access control > CE" do
expect(ProtectedBranch.count).to eq(1)
- within(".protected-branches-list") do
- within_select(".js-allowed-to-push") do
- click_on(access_type_name)
- end
- end
-
+ set_allowed_to('push', access_type_name, form: edit_form)
wait_for_requests
expect(ProtectedBranch.last.push_access_levels.map(&:access_level)).to include(access_type_id)
end
- it "allows updating protected branches so that #{access_type_name} can merge to them" do
+ it "allows updating protected branches so that #{access_type_name} can merge to them",
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/425080' do
visit project_protected_branches_path(project)
show_add_form
@@ -63,12 +61,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
expect(ProtectedBranch.count).to eq(1)
- within(".protected-branches-list") do
- within_select(".js-allowed-to-merge") do
- click_on(access_type_name)
- end
- end
-
+ set_allowed_to('merge', access_type_name, form: edit_form)
wait_for_requests
expect(ProtectedBranch.last.merge_access_levels.map(&:access_level)).to include(access_type_id)
diff --git a/spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb b/spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb
index 703ba5b018a..2b7147fa4b4 100644
--- a/spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb
+++ b/spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb
@@ -19,7 +19,7 @@ RSpec.shared_examples 'Deploy keys with protected tags' do
find(".js-allowed-to-create").click
wait_for_requests
- within('[data-testid="allowed-to-create-dropdown"]') do
+ within('.dropdown-menu') do
dropdown_headers = page.all('.dropdown-header').map(&:text)
expect(dropdown_headers).to contain_exactly(*all_dropdown_sections)
@@ -53,7 +53,7 @@ RSpec.shared_examples 'Deploy keys with protected tags' do
find(".js-allowed-to-create").click
wait_for_requests
- within('[data-testid="allowed-to-create-dropdown"]') do
+ within('.dropdown-menu') do
dropdown_headers = page.all('.dropdown-header').map(&:text)
expect(dropdown_headers).to contain_exactly(*dropdown_sections_minus_deploy_keys)
diff --git a/spec/support/shared_examples/features/runners_shared_examples.rb b/spec/support/shared_examples/features/runners_shared_examples.rb
index 0c043f48c5f..861c205337a 100644
--- a/spec/support/shared_examples/features/runners_shared_examples.rb
+++ b/spec/support/shared_examples/features/runners_shared_examples.rb
@@ -94,6 +94,17 @@ RSpec.shared_examples 'shows runner in list' do
end
end
+RSpec.shared_examples 'shows runner details from list' do
+ it 'shows runner details page' do
+ click_link("##{runner.id} (#{runner.short_sha})")
+
+ expect(current_url).to include(runner_page_path)
+
+ expect(page).to have_selector 'h1', text: "##{runner.id} (#{runner.short_sha})"
+ expect(page).to have_content "#{s_('Runners|Description')} #{runner.description}"
+ end
+end
+
RSpec.shared_examples 'pauses, resumes and deletes a runner' do
include Spec::Support::Helpers::ModalHelpers
@@ -191,6 +202,13 @@ RSpec.shared_examples 'shows runner jobs tab' do
end
end
+RSpec.shared_examples 'shows locked field' do
+ it 'shows locked checkbox with description', :js do
+ expect(page).to have_selector('input[type="checkbox"][name="locked"]')
+ expect(page).to have_content(_('Lock to current projects'))
+ end
+end
+
RSpec.shared_examples 'submits edit runner form' do
it 'breadcrumb contains runner id and token' do
page.within '[data-testid="breadcrumb-links"]' do
diff --git a/spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb b/spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb
index 8ebec19a884..c2d144bef3b 100644
--- a/spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb
+++ b/spec/support/shared_examples/features/sidebar/sidebar_labels_shared_examples.rb
@@ -86,7 +86,7 @@ RSpec.shared_examples 'labels sidebar widget' do
context 'creating a label', :js do
before do
page.within(labels_widget) do
- page.find('[data-testid="create-label-button"]').click
+ click_button 'Create project label'
end
end
@@ -96,12 +96,11 @@ RSpec.shared_examples 'labels sidebar widget' do
end
end
- it 'creates new label', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391240' do
+ it 'creates new label' do
page.within(labels_widget) do
fill_in 'Name new label', with: 'wontfix'
- page.find('.suggest-colors a', match: :first).click
- page.find('button', text: 'Create').click
- wait_for_requests
+ click_link 'Magenta-pink'
+ click_button 'Create'
expect(page).to have_content 'wontfix'
end
diff --git a/spec/support/shared_examples/features/snippets_shared_examples.rb b/spec/support/shared_examples/features/snippets_shared_examples.rb
index bf870b3ce66..383f81d048f 100644
--- a/spec/support/shared_examples/features/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/features/snippets_shared_examples.rb
@@ -52,7 +52,7 @@ RSpec.shared_examples 'tabs with counts' do
end
RSpec.shared_examples 'does not show New Snippet button' do
- let(:user) { create(:user, :external) }
+ let(:user) { create(:user, :external, :no_super_sidebar) }
specify do
sign_in(user)
diff --git a/spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb b/spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb
index 0b0c9edcb42..c1057671699 100644
--- a/spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb
@@ -41,15 +41,15 @@ RSpec.shared_examples 'variable list pagination' do |variable_type|
it 'sorts variables alphabetically in ASC and DESC order' do
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq(variable.key)
- expect(find('.js-ci-variable-row:nth-child(20) td[data-label="Key"]').text).to eq('test_key_8')
+ expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]')).to have_content(variable.key)
+ expect(find('.js-ci-variable-row:nth-child(20) td[data-label="Key"]')).to have_content('test_key_8')
end
click_button 'Next'
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq('test_key_9')
+ expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]')).to have_content('test_key_9')
end
page.within('[data-testid="ci-variable-table"]') do
@@ -59,8 +59,8 @@ RSpec.shared_examples 'variable list pagination' do |variable_type|
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq('test_key_9')
- expect(find('.js-ci-variable-row:nth-child(20) td[data-label="Key"]').text).to eq('test_key_0')
+ expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]')).to have_content('test_key_9')
+ expect(find('.js-ci-variable-row:nth-child(20) td[data-label="Key"]')).to have_content('test_key_0')
end
end
end
diff --git a/spec/support/shared_examples/features/variable_list_shared_examples.rb b/spec/support/shared_examples/features/variable_list_shared_examples.rb
index 3a91b798bbd..5951d3e781b 100644
--- a/spec/support/shared_examples/features/variable_list_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_shared_examples.rb
@@ -3,7 +3,7 @@
RSpec.shared_examples 'variable list' do
it 'shows a list of variables' do
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq(variable.key)
+ expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]')).to have_content(variable.key)
end
end
@@ -17,7 +17,7 @@ RSpec.shared_examples 'variable list' do
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq('key')
+ expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]')).to have_content('key')
end
end
@@ -31,8 +31,8 @@ RSpec.shared_examples 'variable list' do
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']").text).to eq('key')
- expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Attributes')}']")).to have_content(s_('CiVariables|Protected'))
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']")).to have_content('key')
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']")).to have_content(s_('CiVariables|Protected'))
end
end
@@ -46,25 +46,25 @@ RSpec.shared_examples 'variable list' do
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']").text).to eq('key')
- expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Attributes')}']")).not_to have_content(s_('CiVariables|Masked'))
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']")).to have_content('key')
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']")).not_to have_content(s_('CiVariables|Masked'))
end
end
it 'reveals and hides variables' do
page.within('[data-testid="ci-variable-table"]') do
- expect(first('.js-ci-variable-row td[data-label="Key"]').text).to eq(variable.key)
+ expect(first('.js-ci-variable-row td[data-label="Key"]')).to have_content(variable.key)
expect(page).to have_content('*' * 5)
click_button('Reveal value')
- expect(first('.js-ci-variable-row td[data-label="Key"]').text).to eq(variable.key)
- expect(first('.js-ci-variable-row td[data-label="Value"]').text).to eq(variable.value)
+ expect(first('.js-ci-variable-row td[data-label="Key"]')).to have_content(variable.key)
+ expect(first('.js-ci-variable-row td[data-label="Value"]')).to have_content(variable.value)
expect(page).not_to have_content('*' * 5)
click_button('Hide value')
- expect(first('.js-ci-variable-row td[data-label="Key"]').text).to eq(variable.key)
+ expect(first('.js-ci-variable-row td[data-label="Key"]')).to have_content(variable.key)
expect(page).to have_content('*' * 5)
end
end
@@ -98,7 +98,7 @@ RSpec.shared_examples 'variable list' do
wait_for_requests
- expect(first('.js-ci-variable-row td[data-label="Key"]').text).to eq('new_key')
+ expect(first('.js-ci-variable-row td[data-label="Key"]')).to have_content('new_key')
end
it 'edits a variable to be unmasked' do
@@ -116,8 +116,8 @@ RSpec.shared_examples 'variable list' do
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Attributes')}']")).to have_content(s_('CiVariables|Protected'))
- expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Attributes')}']")).not_to have_content(s_('CiVariables|Masked'))
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']")).to have_content(s_('CiVariables|Protected'))
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']")).not_to have_content(s_('CiVariables|Masked'))
end
end
@@ -145,7 +145,7 @@ RSpec.shared_examples 'variable list' do
end
page.within('[data-testid="ci-variable-table"]') do
- expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Attributes')}']")).to have_content(s_('CiVariables|Masked'))
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']")).to have_content(s_('CiVariables|Masked'))
end
end
@@ -234,9 +234,9 @@ RSpec.shared_examples 'variable list' do
# expect to find 3 rows of variables in alphabetical order
expect(page).to have_selector('.js-ci-variable-row', count: 3)
rows = all('.js-ci-variable-row')
- expect(rows[0].find('td[data-label="Key"]').text).to eq('ckey')
- expect(rows[1].find('td[data-label="Key"]').text).to eq('test_key')
- expect(rows[2].find('td[data-label="Key"]').text).to eq('zkey')
+ expect(rows[0].find('td[data-label="Key"]')).to have_content('ckey')
+ expect(rows[1].find('td[data-label="Key"]')).to have_content('test_key')
+ expect(rows[2].find('td[data-label="Key"]')).to have_content('zkey')
end
context 'defaults to the application setting' do
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
index d3863c9a675..18e0cfdad00 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -179,6 +179,45 @@ RSpec.shared_examples 'work items assignees' do
expect(work_item.reload.assignees).to include(user)
end
+
+ it 'successfully assigns the current user by clicking `Assign myself` button' do
+ find('[data-testid="work-item-assignees-input"]').hover
+ find('[data-testid="assign-self"]').click
+ wait_for_requests
+
+ expect(work_item.reload.assignees).to include(user)
+ end
+
+ it 'successfully removes all users on clear all button click' do
+ find('[data-testid="work-item-assignees-input"]').hover
+ find('[data-testid="assign-self"]').click
+ wait_for_requests
+
+ expect(work_item.reload.assignees).to include(user)
+
+ find('[data-testid="work-item-assignees-input"]').click
+ find('[data-testid="clear-all-button"]').click
+ find("body").click
+ wait_for_requests
+
+ expect(work_item.reload.assignees).not_to include(user)
+ end
+
+ it 'successfully removes user on clicking badge cross button' do
+ find('[data-testid="work-item-assignees-input"]').hover
+ find('[data-testid="assign-self"]').click
+ wait_for_requests
+
+ expect(work_item.reload.assignees).to include(user)
+
+ within('[data-testid="work-item-assignees-input"]') do
+ find('[data-testid="close-icon"]').click
+ end
+ find("body").click
+ wait_for_requests
+
+ expect(work_item.reload.assignees).not_to include(user)
+ end
end
RSpec.shared_examples 'work items labels' do
diff --git a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
index 19001abcbe2..ed8feebf1f6 100644
--- a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
+++ b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
@@ -1406,7 +1406,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
expect(finder.execute.to_sql)
- .to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
+ .to match(/^WITH "issues" AS MATERIALIZED/)
end
end
@@ -1416,7 +1416,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
expect(finder.execute.to_sql)
- .to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
+ .to match(/^WITH "issues" AS MATERIALIZED/)
end
end
@@ -1426,7 +1426,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
expect(finder.execute.to_sql)
- .to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
+ .to match(/^WITH "issues" AS MATERIALIZED/)
end
end
@@ -1436,7 +1436,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
expect(finder.execute.to_sql)
- .to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/)
+ .to match(/^WITH "issues" AS MATERIALIZED/)
end
end
end
diff --git a/spec/support/shared_examples/graphql/mutations/update_time_estimate_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/update_time_estimate_shared_examples.rb
index d6d360bb413..a69b56c3d58 100644
--- a/spec/support/shared_examples/graphql/mutations/update_time_estimate_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/update_time_estimate_shared_examples.rb
@@ -6,11 +6,25 @@ RSpec.shared_examples 'updating time estimate' do
let(:input_params) { input.merge(extra_params).merge({ timeEstimate: time_estimate }) }
+ before do
+ resource.update!(time_estimate: 1800)
+ end
+
+ context 'when time estimate is not provided' do
+ let(:input_params) { input.merge(extra_params).except(:timeEstimate) }
+
+ it 'does not update' do
+ expect { post_graphql_mutation(mutation, current_user: current_user) }
+ .not_to change { resource.reload.time_estimate }
+ end
+ end
+
context 'when time estimate is not a valid numerical value' do
let(:time_estimate) { '-3.5d' }
it 'does not update' do
- expect { post_graphql_mutation(mutation, current_user: current_user) }.not_to change { resource.time_estimate }
+ expect { post_graphql_mutation(mutation, current_user: current_user) }
+ .not_to change { resource.reload.time_estimate }
end
it 'returns error' do
@@ -24,7 +38,8 @@ RSpec.shared_examples 'updating time estimate' do
let(:time_estimate) { 'nonsense' }
it 'does not update' do
- expect { post_graphql_mutation(mutation, current_user: current_user) }.not_to change { resource.time_estimate }
+ expect { post_graphql_mutation(mutation, current_user: current_user) }
+ .not_to change { resource.reload.time_estimate }
end
it 'returns error' do
@@ -47,6 +62,7 @@ RSpec.shared_examples 'updating time estimate' do
'1h' | 3600
'0h' | 0
'-0h' | 0
+ nil | 0
end
with_them do
diff --git a/spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb b/spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb
index b346f35bdc9..2c94f21e144 100644
--- a/spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb
@@ -61,14 +61,6 @@ RSpec.shared_examples 'Gitlab-style deprecations' do
expect(deprecable.deprecation_reason).to eq('This was renamed. Deprecated in 1.10.')
end
- it 'supports named reasons: alpha' do
- deprecable = subject(deprecated: { milestone: '1.10', reason: :alpha })
-
- expect(deprecable.deprecation_reason).to eq(
- 'This feature is an Experiment. It can be changed or removed at any time. Introduced in 1.10.'
- )
- end
-
it 'supports :alpha' do
deprecable = subject(alpha: { milestone: '1.10' })
@@ -82,7 +74,7 @@ RSpec.shared_examples 'Gitlab-style deprecations' do
subject(alpha: { milestone: '1.10' }, deprecated: { milestone: '1.10', reason: 'my reason' } )
end.to raise_error(
ArgumentError,
- eq("`experiment` and `deprecated` arguments cannot be passed at the same time")
+ eq("`alpha` and `deprecated` arguments cannot be passed at the same time")
)
end
diff --git a/spec/support/shared_examples/harbor/artifacts_controller_shared_examples.rb b/spec/support/shared_examples/harbor/artifacts_controller_shared_examples.rb
index 85fcd426e3d..16e25bf96dd 100644
--- a/spec/support/shared_examples/harbor/artifacts_controller_shared_examples.rb
+++ b/spec/support/shared_examples/harbor/artifacts_controller_shared_examples.rb
@@ -87,17 +87,7 @@ RSpec.shared_examples 'a harbor artifacts controller' do |args|
get harbor_artifact_url(container, repository_id), headers: json_header
end
- context 'with harbor registry feature flag enabled' do
- it_behaves_like 'responds with 200 status with json'
- end
-
- context 'with harbor registry feature flag disabled' do
- before do
- stub_feature_flags(harbor_registry_integration: false)
- end
-
- it_behaves_like 'responds with 404 status'
- end
+ it_behaves_like 'responds with 200 status with json'
context 'with anonymous user' do
before do
diff --git a/spec/support/shared_examples/harbor/repositories_controller_shared_examples.rb b/spec/support/shared_examples/harbor/repositories_controller_shared_examples.rb
index b35595a10b2..a0d47d1a2d1 100644
--- a/spec/support/shared_examples/harbor/repositories_controller_shared_examples.rb
+++ b/spec/support/shared_examples/harbor/repositories_controller_shared_examples.rb
@@ -87,17 +87,7 @@ RSpec.shared_examples 'a harbor repositories controller' do |args|
get harbor_repository_url(container)
end
- context 'with harbor registry feature flag enabled' do
- it_behaves_like 'responds with 200 status with html'
- end
-
- context 'with harbor registry feature flag disabled' do
- before do
- stub_feature_flags(harbor_registry_integration: false)
- end
-
- it_behaves_like 'responds with 404 status'
- end
+ it_behaves_like 'responds with 200 status with html'
context 'with anonymous user' do
before do
@@ -121,17 +111,7 @@ RSpec.shared_examples 'a harbor repositories controller' do |args|
get harbor_repository_url(container), headers: json_header
end
- context 'with harbor registry feature flag enabled' do
- it_behaves_like 'responds with 200 status with json'
- end
-
- context 'with harbor registry feature flag disabled' do
- before do
- stub_feature_flags(harbor_registry_integration: false)
- end
-
- it_behaves_like 'responds with 404 status'
- end
+ it_behaves_like 'responds with 200 status with json'
context 'with valid params' do
context 'with valid page params' do
diff --git a/spec/support/shared_examples/harbor/tags_controller_shared_examples.rb b/spec/support/shared_examples/harbor/tags_controller_shared_examples.rb
index 46fea7fdff6..aee728295de 100644
--- a/spec/support/shared_examples/harbor/tags_controller_shared_examples.rb
+++ b/spec/support/shared_examples/harbor/tags_controller_shared_examples.rb
@@ -76,17 +76,7 @@ RSpec.shared_examples 'a harbor tags controller' do |args|
headers: json_header)
end
- context 'with harbor registry feature flag enabled' do
- it_behaves_like 'responds with 200 status with json'
- end
-
- context 'with harbor registry feature flag disabled' do
- before do
- stub_feature_flags(harbor_registry_integration: false)
- end
-
- it_behaves_like 'responds with 404 status'
- end
+ it_behaves_like 'responds with 200 status with json'
context 'with anonymous user' do
before do
diff --git a/spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb b/spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb
deleted file mode 100644
index d4fe45a91a0..00000000000
--- a/spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'behind AI related feature flags' do |provider_flag|
- context "when #{provider_flag} is disabled" do
- before do
- stub_feature_flags(provider_flag => false)
- end
-
- it 'responds as not found' do
- post api(url, current_user), params: input_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'when ai_experimentation_api is disabled' do
- before do
- stub_feature_flags(ai_experimentation_api: false)
- end
-
- it 'responds as not found' do
- post api(url, current_user), params: input_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-end
-
-RSpec.shared_examples 'delegates AI request to Workhorse' do
- it 'responds with Workhorse send-url headers' do
- post api(url, current_user), params: input_params
-
- expect(response.body).to eq('""')
- expect(response).to have_gitlab_http_status(:ok)
-
- send_url_prefix, encoded_data = response.headers['Gitlab-Workhorse-Send-Data'].split(':')
- data = Gitlab::Json.parse(Base64.urlsafe_decode64(encoded_data))
-
- expect(send_url_prefix).to eq('send-url')
- expect(data).to eq({
- 'AllowRedirects' => false,
- 'Method' => 'POST'
- }.merge(expected_params))
- end
-end
diff --git a/spec/support/shared_examples/lib/gitlab/bitbucket_import/object_import_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/bitbucket_import/object_import_shared_examples.rb
new file mode 100644
index 00000000000..3dbe43d822f
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/bitbucket_import/object_import_shared_examples.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Gitlab::BitbucketImport::ObjectImporter do
+ include AfterNextHelpers
+
+ describe '.sidekiq_retries_exhausted' do
+ let(:job) { { 'args' => [1, {}, 'key'], 'jid' => 'jid' } }
+
+ it 'notifies the waiter' do
+ expect(Gitlab::JobWaiter).to receive(:notify).with('key', 'jid')
+
+ described_class.sidekiq_retries_exhausted_block.call(job, StandardError.new)
+ end
+ end
+
+ describe '#perform' do
+ let_it_be(:import_started_project) { create(:project, :import_started) }
+
+ let(:project_id) { project_id }
+ let(:waiter_key) { 'key' }
+
+ shared_examples 'notifies the waiter' do
+ specify do
+ allow_next(worker.importer_class).to receive(:execute)
+
+ expect(Gitlab::JobWaiter).to receive(:notify).with(waiter_key, anything)
+
+ worker.perform(project_id, {}, waiter_key)
+ end
+ end
+
+ context 'when project does not exist' do
+ let(:project_id) { non_existing_record_id }
+
+ it_behaves_like 'notifies the waiter'
+ end
+
+ context 'when project has import started' do
+ let_it_be(:project) do
+ create(:project, :import_started, import_data_attributes: {
+ data: { 'project_key' => 'key', 'repo_slug' => 'slug' },
+ credentials: { 'token' => 'token' }
+ })
+ end
+
+ let(:project_id) { project.id }
+
+ it 'calls the importer' do
+ expect(Gitlab::BitbucketImport::Logger).to receive(:info).twice
+ expect_next(worker.importer_class, project, kind_of(Hash)).to receive(:execute)
+
+ worker.perform(project_id, {}, waiter_key)
+ end
+
+ it_behaves_like 'notifies the waiter'
+
+ context 'when the importer raises an ActiveRecord::RecordInvalid error' do
+ before do
+ allow_next(worker.importer_class).to receive(:execute).and_raise(ActiveRecord::RecordInvalid)
+ end
+
+ it 'tracks the error' do
+ expect(Gitlab::Import::ImportFailureService).to receive(:track).once
+
+ worker.perform(project_id, {}, waiter_key)
+ end
+ end
+
+ context 'when the importer raises a StandardError' do
+ before do
+ allow_next(worker.importer_class).to receive(:execute).and_raise(StandardError)
+ end
+
+ it 'tracks the error and raises the error' do
+ expect(Gitlab::Import::ImportFailureService).to receive(:track).once
+
+ expect { worker.perform(project_id, {}, waiter_key) }.to raise_error(StandardError)
+ end
+ end
+ end
+
+ context 'when project import has been cancelled' do
+ let_it_be(:project_id) { create(:project, :import_canceled).id }
+
+ it 'does not call the importer' do
+ expect_next(worker.importer_class).not_to receive(:execute)
+
+ worker.perform(project_id, {}, waiter_key)
+ end
+
+ it_behaves_like 'notifies the waiter'
+ end
+ end
+
+ describe '#importer_class' do
+ it 'does not raise a NotImplementedError' do
+ expect(worker.importer_class).not_to be_nil
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/bitbucket_import/stage_methods_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/bitbucket_import/stage_methods_shared_examples.rb
new file mode 100644
index 00000000000..f128aa92a53
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/bitbucket_import/stage_methods_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Gitlab::BitbucketImport::StageMethods do
+ describe '.sidekiq_retries_exhausted' do
+ let(:job) { { 'args' => [project.id] } }
+
+ it 'tracks the import failure' do
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track).with(
+ project_id: project.id,
+ exception: StandardError.new,
+ fail_import: true
+ )
+
+ described_class.sidekiq_retries_exhausted_block.call(job, StandardError.new)
+ end
+ end
+
+ describe '.perform' do
+ let(:worker) { described_class.new }
+
+ it 'executes the import' do
+ expect(worker).to receive(:import).with(project).once
+ expect(Gitlab::BitbucketImport::Logger).to receive(:info).twice
+
+ worker.perform(project.id)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb
index ec2ae0b8a73..4eae8632467 100644
--- a/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/object_import_shared_examples.rb
@@ -7,7 +7,7 @@ RSpec.shared_examples Gitlab::BitbucketServerImport::ObjectImporter do
let(:job) { { 'args' => [1, {}, 'key'], 'jid' => 'jid' } }
it 'notifies the waiter' do
- expect(Gitlab::JobWaiter).to receive(:notify).with('key', 'jid')
+ expect(Gitlab::JobWaiter).to receive(:notify).with('key', 'jid', ttl: Gitlab::Import::JOB_WAITER_TTL)
described_class.sidekiq_retries_exhausted_block.call(job, StandardError.new)
end
@@ -23,7 +23,7 @@ RSpec.shared_examples Gitlab::BitbucketServerImport::ObjectImporter do
specify do
allow_next(worker.importer_class).to receive(:execute)
- expect(Gitlab::JobWaiter).to receive(:notify).with(waiter_key, anything)
+ expect(Gitlab::JobWaiter).to receive(:notify).with(waiter_key, anything, ttl: Gitlab::Import::JOB_WAITER_TTL)
worker.perform(project_id, {}, waiter_key)
end
diff --git a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
index 10f58748698..7cfab5c8295 100644
--- a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
@@ -35,8 +35,8 @@ RSpec.shared_examples 'common trace features' do
stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: trace.job.project)
end
- it 'calls ::Ci::Build.sticking.unstick_or_continue_sticking' do
- expect(::Ci::Build.sticking).to receive(:unstick_or_continue_sticking)
+ it 'calls ::Ci::Build.sticking.find_caught_up_replica' do
+ expect(::Ci::Build.sticking).to receive(:find_caught_up_replica)
.with(described_class::LOAD_BALANCING_STICKING_NAMESPACE, trace.job.id)
.and_call_original
@@ -49,8 +49,8 @@ RSpec.shared_examples 'common trace features' do
stub_feature_flags(gitlab_ci_archived_trace_consistent_reads: false)
end
- it 'does not call ::Ci::Build.sticking.unstick_or_continue_sticking' do
- expect(::Ci::Build.sticking).not_to receive(:unstick_or_continue_sticking)
+ it 'does not call ::Ci::Build.sticking.find_caught_up_replica' do
+ expect(::Ci::Build.sticking).not_to receive(:find_caught_up_replica)
trace.read { |stream| stream }
end
diff --git a/spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb
index df795723874..b80a51a1fc6 100644
--- a/spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/database/cte_materialized_shared_examples.rb
@@ -4,40 +4,17 @@ RSpec.shared_examples 'CTE with MATERIALIZED keyword examples' do
describe 'adding MATERIALIZE to the CTE' do
let(:options) { {} }
- before do
- # Clear the cached value before the test
- Gitlab::Database::AsWithMaterialized.clear_memoization(:materialized_supported)
- end
-
- context 'when PG version is <12' do
- it 'does not add MATERIALIZE keyword' do
- allow(ApplicationRecord.database).to receive(:version).and_return('11.1')
+ it 'adds MATERIALIZE keyword' do
+ allow(ApplicationRecord.database).to receive(:version).and_return('12.1')
- expect(query).to include(expected_query_block_without_materialized)
- end
+ expect(query).to include(expected_query_block_with_materialized)
end
- context 'when PG version is >=12' do
- it 'adds MATERIALIZE keyword' do
- allow(ApplicationRecord.database).to receive(:version).and_return('12.1')
-
- expect(query).to include(expected_query_block_with_materialized)
- end
+ context 'when materialized is disabled' do
+ let(:options) { { materialized: false } }
- context 'when version is higher than 12' do
- it 'adds MATERIALIZE keyword' do
- allow(ApplicationRecord.database).to receive(:version).and_return('15.1')
-
- expect(query).to include(expected_query_block_with_materialized)
- end
- end
-
- context 'when materialized is disabled' do
- let(:options) { { materialized: false } }
-
- it 'does not add MATERIALIZE keyword' do
- expect(query).to include(expected_query_block_without_materialized)
- end
+ it 'does not add MATERIALIZE keyword' do
+ expect(query).to include(expected_query_block_without_materialized)
end
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/import/advance_stage_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/import/advance_stage_shared_examples.rb
new file mode 100644
index 00000000000..0fef5269ab6
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/import/advance_stage_shared_examples.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Gitlab::Import::AdvanceStage do |factory:|
+ let_it_be(:project) { create(:project) }
+ let_it_be_with_reload(:import_state) { create(factory, :started, project: project, jid: '123') }
+ let(:worker) { described_class.new }
+ let(:next_stage) { :finish }
+
+ describe '#perform', :clean_gitlab_redis_shared_state do
+ context 'when the project no longer exists' do
+ it 'does not perform any work' do
+ expect(worker).not_to receive(:wait_for_jobs)
+
+ worker.perform(non_existing_record_id, { '123' => 2 }, next_stage)
+ end
+ end
+
+ context 'when there are remaining jobs' do
+ it 'reschedules itself' do
+ expect(worker)
+ .to receive(:wait_for_jobs)
+ .with({ '123' => 2 })
+ .and_return({ '123' => 1 })
+
+ expect(described_class)
+ .to receive(:perform_in)
+ .with(described_class::INTERVAL, project.id, { '123' => 1 }, next_stage)
+
+ worker.perform(project.id, { '123' => 2 }, next_stage)
+ end
+
+ context 'when the project import is not running' do
+ before do
+ import_state.update_column(:status, :failed)
+ end
+
+ it 'does not perform any work' do
+ expect(worker).not_to receive(:wait_for_jobs)
+ expect(described_class).not_to receive(:perform_in)
+
+ worker.perform(project.id, { '123' => 2 }, next_stage)
+ end
+
+ it 'clears the JobWaiter cache' do
+ expect(Gitlab::JobWaiter).to receive(:delete_key).with('123')
+
+ worker.perform(project.id, { '123' => 2 }, next_stage)
+ end
+ end
+ end
+
+ context 'when there are no remaining jobs' do
+ before do
+ allow(worker)
+ .to receive(:wait_for_jobs)
+ .with({ '123' => 2 })
+ .and_return({})
+ end
+
+ it 'schedules the next stage' do
+ next_worker = described_class::STAGES[next_stage]
+
+ expect_next_found_instance_of(import_state.class) do |state|
+ expect(state).to receive(:refresh_jid_expiration)
+ end
+
+ expect(next_worker).to receive(:perform_async).with(project.id)
+
+ worker.perform(project.id, { '123' => 2 }, next_stage)
+ end
+
+ it 'raises KeyError when the stage name is invalid' do
+ expect { worker.perform(project.id, { '123' => 2 }, :kittens) }
+ .to raise_error(KeyError)
+ end
+ end
+ end
+
+ describe '#wait_for_jobs' do
+ it 'waits for jobs to complete and returns a new pair of keys to wait for' do
+ waiter1 = instance_double("Gitlab::JobWaiter", jobs_remaining: 1, key: '123')
+ waiter2 = instance_double("Gitlab::JobWaiter", jobs_remaining: 0, key: '456')
+
+ expect(Gitlab::JobWaiter)
+ .to receive(:new)
+ .ordered
+ .with(2, '123')
+ .and_return(waiter1)
+
+ expect(Gitlab::JobWaiter)
+ .to receive(:new)
+ .ordered
+ .with(1, '456')
+ .and_return(waiter2)
+
+ expect(waiter1)
+ .to receive(:wait)
+ .with(described_class::BLOCKING_WAIT_TIME)
+
+ expect(waiter2)
+ .to receive(:wait)
+ .with(described_class::BLOCKING_WAIT_TIME)
+
+ new_waiters = worker.wait_for_jobs({ '123' => 2, '456' => 1 })
+
+ expect(new_waiters).to eq({ '123' => 1 })
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
index c2898513424..025f0d5c7ea 100644
--- a/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
@@ -15,7 +15,7 @@ RSpec.shared_examples 'a repo type' do
describe '#repository_for' do
it 'finds the repository for the repo type' do
- expect(described_class.repository_for(expected_repository_resolver)).to eq(expected_repository)
+ expect(described_class.repository_for(expected_container)).to eq(expected_repository)
end
it 'returns nil when container is nil' do
diff --git a/spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb
index 6b296d0e78a..ac72b31d5a4 100644
--- a/spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'search results filtered by archived' do |feature_flag_name|
+RSpec.shared_examples 'search results filtered by archived' do |feature_flag_name, migration_name|
context 'when filter not provided (all behavior)' do
let(:filters) { {} }
@@ -28,16 +28,33 @@ RSpec.shared_examples 'search results filtered by archived' do |feature_flag_nam
end
end
- context "when the #{feature_flag_name} feature flag is disabled" do
- let(:filters) { {} }
+ if feature_flag_name.present?
+ context "when the #{feature_flag_name} feature flag is disabled" do
+ let(:filters) { {} }
+
+ before do
+ stub_feature_flags("#{feature_flag_name}": false)
+ end
- before do
- stub_feature_flags("#{feature_flag_name}": false)
+ it 'returns archived and unarchived results' do
+ expect(results.objects(scope)).to include unarchived_result
+ expect(results.objects(scope)).to include archived_result
+ end
end
+ end
- it 'returns archived and unarchived results' do
- expect(results.objects(scope)).to include unarchived_result
- expect(results.objects(scope)).to include archived_result
+ if migration_name.present?
+ context "when the #{migration_name} is not completed" do
+ let(:filters) { {} }
+
+ before do
+ set_elasticsearch_migration_to(migration_name.to_s, including: false)
+ end
+
+ it 'returns archived and unarchived results' do
+ expect(results.objects(scope)).to include unarchived_result
+ expect(results.objects(scope)).to include archived_result
+ end
end
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
deleted file mode 100644
index 9dc18555340..00000000000
--- a/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'tracked issuable events' do
- before do
- stub_application_setting(usage_ping_enabled: true)
- end
-
- def count_unique(date_from: Date.today.beginning_of_week, date_to: 1.week.from_now)
- Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: action, start_date: date_from, end_date: date_to)
- end
-
- specify do
- aggregate_failures do
- expect(track_action({ author: user1 }.merge(track_params))).to be_truthy
- expect(track_action({ author: user1 }.merge(track_params))).to be_truthy
- expect(track_action({ author: user2 }.merge(track_params))).to be_truthy
- expect(count_unique).to eq(2)
- end
- end
-
- it 'does not track edit actions if author is not present' do
- expect(track_action({ author: nil }.merge(track_params))).to be_nil
- end
-end
-
-RSpec.shared_examples 'tracked issuable snowplow and service ping events for given event params' do
- it_behaves_like 'tracked issuable events'
-
- it 'emits snowplow event' do
- track_action({ author: user1 }.merge(track_params))
-
- expect_snowplow_event(**{ category: category, action: event_action, user: user1 }.merge(event_params))
- end
-end
-
-RSpec.shared_examples 'tracked issuable internal event for given event params' do
- it_behaves_like 'tracked issuable events'
-
- it_behaves_like 'internal event tracking' do
- subject(:track_event) { track_action({ author: user1 }.merge(track_params)) }
-
- let(:user) { user1 }
- let(:namespace) { project&.namespace }
- end
-end
-
-RSpec.shared_examples 'tracked issuable internal event with project' do
- it_behaves_like 'tracked issuable internal event for given event params' do
- let(:track_params) { original_params || { project: project } }
- end
-end
-
-RSpec.shared_examples 'tracked issuable snowplow and service ping events with project' do
- it_behaves_like 'tracked issuable snowplow and service ping events for given event params' do
- let(:context) do
- Gitlab::Tracking::ServicePingContext
- .new(data_source: :redis_hll, event: event_property)
- .to_h
- end
-
- let(:track_params) { original_params || { project: project } }
- let(:event_params) { { project: project }.merge(label: event_label, property: event_property, namespace: project.namespace, context: [context]) }
- end
-end
-
-RSpec.shared_examples 'tracked issuable snowplow and service ping events with namespace' do
- it_behaves_like 'tracked issuable snowplow and service ping events for given event params' do
- let(:context) do
- Gitlab::Tracking::ServicePingContext
- .new(data_source: :redis_hll, event: event_property)
- .to_h
- end
-
- let(:track_params) { { namespace: namespace } }
- let(:event_params) { track_params.merge(label: event_label, property: event_property, context: [context]) }
- end
-end
-
-RSpec.shared_examples 'does not track with namespace when feature flag is disabled' do |feature_flag|
- context "when feature flag #{feature_flag} is disabled" do
- it 'does not track action' do
- stub_feature_flags(feature_flag => false)
-
- expect(track_action(author: user1, namespace: namespace)).to be_nil
- end
- end
-end
diff --git a/spec/support/shared_examples/lib/menus_shared_examples.rb b/spec/support/shared_examples/lib/menus_shared_examples.rb
index 0aa98517444..575f48c43e0 100644
--- a/spec/support/shared_examples/lib/menus_shared_examples.rb
+++ b/spec/support/shared_examples/lib/menus_shared_examples.rb
@@ -62,6 +62,13 @@ RSpec.shared_examples_for 'not serializable as super_sidebar_menu_args' do
end
end
+RSpec.shared_examples_for 'a panel instantiable by the anonymous user' do
+ it do
+ context.instance_variable_set(:@current_user, nil)
+ expect(described_class.new(context)).to be_a(described_class)
+ end
+end
+
RSpec.shared_examples_for 'a panel with uniquely identifiable menu items' do
let(:menu_items) do
subject.instance_variable_get(:@menus)
diff --git a/spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb b/spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb
index 5e8aebb4f29..6a43b9b4300 100644
--- a/spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb
+++ b/spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
-RSpec.shared_examples 'User profile menu' do |title:, icon:, active_route:|
+RSpec.shared_examples 'User profile menu' do |
+ icon:, active_route:, avatar_shape: 'rect', expect_avatar: false, entity_id: nil,
+ # A nil title will fall back to user.name.
+ title: nil
+|
let_it_be(:current_user) { build(:user) }
let_it_be(:user) { build(:user) }
@@ -17,13 +21,19 @@ RSpec.shared_examples 'User profile menu' do |title:, icon:, active_route:|
end
it 'renders the correct title' do
- expect(subject.title).to eq title
+ expect(subject.title).to eq(title || user.name)
end
it 'renders the correct icon' do
expect(subject.sprite_icon).to eq icon
end
+ it 'renders the correct avatar' do
+ expect(subject.avatar).to eq(expect_avatar ? user.avatar_url : nil)
+ expect(subject.avatar_shape).to eq(avatar_shape)
+ expect(subject.entity_id).to eq(entity_id)
+ end
+
it 'defines correct active route' do
expect(subject.active_routes[:path]).to be active_route
end
diff --git a/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb b/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
index 5f59d43ad19..179bbc8734d 100644
--- a/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
+++ b/spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb
@@ -55,6 +55,8 @@ RSpec.shared_examples 'it has loose foreign keys' do
end
RSpec.shared_examples 'cleanup by a loose foreign key' do
+ include LooseForeignKeysHelper
+
let(:foreign_key_definition) do
foreign_keys_for_parent = Gitlab::Database::LooseForeignKeys.definitions_by_table[parent.class.table_name]
foreign_keys_for_parent.find { |definition| definition.from_table == model.class.table_name }
@@ -75,9 +77,7 @@ RSpec.shared_examples 'cleanup by a loose foreign key' do
expect(find_model).to be_present
- LooseForeignKeys::DeletedRecord.using_connection(parent.connection) do
- LooseForeignKeys::ProcessDeletedRecordsService.new(connection: parent.connection).execute
- end
+ process_loose_foreign_key_deletions(record: parent)
if foreign_key_definition.on_delete.eql?(:async_delete)
expect(find_model).not_to be_present
diff --git a/spec/support/shared_examples/mailers/notify_shared_examples.rb b/spec/support/shared_examples/mailers/notify_shared_examples.rb
index cf1ab7697ab..987060d73b9 100644
--- a/spec/support/shared_examples/mailers/notify_shared_examples.rb
+++ b/spec/support/shared_examples/mailers/notify_shared_examples.rb
@@ -54,6 +54,14 @@ RSpec.shared_examples 'an email with X-GitLab headers containing IDs' do
expect(subject.header["X-GitLab-#{model.class.name}-IID"]).to eq nil
end
end
+
+ it 'has X-GitLab-*-State header if model has state defined' do
+ if model.respond_to?(:state)
+ is_expected.to have_header "X-GitLab-#{model.class.name}-State", model.state.to_s
+ else
+ expect(subject.header["X-GitLab-#{model.class.name}-State"]).to eq nil
+ end
+ end
end
RSpec.shared_examples 'an email with X-GitLab headers containing project details' do
diff --git a/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb b/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
index fdb31fa5d9d..37c338a7712 100644
--- a/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
+++ b/spec/support/shared_examples/migrations/add_work_item_widget_shared_examples.rb
@@ -32,3 +32,110 @@ RSpec.shared_examples 'migration that adds widget to work items definitions' do
end
end
end
+
+# Shared examples for testing migration that adds a single widget to a work item type
+#
+# It expects the following variables
+# - `target_type_enum_value`: Int, enum value for the target work item type, typically defined in the migration
+# as a constant
+# - `target_type`: Symbol, the target type's name
+# - `additional_types`: Hash (optional), name of work item types and their corresponding enum value that are defined
+# at the time the migration was created but are missing from `base_types`.
+# - `widgets_for_type`: Hash, name of the widgets included in the target type with their corresponding enum value
+RSpec.shared_examples 'migration that adds a widget to a work item type' do
+ include MigrationHelpers::WorkItemTypesHelper
+
+ let(:work_item_types) { table(:work_item_types) }
+ let(:work_item_widget_definitions) { table(:work_item_widget_definitions) }
+ let(:additional_base_types) { try(:additional_types) || {} }
+ let(:base_types) do
+ {
+ issue: 0,
+ incident: 1,
+ test_case: 2,
+ requirement: 3,
+ task: 4,
+ objective: 5,
+ key_result: 6,
+ epic: 7
+ }.merge!(additional_base_types)
+ end
+
+ after(:all) do
+ # Make sure base types are recreated after running the migration
+ # because migration specs are not run in a transaction
+ reset_work_item_types
+ end
+
+ before do
+ # Database needs to be in a similar state as when the migration was created
+ reset_db_state_prior_to_migration
+ end
+
+ describe '#up' do
+ it "adds widget to work item type", :aggregate_failures do
+ expect do
+ migrate!
+ end.to change { work_item_widget_definitions.count }.by(1)
+
+ work_item_type = work_item_types.find_by(namespace_id: nil, base_type: target_type_enum_value)
+ created_widget = work_item_widget_definitions.last
+
+ expect(created_widget).to have_attributes(
+ widget_type: described_class::WIDGET_ENUM_VALUE,
+ name: described_class::WIDGET_NAME,
+ work_item_type_id: work_item_type.id
+ )
+ end
+
+ context 'when type does not exist' do
+ it 'skips creating the new widget definition' do
+ work_item_types.where(namespace_id: nil, base_type: base_types[target_type]).delete_all
+
+ expect do
+ migrate!
+ end.to not_change(work_item_widget_definitions, :count)
+ end
+ end
+ end
+
+ describe '#down' do
+ it "removes widget from work item type" do
+ migrate!
+
+ expect { schema_migrate_down! }.to change { work_item_widget_definitions.count }.by(-1)
+ end
+ end
+
+ def reset_db_state_prior_to_migration
+ work_item_types.delete_all
+
+ base_types.each do |type_sym, type_enum|
+ create_work_item_type!(type_sym.to_s.titleize, type_enum)
+ end
+
+ target_type_record = work_item_types.find_by_name(target_type.to_s.titleize)
+
+ widgets = widgets_for_type.map do |widget_name_value, widget_enum_value|
+ {
+ work_item_type_id: target_type_record.id,
+ name: widget_name_value,
+ widget_type: widget_enum_value
+ }
+ end
+
+ # Creating all widgets for the type so the state in the DB is as close as possible to the actual state
+ work_item_widget_definitions.upsert_all(
+ widgets,
+ unique_by: :index_work_item_widget_definitions_on_default_witype_and_name
+ )
+ end
+
+ def create_work_item_type!(type_name, type_enum_value)
+ work_item_types.create!(
+ name: type_name,
+ namespace_id: nil,
+ base_type: type_enum_value
+ )
+ end
+end
diff --git a/spec/support/shared_examples/models/concerns/linkable_items_shared_examples.rb b/spec/support/shared_examples/models/concerns/linkable_items_shared_examples.rb
index efd27a051fe..eb37fe66c11 100644
--- a/spec/support/shared_examples/models/concerns/linkable_items_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/linkable_items_shared_examples.rb
@@ -78,5 +78,16 @@ RSpec.shared_examples 'includes LinkableItem concern' do
expect(described_class.for_items(item, item2)).to contain_exactly(target_link)
end
end
+
+ describe '.for_source_and_target' do
+ let_it_be(:item3) { create(:work_item, project: project) }
+ let_it_be(:link1) { create(link_factory, source: item, target: item1) }
+ let_it_be(:link2) { create(link_factory, source: item, target: item2) }
+ let_it_be(:link3) { create(link_factory, source: item, target: item3) }
+
+ it 'includes links for provided source and target' do
+ expect(described_class.for_source_and_target(item, [item1, item2])).to contain_exactly(link1, link2)
+ end
+ end
end
end
diff --git a/spec/support/shared_examples/models/group_shared_examples.rb b/spec/support/shared_examples/models/group_shared_examples.rb
index 9f3359ba4ab..6397e7a87d7 100644
--- a/spec/support/shared_examples/models/group_shared_examples.rb
+++ b/spec/support/shared_examples/models/group_shared_examples.rb
@@ -3,7 +3,6 @@
RSpec.shared_examples 'checks self and root ancestor feature flag' do
let_it_be(:root_group) { create(:group) }
let_it_be(:group) { create(:group, parent: root_group) }
- let_it_be(:project) { create(:project, group: group) }
subject { group.public_send(feature_flag_method) }
@@ -41,3 +40,47 @@ RSpec.shared_examples 'checks self and root ancestor feature flag' do
it { is_expected.to be_truthy }
end
end
+
+RSpec.shared_examples 'checks self (project) and root ancestor feature flag' do
+ let_it_be(:root_group) { create(:group) }
+ let_it_be(:group) { create(:group, parent: root_group) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ subject { project.public_send(feature_flag_method) }
+
+ context 'when FF is enabled for the root group' do
+ before do
+ stub_feature_flags(feature_flag => root_group)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when FF is enabled for the group' do
+ before do
+ stub_feature_flags(feature_flag => group)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when FF is enabled for the project' do
+ before do
+ stub_feature_flags(feature_flag => project)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when FF is disabled globally' do
+ before do
+ stub_feature_flags(feature_flag => false)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when FF is enabled globally' do
+ it { is_expected.to be_truthy }
+ end
+end
diff --git a/spec/support/shared_examples/models/members_notifications_shared_example.rb b/spec/support/shared_examples/models/members_notifications_shared_example.rb
index 329cb812a08..5c783b5cfa7 100644
--- a/spec/support/shared_examples/models/members_notifications_shared_example.rb
+++ b/spec/support/shared_examples/models/members_notifications_shared_example.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
RSpec.shared_examples 'members notifications' do |entity_type|
+ let_it_be(:user) { create(:user) }
+
let(:notification_service) { double('NotificationService').as_null_object }
before do
@@ -8,7 +10,7 @@ RSpec.shared_examples 'members notifications' do |entity_type|
end
describe "#after_create" do
- let(:member) { build(:"#{entity_type}_member", "#{entity_type}": create(entity_type.to_s)) }
+ let(:member) { build(:"#{entity_type}_member", "#{entity_type}": create(entity_type.to_s), user: user) }
it "sends email to user" do
expect(notification_service).to receive(:"new_#{entity_type}_member").with(member)
@@ -35,7 +37,9 @@ RSpec.shared_examples 'members notifications' do |entity_type|
describe '#after_commit' do
context 'on creation of a member requesting access' do
- let(:member) { build(:"#{entity_type}_member", :access_request, "#{entity_type}": create(entity_type.to_s)) }
+ let(:member) do
+ build(:"#{entity_type}_member", :access_request, "#{entity_type}": create(entity_type.to_s), user: user)
+ end
it "calls NotificationService.new_access_request" do
expect(notification_service).to receive(:new_access_request).with(member)
diff --git a/spec/support/shared_examples/models/users/pages_visits_shared_examples.rb b/spec/support/shared_examples/models/users/pages_visits_shared_examples.rb
new file mode 100644
index 00000000000..0b3e8516d25
--- /dev/null
+++ b/spec/support/shared_examples/models/users/pages_visits_shared_examples.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'namespace visits model' do
+ it { is_expected.to validate_presence_of(:entity_id) }
+ it { is_expected.to validate_presence_of(:user_id) }
+ it { is_expected.to validate_presence_of(:visited_at) }
+
+ describe '#visited_around?' do
+ context 'when the checked time matches a recent visit' do
+ [-15.minutes, 15.minutes].each do |time_diff|
+ it 'returns true' do
+ expect(described_class.visited_around?(entity_id: entity.id, user_id: user.id,
+ time: base_time + time_diff)).to be(true)
+ end
+ end
+ end
+
+ context 'when the checked time does not match a recent visit' do
+ [-16.minutes, 16.minutes].each do |time_diff|
+ it 'returns false' do
+ expect(described_class.visited_around?(entity_id: entity.id, user_id: user.id,
+ time: base_time + time_diff)).to be(false)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/redis/redis_shared_examples.rb b/spec/support/shared_examples/redis/redis_shared_examples.rb
index 9224e01b1fe..23ec4a632b7 100644
--- a/spec/support/shared_examples/redis/redis_shared_examples.rb
+++ b/spec/support/shared_examples/redis/redis_shared_examples.rb
@@ -365,6 +365,90 @@ RSpec.shared_examples "redis_shared_examples" do
end
end
+ describe "#parse_client_tls_options" do
+ let(:dummy_certificate) { OpenSSL::X509::Certificate.new }
+ let(:dummy_key) { OpenSSL::PKey::RSA.new }
+ let(:resque_yaml_config_without_tls) { { url: 'redis://localhost:6379' } }
+ let(:resque_yaml_config_with_tls) do
+ {
+ url: 'rediss://localhost:6380',
+ ssl_params: {
+ cert_file: '/tmp/client.crt',
+ key_file: '/tmp/client.key'
+ }
+ }
+ end
+
+ let(:parsed_config_with_tls) do
+ {
+ url: 'rediss://localhost:6380',
+ ssl_params: {
+ cert: dummy_certificate,
+ key: dummy_key
+ }
+ }
+ end
+
+ before do
+ allow(::File).to receive(:exist?).and_call_original
+ allow(::File).to receive(:read).and_call_original
+ end
+
+ context 'when configuration does not have TLS related options' do
+ it 'returns the coniguration as-is' do
+ expect(subject.send(:parse_client_tls_options,
+ resque_yaml_config_without_tls)).to eq(resque_yaml_config_without_tls)
+ end
+ end
+
+ context 'when specified certificate file does not exist' do
+ before do
+ allow(::File).to receive(:exist?).with("/tmp/client.crt").and_return(false)
+ allow(::File).to receive(:exist?).with("/tmp/client.key").and_return(true)
+ end
+
+ it 'raises error about missing certificate file' do
+ expect do
+ subject.send(:parse_client_tls_options,
+ resque_yaml_config_with_tls)
+ end.to raise_error(Gitlab::Redis::Wrapper::InvalidPathError,
+ "Certificate file /tmp/client.crt specified in in `resque.yml` does not exist.")
+ end
+ end
+
+ context 'when specified key file does not exist' do
+ before do
+ allow(::File).to receive(:exist?).with("/tmp/client.crt").and_return(true)
+ allow(::File).to receive(:read).with("/tmp/client.crt").and_return("DUMMY_CERTIFICATE")
+ allow(OpenSSL::X509::Certificate).to receive(:new).with("DUMMY_CERTIFICATE").and_return(dummy_certificate)
+ allow(::File).to receive(:exist?).with("/tmp/client.key").and_return(false)
+ end
+
+ it 'raises error about missing key file' do
+ expect do
+ subject.send(:parse_client_tls_options,
+ resque_yaml_config_with_tls)
+ end.to raise_error(Gitlab::Redis::Wrapper::InvalidPathError,
+ "Key file /tmp/client.key specified in in `resque.yml` does not exist.")
+ end
+ end
+
+ context 'when configuration valid TLS related options' do
+ before do
+ allow(::File).to receive(:exist?).with("/tmp/client.crt").and_return(true)
+ allow(::File).to receive(:exist?).with("/tmp/client.key").and_return(true)
+ allow(::File).to receive(:read).with("/tmp/client.crt").and_return("DUMMY_CERTIFICATE")
+ allow(::File).to receive(:read).with("/tmp/client.key").and_return("DUMMY_KEY")
+ allow(OpenSSL::X509::Certificate).to receive(:new).with("DUMMY_CERTIFICATE").and_return(dummy_certificate)
+ allow(OpenSSL::PKey).to receive(:read).with("DUMMY_KEY").and_return(dummy_key)
+ end
+
+ it "converts cert_file and key_file appropriately" do
+ expect(subject.send(:parse_client_tls_options, resque_yaml_config_with_tls)).to eq(parsed_config_with_tls)
+ end
+ end
+ end
+
describe '#fetch_config' do
before do
FileUtils.mkdir_p(File.join(rails_root, 'config'))
diff --git a/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb b/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
index 74dbec063e0..625f16824b4 100644
--- a/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
+++ b/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
@@ -72,7 +72,7 @@ RSpec.shared_examples 'GET access tokens are paginated and ordered' do
first_token = assigns(:active_access_tokens).first.as_json
expect(first_token['name']).to eq("Token1")
- expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+ expect(first_token['expires_at']).to eq(expires_1_day_from_now.iso8601)
end
it "orders tokens on id in case token has same expires_at" do
@@ -82,11 +82,11 @@ RSpec.shared_examples 'GET access tokens are paginated and ordered' do
first_token = assigns(:active_access_tokens).first.as_json
expect(first_token['name']).to eq("Token3")
- expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+ expect(first_token['expires_at']).to eq(expires_1_day_from_now.iso8601)
second_token = assigns(:active_access_tokens).second.as_json
expect(second_token['name']).to eq("Token1")
- expect(second_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+ expect(second_token['expires_at']).to eq(expires_1_day_from_now.iso8601)
end
end
diff --git a/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
index 6eceb7c350d..04f340fef37 100644
--- a/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
@@ -518,6 +518,39 @@ RSpec.shared_examples 'graphql issue list request spec' do
end
end
+ context 'when fetching external participants' do
+ before_all do
+ issue_a.update!(external_author: 'user@example.com')
+ end
+
+ let(:fields) do
+ <<~QUERY
+ nodes {
+ id
+ externalAuthor
+ }
+ QUERY
+ end
+
+ it 'returns the email address' do
+ post_query
+
+ emails = issues_data.pluck('externalAuthor').compact
+ expect(emails).to contain_exactly('user@example.com')
+ end
+
+ context 'when user does not have access to view emails' do
+ let(:current_user) { external_user }
+
+ it 'obfuscates the email address' do
+ post_query
+
+ emails = issues_data.pluck('externalAuthor').compact
+ expect(emails).to contain_exactly("us*****@e*****.c**")
+ end
+ end
+ end
+
context 'when fetching escalation status' do
let_it_be(:escalation_status) { create(:incident_management_issuable_escalation_status, issue: issue_a) }
let_it_be(:incident_type) { WorkItems::Type.default_by_type(:incident) }
diff --git a/spec/support/shared_examples/requests/api/graphql/work_item_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/work_item_list_shared_examples.rb
new file mode 100644
index 00000000000..a9c422c8f2d
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/work_item_list_shared_examples.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'graphql work item list request spec' do
+ let(:work_item_ids) { graphql_dig_at(work_item_data, :id) }
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_query
+ end
+ end
+
+ describe 'filters' do
+ before do
+ post_query
+ end
+
+ context 'when filtering by author username' do
+ let(:author) { create(:author) }
+ let(:authored_work_item) { create(:work_item, author: author, **container_build_params) }
+
+ let(:item_filter_params) { { author_username: authored_work_item.author.username } }
+
+ it 'returns correct results' do
+ expect(work_item_ids).to contain_exactly(authored_work_item.to_global_id.to_s)
+ end
+ end
+
+ context 'when filtering by state' do
+ let_it_be(:opened_work_item) { create(:work_item, :opened, **container_build_params) }
+ let_it_be(:closed_work_item) { create(:work_item, :closed, **container_build_params) }
+
+ context 'when filtering by state opened' do
+ let(:item_filter_params) { { state: :opened } }
+
+ it 'filters by state' do
+ expect(work_item_ids).to include(opened_work_item.to_global_id.to_s)
+ expect(work_item_ids).not_to include(closed_work_item.to_global_id.to_s)
+ end
+ end
+
+ context 'when filtering by state closed' do
+ let(:item_filter_params) { { state: :closed } }
+
+ it 'filters by state' do
+ expect(work_item_ids).not_to include(opened_work_item.to_global_id.to_s)
+ expect(work_item_ids).to include(closed_work_item.to_global_id.to_s)
+ end
+ end
+ end
+
+ context 'when filtering by type' do
+ let_it_be(:issue_work_item) { create(:work_item, :issue, **container_build_params) }
+ let_it_be(:task_work_item) { create(:work_item, :task, **container_build_params) }
+
+ context 'when filtering by issue type' do
+ let(:item_filter_params) { { types: [:ISSUE] } }
+
+ it 'filters by type' do
+ expect(work_item_ids).to include(issue_work_item.to_global_id.to_s)
+ expect(work_item_ids).not_to include(task_work_item.to_global_id.to_s)
+ end
+ end
+
+ context 'when filtering by task type' do
+ let(:item_filter_params) { { types: [:TASK] } }
+
+ it 'filters by type' do
+ expect(work_item_ids).not_to include(issue_work_item.to_global_id.to_s)
+ expect(work_item_ids).to include(task_work_item.to_global_id.to_s)
+ end
+ end
+ end
+
+ context 'when filtering by iid' do
+ let_it_be(:work_item_by_iid) { create(:work_item, **container_build_params) }
+
+ context 'when using the iid filter' do
+ let(:item_filter_params) { { iid: work_item_by_iid.iid.to_s } }
+
+ it 'returns only items by the given iid' do
+ expect(work_item_ids).to contain_exactly(work_item_by_iid.to_global_id.to_s)
+ end
+ end
+
+ context 'when using the iids filter' do
+ let(:item_filter_params) { { iids: [work_item_by_iid.iid.to_s] } }
+
+ it 'returns only items by the given iid' do
+ expect(work_item_ids).to contain_exactly(work_item_by_iid.to_global_id.to_s)
+ end
+ end
+ end
+ end
+
+ def work_item_data
+ graphql_data.dig(*work_item_node_path)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb b/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb
index f2c38d70508..00e50b07909 100644
--- a/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/ml/mlflow/mlflow_shared_examples.rb
@@ -8,12 +8,25 @@ RSpec.shared_examples 'MLflow|Not Found - Resource Does Not Exist' do
end
end
-RSpec.shared_examples 'MLflow|Requires api scope' do
+RSpec.shared_examples 'MLflow|Requires api scope and write permission' do
context 'when user has access but token has wrong scope' do
let(:access_token) { tokens[:read] }
it { is_expected.to have_gitlab_http_status(:forbidden) }
end
+
+ context 'when user has access but is not allowed to write' do
+ before do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?)
+ .with(current_user, :write_model_experiments, project)
+ .and_return(false)
+ end
+
+ it "is Unauthorized" do
+ is_expected.to have_gitlab_http_status(:unauthorized)
+ end
+ end
end
RSpec.shared_examples 'MLflow|Requires read_api scope' do
diff --git a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
index 6b6bf375827..5f043cdd996 100644
--- a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
@@ -280,7 +280,10 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
end
end
- status = :not_found if scope == :group && params[:package_name_type] == :non_existing && !params[:request_forward]
+ if (scope == :group && params[:package_name_type] == :non_existing) &&
+ (!params[:request_forward] || (!params[:auth] && params[:request_forward] && params[:visibility] != :public))
+ status = :not_found
+ end
# Check the error message for :not_found
example_name = 'returning response status with error' if status == :not_found
@@ -873,3 +876,67 @@ RSpec.shared_examples 'rejects invalid package names' do
expect(Gitlab::Json.parse(response.body)).to eq({ 'error' => 'package_name should be a valid file path' })
end
end
+
+RSpec.shared_examples 'handling get metadata requests for packages in multiple projects' do
+ let_it_be(:project2) { create(:project, namespace: namespace) }
+ let_it_be(:package2) do
+ create(:npm_package,
+ project: project2,
+ name: "@#{group.path}/scoped_package",
+ version: '1.2.0')
+ end
+
+ let(:headers) { build_token_auth_header(personal_access_token.token) }
+
+ subject { get(url, headers: headers) }
+
+ before_all do
+ project.update!(visibility: 'private')
+
+ group.add_guest(user)
+ project.add_reporter(user)
+ project2.add_reporter(user)
+ end
+
+ it 'includes all matching package versions in the response' do
+ subject
+
+ expect(json_response['versions'].keys).to match_array([package.version, package2.version])
+ end
+
+ context 'with the feature flag disabled' do
+ before do
+ stub_feature_flags(npm_allow_packages_in_multiple_projects: false)
+ end
+
+ it 'returns matching package versions from only one project' do
+ subject
+
+ expect(json_response['versions'].keys).to match_array([package2.version])
+ end
+ end
+
+ context 'with limited access to the project with the last package version' do
+ before_all do
+ project2.add_guest(user)
+ end
+
+ it 'includes matching package versions from authorized projects in the response' do
+ subject
+
+ expect(json_response['versions'].keys).to contain_exactly(package.version)
+ end
+ end
+
+ context 'with limited access to the project with the first package version' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'includes matching package versions from authorized projects in the response' do
+ subject
+
+ expect(json_response['versions'].keys).to contain_exactly(package2.version)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
index 2e66bae26ba..1be99040ae5 100644
--- a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
@@ -373,14 +373,6 @@ RSpec.shared_examples 'process nuget download content request' do |user_type, st
end
it_behaves_like 'bumping the package last downloaded at field'
-
- context 'when nuget_normalized_version feature flag is disabled' do
- before do
- stub_feature_flags(nuget_normalized_version: false)
- end
-
- it_behaves_like 'returning response status', :not_found
- end
end
end
end
@@ -710,4 +702,38 @@ RSpec.shared_examples 'nuget upload endpoint' do |symbol_package: false|
it_behaves_like 'returning response status', :forbidden
end
+
+ context 'when package duplicates are not allowed' do
+ let(:headers) { basic_auth_header(deploy_token.username, deploy_token.token).merge(workhorse_headers) }
+ let_it_be(:existing_package) { create(:nuget_package, project: project) }
+ let_it_be(:metadata) { { package_name: existing_package.name, package_version: existing_package.version } }
+ let_it_be(:package_settings) do
+ create(:namespace_package_setting, :group, namespace: project.namespace, nuget_duplicates_allowed: false)
+ end
+
+ before do
+ allow_next_instance_of(::Packages::Nuget::MetadataExtractionService) do |instance|
+ allow(instance).to receive(:execute).and_return(ServiceResponse.success(payload: metadata))
+ end
+ end
+
+ it_behaves_like 'returning response status', :conflict unless symbol_package
+ it_behaves_like 'returning response status', :created if symbol_package
+
+ context 'when exception_regex is set' do
+ before do
+ package_settings.update_column(:nuget_duplicate_exception_regex, ".*#{existing_package.name.last(3)}.*")
+ end
+
+ it_behaves_like 'returning response status', :created
+ end
+
+ context 'when nuget_duplicates_option feature flag is disabled' do
+ before do
+ stub_feature_flags(nuget_duplicates_option: false)
+ end
+
+ it_behaves_like 'returning response status', :created
+ end
+ end
end
diff --git a/spec/support/shared_examples/requests/api_keyset_pagination_shared_examples.rb b/spec/support/shared_examples/requests/api_keyset_pagination_shared_examples.rb
new file mode 100644
index 00000000000..85db36013dd
--- /dev/null
+++ b/spec/support/shared_examples/requests/api_keyset_pagination_shared_examples.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'an endpoint with keyset pagination' do |invalid_order: 'name', invalid_sort: 'asc'|
+ include KeysetPaginationHelpers
+
+ let(:keyset_params) { { pagination: 'keyset', per_page: 1 } }
+ let(:additional_params) { {} }
+
+ subject do
+ get api_call, params: keyset_params.merge(additional_params)
+ response
+ end
+
+ context 'on making requests with supported ordering structure' do
+ it 'includes keyset url params in the url response' do
+ is_expected.to have_gitlab_http_status(:ok)
+ is_expected.to include_keyset_url_params
+ end
+
+ it 'does not include pagination headers' do
+ is_expected.to have_gitlab_http_status(:ok)
+ is_expected.not_to include_pagination_headers
+ end
+
+ it 'paginates the records correctly', :aggregate_failures do
+ is_expected.to have_gitlab_http_status(:ok)
+ records = json_response
+ expect(records.size).to eq(1)
+ expect(records.first['id']).to eq(first_record.id)
+
+ get api_call, params: pagination_params_from_next_url(response)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ records = Gitlab::Json.parse(response.body)
+ expect(records.size).to eq(1)
+ expect(records.first['id']).to eq(second_record.id)
+ end
+ end
+
+ context 'on making requests with unsupported ordering structure' do
+ let(:additional_params) { { order_by: invalid_order, sort: invalid_sort } }
+
+ if invalid_order
+ it 'returns error', :aggregate_failures do
+ is_expected.to have_gitlab_http_status(:method_not_allowed)
+ expect(json_response['error']).to eq('Keyset pagination is not yet available for this type of request')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
index dafa324b3c6..48d3e438322 100644
--- a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
+++ b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
@@ -148,6 +148,12 @@ RSpec.shared_examples 'rate-limited token requests' do
expect(response).not_to have_gitlab_http_status(:too_many_requests)
end
+ matched = throttle_types[throttle_setting_prefix]
+
+ if request_method == 'GET' && throttle_setting_prefix == 'throttle_protected_paths'
+ matched = 'throttle_authenticated_get_protected_paths_api'
+ end
+
arguments = a_hash_including({
message: 'Rack_Attack',
status: 429,
@@ -155,7 +161,7 @@ RSpec.shared_examples 'rate-limited token requests' do
remote_ip: '127.0.0.1',
request_method: request_method,
path: request_args.first,
- matched: throttle_types[throttle_setting_prefix]
+ matched: matched
}.merge(log_data))
expect(Gitlab::AuthLogger).to receive(:error).with(arguments).once
@@ -166,7 +172,14 @@ RSpec.shared_examples 'rate-limited token requests' do
end
it_behaves_like 'tracking when dry-run mode is set' do
- let(:throttle_name) { throttle_types[throttle_setting_prefix] }
+ let(:throttle_name) do
+ name = throttle_types[throttle_setting_prefix]
+ if request_method == 'GET' && throttle_setting_prefix == 'throttle_protected_paths'
+ name = 'throttle_authenticated_get_protected_paths_api'
+ end
+
+ name
+ end
def do_request
make_request(request_args)
@@ -315,7 +328,13 @@ RSpec.shared_examples 'rate-limited web authenticated requests' do
expect(response).not_to have_gitlab_http_status(:too_many_requests)
end
- arguments = a_hash_including({
+ matched = throttle_types[throttle_setting_prefix]
+
+ if request_method == 'GET' && throttle_setting_prefix == 'throttle_protected_paths'
+ matched = 'throttle_authenticated_get_protected_paths_web'
+ end
+
+ arguments = a_hash_including(
message: 'Rack_Attack',
status: 429,
env: :throttle,
@@ -324,15 +343,22 @@ RSpec.shared_examples 'rate-limited web authenticated requests' do
path: url_that_requires_authentication,
user_id: user.id,
'meta.user' => user.username,
- matched: throttle_types[throttle_setting_prefix]
- })
+ matched: matched
+ )
expect(Gitlab::AuthLogger).to receive(:error).with(arguments).once
expect { request_authenticated_web_url }.not_to exceed_query_limit(control_count)
end
it_behaves_like 'tracking when dry-run mode is set' do
- let(:throttle_name) { throttle_types[throttle_setting_prefix] }
+ let(:throttle_name) do
+ name = throttle_types[throttle_setting_prefix]
+ if request_method == 'GET' && throttle_setting_prefix == 'throttle_protected_paths'
+ name = 'throttle_authenticated_get_protected_paths_web'
+ end
+
+ name
+ end
def do_request
request_authenticated_web_url
diff --git a/spec/support/shared_examples/services/incident_shared_examples.rb b/spec/support/shared_examples/services/incident_shared_examples.rb
index db2b448f567..94467ad53fa 100644
--- a/spec/support/shared_examples/services/incident_shared_examples.rb
+++ b/spec/support/shared_examples/services/incident_shared_examples.rb
@@ -40,7 +40,7 @@ end
RSpec.shared_examples 'incident management label service' do
let_it_be(:project) { create(:project, :private) }
- let_it_be(:user) { User.alert_bot }
+ let_it_be(:user) { Users::Internal.alert_bot }
let(:service) { described_class.new(project, user) }
subject(:execute) { service.execute }
diff --git a/spec/support/shared_examples/services/issuable/issuable_update_service_shared_examples.rb b/spec/support/shared_examples/services/issuable/issuable_update_service_shared_examples.rb
index 3f95d6060ea..9624f7a4450 100644
--- a/spec/support/shared_examples/services/issuable/issuable_update_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/issuable/issuable_update_service_shared_examples.rb
@@ -145,6 +145,77 @@ RSpec.shared_examples 'updating issuable labels' do
end
end
+RSpec.shared_examples 'updating merged MR with locked labels' do
+ context 'when add_label_ids and label_ids are passed' do
+ let(:params) { { label_ids: [label_a.id], add_label_ids: [label_c.id] } }
+
+ it 'replaces unlocked labels with the ones in label_ids and adds those in add_label_ids' do
+ issuable.update!(labels: [label_b, label_unlocked])
+ update_issuable(params)
+
+ expect(issuable.label_ids).to contain_exactly(label_a.id, label_b.id, label_c.id)
+ end
+ end
+
+ context 'when remove_label_ids and label_ids are passed' do
+ let(:params) { { label_ids: [label_a.id, label_b.id, label_c.id], remove_label_ids: [label_a.id] } }
+
+ it 'replaces unlocked labels with the ones in label_ids and does not remove locked label in remove_label_ids' do
+ issuable.update!(labels: [label_a, label_c, label_unlocked])
+ update_issuable(params)
+
+ expect(issuable.label_ids).to contain_exactly(label_a.id, label_b.id, label_c.id)
+ end
+ end
+
+ context 'when add_label_ids and remove_label_ids are passed' do
+ let(:params) { { add_label_ids: [label_c.id], remove_label_ids: [label_a.id, label_unlocked.id] } }
+
+ before do
+ issuable.update!(labels: [label_a, label_unlocked])
+ update_issuable(params)
+ end
+
+ it 'adds the passed labels' do
+ expect(issuable.label_ids).to include(label_c.id)
+ end
+
+ it 'removes the passed unlocked labels' do
+ expect(issuable.label_ids).to include(label_a.id)
+ expect(issuable.label_ids).not_to include(label_unlocked.id)
+ end
+ end
+
+ context 'when same id is passed as add_label_ids and remove_label_ids' do
+ let(:params) { { add_label_ids: [label_a.id], remove_label_ids: [label_a.id] } }
+
+ context 'for a label assigned to an issue' do
+ it 'does not remove the label' do
+ issuable.update!(labels: [label_a])
+ update_issuable(params)
+
+ expect(issuable.label_ids).to contain_exactly(label_a.id)
+ end
+ end
+
+ context 'for a label not assigned to an issue' do
+ it 'does not add the label' do
+ expect(issuable.label_ids).to be_empty
+ end
+ end
+ end
+
+ context 'when duplicate label titles are given' do
+ let(:params) { { labels: [label_c.title, label_c.title] } }
+
+ it 'assigns the label once' do
+ update_issuable(params)
+
+ expect(issuable.labels).to contain_exactly(label_c)
+ end
+ end
+end
+
RSpec.shared_examples 'keeps issuable labels sorted after update' do
before do
update_issuable(label_ids: [label_b.id])
diff --git a/spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb b/spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb
index 1532e870dcc..b955b71a6bb 100644
--- a/spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb
+++ b/spec/support/shared_examples/services/issuable_links/destroyable_issuable_links_shared_examples.rb
@@ -1,13 +1,7 @@
# frozen_string_literal: true
-RSpec.shared_examples 'a destroyable issuable link' do |required_role: :reporter|
+RSpec.shared_examples 'a destroyable issuable link' do
context 'when successfully removes an issuable link' do
- before do
- [issuable_link.target, issuable_link.source].each do |issuable|
- issuable.resource_parent.try(:"add_#{required_role}", user)
- end
- end
-
it 'removes related issue' do
expect { subject }.to change { issuable_link.class.count }.by(-1)
end
@@ -28,6 +22,9 @@ RSpec.shared_examples 'a destroyable issuable link' do |required_role: :reporter
end
context 'when failing to remove an issuable link' do
+ let_it_be(:non_member) { create(:user) }
+ let(:user) { non_member }
+
it 'does not remove relation' do
expect { subject }.not_to change { issuable_link.class.count }.from(1)
end
diff --git a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
deleted file mode 100644
index 9b2e038a331..00000000000
--- a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb
+++ /dev/null
@@ -1,193 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'misconfigured dashboard service response' do |status_code, message = nil|
- it 'returns an appropriate message and status code', :aggregate_failures do
- result = service_call
-
- expect(result.keys).to contain_exactly(:message, :http_status, :status)
- expect(result[:status]).to eq(:error)
- expect(result[:http_status]).to eq(status_code)
- expect(result[:message]).to eq(message) if message
- end
-end
-
-RSpec.shared_examples 'valid dashboard service response for schema' do
- it 'returns a json representation of the dashboard' do
- result = service_call
-
- expect(result.keys).to contain_exactly(:dashboard, :status)
- expect(result[:status]).to eq(:success)
-
- schema_path = Rails.root.join('spec/fixtures', dashboard_schema)
- validator = JSONSchemer.schema(schema_path)
- expect(validator.valid?(result[:dashboard].with_indifferent_access)).to be true
- end
-end
-
-RSpec.shared_examples 'valid dashboard service response' do
- let(:dashboard_schema) { 'lib/gitlab/metrics/dashboard/schemas/dashboard.json' }
-
- it_behaves_like 'valid dashboard service response for schema'
-end
-
-RSpec.shared_examples 'caches the unprocessed dashboard for subsequent calls' do
- specify do
- expect_next_instance_of(::Gitlab::Config::Loader::Yaml) do |loader|
- expect(loader).to receive(:load_raw!).once.and_call_original
- end
-
- described_class.new(*service_params).get_dashboard
- described_class.new(*service_params).get_dashboard
- end
-end
-
-# This spec is applicable for predefined/out-of-the-box dashboard services.
-RSpec.shared_examples 'refreshes cache when dashboard_version is changed' do
- specify do
- allow_next_instance_of(described_class) do |service|
- allow(service).to receive(:dashboard_version).and_return('1', '2')
- end
-
- expect_file_read(Rails.root.join(described_class::DASHBOARD_PATH)).twice.and_call_original
-
- service = described_class.new(*service_params)
-
- service.get_dashboard
- service.get_dashboard
- end
-end
-
-# This spec is applicable for predefined/out-of-the-box dashboard services.
-# This shared_example requires the following variables to be defined:
-# dashboard_path: Relative path to the dashboard, ex: 'config/prometheus/common_metrics.yml'
-# dashboard_version: The version string used in the cache_key.
-RSpec.shared_examples 'dashboard_version contains SHA256 hash of dashboard file content' do
- specify do
- dashboard = File.read(Rails.root.join(dashboard_path))
- expect(dashboard_version).to eq(Digest::SHA256.hexdigest(dashboard))
- end
-end
-
-RSpec.shared_examples 'valid embedded dashboard service response' do
- let(:dashboard_schema) { 'lib/gitlab/metrics/dashboard/schemas/embedded_dashboard.json' }
-
- it_behaves_like 'valid dashboard service response for schema'
-end
-
-RSpec.shared_examples 'raises error for users with insufficient permissions' do
- context 'when the user does not have sufficient access' do
- let(:user) { build(:user) }
-
- it_behaves_like 'misconfigured dashboard service response', :unauthorized
- end
-
- context 'when the user is anonymous' do
- let(:user) { nil }
-
- it_behaves_like 'misconfigured dashboard service response', :unauthorized
- end
-end
-
-RSpec.shared_examples 'valid dashboard cloning process' do |dashboard_template, sequence|
- context "dashboard template: #{dashboard_template}" do
- let(:dashboard) { dashboard_template }
- let(:dashboard_attrs) do
- {
- commit_message: commit_message,
- branch_name: branch,
- start_branch: project.default_branch,
- encoding: 'text',
- file_path: ".gitlab/dashboards/#{file_name}",
- file_content: file_content_hash.to_yaml
- }
- end
-
- it 'delegates commit creation to Files::CreateService', :aggregate_failures do
- service_instance = instance_double(::Files::CreateService)
- allow(::Gitlab::Metrics::Dashboard::Processor).to receive(:new).and_return(double(process: file_content_hash))
- expect(::Files::CreateService).to receive(:new).with(project, user, dashboard_attrs).and_return(service_instance)
- expect(service_instance).to receive(:execute).and_return(status: :success)
-
- service_call
- end
-
- context 'user has defined custom metrics' do
- it 'uses external service to includes them into new file content', :aggregate_failures do
- service_instance = double(::Gitlab::Metrics::Dashboard::Processor)
- expect(::Gitlab::Metrics::Dashboard::Processor).to receive(:new).with(project, file_content_hash, sequence, {}).and_return(service_instance)
- expect(service_instance).to receive(:process).and_return(file_content_hash)
- expect(::Files::CreateService).to receive(:new).with(project, user, dashboard_attrs).and_return(double(execute: { status: :success }))
-
- service_call
- end
- end
- end
-end
-
-RSpec.shared_examples 'misconfigured dashboard service response with stepable' do |status_code, message = nil|
- it 'returns an appropriate message and status code', :aggregate_failures do
- result = service_call
-
- expect(result.keys).to contain_exactly(:message, :http_status, :status, :last_step)
- expect(result[:status]).to eq(:error)
- expect(result[:http_status]).to eq(status_code)
- expect(result[:message]).to eq(message) if message
- end
-end
-
-RSpec.shared_examples 'updates gitlab_metrics_dashboard_processing_time_ms metric' do
- specify :prometheus do
- service_call
- metric = subject.send(:processing_time_metric)
- labels = subject.send(:processing_time_metric_labels)
-
- expect(metric.get(labels)).to be > 0
- end
-end
-
-RSpec.shared_examples '#raw_dashboard raises error if dashboard loading fails' do
- context 'when yaml is too large' do
- before do
- allow_next_instance_of(::Gitlab::Config::Loader::Yaml) do |loader|
- allow(loader).to receive(:load_raw!)
- .and_raise(Gitlab::Config::Loader::Yaml::DataTooLargeError, 'The parsed YAML is too big')
- end
- end
-
- it 'raises error' do
- expect { subject.raw_dashboard }.to raise_error(
- Gitlab::Metrics::Dashboard::Errors::LayoutError,
- 'The parsed YAML is too big'
- )
- end
- end
-
- context 'when yaml loader returns error' do
- before do
- allow_next_instance_of(::Gitlab::Config::Loader::Yaml) do |loader|
- allow(loader).to receive(:load_raw!)
- .and_raise(Gitlab::Config::Loader::FormatError, 'Invalid configuration format')
- end
- end
-
- it 'raises error' do
- expect { subject.raw_dashboard }.to raise_error(
- Gitlab::Metrics::Dashboard::Errors::LayoutError,
- 'Invalid yaml'
- )
- end
- end
-
- context 'when yaml is not a hash' do
- before do
- allow_next_instance_of(::Gitlab::Config::Loader::Yaml) do |loader|
- allow(loader).to receive(:load_raw!)
- .and_raise(Gitlab::Config::Loader::Yaml::NotHashError, 'Invalid configuration format')
- end
- end
-
- it 'returns nil' do
- expect(subject.raw_dashboard).to eq({})
- end
- end
-end
diff --git a/spec/support/shared_examples/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/shared_examples/services/migrate_to_ghost_user_service_shared_examples.rb
index e77d73d1c72..621fb99afe5 100644
--- a/spec/support/shared_examples/services/migrate_to_ghost_user_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/migrate_to_ghost_user_service_shared_examples.rb
@@ -38,7 +38,7 @@ RSpec.shared_examples "migrating a deleted user's associated records to the ghos
migrated_record = record_class.find_by_id(record.id)
migrated_fields.each do |field|
- expect(migrated_record.public_send(field)).to eq(User.ghost)
+ expect(migrated_record.public_send(field)).to eq(Users::Internal.ghost)
end
end
@@ -47,7 +47,7 @@ RSpec.shared_examples "migrating a deleted user's associated records to the ghos
migrated_record = record_class.find_by_id(record.id)
- check_user = always_ghost ? User.ghost : user
+ check_user = always_ghost ? Users::Internal.ghost : user
migrated_fields.each do |field|
expect(migrated_record.public_send(field)).to eq(check_user)
diff --git a/spec/support/shared_examples/services/pages_size_limit_shared_examples.rb b/spec/support/shared_examples/services/pages_size_limit_shared_examples.rb
deleted file mode 100644
index d9e906ebb75..00000000000
--- a/spec/support/shared_examples/services/pages_size_limit_shared_examples.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'pages size limit is' do |size_limit|
- context "when size is below the limit" do
- before do
- allow(metadata).to receive(:total_size).and_return(size_limit - 1.megabyte)
- allow(metadata).to receive(:entries).and_return([])
- end
-
- it 'updates pages correctly' do
- subject.execute
-
- expect(deploy_status.description).not_to be_present
- expect(project.pages_metadatum).to be_deployed
- end
- end
-
- context "when size is above the limit" do
- before do
- allow(metadata).to receive(:total_size).and_return(size_limit + 1.megabyte)
- allow(metadata).to receive(:entries).and_return([])
- end
-
- it 'limits the maximum size of gitlab pages' do
- subject.execute
-
- expect(deploy_status.description)
- .to match(/artifacts for pages are too large/)
- expect(deploy_status).to be_script_failure
- end
- end
-end
diff --git a/spec/support/shared_examples/services/protected_branches_shared_examples.rb b/spec/support/shared_examples/services/protected_branches_shared_examples.rb
new file mode 100644
index 00000000000..ce607a6b956
--- /dev/null
+++ b/spec/support/shared_examples/services/protected_branches_shared_examples.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'with scan result policy blocking protected branches' do
+ before do
+ create(
+ :scan_result_policy_read,
+ :blocking_protected_branches,
+ project: project)
+
+ stub_licensed_features(security_orchestration_policies: true)
+ end
+end
diff --git a/spec/support/shared_examples/services/users/build_service_shared_examples.rb b/spec/support/shared_examples/services/users/build_service_shared_examples.rb
index e448f2f874b..45ebc837e6d 100644
--- a/spec/support/shared_examples/services/users/build_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/users/build_service_shared_examples.rb
@@ -33,57 +33,6 @@ RSpec.shared_examples 'common user build items' do
end
RSpec.shared_examples_for 'current user not admin build items' do
- using RSpec::Parameterized::TableSyntax
-
- context 'with "user_default_external" application setting' do
- where(:user_default_external, :external, :email, :user_default_internal_regex, :result) do
- true | nil | 'fl@example.com' | nil | true
- true | true | 'fl@example.com' | nil | true
- true | false | 'fl@example.com' | nil | true # admin difference
-
- true | nil | 'fl@example.com' | '' | true
- true | true | 'fl@example.com' | '' | true
- true | false | 'fl@example.com' | '' | true # admin difference
-
- true | nil | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
- true | true | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
- true | false | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
-
- true | nil | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true
- true | true | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true
- true | false | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | true # admin difference
-
- false | nil | 'fl@example.com' | nil | false
- false | true | 'fl@example.com' | nil | false # admin difference
- false | false | 'fl@example.com' | nil | false
-
- false | nil | 'fl@example.com' | '' | false
- false | true | 'fl@example.com' | '' | false # admin difference
- false | false | 'fl@example.com' | '' | false
-
- false | nil | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
- false | true | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
- false | false | 'fl@example.com' | '^(?:(?!\.ext@).)*$\r?' | false
-
- false | nil | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false
- false | true | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false # admin difference
- false | false | 'tester.ext@domain.com' | '^(?:(?!\.ext@).)*$\r?' | false
- end
-
- with_them do
- before do
- stub_application_setting(user_default_external: user_default_external)
- stub_application_setting(user_default_internal_regex: user_default_internal_regex)
-
- params.merge!({ external: external, email: email }.compact)
- end
-
- it 'sets the value of Gitlab::CurrentSettings.user_default_external' do
- expect(user.external).to eq(result)
- end
- end
- end
-
context 'when "email_confirmation_setting" application setting is set to `hard`' do
before do
stub_application_setting_enum('email_confirmation_setting', 'hard')
diff --git a/spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb b/spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb
index eb03f0888b9..5d24aa10453 100644
--- a/spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb
+++ b/spec/support/shared_examples/users/migrate_records_to_ghost_user_service_shared_examples.rb
@@ -32,7 +32,7 @@ RSpec.shared_examples 'migrating records to the ghost user' do |record_class, fi
migrated_record = record_class.find_by_id(record.id)
migrated_fields.each do |field|
- expect(migrated_record.public_send(field)).to eq(User.ghost)
+ expect(migrated_record.public_send(field)).to eq(Users::Internal.ghost)
end
end
end
diff --git a/spec/support/shared_examples/users/pages_visits_shared_examples.rb b/spec/support/shared_examples/users/pages_visits_shared_examples.rb
new file mode 100644
index 00000000000..1a613fa0aed
--- /dev/null
+++ b/spec/support/shared_examples/users/pages_visits_shared_examples.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'namespace visits tracking worker' do
+ let_it_be(:base_time) { DateTime.now }
+
+ context 'when params are provided' do
+ before do
+ worker.perform(entity_type, entity.id, user.id, base_time)
+ end
+
+ include_examples 'an idempotent worker' do
+ let(:job_args) { [entity_type, entity.id, user.id, base_time] }
+
+ it 'tracks the entity visit' do
+ latest_visit = model.last
+
+ expect(model.count).to be(1)
+ expect(latest_visit[:entity_id]).to be(entity.id)
+ expect(latest_visit.user_id).to be(user.id)
+ end
+ end
+
+ context 'when a visit occurs within 15 minutes of a previously tracked one' do
+ [-15.minutes, 15.minutes].each do |time_diff|
+ it 'does not track the visit' do
+ worker.perform(entity_type, entity.id, user.id, base_time + time_diff)
+
+ expect(model.count).to be(1)
+ end
+ end
+ end
+
+ context 'when a visit occurs more than 15 minutes away from a previously tracked one' do
+ [-16.minutes, 16.minutes].each do |time_diff|
+ it 'tracks the visit' do
+ worker.perform(entity_type, entity.id, user.id, base_time + time_diff)
+
+ expect(model.count).to be > 1
+ end
+ end
+ end
+ end
+
+ context 'when user is missing' do
+ before do
+ worker.perform(entity_type, entity.id, nil, base_time)
+ end
+
+ it 'does not do anything' do
+ expect(model.count).to be(0)
+ end
+ end
+
+ context 'when entity is missing' do
+ before do
+ worker.perform(entity_type, nil, user.id, base_time)
+ end
+
+ it 'does not do anything' do
+ expect(model.count).to be(0)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb b/spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb
index 8ecb04bfdd6..1ea5eb6fd2e 100644
--- a/spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb
+++ b/spec/support/shared_examples/workers/background_migration_worker_shared_examples.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
RSpec.shared_examples 'it runs background migration jobs' do |tracking_database|
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: false)
+ end
+
describe 'defining the job attributes' do
it 'defines the data_consistency as always' do
expect(described_class.get_data_consistency).to eq(:always)
@@ -74,6 +78,38 @@ RSpec.shared_examples 'it runs background migration jobs' do |tracking_database|
end
end
+ context 'when disallow_database_ddl_feature_flags feature flag is disabled' do
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+ end
+
+ it 'does not perform the job, reschedules it in the future, and logs a message' do
+ expect(worker).not_to receive(:perform_with_connection)
+
+ expect(Sidekiq.logger).to receive(:info) do |payload|
+ expect(payload[:class]).to eq(described_class.name)
+ expect(payload[:database]).to eq(tracking_database)
+ expect(payload[:message]).to match(/skipping execution, migration rescheduled/)
+ end
+
+ lease_attempts = 3
+ delay = described_class::BACKGROUND_MIGRATIONS_DELAY
+ job_args = [10, 20]
+
+ freeze_time do
+ worker.perform('Foo', job_args, lease_attempts)
+
+ job = described_class.jobs.find { |job| job['args'] == ['Foo', job_args, lease_attempts] }
+ expect(job).to be, "Expected the job to be rescheduled with (#{job_args}, #{lease_attempts}), but it was not."
+
+ expected_time = delay.to_i + Time.now.to_i
+ expect(job['at']).to eq(expected_time),
+ "Expected the job to be rescheduled in #{expected_time} seconds, " \
+ "but it was rescheduled in #{job['at']} seconds."
+ end
+ end
+ end
+
context 'when execute_background_migrations feature flag is enabled' do
before do
stub_feature_flags(execute_background_migrations: true)
diff --git a/spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb b/spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb
index 8fdd59d1d8c..cf488a4d753 100644
--- a/spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb
+++ b/spec/support/shared_examples/workers/batched_background_migration_execution_worker_shared_example.rb
@@ -3,6 +3,10 @@
RSpec.shared_examples 'batched background migrations execution worker' do
include ExclusiveLeaseHelpers
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: false)
+ end
+
it 'is a limited capacity worker' do
expect(described_class.new).to be_a(LimitedCapacity::Worker)
end
@@ -100,6 +104,23 @@ RSpec.shared_examples 'batched background migrations execution worker' do
end
end
+ context 'when disable ddl flag is enabled' do
+ let(:migration) do
+ create(:batched_background_migration, :active, interval: job_interval, table_name: table_name)
+ end
+
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+ end
+
+ it 'does nothing' do
+ expect(Gitlab::Database::BackgroundMigration::BatchedMigration).not_to receive(:find_executable)
+ expect(worker).not_to receive(:run_migration_job)
+
+ worker.perform_work(database_name, migration.id)
+ end
+ end
+
context 'when the feature flag is enabled' do
before do
stub_feature_flags(execute_batched_migrations_on_schedule: true)
diff --git a/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb b/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb
index e7385f9abb6..003b8d07819 100644
--- a/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb
+++ b/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb
@@ -3,6 +3,10 @@
RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_database, table_name|
include ExclusiveLeaseHelpers
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: false)
+ end
+
describe 'defining the job attributes' do
it 'defines the data_consistency as always' do
expect(described_class.get_data_consistency).to eq(:always)
@@ -51,6 +55,12 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d
expect(described_class.enabled?).to be_falsey
end
+
+ it 'returns false when disallow_database_ddl_feature_flags feature flag is enabled' do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+
+ expect(described_class.enabled?).to be_falsey
+ end
end
describe '#perform' do
@@ -116,6 +126,18 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d
end
end
+ context 'when the disallow_database_ddl_feature_flags feature flag is enabled' do
+ before do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+ end
+
+ it 'does nothing' do
+ expect(worker).not_to receive(:queue_migrations_for_execution)
+
+ worker.perform
+ end
+ end
+
context 'when the execute_batched_migrations_on_schedule feature flag is enabled' do
let(:base_model) { Gitlab::Database.database_base_models[tracking_database] }
let(:connection) { base_model.connection }
diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb
index dc475b92c0b..b25f39c5e74 100644
--- a/spec/support/sidekiq.rb
+++ b/spec/support/sidekiq.rb
@@ -5,9 +5,11 @@ RSpec.configure do |config|
# We need to cleanup the queues before running jobs in specs because the
# middleware might have written to redis
redis_queues_cleanup!
+ redis_queues_metadata_cleanup!
Sidekiq::Testing.inline!(&block)
ensure
redis_queues_cleanup!
+ redis_queues_metadata_cleanup!
end
# As we'll review the examples with this tag, we should either:
diff --git a/spec/support_specs/capybara_wait_for_all_requests_spec.rb b/spec/support_specs/capybara_wait_for_all_requests_spec.rb
index ddd4be6c644..64b89ba0b56 100644
--- a/spec/support_specs/capybara_wait_for_all_requests_spec.rb
+++ b/spec/support_specs/capybara_wait_for_all_requests_spec.rb
@@ -23,37 +23,37 @@ RSpec.describe 'capybara_wait_for_all_requests', feature_category: :tooling do #
end
end
- context 'for Capybara::Node::Actions::WaitForAllRequestsAfterClickButton' do
+ context 'for Capybara::Node::Actions::WaitForRequestsAfterClickButton' do
let(:node) do
Class.new do
def click_button(locator = nil, **_options)
locator
end
- prepend Capybara::Node::Actions::WaitForAllRequestsAfterClickButton
+ prepend Capybara::Node::Actions::WaitForRequestsAfterClickButton
end.new
end
- it 'waits for all requests after a click button' do
- expect(node).to receive(:wait_for_all_requests)
+ it 'waits for requests after a click button' do
+ expect(node).to receive(:wait_for_requests)
node.click_button
end
end
- context 'for Capybara::Node::Actions::WaitForAllRequestsAfterClickLink' do
+ context 'for Capybara::Node::Actions::WaitForRequestsAfterClickLink' do
let(:node) do
Class.new do
def click_link(locator = nil, **_options)
locator
end
- prepend Capybara::Node::Actions::WaitForAllRequestsAfterClickLink
+ prepend Capybara::Node::Actions::WaitForRequestsAfterClickLink
end.new
end
- it 'waits for all requests after a click link' do
- expect(node).to receive(:wait_for_all_requests)
+ it 'waits for requests after a click link' do
+ expect(node).to receive(:wait_for_requests)
node.click_link
end
diff --git a/spec/support_specs/database/duplicate_indexes_spec.rb b/spec/support_specs/database/duplicate_indexes_spec.rb
new file mode 100644
index 00000000000..bbcb80f0593
--- /dev/null
+++ b/spec/support_specs/database/duplicate_indexes_spec.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Database::DuplicateIndexes, feature_category: :database do
+ index_class = ActiveRecord::ConnectionAdapters::IndexDefinition
+ let(:default_index_options) { { using: :btree, orders: {}, unique: false, opclasses: {}, where: nil } }
+
+ let(:table_name) { 'foobar' }
+ let(:index1) { instance_double(index_class, default_index_options.merge(name: 'index1', columns: %w[user_id])) }
+ let(:index1_copy) { instance_double(index_class, default_index_options.merge(name: 'index1b', columns: %w[user_id])) }
+ let(:index2) { instance_double(index_class, default_index_options.merge(name: 'index2', columns: %w[project_id])) }
+ let(:index3) do
+ instance_double(index_class, default_index_options.merge(name: 'index3', columns: %w[user_id project_id]))
+ end
+
+ let(:index3_inverse) do
+ instance_double(index_class, default_index_options.merge(name: 'index3_inverse', columns: %w[project_id user_id]))
+ end
+
+ let(:index1_unique) do
+ instance_double(index_class, default_index_options.merge(name: 'index1_unique', columns: %w[user_id], unique: true))
+ end
+
+ let(:index1_desc) do
+ instance_double(
+ index_class,
+ default_index_options.merge(name: 'index1', columns: %w[user_id], orders: { user_id: 'desc' })
+ )
+ end
+
+ let(:index3_with_where) do
+ instance_double(
+ index_class,
+ default_index_options.merge(name: 'index3_with_where', columns: %w[user_id project_id], where: "id > 100")
+ )
+ end
+
+ subject(:duplicate_indexes) do
+ described_class.new(table_name, indexes).duplicate_indexes
+ end
+
+ context 'when there are no duplicate indexes' do
+ let(:indexes) { [index1, index2] }
+
+ it { expect(duplicate_indexes).to be_empty }
+ end
+
+ context 'when overlapping indexes' do
+ let(:indexes) { [index1, index3] }
+
+ it 'detects a duplicate index between index1 and index3' do
+ expected_duplicate_indexes = { index_struct(index3) => [index_struct(index1)] }
+
+ expect(duplicate_indexes).to eq(expected_duplicate_indexes)
+ end
+ end
+
+ context 'when the indexes have the inverse order of columns' do
+ let(:indexes) { [index3, index3_inverse] }
+
+ it 'does not detect duplicate indexes between index3 and index3_inverse' do
+ expect(duplicate_indexes).to eq({})
+ end
+ end
+
+ # For now we ignore other indexes that are UNIQUE and have a matching columns subset of
+ # the btree_index columns, as UNIQUE indexes are still needed to enforce uniqueness
+ # constraints on subset of the columns.
+ context 'when the index with matching sub-columns is unique' do
+ let(:indexes) { [index3, index1_unique] }
+
+ it 'does not detect duplicate indexes between index3 and index1_unique' do
+ expect(duplicate_indexes).to eq({})
+ end
+ end
+
+ context 'when the one of the indexes is a conditional index' do
+ let(:indexes) { [index3, index3_with_where] }
+
+ it 'does not detect duplicate indexes between index3 and index3_with_where' do
+ expect(duplicate_indexes).to eq({})
+ end
+ end
+
+ context 'when identical indexes' do
+ let(:indexes) { [index1, index1_copy] }
+
+ it 'detects a duplicate index between index1 and index3' do
+ expected_duplicate_indexes = {
+ index_struct(index1) => [index_struct(index1_copy)],
+ index_struct(index1_copy) => [index_struct(index1)]
+ }
+
+ expect(duplicate_indexes).to eq(expected_duplicate_indexes)
+ end
+ end
+
+ context 'when indexes have the same columns but with different order' do
+ let(:indexes) { [index1, index1_desc] }
+
+ it { expect(duplicate_indexes).to be_empty }
+ end
+
+ def index_struct(index)
+ Database::DuplicateIndexes.btree_index_struct(index)
+ end
+end
diff --git a/spec/support_specs/database/multiple_databases_helpers_spec.rb b/spec/support_specs/database/multiple_databases_helpers_spec.rb
index 2577b64f214..0191a759605 100644
--- a/spec/support_specs/database/multiple_databases_helpers_spec.rb
+++ b/spec/support_specs/database/multiple_databases_helpers_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Database::MultipleDatabasesHelpers' do
let(:query) do
<<~SQL
- WITH cte AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (SELECT 1) SELECT 1;
+ WITH cte AS MATERIALIZED (SELECT 1) SELECT 1;
SQL
end
diff --git a/spec/support_specs/helpers/redis_commands/recorder_spec.rb b/spec/support_specs/helpers/redis_commands/recorder_spec.rb
index f41624d8dcc..ef46db5e29e 100644
--- a/spec/support_specs/helpers/redis_commands/recorder_spec.rb
+++ b/spec/support_specs/helpers/redis_commands/recorder_spec.rb
@@ -8,12 +8,6 @@ RSpec.describe RedisCommands::Recorder, :use_clean_rails_redis_caching do
let(:cache) { Rails.cache }
let(:pattern) { nil }
- before do
- # do not need to test for positive case since this is testing
- # a spec support class
- stub_feature_flags(use_primary_and_secondary_stores_for_cache: false)
- end
-
describe '#initialize' do
context 'with a block' do
it 'records Redis commands' do
diff --git a/spec/tasks/gitlab/audit_event_types/check_docs_task_spec.rb b/spec/tasks/gitlab/audit_event_types/check_docs_task_spec.rb
index 5dd7599696b..b492289e99e 100644
--- a/spec/tasks/gitlab/audit_event_types/check_docs_task_spec.rb
+++ b/spec/tasks/gitlab/audit_event_types/check_docs_task_spec.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
-require 'spec_helper'
+require 'rake_helper'
require_relative '../../../../lib/tasks/gitlab/audit_event_types/check_docs_task'
require_relative '../../../../lib/tasks/gitlab/audit_event_types/compile_docs_task'
RSpec.describe Tasks::Gitlab::AuditEventTypes::CheckDocsTask, feature_category: :audit_events do
- let_it_be(:docs_dir) { Rails.root.join("tmp/tests/doc/administration/audit_event_streaming") }
- let_it_be(:docs_path) { Rails.root.join(docs_dir, 'audit_event_types.md') }
- let_it_be(:template_erb_path) { Rails.root.join("tooling/audit_events/docs/templates/audit_event_types.md.erb") }
+ let(:docs_dir) { Rails.root.join("tmp/tests/doc/administration/audit_event_streaming") }
+ let(:docs_path) { Rails.root.join(docs_dir, 'audit_event_types.md') }
+ let(:template_erb_path) { Rails.root.join("tooling/audit_events/docs/templates/audit_event_types.md.erb") }
subject(:check_docs_task) { described_class.new(docs_dir, docs_path, template_erb_path) }
@@ -37,7 +37,7 @@ RSpec.describe Tasks::Gitlab::AuditEventTypes::CheckDocsTask, feature_category:
end
context 'when an existing audit event type is removed' do
- let_it_be(:updated_definition) { Gitlab::Audit::Type::Definition.definitions.except(:feature_flag_created) }
+ let(:updated_definition) { Gitlab::Audit::Type::Definition.definitions.except(:feature_flag_created) }
it 'raises an error' do
expect(Gitlab::Audit::Type::Definition).to receive(:definitions).and_return(updated_definition)
@@ -50,7 +50,7 @@ RSpec.describe Tasks::Gitlab::AuditEventTypes::CheckDocsTask, feature_category:
end
context 'when an existing audit event type is updated' do
- let_it_be(:updated_definition) { Gitlab::Audit::Type::Definition.definitions }
+ let(:updated_definition) { Gitlab::Audit::Type::Definition.definitions }
it 'raises an error' do
updated_definition[:feature_flag_created].attributes[:streamed] = false
diff --git a/spec/tasks/gitlab/audit_event_types/compile_docs_task_spec.rb b/spec/tasks/gitlab/audit_event_types/compile_docs_task_spec.rb
index a881d17d3b8..0ee85b1283b 100644
--- a/spec/tasks/gitlab/audit_event_types/compile_docs_task_spec.rb
+++ b/spec/tasks/gitlab/audit_event_types/compile_docs_task_spec.rb
@@ -1,12 +1,12 @@
# frozen_string_literal: true
-require 'spec_helper'
+require 'rake_helper'
require_relative '../../../../lib/tasks/gitlab/audit_event_types/compile_docs_task'
RSpec.describe Tasks::Gitlab::AuditEventTypes::CompileDocsTask, feature_category: :audit_events do
- let_it_be(:docs_dir) { Rails.root.join("tmp/tests/doc/administration/audit_event_streaming") }
- let_it_be(:docs_path) { Rails.root.join(docs_dir, 'audit_event_types.md') }
- let_it_be(:template_erb_path) { Rails.root.join("tooling/audit_events/docs/templates/audit_event_types.md.erb") }
+ let(:docs_dir) { Rails.root.join("tmp/tests/doc/administration/audit_event_streaming") }
+ let(:docs_path) { Rails.root.join(docs_dir, 'audit_event_types.md') }
+ let(:template_erb_path) { Rails.root.join("tooling/audit_events/docs/templates/audit_event_types.md.erb") }
subject(:compile_docs_task) { described_class.new(docs_dir, docs_path, template_erb_path) }
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 04634af12a8..fda27d5827f 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
%w[db repositories]
end
- before(:all) do # rubocop:disable RSpec/BeforeAll
+ before(:all) do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/gitlab/backup'
Rake.application.rake_require 'tasks/gitlab/shell'
@@ -222,7 +222,7 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
# We only need a backup of the repositories for this test
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,terraform_state,registry')
- create(:project, :repository)
+ create(:project_with_design, :repository)
end
it 'removes stale data' do
@@ -241,7 +241,7 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
end
context 'when the backup is restored' do
- let!(:included_project) { create(:project, :repository) }
+ let!(:included_project) { create(:project_with_design, :repository) }
let!(:original_checksum) { included_project.repository.checksum }
before do
@@ -286,7 +286,7 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
allow(Ci::ApplicationRecord.connection).to receive(:reconnect!)
end
- let!(:project) { create(:project, :repository) }
+ let!(:project) { create(:project_with_design, :repository) }
context 'with specific backup tasks' do
before do
@@ -463,9 +463,9 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
shared_examples 'includes repositories in all repository storages' do
specify :aggregate_failures do
- project_a = create(:project, :repository)
+ project_a = create(:project_with_design, :repository)
project_snippet_a = create(:project_snippet, :repository, project: project_a, author: project_a.first_owner)
- project_b = create(:project, :repository, repository_storage: second_storage_name)
+ project_b = create(:project_with_design, :repository, repository_storage: second_storage_name)
project_snippet_b = create(
:project_snippet,
:repository,
@@ -474,7 +474,6 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
repository_storage: second_storage_name
)
create(:wiki_page, container: project_a)
- create(:design, :with_file, issue: create(:issue, project: project_a))
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
@@ -517,9 +516,9 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
end
it 'includes repositories in default repository storage', :aggregate_failures do
- project_a = create(:project, :repository)
+ project_a = create(:project_with_design, :repository)
project_snippet_a = create(:project_snippet, :repository, project: project_a, author: project_a.first_owner)
- project_b = create(:project, :repository, repository_storage: second_storage_name)
+ project_b = create(:project_with_design, :repository, repository_storage: second_storage_name)
project_snippet_b = create(
:project_snippet,
:repository,
@@ -528,7 +527,6 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
repository_storage: second_storage_name
)
create(:wiki_page, container: project_a)
- create(:design, :with_file, issue: create(:issue, project: project_a))
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
@@ -564,7 +562,7 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
# We only need a backup of the repositories for this test
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,terraform_state,registry')
- create(:project, :repository)
+ create(:project_with_design, :repository)
end
it 'passes through concurrency environment variables' do
@@ -602,7 +600,7 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
before do
stub_env('SKIP', 'an-unknown-type,repositories,uploads,anotherunknowntype')
- create(:project, :repository)
+ create(:project_with_design, :repository)
end
it "does not contain repositories and uploads" do
@@ -660,7 +658,7 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
before do
stub_env('SKIP', 'tar')
- create(:project, :repository)
+ create(:project_with_design, :repository)
end
it 'created files with backup content and no tar archive' do
diff --git a/spec/tasks/gitlab/ci_secure_files/check_rake_spec.rb b/spec/tasks/gitlab/ci_secure_files/check_rake_spec.rb
index b3bd6be8fde..fc9aae3597e 100644
--- a/spec/tasks/gitlab/ci_secure_files/check_rake_spec.rb
+++ b/spec/tasks/gitlab/ci_secure_files/check_rake_spec.rb
@@ -4,7 +4,7 @@ require 'rake_helper'
RSpec.describe 'gitlab:ci_secure_files', factory_default: :keep, feature_category: :mobile_devops do
describe 'check' do
- let_it_be(:project) { create_default(:project).freeze }
+ let!(:project) { create_default(:project).freeze }
let!(:secure_file) { create(:ci_secure_file) }
before do
diff --git a/spec/tasks/gitlab/ci_secure_files/migrate_rake_spec.rb b/spec/tasks/gitlab/ci_secure_files/migrate_rake_spec.rb
index 37ae0d694eb..f3856969a6e 100644
--- a/spec/tasks/gitlab/ci_secure_files/migrate_rake_spec.rb
+++ b/spec/tasks/gitlab/ci_secure_files/migrate_rake_spec.rb
@@ -3,12 +3,12 @@
require 'rake_helper'
RSpec.describe 'gitlab:ci_secure_files', feature_category: :mobile_devops do
- let_it_be(:local_file) { create(:ci_secure_file) }
+ let!(:local_file) { create(:ci_secure_file) }
let(:logger) { instance_double(Logger) }
let(:helper) { double }
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/ci_secure_files/migrate'
end
diff --git a/spec/tasks/gitlab/container_registry_rake_spec.rb b/spec/tasks/gitlab/container_registry_rake_spec.rb
index f4bd8560cd0..d0c728bf36d 100644
--- a/spec/tasks/gitlab/container_registry_rake_spec.rb
+++ b/spec/tasks/gitlab/container_registry_rake_spec.rb
@@ -3,9 +3,9 @@
require 'rake_helper'
RSpec.describe 'gitlab:container_registry namespace rake tasks', :silence_stdout do
- let_it_be(:api_url) { 'http://registry.gitlab' }
+ let(:api_url) { 'http://registry.gitlab' }
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/container_registry'
end
diff --git a/spec/tasks/gitlab/db/cells/bump_cell_sequences_rake_spec.rb b/spec/tasks/gitlab/db/cells/bump_cell_sequences_rake_spec.rb
index a5dd7c0ff09..a1725d6fed7 100644
--- a/spec/tasks/gitlab/db/cells/bump_cell_sequences_rake_spec.rb
+++ b/spec/tasks/gitlab/db/cells/bump_cell_sequences_rake_spec.rb
@@ -4,7 +4,7 @@ require 'rake_helper'
RSpec.describe 'gitlab:db:cells:bump_cell_sequences', :silence_stdout,
:suppress_gitlab_schemas_validate_connection, feature_category: :cell, query_analyzers: false do
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/db/cells/bump_cell_sequences'
# empty task as env is already loaded
diff --git a/spec/tasks/gitlab/db/decomposition/connection_status_rake_spec.rb b/spec/tasks/gitlab/db/decomposition/connection_status_rake_spec.rb
index 5116ee5663e..352e3d944fc 100644
--- a/spec/tasks/gitlab/db/decomposition/connection_status_rake_spec.rb
+++ b/spec/tasks/gitlab/db/decomposition/connection_status_rake_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe 'gitlab:db:decomposition:connection_status', feature_category: :c
subject { run_rake_task('gitlab:db:decomposition:connection_status') }
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/db/decomposition/connection_status'
end
diff --git a/spec/tasks/gitlab/db/decomposition/rollback/bump_ci_sequences_rake_spec.rb b/spec/tasks/gitlab/db/decomposition/rollback/bump_ci_sequences_rake_spec.rb
index f923d09bdaa..3d4b977644f 100644
--- a/spec/tasks/gitlab/db/decomposition/rollback/bump_ci_sequences_rake_spec.rb
+++ b/spec/tasks/gitlab/db/decomposition/rollback/bump_ci_sequences_rake_spec.rb
@@ -4,7 +4,7 @@ require 'rake_helper'
RSpec.describe 'gitlab:db:decomposition:rollback:bump_ci_sequences', :silence_stdout,
:suppress_gitlab_schemas_validate_connection, feature_category: :cell, query_analyzers: false do
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/db/decomposition/rollback/bump_ci_sequences'
# empty task as env is already loaded
diff --git a/spec/tasks/gitlab/db/lock_writes_rake_spec.rb b/spec/tasks/gitlab/db/lock_writes_rake_spec.rb
index 069f5dc7d84..5baf13b9847 100644
--- a/spec/tasks/gitlab/db/lock_writes_rake_spec.rb
+++ b/spec/tasks/gitlab/db/lock_writes_rake_spec.rb
@@ -3,7 +3,7 @@
require 'rake_helper'
RSpec.describe 'gitlab:db:lock_writes', :reestablished_active_record_base, feature_category: :cell do
- before_all do
+ before(:all) do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/seed_fu'
Rake.application.rake_require 'tasks/gitlab/db/validate_config'
diff --git a/spec/tasks/gitlab/db/migration_fix_15_11_rake_spec.rb b/spec/tasks/gitlab/db/migration_fix_15_11_rake_spec.rb
index 41d77d6efc7..9a101921b68 100644
--- a/spec/tasks/gitlab/db/migration_fix_15_11_rake_spec.rb
+++ b/spec/tasks/gitlab/db/migration_fix_15_11_rake_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'migration_fix_15_11', :reestablished_active_record_base, feature
let(:target_init_schema) { '20220314184009' }
let(:earlier_init_schema) { '20210101010101' }
- before_all do
+ before(:all) do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/gitlab/db/migration_fix_15_11'
diff --git a/spec/tasks/gitlab/db/truncate_legacy_tables_rake_spec.rb b/spec/tasks/gitlab/db/truncate_legacy_tables_rake_spec.rb
index 78d2bcba8a2..518acfc5d81 100644
--- a/spec/tasks/gitlab/db/truncate_legacy_tables_rake_spec.rb
+++ b/spec/tasks/gitlab/db/truncate_legacy_tables_rake_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'gitlab:db:truncate_legacy_tables', :silence_stdout, :reestablish
let(:test_gitlab_main_table) { '_test_gitlab_main_table' }
let(:test_gitlab_ci_table) { '_test_gitlab_ci_table' }
- before_all do
+ before(:all) do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/seed_fu'
Rake.application.rake_require 'tasks/gitlab/db/validate_config'
diff --git a/spec/tasks/gitlab/db/validate_config_rake_spec.rb b/spec/tasks/gitlab/db/validate_config_rake_spec.rb
index e2e1cf249f0..e58667578b2 100644
--- a/spec/tasks/gitlab/db/validate_config_rake_spec.rb
+++ b/spec/tasks/gitlab/db/validate_config_rake_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'gitlab:db:validate_config', :silence_stdout, :suppress_gitlab_sc
# which would not be cleaned either by `DbCleaner`
self.use_transactional_tests = false
- before_all do
+ before(:all) do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/seed_fu'
Rake.application.rake_require 'tasks/gitlab/db/validate_config'
diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb
index 344429dc6ec..c35c162c99a 100644
--- a/spec/tasks/gitlab/db_rake_spec.rb
+++ b/spec/tasks/gitlab/db_rake_spec.rb
@@ -1,10 +1,9 @@
# frozen_string_literal: true
-require 'spec_helper'
-require 'rake'
+require 'rake_helper'
RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_category: :database do
- before(:all) do # rubocop:disable RSpec/BeforeAll
+ before(:all) do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/seed_fu'
Rake.application.rake_require 'tasks/gitlab/db'
@@ -18,6 +17,7 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
allow(Rake::Task['db:migrate']).to receive(:invoke).and_return(true)
allow(Rake::Task['db:schema:load']).to receive(:invoke).and_return(true)
allow(Rake::Task['db:seed_fu']).to receive(:invoke).and_return(true)
+ stub_feature_flags(disallow_database_ddl_feature_flags: false)
end
describe 'mark_migration_complete' do
@@ -551,9 +551,9 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
end
describe 'clean_structure_sql' do
- let_it_be(:clean_rake_task) { 'gitlab:db:clean_structure_sql' }
- let_it_be(:test_task_name) { 'gitlab:db:_test_multiple_structure_cleans' }
- let_it_be(:input) { 'this is structure data' }
+ let(:clean_rake_task) { 'gitlab:db:clean_structure_sql' }
+ let(:test_task_name) { 'gitlab:db:_test_multiple_structure_cleans' }
+ let(:input) { 'this is structure data' }
let(:output) { StringIO.new }
@@ -882,6 +882,16 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
end
end
+ context 'when database ddl feature flag is enabled' do
+ it 'is a no-op' do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+
+ expect(Gitlab::Database::AsyncIndexes).not_to receive(:execute_pending_actions!)
+
+ expect { run_rake_task('gitlab:db:execute_async_index_operations:main') }.to raise_error(SystemExit)
+ end
+ end
+
context 'with geo configured' do
before do
skip_unless_geo_configured
@@ -956,6 +966,16 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
end
end
+ context 'when database ddl feature flag is enabled' do
+ it 'is a no-op' do
+ stub_feature_flags(disallow_database_ddl_feature_flags: true)
+
+ expect(Gitlab::Database::AsyncConstraints).not_to receive(:validate_pending_entries!)
+
+ expect { run_rake_task('gitlab:db:validate_async_constraints:main') }.to raise_error(SystemExit)
+ end
+ end
+
context 'with geo configured' do
before do
skip_unless_geo_configured
diff --git a/spec/tasks/gitlab/dependency_proxy/migrate_rake_spec.rb b/spec/tasks/gitlab/dependency_proxy/migrate_rake_spec.rb
index e1504a8aaf5..0bda879bd7c 100644
--- a/spec/tasks/gitlab/dependency_proxy/migrate_rake_spec.rb
+++ b/spec/tasks/gitlab/dependency_proxy/migrate_rake_spec.rb
@@ -3,7 +3,7 @@
require 'rake_helper'
RSpec.describe 'gitlab:dependency_proxy namespace rake task', :silence_stdout do
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/dependency_proxy/migrate'
end
diff --git a/spec/tasks/gitlab/generate_sample_prometheus_data_rake_spec.rb b/spec/tasks/gitlab/generate_sample_prometheus_data_rake_spec.rb
deleted file mode 100644
index 67bf512c6da..00000000000
--- a/spec/tasks/gitlab/generate_sample_prometheus_data_rake_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-require 'rake_helper'
-
-RSpec.describe 'gitlab:generate_sample_prometheus_data rake task', :silence_stdout do
- let(:cluster) { create(:cluster, :provided_by_user, :project) }
- let(:environment) { create(:environment, project: cluster.project) }
- let(:sample_query_file) { File.join(Rails.root, Metrics::SampleMetricsService::DIRECTORY, 'test_query_result.yml') }
- let!(:metric) { create(:prometheus_metric, project: cluster.project, identifier: 'test_query_result') }
-
- around do |example|
- example.run
- ensure
- FileUtils.rm(sample_query_file)
- end
-
- it 'creates the file correctly' do
- Rake.application.rake_require 'tasks/gitlab/generate_sample_prometheus_data'
- allow(Environment).to receive(:find).and_return(environment)
- allow(environment).to receive_message_chain(:prometheus_adapter, :prometheus_client, :query_range) { sample_query_result[30] }
- run_rake_task('gitlab:generate_sample_prometheus_data', [environment.id])
-
- expect(File.exist?(sample_query_file)).to be true
-
- query_file_content = YAML.load_file(sample_query_file)
-
- expect(query_file_content).to eq(sample_query_result)
- end
-end
-
-def sample_query_result
- file = File.join(Rails.root, 'spec/fixtures/gitlab/sample_metrics', 'sample_metric_query_result.yml')
- YAML.load_file(File.expand_path(file, __dir__))
-end
diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb
index 7eca2773cf2..5a395c8f6ef 100644
--- a/spec/tasks/gitlab/gitaly_rake_spec.rb
+++ b/spec/tasks/gitlab/gitaly_rake_spec.rb
@@ -3,7 +3,7 @@
require 'rake_helper'
RSpec.describe 'gitlab:gitaly namespace rake task', :silence_stdout do
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/gitaly'
end
diff --git a/spec/tasks/gitlab/lfs/migrate_rake_spec.rb b/spec/tasks/gitlab/lfs/migrate_rake_spec.rb
index 09c95783867..cbc39c6b093 100644
--- a/spec/tasks/gitlab/lfs/migrate_rake_spec.rb
+++ b/spec/tasks/gitlab/lfs/migrate_rake_spec.rb
@@ -3,7 +3,7 @@
require 'rake_helper'
RSpec.describe 'gitlab:lfs namespace rake task', :silence_stdout do
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/lfs/migrate'
end
diff --git a/spec/tasks/gitlab/packages/migrate_rake_spec.rb b/spec/tasks/gitlab/packages/migrate_rake_spec.rb
index be69990a745..cdc817cdf38 100644
--- a/spec/tasks/gitlab/packages/migrate_rake_spec.rb
+++ b/spec/tasks/gitlab/packages/migrate_rake_spec.rb
@@ -3,7 +3,7 @@
require 'rake_helper'
RSpec.describe 'gitlab:packages namespace rake task', :silence_stdout do
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/packages/migrate'
end
diff --git a/spec/tasks/gitlab/password_rake_spec.rb b/spec/tasks/gitlab/password_rake_spec.rb
index 5d5e5af2536..21a6dc102e6 100644
--- a/spec/tasks/gitlab/password_rake_spec.rb
+++ b/spec/tasks/gitlab/password_rake_spec.rb
@@ -3,8 +3,8 @@
require 'rake_helper'
RSpec.describe 'gitlab:password rake tasks', :silence_stdout do
- let_it_be(:user_1) { create(:user, username: 'foobar', password: User.random_password) }
- let_it_be(:password) { User.random_password }
+ let!(:user_1) { create(:user, username: 'foobar', password: User.random_password) }
+ let(:password) { User.random_password }
def stub_username(username)
allow(Gitlab::TaskHelpers).to receive(:prompt).with('Enter username: ').and_return(username)
diff --git a/spec/tasks/gitlab/refresh_project_statistics_build_artifacts_size_rake_spec.rb b/spec/tasks/gitlab/refresh_project_statistics_build_artifacts_size_rake_spec.rb
index f0fc3c501c5..60c0d80223e 100644
--- a/spec/tasks/gitlab/refresh_project_statistics_build_artifacts_size_rake_spec.rb
+++ b/spec/tasks/gitlab/refresh_project_statistics_build_artifacts_size_rake_spec.rb
@@ -6,9 +6,9 @@ RSpec.describe 'gitlab:refresh_project_statistics_build_artifacts_size rake task
let(:rake_task) { 'gitlab:refresh_project_statistics_build_artifacts_size' }
describe 'enqueuing build artifacts size statistics refresh for given list of project IDs' do
- let_it_be(:project_1) { create(:project) }
- let_it_be(:project_2) { create(:project) }
- let_it_be(:project_3) { create(:project) }
+ let!(:project_1) { create(:project) }
+ let!(:project_2) { create(:project) }
+ let!(:project_3) { create(:project) }
let(:csv_body) do
<<~BODY
diff --git a/spec/tasks/gitlab/snippets_rake_spec.rb b/spec/tasks/gitlab/snippets_rake_spec.rb
index f0ba5ac2d92..231c2dae006 100644
--- a/spec/tasks/gitlab/snippets_rake_spec.rb
+++ b/spec/tasks/gitlab/snippets_rake_spec.rb
@@ -3,13 +3,13 @@
require 'rake_helper'
RSpec.describe 'gitlab:snippets namespace rake task', :silence_stdout do
- let_it_be(:user) { create(:user) }
- let_it_be(:migrated) { create(:personal_snippet, :repository, author: user) }
+ let!(:user) { create(:user) }
+ let!(:migrated) { create(:personal_snippet, :repository, author: user) }
let(:non_migrated) { create_list(:personal_snippet, 3, author: user) }
let(:non_migrated_ids) { non_migrated.pluck(:id) }
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/snippets'
end
diff --git a/spec/tasks/gitlab/terraform/migrate_rake_spec.rb b/spec/tasks/gitlab/terraform/migrate_rake_spec.rb
index 0547d351065..3797c01a9cb 100644
--- a/spec/tasks/gitlab/terraform/migrate_rake_spec.rb
+++ b/spec/tasks/gitlab/terraform/migrate_rake_spec.rb
@@ -3,12 +3,12 @@
require 'rake_helper'
RSpec.describe 'gitlab:terraform_states', :silence_stdout do
- let_it_be(:version) { create(:terraform_state_version) }
+ let!(:version) { create(:terraform_state_version) }
let(:logger) { instance_double(Logger) }
let(:helper) { double }
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/terraform/migrate'
end
diff --git a/spec/tasks/gitlab/web_hook_rake_spec.rb b/spec/tasks/gitlab/web_hook_rake_spec.rb
index cb6a6e72ab1..6ad65f55142 100644
--- a/spec/tasks/gitlab/web_hook_rake_spec.rb
+++ b/spec/tasks/gitlab/web_hook_rake_spec.rb
@@ -3,10 +3,10 @@
require 'rake_helper'
RSpec.describe 'gitlab:web_hook namespace rake tasks', :silence_stdout do
- let_it_be(:group, refind: true) { create(:group) }
- let_it_be(:project1, reload: true) { create(:project, namespace: group) }
- let_it_be(:project2, reload: true) { create(:project, namespace: group) }
- let_it_be(:other_group_project, reload: true) { create(:project) }
+ let!(:group) { create(:group) }
+ let!(:project1) { create(:project, namespace: group) }
+ let!(:project2) { create(:project, namespace: group) }
+ let!(:other_group_project) { create(:project) }
let(:url) { 'http://example.com' }
let(:hook_urls) { (project1.hooks + project2.hooks).map(&:url) }
diff --git a/spec/tasks/gitlab/workhorse_rake_spec.rb b/spec/tasks/gitlab/workhorse_rake_spec.rb
index 17f3133ecdc..e87bef9f01f 100644
--- a/spec/tasks/gitlab/workhorse_rake_spec.rb
+++ b/spec/tasks/gitlab/workhorse_rake_spec.rb
@@ -3,7 +3,7 @@
require 'rake_helper'
RSpec.describe 'gitlab:workhorse namespace rake task', :silence_stdout, feature_category: :source_code_management do
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/workhorse'
end
diff --git a/spec/tasks/gitlab/x509/update_rake_spec.rb b/spec/tasks/gitlab/x509/update_rake_spec.rb
index abf8316d978..118b0b2b960 100644
--- a/spec/tasks/gitlab/x509/update_rake_spec.rb
+++ b/spec/tasks/gitlab/x509/update_rake_spec.rb
@@ -3,7 +3,7 @@
require 'rake_helper'
RSpec.describe 'gitlab:x509 namespace rake task', :silence_stdout do
- before_all do
+ before(:all) do
Rake.application.rake_require 'tasks/gitlab/x509/update'
end
diff --git a/spec/tasks/migrate/schema_check_rake_spec.rb b/spec/tasks/migrate/schema_check_rake_spec.rb
index 5afad752982..4d0f59295a6 100644
--- a/spec/tasks/migrate/schema_check_rake_spec.rb
+++ b/spec/tasks/migrate/schema_check_rake_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'schema_version_check rake task', :silence_stdout do
include StubENV
let(:valid_schema_version) { 20211004170422 }
- before_all do
+ before(:all) do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/migrate/schema_check'
diff --git a/spec/tooling/danger/clickhouse_spec.rb b/spec/tooling/danger/clickhouse_spec.rb
new file mode 100644
index 00000000000..ad2f0b4a827
--- /dev/null
+++ b/spec/tooling/danger/clickhouse_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'rspec-parameterized'
+require 'gitlab-dangerfiles'
+require 'danger'
+require 'danger/plugins/internal/helper'
+require 'gitlab/dangerfiles/spec_helper'
+
+require_relative '../../../tooling/danger/clickhouse'
+
+RSpec.describe Tooling::Danger::Clickhouse, feature_category: :tooling do
+ include_context "with dangerfile"
+
+ let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
+ let(:migration_files) do
+ %w[
+ db/click_house/20220901010203_add_widgets_table.rb
+ db/click_house/20220909010203_add_properties_column.rb
+ db/click_house/20220910010203_drop_tools_table.rb
+ db/click_house/20220912010203_add_index_to_widgets_table.rb
+ ]
+ end
+
+ subject(:clickhouse) { fake_danger.new(helper: fake_helper) }
+
+ describe '#changes' do
+ using RSpec::Parameterized::TableSyntax
+
+ where do
+ {
+ 'with click_house gem changes' => {
+ modified_files: %w[gems/click_house-client/lib/click_house/client.rb],
+ changes_by_category: {
+ database: [],
+ clickhouse: %w[gems/click_house-client/lib/click_house/client.rb]
+ },
+ impacted_files: %w[gems/click_house-client/lib/click_house/client.rb]
+ },
+ 'with clickhouse data changes' => {
+ modified_files: %w[db/clickhouse/20230720114001_add_magic_table_migration.rb],
+ changes_by_category: {
+ database: [],
+ clickhouse: %w[db/clickhouse/20230720114001_add_magic_table_migration.rb]
+ },
+ impacted_files: %w[db/clickhouse/20230720114001_add_magic_table_migration.rb]
+ },
+ 'with clickhouse app changes' => {
+ modified_files: %w[lib/click_house/query_builder.rb],
+ changes_by_category: {
+ database: [],
+ clickhouse: %w[lib/click_house/query_builder.rb]
+ },
+ impacted_files: %w[lib/click_house/query_builder.rb]
+ }
+ }
+ end
+
+ with_them do
+ before do
+ allow(fake_helper).to receive(:modified_files).and_return(modified_files)
+ allow(fake_helper).to receive(:all_changed_files).and_return(modified_files)
+ allow(fake_helper).to receive(:changes_by_category).and_return(changes_by_category)
+ end
+
+ it 'returns only clickhouse changes' do
+ expect(clickhouse.changes).to match impacted_files
+ end
+ end
+ end
+end
diff --git a/spec/tooling/danger/ignored_model_columns_spec.rb b/spec/tooling/danger/ignored_model_columns_spec.rb
new file mode 100644
index 00000000000..737b6cce077
--- /dev/null
+++ b/spec/tooling/danger/ignored_model_columns_spec.rb
@@ -0,0 +1,145 @@
+# frozen_string_literal: true
+
+require 'danger'
+require 'gitlab/dangerfiles/spec_helper'
+
+require_relative '../../../tooling/danger/ignored_model_columns'
+require_relative '../../../tooling/danger/project_helper'
+
+RSpec.describe Tooling::Danger::IgnoredModelColumns, feature_category: :tooling do
+ subject(:ignored_model_columns) { fake_danger.new(helper: fake_helper) }
+
+ let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
+ let(:fake_project_helper) { instance_double(Tooling::Danger::ProjectHelper) }
+ let(:comment) { described_class::COMMENT.chomp }
+ let(:file_diff) do
+ File.read(File.expand_path("../fixtures/#{fixture}", __dir__)).split("\n")
+ end
+
+ include_context "with dangerfile"
+
+ describe '#add_comment_for_ignored_model_columns' do
+ let(:file_lines) { file_diff.map { |line| line.delete_prefix('+').delete_prefix('-') } }
+
+ before do
+ allow(ignored_model_columns).to receive(:project_helper).and_return(fake_project_helper)
+ allow(ignored_model_columns.project_helper).to receive(:file_lines).and_return(file_lines)
+ allow(ignored_model_columns.helper).to receive(:all_changed_files).and_return([filename])
+ allow(ignored_model_columns.helper).to receive(:changed_lines).with(filename).and_return(file_diff)
+ end
+
+ context 'when table column is renamed in a regular migration' do
+ let(:filename) { 'db/migrate/rename_my_column_migration.rb' }
+ let(:fixture) { 'rename_column_migration.txt' }
+ let(:matching_lines) { [7, 11, 15, 19, 23, 27, 31, 35, 39] }
+
+ it 'adds comment at the correct line' do
+ matching_lines.each do |line_number|
+ expect(ignored_model_columns).to receive(:markdown).with("\n#{comment}", file: filename, line: line_number)
+ end
+
+ ignored_model_columns.add_comment_for_ignored_model_columns
+ end
+ end
+
+ context 'when table column is renamed in a post migration' do
+ let(:filename) { 'db/post_migrate/remove_column_migration.rb' }
+ let(:fixture) { 'remove_column_migration.txt' }
+ let(:matching_lines) { [7, 8, 16, 24, 32, 40, 48, 56, 64, 72] }
+
+ it 'adds comment at the correct line' do
+ matching_lines.each do |line_number|
+ expect(ignored_model_columns).to receive(:markdown).with("\n#{comment}", file: filename, line: line_number)
+ end
+
+ ignored_model_columns.add_comment_for_ignored_model_columns
+ end
+ end
+
+ context 'when table cleanup is performed in a post migration' do
+ let(:filename) { 'db/post_migrate/cleanup_conversion_big_int_migration.rb' }
+ let(:fixture) { 'cleanup_conversion_migration.txt' }
+ let(:matching_lines) { [7, 11, 15, 19, 23, 27, 31, 35, 39] }
+
+ it 'adds comment at the correct line' do
+ matching_lines.each do |line_number|
+ expect(ignored_model_columns).to receive(:markdown).with("\n#{comment}", file: filename, line: line_number)
+ end
+
+ ignored_model_columns.add_comment_for_ignored_model_columns
+ end
+ end
+
+ context 'when a regular migration does not rename table column' do
+ let(:filename) { 'db/migrate/my_migration.rb' }
+ let(:file_diff) do
+ [
+ "+ undo_cleanup_concurrent_column_rename(:my_table, :old_column, :new_column)",
+ "- cleanup_concurrent_column_rename(:my_table, :new_column, :old_column)"
+ ]
+ end
+
+ let(:file_lines) do
+ [
+ ' def up',
+ ' undo_cleanup_concurrent_column_rename(:my_table, :old_column, :new_column)',
+ ' end'
+ ]
+ end
+
+ it 'does not add comment' do
+ expect(ignored_model_columns).not_to receive(:markdown)
+
+ ignored_model_columns.add_comment_for_ignored_model_columns
+ end
+ end
+
+ context 'when a post migration does not remove table column' do
+ let(:filename) { 'db/migrate/my_migration.rb' }
+ let(:file_diff) do
+ [
+ "+ add_column(:my_table, :my_column, :type)",
+ "- remove_column(:my_table, :my_column)"
+ ]
+ end
+
+ let(:file_lines) do
+ [
+ ' def up',
+ ' add_column(:my_table, :my_column, :type)',
+ ' end'
+ ]
+ end
+
+ it 'does not add comment' do
+ expect(ignored_model_columns).not_to receive(:markdown)
+
+ ignored_model_columns.add_comment_for_ignored_model_columns
+ end
+ end
+
+ context 'when a post migration does not convert table column' do
+ let(:filename) { 'db/migrate/my_migration.rb' }
+ let(:file_diff) do
+ [
+ "+ restore_conversion_of_integer_to_bigint(TABLE, COLUMNS)",
+ "- cleanup_conversion_of_integer_to_bigint(TABLE, COLUMNS)"
+ ]
+ end
+
+ let(:file_lines) do
+ [
+ ' def up',
+ ' cleanup_conversion_of_integer_to_bigint(TABLE, COLUMNS)',
+ ' end'
+ ]
+ end
+
+ it 'does not add comment' do
+ expect(ignored_model_columns).not_to receive(:markdown)
+
+ ignored_model_columns.add_comment_for_ignored_model_columns
+ end
+ end
+ end
+end
diff --git a/spec/tooling/fixtures/cleanup_conversion_migration.txt b/spec/tooling/fixtures/cleanup_conversion_migration.txt
new file mode 100644
index 00000000000..14a7937b469
--- /dev/null
+++ b/spec/tooling/fixtures/cleanup_conversion_migration.txt
@@ -0,0 +1,44 @@
++# frozen_string_literal: true
++
++class TestMigration < Gitlab::Database::Migration[2.1]
++ disable_ddl_transaction!
++
++ def up
++ cleanup_conversion_of_integer_to_bigint :my_table, :my_column
++ end
++
++ def up
++ cleanup_conversion_of_integer_to_bigint 'my_table', 'my_column'
++ end
++
++ def up
++ cleanup_conversion_of_integer_to_bigint "my_table", "my_column", "new_column"
++ end
++
++ def up
++ cleanup_conversion_of_integer_to_bigint TABLE_NAME, MY_COLUMN
++ end
++
++ def up
++ cleanup_conversion_of_integer_to_bigint(:my_table, :my_column)
++ end
++
++ def up
++ cleanup_conversion_of_integer_to_bigint('my_table', 'my_column')
++ end
++
++ def up
++ cleanup_conversion_of_integer_to_bigint("my_table", "my_column")
++ end
++
++ def up
++ cleanup_conversion_of_integer_to_bigint(TABLE_NAME, MY_COLUMN)
++ end
++
++ def up
++ cleanup_conversion_of_integer_to_bigint(
++ :my_table,
++ :my_column
++ )
++ end
++end
diff --git a/spec/tooling/fixtures/remove_column_migration.txt b/spec/tooling/fixtures/remove_column_migration.txt
new file mode 100644
index 00000000000..885f0060d92
--- /dev/null
+++ b/spec/tooling/fixtures/remove_column_migration.txt
@@ -0,0 +1,84 @@
++# frozen_string_literal: true
++
++class TestMigration < Gitlab::Database::Migration[2.1]
++ disable_ddl_transaction!
++
++ def up
++ remove_column :my_table, :my_column
++ remove_column :my_other_table, :my_column
++ end
++
++ def down
++ remove_column :my_table, :my_column
++ end
++
++ def up
++ remove_column 'my_table', 'my_column'
++ end
++
++ def down
++ remove_column 'my_table', 'my_column'
++ end
++
++ def up
++ remove_column "my_table", "my_column", "new_column"
++ end
++
++ def down
++ remove_column "my_table", "my_column", "new_column"
++ end
++
++ def up
++ remove_column TABLE_NAME, MY_COLUMN
++ end
++
++ def down
++ remove_column TABLE_NAME, MY_COLUMN
++ end
++
++ def up
++ remove_column(:my_table, :my_column)
++ end
++
++ def down
++ remove_column(:my_table, :my_column)
++ end
++
++ def up
++ remove_column('my_table', 'my_column')
++ end
++
++ def down
++ remove_column('my_table', 'my_column')
++ end
++
++ def up
++ remove_column("my_table", "my_column")
++ end
++
++ def down
++ remove_column("my_table", "my_column")
++ end
++
++ def up
++ remove_column(TABLE_NAME, MY_COLUMN)
++ end
++
++ def down
++ remove_column(TABLE_NAME, MY_COLUMN)
++ end
++
++ def up
++ remove_column(
++ :my_table,
++ :my_column
++ )
++ end
++
++ def down
++ remove_column(
++ :my_table,
++ :my_column
++ )
++ end
++end
diff --git a/spec/tooling/fixtures/rename_column_migration.txt b/spec/tooling/fixtures/rename_column_migration.txt
new file mode 100644
index 00000000000..e79029219a5
--- /dev/null
+++ b/spec/tooling/fixtures/rename_column_migration.txt
@@ -0,0 +1,45 @@
++# frozen_string_literal: true
++
++class TestMigration < Gitlab::Database::Migration[2.1]
++ disable_ddl_transaction!
++
++ def up
++ cleanup_concurrent_column_rename :my_table, :old_column, :new_column
++ end
++
++ def up
++ cleanup_concurrent_column_rename 'my_table', 'old_column', 'new_column'
++ end
++
++ def up
++ cleanup_concurrent_column_rename "my_table", "old_column", "new_column"
++ end
++
++ def up
++ cleanup_concurrent_column_rename TABLE_NAME, OLD_COLUMN_NAME, NEW_COLUMN_NAME
++ end
++
++ def up
++ cleanup_concurrent_column_rename(:my_table, :old_column, :new_column)
++ end
++
++ def up
++ cleanup_concurrent_column_rename('my_table', 'old_column', 'new_column')
++ end
++
++ def up
++ cleanup_concurrent_column_rename("my_table", "old_column", "new_column")
++ end
++
++ def up
++ cleanup_concurrent_column_rename(TABLE_NAME, OLD_COLUMN_NAME, NEW_COLUMN_NAME)
++ end
++
++ def up
++ cleanup_concurrent_column_rename(
++ :my_table,
++ :old_column,
++ :new_column
++ )
++ end
++end
diff --git a/spec/uploaders/packages/nuget/symbol_uploader_spec.rb b/spec/uploaders/packages/nuget/symbol_uploader_spec.rb
new file mode 100644
index 00000000000..bdcb5245c1c
--- /dev/null
+++ b/spec/uploaders/packages/nuget/symbol_uploader_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Nuget::SymbolUploader, feature_category: :package_registry do
+ let(:object_storage_key) { 'object/storage/key' }
+ let(:symbol) { build_stubbed(:nuget_symbol, object_storage_key: object_storage_key) }
+
+ subject { described_class.new(symbol, :file) }
+
+ describe '#store_dir' do
+ it 'uses the object_storage_key' do
+ expect(subject.store_dir).to eq(object_storage_key)
+ end
+
+ context 'without the object_storage_key' do
+ let(:object_storage_key) { nil }
+
+ it 'raises the error' do
+ expect { subject.store_dir }
+ .to raise_error(
+ described_class::ObjectNotReadyError,
+ 'Packages::Nuget::Symbol model not ready'
+ )
+ end
+ end
+ end
+end
diff --git a/spec/views/admin/application_settings/general.html.haml_spec.rb b/spec/views/admin/application_settings/general.html.haml_spec.rb
index 3b3a8a675a0..99564003d59 100644
--- a/spec/views/admin/application_settings/general.html.haml_spec.rb
+++ b/spec/views/admin/application_settings/general.html.haml_spec.rb
@@ -125,7 +125,6 @@ RSpec.describe 'admin/application_settings/general.html.haml' do
shared_examples 'does not render the form' do
it 'does not render the form' do
expect(rendered).not_to have_field('application_setting_instance_level_code_suggestions_enabled')
- expect(rendered).not_to have_field('application_setting_ai_access_token')
end
end
diff --git a/spec/views/admin/identities/index.html.haml_spec.rb b/spec/views/admin/identities/index.html.haml_spec.rb
index 3e8def003ae..a4f6579f5ef 100644
--- a/spec/views/admin/identities/index.html.haml_spec.rb
+++ b/spec/views/admin/identities/index.html.haml_spec.rb
@@ -20,18 +20,19 @@ RSpec.describe 'admin/identities/index.html.haml', :aggregate_failures do
it 'shows table headers' do
render
- expect(rendered).to include('<th class="gl-border-t-0!">').exactly(5)
+ expect(rendered).to include('<th class="gl-border-t-0!">').exactly(6)
expect(rendered).to include(_('Provider'))
expect(rendered).to include(s_('Identity|Provider ID'))
expect(rendered).to include(_('Group'))
expect(rendered).to include(_('Identifier'))
+ expect(rendered).to include(_('Active'))
expect(rendered).to include(_('Actions'))
end
it 'shows information text' do
render
- expect(rendered).to include('<td colspan="5">').exactly(1)
+ expect(rendered).to include('<td colspan="6">').exactly(1)
expect(rendered).to include(_('This user has no identities'))
end
end
@@ -41,10 +42,10 @@ RSpec.describe 'admin/identities/index.html.haml', :aggregate_failures do
assign(:identities, ldap_user.identities)
end
- it 'shows exactly 5 columns' do
+ it 'shows exactly 6 columns' do
render
- expect(rendered).to include('</td>').exactly(5)
+ expect(rendered).to include('</td>').exactly(6)
end
it 'shows identity without provider ID or group' do
diff --git a/spec/views/devise/shared/_signin_box.html.haml_spec.rb b/spec/views/devise/shared/_signin_box.html.haml_spec.rb
index e2aa0bb9870..24937cfdd4a 100644
--- a/spec/views/devise/shared/_signin_box.html.haml_spec.rb
+++ b/spec/views/devise/shared/_signin_box.html.haml_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe 'devise/shared/_signin_box' do
it 'renders user_login label' do
render
- expect(rendered).to have_content(_('Username or email'))
+ expect(rendered).to have_content(_('Username or primary email'))
end
end
diff --git a/spec/views/devise/shared/_signup_omniauth_provider_list_spec.rb b/spec/views/devise/shared/_signup_omniauth_provider_list_spec.rb
new file mode 100644
index 00000000000..cc3ee52e73b
--- /dev/null
+++ b/spec/views/devise/shared/_signup_omniauth_provider_list_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'devise/shared/_signup_omniauth_provider_list', feature_category: :system_access do
+ let_it_be(:provider_label) { :github }.freeze
+ let_it_be(:tracking_label) { 'free_registration' }.freeze
+ let_it_be(:tracking_action) { "#{provider_label}_sso" }.freeze
+
+ subject { rendered }
+
+ before do
+ allow(view).to receive(:providers).and_return([provider_label])
+ allow(view).to receive(:tracking_label).and_return(tracking_label)
+ allow(view).to receive(:glm_tracking_params).and_return({})
+ end
+
+ shared_examples 'sso buttons have snowplow tracking' do
+ it 'contains tracking attributes' do
+ css = "[data-track-action='#{tracking_action}']"
+ css += "[data-track-label='#{tracking_label}']"
+
+ expect(rendered).to have_css(css)
+ end
+ end
+
+ context 'when feature flag is true' do
+ before do
+ stub_feature_flags(restyle_login_page: true)
+
+ render
+ end
+
+ it { is_expected.to have_content(_("Register with:")) }
+
+ it_behaves_like 'sso buttons have snowplow tracking'
+ end
+
+ context 'when feature flag is false' do
+ before do
+ stub_feature_flags(restyle_login_page: false)
+
+ render
+ end
+
+ it { is_expected.to have_content(_("Create an account using:")) }
+
+ it_behaves_like 'sso buttons have snowplow tracking'
+ end
+end
diff --git a/spec/views/events/event/_push.html.haml_spec.rb b/spec/views/events/event/_push.html.haml_spec.rb
index f4d3258ff67..fe4357d3ad5 100644
--- a/spec/views/events/event/_push.html.haml_spec.rb
+++ b/spec/views/events/event/_push.html.haml_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'events/event/_push.html.haml' do
let(:event) { build_stubbed(:push_event) }
+ let(:event_presenter) { event.present }
context 'with a branch' do
let(:payload) { build_stubbed(:push_event_payload, event: event) }
@@ -16,14 +17,14 @@ RSpec.describe 'events/event/_push.html.haml' do
allow(event.project.repository).to receive(:branch_exists?).with(event.ref_name).and_return(true)
link = project_commits_path(event.project, event.ref_name)
- render partial: 'events/event/push', locals: { event: event }
+ render partial: 'events/event/push', locals: { event: event_presenter }
expect(rendered).to have_link(event.ref_name, href: link)
end
context 'that has been deleted' do
it 'does not link to the branch' do
- render partial: 'events/event/push', locals: { event: event }
+ render partial: 'events/event/push', locals: { event: event_presenter }
expect(rendered).not_to have_link(event.ref_name)
end
@@ -40,7 +41,7 @@ RSpec.describe 'events/event/_push.html.haml' do
end
it 'includes the count in the text' do
- render partial: 'events/event/push', locals: { event: event }
+ render partial: 'events/event/push', locals: { event: event_presenter }
expect(rendered).to include('4 branches')
end
@@ -58,14 +59,14 @@ RSpec.describe 'events/event/_push.html.haml' do
allow(event.project.repository).to receive(:tag_exists?).with(event.ref_name).and_return(true)
link = project_commits_path(event.project, event.ref_name)
- render partial: 'events/event/push', locals: { event: event }
+ render partial: 'events/event/push', locals: { event: event_presenter }
expect(rendered).to have_link(event.ref_name, href: link)
end
context 'that has been deleted' do
it 'does not link to the tag' do
- render partial: 'events/event/push', locals: { event: event }
+ render partial: 'events/event/push', locals: { event: event_presenter }
expect(rendered).not_to have_link(event.ref_name)
end
@@ -82,7 +83,7 @@ RSpec.describe 'events/event/_push.html.haml' do
end
it 'includes the count in the text' do
- render partial: 'events/event/push', locals: { event: event }
+ render partial: 'events/event/push', locals: { event: event_presenter }
expect(rendered).to include('4 tags')
end
diff --git a/spec/views/layouts/_page.html.haml_spec.rb b/spec/views/layouts/_page.html.haml_spec.rb
new file mode 100644
index 00000000000..da9d086efe0
--- /dev/null
+++ b/spec/views/layouts/_page.html.haml_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'layouts/_page', feature_category: :geo_replication do
+ let_it_be(:user) { build_stubbed(:user) }
+
+ describe '_silent_mode_banner' do
+ before do
+ allow(view).to receive(:current_user).and_return(user)
+ allow(view).to receive(:current_user_mode).and_return(Gitlab::Auth::CurrentUserMode.new(user))
+ end
+
+ describe 'when ::Gitlab::SilentMode.enabled? is true' do
+ before do
+ allow(::Gitlab::SilentMode).to receive(:enabled?).and_return(true)
+ end
+
+ it 'renders silent mode banner' do
+ render
+
+ expect(rendered).to have_text('Silent mode is enabled')
+ end
+ end
+
+ describe 'when ::Gitlab::SilentMode.enabled? is false' do
+ before do
+ allow(::Gitlab::SilentMode).to receive(:enabled?).and_return(false)
+ end
+
+ it 'does not silent mode banner' do
+ render
+
+ expect(rendered).not_to have_text('Silent mode is enabled')
+ end
+ end
+ end
+end
diff --git a/spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb b/spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb
index 89a03d72a90..f81e8c5badf 100644
--- a/spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb
+++ b/spec/views/layouts/header/_super_sidebar_logged_out.html.haml_spec.rb
@@ -19,6 +19,10 @@ RSpec.describe 'layouts/header/_super_sidebar_logged_out', feature_category: :na
expect(rendered).to have_content('Pricing')
expect(rendered).to have_content('Contact Sales')
end
+
+ it 'renders the free trial button' do
+ expect(rendered).to have_content('Get free trial')
+ end
end
context 'on self-managed' do
diff --git a/spec/views/layouts/organization.html.haml_spec.rb b/spec/views/layouts/organization.html.haml_spec.rb
new file mode 100644
index 00000000000..72a4abd288a
--- /dev/null
+++ b/spec/views/layouts/organization.html.haml_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'layouts/organization', feature_category: :cell do
+ let_it_be(:organization) { build_stubbed(:organization) }
+ let_it_be(:current_user) { build_stubbed(:user, :admin) }
+
+ before do
+ allow(view).to receive(:current_user).and_return(current_user)
+ allow(view).to receive(:current_user_mode).and_return(Gitlab::Auth::CurrentUserMode.new(current_user))
+ allow(view).to receive(:users_path).and_return('/root')
+ end
+
+ subject do
+ render
+
+ rendered
+ end
+
+ describe 'navigation' do
+ context 'when action is #index' do
+ before do
+ allow(view).to receive(:params).and_return({ action: 'index' })
+ end
+
+ it 'renders your_work navigation' do
+ subject
+
+ expect(view.instance_variable_get(:@nav)).to eq('your_work')
+ end
+ end
+
+ context 'when action is #new' do
+ before do
+ allow(view).to receive(:params).and_return({ action: 'new' })
+ end
+
+ it 'renders your_work navigation' do
+ subject
+
+ expect(view.instance_variable_get(:@nav)).to eq('your_work')
+ end
+ end
+
+ context 'when action is #show' do
+ before do
+ allow(view).to receive(:params).and_return({ action: 'show' })
+ view.instance_variable_set(:@organization, organization)
+ end
+
+ it 'renders organization navigation' do
+ subject
+
+ expect(view.instance_variable_get(:@nav)).to eq('organization')
+ end
+ end
+ end
+end
diff --git a/spec/views/layouts/snippets.html.haml_spec.rb b/spec/views/layouts/snippets.html.haml_spec.rb
index 1e6963a6526..b7139f84174 100644
--- a/spec/views/layouts/snippets.html.haml_spec.rb
+++ b/spec/views/layouts/snippets.html.haml_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'layouts/snippets', feature_category: :source_code_management do
describe 'sidebar' do
context 'when signed in' do
- let(:user) { build_stubbed(:user) }
+ let(:user) { build_stubbed(:user, :no_super_sidebar) }
it 'renders the "Your work" sidebar' do
render
diff --git a/spec/views/projects/empty.html.haml_spec.rb b/spec/views/projects/empty.html.haml_spec.rb
index 2b19b364365..c478b446864 100644
--- a/spec/views/projects/empty.html.haml_spec.rb
+++ b/spec/views/projects/empty.html.haml_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe 'projects/empty' do
expect(rendered).to have_content('Invite your team')
expect(rendered).to have_content('Add members to this project and start collaborating with your team.')
expect(rendered).to have_selector('.js-invite-members-trigger')
- expect(rendered).to have_selector('[data-trigger-source=project-empty-page]')
+ expect(rendered).to have_selector('[data-trigger-source=project_empty_page]')
end
context 'when user does not have permissions to invite members' do
diff --git a/spec/views/projects/issues/service_desk/_issue.html.haml_spec.rb b/spec/views/projects/issues/service_desk/_issue.html.haml_spec.rb
index ee582ee9927..7f294f12d64 100644
--- a/spec/views/projects/issues/service_desk/_issue.html.haml_spec.rb
+++ b/spec/views/projects/issues/service_desk/_issue.html.haml_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe 'projects/issues/service_desk/_issue.html.haml', feature_category
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) }
+ let_it_be(:issue) { create(:issue, author: Users::Internal.support_bot, service_desk_reply_to: email) }
context 'with anonymous user' do
it 'obfuscates service_desk_reply_to email for anonymous user' do
diff --git a/spec/views/projects/pages/_pages_settings.html.haml_spec.rb b/spec/views/projects/pages/_pages_settings.html.haml_spec.rb
index 4f54ddbdb60..e790305da5d 100644
--- a/spec/views/projects/pages/_pages_settings.html.haml_spec.rb
+++ b/spec/views/projects/pages/_pages_settings.html.haml_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'projects/pages/_pages_settings', feature_category: :pages do
- let_it_be(:project) { build_stubbed(:project, :repository) }
+ let_it_be(:project) { build_stubbed(:project) }
let_it_be(:user) { build_stubbed(:user) }
before do
@@ -18,4 +18,32 @@ RSpec.describe 'projects/pages/_pages_settings', feature_category: :pages do
expect(rendered).to have_content('Use unique domain')
end
end
+
+ context 'for pages multiple versions' do
+ context 'when current user does not have access to pages multiple versions toggle' do
+ it 'shows the multiple versions toggle' do
+ allow(view)
+ .to receive(:can?)
+ .with(user, :pages_multiple_versions, project)
+ .and_return(false)
+
+ render
+
+ expect(rendered).not_to have_content('Use multiple versions')
+ end
+ end
+
+ context 'when current user have access to pages multiple versions toggle' do
+ it 'shows the multiple versions toggle' do
+ allow(view)
+ .to receive(:can?)
+ .with(user, :pages_multiple_versions, project)
+ .and_return(true)
+
+ render
+
+ expect(rendered).to have_content('Use multiple versions')
+ end
+ end
+ end
end
diff --git a/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb b/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb
deleted file mode 100644
index 13ec7207ec9..00000000000
--- a/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'projects/pipeline_schedules/_pipeline_schedule' do
- let(:owner) { create(:user) }
- let(:maintainer) { create(:user) }
- let(:project) { create(:project) }
- let(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) }
-
- before do
- assign(:project, project)
-
- allow(view).to receive(:current_user).and_return(user)
- allow(view).to receive(:pipeline_schedule).and_return(pipeline_schedule)
-
- allow(view).to receive(:can?).and_return(true)
- end
-
- context 'taking ownership of schedule' do
- context 'when non-owner is signed in' do
- let(:user) { maintainer }
-
- before do
- allow(view).to receive(:can?).with(maintainer, :admin_pipeline_schedule, pipeline_schedule).and_return(true)
- end
-
- it 'non-owner can take ownership of pipeline' do
- render
-
- expect(rendered).to have_button('Take ownership')
- end
- end
-
- context 'when owner is signed in' do
- let(:user) { owner }
-
- before do
- allow(view).to receive(:can?).with(owner, :admin_pipeline_schedule, pipeline_schedule).and_return(false)
- end
-
- it 'owner cannot take ownership of pipeline' do
- render
-
- expect(rendered).not_to have_button('Take ownership')
- end
- end
- end
-end
diff --git a/spec/views/registrations/welcome/show.html.haml_spec.rb b/spec/views/registrations/welcome/show.html.haml_spec.rb
index 4188bd7e956..b652defbd1f 100644
--- a/spec/views/registrations/welcome/show.html.haml_spec.rb
+++ b/spec/views/registrations/welcome/show.html.haml_spec.rb
@@ -17,5 +17,4 @@ RSpec.describe 'registrations/welcome/show', feature_category: :onboarding do
it { is_expected.not_to have_selector('label[for="user_setup_for_company"]') }
it { is_expected.to have_button('Get started!') }
- it { is_expected.not_to have_selector('input[name="user[email_opted_in]"]') }
end
diff --git a/spec/workers/bulk_import_worker_spec.rb b/spec/workers/bulk_import_worker_spec.rb
index ec8550bb3bc..c96e5ace124 100644
--- a/spec/workers/bulk_import_worker_spec.rb
+++ b/spec/workers/bulk_import_worker_spec.rb
@@ -137,5 +137,174 @@ RSpec.describe BulkImportWorker, feature_category: :importers do
end
end
end
+
+ context 'when importing a group' do
+ it 'creates trackers for group entity' do
+ bulk_import = create(:bulk_import)
+ entity = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import)
+
+ subject.perform(bulk_import.id)
+
+ expect(entity.trackers.to_a).to include(
+ have_attributes(
+ stage: 0, status_name: :created, relation: BulkImports::Groups::Pipelines::GroupPipeline.to_s
+ ),
+ have_attributes(
+ stage: 1, status_name: :created, relation: BulkImports::Groups::Pipelines::GroupAttributesPipeline.to_s
+ )
+ )
+ end
+ end
+
+ context 'when importing a project' do
+ it 'creates trackers for project entity' do
+ bulk_import = create(:bulk_import)
+ entity = create(:bulk_import_entity, :project_entity, bulk_import: bulk_import)
+
+ subject.perform(bulk_import.id)
+
+ expect(entity.trackers.to_a).to include(
+ have_attributes(
+ stage: 0, status_name: :created, relation: BulkImports::Projects::Pipelines::ProjectPipeline.to_s
+ ),
+ have_attributes(
+ stage: 1, status_name: :created, relation: BulkImports::Projects::Pipelines::RepositoryPipeline.to_s
+ )
+ )
+ end
+ end
+
+ context 'when tracker configuration has a minimum version defined' do
+ before do
+ allow_next_instance_of(BulkImports::Groups::Stage) do |stage|
+ allow(stage).to receive(:config).and_return(
+ {
+ pipeline1: { pipeline: 'PipelineClass1', stage: 0 },
+ pipeline2: { pipeline: 'PipelineClass2', stage: 1, minimum_source_version: '14.10.0' },
+ pipeline3: { pipeline: 'PipelineClass3', stage: 1, minimum_source_version: '15.0.0' },
+ pipeline5: { pipeline: 'PipelineClass4', stage: 1, minimum_source_version: '15.1.0' },
+ pipeline6: { pipeline: 'PipelineClass5', stage: 1, minimum_source_version: '16.0.0' }
+ }
+ )
+ end
+ end
+
+ context 'when the source instance version is older than the tracker mininum version' do
+ let_it_be(:bulk_import) { create(:bulk_import, source_version: '15.0.0') }
+ let_it_be(:entity) { create(:bulk_import_entity, :group_entity, bulk_import: bulk_import) }
+
+ it 'creates trackers as skipped if version requirement does not meet' do
+ subject.perform(bulk_import.id)
+
+ expect(entity.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }).to contain_exactly(
+ [:created, 'PipelineClass1'],
+ [:created, 'PipelineClass2'],
+ [:created, 'PipelineClass3'],
+ [:skipped, 'PipelineClass4'],
+ [:skipped, 'PipelineClass5']
+ )
+ end
+
+ it 'logs an info message for the skipped pipelines' do
+ expect_next_instance_of(Gitlab::Import::Logger) do |logger|
+ expect(logger).to receive(:info).with({
+ message: 'Pipeline skipped as source instance version not compatible with pipeline',
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
+ importer: 'gitlab_migration',
+ pipeline_name: 'PipelineClass4',
+ minimum_source_version: '15.1.0',
+ maximum_source_version: nil,
+ source_version: '15.0.0'
+ })
+
+ expect(logger).to receive(:info).with({
+ message: 'Pipeline skipped as source instance version not compatible with pipeline',
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
+ importer: 'gitlab_migration',
+ pipeline_name: 'PipelineClass5',
+ minimum_source_version: '16.0.0',
+ maximum_source_version: nil,
+ source_version: '15.0.0'
+ })
+ end
+
+ subject.perform(bulk_import.id)
+ end
+ end
+
+ context 'when the source instance version is undefined' do
+ it 'creates trackers as created' do
+ bulk_import = create(:bulk_import, source_version: nil)
+ entity = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import)
+
+ subject.perform(bulk_import.id)
+
+ expect(entity.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }).to contain_exactly(
+ [:created, 'PipelineClass1'],
+ [:created, 'PipelineClass2'],
+ [:created, 'PipelineClass3'],
+ [:created, 'PipelineClass4'],
+ [:created, 'PipelineClass5']
+ )
+ end
+ end
+ end
+
+ context 'when tracker configuration has a maximum version defined' do
+ before do
+ allow_next_instance_of(BulkImports::Groups::Stage) do |stage|
+ allow(stage).to receive(:config).and_return(
+ {
+ pipeline1: { pipeline: 'PipelineClass1', stage: 0 },
+ pipeline2: { pipeline: 'PipelineClass2', stage: 1, maximum_source_version: '14.10.0' },
+ pipeline3: { pipeline: 'PipelineClass3', stage: 1, maximum_source_version: '15.0.0' },
+ pipeline5: { pipeline: 'PipelineClass4', stage: 1, maximum_source_version: '15.1.0' },
+ pipeline6: { pipeline: 'PipelineClass5', stage: 1, maximum_source_version: '16.0.0' }
+ }
+ )
+ end
+ end
+
+ context 'when the source instance version is older than the tracker maximum version' do
+ it 'creates trackers as skipped if version requirement does not meet' do
+ bulk_import = create(:bulk_import, source_version: '15.0.0')
+ entity = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import)
+
+ subject.perform(bulk_import.id)
+
+ expect(entity.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }).to contain_exactly(
+ [:created, 'PipelineClass1'],
+ [:skipped, 'PipelineClass2'],
+ [:created, 'PipelineClass3'],
+ [:created, 'PipelineClass4'],
+ [:created, 'PipelineClass5']
+ )
+ end
+ end
+
+ context 'when the source instance version is a patch version' do
+ it 'creates trackers with the same status as the non-patch source version' do
+ bulk_import_1 = create(:bulk_import, source_version: '15.0.1')
+ entity_1 = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import_1)
+
+ bulk_import_2 = create(:bulk_import, source_version: '15.0.0')
+ entity_2 = create(:bulk_import_entity, :group_entity, bulk_import: bulk_import_2)
+
+ described_class.perform_inline(bulk_import_1.id)
+ described_class.perform_inline(bulk_import_2.id)
+
+ trackers_1 = entity_1.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }
+ trackers_2 = entity_2.trackers.collect { |tracker| [tracker.status_name, tracker.relation] }
+
+ expect(trackers_1).to eq(trackers_2)
+ end
+ end
+ end
end
end
diff --git a/spec/workers/bulk_imports/finish_project_import_worker_spec.rb b/spec/workers/bulk_imports/finish_project_import_worker_spec.rb
new file mode 100644
index 00000000000..3f5f8477667
--- /dev/null
+++ b/spec/workers/bulk_imports/finish_project_import_worker_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::FinishProjectImportWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:job_args) { [project.id] }
+
+ describe '#perform' do
+ it_behaves_like 'an idempotent worker' do
+ it 'calls after_import for the project' do
+ expect_next_found_instance_of(Project) do |project|
+ expect(project).to receive(:after_import)
+ end
+
+ described_class.new.perform(project.id)
+ end
+
+ context 'when no project is found' do
+ let(:job_args) { nil }
+
+ it 'returns without error' do
+ expect { described_class.new.perform(project.id) }.not_to raise_error
+ end
+ end
+ end
+ end
+end
diff --git a/spec/workers/bulk_imports/pipeline_batch_worker_spec.rb b/spec/workers/bulk_imports/pipeline_batch_worker_spec.rb
index c10e1b486ab..3c33910b62c 100644
--- a/spec/workers/bulk_imports/pipeline_batch_worker_spec.rb
+++ b/spec/workers/bulk_imports/pipeline_batch_worker_spec.rb
@@ -73,6 +73,16 @@ RSpec.describe BulkImports::PipelineBatchWorker, feature_category: :importers do
end
end
+ context 'when batch status is started' do
+ let(:batch) { create(:bulk_import_batch_tracker, :started, tracker: tracker) }
+
+ it 'runs the given pipeline batch successfully' do
+ subject.perform(batch.id)
+
+ expect(batch.reload).to be_finished
+ end
+ end
+
context 'when exclusive lease cannot be obtained' do
it 'does not run the pipeline' do
expect(subject).to receive(:try_obtain_lease).and_return(false)
diff --git a/spec/workers/click_house/events_sync_worker_spec.rb b/spec/workers/click_house/events_sync_worker_spec.rb
index 8f328839cfd..01267db36a7 100644
--- a/spec/workers/click_house/events_sync_worker_spec.rb
+++ b/spec/workers/click_house/events_sync_worker_spec.rb
@@ -3,48 +3,125 @@
require 'spec_helper'
RSpec.describe ClickHouse::EventsSyncWorker, feature_category: :value_stream_management do
- let(:databases) { { main: :some_db } }
let(:worker) { described_class.new }
- before do
- allow(ClickHouse::Client.configuration).to receive(:databases).and_return(databases)
- end
-
- include_examples 'an idempotent worker' do
- context 'when the event_sync_worker_for_click_house feature flag is on' do
+ it_behaves_like 'an idempotent worker' do
+ context 'when the event_sync_worker_for_click_house feature flag is on', :click_house do
before do
stub_feature_flags(event_sync_worker_for_click_house: true)
end
- it 'returns true' do
- expect(worker).to receive(:log_extra_metadata_on_done).with(:result, { status: :processed })
+ context 'when there is nothing to sync' do
+ it 'adds metadata for the worker' do
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:result,
+ { status: :processed, records_inserted: 0, reached_end_of_table: true })
- worker.perform
+ worker.perform
+
+ events = ClickHouse::Client.select('SELECT * FROM events', :main)
+ expect(events).to be_empty
+ end
end
- context 'when no ClickHouse databases are configured' do
- let(:databases) { {} }
+ context 'when syncing records' do
+ 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(:project_event2) { create(:event, :closed, project: project, target: issue) }
+ let_it_be(:event_without_parent) { create(:event, :joined, project: nil, group: nil) }
+ let_it_be(:group_event) { create(:event, :created, group: group, project: nil) }
+ let_it_be(:project_event1) { create(:event, :created, project: project, target: issue) }
+ # looks invalid but we have some records like this on PRD
- it 'skips execution' do
- expect(worker).to receive(:log_extra_metadata_on_done).with(:result, { status: :disabled })
+ it 'inserts all records' do
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:result,
+ { status: :processed, records_inserted: 4, reached_end_of_table: true })
worker.perform
+
+ expected_records = [
+ hash_including('id' => project_event2.id, 'path' => "#{group.id}/#{project.project_namespace.id}/",
+ 'target_type' => 'Issue'),
+ hash_including('id' => event_without_parent.id, 'path' => '', 'target_type' => ''),
+ hash_including('id' => group_event.id, 'path' => "#{group.id}/", 'target_type' => ''),
+ hash_including('id' => project_event1.id, 'path' => "#{group.id}/#{project.project_namespace.id}/",
+ 'target_type' => 'Issue')
+ ]
+
+ events = ClickHouse::Client.select('SELECT * FROM events ORDER BY id', :main)
+
+ expect(events).to match(expected_records)
+
+ last_processed_id = ClickHouse::SyncCursor.cursor_for(:events)
+ expect(last_processed_id).to eq(project_event1.id)
end
- end
- context 'when exclusive lease error happens' do
- it 'skips execution' do
- expect(worker).to receive(:in_lock).and_raise(Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError)
- expect(worker).to receive(:log_extra_metadata_on_done).with(:result, { status: :skipped })
+ context 'when multiple batches are needed' do
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+ stub_const("#{described_class}::INSERT_BATCH_SIZE", 1)
+ end
- worker.perform
+ it 'inserts all records' do
+ worker.perform
+
+ events = ClickHouse::Client.select('SELECT * FROM events', :main)
+ expect(events.size).to eq(4)
+ end
+ end
+
+ context 'when time limit is reached' do
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+ end
+
+ it 'stops the processing' do
+ allow_next_instance_of(Analytics::CycleAnalytics::RuntimeLimiter) do |runtime_limiter|
+ allow(runtime_limiter).to receive(:over_time?).and_return(false, true)
+ end
+
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:result,
+ { status: :processed, records_inserted: 2, reached_end_of_table: false })
+
+ worker.perform
+
+ last_processed_id = ClickHouse::SyncCursor.cursor_for(:events)
+ expect(last_processed_id).to eq(event_without_parent.id)
+ end
+ end
+
+ context 'when syncing from a certain point' do
+ before do
+ ClickHouse::SyncCursor.update_cursor_for(:events, project_event2.id)
+ end
+
+ it 'syncs records after the cursor' do
+ worker.perform
+
+ events = ClickHouse::Client.select('SELECT id FROM events ORDER BY id', :main)
+ expect(events).to eq([{ 'id' => event_without_parent.id }, { 'id' => group_event.id },
+ { 'id' => project_event1.id }])
+ end
+
+ context 'when there is nothing to sync' do
+ it 'does nothing' do
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:result,
+ { status: :processed, records_inserted: 0, reached_end_of_table: true })
+
+ ClickHouse::SyncCursor.update_cursor_for(:events, project_event1.id)
+ worker.perform
+
+ events = ClickHouse::Client.select('SELECT id FROM events ORDER BY id', :main)
+ expect(events).to be_empty
+ end
+ end
end
end
end
- context 'when the event_sync_worker_for_click_house feature flag is off' do
+ context 'when clickhouse is not configured' do
before do
- stub_feature_flags(event_sync_worker_for_click_house: false)
+ allow(ClickHouse::Client.configuration).to receive(:databases).and_return({})
end
it 'skips execution' do
@@ -54,4 +131,28 @@ RSpec.describe ClickHouse::EventsSyncWorker, feature_category: :value_stream_man
end
end
end
+
+ context 'when exclusive lease error happens' do
+ it 'skips execution' do
+ stub_feature_flags(event_sync_worker_for_click_house: true)
+ allow(ClickHouse::Client.configuration).to receive(:databases).and_return({ main: :some_db })
+
+ expect(worker).to receive(:in_lock).and_raise(Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:result, { status: :skipped })
+
+ worker.perform
+ end
+ end
+
+ context 'when the event_sync_worker_for_click_house feature flag is off' do
+ before do
+ stub_feature_flags(event_sync_worker_for_click_house: false)
+ end
+
+ it 'skips execution' do
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:result, { status: :disabled })
+
+ worker.perform
+ end
+ end
end
diff --git a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
index 3b7bbfc8a7b..27e1077b138 100644
--- a/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/object_importer_spec.rb
@@ -273,7 +273,8 @@ RSpec.describe Gitlab::GithubImport::ObjectImporter, :aggregate_failures, featur
.to receive(:notify)
.with(
job['args'].last,
- job['jid']
+ job['jid'],
+ ttl: Gitlab::Import::JOB_WAITER_TTL
)
sidekiq_retries_exhausted
diff --git a/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb b/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
index 6475be0243c..c76ce6b555f 100644
--- a/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
+++ b/spec/workers/concerns/gitlab/github_import/rescheduling_methods_spec.rb
@@ -110,7 +110,7 @@ RSpec.describe Gitlab::GithubImport::ReschedulingMethods, feature_category: :imp
expect(Gitlab::JobWaiter)
.to receive(:notify)
- .with('123', 'abc123')
+ .with('123', 'abc123', ttl: Gitlab::Import::JOB_WAITER_TTL)
worker.notify_waiter('123')
end
diff --git a/spec/workers/concerns/gitlab/import/notify_upon_death_spec.rb b/spec/workers/concerns/gitlab/import/notify_upon_death_spec.rb
new file mode 100644
index 00000000000..1f760e8542b
--- /dev/null
+++ b/spec/workers/concerns/gitlab/import/notify_upon_death_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Import::NotifyUponDeath, feature_category: :importers do
+ let(:worker_class) do
+ Class.new do
+ include Sidekiq::Worker
+ include Gitlab::Import::NotifyUponDeath
+ end
+ end
+
+ describe '.sidekiq_retries_exhausted' do
+ it 'notifies the JobWaiter when 3 arguments are given and the last is a String' do
+ job = { 'args' => [12, {}, '123abc'], 'jid' => '123' }
+
+ expect(Gitlab::JobWaiter)
+ .to receive(:notify)
+ .with('123abc', '123', ttl: Gitlab::Import::JOB_WAITER_TTL)
+
+ worker_class.sidekiq_retries_exhausted_block.call(job)
+ end
+
+ it 'does not notify the JobWaiter when only 2 arguments are given' do
+ job = { 'args' => [12, '123abc'], 'jid' => '123' }
+
+ expect(Gitlab::JobWaiter)
+ .not_to receive(:notify)
+
+ worker_class.sidekiq_retries_exhausted_block.call(job)
+ end
+
+ it 'does not notify the JobWaiter when only 1 argument is given' do
+ job = { 'args' => ['123abc'], 'jid' => '123' }
+
+ expect(Gitlab::JobWaiter)
+ .not_to receive(:notify)
+
+ worker_class.sidekiq_retries_exhausted_block.call(job)
+ end
+
+ it 'does not notify the JobWaiter when the last argument is not a String' do
+ job = { 'args' => [12, {}, 40], 'jid' => '123' }
+
+ expect(Gitlab::JobWaiter)
+ .not_to receive(:notify)
+
+ worker_class.sidekiq_retries_exhausted_block.call(job)
+ end
+ end
+end
diff --git a/spec/workers/concerns/gitlab/notify_upon_death_spec.rb b/spec/workers/concerns/gitlab/notify_upon_death_spec.rb
deleted file mode 100644
index 36faf3ee296..00000000000
--- a/spec/workers/concerns/gitlab/notify_upon_death_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::NotifyUponDeath, feature_category: :shared do
- let(:worker_class) do
- Class.new do
- include Sidekiq::Worker
- include Gitlab::NotifyUponDeath
- end
- end
-
- describe '.sidekiq_retries_exhausted' do
- it 'notifies the JobWaiter when 3 arguments are given and the last is a String' do
- job = { 'args' => [12, {}, '123abc'], 'jid' => '123' }
-
- expect(Gitlab::JobWaiter)
- .to receive(:notify)
- .with('123abc', '123')
-
- worker_class.sidekiq_retries_exhausted_block.call(job)
- end
-
- it 'does not notify the JobWaiter when only 2 arguments are given' do
- job = { 'args' => [12, {}], 'jid' => '123' }
-
- expect(Gitlab::JobWaiter)
- .not_to receive(:notify)
-
- worker_class.sidekiq_retries_exhausted_block.call(job)
- end
-
- it 'does not notify the JobWaiter when only 1 argument is given' do
- job = { 'args' => [12], 'jid' => '123' }
-
- expect(Gitlab::JobWaiter)
- .not_to receive(:notify)
-
- worker_class.sidekiq_retries_exhausted_block.call(job)
- end
-
- it 'does not notify the JobWaiter when the last argument is not a String' do
- job = { 'args' => [12, {}, 40], 'jid' => '123' }
-
- expect(Gitlab::JobWaiter)
- .not_to receive(:notify)
-
- worker_class.sidekiq_retries_exhausted_block.call(job)
- end
- end
-end
diff --git a/spec/workers/concerns/limited_capacity/worker_spec.rb b/spec/workers/concerns/limited_capacity/worker_spec.rb
index 65906eef0fa..8092adec3b9 100644
--- a/spec/workers/concerns/limited_capacity/worker_spec.rb
+++ b/spec/workers/concerns/limited_capacity/worker_spec.rb
@@ -57,10 +57,26 @@ RSpec.describe LimitedCapacity::Worker, :clean_gitlab_redis_queues, :aggregate_f
it 'enqueues jobs' do
expect(worker_class)
.to receive(:bulk_perform_async)
- .with([[:arg], [:arg], [:arg]])
+ .with([[:arg], [:arg], [:arg]]).and_call_original
+
+ expect(Sidekiq::Client).to receive(:push_bulk)
perform_with_capacity
end
+
+ context 'when max_running_jobs is 0' do
+ let(:max_running_jobs) { 0 }
+
+ it 'does not enqueue jobs' do
+ expect(worker_class)
+ .to receive(:bulk_perform_async)
+ .with([]).and_call_original
+
+ expect(Sidekiq::Client).not_to receive(:push_bulk)
+
+ perform_with_capacity
+ end
+ end
end
describe '#perform' do
diff --git a/spec/workers/database/lock_tables_worker_spec.rb b/spec/workers/database/lock_tables_worker_spec.rb
new file mode 100644
index 00000000000..cb720959db0
--- /dev/null
+++ b/spec/workers/database/lock_tables_worker_spec.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Database::LockTablesWorker, feature_category: :cell do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:worker) { described_class.new }
+ let(:exception_class) { described_class::TableShouldNotBeLocked }
+
+ describe '#perform' do
+ context 'when running with single database' do # this covers both single-db and single-db-ci-connection cases
+ before do
+ skip_if_database_exists(:ci)
+ end
+
+ it 'skips executing the job' do
+ expect do
+ worker.perform('ci', %w[ci_pipelines])
+ end.to raise_error(exception_class, 'GitLab is not running in multiple database mode')
+ end
+ end
+
+ context 'when running in decomposed database' do
+ before do
+ skip_if_shared_database(:ci)
+ end
+
+ context 'when the table is wrong' do
+ context 'when trying to lock tables on an unknown database' do
+ it 'raises an exception' do
+ expect do
+ worker.perform('foobar', %w[ci_pipelines])
+ end.to raise_error(exception_class, /does not support locking writes on tables/)
+ end
+ end
+
+ context 'when trying to lock tables on the database that does not support locking' do
+ it 'raises an exception' do
+ expect do
+ worker.perform('geo', %w[ci_pipelines]) # ci tables should be locked only on main
+ end.to raise_error(exception_class, /does not support locking writes on tables/)
+ end
+ end
+
+ context 'when trying to lock tables on the wrong database' do
+ it 'raises an exception' do
+ expect do
+ worker.perform('ci', %w[ci_pipelines]) # ci tables should be locked only on main
+ end.to raise_error(exception_class, "table 'ci_pipelines' should not be locked on the database 'ci'")
+ end
+ end
+
+ context 'when trying to lock shared tables on the database' do
+ it 'raises an exception' do
+ expect do
+ worker.perform('main', %w[loose_foreign_keys_deleted_records])
+ end.to raise_error(exception_class, /should not be locked on the database 'main'/)
+ end
+ end
+ end
+
+ context 'when the table is correct' do
+ context 'when the table is not locked for writes' do
+ where(:database_name, :tables) do
+ :ci | %w[users namespaces]
+ :main | %w[ci_pipelines ci_builds]
+ end
+
+ with_them do
+ it 'locks the tables on the corresponding database' do
+ tables.each do |table_name|
+ unlock_table(database_name, table_name)
+ expect(lock_writes_manager(database_name, table_name).table_locked_for_writes?).to eq(false)
+ end
+
+ expected_log_results = tables.map do |table_name|
+ { action: "locked", database: database_name, dry_run: false, table: table_name }
+ end
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:performed_actions, expected_log_results)
+
+ worker.perform(database_name, tables)
+ tables.each do |table_name|
+ expect(lock_writes_manager(database_name, table_name).table_locked_for_writes?).to eq(true)
+ end
+ end
+ end
+
+ context 'when the table is already locked for writes' do
+ where(:database_name, :tables) do
+ :ci | %w[users namespaces]
+ :main | %w[ci_pipelines ci_builds]
+ end
+
+ with_them do
+ it 'skips locking the tables on the corresponding database' do
+ tables.each do |table_name|
+ lock_table(database_name, table_name)
+ end
+
+ expected_log_results = tables.map do |table_name|
+ { action: 'skipped', database: database_name, dry_run: false, table: table_name }
+ end
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:performed_actions, expected_log_results)
+
+ worker.perform(database_name, tables)
+ tables.each do |table_name|
+ expect(lock_writes_manager(database_name, table_name).table_locked_for_writes?).to eq(true)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def lock_table(database_name, table_name)
+ lock_writes_manager(database_name, table_name).lock_writes
+ end
+
+ def unlock_table(database_name, table_name)
+ lock_writes_manager(database_name, table_name).unlock_writes
+ end
+
+ def lock_writes_manager(database_name, table_name)
+ connection = Gitlab::Database.database_base_models_with_gitlab_shared[database_name].connection
+ Gitlab::Database::LockWritesManager.new(
+ table_name: table_name,
+ connection: connection,
+ database_name: database_name,
+ with_retries: false,
+ dry_run: false
+ )
+ end
+end
diff --git a/spec/workers/database/monitor_locked_tables_worker_spec.rb b/spec/workers/database/monitor_locked_tables_worker_spec.rb
index 47475a0ad4a..7e900259265 100644
--- a/spec/workers/database/monitor_locked_tables_worker_spec.rb
+++ b/spec/workers/database/monitor_locked_tables_worker_spec.rb
@@ -19,6 +19,10 @@ RSpec.describe Database::MonitorLockedTablesWorker, feature_category: :cell do
end
context 'when running in decomposed database' do
+ before do
+ skip_if_shared_database(:ci)
+ end
+
context 'when the feature flag is disabled' do
before do
stub_feature_flags(monitor_database_locked_tables: false)
@@ -32,7 +36,6 @@ RSpec.describe Database::MonitorLockedTablesWorker, feature_category: :cell do
context 'when the feature flag is enabled' do
before do
- skip_if_shared_database(:ci)
stub_feature_flags(monitor_database_locked_tables: true)
allow(Gitlab::Database::TablesLocker).to receive(:new).and_return(tables_locker)
end
@@ -73,6 +76,56 @@ RSpec.describe Database::MonitorLockedTablesWorker, feature_category: :cell do
worker.perform
end
+
+ context 'with automatically locking the unlocked tables' do
+ context 'when there are no tables to be locked' do
+ before do
+ stub_feature_flags(lock_tables_in_monitoring: true)
+ allow(tables_locker).to receive(:lock_writes).and_return([])
+ end
+
+ it 'does not call the Database::LockTablesWorker' do
+ expect(Database::LockTablesWorker).not_to receive(:perform_async)
+ end
+ end
+
+ context 'when there are tables to be locked' do
+ before do
+ lock_writes_results = [
+ { table: 'users', database: 'ci', action: 'needs_lock' },
+ { table: 'projects', database: 'ci', action: 'needs_lock' },
+ { table: 'ci_builds', database: 'main', action: 'needs_lock' },
+ { table: 'ci_pipelines', database: 'main', action: 'skipped' }
+ ]
+ allow(tables_locker).to receive(:lock_writes).and_return(lock_writes_results)
+ end
+
+ context 'when feature flag lock_tables_in_monitoring is enabled' do
+ before do
+ stub_feature_flags(lock_tables_in_monitoring: true)
+ end
+
+ it 'locks the tables that need to be locked' do
+ expect(Database::LockTablesWorker).to receive(:perform_async).once.with('ci', %w[users projects])
+ expect(Database::LockTablesWorker).to receive(:perform_async).once.with('main', %w[ci_builds])
+
+ worker.perform
+ end
+ end
+
+ context 'when feature flag lock_tables_in_monitoring is disabled' do
+ before do
+ stub_feature_flags(lock_tables_in_monitoring: false)
+ end
+
+ it 'does not lock the tables that need to be locked' do
+ expect(Database::LockTablesWorker).not_to receive(:perform_async)
+
+ worker.perform
+ end
+ end
+ end
+ end
end
end
end
diff --git a/spec/workers/environments/stop_job_success_worker_spec.rb b/spec/workers/environments/stop_job_success_worker_spec.rb
index 3a2db8cfb77..df0acf46bd9 100644
--- a/spec/workers/environments/stop_job_success_worker_spec.rb
+++ b/spec/workers/environments/stop_job_success_worker_spec.rb
@@ -4,39 +4,54 @@ require 'spec_helper'
RSpec.describe Environments::StopJobSuccessWorker, feature_category: :continuous_delivery do
describe '#perform' do
- subject { described_class.new.perform(build.id) }
+ let_it_be_with_refind(:environment) { create(:environment, state: :available) }
- context 'when build exists' do
- context 'when the build will stop an environment' do
- let!(:build) { create(:ci_build, :stop_review_app, environment: environment.name, project: environment.project, status: :success) } # rubocop:disable Layout/LineLength
- let(:environment) { create(:environment, state: :available) }
+ subject { described_class.new.perform(job.id) }
- it 'stops the environment' do
+ shared_examples_for 'stopping an associated environment' do
+ it 'stops the environment' do
+ expect(environment).to be_available
+
+ subject
+
+ expect(environment.reload).to be_stopped
+ end
+
+ context 'when the job fails' do
+ before do
+ job.update!(status: :failed)
+ environment.update!(state: :available)
+ end
+
+ it 'does not stop the environment' do
expect(environment).to be_available
subject
- expect(environment.reload).to be_stopped
+ expect(environment.reload).not_to be_stopped
end
+ end
+ end
- context 'when the build fails' do
- before do
- build.update!(status: :failed)
- environment.update!(state: :available)
- end
-
- it 'does not stop the environment' do
- expect(environment).to be_available
+ context 'with build job' do
+ let!(:job) do
+ create(:ci_build, :stop_review_app, environment: environment.name, project: environment.project,
+ status: :success)
+ end
- subject
+ it_behaves_like 'stopping an associated environment'
+ end
- expect(environment.reload).not_to be_stopped
- end
- end
+ context 'with bridge job' do
+ let!(:job) do
+ create(:ci_bridge, :stop_review_app, environment: environment.name, project: environment.project,
+ status: :success)
end
+
+ it_behaves_like 'stopping an associated environment'
end
- context 'when build does not exist' do
+ context 'when job does not exist' do
it 'does not raise exception' do
expect { described_class.new.perform(123) }
.not_to raise_error
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index 3cd030e678d..9a94a836d60 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -142,6 +142,7 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'BulkImports::EntityWorker' => false,
'BulkImports::PipelineWorker' => false,
'BulkImports::PipelineBatchWorker' => false,
+ 'BulkImports::FinishProjectImportWorker' => 5,
'Chaos::CpuSpinWorker' => 3,
'Chaos::DbSpinWorker' => 3,
'Chaos::KillWorker' => false,
@@ -194,6 +195,7 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'CreateGithubWebhookWorker' => 3,
'CreateNoteDiffFileWorker' => 3,
'CreatePipelineWorker' => 3,
+ 'Database::LockTablesWorker' => false,
'Database::BatchedBackgroundMigration::CiExecutionWorker' => 0,
'Database::BatchedBackgroundMigration::MainExecutionWorker' => 0,
'DeleteContainerRepositoryWorker' => 3,
@@ -233,8 +235,6 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Geo::Batch::ProjectRegistrySchedulerWorker' => 3,
'Geo::Batch::ProjectRegistryWorker' => 3,
'Geo::ContainerRepositorySyncWorker' => 1,
- 'Geo::DesignRepositoryShardSyncWorker' => false,
- 'Geo::DesignRepositorySyncWorker' => 1,
'Geo::DestroyWorker' => 3,
'Geo::EventWorker' => 3,
'Geo::FileRemovalWorker' => 3,
@@ -247,6 +247,7 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Geo::RepositoryVerification::Secondary::SingleWorker' => false,
'Geo::ReverificationBatchWorker' => 0,
'Geo::BulkMarkPendingBatchWorker' => 0,
+ 'Geo::BulkMarkVerificationPendingBatchWorker' => 0,
'Geo::Scheduler::Primary::SchedulerWorker' => false,
'Geo::Scheduler::SchedulerWorker' => false,
'Geo::Scheduler::Secondary::SchedulerWorker' => false,
@@ -255,6 +256,10 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Geo::VerificationTimeoutWorker' => false,
'Geo::VerificationWorker' => 3,
'GeoRepositoryDestroyWorker' => 3,
+ 'Gitlab::BitbucketImport::AdvanceStageWorker' => 3,
+ 'Gitlab::BitbucketImport::Stage::FinishImportWorker' => 3,
+ 'Gitlab::BitbucketImport::Stage::ImportPullRequestsWorker' => 3,
+ 'Gitlab::BitbucketImport::Stage::ImportRepositoryWorker' => 3,
'Gitlab::BitbucketServerImport::AdvanceStageWorker' => 3,
'Gitlab::BitbucketServerImport::Stage::FinishImportWorker' => 3,
'Gitlab::BitbucketServerImport::Stage::ImportLfsObjectsWorker' => 3,
@@ -342,6 +347,9 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'JiraConnect::SyncProjectWorker' => 3,
'LdapGroupSyncWorker' => 3,
'Licenses::ResetSubmitLicenseUsageDataBannerWorker' => 13,
+ 'Llm::Embedding::GitlabDocumentation::SetEmbeddingsOnTheRecordWorker' => 5,
+ 'Llm::Embedding::GitlabDocumentation::CreateEmptyEmbeddingsRecordsWorker' => 3,
+ 'Llm::Embedding::GitlabDocumentation::CreateDbEmbeddingsPerDocFileWorker' => 5,
'Llm::TanukiBot::UpdateWorker' => 1,
'Llm::TanukiBot::RecreateRecordsWorker' => 3,
'MailScheduler::IssueDueWorker' => 3,
@@ -366,10 +374,8 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Onboarding::PipelineCreatedWorker' => 3,
'Onboarding::ProgressWorker' => 3,
'Onboarding::UserAddedWorker' => 3,
- 'Namespaces::FreeUserCap::OverLimitNotificationWorker' => false,
'Namespaces::RootStatisticsWorker' => 3,
'Namespaces::ScheduleAggregationWorker' => 3,
- 'Namespaces::FreeUserCap::NotificationClearingWorker' => false,
'NewEpicWorker' => 3,
'NewIssueWorker' => 3,
'NewMergeRequestWorker' => 3,
diff --git a/spec/workers/gitlab/bitbucket_import/advance_stage_worker_spec.rb b/spec/workers/gitlab/bitbucket_import/advance_stage_worker_spec.rb
new file mode 100644
index 00000000000..16e3a3dc481
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_import/advance_stage_worker_spec.rb
@@ -0,0 +1,115 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::AdvanceStageWorker, :clean_gitlab_redis_shared_state, feature_category: :importers do
+ let(:project) { create(:project) }
+ let(:import_state) { create(:import_state, project: project, jid: '123') }
+ let(:worker) { described_class.new }
+
+ describe '#perform' do
+ context 'when the project no longer exists' do
+ it 'does not perform any work' do
+ expect(worker).not_to receive(:wait_for_jobs)
+
+ worker.perform(-1, { '123' => 2 }, :finish)
+ end
+ end
+
+ context 'when there are remaining jobs' do
+ before do
+ allow(worker)
+ .to receive(:find_import_state)
+ .and_return(import_state)
+ end
+
+ it 'reschedules itself' do
+ expect(worker)
+ .to receive(:wait_for_jobs)
+ .with({ '123' => 2 })
+ .and_return({ '123' => 1 })
+
+ expect(described_class)
+ .to receive(:perform_in)
+ .with(described_class::INTERVAL, project.id, { '123' => 1 }, :finish)
+
+ worker.perform(project.id, { '123' => 2 }, :finish)
+ end
+ end
+
+ context 'when there are no remaining jobs' do
+ before do
+ allow(worker)
+ .to receive(:find_import_state)
+ .and_return(import_state)
+
+ allow(worker)
+ .to receive(:wait_for_jobs)
+ .with({ '123' => 2 })
+ .and_return({})
+ end
+
+ it 'schedules the next stage' do
+ expect(import_state)
+ .to receive(:refresh_jid_expiration)
+
+ expect(Gitlab::BitbucketImport::Stage::FinishImportWorker)
+ .to receive(:perform_async)
+ .with(project.id)
+
+ worker.perform(project.id, { '123' => 2 }, :finish)
+ end
+
+ it 'raises KeyError when the stage name is invalid' do
+ expect { worker.perform(project.id, { '123' => 2 }, :kittens) }
+ .to raise_error(KeyError)
+ end
+ end
+ end
+
+ describe '#wait_for_jobs' do
+ it 'waits for jobs to complete and returns a new pair of keys to wait for' do
+ waiter1 = instance_double(Gitlab::JobWaiter, jobs_remaining: 1, key: '123')
+ waiter2 = instance_double(Gitlab::JobWaiter, jobs_remaining: 0, key: '456')
+
+ expect(Gitlab::JobWaiter)
+ .to receive(:new)
+ .ordered
+ .with(2, '123')
+ .and_return(waiter1)
+
+ expect(Gitlab::JobWaiter)
+ .to receive(:new)
+ .ordered
+ .with(1, '456')
+ .and_return(waiter2)
+
+ expect(waiter1)
+ .to receive(:wait)
+ .with(described_class::BLOCKING_WAIT_TIME)
+
+ expect(waiter2)
+ .to receive(:wait)
+ .with(described_class::BLOCKING_WAIT_TIME)
+
+ new_waiters = worker.wait_for_jobs({ '123' => 2, '456' => 1 })
+
+ expect(new_waiters).to eq({ '123' => 1 })
+ end
+ end
+
+ describe '#find_import_state' do
+ it 'returns a ProjectImportState' do
+ import_state.update_column(:status, 'started')
+
+ found = worker.find_import_state(project.id)
+
+ expect(found).to be_an_instance_of(ProjectImportState)
+ expect(found.attributes.keys).to match_array(%w[id jid])
+ end
+
+ it 'returns nil if the project import is not running' do
+ expect(worker.find_import_state(project.id)).to be_nil
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_import/import_pull_request_worker_spec.rb b/spec/workers/gitlab/bitbucket_import/import_pull_request_worker_spec.rb
new file mode 100644
index 00000000000..082499be515
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_import/import_pull_request_worker_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::ImportPullRequestWorker, feature_category: :importers do
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketImport::ObjectImporter
+end
diff --git a/spec/workers/gitlab/bitbucket_import/stage/finish_import_worker_spec.rb b/spec/workers/gitlab/bitbucket_import/stage/finish_import_worker_spec.rb
new file mode 100644
index 00000000000..11baa58f1ab
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_import/stage/finish_import_worker_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Stage::FinishImportWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketImport::StageMethods
+
+ it 'does not abort on failure' do
+ expect(worker.abort_on_failure).to be_falsey
+ end
+
+ describe '#perform' do
+ it 'finalises the import process' do
+ expect_next_instance_of(Gitlab::Import::Metrics, :bitbucket_importer, project) do |metric|
+ expect(metric).to receive(:track_finished_import)
+ end
+
+ worker.perform(project.id)
+
+ expect(project.import_state.reload).to be_finished
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker_spec.rb b/spec/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker_spec.rb
new file mode 100644
index 00000000000..8f425066160
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Stage::ImportPullRequestsWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ subject(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketImport::StageMethods
+
+ describe '#perform' do
+ context 'when the import succeeds' do
+ before do
+ allow_next_instance_of(Gitlab::BitbucketImport::Importers::PullRequestsImporter) do |importer|
+ allow(importer).to receive(:execute).and_return(Gitlab::JobWaiter.new(2, '123'))
+ end
+ end
+
+ it 'schedules the next stage' do
+ expect(Gitlab::BitbucketImport::AdvanceStageWorker).to receive(:perform_async)
+ .with(project.id, { '123' => 2 }, :finish)
+
+ worker.perform(project.id)
+ end
+
+ it 'logs stage start and finish' do
+ expect(Gitlab::BitbucketImport::Logger)
+ .to receive(:info).with(hash_including(message: 'starting stage', project_id: project.id))
+ expect(Gitlab::BitbucketImport::Logger)
+ .to receive(:info).with(hash_including(message: 'stage finished', project_id: project.id))
+
+ worker.perform(project.id)
+ end
+ end
+
+ context 'when project does not exists' do
+ it 'does not call the importer' do
+ expect(Gitlab::BitbucketImport::Importers::PullRequestsImporter).not_to receive(:new)
+
+ worker.perform(-1)
+ end
+ end
+
+ context 'when project import state is not `started`' do
+ it 'does not call the importer' do
+ project = create(:project, :import_canceled)
+
+ expect(Gitlab::BitbucketImport::Importers::PullRequestsImporter).not_to receive(:new)
+
+ worker.perform(project.id)
+ end
+ end
+
+ context 'when the importer fails' do
+ it 'does not schedule the next stage and raises error' do
+ exception = StandardError.new('Error')
+
+ allow_next_instance_of(Gitlab::BitbucketImport::Importers::PullRequestsImporter) do |importer|
+ allow(importer).to receive(:execute).and_raise(exception)
+ end
+
+ expect(Gitlab::Import::ImportFailureService)
+ .to receive(:track).with(
+ project_id: project.id,
+ exception: exception,
+ error_source: described_class.name,
+ fail_import: false
+ ).and_call_original
+
+ expect { worker.perform(project.id) }
+ .to change { Gitlab::BitbucketImport::AdvanceStageWorker.jobs.size }.by(0)
+ .and raise_error(exception)
+ end
+ end
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_import/stage/import_repository_worker_spec.rb b/spec/workers/gitlab/bitbucket_import/stage/import_repository_worker_spec.rb
new file mode 100644
index 00000000000..2234a49d66c
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_import/stage/import_repository_worker_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketImport::Stage::ImportRepositoryWorker, feature_category: :importers do
+ let_it_be(:project) { create(:project, :import_started) }
+
+ let(:worker) { described_class.new }
+
+ it_behaves_like Gitlab::BitbucketImport::StageMethods
+
+ it 'executes the importer and enqueues ImportPullRequestsWorker' do
+ expect(Gitlab::BitbucketImport::Importers::RepositoryImporter).to receive_message_chain(:new, :execute)
+ .and_return(true)
+
+ expect(Gitlab::BitbucketImport::Stage::ImportPullRequestsWorker).to receive(:perform_async).with(project.id)
+ .and_return(true).once
+
+ worker.perform(project.id)
+ end
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/advance_stage_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/advance_stage_worker_spec.rb
new file mode 100644
index 00000000000..14e93440422
--- /dev/null
+++ b/spec/workers/gitlab/bitbucket_server_import/advance_stage_worker_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BitbucketServerImport::AdvanceStageWorker, feature_category: :importers do
+ it_behaves_like Gitlab::Import::AdvanceStage, factory: :import_state
+end
diff --git a/spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb b/spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb
index dd3235f846c..376078532cd 100644
--- a/spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb
+++ b/spec/workers/gitlab/bitbucket_server_import/import_pull_request_worker_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Gitlab::BitbucketServerImport::ImportPullRequestWorker, feature_c
end
it 'notifies job waiter' do
- expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid')
+ expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid', ttl: Gitlab::Import::JOB_WAITER_TTL)
worker.perform(project.id, {}, job_waiter_key)
end
@@ -44,7 +44,7 @@ RSpec.describe Gitlab::BitbucketServerImport::ImportPullRequestWorker, feature_c
context 'when project does not exists' do
it 'does not call importer and notifies job waiter' do
expect(importer_class).not_to receive(:new)
- expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid')
+ expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid', ttl: Gitlab::Import::JOB_WAITER_TTL)
worker.perform(-1, {}, job_waiter_key)
end
@@ -55,7 +55,7 @@ RSpec.describe Gitlab::BitbucketServerImport::ImportPullRequestWorker, feature_c
project = create(:project, :import_canceled)
expect(importer_class).not_to receive(:new)
- expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid')
+ expect(Gitlab::JobWaiter).to receive(:notify).with(job_waiter_key, 'jid', ttl: Gitlab::Import::JOB_WAITER_TTL)
worker.perform(project.id, {}, job_waiter_key)
end
diff --git a/spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb b/spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb
index 2e89263bcf3..dc715c3026b 100644
--- a/spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb
+++ b/spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe Gitlab::GithubGistsImport::ImportGistWorker, feature_category: :i
.to receive(:info)
.with(log_attributes.merge('message' => 'start importer'))
expect(importer).to receive(:execute).and_return(importer_result)
- expect(Gitlab::JobWaiter).to receive(:notify).with('some_key', subject.jid)
+ expect(Gitlab::JobWaiter).to receive(:notify).with('some_key', subject.jid, ttl: Gitlab::Import::JOB_WAITER_TTL)
expect(Gitlab::GithubImport::Logger)
.to receive(:info)
.with(log_attributes.merge('message' => 'importer finished'))
@@ -114,7 +114,9 @@ RSpec.describe Gitlab::GithubGistsImport::ImportGistWorker, feature_category: :i
expect(Gitlab::GithubImport::Logger)
.to receive(:error)
.with(log_attributes.merge('message' => 'importer failed', 'error.message' => 'error_message'))
- expect(Gitlab::JobWaiter).to receive(:notify).with('some_key', subject.jid)
+ expect(Gitlab::JobWaiter)
+ .to receive(:notify)
+ .with('some_key', subject.jid, ttl: Gitlab::Import::JOB_WAITER_TTL)
subject.perform(user.id, gist_hash, 'some_key')
@@ -189,7 +191,7 @@ RSpec.describe Gitlab::GithubGistsImport::ImportGistWorker, feature_category: :i
it 'notifies the JobWaiter' do
expect(Gitlab::JobWaiter)
.to receive(:notify)
- .with(job['args'].last, job['jid'])
+ .with(job['args'].last, job['jid'], ttl: Gitlab::Import::JOB_WAITER_TTL)
sidekiq_retries_exhausted
end
diff --git a/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb b/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
index 121f30ea9d5..60c117a2a90 100644
--- a/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/advance_stage_worker_spec.rb
@@ -2,114 +2,6 @@
require 'spec_helper'
-RSpec.describe Gitlab::GithubImport::AdvanceStageWorker, :clean_gitlab_redis_shared_state, feature_category: :importers do
- let(:project) { create(:project) }
- let(:import_state) { create(:import_state, project: project, jid: '123') }
- let(:worker) { described_class.new }
-
- describe '#perform' do
- context 'when the project no longer exists' do
- it 'does not perform any work' do
- expect(worker).not_to receive(:wait_for_jobs)
-
- worker.perform(-1, { '123' => 2 }, :finish)
- end
- end
-
- context 'when there are remaining jobs' do
- before do
- allow(worker)
- .to receive(:find_import_state)
- .and_return(import_state)
- end
-
- it 'reschedules itself' do
- expect(worker)
- .to receive(:wait_for_jobs)
- .with({ '123' => 2 })
- .and_return({ '123' => 1 })
-
- expect(described_class)
- .to receive(:perform_in)
- .with(described_class::INTERVAL, project.id, { '123' => 1 }, :finish)
-
- worker.perform(project.id, { '123' => 2 }, :finish)
- end
- end
-
- context 'when there are no remaining jobs' do
- before do
- allow(worker)
- .to receive(:find_import_state)
- .and_return(import_state)
-
- allow(worker)
- .to receive(:wait_for_jobs)
- .with({ '123' => 2 })
- .and_return({})
- end
-
- it 'schedules the next stage' do
- expect(import_state)
- .to receive(:refresh_jid_expiration)
-
- expect(Gitlab::GithubImport::Stage::FinishImportWorker)
- .to receive(:perform_async)
- .with(project.id)
-
- worker.perform(project.id, { '123' => 2 }, :finish)
- end
-
- it 'raises KeyError when the stage name is invalid' do
- expect { worker.perform(project.id, { '123' => 2 }, :kittens) }
- .to raise_error(KeyError)
- end
- end
- end
-
- describe '#wait_for_jobs' do
- it 'waits for jobs to complete and returns a new pair of keys to wait for' do
- waiter1 = double(:waiter1, jobs_remaining: 1, key: '123')
- waiter2 = double(:waiter2, jobs_remaining: 0, key: '456')
-
- expect(Gitlab::JobWaiter)
- .to receive(:new)
- .ordered
- .with(2, '123')
- .and_return(waiter1)
-
- expect(Gitlab::JobWaiter)
- .to receive(:new)
- .ordered
- .with(1, '456')
- .and_return(waiter2)
-
- expect(waiter1)
- .to receive(:wait)
- .with(described_class::BLOCKING_WAIT_TIME)
-
- expect(waiter2)
- .to receive(:wait)
- .with(described_class::BLOCKING_WAIT_TIME)
-
- new_waiters = worker.wait_for_jobs({ '123' => 2, '456' => 1 })
-
- expect(new_waiters).to eq({ '123' => 1 })
- end
- end
-
- describe '#find_import_state' do
- it 'returns a ProjectImportState' do
- import_state.update_column(:status, 'started')
-
- found = worker.find_import_state(project.id)
-
- expect(found).to be_an_instance_of(ProjectImportState)
- expect(found.attributes.keys).to match_array(%w(id jid))
- end
-
- it 'returns nil if the project import is not running' do
- expect(worker.find_import_state(project.id)).to be_nil
- end
- end
+RSpec.describe Gitlab::GithubImport::AdvanceStageWorker, feature_category: :importers do
+ it_behaves_like Gitlab::Import::AdvanceStage, factory: :import_state
end
diff --git a/spec/workers/gitlab/jira_import/advance_stage_worker_spec.rb b/spec/workers/gitlab/jira_import/advance_stage_worker_spec.rb
new file mode 100644
index 00000000000..d7c5d8aba4d
--- /dev/null
+++ b/spec/workers/gitlab/jira_import/advance_stage_worker_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::JiraImport::AdvanceStageWorker, feature_category: :importers do
+ it_behaves_like Gitlab::Import::AdvanceStage, factory: :jira_import_state
+end
diff --git a/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb b/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb
index 5209395923f..6dfab44b228 100644
--- a/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb
+++ b/spec/workers/gitlab/jira_import/import_issue_worker_spec.rb
@@ -12,9 +12,9 @@ RSpec.describe Gitlab::JiraImport::ImportIssueWorker, feature_category: :importe
describe 'modules' do
it { expect(described_class).to include_module(ApplicationWorker) }
- it { expect(described_class).to include_module(Gitlab::NotifyUponDeath) }
it { expect(described_class).to include_module(Gitlab::JiraImport::QueueOptions) }
it { expect(described_class).to include_module(Gitlab::Import::DatabaseHelpers) }
+ it { expect(described_class).to include_module(Gitlab::Import::NotifyUponDeath) }
end
subject { described_class.new }
diff --git a/spec/workers/incident_management/close_incident_worker_spec.rb b/spec/workers/incident_management/close_incident_worker_spec.rb
index 02ca5260fbd..b218bf4ced1 100644
--- a/spec/workers/incident_management/close_incident_worker_spec.rb
+++ b/spec/workers/incident_management/close_incident_worker_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe IncidentManagement::CloseIncidentWorker, feature_category: :incid
subject(:worker) { described_class.new }
describe '#perform' do
- let_it_be(:user) { User.alert_bot }
+ let_it_be(:user) { Users::Internal.alert_bot }
let_it_be(:project) { create(:project) }
let_it_be(:issue, reload: true) { create(:incident, project: project) }
diff --git a/spec/workers/incident_management/process_alert_worker_v2_spec.rb b/spec/workers/incident_management/process_alert_worker_v2_spec.rb
index 476b6f04942..b9d7cd9fee8 100644
--- a/spec/workers/incident_management/process_alert_worker_v2_spec.rb
+++ b/spec/workers/incident_management/process_alert_worker_v2_spec.rb
@@ -19,14 +19,14 @@ RSpec.describe IncidentManagement::ProcessAlertWorkerV2, feature_category: :inci
allow(Gitlab::AppLogger).to receive(:warn).and_call_original
allow(AlertManagement::CreateAlertIssueService)
- .to receive(:new).with(alert, User.alert_bot)
+ .to receive(:new).with(alert, Users::Internal.alert_bot)
.and_call_original
end
shared_examples 'creates issue successfully' do
it 'creates an issue' do
expect(AlertManagement::CreateAlertIssueService)
- .to receive(:new).with(alert, User.alert_bot)
+ .to receive(:new).with(alert, Users::Internal.alert_bot)
expect { perform_worker }.to change { Issue.count }.by(1)
end
diff --git a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
index 2e77f38e221..278efd3406c 100644
--- a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
+++ b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
@@ -166,4 +166,66 @@ RSpec.describe LooseForeignKeys::CleanupWorker, feature_category: :cell do
end
end
end
+
+ describe 'turbo mode' do
+ context 'when turbo mode is off' do
+ where(:database_name, :feature_flag) do
+ :main | :loose_foreign_keys_turbo_mode_main
+ :ci | :loose_foreign_keys_turbo_mode_ci
+ end
+
+ with_them do
+ before do
+ skip unless Gitlab::Database.has_config?(database_name)
+ stub_feature_flags(feature_flag => false)
+ end
+
+ it 'does not use TurboModificationTracker' do
+ allow_next_instance_of(LooseForeignKeys::TurboModificationTracker) do |instance|
+ expect(instance).not_to receive(:over_limit?)
+ end
+
+ perform_for(db: database_name)
+ end
+
+ it 'logs not using turbo mode' do
+ expect_next_instance_of(LooseForeignKeys::CleanupWorker) do |instance|
+ expect(instance).to receive(:log_extra_metadata_on_done).with(:stats, a_hash_including(turbo_mode: false))
+ end
+
+ perform_for(db: database_name)
+ end
+ end
+ end
+
+ context 'when turbo mode is on' do
+ where(:database_name, :feature_flag) do
+ :main | :loose_foreign_keys_turbo_mode_main
+ :ci | :loose_foreign_keys_turbo_mode_ci
+ end
+
+ with_them do
+ before do
+ skip unless Gitlab::Database.has_config?(database_name)
+ stub_feature_flags(feature_flag => true)
+ end
+
+ it 'does not use TurboModificationTracker' do
+ expect_next_instance_of(LooseForeignKeys::TurboModificationTracker) do |instance|
+ expect(instance).to receive(:over_limit?).at_least(:once)
+ end
+
+ perform_for(db: database_name)
+ end
+
+ it 'logs using turbo mode' do
+ expect_next_instance_of(LooseForeignKeys::CleanupWorker) do |instance|
+ expect(instance).to receive(:log_extra_metadata_on_done).with(:stats, a_hash_including(turbo_mode: true))
+ end
+
+ perform_for(db: database_name)
+ end
+ end
+ end
+ end
end
diff --git a/spec/workers/merge_requests/ensure_prepared_worker_spec.rb b/spec/workers/merge_requests/ensure_prepared_worker_spec.rb
new file mode 100644
index 00000000000..8f599ffe642
--- /dev/null
+++ b/spec/workers/merge_requests/ensure_prepared_worker_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe MergeRequests::EnsurePreparedWorker, :sidekiq_inline, feature_category: :code_review_workflow do
+ subject(:worker) { described_class.new }
+
+ let_it_be(:merge_request_1, reload: true) { create(:merge_request, prepared_at: :nil) }
+ let_it_be(:merge_request_2, reload: true) { create(:merge_request, prepared_at: Time.current) }
+ let_it_be(:merge_request_3, reload: true) { create(:merge_request, prepared_at: :nil) }
+
+ describe '#perform' do
+ context 'when ensure_merge_requests_prepared is enabled' do
+ it 'creates the expected NewMergeRequestWorkers of the unprepared merge requests' do
+ expect(merge_request_1.prepared_at).to eq(nil)
+ expect(merge_request_2.prepared_at).to eq(merge_request_2.prepared_at)
+ expect(merge_request_3.prepared_at).to eq(nil)
+
+ worker.perform
+
+ expect(merge_request_1.reload.prepared_at).not_to eq(nil)
+ expect(merge_request_2.reload.prepared_at).to eq(merge_request_2.prepared_at)
+ expect(merge_request_3.reload.prepared_at).not_to eq(nil)
+ end
+ end
+
+ context 'when ensure_merge_requests_prepared is disabled' do
+ before do
+ stub_feature_flags(ensure_merge_requests_prepared: false)
+ end
+
+ it 'does not prepare any merge requests' do
+ expect(merge_request_1.prepared_at).to eq(nil)
+ expect(merge_request_2.prepared_at).to eq(merge_request_2.prepared_at)
+ expect(merge_request_3.prepared_at).to eq(nil)
+
+ worker.perform
+
+ expect(merge_request_1.prepared_at).to eq(nil)
+ expect(merge_request_2.prepared_at).to eq(merge_request_2.prepared_at)
+ expect(merge_request_3.prepared_at).to eq(nil)
+ end
+ end
+ end
+
+ it_behaves_like 'an idempotent worker' do
+ it 'creates the expected NewMergeRequestWorkers of the unprepared merge requests' do
+ expect(merge_request_1.prepared_at).to eq(nil)
+ expect(merge_request_2.prepared_at).to eq(merge_request_2.prepared_at)
+ expect(merge_request_3.prepared_at).to eq(nil)
+
+ subject
+
+ expect(merge_request_1.reload.prepared_at).not_to eq(nil)
+ expect(merge_request_2.reload.prepared_at).to eq(merge_request_2.prepared_at)
+ expect(merge_request_3.reload.prepared_at).not_to eq(nil)
+ end
+ end
+end
diff --git a/spec/workers/metrics/global_metrics_update_worker_spec.rb b/spec/workers/metrics/global_metrics_update_worker_spec.rb
deleted file mode 100644
index d5bfbcc928a..00000000000
--- a/spec/workers/metrics/global_metrics_update_worker_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ::Metrics::GlobalMetricsUpdateWorker, feature_category: :metrics do
- subject { described_class.new }
-
- describe '#perform' do
- let(:service) { ::Metrics::GlobalMetricsUpdateService.new }
-
- it 'delegates to ::Metrics::GlobalMetricsUpdateService' do
- expect(::Metrics::GlobalMetricsUpdateService).to receive(:new).and_return(service)
- expect(service).to receive(:execute)
-
- subject.perform
- end
-
- context 'for an idempotent worker' do
- include_examples 'an idempotent worker' do
- it 'exports metrics' do
- allow(Gitlab).to receive(:maintenance_mode?).and_return(true).at_least(1).time
-
- perform_multiple
-
- expect(service.maintenance_mode_metric.get).to eq(1)
- end
- end
- end
- end
-end
diff --git a/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb b/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
deleted file mode 100644
index 237b5081bb1..00000000000
--- a/spec/workers/namespaces/in_product_marketing_emails_worker_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Namespaces::InProductMarketingEmailsWorker, '#perform', unless: Gitlab.ee?, feature_category: :experimentation_activation do
- # Running this in EE would call the overridden method, which can't be tested in CE.
- # The EE code is covered in a separate EE spec.
-
- context 'when the in_product_marketing_emails_enabled setting is disabled' do
- before do
- stub_application_setting(in_product_marketing_emails_enabled: false)
- end
-
- it 'does not execute the email service' do
- expect(Namespaces::InProductMarketingEmailsService).not_to receive(:send_for_all_tracks_and_intervals)
-
- subject.perform
- end
- end
-
- context 'when the in_product_marketing_emails_enabled setting is enabled' do
- before do
- stub_application_setting(in_product_marketing_emails_enabled: true)
- end
-
- it 'executes the email service' do
- expect(Namespaces::InProductMarketingEmailsService).to receive(:send_for_all_tracks_and_intervals)
-
- subject.perform
- end
- end
-end
diff --git a/spec/workers/new_merge_request_worker_spec.rb b/spec/workers/new_merge_request_worker_spec.rb
index 58f6792f9a0..4ed9b61a9d7 100644
--- a/spec/workers/new_merge_request_worker_spec.rb
+++ b/spec/workers/new_merge_request_worker_spec.rb
@@ -88,33 +88,25 @@ RSpec.describe NewMergeRequestWorker, feature_category: :code_review_workflow do
worker.perform(merge_request.id, user.id)
end
- context 'when add_prepared_state_to_mr feature flag is off' do
+ context 'when the merge request is prepared' do
before do
- stub_feature_flags(add_prepared_state_to_mr: false)
+ merge_request.update!(prepared_at: Time.current)
end
- it 'calls the create service' do
- expect_next_instance_of(MergeRequests::AfterCreateService, project: merge_request.target_project, current_user: user) do |service|
- expect(service).to receive(:execute).with(merge_request)
- end
+ it 'does not call the create service' do
+ expect(MergeRequests::AfterCreateService).not_to receive(:new)
worker.perform(merge_request.id, user.id)
end
end
- context 'when add_prepared_state_to_mr feature flag is on' do
- before do
- stub_feature_flags(add_prepared_state_to_mr: true)
- end
-
- context 'when the merge request is not prepared' do
- it 'calls the create service' do
- expect_next_instance_of(MergeRequests::AfterCreateService, project: merge_request.target_project, current_user: user) do |service|
- expect(service).to receive(:execute).with(merge_request)
- end
-
- worker.perform(merge_request.id, user.id)
+ context 'when the merge request is not prepared' do
+ it 'calls the create service' do
+ expect_next_instance_of(MergeRequests::AfterCreateService, project: merge_request.target_project, current_user: user) do |service|
+ expect(service).to receive(:execute).with(merge_request).and_call_original
end
+
+ worker.perform(merge_request.id, user.id)
end
end
end
diff --git a/spec/workers/new_note_worker_spec.rb b/spec/workers/new_note_worker_spec.rb
index 651b5742854..3465cffea2d 100644
--- a/spec/workers/new_note_worker_spec.rb
+++ b/spec/workers/new_note_worker_spec.rb
@@ -77,7 +77,7 @@ RSpec.describe NewNoteWorker, feature_category: :team_planning do
end
context 'when Note author has been deleted' do
- let_it_be(:note) { create(:note, author: User.ghost) }
+ let_it_be(:note) { create(:note, author: Users::Internal.ghost) }
it "does not call NotificationService" do
expect(NotificationService).not_to receive(:new)
diff --git a/spec/workers/pages/invalidate_domain_cache_worker_spec.rb b/spec/workers/pages/invalidate_domain_cache_worker_spec.rb
deleted file mode 100644
index b3c81b25a93..00000000000
--- a/spec/workers/pages/invalidate_domain_cache_worker_spec.rb
+++ /dev/null
@@ -1,267 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Pages::InvalidateDomainCacheWorker, feature_category: :pages do
- shared_examples 'clears caches with' do |event_class:, event_data:, caches:|
- include AfterNextHelpers
-
- let(:event) { event_class.new(data: event_data) }
-
- subject { consume_event(subscriber: described_class, event: event) }
-
- it_behaves_like 'subscribes to event'
-
- it 'clears the cache with Gitlab::Pages::CacheControl' do
- caches.each do |cache|
- expect_next(Gitlab::Pages::CacheControl, type: cache[:type], id: cache[:id])
- .to receive(:clear_cache)
- end
-
- subject
- end
- end
-
- context 'when a project have multiple domains' do
- include AfterNextHelpers
-
- let_it_be(:project) { create(:project) }
- let_it_be(:pages_domain) { create(:pages_domain, project: project) }
- let_it_be(:pages_domain2) { create(:pages_domain, project: project) }
-
- let(:event) do
- Pages::PageDeployedEvent.new(
- data: {
- project_id: project.id,
- namespace_id: project.namespace_id,
- root_namespace_id: project.root_ancestor.id
- }
- )
- end
-
- subject { consume_event(subscriber: described_class, event: event) }
-
- it 'clears the cache with Gitlab::Pages::CacheControl' do
- expect_next(Gitlab::Pages::CacheControl, type: :namespace, id: project.namespace_id)
- .to receive(:clear_cache)
- expect_next(Gitlab::Pages::CacheControl, type: :domain, id: pages_domain.id)
- .to receive(:clear_cache)
- expect_next(Gitlab::Pages::CacheControl, type: :domain, id: pages_domain2.id)
- .to receive(:clear_cache)
-
- subject
- end
- end
-
- it_behaves_like 'clears caches with',
- event_class: Pages::PageDeployedEvent,
- event_data: { project_id: 1, namespace_id: 2, root_namespace_id: 3 },
- caches: [
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Pages::PageDeletedEvent,
- event_data: { project_id: 1, namespace_id: 2, root_namespace_id: 3 },
- caches: [
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Projects::ProjectDeletedEvent,
- event_data: { project_id: 1, namespace_id: 2, root_namespace_id: 3 },
- caches: [
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Projects::ProjectCreatedEvent,
- event_data: { project_id: 1, namespace_id: 2, root_namespace_id: 3 },
- caches: [
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Projects::ProjectArchivedEvent,
- event_data: { project_id: 1, namespace_id: 2, root_namespace_id: 3 },
- caches: [
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Projects::ProjectPathChangedEvent,
- event_data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- old_path: 'old_path',
- new_path: 'new_path'
- },
- caches: [
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Projects::ProjectTransferedEvent,
- event_data: {
- project_id: 1,
- old_namespace_id: 2,
- old_root_namespace_id: 3,
- new_namespace_id: 4,
- new_root_namespace_id: 5
- },
- caches: [
- { type: :namespace, id: 3 },
- { type: :namespace, id: 5 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Groups::GroupTransferedEvent,
- event_data: {
- group_id: 1,
- old_root_namespace_id: 3,
- new_root_namespace_id: 5
- },
- caches: [
- { type: :namespace, id: 3 },
- { type: :namespace, id: 5 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Groups::GroupPathChangedEvent,
- event_data: {
- group_id: 1,
- root_namespace_id: 2,
- old_path: 'old_path',
- new_path: 'new_path'
- },
- caches: [
- { type: :namespace, id: 2 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: Groups::GroupDeletedEvent,
- event_data: {
- group_id: 1,
- root_namespace_id: 3
- },
- caches: [
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: PagesDomains::PagesDomainDeletedEvent,
- event_data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- domain_id: 4,
- domain: 'somedomain.com'
- },
- caches: [
- { type: :domain, id: 4 },
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: PagesDomains::PagesDomainUpdatedEvent,
- event_data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- domain_id: 4,
- domain: 'somedomain.com'
- },
- caches: [
- { type: :domain, id: 4 },
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'clears caches with',
- event_class: PagesDomains::PagesDomainCreatedEvent,
- event_data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- domain_id: 4,
- domain: 'somedomain.com'
- },
- caches: [
- { type: :domain, id: 4 },
- { type: :namespace, id: 3 }
- ]
-
- context 'when project attributes change' do
- Projects::ProjectAttributesChangedEvent::PAGES_RELATED_ATTRIBUTES.each do |attribute|
- it_behaves_like 'clears caches with',
- event_class: Projects::ProjectAttributesChangedEvent,
- event_data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- domain_id: 4,
- attributes: [attribute]
- },
- caches: [
- { type: :domain, id: 4 },
- { type: :namespace, id: 3 }
- ]
- end
-
- it_behaves_like 'ignores the published event' do
- let(:event) do
- Projects::ProjectAttributesChangedEvent.new(
- data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- attributes: ['unknown']
- }
- )
- end
- end
- end
-
- context 'when project features change' do
- it_behaves_like 'clears caches with',
- event_class: Projects::ProjectFeaturesChangedEvent,
- event_data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- features: ['pages_access_level']
- },
- caches: [
- { type: :namespace, id: 3 }
- ]
-
- it_behaves_like 'ignores the published event' do
- let(:event) do
- Projects::ProjectFeaturesChangedEvent.new(
- data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- features: ['unknown']
- }
- )
- end
- end
- end
-
- context 'when namespace based cache keys are duplicated' do
- # de-dups namespace cache keys
- it_behaves_like 'clears caches with',
- event_class: Projects::ProjectTransferedEvent,
- event_data: {
- project_id: 1,
- old_namespace_id: 2,
- old_root_namespace_id: 5,
- new_namespace_id: 4,
- new_root_namespace_id: 5
- },
- caches: [
- { type: :namespace, id: 5 }
- ]
- end
-end
diff --git a/spec/workers/personal_access_tokens/expiring_worker_spec.rb b/spec/workers/personal_access_tokens/expiring_worker_spec.rb
index 01ce4e85fe2..0cc63fdb85e 100644
--- a/spec/workers/personal_access_tokens/expiring_worker_spec.rb
+++ b/spec/workers/personal_access_tokens/expiring_worker_spec.rb
@@ -58,5 +58,32 @@ RSpec.describe PersonalAccessTokens::ExpiringWorker, type: :worker, feature_cate
expect { worker.perform }.not_to change { pat.reload.expire_notification_delivered }
end
end
+
+ context 'when a token is owned by a project bot' do
+ let_it_be(:maintainer1) { create(:user) }
+ let_it_be(:maintainer2) { create(:user) }
+ let_it_be(:project_bot) { create(:user, :project_bot) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:expiring_token) { create(:personal_access_token, user: project_bot, expires_at: 5.days.from_now) }
+
+ before_all do
+ project.add_developer(project_bot)
+ project.add_maintainer(maintainer1)
+ project.add_maintainer(maintainer2)
+ end
+
+ it 'uses notification service to send the email' do
+ expect_next_instance_of(NotificationService) do |notification_service|
+ expect(notification_service).to receive(:resource_access_tokens_about_to_expire)
+ .with(project_bot, match_array([expiring_token.name]))
+ end
+
+ worker.perform
+ end
+
+ it 'marks the notification as delivered' do
+ expect { worker.perform }.to change { expiring_token.reload.expire_notification_delivered }.from(false).to(true)
+ end
+ end
end
end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 5c8a75aca3f..2e0a2535453 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -282,7 +282,7 @@ RSpec.describe PostReceive, feature_category: :source_code_management do
let(:user) { project.creator }
let(:label) { 'counts.source_code_pushes' }
let(:property) { 'source_code_pushes' }
- let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: label).to_h] }
+ let(:context) { [Gitlab::Usage::MetricDefinition.context_for(label).to_h] }
subject(:post_receive) { perform }
end
diff --git a/spec/workers/projects/record_target_platforms_worker_spec.rb b/spec/workers/projects/record_target_platforms_worker_spec.rb
index ecb6aab7349..116da404112 100644
--- a/spec/workers/projects/record_target_platforms_worker_spec.rb
+++ b/spec/workers/projects/record_target_platforms_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Projects::RecordTargetPlatformsWorker, feature_category: :groups_and_projects do
+RSpec.describe Projects::RecordTargetPlatformsWorker, feature_category: :experimentation_activation do
include ExclusiveLeaseHelpers
let_it_be(:swift) { create(:programming_language, name: 'Swift') }
diff --git a/spec/workers/users/migrate_records_to_ghost_user_in_batches_worker_spec.rb b/spec/workers/users/migrate_records_to_ghost_user_in_batches_worker_spec.rb
index 38ea7c43267..fbbfd44bba6 100644
--- a/spec/workers/users/migrate_records_to_ghost_user_in_batches_worker_spec.rb
+++ b/spec/workers/users/migrate_records_to_ghost_user_in_batches_worker_spec.rb
@@ -34,8 +34,8 @@ RSpec.describe Users::MigrateRecordsToGhostUserInBatchesWorker, feature_category
it 'migrates issue to ghost user' do
subject
- expect(issue.reload.author).to eq(User.ghost)
- expect(issue.last_edited_by).to eq(User.ghost)
+ expect(issue.reload.author).to eq(Users::Internal.ghost)
+ expect(issue.last_edited_by).to eq(Users::Internal.ghost)
end
end
end
diff --git a/spec/workers/users/track_namespace_visits_worker_spec.rb b/spec/workers/users/track_namespace_visits_worker_spec.rb
new file mode 100644
index 00000000000..cfb2b7ab5eb
--- /dev/null
+++ b/spec/workers/users/track_namespace_visits_worker_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::TrackNamespaceVisitsWorker, feature_category: :navigation do
+ describe '#perform' do
+ let_it_be(:user) { create(:user) }
+
+ context 'when tracking a group' do
+ let_it_be(:entity) { create(:group) }
+ let_it_be(:entity_type) { 'groups' }
+ let_it_be(:worker) { described_class.new }
+ let_it_be(:model) { ::Users::GroupVisit }
+
+ it_behaves_like 'namespace visits tracking worker'
+ end
+
+ context 'when tracking a project' do
+ let_it_be(:entity) { create(:project) }
+ let_it_be(:entity_type) { 'projects' }
+ let_it_be(:worker) { described_class.new }
+ let_it_be(:model) { ::Users::ProjectVisit }
+
+ it_behaves_like 'namespace visits tracking worker'
+ end
+ end
+end
diff --git a/storybook/config/addons/make_container/index.js b/storybook/config/addons/make_container/index.js
new file mode 100644
index 00000000000..2bc7fa92b8a
--- /dev/null
+++ b/storybook/config/addons/make_container/index.js
@@ -0,0 +1,12 @@
+/**
+ * Return a story decorator function, which wraps the given story in a `div`
+ * element with the given `style` attributes.
+ *
+ * @param {object} style The style attribute to apply to the container.
+ * @return {function} The story decorator.
+ */
+export const makeContainer = (style) => (Story) => ({
+ render(h) {
+ return h('div', { style }, [h(Story())]);
+ },
+});
diff --git a/storybook/config/preview.js b/storybook/config/preview.js
index fc04623071a..e31f36ca70e 100644
--- a/storybook/config/preview.js
+++ b/storybook/config/preview.js
@@ -1,6 +1,7 @@
// Some modules read window.gon on initialization thus we need to define this object before anything else
import './gon';
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import translateMixin from '~/vue_shared/translate';
import { initializeGitLabAPIAccess } from './addons/gitlab_api_access/preview';
@@ -13,6 +14,7 @@ const stylesheetsRequireCtx = require.context(
initializeGitLabAPIAccess();
translateMixin(Vue);
+Vue.use(VueApollo);
stylesheetsRequireCtx('./application.scss');
stylesheetsRequireCtx('./application_utilities.scss');
diff --git a/tooling/audit_events/docs/templates/audit_event_types.md.erb b/tooling/audit_events/docs/templates/audit_event_types.md.erb
index 9376b3c4fcd..429d341f9a6 100644
--- a/tooling/audit_events/docs/templates/audit_event_types.md.erb
+++ b/tooling/audit_events/docs/templates/audit_event_types.md.erb
@@ -17,18 +17,24 @@ info: "See the Technical Writers assigned to Development Guidelines: https://abo
Please do not edit this file directly. To update this file, run:
bundle exec rake gitlab:audit_event_types:compile_docs
+
+ To make changes to the output of the rake task,
+ edit `tooling/audit_events/docs/templates/audit_event_types.md.erb`.
--->
-# Audit event types **(ULTIMATE)**
+# Audit event types **(PREMIUM ALL)**
Audit event types are used to [filter streamed audit events](index.md#update-event-filters).
-Every audit event is associated with an event type. The association with the event type can mean that an audit event is:
+Every audit event is associated with an event type. Audit event types can allow audit events to be:
+
+- Saved to the database. Available in the Premium and Ultimate tier. You can retrieve audit events associated with these
+ types by using the audit events dashboard or the [audit events API](../../api/audit_events.md).
+- Streamed to external destinations. Available in the Ultimate tier. You can stream audit events associated with these
+ types [to external destinations](../index.md) if a destination is set.
-- Saved to database. Audit events associated with these types are retrievable by using the audit events dashboard or the [audit events API](../../api/audit_events.md).
-- Streamed. Audit events associated with these types are [streamed to external destinations](../index.md) if a
- destination is set.
-- Not streamed. Audit events associated with these types are not streamed to external destinations even if a destination is set.
+Some audit event types don't allow saving audit events to the database. Other audit event types don't allow streaming
+audit events to external destinations.
## Available audit event types
diff --git a/tooling/danger/clickhouse.rb b/tooling/danger/clickhouse.rb
new file mode 100644
index 00000000000..b36e12219ed
--- /dev/null
+++ b/tooling/danger/clickhouse.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Tooling
+ module Danger
+ module Clickhouse
+ def changes
+ helper.changes_by_category[:clickhouse]
+ end
+ end
+ end
+end
diff --git a/tooling/danger/ignored_model_columns.rb b/tooling/danger/ignored_model_columns.rb
new file mode 100644
index 00000000000..50379eed85c
--- /dev/null
+++ b/tooling/danger/ignored_model_columns.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require_relative 'suggestor'
+
+module Tooling
+ module Danger
+ module IgnoredModelColumns
+ include ::Tooling::Danger::Suggestor
+
+ METHODS = %w[remove_column cleanup_concurrent_column_rename cleanup_conversion_of_integer_to_bigint].freeze
+ MIGRATION_FILES_REGEX = %r{^db/(post_)?migrate}
+ MIGRATION_METHODS_REGEX = /^\+\s*(.*\.)?(#{METHODS.join('|')})[(\s]/
+ UP_METHOD_REGEX = /^.+(def\sup)/
+ END_METHOD_REGEX = /^.+(end)/
+ DOC_URL = "https://docs.gitlab.com/ee/development/database/avoiding_downtime_in_migrations.html"
+
+ COMMENT = <<~COMMENT.freeze
+ Column operations, like [dropping](#{DOC_URL}#dropping-columns), [renaming](#{DOC_URL}#renaming-columns) or
+ [primary key conversion](#{DOC_URL}#migrating-integer-primary-keys-to-bigint), require columns to be ignored in
+ the model. This step is necessary because Rails caches the columns and re-uses it in various places across the
+ application. Please ensure that columns are properly ignored in the model.
+ COMMENT
+
+ def add_comment_for_ignored_model_columns
+ migration_files.each do |filename|
+ add_suggestion(filename: filename, regex: MIGRATION_METHODS_REGEX, comment_text: COMMENT)
+ end
+ end
+
+ private
+
+ # This method was overwritten to make use of +up_method_lines+.
+ # It's necessary to only match lines that are inside the +up+ block in a migration file.
+ #
+ # @return [Integer, Nil] the line number - only if the line is from within a +up+ method
+ def find_line_number(file_lines, searched_line, exclude_indexes: [])
+ lines_to_search = up_method_lines(file_lines)
+
+ _, index = file_lines.each_with_index.find do |file_line, index|
+ next unless lines_to_search.include?(index)
+
+ file_line == searched_line && !exclude_indexes.include?(index) # rubocop:disable Rails/NegateInclude
+ end
+
+ index
+ end
+
+ # Return the line numbers from within the up method
+ #
+ # @example
+ # line 0 def up
+ # line 1 cleanup_conversion_of_integer_to_bigint():my_table, :my_column)
+ # line 2 remove_column(:my_table, :my_column)
+ # line 3 other_method
+ # line 4 end
+ #
+ # => [1, 2, 3]
+ def up_method_lines(file_lines)
+ capture_up_block = false
+ up_method_content_lines = []
+
+ file_lines.each_with_index do |content, line_number|
+ capture_up_block = false if capture_up_block && END_METHOD_REGEX.match?(content)
+ up_method_content_lines << line_number if capture_up_block
+ capture_up_block = true if UP_METHOD_REGEX.match?(content)
+ end
+
+ up_method_content_lines
+ end
+
+ def migration_files
+ helper.all_changed_files.grep(MIGRATION_FILES_REGEX)
+ end
+ end
+ end
+end
diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb
index 633c7b57097..d0cea5516ac 100644
--- a/tooling/danger/project_helper.rb
+++ b/tooling/danger/project_helper.rb
@@ -98,8 +98,8 @@ module Tooling
\.gitlab/ci/frontend\.gitlab-ci\.yml
)\z}x => %i[frontend tooling],
- %r{\A((ee|jh)/)?db/(geo/)?(migrate|post_migrate)/} => [:database],
- %r{\A((ee|jh)/)?db/(?!fixtures)[^/]+} => [:database],
+ %r{\A((ee|jh)/)?db/(geo/)?(?!click_house|fixtures)[^/]+} => [:database],
+ %r{\A((ee|jh)/)?db/[^/]+\z} => [:database], # db/ root files
%r{\A((ee|jh)/)?lib/gitlab/(database|background_migration|sql)(/|\.rb)} => [:database, :backend],
%r{\A(app/services/authorized_project_update/find_records_due_for_refresh_service)(/|\.rb)} => [:database, :backend],
%r{\A(app/models/project_authorization|app/services/users/refresh_authorized_projects_service)(/|\.rb)} => [:database, :backend],
diff --git a/tooling/danger/required_stops.rb b/tooling/danger/required_stops.rb
index dcba23021ad..788be5d70e6 100644
--- a/tooling/danger/required_stops.rb
+++ b/tooling/danger/required_stops.rb
@@ -17,8 +17,7 @@ module Tooling
WARNING_COMMENT = <<~COMMENT.freeze
Finalizing data migration might be time consuming and require a [required stop](#{DOC_URL}).
Check the timings of the underlying data migration.
- If possible postpone the finalization to the scheduled required stop.
- If postponing is impossible please create new required stop as documentation suggests.
+ If possible schedule finalization for the first minor version after the next required stop.
COMMENT
def add_comment_for_finalized_migrations
diff --git a/vendor/assets/javascripts/vue-virtual-scroller/src/components/RecycleScroller.vue b/vendor/assets/javascripts/vue-virtual-scroller/src/components/RecycleScroller.vue
index f6838ddbb92..e319b199cb0 100644
--- a/vendor/assets/javascripts/vue-virtual-scroller/src/components/RecycleScroller.vue
+++ b/vendor/assets/javascripts/vue-virtual-scroller/src/components/RecycleScroller.vue
@@ -146,7 +146,7 @@ export default {
const items = this.items
const field = this.sizeField
const minItemSize = this.minItemSize
- let computedMinSize = 10000
+ let computedMinSize = this.buffer
let accumulator = 0
let current
for (let i = 0, l = items.length; i < l; i++) {
diff --git a/vendor/gems/mail-smtp_pool/.gitlab-ci.yml b/vendor/gems/mail-smtp_pool/.gitlab-ci.yml
index 260bc1aaa1f..30bdb77a81c 100644
--- a/vendor/gems/mail-smtp_pool/.gitlab-ci.yml
+++ b/vendor/gems/mail-smtp_pool/.gitlab-ci.yml
@@ -3,8 +3,3 @@ include:
inputs:
gem_name: "mail-smtp_pool"
gem_path_prefix: "vendor/gems/"
-
-rspec:
- parallel:
- matrix:
- - RUBY_VERSION: ["3.0"] # 3.1 & 3.2 aren't supported yet
diff --git a/vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec b/vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec
index 3d9036f19b1..85ff20f4485 100644
--- a/vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec
+++ b/vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
# Please maintain alphabetical order for dependencies
spec.add_runtime_dependency 'connection_pool', '~> 2.0'
- spec.add_runtime_dependency 'mail', '~> 2.7'
+ spec.add_runtime_dependency 'mail', '~> 2.8'
# Please maintain alphabetical order for dev dependencies
spec.add_development_dependency 'rspec', '~> 3.10.0'
diff --git a/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb
index 78426296406..70526a0d696 100644
--- a/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb
+++ b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb
@@ -14,7 +14,7 @@ describe Mail::SMTPPool::Connection do
end
after do
- MockSMTP.clear_deliveries
+ MockSMTP.reset
end
describe '#deliver!' do
@@ -58,7 +58,7 @@ describe Mail::SMTPPool::Connection do
context 'with an SMTP error' do
before do
- expect(mock_smtp).to receive(:rset).once.and_raise(Net::SMTPServerBusy)
+ expect(mock_smtp).to receive(:rset).once.and_raise(Net::SMTPServerBusy, nil)
end
it 'creates a new SMTP connection' do
diff --git a/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb
index bbe5ef8b068..7c47116d0a6 100644
--- a/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb
+++ b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb
@@ -46,7 +46,7 @@ describe Mail::SMTPPool do
end
after do
- MockSMTP.clear_deliveries
+ MockSMTP.reset
end
it 'delivers mail using a connection from the pool' do
diff --git a/vendor/gems/mail-smtp_pool/spec/spec_helper.rb b/vendor/gems/mail-smtp_pool/spec/spec_helper.rb
index 4d339850381..849765e7881 100644
--- a/vendor/gems/mail-smtp_pool/spec/spec_helper.rb
+++ b/vendor/gems/mail-smtp_pool/spec/spec_helper.rb
@@ -2,21 +2,46 @@
require 'mail/smtp_pool'
+# Based on https://github.com/mikel/mail/blob/2.8.1/spec/spec_helper.rb#L73-L155
+class Net::SMTP
+ class << self
+ alias unstubbed_new new
+ end
+
+ def self.new(*args)
+ MockSMTP.new
+ end
+end
+
# Original mockup from ActionMailer
-# Based on https://github.com/mikel/mail/blob/22a7afc23f253319965bf9228a0a430eec94e06d/spec/spec_helper.rb#L74-L138
class MockSMTP
+ attr_accessor :open_timeout, :read_timeout
+
+ def self.reset
+ test = Net::SMTP.unstubbed_new('example.com')
+ @@tls = test.tls?
+ @@starttls = test.starttls?
+
+ @@deliveries = []
+ @started = false
+ end
+
+ reset
+
def self.deliveries
@@deliveries
end
- def self.security
- @@security
+ def self.tls
+ @@tls
+ end
+
+ def self.starttls
+ @@starttls
end
def initialize
- @@deliveries = []
- @@security = nil
- @started = false
+ self.class.reset
end
def sendmail(mail, from, to)
@@ -50,35 +75,29 @@ class MockSMTP
return true
end
- def self.clear_deliveries
- @@deliveries = []
- end
-
- def self.clear_security
- @@security = nil
- end
-
def enable_tls(context)
- raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security && @@security != :enable_tls
- @@security = :enable_tls
+ raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@starttls == :always
+ @@tls = true
context
end
+ def disable_tls
+ @@tls = false
+ end
+
def enable_starttls(context = nil)
- raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security == :enable_tls
- @@security = :enable_starttls
+ raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@tls
+ @@starttls = :always
context
end
def enable_starttls_auto(context)
- raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security == :enable_tls
- @@security = :enable_starttls_auto
+ raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@tls
+ @@starttls = :auto
context
end
-end
-class Net::SMTP
- def self.new(*args)
- MockSMTP.new
+ def disable_starttls
+ @@starttls = false
end
end
diff --git a/vendor/project_templates/typo3_distribution.tar.gz b/vendor/project_templates/typo3_distribution.tar.gz
index 1de92d781af..b25f949011f 100644
--- a/vendor/project_templates/typo3_distribution.tar.gz
+++ b/vendor/project_templates/typo3_distribution.tar.gz
Binary files differ
diff --git a/vite.config.js b/vite.config.js
new file mode 100644
index 00000000000..6ff6cda0288
--- /dev/null
+++ b/vite.config.js
@@ -0,0 +1,106 @@
+import path from 'path';
+import { defineConfig } from 'vite';
+import svgLoader from 'vite-svg-loader';
+import vue from '@vitejs/plugin-vue2';
+import graphql from '@rollup/plugin-graphql';
+import RubyPlugin from 'vite-plugin-ruby';
+import { viteCommonjs } from '@originjs/vite-plugin-commonjs';
+import webpackConfig from './config/webpack.config';
+import {
+ IS_EE,
+ IS_JH,
+ SOURCEGRAPH_PUBLIC_PATH,
+ GITLAB_WEB_IDE_PUBLIC_PATH,
+} from './config/webpack.constants';
+import viteSharedConfig from './config/vite.json';
+
+const aliasArr = Object.entries(webpackConfig.resolve.alias).map(([find, replacement]) => ({
+ find: find.includes('$') ? new RegExp(find) : find,
+ replacement,
+}));
+
+const assetsPath = path.resolve(__dirname, 'app/assets');
+const javascriptsPath = path.resolve(assetsPath, 'javascripts');
+
+const emptyComponent = path.resolve(javascriptsPath, 'vue_shared/components/empty_component.js');
+
+const [rubyPlugin, ...rest] = RubyPlugin();
+
+// We can't use regular 'resolve' which points to sourceCodeDir in vite.json
+// Because we need for '~' alias to resolve to app/assets/javascripts
+// We can't use javascripts folder in sourceCodeDir because we also need to resolve other assets
+// With undefined 'resolve' an '~' alias from Webpack config is used instead
+// See the issue for details: https://github.com/ElMassimo/vite_ruby/issues/237
+const fixedRubyPlugin = [
+ {
+ ...rubyPlugin,
+ config: (...args) => {
+ const originalConfig = rubyPlugin.config(...args);
+ return {
+ ...originalConfig,
+ resolve: undefined,
+ };
+ },
+ },
+ ...rest,
+];
+
+const EE_ALIAS_FALLBACK = [
+ {
+ find: /^ee_component\/(.*)\.vue/,
+ replacement: emptyComponent,
+ },
+];
+
+const JH_ALIAS_FALLBACK = [
+ {
+ find: /^jh_component\/(.*)\.vue/,
+ replacement: emptyComponent,
+ },
+];
+
+export default defineConfig({
+ resolve: {
+ alias: [
+ ...aliasArr,
+ ...(IS_EE ? [] : EE_ALIAS_FALLBACK),
+ ...(IS_JH ? [] : JH_ALIAS_FALLBACK),
+ {
+ find: '~/',
+ replacement: javascriptsPath,
+ },
+ ],
+ },
+ plugins: [
+ fixedRubyPlugin,
+ vue({
+ template: {
+ compilerOptions: {
+ whitespace: 'preserve',
+ },
+ },
+ }),
+ graphql(),
+ svgLoader({
+ defaultImport: 'raw',
+ }),
+ viteCommonjs({
+ include: [path.resolve(javascriptsPath, 'locale/ensure_single_line.cjs')],
+ }),
+ ],
+ define: {
+ IS_EE: IS_EE ? 'window.gon && window.gon.ee' : JSON.stringify(false),
+ IS_JH: IS_JH ? 'window.gon && window.gon.jh' : JSON.stringify(false),
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
+ 'process.env.SOURCEGRAPH_PUBLIC_PATH': JSON.stringify(SOURCEGRAPH_PUBLIC_PATH),
+ 'process.env.GITLAB_WEB_IDE_PUBLIC_PATH': JSON.stringify(GITLAB_WEB_IDE_PUBLIC_PATH),
+ },
+ server: {
+ hmr: {
+ host: viteSharedConfig?.development?.host || 'localhost',
+ // ensure we stay compatible with HTTPS enabled for GDK
+ protocol: 'ws',
+ },
+ https: false,
+ },
+});
diff --git a/workhorse/config_test.go b/workhorse/config_test.go
index a6a1bdd7187..64f0a24d148 100644
--- a/workhorse/config_test.go
+++ b/workhorse/config_test.go
@@ -34,6 +34,7 @@ trusted_cidrs_for_propagation = ["10.0.0.1/8"]
[redis]
password = "redis password"
+SentinelPassword = "sentinel password"
[object_storage]
provider = "test provider"
[image_resizer]
@@ -68,6 +69,7 @@ key = "/path/to/private/key"
// fields in each section; that should happen in the tests of the
// internal/config package.
require.Equal(t, "redis password", cfg.Redis.Password)
+ require.Equal(t, "sentinel password", cfg.Redis.SentinelPassword)
require.Equal(t, "test provider", cfg.ObjectStorageCredentials.Provider)
require.Equal(t, uint32(123), cfg.ImageResizerConfig.MaxScalerProcs, "image resizer max_scaler_procs")
require.Equal(t, []string{"127.0.0.1/8", "192.168.0.1/8"}, cfg.TrustedCIDRsForXForwardedFor)
diff --git a/workhorse/gitaly_integration_test.go b/workhorse/gitaly_integration_test.go
index a7ec0b63b9d..929b9263dfd 100644
--- a/workhorse/gitaly_integration_test.go
+++ b/workhorse/gitaly_integration_test.go
@@ -20,6 +20,8 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"gitlab.com/gitlab-org/gitaly/v16/streamio"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/api"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/gitaly"
@@ -76,27 +78,24 @@ func realGitalyOkBody(t *testing.T, gitalyAddress string) *api.Response {
}
func ensureGitalyRepository(t *testing.T, apiResponse *api.Response) error {
- ctx, namespace, err := gitaly.NewNamespaceClient(
- context.Background(),
- apiResponse.GitalyServer,
- )
-
- if err != nil {
- return err
- }
- ctx, repository, err := gitaly.NewRepositoryClient(ctx, apiResponse.GitalyServer)
+ ctx, repository, err := gitaly.NewRepositoryClient(context.Background(), apiResponse.GitalyServer)
if err != nil {
return err
}
// Remove the repository if it already exists, for consistency
- rmNsReq := &gitalypb.RemoveNamespaceRequest{
- StorageName: apiResponse.Repository.StorageName,
- Name: apiResponse.Repository.RelativePath,
- }
- _, err = namespace.RemoveNamespace(ctx, rmNsReq)
- if err != nil {
- return err
+ if _, err := repository.RepositoryServiceClient.RemoveRepository(ctx, &gitalypb.RemoveRepositoryRequest{
+ Repository: &gitalypb.Repository{
+ StorageName: apiResponse.Repository.StorageName,
+ RelativePath: apiResponse.Repository.RelativePath,
+ },
+ }); err != nil {
+ status, ok := status.FromError(err)
+ if !ok || !(status.Code() == codes.NotFound && status.Message() == "repository does not exist") {
+ return fmt.Errorf("remove repository: %w", err)
+ }
+
+ // Repository didn't exist.
}
stream, err := repository.CreateRepositoryFromBundle(ctx)
@@ -139,13 +138,13 @@ func TestAllowedClone(t *testing.T) {
defer ws.Close()
// Do the git clone
- require.NoError(t, os.RemoveAll(scratchDir))
- cloneCmd := exec.Command("git", "clone", fmt.Sprintf("%s/%s", ws.URL, testRepo), checkoutDir)
+ tmpDir := t.TempDir()
+ cloneCmd := exec.Command("git", "clone", fmt.Sprintf("%s/%s", ws.URL, testRepo), tmpDir)
runOrFail(t, cloneCmd)
// We may have cloned an 'empty' repository, 'git log' will fail in it
logCmd := exec.Command("git", "log", "-1", "--oneline")
- logCmd.Dir = checkoutDir
+ logCmd.Dir = tmpDir
runOrFail(t, logCmd)
})
}
@@ -167,13 +166,13 @@ func TestAllowedShallowClone(t *testing.T) {
defer ws.Close()
// Shallow git clone (depth 1)
- require.NoError(t, os.RemoveAll(scratchDir))
- cloneCmd := exec.Command("git", "clone", "--depth", "1", fmt.Sprintf("%s/%s", ws.URL, testRepo), checkoutDir)
+ tmpDir := t.TempDir()
+ cloneCmd := exec.Command("git", "clone", "--depth", "1", fmt.Sprintf("%s/%s", ws.URL, testRepo), tmpDir)
runOrFail(t, cloneCmd)
// We may have cloned an 'empty' repository, 'git log' will fail in it
logCmd := exec.Command("git", "log", "-1", "--oneline")
- logCmd.Dir = checkoutDir
+ logCmd.Dir = tmpDir
runOrFail(t, logCmd)
})
}
@@ -194,9 +193,14 @@ func TestAllowedPush(t *testing.T) {
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
+ // Do the git clone
+ tmpDir := t.TempDir()
+ cloneCmd := exec.Command("git", "clone", fmt.Sprintf("%s/%s", ws.URL, testRepo), tmpDir)
+ runOrFail(t, cloneCmd)
+
// Perform the git push
pushCmd := exec.Command("git", "push", fmt.Sprintf("%s/%s", ws.URL, testRepo), fmt.Sprintf("master:%s", newBranch()))
- pushCmd.Dir = checkoutDir
+ pushCmd.Dir = tmpDir
runOrFail(t, pushCmd)
})
}
@@ -249,7 +253,7 @@ func TestAllowedGetGitArchive(t *testing.T) {
apiResponse := realGitalyOkBody(t, gitalyAddress)
require.NoError(t, ensureGitalyRepository(t, apiResponse))
- archivePath := path.Join(scratchDir, "my/path")
+ archivePath := path.Join(t.TempDir(), "my/path")
archivePrefix := "repo-1"
msg := serializedProtoMessage("GetArchiveRequest", &gitalypb.GetArchiveRequest{
@@ -296,7 +300,7 @@ func TestAllowedGetGitArchiveOldPayload(t *testing.T) {
repo := &apiResponse.Repository
require.NoError(t, ensureGitalyRepository(t, apiResponse))
- archivePath := path.Join(scratchDir, "my/path")
+ archivePath := path.Join(t.TempDir(), "my/path")
archivePrefix := "repo-1"
jsonParams := fmt.Sprintf(
diff --git a/workhorse/gitaly_test.go b/workhorse/gitaly_test.go
index 6bbc67228c3..270c40cb4bc 100644
--- a/workhorse/gitaly_test.go
+++ b/workhorse/gitaly_test.go
@@ -31,9 +31,6 @@ import (
)
func TestFailedCloneNoGitaly(t *testing.T) {
- // Prepare clone directory
- require.NoError(t, os.RemoveAll(scratchDir))
-
authBody := &api.Response{
GL_ID: "user-123",
GL_USERNAME: "username",
@@ -48,7 +45,7 @@ func TestFailedCloneNoGitaly(t *testing.T) {
defer ws.Close()
// Do the git clone
- cloneCmd := exec.Command("git", "clone", fmt.Sprintf("%s/%s", ws.URL, testRepo), checkoutDir)
+ cloneCmd := exec.Command("git", "clone", fmt.Sprintf("%s/%s", ws.URL, testRepo), t.TempDir())
out, err := cloneCmd.CombinedOutput()
t.Log(string(out))
require.Error(t, err, "git clone should have failed")
@@ -632,7 +629,7 @@ func TestGetArchiveProxiedToGitalySuccessfully(t *testing.T) {
archivePath string
cacheDisabled bool
}{
- {archivePath: path.Join(scratchDir, "my/path"), cacheDisabled: false},
+ {archivePath: path.Join(t.TempDir(), "my/path"), cacheDisabled: false},
{archivePath: "/var/empty/my/path", cacheDisabled: true},
}
@@ -668,7 +665,7 @@ func TestGetArchiveProxiedToGitalyInterruptedStream(t *testing.T) {
archivePath := "my/path"
archivePrefix := "repo-1"
jsonParams := fmt.Sprintf(`{"GitalyServer":{"Address":"%s","Token":""},"GitalyRepository":{"storage_name":"%s","relative_path":"%s"},"ArchivePath":"%s","ArchivePrefix":"%s","CommitId":"%s"}`,
- gitalyAddress, repoStorage, repoRelativePath, path.Join(scratchDir, archivePath), archivePrefix, oid)
+ gitalyAddress, repoStorage, repoRelativePath, path.Join(t.TempDir(), archivePath), archivePrefix, oid)
resp, _, err := doSendDataRequest("/archive.tar.gz", "git-archive", jsonParams)
require.NoError(t, err)
@@ -850,7 +847,13 @@ type combinedServer struct {
}
func startGitalyServer(t *testing.T, finalMessageCode codes.Code) (*combinedServer, string) {
- socketPath := path.Join(scratchDir, fmt.Sprintf("gitaly-%d.sock", rand.Int()))
+ tmpFolder, err := os.MkdirTemp("", "gitaly")
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ os.RemoveAll(tmpFolder)
+ })
+
+ socketPath := path.Join(tmpFolder, fmt.Sprintf("gitaly-%d.sock", rand.Int()))
if err := os.Remove(socketPath); err != nil && !os.IsNotExist(err) {
t.Fatal(err)
}
diff --git a/workhorse/go.mod b/workhorse/go.mod
index 17ae3ce12ec..18699787e6e 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -15,13 +15,13 @@ require (
github.com/golang/protobuf v1.5.3
github.com/gomodule/redigo v2.0.0+incompatible
github.com/gorilla/websocket v1.5.0
- github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/johannesboyne/gofakes3 v0.0.0-20230506070712-04da935ef877
github.com/jpillora/backoff v1.0.0
github.com/mitchellh/copystructure v1.2.0
github.com/prometheus/client_golang v1.16.0
github.com/rafaeljusto/redigomock/v3 v3.1.2
+ github.com/redis/go-redis/v9 v9.1.0
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
github.com/sirupsen/logrus v1.9.3
github.com/smartystreets/goconvey v1.7.2
@@ -65,6 +65,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/client9/reopen v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
@@ -78,6 +79,7 @@ require (
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
github.com/googleapis/gax-go/v2 v2.11.0 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
+ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
diff --git a/workhorse/go.sum b/workhorse/go.sum
index f3ceee8b5e8..5163d055187 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -869,6 +869,8 @@ github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0=
+github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
@@ -1068,6 +1070,8 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/digitalocean/godo v1.78.0/go.mod h1:GBmu8MkjZmNARE7IXRPmkbbnocNN8+uBm0xbEVw2LCs=
@@ -2047,6 +2051,8 @@ github.com/rafaeljusto/redigomock/v3 v3.1.2 h1:B4Y0XJQiPjpwYmkH55aratKX1VfR+JRqz
github.com/rafaeljusto/redigomock/v3 v3.1.2/go.mod h1:F9zPqz8rMriScZkPtUiLJoLruYcpGo/XXREpeyasREM=
github.com/rakyll/embedmd v0.0.0-20171029212350-c8060a0752a2/go.mod h1:7jOTMgqac46PZcF54q6l2hkLEG8op93fZu61KmxWDV4=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
+github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
diff --git a/workhorse/internal/config/config.go b/workhorse/internal/config/config.go
index 687986974a3..3b928d42fe1 100644
--- a/workhorse/internal/config/config.go
+++ b/workhorse/internal/config/config.go
@@ -83,13 +83,14 @@ type GoogleCredentials struct {
}
type RedisConfig struct {
- URL TomlURL
- Sentinel []TomlURL
- SentinelMaster string
- Password string
- DB *int
- MaxIdle *int
- MaxActive *int
+ URL TomlURL
+ Sentinel []TomlURL
+ SentinelMaster string
+ SentinelPassword string
+ Password string
+ DB *int
+ MaxIdle *int
+ MaxActive *int
}
type ImageResizerConfig struct {
diff --git a/workhorse/internal/dependencyproxy/dependencyproxy.go b/workhorse/internal/dependencyproxy/dependencyproxy.go
index e170b001806..dbea3c29aec 100644
--- a/workhorse/internal/dependencyproxy/dependencyproxy.go
+++ b/workhorse/internal/dependencyproxy/dependencyproxy.go
@@ -23,8 +23,15 @@ type Injector struct {
}
type entryParams struct {
- Url string
- Header http.Header
+ Url string
+ Headers http.Header
+ UploadConfig uploadConfig
+}
+
+type uploadConfig struct {
+ Headers http.Header
+ Method string
+ Url string
}
type nullResponseWriter struct {
@@ -55,7 +62,13 @@ func (p *Injector) SetUploadHandler(uploadHandler http.Handler) {
}
func (p *Injector) Inject(w http.ResponseWriter, r *http.Request, sendData string) {
- dependencyResponse, err := p.fetchUrl(r.Context(), sendData)
+ params, err := p.unpackParams(sendData)
+ if err != nil {
+ fail.Request(w, r, err)
+ return
+ }
+
+ dependencyResponse, err := p.fetchUrl(r.Context(), params)
if err != nil {
fail.Request(w, r, err)
return
@@ -70,11 +83,10 @@ func (p *Injector) Inject(w http.ResponseWriter, r *http.Request, sendData strin
w.Header().Set("Content-Length", dependencyResponse.Header.Get("Content-Length"))
teeReader := io.TeeReader(dependencyResponse.Body, w)
- saveFileRequest, err := http.NewRequestWithContext(r.Context(), "POST", r.URL.String()+"/upload", teeReader)
+ saveFileRequest, err := p.newUploadRequest(r.Context(), params, r, teeReader)
if err != nil {
fail.Request(w, r, fmt.Errorf("dependency proxy: failed to create request: %w", err))
}
- saveFileRequest.Header = r.Header.Clone()
// forward headers from dependencyResponse to rails and client
for key, values := range dependencyResponse.Header {
@@ -100,17 +112,56 @@ func (p *Injector) Inject(w http.ResponseWriter, r *http.Request, sendData strin
}
}
-func (p *Injector) fetchUrl(ctx context.Context, sendData string) (*http.Response, error) {
+func (p *Injector) fetchUrl(ctx context.Context, params *entryParams) (*http.Response, error) {
+ r, err := http.NewRequestWithContext(ctx, "GET", params.Url, nil)
+ if err != nil {
+ return nil, fmt.Errorf("dependency proxy: failed to fetch dependency: %w", err)
+ }
+ r.Header = params.Headers
+
+ return httpClient.Do(r)
+}
+
+func (p *Injector) newUploadRequest(ctx context.Context, params *entryParams, originalRequest *http.Request, body io.Reader) (*http.Request, error) {
+ method := p.uploadMethodFrom(params)
+ uploadUrl := p.uploadUrlFrom(params, originalRequest)
+ request, err := http.NewRequestWithContext(ctx, method, uploadUrl, body)
+ if err != nil {
+ return nil, err
+ }
+
+ request.Header = originalRequest.Header.Clone()
+
+ for key, values := range params.UploadConfig.Headers {
+ request.Header.Del(key)
+ for _, value := range values {
+ request.Header.Add(key, value)
+ }
+ }
+
+ return request, nil
+}
+
+func (p *Injector) unpackParams(sendData string) (*entryParams, error) {
var params entryParams
if err := p.Unpack(&params, sendData); err != nil {
return nil, fmt.Errorf("dependency proxy: unpack sendData: %v", err)
}
- r, err := http.NewRequestWithContext(ctx, "GET", params.Url, nil)
- if err != nil {
- return nil, fmt.Errorf("dependency proxy: failed to fetch dependency: %v", err)
+ return &params, nil
+}
+
+func (p *Injector) uploadMethodFrom(params *entryParams) string {
+ if params.UploadConfig.Method != "" {
+ return params.UploadConfig.Method
}
- r.Header = params.Header
+ return http.MethodPost
+}
- return httpClient.Do(r)
+func (p *Injector) uploadUrlFrom(params *entryParams, originalRequest *http.Request) string {
+ if params.UploadConfig.Url != "" {
+ return params.UploadConfig.Url
+ }
+
+ return originalRequest.URL.String() + "/upload"
}
diff --git a/workhorse/internal/dependencyproxy/dependencyproxy_test.go b/workhorse/internal/dependencyproxy/dependencyproxy_test.go
index d893ddc500f..bee74ce0a9e 100644
--- a/workhorse/internal/dependencyproxy/dependencyproxy_test.go
+++ b/workhorse/internal/dependencyproxy/dependencyproxy_test.go
@@ -2,6 +2,7 @@ package dependencyproxy
import (
"encoding/base64"
+ "encoding/json"
"fmt"
"io"
"net/http"
@@ -149,6 +150,158 @@ func TestSuccessfullRequest(t *testing.T) {
require.Equal(t, dockerContentDigest, response.Header().Get("Docker-Content-Digest"))
}
+func TestValidUploadConfiguration(t *testing.T) {
+ content := []byte("content")
+ contentLength := strconv.Itoa(len(content))
+ contentType := "text/plain"
+ testHeader := "test-received-url"
+ originResourceServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set(testHeader, r.URL.Path)
+ w.Header().Set("Content-Length", contentLength)
+ w.Header().Set("Content-Type", contentType)
+ w.Write(content)
+ }))
+
+ testCases := []struct {
+ desc string
+ uploadConfig *uploadConfig
+ expectedConfig uploadConfig
+ }{
+ {
+ desc: "with the default values",
+ expectedConfig: uploadConfig{
+ Method: http.MethodPost,
+ Url: "/target/upload",
+ },
+ }, {
+ desc: "with overriden method",
+ uploadConfig: &uploadConfig{
+ Method: http.MethodPut,
+ },
+ expectedConfig: uploadConfig{
+ Method: http.MethodPut,
+ Url: "/target/upload",
+ },
+ }, {
+ desc: "with overriden url",
+ uploadConfig: &uploadConfig{
+ Url: "http://test.org/overriden/upload",
+ },
+ expectedConfig: uploadConfig{
+ Method: http.MethodPost,
+ Url: "http://test.org/overriden/upload",
+ },
+ }, {
+ desc: "with overriden headers",
+ uploadConfig: &uploadConfig{
+ Headers: map[string][]string{"Private-Token": {"123456789"}},
+ },
+ expectedConfig: uploadConfig{
+ Headers: map[string][]string{"Private-Token": {"123456789"}},
+ Method: http.MethodPost,
+ Url: "/target/upload",
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ uploadHandler := &fakeUploadHandler{
+ handler: func(w http.ResponseWriter, r *http.Request) {
+ require.Equal(t, tc.expectedConfig.Url, r.URL.String())
+ require.Equal(t, tc.expectedConfig.Method, r.Method)
+
+ if tc.expectedConfig.Headers != nil {
+ for k, v := range tc.expectedConfig.Headers {
+ require.Equal(t, v, r.Header[k])
+ }
+ }
+
+ w.WriteHeader(200)
+ },
+ }
+
+ injector := NewInjector()
+ injector.SetUploadHandler(uploadHandler)
+
+ sendData := map[string]interface{}{
+ "Token": "token",
+ "Url": originResourceServer.URL + `/remote/file`,
+ }
+
+ if tc.uploadConfig != nil {
+ sendData["UploadConfig"] = tc.uploadConfig
+ }
+
+ sendDataJsonString, err := json.Marshal(sendData)
+ require.NoError(t, err)
+
+ response := makeRequest(injector, string(sendDataJsonString))
+
+ //checking the response
+ require.Equal(t, 200, response.Code)
+ require.Equal(t, string(content), response.Body.String())
+ // checking remote file request
+ require.Equal(t, "/remote/file", response.Header().Get(testHeader))
+ })
+ }
+}
+
+func TestInvalidUploadConfiguration(t *testing.T) {
+ baseSendData := map[string]interface{}{
+ "Token": "token",
+ "Url": "http://remote.dev/remote/file",
+ }
+ testCases := []struct {
+ desc string
+ sendData map[string]interface{}
+ }{
+ {
+ desc: "with an invalid overriden method",
+ sendData: mergeMap(baseSendData, map[string]interface{}{
+ "UploadConfig": map[string]string{
+ "Method": "TEAPOT",
+ },
+ }),
+ }, {
+ desc: "with an invalid url",
+ sendData: mergeMap(baseSendData, map[string]interface{}{
+ "UploadConfig": map[string]string{
+ "Url": "invalid_url",
+ },
+ }),
+ }, {
+ desc: "with an invalid headers",
+ sendData: mergeMap(baseSendData, map[string]interface{}{
+ "UploadConfig": map[string]interface{}{
+ "Headers": map[string]string{
+ "Private-Token": "not_an_array",
+ },
+ },
+ }),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ sendDataJsonString, err := json.Marshal(tc.sendData)
+ require.NoError(t, err)
+
+ response := makeRequest(NewInjector(), string(sendDataJsonString))
+
+ require.Equal(t, 500, response.Code)
+ require.Equal(t, "Internal Server Error\n", response.Body.String())
+ })
+ }
+}
+
+func mergeMap(from map[string]interface{}, into map[string]interface{}) map[string]interface{} {
+ for k, v := range from {
+ into[k] = v
+ }
+ return into
+}
+
func TestIncorrectSendData(t *testing.T) {
response := makeRequest(NewInjector(), "")
diff --git a/workhorse/internal/gitaly/gitaly.go b/workhorse/internal/gitaly/gitaly.go
index d9dbbdbb605..e4fbad17017 100644
--- a/workhorse/internal/gitaly/gitaly.go
+++ b/workhorse/internal/gitaly/gitaly.go
@@ -7,7 +7,6 @@ import (
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 https://gitlab.com/gitlab-org/gitlab/-/issues/324868
"github.com/golang/protobuf/proto" //lint:ignore SA1019 https://gitlab.com/gitlab-org/gitlab/-/issues/324868
- grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
@@ -114,16 +113,6 @@ func NewRepositoryClient(ctx context.Context, server api.GitalyServer) (context.
return withOutgoingMetadata(ctx, server), &RepositoryClient{grpcClient}, nil
}
-// NewNamespaceClient is only used by the Gitaly integration tests at present
-func NewNamespaceClient(ctx context.Context, server api.GitalyServer) (context.Context, *NamespaceClient, error) {
- conn, err := getOrCreateConnection(server)
- if err != nil {
- return nil, nil, err
- }
- grpcClient := gitalypb.NewNamespaceServiceClient(conn)
- return withOutgoingMetadata(ctx, server), &NamespaceClient{grpcClient}, nil
-}
-
func NewDiffClient(ctx context.Context, server api.GitalyServer) (context.Context, *DiffClient, error) {
conn, err := getOrCreateConnection(server)
if err != nil {
@@ -173,23 +162,19 @@ func CloseConnections() {
func newConnection(server api.GitalyServer) (*grpc.ClientConn, error) {
connOpts := append(gitalyclient.DefaultDialOpts,
grpc.WithPerRPCCredentials(gitalyauth.RPCCredentialsV2(server.Token)),
- grpc.WithStreamInterceptor(
- grpc_middleware.ChainStreamClient(
- grpctracing.StreamClientTracingInterceptor(),
- grpc_prometheus.StreamClientInterceptor,
- grpccorrelation.StreamClientCorrelationInterceptor(
- grpccorrelation.WithClientName("gitlab-workhorse"),
- ),
+ grpc.WithChainStreamInterceptor(
+ grpctracing.StreamClientTracingInterceptor(),
+ grpc_prometheus.StreamClientInterceptor,
+ grpccorrelation.StreamClientCorrelationInterceptor(
+ grpccorrelation.WithClientName("gitlab-workhorse"),
),
),
- grpc.WithUnaryInterceptor(
- grpc_middleware.ChainUnaryClient(
- grpctracing.UnaryClientTracingInterceptor(),
- grpc_prometheus.UnaryClientInterceptor,
- grpccorrelation.UnaryClientCorrelationInterceptor(
- grpccorrelation.WithClientName("gitlab-workhorse"),
- ),
+ grpc.WithChainUnaryInterceptor(
+ grpctracing.UnaryClientTracingInterceptor(),
+ grpc_prometheus.UnaryClientInterceptor,
+ grpccorrelation.UnaryClientCorrelationInterceptor(
+ grpccorrelation.WithClientName("gitlab-workhorse"),
),
),
diff --git a/workhorse/internal/gitaly/gitaly_test.go b/workhorse/internal/gitaly/gitaly_test.go
index 0ea5da20da3..04d3a0a79aa 100644
--- a/workhorse/internal/gitaly/gitaly_test.go
+++ b/workhorse/internal/gitaly/gitaly_test.go
@@ -46,15 +46,6 @@ func TestNewRepositoryClient(t *testing.T) {
testOutgoingMetadata(t, ctx)
}
-func TestNewNamespaceClient(t *testing.T) {
- ctx, _, err := NewNamespaceClient(
- context.Background(),
- serverFixture(),
- )
- require.NoError(t, err)
- testOutgoingMetadata(t, ctx)
-}
-
func TestNewDiffClient(t *testing.T) {
ctx, _, err := NewDiffClient(
context.Background(),
diff --git a/workhorse/internal/gitaly/namespace.go b/workhorse/internal/gitaly/namespace.go
deleted file mode 100644
index a9bc2d07a7e..00000000000
--- a/workhorse/internal/gitaly/namespace.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package gitaly
-
-import "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
-
-// NamespaceClient encapsulates NamespaceService calls
-type NamespaceClient struct {
- gitalypb.NamespaceServiceClient
-}
diff --git a/workhorse/internal/goredis/goredis.go b/workhorse/internal/goredis/goredis.go
new file mode 100644
index 00000000000..13a9d4cc34f
--- /dev/null
+++ b/workhorse/internal/goredis/goredis.go
@@ -0,0 +1,186 @@
+package goredis
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "time"
+
+ redis "github.com/redis/go-redis/v9"
+
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/config"
+ _ "gitlab.com/gitlab-org/gitlab/workhorse/internal/helper"
+ internalredis "gitlab.com/gitlab-org/gitlab/workhorse/internal/redis"
+)
+
+var (
+ rdb *redis.Client
+ // found in https://github.com/redis/go-redis/blob/c7399b6a17d7d3e2a57654528af91349f2468529/sentinel.go#L626
+ errSentinelMasterAddr error = errors.New("redis: all sentinels specified in configuration are unreachable")
+)
+
+const (
+ // Max Idle Connections in the pool.
+ defaultMaxIdle = 1
+ // Max Active Connections in the pool.
+ defaultMaxActive = 1
+ // Timeout for Read operations on the pool. 1 second is technically overkill,
+ // it's just for sanity.
+ defaultReadTimeout = 1 * time.Second
+ // Timeout for Write operations on the pool. 1 second is technically overkill,
+ // it's just for sanity.
+ defaultWriteTimeout = 1 * time.Second
+ // Timeout before killing Idle connections in the pool. 3 minutes seemed good.
+ // If you _actually_ hit this timeout often, you should consider turning of
+ // redis-support since it's not necessary at that point...
+ defaultIdleTimeout = 3 * time.Minute
+)
+
+// createDialer references https://github.com/redis/go-redis/blob/b1103e3d436b6fe98813ecbbe1f99dc8d59b06c9/options.go#L214
+// it intercepts the error and tracks it via a Prometheus counter
+func createDialer(sentinels []string) func(ctx context.Context, network, addr string) (net.Conn, error) {
+ return func(ctx context.Context, network, addr string) (net.Conn, error) {
+ var isSentinel bool
+ for _, sentinelAddr := range sentinels {
+ if sentinelAddr == addr {
+ isSentinel = true
+ break
+ }
+ }
+
+ dialTimeout := 5 * time.Second // go-redis default
+ destination := "redis"
+ if isSentinel {
+ // This timeout is recommended for Sentinel-support according to the guidelines.
+ // https://redis.io/topics/sentinel-clients#redis-service-discovery-via-sentinel
+ // For every address it should try to connect to the Sentinel,
+ // using a short timeout (in the order of a few hundreds of milliseconds).
+ destination = "sentinel"
+ dialTimeout = 500 * time.Millisecond
+ }
+
+ netDialer := &net.Dialer{
+ Timeout: dialTimeout,
+ KeepAlive: 5 * time.Minute,
+ }
+
+ conn, err := netDialer.DialContext(ctx, network, addr)
+ if err != nil {
+ internalredis.ErrorCounter.WithLabelValues("dial", destination).Inc()
+ } else {
+ if !isSentinel {
+ internalredis.TotalConnections.Inc()
+ }
+ }
+
+ return conn, err
+ }
+}
+
+// implements the redis.Hook interface for instrumentation
+type sentinelInstrumentationHook struct{}
+
+func (s sentinelInstrumentationHook) DialHook(next redis.DialHook) redis.DialHook {
+ return func(ctx context.Context, network, addr string) (net.Conn, error) {
+ conn, err := next(ctx, network, addr)
+ if err != nil && err.Error() == errSentinelMasterAddr.Error() {
+ // check for non-dialer error
+ internalredis.ErrorCounter.WithLabelValues("master", "sentinel").Inc()
+ }
+ return conn, err
+ }
+}
+
+func (s sentinelInstrumentationHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
+ return func(ctx context.Context, cmd redis.Cmder) error {
+ return next(ctx, cmd)
+ }
+}
+
+func (s sentinelInstrumentationHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {
+ return func(ctx context.Context, cmds []redis.Cmder) error {
+ return next(ctx, cmds)
+ }
+}
+
+func GetRedisClient() *redis.Client {
+ return rdb
+}
+
+// Configure redis-connection
+func Configure(cfg *config.RedisConfig) error {
+ if cfg == nil {
+ return nil
+ }
+
+ var err error
+
+ if len(cfg.Sentinel) > 0 {
+ rdb = configureSentinel(cfg)
+ } else {
+ rdb, err = configureRedis(cfg)
+ }
+
+ return err
+}
+
+func configureRedis(cfg *config.RedisConfig) (*redis.Client, error) {
+ if cfg.URL.Scheme == "tcp" {
+ cfg.URL.Scheme = "redis"
+ }
+
+ opt, err := redis.ParseURL(cfg.URL.String())
+ if err != nil {
+ return nil, err
+ }
+
+ opt.DB = getOrDefault(cfg.DB, 0)
+ opt.Password = cfg.Password
+
+ opt.PoolSize = getOrDefault(cfg.MaxActive, defaultMaxActive)
+ opt.MaxIdleConns = getOrDefault(cfg.MaxIdle, defaultMaxIdle)
+ opt.ConnMaxIdleTime = defaultIdleTimeout
+ opt.ReadTimeout = defaultReadTimeout
+ opt.WriteTimeout = defaultWriteTimeout
+
+ opt.Dialer = createDialer([]string{})
+
+ return redis.NewClient(opt), nil
+}
+
+func configureSentinel(cfg *config.RedisConfig) *redis.Client {
+ sentinels := make([]string, len(cfg.Sentinel))
+ for i := range cfg.Sentinel {
+ sentinelDetails := cfg.Sentinel[i]
+ sentinels[i] = fmt.Sprintf("%s:%s", sentinelDetails.Hostname(), sentinelDetails.Port())
+ }
+
+ client := redis.NewFailoverClient(&redis.FailoverOptions{
+ MasterName: cfg.SentinelMaster,
+ SentinelAddrs: sentinels,
+ Password: cfg.Password,
+ SentinelPassword: cfg.SentinelPassword,
+ DB: getOrDefault(cfg.DB, 0),
+
+ PoolSize: getOrDefault(cfg.MaxActive, defaultMaxActive),
+ MaxIdleConns: getOrDefault(cfg.MaxIdle, defaultMaxIdle),
+ ConnMaxIdleTime: defaultIdleTimeout,
+
+ ReadTimeout: defaultReadTimeout,
+ WriteTimeout: defaultWriteTimeout,
+
+ Dialer: createDialer(sentinels),
+ })
+
+ client.AddHook(sentinelInstrumentationHook{})
+
+ return client
+}
+
+func getOrDefault(ptr *int, val int) int {
+ if ptr != nil {
+ return *ptr
+ }
+ return val
+}
diff --git a/workhorse/internal/goredis/goredis_test.go b/workhorse/internal/goredis/goredis_test.go
new file mode 100644
index 00000000000..6b281229ea4
--- /dev/null
+++ b/workhorse/internal/goredis/goredis_test.go
@@ -0,0 +1,107 @@
+package goredis
+
+import (
+ "context"
+ "net"
+ "sync/atomic"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/config"
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/helper"
+)
+
+func mockRedisServer(t *testing.T, connectReceived *atomic.Value) string {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+
+ require.Nil(t, err)
+
+ go func() {
+ defer ln.Close()
+ conn, err := ln.Accept()
+ require.Nil(t, err)
+ connectReceived.Store(true)
+ conn.Write([]byte("OK\n"))
+ }()
+
+ return ln.Addr().String()
+}
+
+func TestConfigureNoConfig(t *testing.T) {
+ rdb = nil
+ Configure(nil)
+ require.Nil(t, rdb, "rdb client should be nil")
+}
+
+func TestConfigureValidConfigX(t *testing.T) {
+ testCases := []struct {
+ scheme string
+ }{
+ {
+ scheme: "redis",
+ },
+ {
+ scheme: "tcp",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.scheme, func(t *testing.T) {
+ connectReceived := atomic.Value{}
+ a := mockRedisServer(t, &connectReceived)
+
+ parsedURL := helper.URLMustParse(tc.scheme + "://" + a)
+ cfg := &config.RedisConfig{URL: config.TomlURL{URL: *parsedURL}}
+
+ Configure(cfg)
+
+ require.NotNil(t, GetRedisClient().Conn(), "Pool should not be nil")
+
+ // goredis initialise connections lazily
+ rdb.Ping(context.Background())
+ require.True(t, connectReceived.Load().(bool))
+
+ rdb = nil
+ })
+ }
+}
+
+func TestConnectToSentinel(t *testing.T) {
+ testCases := []struct {
+ scheme string
+ }{
+ {
+ scheme: "redis",
+ },
+ {
+ scheme: "tcp",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.scheme, func(t *testing.T) {
+ connectReceived := atomic.Value{}
+ a := mockRedisServer(t, &connectReceived)
+
+ addrs := []string{tc.scheme + "://" + a}
+ var sentinelUrls []config.TomlURL
+
+ for _, a := range addrs {
+ parsedURL := helper.URLMustParse(a)
+ sentinelUrls = append(sentinelUrls, config.TomlURL{URL: *parsedURL})
+ }
+
+ cfg := &config.RedisConfig{Sentinel: sentinelUrls}
+ Configure(cfg)
+
+ require.NotNil(t, GetRedisClient().Conn(), "Pool should not be nil")
+
+ // goredis initialise connections lazily
+ rdb.Ping(context.Background())
+ require.True(t, connectReceived.Load().(bool))
+
+ rdb = nil
+ })
+ }
+}
diff --git a/workhorse/internal/goredis/keywatcher.go b/workhorse/internal/goredis/keywatcher.go
new file mode 100644
index 00000000000..741bfb17652
--- /dev/null
+++ b/workhorse/internal/goredis/keywatcher.go
@@ -0,0 +1,236 @@
+package goredis
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/jpillora/backoff"
+ "github.com/redis/go-redis/v9"
+
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/log"
+ internalredis "gitlab.com/gitlab-org/gitlab/workhorse/internal/redis"
+)
+
+type KeyWatcher struct {
+ mu sync.Mutex
+ subscribers map[string][]chan string
+ shutdown chan struct{}
+ reconnectBackoff backoff.Backoff
+ redisConn *redis.Client
+ conn *redis.PubSub
+}
+
+func NewKeyWatcher() *KeyWatcher {
+ return &KeyWatcher{
+ shutdown: make(chan struct{}),
+ reconnectBackoff: backoff.Backoff{
+ Min: 100 * time.Millisecond,
+ Max: 60 * time.Second,
+ Factor: 2,
+ Jitter: true,
+ },
+ }
+}
+
+const channelPrefix = "workhorse:notifications:"
+
+func countAction(action string) { internalredis.TotalActions.WithLabelValues(action).Add(1) }
+
+func (kw *KeyWatcher) receivePubSubStream(ctx context.Context, pubsub *redis.PubSub) error {
+ kw.mu.Lock()
+ // We must share kw.conn with the goroutines that call SUBSCRIBE and
+ // UNSUBSCRIBE because Redis pubsub subscriptions are tied to the
+ // connection.
+ kw.conn = pubsub
+ kw.mu.Unlock()
+
+ defer func() {
+ kw.mu.Lock()
+ defer kw.mu.Unlock()
+ kw.conn.Close()
+ kw.conn = nil
+
+ // Reset kw.subscribers because it is tied to Redis server side state of
+ // kw.conn and we just closed that connection.
+ for _, chans := range kw.subscribers {
+ for _, ch := range chans {
+ close(ch)
+ internalredis.KeyWatchers.Dec()
+ }
+ }
+ kw.subscribers = nil
+ }()
+
+ for {
+ msg, err := kw.conn.Receive(ctx)
+ if err != nil {
+ log.WithError(fmt.Errorf("keywatcher: pubsub receive: %v", err)).Error()
+ return nil
+ }
+
+ switch msg := msg.(type) {
+ case *redis.Subscription:
+ internalredis.RedisSubscriptions.Set(float64(msg.Count))
+ case *redis.Pong:
+ // Ignore.
+ case *redis.Message:
+ internalredis.TotalMessages.Inc()
+ internalredis.ReceivedBytes.Add(float64(len(msg.Payload)))
+ if strings.HasPrefix(msg.Channel, channelPrefix) {
+ kw.notifySubscribers(msg.Channel[len(channelPrefix):], string(msg.Payload))
+ }
+ default:
+ log.WithError(fmt.Errorf("keywatcher: unknown: %T", msg)).Error()
+ return nil
+ }
+ }
+}
+
+func (kw *KeyWatcher) Process(client *redis.Client) {
+ log.Info("keywatcher: starting process loop")
+
+ ctx := context.Background() // lint:allow context.Background
+ kw.mu.Lock()
+ kw.redisConn = client
+ kw.mu.Unlock()
+
+ for {
+ pubsub := client.Subscribe(ctx, []string{}...)
+ if err := pubsub.Ping(ctx); err != nil {
+ log.WithError(fmt.Errorf("keywatcher: %v", err)).Error()
+ time.Sleep(kw.reconnectBackoff.Duration())
+ continue
+ }
+
+ kw.reconnectBackoff.Reset()
+
+ if err := kw.receivePubSubStream(ctx, pubsub); err != nil {
+ log.WithError(fmt.Errorf("keywatcher: receivePubSubStream: %v", err)).Error()
+ }
+ }
+}
+
+func (kw *KeyWatcher) Shutdown() {
+ log.Info("keywatcher: shutting down")
+
+ kw.mu.Lock()
+ defer kw.mu.Unlock()
+
+ select {
+ case <-kw.shutdown:
+ // already closed
+ default:
+ close(kw.shutdown)
+ }
+}
+
+func (kw *KeyWatcher) notifySubscribers(key, value string) {
+ kw.mu.Lock()
+ defer kw.mu.Unlock()
+
+ chanList, ok := kw.subscribers[key]
+ if !ok {
+ countAction("drop-message")
+ return
+ }
+
+ countAction("deliver-message")
+ for _, c := range chanList {
+ select {
+ case c <- value:
+ default:
+ }
+ }
+}
+
+func (kw *KeyWatcher) addSubscription(ctx context.Context, key string, notify chan string) error {
+ kw.mu.Lock()
+ defer kw.mu.Unlock()
+
+ if kw.conn == nil {
+ // This can happen because CI long polling is disabled in this Workhorse
+ // process. It can also be that we are waiting for the pubsub connection
+ // to be established. Either way it is OK to fail fast.
+ return errors.New("no redis connection")
+ }
+
+ if len(kw.subscribers[key]) == 0 {
+ countAction("create-subscription")
+ if err := kw.conn.Subscribe(ctx, channelPrefix+key); err != nil {
+ return err
+ }
+ }
+
+ if kw.subscribers == nil {
+ kw.subscribers = make(map[string][]chan string)
+ }
+ kw.subscribers[key] = append(kw.subscribers[key], notify)
+ internalredis.KeyWatchers.Inc()
+
+ return nil
+}
+
+func (kw *KeyWatcher) delSubscription(ctx context.Context, key string, notify chan string) {
+ kw.mu.Lock()
+ defer kw.mu.Unlock()
+
+ chans, ok := kw.subscribers[key]
+ if !ok {
+ // This can happen if the pubsub connection dropped while we were
+ // waiting.
+ return
+ }
+
+ for i, c := range chans {
+ if notify == c {
+ kw.subscribers[key] = append(chans[:i], chans[i+1:]...)
+ internalredis.KeyWatchers.Dec()
+ break
+ }
+ }
+ if len(kw.subscribers[key]) == 0 {
+ delete(kw.subscribers, key)
+ countAction("delete-subscription")
+ if kw.conn != nil {
+ kw.conn.Unsubscribe(ctx, channelPrefix+key)
+ }
+ }
+}
+
+func (kw *KeyWatcher) WatchKey(ctx context.Context, key, value string, timeout time.Duration) (internalredis.WatchKeyStatus, error) {
+ notify := make(chan string, 1)
+ if err := kw.addSubscription(ctx, key, notify); err != nil {
+ return internalredis.WatchKeyStatusNoChange, err
+ }
+ defer kw.delSubscription(ctx, key, notify)
+
+ currentValue, err := kw.redisConn.Get(ctx, key).Result()
+ if errors.Is(err, redis.Nil) {
+ currentValue = ""
+ } else if err != nil {
+ return internalredis.WatchKeyStatusNoChange, fmt.Errorf("keywatcher: redis GET: %v", err)
+ }
+ if currentValue != value {
+ return internalredis.WatchKeyStatusAlreadyChanged, nil
+ }
+
+ select {
+ case <-kw.shutdown:
+ log.WithFields(log.Fields{"key": key}).Info("stopping watch due to shutdown")
+ return internalredis.WatchKeyStatusNoChange, nil
+ case currentValue := <-notify:
+ if currentValue == "" {
+ return internalredis.WatchKeyStatusNoChange, fmt.Errorf("keywatcher: redis GET failed")
+ }
+ if currentValue == value {
+ return internalredis.WatchKeyStatusNoChange, nil
+ }
+ return internalredis.WatchKeyStatusSeenChange, nil
+ case <-time.After(timeout):
+ return internalredis.WatchKeyStatusTimeout, nil
+ }
+}
diff --git a/workhorse/internal/goredis/keywatcher_test.go b/workhorse/internal/goredis/keywatcher_test.go
new file mode 100644
index 00000000000..b64262dc9c8
--- /dev/null
+++ b/workhorse/internal/goredis/keywatcher_test.go
@@ -0,0 +1,301 @@
+package goredis
+
+import (
+ "context"
+ "os"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/config"
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/redis"
+)
+
+var ctx = context.Background()
+
+const (
+ runnerKey = "runner:build_queue:10"
+)
+
+func initRdb() {
+ buf, _ := os.ReadFile("../../config.toml")
+ cfg, _ := config.LoadConfig(string(buf))
+ Configure(cfg.Redis)
+}
+
+func (kw *KeyWatcher) countSubscribers(key string) int {
+ kw.mu.Lock()
+ defer kw.mu.Unlock()
+ return len(kw.subscribers[key])
+}
+
+// Forces a run of the `Process` loop against a mock PubSubConn.
+func (kw *KeyWatcher) processMessages(t *testing.T, numWatchers int, value string, ready chan<- struct{}, wg *sync.WaitGroup) {
+ kw.mu.Lock()
+ kw.redisConn = rdb
+ psc := kw.redisConn.Subscribe(ctx, []string{}...)
+ kw.mu.Unlock()
+
+ errC := make(chan error)
+ go func() { errC <- kw.receivePubSubStream(ctx, psc) }()
+
+ require.Eventually(t, func() bool {
+ kw.mu.Lock()
+ defer kw.mu.Unlock()
+ return kw.conn != nil
+ }, time.Second, time.Millisecond)
+ close(ready)
+
+ require.Eventually(t, func() bool {
+ return kw.countSubscribers(runnerKey) == numWatchers
+ }, time.Second, time.Millisecond)
+
+ // send message after listeners are ready
+ kw.redisConn.Publish(ctx, channelPrefix+runnerKey, value)
+
+ // close subscription after all workers are done
+ wg.Wait()
+ kw.mu.Lock()
+ kw.conn.Close()
+ kw.mu.Unlock()
+
+ require.NoError(t, <-errC)
+}
+
+type keyChangeTestCase struct {
+ desc string
+ returnValue string
+ isKeyMissing bool
+ watchValue string
+ processedValue string
+ expectedStatus redis.WatchKeyStatus
+ timeout time.Duration
+}
+
+func TestKeyChangesInstantReturn(t *testing.T) {
+ initRdb()
+
+ testCases := []keyChangeTestCase{
+ // WatchKeyStatusAlreadyChanged
+ {
+ desc: "sees change with key existing and changed",
+ returnValue: "somethingelse",
+ watchValue: "something",
+ expectedStatus: redis.WatchKeyStatusAlreadyChanged,
+ timeout: time.Second,
+ },
+ {
+ desc: "sees change with key non-existing",
+ isKeyMissing: true,
+ watchValue: "something",
+ processedValue: "somethingelse",
+ expectedStatus: redis.WatchKeyStatusAlreadyChanged,
+ timeout: time.Second,
+ },
+ // WatchKeyStatusTimeout
+ {
+ desc: "sees timeout with key existing and unchanged",
+ returnValue: "something",
+ watchValue: "something",
+ expectedStatus: redis.WatchKeyStatusTimeout,
+ timeout: time.Millisecond,
+ },
+ {
+ desc: "sees timeout with key non-existing and unchanged",
+ isKeyMissing: true,
+ watchValue: "",
+ expectedStatus: redis.WatchKeyStatusTimeout,
+ timeout: time.Millisecond,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+
+ // setup
+ if !tc.isKeyMissing {
+ rdb.Set(ctx, runnerKey, tc.returnValue, 0)
+ }
+
+ defer func() {
+ rdb.FlushDB(ctx)
+ }()
+
+ kw := NewKeyWatcher()
+ defer kw.Shutdown()
+ kw.redisConn = rdb
+ kw.conn = kw.redisConn.Subscribe(ctx, []string{}...)
+
+ val, err := kw.WatchKey(ctx, runnerKey, tc.watchValue, tc.timeout)
+
+ require.NoError(t, err, "Expected no error")
+ require.Equal(t, tc.expectedStatus, val, "Expected value")
+ })
+ }
+}
+
+func TestKeyChangesWhenWatching(t *testing.T) {
+ initRdb()
+
+ testCases := []keyChangeTestCase{
+ // WatchKeyStatusSeenChange
+ {
+ desc: "sees change with key existing",
+ returnValue: "something",
+ watchValue: "something",
+ processedValue: "somethingelse",
+ expectedStatus: redis.WatchKeyStatusSeenChange,
+ },
+ {
+ desc: "sees change with key non-existing, when watching empty value",
+ isKeyMissing: true,
+ watchValue: "",
+ processedValue: "something",
+ expectedStatus: redis.WatchKeyStatusSeenChange,
+ },
+ // WatchKeyStatusNoChange
+ {
+ desc: "sees no change with key existing",
+ returnValue: "something",
+ watchValue: "something",
+ processedValue: "something",
+ expectedStatus: redis.WatchKeyStatusNoChange,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ if !tc.isKeyMissing {
+ rdb.Set(ctx, runnerKey, tc.returnValue, 0)
+ }
+
+ kw := NewKeyWatcher()
+ defer kw.Shutdown()
+ defer func() {
+ rdb.FlushDB(ctx)
+ }()
+
+ wg := &sync.WaitGroup{}
+ wg.Add(1)
+ ready := make(chan struct{})
+
+ go func() {
+ defer wg.Done()
+ <-ready
+ val, err := kw.WatchKey(ctx, runnerKey, tc.watchValue, time.Second)
+
+ require.NoError(t, err, "Expected no error")
+ require.Equal(t, tc.expectedStatus, val, "Expected value")
+ }()
+
+ kw.processMessages(t, 1, tc.processedValue, ready, wg)
+ })
+ }
+}
+
+func TestKeyChangesParallel(t *testing.T) {
+ initRdb()
+
+ testCases := []keyChangeTestCase{
+ {
+ desc: "massively parallel, sees change with key existing",
+ returnValue: "something",
+ watchValue: "something",
+ processedValue: "somethingelse",
+ expectedStatus: redis.WatchKeyStatusSeenChange,
+ },
+ {
+ desc: "massively parallel, sees change with key existing, watching missing keys",
+ isKeyMissing: true,
+ watchValue: "",
+ processedValue: "somethingelse",
+ expectedStatus: redis.WatchKeyStatusSeenChange,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ runTimes := 100
+
+ if !tc.isKeyMissing {
+ rdb.Set(ctx, runnerKey, tc.returnValue, 0)
+ }
+
+ defer func() {
+ rdb.FlushDB(ctx)
+ }()
+
+ wg := &sync.WaitGroup{}
+ wg.Add(runTimes)
+ ready := make(chan struct{})
+
+ kw := NewKeyWatcher()
+ defer kw.Shutdown()
+
+ for i := 0; i < runTimes; i++ {
+ go func() {
+ defer wg.Done()
+ <-ready
+ val, err := kw.WatchKey(ctx, runnerKey, tc.watchValue, time.Second)
+
+ require.NoError(t, err, "Expected no error")
+ require.Equal(t, tc.expectedStatus, val, "Expected value")
+ }()
+ }
+
+ kw.processMessages(t, runTimes, tc.processedValue, ready, wg)
+ })
+ }
+}
+
+func TestShutdown(t *testing.T) {
+ initRdb()
+
+ kw := NewKeyWatcher()
+ kw.redisConn = rdb
+ kw.conn = kw.redisConn.Subscribe(ctx, []string{}...)
+ defer kw.Shutdown()
+
+ rdb.Set(ctx, runnerKey, "something", 0)
+
+ wg := &sync.WaitGroup{}
+ wg.Add(2)
+
+ go func() {
+ defer wg.Done()
+ val, err := kw.WatchKey(ctx, runnerKey, "something", 10*time.Second)
+
+ require.NoError(t, err, "Expected no error")
+ require.Equal(t, redis.WatchKeyStatusNoChange, val, "Expected value not to change")
+ }()
+
+ go func() {
+ defer wg.Done()
+ require.Eventually(t, func() bool { return kw.countSubscribers(runnerKey) == 1 }, 10*time.Second, time.Millisecond)
+
+ kw.Shutdown()
+ }()
+
+ wg.Wait()
+
+ require.Eventually(t, func() bool { return kw.countSubscribers(runnerKey) == 0 }, 10*time.Second, time.Millisecond)
+
+ // Adding a key after the shutdown should result in an immediate response
+ var val redis.WatchKeyStatus
+ var err error
+ done := make(chan struct{})
+ go func() {
+ val, err = kw.WatchKey(ctx, runnerKey, "something", 10*time.Second)
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ require.NoError(t, err, "Expected no error")
+ require.Equal(t, redis.WatchKeyStatusNoChange, val, "Expected value not to change")
+ case <-time.After(100 * time.Millisecond):
+ t.Fatal("timeout waiting for WatchKey")
+ }
+}
diff --git a/workhorse/internal/redis/keywatcher.go b/workhorse/internal/redis/keywatcher.go
index 2fd0753c3c9..8f1772a9195 100644
--- a/workhorse/internal/redis/keywatcher.go
+++ b/workhorse/internal/redis/keywatcher.go
@@ -37,32 +37,32 @@ func NewKeyWatcher() *KeyWatcher {
}
var (
- keyWatchers = promauto.NewGauge(
+ KeyWatchers = promauto.NewGauge(
prometheus.GaugeOpts{
Name: "gitlab_workhorse_keywatcher_keywatchers",
Help: "The number of keys that is being watched by gitlab-workhorse",
},
)
- redisSubscriptions = promauto.NewGauge(
+ RedisSubscriptions = promauto.NewGauge(
prometheus.GaugeOpts{
Name: "gitlab_workhorse_keywatcher_redis_subscriptions",
Help: "Current number of keywatcher Redis pubsub subscriptions",
},
)
- totalMessages = promauto.NewCounter(
+ TotalMessages = promauto.NewCounter(
prometheus.CounterOpts{
Name: "gitlab_workhorse_keywatcher_total_messages",
Help: "How many messages gitlab-workhorse has received in total on pubsub.",
},
)
- totalActions = promauto.NewCounterVec(
+ TotalActions = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "gitlab_workhorse_keywatcher_actions_total",
Help: "Counts of various keywatcher actions",
},
[]string{"action"},
)
- receivedBytes = promauto.NewCounter(
+ ReceivedBytes = promauto.NewCounter(
prometheus.CounterOpts{
Name: "gitlab_workhorse_keywatcher_received_bytes_total",
Help: "How many bytes of messages gitlab-workhorse has received in total on pubsub.",
@@ -72,7 +72,7 @@ var (
const channelPrefix = "workhorse:notifications:"
-func countAction(action string) { totalActions.WithLabelValues(action).Add(1) }
+func countAction(action string) { TotalActions.WithLabelValues(action).Add(1) }
func (kw *KeyWatcher) receivePubSubStream(conn redis.Conn) error {
kw.mu.Lock()
@@ -93,7 +93,7 @@ func (kw *KeyWatcher) receivePubSubStream(conn redis.Conn) error {
for _, chans := range kw.subscribers {
for _, ch := range chans {
close(ch)
- keyWatchers.Dec()
+ KeyWatchers.Dec()
}
}
kw.subscribers = nil
@@ -102,13 +102,13 @@ func (kw *KeyWatcher) receivePubSubStream(conn redis.Conn) error {
for {
switch v := kw.conn.Receive().(type) {
case redis.Message:
- totalMessages.Inc()
- receivedBytes.Add(float64(len(v.Data)))
+ TotalMessages.Inc()
+ ReceivedBytes.Add(float64(len(v.Data)))
if strings.HasPrefix(v.Channel, channelPrefix) {
kw.notifySubscribers(v.Channel[len(channelPrefix):], string(v.Data))
}
case redis.Subscription:
- redisSubscriptions.Set(float64(v.Count))
+ RedisSubscriptions.Set(float64(v.Count))
case error:
log.WithError(fmt.Errorf("keywatcher: pubsub receive: %v", v)).Error()
// Intermittent error, return nil so that it doesn't wait before reconnect
@@ -205,7 +205,7 @@ func (kw *KeyWatcher) addSubscription(key string, notify chan string) error {
kw.subscribers = make(map[string][]chan string)
}
kw.subscribers[key] = append(kw.subscribers[key], notify)
- keyWatchers.Inc()
+ KeyWatchers.Inc()
return nil
}
@@ -224,7 +224,7 @@ func (kw *KeyWatcher) delSubscription(key string, notify chan string) {
for i, c := range chans {
if notify == c {
kw.subscribers[key] = append(chans[:i], chans[i+1:]...)
- keyWatchers.Dec()
+ KeyWatchers.Dec()
break
}
}
diff --git a/workhorse/internal/redis/redis.go b/workhorse/internal/redis/redis.go
index 03118cfcef6..c79e1e56b3a 100644
--- a/workhorse/internal/redis/redis.go
+++ b/workhorse/internal/redis/redis.go
@@ -45,14 +45,14 @@ const (
)
var (
- totalConnections = promauto.NewCounter(
+ TotalConnections = promauto.NewCounter(
prometheus.CounterOpts{
Name: "gitlab_workhorse_redis_total_connections",
Help: "How many connections gitlab-workhorse has opened in total. Can be used to track Redis connection rate for this process",
},
)
- errorCounter = promauto.NewCounterVec(
+ ErrorCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "gitlab_workhorse_redis_errors",
Help: "Counts different types of Redis errors encountered by workhorse, by type and destination (redis, sentinel)",
@@ -100,7 +100,7 @@ func sentinelConn(master string, urls []config.TomlURL) *sentinel.Sentinel {
}
if err != nil {
- errorCounter.WithLabelValues("dial", "sentinel").Inc()
+ ErrorCounter.WithLabelValues("dial", "sentinel").Inc()
return nil, err
}
return c, nil
@@ -159,7 +159,7 @@ func sentinelDialer(dopts []redis.DialOption) redisDialerFunc {
return func() (redis.Conn, error) {
address, err := sntnl.MasterAddr()
if err != nil {
- errorCounter.WithLabelValues("master", "sentinel").Inc()
+ ErrorCounter.WithLabelValues("master", "sentinel").Inc()
return nil, err
}
dopts = append(dopts, redis.DialNetDial(keepAliveDialer))
@@ -214,9 +214,9 @@ func countDialer(dialer redisDialerFunc) redisDialerFunc {
return func() (redis.Conn, error) {
c, err := dialer()
if err != nil {
- errorCounter.WithLabelValues("dial", "redis").Inc()
+ ErrorCounter.WithLabelValues("dial", "redis").Inc()
} else {
- totalConnections.Inc()
+ TotalConnections.Inc()
}
return c, err
}
diff --git a/workhorse/main.go b/workhorse/main.go
index ca9b86de528..9ba213d47d3 100644
--- a/workhorse/main.go
+++ b/workhorse/main.go
@@ -17,8 +17,10 @@ import (
"gitlab.com/gitlab-org/labkit/monitoring"
"gitlab.com/gitlab-org/labkit/tracing"
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/builds"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/config"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/gitaly"
+ "gitlab.com/gitlab-org/gitlab/workhorse/internal/goredis"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/queueing"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/redis"
"gitlab.com/gitlab-org/gitlab/workhorse/internal/secret"
@@ -224,9 +226,32 @@ func run(boot bootConfig, cfg config.Config) error {
secret.SetPath(boot.secretPath)
keyWatcher := redis.NewKeyWatcher()
- if cfg.Redis != nil {
- redis.Configure(cfg.Redis, redis.DefaultDialFunc)
- go keyWatcher.Process()
+
+ var watchKeyFn builds.WatchKeyHandler
+ var goredisKeyWatcher *goredis.KeyWatcher
+
+ if os.Getenv("GITLAB_WORKHORSE_FF_GO_REDIS_ENABLED") == "true" {
+ log.Info("Using redis/go-redis")
+
+ goredisKeyWatcher = goredis.NewKeyWatcher()
+ if err := goredis.Configure(cfg.Redis); err != nil {
+ log.WithError(err).Error("unable to configure redis client")
+ }
+
+ if rdb := goredis.GetRedisClient(); rdb != nil {
+ go goredisKeyWatcher.Process(rdb)
+ }
+
+ watchKeyFn = goredisKeyWatcher.WatchKey
+ } else {
+ log.Info("Using gomodule/redigo")
+
+ if cfg.Redis != nil {
+ redis.Configure(cfg.Redis, redis.DefaultDialFunc)
+ go keyWatcher.Process()
+ }
+
+ watchKeyFn = keyWatcher.WatchKey
}
if err := cfg.RegisterGoCloudURLOpeners(); err != nil {
@@ -241,7 +266,7 @@ func run(boot bootConfig, cfg config.Config) error {
gitaly.InitializeSidechannelRegistry(accessLogger)
- up := wrapRaven(upstream.NewUpstream(cfg, accessLogger, keyWatcher.WatchKey))
+ up := wrapRaven(upstream.NewUpstream(cfg, accessLogger, watchKeyFn))
done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)
@@ -275,6 +300,10 @@ func run(boot bootConfig, cfg config.Config) error {
ctx, cancel := context.WithTimeout(context.Background(), cfg.ShutdownTimeout.Duration) // lint:allow context.Background
defer cancel()
+ if goredisKeyWatcher != nil {
+ goredisKeyWatcher.Shutdown()
+ }
+
keyWatcher.Shutdown()
return srv.Shutdown(ctx)
}
diff --git a/workhorse/main_test.go b/workhorse/main_test.go
index 05834ab5d64..39eaa3ee30b 100644
--- a/workhorse/main_test.go
+++ b/workhorse/main_test.go
@@ -35,7 +35,6 @@ import (
"gitlab.com/gitlab-org/gitlab/workhorse/internal/upstream"
)
-const scratchDir = "testdata/scratch"
const testRepoRoot = "testdata/repo"
const testDocumentRoot = "testdata/public"
const testAltDocumentRoot = "testdata/alt-public"
@@ -45,9 +44,6 @@ var absDocumentRoot string
const testRepo = "group/test.git"
const testProject = "group/test"
-var checkoutDir = path.Join(scratchDir, "test")
-var cacheDir = path.Join(scratchDir, "cache")
-
func TestMain(m *testing.M) {
if _, err := os.Stat(path.Join(testRepoRoot, testRepo)); os.IsNotExist(err) {
log.WithError(err).Fatal("cannot find test repository. Please run 'make prepare-tests'")
@@ -64,9 +60,6 @@ func TestMain(m *testing.M) {
}
func TestDeniedClone(t *testing.T) {
- // Prepare clone directory
- require.NoError(t, os.RemoveAll(scratchDir))
-
// Prepare test server and backend
ts := testAuthServer(t, nil, nil, 403, "Access denied")
defer ts.Close()
@@ -74,7 +67,7 @@ func TestDeniedClone(t *testing.T) {
defer ws.Close()
// Do the git clone
- cloneCmd := exec.Command("git", "clone", fmt.Sprintf("%s/%s", ws.URL, testRepo), checkoutDir)
+ cloneCmd := exec.Command("git", "clone", fmt.Sprintf("%s/%s", ws.URL, testRepo), t.TempDir())
out, err := cloneCmd.CombinedOutput()
t.Log(string(out))
require.Error(t, err, "git clone should have failed")
@@ -89,7 +82,7 @@ func TestDeniedPush(t *testing.T) {
// Perform the git push
pushCmd := exec.Command("git", "push", "-v", fmt.Sprintf("%s/%s", ws.URL, testRepo), fmt.Sprintf("master:%s", newBranch()))
- pushCmd.Dir = checkoutDir
+ pushCmd.Dir = t.TempDir()
out, err := pushCmd.CombinedOutput()
t.Log(string(out))
require.Error(t, err, "git push should have failed")
@@ -125,14 +118,12 @@ func TestRegularProjectsAPI(t *testing.T) {
func TestAllowedXSendfileDownload(t *testing.T) {
contentFilename := "my-content"
- prepareDownloadDir(t)
allowedXSendfileDownload(t, contentFilename, "foo/uploads/bar")
}
func TestDeniedXSendfileDownload(t *testing.T) {
contentFilename := "my-content"
- prepareDownloadDir(t)
deniedXSendfileDownload(t, contentFilename, "foo/uploads/bar")
}
@@ -721,11 +712,6 @@ func setupAltStaticFile(t *testing.T, fpath, content string) {
absDocumentRoot = testhelper.SetupStaticFileHelper(t, fpath, content, testAltDocumentRoot)
}
-func prepareDownloadDir(t *testing.T) {
- require.NoError(t, os.RemoveAll(scratchDir))
- require.NoError(t, os.MkdirAll(scratchDir, 0755))
-}
-
func newBranch() string {
return fmt.Sprintf("branch-%d", time.Now().UnixNano())
}
@@ -962,7 +948,7 @@ func TestDependencyProxyInjector(t *testing.T) {
w.Header().Set("Gitlab-Workhorse-Send-Data", `send-dependency:`+base64.URLEncoding.EncodeToString([]byte(params)))
case "/base/upload/authorize":
w.Header().Set("Content-Type", api.ResponseContentType)
- _, err := fmt.Fprintf(w, `{"TempPath":"%s"}`, scratchDir)
+ _, err := fmt.Fprintf(w, `{"TempPath":"%s"}`, t.TempDir())
require.NoError(t, err)
case "/base/upload":
w.WriteHeader(tc.finalizeStatus)
diff --git a/workhorse/sendfile_test.go b/workhorse/sendfile_test.go
index f2b6da4eebd..ed8edf01533 100644
--- a/workhorse/sendfile_test.go
+++ b/workhorse/sendfile_test.go
@@ -20,7 +20,6 @@ func TestDeniedLfsDownload(t *testing.T) {
contentFilename := "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a17f80"
url := fmt.Sprintf("gitlab-lfs/objects/%s", contentFilename)
- prepareDownloadDir(t)
deniedXSendfileDownload(t, contentFilename, url)
}
@@ -28,14 +27,11 @@ func TestAllowedLfsDownload(t *testing.T) {
contentFilename := "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a17f80"
url := fmt.Sprintf("gitlab-lfs/objects/%s", contentFilename)
- prepareDownloadDir(t)
allowedXSendfileDownload(t, contentFilename, url)
}
func allowedXSendfileDownload(t *testing.T, contentFilename string, filePath string) {
- contentPath := path.Join(cacheDir, contentFilename)
- prepareDownloadDir(t)
-
+ contentPath := path.Join(t.TempDir(), contentFilename)
// Prepare test server and backend
ts := testhelper.TestServerWithHandler(regexp.MustCompile(`.`), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.WithFields(log.Fields{"method": r.Method, "url": r.URL}).Info("UPSTREAM")
@@ -51,7 +47,6 @@ func allowedXSendfileDownload(t *testing.T, contentFilename string, filePath str
ws := startWorkhorseServer(ts.URL)
defer ws.Close()
- require.NoError(t, os.MkdirAll(cacheDir, 0755))
contentBytes := []byte("content")
require.NoError(t, os.WriteFile(contentPath, contentBytes, 0644))
@@ -68,8 +63,6 @@ func allowedXSendfileDownload(t *testing.T, contentFilename string, filePath str
}
func deniedXSendfileDownload(t *testing.T, contentFilename string, filePath string) {
- prepareDownloadDir(t)
-
// Prepare test server and backend
ts := testhelper.TestServerWithHandler(regexp.MustCompile(`.`), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.WithFields(log.Fields{"method": r.Method, "url": r.URL}).Info("UPSTREAM")
diff --git a/workhorse/upload_test.go b/workhorse/upload_test.go
index 62a78dd9464..de7c5c6dd52 100644
--- a/workhorse/upload_test.go
+++ b/workhorse/upload_test.go
@@ -74,9 +74,9 @@ func uploadTestServer(t *testing.T, allowedHashFunctions []string, authorizeTest
var err error
if len(allowedHashFunctions) == 0 {
- _, err = fmt.Fprintf(w, `{"TempPath":"%s"}`, scratchDir)
+ _, err = fmt.Fprintf(w, `{"TempPath":"%s"}`, t.TempDir())
} else {
- _, err = fmt.Fprintf(w, `{"TempPath":"%s", "UploadHashFunctions": ["%s"]}`, scratchDir, strings.Join(allowedHashFunctions, `","`))
+ _, err = fmt.Fprintf(w, `{"TempPath":"%s", "UploadHashFunctions": ["%s"]}`, t.TempDir(), strings.Join(allowedHashFunctions, `","`))
}
require.NoError(t, err)
@@ -386,7 +386,7 @@ func TestLfsUpload(t *testing.T) {
lfsApiResponse := fmt.Sprintf(
`{"TempPath":%q, "LfsOid":%q, "LfsSize": %d}`,
- scratchDir, oid, len(reqBody),
+ t.TempDir(), oid, len(reqBody),
)
ts := testhelper.TestServerWithHandler(regexp.MustCompile(`.`), func(w http.ResponseWriter, r *http.Request) {
@@ -512,7 +512,7 @@ func packageUploadTestServer(t *testing.T, method string, resource string, reqBo
return testhelper.TestServerWithHandler(regexp.MustCompile(`.`), func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, r.Method, method)
apiResponse := fmt.Sprintf(
- `{"TempPath":%q, "Size": %d}`, scratchDir, len(reqBody),
+ `{"TempPath":%q, "Size": %d}`, t.TempDir(), len(reqBody),
)
switch r.RequestURI {
case resource + "/authorize":
diff --git a/yarn.lock b/yarn.lock
index e295609732f..ef68193fbf0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -328,9 +328,9 @@
js-tokens "^4.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.4", "@babel/parser@^7.16.8", "@babel/parser@^7.18.10", "@babel/parser@^7.18.4", "@babel/parser@^7.19.0":
- version "7.21.2"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3"
- integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==
+ version "7.21.3"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3"
+ integrity sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.17.12":
version "7.17.12"
@@ -1000,20 +1000,35 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@braintree/sanitize-url@^6.0.0":
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz#fe364f025ba74f6de6c837a84ef44bdb1d61e68f"
- integrity sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==
+"@braintree/sanitize-url@^6.0.1":
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783"
+ integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==
-"@csstools/selector-specificity@^2.0.1":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.1.tgz#b6b8d81780b9a9f6459f4bfe9226ac6aefaefe87"
- integrity sha512-aG20vknL4/YjQF9BSV7ts4EWm/yrjagAN7OWBNmlbEOUiu0llj4OGrFoOKK3g2vey4/p2omKCoHrWtPxSwV3HA==
+"@csstools/css-parser-algorithms@^2.3.0":
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.1.tgz#ec4fc764ba45d2bb7ee2774667e056aa95003f3a"
+ integrity sha512-xrvsmVUtefWMWQsGgFffqWSK03pZ1vfDki4IVIIUxxDKnGBzqNgv0A7SB1oXtVNEkcVO8xi1ZrTL29HhSu5kGA==
+
+"@csstools/css-tokenizer@^2.1.1":
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-2.2.0.tgz#9d70e6dcbe94e44c7400a2929928db35c4de32b5"
+ integrity sha512-wErmsWCbsmig8sQKkM6pFhr/oPha1bHfvxsUY5CYSQxwyhA9Ulrs8EqCgClhg4Tgg2XapVstGqSVcz0xOYizZA==
+
+"@csstools/media-query-list-parser@^2.1.2":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.4.tgz#0017f99945f6c16dd81a7aacf6821770933c3a5c"
+ integrity sha512-V/OUXYX91tAC1CDsiY+HotIcJR+vPtzrX8pCplCpT++i8ThZZsq5F5dzZh/bDM3WUOjrvC1ljed1oSJxMfjqhw==
+
+"@csstools/selector-specificity@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz#798622546b63847e82389e473fd67f2707d82247"
+ integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==
-"@cubejs-client/core@^0.33.47":
- version "0.33.47"
- resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.33.47.tgz#c5b45c8b75570b5fe3023436ad9d28f459e62129"
- integrity sha512-da2aCompNvSrP/DFROJ4oLNQ1VBcKISwqEG8YMH54kRKSx1C+TPFw311sgzmuLRD7psXgUJuCHq1Co1SrEjN7Q==
+"@cubejs-client/core@^0.33.55":
+ version "0.33.55"
+ resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.33.55.tgz#1e44a3c93d3f129550fb6f9f4170431899981a83"
+ integrity sha512-gveK3ZlI5qdljjnvucd5AnGuxJWxf3JBBHfsYYCCGMInFsmU69QLpGfzfsmYsr4+vrYxmqzoTnuiieucIONhqA==
dependencies:
"@babel/runtime" "^7.1.2"
core-js "^3.6.5"
@@ -1023,12 +1038,12 @@
url-search-params-polyfill "^7.0.0"
uuid "^8.3.2"
-"@cubejs-client/vue@^0.33.47":
- version "0.33.47"
- resolved "https://registry.yarnpkg.com/@cubejs-client/vue/-/vue-0.33.47.tgz#abdf1c7985c83d66a69cf338bf43cacba68db713"
- integrity sha512-wy0YJxzfaeFUNRRfRf75pNiDTOkFFdKCtAnuvHDHTJWWh9xW7wUAcel/PNrYoqbcXle4zmgoO0r7xWpIQIqkhg==
+"@cubejs-client/vue@^0.33.55":
+ version "0.33.55"
+ resolved "https://registry.yarnpkg.com/@cubejs-client/vue/-/vue-0.33.55.tgz#34f37c8813a670e21eb7c2020cf421dce14da8d3"
+ integrity sha512-8ZaLbO7SX85J8B7P7aJ566KO6HfpFZw9FUc0yQk0oFtvBzsX/bvGPl3ozVSjaxz9ZuYareWKDtGy6BQTNLyE0A==
dependencies:
- "@cubejs-client/core" "^0.33.47"
+ "@cubejs-client/core" "^0.33.55"
core-js "^3.6.5"
ramda "^0.27.2"
@@ -1037,6 +1052,121 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
+"@esbuild/android-arm64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.15.tgz#abbe87b815d2f95ec749ffb4eba65d7d5343411f"
+ integrity sha512-NI/gnWcMl2kXt1HJKOn2H69SYn4YNheKo6NZt1hyfKWdMbaGadxjZIkcj4Gjk/WPxnbFXs9/3HjGHaknCqjrww==
+
+"@esbuild/android-arm@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.15.tgz#6afedd79c68d5d4d1e434e20a9ab620bb5849372"
+ integrity sha512-wlkQBWb79/jeEEoRmrxt/yhn5T1lU236OCNpnfRzaCJHZ/5gf82uYx1qmADTBWE0AR/v7FiozE1auk2riyQd3w==
+
+"@esbuild/android-x64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.15.tgz#cdd886a58748b1584ad72d960c446fa958c11ab3"
+ integrity sha512-FM9NQamSaEm/IZIhegF76aiLnng1kEsZl2eve/emxDeReVfRuRNmvT28l6hoFD9TsCxpK+i4v8LPpEj74T7yjA==
+
+"@esbuild/darwin-arm64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.15.tgz#648b124a6a63022adb5b0cf441e264e8f5ba4af2"
+ integrity sha512-XmrFwEOYauKte9QjS6hz60FpOCnw4zaPAb7XV7O4lx1r39XjJhTN7ZpXqJh4sN6q60zbP6QwAVVA8N/wUyBH/w==
+
+"@esbuild/darwin-x64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.15.tgz#91cd2601c1604d123454d325e6b24fb6438350cf"
+ integrity sha512-bMqBmpw1e//7Fh5GLetSZaeo9zSC4/CMtrVFdj+bqKPGJuKyfNJ5Nf2m3LknKZTS+Q4oyPiON+v3eaJ59sLB5A==
+
+"@esbuild/freebsd-arm64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.15.tgz#575940b0fc2f52833de4f6360445586742a8ff8b"
+ integrity sha512-LoTK5N3bOmNI9zVLCeTgnk5Rk0WdUTrr9dyDAQGVMrNTh9EAPuNwSTCgaKOKiDpverOa0htPcO9NwslSE5xuLA==
+
+"@esbuild/freebsd-x64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.15.tgz#09694fc601dd8d3263a1075977ee7d3488514ef8"
+ integrity sha512-62jX5n30VzgrjAjOk5orYeHFq6sqjvsIj1QesXvn5OZtdt5Gdj0vUNJy9NIpjfdNdqr76jjtzBJKf+h2uzYuTQ==
+
+"@esbuild/linux-arm64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.15.tgz#2f5d226b024964f2b5b6bce7c874a8ad31785fa2"
+ integrity sha512-BWncQeuWDgYv0jTNzJjaNgleduV4tMbQjmk/zpPh/lUdMcNEAxy+jvneDJ6RJkrqloG7tB9S9rCrtfk/kuplsQ==
+
+"@esbuild/linux-arm@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.15.tgz#172331fc66bbe89ba96e5e2ad583b2faa132d85c"
+ integrity sha512-dT4URUv6ir45ZkBqhwZwyFV6cH61k8MttIwhThp2BGiVtagYvCToF+Bggyx2VI57RG4Fbt21f9TmXaYx0DeUJg==
+
+"@esbuild/linux-ia32@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.15.tgz#fa797051131ee5f46d70c65a7edd14b6230cfc2f"
+ integrity sha512-JPXORvgHRHITqfms1dWT/GbEY89u848dC08o0yK3fNskhp0t2TuNUnsrrSgOdH28ceb1hJuwyr8R/1RnyPwocw==
+
+"@esbuild/linux-loong64@0.14.54":
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
+ integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
+
+"@esbuild/linux-loong64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.15.tgz#aeae1fa3d92b1486a91c0cb1cfd9c0ebe9168de4"
+ integrity sha512-kArPI0DopjJCEplsVj/H+2Qgzz7vdFSacHNsgoAKpPS6W/Ndh8Oe24HRDQ5QCu4jHgN6XOtfFfLpRx3TXv/mEg==
+
+"@esbuild/linux-mips64el@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.15.tgz#b63cfe356c33807c4d8ee5a75452922e98502073"
+ integrity sha512-b/tmngUfO02E00c1XnNTw/0DmloKjb6XQeqxaYuzGwHe0fHVgx5/D6CWi+XH1DvkszjBUkK9BX7n1ARTOst59w==
+
+"@esbuild/linux-ppc64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.15.tgz#7dcb394e69cb47e4dc8a5960dd58b1a273d07f5d"
+ integrity sha512-KXPY69MWw79QJkyvUYb2ex/OgnN/8N/Aw5UDPlgoRtoEfcBqfeLodPr42UojV3NdkoO4u10NXQdamWm1YEzSKw==
+
+"@esbuild/linux-riscv64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.15.tgz#fdfb9cf23b50d33112315e3194b9e16f7abf6c30"
+ integrity sha512-komK3NEAeeGRnvFEjX1SfVg6EmkfIi5aKzevdvJqMydYr9N+pRQK0PGJXk+bhoPZwOUgLO4l99FZmLGk/L1jWg==
+
+"@esbuild/linux-s390x@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.15.tgz#ce608d95989a502878d7cb1167df791e45268011"
+ integrity sha512-632T5Ts6gQ2WiMLWRRyeflPAm44u2E/s/TJvn+BP6M5mnHSk93cieaypj3VSMYO2ePTCRqAFXtuYi1yv8uZJNA==
+
+"@esbuild/linux-x64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.15.tgz#49bbba5607702709f63b41906b4f1bcc44cf2f8e"
+ integrity sha512-MsHtX0NgvRHsoOtYkuxyk4Vkmvk3PLRWfA4okK7c+6dT0Fu4SUqXAr9y4Q3d8vUf1VWWb6YutpL4XNe400iQ1g==
+
+"@esbuild/netbsd-x64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.15.tgz#08b5ccaf027c7e2174b9a19c29bebfe59dce1cfb"
+ integrity sha512-djST6s+jQiwxMIVQ5rlt24JFIAr4uwUnzceuFL7BQT4CbrRtqBPueS4GjXSiIpmwVri1Icj/9pFRJ7/aScvT+A==
+
+"@esbuild/openbsd-x64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.15.tgz#38ec4223ebab562f0a89ffe20a40f05d500f89f0"
+ integrity sha512-naeRhUIvhsgeounjkF5mvrNAVMGAm6EJWiabskeE5yOeBbLp7T89tAEw0j5Jm/CZAwyLe3c67zyCWH6fsBLCpw==
+
+"@esbuild/sunos-x64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.15.tgz#dbbebf641957a54b77f39ca9b10b0b38586799ba"
+ integrity sha512-qkT2+WxyKbNIKV1AEhI8QiSIgTHMcRctzSaa/I3kVgMS5dl3fOeoqkb7pW76KwxHoriImhx7Mg3TwN/auMDsyQ==
+
+"@esbuild/win32-arm64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.15.tgz#7f15fe5d14b9b24eb18ca211ad92e0f5df92a18b"
+ integrity sha512-HC4/feP+pB2Vb+cMPUjAnFyERs+HJN7E6KaeBlFdBv799MhD+aPJlfi/yk36SED58J9TPwI8MAcVpJgej4ud0A==
+
+"@esbuild/win32-ia32@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.15.tgz#a6609735a4a5e8fbdeb045720bc8be46825566fa"
+ integrity sha512-ovjwoRXI+gf52EVF60u9sSDj7myPixPxqzD5CmkEUmvs+W9Xd0iqISVBQn8xcx4ciIaIVlWCuTbYDOXOnOL44Q==
+
+"@esbuild/win32-x64@0.18.15":
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.15.tgz#41ee66253566124cc44bce1b4c760a87d9f5bf1d"
+ integrity sha512-imUxH9a3WJARyAvrG7srLyiK73XdX83NXQkjKvQ+7vPh3ZxoLrzvPkQKKw2DwZ+RV2ZB6vBfNHP8XScAmQC3aA==
+
"@eslint-community/eslint-utils@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz#a831e6e468b4b2b5ae42bf658bea015bf10bc518"
@@ -1049,10 +1179,10 @@
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8"
integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==
-"@eslint/eslintrc@^2.1.1":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.1.tgz#18d635e24ad35f7276e8a49d135c7d3ca6a46f93"
- integrity sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==
+"@eslint/eslintrc@^2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396"
+ integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
@@ -1064,10 +1194,10 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@eslint/js@^8.46.0":
- version "8.46.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.46.0.tgz#3f7802972e8b6fe3f88ed1aabc74ec596c456db6"
- integrity sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==
+"@eslint/js@8.49.0":
+ version "8.49.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333"
+ integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==
"@floating-ui/core@^1.2.6":
version "1.2.6"
@@ -1081,18 +1211,30 @@
dependencies:
"@floating-ui/core" "^1.2.6"
+"@gitlab/application-sdk-browser@^0.2.8":
+ version "0.2.8"
+ resolved "https://registry.yarnpkg.com/@gitlab/application-sdk-browser/-/application-sdk-browser-0.2.8.tgz#d4c824e44f033a4af5a11e63e18350de6b7c9228"
+ integrity sha512-jVE11bWHrMHVc4B+t/QD2z1rzUP1rgSP15hHDiM48219I3uahmA5ZMeuYqldaJzimTMEEkV+bdWIA4eNiJXVFA==
+ dependencies:
+ "@snowplow/browser-plugin-client-hints" "^3.9.0"
+ "@snowplow/browser-plugin-error-tracking" "^3.9.0"
+ "@snowplow/browser-plugin-link-click-tracking" "^3.9.0"
+ "@snowplow/browser-plugin-performance-timing" "^3.9.0"
+ "@snowplow/browser-tracker" "^3.9.0"
+
"@gitlab/at.js@1.5.7":
version "1.5.7"
resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.7.tgz#1ee6f838cc4410a1d797770934df91d90df8179e"
integrity sha512-c6ySRK/Ma7lxwpIVbSAF3P+xiTLrNTGTLRx4/pHK111AdFxwgUwrYF6aVZFXvmG65jHOJHoa0eQQ21RW6rm0Rg==
-"@gitlab/cluster-client@^1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@gitlab/cluster-client/-/cluster-client-1.2.0.tgz#3b56da46748403354b5af73678b17db3851cbe53"
- integrity sha512-2emHgfOF9CdibzwXJ2yZVf2d+ez8b67O47qa+pwlG+NnYatjfIcj9Pkzs4kBcO/9+j2lVH/EegPDyEkZZt8Irg==
+"@gitlab/cluster-client@^1.3.0":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/cluster-client/-/cluster-client-1.3.0.tgz#0b25330929f2527501f62f43fbbb0d09b8755eeb"
+ integrity sha512-B53Gm3XYK9TVdoSnPkhma0MESpdo4WW/1/Rtt5YOk5vN869TggF74D064hgqfEo8n7z8w1yMCF/fGpXkDU8YVg==
dependencies:
axios "^0.24.0"
core-js "^3.29.1"
+ mitt "^3.0.1"
"@gitlab/eslint-plugin@19.0.1":
version "19.0.1"
@@ -1118,24 +1260,24 @@
resolved "https://registry.yarnpkg.com/@gitlab/fonts/-/fonts-1.3.0.tgz#df89c1bb6714e4a8a5d3272568aa4de7fb337267"
integrity sha512-DoMUIN3DqjEn7wvcxBg/b7Ite5fTdF5EmuOZoBRo2j0UBGweDXmNBi+9HrTZs4cBU660dOxcf1hATFcG3npbPg==
-"@gitlab/stylelint-config@4.1.0":
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/@gitlab/stylelint-config/-/stylelint-config-4.1.0.tgz#bd431406c8f8725afba353652f08e42c3301a982"
- integrity sha512-WiTLRKoXutmAKR0z4Z/kuXiTAtblyA2XWX6vb2/NHhLd7oboKrxR8CiznSfw7SNxmYtqW/ripaQOdanR1fYMwA==
+"@gitlab/stylelint-config@5.0.0":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/stylelint-config/-/stylelint-config-5.0.0.tgz#1f644bcf2cf11d77a77bfbe06c7ac79519684580"
+ integrity sha512-uNMAJkH4C33XfBZDVAZTluaTOU9vEQ6uwUiKBgTsklH3bDPw39jiNvHOwTib956NiY74OwXU3fL2poMFdDgKcg==
dependencies:
- postcss-scss "4.0.4"
- stylelint-declaration-strict-value "1.8.0"
- stylelint-scss "4.2.0"
+ postcss-scss "4.0.7"
+ stylelint-declaration-strict-value "1.9.2"
+ stylelint-scss "5.1.0"
-"@gitlab/svgs@3.59.0":
- version "3.59.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.59.0.tgz#21090154aa7987e059264e13182c4c60e6d0d4b3"
- integrity sha512-5+FZ0Clwtf2X6oHEEVCwbhqhmnxT8Ds1CGFxHzzWsvQ5Hkdt658BVAicsbvQSU+TuEIhnKOK3BfooyleMUwLlQ==
+"@gitlab/svgs@3.63.0":
+ version "3.63.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.63.0.tgz#48e41f50e6b03bcd065eafebf44b8c0f23de3df3"
+ integrity sha512-rmEljjWhF7iieTjdx2edcsbSqgnW6AdD5Ou37p+cdlIll3lCcK85HpB5Kq474FNLCGoyTaVtnwpURBbWQMv/cg==
-"@gitlab/ui@65.0.1":
- version "65.0.1"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-65.0.1.tgz#4ce7ff6cc9c1ceb54111ba095bb64944f577390d"
- integrity sha512-cVMYYJPRwtNviReOVU3U08wFUt8k8Lo/ypbTgpWdio42kldr2foj5xRTN3jsKu5WwlePA6WEGOryl4MsGaQXhg==
+"@gitlab/ui@66.4.0":
+ version "66.4.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-66.4.0.tgz#d7361aa1eec66f9691ba92fd69a2d73740c1edf1"
+ integrity sha512-UNXZC7mLVqFyMyBNUqbCQ4WQgtpJv9RguEO8Cqsod/2CcyznA9Z/s/aoI2mKt5Bz4PZYHkX5fH35rD+0+1Yfhw==
dependencies:
"@floating-ui/dom" "1.2.9"
bootstrap-vue "2.23.1"
@@ -1150,10 +1292,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.7.3.tgz#9ea641146436da388ffbad25d7f2abe0df52c235"
integrity sha512-NMV++7Ew1FSBDN1xiZaauU9tfeSfgDHcOLpn+8bGpP+O5orUPm2Eu66R5eC5gkjBPaXosNAxNWtriee+aFk4+g==
-"@gitlab/web-ide@0.0.1-dev-20230821141730":
- version "0.0.1-dev-20230821141730"
- resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20230821141730.tgz#31c14414301cbaa51687c9c0d63cfa1b971e0674"
- integrity sha512-EleHzSuoIPNoBhfXQUecJ1P7YqfelBlk6qXsX9YNOiAfsBcw9BGMA+x7R+QobaioVGd3ewrjxgdu1RqD1+sBqQ==
+"@gitlab/web-ide@0.0.1-dev-20230915130935":
+ version "0.0.1-dev-20230915130935"
+ resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20230915130935.tgz#a7c8585d3413b235a23d54c5fb3d5f22be95f443"
+ integrity sha512-80zCGoVU1GhovWOH/ieYKzYx4IWmXovbjpM2elwvggAZBVqwHN1pvhgm/W4XjE18kSRAxRCjHIkhEflb0Mhntg==
"@graphql-eslint/eslint-plugin@3.20.1":
version "3.20.1"
@@ -1337,10 +1479,10 @@
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.2.tgz#6fc464307cbe3c8ca5064549b806360d84457b04"
integrity sha512-9anpBMM9mEgZN4wr2v8wHJI2/u5TnnggewRN6OlvXTTnuVyoY19X6rOv9XTqKRw6dcGKwZsBi8n0kDE2I5i4VA==
-"@humanwhocodes/config-array@^0.11.10":
- version "0.11.10"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2"
- integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==
+"@humanwhocodes/config-array@^0.11.11":
+ version "0.11.11"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"
+ integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
@@ -1625,13 +1767,6 @@
resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796"
integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==
-"@khanacademy/simple-markdown@^0.8.6":
- version "0.8.6"
- resolved "https://registry.yarnpkg.com/@khanacademy/simple-markdown/-/simple-markdown-0.8.6.tgz#9c9aef1f5ce2ce60292d13849165965a57c26f25"
- integrity sha512-mAUlR9lchzfqunR89pFvNI51jQKsMpJeWYsYWw0DQcUXczn/T/V6510utgvm7X0N3zN87j1SvuKk8cMbl9IAFw==
- dependencies:
- "@types/react" ">=16.0.0"
-
"@leichtgewicht/ip-codec@^2.0.1":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz#0300943770e04231041a51bd39f0439b5c7ab4f0"
@@ -1694,15 +1829,22 @@
consola "^2.15.0"
node-fetch "^2.6.1"
+"@originjs/vite-plugin-commonjs@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@originjs/vite-plugin-commonjs/-/vite-plugin-commonjs-1.0.3.tgz#2e3fb11ec78847da9422b79c103953f94d667f09"
+ integrity sha512-KuEXeGPptM2lyxdIEJ4R11+5ztipHoE7hy8ClZt3PYaOVQ/pyngd2alaSrPnwyFeOW1UagRBaQ752aA1dTMdOQ==
+ dependencies:
+ esbuild "^0.14.14"
+
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
-"@polka/url@^1.0.0-next.9":
- version "1.0.0-next.12"
- resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.12.tgz#431ec342a7195622f86688bbda82e3166ce8cb28"
- integrity sha512-6RglhutqrGFMO1MNUXp95RBuYIuc8wTnMAV5MUhLmjTOy78ncwOw7RgeQ/HeymkKXRhZd0s2DNrM1rL7unk3MQ==
+"@polka/url@^1.0.0-next.20":
+ version "1.0.0-next.21"
+ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
+ integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@popperjs/core@^2.11.2", "@popperjs/core@^2.9.0":
version "2.11.5"
@@ -1754,6 +1896,33 @@
dependencies:
type-fest "^2.0.0"
+"@rollup/plugin-graphql@^2.0.3":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-graphql/-/plugin-graphql-2.0.3.tgz#35fea077e225e2982ce8483dd6c381e8cca03aea"
+ integrity sha512-IuuELo+0t29adRuLVg8izBFiUXFSFw8BmezespscynRfvfXSOV0S7g8RzQt75VzP6KHHVmNmlAgz+8qlkLur3w==
+ dependencies:
+ "@rollup/pluginutils" "^5.0.1"
+ graphql-tag "^2.12.6"
+
+"@rollup/pluginutils@^5.0.1":
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33"
+ integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==
+ dependencies:
+ "@types/estree" "^1.0.0"
+ estree-walker "^2.0.2"
+ picomatch "^2.3.1"
+
+"@sentry-internal/tracing@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.66.0.tgz#45ea607917d55a5bcaa3229341387ff6ed9b3a2b"
+ integrity sha512-3vCgC2hC3T45pn53yTDVcRpHoJTBxelDPPZVsipAbZnoOVPkj7n6dNfDhj3I3kwWCBPahPkXmE+R4xViR8VqJg==
+ dependencies:
+ "@sentry/core" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
+ tslib "^2.4.1 || ^1.9.3"
+
"@sentry/core@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3"
@@ -1765,14 +1934,14 @@
"@sentry/utils" "5.30.0"
tslib "^1.9.3"
-"@sentry/core@7.21.1":
- version "7.21.1"
- resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.21.1.tgz#d0423282d90875625802dfe380f9657e9242b72b"
- integrity sha512-Og5wEEsy24fNvT/T7IKjcV4EvVK5ryY2kxbJzKY6GU2eX+i+aBl+n/vp7U0Es351C/AlTkS+0NOUsp2TQQFxZA==
+"@sentry/core@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.66.0.tgz#8968f2a9e641d33e3750a8e24d1d39953680c4f2"
+ integrity sha512-WMAEPN86NeCJ1IT48Lqiz4MS5gdDjBwP4M63XP4msZn9aujSf2Qb6My5uT87AJr9zBtgk8MyJsuHr35F0P3q1w==
dependencies:
- "@sentry/types" "7.21.1"
- "@sentry/utils" "7.21.1"
- tslib "^1.9.3"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
+ tslib "^2.4.1 || ^1.9.3"
"@sentry/hub@5.30.0":
version "5.30.0"
@@ -1792,15 +1961,24 @@
"@sentry/types" "5.30.0"
tslib "^1.9.3"
+"@sentry/replay@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.66.0.tgz#5469144192824e7688c475ed29586a8cce6606f6"
+ integrity sha512-5Y2SlVTOFTo3uIycv0mRneBakQtLgWkOnsJaC5LB0Ip0TqVKiMCbQ578vvXp+yvRj4LcS1gNd98xTTNojBoQNg==
+ dependencies:
+ "@sentry/core" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
+
"@sentry/types@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.30.0.tgz#19709bbe12a1a0115bc790b8942917da5636f402"
integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==
-"@sentry/types@7.21.1":
- version "7.21.1"
- resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.21.1.tgz#408a7b95a66ddc30c4359979594e03bee8f9fbdc"
- integrity sha512-3/IKnd52Ol21amQvI+kz+WB76s8/LR5YvFJzMgIoI2S8d82smIr253zGijRXxHPEif8kMLX4Yt+36VzrLxg6+A==
+"@sentry/types@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.66.0.tgz#4ec290cc6a3dd2024a61a0bffb468cedb409f7fb"
+ integrity sha512-uUMSoSiar6JhuD8p7ON/Ddp4JYvrVd2RpwXJRPH1A4H4Bd4DVt1mKJy1OLG6HdeQv39XyhB1lPZckKJg4tATPw==
"@sentry/utils@5.30.0":
version "5.30.0"
@@ -1810,13 +1988,13 @@
"@sentry/types" "5.30.0"
tslib "^1.9.3"
-"@sentry/utils@7.21.1":
- version "7.21.1"
- resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.21.1.tgz#96582345178015fd32fe9159c25c44ccf2f99d2a"
- integrity sha512-F0W0AAi8tgtTx6ApZRI2S9HbXEA9ENX1phTZgdNNWcMFm1BNbc21XEwLqwXBNjub5nlA6CE8xnjXRgdZKx4kzQ==
+"@sentry/utils@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.66.0.tgz#2e37c96610f26bc79ac064fca4222ea91fece68d"
+ integrity sha512-9GYUVgXjK66uXXcLXVMXVzlptqMtq1eJENCuDeezQiEFrNA71KkLDg00wESp+LL+bl3wpVTBApArpbF6UEG5hQ==
dependencies:
- "@sentry/types" "7.21.1"
- tslib "^1.9.3"
+ "@sentry/types" "7.66.0"
+ tslib "^2.4.1 || ^1.9.3"
"@sinclair/typebox@^0.24.1":
version "0.24.40"
@@ -1845,6 +2023,15 @@
"@snowplow/browser-tracker-core" "3.9.0"
tslib "^2.3.1"
+"@snowplow/browser-plugin-error-tracking@^3.9.0":
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/@snowplow/browser-plugin-error-tracking/-/browser-plugin-error-tracking-3.13.1.tgz#e6eb068ae157f8ae5f54d9949c8811be6930e840"
+ integrity sha512-mYcEaq6EqSUwhmD9DGgloDjMAXaxzz3RDANtRYimpAehG0kfEe2Wv8IOUlmMgEgr1l6vsLUw/ZcYNKNb1BcFYw==
+ dependencies:
+ "@snowplow/browser-tracker-core" "3.13.1"
+ "@snowplow/tracker-core" "3.13.1"
+ tslib "^2.3.1"
+
"@snowplow/browser-plugin-form-tracking@^3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@snowplow/browser-plugin-form-tracking/-/browser-plugin-form-tracking-3.9.0.tgz#926109e34824238555fce80288cd28bb6f38688b"
@@ -1891,6 +2078,16 @@
jstimezonedetect "1.0.7"
tslib "^2.3.1"
+"@snowplow/browser-tracker-core@3.13.1":
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/@snowplow/browser-tracker-core/-/browser-tracker-core-3.13.1.tgz#154f5094efb794cdecf009fe513839216bcfd8ef"
+ integrity sha512-c6950aM8aZqidiBQd6s4AFcJMYtGX7O3VqbIjJVhlW2ZiO+S5Ul2Hbpw8cNrVyGB2QGvtxf3pCc/WDi5m1Bhvw==
+ dependencies:
+ "@snowplow/tracker-core" "3.13.1"
+ sha1 "^1.1.1"
+ tslib "^2.3.1"
+ uuid "^3.4.0"
+
"@snowplow/browser-tracker-core@3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@snowplow/browser-tracker-core/-/browser-tracker-core-3.9.0.tgz#7489cfedc334506cbea24891de07b4880897e372"
@@ -1910,6 +2107,14 @@
"@snowplow/tracker-core" "3.9.0"
tslib "^2.3.1"
+"@snowplow/tracker-core@3.13.1":
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/@snowplow/tracker-core/-/tracker-core-3.13.1.tgz#f7a93241dcaaf80e41cf54bc78c4aa559eb01baa"
+ integrity sha512-IXMGI61rA6OhWtFYJCl11TKe9UePWmD5NKSn9sfDoFyH3cMg3fgurA2tnz7vKQ/bvfMFhEsZ/QAYzrPNRJQABw==
+ dependencies:
+ tslib "^2.3.1"
+ uuid "^3.4.0"
+
"@snowplow/tracker-core@3.9.0":
version "3.9.0"
resolved "https://registry.yarnpkg.com/@snowplow/tracker-core/-/tracker-core-3.9.0.tgz#f59e3ab90003abb77b592e9e554be9ab9e121857"
@@ -2149,6 +2354,11 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
+"@trysound/sax@0.2.0":
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
+ integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
+
"@types/aria-query@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0"
@@ -2217,6 +2427,23 @@
dependencies:
"@types/node" "*"
+"@types/d3-scale-chromatic@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#103124777e8cdec85b20b51fd3397c682ee1e954"
+ integrity sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==
+
+"@types/d3-scale@^4.0.3":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.3.tgz#7a5780e934e52b6f63ad9c24b105e33dd58102b5"
+ integrity sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==
+ dependencies:
+ "@types/d3-time" "*"
+
+"@types/d3-time@*":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.0.tgz#e1ac0f3e9e195135361fa1a1d62f795d87e6e819"
+ integrity sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==
+
"@types/debug@^4.0.0":
version "4.1.7"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82"
@@ -2224,6 +2451,11 @@
dependencies:
"@types/ms" "*"
+"@types/estree@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
+ integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
+
"@types/events@*":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86"
@@ -2351,7 +2583,7 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
-"@types/minimist@^1.2.0":
+"@types/minimist@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
@@ -2381,11 +2613,6 @@
resolved "https://registry.yarnpkg.com/@types/object.pick/-/object.pick-1.3.2.tgz#9eb28118240ad8f658b9c9c6caf35359fdb37150"
integrity sha512-sn7L+qQ6RLPdXRoiaE7bZ/Ek+o4uICma/lBFPyJEKDTPTBP1W8u0c4baj3EiS4DiqLs+Hk+KUGvMVJtAw3ePJg==
-"@types/parse-json@^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
- integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
-
"@types/parse5@^5":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.0.tgz#9ae2106efc443d7c1e26570aa8247828c9c80f11"
@@ -2401,11 +2628,6 @@
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.1.tgz#76e72d8a775eef7ce649c63c8acae1a0824bbaed"
integrity sha512-XFjFHmaLVifrAKaZ+EKghFHtHSUonyw8P2Qmy2/+osBnrKbH9UYtlK10zg8/kCt47MFilll/DEDKy3DHfJ0URw==
-"@types/prop-types@*":
- version "15.7.5"
- resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
- integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
-
"@types/qs@*":
version "6.9.7"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
@@ -2416,25 +2638,11 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
-"@types/react@>=16.0.0":
- version "18.0.33"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.33.tgz#a1575160cb4376787c2f5fe0312302f824baa61e"
- integrity sha512-sHxzVxeanvQyQ1lr8NSHaj0kDzcNiGpILEVt69g9S31/7PfMvNCKLKcsHw4lYKjs3cGNJjXSP4mYzX43QlnjNA==
- dependencies:
- "@types/prop-types" "*"
- "@types/scheduler" "*"
- csstype "^3.0.2"
-
"@types/retry@^0.12.0":
version "0.12.1"
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.1.tgz#d8f1c0d0dc23afad6dc16a9e993a0865774b4065"
integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==
-"@types/scheduler@*":
- version "0.16.3"
- resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
- integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
-
"@types/serve-index@^1.9.1":
version "1.9.1"
resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278"
@@ -2571,6 +2779,11 @@
"@typescript-eslint/types" "5.38.0"
eslint-visitor-keys "^3.3.0"
+"@vitejs/plugin-vue2@^1.1.2":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue2/-/plugin-vue2-1.1.2.tgz#891f0acc5a6a2b4886a74cb8d6359d42f19f968a"
+ integrity sha512-y6OEA+2UdJ0xrEQHodq20v9r3SpS62IOHrgN92JPLvVpNkhcissu7yvD5PXMzMESyazj0XNWGsc8UQk8+mVrjQ==
+
"@vue/apollo-components@^4.0.0-beta.4":
version "4.0.0-beta.4"
resolved "https://registry.yarnpkg.com/@vue/apollo-components/-/apollo-components-4.0.0-beta.4.tgz#cc2510cf22636c5b13fb42470578031631af6c51"
@@ -2621,7 +2834,7 @@
postcss "^8.4.14"
source-map "^0.6.1"
-"@vue/compiler-sfc@^3.2.47":
+"@vue/compiler-sfc@^3.2.20", "@vue/compiler-sfc@^3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==
@@ -3177,11 +3390,6 @@ array-buffer-byte-length@^1.0.0:
call-bind "^1.0.2"
is-array-buffer "^3.0.1"
-array-find@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
- integrity sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=
-
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@@ -3213,6 +3421,16 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+array.prototype.find@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.2.1.tgz#769b8182a0b535c3d76ac025abab98ba1e12467b"
+ integrity sha512-I2ri5Z9uMpMvnsNrHre9l3PaX+z9D0/z6F7Yt2u15q7wt0I62g5kX6xUKR1SJiefgG+u2/gJUmM8B47XRvQR6w==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.20.4"
+ es-shim-unscopables "^1.0.0"
+
array.prototype.findlastindex@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz#bc229aef98f6bd0533a2bc61ff95209875526c9b"
@@ -3297,6 +3515,18 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+autoprefixer@^10.4.8:
+ version "10.4.14"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d"
+ integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==
+ dependencies:
+ browserslist "^4.21.5"
+ caniuse-lite "^1.0.30001464"
+ fraction.js "^4.2.0"
+ normalize-range "^0.1.2"
+ picocolors "^1.0.0"
+ postcss-value-parser "^4.2.0"
+
autosize@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/autosize/-/autosize-5.0.1.tgz#ed269b0fa9b7eb47627048a1bb3299e99e003a0f"
@@ -3654,15 +3884,15 @@ browserify-zlib@^0.2.0:
dependencies:
pako "~1.0.5"
-browserslist@^4.20.2, browserslist@^4.20.3, browserslist@^4.21.3:
- version "4.21.3"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
- integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
+browserslist@^4.20.2, browserslist@^4.20.3, browserslist@^4.21.3, browserslist@^4.21.5:
+ version "4.21.5"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7"
+ integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
dependencies:
- caniuse-lite "^1.0.30001370"
- electron-to-chromium "^1.4.202"
- node-releases "^2.0.6"
- update-browserslist-db "^1.0.5"
+ caniuse-lite "^1.0.30001449"
+ electron-to-chromium "^1.4.284"
+ node-releases "^2.0.8"
+ update-browserslist-db "^1.0.10"
bser@2.1.1:
version "2.1.1"
@@ -3820,26 +4050,27 @@ callsites@^3.0.0:
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-camelcase-keys@^6.2.2:
- version "6.2.2"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
- integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
+camelcase-keys@^7.0.0:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-7.0.2.tgz#d048d8c69448745bb0de6fc4c1c52a30dfbe7252"
+ integrity sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==
dependencies:
- camelcase "^5.3.1"
- map-obj "^4.0.0"
- quick-lru "^4.0.1"
+ camelcase "^6.3.0"
+ map-obj "^4.1.0"
+ quick-lru "^5.1.1"
+ type-fest "^1.2.1"
camelcase@^5.0.0, camelcase@^5.2.0, camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
-camelcase@^6.2.0:
+camelcase@^6.2.0, camelcase@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-caniuse-lite@^1.0.30001370:
+caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464:
version "1.0.30001478"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001478.tgz#0ef8a1cf8b16be47a0f9fc4ecfc952232724b32a"
integrity sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==
@@ -4028,13 +4259,6 @@ clone-deep@^4.0.1:
kind-of "^6.0.2"
shallow-clone "^3.0.0"
-clone-regexp@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f"
- integrity sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==
- dependencies:
- is-regexp "^2.0.0"
-
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -4077,10 +4301,10 @@ color-name@^1.1.4, color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-colord@^2.9.2:
- version "2.9.2"
- resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1"
- integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==
+colord@^2.9.3:
+ version "2.9.3"
+ resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
+ integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
colorette@^2.0.10, colorette@^2.0.14:
version "2.0.16"
@@ -4307,10 +4531,10 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
-core-js@^3.29.1, core-js@^3.32.0, core-js@^3.6.5:
- version "3.32.0"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.0.tgz#7643d353d899747ab1f8b03d2803b0312a0fb3b6"
- integrity sha512-rd4rYZNlF3WuoYuRIDEmbR/ga9CeuWX9U05umAvgrrZoHY4Z++cp/xwPQMvUpBB4Ag6J8KfD80G0zwCyaSxDww==
+core-js@^3.29.1, core-js@^3.32.2, core-js@^3.6.5:
+ version "3.32.2"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.2.tgz#172fb5949ef468f93b4be7841af6ab1f21992db7"
+ integrity sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ==
core-util-is@~1.0.0:
version "1.0.3"
@@ -4341,16 +4565,15 @@ cosmiconfig@8.0.0:
parse-json "^5.0.0"
path-type "^4.0.0"
-cosmiconfig@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
- integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
+cosmiconfig@^8.2.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd"
+ integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==
dependencies:
- "@types/parse-json" "^4.0.0"
import-fresh "^3.2.1"
+ js-yaml "^4.1.0"
parse-json "^5.0.0"
path-type "^4.0.0"
- yaml "^1.10.0"
create-ecdh@^4.0.0:
version "4.0.0"
@@ -4470,10 +4693,10 @@ css-color-names@0.0.4:
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=
-css-functions-list@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.1.0.tgz#cf5b09f835ad91a00e5959bcfc627cd498e1321b"
- integrity sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==
+css-functions-list@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.2.0.tgz#8290b7d064bf483f48d6559c10e98dc4d1ad19ee"
+ integrity sha512-d/jBMPyYybkkLVypgtGv12R+pIFw4/f/IHtCTxWpZc8ofTYOPigIgmA6vu5rMHartZC+WuXhBUHfnyNUIQSYrg==
css-loader@^2.1.1:
version "2.1.1"
@@ -4492,16 +4715,16 @@ css-loader@^2.1.1:
postcss-value-parser "^3.3.0"
schema-utils "^1.0.0"
-css-select@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.2.tgz#8b52b6714ed3a80d8221ec971c543f3b12653286"
- integrity sha512-nu5ye2Hg/4ISq4XqdLY2bEatAcLIdt3OYGFc9Tm9n7VSlFBcfRv0gBNksHRgSdUDQGtN3XrZ94ztW+NfzkFSUw==
+css-select@^4.1.2, css-select@^4.1.3:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
+ integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
dependencies:
boolbase "^1.0.0"
- css-what "^5.0.0"
- domhandler "^4.2.0"
- domutils "^2.6.0"
- nth-check "^2.0.0"
+ css-what "^6.0.1"
+ domhandler "^4.3.1"
+ domutils "^2.8.0"
+ nth-check "^2.0.1"
css-selector-parser@^1.3:
version "1.3.0"
@@ -4513,12 +4736,20 @@ css-shorthand-properties@^1.0.0:
resolved "https://registry.yarnpkg.com/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz#1c808e63553c283f289f2dd56fcee8f3337bd935"
integrity sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==
-css-tree@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.1.0.tgz#170e27ccf94e7c5facb183765c25898be843d1d2"
- integrity sha512-PcysZRzToBbrpoUrZ9qfblRIRf8zbEAkU0AIpQFtgkFK0vSbzOmBCvdSAx2Zg7Xx5wiYJKUKk0NMP7kxevie/A==
+css-tree@^1.1.2, css-tree@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
+ integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
+ dependencies:
+ mdn-data "2.0.14"
+ source-map "^0.6.1"
+
+css-tree@^2.0.1, css-tree@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20"
+ integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==
dependencies:
- mdn-data "2.0.27"
+ mdn-data "2.0.30"
source-map-js "^1.0.1"
css-values@^0.1.0:
@@ -4535,6 +4766,11 @@ css-what@^5.0.0:
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe"
integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==
+css-what@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
+ integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
+
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
@@ -4545,6 +4781,13 @@ cssfontparser@^1.2.1:
resolved "https://registry.yarnpkg.com/cssfontparser/-/cssfontparser-1.2.1.tgz#f4022fc8f9700c68029d542084afbaf425a3f3e3"
integrity sha1-9AIvyPlwDGgCnVQghK+69CWj8+M=
+csso@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
+ integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
+ dependencies:
+ css-tree "^1.1.2"
+
cssom@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36"
@@ -4562,7 +4805,7 @@ cssstyle@^2.3.0:
dependencies:
cssom "~0.3.6"
-csstype@^3.0.2, csstype@^3.1.0:
+csstype@^3.1.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
@@ -5180,6 +5423,11 @@ decamelize@^1.1.0, decamelize@^1.2.0:
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+decamelize@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9"
+ integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==
+
decimal.js@^10.3.1:
version "10.4.0"
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.0.tgz#97a7448873b01e92e5ff9117d89a7bca8e63e0fe"
@@ -5434,10 +5682,10 @@ domexception@^4.0.0:
dependencies:
webidl-conversions "^7.0.0"
-domhandler@^4.0.0, domhandler@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
- integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
+domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
+ integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
dependencies:
domelementtype "^2.2.0"
@@ -5446,15 +5694,15 @@ dommatrix@^1.0.3:
resolved "https://registry.yarnpkg.com/dommatrix/-/dommatrix-1.0.3.tgz#e7c18e8d6f3abdd1fef3dd4aa74c4d2e620a0525"
integrity sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==
-dompurify@2.4.5, dompurify@^2.4.5:
- version "2.4.5"
- resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.5.tgz#0e89a27601f0bad978f9a924e7a05d5d2cccdd87"
- integrity sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==
+dompurify@^3.0.5:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.5.tgz#eb3d9cfa10037b6e73f32c586682c4b2ab01fbed"
+ integrity sha512-F9e6wPGtY+8KNMRAVfxeCOHU0/NPWMSENNq4pQctuXRqqdEPW7q3CrLbR5Nse044WwacyjHGOMlvNsBe1y6z9A==
-domutils@^2.5.2, domutils@^2.6.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.6.0.tgz#2e15c04185d43fb16ae7057cb76433c6edb938b7"
- integrity sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==
+domutils@^2.5.2, domutils@^2.6.0, domutils@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+ integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
dependencies:
dom-serializer "^1.0.1"
domelementtype "^2.2.0"
@@ -5513,10 +5761,10 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-electron-to-chromium@^1.4.202:
- version "1.4.230"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.230.tgz#666909fdf5765acb1348b69752ee9955dc1664b7"
- integrity sha512-3pwjAK0qHSDN9+YAF4fJknsSruP7mpjdWzUSruIJD/JCH77pEh0SorEyb3xVaKkfwk2tzjOt2D8scJ0KAdfXLA==
+electron-to-chromium@^1.4.284:
+ version "1.4.335"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.335.tgz#69c08baa608bbb58e290d83320190fa82c835efe"
+ integrity sha512-l/eowQqTnrq3gu+WSrdfkhfNHnPgYqlKAwxz7MTOj6mom19vpEDHNXl6dxDxyTiYuhemydprKr/HCrHfgk+OfQ==
elkjs@^0.8.2:
version "0.8.2"
@@ -5702,6 +5950,161 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
+esbuild-android-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
+ integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
+
+esbuild-android-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
+ integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
+
+esbuild-darwin-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
+ integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
+
+esbuild-darwin-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
+ integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
+
+esbuild-freebsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
+ integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
+
+esbuild-freebsd-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
+ integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
+
+esbuild-linux-32@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
+ integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
+
+esbuild-linux-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
+ integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
+
+esbuild-linux-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
+ integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
+
+esbuild-linux-arm@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
+ integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
+
+esbuild-linux-mips64le@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
+ integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
+
+esbuild-linux-ppc64le@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
+ integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
+
+esbuild-linux-riscv64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
+ integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
+
+esbuild-linux-s390x@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
+ integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
+
+esbuild-netbsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
+ integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
+
+esbuild-openbsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
+ integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
+
+esbuild-sunos-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
+ integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
+
+esbuild-windows-32@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
+ integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
+
+esbuild-windows-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
+ integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
+
+esbuild-windows-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
+ integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
+
+esbuild@^0.14.14:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2"
+ integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
+ optionalDependencies:
+ "@esbuild/linux-loong64" "0.14.54"
+ esbuild-android-64 "0.14.54"
+ esbuild-android-arm64 "0.14.54"
+ esbuild-darwin-64 "0.14.54"
+ esbuild-darwin-arm64 "0.14.54"
+ esbuild-freebsd-64 "0.14.54"
+ esbuild-freebsd-arm64 "0.14.54"
+ esbuild-linux-32 "0.14.54"
+ esbuild-linux-64 "0.14.54"
+ esbuild-linux-arm "0.14.54"
+ esbuild-linux-arm64 "0.14.54"
+ esbuild-linux-mips64le "0.14.54"
+ esbuild-linux-ppc64le "0.14.54"
+ esbuild-linux-riscv64 "0.14.54"
+ esbuild-linux-s390x "0.14.54"
+ esbuild-netbsd-64 "0.14.54"
+ esbuild-openbsd-64 "0.14.54"
+ esbuild-sunos-64 "0.14.54"
+ esbuild-windows-32 "0.14.54"
+ esbuild-windows-64 "0.14.54"
+ esbuild-windows-arm64 "0.14.54"
+
+esbuild@^0.18.10:
+ version "0.18.15"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.15.tgz#5b5c1a22e608afd5675f82ad466c4d2cfd723f85"
+ integrity sha512-3WOOLhrvuTGPRzQPU6waSDWrDTnQriia72McWcn6UCi43GhCHrXH4S59hKMeez+IITmdUuUyvbU9JIp+t3xlPQ==
+ optionalDependencies:
+ "@esbuild/android-arm" "0.18.15"
+ "@esbuild/android-arm64" "0.18.15"
+ "@esbuild/android-x64" "0.18.15"
+ "@esbuild/darwin-arm64" "0.18.15"
+ "@esbuild/darwin-x64" "0.18.15"
+ "@esbuild/freebsd-arm64" "0.18.15"
+ "@esbuild/freebsd-x64" "0.18.15"
+ "@esbuild/linux-arm" "0.18.15"
+ "@esbuild/linux-arm64" "0.18.15"
+ "@esbuild/linux-ia32" "0.18.15"
+ "@esbuild/linux-loong64" "0.18.15"
+ "@esbuild/linux-mips64el" "0.18.15"
+ "@esbuild/linux-ppc64" "0.18.15"
+ "@esbuild/linux-riscv64" "0.18.15"
+ "@esbuild/linux-s390x" "0.18.15"
+ "@esbuild/linux-x64" "0.18.15"
+ "@esbuild/netbsd-x64" "0.18.15"
+ "@esbuild/openbsd-x64" "0.18.15"
+ "@esbuild/sunos-x64" "0.18.15"
+ "@esbuild/win32-arm64" "0.18.15"
+ "@esbuild/win32-ia32" "0.18.15"
+ "@esbuild/win32-x64" "0.18.15"
+
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@@ -5778,12 +6181,12 @@ eslint-import-resolver-node@^0.3.7:
is-core-module "^2.11.0"
resolve "^1.22.1"
-eslint-import-resolver-webpack@0.13.4:
- version "0.13.4"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.4.tgz#77b3ea5dabc483053c75ccf29d0fe8f706a71897"
- integrity sha512-6RN3DFoOu8J05VAjuclAquTiLou/JYZx4x7qoL2rC96LmNqYyIwszSqb+Ys1Q+eA6qvQhXYKDaHnEpHmDA0qBw==
+eslint-import-resolver-webpack@0.13.7:
+ version "0.13.7"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.7.tgz#49cd0108767b1f8ff81123c7e1ae362305aad47b"
+ integrity sha512-2a+meyMeABBRO4K53Oj1ygkmt5lhQS79Lmx2f684Qnv6gjvD4RLOM5jfPGTXwQ0A2K03WSoKt3HRQu/uBgxF7w==
dependencies:
- array-find "^1.0.0"
+ array.prototype.find "^2.2.1"
debug "^3.2.7"
enhanced-resolve "^0.9.1"
find-root "^1.1.0"
@@ -5792,7 +6195,7 @@ eslint-import-resolver-webpack@0.13.4:
is-core-module "^2.13.0"
is-regex "^1.1.4"
lodash "^4.17.21"
- resolve "^1.22.4"
+ resolve "^2.0.0-next.4"
semver "^5.7.2"
eslint-module-utils@^2.8.0:
@@ -5802,10 +6205,10 @@ eslint-module-utils@^2.8.0:
dependencies:
debug "^3.2.7"
-eslint-plugin-import@^2.28.0:
- version "2.28.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz#8d66d6925117b06c4018d491ae84469eb3cb1005"
- integrity sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==
+eslint-plugin-import@^2.28.0, eslint-plugin-import@^2.28.1:
+ version "2.28.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4"
+ integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==
dependencies:
array-includes "^3.1.6"
array.prototype.findlastindex "^1.2.2"
@@ -5816,13 +6219,12 @@ eslint-plugin-import@^2.28.0:
eslint-import-resolver-node "^0.3.7"
eslint-module-utils "^2.8.0"
has "^1.0.3"
- is-core-module "^2.12.1"
+ is-core-module "^2.13.0"
is-glob "^4.0.3"
minimatch "^3.1.2"
object.fromentries "^2.0.6"
object.groupby "^1.0.0"
object.values "^1.1.6"
- resolve "^1.22.3"
semver "^6.3.1"
tsconfig-paths "^3.14.2"
@@ -5917,21 +6319,21 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
-eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.2:
- version "3.4.2"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz#8c2095440eca8c933bedcadf16fefa44dbe9ba5f"
- integrity sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
-eslint@8.46.0:
- version "8.46.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.46.0.tgz#a06a0ff6974e53e643acc42d1dcf2e7f797b3552"
- integrity sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==
+eslint@8.49.0:
+ version "8.49.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42"
+ integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.6.1"
- "@eslint/eslintrc" "^2.1.1"
- "@eslint/js" "^8.46.0"
- "@humanwhocodes/config-array" "^0.11.10"
+ "@eslint/eslintrc" "^2.1.2"
+ "@eslint/js" "8.49.0"
+ "@humanwhocodes/config-array" "^0.11.11"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
ajv "^6.12.4"
@@ -5941,7 +6343,7 @@ eslint@8.46.0:
doctrine "^3.0.0"
escape-string-regexp "^4.0.0"
eslint-scope "^7.2.2"
- eslint-visitor-keys "^3.4.2"
+ eslint-visitor-keys "^3.4.3"
espree "^9.6.1"
esquery "^1.4.2"
esutils "^2.0.2"
@@ -6066,13 +6468,6 @@ execa@^5.0.0:
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"
-execall@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45"
- integrity sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==
- dependencies:
- clone-regexp "^2.1.0"
-
exit@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@@ -6199,10 +6594,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.4, fast-glob@^3.2.9:
- version "3.2.12"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
- integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
+fast-glob@^3.2.12, fast-glob@^3.2.4, fast-glob@^3.2.9, fast-glob@^3.3.0:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4"
+ integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
@@ -6225,10 +6620,10 @@ fast-mersenne-twister@1.0.2:
resolved "https://registry.yarnpkg.com/fast-mersenne-twister/-/fast-mersenne-twister-1.0.2.tgz#5ead7caf3ace592a5789d11767732bd81cbaaa56"
integrity sha512-IaClPxsoBu3MxGpcURyjV8otT5Bj4ARoK0KBCJGnEVnD1A/qclL5eIeYiUuwG/WWJPxL1jlK61HTm2T6SBmvBQ==
-fastest-levenshtein@^1.0.12:
- version "1.0.12"
- resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
- integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
+fastest-levenshtein@^1.0.12, fastest-levenshtein@^1.0.16:
+ version "1.0.16"
+ resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
+ integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
fastq@^1.6.0:
version "1.13.0"
@@ -6439,6 +6834,11 @@ forwarded@0.2.0:
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+fraction.js@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
+ integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
+
fragment-cache@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
@@ -6555,11 +6955,6 @@ get-stdin@^6.0.0:
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
-get-stdin@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53"
- integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==
-
get-stdin@~9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575"
@@ -6779,7 +7174,7 @@ graphql-sse@^1.0.1:
resolved "https://registry.yarnpkg.com/graphql-sse/-/graphql-sse-1.0.4.tgz#051598b0e06c225327aac659f19fcc18bcaa0191"
integrity sha512-oB43ifRcEdElgep9jTP9qsj5cJ7Ny/1tAFyIl1W3A0hXRRg/P71tUHzMFBrRkEsJ9IA7MTp+RKSJfh52QR6PBQ==
-graphql-tag@^2.11.0, graphql-tag@^2.12.3:
+graphql-tag@^2.11.0, graphql-tag@^2.12.3, graphql-tag@^2.12.6:
version "2.12.6"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1"
integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==
@@ -6796,10 +7191,10 @@ graphql@^15.7.2:
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.7.2.tgz#85ab0eeb83722977151b3feb4d631b5f2ab287ef"
integrity sha512-AnnKk7hFQFmU/2I9YSQf3xw44ctnSFCfp3zE0N6W174gqe9fWG/2rKaKxROK7CcI3XtERpjEKFqts8o319Kf7A==
-gridstack@^8.4.0:
- version "8.4.0"
- resolved "https://registry.yarnpkg.com/gridstack/-/gridstack-8.4.0.tgz#7af49159f9dc144c89a2c56246e1710406f75fcf"
- integrity sha512-qLJuJrBy9bbG3hI+h2cEhiuZ51J3MyEMmv5AXg7MCFiBeG8A4HyIUytueqtD/oZcA3Pccq2Xoj7GrwpmKOS3ig==
+gridstack@^9.2.0:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/gridstack/-/gridstack-9.2.0.tgz#1a415185649a8ebe8a92f9aebea14183f2996d25"
+ integrity sha512-+uWb4p1Za3j6OfvumXzuWQ4EcDh3kZZFLr0vONLPdrtGPJuxb73TjqttEu4igW7iP2Y80kewfYnNT6kQ0blJQQ==
gzip-size@^6.0.0:
version "6.0.0"
@@ -7072,10 +7467,10 @@ html-escaper@^2.0.0:
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491"
integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==
-html-tags@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961"
- integrity sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==
+html-tags@^3.3.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce"
+ integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==
html-void-elements@^2.0.0:
version "2.0.1"
@@ -7216,7 +7611,7 @@ ignore-by-default@^1.0.1:
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
-ignore@^5.2.0, ignore@~5.2.4:
+ignore@^5.2.0, ignore@^5.2.4, ignore@~5.2.4:
version "5.2.4"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
@@ -7267,6 +7662,11 @@ indent-string@^4.0.0:
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+indent-string@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5"
+ integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==
+
infer-owner@^1.0.3, infer-owner@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
@@ -7428,7 +7828,7 @@ is-ci@^2.0.0:
dependencies:
ci-info "^2.0.0"
-is-core-module@^2.11.0, is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.5.0:
+is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.9.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
@@ -7580,11 +7980,6 @@ is-regex@^1.1.4:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
-is-regexp@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d"
- integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==
-
is-shared-array-buffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
@@ -8367,10 +8762,10 @@ kleur@^4.0.3:
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d"
integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==
-known-css-properties@^0.25.0:
- version "0.25.0"
- resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.25.0.tgz#6ebc4d4b412f602e5cfbeb4086bd544e34c0a776"
- integrity sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==
+known-css-properties@^0.27.0:
+ version "0.27.0"
+ resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.27.0.tgz#82a9358dda5fe7f7bd12b5e7142c0a205393c0c5"
+ integrity sha512-uMCj6+hZYDoffuvAJjFAPz56E9uoowFHmTkqRtRq5WyC5Q6Cu/fTZKNQpX/RbzChBYLLl3lo8CjFZBAZXq9qFg==
launch-editor@^2.6.0:
version "2.6.0"
@@ -8451,9 +8846,9 @@ loader-runner@^4.1.0:
integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
- integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.2.tgz#29a957f3a63973883eb684f10ffd3d151fec01a3"
+ integrity sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"
@@ -8520,6 +8915,11 @@ lodash.debounce@^4.0.8:
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
+lodash.escape@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
+ integrity sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==
+
lodash.find@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
@@ -8605,6 +9005,11 @@ lodash.pick@^4.4.0:
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
+lodash.pullall@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.pullall/-/lodash.pullall-4.2.0.tgz#9d98b8518b7c965b0fae4099bd9fb7df8bbf38ba"
+ integrity sha512-VhqxBKH0ZxPpLhiu68YD1KnHmbhQJQctcipvmFnqIBDYzcIHzf3Zpu0tpeOKtR4x76p9yohc506eGdOjTmyIBg==
+
lodash.snakecase@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
@@ -8727,7 +9132,7 @@ map-obj@^1.0.0:
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
-map-obj@^4.0.0:
+map-obj@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a"
integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==
@@ -8841,10 +9246,10 @@ mdast-util-find-and-replace@^2.0.0:
unist-util-is "^5.0.0"
unist-util-visit-parents "^4.0.0"
-mdast-util-from-markdown@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz#84df2924ccc6c995dec1e2368b2b208ad0a76268"
- integrity sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==
+mdast-util-from-markdown@^1.0.0, mdast-util-from-markdown@^1.3.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz#9421a5a247f10d31d2faed2a30df5ec89ceafcf0"
+ integrity sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==
dependencies:
"@types/mdast" "^3.0.0"
"@types/unist" "^2.0.0"
@@ -8957,10 +9362,15 @@ mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0:
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9"
integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==
-mdn-data@2.0.27:
- version "2.0.27"
- resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.27.tgz#1710baa7b0db8176d3b3d565ccb7915fc69525ab"
- integrity sha512-kwqO0I0jtWr25KcfLm9pia8vLZ8qoAKhWZuZMbneJq3jjBD3gl5nZs8l8Tu3ZBlBAHVQtDur9rdDGyvtfVraHQ==
+mdn-data@2.0.14:
+ version "2.0.14"
+ resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
+ integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
+
+mdn-data@2.0.30:
+ version "2.0.30"
+ resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc"
+ integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==
mdurl@^1.0.0, mdurl@^1.0.1:
version "1.0.1"
@@ -9000,23 +9410,23 @@ memory-fs@^0.5.0:
errno "^0.1.3"
readable-stream "^2.0.1"
-meow@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364"
- integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==
+meow@^10.1.5:
+ version "10.1.5"
+ resolved "https://registry.yarnpkg.com/meow/-/meow-10.1.5.tgz#be52a1d87b5f5698602b0f32875ee5940904aa7f"
+ integrity sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==
dependencies:
- "@types/minimist" "^1.2.0"
- camelcase-keys "^6.2.2"
- decamelize "^1.2.0"
+ "@types/minimist" "^1.2.2"
+ camelcase-keys "^7.0.0"
+ decamelize "^5.0.0"
decamelize-keys "^1.1.0"
hard-rejection "^2.1.0"
minimist-options "4.1.0"
- normalize-package-data "^3.0.0"
- read-pkg-up "^7.0.1"
- redent "^3.0.0"
- trim-newlines "^3.0.0"
- type-fest "^0.18.0"
- yargs-parser "^20.2.3"
+ normalize-package-data "^3.0.2"
+ read-pkg-up "^8.0.0"
+ redent "^4.0.0"
+ trim-newlines "^4.0.2"
+ type-fest "^1.2.2"
+ yargs-parser "^20.2.9"
merge-descriptors@1.0.1:
version "1.0.1"
@@ -9040,25 +9450,28 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-mermaid@10.1.0:
- version "10.1.0"
- resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.1.0.tgz#6e40d5250174f4750ca6548e4ee00f6ae210855a"
- integrity sha512-LYekSMNJygI1VnMizAPUddY95hZxOjwZxr7pODczILInO0dhQKuhXeu4sargtnuTwCilSuLS7Uiq/Qn7HTVrmA==
+mermaid@10.3.1:
+ version "10.3.1"
+ resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.3.1.tgz#2f3c7e9f6bd7a8da2bef71cce2a542c8eba2a62e"
+ integrity sha512-hkenh7WkuRWPcob3oJtrN3W+yzrrIYuWF1OIfk/d0xGE8UWlvDhfexaHmDwwe8DKQgqMLI8DWEPwGprxkumjuw==
dependencies:
- "@braintree/sanitize-url" "^6.0.0"
- "@khanacademy/simple-markdown" "^0.8.6"
+ "@braintree/sanitize-url" "^6.0.1"
+ "@types/d3-scale" "^4.0.3"
+ "@types/d3-scale-chromatic" "^3.0.0"
cytoscape "^3.23.0"
cytoscape-cose-bilkent "^4.1.0"
cytoscape-fcose "^2.1.0"
d3 "^7.4.0"
+ d3-sankey "^0.12.3"
dagre-d3-es "7.0.10"
dayjs "^1.11.7"
- dompurify "2.4.5"
+ dompurify "^3.0.5"
elkjs "^0.8.2"
khroma "^2.0.0"
lodash-es "^4.17.21"
+ mdast-util-from-markdown "^1.3.0"
non-layered-tidy-tree-layout "^2.0.2"
- stylis "^4.1.2"
+ stylis "^4.1.3"
ts-dedent "^2.2.0"
uuid "^9.0.0"
web-worker "^1.2.0"
@@ -9409,11 +9822,6 @@ mime@1.6.0:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-mime@^2.3.1:
- version "2.4.4"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
- integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
-
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@@ -9426,7 +9834,7 @@ min-document@^2.19.0:
dependencies:
dom-walk "^0.1.0"
-min-indent@^1.0.0:
+min-indent@^1.0.0, min-indent@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
@@ -9572,6 +9980,11 @@ mississippi@^3.0.0:
stream-each "^1.1.0"
through2 "^2.0.0"
+mitt@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
+ integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
+
mixin-deep@^1.2.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
@@ -9664,6 +10077,11 @@ mri@^1.1.0:
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
+mrmime@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27"
+ integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==
+
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -9687,10 +10105,10 @@ multicast-dns@^7.2.4:
dns-packet "^5.2.2"
thunky "^1.0.2"
-nanoid@^3.3.4:
- version "3.3.4"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
- integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
+nanoid@^3.3.6:
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
+ integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
nanomatch@^1.2.9:
version "1.2.13"
@@ -9780,10 +10198,10 @@ node-libs-browser@^2.2.1:
util "^0.11.0"
vm-browserify "^1.0.1"
-node-releases@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
- integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
+node-releases@^2.0.8:
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f"
+ integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
nodemon@^2.0.19:
version "2.0.19"
@@ -9830,7 +10248,7 @@ normalize-package-data@^2.5.0:
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
-normalize-package-data@^3.0.0:
+normalize-package-data@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e"
integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==
@@ -9852,6 +10270,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+normalize-range@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
+ integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
+
npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
@@ -9859,7 +10282,7 @@ npm-run-path@^4.0.1:
dependencies:
path-key "^3.0.0"
-nth-check@^2.0.0, nth-check@^2.0.1:
+nth-check@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2"
integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==
@@ -10399,15 +10822,15 @@ postcss-safe-parser@^6.0.0:
resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1"
integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==
-postcss-scss@4.0.4:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.4.tgz#aa8f60e19ee18259bc193db9e4b96edfce3f3b1f"
- integrity sha512-aBBbVyzA8b3hUL0MGrpydxxXKXFZc5Eqva0Q3V9qsBOLEMsjb6w49WfpsoWzpEgcqJGW4t7Rio8WXVU9Gd8vWg==
+postcss-scss@4.0.7:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.7.tgz#cfe5507aaff81b3d8992039ad015da4bd3dccd2f"
+ integrity sha512-xPv2GseoyXPa58Nro7M73ZntttusuCmZdeOojUFR5PZDz2BR62vfYx1w9TyOnp1+nYFowgOMipsCBhxzVkAEPw==
-postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9:
- version "6.0.10"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
- integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
+postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.13, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.9:
+ version "6.0.13"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b"
+ integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==
dependencies:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
@@ -10417,17 +10840,17 @@ postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
-postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
+postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
-postcss@8.4.14, postcss@^8.1.10, postcss@^8.2.1, postcss@^8.4.14:
- version "8.4.14"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
- integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
+postcss@8.4.28, postcss@^8.1.10, postcss@^8.2.1, postcss@^8.4.14, postcss@^8.4.25, postcss@^8.4.27:
+ version "8.4.28"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.28.tgz#c6cc681ed00109072816e1557f889ef51cf950a5"
+ integrity sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==
dependencies:
- nanoid "^3.3.4"
+ nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
@@ -10600,10 +11023,10 @@ prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.0:
prosemirror-state "^1.0.0"
w3c-keyname "^2.2.0"
-prosemirror-markdown@1.11.1, prosemirror-markdown@^1.10.1:
- version "1.11.1"
- resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.11.1.tgz#441ad0ac4ab7c30f50623517e65c6bb8e966e9e3"
- integrity sha512-CLOieKoaSSEusKyYcXIj8v2qHGLW+tnuffci+8678Sen48NEFQE7M3o0Nx0gj9v63iVDj+yLibj2gCe8eb3jIw==
+prosemirror-markdown@1.11.2, prosemirror-markdown@^1.10.1:
+ version "1.11.2"
+ resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.11.2.tgz#f6e529e669d11fa3eec859e93c0d2c91788d6c80"
+ integrity sha512-Eu5g4WPiCdqDTGhdSsG9N6ZjACQRYrsAkrF9KYfdMaCmjIApH75aVncsWYOJvEk2i1B3i8jZppv3J/tnuHGiUQ==
dependencies:
markdown-it "^13.0.1"
prosemirror-model "^1.0.0"
@@ -10813,10 +11236,10 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
-quick-lru@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
- integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
+quick-lru@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
+ integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
ramda@^0.27.2:
version "0.27.2"
@@ -10892,6 +11315,15 @@ read-pkg-up@^7.0.1:
read-pkg "^5.2.0"
type-fest "^0.8.1"
+read-pkg-up@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-8.0.0.tgz#72f595b65e66110f43b052dd9af4de6b10534670"
+ integrity sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==
+ dependencies:
+ find-up "^5.0.0"
+ read-pkg "^6.0.0"
+ type-fest "^1.0.1"
+
read-pkg@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
@@ -10902,6 +11334,16 @@ read-pkg@^5.2.0:
parse-json "^5.0.0"
type-fest "^0.6.0"
+read-pkg@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-6.0.0.tgz#a67a7d6a1c2b0c3cd6aa2ea521f40c458a4a504c"
+ integrity sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==
+ dependencies:
+ "@types/normalize-package-data" "^2.4.0"
+ normalize-package-data "^3.0.2"
+ parse-json "^5.2.0"
+ type-fest "^1.0.1"
+
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
@@ -10957,13 +11399,13 @@ rechoir@^0.7.0:
dependencies:
resolve "^1.9.0"
-redent@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
- integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
+redent@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/redent/-/redent-4.0.0.tgz#0c0ba7caabb24257ab3bb7a4fd95dd1d5c5681f9"
+ integrity sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==
dependencies:
- indent-string "^4.0.0"
- strip-indent "^3.0.0"
+ indent-string "^5.0.0"
+ strip-indent "^4.0.0"
regenerate-unicode-properties@^10.0.1:
version "10.0.1"
@@ -11150,7 +11592,7 @@ resolve.exports@^1.1.0:
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9"
integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==
-resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.3, resolve@^1.22.4, resolve@^1.9.0:
+resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.9.0:
version "1.22.4"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34"
integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==
@@ -11159,6 +11601,15 @@ resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.2
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
+resolve@^2.0.0-next.4:
+ version "2.0.0-next.4"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660"
+ integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==
+ dependencies:
+ is-core-module "^2.9.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@@ -11201,6 +11652,13 @@ robust-predicates@^3.0.0:
resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a"
integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==
+rollup@^3.27.1:
+ version "3.27.2"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.27.2.tgz#59adc973504408289be89e5978e938ce852c9520"
+ integrity sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==
+ optionalDependencies:
+ fsevents "~2.3.2"
+
rope-sequence@^1.3.0:
version "1.3.3"
resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.3.tgz#3f67fc106288b84b71532b4a5fd9d4881e4457f0"
@@ -11429,15 +11887,17 @@ send@0.17.2:
"@sentry/utils" "5.30.0"
tslib "^1.9.3"
-"sentrybrowser7@npm:@sentry/browser@^7.21.1":
- version "7.21.1"
- resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.21.1.tgz#bffa3ea19050c06400107d2297b9802f9719f98b"
- integrity sha512-cS2Jz2+fs9+4pJqLJPtYqGyY97ywJDWAWIR1Yla3hs1QQuH6m0Nz3ojZD1gE2eKH9mHwkGbnNAh+hHcrYrfGzw==
+"sentrybrowser@npm:@sentry/browser@7.66.0":
+ version "7.66.0"
+ resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.66.0.tgz#9aa3078f8914d2f8acb4ad9fc7b2011c80e357f5"
+ integrity sha512-rW037rf8jkhyykG38+HUdwkRCKHJEMM5NkCqPIO5zuuxfLKukKdI2rbvgJ93s3/9UfsTuDFcKFL1u43mCn6sDw==
dependencies:
- "@sentry/core" "7.21.1"
- "@sentry/types" "7.21.1"
- "@sentry/utils" "7.21.1"
- tslib "^1.9.3"
+ "@sentry-internal/tracing" "7.66.0"
+ "@sentry/core" "7.66.0"
+ "@sentry/replay" "7.66.0"
+ "@sentry/types" "7.66.0"
+ "@sentry/utils" "7.66.0"
+ tslib "^2.4.1 || ^1.9.3"
serialize-javascript@^2.1.2:
version "2.1.2"
@@ -11601,14 +12061,14 @@ simple-update-notifier@^1.0.7:
dependencies:
semver "~7.0.0"
-sirv@^1.0.7:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.11.tgz#81c19a29202048507d6ec0d8ba8910fda52eb5a4"
- integrity sha512-SR36i3/LSWja7AJNRBz4fF/Xjpn7lQFI30tZ434dIy+bitLYSP+ZEenHg36i23V2SGEz+kqjksg0uOGZ5LPiqg==
+sirv@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.3.tgz#ca5868b87205a74bef62a469ed0296abceccd446"
+ integrity sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==
dependencies:
- "@polka/url" "^1.0.0-next.9"
- mime "^2.3.1"
- totalist "^1.0.0"
+ "@polka/url" "^1.0.0-next.20"
+ mrmime "^1.0.0"
+ totalist "^3.0.0"
sisteransi@^1.0.4:
version "1.0.5"
@@ -11807,6 +12267,11 @@ ssri@^8.0.0:
dependencies:
minipass "^3.1.1"
+stable@^0.1.8:
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+ integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
stack-utils@^2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5"
@@ -11972,6 +12437,13 @@ strip-indent@^3.0.0:
dependencies:
min-indent "^1.0.0"
+strip-indent@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-4.0.0.tgz#b41379433dd06f5eae805e21d631e07ee670d853"
+ integrity sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==
+ dependencies:
+ min-indent "^1.0.1"
+
strip-json-comments@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
@@ -12002,75 +12474,74 @@ style-to-object@^0.3.0:
dependencies:
inline-style-parser "0.1.1"
-stylelint-declaration-strict-value@1.8.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/stylelint-declaration-strict-value/-/stylelint-declaration-strict-value-1.8.0.tgz#d14f368d5974085896d6573cab7c82ad4f415f57"
- integrity sha512-0+DbPQMgqomlBG+uycI3PZ1BzjJ7mJA065Lx+iTg9tlmjBD36f3ZaIq1ggRZQitE0w+KcbXGzFt6axR1LIP2hw==
+stylelint-declaration-strict-value@1.9.2:
+ version "1.9.2"
+ resolved "https://registry.yarnpkg.com/stylelint-declaration-strict-value/-/stylelint-declaration-strict-value-1.9.2.tgz#f2a884c669974a73f82c9f24b05beb81bc337480"
+ integrity sha512-Z/2yr7g4tq2iGOUWhZLzHL2g2GJYJGcPkfjDh++zI8ukLxW0tcLGJjo64XYCDjja6YcECPDUWbpN+OAoAtAYvw==
dependencies:
css-values "^0.1.0"
shortcss "^0.1.3"
-stylelint-scss@4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-4.2.0.tgz#e25fd390ee38a7e89fcfaec2a8f9dce2ec6ddee8"
- integrity sha512-HHHMVKJJ5RM9pPIbgJ/XA67h9H0407G68Rm69H4fzFbFkyDMcTV1Byep3qdze5+fJ3c0U7mJrbj6S0Fg072uZA==
+stylelint-scss@5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-5.1.0.tgz#dd318bc5c65f7a11f3ecacc7b6e8b67e7f2f1df1"
+ integrity sha512-E+KlQFXv1Euha43qw3q+wKBSli557wxbbo6/39DWhRNXlUa9Cz+FYrcgz+PT6ag0l6UisCYjAGCNhoSl4FcwlA==
dependencies:
- lodash "^4.17.21"
postcss-media-query-parser "^0.2.3"
postcss-resolve-nested-selector "^0.1.1"
- postcss-selector-parser "^6.0.6"
- postcss-value-parser "^4.1.0"
+ postcss-selector-parser "^6.0.13"
+ postcss-value-parser "^4.2.0"
-stylelint@^14.9.1:
- version "14.9.1"
- resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.9.1.tgz#6494ed38f148b1e75b402d678a3b6a8aae86dfda"
- integrity sha512-RdAkJdPiLqHawCSnu21nE27MjNXaVd4WcOHA4vK5GtIGjScfhNnaOuWR2wWdfKFAvcWQPOYe311iveiVKSmwsA==
+stylelint@^15.10.2:
+ version "15.10.2"
+ resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-15.10.2.tgz#0ee5a8371d3a2e1ff27fefd48309d3ddef7c3405"
+ integrity sha512-UxqSb3hB74g4DTO45QhUHkJMjKKU//lNUAOWyvPBVPZbCknJ5HjOWWZo+UDuhHa9FLeVdHBZXxu43eXkjyIPWg==
dependencies:
- "@csstools/selector-specificity" "^2.0.1"
+ "@csstools/css-parser-algorithms" "^2.3.0"
+ "@csstools/css-tokenizer" "^2.1.1"
+ "@csstools/media-query-list-parser" "^2.1.2"
+ "@csstools/selector-specificity" "^3.0.0"
balanced-match "^2.0.0"
- colord "^2.9.2"
- cosmiconfig "^7.0.1"
- css-functions-list "^3.1.0"
+ colord "^2.9.3"
+ cosmiconfig "^8.2.0"
+ css-functions-list "^3.2.0"
+ css-tree "^2.3.1"
debug "^4.3.4"
- execall "^2.0.0"
- fast-glob "^3.2.11"
- fastest-levenshtein "^1.0.12"
+ fast-glob "^3.3.0"
+ fastest-levenshtein "^1.0.16"
file-entry-cache "^6.0.1"
- get-stdin "^8.0.0"
global-modules "^2.0.0"
globby "^11.1.0"
globjoin "^0.1.4"
- html-tags "^3.2.0"
- ignore "^5.2.0"
+ html-tags "^3.3.1"
+ ignore "^5.2.4"
import-lazy "^4.0.0"
imurmurhash "^0.1.4"
is-plain-object "^5.0.0"
- known-css-properties "^0.25.0"
+ known-css-properties "^0.27.0"
mathml-tag-names "^2.1.3"
- meow "^9.0.0"
+ meow "^10.1.5"
micromatch "^4.0.5"
normalize-path "^3.0.0"
picocolors "^1.0.0"
- postcss "^8.4.14"
- postcss-media-query-parser "^0.2.3"
+ postcss "^8.4.25"
postcss-resolve-nested-selector "^0.1.1"
postcss-safe-parser "^6.0.0"
- postcss-selector-parser "^6.0.10"
+ postcss-selector-parser "^6.0.13"
postcss-value-parser "^4.2.0"
resolve-from "^5.0.0"
string-width "^4.2.3"
strip-ansi "^6.0.1"
style-search "^0.1.0"
- supports-hyperlinks "^2.2.0"
+ supports-hyperlinks "^3.0.0"
svg-tags "^1.0.0"
- table "^6.8.0"
- v8-compile-cache "^2.3.0"
- write-file-atomic "^4.0.1"
+ table "^6.8.1"
+ write-file-atomic "^5.0.1"
-stylis@^4.1.2:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7"
- integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==
+stylis@^4.1.3:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.0.tgz#abe305a669fc3d8777e10eefcfc73ad861c5588c"
+ integrity sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==
subscriptions-transport-ws@^0.11.0:
version "0.11.0"
@@ -12104,7 +12575,7 @@ supports-color@^8.0.0:
dependencies:
has-flag "^4.0.0"
-supports-hyperlinks@^2.0.0, supports-hyperlinks@^2.2.0:
+supports-hyperlinks@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb"
integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==
@@ -12112,6 +12583,14 @@ supports-hyperlinks@^2.0.0, supports-hyperlinks@^2.2.0:
has-flag "^4.0.0"
supports-color "^7.0.0"
+supports-hyperlinks@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz#c711352a5c89070779b4dad54c05a2f14b15c94b"
+ integrity sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==
+ dependencies:
+ has-flag "^4.0.0"
+ supports-color "^7.0.0"
+
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
@@ -12122,6 +12601,19 @@ svg-tags@^1.0.0:
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=
+svgo@^2.7.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
+ integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
+ dependencies:
+ "@trysound/sax" "0.2.0"
+ commander "^7.2.0"
+ css-select "^4.1.3"
+ css-tree "^1.1.3"
+ csso "^4.2.0"
+ picocolors "^1.0.0"
+ stable "^0.1.8"
+
swagger-cli@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/swagger-cli/-/swagger-cli-4.0.4.tgz#c3f0b94277073c776b9bcc3ae7507b372f3ff414"
@@ -12157,10 +12649,10 @@ sync-fetch@^0.3.1:
buffer "^5.7.0"
node-fetch "^2.6.1"
-table@^6.8.0:
- version "6.8.0"
- resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca"
- integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==
+table@^6.8.1:
+ version "6.8.1"
+ resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf"
+ integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==
dependencies:
ajv "^8.0.1"
lodash.truncate "^4.4.2"
@@ -12363,10 +12855,10 @@ toidentifier@1.0.1:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
-totalist@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
- integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
+totalist@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8"
+ integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==
touch@^3.1.0:
version "3.1.0"
@@ -12408,10 +12900,10 @@ traverse@^0.6.7:
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe"
integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==
-trim-newlines@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
- integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
+trim-newlines@^4.0.2:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.1.1.tgz#28c88deb50ed10c7ba6dc2474421904a00139125"
+ integrity sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==
trough@^2.0.0:
version "2.1.0"
@@ -12460,10 +12952,10 @@ tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
- integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
+tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.4.1, "tslib@^2.4.1 || ^1.9.3", tslib@^2.5.0:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
+ integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
tsutils@^3.21.0:
version "3.21.0"
@@ -12496,11 +12988,6 @@ type-detect@4.0.8:
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
-type-fest@^0.18.0:
- version "0.18.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
- integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
-
type-fest@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
@@ -12521,6 +13008,11 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
+ integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
+
type-fest@^2.0.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
@@ -12779,10 +13271,10 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
-update-browserslist-db@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38"
- integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==
+update-browserslist-db@^1.0.10:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
+ integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==
dependencies:
escalade "^3.1.1"
picocolors "^1.0.0"
@@ -12880,11 +13372,6 @@ uvu@^0.5.0:
kleur "^4.0.3"
sade "^1.7.3"
-v8-compile-cache@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
- integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
-
v8-to-istanbul@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4"
@@ -12943,6 +13430,33 @@ visibilityjs@^1.2.4:
resolved "https://registry.yarnpkg.com/visibilityjs/-/visibilityjs-1.2.4.tgz#bff8663da62c8c10ad4ee5ae6a1ae6fac4259d63"
integrity sha1-v/hmPaYsjBCtTuWuahrm+sQlnWM=
+vite-plugin-ruby@^3.2.2:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/vite-plugin-ruby/-/vite-plugin-ruby-3.2.2.tgz#a174bc435b11350cfcb1b976342ca740d0bcaed2"
+ integrity sha512-cuHG1MajRWPR8YdfF6lvgsQRnKFEBRwZF//asFbRiI1psacxB5aPlHSvYZYxAu5IflrAa0MdR0HxEq+g98M3iQ==
+ dependencies:
+ debug "^4.3.4"
+ fast-glob "^3.2.12"
+
+vite-svg-loader@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/vite-svg-loader/-/vite-svg-loader-3.6.0.tgz#71d246cba5e808c7f183a2a56a9dde6856bb0c92"
+ integrity sha512-bZJffcgCREW57kNkgMhuNqeDznWXyQwJ3wKrRhHLMMzwDnP5jr3vXW3cqsmquRR7VTP5mLdKj1/zzPPooGUuPw==
+ dependencies:
+ "@vue/compiler-sfc" "^3.2.20"
+ svgo "^2.7.0"
+
+vite@^4.4.9:
+ version "4.4.9"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d"
+ integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==
+ dependencies:
+ esbuild "^0.18.10"
+ postcss "^8.4.27"
+ rollup "^3.27.1"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
vm-browserify@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
@@ -13004,10 +13518,10 @@ vue-hot-reload-api@^2.3.0:
hash-sum "^2.0.0"
loader-utils "^2.0.0"
-vue-loader@15.10.1:
- version "15.10.1"
- resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.10.1.tgz#c451c4cd05a911aae7b5dbbbc09fb913fb3cca18"
- integrity sha512-SaPHK1A01VrNthlix6h1hq4uJu7S/z0kdLUb6klubo738NeQoLbS6V9/d8Pv19tU0XdQKju3D1HSKuI8wJ5wMA==
+vue-loader@15.10.2:
+ version "15.10.2"
+ resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.10.2.tgz#6dccfda8661caa7f5415806a5e386fd3258d8112"
+ integrity sha512-ndeSe/8KQc/nlA7TJ+OBhv2qalmj1s+uBs7yHDRFaAXscFTApBzY9F1jES3bautmgWjDlDct0fw8rPuySDLwxw==
dependencies:
"@vue/component-compiler-utils" "^3.1.0"
hash-sum "^1.0.2"
@@ -13065,10 +13579,10 @@ vue-template-es2015-compiler@^1.9.0:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
-vue-test-utils-compat@0.0.13:
- version "0.0.13"
- resolved "https://registry.yarnpkg.com/vue-test-utils-compat/-/vue-test-utils-compat-0.0.13.tgz#31cf91746601c2cafb0f4e560d32e7d6782c1380"
- integrity sha512-h4EBx87YmYTZF8xZvRmX04YsuyTHz4kkmcJS6J7NBMgWQecjq/fmAfLzpYnVF32E7Yus4uB3xv6iaaVtJp4YGQ==
+vue-test-utils-compat@0.0.14:
+ version "0.0.14"
+ resolved "https://registry.yarnpkg.com/vue-test-utils-compat/-/vue-test-utils-compat-0.0.14.tgz#c21556bba8bf605e7211ae094e8c9efd9ef83689"
+ integrity sha512-LtTdBGYOjByCy+XtpSK1rf2HPB0xo7L9jHP5v2BoE2iZ7IBnqIHliDQK/uPPfzXml79AxxB7XVGVu4zPxWki5A==
vue-virtual-scroll-list@^1.4.7:
version "1.4.7"
@@ -13203,20 +13717,27 @@ webidl-conversions@^7.0.0:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a"
integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==
-webpack-bundle-analyzer@^4.9.0:
- version "4.9.0"
- resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.0.tgz#fc093c4ab174fd3dcbd1c30b763f56d10141209d"
- integrity sha512-+bXGmO1LyiNx0i9enBu3H8mv42sj/BJWhZNFwjz92tVnBa9J3JMGo2an2IXlEleoDOPn/Hofl5hr/xCpObUDtw==
+webpack-bundle-analyzer@^4.9.1:
+ version "4.9.1"
+ resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.1.tgz#d00bbf3f17500c10985084f22f1a2bf45cb2f09d"
+ integrity sha512-jnd6EoYrf9yMxCyYDPj8eutJvtjQNp8PHmni/e/ulydHBWhT5J3menXt3HEkScsu9YqMAcG4CfFjs3rj5pVU1w==
dependencies:
"@discoveryjs/json-ext" "0.5.7"
acorn "^8.0.4"
acorn-walk "^8.0.0"
- chalk "^4.1.0"
commander "^7.2.0"
+ escape-string-regexp "^4.0.0"
gzip-size "^6.0.0"
- lodash "^4.17.20"
+ is-plain-object "^5.0.0"
+ lodash.debounce "^4.0.8"
+ lodash.escape "^4.0.1"
+ lodash.flatten "^4.4.0"
+ lodash.invokemap "^4.6.0"
+ lodash.pullall "^4.2.0"
+ lodash.uniqby "^4.7.0"
opener "^1.5.2"
- sirv "^1.0.7"
+ picocolors "^1.0.0"
+ sirv "^2.0.3"
ws "^7.3.1"
webpack-cli@^4.10.0:
@@ -13305,10 +13826,10 @@ webpack-stats-plugin@^0.3.1:
resolved "https://registry.yarnpkg.com/webpack-stats-plugin/-/webpack-stats-plugin-0.3.1.tgz#1103c39a305a4e6ba15d5078db84bc0b35447417"
integrity sha512-pxqzFE055NlNTlNyfDG3xlB2QwT1EWdm/CF5dCJI/e+rRHVxrWhWg1rf1lfsWhI1/EePv8gi/A36YxO/+u0FgQ==
-webpack@^4.46.0:
- version "4.46.0"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542"
- integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==
+webpack@^4.47.0:
+ version "4.47.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.47.0.tgz#8b8a02152d7076aeb03b61b47dad2eeed9810ebc"
+ integrity sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==
dependencies:
"@webassemblyjs/ast" "1.9.0"
"@webassemblyjs/helper-module-context" "1.9.0"
@@ -13499,6 +14020,14 @@ write-file-atomic@^4.0.1:
imurmurhash "^0.1.4"
signal-exit "^3.0.7"
+write-file-atomic@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7"
+ integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==
+ dependencies:
+ imurmurhash "^0.1.4"
+ signal-exit "^4.0.1"
+
"ws@^5.2.0 || ^6.0.0 || ^7.0.0", ws@^7.3.1:
version "7.5.7"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67"
@@ -13567,11 +14096,6 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-yaml@^1.10.0:
- version "1.10.2"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
- integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
-
yaml@^2.0.0, yaml@^2.0.0-10:
version "2.1.1"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec"
@@ -13585,7 +14109,7 @@ yargs-parser@^18.1.2:
camelcase "^5.0.0"
decamelize "^1.2.0"
-yargs-parser@^20.2.3:
+yargs-parser@^20.2.9:
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==